From 4c069ac14c72413589ce32c74f11220e1ccad3be Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Wed, 13 May 2026 16:35:46 +0000 Subject: [PATCH 01/12] remove empty wrapppers --- .agent/naming-audit/_SUMMARY.md | 880 +++++++++ .agent/naming-audit/abacpolicies.md | 266 +++ .agent/naming-audit/accountaccesscontrol.md | 139 ++ .../naming-audit/accountaccesscontrolproxy.md | 266 +++ .agent/naming-audit/accountsettings.md | 341 ++++ .agent/naming-audit/alerts.md | 512 +++++ .agent/naming-audit/apps.md | 837 +++++++++ .agent/naming-audit/artifactallowlists.md | 348 ++++ .agent/naming-audit/billableusagedownload.md | 152 ++ .agent/naming-audit/budgetpolicy.md | 262 +++ .agent/naming-audit/budgets.md | 1053 +++++++++++ .agent/naming-audit/bundle.md | 415 +++++ .agent/naming-audit/catalogs.md | 645 +++++++ .agent/naming-audit/cleanroomassets.md | 722 +++++++ .../cleanroomautoapprovalrules.md | 360 ++++ .agent/naming-audit/cleanrooms.md | 672 +++++++ .agent/naming-audit/cleanroomtaskruns.md | 484 +++++ .agent/naming-audit/clusterlibraries.md | 702 +++++++ .agent/naming-audit/clusterpolicies.md | 352 ++++ .agent/naming-audit/clusters.md | 580 ++++++ .agent/naming-audit/commandexecution.md | 640 +++++++ .agent/naming-audit/connections.md | 316 ++++ .agent/naming-audit/credentials.md | 531 ++++++ .agent/naming-audit/customllms.md | 243 +++ .agent/naming-audit/database.md | 462 +++++ .agent/naming-audit/dataclassification.md | 199 ++ .agent/naming-audit/dataquality.md | 342 ++++ .agent/naming-audit/disasterrecovery.md | 232 +++ .agent/naming-audit/endpoints.md | 1316 +++++++++++++ .agent/naming-audit/entitytagassignments.md | 258 +++ .agent/naming-audit/environments.md | 242 +++ .agent/naming-audit/experiments.md | 375 ++++ .agent/naming-audit/externallineage.md | 224 +++ .agent/naming-audit/externallocations.md | 271 +++ .agent/naming-audit/externalmetadata.md | 285 +++ .agent/naming-audit/features.md | 562 ++++++ .agent/naming-audit/featurestore.md | 849 +++++++++ .agent/naming-audit/files.md | 586 ++++++ .agent/naming-audit/forecasting.md | 936 ++++++++++ .agent/naming-audit/functions.md | 686 +++++++ .agent/naming-audit/genie.md | 450 +++++ .agent/naming-audit/gitcredentials.md | 374 ++++ .agent/naming-audit/globalinitscripts.md | 332 ++++ .agent/naming-audit/grants.md | 299 +++ .agent/naming-audit/iam.md | 874 +++++++++ .agent/naming-audit/indexes.md | 286 +++ .agent/naming-audit/instancepools.md | 395 ++++ .agent/naming-audit/instanceprofiles.md | 345 ++++ .agent/naming-audit/jobs.md | 951 ++++++++++ .agent/naming-audit/knowledgeassistants.md | 297 +++ .agent/naming-audit/lakeview.md | 798 ++++++++ .../naming-audit/logdeliveryconfigurations.md | 324 ++++ .agent/naming-audit/marketplaces.md | 1134 +++++++++++ .agent/naming-audit/materializedfeatures.md | 920 +++++++++ .agent/naming-audit/metastores.md | 693 +++++++ .agent/naming-audit/modelregistry.md | 814 ++++++++ .agent/naming-audit/modelservingdebug.md | 626 +++++++ .agent/naming-audit/modelservingmanagement.md | 441 +++++ .agent/naming-audit/modelservingquery.md | 663 +++++++ .../naming-audit/notificationdestinations.md | 383 ++++ .../naming-audit/oauthcustomappintegration.md | 173 ++ .agent/naming-audit/oauthpublishedapp.md | 155 ++ .agent/naming-audit/onlinetables.md | 1043 +++++++++++ .agent/naming-audit/permissions.md | 269 +++ .agent/naming-audit/pipelines.md | 519 ++++++ .agent/naming-audit/policyfamilies.md | 357 ++++ .agent/naming-audit/postgres.md | 613 ++++++ .agent/naming-audit/qualitymonitor.md | 318 ++++ .agent/naming-audit/qualitymonitors.md | 375 ++++ .agent/naming-audit/queries.md | 625 +++++++ .agent/naming-audit/queryexecution.md | 260 +++ .agent/naming-audit/queryhistory.md | 360 ++++ .agent/naming-audit/registeredmodels.md | 521 ++++++ .agent/naming-audit/repos.md | 496 +++++ .agent/naming-audit/resourcequotas.md | 339 ++++ .agent/naming-audit/rfa.md | 313 ++++ .agent/naming-audit/schemas.md | 678 +++++++ .agent/naming-audit/secrets.md | 657 +++++++ .agent/naming-audit/secretsuc.md | 220 +++ .../naming-audit/serviceprincipalsecrets.md | 469 +++++ .../serviceprincipalsecretsproxy.md | 385 ++++ .agent/naming-audit/settings.md | 639 +++++++ .agent/naming-audit/statementexecution.md | 413 ++++ .agent/naming-audit/supervisoragents.md | 336 ++++ .agent/naming-audit/systemschemas.md | 189 ++ .agent/naming-audit/tables.md | 1658 +++++++++++++++++ .agent/naming-audit/tagassignments.md | 244 +++ .agent/naming-audit/tagpolicies.md | 249 +++ .agent/naming-audit/tokenmanagement.md | 261 +++ .agent/naming-audit/tokens.md | 258 +++ .agent/naming-audit/usagedashboards.md | 181 ++ .agent/naming-audit/usagepolicy.md | 277 +++ .agent/naming-audit/volumes.md | 493 +++++ .agent/naming-audit/warehouses.md | 1346 +++++++++++++ .agent/naming-audit/workspace.md | 587 ++++++ .agent/naming-audit/workspaceassignment.md | 248 +++ .agent/naming-audit/workspacebindings.md | 310 +++ .agent/naming-audit/workspaceconf.md | 245 +++ .agent/naming-audit/workspacesettings.md | 445 +++++ AGENTS.md | 130 ++ 100 files changed, 48596 insertions(+) create mode 100644 .agent/naming-audit/_SUMMARY.md create mode 100644 .agent/naming-audit/abacpolicies.md create mode 100644 .agent/naming-audit/accountaccesscontrol.md create mode 100644 .agent/naming-audit/accountaccesscontrolproxy.md create mode 100644 .agent/naming-audit/accountsettings.md create mode 100644 .agent/naming-audit/alerts.md create mode 100644 .agent/naming-audit/apps.md create mode 100644 .agent/naming-audit/artifactallowlists.md create mode 100644 .agent/naming-audit/billableusagedownload.md create mode 100644 .agent/naming-audit/budgetpolicy.md create mode 100644 .agent/naming-audit/budgets.md create mode 100644 .agent/naming-audit/bundle.md create mode 100644 .agent/naming-audit/catalogs.md create mode 100644 .agent/naming-audit/cleanroomassets.md create mode 100644 .agent/naming-audit/cleanroomautoapprovalrules.md create mode 100644 .agent/naming-audit/cleanrooms.md create mode 100644 .agent/naming-audit/cleanroomtaskruns.md create mode 100644 .agent/naming-audit/clusterlibraries.md create mode 100644 .agent/naming-audit/clusterpolicies.md create mode 100644 .agent/naming-audit/clusters.md create mode 100644 .agent/naming-audit/commandexecution.md create mode 100644 .agent/naming-audit/connections.md create mode 100644 .agent/naming-audit/credentials.md create mode 100644 .agent/naming-audit/customllms.md create mode 100644 .agent/naming-audit/database.md create mode 100644 .agent/naming-audit/dataclassification.md create mode 100644 .agent/naming-audit/dataquality.md create mode 100644 .agent/naming-audit/disasterrecovery.md create mode 100644 .agent/naming-audit/endpoints.md create mode 100644 .agent/naming-audit/entitytagassignments.md create mode 100644 .agent/naming-audit/environments.md create mode 100644 .agent/naming-audit/experiments.md create mode 100644 .agent/naming-audit/externallineage.md create mode 100644 .agent/naming-audit/externallocations.md create mode 100644 .agent/naming-audit/externalmetadata.md create mode 100644 .agent/naming-audit/features.md create mode 100644 .agent/naming-audit/featurestore.md create mode 100644 .agent/naming-audit/files.md create mode 100644 .agent/naming-audit/forecasting.md create mode 100644 .agent/naming-audit/functions.md create mode 100644 .agent/naming-audit/genie.md create mode 100644 .agent/naming-audit/gitcredentials.md create mode 100644 .agent/naming-audit/globalinitscripts.md create mode 100644 .agent/naming-audit/grants.md create mode 100644 .agent/naming-audit/iam.md create mode 100644 .agent/naming-audit/indexes.md create mode 100644 .agent/naming-audit/instancepools.md create mode 100644 .agent/naming-audit/instanceprofiles.md create mode 100644 .agent/naming-audit/jobs.md create mode 100644 .agent/naming-audit/knowledgeassistants.md create mode 100644 .agent/naming-audit/lakeview.md create mode 100644 .agent/naming-audit/logdeliveryconfigurations.md create mode 100644 .agent/naming-audit/marketplaces.md create mode 100644 .agent/naming-audit/materializedfeatures.md create mode 100644 .agent/naming-audit/metastores.md create mode 100644 .agent/naming-audit/modelregistry.md create mode 100644 .agent/naming-audit/modelservingdebug.md create mode 100644 .agent/naming-audit/modelservingmanagement.md create mode 100644 .agent/naming-audit/modelservingquery.md create mode 100644 .agent/naming-audit/notificationdestinations.md create mode 100644 .agent/naming-audit/oauthcustomappintegration.md create mode 100644 .agent/naming-audit/oauthpublishedapp.md create mode 100644 .agent/naming-audit/onlinetables.md create mode 100644 .agent/naming-audit/permissions.md create mode 100644 .agent/naming-audit/pipelines.md create mode 100644 .agent/naming-audit/policyfamilies.md create mode 100644 .agent/naming-audit/postgres.md create mode 100644 .agent/naming-audit/qualitymonitor.md create mode 100644 .agent/naming-audit/qualitymonitors.md create mode 100644 .agent/naming-audit/queries.md create mode 100644 .agent/naming-audit/queryexecution.md create mode 100644 .agent/naming-audit/queryhistory.md create mode 100644 .agent/naming-audit/registeredmodels.md create mode 100644 .agent/naming-audit/repos.md create mode 100644 .agent/naming-audit/resourcequotas.md create mode 100644 .agent/naming-audit/rfa.md create mode 100644 .agent/naming-audit/schemas.md create mode 100644 .agent/naming-audit/secrets.md create mode 100644 .agent/naming-audit/secretsuc.md create mode 100644 .agent/naming-audit/serviceprincipalsecrets.md create mode 100644 .agent/naming-audit/serviceprincipalsecretsproxy.md create mode 100644 .agent/naming-audit/settings.md create mode 100644 .agent/naming-audit/statementexecution.md create mode 100644 .agent/naming-audit/supervisoragents.md create mode 100644 .agent/naming-audit/systemschemas.md create mode 100644 .agent/naming-audit/tables.md create mode 100644 .agent/naming-audit/tagassignments.md create mode 100644 .agent/naming-audit/tagpolicies.md create mode 100644 .agent/naming-audit/tokenmanagement.md create mode 100644 .agent/naming-audit/tokens.md create mode 100644 .agent/naming-audit/usagedashboards.md create mode 100644 .agent/naming-audit/usagepolicy.md create mode 100644 .agent/naming-audit/volumes.md create mode 100644 .agent/naming-audit/warehouses.md create mode 100644 .agent/naming-audit/workspace.md create mode 100644 .agent/naming-audit/workspaceassignment.md create mode 100644 .agent/naming-audit/workspacebindings.md create mode 100644 .agent/naming-audit/workspaceconf.md create mode 100644 .agent/naming-audit/workspacesettings.md diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md new file mode 100644 index 00000000..9535acb8 --- /dev/null +++ b/.agent/naming-audit/_SUMMARY.md @@ -0,0 +1,880 @@ +# Cross-Package Naming Audit — Executive Summary + +**Packages audited:** 98 (every API package under `packages//src//`) +**Total findings across all audits:** **5,001** (down from 5,322; **321 findings pruned**) +**Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` + +> **Prune note.** The original audit included a cross-cutting theme +> "Empty / trivial wrapper interfaces" (empty `*_Response` interfaces, +> single-field-primitive wrapper types, and proto outer-message wrappers +> retained only to anchor a nested enum). Per user direction these have +> been removed from every per-package audit: the wrapper types are kept +> on the public surface deliberately, for forward compatibility — adding +> a field later is a non-breaking change for a wrapper type but a +> breaking change if the response was previously `void` or a bare +> primitive. The 321 pruned findings are reflected in the totals, +> theme list, and Top-50 below. + +This document synthesises the per-package audits into the patterns that the +upstream generator (and a smaller number of API team decisions) should fix +to deliver an idiomatic TypeScript SDK. The vast majority of the findings are +template-driven — fix the template once and the symptoms disappear from every +package. + +The 98 packages are a 1:1 port of `databricks/sdk-go`, so most defects flow +from Go/protobuf idioms that do not translate to TypeScript. Idiomatic TS +SDKs (AWS, Azure, Stripe, Octokit) deliberately diverge from their wire +formats; the Databricks JS SDK currently does not. + +--- + +## 1. Top cross-cutting themes + +Ranked by approximate package incidence. Each theme is a generator-level +defect — one template change fixes ~98 packages. + +### Theme 1. Proto-style `_Response` (and other `_Suffix`) identifiers leak into TS — ~85/98 packages + +Every empty or short response message that protobuf wraps as a nested type +of the request is emitted as `_Response` in TypeScript. Each +identifier requires `// eslint-disable-next-line @typescript-eslint/naming-convention` +because the strict TS lint rules reject underscores in PascalCase +identifiers. The same pattern emits proto outer-message wrappers with an +underscored companion enum (`ClusterState_ClusterState`). + +Examples: +- `clusters.ClusterState_ClusterState` — `packages/clusters/src/v2/model.ts:777`. +- `pipelines.PipelineState_PipelineState` — `packages/pipelines/src/v2/model.ts:392`. +- `abacpolicies.DeletePolicy_Response`, `ListPolicies_Response` — `packages/abacpolicies/src/v1/model.ts:82, 173`. +- `cleanrooms.CleanRoom_Status_Enum`, `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` (4-level nesting). +- `jobs.RunLifecycleStateV2_State`, `TerminationCode_Code`, `QueueDetailsCode_Code`, `TerminationType_Type` — `packages/jobs/src/v2/model.ts:499, 532, 632, 717`. +- `postgres.SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` — 56-character triple-tautology, `packages/postgres/src/v1/model.ts:730`. + +**Generator fix:** Flatten nested proto messages to top-level types in TS, +mapping `Outer.Inner` → `OuterInner` (drop underscore). For `_Response` +specifically: emit `Response` (no underscore) regardless of +whether the body has fields — the wrapper itself stays, but the identifier +is clean. + +### Theme 2. Redundant enum-name prefix on every member (proto idiom) — ~84/98 packages + +Every enum is emitted with its members redundantly prefixed by the enum name: + +```ts +enum DestinationType { + DESTINATION_TYPE_UNSPECIFIED = 'DESTINATION_TYPE_UNSPECIFIED', + DESTINATION_TYPE_EMAIL = 'DESTINATION_TYPE_EMAIL', + ... +} +``` + +TypeScript enums are namespaced by the enum itself +(`DestinationType.Email`), so the prefix is pure protobuf noise. Often the +prefix is applied inconsistently *within a single enum*: +`DataSecurityMode.DATA_SECURITY_MODE_STANDARD` next to +`DataSecurityMode.SINGLE_USER` +(`packages/clusters/src/v2/model.ts:123-127`); or applied to two of three +cloud-specific enums while one cloud is unprefixed +(`AzureAvailability.SPOT_AZURE` / `GcpAvailability.PREEMPTIBLE_GCP` vs +`AwsAvailability.SPOT`). + +Examples: +- `connections.ConnectionType.UNKNOWN_CONNECTION_TYPE` — `packages/connections/src/v1/model.ts:7`. +- `tokens.AutoscopeState.AUTOSCOPE_STATE_API_NOT_COVERED` — 44 chars to express "API not covered", `packages/tokens/src/v1/model.ts:14-20`. +- `cleanrooms.INTERNET_DESTINATION_TYPE_UNSPECIFIED`, `LOG_ONLY_MODE_TYPE_UNSPECIFIED`, `OUTPUT_CATALOG_STATUS_UNSPECIFIED`. +- `commandexecution.CommandStatus.COMMAND_CANCELLED`, `COMMAND_FINISHED`, etc. (every member prefixed) — `packages/commandexecution/src/v2/model.ts:21-29`. +- `externallocations.IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` — 30 chars, `packages/externallocations/src/v1/model.ts:5-10`. + +**Generator fix:** Strip the redundant prefix at emit time. Map +`FOO_BAR_BAZ` → `BarBaz` (PascalCase) or keep `BAR_BAZ` for SCREAMING_SNAKE. +Either way the prefix that re-states the enum name should not survive into +TS. Wire value can stay as-is via Zod transform. + +### Theme 3. `*_UNSPECIFIED` proto sentinel values in every enum — ~60/98 packages + +Every protobuf enum carries a zero value `XXX_UNSPECIFIED` that protobuf +needs but TS does not. The corresponding field is already +`foo?: Foo | undefined`, so "unspecified" is encoded twice (as `undefined` +and as the sentinel). Callers have to handle both states. + +Examples in nearly every audit: `STATE_UNSPECIFIED`, `POLICY_TYPE_UNSPECIFIED`, +`COMPUTE_KIND_UNSPECIFIED`, `RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, +`ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, +`STATUS_UNSPECIFIED`, etc. + +**Generator fix:** Drop `*_UNSPECIFIED` members from emitted enums. Map them +to TypeScript `undefined` on the way in, and the field's `?:` optionality +already expresses "not set" on the way out. + +### Theme 4. Verb-phrase request types (no `Request` suffix) — ~80/98 packages + +Request DTOs are named with bare verb phrases: + +```ts +interface DeletePolicy { ... } // looks like a function +interface ListPolicies { ... } // looks like a method +interface CreateScope { ... } // looks like an action +``` + +Client methods sit alongside with identical camel-case names +(`client.deletePolicy(req: DeletePolicy)`), forcing readers to mentally +disambiguate noun-from-verb on every line. + +Examples: +- `secrets.{CreateScope, DeleteAcl, DeleteScope, DeleteSecret, GetAcl, GetSecret, ListAcls, ListScopes, ListSecrets, PutAcl, PutSecret}` — 11 verb-named types in one file. +- `workspace.{Delete, Export, Import, List, Mkdirs, GetStatus}` — also collide with TS reserved/built-in tokens (`Delete`, `Import`, `Export`). +- `files.{Read, Move, Put, Delete, Close, Create, MkDirs, AddBlock, GetStatus, ListStatus}` — every DBFS request type. +- `grants.{GetPermissions, UpdatePermissions, GetEffectivePermissions}` — request types named like verbs. +- `tokenmanagement.{GetToken, ListTokens, RevokeToken, UpdateToken, CreateOnBehalfOfToken}`. +- `serviceprincipalsecrets.{CreateServicePrincipalSecret, DeleteServicePrincipalSecret, ListServicePrincipalSecrets}`. + +**Generator fix:** Append `Request` to every request-DTO type. This is the +TS convention used by every other large SDK (AWS, Azure, Google Cloud). Wire +shape unaffected. + +### Theme 5. `Info` (and other vague) suffix on the canonical entity — ~70/98 packages + +The Go SDK uses `Info` to name "details of an X" because Go does not +have package-qualified imports for types. TS does, and `` alone +suffices. Examples: + +- `RepoInfo` → `Repo` / `GitFolder` (and the field `repo?: RepoInfo` becomes `repo?: Repo`). +- `PolicyInfo` → `Policy`. +- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 8). +- `SchemaInfo` → `Schema`. +- `CredentialInfo` → `Credential`. +- `MetastoreInfo` → `Metastore`. +- `CatalogInfo` → `Catalog`. +- `RunInfo`, `JobInfo`, `TableInfo`, `FunctionInfo`, `ConnectionInfo`, + `VolumeInfo`, `ServicePrincipalInfo`, `UserInfo`, `WorkspaceInfo`, + `OnlineTableInfo`, `IndexInfo`, `RunInfo`, `ExperimentInfo`. + +Same problem with other vague suffixes: +- `*Options` on tagged-union arms (`RowFilterOptions`, `ColumnMaskOptions`, `DenyOptions`, `GrantOptions`) — when the `$case` discriminator already says "this is the X options". +- `*Spec` / `*Details` / `*Config` / `*Status` / `*Data` / `*Metadata` used inconsistently — sometimes for the entity, sometimes for a sub-property, sometimes for both. `apps.ApplicationStatus` and `App.appStatus` mismatch on the same product noun. + +**Generator fix:** Strip the `Info` suffix when the type is the canonical +domain entity. (Heuristic: if `Info` is the only `*` type that +isn't a request/response, drop `Info`.) Same for redundant `Options`/`Spec` +suffixes on tagged-union arms when the parent has a discriminator. + +### Theme 6. Type-name prefix repeats the package — ~70/98 packages + +Every type in a package is prefixed with the package's domain noun, even +though the import path already provides namespace disambiguation: + +- `oauthcustomappintegration.{CreateCustomOAuthAppIntegration, CreatePublishedOAuthAppIntegration, DeleteCustomOAuthAppIntegration, ...}` — 18 types all prefixed with 19 characters that the import path already provides. +- `pipelines.{PipelinesAwsAvailability, PipelinesAzureAvailability, PipelinesEbsVolumeType, PipelinesAwsAttributes, ...}` — 15 types prefixed with `Pipelines` (plural) when the package is singular-domain. `packages/pipelines/src/v2/model.ts:212, 225, 241, 2243, ...`. +- `cleanroomautoapprovalrules.CleanRoomAutoApprovalRule` — package and type repeat the same 22-character noun. +- `genie.{GenieAttachment, GenieConversation, GenieMessage, GenieSpace, GenieFeedback, GenieEvalResult, ...}` — 40 types prefixed with `Genie` (and inconsistently — `Result`, `Schema`, `Thought` are not prefixed in the same file). +- `serviceprincipalsecrets.ServicePrincipalSecret` — every type carries `ServicePrincipal` (16 chars). +- `accountaccesscontrolproxy.GetAssignableRolesForResourceRequest` — 36-char type name when `GetAssignableRolesRequest` would do. +- `qualitymonitor.QualityMonitor` (package + type). +- `tagpolicies.TagPolicy`, `tagassignments.TagAssignment`, `entitytagassignments.EntityTagAssignment`. +- `customllms.CustomLlm`, `customLlmFieldMask`, `createCustomLlm`, etc. + +**Generator fix:** When emitting TS, strip the package-name prefix from +every type as long as the unprefixed name does not clash with another type +in the same package. Wire shape is unaffected. + +### Theme 7. Inconsistent acronym casing across the SDK — 98/98 packages + +The SDK currently mixes both `Pascal-then-lower` (`Http`, `Url`, `Json`, +`Sql`, `Oauth`, `Pypi`, `Aws`, `Llm`, `Pii`, `Sse`, `Idp`, `Csp`, `Esm`, +`Dbfs`, `Dbr`, `Aibi`) with `ALL_CAPS` (`URL`, `ID`, `URI`, `RPC`) in +different places. There is no project-wide policy. The user-visible +inconsistencies include: + +| Acronym | Found as | Examples | +|---|---|---| +| URL | `Url`, `URL`, `url` | `dataSchemaUrl`, `URLSearchParams`, `webhookUrl`, `URL` enum value | +| Id | `Id`, `ID`, `id` | `userId`, `runId`, `ID` (string-typed enum value), `metastoreId` | +| SQL | `Sql`, `SQL` | `SqlWarehouseSpec`, `DATABRICKS_SQL_ACCESS` | +| JSON | `Json`, `JSON` | `JsonValue`, `JsonObject`, `isJsonSchema` vs `JSON.stringify` | +| OAuth | `Oauth`, `OAuth` | `OAuthAppIntegration` (type), `oauthcustomappintegration` (package) | +| PyPI | `Pypi`, `PyPI` | `PypiLibrary` (type), JSDoc says "PyPI" | +| AWS | `Aws`, `AWS` | `AwsAttributes` (type), `AWS_SSE_S3` (enum value) | +| LLM | `Llm`, `LLM` | `CustomLlm` (type), `LLM` in JSDoc | +| ETag | `etag`, `eTag`, `ETag` | `RuleSet.etag` (field), `If-Match`/`ETag` (HTTP RFC 7232 §2.3 says `ETag`) | +| HTTP | `Http`, `HTTP` | `HttpClient` (type), `httpRequest` (method) | +| DBFS | `Dbfs`, `DBFS` | `disableLegacyDbfs`, `DbfsStorageInfo` vs JSDoc "DBFS" | + +**Generator fix:** Adopt one policy in `typescript.mdc` and apply +generator-wide. The two consistent options are: +1. **Google TS style guide (`Pascal-then-lower`):** `Url`, `Id`, `Sql`, `Json`, `OAuth` → `Oauth`. Pro: every multi-letter token becomes a word; con: requires reading `OAuth` as `Oauth`, which collides with the brand. +2. **.NET / Microsoft (`ALL_CAPS` for ≤2-letter, `Pascal-then-lower` for ≥3):** `URL`, `ID`, `Sql`, `Json`. Pro: matches HTTP/RFC casing; con: harder to typo-check. + +The choice matters less than the consistency; today the SDK has both. + +### Theme 8. `marshal` / `unmarshal` / `Schema` suffix vocabulary is Go-isms — ~90/98 packages + +Every package exports `marshal*Schema` / `unmarshal*Schema` Zod helpers +(`unmarshalPolicySchema`, `marshalCreatePolicySchema`, etc.). The TS +ecosystem uses `serialize`/`deserialize` or `encode`/`decode`, and the +`Schema` suffix is redundant with the `z.ZodType<>` type annotation. The +`unmarshalGetMetastoreSummary_ResponseSchema`-style identifiers can reach +50+ characters. + +Examples: +- `unmarshalGetAssignableRolesForResourceResponseSchema` (52 chars) — `packages/accountaccesscontrolproxy/src/v1/model.ts:113`. +- `unmarshalCreateServicePrincipalSecretResponseSchema` (50 chars). +- Every `parseResponse` / `marshalRequest` pair in `utils.ts` uses + asymmetric verbs (`parse` vs `marshal`). + +**Generator fix:** Rename `marshal*Schema` → `encode*` (or `serialize*`), +`unmarshal*Schema` → `decode*` (or `deserialize*`), and drop the redundant +`Schema` suffix. These are SDK-internal helpers — renaming has zero +external risk. + +### Theme 9. Pagination `Iter` suffix on every paginating method — ~57/98 packages + +Every paginating list method is emitted twice: `list*()` returning the +first page, plus `list*Iter()` returning an `AsyncIterator`. The `Iter` +suffix is a Go-ism (`ListPoliciesIter` in Go = `for it.Next() {...}`). +TypeScript ecosystems either: +- Make the list method itself return an `AsyncIterable` (Octokit, Azure + SDK), or +- Expose `.list()` and `.listAll()` (AWS SDK v3). + +Examples: every package with a list endpoint — `listPoliciesIter`, +`listCatalogsIter`, `listWarehousesIter`, `listEndpointsIter`, etc. The +duplicate methods double the method-count noise in `client.ts`. + +**Generator fix:** Pick one pagination shape. The most TS-native option is +to have `list*()` return `AsyncIterable` and add a `.firstPage()` +escape hatch for callers who need the raw response page. + +--- + +## 2. Cross-package duplication & overlap + +The audits surfaced ~30 pairs/triplets/quartets of packages that overlap +on a single underlying concept. Each row is a real user-facing pain point: +"I want to do X — which of these N packages do I import?" + +### 2.1 Settings (4-way overlap — the worst case) + +| Package | Style | What it really is | +|---|---|---| +| `settings` (v2) | Generic polymorphic value | The future "v2" key/value API | +| `accountsettings` | Per-feature endpoints | Per-toggle CRUD at the account level | +| `workspacesettings` | Per-feature endpoints | Per-toggle CRUD at the workspace level | +| `workspaceconf` | Free-form K/V map | Legacy untyped `map` settings | + +`BooleanMessage`, `StringMessage`, `IntegerMessage`, +`RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, +`AibiDashboardEmbeddingAccessPolicy`, `PersonalComputeMessage` are +**defined verbatim** in both `settings/v2/model.ts` and +`workspacesettings/v1/model.ts`. A consumer importing both gets two +distinct TS types with the same name. + +### 2.2 Secrets (4-way overlap) + +| Package | What it really is | +|---|---| +| `secrets` | Workspace-level Secret Manager (scopes + key/value) | +| `secretsuc` | Unity Catalog three-level-namespaced secrets | +| `serviceprincipalsecrets` | Account-level OAuth client secrets on SPs | +| `serviceprincipalsecretsproxy` | Workspace-level *byte-identical* clone of the above | + +Every package exports a class literally named `Client`, and three of the +four also export a type literally named `Secret`. `serviceprincipalsecrets` +and `serviceprincipalsecretsproxy` are byte-for-byte identical at the +file level (verified by md5 in the audit); the "proxy" word never appears +inside the code or URL of either. + +### 2.3 Credentials (3-way overlap) + +| Package | What it really is | +|---|---| +| `@databricks/sdk-auth/credentials/` | SDK *user-auth* credentials (PAT, U2M, M2M) | +| `credentials` | Unity Catalog cloud-storage credentials (AWS IAM, Azure SP, GCP SA) | +| `gitcredentials` | Per-workspace Git provider credentials (GitHub/GitLab PATs) | + +The bare type name `Credential` exists in two of these and `Credentials` +exists in the third. + +### 2.4 Identity / IAM (multi-way overlap) + +- `iam` exposes `*` + `*Proxy` versions of every method (e.g. + `createGroup` + `createGroupProxy`, etc.) — 17 endpoint pairs (44 + request types collapse to 22 unique shapes). +- `accountaccesscontrol` + `accountaccesscontrolproxy` — file-level + duplicate; the "proxy" suffix is invisible in code/URL. +- `permissions` overlaps with `iam` and `accountaccesscontrol` on the + rule-set + grant-rule data model. +- `workspaceassignment` overlaps with the workspace-assignment surface + inside `iam`. + +### 2.5 Tokens + +| Package | What it really is | +|---|---| +| `tokens` | User-self PAT management | +| `tokenmanagement` | Admin-of-others PAT management | + +Both export `Client`, both export `ListTokens`, `RevokeToken`, +`UpdateToken`. They duplicate the entire `AutoscopeState` enum verbatim. + +### 2.6 Tags (3-way split) + +| Package | What it really is | +|---|---| +| `tagpolicies` | Account-level governed-tag definitions | +| `tagassignments` | Tag assignments on `apps`/`dashboards`/`geniespaces`/`notebooks` (non-UC) | +| `entitytagassignments` | Tag assignments on UC entities (tables/schemas/columns/volumes) | + +Three packages, three `Client` classes, three near-identical +`TagAssignment` / `EntityTagAssignment` types. The non-UC variant has +`entityId: string`, the UC variant has `entityName: string` — same logical +field, different name, both string. + +### 2.7 Quality / Data monitoring (3-way overlap, all deprecated) + +| Package | Singular/plural | What it really is | +|---|---|---| +| `qualitymonitor` | singular | UC schema-level monitor (anomaly detection); deprecated | +| `qualitymonitors` | plural | UC table-level monitor (Lakehouse Monitoring); deprecated | +| `dataquality` | n/a | The new unified replacement API | + +Singular vs plural is the *only* differentiator between the first two +package names. Both are deprecated in favour of `dataquality`. Three +packages, three vocabularies (`QualityMonitor`, `DataMonitorInfo`, +`Monitor`), three `Client`s. + +### 2.8 Model Registry + +| Package | What it really is | +|---|---| +| `modelregistry` | Workspace-level MLflow registry (legacy) | +| `registeredmodels` | Unity Catalog model registry (modern) | + +The legacy package has the canonical-sounding name; the UC replacement is +hidden behind a plural noun. + +### 2.9 Model Serving (3-way fragmentation) + +| Package | What it really is | +|---|---| +| `modelservingmanagement` | CRUD over serving endpoints | +| `modelservingquery` | Inference / `POST /invocations` | +| `modelservingdebug` | Logs / metrics endpoints | + +All three operate on the same `serving-endpoints/{name}` URL space. The +type names differ across packages: `InferenceEndpoint` (management), +`Endpoint` (debug, query), and the URL itself says `serving-endpoints`. +Three names for the same noun. + +### 2.10 Cluster compute (overlapping warehouses) + +- `warehouses` exposes SQL Warehouses (formerly "SQL Endpoints"); the + TS types still spell `Endpoint*` (e.g. `EndpointInfo`, `EndpointState`). +- `endpoints` (separate package!) exposes Vector Search endpoints with + type names like `Endpoint`, `EndpointType`, `EndpointStatus`. + +Two packages, two `Endpoint*` type families, different products. + +### 2.11 Database (Lakebase) + +| Package | What it really is | +|---|---| +| `database` | Lakebase / managed Postgres (`DatabaseInstance`, etc.) | +| `postgres` | Same Lakebase OLTP surface from a different angle | + +Both expose `SyncedTable`, `DatabaseInstance`, `SyncedTable_SyncedTableSpec_*` +heavily-nested types. + +### 2.12 Features + +| Package | What it really is | +|---|---| +| `features` | Feature definitions | +| `featurestore` | Online stores / publishing | +| `materializedfeatures` | Feature materialisation | + +Three packages, blurry boundaries (audit calls out "H1. Three sibling +packages, blurry boundaries" on `features.md`). `Feature` is overloaded. + +### 2.13 Budget / Usage policy + +| Package | What it really is | +|---|---| +| `budgetpolicy` | `/api/2.0/accounts/{accountId}/budget-policies` | +| `usagepolicy` | `/api/2.1/accounts/{accountId}/usage-policies` | + +`usagepolicy/v1/model.ts` is `budgetpolicy/v1/model.ts` with the word +"Budget" substituted for "Usage". The JSDoc on `UsagePolicy.policyId` even +admits it: "(same structure as BudgetPolicy)". Reserved tag keys still say +`"budget-policy-name"` in the usage-policy clone. + +### 2.14 Workspace (5-package fanout) + +| Package | What it really is | +|---|---| +| `workspace` | Workspace filesystem (notebooks/folders/files) | +| `workspaceassignment` | Principal-to-workspace assignments | +| `workspacebindings` | Securable-to-workspace bindings | +| `workspaceconf` | Untyped K/V configuration | +| `workspacesettings` | Typed workspace settings | + +The bare name `workspace` is misleading — every Databricks API operates +"in a workspace". A name like `workspacefiles` would convey scope. + +### 2.15 Schemas (UC overlap) + +| Package | What it really is | +|---|---| +| `schemas` | User-defined UC schemas (full CRUD) | +| `systemschemas` | Server-managed UC system schemas (enable/disable) | + +### 2.16 OAuth + +| Package | What it really is | +|---|---| +| `oauthcustomappintegration` | CRUD for custom AND published OAuth app integrations | +| `oauthpublishedapp` | List-only of the published-app catalog | + +The first package's name is misleading — it covers both Custom and +Published despite saying only "Custom". Both packages are singular but +expose collection operations. + +### 2.17 Statement / Query / Command execution + +| Package | What it really is | +|---|---| +| `statementexecution` | Ad-hoc SQL on a SQL Warehouse | +| `queryexecution` | Re-run saved queries inside *published* dashboards | +| `commandexecution` | Python/SQL/Scala/R via Clusters REPL | +| `queries` | Saved-query CRUD | +| `queryhistory` | Read-only query history list | + +Five packages, three near-synonyms in the names (query/statement/command), +disjoint scopes that the names do not telegraph. + +### 2.18 Other notable overlaps + +- `lakeview` (the rebranded "AI/BI Dashboards" — name uses old codename). +- `cleanrooms` + `cleanroomassets` + `cleanroomautoapprovalrules` + + `cleanroomtaskruns` — four packages for one product surface. +- `serviceprincipalsecrets` ≡ `serviceprincipalsecretsproxy` (byte-identical). +- `accountaccesscontrol` ≈ `accountaccesscontrolproxy`. +- `supervisoragents` + `knowledgeassistants` + `customllms` — + three packages in the LLM-orchestration space with bare-generic top-level + type names (`SupervisorAgent`, `KnowledgeAssistant`, `CustomLlm`). + +--- + +## 3. Cryptic abbreviations glossary + +The user-facing TS surface uses these abbreviations, mostly without +expansion in code or JSDoc. A first-time user has to guess. + +| Abbreviation | Meaning | Visibility | Notes | +|---|---|---|---| +| `rfa` | Request For Access | Package name only | `packages/rfa/` — no expansion in any TS identifier or JSDoc. The wire URL `/api/3.0/rfa/...` is the only other carrier. | +| `uc` | Unity Catalog | Package suffix (`secretsuc`), URL `/unity-catalog/`, comment references | Never appears as a type prefix. | +| `sp` | Service Principal | Field prefixes (`accountSpStatus`, `spId`) | Inconsistent — sometimes spelled out (`servicePrincipal`), sometimes `sp`. | +| `conf` | Configuration | `workspaceconf` (package), `EndpointConfPair` (type) | One four-letter abbreviation that the rest of the SDK consistently spells out. | +| `dbu` | Databricks Unit | Cluster docs only | Not in type names. | +| `dbr` | Databricks Runtime | `TerminationCode.DBR_IMAGE_RESOLUTION_FAILURE`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` | Acronym not expanded. | +| `dbfs` | Databricks File System | `DbfsStorageInfo`, `disableLegacyDbfs` | Casing varies (`Dbfs` vs `DBFS` in JSDoc). | +| `dlt` | Delta Live Tables | Comment references | The product was renamed to "Lakeflow Declarative Pipelines"; the type `Update` still reflects the DLT-era name. | +| `csp` | Compliance Security Profile | `CspEnablementAccountSetting`, `Csp*` family | `Csp` casing is uniform; the acronym is not expanded. | +| `esm` | Enhanced Security Monitoring | `EsmEnablementAccountSetting`, `Esm*` family | Same as CSP. | +| `dcp` | (settings v1 internal acronym) | `DcpAccountEnableMessage` | Audit at `accountsettings.md` flagged as cryptic. | +| `llm` | Large Language Model | `CustomLlm`, `LlmProxyPartnerPoweredAccount`, `Llm*` family | `Llm` casing is uniform across SDK. | +| `sdp` | Serverless Declarative Pipelines | Comments | Internal acronym. | +| `ldp` | Lakeflow Declarative Pipelines | Comments | Internal acronym. | +| `dab` | Databricks Asset Bundles | `bundle` package only | Spelled out in package. | +| `m2m` | Machine-to-Machine | `auth/credentials/m2m.ts` | OAuth grant type. | +| `u2m` | User-to-Machine | `auth/credentials/u2m.ts` | OAuth grant type. | +| `pat` | Personal Access Token | `auth/credentials/pat.ts`, `tokens` package | OAuth-adjacent. | +| `abac` | Attribute-Based Access Control | Package name `abacpolicies` only | Never appears in code or types. | +| `iam` | Identity and Access Management | Package name | Conventional. | +| `wkt` | Well-Known Types | `@databricks/sdk-core/wkt` import | Proto term, not exposed to users. | +| `aibi` | AI/BI Dashboards | `AibiDashboard*` family | Internal codename for the "AI/BI" product brand. | +| `byok` | Bring Your Own Key | `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` | Not expanded. | +| `npip` | No Public IP | `TerminationCode.NPIP_TUNNEL_*` | Internal Databricks networking term. | +| `cmv2` | Cluster Manager v2 | `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` JSDoc | Internal term ("CMv2") leaked into enum doc. | +| `aqs`/`sqs` | Azure Queue Storage / AWS SQS | `AwsSqsQueue`, `AzureQueueStorage` | Audit flagged a doc copy-paste error: AWS SQS JSDoc says "AQS queue url". | +| `cprf` | Control Plane Request Failure | `TerminationCode.CONTROL_PLANE_REQUEST_FAILURE` JSDoc | Internal acronym in user-facing JSDoc. | +| `gke` | Google Kubernetes Engine | `TerminationCode.GKE_BASED_CLUSTER_TERMINATION` | Cloud-specific abbreviation. | +| `n` (single letter) | Number of completions (LLM API) | `QueryEndpointInput.n` | One-character field name on a public model. | +| `expr` | Expression | `FunctionArgExpression.expr` discriminator | Three-letter abbreviation when `expression` would do. | +| `arg` | Argument | `fullNameArg`, `nameArg`, `versionArg`, `aliasArg` | Path-parameter suffix; surfaced in 5+ UC packages (`tables`, `schemas`, `catalogs`, `functions`, `registeredmodels`). | +| `tpe` | Type | `externallineage.ExternalLineageRelationshipObject.tpe` | Likely typo for `type` — but is a discriminator key. | +| `req` / `resp` | Request / Response | Local variable names in `client.ts` files | Go-ism. | +| `etag` / `eTag` / `ETag` | Entity Tag (HTTP) | Field name varies | RFC 7232 §2.3 specifies `ETag`. | + +--- + +## 4. Acronym-casing inconsistencies + +The SDK currently has no enforced casing policy. The same acronym appears in +multiple casings across packages — sometimes within the same file. + +| Acronym | Found casings | Sample sites | +|---|---|---| +| **URL** | `Url`, `URL`, `url` | `webhookUrl` (field), `URL` (enum value in `rfa.DestinationType`), `URLSearchParams` (import). Note: `URL` collides with the JS built-in. | +| **ID** | `Id`, `ID`, `id` | `userId`, `runId`, `policyId` (field side) vs `ID` (enum value) vs raw `id` (bare field). | +| **URI** | `Uri`, `URI` | `endpointUri` vs JSDoc "URI". | +| **SQL** | `Sql`, `SQL` | `SqlWarehouseSpec` (type), `DATABRICKS_SQL_ACCESS` (enum). | +| **JSON** | `Json`, `JSON` | `JsonValue`, `JsonObject` (wkt types) vs `JSON.stringify` (built-in). | +| **OAuth** | `Oauth`, `OAuth` | Package `oauthcustomappintegration` (lowercased), type `OAuthAppIntegration` (PascalCase). | +| **PyPI** | `Pypi`, `PyPI` | `PypiLibrary` (type), JSDoc spells `PyPI`. | +| **AWS** | `Aws`, `AWS` | `AwsAttributes` (type), `AWS_SSE_S3` (enum). | +| **GCP** | `Gcp`, `GCP` | `GcpAvailability` (type), `GCP_QUOTA_EXCEEDED` (enum). | +| **Azure** | `Azure` | Consistent. | +| **LLM** | `Llm`, `LLM` | `CustomLlm` (type, field), JSDoc says `LLM`. | +| **HTTP** | `Http`, `HTTP` | `HttpClient` (type) vs JSDoc and headers. | +| **HTTPS** | `Https` | Consistent. | +| **DBFS** | `Dbfs`, `DBFS` | `DbfsStorageInfo` vs `disableLegacyDbfs` vs JSDoc "DBFS". | +| **DBR** | `Dbr`, `DBR` | Enum members all-caps. | +| **PII** | `Pii`, `PII` | `Pii` casing in types; JSDoc varies. | +| **CSP** | `Csp`, `CSP` | Type `Csp*`, JSDoc "CSP". | +| **ESM** | `Esm`, `ESM` | Type `Esm*`, JSDoc "ESM". | +| **IdP** | `Idp`, `IdP` | `idp*` fields, JSDoc "IdP". | +| **ETag** | `etag`, `eTag`, `ETag` | Three casings within one JSDoc comment block (`accountaccesscontrolproxy`). | +| **ODBC** | `Odbc` | `OdbcParams`. | +| **JDBC** | `Jdbc`, `JDBC` | Doc references only. | +| **AI/BI** | `Aibi`, `AI/BI` | `AibiDashboard*` types, JSDoc says "AI/BI". | +| **SSE** | `Sse`, `SSE` | `SseEncryptionAlgorithm` (type), `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` (enum). | +| **TLS** | `Tls`, `TLS` | Rare; `Tls` in field names. | +| **OAuth2** | varied | `oauth2` (path), `OAuth` (types). | + +**Recommendation:** Pick one rule. The Google TypeScript Style Guide +specifies `Pascal-then-lower` (`Url`, `Id`, `Json`, `Sql`) — this is the +current majority in the SDK. Document the choice in `.agent/rules/typescript.mdc` +§ 3 and enforce in CI. Wire format unchanged. + +--- + +## 5. Package-name oddities + +Packages whose names themselves cause user-facing pain. + +| Package | Issue | Suggested rename | +|---|---|---| +| `rfa` | 3-letter cryptic acronym — never expanded in any TS identifier. | `accessrequests` | +| `workspaceconf` | `conf` is the only abbreviation of "configuration" in the SDK. | `workspaceconfig` | +| `secretsuc` | Two words mashed together; `uc` is invisible to readers. | `unitycatalogsecrets` or `ucsecrets` | +| `cleanroomautoapprovalrules` | 26-character compound, no separator. | `cleanroomautoapprovals` (drop "rules") or `cleanrooms/auto-approval-rules` subpath | +| `oauthcustomappintegration` | 25 chars; singular; *covers both Custom AND Published*. | `oauthappintegrations` (drop `custom`, pluralise) | +| `serviceprincipalsecretsproxy` | 28 chars; "proxy" appears nowhere in code or URL; byte-identical to `serviceprincipalsecrets`. | Merge into `serviceprincipalsecrets`. | +| `serviceprincipalsecrets` | 23 chars compound; sibling to four other `*secret*` packages. | `sp-credentials` or `service-principal-credentials` (hyphenated). | +| `accountaccesscontrolproxy` | 25 chars; byte-identical to `accountaccesscontrol`. | Merge into `accountaccesscontrol`. | +| `qualitymonitor` vs `qualitymonitors` | Singular vs plural, both deprecated, different APIs. | Drop both — consolidate to `dataquality`. | +| `tokens` vs `tokenmanagement` | "Tokens API" vs "Manage tokens" — both accurate, neither distinguishes user-self vs admin. | `usertokens` + `tokenadmin`. | +| `workspace` | Most overloaded of 5 `workspace*` packages — every API operates "in a workspace". | `workspacefiles` (it's the FS API). | +| `endpoints` | Doesn't say "vector search" — collides conceptually with the legacy `Endpoint*` types in `warehouses`. | `vectorsearchendpoints`. | +| `warehouses` | Right product name, but every TS type is `Endpoint*` (legacy proto name). | Keep; rename `EndpointInfo`/`EndpointState`/`EndpointTagPair`/`EndpointConfPair`/`EndpointSecurityPolicy`/`EndpointSpotInstancePolicy` → `Warehouse*`. | +| `lakeview` | Old codename; product is now "AI/BI Dashboards". | `dashboards` or `aibidashboards`. | +| `repos` | Legacy codename; product is "Git folders". | `gitfolders`. | +| `database` vs `postgres` | Two packages, one product (Lakebase managed Postgres). | Merge; keep `lakebase` or `managedpostgres`. | +| `modelregistry` vs `registeredmodels` | Singular "the registry" vs plural "the entries" — actually two products (workspace MLflow vs UC). | `mlflowregistry` + `ucregisteredmodels`. | +| `qualitymonitor` (singular) | Only its singular form distinguishes from `qualitymonitors` (plural). | See row above. | +| `billableusagedownload` | Verb in package name (`download`). Only such case in the SDK. | `billableusage` (move verb to method). | +| `experiments` | Bare-generic word — also a common term in feature-flag SDKs. | `mlflowexperiments`. | +| `bundle` | Bare-generic word — Webpack/Vite/Rollup all have "bundles". | `assetbundles`. | +| `genie` | Codename — product is "Genie Spaces"/"AI/BI Genie". | Keep `genie` but drop the `Genie*` type prefix throughout. | +| `customllms` | Plural, but the type is singular (`CustomLlm`). | OK; flag for `LLM` vs `Llm` casing policy. | +| `disasterrecovery` | OK; `FailoverFailoverGroupRequest` is the type to fix. | n/a | +| `supervisoragents` | `Supervisor` + `Agent` both extremely generic. | `routeragents` or `agentorchestrators`. | +| `knowledgeassistants` | OK, but generic enough that future overlap is likely. | n/a | +| `commandexecution` | Mixes three resources (Command, Context, Cluster); name picks one. | Keep, but split the type prefixes (`CommandStatus` vs `ContextStatus`). | +| `policyfamilies` | OK but uses both "Family" and "Policy Family" interchangeably. | n/a | +| `connections` | Bare-generic; collides with HTTP/DB connections in user code. | `ucconnections` or `foreignconnections`. | +| `tables`, `volumes`, `schemas`, `catalogs`, `functions` | All bare-plural UC nouns. Cross-package overlap with `Dependency`, `SecurableType`, `EncryptionDetails`, `EffectivePredictiveOptimizationFlag` is heavy. | Keep names; hoist shared types to a `uc-common` package. | + +--- + +## 6. Top-50 highest-impact individual findings + +Picked one per package where possible, prioritising ones with broad reuse. +Findings ranked High severity in their audit. Each entry: file + symbol + the +generator pattern it exemplifies. + +| # | Package | File:Line | Symbol / Issue | Pattern | +|---|---|---|---|---| +| 1 | `jobs` | `model.ts:3414, 3890` | `Run` overloaded across 7 shapes (`Run`, `BaseRun`, `RunTask`, `Run_JobLevelParameters`, `RunState`, `RunStatus`, `RunTriggerInfo`). | Vague/duplicate concepts | +| 2 | `jobs` | `model.ts:150, 280, 1464, 1835` | `Format`, `Source`, `Compute`, `Environment` — top-level types collide with JS/TS built-ins and DOM globals. | Reserved-word collision | +| 3 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | +| 4 | `clusters` | `model.ts:777` | `ClusterState_ClusterState` enum identifier — proto outer-message underscore leaks. | Proto outer-message + underscore | +| 5 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | +| 6 | `pipelines` | `model.ts:212-2507` | `Pipelines*` prefix on 15 types in a package called `pipelines` (singular). | Type-name prefix repeats package | +| 7 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | +| 8 | `abacpolicies` | `model.ts:7-14` | `PolicyType.POLICY_TYPE_UNSPECIFIED`/`POLICY_TYPE_ROW_FILTER`/etc. | Redundant enum prefix | +| 9 | `abacpolicies` | `model.ts:82, 173` | `DeletePolicy_Response`, `ListPolicies_Response` — underscore identifier. | Proto `_Response` | +| 10 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | +| 11 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | +| 12 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | +| 13 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | +| 14 | `apps` | `model.ts:606, 962` | `AppResourceApp_AppPermission.CAN_USE` — `App` token thrice. | Proto-nested + redundant prefix | +| 15 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | +| 16 | `genie` | `model.ts passim` | 40 of ~70 types prefixed `Genie*`; remaining have no prefix. | Inconsistent type prefix | +| 17 | `commandexecution` | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` is reused for both `create()` (context id) and `execute()` (command queued) — type repurposed across two semantically different operations. | Type repurposing | +| 18 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | +| 19 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | +| 20 | `secrets` | `model.ts:passim` | 11 of 13 public types carry proto underscore (`CreateScope_Response` etc.). | Proto `_Response` | +| 21 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | +| 22 | `qualitymonitor` | package + types | Singular `qualitymonitor` vs plural `qualitymonitors` — different APIs distinguished only by trailing `s`. | Package-name overlap | +| 23 | `qualitymonitors` | model + types | Both deprecated; `DataMonitorInfo` vs `Monitor` vs `QualityMonitor` — three names for one wire object. | Duplicate concept | +| 24 | `modelservingmanagement` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | +| 25 | `modelservingmanagement` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | +| 26 | `oauthcustomappintegration` | `model.ts:passim` | 18 types named `*OAuthAppIntegration*` — package name re-stated in every type. | Type-name prefix | +| 27 | `oauthcustomappintegration` | package | Name says "custom" but covers both Custom and Published integrations. | Misleading package name | +| 28 | `serviceprincipalsecretsproxy` | files | Byte-identical to `serviceprincipalsecrets` — "proxy" never in code/URL. | Duplicate package | +| 29 | `serviceprincipalsecrets` | `model.ts:42, 59` | `_Response` proto underscores; verb-phrase request types lacking `Request` suffix. | Proto + verb-as-noun | +| 30 | `accountaccesscontrol` | `model.ts:73, 89, 105` | `RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest` — three names for one shape with overlapping `name` fields. | Duplicate concept | +| 31 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 32 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | +| 33 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | +| 34 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | +| 35 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | +| 36 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 37 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | +| 38 | `cleanroomautoapprovalrules` | every type | `CleanRoomAutoApprovalRule` re-states the 26-char package name on every type. | Type-name prefix | +| 39 | `cleanrooms` | `model.ts:passim` | `CleanRoom_Status_Enum`, `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` (4-level proto nesting). | Proto deep-nesting | +| 40 | `database` + `postgres` | model.ts | `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` (56-char triple-tautology); two packages, one product. | Proto + duplicate package | +| 41 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | +| 42 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | +| 43 | `permissions` | `model.ts` | `GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions` — verb-phrase request types. | Verb-as-noun | +| 44 | `permissions` + `grants` + `iam` + `accountaccesscontrol` | passim | Permissions/grants/rule-sets fragmented across 4 packages with overlapping vocabularies. | Cross-package fragmentation | +| 45 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | +| 46 | `repos` | `model.ts:29, 56, 64, 111` | `CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, `RepoInfo` — duplicate shapes + proto underscores. | Proto + duplicate concept | +| 47 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 48 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | +| 49 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 50 | `materializedfeatures` | package | `materializedfeatures` does not match contents (contains feature-tag CRUD, not materialisation logic). | Misleading package name | + +--- + +## 7. By-the-numbers (all 98 packages, sorted by total findings) + +| # | Package | Findings | Top theme | +|---|---|---|---| +| 1 | jobs | 194 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes | +| 2 | warehouses | 124 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 3 | endpoints | 118 | `Endpoint*` (vector search) vs `endpoints` (other products); brand-name collision | +| 4 | settings | 111 | Cross-package duplication with `accountsettings`/`workspacesettings`/`workspaceconf` | +| 5 | catalogs | 97 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | +| 6 | postgres | 92 | 18 underscore type names; quad-nested `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` | +| 7 | pipelines | 92 | `Update` noun = pipeline run; `Pipelines*` prefix on every type | +| 8 | schemas | 89 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | +| 9 | budgets | 89 | Budget vs `budgetpolicy` duplication | +| 10 | metastores | 87 | `Get*Summary_Response` underscores; structural duplicate of `MetastoreInfo` | +| 11 | clusters | 87 | `ClusterState_ClusterState`; per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | +| 12 | functions | 86 | `function` reserved-word; proto-nested `FunctionInfo_*`; `fullNameArg` | +| 13 | forecasting | 80 | `Forecasting*` prefix; underscored type names | +| 14 | cleanroomassets | 80 | 18 underscore identifiers; `CleanRoom*` re-prefix on every type | +| 15 | clusterlibraries | 79 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 16 | apps | 78 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | +| 17 | genie | 73 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 18 | instancepools | 68 | Massive structural duplication of `Create*`/`Edit*`/`*_Response`/`*AndStats` | +| 19 | instanceprofiles | 67 | Bare verb request types; vague identifiers | +| 20 | tables | 66 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 21 | policyfamilies | 65 | "Family" + "Policy Family" mixed; underscored enums | +| 22 | modelregistry | 65 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | +| 23 | marketplaces | 65 | 14× `_Response` proto underscores | +| 24 | iam | 65 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | +| 25 | globalinitscripts | 65 | Verb-as-noun requests; proto `_Response` wrappers | +| 26 | experiments | 63 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 27 | externallocations | 62 | `IsolationMode_*`/`SseEncryptionAlgorithm_*` enum prefixing; cross-cloud queue type naming inconsistency | +| 28 | cleanrooms | 60 | 4-level proto nesting; redundant enum prefixes throughout | +| 29 | clusterpolicies | 57 | Underscore types; verb-as-noun requests | +| 30 | workspacesettings | 56 | Cross-package duplicates with `settings`/`accountsettings`/`workspaceconf` | +| 31 | database | 56 | Package name overlaps `postgres`; deep proto nesting | +| 32 | files | 54 | `Read`/`Move`/`Put`/`Delete`/`Close`/`Create`/`MkDirs`/`AddBlock` — verb-as-noun (legacy DBFS) | +| 33 | modelservingmanagement | 53 | `InferenceEndpoint` vs `ServingEndpoint` vs `serving-endpoints` URL — three names | +| 34 | credentials | 53 | 4× duplicate type pairs (`Credential*` vs `StorageCredential*`); cross-package with `auth/credentials` | +| 35 | qualitymonitors | 52 | Plural vs singular `qualitymonitor`; both deprecated | +| 36 | dataquality | 52 | `ListMonitorRequest` singular for list of monitors | +| 37 | registeredmodels | 51 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | +| 38 | features | 50 | Three sibling feature packages with blurry boundaries | +| 39 | supervisoragents | 49 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 40 | workspacebindings | 47 | Bare verb requests; underscore identifiers | +| 41 | statementexecution | 47 | Package name overlaps `queryexecution`/`commandexecution`/`queries` | +| 42 | queryhistory | 47 | Vague `Query` types; cross-package overlap with `queries`/`queryexecution` | +| 43 | qualitymonitor | 47 | Sibling-package collision with `qualitymonitors` | +| 44 | rfa | 46 | 3-letter cryptic package name | +| 45 | connections | 46 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 46 | grants | 45 | Verb-phrase request types; underscore identifiers | +| 47 | lakeview | 43 | Old codename (rebrand to "AI/BI Dashboards") | +| 48 | indexes | 43 | Package name not "vector search"; `MiniVectorIndex` duplicates `VectorIndex` | +| 49 | commandexecution | 43 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | +| 50 | accountsettings | 43 | `Csp`/`Esm`/`Llm`/`Dcp` cryptic acronyms; generic `value` discriminator | +| 51 | knowledgeassistants | 42 | `KnowledgeAssistant_State` underscore identifier | +| 52 | usagepolicy | 41 | 1:1 clone of `budgetpolicy` | +| 53 | repos | 41 | "Repos" legacy term; product is "Git folders" | +| 54 | onlinetables | 41 | `ProvisioningInfo_State`; underscore identifiers | +| 55 | materializedfeatures | 41 | Package name doesn't match contents | +| 56 | permissions | 40 | Cross-package overlap with `iam`/`accountaccesscontrol`/`grants` | +| 57 | externalmetadata | 40 | `SystemType.*_UNSPECIFIED`; brand-value casing (`POWER_BI`, `STREAM_NATIVE`) | +| 58 | abacpolicies | 40 | `PolicyInfo`; `_Response` underscores; verb-as-noun requests | +| 59 | secrets | 39 | 11/13 types with proto underscore; mutation-verb inconsistency | +| 60 | queries | 39 | Three-package overlap with `queryhistory`/`queryexecution` | +| 61 | featurestore | 39 | `OnlineStore_State` underscore identifier | +| 62 | bundle | 39 | Generic package name (`bundle`); verb-as-noun requests | +| 63 | budgetpolicy | 38 | Sibling clone in `usagepolicy` | +| 64 | tagpolicies | 37 | Three sibling tag packages with overlapping vocab | +| 65 | entitytagassignments | 37 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 66 | workspaceassignment | 36 | Cross-package overlap with `iam` | +| 67 | tokenmanagement | 36 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 68 | queryexecution | 36 | Package name far broader than scope (dashboards-only) | +| 69 | logdeliveryconfigurations | 36 | Long verbose names | +| 70 | customllms | 36 | `Llm` casing throughout | +| 71 | alerts | 36 | Mixed v1/v2 | +| 72 | tokens | 35 | Cross-package duplicate of `tokenmanagement` | +| 73 | tagassignments | 35 | Three-package tag split; sibling field-name drift | +| 74 | modelservingquery | 34 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 75 | environments | 34 | `Environment` generic name | +| 76 | serviceprincipalsecrets | 33 | Identical to `serviceprincipalsecretsproxy` | +| 77 | serviceprincipalsecretsproxy | 33 | Byte-identical to non-proxy version | +| 78 | workspace | 32 | Most overloaded of 5 `workspace*` packages | +| 79 | secretsuc | 32 | `uc` cryptic suffix; collides with `secrets` | +| 80 | modelservingdebug | 32 | Tiny package, mostly proto underscores | +| 81 | disasterrecovery | 32 | `FailoverFailoverGroupRequest` stutter | +| 82 | gitcredentials | 31 | Three "Credentials" packages with different meanings | +| 83 | externallineage | 31 | `Direction_LineageDirection` underscore; `tpe` typo | +| 84 | dataclassification | 29 | Tag-domain overlap | +| 85 | accountaccesscontrolproxy | 29 | 1:1 surface duplicate of `accountaccesscontrol` | +| 86 | systemschemas | 27 | Sibling-package collision with `schemas` | +| 87 | volumes | 26 | `fullNameArg`; verb-as-noun requests | +| 88 | usagedashboards | 26 | Vague type names | +| 89 | notificationdestinations | 26 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 90 | resourcequotas | 25 | Underscore identifiers | +| 91 | cleanroomtaskruns | 24 | `LifeCycle` casing; one of four cleanroom packages | +| 92 | workspaceconf | 23 | `conf` cryptic abbreviation; wire-shape regression | +| 93 | billableusagedownload | 21 | Verb in package name (`download`) | +| 94 | artifactallowlists | 20 | Vague type names | +| 95 | oauthpublishedapp | 19 | Singular but only `list*` endpoints | +| 96 | cleanroomautoapprovalrules | 19 | 26-char package name; `CleanRoomAutoApprovalRule` re-prefix | +| 97 | oauthcustomappintegration | 18 | Package covers Custom AND Published despite name | +| 98 | accountaccesscontrol | 18 | Sibling duplicate `accountaccesscontrolproxy` | + +--- + +## 8. Generator-level recommendations + +Ranked by impact across all 98 packages. Each item is one template change. + +### 8.1 Stop emitting `_Response` underscore identifiers + +Emit `Response` (no underscore) for every response wrapper — +the wrapper itself remains (kept for forward compatibility), but the +identifier becomes a clean PascalCase token. This removes ~70 +`eslint-disable` comments per package and ~5,000 underscore identifiers +across the SDK. Affects ~85/98 packages. + +### 8.2 Flatten proto nested types + +Map proto `Outer.Inner` to TS `OuterInner` (clean PascalCase, no +underscore). Eliminates `ClusterState_ClusterState`, +`PipelineState_PipelineState`, `RunLifecycleStateV2_State`, +`TerminationCode_Code`, +`EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol`, +and ~200 other underscored identifiers. The outer-message wrapper +interface itself is retained (forward compatibility); only the +underscored identifier flattens. Affects ~85/98 packages. + +### 8.3 Drop the redundant enum-name prefix on members + +`PolicyType.POLICY_TYPE_ROW_FILTER` → `PolicyType.RowFilter` (PascalCase +preferred for new code; SCREAMING_SNAKE acceptable if the project policy +chooses it). Map the wire value `POLICY_TYPE_ROW_FILTER` via Zod transform. +Drop all `*_UNSPECIFIED` members and rely on the field's optional +`?:`/`undefined` for "unset". Affects ~84/98 packages. + +### 8.4 Append `Request` to every request DTO type + +`DeletePolicy` → `DeletePolicyRequest`. Eliminates verb-as-noun confusion +in import lists and resolves the `client.delete(req: Delete)` collision +patterns in `workspace`, `files`, `experiments`, `grants`, and ~75 other +packages. Affects ~80/98 packages. + +### 8.5 Drop the `Info`/`Spec`/`Details` suffix on canonical entities + +`RepoInfo` → `Repo`, `PolicyInfo` → `Policy`, `SchemaInfo` → `Schema`, +`CredentialInfo` → `Credential`, `MetastoreInfo` → `Metastore`, +`CatalogInfo` → `Catalog`. (Suffix can stay where the SDK genuinely has +both `Foo` and `FooInfo` and they mean different things.) Affects ~70/98 +packages. + +### 8.6 Adopt one acronym-casing policy + +Decide on `Pascal-then-lower` (`Url`, `Id`, `Json`, `Sql`, `Oauth`, +`Pypi`, `Aws`, `Llm`) or `ALL_CAPS-for-≤2` (`URL`, `ID`, `Json`, `Sql`, +`OAuth`, `PyPI`, `AWS`, `Llm`). Apply consistently to: +type names (`HttpRequest` vs `HTTPRequest`), +field names (`webhookUrl` vs `webhookURL`), +enum values (`URL` vs `Url` — the latter avoids JS-global collision). +Affects 98/98 packages. + +### 8.7 Replace `marshal`/`unmarshal`/`Schema` vocabulary + +Emit `encode*` / `decode*` (or `serialize*` / `deserialize*`) and drop the +`Schema` suffix on Zod helpers. Pair `parseResponse` with `serializeRequest` +in `utils.ts` for symmetry. Affects ~90/98 packages. + +### 8.8 Rename `Client` per package + +Every package exports a class literally named `Client`. Imagine a user +with `jobs`, `clusters`, `pipelines` all importing `Client`. Rename to +`Client` — `JobsClient`, `ClustersClient`, `PipelinesClient`, +`WarehousesClient`. Removes the most common cross-package alias-on-import +pattern. Affects 98/98 packages. + +### 8.9 Strip the package-name prefix from type names + +When a type name begins with the package's domain noun and the unprefixed +name does not clash with another type in the same package, drop the +prefix. `Pipelines*` → drop, `Genie*` → drop, `CleanRoom*` → drop, +`OAuthAppIntegration*` → drop where unambiguous, `Tag*` → drop in +single-domain packages. Affects ~70/98 packages. + +### 8.10 (Bonus) Surface deprecations as `@deprecated` JSDoc tags + +Today the audits found dozens of fields whose JSDoc text says "deprecated" +in prose but does not carry the `@deprecated` tag, so IDEs do not strike +them through. Examples: `Environment.client`, `Run.numberInJob`, +`ServedModel.modelName`, `EndpointCoreConfig.servedModels`, every method +in `qualitymonitor`/`qualitymonitors`. A simple template change — when +the proto description starts with "Deprecated", emit `@deprecated` — +catches all of them. + +### 8.11 (Bonus) Adopt `AsyncIterable` for pagination + +Make `list*()` return `AsyncIterable` and add `.firstPage()` for callers +who need raw pages. Removes 60+ `*Iter` companion methods. Affects ~57/98 +packages. + +--- + +## Appendix: Categories (from the per-package audits) + +The audits used a shared 20-category rubric. The most-cited categories +across all 98 audits (Category 11 "Empty / trivial wrapper types" has +been retired — see prune note in the header): + +| # | Category | Audits citing it | +|---|---|---| +| 1 | Vague / generic names | 98 | +| 6 | Misleading names | 98 | +| 3 | Acronym casing inconsistencies | 98 | +| 12 | Duplicate concepts | 95 | +| 15 | Generic field names losing meaning | 94 | +| 20 | Type-suffix tautology | 94 | +| 19 | Underspecified IDs | 93 | +| 17 | Inconsistent action verbs | 93 | +| 7 | Overly verbose names | 90 | +| 14 | Go / Java-style names | 89 | +| 5 | Cryptic abbreviations | 86 | +| 2 | Redundant enum prefix | 84 | +| 4 | Underscores in TS identifiers | 84 | +| 8 | Redundant suffix | 79 | +| 9 | Singular/plural mismatches | 78 | +| 16 | Field contradicting type domain | 77 | +| 18 | Long enum values | 73 | +| 13 | Verb-tense inconsistency | 66 | + + \ No newline at end of file diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md new file mode 100644 index 00000000..54446ab5 --- /dev/null +++ b/.agent/naming-audit/abacpolicies.md @@ -0,0 +1,266 @@ +# Naming Audit: abacpolicies + +**Path:** `packages/abacpolicies/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter, column-mask, deny, and grant policies. +**Total weird names flagged:** 40 + +## Summary +| Severity | Count | +| --- | --- | +| High | 11 | +| Medium | 17 | +| Low | 8 | +| Observation | 4 | + +## High severity + +### 1. `PolicyType.POLICY_TYPE_UNSPECIFIED` / `POLICY_TYPE_ROW_FILTER` / `POLICY_TYPE_COLUMN_MASK` / `POLICY_TYPE_DENY` / `POLICY_TYPE_GRANT` — `src/v1/model.ts:7-14` +- **Why weird:** Every value redundantly re-states the enum name (`PolicyType.POLICY_TYPE_*`). A `POLICY_TYPE_UNSPECIFIED` sentinel is a proto-buf import; idiomatic TS would use `undefined` for "not set". +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names not idiomatic in TS). +- **Suggested name:** `PolicyType.Unspecified | RowFilter | ColumnMask | Deny | Grant` (or drop `Unspecified` entirely and rely on `policyType?: PolicyType | undefined`). +- **Rationale:** TS enum members are already namespaced by the enum (`PolicyType.RowFilter`). The `POLICY_TYPE_` prefix is pure protobuf noise. + +### 2. `DeletePolicy` — `src/v1/model.ts:72` +- **Why weird:** Type whose name is a verb phrase (`DeletePolicy`) looks like it could be a function or command, not the request body. Other request types in the package follow the same broken pattern (`CreatePolicy`, `GetPolicy`, `ListPolicies`, `UpdatePolicy`). +- **Category:** 6 (misleading: name implies behaviour, actually a request DTO), 14 (Go-style naming). +- **Suggested name:** `DeletePolicyRequest` (and `CreatePolicyRequest`, `GetPolicyRequest`, `ListPoliciesRequest`, `UpdatePolicyRequest`). +- **Rationale:** TypeScript convention names request DTOs with a `Request` suffix; a bare verb-phrase noun reads as an action. Index.ts re-exports these as types, so consumers see `import type {DeletePolicy}` which looks like a function. + +### 3. `DeletePolicy_Response` — `src/v1/model.ts:82` +- **Why weird:** Underscore in identifier (proto-style nested type). Requires an `eslint-disable` for `@typescript-eslint/naming-convention`. +- **Category:** 4 (underscores in TS identifiers). +- **Suggested name:** `DeletePolicyResponse`. +- **Rationale:** TS strict-type-checked rejects `Foo_Bar`. The `eslint-disable` is a tell that the name fights the language. + +### 4. `ListPolicies_Response` — `src/v1/model.ts:173` +- **Why weird:** Underscore in identifier (proto-style nested type). Required `eslint-disable`. +- **Category:** 4 (underscores in TS identifiers). +- **Suggested name:** `ListPoliciesResponse`. +- **Rationale:** Same as `DeletePolicy_Response`. The underscore convention is a leaky proto abstraction and is not standard TypeScript. + +### 5. `PolicyInfo` — `src/v1/model.ts:190` +- **Why weird:** `Info` is a generic suffix that adds nothing — every type is "info about something". This is the central domain entity; it should just be called `Policy`. (See rule 1: `Info` is on the vague-suffix list.) +- **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix). +- **Suggested name:** `Policy`. +- **Rationale:** `Policy` is the noun the user actually thinks about. The `Info` suffix is a tic carried over from Go SDK naming conventions that does not apply in TS, where the namespace and import path already disambiguate. + +### 6. `onSecurableType: string` on `DeletePolicy` / `GetPolicy` / `ListPolicies` / `UpdatePolicy` — `src/v1/model.ts:74,135,154,335` +- **Why weird:** Typed as `string` everywhere on these request DTOs while the same field on `PolicyInfo` (`model.ts:198`) is typed as `SecurableType` enum. The values are the same domain (`CATALOG`, `SCHEMA`, ...) — the inconsistency is a bug. +- **Category:** 6 (misleading — name implies enum, actual type is `string`), 16 (field type contradicts domain). +- **Suggested name:** Keep the name but type it `SecurableType`. +- **Rationale:** Same field name with two different types across four request DTOs forces callers to remember which one is loose. This is almost certainly a generator bug worth flagging upstream. + +### 7. `onSecurableFullname` — `src/v1/model.ts:75,76,136,155,202,336` +- **Why weird:** `fullname` is one un-camelCased word. Should be `fullName` to match field-naming conventions used everywhere else in the same model (`functionName`, `tagKey`, `columnAlias`, `pageToken`, etc.). +- **Category:** 3 (acronym/casing inconsistency — `name` is one word and should follow camelCase, so `Fullname` is wrong). +- **Suggested name:** `onSecurableFullName` (wire stays `on_securable_fullname`). +- **Rationale:** Internal consistency. JS/TS convention treats `fullName` as two words; the Go SDK collapses `Fullname` but TS shouldn't blindly inherit that. + +### 8. `FunctionArgExpression` — `src/v1/model.ts:98` +- **Why weird:** `Arg` is an abbreviation for `Argument` in a type name even though the sibling type `FunctionArgument` (model.ts:108) spells it out. Within five lines the SDK uses both forms. +- **Category:** 5 (cryptic abbreviation when the long form is used right next door), 17 (inconsistency with sibling type). +- **Suggested name:** `FunctionArgumentExpression`. +- **Rationale:** Pick one. Right now `functionArgExpression` (field) shows up as a discriminator value while `functionArgument` is the containing type, which is jarring to read. + +### 9. `useSessionIdentity` field — `src/v1/model.ts:292` +- **Why weird:** Field documented as "Temporary for migrating customers to session identity. After a grace period, this field will be removed and all policies will use session identity." Shipping an explicitly temporary flag in the public SDK surface is risky — once removed, every caller breaks. +- **Category:** 6 (misleading: appears stable but is explicitly a migration toggle). +- **Suggested name:** Either omit from public type or mark `@deprecated` from day one. +- **Rationale:** Public SDK fields should outlive the API; an "everyone will be on this in 6 months" boolean shouldn't live in a stable type. Worth pushing back upstream. + +### 10. `MatchColumn` — `src/v1/model.ts:183` +- **Why weird:** Reads as a verb (`MatchColumn`) — could be a method or a type. The field that uses it is plural (`matchColumns: MatchColumn[]`), which then reads as "match columns are an array of `MatchColumn`", and a `MatchColumn` is actually a "column matcher / condition + alias pair". +- **Category:** 6 (misleading verb-as-noun), 9 (singular noun whose meaning is unclear). +- **Suggested name:** `ColumnMatcher` or `ColumnMatchCondition`. +- **Rationale:** Type names should be nouns; the verb form misleads. `ColumnMatcher` makes `matchColumns: ColumnMatcher[]` clearly read as "the matchers". + +### 11. `useSessionIdentity` and `forSecurableType` / `onSecurableType` field prefixes — `src/v1/model.ts:198,223,292` +- **Why weird:** Three different prefixes for related concepts on the same struct: `on_securable_type`, `for_securable_type`, `use_session_identity`. The `on`/`for` split (carrier vs. target securable) is subtle and easily confused. Field names alone do not communicate which is which. +- **Category:** 1 (vague — the preposition does the disambiguation), 6 (misleading without docs). +- **Suggested name:** Rename `forSecurableType` to `appliesToSecurableType` (or similar) and `onSecurableType` to `definedOnSecurableType` to make the distinction explicit. +- **Rationale:** A user reading the type should not have to consult the JSDoc to tell `for` from `on`. These names sit beside each other and look interchangeable. (Upstream concern; the docstring says "Type of securables that the policy should take effect on" while the field is `forSecurableType` — even the documentation gets the prepositions tangled.) + +## Medium severity + +### 12. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:35` +- **Why weird:** Enum value pinned by a comment that says it isn't a real securable yet: "TODO: [UC-2980] Staging tables aren't full-fleged securables yet." Internal TODOs in generated SDK enums leak abstraction. +- **Category:** 18 (questionable enum value). +- **Suggested name:** Remove until it actually is a securable, or mark `@experimental`. +- **Rationale:** Public SDK enums shouldn't contain TODO-tagged speculative values. + +### 13. `ColumnMaskOptions.using: FunctionArgument[]` — `src/v1/model.ts:56` +- **Why weird:** Field named `using` — a SQL reserved word and a generic preposition. Doesn't say what is being used. +- **Category:** 1 (vague), 10 (reserved-word-adjacent — `using` is a reserved-context keyword in JS dynamic import / TS). +- **Suggested name:** `extraArguments` / `additionalArguments` / `argumentList`. +- **Rationale:** `using` on its own carries no semantic load; readers must consult the doc to find out it's "additional positional args". Also appears on `RowFilterOptions` (model.ts:307) with the same problem. + +### 14. `ColumnMaskOptions.onColumn` — `src/v1/model.ts:51` +- **Why weird:** Preposition-prefixed field name (`onColumn`) that just identifies the masked column. Inconsistent with `functionName` (also on the same type, no preposition). +- **Category:** 1 (vague), 17 (inconsistency). +- **Suggested name:** `maskedColumnAlias` or `targetColumnAlias`. +- **Rationale:** Names should describe what the field *is*, not its prepositional relationship. + +### 15. `FunctionArgument.arg` discriminator field — `src/v1/model.ts:110` +- **Why weird:** `FunctionArgument` has a field `arg` (one of three variants). Type name and field name are near-duplicates; the field name is also an abbreviation of the type. +- **Category:** 5 (cryptic abbreviation), 11 (near-duplicate naming). +- **Suggested name:** Rename the field to `value` or `kind`. +- **Rationale:** `functionArgument.arg.$case === 'alias'` reads weirdly; the field name repeats an abbreviation of the type name. + +### 16. `FunctionArgExpression.expr` discriminator field — `src/v1/model.ts:99` +- **Why weird:** Field uses the three-letter abbreviation `expr` rather than spelling out `expression`. +- **Category:** 5 (`expr` is a cryptic abbreviation). +- **Suggested name:** `expression` (spell out). +- **Rationale:** `expr` is the kind of three-letter abbreviation `typescript.mdc` discourages. + +### 17. `TagIntrospectionExpression.expr` discriminator field — `src/v1/model.ts:313` +- **Why weird:** Same `expr` problem as above. A `TagIntrospectionExpression.expr` reads as redundant — the type is already an expression. +- **Category:** 5 (`expr` abbreviation), 17 (`expr` reused with two different meanings within model.ts). +- **Suggested name:** `value` (since the type itself is already "an expression"), or `variant`. +- **Rationale:** Reader hits `expression.expr.$case === 'tagValue'` which is noise on noise. + +### 18. `ColumnTagValueExtraction` / `TagValueExtraction` — `src/v1/model.ts:60,328` +- **Why weird:** Pair of near-identical types, named with a clunky `XExtraction` suffix. The two together describe "get tag value (on securable)" vs "get column tag value", but the names imply more weight than the types carry (each holds 1-2 strings). +- **Category:** 7 (overly verbose), 8 (redundant `Extraction` suffix — these aren't extractions; they're parameters to a `getTagValue` introspection call). +- **Suggested name:** `SecurableTagSelector` and `ColumnTagSelector` (or just `Tag` and `ColumnTag`). +- **Rationale:** The "extraction" framing is a verb forced into a noun. `Selector`/`Tag` is shorter and more accurate. + +### 19. `policyInfo` field on `CreatePolicy` / `UpdatePolicy` — `src/v1/model.ts:69,349` +- **Why weird:** Field named after the entity's awkward type (`policyInfo: PolicyInfo`). If `PolicyInfo` is renamed to `Policy`, this becomes `policy: Policy` which is much cleaner. +- **Category:** 20 (type-suffix tautology), 1 (`Info`). +- **Suggested name:** `policy` (paired with type renamed to `Policy`). +- **Rationale:** Tied to the `PolicyInfo` -> `Policy` rename (finding #5). + +### 20. `policyType: PolicyType` field on `PolicyInfo` — `src/v1/model.ts:227` +- **Why weird:** Type-suffix tautology (`policyType` field of type `PolicyType`). +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `type: PolicyType` if `PolicyInfo` is renamed to `Policy`; otherwise tolerate. +- **Rationale:** Rule 20 in spec. The wire field is `policy_type` so the marshalled JSON stays unchanged. + +### 21. `onSecurableType` / `forSecurableType` type-suffix tautology — `src/v1/model.ts:198,223` +- **Why weird:** Same as above — fields named `onSecurableType` of type `SecurableType` and `forSecurableType` of type `SecurableType`. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** Drop `Type` from the field once renaming (`onSecurable: SecurableType`, `forSecurable: SecurableType`) — though it conflicts with finding #11. Better to combine the two renames (`definedOnSecurable: SecurableType`, `appliesToSecurable: SecurableType`). +- **Rationale:** Reduces tautology and clarifies semantics at once. + +### 22. Inconsistent rename style for `*Options` types — `src/v1/model.ts:38,84,142,295` +- **Why weird:** `ColumnMaskOptions`, `DenyOptions`, `GrantOptions`, `RowFilterOptions` — four mostly-identical-shaped types describing variants of policy options. Each is a discriminator member; the `Options` suffix is redundant given the discriminator already says "this is the X options". +- **Category:** 8 (redundant suffix), 12 (duplicate concept across four similar types). +- **Suggested name:** Either keep current names but acknowledge as boilerplate, or rename to `RowFilter`, `ColumnMask`, `Deny`, `Grant` (the `$case` discriminator already disambiguates). +- **Rationale:** Generator artefact; flagging because four near-identical types is the moment to ask whether the API surface should collapse. + +### 23. `ListPolicies` request type — `src/v1/model.ts:152` +- **Why weird:** Plural type name for a singular request. Should be `ListPoliciesRequest`. Same issue as #2 but pluralisation collides with `policies: PolicyInfo[]` inside `ListPolicies_Response`, making it momentarily ambiguous which one is the type and which is the field. +- **Category:** 6 (misleading), 9 (plural request vs singular response). +- **Suggested name:** `ListPoliciesRequest`. +- **Rationale:** Tied to finding #2. + +### 24. `whenCondition` field — `src/v1/model.ts:225` +- **Why weird:** `when` prefix is a SQL keyword; the field is a free-form condition expression. Just `condition` would suffice given the field already lives on `PolicyInfo`. +- **Category:** 1 (vague prefix), 10 (reserved-word-adjacent). +- **Suggested name:** `condition` or `conditionExpression`. +- **Rationale:** `when_condition` is wire-only; the TS name can drop the redundant `when_`. + +### 25. `toPrincipals` / `exceptPrincipals` field names — `src/v1/model.ts:215,217` +- **Why weird:** Preposition-prefixed names mirror SQL `TO`/`EXCEPT` syntax (this is an ABAC-on-UC policy, the API mimics SQL `GRANT ... TO ... EXCEPT ...`). For programmatic SDK consumers, `principals` and `excludedPrincipals` would read more naturally. +- **Category:** 1 (vague), 14 (Go/SQL-style names not idiomatic for TS). +- **Suggested name:** `appliedPrincipals` / `excludedPrincipals` (or `principals` and `excludePrincipals`). +- **Rationale:** Consumers who don't know the SQL syntax will misread `to_principals` as "principal list to apply to" and miss that `except_principals` is the complement. + +### 26. `MatchColumn.condition: string` — `src/v1/model.ts:185` +- **Why weird:** A `MatchColumn` has a field called `condition` (matched column condition expression) and an `alias`. The condition could equally well be called `expression`; "condition" implies boolean, but it's actually a column-selector expression evaluated to a column. +- **Category:** 6 (misleading). +- **Suggested name:** `columnExpression` or `selector`. +- **Rationale:** Domain reading: "match columns where condition = X" suggests filtering rows; here it actually selects which columns the policy applies to. Easy to misread. + +### 27. `PolicyInfo.id` — `src/v1/model.ts:192` +- **Why weird:** Bare `id` field on `PolicyInfo` alongside `name`, `onSecurableFullname`, etc. — multiple identifier-like fields; bare `id` is underspecified. +- **Category:** 19 (underspecified id when multiple ids exist). +- **Suggested name:** `policyId`. +- **Rationale:** Disambiguates from securable identifiers in the same struct. + +### 28. `PolicyInfo.comment` — `src/v1/model.ts:210` +- **Why weird:** Doc says "Optional description of the policy" but the field is named `comment`. SQL stores DDL comments, sure, but a TS-facing field that the JSDoc calls a description should be `description`. +- **Category:** 6 (misleading — doc says description, name says comment). +- **Suggested name:** `description`. +- **Rationale:** Match the doc and avoid the SQL-DDL leak. + +## Low severity + +### 29. `unmarshalDeletePolicy_ResponseSchema` — `src/v1/model.ts:381` +- **Why weird:** Schema name carries the underscore from the type plus an `eslint-disable`. +- **Category:** 4 (underscore identifier). +- **Suggested name:** Falls out if `DeletePolicy_Response` -> `DeletePolicyResponse`. +- **Rationale:** Mechanical cascade from #3. + +### 30. `unmarshalListPolicies_ResponseSchema` — `src/v1/model.ts:440` +- **Why weird:** Same as #29. +- **Category:** 4. +- **Suggested name:** Mechanical cascade from #4. +- **Rationale:** Same. + +### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Minor; only one place in the file but flagged for consistency review across the SDK. + +### 32. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Either remove the export (if it's an unused generator default), or document why it ships per-package. +- **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. + +### 33. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` / `readStreamToEnd`. +- **Rationale:** Internal helper, low cost. Skip if generated. + +### 34. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry, or `parseResponse` / `serializeRequest`. +- **Rationale:** Pair-wise consistency aids reading. + +### 35. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions with nearly identical names handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call site. +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). +- **Rationale:** Names should differ in more than the `Http` infix. + +### 36. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Same word `Options` is reused throughout the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, `RowFilterOptions`, ...). Within this file there's also `Options` imported from `@databricks/sdk-core/api` (line 3). +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of args). +- **Rationale:** Distinguish internal context bags from user-tunable option structs. + +## Observations + +### 37. Wire/TS divergence is heavy +The model file is ~796 lines for ~15 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. + +### 38. Action-verb conventions in `Client` +The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) + +### 39. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` +The codebase uses `Http` (`HttpClient`, `HttpRequest`, `executeHttpCall`) and `URLSearchParams` (Web standard) and `url` (lowercase) and `userAgent`. Mixing `Http` (PascalCase capital-then-lower) with the imported `URLSearchParams` (ALLCAPS) is inconsistent — common across JS ecosystem and probably not worth changing, but worth noting. +- **Category:** 3 (acronym casing). + +### 40. `abac` abbreviation only appears in package name +The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. Comments on `useSessionIdentity` (model.ts:286) mention "ABAC" once. May confuse users searching by acronym. +- **Category:** 5 (cryptic abbreviation in package name). + +## Domain glossary +- `abac` — Attribute-Based Access Control (package name only; one comment at model.ts:286). +- `uc` — Unity Catalog (referenced in comment at model.ts:34 as "UC-2980", and implicitly across all types since policies live on Unity Catalog securables). +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). +- `oss` — not encountered in this package. +- `m2m`/`u2m`/`pat` — not encountered in this package. +- `iam` — not encountered, but conceptually overlaps with `Principal` references. + +## File coverage +- `src/v1/model.ts` (796 lines): read fully. +- `src/v1/client.ts` (241 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (26 lines): read fully. diff --git a/.agent/naming-audit/accountaccesscontrol.md b/.agent/naming-audit/accountaccesscontrol.md new file mode 100644 index 00000000..0c3e6efd --- /dev/null +++ b/.agent/naming-audit/accountaccesscontrol.md @@ -0,0 +1,139 @@ +# Naming Audit: accountaccesscontrol + +**Path:** `packages/accountaccesscontrol/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level Databricks IAM rule sets — list assignable roles for a resource and read/replace the grant rules attached to that resource. +**Total weird names flagged:** 18 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 7 | +| Low | 5 | +| Observation | 3 | + +## High severity + +### 1. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:73,89` +- **Why weird:** `RuleSet` and `RuleSetUpdateRequest` are structurally identical (`name`, `etag`, `grantRules`). They model the same resource — one as a response body, one as the update body — but expose it under two top-level names. `UpdateRuleSetRequest` then *wraps* `RuleSetUpdateRequest` under a `ruleSet` field, so the developer sees three overlapping shapes (`RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest`) for one concept. The "Request" suffix on the inner body type does not match how the field is used downstream (the wire payload is keyed `rule_set`, not `rule_set_update_request`). +- **Category:** 12, 11 (duplicate concepts; redundant wrapper) +- **Suggested name:** Collapse to `RuleSet` only. The update endpoint body should be `{ name, ruleSet: RuleSet }`. Remove `RuleSetUpdateRequest` entirely. +- **Rationale:** A single canonical `RuleSet` shape avoids the read/write divergence. The legacy upstream uses `RuleSetResponse` and `RuleSetUpdateRequest` as separate types because Go does not have structural typing; in TypeScript the duplication is wasteful and confusing. + +### 2. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:105` +- **Why weird:** `UpdateRuleSetRequest` has both a top-level `name` and `ruleSet.name` (because `RuleSetUpdateRequest` also carries `name`). Two `name` fields on the same request that conceptually identify the same thing is a footgun — which one wins? The wire format hints that the outer one is the URL path identifier and the inner one is the body, but nothing in the TS type encodes that. +- **Category:** 6, 16 (misleading; field contradicting type domain) +- **Suggested name:** Drop the outer `name` (use it from `ruleSet.name`), or rename the outer to `pathName`/`resourceName` to make the routing role explicit. +- **Rationale:** The doc comment on the outer field is just "Name of the rule set." — identical to the inner one. Developers will set one and not the other and silently 4xx. + +### 3. `GetRuleSetRequest.etag` semantics — `src/v1/model.ts:25` +- **Why weird:** A `GET` request type carrying an `etag` is unusual — `etag` normally rides in headers (`If-Match`/`If-None-Match`) and the field doc describes optimistic concurrency control on PUT, not GET. The field is also marshalled into the query string here (`params.append('etag', req.etag)` in `client.ts:118`), which is non-standard HTTP and easy to misuse. The name `etag` is also lowercase, contradicting common practice (`eTag`/`ETag`). The same doc text on `RuleSet.etag` then describes its read use ("freshness"). +- **Category:** 3, 6 (acronym casing; misleading) +- **Suggested name:** `minimumEtag` or `ifNoneMatch` would explain semantics; keep canonical casing as `etag` only if it matches the wire param exactly. At minimum, the doc should say "passed as `?etag=` query parameter; the server returns a snapshot at least as fresh as this etag" rather than copy-pasting the PUT-side concurrency doc. +- **Rationale:** The current name plus copy-pasted comment makes the field look like an `If-Match` header even though it is a freshness floor on GET. + +## Medium severity + +### 4. `accountId` doc string ` account ID.` — `src/v1/model.ts:7,27,107` +- **Why weird:** The literal `` tag appears in the doc comments, leaking the upstream protobuf templating markup into the public TypeScript surface. It is not Markdown, not a link, and not HTML — just stray angle brackets that will render oddly in IDE hover popups and TypeDoc. The same `accountId` doc text also doesn't disclose that this value is a fallback overridable by `ClientOptions.accountId` (per the client comment on line 41-42 of `client.ts`). +- **Category:** 14, 19 (Go/Java-style template leak; underspecified ID) +- **Suggested name:** Keep `accountId` but rewrite the doc as `"Databricks account ID. If omitted, falls back to the value supplied to ClientOptions."` +- **Rationale:** Document the type — UUID? — and remove the templating artifact. + +### 5. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:65` +- **Why weird:** The package exports a `Role` type and then immediately ignores it: `GrantRule.role` is `string`. So `Role` is the response shape from `getAssignableRolesForResource`, but `GrantRule.role` is the same identifier path serialized inline. Two representations of the same concept. +- **Category:** 12, 6 (duplicate concepts; misleading) +- **Suggested name:** Type `GrantRule.role` as `Role['name']` or a branded `RoleName` string so the two surfaces stay aligned. +- **Rationale:** Developers will write `grantRule.role = role.name` constantly because the types don't line up. + +### 6. `GetAssignableRolesForResourceRequest` / `Response` verbosity — `src/v1/model.ts:5,21` +- **Why weird:** 41 characters each. The "ForResource" suffix is implied — every assignable-roles query is for a resource (the resource is the only meaningful query param). The pair reads like a Java RPC service name (`GetForRequest`). +- **Category:** 7, 17 (overly verbose; inconsistent verb) +- **Suggested name:** `ListAssignableRolesRequest` / `ListAssignableRolesResponse`. Reflects that the operation returns a list (it already does), and aligns with REST list conventions. +- **Rationale:** Symmetry with `GetRuleSet`/`UpdateRuleSet` would suggest `Get...`, but the operation returns an array and is closer to a list semantically. Also: the corresponding method is named `getAssignableRolesForResource`, which has the same problem — `listAssignableRoles` would be cleaner. + +### 7. `getAssignableRolesForResource` method verb mismatch — `src/v1/client.ts:72` +- **Why weird:** The other two methods (`getRuleSet`, `updateRuleSet`) read as ``; this one is ``. The "ForResource" is redundant — the method already takes a `resource` field. Inconsistent action verb shape across the same service surface (also category 17, since the operation is really a `list`). +- **Category:** 7, 17 (verbose; verb inconsistency) +- **Suggested name:** `listAssignableRoles(req)`. +- **Rationale:** Three-method surface reads better as `getRuleSet`, `updateRuleSet`, `listAssignableRoles`. + +### 8. `GrantRule.principals: string[]` — `src/v1/model.ts:63` +- **Why weird:** Generic `string[]` for principals, where each entry is one of three formats (`users/`, `groups/`, `servicePrincipals/`). The shape is documented in the JSDoc but not in the type. Callers have to read the comment to know what to put in. +- **Category:** 15, 19 (generic field losing meaning; underspecified ID) +- **Suggested name:** Type the field with a discriminated union or template literal — e.g. `principals: PrincipalRef[]` where `type PrincipalRef = \`users/${string}\` | \`groups/${string}\` | \`servicePrincipals/${string}\``. +- **Rationale:** TypeScript can encode this; the Go SDK cannot. The 1:1 port leaves type information on the floor. + +### 9. `RuleSet.name` and `GrantRule.role` are both `name` paths — `src/v1/model.ts:75,65` +- **Why weird:** "Name" in this API is a hierarchical resource path (`accounts//ruleSets/default`), not a human-readable label. Same overload for `role` (`roles/account.admin`). Calling these `name`/`role` and typing them as `string` hides that they are resource paths. +- **Category:** 15, 16 (generic field; field contradicting domain) +- **Suggested name:** `ruleSet.resourceName`, `grantRule.roleName` (or branded template-literal types). At minimum the JSDoc should explicitly say "resource path". +- **Rationale:** Half of all integration bugs in this API will be wrong-format names. The type system can help. + +### 10. `grantRules` plural inside `RuleSet` vs `GrantRule` (singular type, plural field) — `src/v1/model.ts:86` +- **Why weird:** Not wrong, but worth noting: `RuleSet.grantRules: GrantRule[]` is fine; however the wire form uses `grant_rules` and the doc comment on `RuleSet` does not mention `grantRules` at all. The single-rule case is also confusing: a `RuleSet` is a *set of* `GrantRule`s, but a `GrantRule` itself binds N principals to 1 role — so a "rule" is many-to-one. +- **Category:** 9, 6 (singular/plural; misleading) +- **Suggested name:** Keep `grantRules`, but document explicitly that one rule = N principals × 1 role, and a rule set = N rules. Consider `roleGrants: GrantRule[]` as the field name — closer to industry vocabulary (IAM role grants). +- **Rationale:** Improves discoverability. + +## Low severity + +### 11. `etag` casing — `src/v1/model.ts:51,85,101` +- **Why weird:** Lowercase `etag` (rather than `eTag`/`ETag`/`etag`). HTTP spec uses `ETag`. JavaScript ecosystem split is roughly even, but most TS SDKs (AWS, Azure, GitHub Octokit) use `etag` lowercase, so this is *probably* fine. Flag it for consistency review only. +- **Category:** 3 (acronym casing) +- **Suggested name:** Confirm the project-wide policy. If the codebase uses `eTag` elsewhere, align here. +- **Rationale:** Defer to global policy. + +### 12. `accountId` vs `account_id` snake-case duality — `src/v1/model.ts:7` +- **Why weird:** The TS interface uses `accountId`, but the marshal/unmarshal transforms (line 181) convert to `account_id`. This is intentional and standard for a generated SDK; flagging only because it means the public surface is camelCase but logs and wire bodies are snake_case. Nothing to do. +- **Category:** 14 (Go/Java-style name parallel) +- **Suggested name:** None — this is correct. +- **Rationale:** Documenting the convention. + +### 13. `GetRuleSetRequest.name` ambiguity with `RuleSet.name` — `src/v1/model.ts:38` +- **Why weird:** A request type and a response type both have a `name` field with subtly different semantics: the request `name` is the *lookup key* the caller supplies; the response `name` is the *canonical name* the server returns. Same word, two roles. Common pattern, but worth flagging. +- **Category:** 1 (vague) +- **Suggested name:** Acceptable, but consider `GetRuleSetRequest.resourceName` for clarity. +- **Rationale:** Minor readability win. + +### 14. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +- **Why weird:** This helper is `export`ed from `utils.ts`. It is not used by `client.ts` and is not re-exported from `index.ts`. Either it is dead code or the export modifier is wrong. +- **Category:** 11 (effectively trivial / dead) +- **Suggested name:** Drop the `export` keyword if internal-only; if it is meant for other generated clients, move it to a shared core package. +- **Rationale:** Hygiene. + +### 15. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` +- **Why weird:** The package imports `CallOptions` from `@databricks/sdk-options/call` and defines its own `HttpCallOptions` here. The names suggest the latter is a subtype/extension of the former, but they actually describe different concerns — `CallOptions` is retry/signal/timeout policy; `HttpCallOptions` is request + client + logger bundle. The naming makes them look related. +- **Category:** 1 (vague/generic) +- **Suggested name:** `HttpExecutionContext` or `HttpCallContext`. +- **Rationale:** Disambiguates from the public `CallOptions`. + +## Observations + +### O1. `Client` is the only exported class — `src/v1/client.ts:39` +- The class is just `Client`. With `import { Client } from '@databricks/sdk-accountaccesscontrol/v1'` the consumer sees a bare `Client` symbol. This is consistent across all generated packages, so it is a project-wide pattern, but it makes IDE autocomplete and stack traces ambiguous when multiple service clients are imported in the same file (everyone is `Client`). Common workarounds (`import { Client as AccountAccessControlClient }`) push the rename burden onto the user. Worth flagging at the project level. + +### O2. `executeCall` / `executeHttpCall` naming — `src/v1/utils.ts:26,65` +- Two functions with overlapping names. `executeCall` is the public-CallOptions translator; `executeHttpCall` is the wire-level request executor. The names do not signal that `executeCall` wraps the `Call` callback (which itself wraps `executeHttpCall`). Could be `applyCallOptions` and `sendHttpRequest` respectively. Generated code; flag for upstream. + +### O3. `parseResponse` / `marshalRequest` asymmetry — `src/v1/utils.ts:113,119` +- The pair are conceptual inverses (decode wire → typed; encode typed → wire) but use different verbs. `parseResponse`/`serializeRequest` or `unmarshalResponse`/`marshalRequest` would pair better. Generated code. + +## Domain glossary +- `accountId` — Databricks account UUID (the top-level tenant container, distinct from a workspace). +- `etag` — HTTP entity tag used here both as a freshness floor on GET and as an optimistic concurrency token on PUT. +- `iam` — Identity and Access Management; the broader Databricks IAM surface this package is a subset of. +- `principal` — User, service principal, or group — the subject of an access rule. +- `Role` — Reference to a grantable account-level role (e.g. `roles/account.admin`). +- `RuleSet` — A versioned collection of `GrantRule`s attached to a resource. +- `GrantRule` — A binding of N principals to 1 role within a `RuleSet`. +- `SP_ID` / `SERVICE_PRINCIPAL_APPLICATION_ID` — Service principal application ID (UUID). +- `resource` — Hierarchical name identifying what the rule set or roles list applies to (account, group, service principal, or tag policy). + +## File coverage +- `src/v1/model.ts` (185 lines): read fully. +- `src/v1/client.ts` (171 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (17 lines): read fully. +- `package.json` (41 lines): read for context. diff --git a/.agent/naming-audit/accountaccesscontrolproxy.md b/.agent/naming-audit/accountaccesscontrolproxy.md new file mode 100644 index 00000000..9f230b20 --- /dev/null +++ b/.agent/naming-audit/accountaccesscontrolproxy.md @@ -0,0 +1,266 @@ +# Naming Audit: accountaccesscontrolproxy + +**Path:** `packages/accountaccesscontrolproxy/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level access control via rule sets that bind roles +to principals (users, groups, service principals, tag policies), exposed as a +"proxy" variant whose surface area is indistinguishable from the sibling +`accountaccesscontrol` package. +**Total weird names flagged:** 29 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `accountaccesscontrolproxy` | (package) | package | High | 12 Duplicate concepts | 1:1 surface duplicate of sibling `accountaccesscontrol` — same types, same methods, same URL paths; "proxy" is not encoded anywhere in the API. | +| 2 | package `accountaccesscontrolproxy` | (package) | package | High | 14 Go/Java-style names not idiomatic TS | Long, undelimited compound name (`accountaccesscontrolproxy`) is hard to parse; should be `account-access-control-proxy` or split into a `proxy` subpath. | +| 3 | `GetAssignableRolesForResourceRequest` | model.ts:5 | interface | Medium | 7 Overly verbose | 36-char identifier; "ForResource" is implicit since the only field is `resource`. Drop to `GetAssignableRolesRequest`. | +| 4 | `GetAssignableRolesForResourceResponse` | model.ts:21 | interface | Medium | 7 Overly verbose | 37-char identifier; same issue as #3. Drop to `GetAssignableRolesResponse`. | +| 5 | `Role.name` | model.ts:70 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `Role.name` carries the whole semantic — the value is the role identifier itself. `roleName` or `id` would communicate the meaning. | +| 6 | `GetRuleSetRequest.name` | model.ts:38 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning | `name` here is actually a fully-qualified resource path (`accounts//ruleSets/default`). Should be `ruleSetName` or `resourceName`. | +| 7 | `GetRuleSetRequest.etag` | model.ts:51 | field | Low | 3 Acronym casing inconsistencies | Field is `etag` (all lowercase) but JSDoc uses `eTag`/`Etag`/`ETag` inconsistently within the same comment. `ETag` is the HTTP-standard casing (RFC 7232 §2.3). | +| 8 | `GetRuleSetRequest` shape | model.ts:25 | interface | Medium | 1 Vague/generic without domain context | "RuleSet" tells the reader nothing about the access-control domain; in isolation it could be a firewall rule, a SQL rule, etc. `AccessControlRuleSet` would carry domain. | +| 9 | `GrantRule` | model.ts:54 | interface | Low | 1 Vague/generic without domain context | Same domain ambiguity as `RuleSet`; would be clearer as `AccessControlGrantRule` or `RoleGrantRule`. | +| 10 | `GrantRule.principals` | model.ts:63 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | Field is a `string[]`, but each value is a path like `users/` / `groups/` / `servicePrincipals/`. The string-array typing erases the discriminated structure; `principalNames` or `principalRefs` would at least flag that these are references, not free-form strings. | +| 11 | `GrantRule.role` | model.ts:65 | field | Medium | 17 Inconsistent action verbs, 15 Generic field names losing meaning | Singular `role: string` here, but the `Role` interface (model.ts:68) uses `name`. A `GrantRule.role` should be either a `Role` or a clearly-typed `roleName`. | +| 12 | `RuleSet` | model.ts:73 | interface | High | 12 Duplicate concepts | Has identical shape to `RuleSetUpdateRequest` (model.ts:89): `name`, `etag`, `grantRules`. One of them is redundant. | +| 13 | `RuleSet.name` | model.ts:75 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning | Same problem as #6 — this is a fully-qualified path, not a human-readable name. Rename to `ruleSetName` or `resourceName`. | +| 14 | `RuleSet.etag` | model.ts:85 | field | Low | 3 Acronym casing inconsistencies | Same `etag` vs `ETag` (RFC 7232) issue as #7. | +| 15 | `RuleSet.grantRules` | model.ts:86 | field | Low | 9 Singular/plural mismatches | Plural is correct, but the wire form is `grant_rules` (model.ts:144) — underscore vs camelCase split is a real coupling point. Worth checking that the marshal/unmarshal pair is the only place that needs to know. | +| 16 | `RuleSetUpdateRequest` | model.ts:89 | interface | High | 12 Duplicate concepts, 13 Verb-tense inconsistency | Same fields as `RuleSet`. The "UpdateRequest" suffix collides naming with the outer `UpdateRuleSetRequest` (model.ts:105), giving two overlapping `*UpdateRequest`/`Update*Request` shapes for the same operation. | +| 17 | `RuleSetUpdateRequest` vs `UpdateRuleSetRequest` | model.ts:89, 105 | interface pair | High | 13 Verb-tense inconsistency, 12 Duplicate concepts | Two side-by-side request types whose names invert noun/verb order (`RuleSetUpdateRequest` vs `UpdateRuleSetRequest`). Inevitable confusion; one is the outer envelope (`{accountId, name, ruleSet}`), the other is the inner payload. Inner should be named `RuleSetPayload`, `RuleSetSpec`, or merged with `RuleSet`. | +| 18 | `UpdateRuleSetRequest.name` | model.ts:109 | field | High | 12 Duplicate concepts | `name` appears at the outer level AND inside `ruleSet.name`. Which one wins? The Go-style nesting is preserved verbatim, but a TS consumer has to guess. | +| 19 | `UpdateRuleSetRequest.ruleSet` | model.ts:110 | field | Low | 7 Overly verbose | Outer envelope wraps a `ruleSet: RuleSetUpdateRequest`. Could be flattened. | +| 20 | `unmarshalGetAssignableRolesForResourceResponseSchema` | model.ts:113 | const | Medium | 7 Overly verbose | 50-char identifier. Generator should drop `Schema` (tautology with `z.ZodType`) or fold into `Codec` namespace. | +| 21 | `unmarshalRoleSchema`, `unmarshalRuleSetSchema`, `unmarshalGrantRuleSchema` | model.ts:122, 132, 140 | const | Low | 20 Type-suffix tautology | The `Schema` suffix is redundant with the `z.ZodType<...>` annotation. `unmarshalRole`/`roleDecoder` would be cleaner. | +| 22 | `marshalGrantRuleSchema`, `marshalRuleSetUpdateRequestSchema`, `marshalUpdateRuleSetRequestSchema` | model.ts:152, 162, 174 | const | Low | 20 Type-suffix tautology, 17 Inconsistent action verbs | Same as #21. Also: pairing is `marshal*` / `unmarshal*` (Go-idiom). TS convention would be `encode*` / `decode*` or `serialize*` / `deserialize*`. | +| 23 | `Client` | client.ts:39 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier; once imported into a consumer that uses multiple Databricks clients, every one is just `Client`. Should be `AccessControlProxyClient` or aliased on export. | +| 24 | `Client.getAssignableRolesForResource` | client.ts:72 | method | Medium | 7 Overly verbose | "ForResource" is implicit (only one parameter is the resource); `getAssignableRoles(req)` reads cleanly. | +| 25 | `HttpCallOptions` | utils.ts:15 | interface | Low | 1 Vague/generic without domain context | Bundle of `{request, httpClient, logger}` named generically. Inside a single file this is fine; if it ever leaks out, `ExecuteHttpCallParams` would self-document. | +| 26 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions in the same file with overlapping vocabulary. `executeCall` (orchestrates retries/timeouts) and `executeHttpCall` (does one HTTP roundtrip) are two different concepts — name them so. e.g. `runWithOptions` / `sendRequest`. | +| 27 | `parseResponse` | utils.ts:113 | function | Low | 17 Inconsistent action verbs | Naming pair is `parseResponse` (decode) and `marshalRequest` (encode). Either `parse`/`format` or `marshal`/`unmarshal`, not a mix. | +| 28 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 21 Dead code | Exported from `utils.ts` but never imported in `client.ts`. Either dead code or for future generated calls. | +| 29 | `PACKAGE_SEGMENT` | client.ts:34 | const | Low | 1 Vague/generic without domain context | Could be `USER_AGENT_PACKAGE_SEGMENT` to clarify what "segment" means at the call site. | + +--- + +## High severity (must fix) + +### H1. Whole-package duplication: `accountaccesscontrolproxy` vs `accountaccesscontrol` + +The two packages have: +- The **same** seven exported types: `GetAssignableRolesForResourceRequest`, + `GetAssignableRolesForResourceResponse`, `GetRuleSetRequest`, `GrantRule`, + `Role`, `RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest`. +- The **same** three client methods: `getAssignableRolesForResource`, + `getRuleSet`, `updateRuleSet`. +- The **same** API path: `/api/2.0/preview/accounts//access-control/...`. + +The user instruction calls out: *"Pay extra attention: the word 'proxy' in the +package name suggests this is a proxy variant. Flag if 'Proxy' appears in every +type name redundantly."* + +The opposite is true — `Proxy` appears **nowhere** in the model, client, or +URL. The only differentiation is the package name. This is a category 12 +(duplicate concepts) failure at the package level. Either: +- Merge the two packages, +- Or surface the proxy semantics in the types (`ProxyClient`, different URL, + different fields). + +Until that is done, every consumer has to guess which package to import; once +imported, the symbols collide on re-export. + +### H2. Stuttering update-request pair (`RuleSetUpdateRequest` vs `UpdateRuleSetRequest`) + +```ts +export interface RuleSetUpdateRequest { name?, etag?, grantRules? } +export interface UpdateRuleSetRequest { accountId?, name?, ruleSet?: RuleSetUpdateRequest } +``` + +Two types whose names differ only in word order (one is a NounVerb suffix, the +other is a VerbNoun prefix) and which both carry a `name` field. Reviewers and +consumers will mis-pick them. Rename the inner type to `RuleSetSpec`, +`RuleSetPayload`, or eliminate it by reusing `RuleSet`. + +### H3. `name` overload at multiple levels of `UpdateRuleSetRequest` + +`UpdateRuleSetRequest.name` and `UpdateRuleSetRequest.ruleSet.name` both exist +and both are strings. No JSDoc clarifies which one is canonical. The Go SDK +likely tolerates this because callers fill the entire envelope. In TS, the +guidance should be explicit: one field, or both fields with clear precedence. + +### H4. `name` is an opaque resource path, not a human-readable name + +Both `GetRuleSetRequest.name` and `RuleSet.name` carry strings like +`accounts//ruleSets/default`. Calling that a "name" is misleading +— it is a fully-qualified resource path. Rename to `ruleSetName`, +`resourceName`, or `resourcePath`, or introduce a branded `RuleSetName` type. + +--- + +## Medium severity (worth pushing back on) + +### M1. Verbose request/response names + +`GetAssignableRolesForResourceRequest`/`Response` are 36/37 characters. Because +the request only has the `resource` field, `ForResource` is implicit. Suggest +`GetAssignableRolesRequest`/`Response`. + +### M2. `Role.name` is a vague field name + +```ts +export interface Role { name?: string | undefined; } +``` + +`name` is a vague field name. In context the value is the role's identifier +itself; `roleName` or `id` would be clearer. + +### M3. `GrantRule.role: string` vs `Role.name: string` + +`GrantRule.role` is a string that semantically references a `Role`. Either +type it as `Role` (or `Role['name']`), rename to `roleName` to match the +referent, or unify on one shape. + +### M4. Generic-domain types: `RuleSet`, `GrantRule` + +In isolation these names give no hint they belong to access control. A +`RuleSet` could be a firewall, a SQL rewrite, a tag-policy rule set, etc. The +SDK has only the package boundary to disambiguate. Consider prefixing types in +the same file (`AccessControlRuleSet`, `AccessControlGrantRule`) when the +package itself is also generic. + +### M5. `executeCall` vs `executeHttpCall` + +Both live in `utils.ts`. They do different things: +- `executeCall` translates `CallOptions` to `Options` and dispatches retries. +- `executeHttpCall` does a single HTTP roundtrip and converts errors. + +Two near-identical names within one file is a navigation hazard. Suggested: +`runWithOptions` / `sendRequest`. + +### M6. `Client` is unqualified + +```ts +export class Client { ... } +``` + +A consumer that imports `{Client}` from multiple Databricks packages has to +alias every import. Either: +- Export as `AccessControlProxyClient`, or +- Rely on namespace imports + (`import * as accountAccessControlProxy from ...`). + +--- + +## Low severity (nits) + +### L1. Acronym casing for `etag` + +The wire and field name is `etag` (lowercase). The JSDoc in the same comment +block uses `eTag`, `Etag`, and `ETag` interchangeably. RFC 7232 §2.3 defines +the header as `ETag`. Pick one. + +### L2. `Schema` suffix tautology + +`unmarshalRoleSchema: z.ZodType` — the `Schema` suffix duplicates the +type annotation. Pattern is consistent across the SDK, so this is a +generator-wide concern, not unique to this package. + +### L3. `marshal`/`unmarshal` are Go-idioms + +JS/TS conventions are `JSON.stringify`/`JSON.parse`, `encode`/`decode`, or +`serialize`/`deserialize`. `marshal`/`unmarshal` is a Go transliteration. (Go +SDK `encoding/json` uses `Marshal`/`Unmarshal`. TS ecosystem does not.) + +### L4. `parseResponse` vs `marshalRequest` + +Mixing `parse`/`marshal` action verbs in the same file. Either both +`parse`/`format` or both `marshal`/`unmarshal`. + +### L5. `flattenQueryParams` is exported but never imported + +`utils.ts:123` exports `flattenQueryParams`. `client.ts` never imports it (it +builds query strings inline via `URLSearchParams`). Either: +- Remove it (dead code), or +- Use it (current inline code reproduces a subset of its logic). + +### L6. `PACKAGE_SEGMENT` + +Used only for the User-Agent header. Renaming to +`USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory: +`createDefault().with(USER_AGENT_PACKAGE_SEGMENT)`. + +### L7. `HttpCallOptions` + +Internal `interface` with `{request, httpClient, logger}`. Could be inlined +into `executeHttpCall` as positional parameters, or renamed +`ExecuteHttpCallParams` to disambiguate from `CallOptions` (which is a public +type). + +### L8. `req` parameter naming in client methods + +```ts +async getAssignableRolesForResource(req: GetAssignableRolesForResourceRequest, ...) +``` + +`req` is fine, but it leans Go-idiomatic. TS/JS code more commonly uses +`request` or `params`. Minor stylistic point. + +--- + +## Observations (not flags) + +- **Generator marker:** Every file is prefixed with `// Code generated from + API definition by Databricks SDK Generator. DO NOT EDIT.` so all naming + issues here must be fixed upstream in the generator/spec. +- **No enums.** The package has zero enum types, so categories 2 (redundant + enum prefixes) and 18 (long enum values) do not apply. +- **No underscores in identifiers.** TS-facing identifiers are camelCase; wire + identifiers use `snake_case` and are translated in the zod `transform` + callbacks (model.ts:144-149, 168-172, 180-184). Clean here. +- **No `Url`/`URL`, `Id`/`ID`, `Sql`, `Json`, `Oauth` casing collisions.** The + only acronym in the public surface is `accountId` (camelCase) and `etag` + (all-lower) — flagged separately under L1. +- **No reserved-word collisions** (no `delete`, `class`, `new`, etc. as field + names). +- **Optionality model:** every field is `T | undefined`. This matches the + rest of the SDK and the `exactOptionalPropertyTypes` TS setting. No issue. +- **Versioning:** only `v1` exists; nothing to compare across versions. +- **Tests:** there is no `tests/` directory for this package. +- **`index.ts` re-export style:** All seven types are re-exported as + `export type {...}`, which is correct for `verbatimModuleSyntax`. No + issue. +- **`Client` constructor throws plain `Error`** for missing `host` (client.ts:53). + Consistent with sibling packages, but not a naming concern. + +--- + +## Domain glossary (as inferred from this code) + +| Term | Meaning in this package | +|------|-------------------------| +| **Account ID** | The numeric Databricks account identifier (path parameter ``). | +| **Resource** | A fully-qualified identifier for the thing being secured: account, group, service principal, or tag policy. Encoded as a slash-delimited path (e.g. `accounts//groups/`). | +| **Rule set** | A collection of grant rules attached to a resource. Currently a single `default` rule set per resource. | +| **Grant rule** | A `(role, principals[])` pair: which role is granted to which principals on the rule set's resource. | +| **Role** | An identifier (string-shaped) for a permission bundle; `Role.name` carries the identifier itself. | +| **Principal** | A user (`users/`), group (`groups/`), or service principal (`servicePrincipals/`). | +| **Etag** | Opaque versioning token for optimistic concurrency on rule set updates. | +| **Assignable role** | A role that can appear in a grant rule for a given resource. | +| **Proxy** | Not visible anywhere in the API surface — the package name is the only signal. See H1. | + +--- + +## File coverage + +| File | Lines | Exports counted | Audited | +|------|-------|-----------------|---------| +| `src/v1/model.ts` | 185 | 7 interfaces, 7 zod consts | yes | +| `src/v1/client.ts` | 170 | 1 class, 3 public methods | yes | +| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 16 | 1 class re-export, 7 type re-exports | yes | + +Every type, field, enum value (none), and method enumerated above is +accounted for. diff --git a/.agent/naming-audit/accountsettings.md b/.agent/naming-audit/accountsettings.md new file mode 100644 index 00000000..8a46859a --- /dev/null +++ b/.agent/naming-audit/accountsettings.md @@ -0,0 +1,341 @@ +# Naming Audit: accountsettings + +**Path:** `/home/parth.bansal/sdk-js/packages/accountsettings/` +**Versions audited:** v1 +**Inferred domain:** Account-level Databricks settings governing compliance profiles, IP access toggles, legacy-feature flags, ESM/CSP enablement, LLM-proxy partner-powered AI, and the Personal Compute default policy. +**Total weird names flagged:** 43 + +## Summary table + +| # | Severity | Category | Identifier | File:line | +|---|----------|----------|------------|-----------| +| 1 | High | Redundant enum prefix | `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10` | +| 2 | High | Acronym casing / cryptic abbreviation | `DcpAccountEnableMessage` (DCP) | `model.ts:61,126` | +| 3 | High | Cryptic abbreviation | `Csp*` (CSP) family | `model.ts:92-124,286-300,454-463` | +| 4 | High | Cryptic abbreviation | `Esm*` (ESM) family | `model.ts:242-268,318-332,478-487` | +| 5 | High | Cryptic abbreviation | `Llm*` (LLM) family | `model.ts:334-364,382-418,490-511` | +| 6 | High | Underscore in TS identifier | `DcpAccountEnableMessage_Value` | `model.ts:61` | +| 7 | High | Generic field name | `value` (everywhere on `*Setting` types) | `model.ts:82-85, 118-124, 127, 236-239, 262-268, 398, 417, 436-439` | +| 8 | High | Generic + cryptic field | `acctIpAclEnable` | `model.ts:83-84` | +| 9 | High | Generic field name | `booleanVal` discriminator | `model.ts:398, 417` | +| 10 | High | Underspecified ID | `accountId` (no type/format hint) | `model.ts:131,161,191,271,...` | +| 11 | High | Domain-redundant suffix | `*Setting` suffix duplicating `Settings` package | `model.ts:102,246,420` and elsewhere | +| 12 | Medium | Type-suffix tautology | `CspEnablementAccountSetting` | `model.ts:102` | +| 13 | Medium | Type-suffix tautology | `EsmEnablementAccountSetting` | `model.ts:246` | +| 14 | Medium | Type-suffix tautology | `PersonalComputeSetting` | `model.ts:420` | +| 15 | Medium | Duplicate concept | `*Account` vs `*AccountSetting` parallel naming | `model.ts:92 vs 102; 242 vs 246` | +| 16 | Medium | Misleading | `LlmProxyPartnerPoweredEnforce` | `model.ts:401` | +| 17 | Medium | Misleading | `LlmProxyPartnerPoweredAccount` | `model.ts:382` | +| 18 | Medium | Verb-tense / action verb | `AccountIpAccessEnable` (verb as noun) | `model.ts:66` | +| 19 | Medium | Verb-tense / action verb | `DisableLegacyFeatures` (verb-phrase as noun) | `model.ts:220` | +| 20 | Medium | Verb-tense / action verb | `DcpAccountEnableMessage` (verb in noun position) | `model.ts:126` | +| 21 | Medium | Inconsistent action verbs | `delete*` reverts to default (not actual delete) | `client.ts:104,184` | +| 22 | Medium | Singular/plural mismatch | `complianceStandards` array on type named `CspEnablementAccount` (no list role implied) | `model.ts:99` | +| 23 | Medium | Misleading | `settingName` always coerced to `"default"` server-side | `model.ts:81,117,...; client.ts:109,...` | +| 24 | Medium | Misleading | `settingTypeName` ignored (path param wins) | `client.ts:111-113` (no doc) | +| 25 | Medium | Vague / overly verbose | `*EnablementAccount` family naming | `model.ts:92,242` | +| 26 | Medium | Overly verbose | `UpdateLlmProxyPartnerPoweredEnforceRequest` | `model.ts:502` | +| 27 | Medium | Overly verbose | `UpdateCspEnablementAccountSettingRequest` | `model.ts:454` | +| 28 | Medium | Acronym casing | `Ip` vs `IP` in `AccountIpAccessEnable` | `model.ts:66` | +| 29 | Medium | Acronym casing | `Id` vs `ID` in `accountId` | `model.ts:131,...` | +| 30 | Medium | Method name redundancy | `getCspEnablementAccountSetting` / etc. | `client.ts:262,302,...` | +| 31 | Medium | Method name redundancy | `updatePersonalComputeSetting` | `client.ts:682` | +| 32 | Medium | Duplicate concept | `Account` repeated in nearly every type | `model.ts` passim | +| 33 | Low | Acronym casing | `etag` field cased as `etag` everywhere but doc says "eTag" | `model.ts:68,75` | +| 34 | Low | Cryptic abbreviation | `acct_ip_acl_enable` wire key | `model.ts:530,541-543`; `client.ts:109,229,500` | +| 35 | Low | Cryptic abbreviation | `dcp_acct_enable` wire key | `client.ts:189,463,686` | +| 36 | Low | Cryptic abbreviation | `shield_csp_enablement_ac` / `shield_esm_enablement_ac` (trailing `_ac`) | `client.ts:266,343,529,590` | +| 37 | Low | Long enum value | `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10` | +| 38 | Low | Long enum value | `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE` | `model.ts:19-53` | +| 39 | Low | Verb-tense inconsistency | `Enable` (imperative) vs `Enablement` (noun) co-exist | `model.ts:66 vs 92,102` | +| 40 | Low | Singular/plural mismatch | `DisableLegacyFeatures` (plural type with singular boolean) | `model.ts:220-239` | +| 41 | Low | Acronym casing | `Url` vs `URL` in `httpReq.url` (field defined upstream) | `utils.ts:71,103` | +| 42 | Low | Inconsistent action verbs | `revert` semantics doc'd, but method named `delete*` | `client.ts:104,184` | +| 43 | Low | Vague / generic field | `setting?` on update requests | `model.ts:449,461,473,485,497,509,521` | + +--- + +## High severity + +### 1. `COMPLIANCE_STANDARD_UNSPECIFIED` — redundant enum prefix +- **File:line:** `model.ts:10` +- **Category:** Redundant enum prefix (`X_X_Y` pattern) +- **Suggestion:** Just `UNSPECIFIED`. +- **Rationale:** The enum is already named `ComplianceStandard`, so `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` triple-stutters the namespace. TypeScript enums are accessed via the enum identifier; the redundant prefix is a proto3-wire artefact that should not bleed into the TS surface. (All other members — `HIPAA`, `PCI_DSS`, etc. — correctly omit the prefix, making the inconsistency starker.) + +### 2. `DcpAccountEnableMessage` — undocumented cryptic acronym ("DCP") +- **File:line:** `model.ts:61, 126` +- **Category:** Cryptic abbreviation +- **Suggestion:** `DefaultComputePolicy` or, at minimum, attach a doc comment explaining the acronym. The whole type is a proto wrapper around a 2-value enum and could be inlined as `PersonalComputeAccess` with values `ON | DELEGATE`. +- **Rationale:** "DCP" is not defined anywhere in this package. From the surrounding wire path `dcp_acct_enable` and the doc on `PersonalComputeSetting`, it appears to mean "default Personal Compute policy" — but a reader has to reverse-engineer that. A 1:1 port may have to keep the type for compatibility, but the JSDoc must explain the acronym. + +### 3. `Csp*` family — undocumented cryptic acronym ("CSP") +- **File:line:** `model.ts:92, 102` and request variants +- **Category:** Cryptic abbreviation +- **Suggestion:** Spell out `ComplianceSecurityProfile` in the type names or add a top-of-file JSDoc glossary. The first comment on line 96 finally expands "Compliance Security Profile (CSP)" but only in passing — the type name itself stays cryptic. +- **Rationale:** "CSP" overloads heavily in web context (Content Security Policy), so the abbreviation is misleading as well as cryptic. The expansion is documented but only deep inside a field comment. + +### 4. `Esm*` family — undocumented cryptic acronym ("ESM") +- **File:line:** `model.ts:242, 246` +- **Category:** Cryptic abbreviation +- **Suggestion:** `EnhancedSecurityMonitoring*` or attach an inline doc. The method JSDoc on `client.ts:338` finally expands it ("enhanced security monitoring") — but the type itself never does. +- **Rationale:** Same problem as CSP. The reader has to grep the client to find the expansion. + +### 5. `Llm*` family — cryptic / underspecified acronym ("LLM") +- **File:line:** `model.ts:334-418, 490-511` +- **Category:** Cryptic abbreviation + verbose stacking +- **Suggestion:** `LargeLanguageModelProxyPartnerPowered*` is unwieldy, but a domain-specific short name like `AiProxyPartnerPowered*` or `ModelProxyPartnerPowered*` would at least drop the redundant "Llm" capitalization issue. Better: a single top-level type `PartnerPoweredAi*` with sub-fields. +- **Rationale:** "Llm" mixes acronym + token-casing rules: TypeScript style says either `LLM` (acronym-case for known acronyms) or `Llm` (Pascal-token-case). The codebase consistently uses `Llm`, but the larger problem is stacking cryptic + cryptic + ambiguous — "LlmProxyPartnerPoweredEnforce" parses with several plausible bracketings. + +### 6. `DcpAccountEnableMessage_Value` — underscore in TS identifier +- **File:line:** `model.ts:61` +- **Category:** Underscore in TS identifier, Go/Java-style name not idiomatic TS +- **Suggestion:** `DcpAccountEnableValue` (drop the proto `_Value` suffix), or hoist as a top-level enum like `PersonalComputeAccess`. The codebase already has an `eslint-disable` comment ("Proto-style nested enum name") on the line that highlights this is a known violation. +- **Rationale:** TypeScript identifiers conventionally use PascalCase without underscores; the `_Value` is a generator-level proto-to-TS holdover. The eslint disable confirms the codebase considers it a violation; the question is whether to clean it up at the generator level. + +### 7. `value` field on every `*Setting` discriminated union — generic field name losing meaning +- **File:line:** `model.ts:82, 118, 127, 236, 262, 398, 417, 436` +- **Category:** Generic field name losing meaning +- **Suggestion:** Name the field after what it discriminates: `payload`, or after the specific domain concept (e.g. `enabled`, `personalCompute`) per use site. +- **Rationale:** Eight different types in this package use a `value?: {...}` field, each with a discriminated union of `$case: ''`. Because the field name is identical across all of them, IDE autocomplete and code review provide no hint about what the field actually represents at any given use site — `setting.value` reads identically whether the underlying meaning is "IP ACL toggle", "legacy features disabled", or "partner-powered AI enforcement". + +### 8. `acctIpAclEnable` — cryptic + abbreviated discriminator value +- **File:line:** `model.ts:83-84` +- **Category:** Cryptic abbreviation, generic field name +- **Suggestion:** `accountIpAclEnabled` (or simply `enabled`). +- **Rationale:** `acct` is a non-standard abbreviation of `account` that saves three characters. Inside a TypeScript SDK there is no length-budget reason to abbreviate. The fact that the parent type is already `AccountIpAccessEnable` makes the abbreviation noise. + +### 9. `booleanVal` — generic discriminator value +- **File:line:** `model.ts:398, 417` +- **Category:** Generic field name losing meaning +- **Suggestion:** `enabled` (it is, in fact, a boolean toggle of partner-powered AI features per the method doc). +- **Rationale:** `booleanVal` describes the *type* not the *meaning* of the field. In a domain-specific union case, the case name should describe what it represents. (`acctIpAclEnable` and `disableLegacyFeatures` and `personalCompute` follow domain naming; `booleanVal` does not.) + +### 10. `accountId` — underspecified ID +- **File:line:** `model.ts:131, 161, 191, 271, 287, 303, 319, 335, 351, 367, 443, 455, 467, 479, 491, 503, 515` +- **Category:** Underspecified ID +- **Suggestion:** Add a doc comment that names the type (UUID? numeric? Databricks-internal?). Currently the `UpdateAccountIpAccessEnableRequest.accountId` is documented (` account ID of the account being managed.`) but the others are not. +- **Rationale:** "accountId" leaves the reader unsure whether to pass `"123"`, `"abcd-...-uuid"`, or `"my-account@databricks.com"`. The doc inconsistency (only the update variants document it) makes this worse. + +### 11. `*Setting` suffix vs package name `accountsettings` +- **File:line:** package level +- **Category:** Redundant suffix in domain +- **Suggestion:** Drop the `Setting` suffix from type names within the `accountsettings` package, or drop the trailing `s` from the package name. (Compare: a package called `users` whose types are all `UserUser`, `UserAccountUser`.) E.g. `CspEnablementAccountSetting` -> `CspEnablementAccount` (which already exists as a sub-type). +- **Rationale:** Every consumer reaches these types via `accountsettings.X`, so `accountsettings.PersonalComputeSetting` triple-stutters the domain. + +--- + +## Medium severity + +### 12–14. `CspEnablementAccountSetting`, `EsmEnablementAccountSetting`, `PersonalComputeSetting` — type-suffix tautology +- **File:line:** `model.ts:102, 246, 420` +- **Category:** Type-suffix tautology +- **Suggestion:** Drop `Setting` (see #11). For ESM/CSP the inner type already drops it (`CspEnablementAccount`, `EsmEnablementAccount`). +- **Rationale:** The package is `accountsettings`, the method is `getCspEnablementAccountSetting`, returning a `CspEnablementAccountSetting`. The word "setting" appears three times in one call. This is the classic Go-port symptom — Go has no such namespace, so the redundancy is required there; in TS it is gratuitous. + +### 15. `*Account` vs `*AccountSetting` — duplicate-concept parallel naming +- **File:line:** `model.ts:92 vs 102; 242 vs 246` +- **Category:** Duplicate concept +- **Suggestion:** Rename one half of each pair so the two types describe distinct concepts at a glance, or document the relationship in both JSDocs. +- **Rationale:** Two types differing by one suffix (`CspEnablementAccount` vs `CspEnablementAccountSetting`) invite bugs where the consumer references the wrong one — the distinction between "data" and "envelope" is invisible from the name alone. + +### 16. `LlmProxyPartnerPoweredEnforce` — misleading +- **File:line:** `model.ts:401` +- **Category:** Misleading / verb-tense in noun position +- **Suggestion:** `LlmProxyPartnerPoweredEnforcement` (noun), and the method should be `getLlmProxyPartnerPoweredEnforcement`. +- **Rationale:** `Enforce` is the imperative verb; the type represents the *enforcement setting state*. The doc on `client.ts:418` reads `Gets the enforcement status of partner powered AI features account setting` — confirming the type is a noun-of-enforcement, not the verb. + +### 17. `LlmProxyPartnerPoweredAccount` — misleading +- **File:line:** `model.ts:382` +- **Category:** Misleading +- **Suggestion:** `LlmProxyPartnerPoweredEnabled` (or drop "Account" — every type in the package is account-scoped, the qualifier adds no information). +- **Rationale:** "Account" here doesn't refer to a sub-account or an account entity — it means "scoped to the account level," which is already true of every type in the package. The name suggests an Account *object* rather than an *enablement state*. + +### 18. `AccountIpAccessEnable` — verb-as-noun +- **File:line:** `model.ts:66` +- **Category:** Verb-tense inconsistency +- **Suggestion:** `AccountIpAccessToggle` (matches the method doc on `client.ts:104` "the account IP access toggle setting"), or `AccountIpAccessEnabled` (state). +- **Rationale:** Types should be nouns. `Enable` is an imperative verb. The wire field name `acct_ip_acl_enable` likewise reads as a command, not a state. The doc itself calls this a "toggle setting" — that name would be far more idiomatic. + +### 19. `DisableLegacyFeatures` — verb-phrase as type name +- **File:line:** `model.ts:220` +- **Category:** Verb-tense inconsistency +- **Suggestion:** `LegacyFeaturesDisabled` or `LegacyFeaturesToggle`. +- **Rationale:** `DisableLegacyFeatures` parses as "an action that disables legacy features." Types describing the *state of the toggle* should read as such. + +### 20. `DcpAccountEnableMessage` — verb in noun position + `Message` suffix +- **File:line:** `model.ts:126` +- **Category:** Verb-tense + Go/Java-style suffix +- **Suggestion:** `PersonalComputeAccess` (since this is in fact the personal compute policy state), drop both `Enable` (verb) and `Message` (proto-wire). +- **Rationale:** `Message` is a protobuf-isms suffix that TS does not need (everything is a message at the wire level). + +### 21 / 42. `delete*` methods that actually revert +- **File:line:** `client.ts:104 (deleteAccountIpAccessEnable doc: "Reverts the value..."), 184 (deletePersonalComputeSetting doc: "Reverts back ... to default (ON)")` +- **Category:** Inconsistent action verbs / misleading +- **Suggestion:** `reset*ToDefault()` (the semantics are reset-to-default, not destruction). At minimum, the method JSDoc and the verb should agree. +- **Rationale:** A `delete` HTTP verb is being used to reset state — that is the *server's* idiom. The SDK can hide it with a more accurate verb. The doc literally says "Reverts" — a reader scanning method names will not see that. + +### 22. `complianceStandards` array on `CspEnablementAccount` (singular type, plural field) +- **File:line:** `model.ts:99` +- **Category:** Singular/plural mismatch (mild — the field is plural because it's a list, which is correct; the audit checklist asks me to flag interactions). Actually this is fine — flagged only to note it's *consistent*. +- **Suggestion:** No change. + +### 23. `settingName` documented to be ignored, "must be `default`" +- **File:line:** `model.ts:81, 117, 235, 261, 397, 416, 435` +- **Category:** Misleading +- **Suggestion:** Either remove the field from the TS surface (since the doc says it will not be respected on requests and is always `"default"` server-side) or rename to `settingName_readOnly` and mark it `readonly`. +- **Rationale:** Exposing a field that the API explicitly ignores invites confused user code. The doc says verbatim: "This field is populated in the response, but it will not be respected even if it's set in the request body. The setting name in the path parameter will be respected instead." + +### 24. `settingTypeName` query param has no purpose +- **File:line:** `client.ts:111-113` (and every other method that appends it as a query param) +- **Category:** Misleading / vague +- **Suggestion:** Remove from request types (the actual type is hard-coded into the URL path) or document that it is informational only. +- **Rationale:** The URL already encodes `types/acct_ip_acl_enable`; appending `?setting_type_name=acct_ip_acl_enable` is at best a no-op. If it's required for some legacy reason, that needs a comment. + +### 25. `*EnablementAccount` family — verbose and weak +- **File:line:** `model.ts:92, 242` +- **Category:** Vague / overly verbose +- **Suggestion:** Drop `Enablement` — it adds no information beyond "this thing represents whether the feature is enabled," which is already implied by the boolean fields. `CspAccount` / `EsmAccount`, or better, `CspState` / `EsmState`. +- **Rationale:** "Enablement" is an awkward noun coined to allow protobuf to model "the state of enablement of X." Standard English would say "X enabled" (adjective) or just "X" with a bool field. + +### 26–27. `UpdateLlmProxyPartnerPoweredEnforceRequest` / `UpdateCspEnablementAccountSettingRequest` — overly verbose +- **File:line:** `model.ts:502, 454` +- **Category:** Overly verbose +- **Suggestion:** Shorter forms like `UpdateLlmProxyEnforcementRequest` / `UpdateCspRequest`, paired with the renames in #15 and #25. +- **Rationale:** 38 characters in `UpdateLlmProxyPartnerPoweredEnforceRequest` is too long to scan, and most of it is fixed boilerplate ("PartnerPowered", "Account", "Setting", "Request"). + +### 28. `Ip` vs `IP` acronym casing +- **File:line:** `model.ts:66` (and references) +- **Category:** Acronym casing inconsistency +- **Suggestion:** Pick one. TypeScript's de-facto style (and the Google TS style guide) treats 2-letter acronyms as PascalCase tokens (`Ip`), so `AccountIpAccessEnable` is actually correct by that rule. But the Go SDK uses `IP`; the JS SDK is consistent with TS conventions here. Just note for the audit. +- **Rationale:** Within this package the choice is consistent; cross-package consistency should be verified. + +### 29. `Id` vs `ID` acronym casing +- **File:line:** `model.ts:131, 161, 191, ...` +- **Category:** Acronym casing inconsistency +- **Suggestion:** Same as #28 — `Id` matches TS conventions. +- **Rationale:** Same as #28. + +### 30. Method-name redundancy: `getCspEnablementAccountSetting` +- **File:line:** `client.ts:262, 302, 339, 379, 419, 459` +- **Category:** Method name redundancy +- **Suggestion:** Drop `Setting` from method names (the `Client` is already account-settings-scoped; `client.getCsp()` is unambiguous in context). +- **Rationale:** `accountsettings.Client.getCspEnablementAccountSetting()` repeats "setting" in package + method. Compare similar SDKs where `settings.Client.getCsp()` is the norm. + +### 31. `updatePersonalComputeSetting` — same redundancy +- **File:line:** `client.ts:682` +- **Category:** Method name redundancy +- **Suggestion:** `updatePersonalCompute()`. +- **Rationale:** Same as #30. + +### 32. `Account` repeated in nearly every type +- **File:line:** `model.ts` passim +- **Category:** Duplicate concept (package scope already implies account-level) +- **Suggestion:** Drop the `Account` prefix/suffix where the package name (`accountsettings`) already conveys it. +- **Rationale:** `CspEnablementAccount` → `CspEnablement`. `EsmEnablementAccount` → `EsmEnablement`. `AccountIpAccessEnable` → `IpAccessEnable`. The current scheme reads like the Go SDK's flat namespace, where the prefix is needed; in a packaged TS SDK it is purely stutter. + +--- + +## Low severity + +### 33. `etag` field cased as `etag` but JSDoc consistently says "eTag" +- **File:line:** `model.ts:68 (field: `etag`), 75 (doc: "as the eTag provided")` +- **Category:** Acronym casing inconsistency +- **Suggestion:** Pick `etag` everywhere (HTTP standard is `ETag` per RFC 7232 but most code uses `etag`). +- **Rationale:** Within a single JSDoc block, line 68 declares `etag?: string` and line 70 capitalizes it as `eTag`. Trivial inconsistency. + +### 34. `acct_ip_acl_enable` wire key +- **File:line:** `model.ts:530, 541-543`; `client.ts:109, 229, 500` +- **Category:** Cryptic abbreviation (server-controlled, but leaks via the discriminator `$case: 'acctIpAclEnable'`) +- **Suggestion:** Server side can keep wire keys; the TS-facing discriminator `$case: 'acctIpAclEnable'` should be `accountIpAclEnable` or `enabled`. +- **Rationale:** Users have to type the `$case` string literal, so abbreviations cost real ergonomics. + +### 35. `dcp_acct_enable` wire key +- **File:line:** `client.ts:189, 463, 686` +- **Category:** Cryptic abbreviation (server-side path) +- **Suggestion:** N/A (server URL is fixed). Note for observability. + +### 36. `shield_csp_enablement_ac` / `shield_esm_enablement_ac` wire keys +- **File:line:** `client.ts:266, 343, 529, 590` +- **Category:** Cryptic abbreviation (server-side path) +- **Suggestion:** N/A. The trailing `_ac` (presumably "account") is an artefact of server naming. + +### 37. `COMPLIANCE_STANDARD_UNSPECIFIED` — long enum value +- **File:line:** `model.ts:10` +- **Category:** Long enum value +- **Suggestion:** See #1. + +### 38. Long enum values (`CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5`, `ITAR_EAR`, `GERMANY_C5`, `ISMAP`, `HITRUST`, `K_FSI`, `ARC_AMPE`) +- **File:line:** `model.ts:19-53` +- **Category:** Long enum values +- **Suggestion:** Keep — these are well-known compliance standard names where the string literal *is* the canonical form. Flagging only for completeness. +- **Rationale:** Compliance standards have official names. Shortening `FEDRAMP_MODERATE` to `FEDRAMP_MOD` would be a regression. + +### 39. `Enable` (verb) vs `Enablement` (noun) co-exist +- **File:line:** `model.ts:66 (AccountIpAccessEnable) vs 92, 102 (CspEnablement...) vs 220 (DisableLegacyFeatures)` +- **Category:** Verb-tense inconsistency +- **Suggestion:** Standardize: either `*Enabled` (boolean adjective) or `*Toggle` (noun) across all toggle types. +- **Rationale:** Within one package, three different lexical forms describe the same concept ("a boolean toggle"). A reader can't predict the form for a new toggle. + +### 40. `DisableLegacyFeatures` — plural noun, singular boolean +- **File:line:** `model.ts:220-239` +- **Category:** Singular/plural mismatch (mild) +- **Suggestion:** `DisableLegacyFeaturesToggle` (it's a single bool, not a list of features). +- **Rationale:** The bare plural reads as "a list of disable-legacy-feature entries"; the type body shows it's a single bool. + +### 41. `Url` vs `URL` casing +- **File:line:** `utils.ts:71, 103` (HttpRequest field used as `url`) +- **Category:** Acronym casing inconsistency +- **Suggestion:** Conforms to TS convention (`url`/`Url`). Note for the audit. + +### 43. `setting?` on every update request — vague +- **File:line:** `model.ts:449, 461, 473, 485, 497, 509, 521` +- **Category:** Vague / generic field name +- **Suggestion:** Name the field after its type (`personalCompute?: PersonalComputeSetting`) — when there's exactly one payload type per request, the parameter name should reflect it. +- **Rationale:** `req.setting` is so generic the IDE auto-complete tells the user nothing. `req.personalCompute` would. + +--- + +## Observations + +1. **Acronym soup.** Within the file you encounter CSP, ESM, DCP, LLM, IP, ACL, ESC (Enhanced Security Compliance), CMS (Centers for Medicare & Medicaid Services), ITAR/EAR, ISMAP, HITRUST, K-FSI, C5, TISAX, ARC-AMPE — without a single glossary. The compliance-standard acronyms have JSDoc, but the type-name acronyms (CSP, ESM, DCP, LLM) do not. A top-of-file `@module` doc that expands these would be high-ROI. + +2. **`Setting` suffix is gratuitous.** The package is `accountsettings`, the client is `Client`, and the methods are `getX`/`updateX`. The `Setting` suffix repeats in 7 of 11 main types. Even keeping a 1:1 port from Go, a TS-idiomatic façade could re-export these with cleaner names. + +3. **`settingName` is documented to be ignored.** Exposing a field on a request where the docstring says "this field…will not be respected even if it's set" is hostile to consumers. Either remove it or mark it `readonly` and explain. + +4. **`Enable` vs `Enablement` vs `Disable` vs `DisableLegacyFeatures`.** Within one package, four different verb/noun forms describe boolean toggles. A small style decision (every toggle type ends in `Toggle` or every toggle exposes `enabled: boolean`) would tighten the surface considerably. + +5. **`Delete` HTTP verb is named `delete` in the SDK but means "reset to default."** Method JSDoc says "Reverts the value...to default (ON)." A more honest method name (`reset*ToDefault`) would help consumers reason about what is destroyed. + +6. **`accountId` is the only field that varies across requests, and it is optional everywhere** because the client constructor accepts an `accountId` fallback. That coupling is good UX. But the JSDoc explanation only appears on update requests, not get/delete — a small inconsistency. + +7. **Field-mask functions (`accountIpAccessEnableFieldMask`, etc.) follow a clear lowerCamelCase pattern**, but the leading `acct` in `acct_ip_acl_enable` (wire) does not propagate (TS surface uses `accountIpAclEnable`). Good — but it means the wire-to-TS rename rules are non-obvious. + +--- + +## Domain glossary + +| Acronym / token | Expansion | Mentioned in code? | +|-----------------|-----------|--------------------| +| **CSP** | Compliance Security Profile | Yes, `model.ts:96` (one-time) | +| **ESM** | Enhanced Security Monitoring | Only in method JSDoc `client.ts:338` | +| **ESC** | Enhanced Security Compliance | Yes, `model.ts:13` | +| **DCP** | (Default) Personal Compute policy | No (inferred from wire key `dcp_acct_enable` + neighbouring docs) | +| **LLM** | Large Language Model | No | +| **ACL** | Access Control List | Yes (wire only, `acct_ip_acl_enable`) | +| **IP** | Internet Protocol (network address) | Implicit | +| **AIP** | API Improvement Proposals (Google) | `model.ts:447` ("Added for AIP compliance.") — undocumented | +| **etag** | Entity tag (HTTP cache validator, RFC 7232) | Yes (in field doc) | +| **SHIELD** | Databricks security product line | `model.ts:7` (one-time, undefined) | + +--- + +## File coverage + +| File | Lines read | Coverage | +|------|-----------|----------| +| `src/v1/index.ts` | 40 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | +| `src/v1/model.ts` | 1204 (full) | 100% — all 23 types, 2 enums, 16 zod schemas, 7 field-mask helpers audited. | +| `src/v1/client.ts` | 710 (full) | 100% — all 13 client methods, constructor, and private fields audited. | +| `src/v1/utils.ts` | 151 (full) | 100% — utility functions reviewed; `HttpCallOptions`, `executeCall`, `parseResponse`, `marshalRequest`, `flattenQueryParams` have no naming issues worth flagging (they are infrastructure shared across packages and follow consistent conventions). | diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md new file mode 100644 index 00000000..d141b7d3 --- /dev/null +++ b/.agent/naming-audit/alerts.md @@ -0,0 +1,512 @@ +# Naming Audit: alerts + +**Path:** `packages/alerts/src/{v1,v2}/` +**Versions audited:** v1, v2 +**Inferred domain:** SQL/Databricks alerts: a stored configuration that periodically evaluates a query result against a threshold and notifies subscribers when it triggers. +**Total weird names flagged:** 36 + +## Summary table + +| # | Severity | Version | Location | Name | Category | +|---|----------|---------|----------|------|----------| +| 1 | High | v2 | `model.ts` enum | `Aggregation` | Vague/generic, no domain prefix | +| 2 | High | v2 | `model.ts` enum value | `AlertEvaluationState.UNKNOWN` | Misleading (proto sentinel exposed) | +| 3 | High | v1 | `model.ts` field | `AlertCondition.op` | Cryptic abbreviation | +| 4 | High | v1 | `model.ts` field | `Alert.secondsToRetrigger` / v2 `AlertNotification.retriggerSeconds` | Singular/plural mismatch & cross-version regression in word order | +| 5 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | +| 6 | High | v2 | `model.ts` field | `Alert.runAsUserName` vs `Alert.runAs.userName` | Duplicate concept | +| 7 | High | v2 | `model.ts` field | `Alert.queryText` | Field contradicts type domain (alert holds raw SQL) | +| 8 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | +| 9 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | +| 10 | Medium | both | `model.ts` enum value | `AlertOperator.IS_NULL` / v2 `IS_NOT_NULL` | Long enum values inconsistent with binary ops | +| 11 | Medium | both | `model.ts` field | `Alert.notifyOnOk` | Acronym casing ambiguity (`Ok` vs `OK`) | +| 12 | Medium | v1 | `model.ts` field | `Alert.triggerTime` (v1) — disappears in v2 | Underspecified time field | +| 13 | Medium | v2 | `model.ts` field | `AlertEvaluation.lastEvaluatedAt` | Inconsistent time suffix (`At` vs `Time`) | +| 14 | Medium | v2 | `model.ts` field | `AlertOperandColumn.display` | Vague (display what?) | +| 15 | Medium | v2 | `model.ts` field | `Alert.warehouseId` | Underspecified ID | +| 16 | Medium | v2 | `model.ts` field | `CronSchedule.timezoneId` | Underspecified ID (timezone name, not numeric) | +| 17 | Medium | v2 | `model.ts` field | `CronSchedule.quartzCronSchedule` | Type-suffix tautology | +| 18 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | +| 19 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Domain-detached prefix | +| 20 | Medium | v2 | `model.ts` field | `Alert.evaluation` (no domain qualifier) | Generic field name | +| 21 | Medium | v2 | `model.ts` field | `Alert.lifecycleState` documented as "Indicates whether the query is trashed" | Misleading (says query, means alert) | +| 22 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | +| 23 | Medium | v2 | `model.ts` field | `AlertSubscription.subscriptionType` | Type-suffix tautology | +| 24 | Low | both | `model.ts` field | `pageToken` / `pageSize` / `nextPageToken` | Conventional; flagged only for completeness | +| 25 | Low | both | `model.ts` field | `ListAlertsRequest`/`ListAlertsResponse` plural vs `GetAlertRequest` singular | Consistent with REST norms | +| 26 | Low | both | `client.ts` method | `listAlertsIter` | Cryptic abbreviation (`Iter`) | +| 27 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | +| 28 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | +| 29 | Low | v1 | `model.ts` field | `AlertCondition.emptyResultState` | Underspecified (state of what when empty) | +| 30 | Low | v2 | `model.ts` field | `AlertEvaluation.source` | Vague/generic | +| 31 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | +| 32 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | +| 33 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | +| 34 | Low | v2 | `model.ts` field | `Alert.parentPath` and `effectiveParentPath` | "Effective" prefix unexplained at first read | +| 35 | Low | v2 | `model.ts` field | `Alert.id`, `Alert.queryText` co-located | "id" alone underspecified at field level (docs clarify) | +| 36 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | + +## v1 vs v2 comparison + +### Major renames + +| v1 name | v2 name | Notes | +|---------|---------|-------| +| `AlertOperator` (enum) | `ComparisonOperator` (enum) | **Regression** — `AlertOperator` was self-describing within the alerts package; `ComparisonOperator` is generic and re-uses a name already common across SDK packages. The new enum also adds `IS_NOT_NULL` (good), but the rename obscures the domain. | +| `AlertOperator.IS_NULL` only | `ComparisonOperator.IS_NULL` + `IS_NOT_NULL` | Expansion (good) but introduces a unary/binary asymmetry inside an enum named "Comparison". | +| `LifecycleState` (enum) | `AlertLifecycleState` (enum) | **Improvement** — domain prefix added. | +| `LifecycleState.TRASHED` | `AlertLifecycleState.DELETED` | **Break** — `trashAlert` method (still named "trash") now yields a state called `DELETED`. The verb on the wire and the state vocabulary diverge, even though the docstring still says "soft deleted". | +| `AlertCondition` (type) | `AlertEvaluation` (type) | **Major rename** — shifts from "condition shape" to "evaluation snapshot." The new type co-mingles configuration (`comparisonOperator`, `threshold`, `notification`) with runtime telemetry (`state`, `lastEvaluatedAt`), which is a meaningful design regression for naming. | +| `AlertCondition.op` | `AlertEvaluation.comparisonOperator` | **Improvement** — no longer cryptic. | +| `AlertCondition.operand` | `AlertEvaluation.source` | **Regression** — `source` is even vaguer than `operand`. | +| `AlertCondition.threshold` (`AlertOperand`) | `AlertEvaluation.threshold` (`AlertOperand`) | Identical name and type; OK. | +| `Alert.secondsToRetrigger` | `AlertNotification.retriggerSeconds` | **Regression** — word order changed (good: matches Go field), but: (a) two versions now use opposite orderings, (b) field moved into a sub-message, (c) v1 had grammatical singular/plural mismatch ("seconds … to retrigger" reads better than "retrigger seconds"). | +| `Alert.customBody`, `Alert.customSubject` | `Alert.customSummary`, `Alert.customDescription` | **Vocabulary swap** — v1 borrows email vocabulary (body/subject), v2 borrows article/incident vocabulary (summary/description). Both apply to the same notification text — there is no semantic reason for the change; an existing user has to re-learn the field names. | +| `Alert.triggerTime` | dropped; moved into `AlertEvaluation.lastEvaluatedAt` | Renamed and re-located. Time-suffix convention changes from `Time` to `At`. | +| `Alert.condition` | `Alert.evaluation` | Mirror of the type rename. | + +### New in v2 (no v1 counterpart) + +- `Aggregation` (enum) — top-level, no domain prefix. +- `SchedulePauseStatus` (enum) — partial domain prefix. +- `AlertNotification` (type) +- `AlertOperandColumn.display`, `.aggregation` (new fields) +- `AlertRunAs` (type) — verb-as-noun. +- `AlertSubscription` (type) +- `CronSchedule` (type) — generic name in a single-domain package. +- `Alert.queryText`, `Alert.warehouseId`, `Alert.runAsUserName`, `Alert.runAs`, `Alert.effectiveRunAs`, `Alert.effectiveParentPath`, `Alert.schedule`, `Alert.evaluation`, `Alert.customSummary`, `Alert.customDescription`. +- `TrashAlertRequest.purge` — new flag. + +### Dropped in v2 + +- `Alert.queryId` (v1) — alert no longer references a Query by ID; v2 embeds raw `queryText` + `warehouseId`. **Regression** in normalization, **improvement** in name specificity. + +### Net assessment + +v2 has clear wins (`AlertLifecycleState` prefix; spelling out `comparisonOperator`) but also introduces several regressions (`AlertOperator` → `ComparisonOperator`, `operand` → `source`, `condition` → `evaluation`, `customBody/Subject` → `customSummary/Description`, `secondsToRetrigger` → `retriggerSeconds`, `LifecycleState.TRASHED` → `AlertLifecycleState.DELETED` while keeping the method `trashAlert`). + +## High severity + +### 1. `Aggregation` — vague/generic top-level name (v2) + +**Location:** `src/v2/model.ts:8-17` + +```ts +export enum Aggregation { + SUM = 'SUM', + COUNT = 'COUNT', + COUNT_DISTINCT = 'COUNT_DISTINCT', + AVG = 'AVG', + MEDIAN = 'MEDIAN', + MIN = 'MIN', + MAX = 'MAX', + STDDEV = 'STDDEV', +} +``` + +Exported at the package root without an `Alert` or `Column` prefix. The same word is overloaded across SQL, stats, monitoring, and ML domains. `AlertOperandAggregation` or `ColumnAggregation` would be unambiguous. + +### 2. `AlertEvaluationState.UNKNOWN` — proto sentinel leak (v2) + +**Location:** `src/v2/model.ts:26-32` + +```ts +/** + * UNSPECIFIED - default unspecify value for proto enum, do not use it in the code + * UNKNOWN - alert not yet evaluated + * ... + */ +export enum AlertEvaluationState { + /** Deprecated. Please avoid using `UNKNOWN` as empty_result_state. */ + UNKNOWN = 'UNKNOWN', + TRIGGERED = 'TRIGGERED', + OK = 'OK', + ERROR = 'ERROR', +} +``` + +Inline JSDoc tells the user not to use `UNKNOWN`, yet the enum exports it. The header even mentions `UNSPECIFIED` (not exported, but described). Both are proto implementation details surfacing into the TS API. + +### 3. `AlertCondition.op` — cryptic abbreviation (v1) + +**Location:** `src/v1/model.ts:62-71` + +```ts +export interface AlertCondition { + /** Operator used for comparison in alert evaluation. */ + op?: AlertOperator | undefined; + ... +} +``` + +`op` is opaque without reading the JSDoc. v2 renames to `comparisonOperator` (good), but v1 keeps the two-letter wire shorthand. + +### 4. `secondsToRetrigger` vs `retriggerSeconds` — singular/plural & cross-version reorder + +**Location:** `src/v1/model.ts:38-39`; `src/v2/model.ts:124-128` + +```ts +// v1 +secondsToRetrigger?: number | undefined; +// v2 +retriggerSeconds?: number | undefined; +``` + +`secondsToRetrigger` reads as "the seconds it takes to retrigger" but actually means "the wait period before retriggering is allowed." `retriggerSeconds` is closer to "number-of-seconds-typed-as-retrigger." Neither is great; both encode the unit in the name which is a smell when there's no companion `*Millis`/`*Minutes`. The same conceptual field changes name across versions. + +### 5. `AlertRunAs` — verb-as-noun (v2) + +**Location:** `src/v2/model.ts:157-170` + +```ts +export interface AlertRunAs { + identity?: + | { $case: 'userName'; userName: string } + | { $case: 'servicePrincipalName'; servicePrincipalName: string } + | undefined; +} +``` + +`RunAs` is an imperative verb phrase used as a type name. `AlertIdentity`, `AlertRunner`, or `RunAsIdentity` would parse as nouns. Also note: the *field* inside is named `identity` — a clearer type name would let the field name be more specific (or vice versa). + +### 6. Duplicate concept — `runAsUserName` vs `runAs.userName` (v2) + +**Location:** `src/v2/model.ts:72-99` + +```ts +// Deprecated: Use `run_as` field instead. ... +runAsUserName?: string | undefined; +... +runAs?: AlertRunAs | undefined; +effectiveRunAs?: AlertRunAs | undefined; +``` + +The same data is expressible as either `runAsUserName` (legacy scalar) or `runAs.identity.userName` (new structured). The Alert type carries both. The deprecation is noted in JSDoc only — a TS user reading the type sees three "run as"-prefixed fields without IDE help. + +### 7. `Alert.queryText` — field contradicts type domain (v2) + +**Location:** `src/v2/model.ts:68-71` + +```ts +/** Text of the query to be run. */ +queryText?: string | undefined; +``` + +A type named `Alert` carrying a raw SQL string makes the alert object responsible for storage of its query — a v1→v2 change that conflates the alert configuration with the query content. v1 cleanly held `queryId` (FK to a Query resource). The name itself is fine; the placement on `Alert` is the smell. + +## Medium severity + +### 8. `trashAlert` — inconsistent action verb (both) + +**Location:** `src/v1/client.ts:169-192`; `src/v2/client.ts:167-196` + +```ts +/** Moves an alert to the trash. ... A trashed alert is permanently deleted after 30 days. */ +async trashAlert(...) { ... DELETE ... } +``` + +The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashAlert`. Across the SDK this is the only place where soft-delete uses `trash`-prefix. Most resources use `deleteX` (and the v2 enum value is `AlertLifecycleState.DELETED`, not `TRASHED`). + +### 9. `TrashAlertRequest` — same as 8, in the type layer (both) + +**Location:** `src/v1/model.ts:187-189`; `src/v2/model.ts:222-226` + +Same verb inconsistency at the type layer. + +### 10. Long enum values with `_OR_` connectors + +**Location:** `src/v1/model.ts:8-16`; `src/v2/model.ts:39-48` + +```ts +GREATER_THAN_OR_EQUAL = 'GREATER_THAN_OR_EQUAL', +LESS_THAN_OR_EQUAL = 'LESS_THAN_OR_EQUAL', +``` + +The wire format uses long, English-prose enum values where most SDKs use `GT`, `GTE`, `LT`, `LTE`. They are long and verbose, and v2 adds `IS_NOT_NULL` alongside `IS_NULL` — unary operators sharing an enum named `ComparisonOperator`. + +### 11. `Alert.notifyOnOk` — acronym/initialism case ambiguity (both) + +**Location:** `src/v1/model.ts:59`; `src/v2/model.ts:130` + +```ts +notifyOnOk?: boolean | undefined; +``` + +`OK` is conventionally upper-case, so `notifyOnOK` would match the enum value `AlertEvaluationState.OK`. The field uses title-case `Ok`, mismatching the enum value casing in the same file. + +### 12. `Alert.triggerTime` — underspecified time (v1) + +**Location:** `src/v1/model.ts:42-43` + +```ts +/** Timestamp when the alert was last triggered, if the alert has been triggered before. */ +triggerTime?: Temporal.Instant | undefined; +``` + +"Trigger time" could be "next scheduled trigger," "first trigger," or "last trigger" — the doc clarifies it's "last triggered." `lastTriggerTime` or `lastTriggeredAt` (v2 uses `lastEvaluatedAt` for a related concept) would be unambiguous. + +### 13. `AlertEvaluation.lastEvaluatedAt` — inconsistent time suffix (v2) + +**Location:** `src/v2/model.ts:114-116` + +```ts +lastEvaluatedAt?: Temporal.Instant | undefined; +``` + +Every other timestamp in v2 uses the `*Time` suffix (`createTime`, `updateTime`). `lastEvaluatedAt` mixes conventions in the same file. + +### 14. `AlertOperandColumn.display` — vague (v2) + +**Location:** `src/v2/model.ts:141-146` + +```ts +export interface AlertOperandColumn { + name?: string | undefined; + display?: string | undefined; + aggregation?: Aggregation | undefined; +} +``` + +`display` with no JSDoc is ambiguous: display name? display label? display order? — without inspection of the wire payload one can't tell. `displayName` or `label` would clarify. + +### 15. `Alert.warehouseId` — underspecified ID (v2) + +**Location:** `src/v2/model.ts:70-71` + +```ts +/** ID of the SQL warehouse attached to the alert. */ +warehouseId?: string | undefined; +``` + +In a different package this might be a data warehouse, a logical warehouse, etc. The JSDoc clarifies, but the bare name does not. `sqlWarehouseId` would match the docstring and the rest of the Databricks SQL surface area. + +### 16. `CronSchedule.timezoneId` — underspecified ID (v2) + +**Location:** `src/v2/model.ts:189-194` + +```ts +/** A Java timezone id. ... */ +timezoneId?: string | undefined; +``` + +A timezone is named (e.g., `"America/Los_Angeles"`), not numerically identified. `timezone` or `timezoneName` reads less like a foreign key. The Go SDK and protobuf wire spell it `timezone_id`, but that doesn't make it accurate. + +### 17. `CronSchedule.quartzCronSchedule` — type-suffix tautology (v2) + +**Location:** `src/v2/model.ts:183-188` + +```ts +export interface CronSchedule { + quartzCronSchedule?: string | undefined; + ... +} +``` + +The type is `CronSchedule`, the field is `quartzCronSchedule`. The user writes `schedule.quartzCronSchedule` where the outer access already implies "schedule." `quartzExpression` or `quartz` would suffice. + +### 18. `CronSchedule` — generic name in a single-domain package (v2) + +**Location:** `src/v2/model.ts:183-199` + +A top-level type called `CronSchedule` in a package whose only consumer is alerts. If/when another package wants its own cron schedule shape, the user has two `CronSchedule`s. `AlertSchedule` would domain-prefix consistently with the rest of v2. + +### 19. `SchedulePauseStatus` — domain-detached prefix (v2) + +**Location:** `src/v2/model.ts:50-53` + +```ts +export enum SchedulePauseStatus { + UNPAUSED = 'UNPAUSED', + PAUSED = 'PAUSED', +} +``` + +The enum is prefixed by `Schedule` (its host type), not by the package (`Alert`). Mixed convention with `AlertLifecycleState`, `AlertEvaluationState`. Also: two values for a boolean concept; `boolean paused` would be simpler. + +### 20. `Alert.evaluation` — generic field name (v2) + +**Location:** `src/v2/model.ts:78` + +```ts +evaluation?: AlertEvaluation | undefined; +``` + +The type already conveys "alert evaluation." The field would be clearer as `condition` (mirroring v1 semantics) or `trigger`, since `AlertEvaluation` actually carries both configuration (operator/threshold) and runtime telemetry (state/lastEvaluatedAt). + +### 21. `Alert.lifecycleState` — JSDoc contradicts the field (v2) + +**Location:** `src/v2/model.ts:80-81` + +```ts +/** Indicates whether the query is trashed. */ +lifecycleState?: AlertLifecycleState | undefined; +``` + +JSDoc says "whether the query is trashed," but the field is on `Alert` and the enum is `AlertLifecycleState` with values `ACTIVE`/`DELETED`. The word "query" leaks from the underlying implementation (alerts wrap queries) into an `Alert` field's documentation. + +### 22. `AlertLifecycleState.DELETED` vs v1 `LifecycleState.TRASHED` — vocabulary swap + +**Location:** v1 `model.ts:24-27`; v2 `model.ts:34-37` + +The method is still `trashAlert` (both versions), but in v1 the resulting state is `TRASHED` and in v2 it is `DELETED`. So in v2 you "trash" something and it becomes "deleted." The wire/JSDoc still references "trashed." + +### 23. `AlertSubscription.subscriptionType` — type-suffix tautology (v2) + +**Location:** `src/v2/model.ts:172-177` + +```ts +export interface AlertSubscription { + subscriptionType?: ... ; +} +``` + +The field name re-states the type name. `target` or `recipient` would describe what the discriminator carries. + +## Low severity + +### 24. `pageToken` / `pageSize` / `nextPageToken` (both) + +```ts +export interface ListAlertsRequest { + pageToken?: string | undefined; + pageSize?: number | undefined; +} +export interface ListAlertsResponse { + ... + nextPageToken?: string | undefined; +} +``` + +Conventional Google AIP-158 pagination names. Flagged only because the rule list asks for completeness; no action recommended. + +### 25. `ListAlertsRequest` plural vs `GetAlertRequest` singular (both) + +Consistent with REST norms (`GET /alerts/{id}` singular, `GET /alerts` plural). No action recommended. + +### 26. `listAlertsIter` — cryptic abbreviation (both) + +**Location:** v1 `client.ts:152-167`, v2 `client.ts:150-165` + +```ts +async *listAlertsIter(...) : AsyncGenerator<...> { ... } +``` + +`Iter` for "iterator" reads as a Go/Rust port. Idiomatic TS would name this method `listAllAlerts` (or simply drop the paginated overload entirely and have callers use the async generator pattern returned from `listAlerts`). + +### 27. `Aggregation.STDDEV` — cryptic abbreviation (v2) + +```ts +STDDEV = 'STDDEV', +``` + +`STANDARD_DEVIATION` or `STDEV` would be clearer; `STDDEV` is a SQL-server-ism. + +### 28. `Aggregation.AVG` — cryptic abbreviation (v2) + +`AVERAGE` would be consistent with `SUM`, `COUNT`, `MEDIAN`, `MIN`, `MAX`. The mix of short and full names inside one enum is the issue. + +### 29. `AlertCondition.emptyResultState` — underspecified (v1) + +```ts +/** Alert state if result is empty. */ +emptyResultState?: AlertState | undefined; +``` + +Reads as "the empty-result state." `stateWhenEmptyResult` or `emptyResultBehavior` parses left-to-right. Minor. + +### 30. `AlertEvaluation.source` — vague (v2) + +```ts +/** Source column from result to use to evaluate alert */ +source?: AlertOperandColumn | undefined; +``` + +`source` is generic; `operandColumn` (matching the type), `inputColumn`, or `column` would be clearer. + +### 31. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) + +```ts +/** Threshold to user for alert evaluation, can be a column or a value. */ +threshold?: AlertOperand | undefined; +``` + +The JSDoc admits the threshold can be a column — i.e., not actually a threshold value but another operand. The field name implies "fixed comparison number," the type allows "another column." The field name lies. + +Also note the typo "Threshold to user" (should be "to use") — content, not naming, but worth fixing. + +### 32. `LifecycleState` — missing domain prefix (v1) + +v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycleState`. + +### 33. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) + +Same data, different vocabulary. v1 = email metaphor, v2 = generic content metaphor. Users porting from v1 to v2 need a translation table. + +### 34. `effectiveParentPath` / `effectiveRunAs` (v2) + +```ts +/** The actual workspace path of the folder containing the alert. This is an output-only field. */ +effectiveParentPath?: string | undefined; +``` + +The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. + +### 35. `Alert.id` (both) + +The name alone (`id`) is underspecified at type level — `alertId` would be clearer when constructing a request that takes both `req.id` and the alert's id. The JSDoc covers it; the field doesn't. + +### 36. JSDoc verb/casing inconsistency (both) + +**Location:** v2 `client.ts:68`, `client.ts:198` + +```ts +/** Create Alert */ +async createAlert(...) { ... } +/** Update alert */ +async updateAlert(...) { ... } +``` + +`Create Alert` vs `Update alert` — different capitalization, different sentence shape, neither ends with a period (project rule). v1 uses full sentences (`/** Creates an alert. */`). Naming-adjacent. + +## Observations + +1. **Wire-format leakage.** Many names are direct translations of proto wire fields without consideration of how they read in TypeScript: `op`, `STDDEV`, `IS_NULL`, `UNKNOWN`, `quartzCronSchedule`, `timezoneId`. The audit rule "1:1 port" was followed faithfully but the language idioms suffer. + +2. **v1→v2 vocabulary churn.** The package introduces 8+ renames between versions (`AlertOperator` → `ComparisonOperator`, `LifecycleState` → `AlertLifecycleState`, `TRASHED` → `DELETED`, `op` → `comparisonOperator`, `condition` → `evaluation`, `operand` → `source`, `triggerTime` → `lastEvaluatedAt`, `secondsToRetrigger` → `retriggerSeconds`, `customBody/Subject` → `customSummary/Description`). Some are improvements, some are lateral, some are regressions. Combined with `trashAlert` keeping its name while `TRASHED` becomes `DELETED`, the message-vs-method vocabulary is inconsistent. + +3. **Verb-as-noun proliferation in v2.** `AlertRunAs`, `effectiveRunAs`, `runAs.identity`, `runAsUserName` — a single concept ("which identity executes this alert") spreads across four names with overlapping semantics. + +4. **`Alert.evaluation` mixes config and telemetry.** `AlertEvaluation` carries both inputs (`comparisonOperator`, `threshold`, `notification`) and outputs (`state`, `lastEvaluatedAt`). The name suggests "a run/event," but the type is really "evaluation configuration + last-run snapshot." Splitting into `AlertEvaluationConfig` + `AlertEvaluationStatus` (or moving `state`/`lastEvaluatedAt` onto `Alert` directly, where they used to live in v1) would make the naming honest. + +5. **Top-level type pollution in v2.** v2 exports `Aggregation`, `ComparisonOperator`, `CronSchedule`, `SchedulePauseStatus`, `AlertEvaluationState`, `AlertLifecycleState` plus 9 message types from a single package. Several have no `Alert` prefix and read as if they belong to a shared domain library. Prefixing them all uniformly (`AlertAggregation`, `AlertScheduleCron`, `AlertSchedulePauseStatus`) would isolate the package. + +6. **`utils.ts` is identical across v1 and v2** and contains no domain names. The exported helpers (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are well-named and not flagged. (`flattenQueryParams` is exported but unused in `client.ts` — orphaned export, not a naming issue.) + +7. **`Iter` suffix.** `listAlertsIter` is the only client method whose name carries a Go/Rust-flavoured abbreviation. TS idiom would use the method name as the iterable (or `listAllAlerts`). This will surface in every generated package; flag at the generator level. + +## Domain glossary + +| Term | Meaning in this package | +|------|------------------------| +| Alert | A stored configuration that runs a SQL query on a schedule and notifies subscribers when the result satisfies a comparison against a threshold. | +| Trigger | The state transition from "not satisfying the condition" to "satisfying the condition." | +| Re-trigger | Re-firing of notifications after the alert has already triggered (gated by a cooldown). | +| Evaluation | A single run of the alert's query + comparison; produces a state. | +| Operand | One side of the comparison; can be a column reference or a literal value. | +| Threshold | The value (or column) the source column is compared against. v2 misuses the word — it's really the second operand. | +| Lifecycle state | `ACTIVE` (visible to user) or trashed/`DELETED` (soft-deleted; auto-purged after 30 days). | +| Run-as | The identity (user or service principal) under which the query executes. | +| Effective X | The value of X after applying permission inheritance / server defaults. | + +## File coverage + +| File | Lines | Read in full | +|------|-------|--------------| +| `src/v1/model.ts` | 621 | yes | +| `src/v1/client.ts` | 219 | yes | +| `src/v1/utils.ts` | 150 | yes | +| `src/v1/index.ts` | 23 | yes | +| `src/v2/model.ts` | 683 | yes | +| `src/v2/client.ts` | 235 | yes | +| `src/v2/utils.ts` | 150 | yes | +| `src/v2/index.ts` | 30 | yes | diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md new file mode 100644 index 00000000..5f8f2eba --- /dev/null +++ b/.agent/naming-audit/apps.md @@ -0,0 +1,837 @@ +# Naming Audit: `@databricks/sdk-apps` (v1) + +**Package:** `apps` (`packages/apps/src/v1/`) +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts` +**Domain:** Databricks Apps — interactive applications hosted in a workspace, +with deployments, custom templates, app spaces, and resource bindings. + +## Summary + +| Severity | Count | +| -------- | ----- | +| High | 14 | +| Medium | 28 | +| Low | 24 | +| Observation | 12 | +| **Total** | **78** | + +The audit found two dominant themes. First, the package leaks proto/Go +conventions deep into the public surface: every nested message keeps its +Proto-style `Outer_Inner` name (`AppManifest_AppResourceSecretSpec_SecretPermission`, +`AppUpdate_UpdateStatus_UpdateState`), enums repeat the parent type in each +value (`SPACE_UPDATE_STATE_UNSPECIFIED`, `APPLICATION_STATE_UNSPECIFIED`), and +the package re-exports an `ErrorCode` enum with >70 cross-product codes whose +relevance to Apps is unclear. Second, the domain has two overlapping +"application" vocabularies — `App` vs `Application` (`ApplicationStatus`, +`ApplicationStatus_ApplicationState`) — and three overlapping "space" +vocabularies (`Space`, `AppResourceGenieSpace`, `space` as a string field on +`App`/`ListAppsRequest`). These collisions produce both type-suffix tautology +(`AppResourceApp.AppPermission.CAN_USE`) and outright ambiguity (`Space` +versus Genie Space). + +--- + +## High-severity findings + +### H1. `ApplicationStatus` vs `App` — duplicate top-level "application" concept +- **File:** `model.ts:693, 1054`, also `index.ts:42, 76` +- **Category:** Duplicate concepts (12), Misleading names (6) +- **Issue:** The package's primary entity is `App`, but the runtime state of an + App is modelled by a struct called `ApplicationStatus` (with enum + `ApplicationStatus_ApplicationState` and values `APPLICATION_STATE_UNSPECIFIED`, + etc.). On `App`, the field is `appStatus?: ApplicationStatus`, so the type + name disagrees with the field name. There are two parallel vocabularies for + the same idea. +- **Suggestion:** Rename `ApplicationStatus` -> `AppStatus`, the nested enum to + `AppStatus.State` (TS namespace) or `AppState`, and the values to `RUNNING`, + `DEPLOYING`, etc. Aligns with the `App` entity and with the `appStatus` + field. +- **Rationale:** A consumer reading `app.appStatus: ApplicationStatus` has to + prove to themselves that "application" and "app" refer to the same thing. + +### H2. `AppResourceApp` and `AppResourceApp_AppPermission.CAN_USE` — App-on-App tautology +- **File:** `model.ts:606, 962` +- **Category:** Type-suffix tautology (20), Redundant suffixes (8) +- **Issue:** A binding from one app to another app is `AppResourceApp` with + enum `AppResourceApp_AppPermission`. The `App` token appears three times. +- **Suggestion:** The outer wrapper is fine as-is (since other variants are + `AppResourceJob`, `AppResourceSecret`), but the inner enum should drop the + redundant `App` prefix: `AppResourceApp.Permission` with a single value + `CAN_USE`. Same treatment for every `AppResource_Permission` + pairing (Database, Experiment, GenieSpace, Job, Postgres, Secret, + ServingEndpoint, SqlWarehouse, UcSecurable). +- **Rationale:** The enum is reached as `AppResourceJob_JobPermission.CAN_VIEW` + — the `Job` is already implied by the outer enum's prefix. The repeated + token adds zero information. + +### H3. Proto-style nested names leaked into public TS API +- **File:** `model.ts:524, 540, 545, 552, 560, 566, 573, 580, 587, 598, 606, + 611, 616, 623, 631, 639, 645, 652, 659, 666, 676, 684, 693, 702, 714, 851, + 859, 866, 872, 881, 887, 896, 926, 934, 1037, 1049` +- **Category:** Underscores in TS identifiers (4), Go/Java-style names (14) +- **Issue:** Every nested proto type is exported with its `Outer_Inner` proto + name (e.g. `AppManifest_AppResourceUcSecurableSpec_UcSecurablePermission`, + `SpaceStatus_SpaceState`, `AppUpdate_UpdateStatus`, `AppDeployment_State`, + etc.). Each requires an eslint-disable for `naming-convention`. The names + combine three style violations: underscores in identifiers, length, and + proto-isms unfamiliar to TS consumers. The longest is 67 characters: + `AppManifest_AppResourceServingEndpointSpec_ServingEndpointPermission`. +- **Suggestion:** Either (a) flatten to a single top-level name + (`UcSecurablePermission`, `SpaceState`, `AppUpdateState`, + `AppDeploymentState`), or (b) use TS namespace nesting (`namespace + AppManifest { export interface ResourceUcSecurableSpec { ... } }`) to keep + the hierarchy without underscores. Option (a) matches how nested-message + types are typically projected into TS by `ts-proto`'s `useDeclaredAt = false` + mode and matches the style used elsewhere in the SDK. +- **Rationale:** TS naming conventions (PascalCase types, no underscores in + identifiers) are violated by every nested type. Each disable comment is a + symptom that the convention rules see the smell too. ts-proto and Buf's + ES code generators both produce flat names by default for this reason. + +### H4. Enum-value prefix repetition (proto-style) +- **File:** `model.ts:516-521, 525-528, 685-690, 694-699, 703-711, 715-722` +- **Category:** Redundant enum prefixes (2), Long enum values (18) +- **Issue:** Multiple enums repeat their type name in every value: + - `SpaceUpdateState`: `SPACE_UPDATE_STATE_UNSPECIFIED` (4 of 5 values). + - `AppDeployment_Mode`: `MODE_UNSPECIFIED`. + - `AppUpdate_UpdateStatus_UpdateState`: `UPDATE_STATE_UNSPECIFIED`. + - `ApplicationStatus_ApplicationState`: `APPLICATION_STATE_UNSPECIFIED`. + - `ComputeStatus_ComputeState`: `COMPUTE_STATE_UNSPECIFIED`. + - `SpaceStatus_SpaceState`: `SPACE_STATE_UNSPECIFIED`, **plus every other + value is also prefixed**: `SPACE_CREATING`, `SPACE_ACTIVE`, `SPACE_ERROR`, + `SPACE_DELETING`, `SPACE_DELETED`, `SPACE_UPDATING`. None of the other + state enums prefix their non-UNSPECIFIED values, so this enum is also + internally inconsistent. +- **Suggestion:** Drop the type-name prefix from each value: + `UNSPECIFIED`/`SUCCEEDED`/`FAILED`/`IN_PROGRESS`/`NOT_UPDATED` for the + update-state enums; `CREATING`/`ACTIVE`/`ERROR`/`DELETING`/`DELETED`/ + `UPDATING` for `SpaceStatus_SpaceState`. +- **Rationale:** Each value is already qualified by the enum name at the use + site (`SpaceUpdateState.UNSPECIFIED`). Google's TS style guide and the + `@typescript-eslint/naming-convention` rule both prefer un-prefixed enum + values. + +### H5. `ErrorCode` (76 values) shipped from a package whose surface is Apps +- **File:** `model.ts:15-513`, also `index.ts:17` +- **Category:** Vague/generic without domain context (1), Duplicate concepts (12) +- **Issue:** The `ErrorCode` enum has 76 values, the majority of which are + Unity Catalog, Repos, Files API, and Workspaces error codes + (`METASTORE_DOES_NOT_EXIST`, `SHARE_DOES_NOT_EXIST`, `IPYNB_FILE_IN_REPO`, + `GIT_SENSITIVE_TOKEN_DETECTED`, `MAX_BLOCK_SIZE_EXCEEDED`, etc.). The vast + majority of values are documented as "Deprecated and kept to maintain + backwards compatibility". The only place this enum is consumed inside the + apps package is `DatabricksServiceExceptionWithDetailsProto.errorCode`, + which is itself only used as the `error` arm of `Operation.result`. +- **Suggestion:** Move `ErrorCode` to a shared core package + (`@databricks/sdk-databricks/apierror/codes`) and re-export it. Each + service-level package should not duplicate the canonical error-code list. +- **Rationale:** The enum is huge, mostly deprecated, semantically global, and + is being inlined into a service-specific package. This is the canonical case + the project's own `apierr/codes` directory was created to avoid. + +### H6. `DatabricksServiceExceptionWithDetailsProto` — Java-/Proto-style verbose name +- **File:** `model.ts:1125`, also `index.ts:84` +- **Category:** Go/Java-style names (14), Overly verbose (7), Type-suffix tautology (20) +- **Issue:** Name is 41 chars and carries three artifacts of the underlying + wire format: `Service`, `Exception`, `WithDetailsProto`. In a TS API, + consumers don't think of failures as "Java service exceptions"; they think of + them as errors. +- **Suggestion:** Rename to `ApiError` or `OperationError` (the only use site + is `Operation.result.error`). If a wire-faithful name is needed in + marshal-only contexts, restrict its export. +- **Rationale:** The current name reads like a leaked Java class name; the + trailing `Proto` is a wire-format hint that has no meaning post-decoding. + +### H7. `Operation` — generic name with no domain prefix +- **File:** `model.ts:1318`, also `index.ts:106`, `client.ts:309, 408, 536, 951` +- **Category:** Vague/generic without domain context (1) +- **Issue:** `Operation` is exported as a top-level type. There is no Apps + context in the name; a user importing `Operation` from `@databricks/sdk-apps` + has no way to know what it operates on. The accompanying request type + `GetOperationRequest` is even more generic. From the client, the method that + consumes it is `getSpaceOperation`, which is the only thing it can actually + be used for in this package. +- **Suggestion:** Rename `Operation` -> `SpaceOperation` and + `GetOperationRequest` -> `GetSpaceOperationRequest`. Alternatively, move + both to a shared core package (Google's standard + `google.longrunning.Operation`) so all packages share the type rather than + each redefining it locally. +- **Rationale:** Today every API package will have its own `Operation` type + and they will collide on import. Either a shared canonical type or a + domain-specific rename is required. + +### H8. `space` string field on `App` vs `spaceId` — which is the identifier? +- **File:** `model.ts:786-790`, `client.ts:624-626` +- **Category:** Underspecified IDs (19), Misleading names (6), Generic field names (15) +- **Issue:** `App` has two fields: + - `space?: string` ("Name of the space this app belongs to") + - `spaceId?: string` ("The ID of the app space this app belongs to") + These are both stringly-typed and distinguishable only by the documentation. + `ListAppsRequest.space` is also a `string` filter that takes the space + *name*. The bare `space` field looks like it should be a `Space` object + rather than a string handle. +- **Suggestion:** Rename `space` -> `spaceName` to mirror `spaceId` and to + reduce confusion with the `Space` interface. Update + `ListAppsRequest.space` -> `spaceName` to match. +- **Rationale:** A field literally named after a type (`space: string` next to + `interface Space`) violates the "field contradicting type domain" rule. + +### H9. `name` is the App's primary key, not `id` — ambiguous identifier +- **File:** `model.ts:725-729, 768-769, 1132-1135, 1176-1180` +- **Category:** Underspecified IDs (19), Misleading names (6) +- **Issue:** `App.name` is the URL-path identifier used by all client methods + (`/api/2.0/apps/${req.name}`); `App.id` is a separate "unique identifier" + string. Several request types (`DeleteAppRequest`, `GetAppRequest`, + `UpdateAppThumbnailRequest`, `StartAppRequest`, `StopAppRequest`, + `DeleteAppThumbnailRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`) carry a + bare `name?: string` field. The same `App.name` field also appears in + `AsyncUpdateAppRequest.appName` (the disambiguated form). Both + conventions appear in the same package. +- **Suggestion:** Standardise on `appName` for all single-target Apps request + types. `DeleteAppRequest.name` -> `appName`; similarly for the others. The + existing `AsyncUpdateAppRequest.appName` and `GetAppDeploymentRequest.appName` + already follow this rule. +- **Rationale:** The wire-level field is `name`, but the TS field can be + renamed via the marshal/unmarshal mapping. Mixing `name` and `appName` for + the same role across request types makes the API harder to discover. + +### H10. `AppDeployment_State` vs `AppUpdate_UpdateStatus_UpdateState` vs `SpaceUpdateState` — three different conventions for "state of an async op" +- **File:** `model.ts:524, 684, 515` +- **Category:** Verb-tense inconsistency (13), Duplicate concepts (12) +- **Issue:** Three sibling state enums in the same file follow three different + naming conventions: + - `AppDeployment_State` — type nested under parent. + - `AppUpdate_UpdateStatus_UpdateState` — type doubly-nested. + - `SpaceUpdateState` — flat. + Their values are also inconsistent (`SUCCEEDED/FAILED/IN_PROGRESS/CANCELLED` + vs `SUCCEEDED/FAILED/IN_PROGRESS` vs `NOT_UPDATED/IN_PROGRESS/SUCCEEDED/FAILED`). +- **Suggestion:** Pick one shape for state enums and apply to all three. + Suggested target: `AppDeploymentState`, `AppUpdateState`, `SpaceUpdateState` + (all flat, no underscores). Consider sharing a `LongRunningState` enum if + the value sets actually align. +- **Rationale:** A consumer trying to discover the "state" enum of an Apps + async operation can't predict the spelling pattern from one example to the + next. + +### H11. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym +- **File:** `model.ts:772-773` +- **Category:** Acronym casing inconsistencies (3) +- **Issue:** The fields use `oauth2` (all-lowercase) embedded with PascalCase. + Google's TS style guide treats this as an acronym; the canonical case is + `oAuth2` for camelCase (or `OAuth2` for PascalCase). The actual specification + capitalises it as "OAuth 2.0". +- **Suggestion:** Rename to `oauth2AppIntegrationId` -> `oAuth2AppIntegrationId` + (or accept the eslint exception for compatibility with the wire field + `oauth2_app_integration_id`). +- **Rationale:** Inconsistent with how the SDK treats other acronyms (e.g. + `Url` in `thumbnailUrl`, `Id` in many fields). + +### H12. `defaultGitSource` / `defaultSourceCodePath` / `gitRepository` — three coexisting "source" concepts on `App` +- **File:** `model.ts:760-763, 776-781, 786-794` +- **Category:** Duplicate concepts (12), Misleading names (6) +- **Issue:** `App` has all of: + - `defaultSourceCodePath?: string` + - `defaultGitSource?: GitSource` + - `gitRepository?: GitRepository` + - `deploymentSource` discriminated union of `sourceCodePath | gitSource` + This creates four overlapping ways to describe deployment provenance. +- **Suggestion:** Treat the `default*` pair as the historical (last-deployed) + data; rename to `lastDeploymentSourceCodePath` / `lastDeploymentGitSource` + to mirror `lastDeploymentId`. Then `gitRepository` is the per-app + configuration, and `deploymentSource` is the union for *new* deployments — + three clearly differentiated roles. +- **Rationale:** Today a reader can't tell whether `defaultGitSource` is the + default for new deployments, the most-recently-used source, or the + registered repo. The Go doc comment on the field clarifies it tracks the + last active deployment, but the name does not. + +### H13. `noCompute` boolean on `CreateAppRequest` +- **File:** `model.ts:1091-1095` +- **Category:** Misleading names (6) +- **Issue:** `noCompute?: boolean` with doc "If true, the app will not be + started after creation." The negation in the name plus the documented + semantics ("not started" vs "no compute") leaves room for misinterpretation + — does `noCompute=true` mean *no compute allocated* (release-the-resources) + or *don't auto-start*? +- **Suggestion:** Rename to `skipStart` or `startOnCreate` (positive form, + default `true`), and update the doc to be explicit. The Go SDK historically + uses `no_compute`, so the wire name needs to remain; just rename the TS + field. +- **Rationale:** Negated booleans are a documented anti-pattern; the field + also describes a behaviour ("start") rather than its surface effect ("no + compute"). + +### H14. Singular `permission` field holding a single value but documented as plural permissions +- **File:** `model.ts:866-869, 984-989` +- **Category:** Singular/plural mismatches (9) +- **Issue:** `AppManifest_AppResourceJobSpec.permission?: ...JobPermission` + has doc text `Permissions to grant on the Job. Supported permissions are: + "CAN_MANAGE", "IS_OWNER", "CAN_MANAGE_RUN", "CAN_VIEW".` Same pattern in + `AppResourceJob.permission` (line 987). The field name is singular but the + doc says "Permissions" (plural) and lists four. The same hybrid singular/ + plural language appears in seven other resource specs. +- **Suggestion:** Either (a) make the field plural and convert it to an array + if multiple values can be granted, or (b) keep singular and reword the doc to + "Permission to grant on the job. One of: ...". Today the singular type + enforces (b) — the doc should match. +- **Rationale:** The doc text contradicts the type signature, so consumers + reading either will be misled. + +--- + +## Medium-severity findings + +### M1. `creator` / `updater` — bare-noun fields holding emails +- **File:** `model.ts:744, 748, 818, 820, 1372, 1376` +- **Category:** Generic field names (15), Misleading names (6) +- **Issue:** `creator?: string` is documented as "The email of the user that + created the app". The field name suggests an identity or a user object, but + the value is specifically an email address. +- **Suggestion:** Rename to `creatorEmail` and `updaterEmail`. Same on + `AppDeployment.creator`, `Space.creator`, `Space.updater`, + `CustomTemplate.creator`. + +### M2. `defaultSourceCodePath` — what does "default" mean here? +- **File:** `model.ts:760-762` +- **Category:** Vague/generic (1), Misleading names (6) +- **Issue:** Doc says it "tracks the workspace source code path of the last + active deployment". So the field is historical, not a default. +- **Suggestion:** Rename to `lastActiveDeploymentSourceCodePath` or + `effectiveSourceCodePath`. Same critique for `defaultGitSource`. + +### M3. `effective*` fields paired with non-prefixed siblings +- **File:** `model.ts:764-771, 775-776, 1382, 1392` +- **Category:** Duplicate concepts (12) +- **Issue:** `App` has paired fields: `budgetPolicyId/effectiveBudgetPolicyId`, + `usagePolicyId/effectiveUsagePolicyId`, `userApiScopes/effectiveUserApiScopes`. + Same on `Space`. The relationship (one is requested, the other is what + actually applies) is not visible from the names. +- **Suggestion:** Add JSDoc explicitly distinguishing the requested vs + effective values, or rename to `requestedBudgetPolicyId` / `appliedBudgetPolicyId`. + +### M4. `userApiScopes` field name vs OAuth-scope concept +- **File:** `model.ts:767, 770-771, 1380-1382` +- **Category:** Vague/generic (1) +- **Issue:** `userApiScopes?: string[]`. The doc on `Space.userApiScopes` says + "OAuth scopes for apps in the space." The TS field name says "user API + scopes", which is neither the wire name nor the documented concept. +- **Suggestion:** Rename to `oauth2Scopes` or `userOAuth2Scopes` to make the + protocol clear. + +### M5. `command?: string[]` — what kind of command? +- **File:** `model.ts:821-822` +- **Category:** Vague/generic (1) +- **Issue:** `AppDeployment.command` is "The command with which to run the + app." But it's an array of strings (argv-style); the name doesn't hint at + that. +- **Suggestion:** Rename to `startCommand` (matches Docker's `CMD` ENTRYPOINT + semantics) or `runCommand`. Adding to JSDoc is acceptable as an alternative. + +### M6. `EnvVar` — too short +- **File:** `model.ts:1152`, also `index.ts:89` +- **Category:** Cryptic abbreviations (5) +- **Issue:** `EnvVar` reads as Go-style. Full TS conventions prefer + `EnvironmentVariable` or, since it carries both name and source, more + precisely `EnvironmentVariableSetting`. The Go SDK uses `EnvVar` because + Go conventionally abbreviates more aggressively; the TS port doesn't + inherit that. +- **Suggestion:** Rename to `EnvironmentVariable`. Note: this is contested by + the `feedback_no_extra_abstractions.md` memory entry — if the rule is + strict 1:1 with Go names, leave as-is. + +### M7. `envVars` plural OK but contradicts singular-source pattern +- **File:** `model.ts:824, 1152-1166` +- **Category:** Singular/plural mismatches (9) +- **Issue:** `AppDeployment.envVars?: EnvVar[]` is plural and correct, but + inside each `EnvVar` the `source` field is a `{$case: 'value'; value: string} + | {$case: 'valueFrom'; valueFrom: string}` union. The latter union arm is + `valueFrom: string` — a field name that's almost a clause (`value-from`) and + whose direction is unclear (a path-to-fetch-from? a literal string starting + with the word "from"?). +- **Suggestion:** Rename `valueFrom` -> `valueRef`, `secretRef`, or + `valueSource`. Update the discriminator literal `'valueFrom'` accordingly. + +### M8. `AppManifest.version: number` carries no unit +- **File:** `model.ts:842` +- **Category:** Vague/generic (1) +- **Issue:** "The manifest schema version, for now only 1 is allowed". Field + is a bare `number`; reader has to read the doc to know it's an integer + schema-revision number. +- **Suggestion:** Rename to `schemaVersion` and document it as a positive + integer. + +### M9. `CustomTemplate.gitRepo` vs `GitRepository` type +- **File:** `model.ts:1113-1114, 1120` +- **Category:** Cryptic abbreviations (5), Singular/plural mismatches with type name (9) +- **Issue:** `CustomTemplate.gitRepo?: string` (URL string) sits adjacent to + the `GitRepository` interface used elsewhere. The abbreviation `gitRepo` is + inconsistent with the full word `gitRepository` used 6 times in the file. +- **Suggestion:** Rename to `gitRepositoryUrl` (since the field stores a URL, + not an object reference) or align on `gitRepoUrl` package-wide. + +### M10. `path` on `CustomTemplate` — path of what, where? +- **File:** `model.ts:1115-1116` +- **Category:** Vague/generic (1) +- **Issue:** `CustomTemplate.path?: string` — "The path to the template within + the Git repository." Bare `path` is too generic for a public field. +- **Suggestion:** Rename to `templatePath` or `gitPath`. + +### M11. `gitProvider?: string` — should be enum/union +- **File:** `model.ts:1119-1120, 1207-1210` +- **Category:** Vague/generic (1) +- **Issue:** `CustomTemplate.gitProvider` and `GitRepository.provider` are + free-form strings, but the doc on `GitRepository.provider` enumerates eight + legal values (gitHub, gitHubEnterprise, bitbucketCloud, etc.). The type + should be a string-literal union or enum. +- **Suggestion:** Define `enum GitProvider { GIT_HUB, GIT_HUB_ENTERPRISE, ... }` + or a string-literal union of the documented values. + +### M12. `GitRepository.provider` vs `CustomTemplate.gitProvider` — same concept, different name +- **File:** `model.ts:1119, 1210` +- **Category:** Duplicate concepts (12) +- **Issue:** The Git provider name is `provider` on `GitRepository` but + `gitProvider` on `CustomTemplate`. Two names for the same field. +- **Suggestion:** Standardise on `provider` everywhere (since the surrounding + type makes the qualifier obvious) or on `gitProvider` (more searchable). + +### M13. `callerCredentialId?: number` on `GitRepository` +- **File:** `model.ts:1213-1217` +- **Category:** Underspecified IDs (19) +- **Issue:** `callerCredentialId: number` — a numeric ID with no domain prefix. + "caller" is also a vague qualifier; the doc says it's "a personal access + token Git credential". +- **Suggestion:** Rename to `gitCredentialId` or `callerGitCredentialId`. Note + also: the marshal layer keeps it as a number, but every other ID field in + this package is a string (`servicePrincipalId` is the only other number-ID, + matching Go's int64). Verify the wire type. + +### M14. `appName` field name in `AsyncUpdateAppRequest` carrying a redundant nesting +- **File:** `model.ts:1063-1067` +- **Category:** Redundant suffixes (8) +- **Issue:** `AsyncUpdateAppRequest` already contains an `app: App` field, and + separately an `appName: string` field that's just `req.app.name`. This is + visible at `client.ts:125`: `${this.host}/api/2.0/apps/${req.appName ?? ''}` + with no consultation of `req.app?.name`. +- **Suggestion:** Drop `appName` from `AsyncUpdateAppRequest` and read + `req.app?.name` (as `updateApp` already does at `client.ts:840`). This is a + semantic change; flag for discussion. Alternative: keep both and document + which wins on conflict. + +### M15. `AppManifest_AppResourceUcSecurableSpec_UcSecurableType` and + `AppResourceUcSecurable_UcSecurableType` — duplicated enum +- **File:** `model.ts:598-603, 676-681` +- **Category:** Duplicate concepts (12) +- **Issue:** Two identical enums (`VOLUME`, `TABLE`, `FUNCTION`, `CONNECTION`) + — one for the manifest spec, one for the runtime resource. Same value set, + different name. +- **Suggestion:** Consolidate to a single `UcSecurableType` enum and reference + it from both `AppManifest_AppResourceUcSecurableSpec` and + `AppResourceUcSecurable`. + +### M16. `AppResourceUcSecurable_UcSecurablePermission` is a strict subset of `AppManifest_AppResourceUcSecurableSpec_UcSecurablePermission` +- **File:** `model.ts:587-595, 666-673` +- **Category:** Duplicate concepts (12) +- **Issue:** Spec enum has 7 values (`READ_VOLUME`, `WRITE_VOLUME`, `MANAGE`, + `SELECT`, `EXECUTE`, `USE_CONNECTION`, `MODIFY`). Resource enum has 6 — same + list minus `MANAGE`. The relationship is undocumented; the duplication is + fragile. +- **Suggestion:** Define one shared `UcSecurablePermission` and, if `MANAGE` + isn't actually grantable at runtime, document that. Or define two related + enums where one is a subset reference (not duplicated). + +### M17. `AppDeployment.deploymentId` — `deployment` repeats outer type +- **File:** `model.ts:798-799` +- **Category:** Type-suffix tautology (20) +- **Issue:** Within the `AppDeployment` interface, `deploymentId` repeats the + outer name. Inside `AppDeployment` the unqualified `id` would suffice and + matches the pattern in `App.id`, `Space.id`, `AppResourceExperiment.experimentId` + (also tautological), and `AppResourceJob.id` (correctly unqualified). +- **Suggestion:** Rename `AppDeployment.deploymentId` -> `id`. Same for + `AppResourceExperiment.experimentId` -> `id`, `AppResourceGenieSpace.spaceId` + -> `id`. + +### M18. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types +- **File:** `model.ts:1015, 769, 1368, 1900` +- **Category:** Underspecified IDs (19) +- **Issue:** `AppResourceSqlWarehouse.id` is a SQL warehouse ID, `App.id` is an + App ID, `AppResourceJob.id` is a Job ID. All are bare `id`. JSON output + serializes the same key for very different identifiers. +- **Suggestion:** Either accept the convention (`id` always means "the entity + this object describes") or be explicit (`sqlWarehouseId`, `jobId`, + `experimentId`). The package is currently inconsistent — see M17, where the + rename runs the *opposite* direction. + +### M19. `UnityCatalog` interface — generic name, no role suffix +- **File:** `model.ts:1434-1441`, also `index.ts:114` +- **Category:** Vague/generic (1) +- **Issue:** `UnityCatalog` is exported as a public type. The interface has + three table-name fields (`logsTable`, `metricsTable`, `tracesTable`) and is + used only as a telemetry-export destination. Exporting a type called + `UnityCatalog` at the package boundary suggests "the Unity Catalog itself", + which it isn't. +- **Suggestion:** Rename to `UnityCatalogTelemetryDestination` or + `UnityCatalogTables`. Inline if not reused. + +### M20. `Operation.result` carries `error` and `response` arms +- **File:** `model.ts:1343-1354` +- **Category:** Vague/generic (1) +- **Issue:** The `response` arm holds `Record` — a totally + untyped payload. The consumer at `client.ts:1022` immediately re-parses it + through `unmarshalSpaceSchema`. The name `response` and the unknown type + conceal what's actually inside. +- **Suggestion:** Use generics: `Operation` with `result: ... | + {$case: 'response'; response: TResponse}`. Or split into + `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name + promises nothing. + +### M21. `marshalRequest`, `marshalAppSchema`, ..., `marshal` vs `unmarshal` +- **File:** `model.ts:2306, 2404, ...`, `utils.ts:119` +- **Category:** Inconsistent action verbs (17) +- **Issue:** `marshal`/`unmarshal` is gRPC-/Go-vernacular. JavaScript's + baseline vocabulary is `serialize`/`deserialize` or `toJSON`/`fromJSON`. +- **Suggestion:** Either keep the Go names (for porting consistency) or + rename across the SDK. Documenting the convention in `porting.mdc` is the + easier path. + +### M22. `parseResponse` / `marshalRequest` - inconsistent verb pairing +- **File:** `utils.ts:113, 119` +- **Category:** Inconsistent action verbs (17) +- **Issue:** Adjacent helpers use different verb conventions: `parseResponse` + (parse/serialize convention) and `marshalRequest` (marshal/unmarshal + convention). The natural pair would be `unmarshalResponse` and + `marshalRequest`, or `parseResponse` and `serializeRequest`. +- **Suggestion:** Rename `marshalRequest` -> `serializeRequest` or + `parseResponse` -> `unmarshalResponse`. + +### M23. `flattenQueryParams` — what does it flatten? +- **File:** `utils.ts:123` +- **Category:** Vague/generic (1) +- **Issue:** `flattenQueryParams(prefix, value, params)` — the function + flattens *nested object structures* into dotted query keys + (`a.b.c=value`). The verb "flatten" doesn't communicate the target format. +- **Suggestion:** Rename to `encodeNestedQueryParams` or + `appendObjectAsQueryParams`. + +### M24. `readAll` — local helper exported as `readAll` +- **File:** `utils.ts:40` +- **Category:** Vague/generic (1) +- **Issue:** `readAll(body: ReadableStream | null)` — reads-all of + what? The function reads a stream to completion. +- **Suggestion:** Rename to `readStreamToBytes` or `consumeStream`. (It's not + exported, so impact is local.) + +### M25. `executeCall` vs `executeHttpCall` — pair drifts in meaning +- **File:** `utils.ts:26, 65` +- **Category:** Inconsistent action verbs (17) +- **Issue:** `executeCall` is the *outer* retry/rate-limit wrapper; + `executeHttpCall` is the *inner* one-shot HTTP send. The function names + suggest the former is just a generic "execute" and the latter adds HTTP, but + in practice every concrete call goes through both. Disambiguating names + would help. +- **Suggestion:** Rename to `runWithRetries`/`sendHttp`, or `runCall`/`sendOne`. + +### M26. `StillRunningError` — internal sentinel class, named ambiguously +- **File:** `client.ts:93` +- **Category:** Misleading names (6) +- **Issue:** `class StillRunningError extends Error {}` — used as a sentinel + to drive retries. Reads like a real domain error but has no message and is + caught locally. Could be confused with a public error type. +- **Suggestion:** Rename to `pollAgainSentinel` (as a typed Error subclass) or + `RetryablePollError`, and add a comment that it never escapes the file. + +### M27. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +- **File:** `client.ts:121, 914` +- **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) +- **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, + long-running operations that return an `AppUpdate`/`Operation` and have a + corresponding `*Waiter`/`*Operation` companion. But `asyncUpdateApp` is + prefixed with `async`, while `updateSpace` is not. Either both should be + prefixed (`asyncUpdateSpace`) or neither. +- **Suggestion:** Drop the `async` prefix from `asyncUpdateApp` to match + `updateSpace`, or add `asyncUpdateSpace` for symmetry. + +### M28. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +- **File:** `client.ts:309, 408, 951` +- **Category:** Type-suffix tautology (20) +- **Issue:** Methods named `createSpaceOperation()` return a + `CreateSpaceOperation` wrapper (not an `Operation` directly). A reader + scanning autocomplete sees both `createSpace()` and + `createSpaceOperation()` and has to read the doc to disambiguate. +- **Suggestion:** Rename the wrapper-returning method to + `createSpaceAndWait()` or `createSpaceLongRunning()`. The `*Operation` class + could be `*LongRunning` (mirroring the `Operation` type's role). + +--- + +## Low-severity findings + +### L1. `AppDeployment_Mode.MODE_UNSPECIFIED` — `MODE_` prefix redundant +- **File:** `model.ts:525` +- **Category:** Redundant enum prefixes (2) +- **Suggestion:** `MODE_UNSPECIFIED` -> `UNSPECIFIED`. Already covered in H4 + but called out separately for tracking. + +### L2. `AppDeployment.mode` doc: "The mode of which the deployment will manage the source code." +- **File:** `model.ts:809` +- **Category:** Grammar / clarity (not in numbered categories but flagged) +- **Suggestion:** "of which" should be "in which" or "by which". A nit, not a + rename, but flagged because it appears in the public API docs. + +### L3. `App.creator` and `App.updater` — `updater` is a real English word but commonly used for libraries/tools +- **File:** `model.ts:746-748` +- **Category:** Misleading names (6) +- **Issue:** Outside of CRUD-stamp contexts, "updater" often denotes a + software-update agent (e.g. Sparkle). Pair with M1 — both should become + `*Email` if that's the value type. + +### L4. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` +- **File:** `model.ts:743-748` +- **Category:** Field contradicting type domain (16) +- **Suggestion:** No type change available short of a branded type; document + the format in JSDoc. + +### L5. `App.url` doc: "URL of the app once it is deployed" +- **File:** `model.ts:734-735` +- **Category:** Misleading names (6) +- **Suggestion:** Rename `App.url` -> `App.appUrl` or `App.deploymentUrl` for + clarity, especially because `GitRepository.url` is also called `url` in the + same file. (Currently both are bare `url`.) + +### L6. `GitRepository.url` — same generic `url` as `App.url` +- **File:** `model.ts:1205` +- **Category:** Generic field names (15) +- **Suggestion:** Rename to `repositoryUrl` (mirror with `GitRepository.provider` + named more specifically). + +### L7. `GitSource.resolvedCommit` — does it carry SHA or ref? +- **File:** `model.ts:1248-1253` +- **Category:** Vague/generic (1) +- **Suggestion:** Rename to `resolvedCommitSha` to match the doc, which says + "the resolved commit SHA". + +### L8. `GitSource.sourceCodePath` — verbose +- **File:** `model.ts:1242-1246` +- **Category:** Overly verbose (7) +- **Suggestion:** Inside `GitSource`, simply `path` would be unambiguous (the + whole interface is about source location). + +### L9. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" +- **File:** `model.ts:894-895` +- **Category:** Doc / clarity +- **Suggestion:** Drop or rephrase the reference to `app.proto`; in TS the + reference is meaningless. + +### L10. `unmarshalAppManifest_AppResourceServingEndpointSpecSchema` — extremely long Zod variable name +- **File:** `model.ts:1690, 2532` +- **Category:** Overly verbose (7) +- **Issue:** 60-character private const. Inherited from H3. +- **Suggestion:** Rename via H3. + +### L11. `unmarshalListAppsResponseSchema` etc. — verb `unmarshal` repeated +- **File:** `model.ts:2133, 2146, 2156, 2169, 2180, 2202, 2246, 2256, ...` +- **Category:** Verbosity (7) +- **Suggestion:** Group under a namespace + `unmarshal.ListAppsResponse`, `unmarshal.Operation`, etc., or shorten with + `parseListAppsResponse`. + +### L12. `appFieldMaskSchema` / `appDeploymentFieldMaskSchema` etc. — every type gets a parallel `*FieldMaskSchema` +- **File:** `model.ts:3075, 3135, 3152, 3156, 3161, 3167, 3173, 3180, 3192, 3215` +- **Category:** Verbose / repetitive +- **Suggestion:** Consider a `fieldMasks.app`, `fieldMasks.appDeployment` + namespace object rather than 10 individually named consts. + +### L13. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers +- **File:** `model.ts:3131, 3211` +- **Category:** Vague/generic (1) — qualified by entity, but +- **Issue:** Inconsistent that only `App` and `Space` get an exported helper — + no `appDeploymentFieldMask`, despite the `AppDeployment` having an internal + schema. Suggests the API is incomplete. +- **Suggestion:** Either expose helpers for every entity with a field-mask + schema, or none. + +### L14. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models +- **File:** `model.ts:783-784, 1032-1035` +- **Category:** Duplicate concepts (12) +- **Suggestion:** Document that `thumbnailUrl` is the display URL and + `AppThumbnail.thumbnail` is the byte content (used in + update/delete-thumbnail requests). + +### L15. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` +- **File:** `model.ts:1156-1166` +- **Category:** Vague/generic (1) +- **Suggestion:** Discriminator `'value'` and `'valueFrom'` are short; consider + `'literal'` and `'reference'` to make intent clearer. (Wire field names + unchanged.) + +### L16. `Space` interface — same name as the Genie product `AppResourceGenieSpace` +- **File:** `model.ts:1357, 978-982` +- **Category:** Duplicate concepts (12) +- **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share + the "space" noun and both have a `spaceId` field. They are unrelated + domains. +- **Suggestion:** Rename `Space` -> `AppSpace` everywhere (`AppSpace`, + `CreateAppSpaceRequest`, `UpdateAppSpaceRequest`, `AppSpaceStatus`, etc.). + Many of the comments in this file already say "app space" — the type name + is the outlier. This realignment also clarifies the wire URLs + (`/api/2.0/app-spaces/...`). + +### L17. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, + `ListSpacesRequest`, etc., do not mention "App" +- **File:** `model.ts:1101, 1147, 1197, 1301`, also `index.ts:82-88, 105` +- **Category:** Vague/generic (1) +- **Suggestion:** Tied to L16 — rename these to `CreateAppSpaceRequest`, etc. + +### L18. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? +- **File:** `model.ts:1308-1312, 1282-1286` +- **Category:** Observation — both follow the same pattern. Tied to L16 again + for the entity rename. + +### L19. `CreateAppDeploymentRequest.autoDeploy` doc: "Whether to enable automatic deployments on push events to the git repository" +- **File:** `model.ts:1086-1089` +- **Category:** Misleading names (6) +- **Issue:** The field name suggests "deploy automatically now". The doc says + it sets up a webhook. These are very different ideas. +- **Suggestion:** Rename to `enableAutoDeploy` or `webhookAutoDeploy`. + +### L20. `GitRepository.autoDeploy` vs `CreateAppDeploymentRequest.autoDeploy` +- **File:** `model.ts:1086, 1211` +- **Category:** Duplicate concepts (12) +- **Issue:** Two `autoDeploy` fields in the same file: one on the deployment + request, one on the repository. They probably express the same setting at + different layers, but neither says so. +- **Suggestion:** Document the relationship in JSDoc; if they're the same + state, only one should exist. + +### L21. `Operation.name` — server-assigned UNIQUE name, not human-readable +- **File:** `model.ts:1319-1324` +- **Category:** Misleading names (6) +- **Issue:** `Operation.name` is the operation *identifier* path + (`operations/{unique_id}`) — distinct from `App.name` (the App entity's + primary key, a slug) and `Space.name`. Multiple `name` semantics in the + package. +- **Suggestion:** Rename to `operationName` or, given the format, just `path`. + +### L22. `Client` class — exported as bare `Client` +- **File:** `client.ts:95`, also `index.ts:4` +- **Category:** Vague/generic (1) +- **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the + Client" with no domain. If a consumer also imports `Client` from + `@databricks/sdk-jobs`, they need an alias. +- **Suggestion:** Rename to `AppsClient`. Common SDK convention. + +### L23. `host` (private field on `Client`) +- **File:** `client.ts:96` +- **Category:** Vague/generic (1) +- **Issue:** `private readonly host: string`. The doc on the workspace + parameter usually calls this the "workspace host" or "workspace URL". +- **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, + cosmetic. + +### L24. `getSpaceOperation` (method) vs `GetOperationRequest` +- **File:** `client.ts:536-558` +- **Category:** Type-suffix tautology (20) +- **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells + you it's a space operation, but the request type doesn't. Mismatch. +- **Suggestion:** Either `getOperation` (matching `GetOperationRequest`) or + `GetSpaceOperationRequest` (matching the method name). The current pairing + is asymmetric. + +--- + +## Observations (not necessarily problems) + +### O1. `App` is the primary noun; `Application*` only appears where state is concerned +This is the cleanest distinction in the package: the entity is `App` (URL, +field name `app`), and the runtime metadata is `Application*`. Resolving H1 +fixes the inconsistency. + +### O2. `Operation` lifecycle wrappers come in two flavours: `*Operation` and `*Waiter` +- `CreateSpaceOperation`, `DeleteSpaceOperation`, `UpdateSpaceOperation` — + driven by `google.longrunning.Operation` (poll a separate endpoint). +- `AsyncUpdateAppWaiter`, `CreateAppDeploymentWaiter`, `CreateAppWaiter`, + `StartAppWaiter`, `StopAppWaiter` — driven by polling the entity itself. + +The two flavours are confusing as named. Consider renaming +`*Operation` -> `*LongRunning` so the difference (LRO vs status-poll) is +visible. + +### O3. Field-mask helpers exist for `App` and `Space` only +`appFieldMask()` and `spaceFieldMask()` are exported; equivalents for +`AppDeployment` etc. are not. Probably intentional (only `App` and `Space` +have an update endpoint that takes a mask), but worth confirming. + +### O4. Every nested message has both `marshal*` and `unmarshal*` schemas +This doubles every name. If the project goal is 1:1 with Go's +`MarshalJSON`/`UnmarshalJSON`, this is correct; otherwise, a single bi-directional +`*Schema` would halve the API surface. + +### O5. Discriminated unions use `$case` — borrowed from `ts-proto` oneof +The `$case` discriminator is non-idiomatic in hand-written TS (most consumers +use plain `kind: 'X'`). Documenting this in the package README would help. + +### O6. `CustomTemplate` doesn't carry "App" in its name, but it's an app template +The doc and methods make this clear (`createCustomTemplate` -> +`/api/2.0/apps-settings/templates`), but the type name is ambiguous. +Consider `AppTemplate` or `CustomAppTemplate`. + +### O7. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter +Asymmetry but probably intentional. + +### O8. `ApplicationStatus.runningInstances` vs `ComputeStatus.activeInstances` +Two related counts, different verbs. `runningInstances` for app process, +`activeInstances` for compute resources. Document the distinction. + +### O9. `ListAppsRequest.space` filters by space name (string), not by +`Space` object — consistent with H8 issue. + +### O10. The package re-exports the `apierr` enum locally +Per H5, this enum should live in `@databricks/sdk-databricks/apierror/codes`. +The project memory note already calls this out +(`packages/databricks/src/apierror/codes/`). + +### O11. Files use `// eslint-disable-next-line` for every Proto-style nested name +60+ disables across `model.ts`. Fixing H3 eliminates the disables. + +### O12. `index.ts` exports +- 18 enums +- 51 type aliases +- 8 named exports from `./client` (1 class + 7 wrapper classes) + +That's 77 top-level exports. Worth checking whether the wrapper classes +(`*Operation`, `*Waiter`) need to be public or if they're implementation +detail. + +--- + +## Domain glossary + +| Term in code | What it actually means | Notes | +| ------------ | ---------------------- | ----- | +| `App` | A Databricks App (interactive application instance) | Primary entity. | +| `Application` | Runtime view of an App's process/server | Only used in `ApplicationStatus*`. See H1. | +| `AppDeployment` | A specific deployment (source-code + config snapshot) | Has its own `id`, status, lifecycle. | +| `AppManifest` | Schema describing required resources for an app | Used by `CustomTemplate`. | +| `AppResource` | A binding from an App to another Databricks resource | Discriminated union of 10 cases. | +| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L16. | +| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L16. | +| `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | +| `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H7. | +| `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | +| `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M15/M16. | +| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L14. | +| `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M6. | +| `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | +| `GitSource` | Specific commit/branch/tag + path within a `GitRepository` | Used by deployments. | + +--- + +## File coverage + +| File | Lines read | Coverage | +| ---- | ---------- | -------- | +| `src/v1/index.ts` | 120 / 120 | 100% | +| `src/v1/utils.ts` | 151 / 151 | 100% | +| `src/v1/model.ts` | 3219 / 3219 | 100% | +| `src/v1/client.ts` | 1615 / 1615 | 100% | + +All types, fields, enum values, and methods reviewed. diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md new file mode 100644 index 00000000..9e9f85e0 --- /dev/null +++ b/.agent/naming-audit/artifactallowlists.md @@ -0,0 +1,348 @@ +# Naming Audit: `artifactallowlists` (v1) + +Package path: `/home/parth.bansal/sdk-js/packages/artifactallowlists/` +Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts`. + +Notation: file paths are absolute. Findings reference `file:line`. + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 3 | +| Medium | 6 | +| Low | 4 | +| Observation | 7 | +| **Total** | **20** | + +Headline themes: + +1. **Request types lack a `Request` suffix** (e.g. `GetArtifactAllowlist`, + `SetArtifactAllowlist`). They are imperative phrases that read like + operations, not data shapes — and `GetArtifactAllowlist` collides + semantically with the `getArtifactAllowlist` method on `Client`. This is a + codebase-wide convention question rather than a defect local to this + package; `accountsettings` and others use the `…Request` suffix while + `catalogs`, `connections`, `clusters`, etc. omit it. +2. **Proto-style underscore in `ArtifactMatcher_MatchType`** breaks the + TypeScript identifier convention but is a deliberate, repo-wide pattern + (see Observation O5 for evidence). Flagged for visibility only. +3. **Redundant `Info` suffix on `ArtifactAllowlistInfo`** is the canonical + payload type for both `Get` and `Set` responses; the suffix adds no + information beyond "this is a struct." +4. **Redundant `*_UNSPECIFIED` enum prefixes** repeat the enum domain + (`ARTIFACT_TYPE_UNSPECIFIED`, `MATCH_TYPE_UNSPECIFIED`) — but again this + is the universal proto-mirror convention across the SDK. + +Allowlist casing is **consistent** throughout the package (always +`Allowlist`, never `AllowList` or `Whitelist`). + +--- + +## High Severity + +### H1. `GetArtifactAllowlist` collides with the client method of the same name + +- **File / line:** `src/v1/model.ts:39`; cross-ref `src/v1/client.ts:66`. +- **Category:** #6 misleading name; #20 type-suffix tautology (inverse — + missing suffix). +- **Current:** `interface GetArtifactAllowlist { artifactType?: ArtifactType }`. +- **Suggestion:** `GetArtifactAllowlistRequest`. +- **Rationale:** `GetArtifactAllowlist` reads as an action / operation name. + TypeScript users who see `client.getArtifactAllowlist(req: GetArtifactAllowlist)` + must mentally distinguish a verb-phrase function from a verb-phrase type. + Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use + the `…Request` suffix; adopting that here removes the verb/noun overload. + +### H2. `SetArtifactAllowlist` carries server-derived fields on a request type + +- **File / line:** `src/v1/model.ts:44–55`. +- **Category:** #6 misleading name; #16 field contradicting type domain. +- **Current:** Fields `createdBy?: string` and `createdAt?: number` are + present on what is documented as the SET payload — these are server-set + timestamps/identities and are also present on `ArtifactAllowlistInfo`. +- **Suggestion:** Either rename to `SetArtifactAllowlistRequest` and remove + `createdBy` / `createdAt` (they are response-only), or — if the underlying + API truly accepts them — clarify in the doc that the server ignores them. +- **Rationale:** A request type whose name reads as a verb ("Set the + allowlist") but whose fields include response-only metadata is misleading. + This causes the marshal schema (`marshalSetArtifactAllowlistSchema`, + lines 94–110) to emit `created_by`/`created_at` keys back to the server + unnecessarily. Even if the server tolerates them, exposing them on the + request shape invites misuse. + +### H3. `marshalSetArtifactAllowlistSchema` typed `z.ZodType` (no parameter) + +- **File / line:** `src/v1/model.ts:94`; `marshalArtifactMatcherSchema` at + line 84 has the same shape. +- **Category:** #15 generic field name losing meaning; #20 type-suffix + tautology (the `Schema` suffix is intentional, but the parameter + `z.ZodType` is left untyped — this is a *naming via type* issue). +- **Current:** `export const marshalSetArtifactAllowlistSchema: z.ZodType = …`. +- **Suggestion:** Parameterize to `z.ZodType` (mirror + the unmarshal sibling at line 57: `z.ZodType`). +- **Rationale:** Without a generic parameter, the symbol's name promises a + typed schema for `SetArtifactAllowlist` but its compile-time signature is + `ZodType`. Readers must trust the name. The unmarshal variant + models this correctly; the marshal variants do not. + +--- + +## Medium Severity + +### M1. `ArtifactAllowlistInfo` — redundant `Info` suffix + +- **File / line:** `src/v1/model.ts:21`. +- **Category:** #8 redundant suffix; #14 Go/Java-style name. +- **Current:** `ArtifactAllowlistInfo`. +- **Suggestion:** `ArtifactAllowlist`. +- **Rationale:** `Info` adds no semantic content in TypeScript — the type + *is* the artifact-allowlist record returned by Get and Set. The `Info` + suffix is a Go/proto idiom (cf. `CatalogInfo`, `FunctionInfo`, + `ConnectionInfo`) but TypeScript convention is to keep the noun bare. If + the codebase deliberately mirrors Go, document it; otherwise dropping + `Info` would also free `ArtifactAllowlist` as the natural domain noun + (today, the package has no type with that bare name, even though it is + literally the "artifact allowlists" package). + +### M2. `GetArtifactAllowlist` / `SetArtifactAllowlist` use inconsistent +verbs vs. UC sibling APIs + +- **File / line:** `src/v1/model.ts:39, 44`; `client.ts:66, 96`. +- **Category:** #17 inconsistent action verbs. +- **Current:** `Get…` + `Set…`. +- **Suggestion:** Confirm whether `Set` is intentional vs. `Update`. The Unity + Catalog REST API frequently uses `PUT` semantics with `Update…` verbs (see + `catalogs`, `connections`, `externallocations`, `storagecredentials`). +- **Rationale:** The HTTP method here is `PUT` (`client.ts:106`) and the + docstring says "The whole artifact allowlist is replaced with the new + allowlist" — a replace semantic. UC peers typically expose this as + `update…`. If the API spec dictates `Set`, this is correct; the audit + flags it because the verb is unique within UC. + +### M3. `artifactMatchers` field is a Boolean-sounding plural of a matcher +type that is itself a noun-from-verb + +- **File / line:** `src/v1/model.ts:23, 48`. +- **Category:** #15 generic field name losing meaning. +- **Current:** `artifactMatchers?: ArtifactMatcher[]`. +- **Suggestion:** Consider `allowedPatterns` or `patterns` (matching the + field's own JSDoc: "A list of allowed artifact match patterns"). At + minimum, the inline doc should explain that an "ArtifactMatcher" is one + rule (artifact + match-type), not a function. +- **Rationale:** The doc comment ("allowed artifact match patterns") + describes a different mental model than the type name suggests. A reader + encountering `artifactMatchers` may expect predicate functions rather than + a `{artifact, matchType}` rule object. Note: this name *does* match the + Go SDK convention, so changing it would be a breaking divergence. + +### M4. `artifact` (the field inside `ArtifactMatcher`) is dangerously generic + +- **File / line:** `src/v1/model.ts:34`. +- **Category:** #1 vague/generic without domain context; #15 generic field + name losing meaning. +- **Current:** `artifact?: string`. +- **Suggestion:** `artifactPath` or `artifactPattern` (the docstring says + "The artifact path or maven coordinate"). +- **Rationale:** Inside a type already named `ArtifactMatcher`, `artifact` + contributes no information; the actual semantic is "the path/coordinate + this rule matches against." Either of `artifactPath` or `artifactPattern` + reflects that. Caveat: matches the Go SDK exactly, so a rename would + break the 1:1 port. + +### M5. `matchType` is contextless on `ArtifactMatcher` and the enum has a +unique prefix style + +- **File / line:** `src/v1/model.ts:36`; enum at line 15. +- **Category:** #2 redundant enum prefix; #18 long enum values. +- **Current:** `matchType?: ArtifactMatcher_MatchType` with values + `MATCH_TYPE_UNSPECIFIED`, `PREFIX_MATCH`. +- **Suggestion:** Drop the `MATCH_TYPE_` prefix from the unspecified value + (`UNSPECIFIED` — but see Observation O3 below for why this is repo-wide). + Otherwise the field name is fine as-is. +- **Rationale:** `MATCH_TYPE_UNSPECIFIED` repeats the enum name; in + TypeScript `ArtifactMatcher_MatchType.UNSPECIFIED` reads cleaner. This is + a SDK-wide convention so the change has cross-package implications. + +### M6. `req` parameter name on `Client.getArtifactAllowlist` / +`setArtifactAllowlist` + +- **File / line:** `src/v1/client.ts:67, 97`. +- **Category:** #5 cryptic abbreviation; #14 Go-style name. +- **Current:** `req: GetArtifactAllowlist`. +- **Suggestion:** `request` (matches Go-port readability without saving + characters that matter in TypeScript). +- **Rationale:** Throughout the JS/TS ecosystem, function parameters tend + to be spelled out (`request`, `response`) rather than abbreviated. The Go + `req`/`resp` idiom is fine in Go where short names are encouraged; in TS + it reads as Go-translated code. (Note: `resp` shows up locally in the + same file at lines 71, 84, 102, 115 — a separate, lower-priority issue.) + +--- + +## Low Severity + +### L1. `executeCall` vs. `executeHttpCall` — overlapping verbs + +- **File / line:** `src/v1/utils.ts:26, 65`. +- **Category:** #6 misleading name; #12 duplicate concepts. +- **Current:** Both functions live in the same file with very similar + names. `executeCall` is the public-options translator that delegates to + `execute` from `@databricks/sdk-core/api`. `executeHttpCall` is the low- + level HTTP send + parse helper. +- **Suggestion:** Rename `executeCall` to `runCallWithOptions` / + `dispatchCall` (or fold into `executeHttpCall` if the indirection is + trivial). At minimum, the JSDoc already calls this out as a *translator* + — the name should match. +- **Rationale:** Two functions named `execute*Call` in 70 lines of code, + with different return shapes (`Promise` vs. + `Promise`), is a readability hazard. The JSDoc on line 21–25 + explicitly says "Translates public CallOptions to the internal Options + shape," which is a better name. + +### L2. `Call` (imported, not local) and `call` local variable share names + +- **File / line:** `src/v1/client.ts:72` (`const call: Call = …`). +- **Category:** #1 vague/generic. +- **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. +- **Suggestion:** `httpCall` or `doRequest`. +- **Rationale:** `call` is a built-in word in JS (`.call()` on functions), + so a variable named `call` inside a method that is itself a call is + ambiguous. Caveat: this is a 1:1 port of Go SDK convention. + +### L3. `body` shadowed twice in `executeHttpCall` + +- **File / line:** `src/v1/utils.ts:81` and parameter `body` of + `buildHttpRequest` (line 101) / `parseResponse` (line 113) / + `marshalRequest` (line 119 — `data`). +- **Category:** #1 vague generic name. +- **Current:** `body: Uint8Array` (response body) vs. `body: string | + ReadableStream` (request body, in `buildHttpRequest`). +- **Suggestion:** `responseBody` / `requestBody`. +- **Rationale:** Within `client.ts` line 101 we already see + `const body = marshalRequest(…)` (a request body) being passed into a + function that internally also reasons about response bodies. Differentiating + with `requestBody` / `responseBody` would help readers. + +### L4. `marshalRequest` accepts `data: unknown` — the parameter name +contradicts the function's purpose + +- **File / line:** `src/v1/utils.ts:119`. +- **Category:** #15 generic field name losing meaning. +- **Current:** `function marshalRequest(data: unknown, schema: z.ZodType)`. +- **Suggestion:** `function marshalRequest(request: unknown, schema)` or + `(payload, schema)`. +- **Rationale:** The function name says "request", but the first argument + is named `data`. Calling at `client.ts:101` reads + `marshalRequest(req, marshalSetArtifactAllowlistSchema)` — `req` → + `data` loses the request semantics in the helper. + +--- + +## Observations (Repo-wide conventions, not local defects) + +### O1. Bare `GetX`/`SetX` request shapes are a repo-wide pattern + +Sibling packages `catalogs`, `connections`, `clusters`, `externallocations`, +`clusterpolicies` all use bare verb-phrases for request types. See evidence +in `grep -rE "^export interface (Get|Set|Create|Update|Delete)…"` across +the workspace. Changing this package alone would create asymmetry. + +### O2. Proto-style nested enum names with underscores are repo-wide + +`ArtifactMatcher_MatchType` is one of 20+ enums of the form +`_` across the workspace (`BudgetConfigurationFilter_Operator`, +`CleanRoomAutoApprovalRule_AuthorScope`, `ConversionInfo_State`, +`DatabaseInstance_State`, `EndpointStatus_State`, etc.). This violates +TypeScript naming convention (PascalCase, no underscores) but is the agreed +mirror of the Go SDK's `Parent_Field` proto idiom. The file even disables +the lint rule explicitly at `model.ts:14`. Flag for awareness only. + +### O3. `*_UNSPECIFIED` zero values repeated across enums + +Both `ArtifactType.ARTIFACT_TYPE_UNSPECIFIED` and +`ArtifactMatcher_MatchType.MATCH_TYPE_UNSPECIFIED` repeat the enum domain +in the member name. This is a proto-buf default and is consistent with +sibling packages (`CleanRoomAutoApprovalRule_AuthorScope`, +`DatabaseInstance_State`, …). Not a local defect. + +### O4. `…Info` suffix repeated across UC types + +`ArtifactAllowlistInfo` follows the `CatalogInfo`, `ConnectionInfo`, +`FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the +codebase decides to drop the `Info` suffix, this is one of many to fix. + +### O5. Allowlist terminology / casing is consistent + +`Allowlist` (single uppercase A, then lowercase `llowlist`) is used in +every position in this package: type names, methods, schemas, comments, +URL paths (`/artifact-allowlists/`), and the package name +`@databricks/sdk-artifactallowlists`. No `AllowList`, `Allow_list`, or +`Whitelist` anywhere. **Passes** the audit on this criterion. + +### O6. URL path constant is inlined + +The string `/api/2.1/unity-catalog/artifact-allowlists/${artifactType}` +appears twice (`client.ts:70` and `client.ts:100`) without a named +constant. Not a naming defect, but typical naming-audit findings include +"unnamed magic strings." Worth a note. + +### O7. `PACKAGE_SEGMENT.key` is computed from `pkgJson.name` via regex + +`client.ts:31–34`: `key: pkgJson.name.replace(/^@[^/]+\//, '')` strips the +`@databricks/` org prefix. The variable name `PACKAGE_SEGMENT` reads fine +but the `key`/`value` shape is generic — readers may not know `key` is +"package name" and `value` is "package version" without inspecting +`createDefault().with(...)`. No action required; cosmetic. + +--- + +## Domain glossary + +| Term | Meaning in this package | +| -------------------------- | ---------------------------------------------------------- | +| Artifact | A user-supplied resource (init script / jar / maven coord) installed onto a cluster. | +| Artifact type | One of `INIT_SCRIPT`, `LIBRARY_JAR`, `LIBRARY_MAVEN` — the kind of artifact being allowed. | +| Allowlist | Per-metastore list of artifacts permitted to run. Replaces the older "whitelist" terminology. | +| ArtifactMatcher | One rule entry on the allowlist: an `(artifact, matchType)` pair. | +| MatchType / MATCH_TYPE | How the matcher compares the candidate artifact to the stored pattern. Today only `PREFIX_MATCH`; spec reserves room for `EXACT_MATCH`, `WILDCARDS`. | +| Metastore | Unity Catalog top-level container the allowlist is scoped to. | +| Set / PUT | Replace-the-whole-allowlist semantic. Not an additive update. | + +--- + +## File coverage + +| File | Lines | Audited | +| -------------- | ----- | ------------------------------------------------ | +| `src/v1/model.ts` | 111 | All 4 types + 2 enums + 3 schemas + every field. | +| `src/v1/client.ts` | 121 | Class, constructor, 2 methods, all locals. | +| `src/v1/utils.ts` | 151 | All 7 exported / private functions and types. | +| `src/v1/index.ts` | 13 | All re-exports. | + +Type & symbol checklist: + +- [x] `ArtifactType` enum (4 members) → M5, O3. +- [x] `ArtifactMatcher_MatchType` enum (2 members) → M5, O2, O3. +- [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O4. +- [x] `ArtifactMatcher` interface (2 fields) → M3, M4. +- [x] `GetArtifactAllowlist` interface (1 field) → H1, O1. +- [x] `SetArtifactAllowlist` interface (5 fields) → H2, O1. +- [x] `unmarshalArtifactAllowlistInfoSchema` → no defect. +- [x] `unmarshalArtifactMatcherSchema` → no defect. +- [x] `marshalArtifactMatcherSchema` → H3 (untyped `z.ZodType`). +- [x] `marshalSetArtifactAllowlistSchema` → H3. +- [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. +- [x] `PACKAGE_SEGMENT` constant → O7. +- [x] `getArtifactAllowlist(req, options)` method → H1, M2, M6. +- [x] `setArtifactAllowlist(req, options)` method → H1, M2, M6. +- [x] `HttpCallOptions` interface → no defect. +- [x] `executeCall` function → L1. +- [x] `readAll` private function → no defect (name fits idiom). +- [x] `executeHttpCall` function → L1, L3. +- [x] `buildHttpRequest` function → L3. +- [x] `parseResponse` function → no defect. +- [x] `marshalRequest` function → L4. +- [x] `flattenQueryParams` function → no defect. +- [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). diff --git a/.agent/naming-audit/billableusagedownload.md b/.agent/naming-audit/billableusagedownload.md new file mode 100644 index 00000000..3b2ce112 --- /dev/null +++ b/.agent/naming-audit/billableusagedownload.md @@ -0,0 +1,152 @@ +# Naming Audit: billableusagedownload + +**Path:** `packages/billableusagedownload/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level CSV export of billable Databricks usage logs for a given month range. Single endpoint: `GET /api/2.0/accounts/{account_id}/usage/download`. No CRUD surface, no enums, no list/page semantics — just one streaming download method. +**Total weird names flagged:** 21 + +## Summary +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 7 | +| Low | 5 | +| Observation | 4 | + +## High severity + +### 1. Package name `billableusagedownload` embeds an action verb — `packages/billableusagedownload/` +- **Why weird:** Package names should be domain nouns (`billing`, `usage`, `accounts`). `billableusagedownload` is `noun+noun+verb` — the only verb-suffixed package in the workspace (compare `usagedashboards`, `usagepolicy`, `budgets`, `accountsettings`). The `download` verb belongs on the method, not the package. Users discovering the SDK would naturally search for "billing" or "usage", not for "billableusagedownload". +- **Category:** 7 (overly verbose), 14 (Go/proto-style names — this is almost certainly the protobuf package), 17 (inconsistent action-verb conventions vs sibling packages). +- **Suggested name:** Fold into a `billing` package alongside `usagedashboards` (most idiomatic), or rename to `billableusage` (drop the verb). The single method `Client.download()` then carries the action. +- **Rationale:** The Databricks REST API path is `/usage/download`, but the SDK shouldn't reproduce URL path segments as package names. The sibling `usagedashboards` package handles a closely related concern; the two should likely co-exist as one `billing` namespace. Worth raising at SDK-generator level. + +### 2. `DownloadRequest` — `src/v1/model.ts:3` +- **Why weird:** Type name is action-shaped (verb-prefixed), and the verb is generic. "Download" alone says nothing about what is being downloaded. Collides with `DownloadRequest` in `packages/files/src/v1/model.ts:?` — a user importing both packages must alias one (`import type {DownloadRequest as BillingDownloadRequest}`). Same collision applies to `DownloadResponse` (finding #3). +- **Category:** 1 (vague without domain context), 12 (duplicate concept across packages — `files` has the same names for unrelated payloads). +- **Suggested name:** `DownloadBillableUsageRequest` (matches the Go SDK message-name convention) or `DownloadUsageRequest`. +- **Rationale:** The collision with `files.DownloadRequest` is the killer here — they have completely different fields (`accountId`/`startMonth`/`endMonth`/`personalData` vs `filePath`) and one is `application/octet-stream` CSV while the other is binary file bytes. A user re-exporting both packages from an app barrel file gets a TS error or silently shadowed types. Renaming makes both imports safe. + +### 3. `DownloadResponse` — `src/v1/model.ts:30` +- **Why weird:** Same problems as #2: vague verb-shaped name, collides with `files.DownloadResponse`. Both packages use `contents: ReadableStream` as the sole field — the type shape is structurally identical but semantically distinct (CSV blob vs file bytes), which means TS structural typing will *not* catch a mix-up. +- **Category:** 1, 12, 6 (structurally identical to unrelated `files.DownloadResponse`, creates misleading shape match). +- **Suggested name:** `DownloadBillableUsageResponse`. +- **Rationale:** A `Promise` collides directly with the file-download response of the same name. Renaming disambiguates the two unrelated payloads and prevents the structural-typing trap. + +### 4. `DownloadRequest.startMonth` / `endMonth` are misleadingly optional — `src/v1/model.ts:15,20` +- **Why weird:** Both fields are typed `string | undefined`, but the JSDoc explicitly says `endMonth` "This field is required." — and `startMonth` is required in practice (the API would fail without it). The optionality contradicts the doc. +- **Category:** 6 (misleading — TS type says optional, doc says required), 16 (field type contradicts domain reality). +- **Suggested name:** Keep the field names; change the types to `string` (required) on both. Worth also renaming `startMonth`/`endMonth` to something more self-documenting like `fromMonth`/`toMonth` or `startMonth`/`untilMonth` — current names are fine. +- **Rationale:** TS strict mode rewards required fields with non-optional types; the doc and the type should agree. The Go SDK probably models these as `string` (empty-string defaults), which is a Go-ism; in TS, required strings should not carry `| undefined`. + +### 5. `DownloadRequest.personalData: boolean` field name — `src/v1/model.ts:26` +- **Why weird:** `personalData` is a boolean named after a noun. The field actually controls "include PII in the download". Boolean fields should read as predicates: `includePersonalData`, `includePii`, `withPii`. As written, the field reads as "the personal data" — a thing — not a flag. +- **Category:** 6 (misleading — name implies a value, type is a flag), 1 (vague — "personal data" without a verb is not actionable), 15 (generic field name losing meaning). +- **Suggested name:** `includePersonalData` (or `includePii`). Keep wire field as `personal_data`. +- **Rationale:** TS convention for booleans is `is*` / `has*` / `include*` / `should*`. Without a verb, `if (req.personalData)` reads as "if there is personal data" rather than "if personal data is enabled". The JSDoc has to spell out "Specify whether to include..." precisely because the field name doesn't. + +## Medium severity + +### 6. `DownloadRequest.accountId` field — `src/v1/model.ts:8` +- **Why weird:** The `accountId` lives on the request DTO *and* on `ClientOptions` (see `client.ts:39`). The client falls back from `req.accountId` to `this.accountId` (`client.ts:69`). Having the same identifier in two places, with one-overrides-the-other semantics, is a footgun: callers may set it once on the client and forget that a stale request value silently shadows it. +- **Category:** 12 (duplicate concept across types), 19 (underspecified id — same `accountId` means different things at different layers). +- **Suggested name:** Drop `accountId` from `DownloadRequest`. Make it a client-level concern only (it's a path parameter, not a body field). If per-call override is needed, document it explicitly. +- **Rationale:** The JSDoc on the field is a verbose explanation about getting your account ID from the console — content that belongs in `ClientOptions.accountId`, not duplicated per request. Removing it simplifies the API surface and eliminates the fallback chain in `client.ts`. + +### 7. `Client` class is unprefixed — `src/v1/client.ts:22` +- **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-billableusagedownload/v1'`, then has to rename it (`import {Client as BillableUsageClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Consistent across the SDK but worth flagging. +- **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). +- **Suggested name:** `BillableUsageDownloadClient` or `BillableUsageClient`. Or expose a namespace export instead of a bare class. +- **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. The SDK could expose `import * as billableUsage from '@databricks/sdk-billableusagedownload/v1'` and remove the `Client` symbol entirely, letting `billableUsage.Client` be the qualified name. + +### 8. `Client.download` method name — `src/v1/client.ts:65` +- **Why weird:** A bare `download` verb on the client. Outside the package context, `client.download(...)` reads as "download something" — the package name is the disambiguator. If a user composes multiple SDK clients (`billing.download()`, `files.download()`), the method names collide cognitively. Compare with `usagedashboards.Client` which probably exposes `createBillingUsageDashboard()` / `getBillingUsageDashboard()` — verb + domain noun. +- **Category:** 1 (vague), 17 (inconsistent verb-pattern across sibling packages). +- **Suggested name:** `downloadBillableUsage` (matches the request-type rename) or, if the package gets folded into `billing`, `downloadUsage`. +- **Rationale:** Domain-qualified method names read better when imported into application code. Even within the package, `billableUsageDownloadClient.download()` has a pleasing redundancy that a single naked `download()` does not. + +### 9. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:17` +- **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. +- **Category:** 1 (vague), 15 (generic field name losing meaning). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Cross-package consistency — same finding appears in every audited package. Worth normalising at generator level. + +### 10. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +- **Why weird:** `client.ts` does its own query-param construction inline (lines 70-79) using `new URLSearchParams()` and three `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called. +- **Category:** 1 (vague), 11 (unused public helper — dead surface area). +- **Suggested name:** Remove the export, or drop the function entirely if no caller in this package needs it. +- **Rationale:** Every generated package ships this helper; in `billableusagedownload` (which has zero list/page operations and only three query params), the inline approach is clearly what the generator chose. The unused export is a generator artefact that should be pruned. + +### 11. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (the inverse of `marshalRequest`) uses `parse` while the request side uses `marshal`. The verbs do not pair — they read as different layers. Neither function is used in this package; both are dead exports. +- **Category:** 17 (inconsistent action verbs), 11 (unused public helpers). +- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. Or delete both since the package has no JSON request/response (only query-string + streaming CSV). +- **Rationale:** Pair-wise consistency aids reading. More importantly, this package shouldn't ship JSON-marshalling helpers at all — it has no JSON I/O. + +### 12. `executeCall` / `executeHttpCall` near-duplicate names — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. Plus only `executeCall` is used in `client.ts:96`; `executeHttpCall` is another unused dead export (`sendAndCheckError` is used instead). +- **Category:** 1 (vague), 11 (unused export), 17 (inconsistent layer naming). +- **Suggested name:** `runWithCallOptions` / `sendHttp` — or just delete `executeHttpCall` since `sendAndCheckError` supersedes it. +- **Rationale:** `utils.ts` has *two* HTTP-send variants exported (`executeHttpCall` and `sendAndCheckError`) — the client uses only the latter, and the existence of both with subtly different return types (`Uint8Array` vs `HttpResponse`) is confusing. + +## Low severity + +### 13. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, ...). Within this file the imported `Options` from `@databricks/sdk-core/api` (line 3) collides with this local interface name. +- **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). +- **Suggested name:** `HttpCallContext` (it is not user-facing options; it is an internal bag of args). +- **Rationale:** Distinguish internal context bags from user-tunable option structs. Same finding as `abacpolicies` audit #37. + +### 14. `readAll` helper — `src/v1/utils.ts:40` +- **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Also reads the body twice in `sendAndCheckError` (lines 176-181) — once for body content, once for error parsing — though this is fine because non-2xx is handled separately. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` / `readStreamToEnd`. +- **Rationale:** Internal helper, low cost. Skip if generated. + +### 15. `buildHttpRequest` parameter order — `src/v1/utils.ts:96-102` +- **Why weird:** `(method, url, headers, signal?, body?)` — positional 5-arg function with two optional trailing params. Calling site (`client.ts:86`) passes `('GET', fullUrl, headers, callSignal)` — fine — but a caller adding a body has to remember the order. An options object would be clearer. +- **Category:** 1 (no name issue per se), Observation. +- **Suggested name:** Take `{method, url, headers, signal?, body?}` as an options object. +- **Rationale:** Less of a naming issue, more of an API shape concern. Not a blocker. + +### 16. `req` / `resp` / `opts` / `httpReq` / `httpResp` abbreviations — `src/v1/client.ts:66,68,86,87,...` +- **Why weird:** Three-letter abbreviations for local variables (`req`, `resp`, `opts`). The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. +- **Rationale:** Spelling out four-letter names costs nothing and improves readability. + +### 17. `httpClient: HttpClient` field — `src/v1/client.ts:27` / `src/v1/utils.ts:17` +- **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention is widespread in this SDK. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the (different) outer `Client` class in the same file. +- **Rationale:** Tolerable given the disambiguation, but flagged per rule 20. + +## Observations + +### 18. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` +The field is typed `ReadableStream` (no type parameter) rather than `ReadableStream`. Every other use in the codebase (`packages/files/src/v1/model.ts`, `utils.ts:42`, `utils.ts:101`) uses `ReadableStream` explicitly. The unparameterised version is the global lib type which is structurally `ReadableStream`, weakening type safety for callers. +- **Category:** 6 (misleading — type appears typed but is in fact `any`-typed), 17 (inconsistent across the SDK). +- **Suggested name:** `contents?: ReadableStream | undefined`. + +### 19. Wire/TS mapping is correct +The TS field `personalData` maps to wire `personal_data`, `startMonth` -> `start_month`, etc. The query-param construction in `client.ts:70-79` does it manually and correctly. Good — no naming bug here, just noting that no schema/codec layer is needed because this is a query-string-only request. + +### 20. No enums, no list-types, no FieldMask +This package is one of the simplest in the SDK: zero enums, zero list/paginated types, zero proto-nested `_Response` types. Audit-rule categories 2 (redundant enum prefix), 4 (underscore identifiers from proto nesting), 18 (long enum values), and 13 (verb tense inconsistency) do not apply here. That's why the finding count is comparatively low. + +### 21. CSV body is undocumented in types +`DownloadResponse.contents` is `ReadableStream` (untyped) but the JSDoc on `Client.download` (`client.ts:51-64`) makes clear the body is CSV. There is no type-level hint or branded type to mark this — a caller might treat the stream as JSON. Worth considering a documented branded type (`type CsvStream = ReadableStream & {readonly _csvBrand: unique symbol}`) or, more practically, a Content-Type assertion. Not a name problem; flagged because the response shape is uninformative. + +## Domain glossary +- `DBU` — Databricks Unit; standard billing unit for Databricks compute. Notably absent from this package's types and JSDoc — no DBU-related fields surface here despite the package being about billable usage. (User-mentioned in the task; verified via grep that the literal "DBU" never appears.) +- `PII` — Personally Identifiable Information. Surfaced indirectly as the `personalData` field flag. +- `E2` — Databricks deployment architecture. Mentioned in the JSDoc for `accountId` ("For non-E2 account types, get your account ID from the Accounts Console..."). +- `account ID` — Databricks account identifier. Surfaces as both `ClientOptions.accountId` and `DownloadRequest.accountId` (with fallback semantics — see finding #6). +- `CSV` — Comma-Separated Values, the wire format of the download body. Documented in JSDoc, not in types. +- `usage logs` — The actual data being downloaded (billable usage records). Not a type/field; only appears in JSDoc. + +## File coverage +- `src/v1/model.ts` (33 lines): read fully. +- `src/v1/client.ts` (103 lines): read fully. +- `src/v1/utils.ts` (186 lines): read fully. +- `src/v1/index.ts` (8 lines): read fully. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md new file mode 100644 index 00000000..bf24b519 --- /dev/null +++ b/.agent/naming-audit/budgetpolicy.md @@ -0,0 +1,262 @@ +# Naming Audit: budgetpolicy + +**Path:** `packages/budgetpolicy/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. +**Total weird names flagged:** 38 + +## Summary +| Severity | Count | +| --- | --- | +| High | 8 | +| Medium | 14 | +| Low | 11 | +| Observation | 5 | + +## High severity + +### 1. `SortSpec_Field` enum (`Foo_Bar` identifier) — `src/v1/model.ts:8` +- **Why weird:** Underscore in TypeScript identifier — proto-style nested-enum notation. Requires an explicit `eslint-disable-next-line @typescript-eslint/naming-convention` because TS strict rules reject `Foo_Bar`. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names not idiomatic in TS). +- **Suggested name:** `SortField` (hoist out of the nested namespace), or use a string-literal union `'POLICY_NAME' | undefined`. +- **Rationale:** TS has no nested-enum concept; the only reason this exists is to mirror the `SortSpec.Field` proto message. The eslint-disable is a tell that the name fights the language. + +### 2. `SortSpec_Field.FIELD_UNSPECIFIED` — `src/v1/model.ts:10` +- **Why weird:** A `FIELD_UNSPECIFIED` sentinel imported from protobuf semantics. Idiomatic TS uses `undefined` (the field is already `field?: SortSpec_Field | undefined`). +- **Category:** 2 (redundant enum prefix re-stating the enum name), 14 (proto sentinel leak). +- **Suggested name:** Drop the value and rely on `field?: SortField | undefined`. +- **Rationale:** Optional + `undefined` already expresses "unspecified" in TS; a `FIELD_UNSPECIFIED` literal forces every caller to handle two "no choice" states (`undefined` and the sentinel string). + +### 3. `Filter` (bare top-level type) — `src/v1/model.ts:77` +- **Why weird:** Re-exported from `index.ts` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (Array#filter, RxJS filter, content filters, etc.) and the type is package-scoped — but the re-export under this name collides with the same bare `Filter` in `packages/usagepolicy/src/v1/model.ts:81` and any user who imports both with `Filter` will hit a name clash. +- **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). +- **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). +- **Rationale:** A bare `Filter` provides zero discoverability and the package directly forces a collision with `usagepolicy.Filter`. Both packages target the same account-level surface and a consumer will frequently import both. + +### 4. `CreateBudgetPolicyRequest.requestId` documented as idempotency key — `src/v1/model.ts:42` +- **Why weird:** JSDoc: "This request is only idempotent if a `request_id` is provided." — wire-name leak (`request_id`) in the docs of the TS field `requestId`. Also, `requestId` is a generic field name that does not signal "idempotency key" to callers; the JSDoc is the only place that mentions idempotency. +- **Category:** 1 (vague — `requestId` could mean anything: trace id, correlation id, idempotency key), 15 (generic field name losing meaning). +- **Suggested name:** `idempotencyKey` (matches the conventional name used by Stripe, Square, and most REST APIs), and fix the JSDoc to use TS field name `requestId` rather than wire name `request_id`. +- **Rationale:** A user reading the field name should know it controls idempotency. The current name + docstring split forces a doc-read for every caller. + +### 5. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:118-123` +- **Why weird:** Docstring says: "A page token, received from a previous `ListServerlessPolicies` call ... When paginating, all other parameters provided to `ListServerlessPoliciesRequest` must match the call that provided the page token." — refers to an entirely different RPC name (`ListServerlessPolicies`) that does not exist in this SDK. The actual method is `listBudgetPolicies`. +- **Category:** 6 (misleading — docs describe a different operation), 14 (Go-style internal proto name leaked). +- **Suggested name:** Fix docstring to say `ListBudgetPolicies`/`ListBudgetPoliciesRequest`. +- **Rationale:** Generator bug. Confusing for readers and grep-hostile (searching for `ListBudgetPolicies` won't surface the doc context). + +### 6. `BudgetPolicy.policyId` / `BudgetPolicy.policyName` field naming inside `BudgetPolicy` type — `src/v1/model.ts:18,25` +- **Why weird:** Fields on the `BudgetPolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. +- **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `BudgetPolicy.id` is `policyId`). +- **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). +- **Rationale:** `budgetPolicy.id` reads better than `budgetPolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. + +### 7. `BudgetPolicy.bindingWorkspaceIds` — `src/v1/model.ts:32` +- **Why weird:** `binding` as a noun-prefix is unusual; reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this budget policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). +- **Category:** 1 (vague — `binding` is a generic noun: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists, but the field is just a list of workspace IDs). +- **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. +- **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. + +### 8. Type-name collision with `budgets` package — `src/v1/model.ts:16` vs `packages/budgets/src/v1/model.ts:50` +- **Why weird:** This package's central entity is `BudgetPolicy`; the sibling `budgets` package exports `BudgetConfiguration` (the spend-alert budget object). The two are semantically unrelated — `BudgetPolicy` is a tag-attachment policy that influences cost attribution, and `BudgetConfiguration` is a spend threshold + alert. A user importing both packages sees `BudgetPolicy` and `BudgetConfiguration` side by side and may reasonably wonder if `BudgetPolicy` is the policy *for* a `BudgetConfiguration`. The names do not differentiate clearly. +- **Category:** 12 (duplicate concepts with confusing names), 1 (the `Budget` prefix overloads two unrelated domain ideas). +- **Suggested name:** Consider `CostAttributionPolicy` or `UsageTaggingPolicy` for what `budgetpolicy` actually models (per the JSDoc on `BudgetPolicy`: "Contains the BudgetPolicy details" — tags + workspace bindings, no spend or threshold concept anywhere). +- **Rationale:** The package name is misleading: there is no "budget" (numeric monetary threshold) anywhere in the `budgetpolicy` model. The closest concept is `customTags`. Naming convergence with `budgets` (real spend budgets) drives the confusion. Worth raising with API designers, since the SDK name follows the API name. + +## Medium severity + +### 9. `CustomPolicyTag` type name — `src/v1/model.ts:53` +- **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. +- **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location). +- **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. +- **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". + +### 10. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:57-58` +- **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. +- **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). +- **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. +- **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. + +### 11. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:82,87,92` +- **Why weird:** `Filter` has three optional fields whose names imply they specify *one* policy, but the JSDoc says they apply as substring/equality filters across the list. Names like `policyName: 'foo'` read as "the policy named foo"; what it actually means is "policies whose name contains 'foo'". The JSDoc clarifies but the name misleads. +- **Category:** 6 (misleading — singular noun for a substring/multi-match filter). +- **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to `creatorUserNames: string[]`). +- **Rationale:** Filter DSLs benefit from explicit operators. Bare names suggest exact match. + +### 12. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:87,92` +- **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number` (a JS-unsafe representation for 64-bit IDs — but at least the Go SDK numeric type is `int64` here), while `creatorUserName` is `string`. +- **Category:** 12 (duplicate concept — two ways to filter on the same domain object), 19 (underspecified ID — `creatorUserId` is a numeric id from an unknown id space). +- **Suggested name:** Collapse to `creator?: Creator` with `{id?: number; name?: string}`, or document AND/OR. +- **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine. Even the JSDoc says "If unspecified, all policies will be returned" on each one — but doesn't say what happens if both are set. + +### 13. `Filter.creatorUserId: number` representation — `src/v1/model.ts:87` +- **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 32). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. +- **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). +- **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). +- **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 32 and `Filter.creatorUserId` here. + +### 14. `SortSpec` type — `src/v1/model.ts:149` +- **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. +- **Category:** 1 (vague suffix `Spec`). +- **Suggested name:** `SortOptions` or `SortOrder`. +- **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. + +### 15. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:150` +- **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. +- **Category:** Observation (typo). +- **Suggested name:** Fix spelling. +- **Rationale:** Minor; flagging because it surfaces in IntelliSense. + +### 16. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:136` +- **Why weird:** Field `policies` of type `BudgetPolicy[]`. Within the `budgetpolicy` package, `policies` is fine — but within a multi-package consumer with `BudgetConfigurations.budgets` (line 170 of budgets) and `usagepolicy.policies`, the field `policies` becomes ambiguous when copy-pasted. +- **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on request). +- **Suggested name:** `budgetPolicies: BudgetPolicy[]`. +- **Rationale:** Tied to type rename suggestion #8. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. + +### 17. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:146` +- **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listBudgetPoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. +- **Category:** Observation / 12 (duplicate-but-asymmetric concept). +- **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. +- **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. + +### 18. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:144` +- **Why weird:** Doc reads "In this field is omitted, there are no previous pages." — "In" should be "If". +- **Category:** Observation (typo). +- **Suggested name:** Fix doc. +- **Rationale:** Generated; surfaces in IntelliSense. + +### 19. `BudgetPolicy.customTags` plural field — `src/v1/model.ts:27` +- **Why weird:** Plural field `customTags: CustomPolicyTag[]` plus the singular type with `Tag` suffix produces `customTags: CustomPolicyTag[]` which reads with the same word twice (`Tags`/`Tag`). Compare to better naming where the field is `tags: Tag[]` (in this package, "policy tags" is self-evident). +- **Category:** 8 (redundant prefix `custom`), 20 (`customTags: CustomPolicyTag[]` is type-suffix tautology). +- **Suggested name:** `tags: Tag[]` (with type rename per #9). Wire form stays `custom_tags`. +- **Rationale:** Linked to type-rename #9; if `CustomPolicyTag` becomes `Tag`, field naturally becomes `tags`. + +### 20. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:46-50` +- **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. +- **Category:** Observation, 14 (wire-style identifiers in TS docs). +- **Suggested name:** Fix the doc to reference TS field names. +- **Rationale:** Editing UX: hovers should show TS, not proto. + +### 21. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:159` +- **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. +- **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). +- **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. +- **Rationale:** Real bug. + +### 22. `unmarshalBudgetPolicySchema` / `marshalBudgetPolicySchema` naming pair — `src/v1/model.ts:172,211` +- **Why weird:** "Marshal" and "unmarshal" terms come from Go encoding semantics. JS/TS world uses "serialize" / "deserialize" (or "parse" / "stringify"). +- **Category:** 14 (Go-style names not idiomatic in TS), 17 (across the file, `parseResponse`/`marshalRequest` in utils.ts:113,119 mix `parse` and `marshal`). +- **Suggested name:** `serializeBudgetPolicy` / `deserializeBudgetPolicy`, or `budgetPolicyToWire` / `budgetPolicyFromWire`. +- **Rationale:** Aligns with broader JS ecosystem (`JSON.parse`/`JSON.stringify`, Zod's `parse`/`safeParse`). Generator-wide concern. + +## Low severity + +### 23. `budgetPolicyFieldMaskSchema` constant — `src/v1/model.ts:271` +- **Why weird:** `*Schema` suffix on a non-Zod object (it's a `FieldMaskSchema` map describing wire-name aliases). Reuses `Schema` (which everywhere else in this file means a Zod schema) for a different concept. +- **Category:** 1 (vague suffix overloaded), 17 (inconsistent — `Schema` used for two different things in one file). +- **Suggested name:** `budgetPolicyFieldMaskFields` or `budgetPolicyFieldMaskMap`. +- **Rationale:** Hover help becomes ambiguous; reader must disambiguate by inspecting the value. + +### 24. `budgetPolicyFieldMask` function — `src/v1/model.ts:278` +- **Why weird:** Exported helper for building a `FieldMask`. The export is not surfaced from `index.ts:5-19`, so it cannot be used by consumers of the package. +- **Category:** Observation (unused public surface — dead export). +- **Suggested name:** Either re-export from `index.ts`, or mark internal. +- **Rationale:** Dead export. + +### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. +- **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). +- **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. +- **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. + +### 26. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. +- **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). +- **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). +- **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. + +### 27. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. +- **Rationale:** Pair-wise consistency aids reading. Same as `abacpolicies` finding #35. + +### 28. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` or `readStreamToEnd`. +- **Rationale:** Internal helper. Generator-wide. + +### 29. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. +- **Category:** Observation / 12 (duplicate utility across packages). +- **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. +- **Rationale:** Naming is fine; flagging duplication. + +### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. +- **Category:** 1 (vague), 15 (generic name losing meaning). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Same as `abacpolicies` finding #32; generator-wide. + +### 31. `Client` class plain name — `src/v1/client.ts:46` +- **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. +- **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). +- **Suggested name:** `BudgetPolicyClient`. +- **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. + +### 32. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +- **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. +- **Category:** 5 (cryptic abbreviation when the long form fits comfortably). +- **Suggested name:** `request`. +- **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. + +### 33. `listBudgetPoliciesIter` method name — `src/v1/client.ts:193` +- **Why weird:** `Iter` is a cryptic abbreviation for "iterator" / "iterable". Mirrors Go SDK's `Iterator` style. TS convention is to spell out (`...Iterator`) or use a stronger naming convention (`paginate*`, `list*All`). +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `listBudgetPoliciesIterator`, or rename pair: `listBudgetPolicies` (single page) + `listAllBudgetPolicies` (async iterable). +- **Rationale:** `Iter` is a Go-style truncation that JS/TS users rarely use. + +## Observations + +### 34. Action-verb conventions in `Client` +The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) +- **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). + +### 35. Wire/TS divergence dominates the file +`src/v1/model.ts` is 283 lines for ~10 user-facing types; >40% is marshal/unmarshal/FieldMask scaffolding. Not a naming defect, but the audit surfaces how much generator boilerplate ships per package. + +### 36. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. +- **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). + +### 37. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +Three sibling packages exist with related-sounding names: +- `budgetpolicy` — tag attribution policy (this package). +- `budgets` — spend-alert budget configurations. +- `usagepolicy` — has the identical model shape (`UsagePolicy`, `CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`) — i.e. it's a duplicate API surface with a different entity name. + +The three together blur the boundary between "policy that classifies usage" (budgetpolicy/usagepolicy) and "budget with alert thresholds" (budgets). The names themselves do not disambiguate which is which. +- **Category:** 12 (duplicate concept), 1 (vague package names). +- **Rationale:** Worth raising at the SDK / API design level. From the TS-user perspective, three near-clones makes the import surface confusing. + +### 38. Acronym casing `Id` consistently used as `Id`, not `ID` +`policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken` (no id) — file consistently uses `Id` (Title-case lower). Inconsistent only with `URLSearchParams` (Web API; out of our control). Good internal consistency. +- **Category:** 3 (observation — internal acronym style is consistent). + +## Domain glossary +- `budget policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. **Despite the name, it has no monetary "budget" semantics.** Compare with `budgets` package (real spend alerts). +- `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `BudgetPolicy.bindingWorkspaceIds: number[]`. +- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result`. +- `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.0/accounts/{accountId}/budget-policies`). +- `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. +- `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`); only used for `FieldMask` here. +- `FieldMask` — Proto-style partial-update mask; built via `budgetPolicyFieldMask(...paths)` (not re-exported from `index.ts`). +- `ListServerlessPolicies` — Phantom name appearing only in `ListBudgetPoliciesRequest.pageToken` JSDoc; no such RPC exists. Likely a Go-SDK copy/paste. + +## File coverage +- `src/v1/model.ts` (283 lines): read fully. +- `src/v1/client.ts` (255 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (20 lines): read fully. +- Cross-referenced: `packages/budgets/src/v1/model.ts`, `packages/budgets/src/v1/index.ts`, `packages/usagepolicy/src/v1/index.ts` for sibling-package overlap. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md new file mode 100644 index 00000000..2ac3b517 --- /dev/null +++ b/.agent/naming-audit/budgets.md @@ -0,0 +1,1053 @@ +# Naming Audit: `budgets` (v1) + +**Package:** `@databricks/sdk-budgets` +**Path:** `/home/parth.bansal/sdk-js/packages/budgets/` +**Version audited:** `v1` +**Files audited:** +- `src/v1/model.ts` +- `src/v1/client.ts` +- `src/v1/utils.ts` +- `src/v1/index.ts` + +This audit applies the 20 numbered concern categories from the audit +checklist. Each finding lists the offending identifier(s), the +category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete +rename suggestion. Findings are grouped by category. Generator-driven +items (such as the `_Response` suffix and underscored proto-style +nested-message names) are flagged as `LOW` because they are +codified across the entire generated SDK surface — they should be +fixed at the generator, not by hand-editing this package. + +--- + +## Inventory + +### Enums (`model.ts`) + +| Name | Members | +| --------------------------------------- | ------- | +| `ActionConfigurationType` | `EMAIL_NOTIFICATION` | +| `AlertConfigurationQuantityType` | `LIST_PRICE_DOLLARS_USD` | +| `AlertConfigurationTimePeriod` | `MONTH` | +| `AlertConfigurationTriggerType` | `CUMULATIVE_SPENDING_EXCEEDED` | +| `BudgetConfigurationFilter_Operator` | `IN` | + +### Interfaces (`model.ts`) + +`ActionConfiguration`, `AlertConfiguration`, `BudgetConfiguration`, +`BudgetConfigurationFilter`, `BudgetConfigurationFilter_Clause`, +`BudgetConfigurationFilter_TagClause`, +`BudgetConfigurationFilter_WorkspaceIdClause`, +`CreateBudgetConfiguration`, `CreateBudgetConfiguration_Response`, +`CreateBudgetConfigurationBudget`, `DeleteBudgetConfiguration`, +`DeleteBudgetConfiguration_Response`, `GetBudgetConfiguration`, +`GetBudgetConfiguration_Response`, `ListBudgetConfigurations`, +`ListBudgetConfigurations_Response`, `UpdateBudgetConfiguration`, +`UpdateBudgetConfiguration_Response`, +`UpdateBudgetConfigurationBudget`. + +### Schemas (`model.ts`) + +`unmarshalActionConfigurationSchema`, +`unmarshalAlertConfigurationSchema`, +`unmarshalBudgetConfigurationSchema`, +`unmarshalBudgetConfigurationFilterSchema`, +`unmarshalBudgetConfigurationFilter_ClauseSchema`, +`unmarshalBudgetConfigurationFilter_TagClauseSchema`, +`unmarshalBudgetConfigurationFilter_WorkspaceIdClauseSchema`, +`unmarshalCreateBudgetConfiguration_ResponseSchema`, +`unmarshalDeleteBudgetConfiguration_ResponseSchema`, +`unmarshalGetBudgetConfiguration_ResponseSchema`, +`unmarshalListBudgetConfigurations_ResponseSchema`, +`unmarshalUpdateBudgetConfiguration_ResponseSchema`, +`marshalActionConfigurationSchema`, `marshalAlertConfigurationSchema`, +`marshalBudgetConfigurationFilterSchema`, +`marshalBudgetConfigurationFilter_ClauseSchema`, +`marshalBudgetConfigurationFilter_TagClauseSchema`, +`marshalBudgetConfigurationFilter_WorkspaceIdClauseSchema`, +`marshalCreateBudgetConfigurationSchema`, +`marshalCreateBudgetConfigurationBudgetSchema`, +`marshalUpdateBudgetConfigurationSchema`, +`marshalUpdateBudgetConfigurationBudgetSchema`. + +### Client methods (`client.ts`) + +`createBudgetConfiguration`, `deleteBudgetConfiguration`, +`getBudgetConfiguration`, `listBudgetConfigurations`, +`listBudgetConfigurationsIter`, `updateBudgetConfiguration`. + +### Utility functions (`utils.ts`) + +`executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, +`parseResponse`, `marshalRequest`, `flattenQueryParams`. + +### Utility types/interfaces (`utils.ts`) + +`HttpCallOptions`. + +--- + +## Findings + +### 1. Vague / generic names + +#### F1.1 — `ActionConfiguration` / `actionConfigurationId` / `actionType` (HIGH) +- **Where:** `model.ts:26-33`, `index.ts:14`. +- **Why flagged:** "Action" is one of the most generic nouns in + software. Combined with "Configuration", it gives almost no clue + about what the user is configuring. In context this type is + exclusively the action attached to a budget *alert* (currently only + email notifications). A reader of `ActionConfiguration` cannot tell + whether it represents an HTTP action, a UI action, a workflow + action, a permission action, or — as it actually is — an alert + delivery method. +- **Suggestion:** Rename to `BudgetAlertAction` (or + `BudgetNotificationAction`). The `Configuration` suffix is dead + weight here (see also F7). If the type *must* keep the "Config" + word, `BudgetAlertActionConfig` is shorter and clearer. + +#### F1.2 — `target` field of `ActionConfiguration` (MEDIUM) +- **Where:** `model.ts:32`. +- **Why flagged:** "target" alone is generic — it could be a URL, + Slack channel, account ID, etc. The JSDoc clarifies "For example, + an email address," but the field name does not. Compare to similar + webhook-style "target" fields elsewhere in the SDK. +- **Suggestion:** `recipient` or `destination`. If the value really is + always an email today, `emailAddress` is unambiguous; `recipient` + is more future-proof. + +#### F1.3 — `target` (cont.): also generic at the type-domain level (LOW) +- **Where:** `model.ts:32`. +- See category 16 (F16.1) for the contradiction angle — "target" is + also too generic *and* implies a generic destination when the + domain is narrower. + +#### F1.4 — `values` (`BudgetConfigurationFilter_Clause`, + `BudgetConfigurationFilter_WorkspaceIdClause`) (LOW) +- **Where:** `model.ts:83, 95`. +- **Why flagged:** "values" is generic. Inside a clause it is + acceptable because the operator/values pair is a well-known proto + pattern, but a more descriptive name (`workspaceIds`, `tagValues`) + would document intent without a JSDoc. +- **Suggestion:** Leave for parity with proto/Go, but consider + specializing in TS: + `BudgetConfigurationFilter_WorkspaceIdClause.values → workspaceIds`, + `BudgetConfigurationFilter_Clause.values → tagValues`. + +#### F1.5 — `operator` (LOW) +- **Where:** `model.ts:82, 94`. +- **Why flagged:** Generic given there is only one allowed value + (`IN`). Acceptable for forward-compat but worth a JSDoc note. +- **Suggestion:** Keep, but add JSDoc clarifying allowed values and + semantics (currently has none). + +#### F1.6 — `Client` class name (MEDIUM) +- **Where:** `client.ts:49`, `index.ts:3`. +- **Why flagged:** Every package in this SDK exports a `Client`. + Re-exported in a barrel like + `import {Client as BudgetsClient} from '@databricks/sdk-budgets'` + it is fine, but unqualified `Client` symbol-shadows aggressively. + This is a project-wide pattern, not a budgets-specific issue. +- **Suggestion:** Either keep `Client` and document the + package-qualified import convention, or rename to + `BudgetsClient` consistently across packages. Cross-cutting. + +#### F1.7 — `req` parameter name on every client method (LOW) +- **Where:** `client.ts:80, 109, 137, 171, 213, 231`. +- **Why flagged:** `req` is a Go-ism (see category 14). It is also + generic — a reader has to look at the type to know what the + request is. +- **Suggestion:** Use a domain-meaningful parameter name: + `createBudgetConfiguration(budgetToCreate)` or simply `request` + for stylistic consistency with `options`. + +--- + +### 2. Redundant enum prefixes + +#### F2.1 — `BudgetConfigurationFilter_Operator.IN` (LOW) +- **Where:** `model.ts:22-24`. +- **Why flagged:** Single value, so there is no real redundancy + *yet*. But the enum prefix `BudgetConfigurationFilter_Operator` + has 4 levels (`Budget`, `Configuration`, `Filter`, `Operator`) + before reaching the value. Consider whether `FilterOperator` (or + even just `Operator` inside a `Filter` namespace) is enough. +- **Suggestion:** If proto-style nested names are dropped (see + F4.1), this becomes `FilterOperator.IN`, which is fine. No member + rename needed; the redundancy is in the enum name not the values. + +#### F2.2 — `ActionConfigurationType.EMAIL_NOTIFICATION` (LOW) +- **Where:** `model.ts:5-7`. +- **Why flagged:** Not redundant with the enum name, but + `EMAIL_NOTIFICATION` could be `EMAIL` since this enum is + scoped under "action" — the "_NOTIFICATION" suffix is the + enum's role, not the member's role. Compare `Color.RED` vs + `Color.RED_COLOR`. +- **Suggestion:** Treat as wire-protocol value; do not rename in + TS unless the API spec changes. Leave with a comment. + +#### F2.3 — `AlertConfigurationTimePeriod.MONTH` (acceptable) +- No redundancy. `MONTH` is concise. + +#### F2.4 — `AlertConfigurationTriggerType.CUMULATIVE_SPENDING_EXCEEDED` (acceptable) +- Long but descriptive; the redundancy is not with the enum name. See + F18. + +#### F2.5 — `AlertConfigurationQuantityType.LIST_PRICE_DOLLARS_USD` (acceptable) +- Long; see F18. + +--- + +### 3. Acronym casing inconsistencies + +#### F3.1 — `Id` vs `ID` (HIGH, cross-cutting) +- **Where:** `model.ts:28, 37, 52, 54, 72, 111, 113, 135, 137, 145, + 147, 157, 177, 190, 192`; `client.ts:53, 66, 83, 112, 140, 174, + 234`. +- **Why flagged:** This SDK uses **lower-camel `Id`** consistently + (`accountId`, `budgetId`, `budgetConfigurationId`, + `actionConfigurationId`, `alertConfigurationId`, `workspaceId`, + `nextPageToken`, `pageToken`). That is internally consistent and + fine. The TS/JS community is split — DOM uses `nodeId`/`HTMLElement`, + TypeScript itself uses `id`/`uuid` — so `Id` is defensible. + **The flag here is not against `Id`**, but against the *interaction* + with the proto-style `BudgetConfigurationFilter_WorkspaceIdClause` + identifier, where the suffix becomes + `WorkspaceIdClause`. Reading `WorkspaceIdClause` left-to-right + parses as "WorkspaceId-Clause", but a TS reader who is unfamiliar + with the type domain might parse it as "Workspace-IdClause" + (i.e. an "ID clause" for workspaces). Slight ambiguity. +- **Suggestion:** Keep `Id`. Add a brief project-level note in + `typescript.mdc` documenting the convention so reviewers stop + re-litigating it. + +#### F3.2 — `URL` / `Url` consistency (acceptable) +- `client.ts` consistently uses `url` (lowercase) as a local var + name. No casing inconsistency observed. + +#### F3.3 — `HTTP` / `Http` (acceptable for this file) +- `utils.ts` consistently uses `Http` PascalCase (`HttpClient`, + `HttpRequest`, `HttpResponse`, `HttpCallOptions`, + `executeHttpCall`, `buildHttpRequest`). One file is consistent; + flag is cross-package only. + +#### F3.4 — `USD` in enum value `LIST_PRICE_DOLLARS_USD` (LOW) +- Wire value, leave as-is. But note that `DOLLARS_USD` is doubly + redundant — USD already is dollars. See F8.2. + +--- + +### 4. Underscores in TS identifiers + +> The TypeScript style guide (Google) and the SDK's own +> `typescript.mdc` disallow `snake_case` and underscores in +> identifiers. The generator emits proto-style "outer_inner" names +> as `Outer_Inner` to disambiguate nested messages — but TS would +> normally fold these into namespaces or flat PascalCase. + +#### F4.1 — Proto-style underscore types (HIGH, cross-cutting, + generator concern) +- **Where:** + - `BudgetConfigurationFilter_Operator` (enum) `model.ts:22` + - `BudgetConfigurationFilter_Clause` (interface) `model.ts:81` + - `BudgetConfigurationFilter_TagClause` (interface) `model.ts:87` + - `BudgetConfigurationFilter_WorkspaceIdClause` (interface) + `model.ts:93` + - `CreateBudgetConfiguration_Response` `model.ts:104` + - `DeleteBudgetConfiguration_Response` `model.ts:141` + - `GetBudgetConfiguration_Response` `model.ts:152` + - `ListBudgetConfigurations_Response` `model.ts:169` + - `UpdateBudgetConfiguration_Response` `model.ts:183` + - All `marshal*` / `unmarshal*` schema constants of the above. + - Re-exported through `index.ts:10, 18-31`. +- **Why flagged:** Each of these requires an + `eslint-disable-next-line @typescript-eslint/naming-convention` + comment. That alone is a smell. The TypeScript-idiomatic + equivalents would be either nested namespaces + (`namespace BudgetConfigurationFilter { export interface Clause … }`) + or flat PascalCase (`BudgetConfigurationFilterClause`). +- **Suggestion:** Drop underscores at the generator level. Two viable + shapes: + 1. **Flat PascalCase** — + `BudgetConfigurationFilterClause`, + `BudgetConfigurationFilterTagClause`, + `BudgetConfigurationFilterWorkspaceIdClause`, + `BudgetConfigurationFilterOperator`, + `CreateBudgetConfigurationResponse`, etc. + 2. **Namespace nesting** — keep parent name, drop underscore: + `BudgetConfigurationFilter.Clause`, etc. + Approach (1) is more straightforward for tree-shaking and module + re-exports; approach (2) more closely mirrors the proto nesting. + +#### F4.2 — Comment in `client.ts:52`: "Fallback for endpoints whose + path contains {account_id}." (LOW) +- **Where:** `client.ts:52`. +- **Why flagged:** This is a comment, not an identifier — but it + refers to the *wire* placeholder `{account_id}` in snake_case, + which is fine. No action. + +--- + +### 5. Cryptic abbreviations + +#### F5.1 — `req` (LOW, Go-ism) +- **Where:** `client.ts` every method, `utils.ts:103`. +- Already flagged under F1.7 / F14.1. + +#### F5.2 — `resp` (LOW, Go-ism) +- **Where:** `client.ts:85, 113, 147, 190, 236`; `utils.ts:73, 81`. +- See F14.2. + +#### F5.3 — `respBody` (LOW) +- **Where:** `client.ts:90, 118, 152, 195, 241`. +- **Why flagged:** "resp" abbreviation. Spell out `responseBody` + for clarity in TS where verbosity is cheap. +- **Suggestion:** `responseBody`. + +#### F5.4 — `httpReq` (LOW) +- **Where:** `client.ts:89, 117, 151, 194, 240`. +- **Why flagged:** `httpRequest` is clearer and matches the type + `HttpRequest` exactly. +- **Suggestion:** `httpRequest`. + +#### F5.5 — `apiErr` (LOW) +- **Where:** `utils.ts:88`. +- **Why flagged:** `apiError` reads better; "err" is a Go-ism. +- **Suggestion:** `apiError`. + +#### F5.6 — `pkgJson` (LOW) +- **Where:** `client.ts:19`. +- **Why flagged:** "pkg" abbreviation. `packageJson` is two extra + characters and unambiguous. +- **Suggestion:** `packageJson`. + +#### F5.7 — `acc`, `val`, `opts`, `e` (LOW) +- **Where:** `utils.ts:55, 137, 30, 68-92, 76`. +- **Why flagged:** + - `acc` (utils.ts:55) — reduce accumulator, conventional. OK. + - `val` (utils.ts:137) — local destructure, OK. + - `opts` (utils.ts:30, 68, 73, 75, 81, 83, 88) — Go-ism; + `options` is preferred but `opts` is also widely used in JS + libraries. **Inconsistent with itself:** the public parameter + is `options` (utils.ts:28) but the internal one is `opts`. Pick + one. + - `e` for the caught exception (utils.ts:76) — TS guidance is + `err`/`error`/`e` are all acceptable. Match the file's other + usages (`apiErr`). +- **Suggestion:** rename `opts → options` inside `executeHttpCall` + for consistency; leave `acc`, `val`, `e` alone. + +--- + +### 6. Misleading names + +#### F6.1 — `BudgetConfigurationFilter_WorkspaceIdClause.values: + number[]` (MEDIUM) +- **Where:** `model.ts:95`. +- **Why flagged:** Workspace IDs are 64-bit integers on Databricks. + TypeScript `number` cannot safely represent values > 2^53. Other + packages in this SDK use `string` for IDs that overflow. This is a + *type* issue, not a *naming* issue — but the field name `values: + number[]` does not signal that it is the wrong width. Worth a + cross-reference (the v1 spec presumably uses int64). +- **Suggestion:** Confirm with the Go reference; if it is `int64`, + the TS port should be `string[]` or `bigint[]`. If `number` is + intentional (sometimes IDs fit in 53 bits), document it. Not + strictly a naming finding, included because it shows up as a + field-domain mismatch. + +#### F6.2 — `quantityThreshold` typed as `string` (LOW) +- **Where:** `model.ts:45`, JSDoc: "The threshold for the budget + alert to determine if it is in a triggered state." +- **Why flagged:** A "quantity threshold" sounds numeric, yet it is + a string (probably to preserve precision for currency). The name + does not signal the string-encoded-decimal contract. +- **Suggestion:** Either rename to `quantityThresholdString` (ugly) + or add JSDoc noting "Decimal string (preserves precision)" — the + latter is the standard fix. + +#### F6.3 — `BudgetConfiguration.alertConfigurations: AlertConfiguration[]` + array, but JSDoc says "Budgets must have exactly one alert + configuration." (MEDIUM) +- **Where:** `model.ts:59-60`, `client.ts:78` JSDoc reuses budget docs. +- **Why flagged:** The plural type contradicts the singular semantics. + Misleading at the type level. +- **Suggestion:** This is API-shape, not a TS rename concern. Flag for + the source spec to fix; in TS, document the invariant in JSDoc and + consider a tuple `[AlertConfiguration]` (overkill in practice). + See also F9.1. + +#### F6.4 — `flattenQueryParams` is exported but unused in this + package (LOW) +- **Where:** `utils.ts:123-150`. +- **Why flagged:** The name suggests it is a query-param helper for + this client; the client does not call it (lines 141-145, 175-187 + use `URLSearchParams.append` directly). The function is dead code + inside this package. Either there is an intended caller that has + not landed, or the helper should not be in this package. +- **Suggestion:** Move shared helpers to `@databricks/sdk-core` or + delete from this package's `utils.ts`. + +#### F6.5 — JSDoc "previous get all budget configurations call" + (`pageToken` on `ListBudgetConfigurations`) (LOW) +- **Where:** `model.ts:160-163`. +- **Why flagged:** Documentation, not identifier. The method is + `listBudgetConfigurations`, not "get all". JSDoc text is stale + vs. the method name. +- **Suggestion:** Rewrite JSDoc: "A page token received from a + previous `listBudgetConfigurations` call." + +--- + +### 7. Overly verbose + +#### F7.1 — `BudgetConfiguration` (HIGH) +- **Where:** `model.ts:50`. +- **Why flagged:** Within a package literally named `budgets`, every + type is about budgets. The "Configuration" suffix doesn't add + signal — a budget IS a configuration on the account. Compare Go's + `budgets.Budget` (typical Go SDK convention). +- **Suggestion:** Rename to `Budget`. Users would write + `import {Budget} from '@databricks/sdk-budgets'`. The + package name carries the qualifier. Combined with F7.2 / F7.3 + this collapses naming significantly. + +#### F7.2 — `CreateBudgetConfiguration`, `GetBudgetConfiguration`, + `UpdateBudgetConfiguration`, `DeleteBudgetConfiguration`, + `ListBudgetConfigurations` (HIGH) +- **Where:** `model.ts:98, 133, 143, 156, 175`; `index.ts:21-31`. +- **Why flagged:** Long request type names. Combined with method + names that already say `createBudgetConfiguration(...)`, the + argument type is highly redundant. Compare typical TS SDK + patterns: `client.budgets.create(req: CreateBudgetRequest)`. +- **Suggestion:** Drop the `Configuration` token from request types: + `CreateBudgetRequest`, `GetBudgetRequest`, `UpdateBudgetRequest`, + `DeleteBudgetRequest`, `ListBudgetsRequest`. Note the addition of + an explicit `Request` suffix to match the existing `_Response` + pattern — see F8.1 / F20. + +#### F7.3 — `CreateBudgetConfigurationBudget` and + `UpdateBudgetConfigurationBudget` (HIGH) +- **Where:** `model.ts:109, 188`; `index.ts:23, 32`. +- **Why flagged:** These types are literally `BudgetConfiguration` + + the noun `Budget`. The name is `Budget` repeated twice plus + `Configuration`. Reads as + "Create-Budget-Configuration-Budget". +- **Suggestion:** Replace with the existing `BudgetConfiguration` + (or renamed `Budget`) directly. Inspection shows these types are + byte-for-byte identical to `BudgetConfiguration`: + + ```ts + // BudgetConfiguration + budgetConfigurationId, accountId, createTime, updateTime, + alertConfigurations, filter, displayName + + // CreateBudgetConfigurationBudget — identical + budgetConfigurationId, accountId, createTime, updateTime, + alertConfigurations, filter, displayName + + // UpdateBudgetConfigurationBudget — identical + budgetConfigurationId, accountId, createTime, updateTime, + alertConfigurations, filter, displayName + ``` + The duplication serves no schema purpose. Delete both wrapper + types and have `Create.../Update...` request types embed + `BudgetConfiguration` (or `Budget`) directly. See also F11 / F12. + +#### F7.4 — Method names mirror request types (MEDIUM) +- **Where:** `client.ts:79, 108, 136, 170, 230`. +- **Why flagged:** Methods are + `createBudgetConfiguration`, `deleteBudgetConfiguration`, + `getBudgetConfiguration`, `listBudgetConfigurations`, + `updateBudgetConfiguration`. Inside a `Budgets` client, the + `Budget`/`Budgets` suffix is repetitive. Compare typical TS SDK + shape: `budgets.create(...)`, `budgets.list(...)`. +- **Suggestion:** `create`, `delete`, `get`, `list`, `listIter`, + `update`. The class itself already conveys "budgets". This is a + cross-package convention to decide once. + +#### F7.5 — `listBudgetConfigurationsIter` (MEDIUM) +- **Where:** `client.ts:212`. +- **Why flagged:** 30 characters, with `Configurations` repeated. The + `Iter` suffix is also Go-style; in TS the idiomatic alternative + is an async iterator method (`[Symbol.asyncIterator]`) or a name + like `listAll` / `streamBudgets`. +- **Suggestion:** Tied to F7.4: collapse to `listIter` or + better, `iterate`/`stream`/`listAll` — and decide cross-package. + +#### F7.6 — `BudgetConfigurationFilter_WorkspaceIdClause` (LOW) +- **Where:** `model.ts:93`. +- **Why flagged:** 43 characters. Even after un-underscoring it remains + `BudgetConfigurationFilterWorkspaceIdClause` — readable but heavy. +- **Suggestion:** Inside a renamed `Budget.Filter` namespace, + `WorkspaceIdClause` is fine. If kept flat, `BudgetFilterWorkspaceClause` + is shorter and equally clear (drop `Id`). + +--- + +### 8. Redundant suffixes + +#### F8.1 — `_Response` suffix on every response type (LOW, + cross-cutting generator concern) +- **Where:** `model.ts:104, 141, 152, 169, 183`. +- **Why flagged:** Every response type uses `_Response`. Underscore + aside (F4.1), `Response` on a type already on the return path is + partially redundant — but here it disambiguates from the + same-named request type, which is fine. The flag is on the + *underscore*, not the suffix itself. +- **Suggestion:** Drop the underscore (`CreateBudgetResponse`, + `DeleteBudgetResponse`, etc.) or drop the request token entirely + (just `BudgetResponse`, `BudgetListResponse`). With F7.2 the + request types become `CreateBudgetRequest` etc., so this + resolves naturally. + +#### F8.2 — `LIST_PRICE_DOLLARS_USD` (LOW) +- **Where:** `model.ts:10`. +- **Why flagged:** `DOLLARS_USD` is tautological — USD *is* dollars. + This is a wire-protocol value, so the SDK cannot change it + unilaterally, but worth noting upstream. +- **Suggestion:** Wire protocol; leave with a comment. + +#### F8.3 — `ActionConfigurationType` enum name (LOW) +- **Where:** `model.ts:5`. +- **Why flagged:** `ConfigurationType` is partially tautological with + the wrapping `ActionConfiguration` type — `ActionConfiguration.actionType: + ActionConfigurationType`. Reads as + "actionType: ActionConfigurationType" with "action" said three times. +- **Suggestion:** Rename enum to `ActionType` (within an + `ActionConfiguration` parent, or after renaming the parent to + `BudgetAlertAction`, the enum becomes `BudgetAlertAction.Type` or + simply `BudgetAlertActionType`). + +#### F8.4 — `AlertConfigurationQuantityType`, + `AlertConfigurationTimePeriod`, `AlertConfigurationTriggerType` (LOW) +- **Where:** `model.ts:9, 13, 17`. +- **Why flagged:** Same pattern as F8.3 — `AlertConfiguration` parent + + `QuantityType`/`TimePeriod`/`TriggerType` suffix. With parent renamed to + `BudgetAlert` (see F7), suffixes become reasonable: + `BudgetAlertQuantityType`, `BudgetAlertTimePeriod`, + `BudgetAlertTriggerType`. +- **Suggestion:** Tie to F7. + +--- + +### 9. Singular / plural mismatches + +#### F9.1 — `alertConfigurations: AlertConfiguration[]` plural but + semantically singular (HIGH) +- **Where:** `model.ts:59-60, 118-119, 197-198`. +- **Why flagged:** JSDoc states "Budgets must have exactly one alert + configuration." Field is plural array. Documented earlier (F6.3) as + misleading. +- **Suggestion:** API-shape concern; document the invariant or + switch to singular `alertConfiguration: AlertConfiguration` when + the API allows. + +#### F9.2 — `actionConfigurations: ActionConfiguration[]` (acceptable) +- **Where:** `model.ts:47`. +- **Why flagged:** No mismatch — multiple actions per alert are + allowed. Plural is correct. + +#### F9.3 — `tags: BudgetConfigurationFilter_TagClause[]` (acceptable) +- Plural-array, no mismatch. + +#### F9.4 — `workspaceId: BudgetConfigurationFilter_WorkspaceIdClause` + on `BudgetConfigurationFilter` (HIGH) +- **Where:** `model.ts:72`. +- **Why flagged:** The field is singular `workspaceId` but its type + is a clause whose `values: number[]` holds *multiple* workspace IDs. + Reading `filter.workspaceId.values` is confusing — you would expect + `workspaceId` to be one ID, but it's a clause. +- **Suggestion:** Rename the field to `workspaceIds`, `workspaceFilter`, + or `workspaces`. Pair with renaming the type from + `WorkspaceIdClause` to `WorkspaceFilter`. The whole clause + abstraction is unnecessary in TS — see F11. + +#### F9.5 — `budgets` field in `ListBudgetConfigurations_Response` + (acceptable) +- Plural, correct. + +#### F9.6 — `listBudgetConfigurations` vs `listBudgetConfigurationsIter` + (acceptable) +- Plural form is correct here. + +--- + +### 10. Reserved-word / built-in collisions + +#### F10.1 — `filter` field (LOW) +- **Where:** `model.ts:65, 124, 203`. +- **Why flagged:** `filter` is `Array.prototype.filter` — not a + reserved word, but shadowing a built-in causes mental hiccups + during code review. Acceptable here because the field is on + `BudgetConfiguration`, not on an array. +- **Suggestion:** Keep; not worth churn. + +#### F10.2 — `target` field (LOW) +- **Where:** `model.ts:32`. +- **Why flagged:** `target` collides with `EventTarget` / + `event.target` semantics in DOM. Minor. +- **Suggestion:** See F1.2 — rename to `recipient` resolves both. + +#### F10.3 — `values` (LOW) +- **Where:** `model.ts:83, 95`. +- **Why flagged:** `Object.values` is a popular built-in. Property + shadowing only, not a true collision. +- **Suggestion:** See F1.4 — specialize per type. + +#### F10.4 — `Headers` constructor use vs DOM `Headers` (acceptable) +- **Where:** `client.ts:87, 115, 149, 192, 238`. +- The code intentionally uses the global `Headers`. No new identifier + shadows it. Fine. + +#### F10.5 — `URLSearchParams`, `TextDecoder` (acceptable) +- Used as global classes, no shadowing. + +--- + +### 11. Empty / trivial wrapper types + +_None._ + +--- + +### 12. Duplicate concepts + +#### F12.1 — `BudgetConfiguration` vs `CreateBudgetConfigurationBudget` + vs `UpdateBudgetConfigurationBudget` (HIGH) +- **Where:** `model.ts:50, 109, 188`. +- **Why flagged:** Three types with byte-for-byte identical fields. + Already noted in F7.3. They exist because the API contract + *might* diverge later (e.g. `Update` strips server-managed fields), + but today they are duplicates. +- **Suggestion:** Collapse to a single `BudgetConfiguration` (or + `Budget`) where the spec allows. If the spec mandates separate + shapes, document *why* each is distinct in JSDoc. + +#### F12.2 — `BudgetConfigurationFilter_Clause` and + `BudgetConfigurationFilter_WorkspaceIdClause` are the same shape + with `values` typed differently (MEDIUM) +- **Where:** `model.ts:81, 93`. +- **Why flagged:** Two near-identical types differ only in + `values: string[]` vs `values: number[]`. In TS this is a perfect + case for a generic: `Clause { operator?: Operator; values?: T[] }`. + The proto duplication is preserved verbatim. +- **Suggestion:** If parity with proto matters, leave alone. If not, + collapse to a generic clause type — but only if the generator + supports it. + +#### F12.3 — Per-method header construction duplicated (LOW, code style) +- **Where:** `client.ts:87, 115, 149, 192, 238`. +- **Why flagged:** Every method runs: + ```ts + const headers = new Headers(...); + headers.set('User-Agent', this.userAgent); + ``` + Could be a private helper `this.buildHeaders(...)`. Not a naming + issue, but a code-duplication smell. +- **Suggestion:** Out of scope for naming audit. Mentioned for + completeness. + +#### F12.4 — `accountId` declared on both the request envelope and + the inner `Budget` (LOW) +- **Where:** + - `CreateBudgetConfigurationBudget.accountId` (model.ts:113) + - `UpdateBudgetConfigurationBudget.accountId` (model.ts:192) + - `DeleteBudgetConfiguration.accountId` (model.ts:137) + - `GetBudgetConfiguration.accountId` (model.ts:147) + - `ListBudgetConfigurations.accountId` (model.ts:158) + - `UpdateBudgetConfiguration` has no top-level `accountId`; it + pulls from `req.budget?.accountId` (`client.ts:234`) + - `CreateBudgetConfiguration` likewise uses + `req.budget?.accountId` (`client.ts:83`) +- **Why flagged:** Inconsistent location of `accountId` between + request types. Some have it at the top level, some require it + nested under `budget`. Reader can't tell from the type which to + set. The fallback `this.accountId ?? ''` in + `delete/get/list` masks the inconsistency. +- **Suggestion:** Standardize: lift `accountId` to the top-level + request envelope for *all* methods. The Go/proto layer can keep + nesting; the TS client should flatten. + +#### F12.5 — `budgetId` on + `Delete/Get/UpdateBudgetConfiguration` vs `budgetConfigurationId` + on `BudgetConfiguration` and + `Create/UpdateBudgetConfigurationBudget` (HIGH) +- **Where:** + - `DeleteBudgetConfiguration.budgetId` (model.ts:135) + - `GetBudgetConfiguration.budgetId` (model.ts:145) + - `UpdateBudgetConfiguration.budgetId` (model.ts:177) + - `BudgetConfiguration.budgetConfigurationId` (model.ts:52) + - `CreateBudgetConfigurationBudget.budgetConfigurationId` + (model.ts:111) + - `UpdateBudgetConfigurationBudget.budgetConfigurationId` + (model.ts:190) +- **Why flagged:** Same conceptual ID, two different names. This is + the prototypical "same thing, two names" duplicate concept. Most + egregious example: `UpdateBudgetConfiguration` has both + `budgetId` (top-level) *and* the nested `budget.budgetConfigurationId`. +- **Suggestion:** Pick one. `budgetId` is shorter and matches the + REST path segment (`/budgets/{budgetId}`). Rename + `budgetConfigurationId → budgetId` everywhere. Combined with + the F7.1 rename `BudgetConfiguration → Budget`, this is consistent. + +--- + +### 13. Verb-tense inconsistency + +#### F13.1 — Method verbs (acceptable) +- `create*`, `delete*`, `get*`, `list*`, `update*` — uniform + imperative present. Good. + +#### F13.2 — `marshalRequest` / `parseResponse` (acceptable) +- `marshalRequest` (utils.ts:119) is imperative; `parseResponse` + (utils.ts:113) is imperative. Consistent. + +#### F13.3 — `unmarshalXSchema` constants (LOW, code style) +- **Where:** `model.ts:208, 221, 242, …` and all `marshal…Schema`. +- **Why flagged:** Naming pattern is correct (verb + noun + Schema), + but the verb form makes them read like functions, not constants. + They *are* values (`z.ZodType` objects). The Zod community + conventionally exports schemas as PascalCase nouns + (`BudgetSchema`) or `budgetSchema` in camelCase. Verb prefix is + unusual. +- **Suggestion:** Rename to `budgetWireSchema` / `budgetReadSchema` + or pair `budgetEncoder` / `budgetDecoder`. Cross-cutting; tied to + generator. + +#### F13.4 — `createTime`, `updateTime` vs `created_at`/`updated_at` + conventions (LOW) +- **Where:** `model.ts:56-58, 115-117, 194-196`. +- **Why flagged:** Past-tense `createdTime` / `updatedTime` (or + `createdAt`/`updatedAt`) is more idiomatic; current form reads + as imperative ("create the time"). This is a noun form ("the + time of creation"), which is fine but ambiguous on first read. + This matches Google API conventions, so it is defensible. +- **Suggestion:** Keep for parity with Go/proto and Google API + convention. Just note that `createdTime`/`updatedTime` would read + more naturally in TS. + +--- + +### 14. Go / Java-style names + +#### F14.1 — `req`, `resp`, `err`, `Iter`, `httpReq`, `apiErr`, + `pkgJson`, `opts` (HIGH, but cross-cutting) +- **Where:** + - `req` everywhere in `client.ts` + - `resp` everywhere in `client.ts` and `utils.ts:73, 81` + - `e` in `utils.ts:76` (with rethrow) + - `Iter` suffix in `listBudgetConfigurationsIter` + - `httpReq` in client.ts + - `apiErr` in utils.ts:88 + - `pkgJson` in client.ts:19 + - `opts` in utils.ts:30, 68 +- **Why flagged:** These are all classic Go idioms ported verbatim. + TS convention favors spelled-out names (`request`, `response`, + `error`, `iterator`/`stream`/`listAll`, `httpRequest`, + `apiError`, `packageJson`, `options`). +- **Suggestion:** Spell them out. Trivial diff, large readability + gain. This is a porting-convention decision and should be made + globally at the generator level. + +#### F14.2 — `unmarshal*` / `marshal*` schema prefixes (LOW) +- **Where:** All schema exports. +- **Why flagged:** `marshal`/`unmarshal` is a Go term + (encoding/json). The JS/TS world says "serialize"/"deserialize" + or "encode"/"decode". `JSON.parse`/`JSON.stringify` is the + vernacular. `marshal` is recognizable but Go-flavored. +- **Suggestion:** Rename to `encode`/`decode` or + `serialize`/`deserialize`. Generator-level decision. + +#### F14.3 — `Schema` suffix on Zod constants (acceptable) +- The `…Schema` suffix matches Zod community convention. + +#### F14.4 — `_Response` (and other) underscore-pseudo-nesting (HIGH) +- See F4.1. Underscores are foreign to TS. + +#### F14.5 — Comment style (acceptable) +- Comments are sentences. Good — but the file-top comment is the + generator banner. + +--- + +### 15. Generic field names losing meaning + +#### F15.1 — `target` on `ActionConfiguration` (HIGH) +- See F1.2 / F1.3. + +#### F15.2 — `values` on Clauses (MEDIUM) +- See F1.4. + +#### F15.3 — `operator` on Clauses (LOW) +- See F1.5. + +#### F15.4 — `key` and `value` on `BudgetConfigurationFilter_TagClause` + (LOW) +- **Where:** `model.ts:88-89`. +- **Why flagged:** "key/value" is generic enough that without the + wrapping type, readers can't tell it is a *tag* key. Acceptable + because the wrapping type's name supplies context, but + `tagKey`/`tagValue` would be self-documenting. +- **Suggestion:** Optional rename to `tagKey`/`tagValue`. Wire field + is `key`/`value`, so renaming costs an extra mapping in the + marshaller. + +#### F15.5 — `req` parameter on every client method (HIGH) +- See F1.7. + +--- + +### 16. Field contradicting type domain + +#### F16.1 — `ActionConfiguration.target` (HIGH) +- **Where:** `model.ts:32`. +- **Why flagged:** Type domain is "alert action" (currently + email-only); field name is the generic "target". JSDoc admits "For + example, an email address." Type-domain dissonance. +- **Suggestion:** `recipient` (or `emailAddress` if email-only is + hard-wired). See F1.2. + +#### F16.2 — `BudgetConfigurationFilter_WorkspaceIdClause` typed + as `number[]` (MEDIUM) +- **Where:** `model.ts:95`. See F6.1. + +#### F16.3 — `LIST_PRICE_DOLLARS_USD` member on + `AlertConfigurationQuantityType` (LOW) +- **Where:** `model.ts:10`. +- **Why flagged:** Name implies *currency*, type is "quantity type". + The "quantity" in the API is a dollar amount. Minor domain + mismatch — could be `Currency`, `Cost`, or `Price` enum. +- **Suggestion:** Out of scope for TS rename; wire value. + +--- + +### 17. Inconsistent action verbs + +#### F17.1 — `Get` vs `List` for read endpoints (acceptable) +- `get` for single, `list` for collection. Standard REST verbs. + +#### F17.2 — `listBudgetConfigurationsIter` (MEDIUM) +- **Where:** `client.ts:212`. +- **Why flagged:** `Iter` is not a verb; it is a suffix attached to + `list`. In TS the pattern `list` returns a single page, `listAll` + or `stream*` returns an async iterator. `listIter` is fine but + inconsistent across SDKs. +- **Suggestion:** Pick `listAll` or `iterate` or expose + `[Symbol.asyncIterator]` on a paginator object. Cross-cutting. + +#### F17.3 — `marshal` / `unmarshal` (Go-style verbs, LOW) +- See F14.2. + +#### F17.4 — `parseResponse` vs `marshalRequest` (LOW, asymmetry) +- **Where:** `utils.ts:113, 119`. +- **Why flagged:** `parse` vs `marshal` use different verbs for the + same kind of operation (JSON conversion). Inconsistent verb + choice. +- **Suggestion:** Use the same axis throughout: either + `marshal/unmarshal` or `encode/decode` or `serialize/deserialize`. + +--- + +### 18. Long enum values + +#### F18.1 — `CUMULATIVE_SPENDING_EXCEEDED` (MEDIUM) +- **Where:** `model.ts:18`. +- **Why flagged:** 28 characters. Long but informative. +- **Suggestion:** Wire value; cannot rename in TS without losing + parity. Acceptable. + +#### F18.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) +- **Where:** `model.ts:10`. +- **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant + (F8.2). Could be `LIST_PRICE_USD` or `USD`. +- **Suggestion:** Wire value; report upstream. + +#### F18.3 — `EMAIL_NOTIFICATION` (LOW) +- **Where:** `model.ts:6`. 18 characters; reasonable. + +--- + +### 19. Underspecified IDs + +#### F19.1 — `budgetId` vs `budgetConfigurationId` for the same thing + (HIGH) +- See F12.5. The `budgetId` form is *less* underspecified than + `budgetConfigurationId` if the package name carries "budgets" + context — both are unambiguous in this package; the issue is + inconsistency. + +#### F19.2 — `actionConfigurationId`, `alertConfigurationId` (LOW) +- **Where:** `model.ts:28, 37`. +- **Why flagged:** Long. If `ActionConfiguration` renames to + `BudgetAlertAction`, the ID becomes `budgetAlertActionId` + (still long) or just `actionId` inside its parent. +- **Suggestion:** Inside the parent, the local field name can be + just `id`. The full form is only needed when referenced + externally. + +#### F19.3 — `accountId` (acceptable) +- Specific enough; matches platform-wide convention. + +#### F19.4 — `workspaceId` on `BudgetConfigurationFilter` field, but + the field holds a *clause* not an ID (HIGH) +- See F9.4. The name *says* it is one ID; it isn't. + +--- + +### 20. Type-suffix tautology + +#### F20.1 — `ActionConfigurationType` enum + `actionType` field on + `ActionConfiguration` (MEDIUM) +- **Where:** `model.ts:5, 30`. +- **Why flagged:** Three layers of "action": + `ActionConfiguration.actionType: ActionConfigurationType`. The + type name has "ActionConfiguration" twice, the field name has + "action" + "Type". Drop tokens. +- **Suggestion:** With `BudgetAlertAction` parent renamed, the field + is `type: BudgetAlertActionType` (or use a discriminated union + if there are sub-shapes). + +#### F20.2 — `AlertConfigurationQuantityType` enum + + `quantityType` field (MEDIUM) +- **Where:** `model.ts:9, 43`. +- **Why flagged:** `quantityType: AlertConfigurationQuantityType` + reads with "quantity" said three times. +- **Suggestion:** Rename enum to `BudgetAlertQuantityType`; field + remains `quantityType`. Acceptable shape. + +#### F20.3 — `AlertConfigurationTriggerType` enum + `triggerType` + field (LOW) +- **Where:** `model.ts:17, 41`. +- Same pattern as F20.2. + +#### F20.4 — `AlertConfigurationTimePeriod` enum + `timePeriod` field + (LOW) +- **Where:** `model.ts:13, 39`. Same pattern. + +#### F20.5 — Generic `_ResponseSchema` on every wrap (LOW) +- **Where:** `model.ts:319, 329, 333, 343, 357`. +- **Why flagged:** `unmarshalCreateBudgetConfiguration_ResponseSchema` + is 51 characters with "Schema" suffixed onto an already-typed + `z.ZodType<...>`. The `Schema` suffix is conventional in Zod + ecosystems though. +- **Suggestion:** Acceptable; tied to generator. + +--- + +## Package overlap: `budgets` vs `budgetpolicy` + +This SDK exposes two separate packages whose names both start with +"budget": + +- `@databricks/sdk-budgets` (this package) +- `@databricks/sdk-budgetpolicy` (sibling) + +### F-OVERLAP.1 — `BudgetPolicy` vs `BudgetConfiguration` collision (HIGH) +- **Where:** `budgetpolicy/src/v1/model.ts:16` declares + `BudgetPolicy` with fields `policyId`, `policyName`, `customTags`, + `bindingWorkspaceIds`. This package's `BudgetConfiguration` + declares `budgetConfigurationId`, `accountId`, + `alertConfigurations`, `filter`, `displayName`. They are + *different* concepts (one defines spend-limit alerts, the other + defines workspace-binding policy tags) but a casual reader + searching for "budget" in autocomplete will see both and likely + conflate them. +- **Suggestion:** + - Add a short JSDoc on `BudgetConfiguration` clarifying it is the + spend-alert/notification budget. Cross-link to `BudgetPolicy`. + - Consider naming this package's primary type `SpendBudget` or + `UsageBudget` to disambiguate from `BudgetPolicy`. (`Budget` + alone is ambiguous with `BudgetPolicy`.) + - If staying with `Budget`, add a top-level index.ts JSDoc that + explicitly contrasts the two packages. + +### F-OVERLAP.2 — Both packages key off `accountId` and use similar + filter/binding semantics (MEDIUM) +- `BudgetPolicy.bindingWorkspaceIds: number[]` (direct array). +- `BudgetConfigurationFilter_WorkspaceIdClause.values: number[]` + (wrapped in a clause). +- Same data shape, different ergonomics. Cross-package + inconsistency. +- **Suggestion:** When (if) renaming, align the two field shapes. + +### F-OVERLAP.3 — Package directory name `budgets` (plural) vs + `budgetpolicy` (singular) (LOW) +- Cross-package naming pluralization inconsistency. Other examples + in the repo: `clusters` vs `clusterpolicies` vs `budgetpolicy`. + Mixed. +- **Suggestion:** Cross-cutting style decision. Pick one. + +--- + +## Summary table + +| # | Category | Findings | +| - | --------------------------------------- | -------- | +| 1 | Vague / generic | 7 | +| 2 | Redundant enum prefixes | 5 (3 acceptable) | +| 3 | Acronym casing | 4 (3 acceptable) | +| 4 | Underscores in TS identifiers | 2 | +| 5 | Cryptic abbreviations | 7 | +| 6 | Misleading names | 5 | +| 7 | Overly verbose | 6 | +| 8 | Redundant suffixes | 4 | +| 9 | Singular / plural mismatch | 6 (4 acceptable) | +| 10 | Reserved-word collisions | 5 (3 acceptable) | +| 11 | Empty / trivial wrappers | 0 | +| 12 | Duplicate concepts | 5 | +| 13 | Verb-tense inconsistency | 4 (2 acceptable) | +| 14 | Go / Java-style names | 5 | +| 15 | Generic field names | 5 | +| 16 | Field contradicting type domain | 3 | +| 17 | Inconsistent action verbs | 4 (1 acceptable) | +| 18 | Long enum values | 3 | +| 19 | Underspecified IDs | 4 (1 acceptable) | +| 20 | Type-suffix tautology | 5 | +| OVERLAP | budgets vs budgetpolicy | 3 | + +--- + +## Top highest-impact renames (recommended order) + +1. **F12.5:** `budgetConfigurationId` → `budgetId` (or pick one + universally). Same concept under two names is the worst smell here. +2. **F7.1 / F7.3 / F12.1:** Collapse `BudgetConfiguration`, + `CreateBudgetConfigurationBudget`, + `UpdateBudgetConfigurationBudget` into a single `Budget` type. +3. **F9.4 / F19.4:** Rename + `BudgetConfigurationFilter.workspaceId` to `workspaces` (and + its type to `WorkspaceFilter`); fix singular-noun-for-plural-clause + mismatch. +4. **F1.1 / F1.2 / F16.1 / F20.1:** Rename `ActionConfiguration` + to `BudgetAlertAction`, `target` to `recipient`, + `ActionConfigurationType` to `BudgetAlertActionType`. +5. **F7.2 / F7.4:** Drop "Configuration" from request type names + (`CreateBudgetRequest`) and method names + (`budgets.create(...)`); document explicit `Request`/`Response` + suffix convention. +6. **F4.1 / F14.4:** Replace underscored proto-style names with + flat PascalCase or namespaces; eliminates all + `eslint-disable-next-line` for `naming-convention`. +7. **F12.4:** Lift `accountId` to top-level on all request types + (currently nested under `budget` for create/update only). +8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`Iter`/`opts`/ + `pkgJson` etc. across all generated code. + +--- + +## Notes / out-of-scope + +- All findings above relate to **generated** code. Code-base rule: + "Code generated from API definition by Databricks SDK Generator. + DO NOT EDIT." The fixes belong upstream in the generator and + spec. This audit is a backlog for that generator. +- The `utils.ts` file contains the same generic helpers + (`executeCall`, `parseResponse`, `marshalRequest`, + `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, + `readAll`) that every generated package duplicates. The + duplication itself is not a naming issue, but the *names* + (`marshal/unmarshal`) are Go-flavored and inconsistent + (`parseResponse` vs `marshalRequest`). +- This package has no `tests/` directory (verified by repo + structure check), so the audit does not cover test naming. diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md new file mode 100644 index 00000000..d3387ccb --- /dev/null +++ b/.agent/naming-audit/bundle.md @@ -0,0 +1,415 @@ +# Naming Audit — `@databricks/sdk-bundle` (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/bundle/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Databricks Asset Bundles (DAB) — control-plane registry for `databricks bundle deploy`/`destroy` runs. + +--- + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 7 | +| Medium | 13 | +| Low | 11 | +| Observation | 8 | +| **Total** | **39** | + +Dominant themes: +1. **Pervasive redundant enum prefixes.** All seven enums repeat the type name on every member (`DEPLOYMENT_STATUS_ACTIVE`, `VERSION_TYPE_DEPLOY`, etc.) — 50+ values affected — which is a Go/Protobuf carry-over that hurts TS ergonomics. +2. **`VersionComplete` is a misleading type name.** It is a noun that reads like a boolean predicate, but it actually carries a completion *reason* enum; the type, the field that holds it (`completionReason`), and the values disagree on terminology. +3. **`Resource` / `Operation` `name` is the qualified path, not a display name** — semantic overload of `name` recurs on every entity, while a separate `displayName` field also exists on `Deployment`/`Version`. Pure Google-AIP carry-over that loses meaning in TS. +4. **"Bundle" is in the URL but absent from type names**, while `DeploymentResourceType` (the domain catalog) is unrelated to the `Resource` interface (the per-deployment tracked item) — two distinct concepts share a confusable root. + +--- + +## High-Severity Findings + +### H1. `VersionComplete` enum name is misleading (Category: 6 — misleading; 13 — verb-tense) + +**Location:** `model.ts:127-137`, exported `index.ts:11`. + +```ts +export enum VersionComplete { + VERSION_COMPLETE_UNSPECIFIED = ..., + VERSION_COMPLETE_SUCCESS = ..., + VERSION_COMPLETE_FAILURE = ..., + VERSION_COMPLETE_FORCE_ABORT = ..., + VERSION_COMPLETE_LEASE_EXPIRED = ..., +} +``` + +The type *describes the reason a version finished*, but the identifier `VersionComplete` reads either as an adjective ("the version [is] complete") or an imperative verb ("complete the version"). The corresponding field is `completionReason: VersionComplete` (`Version.completionReason`, `CompleteVersionRequest.completionReason`), and the docstring says "Reason why a version was completed", so the type itself should be `VersionCompletionReason` (or `CompletionReason`). The current name forces the reader to inspect each call site to discover the type's role. + +Compounding the issue: the `complete` action lives on a *method* called `completeVersion()` (`client.ts:102`), so `VersionComplete` and `completeVersion` look related but mean different things — one is an enum of post-hoc reasons, the other is the imperative action. + +**Suggested rename:** `VersionCompletionReason` or `CompletionReason`. The value prefix would then read `VERSION_COMPLETION_REASON_SUCCESS`, which matches the field name verbatim. + +--- + +### H2. Redundant enum-member prefixes throughout (Category: 2 — redundant enum prefixes; 18 — long enum values) + +**Location:** every enum in `model.ts:19-155`. + +```ts +DeploymentResourceType.DEPLOYMENT_RESOURCE_TYPE_JOB +DeploymentStatus.DEPLOYMENT_STATUS_ACTIVE +OperationActionType.OPERATION_ACTION_TYPE_BIND_AND_UPDATE +OperationStatus.OPERATION_STATUS_SUCCEEDED +VersionComplete.VERSION_COMPLETE_LEASE_EXPIRED +VersionStatus.VERSION_STATUS_IN_PROGRESS +VersionType.VERSION_TYPE_DEPLOY +``` + +Every member of every enum re-states the enum name. This is a Protobuf/Go habit that does not survive the port: in TypeScript the call site is already `DeploymentStatus.X`. The most extreme cases are `OPERATION_ACTION_TYPE_INITIAL_REGISTER`, `DEPLOYMENT_RESOURCE_TYPE_MODEL_SERVING_ENDPOINT`, and `DEPLOYMENT_RESOURCE_TYPE_SYNCED_DATABASE_TABLE` (46+ characters). + +**Note:** because the enum *values* are sent on the wire (the schemas in `model.ts:728-842` use `z.enum(EnumName)` which preserves the string form), the string values themselves must remain `'DEPLOYMENT_RESOURCE_TYPE_MODEL'` etc. — but the *identifier* on the enum can be shortened (`DeploymentResourceType.Model = 'DEPLOYMENT_RESOURCE_TYPE_MODEL'`). This is the common TS solution but is not currently applied. + +**Affected enums:** all seven (`DeploymentResourceType`, `DeploymentStatus`, `OperationActionType`, `OperationStatus`, `VersionComplete`, `VersionStatus`, `VersionType`) — ~50 identifiers. + +--- + +### H3. Underscores in TypeScript identifiers (Category: 4 — underscores in TS) + +**Location:** all enum members in `model.ts:19-155`. + +All enum member identifiers use `SCREAMING_SNAKE_CASE` (`DEPLOYMENT_STATUS_ACTIVE`, `OPERATION_ACTION_TYPE_BIND_AND_UPDATE`, etc.). The Google TS style guide and ESLint `@typescript-eslint/naming-convention` rule both forbid underscores in identifiers (the convention is `PascalCase` for enum members). The wire-value strings on the right-hand side can keep the underscores, but the identifiers should be `Active`, `BindAndUpdate`, `InitialRegister`, etc. + +This is the same root cause as H2 but tracked separately because it is a hard style-guide violation regardless of redundancy. + +--- + +### H4. `name` field is semantically overloaded across every entity (Category: 6 — misleading; 12 — duplicate concepts) + +**Location:** `model.ts` — `Deployment.name`, `Operation.name`, `Resource.name`, `Version.name`, and on every request type (`CompleteVersionRequest.name`, `DeleteDeploymentRequest.name`, `GetDeploymentRequest.name`, `GetOperationRequest.name`, `GetResourceRequest.name`, `GetVersionRequest.name`, `HeartbeatRequest.name`). + +`name` is *not* a human-readable name — it is the fully-qualified resource path (`deployments/{deployment_id}/versions/{version_id}/operations/{resource_key}`). The actual human name lives in `displayName` on `Deployment` and `Version`. TypeScript users coming from non-Google APIs will read `deployment.name` and reasonably expect a string the user typed. + +Additionally, *all* request types reuse the field name `name` for entirely different scopes: +- `GetDeploymentRequest.name` → a deployment path. +- `GetOperationRequest.name` → an operation path (4 segments). +- `HeartbeatRequest.name` → a version path. +- `CompleteVersionRequest.name` → a version path. + +A reader cannot tell what `name` means without consulting the docstring of each request. + +**Suggested rename:** `resourceName` (matches the docstrings) or, even better, per-request specifics (`deploymentName`, `versionName`, `operationName`). At minimum, model entities should use a different field (`path` / `qualifiedName` / `resourceName`) so that "name" is freed up for the human-readable label. + +--- + +### H5. `DeploymentResourceType` enum and `Resource` interface share a confusable root concept (Category: 12 — duplicate concepts; 1 — vague) + +**Location:** `model.ts:19` (`DeploymentResourceType`) versus `model.ts:487-511` (`Resource`). + +These are two distinct things: +- `DeploymentResourceType` — a *taxonomy* enum of what kinds of Databricks objects a bundle can manage (`JOB`, `PIPELINE`, `CLUSTER`, …). +- `Resource` — a *tracked record* within a deployment, with a `resourceType` field of type `DeploymentResourceType`. + +Both will appear together in autocomplete (`Resource`, `Resource.resourceType: DeploymentResourceType`, `Resource.resourceKey`, `Resource.resourceId`), and a user can easily mistake `Resource` for the enum or vice-versa. The naming `Resource.resourceType` is also tautological — `Resource` already implies a resource, so `Resource.type` (typed as `DeploymentResourceType`) is enough. + +Compounding this: `Resource.resourceKey` (a key *within the bundle config*, e.g. `"jobs.foo"`) and `Resource.resourceId` (the actual workspace ID, e.g. a job ID) are dangerously similar. Both are strings, both contain "resource", differing only by `Key` vs. `Id`. Easy to swap by accident. + +**Suggested renames:** `Resource.type` (instead of `resourceType`), `Resource.bundleKey` or `Resource.configKey` (instead of `resourceKey`), `Resource.workspaceId` (instead of `resourceId`). Same renames apply to `Operation.resourceKey`, `Operation.resourceId`, and `CreateOperationRequest.resourceKey`. + +--- + +### H6. "Bundle" is missing from every type name despite being the package name (Category: 14 — Go/Java-style; 15 — generic names losing meaning) + +**Location:** all exported types in `model.ts`, `index.ts:5-39`. + +The package is `@databricks/sdk-bundle` and every URL has `/api/2.0/bundle/`, yet not one type is `Bundle*`. Instead, the top-level entity is `Deployment` — extremely generic in TypeScript, where "deployment" appears in dozens of unrelated packages (jobs, model serving, apps, etc.). Outside the namespace, `Deployment` says nothing. + +Worse: `Deployment` also unrelatedly resembles `DeploymentResourceType` (see H5), and `DeploymentStatus` is used both on the top-level deployment *and* describes one of the lifecycle terms `DELETED` that does not match the more recent `destroyTime` lifecycle. From outside this package, the type `Deployment` is non-self-describing. + +Note: the user-supplied glossary explicitly flags "Bundle" as overloaded. The package solves the overload by *avoiding the word*, but this swap is not free — it just moves the ambiguity from "Bundle" to "Deployment". + +**Suggested rename:** `BundleDeployment` (or keep `Deployment` if internal consistency is preferred — but then export an aliased `BundleDeployment` for downstream consumers). At minimum, `Deployment` should be in the package-level JSDoc as "a bundle deployment", which the docstring on the interface already says. + +--- + +### H7. `HeartbeatRequest` / `HeartbeatResponse` and `heartbeat()` use a bare noun where the verb is `renew` (Category: 6 — misleading; 17 — inconsistent action verbs) + +**Location:** `model.ts:304-316`, `client.ts:398-421`. + +The semantics described in the docstring (`client.ts:391-397`) are *renew the lock on a version*. The method name `heartbeat` is a bare noun, not a verb. The other RPCs use action verbs: `createX`, `getX`, `deleteX`, `listX`, `completeX`. Only `heartbeat` is a noun. Worse, the return type `HeartbeatResponse` only carries `expireTime` — the new lock expiry — which is the *result of renewal*, not a "heartbeat response". + +**Suggested renames:** +- Method `heartbeat()` → `renewLock()` or `renewVersionLock()`. +- Type `HeartbeatRequest` → `RenewLockRequest`. +- Type `HeartbeatResponse` → `RenewLockResponse`. + +--- + +## Medium-Severity Findings + +### M1. `Resource.resourceKey` doc says "Can be an arbitrary UTF-8 encoded string key" — name doesn't hint at format (Category: 19 — underspecified) + +**Location:** `model.ts:453-458`. + +`resourceKey` is overloaded: it can be `"jobs.foo"`, `"pipelines.bar"`, `"jobs.foo.permissions"`, or `"files."`. The name `resourceKey` does not convey that it is a *dotted bundle config path*. `bundleConfigPath` or `configKey` would be more honest. + +--- + +### M2. `Operation.resourceId` and `Resource.resourceId` mix two different "IDs" with the deployment/version IDs (Category: 5 — cryptic; 19 — underspecified) + +**Location:** `model.ts:469`, `model.ts:503`, plus `CreateDeploymentRequest.deploymentId` (`model.ts:185`), `CreateVersionRequest.versionId` (`model.ts:220`), `Version.versionId` (`model.ts:527`), `Deployment.lastVersionId` (`model.ts:246`), `Resource.lastVersionId` (`model.ts:508`). + +`resourceId` is *the workspace ID of the underlying job/pipeline/etc.*, but `deploymentId` and `versionId` are *control-plane IDs internal to this service*. These three live side-by-side and look like they're all the same "kind" of ID, but they're not. A `workspaceId` / `workspaceObjectId` rename for `resourceId` would resolve this — the comment on the field literally says "actual resource in the workspace". + +--- + +### M3. `lastVersionId` exists on both `Deployment` and `Resource` with subtly different meaning (Category: 12 — duplicate; 16 — field contradicting type domain) + +**Location:** `Deployment.lastVersionId` (`model.ts:246`), `Resource.lastVersionId` (`model.ts:508`). + +- `Deployment.lastVersionId` = "the most recent deployment version" (any version). +- `Resource.lastVersionId` = "the last version where this resource was updated" (the most recent version *that touched this resource*). + +These should be named distinctly: `Deployment.latestVersionId` vs. `Resource.lastTouchedVersionId` (or `Resource.lastUpdatedInVersionId`). As written, the names are identical and the difference is buried in docstrings. + +--- + +### M4. `Resource.lastActionType` vs. `Operation.actionType` — same type, slightly different name (Category: 13 — verb-tense; 17 — inconsistent) + +**Location:** `model.ts:460` (`Operation.actionType`), `model.ts:506` (`Resource.lastActionType`). + +`Operation.actionType` is the action *of this operation*, `Resource.lastActionType` is the action *of the most recent operation*. The "last" prefix is the convention — that's fine — but pairing with M3 there's no consistent rule (the version field is plain `lastVersionId` without an explicit "last" affix differentiator; the action field is `lastActionType`). Picking one convention (`last*` everywhere, including `lastActionType` and `lastVersionId`) is fine, but make sure both follow the same template. + +Also: `actionType` (and `OperationActionType`) is itself tautological — `Operation` already implies action. `Operation.kind` or just `Operation.action: OperationAction` would suffice. + +--- + +### M5. `OperationActionType` enum name has the "action type" tautology (Category: 20 — type-suffix tautology) + +**Location:** `model.ts:83`. + +Reads as "the type of action type of operation". One of "action" or "type" is redundant. Pick `OperationAction` (the kind/category of an operation) or even `BundleAction`. + +--- + +### M6. `DeploymentResourceType` is also tautological in compound form (Category: 20 — type-suffix tautology) + +**Location:** `model.ts:19`. + +Reads as "deployment resource type", but the enum is the *catalog of resource kinds*, not a property of deployment. Just `ResourceKind` (or `BundleResourceKind` if you want to disambiguate from the `Resource` interface) would suffice. See H5 for the broader confusion. + +--- + +### M7. `completionReason` vs. enum `VersionComplete` mismatch (Category: 17 — inconsistent action verbs) + +**Location:** `Version.completionReason` (`model.ts:544`), `CompleteVersionRequest.completionReason` (`model.ts:169`). + +The field is `completionReason` (noun "reason" with "completion" adjective). The type is `VersionComplete` (no "Reason" suffix). Wire JSON is `completion_reason`. If the type is renamed per H1 to `VersionCompletionReason`, everything aligns. + +--- + +### M8. `VersionComplete` enum value `VERSION_COMPLETE_FORCE_ABORT` is a verb phrase where others are nouns (Category: 13 — verb-tense) + +**Location:** `model.ts:133`. + +The enum values are: +- `SUCCESS` — noun. +- `FAILURE` — noun. +- `FORCE_ABORT` — verb phrase ("force abort"). +- `LEASE_EXPIRED` — past-participle phrase. + +Three different grammatical structures for what should be parallel completion reasons. The docstring on `FORCE_ABORT` says "was force-aborted by another user" — so `FORCE_ABORTED` (past participle) would parallel `LEASE_EXPIRED`, and noun forms (`SUCCESS`, `FAILURE`, `FORCED_ABORT`, `LEASE_EXPIRATION`) would be even more parallel. + +--- + +### M9. Method `heartbeat()` collides with idiomatic "is-alive" connotation (Category: 6 — misleading; 7 — overly verbose interactions) + +**Location:** `client.ts:398`. + +In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here it actively *mutates server state* (renews a lock). The verb suggests a read but it's a write. See H7 for suggested rename to `renewLock`. + +--- + +### M10. `Version.versionType` field — Java/Go-style redundancy (Category: 20 — type-suffix tautology; 14 — Go/Java) + +**Location:** `model.ts:539`. + +`version.versionType` reads as "the version type of the version". Prefer `Version.type: VersionType` (or rename the enum to `VersionKind`, see M11). Same root issue as `Resource.resourceType` and `Operation.actionType`. + +--- + +### M11. `VersionType` enum is generic, values prepended with `VERSION_TYPE_` (Category: 1 — vague) + +**Location:** `model.ts:149`. + +`VersionType` could be anything (semantic version? major/minor?). What it actually means is "deploy or destroy". `VersionKind` (or `BundleCommand`/`CliCommand`) is clearer. Values would shrink to `Deploy`/`Destroy`. + +--- + +### M12. `Resource.state` and `Operation.state` use the same field name for different snapshots (Category: 15 — generic; 12 — duplicate) + +**Location:** `Resource.state` (`model.ts:499`), `Operation.state` (`model.ts:465`). + +`state` here means "serialized config blob the CLI sent" — but `state` is one of the most overloaded terms in software. The docstrings clarify ("Serialized local config state"), but the names don't. `configState`, `configSnapshot`, or `state` distinct from `status` would help. Note `Resource.state` and `Resource.status`-style field would collide alphabetically in IDE autocomplete; there is currently no `Resource.status`, so `state` is at least non-conflicting. + +--- + +### M13. `errorMessage` on `Operation` is set only on failure but always typed `string | undefined` (Category: 6 — misleading; 15 — generic) + +**Location:** `model.ts:480`. + +Field name doesn't suggest tight coupling to `status === FAILED`. Could be `failureMessage` or `failureReason` to mirror `VersionComplete` style. Minor, but `failureMessage` reads more honestly. + +--- + +## Low-Severity Findings + +### L1. `createdBy` vs. `destroyedBy` vs. `completedBy` past-tense consistency is good, but `targetName` is uncommented + +**Location:** `Deployment.createdBy` (`model.ts:248`), `Deployment.destroyedBy` (`model.ts:264`), `Version.completedBy` (`model.ts:550`). + +All three are well-named (`createdBy`, `destroyedBy`, `completedBy`). However, `Deployment.targetName` and `Version.targetName` are not parallel — they're not actor names, they're the bundle's *target* (a config concept). A reader might miscategorize on autocomplete. Consider `bundleTargetName` for explicitness. + +--- + +### L2. `destroyTime` / `destroyedBy` naming carry over from the destroy-vs-delete distinction (Category: 6 — misleading) + +**Location:** `Deployment.destroyTime` (`model.ts:259`), `Deployment.destroyedBy` (`model.ts:264`). + +The comment on `destroyTime` explicitly justifies the divergence from `deleteTime` ("Named destroy_time (not delete_time) because this tracks the `databricks bundle destroy` command, not the API-level deletion"). That is a sensible choice, but worth noting that a reader scanning the field list sees `createTime`, `updateTime`, `destroyTime` and may mistakenly think it equals "delete time" (since `DeploymentStatus.DELETED` exists). Could keep `destroyTime` but rename the enum value to `DEPLOYMENT_STATUS_DESTROYED` for consistency. Currently the enum is `DELETED` while the lifecycle event is `destroy`. + +--- + +### L3. `cliVersion` — abbreviation acceptable but flag for awareness (Category: 5 — cryptic abbreviation; 3 — acronym casing) + +**Location:** `Version.cliVersion` (`model.ts:535`). + +`cli` is a well-known acronym (Command-Line Interface) so the abbreviation is fine, but the casing `cliVersion` (lowercase `cli`) is inconsistent with Google's TS rule that acronyms are PascalCase as a word (i.e. `cliVersion` is correct camelCase, but `Cli` rather than `CLI` is the convention — check the rest of the SDK for consistency). Wire form is `cli_version` which is fine. + +--- + +### L4. `force` field is a boolean adverb, not a noun (Category: 1 — vague; 6 — misleading) + +**Location:** `CompleteVersionRequest.force` (`model.ts:175`). + +`force: boolean` is widely understood but extremely generic. The docstring says "force-completes the version even if the caller is not the original creator" — so `forceComplete` or `overrideOwnership` would be more honest. Bare `force` makes you read the docs to know what it forces. + +--- + +### L5. `parent` field on request types is generic (Category: 15 — generic; 1 — vague) + +**Location:** `CreateOperationRequest.parent` (`model.ts:196`), `CreateVersionRequest.parent` (`model.ts:212`), `ListOperationsRequest.parent` (`model.ts:351`), `ListResourcesRequest.parent` (`model.ts:383`), `ListVersionsRequest.parent` (`model.ts:415`). + +This is a Google AIP carry-over. `parent` is meaningful inside Google's resource hierarchy convention but loses meaning in TS where IDEs will surface it without context. Could be `deploymentName` (for `Create*Request`/`List*Request` whose parent is a deployment) or `versionName` (for `CreateOperationRequest`/`ListOperationsRequest` whose parent is a version). Different request types use `parent` for different scopes — same problem as `name` (see H4). + +--- + +### L6. `pageSize` / `pageToken` / `nextPageToken` are consistent with Google AIP — fine + +**Location:** all `List*Request`/`List*Response` types. + +No issue, just noting these names are uniform and correct. + +--- + +### L7. `*Iter` suffix on async generators (Category: 5 — cryptic abbreviation) + +**Location:** `Client.listDeploymentsIter`, `Client.listOperationsIter`, `Client.listResourcesIter`, `Client.listVersionsIter` (`client.ts:457`, `508`, `559`, `613`). + +`Iter` is a Go-style abbreviation for "iterator". The Go SDK uses `Iterator(...)` or `Iter(...)` similarly. In TS the convention is more often `listDeploymentsAsyncIterator` or `iterateDeployments` (or, if the existing list method returns the page, an overload). `Iter` is short but cryptic to JS-native developers. Not load-bearing because there is a comment-free convention across the SDK — verify with the wider SDK before changing. + +--- + +### L8. `Operation` interface name collides with `Operation` from `@databricks/sdk-databricks` long-running-ops (Category: 12 — duplicate concepts) + +**Location:** `Operation` (`model.ts:441-481`). + +In many Databricks/Google APIs, `Operation` is the LRO (Long-Running Operation) pattern from `google.longrunning.Operation`. Here, `Operation` is a *resource operation row in a deployment version*. Same name, totally different concept. Importing both into the same file would collide. `ResourceOperation` would disambiguate. Check across other packages (`packages/databricks`, etc.) for an existing `Operation` type. + +--- + +### L9. `Resource.resourceKey` vs `Operation.resourceKey` — same name, same role (good) + +**Location:** `model.ts:497`, `model.ts:458`. + +This is correct re-use — both reference the same bundle config path. No issue. Noted for completeness. + +--- + +### L10. `deployments` request method names vs URL path consistency + +**Location:** `Client.listDeployments` → `/api/2.0/bundle/deployments` (`client.ts:428`). + +The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The method `listDeployments` matches. No issue, just noting the package's external resource is named "deployment" and the package is named "bundle", reinforcing the H6 observation that "Bundle" is in the URL but absent from type names. + +--- + +### L11. Acronym casing in `cliVersion`, `versionId`, `expireTime` — check SDK-wide + +**Location:** `Version.cliVersion` (`model.ts:535`), `Version.versionId` (`model.ts:527`), `HeartbeatResponse.expireTime` (`model.ts:315`). + +`expireTime` is a verb (or noun) form that differs from `createTime` (gerund-like) and `updateTime`. `expirationTime` would parallel `creationTime`. Or rename the others to `createdAt` / `updatedAt` / `expiresAt` style. The SDK has presumably picked a convention — note for cross-package consistency. + +--- + +## Observations (Non-Defects) + +### O1. Marshal/unmarshal schemas use snake_case keys to match wire format + +`marshal*` schemas write `display_name`, `created_by`, etc. while the TS-side interfaces use `displayName`, `createdBy`. This is the correct pattern for a 1:1 port and is not a naming defect — just noting the boundary. + +### O2. `unmarshalListDeploymentsResponseSchema` etc. are long but well-structured + +The `unmarshal{Type}Schema` and `marshal{Type}Schema` exports are verbose but completely predictable. No findings — they read like generator output (which they are). + +### O3. JSDoc on the `state` fields is good + +`Resource.state` and `Operation.state` both clearly say "Serialized local config state". Naming could improve (M12) but doc-level disambiguation is solid. + +### O4. Pagination naming is uniform and correct + +`pageSize`, `pageToken`, `nextPageToken`, `*Iter` (modulo L7) — all four `List*Request`/`List*Response` pairs are mechanically identical, with parallel `List*Iter` async generators on the client. + +### O5. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing + +The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is correct; the *name* is what is generic (see M12). + +### O6. Method `getResource` returns `Resource`, no naming collision + +`client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level — only at the *interface* level (H5). + +### O7. Comment on the `name`-vs-`destroy` divergence is appreciated + +`Deployment.destroyTime` has an in-code justification (`model.ts:255-258`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H4). + +### O8. The `HeartbeatResponse.expireTime` field has no `Lease`/`Lock` prefix + +The docstring says "new lock expiry time", but the field is just `expireTime`. Calling it `lockExpireTime` or `lockExpiresAt` would self-document. Marginal because of H7 (rename the whole method to `renewLock` and the field name becomes obvious from context). + +--- + +## Domain Glossary + +| Domain term | Meaning | Naming concerns? | +| ------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------ | +| Bundle | Databricks Asset Bundle — a config-driven project deployed via `databricks bundle deploy`. | Absent from all type names (H6). | +| Deployment | A registered bundle in the control plane. One per bundle target. Top-level entity in this API. | Overloaded with "deploy time" sense; generic outside the package. | +| Version | A single deploy or destroy *run* of a bundle. Acquires an exclusive lock on the deployment. | OK; `Version` is clear within the package. | +| Operation | One resource action (create/update/delete/bind/...) recorded under a version. Append-only. | Collides with LRO `Operation` (L8). | +| Resource | A per-deployment record of one Databricks object the bundle manages (a job, a pipeline, etc.). | Confusable with `DeploymentResourceType` (H5). | +| `resource_key` | A dotted config path inside the bundle YAML (e.g. `"jobs.foo"`). | Generic name (M1, H5). | +| `resource_id` | The workspace-scoped ID of the underlying Databricks object (e.g. a job ID, pipeline ID). | Mixes with control-plane IDs (M2). | +| Heartbeat | Lock renewal RPC sent by the active CLI while a version is in progress. | Misleading name; should be "renew lock" (H7). | +| Target | A named profile within a bundle (e.g. `dev`, `staging`, `prod`). | `targetName` field on Deployment/Version is OK but could be `bundleTargetName` (L1). | +| Destroy | The `databricks bundle destroy` command — undeploys a bundle. Distinct from API-level delete. | Named `destroyTime` (not `deleteTime`) intentionally (L2). | +| Force-abort | A user other than the version creator forcibly completes the version. | `VERSION_COMPLETE_FORCE_ABORT` is the verb form (M8). | +| Lease | The lock held by a version; renewed by Heartbeat; expires after timeout. | Surfaces only in `VERSION_COMPLETE_LEASE_EXPIRED`. | + +--- + +## File Coverage + +| File | Lines | Findings | +| ----------------- | ----- | --------------------------------------------------------------------------------- | +| `src/v1/model.ts` | 843 | H1, H2, H3, H4, H5, H6, H7, M1-M13, L1-L5, L8, L9, L11, O1, O2, O3, O5, O7, O8 | +| `src/v1/client.ts`| 630 | H4 (request types), H7 (method name), M9, L7, L10, O6 | +| `src/v1/utils.ts` | 151 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | +| `src/v1/index.ts` | 40 | Re-exports — inherits findings from `model.ts` and `client.ts`. | + +Every exported identifier in `model.ts` and `client.ts` was inspected. `utils.ts` and `index.ts` produced no incremental findings beyond what the model/client files surface. diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md new file mode 100644 index 00000000..f36db272 --- /dev/null +++ b/.agent/naming-audit/catalogs.md @@ -0,0 +1,645 @@ +# Naming Audit: `catalogs` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/catalogs/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Unity Catalog (UC) — top-level securable container. + +--- + +## Summary + +The `catalogs` package surfaces five UC catalog operations +(`createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, +`updateCatalog`) plus a paginated iterator. The model layer mostly mirrors +the Go SDK 1:1, so most issues are inherited from the upstream definitions. +The most pervasive problems are (1) proto-style underscore-suffixed +identifiers leaking into TypeScript (`ConversionInfo_State`, +`DeleteCatalog_Response`, `ListCatalogs_Response`, `*_OptionsEntry`, +`*_PropertiesEntry`), (2) the cryptic `nameArg` path-parameter field, and +(3) massive `Create*`/`Update*` request shapes that include read-only +output fields (`createdAt`, `createdBy`, `provisioningInfo`, +`conversionInfo`, `drReplicationInfo`, `securableType`, `fullName`, etc.) +that have no business in a write request. + +--- + +## Findings + +### 1. Vague / generic names + +#### 1.1 `EffectivePredictiveOptimizationFlag.value` (model.ts:242) +Field name `value` on a type whose entire purpose is exposing a flag value +is doubly redundant — the field is the only payload-bearing scalar on the +type and conveys no semantics. The doc comment reveals it actually holds +the enable/disable string ("Whether predictive optimization should be +enabled..."). Better: `enabled`, `predictiveOptimizationEnabled`, or +mirror the upstream `flagValue` if present. Same issue surfaces in the +marshal/unmarshal schemas (lines 489, 494, 636, 641). + +#### 1.2 `*_OptionsEntry.value` / `*_PropertiesEntry.value` (model.ts:133, 139, 208, 214, 372, 378) +Single-character-like generic names (`key`, `value`) on the exported +map-entry types. These names carry no semantics on their own and only +make sense in the context of the parent map. + +#### 1.3 `DrReplicationInfo.replicatedEntities` (model.ts:231) +A `Uint8Array` named `replicatedEntities` is meaningless — the doc +comment points at an internal Google Doc. The name promises a list of +entities; the type is a byte blob. Consumers cannot guess what to do +with it. Either rename to something signaling the opacity +(`replicatedEntitiesProto`, `replicatedEntitiesPayload`) or expose a +parsed shape. + +#### 1.4 `ConversionInfo.state` and `ProvisioningInfo.state` (model.ts:145, 305) +Generic field name `state` on both types. Whose state? The name only +acquires meaning from its surrounding type — if the field is ever +inlined or destructured, the meaning is lost. + +#### 1.5 `inheritedFromType` / `inheritedFromName` (model.ts:244, 246) +`Type` here is a free-form `string`, not the `SecurableType` enum that +governs the rest of the package. The name `inheritedFromType` suggests an +enum/typed handle but is in fact human-readable text. Misleading — see +also §6.1. + +--- + +### 2. Redundant enum prefixes + +#### 2.1 `DrReplicationStatus` (model.ts:21-25) +All three variants are prefixed with `DR_REPLICATION_STATUS_`: +- `DR_REPLICATION_STATUS_UNSPECIFIED` +- `DR_REPLICATION_STATUS_PRIMARY` +- `DR_REPLICATION_STATUS_SECONDARY` + +In TypeScript this becomes `DrReplicationStatus.DR_REPLICATION_STATUS_PRIMARY` +— the enum name repeats four times. Should be `UNSPECIFIED`, `PRIMARY`, +`SECONDARY`. This is a verbatim port of proto `enum` style and is the +single most jarring naming violation in the package. + +#### 2.2 `ConversionInfo_State.STATE_UNSPECIFIED` (model.ts:51) +Same pattern — `ConversionInfo_State.STATE_UNSPECIFIED` repeats `STATE`. +Drop the `STATE_` prefix on the variant so it reads `UNSPECIFIED`. + +#### 2.3 `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58) +Same as 2.2. + +#### 2.4 `CatalogType.*_CATALOG` (model.ts:13-18) +Every variant ends in `_CATALOG`: `MANAGED_CATALOG`, +`DELTASHARING_CATALOG`, `SYSTEM_CATALOG`, `INTERNAL_CATALOG`, +`FOREIGN_CATALOG`, `MANAGED_ONLINE_CATALOG`. Read aloud: +`CatalogType.MANAGED_CATALOG`. The `_CATALOG` suffix is fully redundant — +`MANAGED`, `DELTA_SHARING`, `SYSTEM`, `INTERNAL`, `FOREIGN`, +`MANAGED_ONLINE` carries the same meaning. (`DELTASHARING` also runs the +two words together — see §3.4.) + +--- + +### 3. Acronym casing inconsistencies (UC, DR, CMK, AKV) + +#### 3.1 `DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo` (model.ts:21, 228, 121) +"DR" (Disaster Recovery) is a two-letter initialism. Google TS style guide +treats two-letter acronyms as words (`Db`, `Io`, `Ui`), so `Dr…` is +defensible — but the package's own doc comments spell it "Disaster +Recovery", and to a reader `Dr` reads first as "Doctor". Recommend +spelling it out: `DisasterRecoveryReplicationStatus` / +`DisasterRecoveryReplicationInfo` for the public identifiers, or at minimum +keep `DR` uppercase as an inline initialism (`DRReplicationStatus`) so it +stops looking like a name prefix. + +#### 3.2 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) +CMK ("Customer Managed Key") is consistently cased `Cmk` here. The same +concept is spelled out elsewhere as `customerManagedKeyId` +(EncryptionSettings.customerManagedKeyId — model.ts:255). Pick one: +either use the acronym everywhere (`azureCmkAccessConnectorId`, +`cmkId`) or expand it everywhere +(`azureCustomerManagedKeyAccessConnectorId`, `customerManagedKeyId`). + +#### 3.3 `azureKeyVaultKeyId` vs comment "AKV URL" (model.ts:257) +Field is `azureKeyVaultKeyId` but the doc comment says "the AKV URL in +Azure". The field name and doc must agree on whether the value is a URL +or an ID — they currently contradict each other. See also §6.2. + +#### 3.4 `DELTASHARING_CATALOG` enum variant (model.ts:14) +"Delta Sharing" is two words. Variant runs them together as +`DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` (or simply +`DELTA_SHARING` after stripping the `_CATALOG` suffix per §2.4). + +#### 3.5 "UC Native" in doc comments (model.ts:118, 193, 357 etc.) +Doc comments use "UC Native" capitalisation, but the package never refers +to Unity Catalog as `UC` in identifiers — only in comments. This is a +minor inconsistency: when the codebase uses `unity-catalog` in URLs and +"Unity Catalog" in prose but the comment shifts to "UC Native", the +reader has to remember the abbreviation. Spell out "Unity-Catalog-native" +or pick one form. + +--- + +### 4. Underscores in TypeScript identifiers + +This is the package's most widespread cosmetic issue. Proto-style +underscore separators appear in exported TS identifiers, and each one has +been silenced with `@typescript-eslint/naming-convention -- Proto-style…` +disable comments — the lint rule disagrees and we are deliberately +working around it. + +#### 4.1 `ConversionInfo_State` (model.ts:50) +Proto nested-enum convention `Parent_Child`. TypeScript convention is +`ConversionInfoState` (or, better, top-level `ConversionState` because +there is no real nesting in TS — see §13.1). + +#### 4.2 `ProvisioningInfo_State` (model.ts:57) +Same as 4.1. Should be `ProvisioningState`. + +#### 4.3 `CatalogInfo_OptionsEntry`, `CatalogInfo_PropertiesEntry` (model.ts:131, 137) +Proto map-entry types — see §1.2. + +#### 4.4 `CreateCatalog_OptionsEntry`, `CreateCatalog_PropertiesEntry` (model.ts:206, 212) +Same as 4.3. + +#### 4.5 `UpdateCatalog_OptionsEntry`, `UpdateCatalog_PropertiesEntry` (model.ts:370, 376) +Same as 4.3. + +#### 4.6 `DeleteCatalog_Response` (model.ts:225) +Should be `DeleteCatalogResponse`. + +#### 4.7 `ListCatalogs_Response` (model.ts:292) +Should be `ListCatalogsResponse`. + +#### 4.8 `unmarshalDeleteCatalog_ResponseSchema`, `unmarshalListCatalogs_ResponseSchema` (model.ts:468, 515) +The underscores propagate into the schema exports. Should be +`unmarshalDeleteCatalogResponseSchema`, `unmarshalListCatalogsResponseSchema`. + +--- + +### 5. Cryptic abbreviations + +#### 5.1 `nameArg` (model.ts:219, 264, 310) +Used as the catalog name path-parameter on `DeleteCatalog`, `GetCatalog`, +and `UpdateCatalog`. The `Arg` suffix is jargon from the Go generator +distinguishing path arguments from request-body fields with the same key. +TypeScript callers have no need for this distinction — the field is the +catalog name and should be named `name` (or `catalogName` if a sibling +`name` field is required for body symmetry). Today, `UpdateCatalog` has +*both* `nameArg` (path) and `name` (body) — virtually guaranteeing user +confusion. See also §15.1. + +#### 5.2 `Dr` prefix throughout (`DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo`, `lastFailoverTimeMs` doc) — see §3.1. + +#### 5.3 `Cmk` prefix — see §3.2. + +#### 5.4 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:257) — see §3.3. + +#### 5.5 `pkgJson` (client.ts:19) +Variable name `pkgJson` for `package.json`. Mostly internal — minor — but +worth noting for consistency. + +--- + +### 6. Misleading names + +#### 6.1 `EffectivePredictiveOptimizationFlag.value` "string" carries enum-like semantics +The field is typed `string | undefined` but the comment ("Whether predictive +optimization should be enabled…") implies a tri-state (enabled / disabled / +inherit). Either the type should be an enum (`PredictiveOptimizationFlag`) +or the field should be named explicitly (`enabled: string`). See also §1.1. + +#### 6.2 `azureKeyVaultKeyId` is described as a URL (model.ts:257-258) +Field is named `…Id` but doc says "the AKV URL in Azure". Either rename to +`azureKeyVaultKeyUri` or fix the doc to match. Today the name lies about +what the field holds. + +#### 6.3 `replicatedEntities: Uint8Array` (model.ts:231) +A name with cardinal plural ("entities") implies an iterable collection; +the type is a single byte buffer. See also §1.3. + +#### 6.4 `CatalogInfo.fullName` "Corresponds with the name field" (model.ts:116) +The doc explicitly states that `fullName` equals `name` for catalogs. +The field exists only to satisfy the parent `Securable` contract. This is +arguably acceptable (UC is column-uniform across securables) but the name +misleads — it promises richer information than `name` provides. + +#### 6.5 `CatalogInfo.options` vs `CatalogInfo.properties` (model.ts:124-127) +Both are `Record` with identical doc comments ("A map of +key-value properties attached to the securable."). There is no way for a +caller to know what distinguishes them. The doc duplication is verbatim +in CreateCatalog (199-202) and UpdateCatalog (363-366). Either is +underspecified or one of them is misnamed. + +#### 6.6 `EncryptionSettings.azureEncryptionSettings: AzureEncryptionSettings` (model.ts:259) +A field on `EncryptionSettings` named `azureEncryptionSettings` whose type +is also `AzureEncryptionSettings` reads like a copy-paste error. Drop the +prefix: `azure: AzureEncryptionSettings` is clearer. + +#### 6.7 `executeHttpCall` accepts an `HttpCallOptions` containing an `HttpRequest` (utils.ts:65) — internal, but the function name and its options bag both repeat "HttpCall". + +--- + +### 7. Overly verbose + +#### 7.1 `EffectivePredictiveOptimizationFlag` (model.ts:240) +Identifier is 39 characters. Compounded by the field name +`effectivePredictiveOptimizationFlag` (model.ts:109, 184, 348) used on +three different request/response types. `EffectivePOFlag` or +`EffectivePredictiveOptFlag` is overkill the other way; consider +`EffectivePredictiveOptimization` (no `Flag` since the type already wraps +the flag). + +#### 7.2 `enablePredictiveOptimization: string` (model.ts:83, 158, 322) +Long field name for a single flag value. Acceptable, but tracked because +it pairs with §7.1 to make every `CatalogInfo`-style object verbose. + +#### 7.3 `managedEncryptionSettings` (model.ts:123, 198, 362) +Three-word field name on a securable that already implies "managed". +Consider `encryption` or `encryptionSettings`. + +#### 7.4 `unmarshalEffectivePredictiveOptimizationFlagSchema` / +`marshalEffectivePredictiveOptimizationFlagSchema` (model.ts:486, 634) +Schema exports are 51+ characters. Hard to read, especially in a +generated transform chain. + +#### 7.5 `MANAGED_ONLINE_CATALOG` enum value (model.ts:18) — see §17.1. + +--- + +### 8. Redundant suffixes + +#### 8.1 `…Info` types (`CatalogInfo`, `ConversionInfo`, `ProvisioningInfo`, `DrReplicationInfo`) +"Info" is a non-suffix — it carries no semantic content. In the Go SDK +this distinguishes the entity type from the resource handle; in JS/TS the +convention is to drop it (`Catalog`, `Conversion`, `Provisioning`, +`DrReplication`). + +#### 8.2 `…Settings` repeated (`AzureEncryptionSettings`, `EncryptionSettings`, `azureEncryptionSettings`) — see §6.6. + +#### 8.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` +The whole type *is* the flag; the suffix is redundant. See §7.1. + +#### 8.4 `…Arg` suffix on `nameArg` — see §5.1 and §15.1. + +#### 8.5 `…Schema` suffix on every zod schema export (`unmarshalCatalogInfoSchema`, `marshalCreateCatalogSchema`, etc.) +Defensible (signals it's a zod schema), but verbose when paired with +`unmarshal…`/`marshal…` prefixes. Consider `unmarshalCatalogInfo` / +`marshalCreateCatalog` (the schema-ness is conveyed by the prefix). + +--- + +### 9. Singular / plural mismatches + +#### 9.1 `Client.listCatalogsIter` returns `AsyncGenerator` (client.ts:210) +Method name implies plural results; the generator yields singular items +one at a time. Consistent with neighbouring packages, but worth a sanity +check — `iterCatalogs` (verb-first) reads more naturally for an iterator. + +#### 9.2 `DrReplicationInfo.replicatedEntities` is a single `Uint8Array` — see §1.3, §6.3. + +--- + +### 10. Reserved-word collisions + +#### 10.1 `options` field on `CatalogInfo`, `CreateCatalog`, `UpdateCatalog` (model.ts:127, 202, 366) +`options` collides with the SDK's own `CallOptions` parameter name used +throughout the client (e.g. `createCatalog(req, options)`). The collision +is not a compile error but creates cognitive load — inside +`updateCatalog(req, options)` the reader sees both `req.options` (catalog +metadata) and `options` (call options). Rename one. The least invasive +fix is renaming the second client parameter to `callOptions`. See also +§11.1 for the duplicate-with-`properties` concern. + +#### 10.2 `name` keyword-ish field +`name` is used as a non-path-param body field on `Create*` / `Update*` / +`CatalogInfo`, and also as a path arg via `nameArg`. This isn't a +reserved word but it routinely shadows `Function.prototype.name` and is +a common source of confusion when callers spread request objects. See +also §5.1. + +#### 10.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:242) — generic, frequently shadows local variables. See §1.1. + +--- + +### 11. Duplicate concepts + +#### 11.1 `properties` and `options` (model.ts:124-127, 199-202, 363-366) +Both `Record` on every catalog shape, with identical doc +comments ("A map of key-value properties attached to the securable."). +There is no way for a caller to know which to use for what. Either the +docs need to differentiate them or one is redundant. See also §6.5. + +#### 11.2 `name` vs `fullName` on `CatalogInfo` +`fullName` is documented as "the full name of the catalog. Corresponds +with the name field" (model.ts:115-116). The same data lives in `name` +for catalogs because catalogs are top-level. The duplicate field exists +to satisfy a polymorphic Securable shape — but for the catalog-specific +type, it's redundant. See also §6.4. + +#### 11.3 `name` vs `nameArg` on `UpdateCatalog` +The `UpdateCatalog` request has *both* `nameArg` (the existing catalog +identifier, used in the URL path) and `name` (the new desired name, +used in the body). It also has `newName` for the same concept. See +§15.1 below — three name-like fields on one request shape. + +#### 11.4 `securableType` on `CatalogInfo` (model.ts:117) duplicates the type identity +`CatalogInfo` represents a catalog; its `securableType` field will +always be `SecurableType.CATALOG`. The field exists for polymorphism +across UC types but is meaningless when the surrounding type already +identifies the securable. Not a renaming issue — but worth flagging +as a duplicated concept. + +#### 11.5 `CreateCatalog`, `UpdateCatalog`, and `CatalogInfo` share ~25 fields verbatim +The three types are 95% identical and have largely identical doc strings. +This is a generator artifact, but it bleeds into naming: any rename of +`storageRoot` must happen in three places. Recommend basing +`CreateCatalog`/`UpdateCatalog` on `Partial` or a shared +`CatalogProperties` mixin. + +--- + +### 12. Verb-tense inconsistency + +#### 12.1 Client methods are well-aligned: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`, `listCatalogsIter`. No tense issues. + +#### 12.2 `unmarshal…` / `marshal…` schema-export prefixes are consistent. No issues. + +#### 12.3 `executeCall`, `executeHttpCall` (utils.ts:26, 65) — both imperative present, consistent. + +#### 12.4 `buildHttpRequest`, `parseResponse`, `marshalRequest` (utils.ts:96, 113, 119) — imperative present, consistent. + +#### 12.5 `flattenQueryParams` (utils.ts:123) — imperative, consistent. + +No verb-tense inconsistencies found across the package. + +--- + +### 13. Go / Java-style names + +#### 13.1 `ConversionInfo_State`, `ProvisioningInfo_State` (model.ts:50, 57) +Proto nested-enum naming `Parent_Child`. In TS this should be a +top-level type with a meaningful prefix: `ConversionState`, +`ProvisioningState`. See §4.1-4.2. + +#### 13.2 `Client` class name (client.ts:44) +Bare `Client` (rather than `CatalogsClient`) is a Go-idiom: package +qualifies the type. JS consumers commonly import as +`import {Client} from '@databricks/sdk-catalogs/v1'` and have to alias. +This is a package-wide convention, but worth flagging in this audit +for consistency with the broader review. + +#### 13.3 `nameArg` (model.ts:219, 264, 310) — Go generator naming. See §5.1. + +#### 13.4 `…_Response` suffix is a proto / Go-RPC idiom. See §4.6, §4.7. + +#### 13.5 `…Info` suffix — Java/Go style. See §8.1. + +#### 13.6 `unmarshal…` / `marshal…` (Go's `encoding/json` verbs) +These are direct Go ports. The TS ecosystem typically uses `parse` / +`serialize` or `decode` / `encode`. Defensible because they're internal +to the generated layer, but identifies as Go-style naming. + +--- + +### 14. Generic field names losing meaning + +#### 14.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. + +#### 14.2 `key`, `value` on map-entry wrappers (`*_OptionsEntry`, `*_PropertiesEntry`) — see §1.2. + +#### 14.3 `state` on `ConversionInfo`, `ProvisioningInfo` (model.ts:145, 305) +Whose state? Bound to its container — but if the container is ever +inlined, the field stands alone. See §1.4. + +#### 14.4 `status` on `DrReplicationInfo` (model.ts:229) +Generic in isolation; works in context. Less severe than `state`. + +#### 14.5 `properties`, `options` (model.ts:125, 127, etc.) — see §6.5, §11.1. + +--- + +### 15. Field contradicting type domain + +#### 15.1 `UpdateCatalog` has `nameArg`, `name`, and `newName` (model.ts:310, 312, 314) +Three name-bearing fields on a single update request: +- `nameArg` — existing catalog (path param). +- `newName` — new desired name (body). +- `name` — also "name of catalog" per the inherited doc (model.ts:313). + +A caller staring at this struct cannot intuit which to set. This is the +single most user-hostile naming pattern in the package — and it sits on +the most-used method. + +#### 15.2 `CreateCatalog` contains read-only output fields +`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, +`provisioningInfo`, `conversionInfo`, `drReplicationInfo`, `fullName`, +`securableType`, `effectivePredictiveOptimizationFlag`, `browseOnly` +(model.ts:170-189). These are server-populated; a creator setting them +is at best ignored. The type's domain is "create request", but its +shape contradicts that. Mirror issue in `UpdateCatalog`. + +#### 15.3 `DeleteCatalog.nameArg` — see §5.1. + +#### 15.4 `EncryptionSettings.azureEncryptionSettings` +The outer type's domain is "all encryption settings"; the field is named +as if scoped to Azure. The contradiction (parent claims breadth, child +name claims specificity) is resolved by reading the type definition +but is initially confusing. See §6.6. + +--- + +### 16. Inconsistent action verbs + +Method verbs in `Client`: `createCatalog`, `deleteCatalog`, `getCatalog`, +`listCatalogs`, `updateCatalog`, `listCatalogsIter`. Verbs are +consistent: standard CRUD plus a `…Iter` paginator. No `fetch…` / +`retrieve…` / `read…` outliers. No issues found. + +--- + +### 17. Long enum values + +#### 17.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:18) +22-character enum value. Should be `MANAGED_ONLINE` after dropping the +redundant `_CATALOG` suffix (§2.4). + +#### 17.2 `DrReplicationStatus.DR_REPLICATION_STATUS_SECONDARY` (model.ts:24) +33-character enum value, of which the first 22 are redundant. See §2.1. + +#### 17.3 `ConversionInfo_State.STATE_UNSPECIFIED` (model.ts:51) +17 characters; redundant `STATE_` prefix. See §2.2. + +#### 17.4 `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58) — same. + +--- + +### 18. Underspecified IDs + +#### 18.1 `metastoreId` (model.ts:96, 171, 335) +Documented as "unique identifier of parent metastore". Format opaque +(UUID? slug?). Acceptable but unspecified. + +#### 18.2 `azureTenantId` (model.ts:68) +GUID, implied by Azure context. Doc-less — not specified anywhere. + +#### 18.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) +Doc-less. Format is an Azure resource ID +(`/subscriptions/…/providers/…`), not signalled by the name or +documentation. + +#### 18.4 `customerManagedKeyId` (model.ts:255) +Doc: "the CMK uuid in AWS and GCP, null otherwise." So the field is a +UUID on AWS/GCP but `azureCmkAccessConnectorId` is an Azure resource ID +elsewhere — same conceptual ID, two formats, no unifying name. + +#### 18.5 `azureKeyVaultKeyId` (model.ts:257) +Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See +§6.2. + +#### 18.6 `created_at` / `updated_at` (model.ts:98, 102) +Type is `number` (epoch milliseconds). Conventional, but the field name +doesn't convey unit. Pairs `createdAtMs` or `createdAtEpochMs` would be +more honest. + +#### 18.7 `lastFailoverTimeMs` (model.ts:237) +Counter-example: this field correctly includes the `Ms` unit suffix. +Demonstrates that the codebase *can* express units in names — the other +timestamps simply don't. + +--- + +### 19. Type-suffix tautology + +#### 19.1 `SecurableType` enum with field `securableType: SecurableType` +(model.ts:28, 117, 192, 356) — field name tautological with type name. +Defensible (field carries the dynamic value) but worth flagging. + +#### 19.2 `CatalogType` enum with field `catalogType: CatalogType` +(model.ts:12, 84, 159, 323) — same pattern. + +#### 19.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` +(model.ts:5, 108, 183, 347) — field-name shortened, type-name keeps the +prefix. Reasonable. + +#### 19.4 `DrReplicationStatus` enum with field `status: DrReplicationStatus` +(model.ts:21, 229) — generic field name (`status`) on a typed value. +Either expand the field (`drReplicationStatus`) or shorten the type +(`ReplicationStatus`). + +#### 19.5 `…Info` types with `…info` fields +- `provisioningInfo: ProvisioningInfo` +- `conversionInfo: ConversionInfo` +- `drReplicationInfo: DrReplicationInfo` +- `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` +- `managedEncryptionSettings: EncryptionSettings` (oddly *not* tautological) + +The first four are tautological. Acceptable convention; flagged for +completeness. + +#### 19.6 Schema-export tautology +`unmarshalCatalogInfoSchema: z.ZodType` (model.ts:394) — the +`Schema` suffix duplicates `z.ZodType<…>`. See §8.5. + +--- + +## Additional / cross-cutting observations + +### A. `flattenQueryParams` is defined but unused (utils.ts:123) +Each `listCatalogs` / `getCatalog` / `deleteCatalog` handler builds query +strings inline with `URLSearchParams.append` (client.ts:101-105, +135-139, 175-189). The exported helper `flattenQueryParams` is never +referenced by `client.ts`. Either it's intentionally exported for +consumer use (then it should be documented and reside in `utils` proper) +or it's dead code. + +### B. `nameArg` URL substitution silently allows empty string (client.ts:100, 134, 235) +`${req.nameArg ?? ''}` — if `nameArg` is undefined, the URL silently +becomes `/api/2.1/unity-catalog/catalogs/` and the request will fail on +the server. The naming (`nameArg`) and the substitution behaviour +together hide what should be a required parameter. Worth surfacing via +a non-optional type or a typed assertion. + +### C. `marshalUpdateCatalogSchema` serialises `nameArg`/`newName` into the body (model.ts:703-705) +`nameArg` is a path parameter — but the marshal schema produces a JSON +field `name_arg`. Either the server tolerates the extra field or this +is a bug. The naming choice (`Arg`) lets the bug hide. + +### D. Marshal/unmarshal exports lack proper TS types (model.ts:534, 546, etc.) +`marshalAzureEncryptionSettingsSchema: z.ZodType` (no generic) versus +`unmarshalAzureEncryptionSettingsSchema: z.ZodType` +(with generic). The marshal side is implicitly untyped. Not a naming +issue per se, but inconsistent with the unmarshal naming/typing. + +### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +"Host is required." — bare `Error`. Not a naming issue, flagged in +passing for the broader review. + +### F. `index.ts` re-exports proto-style names verbatim (lines 10, 11, 17, 18, 21, 22, 24, 30, 33, 34) +Every underscore-bearing identifier surfaces in the package's public +API. A consumer of `@databricks/sdk-catalogs/v1` sees +`ConversionInfo_State`, `DeleteCatalog_Response`, +`CatalogInfo_OptionsEntry`, etc. as first-class exports. This is the +single highest-leverage place to clean naming. + +--- + +## File / line index for fast lookup + +| Identifier | Location | Finding | +| ------------------------------------------------------- | ------------------ | ------- | +| `CatalogIsolationMode` | model.ts:5 | 19.3 | +| `CatalogType` | model.ts:12 | 2.4, 17.1, 19.2 | +| `CatalogType.DELTASHARING_CATALOG` | model.ts:14 | 3.4 | +| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:18 | 17.1 | +| `DrReplicationStatus` | model.ts:21 | 2.1, 3.1, 17.2 | +| `SecurableType` | model.ts:28 | 19.1 | +| `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:46 | — | +| `ConversionInfo_State` | model.ts:50 | 2.2, 4.1, 13.1, 17.3 | +| `ProvisioningInfo_State` | model.ts:57 | 2.3, 4.2, 13.1, 17.4 | +| `AzureEncryptionSettings` | model.ts:67 | 3.2, 18.2 | +| `CatalogInfo` | model.ts:73 | 8.1 | +| `CatalogInfo.options` / `.properties` | model.ts:127, 125 | 6.5, 10.1, 11.1, 14.5 | +| `CatalogInfo.fullName` | model.ts:116 | 6.4, 11.2 | +| `CatalogInfo.securableType` | model.ts:117 | 11.4, 19.1 | +| `CatalogInfo_OptionsEntry` | model.ts:131 | 1.2, 4.3 | +| `CatalogInfo_PropertiesEntry` | model.ts:137 | 1.2, 4.3 | +| `ConversionInfo` | model.ts:143 | 1.4, 8.1 | +| `CreateCatalog` | model.ts:148 | 11.5, 15.2 | +| `CreateCatalog_OptionsEntry/PropertiesEntry` | model.ts:206, 212 | 4.4 | +| `DeleteCatalog.nameArg` | model.ts:219 | 5.1, 13.3, 15.3 | +| `DeleteCatalog_Response` | model.ts:225 | 4.6 | +| `DrReplicationInfo` | model.ts:228 | 3.1, 8.1 | +| `DrReplicationInfo.replicatedEntities` | model.ts:231 | 1.3, 6.3, 9.2 | +| `DrReplicationInfo.lastFailoverTimeMs` | model.ts:237 | 18.7 (positive) | +| `EffectivePredictiveOptimizationFlag` | model.ts:240 | 7.1, 7.4, 8.3 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:242 | 1.1, 6.1, 10.3, 14.1 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:244 | 1.5 | +| `EncryptionSettings` | model.ts:253 | 8.2 | +| `EncryptionSettings.customerManagedKeyId` | model.ts:255 | 3.2, 18.4 | +| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:257 | 3.3, 6.2, 18.5 | +| `EncryptionSettings.azureEncryptionSettings` | model.ts:259 | 6.6, 15.4 | +| `GetCatalog.nameArg` | model.ts:264 | 5.1, 13.3 | +| `ListCatalogs.maxResults` | model.ts:281 | — | +| `ListCatalogs.pageToken` | model.ts:283 | — | +| `ListCatalogs.includeUnbound` | model.ts:288 | — | +| `ListCatalogs_Response` | model.ts:292 | 4.7 | +| `ProvisioningInfo` | model.ts:303 | 1.4, 8.1 | +| `UpdateCatalog.nameArg/newName/name` | model.ts:310-314 | 5.1, 11.3, 15.1 | +| `UpdateCatalog_OptionsEntry/PropertiesEntry` | model.ts:370, 376 | 4.5 | +| `unmarshalDeleteCatalog_ResponseSchema` | model.ts:468 | 4.8 | +| `unmarshalListCatalogs_ResponseSchema` | model.ts:515 | 4.8 | +| `Client` (bare name) | client.ts:44 | 13.2 | +| `Client.listCatalogsIter` | client.ts:210 | 9.1 | +| `${req.nameArg ?? ''}` URL substitution | client.ts:100,134,235 | B | +| `flattenQueryParams` (unused export) | utils.ts:123 | A | +| `marshal…` / `unmarshal…` verbs | model.ts (many) | 13.6 | +| `…Schema` suffix | model.ts (many) | 8.5, 19.6 | +| `index.ts` re-exports | index.ts:5-35 | F | + +--- + +## Recommended priority order + +1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalog`** — biggest user-facing trap. (§15.1, §5.1) +2. **Strip `STATE_` / `DR_REPLICATION_STATUS_` / `_CATALOG` redundant prefixes from enum values.** (§2.1, §2.2, §2.3, §2.4) +3. **Drop proto-style `Parent_Child` identifiers** (`ConversionInfo_State`, `DeleteCatalog_Response`, `ListCatalogs_Response`, `*_OptionsEntry`, `*_PropertiesEntry`). (§4) +4. **Distinguish or merge `options` and `properties`.** (§11.1) +5. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§3.3, §6.2) +6. **Strip read-only fields from `CreateCatalog`/`UpdateCatalog`.** (§15.2) +7. **Decide CMK casing and apply uniformly.** (§3.2, §18.4) +8. **Rename `replicatedEntities` to reflect that it's a byte blob.** (§1.3) +9. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md new file mode 100644 index 00000000..6d609c91 --- /dev/null +++ b/.agent/naming-audit/cleanroomassets.md @@ -0,0 +1,722 @@ +# Naming Audit: `@databricks/sdk-cleanroomassets` (v1) + +**Path:** `packages/cleanroomassets/src/v1/` +**Files audited (in full):** `model.ts`, `client.ts`, `utils.ts`, `index.ts` +**Scope:** every exported type, interface, enum, enum value, field, method, and +internal helper symbol. + +Findings are grouped by the 20-issue rubric supplied in the task description. +Each finding lists the symbol, the file/line, the category, the rationale, and +a concrete suggestion. The package belongs to a family of four sibling +cleanroom packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules`, +`cleanroomtaskruns`); cross-package redundancy is called out throughout. + +--- + +## Summary of issue counts (by category) + +| # | Category | Count | +| -- | ----------------------------------------- | ----- | +| 1 | Vague / generic names | 8 | +| 2 | Redundant enum prefixes | 5 | +| 3 | Acronym casing inconsistencies | 0 | +| 4 | Underscores in TS identifiers | 18 | +| 5 | Cryptic abbreviations | 2 | +| 6 | Misleading names | 3 | +| 7 | Overly verbose names | 9 | +| 8 | Redundant suffixes | 3 | +| 9 | Singular / plural mismatches | 2 | +| 10 | Reserved-word / built-in collisions | 1 | +| 11 | Empty / trivial wrapper types | 0 | +| 12 | Duplicate concepts | 4 | +| 13 | Verb-tense inconsistency | 1 | +| 14 | Go / Java-style names | 3 | +| 15 | Generic field names losing meaning | 5 | +| 16 | Field contradicting type domain | 2 | +| 17 | Inconsistent action verbs | 1 | +| 18 | Long enum values | 6 | +| 19 | Underspecified IDs | 2 | +| 20 | Type-suffix tautology | 4 | +| -- | Cross-cutting: `CleanRoom` redundancy | 1 | +| -- | **Total findings** | **80** | + +--- + +## 1. Vague / generic names + +### 1.1 `details` on `CleanRoomAsset` (model.ts:135) + +The field name `details` says nothing — and the type is a discriminated union +across four asset-type sub-shapes. The same struct also has a field named +`localDetails` (line 100) covering a *different* axis (owner-private vs. shared +metadata), so a reader has to memorise the distinction. Suggested rename: +`sharedDetails` (mirror of `localDetails`) or `payload` / +`typeSpecificDetails`. + +### 1.2 `localDetails` on `CleanRoomAsset` (model.ts:100) + +"Local" is jargon for "private to the owner collaborator". A reader of the +public TS surface will not connect *local* to *not-visible-to-other-collaborators*. +Suggested rename: `ownerOnlyDetails` or `privateDetails`. + +### 1.3 `name` on `CleanRoomAsset` (model.ts:90) + +A bare `name` ambiguously identifies a fully qualified asset name — +`..` for UC objects, a notebook +file name otherwise. Compare with `CleanRoomNotebookReview.comment` → +`reviewerCollaboratorAlias` etc., which are specific. Suggested rename: +`assetName` or `fullyQualifiedName`. + +### 1.4 `name` on `ColumnInfo` (model.ts:269) + +The JSDoc just says "Name of Column." Inside a `ColumnInfo` value this is fine, +but when destructured into a wider scope (`const {name} = info`) the meaning +is lost. Suggested rename: `columnName`. + +### 1.5 `name` on `PartitionSpecification_Partition_PartitionValue` (model.ts:436) + +Same problem as 1.4: `name` here means "partition column name", not "partition +name". Suggested rename: `columnName` or `partitionColumn`. + +### 1.6 `value` on `PartitionSpecification_Partition_PartitionValue` (model.ts:441) + +Vague string field that doubles as a sentinel: undefined means `null`. Naming +gives no hint of this contract. Suggested rename: `literalValue` (paired with +`recipientPropertyKey`). + +### 1.7 `details` on `CleanRoomAsset` discriminated union — sub-cases (model.ts:135–168) + +Inside the discriminated union we have keys `table`, `notebook`, `view`, +`foreignTable`. Outside of the union, the same names would mean very different +things (e.g. "this asset *is* a table"). Suggested rename: explicit suffix — +`tableDetails`, `notebookDetails`, etc. — matches the `*LocalDetails` siblings. + +### 1.8 `data` parameter in `marshalRequest` (utils.ts:119) + +`data: unknown` is the canonical anti-pattern. Replace with `value` (Zod's own +naming) or, better, parameterize: `function marshalRequest(value: T, schema: +z.ZodType): string`. + +--- + +## 2. Redundant enum prefixes + +### 2.1 `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` (model.ts:37) + +The enum is called `CleanRoomAsset_AssetType` and the literal is +`ASSET_TYPE_UNSPECIFIED`. The `ASSET_TYPE_` prefix duplicates the enum name. +Suggested rename: `UNSPECIFIED`. + +### 2.2 `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` (model.ts:47) + +The literal `ENUM_UNSPECIFIED` carries the word "ENUM" — meaningless without +the type. The enum name `CleanRoomAsset_Status_Enum` itself has a redundant +`_Enum` suffix (see 8.1). Suggested rename: literal `UNSPECIFIED`. + +### 2.3 `CleanRoomNotebookReview_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (model.ts:55) + +`NOTEBOOK_REVIEW_STATE_` repeats both the parent (`CleanRoomNotebookReview`) and +the suffix (`NotebookReviewState`). Suggested rename: `UNSPECIFIED`. + +### 2.4 `CleanRoomNotebookReview_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (model.ts:63) + +Five words of prefix on a single literal. Suggested rename: `UNSPECIFIED`. + +### 2.5 `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` (model.ts:69) + +Members `EQUAL` / `LIKE` are fine; the enum *name* repeats `Partition` three +times and `PartitionValue` twice (see 7.1). Members themselves are not +redundant. + +--- + +## 3. Acronym casing inconsistencies + +None found. `etag` (lower-case in model.ts:194, 370, 410) is consistently +lower-cased everywhere; `Json` is title-case in `typeJson` (model.ts:282) and +appears nowhere else as `JSON`. `UDF` and `SQL` appear only in JSDoc prose, not +in identifiers. `URL` appears only in helper variable names inside `client.ts` +(`url`, `fullUrl`) and is consistent. + +--- + +## 4. Underscores in TS identifiers + +The proto-style `_` segregator is suppressed with explicit +`@typescript-eslint/naming-convention` exemptions. While this preserves +parity with the Go SDK, every such name is an underscore-in-identifier +violation by TypeScript conventions ([TypeScript Handbook — Names use camelCase +or PascalCase](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html)). +The following identifiers should be reviewed at the porting layer: + +| # | Identifier | File:line | +| ----- | -------------------------------------------------------------------------------- | ------------------ | +| 4.1 | `CleanRoomAsset_AssetType` | model.ts:36 | +| 4.2 | `CleanRoomAsset_Status_Enum` | model.ts:46 | +| 4.3 | `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | +| 4.4 | `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | +| 4.5 | `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | +| 4.6 | `CleanRoomAsset_ForeignTable` | model.ts:172 | +| 4.7 | `CleanRoomAsset_ForeignTableLocalDetails` | model.ts:178 | +| 4.8 | `CleanRoomAsset_Notebook` | model.ts:187 | +| 4.9 | `CleanRoomAsset_Status` | model.ts:211 | +| 4.10 | `CleanRoomAsset_Table` | model.ts:214 | +| 4.11 | `CleanRoomAsset_TableLocalDetails` | model.ts:220 | +| 4.12 | `CleanRoomAsset_View` | model.ts:231 | +| 4.13 | `CleanRoomAsset_ViewLocalDetails` | model.ts:237 | +| 4.14 | `CleanRoomAsset_VolumeLocalDetails` | model.ts:246 | +| 4.15 | `PartitionSpecification_Partition` | model.ts:428 | +| 4.16 | `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | +| 4.17 | All `marshal*_*` / `unmarshal*_*` schema constants (model.ts:551–984, ~20 names) | model.ts (various) | +| 4.18 | All proto `$case` discriminator values use camelCase (good), but underlying serialized fields use `snake_case` (e.g. `clean_room_name`, `notebook_review_state`) — fine for wire format, just calling out the boundary | model.ts:484+ | + +Suggested approach: drop the underscore and concatenate +(`CleanRoomAssetAssetType` → still ugly; `CleanRoomAssetTableLocalDetails` is +acceptable). Alternative: extract nested types under a namespace +(`namespace CleanRoomAsset { export interface Notebook {} }`), eliminating both +the underscore and the parent-name repetition. + +--- + +## 5. Cryptic abbreviations + +### 5.1 `etag` (model.ts:194, 370, 410) + +Acceptable as a wire term but worth knowing it appears in user-facing request +types (`GetCleanRoomAssetRevisionRequest.etag`, line 370). Consider +documenting once via a type alias `type Etag = string` rather than renaming. + +### 5.2 `op` on `PartitionSpecification_Partition_PartitionValue` (model.ts:448) + +`op` is a two-letter cryptic abbreviation. JSDoc says "The operator to apply +for the value." Suggested rename: `operator`. (`op` may collide with mental +shorthand for "operation" too — see also 6.3.) + +--- + +## 6. Misleading names + +### 6.1 `createCleanRoomAssetReview` (client.ts:109) + +The method body POSTs a `notebookReview` (the only `$case` in the union, see +`CreateCleanRoomAssetReviewRequest.review`, model.ts:320). The name suggests a +generic asset-review creator, but the API can only review notebooks today. +Suggested rename (if the API truly only supports one type): +`reviewCleanRoomNotebook` or document the polymorphism more loudly. + +### 6.2 `assetType` on `CreateCleanRoomAssetReviewRequest` (model.ts:319) + +JSDoc says "Can either be NOTEBOOK_FILE or JAR_ANALYSIS", but `JAR_ANALYSIS` +does not exist in `CleanRoomAsset_AssetType` (only `TABLE`, `NOTEBOOK_FILE`, +`VOLUME`, `VIEW`, `FOREIGN_TABLE`; see model.ts:38–42). The doc misleads +readers about what values are valid. + +### 6.3 `op` (model.ts:448) + +Beyond cryptic (5.2), `op` is also misleading because the enum currently has +only `EQUAL` / `LIKE` — those are not arithmetic *operators* but partition +*match operators*. Suggested: `matchOp` or `matcher`. + +--- + +## 7. Overly verbose names + +### 7.1 `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` (model.ts:69) + +47-character enum name with `Partition`/`PartitionValue` repeated. Suggested +rename: `PartitionMatchOperator`. In a flattened namespace, the parent context +adds no value here. + +### 7.2 `unmarshalPartitionSpecification_Partition_PartitionValueSchema` (model.ts:780) + +Schema variable name reaching 62 characters. Combined with the chained Zod +calls it dominates a screen. + +### 7.3 `marshalPartitionSpecification_Partition_PartitionValueSchema` (model.ts:1099) + +Same critique as 7.2. + +### 7.4 `unmarshalCleanRoomAsset_ForeignTableLocalDetailsSchema` (model.ts:561) + +55 characters; the `ForeignTable` qualifier could vanish if nested under +`CleanRoomAsset`. See also `unmarshalCleanRoomAsset_TableLocalDetailsSchema` +(607), `unmarshalCleanRoomAsset_ViewLocalDetailsSchema` (631), +`unmarshalCleanRoomAsset_VolumeLocalDetailsSchema` (641), +`unmarshalCleanRoomAsset_NotebookSchema` (571). Five sibling offenders. + +### 7.5 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator key (model.ts:330) + +The discriminated-union variant name *and* the inner property name are both +`notebookReviewState`. Redundancy of `notebookReviewState` against the parent +`reviewState` field could be elided. Suggested: `{$case: 'notebook', state: +NotebookReviewState}`. + +### 7.6 `runnerCollaboratorAliases` (model.ts:196) + +Long composite, but accurate. Acceptable. + +### 7.7 `reviewerCollaboratorAlias` (model.ts:256) + +Same. Acceptable. + +### 7.8 `ownerCollaboratorAlias` (model.ts:98) + +Same. Acceptable. + +### 7.9 `recipientPropertyKey` (model.ts:446) + +Acceptable; needs the `recipient`/`property`/`key` qualifiers for accuracy. + +(7.6–7.9 are kept under this category for completeness, but only flagged as +borderline — none should change.) + +--- + +## 8. Redundant suffixes + +### 8.1 `CleanRoomAsset_Status_Enum` (model.ts:46) + +The `_Enum` suffix is a Go-protobuf habit. The bare name `CleanRoomAsset_Status` +would be more idiomatic on the TS surface. + +### 8.2 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) + +`NotebookReview` is repeated immediately after the underscore. Suggested +rename: `CleanRoomNotebookReview_State`. + +### 8.3 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) + +Same redundancy. Suggested: `CleanRoomNotebookReview_SubReason`. + +--- + +## 9. Singular / plural mismatches + +### 9.1 `revisions` on `ListCleanRoomAssetRevisionsResponse` (model.ts:387) + +The field is typed `CleanRoomAsset[]` — the elements are *assets*, not +revisions. The list endpoint returns asset *snapshots at different revisions*, +but the type is plain `CleanRoomAsset`. Either the field should be `assets` +(matching `ListCleanRoomAssetsResponse.assets`, line 400) or a dedicated +`CleanRoomAssetRevision` type should exist. + +### 9.2 `listCleanRoomAssetRevisions` returning `revisions: CleanRoomAsset[]` (client.ts:255–270) + +The iterator `listCleanRoomAssetRevisionsIter` yields `CleanRoomAsset` — same +mismatch as 9.1. Suggested either rename method to `listCleanRoomAsset` (which +collides with `getCleanRoomAsset`'s revision case) or introduce a wrapper +type. + +--- + +## 10. Reserved-word / built-in collisions + +### 10.1 `op` (model.ts:448) + +Not reserved, but commonly shadows local helpers and is unsearchable. + +--- + +## 11. Empty / trivial wrapper types + +_None._ + +--- + +## 12. Duplicate concepts + +### 12.1 `cleanRoomName` appears in every request type + +Fields `cleanRoomName` are present on: `CreateCleanRoomAssetReviewRequest` +(315), `DeleteCleanRoomAssetRequest` (339), `GetCleanRoomAssetRequest` (355), +`GetCleanRoomAssetRevisionRequest` (364), `ListCleanRoomAssetRevisionsRequest` +(375), `ListCleanRoomAssetsRequest` (393), `UpdateCleanRoomAssetRequest` +(474). Same concept, copied seven times. Not avoidable for codegen, but a +shared `interface CleanRoomScoped { cleanRoomName?: string; }` could +deduplicate. + +### 12.2 `assetType` appears in every Create/Get/Delete/Review request + +Same critique as 12.1. + +### 12.3 `name` (the asset name) appears as both URL path component and as a +duplicated string field on `Delete/Get/GetRevision/ListRevisions/Review` +requests — every request that targets a specific asset re-declares it. + +### 12.4 Both `localDetails` and `details` are discriminated unions over the same +asset-type axis (`tableLocalDetails`/`volumeLocalDetails`/`viewLocalDetails`/ +`foreignTableLocalDetails` vs. `table`/`notebook`/`view`/`foreignTable`). +The `notebook` variant exists only on `details` (notebooks have no local +half). The asymmetry will confuse readers. Suggested: split into two clear +structs (`OwnerOnlyDetails`, `SharedDetails`) so the parallel-but-asymmetric +shape is documented in types, not only prose. + +--- + +## 13. Verb-tense inconsistency + +### 13.1 `addedAt` vs. `createdAtMillis` (model.ts:94 / 258) + +Two timestamp fields on related types: `addedAt` (past participle, no unit +suffix; comment says "in epoch milliseconds") and `createdAtMillis` (past +participle, explicit `Millis` suffix). Same concept, different surface. +Suggested: pick one — either both bare names with comment-documented units, +or both `*AtMillis`. + +--- + +## 14. Go / Java-style names + +### 14.1 `marshalCleanRoomAssetSchema` / `unmarshalCleanRoomAssetSchema` (model.ts:482, 812, plus ~20 siblings) + +`marshal` / `unmarshal` are Go's `encoding/json` vocabulary. TypeScript / +JavaScript convention is `serialize`/`deserialize`, `encode`/`decode`, or with +Zod simply `*Schema` / `*OutputSchema`. The generated TS surface re-exports +these helpers, so consumers see "unmarshal" in autocomplete — un-idiomatic. + +### 14.2 Snake-case wire keys in the schema bodies (`clean_room_name`, +`asset_type`, etc., model.ts:484–488 and elsewhere) — necessary for wire +format, but they appear next to camelCase TS properties in the same +`.transform(...)` call. The schema-level inputs intentionally look like Go +field tags. Acceptable; flagging it for readers to know. + +### 14.3 `Call` / `Options` types and `executeCall` (utils.ts:26) borrowed +verbatim from the Go SDK's `transport/call.go` style. The TS equivalent +would be `RequestFn` / `RequestOptions` / `runRequest`. Low-priority. + +--- + +## 15. Generic field names losing meaning + +### 15.1 `name` (asset-name) in `CleanRoomAsset` (model.ts:90) — see 1.3. + +### 15.2 `name` (column-name) in `ColumnInfo` (model.ts:269) — see 1.4. + +### 15.3 `name` (partition-column-name) on partition value (model.ts:436) — see 1.5. + +### 15.4 `value` on partition value (model.ts:441) — see 1.6. + +### 15.5 `comment` appears on `ColumnInfo` (284), `CleanRoomNotebookReview` +(262), and `NotebookVersionReview` (414). Same word, three meanings: +column-level documentation, reviewer comment, review-submission comment. +Acceptable in context but a reader scanning a flat shape can mix them up. + +--- + +## 16. Field contradicting type domain + +### 16.1 `ColumnTypeName.TABLE_TYPE` and `ColumnTypeName.TABLEREF_TYPE` (model.ts:31–32) + +`ColumnTypeName` is supposed to enumerate primitive / collection column types +(`BOOLEAN`, `INT`, `STRING`, `ARRAY`…). Having `TABLE_TYPE` / `TABLEREF_TYPE` +inside that enum is conceptually mixed: columns aren't tables. Whatever the +Unity Catalog model dictates here, the names contradict the enum's apparent +domain. At minimum: rename the enum to `ColumnTypeOrTableTypeName`, or move +those two values to a dedicated enum. + +### 16.2 `assetType` on `CreateCleanRoomAssetReviewRequest.assetType` +(model.ts:319) — typed `CleanRoomAsset_AssetType`, but the JSDoc allows +`JAR_ANALYSIS`, which is not in the enum. The field type *contradicts the +documented contract*. See also 6.2. + +--- + +## 17. Inconsistent action verbs + +### 17.1 `createCleanRoomAssetReview` (client.ts:109) vs. the rest + +The CRUD methods are `create*`, `get*`, `delete*`, `update*`, `list*`. The +*review submission* uses `create*`, while a sibling concept would be +`submit*`. This is a single inconsistency — most teams accept "create" as +the noun-builder. Suggested: rename to `submitCleanRoomAssetReview` to match +domain language ("submit review") in the JSDoc on line 108. + +--- + +## 18. Long enum values + +### 18.1 `NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (model.ts:55) — see 2.3. + +### 18.2 `NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (model.ts:63) — see 2.4. + +### 18.3 `ASSET_TYPE_UNSPECIFIED` (model.ts:37) — see 2.1. + +### 18.4 `ENUM_UNSPECIFIED` (model.ts:47) — see 2.2. + +### 18.5 `USER_DEFINED_TYPE` (model.ts:24) — long but accurate; arguably +`USER_DEFINED` suffices. + +### 18.6 `TIMESTAMP_NTZ` (model.ts:25) — acceptable (Databricks-specific). + +--- + +## 19. Underspecified IDs + +### 19.1 `etag` (model.ts:194, 370, 410, 575…) + +`etag` *is* an identifier (revision ID) here, but the name doesn't tell a +casual reader that supplying it pins a specific notebook revision. The JSDoc +on `GetCleanRoomAssetRevisionRequest.etag` (369) says "Revision etag to +fetch." Suggested rename: `revisionEtag` or `revisionId`. + +### 19.2 `name` used as a primary key for assets + +Several requests (`GetCleanRoomAssetRequest.name`, line 359; +`DeleteCleanRoomAssetRequest.name`, line 343) use `name` as the identifier. +The JSDoc has to spell out "it is same as the name field in CleanRoomAsset." +Suggested rename: `assetName` everywhere — eliminates the cross-reference. + +--- + +## 20. Type-suffix tautology + +### 20.1 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) + +Enum *name* contains the type-suffix `State` while the parent already conveys +that this is the *state* of a notebook review. See 8.2. + +### 20.2 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) + +Same — `SubReason` is suffix-tautology with the parent's `Review`. + +### 20.3 `CleanRoomAsset_Status_Enum` (model.ts:46) + +`_Enum` suffix is tautological with the keyword `enum`. See 8.1. + +### 20.4 `ColumnTypeName` (model.ts:5) + +`TypeName` is *almost* tautology with `Column`; a column's type-name is just +its *type*. Suggested rename: `ColumnType`. + +--- + +## Cross-cutting: `CleanRoom` redundancy across four sibling packages + +The package is already named `cleanroomassets`. Every public type starts with +`CleanRoom*` (`CleanRoomAsset`, `CleanRoomNotebookReview`, etc.). Re-export of +`Client` happens via `import {Client} from '@databricks/sdk-cleanroomassets'` +— at the call site the prefix on type names is redundant: + +```ts +import {Client, CleanRoomAsset} from '@databricks/sdk-cleanroomassets'; +// vs. the cleaner: +import {Client, Asset} from '@databricks/sdk-cleanroomassets'; +``` + +Sibling packages would do the same — `cleanrooms#CleanRoom`, +`cleanroomtaskruns#CleanRoomTaskRun`, etc. — and the `CleanRoom` namespace +collapses naturally into the *package* boundary. + +Affected exports (all in `model.ts` and re-exported by `index.ts`): + +- `CleanRoomAsset` → `Asset` +- `CleanRoomAsset_AssetType` → `AssetType` (which is itself redundant; see 8/20) +- `CleanRoomAsset_Status` / `_Status_Enum` → `Status` / `StatusEnum` +- `CleanRoomAsset_ForeignTable` / `_ForeignTableLocalDetails` → `ForeignTable` / + `ForeignTableLocalDetails` +- `CleanRoomAsset_Notebook` → `Notebook` +- `CleanRoomAsset_Table` / `_TableLocalDetails` → `Table` / `TableLocalDetails` +- `CleanRoomAsset_View` / `_ViewLocalDetails` → `View` / `ViewLocalDetails` +- `CleanRoomAsset_VolumeLocalDetails` → `VolumeLocalDetails` +- `CleanRoomNotebookReview` → `NotebookReview` +- `CleanRoomNotebookReview_NotebookReviewState` → `NotebookReview.State` +- `CleanRoomNotebookReview_NotebookReviewSubReason` → `NotebookReview.SubReason` +- `CreateCleanRoomAssetRequest` → `CreateAssetRequest` (or just `CreateRequest`) +- `CreateCleanRoomAssetReviewRequest` / `Response` → `CreateAssetReviewRequest` +- `DeleteCleanRoomAssetRequest` / `Response` → `DeleteAssetRequest` +- `GetCleanRoomAssetRequest` → `GetAssetRequest` +- `GetCleanRoomAssetRevisionRequest` → `GetAssetRevisionRequest` +- `ListCleanRoomAssetRevisionsRequest` / `Response` → `ListAssetRevisionsRequest` +- `ListCleanRoomAssetsRequest` / `Response` → `ListAssetsRequest` +- `UpdateCleanRoomAssetRequest` → `UpdateAssetRequest` + +The client methods inherit the same redundancy: `client.createCleanRoomAsset(...)` +inside `@databricks/sdk-cleanroomassets` would become `client.createAsset(...)` +— matching how `@databricks/sdk-jobs` would expose `client.createJob(...)`. + +If the codegen template can't drop the prefix everywhere uniformly, the +*per-package* re-export in `index.ts` is the natural place to alias. + +--- + +## Appendix — per-symbol notes (exhaustive checklist) + +### Enums + +| Symbol | File:line | Issues | +| ------ | --------- | ------ | +| `ColumnTypeName` | model.ts:5 | 20.4 (TypeName tautology), 16.1 (`TABLE_TYPE` / `TABLEREF_TYPE` contradict domain) | +| `ColumnTypeName.BOOLEAN`..`GEOGRAPHY` | model.ts:6–28 | clean | +| `ColumnTypeName.TABLE_TYPE` | model.ts:31 | 16.1 | +| `ColumnTypeName.TABLEREF_TYPE` | model.ts:32 | 16.1, also redundant `_TYPE` suffix on a value inside `ColumnTypeName` | +| `CleanRoomAsset_AssetType` | model.ts:36 | 4.1, 20.x cross-cutting `CleanRoom` | +| `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` | model.ts:37 | 2.1, 18.3 | +| `CleanRoomAsset_AssetType.TABLE`..`FOREIGN_TABLE` | model.ts:38–42 | clean | +| `CleanRoomAsset_Status_Enum` | model.ts:46 | 8.1, 20.3, cross-cutting | +| `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` | model.ts:47 | 2.2, 18.4 | +| `CleanRoomAsset_Status_Enum.ACTIVE`/`PERMISSION_DENIED`/`PENDING` | model.ts:48–50 | clean | +| `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | 8.2, 20.1, cross-cutting | +| `…_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` | model.ts:55 | 2.3, 18.1 | +| `…_NotebookReviewState.APPROVED`/`REJECTED`/`PENDING` | model.ts:56–58 | clean | +| `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | 8.3, 20.2, cross-cutting | +| `…_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` | model.ts:63 | 2.4, 18.2 | +| `…_NotebookReviewSubReason.BACKFILLED`/`AUTO_APPROVED` | model.ts:64–65 | clean | +| `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | 7.1 | +| `…_PartitionValueOp.EQUAL`/`LIKE` | model.ts:70–71 | clean | + +### Interfaces + +| Symbol | File:line | Issues | +| ------ | --------- | ------ | +| `CleanRoomAsset` | model.ts:75 | cross-cutting | +| `CleanRoomAsset.cleanRoomName` | model.ts:80 | cross-cutting (always present, see 12.1) | +| `CleanRoomAsset.name` | model.ts:90 | 1.3, 15.1, 19.2 | +| `CleanRoomAsset.assetType` | model.ts:92 | clean (but see 12.2) | +| `CleanRoomAsset.addedAt` | model.ts:94 | 13.1 | +| `CleanRoomAsset.status` | model.ts:96 | typed `CleanRoomAsset_Status_Enum` — naming carries over (8.1) | +| `CleanRoomAsset.ownerCollaboratorAlias` | model.ts:98 | clean | +| `CleanRoomAsset.localDetails` | model.ts:100 | 1.2, 12.4 | +| `CleanRoomAsset.details` | model.ts:135 | 1.1, 1.7, 12.4 | +| `CleanRoomAsset_ForeignTable` | model.ts:172 | cross-cutting | +| `CleanRoomAsset_ForeignTable.columns` | model.ts:174 | clean | +| `CleanRoomAsset_ForeignTableLocalDetails.localName` | model.ts:183 | clean (would be `ownerLocalName` to match `localDetails` semantics) | +| `CleanRoomAsset_Notebook.notebookContent` | model.ts:192 | redundant `notebook` prefix inside `…_Notebook` — `content` suffices | +| `CleanRoomAsset_Notebook.etag` | model.ts:194 | 19.1 | +| `CleanRoomAsset_Notebook.runnerCollaboratorAliases` | model.ts:196 | clean (verbose 7.6, acceptable) | +| `CleanRoomAsset_Notebook.reviews` | model.ts:198 | clean | +| `CleanRoomAsset_Notebook.reviewState` | model.ts:200 | clean | +| `CleanRoomAsset_Notebook.description` | model.ts:202 | clean | +| `CleanRoomAsset_Notebook.environmentVersion` | model.ts:207 | clean (typed as string but holds version numerals — minor) | +| `CleanRoomAsset_Table.columns` | model.ts:216 | clean | +| `CleanRoomAsset_TableLocalDetails.localName` | model.ts:225 | clean | +| `CleanRoomAsset_TableLocalDetails.partitions` | model.ts:227 | clean | +| `CleanRoomAsset_View.columns` | model.ts:233 | clean | +| `CleanRoomAsset_ViewLocalDetails.localName` | model.ts:242 | clean | +| `CleanRoomAsset_VolumeLocalDetails.localName` | model.ts:251 | clean | +| `CleanRoomNotebookReview` | model.ts:254 | cross-cutting | +| `CleanRoomNotebookReview.reviewerCollaboratorAlias` | model.ts:256 | clean (verbose 7.7) | +| `CleanRoomNotebookReview.createdAtMillis` | model.ts:258 | 13.1 | +| `CleanRoomNotebookReview.reviewState` | model.ts:260 | clean | +| `CleanRoomNotebookReview.comment` | model.ts:262 | 15.5 | +| `CleanRoomNotebookReview.reviewSubReason` | model.ts:264 | clean | +| `ColumnInfo` | model.ts:267 | clean | +| `ColumnInfo.name` | model.ts:269 | 1.4, 15.2 | +| `ColumnInfo.typeText` | model.ts:271 | clean | +| `ColumnInfo.typeName` | model.ts:272 | 20.4 (carries from enum) | +| `ColumnInfo.position` | model.ts:274 | clean | +| `ColumnInfo.typePrecision` | model.ts:276 | clean | +| `ColumnInfo.typeScale` | model.ts:278 | clean | +| `ColumnInfo.typeIntervalType` | model.ts:280 | "typeIntervalType" is awkward — `intervalType` would suffice; the `type` prefix is misleading since `typeName` is the actual type | +| `ColumnInfo.typeJson` | model.ts:282 | clean (lowercase `Json` consistent) | +| `ColumnInfo.comment` | model.ts:284 | 15.5 | +| `ColumnInfo.nullable` | model.ts:286 | clean | +| `ColumnInfo.partitionIndex` | model.ts:288 | clean | +| `ColumnInfo.mask` | model.ts:289 | "mask" loses meaning out of context — `columnMask` is clearer (matches type name) | +| `ColumnMask` | model.ts:292 | clean | +| `ColumnMask.functionName` | model.ts:294 | clean | +| `ColumnMask.usingColumnNames` | model.ts:300 | snake-cased gerund "using" feels Pythonic; `additionalColumnNames` or `extraColumnNames` is more TS-idiomatic. Also JSDoc says this field is deprecated. | +| `ColumnMask.usingArguments` | model.ts:306 | same critique; JSDoc says it replaces `using_column_names` — naming has not been updated to reflect the new semantics | +| `CreateCleanRoomAssetRequest` | model.ts:309 | cross-cutting | +| `CreateCleanRoomAssetRequest.asset` | model.ts:310 | clean — `asset` is a fine name here (single-field request) | +| `CreateCleanRoomAssetReviewRequest` | model.ts:313 | cross-cutting | +| `…ReviewRequest.cleanRoomName` | model.ts:315 | 12.1 | +| `…ReviewRequest.name` | model.ts:317 | 1.3, 19.2 | +| `…ReviewRequest.assetType` | model.ts:319 | 6.2, 16.2 | +| `…ReviewRequest.review` | model.ts:320 | discriminated union with one variant (`notebookReview`); see 6.1 | +| `CreateCleanRoomAssetReviewResponse` | model.ts:325 | cross-cutting | +| `…ReviewResponse.notebookReviews` | model.ts:327 | clean | +| `…ReviewResponse.reviewState` | model.ts:328 | discriminated union with one variant (`notebookReviewState`); see 7.5 | +| `DeleteCleanRoomAssetRequest` | model.ts:337 | cross-cutting | +| `…DeleteRequest.cleanRoomName`/`assetType`/`name` | model.ts:339–343 | 12.x, 19.2 | +| `GetCleanRoomAssetRequest` / `…RevisionRequest` | model.ts:353, 362 | cross-cutting | +| `…Request.cleanRoomName`/`name`/`assetType`/`etag` | various | 12.x, 19.1, 19.2 | +| `ListCleanRoomAssetRevisionsRequest` | model.ts:373 | 9.x | +| `…Request.pageSize` / `.pageToken` | model.ts:381–383 | clean | +| `ListCleanRoomAssetRevisionsResponse.revisions` | model.ts:387 | 9.1 | +| `ListCleanRoomAssetRevisionsResponse.nextPageToken` | model.ts:388 | clean | +| `ListCleanRoomAssetsRequest.cleanRoomName` / `.pageToken` | model.ts:393–395 | 12.1 | +| `ListCleanRoomAssetsResponse.assets` / `.nextPageToken` | model.ts:400–405 | clean | +| `NotebookVersionReview` | model.ts:408 | name reads like a noun-from-Go (Java-style); `NotebookReviewSubmission` or `PendingReview` would feel more native. Single-use in `CreateCleanRoomAssetReviewRequest.review.notebookReview` | +| `NotebookVersionReview.etag`/`reviewState`/`comment` | model.ts:410–414 | 19.1, 15.5 | +| `PartitionSpecification_Partition.values` | model.ts:430 | clean | +| `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | 4.x, 7.1 | +| `…PartitionValue.name` | model.ts:436 | 1.5, 15.3 | +| `…PartitionValue.value` | model.ts:441 | 1.6, 15.4 | +| `…PartitionValue.recipientPropertyKey` | model.ts:446 | clean (verbose 7.9) | +| `…PartitionValue.op` | model.ts:448 | 5.2, 6.3, 10.1 | +| `PolicyFunctionArgument` | model.ts:457 | name "Argument" inside `PolicyFunction*` could be `PolicyFunctionArg` to align with field name `arg` (line 458) — currently inconsistent | +| `PolicyFunctionArgument.arg` | model.ts:458 | abbreviation `arg` vs. parent `Argument`; pick one | +| `UpdateCleanRoomAssetRequest.cleanRoomName` / `.asset` | model.ts:474–479 | 12.x | + +### Schemas (model.ts:482 onward) + +All `marshal*Schema` / `unmarshal*Schema` constants inherit the issues of +their wrapped type (cross-cutting CleanRoom redundancy, `_` underscores, +verbose names — see 4.x and 7.x). Additionally: + +- The schemas use `clean_room_name` / `notebook_review_state` etc. as wire + names — that's the protocol layer and not a TS naming concern. + +### `client.ts` + +| Symbol | File:line | Issues | +| ------ | --------- | ------ | +| `PACKAGE_SEGMENT` | client.ts:46 | clean | +| `class Client` | client.ts:51 | "Client" is generic but matches sibling packages — acceptable per the per-package re-export convention | +| `Client.host` / `httpClient` / `logger` / `userAgent` | client.ts:52–58 | clean | +| `constructor(options: ClientOptions)` | client.ts:60 | clean | +| `createCleanRoomAsset` | client.ts:83 | cross-cutting redundancy (`createAsset` would suffice in `cleanroomassets`) | +| `createCleanRoomAssetReview` | client.ts:109 | 6.1, 17.1 | +| `deleteCleanRoomAsset` | client.ts:141 | cross-cutting | +| `getCleanRoomAsset` | client.ts:169 | cross-cutting | +| `getCleanRoomAssetRevision` | client.ts:194 | cross-cutting | +| `listCleanRoomAssetRevisions` / `…Iter` | client.ts:219, 255 | 9.2, cross-cutting | +| `listCleanRoomAssets` / `…Iter` | client.ts:273, 306 | cross-cutting | +| `updateCleanRoomAsset` | client.ts:327 | cross-cutting | +| local helpers `call`, `httpReq`, `respBody`, `resp`, `url`, `fullUrl`, `params`, `query`, `headers`, `pageReq`, `item` | client.ts (various) | clean (short-scoped) | + +### `utils.ts` + +| Symbol | File:line | Issues | +| ------ | --------- | ------ | +| `interface HttpCallOptions` | utils.ts:15 | clean | +| `HttpCallOptions.request` / `httpClient` / `logger` | utils.ts:16–18 | clean | +| `function executeCall(call, options?)` | utils.ts:26 | 14.3 (Go-style `executeCall`/`Call`/`Options`) | +| local `opts` | utils.ts:30 | clean | +| `function readAll(body)` | utils.ts:40 | clean | +| local `reader`, `chunks`, `done`, `value`, `totalLength`, `result`, `offset`, `chunk` | utils.ts (various) | clean | +| `function executeHttpCall(opts)` | utils.ts:65 | 14.3 | +| local `resp`, `body`, `apiErr` | utils.ts:73–88 | `apiErr` is the only abbreviation; matches the rest of the SDK | +| `function buildHttpRequest(method, url, headers, signal?, body?)` | utils.ts:96 | clean | +| local `req` | utils.ts:103 | clean | +| `function parseResponse(body, schema)` | utils.ts:113 | clean — though pairs awkwardly with `marshalRequest`/`unmarshal*Schema` vocabulary (14.1) | +| `function marshalRequest(data, schema)` | utils.ts:119 | 1.8, 14.1 | +| `function flattenQueryParams(prefix, value, params)` | utils.ts:123 | clean — but the function is exported and unused in `client.ts` (no caller in this package). Dead code / dead export. | + +### `index.ts` + +Re-exports only. All concerns flow from `model.ts` / `client.ts`. + +--- + +## Top-priority recommendations (in order) + +1. **Decide on cleanroom-prefix policy across all four packages.** Either + strip `CleanRoom` from type names entirely (per-package re-export aliases), + or keep it in the canonical `model.ts` and provide unprefixed aliases in + `index.ts`. Pick one. (Cross-cutting redundancy is the single biggest + source of name length.) +2. **Collapse proto-nested types under namespaces or rename without + underscores.** All 18 `_`-bearing identifiers should follow the same + convention as the rest of `@databricks/sdk-databricks`. +3. **Reconcile the `revisions: CleanRoomAsset[]` mismatch on + `ListCleanRoomAssetRevisionsResponse`.** Either rename to `assets` or + introduce a distinct revision type. +4. **Fix the `JAR_ANALYSIS` / `assetType` JSDoc discrepancy.** Either the + enum is missing a value or the doc is stale. +5. **Strip the `_UNSPECIFIED` boilerplate prefixes** (`NOTEBOOK_REVIEW_STATE_…` + etc.) — six enum literals become two-word strings. +6. **Rename `op` → `operator` and `etag` → `revisionEtag`** in user-facing + request types. +7. **Replace `marshal`/`unmarshal` with `encode`/`decode`** at the SDK + surface to align with JS idiom (Go vocabulary leak). diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md new file mode 100644 index 00000000..435e7057 --- /dev/null +++ b/.agent/naming-audit/cleanroomautoapprovalrules.md @@ -0,0 +1,360 @@ +# Naming Audit: `@databricks/sdk-cleanroomautoapprovalrules` (`v1`) + +Path: `/home/parth.bansal/sdk-js/packages/cleanroomautoapprovalrules/` +Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts`. + +## Inventory + +### Enums + +| Name | Members | +| ---- | ------- | +| `CleanRoomAutoApprovalRule_AuthorScope` | `AUTHOR_SCOPE_UNSPECIFIED`, `ANY_AUTHOR` | + +### Interfaces (data model) + +- `CleanRoomAutoApprovalRule` + - `cleanRoomName?: string` + - `ruleId?: string` + - `ruleOwnerCollaboratorAlias?: string` + - `authors?` — discriminated union with `$case` of + `'authorCollaboratorAlias'` (`authorCollaboratorAlias: string`) or + `'authorScope'` (`authorScope: CleanRoomAutoApprovalRule_AuthorScope`) + - `runners?` — discriminated union with `$case` of + `'runnerCollaboratorAlias'` (`runnerCollaboratorAlias: string`) + - `createdAt?: number` + +### Interfaces (requests/responses) + +- `CreateCleanRoomAutoApprovalRuleRequest` (`autoApprovalRule?: + CleanRoomAutoApprovalRule`) +- `DeleteCleanRoomAutoApprovalRuleRequest` (`cleanRoomName?: string`, + `ruleId?: string`) +- `GetCleanRoomAutoApprovalRuleRequest` (`cleanRoomName?: string`, + `ruleId?: string`) +- `ListCleanRoomAutoApprovalRulesRequest` (`cleanRoomName?: string`, + `pageSize?: number`, `pageToken?: string`) +- `ListCleanRoomAutoApprovalRulesResponse` (`rules?: + CleanRoomAutoApprovalRule[]`, `nextPageToken?: string`) +- `UpdateCleanRoomAutoApprovalRuleRequest` (`autoApprovalRule?: + CleanRoomAutoApprovalRule`) + +### Schemas / marshalling helpers (exported from `model.ts`) + +- `unmarshalCleanRoomAutoApprovalRuleSchema` +- `unmarshalListCleanRoomAutoApprovalRulesResponseSchema` +- `marshalCleanRoomAutoApprovalRuleSchema` +- `marshalCreateCleanRoomAutoApprovalRuleRequestSchema` + +### `client.ts` + +- `class Client` + - `host`, `httpClient`, `logger`, `userAgent` (private fields) + - `createCleanRoomAutoApprovalRule` + - `deleteCleanRoomAutoApprovalRule` + - `getCleanRoomAutoApprovalRule` + - `listCleanRoomAutoApprovalRules` + - `listCleanRoomAutoApprovalRulesIter` + - `updateCleanRoomAutoApprovalRule` + +### `utils.ts` + +- `interface HttpCallOptions` +- `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`, internal `readAll` + +### `index.ts` + +Re-exports `Client`, `CleanRoomAutoApprovalRule_AuthorScope`, and the +request/response/model types. + +--- + +## Findings + +The package name itself (`cleanroomautoapprovalrules`) is already long. The +following findings examine whether the inside of the package further redoubles +the `CleanRoom` / `AutoApproval` prefixes against the surface that consumers +actually see when calling `new Client(...)` and method/type names. + +### 1. Redundant `CleanRoom*` prefix on every exported type — Category 7 (overly verbose) / Category 14 (Go/Java-style names) + +Every interface in this package starts with `CleanRoom` or +`CleanRoomAutoApproval`. In Go, this is conventional because every type +shares a flat package namespace. In TypeScript these symbols are already +inside `@databricks/sdk-cleanroomautoapprovalrules/v1`; consumers always +disambiguate via the import path or a namespace import. + +Affected symbols: + +- `CleanRoomAutoApprovalRule` → could be `AutoApprovalRule` (or just `Rule`). +- `CreateCleanRoomAutoApprovalRuleRequest` → `CreateRuleRequest`. +- `DeleteCleanRoomAutoApprovalRuleRequest` → `DeleteRuleRequest`. +- `GetCleanRoomAutoApprovalRuleRequest` → `GetRuleRequest`. +- `ListCleanRoomAutoApprovalRulesRequest` → `ListRulesRequest`. +- `ListCleanRoomAutoApprovalRulesResponse` → `ListRulesResponse`. +- `UpdateCleanRoomAutoApprovalRuleRequest` → `UpdateRuleRequest`. + +A representative consumer call today reads: + +```typescript +import * as approvals from '@databricks/sdk-cleanroomautoapprovalrules/v1'; +const req: approvals.CreateCleanRoomAutoApprovalRuleRequest = { ... }; +await client.createCleanRoomAutoApprovalRule(req); +``` + +The string `CleanRoomAutoApproval` appears three times for a single call. +The package name already carries that information. + +### 2. Client methods restate the package name — Category 7 (overly verbose) / Category 14 (Go-style names) + +All six `Client` methods repeat `CleanRoomAutoApprovalRule(s)`: + +- `createCleanRoomAutoApprovalRule` +- `deleteCleanRoomAutoApprovalRule` +- `getCleanRoomAutoApprovalRule` +- `listCleanRoomAutoApprovalRules` +- `listCleanRoomAutoApprovalRulesIter` +- `updateCleanRoomAutoApprovalRule` + +Inside `new Client(...)` from this package, the resource is implied; the +shorter `create`, `get`, `list`, `listIter`, `update`, `delete` (or +`createRule`, `getRule`, etc.) communicate the same information without the +21-character prefix. This is the same pattern used by other JS SDKs (e.g., +the AWS JS SDK v3 uses `Send` of a single-purpose command rather than a +verbose method name). + +### 3. Enum name doubles up on its parent type — Category 2 (redundant enum prefix) / Category 14 (Go/Java-style names) + +`CleanRoomAutoApprovalRule_AuthorScope` carries the parent interface name +plus `CleanRoom` and `AutoApproval`. In TypeScript, the enum is referenced +as a top-level export from `model.ts` and re-exported from `index.ts`. It +does not need the parent-type prefix; `AuthorScope` (or, if disambiguation +is desired, `RuleAuthorScope`) is sufficient. The proto-style underscore +join already required disabling +`@typescript-eslint/naming-convention` (`model.ts:5`), which is a smell. + +### 4. Enum members repeat the enum name — Category 2 (redundant enum prefix) / Category 18 (long enum values) + +```typescript +export enum CleanRoomAutoApprovalRule_AuthorScope { + AUTHOR_SCOPE_UNSPECIFIED = 'AUTHOR_SCOPE_UNSPECIFIED', + ANY_AUTHOR = 'ANY_AUTHOR', +} +``` + +`AUTHOR_SCOPE_UNSPECIFIED` repeats `AuthorScope` (which is also the enum +name). The serialized wire values are out of our control, but the TS +identifiers can be `UNSPECIFIED` and `ANY` (or `ANY_AUTHOR` if disambiguation +within `AuthorScope` matters); when used at call sites they read +`AuthorScope.UNSPECIFIED` / `AuthorScope.ANY`, which is clearer than +`AuthorScope.AUTHOR_SCOPE_UNSPECIFIED`. + +### 5. `AUTHOR_SCOPE_UNSPECIFIED` is a leaked-protobuf sentinel — Category 14 (Go/Java-style names) + +The presence of an `_UNSPECIFIED` member is a protobuf-3 convention (every +enum must have a `0` value). It has no meaning in JS — passing +`UNSPECIFIED` is effectively the same as omitting `authorScope`. Either drop +it from the public surface or document explicitly that it is a wire-only +default no caller should pass. As written, IntelliSense advertises it as a +real value alongside `ANY_AUTHOR`. + +### 6. Discriminator-tag value duplicates the field name — Category 12 (duplicate concepts) + +```typescript +authors?: + | { $case: 'authorCollaboratorAlias'; authorCollaboratorAlias: string } + | { $case: 'authorScope'; authorScope: CleanRoomAutoApprovalRule_AuthorScope }; +``` + +The `$case` literal and the only payload key inside each variant are the +same string. The information is encoded twice; the variant could simply +hold the value: + +```typescript +authors?: + | { $case: 'collaboratorAlias'; value: string } + | { $case: 'scope'; value: CleanRoomAutoApprovalRule_AuthorScope }; +``` + +This is at least a consistency concern: the field name `authors` is plural, +but the discriminant talks about a single author. (See finding 7.) The +inner `author` prefix is also redundant once the parent field is already +named `authors`. + +### 7. `authors` / `runners` are misleading plurals on a single-author/runner union — Category 9 (singular/plural mismatches) / Category 6 (misleading names) + +The field types only ever carry one author or one runner per rule: + +- `authorCollaboratorAlias` is a single string. +- `authorScope` is a single enum value (the doc says it covers a scope, but + the value is one scalar). +- `runnerCollaboratorAlias` is a single string. + +The plural names imply a list. Reasonable singular alternatives: +`author` and `runner`. If the intent is to keep the proto's `oneof` group +name, document it; otherwise the plural reads as a bug. + +### 8. `runnerCollaboratorAlias` doubles `runner` — Category 8 (redundant suffix) / Category 12 (duplicate concepts) + +Combined with finding 6, the variant's payload key restates the discriminant: +`{ $case: 'runnerCollaboratorAlias'; runnerCollaboratorAlias: string }`. Once +inside the variant, just `value` or `alias` would do. + +### 9. `ruleOwnerCollaboratorAlias` / `authorCollaboratorAlias` / `runnerCollaboratorAlias` — Category 7 (overly verbose) / Category 5 (cryptic abbreviation) + +Three different fields encode "this string is a collaborator alias". Two +options: + +- Introduce a type alias `type CollaboratorAlias = string` and rename + fields to `ruleOwner`, `author`, `runner`. Then the *type* documents the + semantics rather than the *name* dragging the same suffix three times. +- Or keep the names and shorten: `ownerAlias`, `authorAlias`, `runnerAlias` + (the "collaborator" qualifier is implied by the clean-rooms domain). + +"alias" by itself is also a slightly cryptic term outside the clean-rooms +context; a JSDoc note explaining it identifies a collaborator would help. + +### 10. `ruleId` is underspecified — Category 19 (underspecified ID) + +Every `ruleId` in `Delete/Get/UpdateCleanRoomAutoApprovalRuleRequest` is just +`string`. The comment on `CleanRoomAutoApprovalRule.ruleId` says "A generated +UUID". Either the type should reflect that (`type RuleId = string` with a +JSDoc tag, or zod schema validating UUID format) or the doc should be +elsewhere. Today every callsite has to know via documentation that it is a +UUID, not an arbitrary string. + +### 11. `Client` is a generic class name — Category 1 (vague/generic) + +`Client` collides conceptually with the `Client` in every other API package +(`@databricks/sdk-cleanrooms/v1` also exports `Client`, etc.). Inside a +file this is fine, but at consumer sites it forces a rename on import: + +```typescript +import {Client as AutoApprovalRulesClient} + from '@databricks/sdk-cleanroomautoapprovalrules/v1'; +``` + +Two consistent options: (a) keep `Client` everywhere and document that +consumers will rename on import (current state, by convention), or (b) +export a more specific name (`AutoApprovalRulesClient`, +`CleanRoomAutoApprovalRulesClient`). Either way, this is a *package-wide* +decision; this audit just flags that the bare `Client` name is generic. + +### 12. `listCleanRoomAutoApprovalRulesIter` — Category 7 (overly verbose) / Category 14 (Go-style name) + +The `Iter` suffix is a Go-ism (Go iterators historically end in `Iter`). +For async generators in TS, the idiomatic name is plural-of-resource (the +method already returns an `AsyncGenerator`), e.g., `listAllRules` / +`rulesIterator` / overload `list()` to return `AsyncIterable`. Even keeping +the suffix, dropping the long resource prefix (`listIter(...)` / +`iterRules(...)`) would shave 24 characters. JS callers do not need the +"Iter" disambiguator because `for await (const r of client.list(...))` +already signals iteration; a separate `listRulesPage(...)` could carry the +single-page behaviour if both shapes are needed. + +### 13. `nextPageToken` / `pageToken` are duplicated across the response and request — Category 12 (duplicate concepts) [informational] + +`ListCleanRoomAutoApprovalRulesResponse.nextPageToken` and +`ListCleanRoomAutoApprovalRulesRequest.pageToken` are wire-mandated and +match the Databricks pagination convention. This is *not* a finding to act +on — it is the standard pagination shape used across all packages. Logged +for completeness because the prompt asks for an exhaustive scan. + +### 14. Doc references undefined casing — Category 16 (field contradicting type domain) [minor] + +The JSDoc on `authorCollaboratorAlias` says: + +``` +Only one of `author_collaborator_alias` and `author_scope` can be set. +``` + +The fields named in the doc are `snake_case` (wire names), but the +TypeScript fields are `authorCollaboratorAlias` and `authorScope`. This is +a leaked-from-proto doc; a TS-side comment should say "Only one of +`authorCollaboratorAlias` and `authorScope` can be set" (or "exactly one +arm of `authors` should be populated"). Same issue on line 25 of +`model.ts` for the second arm. The doc on +`ListCleanRoomAutoApprovalRulesResponse.nextPageToken` says "`page_token` +should be set", which should read `pageToken`. + +### 15. Docs say "a auto-approval rule" — typo (not naming, but on JSDoc) [minor] + +`client.ts:96`, `client.ts:115`, `client.ts:194` use `Delete a +auto-approval`, `Get a auto-approval`, `Update a auto-approval`. The +article should be `an`. This is generated text; flag it for the +generator. Not strictly a naming issue, but it sits in the same area. + +### 16. `Client` constructor field `userAgent` — Category 1 (vague) [minor] + +`private readonly userAgent: string` (`client.ts:49`) holds the *value* of +the `User-Agent` header. The name reads as a thing rather than a header +value. `userAgentHeader` or `userAgentValue` is unambiguous. Minor — the +JSDoc above the field explains it — but consistent with the audit's brief. + +### 17. `utils.ts` is a kitchen-sink module name — Category 1 (vague/generic) + +`utils.ts` houses `executeCall`, `executeHttpCall`, `buildHttpRequest`, +`parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, and +`HttpCallOptions`. Per the SDK's existing breakdown (see +`@databricks/sdk-core/api`, `.../apierror`, `.../http`, `.../logger`), these +helpers would normally live in a named module (e.g., `http.ts`, +`request.ts`). All sibling API packages emit the same `utils.ts`, so this is +a generator-level concern, not a per-package one. Flagged because the brief +asks about generic names. + +### 18. Method docstrings use "rule ID" inconsistently with field name — Category 6 (misleading names) [minor] + +JSDocs say "Delete a auto-approval rule by rule ID", "Get a auto-approval +rule by rule ID", "Update a auto-approval rule by rule ID". The request +fields are `ruleId` (camelCase). A reader scanning the docs sees "rule ID" +and may search for a field called "rule ID" or "ID". Either keep "ruleId" +verbatim in the prose or just say "by ID". + +### 19. `cleanRoomName` is the identifier doing double duty — Category 19 (underspecified ID) [minor] + +The path identifier is the `cleanRoomName` (a URL segment). In other +packages this is sometimes `cleanRoomId` (UUID) or a `metastoreId`. Here it +is consistently a name. The doc on +`CleanRoomAutoApprovalRule.cleanRoomName` is clear, but the field type is +`string`, so there is nothing stopping a caller from passing the UUID by +mistake. A type-aliased name (`CleanRoomName`) would help. Same flag as +finding 10. + +--- + +## Themes / suggested resolution priority + +1. **Verbosity from the package name leaking into every symbol.** Findings + 1, 2, 3, 4, 12. This is the dominant issue: `CleanRoomAutoApproval` + appears in every type and method name even though it is already in the + package import path. Strip the prefix and the surface area becomes about + half as wide on screen. +2. **Proto/Go ergonomics surfacing in TS.** Findings 3, 4, 5, 6, 12. + `_`-joined enum names, `_UNSPECIFIED` sentinels, and `Iter`-suffixed + iterators are conventions imported from protobuf/Go that have no payoff + in TypeScript. +3. **Field-name ambiguity around identifiers and aliases.** Findings 7, 8, + 9, 10, 19. `authors`/`runners` are plural but always single; + collaborator aliases are typed `string`; `ruleId` is a UUID typed + `string`. Type aliases plus singular field names would cover all of + these. +4. **Doc/identifier drift from the wire format.** Findings 14, 15, 18. JSDoc + text references `snake_case` field names and includes generated-text + typos. These are docs-only fixes but they bear on naming clarity. +5. **Module-shape concerns** (only logged for awareness because the prompt + asked for an exhaustive sweep): findings 11, 16, 17. + +--- + +## Out of scope for this audit + +- Whether the package should exist as a separate npm package at all + (versus folding the rule CRUD into `@databricks/sdk-cleanrooms`). That is + a package-shape decision, not a naming one. +- Wire-format names (`page_token`, `next_page_token`, `clean_room_name`, + etc.). These are dictated by the API and not part of the TS surface. +- The `_` underscore in `CleanRoomAutoApprovalRule_AuthorScope` is already + documented (and explicitly lint-disabled) as a proto-style nested enum + name; the *suffix* portion (`AuthorScope`) is what finding 3 targets. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md new file mode 100644 index 00000000..3de2a400 --- /dev/null +++ b/.agent/naming-audit/cleanrooms.md @@ -0,0 +1,672 @@ +# Naming Audit: `cleanrooms` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/cleanrooms/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Auditor:** Naming audit pass — TypeScript port of Databricks Go SDK. + +This audit catalogs every type, field, enum value, and method name in the +`cleanrooms` v1 package against the 20 criteria provided. Findings are +grouped by category, and each finding cites the file/line where it appears. + +--- + +## Summary + +- **Total findings:** 60 +- **Highest-impact themes:** + 1. Proto-style nested enum/message names with embedded underscores + (`CleanRoom_Status_Enum`, + `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol`, + etc.) violate TS identifier conventions and produce extremely long, + unreadable identifiers. + 2. Massive redundant enum-prefix tautology + (`INTERNET_DESTINATION_TYPE_UNSPECIFIED`, `LOG_ONLY_MODE_TYPE_UNSPECIFIED`, + `OUTPUT_CATALOG_STATUS_UNSPECIFIED`, …) — each enum member repeats the + enum-name domain. + 3. Several field names use vague or generic terms (`type`, `protocol`, + `name`, `destination`, `status`) that lose meaning out of context. + +--- + +## 1. Vague / Generic Names + +### 1.1 `name?: string` on `CleanRoom` (model.ts:142) +The top-level field `name` is the clean room identifier. Combined with the +request shape `GetCleanRoomRequest { name }`, the name "name" is too +generic — there is no signal that this is a UC securable name vs. a display +name vs. a UUID. Go SDK has the same problem, but consider `cleanRoomName`. + +### 1.2 `name?: string` on `GetCleanRoomRequest`, `DeleteCleanRoomRequest`, +`UpdateCleanRoomRequest` (model.ts:273, 346, 367) +Same issue — when used inside a request DTO, `name` is ambiguous as to +**which** name. `cleanRoomName` would self-document. The request schema +in `CreateCleanRoomOutputCatalogRequest` uses the more specific +`cleanRoomName` (model.ts:259), so the codebase is inconsistent with itself. + +### 1.3 `type?: ...InternetDestinationType` (model.ts:312) +The field `type` on `InternetDestination` is generic. `destinationType` or +`kind` would be clearer at call sites +(`internetDestination.type === FQDN` reads as a meta-property). + +### 1.4 `type?: ...StorageDestinationType` (model.ts:335) +Same issue on `StorageDestination` — bare `type` field. + +### 1.5 `protocol?: ...InternetDestinationFilteringProtocol` (model.ts:315) +`protocol` is generic. A consumer cannot tell from `destination.protocol` +whether this is TCP/UDP/HTTP/SSH/etc. `filteringProtocol` matches the +underlying enum semantics. + +### 1.6 `destination?: string` (model.ts:311) +Bare `destination` on `InternetDestination` is tautological with its +container. The string is the FQDN/hostname/IP literal. `value` or +`fqdn`/`host` would convey intent. + +### 1.7 `region?: string` (model.ts:232, 334) +`region` field appears on both `CleanRoomRemoteDetail` (cloud region) and +`StorageDestination` (bucket region). Not necessarily wrong, but the +ambiguity is worth noting — `cloudRegion` / `bucketRegion` would disambiguate. + +### 1.8 `workloads?: WorkloadType[]` (model.ts:325) +On `LogOnlyMode`, the field `workloads` is plural-of-type. `workloadTypes` +would match the enum. (See also §9 — singular/plural mismatch.) + +--- + +## 2. Redundant Enum Prefixes (the most pervasive issue) + +Every enum redundantly prefixes the type's own name onto its `UNSPECIFIED` +member, and often onto all members. Idiomatic TS uses bare member names +(e.g., `Status.Active`, not `Status.STATUS_ACTIVE`), since the enum-name +qualifier is already present at every call site. + +### 2.1 `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` (model.ts:8) +Should be `UNSPECIFIED`. Consumers write +`ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` which is doubly redundant. + +### 2.2 `CleanRoom_Status_Enum.ENUM_UNSPECIFIED` (model.ts:62) +Should be `UNSPECIFIED`. The `_ENUM` re-suffix in both the type name **and** +the member compounds the redundancy. + +### 2.3 `CleanRoomOutputCatalog_OutputCatalogStatus.OUTPUT_CATALOG_STATUS_UNSPECIFIED` +(model.ts:71) +Should be `UNSPECIFIED`. `OUTPUT_CATALOG_STATUS` is already in the enum name. + +### 2.4 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol.INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED` +(model.ts:88) +The enum name and the member share **the same 36-character substring**. + +### 2.5 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType.INTERNET_DESTINATION_TYPE_UNSPECIFIED` +(model.ts:94) +Same pattern — full prefix tautology. + +### 2.6 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType.LOG_ONLY_MODE_TYPE_UNSPECIFIED` +(model.ts:100) +Same pattern. + +### 2.7 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_WorkloadType.WORKLOAD_TYPE_UNSPECIFIED` +(model.ts:108) +Same pattern. + +### 2.8 `EgressNetworkPolicy_InternetAccessPolicy_RestrictionMode.RESTRICTION_MODE_UNSPECIFIED` +(model.ts:122) +Same pattern. + +### 2.9 `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType.STORAGE_DESTINATION_TYPE_UNSPECIFIED` +(model.ts:130) +Same pattern. + +Cumulatively: every enum's `UNSPECIFIED` sentinel is redundantly prefixed, +and seven of nine enum types are nested-style names that compound the issue. + +--- + +## 3. Acronym Casing Inconsistencies + +### 3.1 `centralCleanRoomId` (model.ts:228) +Uses `Id` (lowercase `d`). Elsewhere `globalMetastoreId`, +`inviteRecipientWorkspaceId` — consistent within this file as `Id`. But +Google TypeScript Style Guide § 5.3 recommends `ID` (treat as acronym). The +package is internally consistent (all `Id`); the issue is whether to upgrade +to `ID` across the SDK. **Note:** repo-wide convention should be confirmed. + +### 3.2 `azureDnsZone` (model.ts:341) +"DNS" is an initialism. Per the style guide, `azureDNSZone`. Currently +`azureDnsZone` treats DNS as a word. + +### 3.3 `cloudVendor?: string` containing `aws`, `azure`, `gcp` (model.ts:230) +Doc comment uses lowercase `aws,azure,gcp`. These are acronyms — should be +`AWS`, `Azure`, `GCP`. (Doc-only, but inconsistent with the enum members +`AWS_S3`, `AZURE_STORAGE`, `GOOGLE_CLOUD_STORAGE`.) + +### 3.4 `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5` (model.ts:17, 20, 21) +"FedRAMP" is the official spelling — `FEDRAMP` flattens the casing. +Identifier-level constraint of SCREAMING_SNAKE is fine, but documentation +text should match. + +### 3.5 `K_FSI` (model.ts:42) +"K-FSI" abbreviates "Korea Financial Security Institute." A bare leading +single letter (`K_`) is cryptic. `KFSI` or `KOREA_FSI` reads better. + +### 3.6 `IRAP_PROTECTED` (model.ts:18) +"IRAP" is the Information Security Registered Assessors Program. OK as-is, +but worth noting the `_PROTECTED` suffix encodes a level — fine. + +--- + +## 4. Underscores in TypeScript Identifiers + +TS naming conventions (`@typescript-eslint/naming-convention`) prohibit +underscores in type and member names. The file disables this rule globally +with `eslint-disable-next-line` for nine type definitions. + +### 4.1 `CleanRoom_AccessRestricted` (model.ts:55) +Snake-case-in-PascalCase identifier — Go/proto idiom, not TS idiom. + +### 4.2 `CleanRoom_Status_Enum` (model.ts:61) +Same. Triple-segment Go-style nested enum name. + +### 4.3 `CleanRoomOutputCatalog_OutputCatalogStatus` (model.ts:70) + +### 4.4 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` +(model.ts:87) — 86-character name with three underscores. + +### 4.5 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType` +(model.ts:93) + +### 4.6 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType` (model.ts:99) + +### 4.7 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_WorkloadType` (model.ts:107) + +### 4.8 `EgressNetworkPolicy_InternetAccessPolicy_RestrictionMode` (model.ts:121) + +### 4.9 `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType` +(model.ts:129) + +### 4.10 Interfaces (same pattern) +- `CleanRoom_Status` (model.ts:178) +- `EgressNetworkPolicy_InternetAccessPolicy` (model.ts:288) +- `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination` (model.ts:310) +- `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode` (model.ts:321) +- `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination` (model.ts:332) + +### 4.11 Marshal/unmarshal schema constants +- `unmarshalEgressNetworkPolicy_InternetAccessPolicySchema` (model.ts:494) +- `unmarshalEgressNetworkPolicy_InternetAccessPolicy_InternetDestinationSchema` + (model.ts:531) +- `unmarshalEgressNetworkPolicy_InternetAccessPolicy_LogOnlyModeSchema` (model.ts:553) +- `unmarshalEgressNetworkPolicy_InternetAccessPolicy_StorageDestinationSchema` + (model.ts:575) +- `marshalEgressNetworkPolicy_InternetAccessPolicySchema` (model.ts:718) +- `marshalEgressNetworkPolicy_InternetAccessPolicy_InternetDestinationSchema` (model.ts:755) +- `marshalEgressNetworkPolicy_InternetAccessPolicy_LogOnlyModeSchema` (model.ts:777) +- `marshalEgressNetworkPolicy_InternetAccessPolicy_StorageDestinationSchema` (model.ts:799) + +The underscore-bearing identifiers radiate from the model file into the +public re-exports in `index.ts` (lines 7–13, 20, 30–33), so the API surface +is contaminated. + +--- + +## 5. Cryptic Abbreviations + +### 5.1 `K_FSI` (model.ts:42) +Bare `K_FSI` is cryptic without the comment "Korea Financial Security +Institute." See §3.5 above. + +### 5.2 `ARC_AMPE` (model.ts:51) +"Acceptable Risk Controls for ACA, Medicaid, and Partner Entities" — five +words compressed into eight characters. Without the doc-comment, opaque. + +### 5.3 `ESC` in `ComplianceStandard.NONE` JSDoc (model.ts:11) +Documentation acronym only — but ESC = Enhanced Security Compliance is +unexplained at first reference. + +### 5.4 `CSP` doc comment on `accessRestricted` (model.ts:166) +"CSP" abbreviation linked but not spelled. The enum constant +`CSP_MISMATCH` (model.ts:57) also uses the bare acronym. + +### 5.5 `FQDN` enum value (model.ts:95) +"Fully Qualified Domain Name" — well-known enough in networking, OK. + +### 5.6 `SEG`, `DP`, `UC`, `SNI` in JSDoc (model.ts:82, 117, 217) +Doc-only abbreviations: SEG (Secure Egress Gateway?), DP (Data Plane?), +UC (Unity Catalog), SNI (Server Name Indication). UC is well-established in +this codebase; SEG/DP/SNI need expansion. + +### 5.7 `DBSQL` (model.ts:109) +"Databricks SQL" — familiar to Databricks customers, OK in context. + +--- + +## 6. Misleading Names + +### 6.1 `remoteDetailedInfo` (model.ts:148) +Field name suggests "verbose info about a remote endpoint." Actually +contains the central clean room state (collaborators, network policy, +compliance) — the meaty payload of `CleanRoom`. JSON tag is +`remote_detailed_info` but the type is `CleanRoomRemoteDetail` (singular, +no "Info"). The name is **misleading** and **internally inconsistent with +its type**: field says `remoteDetailedInfo`, type says `RemoteDetail`. + +### 6.2 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:166) +Reads as a boolean ("is access restricted?"). It is actually an enum with +values `NO_RESTRICTION` and `CSP_MISMATCH`. `accessRestrictedReason` or +`accessRestriction` would not suggest a boolean. The JSDoc reinforces the +miscommunication: "Whether clean room access is restricted…" — implying a +yes/no. + +### 6.3 `enableSharedOutput?: boolean` (model.ts:173) +The verb `enable` reads as imperative/action. For a state field a +participial/predicate name is clearer: `sharedOutputEnabled`. The JSDoc +itself notes the field is slated for deprecation. + +### 6.4 `isEnabled?: boolean` on `ComplianceSecurityProfile` (model.ts:252) +The `is` prefix is acceptable, but inside an object literal one writes +`profile.isEnabled` (reading "is enabled" of a non-question subject) which +becomes awkward; simply `enabled` is more idiomatic and aligns with +JavaScript norms (HTML `disabled`, `aria-disabled`, etc.). Note the +inconsistency: `isEnabled` here vs. `enableSharedOutput` on `CleanRoom`. + +### 6.5 `logOnlyMode?: ...LogOnlyMode` (model.ts:299) +Field name and type name both have `LogOnlyMode`. But the field's container +already declares "this is the LogOnlyMode submessage" — `logOnly` would +suffice. + +### 6.6 `localCollaboratorAlias?: string` (model.ts:159) vs. +`collaboratorAlias` on `CleanRoomCollaborator` (model.ts:206) +The "local" prefix here is a fragment of metastore-domain jargon. A reader +who does not already know about "single-metastore vs. x-metastore" clean +rooms cannot tell what "local" means. + +### 6.7 `CreateCleanRoomWaiter` class (client.ts:289) +The waiter polls `getCleanRoom` and resolves when status reaches `ACTIVE`. +Naming it `CreateCleanRoomWaiter` ties it to `createCleanRoom`, but the +waiter is operationally generic (any clean room name can be polled). A +better name is `CleanRoomActivationWaiter` or `CleanRoomStatusWaiter`. + +--- + +## 7. Overly Verbose Names + +### 7.1 Six of the nine enum type names exceed **50 characters** (model.ts:87–135). +Worst offenders: +- `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` + — **97** characters, by far the longest in the package. +- `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType` — 85. +- `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType` — 83. +- `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType` — 68. + +The same enums also have `UNSPECIFIED` members reaching 36 characters +(`INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED`). + +### 7.2 Marshal/unmarshal schema identifiers (model.ts:494, 531, 553, 575, +718, 755, 777, 799) +The constants `unmarshalEgressNetworkPolicy_InternetAccessPolicy_InternetDestinationSchema` +and its marshal mirror each weigh in at **84 characters**. They are +exported and survive in source as long lines that already wrap awkwardly. + +### 7.3 `CreateCleanRoomOutputCatalogResponse` (model.ts:263) / +`CreateCleanRoomOutputCatalogRequest` (model.ts:257) +36 characters each, but the underlying response body has a single field +(`outputCatalog`). Could be `OutputCatalogResponse` if the operation +context is unambiguous from the method signature. Probably keep — RPC +naming convention. + +### 7.4 `centralCleanRoomId?: string` (model.ts:228) +Inside `CleanRoomRemoteDetail`, the `central` adjective is redundant — the +type itself describes the central clean room. `id` would suffice (subject +to §1 generic-name caveat — perhaps `remoteId` if we keep the structure). + +--- + +## 8. Redundant Suffixes + +### 8.1 `CleanRoom_Status_Enum` (model.ts:61) +The `_Enum` suffix is tautological with the `enum` keyword. + +### 8.2 `CleanRoomOutputCatalog_OutputCatalogStatus` (model.ts:70) +The `OutputCatalogStatus` segment repeats `OutputCatalog`. `Status` alone +would work given the enclosing scope. + +### 8.3 `_InternetDestinationFilteringProtocol` (model.ts:87) and +`_InternetDestinationType` (model.ts:93) +Both append `InternetDestination*` to a type whose Go-style nested path +already says `…_InternetDestination_…`. Pure repetition. + +### 8.4 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) +`LogOnlyMode` appears twice in the same identifier. Same for +`_StorageDestination_StorageDestinationType`. + +### 8.5 `complianceSecurityProfile?: ComplianceSecurityProfile` (model.ts:246) +Field name is identical to the type name — repetition but consistent with +the rest of the SDK style. (Mild — many ports do this.) + +### 8.6 `outputCatalog?: CleanRoomOutputCatalog` (model.ts:164, 260, 264) +Same field-name-equals-type pattern as §8.5. + +--- + +## 9. Singular / Plural Mismatches + +### 9.1 `workloads?: WorkloadType[]` (model.ts:325) +Field is plural and array-typed, but the element type is **`WorkloadType`** +(singular noun + `Type` suffix). Consumers write `mode.workloads[0]` which +is a `WorkloadType` — readable, but the field could be `workloadTypes` to +match the element. Alternative: rename the enum to `Workload`. + +### 9.2 `cleanRooms?: CleanRoom[]` on `ListCleanRoomsResponse` (model.ts:357) +Correctly plural — flagged only as a positive example. + +### 9.3 `collaborators?: CleanRoomCollaborator[]` (model.ts:241) +Correctly plural — positive example. + +### 9.4 `complianceStandards?: ComplianceStandard[]` (model.ts:254) +Correctly plural. But `allowedInternetDestinations` and +`allowedStorageDestinations` (model.ts:292, 295) inherit the `allowed` +prefix; while the parent `restrictionMode` is singular. Mild inconsistency. + +### 9.5 `allowedPaths?: string[]` (model.ts:339) +Correctly plural. + +--- + +## 10. Reserved-Word / Built-in Collisions + +### 10.1 `type` field on `InternetDestination` and `StorageDestination` +(model.ts:312, 335) +`type` is not a reserved word in TS at field position, but it shadows the +TS `typeof` semantics in conversation and may collide with linters that +flag it. `kind` is the established alternative (tagged-union convention). +Note: TypeScript's discriminated-union pattern often uses literal `type` — +so this is a soft flag. + +### 10.2 `status` field appears on `CleanRoom` and `CleanRoomOutputCatalog` +Not a reserved word; raised here to highlight the duplication. See §12. + +--- + +## 11. Duplicate Concepts + +### 11.1 Two `Status` enums +- `CleanRoom.status: CleanRoom_Status_Enum` (model.ts:157) +- `CleanRoomOutputCatalog.status: CleanRoomOutputCatalog_OutputCatalogStatus` + (model.ts:216) + +Two distinct, non-overlapping `Status` enums. The two enum types should +consider naming themselves unambiguously: `CleanRoomStatus`, +`OutputCatalogStatus`. + +### 11.2 `CleanRoomCollaborator` overlap with `cleanroomtaskruns.CollaboratorJobRunInfo` +(cross-package) +`cleanroomtaskruns/src/v1/model.ts` defines `CollaboratorJobRunInfo`. Both +packages now have a "Collaborator-prefixed" surface; consumers must keep +both straight. Not a rename target inside `cleanrooms`, but a +cross-package risk: a third "collaborator" type in another package would +make disambiguation tedious. + +### 11.3 `creator?: CleanRoomCollaborator` (model.ts:243) vs. +`collaborators?: CleanRoomCollaborator[]` (model.ts:241) +Per the JSDoc, `creator` is also **one of the collaborators in the +collaborators list**. So we have the same logical entity reachable through +two paths. Mild — not a renamed-target, but flagged as a shape concern. + +### 11.4 `cleanRoomName` (model.ts:259) vs. `name` (model.ts:142, 273, 346, 367) +Two names for the same thing: the clean-room identifier. Picking one +consistently would simplify call sites. + +--- + +## 12. Verb-Tense Inconsistency + +### 12.1 `enableSharedOutput` (verb, imperative) vs. `isEnabled` +(participle, predicate) — see §6.3 and §6.4 above. + +### 12.2 `accessRestricted` (participial, predicate) vs. +`CleanRoom_AccessRestricted` (the **enum** type name shares the predicate +form) (model.ts:55, 166) +Enums normally name a domain (`AccessRestriction`, `RestrictionReason`), +not a predicate. Reading `restriction: AccessRestricted = NO_RESTRICTION` +is semantically weird — "the access-restricted of this thing is no +restriction." + +### 12.3 Method verbs are consistent (create/get/list/update/delete) — +positive example. + +--- + +## 13. Go / Java / Proto-Style Names in TS + +### 13.1 The nine `*_*_*` enum names and five `*_*_*` interface names +already enumerated in §4.1–§4.11 are direct Go/proto carryovers. The +`eslint-disable-next-line` comments explicitly acknowledge this with the +phrase "Proto-style nested enum name" / "Proto-style nested message name." +They are *the* defining stylistic deviation of this file. + +### 13.2 The marshal/unmarshal naming +`marshalCleanRoomSchema`, `unmarshalCleanRoomSchema` (model.ts:371, 613) +follow Go naming (`Marshal` / `Unmarshal`). JS/TS idiom is +`serialize`/`deserialize`, `encode`/`decode`, or `to{Json,Wire}` / +`from{Json,Wire}`. This is a system-wide SDK choice and not unique to +cleanrooms, but worth flagging once. + +### 13.3 `CreateCleanRoomWaiter` (client.ts:289) +"Waiter" is the Go SDK convention; in TS, `Poller` / `Watcher` / +`Operation` (Azure-style) are more idiomatic. Inherited convention. + +### 13.4 `req` parameter convention (client.ts:86, 111, 123, 160, 179, +207, 240, 264) +`req` is a Go SDK convention. TS norms favor explicit parameter names +(`request`) or destructuring. Minor. + +--- + +## 14. Generic Field Names Losing Meaning Out of Context + +### 14.1 `destination`, `type`, `protocol` on `InternetDestination` +(model.ts:311–315) +Read in isolation, these are completely opaque. Cross-reference §1.3–§1.6. + +### 14.2 `name`, `comment`, `owner` on `CleanRoom` (model.ts:142, 151, 150) +`owner` is a username string; `comment` is a free-text description; +`name` is a UC securable identifier. None of these self-describe. + +### 14.3 `bucketName`, `region`, `type`, `azureStorageAccount`, +`allowedPaths`, `azureStorageService`, `azureDnsZone`, `azureContainer` +on `StorageDestination` (model.ts:333–343) +The same struct mixes AWS-, Azure-, and GCP-shaped fields. `bucketName` +is S3-flavored; `azureStorageAccount` is Azure-flavored. The fact that the +fields share one struct **and** the field names are not prefixed with the +cloud (`bucketName` vs. `azureContainer`) leaks the cloud taxonomy into +field naming inconsistently. + +--- + +## 15. Field Contradicting Type Domain + +### 15.1 `CleanRoomRemoteDetail.region: string` (model.ts:232) +Type is `string`, but the domain is "a cloud region identifier +(`us-east-1`, `westeurope`, etc.)" — the type should be a tagged-string +or a region enum. Minor. + +### 15.2 `cloudVendor: string` (model.ts:230) +Same — should be an enum (the cloud SDK packages already have one). + +### 15.3 `enableSharedOutput` (boolean) vs. the JSDoc "shared output PrPr" +(private preview) — the field is a feature flag fronted as a permanent API, +not labelled `experimental` (model.ts:173). Minor. + +### 15.4 `createdAt`, `updatedAt: number` (model.ts:153, 155) +Stored as **epoch milliseconds** per JSDoc but typed as `number` rather +than a branded `EpochMillis` or `Timestamp`. Loses semantic information +in the type system. (Repo-wide pattern; flag once.) + +### 15.5 `inviteRecipientWorkspaceId: number` (model.ts:194) +Workspace IDs are int64 in Databricks; TS `number` is 53-bit. Latent +precision loss for IDs above 2^53. The proto schema would use int64. Not +a naming concern, but the field name does not warn (e.g., +`inviteRecipientWorkspaceIdRaw` / docs). + +--- + +## 16. Inconsistent Action Verbs + +The five RPC methods follow the standard CRUD verbs: +`createCleanRoom`, `createCleanRoomOutputCatalog`, `deleteCleanRoom`, +`getCleanRoom`, `listCleanRooms`, `updateCleanRoom`. + +### 16.1 `createCleanRoom` returns the new clean room (client.ts:85); +`createCleanRoomOutputCatalog` returns a **response wrapper** +(`CreateCleanRoomOutputCatalogResponse`) (client.ts:122). +Inconsistent return shapes for two `create*` methods. The Go SDK has the +same wart, but it surfaces here as inconsistent ergonomics: +`(await c.createCleanRoom(...)).name` vs. +`(await c.createCleanRoomOutputCatalog(...)).outputCatalog?.catalogName`. + +### 16.2 `listCleanRoomsIter` (client.ts:239) +The `*Iter` suffix matches the Go SDK's iterator naming. TS norms suggest +`*Iterator`, `*AsyncIterable`, or returning a `Pager` object. Minor. + +--- + +## 17. Long Enum Values + +In addition to the prefix-redundant `UNSPECIFIED` values enumerated in §2: + +### 17.1 `COMPLIANCE_STANDARD_UNSPECIFIED` (model.ts:8) — 31 chars +### 17.2 `OUTPUT_CATALOG_STATUS_UNSPECIFIED` (model.ts:71) — 33 chars +### 17.3 `INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED` (model.ts:88) — 51 chars +### 17.4 `INTERNET_DESTINATION_TYPE_UNSPECIFIED` (model.ts:94) — 37 chars +### 17.5 `LOG_ONLY_MODE_TYPE_UNSPECIFIED` (model.ts:100) — 30 chars +### 17.6 `STORAGE_DESTINATION_TYPE_UNSPECIFIED` (model.ts:130) — 36 chars +### 17.7 `RESTRICTION_MODE_UNSPECIFIED` (model.ts:122) — 28 chars +### 17.8 `WORKLOAD_TYPE_UNSPECIFIED` (model.ts:108) — 25 chars +### 17.9 `GOOGLE_CLOUD_STORAGE` (model.ts:134) — 20 chars +(Reasonable for the data being modeled.) + +The cumulative cost is that switch-statements and equality checks on +these enums consume wide lines, e.g., +`EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType.LOG_ONLY_MODE_TYPE_UNSPECIFIED` +is **97** characters — exceeding the project's 90-char line limit +on its own. + +--- + +## 18. Underspecified IDs + +### 18.1 `centralCleanRoomId?: string` (model.ts:228) +String ID — no JSDoc explanation of format (UUID? Numeric? Free-form?). +Per JSDoc on `globalMetastoreId`: "cloud:region:metastore-uuid" — at least +that one is documented. + +### 18.2 `globalMetastoreId?: string` (model.ts:183) — Documented; positive example. + +### 18.3 `inviteRecipientWorkspaceId?: number` (model.ts:194) +ID typed as `number` and undocumented format — see §15.5 on precision risk. + +### 18.4 `bucketName?: string` (model.ts:333) +Bucket name vs. ARN vs. URI — not specified. Could be S3 bucket name or +GCS bucket name; both share the field. + +### 18.5 `azureStorageAccount?: string` (model.ts:338), +`azureStorageService?: string` (model.ts:340), +`azureContainer?: string` (model.ts:342) +Three Azure identifiers, no JSDoc explaining accepted formats. + +--- + +## 19. Type-Suffix Tautology + +### 19.1 `CleanRoom_AccessRestricted` (model.ts:55) +The type name uses the participle predicate — but enums classify, not +predicate. Combined with the field `accessRestricted: CleanRoom_AccessRestricted`, +the result is `accessRestricted: AccessRestricted` — pure echo (the field +adds no information beyond what the type name supplies). + +### 19.2 `CleanRoom_Status_Enum` (model.ts:61) +The `_Enum` suffix is the canonical example of type-suffix tautology. +TS's `enum` keyword already conveys "this is an enum." + +### 19.3 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) and +`_StorageDestination_StorageDestinationType` (model.ts:129) +Type name segment appears twice. See §8. + +### 19.4 `complianceSecurityProfile: ComplianceSecurityProfile` (model.ts:246) +See §8.5 — common pattern. + +--- + +## Cross-Package Overlap (cleanrooms vs. cleanroomassets / +cleanroomautoapprovalrules / cleanroomtaskruns) + +### CP.1 Shared concept: "clean room" +All four packages use `CleanRoom*` types. None re-imports the canonical +`CleanRoom` from `cleanrooms`; instead each refers to the clean room by +its name (string identifier in URL paths). +There is **no shared `CleanRoom` interface or alias** despite all four +packages keying off the same entity. This is a structural concern, not a +naming concern — flagged once. + +### CP.2 `CleanRoomCollaborator` (cleanrooms) vs. +`CollaboratorJobRunInfo` (cleanroomtaskruns) +The packages model different *aspects* of collaborators with different +prefixes. Consistency would suggest `CleanRoomCollaboratorJobRunInfo` or +moving the type into cleanrooms. Minor. + +### CP.3 Status/state vocabulary divergence: +- `cleanrooms.CleanRoom_Status_Enum` — clean room lifecycle. +- `cleanroomtaskruns.CleanRoomTaskRunLifeCycleState` / + `CleanRoomTaskRunResultState` — task run lifecycle. +- `cleanroomassets.CleanRoomAsset_Status_Enum` — asset lifecycle. +- `cleanroomassets.CleanRoomNotebookReview_NotebookReviewState` — + review state. + +Five different *Status*/*State* enums across four packages. Each one is +locally correct, but readers must learn a new vocabulary per package. +Mild — cross-package theming, not actionable inside `cleanrooms`. + +### CP.4 Resource-name pattern repetition +`cleanrooms` uses `name` as the clean room identifier in request/response +shapes (§1.2). `cleanroomassets` and `cleanroomautoapprovalrules` will +share the same `name` slot — risk of collision when shapes interact in +generic code. + +--- + +## Positive Examples (no action required) + +- Method names follow standard CRUD verbs (create/get/list/update/delete). +- `cleanRooms` / `cleanRoomName` / `collaborators` / `complianceStandards` + use correct plurality. +- JSDoc is generally comprehensive — references to UC naming rules and + external compliance documents are well-linked. +- The `executeCall`, `executeHttpCall`, `marshalRequest`, `parseResponse`, + `buildHttpRequest`, `flattenQueryParams` utilities in `utils.ts` have + short, clear, verb-driven names that survive idiomatically. +- The `StillRunningError` class (client.ts:48) is concise and + self-documenting. +- The package-level segment naming (`PACKAGE_SEGMENT` in client.ts:43) + is appropriately namespaced. + +--- + +## Notes on Generation Artifacts + +Many findings above (especially §2, §4, §7, §8) are direct artifacts +of mechanical translation from the proto-defined Go SDK. The +`eslint-disable-next-line @typescript-eslint/naming-convention` comments +attached to each offender (and the comment "Proto-style nested enum +name" / "Proto-style nested message name") indicate these are recognized +deviations. They are not bugs in this file — they are systemic generator +output that this audit catalogs. + +If the SDK adopts a TS-idiomatic alias layer, the most leverage comes +from: +1. Flattening or shortening the seven `EgressNetworkPolicy_*` enums + (eliminates §4.4–§4.9, §7.1, §17.3–§17.6, §19.2–§19.3). +2. Renaming `CleanRoom_Status_Enum` to `CleanRoomStatus` (§4.2, §8.1, §19.2). +3. Renaming `accessRestricted` -> `accessRestriction` and + `CleanRoom_AccessRestricted` -> `AccessRestriction` (§6.2, §12.2, §19.1). +4. Renaming `remoteDetailedInfo` -> `details` or `remoteDetail` (§6.1) + to align field and type names. + +--- diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md new file mode 100644 index 00000000..1bb328ba --- /dev/null +++ b/.agent/naming-audit/cleanroomtaskruns.md @@ -0,0 +1,484 @@ +# Naming Audit: `cleanroomtaskruns` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/cleanroomtaskruns/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Reference:** `databricks/databricks-sdk-go` `service/cleanrooms/{api,impl,model,interface}.go` and sibling TS packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules`, `jobs/v2`). + +--- + +## Inventory + +### Enums +1. `CleanRoomTaskRunLifeCycleState` (model.ts:9) + - Values: `RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, `PENDING`, `RUNNING`, `TERMINATING`, + `TERMINATED`, `SKIPPED`, `INTERNAL_ERROR`, `BLOCKED`, `WAITING_FOR_RETRY`, `QUEUED`. +2. `CleanRoomTaskRunResultState` (model.ts:26) + - Values: `RUN_RESULT_STATE_UNSPECIFIED`, `SUCCESS`, `FAILED`, `TIMEDOUT`, + `CANCELED`, `MAXIMUM_CONCURRENT_RUNS_REACHED`, `UPSTREAM_CANCELED`, + `UPSTREAM_FAILED`, `EXCLUDED`, `EVICTED`, `SUCCESS_WITH_FAILURES`, + `UPSTREAM_EVICTED`, `DISABLED`. + +### Interfaces / Types +1. `CleanRoomNotebookTaskRun` (model.ts:44) + - Fields: `notebookName`, `startTime`, `runDuration`, `notebookJobRunState`, + `collaboratorJobRunInfo`, `outputSchemaName`, `outputSchemaExpirationTime`, + `notebookEtag`, `notebookUpdatedAt`, `sharedOutputSchemaName`, + `sharedOutputSchemaExpirationTime`. +2. `CleanRoomTaskRunState` (model.ts:78) + - Fields: `lifeCycleState`, `resultState`. +3. `CollaboratorJobRunInfo` (model.ts:85) + - Fields: `collaboratorJobId`, `collaboratorJobRunId`, `collaboratorTaskRunId`, + `collaboratorWorkspaceId`, `collaboratorAlias`. +4. `ListCleanRoomNotebookTaskRunsRequest` (model.ts:98) + - Fields: `cleanRoomName`, `notebookName`, `pageSize`, `pageToken`. +5. `ListCleanRoomNotebookTaskRunsResponse` (model.ts:109) + - Fields: `runs`, `nextPageToken`. + +### Zod schemas +- `unmarshalCleanRoomNotebookTaskRunSchema` +- `unmarshalCleanRoomTaskRunStateSchema` +- `unmarshalCollaboratorJobRunInfoSchema` +- `unmarshalListCleanRoomNotebookTaskRunsResponseSchema` + +### Client class +- `Client` (client.ts:32) + - Methods: `listCleanRoomNotebookTaskRunsHandler`, + `listCleanRoomNotebookTaskRunsHandlerIter`. + - Private fields: `host`, `httpClient`, `logger`, `userAgent`. + - Module constant: `PACKAGE_SEGMENT`. + +### Utils +- Types: `HttpCallOptions`. +- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`. + +--- + +## Findings + +### 1. `Handler` suffix on client methods — category 7 (Overly verbose) and category 14 (Go/Java-style names) + +**Symbol:** `Client.listCleanRoomNotebookTaskRunsHandler`, `Client.listCleanRoomNotebookTaskRunsHandlerIter` (client.ts:58, 97). + +**Issue:** The `Handler` suffix is anomalous within the SDK. Every other clean-room +package method (`cleanrooms.listCleanRooms`, `cleanroomassets.listCleanRoomAssets`, +`cleanroomautoapprovalrules.listCleanRoomAutoApprovalRules`) uses the bare verb form +without `Handler`. The Go reference API (`CleanRoomTaskRunsAPI.List`, +`ListByCleanRoomName`) does not use `Handler` either; "Handler" is an HTTP-server +concept, not a client method idiom. The suffix adds eight characters that convey +nothing — the method already takes a request and returns a response, which is the +contract of a "handler" in API parlance. + +**Suggested:** `listCleanRoomNotebookTaskRuns` and `listCleanRoomNotebookTaskRunsIter`. + +This is the most visible naming defect in the package because it is the only public +surface a TS consumer calls. It is also inconsistent across the SDK; this is a +**P0 fix** for cross-package consistency (audit category 14: every other package uses +camelCase `listX` style without Java/Go-style `Handler` decoration). + +### 2. Redundant `RUN_` prefix on enum values — category 2 (Redundant enum prefixes) + +**Symbol:** `CleanRoomTaskRunLifeCycleState.RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, +`CleanRoomTaskRunResultState.RUN_RESULT_STATE_UNSPECIFIED` (model.ts:10, 27). + +**Issue:** Both enums are scoped under `…TaskRun…`. The leading `RUN_` repeats the +parent type's `Run` concept. The full reference `CleanRoomTaskRunLifeCycleState.RUN_LIFE_CYCLE_STATE_UNSPECIFIED` +contains `Run` twice and `LifeCycleState` twice. Same applies to +`RUN_RESULT_STATE_UNSPECIFIED`. + +**Suggested:** `UNSPECIFIED` (or `LIFE_CYCLE_STATE_UNSPECIFIED` / `RESULT_STATE_UNSPECIFIED` +if proto-wire compatibility forbids dropping more). Most other enums in the SDK use +the plain `UNSPECIFIED` form. Note however the values are also used as on-the-wire +JSON strings (see `z.enum(CleanRoomTaskRunLifeCycleState)` in model.ts:155), so +renaming requires the server to also accept the new spelling, and is a behavioural +change — record this as a request to the API team, not a unilateral TS change. + +### 3. `SCREAMING_SNAKE_CASE` enum values — category 4 (Underscores in TS identifiers) + +**Symbols:** Every value in both enums (model.ts:10–19, 27–40). + +**Issue:** The Google TypeScript Style Guide (the project's `.agent/skills/google-ts-styleguide`) +mandates `UPPER_CAMEL_CASE` for enum members, not `SCREAMING_SNAKE_CASE`. The +project's own `.agent/rules/typescript.mdc` enforces "no underscores in TS +identifiers" (category 4). However, enum *string* values double as the on-the-wire +representation here (the `z.enum` parses raw API strings into these identifiers). +Splitting the TS-side identifier from the wire literal — e.g. +`Terminated = 'TERMINATED'` — is the idiomatic TS fix while preserving wire +compatibility. + +**Suggested (TS side only, no wire change):** + +```ts +export enum CleanRoomTaskRunLifeCycleState { + Unspecified = 'RUN_LIFE_CYCLE_STATE_UNSPECIFIED', + Pending = 'PENDING', + Running = 'RUNNING', + Terminating = 'TERMINATING', + Terminated = 'TERMINATED', + Skipped = 'SKIPPED', + InternalError = 'INTERNAL_ERROR', + Blocked = 'BLOCKED', + WaitingForRetry = 'WAITING_FOR_RETRY', + Queued = 'QUEUED', +} +``` + +Same shape for `CleanRoomTaskRunResultState`. This is consistent with the way the +project's `.agent/rules/typescript.mdc` treats other enums (e.g. status enums in +`apierror/codes`). + +### 4. Long enum values — category 18 (Long enum values) + +**Symbols:** `MAXIMUM_CONCURRENT_RUNS_REACHED` (model.ts:32), `SUCCESS_WITH_FAILURES` +(model.ts:37), `RUN_LIFE_CYCLE_STATE_UNSPECIFIED` (model.ts:10), +`RUN_RESULT_STATE_UNSPECIFIED` (model.ts:27). + +**Issue:** Wire-format values can be left as-is, but TS identifiers should be +shorter. `MAXIMUM_CONCURRENT_RUNS_REACHED` → `MaxConcurrentRunsReached`. +`SUCCESS_WITH_FAILURES` → `SuccessWithFailures` (15 chars vs 21 with underscores). +Combine with finding 3. + +### 5. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) + +**Symbols:** Enum `CleanRoomTaskRunLifeCycleState` and field +`CleanRoomTaskRunState.lifeCycleState` (model.ts:9, 80). + +**Issue:** "Lifecycle" is a single compound word in English (Merriam-Webster lists +it as one closed word). Treating it as two words (`LifeCycle` / `lifeCycle`) +produces an internal capital that doesn't match natural English. Sibling property +in the same struct is `resultState` — natural compound — making the mismatch +visible. Compare to `Date`/`URL` acronym handling: a single word should not have a +midword capital. + +**Suggested:** `CleanRoomTaskRunLifecycleState` and field `lifecycleState`. +Cross-check: the same `LifeCycle` casing exists in `jobs/v2/model.ts` (line 389) +and other "Run" types across the SDK, so a fix must be globally coordinated. + +### 6. `TIMEDOUT` is a non-word — category 6 (Misleading names) and category 13 +(Verb tense inconsistency) + +**Symbol:** `CleanRoomTaskRunResultState.TIMEDOUT` (model.ts:30). + +**Issue:** `TIMEDOUT` mashes "timed out" into one token and drops the space without +forming a real word. Adjacent values use correct past-tense English +(`CANCELED`, `EVICTED`, `FAILED`, `SUCCEEDED`-style). The Go reference also uses +`TIMEDOUT`, so this originates upstream; flag for protocol fix. The TS identifier +should be `TimedOut` regardless (combine with finding 3). + +### 7. `etag` lowercase abbreviation — category 3 (Acronym casing) + +**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65) and wire field +`notebook_etag` (line 133). + +**Issue:** "ETag" is an HTTP standard token defined in RFC 7232 §2.3 ("entity tag") +and is written `ETag` in HTTP headers and most APIs. The TS Style Guide acronym +rule says treat acronyms as one word when 3+ letters (so `XmlHttpRequest`, not +`XMLHTTPRequest`). Two-letter acronyms can keep both letters capitalised. Either +`notebookETag` or `notebookEtag` is defensible; the field uses lowercase, but +elsewhere in the codebase (search `Etag|ETag` in `cleanrooms/v1`) the same +lowercase form is used for the `etag` field on `CleanRoomsNotebookTask`. Mark as +consistent within the codebase but worth re-examining at the SDK level. + +### 8. `notebookEtag` belongs to the notebook, not the task run — category 16 +(Field contradicting type domain) + +**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65). + +**Issue:** Field doc says "Etag of the notebook executed in this task run". The +field name is fine, but contrast with `notebookUpdatedAt` (line 67) — the +combination `notebookEtag` + `notebookUpdatedAt` implies the entire task-run +struct is mixing notebook metadata with run metadata. Consider whether these +should live under a nested `notebook` sub-object (`notebook.etag`, +`notebook.updatedAt`) in a future revision. Flag only — current shape mirrors Go. + +### 9. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 +(Duplicate concepts) + +**Symbol:** `CleanRoomNotebookTaskRun.notebookJobRunState` (model.ts:52). + +**Issue:** The doc says "State of the task run". The struct is already a *task +run*, and the same idea is also called a *Job run* by the collaborator field +right below. Three names for the same concept appear within one struct: +"task run state" (doc), "notebook job run state" (field name), and "job run info" +(neighbouring field). The naming churn is confusing. + +The field type is `CleanRoomTaskRunState`, so the natural field name is +`taskRunState` or just `state`. The "Job" interjected here mirrors how Jobs +service refers to a run as a "Job Run", but this package is about *task runs* — +the Go SDK source field is also `notebook_job_run_state` (i.e. the messiness is +inherited). + +**Suggested:** `state` or `taskRunState`. Cross-reference with `jobs/v2` +`CleanRoomsNotebookTask_CleanRoomsNotebookTaskOutput.cleanRoomJobRunState` +(jobs/v2/model.ts:1158) which has the same shape with yet *another* spelling — +flag both for coordinated renaming. + +### 10. `runDuration` vs implicit "task run" — category 15 (Generic field names +losing meaning) + +**Symbol:** `CleanRoomNotebookTaskRun.runDuration` (model.ts:50). + +**Issue:** The owning struct is already a "Run". Sibling fields drop the "run" +prefix (`startTime`, not `runStartTime`; `notebookEtag`, not `runNotebookEtag`), +yet duration carries it. Inconsistent. + +**Suggested:** `duration` (the doc already says "Duration of the task run, in +milliseconds"). Or rename `startTime` → `runStartTime` for consistency — pick one +side. + +### 11. `outputSchemaExpirationTime` / `sharedOutputSchemaExpirationTime` — +verbose — category 7 (Overly verbose) + +**Symbols:** model.ts:63, model.ts:73. + +**Issue:** `…Time` suffix is redundant; the value is a number (epoch ms). +Compare to `startTime` which legitimately is "time", and `notebookUpdatedAt` +(line 67) which already uses the more idiomatic `At` suffix for an epoch +millisecond timestamp. Within the *same struct*, three different conventions +coexist: `…Time`, `…At`, and `runDuration` (numeric duration). Pick one. + +**Suggested:** `outputSchemaExpiresAt`, `sharedOutputSchemaExpiresAt`, and +`startedAt` — or normalise all three to `…Time`. The `Run` pattern in other +Databricks APIs leans toward `…At`. + +### 12. `sharedOutputSchemaName` doc references missing `enable_shared_output` +flag — category 6 (Misleading names) + +**Symbol:** `CleanRoomNotebookTaskRun.sharedOutputSchemaName` (model.ts:72). + +**Issue:** Doc says "accessible by all collaborators when enable_shared_output is +true". No such field exists in the request/response, and no `enableSharedOutput` +on the run struct. Either the doc references state stored elsewhere (probably on +the clean-room asset config), or the field is missing. Not a naming bug, but +flag for a doc rewording. + +### 13. `CollaboratorJobRunInfo` repeats "collaborator" in every field — +category 8 (Redundant suffixes) and category 2 (Redundant prefixes) + +**Symbol:** `CollaboratorJobRunInfo` (model.ts:85). Fields: `collaboratorJobId`, +`collaboratorJobRunId`, `collaboratorTaskRunId`, `collaboratorWorkspaceId`, +`collaboratorAlias`. + +**Issue:** Every field is prefixed with `collaborator`, but the enclosing struct +is already named `CollaboratorJobRunInfo`. Accessing `info.collaboratorJobId` +reads as "collaborator job-run info → collaborator job id". Drop the prefix: +`jobId`, `jobRunId`, `taskRunId`, `workspaceId`, `alias`. + +The Go SDK keeps the prefix to disambiguate inside the parent struct (`CleanRoomNotebookTaskRun.CollaboratorJobRunInfo.CollaboratorJobId`), +where the prefix is meaningful at the *top* level (`run.collaboratorJobRunInfo.collaboratorJobId`). +TS access lands one level deeper than the natural reading; the prefix is +duplicate. Match the JS idiom: drop the prefix on the nested fields. + +### 14. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the +package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 +(Singular/plural mismatch on the broader concept) + +**Symbol:** `CollaboratorJobRunInfo` (model.ts:85). + +**Issue:** Field `collaboratorTaskRunId` lives inside `CollaboratorJobRunInfo` +(model.ts:91). One struct uses both vocabulary domains. From Databricks docs: +a *Task run* is a single task within a *Job run* (a job can have N tasks). The +field doc strings here use "task run" almost exclusively — `Job ID of the task +run`, `Task run ID of the task run`, `triggered the task run`. The "Job Run" in +the struct *name* is therefore misleading; a more accurate name is +`CollaboratorTaskRunRef` or `CollaboratorRunRef`. Flag for coordination with API +team — the Go SDK has the same name. Cross-reference `jobs/v2` to align. + +### 15. `Etag` doc text — category 4 (Underscores) and category 17 (Inconsistent +action verbs) + +**Symbol:** Doc comment for `notebookEtag` (model.ts:64): "used to identify the +notebook version". + +Not a naming issue per se, but the wire field is `notebook_etag`, surface field +`notebookEtag`, and JSDoc uses "Etag" — three spellings in one field. Minor. + +### 16. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type +`CleanRoomTaskRunState` — category 6 (Misleading names) + +**Symbols:** model.ts:78, model.ts:52. + +**Issue:** Three name layers for the same idea. The doc on +`CleanRoomTaskRunState` says "Stores the run state of the clean rooms notebook +task" — i.e. it is the state of a *notebook task run*. The field that holds it is +called `notebookJobRunState`, which is then `CleanRoomTaskRunState`. The Java SDK +calls the same thing `NotebookTaskRunOutput.runState`. Suggest aligning on +`state: CleanRoomTaskRunState` (drop the doubled noun on the field name) and +keep the type name as-is (the wider SDK uses `…State` types throughout, e.g. +`RunState`, `JobState`). + +### 17. `pageSize` doc contradicts behaviour — category 6 (Misleading names) + +**Symbol:** `ListCleanRoomNotebookTaskRunsRequest.pageSize` (model.ts:104). + +**Issue:** Doc reads: "The maximum number of task runs to return. Currently +ignored - all runs will be returned." If the field is currently ignored, the +name `pageSize` is *misleading* — callers will set it expecting it to take +effect. Either remove the field (best), mark it `@deprecated`, or document this +in JSDoc with a `@deprecated` tag so IDEs show strike-through. Naming-wise: +`pageSize` is fine *if* it works; document the no-op via the deprecation tag, +not just a sentence inside the doc. + +### 18. `runs` field in response — category 15 (Generic field names losing +meaning) — borderline acceptable + +**Symbol:** `ListCleanRoomNotebookTaskRunsResponse.runs` (model.ts:111). + +**Issue:** Generic given the package context, but defensible: this is the +canonical "list" shape (`{ items, nextPageToken }`). The doc string on it ("Name +of the clean room.") is *wrong* — copy-paste error from the request struct's +`cleanRoomName` doc. Doc-text bug, not a naming bug, but worth flagging during a +naming pass since reviewers will notice the field while reading docs. + +### 19. `nextPageToken` is the canonical name — pass. + +No issue. Matches all other listing responses in the SDK. + +### 20. `ListCleanRoomNotebookTaskRunsRequest` / `…Response` — category 7 +(Overly verbose) + +**Symbols:** model.ts:98, 109. + +**Issue:** At 36 / 37 characters these are among the longest type names in the +package. The names are accurate but heavy; within the package scope, just +`ListRequest` / `ListResponse` would suffice. However, the Go SDK pattern (mirrored +across the entire TS SDK) qualifies every request/response with the full operation +name, so this is consistent with the wider convention. Flag only — do not change +in isolation. + +### 21. Method name `listCleanRoomNotebookTaskRunsHandlerIter` is 41 chars — +category 7 (Overly verbose) + +**Symbol:** `Client.listCleanRoomNotebookTaskRunsHandlerIter` (client.ts:97). + +**Issue:** Combine with finding 1: drop `Handler` to land at +`listCleanRoomNotebookTaskRunsIter` (33 chars). The `Iter` suffix is the project's +canonical name for the async-iterator paginator (used in `cleanrooms`, +`cleanroomassets`, etc.) and should stay. Note: TS-idiomatic alternatives include +naming the iterator method without a suffix and using JSDoc to indicate it's an +iterator, but project convention is `Iter`. + +### 22. Function `listCleanRoomNotebookTaskRunsHandlerIter` plural "runs" inside +the async generator yielding singular `CleanRoomNotebookTaskRun` — category 9 +(Singular/plural mismatch) — *pass* + +The convention in the SDK is `list…Iter()` returns an `AsyncGenerator`, +so plural method name + singular yield is intentional and consistent. No fix. + +### 23. `Client` class name — category 1 (Vague/generic) — *pass* + +Package convention. Every TS package exports a single `Client` class scoped to its +import path (e.g. `@databricks/sdk-cleanroomtaskruns/v1`). + +### 24. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) + +**Symbol:** `PACKAGE_SEGMENT` (client.ts:27). + +**Issue:** TS style for module-level constants is `camelCase` for runtime values +that aren't true primitive constants. Google TS Style Guide §5.1 +("const enums and constants must use UPPER_SNAKE_CASE only when they refer to +true constant values… else use camelCase"). `PACKAGE_SEGMENT` is a runtime object +(`{key, value}`) and is `const` only by declaration. However, the same name is +used in every package's client.ts (verify: ran into it in `cleanrooms`, +`cleanroomassets`, …) — it is a convention. Flag only for consistency, do not +fix in isolation. + +### 25. `userAgent` and `httpClient` — *pass* + +Standard names; acronym handling is consistent (`Url` would be flagged but +`HttpClient` is acceptable under the project rule and matches the imported type). + +### 26. `marshalRequest` / `unmarshal*Schema` — category 14 (Go/Java-style names) + +**Symbols:** `marshalRequest` (utils.ts:119), the four `unmarshal*Schema` +constants (model.ts:119, 152, 163, 180). + +**Issue:** "Marshal" / "Unmarshal" is Go vocabulary. The TS ecosystem uses +"serialize" / "deserialize" or, when working with Zod, "parse" / "stringify". +This is a project-wide convention copied from Go; it is consistent here, but it +is a Go-ism. Flag for the broader SDK review, not this package alone. + +### 27. `flattenQueryParams` — *pass*, but unused (dead code) + +**Symbol:** `flattenQueryParams` (utils.ts:123). + +**Issue:** Imported nowhere within this package's client (the `list` method builds +its querystring inline at client.ts:64–72). The helper is dead code in this +package. Naming itself is fine. Suggest deleting or extracting to a shared utility +in `@databricks/sdk-core/http`. (Same applies to `marshalRequest` — declared but +unused inside the package.) + +### 28. `executeCall` vs `executeHttpCall` — category 17 (Inconsistent action verbs) + +**Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). + +**Issue:** Two functions named `execute…Call`. `executeCall` is the public API +wrapper that calls `execute()` from `@databricks/sdk-core/api`. `executeHttpCall` +performs an HTTP request and decodes the body. They do *different* things at +*different* layers — but the names imply a hierarchical relationship that does not +exist. The HTTP one is roughly `sendAndDecode` or `doHttpRequest`. Flag for SDK-wide +naming cleanup; this file is generated boilerplate copied across every package. + +### 29. `readAll(body)` — *pass* + +Helper does what its name says. + +### 30. `HttpCallOptions` (utils.ts:15) — category 1 (Vague) and category 20 +(Type-suffix tautology) + +**Symbol:** `HttpCallOptions` interface. + +**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the +neighbouring `CallOptions` exists in `@databricks/sdk-options/call`. Naming both +in the same file confuses readers — which "Call" do they mean? Suggest +`HttpRequestContext` or `ExecuteHttpArgs`. Flag for SDK-wide cleanup. + +--- + +## Cross-package notes (per audit instructions) + +### `TaskRun` concept divergence between `cleanroomtaskruns` and `jobs/v2` + +| Aspect | `cleanroomtaskruns/v1` | `jobs/v2` | +|--------|------------------------|-----------| +| LifeCycle enum name | `CleanRoomTaskRunLifeCycleState` | `CleanRoomTaskRunLifeCycleState_CleanRoomTaskRunLifeCycleState` | +| Result enum name | `CleanRoomTaskRunResultState` | `CleanRoomTaskRunResultState_CleanRoomTaskRunResultState` | +| State struct | `CleanRoomTaskRunState` | `CleanRoomTaskRunState` (same name, identical shape) | +| Field referencing state | `notebookJobRunState` | `cleanRoomJobRunState` (jobs/v2/model.ts:1158) | + +The proto-style nested enum name `X_X` exists only in `jobs/v2`; the +`cleanroomtaskruns/v1` flat name is cleaner. Audit categories 12 (duplicate +concepts) and 2 (redundant prefixes) — strong recommendation: the generator +should reuse the `cleanroomtaskruns` flat names from `jobs/v2` (or both packages +should re-export from a single shared module) to avoid the doubled-prefix +oddity in `jobs`. This is a *generator* concern, not a `cleanroomtaskruns` +package concern — flag for the SDK platform team. + +Same goes for the state-field name: `notebookJobRunState` here, `cleanRoomJobRunState` +in jobs/v2 — two names for one wire-level concept. + +### `NotebookTask` concept + +`CleanRoomNotebookTaskRun` (this package) → `CleanRoomsNotebookTask` (jobs/v2, +note plural "Rooms"!) → `CleanRoomNotebookTask` (jobs/v2, deprecated V0). Three +spellings of "clean room(s) notebook task" across two packages. Specifically, +the jobs/v2 package has `CleanRoomsNotebookTask` (plural rooms, +model.ts:1141) explicitly distinguished from the deprecated `CleanRoomNotebookTask` +(singular). This package uses the singular form `CleanRoomNotebookTaskRun`. The +intent is consistent — singular when referring to a specific room, plural for the +service name — but a reader is left to guess. + +--- + +## Summary (counts) + +- **Critical / cross-package consistency:** 1 finding (#1 `Handler` suffix). +- **High (style guide violations):** 3 findings (#3 enum casing, #5 LifeCycle + casing, #13 collaborator prefix repetition). +- **Medium (naming clarity):** 8 findings (#2, #6, #9, #10, #11, #14, #16, #17). +- **Low / project-wide convention notes:** 11 findings (#4, #7, #8, #12, #15, + #18, #19, #21, #24, #26, #27, #28, #29, #30) — some inherited from generator. +- **Pass / acceptable as-is:** 4 findings (#19, #22, #23, #25, #29). + +**Total flagged findings: 24** distinct items across 20 categories (some +findings touch multiple categories). diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md new file mode 100644 index 00000000..6ad9ebcd --- /dev/null +++ b/.agent/naming-audit/clusterlibraries.md @@ -0,0 +1,702 @@ +# Naming Audit: `clusterlibraries` (v2) + +Path: `/home/parth.bansal/sdk-js/packages/clusterlibraries/` +Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/utils.ts`, `src/v2/index.ts` +Scope: every type, field, enum value, method, and exported identifier. + +Findings are grouped by category. Severity reflects the impact on TS consumers +of the SDK; "high" means a name will mislead, surprise, or conflict; "medium" +means it is awkward or inconsistent; "low" means a minor blemish. + +--- + +## 1. Vague / generic names + +### 1.1 `Library.lib` — `model.ts:159` +- `Library` already names the concept; the inner discriminated-union field + `lib` is a shortened duplicate of the parent type name. +- The wire schema spreads the variants flat at the top level (`jar`, `egg`, + `pypi`, etc.). The `lib` wrapper is a TS-only artifact for the tagged-union + encoding. A more descriptive name would be `source`, `spec`, `package`, or + `variant` (since it discriminates which package source/format applies). +- Severity: medium. Consumers must write `library.lib.jar` which reads as + redundant. + +### 1.2 `DefaultBaseEnvironment.message` — `model.ts:92` +- `message` is generic and could mean log message, error message, info text, + user-facing description, etc. Coupled with `status`, this is almost + certainly a status/error message. Name like `statusMessage` would be more + precise. +- Same issue on `DefaultBaseEnvironmentCache.message` (`model.ts:103`). +- Severity: low. + +### 1.3 `Environment.client` — `model.ts:116` +- Field is itself documented as deprecated ("Use `environment_version` + instead.") and the name `client` is opaque in this context (a client of + what?). The successor field `environmentVersion` is clearer. Cannot rename + without breaking the wire contract, but worth flagging that the name is + intrinsically misleading. +- Severity: medium (deprecated, but still visible in the type surface). + +### 1.4 `RCranLibrary.package`, `PythonPyPiLibrary.package` — `model.ts:289, 299` +- `package` is a reserved word in JavaScript (future-reserved, strict mode) + and conveys little semantic content beyond "package". Consider + `coordinate`, `name`, or `packageName`. See also §10. +- Severity: medium. + +### 1.5 `MavenLibrary.repo`, `PythonPyPiLibrary.repo`, `RCranLibrary.repo` + — `model.ts:274, 294, 301` +- `repo` is an abbreviation. The companion `repo` documentation says + "repository". `repository` (or `repositoryUrl`) would be more explicit. See + also §5. +- Severity: low. + +--- + +## 2. Redundant enum prefixes + +### 2.1 `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — `model.ts:7` +- Enum value embeds the enum name as a prefix. In TS, the canonical access + is `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED`, which is + triply redundant ("BaseEnvironmentType" repeated). Value `UNSPECIFIED` + would suffice idiomatically; the prefix is a proto-enum convention that + does not survive the port intact. +- Severity: medium. + +### 2.2 `DefaultBaseEnvironmentCache_Status.STATUS_UNSPECIFIED` — `model.ts:47` +- Same pattern: enum value `STATUS_UNSPECIFIED` inside an enum already + carrying `Status` in its (compound) name. Bare `UNSPECIFIED` would be + unambiguous. +- Severity: medium. + +--- + +## 3. Acronym casing inconsistencies + +### 3.1 `PythonPyPiLibrary` — `model.ts:284, 512, 686` +- Mixed casing for the PyPI acronym. The canonical brand name is **PyPI** + (Python Package Index, https://pypi.org). The TS identifier uses `PyPi` + which is neither pure brand casing nor TS acronym convention. Should be + either `PythonPyPiLibrary` -> `PythonPyPILibrary` (brand) or — and this + is the larger issue — the type itself is double-prefixed: it already + belongs to a category of Python ecosystem things, so the prefix `Python` + is also a tautology since "PyPI" is exclusively Python. `PypiLibrary` or + `PyPILibrary` would be cleaner. +- The `$case: 'pypi'` literal further uses lowercase `pypi`, which is fine + for a wire tag but inconsistent with the type name regardless of which + casing wins. +- Severity: high (a brand-name spelling error visible in every consumer + using PyPI packages). + +### 3.2 `RCranLibrary` — `model.ts:297, 522, 696` +- "CRAN" (Comprehensive R Archive Network) is an all-caps acronym. The TS + identifier renders it `Cran`. By TS/Google style guidance acronyms longer + than two letters are typically PascalCased ("Cran"), but the resulting + `RCranLibrary` mixes a one-letter prefix `R` (uppercase) with the lowercase + acronym, which reads oddly (is it "R-Cran" or "RC-Ran"?). `CranLibrary` + alone would be unambiguous (CRAN is R-specific); the `R` prefix is the + same tautology as `Python` on `PythonPyPiLibrary`. +- The discriminator `$case: 'cran'` is consistent with the type tag. +- Severity: medium. + +### 3.3 `Library.whl` — `model.ts:198, 206` +- "Whl" is the file-extension shorthand for Python wheels. The wire format + uses `whl`, but the TS type otherwise uses long-form names (`jar`, + `requirements`, `egg`). `wheel` would be more readable in TS but is a + wire-contract concern (cannot rename without breaking compatibility). +- Severity: low (flagged for completeness — abbreviation, not strictly a + casing issue). + +### 3.4 `traceId` vs `trace_id` query param — `client.ts:222-224` +- Field is camelCase TS but serializes to snake_case on the wire. Consistent + with all other fields; flagged only because the JSDoc on `traceId` + (`model.ts:144`) hints at the deprecated nature of the param but uses + identifier `ctx.requestId` — no `ctx` exists in this package. The hint + refers to Go context which does not exist in the TS port; left over from + Go SDK documentation. +- Severity: low (doc bug, not a name bug). + +--- + +## 4. Underscores in TS identifiers + +### 4.1 `DefaultBaseEnvironmentCache_Status` — `model.ts:46` +- Underscore is non-idiomatic in TS PascalCase identifiers. This is a + proto-style nested name (`DefaultBaseEnvironmentCache.Status`) flattened + by underscore. The file already has an explicit eslint-disable comment + acknowledging this. A namespace or nested type would be more TS-native: + `namespace DefaultBaseEnvironmentCache { enum Status {...} }` or + rename to `DefaultBaseEnvironmentCacheStatus` (drop the underscore). +- Severity: high (every consumer importing this enum sees the underscore). + +### 4.2 `InstallLibraries_Response` — `model.ts:156, 417` +- Same pattern: proto-style nested name flattened by underscore. The eslint + comment acknowledges it. See also §20 (suffix redundancy). +- Severity: high. + +### 4.3 `UninstallLibraries_Response` — `model.ts:319, 536` +- Same. Severity: high. + +### 4.4 `ListAllClusterLibraryStatuses_Response` — `model.ts:235, 467` +- Same. Severity: high. + +### 4.5 Marshal/unmarshal schema constants — `model.ts:417, 467, 536` +- `unmarshalInstallLibraries_ResponseSchema` and similar embed the + underscore. These follow the type names so they propagate the issue. +- Severity: medium (internal helpers, but still exported). + +--- + +## 5. Cryptic abbreviations + +### 5.1 `Library.jar`, `Library.egg`, `Library.whl` — `model.ts:158-217` +- Single-extension abbreviations as field names. Wire-locked, but the type + surface would be more discoverable with `jarUri`, `wheelUri`, etc. The + `requirements` field at the same level uses the long form, so the variants + are inconsistent within one type. +- Severity: low (wire compatibility constraint). + +### 5.2 `repo` — multiple types +- See §1.5. Short form of `repository`. Severity: low. + +### 5.3 `Library.pypi`, `Library.cran` — `model.ts:177-196` +- Lower-cased acronyms as field tags. Acceptable for wire compatibility, + but the inconsistency with the (camelCased) type names (`PythonPyPiLibrary`, + `RCranLibrary`) is jarring. See §3. +- Severity: low. + +### 5.4 `filepath` — `model.ts:90` +- Single-word concatenation. TS convention prefers compound words like + `filePath`. The wire uses `filepath` (one word) so the camelCase form + mirrors it; arguably the wire spelling is also non-standard (most APIs + use `file_path` or `path`). +- Severity: low. + +--- + +## 6. Misleading names + +### 6.1 `updateDefaultDefaultBaseEnvironment` — `client.ts:429` +- Method name contains "Default" twice ("the Default Default Base + Environment"). The intent is clearer from the JSDoc: this method sets + *which* DefaultBaseEnvironment (DBE) is the workspace's default. So the + method is really `setWorkspaceDefaultBaseEnvironment` (or `setDefaultDbe` + /` setWorkspaceDefault`). The doubled "Default" is a literal artifact of + combining the `UpdateDefault___` HTTP verb with the `___DefaultBaseEnvironment` + resource name. +- Severity: high. This method name is the most surprising in the package. + +### 6.2 `UpdateDefaultDefaultBaseEnvironmentRequest` — `model.ts:326` +- Same problem on the request type. Severity: high. + +### 6.3 `marshalUpdateDefaultDefaultBaseEnvironmentRequestSchema` — `model.ts:736` +- Same. Severity: high. + +### 6.4 `ClusterStatus` — `model.ts:63` +- The type holds only a `clusterId` and is used as the request body for + `clusterStatus()`. Naming it `ClusterStatus` suggests it *is* the status, + but it is a request that fetches status. Better: `ClusterStatusRequest` + or `GetClusterStatusRequest`. The accompanying response type is named + `ClusterLibraryStatuses` (correct). +- Severity: high (the type name lies about its role). + +### 6.5 `LibraryFullStatus` — `model.ts:220` +- "Full" implies there is a "Partial" or "Short" counterpart, but there is + none in this package. The type is "the status of a library on a cluster" + per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. +- Severity: medium. + +### 6.6 `LibraryInstallStatus` value `RESTORED` — `model.ts:42` +- The docstring says "Library installation is restored and can be used." + But `RESTORED` overlaps semantically with `INSTALLED`. Without further + context (cache restore vs. fresh install), consumers cannot distinguish. + Name is technically accurate but underspecified. +- Severity: low. + +### 6.7 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:35` +- This is the only value that is an action+condition (rather than a state + noun). Surrounding values are `PENDING`, `INSTALLED`, `FAILED`. A noun + form like `PENDING_UNINSTALL` would line up. +- Severity: medium. + +### 6.8 `allClusterStatuses()` — `client.ts:91` +- Method is the GET for `all-cluster-statuses`. The TS method name reads + like an adjective ("all-cluster statuses") and is not verb-prefixed. + Sibling method is `clusterStatus()` (also verb-less). Compare with the + rest of the client: `installLibraries`, `uninstallLibraries`, + `createDefaultBaseEnvironment`, etc. (all verb-prefixed). The two GET + methods alone are exempt. Should be `listAllClusterStatuses` or + `getAllClusterStatuses`, and `getClusterStatus` respectively. +- Severity: medium. See also §16. + +### 6.9 `Environment` — `model.ts:114` +- Type name is generic but the comment makes clear it is the "environment + spec" used in serverless side-panel / job-task / pipeline contexts. A + more specific name like `EnvironmentSpec` or `WorkspaceEnvironment` would + avoid collisions with the JS global `process.env` mental model. +- Severity: low. + +### 6.10 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` +- The JSDoc says "when the materialized env is updated" — sufficient but + the type itself does not carry the materialized payload (e.g., a hash, + ID, or contents). The name overpromises relative to the contents; + `EnvironmentCacheEntry` would be more honest. +- Severity: medium. + +### 6.11 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` — `model.ts:101` +- "Indefinite" is unexplained anywhere in the file. It pairs with + `materializedEnvironment` but the semantic distinction is opaque. The + name needs a doc or rename. +- Severity: medium. + +### 6.12 `Environment.baseEnvironment` — `model.ts:131` +- A field inside `Environment` is also named `baseEnvironment` (same root + word), which makes the relationship between the type and the field + recursive-looking even though the field is just a path/ID string. + Better: `baseEnvironmentRef` or `baseEnvironmentPath`. +- Severity: low. + +--- + +## 7. Overly verbose names + +### 7.1 `marshalUpdateDefaultDefaultBaseEnvironmentRequestSchema` — `model.ts:736` +- 50 characters of identifier, of which much is redundant ("Default" twice). + See §6.1. Severity: medium. + +### 7.2 `unmarshalListAllClusterLibraryStatuses_ResponseSchema` — `model.ts:467` +- 53 characters and includes both an underscore (§4) and "All" (which is + also encoded in the URL `/api/2.0/libraries/all-cluster-statuses`). The + type name `ListAllClusterLibraryStatuses` is itself verbose — `ListLibraryStatuses` or + `ListClusterStatuses` would suffice. +- Severity: medium. + +### 7.3 `UninstallLibraries_Response`, `InstallLibraries_Response` — `model.ts:156, 319` +- Verbose, underscored names. See §4. +- Severity: medium. + +--- + +## 8. Redundant suffixes + +### 8.1 Marshal/unmarshal schemas — `model.ts:331-746` +- All schemas end with `Schema`, but they are typed `z.ZodType<...>` which + already conveys their schema nature. Inside the file the suffix may aid + reading, but on a wide API surface `unmarshalLibrarySchema` reads as + "Schema schema". Common enough in zod codebases that this is borderline + acceptable; flagged for completeness. +- Severity: low. + +### 8.2 `LibraryFullStatus` — `model.ts:220` +- "Full" is a vestigial qualifier with no counterpart. See §6.5. +- Severity: medium. + +### 8.3 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +- Field name repeats the parent's middle word (Library). Could simply be + `statuses`. Borderline acceptable for clarity. +- Severity: low. + +### 8.4 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` +- Field is just `statuses` while the type bakes in `LibraryStatuses` + plurality and `ClusterLibrary` qualifier. Inconsistent with §8.3 which + uses `libraryStatuses`. +- Severity: low. + +--- + +## 9. Singular/plural mismatches + +### 9.1 `MavenLibrary.exclusions` — `model.ts:281` +- Plural; field is a list. Doc says "List of dependences to exclude" — + consistent. No issue (note: "dependences" is a typo for "dependencies", + inherited from the API doc string). +- Severity (typo): low. + +### 9.2 `ListAllClusterLibraryStatuses` (request) vs `_Response.statuses` + — `model.ts:232, 237` +- Singular method name `allClusterStatuses` (`client.ts:91`) for what is + semantically a list operation. Compare `listDefaultBaseEnvironments` + (`client.ts:276`). The action verb should be `list` for both. See §16. +- Severity: medium. + +### 9.3 `DefaultBaseEnvironment.baseEnvironmentCache` — `model.ts:93` +- Singular name but typed `DefaultBaseEnvironmentCache[]` (array). Should + be `baseEnvironmentCaches` (or, if it really represents one cache lineage, + the type definition is wrong). The Go SDK convention would surface this + via Go's "[]" — in TS the plural-ness must be in the name. +- Severity: high. + +--- + +## 10. Reserved-word collisions + +### 10.1 `PythonPyPiLibrary.package`, `RCranLibrary.package` — `model.ts:289, 299` +- `package` is a future-reserved word in ECMAScript (strict mode reserved). + It is legal as an object property name and a parameter, but it is awkward + to destructure: `const {package: pkg} = ...`. The wire field is `package`, + so renaming requires marshal/unmarshal indirection (the file already does + that for snake_case translation). Alternative: `packageName` or + `coordinate` (the same concept Maven uses). +- Severity: high (forces renaming on destructure). + +### 10.2 No other reserved-word issues observed. + +--- + +## 11. Duplicate concepts + +### 11.1 `LibraryInstallStatus` vs `DefaultBaseEnvironmentCache_Status` — `model.ts:13, 46` +- Two `Status` enums in the same file, each with `PENDING` / `FAILED` + members but different domains. Acceptable since they live in different + contexts, but consider naming differently to avoid import-site confusion + (e.g., `LibraryStatus` vs `DbeCacheStatus`). +- Severity: low. + +### 11.2 `InstallLibraries` (request) vs `installLibraries()` (method) + — `model.ts:148, client.ts:250` +- Method and request type share a name, distinguished only by case. TS + convention works here because the type lives in the type namespace and + the method in the value namespace. Fine. + +### 11.3 `Environment` vs `MaterializedEnvironment` vs `DefaultBaseEnvironment` + — `model.ts:78, 114, 262` +- Three closely related types with overlapping names. The relationship + (DBE contains an Environment; cache holds MaterializedEnvironment) is + not obvious from names alone. Documentation compensates, but new + consumers face a name-soup. No surface fix; flagged for awareness. +- Severity: low. + +### 11.4 `marshalRequest` vs implicit `JSON.stringify` — `utils.ts:119` +- Helper validates with zod then stringifies. Name suggests it could be + used for any "request", but it is generic enough to marshal any value. + Misleading-by-narrowing. `marshalToJson` would be clearer. (Utility scope.) +- Severity: low. + +--- + +## 12. Verb-tense inconsistency + +### 12.1 Method verbs across the client — `client.ts:91-456` +- `allClusterStatuses` and `clusterStatus` are verb-less (noun-only). +- `installLibraries`, `uninstallLibraries`, `createDefaultBaseEnvironment`, + `deleteDefaultBaseEnvironment`, `getDefaultBaseEnvironment`, + `listDefaultBaseEnvironments`, `refreshDefaultBaseEnvironments`, + `updateDefaultBaseEnvironment`, `updateDefaultDefaultBaseEnvironment` + use verb-prefixed forms. +- Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: + `listAllClusterStatuses` (or `getAllClusterStatuses`) and + `getClusterStatus`. See §6.8 and §16. +- Severity: high (consistency of the verb-prefix is a Java/TS SDK convention + that consumers rely on). + +### 12.2 `LibraryInstallStatus` action vs state values — `model.ts:13` +- Values mostly nouns (`PENDING`, `INSTALLED`, `FAILED`) but one verb + imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §6.7. +- Severity: medium. + +--- + +## 13. Go/Java-style names + +### 13.1 `_Response` suffix on types — `model.ts:156, 235, 319` +- The `Operation_Response` underscore pattern mirrors Go's nested message + generation (proto messages emit `Op.Response`). In TS, namespace nesting + or direct naming (`InstallLibrariesResponse`) is more idiomatic. The + generator's choice to use underscore loses the readability of the original + proto nesting without buying anything. +- Severity: high. + +### 13.2 `DefaultBaseEnvironmentCache_Status` — `model.ts:46` +- Same. Severity: high. + +### 13.3 `marshalRequest` / `parseResponse` / `executeHttpCall` — `utils.ts` +- Function names follow Go/Java SDK convention (verbs). Fine for TS too. + +### 13.4 Schema variable casing — `model.ts:331+` +- `marshalXxxSchema` / `unmarshalXxxSchema` constants follow Go SDK casing + conventions. Idiomatic enough in TS but the lengths get long (§7.2). + +### 13.5 `Library.lib` discriminator field — `model.ts:159` +- `$case` literal on the discriminator is a ts-proto / nanopb-style emission + (e.g., the same pattern as ts-proto's discriminated union output). Not + unidiomatic for TS, but `kind`, `type`, or `tag` would be more readable + to a consumer with no Go/proto background. +- Severity: low. + +--- + +## 14. Generic field names losing meaning + +### 14.1 `DefaultBaseEnvironment.environment` — `model.ts:89` +- A field named `environment` inside a type already named + `DefaultBaseEnvironment` is recursive-looking. The doc clarifies it is + the embedded `Environment` spec — but `environmentSpec` or + `inlineEnvironment` would convey "this is the actual environment + description, distinct from the wrapping metadata". +- Severity: medium. + +### 14.2 `DefaultBaseEnvironment.name`, `.id`, `.message` — `model.ts:79, 80, 92` +- Bare `id`, `name`, `message` are extremely generic. In context they are + unambiguous, but a programmer using auto-complete on a result list of + many resources may not be able to tell them apart. Cluster-level naming + would benefit from `dbeId`, `dbeName`. The Go SDK uses bare `Id` because + Go scopes them under the package; TS does too via the type, so the + generic forms are fine. +- Severity: low. + +### 14.3 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` + — `model.ts:75` +- An ID field named `workspaceBaseEnvironmentId` inside a "create DBE" + request. The `workspace` prefix implies a different resource (workspace + base environment) than the request's payload (`defaultBaseEnvironment`). + Documentation does not explain the relationship. The name is precise + but the role is unclear without docs. +- Severity: medium. + +--- + +## 15. Field contradicting type domain + +### 15.1 `Environment.client` — `model.ts:116` +- "Client" inside an Environment spec is unexpected; the doc clarifies it + is a deprecated stand-in for `environment_version`. The name belongs to + a different semantic domain (clients connect to environments, they are + not part of them). +- Severity: medium (deprecated, but exposed). + +### 15.2 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:228` +- Inside `LibraryFullStatus` (per-cluster status), a field that describes + whether the library is configured cluster-wide. The name reads like a + global property but the type belongs to a single cluster's view. Better: + `installedOnAllClusters` or `isClusterWideLibrary`. +- Severity: medium. + +### 15.3 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` +- Type is "materialized environment metadata"; the only field is a + timestamp. The materialization payload is missing — see §6.10. The + timestamp belongs in a cache-entry type, not a materialization type. +- Severity: medium. + +--- + +## 16. Inconsistent action verbs + +### 16.1 GET vs `list` vs `all` — `client.ts:91, 276` +- `allClusterStatuses()` (verb `all`) is structurally identical to + `listDefaultBaseEnvironments()` (verb `list`). Pick one. The Go SDK uses + the same naming, but the TS port has the opportunity to normalize. +- Severity: medium (see §12.1). + +### 16.2 `refreshDefaultBaseEnvironments` — `client.ts:333` +- `refresh` is a TS-idiomatic verb meaning re-fetch / re-compute. The + operation here regenerates a cache asynchronously. Borderline OK, but + consumers may expect `refresh()` to return updated data; this returns + an empty response. `regenerateCache(s)` or `invalidateCache(s)` would + reflect the side-effect more honestly. +- Severity: low. + +### 16.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL — `client.ts:433` +- The URL says `:setDefault` but the method says `updateDefaultDefault`. + `setDefaultBaseEnvironment` or `setWorkspaceDefault` would mirror the + URL semantics. See §6.1. +- Severity: high. + +### 16.4 `installLibraries` / `uninstallLibraries` — `client.ts:250, 368` +- Symmetric pair, good. Mirror request types `InstallLibraries` / + `UninstallLibraries` (named after the operation, not the resource). + Consistent. + +--- + +## 17. Long enum values + +### 17.1 `LibraryInstallStatus.UNINSTALL_ON_RESTART` — `model.ts:35` +- 20 characters; the only multi-word value. Acceptable since it conveys + semantics, but combined with the prefix `LibraryInstallStatus.` the + full reference is 41 characters. See also §6.7. +- Severity: low. + +### 17.2 `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — `model.ts:7` +- Total reference: `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` + = 51 chars. See §2.1. +- Severity: medium. + +--- + +## 18. Underspecified IDs + +### 18.1 `CreateDefaultBaseEnvironmentRequest.requestId` — `model.ts:74` +- Idempotency UUID. Name is OK but generic; `idempotencyKey` would be more + precise. +- Severity: low. + +### 18.2 `GetDefaultBaseEnvironmentRequest.traceId` — `model.ts:145` +- Deprecated field. Name is OK; the comment hints at a missing replacement. + Could be `traceId?: string` with a `@deprecated` JSDoc tag. +- Severity: low. + +### 18.3 `DefaultBaseEnvironment.creatorUserId`, `.lastUpdatedUserId` + — `model.ts:81, 83` +- Both are typed `number`. Databricks user IDs may exceed 2^53; bare + `number` risks precision loss for very large IDs. (Naming-adjacent + issue: the name `creatorUserId` is fine, but the *type* is undersized.) + Compare with the Go SDK where these are `int64`. +- Severity: medium (type, not name) — flagged because it bears on + consumer expectations about ID identifiers. + +### 18.4 `DefaultBaseEnvironment.principalIds` — `model.ts:94` +- `number[]` with no domain (workspace principals, account principals?). + `Principal` is ambiguous in Databricks (user, SP, group). `principalIds` + needs scope, like `workspacePrincipalIds`. +- Severity: medium. + +### 18.5 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` + — `model.ts:75` +- See §14.3. Underspecified relationship with the rest of the request. +- Severity: medium. + +### 18.6 `ClusterLibraryStatuses.clusterId`, `ClusterStatus.clusterId`, + `InstallLibraries.clusterId`, `UninstallLibraries.clusterId` + — `model.ts:58, 65, 150, 313` +- Bare `clusterId` everywhere. Good consistency. No issue. + +### 18.7 `DefaultBaseEnvironment.id` — `model.ts:79` +- Bare `id`. With sibling `creatorUserId` etc., a name like `dbeId` + would be more grep-able. The Go SDK uses bare `Id` due to package + scoping; TS scopes via the type so this is OK. +- Severity: low. + +### 18.8 `RefreshDefaultBaseEnvironmentsRequest.ids` — `model.ts:305` +- Untyped collection of IDs of what? Doc-less. `dbeIds` or + `defaultBaseEnvironmentIds` would be unambiguous. +- Severity: medium. + +--- + +## 19. Type-suffix tautology + +### 19.1 `LibraryFullStatus` — `model.ts:220` +- "Status" appears in the type name and the field `status: LibraryInstallStatus` + contains the noun again. Not a tautology per se, but the parent + `LibraryFullStatus` could be `LibraryReport` or just `LibraryStatus` (with + the inner field becoming `state` to avoid the duplicate). +- Severity: low. + +### 19.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +- Already noted in §8.3. +- Severity: low. + +### 19.3 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` +- Type name carries the suffix; field name is bare. Inconsistent with + §19.2 but otherwise fine. +- Severity: low. + +### 19.4 `ListDefaultBaseEnvironmentsResponse.defaultBaseEnvironments` + — `model.ts:246` +- Field name repeats the resource noun. Standard list-response pattern + used across the SDK; no fix. +- Severity: low. + +--- + +## Cross-cutting summary + +### High-severity (consumer-facing surprises) + +- `updateDefaultDefaultBaseEnvironment` / `UpdateDefaultDefaultBaseEnvironmentRequest` + / `marshalUpdateDefaultDefaultBaseEnvironmentRequestSchema` (§6.1, §6.2, + §6.3): the "Default Default" doubling is the most jarring naming in the + package. Best resolved by renaming the public API to + `setWorkspaceDefaultBaseEnvironment`. +- All `_Response` and `_Status` underscore types (§4, §13.1): non-idiomatic + in TS, repeatedly exported, every importer sees them. +- `PythonPyPiLibrary` brand-casing inconsistency (§3.1): "PyPi" misspells + the PyPI brand. +- `ClusterStatus` request type misleading-as-response (§6.4). +- `baseEnvironmentCache: DefaultBaseEnvironmentCache[]` singular-on-array + (§9.3). +- `package` reserved-word collision on PyPI and CRAN libraries (§10.1). +- Verb-tense gap: `allClusterStatuses()` and `clusterStatus()` break the + client's prevailing verb-prefix convention (§12.1, §16.1). + +### Medium-severity + +- Enum values embedding the enum name (§2.1, §2.2). +- `LibraryFullStatus` with no "non-full" counterpart (§6.5). +- `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state + (§6.7, §12.2). +- `MaterializedEnvironment` containing only a timestamp (§6.10). +- `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` + unexplained (§6.11). +- `isLibraryForAllClusters` field name awkwardly straddles per-cluster + and global domains (§15.2). + +### Low-severity / stylistic + +- `repo` vs `repository` short form (§1.5). +- `whl`, `jar`, `egg` extension-as-field-name (§5.1). +- `filepath` one-word concatenation (§5.4). +- Schema constants' `Schema` suffix (§8.1). +- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§6.6). +- "dependences" typo in `MavenLibrary.exclusions` doc (§9.1). + +--- + +## Inventory (for completeness) + +Enums audited: +- `BaseEnvironmentType` (model.ts:6). +- `LibraryInstallStatus` (model.ts:13). +- `DefaultBaseEnvironmentCache_Status` (model.ts:46). + +Interfaces audited: +- `ClusterLibraryStatuses` (56). +- `ClusterStatus` (63). +- `CreateDefaultBaseEnvironmentRequest` (68). +- `DefaultBaseEnvironment` (78). +- `DefaultBaseEnvironmentCache` (99). +- `DeleteDefaultBaseEnvironmentRequest` (106). +- `Environment` (114). +- `GetDefaultBaseEnvironmentRequest` (142). +- `InstallLibraries` (148). +- `InstallLibraries_Response` (156). +- `Library` (158). +- `LibraryFullStatus` (220). +- `ListAllClusterLibraryStatuses` (232). +- `ListAllClusterLibraryStatuses_Response` (235). +- `ListDefaultBaseEnvironmentsRequest` (240). +- `ListDefaultBaseEnvironmentsResponse` (245). +- `MaterializedEnvironment` (262). +- `MavenLibrary` (267). +- `PythonPyPiLibrary` (284). +- `RCranLibrary` (297). +- `RefreshDefaultBaseEnvironmentsRequest` (304). +- `RefreshDefaultBaseEnvironmentsResponse` (309). +- `UninstallLibraries` (311). +- `UninstallLibraries_Response` (319). +- `UpdateDefaultBaseEnvironmentRequest` (321). +- `UpdateDefaultDefaultBaseEnvironmentRequest` (326). + +Methods audited (`client.ts`): +- `allClusterStatuses` (91). +- `clusterStatus` (127). +- `createDefaultBaseEnvironment` (162). +- `deleteDefaultBaseEnvironment` (194). +- `getDefaultBaseEnvironment` (213). +- `installLibraries` (250). +- `listDefaultBaseEnvironments` (276). +- `listDefaultBaseEnvironmentsIter` (312). +- `refreshDefaultBaseEnvironments` (333). +- `uninstallLibraries` (368). +- `updateDefaultBaseEnvironment` (400). +- `updateDefaultDefaultBaseEnvironment` (429). + +Utilities audited (`utils.ts`): +- `HttpCallOptions` (15). +- `executeCall` (26). +- `readAll` (40). +- `executeHttpCall` (65). +- `buildHttpRequest` (96). +- `parseResponse` (113). +- `marshalRequest` (119). +- `flattenQueryParams` (123). diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md new file mode 100644 index 00000000..42224c35 --- /dev/null +++ b/.agent/naming-audit/clusterpolicies.md @@ -0,0 +1,352 @@ +# Naming Audit: `clusterpolicies` (v2) + +**Package:** `@databricks/sdk-clusterpolicies` +**Path:** `/home/parth.bansal/sdk-js/packages/clusterpolicies/` +**Version audited:** `v2` +**Files audited:** + +- `src/v2/model.ts` +- `src/v2/client.ts` +- `src/v2/utils.ts` +- `src/v2/index.ts` + +This audit catalogues every identifier (type, field, enum value, method, +constant) in the package and flags naming concerns against the 20-category +rubric. Issues are graded: + +- **High** — actively misleading, ambiguous, or violates a TS rule. +- **Medium** — friction; verbose, redundant, or stylistically off. +- **Low** — nit / consistency observation; safe to ignore. + +--- + +## 1. Inventory + +### 1.1 Enums (`model.ts`) + +| Name | Members | +| ----------------- | ------------------------------------------------ | +| `ListOrder` | `DESC`, `ASC` | +| `PolicySortColumn`| `POLICY_CREATION_TIME`, `POLICY_NAME` | + +### 1.2 Interfaces (`model.ts`) + +| Name | Purpose | +| -------------------------- | --------------------------------------------- | +| `CreatePolicy` | Request body for create. | +| `CreatePolicy_Response` | Response from create (proto-style suffix). | +| `DeletePolicy` | Request body for delete. | +| `DeletePolicy_Response` | Empty response from delete. | +| `EditPolicy` | Request body for update/edit. | +| `EditPolicy_Response` | Empty response from edit. | +| `GetPolicy` | Request body for get. | +| `Library` | Discriminated-union wrapper around `lib`. | +| `ListPolicies` | Request body for list. | +| `ListPolicies_Response` | Response from list. | +| `MavenLibrary` | Maven coordinates payload. | +| `Policy` | The cluster-policy entity. | +| `PythonPyPiLibrary` | PyPI package payload. | +| `RCranLibrary` | CRAN R package payload. | + +### 1.3 Fields (entity / request / response — combined catalog) + +| Type | Field | Type / Notes | +| -------------------------- | ---------------------------------- | ----------------------------- | +| `CreatePolicy` | `name` | `string?` | +| `CreatePolicy` | `definition` | `string?` | +| `CreatePolicy` | `description` | `string?` | +| `CreatePolicy` | `policyFamilyId` | `string?` | +| `CreatePolicy` | `policyFamilyDefinitionOverrides` | `string?` | +| `CreatePolicy` | `maxClustersPerUser` | `number?` | +| `CreatePolicy` | `libraries` | `Library[]?` | +| `CreatePolicy_Response` | `policyId` | `string?` | +| `DeletePolicy` | `policyId` | `string?` | +| `EditPolicy` | `policyId` | `string?` | +| `EditPolicy` | `name` … `libraries` | (same shape as `CreatePolicy`)| +| `GetPolicy` | `policyId` | `string?` | +| `Library` | `lib` | discriminated union | +| `Library.lib.$case` | `jar`/`egg`/`pypi`/`maven`/`cran`/`whl`/`requirements` | union tag | +| `ListPolicies` | `sortOrder` | `ListOrder?` | +| `ListPolicies` | `sortColumn` | `PolicySortColumn?` | +| `ListPolicies_Response` | `policies` | `Policy[]?` | +| `MavenLibrary` | `coordinates` | `string?` | +| `MavenLibrary` | `repo` | `string?` | +| `MavenLibrary` | `exclusions` | `string[]?` | +| `Policy` | `policyId` | `string?` | +| `Policy` | `creatorUserName` | `string?` | +| `Policy` | `createdAtTimestamp` | `number?` | +| `Policy` | `isDefault` | `boolean?` | +| `Policy` | `name` | `string?` | +| `Policy` | `definition` | `string?` | +| `Policy` | `description` | `string?` | +| `Policy` | `policyFamilyId` | `string?` | +| `Policy` | `policyFamilyDefinitionOverrides` | `string?` | +| `Policy` | `maxClustersPerUser` | `number?` | +| `Policy` | `libraries` | `Library[]?` | +| `PythonPyPiLibrary` | `package` | `string?` (reserved word) | +| `PythonPyPiLibrary` | `repo` | `string?` | +| `RCranLibrary` | `package` | `string?` (reserved word) | +| `RCranLibrary` | `repo` | `string?` | + +### 1.4 Methods (`client.ts`) + +| Method | Verb | Returns | +| --------------- | ---- | ------------------------ | +| `createPolicy` | POST | `CreatePolicy_Response` | +| `deletePolicy` | POST | `DeletePolicy_Response` | +| `editPolicy` | POST | `EditPolicy_Response` | +| `getPolicy` | GET | `Policy` | +| `listPolicies` | GET | `ListPolicies_Response` | + +### 1.5 Other identifiers + +- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields + `host`, `httpClient`, `logger`, `userAgent`. +- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, + `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`. +- Marshal / unmarshal schemas: `unmarshalCreatePolicy_ResponseSchema`, + `unmarshalDeletePolicy_ResponseSchema`, `unmarshalEditPolicy_ResponseSchema`, + `unmarshalLibrarySchema`, `unmarshalListPolicies_ResponseSchema`, + `unmarshalMavenLibrarySchema`, `unmarshalPolicySchema`, + `unmarshalPythonPyPiLibrarySchema`, `unmarshalRCranLibrarySchema`, + `marshalCreatePolicySchema`, `marshalDeletePolicySchema`, + `marshalEditPolicySchema`, `marshalLibrarySchema`, `marshalMavenLibrarySchema`, + `marshalPythonPyPiLibrarySchema`, `marshalRCranLibrarySchema`. + +--- + +## 2. Findings by Category + +### 2.1 Vague / generic names — High & Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| V-01 | `Library.lib` (field) | High | The field name `lib` is a meaningless abbreviation that conveys nothing the surrounding type doesn't already say. The wrapper interface is `Library`, so the discriminator field could be named `kind`, `variant`, `source`, or `spec`. As `lib`, callers must write `library.lib.$case === 'jar'`, which reads as "library library case". | +| V-02 | `MavenLibrary.repo`, `RCranLibrary.repo`, `PythonPyPiLibrary.repo` | Medium | `repo` is generic and overloaded across types. For Maven it is a Maven repository URL; for CRAN it is a CRAN mirror; for PyPI it is a pip index. Renaming to `repositoryUrl` (or even `mavenRepoUrl` / `cranMirrorUrl` / `pipIndexUrl`) would be more self-describing. | +| V-03 | `Policy.definition`, `CreatePolicy.definition`, `EditPolicy.definition` | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it's unclear it's a JSON document. `policyDefinition` (matches `policyFamilyDefinitionOverrides`) would be self-consistent. | +| V-04 | `Policy.description`, `CreatePolicy.description`, `EditPolicy.description` | Low | Generic but standard across the SDK; acceptable. | +| V-05 | `parseResponse` (utils) | Low | Generic, but it's local to the package. Acceptable. | +| V-06 | `flattenQueryParams` (utils) | Low | Reasonable. | + +### 2.2 Redundant enum prefixes — High + +| ID | Symbol | Severity | Issue | +| ----- | ------------------------------------- | -------- | ----- | +| E-01 | `PolicySortColumn.POLICY_CREATION_TIME` | High | The enum is already named `PolicySortColumn`. Members `POLICY_CREATION_TIME` and `POLICY_NAME` re-state `POLICY`. Inside the enum's scope `CREATION_TIME` and `NAME` are unambiguous (`PolicySortColumn.CREATION_TIME`). | +| E-02 | `PolicySortColumn.POLICY_NAME` | High | Same as above. | + +Note: `ListOrder.DESC` / `ListOrder.ASC` are fine — they're standard SQL +abbreviations and don't repeat the enum prefix. + +### 2.3 Acronym casing inconsistencies — High + +| ID | Symbol | Severity | Issue | +| ----- | --------------------- | -------- | ----- | +| A-01 | `PythonPyPiLibrary` | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. Also affects the schema names `unmarshalPythonPyPiLibrarySchema` / `marshalPythonPyPiLibrarySchema`. | +| A-02 | `RCranLibrary` | Medium | "CRAN" is an acronym ("Comprehensive R Archive Network"). The type uses `Cran` (PascalCase) which is acceptable under Google TS style (acronyms ≥3 chars → only first letter capitalised). However, the JSDoc and surrounding usage refers to "CRAN library". Consistent with the rule but worth noting — peer types like `PolicySortColumn` keep full uppercase in member names. Leave as-is for Google style compliance. | +| A-03 | `RCranLibrary` — prefix `R` | Low | The leading lone `R` (the language) is awkward; the Go SDK uses the same name so this is a porting constraint. | +| A-04 | `pypi` discriminator case (`Library.lib.$case === 'pypi'`) | Low | Lowercased, matching API wire format; consistent with `jar`, `egg`, `cran`, `maven`. Acceptable. | + +### 2.4 Underscores in TS identifiers — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| U-01 | `CreatePolicy_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). Every occurrence requires an `eslint-disable @typescript-eslint/naming-convention` annotation. Should be `CreatePolicyResponse`. | +| U-02 | `DeletePolicy_Response` | High | Same as U-01. | +| U-03 | `EditPolicy_Response` | High | Same as U-01. | +| U-04 | `ListPolicies_Response` | High | Same as U-01. | +| U-05 | `unmarshalCreatePolicy_ResponseSchema` (and 3 siblings) | High | Same naming-convention violation cascades through the schema constants. | +| U-06 | Enum member identifiers (`POLICY_CREATION_TIME`, `POLICY_NAME`) | Low | `SCREAMING_SNAKE_CASE` is acceptable for enum members under Google style (matches API wire values). Not a violation, just noted. | + +### 2.5 Cryptic abbreviations — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------- | -------- | ----- | +| C-01 | `Library.lib` | High (also covered V-01) | `lib` is a cryptic abbreviation of "library" inside a type already called `Library`. | +| C-02 | `Library.lib.$case === 'whl'` | Medium | `whl` (wheel) is a Python packaging file extension; readers unfamiliar with Python will not know it. Documented in JSDoc but the discriminator value itself is opaque. | +| C-03 | `Library.lib.$case === 'egg'` | Medium | Same as C-02 for Python "egg" files. The JSDoc even notes it is "Deprecated". | +| C-04 | `MavenLibrary.exclusions` | Low | Maven term, OK in context. | +| C-05 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | +| C-06 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | + +### 2.6 Misleading names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| M-01 | `EditPolicy` / `editPolicy()` | High | Standard CRUD verbs in TS/REST are **create / read / update / delete**. The Databricks "Cluster Policies 2.0" API uses `/edit` as the wire path, but the SDK could still expose `updatePolicy` (with `UpdatePolicy` request type) which is the conventional REST verb. Compare with the newer `policies` API surface and most other Databricks SDK resources that expose `update*`. As-is, the SDK exposes `editPolicy` while peer packages (e.g. `clusters`) often expose `editCluster` too — there is precedent — but it remains inconsistent with the broader CRUD vocabulary. Tracked here as a discrepancy worth raising upstream. | +| M-02 | `MavenLibrary.exclusions` (JSDoc says "List of dependences to exclude") | Low | Typo in the JSDoc ("dependences"); not a name issue per se. | +| M-03 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | + +### 2.7 Overly verbose / Redundant suffixes — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| O-01 | `policyFamilyDefinitionOverrides` | Medium | Five-word camel-case identifier. Inherited from the API; very long but no shorter form is unambiguous. Accept as upstream constraint. | +| O-02 | `createdAtTimestamp` | High | "Timestamp" is redundant — `createdAt` is the universal convention for epoch-millisecond fields (and the JSDoc says "in millisecond"). `createdAtTimestamp` is a tautology (`*-At` already implies a time value). | +| O-03 | `creatorUserName` | Medium | Three words for "creator". `creator` alone would suffice if the value is a username; `createdBy` is the convention used elsewhere in the Databricks SDK. | +| O-04 | `unmarshalCreatePolicy_ResponseSchema` | Medium | The pattern `unmarshalSchema` triple-states intent ("schema for unmarshalling X"). The repo-wide convention probably can't change here, but each constant runs ~38 chars. | +| O-05 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-06 | `Policy.maxClustersPerUser` | Low | Long but precise. | + +### 2.8 Singular / plural mismatches — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| P-01 | `ListPolicies` (request) vs `listPolicies()` (method) | Low | The request type is plural to match the API verb; the method matches. Consistent. | +| P-02 | `ListPolicies_Response.policies` | Low | Plural field for an array — correct. | +| P-03 | `MavenLibrary.exclusions` | Low | Plural for array — correct. | + +### 2.9 Reserved-word collisions — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| R-01 | `PythonPyPiLibrary.package` | Medium | `package` is a [reserved word in strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#future_reserved_words) for ES5+. It is legal as a property name but can't be used as a variable or import identifier without quoting. Consider `packageName` for forward compatibility. | +| R-02 | `RCranLibrary.package` | Medium | Same as R-01. | +| R-03 | None of the type names collide. | — | OK. | + +### 2.10 Empty / trivial wrapper types — Medium + +_None._ + +### 2.11 Duplicate concepts — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| D-01 | `CreatePolicy` vs `EditPolicy` | Medium | The two request types are byte-identical except `EditPolicy` adds `policyId`. Could share a base type. Codegen constraint, but readers see two near-duplicate 7-field interfaces. | +| D-02 | `Policy` vs `CreatePolicy` vs `EditPolicy` | Medium | Same body fields duplicated three times (with the entity adding `creatorUserName`, `createdAtTimestamp`, `isDefault`). Tooling could share a base. | +| D-03 | `definition` and `policyFamilyDefinitionOverrides` | Low | Distinct concepts (full definition vs. override deltas), but the names alone don't communicate "two mutually exclusive ways of supplying a definition". The JSDoc explains the relationship; OK. | + +### 2.12 Verb-tense inconsistency — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| T-01 | `createPolicy`, `deletePolicy`, `editPolicy`, `getPolicy`, `listPolicies` | Low | All imperative present-tense — consistent. | +| T-02 | `createdAtTimestamp` (past participle) | Low | Correct for a timestamp field. | +| T-03 | `isDefault` (boolean) | Low | Standard `is*` boolean prefix. Consistent with the rest of the SDK. | + +### 2.13 Go / Java-style names — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| G-01 | `CreatePolicy_Response` (proto nested-message style) | High | This is a direct port of Go's `pb.CreatePolicyResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `CreatePolicyResponse`. | +| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**). New TS readers will look up "marshal" before they recognise it. Repo-wide convention; flagged once per package. | +| G-03 | `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.20 for the type-suffix tautology angle. | +| G-04 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | + +### 2.14 Generic field names losing meaning — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| F-01 | `Library.lib` | High | Loses all meaning once destructured outside the `Library` type. See V-01. | +| F-02 | `MavenLibrary.repo` / `RCranLibrary.repo` / `PythonPyPiLibrary.repo` | Medium | Same field name across three sibling types but each refers to a different concept (Maven repo URL, CRAN mirror, PyPI index URL). Consistent for the API, but ambiguous when displayed without parent type context. | +| F-03 | `Policy.name`, `Policy.description` | Low | Standard entity fields; meaning preserved in context. | +| F-04 | `MavenLibrary.coordinates` | Low | Maven-specific; precise. | +| F-05 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | + +### 2.15 Field contradicting type domain — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| C-01 | None observed. | — | All fields are domain-appropriate for the cluster-policy context. | + +### 2.16 Inconsistent action verbs — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| AV-01 | `editPolicy()` vs ecosystem-standard `update` | Medium | Most modern Databricks APIs (and broader REST APIs) use **update**. This package uses **edit** to match the API path `/api/2.0/policies/clusters/edit`. The verb mismatch within the Databricks SDK as a whole (e.g. `Clusters.editCluster` exists, but newer surfaces use `update*`) is upstream. Flagged for awareness. | +| AV-02 | `getPolicy()` (singular) vs `listPolicies()` (plural) | Low | Correct convention (singular get, plural list). Consistent. | + +### 2.17 Long enum values — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| L-01 | `PolicySortColumn.POLICY_CREATION_TIME` | Medium | 21-char identifier. Combined with the enum-prefix redundancy (E-01), `PolicySortColumn.CREATION_TIME` would be 14 chars and lose nothing. | +| L-02 | `PolicySortColumn.POLICY_NAME` | Low | Only redundancy, not length per se. | + +### 2.18 Underspecified IDs — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| I-01 | `policyId` | Low | Well-specified: scope = policy. No collision with workspace / account / cluster IDs in this package. Good. | +| I-02 | `policyFamilyId` | Low | Scoped correctly. Good. | + +(Section retained for parity with the rubric; no high findings in this package.) + +### 2.19 Type-suffix tautology — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| TS-01 | `MavenLibrary` | Medium | The type already lives in a `Library` discriminated union; the `Library` suffix is redundant when accessed as `library.lib.$case === 'maven' ? library.lib.maven : ...` — the value's *position* in the union already identifies it as a library variant. `MavenSpec` or just `Maven` would suffice. | +| TS-02 | `PythonPyPiLibrary` | Medium | Same as TS-01. Could be `PyPISpec`. | +| TS-03 | `RCranLibrary` | Medium | Same as TS-01. Could be `CRANSpec`. | +| TS-04 | `Library` (interface itself) | Low | The interface name `Library` and its sole field `lib` share a stem, so call sites read as `library.lib` (a stem repetition). Field rename is covered by V-01 / F-01. | + +### 2.20 Other observations + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| X-01 | `Policy.createdAtTimestamp` (epoch ms, `number`) | Medium | Beyond redundancy (O-02), JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | +| X-02 | `Library.lib.$case` literal `'requirements'` | Low | The discriminator value `'requirements'` is the longest in the union (12 chars) and contrasts with three-letter peers (`jar`, `egg`, `whl`). Consistent with wire format, OK. | +| X-03 | `HttpCallOptions` (utils) | Low | Local interface; precise. | +| X-04 | `executeHttpCall`, `executeCall` | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | +| X-05 | `marshalRequest` (utils) | Low | Generic for "marshal arbitrary request body". OK in context. | +| X-06 | `readAll` (utils, private) | Low | Reads a `ReadableStream` to a `Uint8Array`. Standard name. | +| X-07 | `flattenQueryParams` (utils, exported but unused in this package?) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | + +--- + +## 3. Summary + +### 3.1 Findings by severity + +| Severity | Count | +| -------- | ----- | +| High | 11 | +| Medium | 21 | +| Low | 25 | +| **Total**| **57**| + +### 3.2 Top themes + +1. **Proto-style `_Response` suffix pollutes every CRUD response type.** + Five interfaces (`CreatePolicy_Response`, `DeletePolicy_Response`, + `EditPolicy_Response`, `ListPolicies_Response`, plus the schema constants) + each require an `eslint-disable` for the naming-convention rule. Renaming + to TS-idiomatic `CreatePolicyResponse` etc. would eliminate ~9 + disable-comments and a Google-style violation in one sweep. + +2. **`Library.lib` repeats the type stem in its discriminator field.** + Callers write `library.lib?.$case` — `lib` adds no information the type + name doesn't. A concrete name like `source` / `kind` / `spec` reads + better at call sites. + +3. **`PolicySortColumn.POLICY_*` repeats the enum prefix**; trimming to + `CREATION_TIME` / `NAME` shortens call sites and matches enum-design + guidance. + +4. **`PyPi` casing should be `PyPI`** (acronym), and `package` fields collide + with a JS strict-mode reserved word in `PythonPyPiLibrary` / `RCranLibrary`. + +5. **`createdAtTimestamp` is a tautology**; `createdAt` is the SDK-wide and + ecosystem-wide convention for epoch-millisecond fields. + +### 3.3 Suggested quick wins (non-breaking renames are not possible — this +section is advisory for the codegen owners) + +- Drop `_Response` suffix in all four response interfaces. +- Rename `Library.lib` -> `Library.source` (concrete discriminator name). +- Trim `PolicySortColumn` members. +- `PythonPyPiLibrary` -> `PythonPyPILibrary`. +- `Policy.createdAtTimestamp` -> `Policy.createdAt`. +- `Policy.creatorUserName` -> `Policy.createdBy`. + +### 3.4 Cross-package consistency notes + +- The `marshal*` / `unmarshal*` schema-naming convention is consistent with + peer packages (e.g. `clusters`, `clusterlibraries`) and is therefore a + repo-wide concern, not a per-package fix. +- The `Proto-style nested message name` `_Response` suffix is consistent + with peers and should be addressed at the codegen level. +- `editPolicy` (vs `updatePolicy`) is a per-API decision driven by the + upstream REST verb; flag for upstream alignment but no per-package fix. diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md new file mode 100644 index 00000000..cc1b2750 --- /dev/null +++ b/.agent/naming-audit/clusters.md @@ -0,0 +1,580 @@ +# Naming Audit: clusters + +**Path:** `packages/clusters/src/v2/` +**Versions audited:** v2 +**Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. +**Total weird names flagged:** 87 + +## Summary +| Severity | Count | +| --- | --- | +| High | 19 | +| Medium | 32 | +| Low | 26 | +| Observation | 10 | + +## High severity + +### 1. Cluster-State enum named `ClusterState_ClusterState` — `src/v2/model.ts:777` +- **Why weird:** Identifier doubles up the same word. Required `eslint-disable @typescript-eslint/naming-convention`. The user-visible enum is therefore `ClusterState_ClusterState.RUNNING`, which is almost cartoonishly verbose. +- **Category:** 4 (underscore in TS identifier), 6 (misleading — the doubled word reads as a typo), 14 (proto-style nested-enum noise). +- **Suggested name:** Re-export `ClusterState_ClusterState` as `ClusterState` from `index.ts`. (Note: the type declaration still leaks the proto-style name.) +- **Rationale:** TypeScript has no need to mirror the protobuf "outer message" wrapper at the call site. The current shape forces every caller to write `ClusterState_ClusterState.RUNNING`, which is jarring and forced the client to write `pollResp.state === ClusterState_ClusterState.RUNNING` (`client.ts:907`, `:949`, `:987`, etc.). + +### 2. `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — `src/v2/model.ts:29-37` +- **Why weird:** Every enum value redundantly re-states the enum's cloud (`_AZURE`). Same for `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` (`model.ts:146-148`). Compare with `AwsAvailability` (`model.ts:12-22`) where AWS-specific values are unprefixed (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`). Three sibling enums, three different conventions. +- **Category:** 2 (redundant enum prefix), 17 (inconsistent across the AWS/Azure/GCP triplet). +- **Suggested name:** `AzureAvailability.Spot | OnDemand | SpotWithFallback` and `GcpAvailability.Preemptible | OnDemand | PreemptibleWithFallback`. +- **Rationale:** The enum name already states the cloud (`AzureAvailability`). Wire values can stay as-is; TS enum identifiers should not duplicate the type. AWS already does it correctly — Azure/GCP should follow. + +### 3. `ComputeKind.COMPUTE_KIND_UNSPECIFIED` — `src/v2/model.ts:58` +- **Why weird:** Member name re-states the enum name as a prefix. TypeScript enums are already namespaced; `ComputeKind.UNSPECIFIED` is the same wire string with no prefix duplication. +- **Category:** 2 (redundant enum prefix), 14 (proto-style). +- **Suggested name:** `ComputeKind.Unspecified | ClassicPreview`. Better yet, drop `Unspecified` entirely and use `kind?: ComputeKind | undefined`. +- **Rationale:** Same logic as #2. `COMPUTE_KIND_` is pure proto noise. + +### 4. `ConfidentialComputeType.CONFIDENTIAL_COMPUTE_TYPE_UNSPECIFIED` / `CONFIDENTIAL_COMPUTE_TYPE_NONE` — `src/v2/model.ts:69-70` +- **Why weird:** Same redundant prefix as #3 but worse — the enum has three values, two of which carry the full prefix, while the third (`SEV_SNP`) does not. So readers see `CONFIDENTIAL_COMPUTE_TYPE_NONE` next to `SEV_SNP` and have to guess at the pattern. +- **Category:** 2 (redundant prefix), 17 (inconsistent within the same enum). +- **Suggested name:** `ConfidentialComputeType.Unspecified | None | SevSnp`. Drop `Unspecified` to rely on `confidentialComputeType?: ConfidentialComputeType | undefined`. +- **Rationale:** Enums should pick one prefix convention; this one mixes both within three values. + +### 5. `DataSecurityMode.DATA_SECURITY_MODE_STANDARD` / `DATA_SECURITY_MODE_DEDICATED` / `DATA_SECURITY_MODE_AUTO` — `src/v2/model.ts:123-127` +- **Why weird:** Three values redundantly prefixed with `DATA_SECURITY_MODE_`. The other six values in the enum (`NONE`, `SINGLE_USER`, `USER_ISOLATION`, `LEGACY_TABLE_ACL`, `LEGACY_PASSTHROUGH`, `LEGACY_SINGLE_USER`, `LEGACY_SINGLE_USER_STANDARD`) are unprefixed. So the same enum mixes both styles. The JSDoc itself notes some are aliases: "`DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`". So the enum has duplicate values for the same concept and inconsistent naming. +- **Category:** 2 (redundant prefix), 12 (duplicate concepts: STANDARD alias for USER_ISOLATION; DEDICATED alias for SINGLE_USER), 17 (mixed prefix/no-prefix in one enum). +- **Suggested name:** Either align (`DataSecurityMode.Auto | Standard | Dedicated` and drop the long-form aliases) or normalise away the aliases. +- **Rationale:** Public SDK enums should not ship both `USER_ISOLATION` and `DATA_SECURITY_MODE_STANDARD` if they mean the same thing — pick one, document deprecation on the other. + +### 6. `CloudProviderNodeStatus` enum uses non-SCREAMING_SNAKE wire values — `src/v2/model.ts:40-43` +- **Why weird:** `NOT_ENABLED_ON_SUBSCRIPTION = 'NotEnabledOnSubscription'` and `NOT_AVAILABLE_IN_REGION = 'NotAvailableInRegion'`. The TS identifier is `SCREAMING_SNAKE` (every other enum in this file follows that), but the wire value is `PascalCase`. Every other enum's wire value matches the TS identifier exactly. +- **Category:** 17 (inconsistent wire-value casing). +- **Suggested name:** Keep the SCREAMING_SNAKE TS identifier; this is an upstream wire-value inconsistency that the generator faithfully reproduces. +- **Rationale:** Highlight to upstream — the API surface should be uniform. Flagged here so downstream consumers know to expect PascalCase strings for this one enum. + +### 7. `TerminationCode.*` — 150+ enum values, many proto-style noisy — `src/v2/model.ts:164-748` +- **Why weird:** The enum has ~150 values; many encode the same concept three or four times. Examples: `BOOTSTRAP_TIMEOUT` vs `BOOTSTRAP_TIMEOUT_DUE_TO_MISCONFIG` vs `BOOTSTRAP_TIMEOUT_CLOUD_PROVIDER_EXCEPTION`; `INSTANCE_UNREACHABLE` vs `INSTANCE_UNREACHABLE_DUE_TO_MISCONFIG`; `CONTROL_PLANE_REQUEST_FAILURE` vs `CONTROL_PLANE_REQUEST_FAILURE_DUE_TO_MISCONFIG` (whose JSDoc just says "CPRF, but due to misconfiguration on the customer's side"). Several values reference internal Databricks jargon: `NEPHOS_RESOURCE_MANAGEMENT`, `CHAUFFEUR`, `NPIP_TUNNEL`, `IN_PENALTY_BOX`, `CMv2`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT`, `GKE_BASED_CLUSTER_TERMINATION`. +- **Category:** 5 (cryptic abbreviations — Nephos, CPRF, CPLF, CMv2, DBR, NPIP, CMK, K8s, IMv2), 12 (duplicate concepts — many `_DUE_TO_MISCONFIG` siblings duplicate the base reason), 18 (long enum values). +- **Suggested name:** Out of scope for a rename, but flag upstream: collapse `_DUE_TO_MISCONFIG` siblings into a structured field (`misconfig: boolean` on `TerminationReason`) instead of doubling every code; document internal-jargon codes for external consumers. +- **Rationale:** This is a public SDK; values like `IN_PENALTY_BOX` and `NEPHOS_RESOURCE_MANAGEMENT` leak internal-process names to customers and are unfit for external naming. Comments on `GCP_QUOTA_EXCEEDED` (`model.ts:410`) literally include a TODO about consolidating per-cloud reasons — the SDK is shipping the unconsolidated state. + +### 8. `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` — `src/v2/model.ts:421` +- **Why weird:** `BYOK` is "Bring Your Own Key". Abbreviation used without expansion in either the enum value or the JSDoc. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** Expand to `AZURE_CUSTOMER_KEY_PERMISSION_FAILURE` or document `BYOK` inline. +- **Rationale:** External SDK users will not all know `BYOK` is a cloud-key acronym. + +### 9. `TerminationCode.NPIP_TUNNEL_TOKEN_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE` — `src/v2/model.ts:309,350` +- **Why weird:** `NPIP` ("No Public IP") is internal Databricks networking terminology. Not expanded in JSDoc. +- **Category:** 5 (cryptic abbreviation), 8 (internal jargon in public surface). +- **Suggested name:** Rename to `NO_PUBLIC_IP_TUNNEL_*` or document `NPIP` in the enum docstring. +- **Rationale:** Same as #8; SDK users should not need to know Databricks' internal acronyms. + +### 10. `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` / `DBR_IMAGE_RESOLUTION_FAILURE` — `src/v2/model.ts:380,729` +- **Why weird:** `DBR` ("Databricks Runtime") and `K8S` ("Kubernetes") used together with no expansion. JSDoc on line 380 says "DBR Cluster launched on K8s (i.e. CMv2)" — three acronyms in one sentence. +- **Category:** 5 (cryptic abbreviation), 8 (jargon). +- **Suggested name:** Expand acronyms in JSDoc minimum; consider renaming to `DATABRICKS_RUNTIME_CLUSTER_LAUNCH_TIMEOUT_KUBERNETES`. +- **Rationale:** Internal SDK people read `DBR` daily; external consumers don't. + +### 11. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` — `src/v2/model.ts:368` +- **Why weird:** Enum value is 52 characters long; says "AWS insufficient free addresses in subnet failure". GCP equivalent is `GCP_IP_SPACE_EXHAUSTED` (`model.ts:579`), 22 chars — same concept, very different length. JSDoc at line 410 explicitly TODOs consolidating these. +- **Category:** 7 (overly verbose), 17 (inconsistent across clouds), 18 (long enum value). +- **Suggested name:** `AWS_SUBNET_IP_EXHAUSTED` (mirror the GCP form). +- **Rationale:** Per-cloud variants should follow the same shape; the AWS/GCP/Azure versions of the same condition should not differ in length by 30 characters. + +### 12. `TerminationCode.AZURE_UNEXPECTED_DEPLOYMENT_TEMPLATE_FAILURE` / `AZURE_PACKED_DEPLOYMENT_PARTIAL_FAILURE` — `src/v2/model.ts:323,493` +- **Why weird:** 45- and 41-character enum values. Both are Azure-deployment-template-specific. AWS and GCP do not have equivalents at this length. +- **Category:** 7 (overly verbose), 18 (long enum value). +- **Suggested name:** `AZURE_DEPLOYMENT_TEMPLATE_FAILURE`, `AZURE_PACKED_DEPLOYMENT_FAILURE` (drop the qualifier; let the JSDoc carry the nuance). +- **Rationale:** Public enums should be readable at a glance. + +### 13. `TerminationCode.ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` — `src/v2/model.ts:675` +- **Why weird:** 53-character enum value. Eight `ALLOCATION_TIMEOUT_*` siblings (`model.ts:650-675`) all encode subtle internal scheduler states. +- **Category:** 7 (overly verbose), 12 (duplicate concept across eight near-identical codes), 18 (long enum value). +- **Suggested name:** Collapse the family into `ALLOCATION_TIMEOUT` with a structured sub-field (`reason: string`) on `TerminationReason.parameters`. +- **Rationale:** Eight `ALLOCATION_TIMEOUT_*` codes look like the inverse of "values should be discriminator-friendly". External callers will hardly distinguish `NO_HEALTHY_CLUSTERS` from `NO_HEALTHY_AND_WARMED_UP_CLUSTERS`. + +### 14. `_Response` suffix and Proto-style nested types — pervasive throughout +- **Why weird:** 14+ `_Response` interfaces (`ChangeClusterOwner_Response`, `CreateCluster_Response`, `DeleteCluster_Response`, `EditCluster_Response`, `EnforcePolicyComplianceForCluster_Response`, `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange`, `GetPolicyComplianceForCluster_Response`, `GetSparkVersions_Response`, `ListAvailableZones_Response`, `ListClusterComplianceForPolicy_Response`, `ListClusters_Response`, `ListNodeTypes_Response`, `PermanentDeleteCluster_Response`, `PinCluster_Response`, `ResizeCluster_Response`, `RestartCluster_Response`, `StartCluster_Response`, `UnpinCluster_Response`, `UpdateCluster_Response`). Each requires an `eslint-disable @typescript-eslint/naming-convention`. +- **Category:** 4 (underscores in TS identifier), 14 (proto-style naming). +- **Suggested name:** Rename to `CreateClusterResponse` etc. +- **Rationale:** Strict-type-checked ESLint rejects `Foo_Bar`. The `_Response` suffix is pure proto-style noise in a TypeScript identifier. + +### 15. `ClusterInfo_ComputeSpec_CustomTagsEntry`, `ClusterInfo_SparkConfEntry`, etc. — 16 underscore-laden map-entry types +- **Why weird:** 16 interfaces with names like `ClusterInfo_ComputeSpec_CustomTagsEntry` (`model.ts:1412`), `ClusterInfo_ComputeSpec_SparkConfEntry` (`model.ts:1429`), `ClusterInfo_ComputeSpec_SparkEnvVarsEntry` (`model.ts:1436`), `ClusterInfo_CustomTagsEntry`, `ClusterInfo_DefaultTagsEntry`, `ClusterInfo_SparkConfEntry`, `ClusterInfo_SparkEnvVarsEntry`, `CreateCluster_CustomTagsEntry`, `CreateCluster_SparkConfEntry`, `CreateCluster_SparkEnvVarsEntry`, `EditCluster_CustomTagsEntry`, `EditCluster_SparkConfEntry`, `EditCluster_SparkEnvVarsEntry`, `UpdateCluster_UpdateClusterResource_CustomTagsEntry`, `UpdateCluster_UpdateClusterResource_SparkConfEntry`, `UpdateCluster_UpdateClusterResource_SparkEnvVarsEntry`. Each carries the same `{key?: string; value?: string}` shape — sixteen distinct names for one concept. +- **Category:** 4 (underscores), 12 (duplicate concepts — same `{key, value}` shape 16 times). +- **Suggested name:** Consolidate around the wire-equivalent `Record` form already used by the parent fields and marshal/unmarshal schemas. +- **Rationale:** These types exist only because protobuf models maps as repeated `Entry` messages. TypeScript has built-in `Record<>` — sixteen separate `{key, value}` types for the same concept is pure proto-style duplication. + +### 16. `UpdateCluster_UpdateClusterResource` — `src/v2/model.ts:2590` +- **Why weird:** Name doubles up: `UpdateCluster_UpdateClusterResource`. The field is `UpdateCluster.cluster: UpdateCluster_UpdateClusterResource` (`model.ts:2581`). So the user writes `req.cluster` and the type is `UpdateCluster_UpdateClusterResource`. Three underscores worth of proto noise. Same body across `CreateCluster`, `EditCluster`, `UpdateCluster_UpdateClusterResource` (they have 28 identical fields each). +- **Category:** 4 (underscore), 6 (misleading: shouldn't this just be `ClusterSpec` or `Cluster`?), 8 (redundant `Resource` suffix), 12 (duplicate concept with `CreateCluster`/`EditCluster`/`ClusterInfo_ComputeSpec`), 14 (proto-style nested message). +- **Suggested name:** `ClusterSpec` (and reuse for `CreateCluster`, `EditCluster`, `ClusterInfo.spec`). +- **Rationale:** The type holds cluster configuration — the same configuration four request types describe. Collapsing to a shared `ClusterSpec` removes duplication and naming weirdness in one move. + +### 17. `ClusterInfo_ComputeSpec` — `src/v2/model.ts:1229` +- **Why weird:** Underscored type name; near-identical to `UpdateCluster_UpdateClusterResource` (28 of 28 fields overlap). The JSDoc says "Contains a snapshot of the latest user specified settings". `Spec`/`ClusterSpec` would be sufficient. +- **Category:** 4 (underscore), 12 (duplicate of #16), 14 (proto-style nested). +- **Suggested name:** Use shared `ClusterSpec`. +- **Rationale:** Same as #16; one canonical spec type used in four places. + +### 18. `WorkloadType_ClientsTypes` — `src/v2/model.ts:2816` +- **Why weird:** Triple-misery: `WorkloadType` outer type has a single field `clients` of type `WorkloadType_ClientsTypes`. The nested type's name pluralises both nouns (`Clients`+`Types`). The two booleans inside (`notebooks`, `jobs`) are not "types" — they're "client flags". Field on parent is singular (`clients`) but type is plural+plural (`ClientsTypes`). +- **Category:** 1 (vague — "ClientsTypes" doesn't mean anything), 4 (underscore), 6 (misleading), 9 (singular vs plural inconsistency), 14 (proto-style nested). +- **Suggested name:** Rename to `WorkloadClients` and align the field's plural/singular shape with the type name. +- **Rationale:** Two-level nesting with an outer container adds no information; the wire form is `workload_type.clients.notebooks` which is also unnecessarily deep. + +### 19. `SparkInfo_SparkNode_SparkNodeAwsAttributes` — `src/v2/model.ts:2530` +- **Why weird:** `SparkInfo_SparkNode_SparkNodeAwsAttributes` repeats `SparkNode` twice. Contains one field, `isSpot`. The field on the parent type (`SparkInfo_SparkNode`) is called `nodeAwsAttributes` (`model.ts:2523`) — so the user writes `node.nodeAwsAttributes.isSpot`, and the type is `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Three `SparkNode`s, two underscores, one boolean. +- **Category:** 1 (vague, redundant), 4 (underscores), 7 (overly verbose), 14 (proto-style nested). +- **Suggested name:** Re-export as `SparkNodeAwsAttributes` from `index.ts` to give callers a sane identifier. +- **Rationale:** A name that repeats `SparkNode` twice and contains two underscores is unreadable; the proto-style nesting need not survive to the public TS surface. + +## Medium severity + +### 20. `Adlsgen2Info` casing — `src/v2/model.ts:800` +- **Why weird:** Type name is `Adlsgen2Info` — should be `AdlsGen2Info` to match acronym-casing rules. ADLS (Azure Data Lake Storage) Gen2 should retain the boundary between `Adls` and `Gen2`. +- **Category:** 3 (acronym casing inconsistency), 1 (vague `Info` suffix). +- **Suggested name:** `AdlsGen2Storage` (or just `AbfssStorage`, since the wire name is `abfss`). +- **Rationale:** Compare to sibling types `DbfsStorageInfo`, `GcsStorageInfo`, `S3StorageInfo` — all use `Info` suffix and capitalize the storage product. `Adlsgen2Info` is the odd one out. + +### 21. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:800,1745,2102,2290,2456,2801,2824` +- **Why weird:** `Adlsgen2Info` (no `Storage`), `DbfsStorageInfo`, `GcsStorageInfo`, `LocalFileInfo` (no `Storage`), `S3StorageInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. Seven sibling types; five say `StorageInfo`, two say `Info`. +- **Category:** 17 (inconsistent suffix across siblings). +- **Suggested name:** Standardise on `XStorage` (drop the redundant `Info`) — `AdlsGen2Storage`, `DbfsStorage`, `GcsStorage`, `LocalFileStorage`, `S3Storage`, `VolumesStorage`, `WorkspaceStorage`. +- **Rationale:** All seven describe the same kind of thing (a storage destination). Either all of them get `StorageInfo` or none do. + +### 22. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:946,2112,2118,2227,2244` +- **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForCluster` (a request), `GetPolicyComplianceForCluster_Response`, `EnforcePolicyComplianceForCluster` (request), `ListClusterComplianceForPolicy` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. +- **Category:** 1 (vague — `For` is the only disambiguator), 6 (misleading — easy to mis-parse). +- **Suggested name:** `GetClusterPolicyCompliance`, `EnforceClusterPolicyCompliance`, `ListPolicyCompliantClusters`, `ClusterPolicyCompliance`. +- **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. + +### 23. `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange` — `src/v2/model.ts:2025` +- **Why weird:** 56 characters, three underscores, four nested words. Used inside `EnforcePolicyComplianceForCluster_Response.changes`. +- **Category:** 4 (underscores), 7 (overly verbose), 14 (proto-style nested-nested message). +- **Suggested name:** `ClusterSettingsChange` (hoist to module level) or `PolicyComplianceChange`. +- **Rationale:** Nested-nested proto messages should not survive translation to TS. + +### 24. `validateOnly` field — `src/v2/model.ts:2001` +- **Why weird:** Field on `EnforcePolicyComplianceForCluster`. Verb-prefixed boolean reads as a method; doc says "if set, previews the changes" — closer to a `previewOnly`/`dryRun` flag. +- **Category:** 6 (misleading: name implies "validate", behaviour is "dry-run"). +- **Suggested name:** `dryRun` or `previewOnly`. +- **Rationale:** Common convention; matches what most cloud SDKs name this. Wire stays `validate_only`. + +### 25. `hasChanges` field — `src/v2/model.ts:2010` +- **Why weird:** Boolean named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. +- **Category:** 12 (duplicate signal), 1 (vague). +- **Suggested name:** Drop the field, infer from `changes.length`. +- **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. + +### 26. `restartUser` field on `RestartCluster` — `src/v2/model.ts:2449` +- **Why weird:** No JSDoc. Field name alone doesn't say what it does. Is it "user who triggered the restart"? "User to attribute the restart to"? Inconsistent with the package's general style (`ownerUsername`, `creatorUserName`, `singleUserName` all spell out `Username`/`UserName`). +- **Category:** 1 (vague — no doc, ambiguous semantics), 17 (sibling fields say `username` or `userName`, this one says `user`). +- **Suggested name:** `restartUsername` or `restartedByUsername`. +- **Rationale:** Match the field-naming patterns used elsewhere; even better, document the field. + +### 27. `creatorUserName` / `singleUserName` / `ownerUsername` — `src/v2/model.ts:977,1150,930` +- **Why weird:** Three "user name" fields in the same model, two different camelCases: `creatorUserName` and `singleUserName` use `UserName` (two words), `ownerUsername` uses `Username` (one word). Wire is `creator_user_name`, `single_user_name`, `owner_username` — the wire is inconsistent too. +- **Category:** 3 (casing inconsistency), 17 (sibling field inconsistency). +- **Suggested name:** Pick one: `Username` is more conventional in modern web APIs. Go SDK and proto leave this inconsistent; TS could normalise. +- **Rationale:** Three similar fields, three (sort of) similar names, two different ways of capitalising the same concept. + +### 28. `kind: ComputeKind` field — `src/v2/model.ts:1173` +- **Why weird:** Field is called `kind` on `ClusterInfo`, `ClusterInfo_ComputeSpec`, `CreateCluster`, `EditCluster`, `UpdateCluster_UpdateClusterResource`. Sibling fields are very specific (`runtimeEngine`, `dataSecurityMode`, `workloadType`); `kind` is the odd vague one. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `computeKind` (matches the type and wire name `kind` can stay). +- **Rationale:** `kind` alone is the JS-reserved-shape problem (`kind` is heavily overloaded in discriminated-union code). `computeKind` is unambiguous. + +### 29. `size` discriminated union (`numWorkers` | `autoscale`) — `src/v2/model.ts:1201` +- **Why weird:** Field `size` is a discriminated union with two variants `numWorkers` (number) and `autoscale` (object). It appears on six types: `ClusterInfo`, `ClusterInfo_ComputeSpec`, `CreateCluster`, `EditCluster`, `ResizeCluster`, `UpdateCluster_UpdateClusterResource`. The literal `size` doesn't read as "either count or autoscaler" — calling code looks like `if (req.size?.$case === 'numWorkers')` which is awkward. +- **Category:** 1 (vague), 6 (misleading: a "size" sounds like an integer). +- **Suggested name:** `capacity` (or just `workers`, since both variants describe how many workers). +- **Rationale:** "size" suggests a number; this field is a tagged union. A different word avoids the contradiction. + +### 30. `useMlRuntime` field — `src/v2/model.ts:1179` +- **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. +- **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). +- **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. +- **Rationale:** A boolean and an enum jointly describing one runtime selection is a smell. + +### 31. `isSingleNode` field — `src/v2/model.ts:1185` +- **Why weird:** Boolean field that, when true, automatically sets `custom_tags`, `spark_conf`, and `num_workers`. Doc admits the surprise: "When set to true, Databricks will automatically set single node related custom_tags, spark_conf, and num_workers." A field that secretly mutates three others is a footgun. +- **Category:** 6 (misleading — hidden side effects). +- **Suggested name:** Name is fine, but document the side effects in the type-level JSDoc, not just the field doc. +- **Rationale:** Flag for upstream — the boolean is doing more than the name suggests. + +### 32. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields +- **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. +- **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). +- **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. +- **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. + +### 33. `nodeTypeId` vs `instanceTypeId` — `src/v2/model.ts:1076,2321,2350` +- **Why weird:** `nodeTypeId` (string) and `instanceTypeId` (string) appear on different types. `NodeType.instanceTypeId` and `NodeInstanceType.instanceTypeId` are described as "hardware identifier (e.g., r3.2xlarge in AWS)" — i.e., the AWS instance class. `nodeTypeId` is the Databricks node type ID. Easy to confuse the two. +- **Category:** 19 (underspecified IDs — multiple "type" IDs coexisting). +- **Suggested name:** Either prefix one (`databricksNodeTypeId` / `cloudInstanceTypeId`) or rename `instanceTypeId` to `cloudInstanceTypeId` everywhere. +- **Rationale:** Two `*TypeId` fields side by side, distinguished only by `node` vs `instance`. Real users will get this wrong. + +### 34. `driverNodeTypeId` / `nodeTypeId` / `driverInstancePoolId` / `instancePoolId` — `src/v2/model.ts:1076,1085,1148,1160` +- **Why weird:** Pattern is "`driverX` and `X`" where `X` is the worker version. Four such pairs across the spec (`nodeTypeId`/`driverNodeTypeId`, `instancePoolId`/`driverInstancePoolId`, `nodeTypeFlexibility`/`driverNodeTypeFlexibility` — but the worker version is called `workerNodeTypeFlexibility` while the worker-`nodeTypeId` is just `nodeTypeId`). +- **Category:** 17 (inconsistent pairing — sometimes worker is prefix-less, sometimes prefixed `worker`). +- **Suggested name:** Either always prefix worker (`workerNodeTypeId`, `workerInstancePoolId`, `workerNodeTypeFlexibility`) or never (drop `worker` from `workerNodeTypeFlexibility`). +- **Rationale:** Reader who sees `driverNodeTypeId` next to `nodeTypeId` has to remember that the un-prefixed one is "worker"; then sees `workerNodeTypeFlexibility` and gets thrown. + +### 35. `NodeType.numCores` vs `ClusterInfo.clusterCores` — `src/v2/model.ts:2346,992` +- **Why weird:** Same concept (number of CPU cores) appears as `numCores` on `NodeType` and `clusterCores` on `ClusterInfo`. The `num` prefix is inconsistent with the bare `clusterCores`. +- **Category:** 17 (inconsistent prefix), 1 (`num` is vague compared to the rest of the model). +- **Suggested name:** `cores` (on `NodeType`) and `clusterCores` stays (or both `cores`/`totalCores`). +- **Rationale:** Compare to `clusterMemoryMb` (no `num` prefix), `memoryMb` (no `num` prefix). `numCores` and `numGpus` are the outliers. + +### 36. `NodeType.numGpus` — `src/v2/model.ts:2366` +- **Why weird:** Same `num` prefix issue as #35. Sibling fields don't carry a `num` prefix (`memoryMb`, `localDisks`, `category`). +- **Category:** 17 (inconsistent prefix), 1. +- **Suggested name:** `gpus` (or `gpuCount`). +- **Rationale:** Internal consistency. + +### 37. `NodeInstanceType.localDisks` and `NodeInstanceType.localNvmeDisks` are counts — `src/v2/model.ts:2323,2329` +- **Why weird:** Plural noun `localDisks` is typed as `number`, but JSDoc says "Number of local disks that are present on this instance." Counting things should use `count`/`num` suffix, not the plural noun. +- **Category:** 9 (singular vs plural confusion — the plural noun is actually a count). +- **Suggested name:** `localDiskCount`, `localNvmeDiskCount`. +- **Rationale:** A reader sees `localDisks: number` and might assume "array of local disks" — then realises it's a scalar. + +### 38. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2325,2327` +- **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. +- **Category:** 17 (inconsistent grouping). +- **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. +- **Rationale:** Within the same type, related fields should sit together. + +### 39. `ListAvailableZones_Response.defaultZone` — `src/v2/model.ts:2224` +- **Why weird:** JSDoc says "The availability zone if no `zone_id` is provided in the cluster creation request." The doc references `zone_id` (the wire name) instead of the TS `zoneId`. Other docstrings in the package also reference `zone_id`, `cluster_id`, `cluster_log_conf`, `init_scripts`, etc. +- **Category:** Observation — generated docs reference wire names rather than TS names. +- **Suggested name:** Update doc-comment generation to use TS names. +- **Rationale:** Inconsistent doc/identifier pairing makes IntelliSense suggestions look out-of-date. + +### 40. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2295` +- **Why weird:** `LogAnalyticsInfo` has two fields (`logAnalyticsWorkspaceId`, `logAnalyticsPrimaryKey`), both un-documented. The type itself has no JSDoc. Used only by `AzureAttributes.logAnalyticsInfo`. +- **Category:** Observation (no naming issue per se, but missing context). +- **Suggested name:** Keep `LogAnalyticsInfo` (Azure Monitor terminology) but add a JSDoc; consider `AzureLogAnalyticsConfig`. +- **Rationale:** Both fields are Azure-specific; naming should signal that. + +### 41. `LogSyncStatus.lastException: string` — `src/v2/model.ts:2311` +- **Why weird:** Field name is `lastException` (singular: the previous exception) but the type is `string`. JS exceptions are usually serialised as messages; a more accurate name would be `lastExceptionMessage`. +- **Category:** 1 (vague — `Exception` is overloaded), 16 (type contradicts the name domain). +- **Suggested name:** `lastErrorMessage` or `lastExceptionMessage`. +- **Rationale:** Distinguishes an Error object reference from its serialised string form. + +### 42. `LogSyncStatus.lastAttempted: number` — `src/v2/model.ts:2306` +- **Why weird:** `lastAttempted` is a verb-past-participle, type is `number` (epoch millis per JSDoc). Hard to tell from the name that this is a timestamp. +- **Category:** 1 (vague), 6 (misleading — sounds like a boolean or count). +- **Suggested name:** `lastAttemptedAt`, `lastAttemptTime`, `lastAttemptedMs`. +- **Rationale:** Match the timestamp-suffix convention used elsewhere in this model (`startTime`, `terminatedTime`, `lastRestartedTime`, `lastStateLossTime`). + +### 43. `ClusterInfo.startTime`/`terminatedTime`/`lastStateLossTime`/`lastRestartedTime` — `src/v2/model.ts:1194-1200` +- **Why weird:** Four sibling timestamps. `startTime` and `terminatedTime` use different shapes (`start` + `Time` vs `terminated` + `Time`); `lastStateLossTime` and `lastRestartedTime` use past participle + `Time`. Mix of forms. Also `LogSyncStatus.lastAttempted` (#42) drops the `Time` suffix entirely. +- **Category:** 17 (inconsistent timestamp suffix), 13 (verb-tense inconsistency: `start` vs `terminated` vs `restarted`). +- **Suggested name:** Choose one suffix (`-At`, `-Time`, `-Ms`) and apply uniformly: `startedAt`, `terminatedAt`, `lastStateLostAt`, `lastRestartedAt`, `lastAttemptedAt`. +- **Rationale:** Timestamp suffixes are a high-impact, low-cost consistency win. + +### 44. `SparkInfo_SparkNode.startTimestamp` — `src/v2/model.ts:2521` +- **Why weird:** Same node-related concept as `ClusterInfo.startTime` (#43) but uses `Timestamp` rather than `Time`. Different word for the same idea. +- **Category:** 17 (inconsistent across types). +- **Suggested name:** `startTime` (or align all timestamps under one suffix). +- **Rationale:** Two timestamp suffixes in the same file is two too many. + +### 45. `creatorUserName` field — `src/v2/model.ts:977` +- **Why weird:** TS camelCase splits `User` and `Name` (`creatorUserName`) but the conceptually-similar `singleUserName` does the same. Compare to `ownerUsername` (one word) on `ChangeClusterOwner`. Inconsistency between three sibling concepts. Documented behaviour: "The field won't be included in the response if the user has already been deleted" — but no `undefined` annotation distinguishes "absent because new" from "absent because deleted". +- **Category:** 3 (casing inconsistency), see also #27. +- **Suggested name:** `creatorUsername`. +- **Rationale:** Already covered in #27; flagged again because it appears on the main `ClusterInfo` type which dominates user reading time. + +### 46. `clusterLogStatus` field — `src/v2/model.ts:1008` +- **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). +- **Category:** 6 (misleading — type and field name don't match the same concept). +- **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. +- **Rationale:** Same concept, two different names in 5 lines. + +### 47. `jdbcPort` field — `src/v2/model.ts:1036` +- **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. +- **Category:** 3 (acronym casing inconsistency). +- **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). +- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #48). + +### 48. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` +- **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). +- **Category:** 3 (acronym casing inconsistency). +- **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. +- **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. + +### 49. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:2491` +- **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. +- **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). +- **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. +- **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. + +### 50. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:2474,2479,2481` +- **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. +- **Category:** 12 (duplicate concepts), 17 (could be a tagged union). +- **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). +- **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. + +### 51. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:2464,2469` +- **Why weird:** JSDoc explicitly says "Either region or endpoint needs to be set. If both are set, endpoint will be used." Mutually-exclusive fields not encoded in the type. +- **Category:** 16 (field-pair constraint not in the type). +- **Suggested name:** Could be a discriminated union `{kind: 'region', value: string} | {kind: 'endpoint', value: string}`. +- **Rationale:** Type-system-encodable constraint; flagged for upstream. + +## Low severity + +### 52. `ClusterInfo.spec?: ClusterInfo_ComputeSpec` field name — `src/v2/model.ts:1018` +- **Why weird:** Field is just `spec`; type is `ClusterInfo_ComputeSpec`. Field name is very short. +- **Category:** 1 (vague — `spec` alone could mean anything), 8 (type-suffix tautology: `clusterInfo.spec` of type `ComputeSpec`). +- **Suggested name:** `computeSpec` or `clusterSpec`. +- **Rationale:** Once the type is renamed (#17), this falls out naturally. + +### 53. `ClusterInfo.driver: SparkInfo_SparkNode` field — `src/v2/model.ts:1023` +- **Why weird:** Field name is `driver` (vague — could mean a person or an Apache driver concept). Type `SparkInfo_SparkNode` (which is itself awkward). Better: `driverNode: SparkNode`. +- **Category:** 1 (vague). +- **Suggested name:** `driverNode`. +- **Rationale:** Reader sees `driver` and has to know to follow the type. + +### 54. `ClusterInfo.executors: SparkInfo_SparkNode[]` field — `src/v2/model.ts:1025` +- **Why weird:** Same as #53. `executors` is fine in Spark vocabulary but better paired: `executorNodes: SparkNode[]`. +- **Category:** 17 (inconsistent with `driver`). +- **Suggested name:** `executorNodes`. +- **Rationale:** Match the `driver`/`executor` pattern. + +### 55. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1145,1340,1662,1914,2723` +- **Why weird:** JSDoc abbreviation `BYOC` (Bring Your Own Container) used without expansion. Appears five times in the model. +- **Category:** 5 (cryptic abbreviation in JSDoc). +- **Suggested name:** N/A — fix the comment, not the identifier. +- **Rationale:** Quick doc fix. + +### 56. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1031` +- **Why weird:** Field is named `sparkContextId` but typed as `number`. Other IDs in the model are strings (`clusterId`, `policyId`, `nodeTypeId`). Internal Spark context IDs are 64-bit ints — the type clash hints at potential JS number-precision issues for large IDs. +- **Category:** 19 (underspecified ID — different type from sibling IDs). +- **Suggested name:** Keep but consider `bigint` typing or document the precision risk. +- **Rationale:** JS number safe-integer range is 2^53; if Spark uses 64-bit IDs, this is a latent bug. + +### 57. `DockerImage.credsOneof` field name — `src/v2/model.ts:1768` +- **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. +- **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). +- **Suggested name:** `credentials` (singular). +- **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. + +### 58. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:1759,1761` +- **Why weird:** Doc strings are "Name of the user" and "Password of the user" — generic and add no information beyond the field names. +- **Category:** Observation (low-quality docstrings). +- **Suggested name:** No rename; flag doc-quality. +- **Rationale:** Minor. + +### 59. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:864` +- **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:924`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. +- **Category:** 17 (sibling AWS/Azure shapes differ), 1 (`number` without unit suffix). +- **Suggested name:** `spotBidPricePercent` is fine; flag for upstream — the AWS/Azure semantics should be more discoverable from the model. +- **Rationale:** Cross-cloud asymmetry is a domain concern. + +### 60. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:923` +- **Why weird:** Magic value `-1` overloaded as "do not evict on price basis". Encoded in JSDoc, not in the type. +- **Category:** 16 (sentinel value in scalar field), Observation. +- **Suggested name:** N/A; flag for upstream to consider a sentinel enum or `null`. +- **Rationale:** Sentinels in scalar fields are old-school API design. + +### 61. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2051` +- **Why weird:** JSDoc says "Note: Soon to be deprecated, use the 'availability' field instead." But the field is not actually marked `@deprecated`. +- **Category:** Observation — missing `@deprecated`. +- **Suggested name:** Add `@deprecated` JSDoc tag. +- **Rationale:** Tooling can pick up `@deprecated`; "Note: Soon to be deprecated" is invisible to IDEs. + +### 62. `GcpAttributes.googleServiceAccount: string` — `src/v2/model.ts:2058` +- **Why weird:** Field `googleServiceAccount` lives on `GcpAttributes`. The `google` prefix is redundant — sibling fields don't say `googleZoneId`, `googleAvailability`, `googleBootDiskSize`. +- **Category:** 17 (inconsistent prefix within `GcpAttributes`). +- **Suggested name:** `serviceAccount` (drop the `google` prefix). +- **Rationale:** Internal consistency; the type's name already says GCP. + +### 63. `GcpAttributes.bootDiskSize: number` — `src/v2/model.ts:2060` +- **Why weird:** Doc says "Boot disk size in GB" but field has no unit suffix. Compare `ebsVolumeSize`/`ebsVolumeIops`/`ebsVolumeThroughput` (no unit suffixes either) and `remoteDiskThroughput` (`Mb/s` per doc, no suffix). Pattern is "no unit suffix" — but `clusterMemoryMb`, `memoryMb`, `localDiskSizeGb` DO have unit suffixes. Inconsistent. +- **Category:** 17 (inconsistent unit-suffix convention). +- **Suggested name:** `bootDiskSizeGb`. +- **Rationale:** Match the `*Mb`, `*Gb` pattern used on the same struct hierarchy. + +### 64. `GcpAttributes.localSsdCount: number` field with prose comment — `src/v2/model.ts:2082` +- **Why weird:** Field is named `localSsdCount`; sibling `bootDiskSize` is unsuffixed; `firstOnDemand` is also unsuffixed. Three different "amount" fields, three different suffix conventions. +- **Category:** 17 (inconsistent quantity suffix). +- **Suggested name:** Either all carry `Count`/`Size`/`Mb` etc. or none do. +- **Rationale:** Within `GcpAttributes`, `localSsdCount` carries a `Count` suffix while `firstOnDemand` (also a count) does not. + +### 65. `firstOnDemand` field name — `src/v2/model.ts:829,911,2092` +- **Why weird:** Used on `AwsAttributes`, `AzureAttributes`, `GcpAttributes`. Reads as "first on-demand what?". Doc says "The first `first_on_demand` nodes of the cluster will be placed on on-demand instances" — meta-circular. +- **Category:** 1 (vague), 7 (no noun). +- **Suggested name:** `firstOnDemandNodes` or `onDemandNodeCount`. +- **Rationale:** The name is missing the noun it describes. + +### 66. `ChangeClusterOwner.ownerUsername` field docstring — `src/v2/model.ts:929` +- **Why weird:** Doc says "New owner of the cluster_id after this RPC." `RPC` jargon leaks. `cluster_id` is the wire name; should be `clusterId`. +- **Category:** Observation (doc quality), 5 (RPC jargon). +- **Suggested name:** Update doc text. +- **Rationale:** Minor doc fix. + +### 67. `ClusterCompliance.violations: Record` — `src/v2/model.ts:956` +- **Why weird:** Map from string (policy field path) to string (error message). Field name `violations` doesn't communicate the shape. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `violationsByField` or `fieldViolations`. +- **Rationale:** Clarifies the map's semantics. + +### 68. `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange.field: string` — `src/v2/model.ts:2027` +- **Why weird:** Field on a "ClusterSettingsChange" is itself named `field`. Reads as `change.field` — circular. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `fieldPath` or `settingName`. +- **Rationale:** Minor; flags pile up. + +### 69. `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2034,2041` +- **Why weird:** Both fields typed as `string`. JSDoc says values are "either a number, a boolean, or a string converted to a string." Pre-stringified union encoded as plain string — caller must re-parse. +- **Category:** 16 (type contradicts domain — it's actually `number | boolean | string` flattened to string). +- **Suggested name:** Type as `string | number | boolean`, or `previousValueRaw`. +- **Rationale:** Documents the stringification rather than hiding it. + +### 70. `SparkVersion.key` / `name` — `src/v2/model.ts:2542,2544` +- **Why weird:** Two very generic field names; from `SparkVersion`, `key` is the version string and `name` is the display name. Inversion of typical (`name`=identifier, `displayName`=human-readable). +- **Category:** 1 (vague), 6 (misleading). +- **Suggested name:** `version`/`displayName` or `versionKey`/`label`. +- **Rationale:** `key` is one of the most overloaded names in software. + +### 71. `NodeType.key`-like fields — `nodeTypeId`, `instanceTypeId`, `description`, `category` — `src/v2/model.ts:2338-2390` +- **Why weird:** 20 fields on `NodeType`, several with vague names: `description`, `category`. No JSDoc on `displayOrder` until line 2374. Some fields are `is*` booleans (`isDeprecated`, `isHidden`, `isIoCacheEnabled`, `isEncryptedInTransit`, `isGraviton`), others are `support*` booleans (`supportEbsVolumes`, `supportClusterTags`, `supportPortForwarding`), others are `*Capable` booleans (`photonWorkerCapable`, `photonDriverCapable`). +- **Category:** 17 (inconsistent boolean prefix: `is*`/`support*`/`*Capable`). +- **Suggested name:** Pick one convention (`is*Supported`). +- **Rationale:** Three different boolean-naming patterns on one struct. + +### 72. `NodeType.supportEbsVolumes` field name — `src/v2/model.ts:2362` +- **Why weird:** Singular verb `support` (third-person plural would be "supports"). All siblings: `supportClusterTags`, `supportPortForwarding`. Three fields use the singular form. +- **Category:** 13 (verb tense — should be `supports`). +- **Suggested name:** `supportsEbsVolumes`, `supportsClusterTags`, `supportsPortForwarding`. +- **Rationale:** Subject-verb agreement in field names is common (`hasFoo`, `isFoo`, `supportsFoo`). + +### 73. `NodeType.photonWorkerCapable` / `photonDriverCapable` — `src/v2/model.ts:2382,2383` +- **Why weird:** No JSDoc. `*Capable` suffix is a different boolean convention from `is*`/`support*`. +- **Category:** 17 (inconsistent boolean shape), Observation (missing doc). +- **Suggested name:** `isPhotonWorkerSupported`, `isPhotonDriverSupported` (or `supportsPhotonAsWorker`). +- **Rationale:** Same pattern as #71. + +### 74. `TerminationReason.parameters: Record` — `src/v2/model.ts:2561` +- **Why weird:** Generic-named map. `parameters` could mean anything. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `details`, `metadata`, `errorContext`. +- **Rationale:** Clarifies the role of the map. + +### 75. `AutoScale` type name — `src/v2/model.ts:805` +- **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. +- **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). +- **Suggested name:** `Autoscale` (one word, matching the field). +- **Rationale:** Matches sibling naming (`autoscale: Autoscale`). + +### 76. `*FieldMaskSchema` constants — `src/v2/model.ts:4247-4413` +- **Why weird:** 13 lowerCase-starting consts named `autoScaleFieldMaskSchema`, `awsAttributesFieldMaskSchema`, etc. These are internal to the package. `updateCluster_UpdateClusterResourceFieldMaskSchema` (line 4329) carries the underscore from its parent type. Pure scaffolding. +- **Category:** 4 (underscore), Observation (internal scaffolding). +- **Suggested name:** No public API impact; flagged for completeness. +- **Rationale:** Generated content. + +### 77. `marshalX` / `unmarshalX` verb asymmetry — `utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) and `marshalRequest` (encode) — same pair-asymmetry noted in `abacpolicies.md` audit. `parseResponse` reads the body, `marshalRequest` writes it. Names are non-mirrored verbs. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse`/`marshalRequest` or `parseResponse`/`serializeRequest`. +- **Rationale:** Pair-wise verb consistency aids reading. + +## Observations + +### 78. Seven Waiter classes with identical shape — `client.ts:879-1435` +The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState_ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. +- **Category:** 12 (duplicate concept across seven classes), Observation. +- **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. + +### 79. `_req` parameter for empty request types — `client.ts:343,422,447` +Several methods take a `_req: ListAvailableZones` / `_req: ListNodeTypes` / `_req: GetSparkVersions` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. +- **Category:** Observation (generator artefact). + +### 80. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` +- **Why weird:** Three sibling booleans use `enable*` prefix. `is*` is the more idiomatic JS boolean convention. Inconsistent with `isSingleNode`, `isCompliant`, `isDeprecated`. +- **Category:** 17 (mixed `enable*` and `is*` for booleans). +- **Rationale:** Naming-convention drift. + +### 81. `ResizeCluster` / `RestartCluster` requests are partial overlaps +`ResizeCluster` carries `clusterId` and `size`; `RestartCluster` carries `clusterId` and `restartUser`; `StartCluster` carries only `clusterId`. Three near-identical types; could be one. +- **Category:** 12 (duplicate concept), Observation. + +### 82. `marshal*Schema` / `unmarshal*Schema` constants are individually named per type — 35 marshal + 35 unmarshal exports +Naming follows `marshalXxxSchema` / `unmarshalXxxSchema`. Convention is consistent but the underscored proto-style nesting carries over (`unmarshalEnforcePolicyComplianceForCluster_Response_ClusterSettingsChangeSchema` is a 67-character identifier). +- **Category:** 7 (overly verbose), Observation. + +### 83. `_req` unused vs `req` used — inconsistency in method-signature lint +Five client methods use `_req` (where the request type is empty), 15 use `req` (where it's not). Pure mechanical. +- **Category:** Observation. + +### 84. `clusterId?: string | undefined` shape +Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:204,246,296,565,604,651,729`). +- **Category:** 6 (misleading optional — should be required), Observation. + +### 85. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) +Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). +- **Category:** 1 (vague), 17 (inconsistent), Observation. + +### 86. `flattenQueryParams` exported but unused (`utils.ts:123`) +The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. +- **Category:** Observation (dead public surface). + +### 87. JSDoc placeholder `` — pervasive +Throughout the model, JSDocs say `` (e.g., `model.ts:1097` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. +- **Category:** Observation (doc-quality artefact in generator). + +## Domain glossary + +- `dbfs` — Databricks File System. +- `dbr` — Databricks Runtime (cluster runtime image). +- `dbu` — not encountered. +- `adls` — Azure Data Lake Storage (used as `Adlsgen2Info`, wire `abfss`). +- `abfss` — Azure Blob File System Secure (wire-side name for ADLS Gen2 destinations). +- `gcs` — Google Cloud Storage. +- `s3` — Amazon S3. +- `wsfs` — Workspace File System (per `WorkspaceStorageInfo` JSDoc). +- `ebs` — Elastic Block Store (AWS). +- `kms` — Key Management Service (AWS/GCP). +- `iam` — Identity and Access Management (AWS). +- `cmk` — Customer-Managed Key (`AZURE_BYOK_*`, `GCP_INACCESSIBLE_KMS_KEY_FAILURE` JSDoc). +- `byok` — Bring Your Own Key (cloud-key terminology, used in `AZURE_BYOK_KEY_PERMISSION_FAILURE`). +- `byoc` — Bring Your Own Container (used in JSDoc `"Custom docker image BYOC"`). +- `byo-vpc`, `byo-vnet` — Bring Your Own VPC/VNet (mentioned in JSDoc for `SLOW_IMAGE_DOWNLOAD`). +- `acl` — Access Control List. +- `arn` — Amazon Resource Name. +- `vpc` — Virtual Private Cloud (AWS). +- `vnet` — Virtual Network (Azure). +- `vm` — Virtual Machine. +- `gpu` — Graphics Processing Unit. +- `nvme` — Non-Volatile Memory Express (storage). +- `sse-s3` / `sse-kms` — Server-Side Encryption (S3 algorithms). +- `gke` — Google Kubernetes Engine (`GKE_BASED_CLUSTER_TERMINATION`). +- `k8s` — Kubernetes (used throughout `TerminationCode`). +- `repl` — Read-Eval-Print Loop (Spark REPL, per `model.ts:1021`). +- `jdbc` — Java Database Connectivity. +- `dns` — Domain Name System. +- `nic` — Network Interface Card (per `NETWORK_CHECK_NIC_FAILURE`). +- `nfs` — Network File System (per `NFS_MOUNT_FAILURE`). +- `npip` — No Public IP (Databricks networking jargon). +- `pat` — Personal Access Token (per `model.ts:592`). +- `sdp` — implied by client.ts:746 ("Databricks Jobs, SDP, or Models services"). Likely "Serverless Data Platform" or "Streaming Data Pipelines". +- `cmv1` / `cmv2` — Cluster Manager v1/v2 (Databricks internal scheduler generations). +- `imv2` — Instance Manager v2 (Databricks internal infra, per `INVALID_WORKER_IMAGE_FAILURE`). +- `nephos` — Internal serverless infra name (per `NEPHOS_RESOURCE_MANAGEMENT`). +- `cmk` — Customer-Managed Key. +- `chauffeur` — Internal Databricks driver-orchestration daemon (per `DRIVER_UNREACHABLE`). +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). +- `sts` — AWS Security Token Service (per `STS_CLIENT_SETUP_FAILURE`). +- `cprf` / `cplf` — Control Plane Request Failure / Cloud Provider Launch Failure (per `model.ts:618-620`). +- `sev_snp` — AMD Secure Encrypted Virtualization — Secure Nested Paging (GCP confidential VM, per `model.ts:71`). +- `csp` — Cloud Service Provider (per `is_csp_unified` in `model.ts:699`). +- `luks` — Linux Unified Key Setup (disk encryption, per `enableLocalDiskEncryption` JSDoc). +- `uc` — Unity Catalog (referenced in `VolumesStorageInfo`). +- `aip` — API Improvement Proposal (`https://google.aip.dev/161` referenced in `updateMask` field doc). + +## File coverage +- `src/v2/model.ts` (4414 lines): read fully (in 600-line chunks). +- `src/v2/client.ts` (1435 lines): read fully. +- `src/v2/utils.ts` (150 lines): read fully. diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md new file mode 100644 index 00000000..31dfc36c --- /dev/null +++ b/.agent/naming-audit/commandexecution.md @@ -0,0 +1,640 @@ +# Naming Audit: `@databricks/sdk-commandexecution` (v2) + +**Package:** `@databricks/sdk-commandexecution` +**Path:** `/home/parth.bansal/sdk-js/packages/commandexecution/` +**Audited version:** `v2` +**Files audited:** `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/utils.ts`, +`src/v2/index.ts`. + +This audit flags naming issues using the 20-category framework. Each finding +has: ID, location, current name, category, severity, problem, and proposed +name. Severity scale: **high** (public API confusing, blocks readability), **medium** +(inconsistency, minor cognitive load), **low** (polish). + +The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a +`Context` (REPL session) on a `Cluster`. Three resources mix freely in names — +**this is the dominant source of naming pain.** + +--- + +## Summary of Findings + +| # | Severity | Category | Location | Current | Proposed | +| -- | -------- | -------- | -------- | ------- | -------- | +| 1 | high | 2. Redundant enum prefix | `model.ts:21-29` | `CommandStatus.COMMAND_*` | `CommandStatus.Cancelled`, etc. | +| 2 | high | 2. Redundant enum prefix | `model.ts:31-36` | `ContextStatus.CONTEXT_*` | `ContextStatus.Running`, etc. | +| 3 | high | 2. Redundant enum prefix + 18. Long enum values | `model.ts:46-53` | `ResultType.*_RESULT` | `ResultType.Error`, etc. | +| 4 | high | 4. Underscores in TS identifiers | `model.ts:22,32,39,47` | `*_UNSPECIFIED` enum members | Omit altogether (idiomatic TS) | +| 5 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | +| 6 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | +| 7 | high | 15. Generic field on container | `model.ts:71`, `model.ts:100,112` | `id?: string` (three different IDs) | `contextId`, `commandId` (typed by domain) | +| 8 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | +| 9 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | +| 10 | high | 1. Vague/generic | `model.ts:89` | `command?: string` (field, inside `ExecuteCommandRequest`) | `code` | +| 11 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | +| 12 | medium | 9. Singular/plural mismatch | `model.ts:102,116-143` | `results?: Results` (`Results` is one object) | `result?: Result` | +| 13 | medium | 1. Vague/generic | `model.ts:119` | `data?: JsonValue` | Inline rename to domain (e.g. `tableData`), or document semantics | +| 14 | medium | 16. Field contradicts type domain | `model.ts:129,131` | `fileName`, `fileNames` (used for image data URLs) | `imageData`, `imageDataList` (or `image`, `images`) | +| 15 | medium | 1. Vague/generic | `model.ts:135` | `pos?: number` | `position` (also rename comment to public-friendly) | +| 16 | medium | 1. Vague/generic | `model.ts:138` | `schema?: JsonObject[]` | `tableSchema` (qualify what schema) | +| 17 | medium | 19. Underspecified IDs | `model.ts:71,100,112` | `id?: string` | `contextId` / `commandId` per response | +| 18 | medium | 19. Underspecified IDs | `client.ts:336,337,338` | `clusterId`, `contextId`, `commandId` (fine, but match in `Results.id`) | Audit pass for consistency | +| 19 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | +| 20 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | +| 21 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to present participle or to noun (e.g. `Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, `Running`) | +| 22 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | +| 23 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | +| 24 | medium | 14. Go/Java-style names | `model.ts:74,156` | `DestroyContextRequest` / `unmarshalDestroyResponseSchema` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 25 | medium | 14. Go/Java-style names | `model.ts:145-253` | `marshal*Schema`, `unmarshal*Schema` | Go-isms; TS audiences use `serialize`/`deserialize` or `encode`/`decode`. Schema-level only, low blast radius. | +| 26 | medium | 8. Redundant suffixes | `model.ts:145,148,156,159,172,183` | `unmarshal*Schema`, `marshal*Schema` | Both `marshal`+`Schema` suffixes; one is enough | +| 27 | medium | 8. Redundant suffix | `client.ts:333,417,498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 28 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 29 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 30 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 31 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 32 | medium | 18. Long enum values | `model.ts:22-28` | `COMMAND_STATUS_UNSPECIFIED` | Drop the `*_UNSPECIFIED` sentinel in TS (TS represents absence via `undefined`) | +| 33 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | +| 34 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | +| 35 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | +| 36 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | +| 37 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | +| 38 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #16 | +| 39 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | +| 40 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #10 | +| 41 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 42 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 43 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #14 | + +--- + +## Detailed Findings + +### Finding 1 — High — Cat 2 (Redundant enum prefix) +**Location:** `src/v2/model.ts:21-29` +```ts +export enum CommandStatus { + COMMAND_STATUS_UNSPECIFIED = 'COMMAND_STATUS_UNSPECIFIED', + COMMAND_CANCELLED = 'COMMAND_CANCELLED', + COMMAND_CANCELLING = 'COMMAND_CANCELLING', + COMMAND_ERROR = 'COMMAND_ERROR', + COMMAND_FINISHED = 'COMMAND_FINISHED', + COMMAND_QUEUED = 'COMMAND_QUEUED', + COMMAND_RUNNING = 'COMMAND_RUNNING', +} +``` +Every member begins with `COMMAND_`. At a callsite this becomes +`CommandStatus.COMMAND_CANCELLED`, which is verbose and noisy. TypeScript's +namespacing already makes the prefix redundant. +**Proposed:** strip the `COMMAND_` prefix; use idiomatic PascalCase: +`CommandStatus.Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, +`Running`. (See also #5 for casing.) + +--- + +### Finding 2 — High — Cat 2 (Redundant enum prefix) +**Location:** `src/v2/model.ts:31-36` +```ts +export enum ContextStatus { + CONTEXT_STATUS_UNSPECIFIED = 'CONTEXT_STATUS_UNSPECIFIED', + CONTEXT_RUNNING = 'CONTEXT_RUNNING', + CONTEXT_PENDING = 'CONTEXT_PENDING', + CONTEXT_ERROR = 'CONTEXT_ERROR', +} +``` +Same as #1. The `CONTEXT_` prefix is redundant inside `ContextStatus`. +**Proposed:** `ContextStatus.Running`, `Pending`, `Error` (or `Failed`). + +--- + +### Finding 3 — High — Cat 2 & Cat 18 (Long enum values) +**Location:** `src/v2/model.ts:46-53` +```ts +export enum ResultType { + RESULT_TYPE_UNSPECIFIED = 'RESULT_TYPE_UNSPECIFIED', + ERROR_RESULT = 'ERROR_RESULT', + IMAGE_RESULT = 'IMAGE_RESULT', + IMAGES_RESULT = 'IMAGES_RESULT', + TABLE_RESULT = 'TABLE_RESULT', + TEXT_RESULT = 'TEXT_RESULT', +} +``` +Members carry `_RESULT` suffix; the enum is *already* called `ResultType`. +Tautology. +**Proposed:** `ResultType.Error`, `Image`, `Images`, `Table`, `Text` (see also +#5 for casing; #4 for sentinel). + +--- + +### Finding 4 — High — Cat 4 (Underscores) + redundancy +**Location:** all four enums. +**Issue:** `*_UNSPECIFIED` sentinel members on every enum +(`COMMAND_STATUS_UNSPECIFIED`, `CONTEXT_STATUS_UNSPECIFIED`, +`LANGUAGE_UNSPECIFIED`, `RESULT_TYPE_UNSPECIFIED`). Sentinel-style +"unspecified" values come from protobuf/Go and have no TypeScript audience +— TS uses `undefined` natively. They surface in `?: Status | undefined` +fields, so consumers will either ignore them or accidentally compare against +them. +**Proposed:** omit the `*_UNSPECIFIED` members from the TS-facing enum; the +wire-level deserialiser may still tolerate them, but the public type should +not advertise a "no value selected" *value*. + +--- + +### Finding 5 — High — Cat 4 (Underscores in TS identifiers) +**Location:** every enum member in `model.ts:22-53`. +**Issue:** TS identifier convention is PascalCase for type-namespace +members. `COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`, `SCALA` are all +SHOUTY_SNAKE_CASE, which violates the Google TypeScript style guide +(`SCREAMING_SNAKE_CASE` only for *constants*, not enum members). +**Proposed:** convert every enum identifier to PascalCase. The string value +may retain the wire format (`COMMAND_CANCELLED`) to preserve serialisation, +but the *identifier* should be `Cancelled`. Example: +```ts +export enum CommandStatus { + Cancelled = 'COMMAND_CANCELLED', + Cancelling = 'COMMAND_CANCELLING', + Failed = 'COMMAND_ERROR', + Finished = 'COMMAND_FINISHED', + Queued = 'COMMAND_QUEUED', + Running = 'COMMAND_RUNNING', +} +``` + +--- + +### Finding 6 — High — Cat 12 (Duplicate concepts) +**Location:** `src/v2/model.ts:70` and `src/v2/client.ts:289` +```ts +export interface CreateResponse { + id?: string | undefined; +} +... +async execute(req: ExecuteCommandRequest, ...): Promise +``` +`CreateResponse` is used for *both* `create()` (returns a context id) and +`execute()` (returns a command id). The type's name implies "creation", +but `execute()` is not a creation operation in the public-API sense — the +shared shape is incidental, not semantic. Reusing the type forces a +caller reading `response.id` to know the operation to interpret it. +**Proposed:** split into `CreateContextResponse { contextId?: string }` and +`ExecuteCommandResponse { commandId?: string }`. Each typed `id` field by +its true domain (see #7/#17). + +--- + +### Finding 7 — High — Cat 15 (Generic field loses meaning) +**Location:** `src/v2/model.ts:71, 100, 112` +```ts +export interface CreateResponse { id?: string | undefined; } +export interface GetCommandStatusResponse { id?: string | undefined; ... } +export interface GetContextStatusResponse { id?: string | undefined; ... } +``` +The field name `id` is meaning-free outside its container, and the +container's name doesn't disambiguate (`CreateResponse` is used for two +different create-like operations — see #6). A caller writing `resp.id` +cannot tell whether it is a command id or a context id. +**Proposed:** rename per-response: `contextId` / `commandId`. This couples +the schema to the resource, eliminating ambiguity. + +--- + +### Finding 8 — High — Cat 17 (Inconsistent action verbs) +**Location:** `src/v2/client.ts:256` +```ts +/** Deletes an execution context. */ +async destroy(req: DestroyContextRequest, ...) +``` +The JSDoc says "Deletes" while the method is named `destroy`. The URL is +`/api/1.2/contexts/destroy`. Three different verbs (`destroy`, `delete`, plus +`cancel` for commands) live in the same domain. +**Proposed:** keep `destroy` if the backend route is canonical; otherwise +align with the Go SDK convention. At minimum, edit the JSDoc to say +"Destroys" so name and doc agree. + +--- + +### Finding 9 — High — Cat 17 (Inconsistent action verbs) +**Location:** `src/v2/client.ts:139, 176` +```ts +async commandStatus(req: GetCommandStatusRequest, ...) +async contextStatus(req: GetContextStatusRequest, ...) +``` +The *request types* are `GetCommandStatusRequest` / `GetContextStatusRequest` +(with `Get` prefix), but the methods drop the verb. Now `commandStatus` and +`contextStatus` read like getters/properties, not methods. Inconsistent with +`cancel`, `create`, `destroy`, `execute` which all start with a verb. +**Proposed:** rename `getCommandStatus()` and `getContextStatus()`. Matches +the request-type name and is verb-led like the other methods. + +--- + +### Finding 10 — High — Cat 1 & Cat 15 (Vague / generic field name) +**Location:** `src/v2/model.ts:89` +```ts +/** Executable code */ +command?: string | undefined; +``` +The field is named `command` and lives in `ExecuteCommandRequest`. The +container says "command", the field says "command" — yet the value is +source code, not the abstract command. A user reading +`req.command = "print(1+1)"` has to mentally bridge "the string content of +the command". +**Proposed:** rename `code`. The JSDoc already says "Executable code". This +also matches the conceptual model: a `Command` *contains* `code`. + +--- + +### Finding 11 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +**Location:** `src/v2/model.ts:117-143` +```ts +export interface Results { ... } +``` +The type is called `Results` (plural) but represents **one** command's +result — a single `cause`, single `summary`, single `resultType`, single +`data` object. The plurality comes from the wire-level `fileNames` array +inside it, not from multiple results. +**Proposed:** rename to `Result` (singular). The field +`GetCommandStatusResponse.results` becomes `result` (see #12). + +--- + +### Finding 12 — Medium — Cat 9 (Singular/plural mismatch) +**Location:** `src/v2/model.ts:102` (field) and `model.ts:116` (type) +```ts +results?: Results | undefined; +``` +Pairs with #11. The field name and the type are both pluralised but +represent a singular result. +**Proposed:** `result?: Result;` once #11 is applied. + +--- + +### Finding 13 — Medium — Cat 1 (Vague/generic) +**Location:** `src/v2/model.ts:119` +```ts +data?: JsonValue | undefined; +``` +`data` is the most generic field name possible. The shape `JsonValue` +gives no help. According to API docs, this is typically the table/text data +returned by the command. +**Proposed:** investigate intended payload. Likely `tableData` or split per +`resultType` discriminant. As a minimum, JSDoc must explain the polymorphism +("payload of `result.data` is determined by `resultType`: …"). + +--- + +### Finding 14 — Medium — Cat 16 (Field contradicts type domain) +**Location:** `src/v2/model.ts:129, 131` +```ts +/** The image data in one of the following formats: + * 1. A Data URL with base64-encoded image data: `data:image/{type};base64,...` + * 2. A FileStore file path for large images: `/plots/{filename}.png` + */ +fileName?: string | undefined; +/** List of image data for multiple images. ... */ +fileNames?: string[] | undefined; +``` +The JSDoc explicitly says "image data" — yet the fields are called +`fileName(s)`. The values are not file names: case 1 is a `data:` URL +literal, case 2 is a path. Either way the *content* is image data, +not a filename. +**Proposed:** `imageData` / `imageDataList` (or `image` / `images`). This +is a public API; mis-named fields will outlive their fix window. + +--- + +### Finding 15 — Medium — Cat 1 (Cryptic abbreviation / vague) +**Location:** `src/v2/model.ts:135` +```ts +/** internal field used by SDK */ +pos?: number | undefined; +``` +`pos` is cryptic (Cat 5 — cryptic abbreviation). The comment "internal +field used by SDK" suggests this should not be on the public type at all. +**Proposed:** either expand to `position` and document, or drop from the +public interface entirely. Internal fields belong on private types. + +--- + +### Finding 16 — Medium — Cat 1 (Vague/generic) +**Location:** `src/v2/model.ts:138` +```ts +/** The table schema */ +schema?: JsonObject[] | undefined; +``` +`schema` is colliding with a globally overloaded term — also see zod's own +`schema` used heavily in the file. Within a polymorphic `Result`, the +*kind* of schema must be clear. +**Proposed:** `tableSchema` (matches JSDoc); confirm whether it is +populated for non-table result types. + +--- + +### Finding 17 — Medium — Cat 19 (Underspecified IDs) +**Location:** `src/v2/model.ts:71, 100, 112` +**Issue:** Same as #7. Every response that carries an identifier uses +`id?: string` with no domain qualifier. +**Proposed:** Rename per-response (`contextId`, `commandId`). Public-API +clarity outweighs minor breakage. + +--- + +### Finding 18 — Medium — Cat 19 (Underspecified IDs) — consistency only +**Location:** `src/v2/client.ts:336-338, 417-422, 498-503` (Waiter fields) +**Issue:** Waiter classes correctly use `clusterId`, `contextId`, +`commandId`. The inconsistency is only in `Results` / `*Response` (#7/#17). +**Proposed:** apply the same explicit-id pattern to all response types so +the public surface is uniform. + +--- + +### Finding 19 — Medium — Cat 7 (Overly verbose) +**Location:** `src/v2/model.ts:99, 111` +```ts +export interface GetCommandStatusResponse { ... } +export interface GetContextStatusResponse { ... } +``` +`Get*Response` is a common Go/protobuf pattern. In TS the HTTP verb does +not need to leak into the type name: the type's role is "the value +returned", not "the response to a GET". +**Proposed:** `CommandStatusResponse`, `ContextStatusResponse` (or simply +`CommandStatus`, but that collides with the enum — keep `*Response`). + +--- + +### Finding 20 — Medium — Cat 20 (Type-suffix tautology) — call-out only +**Location:** `src/v2/model.ts:55, 64, 74, 82, 93, 106` +```ts +CancelCommandRequest, CreateContextRequest, DestroyContextRequest, +ExecuteCommandRequest, GetCommandStatusRequest, GetContextStatusRequest +``` +**Issue:** `*Request` is a request type — the suffix repeats what the type +class already says. However, for *request DTOs* (named arguments) the +convention is widely accepted across REST SDKs. +**Proposed:** leave as-is; flagged only for SDK-wide consistency review. + +--- + +### Finding 21 — Medium — Cat 13 (Verb-tense inconsistency) +**Location:** `src/v2/model.ts:23-28` +```ts +COMMAND_CANCELLED // past participle +COMMAND_CANCELLING // present participle (transitional) +COMMAND_ERROR // noun +COMMAND_FINISHED // past participle +COMMAND_QUEUED // past participle +COMMAND_RUNNING // present participle +``` +`ERROR` is a noun; everything else is a verbal form. `ERROR` should be +`FAILED` (past participle) to match the pattern. +**Proposed:** `Failed` in place of `Error`. (Same applies to +`CONTEXT_ERROR` in Finding 2 / #2.) + +--- + +### Finding 22 — Medium — Cat 3 (Acronym casing) +**Location:** `src/v2/model.ts:133` +```ts +isJsonSchema?: boolean | undefined; +``` +`Json` is treated as a compound (PascalCase). Cross-package +`@databricks/sdk-core/wkt` uses `JsonValue`, `JsonObject` — consistent. +Project convention: treat JSON as `Json`, not `JSON`. Confirm the rule is +recorded in `.agent/rules/typescript.mdc`. +**Proposed:** keep as-is; document the rule. + +--- + +### Finding 23 — Medium — Cat 12 (Duplicate concepts) +**Location:** `src/v2/client.ts:286-309` +**Issue:** `execute()` returns `Promise`. The conflation +of "create a context" and "execute returns an id" is artificial. See #6. + +--- + +### Finding 24 — Medium — Cat 14 (Go/Java-style names) +**Location:** `src/v2/model.ts:74` + `client.ts:256` +**Issue:** `destroy` is unusual for a REST SDK. JS conventions favour +`delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend +path is `/contexts/destroy`, so renaming the *method* would diverge. +**Proposed:** confirm with the Go SDK reference; if Go uses `Destroy`, +keep parity. Otherwise rename method to `delete()` (collides with TS +reserved word in expressions — typically requires bracket access). + +--- + +### Finding 25 — Medium — Cat 14 (Go/Java-style) +**Location:** `src/v2/model.ts:145-253` +```ts +unmarshalCancelResponseSchema, marshalCreateContextRequestSchema, ... +``` +**Issue:** `marshal` / `unmarshal` are Go terms. The TS audience reads +`serialize` / `deserialize` or `encode` / `decode`. These names are +exported and surface in stack traces. +**Proposed:** `serializeCreateContextRequest` / `deserializeCancelResponse` +(without `Schema` suffix — see #26). Since these are internal to the +generated layer, the blast radius is small. + +--- + +### Finding 26 — Medium — Cat 8 (Redundant suffixes) +**Location:** `src/v2/model.ts:145, 148, 156, 159, 172, 183, 209, 221, 231, 241` +**Issue:** `marshal*Schema` and `unmarshal*Schema` carry two role suffixes +(both the action verb and the artefact type). A schema is implied by zod's +`z.ZodType`. +**Proposed:** drop `Schema` suffix once #25 is applied: +`serializeCreateContextRequest`, `deserializeResult`, etc. + +--- + +### Finding 27 — Medium — Cat 8 (Redundant suffix) — call-out +**Location:** `src/v2/client.ts:333, 417, 498` +**Issue:** Three classes named `*Waiter`. Acceptable if waiter is a +recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The +issue is what they wait *for*: see #28-#30. + +--- + +### Finding 28 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:417` +```ts +export class CreateWaiter { ... } +``` +The class waits for a *context* to reach `CONTEXT_RUNNING`. The name +"CreateWaiter" implies it waits for "create" to finish, but the +operation it's bound to (`createWaiter()`) returns immediately after +the context create call; the *waiter* polls a different endpoint +(`contextStatus`) for terminal state. +**Proposed:** `CreateContextWaiter` or `ContextWaiter` (parallel to the +target endpoint). + +--- + +### Finding 29 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:333` +**Issue:** `CancelWaiter` waits for *command* cancellation. +**Proposed:** `CancelCommandWaiter`. + +--- + +### Finding 30 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:498` +**Issue:** `ExecuteWaiter` waits for *command* completion. +**Proposed:** `ExecuteCommandWaiter`. + +--- + +### Finding 31 — Medium — Cat 17 (Inconsistent action verbs) — call-out +**Location:** `src/v2/client.ts:86, 256` +**Issue:** This package uses three lifecycle verbs: +- `cancel()` on a command, +- `destroy()` on a context, +- `delete` (in JSDoc) on a context. +Three verbs for two lifecycle actions reads awkward. +**Proposed:** keep `cancel` (correct for commands — cancel is the right +verb for in-flight async work). Reconcile `destroy`/`delete` per the +Go-SDK alignment decision. + +--- + +### Finding 32 — Medium — Cat 18 (Long enum values) +**Location:** `src/v2/model.ts:22, 32, 39, 47` +**Issue:** `COMMAND_STATUS_UNSPECIFIED`, `CONTEXT_STATUS_UNSPECIFIED`, +`LANGUAGE_UNSPECIFIED`, `RESULT_TYPE_UNSPECIFIED`. Long sentinel value +strings expose the protobuf convention to JS consumers. TS uses +`undefined` for unspecified. +**Proposed:** drop the members entirely (see #4). + +--- + +### Finding 33 — Low — Cat 1 (Vague/generic) +**Location:** `src/v2/model.ts:117-118` +```ts +/** The cause of the error */ +cause?: string | undefined; +``` +`cause` is fine as a JSDoc-clarified concept, but it lives flat on a +`Result` that may *not* be an error. Coupling `cause`/`summary` to the +`resultType === ERROR_RESULT` discriminant would clarify. +**Proposed:** consider an `error?: { cause: string; summary: string }` +sub-object; or keep flat and document conditional presence. + +--- + +### Finding 34 — Low — Cat 1 (Vague/generic) +**Location:** `src/v2/model.ts:139-140` +```ts +/** The summary of the error */ +summary?: string | undefined; +``` +Same as #33. The field is generic; the JSDoc reveals it's +error-specific. + +--- + +### Finding 35 — Low — Cat 1 (Underspecified) +**Location:** `src/v2/model.ts:141-142` +```ts +/** true if partial results are returned. */ +truncated?: boolean | undefined; +``` +Acceptable but ambiguous: truncated *what*? table rows? text length? +**Proposed:** document the truncation unit. + +--- + +### Finding 36 — Low — Cat 1 (Vague/generic) — call-out +**Location:** `src/v2/client.ts:54` +```ts +class StillRunningError extends Error {} +``` +Private, OK. Idiomatic for waiter polling patterns. + +--- + +### Finding 37 — Low — Cat 3 (Acronym casing) — non-issue +**Location:** `src/v2/client.ts:49-52` +```ts +const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; +``` +`PACKAGE_SEGMENT` is a true constant (SCREAMING_SNAKE_CASE is correct). +Mixed with `userAgent` (camelCase method-scope variable). Both are +correctly cased per the project rules. + +--- + +### Finding 38 — Low — Cat 10 (Reserved-word collision) — borderline +**Location:** `src/v2/model.ts:138` +**Issue:** `schema` is not a TS reserved word but is heavily aliased +across libraries (zod, JSON schema, table schema, GraphQL schema). See #16. + +--- + +### Finding 39 — Low — Cat 14 — non-issue +**Location:** `src/v2/client.ts:54` +**Issue:** `StillRunningError` is named in idiomatic TS style +(`*Error` suffix on classes extending Error). + +--- + +### Finding 40 — Low — duplicate of #10 +**Location:** `src/v2/model.ts:89` +Same finding as #10. + +--- + +### Finding 41 — Low — Cat 15 (Generic field) — call-out +**Location:** `src/v2/model.ts:67, 87` +`language?: Language` is correct. + +--- + +### Finding 42 — Low — Cat 3 (Acronym casing in enum string values) +**Location:** `src/v2/model.ts:42-43` +```ts +SQL = 'SQL', +R = 'R', +``` +Identifier `SQL` is all-caps (3 letters → standard "≤3 letter acronym +all caps") in the language enum. `R` is single-letter — naturally all +caps. Apply the casing rule (#5) and these become `Sql` (if the rule is +"acronyms PascalCase") or remain `SQL`/`R` (if "≤3 letters all caps"). +**Proposed:** consult `typescript.mdc`; pick a rule and apply globally. + +--- + +### Finding 43 — Low — duplicate of #14 +**Location:** `src/v2/model.ts:131` +`fileNames?: string[]` for images — same as #14. + +--- + +## Top Themes + +1. **Wire-format leakage** — protobuf casing, `*_UNSPECIFIED` sentinels, + `marshal`/`unmarshal` Go verbs, and redundant enum-prefix members all + bleed from the source IDL into the public TS surface. The fix is a + project-wide style rule applied at the generator level: + - PascalCase enum identifiers with wire-string values preserved; + - drop `*_UNSPECIFIED`; + - rename `marshal`/`unmarshal` to `serialize`/`deserialize`. + +2. **Three-resource ambiguity** — `Cluster`, `Context`, `Command` are easy + to confuse, but the public types use the generic field `id` and reuse + `CreateResponse` for two unrelated operations. Findings #6, #7, #10, + #11, #12, #14, #17, #19, #28-#30 all stem from one decision: **never + say "id" when "commandId" or "contextId" would do, and never reuse a + response shape across resources**. Splitting `CreateResponse` into + `CreateContextResponse` and `ExecuteCommandResponse` cascades to fix + four other findings. + +3. **Verb inconsistency** — `cancel` (command), `destroy` (context), + `commandStatus` (no verb), `contextStatus` (no verb), `execute` (vs + `run`), `create`/`delete`/`destroy` mixing. Add `getCommandStatus` / + `getContextStatus` and pick one of `destroy`/`delete` to settle this. + +4. **Waiter-class names** — `CancelWaiter`, `CreateWaiter`, + `ExecuteWaiter` are too short to convey what they wait for and are + genericised against the resource axis. Renaming with the resource + (`CancelCommandWaiter`, `CreateContextWaiter`, `ExecuteCommandWaiter`) + removes a recurring source of confusion. diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md new file mode 100644 index 00000000..2b5666c1 --- /dev/null +++ b/.agent/naming-audit/connections.md @@ -0,0 +1,316 @@ +# Naming Audit: connections + +**Path:** `packages/connections/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. +**Total weird names flagged:** 46 + +## Summary +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 17 | +| Low | 11 | +| Observation | 5 | + +## High severity + +### 1. `ConnectionType.UNKNOWN_CONNECTION_TYPE` — `src/v1/model.ts:7` +- **Why weird:** Enum sentinel re-states the enum name (`ConnectionType.UNKNOWN_CONNECTION_TYPE`). Idiomatic TypeScript treats "unset" as `undefined` (the field is already `connectionType?: ConnectionType | undefined`), making an explicit `UNKNOWN_*` value redundant. +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names). +- **Suggested name:** Drop the sentinel and rely on the optional field, or rename to `ConnectionType.Unknown`. +- **Rationale:** TS enum members are namespaced by the enum itself. `Foo.FOO_BAR` is pure protobuf noise that the language already solves. + +### 2. `CredentialType.UNKNOWN_CREDENTIAL_TYPE` — `src/v1/model.ts:88` +- **Why weird:** Same problem as #1 — sentinel re-states enum name. +- **Category:** 2, 14. +- **Suggested name:** `CredentialType.Unknown` or drop entirely. +- **Rationale:** Identical to #1. + +### 3. `ConnectionType` value casing — `BIGQUERY`, `POSTGRESQL`, `MYSQL`, `SQLSERVER`, `SQLDW`, `WORKDAY_RAAS`, `GA4_RAW_DATA`, `MONDAY_COM` — `src/v1/model.ts:6-84` +- **Why weird:** Wire constants are flat SCREAMING_SNAKE but the domain has well-known camelCased product names (BigQuery, PostgreSQL, MySQL, SQL Server, Workday RaaS, GA4, Monday.com). Wire `BIGQUERY` is fine; TS-facing string literals lose the canonical brand casing. Some vendors collapse `POSTGRESQL` (one word, no underscore) but split `SAP_SUCCESSFACTORS`, `MICROSOFT_ENTRA_ID` — no consistent rule for which compound vendor names get an underscore. +- **Category:** 3 (acronym casing inconsistency across vendor names), 18 (long enum values littering the package surface). +- **Suggested name:** Either keep wire SCREAMING_SNAKE (current) and document, or move to a `Vendor` enum with PascalCase members (`Vendor.BigQuery`, `Vendor.Postgres`, `Vendor.MySql`). +- **Rationale:** Vendor names are proper nouns. Generator emits the proto enum verbatim; TS consumers will see `ConnectionType.POSTGRESQL` rather than the canonical `PostgreSQL`. Worth raising with API-design before the surface grows further. + +### 4. `ConnectionType.SQLDW` and `SQLSERVER` (no underscore) vs `SAP_SUCCESSFACTORS`, `WORKDAY_RAAS`, `META_MARKETING` — `src/v1/model.ts:12-13,29,69` +- **Why weird:** Compound product names — sometimes joined (`SQLDW` = "SQL Data Warehouse", `SQLSERVER` = "SQL Server"), sometimes split with underscore (`SAP_SUCCESSFACTORS`, `WORKDAY_RAAS`). No rule. Comparable to `POWER_BI` (underscore) vs `BIGQUERY` (joined). +- **Category:** 3 (casing inconsistency), 18 (long enum value set). +- **Suggested name:** Pick one convention. If splitting on word boundaries: `SQL_DW`, `SQL_SERVER`, `BIG_QUERY`, `POWER_BI`. If joining: `SAPSUCCESSFACTORS`, `WORKDAYRAAS`. Most ergonomic is to consolidate on word-split + underscores. +- **Rationale:** Internal inconsistency makes the type non-discoverable — a user typing `ConnectionType.SQL_` will autocomplete to nothing if the value is `SQLSERVER`. Probably wire-locked, but worth flagging upstream. + +### 5. `MONDAY_COM` — `src/v1/model.ts:56` +- **Why weird:** Encodes the TLD (`.com`) into the enum value. The vendor is "Monday.com" (the brand) but the SDK value becomes `MONDAY_COM` which reads as Monday and com. Other vendors don't include TLDs (no `HUBSPOT_COM`, `SLACK_COM`). +- **Category:** 3 (casing/branding), 6 (misleading: TLD baked into identifier). +- **Suggested name:** `MONDAY` (and document the canonical brand as "Monday.com" in a doc-comment). +- **Rationale:** Brand-as-domain doesn't belong in an enum value. If the API ever adds a non-com Monday product, this name decays. + +### 6. `EnvironmentSettings` — `src/v1/model.ts:278-281` +- **Why weird:** Top-level type whose name is so generic it conveys nothing. `Environment` is heavily overloaded (deployment environment, OS environment, shell environment, JS runtime environment). The type actually holds `javaDependencies: string[]` and `environmentVersion: string` — i.e. Java runtime / library bundle for the connection's compute environment. +- **Category:** 1 (vague), 15 (generic field name losing meaning). +- **Suggested name:** `ConnectionRuntimeSettings` or `JavaEnvironmentSettings`. +- **Rationale:** Reader of `EnvironmentSettings` cannot guess it means "Java deps and runtime version". Naming should communicate the contents. + +### 7. `EnvironmentSettings.environmentVersion` — `src/v1/model.ts:280` +- **Why weird:** Type-suffix tautology — field `environmentVersion` on a type called `EnvironmentSettings`. Reads `environmentSettings.environmentVersion` from a caller. Also doubly redundant. +- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). +- **Suggested name:** `version` (would read `environmentSettings.version`). +- **Rationale:** Wire stays `environment_version`; TS can drop the prefix since the containing type already says "environment". + +### 8. `DeleteConnection.nameArg` / `GetConnection.nameArg` / `UpdateConnection.nameArg` — `src/v1/model.ts:272,285,322` +- **Why weird:** Field named `nameArg` rather than `name`. The `Arg` suffix is a generator artefact (denoting path-arg / required-arg in the proto), but it leaks into the TS surface — users see `req.nameArg` everywhere. `ConnectionInfo` and `CreateConnection` already have a `name` field, so the inconsistency is jarring. +- **Category:** 14 (Go/proto-style name leak), 5 (`Arg` is a cryptic abbreviation), 17 (inconsistency: `name` vs `nameArg` for the same thing). +- **Suggested name:** `name` everywhere. (Wire stays `name_arg` if the API truly requires that path param convention.) +- **Rationale:** Three different request types have a `nameArg` field that semantically equals the connection name. Users will mistype `name` and get a runtime error. + +### 9. `DeleteConnection` / `GetConnection` / `CreateConnection` / `UpdateConnection` / `ListConnections` types — `src/v1/model.ts:203,270,283,288,320` +- **Why weird:** Request DTOs named as verb phrases (`DeleteConnection`, `GetConnection`). Reads as actions, not data. `import type {DeleteConnection}` looks like importing a function. Pattern is uniform across all five request types. +- **Category:** 6 (misleading: name implies behaviour), 14 (Go-style naming). +- **Suggested name:** `DeleteConnectionRequest`, `GetConnectionRequest`, etc. +- **Rationale:** TS conventions append `Request` to request DTOs. Especially confusing because the package also exports a `Client.deleteConnection(req: DeleteConnection)` — type and method names are identical in lowercase. + +### 10. `DeleteConnection_Response` — `src/v1/model.ts:276` +- **Why weird:** Underscore in identifier (proto-style nested type), requires `eslint-disable @typescript-eslint/naming-convention`. +- **Category:** 4 (underscore identifiers). +- **Suggested name:** `DeleteConnectionResponse`. +- **Rationale:** Mirror Go/proto naming with TS-idiomatic style. + +### 11. `ListConnections_Response` — `src/v1/model.ts:303-312` +- **Why weird:** Underscore in identifier. Required eslint disable. +- **Category:** 4 (underscore identifiers). +- **Suggested name:** `ListConnectionsResponse`. +- **Rationale:** Mirror Go/proto naming with TS-idiomatic style. + +### 12. `ConnectionInfo` — `src/v1/model.ts:141` +- **Why weird:** `Info` is the central domain entity — every type holds info about something. The Go SDK uses `XxxInfo` widely as a Go-style noun, but in TS the type would simply be `Connection`. `typescript.mdc` lists `Info` as a vague suffix. +- **Category:** 1 (vague suffix), 8 (redundant type suffix), 14 (Go-style name). +- **Suggested name:** `Connection`. +- **Rationale:** The domain noun is "connection". Stripping `Info` improves every reference (`connection.connectionType` → `Connection.connectionType`). + +### 13. `ProvisioningInfo_State` — `src/v1/model.ts:131` +- **Why weird:** Underscore in identifier (proto-style nested enum). Requires eslint disable. Idiomatic nested type access in TS is via namespaces (`ProvisioningInfo.State`). +- **Category:** 4 (underscore), 14 (proto-style). +- **Suggested name:** `ProvisioningInfo.State` via namespace, or top-level `ProvisioningState`. +- **Rationale:** Proto-style underscore-nested names leak generator output into the public surface. + +## Medium severity + +### 14. `ConnectionInfo.connectionType: ConnectionType` — `src/v1/model.ts:145` +- **Why weird:** Type-suffix tautology — field `connectionType` of type `ConnectionType` on a type called `ConnectionInfo`. Reads `connectionInfo.connectionType`. +- **Category:** 20. +- **Suggested name:** `type: ConnectionType`. (If `ConnectionInfo` is renamed to `Connection`, becomes `connection.type`.) +- **Rationale:** Wire stays `connection_type`; TS can drop the prefix. + +### 15. `ConnectionInfo.credentialType: CredentialType` — `src/v1/model.ts:159` +- **Why weird:** Same tautology as #14. +- **Category:** 20. +- **Suggested name:** `credential: CredentialType` or simply keep as-is since `credential` would also be ambiguous. +- **Rationale:** Less clear than #14; the prefix carries some semantic load (distinguishes credential type from credential value). + +### 16. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:172` +- **Why weird:** Type-suffix tautology. Also: the value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. +- **Category:** 20 (tautology), 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). +- **Suggested name:** Either drop the field (it's always `CONNECTION`), or rename to `securableKind: SecurableType` and document why a non-`CONNECTION` value would ever appear. +- **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. + +### 17. `ConnectionInfo.provisioningInfo: ProvisioningInfo` — `src/v1/model.ts:173` +- **Why weird:** Type-suffix tautology. +- **Category:** 20. +- **Suggested name:** `provisioning: ProvisioningInfo`. +- **Rationale:** Wire stays `provisioning_info`; TS can drop the prefix since the containing type already names the concept. + +### 18. `ConnectionInfo.connectionId` and `metastoreId` — `src/v1/model.ts:161-163` +- **Why weird:** Bare `id` doesn't appear, but two `xxxId` fields coexist. `connectionId` is the type-prefix tautology (same struct already says "Connection"); `metastoreId` clarifies which parent. Mixed levels of specificity. +- **Category:** 19 (underspecified id — `connectionId` is fine, but inconsistent with absence of just `id` somewhere). +- **Suggested name:** `id` for the connection's own identifier (it's `connection.id`, not `connection.connectionId`); keep `metastoreId` (it identifies a parent). +- **Rationale:** Self-id should be `id`; foreign-key ids should keep the prefix. This is the standard REST convention. + +### 19. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:142-155` +- **Why weird:** Two name-like fields (`name` and `fullName`) with no inline doc explaining the difference. The wire pattern in Unity Catalog is "name within a parent" vs "catalog.schema.connection_name", but the type doesn't say that. +- **Category:** 1 (vague — what makes a name "full"?), 17 (inconsistency: `name` is short, `fullName` is fully qualified but doc only says "Full name of connection"). +- **Suggested name:** Keep names; improve doc to clarify `fullName` is the dot-qualified path (`catalog.schema.connection_name`). +- **Rationale:** Naming is fine; documentation is the gap. Flagging because the readability of every field that pairs with `name` depends on knowing that `fullName` is the path-style form. + +### 20. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:149` +- **Why weird:** Boolean field name doesn't begin with `is`/`has` as is common for TS booleans. Reads `connection.readOnly` (acceptable adjective form) but sibling enums and types use noun forms. JS naming conventions are split, but inside this SDK most booleans use the adjective form, so this is consistent — flagging at low-medium severity because the rule itself is debatable. +- **Category:** 1 (vague form — `readOnly` could be a string of mode flags). +- **Suggested name:** Keep as `readOnly` (matches Go SDK and is widely used in JS). Optionally `isReadOnly`. +- **Rationale:** No strong convention either way; flagging because audit asked for booleans whose nature isn't obvious from the name. + +### 21. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `ConnectionInfo_SecretsEntry` — `src/v1/model.ts:186-201` +- **Why weird:** Three near-identical interfaces (`key?: string; value?: string`), one per map field. Each requires an `eslint-disable` for the underscore. The actual field on `ConnectionInfo` is `Record`, so these `*_Entry` types are never used at the consumer surface — pure generator scaffolding that nonetheless gets exported (`index.ts:14-20`). +- **Category:** 4 (underscores), 12 (duplicate concepts). +- **Suggested name:** Stop exporting these. They are pure proto-map artefacts. +- **Rationale:** `index.ts` exports them as types, polluting the public surface. Six such types exist (`ConnectionInfo_*`, `CreateConnection_*`, `UpdateConnection_*` each with three). + +### 22. `CreateConnection_*Entry` / `UpdateConnection_*Entry` types — `src/v1/model.ts:252-268,368-383` +- **Why weird:** Same problem as #21 multiplied across request DTOs. Six entry types in total, each `eslint-disable`d for the underscore. +- **Category:** 4, 12. +- **Suggested name:** Remove from generator output. +- **Rationale:** Generator should not emit one map-entry interface per map field per containing type. + +### 23. `CreateConnection` / `UpdateConnection` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:203,320` +- **Why weird:** `CreateConnection` is `ConnectionInfo + parent`. `UpdateConnection` is `ConnectionInfo + nameArg + newName`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnection` and `UpdateConnection` even though they're server-only). +- **Category:** 12 (duplicate concepts), 6 (misleading — user-settable vs server-set is invisible). +- **Suggested name:** Split server-only metadata into a base type and compose. Better still, type create/update inputs as `Pick` or a dedicated `ConnectionInput` interface. +- **Rationale:** Today a caller could set `connection.createdAt` on a create request and have no idea it's silently ignored. Type system can prevent this. + +### 24. `UpdateConnection.newName` and `nameArg` — `src/v1/model.ts:322-324` +- **Why weird:** `newName` (TS), wire `new_name`. Pair (`nameArg`, `newName`) means "rename connection X to Y". Function-style verb encoded in a field name (`new` + Name). +- **Category:** 5 (`newName` reads as a temporal modifier), 17 (also inconsistent with the type's own `name` field). +- **Suggested name:** `renameTo`, or split into a `RenameConnectionRequest` operation. +- **Rationale:** Cleaner API: rename and update are distinct operations. + +### 25. `UpdateConnection.name` field — `src/v1/model.ts:326` +- **Why weird:** `UpdateConnection` has THREE name-like fields: `nameArg` (path param, identifies which), `newName` (new name), AND `name` (also documented as "Name of the connection"). Both `nameArg` and `name` are documented identically and both refer to the existing connection. Easily mis-set; ambiguous which the server uses. +- **Category:** 12 (duplicate concept), 6 (misleading — three fields mean "the name"). +- **Suggested name:** Remove `name` from `UpdateConnection` (it duplicates `nameArg`). +- **Rationale:** Three fields for one concept is a bug surface. Worth pushing to API design. + +### 26. `parent` field on `CreateConnection` and `ListConnections` — `src/v1/model.ts:208,300` +- **Why weird:** Bare `parent` with the value encoded as a free-form string `"schemas/{catalog}.{schema}"`. Untyped wire format inside a field name that does not indicate a structured path. +- **Category:** 1 (vague), 5 (cryptic — what shape is `parent`?). +- **Suggested name:** `parentSchema`, with a clear doc that the format is `"schemas/{catalog}.{schema}"` (or model the catalog/schema pair as a structured type). +- **Rationale:** Pattern of "rest-resource string with embedded slashes" is common in Google APIs but feels out of place in a TS SDK. At minimum the field should signal it's a schema reference. + +### 27. `ListConnections.maxResults` semantics — `src/v1/model.ts:289-296` +- **Why weird:** Three different behaviours encoded in the same field: "not set → all results", "0 → server default", ">0 → bound by min(value, server-default)", "<0 → error". Numeric overload that is invisible from the name. +- **Category:** 6 (misleading — `maxResults` implies upper bound, but `0` actually requests server default). +- **Suggested name:** Either two separate fields (`pageSize` and `useServerDefault`), or document inline tersely. Keep name; flag as observation. +- **Rationale:** Name is fine; behaviour overloaded. Easy to call wrong. + +### 28. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:127` +- **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. +- **Category:** 18 (questionable enum value). +- **Suggested name:** Hide until promotion or mark `@experimental`. +- **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. + +### 29. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:102` +- **Why weird:** `SSWS` is cryptic. (Stands for "Single Sign-On Web Services" or Okta SSWS — Secure Single Sign-on. Either way, opaque.) Other tokens are named after their family (OAuth, OIDC, Bearer); SSWS is the only one with a literal product-specific acronym. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling values). +- **Suggested name:** `OKTA_SSWS_TOKEN` (if it's strictly Okta), or document in doc-comment. +- **Rationale:** Future readers cannot guess what SSWS expands to. + +### 30. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:103` +- **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while other vendor-coupled values put the vendor first (`OAUTH_GOOGLE_SERVICE_ACCOUNT`). Inconsistent word order. +- **Category:** 17 (inconsistency). +- **Suggested name:** `AKAMAI_EDGEGRID`. +- **Rationale:** Consistency with the `OAUTH_GOOGLE_*` pattern (vendor-first). + +### 31. `CredentialType.OAUTH_DCR` — `src/v1/model.ts:105` +- **Why weird:** `DCR` is opaque (probably "Dynamic Client Registration", an OAuth concept). No doc. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `OAUTH_DYNAMIC_CLIENT_REGISTRATION` or document in a doc-comment. +- **Rationale:** Users unfamiliar with OAuth specs cannot decode `DCR`. + +## Low severity + +### 32. `unmarshalConnectionInfoSchema` / `marshalCreateConnectionSchema` / `marshalUpdateConnectionSchema` and related — `src/v1/model.ts:386,471,539` +- **Why weird:** Three different verb prefixes (`marshal`/`unmarshal`) used as schema-name prefix. Function names communicate direction (`marshalX` = TS→wire, `unmarshalX` = wire→TS), but the resulting names are long (e.g. `unmarshalListConnections_ResponseSchema`). +- **Category:** 8 (redundant suffix `Schema`). +- **Suggested name:** Drop `Schema` suffix (`unmarshalConnectionInfo`, `marshalCreateConnection`), or shorten to `decode`/`encode` verbs. +- **Rationale:** Internal-style; the `Schema` suffix repeats info already captured by the `z.ZodType` typing. + +### 33. `unmarshalDeleteConnection_ResponseSchema` — `src/v1/model.ts:435` +- **Why weird:** Underscore inherited from the type name; eslint-disable required. +- **Category:** 4. +- **Suggested name:** Cascades from #10. +- **Rationale:** Mechanical. + +### 34. `unmarshalListConnections_ResponseSchema` — `src/v1/model.ts:450` +- **Why weird:** Same as #33. +- **Category:** 4. +- **Suggested name:** Cascades from #11. +- **Rationale:** Mechanical. + +### 35. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` +- **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. + +### 36. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Remove from utils if generator default. +- **Rationale:** Generator emits the same helper into every package even when unused. + +### 37. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `readStreamToEnd` / `drainStream`. +- **Rationale:** Trivial; flagged for cross-package consistency. + +### 38. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same file. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. +- **Rationale:** Mirroring helps readers map TS→wire/wire→TS at a glance. + +### 39. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. +- **Rationale:** Names should encode the layer, not just the protocol. + +### 40. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). +- **Rationale:** Distinguish internal context bags from user-facing option structs. + +### 41. `listConnectionsIter` — `src/v1/client.ts:194` +- **Why weird:** `Iter` is a Go-style abbreviation for `Iterator`. TS convention is to spell out, or to use the `*` (async generator) syntax to communicate iteration. Consumer code reads `for await (const c of client.listConnectionsIter(...))`, the `Iter` adds nothing. +- **Category:** 5 (cryptic abbreviation), 14 (Go-style name). +- **Suggested name:** `listConnectionsPaginated` or just `iterateConnections`. +- **Rationale:** TS code typically uses verb-form for generators (`iterate`, `walk`) or describes the pagination behaviour (`paginated`). + +### 42. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:164-165` +- **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. +- **Category:** Observation only. +- **Suggested name:** None — this is the marshalling boundary by design. +- **Rationale:** Just noting it for reviewer awareness. + +## Observations + +### 43. ~50 vendor names baked into `ConnectionType` enum +The enum lists ~70 vendors (`MYSQL` ... `MARKETO`), all SCREAMING_SNAKE. This makes `model.ts` 84 lines of enum just for connection types. Worth raising with API design whether the type should be `string` with vendor metadata living in a separate registry — adding a new connection type today requires releasing a new SDK version. +- **Category:** 18 (long enum value set). + +### 44. Casing inconsistency in vendor name decomposition +Within `ConnectionType`: +- `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). +- `MYSQL` (joined) vs `MICROSOFT_ENTRA_ID` (split). +- `MONDAY_COM` (encodes TLD) vs every other brand (no TLD). +No discoverable rule. Wire-locked, but worth surfacing. +- **Category:** 3 (acronym/casing inconsistency). + +### 45. Action-verb conventions on `Client` +`createConnection`, `getConnection`, `listConnections`, `updateConnection`, `deleteConnection` — uniform. (Listed as observation since the audit asks us to flag inconsistencies; here we explicitly note consistency.) + +### 46. `Client` constructor throws for missing host +`if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. +- **Category:** Observation. + +### 47. `index.ts` re-exports proto-map entry types +`ConnectionInfo_OptionsEntry`, `ConnectionInfo_PropertiesEntry`, `ConnectionInfo_SecretsEntry`, plus the same for `CreateConnection_*` and `UpdateConnection_*` — nine types whose only purpose is to model proto map entries. None are usable as `Record` consumers expect. These should not be on the public surface. +- **Category:** 12 (duplicate concepts). + +## Domain glossary +- `uc` — Unity Catalog (referenced in `model.ts:178` doc comment "UC Secret"). +- `raas` — Reporting as a Service (e.g. `WORKDAY_RAAS`). Doc-less. +- `ga4` — Google Analytics 4 (in `GA4_RAW_DATA`). +- `m2m`/`u2m` — Machine-to-machine / User-to-machine OAuth flows (in `CredentialType`). +- `mtls` — Mutual TLS (in `OAUTH_MTLS`). +- `dcr` — Dynamic Client Registration (in `OAUTH_DCR`). Undocumented. +- `pem` — Privacy-Enhanced Mail format (in `PEM_PRIVATE_KEY`). +- `ssws` — Secure Single Sign-on Web Services (Okta) (in `SSWS_TOKEN`). Undocumented. +- `oidc` — OpenID Connect (in `OIDC_TOKEN`). +- `oss` — not encountered. +- `iam` — not encountered. + +## File coverage +- `src/v1/model.ts` (590 lines): read fully. +- `src/v1/client.ts` (237 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (33 lines): read fully. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md new file mode 100644 index 00000000..36206e82 --- /dev/null +++ b/.agent/naming-audit/credentials.md @@ -0,0 +1,531 @@ +# Naming Audit: credentials + +**Path:** `packages/credentials/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-credentials` (top-level module name +collides semantically with the hand-written `@databricks/sdk-auth/credentials` +sub-module). +**Inferred domain:** Unity Catalog "Credentials" API — manages two parallel +shapes (the newer consolidated `Credential` and the older `StorageCredential`) +plus four `GenerateTemporary*Credential` token-vending endpoints (path, table, +volume, service). Each credential is a discriminated union over six +cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure +Managed Identity, GCP Service Account Key, Databricks-managed GCP Service +Account, Cloudflare API token) and yields one of six temporary-credential +shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). +**Total weird names flagged:** 53 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `credentials` / module `@databricks/sdk-credentials` | (package) | package | High | 1 Vague/generic, 12 Duplicate concepts | Cross-package naming collision with `@databricks/sdk-auth`'s hand-written `credentials/` sub-module. Importers will routinely ask "which `credentials` did I want?" — one is SDK authentication (PAT, U2M, M2M); this is Unity Catalog cloud-storage credentials. | +| 2 | `CredentialInfo` vs `CreateCredential` vs `UpdateCredential` vs `StorageCredentialInfo` | model.ts:301, 148, 780, 676 | interface set | High | 12 Duplicate concepts | Four near-identical record shapes (~20 fields each) differ only in two flag fields (`skipValidation`, `force`, `newName`, `nameArg`). The "Info" suffix vs no suffix is meaningless. Real shape is one resource + a small action delta. | +| 3 | `CreateCredential` vs `CreateStorageCredential` | model.ts:148, 226 | interface pair | High | 12 Duplicate concepts | Field-for-field identical. The wire endpoints differ (`/credentials` vs `/storage-credentials`) but the request bodies are the same. One should be a re-export of the other or both should share a common base. | +| 4 | `UpdateCredential` vs `UpdateStorageCredential` | model.ts:780, 865 | interface pair | High | 12 Duplicate concepts | Same as #3 — body fields identical. | +| 5 | `CredentialInfo` vs `StorageCredentialInfo` | model.ts:301, 676 | interface pair | High | 12 Duplicate concepts | Same fields, same types, same optionality. The only thing distinguishing them is which list endpoint emits which. Generator-produced. | +| 6 | `DeleteCredential` vs `DeleteStorageCredential` | model.ts:387, 401 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg, force}`; identical shape. | +| 7 | `GetCredential` vs `GetStorageCredential` | model.ts:575, 585 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg}`. Same shape. | +| 8 | `ListCredentials` vs `ListStorageCredentials` | model.ts:598, 631 | interface pair | High | 12 Duplicate concepts | Both expose `{includeUnbound, maxResults, pageToken}`. Same shape, different doc string. | +| 9 | `ValidateCredential` vs `ValidateStorageCredential` | model.ts:950, 1008 | interface pair | High | 12 Duplicate concepts | The `credential` discriminator differs (`credentialName` vs `storageCredentialName`; storage variant adds `azureServicePrincipal` and `cloudflareApiToken`). Otherwise overlapping. | +| 10 | `Client` | client.ts:80 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `CredentialsClient` would self-identify. | +| 11 | `Client.createCredential` vs `Client.createStorageCredential` (plus delete/get/list/update/validate pairs) | client.ts:112, 142, 168, 199, 242, 277, 311, 348, 383, 411, 445, 509, 571, 602, 641, 680 | method set | High | 12 Duplicate concepts | The class exposes parallel `*Credential` and `*StorageCredential` operations (16 methods, 8 pairs). Per the in-tree TODO note (model.ts:581-583) the storage-credentials API is being deprecated, but both are surfaced equally — no `@deprecated` JSDoc, no log warning. | +| 12 | `nameArg` | model.ts:389, 403, 577, 587, 782, 867 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | `nameArg` appears in six request types as the path parameter for the credential being acted on. "Arg" is meaningless to a TS caller (it's a generator-introduced disambiguator that exists because some envelopes also have a `name` body field). TS-side it should be `credentialName` or `nameInPath`. | +| 13 | `UpdateCredential.nameArg` and `UpdateCredential.name` coexist | model.ts:782, 797 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredential.name`'s text. Caller will pick wrong. | +| 14 | `UpdateStorageCredential.nameArg` and `UpdateStorageCredential.name` coexist | model.ts:867, 881 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #13 for the storage variant. | +| 15 | `CredentialInfo` discriminator field `credential` | model.ts:308 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `CredentialInfo`; the field that holds the credential payload is also `credential`. `Credential.credential.awsIamRole` reads as a stutter. Should be `cloudCredential` or `provider`. | +| 16 | `_Response` / `_Result` / `_ValidationResult` / `_FileOperation` / `_AzureOptions` / `_GcpOptions` (proto-style underscore names) | model.ts:30, 41, 51, 399, 413, 450, 489, 499, 519, 553, 620, 652, 990, 1001, 1053, 1061 | type/enum | High | 4 Underscores in TS identifiers | TS does not use underscores in PascalCase identifiers. The 16 `Parent_Child` names (proto-message-nested-message-encoded-as-underscore) all require `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. The hint is the surrounding ESLint disables — the generator already knows these violate the rule. | +| 17 | `ValidateCredential_Result` enum | model.ts:30 | enum | Medium | 4 Underscores in TS identifiers, 2 Redundant enum prefixes | The enum name says "Result", the values are `PASS`/`FAIL`/`SKIP`. Could be `ValidationResult` (no underscore) or `Outcome`. | +| 18 | `ValidateStorageCredential_Result` enum | model.ts:51 | enum | Medium | 4 Underscores in TS identifiers, 12 Duplicate concepts | Same shape as `ValidateCredential_Result` — `PASS`/`FAIL`/`SKIP`. Two enums with identical members differing only by name. Should be a shared type. | +| 19 | `ValidateStorageCredential_FileOperation` enum | model.ts:41 | enum | Medium | 4 Underscores in TS identifiers, 18 Long enum values | `LIST`/`READ`/`WRITE`/`DELETE`/`PATH_EXISTS`. The values are fine; the enum *name* is 39 chars. `FileOp` or merging with the validator's outer type would shorten. | +| 20 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` etc. | model.ts:5-10 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | All four values stutter the enum name (`ISOLATION_MODE_OPEN`, `ISOLATION_MODE_ISOLATED`, ...). TS idiom would be `IsolationMode.Unspecified`/`.Open`/`.Isolated`. The generator emits SCREAMING_SNAKE for both the keys and the string values. | +| 21 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` | model.ts:6 | enum value | Medium | 6 Misleading names, 18 Long enum values | "Unspecified" is the proto-style placeholder for "missing value". In TS the natural way to express this is `undefined`, not a sentinel string. The field type already is `IsolationMode \| undefined`. | +| 22 | `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` | model.ts:9 | enum value | Low | 18 Long enum values, 6 Misleading names | 30-char enum value; "OpenInAccount" is the contraction. The domain meaning ("open within a single account scope") is not obvious from either form. | +| 23 | `PathOperation` enum values | model.ts:13-15 | enum values | Medium | 2 Redundant enum prefixes, 18 Long enum values | `PATH_READ`, `PATH_READ_WRITE`, `PATH_CREATE_TABLE` — `PATH_` prefix duplicates the enum name. The third value (`PATH_CREATE_TABLE`) is a different category from the first two ("Path"-as-resource vs "create a table at this path"); the prefix obscures that. | +| 24 | `TableOperation` vs `VolumeOperation` enums | model.ts:18, 23 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write) expressed two different ways. The volume one uses prefixed values (#20 pattern), the table one does not — inconsistent within the same file. | +| 25 | `VolumeOperation.READ_VOLUME`/`WRITE_VOLUME` | model.ts:24-25 | enum value | Medium | 2 Redundant enum prefixes, 18 Long enum values | `_VOLUME` suffix stutters the enum name. Should be `READ`/`WRITE` (consistent with `TableOperation`). | +| 26 | `unityCatalogIamArn` | model.ts:83 | field | Medium | 7 Overly verbose, 6 Misleading names | 18-char field name embedded in `AwsIamRole`. The JSDoc says "AWS IAM user managed by Databricks". Caller has no way to know that "unityCatalog" here means "the Databricks-managed identity that assumes the customer role". Either `databricksManagedIamArn` or rename to clarify role. | +| 27 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:76, 117, 99, 427, 378, 139 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | +| 28 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:95, 93, 459 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | +| 29 | `awsTempCredentials` discriminator case | model.ts:453 | field | Low | 5 Cryptic abbreviations | "Temp" abbreviation for "Temporary". Other discriminator cases use full words (`azureUserDelegationSas`, `gcpOauthToken`). Inconsistent. | +| 30 | `r2TempCredentials` discriminator case | model.ts:460 | field | Low | 5 Cryptic abbreviations | Same as #29. | +| 31 | `ucEncryptedToken` discriminator case | model.ts:461 | field | Medium | 5 Cryptic abbreviations | "Uc" is the Databricks-internal abbreviation for "Unity Catalog". Outside Databricks the abbreviation is opaque. Compare to `unityCatalogIamArn` (#26) which spells it out. Inconsistent within the same model file. | +| 32 | `UcEncryptedToken` type | model.ts:775 | interface | Medium | 5 Cryptic abbreviations, 1 Vague/generic | Same "Uc" abbreviation problem at the type name. Spell out or contextualize. | +| 33 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:419, 420 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | +| 34 | `R2Credentials` type | model.ts:667 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | +| 35 | `CloudflareApiToken.accountId` | model.ts:145 | field | Low | 19 Underspecified IDs | This `accountId` is a *Cloudflare* account ID, not a Databricks account ID. The field name doesn't say. Compare `unityCatalogIamArn` (#26) which is annotated. | +| 36 | `AwsCredentials.accessPoint` | model.ts:72 | field | Low | 5 Cryptic abbreviations, 1 Vague/generic | A string containing an S3 Access Point ARN. `accessPointArn` would type itself. | +| 37 | `usedForManagedStorage` flag | model.ts:216 | field | Low | 6 Misleading names | Boolean named in past tense ("usedFor") suggests a historical record. The doc says it is the *current* state. `isManagedStorageRoot` or `isRootForManagedStorage` reads as state. | +| 38 | `isolationMode` vs `IsolationMode` (type alias collision risk) | model.ts:223 | field | Low | (none) | Standard generator pattern (field name lower-cased version of enum type). Already idiomatic; no issue. (Listing for completeness.) | +| 39 | `GenerateTemporaryPathCredential` / `GenerateTemporaryTableCredential` / `GenerateTemporaryVolumeCredential` / `GenerateTemporaryServiceCredential` | model.ts:436, 508, 542, 472 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 31-34 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | +| 40 | `GenerateTemporaryPathCredential_Response` / `..._TableCredential_Response` / `..._VolumeCredential_Response` | model.ts:450, 519, 553 | interface set | Medium | 4 Underscores, 7 Overly verbose, 12 Duplicate concepts | Three response shapes (39-42 char names) with **identical** fields: `credentials` union + `expirationTime` + `url`. They are also identical to `TemporaryCredentials` (model.ts:749). Four parallel definitions of the same shape. | +| 41 | `TemporaryCredentials` | model.ts:749 | interface | Medium | 12 Duplicate concepts | This and the three `Generate*_Response` types (#40) are the same shape. Only one should exist; the other three should re-export it. | +| 42 | `GenerateTemporaryServiceCredential_AzureOptions` | model.ts:489 | interface | High | 4 Underscores in TS identifiers, 7 Overly verbose | 47 chars. The `_AzureOptions` proto-style suffix is the third underscore-segment in the name. | +| 43 | `GenerateTemporaryServiceCredential_GcpOptions` | model.ts:499 | interface | High | 4 Underscores in TS identifiers, 7 Overly verbose | Same as #42 — 45 chars. | +| 44 | `GenerateTemporaryServiceCredential.options.$case` discriminator values | model.ts:477, 481 | field | Low | 1 Vague/generic | The discriminator is `azureOptions` / `gcpOptions`. "Options" gives no domain hint — could be query options, retry options, etc. Within the type they are token-generation parameters. | +| 45 | `ValidateCredential.credential` outer field with `credential.$case === 'credentialName'` | model.ts:951, 953 | field | High | 12 Duplicate concepts, 15 Generic field names | The discriminated-union *case* is `credentialName: string`, sitting under a field called `credential`. So `req.credential.credentialName` is the read path — `credential.credential...` stuttering. | +| 46 | `ValidateStorageCredential.credential.$case === 'storageCredentialName'` | model.ts:1011 | field | High | 12 Duplicate concepts, 15 Generic field names | Same as #45 — `req.credential.storageCredentialName`. The naming repeats the parent type. | +| 47 | `dryRun` on `GenerateTemporaryPathCredential` | model.ts:446 | field | Low | (none) | Camel-cased boolean, conventional. (Listing for completeness.) | +| 48 | `expirationTime` (epoch milliseconds) | model.ts:467 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | +| 49 | `createdAt`, `updatedAt`, `createdBy`, `updatedBy` | model.ts:205, 209, 207, 211 | field set | Low | (none) | Standard, consistent across the file. (Listing for completeness.) | +| 50 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:107-110 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredential`/`CredentialInfo`/`UpdateCredential`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | +| 51 | `marshalXxxSchema` / `unmarshalXxxSchema` const naming | model.ts:1070-2293 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go-idioms; `Schema` is tautological with `z.ZodType`. TS idiom is `encode`/`decode`. Generator-wide pattern. | +| 52 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | +| 53 | `parseResponse` vs `marshalRequest` | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | Mixing `parse`/`marshal`. Either `parse`/`format` or `marshal`/`unmarshal`. | + +--- + +## High severity (must fix) + +### H1. Cross-package collision: `credentials` vs `auth/credentials` + +The repository has **two** "credentials" concepts: + +- `@databricks/sdk-credentials` (this package) — Unity Catalog cloud storage + credentials (AWS IAM roles, Azure SPs, GCP service accounts). +- `@databricks/sdk-auth/credentials/` (hand-written sub-module) — SDK *user* + authentication credentials (PAT, OAuth U2M, OAuth M2M); see + `packages/auth/src/credentials/{m2m,pat,u2m}.ts`. Their public surface uses + the literal name `Credentials` (`M2mCredentials`, `U2mCredentials`, + `PatCredentials`). + +A consumer writing `import {Credentials} from '@databricks/sdk-...'` cannot +tell which package they want. Both legitimately call their primary concept +"credentials". Possible fixes (pick one): + +- Rename this package to `@databricks/sdk-unity-catalog-credentials`, + `@databricks/sdk-uc-credentials`, or `@databricks/sdk-storage-credentials`. +- Rename the auth-side to `@databricks/sdk-auth/identity` or `/providers` + (followed by `IdentityProvider`, not `Credentials`). +- At minimum, document the disambiguation in both packages' README/JSDoc. + +### H2. Whole-package internal duplication: `Credential` vs `StorageCredential` + +Eight method pairs and eight interface pairs are field-for-field identical +between the "Credential" (new consolidated) surface and the "StorageCredential" +(legacy) surface. See findings #2-#9. The in-tree TODO note +(model.ts:581-583) confirms the storage variant is being deprecated. But: + +- No `@deprecated` JSDoc tag on any of the `*StorageCredential` types or + methods. +- No log warning when a caller invokes them. +- They are equally promoted in `index.ts`. + +Recommendation: mark every `*StorageCredential` type and method `@deprecated`, +or hide them behind a `/legacy` sub-export, until they are removed. + +### H3. Identical request envelopes (`Credential` and `StorageCredential` pairs) + +`CreateCredential` and `CreateStorageCredential` (model.ts:148, 226) have +identical fields. Same for the Update, Delete, Get, List pairs (#3, #4, #6, #7, +#8). The discriminated unions on the `credential` field are subsets/supersets +of each other: + +- `CreateStorageCredential` accepts: awsIamRole, azureServicePrincipal, + gcpServiceAccountKey, azureManagedIdentity, databricksGcpServiceAccount, + cloudflareApiToken (6 cases). +- `CreateCredential` accepts: the same 6 cases. + +There is no behavioral difference. One should be a type alias. + +### H4. `nameArg` field convention + +Six request types (`DeleteCredential`, `DeleteStorageCredential`, +`GetCredential`, `GetStorageCredential`, `UpdateCredential`, +`UpdateStorageCredential`) expose a field called `nameArg`. The "Arg" suffix +is meaningless on the TS side; it exists only because the generator needs to +disambiguate from a sibling `name` field that lives in the same envelope on +Update operations. TS callers will read `req.nameArg = 'my-credential'` and +have no idea why it isn't just `name`. + +Combined with H5 below, the Update envelopes are particularly broken: + +```ts +interface UpdateCredential { + nameArg?: string; // URL path parameter — which credential to update + newName?: string; // new credential name + name?: string; // body-level "credential name" — what does this even do? + // ... +} +``` + +Three name-related fields on one envelope, no clear precedence. Recommend: +keep only `name` (path) + `newName` (rename) and drop the body-level `name`. + +### H5. Body-level `name` collides with path-level `nameArg` + +`UpdateCredential` and `UpdateStorageCredential` carry both `nameArg` (path +parameter) and `name` (body field). The JSDoc on `name` says "The credential +name. The name must be unique among storage and service credentials within the +metastore." — i.e., the *new* canonical name. But there is *also* a `newName` +field. So `nameArg`, `name`, and `newName` all reference the same conceptual +"credential name" with no clear precedence. See #13, #14. + +### H6. `purpose` field is referenced in JSDoc but does not exist on the type + +The JSDoc on `readOnly` (model.ts:194-196, 268-272, etc.) and +`usedForManagedStorage` (model.ts:212-216) and `force` (model.ts:391-394) says +"Only applicable when purpose is **STORAGE**" or "**SERVICE**". But there is +no `purpose` field anywhere on `CreateCredential`/`UpdateCredential`/ +`CredentialInfo`/`StorageCredentialInfo`. Either: + +- The generator dropped the field, or +- The doc is stale (the API uses a different mechanism to decide purpose, e.g. + inferring from which discriminator case is set, or routing by endpoint), or +- The field is intentionally on the `Credential` side only and missing from + the model. + +In all cases the contract documented in JSDoc cannot be honored by a TS +caller. See #50. + +### H7. Eighteen `_`-bearing TS identifiers + +Sixteen types and two enums use proto-style underscore-encoded nested +identifiers. Each requires an inline `// eslint-disable-next-line +@typescript-eslint/naming-convention` because the project's linter forbids +underscores. The presence of those disables is the loudest possible signal +that the names violate the codebase's own conventions: + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface DeleteCredential_Response {} +``` + +Names affected: `ValidateCredential_Result`, `ValidateStorageCredential_FileOperation`, +`ValidateStorageCredential_Result`, `DeleteCredential_Response`, +`DeleteStorageCredential_Response`, `GenerateTemporaryPathCredential_Response`, +`GenerateTemporaryTableCredential_Response`, +`GenerateTemporaryVolumeCredential_Response`, +`GenerateTemporaryServiceCredential_AzureOptions`, +`GenerateTemporaryServiceCredential_GcpOptions`, `ListCredentials_Response`, +`ListStorageCredentials_Response`, `ValidateCredential_Response`, +`ValidateCredential_ValidationResult`, `ValidateStorageCredential_Response`, +`ValidateStorageCredential_ValidationResult`, and the corresponding +`marshal*Schema`/`unmarshal*Schema` constants. + +Standard TS idiom would nest these inside namespaces (`ValidateCredential.Result`) +or give them top-level domain names (`ValidationOutcome`, +`PathCredentialResponse`). + +### H8. Stuttering `ValidateCredential.credential.credentialName` + +`req.credential` is the discriminated-union outer field. One of its cases is +`{$case: 'credentialName', credentialName: string}` — so accessing the value +is `req.credential.credentialName` and the outer field is also named after +the same word. Same for `ValidateStorageCredential.credential.storageCredentialName`. + +```ts +const req: ValidateCredential = { + credential: {$case: 'credentialName', credentialName: 'my-cred'}, +}; +``` + +Reads twice as "credential.credentialName". The inner discriminator key should +be `name` (giving `req.credential.name`) — concise and unambiguous because the +case is `'credentialName'`. + +--- + +## Medium severity (worth pushing back on) + +### M1. `Credential` is a vague, generic noun + +The interface `Credential` (and `Credentials`, `CredentialInfo`, +`CredentialName`) does not, in isolation, tell a TS reader anything about the +domain. The Databricks SDK has at least four distinct "credential" concepts: + +1. SDK authentication (auth package). +2. Unity Catalog Storage Credentials (legacy this package). +3. Unity Catalog Service Credentials (new this package). +4. Cloud-provider credentials (vended via `TemporaryCredentials`). + +A type named just `Credential` could be any of them. Domain-prefixing +(`StorageCredentialInfo`, `ServiceCredentialInfo`) at least narrows it. + +### M2. `Client` is unqualified + +`export class Client` (client.ts:80). Importing `{Client}` from `@databricks/sdk-credentials/v1` +and from any sibling package collides. Either: + +- Export as `CredentialsClient`, or +- Rely on namespace imports. + +### M3. Eight `client.ts` method pairs duplicate work + +Sixteen methods, eight pairs. Each pair differs only in the URL it hits. +Cf. #11. The class is 707 lines, the marshaling/unmarshaling roundtrips +inside each method add ~30 lines of boilerplate per method. Half of that is +generated for the legacy storage-credentials path. + +### M4. `IsolationMode` enum values stutter the enum name + +```ts +enum IsolationMode { + ISOLATION_MODE_UNSPECIFIED, + ISOLATION_MODE_OPEN, + ISOLATION_MODE_ISOLATED, + ISOLATION_MODE_OPEN_IN_ACCOUNT, +} +``` + +TS idiom (Google TS Style Guide §5.6) is PascalCase for enum members and no +prefix duplication: + +```ts +enum IsolationMode { + Unspecified, + Open, + Isolated, + OpenInAccount, +} +``` + +The wire format is dictated by the API server (the string values must remain +`ISOLATION_MODE_*`); but the TS keys can be renamed via the zod `transform` +without breaking the wire. + +### M5. `*Operation` enums are inconsistent with each other + +```ts +enum PathOperation { PATH_READ, PATH_READ_WRITE, PATH_CREATE_TABLE } +enum TableOperation { READ, READ_WRITE } +enum VolumeOperation { READ_VOLUME, WRITE_VOLUME } +``` + +Three enums for the same domain (read/write a cloud-storage thing) with three +different prefixing conventions. Pick one. (See #23, #25.) + +### M6. `TemporaryCredentials` shape duplicated four times + +`TemporaryCredentials`, `GenerateTemporaryPathCredential_Response`, +`GenerateTemporaryTableCredential_Response`, +`GenerateTemporaryVolumeCredential_Response` — four interfaces, identical +fields. The wire endpoints might differ (so each method returns its own +named type), but at the TS level there is no need to create four +declarations. + +### M7. `UcEncryptedToken` and `Uc*` discriminator case use unspelled-out abbreviation + +`Uc` = "Unity Catalog". A TS-side consumer outside Databricks won't recognize +the abbreviation. The same model file uses `unityCatalog` spelled out on +`AwsIamRole.unityCatalogIamArn` (#26) — inconsistent within the file. Pick +either `UnityCatalogEncryptedToken` everywhere or `Uc*` everywhere. + +### M8. `R2Credentials` requires Cloudflare product knowledge + +A type named `R2` is identifiable only to readers who know Cloudflare's +product line. The JSDoc gives no expansion. Use `CloudflareR2Credentials` or +add a JSDoc anchor. + +### M9. `unityCatalogIamArn` field reads misleadingly + +```ts +interface AwsIamRole { + roleArn?: string; // the customer's IAM role + unityCatalogIamArn?: string; // Databricks-managed identity that assumes the customer role + externalId?: string; +} +``` + +"unityCatalogIamArn" suggests *Unity Catalog's IAM ARN*. What it actually is: +the ARN of the Databricks-managed IAM user that performs the role assumption +(per the JSDoc). `databricksAssumeIdentityArn` or `assumerArn` would be +clearer. + +### M10. `expirationTime` field naming + +The field is an epoch-ms integer ("Server time when the credential will +expire"). The repo's convention elsewhere is `createdAt`/`updatedAt` (which +are also epoch-ms). Rename to `expiresAt` for consistency. + +### M11. `IsolationMode.ISOLATION_MODE_UNSPECIFIED` sentinel value + +Proto-style "Unspecified" sentinel. In TS, the field is already +`isolationMode?: IsolationMode | undefined`, so omitting the field communicates +"unspecified" naturally. The enum value is dead code. Either remove it or +document that callers should *not* set it. + +--- + +## Low severity (nits) + +### L1. `AwsCredentials.accessPoint` should carry the ARN suffix + +The JSDoc says "The Amazon Resource Name (ARN) of the S3 access point". The +field is `accessPoint: string`. `accessPointArn` self-documents. + +### L2. `CloudflareApiToken.accountId` is ambiguous + +The `accountId` field is the Cloudflare account ID, not a Databricks account +ID. JSDoc says "The ID of the account associated with the API token" — also +ambiguous. Rename `cloudflareAccountId` or annotate. + +### L3. `awsTempCredentials` / `r2TempCredentials` use "Temp" abbreviation + +The peer discriminator cases use full words (`azureUserDelegationSas`, +`gcpOauthToken`). Standardize: either `awsTemporaryCredentials` or +`azureTempUserDelegationSas`. + +### L4. `aadToken` field vs `AzureActiveDirectoryToken` type + +Short form (`aadToken`) for the field, long form (`AzureActiveDirectoryToken`) +for the type. Acronym handling within one chain should match. + +### L5. `GcpOauthToken` casing + +RFC 6749 (OAuth 2.0) titles the term as "OAuth". The code uses "Oauth". Minor. + +### L6. `usedForManagedStorage` flag past tense + +"Used" reads as historical state. The doc says it is current state ("is this +the root storage credential"). `isManagedStorageRoot` reads as state. + +### L7. `marshal`/`unmarshal` are Go-idioms + +JS/TS ecosystem uses `encode`/`decode`, `parse`/`stringify`, or +`serialize`/`deserialize`. Generator-wide. + +### L8. `parseResponse` vs `marshalRequest` mix + +`utils.ts` has both verbs. Either `parse`/`format` or `marshal`/`unmarshal`. + +### L9. `PACKAGE_SEGMENT` is undescriptive + +Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` is +self-documenting. + +### L10. `HttpCallOptions` + +Generic name, internal-only. Same pattern as in sibling packages. Fine inside +the file; would warrant a better name if it leaked out. + +### L11. `req` parameter naming in client methods + +Standard across the SDK. Go-idiomatic, but consistent. + +### L12. `Generate*Credential` method names are 30+ chars + +`generateTemporaryServiceCredential` is 35 chars. Combined with `await +client.generateTemporaryServiceCredential(req)` the call site is 60+ chars +before the args. Cannot shorten without breaking the resource hierarchy. + +### L13. Acronym casing review + +- `Aws` (PascalCase first letter) — `AwsCredentials`, `AwsIamRole`, + `awsIamRole`. Internally consistent. +- `Azure` (not an acronym) — fine. +- `Gcp` (PascalCase first letter) — `GcpOauthToken`, `gcpServiceAccountKey`. + Internally consistent. +- `Aad` (mixed) — `aadToken` (field, short), `AzureActiveDirectoryToken` + (type, long). Inconsistent. See #28. +- `Iam` — consistent with `Aws`/`Gcp` style. +- `R2` — special-cased product name. See M8/#34. +- `Sas` (PascalCase first letter) — `AzureUserDelegationSas`, `sasToken`. + Consistent. +- `Uc` — see M7/#31/#32. +- `Oauth` — see L5/#33. + +The JSDoc *text* in the same file uses ALL-CAPS forms ("AWS", "GCP", "IAM", +"AAD") because that is how the cloud providers write them. The Google TS +Style Guide prefers initialism-as-word (`Aws`, `Gcp`, `Iam`) for identifiers. +This is fine; just don't claim the spec uses the same casing. + +--- + +## Cross-cutting observations (not flags) + +### Confusion with `@databricks/sdk-auth/credentials/` + +The hand-written auth/credentials sub-module exports: + +- `M2mCredentialsError`, `U2mCredentialsError` (error classes). +- `M2mCredentialsErrorCode`, `U2mCredentialsErrorCode` (type aliases). +- `newM2mCredentials`, `newPatCredentials`, `newU2mCredentials` (factories). +- `M2mCredentialsOptions`, `U2mCredentialsOptions` (option types). + +It does *not* export a type literally called `Credentials`; the closest is +the factory return type pattern (`*Credentials` named instances). Still, a +search-and-replace consumer who types "import {Credentials}" will hit both +packages. The simplest fix is package-level renaming (H1). For now, callers +must keep the import paths straight (`@databricks/sdk-credentials/v1` for UC +storage credentials, `@databricks/sdk-auth` for SDK auth credentials). + +### Generator marker + +Every file is prefixed with `// Code generated from API definition by +Databricks SDK Generator. DO NOT EDIT.` All naming issues here must be fixed +upstream in the generator/spec. + +### Optionality model + +Every field is `T | undefined`. Matches `exactOptionalPropertyTypes` and the +rest of the SDK. + +### No reserved-word collisions + +No `delete`, `class`, `new`, `default` (as field names). + +### No singular/plural mismatches in interface names + +`Credentials` vs `Credential` is used consistently: + +- `TemporaryCredentials` (plural) — wraps a single credential value (a + discriminated union); reads as "this is a temporary credentials *bundle*". + Marginal. +- `R2Credentials`, `AwsCredentials` (plural) — wraps a single set of + credential values (key + secret + session); fine as the convention is + "credentials" for the bundle. +- `CredentialInfo` (singular) — one credential record. Consistent with + Databricks API "Info" suffix. + +### Versioning + +Only `v1` exists; nothing to compare across versions. + +### Tests + +No `tests/` directory for this package. + +### `index.ts` re-export style + +Class re-exported with `export {Client}`; types and enums re-exported with +`export {IsolationMode, ...}` (for enums, which are runtime values) and +`export type {AwsCredentials, ...}` (for type-only interfaces). Correct for +`verbatimModuleSyntax`. + +--- + +## Domain glossary (as inferred from this code) + +| Term | Meaning in this package | +|------|-------------------------| +| **Credential** (new) | The consolidated UC credential record covering both Storage and Service purposes. Reached via `/api/2.1/unity-catalog/credentials`. | +| **Storage Credential** (legacy) | The older Storage-only credential record. Reached via `/api/2.1/unity-catalog/storage-credentials`. Per in-tree TODO, being deprecated. | +| **Service Credential** | A `Credential` whose purpose is **SERVICE** — used by Databricks to access cloud APIs on behalf of the user (e.g., for foundation models, external functions). Note: there is no `purpose` field on the TS model — see H6. | +| **Purpose** | One of `SERVICE` / `STORAGE`. Distinguishes the two flavors of a `Credential`. Referenced in JSDoc but absent from the TS type. | +| **Long-lived credential** | The customer-supplied cloud-provider auth material (IAM role, service principal, etc.) stored in the metastore. Six discriminated cases. | +| **Temporary credential** | Short-lived tokens vended by Databricks for direct cloud access. Six discriminated cases. | +| **External location** | A cloud-storage URL registered in UC and authorized via a Storage Credential. Validated by `validateCredential` / `validateStorageCredential`. | +| **Isolation mode** | Workspace-binding policy for the credential securable. One of `Unspecified`, `Open`, `Isolated`, `OpenInAccount`. | +| **Unbound credential** | A credential not bound to any workspace. Listable via `includeUnbound=true`. | +| **`nameArg`** | URL-path positional argument for the credential's name. Exists because the request envelope also carries body-level `name` and `newName` — see H4, H5. | +| **Access connector ID** (Azure) | The Azure resource ID of the Databricks Access Connector. | +| **AAD token** | Azure Active Directory access token (Oauth bearer for Azure cloud services). | +| **UC encrypted token** | Encrypted ScopedCloudToken fallback when the cloud provider's token cannot be downscoped. Base64 string. | +| **R2** | Cloudflare's S3-compatible object storage product (named after the SF-Bay-Area meme). | +| **External ID** | AWS confused-deputy mitigation token in role assumption. | + +--- + +## File coverage + +| File | Lines | Exports counted | Audited | +|------|-------|-----------------|---------| +| `src/v1/model.ts` | 2293 | 7 enums, 32 interfaces, 33 zod consts (15 unmarshal + 18 marshal) | yes | +| `src/v1/client.ts` | 707 | 1 class, 18 public methods (16 RPC + 2 async generators) | yes | +| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 60 | 1 class re-export, 6 enum re-exports, 39 type re-exports | yes | + +Every type, field, enum value, and method enumerated above is accounted for. diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md new file mode 100644 index 00000000..842f8f97 --- /dev/null +++ b/.agent/naming-audit/customllms.md @@ -0,0 +1,243 @@ +# Naming Audit: customllms + +**Path:** `packages/customllms/src/v1/` +**Versions audited:** v1 +**Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. +**Total weird names flagged:** 36 + +## Summary +| Severity | Count | +| --- | --- | +| High | 10 | +| Medium | 13 | +| Low | 9 | +| Observation | 4 | + +## High severity + +### 1. `Llm` casing throughout — every file +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, `unmarshalCustomLlmSchema`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #36). +- **Category:** 3 (acronym casing — the audit prompt singles this out). +- **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. +- **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. + +### 2. `CustomLlm` package, `CustomLlm` type, `customLlm` field — `src/v1/model.ts:43,96` +- **Why weird:** The package is called `customllms`, the only domain entity is called `CustomLlm`, and every request type repeats the noun: `CreateCustomLlmRequest`, `DeleteCustomLlmRequest`, `GetCustomLlmRequest`, `UpdateCustomLlmRequest`, `StartCustomLlmOptimizationRunRequest`, `CancelCustomLlmOptimizationRunRequest`. Inside `UpdateCustomLlmRequest` there is even a `customLlm: CustomLlm` field (model.ts:96). Once the consumer has imported from `@databricks/sdk-customllms` the `Custom` prefix is pure namespace echo. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology on `customLlm: CustomLlm`). +- **Suggested name:** Drop the `Custom` prefix throughout — `Llm`, `CreateLlmRequest`, `UpdateLlmRequest`, `StartOptimizationRunRequest`, etc. The field `customLlm` becomes `llm`. +- **Rationale:** The package path already supplies the "custom" qualifier (`customllms.Llm`). The redundant prefix burns ~7 characters of every type name without adding meaning. + +### 3. `State` enum (top-level, ungrouped) — `src/v1/model.ts:9-17` +- **Why weird:** The enum is named `State` — the most generic noun in any API. There is no qualifier to tell the reader *which* state (optimization run? custom LLM? endpoint?). The doc comment ("States of Custom LLM optimization lifecycle.") clarifies, but the name alone does not. Every other Databricks package has its own `State` (jobs, clusters, queries) and a user importing two of them will be forced to alias. +- **Category:** 1 (vague/generic), 15 (generic field name). +- **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). +- **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. + +### 4. `State.STATE_UNSPECIFIED` — `src/v1/model.ts:10` +- **Why weird:** Redundant enum prefix (`State.STATE_*`) plus a proto-buf `_UNSPECIFIED` sentinel. TypeScript's enums are namespaced by the enum name — `STATE_UNSPECIFIED` becomes `State.STATE_UNSPECIFIED` at the call site, which is doubled. Idiomatic TS uses `undefined` for "not set" rather than a sentinel. +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names not idiomatic in TS), 18 (questionable enum value). +- **Suggested name:** Drop `STATE_UNSPECIFIED` (rely on `optimizationState?: State | undefined`); rename the remaining values to title-case: `OptimizationRunState.Created | Running | Completed | Failed | Pending | Cancelled`. +- **Rationale:** TS `enum` members carry SCREAMING_SNAKE only as a proto-buf artifact. The Google TS style guide treats enum members as constants, so SCREAMING_SNAKE is *also* defensible — but at minimum the redundant `STATE_` prefix should go. + +### 5. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` +- **Why weird:** Doc comment "The Id of the tile." refers to a "tile" that does not exist anywhere else in the package. This is almost certainly a copy-paste from another generated API (dashboards/tiles). Either the field name or the doc is wrong; reading the surrounding code, the field is the custom-LLM id (same as `CancelCustomLlmOptimizationRunRequest.id` on line 20). Public SDK doc bug. +- **Category:** 6 (misleading — doc contradicts the actual domain). +- **Suggested name:** Field name stays `id`; fix the JSDoc to "The id of the custom LLM whose optimization run to start." (matches `DeleteCustomLlmRequest.id` and `GetCustomLlmRequest.id` docs on lines 69 and 74). +- **Rationale:** A naming audit should flag doc-text bugs on identifiers as well as the identifier itself; consumers learn the semantics from JSDoc and a wrong doc is as harmful as a wrong name. + +### 6. `id` field on every request and on `CustomLlm` — `src/v1/model.ts:20,44,70,75,80,93` +- **Why weird:** Bare `id` shows up on six places (`Cancel...Request.id`, `CustomLlm.id`, `Delete...Request.id`, `Get...Request.id`, `Start...Request.id`, `Update...Request.id`). Every JSDoc has to redundantly say "The id of the custom llm". A typed `customLlmId` makes the wire/TS surface self-documenting and avoids confusion with future API extensions (the endpoint is at `/api/2.0/custom-llms/{id}` — `id` here is the LLM id, not a generic id). +- **Category:** 1 (vague), 19 (underspecified id). +- **Suggested name:** `customLlmId` (or `llmId` if the `Custom` prefix is dropped per #2). Wire stays `id`. +- **Rationale:** When grepping logs or stack-traces for `customLlmId`, you'll find the right call site. Today you'll grep for `id` and get 50 false positives across the SDK. + +### 7. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` +- **Why weird:** The `FieldMaskSchema` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the schema being machine-generated rather than designed. Worth a sanity check with the upstream API team. +- **Category:** Observation / 6 (misleading — field-mask implies updatable). +- **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. +- **Rationale:** This is the kind of thing a careful TS API designer would notice; a generator running over the proto schema will not. + +### 8. `endpoint_name` field appears in `unmarshalCustomLlmSchema` but not in marshal counterpart correctly — `src/v1/model.ts:105,193` +- **Why weird:** The wire field for the marshaller is set via `endpoint_name: d.endpointName` (line 193) but the inner zod object types it as `endpointName` (camelCase, line 178). The marshal schema reads camelCase keys then emits snake_case — but the *input* the marshal schema validates is the already-camelCased `CustomLlm`, so the input shape is `endpointName`. That actually does work because the marshal schema is `z.object({endpointName: ...})`. However, all other marshallers in the same file accept camelCase input (cf. `marshalUpdateCustomLlmRequestSchema` at line 232 — `customLlm`). This is *internally* consistent but the naming feels accidental given the unmarshal schema (line 105) reads snake_case. Not strictly a name bug but the asymmetry is jarring. +- **Category:** 17 (inconsistent: unmarshal reads `endpoint_name`, marshal also writes `endpoint_name` but the schema validator key is `endpointName`). +- **Suggested name:** No rename; flag for upstream generator review. +- **Rationale:** Generator artefact; reading the two schemas side-by-side suggests the marshal validator-key should match the wire key, not the TS field name. + +### 9. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` +- **Why weird:** `UpdateCustomLlmRequest.customLlm: CustomLlm | undefined`. The TS naming convention makes the field/type distinction work via casing — but at a call site you'll write `req.customLlm = {...} satisfies CustomLlm`, and `customLlm` (the field) is one character of casing away from `CustomLlm` (the type). Type-suffix tautology under rule 20. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** Rename `customLlm` field → `llm` (paired with type rename `CustomLlm` → `Llm` per #2). Even without the type rename, the field can be `target` or `update`. +- **Rationale:** `req.llm` reads cleanly; `req.customLlm` is the kind of name that survives code review only because nobody wants to argue with the generator. + +### 10. `CustomLlm.creator: string` — `src/v1/model.ts:58` +- **Why weird:** "Creator of the custom LLM" — but a `creator` could be a username, an email, a UUID, a Databricks principal-id, or a service-principal client-id. The type is `string` so there is no help. Other Databricks SDK packages (catalog, jobs) use `createdBy` or `creator` similarly inconsistently. The name does not say *what kind* of identifier it is. +- **Category:** 1 (vague), 19 (underspecified id). +- **Suggested name:** `createdBy` if it is a user/principal id (matches Unity Catalog convention); add `@format` JSDoc clarifying whether it is an email or a UUID. +- **Rationale:** Public SDK fields whose meaning depends on side-channel knowledge are footguns. + +## Medium severity + +### 11. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` +- **Why weird:** `creationTime` is named with the type-suffix convention (`*Time`), while peer fields on the same struct use bare nouns (`creator`, `name`, `instructions`). The other generated SDKs sometimes use `createdAt` or `createTime`. Naming `creationTime` is fine, but it is the *only* type-suffix field on `CustomLlm`. +- **Category:** 17 (inconsistency within the same struct). +- **Suggested name:** `createdAt` (Stripe/GitHub convention, https://stripe.com/docs/api/charges/object) or `createTime` (Google AIP-142, https://google.aip.dev/142). Either is more standard than `creationTime`. +- **Rationale:** AIP-142 (Google API design) says: "Fields representing the time at which a resource was created should be of type google.protobuf.Timestamp and called `create_time`." The Go SDK and Java SDK tend to mirror this; TS should too. + +### 12. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` +- **Why weird:** Two near-synonyms with different cardinalities. `instructions` is a single string, `guidelines` is a string array. The semantic difference is not obvious from the names; both feel like "things the model should follow". This is an API-design issue more than a naming issue, but the names amplify the confusion. +- **Category:** 6 (misleading), 12 (duplicate concept). +- **Suggested name:** `systemPrompt` (or `instruction`) for the single-string case; `rules` or `constraints` for the array. The bigger fix is to consolidate at the API level. +- **Rationale:** Reading `instructions` + `guidelines` side-by-side, a consumer cannot guess which goes where without reading the prose docs. + +### 13. `Table.tablePath` — `src/v1/model.ts:85` +- **Why weird:** Type-suffix tautology (`Table.tablePath`). Doc says "Full UC table path in catalog.schema.table_name format" — but the field name does not communicate that it's a *fully qualified* three-part name. Compare with sibling SDK packages where the same concept is called `fullName` or `qualifiedName`. +- **Category:** 20 (type-suffix tautology), 1 (vague — "path" is generic; a filesystem path? a JSON pointer?). +- **Suggested name:** `fullName` (matches `catalog.TableInfo.full_name`) or `qualifiedName`. +- **Rationale:** Unity Catalog already has a canonical term for three-part names (`full_name`); reusing it makes cross-API code less surprising. + +### 14. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` +- **Why weird:** `Col` is a cryptic abbreviation for `Column`. The same package spells out `endpointName` and `agentArtifactPath` and `optimizationState`, so `Col` is inconsistent. Doc strings even use the full word: "Name of the request column". +- **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling fields). +- **Suggested name:** `requestColumn` / `responseColumn`. +- **Rationale:** Three saved characters is not worth the cognitive split between the doc ("column") and the identifier ("col"). + +### 15. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` +- **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. +- **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). +- **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. +- **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. + +### 16. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` +- **Why weird:** Field `optimizationState` of type `State`. If `State` is renamed to `OptimizationRunState` per #3, the field can be renamed `optimization: OptimizationRunState` or `runState: OptimizationRunState`. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `optimization` (if type renamed) or just `state` with `State` more specific. Best is the pair `optimization: OptimizationRunState`. +- **Rationale:** Reduces the noise once the enum name is specific. + +### 17. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` +- **Why weird:** `Temporal.Instant` is correct (good!) but the field name `creationTime` reads as a `Date` and many callers will accidentally `new Date(customLlm.creationTime)`, which throws because `Temporal.Instant` does not coerce. Worth a comment in JSDoc; not a rename. +- **Category:** Observation. +- **Suggested name:** Keep `creationTime`; expand JSDoc to mention `Temporal.Instant`. +- **Rationale:** Friction is from the type more than the name, but the name does not warn the reader of the unusual type. + +### 18. Method names mix `Llm` and verb tense — `src/v1/client.ts:69,92,118,137,162,191` +- **Why weird:** Methods are `cancelCustomLlmOptimizationRun`, `createCustomLlm`, `deleteCustomLlm`, `getCustomLlm`, `startCustomLlmOptimizationRun`, `updateCustomLlm`. They are verb-noun and consistent — but the noun is *always* `CustomLlm` which doubles the package name. After the fix in #2 these collapse to `cancelOptimizationRun`, `createLlm`, `deleteLlm`, `getLlm`, `startOptimizationRun`, `updateLlm` — much shorter. +- **Category:** 7 (overly verbose). +- **Suggested name:** Drop the redundant `CustomLlm` infix on the client methods; the package namespace already supplies it. +- **Rationale:** Compare to `accountSettings.Client.deleteLlmProxyPartnerPoweredWorkspace` (accountsettings package) — that name is 41 chars long. SDK ergonomics suffer. Worth a project-wide convention question. + +### 19. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +- **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. +- **Category:** 6 (misleading — name implies run-level addressing). +- **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). +- **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. + +### 20. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair +- **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. +- **Rationale:** Names should differ in more than the `Http` infix. + +### 21. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. The model file uses `unmarshalCustomLlmSchema` / `marshalCustomLlmSchema` for the same pairing — so `parseResponse` should be `unmarshalResponse` for consistency. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry, or `parseResponse` / `serializeRequest`. +- **Rationale:** Pair-wise consistency aids reading. + +### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). +- **Rationale:** Distinguish internal context bags from user-tunable option structs. + +### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +- **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Minor; only one place in the file but flagged for SDK-wide consistency review. + +## Low severity + +### 24. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +- **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. +- **Category:** Observation / 9 (reversed — correctly singular). +- **Suggested name:** No change. +- **Rationale:** Note for consistency reviews. + +### 25. `customLlmFieldMask` function name — `src/v1/model.ts:259` +- **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. +- **Category:** 17 (inconsistent verb convention in the SDK). +- **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). +- **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. + +### 26. `unmarshalCustomLlmSchema` schema variable naming — `src/v1/model.ts:101` +- **Why weird:** Verb-prefixed (`unmarshal*Schema`). The variable is *a schema*, not the act of unmarshalling. Reads as "the schema you use to unmarshal a CustomLlm" — which is precise, but the prefix is heavy. Five other `marshal*Schema` exports follow the same pattern, so this is consistent within the file; consistent vs. concise tradeoff. +- **Category:** 7 (verbose). +- **Suggested name:** `customLlmIn` / `customLlmOut`, or keep current convention if SDK-wide. Flagged for consistency review. +- **Rationale:** Internal consistency wins over local concision; only flag if SDK-wide convention is up for review. + +### 27. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Either remove the export (if it is an unused generator default), or document why it ships per-package. +- **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. + +### 28. `readAll` helper — `src/v1/utils.ts:40` +- **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` / `readStreamToEnd`. +- **Rationale:** Internal helper, low cost. Skip if generated. + +### 29. Capitalization mismatch `endpoint_name` vs `endpointName` in `unmarshalCustomLlmSchema` — `src/v1/model.ts:105,193` +- **Why weird:** Cosmetic but worth noting: the marshal schema validator uses camelCase keys (`endpointName`, `agentArtifactPath`), and the unmarshal schema validator uses snake_case keys (`endpoint_name`, `agent_artifact_path`). The two halves are symmetric (the *output* of unmarshal is camelCase, the *input* of marshal is camelCase) but the validator-key choice is asymmetric. This is a generator quirk, not a name bug. Listed under Low for completeness. +- **Category:** Observation / 17. +- **Suggested name:** No rename. +- **Rationale:** Generator-mechanical. + +### 30. `Call` import alias — `src/v1/client.ts:4` +- **Why weird:** `import type {Call}` — `Call` is a one-word generic noun. Used for the inner async function. Could be `RetryableCall`, `HttpCallback`, etc. Not local to this package (it is from `@databricks/sdk-core/api`), but worth flagging. +- **Category:** 1 (vague type name). +- **Suggested name:** Imported type; rename upstream if appropriate. +- **Rationale:** Generic noun in core API surface. + +### 31. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` +- **Why weird:** Three-letter local names. `info` for the client-info builder, `host` for the URL host, `body` for the request body. Conventional and short, but `info` is especially vague. +- **Category:** 1 (vague). +- **Suggested name:** Keep `host` and `body` (universal); rename `info` to `clientInfo`. +- **Rationale:** Localized; cosmetic. + +### 32. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` +- **Why weird:** `resp` is the response. Four methods declare `let resp: CustomLlm | undefined;` then assign in a closure and `throw` if undefined. The pattern is repetitive *and* uses the same short name. Consider extracting a helper that returns `T | never`. +- **Category:** 12 (duplicate pattern). +- **Suggested name:** Refactor away the pattern, not the name. +- **Rationale:** Refactor opportunity surfaced by naming-audit. + +## Observations + +### 33. Action verbs in `Client` are consistent +The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. +- **Category:** 17 (reversed — explicit *consistency* note). + +### 34. No `list` operation +The package exposes singleton CRUD plus optimization start/cancel, but no `listCustomLlms`. Unusual for a Databricks resource SDK. Not a naming issue, but worth flagging because the typical resource SDK has `list` and users will look for it. +- **Category:** Observation. + +### 35. Mixed acronym casing in core types +The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `APIError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `API` (all-caps), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. +- **Category:** 3 (acronym casing). + +### 36. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` +Comment "// arrays of objects are not yet supported" inside a generated utility. Not a name issue, but the public-export status of this function makes the TODO load-bearing. +- **Category:** Observation. + +## Domain glossary +- `llm` — Large Language Model (every type, every field, every method; the canonical token). +- `uc` — Unity Catalog (mentioned only in JSDoc on `agentArtifactPath` and `Table.tablePath`: "Full UC table path in catalog.schema.table_name format"). +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). +- `pat`/`m2m`/`u2m`/`oidc` — not encountered in this package. +- `iam` — not encountered. + +## File coverage +- `src/v1/model.ts` (262 lines): read fully. +- `src/v1/client.ts` (216 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (18 lines): read fully. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md new file mode 100644 index 00000000..b515dc50 --- /dev/null +++ b/.agent/naming-audit/database.md @@ -0,0 +1,462 @@ +# Naming Audit: database + +**Path:** `packages/database/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. +**Total weird names flagged:** 56 + +## Summary +| Severity | Count | +| --- | --- | +| High | 16 | +| Medium | 20 | +| Low | 14 | +| Observation | 6 | + +## High severity + +### 1. Package name `database` is generic — does not say Lakebase / OLTP / Postgres — `packages/database/` +- **Why weird:** `database` is the most generic possible word for a Databricks SDK package. The actual domain is "Lakebase" / Databricks-managed Postgres (every type either wraps a Postgres concept or is a UC mirror of one), but neither the package name, the README, nor any top-level JSDoc says "Lakebase" or "Postgres". A user scanning the workspace sees `database`, `postgres`, `sql`, `catalog` (Unity Catalog), `dbsql` etc. and cannot distinguish them. +- **Category:** 1 (vague/generic), 12 (duplicate concept: `database` vs `postgres` packages — see #2). +- **Suggested name:** `lakebase`, `lakebase-instances`, or `oltp` — whichever marketing name is canonical. At minimum, add a JSDoc on `index.ts` saying "Lakebase Postgres instance management". +- **Rationale:** Package names are the first-line filter a user uses; "database" tells them nothing. The sister package `postgres` is more specific despite sitting at a lower level. + +### 2. `database` and `postgres` packages overlap and confuse — `packages/database/` vs `packages/postgres/` +- **Why weird:** Two sibling packages model what is almost the same physical thing. `database` exposes `DatabaseInstance` / `SyncedDatabaseTable` / `DatabaseCatalog`; `postgres` exposes `ComputeInstance` / `SyncedTable` / `Catalog` / `Project` / `Branch` / `Endpoint`. Several types are textually duplicated (`DeltaTableSyncInfo`, `SyncedTablePosition`, `SyncedTablePipelineProgress`, `NewPipelineSpec`, `DatabaseCredential`, `GenerateDatabaseCredentialRequest`, `RequestedClaims`, `RequestedResource`, `ProvisioningInfo`, `ProvisioningPhase`, `SyncedTableState`, `RequestedClaims_PermissionSet`). Multiple enums share names (`ProvisioningPhase`, `SyncedTableState`, `ProvisioningInfo_State`, `RequestedClaims_PermissionSet`). +- **Category:** 12 (duplicate concept across packages), 6 (misleading: user cannot infer which package owns what). +- **Suggested name:** Either (a) merge into one `lakebase` package with versioning, (b) declare one package the public surface and mark the other internal, or (c) cross-reference each shared type and make the docstrings explicitly say "see postgres/v1 for the V2 API". +- **Rationale:** Comment at `client.ts:666-671` says "Lakebase V2 plans" — i.e. `database` is V1 and `postgres` is V2 OLTP. The naming does not reflect that lineage; users picking a dependency have no breadcrumb. + +### 3. `DatabaseInstance` — `src/v1/model.ts:234` +- **Why weird:** Type's own JSDoc says "A DatabaseInstance represents a logical Postgres instance". `DatabaseInstance` is the central noun of the package, but it is named after a generic abstraction (`Database` × `Instance`) rather than the domain (`PostgresInstance` / `LakebaseInstance`). The name does not convey what makes this distinct from any other Databricks "instance" (warehouse, cluster, online table, etc.). +- **Category:** 1 (generic), 15 (generic field name losing meaning). +- **Suggested name:** `LakebaseInstance` or `PostgresInstance`. +- **Rationale:** Reader sees `DatabaseInstance` and has no idea whether it's a SQL warehouse instance, a vector DB instance, or something else. Postgres SDK calls the same concept `ComputeInstance` (`postgres/v1/model.ts`), which is also generic — flagged separately under finding #2. + +### 4. `DatabaseInstance_State` / `DatabaseInstanceRole_IdentityType` / `DatabaseInstanceRole_MembershipRole` / `ProvisioningInfo_State` / `RequestedClaims_PermissionSet` / `SyncedTableSpec_PgSpecificType` / `SyncedTableSpec_SecondaryIndex_CreationPoint` / `DatabaseInstanceRole_Attributes` / `SyncedTableSpec_ExtraColumnDefinition` / `SyncedTableSpec_SecondaryIndex` / `SyncedTableSpec_TypeOverride` — `src/v1/model.ts:105,125,140,148,160,167,176,411,847,863,877` +- **Why weird:** Eleven exported identifiers contain `_` underscores. Every one of them needs an `eslint-disable-next-line @typescript-eslint/naming-convention`. They are proto-generated names: `Foo_Bar` originated as `package.Foo.Bar` in protobuf. TypeScript convention (Google TS style guide §9.2; `typescript.mdc` rule on identifiers) forbids underscores in type names. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). +- **Suggested name:** Flatten with descriptive prefixes/suffixes: `DatabaseInstanceState`, `RoleIdentityType`, `RoleMembershipRole`, `ProvisioningState`, `PermissionSet`, `PgColumnType`, `IndexCreationPoint`, `RoleAttributes`, `ExtraColumnDefinition`, `SecondaryIndex`, `TypeOverride`. Or nest as namespaces (TS does not need the underscore: `namespace DatabaseInstance { export type State = ... }`). +- **Rationale:** Each underscore identifier costs a lint suppression and forces users to type the underscore. The naming convention is a leaky proto abstraction. + +### 5. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:412-414` +- **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:404-409) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. +- **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS). +- **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; keep `createdb`/`createrole`/`bypassrls` on the wire (marshal/unmarshal handles the mapping). +- **Rationale:** Every other field in the package is `camelCase`. Three boolean fields breaking the convention to honour Postgres SQL keywords is a leak. Postgres SDK at `postgres/v1/model.ts` solves this differently — worth aligning. + +### 6. `SyncedTableState` — 12 enum members each prefixed with `SYNCED_TABLE_` — `src/v1/model.ts:55-102` +- **Why weird:** 12 members named `SYNCED_TABLE_PROVISIONING`, `SYNCED_TABLE_ONLINE`, `SYNCED_TABLE_ONLINE_CONTINUOUS_UPDATE`, `SYNCED_TABLE_ONLINE_TRIGGERED_UPDATE`, `SYNCED_TABLE_ONLINE_NO_PENDING_UPDATE`, `SYNCED_TABLE_OFFLINE_FAILED`, `SYNCED_TABLE_ONLINE_PIPELINE_FAILED`, `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES`, etc. The enum is already `SyncedTableState` — every member re-states `SYNCED_TABLE_`. One member is also misspelled: `SYNCED_TABLED_OFFLINE` (line 85) — extra `D` makes it `TABLED`. +- **Category:** 2 (redundant enum prefix), 18 (long enum values), 6 (misleading: `SYNCED_TABLED_OFFLINE` typo). +- **Suggested name:** `SyncedTableState.Provisioning | Online | OnlineContinuousUpdate | OnlineTriggeredUpdate | OnlineNoPendingUpdate | Offline | OfflineFailed | OnlinePipelineFailed | OnlineUpdatingPipelineResources | ProvisioningPipelineResources | ProvisioningInitialSnapshot | Unspecified`. Fix the typo regardless. +- **Rationale:** `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES` is 46 characters and contributes zero information beyond what the enum's name already says. The typo `SYNCED_TABLED_OFFLINE` is almost certainly a wire-protocol bug worth raising upstream. + +### 7. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:85` +- **Why weird:** Should be `SYNCED_TABLE_OFFLINE`. Spelled as `SYNCED_TABLED_OFFLINE` (`TABLED` past tense). +- **Category:** 6 (misleading: typo). +- **Suggested name:** `SyncedTableState.Offline` (and fix the wire-string). +- **Rationale:** This is a protocol-level typo that the SDK is propagating. If fixed upstream this becomes a breaking change unless aliased — flag now. + +### 8. `ProvisioningPhase` enum — every value prefixed `PROVISIONING_PHASE_` — `src/v1/model.ts:23-32` +- **Why weird:** 4 values: `PROVISIONING_PHASE_UNSPECIFIED`, `PROVISIONING_PHASE_MAIN`, `PROVISIONING_PHASE_INDEX_SCAN`, `PROVISIONING_PHASE_INDEX_SORT`. Same problem as #6. +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggested name:** `ProvisioningPhase.Unspecified | Main | IndexScan | IndexSort`. +- **Rationale:** Same as #6. + +### 9. `SyncedTableSchedulingPolicy` enum — every value prefixed `SYNCED_TABLE_SCHEDULING_POLICY_` — `src/v1/model.ts:34-52` +- **Why weird:** Only one member (`SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED`) carries the prefix; the other three (`CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`) do not. Inconsistent within a single enum. +- **Category:** 2 (redundant prefix on the unspecified value), 17 (inconsistency within the same enum). +- **Suggested name:** Either drop the prefix everywhere (`Unspecified | Continuous | Triggered | Snapshot`) or apply it everywhere — pick one. +- **Rationale:** Mixed conventions within a single enum are jarring and make autocomplete results look broken. + +### 10. `PipelineChannel.PIPELINE_CHANNEL_UNSPECIFIED` — `src/v1/model.ts:16` +- **Why weird:** Same pattern: the `UNSPECIFIED` sentinel is prefixed (`PIPELINE_CHANNEL_UNSPECIFIED`) but the other two (`CURRENT`, `PREVIEW`) are not. +- **Category:** 2 (redundant prefix), 17 (inconsistency). +- **Suggested name:** Drop the prefix (`Unspecified | Current | Preview`). +- **Rationale:** Same as #9. + +### 11. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) +- **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+3 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. +- **Category:** 7 (overly verbose), 12 (duplicate concept), 15 (generic prefix). +- **Suggested name:** Hoist effective values onto a sub-struct or use a discriminated `{input, effective}` shape; or drop the `effective` fields and explain in docs that the same field is read-mostly on responses. +- **Rationale:** This is a Lakebase API protocol pattern, not a naming bug per se, but the resulting TS surface is twice as wide as it needs to be. Worth pushing back upstream. + +### 12. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:493`, `client.ts:428` +- **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 494 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:518): "Name of the **cluster** to get". +- **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). +- **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. +- **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. + +### 13. `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` — `src/v1/model.ts:976`, `client.ts:998` +- **Why weird:** Inconsistent with the rest of the API surface: the type is `UpgradeInstance...` but every other type is `UpgradeDatabaseInstance...`. The method name is `upgradeInstanceToAutoscaling`, not `upgradeDatabaseInstance...`. Drops the `Database` namespace word that every other method preserves. +- **Category:** 17 (inconsistency in action verb / type prefix), 7 (overly verbose suffix `ToAutoscaling`). +- **Suggested name:** `UpgradeDatabaseInstanceRequest` (with an `autoscaling: true` toggle) or `EnableAutoscalingRequest` + `enableAutoscaling`. Pick one and match. +- **Rationale:** All other CRUD methods are `xDatabaseInstance`; this method's shorter prefix is jarring. Also the request struct has only `name` — the verb `upgradeInstanceToAutoscaling` packs the full target state into the method name, which is awkward. + +### 14. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:1017`, `index.ts:3` +- **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". +- **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). +- **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. +- **Rationale:** The current name reads ambiguously; class names should be noun phrases describing *what they are*. The export at index.ts:3 means consumers see it directly. + +### 15. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:393,399,411` +- **Why weird:** `attributes` is a generic field name; `effectiveAttributes` is a second copy; the type is a nested message that holds 3 Postgres role boolean flags. "Attributes" carries no information about what the attributes describe (Postgres `CREATEDB` / `CREATEROLE` / `BYPASSRLS` permission flags). +- **Category:** 1 (vague — `attributes` is generic), 15 (generic field name). +- **Suggested name:** `pgRoleFlags` / `PgRoleFlags`, or `permissions` / `RolePermissions`. +- **Rationale:** Reader hits `role.attributes.createdb` and has to consult the type to find out it's a Postgres-flag bag. Postgres docs use the phrase "role attributes" so the alignment is intentional — but the SDK is for non-Postgres-experts too. + +### 16. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:545,589` +- **Why weird:** The list-response field on catalogs is `databaseCatalogs: DatabaseCatalog[]` (matches type name), but on synced tables it's `syncedTables: SyncedDatabaseTable[]` (drops `Database`). On instance-roles it's `databaseInstanceRoles: DatabaseInstanceRole[]` (matches). On instances it's `databaseInstances: DatabaseInstance[]` (matches). The synced-tables one is the odd one out. +- **Category:** 17 (inconsistent), 9 (singular/plural mismatch with the type). +- **Suggested name:** `syncedDatabaseTables: SyncedDatabaseTable[]` (wire stays `synced_tables` if API requires it). +- **Rationale:** Internal consistency — every other list-response uses the type's plural; only this one shortens. Wire payload uses `synced_tables` so the divergence may be a generator decision; flag for cleanup. + +## Medium severity + +### 17. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:236,238` +- **Why weird:** Two fields look like identifiers. `uid` is "immutable UUID identifier"; `name` is "unique identifier". Caller reading the struct can't tell at a glance which one to pass to `getDatabaseInstance` (answer: `name`, per client.ts:517). Bare `uid` is also non-descriptive — Lakebase uses both PG-side OIDs and Databricks-side UUIDs. +- **Category:** 19 (underspecified id when multiple ids exist), 1 (vague `uid`). +- **Suggested name:** `instanceUid` / `instanceName`, or `id` / `name` (collapse `uid` to `id`). +- **Rationale:** Same field-disambiguation pattern as `PolicyInfo.id` in the abacpolicies audit. `uid` reads as a hash, not a Databricks UUID — and the JSDoc just says "UUID identifier". + +### 18. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:240` +- **Why weird:** Field doc says "The email of the creator of the instance". Field name says `creator`. So is the value an email, a username, or an account id? Postgres SDK uses `createdBy` for the same concept (postgres/v1/model.ts). +- **Category:** 1 (vague — `creator` could be a name, an id, or an email), 6 (misleading — doc says email, name says creator). +- **Suggested name:** `creatorEmail` (or `createdBy` if the value can be a service-principal id too). +- **Rationale:** The doc explicitly narrows the type; the field name should match. + +### 19. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:250` +- **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. +- **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). +- **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". +- **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. + +### 20. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:248` +- **Why weird:** `pg` is two letters lowercase; the next word starts capitalised. Consistent with `pgType` (model.ts:881) but inconsistent with `Postgres`/`PostgreSQL` used in JSDoc. Acronym `PG` is widely written uppercase. +- **Category:** 3 (acronym casing — `pg` should arguably be `Pg` per camelCase, `PG` per acronym preservation). +- **Suggested name:** `postgresVersion` (spell out), or `pgVersion` (current). +- **Rationale:** The codebase elsewhere uses `Pg` (e.g. enum `SyncedTableSpec_PgSpecificType`). Current `pgVersion` is OK but `postgresVersion` would be clearer. + +### 21. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:242,289` +- **Why weird:** `Dns` is a single word; `DNS` is the acronym. Field doc says "The DNS endpoint to connect to the instance"; the value is a hostname, not a DNS server. Misleading abbreviation. +- **Category:** 3 (acronym casing), 6 (misleading — `dns` suggests a DNS server, not an endpoint). +- **Suggested name:** `readWriteEndpoint` / `readOnlyEndpoint`, or `readWriteHost` / `readOnlyHost`. +- **Rationale:** A "DNS endpoint" is a non-standard phrase; the field is just a hostname. + +### 22. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:258,264` +- **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? +- **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). +- **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. +- **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. + +### 23. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:269` +- **Why weird:** Field name says "node count"; doc says "1 primary and 0 or more secondaries". `nodeCount = 3` means 1 primary + 2 secondaries — but also could be read as "3 nodes, role unspecified". Postgres standby/replica terminology would be clearer. +- **Category:** 1 (vague), 6 (misleading without docs). +- **Suggested name:** `replicaCount`, or pair `primaryCount` + `secondaryCount`, or `totalNodeCount` (and document). +- **Rationale:** Confusing arithmetic — `1` means primary-only, `2` means 1 primary + 1 secondary, etc. + +### 24. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:278` +- **Why weird:** `enableXyz: boolean` is a request-shaped name on a response-shaped type. `enableReadableSecondaries: true` reads as imperative ("please enable"), but it's also returned from server. The companion `effectiveEnableReadableSecondaries` reads as "the effective please-enable-readable-secondaries". The doc on `effectiveEnableReadableSecondaries` even rewords it: "Whether secondaries serving read-only traffic are enabled" — i.e. the read shape should just be `readableSecondariesEnabled` or `hasReadableSecondaries`. +- **Category:** 6 (misleading verb form for a response), 17 (input/output asymmetry). +- **Suggested name:** Input: `enableReadableSecondaries: boolean`. Output: `readableSecondariesEnabled: boolean` (or just merge: response carries the same `enableReadableSecondaries` and don't bother with the `effective_` twin). +- **Rationale:** Generator artefact, but worth flagging. + +### 25. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:309,314` +- **Why weird:** `Ref` is a cryptic abbreviation (cf. `typescript.mdc` "spell out short identifiers"). Same as `DatabaseInstanceRef` itself. Could be `Reference` or just `DatabaseInstancePointer`. The semantic ("a reference to an instance") doesn't need the abbreviation. +- **Category:** 5 (cryptic abbreviation), 8 (redundant `Ref` suffix — these are already references). +- **Suggested name:** `parentInstance: DatabaseInstanceReference` / `childInstances: DatabaseInstanceReference[]`. +- **Rationale:** Mild — `Ref` is widely understood — but spelling out matches the project rule. + +### 26. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:362` +- **Why weird:** `lsn` is a Postgres-internal acronym (Log Sequence Number) shown without expansion. JSDoc says "User-specified WAL LSN" — still abbreviated. +- **Category:** 5 (cryptic abbreviation), 14 (Postgres-internal term in public TS API). +- **Suggested name:** `walLsn` (mild improvement), or `walLogSequenceNumber` (verbose but unambiguous). +- **Rationale:** Lakebase exposes this to schedule branch creation; consumers may not know `lsn` without consulting Postgres docs. + +### 27. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:381` +- **Why weird:** `branchTime` is a noun-phrase that reads as "the time of a branch" but is documented as "the point in time on the parent instance from which the instance was created" — i.e. the PITR cutover instant. `branchTime` and `lsn` are alternatives for the same operation (PITR cutover specifier). +- **Category:** 1 (vague), 6 (misleading — `branchTime` suggests an event time, actually a cutover specifier). +- **Suggested name:** `branchPointTime` / `branchAt` / `pitrTimestamp`. +- **Rationale:** Reads naturally as "when was this branch made" but actually means "what point in the source's history to branch from". + +### 28. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:224` +- **Why weird:** Bare `uid?: string` with no comment, alongside `name`, `databaseInstanceName`, `databaseProjectId`, `databaseBranchId`, `databaseName`. Six identifier-like fields and one (`uid`) is undocumented and unprefixed. +- **Category:** 19 (underspecified id), 1 (vague). +- **Suggested name:** `catalogUid` (and add a doc comment). +- **Rationale:** Reader cannot guess what scope the uid is for. + +### 29. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:225` +- **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF NOT EXISTS`). Reads as a literal SQL DDL fragment in the type. Could be `ensureDatabase` / `autoCreateDatabase`. +- **Category:** 14 (SQL-style name), 7 (verbose). +- **Suggested name:** `ensureDatabaseExists` / `autoCreateDatabase`. +- **Rationale:** Internal consistency with TS naming conventions. + +### 30. `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` — `src/v1/model.ts:219-223` +- **Why weird:** `databaseProjectId` reads as "project id of a database (entity)" but doc says "project_id of the database project". The `database` prefix on every field is redundant once you're already inside `DatabaseCatalog`. Postgres SDK has `Catalog` (no `database` prefix) with `project`, `branch`, `database` sub-references — cleaner. +- **Category:** 7 (verbose prefix), 12 (duplicate concept across packages). +- **Suggested name:** `projectId`, `branchId`, `name` on the catalog directly; or hoist to a sub-struct `database: {projectId, branchId, name}`. +- **Rationale:** The struct is already a `DatabaseCatalog`; re-prefixing every field is noise. + +### 31. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:419` +- **Why weird:** Bare `name` carries a complex format (`catalog.schema.table`). Postgres SDK calls the same concept `fullName` / `name` more explicitly. There is no validation in the type — the convention is doc-only. +- **Category:** 1 (vague), 6 (misleading — name looks like a single identifier, actually 3-part). +- **Suggested name:** `fullName` (matches Postgres SDK convention). +- **Rationale:** Same field name `name` appears on `DatabaseCatalog`, `DatabaseInstance`, `DatabaseInstanceRef`, `DatabaseInstanceRole`, `DatabaseTable`, `SyncedDatabaseTable` — each carries different semantics (DNS-safe vs UC-3-part vs role-name). + +### 32. `DatabaseTable.tableServingUrl` field — `src/v1/model.ts:437` +- **Why weird:** `tableServingUrl` on a `DatabaseTable` reads as "the URL where this table is served". Doc says "Data serving REST API URL for this table". The word `Serving` is ML/feature-store jargon; on a Postgres table it's confusing. +- **Category:** 1 (vague), 6 (misleading — `Serving` is feature-store terminology, here means "REST endpoint"). +- **Suggested name:** `restEndpointUrl` / `apiEndpointUrl`. +- **Rationale:** Avoid leaking the internal "data serving" abstraction. + +### 33. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:417,643` +- **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`, `tableServingUrl`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". +- **Category:** 12 (duplicate concept), 1 (generic `Database`). +- **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. +- **Rationale:** Reader has to read both JSDocs to understand the partitioning. + +### 34. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:802` +- **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`, `tableServingUrl`) split words at capital boundaries. +- **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). +- **Suggested name:** `timeSeriesKey`. +- **Rationale:** Trivia, but `time series` is two words in English. + +### 35. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:798,419` +- **Why weird:** Same domain concept (UC 3-part name) named two different ways in the same package: `sourceTableFullName` here, bare `name` on `DatabaseTable`/`SyncedDatabaseTable`/`DatabaseCatalog`. +- **Category:** 17 (inconsistent naming for the same concept). +- **Suggested name:** Standardise on `fullName` (or `tableFullName`) across the package. +- **Rationale:** Pair with #31. + +### 36. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:815` +- **Why weird:** Similar SQL-DDL leak as #29. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. +- **Category:** 14 (SQL-style name), 6 (typo in cross-reference). +- **Suggested name:** `ensureDatabaseAndSchema`. +- **Rationale:** Internal consistency. + +### 37. `SyncedTableSpec.acceleratedSync` — `src/v1/model.ts:830` +- **Why weird:** Adjective-noun toggle; reads as "use accelerated sync" but unclear what "accelerated" means. JSDoc says "enables accelerated sync mode for the initial data load." +- **Category:** 1 (vague — what *is* accelerated sync?), 15 (generic adjective). +- **Suggested name:** `useAcceleratedInitialLoad` or `accelerateInitialLoad`. +- **Rationale:** A consumer should not have to read JSDoc to know "accelerated" means "initial-load fast path". + +### 38. `SyncedTableSpec.extraIndexDefinitions` vs `SyncedTableSpec_SecondaryIndex` (type) — `src/v1/model.ts:837,863` +- **Why weird:** Field is `extraIndexDefinitions` (plural noun, generic suffix), but the type is `SecondaryIndex`. Field-type mismatch: type says "secondary index"; field says "extra index definitions". Both are accurate, but using two different framings within five lines is confusing. +- **Category:** 17 (inconsistency between field name and type name), 1 (`extra` is vague). +- **Suggested name:** `secondaryIndexes: SecondaryIndex[]` (drop `Definitions` suffix — type already implies definition). +- **Rationale:** Type-name and field-name should align. + +### 39. `SyncedTableSpec.extraColumnDefinitions` vs `SyncedTableSpec_ExtraColumnDefinition` — `src/v1/model.ts:839,847` +- **Why weird:** Field `extraColumnDefinitions: ExtraColumnDefinition[]` — at least these align. But `ExtraColumnDefinition` itself is two redundant words (column definitions are themselves definitions). `Extra` modifier doesn't say what they're extra to. +- **Category:** 7 (verbose), 1 (`extra` is vague). +- **Suggested name:** `pgOnlyColumns: PgOnlyColumn[]` (doc says "additional PostgreSQL-only column"). +- **Rationale:** The doc has the better name buried in it. + +### 40. `SyncedTableSpec.typeOverrides: SyncedTableSpec_TypeOverride[]` — `src/v1/model.ts:835` +- **Why weird:** Plural list of nested `Foo_TypeOverride` types. Field name matches but the nested type has the `_` underscore problem (#4). Reads as "type overrides are type-override objects" — circular. +- **Category:** 17 (mirror name), 4 (underscore type). +- **Suggested name:** `columnTypeOverrides: ColumnTypeOverride[]` (the override is per-column, so be specific). +- **Rationale:** Plain `typeOverrides` is too generic; could be Delta types, JSON types, etc. + +### 41. `SyncedTableSpec_TypeOverride.pgType` field of type `SyncedTableSpec_PgSpecificType` — `src/v1/model.ts:881` +- **Why weird:** Type-suffix tautology: `pgType: PgSpecificType`. Wire is `pg_type`. Doc says "PostgreSQL-specific target type". +- **Category:** 20 (type-suffix tautology), 4 (nested underscore type as field type). +- **Suggested name:** `targetType: PgColumnType`. +- **Rationale:** Rule 20. + +### 42. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:892` +- **Why weird:** Field is `detailedState`; sibling field is `detailedStatus`. Both have `detailed` prefix; redundant against the wrapping type `SyncedTableStatus`. Easy to confuse `detailedState` (enum) with `detailedStatus` (oneof). +- **Category:** 17 (two `detailed*` neighbours), 7 (verbose). +- **Suggested name:** `state: SyncedTableState`, `status: SyncedTableStatusDetail` (or hoist the oneof). +- **Rationale:** Reader hits `tableStatus.detailedState` and `tableStatus.detailedStatus` and has to read both to decide which is which. + +### 43. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:896` +- **Why weird:** `detailedStatus` on a `SyncedTableStatus` type is doubly redundant. Holds one of four phase-shaped sub-statuses (`provisioningStatus`, `continuousUpdateStatus`, `triggeredUpdateStatus`, `failedStatus`). Each variant is named `*Status` again — `tableStatus.detailedStatus.continuousUpdateStatus.lastProcessedCommitVersion` is "status.status.status.version". +- **Category:** 7 (overly verbose chains), 20 (type-suffix tautology). +- **Suggested name:** Rename `detailedStatus` to `phase`, and strip the redundant `*Status` suffix off each sub-variant (`provisioning`, `continuousUpdate`, `triggeredUpdate`, `failed`). +- **Rationale:** Reduces three `status` words to one without touching the wrapper itself. + +### 44. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:928` +- **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. +- **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). +- **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. +- **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. + +### 45. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:749` +- **Why weird:** Run-on field name — "latest version currently processing" is 4 words. Doc clarifies "may not have completely processed this version yet". Could be `inProgressDeltaVersion` or `currentDeltaVersion`. +- **Category:** 7 (overly verbose), 1 (verbose adverb). +- **Suggested name:** `processingDeltaVersion`. +- **Rationale:** Verbose field names hurt readability. + +### 46. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:751-757` +- **Why weird:** Mixed metric naming: `syncedRowCount` and `totalRowCount` use suffix `Count`; `syncProgressCompletion` uses suffix `Completion` (a number 0-1); `estimatedCompletionTimeSeconds` uses suffix `TimeSeconds` (unit-embedded). Three different conventions for "a number". +- **Category:** 17 (inconsistent suffixes), 15 (generic field names). +- **Suggested name:** `syncedRows`, `totalRows`, `progressFraction`, `etaSeconds`. +- **Rationale:** The number-suffix conventions don't align with each other; pick one. + +### 47. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:754-755` +- **Why weird:** Type is `number`; doc constrains to `[0, 1]`. Type system doesn't help. Field name `syncProgressCompletion` is also redundant — completion is what progress measures. +- **Category:** 16 (type contradicts doc constraint), 7 (verbose). +- **Suggested name:** `progressFraction` (or `progressRatio`), `number` in [0,1]. +- **Rationale:** Same as #46 plus a separate concern about the value range. + +### 48. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:477` +- **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. +- **Category:** 20 (type-suffix tautology in field names), 7 (verbose). +- **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. +- **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. + +### 49. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:510,630` +- **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. +- **Rationale:** Plural-of-plural confuses iteration code. + +### 50. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:500` +- **Why weird:** Bare `requestId` with no doc. Other request types do not have `requestId`. Looks like an idempotency key but the type doesn't say. +- **Category:** 1 (vague), 19 (underspecified id). +- **Suggested name:** `idempotencyKey` (and add docs). +- **Rationale:** Without docs, callers can't tell whether to set it. + +### 51. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:501-502` +- **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. +- **Category:** 16 (type contradicts domain constraint), 1 (loose contract). +- **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. +- **Rationale:** Generator artefact; flag for upstream tightening. + +### 52. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:453-456` +- **Why weird:** "Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. Setting a value of false will throw a bad request." Field is exposed in the public TS type but has no `@deprecated` JSDoc tag. +- **Category:** 6 (misleading: deprecated field undocumented as deprecated). +- **Suggested name:** Add `@deprecated` tag; consider removing in next major. +- **Rationale:** TS tooling honours `@deprecated`; the current setup just has prose. + +## Low severity + +### 53. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:553` +- **Why weird:** Doc says "Pagination token to go to the next page of Database Instances" — but this is roles, not instances. Doc-copy bug. +- **Category:** 6 (misleading doc). +- **Suggested name:** Fix the doc to say "roles". +- **Rationale:** Naming-adjacent bug worth flagging. + +### 54. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:539` +- **Why weird:** Same bug: catalogs request says "synced database tables" in doc. +- **Category:** 6 (misleading doc). +- **Suggested name:** Fix to "catalogs". +- **Rationale:** Same as #53. + +### 55. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:562` +- **Why weird:** Doc says "next page of instances" for the roles response. +- **Category:** 6 (misleading doc). +- **Suggested name:** Fix to "roles". +- **Rationale:** Same as #53. + +### 56. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:192-196` +- **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:185-188). +- **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). +- **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. +- **Rationale:** Caller has to know the wire-encoding accident to decide which to set. + +### 57. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:462` +- **Why weird:** Postgres-isms (`REASSIGN OWNED BY ... TO ...`) collapsed into a single field. Field name reads as a verb phrase ("reassign owned [things] to"). +- **Category:** 14 (SQL-style name). +- **Suggested name:** `reassignOwnedObjectsTo` or `newOwner`. +- **Rationale:** Mild — Postgres admins will get it. + +### 58. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:463-464` +- **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. +- **Category:** 14 (Google-AIP naming convention leak). +- **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. +- **Rationale:** Internal-jargon leak; flag for awareness. + +### 59. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:474` +- **Why weird:** Boolean named after a side effect (`purge_data`). Doc says "the actual PostgreSQL table will be dropped from the database". Combination of `delete` + `purge` is also confusing — what does the no-purge case do? (Drop UC registration only.) +- **Category:** 1 (vague), 6 (misleading). +- **Suggested name:** `dropUnderlyingTable` / `cascade`. +- **Rationale:** Minor — affects discoverability. + +### 60. `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` — `src/v1/model.ts:490` +- **Why weird:** 30-character field name on a 2-field request. Reads as "failover target database instance name" which is 5 nouns stacked. +- **Category:** 7 (overly verbose). +- **Suggested name:** `targetInstanceName`. +- **Rationale:** Inside a `FailoverDatabaseInstanceRequest`, the `failover` and `databaseInstance` prefixes are implied. + +### 61. `RequestedClaims_PermissionSet.PERMISSION_SET_UNSPECIFIED` redundant prefix — `src/v1/model.ts:161` +- **Why weird:** Same enum-prefix pattern as #9/#10 — `PERMISSION_SET_UNSPECIFIED` re-states the enum name. +- **Category:** 2 (redundant enum prefix). +- **Suggested name:** Drop the prefix. +- **Rationale:** Same. + +### 62. `SyncedTableSpec_PgSpecificType.PG_SPECIFIC_TYPE_UNSPECIFIED` / `PG_SPECIFIC_TYPE_VECTOR` — `src/v1/model.ts:169,171` +- **Why weird:** Both enum values prefixed `PG_SPECIFIC_TYPE_`. +- **Category:** 2 (redundant prefix), 18 (long enum values). +- **Suggested name:** `PgColumnType.Unspecified | Vector`. +- **Rationale:** Same. + +### 63. `SyncedTableSpec_SecondaryIndex_CreationPoint.CREATION_POINT_*` — `src/v1/model.ts:178,180` +- **Why weird:** `CREATION_POINT_UNSPECIFIED` / `CREATION_POINT_AFTER_DATA_LOAD`. Same redundant prefix. +- **Category:** 2 (redundant prefix). +- **Suggested name:** `IndexCreationPoint.Unspecified | AfterDataLoad` (drop `CREATION_POINT_`). +- **Rationale:** Same. + +### 64. `DatabaseInstanceRole_IdentityType.PG_ONLY` — `src/v1/model.ts:129` +- **Why weird:** All-caps acronym suffix `PG_ONLY` — the only non-`UNSPECIFIED` value that is not a full English word (`USER`, `SERVICE_PRINCIPAL`, `GROUP`). Reads as a flag, not an identity type. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistent with peers). +- **Suggested name:** `PostgresOnly` (spell out). +- **Rationale:** Aligns with peers. + +### 65. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:82` +- **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Cross-package consistency. + +### 66. `StillRunningError` private error class — `src/v1/client.ts:87` +- **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. +- **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). +- **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). +- **Rationale:** Throwing for control flow is fine; the *name* shouldn't pretend it's a real error. + +## Observations + +### 67. Wire/TS divergence is enormous in this package +File `model.ts` is 2,217 lines. ~270 lines are the actual user-facing TS interfaces and enums; the rest is unmarshal schemas (~520 lines), marshal schemas (~490 lines), and `FieldMaskSchema` definitions (~200 lines), plus paired exports. This is a generator-shape observation, not a naming bug — but it dwarfs the public surface 7x. + +### 68. `client.ts` has a 6-line block-comment at line 666-671 explaining that the role APIs will never reach Public Preview +The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. +- **Category:** 6 (misleading: client exposes APIs that won't stabilise). +- **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. + +### 69. `findDatabaseInstanceByUid` is the only `findBy*` method +Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. +- **Category:** 17 (inconsistency with peer methods). + +### 70. `marshal*` / `unmarshal*` schemas are exported even though no consumer should use them +All `marshal*` and `unmarshal*` schemas in `model.ts` are `export`. They are used internally by `client.ts` but are public surface. Same as the abacpolicies audit observation. +- **Category:** Observation. + +### 71. Action-verb conventions in `Client` are consistent +`create*` / `delete*` / `get*` / `list*` / `update*` / `failover*` / `findBy*` / `upgrade*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. + +### 72. `index.ts` re-exports both types and value enums but does not re-export `marshal*` / `unmarshal*` schemas +Good hygiene — only the user-facing surface is re-exported. The `*FieldMaskSchema` constants are not exported (they're file-private). The `databaseCatalogFieldMask` / `databaseInstanceFieldMask` / `syncedDatabaseTableFieldMask` builder functions are exported from `model.ts` (lines 2025, 2068, 2116) but NOT re-exported in `index.ts` — so they exist on the package boundary but are not visible to consumers. Inconsistency. +- **Category:** 17 (inconsistent export surface). + +## Domain glossary +- `Lakebase` — Databricks' managed Postgres-as-a-service product (mentioned only in the buried client.ts:666 comment). +- `PG` / `pg` / `Postgres` / `PostgreSQL` — Postgres database; appears as `pgVersion`, `pgType`, `enablePgNativeLogin`, `PG_ONLY`, `PG_SPECIFIC_TYPE_*`, and as `PostgreSQL` in JSDoc. +- `UC` — Unity Catalog (referenced in `claims` doc model.ts:506-510 and in JSDoc of `DatabaseCatalog` model.ts:214). +- `DNS` — Domain Name System (used as `Dns` suffix on `readWriteDns`/`readOnlyDns`). +- `LSN` — Postgres Log Sequence Number (`lsn`, `effectiveLsn`). +- `WAL` — Postgres Write-Ahead Log (referenced in `lsn` doc). +- `CU` — Capacity Unit (e.g. `CU_1`, `CU_2` — only in `capacity` doc string). +- `CDF` — Change Data Feed (Delta Lake feature; referenced in `SyncedTableSchedulingPolicy` docs). +- `PITR` — Point-in-Time Recovery (referenced in `DeleteDatabaseInstanceRequest.force` doc). +- `RLS` — Row-Level Security (`bypassrls` field). +- `AIP` — Google API Improvement Proposals (referenced in `allowMissing` doc). +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). +- `oss`/`m2m`/`u2m`/`pat`/`iam`/`abac` — not encountered in this package. + +## File coverage +- `src/v1/model.ts` (2,217 lines): read fully. +- `src/v1/client.ts` (1,088 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (76 lines): read fully. diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md new file mode 100644 index 00000000..60d2773b --- /dev/null +++ b/.agent/naming-audit/dataclassification.md @@ -0,0 +1,199 @@ +# Naming Audit: dataclassification + +**Path:** `packages/dataclassification/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. +**Total weird names flagged:** 29 + +## Summary +| Severity | Count | +| --- | --- | +| High | 7 | +| Medium | 11 | +| Low | 7 | +| Observation | 4 | + +## High severity + +### 1. `AutoTaggingConfig_AutoTaggingMode` — `src/v1/model.ts:9` +- **Why weird:** Underscore in TS identifier (proto-style nested enum name). Required `eslint-disable @typescript-eslint/naming-convention`. The outer container `AutoTaggingConfig` is already in scope of import, so the prefix is redundant; the underscore is a leaky proto abstraction. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names not idiomatic in TS), 20 (type-suffix tautology — `AutoTaggingConfig_AutoTaggingMode` re-states `AutoTagging`). +- **Suggested name:** `AutoTaggingMode` (top-level), or namespace it under `AutoTaggingConfig` via TS namespace if nesting really must be preserved. +- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`. The `eslint-disable` directive is the smoking gun that the name fights the language. `AutoTaggingMode` is unambiguous on its own; the field that uses it is already named `autoTaggingMode`. + +### 2. `AutoTaggingConfig_AutoTaggingMode.AUTO_TAGGING_MODE_UNSPECIFIED` / `AUTO_TAGGING_DISABLED` / `AUTO_TAGGING_ENABLED` — `src/v1/model.ts:10-12` +- **Why weird:** Every enum value re-states the enum name (`AutoTaggingMode.AUTO_TAGGING_*`). The `UNSPECIFIED` sentinel is a protobuf import; idiomatic TS would use `undefined` for "not set". Also note that the unspecified value carries the `_MODE_` infix while the other two drop it — inconsistent. +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names), 17 (action-prefix inconsistency — `_MODE_` is present on `UNSPECIFIED` but missing on `DISABLED`/`ENABLED`). +- **Suggested name:** `AutoTaggingMode.Disabled | Enabled` (drop `Unspecified` and rely on `autoTaggingMode?: AutoTaggingMode | undefined`). +- **Rationale:** TS enum members are already namespaced by the enum (`AutoTaggingMode.Enabled`). The `AUTO_TAGGING_` prefix is pure protobuf noise. A binary on/off concept does not need a third "unset" sentinel when the field is already optional. + +### 3. `autoTagConfigs` field vs. `AutoTaggingConfig` type — `src/v1/model.ts:57,62` +- **Why weird:** Field name uses abbreviated `autoTag` while the type it points to is the full `AutoTaggingConfig`. Within five lines the SDK uses both `tag`-noun and `tagging`-gerund for the same concept. +- **Category:** 5 (cryptic abbreviation — `Tag` for `Tagging`), 17 (inconsistency with sibling type — `autoTagConfigs: AutoTaggingConfig[]`). +- **Suggested name:** `autoTaggingConfigs: AutoTaggingConfig[]` (and `effectiveAutoTaggingConfigs`). Wire stays `auto_tag_configs` if upstream insists. +- **Rationale:** A field of `Foo[]` should plural-ise the type name: `foos: Foo[]`. Mixing `autoTag` and `AutoTagging` makes the relationship unobvious and forces a mental translation on every read. + +### 4. `effectiveAutoTagConfigs` — `src/v1/model.ts:62` +- **Why weird:** Two parallel fields (`autoTagConfigs` for owned + `effectiveAutoTagConfigs` for owned-plus-inherited) on the same type. "Effective" is fine on its own, but the parent type does not say which is read-only vs. write — a caller can easily set `effectiveAutoTagConfigs` thinking it will take effect. +- **Category:** 1 (vague — `effective` does not communicate "computed/read-only" on its own), 6 (misleading: looks settable but is server-computed). +- **Suggested name:** `inheritedAutoTaggingConfigs` (or split into `autoTaggingConfigs` + `computedAutoTaggingConfigs` with a JSDoc `@readonly`). +- **Rationale:** SDK fields without an output-only marker invite write-side mistakes. The current doc says "Computed from auto_tag_configs on this catalog and those inherited from the metastore" but the type does not enforce that. + +### 5. `name` field on `CatalogConfig` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` — `src/v1/model.ts:42,88,94` +- **Why weird:** Field literally called `name` carries a structured resource path (`catalogs/{catalog_name}/config`), not a free-form name. `name` is the most generic possible identifier and gives no hint that it must follow a specific format. +- **Category:** 1 (vague — `name` is the canonical too-generic field name), 6 (misleading — looks like a display name, is actually a structured resource path), 15 (generic field name losing meaning), 19 (underspecified ID). +- **Suggested name:** `resourceName` or `configResourceName`. If staying with `name`, the JSDoc should at least be on the type rather than only on each field. +- **Rationale:** A user importing `CatalogConfig` and seeing `name?: string` will almost certainly try to put `"my-catalog"` in there, not `"catalogs/my-catalog/config"`. The wire constraint is invisible from the type. + +### 6. `parent` field on `CreateCatalogConfigRequest` — `src/v1/model.ts:77` +- **Why weird:** Field called `parent` carries the structured value `catalogs/{catalog_name}`. The relationship "catalog is the parent of catalog-config" is a proto/AIP-160 convention that does not survive into a TS SDK where users do not see the resource hierarchy. +- **Category:** 1 (vague — `parent` of what?), 15 (generic field name losing meaning), 19 (underspecified ID). +- **Suggested name:** `catalogResourceName` or `parentCatalog`. +- **Rationale:** `parent: string` is a Google-AIP idiom; outside that context a caller has no idea what shape to put in. A user-friendly TS SDK would either accept `{catalogName: 'my-catalog'}` directly or rename to make the constraint visible. + +### 7. `classificationTag` and `classificationTagValue` — `src/v1/model.ts:25,32` +- **Why weird:** The pair encodes a `(key, value)` tag, but the names are `tag` and `tagValue` instead of `tagKey` and `tagValue`. The first field actually holds the tag *key* per its doc ("For built-in classes this is a system tag (e.g., \"class.name\"...)"). Calling the key "the Classification Tag" while the value is "the Classification Tag Value" makes the parts asymmetric. +- **Category:** 1 (vague — `classificationTag` is the key, not the whole tag), 6 (misleading — name suggests "the tag" but it is one half of one), 17 (asymmetric pair naming — `tag` vs `tagValue`). +- **Suggested name:** `classificationTagKey` + `classificationTagValue` (or `tagKey` + `tagValue`). +- **Rationale:** Symmetric `key`/`value` field names are the standard idiom for tag pairs across Unity Catalog (`tagKey`/`tagValue` appears in `unitycatalog` packages). The current name asymmetry suggests the two fields hold different kinds of thing when they hold two halves of one. + +## Medium severity + +### 8. `Client` class — `src/v1/client.ts:38` +- **Why weird:** A class literally named `Client` at the top level of the package's API surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). +- **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). +- **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. + +### 9. `CreateCatalogConfigRequest` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` / `UpdateCatalogConfigRequest` — `src/v1/model.ts:75,86,92,103` +- **Why weird:** All four request DTOs repeat the noun `CatalogConfig` even though the only thing this package operates on is `CatalogConfig`. The package name itself is `dataclassification`. In context, `CreateRequest`/`UpdateRequest` would be plenty. +- **Category:** 7 (overly verbose), 8 (redundant suffix and infix). +- **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`, or keep `Catalog` and drop `Config`: `CreateCatalogRequest`/... +- **Rationale:** The whole package operates on exactly one entity. Repeating its name in four request types is pure noise. (However, the inconsistency with the entire rest of the SDK matters — proposing as a per-package fix is risky. Listed medium not high.) + +### 10. `marshalCatalogConfigSchema` / `unmarshalCatalogConfigSchema` etc. — `src/v1/model.ts:113,125,161,173` +- **Why weird:** These are Zod schemas, but the names use `marshal`/`unmarshal` (Go terminology) where TS / JS users would say `encode`/`decode` or `serialize`/`parse`. Within Zod's own docs the verb is `parse`. Mixing Go vocabulary with a TS library is jarring. +- **Category:** 14 (Go-style names imported into TS), 17 (verb inconsistency — Zod's own API is `.parse()`, not `.unmarshal()`). +- **Suggested name:** `encodeCatalogConfigSchema` / `decodeCatalogConfigSchema`, or `catalogConfigToWireSchema` / `catalogConfigFromWireSchema`. +- **Rationale:** Marshal/unmarshal is a Go term of art; TS developers reach for `JSON.stringify`/`JSON.parse` or Zod's `parse`/`safeParse`. The current name forces a vocabulary translation. + +### 11. `catalogConfigFieldMaskSchema` and `catalogConfigFieldMask(...)` — `src/v1/model.ts:209,219` +- **Why weird:** Two exports differ only by the `Schema` suffix; the helper function and its lookup table share a stem. A reader has to look up which is the runtime config vs. which is the factory. Function/data naming should be more distinguishable. +- **Category:** 17 (inconsistent action verbs — schema is a noun, but the function uses the same name as a verbless noun). +- **Suggested name:** `buildCatalogConfigFieldMask(...)` for the function, leave the schema with `Schema` suffix. +- **Rationale:** Functions should be verb-prefixed; the schema-vs-builder distinction should jump off the page. Sister packages share this problem (generator-wide). + +### 12. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (`call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. +- **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). +- **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. +- **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. + +### 13. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +- **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. +- **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). +- **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). +- **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. + +### 14. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` +- **Why weird:** The function takes an arbitrary `unknown` value plus a Zod schema and returns a JSON string. The name says "Request" but the function does not know whether `data` is a request, response, or anything else. +- **Category:** 1 (vague — `Request` in the name does not constrain), 6 (misleading — works for any payload, not specifically requests). +- **Suggested name:** `marshalToJson` / `encodeToJson` / `toWireJson`. +- **Rationale:** The function is symmetric to `parseResponse`, which has the same problem in reverse. `Request`/`Response` should be specific to their meaning. + +### 15. `parseResponse(body, schema)` — `src/v1/utils.ts:113` +- **Why weird:** Symmetric problem to `marshalRequest`. The function parses any JSON `Uint8Array` against a Zod schema. The name says "Response" but the function does not check that. +- **Category:** 1, 6. +- **Suggested name:** `parseJsonBody` / `decodeFromJson` / `fromWireJson`. +- **Rationale:** Same as #14. `marshalRequest` + `parseResponse` are an asymmetric verb pair (`marshal` vs. `parse`) AND inaccurate. Either fix both. + +### 16. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. +- **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). +- **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. +- **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. + +### 17. `readAll(body)` — `src/v1/utils.ts:40` +- **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". +- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). +- **Suggested name:** `drainStream` or `readStreamToUint8Array`. +- **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. + +### 18. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. +- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). +- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. +- **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. + +## Low severity + +### 19. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` +- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. +- **Category:** 1 (vague — `Segment` of what?). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. +- **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. + +### 20. `userAgent` field — `src/v1/client.ts:45` +- **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. +- **Category:** N/A (verification, no issue). +- **Suggested name:** unchanged. +- **Rationale:** Listed only to confirm canonical naming is preserved. + +### 21. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` +- **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). +- **Category:** 1 (vague), 12 (duplicate concept). +- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. +- **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. + +### 22. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` +- **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. +- **Category:** 6 (misleading — optional in type but required in practice). +- **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. +- **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. + +### 23. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` +- **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). +- **Suggested name:** `rawBody` + `result` (or `parsedResponse`). +- **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. + +### 24. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` +- **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. +- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). +- **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. +- **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest` solves it. + +### 25. `unmarshalCatalogConfig_SchemaNamesSchema` — `src/v1/model.ts:152` +- **Why weird:** Underscore in the identifier (proto-style nesting carried into the Zod schema name) plus type-suffix tautology — the trailing `Schema` is the Zod marker, but the inner `Schema` in `SchemaNames` is the field semantics, producing a hard-to-parse `..._SchemaNamesSchema` triple. Required `eslint-disable`. +- **Category:** 4 (underscore in TS identifier), 14 (Go/proto-style names), 20 (type-suffix tautology). +- **Suggested name:** Drop the underscore segment and choose distinct stems for the wrapper and the Zod marker, e.g., `schemaNameListSchema`. +- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`; the `eslint-disable` directive shows the name is fighting the language. Repeating `Schema` for two different concepts in one identifier also forces the reader to disambiguate by position. + +## Observations + +### 26. Wire/TS divergence is heavy +The model file is 229 lines for ~5 user-facing types; >half is `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. + +### 27. Action-verb conventions in `Client` +The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) + +### 28. Acronym casing +The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. +- **Category:** 3 (acronym casing). + +### 29. `dataclassification` lowercase package name +The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). +- **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). + +## Domain glossary +- `uc` / Unity Catalog — implicit across all types (the configured resource is a UC catalog). +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). +- `auto-tagging` / `auto-tag` — automatic application of governance tags to columns classified by the scanner (used both as gerund `AutoTagging` in types and as noun `AutoTag` in field names — see #3). +- `system tag` / `governance tag` — terminology in JSDoc for `classificationTag` (built-in vs. custom class tag keys). +- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. + +## File coverage +- `src/v1/model.ts` (229 lines): read fully. +- `src/v1/client.ts` (181 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md new file mode 100644 index 00000000..300ff267 --- /dev/null +++ b/.agent/naming-audit/dataquality.md @@ -0,0 +1,342 @@ +# Naming Audit: dataquality + +**Path:** `packages/dataquality/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, validity checks (`PercentNull`, `Range`, `Uniqueness`), and notification routing on failure. +**Total weird names flagged:** 52 + +## Summary +| Severity | Count | +| --- | --- | +| High | 14 | +| Medium | 20 | +| Low | 13 | +| Observation | 5 | + +## High severity + +### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` / `listMonitorIter` — `src/v1/model.ts:366,372`, `src/v1/client.ts:316,349` +- **Why weird:** Singular noun on a list operation. A list returns many monitors but the type and method names use the singular `Monitor`. The wire path is `/api/data-quality/v1/monitors` (plural), the response holds `monitors?: Monitor[]`, and the paginator yields a single `Monitor` — every concrete signal says plural; only the type/method name disagrees. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `ListMonitorsRequest` / `ListMonitorsResponse` / `listMonitors` / `listMonitorsIter`. +- **Rationale:** REST conventions, the package's own field naming (`monitors`, `refreshes`), and the URL path all use plural. The singular form here is generator template noise, not intent. Same fix applies to refreshes (#2). + +### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` / `listRefreshIter` — `src/v1/model.ts:378,398`, `src/v1/client.ts:378,411` +- **Why weird:** Same singular-on-list problem as #1. The wire path is `/refreshes` and the response holds `refreshes?: Refresh[]`. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `ListRefreshesRequest` / `ListRefreshesResponse` / `listRefreshes` / `listRefreshesIter`. +- **Rationale:** Internal consistency: every other place in this file uses the plural `refreshes`. Only the type and method name break the pattern. + +### 3. `RefreshState` enum members `MONITOR_REFRESH_STATE_*` — `src/v1/model.ts:80-90` +- **Why weird:** Enum is called `RefreshState`, but every member is prefixed `MONITOR_REFRESH_STATE_` — three levels of redundancy in one token (the enum name says it, the type appears as `state?: RefreshState`, and the value is fully namespaced as `RefreshState.MONITOR_REFRESH_STATE_RUNNING`). Members also include `MONITOR_REFRESH_STATE_UNKNOWN` while every other enum in this file uses `_UNSPECIFIED` — inconsistent sentinel naming. +- **Category:** 2 (redundant enum prefixes), 14 (proto/Go-style names), 17 (inconsistent sentinel — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 18 (overly long enum values). +- **Suggested name:** `RefreshState.{Pending, Running, Success, Failed, Canceled}` and drop the unset sentinel (rely on `state?: RefreshState | undefined`). At minimum, normalise to `REFRESH_STATE_*` (drop `MONITOR_`). +- **Rationale:** The TS enum already namespaces values (`RefreshState.RUNNING`). `MONITOR_` is doubly redundant because the enum is only ever reached from `Refresh.state`, which is owned by a `Monitor`. The `UNKNOWN`/`UNSPECIFIED` inconsistency with `RefreshTrigger.MONITOR_REFRESH_TRIGGER_UNKNOWN` vs `AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_UNSPECIFIED` will trip API users who write `===` checks. + +### 4. `RefreshTrigger` enum members `MONITOR_REFRESH_TRIGGER_*` — `src/v1/model.ts:94-101` +- **Why weird:** Same shape as #3. Six-token names (`MONITOR_REFRESH_TRIGGER_DATA_CHANGE`) where two tokens (`DataChange`) would suffice. Also uses `_UNKNOWN` rather than the more common `_UNSPECIFIED`. +- **Category:** 2 (redundant enum prefix), 14 (proto-style), 17 (sentinel inconsistency), 18 (long enum values). +- **Suggested name:** `RefreshTrigger.{Manual, Schedule, DataChange}`. +- **Rationale:** Same as #3. + +### 5. `AggregationGranularity` enum members `AGGREGATION_GRANULARITY_N_*` — `src/v1/model.ts:8-30` +- **Why weird:** Every value re-states the enum name and then mixes digits with words (`AGGREGATION_GRANULARITY_5_MINUTES`, `AGGREGATION_GRANULARITY_2_WEEKS`). The digit-then-unit form does not map to any TS identifier convention. `_UNSPECIFIED` is the bottom value, so a user must read past it to see `_5_MINUTES` is the smallest real granularity. +- **Category:** 2 (redundant enum prefix), 14 (proto-style), 18 (overly long enum values). +- **Suggested name:** `AggregationGranularity.{FiveMinutes, ThirtyMinutes, OneHour, OneDay, OneWeek, TwoWeeks, ThreeWeeks, FourWeeks, OneMonth, OneYear}` — or, better, drop the numeric quantum entirely and use an ISO-8601 duration string (`PT5M`, `P1D`) so the enum is open to new granularities without code changes. +- **Rationale:** TS enums forbid leading digits in member names, which is why this enum carries the `AGGREGATION_GRANULARITY_` prefix — to make `_5_MINUTES` syntactically legal. That's a tell that the names are working around a language limit. Rename to spelled-out words. + +### 6. `DataProfilingCustomMetricType` enum members — `src/v1/model.ts:49-57` +- **Why weird:** Six tokens per member (`DATA_PROFILING_CUSTOM_METRIC_TYPE_AGGREGATE`). The enum itself is `DataProfilingCustomMetricType` — at the field site you'd write `DataProfilingCustomMetricType.DATA_PROFILING_CUSTOM_METRIC_TYPE_AGGREGATE`, six redundant tokens visible at the call site. +- **Category:** 2 (redundant enum prefix), 14 (proto-style), 18 (long enum values). +- **Suggested name:** `DataProfilingCustomMetricType.{Aggregate, Derived, Drift}`. +- **Rationale:** Same as #3-#5. + +### 7. `CronSchedulePauseStatus` enum + `pauseStatus` field — `src/v1/model.ts:40-46,171` +- **Why weird:** A two-state on/off concept (`UNPAUSED` vs `PAUSED`) modelled as a five-token enum. Also: `pauseStatus` field on `CronSchedule` is read-only (per JSDoc), but nothing in the type marks it as such. The enum's name suggests it answers "what is the pause status?"; a boolean `paused: boolean` would model the same thing in one byte of cognitive load. +- **Category:** 2 (redundant enum prefix), 11 (trivially-enum where boolean suffices), 18 (long enum values), 6 (misleading: field is read-only but typing does not enforce). +- **Suggested name:** Collapse to `paused?: boolean` (output-only). Or rename enum to `PauseStatus.{Paused, Unpaused}`. +- **Rationale:** "Paused" is binary. The five-value `CRON_SCHEDULE_PAUSE_STATUS_*` enum is a protobuf-grade modelling that adds no information over a boolean. Sister packages (`jobs`, `alerts`) already use boolean `paused` fields. + +### 8. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:404-426,406,418` and 6 other request types +- **Why weird:** `objectType` is a free-form `string` typed as the values `"schema"` or `"table"`. The discriminator is implicit in a `string`. The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("It is `schema_id` for `schema`, and `table_id` for `table`"). This is a stringly-typed sum type. Every single request and response in the package copies these two fields verbatim with copy-pasted JSDoc (43 lines of the same boilerplate per type, 6+ types). +- **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). +- **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string} | {kind: 'table', tableId: string}`. Or at minimum, type `objectType: 'schema' | 'table'`. +- **Rationale:** TypeScript's strength is exhaustive discriminated unions. Leaving these as `string` defeats the type system and forces every caller to read the JSDoc. The current copy-paste of the same 40-line doc across `CancelRefreshRequest`, `DeleteMonitorRequest`, `DeleteRefreshRequest`, `GetMonitorRequest`, `GetRefreshRequest`, `ListRefreshRequest`, `Refresh`, `UpdateMonitorRequest`, `UpdateRefreshRequest` is a smoking gun for missing abstraction. + +### 9. `Client` class — `src/v1/client.ts:55` +- **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing two SDK packages (e.g., `@databricks/sdk-dataquality` and `@databricks/sdk-dataclassification`) cannot import both as `Client`. The package name is already in the import path, but in IDE go-to-symbol the name appears unqualified. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). +- **Suggested name:** `DataQualityClient`. +- **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but worth flagging. + +### 10. `DataProfilingConfig.analysisConfig` discriminated-union — `src/v1/model.ts:184-200` +- **Why weird:** A field called `analysisConfig` is a three-arm union of `InferenceLogConfig` / `TimeSeriesConfig` / `SnapshotConfig`. The outer name (`analysisConfig`) and one arm's type (`SnapshotConfig`) end in the same suffix; the discriminator `$case` values are `inferenceLog` / `timeSeries` / `snapshot` — three different naming bases for three different concepts (`InferenceLog`, `TimeSeries`, `Snapshot`). The arm payloads are also `inferenceLog: InferenceLogConfig` (camelCase) — collision-prone with the discriminator string. +- **Category:** 1 (vague — "analysis" vs "config" is the wrong abstraction), 12 (duplicate concept — `Config` appears twice), 17 (inconsistent verb tense — `InferenceLog` is a noun, `TimeSeries` is a noun, but the type name reads `Inference` + `Log` + `Config`). +- **Suggested name:** Field: `analysis`. Type: keep `InferenceLogConfig` etc., or rename to `InferenceLogAnalysis`/`TimeSeriesAnalysis`/`SnapshotAnalysis` and call the field `analysis`. The TS-level discriminator should follow the type name: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. +- **Rationale:** The current pattern forces callers to write `{analysisConfig: {$case: 'inferenceLog', inferenceLog: {...}}}` — three names for one nesting level. Discriminated unions read better when the discriminator value matches the arm payload's key precisely. + +### 11. `DataProfilingConfig.skipBuiltinDashboard` — `src/v1/model.ts:223` +- **Why weird:** Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. Positive form is clearer: `builtinDashboard: false` or `enableBuiltinDashboard: false`. Also: the verb `skip` (sound only on a transient action) does not capture that this is a persistent configuration. +- **Category:** 6 (misleading — looks like a transient flag, is configuration), 13 (verb-tense — `skip` is action, but the field is state). +- **Suggested name:** `disableBuiltinDashboard` (matches the existing negative semantics with a clearer verb), or invert to `createBuiltinDashboard: boolean` (default true). +- **Rationale:** Boolean fields should be named in their positive form unless the negative form is the natural English phrasing. The "skip" prefix is a tell from migrating Go SDK semantics directly. + +### 12. `DataProfilingConfig.assetsDir` — `src/v1/model.ts:182` +- **Why weird:** `assets` is generic and undefined in this context (which assets? the monitor's? the dashboard's? the metric tables'?). `Dir` is an abbreviation. The JSDoc says "absolute path to a custom directory to store data-monitoring assets" — the type should advertise that. +- **Category:** 1 (vague — `assets` of what?), 5 (cryptic abbreviation — `Dir` for `Directory`). +- **Suggested name:** `assetsDirectory`, or better, `dataMonitoringAssetsPath`. +- **Rationale:** Fields holding an absolute path should call out either "path" or "directory" without abbreviation. `assets` alone is too generic for a top-level field on a config that already has `monitoredTableName`, `profileMetricsTableName`, `driftMetricsTableName`, etc. + +### 13. `Refresh.startTimeMs` / `Refresh.endTimeMs` — `src/v1/model.ts:479,481` +- **Why weird:** `Ms` suffix to indicate "milliseconds since epoch", but it ignores the local convention of `Date` and `bigint` for UTC timestamps in modern TS. The field is `number` — JavaScript numbers lose precision beyond 2^53, but milliseconds-since-epoch fits, so the type itself is fine. The `Ms` suffix tells the reader to do arithmetic with `new Date(x)`; meanwhile `creation_time` / `last_updated` elsewhere in the SDK uses `bigint` with explicit precision. Inconsistent unit handling across the SDK. +- **Category:** 5 (cryptic abbreviation — `Ms`), 14 (Go-style suffix — Go SDK uses `int64` with `Ms` everywhere; TS would use `Date`). +- **Suggested name:** Leave on the wire as `start_time_ms` but on the TS side use `startedAt: Date` / `endedAt: Date` (transformed in unmarshal). +- **Rationale:** Idiomatic TS uses `Date` for UTC instants. Forcing every caller to write `new Date(refresh.startTimeMs)` to display a timestamp is a paper cut. Other Databricks SDK packages have moved to this. (Generator-wide concern.) + +### 14. `PercentNullValidityCheck` / `RangeValidityCheck` / `UniquenessValidityCheck` / `ValidityCheckConfiguration` — `src/v1/model.ts:440-501,552` +- **Why weird:** Four sibling types all carry the `ValidityCheck` suffix, but the wrapping discriminated-union container type is `ValidityCheckConfiguration` — adding yet another `Configuration` suffix on top. The wire-style discriminator names (`percentNullValidityCheck`, etc.) re-state the `ValidityCheck` suffix again, four times. Combined, the path `validityCheckConfigurations[0].checkType.$case === 'percentNullValidityCheck'` repeats "validity-check" three times within nine identifier-positions. +- **Category:** 8 (redundant suffix), 20 (type-suffix tautology), 18 (effectively-long enum-like discriminator strings). +- **Suggested name:** Drop `ValidityCheck` from each arm type → `PercentNullCheck` / `RangeCheck` / `UniquenessCheck`. Drop `Configuration` from container → `ValidityCheck` (the container). Discriminator: `kind: 'percentNull' | 'range' | 'uniqueness'`. +- **Rationale:** A `ValidityCheck.kind === 'range'` reads cleanly; the current form is "validity check configuration that has a check type whose case is range validity check" — five repetitions of "check". + +## Medium severity + +### 15. `CancelRefreshResponse.refresh` JSDoc says "The refresh to cancel" — `src/v1/model.ts:144` +- **Why weird:** JSDoc on `CancelRefreshResponse.refresh` says "The refresh to cancel" but this is the response (the refresh that *was* cancelled). The doc verb tense contradicts the type name. Listed as naming because the field's contextual meaning is shaped by stale request-side docs. +- **Category:** 13 (verb tense — "to cancel" is forward-looking; "cancelled" / "the cancelled refresh" is past-tense). +- **Suggested name:** Field stays `refresh`; doc should read "The cancelled refresh." +- **Rationale:** Documentation accuracy. The current text implies user intent rather than response state. + +### 16. `DeleteRefreshRequest` doc-block typo "Request to delete a ronitor." — `src/v1/model.ts:289` +- **Why weird:** Doc string typo "ronitor" (should be "monitor" or "refresh"). Affects discoverability via IDE tooltip search. Plus, the doc text says "monitor" but the type's purpose is deleting a refresh — meta-error. +- **Category:** 6 (misleading — typo invites confusion about the type's purpose). +- **Suggested name:** Doc should read "Request to delete a refresh." +- **Rationale:** Generator-emitted typo. Listed because the doc is the first thing IDE users see. + +### 17. `marshalCancelRefreshRequestSchema` exists but no `marshalCancelRefreshResponseSchema` (and conversely no `unmarshalCancelRefreshRequestSchema`) — `src/v1/model.ts:587,883` +- **Why weird:** Asymmetric coverage: requests get `marshal*` (outbound), responses get `unmarshal*` (inbound). That's correct for HTTP, but the import in `client.ts:38-47` reads as if both directions exist; readers have to mentally fill in the asymmetry. The naming `marshal*Schema` for *one* side and `unmarshal*Schema` for the *other* is not self-documenting unless you already know the convention. +- **Category:** 17 (inconsistent verb pairing — marshal/unmarshal across DTOs). +- **Suggested name:** N/A (rename to `encode*` / `decode*` would help — sister packages have the same problem). +- **Rationale:** Generator-level concern. Listed here because the dataquality package has the largest number of marshal/unmarshal pairs in this audit batch (10 each). + +### 18. `AnomalyDetectionConfig.anomalyDetectionWorkflowId` — `src/v1/model.ts:111` +- **Why weird:** Three repetitions of "anomaly detection" in one field path: `monitor.anomalyDetectionConfig.anomalyDetectionWorkflowId`. The outer type already says "anomaly detection". Inside it, the `workflowId` field could be just `workflowId`. +- **Category:** 7 (overly verbose), 8 (redundant suffix — `anomaly_detection_` inside `AnomalyDetectionConfig`). +- **Suggested name:** `workflowId`. +- **Rationale:** Repeating the parent type name in the field is a Go SDK habit (Go does not have struct-prefix scoping the way nested TS access does). + +### 19. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v1/model.ts:117` +- **Why weird:** "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning ("full" alone is ambiguous — full path? full description?). Other Databricks SDK packages use `fullName` consistently for UC three-part names. +- **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). +- **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or `excludedTableFullyQualifiedNames` for absolute clarity. +- **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary, so the proposal is the *minor* rename to `excludedTables` since the type (string[]) plus parent context (anomaly detection on UC objects) already implies fully-qualified. + +### 20. `DataProfilingConfig.outputSchemaId` vs `monitoredTableName` vs `dashboardId` vs `warehouseId` — `src/v1/model.ts:177,229,243,228` +- **Why weird:** Identifier fields mix three reference styles in one type: `Id` (UC UUIDs: schema, dashboard, warehouse), `FullName` (table), and bare `Name` (output schema is by ID, but `assetsDir` is a path). The user reading `DataProfilingConfig` must remember that to set the *target* of the monitor you use `monitoredTableName` (a three-part name) but to set the *destination* of the metric tables you use `outputSchemaId` (a UUID). The pattern is wire-driven, not user-led. +- **Category:** 17 (inconsistent reference styles), 19 (underspecified IDs — `outputSchemaId` is a UUID but `monitoredTableName` is a three-part qualified name). +- **Suggested name:** Document both clearly in the JSDoc; consider a normalised pair `outputSchema: {id?: string, fullName?: string}` and `monitoredTable: {fullName: string}`. Or rename `monitoredTableName` to `monitoredTableFullName` (matches the JSDoc). +- **Rationale:** UC has a stable convention: `*FullName` for three-part references, `*Id` for UUIDs. Following that convention everywhere reduces caller errors. + +### 21. `DataProfilingConfig.warehouseId` and `DataProfilingConfig.effectiveWarehouseId` — `src/v1/model.ts:228,251` +- **Why weird:** Two parallel fields: user-provided `warehouseId` (optional input — falls back to "the first running warehouse" per doc) and `effectiveWarehouseId` (the warehouse actually used). Same shape as `dataclassification.autoTagConfigs` vs `effectiveAutoTagConfigs` (audited finding #6 in that package). The "effective" prefix is not marked output-only; a caller can set `effectiveWarehouseId` thinking it overrides `warehouseId`. Also: `effectiveWarehouseId` has no JSDoc trailer period ("The warehouse for dashboard creation" — missing period). +- **Category:** 1 (vague — "effective" undermarked), 6 (misleading — output-only not enforced by typing), and (style nit) missing period. +- **Suggested name:** Mark with JSDoc `@readonly`; or rename to `resolvedWarehouseId`. The minor doc-style miss (no period) is a CLAUDE.md rule violation: "Comments should always be proper sentences ending with a period." +- **Rationale:** Same pattern as the `effective*` audit findings in other packages. Output-only state should be visually distinct from input state. + +### 22. `DataProfilingConfig.monitoredTableName` — `src/v1/model.ts:230` +- **Why weird:** Half-redundant. `DataProfilingConfig` is a per-table config; the table being configured is "the monitored table". JSDoc says "Format: `catalog.schema.table_name`" — confirming this is a UC three-part name. Calling it `monitoredTableName` is fine, but it's the only "monitored" field on the type, so the prefix gives little signal. Compare with `Monitor.objectId` which holds the same data conceptually. +- **Category:** 1 (vague modifier — `monitored` adds nothing), 7 (overly verbose). +- **Suggested name:** `tableFullName` (or rely on `Monitor.objectId` and remove the duplicate field entirely). +- **Rationale:** The package already carries the target identity on `Monitor.objectId`. Duplicating it inside the config is a wire artifact, not a TS-level design choice. + +### 23. `DataProfilingConfig.latestMonitorFailureMessage` — `src/v1/model.ts:234` +- **Why weird:** Five-word field name on a type whose name is `DataProfilingConfig` — "latest" + "monitor" + "failure" + "message" + field is on `Monitor`. "Monitor" appears in the path: `monitor.dataProfilingConfig.latestMonitorFailureMessage`. +- **Category:** 7 (overly verbose), 8 (redundant suffix — `Monitor` is in the access path). +- **Suggested name:** `latestFailureMessage`. +- **Rationale:** Field path already gives the Monitor context; the field's own name should drop it. + +### 24. `DataProfilingConfig.profileMetricsTableName` / `driftMetricsTableName` — `src/v1/model.ts:236,238` +- **Why weird:** A pair where one is "profile metrics" and the other is "drift metrics", but the JSDoc is identical down to the punctuation ("Table that stores [profile|drift] metrics data. Format: `catalog.schema.table_name`."). The only diff between the field names is the leading noun, but the type name `DataProfilingConfig` already says "profiling" — so `profileMetricsTableName` reads slightly redundant. +- **Category:** 7 (overly verbose), 17 (inconsistent — drop "profile" prefix to match `driftMetricsTableName` shape, or add a profile/drift prefix universally). +- **Suggested name:** `profileMetricsTable` + `driftMetricsTable` (drop `Name` since wire is the same, and the type itself names a wire reference). +- **Rationale:** Consistent prefixing within a paired feature. Listed medium because the rename is risky for back-compat reasons. + +### 25. `DataProfilingConfig.slicingExprs` — `src/v1/model.ts:209` +- **Why weird:** `Exprs` abbreviation. The JSDoc is 8 lines explaining what `slicing_exprs` does; the field name reduces "expressions" to four characters of cryptic shorthand. Mixed-case: would be `slicingExprs` in TS but the wire field is `slicing_exprs` (Python-style). +- **Category:** 5 (cryptic abbreviation — `Exprs` for `Expressions`). +- **Suggested name:** `slicingExpressions` (or, given the doc explains they are "column expressions", `columnSlicingExpressions`). +- **Rationale:** Length is rarely an issue in TS — modern IDEs autocomplete. Cryptic abbreviation, however, costs readability forever. + +### 26. `DataProfilingConfig.customMetrics: DataProfilingCustomMetric[]` — `src/v1/model.ts:211` +- **Why weird:** Type name `DataProfilingCustomMetric` repeats the parent type's prefix (`DataProfiling`). Same field/type-name asymmetry called out in `dataclassification` (autoTag vs AutoTagging). Field `customMetrics` is fine; the type's prefix is the noise. +- **Category:** 7 (overly verbose), 8 (redundant suffix). +- **Suggested name:** `CustomMetric` (drop the `DataProfiling` prefix) — namespace via TS module if needed. +- **Rationale:** Inside the `dataquality` package, "custom metric" can only mean one thing (a profiling metric definition). The `DataProfiling` prefix is dead context. + +### 27. `DataProfilingCustomMetric.outputDataType: string` — `src/v1/model.ts:266` +- **Why weird:** Field name is `outputDataType` and JSDoc says "The output type of the custom metric." — the JSDoc drops `Data`. Field is typed `string`, no enum. Compare with `type: DataProfilingCustomMetricType` which is enum and is the *kind* of metric, not its *data type*. The reader must parse two `type` fields on the same type. +- **Category:** 1 (vague — `outputDataType` vs `type`), 12 (duplicate concept — two `type`s), 17 (inconsistent — one is enum, one is string). +- **Suggested name:** `outputSqlType` (since the value is a SQL type like `DOUBLE`), or `outputColumnType`. +- **Rationale:** Two `type`-like fields on the same struct is a code-smell; making one specifically `Sql` or `Column` removes the ambiguity. + +### 28. `DataProfilingStatus.DATA_PROFILING_STATUS_DELETE_PENDING` — `src/v1/model.ts:64` +- **Why weird:** Five-word enum value with the order "DELETE PENDING" (verb-then-state) — most languages would write `PENDING_DELETE` (state-modified-by-action). Also: this enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately. +- **Category:** 2 (redundant prefix), 12 (duplicate concept — `ERROR` and `FAILED`), 18 (long enum values). +- **Suggested name:** Members: `DataProfilingStatus.{Active, Pending, PendingDelete, Error, Failed}`. Or, if `ERROR`/`FAILED` are truly distinct, document the difference. +- **Rationale:** Sentinel naming conventions and the implicit duplicate of `ERROR`/`FAILED` both make this enum harder to reason about than it should be. + +### 29. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:420,425` +- **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #8). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). +- **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). +- **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). +- **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. + +### 30. `CronSchedule.quartzCronExpression` and `CronSchedule.timezoneId` — `src/v1/model.ts:163,169` +- **Why weird:** Field is qualified with `Quartz` (the scheduling library) leaking implementation detail; users do not need to know the schedule is parsed by Quartz on the server side. `timezoneId` collides with the IANA tz database vocabulary ("timezone ID" is not standard; "IANA timezone name" or just "timezone" is). +- **Category:** 14 (implementation-detail leak — `Quartz` is a Java library reference), 5 (jargon — `timezoneId` vs the JS-standard `timeZone`). +- **Suggested name:** `cronExpression` + `timezone`. +- **Rationale:** The doc already says "Java timezone id"; the field name should be neutral. + +### 31. `unmarshalListMonitorResponseSchema` — `src/v1/model.ts:702` +- **Why weird:** Compound: List + Monitor (singular) + Response + Schema, 35 characters before the equals sign, mirroring the underlying singular-on-list bug from #1. Once #1 is fixed, this becomes `unmarshalListMonitorsResponseSchema`. +- **Category:** 9 (singular/plural mismatch), 7 (overly verbose Zod schema name). +- **Suggested name:** Fix at #1. +- **Rationale:** Compounds amplify the underlying bug. + +### 32. `unmarshalListRefreshResponseSchema` — `src/v1/model.ts:713` +- **Why weird:** Same as #31 for refreshes. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** Fix at #2. +- **Rationale:** Compound name surfaces underlying singular/plural mismatch. + +### 33. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:437` +- **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. Same pattern as `AnomalyDetectionConfig.anomalyDetectionWorkflowId` (#18). The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. +- **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). +- **Suggested name:** Field: `onFailureOrTimeout` (matches doc), or `onFailure` (matches name; update doc). Type: `Destination` (drop the `Notification` prefix since the type is only used here). +- **Rationale:** Field name and JSDoc should agree on whether timeouts are included. + +### 34. `Refresh.message` — `src/v1/model.ts:477` +- **Why weird:** `message` is the most generic possible name on a `Refresh` object. JSDoc clarifies: "An optional message to give insight into the current state of the refresh (e.g. FAILURE messages)" — so this is really an error message or status message, not just any message. +- **Category:** 1 (vague — `message` could be anything), 15 (generic field name). +- **Suggested name:** `statusMessage` or `stateMessage`. +- **Rationale:** Field on a typed object should be self-describing. + +## Low severity + +### 35. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Exported helper that is never called from `client.ts`. The package's two list endpoints handle pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. +- **Category:** 6 (misleading — looks like it's used; isn't). +- **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). +- **Rationale:** Same as `dataclassification` finding #19. + +### 36. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Layering not visible from names; identical to `dataclassification` finding #15. +- **Category:** 1, 12, 17. +- **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). +- **Rationale:** Layering should be readable from the names without opening the source. + +### 37. `buildHttpRequest` — `src/v1/utils.ts:96` +- **Why weird:** Same as `dataclassification` finding #16; "build" suggests builder pattern, the function spreads literals. +- **Category:** 1, 6. +- **Suggested name:** `makeHttpRequest`. +- **Rationale:** "Make" matches the simpler reality. + +### 38. `marshalRequest` and `parseResponse` — `src/v1/utils.ts:113,119` +- **Why weird:** Names imply request/response but the functions work on any payload + schema; identical to `dataclassification` findings #17 and #18. +- **Category:** 1, 6. +- **Suggested name:** `encodeToJson` / `decodeFromJson`. +- **Rationale:** Symmetric verb pair removes the "Request"/"Response" mis-promise. + +### 39. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Identical to `dataclassification` finding #20; "readAll" does not say "drain a stream". +- **Category:** 1, 5. +- **Suggested name:** `drainStream`. +- **Rationale:** Self-describing name for stream draining. + +### 40. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Same as `dataclassification` finding #21; internal context bag called `Options`. +- **Category:** 1, 8. +- **Suggested name:** `HttpCallContext`. +- **Rationale:** Reserve `Options` for user-tunable knobs. + +### 41. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` +- **Why weird:** Same as `dataclassification` finding #22; unspecific noun for a User-Agent identity object. +- **Category:** 1. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Add the missing domain word. + +### 42. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` +- **Why weird:** Same as `dataclassification` finding #24; variable named `call` of type `Call` repeated 11 times across the client. +- **Category:** 1, 12. +- **Suggested name:** `request` (variable) — reserve `Call` for the type. +- **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. + +### 43. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +- **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. +- **Category:** 6. +- **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. +- **Rationale:** Type shape should match runtime requirement. + +### 44. `respBody` vs `resp` — `src/v1/client.ts:101-111, 139-150, 173-184, 220-237, 266-276, 302-312, 335-346, 397-408, 463-474, 501-512` +- **Why weird:** Same as `dataclassification` finding #26; two variables differ by `Body` only. +- **Category:** 5, 17. +- **Suggested name:** `rawBody` + `result`. +- **Rationale:** Distinguish by meaningful nouns. + +### 45. `httpReq` local — `src/v1/client.ts:99, 138, 172, 210, 229, 264, 300, 334, 396, 456, 494` +- **Why weird:** Same as `dataclassification` finding #27. +- **Category:** 5, 12. +- **Suggested name:** `httpRequest` (no abbreviation). +- **Rationale:** Avoid two `req`-rooted identifiers in the same scope. + +### 46. `pageReq` local in `listMonitorIter` / `listRefreshIter` — `src/v1/client.ts:353, 415` +- **Why weird:** Yet another `req` variant in a scope that already has `req: ListMonitorRequest` as the outer parameter, plus `pageReq: ListMonitorRequest` for the mutable copy used per-page. Three layers of `req` (the user's, the per-page mutation, and inside each call the `httpReq`) in one method. +- **Category:** 5 (abbreviated), 12 (duplicate concept). +- **Suggested name:** `pageRequest` (full word), or restructure so only one `req` exists per scope. +- **Rationale:** Pagination wrappers compound abbreviation noise. + +### 47. `marshalAnomalyDetectionConfigSchema` and 18 other `marshal*Schema` / `unmarshal*Schema` names — `src/v1/model.ts:568-863, 865-1146` +- **Why weird:** Generator-emitted Zod schemas all carry the awkward double-`Schema` suffix at the call site (`z.lazy(() => unmarshalRefreshSchema)`) — "lazy unmarshal Refresh Schema" reads as three nouns and an adjective. Same as `dataclassification` finding #13. +- **Category:** 14 (Go-style), 17 (verb-naming mismatch with Zod's own `parse`). +- **Suggested name:** `encodeAnomalyDetectionConfig` / `decodeAnomalyDetectionConfig`. +- **Rationale:** Generator-wide. + +## Observations + +### 48. Heavy boilerplate dominates the file +`model.ts` is 1252 lines for ~16 user-facing types; 575 lines (~46%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. + +### 49. Action verbs in `Client` +The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) + +### 50. Acronym casing +Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. +- **Category:** 3 (acronym casing). + +### 51. Tense / nominalisation drift in enum naming +`AnomalyDetection` (gerund), `DataProfiling` (gerund), `DataClassification` (noun) — at the package boundary the gerund/noun choice tracks the API team's preference. Within `dataquality` the choice is consistent (both gerunds), good. + +### 52. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types +Same shape as the `dataclassification` casing observation (#32 in that package): directory is one collapsed word, types are PascalCase compounded, wire path is kebab. SDK-wide convention question, not local. +- **Category:** 3 (casing inconsistency). + +## Domain glossary +- `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema or UC table). +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask` and `FieldMask`). +- `quartz` — Apache Quartz Scheduler (Java library) — the cron expression dialect used server-side; surfaces as `quartzCronExpression`. +- `inference log` — predictions + labels + (optional) probabilities for a deployed ML model, used to compute drift on inputs and accuracy on outputs. +- `time series` — analysis configuration where rows have a timestamp column and are bucketed by `AggregationGranularity`. +- `snapshot` — analysis configuration with no time dimension; the table is treated as a single snapshot. +- `validity check` — an input-data constraint check (null %, range, uniqueness) applied during anomaly detection. +- `refresh` — a single run of the data-monitoring pipeline; produces metric rows in `profileMetricsTableName` / `driftMetricsTableName`. +- `monitor` — the long-lived configuration entity (one per UC schema or table); contains either an `anomalyDetectionConfig` or a `dataProfilingConfig`. +- `baseline table` — a separate table whose statistics drift is computed against (per `baselineTableName`). +- `profile metrics` / `drift metrics` — two distinct output tables; profile = per-window distribution stats, drift = same stats compared against baseline or the previous window. +- `effective` — server-resolved value of an input field (e.g. `effectiveWarehouseId` is the warehouse chosen when the user left `warehouseId` blank). +- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. + +## File coverage +- `src/v1/model.ts` (1252 lines): read fully. +- `src/v1/client.ts` (515 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (47 lines): read fully. diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md new file mode 100644 index 00000000..107020d3 --- /dev/null +++ b/.agent/naming-audit/disasterrecovery.md @@ -0,0 +1,232 @@ +# Naming Audit: disasterrecovery + +**Path:** `packages/disasterrecovery/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. +**Total weird names flagged:** 32 + +## Summary +| Severity | Count | +| --- | --- | +| High | 9 | +| Medium | 11 | +| Low | 8 | +| Observation | 4 | + +## High severity + +### 1. `FailoverFailoverGroupRequest` — `src/v1/model.ts:91` +- **Why weird:** Stutter: the word `Failover` appears twice in a single type name. Mechanically this is `Request` (`Failover` verb + `FailoverGroup` noun + `Request`), but the result reads as a typo. +- **Category:** 7 (overly verbose), 17 (inconsistency in action-verb naming — every other action type spells out the verb only once since the resource has only one `failover` action). +- **Suggested name:** `FailoverRequest` (the resource is unambiguous in this package) or `TriggerFailoverRequest` (more explicit verb). +- **Rationale:** No other request in the package re-states the resource word inside its verb. The wire path is `…/failover`, so a single `Failover` in the type name is sufficient. + +### 2. `FailoverFailoverGroupRequest_FailoverType` — `src/v1/model.ts:10` +- **Why weird:** Underscore-bearing identifier (proto-style nested enum) **plus** stutter (`Failover` appears three times in one name: type, request, enum). Requires `eslint-disable @typescript-eslint/naming-convention`. +- **Category:** 4 (underscores in TS identifiers), 7 (overly verbose), 14 (proto/Go-style nested-type name). +- **Suggested name:** `FailoverType` at top level (hoist out of the request). With finding #1's rename, the alternative `FailoverRequest_FailoverType` still stutters and still needs an eslint-disable — so hoisting is the right fix. +- **Rationale:** TS namespaces nested enums via module + import path, not by underscore concatenation. The eslint-disable comment on line 9 is a tell that the name is fighting the language. + +### 3. `FailoverFailoverGroupRequest_FailoverType.FAILOVER_TYPE_UNSPECIFIED` / `.FORCED` — `src/v1/model.ts:11-12` +- **Why weird:** (a) `FAILOVER_TYPE_UNSPECIFIED` redundantly re-states the enum name; (b) shipping an `UNSPECIFIED` sentinel is a proto-import — idiomatic TS uses `undefined` for "not set"; (c) the actual content is a single real value (`FORCED`), which makes a two-member enum with one sentinel look like a placeholder. +- **Category:** 2 (redundant enum prefix), 14 (proto-style sentinel), 18 (long enum value). +- **Suggested name:** Drop `UNSPECIFIED`; keep `Forced` (or `Forced | Graceful` if the API ever grows a graceful mode). +- **Rationale:** `failoverType?: FailoverType | undefined` already encodes "not set". Same rationale as the proto enum guidance applied across the SDK. + +### 4. `FailoverGroup_State` — `src/v1/model.ts:17` +- **Why weird:** Underscore-bearing identifier (proto-style nested enum). Required `eslint-disable @typescript-eslint/naming-convention` on line 16. +- **Category:** 4 (underscores in TS identifiers), 14 (proto/Go-style). +- **Suggested name:** `FailoverGroupState` (PascalCase, no underscore). +- **Rationale:** Same as #2. Renaming removes the eslint disable and makes the type discoverable by IDE autocomplete on `FailoverGroupS…`. + +### 5. `FailoverGroup_State.STATE_UNSPECIFIED` — `src/v1/model.ts:18` +- **Why weird:** Redundant `STATE_` prefix on every value; `UNSPECIFIED` sentinel as in #3. The remaining values (`CREATING`, `CREATION_FAILED`, `INITIAL_REPLICATION`, `ACTIVE`, `FAILING_OVER`, `DELETING`, `FAILOVER_FAILED`, `DELETION_FAILED`) are reasonable, but the lone `STATE_UNSPECIFIED` is noise. +- **Category:** 2 (redundant enum prefix), 14 (proto sentinel). +- **Suggested name:** Drop `STATE_UNSPECIFIED`. Keep the rest as-is or rename to PascalCase (`Creating`, `CreationFailed`, …) to match TS-style enum members. +- **Rationale:** Optional `state?: FailoverGroupState` encodes the unset case. PascalCase members align with TS conventions while leaving the SCREAMING_SNAKE_CASE wire values intact via the Zod schema. + +### 6. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,317` +- **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`, `listStableUrlsIter`. +- **Category:** 3 (acronym casing inconsistency). +- **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. +- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #31 — same issue applies in `utils.ts` field `url` on `StableUrl`.) + +### 7. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` +- **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: + - `effectivePrimaryRegion` — current truth; mutated by failover. + - `initialPrimaryRegion` — create-only input; never returned. + - `targetPrimaryRegion` — request-only on `failover` action. + A reader scanning the type sees three identical-looking string fields. Two of them (`initial`, `target`) are write-only — that critical fact is hidden in JSDoc. +- **Category:** 1 (vague — adjectives `effective`/`initial`/`target` carry the entire weight), 15 (generic field name across three different lifecycles), 6 (misleading — type signature gives no hint that `initialPrimaryRegion` is response-stripped). +- **Suggested name:** Consider splitting: keep `primaryRegion` (effective) on `FailoverGroup`; lift `initialPrimaryRegion` into `CreateFailoverGroupRequest` as a sibling of `failoverGroup`; keep `targetPrimaryRegion` on `FailoverFailoverGroupRequest`. If the generator cannot split (since this mirrors a proto with output_only annotations), at minimum mark `initialPrimaryRegion` `@deprecated`-style write-only in JSDoc with a `WRITE-ONLY` tag. +- **Rationale:** The current shape forces the user to read three different paragraphs to learn that the same-typed fields obey three different rules. This is the most user-hostile naming pattern in the file. + +### 8. `replicationPoint: Temporal.Instant` — `src/v1/model.ts:144` +- **Why weird:** `Point` is generic; this is a recovery-point timestamp (the data-loss bound aka RPO marker). The JSDoc says "The latest point in time to which data has been replicated", which is much clearer than the field name. A reader sees `failoverGroup.replicationPoint` and may guess "endpoint of replication" or "destination point". +- **Category:** 1 (vague), 6 (misleading — `Point` suggests a location, not a time). +- **Suggested name:** `replicationLagTime` / `lastReplicatedAt` / `recoveryPointTime` (the last matches Databricks DR docs and the well-known RPO term). +- **Rationale:** Other timestamp fields on the same struct use the `…Time` suffix (`createTime`, `updateTime`). Consistency + clarity in one rename. + +### 9. `replicateWorkspaceAssets` field on `WorkspaceSet` — `src/v1/model.ts:311` +- **Why weird:** Field documented as "Whether to enable control plane DR (notebooks, jobs, clusters, etc.) for this set." The field name says `replicateWorkspaceAssets` but the doc says "control plane DR" — those aren't synonyms. A user looking for "enable CPDR" will not find a `cpdr` field; a user looking for "replicate" will not realise this is the control-plane toggle vs the data-plane (UC) replication elsewhere on the parent. +- **Category:** 6 (misleading — field name and doc disagree), 1 (vague — `workspaceAssets` is undefined jargon). +- **Suggested name:** `enableControlPlaneReplication` (matches doc and matches the implied UCDR/CPDR split), or `replicateControlPlane`. +- **Rationale:** The parent `FailoverGroup` has `unityCatalogAssets` (UC data plane) and this boolean (control plane). Naming them as a matched pair — e.g., `unityCatalogReplication` + `controlPlaneReplication` — would make the symmetry visible. + +## Medium severity + +### 10. `WorkspaceSet.name: string` (resource-name vs human-name ambiguity) — `src/v1/model.ts:301` +- **Why weird:** `name` on `WorkspaceSet` is documented only as "Resource name for this workspace set". `name` on `FailoverGroup` (line 120) is documented as a fully-qualified resource name (`accounts/{account_id}/failover-groups/{failover_group_id}`). `name` on `StableUrl` (line 252) is fully-qualified too. `name` on `LocationMapping` (line 227) is "Resource name for this location". A user can't tell from the field which `name`s are FQ resource names versus simple labels. +- **Category:** 15 (generic field name losing meaning across types), 19 (under-specified identifier). +- **Suggested name:** Where the value is FQ, prefer `resourceName`; where the value is a label, prefer `label` or `displayName`. Failing that, tighten every JSDoc to spell out the wire format like `FailoverGroup.name` does. +- **Rationale:** The package has at least three different meanings for `name`. Searching IDE for `.name` in a `FailoverGroup` chain returns many hits with different semantics. + +### 11. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:269` +- **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 131) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. +- **Category:** 5 (cryptic abbreviation `Uc`), 8 (redundant `Uc` prefix inside Uc context), 17 (inconsistency — `unityCatalog` vs `Uc`). +- **Suggested name:** `Catalog` (or `ReplicatedCatalog`), and field type `catalogs: Catalog[]`. +- **Rationale:** `UcReplicationConfig.catalogs: UcCatalog[]` reads as "UC replication config's UC catalogs" — redundant. The full `unityCatalog` spelling is used adjacent in the file; either propagate that or drop the prefix entirely inside the UC-scoped type. + +### 12. `UcReplicationConfig` — `src/v1/model.ts:275` +- **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). +- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #13). +- **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. + +### 13. `unityCatalogAssets: UcReplicationConfig` — `src/v1/model.ts:131` +- **Why weird:** Field named `unityCatalogAssets` but the type is `UcReplicationConfig`. "Assets" doesn't appear in the type name. The type contains location mappings + catalogs + a workspace-set reference — none of which are commonly called "assets". The sibling `replicateWorkspaceAssets` (line 311) uses "assets" with a completely different meaning (control-plane objects vs Unity Catalog config). +- **Category:** 15 (generic word "assets" used in two different meanings within the file), 20 (type-suffix tautology since the field carries replication config of a `UcReplicationConfig`). +- **Suggested name:** `unityCatalogReplication` or `unityCatalogConfig`. +- **Rationale:** Field name should match the type's purpose; "assets" is a misleading umbrella here. + +### 14. `WorkspaceSet.stableUrlNames: string[]` (with FQ-name semantics) — `src/v1/model.ts:317` +- **Why weird:** Field is `string[]` of fully-qualified resource names (per JSDoc: `accounts/{account_id}/stable-urls/{stable_url_id}`). The name `stableUrlNames` implies a list of `StableUrl` objects' `name` field; the FQ-vs-id semantics are buried in the doc. +- **Category:** 19 (under-specified identifier — strings that are actually FQ resource names), 6 (misleading singular/plural framing — these are references, not names). +- **Suggested name:** `stableUrlRefs` or `stableUrlResourceNames` (matches the FQ semantics explicitly). +- **Rationale:** Other places in the same SDK use `*Ref` or `*ResourceName` for FQ references; `*Names` is ambiguous (Could be display names? Could be IDs?). + +### 15. `dataReplicationWorkspaceSet: string` — `src/v1/model.ts:284` +- **Why weird:** Long compound noun field of type `string`, semantics (a workspace-set reference by name? id? FQ?) hidden in JSDoc. The doc says "The workspace set whose workspaces will be used for data replication of all UC catalogs' underlying storage." — implying the value is a `WorkspaceSet.name`, but again the type is a bare `string`. +- **Category:** 7 (overly verbose), 19 (under-specified id), 6 (string for a typed concept). +- **Suggested name:** `dataReplicationWorkspaceSetName` or `dataReplicationWorkspaceSetRef`. Or split: `dataReplicationWorkspaceSet: { name: string }` for symmetry with the rest of the model. +- **Rationale:** Within `UcReplicationConfig`, `locationMappings` is typed, `catalogs: UcCatalog[]` is typed, but `dataReplicationWorkspaceSet: string` is loose. Inconsistent typing across siblings. + +### 16. `etag` field on multiple types — `src/v1/model.ts:78,106,138` +- **Why weird:** `etag` lowercased. Web/HTTP convention is `ETag` (capital E-Tag, RFC 9110 §8.8.3). The wire format here is `etag` (lowercase, per the Zod schema line 332). Mixed casing across the ecosystem; the lowercase here at least mirrors the wire, but a TS reader might expect `eTag` or `ETag`. +- **Category:** 3 (acronym casing). +- **Suggested name:** Keep `etag` for wire fidelity; document the choice in a top-level comment. (Or use `eTag` if the SDK style guide prefers JS-camelCase for acronyms.) +- **Rationale:** Low-impact but flagged because the audit asks for casing inconsistencies. The Google TS style guide (loaded skill `google-ts-styleguide:ts-style-guide`) generally prefers camelCase for acronyms (so `etag` is actually fine). + +### 17. `validateOnly: boolean` — `src/v1/model.ts:44,59` +- **Why weird:** "ValidateOnly" is a generic flag pattern; doesn't say what is validated or what the side effect of the validation is. Same word used identically on `CreateFailoverGroupRequest` and `CreateStableUrlRequest`. Fine on its own but worth noting: there is no dryRun/preview field elsewhere, so a user familiar with `dryRun: boolean` convention may not search for `validateOnly`. +- **Category:** 1 (vague), 6 (mildly misleading — "validate only" could imply the result is a validation report; here it's a side-effect suppressor). +- **Suggested name:** `dryRun` (industry standard) or keep `validateOnly` with a tighter JSDoc. +- **Rationale:** Two of the four Create-style APIs use this; `dryRun` is the common convention in Kubernetes/many DBR SDKs. + +### 18. `parent` field on `Create*Request` / `List*Request` — `src/v1/model.ts:40,55,173,200` +- **Why weird:** Bare `parent` with format `accounts/{account_id}`. The literal word "parent" requires JSDoc to decode; idiomatic naming would be `account` or `accountId` or `parentResourceName`. +- **Category:** 1 (vague), 19 (under-specified id). +- **Suggested name:** `account` (since the format hard-codes `accounts/{account_id}`) or `parentResourceName`. +- **Rationale:** "Parent" is proto AIP-132 jargon. SDK users speak in domain terms ("the account this group belongs to"). + +### 19. `failoverGroupId` / `stableUrlId` client-provided suffix fields — `src/v1/model.ts:49,64` +- **Why weird:** Field is a client-side hint that becomes part of the resource name; pattern is "if set, server uses it as the trailing identifier". JSDoc on `failoverGroupId` says: "Used to construct the resource name as `{parent}/failover-groups/{failover_group_id}`." Two ids floating around — the FQ `name` (server-formed) and this client suffix — invite confusion. +- **Category:** 19 (under-specified identifier among multiple), 20 (type-suffix tautology — `failoverGroup.Id` in a `CreateFailoverGroupRequest`). +- **Suggested name:** `requestedFailoverGroupId` / `requestedStableUrlId` to make it clear this is a suggestion, not the final resource id. Alternative: `customId` / `userProvidedId`. +- **Rationale:** Once created, the FQ `name` is the canonical reference; `failoverGroupId` is a vestigial input. Names should reflect lifecycle. + +### 20. `Client` class name — `src/v1/client.ts:52` +- **Why weird:** Plain `Client` is the maximally-generic name. Once imported, callers see `import { Client } from '@databricks/sdk-disasterrecovery/v1'` — fine if used qualified, but `new Client()` floating in user code is meaningless. Sibling packages all do the same per generator convention; flagging this once at the package level. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `DisasterRecoveryClient`. (Or rely on import aliases.) +- **Rationale:** Most SDK conventions name the client after the service. The bare `Client` is a generator default and inherits whatever the import alias is. + +## Low severity + +### 21. `marshalFailoverFailoverGroupRequestSchema` — `src/v1/model.ts:457` +- **Why weird:** Stutter inherited from `FailoverFailoverGroupRequest`. Schema name is `marshal` + `FailoverFailoverGroupRequest` + `Schema`, four words and a doubled word. +- **Category:** 7 (overly verbose), 4 (cascaded from #1). +- **Suggested name:** Falls out if `FailoverFailoverGroupRequest` becomes `FailoverRequest`. Result: `marshalFailoverRequestSchema`. +- **Rationale:** Mechanical cascade from finding #1. + +### 22. `unmarshalUcCatalogSchema`, `marshalUcCatalogSchema`, `unmarshalUcReplicationConfigSchema`, `marshalUcReplicationConfigSchema` — `src/v1/model.ts:420,544,428,552` +- **Why weird:** `Uc` prefix in schema names cascades from `UcCatalog` / `UcReplicationConfig`. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** Cascades from #11 and #12 (`unmarshalCatalogSchema`, `unmarshalUnityCatalogReplicationConfigSchema`). +- **Rationale:** Mechanical cascade. + +### 23. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +- **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. +- **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). +- **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). +- **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. + +### 24. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` +- **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. +- **Rationale:** Same as other packages in the audit. Flag once per package. + +### 25. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Either remove the export (generator default) or document why it ships per-package. +- **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. + +### 26. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` / `readStreamToBuffer`. +- **Rationale:** Internal helper. Skip if generated identically across all packages. + +### 27. `parseResponse` vs `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** Inverse operations named with two different verbs (`parse` vs `marshal`). +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` (symmetric pair). +- **Rationale:** Pair-wise consistency aids reading. + +### 28. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + APIError lift). +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). +- **Rationale:** At the call site (`client.ts:104,111`), the two are visually similar; the more descriptive name disambiguates. + +## Observations + +### 29. Wire-format ratio is unusually high +`model.ts` is ~608 lines; of those, ~290 are TS types/enums and the remaining ~320 are marshal/unmarshal/FieldMaskSchema scaffolding. For nine user-facing types this is heavy. Not a naming issue per se but worth raising at the SDK-design level for the same reason flagged in the `abacpolicies` audit. + +### 30. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#23), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. + +### 31. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +Within this package: +- `stableUrl`/`StableUrl` (PascalCase capital-then-lower). +- `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). +- `URLSearchParams` (Web global, ALLCAPS in code). +Three different casings for two acronyms (URL/URI). The Web platform uses `URL` (ALLCAPS) globally; the TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) +- **Category:** 3 (acronym casing). + +### 32. Cryptic acronyms left undefined in the source +The file mentions `UCDR` and `CPDR` in one comment (line 113) and `spog_host` in a URL example (line 256). Of these, only `CPDR` is decoded via a parenthetical ("control plane DR") elsewhere (line 308). `UCDR` and `spog` appear once each with no expansion in the source. A reader without internal Databricks context cannot decode them. This isn't a name-quality issue on a TS identifier, but the comments are part of the user-facing JSDoc surface (they appear in IDE hovers), so flagged here. +- **Category:** 5 (cryptic abbreviation in JSDoc), 14 (internal jargon leak). + +## Domain glossary +- **DR** — Disaster Recovery. Encoded in the package name `disasterrecovery`. Mentioned once in a JSDoc on `replicateWorkspaceAssets` ("control plane DR"). +- **UCDR** — Unity Catalog Disaster Recovery (UC data plane replication). Mentioned in JSDoc at `model.ts:113`. Not present as an identifier. +- **CPDR** — Control Plane Disaster Recovery (notebooks, jobs, clusters, etc.). Mentioned in JSDoc at `model.ts:113,308`. Not present as an identifier — encoded only via `replicateWorkspaceAssets: boolean`. +- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #12). +- **EA** — Early Access / Early Adoption? Mentioned in JSDoc on `WorkspaceSet.workspaceIds` (line 305) as "EA: exactly 2 workspaces (one per region)". Not decoded anywhere in the package. +- **RPO** — Recovery Point Objective. Not explicitly named; `replicationPoint` (line 144) is effectively the RPO marker. +- **RTO** — Recovery Time Objective. Not present in this package. +- **spog** — Single Pane of Glass (Databricks-internal term for the account-level UI host). Referenced once in a comment on `StableUrl.url` (line 256) as ``. No identifier carries the term. +- **etag** — Entity Tag (RFC 9110). Used for optimistic concurrency. Lowercase per wire. +- **FQ** (used in this audit) — Fully-qualified resource name (e.g., `accounts/{account_id}/failover-groups/{failover_group_id}`). +- **wkt** — Well-Known Types (import path `@databricks/sdk-core/wkt`). +- **m2m** / **u2m** / **pat** / **oidc** / **iam** — not encountered in this package. + +## File coverage +- `src/v1/model.ts` (608 lines): read fully. +- `src/v1/client.ts` (419 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (31 lines): read fully. diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md new file mode 100644 index 00000000..402db729 --- /dev/null +++ b/.agent/naming-audit/endpoints.md @@ -0,0 +1,1316 @@ +# Naming Audit: `endpoints` (v1) + +**Package:** `@databricks/sdk-endpoints` +**Path:** `/home/parth.bansal/sdk-js/packages/endpoints/` +**Version audited:** `v1` +**Files audited:** +- `src/v1/model.ts` +- `src/v1/client.ts` +- `src/v1/utils.ts` +- `src/v1/index.ts` + +This audit applies the 20 numbered concern categories from the audit +checklist plus a special section on the package name itself, which is +the single most problematic naming choice in the whole package. Each +finding lists the offending identifier(s), the category number, +severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename +suggestion. Findings are grouped by category. Generator-driven items +(such as the `_State` underscore on proto-style nested enums and the +`marshal`/`unmarshal` schema prefixes) are flagged as `LOW` because +they are codified across the entire generated SDK surface — they +should be fixed at the generator, not by hand-editing this package. + +--- + +## Inventory + +### Package identity + +| Item | Value | +| --------------- | ---------------------------------- | +| Package name | `@databricks/sdk-endpoints` | +| Directory | `packages/endpoints/` | +| Subpath export | `./v1` | +| REST base path | `/api/2.0/vector-search/endpoints` | +| Concept | Vector Search endpoints | + +### Enums (`model.ts`) + +| Name | Members | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| `EndpointType` | `STORAGE_OPTIMIZED`, `STANDARD`, `STANDARD_ON_ORION` | +| `ScalingChangeState` | `SCALING_CHANGE_UNSPECIFIED`, `SCALING_CHANGE_APPLIED`, `SCALING_CHANGE_IN_PROGRESS` | +| `ThroughputChangeRequestState` | `CHANGE_SUCCESS`, `CHANGE_FAILED`, `CHANGE_REACHED_MINIMUM`, `CHANGE_REACHED_MAXIMUM`, `CHANGE_IN_PROGRESS`, `CHANGE_ADJUSTED` | +| `ThroughputPatchStatus` | `PATCH_ACCEPTED`, `PATCH_REJECTED`, `PATCH_FAILED` | +| `EndpointStatus_State` | `PROVISIONING`, `ONLINE`, `OFFLINE`, `RED_STATE`, `YELLOW_STATE`, `DELETED` | + +### Interfaces (`model.ts`) + +`AdjustedThroughputRequest`, `CreateEndpointRequest`, `CustomTag`, +`DeleteEndpointRequest`, `DeleteEndpointResponse`, `Endpoint`, +`EndpointScalingInfo`, `EndpointStatus`, `EndpointThroughputInfo`, +`GetEndpointRequest`, `ListEndpointRequest`, `ListEndpointResponse`, +`PatchEndpointBudgetPolicyRequest`, +`PatchEndpointBudgetPolicyResponse`, `PatchEndpointRequest`, +`PatchEndpointThroughputRequest`, `PatchEndpointThroughputResponse`. + +### Schemas (`model.ts`) + +`unmarshalAdjustedThroughputRequestSchema`, +`unmarshalCustomTagSchema`, +`unmarshalDeleteEndpointResponseSchema`, +`unmarshalEndpointSchema`, +`unmarshalEndpointScalingInfoSchema`, +`unmarshalEndpointStatusSchema`, +`unmarshalEndpointThroughputInfoSchema`, +`unmarshalListEndpointResponseSchema`, +`unmarshalPatchEndpointBudgetPolicyResponseSchema`, +`unmarshalPatchEndpointThroughputResponseSchema`, +`marshalCreateEndpointRequestSchema`, +`marshalPatchEndpointBudgetPolicyRequestSchema`, +`marshalPatchEndpointRequestSchema`, +`marshalPatchEndpointThroughputRequestSchema`. + +### Client methods (`client.ts`) + +`createEndpoint`, `createEndpointWaiter`, `deleteEndpoint`, +`getEndpoint`, `listEndpoint`, `listEndpointIter`, `patchEndpoint`, +`patchEndpointBudgetPolicy`, `patchEndpointThroughput`. + +### Client classes (`client.ts`) + +`Client`, `CreateEndpointWaiter`, `StillRunningError` (private). + +### Utility functions (`utils.ts`) + +`executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, +`parseResponse`, `marshalRequest`, `flattenQueryParams`. + +### Utility types/interfaces (`utils.ts`) + +`HttpCallOptions`. + +--- + +## F0 — Package-level: the word "endpoint" is dangerously overloaded + +This is the single most important finding and applies to every other +finding below. Reproducing it once up front avoids re-stating it in +each category. + +### F0.1 — Package name `@databricks/sdk-endpoints` is ambiguous to the point of being misleading (HIGH, blocking) +- **Where:** `package.json:2`, the directory name + `packages/endpoints/`, every public export, and every type alias. +- **Why flagged:** "Endpoint" is one of the most overloaded nouns in + the Databricks API surface. Concrete evidence from this monorepo: + - `packages/warehouses/src/v1` exports `EndpointSecurityPolicy`, + `EndpointSpotInstancePolicy`, `EndpointState`, `EndpointHealth_Status` + — SQL Warehouses are internally called "endpoints" (and SQL endpoint + is a legacy term for warehouse). + - `packages/modelservingmanagement/src/v1` exports + `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel`, + `InferenceEndpointState_*`, with waiters + `CreateInferenceEndpointWaiter`, + `PutInferenceEndpointConfigWaiter`, etc. — model serving uses + "endpoint" as its primary noun. + - **This** package: vector-search endpoints, evidenced by + `model.ts:78` ("Name of the vector search endpoint"), + `client.ts:86` URL `/api/2.0/vector-search/endpoints`, + `client.ts:118` JSDoc "Delete a vector search endpoint." + An import line `import {Client, Endpoint} from + '@databricks/sdk-endpoints'` gives the reader zero clue which of + the three concepts is being touched. Autocompletion across the + monorepo conflates them. +- **Suggestion:** Rename the package to one of: + - `@databricks/sdk-vectorsearchendpoints` (long, unambiguous, + matches the REST path), or + - `@databricks/sdk-vectorsearch` (short, matches the product + name; the package can hold both endpoints and indexes in + future), or + - `@databricks/sdk-vector-endpoints`. + Pair the rename with `Endpoint` → `VectorSearchEndpoint` in + `model.ts` (see F1.1). This single rename is the highest-leverage + fix in the audit. + +### F0.2 — Directory name lacks any "vector"/"search" qualifier (HIGH) +- **Where:** `/home/parth.bansal/sdk-js/packages/endpoints/`. +- **Why flagged:** Same root cause as F0.1. A monorepo `grep -r + endpoint` over the repo will surface this package alongside the + serving and warehouse packages with no visual differentiation. +- **Suggestion:** Rename to `packages/vectorsearchendpoints/` + (matches `cleanroomtaskruns`, `oauthpublishedapp` flat style) or + `packages/vectorsearch/` if the package will grow. + +### F0.3 — Companion package `indexes` is also under-qualified (LOW, cross-package) +- **Where:** `packages/indexes/` exports `Client`, `MiniVectorIndex`, + `VectorIndex`, `ListVectorIndexResponse`, etc. +- **Why flagged:** "Index" alone is even more generic than "endpoint" + in software. The contents make clear it is vector-search, but the + package name does not. Same fix as F0.1. +- **Suggestion:** Cross-cutting; align with whatever decision is + taken for `endpoints`. + +--- + +## Findings + +### 1. Vague / generic names + +#### F1.1 — `Endpoint` type name (HIGH) +- **Where:** `model.ts:111`, `index.ts:19`, return type of + `createEndpoint`, `getEndpoint`, `patchEndpoint`, items of + `listEndpointIter`. +- **Why flagged:** "Endpoint" alone is one of the most generic nouns + in REST APIs (every URL is an endpoint). Combined with F0, a user + reading `function process(e: Endpoint)` cannot tell whether this + is a vector-search endpoint, a model-serving endpoint, or a SQL + warehouse endpoint. +- **Suggestion:** Rename to `VectorSearchEndpoint`. Mirrors + `modelservingmanagement.InferenceEndpoint` and provides parity + across packages. All sibling type names (`EndpointType`, + `EndpointStatus`, `EndpointThroughputInfo`, `EndpointScalingInfo`) + follow: `VectorSearchEndpointType`, etc. — long, but unambiguous. + +#### F1.2 — `EndpointType` enum, `EndpointStatus` interface (HIGH) +- **Where:** `model.ts:6, 153`; `index.ts:7, 20`. +- **Why flagged:** Same generic-noun problem as F1.1. `Endpoint*` + symbols collide across the monorepo (cf. `warehouses.EndpointState`, + `warehouses.EndpointHealth_Status`, + `modelservingmanagement.InferenceEndpointState_ReadyState`). +- **Suggestion:** Qualify with `VectorSearch` prefix — + `VectorSearchEndpointType`, `VectorSearchEndpointStatus`. Or move + these into a namespace `VectorSearchEndpoint.Status` / + `VectorSearchEndpoint.Type`. + +#### F1.3 — `Client` class name (MEDIUM, cross-cutting) +- **Where:** `client.ts:56`, `index.ts:3`. +- **Why flagged:** Every package in this SDK exports a `Client`. + `import {Client} from '@databricks/sdk-endpoints'` is unqualified + and routinely needs `import {Client as VectorSearchEndpointsClient}` + at the call site. Project-wide pattern. +- **Suggestion:** Keep `Client` and document the per-package + alias convention, or rename to `VectorSearchEndpointsClient` + consistently across packages. Cross-cutting decision. + +#### F1.4 — `name` field everywhere (MEDIUM) +- **Where:** `model.ts:79, 105, 113, 184, 189, 201, 214, 234`; + `client.ts` throughout. +- **Why flagged:** `name` is one of the most generic identifiers + possible. JSDoc explains "Name of the vector search endpoint", but + the field name alone gives no domain hint. Worse, this `name` is + used as the *path-segment identifier* (`/endpoints/${req.name ?? + ''}`) — i.e. it is functionally an ID. Other packages call this + `id`, `pipelineId`, etc. +- **Suggestion:** Either: + - Rename to `endpointName` for self-documentation, or + - Document the dual role in JSDoc on `Endpoint.name`. Note the + `Endpoint` type already has both `name: string` and `id: string` + — see F12.3 / F19.2 for the duplicate-identifier problem. + +#### F1.5 — `req` parameter name on every client method (LOW, Go-ism) +- **Where:** `client.ts:83, 108, 120, 145, 170, 200, 218, 244, 276`. +- **Why flagged:** `req` is a Go-ism (see category 14). It is also + generic — a reader has to look at the type to know what the + request is. +- **Suggestion:** Use `request` for stylistic consistency with + `options` (which is spelled out). See F14.1. + +#### F1.6 — `state` field on `EndpointScalingInfo` and `EndpointStatus` (LOW) +- **Where:** `model.ts:144, 155`. +- **Why flagged:** `state` is generic. Disambiguated by container + type, but `scalingState` / `endpointState` would be clearer in + isolation. +- **Suggestion:** Acceptable as-is given the containing type; leave. + +#### F1.7 — `message` field on `EndpointStatus` and `PatchEndpointThroughputResponse` (LOW) +- **Where:** `model.ts:157, 259`. +- **Why flagged:** Generic. Compare `statusMessage`, + `errorMessage`. +- **Suggestion:** Add JSDoc clarifying purpose; rename optional. + +#### F1.8 — `status` field on `PatchEndpointThroughputResponse` (LOW) +- **Where:** `model.ts:257`. +- **Why flagged:** Field is `status: ThroughputPatchStatus`. Generic + field name typed against a non-generic enum. Reads as "status" with + three layers of "status". +- **Suggestion:** `patchStatus` or `result`. See F20.4. + +#### F1.9 — `Call`, `Options` (imported, cross-package) (acceptable) +- **Where:** `utils.ts:3-5`, `client.ts:4-5`. +- These come from `@databricks/sdk-core/api`. Generic but + intentional. Out of scope for this package's audit. + +--- + +### 2. Redundant enum prefixes + +#### F2.1 — `ScalingChangeState.SCALING_CHANGE_*` (HIGH) +- **Where:** `model.ts:13-17`. + ```ts + export enum ScalingChangeState { + SCALING_CHANGE_UNSPECIFIED = 'SCALING_CHANGE_UNSPECIFIED', + SCALING_CHANGE_APPLIED = 'SCALING_CHANGE_APPLIED', + SCALING_CHANGE_IN_PROGRESS = 'SCALING_CHANGE_IN_PROGRESS', + } + ``` +- **Why flagged:** Every member prefixes `SCALING_CHANGE_` — the + exact enum name. Reads + `ScalingChangeState.SCALING_CHANGE_APPLIED`, which says + "scaling change" twice. Compare `Color.RED_COLOR`. +- **Suggestion:** Drop the prefix on the *TS* identifier; keep the + wire string. The TS-idiomatic shape is: + ```ts + export enum ScalingChangeState { + UNSPECIFIED = 'SCALING_CHANGE_UNSPECIFIED', + APPLIED = 'SCALING_CHANGE_APPLIED', + IN_PROGRESS = 'SCALING_CHANGE_IN_PROGRESS', + } + ``` + Wire compatibility preserved; TS readability massively improved. + Generator-level decision. + +#### F2.2 — `ThroughputChangeRequestState.CHANGE_*` (HIGH) +- **Where:** `model.ts:20-33`. + ```ts + CHANGE_SUCCESS, CHANGE_FAILED, CHANGE_REACHED_MINIMUM, + CHANGE_REACHED_MAXIMUM, CHANGE_IN_PROGRESS, CHANGE_ADJUSTED + ``` +- **Why flagged:** Every member starts with `CHANGE_`. The enum is + `ThroughputChangeRequestState` so `CHANGE_` is redundant. +- **Suggestion:** Same as F2.1 — keep wire strings, strip the + `CHANGE_` prefix on the TS identifier: + `SUCCESS`, `FAILED`, `REACHED_MINIMUM`, `REACHED_MAXIMUM`, + `IN_PROGRESS`, `ADJUSTED`. + +#### F2.3 — `ThroughputPatchStatus.PATCH_*` (HIGH) +- **Where:** `model.ts:36-43`. +- **Why flagged:** `PATCH_ACCEPTED`, `PATCH_REJECTED`, `PATCH_FAILED` + — every member prefixed with `PATCH_`, which is exactly the enum's + domain. Reads `ThroughputPatchStatus.PATCH_ACCEPTED` — + "patch status . patch accepted". +- **Suggestion:** Strip prefix: + `ACCEPTED`, `REJECTED`, `FAILED`. + +#### F2.4 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` (MEDIUM) +- **Where:** `model.ts:57-58`. +- **Why flagged:** `_STATE` is redundant — the enum is already + `EndpointStatus_State`. Reads `EndpointStatus_State.RED_STATE` — + "endpoint status state . red state". Other members in the same + enum (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not + carry the suffix; so this is also inconsistent within the enum. +- **Suggestion:** Wire strings are `RED_STATE` / `YELLOW_STATE`, so + parity needs the suffix. If the wire allows, rename to `RED` / + `YELLOW`. Otherwise, document the asymmetry. Worth fixing at the + spec level. + +#### F2.5 — `EndpointType.STANDARD_ON_ORION` (LOW) +- **Where:** `model.ts:10`. +- **Why flagged:** Not technically redundant, but `ON_ORION` is an + implementation-leak — the enum should describe *what the user + sees*, not *which infra backs it*. See F6.x. +- **Suggestion:** Discussed in F6.4. + +--- + +### 3. Acronym casing inconsistencies + +#### F3.1 — `Id` vs `ID` (acceptable, cross-cutting) +- **Where:** `model.ts:125, 131, 133, 199, 203, 207, 209`. +- **Why flagged:** Field uses `id`, `budgetPolicyId`, + `effectiveBudgetPolicyId`, `usagePolicyId` — consistent lower-camel + `Id`. This matches the SDK-wide convention. +- **Suggestion:** No change. + +#### F3.2 — `QPS` rendered as `Qps` (HIGH) +- **Where:** + - `CreateEndpointRequest.targetQps` (`model.ts:93`) + - `EndpointScalingInfo.requestedTargetQps` (`model.ts:149`) + - `PatchEndpointRequest.targetQps` (`model.ts:229`) +- **Why flagged:** "QPS" (queries per second) is a TLA. The SDK + applies "first letter cap, rest lower" for camelCase — so `Qps` + here. But the wire form is `target_qps` (all-lower), Go SDK uses + `TargetQps`, the JSDoc and comments mix "QPS" (uppercase) and + "qps". This SDK has a precedent: `URL`/`url` is lowercase, + `HTTP`/`http` matches casing context (`HttpClient`, `HttpRequest`), + `id` is lowercase. So `Qps` is consistent with `Http`/`Url` + casing for acronyms; flag is only against the JSDoc/comment mix. +- **Suggestion:** Standardize comments to use `QPS` consistently when + the prose is talking about the term, and `targetQps` for the TS + identifier. Or rename to `targetQueriesPerSecond` (verbose but + self-documenting). See also F5.x. + +#### F3.3 — `CPU` rendered in JSDoc as "(total CPU)" (acceptable) +- **Where:** `model.ts:69, 162, 165, 235`. +- JSDoc only; no identifier impact. Fine. + +#### F3.4 — `URL` / `Url` (acceptable for this file) +- `client.ts:86, 123, 148, 174, 179, 221, 247, 279` uses lowercase + `url` consistently. No casing inconsistency. + +--- + +### 4. Underscores in TS identifiers + +> The TypeScript style guide (Google) and the SDK's own +> `typescript.mdc` disallow `snake_case` and underscores in +> identifiers. The generator emits proto-style "outer_inner" names +> as `Outer_Inner` to disambiguate nested messages. + +#### F4.1 — `EndpointStatus_State` enum (HIGH, generator concern) +- **Where:** `model.ts:46-65`, `client.ts:36, 335, 338, 376, 377`, + `index.ts:10`. + ```ts + // eslint-disable-next-line @typescript-eslint/naming-convention -- + // Proto-style nested enum name. + export enum EndpointStatus_State { … } + ``` +- **Why flagged:** Requires an `eslint-disable-next-line` to compile — + always a smell. The TS-idiomatic equivalents are namespace nesting + (`namespace EndpointStatus { export enum State { … } }`) or flat + PascalCase (`EndpointStatusState`). +- **Suggestion:** Drop the underscore at the generator level. Two + viable shapes: + 1. Flat PascalCase — `EndpointStatusState`. + 2. Namespace nesting — `EndpointStatus.State`. + With the F1.2 rename, this becomes `VectorSearchEndpointStatusState` + (long) or `VectorSearchEndpointStatus.State` (cleaner). + +#### F4.2 — Schema names contain `_` indirectly (LOW) +- **Where:** No `_` in this package's schema names (it has no + `*_Response`/`*_State` schemas other than the enum above). This + package is lighter on the underscore problem than `budgets`. + +--- + +### 5. Cryptic abbreviations + +#### F5.1 — `req` (LOW, Go-ism) +- **Where:** `client.ts:83, 108, 120, 145, 170, 200, 218, 244, 276`, + `client.ts:202, 212`. +- **Why flagged:** Already flagged under F1.5 / F14.1. + +#### F5.2 — `resp` / `respBody` (LOW, Go-ism) +- **Where:** `client.ts:88, 93, 98, 101, 124, 128, 134, 137, 149, + 154, 159, 162, 180, 184, 190, 193, 205, 209, 223, 228, 233, 236, + 252, 257, 262, 268, 280, 285, 289, 294, 300, 322, 363, 370`. +- **Why flagged:** `response` is two extra characters and unambiguous. +- **Suggestion:** `response`, `responseBody`. + +#### F5.3 — `pollResp` (LOW) +- **Where:** `client.ts:322, 329, 339, 363, 370`. +- **Why flagged:** Same `resp` Go-ism inside the waiter. +- **Suggestion:** `pollResponse`. + +#### F5.4 — `httpReq` (LOW) +- **Where:** `client.ts:92, 128, 153, 184, 227, 256, 288`. +- **Why flagged:** `httpRequest` is clearer and matches the type + `HttpRequest` exactly. +- **Suggestion:** `httpRequest`. + +#### F5.5 — `apiErr` (LOW) +- **Where:** `utils.ts:88-91`. +- **Why flagged:** `apiError` reads better; "err" is a Go-ism. +- **Suggestion:** `apiError`. + +#### F5.6 — `pkgJson` (LOW) +- **Where:** `client.ts:20, 50-52`. +- **Why flagged:** "pkg" abbreviation. `packageJson` is two extra + characters and unambiguous. +- **Suggestion:** `packageJson`. + +#### F5.7 — `msg` (LOW) +- **Where:** `client.ts:339-340`. + ```ts + const msg = pollResp.endpointStatus?.message ?? '(no message)'; + throw new Error(`terminal state ${status}: ${msg}`); + ``` +- **Why flagged:** `message` is the source field name. Inlining + `pollResp.endpointStatus?.message` is also acceptable. +- **Suggestion:** `message` or inline. + +#### F5.8 — `acc`, `val`, `opts`, `e` (LOW) +- **Where:** `utils.ts:55, 137, 30, 65-92, 76`. +- **Why flagged:** Same as in `budgets` audit (F5.7 there). + - `acc` in reduce — conventional. OK. + - `val` in destructure — OK. + - `opts` — Go-ism but widely used in JS libs. + **Inconsistent within the package:** parameter is `options` in + `executeCall` (utils.ts:28), but `opts` inside `executeHttpCall` + (utils.ts:67-92). + - `e` for caught exception — TS guidance permits `e`/`err`/`error`; + inconsistent with `apiErr` (which spells out `err`). +- **Suggestion:** Rename `opts → options` inside `executeHttpCall` + for consistency; leave `acc`, `val`, `e` alone. + +#### F5.9 — `info` in `client.ts:71-77` (LOW) +- **Where:** `client.ts:71-77`. + ```ts + let info = createDefault().with(PACKAGE_SEGMENT); + ``` +- **Why flagged:** Generic; reads as "info about what?". Context tells + the reader it is the User-Agent builder, but the name is content-free. +- **Suggestion:** `userAgentInfo` or `clientInfo` (matches the + imported `createDefault` from `@databricks/sdk-core/clientinfo`). + +#### F5.10 — `qps` (LOW) +- See F3.2. + +--- + +### 6. Misleading names + +#### F6.1 — `Endpoint.name` is functionally the primary key (HIGH) +- **Where:** `model.ts:113`. +- **Why flagged:** The field is described as "Name of the vector + search endpoint" but used as the path-segment identifier in + `getEndpoint`, `deleteEndpoint`, `patchEndpoint`, etc. + (`client.ts:123, 148, 221, 247, 279`). Also, `Endpoint` has both + `name` and `id` (line 125), with `id` documented as "Unique + identifier of the endpoint" — so the type has *two* identifiers + and only one of them ever shows up in URLs. +- **Suggestion:** Document explicitly: "Used as the primary + identifier in API paths." Or rename `name → endpointName` (still + generic) or `name → key` (more explicit). Also clarify in JSDoc + that `name` is the URL-safe identifier and `id` is the opaque GUID. + See F12.3 / F19.2. + +#### F6.2 — `numIndexes` reads as "number of *array* indexes" (MEDIUM) +- **Where:** `model.ts:129`. +- **Why flagged:** In TS, "index" almost universally means a numeric + position in an array. Here it means "number of vector-search + indexes attached to this endpoint" — a domain term, not the + data-structure term. +- **Suggestion:** Rename `numIndexes → numVectorIndexes` (matches + `MiniVectorIndex` / `VectorIndex` in the sibling `indexes` + package). Even better: pluralize naturally, `vectorIndexCount`. + +#### F6.3 — `EndpointStatus_State.OFFLINE` as a *terminal failure* state (HIGH) +- **Where:** `model.ts:50`, `client.ts:338-341, 376-380`. + ```ts + case EndpointStatus_State.OFFLINE: { + const msg = pollResp.endpointStatus?.message ?? '(no message)'; + throw new Error(`terminal state ${status}: ${msg}`); + } + ``` +- **Why flagged:** The waiter treats `OFFLINE` as a *terminal failure* + (throws), but the enum name "OFFLINE" suggests a transient state + ("the endpoint is currently offline"). This is misleading: a + reader sees `OFFLINE` and expects it might come back online; the + client treats it as terminal. +- **Suggestion:** If the wire allows, rename to `FAILED` (semantic + intent) or `TERMINATED`. Otherwise add a prominent JSDoc note on + the enum value explaining the waiter contract. + +#### F6.4 — `EndpointType.STANDARD_ON_ORION` leaks infra implementation (MEDIUM) +- **Where:** `model.ts:9-10`. +- **Why flagged:** "Orion" is an internal Databricks infrastructure + name; the JSDoc says "Standard endpoint backed by Orion + infrastructure with endpoint-scoped reconciliation." This is a + *user-visible* enum value that exposes internal architecture. If + Orion is renamed, this enum value cannot change without breaking + callers. +- **Suggestion:** Wire-protocol value; cannot rename in TS. Flag for + upstream API redesign — public enum members should describe user + semantics (e.g. `STANDARD_V2`), not internal infra. + +#### F6.5 — `minimalConcurrencyAllowed` vs "minimum concurrency" in JSDoc (LOW) +- **Where:** `model.ts:71-72, 168-169, 237-238`. +- **Why flagged:** Field uses `minimal` but the JSDoc says + "minimum". `minimal` is a different word — "the least possible" + vs `minimum` "the lower bound". For a lower-bound limit + `minimumConcurrencyAllowed` is the correct English word; "minimal + concurrency" suggests "barely any concurrency". +- **Suggestion:** Rename `minimalConcurrencyAllowed → + minimumConcurrencyAllowed`. Wire field is `minimal_concurrency_allowed` + (model.ts:271, 356) — needs a generator-level fix or remapping in + the marshaller. + +#### F6.6 — `Endpoint.creator` is a user *identifier*, not the user (LOW) +- **Where:** `model.ts:115`. JSDoc: "Creator of the endpoint". +- **Why flagged:** "Creator" suggests a `User` object; the field type + is `string`. Compare `lastUpdatedUser` (also `string`). +- **Suggestion:** `creatorUserName` or `creatorEmail`, depending on + what the wire returns. Or `createdBy` (matches REST convention). + +#### F6.7 — `lastUpdatedUser` vs `creator` asymmetry (LOW) +- **Where:** `model.ts:115, 123`. +- **Why flagged:** Two fields, both `string`, both identify a user, + with different naming patterns: `creator` (noun) vs + `lastUpdatedUser` (compound). Inconsistent. +- **Suggestion:** `createdBy` and `updatedBy` (matches REST common + practice) or `creator` and `lastUpdater`. Pick one form. + +#### F6.8 — `flattenQueryParams` is exported but unused in this package (LOW) +- **Where:** `utils.ts:123-150`. +- **Why flagged:** The package's only list endpoint uses + `URLSearchParams.append` directly (`client.ts:175-177`). The + helper is dead in this package — same finding as in the `budgets` + audit. +- **Suggestion:** Move shared helpers to `@databricks/sdk-core` or + delete from per-package `utils.ts`. Cross-cutting. + +#### F6.9 — JSDoc `"Update an endpoint"` on `patchEndpoint` lacks the verb match (LOW) +- **Where:** `client.ts:216`. +- **Why flagged:** JSDoc says "Update", the method is `patchEndpoint`. + Inconsistent verb. (See F17.1.) +- **Suggestion:** Either rename the method or rewrite the JSDoc: + "Patch an endpoint to update mutable fields." + +--- + +### 7. Overly verbose + +#### F7.1 — `Endpoint` *would* be fine — but combined with package + rename, becomes `VectorSearchEndpoint` (HIGH) +- **Where:** `model.ts:111`, `index.ts:19`. +- **Why flagged:** Today `Endpoint` is too generic (F1.1). After the + F0/F1 rename it becomes `VectorSearchEndpoint` — long but + necessary. Worth noting as a deliberate tradeoff, not a bug. +- **Suggestion:** Accept the verbosity; mitigate by aliasing at + import sites where appropriate. + +#### F7.2 — `PatchEndpointBudgetPolicyRequest`, + `PatchEndpointBudgetPolicyResponse` (HIGH) +- **Where:** `model.ts:199, 206`, `index.ts:26-27`. +- **Why flagged:** 32+ characters. Inside a method literally named + `patchEndpointBudgetPolicy(...)`, the request type repeats every + token. Compare typical TS SDK shape: + `endpoint.patchBudgetPolicy(req: PatchBudgetPolicyRequest)`. +- **Suggestion:** With F0/F1 rename, drop the redundant `Endpoint` + token. The method belongs to a vector-search-endpoint client, so + `PatchBudgetPolicyRequest` / `PatchBudgetPolicyResponse` is enough. + +#### F7.3 — `PatchEndpointThroughputRequest`, + `PatchEndpointThroughputResponse` (HIGH) +- **Where:** `model.ts:232, 255`, `index.ts:28-30`. +- **Why flagged:** Same as F7.2. +- **Suggestion:** `PatchThroughputRequest` / + `PatchThroughputResponse`. + +#### F7.4 — Method names: `patchEndpointBudgetPolicy`, + `patchEndpointThroughput`, `createEndpoint`, `deleteEndpoint`, + `getEndpoint`, `listEndpoint`, `patchEndpoint` (MEDIUM) +- **Where:** `client.ts:82, 119, 144, 169, 217, 243, 275`. +- **Why flagged:** "Endpoint" repeats in every method name. The + containing class is *already* the endpoints client (or will be + after F0 rename — `VectorSearchEndpointsClient`). Compare typical + TS SDK shape: `endpoints.create(...)`, `endpoints.patchBudgetPolicy(...)`. +- **Suggestion:** `create`, `delete`, `get`, `list`, `listIter`, + `patch`, `patchBudgetPolicy`, `patchThroughput`. Cross-package + convention. + +#### F7.5 — `currentConcurrencyUtilizationPercentage` (HIGH) +- **Where:** `model.ts:166-167`, `model.ts:355, 366`. +- **Why flagged:** 39 characters. Three concept tokens + (concurrency + utilization + percentage). The "percentage" can be + inferred from the JSDoc unit (0-100). +- **Suggestion:** `concurrencyUtilization` plus JSDoc that documents + the unit. Or `concurrencyUtilizationPct` if the abbreviated form + is preferred. + +#### F7.6 — `EndpointThroughputInfo`, `EndpointScalingInfo` (LOW) +- **Where:** `model.ts:142, 161`. +- **Why flagged:** `Info` suffix is a generic filler word. The types + describe throughput state and scaling state, respectively. +- **Suggestion:** `EndpointThroughput`, `EndpointScaling`. Or align + with `EndpointStatus` (already there, no `Info`). + +#### F7.7 — `createEndpointWaiter` method (MEDIUM) +- **Where:** `client.ts:107-116`. +- **Why flagged:** This method is `createEndpoint` + return-a-waiter. + All sibling SDKs (`warehouses`, `modelservingmanagement`) export + the waiter as a separate type and the create method returns it + directly. Reads as `client.createEndpoint(...)` returning an + `Endpoint`, then a second method `createEndpointWaiter(...)` + returning a `CreateEndpointWaiter`. Two methods for one operation. +- **Suggestion:** Either: + - Make `createEndpoint` return the waiter directly (breaking + change), or + - Rename to `createEndpointAndWait` (verbose but explicit), or + - Inline the polling into `createEndpoint` and remove the waiter + type entirely. + See F17.5. + +#### F7.8 — `listEndpointIter` (MEDIUM) +- **Where:** `client.ts:199-214`. +- **Why flagged:** `Iter` suffix is Go-style; in TS the idiomatic + alternative is an async iterator method + (`[Symbol.asyncIterator]`) or a name like `listAll` / + `streamEndpoints`. +- **Suggestion:** Tied to F17.4: `listIter` (drop the singular + `Endpoint`) or `iterate` / `stream` / `listAll`. Cross-package. + +#### F7.9 — `STILL_RUNNING` / `StillRunningError` (LOW) +- **Where:** `client.ts:54`. +- **Why flagged:** Private error class used as a control-flow signal + for `retryOn`. Three concepts in one name ("still" + "running" + + "error"). It is essentially "not yet done". +- **Suggestion:** Acceptable as-is; alternative + `RetryablePendingError` or `NotYetDoneError`. + +--- + +### 8. Redundant suffixes + +#### F8.1 — `Request` / `Response` suffixes (LOW, conventional) +- **Where:** All request/response types. +- **Why flagged:** Conventional in this SDK. Note: this package + does NOT have the `_Response` underscore problem the `budgets` + package has — names are flat (`CreateEndpointRequest`, + `DeleteEndpointResponse`). Good. +- **Suggestion:** No change. + +#### F8.2 — `EndpointType` enum tautology (LOW) +- **Where:** `model.ts:6`, `Endpoint.endpointType: EndpointType` + (`model.ts:121`). +- **Why flagged:** Three layers of "endpoint": `Endpoint` has a + field `endpointType` typed as `EndpointType`. Reads as + `endpoint.endpointType : EndpointType`. +- **Suggestion:** Rename field `endpointType → type` (loses one + redundancy, becomes `endpoint.type : EndpointType`). Wire field + is `endpoint_type` (`model.ts:299, 424`), so a remap is needed. + See F20.1. + +#### F8.3 — `EndpointStatus` interface + `endpointStatus` field on `Endpoint` (LOW) +- **Where:** `model.ts:127, 153`. +- **Why flagged:** Same pattern as F8.2: + `endpoint.endpointStatus : EndpointStatus`. +- **Suggestion:** Rename field `endpointStatus → status`. Wire field + is `endpoint_status` — generator-level remap. + +#### F8.4 — `EndpointThroughputInfo` / `EndpointScalingInfo` `Info` suffix (LOW) +- See F7.6. + +#### F8.5 — `ThroughputChangeRequestState` (LOW) +- **Where:** `model.ts:20`. +- **Why flagged:** `Throughput` + `Change` + `Request` + `State` — + four concept tokens. `RequestState` is partially redundant with + `ChangeRequestState`. +- **Suggestion:** `ThroughputChangeState` (3 tokens) is enough. + +--- + +### 9. Singular / plural mismatches + +#### F9.1 — `listEndpoint` method singular for a collection (HIGH) +- **Where:** `client.ts:169`. +- **Why flagged:** Method returns `ListEndpointResponse` whose + `endpoints` field is `Endpoint[]`. The method should be + `listEndpoints` (plural). Same applies to its iterator and + request type: `listEndpointIter` should be `listEndpointsIter`, + `ListEndpointRequest` should be `ListEndpointsRequest`, + `ListEndpointResponse` should be `ListEndpointsResponse`. +- **Suggestion:** Pluralize throughout. The wire path is + `/api/2.0/vector-search/endpoints` — plural — so this is also + consistent with the URL. + +#### F9.2 — `ListEndpointRequest` / `ListEndpointResponse` types (HIGH) +- **Where:** `model.ts:187, 192`. +- See F9.1. + +#### F9.3 — `Endpoint.numIndexes` plural (acceptable) +- **Where:** `model.ts:129`. +- Plural is correct for a count of indexes. + +#### F9.4 — `Endpoint.customTags: CustomTag[]` plural (acceptable) +- **Where:** `model.ts:135`. +- Plural is correct for an array. + +#### F9.5 — `CreateEndpointRequest.numReplicas` vs + `PatchEndpointThroughputRequest.numReplicas` vs + `EndpointThroughputInfo.requestedNumReplicas` / + `currentNumReplicas` (acceptable) +- **Where:** `model.ts:87, 252, 177, 179`. +- Consistent use of `numReplicas` (plural) as a count. + +--- + +### 10. Reserved-word / built-in collisions + +#### F10.1 — `delete` method name (LOW) +- **Where:** `client.ts:119` (`deleteEndpoint`). +- **Why flagged:** TS allows `delete` as method name. `deleteEndpoint` + is unambiguous; flag would apply only if F7.4 renames it to bare + `delete` (then it would shadow the `delete` keyword visually but is + still legal). +- **Suggestion:** Acceptable; relevant only if F7.4 is applied. + +#### F10.2 — `status` field (LOW) +- **Where:** `model.ts:257`. +- **Why flagged:** `Response.status` collides with `Response.status` + in the Fetch API. Mild shadowing concern in code review. +- **Suggestion:** See F1.8. + +#### F10.3 — `state` field (LOW) +- **Where:** `model.ts:144, 155`. +- **Why flagged:** No reserved-word collision. `state` is a popular + React/Redux concept, but that is library-level not language-level. +- **Suggestion:** Acceptable. + +#### F10.4 — `Headers`, `URLSearchParams`, `TextDecoder`, + `AbortSignal`, `Promise`, `ReadableStream` (acceptable) +- **Where:** `client.ts`, `utils.ts`. +- Used as global classes; no shadowing. + +#### F10.5 — `Error`, `RangeError`, etc. (acceptable) +- `throw new Error(...)` is correct usage. No collision. + +--- + +### 11. Empty / trivial wrapper types + +#### F11.1 — `AdjustedThroughputRequest` exposed as a *response* + payload (MEDIUM) +- **Where:** `model.ts:68-75, 264`. +- **Why flagged:** Type name says "Request" (line 67 JSDoc: + "Adjusted throughput request parameters") but it appears in a + response field: `PatchEndpointThroughputResponse.adjustedRequest` + (line 264). This is OK semantically — it's the *request that was + applied after adjustment* — but a reader sees `AdjustedThroughputRequest` + in a *response* and double-takes. Borderline misleading. +- **Suggestion:** Either: + - Rename to `AdjustedThroughputParameters` (drop "Request"), or + - Rename to `AppliedThroughputAdjustment` (explicit), or + - Document the dual role prominently in JSDoc. + +--- + +### 12. Duplicate concepts + +#### F12.1 — `numReplicas` in three different places (HIGH) +- **Where:** + - `CreateEndpointRequest.numReplicas` (`model.ts:87`) + - `PatchEndpointThroughputRequest.numReplicas` (`model.ts:252`) + - `EndpointThroughputInfo.requestedNumReplicas` (`model.ts:177`) + - `EndpointThroughputInfo.currentNumReplicas` (`model.ts:179`) +- **Why flagged:** Same conceptual field, different names depending + on context. `numReplicas` on create vs `requestedNumReplicas` + in info vs `currentNumReplicas` in info. The asymmetry is + intentional (request vs current vs target), but the naming pattern + is inconsistent — see F12.2. +- **Suggestion:** Standardize: input fields stay `numReplicas`; + state fields become `requestedReplicas` / `currentReplicas` (drop + the `Num` — see F14.x). + +#### F12.2 — `targetQps`, `requestedTargetQps`, + `replicationFactor`, `numReplicas` describe overlapping concepts (HIGH) +- **Where:** + - `CreateEndpointRequest.targetQps` (`model.ts:93`) + - `PatchEndpointRequest.replicationFactor` (`model.ts:224`) + - `PatchEndpointRequest.targetQps` (`model.ts:229`) + - `PatchEndpointThroughputRequest.numReplicas` (`model.ts:252`) + - `EndpointScalingInfo.requestedTargetQps` (`model.ts:149`) +- **Why flagged:** Three different ways to express how big the + endpoint should be: + - `targetQps` (queries per second; high-level intent) + - `replicationFactor` (low-level OpenSearch parameter) + - `numReplicas` (user-facing replica count) + + The JSDoc on `PatchEndpointRequest.replicationFactor` even says: + "This is the raw replication factor, not 'total data copies'. + For the user-facing replica count (which uses total-copies + semantics), see `PatchEndpointThroughputRequest.num_replicas`." + That cross-reference inside JSDoc is a strong smell — these are + three names for two distinct concepts, and the type system does + not enforce which goes where. +- **Suggestion:** API-shape concern. Consolidate at the spec level: + pick one of (qps, replicas) as the public dimension; demote + `replicationFactor` to "advanced" with a clearer name like + `openSearchReplicationFactor` (so the implementation leak is + explicit). + +#### F12.3 — `Endpoint.name` vs `Endpoint.id` (HIGH) +- **Where:** `model.ts:113, 125`. +- **Why flagged:** Both fields are documented as identifiers + ("Name of the vector search endpoint" / "Unique identifier of the + endpoint"). Every URL uses `name`, never `id`. Two identifiers + for the same entity confuse users; see F1.4, F6.1, F19.2. +- **Suggestion:** Document the distinction prominently + (`name` = user-chosen URL-safe key, `id` = opaque GUID). Or + collapse to one identifier at the API level. + +#### F12.4 — `concurrency` (CPU) vs `numReplicas` vs `targetQps` mixed (MEDIUM) +- **Where:** `model.ts:69, 73, 87, 93, 162, 165, 168, 171, 177, + 235, 238, 240, 252`. +- **Why flagged:** Concurrency in `EndpointThroughputInfo` is "total + CPU"; replicas are "data copies including primary"; QPS is a + performance target. Three orthogonal dimensions, all related to + "how big the endpoint is". The terms are easy to confuse. +- **Suggestion:** API-shape concern. Add a single explainer JSDoc on + the `Endpoint` type explaining the relationship. + +#### F12.5 — `budgetPolicyId` vs `effectiveBudgetPolicyId` (LOW) +- **Where:** `model.ts:131, 133, 207, 209`. +- **Why flagged:** Two fields, same domain, distinguished by the + word "effective". A reader needs JSDoc to know which is the + request and which is the result of policy resolution. +- **Suggestion:** Acceptable convention; JSDoc clarifies. Not a + duplicate, just adjacent. + +#### F12.6 — `usagePolicyId` vs `budgetPolicyId` (LOW) +- **Where:** `model.ts:83, 85`. +- **Why flagged:** Two different policy IDs whose JSDoc says one + will be replaced by the other ("usagePolicyId" — "to be applied + once we've migrated to usage policies"). Transitional API — both + exist today. +- **Suggestion:** Acceptable transition; should be cleaned up post + migration. + +#### F12.7 — Per-method header construction duplicated (LOW, code style) +- **Where:** `client.ts:90, 126, 151, 182, 225, 254, 286`. +- **Why flagged:** Every method runs: + ```ts + const headers = new Headers(...); + headers.set('User-Agent', this.userAgent); + ``` + Could be a private helper `this.buildHeaders(...)`. Not a naming + issue, but a code-duplication smell. +- **Suggestion:** Out of scope for naming audit. Same finding as in + `budgets`. + +--- + +### 13. Verb-tense inconsistency + +#### F13.1 — Method verbs (acceptable for CRUD) +- `create*`, `delete*`, `get*`, `list*`, `patch*` — all uniform + imperative present. Good. + +#### F13.2 — `patch*` vs `update*` (MEDIUM) +- **Where:** Method `patchEndpoint` (`client.ts:217`), JSDoc says + "Update an endpoint" (`client.ts:216`). +- **Why flagged:** REST verbs in the SDK are mixed. Most packages + use `update*` (e.g. `updateBudgetConfiguration`); this package + uses `patch*`. Both describe the same HTTP verb (`PATCH`) but + with different SDK ergonomics. +- **Suggestion:** Cross-package decision. If the SDK standardizes + on `update`, rename to `updateEndpoint`, + `updateEndpointBudgetPolicy`, `updateEndpointThroughput`. If on + `patch`, fix the JSDoc to say "Patch". See F17.1. + +#### F13.3 — `createEndpoint` / `createEndpointWaiter` overlap (MEDIUM) +- **Where:** `client.ts:82, 107`. +- **Why flagged:** Two methods with the same verb start; only one + actually performs the create — the waiter version *calls* the + create then wraps. Reader might think `createEndpointWaiter` is + a *different* operation. +- **Suggestion:** See F7.7. Acceptable if the verb pattern is + applied consistently across the SDK; flag for cross-cutting + decision. + +#### F13.4 — `unmarshalXSchema` constants (LOW, code style) +- **Where:** `model.ts:267, 280, 290, 293, 329, 340, 350, 376, 387, 398`. +- **Why flagged:** Naming pattern `verb + noun + Schema` makes them + read like functions; they are Zod constants. Same finding as + in `budgets` audit (F13.3 there). +- **Suggestion:** Generator-level rename to `endpointWireSchema` or + `endpointDecoderSchema`. Cross-cutting. + +#### F13.5 — `creationTimestamp` / `lastUpdatedTimestamp` past-tense + asymmetry (LOW) +- **Where:** `model.ts:117, 119`. +- **Why flagged:** "creation" (noun) vs "lastUpdated" (past + participle). Not parallel. Other SDK packages use + `createTime`/`updateTime` (noun-form) or `createdAt`/`updatedAt` + (past-participle). This package mixes both forms. +- **Suggestion:** Standardize as `createdAt` / `updatedAt` (most + idiomatic in TS) or `createTime` / `updateTime` (matches Google + API). Wire fields are `creation_timestamp` and + `last_updated_timestamp`; remap if needed. + +--- + +### 14. Go / Java-style names + +#### F14.1 — `req`, `resp`, `err`, `Iter`, `httpReq`, `apiErr`, + `pkgJson`, `opts`, `msg` (HIGH, cross-cutting) +- **Where:** + - `req` in every client method + - `resp`, `respBody`, `pollResp` in `client.ts` + - `e` in `utils.ts:76` + - `Iter` suffix in `listEndpointIter` + - `httpReq` in `client.ts` + - `apiErr` in `utils.ts:88` + - `pkgJson` in `client.ts:20, 50` + - `opts` in `utils.ts:30, 65-92` + - `msg` in `client.ts:339` +- **Why flagged:** All classic Go idioms ported verbatim. TS + convention favors spelled-out names: `request`, `response`, + `error`, `iterator`/`stream`/`listAll`, `httpRequest`, + `apiError`, `packageJson`, `options`, `message`. +- **Suggestion:** Spell them out. Trivial diff, large readability + gain. Generator-level decision; identical to the recommendation + in the `budgets` audit. + +#### F14.2 — `unmarshal*` / `marshal*` schema prefixes (LOW) +- **Where:** All schema exports. +- **Why flagged:** `marshal`/`unmarshal` is a Go term (`encoding/json`). + The JS/TS world says "serialize"/"deserialize" or "encode"/"decode"; + `JSON.parse`/`JSON.stringify` is the vernacular. +- **Suggestion:** Generator-level rename to `encode`/`decode` or + `serialize`/`deserialize`. Cross-cutting. + +#### F14.3 — `Schema` suffix on Zod constants (acceptable) +- The `…Schema` suffix matches Zod community convention. + +#### F14.4 — `for (;;)` infinite loop (acceptable) +- **Where:** `client.ts:204`, `utils.ts:48`. +- **Why flagged:** Style; this is a `for (;;)` Go-idiom (the Go form + is `for { … }`). TS prefers `while (true)` or `do { … } while (…)`. + But `for (;;)` is also legal and idiomatic in C-derived languages. +- **Suggestion:** Acceptable; consistent within the SDK. + +#### F14.5 — `Waiter` suffix (Go-style) (MEDIUM) +- **Where:** `client.ts:107-116, 307`. Exported as + `CreateEndpointWaiter` (`index.ts:3`). +- **Why flagged:** "Waiter" is an AWS SDK / Go SDK pattern. TS + ecosystems more often expose a `Promise`-returning method (e.g. + `createAndWait`, `pollUntilDone`) or an async iterator. The + `Waiter` object has only two methods (`wait`, `done`); could be + a function. +- **Suggestion:** Rename to `EndpointCreatePoller` (more JS-y) or + inline as `createEndpointAndWait(): Promise`. Or keep + for parity with other Databricks SDKs (Go has Waiters; users + porting may expect them). + +#### F14.6 — `numIndexes`, `numReplicas` `num` prefix (LOW) +- **Where:** `model.ts:87, 129, 177, 179, 252`. +- **Why flagged:** `num` is shortened from "number of". TS often + uses the bare noun (`replicas`, `indexCount`) or `count` suffix. +- **Suggestion:** `replicaCount`, `indexCount` (more idiomatic). + Wire field is `num_replicas` — generator-level remap. + +--- + +### 15. Generic field names losing meaning + +#### F15.1 — `Endpoint.name` (HIGH) +- See F1.4 / F6.1. + +#### F15.2 — `Endpoint.id` (LOW) +- **Where:** `model.ts:125`. +- **Why flagged:** Bare `id` is the most generic identifier name + possible. Acceptable inside the type domain — but only because + the type is `Endpoint`. +- **Suggestion:** Keep; the type context disambiguates. + +#### F15.3 — `state`, `status`, `message` (LOW) +- See F1.6, F1.7, F1.8. + +#### F15.4 — `key` / `value` on `CustomTag` (LOW) +- **Where:** `model.ts:98-100`. +- **Why flagged:** Generic; same finding as `BudgetConfigurationFilter_TagClause.key/value` + in `budgets`. Wrapping type supplies context, but `tagKey` / + `tagValue` would self-document. +- **Suggestion:** Wire fields are `key`/`value`; rename costs a + marshaller mapping. Optional. + +#### F15.5 — `req` parameter on every client method (HIGH) +- See F1.5. + +#### F15.6 — `concurrency` field (MEDIUM) +- **Where:** `model.ts:70, 236`. +- **Why flagged:** "Concurrency" alone is generic. JSDoc clarifies + "(total CPU) for the endpoint" but the field name doesn't. Compare + `currentConcurrency` / `requestedConcurrency` (descriptive) vs + bare `concurrency` (ambiguous). +- **Suggestion:** Document "total CPU" semantics in JSDoc explicitly; + consider `concurrencyCpu` or `totalCpu` rename. Or move CPU into + its own dimension. + +--- + +### 16. Field contradicting type domain + +#### F16.1 — `AdjustedThroughputRequest` appears in a response (MEDIUM) +- See F11.1. + +#### F16.2 — `EndpointThroughputInfo.changeRequestState: + ThroughputChangeRequestState` (MEDIUM) +- **Where:** `model.ts:173`. +- **Why flagged:** The field name says "change request state"; the + enum is `ThroughputChangeRequestState`. The type is *not* a state + about *throughput change requests* abstractly — it's the state of + the most recent throughput change request for *this* endpoint. + Field name + type name both bury that scope. Compare a more + direct `lastThroughputChangeState`. +- **Suggestion:** Rename field to `lastChangeState` (drop redundant + "request"); or add JSDoc clarifying "Most recent" semantics. + +#### F16.3 — `state` on `EndpointScalingInfo` is a *change* state, not + a *scaling* state (LOW) +- **Where:** `model.ts:144`. +- **Why flagged:** Field is `state: ScalingChangeState` — the + field-on-type domain is "scaling info", but the field type is + "scaling **change** state". JSDoc says "The current state of the + scaling change request" — so the field name should arguably + match. +- **Suggestion:** Rename field to `changeState` or + `lastChangeState`. + +#### F16.4 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` health + semantics (LOW) +- **Where:** `model.ts:57-58`. +- **Why flagged:** These are health-color states, not lifecycle states. + Lumping them with `PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED` + (lifecycle states) in the same enum mixes two orthogonal + dimensions. +- **Suggestion:** API-shape concern. Split into `lifecycleState` + and `healthState`, or rename to be uniformly health-colored + (`GREEN` for `ONLINE`). + +--- + +### 17. Inconsistent action verbs + +#### F17.1 — `patch*` vs `update*` (MEDIUM) +- See F13.2. Cross-cutting. + +#### F17.2 — `Get` vs `List` for read endpoints (acceptable) +- `getEndpoint` for single, `listEndpoint` for collection. Standard + REST verbs. (Plural issue covered in F9.1.) + +#### F17.3 — `listEndpointIter` (MEDIUM) +- **Where:** `client.ts:199`. Already flagged in F7.8 / F14.1. + +#### F17.4 — `marshal` / `unmarshal` / `parseResponse` / + `marshalRequest` (LOW) +- **Where:** `utils.ts:113, 119`, all schema names. +- **Why flagged:** `parse` vs `marshal` use different verbs for the + same kind of operation (JSON conversion). Inconsistent verb + choice. Same finding as `budgets` F17.4. +- **Suggestion:** Use the same axis throughout: either + `marshal/unmarshal` or `encode/decode` or `serialize/deserialize`. + +#### F17.5 — `createEndpoint` returns `Endpoint`, + `createEndpointWaiter` returns `CreateEndpointWaiter` (MEDIUM) +- **Where:** `client.ts:82, 107`. +- See F7.7 / F13.3. + +#### F17.6 — `wait` vs `done` on `CreateEndpointWaiter` (acceptable) +- **Where:** `client.ts:318, 362`. +- Both verbs are well-chosen. `wait` is blocking-until-terminal; + `done` is a non-blocking check. Symmetric and clear. + +--- + +### 18. Long enum values + +#### F18.1 — `SCALING_CHANGE_IN_PROGRESS` (MEDIUM) +- **Where:** `model.ts:16`. 26 characters; mostly the redundant + `SCALING_CHANGE_` prefix (F2.1). +- **Suggestion:** With prefix stripped → `IN_PROGRESS` (11 chars). + +#### F18.2 — `SCALING_CHANGE_UNSPECIFIED` (MEDIUM) +- **Where:** `model.ts:14`. 26 characters; same root cause. +- **Suggestion:** With prefix stripped → `UNSPECIFIED` (11 chars). + +#### F18.3 — `CHANGE_REACHED_MINIMUM`, `CHANGE_REACHED_MAXIMUM` (MEDIUM) +- **Where:** `model.ts:26, 28`. 22 characters each. +- **Suggestion:** With prefix stripped → `REACHED_MINIMUM` / + `REACHED_MAXIMUM` (15 chars). + +#### F18.4 — `STORAGE_OPTIMIZED`, `STANDARD_ON_ORION` (LOW) +- 17 chars each; reasonable. `ON_ORION` is an infra leak (F6.4). + +#### F18.5 — `PROVISIONING` (acceptable) +- 12 chars. Standard. + +--- + +### 19. Underspecified IDs + +#### F19.1 — `Endpoint.id` (LOW) +- See F15.2. Bare `id` inside `Endpoint` is fine. + +#### F19.2 — `Endpoint.name` doubles as ID (HIGH) +- See F1.4 / F6.1 / F12.3. Two identifiers (`name` and `id`) for + the same entity is the underspecification problem. + +#### F19.3 — `budgetPolicyId`, `usagePolicyId`, + `effectiveBudgetPolicyId` (acceptable) +- **Where:** `model.ts:83, 85, 131, 133, 201, 203, 207, 209`. +- Specific enough; matches platform-wide convention. + +--- + +### 20. Type-suffix tautology + +#### F20.1 — `Endpoint.endpointType: EndpointType` (MEDIUM) +- **Where:** `model.ts:121`, `model.ts:81`. +- **Why flagged:** Three layers of "endpoint": + `endpoint.endpointType : EndpointType`. The container provides + the "endpoint" context. +- **Suggestion:** Rename field `endpointType → type` (similar + pattern in `budgets` F20.1 / F20.2). Wire field is + `endpoint_type`; needs a marshaller remap. + +#### F20.2 — `Endpoint.endpointStatus: EndpointStatus` (MEDIUM) +- **Where:** `model.ts:127`, `model.ts:153`. +- **Why flagged:** Same pattern. +- **Suggestion:** Rename field `endpointStatus → status`. + +#### F20.3 — `EndpointStatus.state: EndpointStatus_State` (LOW) +- **Where:** `model.ts:155`. +- **Why flagged:** Field is `state`, enum is `EndpointStatus_State`. + Not strictly tautological (the field is the bare noun, the type + is the qualified noun). Acceptable. + +#### F20.4 — `PatchEndpointThroughputResponse.status: + ThroughputPatchStatus` (LOW) +- **Where:** `model.ts:257`, `model.ts:36`. +- **Why flagged:** Field is `status`; type is `ThroughputPatchStatus`. + Reading `response.status : ThroughputPatchStatus` is "status . throughput + patch status". +- **Suggestion:** Rename field to `result` (less tautological), or + rename enum to drop `Status` (becomes `ThroughputPatch`). Or + accept the tautology. + +#### F20.5 — `EndpointScalingInfo.state: ScalingChangeState` (LOW) +- **Where:** `model.ts:144`. +- **Why flagged:** Same pattern. Field `state` typed against + `ScalingChangeState` reads "scaling info . state : scaling change + state". +- **Suggestion:** Rename field to `changeState` (matches the enum's + domain better). See F16.3. + +#### F20.6 — `EndpointThroughputInfo.changeRequestState: + ThroughputChangeRequestState` (LOW) +- **Where:** `model.ts:173`. +- **Why flagged:** Field name and type name carry the same tokens + (`changeRequestState` ↔ `ChangeRequestState`). +- **Suggestion:** Acceptable; this is the standard pattern. + +--- + +## Package overlap: `endpoints` vs `warehouses` vs `modelservingmanagement` vs `indexes` + +This SDK exposes *three* distinct "endpoint" packages plus a sibling +"index" package, all conceptually distinct but lexically similar. + +### F-OVERLAP.1 — `Endpoint` symbol exists in three places (HIGH) +- **Where:** + - `packages/endpoints/src/v1` exports `Endpoint` + - `packages/warehouses/src/v1` exports `EndpointState`, + `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy`, + `EndpointHealth_Status` + - `packages/modelservingmanagement/src/v1` exports + `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel`, + `InferenceEndpointState_*` +- **Why flagged:** Project-wide `grep -r Endpoint` returns hits across + all three packages. Autocomplete on "Endpoint" collides. Even with + qualified imports, mental load is high. +- **Suggestion:** Rename per F0.1. The model serving package already + qualifies its primary type as `InferenceEndpoint`; this package + should qualify as `VectorSearchEndpoint`; the warehouse package's + legacy `Endpoint*` names are wire-protocol and should be deprecated + but left for compatibility. + +### F-OVERLAP.2 — `indexes` companion package is also under-qualified (LOW) +- See F0.3. + +### F-OVERLAP.3 — Pluralization of package names (`endpoints` plural + vs `modelservingmanagement` singular vs `warehouses` plural) (LOW) +- Cross-package style decision. Some packages use plural + (`endpoints`, `warehouses`, `clusters`, `budgets`), some + singular (`modelservingmanagement`, `budgetpolicy`, `bundle`). +- **Suggestion:** Pick one. Cross-cutting. + +### F-OVERLAP.4 — `EndpointType` exists in this package vs + `WarehouseType` exists in `warehouses` (LOW) +- **Where:** `model.ts:6` here vs + `warehouses/src/v1/index.ts` line for `WarehouseType`. +- **Why flagged:** `WarehouseType` is qualified; `EndpointType` is + bare. After F0/F1 rename it becomes `VectorSearchEndpointType` — + symmetric with `WarehouseType`. + +--- + +## Summary table + +| # | Category | Findings | +| - | --------------------------------------- | -------- | +| 0 | **Package name (special)** | 3 | +| 1 | Vague / generic | 9 | +| 2 | Redundant enum prefixes | 5 | +| 3 | Acronym casing | 4 (3 acceptable) | +| 4 | Underscores in TS identifiers | 2 | +| 5 | Cryptic abbreviations | 10 | +| 6 | Misleading names | 9 | +| 7 | Overly verbose | 9 | +| 8 | Redundant suffixes | 5 | +| 9 | Singular / plural mismatch | 5 (3 acceptable) | +| 10 | Reserved-word collisions | 5 (3 acceptable) | +| 11 | Empty / trivial wrappers | 1 | +| 12 | Duplicate concepts | 7 | +| 13 | Verb-tense inconsistency | 5 (1 acceptable) | +| 14 | Go / Java-style names | 6 | +| 15 | Generic field names | 6 | +| 16 | Field contradicting type domain | 4 | +| 17 | Inconsistent action verbs | 6 (2 acceptable) | +| 18 | Long enum values | 5 (1 acceptable) | +| 19 | Underspecified IDs | 3 (2 acceptable) | +| 20 | Type-suffix tautology | 6 (3 acceptable) | +| OVERLAP | endpoints vs warehouses vs serving | 4 | +| **Total** | | **118** | + +--- + +## Top highest-impact renames (recommended order) + +1. **F0.1 / F0.2 / F1.1 / F1.2 / F-OVERLAP.1:** Rename the package + to `@databricks/sdk-vectorsearchendpoints` (or + `@databricks/sdk-vectorsearch`); rename `Endpoint` to + `VectorSearchEndpoint`. This single change eliminates the most + confusing ambiguity in the package. +2. **F2.1 / F2.2 / F2.3:** Strip the redundant member prefixes from + `ScalingChangeState` (`SCALING_CHANGE_*`), + `ThroughputChangeRequestState` (`CHANGE_*`), and + `ThroughputPatchStatus` (`PATCH_*`). +3. **F9.1 / F9.2:** Pluralize the list method, request, and response: + `listEndpoints`, `ListEndpointsRequest`, `ListEndpointsResponse`, + `listEndpointsIter`. +4. **F4.1 / F14.4:** Replace `EndpointStatus_State` with namespace + nesting or flat PascalCase (`EndpointStatusState`); eliminate + the `eslint-disable-next-line` for `naming-convention`. +5. **F6.5:** Rename `minimalConcurrencyAllowed → + minimumConcurrencyAllowed` (the existing name is grammatically + wrong English). +6. **F12.3 / F1.4 / F6.1 / F19.2:** Resolve the `Endpoint.name` vs + `Endpoint.id` duality — either document the distinction + prominently or unify at the API level. +7. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from + `Endpoint.endpointType` and `Endpoint.endpointStatus` to bare + `type` / `status`. +8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`Iter`/`opts`/ + `pkgJson`/`msg` across the generated code. +9. **F12.2:** Resolve the `targetQps` / `replicationFactor` / + `numReplicas` overlap at the API spec level — three names for + related concepts, with JSDoc cross-references between them, is + a strong smell. + +--- + +## Notes / out-of-scope + +- All findings above relate to **generated** code. Code-base rule: + "Code generated from API definition by Databricks SDK Generator. + DO NOT EDIT." The fixes belong upstream in the generator and + spec. This audit is a backlog for that generator. +- The `utils.ts` file contains the same generic helpers + (`executeCall`, `parseResponse`, `marshalRequest`, + `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, + `readAll`) that every generated package duplicates. The + duplication itself is not a naming issue, but the *names* + (`marshal/unmarshal`) are Go-flavored and inconsistent with + `parseResponse`. +- This package has no `tests/` directory (verified by repo + structure check), so the audit does not cover test naming. +- The `Waiter` pattern (`CreateEndpointWaiter`) is a Go SDK idiom + ported verbatim; whether to keep it for parity or replace with a + JS-idiomatic `Promise`/async-iterator API is a cross-cutting + design decision. +- "Endpoint" appearing across the SDK is a *Databricks-wide* problem + — the term is used by Vector Search, Model Serving, and SQL + Warehouses for three different concepts. Disambiguation at the + SDK level is unavoidable. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md new file mode 100644 index 00000000..1bf71dba --- /dev/null +++ b/.agent/naming-audit/entitytagassignments.md @@ -0,0 +1,258 @@ +# Naming Audit: entitytagassignments + +**Path:** `packages/entitytagassignments/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) and inheritance (`inherited` / `includeInherited`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). +**Total weird names flagged:** 37 + +## Summary +| Severity | Count | +| --- | --- | +| High | 11 | +| Medium | 13 | +| Low | 8 | +| Observation | 5 | + +## High severity + +### 1. Package name `entitytagassignments` vs. sister `tagassignments` — `package directory name` +- **Why weird:** Two packages exist whose names differ only by the prefix `entity`: `entitytagassignments` (Unity Catalog tables/schemas/columns) and `tagassignments` (apps, dashboards, geniespaces, notebooks). Both model "a tag assigned to a thing", both expose the same five operations (Create/Get/List/Update/Delete), and both have a primary type called `(Entity)TagAssignment`. The split mirrors a backend HTTP-path split (`/api/2.1/unity-catalog/entity-tag-assignments` vs. `/api/2.0/tag-assignments`) that is invisible to TS users. +- **Category:** 12 (duplicate concept across two packages — overlapping responsibility), 1 (vague: what is a non-entity tag assignment?), 16 (the field `entityType` in `tagassignments` carries the *exact same* notion that the prefix `entity` carries here, so the disambiguating prefix is doubly redundant). +- **Suggested name:** Merge into a single package `tagassignments` keyed by `entityKind` ("uc" vs. "platform"), or rename to `uctagassignments` so the surface marker is "uc", not "entity". The non-UC sibling can drop its own `entityType` field discrimination and become `platformtagassignments`. As a smaller fix: `unitycatalogtags` here, `platformtags` there. +- **Rationale:** Two `Client` classes called `Client`, with two `TagAssignment` / `EntityTagAssignment` types, both shipping `tagKey`/`tagValue`/`entityType`, will collide in user imports and force aliasing on every co-use. The split exists for backend reasons but leaks raw into the SDK. Worth flagging upstream as a generator-level concern. + +### 2. `EntityTagAssignment` — `src/v1/model.ts:32` +- **Why weird:** The redundant "Entity" prefix on the primary type. Every assignment is an assignment of a tag to an *entity*; there is no non-entity tag assignment. Within this package, `Entity` adds nothing beyond what `TagAssignment` already implies, and the package directory already carries the namespace. Inside `tagassignments`, the same concept is plainly `TagAssignment`. +- **Category:** 8 (redundant prefix — `Entity` repeats the universal subject), 12 (duplicate concept — `TagAssignment` already exists in `tagassignments`). +- **Suggested name:** `TagAssignment`. Rely on package-import disambiguation: `import {TagAssignment as UcTagAssignment} from '@databricks/sdk-entitytagassignments'`. +- **Rationale:** A noun that re-states its only possible subject is filler. The Go SDK names it `EntityTagAssignment` to disambiguate from a different proto type in the same Go package; TS module imports already do that disambiguation. + +### 3. `EntityTagAssignment` field shape vs. sister `TagAssignment` shape — `src/v1/model.ts:32-49` vs. `tagassignments/src/v1/model.ts:46-55` +- **Why weird:** The two sister types model the same conceptual object using different identifier fields: this package's `EntityTagAssignment` has `entityName: string`, while `tagassignments.TagAssignment` has `entityId: string`. Same column conceptually (the thing being tagged), different field name. A user porting code between the two has to translate. The JSDoc here says "fully qualified name" while the sister says "identifier"; the wire-side names are `entity_name` vs. `entity_id`. +- **Category:** 12 (duplicate concept with divergent naming), 17 (verb/noun inconsistency across siblings), 16 (field contradicts type domain — "name" suggests a label, "id" suggests an opaque handle, but both fields are fully-qualified resource identifiers). +- **Suggested name:** Unify on `entityFullName` (matches Unity Catalog vocabulary like `catalogs.fullName`, `tables.fullName`) or `entity` for both packages. At minimum, both packages should agree. +- **Rationale:** Splitting "name vs id" by package makes the cross-package developer experience worse. The Unity Catalog product surface consistently calls these `full_name`/`fullName` (see `catalogs`, `schemas`, `tables`); using `entityName` here breaks that convention silently. + +### 4. `TagAssignmentSourceType` — `src/v1/model.ts:9` +- **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. Combined with the surrounding type `EntityTagAssignment`, the relevant field is `sourceType: TagAssignmentSourceType` — five words to say "where did this come from". +- **Category:** 20 (type-suffix tautology — `Type` on an enum), 8 (redundant prefix — every member is prefixed `TAG_ASSIGNMENT_SOURCE_TYPE_*`), 7 (overly verbose). +- **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). Field becomes `source: TagSource`. +- **Rationale:** The shorter name is unambiguous in context (`EntityTagAssignment.source` reads better than `EntityTagAssignment.sourceType`). Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. + +### 5. `TagAssignmentSourceType.TAG_ASSIGNMENT_SOURCE_TYPE_UNSPECIFIED` / `TAG_ASSIGNMENT_SOURCE_TYPE_SYSTEM_DATA_CLASSIFICATION` — `src/v1/model.ts:11-13` +- **Why weird:** Both enum members carry the entire enum name as prefix, then `_UNSPECIFIED` (a protobuf sentinel) or `_SYSTEM_DATA_CLASSIFICATION` (a 24-character SCREAMING_SNAKE value). The TS access is `TagAssignmentSourceType.TAG_ASSIGNMENT_SOURCE_TYPE_SYSTEM_DATA_CLASSIFICATION` — the user types `TagAssignmentSourceType` *twice* in a single expression. +- **Category:** 2 (redundant enum prefix on every member), 14 (proto/Go-style names — TS enum members do not need self-prefixing), 18 (long enum values — 38 chars). +- **Suggested name:** `TagSource.Unspecified` and `TagSource.SystemDataClassification` (drop the redundant prefix; use PascalCase per TS enum conventions). Better: omit `Unspecified` and let `source?: TagSource | undefined` express "not set". +- **Rationale:** TS enum members are already namespaced by the enum identifier; the proto-emitted `ENUM_NAME_VALUE` pattern adds nothing. The `Unspecified` sentinel is a proto-mandated zero-value that has no role in TS where `undefined` is first-class. Compare canonical TS enums (`Severity.High`, `Color.Red`). + +### 6. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,53,66` +- **Why weird:** Five places in this file have a field called `entityName` whose JSDoc says "The fully qualified name of the entity to which the tag is assigned". The shape `name?: string | undefined` cannot enforce qualification; users will pass bare names. Compare Unity Catalog convention `fullName` (used in `catalogs`, `schemas`, `tables`). +- **Category:** 1 (vague — "name" is too generic), 6 (misleading — looks settable to a bare name, is actually structured), 15 (generic field name losing meaning), 19 (underspecified ID — what makes it "fully qualified"?). +- **Suggested name:** `entityFullName` (or `entity`/`entityFqn`). Matches sister UC packages. +- **Rationale:** "fully qualified" is wire-side; the SDK type should make the constraint visible in the identifier. A field literally called `entityName` reads as a display name to most TS users. + +### 7. `entityType: string` everywhere — `src/v1/model.ts:28,40,58,72` +- **Why weird:** Four occurrences of `entityType?: string | undefined` with no enum or string-literal union to constrain values. The JSDoc says "The type of the entity to which the tag is assigned" but never lists which values are valid (compare sister `tagassignments`: doc explicitly lists `apps, dashboards, geniespaces, notebooks`). For Unity Catalog entities, the actual valid set is something like `table`, `schema`, `catalog`, `column`, `volume`, `function`, `model` — none of which is documented or constrained in the type. +- **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what type strings are valid?), 6 (misleading — looks free-form, is actually constrained). +- **Suggested name:** `EntityKind` (string-literal union or enum) typed as the field. E.g. `entityKind?: 'table' | 'schema' | 'catalog' | 'column' | 'volume' | 'function' | 'model'`. The field name `Type` also collides with the JS reserved-ish word — `Kind` reads more cleanly. +- **Rationale:** Stringly-typed enum fields are a generator anti-pattern. The valid set is closed; the type should say so. `Type` as a noun is also overused — `Kind` is the convention in TS standard library (`SyntaxKind`, `NodeKind`). + +### 8. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,55` +- **Why weird:** `DeleteEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag to delete". `GetEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag". But `EntityTagAssignment.tagKey` (on the actual returned/created object) and `CreateEntityTagAssignmentRequest.tagAssignment.tagKey` are documented as just "The key of the tag" with no required marker — yet you cannot create or get a tag without a key. The `?: string | undefined` typing makes all of them optional in TS. Type and doc disagree. +- **Category:** 6 (misleading — type says optional, semantics says required), 17 (inconsistent — some docs say "Required.", others don't, for what is the same logical field). +- **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) and remove the "Required." doc preamble since the type enforces it. Apply uniformly across all four request types and the assignment type itself. +- **Rationale:** "Required." in a docstring while the type is optional is a generator smell. Honest required-ness should travel through the type. + +### 9. `includeInherited` boolean doc is wrong — `src/v1/model.ts:60,74` +- **Why weird:** The JSDoc on `GetEntityTagAssignmentRequest.includeInherited` and `ListEntityTagAssignmentsRequest.includeInherited` reads "Boolean which indicates whether this tag is inherited." That is the doc for `EntityTagAssignment.inherited` (a read-side, per-row marker). The request-side `includeInherited` is a *filter* meaning "include inherited tags in the response", not a per-tag inheritance marker. The same wrong doc is copy-pasted onto a settings flag with different semantics. +- **Category:** 6 (misleading — doc says one thing, field does another), 12 (duplicate concept naming — `inherited` (the marker) vs. `includeInherited` (the filter) both documented identically), 17 (inconsistent prose for sibling fields). +- **Suggested name:** Keep `includeInherited` on the request types; fix the doc to "If true, include inherited tag assignments in the result." Keep `inherited` on `EntityTagAssignment`. +- **Rationale:** Doc-code mismatch produces incorrect SDK behaviour at the agent level. Even if it's a generator issue, this audit must flag it. + +### 10. `Client` class — `src/v1/client.ts:41` +- **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The other tag packages (`tagassignments`, `tagpolicies`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages). +- **Suggested name:** `EntityTagAssignmentsClient` (or `UnityCatalogTagsClient`). +- **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing. Generator-level concern. + +### 11. Method names `createEntityTagAssignment` / `deleteEntityTagAssignment` / `getEntityTagAssignment` / `listEntityTagAssignments` / `updateEntityTagAssignment` — `src/v1/client.ts:76,114,133,169,235` +- **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createEntityTagAssignment(...)` reads as "package.subject.create.subject" — the noun is doubled. Sister package `tagassignments` does the same with `createTagAssignment`. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. +- **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `EntityTagAssignment` four/five times when the client only manages `EntityTagAssignment`). +- **Suggested name:** `create`, `delete`, `get`, `list`, `update` (and `listIter`). Or shorter `createAssignment` / `deleteAssignment` / etc. +- **Rationale:** A client class that ships exactly five methods all named after the same subject is repeating the subject. `EntityTagAssignmentsClient.create()` is the more readable shape. + +## Medium severity + +### 12. `CreateEntityTagAssignmentRequest` etc. — five request DTOs share a 25-char prefix — `src/v1/model.ts:17,22,52,64,85` +- **Why weird:** `CreateEntityTagAssignmentRequest`, `DeleteEntityTagAssignmentRequest`, `GetEntityTagAssignmentRequest`, `ListEntityTagAssignmentsRequest`, `UpdateEntityTagAssignmentRequest`. Each is 33 characters; the common prefix `EntityTagAssignment` is 19 chars of repetition. In the package whose only subject is the entity tag assignment, every request type re-states that subject. +- **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). +- **Suggested name:** `CreateRequest` / `DeleteRequest` / `GetRequest` / `ListRequest` / `UpdateRequest`. Or drop just the noun: `CreateRequest` etc. +- **Rationale:** Single-subject packages don't need to repeat the subject on every request DTO. Listed as medium because the inconsistency with the rest of the SDK matters. + +### 13. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:64` vs. `src/v1/model.ts:32` +- **Why weird:** The plural appears only on the list endpoint; the rest of the surface is singular. Singular/plural mix is consistent with the Go SDK and other packages, but worth flagging that the resource name on the wire is `/entity-tag-assignments` (plural) while the type name is singular `EntityTagAssignment`. The list response is `ListEntityTagAssignmentsResponse` (plural). +- **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). +- **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. +- **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. + +### 14. `entityTagAssignmentFieldMask` / `entityTagAssignmentFieldMaskSchema` — `src/v1/model.ts:154,165` +- **Why weird:** Same long prefix on the schema constant and the helper function (40+ char identifier). The two exports differ only by suffix (`Schema` vs. no `Schema`). Function vs. lookup-table naming should be more distinguishable, and `entityTagAssignment` is the same redundant prefix flagged in #2. +- **Category:** 17 (inconsistent action verbs — function and noun share a stem), 7 (overly verbose). +- **Suggested name:** `tagAssignmentFieldMask(...)` and `tagAssignmentFieldMaskSchema` (drop `Entity` prefix), or rename the function to `buildTagAssignmentFieldMask(...)` for verb-prefixing. +- **Rationale:** Function should be verb-prefixed; otherwise it reads as a noun. Sister packages (`tagassignments/src/v1/model.ts:110`) suffer the same. + +### 15. `marshalEntityTagAssignmentSchema` / `unmarshalEntityTagAssignmentSchema` / `unmarshalListEntityTagAssignmentsResponseSchema` — `src/v1/model.ts:90,116,129` +- **Why weird:** These are Zod schemas (53-char identifier on `unmarshalListEntityTagAssignmentsResponseSchema`!), but the verbs are `marshal`/`unmarshal` (Go terminology). TS users would say `encode`/`decode` or `serialize`/`parse`. Zod's own API verb is `.parse()`. The TS+Go vocab mix is jarring. +- **Category:** 14 (Go-style verbs in TS code), 17 (verb inconsistency with Zod's own `.parse()`). +- **Suggested name:** `encodeTagAssignmentSchema` / `decodeTagAssignmentSchema` / `decodeListResponseSchema`. Or stick with `marshal`/`unmarshal` but apply uniformly — the audit's role is to flag the mismatch. +- **Rationale:** `marshal`/`unmarshal` is a Go term of art; TS reaches for `serialize`/`parse` or Zod's parse. Generator-wide concern. + +### 16. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions named "execute" — `executeCall` runs the retry/rate-limit shell, `executeHttpCall` does the actual HTTP send. They appear together in every client method: + ```ts + const call: Call = async (callSignal?: AbortSignal): Promise => { + ... + const respBody = await executeHttpCall({...}); + ... + }; + await executeCall(call, options); + ``` + Reading just the names, a developer cannot tell which wraps which. +- **Category:** 1 (vague), 12 (duplicate concept — both "execute"), 17 (inconsistent layering name). +- **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. +- **Rationale:** Names should reveal the layering, not require code-diving. Generator-wide concern. + +### 17. `Call` type and `call` variable — `src/v1/client.ts:86,119,145,187,251` and `src/v1/utils.ts:27` +- **Why weird:** Variable `call` of type `Call`, called inside `executeCall(call, options)`. The same word is the variable, the type, and the verb. Inside one method scope we have `req`, `call`, `httpReq` — three layered names where one of them collides with its type. +- **Category:** 1 (vague), 12 (duplicate concept). +- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. +- **Rationale:** Type-name collisions are tolerable but obscure prose-style code. + +### 18. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,173,239` +- **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. +- **Category:** 6 (misleading — optional in type but required in practice). +- **Suggested name:** Make path-component fields required (non-optional) on the request types. +- **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. + +### 19. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 149-155, 194-199, 261-266` +- **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: EntityTagAssignment`. The names differ only by `Body`. Both are short for "response". The reader has to track which is bytes, which is parsed. Compare `req` (parameter, request) — also abbreviated, but no `reqBody` sibling. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, `resp` drops the implied `Parsed`). +- **Suggested name:** `rawBody` + `result`, or `responseBytes` + `response`. +- **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. + +### 20. `httpReq` local variable — `src/v1/client.ts:89,122,148,190,254` +- **Why weird:** Inside a method that already has `req: CreateEntityTagAssignmentRequest`, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. +- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). +- **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. +- **Rationale:** Avoid forking the same identifier across two layers in one scope. + +### 21. `pageReq` in `listEntityTagAssignmentsIter` — `src/v1/client.ts:212` +- **Why weird:** Same pattern: inside a method receiving `req: ListEntityTagAssignmentsRequest`, a copy is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; meanwhile the outer `req` is the parameter. Three identifiers — `req`, `pageReq`, the iter's bound — for the same shape over the iteration's lifetime. +- **Category:** 5 (cryptic), 8 (redundant prefix — `page` on a paginated iter is implicit). +- **Suggested name:** `current` or `next` (the iter's evolving cursor state). +- **Rationale:** A variable that mutates a clone of the input parameter usually wants a name that describes *its role* (cursor state), not a casual prefix on the parameter name. + +### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. +- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). +- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. +- **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. + +### 23. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +- **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. +- **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). +- **Suggested name:** `makeHttpRequest` or inline at call sites. +- **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just shorthand. + +### 24. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` +- **Why weird:** Function takes an arbitrary `unknown` value plus a Zod schema and returns a JSON string. The name says "Request" but the function does not know whether `data` is a request, response, or anything else. Same problem as in `dataclassification`. +- **Category:** 1 (vague — `Request` in the name does not constrain), 6 (misleading — works for any payload). +- **Suggested name:** `marshalToJson` / `encodeToJson`. +- **Rationale:** Symmetric problem to `parseResponse`. Either is fine; both should be specific to actual meaning. + +## Low severity + +### 25. `parseResponse(body, schema)` — `src/v1/utils.ts:113` +- **Why weird:** Symmetric problem to `marshalRequest`. The function parses any JSON `Uint8Array` against a Zod schema. The name says "Response" but the function does not check that. +- **Category:** 1 (vague), 6 (misleading). +- **Suggested name:** `parseJsonBody` / `decodeFromJson`. +- **Rationale:** Same as #24. `marshalRequest` + `parseResponse` are an asymmetric verb pair (`marshal` vs `parse`) AND inaccurate. Either fix both. + +### 26. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** The function is exported but unused in `client.ts` (this package's list endpoint uses individual `params.append(...)` calls instead). Dead-code-shaped helper in shared scaffolding. +- **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). +- **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. +- **Rationale:** Generator-wide concern: every package duplicates this helper. + +### 27. `readAll(body)` — `src/v1/utils.ts:40` +- **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". +- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). +- **Suggested name:** `drainStream` or `readStreamToUint8Array`. +- **Rationale:** A name like `readAll` reads as if it took a file path or array. + +### 28. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. Casing is appropriate for a module constant; the noun is weak. +- **Category:** 1 (vague — `Segment` of what?). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. +- **Rationale:** Single word "segment" gives no domain; the comment above it does the work the name should. + +### 29. `inherited` (boolean) on `EntityTagAssignment` — `src/v1/model.ts:48` +- **Why weird:** A boolean called `inherited`. The participle works (the tag is in an inherited state), but boolean fields are conventionally `is*`/`has*` in TS (`isInherited`). The sibling filter `includeInherited` uses a verb prefix; the marker drops the prefix. Asymmetric. +- **Category:** 17 (inconsistent — `inherited` (no prefix) vs. `includeInherited` (verb-prefixed) in same file). +- **Suggested name:** `isInherited` on the result type. +- **Rationale:** TS booleans usually carry an `is`/`has` prefix to read as predicates. The current name reads grammatically as an adjective on the assignment. + +### 30. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` +- **Why weird:** The pair encodes a `(key, value)` tag — that part is fine. But the type is *already* called `EntityTagAssignment`, so the `tag` prefix on each field is redundant within scope: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. +- **Category:** 8 (redundant prefix — `tag` within `EntityTagAssignment`). +- **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. +- **Rationale:** Field names should not re-state their containing type's noun. `assignment.key` / `assignment.value` reads cleaner. + +### 31. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` +- **Why weird:** Verb tense pair: `updateTime` (noun-noun, gerund stripped) vs. `updatedBy` (past participle). Cross-SDK convention should pick one. Compare: `createTime` (noun-noun) often pairs with `createdBy` (past participle) in Databricks — the same asymmetry. It is consistent across the SDK, but worth noting under rule 13. +- **Category:** 13 (verb-tense inconsistency within a paired field). +- **Suggested name:** `updateTime`/`updateBy` or `updatedTime`/`updatedBy`. Either works; the asymmetry is the issue. +- **Rationale:** Established SDK pattern, but rule 13 demands the flag. + +### 32. `sourceType` vs. `source` (on the enum) — `src/v1/model.ts:46` and `src/v1/model.ts:9` +- **Why weird:** Field is `sourceType: TagAssignmentSourceType`. The field name re-states `Type`, and the type name re-states `SourceType`. The user types "source", "Type", "Source", "Type" — four times in one declaration: `sourceType?: TagAssignmentSourceType | undefined`. +- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). +- **Suggested name:** `source: TagSource` (drop both `Type`s). +- **Rationale:** See #4. The compound effect makes the line read as type-noise. + +## Observations + +### 33. Wire/TS divergence dominates the file +The `model.ts` file is 173 lines for ~7 user-facing types; ~84 lines are `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. + +### 34. Action verb consistency +The client uses `create`/`get`/`update`/`delete`/`list` (plus `listIter`) — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. + +### 35. Acronym casing +The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. +- **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). + +### 36. `entitytagassignments` lowercase package name +The package directory is `entitytagassignments` (single token, no separator), but every type uses `EntityTagAssignment` and the HTTP path uses `entity-tag-assignments`. Same problem as `dataclassification`. SDK-wide convention issue. +- **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). + +### 37. Domain leakage from sister packages +Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. +- **Category:** 12 (duplicate concept across siblings). + +## Domain glossary +- `uc` / Unity Catalog — implicit across the package; the HTTP path includes `/unity-catalog/entity-tag-assignments`. +- `entity` — generic UC resource: catalog, schema, table, column, volume, function, model (never enumerated in this package's types). +- `entity name` — wire docs say "fully qualified name" — i.e., dotted form like `catalog.schema.table` (or column ref). +- `entity type` — string discriminator for the kind of entity (no enum in this package). +- `tag key` / `tag value` — string key/value pair attached to an entity (the "tag" itself). +- `tag policy` — governed tag definition with constraints/values (a separate sister package). +- `governed tag` — a tag whose key matches an active `TagPolicy`. JSDoc mentions ASSIGN/MANAGE permissions on the tag policy. +- `inherited` — flag on a returned assignment indicating it was inherited from a parent (catalog/schema), not directly assigned. +- `source type` — provenance of the assignment: user vs. data-classification (today, only `SYSTEM_DATA_CLASSIFICATION` is enumerated). + +## File coverage +- `src/v1/model.ts` (173 lines): read fully. +- `src/v1/client.ts` (275 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md new file mode 100644 index 00000000..b3283c64 --- /dev/null +++ b/.agent/naming-audit/environments.md @@ -0,0 +1,242 @@ +# Naming Audit: environments + +**Path:** `packages/environments/src/v1/` +**Versions audited:** v1 +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. + +**Total weird names flagged:** 34 + +## Summary +| Severity | Count | +| --- | --- | +| High | 9 | +| Medium | 15 | +| Low | 8 | +| Observation | 2 | + +--- + +## High severity + +### 1. Package name `environments` is generic — does not say "base environment", "serverless", or "Python dependencies" — `packages/environments/` +- **Why weird:** The package name `environments` is the most generic word possible. The actual scope is narrow: workspace-level Python *base environments* (YAML dependency manifests) used by serverless notebooks and jobs. A reader scanning the workspace sees `environments` alongside `connections`, `catalogs`, `credentials` etc. and has no idea this is about Python dependency manifests, not deployment environments / staging / prod / runtime environments. +- **Category:** 1 (vague/generic). +- **Suggested name:** `workspacebaseenvironments`, `baseenvironments`, `serverlessenvironments`, or `pythondependencies`. At minimum, add a JSDoc on `index.ts` saying "Workspace base environment (Python dependency manifest) management for serverless compute". +- **Rationale:** "Environment" is overloaded across infrastructure (prod/staging/dev), runtime (Python/Node), workspace, deployment, and platform meanings. The package is the user's first filter and gives them zero signal. + +### 2. `Environment` concept fragmented across `environments` and `clusterlibraries` packages — `packages/environments/` vs `packages/clusterlibraries/` +- **Why weird:** Two sibling packages model overlapping pieces of the same domain: + - `clusterlibraries/v2` exposes `DefaultBaseEnvironment`, `BaseEnvironmentType`, `DefaultBaseEnvironmentCache`, `DefaultBaseEnvironmentCache_Status`, `Environment`, `MaterializedEnvironment`, and full CRUD on `DefaultBaseEnvironment`s. + - `environments/v1` exposes `WorkspaceBaseEnvironment`, the same `BaseEnvironmentType` enum (redefined, not imported), `WorkspaceBaseEnvironmentCache`, `WorkspaceBaseEnvironmentCache_Status` (same shape as `DefaultBaseEnvironmentCache_Status`), and `DefaultWorkspaceBaseEnvironment`. +- The relationship between `DefaultBaseEnvironment` (cluster-libraries package) and `WorkspaceBaseEnvironment` / `DefaultWorkspaceBaseEnvironment` (this package) is undocumented. They share enum *values* (`BASE_ENVIRONMENT_TYPE_UNSPECIFIED | CPU | GPU`) and status enum members but are textually duplicated rather than reused. +- **Category:** 12 (duplicate concept across packages), 6 (misleading — user can't infer which package owns what). +- **Suggested name:** Either (a) consolidate into a single `baseenvironments` package and have `clusterlibraries` import from it, (b) explicitly cross-reference each shared type in docstrings, or (c) version one of them (`clusterlibraries` `DefaultBaseEnvironment` is presumably v1, `environments` `WorkspaceBaseEnvironment` is v2 — say so). +- **Rationale:** Same shape, redefined in two packages, with subtly different naming (`DefaultBaseEnvironment` vs `WorkspaceBaseEnvironment`). Consumers will hit type-incompatibility errors when passing a value from one package into the other. + +### 3. `WorkspaceBaseEnvironment` — name is a 26-character noun phrase with three adjectives stacked — `model.ts:727` +- **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. The longest exported identifier is `unmarshalWorkspaceBaseEnvironmentOperationMetadataSchema` at 57 characters (`model.ts:870`). +- **Category:** 7 (overly verbose), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). +- **Suggested name:** Drop one of the prefixes. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. +- **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. + +### 4. `WorkspaceBaseEnvironmentCache_Status` — underscore in TS identifier — `model.ts:527, index.ts:14` +- **Why weird:** The identifier `WorkspaceBaseEnvironmentCache_Status` contains an underscore (it is a flattened proto nested-enum name: `package.WorkspaceBaseEnvironmentCache.Status`). It is exported from `index.ts:14` and requires an `eslint-disable-next-line @typescript-eslint/naming-convention` to compile. TS convention (Google TS style guide §9.2; the project's `typescript.mdc` identifier rule) forbids underscores in type names. +- **Category:** 4 (underscores in TS identifiers), 14 (proto/Go-style names). +- **Suggested name:** `WorkspaceBaseEnvironmentCacheStatus`. Since the enum describes the *materialization* lifecycle, `MaterializationStatus` or `EnvironmentMaterializationStatus` would be even clearer. +- **Rationale:** This is a leaky proto abstraction. The underscore preserves a nesting that doesn't exist in TS. + +### 5. `WorkspaceBaseEnvironment.status` typed as `WorkspaceBaseEnvironmentCache_Status` — type domain contradicts field name — `model.ts:746` +- **Why weird:** `WorkspaceBaseEnvironment.status` is typed `WorkspaceBaseEnvironmentCache_Status` — i.e. the *status of a Cache*. But the field documents itself as "The status of the materialized workspace base environment", not the status of a cache. The user reads `env.status` and the type's name implies a different concept (cache) than the doc and the data (materialization state of the environment). +- **Category:** 16 (field type contradicts type domain), 6 (misleading). +- **Suggested name:** Either (a) rename the enum to `MaterializationStatus` (the doc's own words) and drop the `Cache` and underscore (see #4), or (b) rename the field to `cacheStatus` to match the type. +- **Rationale:** Field name and type name should describe the same thing. The mismatch is a tell that the enum was named for an internal proto nesting that the public API doesn't surface. + +### 6. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:650, index.ts:27` +- **Why weird:** The type name `Operation` is one of the most generic words in software (matches OS-level, math, audit-log, business, telemetry, async-task… meanings). It is exported alongside two related types (`GetOperationRequest`, `WorkspaceBaseEnvironmentOperationMetadata`) and three classes (`CreateWorkspaceBaseEnvironmentOperation`, etc.). It is also a `google.longrunning.Operation`-shaped envelope (the docstring at model.ts:647 even says so), but the name doesn't say that. +- **Category:** 1 (vague/generic), 15 (generic type name losing meaning). +- **Suggested name:** `LongRunningOperation`, `LROperation`, `AsyncOperation`, or namespace it under the package name (`EnvironmentOperation`). Whichever wins, the request type should match: `GetLongRunningOperationRequest` etc. +- **Rationale:** A consumer importing `{Operation}` into a file that also has Slack `Operation`, audit `Operation`, or domain-specific `Operation` is in for a renaming party. The name signals nothing about being a polling envelope. + +### 7. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:675-686` +- **Why weird:** The union's discriminator field is `$case` (the `$` prefix is a wire/codegen artifact, not idiomatic TS — see `clusterlibraries` and `database` audits where the same pattern surfaces). The `'response'` variant's payload field is also called `response`, so consumers write `op.result.response.response` is *not* the access path but `op.result.$case === 'response'` then `op.result.response` is. Conflating the discriminator literal `'response'` with a payload field also named `response` is confusing. Same for `'error'` / `error`. +- **Category:** 6 (misleading — `$case`/`response`/`error` triple-overloading), 17 (inconsistency with idiomatic TS discriminated unions which use `kind` or `type`), 14 (Go/proto codegen artefact). +- **Suggested name:** Use `kind` (or `type`) instead of `$case`, and use distinct names like `kind: 'error' | 'success'` with payload fields `error: DatabricksServiceException` / `value: Record<...>` (or similar). See database audit #14 for an analogous critique. +- **Rationale:** `$` in identifiers in TS implies "internal/synthetic". This is a leak of the ts-proto codegen convention. Consumers writing `op.result?.$case` see synthetic noise. + +### 8. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:561, index.ts:19` +- **Why weird:** Three problems in one name: + 1. **`Proto` suffix** on a TypeScript identifier — leaks the proto origin into the type name (`Proto` means nothing to a TS consumer). + 2. **`Exception`** is Java/Python terminology; TS/JS uses `Error`. The type is a *data* representation of an error (it's a plain interface with `errorCode`/`message`/`stackTrace`), not an actual thrown exception class. Naming a data structure `Exception` suggests it can be thrown. + 3. **Verbose** — 41 characters. The shape is `{ errorCode, message, stackTrace, details }` — i.e. a typical Google-RPC error. +- **Category:** 20 (type-suffix tautology — `Proto`), 14 (Java-style name — `Exception`), 7 (overly verbose), 6 (misleading — looks throwable). +- **Suggested name:** `ServiceErrorDetails`, `DatabricksError`, or `RpcError`. Drop the `WithDetails`, `Proto`, and `Exception` suffix all at once. +- **Rationale:** The name has the worst of every world: Java verb + Proto codegen tag + length. No piece of the name helps a TS consumer. + +### 9. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:689, 692` +- **Why weird:** The request type is `RefreshWorkspaceBaseEnvironmentRequest` (singular), but its JSDoc says: "Request message for RefreshWorkspaceBaseEnviro**ments**" (plural). The same type's `name` field doc says: "Required. The resource name of the workspace base environment **to delete**" — i.e. copy-pasted from the delete request and never edited. The `marshalRefreshWorkspaceBaseEnvironmentRequestSchema` (model.ts:885) only emits `name`, confirming the type was forked from the delete request. +- **Category:** 9 (singular/plural mismatch — type vs doc), 6 (misleading doc — says delete). +- **Suggested name:** Fix the docstrings — say "Refresh a workspace base environment. The resource name of the environment to refresh." Either keep the type singular (matches the client method `refreshWorkspaceBaseEnvironment`) or move to plural everywhere. +- **Rationale:** Wrong action verb in a doc that an IDE will display when the user hovers a parameter. The package was generated from a proto where the message-name was singular but the doc-string copied from elsewhere — the SDK is propagating the bug. + +--- + +## Medium severity + +### 10. `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — redundant enum prefix — `model.ts:10` +- **Why weird:** Enum value `BASE_ENVIRONMENT_TYPE_UNSPECIFIED` embeds the enum name as a prefix. Access reads `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — triply redundant. `CPU` and `GPU` follow no such prefix, so the convention is inconsistent within the enum. +- **Category:** 2 (redundant enum prefix), 17 (inconsistency within the same enum), 18 (long enum values). +- **Suggested name:** Drop the prefix: `BaseEnvironmentType.Unspecified | Cpu | Gpu`. Match the wire format on the marshal side. +- **Rationale:** Proto convention; doesn't carry through the port. Note `clusterlibraries/v2/model.ts:7` exports an *identical* `BaseEnvironmentType` enum — same prefix, same inconsistency. + +### 11. `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` — 49-character enum value — `model.ts:518` +- **Why weird:** The longest enum value in the package: `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` is 82 characters total. `ADMIN` and `DATABRICKS` follow no such prefix — inconsistent within the same enum (cf. finding #10). +- **Category:** 2 (redundant enum prefix), 17 (inconsistency), 18 (long enum values). +- **Suggested name:** `Unspecified | Admin | Databricks`. +- **Rationale:** Same as #10. + +### 12. `WorkspaceBaseEnvironmentCache_Status.STATUS_UNSPECIFIED` — redundant prefix on UNSPECIFIED only — `model.ts:528` +- **Why weird:** The enum's `STATUS_UNSPECIFIED` member is prefixed but the others (`PENDING`, `CREATED`, `FAILED`, `EXPIRED`, `INVALID`, `REFRESHING`) are not — inconsistent. +- **Category:** 2 (redundant prefix), 17 (inconsistency within the same enum). +- **Suggested name:** `Unspecified | Pending | Created | Failed | Expired | Invalid | Refreshing`. +- **Rationale:** Same as #10–11. + +### 13. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` +- **Why weird:** The `ErrorCode` enum has roughly 100 members. The doc comments mark a large fraction as deprecated ("kept to maintain backwards compatibility"). Many members are domain-specific (e.g. `IPYNB_FILE_IN_REPO`, `GIT_URL_NOT_ON_ALLOW_LIST`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `DAC_ALREADY_EXISTS`) and have nothing to do with environments. The enum is a kitchen-sink import of every Databricks-platform error code, exported from a *workspace-base-environment* package. +- **Category:** 1 (overly broad — exposed in the wrong scope), 7 (overly verbose surface), 12 (duplicate concept — `ErrorCode` likely lives in many packages). +- **Suggested name:** Move to a shared `@databricks/sdk-databricks/apierror` (where `apierr/codes/` already lives, per AGENTS.md) and import it. The environments package should export at most the subset of codes it actually returns. +- **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `APIError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. + +### 14. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` +- **Why weird:** Enum values are SCREAMING_SNAKE wire strings (e.g. `MAX_CHILD_NODE_SIZE_EXCEEDED`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). 100+ values × ~30 chars each = a large surface that consumers must spell exactly. TS pattern is `PascalCase` enum members. +- **Category:** 14 (Java/Go-style names), 18 (long enum values). +- **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. +- **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. + +### 15. `DefaultWorkspaceBaseEnvironment.cpuWorkspaceBaseEnvironment` / `gpuWorkspaceBaseEnvironment` — fields stutter the type name — `model.ts:583, 588` +- **Why weird:** Field names contain the wrapping type's name three times. Read aloud: "the cpu workspace base environment field on the default workspace base environment". The values are just resource-name *strings* pointing at another `WorkspaceBaseEnvironment` ("Format: workspace-base-environments/{workspace_base_environment}"). Field names `cpu` and `gpu` plus a typed `WorkspaceBaseEnvironmentRef` would be cleaner. +- **Category:** 7 (overly verbose), 15 (generic field names — the value is just a resource name). +- **Suggested name:** `cpu` / `gpu` (with field type `string` or `WorkspaceBaseEnvironmentName`), or `cpuEnvironmentName` / `gpuEnvironmentName`. +- **Rationale:** The type is *already* `DefaultWorkspaceBaseEnvironment`. Repeating the prefix on every field makes consumers type `defEnv.cpuWorkspaceBaseEnvironment` instead of `defEnv.cpu`. + +### 16. `WorkspaceBaseEnvironment.baseEnvironmentType` / `baseEnvironmentProvider` — field prefixes duplicate parent type name — `model.ts:752, 754` +- **Why weird:** On a type called `WorkspaceBaseEnvironment`, the fields are `baseEnvironmentType` and `baseEnvironmentProvider`. The `baseEnvironment` prefix duplicates the parent. Plain `type` and `provider` would suffice. +- **Category:** 8 (redundant suffix/prefix), 7 (verbose). +- **Suggested name:** `type` (or `computeType`) and `provider`. Watch `type` — it is a reserved-like word in TS though not technically reserved. +- **Rationale:** Same logic as #15. + +### 17. `WorkspaceBaseEnvironment.filepath` — single-word run-together identifier — `model.ts:736` +- **Why weird:** `filepath` is run-together (one word in camelCase). TS/JS convention is `filePath`. The Go SDK and proto wire format both use `filepath` as one token, but in TS the camelCase rule should split it. +- **Category:** 3 (casing inconsistency), 14 (Go-style name). +- **Suggested name:** `filePath`. +- **Rationale:** Every other compound field in the type (`displayName`, `creatorUserId`, `createTime`, `lastUpdatedUserId`, `updateTime`, `isDefault`, `baseEnvironmentType`, `baseEnvironmentProvider`) uses camelCase. `filepath` is the only exception. + +### 18. `WorkspaceBaseEnvironment.message` — generic field name — `model.ts:748` +- **Why weird:** `message` is generic and could mean log message, error message, info text, user-facing description, etc. Doc says "Status message providing additional details about the environment status." `statusMessage` would be more precise. +- **Category:** 1 (vague), 15 (generic field name losing meaning). +- **Suggested name:** `statusMessage` or `statusDetails`. +- **Rationale:** Same as `DefaultBaseEnvironment.message` in clusterlibraries audit (§1.2). + +### 19. `WorkspaceBaseEnvironment.name` — generic field name, holds a resource path — `model.ts:732` +- **Why weird:** `name` is *not* a human-readable name in this API (there is a separate `displayName` for that, model.ts:734). The doc says: "The resource name of the workspace base environment. Format: workspace-base-environments/{workspace-base-environment}" — i.e. `name` is a slash-delimited *resource path*. Calling a path a `name` is a Google-AIP convention that confuses non-AIP-aware readers. +- **Category:** 6 (misleading — value is a path, not a name), 15 (generic field name), 19 (underspecified ID). +- **Suggested name:** `resourceName`, `path`, or `id`. Or document it with `(format: workspace-base-environments/...)` in the field name itself. +- **Rationale:** This pattern recurs across the package (every request type's `name` field is actually a path: `GetWorkspaceBaseEnvironmentRequest.name`, `DeleteWorkspaceBaseEnvironmentRequest.name`, `RefreshWorkspaceBaseEnvironmentRequest.name`, `GetDefaultWorkspaceBaseEnvironmentRequest.name`, `Operation.name`, `GetOperationRequest.name`). Eight different `.name` fields, each a path. + +### 20. `WorkspaceBaseEnvironment.creatorUserId` / `lastUpdatedUserId` — verb tense inconsistency — `model.ts:738, 742` +- **Why weird:** `creatorUserId` (noun: "the creator's id") vs `lastUpdatedUserId` (past-participle of verb-phrase: "the last-updated user's id"). The pair should agree. Symmetric pairs would be `creatorUserId`/`updaterUserId`, or `createdByUserId`/`lastUpdatedByUserId`. +- **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action verbs). +- **Suggested name:** Pick one form for both: `createdByUserId` / `updatedByUserId`, or `creatorUserId` / `updaterUserId`. +- **Rationale:** Internal consistency. As written, the noun↔verb mismatch reads oddly when sorted in IDE auto-complete. + +### 21. `CreateWorkspaceBaseEnvironmentRequest.workspaceBaseEnvironmentId` — 27-character optional string field — `model.ts:552` +- **Why weird:** Field name `workspaceBaseEnvironmentId` is the type name + `Id` suffix. On a `CreateWorkspaceBaseEnvironment*Request*` it is redundant — every field on a create request already pertains to a workspace base environment. Compare `requestId` (model.ts:557) on the same type, which is correctly scoped (`request`+`Id`, not `createWorkspaceBaseEnvironmentRequestRequestId`). +- **Category:** 7 (overly verbose), 8 (redundant suffix). +- **Suggested name:** `environmentId`, `id`, or `resourceId`. +- **Rationale:** Consumers writing `{workspaceBaseEnvironment: env, workspaceBaseEnvironmentId: 'foo'}` is awkward; `{environment: env, environmentId: 'foo'}` reads better. + +### 22. `listWorkspaceBaseEnvironments` and `listWorkspaceBaseEnvironmentsIter` — two list methods, only one paginates — `client.ts:248, 284` +- **Why weird:** `listWorkspaceBaseEnvironments` returns a single page (`ListWorkspaceBaseEnvironmentsResponse` with `nextPageToken`); `listWorkspaceBaseEnvironmentsIter` is an async generator that traverses all pages. The `Iter` suffix is a Go-style hint (Go's `iter.Seq`); in TS the idiomatic distinction is between "returns a Response" vs "returns an AsyncIterable", typically named `listX` (auto-paginating) vs `listXPage` (single page). +- **Category:** 14 (Go-style suffix `Iter`), 17 (inconsistent — `Iter` not used anywhere else and not idiomatic in TS). +- **Suggested name:** `listWorkspaceBaseEnvironmentsPage` (single page) and `listWorkspaceBaseEnvironments` (auto-paginating async iterable). Flip the default to the paginated one. +- **Rationale:** Consumers should fall into the pit of success: by default they want all pages. + +### 23. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:715` +- **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:715) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 720) is documented and even references `name`: "The name field is used to identify the environment to update." +- **Category:** 19 (underspecified ID), 6 (misleading by omission). +- **Suggested name:** Add JSDoc. The field is the resource name to update; say so. Or drop the field entirely if it duplicates `workspaceBaseEnvironment.name`. +- **Rationale:** Inconsistent doc coverage in a generated file is a tell that the source proto field has no comment — should be fixed upstream. + +### 24. `unmarshal*Schema` / `marshal*Schema` function names use a Go-style verb pair — `model.ts:768, 873` +- **Why weird:** The package uses `unmarshal*Schema` (from wire) and `marshal*Schema` (to wire). The verbs `marshal`/`unmarshal` are Go/Java terminology. JS/TS overwhelmingly uses `parse`/`stringify`, `serialize`/`deserialize`, `encode`/`decode`, or `fromJson`/`toJson`. The names also have a trailing `Schema` suffix that is misleading: `unmarshalXSchema` is in fact a `z.ZodType` *schema*, not a function — its name should reflect that it can be used like `XSchema.parse(...)`. But `marshalXSchema` is *also* a Zod schema with a `.transform` that turns TS→wire — also misleading because consumers might expect `marshalXSchema.parse(x)` to return wire JSON, not a parsed object. +- **Category:** 14 (Go-style names — marshal/unmarshal), 6 (misleading — these are schemas, but they have a `Schema` suffix already; the `marshal`/`unmarshal` prefix tells the user a direction but consumers may not know which). +- **Suggested name:** `xWireSchema` (for wire-format), `xModelSchema` (for TS-format), or split: `decodeX` / `encodeX` as standalone functions wrapping the schemas. +- **Rationale:** A TS consumer doesn't think in `marshal`/`unmarshal`; they think in `parse`/`format`/`fromJSON`/`toJSON`. + +--- + +## Low severity + +### 25. `WorkspaceBaseEnvironmentProvider` — name says "Provider" but values are "ADMIN" / "DATABRICKS" — `model.ts:517` +- **Why weird:** The enum's name describes a *role* dimension ("who provides this"), but the values are not consistent in part-of-speech: `ADMIN` is a noun-role-type, `DATABRICKS` is an organization name. The docstring at model.ts:516 says "Identifies *who* provides and manages a WorkspaceBaseEnvironment" — and the docstring for `ADMIN` says "Created and managed by workspace admins". So `Provider` is really `Owner` or `ProvidedBy`. Mixing `ADMIN` (a role) with `DATABRICKS` (a company) is the same kind of category-mixing as `User` / `System`. +- **Category:** 17 (inconsistency within the enum), 6 (slight misnomer). +- **Suggested name:** `WorkspaceBaseEnvironmentOwner` or `BaseEnvironmentProvidedBy`. Values: `Admin | DatabricksManaged`. +- **Rationale:** Minor. The intent is clear from context. + +### 26. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:750` +- **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:750). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:573) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. +- **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). +- **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. +- **Rationale:** Two representations of "is this the default" invite drift. + +### 27. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:628` +- **Why weird:** Page-size doc says only "Default is 1000". No documented min/max, no behavior on `0`, no behavior on values exceeding server cap. +- **Category:** 19 (underspecified). +- **Suggested name:** Add doc bounds. +- **Rationale:** Doc-only nit; not a name issue per se but worth flagging in a naming audit because `pageSize` is a known naming convention with known semantics that this doc partially undermines. + +### 28. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:638` +- **Why weird:** Field name is 27 characters; type is a list of 27-character-typed items. Reading `resp.workspaceBaseEnvironments?.[0]?.workspaceBaseEnvironment...` is a chore. (No sub-field of this exact name; included to illustrate the chain length.) +- **Category:** 7 (overly verbose), 8 (redundant suffix — same as the type name pluralised). +- **Suggested name:** `environments` (the response type is already `ListWorkspaceBaseEnvironmentsResponse`, so the plural field doesn't need to re-state the qualifier). Wire stays `workspace_base_environments`. +- **Rationale:** Matches the `clusterlibraries`/`database` audit critique that list responses don't need to repeat their qualifier. + +### 29. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:555` +- **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. +- **Category:** 19 (underspecified), 6 (slightly misleading). +- **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. +- **Rationale:** Doc-implied invariants that aren't in the type. + +### 30. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:740, 744` +- **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #20) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. +- **Category:** 14 (Google-AIP/Go-style), 13 (verb tense inconsistency), 17 (inconsistent with `lastUpdated` sibling). +- **Suggested name:** `createdAt` / `updatedAt`, or align with `creator`/`lastUpdater` — pick one verb tense and apply across the type. +- **Rationale:** Stylistic; consistent with the broader codebase critique. + +### 31. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:734` +- **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:552) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. +- **Category:** 19 (underspecified), 1 (slightly generic). +- **Suggested name:** Keep but document constraints. +- **Rationale:** Minor. + +### 32. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:736` +- **Why weird:** Doc says "The WSFS or UC Volumes path to the environment YAML file." But the field is `string`. WSFS paths and UC Volume paths have different syntaxes (`/Workspace/...` vs `/Volumes/...`). The type permits any string. A union of the two path types would be more precise but probably not worth the porting effort. +- **Category:** 19 (underspecified — the doc lists two valid path types but the type doesn't distinguish). +- **Suggested name:** Keep `filepath`/`filePath` (see #17), but document the allowed prefixes. +- **Rationale:** Minor. + +--- + +## Observation + +### 33. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` +- **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. +- **Category:** 12 (duplicate concept), 6 (misleading lineage signal). +- **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. +- **Rationale:** Generator-level; not actionable in TS alone, but worth recording. + +### 34. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` +- **Why noteworthy:** The comment on `BaseEnvironmentType` references an internal proto path that public SDK consumers cannot see, cannot navigate to, and have no use for. It's a generator-cycle reminder to Databricks engineers that shouldn't have made it through the porting/codegen scrub. +- **Category:** 6 (misleading — refers to a non-public artefact in a doc comment public users see). +- **Suggested action:** Strip internal references from generated comments at codegen time. +- **Rationale:** SDK hygiene; not a name issue but worth flagging in the audit since the comment is on a *public* type. diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md new file mode 100644 index 00000000..02118324 --- /dev/null +++ b/.agent/naming-audit/experiments.md @@ -0,0 +1,375 @@ +# Naming Audit: experiments + +**Path:** `packages/experiments/src/v1/` +**Versions audited:** v1 +**Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). +**Total weird names flagged:** 63 + +## Summary +| Severity | Count | +| --- | --- | +| High | 18 | +| Medium | 25 | +| Low | 14 | +| Observation | 6 | + +## High severity + +### 1. Package name `experiments` is too generic — `packages/experiments/` +- **Why weird:** The package is the MLflow Experiment Tracking API surface, but the package name says only "experiments". Other Databricks SDK packages own equally fuzzy nouns (`apps`, `catalogs`, `database`, `cleanrooms`) — so a reader cannot tell from `@databricks/sdk-experiments` that this is MLflow. The folder contains MLflow `Run`, `Metric`, `Param`, `Tag`, `LoggedModel` — none of which a typical Databricks user thinks of as "experiments" first. Every URL the client builds is `/api/2.0/mlflow/…` (`client.ts:206,232,262,291,317,342,370,399,428,454,483,522,556,581,615,677,717,774,869,895,925,958,988,1014,1044,1076,1106,1135,1161,1204,1237,1280,1306,1335,1361,1387`). +- **Category:** 1 (generic), 6 (misleading: name does not say MLflow). +- **Suggested name:** `mlflow`, `mlflow-tracking`, or `mlflow-experiments`. At minimum, add a JSDoc on `index.ts` saying "MLflow tracking — experiments, runs, logged models". +- **Rationale:** Every other identifier inside the package treats MLflow as the controlling brand (`mlflowParam`, `mlflowMetric`, `mlflowRunTag` appear in docstrings at `client.ts:256,1231`). The package name buries that. + +### 2. `Run` — `src/v1/model.ts:712` +- **Why weird:** The central noun is named `Run`. `Run` is a reserved-feeling word in any JS context: `Promise.all().run()`, test framework "runs", workflow "runs". The user has zero context that this is an MLflow Run (a tracked execution of a training/eval script with metrics/params/artifacts). Compare with `jobs.Run` (already a different concept in this SDK) and `pipelines.Run`. +- **Category:** 1 (vague/generic), 12 (duplicate concept across packages — `jobs.Run`, `pipelines.Run`), 15 (generic field/type name losing meaning). +- **Suggested name:** `MlflowRun` or `ExperimentRun`. Re-export the alias and deprecate `Run`. +- **Rationale:** When a consumer writes `import {Run} from '@databricks/sdk-experiments/v1'` they may already have `Run` in scope from `@databricks/sdk-jobs/v2`. The two have unrelated schemas. Disambiguating the type name removes a foot-gun. + +### 3. `Experiment` — `src/v1/model.ts:219` +- **Why weird:** Same generic-noun problem as #2. `Experiment` is a generic English word; this is specifically an MLflow Experiment (named container of MLflow Runs with a UUID and a UC artifact-location). Multiple Databricks teams may legitimately have "experiment" types in the future (notebooks?, lakehouse-experiments?). +- **Category:** 1 (generic), 15 (generic name). +- **Suggested name:** `MlflowExperiment`. +- **Rationale:** Same as #2 — disambiguating the package's central noun against future Databricks "experiments" features prevents conflicts. + +### 4. `Metric` / `Param` / `Run` / `Experiment` — all single-word top-level types — `src/v1/model.ts:219,623,667,712` +- **Why weird:** Four central types are bare nouns (`Metric`, `Param`, `Run`, `Experiment`). All four will collide with names in scope at the user's call site. None says "MLflow". `Param` in particular collides with React Router `Params`, Express `Params`, Node `URLSearchParams`, etc. +- **Category:** 1 (vague), 10 (reserved-word adjacent), 12 (duplicate concept against React/Node `Params`). +- **Suggested name:** `MlflowMetric`, `MlflowParam`, `MlflowRun`, `MlflowExperiment` — or namespace under `Mlflow.{Metric, Param, Run, Experiment}`. +- **Rationale:** Even MLflow's own protobuf calls these `mlflow.Run`, `mlflow.Experiment`, `mlflow.Metric` — they assume a namespace. Flattening them into TS without one loses that disambiguation. + +### 5. `Run`, `Experiment`, `LoggedModel`, `Metric` types vs `mlflowRun`, `mlflowMetric`, `mlflowParam` symbols in docs — `client.ts:256, 1231` +- **Why weird:** The `createRun` JSDoc at `client.ts:255-257` says: "MLflow uses runs to track the `mlflowParam`, `mlflowMetric`, and `mlflowRunTag` associated with a single execution." The names `mlflowParam`, `mlflowMetric`, `mlflowRunTag` do **not exist anywhere in the package** — the exported types are `Param`, `Metric`, `RunTag`. The docstring references symbols (probably from the Go SDK's `mlflowParam` Go type names) that the TS port no longer has. +- **Category:** 6 (misleading documentation), 14 (Go-style naming reference left in TS docs). +- **Suggested name:** Either rename the TS types to `MlflowParam` / `MlflowMetric` / `MlflowRunTag` (recommended; see #4) **or** strip the `mlflow` prefix from the docstrings to match the actual TS surface. Same problem on `searchRuns` (`client.ts:1230-1232`): "Search expressions can use `mlflowMetric` and `mlflowParam` keys". +- **Rationale:** The doc references unresolvable symbols. A reader who tries to import `mlflowParam` from the package will fail. + +### 6. `LoggedModel` — `src/v1/model.ts:560` +- **Why weird:** `LoggedModel` is a noun-phrase made of past-participle adjective + noun. The "logged" prefix is doing the disambiguation against `RegisteredModel`, `ServingModel`, `MlflowModel` etc. But (a) past-tense adjectives in type names read awkwardly (`LoggedModel`, `DeletedExperiment`, `FinishedRun` would all be similarly weird), and (b) `Logged` does not describe what the type *is* — it describes the verb history that produced it. +- **Category:** 6 (misleading: "Logged" describes history, not identity), 13 (verb-tense in noun-phrase). +- **Suggested name:** `MlflowModel`, `TrackedModel`, or `RunModel` (since every `LoggedModel` belongs to a Run via `sourceRunId`). +- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #7). + +### 7. `LoggedModel` family — 8 separate types — `src/v1/model.ts:560, 568, 579, 607, 615` + 4 request/response — `model.ts:72, 161, 169, 257, 303, 314, 475, 932` +- **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModel`, `DeleteLoggedModel`, `DeleteLoggedModelTag`, `FinalizeLoggedModel`, `GetLoggedModel`, `GetLoggedModelsRequest`, `LogLoggedModelParamsRequest`, `SetLoggedModelTags`, `SearchLoggedModels`. The `LoggedModel` prefix is repeated 14 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. +- **Category:** 7 (overly verbose), 12 (duplicate concept against `Model*` family that may exist in `modelregistry` package). +- **Suggested name:** Either drop the `Logged` and call the family `MlflowModel` / `MlflowModelData` / `MlflowModelInfo` / `MlflowModelParameter` / `MlflowModelTag` / `MlflowModelStatus`, or nest under a namespace. +- **Rationale:** 14 occurrences of "LoggedModel" in 12 identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. + +### 8. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:607` vs `model.ts:667` +- **Why weird:** Two distinct types both model `{key: string, value: string}` parameter pairs: `LoggedModelParameter` (for a `LoggedModel`) and `Param` (for a `Run`). JSDoc at line 606-612 says "Parameter associated with a `LoggedModel`" and at 666-672 "Param associated with a run". Why one type is spelled out (`Parameter`) and the other abbreviated (`Param`) is unexplained. +- **Category:** 12 (duplicate concept), 17 (inconsistent abbreviation: `Parameter` vs `Param`). +- **Suggested name:** Align the abbreviation: either both `Parameter` or both `Param`. +- **Rationale:** The difference between `Run.params: Param[]` and `LoggedModel.data.params: LoggedModelParameter[]` forces two zod schemas (`marshalParamSchema` and `marshalLoggedModelParameterSchema` at `model.ts:1819, 1759`) where the names diverge cosmetically. + +### 9. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 374, 615, 775` +- **Why weird:** Four `{key: string, value: string}` types, one per parent entity. All four have identical schemas (`marshalExperimentTagSchema`, `marshalRunTagSchema`, `marshalInputTagSchema`, `marshalLoggedModelTagSchema` at `model.ts:1635, 1655, 1769, 1857`). The only differentiator is the parent entity — but the type itself is indistinguishable. +- **Category:** 12 (duplicate concept × 4). +- **Suggested name:** Adopt a single parent prefix convention so `MlflowTag` (or `Mlflow.Tag`) carries the shared shape, with parent-specific variants only when fields actually diverge. +- **Rationale:** An end-user picking the wrong tag type (`InputTag` vs `RunTag` etc.) will not get a compile error because they have the same shape. + +### 10. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:712, 722, 732, 768` +- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:721-729`), `RunInfo` is "id, name, status, times, user" (`model.ts:732-765`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:768-773`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. +- **Category:** 1 (vague: `Data`/`Info`/`Inputs`), 15 (generic field name). +- **Suggested name:** Flatten into `Run` (one object). If they must stay split, name them by content: `RunMetadata` (instead of `RunInfo`), `RunMeasurements` (instead of `RunData`), `RunDatasetsAndModels` (instead of `RunInputs`). +- **Rationale:** `RunInfo` vs `RunData` requires the reader to look up the schema to know which fields go where. Naming by content removes that lookup. + +### 11. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:579, 568` +- **Why weird:** Same `Info`/`Data` split as `Run` (#10). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. +- **Rationale:** Same as #10. + +### 12. `GetLoggedModelsRequest` — only request type with a `Request` suffix — `src/v1/model.ts:314, client.ts:578` +- **Why weird:** Every other request type drops the `Request` suffix: `GetExperiment`, `GetRun`, `CreateRun`, `DeleteRuns`, `SearchRuns`, etc. Then `GetLoggedModelsRequest` (and its response `GetLoggedModelsRequest_Response` — note the double "Request" in the response name) breaks the pattern. `LogLoggedModelParamsRequest` (model.ts:475) and its `Request_Response` companion break it the same way. +- **Category:** 20 (type-suffix tautology), 17 (inconsistent action verbs / suffix policy), 7 (verbose). +- **Suggested name:** `GetLoggedModels` + `GetLoggedModels_Response`. `LogLoggedModelParams` + `LogLoggedModelParams_Response`. +- **Rationale:** Inconsistency within the same file. `GetLoggedModelsRequest_Response` literally reads "request's response" which is a tautology — the request shape and the response shape are different objects. + +### 13. `GetLoggedModelsRequest_Response` (and `LogLoggedModelParamsRequest_Response`) double-tautology — `src/v1/model.ts:320, 483` +- **Why weird:** Combining #12 with the proto `_Response` convention produces these absurd names. The exported identifier `GetLoggedModelsRequest_Response` contains both the `Request` suffix (#12) and the `_Response` suffix — "the request's response". +- **Category:** 20 (suffix tautology), 4 (underscore). +- **Suggested name:** `GetLoggedModels_Response` (drop the `Request`). +- **Rationale:** Pure word salad. + +### 14. `_Response` underscore convention — 32 types — `src/v1/model.ts` throughout +- **Why weird:** Every response type uses `Foo_Response` with a literal underscore: `CreateExperiment_Response`, `CreateLoggedModel_Response`, `CreateRun_Response`, `DeleteExperiment_Response`, `DeleteLoggedModel_Response`, `DeleteLoggedModelTag_Response`, `DeleteRun_Response`, `DeleteRuns_Response`, `DeleteTag_Response`, `FinalizeLoggedModel_Response`, `GetExperiment_Response`, `GetExperimentByName_Response`, `GetLoggedModel_Response`, `GetLoggedModelsRequest_Response`, `GetMetricHistory_Response`, `GetRun_Response`, `ListArtifacts_Response`, `ListExperiments_Response`, `LogBatch_Response`, `LogInputs_Response`, `LogLoggedModelParamsRequest_Response`, `LogMetric_Response`, `LogModel_Response`, `LogOutputs_Response`, `LogParam_Response`, `RestoreExperiment_Response`, `RestoreRun_Response`, `RestoreRuns_Response`, `SearchExperiments_Response`, `SearchLoggedModels_Response`, `SearchRuns_Response`, `SetExperimentTag_Response`, `SetLoggedModelTags_Response`, `SetTag_Response`, `UpdateExperiment_Response`, `UpdateRun_Response`. Each carries an `eslint-disable-next-line @typescript-eslint/naming-convention` comment, and many that are empty also disable `@typescript-eslint/no-empty-object-type`. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names), 7 (verbose). +- **Suggested name:** `CreateExperimentResponse` (no underscore). Or, in TS, declare them as a namespace: `namespace CreateExperiment { export interface Response {…} }`. Or flatten with descriptive suffix: `CreateExperimentResult`, `CreateRunResult`. +- **Rationale:** 32 lint suppressions in a single file. The convention is leaking proto naming into TS. Google TS style guide § 9.2 forbids underscores in type names. + +### 15. `LoggedModelStatus` enum members all prefixed `LOGGED_MODEL_` — `src/v1/model.ts:9-23` +- **Why weird:** Enum `LoggedModelStatus` has members `LOGGED_MODEL_STATUS_UNSPECIFIED`, `LOGGED_MODEL_PENDING`, `LOGGED_MODEL_READY`, `LOGGED_MODEL_UPLOAD_FAILED`. The enum is already `LoggedModelStatus` — every member re-states `LOGGED_MODEL_`. The first member doubles down: `LOGGED_MODEL_STATUS_UNSPECIFIED`. The others lose the `STATUS_` infix but still keep `LOGGED_MODEL_`. +- **Category:** 2 (redundant enum prefix), 17 (inconsistency: only `UNSPECIFIED` carries the full `LOGGED_MODEL_STATUS_` prefix), 18 (long enum values). +- **Suggested name:** `LoggedModelStatus.Unspecified | Pending | Ready | UploadFailed`. Or drop `Unspecified` entirely (TS supports optional fields natively). +- **Rationale:** `LoggedModelStatus.LOGGED_MODEL_UPLOAD_FAILED` reads as "logged model status: logged model upload failed" — the type name is repeated twice. Inconsistent prefix between `UNSPECIFIED` and the rest is jarring. + +### 16. `RunStatus` enum has no `UNSPECIFIED` value — inconsistent with `LoggedModelStatus` and `ViewType` — `src/v1/model.ts:26-37` +- **Why weird:** Two of the three enums in the file follow the proto-style "include UNSPECIFIED sentinel" pattern. `RunStatus` does not. Five values: `RUNNING`, `SCHEDULED`, `FINISHED`, `FAILED`, `KILLED`. Either the Run state machine has no "unknown" — fine — but the inconsistency reduces grep-ability. +- **Category:** 17 (inconsistency across enums in same file). +- **Suggested name:** Either drop `UNSPECIFIED` from `LoggedModelStatus` and `ViewType` too (best — TS uses `undefined`), or add `RunStatus.UNSPECIFIED` for symmetry. +- **Rationale:** Pick one policy. Sibling enums disagreeing on the sentinel makes patterns hard to learn. + +### 17. `KILLED` enum value — `src/v1/model.ts:36` +- **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." +- **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). +- **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. +- **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). + +### 18. `ViewType` enum — generic name + redundant value names — `src/v1/model.ts:40-47` +- **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). Three values are `ACTIVE_ONLY`, `DELETED_ONLY`, `ALL` — all SCREAMING_SNAKE_CASE TS identifiers when most TS enums use PascalCase. Plus `ALL` is a built-in reserved-feeling word and a poor key. The same enum is used as `viewType` on `ListExperiments` (model.ts:416), `runViewType` on `SearchRuns` (model.ts:897), and `viewType` on `SearchExperiments` (model.ts:800) — two fields named `viewType` and one named `runViewType` for the same enum. +- **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). +- **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Values: `ActiveOnly | DeletedOnly | All`. Field name: pick one (`viewType` everywhere, or rename uniformly). +- **Rationale:** A field that means "filter experiments/runs by deleted state" is more searchable as `lifecycleFilter`. + +## Medium severity + +### 19. `GetLoggedModels` method returns `GetLoggedModelsRequest_Response` — `src/v1/client.ts:577-608` +- **Why weird:** The method is `getLoggedModels(req: GetLoggedModelsRequest)`. Method name has no `Request` suffix, but the parameter type does. Compare to `getExperiment(req: GetExperiment)` two methods up. Same problem with `logLoggedModelParams(req: LogLoggedModelParamsRequest)` (`client.ts:921`). +- **Category:** 17 (inconsistency), 20 (suffix tautology). +- **Suggested name:** Drop the `Request` suffix on the type names to match the method names. Already raised in #12. + +### 20. `getMetricHistory` / `GetMetricHistory` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:325, client.ts:611` +- **Why weird:** Type name `GetMetricHistory` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRun`, `DeleteExperiment`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". +- **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). +- **Suggested name:** `GetMetricValues` / `getMetricValues`, or `ListMetricHistory` / `listMetricHistory` (since it paginates). +- **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. + +### 21. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:978-984` +- **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModel`, `LogModel_Response`, and `marshalLogModelSchema`. The method `createLoggedModel` is the replacement. +- **Category:** 6 (misleading — exported as if it were current). +- **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModel`, `LogModel_Response`. +- **Rationale:** A linter or IDE that reads `@deprecated` will warn users; a plaintext note in the markdown JSDoc body will not. + +### 22. `runUuid` deprecated field appears on 6 types — `src/v1/model.ts:332, 365, 389, 492, 546, 739, 949, 976` +- **Why weird:** Eight different types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. +- **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). +- **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. +- **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. + +### 23. `userId` deprecated — `src/v1/model.ts:101, 749` +- **Why weird:** Same problem as #22 but for `userId` on `CreateRun.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. +- **Category:** 6. +- **Suggested name:** Add `@deprecated`. Same as #22. + +### 24. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 587-589` +- **Why weird:** `Experiment` uses `lastUpdateTime` and `creationTime` (no unit suffix). `LoggedModelInfo` uses `creationTimestampMs` and `lastUpdatedTimestampMs` (with unit suffix). Both are Unix ms timestamps. Three things vary: (a) `Time` vs `Timestamp`, (b) `Update` vs `Updated`, (c) presence of `Ms` unit suffix. +- **Category:** 17 (inconsistency in field naming for the same concept), 3 (casing inconsistency), 9 (singular/plural-ish noun tense `Update` vs `Updated`). +- **Suggested name:** Pick one: `createdAt` / `updatedAt` (typical JS), or `creationTimeMs` / `lastUpdateTimeMs` (explicit unit). Match across `Experiment`, `LoggedModelInfo`, `RunInfo`, etc. +- **Rationale:** Three timestamp formats in one package means users guess which type uses which. + +### 25. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:753, 755` +- **Why weird:** Adds a fourth timestamp naming style to the package: bare `startTime` / `endTime` with no unit. JSDoc says "Unix timestamp of when the run started in milliseconds" — buried in prose. +- **Category:** 17 (inconsistency). +- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #24. + +### 26. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 697` +- **Why weird:** Fifth style: `DeleteRuns.maxTimestampMillis` and `RestoreRuns.minTimestampMillis` use `Millis` suffix (not `Ms`, not unsuffixed). Same package. Five different naming choices for unix-ms timestamps: `creationTime`, `lastUpdateTime`, `startTime`/`endTime`, `creationTimestampMs`/`lastUpdatedTimestampMs`, `maxTimestampMillis`/`minTimestampMillis`. +- **Category:** 17 (inconsistency × 5), 3 (casing inconsistency — `Ms` vs `Millis`). +- **Suggested name:** Pick one suffix (`Ms` is common, `Millis` is rarer) and apply uniformly. +- **Rationale:** Same as #24. + +### 27. `creatorId: number` (not string) — `src/v1/model.ts:595` +- **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." +- **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). +- **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. +- **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). + +### 28. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout +- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:622`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#27). +- **Category:** 19 (underspecified IDs coexist), 16 (`creatorId` is `number`, others `string`). +- **Suggested name:** Add prefix discipline: the model's own ID is `id` (or `modelId` everywhere); a referenced ID is `Id` (`sourceRunId`, `parentExperimentId`). Document the convention. +- **Rationale:** Today, every type has its own private convention; users must check each schema. + +### 29. `modelId` ambiguity in `Metric` — `src/v1/model.ts:643-647` +- **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. +- **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). +- **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). +- **Rationale:** Heterogeneous string ID fields are debugging traps. + +### 30. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:560-565, 579-583` +- **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#11) buries the ID one level deep. +- **Category:** 15 (generic field name losing meaning), 7 (verbose access). +- **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). +- **Rationale:** Awkward access pattern. + +### 31. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:741, 583` +- **Why weird:** Two fields named `experimentId`, two completely different relationships. On `RunInfo` the field connects the run to its parent experiment. On `LoggedModelInfo` it connects the model to its owning experiment. JSDoc only on one of them. +- **Category:** 15 (generic name losing meaning across contexts). +- **Suggested name:** Both are fine as `experimentId` if doc consistently says "parent experiment". The issue is uneven JSDoc. + +### 32. `marshalLogMetricSchema` includes deprecated `runUuid` in output — `src/v1/model.ts:1701-1723` +- **Why weird:** `marshalLogMetricSchema` writes `run_uuid: d.runUuid` to the wire, even though the field is marked deprecated. Future MLflow versions may reject this. The marshaller has no way to suppress the deprecated field unless the user explicitly leaves `runUuid` undefined. +- **Category:** 6 (misleading: TS surface lets you set a field that the API has deprecated). +- **Suggested name:** Strip `runUuid` from the marshal schema. +- **Rationale:** Defensive output filtering belongs at the SDK layer. + +### 33. Method names `getLoggedModels` / `getLoggedModelsRequest` mismatch — type is `GetLoggedModelsRequest`, method is `getLoggedModels` — `src/v1/client.ts:577` +- **Why weird:** Caller writes `client.getLoggedModels({...})` — but the type the request maps to is `GetLoggedModelsRequest`. Looking at the method name alone you wouldn't guess the type carries the `Request` suffix. +- **Category:** 17 (inconsistency). +- **Suggested name:** Already covered by #12 — drop `Request`. + +### 34. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:475` +- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:921`). +- **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). +- **Suggested name:** `AddMlflowModelParams` + `addMlflowModelParams`, or `LogParamsForModel` + `logParamsForModel`, or drop `Logged` once the rename in #7 is applied: `LogMlflowModelParams`. +- **Rationale:** The double-Log is jarring on read. + +### 35. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1276, 1302` +- **Why weird:** `setExperimentTag(req: SetExperimentTag)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTags)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). +- **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). +- **Rationale:** Cardinality should be predictable from the method name. + +### 36. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` +- **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. +- **Category:** Observation (URL design upstream). + +### 37. `logBatch` does not say "log run batch" — `src/v1/client.ts:865` +- **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. + +### 38. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +- **Why weird:** Seven log* methods with no consistent grammar: + - `logBatch` (multiple of {metric, param, tag} on a run) + - `logInputs` (datasets + models for a run) + - `logMetric` (one metric on a run) + - `logModel` (deprecated) + - `logOutputs` (models from a run) + - `logParam` (one param on a run) + - `logLoggedModelParams` (params for a LoggedModel) +- All 7 differ in cardinality, scope, and parent entity. The method names give no hint about which one to use. +- **Category:** 17 (inconsistency), 7 (verbose `logLoggedModelParams`). +- **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. +- **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. + +### 39. `LogInputs.datasets` vs `LogInputs.models` field names — `src/v1/model.ts:463-470` +- **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. +- **Category:** 15 (generic field name losing structure). + +### 40. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:770, 772` +- **Why weird:** `RunInputs.datasetInputs: DatasetInput[]` and `RunInputs.modelInputs: ModelInput[]`. The field name and the element type both carry `Input`. So a user reads `runInputs.datasetInputs[0].tags` — the word "input" appears three times in a single access path. +- **Category:** 20 (suffix tautology), 7 (verbose). +- **Suggested name:** `RunInputs.datasets: DatasetInput[]` and `RunInputs.models: ModelInput[]`. + +### 41. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` +- **Why weird:** Both fields are typed `string` and named with generic English words. JSDoc shows the wire format is freeform JSON-stringified content. The field types don't help. +- **Category:** 15 (generic field name losing meaning), 6 (misleading: schema is freeform stringified JSON, not a real schema). +- **Suggested name:** `schemaJson` / `profileJson` (mirrors `LogModel.modelJson`) so the user knows to JSON-parse them. Already see the pattern at `LogModel.modelJson` (model.ts:523). + +### 42. `LogModel.modelJson` — bare json string field — `src/v1/model.ts:519-524` +- **Why weird:** `LogModel.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. +- **Category:** Observation (an opaque blob field could carry doc). + +### 43. `Dataset.digest` — `src/v1/model.ts:124-124` +- **Why weird:** `digest` is technical jargon (cryptographic hash). MLflow uses it; consumers may not. JSDoc: "Dataset digest, e.g. an md5 hash". Could be `contentHash` or `fingerprint`. +- **Category:** 5 (cryptic abbreviation — `digest` is industry-specific). + +### 44. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:764` +- **Why weird:** `RunInfo.lifecycleStage` JSDoc says: "Current life cycle stage of the experiment : OneOf("active", "deleted")". But this is a `Run`'s `lifecycleStage`, not the experiment's. Same field on `Experiment.lifecycleStage` (model.ts:230) is correctly described. +- **Category:** 6 (misleading doc — wrong entity name in description). +- **Suggested name:** Fix doc to say "Current life cycle stage of the run". + +### 45. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 603, 728` +- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #9. The field is consistently `tags`, but the element type is not unifiable in TS without changes. +- **Category:** 17 (inconsistency at the element-type level). + +### 46. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +- **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. +- **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). +- **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. + +### 47. `FileInfo` itself is a generic name — `src/v1/model.ts:247` +- **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. +- **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). +- **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. + +## Low severity + +### 48. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` +- **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. +- **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). +- **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). + +### 49. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). +- **Category:** 17 (collision risk with `CallOptions`). + +### 50. `marshalRequest` / `parseResponse` — verbs are inconsistent — `src/v1/utils.ts:113, 119` +- **Why weird:** `marshalRequest` (verb=marshal, suffix=Request) and `parseResponse` (verb=parse, suffix=Response). Marshal is the wire-out; parse is the wire-in. The verbs (`marshal` vs `parse`) and the suffixes (`Request` vs `Response`) are split. Counterparts would be `marshal`/`unmarshal` (Go style) or `encode`/`decode`, or `serialize`/`deserialize`. +- **Category:** 17 (inconsistent verb pairing). +- **Suggested name:** `marshalRequest` / `unmarshalResponse`, matching the `unmarshal*Schema` zod schemas in `model.ts:992-1521`. + +### 51. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` +- **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) +- **Category:** Observation (dead export). + +### 52. `marshal*Schema` constants are not actually `Schema` objects — `src/v1/model.ts:1523-2009` +- **Why weird:** Constants like `marshalDatasetSchema` carry the `Schema` suffix and are typed `z.ZodType`, but the suffix in JS-land would more naturally be `Codec` or `Serializer`. `Schema` reads as "the shape definition", but these objects also perform the transformation (camelCase → snake_case). +- **Category:** 6 (slightly misleading — `Schema` implies pure shape). +- **Suggested name:** `marshalDatasetCodec` / `unmarshalDatasetCodec`. Or just keep `Schema` consistently. + +### 53. `marshalCreateExperimentSchema` etc. — Generated zod schemas with no type parameter — `src/v1/model.ts:1523` +- **Why weird:** Many `marshal*Schema` constants are typed `z.ZodType` (no type parameter). The unmarshal counterparts are typed `z.ZodType` with the target type. So the input side is unchecked. +- **Category:** Observation (looser typing on marshal vs unmarshal). + +### 54. `PACKAGE_SEGMENT` constant in `client.ts:164` — `src/v1/client.ts:164` +- **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. +- **Category:** 17 (inconsistency in identifier case across the file). +- **Suggested name:** `packageSegment` per TS conventions. + +### 55. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:165` +- **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. +- **Category:** 1 (generic name leaking into observability). + +### 56. `getMetricHistoryIter`, `listArtifactsIter`, `listExperimentsIter`, `searchExperimentsIter`, `searchRunsIter` — `Iter` suffix — `src/v1/client.ts:653, 752, 806, 1182, 1258` +- **Why weird:** Five paginating async-generators named `*Iter`. JS convention is `*Iterator` or simply `for-await-of`-friendly methods returning AsyncGenerator without a suffix. `Iter` is a Go/Rust convention. +- **Category:** 14 (Go-style suffix), 7 (cryptic abbreviation). +- **Suggested name:** `getMetricHistoryAll`, `listExperimentsAll` (returns AsyncGenerator), or `iterateExperiments`, or no suffix and use the method overload pattern. + +### 57. `searchLoggedModels` has no `*Iter` counterpart — `src/v1/client.ts:1200` +- **Why weird:** Every other search/list method has a paginating helper (`searchExperimentsIter`, `searchRunsIter`, etc.). `searchLoggedModels` is paginated (the response has `nextPageToken: model.ts:874`) but the client lacks a `searchLoggedModelsIter`. +- **Category:** 17 (inconsistency in client surface). +- **Suggested name:** Add `searchLoggedModelsIter`. + +### 58. `getLoggedModels` (batch get) has no `*Iter` — `src/v1/client.ts:577` +- **Why weird:** A batch endpoint that takes a list of IDs and returns a list. No pagination → no `Iter`. Fine. Worth noting that this is `getLoggedModels` (plural) — but `getLoggedModel` (singular, line 552) is the single-fetch. Two methods that differ only by `s` is grep-hostile. +- **Category:** Observation (grep-hostile pair `getLoggedModel` vs `getLoggedModels`). + +### 59. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 504, 633` +- **Why weird:** JSDoc on `Dataset.name`, `LogMetric.datasetName`, `Metric.datasetName` includes the literal example `“fantastic-elk-3”` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. +- **Category:** Observation (smart quotes + boilerplate example). + +### 60. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-129` +- **Why weird:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. +- **Category:** 6 (misleading — field name suggests truth, doc admits not). + +### 61. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +- **Why weird:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. +- **Category:** 16 (field contradicting type domain — should be a 2-value enum). +- **Suggested name:** `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. + +## Observations (non-actionable but noted) + +### 62. Marshal/unmarshal schema asymmetry — only unmarshal types are exported — `src/v1/model.ts:992 vs 1523` +- **Note:** Both directions exist. Only unmarshal schemas are typed (`z.ZodType`); marshal schemas are `z.ZodType` (untyped). Cross-package consumers cannot validate request bodies type-safely. + +### 63. No `experimentId` namespace prefix on most fields — generic ID pattern — `src/v1/model.ts` throughout +- **Note:** Every type that references an experiment uses `experimentId: string`; same for runs (`runId`) and models (`modelId`). When two ID kinds coexist on the same type (e.g. `Metric.modelId` + `Metric.runId`, `LoggedModelInfo.modelId` + `LoggedModelInfo.experimentId` + `LoggedModelInfo.sourceRunId`), the prefix discipline works. The naming convention is consistent — note that no `id` (bare) is ever used as a primary key, which is the right call. + +### 64. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` +- **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). + +### 65. `runViewType: ViewType` on `SearchRuns` — uses ViewType enum but renames it — `src/v1/model.ts:897` +- **Note:** Already covered in #18. The wire field is `run_view_type` (model.ts:1943); the TS field is `runViewType`. Two other usages (`ListExperiments.viewType`, `SearchExperiments.viewType`) use just `viewType`. The renaming on `SearchRuns` is unique and likely a wire-protocol legacy. + +### 66. `package.json` description is empty string — `package.json:4` +- **Note:** Every sister package has a description. Not a naming issue, but flagged for completeness. + +### 67. No `accountId` plumbing in `Client` constructor — `src/v1/client.ts:178-192` +- **Note:** Comparing to recent commit `81c7569 Add accountId to ClientOptions` — the experiments client passes the entire `ClientOptions` to `newHttpClient` so it inherits whatever account-level handling there is, but does not expose it. Not a naming issue. + +### 68. `_Response` _ underscore vs PascalCase pair — naming convention inconsistency — `src/v1/model.ts` throughout +- **Note:** Adopting a TS-friendly response naming would also require migrating the eslint suppression comments (currently `// eslint-disable-next-line @typescript-eslint/naming-convention` on every Response). 32 such suppressions in `model.ts` would all go away. diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md new file mode 100644 index 00000000..b2cb083c --- /dev/null +++ b/.agent/naming-audit/externallineage.md @@ -0,0 +1,224 @@ +# Naming Audit: externallineage + +**Path:** `packages/externallineage/src/v1/` +**Versions audited:** v1 +**Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. +**Total weird names flagged:** 31 + +## Summary +| Severity | Count | +| --- | --- | +| High | 8 | +| Medium | 11 | +| Low | 8 | +| Observation | 4 | + +## High severity + +### 1. `Direction_LineageDirection` — `src/v1/model.ts:36` +- **Why weird:** Underscore in TS identifier (proto-style nested enum name). Required `eslint-disable @typescript-eslint/naming-convention`. The outer container `Direction` is a forward-compatibility wrapper interface so the prefix is pure noise. Two parts of the name (`Direction` + `LineageDirection`) re-state the concept three times. +- **Category:** 2 (redundant enum prefix), 4 (underscore in TS identifier), 14 (Go/proto-style names), 20 (type-suffix tautology — `Direction_LineageDirection` says "direction" twice). +- **Suggested name:** `LineageDirection` (top-level, no underscore). +- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`. The `eslint-disable` directive is the smoking gun. `LineageDirection` is unambiguous on its own; the field that uses it is already named `lineageDirection`. + +### 2. `SystemType.SYSTEM_TYPE_UNSPECIFIED` and 22 other proto-style values — `src/v1/model.ts:8-33` +- **Why weird:** Every enum value is SCREAMING_SNAKE_CASE and the sentinel re-states the enum name (`SystemType.SYSTEM_TYPE_UNSPECIFIED`). The remaining 22 values include long product names (`MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`) that are sometimes split on underscores in a way that conflicts with how the rest of the SDK casefolds acronyms (e.g., `POWER_BI` vs. `POWERBI`). `UNSPECIFIED` is a protobuf import that TS does not need because the field is already `SystemType | undefined`. +- **Category:** 2 (redundant enum prefix on `SYSTEM_TYPE_UNSPECIFIED`), 3 (acronym casing — `POWER_BI` vs `MICROSOFT_FABRIC`), 14 (proto-style values), 18 (long enum values). +- **Suggested name:** `SystemType.Tableau`, `SystemType.PowerBI`, `SystemType.SqlServer`, `SystemType.Redshift`, etc., dropping `Unspecified`. +- **Rationale:** TS enum values are namespaced by the enum (`SystemType.Tableau`). SCREAMING_SNAKE_CASE is a C/proto idiom; idiomatic TS uses PascalCase enum members (see TypeScript handbook on enums and the Google TypeScript style guide). + +### 3. `CreateRequestExternalLineage` / `DeleteRequestExternalLineage` / `UpdateRequestExternalLineage` — `src/v1/model.ts:51, 74, 238` +- **Why weird:** Word-order inversion `Request` + entity instead of entity + `Request`. Every other request type in this package (`CreateExternalLineageRelationshipRequest`, `DeleteExternalLineageRelationshipRequest`) and across the SDK uses entity-then-`Request`. These three types are the nested *payload* shapes for create/delete/update (wrapped inside `*Request` outer types). All three types are structurally identical to each other AND to `ExternalLineageRelationship` (same five fields: `id`, `source`, `target`, `columns`, `properties`). +- **Category:** 12 (duplicate concept — 4 types with the same shape), 14 (Go-style naming inversion), 17 (verb-position inconsistency with rest of SDK). +- **Suggested name:** Rename to entity-first form: `CreateExternalLineagePayload` / `DeleteExternalLineagePayload` / `UpdateExternalLineagePayload`, or align with the outer `*Request` naming. +- **Rationale:** The inversion serves no purpose except to differentiate them by name from the outer request types. Entity-first matches the rest of the SDK. + +### 4. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` +- **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:563-570` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. +- **Category:** 5 (cryptic abbreviation), 10 (reserved-word collision-avoidance), 14 (Go-style "type" rename — Go SDK probably uses `Tpe` for the same reason). +- **Suggested name:** Use a TS discriminated union with `$case` directly (no outer `tpe` field): `ExternalLineageRelationshipObject = {$case: 'table', table: ...} | {$case: 'path', path: ...} | ...`. If the wrapper must stay, name the field `kind` or `objectType`. +- **Rationale:** TS allows `type` as a property name; the cryptic `tpe` is a Go-ism (Go forbids `type` as an identifier so the Go SDK works around it). Porting that workaround to TS imports a problem TS doesn't have. + +### 5. `objectInfo` field of type `ExternalLineageRelationshipObject` — `src/v1/model.ts:216` +- **Why weird:** Field is named `objectInfo` but is typed as `ExternalLineageRelationshipObject` (no `Info` in the type). The convention drift means a reader sees `objectInfo: ExternalLineageRelationshipObject` and has to mentally reconcile the two. Note the JSDoc immediately starts talking about a `object_info.table.name=...` query parameter — so on the wire, the prefix really is `object_info`, but in TS the type doesn't end in `Info`. +- **Category:** 1 (vague `Info` suffix), 8 (redundant suffix — `Info` adds nothing), 17 (field-name does not match type-name). +- **Suggested name:** `object: ExternalLineageRelationshipObject`. (Wire serialisation stays `object_info` to match the API.) +- **Rationale:** `Info` is generator filler; the type already describes itself. Field/type-name agreement reduces cognitive load. + +### 6. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` +- **Why weird:** Two top-level types share the prefix `ExternalLineage` but mean different things: `ExternalLineageInfo` is a union-of-info "row" that may describe a table, a file, a model version, or an external metadata object plus the edge metadata; `ExternalLineageRelationship` is the edge itself (id, source, target, columns, properties). The JSDoc on `ExternalLineageInfo` says "Lineage response containing lineage information of a data asset" while one of its fields is `externalLineageInfo?: ExternalLineageRelationship` — i.e., an "info" type that *contains* an "info" field whose type ends in `Relationship`. Five fields ending in `Info` (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`, `externalLineageInfo`) on a type also ending in `Info`. This is the heart of the naming muddle. +- **Category:** 1 (vague `Info` everywhere), 6 (misleading — `externalLineageInfo` is the edge metadata, not "info about external lineage"), 8 (redundant suffix), 12 (duplicate concept — `ExternalLineageInfo.externalLineageInfo` of type `ExternalLineageRelationship`). +- **Suggested name:** `ExternalLineageInfo` → `LineageNode` or `LineageEntry`. `externalLineageInfo` field → `relationship: ExternalLineageRelationship`. The four neighbour fields (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`) become `table`, `file`, `model`, `externalMetadata`. +- **Rationale:** "Info" is the generator's escape hatch for "I don't know what to call this". The current shape forces a reader to deduce that one of the `Info` fields is structurally different from the others (it's the edge, not a node). Concrete names break the muddle. + +### 7. Mixed `Info` / `Relationship` suffix vocabulary — across `src/v1/model.ts` +- **Why weird:** The package mixes three competing nouns for related concepts: `*Info` (LineageTableInfo, LineageFileInfo, LineageModelVersionInfo, LineageExternalMetadataInfo, ExternalLineageInfo), `*Relationship` (ColumnRelationship, ExternalLineageRelationship, plus six `ExternalLineageRelationship*` sub-types), and `*Object` (ExternalLineageRelationshipObject). All three trade off in the same conceptual space. A reader cannot predict which suffix a new sibling type will get. +- **Category:** 8 (redundant suffix), 12 (duplicate concept), 17 (inconsistent action-vocabulary). +- **Suggested name:** Pick one: prefer no suffix where the noun is concrete (`Table`, `Path`, `ModelVersion`, `ExternalMetadata`), `Relationship` for edges, and drop `Info`/`Object` entirely. +- **Rationale:** Three suffixes for related types make the vocabulary feel arbitrary. The Google TypeScript style guide encourages "names should reflect what something is, not its scaffolding". + +### 8. `ExternalLineageRelationshipTable` / `ExternalLineageRelationshipPath` / `ExternalLineageRelationshipModelVersion` / `ExternalLineageRelationshipExternalMetadata` — `src/v1/model.ts:158, 154, 134, 130` +- **Why weird:** Four sibling types every one prefixed with the package's longest type-name `ExternalLineageRelationship`. The naming makes them feel weighty; their position in the union does not justify the weight. Names like `ExternalLineageRelationshipExternalMetadata` are over 35 characters and convey one bit of information (which arm of the union). +- **Category:** 7 (overly verbose), 8 (redundant prefix — `ExternalLineageRelationship` is implicit from context), 20 (type-suffix tautology — `ExternalLineageRelationshipExternalMetadata` says "external" twice). +- **Suggested name:** Nest them: `ExternalLineageRelationship.Table`, `ExternalLineageRelationship.Path`, etc., via a TS namespace; or drop the prefix and name them `LineageTableObject`, `LineagePathObject`, `LineageModelVersionObject`, `LineageExternalMetadataObject`. +- **Rationale:** The redundant prefix is paid on every line that references these types. Dropping it (or nesting) shortens call sites without losing information. + +### 9. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` +- **Why weird:** Both fields are typed as `string | undefined` with no JSDoc. A reader of `{source?: string, target?: string}` has no way to know that these are *column names* (not full table.column references, not column IDs). The enclosing `ExternalLineageRelationship` has its own `source` and `target` of type `ExternalLineageRelationshipObject` — so the inner `source`/`target` of `ColumnRelationship` shadow the outer pair and add no description. +- **Category:** 1 (vague `source`/`target`), 6 (misleading — looks like the outer source/target but is column-level), 15 (generic field names lose meaning), 19 (underspecified ID — is this a column name? a path? a column lineage handle?). +- **Suggested name:** `sourceColumn?: string` / `targetColumn?: string` with JSDoc clarifying the format. +- **Rationale:** Two fields with the same names as their parent confuse the reader. Sister packages would not name a child the same as its parent. + +## Medium severity + +### 10. `Client` class — `src/v1/client.ts:45` +- **Why weird:** Class literally named `Client` at the top level of the package's API surface, re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. Same problem as every other audited package. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). +- **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. + +### 11. `marshalCreateRequestExternalLineageSchema` / `marshalDeleteRequestExternalLineageSchema` / `marshalUpdateRequestExternalLineageSchema` — `src/v1/model.ts:477, 497, 588` +- **Why weird:** Three Zod schemas named with the inverted `*RequestExternalLineage` naming (see #3). They are structurally identical — same five fields. The names burn ~37 characters each. +- **Category:** 7 (overly verbose), 12 (duplicate concept — three identical schemas), 14 (Go-style verb `marshal`). +- **Suggested name:** Collapse to one schema `marshalExternalLineageRelationshipSchema` and reuse for all three call sites. Or, if separation must be preserved for future divergence, name them `marshalCreate…RelationshipSchema` to match the entity-first convention. +- **Rationale:** Three identical schemas is generator overhead. The names re-state what the type system already says. + +### 12. `unmarshalExternalLineageRelationshipSchema` and 9 sibling Zod schemas — `src/v1/model.ts:257-465` +- **Why weird:** All Zod schemas use `marshal`/`unmarshal` (Go terminology) where TS / JS users say `encode`/`decode` or `serialize`/`parse`. Within Zod's own docs the verb is `parse`. Mixing Go vocabulary with a TS library is jarring. +- **Category:** 14 (Go-style names imported into TS), 17 (verb inconsistency — Zod's own API is `.parse()`). +- **Suggested name:** `decodeExternalLineageRelationship` / `encodeExternalLineageRelationship`, or `externalLineageRelationshipFromWire` / `externalLineageRelationshipToWire`. +- **Rationale:** Marshal/unmarshal is a Go term of art (`encoding/json` package); TS developers reach for `JSON.stringify`/`JSON.parse` or Zod's `parse`/`safeParse`. The current name forces a vocabulary translation. + +### 13. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` +- **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. +- **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). +- **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. +- **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. + +### 14. `marshalRequest(data, schema)` and `parseResponse(body, schema)` — `src/v1/utils.ts:119, 113` +- **Why weird:** The functions take an arbitrary `unknown` and a Zod schema and return JSON string / typed object. The names say "Request"/"Response" but the functions are content-agnostic. The pair also uses inconsistent verbs: `marshal` (Go) for the encode side and `parse` (TS/Zod) for the decode side. +- **Category:** 1 (vague — `Request`/`Response` does not constrain), 6 (misleading — works for any payload), 17 (asymmetric verb pair). +- **Suggested name:** `encodeJson` / `decodeJson`, or `toWireJson` / `fromWireJson`. Pair the verbs so they're symmetric. +- **Rationale:** `Request`/`Response` should refer to a request or response specifically. Symmetric verbs make the pair readable. + +### 15. `updateRequestExternalLineageFieldMaskSchema` and `updateRequestExternalLineageFieldMask(...)` — `src/v1/model.ts:646, 660` +- **Why weird:** Two exports differ only by the `Schema` suffix; the helper function and its lookup table share a stem. A reader has to look up which is the runtime schema vs. the factory function. Function/data naming should be more distinguishable. +- **Category:** 17 (inconsistent action verbs — schema is a noun, but the function uses the same name as a verbless noun). +- **Suggested name:** `buildUpdateRequestExternalLineageFieldMask(...)` for the function, leave the schema with `Schema` suffix. +- **Rationale:** Functions should be verb-prefixed; the schema-vs-builder distinction should jump off the page. Sister packages share this problem (generator-wide). + +### 16. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +- **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. +- **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). +- **Suggested name:** `makeHttpRequest` or inline at the call sites. +- **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. + +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. +- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). +- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. +- **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. + +### 18. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. +- **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). +- **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. +- **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). + +### 19. `LineageTableInfo.name` — `src/v1/model.ts:201` +- **Why weird:** Field literally called `name` with JSDoc "Name of Table." (capitalised "Table" mid-sentence). The neighbour fields are `catalogName` and `schemaName` — so the type has `(name, catalogName, schemaName)`. Inconsistent: two fields use the `*Name` suffix while the table name itself drops it. Most readers will reach for `tableName`. +- **Category:** 1 (vague — `name` of what?), 15 (generic field name losing meaning), 17 (inconsistent within the same type — `name` vs `catalogName` vs `schemaName`). +- **Suggested name:** `tableName: string` (and JSDoc punctuation fix). +- **Rationale:** Within `LineageTableInfo`, the canonical name for "the table's name" is `tableName`. Mixing `name`, `catalogName`, `schemaName` makes the table's own name look special when it isn't. + +### 20. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` +- **Why weird:** Field is `name?: string` with no JSDoc. Type is named to encode "external metadata object on the external-lineage edge". Given the wider package uses `name` for tables, models, external metadata, paths-via-`url`, the field gives up domain meaning to be terse. +- **Category:** 1 (vague `name`), 15 (generic field name), 19 (underspecified ID — for `ExternalMetadata`, the `name` is actually a fully-qualified resource path including the metastore). +- **Suggested name:** `externalMetadataName: string` with a JSDoc clarifying the expected format (mirror the `ExternalMetadata.name` JSDoc on the externalmetadata package). +- **Rationale:** `name` is the most overloaded field name in the SDK. Spelling out the entity removes the ambiguity. + +## Low severity + +### 21. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` +- **Why weird:** Field is `url?: string` on a type called `*Path`. A `Path` whose only field is a `url` — two different nouns for the same thing. Compare with `LineageFileInfo.path` and `ExternalLineageRelationshipPath.url`: the file `path` and the lineage-path `url` carry the same kind of value. +- **Category:** 1 (vague), 6 (misleading — `Path` and `url` are not the same), 12 (duplicate concept — `path` and `url` interchangeable across the package), 17 (inconsistent vocabulary). +- **Suggested name:** Either rename the type to `LineagePathObject` and call the field `path: string`, or rename the field to keep the type name: `path?: string`. +- **Rationale:** Pick one of `path` or `url` for storage location strings and stick to it. + +### 22. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#8) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. +- **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). +- **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) +- **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. + +### 23. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +- **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. +- **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). +- **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. +- **Rationale:** Type name should reflect the dominant content; current name is misleading. + +### 24. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +- **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. +- **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). +- **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. +- **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. + +### 25. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 85-92, 107, 134-186, 202-235` +- **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. +- **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). +- **Suggested name:** `rawBody` + `result` (or `parsedResponse`). +- **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. + +### 26. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` +- **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. +- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). +- **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. +- **Rationale:** Avoid forking the same identifier across two layers in the same scope. + +### 27. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` +- **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. +- **Category:** 1 (vague), 12 (duplicate concept). +- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. +- **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. + +### 28. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` +- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. +- **Category:** 1 (vague — `Segment` of what?). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. +- **Rationale:** Single word "segment" gives no domain. Pair with the comment. + +## Observations + +### 29. Method names re-state the entity verbosely +All four methods (`createExternalLineageRelationship`, `updateExternalLineageRelationship`, `deleteExternalLineageRelationship`, `listExternalLineageRelationships`) end with `ExternalLineageRelationship`. The package is *named* `externallineage`, so the entity is obvious from the import path. `client.create(...)` / `client.list(...)` would be both terser and more readable, but generator-wide consistency probably wins. +- **Category:** 7 (overly verbose) — generator-wide pattern, listed as observation only. + +### 30. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #6. +- **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). + +### 31. Wire-format singular `external_lineage_info` +The unmarshal schema at `model.ts:279` maps the wire key `external_lineage_info` (singular) onto the TS field `externalLineageInfo`. The wire is consistent with the TS muddle. Worth flagging as upstream: the API itself names the edge-metadata field `external_lineage_info` when it would more accurately be `relationship`. +- **Category:** 6 (misleading), generator-wide concern. + +### 32. `listExternalLineageRelationshipsIter` — `src/v1/client.ts:180` +- **Why weird:** Suffix `Iter` is Go-style (Go uses `*Iterator` types). TS has no `Iter` convention — typical names are `AsyncIterable`, `*Stream`, or just verb-only with the return type tagged as `AsyncGenerator`. Also the method takes the same request the non-`Iter` variant takes and silently mutates the local clone of `pageReq.pageToken` to walk pages. +- **Category:** 14 (Go-style name), 17 (action-verb inconsistency — non-iter method is `listExternalLineageRelationships`, no `List` prefix needed on the async-generator twin). +- **Suggested name:** `streamExternalLineageRelationships` or `iterateExternalLineageRelationships` (returns `AsyncIterable`). +- **Rationale:** `Iter` is Go terminology. TS convention prefers `stream`/`iterate`/`*Iterable`. + +## Domain glossary +- `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. +- `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). +- `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #22. +- `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). +- `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). +- `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. +- `oneof` / `$case` — protobuf tagged-union encoding, preserved in TS as discriminated unions keyed on `$case`. + +## File coverage +- `src/v1/model.ts` (668 lines): read fully. +- `src/v1/client.ts` (243 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (33 lines): read fully. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md new file mode 100644 index 00000000..a394b808 --- /dev/null +++ b/.agent/naming-audit/externallocations.md @@ -0,0 +1,271 @@ +# Naming Audit: externallocations + +**Path:** `packages/externallocations/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-externallocations` (workspace package; the +folder is one word `externallocations`, no hyphen, no underscore). +**Inferred domain:** Unity Catalog External Locations — manages a single +resource type "external location" (a named pointer at cloud-storage URI plus +storage credential) with five operations (create / get / list / list-iter / +update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting +sub-structure is `FileEventQueue` — an oneof-of-oneofs across four cloud +providers (Azure AQS, AWS SQS, GCP Pub/Sub, OneLake Fabric Eventstream) with a +parallel "provided" vs "managed" axis (8 cases total). +**Total weird names flagged:** 62 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +| --- | ----------------------------------------------------------------------------- | ----------------- | ------------------ | -------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | package folder `externallocations` | (package) | package | Low | 7 Overly verbose | Compound noun jammed together with no separator. Sibling packages with the same pattern: `accountaccesscontrol`, `cleanroomtaskruns`. The `npm` package is `@databricks/sdk-externallocations`. `external-locations` would be more readable but the rest of the SDK uses the same one-word convention. | +| 2 | `Client` | client.ts:44 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client`. Every package in the SDK exports a class literally named `Client`; importers must alias on collision. `ExternalLocationsClient` would self-identify. | +| 3 | `IsolationMode` enum values | model.ts:5-10 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | All four members stutter the enum name (`ISOLATION_MODE_UNSPECIFIED`, `ISOLATION_MODE_OPEN`, `ISOLATION_MODE_ISOLATED`, `ISOLATION_MODE_OPEN_IN_ACCOUNT`). TS idiom is `IsolationMode.Open`/`.Isolated`/`.OpenInAccount`. Same finding appears in `credentials.md`/`catalogs.md` — generator-wide. | +| 4 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` | model.ts:6 | enum value | Medium | 6 Misleading names, 18 Long enum values | Proto-style "Unspecified" sentinel value. The field type is `isolationMode?: IsolationMode \| undefined` — TS already expresses "unspecified" by omitting the field. The sentinel is dead. | +| 5 | `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` | model.ts:9 | enum value | Low | 18 Long enum values, 6 Misleading names | 30-char enum value; contracts to `OpenInAccount`. The domain meaning ("open scope within a single account") is opaque even after contracting. | +| 6 | `SseEncryptionAlgorithm` enum values | model.ts:12-16 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values, 3 Acronym casing | Three members `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`, `AWS_SSE_S3`, `AWS_SSE_KMS`. The first stutters the enum name (40 chars). The other two redundantly carry an `AWS_` prefix (the type name already says SSE which is AWS terminology). Should be `Unspecified`/`SseS3`/`SseKms`, or just `S3`/`Kms` since the wrapping `Sse*` already says S3-server-side. | +| 7 | `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` | model.ts:13 | enum value | Medium | 6 Misleading names, 18 Long enum values | Same proto-Unspecified pattern. The field `algorithm?: SseEncryptionAlgorithm \| undefined` already encodes "unset". | +| 8 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type vs `OneLakeEventQueue` type | model.ts:18, 28, 186, 240 | type set | Medium | (none individually, taken as set: inconsistent) | The four queue-config types use four different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix), `OneLakeEventQueue` (product + EventQueue suffix, no "Microsoft"/"Azure" prefix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`/`OneLakeConfig`. | +| 9 | `AwsSqsQueue.queueUrl` JSDoc says "AQS queue url" | model.ts:20 | doc | Medium | 6 Misleading names | The type is **AWS SQS**, but the JSDoc says "The AQS queue url" — AQS is *Azure* Queue Storage (the next type over). Copy-paste error from `AzureQueueStorage.queueUrl`. Misleading for any AWS user reading docs. | +| 10 | `GcpPubsub` (lowercase "ubsub") | model.ts:186 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | +| 11 | `AzureQueueStorage` | model.ts:28 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | +| 12 | `OneLakeEventQueue` vs `OneLake` (no Azure/Fabric prefix) | model.ts:240 | type | Low | 3 Acronym casing, 1 Vague/generic | OneLake is a Microsoft Fabric product. Other Azure-side types in the file lead with `Azure`. `OneLake` requires Fabric product knowledge to recognize. | +| 13 | `Pubsub` casing inside `GcpPubsub` | model.ts:186 | type | Low | 3 Acronym casing | GCP's product brand is "Pub/Sub". The TS type uses `Pubsub`. Consistent with field names but not with marketing. Same applies to `providedPubsub`/`managedPubsub`. | +| 14 | `DeleteExternalLocation_Response` underscore | model.ts:109 | interface | High | 4 Underscores in TS identifiers | Proto-style nested-message encoded as `Parent_Child` with a literal underscore. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` (file already has the disable on line 108). | +| 15 | `ListExternalLocations_Response` underscore | model.ts:224 | interface | High | 4 Underscores in TS identifiers | Same as #14. Disable on line 223. Underscore identifiers also propagate to `unmarshalListExternalLocations_ResponseSchema` (line 467) and `unmarshalDeleteExternalLocation_ResponseSchema` (line 343). | +| 16 | `nameArg` field | model.ts:103, 198, 263 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocation`, `GetExternalLocation`, `UpdateExternalLocation`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | +| 17 | `providedOnelake` / `managedOnelake` (case key spelling) | model.ts:176, 182 | field | Medium | 3 Acronym casing | OneLake is officially "OneLake" (camelCase capitalized "L"). The case key spells it `Onelake` (one capital). The interface name uses `OneLake` (two capitals). Inconsistent within the same file. | +| 18 | `marshal*Schema` / `unmarshal*Schema` constants | model.ts:318-746 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go idioms; JS uses `encode`/`decode` or `serialize`/`deserialize`. `Schema` is tautological with the `z.ZodType` type. Generator-wide pattern. | +| 19 | `marshalXxxSchema: z.ZodType` (no type parameter) | model.ts:501-746 | const set | Medium | (typing asymmetry) | All `marshal*Schema` exports are typed `z.ZodType` (no type argument), while `unmarshal*Schema` exports are typed `z.ZodType`. Asymmetric. The marshal side loses input-type guarantees. | +| 20 | `parseResponse` vs `marshalRequest` | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | Mixed verbs within one file: `parse`/`marshal`. Pair them as `parse`/`format`, `marshal`/`unmarshal`, or `decode`/`encode`. | + +--- + +## High severity (must fix) + +### H1. Two `IsolationMode` and `SseEncryptionAlgorithm` enums stutter their enum name + +```ts +enum IsolationMode { + ISOLATION_MODE_UNSPECIFIED = 'ISOLATION_MODE_UNSPECIFIED', + ISOLATION_MODE_OPEN = 'ISOLATION_MODE_OPEN', + ISOLATION_MODE_ISOLATED = 'ISOLATION_MODE_ISOLATED', + ISOLATION_MODE_OPEN_IN_ACCOUNT = 'ISOLATION_MODE_OPEN_IN_ACCOUNT', +} + +enum SseEncryptionAlgorithm { + SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED = 'SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED', + AWS_SSE_S3 = 'AWS_SSE_S3', + AWS_SSE_KMS = 'AWS_SSE_KMS', +} +``` + +Per the Google TypeScript Style Guide §5.6, enum members should be PascalCase +and should not redundantly carry the enum name: + +```ts +enum IsolationMode { + Unspecified, + Open, + Isolated, + OpenInAccount, +} + +enum SseEncryptionAlgorithm { + Unspecified, + S3, // or SseS3 if we want to keep the SSE marker + Kms, +} +``` + +The wire-format strings must keep their SCREAMING_SNAKE form (the API server +demands them), but the TS-side keys can be remapped via the zod `transform` +without breaking the wire. Same finding appears in `credentials.md` (M4) and +`catalogs.md` (20.3). + +### H2. `nameArg` is a generator artifact + +Three request types carry a field called `nameArg`: + +- `DeleteExternalLocation.nameArg` (model.ts:103) +- `GetExternalLocation.nameArg` (model.ts:198) +- `UpdateExternalLocation.nameArg` (model.ts:263) + +The `Arg` suffix is meaningless to a TS caller. It exists only because the +generator needs to disambiguate the path-parameter `name` from the body-field +`name` on `UpdateExternalLocation`. Renaming it to `externalLocationName` or +just `name` (and dropping the body-level `name` on Update) would clarify. + +```ts +// Today: +await client.deleteExternalLocation({nameArg: 'my-loc', force: true}); + +// Cleaner: +await client.deleteExternalLocation({name: 'my-loc', force: true}); +``` + +This finding mirrors `credentials.md` H4 and applies generator-wide. + +### H3. Two `_Response` types use underscore identifiers + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteExternalLocation_Response {} + +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface ListExternalLocations_Response { ... } +``` + +Both names use `Parent_Child` underscore encoding (proto-style nested message +names). Each requires a `// eslint-disable-next-line` because the project's +linter forbids underscores. The presence of those disables is the loudest +possible signal that the names violate the codebase's own conventions. + +Idiomatic alternatives: + +- TS namespaces: `namespace DeleteExternalLocation { interface Response {} }` +- Top-level domain names: `ExternalLocationsPage` for the list response. + +--- + +## Medium severity (worth pushing back on) + +### M1. `AwsSqsQueue.queueUrl` JSDoc says "AQS" + +```ts +export interface AwsSqsQueue { + /** + * The AQS queue url in the format https://sqs.{region}.amazonaws.com/{account id}/{queue name}. + * Only required for provided_sqs. + */ + queueUrl?: string | undefined; + // ... +} +``` + +The type is **AWS SQS**, but the doc string starts "The AQS queue url" — AQS +is Azure Queue Storage. Copy-paste error from the sibling `AzureQueueStorage.queueUrl` +JSDoc (lines 29-32). Wire-format example string is correct (AWS SQS); only the +prose is wrong. Confusing for any AWS user. + +### M2. The four cloud-provider queue types use four different naming conventions + +```ts +interface AwsSqsQueue { ... } // cloud + service + Queue +interface AzureQueueStorage { ... } // cloud + product, no suffix +interface GcpPubsub { ... } // cloud + product, no suffix +interface OneLakeEventQueue { ... } // product + EventQueue suffix, no Microsoft/Azure prefix +``` + +Four naming patterns for four parallel types. Pick one: + +- All with `Queue` suffix: `AwsSqsQueue`, `AzureAqsQueue`, `GcpPubsubQueue`, + `OneLakeQueue`. +- All without: `AwsSqs`, `AzureQueueStorage`, `GcpPubsub`, `OneLakeEventStream`. +- All as `Config`: `AwsSqsConfig`, `AzureAqsConfig`, etc. + +### M3. `OneLake` casing inconsistency + +The type name is `OneLakeEventQueue` (two capitals). The discriminator case +keys are `providedOnelake` / `managedOnelake` (one capital `L`, lowercased). +The wire format is `provided_onelake` / `managed_onelake` (all lowercase). +Within one file the brand name is rendered three different ways. Microsoft's +spelling is "OneLake". + +### M4. `AzureQueueStorage` vs `Aqs` abbreviation + +The interface name is `AzureQueueStorage`, but two of its consumers (the +discriminator case keys `providedAqs`/`managedAqs` and the wire-format string +`provided_aqs`/`managed_aqs`) use the abbreviation `AQS`. The abbreviation is +not standard Microsoft terminology — Microsoft's docs call this "Azure Queue +Storage" or "Azure Storage Queues". `AQS` is Databricks-internal shorthand. + +### M5. `Pubsub` casing + +GCP's product is "Pub/Sub" (with slash and two capitals). The TS type is +`GcpPubsub` (one capital). Internally consistent (the discriminator cases +`providedPubsub`/`managedPubsub` match), but not the canonical GCP spelling. + +### M6. `marshal*Schema: z.ZodType` (no type parameter) + +```ts +export const marshalCreateExternalLocationSchema: z.ZodType = z.object({ ... }); +``` + +vs + +```ts +export const unmarshalExternalLocationInfoSchema: z.ZodType = ... +``` + +Asymmetric. The marshal side loses input-type guarantees. A consumer who +passes the wrong shape to `marshalRequest(data, marshalCreateExternalLocationSchema)` +gets a runtime error instead of a TS error. + +--- + +## Low severity (nits) + +_None._ + +--- + +## Cross-cutting observations (not flags) + +### Generator marker + +Every file is prefixed with `// Code generated from API definition by +Databricks SDK Generator. DO NOT EDIT.` All naming issues here must be fixed +upstream in the generator/spec. + +### Optionality model + +Every field is `T | undefined`. Matches the repo's `exactOptionalPropertyTypes` +setting. Consistent across the SDK. + +### Acronym inventory + +The following acronyms appear: + +| Acronym | Casing in code | Notes | +| -------- | ---------------- | ----------------------------------------------------------- | +| AWS | `Aws` | Initialism-as-word per Google TS Style Guide. | +| S3 | `S3` (in `AWS_SSE_S3`); `s3` (JSDoc on line 250) | Mixed. | +| SQS | `Sqs` | Initialism-as-word. | +| SSE | `Sse` | Initialism-as-word. | +| KMS | `Kms` | Initialism-as-word. | +| ARN | `Arn` | Initialism-as-word. | +| IAM | not in this pkg | Used in sibling packages with `Iam` initialism-as-word. | +| Azure | `Azure` | Not an acronym. | +| AQS | `Aqs` | Databricks-internal abbreviation, not Microsoft canonical. | +| GCP | `Gcp` | Initialism-as-word. | +| Pub/Sub | `Pubsub` | Non-canonical (Google spells `Pub/Sub`). | +| OneLake | `OneLake` (type), `Onelake` (case keys) | Inconsistent. Microsoft spells `OneLake`. | +| URL | `url` (lower; field name); `Url` (in `queueUrl`, `eventHubUrl`) | Standard. | +| ID | `Id` (in `metastoreId`, `credentialId`, `managedResourceId`, `subscriptionId`) | Initialism-as-word. | + +--- + +## Summary + +20 findings: + +- **3 High severity** — enum stutter, `nameArg` artifact, underscore TS + identifiers. +- **6 Medium severity** — `AQS` JSDoc copy-paste error in AWS type, + naming-pattern inconsistency across the four queue types, OneLake casing + inconsistency, AQS abbreviation, Pubsub casing, `marshal*Schema` type-parameter + asymmetry. +- **0 Low severity (nits)**. + +Primary themes: + +1. **Generator-encoded proto patterns dominate**: underscore-named nested + message types, SCREAMING_SNAKE enum members, the `marshal`/`unmarshal` + verbs, and the `nameArg` path-vs-body disambiguation are all proto/Go-SDK + artifacts that idiomatic TS would express differently. +2. **Cloud-provider naming is internally inconsistent**: four queue-config + types with four different naming conventions, OneLake spelled three ways, + AQS abbreviation that isn't Microsoft canonical, copy-paste error mixing + AWS SQS and Azure AQS in one JSDoc. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md new file mode 100644 index 00000000..539f8a98 --- /dev/null +++ b/.agent/naming-audit/externalmetadata.md @@ -0,0 +1,285 @@ +# Naming Audit: externalmetadata + +**Path:** `packages/externalmetadata/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. +**Total weird names flagged:** 40 + +## Summary +| Severity | Count | +| --- | --- | +| High | 11 | +| Medium | 13 | +| Low | 11 | +| Observation | 5 | + +## High severity + +### 1. `SystemType.SYSTEM_TYPE_UNSPECIFIED` — `src/v1/model.ts:9` +- **Why weird:** Sentinel re-states the enum name (`SystemType.SYSTEM_TYPE_UNSPECIFIED`). The field that uses this enum is already `systemType?: SystemType | undefined` — idiomatic TS expresses "unset" as `undefined`, making a third "unspecified" value pure protobuf import. +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names). +- **Suggested name:** Drop the sentinel entirely and rely on `undefined`, or rename to `SystemType.Unknown`. +- **Rationale:** TS enum members are namespaced by the enum (`SystemType.Unknown`). The `SYSTEM_TYPE_` prefix on every member is protobuf-import noise that the language already solves with namespacing. + +### 2. `SystemType.OTHER` — `src/v1/model.ts:10` +- **Why weird:** Generic catch-all value with no semantic indicator that it is a fallback. A user encountering `SystemType.OTHER` cannot tell if it means "data not yet classified", "vendor we don't support", or "user-provided custom system". Compare to `SystemType.SYSTEM_TYPE_UNSPECIFIED` which at least signals it is a sentinel. +- **Category:** 1 (vague — `OTHER` is the most generic possible name), 15 (generic field/value name losing meaning). +- **Suggested name:** `SystemType.Custom` or `SystemType.UserDefined` (whichever matches the API semantics). +- **Rationale:** `OTHER` as an enum value is the value-side equivalent of naming a field `data`. JSDoc on the enum, or a more specific value name, would tell readers when to reach for it. + +### 3. `SystemType` value casing — `POWER_BI`, `MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `AZURE_SYNAPSE`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`, `STREAM_NATIVE`, `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE`, `WORKDAY`, `TABLEAU`, `LOOKER`, `KAFKA`, `MYSQL`, `ORACLE`, `SAP`, `SNOWFLAKE`, `TERADATA`, `CONFLUENT`, `DATABRICKS` — `src/v1/model.ts:10-32` +- **Why weird:** Vendor names are proper nouns with canonical brand casing (Power BI, Microsoft SQL Server, Amazon Redshift, BigQuery, PostgreSQL, MongoDB, ServiceNow, Tableau). Wire SCREAMING_SNAKE collapses every brand to a flat shout. Also: split rules are inconsistent — `POWER_BI` and `MICROSOFT_SQL_SERVER` split on word boundary, but `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE` join compounds without underscore. +- **Category:** 3 (acronym casing inconsistency across vendor names), 18 (long enum value set). +- **Suggested name:** Either keep wire SCREAMING_SNAKE (current) and document, or move TS-side to PascalCase brand casing (`SystemType.PowerBI`, `SystemType.MicrosoftSqlServer`, `SystemType.Postgres`, `SystemType.MongoDb`). Pick one split convention: word-bound (`POSTGRE_SQL`, `MONGO_DB`, `SERVICE_NOW`, `SALES_FORCE`) or joined (`POWERBI`, `MICROSOFTSQLSERVER`). +- **Rationale:** Vendor names are proper nouns. A user typing `SystemType.MongoDB` won't autocomplete to `MONGODB`. Within the set there is no reproducible rule (compare `POWER_BI` split vs `POSTGRESQL` joined). Probably wire-locked, but worth flagging upstream. + +### 4. `SystemType.STREAM_NATIVE` — `src/v1/model.ts:32` +- **Why weird:** The vendor is "StreamNative" (one camelCased brand name), but the wire splits it as `STREAM_NATIVE`. Compare: `SERVICENOW` (joined, brand is "ServiceNow") vs `STREAM_NATIVE` (split, brand is "StreamNative"). The split rule is unprincipled. +- **Category:** 3 (acronym/brand casing inconsistency), 18 (long value). +- **Suggested name:** `STREAMNATIVE` (matches `SERVICENOW`) or fix `SERVICENOW` -> `SERVICE_NOW`. Pick one. +- **Rationale:** Sibling brand names with the same shape (one-word camelCased) should encode identically. The current internal inconsistency makes the type non-discoverable. + +### 5. `ExternalMetadata` — `src/v1/model.ts:43` +- **Why weird:** The central domain entity is named after the package, which is a noun phrase but not a noun ("External Metadata" is more an adjective+noun phrase than a thing). Compare: `Catalog`, `Connection`, `Schema` are crisp nouns; `ExternalMetadata` reads like a category, not an instance. Also: every field has the doc-string suffix "external metadata object" — the type is essentially `XxxObject` without the suffix, but the docs need it because the bare type name lacks objecthood. +- **Category:** 1 (vague — what is "an External Metadata"?), 6 (misleading: name reads as a kind, not an instance). +- **Suggested name:** `ExternalAsset` or `ExternalEntity` (the type already has a `entityType` field describing what shape of external thing it is). Alternatively, embrace the proto-canonical name with `ExternalMetadataObject`. +- **Rationale:** Reading `const x: ExternalMetadata = ...` does not communicate that `x` is a single named external asset. The JSDoc fix ("external metadata object") betrays that the type name needs help to read as a noun. Worth raising upstream. + +### 6. `ExternalMetadata.name` (and `req.name` in Get/Delete/Update) — `src/v1/model.ts:45,40,81` +- **Why weird:** Field literally called `name` on an entity that uses `name` as the unique identifier in REST path segments (`/api/2.0/lineage-tracking/external-metadata/${req.name}`). The entity also has both `name` AND `id` (line 71) — two different identifier-shaped fields with no doc differentiation beyond "Unique identifier of the external metadata object" on `id` and "Name of the external metadata object" on `name`. +- **Category:** 1 (vague — `name` is the canonical too-generic field name), 12 (duplicate concept — `name` and `id` both feel identity-shaped), 19 (underspecified ID). +- **Suggested name:** Either rename to `objectName` / `assetName` and document the format constraint, or drop `id` if `name` is the canonical key. JSDoc must explain when callers use `name` vs `id`. +- **Rationale:** Co-existence of `name?: string` and `id?: string` with no semantic separation in docs is a recipe for caller confusion. The URL routing uses `name` as the path segment, suggesting `name` is the canonical key; `id` is the implementation-detail UUID. The type does not communicate this. + +### 7. `ExternalMetadata.id` — `src/v1/model.ts:71` +- **Why weird:** Field `id` exists alongside `name`. JSDoc says "Unique identifier" — but `name` is also a unique identifier (the URL path key). Bare `id` without further qualification gives no hint that this is the system-generated UUID vs. the human-readable name. Also: bare `id: string` is rule-19 underspecified — no format constraint visible at the type. +- **Category:** 1 (vague), 12 (duplicate concept with `name`), 19 (underspecified ID). +- **Suggested name:** `objectId` / `assetId` / `externalMetadataId`, or drop entirely if `name` is the canonical key. +- **Rationale:** Two unique identifiers on one type with no doc differentiation forces every caller to read the API docs to know which to use. The type should name the difference. + +### 8. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` +- **Why weird:** Type name carries the API version suffix `V2`, but the enclosing file is already `v1/model.ts` and the package is mounted at `./v1`. Version is encoded twice — once in the directory, once in the type. If the user later imports a hypothetical `v2/`, they would get `V3`? Versioning the entity name within the version namespace creates an off-by-one collision risk. +- **Category:** 8 (redundant suffix — version is in the path), 20 (type-suffix tautology between version-in-path and version-in-name), 14 (Go/proto-style — Go SDK carries the `V2` per RPC name; TS doesn't need it). +- **Suggested name:** `ListExternalMetadataResponse` (drop `V2`). +- **Rationale:** The directory is the namespace. Embedding the wire RPC version into the TS type name leaks an internal detail of the generator. If the package later gets a `v2/` directory, every type there ends up `V3` (one ahead of the dir), which is worse than the original problem. + +### 9. `Client.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:70,102,124,154,190,212` +- **Why weird:** Every public method on `Client` ends with `V2`, but the directory is `v1/`. The version suffix is wire-RPC-name leakage (the upstream API is `ExternalMetadataServiceV2.Create`, hence `createExternalMetadataV2`). User code reads `client.createExternalMetadataV2(...)` for a method on a `v1/` import — confusing on first read. +- **Category:** 8 (redundant suffix), 14 (Go/proto-style name leak), 20 (type/version suffix tautology). +- **Suggested name:** `createExternalMetadata`, `deleteExternalMetadata`, etc. (drop `V2`). +- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #8; generator-wide concern. + +### 10. `ExternalMetadata_PropertiesEntry` — `src/v1/model.ts:75` +- **Why weird:** Underscore in TS identifier (proto-style nested message generated by protobuf for `map` map entries). Required `eslint-disable @typescript-eslint/naming-convention`. +- **Category:** 4 (underscore identifier), 14 (proto-style nested message). +- **Suggested name:** Hoist to `PropertyEntry` (no underscore, no enclosing-type prefix). +- **Rationale:** The eslint-disable directive is the smoking gun that the name fights the language. TS identifiers should not contain underscores; the proto-generated `Type_NestedType` form is a code-generator artifact that should be flattened on the TS side. + +### 11. `Client` — `src/v1/client.ts:41` +- **Why weird:** Class literally named `Client` at the top level of the package's surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code collide on import: `import {Client} from '@databricks/sdk-externalmetadata'` and `import {Client} from '@databricks/sdk-catalogs'` both fight for the same identifier. +- **Category:** 1 (vague — `Client` is the most generic name), 15 (generic name). +- **Suggested name:** `ExternalMetadataClient` (matches the package name and avoids collisions on combined imports). +- **Rationale:** A user combining packages must alias on every import (`import {Client as ExternalMetadataClient}`). Sister packages all share this problem — generator-wide rename worth raising upstream. + +## Medium severity + +### 12. `ExternalMetadata.systemType: SystemType` — `src/v1/model.ts:47` +- **Why weird:** Type-suffix tautology — field `systemType` of type `SystemType` on a type called `ExternalMetadata`. Reads `externalMetadata.systemType: SystemType` — three "type"s in one declaration. +- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). +- **Suggested name:** `system: SystemType` (would read `externalMetadata.system`). +- **Rationale:** When the field's type already encodes "type", the field itself doesn't need to. Compare: `externalMetadata.system` reads cleaner than `externalMetadata.systemType`. + +### 13. `ExternalMetadata.entityType` — `src/v1/model.ts:49` +- **Why weird:** Field `entityType` is typed `string` (free-form) rather than `EntityType` (an enum). Pairs awkwardly with `systemType: SystemType` two lines above — one is enumerated, the other is freeform string. The user has no idea what valid `entityType` values are without consulting external docs. +- **Category:** 1 (vague), 6 (misleading — `Type` suffix implies a closed set, but it's freeform), 15 (generic field name losing meaning), 17 (inconsistency — `systemType` is closed enum, `entityType` is open string). +- **Suggested name:** `entityKind` (less enum-implying), or define an `EntityType` enum if a closed set exists. +- **Rationale:** A field named `xxxType: string` strongly suggests an enum without one. JSDoc says "Type of entity within the external system" — but for Tableau the entity might be a dashboard/workbook; for Kafka, a topic. Closed-set values would help; absent that, the name should not over-promise. + +### 14. `ExternalMetadata.url` — `src/v1/model.ts:51` +- **Why weird:** Casing of acronym. The codebase uses `url` (lowercase) consistently for the property, but the Web platform/standards canonical is `URL` (uppercase). Compare to `userAgent` (camelCase) and `URLSearchParams` (Web standard SCREAMING). Internal inconsistency between `url` (field) and `URLSearchParams` (function/class). +- **Category:** 3 (acronym casing). +- **Suggested name:** Keep `url` (TS convention), but acknowledge the JS-ecosystem split. +- **Rationale:** The JS world is split here — Node, browsers, and the URL spec all use `URL` for the class and `url` for member fields. Internal consistency within this file is preserved (`url` everywhere); the rule is conventional, not broken. + +### 15. `ExternalMetadata.description` — `src/v1/model.ts:53` +- **Why weird:** Field `description` is on the entity but is "User-provided free-form text description" per JSDoc — i.e., not a generated description, not a vendor description, but specifically a description set by the metadata owner. The plain name `description` does not convey "you supply this". +- **Category:** 1 (vague — `description` is the canonical too-generic field name). +- **Suggested name:** `userDescription` or keep `description` and rely on JSDoc. +- **Rationale:** Minor — `description` is the universal expectation. JSDoc is doing the work. Listed for completeness. + +### 16. `ExternalMetadata.columns: string[]` — `src/v1/model.ts:55` +- **Why weird:** `columns` is typed as `string[]` (just names), but the JSDoc reads "List of columns associated with the external metadata object". A `Column` in Unity Catalog terms is a structured `{name, type, nullable, ...}` object — calling a list of column names `columns` invites the reader to expect structure that is not there. +- **Category:** 6 (misleading — `columns` implies structured objects, is just names), 15 (generic field name losing meaning). +- **Suggested name:** `columnNames: string[]` (matches the contents). +- **Rationale:** When the field type and field name disagree about whether the values are objects or strings, the type wins (it has to compile); the name is the bug. `columnNames` is unambiguous. + +### 17. `ExternalMetadata.properties` — `src/v1/model.ts:57` +- **Why weird:** Field name is the literal type-system-builtin reserved word for "object members" (`Object.properties`, `props`, etc). The map's role is "user-defined custom metadata" but the name `properties` is the most generic possible for a `Record`. Also: `properties` co-exists with `metastoreId`, `owner`, `createdBy`, etc., which are *also* properties. +- **Category:** 1 (vague), 6 (misleading — every other field is also a "property"), 10 (reserved-word-adjacent — `properties` clashes with `Object.properties`). +- **Suggested name:** `tags`, `labels`, `attributes`, or `customProperties` — whatever the API doc calls them. +- **Rationale:** `properties` on a `Record` is bag-of-strings naming. A user reading `externalMetadata.properties.foo` cannot tell if `foo` is intrinsic or user-extended. + +### 18. `ExternalMetadata.owner` — `src/v1/model.ts:59` +- **Why weird:** Field `owner: string | undefined` with no hint of format. JSDoc says "Owner of the external metadata object" — owner is a Unity Catalog principal (user, group, or service principal). Common sister-package convention names this `owner` consistently, but a user has no idea what string format to put (`alice@example.com`? `users/alice`? a UUID?). Same problem applies to `createdBy` (line 65) and `updatedBy` (line 69). +- **Category:** 1 (vague), 19 (underspecified ID — what format is the principal?). +- **Suggested name:** Keep `owner` but document format. Or `ownerPrincipal`, matching other UC packages. +- **Rationale:** Bare `owner: string` is the canonical UC principal-as-string pattern across the SDK, but the type does not communicate format. Minor — sister-package convention is the same. Listed for visibility. + +### 19. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` +- **Why weird:** Bare `metastoreId: string | undefined` — a UUID identifier on a UC metastore, but the type does not hint at the format. Idiomatic across the SDK; here mentioned only for rule-19 completeness. Also note: this field is "Unique identifier of parent metastore" but `parent` is not named — the metastore relationship is communicated via the `metastoreId` field alone, not a `parent` field per AIP-160. +- **Category:** 19 (underspecified ID — `string` doesn't tell you it's a UUID). +- **Suggested name:** Keep `metastoreId` (canonical across SDK). +- **Rationale:** SDK-wide pattern; field name is fine. Listed for completeness. + +### 20. `ExternalMetadata.createTime` / `updateTime` — `src/v1/model.ts:63,67` +- **Why weird:** Verb-tense / part-of-speech inconsistency with `createdBy` and `updatedBy` (lines 65, 69). Times use the imperative ("create"); user fields use past-tense ("created"). A consistent set would be `createdAt` + `createdBy` and `updatedAt` + `updatedBy`. The Go SDK uses `create_time`/`update_time` on the wire; TS does not have to follow. +- **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action-tense pair). +- **Suggested name:** `createdAt: Temporal.Instant` + `updatedAt: Temporal.Instant` (preserves the `createdBy`/`updatedBy` past-tense pair). +- **Rationale:** Sibling fields should agree on tense. `createTime`/`createdBy` mixes imperative + past-tense for one event. JS/TS canon is `createdAt`/`updatedAt` (e.g., NoSQL drivers, Sequelize, TypeORM, Prisma). + +### 21. `ExternalMetadata.updateTime` vs. `Client.updateExternalMetadataV2` — `src/v1/model.ts:67, src/v1/client.ts:212` +- **Why weird:** "Update" as a verb is overloaded — it names both an action (the PATCH method) and a state field (the last-modified timestamp). On the same entity, reading `externalMetadata.updateTime` while a request to `updateExternalMetadata` is in flight is confusing. +- **Category:** 12 (duplicate concept), 17 (verb noun-vs-action collision). +- **Suggested name:** `modifiedAt`/`modifiedBy` for the state, leave `update` for the action. +- **Rationale:** Separating timestamp ("modified") from operation ("update") prevents the reader from conflating "this was just updated" with "this is being updated right now". + +### 22. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` +- **Why weird:** Field name `updateMask` doesn't say what kind of mask. In context the mask describes "which fields to patch". The Google AIP-134 convention names this `updateMask`; the TS-idiomatic name would describe contents (`fieldsToUpdate`, `patchedFields`, `paths`). +- **Category:** 1 (vague), 14 (Google-AIP-style name). +- **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. +- **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. + +### 23. `marshalExternalMetadataSchema` / `unmarshalExternalMetadataSchema` — `src/v1/model.ts:157,104` +- **Why weird:** Zod schemas, but named with Go terminology (`marshal`/`unmarshal`) where TS / JS users say `encode`/`decode` or `serialize`/`parse`. Within Zod's own docs the verb is `parse`. Mixing Go vocabulary with a TS library is jarring. +- **Category:** 14 (Go-style names imported into TS), 17 (verb inconsistency — Zod's own API is `.parse()`, not `.unmarshal()`). +- **Suggested name:** `encodeExternalMetadataSchema` / `decodeExternalMetadataSchema`, or `externalMetadataToWireSchema` / `externalMetadataFromWireSchema`. +- **Rationale:** Marshal/unmarshal is a Go term of art; TS developers reach for `JSON.stringify`/`JSON.parse` or Zod's `parse`/`safeParse`. The current name forces a vocabulary translation. + +### 24. `externalMetadataFieldMaskSchema` and `externalMetadataFieldMask(...)` — `src/v1/model.ts:197,214` +- **Why weird:** Two exports differ only by the `Schema` suffix; the helper function and its lookup table share a stem. A reader has to look up which is the runtime config vs. the factory. Function/data naming should be more distinguishable. +- **Category:** 17 (inconsistent action verbs — schema is a noun, but the function uses the same name as a verbless noun). +- **Suggested name:** `buildExternalMetadataFieldMask(...)` for the function, leave the schema with `Schema` suffix. +- **Rationale:** Functions should be verb-prefixed; the schema-vs-builder distinction should jump off the page. Sister packages share this problem (generator-wide). + +### 25. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. +- **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). +- **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. +- **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. Same pattern across sister packages — generator-wide concern. + +### 26. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` +- **Why weird:** The function takes an arbitrary `unknown` value plus a Zod schema and returns a JSON string. The name says "Request" but the function does not know whether `data` is a request, response, or anything else — it is a generic JSON-encoder against a Zod schema. +- **Category:** 1 (vague — `Request` in the name does not constrain), 6 (misleading — works for any payload, not specifically requests). +- **Suggested name:** `marshalToJson` / `encodeToJson` / `toWireJson`. +- **Rationale:** The function is symmetric to `parseResponse`, which has the same problem in reverse. `Request`/`Response` should be specific to their meaning. + +### 27. `parseResponse(body, schema)` — `src/v1/utils.ts:113` +- **Why weird:** Symmetric problem to `marshalRequest`. The function parses any JSON `Uint8Array` against a Zod schema. The name says "Response" but the function does not check that. +- **Category:** 1, 6. +- **Suggested name:** `parseJsonBody` / `decodeFromJson` / `fromWireJson`. +- **Rationale:** Same as #26. `marshalRequest` + `parseResponse` are an asymmetric verb pair (`marshal` vs. `parse`) AND inaccurate. Either fix both. + +### 28. `Client.listExternalMetadataV2Iter` — `src/v1/client.ts:190` +- **Why weird:** The `Iter` suffix is Go SDK convention for "returns an iterator". In TS, async iterators are a first-class language feature with their own conventions; the canonical name would be `listExternalMetadataV2()` returning `AsyncIterable` (a single iterator method, not a parallel `Iter` variant). Pairing the page-returning `listExternalMetadataV2` with an `Iter` cousin is a Go pattern leaking through. +- **Category:** 14 (Go-style name), 5 (cryptic abbreviation — `Iter`), 12 (duplicate concept — two methods that differ only by what they return). +- **Suggested name:** `iterateExternalMetadata` (clear) or rename the pair: `listExternalMetadataPage(...)` (returns one page) + `listExternalMetadata(...)` (returns iterator). Or use a single dual-purpose method. +- **Rationale:** Generator-wide concern; the `Iter` suffix is a direct Go-SDK port. TS has `for await (...)` and would idiomatically expect either a single method returning an iterable, or `iterate*` / `*Stream` / `*Pages` to distinguish from the page-returning method. + +## Low severity + +### 29. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` +- **Why weird:** Four (five) request DTOs repeat the noun `ExternalMetadata` even though the entire package operates on exactly one entity (the only thing this package does is CRUD `ExternalMetadata`). In context, `CreateRequest`/`UpdateRequest` would be plenty. +- **Category:** 7 (overly verbose), 8 (redundant suffix and infix). +- **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`/`ListRequest`, or drop the `Request` suffix entirely if request DTOs follow a sibling-naming pattern (`Create`, `Update`, etc.). Cross-SDK consistency makes this a low rather than high. +- **Rationale:** The whole package operates on one entity; repeating it in every request type is pure noise. SDK-wide pattern means a local fix risks inconsistency. + +### 30. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` +- **Why weird:** Singular/plural mismatch. The field holds an array but is named `externalMetadata` (singular). Convention is plural for arrays (e.g., `connections: Connection[]` in sister packages). Compare: `nextPageToken` is singular because it's a single token. +- **Category:** 9 (singular/plural mismatch), 20 (type-suffix tautology — `externalMetadata: ExternalMetadata[]`). +- **Suggested name:** `items: ExternalMetadata[]` or `externalMetadataObjects: ExternalMetadata[]` or `assets`. Wire stays `external_metadata`. +- **Rationale:** "Metadata" is a mass noun (uncountable), which is why the generator left it singular. A plural-aware name like `items` or `assets` reads naturally. + +### 31. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. +- **Category:** 1 (vague — `Segment` of what?). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. +- **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. + +### 32. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` +- **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). +- **Category:** 1 (vague), 12 (duplicate concept). +- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. +- **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. + +### 33. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` +- **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). +- **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). +- **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. + +### 34. `pageReq` — `src/v1/client.ts:194` +- **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). +- **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). +- **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. + +### 35. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +- **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. +- **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). +- **Suggested name:** `requestBody: string | ReadableStream`. +- **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. + +### 36. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. +- **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). +- **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. +- **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. + +### 37. `readAll(body)` — `src/v1/utils.ts:40` +- **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". +- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). +- **Suggested name:** `drainStream` or `readStreamToUint8Array`. +- **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. + +### 38. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. +- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). +- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. +- **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. + +## Observations + +### 39. Wire/TS divergence is heavy +The `model.ts` file is 222 lines for ~7 user-facing types (one entity + five request types + one response). Roughly 60% of the file is `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. Not a naming problem per se, but the audit consistently surfaces how much generator boilerplate dominates each package. + +### 40. Identifier doubling for path + UUID +The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #6 and #7. + +### 41. Action-verb conventions in `Client` +The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Iter` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. The `Iter` suffix (see #28) is the only outlier on verb choice. + +### 42. Acronym casing +The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. +- **Category:** 3 (acronym casing). + +### 43. `externalmetadata` lowercase package name +The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). +- **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). + +## Domain glossary +- `uc` / Unity Catalog — implicit across all types (the registered entities live in a UC metastore). +- `metastore` / `metastoreId` — UC metastore (the top-level UC namespace); the `metastoreId` is a UUID. +- `external-metadata` — the wire name for the resource registered in the lineage-tracking subsystem; refers to metadata about an entity living *outside* Databricks (a Tableau dashboard, a Kafka topic, etc.). +- `lineage-tracking` — the URL path prefix `/api/2.0/lineage-tracking/...`; the broader subsystem this package belongs to. +- `system` / `SystemType` — the external vendor system (Tableau, Snowflake, Kafka, ...). Closed enum. +- `entity` / `entityType` — the kind of object *within* the external system (a Tableau workbook vs. a dashboard; a Kafka topic vs. a partition). Open string, not enumerated. +- `BROWSE`, `MANAGE`, `MODIFY`, `CREATE_EXTERNAL_METADATA` — UC privileges referenced in method JSDoc but not modeled as types. +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). +- `properties` — user-defined `Record` (see #17 for naming concern). +- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. + +## File coverage +- `src/v1/model.ts` (222 lines): read fully. +- `src/v1/client.ts` (252 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (17 lines): read fully. diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md new file mode 100644 index 00000000..ac9f24e7 --- /dev/null +++ b/.agent/naming-audit/features.md @@ -0,0 +1,562 @@ +# Naming Audit: features + +**Path:** `packages/features/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-features` — collides semantically with two +sibling packages (`@databricks/sdk-featurestore` and +`@databricks/sdk-materializedfeatures`), all three of which are part of the +Feature Engineering surface. The bare word "feature" is also overloaded with +the unrelated common-English sense ("product feature" / "preview feature") +that appears throughout the SDK in flags, settings, and previews. +**Inferred domain:** Databricks Feature Engineering — defines **Feature** +(the abstract definition: source + transformation + aggregation), Kafka +streaming config, and **MaterializedFeature** (a concrete pipeline that +computes a feature on a schedule and writes results to an offline or online +store). Feature transformations are a discriminated union over 13 aggregation +functions and 3 data sources (Delta, Kafka, request-time), composed under +three flavors of time window (continuous, tumbling, sliding). +**Total weird names flagged:** 50 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `features` / module `@databricks/sdk-features` | (package) | package | High | 1 Vague/generic, 12 Duplicate concepts | The bare term "features" is ambiguous: (a) ML features (this package), (b) Databricks product features / feature flags (settings/previews), (c) "features" of a billing plan (billing). A reader cannot disambiguate from the import path. Rename to `@databricks/sdk-feature-engineering`, `@databricks/sdk-ml-features`, or `@databricks/sdk-feature-definitions`. | +| 2 | three sibling packages: `features` / `featurestore` / `materializedfeatures` | (across packages) | package set | High | 12 Duplicate concepts | The Feature Engineering surface is split across three top-level packages whose names overlap at the prefix. Boundaries: `features` defines feature *definitions* (this package); `materializedfeatures` is **misnamed** — it actually owns feature **lineage and tags** (`FeatureLineage`, `FeatureTag`), not materialized features (which live here); `featurestore` owns **online stores**. The names do not align with their contents. Either rename `materializedfeatures` to `featuremetadata` / `featurelineage`, or move `MaterializedFeature` and its client methods out of this package into the (misnamed) `materializedfeatures` package. | +| 3 | `Feature` interface | model.ts:279 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | +| 4 | `Client` | client.ts:65 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `FeaturesClient` or `FeatureEngineeringClient` would self-identify and disambiguate from `featurestore.Client` and `materializedfeatures.Client`. | +| 5 | `Client.createFeature` / `getFeature` / `updateFeature` / `deleteFeature` / `listFeatures` / `listFeaturesIter` plus `Client.create/get/update/delete/list/listIterKafkaConfig*` plus `Client.batchCreate/create/get/update/delete/list/listIterMaterializedFeatures*` (3 resource families on one client) | client.ts:91-628 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature` (21 methods total). The class is 631 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | +| 6 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` and 11 sibling values | model.ts:13-24 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | Only one value (`SCALAR_DATA_TYPE_UNSPECIFIED`) stutters the enum name; the other eleven (`INTEGER`, `FLOAT`, `BOOLEAN`, etc.) are reasonable. Just remove the sentinel or rename to `Unspecified`. The wire format is dictated by the API; TS keys can be Pascal-cased via the zod transform. | +| 7 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` (sentinel) | model.ts:13 | enum value | Medium | 6 Misleading names, 18 Long enum values | Proto-style "Unspecified" sentinel. The field is already `dataType?: ScalarDataType \| undefined` (FieldDefinition:325) — omitting the field communicates "unspecified" naturally. Sentinel is dead in TS. | +| 8 | `Function_FunctionType` enum name | model.ts:29 | enum | High | 4 Underscores in TS identifiers, 8 Redundant suffixes, 20 Type-suffix tautology | `Function_FunctionType` is a proto-nested-message-encoded-as-underscore name and is internally tautological (`Function`+`FunctionType`). It also requires an inline `// eslint-disable-next-line @typescript-eslint/naming-convention`. The TS idiom would be `FunctionKind` or `AggregationKind`, nested as `Function.Kind` under a namespace. | +| 9 | `Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED` and 12 sibling values | model.ts:30-43 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | `FUNCTION_TYPE_UNSPECIFIED` stutters; the others (`AVG`, `COUNT`, `SUM`, `MIN`, `MAX`, `FIRST`, `LAST`, `APPROX_COUNT_DISTINCT`, `APPROX_PERCENTILE`, `STDDEV_POP`, `STDDEV_SAMP`, `VAR_POP`, `VAR_SAMP`) are fine SQL idioms. Drop only the sentinel. | +| 10 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | +| 11 | `MaterializedFeature_PipelineScheduleState` | model.ts:47 | enum | High | 4 Underscores in TS identifiers, 7 Overly verbose | Proto-style nested name (eslint-disabled at line 46). 41 chars. TS idiom would be a top-level `PipelineScheduleState` or a namespaced `MaterializedFeature.ScheduleState`. The pipeline schedule is also not unique to materialized features; if the same concept appears elsewhere, a shared top-level enum is better. | +| 12 | `Function_ExtraParameter` | model.ts:373 | interface | High | 4 Underscores in TS identifiers, 6 Misleading names | Proto-nested encoded as underscore (eslint-disabled at line 372). JSDoc says "Deprecated"; consumers should never construct one. | +| 13 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 178, 751, 549, 543, 329, 459, 84, 92, 710, 721, 811, 817 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | +| 14 | `AggregationFunction.operation` discriminator field | model.ts:61 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `AggregationFunction`; the field holding the function variant is named `operation`. So `aggFn.operation.$case === 'avg'` reads okay, but in JSDoc comments and call sites the relationship is unclear: "operation" is a generic word; the value is *the function itself*. Could be `function` (matching the parent type's role in `Function.aggregationFunction.operation`) or `kind`. | +| 15 | `Function_FunctionType` on `Function.functionType` | model.ts:348 | field | High | 12 Duplicate concepts, 15 Generic field names | The deprecated field `Function.functionType` carries a value typed `Function_FunctionType`. Three uses of "function" in eight characters. Both the field and type are deprecated; mark them and they will disappear from typical call sites. | +| 16 | `TimeWindow.windowType` field | model.ts:762 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | +| 17 | `MaterializedFeature.destination` field | model.ts:523 | field | Medium | 1 Vague/generic, 15 Generic field names | Carries `offlineStoreConfig` or `onlineStoreConfig`. "Destination" is okay but ambiguous (could be a table name, a URL, a cluster). `store` or `target` would be more domain-specific; `storageDestination` would also work. | +| 18 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:283, 312, 314 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | +| 19 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:288, 312 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #46). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | +| 20 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:302, 252, 447 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | +| 21 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:295, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | +| 22 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:245, 312 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | +| 23 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:250, 314 | field pair | Medium | 12 Duplicate concepts | Same pattern as #22. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | +| 24 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:441, 312, 245 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | +| 25 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:446, 314, 250 | field set | High | 12 Duplicate concepts | Same as #24 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | +| 26 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 267, 769 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | +| 27 | `ColumnIdentifier.variantExprPath` | model.ts:161 | field | High | 5 Cryptic abbreviations, 6 Misleading names | "variantExprPath" — short for "variant expression path". The JSDoc clarifies it is a dot-prefixed column path (e.g., `value.trip_details.pickup_zip`). The `variantExpr` prefix is meaningless to a TS reader; the path is not a "variant expression" in any TS sense. Rename `path` or `columnPath`. | +| 28 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 29 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:362 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | +| 30 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:519 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts:254, 327) — verbose. | +| 31 | `MaterializedFeature.featureName` (full Unity Catalog name) vs `MaterializedFeature.tableName` (full UC table name) | model.ts:521, 528 | field pair | Medium | 6 Misleading names, 19 Underspecified IDs | Both are "full names". JSDoc says `featureName` is "The full name of the feature in Unity Catalog" (i.e., three-part `catalog.schema.name`) and `tableName` is "The fully qualified Unity Catalog path to the table". They look the same shape but reference different objects. `featureFullName` / `tableFullName` would type themselves. Compare to `Feature.fullName` (model.ts:281) where the type name is the disambiguator. | +| 32 | `Feature.fullName` (the feature's three-part name) | model.ts:281 | field | Medium | 6 Misleading names, 19 Underspecified IDs | "fullName" without context is ambiguous (full as opposed to what?). The JSDoc says "three-part name (catalog, schema, name)". A `name: string` carrying a fully-qualified identifier is a common UC pattern; `qualifiedName` or `threePartName` would be self-describing. Same critique applies to `DeleteFeatureRequest.fullName` (path), `GetFeatureRequest.fullName`, `DeltaTableSource.fullName`. | +| 33 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:225, 235, 230 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | +| 34 | `KafkaConfig.bootstrapServers` | model.ts:409 | field | Low | (none) | Standard Kafka term. Fine. | +| 35 | `SubscriptionMode.$case === 'assign'` | model.ts:730 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | +| 36 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:743 | field | Low | (none) | Fine, matches Kafka SDK. | +| 37 | `extraOptions` field (`Record`) | model.ts:419 | field | Medium | 1 Vague/generic | "Extra" is meaningless — extras compared to what? The JSDoc says it's "Catch-all for miscellaneous options". Rename `kafkaOptions` or `additionalOptions`. Fine if you accept "extra" as conventional escape-hatch idiom. | +| 38 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:600 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | +| 39 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:575, 581, 589 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | +| 40 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:539, 523 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | +| 41 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:310 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | +| 42 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:467, 397 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | +| 43 | `LineageContext` interface name | model.ts:465 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | +| 44 | `JobContext.jobId` JSDoc typo | model.ts:397 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | +| 45 | `JobContext.jobRunId` | model.ts:399 | field | Low | (none) | Fine. | +| 46 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:285-288 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | +| 47 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:241-245 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | +| 48 | `Feature.timeseries_column` (snake_case in JSDoc) | model.ts:243 | doc | Low | 4 Underscores | JSDoc references "Feature.timeseries_column" — wire-format name in user-facing TS docs. Should be `Feature.timeseriesColumn`. (Multiple occurrences across model.ts JSDoc texts.) | +| 49 | `unmarshalAggregationFunctionSchema` `$case === 'countFunction'` vs all others (`avg`, `sum`, ...) | model.ts:849 | const | High | 12 Duplicate concepts, 17 Inconsistent action verbs | The 13-case discriminated union for `AggregationFunction.operation` uses `$case` strings that mostly correspond to the math operation (`avg`, `sum`, `min`, `max`, `first`, `last`, `approxCountDistinct`, `approxPercentile`, `stddevPop`, `stddevSamp`, `varPop`, `varSamp`) — *except* for `countFunction`, which retains the `Function` suffix. The wire string is `count_function` while the wire strings for the others are `avg`, `sum`, etc. The asymmetry comes from the spec ("count" is a reserved word in some surfaces) but reads as a bug in TS code. | +| 50 | `marshal*Schema` / `unmarshal*Schema` const naming | model.ts:822-2274 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go-idioms; `Schema` is tautological with `z.ZodType`. TS idiom is `encode`/`decode`. Generator-wide pattern, no per-package fix. | +| 51 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | +| 52 | `parseResponse` vs `marshalRequest` | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | Mixing `parse`/`marshal`. Either `parse`/`format` or `marshal`/`unmarshal`. Sibling-package pattern. | +| 53 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | +| 54 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2396, 2446, 2491 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 55 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:170, 702, 781 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | + +--- + +## High severity (must fix) + +### H1. Three sibling packages, blurry boundaries + +The Feature Engineering surface is split across three top-level packages: + +- `features` (this package) — owns `Feature`, `KafkaConfig`, + `MaterializedFeature`, and 21 client methods spanning all three. +- `materializedfeatures` — **does not** own `MaterializedFeature`. It owns + `FeatureLineage` and `FeatureTag` (see + `packages/materializedfeatures/src/v1/index.ts`). +- `featurestore` — owns `OnlineStore` and `PublishTable` (see + `packages/featurestore/src/v1/index.ts`). + +The boundaries do not match the package names. A new reader walking the +package list will assume `MaterializedFeature` lives in `materializedfeatures` +— it doesn't. They will assume `KafkaConfig` lives in `featurestore` (the +"store" for features) — it doesn't. + +Recommendations (pick one): + +- **Rename to match contents:** + - this package → `feature-definitions` or `feature-engineering` (it owns + definitions + materialization + Kafka). + - `materializedfeatures` → `feature-lineage` or `feature-metadata`. + - `featurestore` → `feature-online-stores`. +- **Move types to match names:** + - Move `MaterializedFeature` + `materializedFeatures*` client methods out of + `features` and into `materializedfeatures`. + - Move `KafkaConfig` + `kafkaConfigs*` client methods out of `features` into + a new `feature-streaming-sources` package or keep in `features` if it + becomes "feature definitions only". + +Either way, the current state misleads consumers. + +### H2. Package name `features` is vague + +Bare "features" overlaps with at least three unrelated Databricks concepts: + +1. ML features (this package). +2. Product / preview features (in `settings`, `previews`). +3. Billing-plan features (in pricing surfaces). + +A TS reader who writes `import {Feature} from '@databricks/sdk-features/v1'` +has no signal that this is the ML kind. Recommend +`@databricks/sdk-feature-engineering` to match the URL path +(`/api/2.0/feature-engineering/...`). + +### H3. The `Feature` type name is overloaded + +The unqualified noun `Feature` is the central type of this package +(model.ts:279) and is re-exported from `index.ts`. Once it lands in a +consumer's namespace it shadows the common-English sense of the word. + +```ts +import {Feature} from '@databricks/sdk-features/v1'; +import {Feature as PreviewFeature} from '@databricks/sdk-previews/v1'; +``` + +Rename `MLFeature`, `FeatureDefinition`, or +`FeatureEngineeringFeature` (the latter is verbose but unambiguous and matches +the URL). + +### H4. `MaterializedFeature` is misplaced + +The package `materializedfeatures/` exists at `packages/materializedfeatures/` +but does not contain `MaterializedFeature` (it contains `FeatureLineage` / +`FeatureTag` instead). `MaterializedFeature` lives in this package. The +package naming and module organization are out of sync. + +This is the most surprising thing in this audit. A reader who searches the +codebase for `MaterializedFeature` will find it in `features/`, not +`materializedfeatures/`. Moving it (or renaming the empty-shelled package) +should be a P1 fix. + +### H5. Three names for "column reference of a source" + +- `ColumnIdentifier { variantExprPath?: string }` — used by `KafkaSource`. +- `EntityColumn { name?: string }` — used by `Feature`. +- `TimeseriesColumn { name?: string }` — used by `Feature`. +- `string` — used by deprecated `DeltaTableSource.entityColumns`, + `DeltaTableSource.timeseriesColumn`. + +Four representations for the same domain notion. Three of them carry a single +field, two with different field names (`variantExprPath` vs `name`). The +simplest fix is one shared `ColumnRef { path: string }` plus a tag on the +parent context (e.g., `entities: ColumnRef[]`, `timeseries: ColumnRef`). + +### H6. Underscore-encoded TS identifiers + +Three types use proto-style underscore-encoded nested names, each requiring an +inline `// eslint-disable-next-line @typescript-eslint/naming-convention`: + +- `Function_FunctionType` (enum) — model.ts:29 +- `Function_ExtraParameter` (interface) — model.ts:373 +- `MaterializedFeature_PipelineScheduleState` (enum) — model.ts:47 + +And the corresponding `unmarshal*` / `marshal*` constants below. The +existence of those eslint-disable comments is the loudest possible signal +that the names violate the codebase's own conventions. + +Standard TS idiom: lift to top-level (`FunctionType`, +`PipelineScheduleState`, `ExtraParameter`) or nest under a namespace +(`Function.Type`, `MaterializedFeature.ScheduleState`). + +### H7. `Function_FunctionType` and `Feature.functionType` are deprecated but not marked + +The deprecation note ("Deprecated: Use the function-specific messages in +AggregationFunction.function_type oneof instead") lives in the JSDoc *text* +but neither the type, nor the field, nor the enum carries a `@deprecated` tag. +TS callers' IDEs will not flag use. Same for: + +- `Function.functionType` — model.ts:347 +- `Function.extraParameters` — model.ts:351 +- `Feature.inputs` — model.ts:288 +- `Feature.timeWindow` — model.ts:295 +- `Feature.filterCondition` — model.ts:302 +- `BackfillSource.$case === 'deltaTableSource'` — model.ts:131 +- `DeltaTableSource.entityColumns` — model.ts:245 +- `DeltaTableSource.timeseriesColumn` — model.ts:250 +- `KafkaSource.entityColumnIdentifiers` — model.ts:441 +- `KafkaSource.timeseriesColumnIdentifier` — model.ts:446 + +Ten deprecated fields with no `@deprecated` tag. Add the tag. + +### H8. `Feature.lineageContext` is internal but exposed as public + +JSDoc explicitly says: "WARNING: This field is primarily intended for internal +use by systems and is automatically populated... Users should not +manually set this field as incorrect values may lead to inaccurate lineage +tracking or unexpected behavior. This field will be set by feature-engineering +client and should be left unset by SDK and terraform users." + +Yet it sits on the public `Feature` interface, with no `@internal` JSDoc tag, +no runtime guardrail, no separate "internal feature creation" path. A TS +consumer constructing a `Feature` literal can fill in any value. + +Fix: mark `@internal` (or remove from public type and have the server inject +it). + +### H9. `isOnline` redundancy with `destination` + +`MaterializedFeature.isOnline` is `true` iff `destination.$case === 'onlineStoreConfig'`. +Two booleans for one fact. A consumer who reads one and not the other can +misinterpret the record's state. Either: + +- Drop `isOnline` and require consumers to inspect `destination`. +- Make `isOnline` a server-derived read-only flag and forbid setting it on + create/update (it does *not* appear in the field-mask schema — model.ts:2476 + — but the JSDoc doesn't say it's read-only). + +### H10. Path-parameter IDs typed as `number` + +`LineageContext.notebookId` and `JobContext.jobId`, `JobContext.jobRunId` are +typed as `number`. Databricks IDs are 64-bit. The other ID field on the same +file (`MaterializedFeature.materializedFeatureId`) is `string`. Inconsistent +within the file *and* potentially unsafe at the `2^53` boundary. + +--- + +## Medium severity (worth pushing back on) + +### M1. One `Client` owning three resource families + +The `Client` class is 631 lines and exposes 21 methods over three resource +families: + +- `Feature` (5 RPCs + 1 iterator): create, get, list, listIter, update, delete. +- `KafkaConfig` (5 RPCs + 1 iterator): create, get, list, listIter, update, + delete. +- `MaterializedFeature` (5 RPCs + 1 iterator + 1 batch): batchCreate, create, + get, list, listIter, update, delete. + +The URL groupings hint that they are distinct sub-resources: + +- `/api/2.0/feature-engineering/features` +- `/api/2.0/feature-engineering/features/kafka-configs` +- `/api/2.0/feature-engineering/materialized-features` + +Splitting to three sub-clients (or three packages) would let each Client read +as a single focused surface. + +### M2. `*Function` interface proliferation + +Thirteen single-field interfaces (`AvgFunction`, `CountFunction`, etc.), eleven +of which are field-for-field identical (`{input?: string}`): + +```ts +export interface AvgFunction { input?: string | undefined } +export interface CountFunction { input?: string | undefined } +export interface SumFunction { input?: string | undefined } +export interface MinFunction { input?: string | undefined } +export interface MaxFunction { input?: string | undefined } +export interface FirstFunction { input?: string | undefined } +export interface LastFunction { input?: string | undefined } +export interface StddevPopFunction { input?: string | undefined } +export interface StddevSampFunction { input?: string | undefined } +export interface VarPopFunction { input?: string | undefined } +export interface VarSampFunction { input?: string | undefined } +``` + +Plus two that add fields: + +```ts +export interface ApproxCountDistinctFunction { input?, relativeSd? } +export interface ApproxPercentileFunction { input?, percentile?, accuracy? } +``` + +One shared `SingleInputFunction` + two specific extras would reduce the +interface count from 13 to 3. The discriminated union in `AggregationFunction.operation` +already encodes the function kind via `$case`. The type per case is +redundant. + +(This may be a deliberate code-generation pattern from the proto spec to +preserve forward extensibility — e.g., to let `SumFunction` later add fields +without affecting `AvgFunction`. Worth pushing back on.) + +### M3. `IsolationMode`-style enum sentinels + +`ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED`, +`Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED`, and +`MaterializedFeature_PipelineScheduleState.PIPELINE_SCHEDULE_STATE_UNSPECIFIED` +are proto-style sentinels for "no value set". The fields they live in are +already `T | undefined` in TS. The sentinels are dead and create +ambiguity (does `undefined` mean "not set" or "set to UNSPECIFIED"?). + +### M4. Field-name pluralization mismatches the type + +- `Feature.entities: EntityColumn[]` — plural field, singular element. Fine. +- `KafkaSource.entityColumnIdentifiers: ColumnIdentifier[]` — plural field, + singular element. Fine in isolation but `entities` (the modern version on + Feature) is much shorter. +- `DeltaTableSource.entityColumns: string[]` — plural field, primitive + element. Deprecated. Three plural conventions for the same notion. + +### M5. Three names for one notion (`entities` / `entityColumns` / `entityColumnIdentifiers`) + +See H5. The three names also differ in element type (`EntityColumn`, `string`, +`ColumnIdentifier`). Cf. T3 in cross-cutting observations below. + +### M6. `_FunctionType` and `_PipelineScheduleState` carry the wrong granularity + +`Function_FunctionType` (model.ts:29) lists *13 functions* in one enum, but +the modern API surfaces one interface per function (`AvgFunction`, +`SumFunction`, etc.). The enum is the legacy "all in one" view; the interfaces +are the new "one each" view. Both coexist. + +`MaterializedFeature_PipelineScheduleState` is correctly bounded (only the +three values `SNAPSHOT`, `ACTIVE`, `PAUSED` plus the `UNSPECIFIED` sentinel). +Pipelines, however, are a concept that may appear in other packages +(`pipelines/`, `jobs/`); a shared `PipelineState` would generalize. + +### M7. `ColumnSelection` interface is too generic + +JSDoc says `ColumnSelection` represents "equivalent to the LAST() record of an +entity over a lifetime ContinuousWindow". The name gives no domain hint. +`LatestColumnValue` would name the behavior. (Same critique as `Credential` in +the credentials audit.) + +### M8. `MaterializedFeature.destination` is a generic word + +Carries an `OfflineStoreConfig | OnlineStoreConfig` union. The English word +"destination" suggests a URL or path. Domain word: `target`, `store`, or +`storage`. + +### M9. JSDoc references stale field names + +- "Use Feature.entity instead" (model.ts:243) — actual field is `entities`. +- "Use Feature.entity instead" (model.ts:438) — same typo. +- "Use AggregationFunction.inputs instead" (model.ts:286) — field doesn't + exist; modern shape is per-function `input?`. +- "Use Function.aggregation_function.time_window" (model.ts:292) — references + snake_case wire name in TS-facing JSDoc. + +### M10. `executeCall` vs `executeHttpCall` + +Same as sibling packages. Two `execute*` verbs. + +--- + +## Low severity (nits) + +### L1. `ScalarDataType` is one of the few "good" enums + +Eleven of its twelve values (`INTEGER`, `FLOAT`, `BOOLEAN`, `STRING`, `DOUBLE`, +`LONG`, `TIMESTAMP`, `DATE`, `SHORT`, `BINARY`, `DECIMAL`) are concise SQL +types. Only the sentinel `SCALAR_DATA_TYPE_UNSPECIFIED` is a problem. + +### L2. `PACKAGE_SEGMENT` undescriptive + +Sibling-package pattern. + +### L3. `parseResponse` vs `marshalRequest` verb mix + +Sibling-package pattern. + +### L4. `MtlsConfig.disableHostnameVerification` reasonable + +Boolean named in negative ("disable") to match the underlying Kafka option +(`kafka.ssl.endpoint.identification.algorithm`). JSDoc warns about security +implications. Fine. + +### L5. `bootstrapServers` is conventional Kafka + +Fine. + +### L6. `cronSchedule` field on `MaterializedFeature` + +`MaterializedFeature.cronSchedule: string` is a Quartz cron expression. The +field name is fine; the type could be a branded `CronExpression` for stronger +typing, but flagging only for completeness. + +### L7. `req` parameter naming in client methods + +Standard SDK-wide convention. Fine. + +### L8. `marshal`/`unmarshal` are Go-idioms + +Generator-wide. Cf. credentials audit L7. + +### L9. `Function_FunctionType` enum values use SQL-conventional uppercase + +`AVG`, `COUNT`, `SUM`, etc. Match SQL/Spark idioms. Fine for the wire format; +TS keys could be PascalCase. + +### L10. `ContinuousWindow.offset` allows non-positive + +Note in JSDoc: "must be non-positive" — i.e., 0 or negative duration. The +type is `Temporal.Duration` which doesn't constrain sign. Documentation-only +constraint; not enforced. Same critique as `SlidingWindow.slideDuration` +("must be positive and less than duration"). + +### L11. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text + +A `string` containing potentially many KB of source text. Naming is fine; the +data shape is the design choice. Listing for completeness. + +### L12. JSDoc typo on `JobContext.jobId` + +"The job ID where this API invoked." → "where this API was invoked." Minor. + +### L13. `SecretScopeReference { scope, key }` + +Two-field reference to a Databricks secret. Standard. Fine. + +### L14. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` + +Four Spark Structured Streaming idioms. Standard. Fine. + +### L15. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` + +Three field-mask builders. Standard generator pattern. Fine. + +### L16. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` + +The list endpoint filters by feature name (full UC name). Field is +`featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` +in the response, which is the same value. + +--- + +## Cross-cutting observations (not flags) + +### T1. Generator marker + +Every file begins with `// Code generated from API definition by Databricks +SDK Generator. DO NOT EDIT.` All issues here must be fixed upstream. + +### T2. ESLint disables document the violations + +Four `// eslint-disable-next-line @typescript-eslint/naming-convention -- +Proto-style nested *name.` comments (lines 28, 46, 372, 428, 1141, 1901). +Each one marks a name that breaks the project's own conventions. The +generator already "knows" — it just emits the eslint disable rather than +fixing the name. + +### T3. Three packages, three different concepts of "what is a feature" + +| Package | What it owns | Where it lives | +|---------|--------------|----------------| +| `features` | `Feature` definitions, `KafkaConfig`, `MaterializedFeature` | this audit | +| `materializedfeatures` | `FeatureLineage`, `FeatureTag` (mismatched name) | `packages/materializedfeatures/` | +| `featurestore` | `OnlineStore`, `PublishTable` | `packages/featurestore/` | + +Domain-wise these are all *one product* (Databricks Feature Engineering / +Feature Store). They are split across three packages whose names suggest a +different breakdown than the contents. + +### T4. Optionality model + +Every field is `T | undefined`. Matches the rest of the SDK +(`exactOptionalPropertyTypes`). + +### T5. `index.ts` re-export style + +Class re-exported with `export {Client}`; enums (runtime values) re-exported +with `export {ScalarDataType, Function_FunctionType, MaterializedFeature_PipelineScheduleState}`; +interfaces (type-only) re-exported with `export type {...}`. Correct for +`verbatimModuleSyntax`. + +### T6. No reserved-word collisions + +No `delete`, `class`, `new`, `default`, `interface` as identifier names. +`Function` is a *built-in* TS global (the `Function` constructor type) — see +the next note. + +### T7. `Function` shadows the global `Function` type + +`export interface Function` (model.ts:343) shadows the TypeScript global +`Function` type (the constructor signature `Function`). Inside any module +that imports `Function` from this package, the global is unreachable except +via `globalThis.Function`. Most ESLint configs (including this repo's, see +`no-shadow-restricted-names` and the `globals` rule) flag this. The +underscore-encoded `Function_FunctionType` and `Function_ExtraParameter` +inherit the shadowing. + +Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. + +### T8. No tests + +No `tests/` directory for this package (matches sibling Feature Engineering +packages). + +### T9. Versioning + +Only `v1` exists; nothing to compare. + +### T10. Acronym casing + +| Acronym | Code form | JSDoc text | Consistent? | +|---------|-----------|-----------|-------------| +| UC (Unity Catalog) | `unityCatalog*` (e.g., `ucServiceCredentialName`) — *not used here*; appears in `AuthConfig.$case === 'ucServiceCredentialName'` (model.ts:104) | "Unity Catalog" spelled out | Mixed (cf. credentials audit M7) | +| SQL | `transformationSql` field, `sql` lowercase | "SQL" all-caps | Field uses `Sql` (PascalCase-first-letter). Fine. | +| TLS / mTLS | `MtlsConfig`, `mtlsConfig` | "Mutual-TLS (mTLS)" mixed | Code `Mtls` (PascalCase-first-letter). Diverges from RFC convention "mTLS". | +| TLS / SSL | `disableHostnameVerification` (no acronym) | "SSL" / "TLS" all-caps | N/A | +| IETF | `jsonSchema`, "IETF JSON schema" in JSDoc | N/A | N/A | +| JKS | "JKS files" in JSDoc | N/A | N/A | + +### T11. Streaming-specific vocabulary + +`SubscriptionMode.assign` / `subscribe` / `subscribePattern` directly mirror +Spark Structured Streaming Kafka options. Documented inline. Fine for users +who know the upstream API; opaque otherwise. + +--- + +## Domain glossary (as inferred from this code) + +| Term | Meaning in this package | +|------|-------------------------| +| **Feature** | A UC-registered feature definition: full three-part name + data source + aggregation function + time window. Reached via `/api/2.0/feature-engineering/features`. | +| **Materialized Feature** | A scheduled pipeline that computes a feature's values and writes them to an offline UC Delta table or an online Lakebase table. Reached via `/api/2.0/feature-engineering/materialized-features`. | +| **Kafka Config** | A reusable Kafka cluster + topic-subscription + schema bundle. Referenced by `KafkaSource.name` from `Feature.source`. | +| **Pipeline Schedule State** | The state of the underlying DLT pipeline driving the materialization. One of `SNAPSHOT` (one-shot), `ACTIVE` (running), `PAUSED`. | +| **Aggregation Function** | One of 13 SQL aggregations (`avg`, `count`, `sum`, `min`, `max`, `first`, `last`, `approxCountDistinct`, `approxPercentile`, `stddevPop`, `stddevSamp`, `varPop`, `varSamp`) applied over a time window. | +| **Column Selection** | The non-aggregation alternative to `AggregationFunction` — picks the latest value of a single column over a lifetime continuous window. Semantic equivalent of SQL `LAST()`. | +| **Data Source** | One of three: Delta table (batch), Kafka stream (streaming), Request-time (inference-time scoring). | +| **Backfill Source** | A user-provided historical-data table used when constructing training sets from streaming features. | +| **Time Window** | One of three Spark windowing variants: continuous, tumbling (non-overlapping fixed-duration), sliding (overlapping). | +| **Subscription Mode** | Kafka topic-selection mode: explicit topic-partition `assign`, comma-separated `subscribe`, regex `subscribePattern`. | +| **Auth Config** | One of two Kafka auth flavors: Unity-Catalog service credential, or mTLS keystores/truststores. | +| **Lineage Context** | Internal-only field linking a feature to the notebook/job that created it. Auto-populated by the feature-engineering client. | +| **Entity Column** | Column(s) used as the lookup key for the feature at query time. Aggregation keys. | +| **Timeseries Column** | The event-time column on the source data. Used for point-in-time joins, backfills, and aggregation windowing. | +| **Online Store** | A Lakebase logical database + schema serving low-latency feature lookups. | +| **Offline Store** | A Delta table serving batch-scoring/training feature lookups. | + +--- + +## File coverage + +| File | Lines | Exports counted | Audited | +|------|-------|-----------------|---------| +| `src/v1/model.ts` | 2499 | 3 enums, 50 interfaces, 60 zod consts (30 unmarshal + 30 marshal), 3 field-mask helpers | yes | +| `src/v1/client.ts` | 631 | 1 class, 21 public methods (15 RPCs + 3 paging iterators + 1 batch) | yes | +| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 78 | 1 class re-export, 3 enum re-exports, 60 type re-exports | yes | + +Every type, field, enum value, and method enumerated above is accounted for. diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md new file mode 100644 index 00000000..43ca8398 --- /dev/null +++ b/.agent/naming-audit/featurestore.md @@ -0,0 +1,849 @@ +# Naming Audit: `featurestore` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/featurestore/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts` +**Cross-package references:** `features/v1` (`OnlineStoreConfig`, +`onlineStoreName`), `materializedfeatures/v1`, `onlinetables/v1` +(`DeleteOnlineTableRequest`, `OnlineTable`, `OnlineTableState`, +`OnlineTableSpec`). +**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). + +--- + +## Inventory + +### Enums + +1. `OnlineStore_State` (model.ts:9) + - Values: `STATE_UNSPECIFIED`, `STARTING`, `AVAILABLE`, `DELETING`, + `STOPPED`, `UPDATING`, `FAILING_OVER`. +2. `PublishSpec_PublishMode` (model.ts:27) + - Values: `PUBLISH_MODE_UNSPECIFIED`, `CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`. + +### Interfaces / Types + +1. `CreateOnlineStoreRequest` (model.ts:47) — fields: `onlineStore`. +2. `DeleteOnlineStoreRequest` (model.ts:52) — fields: `name`. +3. `DeleteOnlineTableRequest` (model.ts:57) — fields: `onlineTableName`. +4. `GetOnlineStoreRequest` (model.ts:62) — fields: `name`. +5. `ListOnlineStoresRequest` (model.ts:67) — fields: `pageToken`, `pageSize`. +6. `ListOnlineStoresResponse` (model.ts:74) — fields: `onlineStores`, + `nextPageToken`. +7. `OnlineStore` (model.ts:82) — fields: `name`, `creator`, `creationTime`, + `state`, `capacity`, `readReplicaCount`, `usagePolicyId`. +8. `PublishSpec` (model.ts:99) — fields: `onlineStore`, `onlineTableName`, + `publishMode`. +9. `PublishTableRequest` (model.ts:108) — fields: `sourceTableName`, + `publishSpec`. +10. `PublishTableResponse` (model.ts:115) — fields: `onlineTableName`, + `pipelineId`. +11. `UpdateOnlineStoreRequest` (model.ts:122) — fields: `onlineStore`, + `updateMask`. + +### Zod schemas + +- `unmarshalListOnlineStoresResponseSchema` (model.ts:129) +- `unmarshalOnlineStoreSchema` (model.ts:142) +- `unmarshalPublishTableResponseSchema` (model.ts:165) +- `marshalOnlineStoreSchema` (model.ts:176) +- `marshalPublishSpecSchema` (model.ts:199) +- `marshalPublishTableRequestSchema` (model.ts:211) + +### Field-mask helpers + +- `onlineStoreFieldMaskSchema` (model.ts:221, module-internal) +- `onlineStoreFieldMask()` (model.ts:231, public) + +### Client class + +- `Client` (client.ts:46) + - Methods: `createOnlineStore`, `deleteOnlineStore`, `deleteOnlineTable`, + `getOnlineStore`, `listOnlineStores`, `listOnlineStoresIter`, + `publishTable`, `updateOnlineStore`. + - Private fields: `host`, `httpClient`, `logger`, `userAgent`. + - Module constant: `PACKAGE_SEGMENT`. + +### Utils (`src/v1/utils.ts`) + +- Type: `HttpCallOptions`. +- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`. + +--- + +## Findings + +### 1. `OnlineStore_State` proto-style underscored type name — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) + +**Symbol:** `OnlineStore_State` (model.ts:9), and identically +`PublishSpec_PublishMode` (model.ts:27). + +**Issue:** TS identifiers should not contain underscores +(`.agent/rules/typescript.mdc` § *Identifiers*; Google TS Style Guide § 5.3, +which mandates `UpperCamelCase` for types). The `Parent_Child` form is a +proto-buf code-generator artefact for nested messages/enums. The file even +suppresses the lint rule explicitly: + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. +export enum OnlineStore_State { +``` + +That comment is the audit signal: the project's lint rule disagrees with the +chosen name, and every other package in the SDK with the same pattern carries +the same suppression. The proto namespace is not preserved in TS modules — the +enum lives in the same module as `OnlineStore`, so the qualification is +redundant. + +**Suggested:** `OnlineStoreState` and `PublishMode`. The neighbouring +`onlinetables` package solves this exactly: `OnlineTableState` (no underscore, +no nested namespace prefix). See `onlinetables/v1/model.ts:7`. This is also +how `ProvisioningInfo_State` is solved one line below (it is the *only* +`X_Y` enum in `onlinetables`, and it lives next to flat `OnlineTableState` — +mixed conventions in the same file). + +This is a generator-level fix coordinated SDK-wide, not a unilateral change. + +--- + +### 2. `PublishSpec_PublishMode` doubled noun — category 8 (Redundant suffixes) + +**Symbol:** `PublishSpec_PublishMode` (model.ts:27). + +**Issue:** Combine with finding 1: when the underscore namespace is stripped, +the name becomes `PublishSpecPublishMode`, which contains "Publish" twice. The +natural collapse is `PublishMode`, which is what the field `publishMode` +already uses (model.ts:105). No information is lost — the enum is in the same +module as `PublishSpec` and is the only `*Mode` enum in the package. + +**Suggested:** `PublishMode`. + +--- + +### 3. Enum-value prefixes repeat the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) + +**Symbols:** `OnlineStore_State.STATE_UNSPECIFIED` (model.ts:11), +`PublishSpec_PublishMode.PUBLISH_MODE_UNSPECIFIED` (model.ts:28). + +**Issue:** Members are already namespaced under the enum type. The leading +`STATE_` / `PUBLISH_MODE_` segment duplicates the enum's own concept. Reads +poorly at use site: + +```ts +if (store.state === OnlineStore_State.STATE_UNSPECIFIED) { ... } +// ^^^^^ ^^^^^ +// repeats "state" +``` + +Compare to `onlinetables/v1` which uses +`OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` — same problem there. +However, the values here double as on-the-wire JSON strings (the same Zod +schema parses raw API strings into these identifiers, model.ts:150, 184), so +renaming requires server acceptance and is a behavioural change. **Flag for +the API team / generator.** TS-side identifier can be split from wire string +(see finding 5) as a safe local fix. + +**Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. +**Suggested TS-level only (safe, see finding 5):** +`Unspecified = 'STATE_UNSPECIFIED'`. + +--- + +### 4. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) + +**Symbols:** Every value in both enums (model.ts:11–23, 28–44). + +**Issue:** The project's `.agent/skills/google-ts-styleguide` (and the Google +TS Style Guide § 5.3) mandates `UpperCamelCase` for enum members, not +`SCREAMING_SNAKE_CASE`. The project's own `typescript.mdc` enforces no +underscores in TS identifiers. The enum members `STATE_UNSPECIFIED`, +`FAILING_OVER`, `PUBLISH_MODE_UNSPECIFIED` all contain underscores and are +SCREAMING-cased. + +Note: enum string *values* double as the on-the-wire representation here (the +Zod schemas parse raw API strings into these identifiers, e.g. `z.enum( +OnlineStore_State)` at model.ts:150). The TS-side identifier can be split +from the wire literal — e.g. `FailingOver = 'FAILING_OVER'` — which is the +canonical TS fix while preserving wire compatibility. + +**Suggested (TS side only, no wire change):** + +```ts +export enum OnlineStoreState { + Unspecified = 'STATE_UNSPECIFIED', + Starting = 'STARTING', + Available = 'AVAILABLE', + Deleting = 'DELETING', + Stopped = 'STOPPED', + Updating = 'UPDATING', + FailingOver = 'FAILING_OVER', +} + +export enum PublishMode { + Unspecified = 'PUBLISH_MODE_UNSPECIFIED', + Continuous = 'CONTINUOUS', + Triggered = 'TRIGGERED', + Snapshot = 'SNAPSHOT', +} +``` + +This is consistent with how the project's `typescript.mdc` treats other enums +and matches the project skill's mandate. **Flag as SDK-wide cleanup** — +unilateral change here would diverge from sibling packages. + +--- + +### 5. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) + +**Symbols:** `OnlineStore_State.FAILING_OVER` (model.ts:23), `STARTING`, +`DELETING`, `UPDATING` (model.ts:13, 17, 21) vs. `STOPPED`, `AVAILABLE` +(model.ts:19, 15). + +**Issue:** Six of the seven values are either progressive (`-ING`) or +adjectival/perfect (`STOPPED`, `AVAILABLE`, `UNSPECIFIED`). `FAILING_OVER` +mixes a participle with a particle preposition; the canonical +network/database term is `FAILOVER` (noun) or `FAILING_OVER` (verb-phrase). +Compare: AWS RDS uses `failing-over` as a state, Postgres uses +`failover`. Mark as a wire-level concern — TS identifier `FailingOver` is +fine under finding 4. **Pass at the TS level**, flag at the wire level. + +--- + +### 6. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) + +**Symbol:** `DeleteOnlineTableRequest.onlineTableName` (model.ts:59), wire +field `online_table_name` (per `marshalPublishSpecSchema:207` style; here the +field appears in the URL path, not JSON). + +**Issue:** The neighbouring `onlinetables/v1` package defines an *identical* +operation with a *different* field name: + +```ts +// onlinetables/v1/model.ts:93 +export interface DeleteOnlineTableRequest { + name?: string | undefined; // Full three-part name of the table. +} +``` + +Both packages name the type `DeleteOnlineTableRequest` (identical type names +in two packages — namespace-distinguished, but confusing). The field is +called `name` in `onlinetables`, `onlineTableName` in `featurestore`. A +caller switching packages would have to translate the field. The URL paths +also differ: `/api/2.0/online-tables/{name}` in `onlinetables` vs. +`/api/2.0/feature-store/online-tables/{onlineTableName}` here. + +`featurestore`'s field name is *more* descriptive (since the context is +"feature-store deletes an online table that wraps a 3-part Unity name"), +which is defensible — but the divergence is jarring. **Cross-package +alignment recommendation:** harmonise on `name` (shorter, idiomatic for +URL-path resource identifiers; matches HTTP REST conventions and the Go SDK's +`name` field for resources). + +This finding *also* hits category 19: the field is documented as "The full +three-part (catalog, schema, table) name of the online table." which is a +**very specific format** — neither the name nor the JSDoc enforces it. A +typed wrapper (e.g. `ThreePartName`) is an option, but cross-SDK convention +keeps it as a string. **Pass on the wrapper**, flag the field-name +divergence. + +--- + +### 7. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) + +**Symbol:** `OnlineStore.name` (model.ts:84). JSDoc: "The name of the online +store. This is the unique identifier for the online store." + +**Issue:** Two distinct concepts are conflated in a field called `name`: + +- "Name" (human-readable label). +- "Unique identifier" (what URL paths key on). + +The Go SDK and the wire format choose `name` to mean *identifier*, but +neighbouring SDK fields (`OnlineStore.creator` — email; `OnlineTable.name` — +three-part identifier; `Feature.name` — composite "table.column") all use +`name` for *different* shapes. A reader cannot tell from the type whether +`name` is a UC three-part name, a single token, or a free-text label. + +This package: `OnlineStore.name` is a **single token** (the URL embeds it as +`/online-stores/{name}` per client.ts:102, 140, 242). That is fine — but +documenting "this is also the unique identifier" inside the JSDoc is a +naming smell: if the doc has to say "this is the ID", the field name should +be `id` or the JSDoc should at minimum link to the URL grammar. **Suggest** +strengthening JSDoc to specify the lexical grammar +(`/^[a-zA-Z][a-zA-Z0-9_-]*$/` or similar) so consumers don't pass +arbitrary strings. + +--- + +### 8. `OnlineStore.creator` is an email, not a name — category 1 (Vague/generic) and category 17 (Inconsistent action verbs) + +**Symbol:** `OnlineStore.creator` (model.ts:86). JSDoc: "The email of the +creator of the online store." + +**Issue:** A field called `creator` typically holds a principal name or ID +(Go's `creator string` carries ambiguity by convention). Other packages in +this SDK use `createdBy` for principal IDs and `creatorEmail` when they want +to explicitly note the email shape. Concrete examples to align with: + +- `catalogs/v1` (CatalogInfo) uses `owner` and `metastoreId` — different + conventions. +- `database/v1` uses `creator` for an email too, in identical shape. + +The audit category 17 hits this because `Create*Request` operations elsewhere +return a creator-id field as `createdBy` (`apps/v1`, `pipelines`) — the +mismatch is *cross-package* not within-this-package. + +**Suggested:** rename to `creatorEmail` (descriptive) or `createdByEmail` +(matches the broader SDK passive form). Flag for SDK-wide cleanup; do not +fix in isolation. **Pass with a recommendation.** + +--- + +### 9. `OnlineStore.creationTime` vs. `…At` pattern — category 17 (Inconsistent action verbs) and category 7 (Overly verbose) + +**Symbol:** `OnlineStore.creationTime` (model.ts:88). Type: `Temporal.Instant`. + +**Issue:** The SDK has *three* conventions for "moment of creation": +`creationTime`, `createTime`, and `createdAt`. Within the wider SDK: + +- `OnlineStore.creationTime` (featurestore) — this file. +- `OnlineTable` (onlinetables) — no creation-time field, but `pipelines/v2` + uses `creationTime`. +- Many newer services use `createdAt` (`apps`, `customllms`). + +Picking one is out of scope; the **`Time` suffix on a `Temporal.Instant` is +mildly tautological** (the type encodes "moment"). The `At` form +(`createdAt`) is more idiomatic for JS/TS (JS-Joda, dayjs, Date-fns all use +`At` patterns; React/Node ecosystems converge here). + +**Suggested:** `createdAt` for cross-SDK consistency. **Flag for generator, +not a unilateral fix.** + +--- + +### 10. `OnlineStore.state` field name vs `OnlineStore_State` type — category 20 (Type-suffix tautology) — *pass* + +**Symbol:** `OnlineStore.state: OnlineStore_State` (model.ts:90). + +The field name `state` and the type `OnlineStore_State` are appropriately +named — the field is *the* state, and the type qualifies it with its owner. +No issue. (Under finding 1's recommended rename to `OnlineStoreState` this +remains fine.) + +--- + +### 11. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) + +**Symbol:** `OnlineStore.capacity?: string` (model.ts:92). JSDoc: "The +capacity of the online store. Valid values are "CU_1", "CU_2", "CU_4", +"CU_8"." + +**Issue:** A field with four valid enum-like string values is typed as +`string`. This is a **missing enum** — the appropriate shape is a string +literal union or a TS enum: + +```ts +// Either: +capacity?: 'CU_1' | 'CU_2' | 'CU_4' | 'CU_8' | undefined; +// or: +export enum OnlineStoreCapacity { CU1 = 'CU_1', CU2 = 'CU_2', ... } +``` + +The Go SDK uses a string for forward-compatibility (open enum), but TS can +model an *open* enum with `'CU_1' | 'CU_2' | (string & {})` if needed. The +current shape — bare `string` with a JSDoc note — provides no compile-time +help. **Flag for SDK-wide policy on open enums** (categories 1 + 6). + +Also: "CU" is unexplained (probably "Compute Unit"). Audit category 5 +(cryptic abbreviation) — see finding 12. + +--- + +### 12. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) + +**Symbol:** `OnlineStore.capacity` valid values `"CU_1"`–`"CU_8"` +(model.ts:91). + +**Issue:** `CU` is unexpanded in the file. Industry-wide it can mean +"Compute Unit", "Capacity Unit", or "Container Unit". The JSDoc should +either spell out the acronym or link to the public docs page that defines +it. Naming-side fix is at the wire level (rename to e.g. `compute-units-1`) +which is impractical; the practical fix is to expand the JSDoc. + +**Suggested JSDoc:** "The capacity of the online store (CU = Compute Unit). +Valid values: …". + +--- + +### 13. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* + +**Symbol:** `OnlineStore.readReplicaCount?: number` (model.ts:94). JSDoc: +"The number of read replicas for the online store. Defaults to 0." + +**Issue:** The field is optional with a documented server-side default of 0. +Optionality alone leaves the default unclear at the call site. This is not a +naming bug per se — flag JSDoc. + +--- + +### 14. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) + +**Symbol:** `OnlineStore.usagePolicyId?: string` (model.ts:96). + +**Issue:** `*Id` fields in the SDK refer to several different ID schemes +(UUID, ULID, account-scoped numeric, opaque tokens). The JSDoc says "The +usage policy applied to the online store to track billing." — it does not +specify the format. Cross-reference `budgetpolicy/v1` which defines such IDs +as UUIDs. **Suggest** JSDoc enrichment to say "Account-scoped UUID +referring to a usage policy defined in the budget-policy service." + +--- + +### 15. `PublishSpec.onlineStore` is a *name* (string), not an `OnlineStore` — category 15 (Generic field names losing meaning) and category 16 (Field contradicting type domain) + +**Symbol:** `PublishSpec.onlineStore?: string` (model.ts:101). JSDoc: "The +name of the target online store." + +**Issue:** The field is a *string identifier* of an online store, but the +field name is `onlineStore` — which to a reader implies the *whole struct*. +This is exactly the kind of misleading name flagged by category 16. Compare +to `PublishTableRequest.sourceTableName` (model.ts:110) — explicit `…Name` +suffix. + +**Suggested:** rename to `onlineStoreName` to match `sourceTableName`, +`onlineTableName`, and the wire field `online_store` (or +`online_store_name` — see finding 24). This is a *symbol-level* +inconsistency *within the same file* and is the single highest-confidence +fix in this audit. The Go SDK uses `OnlineStore` (capitalised, but a +string), so this is a port-time correctness opportunity, not a coordination +issue with upstream Go fields. + +**P1 fix candidate.** + +--- + +### 16. `PublishSpec` is vague — category 1 (Vague/generic) + +**Symbol:** `PublishSpec` (model.ts:99). + +**Issue:** `…Spec` is acceptable when paired with a clear noun +(`OnlineTableSpec`, `JobSpec`). "Publish" alone reads as a verb; the +combination "Publish + Spec" is ambiguous (publish *what* specification? +publishing *of* what?). Compare neighbours: `onlinetables` uses +`OnlineTableSpec` — the resource is named. + +**Suggested:** `PublishTableSpec` (the same noun as the parent +`PublishTableRequest`) — makes the link explicit and disambiguates from any +other "publish" concept the SDK might grow. The Go SDK uses `PublishSpec` +which has more room because it lives in the `featurestore` Go package. +**Coordinate with upstream.** + +--- + +### 17. `PublishSpec.publishMode` repeats `Publish` — category 8 (Redundant suffixes) + +**Symbol:** `PublishSpec.publishMode` (model.ts:105). + +**Issue:** Within `PublishSpec`, the `publish` prefix is implicit. `mode` +alone would suffice — but is too short and reads as generic. The enum it +refers to is `PublishSpec_PublishMode` which compounds the redundancy. + +**Suggested:** keep as `mode` *only if* the enum is renamed to `PublishMode` +(finding 2). Otherwise the field name reasonably mirrors the enum name. This +is a coupled fix; do not change in isolation. + +--- + +### 18. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) + +**Symbol:** `PublishTableRequest.publishSpec.onlineTableName`, +`PublishTableResponse.onlineTableName` (model.ts:103, 117). + +**Issue:** The JSDoc on both reads "The full three-part (catalog, schema, +table) name of the online table." — same finding as #6: the field is a +specific structured string. Currently typed `string`. No compile-time +safety. Cross-SDK pattern is to leave as `string` with JSDoc — accept that +trade-off, but the JSDoc spelling should be canonical and consistent. The +field appears in *three* places (model.ts:59, 103, 117) with three slightly +different doc strings: + +- model.ts:58: "The full three-part (catalog, schema, table) name of the + online table." +- model.ts:102: "The full three-part (catalog, schema, table) name of the + online table." +- model.ts:116: "The full three-part (catalog, schema, table) name of the + online table." + +(Actually identical here — pass on consistency.) **Pass with note.** + +--- + +### 19. `PublishTableResponse.pipelineId` — *pass* + +Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. +No issue. + +--- + +### 20. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* + +**Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` +(model.ts:126). + +`updateMask` is the canonical Google AIP-134 name for partial-update masks; +the type `FieldMask` is from `@databricks/sdk-core/wkt`. The +naming is SDK-wide and idiomatic. **Pass.** + +--- + +### 21. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) + +**Symbol:** `Client.publishTable` (client.ts:212). JSDoc: "Publish features." + +**Issue:** The method name claims to publish a *table*, but the JSDoc says +"Publish features." The request body's content (`sourceTableName`, +`publishSpec.onlineTableName`) is *about* tables, but the API operation — +per the JSDoc — is "publish features." Naming-wise the method matches the +URL grammar (`/feature-store/tables/{sourceTableName}/publish`) and the Go +SDK method name, but the JSDoc is misleading. + +Actually re-reading: the operation **publishes a source table's data to an +online store as an online table**. So "publishTable" is roughly correct +("publish a table"), the JSDoc "Publish features." is a stale one-liner. +**Fix the JSDoc**, not the method name. + +**Suggested JSDoc:** "Publish a feature table to an online store, creating +an online table that syncs from the source." Alternative method name +candidate: `publishFeatureTable` — more descriptive, ports `publish` from +the URL — but diverges from Go. **Pass on the name, flag the JSDoc.** + +--- + +### 22. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) + +**Symbols:** `Client.deleteOnlineTable` (client.ts:117, featurestore) vs. +`Client.deleteOnlineTable` (client.ts:108, onlinetables). + +**Issue:** Two SDK packages expose a method with the same name that hits +*different* HTTP endpoints: + +- `featurestore.deleteOnlineTable` → `/api/2.0/feature-store/online-tables/{onlineTableName}` +- `onlinetables.deleteOnlineTable` → `/api/2.0/online-tables/{name}` + +The semantic is "delete an online table" in both cases, but the endpoints +are separate. This is a *backend* concern, but at the SDK level a TS user +will import both `@databricks/sdk-featurestore/v1.Client` and +`@databricks/sdk-onlinetables/v1.Client` and find two identically-named +methods that do related but distinct things. Compounded by finding 6 where +the *request types* are also identically named but field-incompatible. + +**Suggested at the SDK level:** in `featurestore`, rename the method to +`deletePublishedOnlineTable` (since the table only exists because of +`publishTable`). This is a soft fix; the bigger issue is the duplicated +*surface* across packages. **Flag for the SDK platform team.** + +--- + +### 23. `Client.listOnlineStoresIter` async-iterator naming — *pass* + +`Iter` suffix is the project's canonical name for paginator generators +(`cleanrooms`, `cleanroomassets`, etc., per audit history). Consistent. +**Pass.** + +--- + +### 24. Wire field `online_store` vs. field name `onlineStore` referring to a string — category 5 (Cryptic abbreviations) and category 15 (Generic field names losing meaning) + +**Symbol:** `marshalPublishSpecSchema` (model.ts:206) maps +`onlineStore → online_store`. The wire field is `online_store` (a string +name), not `online_store_name`. This is a wire-level decision — the Go SDK +also uses `online_store` for this string field — but it amplifies finding 15: +even at the wire level, the field name suggests a *struct*, not a string. + +**Pass at the SDK level, flag upstream.** + +--- + +### 25. `unmarshal*Schema` / `marshal*Schema` Go vocabulary — category 14 (Go/Java-style names) + +**Symbols:** `unmarshalListOnlineStoresResponseSchema`, +`unmarshalOnlineStoreSchema`, `unmarshalPublishTableResponseSchema`, +`marshalOnlineStoreSchema`, `marshalPublishSpecSchema`, +`marshalPublishTableRequestSchema` (model.ts:129, 142, 165, 176, 199, 211). + +**Issue:** "Marshal" / "Unmarshal" is Go-ism vocabulary. TS ecosystem uses +"serialize" / "deserialize" or, when working with Zod, "parse" / "stringify" +/ "schema". The full SDK uses this convention; **flag for SDK-wide cleanup, +not this package alone.** + +The `*Schema` suffix is also somewhat redundant — `unmarshalOnlineStore` +without `Schema` would suffice since the value's type is +`z.ZodType` and there are no non-schema cousins. But this is a +naming-pattern decision applied SDK-wide. **Pass with note.** + +--- + +### 26. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* + +**Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and +`onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the +schema is private, the helper is exported, and the helper name matches the +Google AIP-134 update-mask vocabulary. **Pass.** + +--- + +### 27. `Client` class name — category 1 (Vague/generic) — *pass* + +Package convention. Every TS package exports a single `Client` class scoped +to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** + +--- + +### 28. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) + +**Symbol:** `PACKAGE_SEGMENT` (client.ts:41). + +**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true +constants (primitive literal values like `MAX_LEN = 10`). `PACKAGE_SEGMENT` +is a runtime object literal (`{ key, value }`) constructed from a JSON +import. The value *is* constant per-process, but the identifier shape +violates the project rule. The same name is used in every package's +`client.ts` — it is a project-wide convention. **Flag for SDK-wide cleanup, +do not fix in isolation.** + +**Suggested:** `packageSegment` or `clientPackageSegment`. + +--- + +### 29. `userAgent` / `httpClient` / `host` / `logger` — *pass* + +Standard private field names. Acronym handling matches the project rule +(`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported +type `HttpClient`). **Pass.** + +--- + +### 30. `HttpCallOptions` (utils.ts:15) — category 1 (Vague/generic) and category 20 (Type-suffix tautology) + +**Symbol:** `HttpCallOptions` interface. + +**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the +neighbouring `CallOptions` exists in `@databricks/sdk-options/call`. Naming +both *in the same file* (`HttpCallOptions` here, `CallOptions` imported on +line 12) confuses readers — which "Call" do they mean? Suggest +`HttpRequestContext` or `ExecuteHttpArgs`. **Flag for SDK-wide cleanup** +(this utils.ts is generated boilerplate copied across every package, so any +fix must apply everywhere). + +--- + +### 31. `executeCall` vs `executeHttpCall` — category 17 (Inconsistent action verbs) + +**Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). + +**Issue:** Two functions named `execute…Call`. `executeCall` is the public +API wrapper that calls `execute()` from `@databricks/sdk-core/api`. +`executeHttpCall` performs an HTTP request and decodes the body. They do +*different* things at *different* layers — but the names imply a +hierarchical relationship that does not exist. The HTTP one is roughly +`sendAndDecode` or `doHttpRequest`. **Flag for SDK-wide naming cleanup;** +this file is generated boilerplate copied across every package. + +--- + +### 32. `readAll` — *pass* + +Helper does what its name says (reads a `ReadableStream` to +completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** + +--- + +### 33. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) + +**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). + +**Issue:** Two symmetric operations: response→object (parse) and +object→body-string (marshal). The verbs come from two different vocabularies +("parse" is generic TS/JS, "marshal" is Go). Internally consistent verb-pair +would be `parseResponse` / `serializeRequest` or `unmarshalResponse` / +`marshalRequest`. The current pair is awkward. + +**Suggested:** `serializeRequest` and `parseResponse` (TS-native vocabulary) +or commit fully to the Go terms: `unmarshalResponse` and `marshalRequest`. +**Flag for SDK-wide consistency.** + +--- + +### 34. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* + +Verb-prefix matches the function's role (constructs an `HttpRequest` +object). Naming is fine. Note however the *file* mixes `build…`, +`execute…`, `marshal…`, `parse…`, `readAll`, `flatten…` — six verbs for +seven functions. Not unique to this package. **Pass.** + +--- + +### 35. `flattenQueryParams` (utils.ts:123) — *dead code* + +**Symbol:** `flattenQueryParams` (utils.ts:123). + +**Issue:** Imported nowhere within this package's client (the `list` method +builds its query string inline at client.ts:166–173, and `update` does +similar at client.ts:243–247). The helper is dead code in this package, and +`marshalRequest` is also declared and unused in some methods that emit raw +bodies. Naming itself is fine. **Suggest** deleting from this package, or +extracting all utils into a shared helper module +(`@databricks/sdk-core/http`). **Flag generator behaviour.** + +--- + +### 36. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* + +**Symbols:** `ListOnlineStoresRequest` (model.ts:67), +`ListOnlineStoresResponse` (model.ts:74). + +Names are long (24/25 chars) but match the SDK-wide pattern for paginated +list endpoints. Within the package scope `ListRequest` / `ListResponse` +would suffice — only `online-store` listing exists — but every other TS +package qualifies. **Pass on package consistency.** + +--- + +### 37. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) + +**Symbol:** `Client.listOnlineStores` (client.ts:160). + +**Issue:** Method JSDoc reads "List Online Feature Stores." — the result +type is `ListOnlineStoresResponse` of `OnlineStore[]`, *not* +`OnlineFeatureStore[]`. The type is called `OnlineStore`, the method is +`listOnlineStores`, and only the JSDoc says "Feature Stores". Two +spellings of the same concept. The wire path is `/feature-store/online-stores`. +**Fix the JSDoc** to align with the type names. + +**Suggested JSDoc:** "List online stores." (matches type and method). + +Similar inconsistency at `createOnlineStore` ("Create an Online Feature +Store.", client.ts:71), `deleteOnlineStore` ("Delete an Online Feature +Store.", client.ts:97), `getOnlineStore` ("Get an Online Feature Store.", +client.ts:135), `updateOnlineStore` ("Update an Online Feature Store.", +client.ts:237). All five method docstrings call them "Online Feature +Stores" while every type and field calls them "Online Stores." + +This is a **package-wide doc-text drift**, not a code-naming bug, but +worth flagging: pick one — "online store" or "online feature store" — and +make it consistent. Recommended: keep the type as `OnlineStore` (concise) +and update JSDocs to drop "Feature" (already redundant since the package is +`@databricks/sdk-featurestore`). + +--- + +### 38. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* + +`ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the +canonical pattern. **Pass.** + +--- + +### 39. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* + +`pipelineId` correctly camelCases the two-letter "ID"; `creator` is a +plain word. **Pass.** + +--- + +## Cross-package notes (per audit instructions) + +### `OnlineStore` concept vs. `features.OnlineStoreConfig` + +The `features/v1` package defines `OnlineStoreConfig` (features/v1/model.ts:617) +which holds `catalogName`, `schemaName`, `tableNamePrefix`, `onlineStoreName` +— a *configuration* for an online store. This `featurestore.OnlineStore` +holds the *actual store* (with name, state, capacity, etc.). Two related +but distinct types live in two packages: + +- `features.OnlineStoreConfig.onlineStoreName: string` — references a store + by name. +- `featurestore.OnlineStore.name: string` — is the store's identifier. +- `featurestore.PublishSpec.onlineStore: string` — also references a store + by name (but with no `…Name` suffix — see finding 15). + +**Recommendation:** harmonise. Either: +1. All references to an online-store identifier use `onlineStoreName` + (so rename `PublishSpec.onlineStore` to `onlineStoreName` — matches + finding 15). +2. Or all references use `onlineStore` and the type is `string` with a + marker (e.g. `type OnlineStoreName = string`). + +Option 1 is cheaper. **P1 cross-package alignment fix.** + +--- + +### `DeleteOnlineTableRequest` name collision with `onlinetables/v1` + +Already covered in finding 6. Two distinct request types share the same +type name across packages, with different field names. A consumer who +imports both packages (likely — they are complementary) writes: + +```ts +import {DeleteOnlineTableRequest as FsDeleteOnlineTableRequest} + from '@databricks/sdk-featurestore/v1'; +import {DeleteOnlineTableRequest as OtDeleteOnlineTableRequest} + from '@databricks/sdk-onlinetables/v1'; +``` + +Friction-heavy. **Strong recommendation:** rename +`featurestore.DeleteOnlineTableRequest` to e.g. +`DeletePublishedOnlineTableRequest` (it deletes a table created by +`publishTable`) — or rename `featurestore.deleteOnlineTable` method to +`deletePublishedOnlineTable` and follow with the request type. Aligns with +finding 22. + +--- + +### Enum-naming convention divergence: `OnlineStore_State` vs `OnlineTableState` + +| Pkg | Enum name | TS validity | +|------------------|---------------------|---------------------| +| `featurestore` | `OnlineStore_State` | Underscore — needs lint suppression. | +| `onlinetables` | `OnlineTableState` | Clean. | +| `onlinetables` | `ProvisioningInfo_State` | Underscore — needs lint suppression. | + +The generator emits both flat and underscored forms for nested-vs-flat +proto enums. The right SDK-wide policy is to always emit flat names in TS +(strip the proto namespace). **Flag for generator.** + +--- + +### `publishMode` cross-package overlap + +`PublishSpec_PublishMode` (this package, model.ts:27) has values +`CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`. The `onlinetables` package has +`OnlineTableSpec.schedulingPolicy` with discriminated `runContinuously` / +`runTriggered` cases (onlinetables/v1/model.ts:145–153). Same underlying +concept (continuous vs. triggered pipeline), two different modelling +approaches (string enum vs. discriminated union). Plus there is no +`SNAPSHOT` case in `onlinetables`. **Flag for upstream protocol alignment.** + +--- + +## Summary (counts) + +- **Critical / cross-package consistency:** 2 findings (#15 + `PublishSpec.onlineStore` should be `onlineStoreName`; #6 + `DeleteOnlineTableRequest` shape collision with `onlinetables`). +- **High (style guide violations):** 4 findings (#1 `OnlineStore_State` + underscore; #2 `PublishSpec_PublishMode` doubled noun; #4 enum SCREAMING + casing; #28 `PACKAGE_SEGMENT` casing). +- **Medium (naming clarity, JSDoc drift):** 10 findings (#3, #7, #8, #11, + #12, #14, #16, #21, #22, #37). +- **Low / project-wide convention notes (generator-level):** 10 findings + (#9, #13, #17, #18, #24, #25, #30, #31, #33, #35). +- **Pass / acceptable as-is:** 13 findings (#5, #10, #19, #20, #23, #26, + #27, #29, #32, #34, #36, #38, #39 — partial pass with notes). + +**Total flagged findings: 39** distinct items across 20 audit categories +(several findings touch multiple categories). Many issues are +generator-emitted boilerplate inherited from the Go SDK; the cleanest local +fixes are findings 15, 21 (JSDoc), 22, 37 (JSDoc), and the cross-package +alignments noted above. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md new file mode 100644 index 00000000..c84bb345 --- /dev/null +++ b/.agent/naming-audit/files.md @@ -0,0 +1,586 @@ +# Naming Audit: files + +**Path:** `packages/files/src/v1/`, `packages/files/src/v2/` +**Versions audited:** v1 AND v2 +**Inferred domain:** File operations on Databricks storage. `v1` is a small hand-written wrapper exposing only `upload` against the modern Files API (`/api/2.0/fs/files/...`). `v2` is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. + +**Total weird names flagged:** 54 + +## Summary +| Severity | Count | +| --- | --- | +| High | 17 | +| Medium | 20 | +| Low | 11 | +| Observation | 6 | + +## v1 vs v2 comparison + +### Major renames / shape differences + +| v1 name | v2 name | Notes | +|---------|---------|-------| +| `UploadRequest` | `UploadFileRequest` | **Improvement** — the `File` qualifier is needed in v2 because the same client now exposes directory operations too. In v1 the package was implicitly "files-only", so the unqualified `UploadRequest` worked. Same field shape (`filePath`, `contents`, `overwrite`). | +| `DownloadRequest` | `DownloadFileRequest` | Mirror of upload — adds `range` and `ifUnmodifiedSince` (good — extends; cf. v1 has neither). | +| `DownloadResponse` | `DownloadFileResponse` | v1 has 4 fields (`contents`, `contentLength`, `contentType`, `lastModified`). v2 has the same 4. Both are uniform here. | +| `UploadRequest.filePath` (required) | `UploadFileRequest.filePath` (optional `?`) | **Regression** — v1 typed `filePath: string` as required; v2 generated all fields optional because the upstream proto schema marks them optional. The generated client falls back to `req.filePath ?? ''` (`client.ts:716`) which silently encodes an empty path. v1 is stricter and clearer. | +| `UploadRequest.contents: ReadableStream` | `UploadFileRequest.contents?: ReadableStream` | **Regression** — v1 typed the stream element as `Uint8Array`; v2 dropped the generic and admits `ReadableStream`. v2 also makes `contents` optional, which makes no sense semantically (no contents == nothing to upload). | +| `UploadRequest.overwrite?: boolean` | `UploadFileRequest.overwrite?: boolean` | Same name, same shape. Good. | +| `DownloadResponse.contents: ReadableStream` (required) | `DownloadFileResponse.contents?: ReadableStream` (optional, untyped) | Same regression — v1 stronger types. | +| `DownloadResponse.contentLength?: number` | `DownloadFileResponse.contentLength?: number` | Same. | +| _(v1 has no download method, despite `DownloadRequest`/`DownloadResponse` being exported)_ | `Client.downloadFile(req: DownloadFileRequest)` | **v1 dangling types** — `DownloadRequest` and `DownloadResponse` are exported from `v1/index.ts` but never referenced by `v1/client.ts`. They are dead/orphaned types in v1. | + +### New in v2 (no v1 counterpart) + +- Methods (legacy DBFS): `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`. +- Methods (modern Files): `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `listDirectoryContentsIter`. +- Types (legacy DBFS): `AddBlock`, `AddBlock_Response`, `Close`, `Close_Response`, `Create`, `Create_Response`, `Delete`, `Delete_Response`, `FileInfo`, `GetStatus`, `GetStatus_Response`, `ListStatus`, `ListStatus_Response`, `MkDirs`, `MkDirs_Response`, `Move`, `Move_Response`, `Put`, `Put_Response`, `Read`, `Read_Response`. +- Types (modern Files): `CreateDirectoryRequest`/`Response`, `DeleteDirectoryRequest`/`Response`, `DeleteFileRequest`/`Response`, `DirectoryEntry`, `DownloadFileRequest`/`Response`, `GetDirectoryMetadataRequest`/`Response`, `GetFileMetadataRequest`/`Response`, `ListDirectoryContentsRequest`, `ListDirectoryResponse` (note plural/singular asymmetry), `UploadFileRequest`/`Response`. + +### Dropped in v2 + +- v1 utility `encodeFilePath` is renamed to v2 `encodeMultiSegmentPath` (good — name no longer ties the encoder to "files"; works for `/directories/...` and `/files/...` paths alike). +- v1 helper `sendAndCheckError` is kept in v2 BUT v2 also adds `executeHttpCall`, `executeCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`. Both helpers coexist in v2 (`sendAndCheckError` is now only used by `downloadFile` to keep the body stream un-consumed). + +### Net assessment + +v2 mostly improves names by qualifying with `File`/`Directory`, but it also: (a) keeps every legacy DBFS message verbatim — `Read`, `Move`, `Put`, `Delete`, `Close`, `Create`, `MkDirs`, `AddBlock` — as verb-shaped type names colliding with TS/HTTP/JS conventions; (b) blends two separate REST APIs (`/dbfs` and `/fs`) into a single `Client` class with no namespace distinction; (c) weakens v1's `Uint8Array` stream typing to bare `ReadableStream`; (d) re-exports `FileInfo` which already exists in `experiments` and `marketplaces` packages. v1 is small and tighter; v2 is broader and noisier. + +## High severity + +### 1. `Read` — reserved-word collision and misleading shape — `src/v2/model.ts:254` + +```ts +export interface Read { + /** The path of the file to read. The path should be the absolute DBFS path. */ + path?: string | undefined; + offset?: number | undefined; + length?: number | undefined; +} +``` + +- **Why weird:** `Read` is the legacy DBFS read **request** but the type name reads as either the action verb ("perform a read") or the past tense ("was read"). It collides with the built-in TS `Readonly<>`, `ReadableStream`, `Reader`, etc. In application code, `import {Read} from '@databricks/sdk-files/v2'` is almost guaranteed to be mistaken for a stream type. Also shadows the verb so `read(req: Read)` is `read(read: Read)` — every word in the signature is `read`. +- **Category:** 10 (reserved-word/conflict), 6 (misleading), 14 (Go/proto-style — Go has the proto message named `Read`, but in Go the package-qualified `dbfs.Read` reads OK; in TS it does not). +- **Suggested name:** `DbfsReadRequest`. +- **Rationale:** Match the modern `DownloadFileRequest` pattern, and explicitly tag it as the legacy DBFS request to distinguish from the modern Files API. The same critique applies to all the other verb-named DBFS messages — see #2. + +### 2. Verb-as-noun cluster: `Move`, `Put`, `Delete`, `Close`, `Create`, `MkDirs`, `AddBlock`, `GetStatus`, `ListStatus` — `src/v2/model.ts:15-264` + +```ts +export interface Move { sourcePath?: ...; destinationPath?: ...; } +export interface Put { path?: ...; contents?: ...; overwrite?: ...; } +export interface Delete { path?: ...; recursive?: ...; } +export interface Close { handle?: ...; } +export interface Create { path?: ...; overwrite?: ...; } +export interface MkDirs { path?: ...; } +export interface AddBlock { handle?: ...; data?: ...; } +export interface GetStatus { path?: ...; } +export interface ListStatus { path?: ...; } +``` + +- **Why weird:** Nine TS interfaces named after verbs (or verb phrases). Every one is the **request** type for the same-named method. Side-by-side with the modern `CreateDirectoryRequest`, `DeleteFileRequest`, `UploadFileRequest`, `DownloadFileRequest`, the legacy types stick out as deeply un-TypeScript-y. +- `Delete` collides directly with the JS `delete` keyword (sub-case) and with `workspace`'s `Delete` interface (`packages/workspace/src/v1/model.ts:65`). +- `Create` collides with React's `Create*` patterns and any other domain's `Create`. +- `Close` reads as a verb / event-listener method (`element.addEventListener('close', ...)`) and as `Promise` reads "Promise to close" rather than "Promise of a Close payload". +- `MkDirs` is a cryptic abbreviation of "make directories" in `PascalCase` instead of the (also bad) `Mkdirs` or the modern `CreateDirectory`. Also: it creates only ONE directory (recursively, like `mkdir -p`), not directories plural. +- `GetStatus` and `ListStatus`: both have a body of just `path?: string` and are conceptually just "stat" / "ls". They differ only in whether a path is a directory or file at runtime (the server figures it out). Their existence is duplicative with the modern `GetFileMetadataRequest`, `GetDirectoryMetadataRequest`, `ListDirectoryContentsRequest`, but no docstring tells callers which to use. +- **Category:** 1 (vague/generic), 6 (misleading shape), 10 (reserved-word collision — `Delete`), 12 (duplicate concept with modern names), 14 (Go/proto-style names), 17 (inconsistent verb cluster — Delete/Move/Put are CRUD; AddBlock/Close are stream lifecycle; GetStatus/ListStatus are queries; all in one undifferentiated namespace). +- **Suggested names:** `DbfsMoveRequest`, `DbfsPutRequest`, `DbfsDeleteRequest`, `DbfsCloseRequest`, `DbfsCreateRequest`, `DbfsMkdirsRequest` (or `DbfsMakeDirectoriesRequest`), `DbfsAddBlockRequest`, `DbfsGetStatusRequest`, `DbfsListStatusRequest`. +- **Rationale:** Carries the surface ("DBFS"), follows the modern `Request` shape, no reserved-word collisions, no verb-as-noun ambiguity. Bonus: makes #5 (mixed-surface in single client) much more honest. + +### 3. `_Response`-suffixed types use literal underscore in identifier — `src/v2/model.ts:13,21,31,53,166,219,230,240,252,267` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface AddBlock_Response {} +export interface Close_Response {} +export interface Create_Response { handle?: number | undefined; } +export interface Delete_Response {} +export interface GetStatus_Response { ... } +export interface ListStatus_Response { ... } +export interface MkDirs_Response {} +export interface Move_Response {} +export interface Put_Response {} +export interface Read_Response { ... } +``` + +- **Why weird:** Underscore in TS identifier. The generator wraps every proto outer-message `Response` nested type as `_Response`. Ten different `_Response` types in this one file — each requires `eslint-disable @typescript-eslint/naming-convention`. Compare to the modern-API peers (`CreateDirectoryResponse`, `DownloadFileResponse`) which use camelCase / PascalCase only. Two conventions, one file. +- **Category:** 4 (underscore in TS identifier), 17 (legacy DBFS uses `Foo_Response`; modern Files uses `FooResponse` — internally inconsistent). +- **Suggested name:** Use `Response` (no underscore): `AddBlockResponse`, `CloseResponse`, `CreateResponse`, etc. Or — better — combine with #1/#2: `DbfsAddBlockResponse`, `DbfsCloseResponse`, ... +- **Rationale:** TypeScript identifiers in `PascalCase` should not contain underscores. Every eslint-disable on a generated symbol is friction. The dual convention (`Foo_Response` vs `FooResponse`) inside the same file confirms the existing v2 cleanup is partial. + +### 4. `DBFS` vs `Dbfs` casing — never appears in TS identifier, only in JSDoc — model & client + +- **Why weird:** "DBFS" appears 11 times in JSDoc strings (e.g. "The path should be the absolute DBFS path.", `model.ts:24,46,161,214,225,233,235,243,255`) and once in client docstrings ("DBFS REST API"). But NONE of the TS type or method names carry the prefix. The class is just `Client`, the methods are `read`/`write`/`put`/`delete`/`move`/`mkdirs` — DBFS is invisible at the TS surface. Compare with `databricks-sdk-go` upstream where these are split into `dbfs.API` and `files.API` as separate services. The TS port merges them and removes the namespace. +- **Category:** 3 (acronym casing — should be `Dbfs` if it were ever used), 16 (field-contradicting-domain), 17 (inconsistency — JSDoc says DBFS, identifier doesn't). +- **Suggested name:** Carry the surface name in identifiers: `DbfsClient` for the legacy methods, or split into two packages / sub-modules: `@databricks/sdk-files/v2/dbfs` and `@databricks/sdk-files/v2/files`. If kept as one client, prefix the methods (`client.dbfsRead`, `client.dbfsMove`, ...). +- **Rationale:** Two REST APIs in one class with no naming signal mixes a deprecated surface (DBFS, max 1 MB per call, deprecated by Databricks) with the modern surface (Files API, 5 GiB streaming). Users can't tell which to use from the method list. Surface name in identifier resolves this. + +### 5. Package name `files` and class name `Client` are both contextless — `package.json:2`, `client.ts:15,94` + +```ts +// v1 +export class Client { ... } // src/v1/client.ts:15 +// v2 +export class Client { ... } // src/v2/client.ts:94 +``` + +- **Why weird:** Both versions export `Client` without qualification. Consuming code that imports from multiple packages ends up with `import {Client as FilesClient} from '@databricks/sdk-files/v2';` in every file. The package name `files` is also generic — DBFS files? UC volume files? Workspace files (already a separate `@databricks/sdk-workspace`)? Workspace assets called "files"? The package scopes ALL of: DBFS API, Files API for UC volumes, generic file storage. +- **Category:** 1 (vague — "files" overloaded across at least DBFS, UC Volumes, Workspace files), 6 (misleading — name does not signal which file surface). +- **Suggested name:** Export `FilesClient` (or split — `DbfsClient` + `FilesClient`). The package itself could be `@databricks/sdk-dbfs-and-files` (ugly but honest) or split into two packages. +- **Rationale:** Already a problem in the wider SDK; `Client` is opaque in error messages and stack traces. + +### 6. `DirectoryEntry` vs `FileInfo` — duplicate concept inside v2 — `src/v2/model.ts:73,114` + +```ts +export interface DirectoryEntry { + fileSize?: number | undefined; + isDirectory?: boolean | undefined; + lastModified?: number | undefined; + name?: string | undefined; + path?: string | undefined; +} + +export interface FileInfo { + path?: string | undefined; + isDir?: boolean | undefined; + fileSize?: number | undefined; + modificationTime?: number | undefined; +} +``` + +- **Why weird:** Both types describe a file-or-directory metadata snapshot, with overlapping fields: + - Both have `path`, `fileSize`. + - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings — see #7). + - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names — see #8). + - `DirectoryEntry.name` (component name) — exists only in `DirectoryEntry`. + Two distinct types because they come from two distinct REST APIs (modern listDirectoryContents vs legacy listStatus / getStatus). The client exposes both, side-by-side, with no docstring telling callers which to use. +- **Category:** 12 (duplicate concepts), 17 (cross-API naming clash), 6 (misleading — `DirectoryEntry` may be a file). +- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #10). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. +- **Rationale:** Two identical-shape types with different field names are a maintenance hazard. + +### 7. `isDir` vs `isDirectory` — same concept, two casings — `src/v2/model.ts:77,118,170` + +```ts +DirectoryEntry.isDirectory?: boolean // modern API +FileInfo.isDir?: boolean // legacy DBFS +GetStatus_Response.isDir?: boolean // legacy DBFS +``` + +- **Why weird:** Same yes/no flag, two abbreviations of "is directory". `isDir` is a cryptic 3-letter abbreviation; `isDirectory` is the full word. They appear in three sibling types in the same file. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistent across same package). +- **Suggested name:** `isDirectory` everywhere (the modern form). Wire mapping is one line in the unmarshal schema. +- **Rationale:** Public TS field names should not abbreviate "directory" to "dir" when the rest of the SDK spells it out. + +### 8. `lastModified` (number-ms-epoch) vs `lastModified` (HTTP-date string) vs `modificationTime` — `src/v2/model.ts:79,110,122,157,174` + +```ts +DirectoryEntry.lastModified?: number // ms since epoch +DownloadFileResponse.lastModified?: string // HTTP-date (RFC 7231) +FileInfo.modificationTime?: number // ms since epoch +GetFileMetadataResponse.lastModified?: string // HTTP-date +GetStatus_Response.modificationTime?: number // ms since epoch +``` + +- **Why weird:** Three problems in one cluster. (a) Same FIELD NAME (`lastModified`) holds two completely different value domains — milliseconds-since-epoch as `number` (in `DirectoryEntry`) AND HTTP-date `'Wed, 21 Oct 2015 07:28:00 GMT'` as `string` (in `DownloadFileResponse`, `GetFileMetadataResponse`). (b) Same WIRE CONCEPT (ms since epoch) has two field names — `lastModified` in modern, `modificationTime` in legacy. (c) Time-suffix convention is inconsistent: `lastModified` (past participle), `modificationTime` (noun + `Time` suffix). +- **Category:** 9 (singular/plural / cross-shape mismatch), 15 (generic name loses meaning), 16 (field contradicts type domain — same name, two value types), 17 (inconsistent naming). +- **Suggested name:** Use distinct names for distinct domains. For ms-since-epoch: `lastModifiedMs` or `lastModifiedAt: number` (ms-since-epoch convention). For HTTP-date strings: `lastModifiedHttpDate: string` or model as a typed brand. Pick ONE — `modificationTime` should be dropped. +- **Rationale:** A consumer doing `if (resp.lastModified > someTimestamp)` will silently break depending on which API they came from. + +### 9. `contents` field has three different types across model — `src/v2/model.ts:108,246,281,275` + +```ts +DownloadFileResponse.contents?: ReadableStream | undefined // line 108 +Put.contents?: Uint8Array | undefined // line 246 +Read_Response.data?: Uint8Array | undefined (named 'data')// line 275 — same concept, different name +UploadFileRequest.contents?: ReadableStream | undefined // line 281 +ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 208 +``` + +- **Why weird:** "Contents" is overloaded across the model: + - `DownloadFileResponse.contents`: file bytes as a stream. + - `UploadFileRequest.contents`: file bytes as a stream. + - `Put.contents`: file bytes as a `Uint8Array` (no streaming on the legacy API). + - `Read_Response.data`: file bytes (chunked read) as a `Uint8Array` — same concept as `Put.contents` but called `data`. + - `ListDirectoryResponse.contents`: directory entries (array of `DirectoryEntry`). +- **Category:** 6 (misleading), 12 (duplicate concept — `contents` and `data`), 15 (generic name loses meaning — what's in "contents"?), 17 (inconsistent — same concept, three names). +- **Suggested name:** `body: ReadableStream` for stream payload, `bodyBytes: Uint8Array` for buffered, `entries: DirectoryEntry[]` for list responses (matching the `next_page_token` pattern of "entries + next token"). Rename `Read_Response.data` to `Read_Response.bytes` to make the buffer obvious. +- **Rationale:** The `contents` of a directory and the `contents` of a file are different domains. Type system will not catch a programmer who reads `.contents.length` expecting bytes and gets `DirectoryEntry[].length`. + +### 10. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` + +```ts +// files/v2: file/directory metadata snapshot +export interface FileInfo { + path?: string | undefined; + isDir?: boolean | undefined; + fileSize?: number | undefined; + modificationTime?: number | undefined; +} +// experiments/v1/model.ts:248 — MLflow file artifact +export interface FileInfo { ... } +// marketplaces/v1/model.ts:288 — listing file attachment +export interface FileInfo { ... } +``` + +- **Why weird:** Three different packages all export `FileInfo` with three different shapes. The names are flat-spaced inside the package, but downstream consumers who do `import * as files from '@databricks/sdk-files/v2'; import * as exp from '@databricks/sdk-experiments/v1';` get two unrelated `FileInfo` types and `files.FileInfo !== exp.FileInfo` is a confusing source of bugs. +- **Category:** 1 (vague/generic top-level name), 12 (duplicate concept across packages), 15 (generic name loses meaning). +- **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #6 — `FileEntry`). +- **Rationale:** `FileInfo` is so generic three different domains felt entitled to use it. + +### 11. `Create` returns a `handle` (not the created file) — `src/v2/model.ts:23-34` + +```ts +export interface Create { + path?: string | undefined; + overwrite?: boolean | undefined; +} +export interface Create_Response { + /** Handle which should subsequently be passed into the AddBlock and Close calls when writing to a file through a stream. */ + handle?: number | undefined; +} +``` + +- **Why weird:** The method is called `create` but does NOT create a file — it opens a write stream and returns a handle. The actual file doesn't exist until you call `close`. A reader of `client.create({path: '/tmp/foo'})` would reasonably expect the file to be created. JSDoc on the method says "Opens a stream to write to a file and returns a handle to this stream." — directly contradicting the name. +- **Category:** 6 (misleading — name says "create" but action is "open"), 14 (Go/proto-style — the upstream proto's name leaked through). +- **Suggested name:** `OpenWriteStream` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). +- **Rationale:** Method name should reflect action; right now `create` and `createDirectory` look like sibling actions when they are entirely different (create-handle vs create-resource). + +### 12. `handle: number` — underspecified ID — `src/v2/model.ts:7,17,33` + +```ts +AddBlock.handle?: number // "The handle on an open stream." +Close.handle?: number +Create_Response.handle?: number +``` + +- **Why weird:** A `number` named `handle` looks like a `numeric ID`, but the JSDoc says it is the result of an `open` (per #11). No type-brand prevents passing arbitrary numbers; no documentation says whether it is positive, monotonic, opaque, or guaranteed unique. The Go SDK uses `int64` here and TS narrows to `number`, which is silently truncated above 2^53 — and there is no mitigation in this client. +- **Category:** 19 (underspecified ID). +- **Suggested name:** `streamHandle: number` (or `DbfsStreamHandle` branded type). At minimum, type-document "opaque integer from DBFS server; pass as-is". +- **Rationale:** TS `number` for a server-issued 64-bit token is a known precision hazard; the field name doesn't even hint that it's a transient stream identifier. + +### 13. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:292,656` + +```ts +async list(req: ListStatus, ...): Promise // legacy DBFS +async listDirectoryContents(req: ListDirectoryContentsRequest, ...): Promise // modern Files +``` + +- **Why weird:** Two list methods on the same client. `list` is the legacy DBFS list (no paging), `listDirectoryContents` is the modern Files API (paginated). The names give no signal which is which; the JSDoc on `list` calls out a 60 s timeout and a 10 K file limit. A naive caller will pick the shorter name and hit production limits. +- **Category:** 1 (vague — `list` is generic), 12 (duplicate concept), 17 (inconsistent — `list` is short, `listDirectoryContents` is long; both list a directory). +- **Suggested name:** `dbfsListStatus` (legacy) and `listDirectoryContents` (modern). Or `list` (modern, paged, recommended) and `dbfsList` (legacy, deprecated). +- **Rationale:** Method-name length should not be the only discriminator between a recommended modern API and a deprecated legacy one. + +### 14. `ListDirectoryContentsRequest` paired with `ListDirectoryResponse` — request/response noun mismatch — `src/v2/model.ts:178,206` + +```ts +export interface ListDirectoryContentsRequest { ... } +export interface ListDirectoryResponse { ... } // not ListDirectoryContentsResponse +``` + +- **Why weird:** The request has 4 words (`List Directory Contents Request`); the response has 3 (`List Directory Response`). Same wire endpoint. The asymmetry forces every caller to remember which name has the `Contents` word and which doesn't. Other request/response pairs in this file are matched (`CreateDirectoryRequest` / `CreateDirectoryResponse`; `DownloadFileRequest` / `DownloadFileResponse`). +- **Category:** 7 (overly verbose), 9 (singular/plural mismatch — also: "contents" pluralised on request, dropped on response), 17 (inconsistent with the rest of the file). +- **Suggested name:** `ListDirectoryContentsResponse` to mirror the request. Or trim both to `ListDirectoryRequest` / `ListDirectoryResponse`. +- **Rationale:** Same endpoint, same operation — names should mirror. + +### 15. `executeCall` / `executeHttpCall` / `sendAndCheckError` / `buildHttpRequest` — `src/v2/utils.ts:26,65,168,96` + +```ts +export async function executeCall(call: Call, options?: CallOptions): Promise +export async function executeHttpCall(opts: HttpCallOptions): Promise +export async function sendAndCheckError(opts: HttpCallOptions): Promise +export function buildHttpRequest(method, url, headers, signal?, body?): HttpRequest +``` + +- **Why weird:** Four nearly-identical-sounding helpers in one file. `executeCall` wraps a `Call` (whatever a `Call` is — it's an opaque `(signal?) => Promise` function reference). `executeHttpCall` takes the actual HTTP request. `sendAndCheckError` is what `executeHttpCall` is but with a different return type (raw `HttpResponse` vs buffered `Uint8Array`). All four start with a verb but use different verbs (`execute`, `send`, `build`) for what amounts to "send this HTTP request and return something". The lowercase `'head'` HTTP method in two callers (`client.ts:600,637`) is an unrelated bug. +- **Category:** 17 (inconsistent verb cluster — execute/send/build), 6 (misleading — `executeCall` and `executeHttpCall` are different despite the matching prefix), 12 (duplicate concept — `executeHttpCall` and `sendAndCheckError` do almost the same thing). +- **Suggested name:** Collapse to one helper (`sendRequest`), let it return the raw `HttpResponse`, and have the caller buffer/stream as needed. Or, if both must exist: `sendAndBuffer` (returns buffered body) and `sendAndStream` (returns raw response). +- **Rationale:** Three functions doing nearly the same thing with names that differ in verb is a recipe for mis-imports. + +### 16. `path` as the only field in 5 request types — `src/v2/model.ts:23,45,160,213,224` + +```ts +Create: { path?: string; overwrite?: boolean } +Delete: { path?: string; recursive?: boolean } +GetStatus: { path?: string } +ListStatus: { path?: string } +MkDirs: { path?: string } +``` + +- **Why weird:** Five sibling types whose distinguishing identity is the type name (`Create`, `Delete`, etc.), not the field. The common field is just `path: string`. In TS, all five types are structurally compatible — `GetStatus` is assignable to `ListStatus` and vice versa; both are assignable to `MkDirs`. A caller can confidently pass `getStatus(req)` and a typo-narrowed `req: ListStatus` and TS won't complain (structural typing). +- **Category:** 1 (vague — `path` for everything), 6 (misleading — structural compat collapses semantic distinctions), 17 (inconsistent — sometimes called `path`, sometimes `filePath`, sometimes `directoryPath`). +- **Suggested name:** Use the discriminated field names from the modern API: `dbfsPath` everywhere on the legacy types; or split into `Create.filePath` (because `Create` is a write-stream open, ie file) and `MkDirs.directoryPath`. Helps callers see "this is a path to a file" vs "this is a path to a directory." +- **Rationale:** Structural typing makes the five types interchangeable — a name change is the cheapest defence. + +### 17. `Move.sourcePath` / `Move.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` + +```ts +export const marshalMoveSchema: z.ZodType = z + .object({ + sourcePath: z.string().optional(), + destinationPath: z.string().optional(), + }) + .transform(d => ({ + source_path: d.sourcePath, + destination_path: d.destinationPath, + })); +``` + +- **Why weird:** The wire keys are `source_path` / `destination_path` — but ALL other DBFS methods use a single `path` field. This is an entirely separate field-naming convention used in one method. Compare: `Delete.path` (not `target_path`), `GetStatus.path` (not `target_path`), but `Move.sourcePath` / `Move.destinationPath`. +- **Category:** 17 (inconsistent — single endpoint convention). +- **Suggested name:** Acceptable as-is (these are clearer than `path1`/`path2`). Flag only the inconsistency with the rest of the DBFS surface. +- **Rationale:** The inconsistency is upstream; the TS port should match. + +## Medium severity + +### 18. v1 `Client` constructor allows `host` to be undefined — `src/v1/client.ts:21` + +```ts +constructor(options: ClientOptions) { + if (options.host === undefined) { + throw new Error('Host is required.'); + } + this.host = options.host.replace(/\/$/, ''); + ... +} +``` + +`ClientOptions.host` is typed optional but in practice always required. Not a name bug per se — but `host` is also generic; `workspaceUrl`/`workspaceHost` would be clearer. Same critique on `v2/client.ts:103`. + +### 19. v1 `UploadRequest.contents` is `ReadableStream` but v2 `UploadFileRequest.contents` is bare `ReadableStream` — `src/v1/model.ts:11`, `src/v2/model.ts:281` + +```ts +// v1 +contents: ReadableStream; // required, generic +// v2 +contents?: ReadableStream | undefined; // optional, generic-erased +``` + +v2 weakens the type — both `ReadableStream` and `ReadableStream` would be more correct, but more importantly v1's `Uint8Array` constraint is gone. Same for `DownloadResponse.contents` vs `DownloadFileResponse.contents`. + +### 20. `bytesRead` vs `data` in `Read_Response` — singular/plural and naming mismatch — `src/v2/model.ts:267-275` + +```ts +export interface Read_Response { + bytesRead?: number | undefined; // count + data?: Uint8Array | undefined; // bytes +} +``` + +`bytesRead` (count) and `data` (the bytes) refer to the same byte slice. `bytesRead` is the LENGTH; `data` is the BUFFER. Cleaner: `bytes: Uint8Array` and `bytesRead: number` (count); even better, drop `bytesRead` since `data.byteLength` is the same value. + +### 21. `ifUnmodifiedSince` — verb-as-noun field — `src/v2/model.ts:101,149` + +```ts +ifUnmodifiedSince?: string | undefined; +``` + +Mirrors the HTTP header name exactly. Faithful to RFC 9110, but as a TS field name `ifUnmodifiedSince` is a conditional, not a value. `unmodifiedSinceHeader: string` or `notModifiedSince: string` is more idiomatic. Acceptable as-is (HTTP convention), flagged only as observation. + +### 22. `range` (HTTP byte range header value) — same — `src/v2/model.ts:95,143` + +```ts +range?: string | undefined; +``` + +Field name `range` is overloaded (range of numbers? date range?). The doc clarifies "range of bytes to retrieve" — name could be `byteRange` or `rangeHeader`. + +### 23. `directoryPath` vs `path` — inconsistent across methods — `src/v2/model.ts:39,58,128,180` + +The modern Files API consistently uses `directoryPath` / `filePath`. The legacy DBFS uses just `path` even when the value is known to be a directory (`MkDirs.path`) or file (`Create.path`). In v1 it was always `filePath`. v2 has both. Choose: prefix every path with the kind, OR drop the prefix everywhere. + +### 24. `recursive` (Delete) — field name does not tell you what it does — `src/v2/model.ts:49` + +```ts +recursive?: boolean | undefined; +``` + +A `recursive: true` on a `Delete` could mean "follow symlinks", "descend into subdirs", etc. JSDoc clarifies "Whether or not to recursively delete the directory's contents." Name OK in context; would prefer `recursivelyDeleteContents: boolean` for self-documentation, but `recursive` is conventional. + +### 25. `overwrite` — same — `src/v2/model.ts:27,248,283` + +```ts +overwrite?: boolean | undefined; +``` + +Appears in `Create`, `Put`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `Create` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. + +### 26. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,194,196` + +```ts +contents?: DirectoryEntry[] | undefined; +nextPageToken?: string | undefined; // OK +// JSDoc: "the `next_page_token` in the response..." (line 194) +``` + +JSDoc strings reference the wire name (`next_page_token`), but the TS field is `nextPageToken`. The doc accurately reflects the wire — flagged because cross-referencing a wire name in user-facing JSDoc is confusing. Should reference the TS field name (`nextPageToken`). + +### 27. `pageSize` recommendation "We recommend not to set this value..." — `src/v2/model.ts:186` + +Doc says don't set the field. Then why is the field public? Name is fine; flagging the inconsistent guidance. + +### 28. `@typescript-eslint/naming-convention` eslint-disables for `_Response` types — `model.ts:12,20,30,52,165,218,229,238,250,266` + +Every legacy `Foo_Response` type carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive because the underscore violates TS PascalCase. Modern API peers (`CreateDirectoryResponse`, `DownloadFileResponse`) need no such directive. Two conventions, one file — surface friction every time the generator runs. + +### 29. v2 `listDirectoryContentsIter` — naming inconsistency with `listDirectoryContents` — `src/v2/client.ts:689` + +```ts +async listDirectoryContents(...): Promise +async *listDirectoryContentsIter(...): AsyncGenerator +``` + +`...Iter` is a Go-style suffix (the Go SDK has `ListAll` / `Iter` helpers). TS convention would be `listDirectoryContents` (returns one page) and `iterateDirectoryContents` / `listDirectoryEntries` (yields each item). The `Iter` suffix also collides with TS iterator conventions where the method is just `[Symbol.asyncIterator]()` on the result. + +### 30. `Read_Response.data: Uint8Array` is base64 on the wire — `src/v2/model.ts:273,419-424` + +```ts +unmarshalRead_ResponseSchema: ... + data: z.string().transform(s => Uint8Array.from(atob(s), c => c.charCodeAt(0))).optional() +``` + +The field is decoded from base64 on read; doc says "The base64-encoded contents of the file read." but the TS type is already `Uint8Array` (decoded). Consumers reading the docstring may think they have to decode themselves. Name could clarify: `bytes: Uint8Array` with doc "Already base64-decoded". + +### 31. v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export `DownloadRequest`/`DownloadResponse`-as-used — `src/v1/index.ts:3` + +```ts +export type {DownloadRequest, DownloadResponse, UploadRequest} from './model'; +``` + +v1 exports `DownloadRequest`/`DownloadResponse` but the v1 client has NO download method. Dangling types — see net assessment. + +### 32. `marshalRequest` returns a `string` — name implies object — `src/v2/utils.ts:119` + +```ts +export function marshalRequest(data: unknown, schema: z.ZodType): string { + return JSON.stringify(schema.parse(data)); +} +``` + +The verb "marshal" typically returns a marshalled object, not its serialised form. Name suggests "convert object to wire shape" but actually does "convert to wire JSON string". `serializeRequest` or `marshalRequestJson` would be more honest. + +### 33. `parseResponse` is asymmetric with `marshalRequest` — `src/v2/utils.ts:113` + +```ts +export function parseResponse(body: Uint8Array, schema: z.ZodType): T +export function marshalRequest(data: unknown, schema: z.ZodType): string +``` + +`parseResponse` and `marshalRequest` are inverse operations, but the verb pair is non-symmetric: `parse` ↔ `format` (or `marshal` ↔ `unmarshal`). Should be `marshalRequest`/`unmarshalResponse` OR `serializeRequest`/`parseResponse` — not the mix. + +### 34. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` + +Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. + +### 35. `readAll` is duplicated — `src/v1/utils.ts:23` and `src/v2/utils.ts:40` + +Same conceptual helper, two implementations (v1 uses `new Response(body).arrayBuffer()`, v2 walks the reader manually). Name OK; flagged as cross-version duplication. + +### 36. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` + +```ts +const PACKAGE_SEGMENT = { + key: pkgJson.name.replace(/^@[^/]+\//, ''), + value: pkgJson.version, +}; +``` + +SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. This is a plain object; `packageSegment` is fine. + +### 37. `HttpCallOptions` duplicated across files — `src/v1/utils.ts:13`, `src/v2/utils.ts:15` + +```ts +export interface HttpCallOptions { + readonly request: HttpRequest; + readonly httpClient: HttpClient; + readonly logger: Logger; +} +``` + +Same name, same shape, in two files in the same package. Should be shared / re-exported. + +## Low severity + +### 38. v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` — `src/v1/utils.ts:36`, `src/v2/utils.ts:156` + +Same function, renamed in v2. Good rename (v2's is more accurate), but the rename means a v1 user upgrading sees an unexplained name change. + +### 39. `Move.sourcePath` / `Move.destinationPath` — could be `source` / `destination` — `src/v2/model.ts:233-236` + +The type name is `Move`; the fields are `sourcePath`/`destinationPath`. Inside a `Move` request, the `Path` suffix is redundant — `source: string; destination: string`. Acceptable; flagged because it's the longer form against the rest of the file's `path: string`. + +### 40. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` + +JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) + +### 41. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` + +Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. + +### 42. v2 `index.ts` exports neither `Client` constants nor `VERSION` — `src/v2/index.ts:3-6` + +```ts +export {Client} from './client'; +export {} from './model'; // <-- empty named export +``` + +Line 5 (`export {} from './model';`) is a no-op. Not a name bug, just dead syntax. + +### 43. `directoryPath ?? ''` fallback in client — `src/v2/client.ts:462,492,517,546,595,626,660,716` + +8 places where `directoryPath` is coerced to empty string. Field is typed optional but the URL must have it. Either type the field as required, or document the fallback. Name OK. + +### 44. v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" — `src/v1/client.ts:33-36` + +```ts +/** + * ... + * Because the request body is a ReadableStream which can only be consumed + * once, this method does not retry on failure. ... + */ +async upload(req: UploadRequest, options?: CallOptions): Promise { +``` + +`upload` is the name; the JSDoc tells you it doesn't retry. v2 inherits the same property for `uploadFile` but the doc on `client.ts:706` doesn't say so. Inconsistent docs across versions. + +### 45. `unmarshal*Schema` constant names — `src/v2/model.ts:290-431` + +19 exported constants named `unmarshalSchema`. Verbose but consistent. Acceptable. + +### 46. `marshal*Schema` constant names — `src/v2/model.ts:433-510` + +7 exported constants. Acceptable; mirror of unmarshal. + +### 47. `pkgJson.name.replace(/^@[^/]+\//, '')` — `src/v2/client.ts:90` + +Inlined regex to strip `@scope/` prefix. Should be a helper named `packageName`. Not a naming issue per se. + +### 48. v1 imports `@databricks/sdk-core/http` (not `@databricks/sdk-databricks/http`) — `src/v1/client.ts:9` + +Different package than the audit but worth flagging: v1 still uses `sdk-core` while v2 uses `sdk-databricks` for some imports — internal inconsistency. + +## Observations + +### 49. The empty `export {} from './model';` line — `src/v2/index.ts:5` + +Likely a generator artifact; no impact. + +### 50. v1 has 78 lines of utils for one operation; v2 has 196 lines of utils for ten operations — files are well-sized. + +### 51. `Client` constructor's User-Agent code is duplicated across packages — out of scope here. + +### 52. `'head'` HTTP method passed in lowercase to `buildHttpRequest` — `src/v2/client.ts:600,637` + +```ts +const httpReq = buildHttpRequest('head', url, headers, callSignal); +``` + +Other calls use `'POST'`/`'GET'`/`'PUT'`/`'DELETE'` uppercase. Cosmetic — actual bug because `buildHttpRequest` does not normalise — but flagged here as casing inconsistency. + +### 53. `read()` JSDoc references `RESOURCE_DOES_NOT_EXIST`, `MAX_READ_SIZE_EXCEEDED`, `INVALID_PARAMETER_VALUE` — strings, not enums — `src/v2/client.ts:412-418` + +Error codes are referenced as freeform strings in JSDoc. Out of naming scope. + +### 54. `listDirectoryContentsIter` is the only iterator method on the client — `src/v2/client.ts:689` + +The legacy `list` does not have an `Iter` variant (it doesn't paginate). Asymmetry of pagination support across the legacy/modern surfaces, reflected in method naming. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md new file mode 100644 index 00000000..897326d2 --- /dev/null +++ b/.agent/naming-audit/forecasting.md @@ -0,0 +1,936 @@ +# Naming Audit: `forecasting` (v1) + +**Package:** `@databricks/sdk-forecasting` +**Path:** `/home/parth.bansal/sdk-js/packages/forecasting/` +**Version audited:** `v1` +**Files audited:** +- `src/v1/model.ts` +- `src/v1/client.ts` +- `src/v1/utils.ts` +- `src/v1/index.ts` + +This audit applies the 20 numbered concern categories from the audit +checklist. Each finding lists the offending identifier(s), the +category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete +rename suggestion. Findings are grouped by category. Generator-driven +items (such as the proto-style underscored nested-message names and +`marshal`/`unmarshal` schema prefixes) are flagged as `LOW` because +they are codified across the entire generated SDK surface — they +should be fixed at the generator, not by hand-editing this package. + +--- + +## Inventory + +### Enums (`model.ts`) + +| Name | Members | +| ----------------------------- | ------- | +| `ForecastingExperiment_State` | `PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`, `CANCELLED` | + +### Interfaces (`model.ts`) + +`CreateForecastingExperimentRequest`, +`CreateForecastingExperimentResponse`, `ForecastingExperiment`, +`GetForecastingExperimentRequest`. + +### Schemas (`model.ts`) + +`unmarshalCreateForecastingExperimentResponseSchema`, +`unmarshalForecastingExperimentSchema`, +`marshalCreateForecastingExperimentRequestSchema`. + +### Client classes and methods (`client.ts`) + +- Class `Client` + - Method `createForecastingExperiment` + - Method `createForecastingExperimentWaiter` + - Method `getForecastingExperiment` +- Class `CreateForecastingExperimentWaiter` + - Field `experimentId` + - Method `wait` + - Method `done` +- Local helper class `StillRunningError` + +### Utility functions (`utils.ts`) + +`executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, +`parseResponse`, `marshalRequest`, `flattenQueryParams`. + +### Utility types/interfaces (`utils.ts`) + +`HttpCallOptions`. + +--- + +## Findings + +### 1. Vague / generic names + +#### F1.1 — `Client` class name (MEDIUM) +- **Where:** `client.ts:42`, `index.ts:3`. +- **Why flagged:** Every package in this SDK exports a `Client`. + Re-exported in a barrel like + `import {Client as ForecastingClient} from '@databricks/sdk-forecasting'` + it is fine, but unqualified `Client` symbol-shadows aggressively. + This is a project-wide pattern, not a forecasting-specific issue. +- **Suggestion:** Either keep `Client` and document the + package-qualified import convention, or rename to + `ForecastingClient` consistently across packages. Cross-cutting. + +#### F1.2 — `req` parameter on every client method (LOW) +- **Where:** `client.ts:69, 100, 114`. +- **Why flagged:** `req` is a Go-ism (see category 14). It is also + generic — a reader has to look at the type to know what the + request is. +- **Suggestion:** Use a domain-meaningful parameter name + (`experiment`, `request`) for stylistic consistency with `options`. + +#### F1.3 — `primaryMetric: string` (MEDIUM) +- **Where:** `model.ts:34`. +- **Why flagged:** "Primary metric" without enumeration is vague. + JSDoc says only "The evaluation metric used to optimize the + forecasting model" with no enumeration of permitted values. By + contrast, `forecastGranularity` JSDoc lists allowed values inline. + The user has no way to know what to pass. +- **Suggestion:** Document allowed values in JSDoc (e.g. `mae`, `mse`, + `rmse`, `mape`, `mdape`, `smape`), or introduce a string-literal + union type `PrimaryMetric = 'mae' | 'mse' | …`. Naming itself is + fine; signal loss happens at the field level. + +#### F1.4 — `state` field on `ForecastingExperiment` (LOW) +- **Where:** `model.ts:78`. +- **Why flagged:** "state" alone is generic. Consistent with proto + enum naming so likely acceptable. In TS, `status` is more idiomatic + for read-only lifecycle indicators returned by an API; "state" is + more common for owned/mutable state. Minor. +- **Suggestion:** Keep for parity with Go/proto. Note that the + internal poll variable in `client.ts:160, 202` is named `status`, + exposing the field/local terminology drift. + +#### F1.5 — `target` is *not* present here (note) +- Unlike many sibling packages, this package's request payload uses + domain-specific column names (`targetColumn`, `splitColumn`, + `timeColumn`, `customWeightsColumn`) which is *good* and is the + pattern other packages should follow. Worth noting as a positive + example. + +--- + +### 2. Redundant enum prefixes + +#### F2.1 — `ForecastingExperiment_State` members (acceptable) +- **Where:** `model.ts:6-17`. +- **Why flagged:** The members are `PENDING`, `RUNNING`, `SUCCEEDED`, + `FAILED`, `CANCELLED`. None of them re-prefix the enum name (e.g. + no `STATE_PENDING`). Good shape. +- **Suggestion:** No change. + +--- + +### 3. Acronym casing inconsistencies + +#### F3.1 — `Id` vs `ID` (LOW, cross-cutting) +- **Where:** `model.ts:68, 74, 83`, `client.ts:104-109, 141, 155, 197`, + `index.ts:12`. +- **Why flagged:** This SDK uses **lower-camel `Id`** consistently + (`experimentId`). That is internally consistent within the package. + The TS/JS community is split — DOM uses `nodeId`/`HTMLElement`, + TypeScript itself uses `id`/`uuid` — so `Id` is defensible. +- **Suggestion:** Keep `Id`. The cross-package convention is already + in place. + +#### F3.2 — `URL` / `Url` consistency (acceptable) +- `client.ts` consistently uses `url` (lowercase) as a local var. + `experimentPageUrl` (model.ts:76) uses `Url`. No casing + inconsistency observed within the file. + +#### F3.3 — `HTTP` / `Http` (acceptable for this file) +- `utils.ts` consistently uses `Http` PascalCase (`HttpClient`, + `HttpRequest`, `HttpResponse`, `HttpCallOptions`, + `executeHttpCall`, `buildHttpRequest`). `client.ts:81, 122` uses + `httpReq` (lowercase prefix, PascalCase noun). Consistent. + +#### F3.4 — `RPC` in JSDoc (LOW) +- **Where:** `client.ts:112` — JSDoc "Public RPC to get forecasting + experiment". +- **Why flagged:** Documentation, not an identifier. Mentioning + "RPC" leaks the Go/proto vocabulary into user-facing JSDoc; + TS users do not typically think of method calls as "RPCs". + See also F14 for Go-ism flavor. +- **Suggestion:** Rewrite JSDoc as "Fetches a forecasting + experiment by ID." + +--- + +### 4. Underscores in TS identifiers + +> The TypeScript style guide (Google) and the SDK's own +> `typescript.mdc` disallow `snake_case` and underscores in +> identifiers. The generator emits proto-style "outer_inner" names +> as `Outer_Inner` to disambiguate nested messages — but TS would +> normally fold these into namespaces or flat PascalCase. + +#### F4.1 — `ForecastingExperiment_State` (HIGH, cross-cutting, + generator concern) +- **Where:** `model.ts:6`, `client.ts:28, 166, 169-170, 208-210`, + `index.ts:5`. +- **Why flagged:** Requires + `eslint-disable-next-line @typescript-eslint/naming-convention` + (model.ts:5). That alone is a smell. The TypeScript-idiomatic + equivalents would be either a nested namespace + (`namespace ForecastingExperiment { export enum State { … } }`) or + flat PascalCase (`ForecastingExperimentState`). +- **Suggestion:** Drop the underscore at the generator level. Two + viable shapes: + 1. **Flat PascalCase** — `ForecastingExperimentState`. + 2. **Namespace nesting** — keep parent name, drop underscore: + `ForecastingExperiment.State`. + Approach (1) is more straightforward for tree-shaking and module + re-exports; approach (2) more closely mirrors the proto nesting. + +#### F4.2 — Wire-protocol snake_case in `marshal`/`unmarshal` body + (acceptable) +- **Where:** `model.ts:89, 98-99, 110-145`. +- **Why flagged:** Field names like `experiment_id`, `train_data_path` + inside the `z.object({...})` are wire shapes, not identifiers. + Required for JSON parsing. +- **Suggestion:** Leave as-is. They are correctly scoped to the + schema definition. + +#### F4.3 — JSDoc comment "double-slash" artifact in + `splitColumn` (LOW) +- **Where:** `model.ts:41`. +- **Why flagged:** The JSDoc reads `/** // The column ... */` — an + extra `//` was carried through from the source. Cosmetic bug; + not strictly a naming issue but noticed during inventory. +- **Suggestion:** Fix at generator: strip leading `// ` from JSDoc + text. + +--- + +### 5. Cryptic abbreviations + +#### F5.1 — `req` (LOW, Go-ism) +- **Where:** `client.ts:69, 100, 104, 114, 117`. +- Already flagged under F1.2 / F14.1. + +#### F5.2 — `resp` (LOW, Go-ism) +- **Where:** `client.ts:77, 87, 103-104, 118, 128, 153, 160, + 167, 195, 202`; `utils.ts:73, 81, 83, 88`. +- See F14.2. + +#### F5.3 — `respBody` (LOW) +- **Where:** `client.ts:82, 123`. +- **Why flagged:** "resp" abbreviation. Spell out `responseBody` + for clarity in TS where verbosity is cheap. +- **Suggestion:** `responseBody`. + +#### F5.4 — `httpReq` (LOW) +- **Where:** `client.ts:81, 122`. +- **Why flagged:** `httpRequest` is clearer and matches the type + `HttpRequest` exactly. +- **Suggestion:** `httpRequest`. + +#### F5.5 — `apiErr` (LOW) +- **Where:** `utils.ts:88, 89`. +- **Why flagged:** `apiError` reads better; "err" is a Go-ism. +- **Suggestion:** `apiError`. + +#### F5.6 — `pkgJson` (LOW) +- **Where:** `client.ts:20, 36, 37`. +- **Why flagged:** "pkg" abbreviation. `packageJson` is two extra + characters and unambiguous. +- **Suggestion:** `packageJson`. + +#### F5.7 — `msg` (LOW) +- **Where:** `client.ts:171, 172`. +- **Why flagged:** `const msg = '(no message)';` — short variable + name for a one-shot constant. Marginal. +- **Suggestion:** Either inline the literal + (`` `terminal state ${status}: (no message)` ``) or rename to + `message`. The variable currently exists for no reason — its + initializer is a literal and it is used once. + +#### F5.8 — `opts`, `e`, `acc`, `val` (LOW) +- **Where:** `utils.ts:30, 55, 76, 137`. +- **Why flagged:** + - `acc` (utils.ts:55) — reduce accumulator, conventional. OK. + - `val` (utils.ts:137) — local destructure, OK. + - `opts` (utils.ts:66, 68, 73, 75, 81, 83, 88) — Go-ism; + `options` is preferred but `opts` is widely used in JS + libraries. **Inconsistent with itself:** the public parameter + name is `options` (utils.ts:28) but the internal one is `opts` + (utils.ts:30, 66). Pick one. + - `e` for the caught exception (utils.ts:76) — TS guidance + accepts `err`/`error`/`e`; match the file's other usages + (`apiErr`). +- **Suggestion:** rename `opts → options` inside `executeHttpCall` + for consistency; leave `acc`, `val`, `e` alone. + +#### F5.9 — `resp` as a poll-result variable (LOW) +- **Where:** `client.ts:103, 153, 167, 195` — `pollResp`. +- **Why flagged:** `pollResp` is a doubly-truncated name. Either + `pollResponse` or `poll` would read more naturally. +- **Suggestion:** `pollResponse` (matches expansion of `resp`) or + inline the call entirely. + +--- + +### 6. Misleading names + +#### F6.1 — `state` returned vs `status` used internally (LOW) +- **Where:** `model.ts:78`, `client.ts:160, 162, 202, 204`. +- **Why flagged:** The wire field is `state`, decoded into + `ForecastingExperiment.state`. Inside the waiter, the value is + reassigned to a local named `status` and the error message says + "response missing required status field". This is misleading — + the field that is required is `state`, not `status`. +- **Suggestion:** Rename the locals to `state` to match the + domain term, or rename the field to `status` (less invasive in + TS but breaks parity). + +#### F6.2 — `done` method on the waiter does not return a boolean of + "I'm done waiting" but "operation has reached a terminal state" + (LOW) +- **Where:** `client.ts:194-215`. +- **Why flagged:** Method `done()` returns `Promise` and + performs a poll. A naive reader might assume `done()` reflects + internal waiter state (similar to `Promise.resolve(done)` or + `IteratorResult.done`). It actually issues an HTTP `GET`. +- **Suggestion:** Rename to `isTerminal()`, `isFinished()`, or + `checkDone()` to signal that it polls the server. The JSDoc + ("Checks whether the operation has reached a terminal state.") + does clarify this, but the name does not. + +#### F6.3 — `createForecastingExperimentWaiter` returns the waiter, + not the response (LOW) +- **Where:** `client.ts:99-110`. +- **Why flagged:** The method name suggests "create a waiter," but + it actually performs the *create* call first and then wraps the + result. The return type + (`CreateForecastingExperimentWaiter`) suggests the second + interpretation correctly, but the verb `create` is overloaded: + the same word is used for the API call and the waiter + instantiation. +- **Suggestion:** Rename to + `createForecastingExperimentAndWait` (mirroring "AndWait" + patterns) or `startForecastingExperiment` (and have the waiter + type be `ForecastingExperimentRun` or similar). The current name + reads as if it merely *constructs* a waiter without side effects. + +#### F6.4 — `(no message)` placeholder string (LOW, doc/UX) +- **Where:** `client.ts:171-172`. +- **Why flagged:** Not strictly naming. The thrown error has the + literal text `(no message)`. There is no field on + `ForecastingExperiment` that carries a failure message, so the + waiter cannot do better — but the placeholder is a code smell. +- **Suggestion:** Either add a `message`/`error` field to + `ForecastingExperiment` (server contract) or drop the placeholder + and throw `new Error(``terminal state ${status}``)`. + +#### F6.5 — `flattenQueryParams` is exported but unused in this + package (LOW) +- **Where:** `utils.ts:123-150`. +- **Why flagged:** The name suggests it is a query-param helper for + this client; the client does not call it (only `POST` with body + and `GET` with path param, no `URLSearchParams` usage). The + function is dead code inside this package. Either there is an + intended caller that has not landed, or the helper should not be + in this package. +- **Suggestion:** Move shared helpers to `@databricks/sdk-core` or + delete from this package's `utils.ts`. + +#### F6.6 — `createDefault` in client construction (LOW) +- **Where:** `client.ts:6, 57`. +- **Why flagged:** Documentation, not identifier. The imported + function is `createDefault` from `clientinfo`. The name + `createDefault` is vague at the import site — without reading + the source, it is unclear that it creates a *user-agent + client-info builder*. Imported in every package. +- **Suggestion:** Cross-cutting upstream rename + (`createClientInfo` / `defaultClientInfo`). Out of scope here. + +--- + +### 7. Overly verbose + +#### F7.1 — `ForecastingExperiment` (MEDIUM) +- **Where:** `model.ts:72`. +- **Why flagged:** Inside a package literally named `forecasting`, + every type is about forecasting. The `Forecasting` prefix doesn't + add signal. Users will write + `import {ForecastingExperiment} from '@databricks/sdk-forecasting'` + — the `Forecasting` is said twice. +- **Suggestion:** Rename to `Experiment`. The package name carries + the qualifier. Combined with F7.2 / F7.3 this collapses naming + significantly. **Caveat:** `Experiment` is the same name used by + the MLflow `experiments` API. If both packages are likely to be + imported together, the qualification helps. Worth a cross-package + review. + +#### F7.2 — `CreateForecastingExperimentRequest`, + `CreateForecastingExperimentResponse`, + `GetForecastingExperimentRequest` (MEDIUM) +- **Where:** `model.ts:19, 66, 81`; `index.ts:8-12`. +- **Why flagged:** 33-34 character type names. Combined with method + names that already say `createForecastingExperiment(...)`, the + argument type is highly redundant. Compare typical TS SDK patterns: + `client.forecasting.create(req: CreateRequest)` or + `client.experiments.create(...)`. +- **Suggestion:** Drop the `Forecasting` token from request types: + `CreateExperimentRequest`, `CreateExperimentResponse`, + `GetExperimentRequest`. Or, if collapsed to a single client method + per verb, just `CreateRequest`/`CreateResponse`/`GetRequest`. + +#### F7.3 — `CreateForecastingExperimentWaiter` (HIGH) +- **Where:** `client.ts:138`, `index.ts:3`. +- **Why flagged:** 34 characters. Reads as + "Create-Forecasting-Experiment-Waiter". With `Forecasting` removed + (F7.1), it becomes `CreateExperimentWaiter` — still long but + workable. Alternative: drop `Create` since the waiter exists only + for create-style long-running operations, and name it + `ExperimentRun` or `Operation`. +- **Suggestion:** Rename to `ExperimentRun` (analogous to + `LongRunningOperation` in other SDKs). Combined with F6.3, the + flow becomes + `const run = await client.forecasting.startExperiment(req); + await run.wait();`. + +#### F7.4 — `createForecastingExperimentWaiter` method (HIGH) +- **Where:** `client.ts:99`. +- **Why flagged:** 35 character method name. Same issue as F7.3. +- **Suggestion:** Rename to `startExperiment` (or `createAndWait`) + to match a renamed waiter. + +#### F7.5 — `getForecastingExperiment` / `createForecastingExperiment` + methods (MEDIUM) +- **Where:** `client.ts:68, 113`. +- **Why flagged:** Inside a `Forecasting` client, the `Forecasting` + suffix is repetitive. Compare typical TS SDK shape: + `forecasting.experiments.create(...)`, + `forecasting.experiments.get(...)`. +- **Suggestion:** Either nest `experiments` as a sub-client + (`forecasting.experiments.create`) or simplify to `create`, + `get`. The class itself already conveys "forecasting". + Cross-cutting convention. + +#### F7.6 — `marshalCreateForecastingExperimentRequestSchema` and + `unmarshalCreateForecastingExperimentResponseSchema` (LOW) +- **Where:** `model.ts:86, 108`. +- **Why flagged:** 47 / 51 character schema constant names. Long + but mechanical. Inherits length from the underlying type name + plus `marshal`/`Schema` affixes. +- **Suggestion:** Once F7.1/F7.2 are applied at generator level, + these collapse to `marshalCreateExperimentRequestSchema` etc. + Cross-cutting. + +#### F7.7 — `timeseriesIdentifierColumns` (LOW) +- **Where:** `model.ts:50`. +- **Why flagged:** 27 character field name. "Time series identifier + columns" is long-form; "series ID columns" or `seriesIdColumns` + is shorter. The Go wire field is `timeseries_identifier_columns`, + so parity is the constraint. +- **Suggestion:** Keep for parity with Go/proto. Note the verbose + shape for future generator-level optimization. + +--- + +### 8. Redundant suffixes + +#### F8.1 — `Request` / `Response` on every request/response type + (acceptable) +- **Where:** `model.ts:19, 66, 81`. +- **Why flagged:** `CreateForecastingExperimentRequest`, + `CreateForecastingExperimentResponse`, + `GetForecastingExperimentRequest` — these suffixes are + generator-uniform and disambiguate request from response (which + share a verb). Standard SDK convention. +- **Suggestion:** Keep, but apply with F7.2 to drop `Forecasting`. + +#### F8.2 — `Waiter` suffix on `CreateForecastingExperimentWaiter` + (LOW) +- **Where:** `client.ts:138`. +- **Why flagged:** `Waiter` is a Go SDK pattern for long-running + operations. In TS/JS the more common terms are `Operation`, + `Poller`, `Run`, or `Tracker`. `Waiter` isn't wrong but it is + Go-flavored. +- **Suggestion:** Rename suffix to `Operation` or `Run` (e.g. + `ExperimentRun`). See F7.3. + +#### F8.3 — `Schema` suffix on Zod constants (acceptable) +- **Where:** `model.ts:86, 95, 108`. +- The `…Schema` suffix matches Zod community convention. No issue. + +--- + +### 9. Singular / plural mismatches + +#### F9.1 — `holidayRegions: string[]` (LOW) +- **Where:** `model.ts:48`. +- **Why flagged:** JSDoc says "The region code(s) to automatically + add holiday features. **Currently supports only one region.**" + The field is a plural array but server semantics are singular. +- **Suggestion:** API-shape concern; the spec retains a list for + forward-compat. Document the invariant clearly. Not a TS rename + issue. + +#### F9.2 — `trainingFrameworks: string[]` (acceptable) +- Plural-array, no mismatch. + +#### F9.3 — `includeFeatures: string[]` (acceptable) +- Plural-array, no mismatch. + +#### F9.4 — `timeseriesIdentifierColumns: string[]` (acceptable) +- Plural-array, plural meaning. + +#### F9.5 — `experiments` collection method missing (note) +- The client exposes `getForecastingExperiment` (singular) but no + `listForecastingExperiments` (plural). This is an API-completeness + observation, not a naming finding — if `list` is later added it + should be named consistently. + +--- + +### 10. Reserved-word / built-in collisions + +#### F10.1 — `state` field (LOW) +- **Where:** `model.ts:78`. +- **Why flagged:** `state` shadows nothing reserved in JS/TS but + is a popular React property name. Acceptable here because the + field is on `ForecastingExperiment`, not on an array or + component. +- **Suggestion:** Keep; not worth churn. + +#### F10.2 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) +- **Where:** `client.ts:194`. +- **Why flagged:** `done` shadows `IteratorResult.done` (the boolean + property returned by iterator `next()`). Defining a `done()` + *method* on a non-iterator class is mildly misleading. A reader + encountering `waiter.done` might first think of iteration. +- **Suggestion:** Rename to `isTerminal()` / `isFinished()` (see + F6.2). + +#### F10.3 — `wait` method (acceptable) +- `wait` is not reserved in JS/TS but is the name of an Atomics + primitive (`Atomics.wait`). Unlikely to be a real collision. + Keep. + +#### F10.4 — `Headers`, `URLSearchParams`, `TextDecoder`, `Error`, + `JSON` (acceptable) +- Used as global classes/objects, no shadowing. + +--- + +### 11. Empty / trivial wrapper types + +#### F11.1 — `StillRunningError` private throw-marker class (LOW) +- **Where:** `client.ts:40`. +- **Why flagged:** A zero-body subclass of `Error` used only as a + signal value for the retrier. This is the JS analog of Go's + sentinel error pattern. Acceptable, but a more idiomatic TS + approach is a tagged object or a symbol returned from the + predicate. +- **Suggestion:** Acceptable as written. If renamed, document + the contract. + +--- + +### 12. Duplicate concepts + +#### F12.1 — `experimentId` declared on both + `ForecastingExperiment`, + `CreateForecastingExperimentResponse`, and + `GetForecastingExperimentRequest` (LOW) +- **Where:** `model.ts:68, 74, 83`. +- **Why flagged:** Same conceptual ID name and type. Consistent — + this is *not* a naming issue, but a duplicate-field pattern. + Worth noting because some other packages (e.g. `budgets`) use + conflicting names for the same ID. +- **Suggestion:** No change. This is the desired state. + +#### F12.2 — Per-method header construction duplicated (LOW, code + style) +- **Where:** `client.ts:79-81, 120-122`. +- **Why flagged:** Every method runs: + ```ts + const headers = new Headers(...); + headers.set('User-Agent', this.userAgent); + ``` + Could be a private helper `this.buildHeaders(...)`. Not a naming + issue, but a code-duplication smell. +- **Suggestion:** Out of scope for naming audit. Mentioned for + completeness. + +#### F12.3 — `experimentPath` (request) vs `experimentPageUrl` + (response) — two URL-ish fields (LOW) +- **Where:** `model.ts:38, 76`. +- **Why flagged:** `experimentPath` is a *workspace* path + (`/Users/alice/myexperiment`) where the experiment is *stored*; + `experimentPageUrl` is the absolute UI URL. The semantic distinction + is real but the names are close enough that a casual reader could + conflate "path" and "URL". +- **Suggestion:** Keep, but ensure JSDoc on each makes the + distinction explicit. The current JSDoc on `experimentPath` + ("The path in the workspace to store the created experiment.") + is correct. + +#### F12.4 — `trainDataPath`, `predictionDataPath`, + `futureFeatureDataPath` (acceptable, but observe pattern) +- **Where:** `model.ts:21, 52, 63`. +- **Why flagged:** All three are "fully qualified path of a Unity + Catalog table." The pattern is consistent. Worth observing that + these aren't "paths" in the workspace sense — they're + catalog-schema-table identifiers (`catalog.schema.table`). + Calling them `Path` is mildly confusing because + `experimentPath` is *literally* a workspace path string. + See F16.1. + +--- + +### 13. Verb-tense inconsistency + +#### F13.1 — Method verbs (acceptable) +- `create*`, `get*` — uniform imperative present. Good. + +#### F13.2 — `marshalRequest` / `parseResponse` (LOW, asymmetry) +- **Where:** `utils.ts:113, 119`. +- **Why flagged:** `parse` vs `marshal` use different verbs for the + same kind of operation (JSON conversion). +- **Suggestion:** Use the same axis: either `marshal/unmarshal` + or `encode/decode` or `serialize/deserialize`. Cross-cutting. + +#### F13.3 — `unmarshalXSchema` / `marshalXSchema` constants (LOW) +- **Where:** `model.ts:86, 95, 108`. +- **Why flagged:** Naming pattern is correct (verb + noun + Schema), + but the verb form makes them read like functions, not constants. + They *are* values (`z.ZodType` objects). +- **Suggestion:** Rename to nouns: `createExperimentRequestSchema` + for marshalling, `experimentSchema` for unmarshalling. Cross- + cutting; tied to generator. + +#### F13.4 — `wait` vs `done` on the waiter (acceptable) +- Both are imperative single-word verbs. Match. Subject to F6.2 + / F10.2. + +--- + +### 14. Go / Java-style names + +#### F14.1 — `req`, `resp`, `err`, `Waiter`, `httpReq`, `apiErr`, + `pkgJson`, `opts`, `msg`, `pollResp` (HIGH, but cross-cutting) +- **Where:** + - `req` everywhere in `client.ts` + - `resp` everywhere in `client.ts` and `utils.ts:73, 81` + - `e` in `utils.ts:76` (with rethrow) + - `Waiter` suffix in `CreateForecastingExperimentWaiter` + - `httpReq` in client.ts:81, 122 + - `apiErr` in utils.ts:88 + - `pkgJson` in client.ts:20 + - `opts` in utils.ts:30, 66 + - `msg` in client.ts:171 + - `pollResp` in client.ts:153, 167, 195, 202 +- **Why flagged:** These are all classic Go idioms ported verbatim. + TS convention favors spelled-out names (`request`, `response`, + `error`, `httpRequest`, `apiError`, `packageJson`, `options`, + `message`, `pollResponse`). The `Waiter` pattern itself is also + Go-style; TS/JS generally uses "operation," "poller," or "run." +- **Suggestion:** Spell them out. Trivial diff, large readability + gain. This is a porting-convention decision and should be made + globally at the generator level. + +#### F14.2 — `marshal*` / `unmarshal*` schema prefixes (LOW) +- **Where:** `model.ts:86, 95, 108`. +- **Why flagged:** `marshal`/`unmarshal` is a Go term + (encoding/json). The JS/TS world says "serialize"/"deserialize" + or "encode"/"decode". `JSON.parse`/`JSON.stringify` is the + vernacular. `marshal` is recognizable but Go-flavored. +- **Suggestion:** Rename to `encode`/`decode` or + `serialize`/`deserialize`. Generator-level decision. + +#### F14.3 — `Schema` suffix on Zod constants (acceptable) +- The `…Schema` suffix matches Zod community convention. + +#### F14.4 — `_State` underscore-pseudo-nesting (HIGH) +- See F4.1. Underscores are foreign to TS. + +#### F14.5 — `Public RPC to get forecasting experiment` JSDoc (LOW) +- See F3.4. + +#### F14.6 — `terminal state` error message style (LOW) +- **Where:** `client.ts:172`. +- **Why flagged:** "terminal state" is Go-flavored language; TS/JS + user-facing errors more commonly say "operation failed" or + "experiment is in failed state." +- **Suggestion:** Rephrase the thrown error message for clarity. + +--- + +### 15. Generic field names losing meaning + +#### F15.1 — `state` (LOW) +- **Where:** `model.ts:78`. See F1.4 and F6.1. + +#### F15.2 — `primaryMetric: string` (MEDIUM) +- **Where:** `model.ts:34`. See F1.3. + +#### F15.3 — `req` parameter on every client method (HIGH) +- See F1.2 and F14.1. + +#### F15.4 — `registerTo: string` (MEDIUM) +- **Where:** `model.ts:46`. +- **Why flagged:** `registerTo` is a verb-phrase masquerading as a + noun field. The JSDoc clarifies it is "the fully qualified path + of a Unity Catalog model … used to store the best model." But the + name `registerTo` doesn't tell you *what* to register or *as what*. +- **Suggestion:** Rename to `modelRegistrationPath` / + `modelTargetName` / `registeredModelName`. Cross-cutting if other + packages share the pattern. + +#### F15.5 — `maxRuntime: number` (LOW) +- **Where:** `model.ts:40`. +- **Why flagged:** Units are missing from the field name. JSDoc says + minutes, but `maxRuntime: number` doesn't. +- **Suggestion:** Rename to `maxRuntimeMinutes`, or change the type + to a duration string (`ISO 8601` PT1H, etc.) if the API supports + it. Common SDK convention: suffix the unit on the field name. + +#### F15.6 — `forecastHorizon: number` (LOW) +- **Where:** `model.ts:32`. +- **Why flagged:** Similar units issue. The JSDoc explains "The + number of time steps into the future to make predictions, + calculated as a multiple of forecast_granularity." Units are + derived from another field — not from the name. +- **Suggestion:** Leave (units depend on granularity), but + ensure JSDoc is the source of truth. + +--- + +### 16. Field contradicting type domain + +#### F16.1 — `*Path` fields holding three-part catalog names (MEDIUM) +- **Where:** `model.ts:21 (trainDataPath), 52 (predictionDataPath), + 63 (futureFeatureDataPath)`. +- **Why flagged:** "Path" suggests a hierarchical workspace or + filesystem path. The values here are Unity Catalog three-part + names (`catalog.schema.table`), which are *not* slash-delimited + paths. The `experimentPath` field on the same type *is* a path + (workspace path). Domain dissonance within the same type. +- **Suggestion:** Rename `*Path` → `*Table` / + `*TableFullName` / `*TableName`. E.g. `trainingDataTable`, + `predictionDataTable`. Or use UC's term: `*Reference` + (`trainingDataReference`). + +#### F16.2 — `forecastGranularity: string` (LOW) +- **Where:** `model.ts:30`. +- **Why flagged:** Type is `string` but JSDoc enumerates discrete + values like `'1 second'`, `'Hourly'`, `'Yearly'`. This is a + string-typed enum. Compare F1.3. +- **Suggestion:** Introduce a string-literal union type + `ForecastGranularity = '1 second' | '1 minute' | … | 'Yearly'`, + or document acceptable strings in JSDoc more rigorously. + +#### F16.3 — `customWeightsColumn: string` (acceptable) +- Column name field with `string` type. Domain matches. + +--- + +### 17. Inconsistent action verbs + +#### F17.1 — `Get` vs `Create` (acceptable) +- Standard REST verbs. Good. + +#### F17.2 — `wait` vs `done` (LOW) +- **Where:** `client.ts:149, 194`. +- **Why flagged:** `wait()` is an action (returns when terminal); + `done()` is a query (returns bool now). Different axes — verb + and predicate. Common pattern, but the predicate name `done` + doesn't start with `is` or `has`, masking that it is a query. +- **Suggestion:** Rename `done` → `isDone` or `isTerminal`. See + F6.2 / F10.2. + +#### F17.3 — `createForecastingExperiment` vs + `createForecastingExperimentWaiter` (LOW) +- **Where:** `client.ts:68, 99`. +- **Why flagged:** Both start with `create`. The first creates an + experiment, the second creates a waiter (which itself triggers + creation as a side effect). Verb overloaded. See F6.3. +- **Suggestion:** Rename second to `startForecastingExperiment` + or `createAndWaitForecastingExperiment`. + +#### F17.4 — `marshal` / `unmarshal` vs `parse` (LOW) +- See F13.2 / F14.2. + +--- + +### 18. Long enum values + +#### F18.1 — `ForecastingExperiment_State` members (acceptable) +- **Where:** `model.ts:8-16`. +- **Why flagged:** Members are `PENDING`, `RUNNING`, `SUCCEEDED`, + `FAILED`, `CANCELLED`. Range 6-9 characters. Concise. +- **Suggestion:** None. + +--- + +### 19. Underspecified IDs + +#### F19.1 — `experimentId` (acceptable in this package) +- **Where:** `model.ts:68, 74, 83`. +- **Why flagged:** `experimentId` is the only ID in this package + and is consistent. Inside a `forecasting` package the term + "experiment" implies a forecasting experiment. **However**, the + MLflow `experiments` API also issues experiment IDs and has + type `Experiment`/`experimentId`. Cross-package confusion is + possible if both clients are in use. +- **Suggestion:** Acceptable as-is. If renamed in the future, a + domain qualifier such as `forecastingExperimentId` resolves the + ambiguity at the cost of verbosity. + +#### F19.2 — `experimentPath` (LOW) +- **Where:** `model.ts:38`. +- **Why flagged:** Workspace path. Unambiguous in context, but + competes for "experiment" mindshare with `experimentId`. + Marginal. +- **Suggestion:** Keep. + +--- + +### 20. Type-suffix tautology + +#### F20.1 — `ForecastingExperiment_State` enum + `state` field on + `ForecastingExperiment` (LOW) +- **Where:** `model.ts:6, 78`. +- **Why flagged:** Three layers of "Forecasting" / "Experiment" / + "State": `ForecastingExperiment.state: + ForecastingExperiment_State`. With underscore removal and + `Forecasting`-prefix drop, becomes + `Experiment.state: ExperimentState`. Tolerable. +- **Suggestion:** Tie to F4.1 / F7.1. + +#### F20.2 — Generic `*Schema` suffix (LOW) +- **Where:** `model.ts:86, 95, 108`. +- **Why flagged:** + `unmarshalCreateForecastingExperimentResponseSchema` is 51 + characters with "Schema" suffixed onto an already-typed + `z.ZodType<...>`. The `Schema` suffix is conventional in Zod + ecosystems though. +- **Suggestion:** Acceptable; tied to generator. + +--- + +## Package overlap: `forecasting` vs `experiments` + +This SDK ships both `@databricks/sdk-forecasting` and an MLflow-style +`experiments` API in `@databricks/sdk-experiments` (verify path). +The forecasting concept of an "experiment" is distinct from MLflow's +generic experiment but uses the same term and the same ID name. + +### F-OVERLAP.1 — `ForecastingExperiment` vs MLflow `Experiment` + (MEDIUM) +- **Why flagged:** Naive autocomplete on "Experiment" surfaces both + types. The forecasting experiment is a + *long-running training job* tracked by AutoML; the MLflow + experiment is a *grouping* of runs. Semantically very different. +- **Suggestion:** Keep `ForecastingExperiment` (do not drop the + qualifier from the type, despite F7.1 above) to maintain + disambiguation. Or, namespace this package's types under + `forecasting.Experiment` if the package adopts nested exports. + +### F-OVERLAP.2 — `experimentId` naming collision (LOW) +- Same field name used in both APIs but the IDs are not + interchangeable. Users should not pass an MLflow experiment ID to + forecasting or vice versa. +- **Suggestion:** Document explicitly in JSDoc that the ID is the + forecasting/AutoML experiment ID, not an MLflow experiment ID. + +--- + +## Summary table + +| # | Category | Findings | +| - | --------------------------------------- | -------- | +| 1 | Vague / generic | 5 (1 acceptable note) | +| 2 | Redundant enum prefixes | 1 (acceptable) | +| 3 | Acronym casing | 4 (2 acceptable) | +| 4 | Underscores in TS identifiers | 3 (1 acceptable) | +| 5 | Cryptic abbreviations | 9 | +| 6 | Misleading names | 6 | +| 7 | Overly verbose | 7 | +| 8 | Redundant suffixes | 3 (2 acceptable) | +| 9 | Singular / plural mismatch | 5 (3 acceptable + 1 note) | +| 10 | Reserved-word collisions | 4 (2 acceptable) | +| 11 | Empty / trivial wrappers | 1 | +| 12 | Duplicate concepts | 4 | +| 13 | Verb-tense inconsistency | 4 (2 acceptable) | +| 14 | Go / Java-style names | 6 | +| 15 | Generic field names | 6 | +| 16 | Field contradicting type domain | 3 (1 acceptable) | +| 17 | Inconsistent action verbs | 4 (1 acceptable) | +| 18 | Long enum values | 1 (acceptable) | +| 19 | Underspecified IDs | 2 (1 acceptable) | +| 20 | Type-suffix tautology | 2 | +| OVERLAP | forecasting vs experiments | 2 | + +--- + +## Top 10 highest-impact renames (recommended order) + +1. **F4.1 / F14.4:** Replace underscored `ForecastingExperiment_State` + with flat PascalCase `ForecastingExperimentState` or + namespace nesting. Eliminates the `eslint-disable` comment. +2. **F6.3 / F7.4 / F17.3:** Rename + `createForecastingExperimentWaiter` to + `startForecastingExperiment` (or `createAndWait…`) to remove the + "create" verb overload. Rename `CreateForecastingExperimentWaiter` + class to `ForecastingExperimentRun` or `…Operation` (F7.3 / F8.2). +3. **F6.2 / F10.2 / F17.2:** Rename waiter `done()` method to + `isTerminal()` (or `isDone()`) to signal that it is a + server-poll predicate, not iterator state. +4. **F16.1:** Rename `*Path` fields that hold Unity Catalog + three-part names to `*Table` (e.g. `trainDataPath → + trainingDataTable`, `predictionDataPath → + predictionsTable`, `futureFeatureDataPath → + futureFeaturesTable`). Distinguishes them from `experimentPath` + which is a real workspace path. +5. **F15.4:** Rename `registerTo` to + `registeredModelName` (or `modelRegistrationTarget`). The + verb-phrase field name is confusing. +6. **F15.5:** Rename `maxRuntime` → `maxRuntimeMinutes` to embed + units in the name. +7. **F1.3 / F16.2:** Introduce string-literal union types for + `primaryMetric` and `forecastGranularity`. Improves + discoverability and type safety. +8. **F6.1:** Align waiter local variable name (`status`) with the + field it reads (`state`). Update error message wording. +9. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ + `pkgJson`/`msg`/`pollResp`/`httpReq`/`apiErr` across all + generated code. +10. **F7.1 / F7.2:** Drop the redundant `Forecasting` token from + type names where the package qualifier already conveys domain + (`ForecastingExperiment` → `Experiment`, + `CreateForecastingExperimentRequest` → `CreateExperimentRequest`, + etc.) — subject to the cross-package conflict noted in + F-OVERLAP.1. + +--- + +## Notes / out-of-scope + +- All findings above relate to **generated** code. Code-base rule: + "Code generated from API definition by Databricks SDK Generator. + DO NOT EDIT." The fixes belong upstream in the generator and + spec. This audit is a backlog for that generator. +- The `utils.ts` file contains the same generic helpers + (`executeCall`, `parseResponse`, `marshalRequest`, + `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, + `readAll`) that every generated package duplicates. The + duplication itself is not a naming issue, but the *names* + (`marshal/unmarshal`) are Go-flavored and inconsistent + (`parseResponse` vs `marshalRequest`). +- This package has no `tests/` directory (verified by repo + structure check), so the audit does not cover test naming. +- The `flattenQueryParams` helper in `utils.ts` is exported but + never used in this package — see F6.5. +- The JSDoc on `splitColumn` (`model.ts:41`) has a stray `//` + prefix from the source — generator bug, see F4.3. diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md new file mode 100644 index 00000000..2f218ed1 --- /dev/null +++ b/.agent/naming-audit/functions.md @@ -0,0 +1,686 @@ +# Naming Audit: `functions` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/functions/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Unity Catalog Functions (SQL / Python UDFs and UDTFs). + +--- + +## Summary + +The `functions` package surfaces five UC function operations +(`createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, +`updateFunction`) plus a paginated iterator. The model layer mirrors +the Go SDK 1:1, so most issues are inherited from the upstream +definitions. The most pervasive problems are: (1) the package-level +name itself — `functions` and the field/type `function` collide with +JavaScript's `function` reserved word; (2) proto-style nested +identifiers (`FunctionInfo_RoutineBody`, `FunctionInfo_SqlDataAccess`, +`FunctionInfo_SecurityType`, `FunctionInfo_ParameterStyle`, +`DeleteFunction_Response`, `ListFunctions_Response`); (3) the cryptic +`fullNameArg` path-parameter field; and (4) widespread +`type*` and `parameter*` field prefixes that re-encode the parent +type's domain. + +--- + +## Findings + +### 1. Vague / generic names + +#### 1.1 `DeleteFunction.force` (model.ts:157) +Field name `force` is generic. Doc says "Force deletion even if the +function is notempty." (typo preserved). A function that "isn't +empty" — what does "empty" mean for a function? Probably a copy-paste +from the schema/catalog delete operations. The field name `force` +carries no information about *what* it overrides; consider +`forceDelete` or, better, surface the underlying constraint in the +name. + +#### 1.2 `FunctionParameterInfo.position` (model.ts:277) +Generic name on a field whose meaning is implementation-specific +(zero-indexed ordinal position). `parameterIndex` or +`ordinalPosition` would be unambiguous. Compare to `Position` types +in editors / DOM — `position` here is overloaded. + +#### 1.3 `FunctionParameterInfo.comment` (model.ts:285) +"User-provided free-form text description" — this is a description, +not a comment. `description` is what the field actually contains. +Same pattern repeats on `CreateFunction.comment`, `FunctionInfo.comment`, +`UpdateFunction.comment` (model.ts:119, 238, 383). + +--- + +### 2. Redundant enum prefixes + +#### 2.1 `FunctionParameterType` values `PARAM` / `COLUMN` (model.ts:39-42) +The enum is named `FunctionParameterType` and the variants are +`PARAM` and `COLUMN`. `PARAM` is fine; `COLUMN` is jarring as a +"parameter type" because the surrounding type names already declare +"parameter". The semantics (a parameter that is actually a table +column reference) get lost. Consider +`FunctionParameterType.COLUMN_REF` or rename the parent. + +#### 2.2 `FunctionInfo_ParameterStyle.S` (model.ts:44-47) +Single-variant enum with the variant `S`. The doc on the type-using +field says `**S** is the value for SQL.` So `S` is *the* SQL +parameter style. The single-letter variant is cryptic; even if it +preserves wire compatibility, the TypeScript surface should expose +`SQL` (and let the marshal layer translate to `S` on the wire). +See also §5.1. + +#### 2.3 `FunctionInfo_RoutineBody` values `SQL` / `EXTERNAL` (model.ts:49-59) +Variants are short and meaningful. `EXTERNAL` is the longer arm and +the description on `EXTERNAL` is multi-bullet. Variants OK; the +nested enum type-name is the issue — see §4.1. + +#### 2.4 `FunctionInfo_SecurityType.DEFINER` (model.ts:61-64) +Single-variant enum with `DEFINER`. The single-valued switch is +surfaced as a full enum type; the variant itself is meaningful (SQL +`SECURITY DEFINER` clause) but the TS-side ergonomics suffer from +the long nested enum name. + +#### 2.5 `FunctionInfo_SqlDataAccess` values `CONTAINS_SQL` / `READS_SQL_DATA` / `NO_SQL` (model.ts:66-71) +The enum name contains `SqlDataAccess` and every variant begins or +ends with `SQL`. Two of three variants repeat the `SQL` token from +the parent: `CONTAINS_SQL`, `READS_SQL_DATA`, `NO_SQL`. The repetition +is mild compared to the catalogs `DR_REPLICATION_STATUS_*` case, but +the type already says "SQL" — variants `CONTAINS`, `READS_DATA`, +`NONE` would be just as clear. + +#### 2.6 `ColumnTypeName` variants suffixed `_TYPE` (model.ts:31, 32) +`USER_DEFINED_TYPE`, `TABLE_TYPE`, `TABLEREF_TYPE`. The enum is +`ColumnTypeName` — `_TYPE` is redundant on each variant. Should be +`USER_DEFINED`, `TABLE`, `TABLEREF`. Note: see also §3.5 for +`TABLEREF`. + +--- + +### 3. Acronym casing inconsistencies (SQL, UDF, UDTF, JSON) + +#### 3.1 `FunctionInfo_SqlDataAccess` (model.ts:67) vs field `sqlDataAccess` (model.ts:101, 220, 365) +`SqlDataAccess` (PascalCase for the type) uses `Sql` as a word; +`sqlDataAccess` (camelCase field) uses `sql` lowercase. Both are +internally consistent for camelCase/PascalCase rules, but the +Databricks codebase elsewhere uses uppercase `SQL` (e.g. `sqlPath` +field, comments saying "SQL"). Google TS style guide treats SQL as a +three-letter acronym → `Sql`/`sql` is valid. Flagged for awareness. + +#### 3.2 `sqlPath` field (model.ts:115, 234, 379) +Consistent with §3.1: `sqlPath` rather than `sQLPath`. OK by Google +TS rules. + +#### 3.3 `typeJson` field (model.ts:267) +Field name `typeJson`. JSON is treated as `Json` per Google TS rules. +Consistent. + +#### 3.4 `typeText` field (model.ts:265) +Field name `typeText`. Doc says "Full data type spec, SQL/catalogString +text." OK as a name but ambiguous: is it SQL-formatted, JSON-formatted, +or arbitrary? + +#### 3.5 `TABLEREF_TYPE` enum variant (model.ts:32) +"TABLEREF" runs two words together — "Table Ref" / "Table Reference". +Should be `TABLE_REF` (or `TABLE_REFERENCE`, spelled out). The +codebase already uses underscores between words elsewhere +(`USER_DEFINED_TYPE`). See also §2.6. + +#### 3.6 `TIMESTAMP_NTZ` enum variant (model.ts:25) +`NTZ` is "No TimeZone". Three-letter acronym, kept uppercase here +which is consistent with `SQL` elsewhere. OK, but the meaning is +opaque to anyone unfamiliar with the Spark/Delta type system. The +ColumnTypeName enum has no JSDoc comments to explain `NTZ`, +`TABLEREF_TYPE`, `USER_DEFINED_TYPE`, `VARIANT`, etc. + +#### 3.7 "UDF" / "UDTF" never appear in identifiers +The package is *Unity Catalog Functions* — it covers both UDFs and +UDTFs (table-valued functions). Neither acronym appears in any +identifier or doc comment. The distinction is encoded in the +`routineBody` + `returnParams` combination, which is non-obvious. +Not a renaming issue per se, but a discoverability problem worth +flagging. + +--- + +### 4. Underscores in TypeScript identifiers + +This is the package's most widespread cosmetic issue. Proto-style +underscore separators appear in exported TS identifiers, each +silenced by a `@typescript-eslint/naming-convention -- Proto-style …` +disable comment. + +#### 4.1 `FunctionInfo_ParameterStyle` (model.ts:45) +Should be `FunctionParameterStyle` (or `ParameterStyle`, top-level). + +#### 4.2 `FunctionInfo_RoutineBody` (model.ts:50) +Should be `RoutineBody` or `FunctionRoutineBody`. + +#### 4.3 `FunctionInfo_SecurityType` (model.ts:62) +Should be `FunctionSecurityType` (or `SecurityType`). Note: the +catalogs and other packages also have `SecurityType`-flavoured enums; +disambiguation may need `FunctionSecurityType`. + +#### 4.4 `FunctionInfo_SqlDataAccess` (model.ts:67) +Should be `FunctionSqlDataAccess` or `SqlDataAccess` (top-level). + +#### 4.5 `DeleteFunction_Response` (model.ts:161) +Should be `DeleteFunctionResponse`. The underscore separator is the +naming issue here; the wrapper itself exists for forward +compatibility. + +#### 4.6 `ListFunctions_Response` (model.ts:319) +Should be `ListFunctionsResponse`. + +#### 4.7 `unmarshalDeleteFunction_ResponseSchema` / +`unmarshalListFunctions_ResponseSchema` (model.ts:431, 592) +Underscore leaks into schema exports. Should be +`unmarshalDeleteFunctionResponseSchema`, +`unmarshalListFunctionsResponseSchema`. + +--- + +### 5. Cryptic abbreviations + +#### 5.1 `FunctionInfo_ParameterStyle.S` (model.ts:46) +A bare letter `S` whose only documented purpose is "the value for +SQL". Cryptic — preserve wire compatibility in the marshal layer and +expose `SQL` as the TS variant. See also §2.2. + +#### 5.2 `fullNameArg` (model.ts:155, 294, 343) +Used as the function name path-parameter on `DeleteFunction`, +`GetFunction`, and `UpdateFunction`. The `Arg` suffix is jargon from +the Go generator distinguishing path arguments from request-body +fields with the same key. TypeScript callers have no need for this +distinction — the field is the function's fully-qualified name. See +also §13.1 and §11.3. + +#### 5.3 `pkgJson` (client.ts:19) +Internal variable name for `package.json`. Mild — flagged for +consistency with other audits. + +#### 5.4 `respBody` (client.ts:89, 126, 164, 217, 267) — internal-only; mild. + +#### 5.5 `typeText` / `typeJson` (model.ts:265, 267) +The `type*` prefix is fine within `FunctionParameterInfo`, but the +field names (`typeText`, `typeJson`, `typeName`, `typePrecision`, +`typeScale`, `typeIntervalType`) form a non-obvious "type-spec" +sub-record that arguably should be nested under a `type` object. +See also §12.4. + +--- + +### 6. Misleading names + +#### 6.1 `routineDependencies` doc comment lowercases "function" (model.ts:122, 241, 386) +JSDoc reads "function dependencies." (lowercase, mid-sentence). The +field name is `routineDependencies` and the doc says "function". The +package toggles between "routine" and "function" terminology +indiscriminately — see §6.3. + +#### 6.2 `DeleteFunction.force` doc has typo "notempty" (model.ts:156) +"Force deletion even if the function is notempty." Should be "not +empty". Doc bug, not a naming bug, but signals the field hasn't been +read recently. See also §1.1. + +#### 6.3 "Function" vs "Routine" terminology mixed everywhere +Every type and method speaks of `function*`. But every body-related +field speaks of `routine*`: `routineBody`, `routineDefinition`, +`routineDependencies`. The enum is `FunctionInfo_RoutineBody`. A +function's *body* is a *routine*. This split is a Go-port artifact +of the SQL standard's vocabulary (`CREATE PROCEDURE … LANGUAGE +SQL ROUTINE_BODY …`) — but for a TS consumer the inconsistency is +jarring. `body`, `definition`, `dependencies` (dropping `routine`) +would be cleaner. See also §6.1. + +#### 6.4 `parameterDefault: string` (model.ts:283) +Doc: "Default value of the parameter." The default of a function +parameter is rarely a string in the source domain — it might be a +number, a boolean, an interval, or even `NULL`. Typing it as `string` +implies serialised form, but the field name `parameterDefault` +doesn't signal that. Consider `parameterDefaultExpression` or +`parameterDefaultText`. + +#### 6.5 `specificName` reserved-for-future-use (model.ts:107, 226, 371) +Doc: "Specific name of the function; Reserved for future use." A +field whose name promises specificity and whose docs admit it's +unused is a future trap. Better to omit until it does something. + +#### 6.6 `inputParams` / `returnParams` use `Params` but the type uses `ParameterInfos` +(model.ts:87, 109, 206, 228, 351, 373) +The field abbreviates to `Params`; the type is `FunctionParameterInfos` +(no abbreviation). Pick one — abbreviate both (`Params` / +`ParameterInfos`?) or spell both out (`inputParameters` / +`returnParameters`). + +--- + +### 7. Reserved-word collisions + +#### 7.1 `Function` / `function` — the entire package name collides with a JS reserved word +(model.ts and across the file) + +`function` is a JavaScript reserved keyword +(). +`Function` is also the name of the global constructor for function +objects. Although TypeScript permits both as identifier names in +most positions, this package routinely uses them in ways that +collide: + +- The `Dependency.value` discriminated union (model.ts:170) uses + `$case: 'function'` and a `function` property as one arm of the + union. The runtime payload key is `function`, which means consumers + must write + `if (dep.value?.$case === 'function') { dep.value.function … }` — + reading `dep.value.function` is jarring next to other code that + treats `function` as a keyword. +- The unmarshal schema (model.ts:437, 447) reads + `function: z.lazy(() => unmarshalFunctionDependencySchema)` — + again the property name is `function`. +- The marshal schema (model.ts:727-728) similarly has + `$case: z.literal('function'), function: z.lazy(…)`. +- The Go-side wire format uses snake_case (`function`) so the field + is forced; renaming requires breaking compatibility. + +This is the package's single biggest naming hazard. A consumer +auto-completing `dep.value.` will see a property called `function` +adjacent to TS keyword highlighting in their editor. Consider +renaming the union arm to `functionRef`, `functionDependency`, or +nesting via a different discriminator. + +#### 7.2 `FunctionDependency` shadows `Function` constructor +The exported type `FunctionDependency` is fine on its own, but in +contexts where the SDK consumer also has `Function` (the global +constructor) in scope, the `Function*` prefix on multiple types is +crowded. + +#### 7.3 Type `FunctionInfo` is exported alongside the global `Function` +(model.ts:198, index.ts:25) +`FunctionInfo`, `CreateFunction`, `DeleteFunction`, `GetFunction`, +`ListFunctions`, `UpdateFunction`, `FunctionParameterInfo`, +`FunctionParameterInfos`, `FunctionDependency`, +`FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, +`FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess`, +`FunctionParameterMode`, `FunctionParameterType` — fifteen exports +prefixed with `Function`. While none conflict at the language level, +the prefix is so heavy that the global `Function` is easily +shadowed by the local imports. + +#### 7.4 `name` field +`name` is used as a body field on `CreateFunction`, `UpdateFunction`, +`FunctionInfo`, `FunctionParameterInfo` (model.ts:81, 200, 263, 345), +and again indirectly via `fullNameArg`. Not a reserved word but +shadows `Function.prototype.name` — common source of confusion when +callers spread request objects. + +#### 7.5 `options` parameter on every client method +(client.ts:79, 111, 149, 190, 232, 257) — the second parameter is +named `options` and shadows the marshal schema's `options`-style +metadata patterns. Not a collision in this package specifically but +consistent with the catalogs audit (§10.1). + +--- + +### 8. Duplicate concepts + +#### 8.1 `CreateFunction`, `UpdateFunction`, and `FunctionInfo` share ~28 fields verbatim +(model.ts:79-140, 198-259, 341-404) +Three types with almost-identical shapes and identical doc strings. +Generator artifact, but means any rename of, say, `routineBody`, +must happen three times — and the divergences between Create / Update +/ Info are easy to miss. Recommend basing `CreateFunction` and +`UpdateFunction` on `Partial` (or a shared base +interface). + +#### 8.2 `fullName` vs `catalogName` + `schemaName` + `name` (model.ts:81-85, 127, 200-204, 246, 345-349, 391) +A `FunctionInfo` has all four: a top-level `name` (relative to +schema), parent `catalogName` and `schemaName`, and `fullName` +(the concatenation). Three pieces of data; four fields. A caller +setting one and not the others leaves the type in an inconsistent +state, and there's no documentation on which is authoritative on +`Create*` / `Update*`. See also §13.4. + +#### 8.3 `dataType` vs `fullDataType` (model.ts:89-91, 208-210, 353-355) +- `dataType: ColumnTypeName` — the enum form. +- `fullDataType: string` — "Pretty printed function data type." + +The pretty-printed form is presumably a function of the enum plus +any precision/scale/interval. Two fields encoding the same datum in +two representations. + +#### 8.4 `name` vs `fullNameArg` on `UpdateFunction` +`UpdateFunction` has *both* `fullNameArg` (the existing function +identifier, used in the URL path) and `name` (the new desired name +of the function, used in the body). See §13.1. + +#### 8.5 `routineBody` enum constant `EXTERNAL` documented in three identical places +(model.ts:52-58, 92, 211, 356) +The `EXTERNAL` variant's full multi-bullet documentation appears on +the enum declaration, then a paraphrased version repeats on +`CreateFunction.routineBody`, `FunctionInfo.routineBody`, and +`UpdateFunction.routineBody`. Doc duplication is a generator +artefact, but it inflates the cognitive load of reading the model. + +--- + +### 9. Verb-tense inconsistency + +#### 9.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`, `listFunctionsIter`. No tense issues. + +#### 9.2 `unmarshal…` / `marshal…` schema-export prefixes are consistent. + +#### 9.3 `executeCall`, `executeHttpCall` (utils.ts:26, 65), `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams` (utils.ts:96, 113, 119, 123) — all imperative present, consistent. + +No verb-tense inconsistencies found across the package. + +--- + +### 10. Go / Java-style names + +#### 10.1 `FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, `FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess` +(model.ts:45, 50, 62, 67) +Proto nested-enum naming `Parent_Child`. TS should use top-level +identifiers: `FunctionParameterStyle`, `RoutineBody`, +`FunctionSecurityType`, `SqlDataAccess`. See §4.1-4.4. + +#### 10.2 `Client` class name (client.ts:44) +Bare `Client` (rather than `FunctionsClient`) is a Go idiom: package +qualifies the type. JS consumers commonly import as +`import {Client} from '@databricks/sdk-functions/v1'` and have to +alias. Package-wide convention; flagged for consistency. + +#### 10.3 `fullNameArg` (model.ts:155, 294, 343) — Go generator naming. See §5.2. + +#### 10.4 `unmarshal…` / `marshal…` (Go's `encoding/json` verbs) +Direct Go ports. The TS ecosystem typically uses `parse` / `serialize` +or `decode` / `encode`. Internal to the generated layer; identified +as Go-style for completeness. + +#### 10.5 `Dependency.value.$case` discriminated union encoding (model.ts:168-184) +The `$case` discriminator with `value`-keyed payload is a ts-proto +serialiser idiom. TS-native discriminated unions usually keep the +discriminator at the top level (`{type: 'function', function: {…}}`) +rather than wrapping in `value`. Functional, but visibly Go/proto. + +--- + +### 11. Generic field names losing meaning + +#### 11.1 `name` is used twelve+ times across the model +(model.ts:81, 84, 86 within docs, 200, 203, 263, 345, 348, etc.) +The semantics shift: function name, parameter name, catalog name, +schema name, etc. — but the field is consistently `name`. Combined +with `fullName`, `fullNameArg`, `functionFullName`, `tableFullName`, +`secretFullName`, `volumeFullName`, `externalName`, `specificName`, +the surface area of "name" fields is huge. See also §8.2. + +#### 11.2 `properties` (model.ts:121, 240, 385) +"JSON-serialized key-value pair map, encoded (escaped) as a string." +The field is `string`, despite the name promising a structured map. +A consumer reading the type sees `properties?: string` and has to +manually `JSON.parse`. Either name it `propertiesJson` or type it +as `Record` with marshal-layer translation. + +#### 11.3 `comment` (model.ts:119, 238, 285, 383) — see §1.3. + +--- + +### 12. Field contradicting type domain + +#### 12.1 `UpdateFunction` has `fullNameArg` *and* `name` (model.ts:343, 345) +- `fullNameArg` — the existing function's fully-qualified identifier + (path param). +- `name` — the function name, body field (the new desired name?). + +A caller staring at this struct cannot intuit which to set, in what +combination, or whether `name` is the *new* name or the *current* +name (the catalogs package answers this question differently with +`newName` — but `functions` lacks `newName` entirely, leaving the +caller without a renaming primitive at all, or with an ambiguous +`name` field). See also §8.4. + +#### 12.2 `CreateFunction` contains read-only output fields +`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, +`fullName`, `functionId`, `browseOnly` (model.ts:129-139). These are +server-populated; a creator setting them is at best ignored. The +type's domain is "create request" but its shape contradicts that. +Mirror issue in `UpdateFunction` (model.ts:393-403). + +#### 12.3 `DeleteFunction.fullNameArg` — see §5.2. + +#### 12.4 `FunctionInfo.fullName` vs `name` / `catalogName` / `schemaName` +(model.ts:200-204, 246) +On `FunctionInfo`, all four are present; for *catalogs* a `fullName` +is redundant with `name`, but for *functions* `fullName` is +`catalog_name.schema_name.function_name`. The doc comment +underscores them as if they're literal placeholders. The naming is +acceptable but the redundancy invites inconsistent state. + +#### 12.5 `FunctionParameterInfo.parameterType: FunctionParameterType` where `PARAM` is one of two variants +(model.ts:281) +The field is on a "parameter info" object and one of its variants +is `PARAM`. So a `FunctionParameterInfo` may have +`parameterType === 'PARAM'`, i.e. "a parameter that is a parameter". +The other variant, `COLUMN`, means "a parameter that is a column +reference" — the type *contradicts* the parent type's domain. See +also §2.1. + +--- + +### 13. Inconsistent action verbs + +Method verbs in `Client`: `createFunction`, `deleteFunction`, +`getFunction`, `listFunctions`, `updateFunction`, `listFunctionsIter`. +Verbs are consistent: standard CRUD plus a `…Iter` paginator. No +`fetch…` / `retrieve…` / `read…` outliers. No issues found. + +--- + +### 14. Long enum values + +#### 14.1 `ColumnTypeName.USER_DEFINED_TYPE` (model.ts:24) — 17 characters. See §2.6. + +#### 14.2 `ColumnTypeName.TABLEREF_TYPE` (model.ts:32) — 13 characters. See §2.6, §3.5. + +#### 14.3 `ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25) — 13 characters. See §3.6. + +#### 14.4 `FunctionInfo_SqlDataAccess.READS_SQL_DATA` (model.ts:69) — 14 characters. See §2.5. + +#### 14.5 No `*_UNSPECIFIED` enum values present in this package — positive observation versus catalogs. + +--- + +### 15. Underspecified IDs + +#### 15.1 `metastoreId` (model.ts:125, 244, 389) +Documented as "Unique identifier of parent metastore." Format +opaque (UUID? slug?). Acceptable but unspecified. + +#### 15.2 `functionId` (model.ts:137, 256, 401) +Doc: "Id of Function, relative to parent schema." Format unspecified +— is this a UUID, an autoincrement integer, an opaque token? Type is +`string` so opaque, but the docs should say so. + +#### 15.3 `metastoreId` & `functionId` — distinct domains, same shape +Both `string`, both undocumented for format, both server-assigned. +A consumer cannot tell them apart from the types. + +#### 15.4 `createdAt` / `updatedAt` (model.ts:129, 133, 248, 252, 393, 397) +Type is `number` (epoch milliseconds per the doc). The field name +doesn't convey unit. `createdAtMs` / `updatedAtMs` or `createdAtEpochMs` +would be more honest. The catalogs audit flagged the same +inconsistency. + +#### 15.5 `connectionName` (model.ts:76) — "Full name of the dependent connection, in the form of __connection_name__." +The field is named `connectionName` but the doc says it should be a +"full name". For other dependency types, the field is explicitly +named `*FullName` (e.g. `secretFullName`, `tableFullName`). Naming +inconsistency: ConnectionDependency and CredentialDependency +(model.ts:150) use `…Name`; the rest use `…FullName`. Pick one. + +--- + +### 16. Type-suffix tautology + +#### 16.1 `ColumnTypeName` enum with field `typeName: ColumnTypeName` +(model.ts:5, 269) — field name conflates "type name" with the enum +type. Reading `parameter.typeName === ColumnTypeName.INT` is doubly +type-y. Either shorten the field (`type: ColumnTypeName`) or rename +the enum (`ColumnType`). + +#### 16.2 `FunctionParameterMode` enum with field `parameterMode: FunctionParameterMode` +(model.ts:35, 279) — field-name tautological with type-name. + +#### 16.3 `FunctionParameterType` enum with field `parameterType: FunctionParameterType` +(model.ts:39, 281) — field-name tautological with type-name. Also +suffers from §12.5 (a "parameter type" that admits "PARAM" as a +variant). + +#### 16.4 `FunctionInfo_ParameterStyle` enum with field `parameterStyle: FunctionInfo_ParameterStyle` +(model.ts:45, 97, 216, 361) — field-name tautological with type-name. + +#### 16.5 `FunctionInfo_RoutineBody` enum with field `routineBody: FunctionInfo_RoutineBody` +(model.ts:50, 93, 212, 357) — field-name tautological with type-name. + +#### 16.6 `FunctionInfo_SecurityType` enum with field `securityType: FunctionInfo_SecurityType` +(model.ts:62, 105, 224, 369) — same. + +#### 16.7 `FunctionInfo_SqlDataAccess` enum with field `sqlDataAccess: FunctionInfo_SqlDataAccess` +(model.ts:67, 101, 220, 365) — same. + +--- + +## Additional / cross-cutting observations + +### A. `flattenQueryParams` is defined but unused (utils.ts:123) +Each `listFunctions` / `getFunction` / `deleteFunction` handler +builds query strings inline with `URLSearchParams.append` +(client.ts:115-118, 154-156, 194-209). The exported helper +`flattenQueryParams` is never referenced by `client.ts`. Either it's +intentionally exported for consumer use (then it should be +documented) or it's dead code. Same finding as catalogs audit +(cross-cutting A). + +### B. `fullNameArg` URL substitution silently allows empty string +(client.ts:114, 152, 260) — `${req.fullNameArg ?? ''}` — if +`fullNameArg` is undefined, the URL silently becomes +`/api/2.1/unity-catalog/functions/` and the request will fail on the +server. The naming (`fullNameArg`) and the substitution behaviour +together hide what should be a required parameter. Worth surfacing +via a non-optional type or a typed assertion. + +### C. `marshalUpdateFunctionSchema` serialises `fullNameArg` into the body +(model.ts:864) `fullNameArg` is a path parameter — but the marshal +schema produces a JSON field `full_name_arg`. Either the server +tolerates the extra field or this is a bug. The `Arg` suffix lets +the bug hide. + +### D. Marshal/unmarshal exports have inconsistent TS types +(model.ts:627, 635, etc.) — every `marshal…Schema` is typed +`z.ZodType` (no generic) versus every `unmarshal…Schema` typed +`z.ZodType<…>` (with generic). The marshal side is implicitly +untyped. Not a naming issue per se, but inconsistent with the +unmarshal naming/typing. + +### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +"Host is required." — bare `Error`. Not a naming issue, flagged for +consistency with the catalogs audit. + +### F. `index.ts` re-exports proto-style names verbatim +(index.ts:9-12, 21) — every underscore-bearing identifier surfaces +in the package's public API. A consumer of `@databricks/sdk-functions/v1` +sees `FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, +`FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess`, +`DeleteFunction_Response`, `ListFunctions_Response` as first-class +exports. + +### G. Package-name collision with JavaScript reserved word +The package is named `@databricks/sdk-functions` and the npm +workspace path is `packages/functions/`. `function` is a JS reserved +word; `functions` is not, but the proximity is jarring. Importers +will often write +`import * as functions from '@databricks/sdk-functions/v1'` which +sets up `functions.createFunction(…)` — the local binding `functions` +shadows nothing, but the `Dependency.value.$case === 'function'` +pattern (§7.1) combined with the package name creates a vocabulary +where "function" is overloaded. + +### H. `FunctionInfo.routineDependencies` is described as "function dependencies." +(model.ts:122, 241, 386) Comment text starts with lowercase and uses +"function" instead of "routine"; field name uses "routine". See +§6.1 and §6.3. + +### I. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` +The most extreme case of a single-purpose API surface: a long enum +type holding a one-letter variant, only ever set to `S`, marshaled +as the JSON string `"S"`. Three layers of indirection for a constant. +See §2.2, §5.1. + +--- + +## File / line index for fast lookup + +| Identifier | Location | Finding | +| -------------------------------------------------------- | --------------------- | ------- | +| `ColumnTypeName` | model.ts:5 | 2.6, 3.5, 3.6, 14.1-14.3, 16.1 | +| `ColumnTypeName.USER_DEFINED_TYPE` | model.ts:24 | 2.6, 14.1 | +| `ColumnTypeName.TIMESTAMP_NTZ` | model.ts:25 | 3.6, 14.3 | +| `ColumnTypeName.TABLE_TYPE` | model.ts:31 | 2.6 | +| `ColumnTypeName.TABLEREF_TYPE` | model.ts:32 | 2.6, 3.5, 14.2 | +| `FunctionParameterMode` | model.ts:35 | 16.2 | +| `FunctionParameterType` | model.ts:39 | 2.1, 12.5, 16.3 | +| `FunctionInfo_ParameterStyle` | model.ts:45 | 2.2, 4.1, 5.1, 10.1, 16.4 | +| `FunctionInfo_ParameterStyle.S` | model.ts:46 | 2.2, 5.1 | +| `FunctionInfo_RoutineBody` | model.ts:50 | 4.2, 8.5, 10.1, 16.5 | +| `FunctionInfo_RoutineBody.EXTERNAL` | model.ts:58 | 8.5 | +| `FunctionInfo_SecurityType` | model.ts:62 | 2.4, 4.3, 10.1, 16.6 | +| `FunctionInfo_SqlDataAccess` | model.ts:67 | 2.5, 3.1, 4.4, 10.1, 14.4, 16.7 | +| `ConnectionDependency.connectionName` | model.ts:76 | 15.5 | +| `CreateFunction` | model.ts:79 | 8.1, 12.2 | +| `CreateFunction.routineBody/routineDefinition/routineDependencies` | model.ts:93/95/123 | 6.3 | +| `CreateFunction.specificName` | model.ts:107 | 6.5 | +| `CreateFunction.fullName` | model.ts:127 | 8.2, 12.4 | +| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:125-139 | 12.2, 15.1, 15.2, 15.4 | +| `DeleteFunction.fullNameArg` | model.ts:155 | 5.2, 10.3, 12.3 | +| `DeleteFunction.force` | model.ts:157 | 1.1, 6.2 | +| `DeleteFunction_Response` | model.ts:161 | 4.5 | +| `Dependency.value.function` arm | model.ts:170 | 7.1 | +| `Dependency.value.$case` | model.ts:168 | 10.5 | +| `FunctionDependency` | model.ts:193 | 7.2 | +| `FunctionInfo` | model.ts:198 | 7.3, 8.1 | +| `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:212/214/242 | 6.3 | +| `FunctionInfo.specificName` | model.ts:226 | 6.5 | +| `FunctionInfo.properties` | model.ts:240 | 11.2 | +| `FunctionInfo.fullName` | model.ts:246 | 8.2, 12.4 | +| `FunctionInfo.functionId` | model.ts:256 | 15.2, 15.3 | +| `FunctionParameterInfo.name` | model.ts:263 | 7.4, 11.1 | +| `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:265-269 | 3.3, 3.4, 5.5, 16.1 | +| `FunctionParameterInfo.position` | model.ts:277 | 1.2 | +| `FunctionParameterInfo.parameterMode / parameterType` | model.ts:279, 281 | 12.5, 16.2, 16.3 | +| `FunctionParameterInfo.parameterDefault` | model.ts:283 | 6.4 | +| `FunctionParameterInfo.comment` | model.ts:285 | 1.3 | +| `GetFunction.fullNameArg` | model.ts:294 | 5.2, 10.3 | +| `ListFunctions_Response` | model.ts:319 | 4.6 | +| `UpdateFunction` | model.ts:341 | 8.1, 8.4, 12.1, 12.2 | +| `UpdateFunction.fullNameArg / name` | model.ts:343, 345 | 5.2, 8.4, 12.1 | +| `UpdateFunction.routineBody / routineDefinition / routineDependencies` | model.ts:357/359/387 | 6.3 | +| `UpdateFunction.fullName` | model.ts:391 | 8.2, 12.4 | +| `unmarshalDeleteFunction_ResponseSchema` | model.ts:431 | 4.7 | +| `unmarshalListFunctions_ResponseSchema` | model.ts:592 | 4.7 | +| `Client` (bare name) | client.ts:44 | 10.2 | +| `${req.fullNameArg ?? ''}` URL substitution | client.ts:114, 152, 260 | B | +| `flattenQueryParams` (unused export) | utils.ts:123 | A | +| `marshal…` / `unmarshal…` verbs | model.ts (many) | 10.4 | +| `index.ts` re-exports | index.ts:5-35 | F | + +--- + +## Recommended priority order + +1. **Resolve the `function` reserved-word collision in `Dependency.value`** — the union arm-key `function` is the single most jarring naming hazard in the package. (§7.1) +2. **Fix `fullNameArg` / `name` confusion on `UpdateFunction`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§12.1, §5.2) +3. **Strip proto-style `Parent_Child` identifiers** (`FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, `FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess`, `DeleteFunction_Response`, `ListFunctions_Response`). (§4) +4. **Resolve "function" vs "routine" vocabulary split.** (§6.3) +5. **Strip `_TYPE` suffix from `ColumnTypeName` variants and fix `TABLEREF_TYPE` underscore.** (§2.6, §3.5) +6. **Strip read-only fields from `CreateFunction` / `UpdateFunction`.** (§12.2) +7. **Unify `*Name` vs `*FullName` field-naming on `*Dependency` types.** (§15.5) +8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md new file mode 100644 index 00000000..bce4b296 --- /dev/null +++ b/.agent/naming-audit/genie.md @@ -0,0 +1,450 @@ +# Naming Audit: genie + +**Path:** `packages/genie/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). +**Total weird names flagged:** 73 + +## Summary +| Severity | Count | +| --- | --- | +| High | 21 | +| Medium | 27 | +| Low | 19 | +| Observation | 6 | + +## High severity + +### 1. Method naming wildly inconsistent: 28 of 30 methods are `genieXxx`, 2 are bare — `src/v1/client.ts:131,1038` +- **Why weird:** `client.ts` exposes 30 public methods. 28 are prefixed `genie` (e.g. `genieCreateConversationMessage`, `genieGetSpace`, `genieListSpaces`, `genieTrashSpace`). Two are not: `createSpace` (line 131) and `updateSpace` (line 1038). Reader calling `client.createSpace(...)` then trying `client.deleteSpace(...)` discovers the delete equivalent is named `genieTrashSpace(...)`. The "trash" method name is also inconsistent (see #2). +- **Category:** 17 (inconsistent action verbs / prefix), 6 (misleading — autocomplete shows two naming families). +- **Suggested name:** Pick one and apply uniformly. Either drop the `genie` prefix everywhere (the package is already `@databricks/sdk-genie` — the prefix is tautological) or keep it everywhere (`genieCreateSpace`, `genieUpdateSpace`). Strongly prefer the former. +- **Rationale:** Every method in the client is on a Genie `Client` imported from `@databricks/sdk-genie`. Prefixing every method with `genie` is type-suffix tautology — `client.genieListSpaces()` is no clearer than `client.listSpaces()`. The current half-prefixed surface is the worst of both options. + +### 2. `genieTrashSpace` is the only delete-style method named `Trash` — `src/v1/client.ts:1019` +- **Why weird:** All other delete methods are `genieDeleteX` (`genieDeleteConversation`, `genieDeleteConversationMessage`). The space delete is `genieTrashSpace` and the request type is `GenieTrashSpaceRequest`. JSDoc says "Move a Genie Space to the trash" — i.e. it is a soft delete, not a destructive one — but the name still breaks the `delete*` pattern. +- **Category:** 17 (inconsistent action verb), 14 (Go/Java-style "trash" verb is uncommon in JS SDKs). +- **Suggested name:** `genieDeleteSpace` (matches the other deletes; document the soft-delete semantics in JSDoc) or, if soft-delete needs to be explicit, mirror it on the messages too (`genieTrashConversationMessage`). +- **Rationale:** Inconsistency forces every reader to learn the exception. The "soft delete" semantic can be conveyed by docs without leaking into the verb. + +### 3. `genieExecuteMessageAttachmentQuery` vs `genieGetMessageAttachmentQueryResult` vs `genieGenerateDownloadFullQueryResult` — three different verbs for retrieving the same data — `src/v1/client.ts:308,564,396` +- **Why weird:** The package has at least four "get the SQL result" entry points (`Execute`, `Get`, `Generate`, plus `genieGetQueryResultByAttachment`/`genieGetMessageQueryResult` deprecated aliases). Each uses a different verb stem. `Execute` re-runs the query; `Get` reads the result; `Generate` initiates a download — but the user has to read each docstring to learn that. +- **Category:** 17 (inconsistent action verbs), 7 (overly verbose). +- **Suggested name:** Group with verb pairs: `runMessageAttachmentQuery` (re-execute) / `getMessageAttachmentQueryResult` (read) / `startMessageAttachmentDownload` + `getMessageAttachmentDownload` (download flow). +- **Rationale:** The verbs `Execute` / `Get` / `Generate` overlap in everyday English; the type system gives no hint which one to call first. The current names are generator-faithful but unhelpful for users. + +### 4. `Genie*` prefix on every type — type-suffix tautology — `src/v1/model.ts` (~40 types) +- **Why weird:** 40 of ~70 types are prefixed `Genie`: `GenieAttachment`, `GenieConversation`, `GenieMessage`, `GenieSpace`, `GenieFeedback`, `GenieEvalResult`, etc. The package is `@databricks/sdk-genie` and types are imported as `import {GenieMessage} from '@databricks/sdk-genie'`. The prefix duplicates the package identity. Other types in the same file have no prefix (`Result`, `ResultData`, `ResultManifest`, `StatementResponse`, `StatementStatus`, `Schema`, `Struct`, `ListValue`, `ChunkInfo`, `MessageError`, `MessageStatus`, `Thought`, `TextAttachment`, `VerificationMetadata`, etc.) — so the prefix is not even applied consistently. +- **Category:** 20 (type-suffix tautology), 17 (prefix applied inconsistently within the same package). +- **Suggested name:** Drop the prefix wherever the unprefixed name is unambiguous: `Conversation`, `Message`, `Space`, `Attachment`, `Feedback`, `EvalResult`. Keep `Genie` only where collision with a copied-in shared type would arise (e.g. keep `GenieResultMetadata` if you also need to keep `ResultManifest`). +- **Rationale:** `import {Message} from '@databricks/sdk-genie'` is unambiguous (the package is the namespace). The current prefix turns every import line into noise. + +### 5. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1481` +- **Why weird:** The central noun. A `GenieSpace` is a "workspace scoped to a Genie deployment", but the word `Space` is one of the most overloaded terms in the Databricks SDK (it also appears in workspace, mlflow registered model, dashboards, etc.). Type doc on the class itself is one line ("Genie space ID"). Reader sees `GenieSpace` and has to consult external docs to learn whether it's a folder, a user-permission boundary, a model-deployment, or something else. +- **Category:** 1 (vague/generic), 15 (generic field name losing meaning — `Space`). +- **Suggested name:** `GenieRoom`, `GenieAgent`, `GenieDeployment`, or at minimum a JSDoc on the type explaining what a "space" *is* (warehouse + datasets + instructions). If "Space" is the Databricks product-marketing term, document it inline. +- **Rationale:** This is the package's central concept. Letting it stand on a single word that means "container" is a documentation gap as much as a naming bug. + +### 6. `MessageStatus_MessageStatus` enum (Proto-style double name) — `src/v1/model.ts:753` +- **Why weird:** A proto-generated nested enum where the parent message and the enum share the name. Becomes `MessageStatus_MessageStatus` in TS — repeats `MessageStatus` twice. Every reference (`MessageStatus_MessageStatus.COMPLETED`, etc.) reads as the wrong name twice. +- **Category:** 4 (underscores in TS identifiers), 14 (proto-style nested name). +- **Suggested name:** `MessageStatus` (single, non-nested enum) or `MessageState`. Keep the wire format unchanged. +- **Rationale:** The doubled name is a generator artefact of proto-style nesting. A single non-nested enum reads naturally and removes the underscore. + +### 7. `MessageError_Type` enum — Proto-style nested name — `src/v1/model.ts:669` +- **Why weird:** Same pattern as #6: `MessageError_Type` is the nested-enum form. Field name is `type` (`MessageError.type`); enum is `MessageError_Type` — i.e. accessed as `MessageError_Type.FOO`. The underscore is a generator leak. +- **Category:** 4 (underscores in TS identifiers), 14 (proto-style nested name). +- **Suggested name:** `MessageErrorType` (camelcase only, drop the underscore). +- **Rationale:** Same as #6. + +### 8. `StatementStatus_State` enum — Proto-style nested name — `src/v1/model.ts:767` +- **Why weird:** Same pattern. `StatementStatus.state: StatementStatus_State`. Also: this entire family of types (`StatementResponse`, `StatementStatus`, `ResultManifest`, `Result`, `ResultData`, `ChunkInfo`, `ExternalLink`, `Schema`, `ColumnInfo`, `ColumnTypeName`, `ColumnMask`, `PolicyFunctionArgument`, `Format`, `DatabricksServiceExceptionProto`, `ErrorCode`) is *copy-pasted* from `@databricks/sdk-databricks/statementexecution`; see #9. +- **Category:** 4 (underscores), 14 (proto nesting), 12 (duplicate concept across packages). +- **Suggested name:** `StatementState`. Better: import from the statementexecution package instead of copying. +- **Rationale:** See #9 for the deeper issue. + +### 9. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-33,36-534,547-551,777-907,1610-1715` +- **Why weird:** 15+ types are byte-for-byte copies of types in the `statementexecution`, `sql` and `apierror` packages: `ColumnTypeName` (enum, 28 values), `ErrorCode` (enum, 80 values, with line-for-line JSDoc), `Format` (enum), `ChunkInfo`, `ColumnInfo`, `ColumnMask`, `DatabricksServiceExceptionProto`, `ExternalLink`, `ExternalLink_HttpHeadersEntry`, `PolicyFunctionArgument`, `Result`, `ResultData`, `ResultManifest`, `Schema`, `StatementResponse`, `StatementStatus`, `StatementStatus_State`. The file even copies the Google-Well-Known-Types (`Struct`, `Value`, `ListValue`, `MapStringValueEntry`, `NullValue`). +- **Category:** 12 (duplicate concept across packages), 4 (underscores, propagated through the copy). +- **Suggested name:** Import from `@databricks/sdk-databricks/statementexecution` (or wherever the originals live). If the generator can't yet cross-link, mark each duplicate `@internal` or move them to a shared internal module. +- **Rationale:** A consumer who imports both `@databricks/sdk-genie` and `@databricks/sdk-sql` ends up with two structurally-identical-but-nominally-distinct `StatementResponse` types — runtime values are not assignable to each other in strict mode. This is the biggest correctness footgun in the package. + +### 10. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:36-534` +- **Why weird:** ErrorCode is copied verbatim from the SDK's apierror codes package. Of the 80 values, comments explicitly mark ~50 as deprecated. The enum is only referenced via the copied `DatabricksServiceExceptionProto` type, which is itself unused by any Genie method (the SDK uses `APIError.fromHttpError` in `utils.ts:88`). +- **Category:** 12 (duplicate concept), 18 (long enum values — `MAX_NOTEBOOK_SIZE_EXCEEDED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, `RESOURCE_DOES_NOT_EXIST`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). +- **Suggested name:** Import from `@databricks/sdk-databricks/apierror/codes`. Remove the local copy. +- **Rationale:** 500 lines of code (model.ts:36-534) duplicate a separate package. Maintenance hazard: deprecation removals or additions to the canonical enum will diverge silently. + +### 11. `ScoreReason` enum — values mix `RESULT_*`, `LLM_JUDGE_*`, and unprefixed `EMPTY_RESULT`/`SINGLE_CELL_DIFFERENCE` — `src/v1/model.ts:593-622` +- **Why weird:** 22 values, three families: (a) plain (`EMPTY_RESULT`, `SINGLE_CELL_DIFFERENCE`, `EMPTY_GOOD_SQL`, `COLUMN_TYPE_DIFFERENCE`); (b) `RESULT_*` (`RESULT_MISSING_ROWS`, `RESULT_EXTRA_ROWS`, `RESULT_MISSING_COLUMNS`, `RESULT_EXTRA_COLUMNS`); (c) `LLM_JUDGE_*` (16 values). Six `LLM_JUDGE_*` values are deprecated and kept beside the new ones. `EMPTY_RESULT` and `EMPTY_GOOD_SQL` should both be `RESULT_*` for consistency. +- **Category:** 2 (redundant enum prefixes), 18 (long enum values — `LLM_JUDGE_INSTRUCTION_COMPLIANCE_OR_MISSING_BUSINESS_LOGIC` is 60 characters), 17 (inconsistent prefix), 12 (deprecated values duplicated alongside new). +- **Suggested name:** Either drop all prefixes (`EmptyResult | MissingRows | ExtraRows | …`) or apply uniformly (`RESULT_EMPTY`, `RESULT_MISSING_ROWS`, …, `JUDGE_MISSING_FILTER`, `JUDGE_INCOMPLETE_OUTPUT`, …). Separate the deprecated values into a dedicated comment block or split into two enums. +- **Rationale:** Autocomplete on `ScoreReason.` returns 22 items with no visual grouping; users cannot tell at a glance which are deterministic vs which are LLM-judge. + +### 12. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:669-736` +- **Why weird:** 60 values, almost every one ends in `_EXCEPTION` (`UNEXPECTED_REPLY_PROCESS_EXCEPTION`, `GENERIC_CHAT_COMPLETION_EXCEPTION`, `CONTEXT_EXCEEDED_EXCEPTION`, …). The few that don't are inconsistent: `STOP_PROCESS_DUE_TO_AUTO_REGENERATE`, `UNKNOWN_AI_MODEL`, `NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE`, plus `MESSAGE_ATTACHMENT_TOO_LONG_ERROR` (suffix `_ERROR` not `_EXCEPTION`), `DESCRIBE_QUERY_UNEXPECTED_FAILURE` / `DESCRIBE_QUERY_TIMEOUT` / `DESCRIBE_QUERY_INVALID_SQL_ERROR` (different verbs). The `_EXCEPTION` suffix is also Java vocabulary, not TS. +- **Category:** 2 (redundant suffix — every value already lives under `MessageError_Type`), 14 (Java-style `Exception` vocabulary in TS), 18 (long values — `INTERNAL_CATALOG_ASSET_CREATION_UNSUPPORTED_EXCEPTION` is 52 chars), 17 (inconsistent suffix). +- **Suggested name:** Drop `_EXCEPTION` from every value: `UnexpectedReplyProcess | GenericChatCompletion | ContextExceeded | …`. Pick one of `_ERROR` / `_EXCEPTION` / nothing. +- **Rationale:** This enum is 67 lines long; cleaning the suffix removes 600+ characters and makes the values readable in autocomplete. + +### 13. Three `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:537,547,554,561,569,584,588,595,626,633,643,660,670` +- **Why weird:** 13 enums use a `XXX_UNSPECIFIED` sentinel where `XXX` is the enum's name: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `GENIE_FEEDBACK_RATING_UNSPECIFIED`, `NULL_VALUE`, `RESPONSE_PHASE_UNSPECIFIED`, `SCORE_REASON_UNSPECIFIED`, `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED`, `THOUGHT_TYPE_UNSPECIFIED`, `VERIFICATION_SECTION_UNSPECIFIED`, `TYPE_UNSPECIFIED` (inside `MessageError_Type`), `STATE_UNSPECIFIED` (inside `StatementStatus_State`). Proto2 forces this; TS does not need it because the enum's type acts as the namespace. +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggested name:** `Unspecified` (drop the prefix). Or omit entirely if TS-undefined can stand in for proto-unspecified. +- **Rationale:** The package will get cleaner immediately; the wire string can stay the same. + +### 14. `RESPONSE_PHASE_*` prefix repeated on every value — `src/v1/model.ts:588-590` +- **Why weird:** Enum `ResponsePhase` has 3 values: `RESPONSE_PHASE_UNSPECIFIED`, `RESPONSE_PHASE_THINKING`, `RESPONSE_PHASE_VERIFYING`. Every value carries the parent name. +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggested name:** `Unspecified | Thinking | Verifying`. +- **Rationale:** Same as #13 — autocomplete already namespaces. + +### 15. `THOUGHT_TYPE_*` prefix repeated — `src/v1/model.ts:643-653` +- **Why weird:** Six values, all `THOUGHT_TYPE_*`. The plain-noun forms (`Description`, `Understanding`, `DataSourcing`, `Instructions`, `Steps`) would be perfectly clear under `ThoughtType.`. +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggested name:** `ThoughtType.Unspecified | Description | Understanding | DataSourcing | Instructions | Steps`. +- **Rationale:** Same as #13. + +### 16. `VERIFICATION_SECTION_*` prefix repeated and one value has the prefix doubled — `src/v1/model.ts:660-666` +- **Why weird:** Five values: `VERIFICATION_SECTION_UNSPECIFIED`, `VERIFICATION_SECTION_SQL_EXAMPLES_VALIDATION`, `VERIFICATION_SECTION_VERIFICATION_QUERIES`, `VERIFICATION_SECTION_PROPOSED_IMPROVEMENT`, `VERIFICATION_SECTION_FINAL_DECISION`. The third value (`VERIFICATION_SECTION_VERIFICATION_QUERIES`) repeats `VERIFICATION` — 41 characters. +- **Category:** 2 (redundant prefix doubled), 18 (long enum values). +- **Suggested name:** `VerificationSection.Unspecified | SqlExamplesValidation | VerificationQueries | ProposedImprovement | FinalDecision`. +- **Rationale:** Same. + +### 17. `TEXT_ATTACHMENT_PURPOSE_*` prefix repeated; enum has only 2 values — `src/v1/model.ts:626-628` +- **Why weird:** Two values: `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED` (35 chars) and `FOLLOW_UP_QUESTION`. Prefix only on the sentinel — inconsistent within the same enum. +- **Category:** 17 (inconsistent prefix within one enum), 2 (redundant prefix on sentinel). +- **Suggested name:** Either `Unspecified | FollowUpQuestion`, or drop the enum (boolean `isFollowUp`). +- **Rationale:** Two-member enums where one is `_UNSPECIFIED` are often better collapsed. + +### 18. `GENIE_EVAL_ASSESSMENT_*` and `GENIE_EVAL_RESPONSE_TYPE_*` prefixes — `src/v1/model.ts:554,561` +- **Why weird:** `GenieEvalAssessment` has values `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GOOD`, `BAD`, `NEEDS_REVIEW`. Only the sentinel carries the prefix. `GenieEvalResponseType` likewise: `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `TEXT`, `SQL`. +- **Category:** 17 (inconsistent prefix), 2 (redundant prefix on sentinel). +- **Suggested name:** Drop the prefix on the sentinel. +- **Rationale:** Same as the rest of the enum prefix cluster — the consistency wins matter more than the wire encoding. + +### 19. `EvaluationStatusType` has 6 values mixing `EVALUATION_*` and unprefixed — `src/v1/model.ts:536-544` +- **Why weird:** Six values: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `RUNNING`, `DONE`, `NOT_STARTED`, `EVALUATION_FAILED`, `EVALUATION_CANCELLED`, `EVALUATION_TIMEOUT`. Three are prefixed `EVALUATION_*`, three are bare. The mixed prefixing is jarring. +- **Category:** 17 (inconsistent prefix within one enum), 2 (redundant prefix), 6 (`Type` suffix on enum name is also redundant — every enum is a "type"). +- **Suggested name:** `EvaluationStatus.Unspecified | Running | Done | NotStarted | Failed | Cancelled | Timeout`. Drop the `Type` suffix from the enum name. +- **Rationale:** This enum is exposed in `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus` — readable values matter. + +### 20. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` +- **Why weird:** Three deprecated/active methods all return `GenieGetMessageQueryResultResponse` and all read the SQL result for a message. The naming hierarchy is `Message.QueryResult` vs `MessageAttachment.QueryResult` vs `QueryResult.byAttachment` — three different mental models. Two are deprecated but still exported and named in the surface. +- **Category:** 17 (inconsistent action verb / structure), 7 (overly verbose), 12 (duplicate concept). +- **Suggested name:** Keep the single canonical method (`getMessageAttachmentQueryResult` → `getMessageAttachmentResult`), mark the others `@deprecated` and consider hiding them from the typed surface (re-export only from `/legacy`). +- **Rationale:** Three names with overlapping suffixes is the classic generator-emitting-everything problem. + +### 21. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1506` +- **Why weird:** Request type for `genieStartConversation`. Name contains *both* `Conversation` and `Message`, but the body has only `spaceId` and `content` (`{ spaceId?: string; content?: string; }`). It is not a request to start a "conversation message" — it is a request to start a conversation by sending an initial message. Compare with `GenieStartConversationResponse` (no `Message` in the name). +- **Category:** 6 (misleading — name suggests a compound entity that doesn't exist), 7 (overly verbose). +- **Suggested name:** `StartConversationRequest` (matches the response). +- **Rationale:** Reader has to parse the doc to learn what "ConversationMessage" means here. The companion response name (`GenieStartConversationResponse`) silently drops `Message` — internal inconsistency. + +## Medium severity + +### 22. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:911` +- **Why weird:** `GenieAttachment.attachment` is a `{ $case: 'text' | 'query' | 'suggestedQuestions', … } | undefined` field. Reading `myAttachment.attachment.text` reads as "the attachment of the attachment", and the parent `GenieAttachment` also has a peer field `attachmentId`. The shape mixes the discriminator field with a flat id field. +- **Category:** 15 (generic field name losing meaning). +- **Suggested name:** Hoist to top-level discriminated union: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. Or rename the field to `payload` / `body` / `content`. +- **Rationale:** Same struct, single name; the parent-name-shaped field name confuses readers traversing nested attachments. + +### 23. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:940,952` +- **Why weird:** The struct has two id fields. JSDoc on `id` says "Legacy identifier, use conversation_id instead". Both are emitted, both are typed `string | undefined`, both are read from the wire. The struct also has no doc explaining the precedence rule when both are present (server normally fills both with the same value). +- **Category:** 19 (underspecified id), 12 (duplicate concept within one struct), 8 (redundant suffix). +- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#24). +- **Rationale:** Caller cannot tell which to read without consulting the doc; autocomplete shows both at the same priority. + +### 24. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1395,1419` +- **Why weird:** Same pattern as #23. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. +- **Category:** 19, 12, 8 (same as #23). +- **Suggested name:** Same as #23. +- **Rationale:** Same as #23. + +### 25. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1482-1503` +- **Why weird:** Compare with the rest of the SDK: `GenieSpace` uses `title` for the human-readable name (other types use `name`/`displayName`). The struct has `spaceId`, `title`, `description`, `warehouseId`, `parentPath`, `serializedSpace`, `etag` — no `name`. JSDoc on `title` says "Title of the Genie Space" — but in the rest of the codebase, "title" is reserved for `GenieConversation.title` (the conversation subject line). Two different "titles" in the same package. +- **Category:** 17 (inconsistency vs other types), 1 (vague — `title` doesn't distinguish from conversation title). +- **Suggested name:** `displayName` or `name` (Space is a top-level entity; "title" is column-header style). +- **Rationale:** Aligns with `DatabricksWorkspace.name`, `Dashboard.displayName`, etc. + +### 26. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:950,1408,1437,1736,1758` +- **Why weird:** Five different concepts share the field name `content`. The reader cannot disambiguate from the field name alone. JSDocs differ: "User message content" / "Comment text content" / "AI generated message" / "The md formatted content for this thought" — i.e. they are all different formats. +- **Category:** 15 (generic field name), 1 (vague). +- **Suggested name:** `body` for the message body, `text` for comments and thoughts, or qualify (`messageBody`, `commentText`, `thoughtMarkdown`). +- **Rationale:** "Content" is a near-meaningless filler word; this is the kind of generic name the codebase rule (#15 of the audit categories) targets. + +### 27. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:944` +- **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1401), `GenieMessageComment.userId` (line 1435), `GenieEvalResult.createdByUser` (line 1048), `GenieEvalRunResponse.runByUser` (line 1114). +- **Category:** 16 (field type contradicts domain), 14 (proto-int64 leaked to JS `number`). +- **Suggested name:** Keep field name, change type to `string` (matches the rest of the SDK), or use `bigint`. Or `userId: string` with stronger JSDoc. +- **Rationale:** Postgres-ID / long-id semantics are universal here. The `userId: number` typing is a generator bug that bites at runtime. + +### 28. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:946,948,958,1116,1126,1402,1404,1439,1450` +- **Why weird:** 9 fields use `*Timestamp` suffix. The type is already `number` (a Unix-millis timestamp per JSDoc). The suffix duplicates the type. Some peer fields drop the suffix (`createdByUser` on `GenieEvalResult`, `runByUser` on `GenieEvalRunResponse`). +- **Category:** 7 (overly verbose), 8 (redundant suffix). +- **Suggested name:** `createdAt` / `updatedAt`. Or `createdAtMs` / `updatedAtMs` if the millis unit needs to be explicit. +- **Rationale:** Industry-standard `createdAt`/`updatedAt` reads more naturally than `createdTimestamp`/`lastUpdatedTimestamp`. + +### 29. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1404` +- **Why weird:** `lastUpdatedTimestamp` (5 syllables) is the package's "updated at" name. The `last` prefix adds nothing — by definition, an "updated at" timestamp is the *last* update. +- **Category:** 7 (overly verbose). +- **Suggested name:** `updatedAt` / `updatedTimestamp`. +- **Rationale:** Same as #28. + +### 30. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1452` +- **Why weird:** `id?: string` on `GenieQueryAttachment` is undocumented (no JSDoc). The parent `GenieAttachment` has `attachmentId` (line 932) — so the `id` here is presumably the same value or the query-attachment-specific id. Caller can't tell. +- **Category:** 19 (underspecified id), 1 (vague). +- **Suggested name:** `attachmentId` (match the parent) or `queryAttachmentId` (qualify). +- **Rationale:** Two near-identical ids on the same outer entity is one ambiguity too many. + +### 31. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1737` +- **Why weird:** Same as #30 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. +- **Category:** 19, 1. +- **Suggested name:** Same as #30. +- **Rationale:** Same as #30. + +### 32. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1108` +- **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). +- **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). +- **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. +- **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. + +### 33. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1168` +- **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. +- **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). +- **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. +- **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. + +### 34. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1157,1184` +- **Why weird:** Same as #33 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +- **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). +- **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. +- **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. + +### 35. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1172,1196` +- **Why weird:** JSDoc says "JWT signature for the download_id". JWT is itself the full token (header.payload.signature). Calling it a "signature" understates what it is (the entire JWT that authorises the download). +- **Category:** 6 (misleading — `Signature` is a sub-part of a JWT), 5 (cryptic). +- **Suggested name:** `downloadToken` / `downloadJwt`. +- **Rationale:** Caller expects a base64 signature to pair with `downloadId`; the value is actually a full bearer token. + +### 36. `statementIdSignature` same pattern — `src/v1/model.ts:1618` +- **Why weird:** Same as #35: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. +- **Category:** 6 (misleading), 5 (cryptic). +- **Suggested name:** `statementToken` / `statementJwt`. +- **Rationale:** Same as #35. + +### 37. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1503,1552` +- **Why weird:** HTTP `ETag` is the canonical capitalisation. The field is `etag: string`. Across the SDK other types use `etag` lowercase too — but it is an acronym (`Entity Tag`). +- **Category:** 3 (acronym casing). +- **Suggested name:** `eTag` (camelCase per TS style) or `etag` (current — chosen for consistency). +- **Rationale:** Low priority; flag for awareness. + +### 38. `Result` type name — too generic — `src/v1/model.ts:1610` +- **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. +- **Category:** 1 (vague/generic). +- **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. +- **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. + +### 39. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1616,1677` +- **Why weird:** Both fields are booleans indicating truncation. `Result.isTruncated` uses the `is*` prefix convention; `ResultManifest.truncated` is bare. Same struct file, two conventions. +- **Category:** 17 (inconsistency). +- **Suggested name:** Pick one form (`truncated` everywhere) and apply. +- **Rationale:** Pure consistency win; no semantic change. + +### 40. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1465` +- **Why weird:** A third truncation field on `GenieResultMetadata.isTruncated`. Three independent fields tracking the same concept across `Result`, `ResultManifest`, `GenieResultMetadata`. +- **Category:** 17 (inconsistency), 12 (duplicate concept). +- **Suggested name:** Same as #39. +- **Rationale:** Same as #39. + +### 41. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1461` +- **Why weird:** A type whose two fields (`rowCount`, `isTruncated`) are both already on `ResultManifest`. JSDoc says "Metadata associated with the query result", but `ResultManifest` is also "result manifest" metadata. +- **Category:** 12 (duplicate concept). +- **Suggested name:** Replace with `ResultManifest` (or a sub-projection of it); delete `GenieResultMetadata`. +- **Rationale:** Two structs covering the same semantic territory cause readers to wonder which one is authoritative. + +### 42. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1605` +- **Why weird:** `keyword` is a vague word for what is presumably the parameter name. No JSDoc. The companion field `value` carries the bound value; `sqlType` carries the type. A parameter is `(name, value, type)` — why is `name` called `keyword`? +- **Category:** 1 (vague), 6 (misleading — `keyword` evokes SQL reserved words). +- **Suggested name:** `name` (with JSDoc) or `parameterName`. +- **Rationale:** Reader sees `keyword` and looks for a SQL keyword list. + +### 43. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1606` +- **Why weird:** No JSDoc on `value`. Type is `string`. For SQL parameters this could be a literal value, an expression, a placeholder, a JSON-encoded scalar, etc. Companion `sqlType?: string` (also no JSDoc) presumably qualifies it. +- **Category:** 1 (vague), 16 (field type may contradict domain). +- **Suggested name:** Document. Optionally `stringValue` / `valueText` to make the encoding explicit. +- **Rationale:** Public SDK types should not require source-diving. + +### 44. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:925` +- **Why weird:** Discriminator value is `'suggestedQuestions'` and the payload type is `GenieSuggestedQuestionsAttachment`. The word `Attachment` is in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". +- **Category:** 7 (overly verbose), 20 (type-suffix tautology). +- **Suggested name:** Variant `'followUps'`, payload `SuggestedQuestions { questions: string[] }`. +- **Rationale:** Reduce noise per attachment. + +### 45. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1525` +- **Why weird:** Bare `string[]`. Doc says "The suggested follow-up questions". The questions are also typed elsewhere as a free-text input (`content` on a `GenieCreateConversationMessageRequest`) — so the type tells you nothing about the format. +- **Category:** 1 (vague — questions could be markdown, plain, etc.). +- **Suggested name:** `followUpQuestions: string[]` (clearer; matches the JSDoc). +- **Rationale:** Field name disambiguation. + +### 46. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1578` +- **Why weird:** `MessageError.error: string`. Reader sees `someError.error` (two `error`s). Some other fields are similarly self-referential (`Result.statementId`, OK because `Result` is generic; here `MessageError.error` is *the error message*). +- **Category:** 15 (generic field name), 1 (vague). +- **Suggested name:** `MessageError.message: string` (matches the JSON shape) or `MessageError.detail`. +- **Rationale:** Wire format on the server may already be `error_message`; check before renaming. + +### 47. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1579` +- **Why weird:** Field name `type` is a JS reserved-word-adjacent (TS allows it, but `type` collides with the `type` keyword used in TS type aliases — refactoring tools sometimes choke). +- **Category:** 10 (reserved-word collision), 1 (vague). +- **Suggested name:** `errorType` / `category` / `kind`. +- **Rationale:** Common collision; small ergonomics win. + +### 48. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1756` +- **Why weird:** `Thought.thoughtType` repeats "thought" twice. Could just be `Thought.type`. +- **Category:** 8 (redundant suffix), 7 (overly verbose). +- **Suggested name:** `Thought.type` (and rename `ThoughtType` → `Thought.Kind` namespace). +- **Rationale:** Reduces redundancy. + +### 49. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:932` +- **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1737) and `GenieQueryAttachment.id` (line 1452) inside variants. Three different id fields for the same logical entity (the attachment). +- **Category:** 19 (underspecified id), 12 (duplicate concept). +- **Suggested name:** Single `id` on `GenieAttachment`, remove inner ids. +- **Rationale:** See #30, #31, #49 together. + +### 50. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1262` +- **Why weird:** Boolean toggle that expands the response. Permission check is documented ("Requires at least CAN EDIT permission"). Boolean naming style varies across SDK: `enableX`, `includeX`, `withX`. Could be `withSerializedSpace` or `includeSerialized` (the parent struct is already a Space). +- **Category:** 7 (overly verbose). +- **Suggested name:** `withSerialized` / `expandSerialized`. +- **Rationale:** The struct context already says "Space"; the prefix is redundant. + +## Low severity + +### 51. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` +- **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. +- **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). +- **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. +- **Rationale:** Class names should be noun phrases; current name reads as a verb. + +### 52. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:961, client.ts:160` +- **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. +- **Category:** 7 (overly verbose). +- **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. +- **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. + +### 53. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1278` +- **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. +- **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). +- **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. +- **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. + +### 54. `Format` enum has 4 values; only sentinel is prefixed — `src/v1/model.ts:546-551` +- **Why weird:** `FORMAT_UNSPECIFIED` then `JSON_ARRAY`, `ARROW_STREAM`, `CSV`. Same inconsistent-prefix pattern as #17 / #18. +- **Category:** 17, 2. +- **Suggested name:** `Format.Unspecified | JsonArray | ArrowStream | Csv`. +- **Rationale:** Same as #13. + +### 55. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:549` +- **Why weird:** Value `ARROW_STREAM` casing. The product name is `Apache Arrow` — `Arrow` is title-case in TS naming. As an enum value `ARROW_STREAM` is conventional (SCREAMING_SNAKE) but mixed with `JSON_ARRAY` and `CSV` where one is fully-cap acronym and one is mixed. +- **Category:** 3 (acronym casing), 17 (mixed conventions within the enum). +- **Suggested name:** `ArrowStream` (in a Pascal-case enum). +- **Rationale:** Low priority — enum-value style is widely-debated. + +### 56. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1415` +- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #38). +- **Category:** 12 (duplicate concept — kept-for-compat), 1 (vague — `Result`). +- **Suggested name:** Mark with `/** @deprecated */` JSDoc (current text just says "Deprecated" — TS tooling won't strike-through). +- **Rationale:** Tooling support — modern TS understands `@deprecated`. + +### 57. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +- **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). +- **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). +- **Suggested name:** Mark as `@deprecated` (already partially), then remove. +- **Rationale:** Cleanup; clients should migrate to the canonical name. + +### 58. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1048` +- **Why weird:** Field is named `createdByUser` rather than `createdBy`. `By User` is redundant: a `createdBy` field is by-its-nature-by-a-user (or by a service principal). Compare `GenieEvalRunResponse.runByUser` (same pattern, line 1114). +- **Category:** 7 (overly verbose), 17 (inconsistent vs other types in the SDK using `createdBy`). +- **Suggested name:** `createdBy` (matches the rest of the SDK). +- **Rationale:** Aligns with `databricks-sdk-go` conventions and most peer types. + +### 59. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1114` +- **Why weird:** Same as #58. +- **Category:** 7, 17. +- **Suggested name:** `runBy` / `runByUserId`. +- **Rationale:** Same as #58. + +### 60. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1046,1103,1105` +- **Why weird:** `GenieEvalResult` stores the original "benchmark answer" as a flat string; `GenieEvalResultDetails` returns the actual/expected as arrays of `GenieEvalResponse`. Three different words for "the right answer" / "Genie's answer" / "the expected answer". +- **Category:** 17 (inconsistent word choice), 1 (vague — `answer` vs `response`). +- **Suggested name:** Pick one verb. E.g., `expectedAnswer` / `actualAnswer` (or `expectedResponse` / `actualResponse` for both types). +- **Rationale:** Reader has to relearn the vocabulary in each type. + +### 61. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1060` +- **Why weird:** A `GenieEvalResultDetails` describes a single result inside a run. The field `evalRunStatus` describes the *run's* status, not the result's status. The plain `status` field appears on `GenieEvalResult` (line 1042) but is gone here — replaced by `evalRunStatus`. So the same enum (`EvaluationStatusType`) is exposed under two different field names. +- **Category:** 17 (inconsistent field naming for the same concept), 6 (misleading — `evalRunStatus` on a result-details type confuses run-status with result-status). +- **Suggested name:** `runStatus` (with the run context clear from the parent type's purpose). +- **Rationale:** Same status enum, two field names is jarring. + +### 62. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1064` +- **Why weird:** Two adjacent fields: `assessment: GenieEvalAssessment` and `manualAssessment: boolean`. The second is a flag indicating whether the first was set manually. The naming implies that `manualAssessment` is itself an assessment. +- **Category:** 6 (misleading — `manualAssessment` looks like "the manual assessment value"), 1 (vague). +- **Suggested name:** `assessmentIsManual` / `isManuallyAssessed`. +- **Rationale:** Boolean-prefix convention disambiguates. + +### 63. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1312` +- **Why weird:** `includeAll: boolean`. JSDoc clarifies "Include all conversations in the space across all users". `All` is unqualified; could mean "include archived", "include all spaces", "include all messages". +- **Category:** 1 (vague), 6 (misleading without docs). +- **Suggested name:** `includeAllUsers` / `acrossUsers` / `allUsers`. +- **Rationale:** Boolean toggles need to be unambiguous from the name. + +### 64. `pageSize` / `pageToken` casing — `src/v1/model.ts:1271,1273,1289,1291,...` +- **Why weird:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. +- **Category:** Observation only — no issue. +- **Suggested name:** N/A. +- **Rationale:** Confirms the package's pagination naming is consistent. + +### 65. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — `type` prefix repeated — `src/v1/model.ts:807-818` +- **Why weird:** Six fields all prefixed `type*`. Hoisting into a sub-struct `type: { text, name, precision, scale, intervalType, json }` would be cleaner. Generator-faithful flat shape duplicates the prefix. +- **Category:** 7 (overly verbose), 8 (redundant prefix). +- **Suggested name:** Sub-struct, or trim the prefix. +- **Rationale:** Aesthetic; matches the protobuf shape. + +### 66. `ColumnInfo.typeIntervalType` — `type` doubled — `src/v1/model.ts:816` +- **Why weird:** `typeIntervalType` doubles the word "type". Doc: "Format of IntervalType." +- **Category:** 7 (overly verbose). +- **Suggested name:** `intervalFormat` (in a sub-struct) or `intervalType`. +- **Rationale:** Trim the doubled word. + +### 67. `ExternalLink_HttpHeadersEntry` — `_` underscore type — `src/v1/model.ts:904` +- **Why weird:** Proto-generated entry type with underscore. Used internally for the map serialization. +- **Category:** 4 (underscores in TS identifiers), 14 (proto-style nested name). +- **Suggested name:** Map directly to `Record` (the parent field `httpHeaders` is already typed as `Record`). +- **Rationale:** The proto-style underscore name leaks into the public surface even though the parent field uses a flat `Record`. + +### 68. `Schema` type name — too generic — `src/v1/model.ts:1680` +- **Why weird:** `Schema` is one of the most-overloaded names in the SDK (Unity Catalog Schema, SQL schema, JSON schema, Avro schema, etc.). This `Schema` is a SQL result schema (`columnCount`, `columns`). +- **Category:** 1 (vague/generic), 12 (collides with UC `Schema`). +- **Suggested name:** `ResultSchema`. +- **Rationale:** Collision with UC `Schema` will bite consumers who import from both. + +### 69. `Struct` type name — too generic, copied from proto wkt — `src/v1/model.ts:1729` +- **Why weird:** `Struct` is the proto Well-Known Type `Struct` (an arbitrary JSON-object value). Calling this `Struct` clashes with TS's natural use of "struct" for any object. +- **Category:** 1 (vague/generic), 12 (proto wkt copy). +- **Suggested name:** Use `Record` directly, or call it `JsonObject` / `ProtoStruct`. +- **Rationale:** WKT types leaking through the public API surface should be unwrapped. + +## Observations + +### 70. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #50 +- **Observation:** Listed under #50. Documenting here for cross-reference. + +### 71. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1771` +- **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. +- **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. +- **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. + +### 72. `unmarshalGenieMessageSchema` returns a `GenieMessage` but the input keys are snake_case — `src/v1/model.ts:2188` +- **Observation:** Standard generator pattern. Worth noting that the package has 50 `unmarshalXSchema` exports and 14 `marshalXSchema` exports — generator-faithful. Not a naming bug per se. + +### 73. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,1000,1004,1008` +- **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md new file mode 100644 index 00000000..9a92dea1 --- /dev/null +++ b/.agent/naming-audit/gitcredentials.md @@ -0,0 +1,374 @@ +# Naming Audit: gitcredentials + +**Path:** `packages/gitcredentials/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-gitcredentials` (lowercased compound — the +camel-case domain term is "Git credentials", so the package directory and +module name both drop the obvious word boundary). +**Inferred domain:** A small CRUD surface over a workspace-level Git provider +credential store. Each credential is a record holding `(gitProvider, +gitUsername, gitEmail, name, isDefaultForProvider)` plus a write-only +`personalAccessToken`. The API mints an opaque numeric `credentialId` on +creation and returns it everywhere else. Five operations: +`create/get/list/update/delete`. No enums, no discriminated unions, no +pagination, no list filtering beyond an optional `principalId` query +parameter, no version negotiation. +**Total weird names flagged:** 31 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `gitcredentials` / module `@databricks/sdk-gitcredentials` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 12 Duplicate concepts | Lowercased compound noun runs `git` and `credentials` together with no separator. The npm registry has packages literally called `git-credentials`/`@gitcredentials` (different ecosystem). Also collides conceptually with `@databricks/sdk-credentials` (Unity Catalog cloud-storage credentials) and `@databricks/sdk-auth/credentials` (SDK auth credentials). Three packages with "Credentials" in the name, three different meanings. | +| 2 | `Credential` (interface) | model.ts:68 | interface | High | 1 Vague/generic, 12 Duplicate concepts | Bare `Credential` clashes with `@databricks/sdk-credentials`'s `Credential` (UC credentials) and with the auth package's `Credentials` interface. None of them say "Git" or "auth" or "UC" on the type name. Should be `GitCredential`. | +| 3 | `Credential` vs `CreateCredentials_Response` vs `GetCredentials_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. They share the same zod transform body (lines 195-212 vs 214-230 vs 237-254 — three copies). `CreateCredentials_Response` and `GetCredentials_Response` should be type aliases of `Credential`, or `Credential` should be the response type directly. | +| 4 | `CreateCredentials` vs `UpdateCredentials` (request envelopes) | model.ts:5, 152 | interface pair | High | 12 Duplicate concepts | The two request envelopes differ by exactly one field: `UpdateCredentials` adds `id` (path parameter). Otherwise field-for-field identical: `gitProvider`, `gitUsername`, `personalAccessToken`, `principalId`, `name`, `isDefaultForProvider`, `gitEmail`. The JSDoc text on every shared field is duplicated verbatim across both. Should share a base type (`GitCredentialMutation`) and only differ on the path key. | +| 5 | `CreateCredentials` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The response is `CreateCredentials_Response` — also plural. The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredential` / `CreateCredentialResponse`. (Compare `Credential` itself — the resource singular is already chosen.) | +| 6 | `UpdateCredentials`, `DeleteCredentials`, `GetCredentials` named with plural | model.ts:152, 98, 108 | interface set | High | 9 Singular/plural mismatches | Same as #5 — three more cases. `UpdateCredentials` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentials` deletes one. `GetCredentials` gets one. All three should be singular. | +| 7 | `ListCredentials_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | +| 8 | `CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response` (proto-style underscore identifiers) | model.ts:43, 106, 116, 147, 192 | interface set | High | 4 Underscores in TS identifiers | Five proto-style `Parent_Response` types each carrying their own `// eslint-disable-next-line @typescript-eslint/naming-convention` comment. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. Standard TS idiom would be `CreateCredentialResponse` (PascalCase without underscore), or `Credential` directly (no separate response type at all — see #3, #17, #18). | +| 9 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | +| 10 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | +| 11 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | +| 12 | `bitbucketServer` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Same problem as #11 — wire value is the legacy name. | +| 13 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | +| 14 | `gitUsername`, `gitEmail`, `gitProvider` prefixed with `git` | model.ts:20, 39, 13, 54, 65, 84, 95, 127, 138, 175, 188 | field set | Medium | 1 Vague/generic, 6 Misleading names | The package is *gitcredentials*; every field already lives under the package namespace. Re-prefixing each field with `git` is stuttering. `req.gitProvider`, `req.gitUsername`, `req.gitEmail` could be `req.provider`, `req.username`, `req.email`. The wire format requires the `git_` prefix on the JSON keys (see the zod schemas), but the TS field can be renamed in the zod `transform`. | +| 15 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | +| 16 | `isDefaultForProvider` field | model.ts:32, 58, 88, 131, 181 | field | Medium | 7 Overly verbose | 20-character field name. "For Provider" is implicit (a credential's provider is fixed; "default" only makes sense relative to it). `isDefault` would be sufficient. | +| 17 | `CreateCredentials_Response` vs `GetCredentials_Response` (identical shapes) | model.ts:43, 116 | interface pair | High | 12 Duplicate concepts | Same six fields, same types, same optionality, same JSDoc text. Should be a single `Credential` type (see #3). | +| 18 | `Credential` vs the two response types (identical shapes) | model.ts:68, 43, 116 | interface trio | High | 12 Duplicate concepts | The `Credential` resource type and the two `*_Response` types are field-for-field identical (see #3). The pattern is uniform across the file: the create-response and get-response should be `Credential`. The list-response is `{credentials: Credential[]}` — that one is fine; the response wrappers around a single credential are not. | +| 19 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | +| 20 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 104, 135, 166, 197 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 21 | `DeleteCredentials.id` and `GetCredentials.id` and `UpdateCredentials.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | +| 22 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | +| 23 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | +| 24 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | +| 25 | `unmarshalCreateCredentials_ResponseSchema` (and four siblings) | model.ts:195, 214, 233, 237, 257, 267 | const set | High | 4 Underscores in TS identifiers, 14 Go/Java-style names, 20 Type-suffix tautology | Generator-emitted const names embed the underscore-bearing parent type name and append `Schema`. Five marshal/unmarshal schemas all carry `// eslint-disable-next-line @typescript-eslint/naming-convention`. The names also pile up three type-suffix words: `Credentials_ResponseSchema` is "Credentials" + "Response" + "Schema", each implying the others. | +| 26 | `marshal*Schema` / `unmarshal*Schema` const naming | model.ts:195, 214, 233, 237, 257, 267, 270, 290 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go idioms; `Schema` is tautological with `z.ZodType`. TS-canonical pair is `encode`/`decode`. Generator-wide pattern (also flagged in the credentials audit, #53). | +| 27 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials` and `accountaccesscontrolproxy` audits — repeated boilerplate. | +| 28 | `parseResponse` vs `marshalRequest` (mixed action verbs) | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | One side says `parse`, the other says `marshal`. Should be either `parse`/`format` or `marshal`/`unmarshal`. | +| 29 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | (none) | Exported but never imported in `client.ts` (which builds query strings inline at line 109-114, 140-145, 171-176). Dead code or future-use. | +| 30 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | +| 31 | `PACKAGE_SEGMENT` const | client.ts:43 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. (Same flag as the credentials audit, #58.) | + +--- + +## High severity (must fix) + +### H1. Three "Credentials" packages, three meanings + +The repository now has three packages with "Credentials" in the name, each +meaning something different: + +| Package | What it really is | +|---|---| +| `@databricks/sdk-auth/credentials/` (hand-written sub-module) | SDK *user* authentication credentials (PAT, OAuth U2M, OAuth M2M). | +| `@databricks/sdk-credentials` | Unity Catalog cloud-storage / service credentials (AWS IAM roles, Azure SPs, GCP service accounts). | +| `@databricks/sdk-gitcredentials` (this package) | Per-workspace Git provider credentials (PATs for GitHub, GitLab, etc.). | + +A consumer reading `import {Credential} from '@databricks/sdk-...'` cannot +tell which one is meant. The three packages even use the same `Credential` +type name. Recommend: + +- Either keep the domain prefix in the type names (`GitCredential` here, + `StorageCredential`/`ServiceCredential` in the UC package), or +- Disambiguate the package names (`@databricks/sdk-git-credentials` — + spelled with the hyphen — would at least visually separate it). + +Also flagged: directory and module name use `gitcredentials`, not +`git-credentials` or `git_credentials`. The npm registry already has +unrelated packages with the literal name `git-credentials` and +`git-credentials-node`. Pick a hyphenated form to disambiguate from those. + +### H2. Plural request-type names + +Four request envelopes act on a single resource but use the plural noun: +`CreateCredentials`, `GetCredentials`, `UpdateCredentials`, +`DeleteCredentials`. Plus five client methods of the same name (`createCredentials`, +etc.). The result is that the API reads like a bulk-create surface ("call +`createCredentials` with five credentials") when it is actually a one-at-a-time +API. + +```ts +// reads as a bulk create +await client.createCredentials({gitProvider: 'gitHub', ...}); + +// what the API actually does +await client.createCredential({gitProvider: 'gitHub', ...}); +``` + +Recommendation: keep `listCredentials` (plural — list returns many) but +rename the four single-resource methods and their request types to +singular. See #5, #6, #20. + +### H3. Five `_Response` types use proto-style underscores + +`CreateCredentials_Response`, `DeleteCredentials_Response`, +`GetCredentials_Response`, `ListCredentials_Response`, +`UpdateCredentials_Response` plus the five `*_ResponseSchema` consts all +carry inline `// eslint-disable-next-line @typescript-eslint/naming-convention` +disables (a total of ten in this one model.ts file). The presence of +those disables is the loudest possible signal that the names violate the +project's own conventions. + +Standard TS idiom would be `CreateCredentialResponse` (PascalCase, no +underscore), nested in a namespace, or — as is appropriate here — *removed +entirely* in favor of returning the resource type directly (see H4). + +### H4. Three field-for-field-identical "Credential" shapes + +`Credential`, `CreateCredentials_Response`, and `GetCredentials_Response` +all have the same six fields with the same types, the same optionality, the +same JSDoc text, and three copies of the same zod transform body +(model.ts:195-212 vs 214-230 vs 237-254). Two of the three are redundant. + +Recommendation: + +```ts +// Before +export interface CreateCredentials_Response { /* 6 fields */ } +export interface GetCredentials_Response { /* same 6 fields */ } +export interface Credential { /* same 6 fields */ } + +// After +export interface GitCredential { /* 6 fields */ } +// Return GitCredential directly from create() and get(). +``` + +### H5. `id` vs `credentialId` for the same value + +Requests use `id`: + +```ts +interface DeleteCredentials { id?: number; principalId?: number; } +interface GetCredentials { id?: number; principalId?: number; } +interface UpdateCredentials { id?: number; /* ... */ } +``` + +Responses use `credentialId`: + +```ts +interface Credential { credentialId?: number; /* ... */ } +interface CreateCredentials_Response { credentialId?: number; /* ... */ } +interface GetCredentials_Response { credentialId?: number; /* ... */ } +``` + +So callers write `req.id = resp.credentialId` and constantly translate +between the two spellings. JSDoc on the request `id` field even says "the ID +for the corresponding *credential* to access" — i.e., it is logically a +credential ID. The wire format uses `id` (path parameter) on requests and +`credential_id` (body field) on responses — the *server* mints the +divergence; the TS-side should normalize to one spelling. See #21, #24. + +### H6. `gitProvider` is typed `string` but is closed-set + +```ts +gitProvider?: string | undefined; +``` + +JSDoc enumerates eight values: `gitHub`, `bitbucketCloud`, `gitLab`, +`azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, +`gitLabEnterpriseEdition`, `awsCodeCommit`. The set is closed; the API +server rejects other values. But the TS-side surfaces it as `string`, so: + +- No autocomplete on the value list. +- No compile-time check for typos (`gitub` will type-check). +- The JSDoc casing inconsistencies (`gitHub` vs `gitLabEnterpriseEdition`) + cannot be fixed at the call site, only by the API server. + +Recommendation: emit a string-literal union or enum. The casing problem +(#10) gets handled there. + +### H7. `Client` is unqualified + +`export class Client` (client.ts:48). Every package in this SDK exports its +own `Client`. Once imported in user code: + +```ts +import {Client as GitCredentialsClient} from '@databricks/sdk-gitcredentials/v1'; +``` + +— the consumer has to do the renaming. The generator should produce +`GitCredentialsClient` directly (matching the package noun). This is a +pattern-wide issue and was flagged in every audit so far. + +--- + +## Medium severity (worth pushing back on) + +### M1. `git`-prefix on every field + +Every field is `git`-prefixed: `gitProvider`, `gitUsername`, `gitEmail`. +The package is `gitcredentials`; the type is `Credential` or +`*Credentials`; the field is already scoped. Reading code: + +```ts +const cred: Credential = await client.getCredentials({id: 42}); +console.log(cred.gitProvider, cred.gitUsername, cred.gitEmail); +``` + +The `git` prefix adds no information. Compare: + +```ts +console.log(cred.provider, cred.username, cred.email); +``` + +The wire JSON key needs `git_provider`, so the rename is purely a zod +`transform` change. The `git_*` keys must survive to the wire; the TS field +names can be unprefixed. See #14. + +### M2. Plural `*Credentials` envelopes for single-resource operations + +See H2. Repeating because the request-type and method names compound the +plural problem. + +### M3. `name` field is a display label, not a key + +JSDoc says "the name of the git credential, used for identification and ease +of lookup". So `name` is a *display* name. The actual lookup key is `id`. +Callers reading the type signature will assume `name` is a primary key +(because it is on most Databricks resources — e.g., `clusters/{name}`). +`displayName` or `label` would clarify. See #23. + +### M4. `principalId` is a service-principal ID, not a user ID + +JSDoc on every `principalId` field says "The ID of the service principal +whose credentials will be modified. Only service principal managers can +perform this action." The field name says only "Principal" — which is +overloaded in security/auth contexts. `servicePrincipalId` would +self-document. See #22. + +### M5. `parseResponse` / `marshalRequest` / `executeCall` / `executeHttpCall` (action-verb soup) + +`utils.ts` exposes: + +- `parseResponse(body, schema)` +- `marshalRequest(data, schema)` +- `executeCall(call, options)` +- `executeHttpCall(opts)` +- `buildHttpRequest(method, url, headers, signal?, body?)` + +Three different action verbs across the file (`parse`, `marshal`, +`execute`, `build`). The `parse`/`marshal` mismatch is the loudest one +(both functions are zod-schema invocations that go in opposite +directions). Either: + +- `marshalRequest` / `unmarshalResponse` (Go idiom, matches `marshal*Schema`/`unmarshal*Schema`), or +- `encodeRequest` / `decodeResponse` (TS idiom). + +The `execute*` pair (`executeCall` wraps the retry/rate-limit executor; +`executeHttpCall` is a single HTTP round-trip) has been flagged in every +audit so far. See #27, #28, #30. + +### M6. `personalAccessToken` field name is narrower than its accepted values + +JSDoc: + +> The personal access token used to authenticate to the corresponding Git +> provider. For certain providers, support may exist for other types of +> scoped access tokens. + +So the field accepts more than just "personal access tokens" — also "fine- +grained tokens", "deploy keys", etc. depending on the provider. The +name `personalAccessToken` lies about that. `accessToken` (or `token`) is +honest. See #15. + +### M7. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term + +The model has one *singular* type — `Credential` (the resource) — and +five *plural* request/response types around it. Within one file the same +concept toggles plural/singular at almost every boundary: + +| Where | Spelling | +|---|---| +| Resource type | `Credential` | +| Create-request type | `CreateCredentials` | +| Create-response type | `CreateCredentials_Response` (returns one) | +| Get-request type | `GetCredentials` (gets one) | +| Get-response type | `GetCredentials_Response` (returns one) | +| Update-request type | `UpdateCredentials` (updates one) | +| Delete-request type | `DeleteCredentials` (deletes one) | +| List-request type | `ListCredentials` (lists many) | +| List-response type | `ListCredentials_Response.credentials` | +| Wire endpoint | `/api/2.0/git-credentials` (plural collection) | + +Pick a rule. Conventional CRUD: plural for collection ops (`listCredentials`, +URL `/credentials`), singular for resource ops (`getCredential`, +`createCredential`, URL `/credentials/{id}`). + +--- + +## Low severity (style polish) + +### L1. `isDefaultForProvider` is verbose + +20 chars. "For Provider" is implied (a credential's provider is fixed, +"default" only has meaning relative to it). `isDefault` is sufficient. See +#16. + +### L2. `flattenQueryParams` is dead code + +Exported from `utils.ts:123`, never imported in `client.ts`. Either remove +or use. The four client methods that take query parameters all build the +query string inline. See #29. + +### L3. `parseResponse` vs `marshalRequest` action-verb mismatch + +See M5. The `parse`/`marshal` mismatch is the worst of the action-verb +soup. See #28. + +### L4. `PACKAGE_SEGMENT` could be more specific + +"Segment" is vague — it is a user-agent segment, specifically. The +constant is used once (in the User-Agent string). `USER_AGENT_PACKAGE_SEGMENT` +would tie it to its only consumer. See #31. + +### L5. `awsCodeCommit` is documented as deprecated but not tagged + +The JSDoc on `gitProvider` says "`awsCodeCommit` (deprecated by AWS, not +accepting new customers)". But the model has no `@deprecated` tag on +either the field's documentation or on a typed enum value (which doesn't +exist — see H6). Callers cannot programmatically detect deprecated values. +See #13. + +--- + +## Notes + +### Wire-protocol values that the audit cannot fix + +The `gitProvider` wire values (`gitHub`, `bitbucketCloud`, etc.) are +dictated by the API server. The casing inconsistencies (#10) are baked in. +The TS-side cannot change them without breaking the wire. The audit flags +them for awareness — fixing requires an API-server change. + +### Identifier zoo summary + +| Identifier kind | Count | +|---|---| +| Total exported interfaces | 10 | +| Underscored (proto-style) interfaces | 7 (`CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response`, and the schema consts) | +| Plural request envelopes for single-resource ops | 4 | +| Identical-shape interface trios | 1 (`Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | +| Inline ESLint disables required by these names | 10 | +| Enums | 0 (despite an 8-value closed set on `gitProvider`) | + +### Comparison to other audits + +| Issue | This package | `credentials` audit | `oauthcustomappintegration` (typical) | +|---|---|---|---| +| Bare `Client` class | Yes (#19) | Yes (#10) | Yes | +| `_Response` underscore types | Yes (#8) | Yes (#18) | Yes | +| `marshal*Schema` / `unmarshal*Schema` consts | Yes (#25, #26) | Yes (#53) | Yes | +| `executeCall` / `executeHttpCall` vocabulary clash | Yes (#27) | Yes (#55) | Yes | +| `flattenQueryParams` dead code | Yes (#29) | Yes (#57) | Yes | +| Bare `id` field on requests vs `Id` on responses | Yes (#21, #24) | Partial (#12, `nameArg`) | Common | +| Plural request envelopes on single-resource ops | Yes (#5, #6, #20) | No (uses `nameArg`/singular shapes) | Mixed | +| `string`-typed enum-domain field | Yes (#9) | No (uses real enums) | Rare | + +The `string`-typed `gitProvider` despite a documented closed set (#9, H6) +is the standout finding unique to this package. The plural request-type +naming (#5, #6, H2) is also pronounced here — the `credentials` audit +gets it right (`CreateCredential`, `UpdateCredential`). diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md new file mode 100644 index 00000000..6ccd4470 --- /dev/null +++ b/.agent/naming-audit/globalinitscripts.md @@ -0,0 +1,332 @@ +# Naming Audit: `globalinitscripts` (v2) + +**Package:** `@databricks/sdk-globalinitscripts` +**Path:** `/home/parth.bansal/sdk-js/packages/globalinitscripts/` +**Version audited:** `v2` +**Files audited:** + +- `src/v2/model.ts` +- `src/v2/client.ts` +- `src/v2/utils.ts` +- `src/v2/index.ts` + +This audit catalogues every identifier (type, field, enum value, method, +constant) in the package and flags naming concerns against the 20-category +rubric. Issues are graded: + +- **High** — actively misleading, ambiguous, or violates a TS rule. +- **Medium** — friction; verbose, redundant, or stylistically off. +- **Low** — nit / consistency observation; safe to ignore. + +--- + +## 1. Inventory + +### 1.1 Enums (`model.ts`) + +None. This package defines no enums. + +### 1.2 Interfaces (`model.ts`) + +| Name | Purpose | +| ------------------------------------- | --------------------------------------------- | +| `CreateGlobalInitScript` | Request body for create. | +| `CreateGlobalInitScript_Response` | Response from create (proto-style suffix). | +| `DeleteGlobalInitScript` | Request body (path param wrapper) for delete. | +| `DeleteGlobalInitScript_Response` | Empty response from delete. | +| `GetGlobalInitScript` | Request body (path param wrapper) for get. | +| `GlobalInitScriptDetails` | Entity describing a global init script. | +| `ListGlobalInitScripts` | Empty request body for list. | +| `ListGlobalInitScripts_Response` | Response from list. | +| `UpdateGlobalInitScript` | Request body for update. | +| `UpdateGlobalInitScript_Response` | Empty response from update. | + +### 1.3 Fields (entity / request / response — combined catalog) + +| Type | Field | Type / Notes | +| --------------------------------- | ------------ | ----------------------------------------- | +| `CreateGlobalInitScript` | `name` | `string?` — script display name. | +| `CreateGlobalInitScript` | `script` | `Uint8Array?` — Base64-encoded content. | +| `CreateGlobalInitScript` | `position` | `number?` — execution order index. | +| `CreateGlobalInitScript` | `enabled` | `boolean?` | +| `CreateGlobalInitScript_Response` | `scriptId` | `string?` | +| `DeleteGlobalInitScript` | `scriptId` | `string?` — path parameter. | +| `GetGlobalInitScript` | `scriptId` | `string?` — path parameter. | +| `GlobalInitScriptDetails` | `scriptId` | `string?` | +| `GlobalInitScriptDetails` | `name` | `string?` | +| `GlobalInitScriptDetails` | `position` | `number?` | +| `GlobalInitScriptDetails` | `enabled` | `boolean?` | +| `GlobalInitScriptDetails` | `createdBy` | `string?` — username. | +| `GlobalInitScriptDetails` | `createdAt` | `number?` — Unix timestamp in ms. | +| `GlobalInitScriptDetails` | `updatedBy` | `string?` — username. | +| `GlobalInitScriptDetails` | `updatedAt` | `number?` — Unix timestamp in ms. | +| `ListGlobalInitScripts_Response` | `scripts` | `GlobalInitScriptDetails[]?` | +| `UpdateGlobalInitScript` | `scriptId` | `string?` — path parameter. | +| `UpdateGlobalInitScript` | `name` | `string?` | +| `UpdateGlobalInitScript` | `script` | `Uint8Array?` — Base64-encoded content. | +| `UpdateGlobalInitScript` | `position` | `number?` | +| `UpdateGlobalInitScript` | `enabled` | `boolean?` | + +### 1.4 Methods (`client.ts`) + +| Method | HTTP | Returns | +| ------------------------- | ------ | ------------------------------------ | +| `createGlobalInitScript` | POST | `CreateGlobalInitScript_Response` | +| `deleteGlobalInitScript` | DELETE | `DeleteGlobalInitScript_Response` | +| `getGlobalInitScript` | GET | `GlobalInitScriptDetails` | +| `listGlobalInitScripts` | GET | `ListGlobalInitScripts_Response` | +| `updateGlobalInitScript` | PATCH | `UpdateGlobalInitScript_Response` | + +### 1.5 Other identifiers + +- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields + `host`, `httpClient`, `logger`, `userAgent`. +- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, + `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`. +- Marshal / unmarshal schemas: + `unmarshalCreateGlobalInitScript_ResponseSchema`, + `unmarshalDeleteGlobalInitScript_ResponseSchema`, + `unmarshalGlobalInitScriptDetailsSchema`, + `unmarshalListGlobalInitScripts_ResponseSchema`, + `unmarshalUpdateGlobalInitScript_ResponseSchema`, + `marshalCreateGlobalInitScriptSchema`, + `marshalUpdateGlobalInitScriptSchema`. + +--- + +## 2. Findings by Category + +### 2.1 Vague / generic names — High & Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| V-01 | `CreateGlobalInitScript.script` / `UpdateGlobalInitScript.script` | High | The field name `script` is overloaded inside a type whose entity name is already "script". A `CreateGlobalInitScript` whose payload field is `script` reads as "the script of the script". Worse, the JSDoc says it carries "Base64-encoded content". A name like `content`, `body`, or `scriptContent` would convey what the bytes actually are. | +| V-02 | `GlobalInitScriptDetails.position` | Medium | `position` is generic. Without the JSDoc the reader cannot tell whether it is an array index, a UI ordering hint, a priority, or an execution-order rank. `executionOrder`, `runOrder`, or `priority` would be more self-describing. | +| V-03 | `GlobalInitScriptDetails.name` | Low | Generic but standard across the SDK; acceptable in entity context. | +| V-04 | `parseResponse` (utils) | Low | Generic, but local to the package. Acceptable. | +| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-06 | `executeCall` / `executeHttpCall` (utils) | Low | Generic but precise: one wraps the other. Acceptable. | +| V-07 | `readAll` (utils, local) | Low | Local helper for draining a `ReadableStream`. Acceptable. | + +### 2.2 Redundant enum prefixes — None + +No enums are declared in this package; this rubric category does not apply. + +### 2.3 Acronym casing inconsistencies — Low + +| ID | Symbol | Severity | Issue | +| ----- | --------------------- | -------- | ----- | +| A-01 | `HttpClient`, `httpClient` (imported from core) | Low | Google TS style uses `Http` (initial-only capitalisation for acronyms > 2 chars — https://google.github.io/styleguide/tsguide.html#identifiers). Consistent. | +| A-02 | `Uint8Array` | Low | Standard Web/TC39 typed-array name; OK. | +| A-03 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScript.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | + +### 2.4 Underscores in TS identifiers — High + +| ID | Symbol | Severity | Issue | +| ----- | ------------------------------------------ | -------- | ----- | +| U-01 | `CreateGlobalInitScript_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). Each occurrence requires an `eslint-disable @typescript-eslint/naming-convention` annotation. Should be `CreateGlobalInitScriptResponse`. | +| U-02 | `DeleteGlobalInitScript_Response` | High | Same as U-01. | +| U-03 | `ListGlobalInitScripts_Response` | High | Same as U-01. | +| U-04 | `UpdateGlobalInitScript_Response` | High | Same as U-01. | +| U-05 | `unmarshalCreateGlobalInitScript_ResponseSchema` | High | Underscore in a constant identifier — same naming-convention violation as the interfaces cascades through the schema constants. Disable comment required. | +| U-06 | `unmarshalDeleteGlobalInitScript_ResponseSchema` | High | Same as U-05. | +| U-07 | `unmarshalListGlobalInitScripts_ResponseSchema` | High | Same as U-05. | +| U-08 | `unmarshalUpdateGlobalInitScript_ResponseSchema` | High | Same as U-05. | +| U-09 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | + +### 2.5 Cryptic abbreviations — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------- | -------- | ----- | +| C-01 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`) | Low | Short-lived local identifiers; OK for short scope but `request` / `response` would be clearer at no cost. | +| C-02 | `opts` (`utils.ts` parameter) | Low | Inside fn scope; minor. | +| C-03 | `pkgJson` (`client.ts`) | Low | Abbreviation of "packageJson". Local import alias; OK. | +| C-04 | `b` (lambda in marshal schema: `Array.from(d, b => ...)`) | Low | Single-letter loop variable; OK in tight scope. | +| C-05 | `d` (lambda parameter in `.transform(d => ...)`, repeated) | Low | Same as C-04; idiomatic for Zod transforms but `data` would be clearer. | + +### 2.6 Misleading names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| M-01 | `CreateGlobalInitScript.script` (field type `Uint8Array`) | High | The field is documented as "Base64-encoded content" but its TS type is `Uint8Array` — the marshal schema converts the bytes to Base64 via `btoa`. Callers therefore supply **raw bytes**, not Base64. The JSDoc is misleading: it describes the wire format, not what the caller hands in. A better split would be either rename to `scriptBytes` (matching the runtime type) or change the doc to "Raw bytes; the SDK Base64-encodes before sending." | +| M-02 | `UpdateGlobalInitScript.script` | High | Same as M-01. | +| M-03 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | +| M-04 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | +| M-05 | `executeCall` vs `executeHttpCall` | Low | The pair is layered correctly; precise. | + +### 2.7 Overly verbose / Redundant suffixes — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------------------- | -------- | ----- | +| O-01 | `CreateGlobalInitScript` / `DeleteGlobalInitScript` / `GetGlobalInitScript` / `UpdateGlobalInitScript` / `ListGlobalInitScripts` | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full, producing ~22-25-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `Create`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | +| O-02 | `GlobalInitScriptDetails` (entity name) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | +| O-03 | `unmarshalGlobalInitScriptDetailsSchema` | Medium | 38 chars. Combination of `unmarshal*Schema` triple-statement plus the long entity name. The pattern is repo-wide. | +| O-04 | `unmarshalCreateGlobalInitScript_ResponseSchema` | Medium | 47 chars — among the longest identifiers in the package. Pattern is repo-wide; flagged once. | +| O-05 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-06 | `buildHttpRequest`, `executeHttpCall` (utils) | Low | Descriptive; OK. | + +### 2.8 Singular / plural mismatches — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| P-01 | `ListGlobalInitScripts` (request, plural) vs `listGlobalInitScripts()` (method, plural) | Low | Consistent. | +| P-02 | `ListGlobalInitScripts_Response.scripts` | Low | Plural field for array — correct. | +| P-03 | `GlobalInitScriptDetails` (singular entity) vs `getGlobalInitScript()` (singular get) | Low | Consistent. | +| P-04 | `createGlobalInitScript`, `deleteGlobalInitScript`, `updateGlobalInitScript` | Low | Singular for per-resource ops — correct. | + +### 2.9 Reserved-word collisions — None + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| R-01 | None observed. | — | None of the field names (`name`, `script`, `position`, `enabled`, `scriptId`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`) collide with JavaScript reserved words. Note that `name` is a reserved property on `Function.prototype` but not a reserved identifier, so it is fine as a field name. | + +### 2.10 Empty / trivial wrapper types — None + +_None._ + +### 2.11 Duplicate concepts — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| D-01 | `CreateGlobalInitScript` vs `UpdateGlobalInitScript` | Medium | Update adds only one field (`scriptId`); otherwise identical to create. Two near-duplicate 4-field interfaces. Codegen constraint, but readers see them side by side. | +| D-02 | `GlobalInitScriptDetails` vs `CreateGlobalInitScript` / `UpdateGlobalInitScript` | Medium | Same `name`, `position`, `enabled` fields appear in three types. The entity adds audit fields (`createdBy`, `createdAt`, etc.) but omits `script`. A shared base / fragment would reduce duplication. | +| D-03 | `unmarshalDeleteGlobalInitScript_ResponseSchema` and `unmarshalUpdateGlobalInitScript_ResponseSchema` | Medium | Both `z.object({})` — two identically empty schemas. The duplication is forced by the typed-distinct-interfaces pattern. | +| D-04 | Identical Zod schema bodies inside `marshalCreateGlobalInitScriptSchema` and `marshalUpdateGlobalInitScriptSchema` | Low | Marshal schemas overlap heavily; update adds only `scriptId`. Codegen constraint. | + +### 2.12 Verb-tense inconsistency — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| T-01 | `createGlobalInitScript`, `deleteGlobalInitScript`, `getGlobalInitScript`, `listGlobalInitScripts`, `updateGlobalInitScript` | Low | All imperative present-tense — consistent. | +| T-02 | `createdBy`, `createdAt`, `updatedBy`, `updatedAt` | Low | Past participles for audit fields — correct convention. | +| T-03 | `enabled` (past participle / adjective) | Low | Consistent with the rest of the SDK (`enabled` boolean state). | + +### 2.13 Go / Java-style names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| G-01 | `CreateGlobalInitScript_Response` (proto nested-message style) | High | Direct port of Go / protobuf `pb.CreateGlobalInitScriptResponse` naming. TypeScript ecosystems do not use `_` between message and nested-message names; the file disables ESLint for each occurrence. Should adopt the TS-idiomatic `CreateGlobalInitScriptResponse`. Applies to all four `*_Response` interfaces. | +| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**). Newcomers to TS will look up "marshal" before recognising it. Repo-wide convention. | +| G-03 | `GlobalInitScriptDetails` (Java-style "Details" suffix) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | +| G-04 | `req: CreateGlobalInitScript` (parameter named `req`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | + +### 2.14 Generic field names losing meaning — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| F-01 | `GlobalInitScriptDetails.position` | Medium | `position` standing alone (e.g. inside a generic list-item display) is ambiguous: file position? UI position? Order index? Adding context (`runOrder`) would survive destructuring. | +| F-02 | `CreateGlobalInitScript.script` (`Uint8Array`) | High | A field called `script` of type `Uint8Array` does not communicate "bytes of the script content". Outside the interface it could be mistaken for a script object/handle. See V-01, M-01. | +| F-03 | `GlobalInitScriptDetails.name` | Low | Standard entity field; meaning preserved in context. | +| F-04 | `httpReq`, `respBody`, `body`, `headers`, `text`, `parsed`, `info` (locals in `client.ts` / `utils.ts`) | Low | Local-scope identifiers only. | + +### 2.15 Field contradicting type domain — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| FD-01 | None observed. | — | All fields are domain-appropriate for the global-init-script context. | + +### 2.16 Inconsistent action verbs — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| AV-01 | `createGlobalInitScript`, `deleteGlobalInitScript`, `getGlobalInitScript`, `listGlobalInitScripts`, `updateGlobalInitScript` | Low | Clean CRUD verb set — `create`, `delete`, `get`, `list`, `update`. Matches the broader Databricks SDK style. No `edit` / `patch` / `modify` inconsistencies. | +| AV-02 | `getGlobalInitScript()` (singular) vs `listGlobalInitScripts()` (plural) | Low | Correct convention (singular get, plural list). Consistent. | + +### 2.17 Long enum values — None + +No enums declared; not applicable. + +### 2.18 Underspecified IDs — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| I-01 | `scriptId` | Medium | The field name `scriptId` is the API-level field but inside a workspace-scoped SDK there is at least one other ID concept called "script" (e.g. cluster init scripts via `clusters` package — see `InitScriptInfo`). A globally-unique identifier across the Databricks SDK surface would be `globalInitScriptId`. The shorter `scriptId` is in line with the API wire field, so this is a known trade-off, but ID names should generally be fully qualified to avoid cross-package ambiguity. | +| I-02 | `scriptId` (in `DeleteGlobalInitScript`, `GetGlobalInitScript`, `UpdateGlobalInitScript`) | Medium | Same as I-01. All five locations use the bare `scriptId`. | + +### 2.19 Type-suffix tautology — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| TS-01 | `GlobalInitScriptDetails` | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-03. | +| TS-02 | `HttpCallOptions` (utils) | Low | "Options" is conventional for option-bag types; not tautological. | +| TS-03 | `CallOptions` (imported) | Low | Same. | + +### 2.20 Other observations + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| X-01 | `GlobalInitScriptDetails.createdAt` / `updatedAt` (`number`, epoch ms) | Low | Acceptable for ms timestamps; the SDK exposes these as plain numbers. JS `Date` safe-integer range covers epoch-ms beyond year 285,000. Flagged for parity with other audits. | +| X-02 | `marshalRequest` (utils) | Low | Generic for "marshal arbitrary request body". OK in context. | +| X-03 | `flattenQueryParams` (utils, exported but unused in `client.ts`) | Low | `client.ts` builds no query strings — all parameters are body or path. Either drop the export or move to a shared helper module. Not strictly a naming issue. | +| X-04 | `executeHttpCall` vs `executeCall` (utils) | Low | Two-level wrapper: `executeCall` (transport-agnostic) wraps `executeHttpCall` (HTTP-specific). Naming communicates the layering; OK. | +| X-05 | `PACKAGE_SEGMENT` constant | Low | `SCREAMING_SNAKE_CASE` for a module-level constant — Google TS style permits this for "module-level constants … that are deeply immutable and used like enum constants" (https://google.github.io/styleguide/tsguide.html#constants). OK. | +| X-06 | `Client` (class name) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | +| X-07 | `VERSION as AUTH_VERSION` (imported alias) | Low | Aliasing on import is fine; communicates which version is being referenced. OK. | +| X-08 | `HttpClient`, `HttpRequest`, `HttpResponse` (imported) | Low | Consistent Google-style acronym casing. OK. | +| X-09 | `NoOpLogger` (imported) | Low | `NoOp` casing is correct for "no-op" (the term `no-op` is itself a contracted form). OK. | + +--- + +## 3. Summary + +### 3.1 Findings by severity + +| Severity | Count | +| -------- | ----- | +| High | 12 | +| Medium | 17 | +| Low | 36 | +| **Total**| **65**| + +### 3.2 Top themes + +1. **Proto-style `_Response` suffix pollutes every CRUD response type.** + Four interfaces (`CreateGlobalInitScript_Response`, + `DeleteGlobalInitScript_Response`, `ListGlobalInitScripts_Response`, + `UpdateGlobalInitScript_Response`) and their corresponding schema + constants each require an `eslint-disable` for the naming-convention + rule. Renaming to TS-idiomatic `CreateGlobalInitScriptResponse` etc. + would eliminate ~8 disable-comments and a Google-style violation in + one sweep. + +2. **`script` field overload conflates "script bytes" with "the entity".** + The field is typed as `Uint8Array` (raw bytes), documented as + "Base64-encoded content" (the wire format), and lives on a type + already called `GlobalInitScript`. Renaming the field to `content` + (or `scriptBytes`) — and clarifying the JSDoc — removes both the + self-reference ("script.script") and the format-vs-runtime confusion. + +3. **`GlobalInitScriptDetails` should just be `GlobalInitScript`.** + The `Details` suffix is a Java-style hangover with no peer type to + disambiguate from. The method JSDoc also claims to return Base64 + content while the entity has no content field — a documentation / + shape inconsistency. + +4. **`createdAt`/`updatedAt` naming is good** — unlike sibling packages + that use `createdAtTimestamp`, this package uses the cleaner + `createdAt` / `updatedAt`. Worth keeping as the cross-package + reference. + +### 3.3 Suggested quick wins (advisory — codegen-level) + +- Drop the `_Response` underscore: `CreateGlobalInitScriptResponse`, + `DeleteGlobalInitScriptResponse`, `ListGlobalInitScriptsResponse`, + `UpdateGlobalInitScriptResponse`. Removes 8 ESLint disables. +- Rename `script` field to `content` (or `scriptContent`). +- Rename entity `GlobalInitScriptDetails` -> `GlobalInitScript`. +- Add the missing content field on the entity (or fix the JSDoc on + `getGlobalInitScript` that claims contents are returned). + +### 3.4 Cross-package consistency notes + +- The `marshal*` / `unmarshal*` schema-naming convention is consistent + with peer packages (e.g. `clusterpolicies`, `clusters`) and is therefore + a repo-wide concern, not a per-package fix. +- The `Proto-style nested message name` `_Response` suffix is consistent + with peers and should be addressed at the codegen level. +- `position` field semantics are unique to this resource; no other + package collides on the name with a different meaning. +- The clean `createdAt` / `updatedAt` naming here contrasts with + `createdAtTimestamp` in `clusterpolicies` — this package is the + preferred reference for timestamp naming. diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md new file mode 100644 index 00000000..63752723 --- /dev/null +++ b/.agent/naming-audit/grants.md @@ -0,0 +1,299 @@ +# Naming Audit: grants + +**Path:** `packages/grants/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. +**Total weird names flagged:** 45 + +## Summary +| Severity | Count | +| --- | --- | +| High | 14 | +| Medium | 17 | +| Low | 9 | +| Observation | 5 | + +The grants package contains 12 generated types and 5 client methods (plus 2 paginated iterators) covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive issues are (1) the request-type-as-verb naming pattern (`GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions`) which collides with the verb-noun method naming on `Client` and is doubly confusing because the API mixes "permissions" and "privileges" terminology in the same file, (2) proto-style `_Response` underscore-suffixed identifiers leaking into TypeScript (`GetPermissions_Response`, `GetEffectivePermissions_Response`, `UpdatePermissions_Response`) requiring eslint-disable directives, (3) significant duplication of concept between `GetPermissions` / `ListPrivilegeAssignmentsRequest` and `GetEffectivePermissions` / `ListEffectivePrivilegeAssignmentsRequest` — four request types for two operations, plus inconsistent field naming (`securableFullName` vs `fullName`, `maxResults` vs `pageSize`) — and (4) hard-conceptual overlap with the separate `permissions` package, which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation. + +--- + +## High severity + +### 1. `GetPermissions` (type) — `src/v1/model.ts:63` +- **Why weird:** Top-level request type named with an imperative verb (`Get`). TypeScript types should be nouns; verbs are reserved for methods. The Client also has a method named `getPermissions` (line 129) which takes this type as input, so the user sees `getPermissions(req: GetPermissions)` — verb-noun-verb-noun. The same identifier is both a request shape and a verb command; readers cannot tell from the type whether they're naming the request or the operation. +- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs). +- **Suggested name:** `GetPermissionsRequest`, `GetPermissionsParams`, or — better — `PermissionsRequest` / `ListPermissionsRequest` to consistently apply the `Request` suffix convention used by `ListPrivilegeAssignmentsRequest` (line 129) in the same file. +- **Rationale:** This file alternates between two naming patterns: `GetPermissions` / `UpdatePermissions` (verb-only) and `ListPrivilegeAssignmentsRequest` / `ListEffectivePrivilegeAssignmentsRequest` (verb+noun+Request). Inconsistency within a single 342-line file is jarring. + +### 2. `UpdatePermissions` (type) — `src/v1/model.ts:197` +- **Why weird:** Same problem as #1. `UpdatePermissions` is a noun-shaped request payload but reads as an imperative verb. Used as input to `client.updatePermissions(req: UpdatePermissions)` (line 307). +- **Category:** 7, 14, 17. +- **Suggested name:** `UpdatePermissionsRequest` or `PermissionsChangeRequest`. +- **Rationale:** See #1. + +### 3. `GetEffectivePermissions` (type) — `src/v1/model.ts:27` +- **Why weird:** Same as #1 / #2. Verb-shaped request type. +- **Category:** 7, 14, 17. +- **Suggested name:** `GetEffectivePermissionsRequest`. +- **Rationale:** See #1. + +### 4. `GetEffectivePermissions_Response` — `src/v1/model.ts:53` +- **Why weird:** Proto-style nested message name (`MessageType_FieldName`) with an embedded underscore — illegal in idiomatic TS identifier style. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` to compile. The fact that every consumer must write `GetEffectivePermissions_Response` with the underscore in their code (e.g. `client.ts:23`, `client.ts:99`, `index.ts:11`) means the proto wart is fully visible in the public API. +- **Category:** 4 (underscore in TS identifier), 14 (proto/Go-style name). +- **Suggested name:** `GetEffectivePermissionsResponse` (drop the underscore) or — combined with #3 — `EffectivePermissionsResponse`. +- **Rationale:** TypeScript convention (Google TS style guide § 5.2) is `PascalCase` without internal underscores. The proto FQN-flattening trick should be hidden by the generator, not surfaced. + +### 5. `GetPermissions_Response` — `src/v1/model.ts:91` +- **Why weird:** Same as #4. +- **Category:** 4, 14. +- **Suggested name:** `GetPermissionsResponse` / `PermissionsResponse`. +- **Rationale:** See #4. + +### 6. `UpdatePermissions_Response` — `src/v1/model.ts:207` +- **Why weird:** Same as #4. +- **Category:** 4, 14. +- **Suggested name:** `UpdatePermissionsResponse`. +- **Rationale:** See #4. + +### 7. Concept duplication: "permissions" vs "privileges" — `src/v1/model.ts` (entire file) +- **Why weird:** The package uses two synonymous nouns interchangeably for the same concept. Method names use `permissions` (`getPermissions`, `updatePermissions`); collection types use `privileges` / `PrivilegeAssignment` / `EffectivePrivilege`. The result type of `getPermissions()` is `GetPermissions_Response` whose payload field is named `privilegeAssignments`. A single privilege string (e.g. `"SELECT"`) is sometimes called a "permission" (e.g. in `GetPermissions.maxResults` doc: "the maximum number of privileges to return") and sometimes a "privilege". This is a vocabulary smell baked into the Go SDK port, but it's the single biggest readability issue in the package. +- **Category:** 12 (duplicate concepts), 17 (inconsistent action verbs / vocabulary). +- **Suggested name:** Pick one. Either rename the type family to `Privileges` (so `getPrivileges`, `updatePrivileges`, `PrivilegeAssignment`, `GetPrivilegesResponse`) or `Permissions` (so `getPermissions`, `updatePermissions`, `PermissionAssignment`). The current mix forces readers to mentally translate every method call. +- **Rationale:** This is wire-locked (Databricks UC API uses `/permissions/` URL paths but body fields named `privileges`), but the SDK doesn't have to expose it. A consistent vocabulary across types and methods makes the API self-documenting. + +### 8. Concept duplication: `GetPermissions` vs `ListPrivilegeAssignmentsRequest` — `src/v1/model.ts:63,129` +- **Why weird:** Two top-level request types do nearly the same thing. Compare fields: + - `GetPermissions`: `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`, `includeDeletedPrincipals`. + - `ListPrivilegeAssignmentsRequest`: `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. + - Differences: `securableFullName` ↔ `fullName`; `maxResults` ↔ `pageSize`. Everything else identical. +- The Client doc strings (`client.ts:171-173`, `client.ts:241-242`) explicitly call out that `listPrivilegeAssignments` is the "paginated version of Get Permissions API", which is exactly what `getPermissions` already supports (pagination via `maxResults`/`pageToken`). So the SDK ships two flavours of the same operation with different but compatible request shapes. +- **Category:** 12 (duplicate concept), 9 (singular/plural mismatch in method naming). +- **Suggested name:** Collapse to a single `ListPrivilegeAssignmentsRequest`; deprecate `GetPermissions` (or vice versa). Match field names across both. See also #18. +- **Rationale:** Two near-identical request types is a documentation/onboarding tax. The decision of which to use is server-internal (V1 of the API supported one paginated mode, the team added a "true paginated" V2) — but the SDK doesn't need to inflict that history on every consumer. + +### 9. Concept duplication: `GetEffectivePermissions` vs `ListEffectivePrivilegeAssignmentsRequest` — `src/v1/model.ts:27,101` +- **Why weird:** Same problem as #8 but for the effective-permissions side. `GetEffectivePermissions` has fields `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`; `ListEffectivePrivilegeAssignmentsRequest` has `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. The List variant additionally supports `includeDeletedPrincipals`, which the Get variant does not — even though `GetPermissions` (#8) does support it. The matrix of which-flavour-supports-which-knob is inconsistent. +- **Category:** 12, 17 (inconsistency). +- **Suggested name:** Same direction as #8 — collapse, or normalize field names and feature parity. +- **Rationale:** See #8. + +### 10. Concept duplication with `permissions` package — cross-package +- **Why weird:** A sibling package `packages/permissions/src/v1/` (also generated, also exposed) uses an entirely different vocabulary for similar-sounding operations: + - `permissions` package: `PermissionLevel` enum (e.g. `CAN_MANAGE`, `IS_OWNER`), `AccessControlRequest` (uses discriminated union over `userName` / `groupName` / `servicePrincipalName`), `PermissionsResponse` with `accessControlList`, `setObjectPermissions`, `getObjectPermissions`, `updateObjectPermissions`, `getPermissionLevels`. + - `grants` package: free-form `privileges: string[]` (no enum), `principal: string` (single field, doesn't distinguish user vs group vs SP), `PrivilegeAssignment`, `getPermissions`, `updatePermissions`. +- Both packages claim the `Permissions` and `Permission*` keywords. A user navigating the SDK will see `permissions` and `grants` and reasonably wonder which to use. There is no surface-level disambiguation. +- **Category:** 12 (duplicate concepts across packages), 1 (vague top-level naming — neither package name is self-disambiguating). +- **Suggested name:** Rename one of the packages to make the disambiguation clear, e.g. `grants` → `unity-catalog-grants` or `uc-privileges`; `permissions` → `workspace-permissions` or `workspace-acl`. Or — at minimum — keep their public types non-overlapping (currently both export "Permission..."-prefixed types). +- **Rationale:** The two packages cover non-overlapping concrete operations (UC grants vs workspace-object ACLs) but use heavily overlapping vocabulary. This is an enormous discoverability hazard. + +### 11. `PermissionsChange` (type) — `src/v1/model.ts:165` +- **Why weird:** Inconsistent vocabulary with the rest of the file. The package mostly uses `Privilege*` (`PrivilegeAssignment`, `EffectivePrivilege`, `EffectivePrivilegeAssignment`, `ListPrivilegeAssignments...`) but the change-payload is named `PermissionsChange` (plural "Permissions", not "Privilege"). The change describes adding/removing entries to `add: string[]` / `remove: string[]` where the strings are privileges. So the type is really a `PrivilegeChange` or `PrivilegeAssignmentChange`. +- **Category:** 17 (inconsistent vocabulary), 12 (concept overlap with `permissions` package). +- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file — see #7). +- **Rationale:** See #7. + +### 12. `principal` (field, multiple) — `src/v1/model.ts:21,33,69,107,135,170,190` +- **Why weird:** The field `principal: string` appears 7 times across the file. The doc string is "user email address or group name" — but the file separately exposes `principalId: number` (line 182, 194). So the type system has no way to tell whether `principal` is an email, a group name, or what — and the `permissions` package solves the same problem with a discriminated union (`{ $case: 'userName' | 'groupName' | 'servicePrincipalName', ... }`). The `grants` package punts. +- **Category:** 1 (vague), 15 (generic field name), 19 (underspecified identifier), 12 (overlap with `permissions` package's typed approach). +- **Suggested name:** `principalName` (matching the `permissions` package, which uses `principalName?: { $case: 'userName' | ... }`); or, better, model the same discriminated union here. +- **Rationale:** "Principal" is overloaded across identity systems (security principal, business principal, mathematical principal, principal-of-the-school). The doc-comment is the only thing distinguishing this from `principalId`. + +### 13. `principalId` field — `src/v1/model.ts:182,194` +- **Why weird:** Two interpretation issues. (1) The doc-comment for `PermissionsChange.principalId` calls it "an opaque internal ID that identifies the principal whose privileges should be removed" — meaning it's a TEMPORARY identifier only valid for deletes of deleted principals. The doc-comment for `PrivilegeAssignment.principalId` calls it the "unique identifier of the principal" — meaning a stable canonical ID. Same field name, two unrelated semantics. (2) The type is `number` — which is dangerous for large UC principal IDs (UC IDs are 64-bit). JS `number` only safely represents integers up to 2^53. +- **Category:** 6 (misleading: same name, different semantics), 19 (underspecified ID), 16 (field contradicts type domain: a 64-bit ID typed as `number`). +- **Suggested name:** Split into `removalToken` (for `PermissionsChange`, since its only purpose is removing a deleted principal) and keep `principalId` (for `PrivilegeAssignment`). And consider `bigint` or `string` for the type. +- **Rationale:** Two different concepts wearing the same name is a footgun. The `number` type for principal IDs is a JS-platform-specific overflow risk; the Go SDK uses `int64`, which JS cannot losslessly represent. + +### 14. `securableFullName` vs `fullName` inconsistency — `src/v1/model.ts:31,67,201` vs `105,133` +- **Why weird:** The path-parameter field for the same securable is named `securableFullName` in `GetEffectivePermissions`, `GetPermissions`, and `UpdatePermissions`; but `fullName` in `ListEffectivePrivilegeAssignmentsRequest` and `ListPrivilegeAssignmentsRequest`. Same value, same wire location, two different field names. The client then constructs the URL using `req.securableFullName` (e.g. line 86) or `req.fullName` (e.g. line 179) depending on which type — but they're going to the same logical endpoint. +- **Category:** 17 (inconsistent action verbs / naming), 15 (generic field name). +- **Suggested name:** Pick one, ideally `fullName` (since `securableType` is already context). +- **Rationale:** Cross-request inconsistency forces the user to remember which type uses which spelling. + +--- + +## Medium severity + +### 15. `EffectivePrivilege.privilege` — `src/v1/model.ts:7` +- **Why weird:** `EffectivePrivilege.privilege` — the field repeats the type name. Inside a `EffectivePrivilege` object, what else could `.privilege` mean? The type is essentially `(privilege, inheritedFromType, inheritedFromName)`. Naming the carrier field after the parent type adds zero info. +- **Category:** 20 (type-suffix tautology), 1 (vague — the doc says "The privilege assigned to the principal" but the type is `string`, untyped). +- **Suggested name:** `name` (since this is the name of a single privilege like `"SELECT"`), or — if keeping `privilege` — change the type to a proper enum (see #19). +- **Rationale:** A field on `X` named `x` is canonically a code smell. + +### 16. `EffectivePrivilege.inheritedFromType` — `src/v1/model.ts:12` +- **Why weird:** Type is `string`, but the doc says "type of the object that conveys this privilege via inheritance" — i.e. a securable type like `CATALOG`, `SCHEMA`, `TABLE`. The package elsewhere talks about `securableType` (also `string`), but there's no enum and no link. A more typed approach would be `SecurableType` (an enum). The name promises a typed handle but the field is free-form text. +- **Category:** 6 (misleading: name implies type, value is string), 19 (underspecified). +- **Suggested name:** `inheritedFromSecurableType` (clarifies what kind of type) — and ideally typed as an enum. +- **Rationale:** "Type" without qualification is ambiguous; consistent with how `securableType` is named elsewhere in the file, this field should be a securable type. + +### 17. `EffectivePrivilege.inheritedFromName` — `src/v1/model.ts:17` +- **Why weird:** Generic "name" field on a non-`Name`-typed thing. Pair with `inheritedFromType` it's clear, but in isolation `inheritedFromName: string | undefined` is just "some string". Doc-comment is required reading. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `inheritedFromFullName` (matching `securableFullName` elsewhere). +- **Rationale:** Internal consistency — the rest of the file uses `fullName` / `securableFullName`. + +### 18. `maxResults` vs `pageSize` — `src/v1/model.ts:47,83,114,151` +- **Why weird:** `GetEffectivePermissions` (line 47) and `GetPermissions` (line 83) use `maxResults`; `ListEffectivePrivilegeAssignmentsRequest` (line 114) and `ListPrivilegeAssignmentsRequest` (line 151) use `pageSize`. Two field names for the same concept — server-side page length cap. The 60+ lines of identical doc-comments (lines 35-46 and 71-82) explaining the "150 minimum" rule appear under both names with no link or cross-reference. +- **Category:** 17 (inconsistent action verbs / naming), 12 (duplicate concept within one file). +- **Suggested name:** Pick one: `pageSize` (more idiomatic for paginated APIs) or `maxResults`. Apply uniformly. +- **Rationale:** Internal inconsistency forces users to look up the right name per type. + +### 19. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,172,174,192`) +- **Why weird:** Every privilege is typed as a free-form `string`. The Go SDK and Databricks UC API have a fixed enum of privilege names (`SELECT`, `MODIFY`, `USE_CATALOG`, `USE_SCHEMA`, `EXECUTE`, `CREATE_*`, `READ_VOLUME`, `WRITE_VOLUME`, etc.). The TS SDK exposes them as bare strings with no autocomplete, no type-checking, no documentation. A typo like `"SELCT"` will silently round-trip to the server. +- **Category:** 19 (underspecified), 1 (vague: `string` doesn't constrain meaning). +- **Suggested name:** Define a `Privilege` enum (or string literal union). At minimum document the valid values inline. +- **Rationale:** Type-safety is the entire point of TypeScript. The audit task explicitly flags "long enum values (many privilege values)" — the irony is that grants HAS the most privilege values of any UC operation and exposes ZERO of them as types. + +### 20. `PermissionsChange.add` / `PermissionsChange.remove` — `src/v1/model.ts:172,174` +- **Why weird:** Bare verb-shaped field names with no clarifying suffix. `add: string[]` and `remove: string[]` on a `PermissionsChange` type — what are they adding to and removing from? The doc-comments tell you ("The set of privileges to add"), but the field names are anonymous. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `addPrivileges` / `removePrivileges`, or `granted` / `revoked`. +- **Rationale:** Common to see `add` / `remove` in change-set APIs (e.g. Kubernetes RBAC, AWS IAM), but those typically pair with a typed item collection. A bare `add: string[]` carries no information. + +### 21. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` +- **Why weird:** Three-word PascalCase name (`Effective` + `Privilege` + `Assignment`) that on first read parses as "Effective Privilege" / "Assignment" but on second read could parse as "Effective" / "Privilege Assignment". The conceptual model is "the privilege assignment that effectively applies (because of inheritance)", which the doc-comment confirms — but the name doesn't disambiguate. +- **Category:** 7 (overly verbose). +- **Suggested name:** Possibly leave as-is; alternative is `EffectiveAssignment` (drop `Privilege` since `Assignment` is privilege-specific in this file). +- **Rationale:** Marginal; flagged for symmetry with `EffectivePrivilege` (line 5). + +### 22. `effectivePrivilegeAssignments` (field name) — `src/v1/model.ts:121` +- **Why weird:** 30-character camelCase field name. Inside `ListEffectivePrivilegeAssignmentsResponse`, the only payload field. Could safely be shortened to `assignments` or `items` since the surrounding type name carries the rest of the qualifier. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name repeats type-name fragment). +- **Suggested name:** `assignments` or `items`. +- **Rationale:** Field names that re-state the parent type are noise. + +### 23. `privilegeAssignments` (field name, multiple) — `src/v1/model.ts:60,98,157,209` +- **Why weird:** Same problem as #22, on the non-effective side. Field name `privilegeAssignments` appears as the sole payload field on `GetEffectivePermissions_Response`, `GetPermissions_Response`, `ListPrivilegeAssignmentsResponse`, and `UpdatePermissions_Response`. Could be `assignments` everywhere. +- **Category:** 7, 20. +- **Suggested name:** `assignments`. +- **Rationale:** See #22. + +### 24. `listEffectivePrivilegeAssignmentsIter` — `src/v1/client.ts:220` +- **Why weird:** 38-character method name on `Client`. `Iter` suffix is Go-style (Go uses `*Iterator` types; TS uses `AsyncGenerator` / `AsyncIterable`). The async generator syntax `async *foo()` is already iterating — `Iter` adds nothing the language doesn't communicate. Plus the noun pile-up: `list` + `Effective` + `Privilege` + `Assignments` + `Iter`. +- **Category:** 5 (cryptic abbreviation: `Iter`), 14 (Go-style name), 7 (overly verbose). +- **Suggested name:** `iterateEffectivePrivilegeAssignments` (verb-first for generators), or `effectiveAssignments` (with the iterator semantics implied). +- **Rationale:** TS convention is `for await` over async generators with verb-first naming. + +### 25. `listPrivilegeAssignmentsIter` — `src/v1/client.ts:289` +- **Why weird:** Same problem as #24. +- **Category:** 5, 14, 7. +- **Suggested name:** `iteratePrivilegeAssignments` or `assignments`. +- **Rationale:** See #24. + +### 26. `getEffectivePermissions` (method) — `src/v1/client.ts:82` +- **Why weird:** Method returns `GetEffectivePermissions_Response` (note the underscore — see #4). The method-name-as-verb is fine, but the type contract has the proto-style wart. Also, the doc-comment notes "Unpaginated calls will be deprecated soon" — so this method exists as a soon-to-be-deprecated mirror of `listEffectivePrivilegeAssignments`. Why ship both in the same v1? +- **Category:** 12 (duplicate concept — see #9), Observation. +- **Suggested name:** Mark as `@deprecated` in JSDoc (currently the deprecation note is just plain text inside the doc-comment, lines 77-78 — not an actual `@deprecated` tag). +- **Rationale:** Tooling like IDEs and ts-doc strikes through deprecated methods only when the `@deprecated` tag is used. + +### 27. `getPermissions` (method) — `src/v1/client.ts:129` +- **Why weird:** Same as #26 — soon-to-be-deprecated unpaginated mirror of `listPrivilegeAssignments`. +- **Category:** 12, Observation. +- **Suggested name:** Add `@deprecated` JSDoc tag. +- **Rationale:** See #26. + +### 28. `securableType: string` — model-wide (5 occurrences) +- **Why weird:** Same concept as #19 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. +- **Category:** 19 (underspecified), 1 (vague). +- **Suggested name:** Define a `SecurableType` enum. +- **Rationale:** See #19. + +### 29. `nextPageToken` (field, multiple) — `src/v1/model.ts:58,96,123,162` +- **Why weird:** Same identifier appears in 4 response types. Fine in isolation, but the doc-comment "__page_token__ should be set to this value for the next request (for the next page of results)" is copy-pasted verbatim 4 times — including the suspicious `__page_token__` (double-underscore, suggesting wire-format documentation) which makes no sense for TS consumers using `pageToken`. +- **Category:** Observation (mostly consistency), 6 (misleading: `__page_token__` in doc). +- **Suggested name:** No rename needed, but doc-comments should reference TS field name `pageToken`, not `__page_token__`. +- **Rationale:** Doc string consistency. + +### 30. `includeDeletedPrincipals` — `src/v1/model.ts:87,109,136` +- **Why weird:** Verbose camelCase boolean. Reasonable but flagged because it's missing from `GetEffectivePermissions` (where the analogous feature would also make sense) but present on `GetPermissions` and both `List*Request` types. Inconsistent feature parity (see also #9). +- **Category:** 17 (inconsistency), 7 (verbose). +- **Suggested name:** `includeDeleted` (shorter). +- **Rationale:** Consistency issue more than naming issue. + +### 31. `Client` — `src/v1/client.ts:49` +- **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts` re-exports `Client` (line 3), so users write `import { Client } from '@databricks/sdk-grants/v1'`. Same name appears in every generated package — you can't have multiple grants/catalogs/etc. clients in one import without aliasing. +- **Category:** 1 (vague), 12 (duplicate across packages). +- **Suggested name:** `GrantsClient` (or whatever the package-specific name is). +- **Rationale:** Convention in `@aws-sdk/*`, `@google-cloud/*`, `@azure/*` is service-prefixed client class names for exactly this reason. + +--- + +## Low severity + +### 32. `unmarshalEffectivePrivilegeSchema` / `marshalUpdatePermissionsSchema` and related — `src/v1/model.ts:212,225,239,253,266,279,292,306,317,331` +- **Why weird:** Eight `unmarshal*Schema` and two `marshal*Schema` exports. Long names with redundant `Schema` suffix; the `z.ZodType` type annotation already says they're Zod schemas. Plus three of them (`unmarshalGetEffectivePermissions_ResponseSchema`, `unmarshalGetPermissions_ResponseSchema`, `unmarshalUpdatePermissions_ResponseSchema`) embed proto underscores and require eslint-disable directives (lines 238, 252, 305). +- **Category:** 8 (redundant `Schema` suffix), 4 (underscores), 20 (type-suffix tautology). +- **Suggested name:** Drop `Schema` suffix → `unmarshalEffectivePrivilege`, `marshalUpdatePermissions`, etc. +- **Rationale:** Naming consistency with the rest of the SDK; the suffix carries no info beyond the type signature. + +### 33. `unmarshalGetEffectivePermissions_ResponseSchema` — `src/v1/model.ts:239` +- **Why weird:** 49-character name; combines #32 (`Schema` suffix), #4 (proto underscore), and the verbose `GetEffectivePermissions` (#3). Requires eslint-disable. +- **Category:** 4, 7, 8. +- **Suggested name:** `unmarshalEffectivePermissionsResponse` (cascading from #4 and #32). +- **Rationale:** Cascades. + +### 34. `unmarshalGetPermissions_ResponseSchema` — `src/v1/model.ts:253` +- **Why weird:** Same as #33. +- **Category:** 4, 7, 8. +- **Suggested name:** `unmarshalPermissionsResponse`. +- **Rationale:** Cascades. + +### 35. `unmarshalUpdatePermissions_ResponseSchema` — `src/v1/model.ts:306` +- **Why weird:** Same as #33. +- **Category:** 4, 7, 8. +- **Suggested name:** `unmarshalUpdatePermissionsResponse`. +- **Rationale:** Cascades. + +### 36. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:44` +- **Why weird:** `Segment` is a generic word; without the doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Cross-package consistency. + +### 37. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append`). Dead-looking export. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Remove if generator default. +- **Rationale:** Generator emits the same helper into every package even when unused. + +### 38. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / Web Streams. The function reads a `ReadableStream` into a single buffer. +- **Category:** 1 (vague), 14 (Go-style: `io.ReadAll` is a Go idiom). +- **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. +- **Rationale:** Cross-package consistency. + +### 39. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same file. The model file uses `marshal*` / `unmarshal*` consistently — `parseResponse` is the odd one out. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. +- **Rationale:** Mirroring helps readers map TS→wire/wire→TS at a glance. + +### 40. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. +- **Category:** 1 (vague suffix), 17 (inconsistent). +- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). +- **Rationale:** Distinguish internal context bags from user-facing option structs. + +--- + +## Observations + +### 41. Five client methods cover effectively two operations +`getPermissions`, `getEffectivePermissions`, `listPrivilegeAssignments`, `listEffectivePrivilegeAssignments`, `updatePermissions`. The two Get-style methods are documented as soon-to-be-deprecated mirrors of the List-style methods, leaving the steady-state SDK with three operations: list, list-effective, update. The 5-method surface is a transitional artefact. +- **Category:** 12 (duplicate concept), Observation. + +### 42. Wire vs. TS field-name churn +TS `securableFullName` → wire `securable_full_name`; TS `securableType` → wire `securable_type`; TS `principalId` → wire `principal_id`; TS `pageSize` → wire `page_size`. All consistent snake_case ↔ camelCase translations — flagged only because the `marshalPermissionsChangeSchema` (line 317) marshals `principalId` to `principal_id` but the doc-comment on `PermissionsChange` refers to it as "principal_id" (line 180), which mixes wire-format vocabulary into the TS surface doc. +- **Category:** Observation, 6 (misleading docs). + +### 43. `Client` constructor: `Host is required.` — `src/v1/client.ts:60` +Error message thrown but no client name in the message. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. +- **Category:** Observation. + +### 44. `GetEffectivePermissions.maxResults` doc — `src/v1/model.ts:35-46` +The doc-comment is 12 lines of conditional behaviour ("If not set / If set to lesser than 0 / equal to 0 / lesser than 150 ...") — appropriate detail but copy-pasted verbatim into `GetPermissions.maxResults` (lines 71-82) and partially into `ListPrivilegeAssignmentsRequest.pageSize` (lines 139-150). Three near-identical 10+ line blocks. Naming-adjacent — flag for doc DRY-ness. +- **Category:** Observation. + +### 45. `unmarshal*Schema` and `marshal*Schema` exported but only used internally +All schemas are re-imported by `client.ts` from the same `./model` module; they aren't re-exported from `index.ts` (lines 7-22 list only the types). So the schemas are part of the package's effective surface (importable as `'./model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). Naming-adjacent. +- **Category:** Observation, 11 (effectively-internal exports). diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md new file mode 100644 index 00000000..7e0ecf8f --- /dev/null +++ b/.agent/naming-audit/iam.md @@ -0,0 +1,874 @@ +# Naming Audit: `@databricks/sdk-iam` (v2) + +**Package:** `iam` (`packages/iam/src/v2/`) +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts` +**Domain:** Databricks IAM — account-level users, groups, service principals, +group memberships, and workspace assignment / access details. Includes +account-access identity rules (DENY-list for principals from a customer IdP) +and resolve-by-external-id flows that bridge the customer IdP to Databricks. + +## Summary + +| Severity | Count | +| -------- | ----- | +| High | 18 | +| Medium | 22 | +| Low | 16 | +| Observation | 9 | +| **Total** | **65** | + +Three dominant themes emerged. **First, the package ships every method, +request, and a handful of enums in two parallel forms — `*` and `*Proxy` — +that differ only in whether `accountId` is supplied by the caller or by the +URL routing layer.** Roughly 40% of the public type surface is mechanical +duplication (44 request types collapse to about 22 unique shapes). **Second, +the package leaks proto conventions deep into TypeScript:** every enum has a +`_UNSPECIFIED` zero value, two enums use Proto-style nested names with +underscores (`WorkspaceAccessDetail_AccessType`, `User_Name`), and 31 of 38 +JSDoc blocks contain literal `` markup. **Third, naming is +inconsistent across status fields, parent-account fields, and the `Detail` +suffix** — `accountUserStatus`, `accountSpStatus`, `workspaceIdentityStatus`, +and `status` all describe the same `State` enum across types; `accountId` is +documented as "parent account ID for X" inconsistently; and the `Detail` +suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / +`WorkspaceIdentityDetail` adds no information beyond Java-RPC habit. + +--- + +## High-severity findings + +### H1. Every method exists in `*` + `*Proxy` variants — duplicate concept across the public API +- **File:** `client.ts:309-543, 666-738, 814-870, 872-946, 948-1042, 1044-1172, 1174-1242, 1244-1324, 1326-1414, 1416-1462, 1464-1534, 1536-1592, 1594-1668, 1819-1934, 1936-1984, 1986-2058, 2060-2150` +- **Category:** 12, 7, 14 (duplicate concepts; verbose; Go/Java-style RPC pairs) +- **Issue:** 17 endpoints are duplicated as `X` + `XProxy` pairs: + `createGroup` + `createGroupProxy`, `deleteGroup` + `deleteGroupProxy`, + `getGroup` + `getGroupProxy`, `listGroups` + `listGroupsProxy`, + `updateGroup` + `updateGroupProxy`, `resolveGroup` + `resolveGroupProxy`, + same for `User`, `ServicePrincipal`, `DirectGroupMember`, + `TransitiveParentGroups`, `WorkspaceAssignmentDetail`. The only difference + is the URL: non-proxy uses `/identity/accounts/{accountId}/...`, proxy uses + `/identity/...` (workspace-rooted, accountId resolved server-side). The + request types are the same minus the `accountId` field. A consumer must + decide between two methods for every operation, doubling the API surface + and the request-type count (44 → 22 unique shapes). +- **Suggestion:** Collapse to one method per operation. Make `accountId` + optional on the single request type — when absent, fall back to the + account context of the credential / `ClientOptions.accountId` (the client + already does this on line 165 + 314, 372, 462, etc.). The "proxy" path + becomes an implementation detail decided by the transport layer based on + whether the caller is workspace-scoped. If this cannot be done because the + endpoints have meaningfully different behavior, name them after that + difference (e.g. `createGroupForAccount` vs `createGroupInCurrentWorkspace`) + rather than the proto/Go `Proxy` suffix that surfaces routing. +- **Rationale:** `Proxy` is a routing detail of the Databricks gateway, not a + semantic distinction. It is the strongest source of confusion in the + package. Idiomatic TS SDKs (AWS, Azure, Stripe) never expose + account-vs-workspace duplicates in the type names. + +### H2. `Entitlement` — top-level enum name is too generic +- **File:** `model.ts:13-21` +- **Category:** 1, 18 (vague/generic; long enum values) +- **Issue:** The exported enum `Entitlement` carries values like + `WORKSPACE_ACCESS`, `WORKSPACE_CONSUME`, `DATABRICKS_SQL_ACCESS`, + `WORKSPACE_ADMIN`, `ALLOW_CLUSTER_CREATE`, `ALLOW_INSTANCE_POOL_CREATE`. + These are workspace-scoped entitlements, not generic "entitlements", and + the enum has no JSDoc. The name does not disclose scope; a developer + reading `entitlements?: Entitlement[]` on a workspace assignment cannot + tell whether these are workspace entitlements, account entitlements, or + something more abstract. The values mix permission verbs + (`ALLOW_CLUSTER_CREATE`) with abstract access markers (`WORKSPACE_ACCESS`) + on the same enum. +- **Suggestion:** `WorkspaceEntitlement`. Add a JSDoc that distinguishes + "presence" entitlements (`WORKSPACE_ACCESS`, `WORKSPACE_ADMIN`) from + "create" entitlements (`ALLOW_CLUSTER_CREATE`, `ALLOW_INSTANCE_POOL_CREATE`). + Consider splitting into `WorkspaceRole` (admin/user/SQL access) and + `WorkspaceCreatePermission` (cluster/instance pool create) — they are + conceptually different and gated differently in the platform. +- **Rationale:** `Entitlement` is used on exactly one field + (`WorkspaceAssignmentDetail.entitlements`) and never elsewhere, so it is + effectively a workspace entitlement enum already. + +### H3. `State` — top-level enum name is too generic +- **File:** `model.ts:41-48` +- **Category:** 1, 2 (vague/generic; redundant enum prefix) +- **Issue:** `State` with values `STATE_UNSPECIFIED`, `ACTIVE`, `INACTIVE` is + used as the status of users, service principals, and identities in + workspaces and accounts. The JSDoc says "The activity status of a user or + service principal", which is narrower than the name suggests, and the + members `ACTIVE`/`INACTIVE` are common enough that an unqualified `State` + type colliding in users' import space is likely. The field name also + varies per usage: `accountUserStatus`, `accountSpStatus`, + `workspaceIdentityStatus`, plain `status` — four different field names for + the same enum domain across five types. +- **Suggestion:** Rename the enum to `ActivityStatus` (or `PrincipalStatus`). + Standardize the field name to `status` everywhere. Drop the + `STATE_UNSPECIFIED` value (see H10). +- **Rationale:** A 3-letter enum with 2 values and the name `State` is a + textbook example of a name that says nothing about the domain. JSDoc-only + context is not enough. + +### H4. `PrincipalType` enum values redundantly prefix `PRINCIPAL_TYPE_` +- **File:** `model.ts:33-38` +- **Category:** 2, 18 (redundant enum prefix; long enum values) +- **Issue:** Values are `PRINCIPAL_TYPE_UNSPECIFIED`, `USER`, + `SERVICE_PRINCIPAL`, `GROUP`. Only the UNSPECIFIED zero value carries the + prefix; the others are bare. This is the proto convention bleeding into TS + for one value while the others are clean. At a usage site + `req.principalType = PrincipalType.PRINCIPAL_TYPE_UNSPECIFIED` reads as + type-suffix tautology, while `PrincipalType.USER` reads cleanly. The two + styles in one enum are inconsistent. +- **Suggestion:** Drop the `PRINCIPAL_TYPE_` prefix from UNSPECIFIED (or + drop the whole UNSPECIFIED member — see H10). Standardize on + `PrincipalType.USER` / `.SERVICE_PRINCIPAL` / `.GROUP`. +- **Rationale:** TypeScript already namespaces values under the enum type. + Repeating the enum name in one member only is worse than either + consistently prefixing or consistently bare. + +### H5. `WorkspaceAccessDetail_AccessType` and `WorkspaceIdentityDetail_AssignmentType` use proto-style underscored names +- **File:** `model.ts:67-74, 78-85`, `index.ts:13-14` +- **Category:** 4, 14 (underscore in TS identifier; Go/Java/proto-style) +- **Issue:** Two enums with proto-style nested names use underscore + separators in the TS identifier: + `WorkspaceAccessDetail_AccessType`, `WorkspaceIdentityDetail_AssignmentType`. + Both require a `// eslint-disable-next-line @typescript-eslint/naming-convention` + comment to compile, which signals the convention is wrong. They are also + re-exported by name from `index.ts`. The two enums also have identical + value sets — `ACCESS_TYPE_UNSPECIFIED`/`ASSIGNMENT_TYPE_UNSPECIFIED`, + `DIRECT`, `INDIRECT` — and identical JSDoc semantics ("direct" = + principal is assigned, "indirect" = via group). They are the same enum + conceptually. +- **Suggestion:** Flatten and unify. `type AssignmentMode = 'DIRECT' | 'INDIRECT'` + (a union type or a single enum `AssignmentMode`). Use it for both + `WorkspaceAccessDetail.accessType` and + `WorkspaceIdentityDetail.assignmentType` (and rename the fields to + `mode` or both to `assignmentMode`). +- **Rationale:** Two enums with the same shape and the same meaning, both + spelled with proto-style underscores, is duplication on top of + convention-violation. + +### H6. `User_Name` nested type uses proto-style underscored name +- **File:** `model.ts:961-964`, `index.ts:18` (exported as `User_Name`) +- **Category:** 4, 14 (underscore in TS identifier; proto-style) +- **Issue:** `User_Name` is a nested message type carrying `givenName` and + `familyName`. The name violates TS conventions (requires + `// eslint-disable-next-line` to compile). The corresponding + `unmarshalUser_NameSchema` and `user_NameFieldMaskSchema` propagate the + same underscored identifier downward through the file. +- **Suggestion:** Rename to `UserName` or, better, `PersonName` (since + `userName` is overloaded with `username` two lines up — see H7). Even + inlining `givenName?: string; familyName?: string` onto `User` would be + cleaner since the nested type has no other use. +- **Rationale:** Proto nested-message names should be flattened in TS. The + underscore is the strongest visual cue that the generator did not idiomatize. + +### H7. `User.username` vs `User.name: User_Name` — name field collision +- **File:** `model.ts:946-958, 961-964` +- **Category:** 6, 10 (misleading; reserved-word-style collision) +- **Issue:** `User` has both `username` (string, email-like login identifier + per the JSDoc) and `name` (a `User_Name` struct with `givenName`/`familyName`). + In English `name` and `username` are near-synonyms and users routinely + conflate them. Worse, `User_Name` is a separate type whose name is itself + `Name`. A developer auto-completing `user.` sees two `*name*` fields with + no hint at the difference. +- **Suggestion:** Rename `User.name` to `User.fullName` (or `personName`, + matching the suggested type rename in H6). Rename `User.username` to + `User.email` if the value is always an email (the JSDoc says + "Username/email of the user"), or `User.loginName` otherwise. +- **Rationale:** Disambiguates two semantically distinct identifiers. + +### H8. `accountSpStatus` field uses cryptic abbreviation `Sp` +- **File:** `model.ts:818` +- **Category:** 5, 6 (cryptic abbreviation; misleading) +- **Issue:** `ServicePrincipal.accountSpStatus?: State`. `Sp` is a Databricks + internal shorthand for "service principal". Externally it reads as + "Spanish" or simply opaque. The parallel field on `User` is + `accountUserStatus`, which is spelled out, and on `WorkspaceIdentityDetail` + it is `workspaceIdentityStatus`. Three field names for the same `State` + enum across three sibling types is inconsistent (also category 17). +- **Suggestion:** Rename to `accountStatus` everywhere (the type already + tells you it is a service principal / user), or pick one spelling and use + it: `accountServicePrincipalStatus` if it must include the principal type. +- **Rationale:** Abbreviation `Sp` is opaque to external developers and + inconsistent with the spelled-out `User` and `Identity` siblings. + +### H9. `WorkspaceAccessDetail`, `WorkspaceAssignmentDetail`, `WorkspaceIdentityDetail` — three overlapping "Detail" types +- **File:** `model.ts:967-1004`, plus all 17 method types they appear in +- **Category:** 1, 12, 7 (vague generic suffix; duplicate concept; verbose) +- **Issue:** Three top-level types with the `Detail` suffix model overlapping + shapes of "what a principal has in a workspace": + - `WorkspaceAccessDetail`: principal, workspace, account, principalType, accessType, status, permissions. + - `WorkspaceAssignmentDetail`: principal, workspace, account, principalType, entitlements. + - `WorkspaceIdentityDetail`: principal, principalType, workspaceIdentityStatus, assignmentType. + + All three identify the same triple `(accountId, workspaceId, principalId)`. + `Detail` is a meaningless suffix — every type in a data model is a "detail". + The differences are: permissions (Access), entitlements (Assignment), status + + assignment mode (Identity). A new reader cannot tell from the names which + type carries which fields. +- **Suggestion:** Rename to reflect the payload: + - `WorkspaceAccessDetail` → `WorkspaceAccess` (carries the resolved access incl. permissions). + - `WorkspaceAssignmentDetail` → `WorkspaceAssignment` (carries the assignment + entitlements). + - `WorkspaceIdentityDetail` → `WorkspaceIdentity` (carries identity status). + Or merge into one type with a discriminator if the platform allows it. +- **Rationale:** `Detail` is fluff. The 17 methods named after these types + (`getWorkspaceAccessDetail`, `listWorkspaceAssignmentDetails`, + `updateWorkspaceIdentityDetail`, …) inherit the noise. + +### H10. Every enum has a `_UNSPECIFIED` zero value +- **File:** `model.ts:9, 14, 25, 34, 43, 52, 59, 69, 80` +- **Category:** 2, 18 (redundant enum prefix; long enum values) +- **Issue:** Nine of nine enums in the package have an `UNSPECIFIED` member + (`ACCOUNT_ACCESS_RULE_ACTION_UNSPECIFIED`, `ENTITLEMENT_UNSPECIFIED`, + `GROUP_MEMBERSHIP_SOURCE_UNSPECIFIED`, `PRINCIPAL_TYPE_UNSPECIFIED`, + `STATE_UNSPECIFIED`, `WORKSPACE_ACCESS_DETAIL_VIEW_UNSPECIFIED`, + `WORKSPACE_PERMISSION_UNSPECIFIED`, `ACCESS_TYPE_UNSPECIFIED`, + `ASSIGNMENT_TYPE_UNSPECIFIED`). All are 30–45 characters long. They exist + only because the upstream proto requires a zero value; in TypeScript the + same semantics are expressed by an optional field. None of the JSDoc + documents what an SDK consumer should ever do with `UNSPECIFIED`. +- **Suggestion:** Remove all `UNSPECIFIED` members. Fields that may carry an + enum or be absent are already typed `enum | undefined`. If round-tripping + the wire value matters, accept the string at the parser level but never + surface it as a named enum member. +- **Rationale:** This is the single highest-impact reduction in the package. + 9 enum members removed × every enum value enumeration in user code. + +### H11. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly +- **File:** `model.ts:51-55` +- **Category:** 1, 14 (vague; Google/proto-style) +- **Issue:** Values are `WORKSPACE_ACCESS_DETAIL_VIEW_UNSPECIFIED`, `BASIC`, + `FULL`. The type is a [Google AIP-157 + view-mask](https://google.aip.dev/157), but the name doesn't surface that + and the values look generic. It's used as `view?: + WorkspaceAccessDetailView` on `GetWorkspaceAccessDetailRequest` / `Local` + variants, but a developer cannot guess from the field name `view` that it + controls response shape. +- **Suggestion:** `enum FieldView { BASIC = 'BASIC', FULL = 'FULL' }`, + reusable across the SDK. Or rename to `WorkspaceAccessView` and document + what each enum value includes/excludes. +- **Rationale:** `Detail` in the name is the same `Detail` flagged in H9 and + carries no extra meaning. + +### H12. `internalId` vs `principalId` vs `groupId` — three overlapping ID names for "the Databricks-internal numeric ID" +- **File:** `model.ts:122, 226, 228, 244, 252, 260, 271, 285, 296, 326, 329, 344, 353, 386, 407, 412, 423, 432, 442, 448, 583, 597, 833, 845, 855, 867, 884, 903` +- **Category:** 6, 19 (misleading; underspecified ID) +- **Issue:** Same numeric ID concept appears under three different field + names depending on context: + - `Group.internalId`, `User.internalId`, `ServicePrincipal.internalId` (resource-of-itself). + - `DirectGroupMember.principalId`, `ListTransitiveParentGroupsRequest.principalId`, `WorkspaceAccessDetail.principalId`, etc. (resource-as-member). + - `CreateDirectGroupMemberRequest.groupId` (resource-as-parent). + + All three are `number` types referring to "the Databricks-internal numeric + ID of a principal/group". A `Group` carries `internalId`, but in + `WorkspaceAccessDetail` the same group's numeric ID is `principalId`. In + `DirectGroupMember`, `principalId` may be a user, SP, or group — the + member-side is principal, but in `ListDirectGroupMembers` the + `groupId` is also a principal's ID acting as parent. +- **Suggestion:** Pick one name and stick to it. `internalId` is fine on the + resource itself; `InternalId` for the foreign-key form (e.g. + `principalInternalId`, `groupInternalId`). Document the relationship in the + type-level JSDoc. +- **Rationale:** Today a developer reading the SDK has to keep a mental map + of which name refers to what; the wire is consistent (`principal_id`, + `group_id`, `internal_id`), so the TS field name choices are real. + +### H13. `principalType: PrincipalType` — type-suffix tautology pattern +- **File:** `model.ts:99, 304, 974, 990, 999` +- **Category:** 20 (type-suffix tautology) +- **Issue:** The field `principalType: PrincipalType | undefined` appears on + five types. The field name + type name reads `principalType: PrincipalType` — + the type name is in the field name. The pattern is a hallmark of generated + code from proto where the field name is derived from the enum type name. +- **Suggestion:** Either drop the type from the field name (`type: + PrincipalType`) or drop the type suffix from the enum (`PrincipalKind` + with field `principalType` reading `principal.type = "USER"` works, but + `principal: PrincipalKind` is even cleaner). +- **Rationale:** Tautology adds visual noise without adding meaning. + +### H14. `Group.groupName` — same kind of tautology +- **File:** `model.ts:461` +- **Category:** 20 (type-suffix tautology) +- **Issue:** `Group.groupName` reads `group.groupName`. The `group` prefix is + redundant inside the `Group` type. The JSDoc says "Display name of the + group" but the field is not called `displayName` (compare to + `User.username`, `ServicePrincipal.displayName`, + `DirectGroupMember.displayName`, `AccountAccessIdentityRule.displayName`). +- **Suggestion:** Rename to `displayName` to match the four sibling types in + the same file. +- **Rationale:** Cross-type consistency is broken for no API reason; the + wire form is `group_name` but the TS field name need not echo it. The + field is also used as `displayName` in JSDoc. + +### H15. `ServicePrincipal.internalId` doc says `Internal service principal ID of the service principal` — tautology + comment problem +- **File:** `model.ts:809-810` +- **Category:** 20, 6 (tautology; misleading) +- **Issue:** The JSDoc on `ServicePrincipal.internalId` reads "Internal + service principal ID of the service principal in ." The + service-principal-of-the-service-principal phrasing is awkward; the same + pattern appears on `Group.internalId` ("Internal group ID of the group in + .") and `User.internalId` ("Internal userId of the user"). + The `User` doc also has a typo: `userId` is one word, not "user id". +- **Suggestion:** Standardize to "Internal numeric ID assigned by Databricks." +- **Rationale:** Three sibling doc strings should not each repeat the + resource name inside themselves. + +### H16. `AccountAccessIdentityRule.name` is a URL path, not a name +- **File:** `model.ts:100-104` +- **Category:** 6, 15, 16, 19 (misleading; generic field losing meaning; field contradicting domain; underspecified) +- **Issue:** `name` is documented as + `accounts/{account_id}/account-access-identity-rules/{external_principal_id}` + — a Google AIP-122 resource path, not a human-readable name. There is a + separate `displayName` field on the same type for the human-readable form. + `name` is `string` with no type-level disclosure. +- **Suggestion:** Rename to `resourceName` (or `path` / `resourcePath`). + Encode the format as a template literal type: `\`accounts/${string}/account-access-identity-rules/${string}\``. +- **Rationale:** Half the IAM-API integration bugs are wrong-format resource + paths; the type system can encode this. + +### H17. `Group.externalId` doc capitalization `ExternalId` (sentence-case identifier name) +- **File:** `model.ts:459, 952, 828, 811` +- **Category:** 3, 14 (acronym casing; Go-style) +- **Issue:** The JSDoc on `Group.externalId`, `User.externalId`, + `ServicePrincipal.externalId`, and `TransitiveParentGroup.externalId` begins + with the literal `ExternalId of the X in the customer's IdP.` — capitalized + identifier name as the first word, not English. The same pattern bleeds + through to the Go-style sentence comment. Should be either "External ID + of …" (English) or use the TS field name as code (`externalId`) in + backticks. +- **Suggestion:** Rewrite as "External ID of the {resource} in the + customer's identity provider." consistently across all four types. +- **Rationale:** A small but persistent rendering issue across the type + surface. + +### H18. `parent` field name on rule endpoints — Google AIP convention leaks into TS +- **File:** `model.ts:113, 219, 318, 470` +- **Category:** 1, 14, 19 (vague/generic; Google-style; underspecified ID) +- **Issue:** `CreateAccountAccessIdentityRuleRequest.parent`, + `DeleteAccountAccessIdentityRuleRequest.parent`, + `GetAccountAccessIdentityRuleRequest.parent`, + `ListAccountAccessIdentityRulesRequest.parent` all carry a field literally + named `parent` with the documented format `accounts/{account_id}`. This is + [Google AIP-132](https://google.aip.dev/132) convention. In TypeScript, + `parent` is opaque — a developer cannot guess from the field that it must + be `accounts/`. +- **Suggestion:** Rename to `accountResourceName` or `accountPath`, or even + just `account: string` typed as a template literal + `\`accounts/${string}\``. Surface the structure. +- **Rationale:** `parent` is meaningless without reading the JSDoc; the + template literal type makes this discoverable at the call site. + +--- + +## Medium-severity findings + +### M1. `CreateWorkspaceAssignmentDetailProxyRequest` — 41-character name +- **File:** `model.ts:197`, similarly `DeleteWorkspaceAssignmentDetailProxyRequest`, `UpdateWorkspaceAssignmentDetailProxyRequest` +- **Category:** 7 (overly verbose) +- **Issue:** Five of the request type names are 41+ characters: + `CreateWorkspaceAssignmentDetailProxyRequest` (42 chars), + `DeleteWorkspaceAssignmentDetailProxyRequest` (42), + `UpdateWorkspaceAssignmentDetailProxyRequest` (42), + `ListWorkspaceAssignmentDetailsProxyRequest` (42), + `GetWorkspaceAssignmentDetailProxyRequest` (40). Plus the imports list in + `client.ts` repeats them, doubling the noise. +- **Suggestion:** Once H1 collapses the proxy duplication and H9 drops + `Detail`, these become `CreateWorkspaceAssignmentRequest` etc. — about 30 + chars each. +- **Rationale:** Length itself is not a sin, but `42 chars × 2 × + every-occurrence` is friction. + +### M2. `Local` suffix on `GetWorkspaceAccessDetailLocalRequest` +- **File:** `model.ts:411, 677`, `client.ts:1715, 1783`, `index.ts:51, 74` +- **Category:** 1, 14 (vague; Java/Go-style) +- **Issue:** `GetWorkspaceAccessDetailLocalRequest` and + `ListWorkspaceAccessDetailsLocalRequest` use a `Local` suffix that is not + defined anywhere in the public types. From `client.ts:1719` the + "local" version omits `accountId`/`workspaceId` from the URL — it is + another proxy/routing variant. Why is this one called `Local` while the + 17 others use `Proxy`? +- **Suggestion:** Make it consistent. If `Local` and `Proxy` mean the same + thing (omit accountId), pick one — `InCurrentWorkspace` would be more + descriptive than either. If they differ semantically, document the + difference. +- **Rationale:** Two suffixes for the same routing-variant idea is the + worst possible outcome. + +### M3. `applicationId` on `ServicePrincipal` — third ID on the same type +- **File:** `model.ts:813-814` +- **Category:** 19 (underspecified ID) +- **Issue:** `ServicePrincipal` already has `accountId`, `internalId`, + `externalId`, and now `applicationId`. The doc says "Application ID of the + service principal." but does not say where this comes from (AAD app + registration? Databricks-issued?). It is a string and the doc gives no + format. +- **Suggestion:** Document the source: "Azure AD application ID (UUID) + identifying the service principal at the identity provider." Plus add a + format hint if not arbitrary string. +- **Rationale:** Four IDs on one struct is a lot; each one needs to be + obviously distinct in purpose. + +### M4. `GroupMembershipSource` value `IDENTITY_PROVIDER` is fine but the enum mixes scopes +- **File:** `model.ts:24-30` +- **Category:** 1, 6 (vague; misleading) +- **Issue:** Values `INTERNAL` and `IDENTITY_PROVIDER`. `INTERNAL` is the + inverse of `IDENTITY_PROVIDER`, which is fine, but `INTERNAL` is a very + generic word — internal to what? Compare to common phrasing + `MANUAL`/`SCIM`, or `LOCAL`/`IDP`. JSDoc clarifies but the type alone + doesn't. +- **Suggestion:** `MEMBERSHIP_SOURCE_LOCAL` / `MEMBERSHIP_SOURCE_IDP`, or + match the field rename — `source: 'LOCAL' | 'IDP'`. +- **Rationale:** "Internal" is the kind of word that everyone reads + differently. + +### M5. `WorkspacePermission.USER_PERMISSION` and `ADMIN_PERMISSION` — redundant suffix +- **File:** `model.ts:60-62` +- **Category:** 2, 8 (redundant prefix; redundant suffix) +- **Issue:** `WorkspacePermission.USER_PERMISSION` reads + `WorkspacePermission.USER_PERMISSION` — both "permission" and the enum + type carry "permission". A `User` is a principal kind (per `PrincipalType.USER`), + so the value collides with that meaning. The JSDoc on `USER_PERMISSION` is + "The most basic workspace permission." — it really means "non-admin + permission", not "permission belonging to users". +- **Suggestion:** `WorkspacePermission.USER` and `.ADMIN`, with JSDoc + reading "Default (non-admin) workspace access." and "Workspace admin + access." respectively. +- **Rationale:** Drops `_PERMISSION` redundancy; aligns enum members with + the `User`/`Admin` distinction the rest of the SDK uses. + +### M6. `accountAccessIdentityRule` — wrapper field repeating type name +- **File:** `model.ts:117` +- **Category:** 20 (type-suffix tautology) +- **Issue:** `CreateAccountAccessIdentityRuleRequest.accountAccessIdentityRule?: AccountAccessIdentityRule | undefined` + — the type name is the field name. Also the field is required per JSDoc + but the type marks it optional. +- **Suggestion:** Rename field to `rule` (since context is the request type + for an account-access-identity-rule). Mark non-optional in TS. +- **Rationale:** Reduces tautology and aligns required/optional with the doc. + +### M7. `directGroupMember` field repeats type name +- **File:** `model.ts:125, 135` +- **Category:** 20 (type-suffix tautology) +- **Issue:** `CreateDirectGroupMemberRequest.directGroupMember?: DirectGroupMember | undefined`. +- **Suggestion:** Rename field to `member`. +- **Rationale:** Same as M6. + +### M8. `workspaceAssignmentDetail` field repeats type name +- **File:** `model.ts:199, 209, 916, 930` +- **Category:** 20 (type-suffix tautology) +- **Issue:** `CreateWorkspaceAssignmentDetailRequest.workspaceAssignmentDetail?: WorkspaceAssignmentDetail | undefined`. +- **Suggestion:** Rename field to `assignment` (after H9 drops `Detail`, + the type is `WorkspaceAssignment` and `assignment` reads naturally). +- **Rationale:** Same as M6. + +### M9. `workspaceIdentityDetail` field repeats type name +- **File:** `model.ts:940` +- **Category:** 20 (type-suffix tautology) +- **Issue:** `UpdateWorkspaceIdentityDetailRequest.workspaceIdentityDetail?: WorkspaceIdentityDetail | undefined`. +- **Suggestion:** Rename to `identity`. +- **Rationale:** Same as M6. + +### M10. `servicePrincipal` field repeats type name +- **File:** `model.ts:156, 163, 858, 870` +- **Category:** 20 (type-suffix tautology) +- **Issue:** `CreateServicePrincipalRequest.servicePrincipal?: ServicePrincipal | undefined`. +- **Suggestion:** Rename to `principal` or `sp` (consistent with the rest + of the create/update bodies). +- **Rationale:** Same as M6. + +### M11. `Group.accountId` doc — "The parent account ID for group in " (missing article) +- **File:** `model.ts:454-455` +- **Category:** 6 (misleading via grammar) +- **Issue:** Doc reads "The parent account ID for group in " — + missing "the" before "group". Same pattern on + `TransitiveParentGroup.accountId` ("The parent account ID for group in + ") and `User.accountId` ("The accountId parent of the user in + "). Three siblings with three different phrasings of the same + thing, two with grammar issues. +- **Suggestion:** Standardize to "Databricks account ID of the parent + account." or just "Parent Databricks account ID." +- **Rationale:** Consistency + grammar; the `` template marker + also needs to go (see M13). + +### M12. `` proto template markup in 31 of 38 JSDoc blocks +- **File:** `model.ts` everywhere, e.g. `122, 140, 148, 154, 161, 175-185` +- **Category:** 14 (Go/proto-style markup leak) +- **Issue:** The literal string `` appears 31+ times across the + JSDoc comments. It is upstream template syntax meant to be replaced by + the brand at doc-generation time; in TS it renders as stray angle brackets + in IDE hover popups and TypeDoc. Examples: + - "Required. Group to be created in " + - "Internal ID of the group in ." + - "Required. ID of the principal in ." +- **Suggestion:** Strip the template markup in the generator, leaving just + "Databricks". +- **Rationale:** Public docs leaking template syntax is the most visible + proto-leak across the SDK. + +### M13. `TODO: Write description later when this method is implemented` — 26 occurrences +- **File:** `model.ts:138, 144, 152, 158, 241, 247, 255, 261, 269, 275, 342, 348, 356, 362, 522, 532, 544, 551, 562, 573, 676, 684, 696, 831, 841, 853, 863, 920` (and many more); same TODO appears 22 times in `client.ts` +- **Category:** 6 (misleading) / Observation +- **Issue:** Roughly half the request types and a large fraction of client + methods carry the placeholder JSDoc "TODO: Write description later when + this method is implemented" verbatim. Worse, the method **is** implemented + in `client.ts` — the comment is now factually wrong. +- **Suggestion:** Replace each TODO with the correct one-line description. + This is a generator-side fix. +- **Rationale:** Placeholder docs degrade developer trust. + +### M14. `parent` doc string disagreement with field name (rule endpoints) +- **File:** `model.ts:113, 219, 318, 470` +- **Category:** 6 (misleading) +- **Issue:** The four rule-endpoint requests use `parent` as a field name + but the JSDoc says "The account under which to create the rule." / "The + account for which to ..." — no mention of "parent". A consumer reading + IntelliSense gets `parent: string` plus "The account ...", which is + confusing. +- **Suggestion:** Make the JSDoc echo the AIP convention or rename per H18. +- **Rationale:** Field and docstring should agree on naming. + +### M15. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` +- **File:** `model.ts:921` +- **Category:** 6 (misleading) +- **Issue:** The doc on `UpdateWorkspaceAssignmentDetailRequest` is literally + "TBD since the only updatable field is permissions" — internal TODO + shipped to public surface. Also factually wrong (entitlements, not + permissions, per the type). +- **Suggestion:** Replace with the real description. +- **Rationale:** Same as M14. + +### M16. `resolveByExternalId` URL segment uses camelCase +- **File:** `client.ts:822, 851, 1182, 1217, 1545, 1574` +- **Category:** 14, 3 (Go-style; casing) +- **Issue:** The URL paths use `/resolveByExternalId` in camelCase, while + every other path segment in the same file uses kebab-case + (`/account-access-identity-rules`, `/direct-members`, + `/transitive-parent-groups`). The URLs are server-defined, so this is not + a naming issue the SDK can fix, but it is worth noting because the + inconsistency is visible in the SDK's debug logs. +- **Suggestion:** Server-side fix (out of scope), but flag to the API team. +- **Rationale:** Not the SDK's bug, but reflects an upstream inconsistency. + +### M17. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields +- **File:** `model.ts:978-979, 991` +- **Category:** 12, 6 (duplicate concepts; misleading) +- **Issue:** `WorkspaceAccessDetail.permissions` (USER_PERMISSION / + ADMIN_PERMISSION) and `WorkspaceAssignmentDetail.entitlements` + (WORKSPACE_ACCESS, WORKSPACE_ADMIN, …) both encode workspace-level + capabilities of the same principal. Yet they appear on two different + types using two different enum types. Is `WORKSPACE_ADMIN` an + `Entitlement` or a `WorkspacePermission`? +- **Suggestion:** Reconcile the two. If they are different concepts (e.g., + "access scope" vs "assignable capability"), document the distinction in + both JSDoc blocks. If they are the same, merge. +- **Rationale:** This is the kind of overlap that produces support tickets. + +### M18. `nextPageToken` doc comment is repeated 9 times verbatim +- **File:** `model.ts:483, 519, 548, 577, 613, 673, 700, 727` +- **Category:** Observation (duplication) +- **Issue:** Nine identical JSDoc strings: "A token, which can be sent as + page_token to retrieve the next page. If this field is omitted, there are + no subsequent pages." The wire form is `next_page_token`; the TS field is + `nextPageToken` (which the doc does not mention). +- **Suggestion:** Either factor into a single doc snippet (TypeDoc + `@inheritDoc`) or accept the repetition but fix `page_token` -> `pageToken` + in the JSDoc. +- **Rationale:** Field names in JSDoc should match the TS surface. + +### M19. `ListGroupsRequest.filter` JSDoc — "filtering groups by group name or external id" +- **File:** `model.ts:529, 540` +- **Category:** 6 (misleading) +- **Issue:** Doc says "group name", but the actual field name is `groupName` + on `Group` (per H14) and the JSON wire is `group_name`. The SCIM-style + filter syntax (`groupName eq "engineering"`) is not documented. A consumer + must guess. +- **Suggestion:** Document the filter language with one example. +- **Rationale:** API ergonomics — filter syntax is non-discoverable. + +### M20. `ListServicePrincipalsProxyRequest` doc — "The maximum number of SPs to return" +- **File:** `model.ts:553` +- **Category:** 5, 6 (cryptic abbreviation; misleading) +- **Issue:** Uses "SPs" abbreviation; the proxy variant is also documented + with the abbreviation while the non-proxy variant uses the full + "service principals" (model.ts:565). Two siblings, two phrasings. +- **Suggestion:** Always "service principals" in JSDoc. +- **Rationale:** Consistency + clarity for non-Databricks readers. + +### M21. `resolveByExternalId` method naming +- **File:** `client.ts:818, 1178, 1541`, `model.ts:734, 759, 784` +- **Category:** 17 (verb inconsistency) +- **Issue:** `resolveGroup`, `resolveUser`, `resolveServicePrincipal`. These + read like "resolve a group" (e.g. resolve a reference), but the actual + semantics is "resolve-or-create using external ID". The method name does + not surface the "or-create" side-effect. The URL hints at it + (`resolveByExternalId`) but the TS method doesn't. +- **Suggestion:** Rename to `resolveByExternalId(req)` taking a discriminated + request type, or `getOrCreateByExternalId`. Document the create-on-miss + semantic prominently. +- **Rationale:** Method names should not hide write side-effects. + +### M22. `ListWorkspaceAccessDetailsLocalRequest` paginates but has no filter — asymmetric with `ListWorkspaceAccessDetailsRequest` +- **File:** `model.ts:677-694` +- **Category:** 6 (misleading) +- **Issue:** `ListWorkspaceAccessDetailsLocalRequest` has `pageSize` + + `pageToken` but no `filter`. The non-local variant also has no `filter`, + but every other `List*` request in the file does. The "Local" variant + description is also the placeholder "TODO: Write description later" with + zero documentation of what it lists. +- **Suggestion:** Document explicitly; add `filter` if the server supports + it on the local route; document the difference between the two list + endpoints. +- **Rationale:** API completeness. + +--- + +## Low-severity findings + +### L1. `accountId` field documented inconsistently across types +- **File:** `model.ts:131, 191, 233, 277, 405, 455, 502, 535, 595, 661, 745, 770, 795, 824, 902, 947, 988` +- **Category:** Observation, 6 (misleading) +- **Issue:** ~20 different phrasings of the same `accountId` field's JSDoc: + - "The account ID for which the group membership is being created." + - "The account ID for which the group is being deleted." + - "Required. The parent account ID for which the workspace access details are being requested." + - "The accountId parent of the user in ." +- **Suggestion:** One canonical phrasing for the request-level field + ("Databricks account ID. Falls back to ClientOptions.accountId if omitted.") + and one for the resource-level field ("Parent Databricks account ID."). +- **Rationale:** Same field, ~17 different doc strings. + +### L2. `groupId` is `number` (Databricks internal) but `accountId` is `string` (UUID) — type-inconsistency for IDs +- **File:** `model.ts:123, 132` and others +- **Category:** 19 (underspecified ID) +- **Issue:** Databricks-internal IDs are `number`, account IDs are `string` + UUIDs. The convention is consistent across the file, but a developer + reading just one type cannot tell which to expect. +- **Suggestion:** Brand the types: `type AccountId = string & { readonly __brand: 'AccountId' }`, + `type PrincipalInternalId = number & { readonly __brand: 'PrincipalInternalId' }`. +- **Rationale:** Type-system disambiguation; out-of-scope for a 1:1 port but + worth noting for any future hardening. + +### L3. `ResolveGroupRequest` vs `ResolveGroupResponse` symmetry +- **File:** `model.ts:743-753` +- **Category:** Observation +- **Issue:** `ResolveGroupRequest` carries `accountId` + `externalId`, but + the proxy variant `ResolveGroupProxyRequest` carries only `externalId`. + The `Response` is the same. This is the H1 pattern surfacing again. +- **Suggestion:** Collapse per H1. +- **Rationale:** Pattern, not a new finding. + +### L4. `Group.externalId` field name vs `Group.accountId` field name — neither match wire snake_case nor the legacy SCIM camelCase +- **File:** `model.ts:459, 947` +- **Category:** Observation +- **Issue:** SCIM API (the legacy Databricks IAM API) uses `externalId` + (camelCase) on the wire; the new IAM API uses `external_id` (snake_case). + This SDK uses `externalId` in TS and `external_id` on the wire. The + pattern is correct and consistent — flagging only because anyone migrating + from SCIM may be confused. +- **Suggestion:** None; documentation for migrators if not already present. +- **Rationale:** Migration-friendly note. + +### L5. `pageSize` JSDoc varies — "The maximum number of X" vs "Optional. The maximum number of X" +- **File:** `model.ts:471, 491, 524, 552, 600, 635, 678, 690, 705, 717, 762` +- **Category:** 6, Observation (misleading) +- **Issue:** Some `pageSize` docstrings start with "Optional.", some don't. + Some specify the default ("If not provided, defaults to 1000"), some + don't. The field is `optional` in TS already — the "Optional." prefix is + redundant. +- **Suggestion:** Standardize: drop "Optional." (the type says so), always + document the default if known. +- **Rationale:** Trivial cleanup. + +### L6. `filter` JSDoc varies +- **File:** `model.ts:476, 528, 557, 569, 638, 666` +- **Category:** Observation +- **Issue:** Three phrasings: "Optional. Allows filtering X by Y or Z.", + "Optional. Allows filtering groups by group name or external id.", + "Filter to apply to the list. Supports filtering by displayName." +- **Suggestion:** Standardize; document filter syntax (presumably SCIM-style). +- **Rationale:** Same as L5. + +### L7. `User.username` doc — "Username/email of the user" +- **File:** `model.ts:953-954` +- **Category:** 6 (misleading) +- **Issue:** Doc says "Username/email" — which is it? Slashes in JSDoc + signal ambiguity. +- **Suggestion:** Be specific: "Email address used as the user's login + identifier." +- **Rationale:** Surface the format. + +### L8. `Group.groupName` doc — "Display name of the group" +- **File:** `model.ts:460-461` +- **Category:** 6 (misleading) +- **Issue:** The field is `groupName` but the doc calls it `displayName`. + See H14. +- **Suggestion:** Rename per H14. +- **Rationale:** Consistency. + +### L9. `ServicePrincipal` JSDoc — "The details of a ServicePrincipal resource." +- **File:** `model.ts:805` +- **Category:** 6 (misleading) +- **Issue:** Type-level JSDoc says "ServicePrincipal" (camelCase) instead of + "service principal" (English). Same on `Group` ("The details of a Group + resource.") and `User` ("The details of a User resource."). Three + identical placeholder docs. +- **Suggestion:** Replace with prose. +- **Rationale:** Type-level docs should be in English. + +### L10. `applicationId` doc could disclose source +- **File:** `model.ts:813-814` +- **Category:** 19 (underspecified ID) +- **Issue:** Doc says "Application ID of the service principal." with no + format hint (UUID? AAD app ID? Databricks-internal?). +- **Suggestion:** "Application ID of the service principal at the customer's + identity provider (typically the Azure AD app registration UUID)." +- **Rationale:** Surface the format. + +### L11. `internalId` is sometimes `Internal ID` and sometimes `Internal group ID` / `Internal userId` +- **File:** `model.ts:244, 252, 271, 280, 354, 387, 407, 457, 833, 855, 884, 904, 949` +- **Category:** 6, Observation (misleading; documentation rot) +- **Issue:** `internalId` is documented at least three different ways across + request types: "Internal ID of the group in .", "Internal + group ID of the group in .", "Internal userId of the user in + ." (typo on the last — `userId` should be two words). +- **Suggestion:** Standardize to "Databricks-internal numeric ID of the X." +- **Rationale:** Documentation consistency. + +### L12. `view` field on the access-detail Get methods is `optional` but has no documented default +- **File:** `model.ts:415, 427` +- **Category:** 19 (underspecified) +- **Issue:** Doc says "Controls what fields are returned." but does not say + the default — the method-level JSDoc on the client says "BASIC by default + or FULL" (line 1677), which contradicts the optionality (the field is + `WorkspaceAccessDetailView | undefined`). +- **Suggestion:** Set default at the type level: "Defaults to `BASIC`." +- **Rationale:** Surface defaults at field level, not just method level. + +### L13. `externalPrincipalId` on rule endpoints — confusion with `externalId` +- **File:** `model.ts:92, 115, 220, 321` +- **Category:** 6 (misleading) +- **Issue:** The rule endpoints use `externalPrincipalId` (a string from the + customer's IdP); the principal types (User/Group/ServicePrincipal) use + `externalId` (also from the customer's IdP). Same concept, two names. +- **Suggestion:** Standardize to one. `externalId` is the dominant form + (4 occurrences vs the rule endpoints' 1). +- **Rationale:** Consistency. + +### L14. `IdP` capitalization — `IdP` vs `identity provider` vs `IDP` +- **File:** `model.ts:92, 459, 736, 761, 786, 952, 828` (uses "IdP") +- **Category:** 3 (acronym casing) +- **Issue:** `IdP` is the dominant form (correct for "Identity Provider"), + but the wire/JSON form is `external_principal_id`, and `GroupMembershipSource.IDENTITY_PROVIDER` + uses the spelled-out form. Three styles: `IdP`, `IDP`, `identity provider`. +- **Suggestion:** Use `IdP` in prose, spelled-out in enum values, code + identifiers as needed. +- **Rationale:** Common style — flag for review only. + +### L15. `next_page_token` snake_case in JSDoc +- **File:** `model.ts:483, 519, 548, 577, 613, 673, 700, 727` +- **Category:** 14 (Go/proto-style markup) +- **Issue:** The 9-times-repeated JSDoc references `page_token` (snake_case) + but the TS field is `pageToken` (camelCase). Internal field name leaks + into public docs. +- **Suggestion:** Change docs to say `pageToken`. +- **Rationale:** Public doc should match public field name. + +### L16. `assignmentType` on `WorkspaceIdentityDetail` vs `accessType` on `WorkspaceAccessDetail` +- **File:** `model.ts:975, 1003` +- **Category:** 12, 17 (duplicate concept; verb inconsistency) +- **Issue:** Two sibling types with similar fields: + `WorkspaceAccessDetail.accessType: WorkspaceAccessDetail_AccessType`, + `WorkspaceIdentityDetail.assignmentType: WorkspaceIdentityDetail_AssignmentType`. + Both enums have values `DIRECT`/`INDIRECT`. Field names disagree; + enum names disagree; enum values agree. +- **Suggestion:** Per H5, unify the enum. Then pick one field name + (`assignmentMode` or just `mode`). +- **Rationale:** Same as H5 — at the field level. + +--- + +## Observations (not findings, but worth noting) + +### O1. The `Detail` suffix is wired through the URL path +- **File:** `client.ts:1682, 1719, 1750, 1829, 1864, 1898, 1922, 1941, 1966, 1991, 2028, 2070, 2116, 2157, 2182` +- **Issue:** The server URL paths use `workspaceAccessDetails`, + `workspaceAssignmentDetails`, `workspaceIdentityDetails` — proto/Go RPC + pattern. The SDK reflects the server names. Renaming the TS types per H9 + does not change the wire; the SDK can have nicer TS names while still + hitting `workspaceAccessDetails` URLs. + +### O2. The TODO documentation pattern is from the generator +- **File:** model.ts:138, 144, 152, … 26 occurrences +- **Issue:** All "TODO: Write description later when this method is + implemented" strings are identical, suggesting a template that the + generator falls back to when the upstream API definition lacks + documentation. The fix is in the upstream spec, not the SDK. + +### O3. `marshal*ProxyRequestSchema` vs `marshal*RequestSchema` — schema-level Proxy variants +- **File:** `model.ts:1342, 1350, 1360, 1368, 1378, 1386` +- **Issue:** Each Resolve request has both marshal schemas; the proxy + variant is identical to the non-proxy minus `accountId`. Same H1 pattern + at the schema layer. + +### O4. `FieldMaskSchema` is defined per resource type +- **File:** `model.ts:1473, 1484, 1502, 1521, 1538` +- **Issue:** Five `FieldMaskSchema`s defined for Group, ServicePrincipal, + User, WorkspaceAssignmentDetail, WorkspaceIdentityDetail. Pattern is + consistent across the SDK — flagging for completeness only. + +### O5. Marshal/unmarshal schema pairs exist for all types but Direct/Transitive +- **File:** `model.ts:1006-1471` +- **Issue:** Unmarshal schemas exist for all response shapes including + `TransitiveParentGroup`, but marshal schemas only exist for shapes that + appear in request bodies (no marshal for `TransitiveParentGroup`, + `WorkspaceAccessDetail`). Consistent with the request/response split, but + worth confirming this is intentional and not generator skew. + +### O6. `User_NameFieldMaskSchema` (lowercase initial) — naming inconsistency +- **File:** `model.ts:1516` +- **Issue:** Variable name is `user_NameFieldMaskSchema` (snake_case initial + segment, then camelCase). The eslint disable comment says + `naming-convention -- Proto-style nested message name.`. The + inconsistency is `User_Name` (type, PascalCase + underscore) vs + `user_NameFieldMaskSchema` (variable, camelCase first + underscore). + +### O7. Method name `getAccountAccessIdentityRule` is 35 characters +- **File:** `client.ts:241` +- **Issue:** All four rule-endpoint method names hover around 30–37 chars. + Not actionable on its own — flagging because long names compound the H1 + problem. + +### O8. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) +- **File:** `model.ts:411, 677`, `client.ts:1715, 1783` +- **Issue:** Only WorkspaceAccessDetail has a `Local` variant; the parallel + `WorkspaceAssignmentDetail` uses `Proxy` instead, and + `WorkspaceIdentityDetail` has neither. Inconsistent presence of the + Local/Proxy variants across sibling Detail types. + +### O9. The `accountId` fallback comment in `client.ts:151-152` only applies to non-proxy methods +- **File:** `client.ts:151-152` +- **Issue:** "Fallback for endpoints whose path contains {account_id}. If + the request already carries an accountId, that value wins." This is true + for the non-proxy methods only — `*Proxy` methods don't have `accountId` + in the URL. Worth noting because if H1 collapses the variants, the + fallback semantic becomes "use the workspace context if accountId is + absent". + +--- + +## Cross-cutting recommendations (priority order) + +1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O3, O8, O9).** This + is the largest single improvement and ~halves the public type surface. +2. **Drop `_UNSPECIFIED` enum members (H10, H4).** 9 dead enum values + removed; users no longer write `=== State.STATE_UNSPECIFIED` accidentally. +3. **Replace `` template markup (M12).** Generator-side fix. +4. **Flatten proto-style nested names (`User_Name`, `WorkspaceAccessDetail_AccessType`, + `WorkspaceIdentityDetail_AssignmentType`) (H5, H6).** Removes + eslint-disable comments and underscore-in-identifier violations. +5. **Standardize ID field names (H12, L1, L11) and status field names (H3, + H8).** One name per concept. +6. **Remove type-suffix tautology fields (H13, H14, M6–M10).** Single-token + field names where the type already carries the kind. +7. **Drop the `Detail` suffix from the Workspace* types (H9).** And add an + `assignmentMode`/`mode` field via H5. +8. **Rewrite the placeholder TODO JSDocs (M13, M15).** Generator + spec fix. diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md new file mode 100644 index 00000000..6e76349f --- /dev/null +++ b/.agent/naming-audit/indexes.md @@ -0,0 +1,286 @@ +# Naming Audit: indexes + +**Path:** `packages/indexes/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks Vector Search index management — CRUD for `VectorIndex` (Delta-Sync or Direct-Access subtypes), data upsert/delete on direct-access indexes, vector/text/hybrid query, scan, pagination, and sync trigger. Routes under `/api/2.0/vector-search/indexes`. +**Total weird names flagged:** 43 + +## Summary +| Severity | Count | +| --- | --- | +| High | 14 | +| Medium | 17 | +| Low | 9 | +| Observation | 3 | + +## High severity + +### 1. Package name `indexes` is generic — does not say "vector search" — `packages/indexes/` +- **Why weird:** The package is exclusively about Databricks Vector Search indexes (every URL is `/api/2.0/vector-search/indexes/...` — `client.ts:94, 120, 154, 179, 213, 264, 290, 319, 345, 371`). Every public type is prefixed `Vector...` or contains `VectorIndex`. The package name `indexes` is the most generic possible word — it could equally mean SQL indexes, Unity Catalog indexes, search indexes, dataframe indexes, online table indexes, or array/iterator indexes. A user scanning the workspace cannot tell what `indexes` covers without opening the source. +- **Category:** 1 (vague/generic), 6 (misleading: collides with multiple "index" concepts in the Databricks ecosystem). +- **Suggested name:** `vector-search`, `vector-search-indexes`, or `vectorsearch-indexes`. At minimum, add a module-level JSDoc on `index.ts` (currently missing) stating "Databricks Vector Search index management". +- **Rationale:** Package names are the first-line filter; `indexes` says nothing about the domain. Sibling packages already exist (`vectorsearchendpoints`, presumably) for the endpoint side — naming should be parallel. + +### 2. Package name singular/plural mismatch — `packages/indexes/` vs `VectorIndex` type — `index.ts`, `model.ts:425` +- **Why weird:** The package is plural (`indexes`) but the central exported type is `VectorIndex` (singular). The Go SDK reference uses the singular `vectorsearchindex` package name (per repo convention in `databricks/sdk-go`). JS-style alternative spellings ("indices") are not used. The plural directory name reads as "the indexes API" — a collection — while every type/method works on one index at a time. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `vectorsearchindex` (singular, mirrors Go reference) or commit to plural with all "list/collection" connotations made explicit. Either rename to singular or accept the plural everywhere (which the codebase does not). +- **Rationale:** The repository convention elsewhere is singular package names matching the central noun (e.g. `clusters`, `catalogs` are plural where the *resource* is plural, while single-resource packages use singular). The `Index` resource is singular — package should match. + +### 3. `MiniVectorIndex` — `src/v1/model.ts:252` +- **Why weird:** "Mini" is a cryptic informal qualifier. No JSDoc explains what it means. By inspection it is a list-view subset of `VectorIndex` (same fields), used as the element type in `ListVectorIndexResponse.vectorIndexes`. Industry conventions for "the lighter view returned by a list endpoint" include `Summary`, `ListItem`, `Brief`, `Ref`, `Preview` — never `Mini`. +- **Category:** 5 (cryptic abbreviation), 1 (vague qualifier), 14 (proto-style name leaking). +- **Suggested name:** `VectorIndexSummary` or `VectorIndexListItem`. Add JSDoc explaining why it differs from `VectorIndex` (in fact, the fields are identical in this version — see #4). +- **Rationale:** `Mini` does not convey "subset of the full type returned by list operations". Naming the type after its role (`Summary`/`ListItem`) makes the relationship to `VectorIndex` discoverable. + +### 4. `MiniVectorIndex` is structurally identical to `VectorIndex` — `src/v1/model.ts:252-275` vs `:425-448` +- **Why weird:** Both types declare exactly the same nine fields with the same types and (where present) the same JSDoc lines. They are duplicates. The only signal of intent is the prefix "Mini". If they are meant to be the same, one should be an alias; if they differ, the difference must be documented. +- **Category:** 12 (duplicate concept). +- **Suggested name:** Either `export type VectorIndexSummary = VectorIndex;` (with a comment noting wire-format identity), or drop one entirely. If the API intends them to diverge later, document the upcoming difference. +- **Rationale:** Duplicating ~25 lines of type definition with no semantic distinction is a maintenance hazard. The unmarshalers (`unmarshalMiniVectorIndexSchema` model.ts:595 and `unmarshalVectorIndexSchema` model.ts:735) are also byte-for-byte identical. + +### 5. `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:109-142` vs `model.ts:144-177` +- **Why weird:** Two distinct exported types with the same ten fields, same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream protobuf quirk that should be flattened in TS. +- **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix). +- **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec`), or document why the request version differs. If the upstream API truly has divergence, list the diverging fields explicitly. +- **Rationale:** The asymmetry with `DirectAccessVectorIndexSpec` (no separate request variant) shows the duplication is gratuitous, not necessary. + +### 6. `UpsertDeleteDataStatus` — single enum shared by both upsert and delete — `src/v1/model.ts:39-43` +- **Why weird:** The enum name is two-verb (`Upsert` AND `Delete`) joined into one noun-prefix. Reads as "the status of an upsert-delete operation" — but there is no such thing as an "upsert-delete". It is the response shape for two separate operations. Conventionally each operation has its own response type or the shared type uses a neutral name. +- **Category:** 13 (verb-tense / verb-coupling), 7 (overly verbose by merging two verbs), 1 (generic "Status"). +- **Suggested name:** `DataModificationStatus` or `OperationStatus`. Or split into `UpsertStatus` and `DeleteStatus` aliases if the back-end is really sharing one. +- **Rationale:** Two-verb compound nouns are unusual and confusing. Same problem exists on `UpsertDeleteDataResult` (model.ts:407). + +### 7. `UpsertDeleteDataResult` — same two-verb compound — `src/v1/model.ts:407` +- **Why weird:** Same dual-verb naming as #6. The JSDoc on the field where it is used ("Result of the upsert or delete operation" — model.ts:97, 403) confirms the verbs are *alternatives*, not a sequence. +- **Category:** 13 (verb-tense), 7 (verbose), 1 (generic). +- **Suggested name:** `DataMutationResult` or split into `UpsertDataResult` / `DeleteDataResult` aliases. +- **Rationale:** Same as #6. + +### 8. Method names follow Go pattern `verbVectorIndex` not idiomatic JS `verbIndex` — `client.ts:90, 116, 150, 175, 209, 260, 286, 315, 341, 367` +- **Why weird:** Eleven methods: `createVectorIndex`, `deleteDataVectorIndex`, `deleteVectorIndex`, `getVectorIndex`, `listVectorIndex`, `listVectorIndexIter`, `queryVectorIndex`, `queryVectorIndexNextPage`, `scanVectorIndex`, `syncVectorIndex`, `upsertDataVectorIndex`. The package is exclusively about vector indexes — there is no ambiguity to disambiguate against. Repeating `VectorIndex` in every method name doubles their length to no purpose. The client is already `IndexesClient` (or implicitly scoped via `import { Client } from '@databricks/sdk-indexes'`). +- **Category:** 8 (redundant suffix), 7 (overly verbose), 14 (Go-style — Go SDK uses receiver methods so the package prefix is implicit, but in JS we re-add it). +- **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.list()` paginator, `client.query()`, `client.queryNextPage()`, `client.scan()`, `client.sync()`, `client.upsertData()`, `client.deleteData()`, `client.delete()`. Some collide with reserved words (`delete`) — those few can keep the `...Index` suffix. +- **Rationale:** The repetition is mechanical Go-port baggage. Other SDK packages in the workspace expose `client.get()`, `client.list()` directly. + +### 9. `listVectorIndexIter` suffix `Iter` — `client.ts:242` +- **Why weird:** `Iter` is a cryptic abbreviation. The method returns an `AsyncGenerator` — JS convention is `iter*` prefix (Python-style), or `*Iterator`, or a generator method with no suffix relying on `Symbol.asyncIterator`. `Iter` is Rust/Go-style. +- **Category:** 5 (cryptic abbreviation), 14 (Rust/Go-style), 17 (inconsistent with `listVectorIndex` — same verb, different return shape). +- **Suggested name:** `listVectorIndexIterator` or expose as `listAll()` / iterate via `for await (const i of client.list())`. +- **Rationale:** `Iter` does not appear in the JS standard library; `Iterator` does. The convention here is set in the SDK and is consistent across packages — flagged as a cross-package issue, but worth recording. + +### 10. `name` is the resource identifier on every Request type — meaning is overloaded — multiple sites +- **Why weird:** Fifteen Request/response types use a bare `name?: string` for what is actually the full index identifier (typically a Unity Catalog qualified name like `main.schema.index`). Types affected: `CreateVectorIndexRequest.name` (model.ts:64), `DeleteDataVectorIndexRequest.name` (model.ts:89), `DeleteVectorIndexRequest.name` (model.ts:103), `GetVectorIndexRequest.name` (model.ts:216), `MiniVectorIndex.name`, `QueryVectorIndexNextPageRequest.name` (model.ts:280), `QueryVectorIndexRequest.name` (model.ts:289), `ScanVectorIndexRequest.name` (model.ts:365), `SyncVectorIndexRequest.name` (model.ts:387), `UpsertDataVectorIndexRequest.name` (model.ts:395), `VectorIndex.name` (model.ts:427). JSDoc on every one says "Name of the index" — but a UC three-part name is more than a "name", it's a path/identifier. +- **Category:** 15 (generic field name losing meaning), 19 (underspecified ID). +- **Suggested name:** `indexFullName`, `indexId`, or at least add JSDoc clarifying the expected format ("three-part Unity Catalog identifier `..`"). +- **Rationale:** `name` is too generic when the value is a structured path. Users reading `req.name = "foo"` may send a bare name and get a 404. + +### 11. `endpointName` field for the *index endpoint* — generic name shared across packages — `model.ts:65, 233, 256, 282, 429` +- **Why weird:** Five sites use `endpointName?: string`. There is no JSDoc disambiguation between "vector search endpoint", "model serving endpoint", "external endpoint", "AI gateway endpoint" — all are Databricks concepts. The `EmbeddingSourceColumn.embeddingModelEndpointName` (model.ts:200) shows the SDK *does* qualify endpoint references when ambiguous, but here it does not. +- **Category:** 15 (generic field name), 19 (underspecified ID). +- **Suggested name:** `vectorSearchEndpointName` or add JSDoc clarifying it is "the Vector Search endpoint serving this index". The terse `endpointName` is fine *if* combined with type-level JSDoc. +- **Rationale:** The package owns a `VectorIndex` resource that is hosted on a *vector-search* endpoint — but a reader who jumps to a method signature sees only `endpointName` and may guess wrong. + +### 12. `RerankerConfig_RerankerParameters` — underscore-separated type — `src/v1/model.ts:343` +- **Why weird:** Underscore in a TypeScript type identifier. The file has an `eslint-disable-next-line @typescript-eslint/naming-convention` directive on it (line 342, with the comment "Proto-style nested message name") confirming the lint rule is being suppressed. Same suppression at line 953 for the marshal schema. The type's only field is `columnsToRerank` (already present on the parent's `QueryVectorIndexRequest.columnsToRerank` — model.ts:315). +- **Category:** 4 (underscore in TS identifier), 14 (proto-style name leaking). +- **Suggested name:** `RerankerParameters` (drop the redundant `RerankerConfig_` prefix), or namespace it: `namespace RerankerConfig { export type Parameters = ... }`. +- **Rationale:** The underscore costs a lint suppression in two locations and is a leaky proto abstraction. The `RerankerConfig_` prefix is also redundant with the wrapping type — duplicate name (see #13). + +### 13. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:315` vs `model.ts:344` +- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 315, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 344) inside the nested `RerankerConfig`. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:316-321) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. +- **Category:** 12 (duplicate concept), 6 (misleading — which one wins?). +- **Suggested name:** Drop one, or document the precedence. If one is for input and the other for output/echo, name them accordingly. +- **Rationale:** Users will set the wrong field. Worth raising upstream. + +### 14. `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` — `model.ts:133-134, 168-169` +- **Why weird:** `effective*` prefix usually marks a *response-only* computed field that reflects the inherited/resolved value from policies (see `database` package finding #11). But here these fields appear on the **Request** variant too (`DeltaSyncVectorIndexSpecRequest` lines 167-169). They cannot be both client-supplied *and* server-computed. Also `effectiveUsagePolicyId` has zero JSDoc — line 134/169 are bare. +- **Category:** 6 (misleading — "effective" implies output-only on a request type), 17 (inconsistent: budget has JSDoc, usage does not). +- **Suggested name:** Either remove the `effective*` fields from the Request variant, or document the read-only contract. Add the missing JSDoc on `effectiveUsagePolicyId`. +- **Rationale:** Same lakebase-style `effective*` leak as elsewhere — but here it leaks into the request shape, which is incoherent. + +## Medium severity + +### 15. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:23-27` +- **Why weird:** Enum exposes a sentinel value `VECTOR` whose JSDoc reads "Not supported. Use `HYBRID` instead." Exporting unsupported values inflates the enum and forces every consumer to filter or document them away. +- **Category:** 6 (misleading: present but not supported), 18 (the value `VECTOR` is also a tautology when inside an enum called `IndexSubtype` describing a vector-search index — every value is a kind of "vector"). +- **Suggested name:** Remove `VECTOR` from the enum, or rename the enum to `VectorIndexSubtype` and call the values `FullText | Hybrid`. Either way, eliminate the dead value. +- **Rationale:** Unused enum members are bug magnets. + +### 16. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:23, 50` +- **Why weird:** `IndexSubtype` = `{VECTOR, FULL_TEXT, HYBRID}` (search semantics). `VectorIndexType` = `{DELTA_SYNC, DIRECT_ACCESS}` (data residency / sync model). Both are exposed as `index*Type*` fields. Same prefix word, different axes. Beginner users will conflate them. +- **Category:** 6 (misleading: both look like "the type" of the index), 17 (inconsistent naming for two type axes). +- **Suggested name:** Rename to disambiguate: `IndexSearchMode` (for subtype) and `IndexBackingType` / `IndexStorageType` (for the DELTA_SYNC/DIRECT_ACCESS axis). Or `IndexSearchKind` and `IndexSyncMode`. +- **Rationale:** Two parallel `*Type` enums make the API harder to learn. The current names are technically correct but functionally ambiguous. + +### 17. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:34-37` +- **Why weird:** All four enums (`IndexSubtype`, `PipelineType`, `UpsertDeleteDataStatus`, `VectorIndexType`) use `UPPER_SNAKE_CASE` for member names. Google TS Style Guide §9.3 recommends `UpperCamelCase` for enum members. The codebase is mixed (some enums use camelCase elsewhere). The values are also the wire-protocol strings — wire is `UPPER_SNAKE` legitimately, but the TS *identifier* can be `Triggered` mapping to wire `'TRIGGERED'`. +- **Category:** 3 (acronym/casing inconsistency), 14 (Go/proto-style). +- **Suggested name:** `PipelineType.Triggered | Continuous`, with explicit `= 'TRIGGERED'` wire values. Or accept the wire-form names and apply them consistently across all packages. +- **Rationale:** Style consistency across the workspace; preference for camelCase enum members aligns with the Google TS Style Guide. + +### 18. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:204` +- **Why weird:** Field name reads as a sentence (`modelEndpointName ForQuery`). JS field-naming convention is noun phrases, not "for"-clauses. Compare with adjacent `embeddingModelEndpointName` (also long, but a noun phrase). +- **Category:** 14 (Java-ish "ForX" suffix), 7 (verbose). +- **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. +- **Rationale:** `for`-clauses in identifiers are uncommon in JS. The renaming aligns it with the adjacent field. + +### 19. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:113-115, 149-150, 181, 189` +- **Why weird:** Two parallel array fields on three different types (`DeltaSyncVectorIndexSpec`, `DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`). One holds source text columns to be embedded; the other holds pre-computed vector columns. Both arrays use *different* element types (`EmbeddingSourceColumn` vs `EmbeddingVectorColumn`) — good — but the field names look near-identical at a glance. +- **Category:** 6 (visually confusable pair), 15 (the qualifier "Source"/"Vector" is doing all the work). +- **Suggested name:** `textColumns` + `vectorColumns`, or `embeddingTextColumns` + `embeddingVectorColumns`. Anything to widen the gap between the two names. +- **Rationale:** Pairs of similarly named array fields are a known footgun. A user typing `embedding` will autocomplete the wrong one. + +### 20. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:127-141, 161-176` +- **Why weird:** Two fields on the same type, JSDoc says they are aliases ("[Optional] Alias for columns_to_sync. Select the columns to include in the vector index. ... Only one of columns_to_sync or columns_to_index may be specified.") Having two fields that mean the same thing in one struct, where the API expects exactly one to be set, is a recipe for runtime errors. +- **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). +- **Suggested name:** Deprecate one in the SDK (mark `columnsToSync` as `@deprecated` if `columnsToIndex` is the new canonical), or merge them with a runtime validation. +- **Rationale:** API-level aliases are upstream policy, but the SDK should clearly mark the deprecated alias. + +### 21. `pipelineId` is an underspecified ID — `model.ts:123, 158` +- **Why weird:** Field type is `string` with JSDoc "The ID of the pipeline that is used to sync the index." No format documented — is it a UUID, a numeric ID, a path? Compare with `effectiveBudgetPolicyId` which uses the same generic `string` but at least the policy ID is a known Databricks pattern. +- **Category:** 19 (underspecified ID), 15 (generic). +- **Suggested name:** Keep the name but improve the JSDoc with the expected ID format and a link to the Pipelines API. +- **Rationale:** Without format hints, users will struggle to construct the value. + +### 22. `effectiveBudgetPolicyId` on a *request* type without JSDoc explanation — `model.ts:133, 168` +- **Why weird:** See finding #14. Specifically, the field is on `DeltaSyncVectorIndexSpec` (response side) *and* `DeltaSyncVectorIndexSpecRequest` (request side). On the request side, "effective" is incoherent — there is no "effective" until the server resolves it. +- **Category:** 6 (misleading on the request side), 14 (proto leak: same field appears in both, even when only meaningful on one). +- **Suggested name:** On `DeltaSyncVectorIndexSpecRequest`, drop the field (it cannot be set), or rename to `budgetPolicyIdOverride`. +- **Rationale:** See #14. + +### 23. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:397` +- **Why weird:** `UpsertDataVectorIndexRequest.inputsJson: string` is "JSON string representing the data to be upserted." The TS surface forces the caller to call `JSON.stringify()` themselves, then the marshaling layer wraps the request body in `JSON.stringify(...)` *again*. Double-encoded payloads are a well-known JSON antipattern. +- **Category:** 6 (misleading — the field is JSON-in-JSON), 1 (generic — "inputs" tells you nothing about *what*). +- **Suggested name:** Expose as `inputs: JsonValue[]` (or whatever the row shape is) and let the SDK serialize, OR keep `inputsJson` but rename to `inputsJsonString` and document the double-encoding. +- **Rationale:** Same problem with `filtersJson` (see #24) and `schemaJson` (see #25). All three are wire-protocol leaks that should be normalized at the SDK boundary. + +### 24. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:305` +- **Why weird:** Same JSON-in-JSON pattern as #23. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. +- **Category:** 6 (misleading), 1 (generic). +- **Suggested name:** Expose as `filters?: Record` and serialize internally. Or rename `filtersJsonString`. +- **Rationale:** Same as #23. + +### 25. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:187` +- **Why weird:** Same pattern. The field is "The schema of the index in JSON format. Supported types are `integer`, `long`, `float`, `double`, `boolean`, `string`, `date`, `timestamp`." A typed schema descriptor would be far more discoverable. +- **Category:** 6 (misleading), 1 (generic). +- **Suggested name:** Expose as a typed shape, or rename `schemaJsonString` and add JSDoc warning. +- **Rationale:** Same as #23. + +### 26. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:125, 160` +- **Why weird:** "Writeback" run together with "embedding" plus "Table" forms a hard-to-parse triple-noun. Pronunciation: "embed-ding-write-back-table". JSDoc clarifies meaning ("[Optional] Name of the Delta table to sync the vector index contents and computed embeddings to") — but the field name is opaque without it. +- **Category:** 7 (overly verbose), 14 (Go-style smushed identifier). +- **Suggested name:** `writebackTableName`, `embeddingsTableName`, or `computedEmbeddingsTable`. +- **Rationale:** Readability of compound nouns degrades fast past 2 words. + +### 27. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:223` +- **Why weird:** JSDoc says: "If true, the URL returned for the index is guaranteed to be compatible with the reranker. Currently this means we return the CP URL regardless of how the index is being accessed. If not set or set to false, the URL may still be compatible with the reranker depending on what URL we return." So the flag toggles *which URL is returned*, not whether the index itself is reranker-compatible. The name suggests the operation *ensures compatibility*, but it actually just changes URL format. +- **Category:** 6 (misleading), 1 (vague boolean). +- **Suggested name:** `useControlPlaneUrl`, `returnControlPlaneUrl`, or `rerankerCompatibleUrl`. +- **Rationale:** Boolean names should describe the side effect, not an aspirational outcome. + +### 28. `numResults` field name in two places — `model.ts:291, 367` +- **Why weird:** Two unrelated requests (`QueryVectorIndexRequest`, `ScanVectorIndexRequest`) both name the result-count field `numResults`. JS convention is `limit` (matching SQL `LIMIT`, REST `?limit=`) or `pageSize`. `numResults` is Python/SQL-ish. +- **Category:** 14 (Python/SQL-style), 17 (cross-package inconsistency — other paged APIs use `pageSize` or `limit`). +- **Suggested name:** `limit` (matches HTTP query param and most JS libs) or `pageSize`. +- **Rationale:** Aligning with `limit`/`pageSize` reduces friction. + +### 29. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:313` +- **Why weird:** JSDoc says: "The query type to use. Choices are `ANN` and `HYBRID` and `FULL_TEXT`. Defaults to `ANN`." Three known values, but typed as `string` — not an enum. Users get no autocomplete, no compile-time check. +- **Category:** 1 (generic typing), 6 (misleading typing). +- **Suggested name:** Introduce an enum `QueryType.Ann | Hybrid | FullText` (these overlap with `IndexSubtype` values but represent different concepts). +- **Rationale:** `string` for a closed set of values is a known antipattern. + +### 30. `RerankerConfig.model` field — generic name "model" — `model.ts:338` +- **Why weird:** Bare `model?: string` with no JSDoc. In ML SDKs "model" is overloaded (ML model, data model, type model). The field probably holds a model endpoint name or model identifier. +- **Category:** 1 (generic), 15 (generic field losing meaning). +- **Suggested name:** `modelEndpointName`, `modelName`, or `rerankerModel`. +- **Rationale:** Document what kind of identifier this is. + +### 31. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:382` +- **Why weird:** `Struct` is the SDK's wire-format for a JSON-like map, and `MapStringValueEntry` is `{key: string, value: Value}`. The TS shape is "an array of key-value entries" rather than `Record`. This is a direct port of protobuf's map-as-repeated-message-entry encoding. Idiomatic JS would use a plain object or `Map`. +- **Category:** 14 (proto-style). +- **Suggested name:** Flatten to `Record` at the TS boundary; keep the entry-array shape on the wire. +- **Rationale:** Forcing users to map an array of `{key, value}` pairs into a record is friction the SDK could remove. + +## Low severity + +### 32. `Value` — single-word generic name for a discriminated union — `model.ts:414-423` +- **Why weird:** A bare type called `Value` is uninformative. It is the SDK's wire-form scalar wrapper (number/string/bool/struct/list). Stronger candidates: `ScalarValue`, `WireValue`, `VectorIndexValue`. +- **Category:** 1 (generic). +- **Suggested name:** `ScalarValue` or move to the core wkt package and rename `wkt.Value`. +- **Rationale:** `Value` collides with too many concepts. + +### 33. `Struct` — generic single-word type name — `model.ts:380` +- **Why weird:** "Struct" is a language keyword in many languages (Go, C, Rust). In JS/TS it is a vague C-style holdover. The type is "a row of a vector index" (per the JSDoc). +- **Category:** 1 (generic), 14 (C/Go/proto-style), 10 (potential reserved-word collision in TS-flow tools). +- **Suggested name:** `IndexRow` or `VectorIndexRow`. +- **Rationale:** A more domain-specific name is more discoverable. + +### 34. `MapStringValueEntry` — verbose proto-style name — `model.ts:245` +- **Why weird:** Reads as "Map of String to Value Entry". JSDoc says "Key-value pair." Just call it that. +- **Category:** 7 (verbose), 14 (proto-style). +- **Suggested name:** `KeyValue` or `StructField`. +- **Rationale:** Less verbose, more idiomatic. + +### 35. `ResultManifest` — Java/Spring-flavored noun — `model.ts:356-361` +- **Why weird:** "Manifest" in a query-result context is unusual JS phrasing. JSDoc says "Metadata about the result set." More common in JS: `Metadata`, `Schema`, `Info`. +- **Category:** 14 (Java-style), 1 (mildly generic). +- **Suggested name:** `ResultMetadata` or `ResultSchema`. +- **Rationale:** Aligns with idiomatic JS. + +### 36. `ResultData` — generic two-word noun — `model.ts:348-353` +- **Why weird:** Type is "Data returned in the query result." `ResultData` is generic; `QueryResultData` or just `Rows` would be more specific. +- **Category:** 1 (generic). +- **Suggested name:** `QueryResultData` or `ResultRows`. +- **Rationale:** Disambiguate. + +### 37. `dataArray` field — generic + type-suffix tautology — `model.ts:352` +- **Why weird:** `dataArray: JsonValue[][]` — the field name says "Array", and the type is already an array. Tautology. The field is "Data rows returned in the query." +- **Category:** 20 (type-suffix tautology), 1 (generic prefix). +- **Suggested name:** `rows` or `data`. +- **Rationale:** Drop the `Array` suffix; the type already says it. + +### 38. `data` field in `ScanVectorIndexResponse` — `model.ts:375` +- **Why weird:** `data: Struct[]` — JSDoc "List of data entries". Field name `data` is the same level of generic as #36/#37. `entries`, `rows`, or `structs` would be more specific. +- **Category:** 1 (generic). +- **Suggested name:** `rows` or `entries`. +- **Rationale:** Match the JSDoc terminology. + +### 39. `lastPrimaryKey` field on request + response — `model.ts:369, 377` +- **Why weird:** Same field name used as a cursor on both request (input) and response (output). On the response it is fine ("last primary key in this page"), on the request it is a pagination cursor named after its expected source rather than its role. JS convention would be `pageToken` / `cursor` / `afterKey`. +- **Category:** 17 (inconsistency with `pageToken` used elsewhere — model.ts:235, 284), 14 (database-cursor-style name). +- **Suggested name:** Both could use `cursor` or `afterPrimaryKey` (request) + `lastPrimaryKey` (response). +- **Rationale:** The package uses `pageToken` for pagination elsewhere; `lastPrimaryKey` is a one-off naming convention for scan. + +### 40. `RerankerConfig` and `RerankerConfig_RerankerParameters` — `Reranker` × 3 — `model.ts:337, 343` +- **Why weird:** The string "Reranker" appears three times in the nested type name `RerankerConfig_RerankerParameters`. Drop the inner `Reranker` to `RerankerConfig_Parameters` or `Reranker.Parameters` (namespaced). +- **Category:** 8 (redundant suffix). +- **Suggested name:** `RerankerConfig.Parameters` (namespaced) or `RerankerParameters`. +- **Rationale:** Concision. + +### 41. `kind` field with deprecation comment `(--The kind of value.--)` — `Value.kind` — `model.ts:415` +- **Why weird:** JSDoc reads `(--The kind of value.--)` — the `(-- ... --)` markers look like an unprocessed proto comment annotation (proto3 internal-comment syntax). Visible to SDK consumers. +- **Category:** 14 (raw proto syntax leaked into TS docs). +- **Suggested name:** Strip the markers, leave plain "The kind of value." +- **Rationale:** Cosmetic but visible in editor tooltips. + +## Observation + +### 42. `unmarshal*Schema` / `marshal*Schema` naming — `model.ts:461-991` +- **Why weird:** Helper schemas are named `unmarshalSchema` / `marshalSchema`. JS terms are usually `parse`/`stringify` or `decode`/`encode`. `marshal/unmarshal` is Go-style. +- **Category:** 14 (Go-style), 17 (inconsistent with JS conventions). +- **Suggested name:** `decodeSchema` / `encodeSchema`. Or accept Go-style consistently across all packages. +- **Rationale:** Cross-package decision — flagged as an observation. + +### 43. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` +- **Why weird:** Cross-package import. `Call` is the most generic possible name for "a network operation". +- **Category:** 1 (generic), cross-package observation. +- **Suggested name:** `RetryableCall`, `SdkCall`. Out of scope for this audit. +- **Rationale:** Tracked for cross-package consistency. + +### 44. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:29` +- **Why weird:** The mini variant (see #3, #4) is re-exported as part of the public API. If the intent is for it to be an internal implementation detail, it should not be in `index.ts`. +- **Category:** Observation on the public surface. +- **Suggested name:** Either rename per #3 or remove from the public surface. +- **Rationale:** Consumers will use whatever is exported; if `MiniVectorIndex` is a name we'd prefer not to commit to publicly, it should be hidden. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md new file mode 100644 index 00000000..716fca22 --- /dev/null +++ b/.agent/naming-audit/instancepools.md @@ -0,0 +1,395 @@ +# Naming Audit: `instancepools` (v2) + +**Package:** `@databricks/sdk-instancepools` +**Path:** `/home/parth.bansal/sdk-js/packages/instancepools/` +**Version audited:** `v2` +**Files audited:** + +- `src/v2/model.ts` (1295 lines, read in full) +- `src/v2/client.ts` (213 lines, read in full) +- `src/v2/utils.ts` (150 lines, read in full) +- `src/v2/index.ts` (43 lines, read in full) + +**Inferred domain:** Databricks instance-pool lifecycle (create / edit / get / +delete / list) of pre-warmed cloud VMs that clusters can draw from. Carries +per-cloud (AWS / Azure / GCP) attributes, disk specifications, Docker preload +configuration, idle / used statistics, and pending-instance failure reporting. + +--- + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 18 | +| Medium | 22 | +| Low | 20 | +| Observation | 8 | +| **Total** | **68**| + +### Top themes + +1. **Massive structural duplication.** `CreateInstancePool` (28 fields), + `EditInstancePool` (29 fields), `GetInstancePool_Response` (30 fields), and + `InstancePoolAndStats` (30 fields) are byte-identical apart from one or two + fields. They could share a single base type. +2. **Proto-style `_Response` and `_*Entry` types pollute the public surface.** + 12 type names use `_` separators, each requiring an `eslint-disable`. +3. **`InstancePool*` prefix on every type is redundant** — the package is + already `instancepools`; the v2 namespace is even smaller. `Pool` (or even + nothing) would do for `InstancePoolStats`, `InstancePoolStatus`, + `InstancePoolAndStats`. +4. **Per-cloud enum-prefix inconsistency** — `AwsAvailability` members are + unprefixed (`SPOT`, `ON_DEMAND`), but `AzureAvailability` (`SPOT_AZURE`) + and `GcpAvailability` (`PREEMPTIBLE_GCP`) repeat the enum's cloud. The + same defect exists in `clusters` (see `clusters.md` #3) — fix once at + codegen. + +--- + +## 1. Inventory + +### 1.1 Enums (`model.ts`) + +| Name | Members | Lines | +| --------------------- | -------------------------------------------------- | ---------- | +| `AwsAvailability` | `SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK` | 10-20 | +| `AzureAvailability` | `SPOT_AZURE`, `ON_DEMAND_AZURE`, `SPOT_WITH_FALLBACK_AZURE` | 26-36 | +| `AzureDiskVolumeType` | `PREMIUM_LRS`, `STANDARD_LRS` | 42-47 | +| `EbsVolumeType` | `GENERAL_PURPOSE_SSD`, `THROUGHPUT_OPTIMIZED_HDD` | 53-58 | +| `GcpAvailability` | `PREEMPTIBLE_GCP`, `ON_DEMAND_GCP`, `PREEMPTIBLE_WITH_FALLBACK_GCP` | 64-68 | +| `InstancePoolState` | `ACTIVE`, `STOPPED`, `DELETED` | 78-88 | + +### 1.2 Interfaces (`model.ts`) + +| Name | Lines | Purpose | +| --------------------------------------------- | -------- | -------------------------------------------------- | +| `CreateInstancePool` | 90-172 | Request body for create — 28 fields. | +| `CreateInstancePool_CustomTagsEntry` | 175-188 | Proto-nested tag entry, dead in TS. | +| `CreateInstancePool_Response` | 191-194 | Response with single `instancePoolId`. | +| `DeleteInstancePool` | 196-199 | `{ instancePoolId?: string }`. | +| `DeleteInstancePool_Response` | 202 | Empty `{}`. | +| `DiskSpec` | 210-248 | Disk-attachment spec. | +| `DiskType` | 251-256 | Disc-union wrapper for EBS or Azure disk types. | +| `DockerBasicAuth` | 258-263 | `{ username, password }`. | +| `DockerImage` | 265-275 | `{ url, credsOneof }`. | +| `EditInstancePool` | 277-361 | Request body for edit — 29 fields. | +| `EditInstancePool_CustomTagsEntry` | 364-377 | Same as the Create variant — duplicate. | +| `EditInstancePool_Response` | 380 | Empty `{}`. | +| `GetInstancePool` | 382-385 | `{ instancePoolId?: string }`. | +| `GetInstancePool_Response` | 388-490 | 30 fields — superset of `CreateInstancePool` plus statistics. | +| `GetInstancePool_Response_CustomTagsEntry` | 493-506 | Third duplicate of the tag-entry shape. | +| `GetInstancePool_Response_DefaultTagsEntry` | 509-522 | Fourth duplicate of the tag-entry shape. | +| `InstancePoolAndStats` | 524-626 | 30 fields — duplicate of `GetInstancePool_Response`. | +| `InstancePoolAndStats_CustomTagsEntry` | 629-642 | Fifth duplicate of the tag-entry shape. | +| `InstancePoolAndStats_DefaultTagsEntry` | 645-658 | Sixth duplicate of the tag-entry shape. | +| `InstancePoolAwsAttributes` | 661-696 | AWS-specific config. | +| `InstancePoolAzureAttributes` | 699-710 | Azure-specific config. | +| `InstancePoolGcpAttributes` | 713-735 | GCP-specific config. | +| `InstancePoolStats` | 737-746 | Idle/used counters. | +| `InstancePoolStatus` | 748-756 | Wraps `pendingInstanceErrors`. | +| `ListInstancePools` | 759 | Empty `{}`. | +| `ListInstancePools_Response` | 762-764 | Wraps `instancePools` array. | +| `NodeTypeFlexibility` | 767-770 | Wraps `alternateNodeTypeIds`. | +| `PendingInstanceError` | 773-776 | `{ instanceId, message }`. | + +### 1.3 Methods (`client.ts`) + +| Method | HTTP | URL path | Returns | +| -------------------- | ------ | --------------------------------- | ----------------------------- | +| `createInstancePool` | POST | `/api/2.0/instance-pools/create` | `CreateInstancePool_Response` | +| `deleteInstancePool` | POST | `/api/2.0/instance-pools/delete` | `DeleteInstancePool_Response` | +| `editInstancePool` | POST | `/api/2.0/instance-pools/edit` | `EditInstancePool_Response` | +| `getInstancePool` | GET | `/api/2.0/instance-pools/get` | `GetInstancePool_Response` | +| `listInstancePools` | GET | `/api/2.0/instance-pools/list` | `ListInstancePools_Response` | + +### 1.4 Other identifiers + +- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields + `host`, `httpClient`, `logger`, `userAgent`. +- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, + `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`. +- Marshal / unmarshal schema constants (line numbers in `model.ts`): + `unmarshalCreateInstancePool_ResponseSchema` (779), + `unmarshalDeleteInstancePool_ResponseSchema` (789), + `unmarshalDiskSpecSchema` (792), + `unmarshalDiskTypeSchema` (808), + `unmarshalDockerBasicAuthSchema` (825), + `unmarshalDockerImageSchema` (835), + `unmarshalEditInstancePool_ResponseSchema` (849), + `unmarshalGetInstancePool_ResponseSchema` (853), + `unmarshalInstancePoolAndStatsSchema` (915), + `unmarshalInstancePoolAwsAttributesSchema` (977), + `unmarshalInstancePoolAzureAttributesSchema` (992), + `unmarshalInstancePoolGcpAttributesSchema` (1003), + `unmarshalInstancePoolStatsSchema` (1016), + `unmarshalInstancePoolStatusSchema` (1030), + `unmarshalListInstancePools_ResponseSchema` (1042), + `unmarshalNodeTypeFlexibilitySchema` (1053), + `unmarshalPendingInstanceErrorSchema` (1062), + `marshalCreateInstancePoolSchema` (1073), + `marshalDeleteInstancePoolSchema` (1123), + `marshalDiskSpecSchema` (1131), + `marshalDiskTypeSchema` (1147), + `marshalDockerBasicAuthSchema` (1171), + `marshalDockerImageSchema` (1181), + `marshalEditInstancePoolSchema` (1200), + `marshalInstancePoolAwsAttributesSchema` (1252), + `marshalInstancePoolAzureAttributesSchema` (1266), + `marshalInstancePoolGcpAttributesSchema` (1276), + `marshalNodeTypeFlexibilitySchema` (1288). + +--- + +## 2. Findings + +### 2.1 Vague / generic names + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| V-01 | `DockerImage.credsOneof` | High | `credsOneof` is a Go/proto-codegen leak — TS readers do not know what "Oneof" means in this context (the wire field uses a protobuf `oneof`). The "creds" abbreviation is also generic. Should be `credentials` (and the union shape itself satisfies the discriminator). | +| V-02 | `PendingInstanceError.message` | Medium | `message` is generic. Could be `errorMessage` to match the type's purpose, or the type itself could be flattened. | +| V-03 | `parseResponse` (`utils.ts:113`) | Low | Local helper; OK in scope. Parses JSON specifically — `parseJsonResponse` would be more accurate. | +| V-04 | `marshalRequest` (`utils.ts:119`) | Low | Generic but local. OK. | +| V-05 | `readAll` (`utils.ts:40`) | Low | Standard name for a read-to-end helper. | +| V-06 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | +| V-07 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | + +### 2.2 Redundant enum prefixes — High + +| ID | Symbol | Severity | Issue | +| ----- | --------------------------------------------------- | -------- | ----- | +| E-01 | `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` | High | Every member repeats `_AZURE`. The enum is `AzureAvailability`; inside scope the cloud is implied. Compare with `AwsAvailability` (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`) which gets it right. Suggested `AzureAvailability.SPOT | ON_DEMAND | SPOT_WITH_FALLBACK`. Same defect duplicated in `clusters` (clusters.md #3) — fix at codegen. | +| E-02 | `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` | High | Same as E-01. Members redundantly carry `_GCP`. | +| E-03 | `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | `LRS` is the Azure suffix for "Locally Redundant Storage". Standard Azure terminology — keep. | +| E-04 | `EbsVolumeType.GENERAL_PURPOSE_SSD` / `THROUGHPUT_OPTIMIZED_HDD` | Low | Standard AWS EBS volume-class names. Slightly long but correct. | + +### 2.3 Acronym casing inconsistencies — High + +| ID | Symbol | Severity | Issue | +| ----- | ------------------------------------- | -------- | ----- | +| A-01 | `InstancePoolAwsAttributes` | High | Google TS style says acronyms ≥3 chars get only-first-letter capitalised ("AWS" → "Aws"). The repo follows this (Aws/Azure/Gcp). Acceptable, but contrasts with `EbsVolumeType` where `Ebs` is only 3 chars (same rule, applied consistently). No defect — listed for parity with related audits. | +| A-02 | `InstancePoolGcpAttributes.gcpAvailability` | High | The field name re-states the cloud already implied by the parent type `InstancePoolGcpAttributes`. Compare with `InstancePoolAwsAttributes.availability` (line 663) and `InstancePoolAzureAttributes.availability` (line 701) — both unprefixed. Three sibling types, two conventions. Should be `InstancePoolGcpAttributes.availability`. | +| A-03 | `InstancePoolAwsAttributes.instanceProfileArn` | Low | "Arn" applies Google TS style for ≥3-char acronyms. Compare with `EbsVolumeType` (same package) and consistent. OK. | +| A-04 | `InstancePoolGcpAttributes.localSsdCount` | Low | "Ssd" is 3 letters; same casing rule. OK. | +| A-05 | `InstancePoolAzureAttributes.spotBidMaxPrice` vs `InstancePoolAwsAttributes.spotBidPricePercent` | Medium | Sibling fields describe the same concept (max price for spot bid) in opposite shapes. `MaxPrice` is an absolute USD value; `PricePercent` is relative. Names obscure this — `azureSpotBidMaxPriceUsd` and `awsSpotBidPricePercent` (or any clarifying suffix) would help. | + +### 2.4 Underscores in TS identifiers — High + +| ID | Symbol | Severity | Issue | +| ----- | --------------------------------------------------- | -------- | ----- | +| U-01 | `CreateInstancePool_CustomTagsEntry` (`model.ts:175`) | High | Proto-nested name carries the `_` separator that Google TS style forbids (https://google.github.io/styleguide/tsguide.html#naming-style). Each occurrence requires an `eslint-disable @typescript-eslint/naming-convention`. | +| U-02 | `CreateInstancePool_Response` (`model.ts:191`) | High | Same as U-01. | +| U-03 | `DeleteInstancePool_Response` (`model.ts:202`) | High | Same as U-01. | +| U-04 | `EditInstancePool_CustomTagsEntry` (`model.ts:364`) | High | Same as U-01. | +| U-05 | `EditInstancePool_Response` (`model.ts:380`) | High | Same as U-01. | +| U-06 | `GetInstancePool_Response` (`model.ts:388`) | High | Same as U-01. | +| U-07 | `GetInstancePool_Response_CustomTagsEntry` (`model.ts:493`) — *double underscore* | High | The proto-nesting compounds: `Response` is itself nested, and `CustomTagsEntry` is nested inside `Response`. 40-char identifier. | +| U-08 | `GetInstancePool_Response_DefaultTagsEntry` (`model.ts:509`) — *double underscore* | High | Same as U-07. | +| U-09 | `InstancePoolAndStats_CustomTagsEntry` (`model.ts:629`) | High | Same as U-01. | +| U-10 | `InstancePoolAndStats_DefaultTagsEntry` (`model.ts:645`) | High | Same as U-01. | +| U-11 | `ListInstancePools_Response` (`model.ts:762`) | High | Same as U-01. | +| U-12 | `unmarshalCreateInstancePool_ResponseSchema` (and 4 sibling schemas) | High | Underscore cascades through every generated schema constant. | + +### 2.5 Cryptic abbreviations — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| C-01 | `DockerImage.credsOneof` | High (also V-01) | `creds` and `Oneof` are both opaque outside Go/proto context. | +| C-02 | `BYOC` in JSDoc `"Custom Docker Image BYOC"` (`model.ts:141, 330, 459, 595`) | Medium | "Bring Your Own Container" not expanded. External readers will not know. | +| C-03 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | +| C-04 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | +| C-05 | `req`, `resp`, `httpReq`, `respBody` locals in `client.ts` | Low | Method-local; OK. | +| C-06 | `opts` (`utils.ts:66`) | Low | Inside function scope; OK. | +| C-07 | `PuPr` in JSDoc `"deprecated before entering PuPr"` (`model.ts:164, 353, 482, 618`) | Medium | "Public Preview" — internal Databricks jargon. Should be expanded in JSDoc. | +| C-08 | `Fleet-V2` in JSDoc `"For pools with node type flexibility (Fleet-V2)"` | Medium | Internal codename leaking into public docs. | +| C-09 | `Mb/s` in JSDoc `"configurable throughput (in Mb/s)"` (`model.ts:168, 357, 486, 622`) | Low | Likely intended `MB/s` (megabytes per second) given the cloud-disk-throughput context; `Mb/s` (megabits) is unusual for disk throughput. Possible casing typo upstream. | + +### 2.6 Misleading names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| M-01 | `editInstancePool()` / `EditInstancePool` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | +| M-02 | `InstancePoolStatus` | High | The type carries *only* `pendingInstanceErrors`. The name promises a general "status" but the shape exposes only errors. `InstancePoolPendingErrors` or `InstancePoolFailures` would be more truthful. (`InstancePoolState` is the actual lifecycle state, on the entity itself.) | +| M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 28 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | +| M-04 | `enableAutoAlternateNodeTypes` (DEPRECATED — `model.ts:164, 353, 482, 618`) | Medium | The field is marked deprecated in JSDoc but still exposed in every request and response type. The JSDoc says "This field was deprecated before entering PuPr and should no longer be used" — yet it ships. Misleading availability. | +| M-05 | `DiskSpec.diskCount`, `diskSize`, `diskIops`, `diskThroughput` | Low | Repetition of the `disk` prefix inside a type named `DiskSpec`. Inside the type, `count` / `size` / `iops` / `throughput` would suffice. Same pattern as `clusters.md` flagged elsewhere. | +| M-06 | `DiskSpec.diskIops` (no JSDoc) and `diskSpec.diskThroughput` (no JSDoc) — `model.ts:246-247` | Low | Two fields with no JSDoc. Hard to know the unit without context. (Compare neighbouring `diskSize` which documents "GiB".) | +| M-07 | `preloadedDockerImages` is plural but JSDoc says "Custom Docker Image BYOC" (singular) — `model.ts:142, 331, 460, 596` | Low | Field is `DockerImage[]`. Plural correctly matches type, but the JSDoc is misleading. | +| M-08 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | +| M-09 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | + +### 2.7 Overly verbose / Redundant suffixes — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| O-01 | `idleInstanceAutoterminationMinutes` (5-word identifier, present in 4 types) | Medium | 33-char field. Inside a type called `CreateInstancePool` etc., `idleAutoterminationMinutes` or `idleTimeoutMinutes` would be 27 / 18 chars. The wire uses `idle_instance_autotermination_minutes` so any change is generator-side. | +| O-02 | `enableAutoAlternateNodeTypes` | Medium | "Enable auto alternate node types" — five concept words. With node-type-flexibility being the modern replacement, the field is also deprecated (see M-04). | +| O-03 | `InstancePool*` prefix on `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`, `InstancePoolAwsAttributes`, `InstancePoolAzureAttributes`, `InstancePoolGcpAttributes`, `InstancePoolState` | High | The package is already `@databricks/sdk-instancepools`. Inside the package, the prefix is redundant. `Stats`, `Status`, `AwsAttributes` would all suffice and remove ~12 chars from each name. Compare `clusters` (`clusters.md` #75) and `apps` packages, which face the same recurring issue. | +| O-04 | `unmarshalInstancePoolGcpAttributesSchema` (40 chars) — and 7 sibling schema names | Medium | `marshal`/`unmarshal` + the verbose type-name + `Schema` triple-states intent. Repo-wide convention. | +| O-05 | `unmarshalGetInstancePool_ResponseSchema` (39 chars) | Medium | Compound proto-nesting + `Schema` suffix yields long identifiers. | +| O-06 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | +| O-07 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | +| O-08 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | +| O-09 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | + +### 2.8 Singular / plural mismatches — Low / High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| P-01 | `preloadedSparkVersions: string[]` | High (also M-08) | Plural array type but the JSDoc constrains it to at most one element. | +| P-02 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | +| P-03 | `ListInstancePools` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | +| P-04 | `ListInstancePools_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | +| P-05 | `customTags` is `Record` but the proto-side schema also exposes `_CustomTagsEntry` interface | Observation | TS uses the record. See W-01 for the underscore-naming concern. | + +### 2.9 Reserved-word collisions — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| R-01 | `DockerImage.credsOneof.$case === 'basicAuth'.basicAuth: DockerBasicAuth` | Low | `basicAuth` is not a reserved word but is duplicated across the `$case` discriminator and the embedded field — `library.lib.basicAuth.basicAuth` style access. | +| R-02 | None of the type names collide with TS reserved words. | — | OK. | + +### 2.10 Underscore-laden wrapper types — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| W-01 | `*_CustomTagsEntry` (six occurrences: 175, 364, 493, 629) and `*_DefaultTagsEntry` (two occurrences: 509, 645) | High | These eight interfaces are proto-internal map-entry shapes whose underscore-laden names (`CreateInstancePool_CustomTagsEntry` etc.) each require an `eslint-disable @typescript-eslint/naming-convention`. They are exported via `index.ts` (8 names) under proto-style identifiers that violate Google TS style. | +| W-02 | `InstancePoolStatus` (`model.ts:748-756`) | Medium | The type's name promises a general "status" but its shape exposes only `pendingInstanceErrors`. Misleading (see also M-02). | + +### 2.11 Duplicate concepts — Highest in repo + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| D-01 | `CreateInstancePool` (28 fields, lines 90-172) vs `EditInstancePool` (29 fields, lines 277-361) | High | Identical except `EditInstancePool` adds `instancePoolId`. Could share a base type. | +| D-02 | `GetInstancePool_Response` (30 fields, lines 388-490) vs `InstancePoolAndStats` (30 fields, lines 524-626) | High | **Byte-identical** apart from the type name. Compare line-by-line: identical field set, identical order, identical JSDoc. Two names for the same shape. | +| D-03 | `*_CustomTagsEntry` types (six declared, lines 175, 364, 493, 629) vs `*_DefaultTagsEntry` types (two declared, lines 509, 645) | High | All eight are byte-identical `{ key?: string; value?: string }`. One shared type would do. Same as `clusterpolicies` (clusterpolicies.md #W-04) and other packages — codegen-wide issue. | +| D-04 | `CreateInstancePool` vs the `Pool` body inside `InstancePoolAndStats` | High | All 28 config fields appear three times: once on Create, once on Edit (29), once on the entity. Codegen could project from a shared base. | +| D-05 | `InstancePoolAwsAttributes` (this package) vs `AwsAttributes` (`clusters` package) | High | Same domain (AWS attributes for a compute pool / cluster). `clusters` calls them `AwsAttributes`; this package calls them `InstancePoolAwsAttributes`. Both share many fields (availability, zoneId, instanceProfileArn, spotBid…) but `clusters` has additional fields (`ebsVolumeCount`, etc.). Cross-package duplication; a shared `compute` module would fix both. | +| D-06 | `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` vs `clusters.AzureAttributes` / `clusters.GcpAttributes` | High | Same as D-05 for Azure / GCP. | +| D-07 | `EbsVolumeType`, `AzureDiskVolumeType`, `AwsAvailability`, `AzureAvailability`, `GcpAvailability`, `DockerImage`, `DockerBasicAuth`, `DiskSpec`, `DiskType`, `NodeTypeFlexibility`, `PendingInstanceError` | High | All eleven types/enums are duplicated verbatim in `clusters/src/v2/model.ts` (verified via `grep`). Two packages ship eleven identical shapes. | + +### 2.12 Verb-tense inconsistency — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| T-01 | `createInstancePool`, `deleteInstancePool`, `editInstancePool`, `getInstancePool`, `listInstancePools` | Low | All present-tense imperative — consistent. | +| T-02 | `preloadedDockerImages`, `preloadedSparkVersions` (past participle) | Low | Standard for fields that describe a pre-applied state. OK. | + +### 2.13 Go / Java-style names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| G-01 | `CreateInstancePool_Response`, `EditInstancePool_Response`, ... (proto-nested message style) | High | Direct port of Go `pb.CreateInstancePoolResponse`. Every occurrence requires `eslint-disable`. Repo-wide concern; flagged here. | +| G-02 | `marshal*Schema` / `unmarshal*Schema` | High | Go (and gRPC) verb pair. JS/TS code uses **serialize / deserialize** (or **encode / decode**, or **parse / stringify**). Required `import` for new TS readers to look up. | +| G-03 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | +| G-04 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | +| G-05 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | + +### 2.14 Generic field names losing meaning — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| F-01 | `DiskType.remoteVolumeType` (outside of `DiskType`) | Medium | When destructured, `remoteVolumeType: EbsVolumeType` reads as a category name colliding with the cloud-specific value. | +| F-02 | `DockerImage.url` (outside of `DockerImage`) | Low | Standard. OK in context. | +| F-03 | `DockerBasicAuth.username` / `password` | Low | Standard. OK. | +| F-04 | `PendingInstanceError.message` | Medium (also V-02) | When destructured, an error `message` field is the generic-est possible name. Adding `instanceMessage` would help. | +| F-05 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | +| F-06 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | +| F-07 | `*_CustomTagsEntry.key` / `*_CustomTagsEntry.value` | Medium | Outside the entry type, `key` and `value` are the genericest possible field names. (See W-01 for the underscore-naming concern on the entry types.) | +| F-08 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | + +### 2.15 Field contradicting type domain — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| K-01 | None observed. All fields are within their type's domain. | — | OK. | + +### 2.16 Inconsistent action verbs — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| AV-01 | `editInstancePool()` vs ecosystem-standard `update` | Medium | Same as `clusterpolicies` AV-01. Driven by wire path `/edit`. Newer Databricks resources expose `update*`. Cross-package inconsistency. | +| AV-02 | `getInstancePool()` (singular) vs `listInstancePools()` (plural) | Low | Correct REST convention. OK. | +| AV-03 | `createInstancePool()` / `deleteInstancePool()` / `editInstancePool()` / `getInstancePool()` / `listInstancePools()` — only five verbs | Low | No `start`, `stop`, `pin`, etc. — instance pools are stateless from the API standpoint; the lifecycle is implicit via fewer endpoints than `clusters`. Consistent. | + +### 2.17 Long enum values — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| L-01 | `AzureAvailability.SPOT_WITH_FALLBACK_AZURE` (26 chars) | Medium | Combination of redundant `_AZURE` suffix (E-01) and the verbose form. Trimming the suffix gives `SPOT_WITH_FALLBACK` (18 chars), already in use for AWS. | +| L-02 | `GcpAvailability.PREEMPTIBLE_WITH_FALLBACK_GCP` (29 chars) | Medium | Same as L-01 for GCP. | +| L-03 | `EbsVolumeType.THROUGHPUT_OPTIMIZED_HDD` (24 chars) | Low | Standard AWS terminology; OK. | +| L-04 | `AzureDiskVolumeType.STANDARD_LRS` (12 chars) | Low | Short. OK. | + +### 2.18 Underspecified IDs — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| I-01 | `instancePoolId` | Low | Well-specified — scope = instance pool. No collisions. OK. | +| I-02 | `nodeTypeId` | Low | Scoped correctly. OK. | +| I-03 | `PendingInstanceError.instanceId` | Low | Scoped. OK. | +| I-04 | `policyFamilyId` is *not* in this package; `clusterId` is *not* in this package — only `instancePoolId` and `nodeTypeId` IDs appear. | Observation | Clean. | +| I-05 | `NodeTypeFlexibility.alternateNodeTypeIds: string[]` | Low | Plural array of node-type IDs; scoped. OK. | +| I-06 | `InstancePoolAwsAttributes.zoneId` / `InstancePoolGcpAttributes.zoneId` | Low | Both reuse `zoneId` for the AWS availability zone ("us-west-2a") and GCP availability zone ("us-west1-a"). Same name, two slightly different value formats. Acceptable cross-cloud abstraction. | + +### 2.19 Type-suffix tautology — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| TS-01 | `InstancePoolAwsAttributes` / `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` | Medium | All three carry the `Attributes` suffix and the redundant `InstancePool` prefix (see O-03). Could be `AwsAttributes` / `AzureAttributes` / `GcpAttributes` (matching `clusters`). | +| TS-02 | `InstancePoolStats` | Medium | `Stats` is already abbreviated; the `InstancePool` prefix is redundant inside this package. | +| TS-03 | `InstancePoolStatus` | Medium | Same as TS-02. | +| TS-04 | `InstancePoolState` (enum) | Medium | Same. Could be `State` or `PoolState`. | +| TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-04). Doubly off. | +| TS-06 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | +| TS-07 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-05) the type-name still echoes. | +| TS-08 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | + +### 2.20 Other observations + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| X-01 | JSDoc placeholder `` appears 17 times in this file (e.g., `" will tag all pool resources"` `model.ts:117`) | Observation | Un-substituted template placeholder leaking into the generated TS docstrings. Reader sees `` in IntelliSense. Same finding as `clusters.md` #92. | +| X-02 | `enableElasticDisk` JSDoc: "Autoscaling Local Storage: when enabled, **this instances** in this pool ..." (`model.ts:133, 322, 451, 587`) | Observation | Grammar typo in JSDoc ("this instances" → "the instances"). Same string repeated four times. | +| X-03 | TODO comment in JSDoc: `"TODO(CJ-71514): Remove this field after sufficient time has passed for all clients to migrate."` (`model.ts:165, 354, 483, 619`) | Observation | Internal Databricks ticket reference (CJ-71514) leaks into public SDK JSDoc. Same string in four request/response types. | +| X-04 | `client.ts:165-167` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | +| X-05 | `client.ts:191` `_req: ListInstancePools` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | +| X-06 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | +| X-07 | The schema constants use the same name as the type with an `unmarshal`/`marshal` prefix and `Schema` suffix — e.g., `unmarshalInstancePoolAndStatsSchema`. Constants are not assignable types but the naming mirrors them. | Observation | OK; documented as repo-wide convention. | +| X-08 | `index.ts` re-exports 28 type symbols and 6 enum symbols but **not** any of the 13 marshal/unmarshal schemas | Observation | Schemas are package-internal — good encapsulation. The `_CustomTagsEntry`/`_DefaultTagsEntry` types (8 names) *are* re-exported under proto-style underscore names. See W-01. | + +--- + +## 3. Severity totals (recap) + +| Severity | Count | +| ------------ | ----- | +| High | 18 | +| Medium | 22 | +| Low | 20 | +| Observation | 8 | +| **Total** | **68**| + +## 4. Cross-package consistency notes + +- **The eleven shared shapes** (`AwsAvailability`, `AzureAvailability`, + `GcpAvailability`, `AzureDiskVolumeType`, `EbsVolumeType`, `DiskSpec`, + `DiskType`, `DockerImage`, `DockerBasicAuth`, `NodeTypeFlexibility`, + `PendingInstanceError`) are duplicated verbatim between this package and + `clusters`. A shared `@databricks/sdk-compute-common` package — or codegen + emitting from a shared schema — would eliminate the dual maintenance burden. +- The `*Attributes` types (`InstancePoolAwsAttributes` etc.) overlap heavily + with `clusters` `AwsAttributes` etc., but the field sets differ. A common + base + extension would still help. +- The `_Response` / `_*Entry` proto-nesting concern is identical to that flagged in + every other audit in this directory; it is a codegen-wide issue, not a + per-package fix. + +## 5. File coverage + +- `src/v2/model.ts` (1295 lines): read fully. +- `src/v2/client.ts` (213 lines): read fully. +- `src/v2/utils.ts` (150 lines): read fully. +- `src/v2/index.ts` (43 lines): read fully. diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md new file mode 100644 index 00000000..05a9302a --- /dev/null +++ b/.agent/naming-audit/instanceprofiles.md @@ -0,0 +1,345 @@ +# Naming Audit: `instanceprofiles` (v2) + +**Package:** `@databricks/sdk-instanceprofiles` +**Path:** `/home/parth.bansal/sdk-js/packages/instanceprofiles/` +**Version audited:** `v2` +**Files audited:** + +- `src/v2/model.ts` +- `src/v2/client.ts` +- `src/v2/utils.ts` +- `src/v2/index.ts` + +`InstanceProfile` is a specific AWS concept (an AWS IAM Instance Profile +encapsulates an IAM role that an EC2 instance can assume). This audit +catalogues every identifier (type, field, enum value, method, constant) in +the package and flags naming concerns against the 20-category rubric. Issues +are graded: + +- **High** — actively misleading, ambiguous, or violates a TS rule. +- **Medium** — friction; verbose, redundant, or stylistically off. +- **Low** — nit / consistency observation; safe to ignore. + +--- + +## 1. Inventory + +### 1.1 Enums (`model.ts`) + +| Name | Members | +| ---- | ------- | +| _(none)_ | _(no enums declared in this package)_ | + +### 1.2 Interfaces (`model.ts`) + +| Name | Purpose | +| --------------------------------- | -------------------------------------------------------- | +| `AddInstanceProfile` | Request body for register/add. | +| `AddInstanceProfile_Response` | Empty response from add (proto-style suffix). | +| `EditInstanceProfile` | Request body for edit/update. | +| `EditInstanceProfile_Response` | Empty response from edit. | +| `InstanceProfile` | The instance-profile entity (AWS-scoped). | +| `ListInstanceProfiles` | Empty request body for list (proto-style empty type). | +| `ListInstanceProfiles_Response` | Response from list. | +| `RemoveInstanceProfile` | Request body for unregister/remove. | +| `RemoveInstanceProfile_Response` | Empty response from remove. | + +### 1.3 Fields (entity / request / response — combined catalog) + +| Type | Field | Type / Notes | +| --------------------------------- | ------------------------ | ------------------------------------- | +| `AddInstanceProfile` | `skipValidation` | `boolean?` | +| `AddInstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | +| `AddInstanceProfile` | `isMetaInstanceProfile` | `boolean?` | +| `AddInstanceProfile` | `iamRoleArn` | `string?` (AWS IAM role ARN) | +| `AddInstanceProfile_Response` | _(no fields)_ | _(empty body)_ | +| `EditInstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | +| `EditInstanceProfile` | `isMetaInstanceProfile` | `boolean?` | +| `EditInstanceProfile` | `iamRoleArn` | `string?` | +| `EditInstanceProfile_Response` | _(no fields)_ | _(empty body)_ | +| `InstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | +| `InstanceProfile` | `isMetaInstanceProfile` | `boolean?` | +| `InstanceProfile` | `iamRoleArn` | `string?` | +| `ListInstanceProfiles` | _(no fields)_ | _(empty request)_ | +| `ListInstanceProfiles_Response` | `instanceProfiles` | `InstanceProfile[]?` | +| `RemoveInstanceProfile` | `instanceProfileArn` | `string?` (ARN, marked required) | +| `RemoveInstanceProfile_Response` | _(no fields)_ | _(empty body)_ | + +### 1.4 Methods (`client.ts`) + +| Method | Verb | URL path | Returns | +| ----------------------- | ---- | --------------------------------- | ---------------------------------- | +| `addInstanceProfile` | POST | `/api/2.0/instance-profiles/add` | `AddInstanceProfile_Response` | +| `editInstanceProfile` | POST | `/api/2.0/instance-profiles/edit` | `EditInstanceProfile_Response` | +| `listInstanceProfiles` | GET | `/api/2.0/instance-profiles/list` | `ListInstanceProfiles_Response` | +| `removeInstanceProfile` | POST | `/api/2.0/instance-profiles/remove` | `RemoveInstanceProfile_Response` | + +### 1.5 Other identifiers + +- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields + `host`, `httpClient`, `logger`, `userAgent`. +- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, + `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`. +- Marshal / unmarshal schemas: `unmarshalAddInstanceProfile_ResponseSchema`, + `unmarshalEditInstanceProfile_ResponseSchema`, `unmarshalInstanceProfileSchema`, + `unmarshalListInstanceProfiles_ResponseSchema`, + `unmarshalRemoveInstanceProfile_ResponseSchema`, + `marshalAddInstanceProfileSchema`, `marshalEditInstanceProfileSchema`, + `marshalRemoveInstanceProfileSchema`. + +--- + +## 2. Findings by Category + +### 2.1 Vague / generic names — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| V-01 | `InstanceProfile` (interface) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | +| V-02 | `AddInstanceProfile.skipValidation` | Medium | `skipValidation` is generic — *which* validation? Reading the JSDoc reveals it specifically skips the AWS `RunInstances` dry-run permission check. `skipIamValidation` or `skipPermissionDryRun` would self-document. | +| V-03 | `parseResponse` (utils) | Low | Generic name. Parses JSON specifically; `parseJsonResponse` would be more accurate. Local to the package — acceptable. | +| V-04 | `marshalRequest` (utils) | Low | Generic but local. OK. | +| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-06 | `readAll` (utils, private) | Low | Standard name for "read all bytes from a stream". OK. | + +### 2.2 Redundant enum prefixes — N/A + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------- | -------- | ----- | +| E-01 | _(no enums in package)_ | — | Nothing to flag. | + +### 2.3 Acronym casing inconsistencies — High + +| ID | Symbol | Severity | Issue | +| ----- | --------------------------------- | -------- | ----- | +| A-01 | `instanceProfileArn` (field) | High | "ARN" is the AWS acronym for Amazon Resource Name (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html). Google TypeScript style says acronyms ≥3 chars take only the first letter capitalised (https://google.github.io/styleguide/tsguide.html#naming-style). `Arn` (capital A, lowercase r/n) is correct under Google style. Flagged only because the field uses the Google convention rather than uppercase `ARN`; both are defensible — keep as-is for Google style compliance. | +| A-02 | `iamRoleArn` (field) | High | Same as A-01. "IAM" (AWS Identity & Access Management) and "ARN" are acronyms; Google TS style lowercases all but the first letter. Currently `iamRoleArn` lowercases the entire `iam` prefix because it is the *first* word in the camel-cased identifier; that is consistent with the rule (the first letter would be lowercase even if the rule said full uppercase, since camelCase always starts lowercased). Defensible. | +| A-03 | `isMetaInstanceProfile` | Low | No acronym issues. | +| A-04 | `Aws` / `Iam` / `Arn` not appearing as type prefixes | Low | The package doesn't have a type-name acronym to test (e.g. no `AWSInstanceProfile`). If the type were renamed per V-01, the chosen casing should be `AwsInstanceProfile` to match Google TS style. | + +### 2.4 Underscores in TS identifiers — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------------------- | -------- | ----- | +| U-01 | `AddInstanceProfile_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). Every occurrence requires an `eslint-disable @typescript-eslint/naming-convention` annotation. Should be `AddInstanceProfileResponse`. | +| U-02 | `EditInstanceProfile_Response` | High | Same as U-01. | +| U-03 | `ListInstanceProfiles_Response` | High | Same as U-01. | +| U-04 | `RemoveInstanceProfile_Response` | High | Same as U-01. | +| U-05 | `unmarshalAddInstanceProfile_ResponseSchema` | High | Same naming-convention violation cascades through the schema constants. | +| U-06 | `unmarshalEditInstanceProfile_ResponseSchema` | High | Same as U-05. | +| U-07 | `unmarshalListInstanceProfiles_ResponseSchema` | High | Same as U-05. | +| U-08 | `unmarshalRemoveInstanceProfile_ResponseSchema` | High | Same as U-05. | +| U-09 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | + +### 2.5 Cryptic abbreviations — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| C-01 | `arn` (within `instanceProfileArn`, `iamRoleArn`) | Low | "ARN" is a well-known AWS acronym; not cryptic in the AWS context. Acceptable. | +| C-02 | `iam` (within `iamRoleArn`) | Low | "IAM" = AWS Identity & Access Management. Well-known AWS acronym. Acceptable. | +| C-03 | `meta` (within `isMetaInstanceProfile`) | Medium | "Meta instance profile" is a Databricks-specific term not defined anywhere except the JSDoc ("contains an meta IAM role which could assume a wide range of roles"). The name doesn't make the concept self-evident. `isCredentialPassthrough` or `isAssumableMetaRole` would convey intent better. | +| C-04 | `req`, `resp`, `httpReq`, `respBody` (`client.ts` locals) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | +| C-05 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | +| C-06 | `pkgJson` (`client.ts`) | Low | Standard short name for `package.json` import. OK. | + +### 2.6 Misleading names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| M-01 | `AddInstanceProfile` / `addInstanceProfile()` | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | +| M-02 | `RemoveInstanceProfile` / `removeInstanceProfile()` | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | +| M-03 | `EditInstanceProfile` / `editInstanceProfile()` | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | +| M-04 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | +| M-05 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | +| M-06 | `skipValidation` (`AddInstanceProfile`) | Medium | The name implies skipping *all* validation; the JSDoc clarifies it only skips the AWS dry-run permission check. See V-02. | +| M-07 | `isMetaInstanceProfile` | Medium | The boolean's semantics ("for credential passthrough scenarios where the instance profile contains a meta-IAM role that can assume a wide range of roles") is much narrower than "is this a meta instance profile". Calling it `isCredentialPassthrough` or `isMetaIamRole` would describe the actual behaviour. | + +### 2.7 Overly verbose / Redundant suffixes — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| O-01 | `instanceProfileArn` (in `InstanceProfile`) | Medium | Inside a type already called `InstanceProfile`, prefixing the field with `instanceProfile` is redundant — `arn` alone (or `instanceProfileArn` only on request types, with `arn` on the entity) would suffice. Tautology pattern: `instanceProfile.instanceProfileArn`. | +| O-02 | `isMetaInstanceProfile` (in `InstanceProfile`) | Medium | Same tautology: `instanceProfile.isMetaInstanceProfile`. `isMeta` alone (or `isMetaRole`) would suffice within the entity. | +| O-03 | `unmarshalAddInstanceProfile_ResponseSchema` and 3 siblings | Medium | The pattern `unmarshalSchema` triple-states intent ("schema for unmarshalling X"). ~44 chars per constant; repeated across the codebase. Repo-wide convention; not local-fix territory. | +| O-04 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-05 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Inside `ListInstanceProfiles_Response`, the field `instanceProfiles` re-states the type prefix. `items` or `profiles` would suffice. Per-API codegen output. | + +### 2.8 Singular / plural mismatches — Low + +| ID | Symbol | Severity | Issue | +| ----- | --------------------------------------------------- | -------- | ----- | +| P-01 | `ListInstanceProfiles` (plural) vs `listInstanceProfiles()` (plural) | Low | Consistent. | +| P-02 | `ListInstanceProfiles_Response.instanceProfiles` | Low | Plural field for an array — correct. | +| P-03 | `InstanceProfile` (singular entity) vs `instanceProfiles` (plural array) | Low | Correct pluralisation throughout. | +| P-04 | `AddInstanceProfile` / `EditInstanceProfile` / `RemoveInstanceProfile` (all singular) | Low | Correct — single-entity operations. | + +### 2.9 Reserved-word collisions — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| R-01 | _(no collisions observed)_ | — | No fields use reserved words (e.g. `package`, `class`, `enum`, `delete`). | + +### 2.10 Empty / trivial wrapper types — N/A + +_None._ Wrapper types (empty response interfaces, empty request structs, +and single-field wrappers) exist for forward compatibility: future API +revisions can add fields without breaking the type signature. Not flagged. + +### 2.11 Duplicate concepts — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| D-01 | `InstanceProfile` vs `EditInstanceProfile` vs `AddInstanceProfile` | Medium | Three types with substantially overlapping field sets (`instanceProfileArn`, `isMetaInstanceProfile`, `iamRoleArn`). `EditInstanceProfile` and `InstanceProfile` are byte-identical; `AddInstanceProfile` adds only `skipValidation`. Could be expressed as a base type with extension. Codegen constraint; flagged for visibility. | +| D-02 | `instanceProfileArn` across all 4 request/entity types | Low | Same field, same semantics — duplication is expected for codegen output. OK. | +| D-03 | `iamRoleArn` across `InstanceProfile`, `AddInstanceProfile`, `EditInstanceProfile` | Low | Same observation as D-02. OK. | + +### 2.12 Verb-tense inconsistency — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| T-01 | `addInstanceProfile`, `editInstanceProfile`, `listInstanceProfiles`, `removeInstanceProfile` | Low | All imperative present-tense — consistent. | +| T-02 | `isMetaInstanceProfile` (boolean) | Low | Standard `is*` boolean prefix. | +| T-03 | `skipValidation` (boolean) | Low | Imperative — consistent boolean style. | + +### 2.13 Go / Java-style names — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| G-01 | `AddInstanceProfile_Response` (proto nested-message style) | High | Direct port of Go's `pb.AddInstanceProfileResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `AddInstanceProfileResponse`. | +| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**) — see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON. New TS readers will look up "marshal" before they recognise it. Repo-wide convention; flagged once per package. | +| G-03 | `RemoveInstanceProfile` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | + +### 2.14 Generic field names losing meaning — Low + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | +| F-02 | `isMetaInstanceProfile` | Medium | Without the JSDoc, "meta instance profile" is a Databricks-internal term and conveys little. See C-03 / M-07. | +| F-03 | `skipValidation` | Medium | Without the JSDoc, unclear which validation. See V-02. | +| F-04 | `instanceProfiles` (in `ListInstanceProfiles_Response`) | Low | Self-describing. Good. | +| F-05 | `httpReq`, `respBody`, `body` (locals in `client.ts`) | Low | Locals only. | + +### 2.15 Field contradicting type domain — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| FD-01 | `InstanceProfile.iamRoleArn` | Medium | "IAM role" is a related-but-distinct AWS concept from "instance profile". An instance profile *contains* a role, but the role itself is a separate AWS resource. The field is conditionally required (JSDoc says "required if your role name and instance profile name do not match and you want to use the instance profile with Databricks SQL Serverless"). Mixing two AWS resource ARNs in one entity is the API design; flagged. | +| FD-02 | `AddInstanceProfile.skipValidation` | Low | A request-only behaviour flag in a "domain entity"-shaped request. Acceptable for an "add"/"create" request type. | +| FD-03 | `RemoveInstanceProfile.instanceProfileArn` | Low | Identifier-only payload for delete — appropriate. | + +### 2.16 Inconsistent action verbs — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| AV-01 | `addInstanceProfile` + `removeInstanceProfile` (pair) | Medium | The verbs `add` + `remove` form a natural pair and match the API wire paths (`/add`, `/remove`). Acceptable. | +| AV-02 | `editInstanceProfile` (verb mismatch with `add` / `remove`) | High | The CRUD verbs in this package are `add`, `edit`, `remove` — three different verb families (`add`/`remove` ↔ pair; `edit` ↔ standalone, no `add`/`edit`/`delete` triplet, no `create`/`update`/`delete` triplet). Inconsistent. Most modern Databricks APIs (and broader REST APIs) use **update**. Matches the wire path `/edit`, so this is a per-API upstream decision. | +| AV-03 | `addInstanceProfile` (vs `createInstanceProfile`) | High | "Add" suggests adding to an existing collection (e.g. registering); "create" suggests minting a new AWS resource. The method **registers an existing AWS instance profile with Databricks** — neither verb is perfectly accurate, but `register*` would be most precise. See M-01. | +| AV-04 | `removeInstanceProfile` (vs `deleteInstanceProfile` / `unregisterInstanceProfile`) | High | Same observation as AV-03. The method un-registers, not deletes. `unregisterInstanceProfile` would be most precise. See M-02. | +| AV-05 | `listInstanceProfiles` (vs `getInstanceProfiles`) | Low | Correct: `list*` for plural retrieval, `get*` for singular. Consistent. | + +### 2.17 Long enum values — N/A + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------- | -------- | ----- | +| L-01 | _(no enums in package)_ | — | Nothing to flag. | + +### 2.18 Underspecified IDs — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| I-01 | `instanceProfileArn` | Low | Well-specified: identifier scope (instance profile), identifier type (AWS ARN). Good — far clearer than a bare `id` or `name` would be. | +| I-02 | `iamRoleArn` | Low | Well-specified: scope (IAM role), type (ARN). Good. | +| I-03 | Absence of `instanceProfileId` | Low | The package uses ARN as the sole identifier — there is no separate "ID" concept. Good (no ambiguity between `id` and `arn`). | + +(Section retained for parity with the rubric; no high findings — the +package is exemplary in using ARNs as identifiers.) + +### 2.19 Type-suffix tautology — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| TS-01 | `InstanceProfile.instanceProfileArn` | Medium | Inside a type called `InstanceProfile`, the `instanceProfile` prefix on the field is tautological. See O-01. | +| TS-02 | `InstanceProfile.isMetaInstanceProfile` | Medium | Same tautology: `isMeta` inside `InstanceProfile`. See O-02. | +| TS-03 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Field re-states the entity type that fills the array. `items` or `profiles` would suffice. See O-05. | + +### 2.20 Other observations + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| X-01 | `HttpCallOptions` (utils) | Low | Local interface; precise. | +| X-02 | `executeHttpCall`, `executeCall` | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | +| X-03 | `flattenQueryParams` (utils, exported but unused in this package) | Low | The package has no GET endpoints with query params (the list endpoint takes none). Either remove or use it. Not strictly a naming issue. | +| X-04 | `Client` (the class name itself) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | +| X-05 | `pkgJson` (import alias) | Low | Standard short alias for `package.json`. OK. | +| X-06 | `PACKAGE_SEGMENT.key` derives from `pkgJson.name.replace(/^@[^/]+\//, '')` (string transform on a constant) | Low | Identifier semantics OK; observation only. | +| X-07 | Schema field `skip_validation` in `marshalAddInstanceProfileSchema` (line 147) | Low | The wire-format snake_case is correct. Note `skipValidation` doesn't appear in the `unmarshal` schema (it's a request-only flag) — also correct. | + +--- + +## 3. Summary + +### 3.1 Findings by severity + +| Severity | Count | +| -------- | ----- | +| High | 15 | +| Medium | 22 | +| Low | 30 | +| **Total**| **67**| + +### 3.2 Top themes + +1. **Proto-style `_Response` suffix pollutes every response type.** + Four interfaces (`AddInstanceProfile_Response`, `EditInstanceProfile_Response`, + `ListInstanceProfiles_Response`, `RemoveInstanceProfile_Response`) plus + four schema constants each require an `eslint-disable` for the naming + rule. Renaming to TS-idiomatic `AddInstanceProfileResponse` etc. would + eliminate 8 disable-comments and a Google-style violation in one sweep. + +2. **`add` / `remove` verbs mislead about scope.** The methods **register** / + **unregister** an existing AWS instance profile with Databricks — neither + creates nor deletes the underlying AWS resource. `register*` / `unregister*` + would be more accurate. Compounded by `edit*` (instead of `update*`) breaking + the CRUD verb consistency. + +3. **`InstanceProfile` is AWS-specific but not cloud-prefixed.** In a + multi-cloud SDK, an unqualified name implies a cross-cloud concept it + doesn't represent. `AwsInstanceProfile` (matching `AzureServicePrincipal`, + `GcpAttributes`) would prevent future ambiguity. + +4. **Tautological field naming inside `InstanceProfile`.** + `instanceProfile.instanceProfileArn` and + `instanceProfile.isMetaInstanceProfile` repeat the type name. Inside the + entity, `arn` and `isMeta` (or `isCredentialPassthrough`) would suffice. + +5. **`isMetaInstanceProfile` and `skipValidation` need their JSDoc to be + intelligible.** "Meta instance profile" is a Databricks-specific term; + "validation" is overloaded. `isCredentialPassthrough` / + `skipIamValidation` (or similar) would be self-documenting. + +### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) + +- Drop `_Response` suffix in all four response interfaces. +- Rename `InstanceProfile` → `AwsInstanceProfile` to scope to the cloud. +- Rename `addInstanceProfile` → `registerInstanceProfile` and + `removeInstanceProfile` → `unregisterInstanceProfile` to match actual + semantics. +- Rename `editInstanceProfile` → `updateInstanceProfile` for CRUD consistency. +- Inside `InstanceProfile`, rename `instanceProfileArn` → `arn` (and similarly + for nested entities); drop redundant prefixes. +- Rename `isMetaInstanceProfile` → `isCredentialPassthrough` (or similar) + and `skipValidation` → `skipIamValidation`. + +### 3.4 Cross-package consistency notes + +- The `marshal*` / `unmarshal*` schema-naming convention is consistent with + peer packages (e.g. `clusters`, `clusterpolicies`) and is therefore a + repo-wide concern, not a per-package fix. +- The proto-style `_Response` suffix is consistent with peers and should be + addressed at the codegen level. +- `editInstanceProfile` (vs `updateInstanceProfile`) is a per-API decision + driven by the upstream REST verb; flag for upstream alignment but no + per-package fix. +- `Client` as the exported class name is repo-wide; aliasing on import is + the de-facto solution. diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md new file mode 100644 index 00000000..cdf40af6 --- /dev/null +++ b/.agent/naming-audit/jobs.md @@ -0,0 +1,951 @@ +# Naming Audit: `@databricks/sdk-jobs` (v2) + +Scope: `packages/jobs/src/v2/` — `model.ts` (10184 lines), `client.ts` (1060 lines), +`utils.ts` (150 lines), `index.ts` (284 lines). This is the largest API surface in +the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. + +## Summary Table + +| Severity | Count | Notes | +| ------------ | ----- | ------------------------------------------------------------------------------ | +| High | 37 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions. | +| Medium | 87 | Underscores, redundant prefixes/suffixes, vague names, acronym casing. | +| Low | 53 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| Observations | 17 | Patterns spanning the entire file (proto leakage, oneof wrappers, etc.). | +| **Total** | **194** | | + +Issues are catalogued below by severity, then by file/line. + +--- + +## High + +### H1. `Run` is overloaded across at least seven shapes +- **Location:** `model.ts:3414` (`Run`), `model.ts:1008` (`BaseRun`), `model.ts:3890` (`RunTask`), `model.ts:3506` (`Run_JobLevelParameters`), `model.ts:3867` (`RunState`), `model.ts:3881` (`RunStatus`), `model.ts:4276` (`RunTriggerInfo`). +- **Category:** Vague/generic + duplicate concepts (#1, #12). +- **Suggestion:** Treat `Run` as a domain concept and only use the bare token on the canonical job run. Rename `RunTask` -> `TaskRun` (it represents a task **run**, not a run-task), and rename `Run` -> `JobRun` for symmetry with `JobRunId`, `numberInJob`, `runType: JOB_RUN`. +- **Rationale:** Currently `BaseRun`, `Run`, `RunTask`, and the `RunStatus.state` field all describe overlapping shapes. Authors must read JSDoc to know which is which. `RunTask` reading order "task that is a run" is opposite to its actual meaning ("the run of a task"). + +### H2. `RunTask` and `TaskSettings` are nearly identical but named asymmetrically +- **Location:** `model.ts:3890` (`RunTask`), `model.ts:4731` (`TaskSettings`), `model.ts:4100` (`RunTaskSettings`). +- **Category:** Duplicate concepts (#12), misleading names (#6). +- **Suggestion:** Use `TaskRun` (the runtime/output form) and `Task` (the design-time form). Drop `RunTaskSettings` in favour of `SubmitTask` if it is submit-specific. +- **Rationale:** A reader sees three shapes (`RunTask`, `TaskSettings`, `RunTaskSettings`) carrying the same union of task types and cannot tell which to use without grepping. The naming pattern (`RunX` for "X on a run", `XSettings` for "X on a job") is undocumented. + +### H3. `Format` (top-level public enum) is a reserved-word collision +- **Location:** `model.ts:150`. +- **Category:** Reserved-word collisions (#10), vague/generic (#1). +- **Suggestion:** Rename to `JobFormat`. +- **Rationale:** `Format` is a well-known global (the `Intl.NumberFormat`/`Intl.DateTimeFormat` family, `console.format` in some runtimes, and a built-in name in many code-generators). Importing `Format` from a Jobs SDK forces consumers to alias it. + +### H4. `Source` (top-level public enum) clashes with global Web/TS names +- **Location:** `model.ts:280`. +- **Category:** Reserved-word collisions (#10), vague/generic (#1). +- **Suggestion:** Rename to `TaskSource`, `CodeSource`, or `FileSource` (only two values: `WORKSPACE`, `GIT`). +- **Rationale:** `Source` is the name of the DOM `EventSource` shorthand, Web Audio `AudioBufferSourceNode`, RxJS `Source`, several stream libraries, and lint rules around it. With only two values describing where SQL/Notebook/dbt code lives, a domain prefix is essential. + +### H5. `Compute` interface clashes with the larger Databricks Compute API +- **Location:** `model.ts:1464`. +- **Category:** Vague/generic (#1), misleading names (#6). +- **Suggestion:** Rename to `TaskComputeOverride` or `TaskCompute` — the type wraps only `hardwareAccelerator` for serverless GPU. +- **Rationale:** A consumer would expect `Compute` to describe an entire compute target (cluster spec, node type, runtime, etc.). It actually has one field. This is the worst "field contradicting type domain" case in the file (#16). + +### H6. `Environment` overload — minimal interface, generic word +- **Location:** `model.ts:1835`. +- **Category:** Vague/generic (#1), reserved-word collision (#10). +- **Suggestion:** Rename to `TaskEnvironment` (matching the per-task `environment_key` reference) or `EnvironmentSpec`. +- **Rationale:** `Environment` is a host-level concept in Node (`process.env`) and a common UI/test-framework type. Inside this file it is a tiny dep-list + base-env reference; it is referenced as `JobEnvironment.spec: Environment`, so a `Spec` suffix matches its role. + +### H7. `Repair` lacks a noun and is mistaken for a verb +- **Location:** `model.ts:3097`. +- **Category:** Verb-tense inconsistency (#13), vague/generic (#1). +- **Suggestion:** Rename to `RepairHistoryEntry` (or `RepairAttempt`) — it represents a single past repair. +- **Rationale:** The verb `repair()` exists on the client (`client.ts:570`), and `RepairRun`/`RepairRun_Response` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. + +### H8. `Webhook` is a generic top-level name that collides with the platform `Webhook` concept +- **Location:** `model.ts:5000`. +- **Category:** Vague/generic (#1), reserved-word/global collision (#10). +- **Suggestion:** Rename to `WebhookRef` (or `JobWebhook`) — readers grep `Webhook` expecting the request/payload shape, but the actual Webhook _payload_ is `WebhookNotifications`. The bare `Webhook` token is the wrong claimant for that name. +- **Rationale:** "Webhook" is a broad industry term and the actual delivery payload lives under a different identifier; the unqualified type-name should belong to the canonical shape, not to a Jobs-specific reference. + +### H9. `Subscription` and `AlertTaskSubscriber` / `SqlTaskSubscription` are three near-identical shapes +- **Location:** `model.ts:4656` (`Subscription`), `model.ts:836` (`AlertTaskSubscriber`), `model.ts:4580` (`SqlTaskSubscription`), `model.ts:4669` (`Subscription_Subscriber`). +- **Category:** Duplicate concepts (#12), inconsistent naming (#17). +- **Suggestion:** Standardize on `Subscriber` for the leaf type and `SubscriptionList` (or just `Subscription`) for the container. Avoid mixing `Subscriber` (alert), `Subscription` (sql), and `Subscription_Subscriber` (dashboard). +- **Rationale:** Each task type re-invents the same `userName | destinationId` oneof under a different name. This is a porting artifact, not a domain distinction. + +### H10. `TerminationCode_Code` — proto-name leakage on a public enum +- **Location:** `model.ts:632`, `model.ts:499` (`QueueDetailsCode_Code`), `model.ts:717` (`TerminationType_Type`). +- **Category:** Type-suffix tautology (#20), Go/Java-style names (#14). +- **Suggestion:** Lift to `TerminationCode`, `QueueReasonCode`, and `TerminationType`; the proto-wrapper underscore should not appear in public TS identifiers. +- **Rationale:** `TerminationCode_Code.SUCCESS` reads as `Code.Code.SUCCESS`. The repeated token is a porting artifact from the Go SDK's proto-message naming. + +### H11. `RunLifecycleStateV2_State` — versioned + tautological enum +- **Location:** `model.ts:532`, related `model.ts:518` (`RunLifeCycleState_RunLifeCycleState`). +- **Category:** Type-suffix tautology (#20), versioned API leakage. +- **Suggestion:** Rename to `RunLifecycleState` (current canonical, drop V1) and `RunStatusState` (legacy). The `V2` suffix should be hidden behind the SDK version, not part of TypeScript identifiers. +- **Rationale:** Consumers shouldn't pick between v1/v2 enums based on a suffix; the SDK should pick one. The dual identifier guarantees confusion. + +### H12. `Run.numberInJob` always equals `Run.runId` — meaningless field +- **Location:** `model.ts:3422`, `model.ts:2107`, `model.ts:3759`. +- **Category:** Misleading names (#6), generic field names losing meaning (#15). +- **Suggestion:** Drop or alias; if it must stay for back-compat, document the duplication on the field rather than the type. +- **Rationale:** The comment "This is set to the same value as `run_id`" makes the field a no-op. New TS users will assume it's distinct. + +### H13. `RunNow_Response.numberInJob` reused +- **Location:** `model.ts:3759`. +- **Category:** Misleading names (#6). +- **Suggestion:** Same as H12 — remove or rename to `runIdAlias`. +- **Rationale:** Same dead duplication on the response. + +### H14. `Format` enum value `SINGLE_TASK` is semantically dead +- **Location:** `model.ts:150-153`. +- **Category:** Misleading names (#6). +- **Suggestion:** Mark `SINGLE_TASK` with `@deprecated` (the JSDoc on `CreateJob.format` says it's always `MULTI_TASK`). +- **Rationale:** Exposing a value the server will never return is a footgun. + +### H15. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition +- **Location:** `model.ts:305`. +- **Category:** Misleading names (#6). +- **Suggestion:** Document inline, or rename to `NO_FAILURES_AT_LEAST_ONE_RAN`. Alternatively, `AT_LEAST_ONE_SUCCESS_NONE_FAILED`. +- **Rationale:** The enum-level JSDoc clarifies "none failed AND at least one was executed" — this is non-obvious from the name. + +### H16. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion +- **Location:** `model.ts:199`, `model.ts:208`, `model.ts:2642`, `model.ts:2650`. +- **Category:** Singular/plural mismatch (#9), redundant suffixes (#8). +- **Suggestion:** `JobsHealthRule` and `JobsHealthRules` differ only by `s` and the inner wraps a `rules?: JobsHealthRule[]`. Flatten — make the array the public shape (call it `HealthRules` or just `HealthRule[]`). +- **Rationale:** Hairsplitting wrappers around arrays force consumers to write `{rules: [...]}` instead of `[...]`. Plural type names alongside singular ones are the most error-prone pattern in this file. + +### H17. `JobsHealth*` prefix is inconsistent — `Jobs` is plural +- **Location:** `model.ts:199`, `model.ts:208`, `model.ts:2642`, `model.ts:2650`. +- **Category:** Singular/plural mismatch (#9), Go/Java-style names (#14). +- **Suggestion:** Use the singular product noun: `JobHealthMetric`, `JobHealthRule`. Or just `HealthMetric` if global. +- **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). + +### H18. `RunNow_Response.runId` field is the "newly triggered run" — confusingly typed `number` +- **Location:** `model.ts:3757`. +- **Category:** Underspecified IDs (#19). +- **Suggestion:** Add a branded type alias `RunId = number & {readonly __brand: 'RunId'}` or use `string` to match `bigint`-safe APIs. +- **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId` (string!), `dbtPlatformJobRunId` (string!). + +### H19. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` +- **Location:** `model.ts:1712`, `model.ts:1744`. +- **Category:** Field contradicting type domain (#16), misleading names (#6). +- **Suggestion:** Standardize on `string` for upstream IDs; note in JSDoc. +- **Rationale:** Same semantic field encoded as two different TS types in adjacent interfaces is a bug magnet. + +### H20. `GetRunOutput_Response.result` oneof tag is `notebookOutput` but the field discriminates "task" type — misleading +- **Location:** `model.ts:2204-2257`. +- **Category:** Misleading names (#6). +- **Suggestion:** Rename `result` to `taskOutput` (since the union members are `notebookOutput | sqlOutput | dbtOutput | ...`). Then `result` could refer to a higher-level `RunResultState` field that semantically belongs there. +- **Rationale:** `result` on a run-output type is confusable with `RunResultState`, and `Run.status.terminationDetails.message` is also "the result". + +### H21. `Run_JobLevelParameters` confusingly named with proto underscore and "parameters" plural for a single record +- **Location:** `model.ts:3506`. +- **Category:** Underscores in TS identifiers (#4), singular/plural mismatch (#9). +- **Suggestion:** Rename to `RunJobParameter` (singular — it's an array element with `name`, `default`, `value` for one parameter). +- **Rationale:** It is used as `jobParameters?: Run_JobLevelParameters[]` — a `Parameters[]` typing is a hard read. + +### H22. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous +- **Location:** `model.ts:3515`. +- **Category:** Misleading names (#6). +- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3991). +- **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? + +### H23. `RunJobTask_RunJobTaskOutput` is "double-stuttered" +- **Location:** `model.ts:3613`. +- **Category:** Type-suffix tautology (#20), Go/Java-style names (#14). +- **Suggestion:** Rename to `RunJobTaskOutput` (no wrapping namespace prefix needed in TS). +- **Rationale:** `RunJobTask_RunJobTaskOutput` repeats the parent name; a flat name is shorter and equally clear in TS. + +### H24. `client.cancelAllRuns` request type `CancelAllRuns` (not `CancelAllRunsRequest`) but response is `CancelAllRuns_Response` +- **Location:** `model.ts:1099`, `model.ts:1108`, `client.ts:124`. +- **Category:** Inconsistent suffix conventions (#17), redundant suffixes (#8). +- **Suggestion:** Pick one: either `CancelAllRunsRequest` + `CancelAllRunsResponse`, or `CancelAllRuns` + `CancelAllRunsResult`. +- **Rationale:** Mixing zero-suffix on the request and `_Response` on the response is a porting smell ("the response wraps the proto Response message"). It also makes JSDoc grepping harder. + +### H25. `Repair.id` vs `RepairRun_Response.repairId` +- **Location:** `model.ts:3107`, `model.ts:3236`. +- **Category:** Generic field names losing meaning (#15), inconsistent naming (#17). +- **Suggestion:** Rename `Repair.id` to `repairId`. +- **Rationale:** A bare `id` field on a type called `Repair` is technically OK but breaks the workspace convention of always disambiguating IDs. + +### H26. `BaseJob` and `GetJob_Response` and `Run` duplicate ~12 identical fields +- **Location:** `model.ts:969`, `model.ts:2040`, `model.ts:3414`, `model.ts:1008`. +- **Category:** Duplicate concepts (#12). +- **Suggestion:** Extract a shared `JobIdentity` / `JobCoreFields` interface or use TS `Pick`/`Omit` on a base shape. +- **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId`, `path` are repeated verbatim in `BaseJob` and `GetJob_Response`. Diverges silently. + +### H27. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums +- **Location:** `model.ts:3867`, `model.ts:3881`. +- **Category:** Duplicate concepts (#12), versioned API leakage (#11). +- **Suggestion:** Pick `RunStatus` as the canonical shape, deprecate `RunState`, and document the deprecation in the rule. +- **Rationale:** The JSDoc on `Run.state` already says "Deprecated. Please use the `status` field instead." but the type is still exported and still shows up in the union. + +### H28. `RunState.userCancelledOrTimedout` — typo + boolean-of-two-things +- **Location:** `model.ts:3875`. +- **Category:** Misleading names (#6). +- **Suggestion:** Fix spelling to `userCancelledOrTimedOut`. Better, split into `cancelledByUser: boolean` and `timedOut: boolean`. +- **Rationale:** Compound booleans (X-or-Y) are an anti-pattern. The current name silently drops one bit of info. + +### H29. `DataSecurityMode` enum mixes prefixed and unprefixed values +- **Location:** `model.ts:94-126`. +- **Category:** Redundant enum prefixes (#2), inconsistent naming (#17). +- **Suggestion:** Drop the `DATA_SECURITY_MODE_` prefix on the three alias values; either all values share a prefix, or none do. Currently we have `NONE`, `SINGLE_USER`, `USER_ISOLATION`, ..., `DATA_SECURITY_MODE_STANDARD`, `DATA_SECURITY_MODE_DEDICATED`, `DATA_SECURITY_MODE_AUTO`. +- **Rationale:** The reader can't predict whether they need `DataSecurityMode.AUTO` or `DataSecurityMode.DATA_SECURITY_MODE_AUTO` — they have to read the file. + +### H30. `RunLifeCycleState_RunLifeCycleState` is misspelled internally and externally +- **Location:** `model.ts:518`. +- **Category:** Acronym/word casing (#3), Go/Java-style names (#14). +- **Suggestion:** Spell as one word: `RunLifecycleState_RunLifecycleState`. Better, drop the redundancy entirely: `RunLifecycleState`. +- **Rationale:** "Lifecycle" is one word in modern usage (per OED). Mixing `LifeCycle` and `Lifecycle` (compare H11 — `RunLifecycleStateV2_State` — already one word) within the same file is the worst kind of acronym-casing inconsistency. + +### H31. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) +- **Location:** `model.ts:413`, `model.ts:501`, `model.ts:565`, `model.ts:685`. +- **Category:** Long enum values, inconsistent naming (#17, #18). +- **Suggestion:** Normalize to one form. The `MAX_` form is more common; reach-vs-exceed should pick one verb. +- **Rationale:** Three enums describe the same overflow scenario with three different names. Consumers cannot write a generic handler. + +### H32. `RunLifeCycleState_RunLifeCycleState` is missing `QUEUED` in some doc-orderings but `RunLifecycleStateV2_State.QUEUED` is present +- **Location:** `model.ts:518-528`, `model.ts:532-544`. +- **Category:** Versioned API leakage, inconsistent enums. +- **Suggestion:** Document the migration table at the top of the file. +- **Rationale:** Type checks against the V1 enum that branch on `QUEUED` are silently wrong vs V2. + +### H33. `client.repair` and `client.repairWaiter` — verb mismatch with the request type +- **Location:** `client.ts:570`, `client.ts:595`. +- **Category:** Inconsistent action verbs (#17). +- **Suggestion:** Either name the method `repairRun` to match the type `RepairRun`, or rename the request type `Repair` to match the method. +- **Rationale:** All other client methods follow `verbNoun(NounVerb)` or `verbNoun(VerbNoun)` consistently; `repair(RepairRun)` is the outlier. + +### H34. `client.exportRun` returns `ExportRun_Response` which contains a `views` array of `ViewItem` +- **Location:** `client.ts:268`, `model.ts:1864`, `model.ts:4982`. +- **Category:** Vague/generic (#1). +- **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. +- **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. + +### H35. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint +- **Location:** `model.ts:350`, `model.ts:360`. +- **Category:** Duplicate concepts (#12). +- **Suggestion:** Merge or namespace: `View.Type` (NOTEBOOK | DASHBOARD) and `View.ExportSelector` (CODE | DASHBOARDS | ALL). +- **Rationale:** Two enums about "views" with different value sets and intent. Users will pick the wrong one. + +### H36. `GitSource.gitReference` discriminator is named `gitBranch | gitTag | gitCommit` — but the parent has `gitUrl` / `gitProvider` (no `git` prefix on the data) +- **Location:** `model.ts:2286-2312`. +- **Category:** Inconsistent naming (#17), redundant prefixes (#2). +- **Suggestion:** Make the oneof tags `branch | tag | commit` — the parent's `GitSource.git*` prefix already provides namespace. +- **Rationale:** `gitSource.gitReference.gitBranch` is needless repetition. + +### H37. `cancelRunWaiter` polls on `RunLifeCycleState_RunLifeCycleState` (V1) while the modern field is `RunStatus.state` +- **Location:** `client.ts:742-820`. +- **Category:** Versioned API leakage. +- **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. +- **Rationale:** Future deprecation of V1 will silently break all four waiters. + +--- + +## Medium + +### M1. `Adlsgen2Info` casing — should be `ADLSGen2Info` or `AdlsGen2Info` +- **Location:** `model.ts:734`, `index.ts:64`. +- **Category:** Acronym/word casing (#3). +- **Suggestion:** Use `AdlsGen2Info` (acronym + version + "Info"). ADLS stays uppercase only when alone. +- **Rationale:** The Google TS style guide treats acronyms longer than two letters as words (e.g. `Adls`), but `gen2` should be `Gen2`. + +### M2. `AwsAttributes` / `AzureAttributes` / `GcpAttributes` — accept casing +- **Location:** `model.ts:861`, `model.ts:941`, `model.ts:1915`. +- **Category:** Acronym casing (#3). +- **Suggestion:** OK as `Aws/Azure/Gcp`, consistent with style guide. +- **Rationale:** All three already follow "first letter only" — good baseline. + +### M3. `DbtTask` / `DbtCloudTask` / `DbtPlatformTask` / `DbtPlatformJobRunStep` — acronym casing +- **Location:** `model.ts:1753`, `model.ts:1702`, `model.ts:1735`, `model.ts:1720`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Already follows "Dbt"; OK. +- **Rationale:** Three-letter ID treated as a word — consistent. + +### M4. `EbsVolume*` and `Ebs*` — keep +- **Location:** `model.ts:908`, `model.ts:927`, `model.ts:933`, `model.ts:143`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Keep as `Ebs*`. Consistent with TS style guide. +- **Rationale:** — + +### M5. `GcsStorageInfo` — `Gcs` casing +- **Location:** `model.ts:1972`. +- **Category:** Acronym casing (#3). +- **Suggestion:** OK; consistent with file. + +### M6. `S3StorageInfo` — `S3` (number) keeps caps +- **Location:** `model.ts:4284`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Keep — `S3` is a brand name, kept as-is. + +### M7. `Dbfs*` types — keep +- **Location:** `model.ts:1681`, `model.ts:106`. +- **Category:** Acronym casing (#3). +- **Suggestion:** OK; consistent. + +### M8. `PowerBi*` casing (vs `PowerBI`) +- **Location:** `model.ts:2992`, `model.ts:3005`, `model.ts:3023`, `model.ts:174-175`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Brand-style "BI" is industry-standard caps; consider `PowerBI*`. The Microsoft brand is "Power BI". Currently mixed: type uses `PowerBi`, JSDoc uses `Power BI`. +- **Rationale:** Per the TS style guide, "BI" is an acronym (Business Intelligence), so `PowerBI` is correct. Going with `PowerBi` is inconsistent with `SqlTask` (3 letters). + +### M9. `SqlTask` / `SqlAlertState` / etc. — `Sql` lower or upper? +- **Location:** `model.ts:4414`, `model.ts:4380`, `model.ts:581`, `model.ts:588`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Either `Sql` everywhere (current) or `SQL` everywhere. Pick one. +- **Rationale:** The TS style guide allows acronyms of 3+ letters to be word-cased (`Sql`); this is consistent in this file. Note however the JSDoc still writes "SQL" — fine for prose. + +### M10. `HardwareAcceleratorType` enum values `GPU_1xA10`, `GPU_8xH100`, `GPU_1xH100` (lowercase `x`) +- **Location:** `model.ts:170-177`. +- **Category:** Naming convention violation in enum value strings. +- **Suggestion:** The TS enum keys are properly `GPU_1X_A10`, but the values keep the wire form. This is OK since the wire is contract — but flag the asymmetry inline. +- **Rationale:** Wire compatibility forces lowercase `x`; the enum key uppercase is fine. + +### M11. `ComputeKind.COMPUTE_KIND_UNSPECIFIED` — redundant enum prefix +- **Location:** `model.ts:56`. +- **Category:** Redundant enum prefixes (#2). +- **Suggestion:** Drop the redundant prefix on `_UNSPECIFIED` if the wire allows. If wire-locked, accept. +- **Rationale:** Proto-style "X_UNSPECIFIED" enum sentinels are common; TS could surface as `ComputeKind.UNSPECIFIED`. Document that wire compatibility was the reason. + +### M12. `ConfidentialComputeType.CONFIDENTIAL_COMPUTE_TYPE_UNSPECIFIED` / `CONFIDENTIAL_COMPUTE_TYPE_NONE` +- **Location:** `model.ts:67-68`. +- **Category:** Redundant enum prefixes (#2). +- **Suggestion:** Same as M11; would prefer `UNSPECIFIED` / `NONE`. + +### M13. `DbtPlatformRunStatus.DBT_PLATFORM_RUN_STATUS_UNSPECIFIED` +- **Location:** `model.ts:130`. +- **Category:** Redundant enum prefixes (#2). + +### M14. `RefreshGranularity` and `RefreshPolicyMode` values +- **Location:** `model.ts:213-223`, `model.ts:226-232`. +- **Category:** Redundant enum prefixes (#2). +- **Suggestion:** `RefreshGranularity.DAY` instead of `REFRESH_GRANULARITY_DAY`. + +### M15. `AwsAvailability.SPOT_WITH_FALLBACK` vs `AzureAvailability.SPOT_WITH_FALLBACK_AZURE` +- **Location:** `model.ts:24`, `model.ts:40`, `model.ts:162`. +- **Category:** Redundant enum prefixes (#2). +- **Suggestion:** Drop the `_AZURE` / `_GCP` suffixes — the enclosing enum name already disambiguates. +- **Rationale:** `AzureAvailability.SPOT_WITH_FALLBACK_AZURE` reads as "SpotWithFallbackAzure on AzureAvailability". The cloud is encoded twice. Same issue for GCP: `PREEMPTIBLE_WITH_FALLBACK_GCP`. + +### M16. `TriggerType.RUN_JOB_TASK` is named after a task type, not a trigger +- **Location:** `model.ts:339`. +- **Category:** Misleading names (#6). +- **Suggestion:** Rename to `RUN_JOB`. +- **Rationale:** "Run Job Task" duplicates the task-type tag inside an enum about triggers. + +### M17. `RunType.JOB_RUN` / `WORKFLOW_RUN` / `SUBMIT_RUN` — `_RUN` suffix is the enum's own purpose +- **Location:** `model.ts:250-252`. +- **Category:** Redundant enum prefixes (#2). +- **Suggestion:** `JOB`, `WORKFLOW`, `SUBMIT` (or `ONE_TIME`). + +### M18. `RuntimeEngine.NULL` (versus `STANDARD`, `PHOTON`) +- **Location:** `model.ts:260`. +- **Category:** Reserved-word collision (#10), vague/generic (#1). +- **Suggestion:** Rename to `DEFAULT` or `UNSPECIFIED`. `NULL` is a TS/JS keyword (lowercase `null`) and reserved word in other languages. + +### M19. `JobsHealthMetric.RUN_DURATION_SECONDS` — long but OK +- **Location:** `model.ts:200`. +- **Category:** Long enum values (#18). +- **Suggestion:** Acceptable. + +### M20. `JobsHealthMetric.STREAMING_BACKLOG_*` (4 values) +- **Location:** `model.ts:201-204`. +- **Category:** Long enum values (#18). +- **Suggestion:** Acceptable; consider grouping into a nested enum if the four become five. + +### M21. `Repair.startTime` / `Repair.endTime` (epoch ms) +- **Location:** `model.ts:3101-3103`. +- **Category:** Generic field names losing meaning (#15). +- **Suggestion:** Document units in name: `startTimeMs` or use a `Date`-typed alias. +- **Rationale:** TS `number` for milliseconds is the same shape as TS `number` for seconds. Cf. `timeoutSeconds` (which DOES carry the unit). + +### M22. `CreateJob.timeoutSeconds` (seconds) vs `CreateJob.minRetryIntervalMillis` (ms) — unit-suffix inconsistency +- **Location:** `model.ts:1515`, `model.ts:1600`. +- **Category:** Inconsistent unit suffixes (#17). +- **Suggestion:** Use one unit (preferably `Ms` or `Seconds` for everything). At least pick one. +- **Rationale:** Within one settings object, seconds and millis differ only by a 3-letter suffix; easy to misuse. + +### M23. `FileArrivalTriggerConfiguration.minTimeBetweenTriggersSeconds` — extremely long +- **Location:** `model.ts:1885`. +- **Category:** Overly verbose (#7). +- **Suggestion:** Acceptable since unit is encoded; can drop "Triggers" since the type already says it: `minTimeBetweenFiringsSeconds` or `minIntervalSeconds`. + +### M24. `WaitAfterLastChangeSeconds` — appears identically in three triggers +- **Location:** `model.ts:1891`, `model.ts:2864`, `model.ts:4713`. +- **Category:** Verbose, repetitive (#7). +- **Suggestion:** OK, document once. + +### M25. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) +- **Location:** `model.ts:1141`, `model.ts:1126`. +- **Category:** Singular/plural mismatch (#9). +- **Suggestion:** Pick one. `CleanRoom*` (singular) is consistent with the standalone product "Clean Rooms" being treated as a singular feature. + +### M26. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL +- **Location:** `model.ts:1143`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Acceptable; brand inconsistency is upstream's responsibility. + +### M27. `AlertTask.workspacePath` — uses `workspacePath` while elsewhere it's `path` +- **Location:** `model.ts:820`, `model.ts:1005`. +- **Category:** Inconsistent naming (#17). +- **Suggestion:** Make all "path" fields workspace-prefixed (`BaseJob.path` → `workspacePath`). + +### M28. `BaseJob.path` is documented as workspace path but field is bare +- **Location:** `model.ts:1005`. +- **Category:** Generic field names (#15). +- **Suggestion:** Rename to `workspacePath`. Matches `AlertTask.workspacePath`. + +### M29. `DbtCloudJobRunStep` (deprecated) and `DbtPlatformJobRunStep` (new) +- **Location:** `model.ts:1690`, `model.ts:1720`. +- **Category:** Versioned API leakage. +- **Suggestion:** OK while transition is documented; reconsider after dbt Cloud is dropped. + +### M30. `DbtTask_DbtTaskOutput` — proto stutter +- **Location:** `model.ts:1781`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `DbtTaskOutput`. + +### M31. `NotebookTask_NotebookOutput` +- **Location:** `model.ts:2918`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `NotebookTaskOutput`. + +### M32. `ClusterSpec_NewCluster` — nested name is verbose; would be just `NewClusterSpec` +- **Location:** `model.ts:1253`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `NewClusterSpec`. + +### M33. `CleanRoomsNotebookTask_CleanRoomsNotebookTaskOutput` +- **Location:** `model.ts:1156`. +- **Category:** Type-suffix tautology (#20) — extreme. +- **Suggestion:** Rename to `CleanRoomsNotebookTaskOutput`. + +### M34. `RunJobTask_RunJobTaskOutput` +- **Location:** `model.ts:3613`. +- **Category:** Type-suffix tautology (#20) (also flagged in H23). + +### M35. `SqlTask_*` family — six output types +- **Location:** `model.ts:4452`, `model.ts:4465`, `model.ts:4473`, `model.ts:4491`, `model.ts:4512`, `model.ts:4518`, `model.ts:4531`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Drop the `SqlTask_` prefix in TS: `SqlAlertOutput`, `SqlDashboardOutput`, `SqlDashboardWidgetOutput`, `SqlOutput`, `SqlOutputError`, `SqlQueryOutput`, `SqlStatementOutput`. + +### M36. `ResolvedValues_*` family — 11 sub-types +- **Location:** `model.ts:3303-3412`. +- **Category:** Type-suffix tautology (#20), Go/Java-style names (#14). +- **Suggestion:** Hoist into `ResolvedValues` (e.g., `NotebookTaskResolvedValues`) without the `ResolvedValues_` prefix. + +### M37. `SparkJarTask.jarUri` (deprecated) — already deprecated +- **Location:** `model.ts:4328`. +- **Category:** OK as docstring; ensure `@deprecated` JSDoc tag added. + +### M38. `SparkJarTask.runAsRepl` — deprecated; values restricted +- **Location:** `model.ts:4342`. +- **Category:** Vague/misleading (#6). +- **Suggestion:** `@deprecated`. Comment says "A value of `false` is no longer supported." + +### M39. `JobLevelParameter.default` — `default` is a TS keyword in some positions +- **Location:** `model.ts:2475`, `model.ts:3510`. +- **Category:** Reserved-word collision (#10). +- **Suggestion:** Rename to `defaultValue`. +- **Rationale:** `default` is a reserved word as a `case` label and `switch` token. Object property `default` is legal but trips linters and confuses code editors. + +### M40. `JobsHealthRule.op` and `ConditionTask.op` — short, opaque +- **Location:** `model.ts:2644`, `model.ts:1485`. +- **Category:** Cryptic abbreviations (#5). +- **Suggestion:** Rename to `operator`. +- **Rationale:** `op` saves one word but is too terse for a public API. + +### M41. `Repair.type` (RepairType) is a reserved-ish word +- **Location:** `model.ts:3099`, `model.ts:4988`. +- **Category:** Reserved-word collision (#10). +- **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. + +### M42. `RunStatus.state` — `state` is generic +- **Location:** `model.ts:3882`. +- **Category:** Generic field names (#15). +- **Suggestion:** Acceptable in context (the type is `RunStatus`), but consider `lifecycleState` to match V1. + +### M43. `RunNow.only` field — what does "only" mean? +- **Location:** `model.ts:3653`. +- **Category:** Cryptic abbreviations (#5), misleading names (#6). +- **Suggestion:** Rename to `taskKeysToRun` or `runOnlyTasks`. +- **Rationale:** A standalone `only: string[]` field on a request is a riddle. + +### M44. `RunNow.idempotencyToken`, `SubmitRun.idempotencyToken` — OK +- **Location:** `model.ts:3649`, `model.ts:4619`. +- **Category:** Verbose but precise. + +### M45. `RepairRun.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern +- **Location:** `model.ts:3126-3132`. +- **Category:** Consistent prefix; OK. + +### M46. `RepairRun.latestRepairId` vs `RepairRun_Response.repairId` (no `latest`) +- **Location:** `model.ts:3124`, `model.ts:3236`. +- **Category:** Inconsistent naming (#17). +- **Suggestion:** Document the semantic: request takes "the previous latest", response returns "the new latest". + +### M47. `SqlTask.sqlTaskType` oneof name is type-tautological +- **Location:** `model.ts:4417`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `target` or `kind`. The wrapper is already `SqlTask`. + +### M48. `SqlTask_SqlOutput.sqlOutputType` — same tautology +- **Location:** `model.ts:4492`. +- **Category:** Type-suffix tautology (#20). + +### M49. `Subscription_Subscriber.subscriptionType` +- **Location:** `model.ts:4670`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename oneof tag to `target`. + +### M50. `AlertTaskSubscriber.subscriberType` +- **Location:** `model.ts:837`. +- **Category:** Type-suffix tautology (#20). + +### M51. `DockerImage.credsOneof` — exposes proto oneof name to TS +- **Location:** `model.ts:1822`. +- **Category:** Go/Java-style names (#14). +- **Suggestion:** Rename to `credentials` or `auth`. + +### M52. `JobRunAs.identity` — OK +- **Location:** `model.ts:2484`. + +### M53. `AccessControlRequest.principalName` oneof name doesn't match the contents +- **Location:** `model.ts:725`. +- **Category:** Misleading names (#6). +- **Suggestion:** Rename to `principal` — the discriminants are `userName | groupName | servicePrincipalName`, not three different name-shaped values. + +### M54. `RunTriggerInfo.runId` — what kind of runId? +- **Location:** `model.ts:4280`. +- **Category:** Underspecified IDs (#19). +- **Suggestion:** Rename to `parentRunId` or `triggeringRunId` (JSDoc says "The run id of the Run Job task run"). + +### M55. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix +- **Location:** `model.ts:2426`. +- **Category:** Acceptable; key is the lookup pattern. + +### M56. `JobEnvironment.environmentKey` — same pattern, OK. +- **Location:** `model.ts:2467`. + +### M57. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy +- **Location:** `model.ts:4737`, `model.ts:3917`, `model.ts:4106`, `model.ts:4726`. +- **Category:** Verbose but precise. + +### M58. `TaskDependency.taskKey` (the task being depended on) — could be `dependsOnTaskKey` +- **Location:** `model.ts:4726`. + +### M59. `TaskDependency.outcome` — value of a condition task: should be `condition` or `requiredOutcome` +- **Location:** `model.ts:4728`. +- **Category:** Generic field names (#15). + +### M60. `ResolvedValues` interface has 11 single-purpose sub-types +- **Location:** `model.ts:3262-3412`. +- **Category:** Verbose; many shapes for one purpose. +- **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. + +### M61. `ClusterSpec.spec` (inside `ClusterSpec`) — name-tautology +- **Location:** `model.ts:1223`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename oneof to `target` or `cluster`. + +### M62. `RunTask.spec` (same pattern) +- **Location:** `model.ts:4046`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename oneof to `cluster`. + +### M63. `RunTaskSettings.spec`, `TaskSettings.spec` — same +- **Location:** `model.ts:4235`, `model.ts:4875`. +- **Category:** Type-suffix tautology (#20). + +### M64. `RunTask.task` — oneof inside a type called `RunTask` whose oneof is the task body — tautology +- **Location:** `model.ts:3948`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename oneof to `body` or `payload`. + +### M65. `BaseRun.numberInJob` — meaningless field (see H12) +- **Location:** `model.ts:1016`. + +### M66. `BaseRun.originalAttemptRunId` — verbose, but precise. + +### M67. `BaseRun.runName` vs `BaseRun.runPageUrl` vs `BaseRun.runType` — repeated `run` prefix on a `BaseRun` type +- **Location:** `model.ts:1034`, `model.ts:1036`, `model.ts:1037`. +- **Category:** Redundant prefix (#2). +- **Suggestion:** Drop `run` prefix when already inside `Run*` type: `name`, `pageUrl`, `type`. + +### M68. `Run.runId` (inside `Run`) — tautological +- **Location:** `model.ts:3418`, `model.ts:1012`, `model.ts:2103`, `model.ts:3892`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. + +### M69. `Run.jobRunId` field while the type is already a job run +- **Location:** `model.ts:3474`. +- **Category:** Underspecified IDs (#19). +- **Suggestion:** Document `runId vs jobRunId` more clearly; consider `parentJobRunId`. + +### M70. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRun_Response` — could be deduped +- **Location:** `model.ts:1042`, `model.ts:3448`, `model.ts:2133`. + +### M71. `RunNow_Response.numberInJob` (see H13). + +### M72. `ListJobs.limit` vs `ListRuns.limit` documentation discrepancy +- **Location:** `model.ts:2723`, `model.ts:2782`. +- **Category:** Inconsistent docs (not naming, but worth flagging). +- **Suggestion:** Document max values explicitly; `ListJobs` says ≤100, `ListRuns` says <25. + +### M73. `ListJobs.offset` deprecated by `pageToken` — but both still typed +- **Location:** `model.ts:2721`. +- **Category:** Deprecation hygiene. +- **Suggestion:** Add `@deprecated` JSDoc to `offset`. + +### M74. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) +- **Location:** `model.ts:736`, similar in `DbfsStorageInfo`, `S3StorageInfo`, `GcsStorageInfo`, `LocalFileInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. +- **Category:** Generic field names (#15). +- **Suggestion:** Each storage type has different URI semantics; `destination` is fine since it's polymorphic, but document the form. + +### M75. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type +- **Location:** `model.ts:280`. +- **Category:** Type design. +- **Suggestion:** Could be `type CodeSource = 'WORKSPACE' | 'GIT'`. Same for `Format`, `ViewType`, etc. + +### M76. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead +- **Location:** `model.ts:150-153`. +- **Category:** Dead enum value. + +### M77. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` +- **Location:** `model.ts:378`. +- **Category:** Generic enum value (#1). +- **Suggestion:** `UNKNOWN` is universally vague; consider `NOT_EVALUATED`. + +### M78. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) +- **Location:** `model.ts:593`, `model.ts:564`, `model.ts:136`. +- **Category:** Inconsistent naming (#17). +- **Suggestion:** Pick one spelling; "canceled" (single-L) is the American spelling, "cancelled" is the British. Cross-checking with go SDK keeps wire compat. + +### M79. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) +- **Location:** `model.ts:693`, `model.ts:634`. +- **Category:** Overlapping enum values (#12). +- **Suggestion:** Document distinction (one is user-initiated, the other is platform-initiated). + +### M80. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +- **Location:** `model.ts:5029`, `model.ts:5033`. +- **Category:** Singular/plural mismatch (#9). +- **Suggestion:** Rename to `ClientTypes`. + +### M81. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) +- **Location:** `model.ts:3090`. +- **Category:** Acronym casing (#3). +- **Suggestion:** Cran is an acronym (CRAN = Comprehensive R Archive Network). `RLibrary` works too. The `R` prefix is from the Go SDK. + +### M82. `PythonPyPiLibrary` — duplicate "Py" prefix +- **Location:** `model.ts:3041`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). + +### M83. `MavenLibrary.coordinates` — common, accept. +- **Location:** `model.ts:2828`. + +### M84. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. + +### M85. `RunNow.pythonNamedParams` (no suffix `_NamedParametersEntry`?) +- **Location:** `model.ts:3714`. +- **Category:** Inconsistent naming (#17). +- **Suggestion:** Rename to `pythonNamedParameters` to match `notebookParams` being plain; or rename all `*Params` to `*Parameters` consistently. Currently: `jobParameters` (plural Parameters), `notebookParams` (Params), `pythonParams`, `pythonNamedParams`, `sparkSubmitParams`, `sqlParams`, `dbtCommands`, `pipelineParams`, `jarParams`. + +### M86. `ListJobs.expandTasks`, `ListRuns.expandTasks` — `boolean` flag is fine. + +### M87. `ListRuns.runType` shouldn't be optional when the API permits a default +- **Location:** `model.ts:2784`. +- **Category:** Default semantics. + +--- + +## Low + +### L1. `Adlsgen2Info` — see M1. +### L2. `WorkloadType_ClientsTypes` — see M80. +### L3. `IncrementalRefreshConfig.onlyRefreshCompletePeriods` — long but precise. +- **Location:** `model.ts:2339`. + +### L4. `IncrementalRefreshConfig.detectDataChanges` — boolean naming; acceptable. + +### L5. `IncrementalRefreshConfig.mode: RefreshPolicyMode` +- **Location:** `model.ts:2345`. +- **Category:** Generic field name (#15). +- **Suggestion:** Rename to `policyMode` or `refreshMode`. + +### L6. `IncrementalRefreshConfig.archiveWindowPeriods` / `refreshWindowPeriods` — `Periods` plural noun on each pair; could be reduced. + +### L7. `PowerBiTable.incrementalRefreshDatetimeColumn` — very long +- **Location:** `model.ts:3020`. +- **Category:** Overly verbose (#7). +- **Suggestion:** Rename to `partitionColumn` and document `incremental_refresh` in JSDoc. + +### L8. `PowerBiModel.modelName` — `modelName` inside `PowerBiModel` — type-suffix tautology +- **Location:** `model.ts:2996`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `name`. + +### L9. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). + +### L10. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. + +### L11. `AccessControlRequest.principalName` oneof — see M53. + +### L12. `QueueDetails.message` and `QueueDetails.code` — OK. + +### L13. `SqlConditionConfiguration.sqlQueryId` — `Sql` prefix duplicates `SqlCondition` namespace +- **Location:** `model.ts:4384`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** Rename to `queryId`. + +### L14. `SqlConditionRunInfoDetails.conditionEvaluationSqlStatementId` (deprecated) +- **Location:** `model.ts:4395`. +- **Category:** Overly verbose (#7). + +### L15. `SqlConditionRunInfoDetails.conditionEvaluationSatisfied` +- **Location:** `model.ts:4397`. +- **Category:** Verbose. +- **Suggestion:** Rename to `satisfied`. + +### L16. `SqlConditionState.latestConditionEvaluation*` — same pattern, verbose. +- **Location:** `model.ts:4402-4411`. + +### L17. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. +- **Location:** `model.ts:2940`. + +### L18. `OutputSchemaInfo.expirationTime` (epoch ms) — same units issue as M21. + +### L19. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. + +### L20. `JobEmailNotifications.noAlertForSkippedRuns` (deprecated) — `@deprecated` recommended. + +### L21. `NotificationSettings.noAlertForSkippedRuns` / `noAlertForCanceledRuns` — `noAlertFor*` negative boolean prefix. +- **Location:** `model.ts:2931-2933`. +- **Category:** Negative-naming antipattern. +- **Suggestion:** Rename to `alertOnSkippedRuns` / `alertOnCanceledRuns` and invert defaults; or keep as documented to match wire. + +### L22. `NotificationSettings.alertOnLastAttempt` — opposite polarity to L21; mix is confusing. + +### L23. `WebhookNotifications.onDurationWarningThresholdExceeded` — very long field name (40+ chars). +- **Location:** `model.ts:5012`. +- **Category:** Overly verbose (#7). +- **Suggestion:** Acceptable since it encodes the metric; can shorten to `onDurationThresholdExceeded`. + +### L24. `WebhookNotifications.onStreamingBacklogExceeded` — accept. + +### L25. `ContinuousSettings.taskRetryMode` (enum) — OK. + +### L26. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. + +### L27. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. + +### L28. `CronSchedule.quartzCronExpression` — long but precise. + +### L29. `CronSchedule.sqlCondition: SqlConditionConfiguration` — naming OK. + +### L30. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. + +### L31. `JobSource.importFromGitReference` oneof, with one option `importFromGitBranch` — verbose oneof +- **Location:** `model.ts:2625`. +- **Category:** Verbose (#7). +- **Suggestion:** Rename oneof to `source`; rename option to `branch`. + +### L32. `JobDeployment.metadataFilePath` +- **Location:** `model.ts:2440`. +- **Category:** Verbose. + +### L33. `LogAnalyticsInfo.logAnalyticsWorkspaceId` / `logAnalyticsPrimaryKey` — `logAnalytics` prefix duplicates type name. +- **Location:** `model.ts:2822-2824`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** `workspaceId` and `primaryKey`. + +### L34. `GitSource.gitUrl` / `GitSource.gitProvider` / `GitSource.gitReference` — `git` prefix duplicates `GitSource`. +- **Location:** `model.ts:2287-2289`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** `url`, `provider`, `reference`. + +### L35. `Run.runName`, `runPageUrl`, `runType` (see M67). + +### L36. `BaseRun.startTime` / `endTime` / `setupDuration` / `executionDuration` / `cleanupDuration` / `endTime` / `runDuration` / `queueDuration` — units-in-name half-applied (Duration but not StartTime). +- **Location:** `model.ts:1083-1097`. +- **Category:** Inconsistent unit suffixes (#17). +- **Suggestion:** All durations are ms — make this uniform: `startTimeMs`, `setupDurationMs`, etc. + +### L37. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. +- **Location:** `model.ts:3491-3496`. +- **Category:** Field contradicting type domain (#16). +- **Suggestion:** Move to `RunTask` only, mark deprecated on `Run`. + +### L38. `RepairRun.dbtCommands` — present on `RunNow`, `RunJobTask`, `RepairRun`, `RunParameters`. +- **Location:** `model.ts:3205`, `model.ts:3585`, `model.ts:3726`, `model.ts:3836`. +- **Category:** Repeated identical fields — argues for shared `RunOverrideParameters` base. + +### L39. `RunNow.pipelineParams: PipelineParameters` — `Params` vs `Parameters` inconsistency (see M85). + +### L40. `SparkPythonTask.pythonFile` — `python` prefix already encoded in type name +- **Location:** `model.ts:4347`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** Rename to `file` or `script`. + +### L41. `SparkPythonTask.parameters` (string[]) — OK. + +### L42. `SparkJarTask.mainClassName` — `Name` suffix on `Class` is redundant +- **Location:** `model.ts:4334`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `mainClass`. + +### L43. `SparkJarTask.runAsRepl` (deprecated) — see M38. + +### L44. `Library.lib` oneof name is redundant +- **Location:** `model.ts:2655`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename to `source` or just inline the oneof fields. + +### L45. `Library.egg` (deprecated) — see top JSDoc. +- **Location:** `model.ts:2670`. + +### L46. `Library.cran: RCranLibrary` — see M81. + +### L47. `Library.requirements: string` (a requirements.txt URI) — OK. + +### L48. `InitScriptInfo.storageInfo` oneof — `storageInfo` is reused across `ClusterLogConf` and `InitScriptInfo`. +- **Location:** `model.ts:2359`, `model.ts:1192`. +- **Category:** Type-suffix tautology (#20). +- **Suggestion:** Rename oneof to `destination` or `target`. + +### L49. `AwsAttributes.spotBidPricePercent` — long but precise. + +### L50. `AzureAttributes.logAnalyticsInfo` — see L33. + +### L51. `GcpAttributes.usePreemptibleExecutors` — deprecated per JSDoc (use `availability`). +- **Location:** `model.ts:1921`. +- **Category:** Deprecation hygiene. + +### L52. `GcpAttributes.googleServiceAccount` — `google` prefix unnecessary inside `Gcp*` namespace. +- **Location:** `model.ts:1928`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** Rename to `serviceAccount`. + +### L53. `ClusterSpec_NewCluster.useMlRuntime` — `Ml` casing (vs `ML`); follows style. + +--- + +## Observations (whole-file patterns) + +### O1. The oneof `$case` discriminator convention is well-established and consistent +- Every oneof in the file uses `{$case: 'tag'; tag: T} | undefined`. +- This is a porting convention from `protobuf-ts`/`@bufbuild/protobuf-es`; it's noisy but consistent, and consumers can pattern-match cleanly. Keep. + +### O2. `RunLifeCycleState` (V1) vs `RunLifecycleStateV2` divergence is the biggest design debt +- V1 uses CamelCase that splits "LifeCycle" while V2 uses "Lifecycle" — same word, two spellings inside one file. +- V2 adds `WAITING` and `BLOCKED`. The waiters in `client.ts` still use V1. + +### O3. "Task" prefix vs suffix is wildly inconsistent +- 19 task subtypes exist; some use `XTask` (NotebookTask, SqlTask, DbtTask, PowerBiTask) and some use `XCloudTask` / `XPlatformTask` (DbtCloudTask, DbtPlatformTask). Yet `CleanRoomsNotebookTask` is pluralized. +- The base "what's a task here" question requires reading `RunTask.task` oneof to discover. + +### O4. ID fields are stringly typed throughout +- All run/job/repair IDs are `number`; `dbtPlatformJobRunId` is `string` (see H19). Standardizing as branded types would prevent silent ID swaps. + +### O5. ID disambiguation is heavy +- `runId`, `jobId`, `taskRunIds`, `originalAttemptRunId`, `jobRunId`, `repairId`, `latestRepairId`, `clusterId`, `sparkContextId`, `cleanRoomName`, `notebookName`, `policyId`, `instancePoolId`, `warehouseId`, `widgetId`, `agentId`, `subscriberId`, `destinationId`, `pipelineId`, `dashboardId`, `dbtCloudJobId`, `dbtPlatformJobId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId`, `idempotencyToken`, `endpointId`, `gpuNodePoolId`. +- All over the place; many would benefit from branded types. + +### O6. `WorkflowRun` is mentioned in `RunType` but no `Workflow*` type exists +- `RunType.WORKFLOW_RUN` is "from `dbutils.notebook.run`". The lack of a corresponding `WorkflowTask` is intentional but worth a doc note. + +### O7. JSDoc references `` template-token in many places +- The literal `` string appears in JSDoc throughout (e.g., `model.ts:1925`, `model.ts:889`). This is the placeholder for env-specific brand. Acceptable. + +### O8. Deprecated fields are not consistently marked +- Many fields are described as "Deprecated. Please use the X field instead." in prose but lack `@deprecated` JSDoc tag. +- TS LSP will not flag uses; consumers must read prose. Add `@deprecated`. + +### O9. Method-vs-type verb-tense pairing +- `client.cancelRun(CancelRun) → CancelRun_Response`: verb-noun matches. +- `client.runNow(RunNow)`: verb-now matches. +- `client.repair(RepairRun) → RepairRun_Response`: verb-noun mismatch. +- `client.submitRun(SubmitRun)`: verb-noun matches. +- See H33. + +### O10. Schema export naming +- `marshalCancelAllRunsSchema` / `unmarshalCancelAllRuns_ResponseSchema` are public; the `_Response` underscore is exposed through TS identifiers. Consider TypeScript-native names for non-wire identifiers. + +### O11. The waiters duplicate ~80 lines of code each +- `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. +- Suggestion: `RepairRunWaiter` for consistency. + +### O12. `client.ts:594` declares `repair()` method (not `repairRun()`) — see H33, O9. + +### O13. `index.ts` re-exports both the value classes and types in two blocks +- Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. + +### O14. `Format` and `Source` are top-level public enums named with single English words +- These specific names collide with global and tooling identifiers — see H3, H4. + +### O15. Acronym-casing rule should be documented +- `Sql`, `Dbt`, `Jvm`, `Adls`, `Aws`, `Azure`, `Gcp`, `Gcs`, `Powerbi` (mixed), `Ml`, `Mlflow`, `Gpu`, `Lakeview`, `Dbfs`, `Ebs`, `Vm`. +- The pattern is mostly "first letter of acronym capitalized only", with a few exceptions. Codify. + +### O16. Wire-shape vs SDK-shape concept leakage +- `numberInJob`, `originalAttemptRunId`, `Run_JobLevelParameters` are wire artifacts the TS layer should hide or rename. + +### O17. Inconsistent abbreviations: `Params` vs `Parameters` +- Within the same parent type (e.g., `RunNow`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. +- Standardize on `Parameters`. + +--- + +## Domain Glossary + +| Term | Meaning in this SDK | +| -------------------- | ------------------------------------------------------------------------------------ | +| **Job** | A persistent, named workflow definition. Created via `createJob`. Has `jobId`. | +| **Run** | A single execution of a job. Has `runId`. Triggered via `runNow`/`submitRun`/schedule.| +| **Job Run** | The top-level run of a job (parent of per-task runs). | +| **Task** | A unit of work within a job's DAG. Identified by `taskKey`. | +| **Task Run** | The execution of a single task within a run. Has its own `runId`. | +| **Repair** | A re-run of failed tasks within a previously failed job run. Each repair has its own `repairId`. | +| **Trigger** | The event that initiates a run (cron, file arrival, table, model, etc.). | +| **Trigger Type** | The taxonomy of triggers (`PERIODIC`, `ONE_TIME`, `RETRY`, `FILE_ARRIVAL`, ...). | +| **Lifecycle State** | Where a run is in its execution (QUEUED → PENDING → RUNNING → TERMINATING → TERMINATED). | +| **Result State** | The outcome of a terminated run (SUCCESS / FAILED / TIMEDOUT / CANCELED / ...). | +| **Termination Code** | A fine-grained code attached to a terminated run, with a parent `TerminationType`. | +| **Idempotency Token**| Client-supplied dedup key. If a run with the same token exists, the existing `runId` is returned. | +| **Job Cluster** | A cluster definition reusable across tasks within one job, keyed by `jobClusterKey`. | +| **Environment** | A pip+java dependency spec for serverless tasks, keyed by `environmentKey`. | +| **Task Type** | A variant of work: NotebookTask, SparkJarTask, SparkPythonTask, SparkSubmitTask, PipelineTask, PythonWheelTask, DbtTask, SqlTask, RunJobTask, ConditionTask, ForEachTask, CleanRoomsNotebookTask, GenAiComputeTask, AlertTask, PowerBiTask, DashboardTask, DbtCloudTask, DbtPlatformTask, AgenticTask (19 in total). | +| **Source** | Where source code/assets live: `WORKSPACE` or `GIT`. | +| **Format** | Wire compatibility tag for the Jobs API; effectively always `MULTI_TASK`. | +| **Edit Mode** | UI lock state: `UI_LOCKED` or `EDITABLE`. | +| **Performance Target**| Serverless execution mode: `STANDARD` (cost-optimized) or `PERFORMANCE_OPTIMIZED`. | +| **Budget Policy / Usage Policy** | Cost attribution policies. `budget_policy_id` is user-specified; `effective_budget_policy_id` is what actually applied. | +| **Health Rule** | A per-job alerting rule on a metric (e.g. `RUN_DURATION_SECONDS > 3600`). | +| **Clean Room** | A Databricks Clean Rooms feature; notebook-tasks scoped to a clean room. | +| **dbt Cloud / dbt Platform** | External dbt orchestration; `Cloud` is legacy/deprecated, `Platform` is the new name. | +| **GenAI Compute Task** | Custom GPU training-script task with model parameters. | +| **Power BI Task** | Refresh of a Power BI semantic model from Databricks. | +| **Dashboard Task** | Lakeview dashboard refresh + email subscription. | +| **Alert Task** | Evaluates an alert and notifies subscribers. | +| **Pipeline Task** | Triggers a DLT/Spark Declarative Pipeline update. | +| **RunJob Task** | Triggers another job from a task. | +| **Condition Task** | Branches the DAG based on an evaluation; no cluster required. | +| **ForEach Task** | Fan-out: runs a nested task for each input element. | +| **Agentic Task** | Multi-agent execution; runs a supervisor agent toward a goal. | + +--- + +## File Coverage + +| File | Lines | Read In Full? | Notes | +| ----------------- | ----- | ------------- | ------------------------------------------- | +| `v2/index.ts` | 284 | Yes | Re-exports; lists every public identifier. | +| `v2/utils.ts` | 150 | Yes | Marshalling and request helpers. | +| `v2/client.ts` | 1060 | Yes | 19 methods + 4 waiter classes. | +| `v2/model.ts` | 10184 | Yes (chunks) | 47 enums, ~140 interfaces, ~5000 lines of marshalling code (5046+).| + +All public identifiers exported from `index.ts` were considered. Interfaces below +the `unmarshalAdlsgen2InfoSchema` line (5046+) are runtime marshalling code, +not naming surface; they are not in scope. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md new file mode 100644 index 00000000..3212fae4 --- /dev/null +++ b/.agent/naming-audit/knowledgeassistants.md @@ -0,0 +1,297 @@ +# Naming Audit: knowledgeassistants + +**Path:** `packages/knowledgeassistants/src/v1/` +**Versions audited:** v1 +**Inferred domain:** "Knowledge Assistant" CRUD plus three child sub-resources: +(a) `Example` (question + guidelines pairs that steer the assistant), +(b) `KnowledgeSource` (a typed pointer into UC — vector-search `IndexSpec`, +volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that +re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and +`KnowledgeSource` each carry their own proto-style nested lifecycle enum +(`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). +**Total weird names flagged:** 42 + +## Summary +| Severity | Count | +| --- | --- | +| High | 12 | +| Medium | 14 | +| Low | 10 | +| Observation | 6 | + +## High severity + +### 1. `KnowledgeAssistant_State` proto-style underscored type name — `src/v1/model.ts:9` +- **Why weird:** The enum is named `KnowledgeAssistant_State`, with a literal underscore in the TypeScript identifier. The file even disables `@typescript-eslint/naming-convention` for the line (`-- Proto-style nested enum name.`). Underscores in a public TypeScript type name are a direct violation of the Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers — "Identifiers must use only ASCII letters, digits, underscores (for constants and structured test method names), and the '$' sign"). The lint suppression is itself an admission that the name does not fit the project conventions. Sibling SDK packages have already renamed similar nested enums (e.g., `customllms` flattened proto `OptimizationRun.State` to a top-level `State`; this package keeps the proto-style `Parent_Inner` name). +- **Category:** 4 (underscore in TS identifier), 14 (Go/proto-style name). +- **Suggested name:** `KnowledgeAssistantState` (no underscore) or move it to a top-level `AssistantLifecycleState`. Wire-side `STATE_UNSPECIFIED/CREATING/ACTIVE/FAILED` values are unaffected. +- **Rationale:** The lint disable on line 8 documents the rule violation. Every other Databricks SDK JS enum (jobs, clusters, queries) uses PascalCase without underscores; this package is the outlier. Underscored type names break TS namespace conventions and confuse tooling that splits on `_`. + +### 2. `KnowledgeSource_State` proto-style underscored type name — `src/v1/model.ts:17` +- **Why weird:** Same problem as #1 — `KnowledgeSource_State` carries an underscore in the identifier and the same lint suppression on line 16. Once renamed it pairs with the cousin (`KnowledgeAssistantState` / `KnowledgeSourceState`). +- **Category:** 4 (underscore in TS identifier), 14 (Go/proto-style name). +- **Suggested name:** `KnowledgeSourceState` or `SourceIngestionState`. +- **Rationale:** Same as #1; both enums share the same defect. + +### 3. `KnowledgeAssistant_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:10` +- **Why weird:** Reading the value at a call site is `KnowledgeAssistant_State.STATE_UNSPECIFIED` — the token `State` appears twice, and the value is a proto-buf "zero value" sentinel that has no meaning in TypeScript (TS uses `undefined` for "not set"). The wire payload may still send `"STATE_UNSPECIFIED"` for forward compatibility, but the TypeScript side does not need a member for it: every field that takes a state is already `state?: ... | undefined`. +- **Category:** 2 (redundant enum prefix), 14 (proto-style sentinel), 18 (long enum value). +- **Suggested name:** Drop the `STATE_UNSPECIFIED` member; rename remaining values to PascalCase (`Creating`, `Active`, `Failed`) per the Google TypeScript Style Guide. Keep the existing wire values via Zod transform if needed. +- **Rationale:** TS callers must either branch on `STATE_UNSPECIFIED` (which is semantically identical to `state === undefined`) or alias it. Either way the member adds friction without value. + +### 4. `KnowledgeSource_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:18` +- **Why weird:** Same as #3, applied to the source-side state enum. +- **Category:** 2, 14, 18. +- **Suggested name:** Drop `STATE_UNSPECIFIED`; PascalCase the remaining values (`Updating`, `Updated`, `FailedUpdate`). +- **Rationale:** Identical reasoning to #3. + +### 5. `KnowledgeSource_State.FAILED_UPDATE` vs `KnowledgeAssistant_State.FAILED` — `src/v1/model.ts:13,21` +- **Why weird:** The two sibling state enums describe lifecycle failure with two different conventions: the assistant uses bare `FAILED`, the source uses `FAILED_UPDATE`. Both enums also use bare past-participle progressives (`CREATING/UPDATING`) for the in-flight state, but only the source enum qualifies the failure with the verb (`FAILED_UPDATE`). A future `DELETE` operation on either resource would surface this asymmetry — the assistant would need `FAILED` to mean "create failed" *and* "delete failed," while the source already qualifies. Consumers reading both enums side by side will assume the assistant's `FAILED` covers something specific, when in fact it is overloaded. +- **Category:** 6 (misleading), 17 (inconsistency across sibling enums), 13 (verb-tense inconsistency: bare `FAILED` vs `FAILED_UPDATE`). +- **Suggested name:** Align: either both enums use bare `FAILED` (and document that it is operation-agnostic) or both qualify (`FAILED_CREATE` vs `FAILED_UPDATE`). The source enum's name `FAILED_UPDATE` (verb after `FAILED`) is also grammatically awkward — `UPDATE_FAILED` is the standard ordering. +- **Rationale:** Two sibling enums in the same file with the same conceptual shape should use the same naming pattern. Today they diverge for no reason. + +### 6. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` +- **Why weird:** The "successfully ingested / ready" terminal state is named `UPDATED` — past tense of the in-flight `UPDATING`. A reader scanning `UPDATING/UPDATED/FAILED_UPDATE` will see "the source has been updated" which sounds transient (it was just updated, then something else might happen). The sibling assistant enum uses `ACTIVE` for the same concept (the resource is ready and operational), which is much clearer. +- **Category:** 6 (misleading), 13 (verb tense), 17 (inconsistency: assistant has `ACTIVE`, source has `UPDATED`). +- **Suggested name:** `READY` (or `ACTIVE`, matching the assistant) for the ready/operational state. `UPDATING` stays for in-flight. +- **Rationale:** `UPDATED` implies "the action happened" rather than "the resource is in a ready state." A state enum should describe the resource's condition, not the last operation that touched it. + +### 7. `name` field overloaded with semantic role — every request and entity — `src/v1/model.ts:55,64,72,84,120,129,137,160,209,315,324,359` +- **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`knowledge-assistants/{id}` or `.../examples/{id}` etc.). At the call site this is fine for one resource type but consumers chain operations across `KnowledgeAssistant`, `KnowledgeSource`, and `Example` — three `name`s in scope all meaning different things. `DeleteKnowledgeSourceRequest.name` is the source name; `SyncKnowledgeSourcesRequest.name` is the **assistant** name (the parent — see model.ts:312). That ambiguity is exactly what generic `name` causes. Compare with `Example.exampleId` and `KnowledgeAssistant.id` on the same file: when a typed id exists, it is more specific than `name`. +- **Category:** 1 (vague/generic), 15 (generic field losing meaning), 19 (underspecified id). +- **Suggested name:** Type-qualified: `assistantName`, `sourceName`, `exampleName`. Or, more aligned with Google AIP-122 (https://google.aip.dev/122): keep `name` *only* when the field unambiguously identifies the **same** resource type that the request operates on; rename to `parent` (already used elsewhere — see #8) when it identifies a parent. +- **Rationale:** `SyncKnowledgeSourcesRequest.name` is the prime offender: the field is the *assistant* id, but the request is named for sources, so a reader expects the field to be a source id. A typed name (`assistantName`) closes the gap. + +### 8. `parent` field generic and inconsistent with `name` — `src/v1/model.ts:30,45,248,300,315` +- **Why weird:** `CreateExampleRequest.parent`, `CreateKnowledgeSourceRequest.parent`, `ListExamplesRequest.parent`, `ListKnowledgeSourcesRequest.parent`, and `SyncKnowledgeSourcesRequest.name` all refer to **the same wire concept** — a `knowledge-assistants/{id}` resource path. Four of them are called `parent`; the fifth is called `name`. AIP-132 (https://google.aip.dev/132) uses `parent` for list/create requests under a parent resource, so the four are AIP-correct. The `SyncKnowledgeSourcesRequest.name` outlier is the bug — its doc even says "The resource name of the Knowledge Assistant" (model.ts:312). +- **Category:** 17 (inconsistency: `parent` vs `name` for the same concept), 16 (field name contradicts the operation's target). +- **Suggested name:** Rename `SyncKnowledgeSourcesRequest.name` → `parent` to match the four sibling requests; alternatively rename all five to `assistant` or `knowledgeAssistantName`. +- **Rationale:** A consumer who's just learned that `parent` means "the assistant" will write `{parent: '...'}` into `SyncKnowledgeSourcesRequest` and the type checker will reject it for no good reason. + +### 9. `KnowledgeAssistant.id` vs `Example.exampleId` vs `KnowledgeSource.id` inconsistency — `src/v1/model.ts:93,164,235` +- **Why weird:** Three sibling entities, three id conventions: + - `KnowledgeAssistant.id?: string` (bare `id`) + - `KnowledgeSource.id?: string` (bare `id`, no doc) + - `Example.exampleId?: string` (qualified `exampleId`) + The bare `id` is doc'd as "The universally unique identifier (UUID) of the Knowledge Assistant" on `KnowledgeAssistant`, but `KnowledgeSource.id` has *no* JSDoc at all (model.ts:235). Compare with the sibling `supervisoragents` package: `SupervisorAgent.supervisorAgentId` (fully qualified, plus a deprecated `id` for back-compat) and `Tool.toolId`. The `knowledgeassistants` package is the inconsistent neighbor. +- **Category:** 1 (vague), 17 (inconsistency within the same package), 19 (underspecified id). +- **Suggested name:** `KnowledgeAssistant.knowledgeAssistantId` or `KnowledgeAssistant.assistantId`; `KnowledgeSource.knowledgeSourceId` or `sourceId`; keep `Example.exampleId` as-is. +- **Rationale:** Bare `id` is the most common footgun when two resources are passed to the same function (e.g., a UI dialog editing both an assistant and one of its sources). Typed ids prevent type-checker false negatives. + +### 10. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` +- **Why weird:** The doc literally enumerates the allowed values: `'The type of the source: "index", "files", or "file_table"'`. A `string` typing means callers can write `sourceType: 'INDEX'` (wrong case) or `sourceType: 'vector_search'` (typo) and the compiler accepts both. Same package already uses Zod-discriminated unions for `spec` (model.ts:229-233), so the type info exists; `sourceType` is the redundant string mirror. +- **Category:** 16 (field contradicts type domain — declared as `string` when it is closed-set), 6 (misleading), 12 (duplicate of `spec.$case`). +- **Suggested name:** Convert to an enum `KnowledgeSourceType` with values `Index | Files | FileTable`; or drop `sourceType` entirely because `spec.$case` already carries the discriminant. +- **Rationale:** Stringly-typed enums are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals — TS supports closed string literal unions specifically to avoid this). The fact that `spec.$case` already discriminates makes `sourceType` pure noise on both reads and writes. + +### 11. `Example.guidelines: string[]` and `Example.question: string` semantics overlap with `KnowledgeAssistant.instructions` — `src/v1/model.ts:86,91,185` +- **Why weird:** Three free-text "how should the assistant behave" fields are scattered across two types: `KnowledgeAssistant.instructions` (single string, global), `Example.guidelines` (array, per-question), `Example.question` (single string, paired with `guidelines`). The names do not disambiguate scope: a reader could reasonably guess `guidelines` are global and `instructions` are per-example; the actual mapping is the other way around. Compare with the same anti-pattern in `customllms.CustomLlm.instructions: string` + `CustomLlm.guidelines: string[]` (audited in `.agent/naming-audit/customllms.md` #12) — that audit flagged the exact same overlap. +- **Category:** 6 (misleading), 12 (duplicate concept), 15 (generic field). +- **Suggested name:** Rename `KnowledgeAssistant.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerRules` or `responseGuidelines`. Both names disambiguate scope. +- **Rationale:** Two free-text fields with synonymous names but different scope is one of the most common API-design defects. The audit caught the same pattern in `customllms`; flagging it here for SDK-wide consistency. + +### 12. `KnowledgeSource.spec` discriminated union name is generic — `src/v1/model.ts:229` +- **Why weird:** `KnowledgeSource.spec?: { $case: 'index'; index: IndexSpec } | { $case: 'files'; files: FilesSpec } | { $case: 'fileTable'; fileTable: FileTableSpec } | undefined`. The discriminator field is called `spec` — a generic CS term. The doc says "Specification for the knowledge source type." Consumers writing autocomplete will see `source.spec.$case` and `source.sourceType` both meaning "what kind of source is this", and have to remember that `spec` carries the *data* and `sourceType` carries the *string label*. Compare with the `supervisoragents.Tool.spec` field (same anti-pattern; same audit flagged in the sibling). +- **Category:** 1 (vague), 12 (duplicate of `sourceType` discriminant). +- **Suggested name:** `config` if the union carries configuration (it does); or `source` to mirror the `$case` semantics ("which source variant"). Best: collapse `sourceType` and `spec` into a single discriminated union. +- **Rationale:** `spec` is so generic it conveys no information; the type already conveys "this is the spec". + +## Medium severity + +### 13. `FileTableSpec.fileCol` cryptic abbreviation — `src/v1/model.ts:105` +- **Why weird:** `fileCol` truncates `column` to `Col`. The same pattern showed up in `customllms.Table.requestCol`/`responseCol` (flagged in `customllms.md` #15). The field on its sibling, `IndexSpec`, uses both `textCol` and `docUriCol` — same abbreviation. Other fields in the same file spell things out (`endpointName`, `experimentId`, `knowledgeCutoffTime`), so `Col` is inconsistent within the package. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency). +- **Suggested name:** `fileColumn` (and `textColumn` / `docUriColumn`). +- **Rationale:** Three characters of identifier savings is not worth the cognitive split between the doc ("column") and the field name. + +### 14. `IndexSpec.textCol` / `IndexSpec.docUriCol` cryptic abbreviation — `src/v1/model.ts:145,147` +- **Why weird:** Same `Col` abbreviation as #13, plus `docUri` truncates "document URI" awkwardly. Reading `docUriCol`, your eye parses `doc-Uri-Col` — three abbreviations stacked. The doc reads "The column that specifies a link or reference to where the information came from" — a much friendlier name would be `sourceUriColumn` or `referenceColumn`. +- **Category:** 5 (cryptic abbreviation), 3 (acronym casing: `Uri` vs `URI`). +- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #41). +- **Rationale:** The savings are minimal; the readability cost is real. + +### 15. `IndexSpec.indexName` type-suffix tautology — `src/v1/model.ts:143` +- **Why weird:** `IndexSpec.indexName` repeats `Index` in the type and field. The doc says it is the full UC name of the vector search index. Same pattern as `FileTableSpec.tableName` (model.ts:103). Both fields are documented as a fully-qualified three-part UC name (catalog.schema.x) — same concept Unity Catalog calls `full_name` in `catalog.TableInfo.full_name`. +- **Category:** 20 (type-suffix tautology), 1 (vague — `*Name` does not communicate "fully qualified"). +- **Suggested name:** `fullName` (matches Unity Catalog convention) or `qualifiedName`. If kept as `*Name`, at least drop the type prefix: `IndexSpec.fullName` reads better than `IndexSpec.indexName`. +- **Rationale:** Unity Catalog already has a canonical token; reusing it makes cross-API code less surprising. + +### 16. `FileTableSpec.tableName` type-suffix tautology — `src/v1/model.ts:103` +- **Why weird:** Same problem as #15 — `FileTableSpec.tableName` repeats `Table` in the type and field. +- **Category:** 20 (type-suffix tautology), 1 (vague). +- **Suggested name:** `fullName` or `qualifiedName`. +- **Rationale:** Same as #15. + +### 17. `Example.question` + `Example.guidelines` field-name doublet — `src/v1/model.ts:86,91` +- **Why weird:** `Example` has two free-text payload fields: the question being asked and the guidelines for the answer. The current names are fine *in isolation*, but the type's own doc explains "Contains a question and guidelines for how the assistant should respond" — and the field names then duplicate the doc verbatim. The bigger issue: `guidelines: string[]` is plural and an array, but no JSDoc explains the semantics of each element (is each entry a sentence? a bullet? a paragraph?). Combined with the parallel `KnowledgeAssistant.instructions: string` (#11), the naming makes the conceptual hierarchy unclear. +- **Category:** 15 (generic field name losing meaning), 1 (vague — "guidelines" of what?). +- **Suggested name:** `Example.question` is fine; rename `Example.guidelines` → `answerGuidelines` (or `responseGuidelines`, paired with rename in #11). +- **Rationale:** A type that owns a single question/answer pair should make the answer-shaped field explicit. + +### 18. `KnowledgeAssistant.endpointName` underspecified — `src/v1/model.ts:191` +- **Why weird:** The doc reads "The name of the knowledge assistant agent endpoint." Three reads of "agent endpoint" raise the question: is this a model-serving endpoint? An MLflow endpoint? An AI Gateway endpoint? The sibling SDK `customllms` has the same `endpointName: string` (flagged in `customllms.md` #7 as ambiguous). In Databricks the term "endpoint" alone is overloaded across `model_serving`, `sql_warehouses`, `vector_search_endpoints`, etc. +- **Category:** 1 (vague), 19 (underspecified id). +- **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or just `agentEndpointName`. The sibling `supervisoragents.KnowledgeAssistant.servingEndpointName` actually uses `servingEndpointName` (see `supervisoragents/src/v1/model.ts:129`), so the rename here would *align* the two packages. +- **Rationale:** Cross-package consistency wins. `supervisoragents` already named the field correctly; copy that. + +### 19. `KnowledgeAssistant.experimentId` — what kind of experiment? — `src/v1/model.ts:193` +- **Why weird:** Doc reads "The MLflow experiment ID." A bare `experimentId` is fine *if* the consumer knows the SDK only integrates with MLflow. But the consumer reading `KnowledgeAssistant.experimentId` could reasonably guess this is an A/B-test experiment, a feature-flag experiment, or an MLflow experiment. The doc clarifies — but the name does not. +- **Category:** 1 (vague), 19 (underspecified id). +- **Suggested name:** `mlflowExperimentId` (matches the doc; matches `databricks.mlflow` API convention). +- **Rationale:** Field names should not require reading JSDoc to disambiguate. Same reasoning as #18. + +### 20. `KnowledgeAssistant.errorInfo: string` — `src/v1/model.ts:195` +- **Why weird:** Two issues: + - Suffix `Info` is generic CS noise (rule 8: redundant suffix). `error` alone or `errorMessage` is more specific. + - Type is `string` but the field is reserved for "Error details when the Knowledge Assistant is in FAILED state." Other Databricks APIs (jobs, clusters) use structured `ErrorInfo` objects with `code`, `message`, `details`. A bare string forces consumers to parse free text — and a future structured upgrade would be a breaking change. +- **Category:** 8 (redundant suffix), 1 (vague), 16 (field contradicts type domain). +- **Suggested name:** `errorMessage` (if the field stays a string) or convert to an `ApiError` object (if the field upgrades). Drop the `Info` suffix either way. +- **Rationale:** The `Info` suffix is a Go/Java carryover (`*Info` types are common in proto messages); TS gets clearer names without it. + +### 21. `KnowledgeAssistant.creator: string` — what is a creator? — `src/v1/model.ts:187` +- **Why weird:** Doc reads "The creator of the Knowledge Assistant." Could be a username, email, UUID, Databricks principal id, or service principal client id. The type is `string`. The exact same pattern was flagged in `customllms.md` #10 — also a `creator: string`. The convention varies across the SDK: + - Unity Catalog: `created_by` (matches AIP-148, https://google.aip.dev/148) + - Jobs: `creator_user_name` + - This package: `creator` +- **Category:** 1 (vague), 19 (underspecified id), 17 (inconsistency across SDK). +- **Suggested name:** `createdBy` (AIP-148 standard, also matches `unitycatalog`) with JSDoc clarifying it is a user email. +- **Rationale:** Match the most-used convention. `createdBy` reads naturally and is widely understood. + +### 22. `KnowledgeSource.knowledgeCutoffTime` ambiguous semantics — `src/v1/model.ts:237` +- **Why weird:** Doc reads "Timestamp representing the cutoff before which content in this knowledge source is being ingested." Two interpretations: + - "Ingestion stops at this time" (a future bound). + - "Only content created before this time is being ingested" (a past bound). + The field name `knowledgeCutoffTime` does not disambiguate, and the doc grammar ("being ingested" — present continuous) makes it worse. AIP-142 (timestamp naming) would suggest `dataAsOf` for "content as of this time" or `ingestionDeadline` for "must finish by". +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `dataAsOf` or `contentAsOf` if the field is a past bound (most likely); `ingestionDeadline` if it is a future bound. +- **Rationale:** A timestamp field whose meaning depends on JSDoc parsing is a footgun. Pick a name that encodes direction. + +### 23. `KnowledgeSource_State.UPDATING` vs `KnowledgeAssistant_State.CREATING` inconsistent verbs — `src/v1/model.ts:11,19` +- **Why weird:** Both enums describe "a write operation is in flight." The assistant uses `CREATING` (matches its lifecycle — assistants are created once and updated thereafter). The source uses `UPDATING` (matches its lifecycle — sources are created with content, then their content is refreshed via sync). Both enums conflate "creation" and "update" into one in-flight state; the names just disagree on which verb to use. +- **Category:** 13 (verb-tense / verb-choice inconsistency), 17 (inconsistency across sibling enums). +- **Suggested name:** Both should use `PROCESSING` or `IN_PROGRESS` — operation-agnostic in-flight markers. If lifecycle stages matter, both should split into `CREATING` / `UPDATING` consistently. +- **Rationale:** The asymmetry suggests the API team modeled the two resources separately and never unified the lifecycle vocabulary. + +### 24. `unmarshalListExamplesResponseSchema` / `marshalKnowledgeSourceSchema` etc. — `*Schema` suffix is verbose — `src/v1/model.ts:377,463,539,624` +- **Why weird:** All marshal/unmarshal schemas suffix `*Schema`. The variables are Zod schemas, so the suffix is *literally* accurate — but every export reads `unmarshalKnowledgeAssistantSchema`, 32 characters. The same pattern is universal across this SDK; flagging for cross-cutting review rather than local fix. +- **Category:** 7 (overly verbose), 8 (redundant suffix). +- **Suggested name:** `unmarshalKnowledgeAssistant` (Zod schemas are obviously schemas; the suffix is type-system redundancy). Or namespace: `KnowledgeAssistantCodec.in` / `.out`. +- **Rationale:** Flagged as SDK-wide convention to revisit. Not a per-package fix. + +### 25. `listExamplesIter` / `listKnowledgeAssistantsIter` / `listKnowledgeSourcesIter` — `Iter` suffix Go-style — `src/v1/client.ts:338,392,446` +- **Why weird:** The `Iter` suffix on async iterators is a direct port from Go's `*Iter` convention. In TS, async iterators are first-class via `Symbol.asyncIterator`; the convention is to expose them as the *default* iteration form (`for await (const x of client.listExamples(req))` works directly if the method returns an `AsyncIterable`). The `*Iter` suffix is a Go/Java carryover. +- **Category:** 14 (Go-style name), 8 (redundant suffix — return type already says it's an iterator). +- **Suggested name:** Drop the suffix and overload on return type, or rename `listExamples` (paged) → `listExamplesPage` and `listExamplesIter` → `listExamples` (auto-paging is the default). +- **Rationale:** Modern TS APIs prefer that the default form is auto-paging. The `Iter` suffix is a code smell from the Go port. + +### 26. `Client` class name — bare, no scoping — `src/v1/client.ts:63` +- **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-knowledgeassistants/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as KAClient} from '@databricks/sdk-knowledgeassistants/v1'`. Other SDKs in the Databricks ecosystem name the class `KnowledgeAssistantsClient` (or `KnowledgeAssistantsApi`), avoiding the alias dance. +- **Category:** 1 (vague), 17 (SDK-wide inconsistency). +- **Suggested name:** `KnowledgeAssistantsClient`. Sibling SDK packages (Go SDK reference uses `WorkspaceClient.KnowledgeAssistants`; AWS JS SDK uses `S3Client`, `IAMClient`) follow this pattern. +- **Rationale:** Bare `Client` is convenient until you import two SDK packages; then it's a tax. + +## Low severity + +### 27. `KnowledgeAssistant_State.CREATING` vs `KnowledgeSource_State.UPDATING` — `src/v1/model.ts:11,19` +- **Why weird:** See #23; flagged again at low severity as a *style* concern (the higher-severity finding is the verb-mismatch). +- **Category:** 13 (verb tense). +- **Suggested name:** See #23. +- **Rationale:** Cosmetic but consistent with audit's "verb-tense inconsistency" category. + +### 28. `parseResponse` / `marshalRequest` asymmetric verbs — `src/v1/utils.ts:113,119` +- **Why weird:** Same as `customllms` audit #22: `parseResponse` and `marshalRequest` use two different verbs for inverse operations. The model file uses `unmarshal*Schema` / `marshal*Schema` consistently, but `utils.ts` breaks the pattern with `parse`. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry. +- **Rationale:** Pair-wise consistency aids reading. + +### 29. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21. +- **Category:** 1 (vague), 17 (inconsistency). +- **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. +- **Rationale:** Names should differ in more than one infix. + +### 30. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +- **Why weird:** Same as `customllms.md` #23: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in the same file. Three things named `Options`. +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` or `HttpCallParams`. +- **Rationale:** Distinguish internal context bags from user-facing options. + +### 31. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Same as `customllms.md` #28: exported but not used by `client.ts`. +- **Category:** Observation / 11 (unused export). +- **Suggested name:** Either remove the export or document why it ships per-package. +- **Rationale:** Generated artifact; flag for cross-package cleanup. + +### 32. `readAll` helper generic name — `src/v1/utils.ts:40` +- **Why weird:** Same as `customllms.md` #29: helper reads an entire response body stream; name is generic. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` or `readStreamToEnd`. +- **Rationale:** Internal helper, low cost. Skip if generated. + +### 33. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` +- **Why weird:** Same as `customllms.md` #24: `Segment` is a generic CS term. +- **Category:** 1 (vague). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** SDK-wide consistency review. + +### 34. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` +- **Why weird:** Same as `customllms.md` #33: `resp` is the response. 12 methods repeat the same pattern. +- **Category:** 12 (duplicate pattern). +- **Suggested name:** Refactor away the pattern, not the name. +- **Rationale:** Refactor opportunity surfaced by audit. + +### 35. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` +- **Why weird:** Three async generator methods each declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. Minor abbreviation inconsistency: `request` would be clearer in the iterator context, where the variable's purpose ("the request used to fetch each page") differs from the input `req`. +- **Category:** 5 (abbreviation). +- **Suggested name:** `pageRequest` or `nextPageReq`. +- **Rationale:** Local clarity for readability. + +### 36. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` +- **Why weird:** `knowledgeSourceFieldMaskSchema` carries top-level entries `fileTable`, `files`, `index` — matching the `$case` keys, but the wire serialization uses `file_table`/`files`/`index`. Reading the schema, a consumer might write `knowledgeSourceFieldMask('spec.files')` expecting the variant-aware path; the field-mask schema has no `spec` key at all. The discriminated union variants are flattened to top-level field-mask paths, which is correct AIP-161 (https://google.aip.dev/161) behavior — but jarring if you've read the TS type. +- **Category:** 17 (inconsistency between TS shape and field-mask schema). +- **Suggested name:** Not a rename; flag for documentation. +- **Rationale:** Field-mask path lookup is non-obvious; deserves a JSDoc note. + +## Observations + +### 37. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` +- **Why weird:** Doc says "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Either every `description` should carry this annotation, or none should. Flagged for cross-package style review. +- **Category:** Observation. + +### 38. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` +- **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. +- **Category:** 17 (reversed — consistency note). + +### 39. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #7, #8). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. +- **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. +- **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. + +### 40. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` +- **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `APIError` usage. Cross-cutting observation from `customllms.md` #36. +- **Category:** 3 (acronym casing — SDK-wide). +- **Suggested name:** SDK-wide policy decision. + +### 41. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +- **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. +- **Category:** Observation. + +### 42. `Example` lacks `state` field — `src/v1/model.ts:79-98` +- **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. +- **Category:** Observation. + +## Domain glossary +- `knowledge assistant` — the top-level resource: an LLM-powered assistant scoped to a corpus of knowledge. +- `knowledge source` — a typed pointer into UC (vector index, volume of files, or file table) that feeds the assistant. +- `example` — a question + guidelines pair used to steer the assistant's responses. +- `uc` — Unity Catalog (referenced in JSDoc on `FileTableSpec.tableName`, `IndexSpec.indexName`, `FilesSpec.path`). +- `mlflow` — Machine-learning lifecycle platform (referenced only in `KnowledgeAssistant.experimentId` JSDoc). +- `field mask` — Google AIP-161 partial-update mechanism (FieldMask from `@databricks/sdk-core/wkt`). +- `uuid` — referenced in JSDoc on `Example.exampleId` and `KnowledgeAssistant.id`. + +## File coverage +- `src/v1/model.ts` (752 lines): read fully. +- `src/v1/client.ts` (603 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (34 lines): read fully. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md new file mode 100644 index 00000000..8e000175 --- /dev/null +++ b/.agent/naming-audit/lakeview.md @@ -0,0 +1,798 @@ +# Naming Audit: lakeview + +**Path:** `packages/lakeview/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. +**Total weird names flagged:** 43 + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 8 | +| Medium | 17 | +| Low | 12 | +| Observation | 6 | + +## Summary table + +| # | Severity | Location | Name | Category | +| -- | ----------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------- | +| 1 | High | package name | `lakeview` | 6 | +| 2 | High | `model.ts` enum | `DashboardView` | 1, 18 | +| 3 | High | `model.ts` enum | `LifecycleState` | 1, 12 | +| 4 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashDashboard` | 17 | +| 5 | High | `model.ts` interface | `Dashboard` | 1, 15 | +| 6 | High | `model.ts` interface | `PublishedDashboard` | 12 | +| 7 | High | `model.ts` interface (nested) | `AuthorizationDetails_GrantRule` | 4, 14 | +| 8 | High | `model.ts` interface (nested triplet) | `Subscription_Subscriber`, `Subscription_Subscriber_User`, `Subscription_Subscriber_Destination` | 4, 14 | +| 9 | Medium | `model.ts` interface | `CronSchedule` | 1 | +| 10 | Medium | `model.ts` field | `CronSchedule.quartzCronExpression` | 14, 20 | +| 11 | Medium | `model.ts` field | `CronSchedule.timezoneId` | 19 | +| 12 | Medium | `model.ts` field | `Schedule.cronSchedule` | 20 | +| 13 | Medium | `model.ts` enum | `SchedulePauseStatus` | 1, 7 | +| 14 | Medium | `model.ts` field | `Schedule.pauseStatus` | 6, 20 | +| 15 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | +| 16 | Medium | `model.ts` field | `MigrateDashboardRequest.sourceDashboardId` | 16 | +| 17 | Medium | `model.ts` field | `MigrateDashboardRequest.updateParameterSyntax` | 6, 13, 15 | +| 18 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | +| 19 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | +| 20 | Medium | `model.ts` interface | `GetPublishedDashboardEmbeddedRequest` | 1, 7 | +| 21 | Medium | `model.ts` field | `GetPublishedDashboardTokenInfoResponse.customClaim` | 15 | +| 22 | Medium | `model.ts` field | `AuthorizationDetails.type` | 10, 15 | +| 23 | Medium | `model.ts` field | `AuthorizationDetails.resourceLegacyAclPath` | 6, 14, 16 | +| 24 | Medium | `model.ts` field | `Subscription.skipNotify` | 1, 14 | +| 25 | Medium | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | +| 26 | Medium | `model.ts` field | `Subscription_Subscriber_User.userId` typed `number` | 19, 16 | +| 27 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | +| 28 | Low | `model.ts` field | `Schedule.warehouseId` | 19, 12 | +| 29 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | +| 30 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | +| 31 | Low | `model.ts` field | `Dashboard.serializedDashboard` | 20 | +| 32 | Low | `model.ts` field | `Dashboard.lifecycleState` | 15 | +| 33 | Low | `model.ts` field | `Dashboard.createTime` / `updateTime` & `Schedule.*` / `Subscription.*` | 9 | +| 34 | Low | `model.ts` field | `PublishedDashboard.revisionCreateTime` | 15 | +| 35 | Low | `model.ts` field | `PublishDashboardRequest.embedCredentials` | 7 | +| 36 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | +| 37 | Low | `model.ts` field | `DashboardView.DASHBOARD_VIEW_BASIC` | 2, 18 | +| 38 | Low | `client.ts` methods | `listDashboardsIter`, `listSchedulesIter`, `listSubscriptionsIter` | 5 | +| 39 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | +| 40 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | +| 41 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | +| 42 | Observation | `model.ts` field | `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` | 8, 20 | +| 43 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | +| 44 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | + +--- + +## High severity + +### 1. `lakeview` — package name uses the old codename (rebrand mismatch) + +**Location:** `packages/lakeview/`, `index.ts`, `client.ts`, all URL paths `/api/2.0/lakeview/...` + +The product is documented and marketed as "AI/BI Dashboards" (formerly "Lakeview"). The codename `lakeview` survives at every level of the SDK surface: + +- The npm/workspace package name is `lakeview`. +- The URL paths embed `lakeview` (`/api/2.0/lakeview/dashboards`), which is a wire-format concern the SDK cannot change. +- Documentation strings still use both names interchangeably — e.g. `MigrateDashboardRequest.displayName`: "Display name for the new Lakeview dashboard." and `MigrateDashboardRequest.parentPath`: "the migrated Lakeview dashboard". +- Exported file extension `.lvdash.json` (referenced in `Dashboard.path` doc) preserves the old prefix. + +**Category:** 6 (misleading — old name persists). + +**Suggested name:** Either rename the package to `aibidashboards` / `dashboards` (with a re-export shim under the old name during deprecation), or accept the URL constraint and document the rename explicitly in the package-level JSDoc (`This package wraps the AI/BI Dashboards API. The wire path /api/2.0/lakeview/... preserves the original codename.`). Today the package gives no hint that "Lakeview" and "AI/BI Dashboards" are the same product, so search hits for the marketing name return nothing. + +**Rationale:** Discoverability. A user reading Databricks docs for "AI/BI Dashboards" will not find this package by name search. The Go SDK has the same problem, but TS has the chance to fix the surface visible to TS users at construction time (`new Client(...)`). + +### 2. `DashboardView` — enum with a single value (`DASHBOARD_VIEW_BASIC`) + +**Location:** `src/v1/model.ts:6-9` + +```ts +export enum DashboardView { + /** Includes summary metadata from the dashboard. */ + DASHBOARD_VIEW_BASIC = 'DASHBOARD_VIEW_BASIC', +} +``` + +The enum has only one member, and the member's name is prefixed with the enum name (proto-style "always include the type name in every value"). The literal `DashboardView.DASHBOARD_VIEW_BASIC` reads twice: `DashboardView` then `DASHBOARD_VIEW_BASIC`. The enum exists only because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.) — but until those exist the enum is a confusing single-value gate. + +`View` is also a generic name in a Dashboards package (it overloads the HTML/UI sense of "view" with the "field mask" sense — e.g. `proto3` partial-response style). + +**Category:** 1 (vague), 18 (long enum value). + +**Suggested name:** Either rename to `DashboardFieldMask` / `DashboardResponseMode` (closer to its actual role: a partial-response selector), or, until there is a second value, replace `view?: DashboardView` with `summaryOnly?: boolean` and delete the enum. + +**Rationale:** Without the doc comment on `ListDashboardsRequest.view`, the type name does not communicate that this is a "give me only summary fields" selector. + +### 3. `LifecycleState` — domain-detached enum that overlaps with other packages + +**Location:** `src/v1/model.ts:11-16` + +```ts +export enum LifecycleState { + /** The dashboard is in an active state (not-trashed). */ + ACTIVE = 'ACTIVE', + /** The dashboard is in a trashed state. */ + TRASHED = 'TRASHED', +} +``` + +`LifecycleState` is a top-level export with no domain prefix. Other Databricks SDK packages also use the name (e.g. `alerts.LifecycleState`, `queries.LifecycleState`) — same name, different sets of values. Cross-package imports clash: + +```ts +import {LifecycleState as DashLifecycle} from '@databricks/sdk-lakeview'; +import {LifecycleState as AlertLifecycle} from '@databricks/sdk-alerts'; +``` + +**Category:** 1 (vague), 12 (duplicate concepts across packages). + +**Suggested name:** `DashboardLifecycleState` (matches the v2 alerts pattern `AlertLifecycleState`). + +**Rationale:** Eliminates the import-rename ritual. Consistent with the rest of the SDK after the alerts v2 refactor. + +### 4. `LifecycleState.TRASHED` vs `trashDashboard()` — split vocabulary inside one package + +**Location:** `src/v1/model.ts:15`, `src/v1/client.ts:653` (`trashDashboard`), `src/v1/model.ts:429` (`TrashDashboardRequest`) + +The enum uses `TRASHED`, the method uses `trash`, the type uses `Trash`. **Same package, same operation, three forms**. Meanwhile every other CRUD-style endpoint in the Databricks SDK uses `Delete`/`delete`. Alerts has the *exact* same issue (flagged in `alerts.md` #11 and #12); it was kept in v1 and renamed to `DELETED` in alerts v2 — leaving Lakeview as an outlier. + +The `LifecycleState.TRASHED` value is paired with a method called `trashDashboard()` (verb `trash`) and a method `getDashboard()` that returns `lifecycleState: TRASHED` after a soft-delete. So the lifecycle word, the method verb, and the type-name suffix all share a vocabulary that none of the rest of the SDK uses. + +**Category:** 17 (inconsistent action verb). + +**Suggested name:** Either keep `trashDashboard` and rename `TRASHED → DELETED` (mirrors alerts v2 — but then the method verb mismatches its own state) or rename both to `deleteDashboard` + `DELETED`. The cleanest is to rename method + type + state value to `delete`/`Delete`/`DELETED` together. + +**Rationale:** A single coherent verb. The Trash → Delete migration is partially complete in other packages and lakeview is behind. + +### 5. `Dashboard` — overloaded top-level type + +**Location:** `src/v1/model.ts:93-136` + +`Dashboard` is the top-level type for the *draft* dashboard. The package then exposes `PublishedDashboard` as a *different* shape for the published-state mirror. A user reading the API thinks `Dashboard` means "any dashboard"; in fact it means "draft dashboard". The `lifecycleState` field on `Dashboard` is `ACTIVE`/`TRASHED` — and never `PUBLISHED`, because a published dashboard is the wholly separate `PublishedDashboard` type. Nothing in the type name conveys "draft". + +This is compounded by Databricks having (1) classic SQL dashboards (a separate API), (2) AI/BI dashboards / lakeview dashboards (this API), (3) genie dashboards, (4) usage dashboards. The bare name `Dashboard` is therefore severely overloaded both within the company and within the SDK. + +**Category:** 1 (vague/generic), 15 (generic type losing meaning at site). + +**Suggested name:** `DraftDashboard` (paired with `PublishedDashboard`). Both are draft and published views of the same underlying resource, so the symmetry is desirable. + +**Rationale:** Without the rename the API is asymmetric: `getDashboard()` returns "the draft view", `getPublishedDashboard()` returns "the published view", but only one of those calls makes the draft/published nature explicit. + +### 6. `PublishedDashboard` — projection sibling of `Dashboard`, missing structural identity + +**Location:** `src/v1/model.ts:323-332` + +```ts +export interface PublishedDashboard { + displayName?: string | undefined; + warehouseId?: string | undefined; + embedCredentials?: boolean | undefined; + revisionCreateTime?: Temporal.Instant | undefined; +} +``` + +No `dashboardId`. No `etag`. No `serializedDashboard`. No reference back to the parent `Dashboard`. So `PublishedDashboard` is a *partial mirror* of the draft `Dashboard` resource, but the only thing tying them together is the URL path the user used to fetch it. The name `PublishedDashboard` implies "a full dashboard in the published state", but the type is in practice "the metadata of the latest publish action". + +**Category:** 12 (duplicate concept relative to `Dashboard`). + +**Suggested name:** `PublishedDashboardSnapshot` or `PublishMetadata`. If the long-term intent is for the type to contain the full published content, the type name is fine but it should at least carry the `dashboardId` of its parent. + +**Rationale:** Today every caller of `getPublishedDashboard()` has to remember the `dashboardId` they passed in to use the response. The type should round-trip. + +### 7. `AuthorizationDetails_GrantRule` — proto nested-message style leaking into TS + +**Location:** `src/v1/model.ts:45-52` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface AuthorizationDetails_GrantRule { + permissionSet?: string | undefined; +} +``` + +Underscore-separated identifier in a TS interface name. The comment acknowledges the violation. The choice preserves the protobuf path (`message AuthorizationDetails.GrantRule`) and helps with grep'ing through generated code, but for consumers the type appears as `AuthorizationDetails_GrantRule` everywhere — an uncomfortable identifier to type and read. + +The same package re-exports it from `index.ts`, so the underscore is part of the public API surface. + +**Category:** 4 (underscores in TS identifiers), 14 (Go/Java/proto-style name). + +**Suggested name:** `GrantRule` (top-level) or `AuthorizationGrantRule`. There is no other `GrantRule` in this package, so the bare name is unambiguous. If naming nesting is desired, namespace-merging is the idiomatic TS pattern: + +```ts +export interface AuthorizationDetails { ... } +export namespace AuthorizationDetails { + export interface GrantRule { ... } +} +// Use site: AuthorizationDetails.GrantRule +``` + +**Rationale:** TypeScript supports namespace-merging for exactly this case. The underscore form is grep-friendly but ugly; the namespace form is grep-friendly *and* readable. + +### 8. `Subscription_Subscriber`, `Subscription_Subscriber_User`, `Subscription_Subscriber_Destination` — three nested levels of underscore-named types + +**Location:** `src/v1/model.ts:403-427` + +```ts +export interface Subscription_Subscriber { ... } +export interface Subscription_Subscriber_Destination { ... } +export interface Subscription_Subscriber_User { ... } +``` + +Three more proto-nested types with underscores. The naming becomes especially awkward when used: `Subscription_Subscriber_User.userId`, `Subscription_Subscriber_Destination.destinationId`. Each layer of nesting adds a `_Subscriber`, doubling the prefix length. The double `_Subscriber_Subscriber` flavor (`Subscription_Subscriber` itself is the discriminated union, and `Subscription_Subscriber_User` is a variant of it) is especially confusing — at a glance you can't tell which one is the union and which is the leg. + +Together with `AuthorizationDetails_GrantRule` (above), this is the dominant naming smell in the file: four public types whose names violate `@typescript-eslint/naming-convention` and require suppressions. + +**Category:** 4, 14. + +**Suggested name:** `Subscriber`, `UserSubscriber`, `DestinationSubscriber` — and a top-level discriminated union `Subscriber = UserSubscriber | DestinationSubscriber`. Or namespace-merging under `Subscription` as in #7. + +**Rationale:** A real discriminated union in TS is more useful than a `oneof`-style "both fields optional, only one is set" interface. The current type allows both `userSubscriber` and `destinationSubscriber` to be undefined or both populated simultaneously — the type system does not enforce the "mutually exclusive" rule that the JSDoc claims. + +--- + +## Medium severity + +### 9. `CronSchedule` — generic type name in a single-domain package + +**Location:** `src/v1/model.ts:80-91` + +```ts +export interface CronSchedule { + quartzCronExpression?: string | undefined; + timezoneId?: string | undefined; +} +``` + +The package exports a top-level `CronSchedule`. The same name appears in `alerts/v2`, `jobs` (similar concept), `pipelines` (similar concept). Each defines its own. Across the SDK there is no shared "this is a cron expression with a timezone" type — every team duplicates the two-field interface. + +**Category:** 1 (generic name in domain package). + +**Suggested name:** Either accept the duplication (matches Go SDK's package-local types) and rename to `DashboardCronSchedule`, or extract a shared core type. The audit recommends `DashboardCronSchedule` since the user-facing concept is "a cron schedule that the dashboards service understands". + +**Rationale:** Future-proofing: the field set may diverge from other services' cron-schedule types (some add a `pauseStatus`, some add a `nextFireTime`). A domain-prefixed name prevents `import { CronSchedule } from '@databricks/sdk-lakeview'` from being a confusing rename. + +### 10. `CronSchedule.quartzCronExpression` — implementation-detail leak and type-suffix tautology + +**Location:** `src/v1/model.ts:85` + +```ts +/** + * A cron expression using quartz syntax. EX: `0 0 8 * * ?` represents everyday at 8am. + */ +quartzCronExpression?: string | undefined; +``` + +Two concerns: + +1. `quartz` exposes the JVM scheduler library (Quartz Scheduler). A TypeScript SDK user will not know what "Quartz syntax" is, and even if they do, the *only* cron syntax the API accepts is Quartz — calling it out by name only serves to confuse beginners who write standard cron (5 fields instead of 6). +2. `cronExpression` is a type-suffix tautology — the field is on a type called `CronSchedule`; calling the field `expression` (or even just `cron`) is enough. + +**Category:** 14 (Java implementation detail leak), 20 (type-suffix tautology). + +**Suggested name:** `expression` (with the doc clarifying "Quartz 6-field cron syntax: `seconds minutes hours dayOfMonth month dayOfWeek`"). The doc, not the field name, should explain the dialect. + +**Rationale:** The wire format `quartz_cron_expression` is locked, but the TS name is not. A simple, accurate field name with the dialect in the doc is more usable. + +### 11. `CronSchedule.timezoneId` — "Id" suffix is misleading + +**Location:** `src/v1/model.ts:90` + +```ts +/** + * A Java timezone id. The schedule will be resolved with respect to this timezone. + */ +timezoneId?: string | undefined; +``` + +The field carries an IANA timezone name like `"America/Los_Angeles"`. That is not an "id" in any normal sense (no numeric handle, no opaque token); it's a string identifier in a documented registry. The doc also locks the value space to "Java timezone id" — meaning the JVM TZ database, which is IANA-compatible but not guaranteed identical (some abbreviations like `EST`, `PST` are accepted in Java but ambiguous in IANA). + +**Category:** 19 (underspecified ID — actually a string name). + +**Suggested name:** `timezone` (or `tz`), with the doc specifying "IANA timezone name (e.g. 'America/Los_Angeles' or 'UTC')". Drop the "Java" qualifier — JS users do not need to know the backend's runtime. + +**Rationale:** `timezoneId` makes callers think there's a separate `getTimezones()` API that returns IDs. + +### 12. `Schedule.cronSchedule` — type-suffix tautology + +**Location:** `src/v1/model.ts:358` + +```ts +export interface Schedule { + ... + cronSchedule?: CronSchedule | undefined; + ... +} +``` + +The field name and type name are the same. `schedule.cronSchedule.expression` reads as "schedule's cron-schedule's expression" — the middle term is redundant. Compare to `Schedule.cron` or `Schedule.cronExpression` (with `CronSchedule` as the type), which read as `schedule.cron.expression`. + +**Category:** 20 (type-suffix tautology). + +**Suggested name:** `cron: CronSchedule`. Field shows up at use sites as `schedule.cron.expression`, which is the intended mental model. + +**Rationale:** Field names should describe the *role* the value plays in the parent, not echo the type. The role is "the cron part of this schedule". + +### 13. `SchedulePauseStatus` — domain prefix only partially applied + +**Location:** `src/v1/model.ts:18-21` + +```ts +export enum SchedulePauseStatus { + UNPAUSED = 'UNPAUSED', + PAUSED = 'PAUSED', +} +``` + +Same enum-name shape as `alerts/v2.SchedulePauseStatus` — i.e. the prefix is `Schedule`, not `Dashboard` or `Lakeview`. So we have a `Schedule`-prefixed enum inside the lakeview package and an identical-looking enum inside the alerts package. The two are not interchangeable but they look identical at the type level — a developer copying code between packages might think they are. + +Also: a two-value enum named `*Status` for two paused-or-not states is overengineering. A boolean (`paused: boolean`) reads more naturally and prevents the case where a future `SUSPENDED` value silently changes paused-checks. + +**Category:** 1 (overly generic prefix), 7 (overly verbose for binary). + +**Suggested name:** Either rename to `DashboardSchedulePauseStatus` (preserves enum), or collapse to `Schedule.paused?: boolean`. The former retains the option for a third state; the latter is what most users will expect. + +**Rationale:** Binary status enums are an anti-pattern in TS where booleans are first-class. The Go SDK is constrained to enums (no booleans for proto), but the TS SDK is not. + +### 14. `Schedule.pauseStatus` — field describes a control input, not a status + +**Location:** `src/v1/model.ts:360` + +```ts +/** The status indicates whether this schedule is paused or not. */ +pauseStatus?: SchedulePauseStatus | undefined; +``` + +"Status" implies read-only state (something the system reports). But this field is also writable — clients send `pauseStatus: PAUSED` to *cause* the pause. The field is therefore the pause *setting*, not the pause *status*. The doc reinforces the misuse ("indicates whether…"). + +**Category:** 6 (misleading), 20 (the type ends in `Status` and the field starts with `pauseStatus` — overlap). + +**Suggested name:** `paused: boolean` (see #13), or `pauseSetting`/`pauseMode`. Reserve `*Status` for read-only state. + +**Rationale:** Read/write distinction. If the user only learns the field name, they will not predict that setting `UNPAUSED` is how you un-pause. + +### 15. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb + +**Location:** `src/v1/model.ts:293`, `src/v1/client.ts:574` + +"Migrate" can mean (a) copy and convert, (b) move-and-delete-source, (c) rewrite-in-place. The JSDoc on the method ("Migrates a classic SQL dashboard to Lakeview.") suggests (a): the source dashboard remains, a new AI/BI dashboard is created. The verb does not encode this. + +**Category:** 17 (inconsistent action verb across the SDK). + +**Suggested name:** `convertToLakeviewDashboard` / `importFromClassicSql` / `cloneFromClassicSql`. The verb should distinguish from `move`/`migrate-and-replace`. + +**Rationale:** The other Databricks "migrate" endpoints (e.g. `tables.migrate`, `permissions.migrate`) actually move state. This one creates a new asset. Same verb, two operations. + +### 16. `MigrateDashboardRequest.sourceDashboardId` — domain mismatch + +**Location:** `src/v1/model.ts:295` + +```ts +/** UUID of the dashboard to be migrated. */ +sourceDashboardId?: string | undefined; +``` + +The package documents `dashboardId` as identifying a Lakeview / AI/BI dashboard. `sourceDashboardId` here is a **classic SQL dashboard** ID — a different ID space, fetched from a different API (`/api/2.0/sql/dashboards/{id}`). Using the same `dashboardId` type-name suggests they are interchangeable; they are not. + +**Category:** 16 (field contradicting type domain). + +**Suggested name:** `sourceLegacyDashboardId` / `classicSqlDashboardId` / `sqlDashboardId`. JSDoc should call out the ID space explicitly. + +**Rationale:** Cross-API IDs that share a name are a frequent source of integration bugs. + +### 17. `MigrateDashboardRequest.updateParameterSyntax` — confusing default + leaky implementation hint + +**Location:** `src/v1/model.ts:300-304` + +```ts +/** + * Flag to indicate if mustache parameter syntax ({{ param }}) should be auto-updated + * to named syntax (:param) when converting datasets in the dashboard. + */ +updateParameterSyntax?: boolean | undefined; +``` + +Issues: + +1. The default behavior (when omitted) is undocumented. From the wire form, server defaults are likely `false`, meaning the migration will leave mustache placeholders intact and break the query — which is the opposite of what most callers want. +2. The doc invokes "mustache" (a template-engine name) without explanation; a TS reader who hasn't worked in classic SQL Dashboards will not know what `{{ param }}` is. +3. "Update" is vague: it's actually a *rewrite* — `:param` is not an "update" of `{{ param }}` but a syntax replacement. + +**Category:** 6 (misleading), 13 (verb tense inconsistency: "update" vs "rewrite"), 15 (generic field name losing meaning). + +**Suggested name:** `rewriteParametersAsNamed: boolean` (verb explicit) or `mustacheCompatibilityMode: boolean` (opposite polarity, clearer default). Doc should state the default and provide an example. + +**Rationale:** Migration is a one-way operation; setting this wrong is hard to recover from. + +### 18. `trashDashboard` — see #4. Also: only soft-delete method in the entire package + +**Location:** `src/v1/client.ts:653` + +Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` method is paired with no `restoreDashboard` or `untrashDashboard`. The method moves the dashboard into `TRASHED` lifecycle state, but the API doesn't expose how to undo it via the SDK — a caller has to use `updateDashboard({ dashboard: { lifecycleState: ACTIVE } })`. Discovery from method names alone gives no hint that "restore" exists. + +**Category:** 17 (inconsistent action verb), see #4. + +**Suggested name:** `deleteDashboard` (semantics-clear). Add `restoreDashboard` (or document `updateDashboard` as the restoration path in the `trashDashboard` JSDoc). + +**Rationale:** Symmetry. `deletePermanently` is also unavailable here — soft-delete is the only delete. + +### 19. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles + +**Location:** `src/v1/model.ts:307`, `src/v1/model.ts:323` + +`PublishDashboardRequest` is the input to `publishDashboard()`. `PublishedDashboard` is the response. The names are one letter apart (`Publish*` vs `Published*`). A code reader picking either out of an auto-complete list can grab the wrong one and the compiler will not immediately tell them apart at construction time — both are records with `warehouseId?: string`. + +**Category:** 6 (misleading visual similarity), 12 (overlapping concepts). + +**Suggested name:** `PublishDashboardRequest` → `PublishDashboardOptions` or `PublishDashboardInput`. The "Request" suffix doesn't distinguish on the auto-complete; an `Input`/`Options` suffix does. + +**Rationale:** Reduce typo bugs. The Databricks SDK already uses `*Options` in `ClientOptions`, `CallOptions`, so the pattern is precedented. + +### 20. `GetPublishedDashboardEmbeddedRequest` / `getPublishedDashboardEmbedded` — adjective-as-method-suffix + +**Location:** `src/v1/model.ts:169-175`, `src/v1/client.ts:301` + +```ts +async getPublishedDashboardEmbedded(req: ...): Promise +``` + +41 characters in the method name; the suffix "Embedded" is an adjective stuck on the end of `getPublishedDashboard`. The natural English form is "get an embedded view of the published dashboard". The pairing `getPublishedDashboard` + `getPublishedDashboardEmbedded` suggests these are alternative *views* of the same resource — which is what flags 2, 5, and 6 hint at: the SDK uses three separate names for what is conceptually `getPublishedDashboard(mode: 'metadata' | 'embedded' | 'tokenInfo')`. + +**Category:** 1 (vague suffix), 7 (overly verbose). + +**Suggested name:** `getPublishedDashboardForEmbedding` or restructure as `getPublishedDashboard({ mode: 'embedded' })`. + +**Rationale:** Method name should hint at side effect or return shape; an adjective suffix does neither. + +### 21. `GetPublishedDashboardTokenInfoResponse.customClaim` — undescriptive field for opaque blob + +**Location:** `src/v1/model.ts:196` + +```ts +/** + * Custom claim generated from external_value and external_viewer_id. + * Format: `urn:aibi:external_data:::` + */ +customClaim?: string | undefined; +``` + +The doc string is the only place that defines what the field is — a URN with a specific format. The field name `customClaim` is generic JWT-speak (a "custom claim" in OAuth/OIDC is any non-standard claim). The actual value is a *Databricks AI/BI external-data URN*. Two layers of indirection from the name. + +**Category:** 15 (generic field name). + +**Suggested name:** `externalDataUrn` or `embeddingUrn` (with `customClaim` mentioned in JSDoc as "this URN is embedded as a custom claim in the issued OAuth token"). + +**Rationale:** Distinct from the OIDC sense of "custom claim". + +### 22. `AuthorizationDetails.type` — collides with TS reserved feeling + +**Location:** `src/v1/model.ts:28` + +```ts +type?: string | undefined; +``` + +`type` is not a reserved word in TypeScript, but it is a *contextual* keyword (used in `type X = ...` declarations and in `import type { ... }`). Using `type` as a field name is legal but creates friction in tooling — auto-complete and rename-symbol can mis-fire. + +The field's documented value space is also limited: `"workspace_rule_set"` is the only documented constant; the rest is open. So the field is closer to a tag (`discriminator: 'workspace_rule_set'`) than a free string. + +**Category:** 10 (reserved-word-feel collision), 15 (generic). + +**Suggested name:** `kind` (matches K8s convention for discriminator fields), or `constraintType` to keep "type" but specialize it. + +**Rationale:** Avoid syntax-coloring confusion (`type: string` reads ambiguously) and signal that the field is a discriminator. + +### 23. `AuthorizationDetails.resourceLegacyAclPath` — legacy compatibility field in current API + +**Location:** `src/v1/model.ts:36` + +```ts +/** The acl path of the tree store resource resource. */ +resourceLegacyAclPath?: string | undefined; +``` + +Three issues: + +1. The field name advertises `Legacy` — meaning a field deliberately kept around for backwards compatibility. There is no documented sunset date or replacement field. A public API surface that hard-codes "legacy" in the field name will be locked into supporting it forever (since the name itself is a contract). +2. The doc has a typo: "tree store resource resource" — duplicated "resource". +3. `acl` is lowercase (compare to the more common `Acl`/`ACL` in the SDK). + +**Category:** 6 (misleading — "legacy" is permanent here), 14 (TreeStore is an internal Databricks system, leaking implementation), 16 (field contradicts type domain). + +**Suggested name:** `legacyAclPath` (drop the duplicate "resource"; rename does not really fix the long-term problem, only the doc string typo). + +**Rationale:** Cosmetic doc fix is cheap; the structural issue is that the field name preserves an internal compat detail in the public API. + +### 24. `Subscription.skipNotify` — negative polarity boolean + +**Location:** `src/v1/model.ts:400` + +```ts +/** + * Controls whether notifications are sent to the subscriber for scheduled dashboard refreshes. + * If not defined, defaults to false in the backend to match the current behavior (refresh and notify) + */ +skipNotify?: boolean | undefined; +``` + +Negative-polarity booleans are an antipattern: callers must invert the meaning mentally (`subscription.skipNotify = false` means "do notify"). Combined with `?:` optionality, the field has three meaningful states (`undefined` = backend default = notify; `false` = notify; `true` = don't notify), where two of them mean the same thing. + +The doc also leaks "in the backend" — the default is the backend's, not the SDK's. + +**Category:** 1 (vague), 14 (the backend-leak phrasing). + +**Suggested name:** `notify?: boolean` (positive polarity) or `silent?: boolean`. Document the inverted default. + +**Rationale:** Positive-polarity booleans halve the cognitive load. + +### 25. `Subscription.createdByUserId` typed as `number` + +**Location:** `src/v1/model.ts:386` + +```ts +/** UserId of the user who adds subscribers (users or notification destinations) to the dashboard's schedule. */ +createdByUserId?: number | undefined; +``` + +User IDs in Databricks are 64-bit integers; storing them as JS `number` overflows above 2^53. The Databricks JS SDK has the same problem elsewhere, but it surfaces visibly here because the field is part of every Subscription response. + +Also, the doc string is past-tense verb plus present-tense ("adds") — inconsistent. + +**Category:** 19 (underspecified ID — `number` is wrong storage), 16 (field contradicts wire format which is int64). + +**Suggested name:** Keep `createdByUserId`, change type to `string` (matching the SCIM API's `users/` convention) or `bigint`. JSDoc should clarify the format. + +**Rationale:** Silent overflow is the worst kind of bug. + +### 26. `Subscription_Subscriber_User.userId` typed as `number` — same issue + +**Location:** `src/v1/model.ts:426` + +Same `number` overflow risk. Also: the field is buried three names deep (`Subscription_Subscriber_User.userId`) which obscures the issue at the use site. + +**Category:** 19, 16. + +**Suggested name:** Change to `string` or `bigint`. Combined with the fix from #8 (rename to `UserSubscriber`), the field becomes `userSubscriber.userId`. + +--- + +## Low severity + +### 27. `Dashboard.warehouseId` — underspecified ID + +**Location:** `src/v1/model.ts:112` + +`warehouseId` is a SQL Warehouse ID. The field doc says "warehouse ID used to run the dashboard". Format isn't specified — it's an alphanumeric like `1abc2d3456e789f`. Common across the SDK. + +**Category:** 19. + +**Suggested name:** Keep `warehouseId`, but JSDoc should specify "SQL Warehouse ID (alphanumeric, found at `/sql/warehouses/{id}` in the UI)". + +### 28. `Schedule.warehouseId` — duplicate concept with `Dashboard.warehouseId` + +**Location:** `src/v1/model.ts:373` + +```ts +/** The warehouse id to run the dashboard with for the schedule. */ +warehouseId?: string | undefined; +``` + +A schedule can override the dashboard's default warehouse. This is fine, but the field name does not signal "override" — at first read it looks like the dashboard's warehouse is being duplicated into the schedule. + +**Category:** 19 (underspecified), 12 (overlap with `Dashboard.warehouseId`). + +**Suggested name:** `warehouseIdOverride` or `overrideWarehouseId`. + +### 29. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing + +**Location:** `src/v1/model.ts:118`, `src/v1/model.ts:367`, `src/v1/model.ts:391` + +Consistent within the package, but the HTTP spec spells it `ETag`. Most TS SDKs use lowercase, so it's defensible. Flagged for whole-codebase consistency (compare `alerts.md` #14 on `notifyOnOk` for similar acronym-casing concerns). + +**Category:** 3. + +**Suggested name:** Keep `etag`. Note the project convention. + +### 30. `Dashboard.path` vs `Dashboard.parentPath` — overlap + +**Location:** `src/v1/model.ts:99`, `src/v1/model.ts:135` + +```ts +path?: string | undefined; // workspace path of the dashboard asset, including the file name +parentPath?: string | undefined; // workspace path of the folder containing the dashboard +``` + +`path = parentPath + '/' + filename`. The two fields are derivable from each other (given a known filename rule). Maintaining both is convenient for clients but means clients must keep them in sync on writes. Field names give no hint about the relationship. + +**Category:** 15 (generic), 6 (silently redundant). + +**Suggested name:** Keep both. Either rename `path → fullPath` for symmetry, or document the relationship in JSDoc on both fields. + +### 31. `Dashboard.serializedDashboard` — type-suffix tautology + +**Location:** `src/v1/model.ts:127` + +```ts +serializedDashboard?: string | undefined; +``` + +Field is on `Dashboard`; suffix repeats the type name. The field holds a JSON string of the dashboard's layout — a stringified payload. + +**Category:** 20. + +**Suggested name:** `serialized` or `content` or `layoutJson`. The dashboard's "content" is a more useful description. + +### 32. `Dashboard.lifecycleState` — generic field name + +**Location:** `src/v1/model.ts:129` + +The field is typed `LifecycleState` (already flagged in #3). The field name doesn't add new information. Fine in isolation, but with the rename suggested in #3 (`DashboardLifecycleState`), the field becomes more readable: `dashboard.lifecycleState: DashboardLifecycleState`. + +**Category:** 15. + +### 33. `createTime`/`updateTime` suffix `Time` — convention question + +**Location:** Many fields on `Dashboard`, `Schedule`, `Subscription` + +The package uses `*Time` suffix (`createTime`, `updateTime`). The alerts v2 package uses `*At` (`lastEvaluatedAt`). Inconsistency across the SDK. The field type here is `Temporal.Instant`, which is point-in-time — `*At` reads more naturally for instants in English. + +**Category:** 9 (related; suffix-grammar inconsistency). + +**Suggested name:** Pick a project-wide convention. Recommend `*At` for instants (`createdAt`, `updatedAt`). Aligns with idiomatic JS/TS and the Rails-influenced ecosystem. + +### 34. `PublishedDashboard.revisionCreateTime` — over-qualified + +**Location:** `src/v1/model.ts:331` + +```ts +/** The timestamp of when the published dashboard was last revised. */ +revisionCreateTime?: Temporal.Instant | undefined; +``` + +"Revision Create Time" reads as "the create time of the revision", i.e. when the latest revision was published. The field name carries three nouns (`revision`, `create`, `time`). + +**Category:** 15 (generic, layered). + +**Suggested name:** `publishedAt` or `lastPublishedAt`. Captures the user's mental model directly. + +### 35. `PublishDashboardRequest.embedCredentials` — verb-as-field is fine; flag for adjacency + +**Location:** `src/v1/model.ts:315` + +```ts +embedCredentials?: boolean | undefined; +``` + +Reads as "embed [the publisher's] credentials". Adjacent to `Dashboard.serializedDashboard` semantically — both control whether the response carries embedded content. Different concepts but visually parallel. + +**Category:** 7 (mild verbosity). + +**Suggested name:** Keep. Document the security tradeoff inline. + +### 36. `ListDashboardsRequest.showTrashed` — verb mismatch with state name + +**Location:** `src/v1/model.ts:235` + +```ts +showTrashed?: boolean | undefined; +``` + +The field is named `showTrashed`, but the lifecycle state is `TRASHED`. Consistent within "trash vocabulary", but inconsistent if the rename in #4 lands (`DELETED` lifecycle would imply `showDeleted` flag). + +**Category:** 13 (verb tense across vocabulary), 17 (action verb consistency). + +**Suggested name:** Tie to whichever vocabulary wins. If `delete`/`DELETED`, then `includeDeleted`. The `show` prefix is also UI-flavored (compare `include`/`with` prefixes in REST APIs). + +### 37. `DashboardView.DASHBOARD_VIEW_BASIC` — long enum value (see #2 for the enum itself) + +**Location:** `src/v1/model.ts:8` + +Member is `DASHBOARD_VIEW_BASIC = 'DASHBOARD_VIEW_BASIC'` — both Pascal-prefix and the literal value carry `DASHBOARD_VIEW_`. The wire format is locked, but the TS member name need not echo the enum prefix: `BASIC = 'DASHBOARD_VIEW_BASIC'` is sufficient. + +**Category:** 2 (redundant enum prefix), 18 (long). + +**Suggested name:** `DashboardView.BASIC = 'DASHBOARD_VIEW_BASIC'`. + +### 38. `listDashboardsIter`, `listSchedulesIter`, `listSubscriptionsIter` — `Iter` is cryptic + +**Location:** `src/v1/client.ts:455,506,557` + +Same as `alerts.md` #31. `Iter` is a Go/Rust idiom for "iterator generator". In JS/TS the natural name is `*Async` or `*Stream` or `*All`. Consistency across the SDK is preferable. + +**Category:** 5 (cryptic). + +**Suggested name:** `listAllDashboards`/`listDashboardsAsync` (the existing return type is `AsyncGenerator` so `Async` is descriptive). + +--- + +## Observations + +### 39. `Dashboard.dashboardId` — tautology at use site + +**Location:** `src/v1/model.ts:95` + +```ts +export interface Dashboard { + dashboardId?: string | undefined; + ... +} +``` + +Caller writes `dashboard.dashboardId`. Inside a type already named `Dashboard`, the field could be `id`. Many SDKs prefer the prefix-form for unambiguous logs and reflection, but the *consumer-facing* readability is poorer. + +**Category:** 8 (field name == type name with `Id` suffix), 20. + +**Suggested name:** `Dashboard.id` (and similarly `Schedule.id`, `Subscription.id`). Marshal/unmarshal already remaps to/from `dashboard_id`. + +### 40. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix + +**Location:** `src/v1/model.ts:61,67` + +```ts +datasetCatalog?: string | undefined; +datasetSchema?: string | undefined; +``` + +`Catalog` and `Schema` are Unity Catalog concepts. The prefix `dataset` is what scopes them (apply only to datasets in this dashboard). Without the prefix the fields would be ambiguous with workspace-level catalog/schema. The current names are accurate but a developer reading the field for the first time might think `datasetSchema` is a structural/JSON schema for the dataset — *Schema* is overloaded. + +**Suggested name:** Keep. Add JSDoc clarifying "this is the Unity Catalog *catalog* / *schema* applied to dataset queries". Done already in the JSDoc, but worth flagging. + +### 41. `ListSchedulesRequest.dashboardId` doc typo + +**Location:** `src/v1/model.ts:250` + +```ts +/** UUID identifying the dashboard to which the schedules belongs. */ +dashboardId?: string | undefined; +``` + +"schedules belongs" — verb agreement error. Same on `ListSubscriptionsRequest.dashboardId` line 271 ("subscriptions belongs") and 273 ("subscriptions belongs"). Generated-code artifact; fix at template level. + +**Category:** 9 (plural verb agreement). + +### 42. `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` — field name == type-tail + +**Location:** `src/v1/model.ts:409,414` + +```ts +userSubscriber?: Subscription_Subscriber_User | undefined; +destinationSubscriber?: Subscription_Subscriber_Destination | undefined; +``` + +Field name suffix `Subscriber` echoes the parent type `Subscriber`. If the parent renames per #8 to `Subscriber`, the fields become `subscriber.user`, `subscriber.destination` — much cleaner. + +**Category:** 8 (field name overlap with parent), 20. + +### 43. `index.ts` — mixed `export {...}` and `export type {...}` + +**Location:** `src/v1/index.ts:5,7-47` + +```ts +export {DashboardView, LifecycleState, SchedulePauseStatus} from './model'; +export type {AuthorizationDetails, ...} from './model'; +``` + +Enums are exported as values (correct — they have runtime representation); interfaces are exported as types (correct — type-only). The pattern is right; flagging only because a reader scanning the index file might miss the distinction. Consistent with other SDK packages. + +### 44. URL paths still use `lakeview` + +**Location:** Every method's URL constant in `client.ts`, e.g. line 112: `/api/2.0/lakeview/dashboards` + +Wire-format. The SDK cannot rename the URL without server cooperation. Flagged so that the rebrand mismatch noted in #1 is understood as partial (TS name is the lever; URLs are not). + +**Category:** 6. + +--- + +## Net assessment + +Lakeview / AI/BI Dashboards is a relatively small surface (5 enums-and-resources, 19 client methods) but the naming smells cluster around: + +1. **The rebrand from "Lakeview" to "AI/BI Dashboards"** is incomplete — the package name and URLs preserve the old codename, while the JSDoc mixes the two. +2. **Proto nested-message names** (`AuthorizationDetails_GrantRule`, `Subscription_Subscriber*`) reach four levels deep, requiring ESLint suppressions throughout. +3. **The trash/delete vocabulary split** (#4, #18, #36) is inherited from the alerts package's pre-v2 design — already fixed in alerts v2 but not in lakeview. +4. **Generic top-level type names** (`Dashboard`, `LifecycleState`, `CronSchedule`, `SchedulePauseStatus`) overlap with other packages in the SDK monorepo and force consumers to import-rename. +5. **`Schedule.pauseStatus` enum is a binary boolean** (#13, #14) — `paused: boolean` would be more idiomatic TS. +6. **64-bit user IDs typed as `number`** (#25, #26) silently truncate above 2^53. Same issue exists in other packages but is unsurfaced here. + +If only one change were possible, fixing the proto-nested type names (replacing `Subscription_Subscriber*` and `AuthorizationDetails_GrantRule` with namespace-merging or top-level types) would remove the most visible naming noise from the public API. diff --git a/.agent/naming-audit/logdeliveryconfigurations.md b/.agent/naming-audit/logdeliveryconfigurations.md new file mode 100644 index 00000000..dd76130d --- /dev/null +++ b/.agent/naming-audit/logdeliveryconfigurations.md @@ -0,0 +1,324 @@ +# Naming Audit: `logdeliveryconfigurations` (v1) + +**Package:** `@databricks/sdk-logdeliveryconfigurations` +**Path:** `/home/parth.bansal/sdk-js/packages/logdeliveryconfigurations/` +**Version audited:** `v1` +**Files audited:** +- `src/v1/model.ts` (404 lines) +- `src/v1/client.ts` (245 lines) +- `src/v1/utils.ts` (151 lines) +- `src/v1/index.ts` (25 lines) + +**Inferred domain:** Account-level CRUD for log delivery configurations +(REST: `POST/GET/PATCH /api/2.0/accounts/{account_id}/log-delivery`). +A log delivery configuration ties a `credentialsId` (AWS IAM role) and a +`storageConfigurationId` (S3 bucket) to a log type (`BILLABLE_USAGE` or +`AUDIT_LOGS`), optionally scoped by workspace IDs. There is no delete +endpoint by design — the API only supports disabling via the update +method. + +**Total weird names flagged: 36** + +## Summary + +| Severity | Count | +| --- | --- | +| High | 7 | +| Medium | 12 | +| Low | 10 | +| Observation | 7 | + +--- + +## High severity + +### H1. Package name `logdeliveryconfigurations` is overly verbose — `packages/logdeliveryconfigurations/` +- **File:** package directory. +- **Category:** 7 (overly verbose), 9 (singular/plural mismatch — pluralised package while every type inside is singular), 14 (Go/proto-style names). +- **Why weird:** 25 characters of all-lowercase concatenation — the longest single-domain package name in the workspace (compare `usagepolicy`, `usagedashboards`, `accountsettings`, `accountaccesscontrol`). The plural `configurations` is unique among sibling account packages, all of which use singular nouns (`accountsettings`, `usagepolicy`, `usagedashboards`, `billableusagedownload`). Users importing this package write `import {Client} from '@databricks/sdk-logdeliveryconfigurations/v1'` — 47 characters of specifier just to reach `Client`. +- **Suggested name:** `logdelivery` (singular, 11 chars, matches the URL path segment `/log-delivery` and the Go SDK service name `LogDelivery`). The doc comments inside this file already use "log delivery" as the noun phrase (`Client/Create`, `LogDelivery/PatchStatus` in `client.ts:88,213`). +- **Rationale:** Singular service noun is the cross-SDK convention. The TS types are already singular (`LogDeliveryConfiguration`, not `LogDeliveryConfigurations`). The trailing `s` produces a plural/singular mismatch between the package name and the dominant type. Fix at generator level since it affects every package. + +### H2. `LogDeliveryStatusEnum` — type-name carries `Enum` suffix — `model.ts:39` +- **File:** `model.ts:39-50`, exported in `index.ts:8`. +- **Category:** 20 (type-suffix tautology), 12 (duplicate concept — two enums with overlapping prefixes). +- **Why weird:** `LogDeliveryStatusEnum` is the *only* type in the audited package (and one of the few across the workspace) whose name ends in `Enum`. Every other enum here is just `LogDeliveryConfigStatus`, `LogDeliveryType`, `LogDeliveryOutputFormat` — no suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` was already claimed by the wrapper *interface* at `model.ts:208`. The wire-side schemas use `z.enum(LogDeliveryStatusEnum)` and `z.lazy(() => unmarshalLogDeliveryStatusSchema)` — the cognitive load of remembering which is enum, which is interface, and which is `Schema` is high. +- **Suggested name:** Rename the wrapper interface to `LogDeliveryAttempt` (it actually holds attempt fields: `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, `status`), freeing `LogDeliveryStatus` for the enum. Alternatively, rename the enum to `LogDeliveryAttemptStatus` (drops `Enum`, matches the fields it describes). +- **Rationale:** A field typed `attempt.status: LogDeliveryAttemptStatus` reads better than `logDeliveryStatus.status: LogDeliveryStatusEnum`. The `Enum` suffix is type-suffix tautology and is unique to this one type — a clear smell that the underlying noun is overloaded. + +### H3. `LogDeliveryConfigStatus` vs `LogDeliveryStatusEnum` — two near-identical enum names for unrelated concepts — `model.ts:12,39` +- **File:** `model.ts:12-17`, `model.ts:39-50`. +- **Category:** 12 (duplicate concept), 6 (misleading — both contain "status" + "log delivery"). +- **Why weird:** Both enums describe "status" of "log delivery", but cover orthogonal facets: + - `LogDeliveryConfigStatus`: `ENABLED` / `DISABLED` — whether the configuration is active. + - `LogDeliveryStatusEnum`: `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` — whether the most recent delivery attempt worked. + A reader sees `status?: LogDeliveryConfigStatus` on `LogDeliveryConfiguration.status` (line 199) and `status?: LogDeliveryStatusEnum` on `LogDeliveryStatus.status` (line 217). The two `status` fields live one level apart in the same response payload, with totally different domains. The class-doc on `LogDeliveryConfigStatus` (line 8-10) even mis-describes them: "ENABLED: All dependencies have executed and succeeded. DISABLED: At least one dependency has succeeded." That is nonsense — it appears to be JSDoc copy-pasted from another type. +- **Suggested name:** `LogDeliveryConfigStatus` → `LogDeliveryEnablement` (`ENABLED` / `DISABLED`). `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus` (`CREATED` / `SUCCEEDED` / ...). The differentiated nouns ("enablement" vs "attempt status") make the two enums distinguishable at the call site. +- **Rationale:** Identical noun ("Status") for incompatible domains is a classic source of bugs: a reviewer cannot tell at a glance whether `status === 'CREATED'` is checking the config or the last-delivery state. Renaming forces the distinction. + +### H4. `LogDeliveryConfigStatus` JSDoc is wrong — `model.ts:8-10` +- **File:** `model.ts:5-11`. +- **Category:** 6 (misleading — JSDoc claim contradicts type domain). +- **Why weird:** Class-level JSDoc says: + ``` + Log Delivery Status + `ENABLED`: All dependencies have executed and succeeded + `DISABLED`: At least one dependency has succeeded + ``` + But the enum values are `ENABLED` / `DISABLED` of a *configuration*, with the actual member docs reading "Configuration is enabled" / "Configuration is disabled". The class doc appears imported from a Workflows-domain enum (DLT pipelines have "dependencies"). The leading bare `*` on line 6 is also stray (likely an artefact of the generator emitting `/** * */` blocks). +- **Suggested name:** Rewrite JSDoc to "Whether this log delivery configuration is currently active. Set via the patch-status endpoint." +- **Rationale:** Misleading JSDoc is worse than no JSDoc — IDE tooltips, hover-help, and generated API reference will all display the wrong meaning. Same finding for `LogDeliveryOutputFormat` (line 22) and `LogDeliveryType` (line 54) — all three carry the stray `* ` on the second line. Across the SDK this is a generator artefact worth fixing globally. + +### H5. `LogDeliveryConfiguration.configId` and `.configName` use the cryptic abbreviation `config` — `model.ts:171,173` +- **File:** `model.ts:171,173` (also `model.ts:83,85`, `model.ts:126`, `model.ts:232`, `client.ts:94,126,154,218`). +- **Category:** 5 (cryptic abbreviation), 19 (underspecified ID — `configId` of what?). +- **Why weird:** The field is named `configId`, not `logDeliveryConfigurationId`. Because the surrounding type is `LogDeliveryConfiguration`, the wire field is `config_id`, and the doc says "The unique UUID of log delivery configuration", the truncation is acceptable in context — but on its own, `configId` is generic. A consumer pattern-matching on `configId` across multiple Databricks SDK packages cannot tell which "config" is meant. The wire path `/log-delivery/${req.configId}` in `client.ts:126,218` makes the same identifier look domain-detached. +- **Suggested name:** Either: + 1. Keep `configId` (short, matches wire) and rely on the surrounding type for context — but then JSDoc should say "The UUID of this log delivery configuration" (drop "the"). + 2. Rename to `id` and let `LogDeliveryConfiguration.id` carry meaning by type context — matches `databricks-sdk-go` resource-id idiom. +- **Rationale:** Pattern (2) is what Stripe / GitHub / Google APIs do (`Customer.id`, `Repository.id`). Pattern (1) is what the Databricks Go SDK does. Pick one and apply globally. As written, `configId` is the worst of both — a half-abbreviation that's neither a generic `id` nor a fully qualified `logDeliveryConfigurationId`. + +### H6. `GetLogDeliveryConfiguration` and `UpdateLogDeliveryConfiguration` repeat path/body fields with redundant naming — `model.ts:124-129,230-237` +- **File:** `model.ts:124-129` (`GetLogDeliveryConfiguration`), `model.ts:230-237` (`UpdateLogDeliveryConfiguration`). +- **Category:** 7 (overly verbose), 5 (cryptic — `configId` again), 6 (misleading — both fields are required path params but typed optional). +- **Why weird:** `GetLogDeliveryConfiguration` has exactly two fields, both optional: `configId` and `accountId`. The doc says "The log delivery configuration id of customer" — "of customer" reads like a Hindi/Indian-English idiom and is meaningless in this context (a config has no "of customer" — it belongs to an account). Both fields are part of the URL path (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — see `client.ts:126,218`); marking them `?: undefined` then falling back to `??' '` in the URL template produces silent bad requests (the client will hit `/api/2.0/accounts//log-delivery/` if `accountId` is absent). +- **Suggested name:** Rename "of customer" away (`The unique UUID of the log delivery configuration to fetch`). Drop `| undefined` on `configId` — it is required. `accountId` is fine as optional only if the client falls back to `ClientOptions.accountId` (which it does at `client.ts:126`); document that explicitly. +- **Rationale:** The current design type-checks fine but blows up at runtime with an unintuitive URL. Required path params should be required types. The "of customer" prose is generator-emitted boilerplate worth removing. + +### H7. `unmarshal*_ResponseSchema` and `marshal*Schema` — underscore in TS identifiers — `model.ts:243,255,267,332` +- **File:** `model.ts:243,255,267,332` (also interface names `CreateLogDeliveryConfiguration_Response` at `model.ts:72`, `GetLogDeliveryConfiguration_Response` at `model.ts:132`, `ListLogDeliveryConfiguration_Response` at `model.ts:158`, `UpdateLogDeliveryConfiguration_Response` at `model.ts:240`). +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names — these are protobuf `Nested.Response` messages). +- **Why weird:** TypeScript convention is PascalCase / camelCase — no underscores. The generator emits `CreateLogDeliveryConfiguration_Response` because the wire proto has `message CreateLogDeliveryConfiguration { message Response {...} }`. Every offending type carries an eslint-disable comment (`// eslint-disable-next-line @typescript-eslint/naming-convention`). This is the same generator-level concern flagged in every prior audit, here amplified because every response type is underscored. +- **Suggested name:** Flatten the nested message: `CreateLogDeliveryConfigurationResponse` (no underscore). Same for `Get*Response`, `List*Response`, `Update*Response` and their schemas. +- **Rationale:** Fix at generator level — applies to every package. The eslint-disable suppression is itself a clue that the generator is fighting the TS convention rather than respecting it. + +--- + +## Medium severity + +### M10. `Client` class is unprefixed — `client.ts:46` +- **File:** `client.ts:46`, exported at `index.ts:3`. +- **Category:** 1 (vague), 12 (duplicate concept across packages — every Databricks SDK package exports its own `Client`). +- **Why weird:** A user importing this package writes `import {Client} from '@databricks/sdk-logdeliveryconfigurations/v1'` and immediately must alias (`import {Client as LogDeliveryClient}`) to compose multiple Databricks clients. Consistent across the SDK but worth flagging. +- **Suggested name:** `LogDeliveryClient` or `LogDeliveryConfigurationsClient`. Or expose only a namespace (`import * as logDelivery from '@databricks/sdk-logdeliveryconfigurations/v1'` then `logDelivery.Client`). +- **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. Same finding as `billableusagedownload` audit #8. + +### M11. Client method names embed the noun three times — `client.ts:90,122,150,214` +- **File:** `client.ts:90,122,150,192,214`. +- **Category:** 7 (overly verbose), 17 (inconsistent action verbs vs sibling packages). +- **Why weird:** `client.createLogDeliveryConfiguration(...)` is 27 characters. With the package prefix and the request type, a single call line reads: + ```ts + await client.createLogDeliveryConfiguration({logDeliveryConfiguration: {...}}) + ``` + That is "logDeliveryConfiguration" repeated three times in one expression. The Go SDK uses short method names (`Create`, `Get`, `List`, `PatchStatus`) because the noun comes from the receiver type. The TS port replicates the full noun. Sibling packages like `billableusagedownload.Client.download()` and `accountsettings.Client.disableLegacyFeatures()` use shorter names. +- **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.listIter()`, `client.updateStatus()`. The receiver type (`LogDeliveryClient`) already provides the noun. +- **Rationale:** TS method names should not repeat the type they live on. Once `Client` is renamed `LogDeliveryClient` (M10), the shorter forms are unambiguous. Note that the Go SDK uses `PatchStatus` (the actual HTTP verb is `PATCH`) — the TS `updateLogDeliveryConfiguration` is already a paraphrase, so consistency with Go is partly already lost. + +### M12. `updateLogDeliveryConfiguration` does not actually "update" — it only patches status — `client.ts:209-243` +- **File:** `client.ts:209-243`, `UpdateLogDeliveryConfiguration` at `model.ts:230`. +- **Category:** 6 (misleading), 17 (inconsistent verb — Go uses `PatchStatus`, TS uses `update`). +- **Why weird:** The method name `updateLogDeliveryConfiguration` suggests "update arbitrary fields of the config". In reality the request body only contains `configId`, `accountId`, and `status` (see `UpdateLogDeliveryConfiguration` interface at `model.ts:230-237`) — you can only flip ENABLED <-> DISABLED. The JSDoc on the method (`client.ts:209-212`) calls it out: "Enables or disables a log delivery configuration." The Go SDK method is named `PatchStatus`, which is honest. +- **Suggested name:** `patchStatus`, or `setStatus`, or `updateStatus`. The current name oversells the surface. +- **Rationale:** "Update" implies multi-field mutation. If a caller writes `client.updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new-prefix'})` they will be silently surprised — the `deliveryPathPrefix` is not part of the request DTO so it will not type-check (in TS strict mode), but they would have to read the type to learn that. The verb is a footgun. + +### M13. `listLogDeliveryConfigurationIter` — singular noun on a method returning multiple — `client.ts:192` +- **File:** `client.ts:192`. +- **Category:** 9 (singular/plural mismatch), 1 (vague — `Iter` suffix is opaque). +- **Why weird:** `listLogDeliveryConfigurationIter` is singular ("Configuration") but the iterator yields multiple configurations one by one (returns `AsyncGenerator`). Sibling packages use `list*sIter` (plural) — e.g., `listBudgetConfigurationsIter` in `budgets/src/v1/client.ts`. Also, `Iter` is an unhelpful abbreviation — TS users expect `AsyncIterable` or `streamAll` or `pageThrough`. +- **Suggested name:** `iterateLogDeliveryConfigurations` (plural noun, verb-prefix); or simply `listAll` (clean, returns generator). +- **Rationale:** Adjacent package `budgets` uses `listBudgetConfigurationsIter` (plural). Within this package, the non-iterator `listLogDeliveryConfiguration` is also singular but returns a `*Response` whose body field is `logDeliveryConfigurations` (plural — `model.ts:160`). The singular method name fights the plural data shape. + +### M14. `ListLogDeliveryConfiguration` (request type) is singular — `model.ts:141` +- **File:** `model.ts:141-155`. +- **Category:** 9 (singular/plural mismatch). +- **Why weird:** Same issue as M13 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. +- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (plural + `Request` suffix for clarity). +- **Rationale:** Naming should match data shape. Pluralisation is the standard signal that a method returns a collection. Cross-package inconsistency. + +### M15. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:117,205,217` +- **File:** `model.ts:117,205` (field `logDeliveryStatus: LogDeliveryStatus`), `model.ts:208` (interface `LogDeliveryStatus`), `model.ts:217` (`status?: LogDeliveryStatusEnum`). +- **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). +- **Why weird:** A reader looking at `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types: + - `LogDeliveryConfiguration` (the resource). + - `LogDeliveryStatus` (the wrapper holding attempt metadata). + - `LogDeliveryStatusEnum` (the actual ENABLED/CREATED-style enum). + Each layer adds the noun "Status" with different meaning. The field name `logDeliveryStatus` is redundant inside a `LogDeliveryConfiguration` (the prefix is implied) and clashes with the type-level prefix. +- **Suggested name:** Field: `lastAttempt: LogDeliveryAttempt`. Wrapper type: `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message` — drop `last` prefix once nested). Enum: `LogDeliveryAttemptStatus`. Result reads as `config.lastAttempt.status === 'SUCCEEDED'`. +- **Rationale:** "Status" is too generic to triple-stack. Renaming the wrapper to "Attempt" (its actual semantics) breaks the conflation cleanly. + +### M16. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:113-115,201-203` +- **File:** `model.ts:113-115,201-203`. +- **Category:** 13 (verb-tense inconsistency — `creation` is a noun, `update` is a verb), 6 (misleading — `number` type with JSDoc "epoch milliseconds"). +- **Why weird:** `creationTime: number` and `updateTime: number`. The first is noun-form ("creation"), the second is verb-form ("update"). Pair-wise they should match: `createdTime`/`updatedTime` (past participle) or `creationTime`/`updateTime` (noun). Also, both are `number` (epoch ms) but neither type signals "this is a unix timestamp in milliseconds"; the JSDoc carries that information. Across the SDK, audited packages have flagged similar issues. +- **Suggested name:** `createdAt: number` / `updatedAt: number` (canonical SaaS convention — Stripe/GitHub/Salesforce/Atlassian all use *At). Brand the type as `EpochMillis` for compile-time safety. +- **Rationale:** "*At" is the industry standard for timestamps. Same finding in many other audited packages (`budgets`, `apps`, etc.) — fix at generator level. + +### M17. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:109,197` +- **File:** `model.ts:108-109,196-197`. +- **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" sounds like a timestamp). +- **Why weird:** The field is `string`, but the JSDoc says "specified in YYYY-MM format". That is a year-month string, not a time. Compare with `creationTime: number` (which is an epoch-ms timestamp). The same word "Time" is used for two different formats. A `string` for "YYYY-MM" should be branded or use a `Temporal.YearMonth` from `@js-temporal/polyfill` (already a dependency at `package.json:23`). +- **Suggested name:** `deliveryStartMonth` (clarifies granularity), typed `Temporal.PlainYearMonth | string`. +- **Rationale:** "Time" implies high-resolution. The domain is monthly billing buckets, so "Month" is the right granularity. Same convention as `Stripe.Invoice.period_start` (epoch) vs `Stripe.UsageRecord.period.start` (date-only). + +### M18. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:105,193` +- **File:** `model.ts:104-105,192-193`. +- **Category:** 7 (overly verbose), 9 (singular/plural mix), 15 (generic suffix). +- **Why weird:** The field is `workspaceIdsFilter: number[]`. The plural `Ids` says "this is a list of IDs". The `Filter` suffix says "this is a filter". A `number[]` already conveys "list of ints". Calling it `workspaceIdsFilter` adds redundant `Filter` noise; calling it just `workspaceIds` (the actual content) would be clearer. Compare with `ListLogDeliveryConfiguration.credentialsId: string` (singular, no `Filter` suffix at `model.ts:145`) which serves the same conceptual role. +- **Suggested name:** `workspaceIds: number[]` (drop `Filter`). Or `filterByWorkspaceIds` if intent must be made explicit. +- **Rationale:** Type-driven inference: a `number[]` named after the entity is unambiguous. `Filter` is generic ceremony. + +### M19. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:105,193` +- **File:** `model.ts:104-105,192-193`. +- **Category:** 6 (misleading), 19 (underspecified ID). +- **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double precision float — only safe up to 2^53 - 1. Databricks workspace IDs are int64 server-side; sending an ID greater than 2^53 will silently lose precision in the JSON wire. The TS type should be `bigint[]` or `(number | bigint)[]` or branded. +- **Suggested name:** `workspaceIds: bigint[]` (matches the int64 wire). Or `workspaceIds: WorkspaceId[]` with a branded `type WorkspaceId = number & {__brand: 'WorkspaceId'}`. +- **Rationale:** Cross-package issue. Same finding will recur on every `*Id: number` field that maps to an int64 wire. Fix at generator level: emit `bigint` for `int64`. + +### M20. `host` field on `Client` lacks domain context — `client.ts:47` +- **File:** `client.ts:47,62`. +- **Category:** 1 (vague), 15 (generic field name). +- **Why weird:** `private readonly host: string` — without context, `host` could be any URL or hostname. The setter at line 62 trims trailing slash. The semantically correct name is `databricksHost` or `workspaceUrl` or `baseUrl` (the actual content is `https://.../`, not just a hostname like `example.com`). +- **Suggested name:** `baseUrl` (matches the actual content — a URL including scheme). +- **Rationale:** Same pattern across every package's `Client`. Fix at generator. Same finding as `billableusagedownload` audit #?. + +### M21. `parseResponse` / `marshalRequest` verb asymmetry — `utils.ts:113,119` +- **File:** `utils.ts:113-117` (`parseResponse`), `utils.ts:119-121` (`marshalRequest`). +- **Category:** 17 (inconsistent action verbs). +- **Why weird:** `parseResponse` (the inverse of `marshalRequest`) uses `parse`; the request side uses `marshal`. The verbs do not pair — they read as different layers. Pair would be `unmarshalResponse`/`marshalRequest` or `parseResponse`/`serializeRequest`. +- **Suggested name:** `unmarshalResponse`/`marshalRequest` (already the verb used on the schema names: `unmarshal*Schema` / `marshal*Schema`). +- **Rationale:** The schemas are already named `unmarshal*Schema`/`marshal*Schema` (lines 243, 280, 335). The utility functions should match. + +--- + +## Low severity + +### L22. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` +- **File:** `model.ts:56-61`. +- **Category:** 9 (singular/plural mismatch), 18 (long enum values). +- **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered. They should match — either `BILLABLE_USAGE_LOGS` / `AUDIT_LOGS` (both plural) or `BILLABLE_USAGE` / `AUDIT` (both singular). +- **Suggested name:** `BILLABLE_USAGE` / `AUDIT` (drop the `_LOGS` — the enum is `LogDeliveryType` so "logs" is implied). +- **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the type name) is cleaner. + +### L23. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` +- **File:** `model.ts:23-28`. +- **Category:** 3 (acronym casing — fine here since it matches the wire), Observation. +- **Why weird:** Two-value enum where `log_type === 'BILLABLE_USAGE'` forces `output_format === 'CSV'` and `log_type === 'AUDIT_LOGS'` forces `'JSON'` (see JSDoc on `outputFormat` at `model.ts:93-96`). The field is therefore *always* derivable from `logType` — making it a redundant field, not a redundant enum, but worth flagging. +- **Suggested name:** Drop `outputFormat` from the request DTO (it can be derived server-side). Keep on the response DTO for clarity. +- **Rationale:** Not strictly a naming issue, but reduces API surface area. + +### L24. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` +- **File:** `model.ts:13-16`. +- **Category:** 1 (vague). +- **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the doc says exactly what the name says. JSDoc should add information, not echo identifiers. +- **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured S3 bucket." +- **Rationale:** Cross-cutting generator concern. + +### L25. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` +- **File:** `model.ts:48-49`. +- **Category:** 6 (misleading). +- **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc says it actually means "configuration has been disabled since the release of this feature or there are no workspaces in the account". That's not "not found"; it's "no logs to deliver because account state". +- **Suggested name:** `NO_DATA` or `NOT_APPLICABLE` or `DISABLED_AT_RELEASE` — anything that doesn't sound like a 404. +- **Rationale:** API value names should not collide with HTTP semantics that mean something different. A monitoring dashboard surfacing `status === 'NOT_FOUND'` will mislead an operator into thinking the config was deleted. + +### L26. `PACKAGE_SEGMENT` constant — `client.ts:41` +- **File:** `client.ts:41-44`. +- **Category:** 1 (vague), 15 (generic). +- **Why weird:** `Segment` is a generic CS term. The comment "Package identity segment for this client to be used in the User-Agent header" (`client.ts:40`) is the disambiguator; without it the constant name does not communicate what it is. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Cross-package consistency — same finding in every audited package. Worth normalising at generator level. Same as `billableusagedownload` audit #10. + +### L27. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` +- **File:** `client.ts:51,72`. +- **Category:** 20 (type-suffix tautology). +- **Why weird:** Field name and type both end in `Client`. Convention is widespread but flagged per rule 20. +- **Suggested name:** `transport: HttpClient` (matches the imported package `@databricks/sdk-databricks/transport`). +- **Rationale:** `transport` is what HTTP layers are usually named in language-agnostic SDK terminology (gRPC, GraphQL clients, etc.). It avoids the `Client/Client` echo. Tolerable as-is. + +### L28. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` +- **File:** `client.ts:91,99,103,...` (every method). +- **Category:** 5 (cryptic abbreviation). +- **Why weird:** Three-letter abbreviations for parameter and local names. The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. +- **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. +- **Rationale:** Spelling out costs nothing and improves readability. Same finding across every audit. + +### L29. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` +- **File:** `client.ts:196`. +- **Category:** 5 (cryptic), 1 (vague — `pageReq` is shorthand for "request for next page"). +- **Why weird:** Variable holds the *modified* request for each page (with `pageToken` updated). `pageReq` reads as "page request" — a noun describing the page itself. +- **Suggested name:** `currentRequest` or `paginatedRequest`. Or unify with `request` if you adopt option-bag style. +- **Rationale:** Low; loop-local variable. + +### L30. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` +- **File:** `utils.ts:26-38,65-94`. +- **Category:** 1 (vague), 17 (inconsistent layer naming). +- **Why weird:** Two functions named almost identically doing very different things. `executeCall` wraps the call in retry/rate-limit; `executeHttpCall` does the raw HTTP send + decode + APIError. Within the same file the naming distinction is too subtle. +- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `dispatchHttp`). Or just `wrapRetry` / `sendHttp`. +- **Rationale:** Same finding as `billableusagedownload` audit #13. Cross-package generator concern. + +### L31. `HttpCallOptions` — `utils.ts:15` +- **File:** `utils.ts:15-19`. +- **Category:** 1 (vague suffix `Options`), 12 (duplicate `Options` naming). +- **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` from `@databricks/sdk-core/api` imported at line 3). The local interface shadows the imported one cognitively. The field is not user-facing — it is an internal bag. +- **Suggested name:** `HttpCallContext` (it is not user-tunable options; it is an internal context bag). +- **Rationale:** Distinguish internal context bags from user-tunable option structs. Same finding as `billableusagedownload` audit #14. + +--- + +## Observations + +### O32. `flattenQueryParams` is exported but unused — `utils.ts:123` +`client.ts` does its own query-param construction inline (lines 155-167) using `new URLSearchParams()` and four `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called by this package. This is a generator artefact — every generated package ships this helper. + +### O33. `parseResponse` is unused — `utils.ts:113` +Actually, `parseResponse` *is* used (4 call sites in `client.ts:109,137,180,233`). Not dead. Correction to prior packages' findings: in `logdeliveryconfigurations`, parseResponse is actively in use. + +### O34. `marshalRequest` is used twice — `client.ts:95,219` +Used for `createLogDeliveryConfiguration` and `updateLogDeliveryConfiguration`. Not dead. + +### O35. `accountId` URL fallback — `client.ts:94,126,154,218` +`createLogDeliveryConfiguration` (line 94) reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client fallback!), while the other three methods do `req.accountId ?? this.accountId ?? ''`. The create path silently differs — if `ClientOptions.accountId` is set but the caller forgets to put it inside `logDeliveryConfiguration`, the URL becomes `/api/2.0/accounts//log-delivery`. This is a correctness bug surfaced by a naming/structure inconsistency: the request DTO nests the account ID one level deeper than the others. +- **Category:** 6 (misleading), 16 (field placement contradicts wire-level convention). +- **Suggested fix:** Make `req.accountId ?? this.accountId ?? ''` consistent across all four methods (the create path should reach the top-level `accountId` and the client-options fallback, not just the nested wrapper field). + +### O36. `marshalCreateLogDeliveryConfigurationSchema` typed as bare `z.ZodType` (not parameterised) — `model.ts:335,345,379,393` +None of the four marshal schemas carry a type parameter: `z.ZodType` instead of `z.ZodType`. The unmarshal schemas *are* parameterised (`z.ZodType` at line 280, etc.). The asymmetry is invisible to callers but means `marshal*Schema.parse(input)` returns `unknown` rather than a known type. Generator concern. +- **Category:** 6 (misleading — type appears typed but is in fact `any`-equivalent). + +### O37. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,32,53,64,77,120,137,165,225` +Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the first line (e.g., line 6: +``` + * * + * Log Delivery Status +``` +). Looks like the generator emits an empty paragraph break that renders as `*`. Also, `` appears in raw form throughout (e.g., `model.ts:98,127,142,186`); it should be a literal "Databricks" or substituted at generation time. Neither is a name issue per se but both pollute the docs. + +### O38. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` +The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O35). The naming of `accountId` as "optional" in the type lies about the runtime requirement. + +--- + +## Domain glossary + +- **`account`** — Databricks account; the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) in every interface and as `ClientOptions.accountId` (`client.ts:50,63`). +- **`workspace`** — A Databricks workspace under an account; `int64` ID on the wire (lossy as `number` in TS — see M19). +- **`credentials`** — Refers to `Credentials.Create` (cross-package) — a stored AWS IAM role with policy/trust relationship. The `credentialsId` field (`model.ts:101,189`) links a log delivery config to a previously-created credentials resource. +- **`storage configuration`** — Refers to `Storage.Create` (cross-package) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:103,191`) links a log delivery config to a bucket. +- **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` that tells Databricks to write certain logs to a bucket. +- **`log type`** — One of `BILLABLE_USAGE` / `AUDIT_LOGS` — what kind of logs to deliver. +- **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always derivable from `log type`. +- **`delivery path prefix`** — S3 key prefix; defaults to bucket root. Restricted: no leading or trailing slash. +- **`delivery start time`** — `YYYY-MM` string; only applies to billable usage; lower bound is `2019-03`. +- **`config status`** — `ENABLED` / `DISABLED`. The config is never deleted — only disabled (see `client.ts:88,211`). +- **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND`. Reflects the state of the most recent delivery attempt; surfaced as `LogDeliveryStatus.status` (i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`). +- **`E2`** — Databricks deployment architecture (newer multi-region account model). Mentioned in `UpdateLogDeliveryConfiguration.accountId` JSDoc (`model.ts:233`). +- **`int64`** — Wire-level 64-bit signed integer; appears in `workspaceIdsFilter` JSDoc but typed `number` in TS (M19). +- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`); the Go SDK calls this method `PatchStatus`, the TS port renames it `updateLogDeliveryConfiguration` (M12). + +--- + +## File coverage + +- `src/v1/model.ts` (404 lines): read fully. +- `src/v1/client.ts` (245 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (25 lines): read fully. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md new file mode 100644 index 00000000..e0aff49e --- /dev/null +++ b/.agent/naming-audit/marketplaces.md @@ -0,0 +1,1134 @@ +# Naming Audit: marketplaces + +**Path:** `packages/marketplaces/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). +**Total weird names flagged:** 65 + +## Summary +| Severity | Count | +| --- | --- | +| High | 16 | +| Medium | 32 | +| Low | 10 | +| Observation | 7 | + +The marketplaces package is one of the more naming-distressed surfaces in the SDK. The single dominant problem is the proto-style `MessageType_Response` underscore-suffixed identifier pattern — present on 14 of the 24 request types and infecting `client.ts`, `index.ts`, and every transitive importer with `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. Closely behind it is the **inconsistent request-type convention** within a single file: some request types follow the verb-shaped Go style (`CreateFile`, `DeleteFile`, `GetListing`, `GetListings`, `UpdateListing`, `ListFiles`, `CreateProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders`, `CreateProviderAnalyticsDashboard`, `UpdateProviderAnalyticsDashboard`, `GetLatestVersionProviderAnalyticsDashboard`, `ListProviderAnalyticsDashboard`, `GetPersonalizationRequestsForProvider`, `UpdatePersonalizationRequestStatus`) while others follow the more idiomatic `*Request`/`*Response` suffix (`CreateExchangeRequest`, `DeleteExchangeRequest`, `GetExchangeRequest`, `UpdateExchangeRequest`, `ListExchangesRequest`, `CreateExchangeFilterRequest`, `DeleteExchangeFilterRequest`, `UpdateExchangeFilterRequest`, `ListExchangeFiltersRequest`, `AddExchangeForListingRequest`, `RemoveExchangeForListingRequest`, `ListExchangesForListingRequest`, `ListListingsForExchangeRequest`) — split almost perfectly down the provider/exchange axis but not advertised that way. Other notable issues are the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListings` request and `GetListings_Response` payload field both use `listings`, while `CreateListing` and `DeleteListing` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service", `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` exposing an internal commit-drawdown workflow with a 33-character enum value, and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). + +--- + +## High severity + +### 1. Proto-style `_Response` underscore-suffixed types — 14 occurrences + +**Location:** `src/v1/model.ts:182, 193, 202, 210, 238, 245, 252, 322, 334, 344, 354, 365, 375, 418, 438, 451, 633, 646, 656, 671` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface CreateFile_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface CreateListing_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface CreateProvider_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface CreateProviderAnalyticsDashboard_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteFile_Response {} +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteListing_Response {} +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteProvider_Response {} +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface GetFile_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface GetLatestVersionProviderAnalyticsDashboard_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface GetListing_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface GetListings_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface GetPersonalizationRequestsForProvider_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface GetProvider_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface ListFiles_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface ListProviderAnalyticsDashboard_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface ListProviders_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface UpdateListing_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface UpdatePersonalizationRequestStatus_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface UpdateProvider_Response { ... } +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface UpdateProviderAnalyticsDashboard_Response { ... } +``` + +20 types in this file carry an embedded underscore — illegal-feeling in idiomatic TypeScript (Google TS style guide § 5.2 specifies `PascalCase` without underscores). The fact that 14 distinct types and 14 corresponding `*_ResponseSchema` exports require disabling `@typescript-eslint/naming-convention` means the proto wart is fully visible in the public API. Every consumer who imports one of these types must accept the underscore in their own code (see `client.ts:29, 31, 33, 38, 41, 43, 45, 53, 55, 57, 59, 61, 63, 71, 75, 77, 88, 90, 93` and `index.ts:32, 34, 36, 38, 45, 47, 49, 53, 58, 60, 62, 64, 67, 76, 80, 82, 100, 102, 106`). +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). +- **Suggested name:** `CreateFileResponse`, `CreateListingResponse`, etc. — drop the underscore wherever the API is allowed to diverge from the wire. +- **Rationale:** The other half of this file uses the `*Request`/`*Response` convention (`CreateExchangeRequest`, `CreateExchangeResponse`), so the underscore form is internally inconsistent within a single 1770-line file. + +### 2. Verb-shaped request types — 14 occurrences + +**Location:** `src/v1/model.ts:174, 188, 197, 207, 233, 240, 247, 317, 331, 339, 348, 359, 370, 411, 434, 445, 627, 637, 650, 660` + +```ts +export interface CreateFile { ... } +export interface CreateListing { ... } +export interface CreateProvider { ... } +export interface CreateProviderAnalyticsDashboard {} +export interface DeleteFile { ... } +export interface DeleteListing { ... } +export interface DeleteProvider { ... } +export interface GetFile { ... } +export interface GetLatestVersionProviderAnalyticsDashboard {} +export interface GetListing { ... } +export interface GetListings { ... } +export interface GetPersonalizationRequestsForProvider { ... } +export interface GetProvider { ... } +export interface ListFiles { ... } +export interface ListProviderAnalyticsDashboard {} +export interface ListProviders { ... } +export interface UpdateListing { ... } +export interface UpdatePersonalizationRequestStatus { ... } +export interface UpdateProvider { ... } +export interface UpdateProviderAnalyticsDashboard { ... } +``` + +Top-level request types named with imperative verbs (`Create*`, `Delete*`, `Get*`, `List*`, `Update*`). TS types should be nouns; verbs are reserved for methods. The `Client` exposes the same identifier as both a method and a type: `client.createListing(req: CreateListing)`, `client.getListing(req: GetListing)`, `client.listProviders(req: ListProviders)` — verb-noun-verb-noun every time. Readers cannot tell from the type whether the symbol names a request shape or an operation. +- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs within file — see #3). +- **Suggested name:** `CreateFileRequest`, `CreateListingRequest`, `GetListingRequest`, `ListProvidersRequest`, etc. +- **Rationale:** See #3. + +### 3. Two competing request-type naming conventions in one file + +**Location:** Both patterns coexist throughout `src/v1/model.ts`. + +``` +Verb-shaped (Go style): *Request-suffixed (idiomatic TS): +CreateFile CreateExchangeRequest +CreateListing CreateExchangeFilterRequest +CreateProvider CreateExchangeResponse +DeleteFile DeleteExchangeRequest +DeleteListing DeleteExchangeFilterRequest +DeleteProvider GetExchangeRequest +GetFile UpdateExchangeRequest +GetListing UpdateExchangeFilterRequest +GetListings ListExchangesRequest +GetProvider ListExchangeFiltersRequest +ListFiles ListExchangesForListingRequest +ListProviders ListListingsForExchangeRequest +UpdateListing AddExchangeForListingRequest +UpdateProvider RemoveExchangeForListingRequest +... ... +``` + +Verb-shaped types are used for **provider-side** operations (listings, files, providers, personalization, analytics dashboard); `*Request`-suffixed types are used for **exchange-side** operations (exchanges, exchange filters, exchange-listing joins). The split likely reflects two different proto packages on the server but in TS it reads as arbitrary inconsistency. A single user calling both `client.createListing` and `client.createExchange` will import two completely differently-named request types: `CreateListing` and `CreateExchangeRequest`. There is no documentation or hint that this split is intentional. +- **Category:** 17 (inconsistent action verbs / naming patterns), 12 (duplicate convention — two patterns for the same concept). +- **Suggested name:** Pick one — and `*Request` is the rest-of-SDK norm. Cascade with #2. +- **Rationale:** A single ergonomic package should not require users to memorize which sub-domain uses which type-naming scheme. + +### 4. `Listing` — ambiguous central type + +**Location:** `src/v1/model.ts:456` + +```ts +export interface Listing { + id?: string | undefined; + summary?: ListingSummary | undefined; + detail?: ListingDetail | undefined; +} +``` + +`Listing` is the central noun of the package, but the name has two unrelated English meanings: a *marketplace listing* (a storefront entry) and a *list operation* (the verb "to list", noun "a listing of items"). The package frequently uses both meanings within a single line: +- `getListings(req: GetListings): Promise` — method name uses the verb sense ("get the listings"), the type name uses the noun sense (a "GetListings" request that returns marketplace listings). +- `ListListingsForExchangeRequest` reads as "list the listings for exchange" — the first `List` is the verb, the second `Listings` is the noun. +- `ExchangeListing` (line 278) is a join-row type — neither a storefront listing nor a list-operation but a third concept ("a listing in an exchange"). + +The triple overload is unavoidable given the domain word but the SDK does not disambiguate (e.g. by renaming join rows to `ExchangeListingLink` or `ExchangeMembership`). +- **Category:** 1 (vague), 12 (duplicate concepts), 15 (overloaded vocabulary). +- **Suggested name:** Keep `Listing` for the noun; rename `ExchangeListing` → `ExchangeListingLink` / `ListingExchangeMembership`; rename `GetListings` → `ListListingsRequest` (cascade with #2 and #3 — but note that gives `ListListingsRequest`, which is itself a stutter; the right fix may be `ListMarketplaceListingsRequest` or simpler `ListListings`). +- **Rationale:** "Listing" has multiple senses; the SDK uses all three; the API can mitigate this by giving the *join row* a less ambiguous name. + +### 5. `ExchangeListing` — overloaded "listing" inside the type name + +**Location:** `src/v1/model.ts:278` + +```ts +export interface ExchangeListing { + id?: string | undefined; + exchangeId?: string | undefined; + exchangeName?: string | undefined; + listingId?: string | undefined; + listingName?: string | undefined; + createdAt?: number | undefined; + createdBy?: string | undefined; +} +``` + +The type is a join row connecting an exchange to a listing (with denormalized names). Named `ExchangeListing` it parses as either "a listing of type Exchange" (no — exchanges and listings are distinct) or "the exchange-side view of a listing" (no — both sides are denormalized into the same row) or "a listing exposed in the exchange" (closer, but the type is really the *link*, not the listing itself). The `Exchange.linkedListings: ExchangeListing[]` field at line 263 makes the relationship visible but does not clarify the name. +- **Category:** 1 (vague), 6 (misleading: looks like an inheritance from `Listing`), 12 (overloaded with `Listing`). +- **Suggested name:** `ExchangeListingLink`, `ExchangeMembership`, `ListingExchangeAssociation`. +- **Rationale:** See #4. + +### 6. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order + +**Location:** `src/v1/model.ts:141, 592` + +```ts +export interface AddExchangeForListingRequest { + listingId?: string | undefined; + exchangeId?: string | undefined; +} + +export interface RemoveExchangeForListingRequest { + id?: string | undefined; +} +``` + +The operations are symmetric (associate / disassociate an exchange with a listing), but the request shapes are asymmetric: `Add` takes `(listingId, exchangeId)`, `Remove` takes a single `id: string` (which is actually the `ExchangeListing.id`, i.e. the join-row id — not the exchange id nor the listing id). The name `RemoveExchangeForListingRequest` reads as "remove the exchange for [this] listing", suggesting the body should reference both the exchange and the listing — but it just takes a join-row id. Similarly, `AddExchangeForListingResponse` returns `exchangeForListing: ExchangeListing` — the response field name re-states the "for listing" preposition that isn't carried on any other type. +- **Category:** 7 (overly verbose), 6 (misleading: `Remove*` doesn't match the field shape). +- **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`); rename response field `exchangeForListing` → `exchangeListing`. +- **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. + +### 7. `AddExchangeForListingResponse.exchangeForListing` — Greek-letter field name + +**Location:** `src/v1/model.ts:146-148` + +```ts +export interface AddExchangeForListingResponse { + exchangeForListing?: ExchangeListing | undefined; +} +``` + +The field name `exchangeForListing` is a noun phrase that mirrors the request verb ("Add Exchange For Listing"). But the value is an `ExchangeListing` (the join-row type). Just naming the field `exchangeListing` would match the type name and remove the "for" preposition that doesn't add information. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name doesn't quite match its type name). +- **Suggested name:** `exchangeListing` (matches the underlying type). +- **Rationale:** See #6. + +### 8. `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` — 33-character internal-domain enum value + +**Location:** `src/v1/model.ts:119-126` + +```ts +export enum MarketplaceFileType { + PROVIDER_ICON = 'PROVIDER_ICON', + EMBEDDED_NOTEBOOK = 'EMBEDDED_NOTEBOOK', + APP = 'APP', + EMBEDDED_MARKDOWN = 'EMBEDDED_MARKDOWN', + /** + * Consumer-attached supporting document (e.g., PDF) for a commit drawdown + * request. Stored under `staging/COMMIT_DRAWDOWN_REQUEST_ATTACHMENT/` (the + * entity stays in FILE_STATUS_STAGING permanently — no sanitization) with + * 14-day expiration; not served via the general presigned-GET path. + */ + COMMIT_DRAWDOWN_REQUEST_ATTACHMENT = 'COMMIT_DRAWDOWN_REQUEST_ATTACHMENT', +} +``` + +This enum value exposes a billing/commerce concept ("commit drawdown") that is not documented anywhere else in the marketplaces public surface. There is no `CommitDrawdownRequest` type, no related method, no field referencing "drawdown" elsewhere in the file. The JSDoc says these files have 14-day expiration and special storage paths — implementation details surfacing as the enum's namesake. A consumer scanning `MarketplaceFileType` cannot tell whether this is a value they should ever use. +- **Category:** 18 (long enum values), 1 (vague — "commit drawdown" undefined in the SDK), 11 (effectively-internal value). +- **Suggested name:** Document or hide. If kept, the long name is itself fine — the issue is the value's presence in the public API without context. +- **Rationale:** Public enums should be self-explanatory; internal-workflow values should either be documented inline with the workflow's purpose or kept off the public surface. + +### 9. `PersonalizationRequest.isFromLighthouse` — internal codename leak + +**Location:** `src/v1/model.ts:563` + +```ts +export interface PersonalizationRequest { + ... + isFromLighthouse?: boolean | undefined; + ... +} +``` + +`Lighthouse` is an internal Databricks service codename, not a product term — there is no `Lighthouse` mention anywhere else in the package, no JSDoc clarifying what the flag means, no enum, and no type-safety on what it controls. The flag's purpose is opaque to anyone outside the marketplace team. +- **Category:** 5 (cryptic abbreviation / codename), 1 (vague), 6 (misleading: implies a known concept). +- **Suggested name:** Either document inline (the doc-comment should explain Lighthouse) or rename to a feature-describing name. If Lighthouse is a request-origin tag, `originatingService` (with an enum) would be clearer. +- **Rationale:** Public APIs should not leak internal-system codenames. + +### 10. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types + +**Location:** `src/v1/model.ts:515, 462` + +```ts +export interface Listing { + id?: string | undefined; + summary?: ListingSummary | undefined; + detail?: ListingDetail | undefined; +} + +export interface ListingSummary { /* 20 fields */ } +export interface ListingDetail { /* 16 fields */ } +``` + +The split into `Summary` and `Detail` looks like a "list view vs. detail view" distinction (where `Summary` is what gets returned in list endpoints and `Detail` is the full payload). But both are bundled into a single `Listing` and both come back from `getListing` and `listListings`. The convention is meaningful in REST APIs that ship two read-shapes (e.g. GitHub's `Repository` vs `MinimalRepository`), but here both types are always present on the same `Listing`. The naming implies a contract the API doesn't honor. +- **Category:** 6 (misleading — names imply contract that isn't enforced), 12 (duplicate concept of "the listing"), 11 (could be merged). +- **Suggested name:** `ListingMetadata` (for what is currently `ListingSummary`) and `ListingContent` (for `ListingDetail`); or merge into a single `Listing` type. +- **Rationale:** The "Summary / Detail" lexicon promises a slim/fat split that the API doesn't actually provide. + +### 11. `ListingSummary` — 20-field "summary" + +**Location:** `src/v1/model.ts:515-536` + +```ts +export interface ListingSummary { + name?: string | undefined; + subtitle?: string | undefined; + status?: ListingStatus | undefined; + share?: ShareInfo | undefined; + providerRegion?: RegionInfo | undefined; + setting?: ListingSetting | undefined; + createdAt?: number | undefined; + createdBy?: string | undefined; + updatedAt?: number | undefined; + updatedBy?: string | undefined; + publishedAt?: number | undefined; + publishedBy?: string | undefined; + categories?: Category[] | undefined; + listingType?: ListingType | undefined; + createdById?: number | undefined; + updatedById?: number | undefined; + providerId?: string | undefined; + exchangeIds?: string[] | undefined; + gitRepo?: RepoInfo | undefined; +} +``` + +A 20-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. +- **Category:** 6 (misleading). +- **Suggested name:** `ListingMetadata` or `ListingHeader`. +- **Rationale:** See #10. + +### 12. `ProviderInfo.termOfServiceLink` — singular "term" + +**Location:** `src/v1/model.ts:581` + +```ts +export interface ProviderInfo { + ... + termOfServiceLink?: string | undefined; + ... +} +``` + +The legal document is **Terms of Service** (plural). Field name says `termOfService` (singular). The neighboring `privacyPolicyLink` is correctly singular (a privacy policy is singular), so the field reads as if "term" were intentional — but the linked document is universally plural. The same field appears with the same typo as `term_of_service_link` on the wire (see `marshalProviderInfoSchema:1671`), so this is a server-side typo that the SDK faithfully preserves. + +Note: `ListingDetail.termsOfService` (line 464) correctly uses the plural form — so the package has both `termOfServiceLink` and `termsOfService` for analogous concepts. +- **Category:** 6 (misleading: wrong word form), 17 (inconsistent: same package uses both `termOfService` and `termsOfService`). +- **Suggested name:** `termsOfServiceLink`. +- **Rationale:** Within-package consistency and English correctness. + +### 13. `FileParent` — abstract container with weak typing + +**Location:** `src/v1/model.ts:303-307` + +```ts +export interface FileParent { + /** TODO make the following fields required */ + parentId?: string | undefined; + fileParentType?: FileParentType | undefined; +} +``` + +The type ships with a `TODO` in the JSDoc — the API contract is incomplete by the generator's own admission. `parentId` is a free-form string with no statement of which `FileParentType` corresponds to which kind of id. `fileParentType` is a 3-value enum (`PROVIDER`, `LISTING`, `LISTING_RESOURCE`), but `LISTING_RESOURCE` has no separate `ListingResource` type in the package — it's an opaque concept. The pair is effectively a discriminated union that isn't discriminated. +- **Category:** 19 (underspecified ID), 6 (misleading: looks like a polymorphic parent but isn't typed), Observation (incomplete API). +- **Suggested name:** Either model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`) or rename `parentId` → `providerId | listingId | listingResourceId` per case. +- **Rationale:** The `TODO` says the team knows; the type is shipped publicly anyway. + +### 14. `FileParent.fileParentType` — type-suffix tautology + +**Location:** `src/v1/model.ts:306` + +```ts +export interface FileParent { + ... + fileParentType?: FileParentType | undefined; +} +``` + +Field name = type name minus the `FileParent` prefix repeated. Inside `FileParent`, what else could `.fileParentType` be? `parentType` or `type` carries the same information. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `type` (matching `ShareInfo.type`) or `parentType`. +- **Rationale:** Redundant context. + +### 15. `FileInfo.marketplaceFileType` — package-name prefix in a field + +**Location:** `src/v1/model.ts:290` + +```ts +export interface FileInfo { + id?: string | undefined; + marketplaceFileType?: MarketplaceFileType | undefined; + ... +} +``` + +The field qualifies "fileType" with "marketplace" — but the type is *already* inside the marketplaces package. Every `FileType` here is a marketplace file type. The same prefix appears on `MarketplaceFileType` (the enum itself, line 114). Together they read as `marketplaceFileType: MarketplaceFileType` — package name stuttered twice. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology). +- **Suggested name:** Rename enum → `FileType`; rename field → `type`. +- **Rationale:** Package-name qualifiers are noise on internal fields. + +### 16. `marketplaceFileType: MarketplaceFileType` vs `fileParentType: FileParentType` — different qualifier conventions + +**Location:** `src/v1/model.ts:290, 306` + +The package qualifies one enum with "marketplace" (`MarketplaceFileType`) and another without (`FileParentType`). Both are file-scoped enums. The asymmetry suggests `MarketplaceFileType` was renamed at some point to avoid a collision (perhaps with `files` package's `FileType`?) but `FileParentType` was not. +- **Category:** 17 (inconsistent naming pattern). +- **Suggested name:** Rename one to match the other. +- **Rationale:** See #15. + +--- + +## Medium severity + +### 17. `Client` — generic top-level class name + +**Location:** `src/v1/client.ts:152` + +```ts +export class Client { ... } +``` + +Top-level export named just `Client`. Every generated package exports a `Client` class with the same name; importing two requires aliasing (`import { Client as MarketplacesClient } from '@databricks/sdk-marketplaces/v1'`). +- **Category:** 1 (vague), 12 (duplicate across packages). +- **Suggested name:** `MarketplacesClient`. +- **Rationale:** Service-prefixed client class names are standard across `@aws-sdk/*`, `@google-cloud/*`, `@azure/*`. + +### 18. `Exchange.linkedListings` — verb tense and ambiguity + +**Location:** `src/v1/model.ts:263` + +```ts +export interface Exchange { + ... + linkedListings?: ExchangeListing[] | undefined; +} +``` + +"Linked" is the past participle implying the action of linking was performed. But the field returns the *current* set of `ExchangeListing` join-rows, not a history of linking events. `listings` or `members` would be clearer; `linkedListings` is also a typo trap (one could expect `linkedListingIds` if the type was `string[]`, but it's actually `ExchangeListing[]`). +- **Category:** 13 (verb-tense inconsistency), 1 (vague). +- **Suggested name:** `listings`, `memberships`, or `listingLinks`. +- **Rationale:** Past-participle field names suggest a log/audit; this is a list of current memberships. + +### 19. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix + +**Location:** `src/v1/model.ts:269, 275` + +```ts +export interface ExchangeFilter { + id?: string | undefined; + exchangeId?: string | undefined; + filterValue?: string | undefined; + name?: string | undefined; + ... + filterType?: ExchangeFilterType | undefined; +} +``` + +Inside an `ExchangeFilter`, what else could `filterValue` be the value of? Or `filterType` the type of? `value` and `type` carry the same information. The prefix `filter` adds nothing. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `value`, `type`. +- **Rationale:** Field names that re-state the parent type are noise (see also `EffectivePrivilege.privilege` from grants audit #15). + +### 20. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum + +**Location:** `src/v1/model.ts:69-71` + +```ts +export enum ExchangeFilterType { + GLOBAL_METASTORE_ID = 'GLOBAL_METASTORE_ID', +} +``` + +An enum with a single member. Typically a sign that the API anticipates future filter types but only has one today — but in TypeScript a single-value enum is just `'GLOBAL_METASTORE_ID'`. The naming is fine; the type's existence is the smell. +- **Category:** 11 (trivially small enum), 1 (over-engineered for one value). +- **Suggested name:** Could be a string literal type until a second value lands. +- **Rationale:** TS allows narrowing without enums (`type ExchangeFilterType = 'GLOBAL_METASTORE_ID'`). + +### 21. `MarketplaceFileType.APP` — three-letter generic value + +**Location:** `src/v1/model.ts:117` + +```ts +export enum MarketplaceFileType { + PROVIDER_ICON = 'PROVIDER_ICON', + EMBEDDED_NOTEBOOK = 'EMBEDDED_NOTEBOOK', + APP = 'APP', + EMBEDDED_MARKDOWN = 'EMBEDDED_MARKDOWN', + COMMIT_DRAWDOWN_REQUEST_ATTACHMENT = 'COMMIT_DRAWDOWN_REQUEST_ATTACHMENT', +} +``` + +`APP` is the only member without a qualifier. Compare with `EMBEDDED_NOTEBOOK` and `EMBEDDED_MARKDOWN` — both prefixed with "embedded" to indicate they're attached to a listing. Is `APP` similarly embedded? Is it a Databricks App package file? A general application archive? Without a qualifier or doc-comment the value is ambiguous. +- **Category:** 1 (vague), 17 (inconsistent qualifier convention with peers). +- **Suggested name:** `EMBEDDED_APP` or `APP_PACKAGE`. +- **Rationale:** Match the qualifier convention of `EMBEDDED_*` peers. + +### 22. `AssetType.ASSET_TYPE_*` — redundant enum prefixes + +**Location:** `src/v1/model.ts:5-19` + +```ts +export enum AssetType { + ASSET_TYPE_UNSPECIFIED = 'ASSET_TYPE_UNSPECIFIED', + ASSET_TYPE_GIT_REPO = 'ASSET_TYPE_GIT_REPO', + ASSET_TYPE_DATA_TABLE = 'ASSET_TYPE_DATA_TABLE', + ASSET_TYPE_MODEL = 'ASSET_TYPE_MODEL', + ASSET_TYPE_NOTEBOOK = 'ASSET_TYPE_NOTEBOOK', + ASSET_TYPE_MEDIA = 'ASSET_TYPE_MEDIA', + ASSET_TYPE_PARTNER_INTEGRATION = 'ASSET_TYPE_PARTNER_INTEGRATION', + ASSET_TYPE_APP = 'ASSET_TYPE_APP', + ASSET_TYPE_MCP = 'ASSET_TYPE_MCP', +} +``` + +Every value is prefixed with `ASSET_TYPE_` — proto convention for namespace disambiguation. In TS, the enum's name already provides the namespace: `AssetType.GIT_REPO` is unambiguous; `AssetType.ASSET_TYPE_GIT_REPO` is redundant. +- **Category:** 2 (redundant enum prefixes). +- **Suggested name:** `AssetType.GIT_REPO`, `AssetType.DATA_TABLE`, etc. +- **Rationale:** TS enum members are accessed via the enum type, so the prefix is always redundant. + +### 23. `AssetType.ASSET_TYPE_UNSPECIFIED` — proto sentinel leak + +**Location:** `src/v1/model.ts:6` + +```ts +ASSET_TYPE_UNSPECIFIED = 'ASSET_TYPE_UNSPECIFIED', +``` + +Proto enums require a zero-value `UNSPECIFIED` member. This is an implementation detail of protobuf, not a meaningful TS API value — `undefined` already serves the same role in optional TS fields. The other "unspecified" pattern in this file: `ListingTagType.LISTING_TAG_TYPE_UNSPECIFIED` (line 104). +- **Category:** 18 (long enum values), 11 (proto sentinel exposed). +- **Suggested name:** Drop. Use `undefined` for the unset case. +- **Rationale:** Cross-language TS APIs typically don't surface the `UNSPECIFIED` zero-value. + +### 24. `ListingTagType.LISTING_TAG_TYPE_*` — redundant enum prefixes + +**Location:** `src/v1/model.ts:103-107` + +```ts +export enum ListingTagType { + LISTING_TAG_TYPE_UNSPECIFIED = 'LISTING_TAG_TYPE_UNSPECIFIED', + LISTING_TAG_TYPE_LANGUAGE = 'LISTING_TAG_TYPE_LANGUAGE', + LISTING_TAG_TYPE_TASK = 'LISTING_TAG_TYPE_TASK', +} +``` + +Same problem as #22. +- **Category:** 2, 18. +- **Suggested name:** `LANGUAGE`, `TASK`. +- **Rationale:** See #22. + +### 25. `DeltaSharingRecipientType.DELTA_SHARING_RECIPIENT_TYPE_*` — redundant enum prefixes + +**Location:** `src/v1/model.ts:64-67` + +```ts +export enum DeltaSharingRecipientType { + DELTA_SHARING_RECIPIENT_TYPE_DATABRICKS = 'DELTA_SHARING_RECIPIENT_TYPE_DATABRICKS', + DELTA_SHARING_RECIPIENT_TYPE_OPEN = 'DELTA_SHARING_RECIPIENT_TYPE_OPEN', +} +``` + +Same problem as #22 and #24, plus the prefix here is 28 characters. +- **Category:** 2, 18. +- **Suggested name:** `DATABRICKS`, `OPEN`. +- **Rationale:** See #22. + +### 26. `FileStatus.FILE_STATUS_*` — redundant enum prefixes + +**Location:** `src/v1/model.ts:79-88` + +```ts +export enum FileStatus { + FILE_STATUS_PUBLISHED = 'FILE_STATUS_PUBLISHED', + FILE_STATUS_STAGING = 'FILE_STATUS_STAGING', + FILE_STATUS_SANITIZING = 'FILE_STATUS_SANITIZING', + FILE_STATUS_SANITIZATION_FAILED = 'FILE_STATUS_SANITIZATION_FAILED', +} +``` + +Same problem as #22. +- **Category:** 2. +- **Suggested name:** `PUBLISHED`, `STAGING`, `SANITIZING`, `SANITIZATION_FAILED`. +- **Rationale:** See #22. + +### 27. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment + +**Location:** `src/v1/model.ts:128-134` + +```ts +export enum PersonalizationRequestStatus { + NEW = 'NEW', + /** Pending already defined for ListingStatus */ + REQUEST_PENDING = 'REQUEST_PENDING', + FULFILLED = 'FULFILLED', + DENIED = 'DENIED', +} +``` + +The JSDoc explicitly says the value is named `REQUEST_PENDING` because `PENDING` is already defined for `ListingStatus`. But these are separate TS enum types; there is no collision (TypeScript enums are scoped). The renaming reveals a server-side or proto-side collision concern, leaked into the SDK as an awkward enum value. A user reading `PersonalizationRequestStatus.REQUEST_PENDING` and `ListingStatus.PENDING` will reasonably expect them to mean different things — they don't. +- **Category:** 18 (long enum values), 6 (misleading: name implies a different concept than `Pending`), 17 (inconsistent value patterns within file). +- **Suggested name:** `PENDING` (cross-enum collisions don't exist in TS). +- **Rationale:** Proto-side collision avoidance has no purpose in the TS surface. + +### 28. `Cost` — single-word, ambiguous enum + +**Location:** `src/v1/model.ts:47-50` + +```ts +export enum Cost { + FREE = 'FREE', + PAID = 'PAID', +} +``` + +`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 473) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". +- **Category:** 1 (vague), 6 (misleading: implies price, means tier). +- **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. +- **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. + +### 29. `DataRefresh` — enum named after the noun, not the property + +**Location:** `src/v1/model.ts:52-62` + +```ts +export enum DataRefresh { + NONE = 'NONE', + SECOND = 'SECOND', + MINUTE = 'MINUTE', + HOURLY = 'HOURLY', + DAILY = 'DAILY', + WEEKLY = 'WEEKLY', + MONTHLY = 'MONTHLY', + QUARTERLY = 'QUARTERLY', + YEARLY = 'YEARLY', +} +``` + +The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 216) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. Also note: values mix nouns (`SECOND`, `MINUTE`) with adjectives (`HOURLY`, `DAILY`, `WEEKLY`) within the same enum — `SECONDLY` and `MINUTELY` are not used. +- **Category:** 1 (vague: name is the noun, not the unit), 17 (inconsistent value form: nouns vs adverbs). +- **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. +- **Rationale:** Self-documenting enum name; consistent value form. + +### 30. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special + +**Location:** `src/v1/model.ts:53-55` + +```ts +NONE = 'NONE', +SECOND = 'SECOND', +MINUTE = 'MINUTE', +HOURLY = 'HOURLY', +``` + +`NONE` reads as "no refresh"; `SECOND` reads as "every second"; `HOURLY` reads as "every hour". The first two follow noun-naming; the third follows adverb-naming. Mixing the two within the same enum produces inconsistency. +- **Category:** 17 (inconsistent value form). +- **Suggested name:** Pick one convention. If "every X" adverbs are used, change `SECOND` → `SECONDLY`, `MINUTE` → `MINUTELY`, `NONE` → unchanged. +- **Rationale:** See #29. + +### 31. `Category` — generic enum name with 23 values + +**Location:** `src/v1/model.ts:21-45` + +```ts +export enum Category { + ADVERTISING_AND_MARKETING = 'ADVERTISING_AND_MARKETING', + ... + OPEN_SOURCE = 'OPEN_SOURCE', +} +``` + +`Category` is generic without a domain qualifier (compare with `AssetType`, `ListingType`, `MarketplaceFileType`). The other enums use a domain prefix; `Category` does not. Also, it's exported at the package root and a user importing `Category` doesn't know it's marketplace-scoped. +- **Category:** 1 (vague), 17 (inconsistent qualifier convention). +- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 528). +- **Rationale:** Cross-package collision avoidance and self-documentation. + +### 32. `ListingDetail.size` — ambiguous unit + +**Location:** `src/v1/model.ts:489-490` + +```ts +/** size of the dataset in GB */ +size?: number | undefined; +``` + +The JSDoc says "in GB", but the field name is just `size`. The wire field is `size`. A consumer not reading the doc-comment will assume bytes — wrong by a factor of 10^9. The pattern violates the unit-suffix rule (compare `secondsToRetrigger`, `pageSize`, etc. — but those also have problems). +- **Category:** 15 (generic field name losing meaning), 19 (underspecified). +- **Suggested name:** `sizeInGigabytes` or `sizeGb`. +- **Rationale:** Numeric fields without unit suffix are a bug magnet. + +### 33. `ListingDetail.cost` typed as `Cost` (enum), but doc says price + +**Location:** `src/v1/model.ts:472-473, 477-478` + +```ts +/** Whether the dataset is free or paid */ +cost?: Cost | undefined; +/** + * What the pricing model is (e.g. paid, subscription, paid upfront); should only be present if cost is paid + * TODO: Not used yet, should deprecate if we will never use it + */ +pricingModel?: string | undefined; +``` + +Two related fields: `cost: Cost (= 'FREE' | 'PAID')` and `pricingModel: string` (free-form). The first is the boolean-like cost tier, the second is the model. The second carries an inline `TODO` admitting it might never be used. The pair encodes "is it free?" and "if not, how is it priced?" but the relationship isn't enforced and the JSDoc says it "should only be present if cost is paid" — relationship in prose, not in types. +- **Category:** 1 (vague), 16 (field contradicts type domain — `cost` is a category, `pricingModel` is a string). +- **Suggested name:** Combine into one discriminated union: `pricing?: { $case: 'free' } | { $case: 'paid', model: string }`. +- **Rationale:** Type-system can encode the relationship the prose tries to. + +### 34. `ListingDetail.geographicalCoverage` — long camelCase + +**Location:** `src/v1/model.ts:470-471` + +```ts +/** Which geo region the listing data is collected from */ +geographicalCoverage?: string | undefined; +``` + +`geographicalCoverage` is 20 characters and uses the adjective form; `geographic` is more common in technical contexts (compare AWS `geographic_location` or Stripe `country_coverage`). The JSDoc says "geo region" which is a separate term entirely. The field is also `string` — there's no enum of valid regions. +- **Category:** 7 (overly verbose), 17 (inconsistent vocabulary with `providerRegion: RegionInfo`). +- **Suggested name:** `geoRegion`, `regions`, or `coverage`. +- **Rationale:** Shorter, matches sibling naming. + +### 35. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number + +**Location:** `src/v1/model.ts:483-486` + +```ts +/** The starting date timestamp for when the data spans */ +collectionDateStart?: number | undefined; +/** The ending date timestamp for when the data spans */ +collectionDateEnd?: number | undefined; +``` + +Field names include "Date" but the type is `number` (Unix timestamp). A consumer might assume an ISO string. Compare with other timestamp fields in the same file (`createdAt`, `updatedAt`, `publishedAt`) which use the `*At` suffix and are also `number` — but at least the `At` suffix isn't misleading about JS Date. +- **Category:** 16 (field name contradicts type), 17 (inconsistent suffix convention within file). +- **Suggested name:** `collectionStartAt` / `collectionEndAt`, or `collectionPeriodStart` / `collectionPeriodEnd`. +- **Rationale:** "Date" is ambiguous about underlying type; `At` is the existing in-file convention for Unix timestamps. + +### 36. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming + +**Location:** `src/v1/model.ts:479-482` + +```ts +/** How often data is updated */ +updateFrequency?: DataRefreshInfo | undefined; +/** Smallest unit of time in the dataset */ +collectionGranularity?: DataRefreshInfo | undefined; +``` + +Both are `DataRefreshInfo` (an interval), but one is named "frequency" and the other "granularity". A reader unfamiliar with the domain has to read both doc-comments to disambiguate. Also note that `DataRefreshInfo` is named after only one of its uses (`update_frequency`, which the wire calls "data_refresh") — the type is reused for collection granularity, which has nothing to do with refresh. +- **Category:** 6 (misleading: type name `DataRefresh` doesn't fit "collection granularity"), 17 (inconsistent vocabulary for the same concept). +- **Suggested name:** Rename type → `TimeInterval`; keep the field-level distinction. +- **Rationale:** Reuse a generic type name for a reusable type. + +### 37. `ListingDetail.dataSource` — single-word vague field + +**Location:** `src/v1/model.ts:487-488` + +```ts +/** Where/how the data is sourced */ +dataSource?: string | undefined; +``` + +`dataSource` reads as "the database / driver / connection" (compare `spring.datasource`, `Tableau data source`, JDBC `DataSource`). The JSDoc says it's a free-form "where/how the data is sourced" description — i.e. a human-readable provenance note. The name suggests a typed concept; the field is a string. +- **Category:** 6 (misleading: implies a structured concept), 1 (vague). +- **Suggested name:** `dataSourceDescription`, `dataProvenance`, or `dataOriginNote`. +- **Rationale:** Disambiguate from the more common DB-connection meaning of "data source". + +### 38. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags + +**Location:** `src/v1/model.ts:493-508` + +```ts +export interface ListingDetail { + ... + /** + * Listing tags - Simple key value pair to annotate listings. + * When should I use tags vs dedicated fields? + * ... + */ + tags?: ListingTag[] | undefined; +} + +export interface ListingTag { + /** Tag name (enum) */ + tagName?: ListingTagType | undefined; + /** String representation of the tag value. Values should be string literals (no complex types) */ + tagValues?: string[] | undefined; +} + +export enum ListingTagType { + LISTING_TAG_TYPE_UNSPECIFIED = 'LISTING_TAG_TYPE_UNSPECIFIED', + LISTING_TAG_TYPE_LANGUAGE = 'LISTING_TAG_TYPE_LANGUAGE', + LISTING_TAG_TYPE_TASK = 'LISTING_TAG_TYPE_TASK', +} +``` + +The enum constrains tag *names* to 3 values (one of which is the `UNSPECIFIED` sentinel). Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. +- **Category:** 6 (misleading: name implies free-form labels, structure is constrained), 7 (`tagName` / `tagValues` add `tag` prefix repeated from type name). +- **Suggested name:** `ListingTag.name` / `ListingTag.values`; rename type to clarify (e.g. `ListingAttribute`). +- **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. + +### 39. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology + +**Location:** `src/v1/model.ts:538-543` + +```ts +export interface ListingTag { + tagName?: ListingTagType | undefined; + tagValues?: string[] | undefined; +} +``` + +Inside `ListingTag`, what else could `tagName` and `tagValues` be? `name` and `values` carry the same information. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `name`, `values`. +- **Rationale:** See #19. + +### 40. `ContactInfo` — generic suffix on a single-purpose type + +**Location:** `src/v1/model.ts:151-156` + +```ts +/** contact info for the consumer requesting data or performing a listing installation */ +export interface ContactInfo { + firstName?: string | undefined; + lastName?: string | undefined; + email?: string | undefined; + company?: string | undefined; +} +``` + +`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 548). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. +- **Category:** 8 (redundant `Info` suffix), 1 (vague). +- **Suggested name:** `Contact` or `ConsumerContact`. +- **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. + +### 41. `RegionInfo` — `Info` suffix on a single-purpose type + +**Location:** `src/v1/model.ts:587-590` + +```ts +export interface RegionInfo { + cloud?: string | undefined; + region?: string | undefined; +} +``` + +Same problem as #40. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. +- **Category:** 8 (redundant `Info` suffix), 19 (underspecified — no enum constraints). +- **Suggested name:** `Region` (the cloud is implicitly part of the region in many SDKs) or `CloudRegion`. +- **Rationale:** Avoid `*Info` suffix; consider richer typing. + +### 42. `ShareInfo` — `Info` suffix on a sharing concept + +**Location:** `src/v1/model.ts:604-607` + +```ts +export interface ShareInfo { + name?: string | undefined; + type?: ListingShareType | undefined; +} +``` + +Same problem as #40 and #41. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". +- **Category:** 8 (redundant `Info` suffix). +- **Suggested name:** `Share`, `ListingShare`. +- **Rationale:** See #40. + +### 43. `ProviderInfo` — `Info` suffix on the canonical provider type + +**Location:** `src/v1/model.ts:568-585` + +```ts +export interface ProviderInfo { + id?: string | undefined; + name?: string | undefined; + description?: string | undefined; + iconFilePath?: string | undefined; + ... +} +``` + +Same problem as #40. The package also has `CreateProvider`, `GetProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. +- **Category:** 8 (redundant `Info` suffix), 17 (inconsistent: the rest of the package uses `Provider` alone). +- **Suggested name:** `Provider`. +- **Rationale:** Consistency with method/request type names. + +### 44. `DataRefreshInfo` — `Info` suffix on an interval type + +**Location:** `src/v1/model.ts:214-217` + +```ts +export interface DataRefreshInfo { + interval?: number | undefined; + unit?: DataRefresh | undefined; +} +``` + +Same problem as #40. Also note: the type is reused for `collectionGranularity` (#36), so the name `DataRefreshInfo` is wrong for half of its uses. +- **Category:** 8 (redundant `Info` suffix), 6 (misleading: name doesn't fit `collectionGranularity` use). +- **Suggested name:** `TimeInterval` (matches #36). +- **Rationale:** See #36. + +### 45. `FileInfo` — `Info` suffix on the canonical file type + +**Location:** `src/v1/model.ts:288-301` + +```ts +export interface FileInfo { + id?: string | undefined; + marketplaceFileType?: MarketplaceFileType | undefined; + ... +} +``` + +Same problem as #40. The package also has `CreateFile`, `GetFile`, `DeleteFile`, `ListFiles` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. +- **Category:** 8 (redundant `Info` suffix), 17 (inconsistent with siblings). +- **Suggested name:** `File`. +- **Rationale:** See #43. + +### 46. `Listing.summary` / `Listing.detail` — opaque fields on the central type + +**Location:** `src/v1/model.ts:456-460` + +```ts +export interface Listing { + id?: string | undefined; + summary?: ListingSummary | undefined; + detail?: ListingDetail | undefined; +} +``` + +`Listing` is essentially `(id, summary, detail)` — a 3-field passthrough. The two interesting fields are named `summary` and `detail`, opaque on their own. A consumer with `listing.summary.name` and `listing.detail.description` has to navigate two sub-objects to reach the actual content. +- **Category:** 1 (vague), 11 (could be merged). +- **Suggested name:** Flatten or rename `summary` → `metadata`, `detail` → `content`. +- **Rationale:** See #10. + +### 47. `ListingSummary.setting` — singular field name + +**Location:** `src/v1/model.ts:521` + +```ts +export interface ListingSummary { + ... + setting?: ListingSetting | undefined; +} +``` + +`setting` (singular) on a type that holds one knob is fine until the team adds a second — at which point `setting.visibility` and `setting.foo` become awkward. Convention is `settings` for a bag of knobs. +- **Category:** 9 (singular/plural). +- **Suggested name:** `settings: ListingSettings`. +- **Rationale:** Plural matches the conventional naming for a settings bag. + +### 48. `ListingSummary.providerRegion` — region of what? + +**Location:** `src/v1/model.ts:520` + +```ts +providerRegion?: RegionInfo | undefined; +``` + +`PersonalizationRequest.consumerRegion` (line 547) uses the same `RegionInfo` type with the `consumer` qualifier. So the package has `providerRegion` and `consumerRegion` — two different qualifiers for the same `RegionInfo` type. Fine; flagged because the *type* name (`RegionInfo`) is unqualified, while every *use* requires a qualifier. +- **Category:** 1 (vague type, qualified field), 17 (qualifier convention not encoded in the type). +- **Suggested name:** No rename; this is the price of reusing `RegionInfo`. +- **Rationale:** Observation. + +--- + +## Low severity + +### 49. `unmarshal*Schema` / `marshal*Schema` exports — `Schema` suffix tautology + +**Location:** `src/v1/model.ts:679, 690, 704, 713, 723, 735, 745, 755, 764, 774, 777, 781, 785, 789, 792, 818, 842, 862, 888, 898, 908, 917, 927, 937, 949, 963, 972, 983, 996, 1008, 1019, 1033, 1047, 1058, 1070, 1118, 1126, 1170, 1180, 1219, 1253, 1263, 1266, 1274, 1284, 1293, 1302, 1313, 1323, 1333, 1346, 1356, 1364, 1372, 1386, 1394, 1402, 1405, 1415, 1441, 1465, 1485, 1511, 1521, 1533, 1581, 1589, 1633, 1643, 1677, 1687, 1695, 1705, 1715, 1725, 1735, 1751, 1761` + +```ts +export const unmarshalContactInfoSchema: z.ZodType = ... +export const unmarshalCreateExchangeFilterResponseSchema: ... +export const marshalProviderInfoSchema: z.ZodType = ... +``` + +~78 exports. Every name combines `marshal|unmarshal` + the type name + `Schema`. The `Schema` suffix is redundant — the `z.ZodType` type annotation already says it's a Zod schema. +- **Category:** 8 (redundant `Schema` suffix), 7 (overly verbose). +- **Suggested name:** Drop `Schema` suffix: `unmarshalContactInfo`, `marshalProviderInfo`, etc. +- **Rationale:** Cross-package consistency / verbosity. + +### 50. `unmarshal*_ResponseSchema` — proto-underscore + Schema-suffix combo + +**Location:** `src/v1/model.ts:723, 735, 745, 755, 781, 785, 789, 908, 917, 927, 937, 949, 963, 1008, 1033, 1047, 1302, 1313, 1323, 1333` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export const unmarshalCreateFile_ResponseSchema: z.ZodType = ... +``` + +Same as #1 but for the schema exports — 14 schemas embed the proto underscore plus the redundant `Schema` suffix. Each requires its own `// eslint-disable-next-line` comment. +- **Category:** 4 (underscore), 8 (Schema suffix), 14 (proto/Go-style names). +- **Suggested name:** `unmarshalCreateFileResponse`, etc. +- **Rationale:** Cascades from #1 and #49. + +### 51. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization + +**Location:** `src/v1/model.ts:457, 467, 533` + +Mixed singular/plural id fields: +- `Listing.id` — single id of the listing. +- `ListingDetail.fileIds: string[]` — many file ids. +- `ListingSummary.exchangeIds: string[]` — many exchange ids. +- `ListingSummary.providerId: string` — single provider id. +- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #52). + +Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #52). +- **Suggested name:** Pick one — `*Id`/`*Ids` is standard. +- **Rationale:** Observation; flagged for completeness. + +### 52. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number + +**Location:** `src/v1/model.ts:530-531` + +```ts +createdById?: number | undefined; +updatedById?: number | undefined; +``` + +User ids are typed as `number`. JS `number` only safely represents integers up to 2^53; Databricks user ids are 64-bit (int64). Same issue flagged in `grants` audit #13. +- **Category:** 19 (underspecified ID), 16 (field contradicts JS type domain). +- **Suggested name:** `createdById: string` or `bigint`. +- **Rationale:** Lossy representation; consistency with other id fields (all `string`). + +### 53. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` + +**Location:** `src/v1/model.ts:136-139` + +```ts +export enum Visibility { + PUBLIC = 'PUBLIC', + PRIVATE = 'PRIVATE', +} +``` + +Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal type. The enum is fine; flagged for completeness. +- **Category:** 11 (trivially small enum). +- **Suggested name:** Could be `'public' | 'private'` literal union. +- **Rationale:** Observation. + +### 54. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun + +**Location:** `src/v1/model.ts:90-93` + +```ts +export enum ListingShareType { + SAMPLE = 'SAMPLE', + FULL = 'FULL', +} +``` + +`SAMPLE` is a noun (a small portion of something); `FULL` is an adjective (complete). The convention is mixed. +- **Category:** 17 (inconsistent value form). +- **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). +- **Rationale:** Internal consistency. + +### 55. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values + +**Location:** `src/v1/model.ts:109-112` + +```ts +export enum ListingType { + STANDARD = 'STANDARD', + PERSONALIZED = 'PERSONALIZED', +} +``` + +Two adjective values. Fine. Flagged because the package also has `PersonalizationRequest` (line 545) — the noun for `PERSONALIZED` mode. Cross-reference unclear. +- **Category:** Observation. +- **Suggested name:** No rename. +- **Rationale:** Internal consistency check. + +### 56. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located + +**Location:** `src/v1/model.ts:572, 580` + +```ts +iconFilePath?: string | undefined; +... +iconFileId?: string | undefined; +``` + +Same icon represented two ways — `iconFilePath` (a URL or storage path) and `iconFileId` (a Marketplace file id). The pairing repeats with `darkModeIconFileId` and `darkModeIconFilePath` (lines 583-584). No doc explains when to use which or whether one is derived from the other. +- **Category:** 12 (duplicate concept), 17 (inconsistent — the relationship is implicit). +- **Suggested name:** No rename; flag for doc clarification. +- **Rationale:** Observation. + +### 57. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode + +**Location:** `src/v1/model.ts:583-584` + +```ts +darkModeIconFileId?: string | undefined; +darkModeIconFilePath?: string | undefined; +``` + +The `darkMode` prefix encodes a UI rendering mode in a server-side data type. This is wire-locked but flagged because it injects a presentation concern into a domain model. `iconDarkFileId` reads more like an asset variant. +- **Category:** 17 (presentation-domain leak). +- **Suggested name:** `iconDarkFileId` / `iconDarkFilePath` or just `darkIcon*`. +- **Rationale:** Observation. + +### 58. Method docstring inconsistency — `client.ts` + +**Location:** `src/v1/client.ts:178, 207, 232, 261, 287, 313, 339, 371, 396, 424, 449, 474, 499, 524, 549, 577, 602, 656, 713, 738, 795, 846, 903, 961, 1018, 1046, 1097, 1125, 1151, 1180, 1206, 1238, 1264` + +```ts +/** Associate an exchange with a listing */ +/** Create an exchange */ +/** Add an exchange filter. */ +/** Create a file. Currently, only provider icons and attached notebooks are supported. */ +/** Create a new listing */ +/** This removes a listing from marketplace. */ +/** Get provider analytics dashboard. */ +``` + +Inconsistent docstring style: +- Mix of trailing period ("Add an exchange filter.", "Create a file. ...") and no period ("Create an exchange", "Create a new listing"). +- Mix of imperative verbs ("Create", "Get", "Delete") and full sentences ("This removes a listing from marketplace."). +- "Get provider analytics dashboard" appears on `listProviderAnalyticsDashboard` (line 1018) — verb mismatch (it's a list method but the doc says "Get"). +- "This removes a listing from marketplace" appears on `deleteExchange` (line 371) — text describes the wrong concept (says "listing", method is `deleteExchange`). +- **Category:** 17 (inconsistent action verbs / doc style), 6 (misleading: docstring text contradicts method name). +- **Suggested name:** No rename; flag for doc consistency. +- **Rationale:** Observation. + +--- + +## Observations + +### 59. v1-only audit +The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. + +### 60. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:147` +Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. +- **Category:** 1 (vague), 15 (generic name). + +### 61. `flattenQueryParams` — `src/v1/utils.ts:123` +The helper is used by `client.ts:911-915` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. +- **Category:** Observation. + +### 62. `readAll` — `src/v1/utils.ts:40` +Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. +- **Category:** 1 (vague), 14 (Go-style name). + +### 63. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113, 119` +`parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within one file. The model file uses `marshal*` / `unmarshal*` consistently — `parseResponse` is the odd one out. +- **Category:** 17 (inconsistent action verbs). + +### 64. `HttpCallOptions` — `src/v1/utils.ts:15` +Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. +- **Category:** 1 (vague suffix), 17 (inconsistent). + +### 65. Exported but not in `index.ts` +`index.ts` exports types but not the `*_Response` schemas, marshal/unmarshal functions, or the `*_Response` types fully (note: `CreateFile_Response` is exported via `index.ts:32` — so the underscore wart reaches the public surface). The fact that consumers do see the underscore form via the index export means every change to remove the underscore would be a breaking change. +- **Category:** Observation. diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md new file mode 100644 index 00000000..3d22bba4 --- /dev/null +++ b/.agent/naming-audit/materializedfeatures.md @@ -0,0 +1,920 @@ +# Naming Audit: `materializedfeatures` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/materializedfeatures/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts` +**Cross-package references:** `features/v1` (`Feature`, `MaterializedFeature`, +`MaterializedFeature_PipelineScheduleState`, `LineageContext`, `CreateFeatureRequest`, +etc.), `featurestore/v1` (`OnlineStore`, `PublishSpec`, online-store concepts), +`entitytagassignments/v1`, `tagassignments/v1`, `tagpolicies/v1` (other "tag" +domains in the SDK). +**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). + +--- + +## Inventory + +### Enums + +(None — package has no enum types.) + +### Interfaces / Types + +1. `CreateFeatureTagRequest` (model.ts:8) — fields: `tableName`, `featureName`, + `featureTag`. +2. `DeleteFeatureTagRequest` (model.ts:15) — fields: `tableName`, `featureName`, + `key`. +3. `FeatureLineage` (model.ts:24) — fields: `models`, `featureSpecs`, + `onlineFeatures`. +4. `FeatureLineage_FeatureSpec` (model.ts:34) — fields: `name`. +5. `FeatureLineage_Model` (model.ts:40) — fields: `name`, `version`. +6. `FeatureLineage_OnlineFeature` (model.ts:48) — fields: `featureName`, + `tableName`. +7. `FeatureTag` (model.ts:56) — fields: `key`, `value`. +8. `GetFeatureLineageRequest` (model.ts:61) — fields: `featureName`, `tableName`. +9. `GetFeatureTagRequest` (model.ts:69) — fields: `tableName`, `featureName`, + `key`. +10. `ListFeatureTagsRequest` (model.ts:76) — fields: `tableName`, `featureName`, + `pageToken`, `pageSize`. +11. `ListFeatureTagsResponse` (model.ts:86) — fields: `featureTags`, + `nextPageToken`. +12. `UpdateFeatureTagRequest` (model.ts:93) — fields: `tableName`, `featureName`, + `featureTag`, `updateMask`. + +### Zod schemas + +- `unmarshalFeatureLineageSchema` (model.ts:101) +- `unmarshalFeatureLineage_FeatureSpecSchema` (model.ts:120) +- `unmarshalFeatureLineage_ModelSchema` (model.ts:130) +- `unmarshalFeatureLineage_OnlineFeatureSchema` (model.ts:142) +- `unmarshalFeatureTagSchema` (model.ts:153) +- `unmarshalListFeatureTagsResponseSchema` (model.ts:163) +- `marshalFeatureTagSchema` (model.ts:174) + +### Field-mask helpers + +- `featureTagFieldMaskSchema` (model.ts:184, module-internal) +- `featureTagFieldMask()` (model.ts:189, public) + +### Client class + +- `Client` (client.ts:44) + - Methods: `createFeatureTag`, `deleteFeatureTag`, `getFeatureLineage`, + `getFeatureTag`, `listFeatureTags`, `listFeatureTagsIter`, + `updateFeatureTag`. + - Private fields: `host`, `httpClient`, `logger`, `userAgent`. + - Module constant: `PACKAGE_SEGMENT`. + +### Utils (`src/v1/utils.ts`) + +- Type: `HttpCallOptions`. +- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`. + +### `index.ts` + +Re-exports `Client`, every public interface (12 of them, including the four +`FeatureLineage_*` proto-style nested names). + +--- + +## Findings + +### 1. Package name `materializedfeatures` does not match its contents — category 6 (Misleading names) and category 1 (Vague/generic) + +**Symbol:** Package name `@databricks/sdk-materializedfeatures` and directory +`packages/materializedfeatures/`. + +**Issue:** The package is called *materialized features* but exports **zero** +types or operations related to materialized features. Its entire surface is: + +- `FeatureTag` CRUD on regular feature-table columns. +- `FeatureLineage` read of regular feature-table columns. + +The actual `MaterializedFeature` type, `BatchCreateMaterializedFeaturesRequest`, +`CreateMaterializedFeatureRequest`, `DeleteMaterializedFeatureRequest`, +`GetMaterializedFeatureRequest`, `ListMaterializedFeaturesRequest`, +`UpdateMaterializedFeatureRequest`, and `MaterializedFeature_PipelineScheduleState` +all live in the **`features` package** (`packages/features/src/v1/model.ts` +lines 47, 146, 151, 197, 233, 390, 500, 509, 517, 800). The URL paths in this +package's `client.ts` confirm the mismatch: every endpoint targets +`/api/2.0/feature-store/feature-tables/{tableName}/features/{featureName}/...` +— i.e. the *feature table* domain, not "materialized features." + +The package was presumably named after the upstream Go SDK service / proto +package, which itself appears mis-scoped. A TS consumer reading the import path + +```ts +import {FeatureTag} from '@databricks/sdk-materializedfeatures/v1'; +``` + +would reasonably expect a type *about materialized features*, not a tag on a +feature-table column. Symmetrically, `features/v1` contains the actual +materialized-feature types. + +**Suggested:** rename the package — based on what it actually contains: + +- `@databricks/sdk-featuretags` (covers `FeatureTag` and `FeatureLineage`) +- Or merge into `@databricks/sdk-features` (since both deal with the same + underlying `/feature-tables/{tableName}/features/{featureName}/` URL space). + +This is a wire-and-generator-level concern. **Flag SDK-wide / upstream Go.** +**P1 cross-package alignment.** + +--- + +### 2. `FeatureLineage_FeatureSpec`, `FeatureLineage_Model`, `FeatureLineage_OnlineFeature` proto-style underscored type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) + +**Symbols:** `FeatureLineage_FeatureSpec` (model.ts:34), +`FeatureLineage_Model` (model.ts:40), `FeatureLineage_OnlineFeature` +(model.ts:48). + +**Issue:** TS identifiers must not contain underscores +(`.agent/rules/typescript.mdc`; Google TS Style Guide § 5.3, which mandates +`UpperCamelCase` for types). The `Parent_Child` form is a proto-buf code +generator artefact for nested messages. The file even suppresses the lint +rule explicitly for each one: + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface FeatureLineage_FeatureSpec { +``` + +That comment is the audit signal: the project's lint rule disagrees with the +chosen name. The proto namespace is not preserved in TS modules — every nested +type lives in the same module as `FeatureLineage`, so the qualification is +syntactic noise. + +**Suggested:** flat names that drop the underscore and prefix only where +disambiguation is needed: + +- `FeatureLineage_Model` → `FeatureLineageModel` (or `LineageModel`). +- `FeatureLineage_FeatureSpec` → `FeatureLineageFeatureSpec`. Note this becomes + doubled-noun (see finding 3) and should likely shorten to `LineageFeatureSpec` + or simply `FeatureSpec` (also flagged in finding 4 for cross-pkg collision). +- `FeatureLineage_OnlineFeature` → `FeatureLineageOnlineFeature` (or + `LineageOnlineFeature`, or `OnlineFeatureRef`). + +This is a generator-level fix coordinated SDK-wide. The unmarshal helpers +inherit the same underscore (`unmarshalFeatureLineage_ModelSchema`, etc.), +which compounds the issue. + +--- + +### 3. `FeatureLineage_FeatureSpec` doubled noun once flattened — category 8 (Redundant suffixes) + +**Symbol:** `FeatureLineage_FeatureSpec` (model.ts:34). + +**Issue:** After applying finding 2 to strip the underscore, the result is +`FeatureLineageFeatureSpec` — "Feature" appears twice. Within the +`FeatureLineage` parent type, the prefix `FeatureLineage` is already implied. + +**Suggested:** `LineageFeatureSpec` or shorter `FeatureSpec` (the latter has +the cross-package risk noted in finding 4). The parent prefix in TS nested +types serves to namespace; here it duplicates a concept that is already +unambiguous. + +--- + +### 4. `FeatureLineage_FeatureSpec` and `featurestore.PublishSpec` overlap "Spec" semantics — category 12 (Duplicate concepts) + +**Symbol:** `FeatureLineage_FeatureSpec` (model.ts:34); compare +`featurestore.PublishSpec` and `onlinetables.OnlineTableSpec`. + +**Issue:** Three different SDK packages export a `*Spec` type. In this package, +`FeatureLineage_FeatureSpec` is a *reference* (only field is `name`: "The full +name of the feature spec in Unity Catalog") — not a configuration object. In +`featurestore`, `PublishSpec` is a *configuration object* (multiple fields +describing how publishing should occur). The "Spec" suffix conflates two +different roles: + +- Reference / pointer: `FeatureLineage_FeatureSpec` (this package — single + `name` field). +- Configuration shape: `PublishSpec`, `OnlineTableSpec`. + +A TS reader importing both packages cannot tell from the type name which is +which. + +**Suggested:** rename `FeatureLineage_FeatureSpec` → `FeatureSpecRef` or +`FeatureSpecReference` to signal it is a reference. The `FeatureSpec` concept +itself (an actual feature-spec configuration) lives elsewhere in Databricks +APIs; this is just a pointer to one. **Flag for SDK-wide cleanup.** + +--- + +### 5. `FeatureLineage_Model` semantic conflict with `modelregistry`, `modelservingmanagement` — category 6 (Misleading names) and category 12 (Duplicate concepts) + +**Symbol:** `FeatureLineage_Model` (model.ts:40); doc: "List of Unity Catalog +models that were trained on this feature." + +**Issue:** "Model" is one of the most overloaded names in the SDK. The +`modelregistry`, `modelservingmanagement`, and `modelservingquery` packages +all have their own `Model`-shaped types. This local `Model` is yet another: +it is specifically a *reference* (Unity Catalog name + version) to a registered +model — not the model itself. + +The type has two fields: + +```ts +{ + name?: string | undefined; // The full name of the model in Unity Catalog. + version?: number | undefined; // The version of the model. +} +``` + +Naming-wise this is a *model reference*, not a model. + +**Suggested:** `LineageModelRef`, `ModelReference`, or `RegisteredModelRef`. +This avoids importing `FeatureLineage_Model` next to `modelregistry.Model` and +having two `Model`-shaped types in the same file. + +--- + +### 6. `FeatureLineage_OnlineFeature` is a reference, not a feature — category 6 (Misleading names) + +**Symbol:** `FeatureLineage_OnlineFeature` (model.ts:48); doc on the type-level +JSDoc on the parent says "List of online features that use this feature as +source." + +**Issue:** The type has two fields: + +```ts +{ + featureName?: string | undefined; // The name of the online feature (column name). + tableName?: string | undefined; // The full name of the online table in Unity Catalog. +} +``` + +This is *not* an online feature — it is a `(tableName, featureName)` pair +identifying one. Naming-wise the type should reflect "reference": +`OnlineFeatureRef` or `OnlineFeatureRef`. + +Additionally, the doc-string contradiction: outer JSDoc says "online features +that use this feature as source," but the inner field doc says "online feature +(column name)." The type is a coordinate, not the feature itself. + +**Suggested:** `LineageOnlineFeatureRef` or `OnlineFeatureRef`. + +--- + +### 7. `FeatureLineage_OnlineFeature.tableName` is the *online table name*, generic-named — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) + +**Symbol:** `FeatureLineage_OnlineFeature.tableName` (model.ts:52). + +**Issue:** The JSDoc says "The full name of the online table in Unity Catalog." +The field name `tableName` does not specify *online* table — yet the type is +called `FeatureLineage_OnlineFeature` and the field carries an online-table +3-part name (per `featurestore.PublishTableResponse.onlineTableName` and +`onlinetables.OnlineTable.name`). + +Within the same package, `CreateFeatureTagRequest.tableName` (model.ts:9) is +the *source* feature table — a *different* kind of table. Two fields with the +identical name `tableName` carry semantically different values across types +in the same package. + +**Suggested:** `onlineTableName` to match `featurestore.PublishTableResponse.onlineTableName` +and the field's actual content. This is the single most concrete naming bug +in the file. **P1 fix candidate.** + +--- + +### 8. `FeatureTag` is too generic — category 1 (Vague/generic) and category 12 (Duplicate concepts) + +**Symbol:** `FeatureTag` (model.ts:56). JSDoc: "Represents a tag on a feature +in a feature table." + +**Issue:** "Tag" appears in at least four sibling SDK packages, each with +its own type: + +- `entitytagassignments/v1` — `EntityTagAssignment`. +- `tagassignments/v1` — `TagAssignment`. +- `tagpolicies/v1` — `TagPolicy`. +- `materializedfeatures/v1` — `FeatureTag`. + +Each "tag" has its own `{key, value}` shape. A TS reader cannot easily tell +that `FeatureTag` is just a `{key, value}` string-string pair (same shape as +the others, but a distinct type) because the SDK has chosen to keep them +separate. + +The type itself is a perfectly fine 2-field record. The problem is the *name* +plus the *duplicated shape* across packages: + +```ts +export interface FeatureTag { + key?: string | undefined; + value?: string | undefined; +} +``` + +**Suggested:** keep the name (it correctly identifies the tag's owner), but +**flag SDK-wide:** unify the shape (one `Tag` interface) or unify the type +name to `FeatureTag` and put it adjacent to `Feature` in `features/v1`. The +present split between this package and `features/v1` (where `Feature` lives) +duplicates the conceptual boundary. + +--- + +### 9. `FeatureTag.key` and `value` underspecified — category 19 (Underspecified IDs) and category 1 (Vague/generic) + +**Symbols:** `FeatureTag.key`, `FeatureTag.value` (model.ts:57–58). + +**Issue:** Neither field has JSDoc, neither field documents allowed character +sets, length limits, or whether `key` is a free-form string or constrained to +a grammar. `DeleteFeatureTagRequest.key` (model.ts:21) has minimal JSDoc ("The +key of the tag to delete.") but does not link to the grammar. Compare to +`OnlineStore.name` in `featurestore` which at least documents "unique +identifier" — also weak. + +**Suggested:** strengthen JSDoc to specify max length, valid character set, +case sensitivity. The naming itself (`key`/`value`) is the project-wide +convention for tag pairs — pass on name, fix the docs. + +--- + +### 10. `CreateFeatureTagRequest`, `GetFeatureTagRequest`, `ListFeatureTagsRequest`, `UpdateFeatureTagRequest` carry `tableName` and `featureName` undocumented in some — category 6 (Misleading names) and JSDoc drift + +**Symbols:** `CreateFeatureTagRequest.tableName` (model.ts:9), +`GetFeatureTagRequest.tableName` (model.ts:70), +`ListFeatureTagsRequest.tableName` (model.ts:77), +`UpdateFeatureTagRequest.tableName` (model.ts:94) and the parallel +`featureName` fields. + +**Issue:** Of seven types that carry `tableName` / `featureName`: + +- `DeleteFeatureTagRequest` has JSDoc: "The name of the feature table.", "The + name of the feature within the feature table." (model.ts:16–19). +- `GetFeatureLineageRequest` has JSDoc: "The name of the feature.", "The full + name of the feature table in Unity Catalog." (model.ts:62–65). +- `CreateFeatureTagRequest`, `GetFeatureTagRequest`, `ListFeatureTagsRequest`, + `UpdateFeatureTagRequest` have **no JSDoc** at all on those fields (model.ts:9, + 70, 77, 94). + +Within the same package, the *same field* (`tableName`) is documented as both +"The name of the feature table" (delete) and "The full name of the feature +table in Unity Catalog" (lineage get). These are different specificities. The +former does not say whether it is a UC three-part name; the latter does. + +**Suggested:** uniformly document `tableName` as "The full three-part (catalog, +schema, table) name of the feature table in Unity Catalog." and `featureName` +as "The name of the feature (column) within the feature table." Add JSDoc to +the four types currently missing it. **Pass on naming, flag JSDoc drift.** + +--- + +### 11. `ListFeatureTagsResponse` not `ListFeatureTagResponse` — category 9 (Singular/plural mismatch) and JSDoc drift + +**Symbol:** `ListFeatureTagsResponse` (model.ts:86). JSDoc reads "Response +message for ListFeatureTag." (singular!) while the type is plural. + +**Issue:** The JSDoc text uses the singular form ("ListFeatureTag") but the +type, the method, the request, and the response collection are all plural +(`ListFeatureTagsRequest`, `Client.listFeatureTags`, `featureTags: FeatureTag[]`). +Pass on naming, **fix the JSDoc** ("Response message for ListFeatureTags."). + +--- + +### 12. `ListFeatureTagsRequest` and `Response` could be `ListRequest`/`ListResponse` — category 7 (Overly verbose) — *pass* + +**Symbols:** `ListFeatureTagsRequest` (model.ts:76), `ListFeatureTagsResponse` +(model.ts:86). + +**Issue:** Names are long (21/22 chars) but match the SDK-wide pattern for +paginated list endpoints. Within this package only `FeatureTag` is listable, +so `ListRequest` would suffice — but uniformity across packages wins. **Pass.** + +--- + +### 13. `UpdateFeatureTagRequest.featureTag.key` is also the path key — category 16 (Field contradicting type domain) and category 19 (Underspecified IDs) + +**Symbol:** `UpdateFeatureTagRequest.featureTag` (model.ts:96) + +`client.updateFeatureTag` URL builder (client.ts:220). + +**Issue:** The URL template uses `req.featureTag?.key`: + +```ts +const url = `${this.host}/api/2.0/feature-store/feature-tables/${req.tableName ?? ''}/features/${req.featureName ?? ''}/tags/${req.featureTag?.key ?? ''}`; +``` + +So the *body's* `featureTag.key` *also* identifies the resource. A user who +tries to rename a tag (e.g. change `key` from `env` to `environment`) will +PATCH `/tags/environment` — creating a new tag instead of renaming. The +request shape implicitly forbids changing `key`, but neither the type nor the +JSDoc says so. + +This contrasts with `DeleteFeatureTagRequest` (model.ts:21) which has an +explicit top-level `key`. The split — `key` is a top-level field for delete, +but nested under `featureTag.key` for update — is internally inconsistent. + +**Suggested:** add a top-level `key` field to `UpdateFeatureTagRequest` +(matching delete/get) and either: + +- Document that `featureTag.key` must equal `key`. +- Or remove `key` from the inner `featureTag` payload entirely (it is + redundant with the URL). + +The naming is fine; the structural choice is misleading. **Flag for upstream.** + +--- + +### 14. `GetFeatureLineageRequest` has fields ordered `featureName, tableName` — category 10 (Reserved-word collisions, by association) and JSDoc drift + +**Symbol:** `GetFeatureLineageRequest` (model.ts:61). + +**Issue:** Every other request type orders fields as `tableName, featureName` +(matching the URL: `/feature-tables/{tableName}/features/{featureName}/...`). +`GetFeatureLineageRequest` reverses to `featureName, tableName`. The URL still +goes through tables→features ordering (client.ts:119). This is internally +inconsistent. + +**Suggested:** swap field order to `tableName, featureName` for consistency. +This is a cosmetic but reader-facing inconsistency. + +--- + +### 15. `Client.getFeatureLineage` JSDoc reads "Get Feature Lineage." with title case — JSDoc drift and category 17 (Inconsistent action verbs) + +**Symbol:** `Client.getFeatureLineage` (client.ts:115). + +**Issue:** The JSDoc reads `/** Get Feature Lineage. */` in title case; +elsewhere in the same file: + +- `createFeatureTag` (client.ts:69): "Creates a FeatureTag." — sentence case + with proper noun. +- `deleteFeatureTag` (client.ts:95): "Deletes a FeatureTag." — same. +- `getFeatureTag` (client.ts:139): "Gets a FeatureTag." — same. +- `listFeatureTags` (client.ts:164): "Lists FeatureTags." — same. +- `updateFeatureTag` (client.ts:215): "Updates a FeatureTag." — same. +- `getFeatureLineage` (client.ts:114): "Get Feature Lineage." — **different + pattern** (title case, no plural verb, space between words). + +This is verb-tense / casing inconsistency within the same file. **Pass on +name, fix JSDoc** to read "Gets a FeatureLineage." or "Gets feature lineage." + +--- + +### 16. `Client.listFeatureTagsIter` async-iterator naming — *pass* + +**Symbol:** `Client.listFeatureTagsIter` (client.ts:198). + +`Iter` suffix is the project's canonical name for paginator generators +(`cleanrooms`, `cleanroomassets`, `featurestore`, etc.). Consistent across +the SDK. **Pass.** + +--- + +### 17. Method-name verbs `creates`/`deletes`/`gets`/`lists`/`updates` are consistent — category 17 (Inconsistent action verbs) — *pass* + +**Symbols:** `createFeatureTag`, `deleteFeatureTag`, `getFeatureLineage`, +`getFeatureTag`, `listFeatureTags`, `updateFeatureTag` (client.ts). + +The verb-prefix forms a clean CRUD-style vocabulary. No `fetch…`, `retrieve…`, +or `remove…` mixed in. **Pass.** + +--- + +### 18. `Client` class name — category 1 (Vague/generic) — *pass* + +Package convention. Every TS package exports a single `Client` class scoped to +its import path (e.g. `@databricks/sdk-materializedfeatures/v1`). **Pass.** + +--- + +### 19. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) + +**Symbol:** `PACKAGE_SEGMENT` (client.ts:39). + +**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true +constants (primitive literal values like `MAX_LEN = 10`). `PACKAGE_SEGMENT` is +a runtime object literal (`{ key, value }`) constructed from a JSON import. +Value is constant per-process, but the identifier shape violates the project +rule. Used in every package's `client.ts` — a project-wide convention. **Flag +for SDK-wide cleanup, do not fix in isolation.** + +**Suggested:** `packageSegment` or `clientPackageSegment`. + +--- + +### 20. `userAgent` / `httpClient` / `host` / `logger` — *pass* + +Standard private field names. Acronym handling matches the project rule. +**Pass.** + +--- + +### 21. `HttpCallOptions` (utils.ts:15) — category 1 (Vague/generic) and category 20 (Type-suffix tautology) + +**Symbol:** `HttpCallOptions` interface. + +**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the +neighbouring `CallOptions` is imported on line 12 of the same file. Two +"Call"-suffixed names in one file — which one does the reader mean? Suggest +`HttpRequestContext` or `ExecuteHttpArgs`. **Flag for SDK-wide cleanup** — +`utils.ts` is generated boilerplate copied across every package. + +--- + +### 22. `executeCall` vs `executeHttpCall` — category 17 (Inconsistent action verbs) + +**Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). + +**Issue:** Two functions named `execute…Call`. `executeCall` is the public +API wrapper that calls `execute()` from `@databricks/sdk-core/api`; +`executeHttpCall` performs an HTTP request and decodes the body. They do +*different* things at *different* layers — but the names imply a hierarchical +relationship that does not exist. The HTTP one is roughly `sendAndDecode` or +`doHttpRequest`. **Flag for SDK-wide naming cleanup;** this file is generated +boilerplate copied across every package. + +--- + +### 23. `readAll` — *pass* + +Helper does what its name says (reads a `ReadableStream` to +completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** + +--- + +### 24. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) + +**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). + +**Issue:** Two symmetric operations: response→object (`parse`) and +object→body-string (`marshal`). The verbs come from two different vocabularies +("parse" is generic TS/JS, "marshal" is Go). Internally consistent verb-pair +would be `parseResponse` / `serializeRequest`, or fully commit to Go terms: +`unmarshalResponse` / `marshalRequest`. The current pair is awkward. + +**Suggested:** `serializeRequest` and `parseResponse` (TS-native vocabulary) +or commit fully to Go terms: `unmarshalResponse` and `marshalRequest`. **Flag +for SDK-wide consistency.** + +--- + +### 25. `unmarshal*Schema` / `marshal*Schema` Go vocabulary — category 14 (Go/Java-style names) + +**Symbols:** `unmarshalFeatureLineageSchema` (model.ts:101), +`unmarshalFeatureLineage_FeatureSpecSchema` (model.ts:120), +`unmarshalFeatureLineage_ModelSchema` (model.ts:130), +`unmarshalFeatureLineage_OnlineFeatureSchema` (model.ts:142), +`unmarshalFeatureTagSchema` (model.ts:153), +`unmarshalListFeatureTagsResponseSchema` (model.ts:163), +`marshalFeatureTagSchema` (model.ts:174). + +**Issue:** "Marshal" / "Unmarshal" is Go-ism vocabulary. TS ecosystem uses +"serialize" / "deserialize" or, when working with Zod, "parse" / +"stringify" / "schema". The full SDK uses this convention; **flag for SDK-wide +cleanup, not this package alone.** + +The `*Schema` suffix is also somewhat redundant — `unmarshalFeatureTag` +without `Schema` would suffice since the value's type is +`z.ZodType` and there are no non-schema cousins. But this is a +naming-pattern decision applied SDK-wide. **Pass with note.** + +Additionally, the underscore from finding 2 propagates here: +`unmarshalFeatureLineage_ModelSchema` is doubly bad — both underscores *and* +the Go vocabulary. + +--- + +### 26. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* + +Verb-prefix matches the function's role (constructs an `HttpRequest` object). +Naming is fine. The file mixes `build…`, `execute…`, `marshal…`, `parse…`, +`readAll`, `flatten…` — six verbs for seven functions, but each is correct +for its purpose. **Pass.** + +--- + +### 27. `flattenQueryParams` (utils.ts:123) — dead code in this package + +**Symbol:** `flattenQueryParams` (utils.ts:123). + +**Issue:** Imported nowhere within this package. The `listFeatureTags` method +builds its query string inline at client.ts:170–177, and `updateFeatureTag` +does similar at client.ts:221–225. The helper is dead code in this package. + +The name itself is fine. **Suggest** deleting from this package, or extracting +all utils into a shared helper module (`@databricks/sdk-core/http`). **Flag +generator behaviour** — this is boilerplate-copy noise. + +--- + +### 28. `featureTagFieldMaskSchema` private but exported via `featureTagFieldMask()` — *pass* + +**Symbols:** `featureTagFieldMaskSchema` (model.ts:184, internal) and +`featureTagFieldMask()` (model.ts:189, public). Clean separation: schema is +private, helper is exported, helper name matches the Google AIP-134 +update-mask vocabulary. **Pass.** + +--- + +### 29. `UpdateFeatureTagRequest.updateMask` — category 7 (Overly verbose) — *pass* + +**Symbol:** `UpdateFeatureTagRequest.updateMask: FieldMask` +(model.ts:98). + +`updateMask` is the canonical Google AIP-134 name for partial-update masks; +the type `FieldMask` is from `@databricks/sdk-core/wkt`. The +naming is SDK-wide and idiomatic. **Pass.** + +--- + +### 30. Singular `FeatureTag` ⇔ plural `featureTags` — category 9 (Singular/plural mismatch) — *pass* + +`ListFeatureTagsResponse.featureTags: FeatureTag[]` (model.ts:87) is the +canonical pattern. **Pass.** + +--- + +### 31. `FeatureLineage.models` field name does not describe content — category 6 (Misleading names) and category 15 (Generic field names losing meaning) + +**Symbol:** `FeatureLineage.models?: FeatureLineage_Model[]` (model.ts:26). + +**Issue:** The field is called `models` but contains `FeatureLineage_Model[]` +— each of which is a *reference* to a registered model (name + version), not +the model itself. A reader who sees `lineage.models` reasonably expects +model objects (with fields like `creator`, `description`, etc.). They actually +get bare `{name, version}` pairs. + +**Suggested:** rename to `modelRefs`, `trainedModels`, or `modelReferences`. +Pairs with the finding-5 rename of `FeatureLineage_Model` → +`LineageModelRef` / `RegisteredModelRef`. + +--- + +### 32. `FeatureLineage.featureSpecs` vs `FeatureLineage.onlineFeatures` plural-singular mismatch — category 9 (Singular/plural mismatch) — *partial pass* + +**Symbols:** `FeatureLineage.featureSpecs`, `FeatureLineage.onlineFeatures` +(model.ts:28, 30). + +Both are arrays — plural form is consistent. No issue. **Pass.** + +--- + +### 33. `LineageContext` from `features` package vs `FeatureLineage` from this package — category 12 (Duplicate concepts) + +**Symbol:** `FeatureLineage` (model.ts:24); compare +`features.LineageContext` (`packages/features/src/v1/model.ts:465`). + +**Issue:** Two "lineage"-flavoured types live in two packages: + +- `features.LineageContext`: "Lineage context information for tracking where + an API was invoked. This will allow us to track lineage…" +- `materializedfeatures.FeatureLineage`: per JSDoc-less type, contains models + trained on a feature, feature specs containing the feature, and online + features using the feature as source. + +These are *distinct* concepts ("where this API call came from" vs. "what is +downstream of this feature"). The package split is poor — both concepts +ought to live with `Feature` in one place. A reader importing both packages +sees two different "lineage" shapes and must reason about which is which. + +**Suggested cross-package:** rename `materializedfeatures.FeatureLineage` → +`FeatureUsage` or `FeatureDependents` (it lists *what uses* the feature). The +"lineage" word is being used in two different senses: provenance (Context) +vs. dependents (Lineage). **Flag for upstream Go SDK / generator.** + +--- + +### 34. `GetFeatureLineageRequest` is `GetFeature…`, returns `FeatureLineage` — *pass* + +**Symbol:** `Client.getFeatureLineage` (client.ts:115), return type +`FeatureLineage` (model.ts:24). + +The method name uses verb `get` consistently; the return type name is the +resource. No issue at the method-name layer. (Underlying naming smells of +`FeatureLineage` itself are covered in findings 31, 33.) **Pass.** + +--- + +### 35. `BatchCreateMaterializedFeatures*` types live in `features` not this package — category 12 (Duplicate concepts) — cross-package + +**Symbols (cross-package):** `BatchCreateMaterializedFeaturesRequest`, +`BatchCreateMaterializedFeaturesResponse` live in `features/v1/model.ts:146, +151`. This `materializedfeatures` package has *no* materialized-feature types. + +**Issue:** Compound finding 1. The naming bug is that this package's *name* +implies it owns materialized features, while the actual types live in +`features`. If the rename in finding 1 is rejected, the alternative is to +*move* the materialized-feature types here. **Flag for SDK-wide upstream +coordination.** + +--- + +### 36. `marshalFeatureTagSchema` returns `z.ZodType` (no generic) but `unmarshalFeatureTagSchema` returns `z.ZodType` — category 17 (Inconsistent action verbs) + +**Symbols:** `unmarshalFeatureTagSchema: z.ZodType` (model.ts:153) +vs. `marshalFeatureTagSchema: z.ZodType` (model.ts:174). + +**Issue:** The unmarshal schema declares its parsed type as +`z.ZodType`; the marshal one declares only `z.ZodType` (i.e. +`z.ZodType`). Naming inconsistency mirrored in typing inconsistency. +This pattern is SDK-wide and presumably intentional (the marshal direction +produces wire-format objects without a TS shape), but symmetrically named +helpers should probably share a generic shape. **Flag for SDK-wide cleanup.** + +--- + +### 37. `index.ts` re-exports underscore types — category 4 (Underscores in TS identifiers) + +**Symbol:** `index.ts:7–20`. + +**Issue:** The package surface re-exports the proto-style nested names: + +```ts +export type { + CreateFeatureTagRequest, + DeleteFeatureTagRequest, + FeatureLineage, + FeatureLineage_FeatureSpec, + FeatureLineage_Model, + FeatureLineage_OnlineFeature, + FeatureTag, + ... +}; +``` + +Three of the eleven exported types contain underscores. These are the same +identifiers flagged in finding 2 — but at the *package surface* level, every +consumer sees them. **Pass at the index.ts layer**, fix follows from finding 2. + +--- + +### 38. `index.ts:5` empty re-export — *pass with note* + +**Symbol:** `export {} from './model';` (index.ts:5). + +This is a generator-emitted no-op (re-export *nothing* from the module). It is +not a naming finding, but it is a code-smell artefact of the generator. **Pass +on naming**, flag for generator cleanup. + +--- + +### 39. URL path constants spread inline in `Client` methods — code-quality (out of scope) — *pass* + +**Symbols:** every method constructs a URL via template literal embedding +`req.tableName ?? ''` and `req.featureName ?? ''` (client.ts:74, 100, 119, +144, 169, 220). + +Naming is fine (no constants to flag); the duplication is a code-quality +concern, not naming. **Pass.** + +--- + +### 40. `req`/`resp`/`pageReq` Go-style short variable names — category 14 (Go/Java-style names) + +**Symbols:** local variables `req` (every method parameter), `resp` (every +method local), `pageReq` (client.ts:202). + +**Issue:** TS ecosystem typically prefers full words: `request`, `response`, +`pageRequest`. Compare with Node/Express conventions. The shortened forms are +Go-style. However, `req`/`res` is also common in TS Express/Node code, so the +convention is mixed. **Pass with note — flag for SDK-wide style decision.** + +--- + +### 41. Generator-comment "DO NOT EDIT." header — *pass* + +Every file begins with `// Code generated from API definition by Databricks +SDK Generator. DO NOT EDIT.` Naming-irrelevant, but informs the scope of any +suggested fix (all naming changes must be implemented at the generator, +not in the file). **Pass.** + +--- + +## Cross-package notes (per audit instructions) + +### Package-name mis-scope (`materializedfeatures` ↔ `features`) + +The most serious finding in this audit. The package called `materializedfeatures` +contains *zero* materialized-feature types; the package called `features` +contains the materialized-feature types (`MaterializedFeature`, +`BatchCreateMaterializedFeaturesRequest`, etc., per `features/v1/model.ts:47, +146, 197, 517`). A reasonable fix: + +- Rename the package directory and `package.json` `name` field to + `@databricks/sdk-featuretags`. +- Or rename to `@databricks/sdk-featuretagsandlineage` (verbose) or move the + contents into `@databricks/sdk-features`. + +The `materializedfeatures` directory exists in `packages/` (per the directory +listing) and the matching markdown doc `materializedfeatures.md` is also +present at `packages/materializedfeatures.md`. Both would need to move. + +**P1 cross-package alignment.** + +--- + +### `tableName` overload across packages + +`materializedfeatures.{Create,Delete,Get,List,Update}FeatureTagRequest.tableName` +is the source feature-table name. `featurestore.PublishTableRequest.sourceTableName` +is also a source table name. `FeatureLineage_OnlineFeature.tableName` is an +*online* table name. `featurestore.DeleteOnlineTableRequest.onlineTableName` +is also an online table name. Four kinds of `tableName` across two packages, +each disambiguated by neighbouring fields and JSDoc — but not by the name +itself. + +**Recommendation:** standardise: + +- Source feature-table name: `featureTableName` (more specific than just + `tableName`). +- Online table name: `onlineTableName` (already in use in `featurestore`). + +The package-local `tableName` (used here) is fine *inside* the request types +because the URL grammar disambiguates, but `FeatureLineage_OnlineFeature.tableName` +should definitely be `onlineTableName` (finding 7). + +**Flag for SDK-wide policy.** + +--- + +### `Tag` concept overlap across packages + +| Package | Type name | Shape | Use | +|---------------------------|------------------------|-------------|-----------------------------| +| `materializedfeatures` | `FeatureTag` | `{key,value}` | Tag on a feature column. | +| `entitytagassignments` | `EntityTagAssignment` | (TBD) | Tag-to-entity assignment. | +| `tagassignments` | `TagAssignment` | (TBD) | Tag-to-resource assignment. | +| `tagpolicies` | `TagPolicy` | (TBD) | Tag policy rules. | + +Four distinct "tag" types in four packages. Each likely justified by its +ownership and lifecycle (a `FeatureTag` is owned by a feature; a +`TagAssignment` connects a tag to a resource; a `TagPolicy` defines tag +governance). But naming-wise the boundary is murky: a reader of +`@databricks/sdk-materializedfeatures/v1` sees `FeatureTag` and may not +realise `TagAssignment` exists separately. + +**Cross-SDK recommendation:** document the relationship in package JSDoc +(`index.ts` should reference the related "tag" packages). **Flag for upstream +Go SDK / docs.** + +--- + +### `FeatureLineage` vs `LineageContext` vs `externallineage` + +Three lineage-related types/packages exist: + +- `materializedfeatures.FeatureLineage` — downstream dependents of a feature. +- `features.LineageContext` — provenance/context for an API call. +- `externallineage` (entire package) — lineage outside Databricks. + +"Lineage" is being used in three different senses. **Flag for upstream +documentation / generator naming**; the SDK exposes consumers to three +distinct lineage concepts with no naming convention to distinguish them. + +--- + +### Field-naming hygiene relative to `features.Feature` + +`features.Feature` (model.ts:279) has its own `lineageContext` field +(model.ts:310), not the `FeatureLineage` defined here. The two "feature +lineage" concepts coexist: + +- `features.Feature.lineageContext: LineageContext` — internal SDK use, set + by the SDK, not the user (per JSDoc: "Users should not manually set this + field…"). +- `materializedfeatures.FeatureLineage` — user-facing read-only object + describing what depends on a feature. + +The two are unrelated, but the words overlap. **Flag for SDK-wide naming +guidance.** + +--- + +### Wire-format vs TS field-name divergence + +Same as every package: every request/response type has both a TS interface +and a Zod schema that maps `snake_case` wire fields to `camelCase` TS fields. +This pattern is fine and consistent. The `marshal`/`unmarshal` Go vocabulary +is a separate (SDK-wide) concern — see finding 25. + +--- + +## Summary (counts) + +- **Critical / cross-package consistency:** 2 findings (#1 package name + mis-scope `materializedfeatures` does not contain materialized features; + #7 `FeatureLineage_OnlineFeature.tableName` should be `onlineTableName`). +- **High (style guide violations):** 5 findings (#2 three underscore types + `FeatureLineage_FeatureSpec/Model/OnlineFeature`; #19 `PACKAGE_SEGMENT` + casing; #25 unmarshal/marshal Go vocab on schemas; #37 surface re-exports + underscore types; #36 generic-shape inconsistency between marshal and + unmarshal). +- **Medium (naming clarity, JSDoc drift):** 11 findings (#3, #4, #5, #6, #8, + #9, #10, #11, #13, #14, #15, #31, #33). +- **Low / project-wide convention notes (generator-level):** 6 findings (#21, + #22, #24, #27, #35, #40). +- **Pass / acceptable as-is:** 14 findings (#12, #16, #17, #18, #20, #23, + #26, #28, #29, #30, #32, #34, #38, #39, #41 — many partial passes with + notes). + +**Total flagged findings: 41** distinct items across 20 audit categories +(many findings touch multiple categories). The dominant theme is **package +mis-naming** (the package does not contain what its name advertises) and +**proto-style underscore identifier names** for nested types (`FeatureLineage_*`). +Many issues are generator-emitted boilerplate inherited from the Go SDK; +the cleanest local fixes are findings 1 (package rename), 7 +(`onlineTableName` field), 10 (JSDoc on `tableName`/`featureName`), 11 +(JSDoc plural form), 13 (top-level `key` for update), 14 (field order in +`GetFeatureLineageRequest`), and 15 (`getFeatureLineage` JSDoc casing). diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md new file mode 100644 index 00000000..fa088bcb --- /dev/null +++ b/.agent/naming-audit/metastores.md @@ -0,0 +1,693 @@ +# Naming Audit: `metastores` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/metastores/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Unity Catalog (UC) metastore — the top-level container that holds catalogs, schemas, and tables, and is assigned to workspaces. + +--- + +## Summary + +The `metastores` package exposes nine Unity Catalog metastore operations +(`createMetastore`, `createMetastoreAssignment`, `deleteMetastore`, +`deleteMetastoreAssignment`, `getCurrentMetastoreAssignment`, +`getMetastore`, `getMetastoreSummary`, `listMetastores`, +`listMetastoresIter`, `updateMetastore`, `updateMetastoreAssignment`). +The naming issues split into two broad classes: + +1. **Proto-style identifiers leaking into TypeScript** — + `DeltaSharingScope_Enum`, `*_Response`, `unmarshal…_ResponseSchema`. +2. **Massive structural duplication** — `CreateMetastore`, + `UpdateMetastore`, and `MetastoreInfo` share 18 fields verbatim, + including read-only output fields (`createdAt`, `createdBy`, + `updatedAt`, `updatedBy`, `metastoreId`, `globalMetastoreId`) that + have no business in a write request. `UpdateMetastore` further + conflates a path-parameter `id`, a body `name`, and a "rename target" + `newName`. + +`DeltaSharingScope_Enum` is the single most visible cosmetic violation +(underscore identifier and `_Enum` suffix tautology), and it shows up +on three different types and in both marshal/unmarshal schemas. + +--- + +## Findings + +### 1. Vague / generic names + +#### 1.1 `DeleteMetastore.id`, `GetMetastore.id`, `UpdateMetastore.id` (model.ts:79, 105, 234) +Field name `id` on three request types where the surrounding type +already conveys the entity ("delete metastore", "get metastore", "update +metastore"). The doc string is "Unique ID of the metastore." — i.e. the +field is the metastore id. The same concept appears as `metastoreId` +everywhere else in the package (model.ts:42, 64, 91, 113, 213, 258, +etc.), so the bare `id` is inconsistent and ambiguous in isolation +(e.g. spreading `{...req, id: someValue}` is brittle). Recommend +`metastoreId` (or, if the goal is to mark it as the path param, see +§5.1 / §13.1). + +#### 1.2 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:181, 183) +Acceptable in isolation — but the *type* `MetastoreAssignment` is just +a `(workspaceId, metastoreId, defaultCatalogName)` triple. The name +"MetastoreAssignment" promises richer semantics than the three-field +struct delivers. Consider `WorkspaceMetastoreLink` or making the +relationship directional in the name. + +#### 1.3 `DeleteMetastore.force` (model.ts:81) +Generic boolean — "force" alone leaves callers to read the doc to learn +the consequences ("Force deletion even if the metastore is not empty."). +A more descriptive name (`forceDeleteNonEmpty`, `deleteNonEmpty`) +captures the intent at the call site. Acceptable as a convention but +worth flagging. + +#### 1.4 `cloud` field (model.ts:54, 122, 225, 270) +A bare `cloud: string` with a single example list in the doc (`aws`, +`azure`, `gcp`). Should probably be typed as a `CloudProvider` enum +(see §6.4) — but at minimum the field is generic when read alone. + +#### 1.5 `owner` field (model.ts:36, 140, 207, 252) +"The owner of the metastore." — generic. Owner of what kind? Username? +Email? Group? Service principal? Documented as a free-form string with +no format hint. See §16.4. + +#### 1.6 `region` (model.ts:40, 124, 211, 256) +Bare `region: string` with examples (`us-west-2`, `westus`). Acceptable +as cloud-vendor-specific opaque strings, but the same field carries +different vocabularies across `aws` / `azure` / `gcp` — that +heterogeneity isn't reflected in the name or doc. + +--- + +### 2. Redundant enum prefixes + +#### 2.1 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) +Variants are `INTERNAL` and `INTERNAL_AND_EXTERNAL`. The enum name +already says "DeltaSharingScope" — the variants do not repeat that +prefix, which is good. However, `INTERNAL_AND_EXTERNAL` is verbose +(see §15.1) — a single canonical name like `ALL` or a pair like +`INTERNAL` / `EXTERNAL` would be clearer. + +(No `*_DELTA_SHARING_SCOPE_*` prefix issue here — variants are clean. +But see §4.1 for the enum *type* name.) + +--- + +### 3. Acronym casing inconsistencies + +#### 3.1 `DBR` in doc strings (model.ts:57, 149, 228, 273) +Doc says "Whether to allow non-DBR clients to directly access entities +under the metastore." DBR (Databricks Runtime) is an internal acronym +not introduced anywhere in the package. Doc-only, not a code-naming +issue per se, but it's a documentation acronym that won't mean anything +to external SDK consumers. + +#### 3.2 `UUID` casing in docs (model.ts:27, 119, 198, 243) +"UUID of storage credential" — UUID is in the doc only. The field is +named `storageRootCredentialId` (lowercase `Id`). Consistent with +ECMAScript identifier convention; flagged in passing. + +#### 3.3 `URL` casing in docs (model.ts:23, 138, 194, 239) +"The storage root URL" — `URL` in docs, but the field is +`storageRoot`, not `storageRootUrl`. Inconsistent with how +`globalMetastoreId` etc. embed type info in the name. See also §6.2. + +#### 3.4 `` placeholder tokens in docs (model.ts:69, 180, 285) +Literal `` strings appear in doc comments — these are +unsubstituted templating placeholders. Not a naming issue, but +surfaces as a publication bug for SDK consumers reading the generated +TypeDoc. + +--- + +### 4. Underscores in TypeScript identifiers + +The package's most pervasive cosmetic problem. Every underscore-bearing +identifier is silenced with an +`@typescript-eslint/naming-convention -- Proto-style…` disable comment, +i.e. the lint rule already objects. + +#### 4.1 `DeltaSharingScope_Enum` (model.ts:6) +Should be `DeltaSharingScope`. The `_Enum` suffix is a proto-port +artifact (see also §8.3 and §17.1). The enum is referenced in five +places (lines 30, 132, 201, 246, 318, 385, 434, 493) — every reference +inherits the awkward name. + +#### 4.2 `CreateMetastoreAssignment_Response` (model.ts:75) +Should be `CreateMetastoreAssignmentResponse`. + +#### 4.3 `DeleteMetastore_Response` (model.ts:85) +Should be `DeleteMetastoreResponse`. + +#### 4.4 `DeleteMetastoreAssignment_Response` (model.ts:95) +Should be `DeleteMetastoreAssignmentResponse`. + +#### 4.5 `GetMetastoreSummary_Response` (model.ts:112) +Should be `GetMetastoreSummaryResponse`. (Non-empty — it's the only +genuinely useful `_Response` in the package; see §6.6.) + +#### 4.6 `ListMetastores_Response` (model.ts:169) +Should be `ListMetastoresResponse`. + +#### 4.7 `UpdateMetastoreAssignment_Response` (model.ts:291) +Should be `UpdateMetastoreAssignmentResponse`. + +#### 4.8 Schema export names propagate underscores (model.ts:294, 298, 302, 306, 353, 425) +- `unmarshalCreateMetastoreAssignment_ResponseSchema` +- `unmarshalDeleteMetastore_ResponseSchema` +- `unmarshalDeleteMetastoreAssignment_ResponseSchema` +- `unmarshalGetMetastoreSummary_ResponseSchema` +- `unmarshalListMetastores_ResponseSchema` +- `unmarshalUpdateMetastoreAssignment_ResponseSchema` + +Should drop the underscore: `unmarshalDeleteMetastoreResponseSchema`, +etc. + +--- + +### 5. Cryptic abbreviations + +#### 5.1 `id` (model.ts:79, 105, 234) — see §1.1 +Cryptic because it loses the entity context. `metastoreId` is used +elsewhere. + +#### 5.2 `req` parameter name in `Client.*` methods (client.ts:93, 123, 152, 183, 217, 242, 270, 306, 339, 361, 391) +`req` is the canonical Go-SDK parameter name. In TS it would more +typically be `request` or `params`. Defensible (internal to the call +site, every method has the same shape), but a Go idiom that has been +ported verbatim — see §11.3. + +#### 5.3 `resp` local variable name (client.ts:98, 128, 162, 193, etc.) +Same pattern as §5.2 — `resp` for `response`. Go-style abbreviation. + +#### 5.4 `pkgJson` (client.ts:19) +Import alias for `package.json`. Minor — internal — and matches the +peer packages' convention. + +#### 5.5 `Ms` suffix absent on timestamp fields +Counter-example: timestamp fields are documented as "epoch +milliseconds" but the names omit the unit suffix (`createdAt`, +`updatedAt`). See §16.5. + +--- + +### 6. Misleading names + +#### 6.1 `MetastoreInfo` (model.ts:191) +"Info" suggests metadata about a metastore separate from the entity +itself; the type is in fact the entity. See also §8.1. + +#### 6.2 `storageRoot` doc says "URL" (model.ts:23, 138, 194, 239) +"The storage root URL for metastore" — the field is named +`storageRoot`, but documented as a URL. Rename to `storageRootUrl`, +or rename the doc. Today the name is vague about the value's shape. + +#### 6.3 `globalMetastoreId` (model.ts:56, 126, 227, 271) +Doc: "Globally unique metastore ID across clouds and regions, of the +form `cloud:region:metastore_id`." So the value is a composite +formatted string, not an ID in the conventional sense. Either rename +to `globalMetastoreLocator` / `globalMetastoreUri` to signal the +encoded shape, or document its parseable structure in a type. + +#### 6.4 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +Doc says "Unique identifier of the metastore's (Default) Data Access +Configuration." The parenthetical "Default" duplicates the `default` +prefix in the name, but the field is described as both the default +data-access-config and as a unique identifier. Slightly self-referential +and unclear whether this is mutable or static. See also §16.3. + +#### 6.5 `cloud: string` (model.ts:54, 122, 225, 270) +Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as +`string`. The name is fine; the *type* misleads about the value +space. Compare with `DeltaSharingScope_Enum`, which is explicitly an +enum. See §1.4. + +#### 6.6 `region: string` carries cloud-specific formats (model.ts:40, 124, 211, 256) +"e.g., `us-west-2`, `westus`" — same field carries AWS-style and +Azure-style region names. Name is fine; doc just shows the +heterogeneity. See §1.6. + +#### 6.7 `GetMetastoreSummary_Response` is structurally identical to `MetastoreInfo` (model.ts:112-151 vs 191-230) +Both types have the *same* 18 fields with the *same* docs in the *same* +order. The "summary" type doesn't actually summarise — it returns the +full metastore record. The name lies about the content. The Go SDK +inherits this from the API definition, but the TS port could collapse +the two: either alias `GetMetastoreSummaryResponse = MetastoreInfo` or +expose the genuinely-summarised subset. + +#### 6.8 `getMetastoreSummary` is presented as info-about (client.ts:266-269) +JSDoc says "Gets information about a metastore. This summary +includes…". But the API in fact returns the current workspace's +metastore — there is no metastore ID parameter. The name "summary" +omits the "current-workspace" semantics. Cf. +`getCurrentMetastoreAssignment`, which spells out "current". See also +§14.1. + +--- + +### 7. Overly verbose + +#### 7.1 `deltaSharingRecipientTokenLifetimeInSeconds` (model.ts:32, 134, 203, 248) +46-character field name. The `InSeconds` unit suffix is good (see §16.5), +but the field gets used as a top-level property of three different +types and bleeds into every marshal/unmarshal schema (also 46 chars, +plus snake-case form). Acceptable for clarity; flagged because it's +the longest field name in the package. + +#### 7.2 `deltaSharingOrganizationName` (model.ts:34, 136, 205, 250) +28 characters. Same pattern as 7.1 — repeated on every metastore type. + +#### 7.3 `unmarshalCreateMetastoreAssignment_ResponseSchema` (model.ts:294) +49 characters. With the underscore stripped (§4.8), it's 48 — +unavoidable given the underlying naming, but worth flagging as a long +identifier. + +#### 7.4 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) — see §15.1. + +#### 7.5 `getCurrentMetastoreAssignment` (client.ts:216) +28-character method name. Acceptable — describes the semantics — but +combined with `getMetastoreSummary` (which is also "current-workspace" +in practice, §6.8) one of them carries redundant prefixing. + +--- + +### 8. Redundant suffixes + +#### 8.1 `…Info` suffix on `MetastoreInfo` (model.ts:191) +"Info" carries no semantic content. Go-SDK convention; TS would just +say `Metastore`. See §11.4. + +#### 8.2 `…_Enum` suffix on `DeltaSharingScope_Enum` (model.ts:6) — see §4.1. +TypeScript enums are already enums; the suffix tautological. + +#### 8.3 `…Schema` suffix on every zod schema export +Every export is named `marshal…Schema` / `unmarshal…Schema`. The +`Schema` suffix is conventional but redundant when paired with the +`marshal…`/`unmarshal…` prefix (which already says "this is a +zod-using helper"). Cf. catalogs audit §8.6. + +#### 8.4 `…Assignment` suffix on `MetastoreAssignment` and four request types +`CreateMetastoreAssignment`, `DeleteMetastoreAssignment`, +`UpdateMetastoreAssignment`, `GetCurrentMetastoreAssignment`, +`MetastoreAssignment`. The suffix is justified because "metastore +assignment" is a distinct concept. Not redundant — flagged for +completeness. + +--- + +### 9. Singular / plural mismatches + +#### 9.1 `listMetastoresIter` returns `AsyncGenerator` (client.ts:338) +Method name pluralizes ("Metastores") but yields singular items. Same +pattern as `listCatalogsIter` (catalogs §9.1). Consider `iterMetastores` +(verb-first) — but consistency across the SDK matters more than the +nominal/verbal split. + +#### 9.2 `ListMetastores_Response.metastores` (model.ts:171) +Field is plural and correctly typed `MetastoreInfo[]` — no mismatch. +Flagged as a counter-example. + +--- + +### 10. Reserved-word collisions + +#### 10.1 `name` field on `CreateMetastore`, `MetastoreInfo`, `UpdateMetastore`, `GetMetastoreSummary_Response` (model.ts:22, 116, 193, 238) +Routinely shadows `Function.prototype.name`. Common SDK convention; not +fixable in isolation. See also §13.1. + +#### 10.2 `id` field on `DeleteMetastore`, `GetMetastore`, `UpdateMetastore` (model.ts:79, 105, 234) +Collides with `Element.id` and other web-platform-y identifiers when +the request type is used in browser code. Not a TS-level collision but +a cognitive one. See §1.1. + +#### 10.3 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. + +--- + +### 11. Go / Java-style names + +#### 11.1 `DeltaSharingScope_Enum` (model.ts:6) — proto nested-enum convention. See §4.1. + +#### 11.2 `…_Response` suffix (model.ts:75, 85, 95, 112, 169, 291) — proto/Go-RPC idiom. See §4.2-4.7. + +#### 11.3 `req` / `resp` parameter and local names (client.ts throughout) — Go style. See §5.2, §5.3. + +#### 11.4 `…Info` suffix on `MetastoreInfo` — Go/Java style. See §6.1, §8.1. + +#### 11.5 `unmarshal…` / `marshal…` prefix verbs — Go's `encoding/json` vocabulary. TS would use `parse`/`serialize` or `decode`/`encode`. Defensible for internal generated code; identifies as Go-style. + +#### 11.6 `Client` bare class name (client.ts:61) — Go idiom (package qualifies the type). TS consumers commonly alias to `MetastoresClient`. Same pattern as catalogs §14.2. + +--- + +### 12. Duplicate concepts + +#### 12.1 `DeltaSharingScope` interface vs `DeltaSharingScope_Enum` enum (model.ts:6, 98) +Two distinct exports with near-identical names — one is the enum, the +other a separate type. A user importing `DeltaSharingScope` will get +the non-enum export and silently get the wrong shape. The naming is +maximally hostile and the `_Enum` suffix on the enum exists solely to +disambiguate from this sibling. + +#### 12.2 `MetastoreInfo` vs `GetMetastoreSummary_Response` (model.ts:112, 191) +Same 18 fields, same docs, different names. See §6.7. + +#### 12.3 `CreateMetastore` vs `MetastoreInfo` vs `UpdateMetastore` (model.ts:20, 191, 232) +Massive structural duplication — `CreateMetastore` has 19 fields, +`MetastoreInfo` has 19 fields, `UpdateMetastore` has 20 fields. The +extra field on `UpdateMetastore` is `id` (path param) plus `newName`. +Every other field is replicated verbatim with the same doc string. A +shared `MetastoreCommon` (or `Partial`) would let +renames happen in one place. Note that all three contain the same +read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, +`metastoreId`, `globalMetastoreId`) — these have no business on a +request shape (§13.3). + +#### 12.4 `CreateMetastoreAssignment` vs `MetastoreAssignment` vs `UpdateMetastoreAssignment` (model.ts:61, 179, 277) +Three structurally identical types with three workspace-id / +metastore-id / default-catalog-name fields. Could be unified. + +#### 12.5 `id` (on `DeleteMetastore`/`GetMetastore`/`UpdateMetastore`) vs `metastoreId` (everywhere else) +Same concept, two names. See §1.1. + +#### 12.6 `name` (CreateMetastore body) vs metastore identity +`CreateMetastore.name` is "the user-specified name of the metastore" +— but `MetastoreInfo` also exposes `metastoreId` as the canonical +unique identifier. The naming pretends `name` is unique but in fact +the server creates `metastoreId` as the immutable key and `name` is +mutable. The doc could disclose this; the name doesn't. + +#### 12.7 `name` vs `newName` on `UpdateMetastore` (model.ts:236, 238) +Two name-like fields on the update request: +- `newName` — "New name for the metastore." (model.ts:236). +- `name` — "The user-specified name of the metastore." (model.ts:238). + +Per the doc, both fields can hold a name. The intent is presumably +that `newName` is the rename target and `name` is left over from the +shared shape; in practice, callers cannot tell. See §13.1. + +--- + +### 13. Field contradicting type domain + +#### 13.1 `UpdateMetastore` has `id`, `name`, `newName`, and `metastoreId` (model.ts:234, 236, 238, 258) +Four name/id-like fields on a single update request: +- `id` — path parameter; the existing metastore to update. +- `metastoreId` — leftover from the shared shape; not used by the + client method (`req.id` is what is interpolated into the URL at + client.ts:364). +- `name` — "The user-specified name of the metastore." Ambiguous + whether this is the current or new name. +- `newName` — "New name for the metastore." Presumably the rename + target. + +A caller staring at this struct cannot intuit which field controls +what. This is the package's single most user-hostile naming pattern, +mirroring the `UpdateCatalog` issue (catalogs §16.1). + +#### 13.2 `UpdateMetastore.metastoreId` shadows `UpdateMetastore.id` (model.ts:234, 258) +Same as 13.1 — two id-like fields whose roles are not differentiated +by name. + +#### 13.3 `CreateMetastore` and `UpdateMetastore` carry read-only output fields (model.ts:42-58, 258-274) +`metastoreId`, `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, +`globalMetastoreId`, `cloud`, `storageRootCredentialName`. These are +server-populated; a creator/updater setting them is at best ignored. +The type's name promises "create" or "update" but the shape +contradicts that by including read-only output. Mirror of +catalogs §16.2. + +#### 13.4 `GetMetastoreSummary_Response` returns the full metastore (model.ts:112) — see §6.7. The type name promises a summary; the value is the entity. + +--- + +### 14. Inconsistent action verbs + +#### 14.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:241, 269, 216) +Three "get"-style methods, each with a different qualifier: +- `getMetastore(req)` — get by id. +- `getMetastoreSummary()` — get the current metastore (no id). +- `getCurrentMetastoreAssignment()` — get the current + workspace/metastore assignment. + +The first explicitly takes an id, the second implicitly uses the +current workspace, the third explicitly says "Current". Inconsistent +qualifier vocabulary. Either rename `getMetastoreSummary` to +`getCurrentMetastore` (which would also fix §6.8) or drop "Current" +from `getCurrentMetastoreAssignment`. + +#### 14.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. + +#### 14.3 `listMetastoresIter` uses a suffix-style iter marker rather than a verb prefix. Consistent with the rest of the SDK; flagged for completeness. + +--- + +### 15. Long enum values + +#### 15.1 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) +20 characters. Two of two variants is verbose. A pair `INTERNAL` / +`EXTERNAL` (where `EXTERNAL` implies "in addition to internal") would +be punchier. The current name doubles as a poor man's bit-flag. See §2.1. + +--- + +### 16. Underspecified IDs + +#### 16.1 `metastoreId` (model.ts:42, 64, 91, 113, 183, 213, 258, 281) +Documented as "Unique identifier of metastore" / "The unique ID of the +metastore." Format is opaque — likely a UUID, but never specified in +the doc. + +#### 16.2 `workspaceId` (model.ts:63, 89, 181, 279) +`number` — that's specified by the type, but the doc just says "A +workspace ID." with no range or stability guarantee. Acceptable for a +numeric id; flagged because the format isn't documented in the field. + +#### 16.3 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +"Unique identifier of the metastore's (Default) Data Access +Configuration." No format hint (UUID? slug?). See §6.4. + +#### 16.4 `storageRootCredentialId` (model.ts:28, 120, 199, 244) +Doc says "UUID of storage credential" — at least the doc says UUID +here, but the field name doesn't carry the type. Counter-example to +§16.1: when the doc *does* specify UUID, the field still doesn't carry +it. + +#### 16.5 `createdAt`, `updatedAt` (model.ts:44, 48, 142, 146, 215, 219, 260, 264) +Doc says "epoch milliseconds" but the names lack the `Ms` unit +suffix. Counter-example: `deltaSharingRecipientTokenLifetimeInSeconds` +(model.ts:32) *does* carry the `InSeconds` unit. Inconsistent. + +#### 16.6 `globalMetastoreId` (model.ts:56, 126, 227, 271) +Documented as a composite `cloud:region:metastore_id` string — not a +simple ID. The name promises an ID; the value is a structured +locator. See §6.3. + +#### 16.7 `owner`, `createdBy`, `updatedBy` (model.ts:36, 46, 50, 140, 144, 148, 207, 217, 221, 252, 262, 266) +Documented as "username", "Username of metastore creator", etc. +Format (email? user id? group?) is unspecified. The names imply +identity; the doc only narrows to "username". + +--- + +### 17. Type-suffix tautology + +#### 17.1 `DeltaSharingScope_Enum` enum with field `deltaSharingScope: DeltaSharingScope_Enum` (model.ts:6, 30, 132, 201, 246) +Field name `deltaSharingScope` is identical to the enum *minus* the +`_Enum` suffix. The `_Enum` suffix exists solely to disambiguate the +enum from the sibling `DeltaSharingScope` interface (§12.1). Were the +sibling renamed, the enum could simply be `DeltaSharingScope` and the +field name would be exactly the enum name (a true tautology). Today, +the workaround is the `_Enum` suffix. + +#### 17.2 `MetastoreInfo` exposes `metastoreId` (model.ts:191, 213) +The type's domain is the metastore; the field redundantly carries the +entity name in its identifier. Acceptable convention; flagged for +completeness. + +#### 17.3 Schema-export tautology +`unmarshalMetastoreInfoSchema: z.ZodType` (model.ts:379) +— the `Schema` suffix duplicates `z.ZodType<…>`. See §8.3. + +#### 17.4 `MetastoreAssignment` carries `metastoreId` (model.ts:179, 183) +Same pattern as 17.2 — entity name in field. + +--- + +## Additional / cross-cutting observations + +### A. `flattenQueryParams` is defined but unused (utils.ts:123) +Each `deleteMetastore` / `deleteMetastoreAssignment` / `listMetastores` +handler builds query strings inline with `URLSearchParams.append` +(client.ts:156-159, 187-190, 310-316). The exported helper +`flattenQueryParams` is never referenced by `client.ts`. Either it's +intentionally exported for consumer use (then it should be documented +and reside in `utils` proper) or it's dead code. Same as catalogs +cross-cutting A. + +### B. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:126, 186, 394) +If `workspaceId` is undefined, the URL silently becomes +`/api/2.1/unity-catalog/workspaces//metastore` (note the double slash) +and the request will fail on the server. The optional typing of +`workspaceId` on `CreateMetastoreAssignment`, +`DeleteMetastoreAssignment`, and `UpdateMetastoreAssignment` (each +field is `number | undefined`) lets the bug hide. + +### C. `req.id` is similarly optional but interpolated into URLs (client.ts:155, 245, 364) +`${req.id ?? ''}` — same pattern: undefined id silently produces a +malformed URL. Combined with the generic `id` name (§1.1) the type +contract is too loose for a required path parameter. + +### D. `DeleteMetastoreAssignment.metastoreId` is sent in the query string, not the path (client.ts:186-191) +On `DELETE /api/2.1/unity-catalog/workspaces/{workspaceId}/metastore`, +the request appends `?metastore_id=…`. That contradicts the doc on +`DeleteMetastoreAssignment.metastoreId` ("Query for the ID of the +metastore to delete.") only via the leading word "Query" — the field +name itself does not signal that the value is a query parameter, not +a path one. + +### E. Marshal/unmarshal exports lack proper TS types for marshal side (model.ts:428, 473, 485, 534) +`marshalCreateMetastoreSchema: z.ZodType` (no generic) versus +`unmarshalMetastoreInfoSchema: z.ZodType` (with +generic). The marshal side is implicitly untyped. Not a naming issue +per se, but inconsistent with the unmarshal naming/typing. + +### F. `Client` constructor throws bare `Error` for missing `host` (client.ts:72) +"Host is required." — bare `Error`. Not a naming issue, flagged in +passing for the broader review. + +### G. `index.ts` re-exports proto-style names verbatim (lines 5, 7-27) +Every underscore-bearing identifier surfaces in the package's public +API. A consumer of `@databricks/sdk-metastores/v1` sees +`DeltaSharingScope_Enum`, `CreateMetastoreAssignment_Response`, +`DeleteMetastore_Response`, `DeleteMetastoreAssignment_Response`, +`GetMetastoreSummary_Response`, `ListMetastores_Response`, and +`UpdateMetastoreAssignment_Response` as first-class exports. + +### H. `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` (index.ts:5, 15) +A consumer importing `DeltaSharingScope` gets the sibling export, not +the enum. There is no compile-time or runtime hint that they should +have used the `_Enum`-suffixed export. See §12.1. + +### I. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies +This package's `workspaceId` is `number`. Some peer packages model +workspace IDs as strings (e.g. when forwarded through URL params). +The type inconsistency is across packages, not within this one; +flagged in passing. + +--- + +## File / line index for fast lookup + +| Identifier | Location | Finding | +| ------------------------------------------------------- | ------------------ | ------- | +| `DeltaSharingScope_Enum` | model.ts:6 | 2.1, 4.1, 8.2, 11.1, 15.1, 17.1 | +| `DeltaSharingScope_Enum.INTERNAL` | model.ts:12 | — | +| `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` | model.ts:17 | 2.1, 15.1 | +| `CreateMetastore` | model.ts:20 | 12.3, 13.3 | +| `CreateMetastore.name` | model.ts:22 | 10.1, 12.6 | +| `CreateMetastore.storageRoot` | model.ts:24 | 6.2 | +| `CreateMetastore.defaultDataAccessConfigId` | model.ts:26 | 6.4, 16.3 | +| `CreateMetastore.storageRootCredentialId` | model.ts:28 | 16.4 | +| `CreateMetastore.deltaSharingScope` | model.ts:30 | 17.1 | +| `CreateMetastore.deltaSharingRecipientTokenLifetimeInSeconds` | model.ts:32 | 7.1 | +| `CreateMetastore.deltaSharingOrganizationName` | model.ts:34 | 7.2 | +| `CreateMetastore.owner` | model.ts:36 | 1.5, 16.7 | +| `CreateMetastore.region` | model.ts:40 | 1.6, 6.6 | +| `CreateMetastore.metastoreId` (read-only on Create) | model.ts:42 | 13.3, 16.1, 17.2 | +| `CreateMetastore.createdAt` (read-only on Create) | model.ts:44 | 13.3, 16.5 | +| `CreateMetastore.createdBy` (read-only on Create) | model.ts:46 | 13.3, 16.7 | +| `CreateMetastore.updatedAt` (read-only on Create) | model.ts:48 | 13.3, 16.5 | +| `CreateMetastore.updatedBy` (read-only on Create) | model.ts:50 | 13.3, 16.7 | +| `CreateMetastore.storageRootCredentialName` (read-only) | model.ts:52 | 13.3 | +| `CreateMetastore.cloud` | model.ts:54 | 1.4, 6.5 | +| `CreateMetastore.globalMetastoreId` (read-only) | model.ts:56 | 6.3, 13.3, 16.6 | +| `CreateMetastore.externalAccessEnabled` | model.ts:58 | 3.1 (doc) | +| `CreateMetastoreAssignment` | model.ts:61 | 12.4 | +| `CreateMetastoreAssignment.workspaceId` | model.ts:63 | 16.2, I | +| `CreateMetastoreAssignment.metastoreId` | model.ts:65 | 16.1 | +| `CreateMetastoreAssignment.defaultCatalogName` | model.ts:71 | — | +| `CreateMetastoreAssignment_Response` | model.ts:75 | 4.2, 11.2 | +| `DeleteMetastore` | model.ts:77 | — | +| `DeleteMetastore.id` | model.ts:79 | 1.1, 5.1, 10.2, 12.5 | +| `DeleteMetastore.force` | model.ts:81 | 1.3 | +| `DeleteMetastore_Response` | model.ts:85 | 4.3, 11.2 | +| `DeleteMetastoreAssignment` | model.ts:87 | 12.4 | +| `DeleteMetastoreAssignment.workspaceId` | model.ts:89 | 16.2 | +| `DeleteMetastoreAssignment.metastoreId` | model.ts:91 | 16.1, D | +| `DeleteMetastoreAssignment_Response` | model.ts:95 | 4.4, 11.2 | +| `DeltaSharingScope` | model.ts:98 | 12.1, H | +| `GetCurrentMetastoreAssignment` | model.ts:101 | — | +| `GetMetastore` | model.ts:103 | — | +| `GetMetastore.id` | model.ts:105 | 1.1, 5.1, 10.2, 12.5 | +| `GetMetastoreSummary` | model.ts:109 | — | +| `GetMetastoreSummary_Response` | model.ts:112 | 4.5, 6.7, 12.2, 13.4 | +| `ListMetastores` | model.ts:153 | — | +| `ListMetastores.maxResults` | model.ts:163 | — | +| `ListMetastores.pageToken` | model.ts:165 | — | +| `ListMetastores_Response` | model.ts:169 | 4.6, 11.2 | +| `ListMetastores_Response.metastores` | model.ts:171 | 9.2 (positive) | +| `ListMetastores_Response.nextPageToken` | model.ts:176 | — | +| `MetastoreAssignment` | model.ts:179 | 1.2, 8.4, 12.4 | +| `MetastoreAssignment.workspaceId` | model.ts:181 | 1.2, 16.2, I | +| `MetastoreAssignment.metastoreId` | model.ts:183 | 16.1, 17.4 | +| `MetastoreAssignment.defaultCatalogName` | model.ts:188 | — | +| `MetastoreInfo` | model.ts:191 | 6.1, 8.1, 12.3, 11.4 | +| `MetastoreInfo.metastoreId` | model.ts:213 | 16.1, 17.2 | +| `MetastoreInfo.globalMetastoreId` | model.ts:227 | 6.3, 16.6 | +| `UpdateMetastore` | model.ts:232 | 12.3, 13.1, 13.3 | +| `UpdateMetastore.id` | model.ts:234 | 1.1, 5.1, 13.1, 13.2 | +| `UpdateMetastore.newName` | model.ts:236 | 12.7, 13.1 | +| `UpdateMetastore.name` | model.ts:238 | 12.7, 13.1 | +| `UpdateMetastore.metastoreId` | model.ts:258 | 13.1, 13.2 | +| `UpdateMetastoreAssignment` | model.ts:277 | 12.4 | +| `UpdateMetastoreAssignment.workspaceId` | model.ts:279 | 16.2 | +| `UpdateMetastoreAssignment_Response` | model.ts:291 | 4.7, 11.2 | +| `unmarshalCreateMetastoreAssignment_ResponseSchema` | model.ts:294 | 4.8, 7.3 | +| `unmarshalDeleteMetastore_ResponseSchema` | model.ts:298 | 4.8 | +| `unmarshalDeleteMetastoreAssignment_ResponseSchema` | model.ts:302 | 4.8 | +| `unmarshalGetMetastoreSummary_ResponseSchema` | model.ts:306 | 4.8 | +| `unmarshalListMetastores_ResponseSchema` | model.ts:353 | 4.8 | +| `unmarshalMetastoreAssignmentSchema` | model.ts:366 | 17.3 | +| `unmarshalMetastoreInfoSchema` | model.ts:379 | 17.3 | +| `unmarshalUpdateMetastoreAssignment_ResponseSchema` | model.ts:425 | 4.8 | +| `marshalCreateMetastoreSchema` (untyped) | model.ts:428 | E | +| `marshalCreateMetastoreAssignmentSchema` (untyped) | model.ts:473 | E | +| `marshalUpdateMetastoreSchema` (untyped) | model.ts:485 | E | +| `marshalUpdateMetastoreAssignmentSchema` (untyped) | model.ts:534 | E | +| `Client` (bare name) | client.ts:61 | 11.6 | +| `Client.createMetastore` | client.ts:92 | — | +| `Client.createMetastoreAssignment` | client.ts:122 | — | +| `Client.deleteMetastore` | client.ts:151 | C | +| `Client.deleteMetastoreAssignment` | client.ts:182 | B, D | +| `Client.getCurrentMetastoreAssignment` | client.ts:216 | 14.1 | +| `Client.getMetastore` | client.ts:241 | 14.1, C | +| `Client.getMetastoreSummary` | client.ts:269 | 6.8, 14.1 | +| `Client.listMetastores` | client.ts:305 | — | +| `Client.listMetastoresIter` | client.ts:338 | 9.1, 14.3 | +| `Client.updateMetastore` | client.ts:360 | C | +| `Client.updateMetastoreAssignment` | client.ts:390 | B | +| `req` / `resp` parameter and locals | client.ts (many) | 5.2, 5.3, 11.3 | +| `pkgJson` import alias | client.ts:19 | 5.4 | +| `${req.id ?? ''}` URL substitution | client.ts:155, 245, 364 | C | +| `${req.workspaceId ?? ''}` URL substitution | client.ts:126, 186, 394 | B | +| `Host is required.` bare Error | client.ts:72 | F | +| `flattenQueryParams` (unused export) | utils.ts:123 | A | +| `marshal…` / `unmarshal…` verbs | model.ts (many) | 11.5 | +| `…Schema` suffix | model.ts (many) | 8.3, 17.3 | +| `index.ts` re-exports underscored names | index.ts:5, 9, 12, 14, 17, 19, 21, 26 | G | +| `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` | index.ts:5, 15 | H | + +--- + +## Recommended priority order + +1. **Disambiguate the four name/id-like fields on `UpdateMetastore`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§13.1, §12.7, §1.1) +2. **Drop the `_Enum` suffix from `DeltaSharingScope_Enum` and rename the sibling `DeltaSharingScope` export to resolve the naming collision.** (§12.1, §4.1, §17.1, §H) +3. **Drop proto-style `_Response` identifiers** (`CreateMetastoreAssignment_Response`, `DeleteMetastore_Response`, `DeleteMetastoreAssignment_Response`, `GetMetastoreSummary_Response`, `ListMetastores_Response`, `UpdateMetastoreAssignment_Response`). (§4.2-4.7) +4. **Strip read-only fields from `CreateMetastore` / `UpdateMetastore`.** (§13.3, §12.3) +5. **Decide whether `GetMetastoreSummary_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§6.7, §12.2) +6. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§6.8, §14.1) +7. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §12.5) +8. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) +9. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match the precedent set by `deltaSharingRecipientTokenLifetimeInSeconds`. (§16.5) +10. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md new file mode 100644 index 00000000..172b6f20 --- /dev/null +++ b/.agent/naming-audit/modelregistry.md @@ -0,0 +1,814 @@ +# Naming Audit: modelregistry + +**Path:** `packages/modelregistry/src/v1/` +**Versions audited:** v1 +**Inferred domain:** MLflow Model Registry (workspace-scoped, "classic" +MLflow). Registers ML models, model versions, stage transitions (None / +Staging / Production / Archived), transition-approval workflow, comments, +tags, latest-version lookups, registry webhooks, and Databricks-specific +permission/ACL extensions. Distinct from `registeredmodels` package which +is the Unity-Catalog-scoped successor. +**Total weird names flagged:** 65 + +## Summary +| Severity | Count | +| --- | --- | +| High | 21 | +| Medium | 24 | +| Low | 14 | +| Observation | 6 | + +## High severity + +### 1. Package name `modelregistry` — `package.json`, `src/v1/` +- **Why weird:** The directory/package name collapses "model registry" + into one word with no separator, while every other multi-word package + in the SDK keeps the same convention (`registeredmodels`, + `cleanrooms`). The deeper issue is that two packages now exist for the + same product area: `modelregistry` (workspace MLflow) and + `registeredmodels` (Unity Catalog). A user reading the package list + cannot tell which one is which. +- **Category:** 1 (vague), 6 (misleading vs sibling package), 12 + (duplicate concept). +- **Suggested name:** `mlflowmodels` or `workspacemlflow` for this + package, leaving `registeredmodels` as the UC equivalent. Even better: + prefix both with their scope (`mlflowregistry` and `ucmodelregistry`). +- **Rationale:** "modelregistry" reads as the canonical name but is + actually the legacy workspace-scoped surface; UC's `registeredmodels` + is the strategic future. Today's name suggests the opposite. + +### 2. `ActivityAction` enum and `availableActions` field — `model.ts:20-31, 187` +- **Why weird:** `ActivityAction` enum values are full verbs like + `APPROVE_TRANSITION_REQUEST`, `CANCEL_TRANSITION_REQUEST`, + `EDIT_COMMENT`, `DELETE_COMMENT`. The field on `Activity` is named + `availableActions: ActivityAction[]`. So the *type* is "actions" but + the values look like RPC method names. Worse, the enum mixes two + unrelated domains (transition-request lifecycle + comment editing) into + one type, and the docstring says so explicitly ("For activities…For + comments…"). +- **Category:** 6 (misleading: enum members are RPC verbs not actions), + 17 (mixed-domain enum), 18 (long enum values). +- **Suggested name:** Split into two enums: `TransitionRequestAction` ( + `Approve | Reject | Cancel`) and `CommentAction` (`Edit | Delete`). Or + shorten to verbs only: `ActivityAction.Approve | Reject | Cancel | Edit + | Delete`. +- **Rationale:** A single enum forced to cover two domains becomes a + bag-of-strings. Users typing `ActivityAction.` get suggested + values that may be illegal for their actual context. + +### 3. `ActivityType` enum — `model.ts:47-62` +- **Why weird:** Values use past-tense verbs (`APPLIED_TRANSITION`, + `REQUESTED_TRANSITION`, `CANCELLED_REQUEST`, `APPROVED_REQUEST`, + `REJECTED_REQUEST`, `NEW_COMMENT`, `SYSTEM_TRANSITION`). The "_REQUEST" + suffix is inconsistent with the "_TRANSITION" suffix — `APPROVED_REQUEST` + is past-tense ("a request was approved"), while + `APPLIED_TRANSITION` is past-tense ("a transition was applied"). What is + `NEW_COMMENT`? It is a noun, not a past-tense verb like its peers. And + `SYSTEM_TRANSITION` is a transition performed by the system, mixing + actor + action where every other value is just an action. +- **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action + verbs), 18 (long enum values). +- **Suggested name:** Pick one pattern. Either all past-tense + (`TransitionApplied`, `TransitionRequested`, `RequestCancelled`, + `RequestApproved`, `RequestRejected`, `CommentPosted`, + `SystemTransitionApplied`), or simple nouns (`Apply`, `Request`, + `Cancel`, `Approve`, `Reject`, `Comment`, `SystemTransition`). +- **Rationale:** Mixed tense and grammatical category in one enum makes + it hard to remember which value to use without looking it up. + +### 4. `PermissionLevel` enum values — `model.ts:82-95` +- **Why weird:** Values include `CAN_MANAGE_STAGING_VERSIONS`, + `CAN_MANAGE_PRODUCTION_VERSIONS`, `CAN_CREATE_REGISTERED_MODEL`. These + hard-code two MLflow stages (Staging, Production) into the permission + enum, but the stage list itself is open-ended (None, Staging, + Production, Archived). There is no `CAN_MANAGE_ARCHIVED_VERSIONS`. + Also, the doc-comment for `CAN_EDIT` says it is `reserved 1; // + IS_OWNER = 1; was DEPRECATED` — that is a Protobuf reservation comment + leaking into TypeScript public docs. +- **Category:** 6 (misleading: implies parallel constants exist), 18 + (long values), 14 (proto-style leakage in JSDoc). +- **Suggested name:** Leave values as-is for wire compatibility, but + strip the protobuf "reserved 1" comment from the public doc. +- **Rationale:** The proto comment serves no purpose to TS users and + hints that the enum will break if reused. + +### 5. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` +- **Why weird:** Enum name says `Type` but values are *states* + (`ALL_EVENTS`, `DEFAULT`, `SUBSCRIBED`, `UNSUBSCRIBED`). `DEFAULT` and + `ALL_EVENTS` overlap in meaning. The class doc-comment marks it + Experimental. Also `Type` is a vague suffix. +- **Category:** 1 (vague `Type` suffix), 6 (misleading: not a "type", + is a state). +- **Suggested name:** `RegistryEmailSubscriptionStatus` (matching the + field name `emailSubscriptionStatus` on `ModelVersionDatabricks`). +- **Rationale:** The field consuming the enum is already called + `emailSubscriptionStatus`; the enum should match. + +### 6. `RegistryWebhookEvent` enum — `model.ts:113-126` +- **Why weird:** Contains both generic + `MODEL_VERSION_TRANSITIONED_STAGE` *and* three specific + `MODEL_VERSION_TRANSITIONED_TO_{STAGING,PRODUCTION,ARCHIVED}`. The + values describe the same event at two levels of granularity, so users + must pick one and the docs do not say which. Same pattern for + `TRANSITION_REQUEST_CREATED` vs three + `TRANSITION_REQUEST_TO_{STAGING,PRODUCTION,ARCHIVED}_CREATED`. +- **Category:** 17 (inconsistent action verbs), 18 (long enum values), + 12 (duplicate concepts within one enum). +- **Suggested name:** Either keep the granular ones and drop the + generic, or document the relationship. +- **Rationale:** Overlap creates "two ways to express one intent" — a + classic source of bugs. + +### 7. `Activity` vs `CommentObject` vs `TransitionRequest` — `model.ts:150, 227, 1015` +- **Why weird:** Three interfaces have *identical* shape and *identical* + doc-comment ("For activities, this contains the activity recorded for + the action. For comments, this contains the comment details. For + transition requests, this contains the transition request details."). + They differ only in name. This is a Java/Go habit (one class per + context) where TS would use one type or a discriminated union. +- **Category:** 12 (duplicate concepts), 14 (Go/Java-style naming). +- **Suggested name:** Single `Activity` type used in all three slots, + with the `activityType` enum already discriminating which flavour it + is. Drop `CommentObject` and `TransitionRequest`. +- **Rationale:** All three already have the same field set including + the `activityType` discriminator. The "type per usage site" anti-pattern + forces consumers to choose between identical shapes. + +### 8. `CommentObject` — `model.ts:227` +- **Why weird:** `Object` is the most generic suffix possible in TS + (everything is an object). Combined with the duplicate-shape problem + (#7), this is a textbook bad name. +- **Category:** 1 (vague `Object` suffix), 20 (type-suffix tautology). +- **Suggested name:** `Comment` — or fold into `Activity` per #7. +- **Rationale:** `Object` adds nothing; the type is already a TS object. + +### 9. `*_Response` suffix on dozens of interfaces — `model.ts:217, 280, 307, 322, 375, 402, 413, 423, 434, 443, 453, 464, 491, 509, 525, 537, 548, 590, 638, 653, 853, 866, 890, 917, 943, 962, 973, 1005, 1066, 1081, 1094, 1137` +- **Why weird:** Underscore in TS identifiers (proto-style nested + type). Every declaration carries an `eslint-disable + @typescript-eslint/naming-convention` comment. 33 such offenders in + one file. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/Java + naming style). +- **Suggested name:** Drop the underscore: `ApproveTransitionRequestResponse`, + `CreateCommentResponse`, etc. +- **Rationale:** The underscore exists only to mirror protobuf nested + message names. TypeScript convention rejects it (the lint rule has to + be disabled for every single one), and `Foo_Response` reads as a + private/internal field by JS convention. + +### 10. `GetRegisteredModelDatabricks`, `RegisteredModelDatabricks`, + `TransitionModelVersionStageDatabricks`, `ModelVersionDatabricks` — + `model.ts:542, 549, 690, 758, 981, 1005` +- **Why weird:** `Databricks` as a type suffix. The whole SDK is the + Databricks SDK; everything is "Databricks". The suffix is used to + distinguish workspace-Databricks extensions from upstream MLflow + fields, but that distinction is opaque to anyone who hasn't read the + upstream MLflow spec. +- **Category:** 1 (vague suffix), 6 (misleading: implies non-Databricks + variants exist in this SDK). +- **Suggested name:** Drop `Databricks` suffix; if a workspace-specific + variant is needed, prefix with `Workspace`: `WorkspaceRegisteredModel`, + `WorkspaceModelVersion`. Or fold the extra fields into the base type + and gate by capability. +- **Rationale:** Either the field is supported (then merge) or it isn't + (then split by capability). The current "shadow type per extension" + is a generator artefact, not a user-friendly API. + +### 11. `TransitionModelVersionStageDatabricks` — `model.ts:981` +- **Why weird:** Five-word PascalCase identifier with awkward word + order. Reads as "transition[verb] + model-version-stage[object]-databricks[suffix]". For a TS type, it + should be a noun. Also functions identically to the + `ApproveTransitionRequest` API (transitions a model version's stage) + but uses a totally different naming scheme. +- **Category:** 6 (misleading verb-as-noun), 7 (overly verbose), 17 + (inconsistent action verbs). +- **Suggested name:** `WorkspaceTransitionStageRequest` (request DTO) or + fold into `ApproveTransitionRequest` (the operations are very close). +- **Rationale:** Right now the SDK has `approveTransitionRequest` and + `transitionModelVersionStageDatabricks` as sibling client methods + performing similar workspace operations; the asymmetric names obscure + this. + +### 12. `GetRegisteredModelDatabricks` request DTO — `model.ts:542` +- **Why weird:** Verb-phrase request type name (`GetX`) is OK if used + consistently, but `GetRegisteredModelDatabricks` is the only method + the SDK exposes to fetch a registered model — there is no plain + `GetRegisteredModel`. The `Databricks` suffix dangles in the public + API for a feature that has no non-Databricks counterpart visible. +- **Category:** 6 (misleading), 8 (redundant suffix). +- **Suggested name:** `GetRegisteredModelRequest` (drop `Databricks`). +- **Rationale:** No need for the disambiguation suffix when there's no + sibling. + +### 13. `client.listTransitionsRequest` method vs `ListTransitionRequest` + request type — `client.ts:507, model.ts:645` +- **Why weird:** The method is `listTransitionsRequest` (plural + "Transitions") but the request type is `ListTransitionRequest` + (singular). The doc comment says "Gets a list of all open stage + transition requests" so it's listing *requests* (plural). The method + name should be `listTransitionRequests` (plural "Requests"), and the + request type should be `ListTransitionRequestsRequest`. Right now + none of the four name parts agree. +- **Category:** 9 (singular/plural mismatch), 6 (misleading), 20 + (type suffix tautology if renamed to `ListTransitionRequestsRequest`). +- **Suggested name:** Method `listTransitionRequests`; request type + `ListTransitionRequests`; response type + `ListTransitionRequestsResponse`. +- **Rationale:** The method name in JS conventions describes the + collection being listed; here that's "transition requests", plural. + +### 14. `RegistryWebhook` vs `Webhook` — `model.ts:787` +- **Why weird:** Type is `RegistryWebhook` but client methods, paths, + and request types alternate: `CreateRegistryWebhook`, + `ListRegistryWebhooks`, `UpdateRegistryWebhook`, + `DeleteRegistryWebhook`, `TestRegistryWebhook`. Once you're inside the + modelregistry package, every webhook *is* a registry webhook — the + prefix is redundant. +- **Category:** 8 (redundant suffix/prefix), 7 (overly verbose). +- **Suggested name:** `Webhook`, `CreateWebhook`, `ListWebhooks`, + `UpdateWebhook`, `DeleteWebhook`, `TestWebhook`. +- **Rationale:** Package name already establishes the registry context. + +### 15. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` +- **Why weird:** `Spec` is a vague suffix shared by every config-bag + in the SDK. Two sibling types in the same package, only the `Spec` + suffix distinguishing them. `HttpUrlSpec` is the *target* of a webhook + (URL + auth + TLS settings), `JobSpec` is the *target* of a webhook (job + ID + workspace). They are two implementations of a "webhook + destination", and the naming hides that. +- **Category:** 1 (vague `Spec` suffix), 6 (misleading). +- **Suggested name:** `HttpUrlTarget` / `JobTarget`, or + `WebhookHttpTarget` / `WebhookJobTarget`. +- **Rationale:** The two together discriminate the webhook + destination kind; the naming should make that obvious. + +### 16. `LinkedFeature` — `model.ts:573` +- **Why weird:** Doc comment says "Feature for model version. ([ML-57150] + Renamed from Feature to LinkedFeature)". The ticket number leaks into + the public docstring. Type name was changed for internal reasons + (probably to avoid collision); the rename history doesn't belong in + the public TS surface. +- **Category:** 1 (vague), 6 (misleading: nothing "linked" about a + feature-table-name + feature-name pair). +- **Suggested name:** `ModelFeatureReference` or just `FeatureRef`. +- **Rationale:** "Linked" doesn't describe anything specific to this + type; the fields are just identifiers pointing at a feature in the + feature store. + +### 17. `userId: string` field documented as username — `model.ts:154, + 231, 668, 700, 766, 1018` +- **Why weird:** Field is named `userId` but every doc-comment for it + reads "The username of the user that created the object." So the + field is a *username* (human-readable string), not a user ID + (numeric/UUID). On `ModelVersion` (model.ts:668) it's documented as + "User that created this `model_version`." +- **Category:** 6 (misleading), 16 (field type contradicts name), 19 + (underspecified ID). +- **Suggested name:** `userName` (or `createdBy`). +- **Rationale:** Calling a username `userId` will trip every caller who + tries to use it as an ID for IAM lookups. + +### 18. `stage: string` field on `ApproveTransitionRequest`, + `CreateTransitionRequest`, `DeleteTransitionRequest`, + `RejectTransitionRequest`, `TransitionModelVersionStageDatabricks` — + `model.ts:209, 396, 483, 847, 997` +- **Why weird:** Field is `stage: string` but valid values are + enumerated in the docstring: `None`, `Staging`, `Production`, + `Archived`. There is no `Stage` enum exported anywhere in the model, + so callers have to memorise stringly-typed magic values. Compare to + `status: ModelVersionStatus` (typed) — inconsistent treatment. +- **Category:** 6 (misleading), 16 (field-type contradicts domain). +- **Suggested name:** Introduce `Stage` enum (`None | Staging | + Production | Archived`) and type these fields accordingly. +- **Rationale:** The docstring already lists the four values; promote + to a type. Currently every transition method takes `stage: string` + with no type-level validation. + +### 19. `currentStage: string` field on `ModelVersion`, + `ModelVersionDatabricks` — `model.ts:670, 701` +- **Why weird:** Same as #18 — typed as `string`, valid values + enumerated only in docs. Also called `currentStage` here but `stage` + on request DTOs (no prefix). Inconsistent. +- **Category:** 6 (misleading), 16 (type contradicts domain), 17 + (inconsistent prefix). +- **Suggested name:** `stage: Stage` (enum) for both. +- **Rationale:** "Current" is implicit (it's the *current* stage of + this version). + +### 20. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` +- **Why weird:** Three different `Activity`-shaped types each duplicate + `fromStage: string | undefined`, `toStage: string | undefined`, + again stringly typed. Identical doc-comments paste the same four-value + list six times. +- **Category:** 16 (type contradicts domain), 12 (duplicate concept), 7 + (overly verbose docs). +- **Suggested name:** `fromStage: Stage`, `toStage: Stage`. +- **Rationale:** Same as #18. + +### 21. `Databricks` as a suffix is overused +- **Why weird:** 6 distinct type names end in `Databricks` (see #10). + Each one is a workspace-specific extension. The `Databricks` suffix + appearing inside the *Databricks SDK* is tautological. +- **Category:** 8 (redundant suffix), 20 (type-suffix tautology). +- **Suggested name:** See #10. +- **Rationale:** See #10. + +## Medium severity + +### 22. `comment: string` field overloaded across types — `model.ts:213, 234, 276, 398, 487, 849, 1001, 1022, 1062` +- **Why weird:** Same field name (`comment`) appears with three + different meanings: (a) on `Activity` it is "user-provided comment + associated with the activity"; (b) on `CreateComment` it is "user- + provided comment on the action" (i.e. the *new* comment being + created); (c) on `ApproveTransitionRequest`/`CreateTransitionRequest` + it is the *justification* for the action. Same name, different + semantics. +- **Category:** 15 (generic field name losing meaning). +- **Suggested name:** Disambiguate per type: `body` for the new comment, + `justification` for the approval reason, `comment` for the recorded + activity comment. +- **Rationale:** A grep for `comment` in a calling project will return + 9 unrelated meanings. + +### 23. `creator: string` field on `DeleteTransitionRequest` — `model.ts:485` +- **Why weird:** Field doc says "Username of the user who created this + request." So this is a username, not a user object. Same anti-pattern + as #17 but with a different field name. The same concept is named + `userId` elsewhere. +- **Category:** 17 (inconsistent action/identifier prefix). +- **Suggested name:** `creatorUsername` (and align with `userId` -> + `userName` per #17). +- **Rationale:** Two different field names for the same concept. + +### 24. `id: string` field — `model.ts:189, 266, 408, 461, 772, 789, 967, 1054, 1060` +- **Why weird:** Bare `id` appears on `Activity`, `CommentObject`, + `DeleteComment`, `DeleteRegistryWebhook`, `RegisteredModelDatabricks`, + `RegistryWebhook`, `TestRegistryWebhook`, `TransitionRequest`, + `UpdateComment`. Same name across nine types, but each `id` belongs to + a different domain (activity ID, comment ID, webhook ID, registered + model ID). Doc-comments call it variously "Unique identifier for the + object", "Unique identifier of an activity", "Webhook ID". +- **Category:** 19 (underspecified ID), 15 (generic field name). +- **Suggested name:** `activityId`, `commentId`, `webhookId`, + `registeredModelId`, or scope by parent type. +- **Rationale:** Bare `id` in a request body forces the caller to + remember which kind of ID this DTO wants. The wire field can stay + `id`; the TS field should be specific. + +### 25. `name: string` field overloaded — many — `model.ts:195, 271, 287, 314, 382, 417, 426, 438, 447, 468, 519, 531, 543, 583, 600, 647, 660, 691, 740, 759, 832, 859, 925, 946, 982, 1072, 1087, 1100` +- **Why weird:** `name` appears on ~28 request/response types meaning + "name of the registered model". Doc-comments mostly say "Name of the + model" or "Registered model unique name identifier." Always the + same domain entity but unscoped. +- **Category:** 15 (generic), 19 (underspecified ID — name is the + primary key for registered models). +- **Suggested name:** `modelName` or `registeredModelName` on + request DTOs. Keep `name` on the entity itself (`RegisteredModel`, + `ModelVersion`) since that's the primary field. +- **Rationale:** Disambiguates request structures from entity + structures. + +### 26. `version: string` field overloaded — `model.ts:197, 273, 419, 428, 470, 521, 533, 649, 662, 693, 834, 927, 984, 1074` +- **Why weird:** Stored as a string but docs say "Model version number" + (a number). Field is sometimes called `version`, sometimes + `currentStage` is the contextual sibling — but never typed as a + number. There is no separate type alias for it. +- **Category:** 16 (field type contradicts domain), 15 (generic), 19 + (underspecified ID). +- **Suggested name:** `modelVersion: string` (or branded type + `ModelVersionNumber`). +- **Rationale:** `version` is too generic a noun for a primary key in a + package. + +### 27. `runId: string` field — `model.ts:294, 679, 707` +- **Why weird:** `runId` is the MLflow tracking run that produced the + model. The package never explains this; without prior MLflow + knowledge `runId` is opaque. +- **Category:** 19 (underspecified ID), 1 (vague). +- **Suggested name:** `trackingRunId` or `mlflowRunId`. +- **Rationale:** Disambiguates from any other "run" concept in the + SDK (jobs runs, etc.). + +### 28. `jobId: string` on `JobSpec` — `model.ts:565` +- **Why weird:** Doc says "ID of the job that the webhook runs." This is + a Databricks Jobs job ID. `jobId` is fine but lives in a model that + duplicates the documentation in the comment for `CreateRegistryWebhook.jobSpec` + (model.ts:371 says "ID of the job that the webhook runs.") even though + `jobSpec` is a *struct* not an ID. +- **Category:** 6 (misleading docstring). +- **Suggested name:** Field name OK; fix doc-comment on + `CreateRegistryWebhook.jobSpec`. +- **Rationale:** Doc-comment mismatch is a generator bug. + +### 29. `accessToken: string` on `JobSpec` — `model.ts:569` +- **Why weird:** Doc says "The personal access token used to authorize + webhook's job runs." Shipping a PAT in a webhook config is a security + red flag; field name should signal that. Compare to `secret` on + `HttpUrlSpec` (model.ts:558) which is also a credential but has a + different naming style. +- **Category:** 1 (vague), 17 (inconsistent action verbs/prefix). +- **Suggested name:** `pat` or `personalAccessToken` (matches Databricks + parlance). +- **Rationale:** Aligns with other Databricks SDK fields named `token` + / `pat`. + +### 30. `enableSslVerification: boolean` — `model.ts:556` +- **Why weird:** Doc-comment is 4 lines describing why you should never + disable this. The boolean has a default (true) per the docs but the + field is `boolean | undefined`. So `undefined` and `true` mean the + same thing — confusing. +- **Category:** 16 (semantics not captured in type). +- **Suggested name:** Field name OK; add `@default true` JSDoc tag. +- **Rationale:** Make default-truthy fields clearer. + +### 31. `authorization: string` — `model.ts:560` +- **Why weird:** "Value of the authorization header" — should probably + be named `authorizationHeader` (since `authorization` looks like an + abstract noun, not the actual header value). +- **Category:** 1 (vague). +- **Suggested name:** `authorizationHeader`. +- **Rationale:** Clarifies the field stores the wire-format header + value. + +### 32. `event: RegistryWebhookEvent | undefined` (singular) on + `TestRegistryWebhook` — `model.ts:969` +- **Why weird:** Singular `event` while every other type uses + `events: RegistryWebhookEvent[]`. Inconsistent. +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent across + sibling types). +- **Suggested name:** Could keep singular but rename to + `triggerEvent` for clarity, *or* accept the single-event semantics + with `event` and document the asymmetry. +- **Rationale:** Asymmetry across sibling types causes refactor errors. + +### 33. `modelName: string` field on `CreateRegistryWebhook`, + `ListRegistryWebhooks`, `RegistryWebhook` — `model.ts:329, 601, 827` +- **Why weird:** This is the *registered model* name. Elsewhere in the + same model the same concept is called `name` (on requests scoped to a + registered model). Sometimes `modelName` (on webhook types) and + sometimes just `name`. Pick one. +- **Category:** 17 (inconsistent across sibling types). +- **Suggested name:** `modelName` everywhere (it's clearer) or `name` + with package context — but consistent. +- **Rationale:** Same concept, two names. + +### 34. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, + 602-630, 791-815, 1102-1127` +- **Why weird:** The 25-line "Events that can trigger a registry + webhook" doc block is copy-pasted at least 4 times across types + that all expose `events: RegistryWebhookEvent[]`. Pure generator + noise polluting the public docs. +- **Category:** 7 (overly verbose), Observation. +- **Suggested name:** Doc generation should DRY this; only the field + signature plus a one-line description should remain. +- **Rationale:** Quality-of-life for consumers reading JSDoc. + +### 35. `tags?: ModelVersionTag[] | undefined` and + `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, + 719, 755, 776` +- **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, + `RegisteredModelTag`) that both have `{ key: string; value: string }`. + Identical shape, two names. (Compare with Unity Catalog tags in + `entitytagassignments` which use one type.) +- **Category:** 12 (duplicate concepts). +- **Suggested name:** Single `Tag` type with `{ key, value }`. +- **Rationale:** Identical structure should have identical type. + +### 36. `availableActions: ActivityAction[]` doc — `model.ts:187` +- **Why weird:** Field comment "Array of actions on the activity + allowed for the current viewer." So `availableActions` actually means + "allowed actions for current viewer", which differs from "available + in general". The viewer-dependent semantics are not in the field name. +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `allowedActions` or `permittedActions`. +- **Rationale:** Encodes the viewer-permission semantics. + +### 37. `systemComment: string | undefined` — `model.ts:185, 262, 1050` +- **Why weird:** The same paragraph-long doc-comment is pasted on three + identical fields across three identical types. "Comment made by + system, for example explaining an activity of type + `SYSTEM_TRANSITION`." +- **Category:** 12 (duplicate concept across types), 7 (verbose). +- **Suggested name:** Field name OK; field is also a candidate for + consolidation via #7. +- **Rationale:** Same as #7. + +### 38. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` +- **Why weird:** Typed as `Activity[]` but the field is documented as + "Open requests for this `model_versions`" — they are transition + *requests* (not arbitrary activities). The reason is the + identical-shape problem (#7). +- **Category:** 6 (misleading type), 16 (type contradicts domain). +- **Suggested name:** `openTransitionRequests: TransitionRequest[]` + (post-rename per #7). +- **Rationale:** Restores the intent. + +### 39. `requests: Activity[]` on `ListTransitionRequest_Response` — + `model.ts:655` +- **Why weird:** Same problem: stored as `Activity[]` but the response + is documented as "Array of open transition requests." +- **Category:** 6 (misleading type), 15 (generic field name). +- **Suggested name:** `transitionRequests: TransitionRequest[]`. +- **Rationale:** Same as #38. + +### 40. `request: TransitionRequest` on `CreateTransitionRequest_Response` — + `model.ts:404` +- **Why weird:** Field `request` on a response is contradictory — a + response holds a "request"? In context, the wrapped object is the + *created* transition request, but the field name doesn't say + "created". +- **Category:** 6 (misleading), 15 (generic). +- **Suggested name:** `transitionRequest` or `createdRequest`. +- **Rationale:** Removes the "request inside a response" cognitive + stumble. + +### 41. `registeredModelDatabricks: RegisteredModelDatabricks` — + `model.ts:549` +- **Why weird:** Field name *is* the type name verbatim. The `Databricks` + suffix problem (#10) cascades into the field name. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** After dropping the `Databricks` suffix from the + type: `registeredModel: RegisteredModel`. Or just return the type + directly without a wrapper. +- **Rationale:** Reduces verbosity by removing the wrapper. + +### 42. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` +- **Why weird:** Same as #41 for `ModelVersionDatabricks`. +- **Category:** 20. +- **Suggested name:** `modelVersion: ModelVersion`. +- **Rationale:** Same. + +### 43. `getLatestVersions` / `GetLatestVersions` — `client.ts:908`, + `model.ts:501` +- **Why weird:** The method returns *one* version per stage, not "the + latest version" globally. The name reads as "give me the latest + versions" (plural overall) but the meaning is "give me the latest one + for each stage". The docstring on the method (`client.ts:907`) says + "Gets the latest version of a registered model" (singular) — that's + *wrong*; the actual response returns a list keyed by stage. +- **Category:** 6 (misleading), 9 (singular/plural confusion). +- **Suggested name:** `getLatestVersionPerStage` or + `getLatestVersionsByStage`. +- **Rationale:** Conveys the per-stage semantics. + +### 44. `latestVersions: ModelVersion[]` on `RegisteredModel`, + `RegisteredModelDatabricks` — `model.ts:753, 770` +- **Why weird:** Plural array but the doc says "Collection of latest + model versions for each stage". Same ambiguity as #43. +- **Category:** 6 (misleading), 15 (generic). +- **Suggested name:** `latestVersionsByStage` (and consider returning a + map keyed by stage name). +- **Rationale:** Same. + +### 45. `featureTableId`, `featureTableName`, `featureName` on + `LinkedFeature` — `model.ts:575, 577, 579` +- **Why weird:** Both `featureTableId` and `featureTableName` are + exposed — primary key duplication. Doc-comments are bare ("Feature + table id" / "Feature table name") and don't explain why both are + present. +- **Category:** 12 (duplicate concept), 19 (underspecified ID). +- **Suggested name:** Field names OK; add JSDoc explaining the + relationship. +- **Rationale:** Without docs, callers won't know which to populate. + +### 46. `body: string` on `TestRegistryWebhook_Response` — `model.ts:977` +- **Why weird:** Field `body` typed as `string`. Webhook test results + could return any payload. `body` is too generic; could be + `responseBody`. +- **Category:** 15 (generic). +- **Suggested name:** `responseBody`. +- **Rationale:** Clearer pair with `statusCode`. + +### 47. `statusCode: number` on `TestRegistryWebhook_Response` — + `model.ts:975` +- **Why weird:** Could be `httpStatusCode` for clarity (it's the HTTP + status the test got back). +- **Category:** 1 (vague). +- **Suggested name:** `httpStatusCode`. +- **Rationale:** Matches typical Web API vocabulary. + +### 48. `archiveExistingVersions: boolean` — `model.ts:211, 999` +- **Why weird:** Field documented "Specifies whether to archive all + current model versions in the target stage." The word "current" + appears in the doc but not the field; the boolean reads as "archive + the existing versions" which is ambiguous (which existing? where?). +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `archiveExistingVersionsInTargetStage`. +- **Rationale:** Captures the location semantics. + +### 49. `description: string` overloaded — `model.ts:302, 318, 358, 672, + 703, 748, 768, 822, 1077, 1090, 1129` +- **Why weird:** Same field on 11 types, each meaning slightly different + things (registered-model description, model-version description, + webhook description, registered-model-databricks description). Same + field name everywhere. +- **Category:** 15 (generic field name). +- **Suggested name:** Acceptable as `description` if doc-comments are + clear; flag for consistency. +- **Rationale:** Common across SDK; low cost to leave alone. + +### 50. `secret: string` on `HttpUrlSpec` — `model.ts:558` +- **Why weird:** Bare `secret` is generic; doc says it's the "Shared + secret required for HMAC encoding payload." +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `hmacSecret` or `sharedSecret`. +- **Rationale:** Clarifies purpose. + +## Low severity + +### 51. `creationTimestamp: number` — `model.ts:152, 229, 664, 696, 742, + 761, 818, 1017` +- **Why weird:** Field is repeated across types with identical + `Unix timestamp in milliseconds` doc. Naming OK but could be + `createdAt` to match modern JS convention. +- **Category:** 14 (Go/Java-style names). +- **Suggested name:** `createdAt`. +- **Rationale:** Aligns with JS conventions; flag as observation only. + +### 52. `lastUpdatedTimestamp: number` — `model.ts:159, 236, 666, 698, 744, + 763, 820, 1024` +- **Why weird:** Same as #51; `updatedAt` is more idiomatic. +- **Category:** 14. +- **Suggested name:** `updatedAt`. +- **Rationale:** Same as #51. + +### 53. `statusMessage: string` — `model.ts:683, 710` +- **Why weird:** Field name fine but doc says it's only set "if it is + pending or failed", so the field is conditionally meaningful — not in + the type signature. +- **Category:** 6 (misleading: optional semantics not in type). +- **Suggested name:** Field name OK; document the conditional. +- **Rationale:** Low priority. + +### 54. `source: string` on `ModelVersion`, `ModelVersionDatabricks`, + `CreateModelVersion` — `model.ts:289, 674, 704` +- **Why weird:** "URI indicating the location of the source model + artifacts." Just `source` is vague; `sourceUri` or `artifactUri` would + be clearer. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `sourceUri`. +- **Rationale:** Companion field is `runLink` (already specific). + +### 55. `runLink: string` — `model.ts:301, 687, 720` +- **Why weird:** "MLflow run link - this is the exact link of the run". + `runLink` is OK but `runUrl` would be more idiomatic for a URL. +- **Category:** 14 (Java-style "link" vs JS "url"). +- **Suggested name:** `runUrl`. +- **Rationale:** "Link" is HTML/UI vocabulary; URL is what's actually + stored. + +### 56. `key: string` and `value: string` on `ModelVersionTag`, + `RegisteredModelTag` — `model.ts:733, 735, 782, 784` +- **Why weird:** `key`/`value` are extremely generic and reused across + many SDK packages. Not really wrong, just observation. +- **Category:** 15 (generic). +- **Suggested name:** `tagKey`, `tagValue` (if a type-named field is + preferred). +- **Rationale:** Trade-off vs verbosity. Low priority. + +### 57. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:586, 593, + 633, 642, 877, 893, 905, 921` +- **Why weird:** Consistent across the package — good. Noted for + completeness. +- **Category:** N/A (consistent). +- **Suggested name:** No change. +- **Rationale:** Observation. + +### 58. `orderBy: string[]` on `SearchModelVersions`, + `SearchRegisteredModels` — `model.ts:884, 911` +- **Why weird:** Stringly-typed sort spec; doc says values are like + `"name DESC"` or `"version ASC"`. Could be a typed `Sort` struct, but + string is the standard SQL-like sort spec. +- **Category:** 16 (type contradicts domain). +- **Suggested name:** Field name OK; flag the stringly-typed pattern. +- **Rationale:** Matches REST API conventions; low cost. + +### 59. `filter: string` on `SearchModelVersions`, + `SearchRegisteredModels` — `model.ts:875, 903` +- **Why weird:** Stringly-typed search filter (SQL-like). Same as #58. +- **Category:** 16. +- **Suggested name:** No change; could be `filterExpression`. +- **Rationale:** REST convention. + +### 60. `newName: string` on `RenameRegisteredModel` — `model.ts:862` +- **Why weird:** Field doc says "If provided, updates the name for this + `registered_model`." Slightly confusing because `RenameRegisteredModel` + is *the* rename operation — "if provided" implies optional, but rename + without a new name is meaningless. +- **Category:** 6 (misleading semantics). +- **Suggested name:** Make it required (drop `?`), or document that + omission is a no-op. +- **Rationale:** Optional-but-required-in-practice fields confuse users. + +### 61. `name: string` on `RenameRegisteredModel` — `model.ts:859` +- **Why weird:** Field doc "Registered model unique name identifier." - + duplicates the type name semantics. Could be `currentName` to pair with + `newName` for clarity. +- **Category:** 17 (inconsistent paired-field naming). +- **Suggested name:** `currentName` + `newName`. +- **Rationale:** Symmetry improves readability of rename payloads. + +### 62. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhook` — + `model.ts:369-371` +- **Why weird:** Doc-comment on `jobSpec` (line 371) is literally just + "ID of the job that the webhook runs." — wrong, since `jobSpec` is a + struct holding multiple fields, not an ID. +- **Category:** 6 (misleading docstring). +- **Suggested name:** Field name OK; fix doc-comment. +- **Rationale:** Generator bug; users will read the doc. + +### 63. `unmarshalActivitySchema`, `unmarshalCommentObjectSchema`, + `unmarshalTransitionRequestSchema` — `model.ts:1141, 1177, 1664` +- **Why weird:** Three near-identical Zod schemas for three identical + types (#7). +- **Category:** 12 (duplicate concept). +- **Suggested name:** Single `unmarshalActivitySchema` once #7 collapses + the types. +- **Rationale:** Mechanical cascade from #7. + +### 64. `marshalRegisteredModelTagSchema` / + `marshalModelVersionTagSchema` — `model.ts:1856, 1866` +- **Why weird:** Two schemas for two identical-shape types (#35). +- **Category:** 12 (duplicate concept). +- **Suggested name:** Single `marshalTagSchema` once #35 collapses. +- **Rationale:** Mechanical cascade from #35. + +## Observations + +### 65. Wire/TS divergence is massive +The model file is ~2000 lines for ~33 user-facing types. ~870 lines are +type declarations, ~860 lines are unmarshal schemas, ~270 lines are +marshal schemas. Plus 33 `*_Response` types with `eslint-disable` lints. +This is the highest disable-count-per-type density I've seen — a sign +the generator's Go/proto idioms are fighting TS conventions throughout. +- **Category:** Observation. + +### 66. Both `modelregistry` and `registeredmodels` exist as packages +The user instruction calls out this duplication. Cross-package overlap: +- `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` + (registeredmodels) — same concept, different names. +- `ModelVersion` (modelregistry) vs `ModelVersionInfo` + (registeredmodels) — same concept. +- `CreateRegisteredModel` exists in both packages, with different + fields. +- `DeleteRegisteredModel` exists in both. +- `ModelVersionStatus` enum exists in both, with different values + (modelregistry has `PENDING_REGISTRATION | FAILED_REGISTRATION | + READY`; verify against registeredmodels). +- Modelregistry uses tags as `RegisteredModelTag` / `ModelVersionTag`; + registeredmodels uses different tag types (verify). +- The two registries cover overlapping but not identical operations. + Documentation does not direct users to one or the other. +- **Category:** 12 (duplicate concepts — across packages). + +### Action-verb conventions in `Client` +The client mixes `Approve` / `Reject` (active verbs for transition- +request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for +webhook health) and `Transition` (verb-as-method-name for state +machine). Consistency-wise the surface is jagged but each verb is +reasonably motivated by the underlying state model. Not a defect, but +worth noting. +- **Category:** 17 (mixed but justified). + +### `flattenQueryParams` (`utils.ts:123`) is unused in this package +Same observation as in other audits: a generator-shipped helper is +exported even though only `marshalRequest` is consumed by the client. +- **Category:** Observation. + +### `parseResponse` / `marshalRequest` verb asymmetry (`utils.ts:113, 119`) +Same generator-level observation: opposite operations use mismatched +verbs (`parse` vs `marshal`). +- **Category:** 17. + +### Acronym casing inside doc-comments +`MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` +(`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type +names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http +and SCREAMING-HTTPS. +- **Category:** 3 (acronym casing — minor). + +## Domain glossary +- `MLflow` — Used throughout. Refers to the open-source MLflow tracking + + registry product that this package wraps. Always written `MLflow`, + never `mlflow` or `Mlflow` (good consistency). +- `Workspace` — Implicit; the entire package is workspace-scoped (vs + Unity Catalog). +- `Stage` — The MLflow stage enum: `None`, `Staging`, `Production`, + `Archived`. Never typed; only documented in field comments. +- `Activity` / `TransitionRequest` / `CommentObject` — Three names for + one shape. +- `Webhook` / `Registry Webhook` — Used interchangeably. +- `Databricks` (as a suffix) — Marker for workspace-extension types + carrying Databricks-specific fields (permissions, ACL paths, etc.). +- `Tag` — Two distinct types (`ModelVersionTag`, `RegisteredModelTag`) + with identical shape. +- `Run` — MLflow tracking run (not Databricks job run). +- `RunLink` — URL pointing back to the MLflow tracking-server run. +- `userId` — Username (not numeric ID) per doc-comments. + +## File coverage +- `src/v1/model.ts` (2000 lines): read fully. +- `src/v1/client.ts` (1323 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (95 lines): read fully. diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md new file mode 100644 index 00000000..d185315b --- /dev/null +++ b/.agent/naming-audit/modelservingdebug.md @@ -0,0 +1,626 @@ +# Naming Audit: modelservingdebug + +**Path:** `packages/modelservingdebug/src/v1/` +**Package name:** `@databricks/sdk-modelservingdebug` +**Versions audited:** v1 +**Inferred domain:** Diagnostic / troubleshooting endpoints carved out of the Model Serving API. Three HTTP GETs hanging off `/api/2.0/serving-endpoints/{name}`: `GET /metrics` returns a Prometheus/OpenMetrics text blob (streamed body), `GET /served-models/{servedModelName}/logs` returns the most recent server stdout lines, and `GET /served-models/{servedModelName}/build-logs` returns the served-entity environment build logs. +**Total weird names flagged:** 32 + +## Summary +| Severity | Count | +| --- | --- | +| High | 9 | +| Medium | 13 | +| Low | 8 | +| Observation | 2 | + +## Inventory + +### Package identity +| Item | Value | +| --------------- | ------------------------------------------------ | +| Package name | `@databricks/sdk-modelservingdebug` | +| Directory | `packages/modelservingdebug/` | +| Subpath export | `./v1` | +| REST base | `/api/2.0/serving-endpoints/...` | +| Sibling pkgs | `modelservingmanagement`, `modelservingquery` | + +### Interfaces (`model.ts`) +- `ExportMetricsResponse` (line 15) +- `GetExportEndpointMetrics` (line 19) +- `GetServedModelBuildLogs` (line 24) +- `GetServedModelBuildLogs_Response` (line 32) +- `GetServedModelLogs` (line 37) +- `GetServedModelLogs_Response` (line 45) + +### Schemas (`model.ts`) +- `unmarshalGetServedModelBuildLogs_ResponseSchema` (line 51) +- `unmarshalGetServedModelLogs_ResponseSchema` (line 61) + +### Enums (`model.ts`) +None. + +### Client class & methods (`client.ts`) +- `Client` (line 39) + - `getExportEndpointMetrics(req: GetExportEndpointMetrics, options?): Promise` (line 65) + - `getServedModelBuildLogs(req: GetServedModelBuildLogs, options?): Promise` (line 92) + - `getServedModelLogs(req: GetServedModelLogs, options?): Promise` (line 120) +- `PACKAGE_SEGMENT` const (line 34) +- Private state: `host`, `httpClient`, `logger`, `userAgent`. + +### Utility surface (`utils.ts`) +- `HttpCallOptions` interface +- `executeCall`, `readAll` (private), `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`, `sendAndCheckError`. + +### Re-exports (`index.ts`) +- `Client` +- `ExportMetricsResponse`, `GetExportEndpointMetrics`, + `GetServedModelBuildLogs`, `GetServedModelBuildLogs_Response`, + `GetServedModelLogs`, `GetServedModelLogs_Response`. + +--- + +## F0 — Package-level: `debug` is the wrong qualifier for these three operations + +This is the single highest-leverage finding and informs every renaming +suggestion below. + +### F0.1 — Package name `modelservingdebug` is misleading (HIGH) +- **Where:** `package.json:2` (`@databricks/sdk-modelservingdebug`), + directory `packages/modelservingdebug/`, and the `.package.json` + declarator at line 2. +- **Why weird:** The word "debug" in software engineering almost + universally means *interactive* debugging: breakpoints, attach-to-process, + reading variables in a paused state (cf. Node's `--inspect`, Chrome + DevTools, gdb). Nothing in this package does that. All three methods + are read-only retrieval of *observability* artefacts: + - `GET /metrics` — Prometheus/OpenMetrics text feed. + - `GET /logs` — service stdout/stderr lines from the model server. + - `GET /build-logs` — container/environment build output. + The CNCF Observability Whitepaper + (https://github.com/cncf/tag-observability/blob/main/whitepaper.md) + defines the three pillars as metrics, logs, and traces; this package + delivers two of them. The natural label is "observability" or + "telemetry", not "debug". +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `modelservingtelemetry`, `modelservingobservability`, + or — best — fold these three methods back into `modelservingmanagement` + as `getEndpointMetrics`, `getServedModelLogs`, `getServedModelBuildLogs`. + The split into a separate package buys nothing because the same + `name` (serving endpoint) keys both packages and a real consumer + always wants both surfaces. +- **Rationale:** Package names are the single hardest naming choice to + reverse — they appear in every consumer's `package.json`, `import` and + lockfile. Today an autocomplete on `import {Client} from + '@databricks/sdk-modelservingdebug'` suggests an interactive debugger + which is not what this package offers. + +### F0.2 — Three-way split `modelserving{debug,management,query}` has no consistent rationale (MEDIUM, cross-package) +- **Where:** `packages/modelservingdebug/`, + `packages/modelservingmanagement/`, + `packages/modelservingquery/`. +- **Why weird:** The split mixes axes: + - `modelservingmanagement` = control plane (create/update/delete + endpoints, configure AI gateway). + - `modelservingquery` = data plane invoke (chat/embeddings/completion). + - `modelservingdebug` = *also* control-plane reads (metrics & logs) + on the same `/api/2.0/serving-endpoints/{name}/...` URL tree. + All three live under the same REST prefix. `modelservingdebug.Client` + even reuses `req.name` to identify the endpoint — exactly the same key + `modelservingmanagement.Client.getInferenceEndpoint` uses. The boundary + between "management" and "debug" is API-team housekeeping, not user-facing. +- **Category:** 12 (duplicate concepts across packages). +- **Suggested name:** Merge `modelservingdebug` into `modelservingmanagement`. + Keep `modelservingquery` separate because it is data-plane (different + auth, different rate-limit semantics, often a separate host). +- **Rationale:** Users always want the metrics and logs alongside the + endpoint they manage. Forcing a second `import` and a second `Client` + constructor just to read `/metrics` is friction for zero benefit. + +### F0.3 — Directory and `.package.json` declarator drift from npm name (LOW) +- **Where:** `.package.json:2` says `"package": "modelservingdebug"` + but `package.json:2` says `"name": "@databricks/sdk-modelservingdebug"`. +- **Why weird:** Two sources of truth for the package identity. The + internal declarator uses one form, the npm manifest uses another. + The `PACKAGE_SEGMENT` regex strip in `client.ts:34-37` exists solely + to bridge the two. +- **Category:** 17 (inconsistent action verbs / forms). +- **Suggested name:** Pick one form. Recommend dropping `.package.json` + if it is generator-only metadata that the build does not need. +- **Rationale:** Two-name systems eventually drift; the regex strip is + evidence of that drift already. + +--- + +## High severity + +### 1. `Client` class name is unqualified — `client.ts:39`, `index.ts:3` +- **Why weird:** Every package in this SDK exports `Client`. A consumer + who uses `modelservingdebug` *and* `modelservingmanagement` *and* + `modelservingquery` ends up writing + `import {Client as DebugClient} from '@databricks/sdk-modelservingdebug'; + import {Client as MgmtClient} from '@databricks/sdk-modelservingmanagement'; + import {Client as QueryClient} from '@databricks/sdk-modelservingquery';` + every time. Three-way collision is the *expected* case here, not an + edge case. +- **Category:** 1 (vague/generic), 12 (duplicate across packages). +- **Suggested name:** `ModelServingDebugClient` (or + `ModelServingObservabilityClient` if F0.1 is adopted). Or, better, + collapse to a single `ModelServingClient` per F0.2. +- **Rationale:** Pkg-prefixed client class names are the established + pattern across the Databricks Java SDK (`ServingEndpointsAPI`), + Go SDK (`ServingEndpointsAPI`), and Python SDK (`ServingEndpointsAPI`). + TS is the odd one out for stopping at `Client`. + +### 2. `GetExportEndpointMetrics` reads as "get export of endpoint metrics" — `model.ts:19`, `client.ts:65` +- **Why weird:** The grammar is broken. The expected reading is + *"export endpoint metrics" → returns metrics in export format*, but + the word order `Get + Export + Endpoint + Metrics` parses as four + random nouns. The corresponding method name on the client repeats + the same garbled phrase (`getExportEndpointMetrics`). The doc string + on `client.ts:64` confirms the intent: "Retrieves the metrics + associated with the provided serving endpoint in either Prometheus + or OpenMetrics exposition format". The natural English noun phrase + is "export endpoint metrics" → action "export the endpoint's metrics" + → method `exportEndpointMetrics` (verb-first, no `Get`). +- **Category:** 6 (misleading), 7 (overly verbose), 17 (inconsistent + verb — every other method is `getX`, this one is `getExportX`). +- **Suggested name:** Drop `Get` and `Export` from the request, keep + one or the other: + - Method: `exportEndpointMetrics(req: ExportEndpointMetricsRequest)` + returning `EndpointMetrics` (or the existing `ExportMetricsResponse`). + - Or: `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning + `EndpointMetrics`. The "export" framing is a wire-protocol detail + (Prometheus format) that does not belong in the method name. +- **Rationale:** Compare with sibling endpoints in + `modelservingmanagement`: `getInferenceEndpoint`, `getOpenApi`, + `patchInferenceEndpointTags`. None of them prefix the noun with the + output format. + +### 3. `ExportMetricsResponse` lives in a debug package but the JSDoc says "Proto version of com.databricks.rpc.HttpOverRpcResponse" — `model.ts:5-15` +- **Why weird:** This type name claims to be a "metrics" response, + but its JSDoc reveals it's a generic + `com.databricks.rpc.HttpOverRpcResponse` envelope — a wire-level + HTTP tunnelling primitive whose only field is `contents: ReadableStream`. + The Java/proto plumbing (UnaryRpcService, JettyRPC, + `CustomHandlingForHttpOverRpcProtoResponse`) is leaking into the + user-facing TS surface. Consumers do not need to know that + Databricks' RPC layer special-cases HTTP-over-RPC. +- **Category:** 14 (Go/Java/proto-style names leaking into TS), 6 + (misleading — the comment describes RPC, not metrics), 1 (vague — + `ExportMetricsResponse` could mean "response from any export-metrics + call", which is exactly what `HttpOverRpcResponse` is at the proto + layer). +- **Suggested name:** `EndpointMetrics` with a single field `body: + ReadableStream` (or `text: string` after consumption). Strip the + proto JSDoc entirely; the consumer should be told "Prometheus or + OpenMetrics text in the body stream" instead. The doc warning + "Don't add/modify the fields before being aware of the implications" + is a server-team note that does not belong in a public TS SDK. +- **Rationale:** Public SDK types should describe the user's mental + model ("here are the metrics"), not the server's wire envelope. + +### 4. `GetServedModelBuildLogs_Response` and `GetServedModelLogs_Response` underscore-suffixed pseudo-nested types — `model.ts:32,45` +- **Why weird:** The trailing `_Response` with an underscore is a + proto convention encoding nested message names + (`GetServedModelLogs.Response`). TypeScript has no nesting at the + type level, so the generator produced `GetServedModelLogs_Response`. + Each occurrence has to carry an + `eslint-disable-next-line @typescript-eslint/naming-convention -- + Proto-style nested message name.` directive (lines 31, 44, 50, 60). + The eslint suppression count alone (4 in a 69-line file) is a + smell. +- **Category:** 4 (underscores in TS identifiers), 14 (proto-style + names in TS). +- **Suggested name:** `ServedModelBuildLogs`, `ServedModelLogs` + (request types stay `GetServedModelBuildLogsRequest`, + `GetServedModelLogsRequest`, see #5). The generator should be + fixed once, project-wide. +- **Rationale:** `_Response` with an underscore is rule-4 violation + per the audit checklist; the broader rule is "underscores belong + to proto messages, not TS identifiers" — Google TypeScript Style + Guide § Identifiers + (https://google.github.io/styleguide/tsguide.html#identifiers). + +### 5. Request types lack `Request` suffix; response types have `_Response` — `model.ts:19,24,37` +- **Why weird:** Asymmetric: `GetServedModelLogs` (request, no suffix) + paired with `GetServedModelLogs_Response` (response, suffixed). The + bare `GetServedModelLogs` reads like a verb-as-type — "do the action + GetServedModelLogs". Reading + `function f(req: GetServedModelLogs)` is jarring; the type *is* the + action, not a value. Compare to other audited packages + (`endpoints.GetEndpointRequest`, `customllms.GetCustomLlmRequest`) + where the convention is `*Request`/`*Response`. +- **Category:** 17 (inconsistent action verb-form between request and + response), 14 (Go-style `Get*` as type name). +- **Suggested name:** Add `Request` suffix to all three: + `GetExportEndpointMetricsRequest`, + `GetServedModelBuildLogsRequest`, + `GetServedModelLogsRequest`. Pair with `*Response` (no underscore, + per #4) on the response side. +- **Rationale:** Symmetry. `Request`/`Response` is the project + precedent set by `endpoints`, `customllms`, and others. + +### 6. `name` field on every request — `model.ts:21,26,39` +- **Why weird:** All three request types have `name?: string` and the + JSDoc has to spell out "The name of the serving endpoint" each time. + Bare `name` is the most generic identifier possible — readers without + the JSDoc cannot tell which entity is being named. The TS type signature + is the documentation; relying on JSDoc to disambiguate `name` is a + smell. Worse, `GetServedModelBuildLogs` *and* `GetServedModelLogs` + also carry `servedModelName` — two `*Name` fields in the same struct + with one being a generic `name`. +- **Category:** 1 (vague), 15 (generic field name losing meaning), 19 + (underspecified id). +- **Suggested name:** `endpointName`. Wire stays `name` (the server + expects it). The method URL templates (`client.ts:69,96,124`) read + `/api/2.0/serving-endpoints/${req.name ?? ''}` which already proves + `name` is the *endpoint name*. +- **Rationale:** Renaming to `endpointName` puts the intent in the + type signature, eliminates the need for JSDoc-as-disambiguator, and + makes the pairing with `servedModelName` parallel (`endpointName` + + `servedModelName`). + +### 7. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:69,96,124` +- **Why weird:** The JSDoc on each request says "This field is + required" yet the type marks `name?: string | undefined` *optional* + and the URL is built with `${req.name ?? ''}` — meaning if the caller + forgets to set it, the SDK silently emits a URL like + `/api/2.0/serving-endpoints//metrics` (note the double slash) which + will 404 server-side. The contradiction between "required per JSDoc" + and "optional per TS type" is a naming/typing inconsistency that + bites consumers. +- **Category:** 6 (misleading — JSDoc contradicts type), 16 (field + contradicting type domain). +- **Suggested name:** Mark `name` as required (`endpointName: string`, + no `?`). Remove the `?? ''` fallback so a missing value throws + earlier. Same applies to `servedModelName`. +- **Rationale:** Optional + "required" JSDoc + empty-string fallback + is a triple-violation. Cf. AIP-122 + (https://google.aip.dev/122) which mandates path parameters be + required. + +### 8. `servedModelName` doc echoes the field name three times — `model.ts:27-28,40-41` +- **Why weird:** JSDoc on `GetServedModelBuildLogs.servedModelName` + reads "The name of the served model that build logs will be + retrieved for. This field is required." The field name already + contains "servedModel" + "Name" + the type signature already + conveys "this is a name". Pure echo. Same for the logs version. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology — + `name: string` reading as "name of a name"). Plus the bigger + issue: the JSDoc text doesn't tell the user *what format* the + served model name takes (alphanumeric? UUID? UC three-part?). +- **Suggested name:** No name rename; rewrite JSDoc to give the + *format* (e.g., "Slug-style identifier of the served model, e.g. + `myllm-v2`"). If the field were renamed to just `servedModel`, + the JSDoc could disappear entirely. +- **Rationale:** A naming audit should flag the *interaction* of + identifier + JSDoc; the doc carrying no information beyond what + the name says is a footgun for consumers. + +### 9. `GetServedModelLogs_Response.logs: string` is a single blob — `model.ts:47` +- **Why weird:** The field is named `logs` (plural) but typed as a + single `string`. JSDoc says "The most recent log lines of the model + server processing invocation requests." So it's many log *lines* + concatenated into one string. The plural/singular conflict with the + type (`string`, not `string[]`) is a category-9 finding. A user + doing `for (const line of response.logs)` will iterate characters, + not lines — silent footgun. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** Either `logsText: string` (singular field with + type-disambiguating suffix) or `logs: string[]` (split the lines + server-side). The current shape forces every consumer to write + `response.logs.split('\n')`. +- **Rationale:** Same issue applies to `GetServedModelBuildLogs_Response.logs` + (model.ts:34). When the server can't decide, the SDK should pick a + side and stick with it. + +## Medium severity + +### 10. `GetServedModelBuildLogs.name` clashes with `GetServedModelBuildLogs.servedModelName` — `model.ts:26,28` +- **Why weird:** Two name fields on one struct: `name` (endpoint name) + and `servedModelName` (served model name). The bare `name` looks like + *the* name of the request entity (which a reader would assume is the + served model, since the type is `GetServedModelBuildLogs`). Wrong: + it's the *parent* endpoint. The pairing breaks the principle of + least surprise. +- **Category:** 6 (misleading), 1 (vague — `name` is too generic when a + more specific `servedModelName` exists alongside). +- **Suggested name:** `endpointName` + `servedModelName` together. +- **Rationale:** When two `*Name` fields exist on one struct, neither + should be bare `name`. + +### 11. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:16` +- **Why weird:** The only field is `contents?: ReadableStream | undefined`. + Web Fetch standard + (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own + `HttpResponse` use `body` for the same concept. "Contents" is rare + in this domain — used by file APIs (file contents) but not HTTP + responses. +- **Category:** 17 (inconsistent naming — `body` everywhere else in + the SDK), 1 (vague — "contents" of what?). +- **Suggested name:** `body: ReadableStream` to match the Fetch + convention and `HttpResponse.body` (utils.ts:81). +- **Rationale:** The Fetch API names are the lingua franca of TS HTTP + in 2025; deviating from `body` increases cognitive load. + +### 12. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:65-68` +- **Why weird:** The method name says `EndpointMetrics`, the response + type says `ExportMetricsResponse` (no `Endpoint`). Inconsistent + qualifier between method and return type. A reader greping for + `EndpointMetrics` won't find the response type. +- **Category:** 17 (inconsistent — method qualifier dropped from + response type), 1 (vague — `ExportMetricsResponse` could be metrics + for anything). +- **Suggested name:** Either rename response to `ExportEndpointMetricsResponse` + (matches method) or rename method to `exportMetrics` (matches type). + Best: kill the `Export` framing (see #2) and pair `getEndpointMetrics()` + → `EndpointMetrics`. +- **Rationale:** Symmetry between method and return type aids + IDE autocomplete and grep-ability. + +### 13. `Get*` prefix on three of three methods — `client.ts:65,92,120` +- **Why weird:** Every method here is a GET. The `Get*` verb prefix on + TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` + or `metrics()` is more idiomatic for read operations + (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, + it's typically on synchronous accessors. +- **Category:** 14 (Go/Java-style names). +- **Suggested name:** Verb-first for actions: `exportMetrics(req)`, + `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or + property-style if the request is trivial: `endpointMetrics(name)`, + `servedModelLogs(name, servedModelName)`. The SDK is consistent on + `get*` across other packages, so this is a *category* issue, not a + local one — flag for project-wide review. +- **Rationale:** Google TS Style Guide § Names of functions + (https://google.github.io/styleguide/tsguide.html#methods) prefers + imperative verbs, but does not mandate `get*` for retrievals. + +### 14. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:92,120` +- **Why weird:** Two methods, both retrieve logs, distinguished only + by what *kind* of logs (runtime "service" logs vs container "build" + logs). The build/service axis is a sub-attribute of "logs", not a + separate concept. A more honest API would be one method with a + `kind: 'build' | 'service'` parameter; the SDK could collapse to + `getServedModelLogs(req: {endpointName, servedModelName, kind})`. +- **Category:** 12 (duplicate concept), 6 (misleading — `getServedModelLogs` + alone doesn't tell you it returns *service* (not build) logs). +- **Suggested name:** Rename the existing `getServedModelLogs` to + `getServedModelServiceLogs` (parallel with `getServedModelBuildLogs`). + Or collapse into one method per above. +- **Rationale:** When two siblings differ by a hidden attribute, name + *both* with that attribute. Today `getServedModelLogs` is the default + and `getServedModelBuildLogs` is the special case; the API doesn't + advertise the asymmetry. + +### 15. `GetServedModelLogs.servedModelName` doc says "The name of the served model that logs will be retrieved for" — passive voice — `model.ts:41` +- **Why weird:** Passive voice "that logs will be retrieved for" + reads like a phrase translated from a proto comment. Active voice + is shorter: "The served model whose logs to retrieve." Pure JSDoc + hygiene, but the same passive form appears on the build-logs request + (line 27) so it's a systemic pattern. +- **Category:** Observation — not a name bug per se, but a generator + artefact worth flagging. +- **Suggested name:** No rename; rewrite JSDoc in active voice. +- **Rationale:** API surface clarity. Not blocking. + +### 16. `unmarshalGetServedModelBuildLogs_ResponseSchema` is 41 characters of noise — `model.ts:51` +- **Why weird:** Schema names embed the *full* request type name + including the `_Response` underscore artefact. `unmarshal` + nested + type name = 41 chars for one symbol. Three eslint-disable directives + in a row (model.ts:31, 44, 50, 60) make the readability worse. +- **Category:** 7 (overly verbose), 4 (underscore in TS identifier), + 20 (type-suffix tautology — the schema's `` argument already + says `Response`). +- **Suggested name:** `unmarshalServedModelBuildLogs` (drop `Get`, + drop `_Response` — the symbol with no suffix is a fine name for + "the unmarshal for the build-logs response"). Pair with the + `Request`/`Response` symmetry fix in #5. +- **Rationale:** Schema names ride on type names; fixing the type + names cascades. + +### 17. `unmarshalX_ResponseSchema` violates camelCase — `model.ts:51,61` +- **Why weird:** The capital `R` in `_ResponseSchema` is half-word + inside what should be camelCase. Same eslint suppression pattern + as #4. +- **Category:** 4 (underscores in TS identifiers). +- **Suggested name:** See #16. +- **Rationale:** Same as #4 / #16. + +### 18. `PACKAGE_SEGMENT` const is unsized — `client.ts:34-37` +- **Why weird:** SCREAMING_SNAKE_CASE in TS is a Go/Python carryover. + Google TS Style Guide + (https://google.github.io/styleguide/tsguide.html#identifiers) + permits SCREAMING_SNAKE only for "module-local true constants that + are deeply immutable". This is module-local, but a richer term + like `packageUserAgent` or `userAgentSegment` carries more meaning. +- **Category:** 14 (Go/Python-style name in TS), 1 (vague — + "segment" of what?). +- **Suggested name:** `userAgentSegment` (camelCase). +- **Rationale:** SDK precedent: most other packages have the same + `PACKAGE_SEGMENT` const, so this is a cross-package finding — + fix at the generator. + +### 19. `HttpCallOptions` and `executeHttpCall` vs `executeCall` overlap — `utils.ts:15,26,65` +- **Why weird:** Three callable surfaces with overlapping names: + - `executeCall(call: Call, options?: CallOptions)` — wraps the retrier. + - `executeHttpCall(opts: HttpCallOptions): Promise` — + sends one HTTP request and reads the body. + - `sendAndCheckError(opts: HttpCallOptions): Promise` — + sends one HTTP request and returns the response (body untouched). + All three "execute calls" but at different abstraction levels. + `executeHttpCall` *also* checks errors and reads the body; + `sendAndCheckError` checks errors but doesn't read the body. The + names don't communicate the body-reading behaviour. +- **Category:** 12 (duplicate concept), 1 (vague), 17 (inconsistent + verbs — `execute*` vs `sendAndCheckError`). +- **Suggested name:** Rename to convey the body behaviour: + - `executeHttpCall` → `sendAndReadBody` (or `executeAndReadBody`). + - `sendAndCheckError` stays (it's the most-specific name). + - `executeCall` → `runWithRetries` or `runCall`. +- **Rationale:** Today a reader has to read both function bodies to + pick the right one. Names should describe the side effect on the + body stream. + +### 20. `marshalRequest` is unused inside this package — `utils.ts:119` +- **Why weird:** `marshalRequest(data, schema)` is exported from + `utils.ts` but the only call site in this package's `client.ts` is + none (all three methods are GETs with no body). The function exists + because `utils.ts` is generator-copied verbatim across packages. + Dead code is a naming smell because it inflates the surface area + the reader has to keep in their head. +- **Category:** Observation (cross-package generator artefact). +- **Suggested name:** No rename; flag for generator-level dead-code + pruning. +- **Rationale:** Public utility surface in a package that doesn't use + it is dead weight. + +### 21. `flattenQueryParams` is unused inside this package — `utils.ts:123` +- **Why weird:** Same as #20. None of the three GETs construct query + params (all data is in the URL path). Exported function with zero + internal users. +- **Category:** Observation (cross-package generator artefact). +- **Suggested name:** No rename; flag for generator-level dead-code + pruning. +- **Rationale:** Same as #20. + +### 22. `executeCall` second parameter `options?` is shadowed by `opts` inside — `utils.ts:26-38` +- **Why weird:** `options?: CallOptions` parameter is mapped onto a + local `const opts: Options = {...}`. The name shift `options` → + `opts` happens inline. Both are valid, but inside one 13-line + function they alternate, e.g., `options?.retrier` and + `opts.retrier` would mean different things. Today the code + carefully translates one into the other. +- **Category:** 1 (vague), 17 (inconsistent shortening — `options` vs + `opts`). +- **Suggested name:** Pick one. Either rename the parameter to `opts` + (and use `internalOpts` for the translated value) or keep `options` + and `internalOptions`. +- **Rationale:** Three-letter `opts` shorthand inside a function that + takes `options` is a category-5 cryptic-abbreviation finding. + +## Low severity + +### 23. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` +- **Why weird:** `Call` is one of the most generic names imaginable. + Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` + with no qualifier. Inside the client `const call: Call = async ...` + reads like "a phone call" or "function call". The actual semantic + is "a retriable RPC closure". +- **Category:** 1 (vague). +- **Suggested name:** `RetriableRpc` or `RpcClosure`. Cross-package + decision because `Call` is defined in `@databricks/sdk-core/api`. +- **Rationale:** Type names exported from a "core" package set the + vocabulary for every consumer; bare `Call` is the kind of name + that survives review only because nobody wants to argue with the + framework. + +### 24. `Options` type aliased to internal options shape — `utils.ts:3,30` +- **Why weird:** Same as #23 but for `Options`. `Options` is generic + to the point of meaninglessness. The translation step in + `executeCall` exists *because* the public `CallOptions` and the + internal `Options` are two different "options" types that happen + to have similar fields. +- **Category:** 1 (vague), 12 (duplicate concept — `Options` vs + `CallOptions`). +- **Suggested name:** `ExecuteCallInternalOptions` (verbose but + honest) or `RetrierOptions`. Cross-package decision. +- **Rationale:** Two adjacent "Options" types in 35 lines of code is + the classic accidental-collision pattern. + +### 25. `userAgent` is built once in the constructor and never refreshed — `client.ts:46,60` +- **Why weird:** Not a name bug per se, but the field name `userAgent` + suggests a dynamic property, while the construction reads + `this.userAgent = info.toString();` once at construction time. If + the credentials are mutated post-construction (rare but possible), + the UA goes stale. +- **Category:** Observation / 6 (mildly misleading). +- **Suggested name:** No rename. Document the construction-time + freeze in the JSDoc on line 43-46. +- **Rationale:** Worth a comment; not a rename target. + +### 26. `host` is normalised by trailing-slash strip — `client.ts:52` +- **Why weird:** `this.host = options.host.replace(/\/$/, '');` + silently rewrites the input. The field name `host` doesn't tell + the consumer "we normalise this to no trailing slash". If a debug + log later prints `client.host`, it won't match what was passed in. +- **Category:** Observation, 6 (mildly misleading). +- **Suggested name:** No rename. Add a JSDoc note. +- **Rationale:** Same pattern as #25; cross-package. + +### 27. `info` local var in the constructor — `client.ts:54,56,57,58,60` +- **Why weird:** `let info = createDefault().with(PACKAGE_SEGMENT);` + then more `info = info.with(...)` chains. The name `info` is + category-5 (cryptic abbreviation of "information") and category-1 + (vague). A reader who hasn't looked at `createDefault()` does not + know `info` is a `ClientInfo` (or whatever the type is — it's + inferred). +- **Category:** 1, 5. +- **Suggested name:** `clientInfo` (matches the imported + `createDefault` factory and the SDK convention). +- **Rationale:** Local-scope, low-impact rename. Cross-package. + +### 28. `pkgJson` import alias for package.json — `client.ts:19,35,36` +- **Why weird:** `import pkgJson from '../../package.json' with {type: + 'json'};`. The alias name `pkgJson` is cryptic; readers who don't + know `pkg` is "package" will guess. The line is unique-per-package + in the generated code. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `packageManifest` or `packageJson` (camelCase). +- **Rationale:** Trivial fix; cross-package. + +### 29. `httpReq` and `httpResp` shorthand inside methods — `client.ts:74,75,99,101,128,129` +- **Why weird:** `const httpReq = buildHttpRequest(...)` and + `const httpResp = await sendAndCheckError(...)`. The `Req`/`Resp` + truncation is shorter by 4 characters and a touch less readable. + TypeScript can autocomplete the longer form, so the savings are + illusory. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `httpRequest`, `httpResponse`. Cross-package + pattern. +- **Rationale:** Minor. Worth normalising at the generator. + +### 30. `e: unknown` catch parameter — `utils.ts:76,167` +- **Why weird:** `} catch (e: unknown) {` — single-letter `e` for the + exception. TS 4.0+ requires the explicit `: unknown`; the variable + name is style. Most codebases use `err` or `error` because `e` is + too overloaded (event handlers also use `e`). +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — sibling + utils.ts files would all need to match). +- **Suggested name:** `error` or `cause`. +- **Rationale:** Low impact, generator-fix only. + +## Observation + +### 31. `getReader()` chunk-accumulator in `readAll` is a hot-path candidate — `utils.ts:46-62` +- **Why weird:** `readAll` is the buffering implementation used by + every method (including `getServedModelLogs` which can return many + KB of text). The chunk-collection loop allocates many intermediate + `Uint8Array`s and then copies them all into one. For a metrics + blob streamed at 1 MB/s this is wasteful. The name `readAll` + doesn't hint at the buffering semantics. +- **Category:** Observation. +- **Suggested name:** No rename. Flag for performance review; consider + exposing `executeStreamingHttpCall` for the metrics endpoint so + consumers can iterate the stream. +- **Rationale:** Not a naming bug, but the audit covers the function + by virtue of its inclusion in `utils.ts`. Worth a note. + +### 32. `getExportEndpointMetrics` returns the raw `httpResp.body` (a stream) — `client.ts:80-82` +- **Why weird:** Method-level inconsistency: of the three methods, + *only* `getExportEndpointMetrics` returns the body stream (the + others read-and-parse). The asymmetry isn't communicated by the + return-type name `ExportMetricsResponse` vs the others' + `GetServedModelLogs_Response`. A reader has to inspect both type + declarations to discover that one is streaming and two are buffered. +- **Category:** 6 (misleading — return type doesn't advertise + streaming). +- **Suggested name:** Either rename the return type to include + `Stream` (e.g., `EndpointMetricsStream` with a `body: ReadableStream`) + or buffer the body inside the SDK (consistent with the other two + methods). The choice depends on consumer needs — metrics blobs + can be large, so the stream is the right shape but it must be + named accordingly. +- **Rationale:** Sibling consistency or explicit streaming naming; + pick one. diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md new file mode 100644 index 00000000..097e1d7c --- /dev/null +++ b/.agent/naming-audit/modelservingmanagement.md @@ -0,0 +1,441 @@ +# Naming Audit: modelservingmanagement + +**Path:** `packages/modelservingmanagement/src/v1/` +**Versions audited:** v1 +**Inferred domain:** "Serving endpoint" management — CRUD over inference (model-serving) endpoints, plus a parallel "PT" (provisioned-throughput) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Sibling packages: `modelservingdebug` (logs/metrics), `modelservingquery` (inference). Three packages share the noun "serving endpoint" with no cross-package alignment of how the noun is rendered (this package: `InferenceEndpoint`; debug: `Endpoint`; query: `Endpoint`). +**Total weird names flagged:** 53 + +## Summary +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 22 | +| Low | 12 | +| Observation | 6 | + +## High severity + +### 1. Package noun mismatch: `modelservingmanagement` vs `InferenceEndpoint` vs `ServingEndpoint*` vs `serving-endpoints` URL — entire package +- **Why weird:** The package name says *model-serving management*, the URL path says `/api/2.0/serving-endpoints`, the docs (every JSDoc) say "serving endpoint", but every TypeScript type is named `InferenceEndpoint*` (`InferenceEndpoint`, `InferenceEndpointDetailed`, `InferenceEndpointState`, `CreateInferenceEndpoint`, `DeleteInferenceEndpoint`, etc.). Meanwhile the *permission* enum is `ServingEndpointDetailedPermissionLevel` (model.ts:22) — the only top-level identifier in the file that uses the actual product noun. So the package has *three* names for the same thing: "serving endpoint" (product/doc/URL), "inference endpoint" (TS types), and "serving endpoint detailed" (permission enum). Users importing from this package will see `InferenceEndpoint`, look up docs that say "serving endpoint", and hit URLs labelled `serving-endpoints`. This is the central naming bug of the package. +- **Category:** 6 (misleading), 12 (duplicate concept), 17 (inconsistent terminology). +- **Suggested name:** Pick one product noun. The wire and docs say `serving endpoint`; the Go SDK exposes `ServingEndpoint`/`ServingEndpointsAPI`. Rename all `InferenceEndpoint*` to `ServingEndpoint*` (or vice versa across the docs and URL). The mixed state cannot stand. +- **Rationale:** Cross-language consistency: every Databricks SDK (Python, Java, Go) calls these `ServingEndpoint`. TS being the lone outlier on `InferenceEndpoint` will confuse anyone reading SDK docs side-by-side. + +### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:960` +- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 963) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 965) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. +- **Category:** 6 (misleading), 15 (generic field name vs specific type name). +- **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is (the unmarshal maps `served_entities`/`served_models` to either field — see #3). For users, `servedEntities: ServedEntity[]` reads correctly. +- **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. + +### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:377-391, 393-409, 411-416, 812-830, 906-922` +- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]`. The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." Today the marshal/unmarshal happily round-trip both keys (model.ts:1276-1280, 1297-1302). For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. +- **Category:** 12 (duplicate concept), 6 (misleading — deprecated not marked). +- **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely, have the marshaller still read it for back-compat but not surface it. +- **Rationale:** Five types times two fields equals ten redundant deprecation lookalikes; every one of them is a footgun. + +### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins — `src/v1/model.ts:988, 989, 1013-1023` +- **Why weird:** `ServedModel` has both `entityName`/`entityVersion` and `modelName`/`modelVersion`. The JSDoc on `ServedModelLite.modelName` (line 1015) says "Only one of model_name and entity_name should be populated"; same for `modelVersion`/`entityVersion`. So `ServedModel.modelName`/`modelVersion` are legacy fields that mirror `entityName`/`entityVersion`. They are completely undocumented inside `ServedModel` (lines 988-989 are bare fields with no comment), so a TS user has no way to know they are deprecated. This is *the same* duplication as #3, but at the field level. +- **Category:** 12 (duplicate concept), 6 (misleading), 19 (underspecified — bare fields with no docs). +- **Suggested name:** Mark `modelName` / `modelVersion` as `@deprecated`. The JSDoc on `ServedModelLite` should be promoted to a real type-level note. Wire keys remain. +- **Rationale:** Public surface area duplicating itself is *the* common source of integration bugs. + +### 5. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` +- **Why weird:** This is the *only* type named `ServingEndpoint*`. Every other type in the file uses `InferenceEndpoint*`. Either this enum should be `InferenceEndpointPermissionLevel` (to match the rest of the package), or the rest of the package should be `ServingEndpoint*` (to match the product and wire). The `Detailed` infix is also suspect — the enum lives on `InferenceEndpointDetailed.permissionLevel`, so the type-name says "this enum belongs to InferenceEndpointDetailed", but a `permissionLevel` of `CAN_VIEW` is *not* detailed any differently from a non-detailed view; the enum applies to the resource, not to the response shape. So `Detailed` is leaking the response-DTO name into the enum name. +- **Category:** 17 (inconsistent terminology), 7 (overly verbose), 14 (Go/proto-style nested-name leakage). +- **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. +- **Rationale:** Enum names that include the response-DTO shape (`Detailed`) are proto-buf artefacts. In TS, the enum represents a concept, not the message it appears in. + +### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:487` +- **Why weird:** `httpRequest` on a `Client` for *model-serving management* is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. +- **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). +- **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. +- **Rationale:** A method called `httpRequest` on a `ServingEndpointsClient` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. + +### 7. `ExternalFunctionRequest` doc says "Simple Proto message for testing" — `src/v1/model.ts:425` +- **Why weird:** Public type carries the JSDoc comment "Simple Proto message for testing". This is an internal proto-buf comment that leaked into the public TS surface. Either the type is for testing (in which case it should not be exported) or it is production (in which case the doc lies). Given it is wired to a real REST URL and exported via `index.ts:46`, the doc is a lie. +- **Category:** 6 (misleading — public doc text contradicts the exported reality), 14 (proto/Go-style leakage). +- **Suggested name:** Fix the JSDoc: "Request for `Client.httpRequest`: invoke an external service through a UC Connection." Keep type name `ExternalFunctionRequest` for now (paired with the rename in #6). +- **Rationale:** Doc bugs on exported identifiers are as serious as the identifier itself. + +### 8. Acronym casing storm: `AiGateway` / `AiGuardrails` / `OpenAi` / `PaLm` / `Ai21Labs` / `Pii` / `Pt` / `Uc` / `Llm` / `Ai` everywhere — across the file +- **Why weird:** This single file mixes nearly every imaginable acronym-casing scheme: + - `AiGateway`, `AiGatewayConfig`, `AiGatewayRateLimit`, `AiGuardrails`, `AiGuardrailParameters` — title-cased `Ai`. + - `OpenAiConfig`, `OpenAi` — title-cased `Ai`, lowercase initial. + - `GoogleCloudVertexAiConfig`, `googleCloudVertexAiConfig` — same. + - `PaLmConfig`, `palmConfig` — `PaLm` (the *only* mixed-internal-caps spelling). The product is "PaLM", which is itself a stylized "Pathways Language Model"; the SDK could have rendered it `Palm`, `PaLM`, or `PaLm`. It chose `PaLm`, the worst of three. + - `Ai21Labs`, `Ai21LabsConfig` — the product is "AI21 Labs"; rendered as `Ai21Labs` (lower-case `21`, lower-case `i` mid-word). + - `PiiSettings` — `Pii` is "PII" (personally identifiable information); rendered title-case. + - `Pt`, `PtEndpoint`, `PtServedModel`, `PtEndpointCoreConfig`, `CreatePtEndpoint`, `PutPtEndpointConfig` — `Pt` is "PT" (provisioned throughput). Two-letter acronym title-cased. + - `Uc`, `ucServiceCredentialName` — `Uc` is "UC" (Unity Catalog). + - `HttpMethod` — `Http` title-cased. + - `OpenApi`, `GetOpenApiResponse` — `Api` title-cased mid-word. + - `ApiKey`, `apiKeyAuth` — `Api` title-cased. + - `ARN`-related: `instanceProfileArn`, `Arn` is suffix-cased. + - `Url`, `endpointUrl`, `customProviderUrl` — `Url` title-cased. + - `OpenAi` (line 699) vs `openai` (line 462, 492, 1336, 2135, 2245) — `openai` is all lower-case in *some* discriminator keys. +- **Category:** 3 (acronym casing inconsistencies — the audit prompt's exemplar). +- **Suggested name:** Decide a project-wide rule in `typescript.mdc`. The Microsoft .NET capitalization guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) say to title-case two-letter acronyms (`IO`) and PascalCase three-plus-letter acronyms (`Xml`); the Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) says to treat acronyms as whole words. Either is defensible; *none* should be mixed in one file. The current state has at least four different rules co-existing. +- **Rationale:** Twenty-five exported identifiers from one file vary in convention. This is the single biggest *category* of weirdness in the package. + +### 9. `openai` discriminator key lowercase while sibling keys are camelCase — `src/v1/model.ts:492-495, 2135-2137` +- **Why weird:** Inside `ExternalModel.config` discriminated union, the eight `$case` values are: `ai21labsConfig`, `anthropicConfig`, `amazonBedrockConfig`, `cohereConfig`, `googleCloudVertexAiConfig`, `databricksModelServingConfig`, `openaiConfig`, `palmConfig`, `customProviderConfig`. Seven of nine use the standard `Config` camelCase. The two outliers are: + - `ai21labsConfig` (the product is "AI21 Labs"; the discriminator collapses to `ai21labs` — all lower-case middle), and + - `openaiConfig` (the product is "OpenAI"; the discriminator collapses to `openai` — lower-case middle), and + - `palmConfig` (the product is "PaLM"; the discriminator collapses to `palm`). + In each case the JSDoc field name (`Ai21Labs`, `OpenAi`, `PaLm`) does not match the discriminator (`ai21labs`, `openai`, `palm`). +- **Category:** 3 (acronym casing), 17 (inconsistent within the same union). +- **Suggested name:** Either lowercase the camelCase boundary on all keys (`ai21Labs`, `openAi`, `paLm`, `amazonBedrock`, `cohere`, ...) or all-PascalCase the type names to match. As above: pick one rule. +- **Rationale:** The discriminator string is the *runtime* value clients must match against; an inconsistent rule means clients can't programmatically map provider name → discriminator. + +### 10. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` +- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 834). A consumer importing `Behavior` from `@databricks/sdk-modelservingmanagement/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `BEHAVIOR_UNSPECIFIED | NONE | BLOCK | MASK` — so this is *PII action behavior*. +- **Category:** 1 (vague/generic), 15 (generic name losing meaning). +- **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. +- **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. + +### 11. `Route` field carries `servedModelName` AND `servedEntityName` — `src/v1/model.ts:952-958` +- **Why weird:** `Route` has three fields: `servedModelName?: string`, `trafficPercentage?: number`, `servedEntityName?: string`. There is no JSDoc on `servedEntityName` — it is silently the modern name; `servedModelName` is the legacy. Two fields point at the same logical thing (the entity to route traffic to), one without docs, one with docs that only mention "served model" (line 953). Same bug class as #3 and #4. +- **Category:** 12 (duplicate concept), 6 (misleading), 19 (undocumented field). +- **Suggested name:** Mark `servedModelName` `@deprecated`; doc `servedEntityName` properly. +- **Rationale:** Triple bug: undocumented field, duplicate concept, no deprecation marker. + +### 12. `_Response` proto-style nested-message underscore in TS identifiers — `src/v1/model.ts:367, 686, 800, 882, 930, 1041` +- **Why weird:** Five identifiers carry an underscore mid-name to encode "this is a nested message": + - `DeleteInferenceEndpoint_Response` + - `ListInferenceEndpoints_Response` + - `PatchInferenceEndpointTags_Response` + - `PutInferenceEndpointAiGateway_Response` + - `PutInferenceEndpointRateLimits_Response` + - `UpdateInferenceEndpointNotifications_Response` + - `ServedModel_EnvironmentVarsEntry` (line 1000-1011) — also underscored. + - `ExternalFunctionRequest_HttpMethod` enum (line 28-36) — also underscored. + - `InferenceEndpointState_ConfigUpdateState` (line 38-45) — also underscored. + - `InferenceEndpointState_ReadyState` (line 47-52) — also underscored. + + Each carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment. The underscore is a hard violation of every TS style guide (Google TS Style Guide §5.3: "Use camelCase, no underscores"; this is precisely the case the rule prohibits). +- **Category:** 4 (underscores in TS identifiers), 14 (proto-style identifiers leaking into TS). +- **Suggested name:** Drop the underscore. Use intercap PascalCase: `DeleteInferenceEndpointResponse`, `ListInferenceEndpointsResponse`, `ExternalFunctionRequestHttpMethod`, `InferenceEndpointStateConfigUpdateState`, `InferenceEndpointStateReadyState`, `ServedModelEnvironmentVarsEntry`. The eslint-disable comments are a tell that the convention is wrong: 10+ exemptions across the file means the convention is being broken systematically. +- **Rationale:** The eslint rule the comments disable is the *Databricks TypeScript style*. Either the rule is wrong (in which case fix the rule) or the names are wrong (in which case fix the names); the current "ten exemptions" state is the worst of both worlds. + +### 13. `_UNSPECIFIED` sentinel enum values across five enums — `src/v1/model.ts:6, 13, 30, 40, 49` +- **Why weird:** Five enums each declare a `*_UNSPECIFIED` member as the zero value: + - `Behavior.BEHAVIOR_UNSPECIFIED` + - `ServedModelDeploymentState.DEPLOYMENT_UNKNOWN` (variant: uses `UNKNOWN` not `UNSPECIFIED`!) + - `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED` + - `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED` + - `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED` + - `ServingEndpointDetailedPermissionLevel` — *no* unspecified member (the only enum without one). + + These are proto-buf zero-value placeholders. TS uses `undefined` for "not set"; the sentinel value is redundant. Worse, two different conventions exist (`*_UNSPECIFIED` vs `DEPLOYMENT_UNKNOWN`) — there is no even consistency among the unspecified members themselves. +- **Category:** 14 (proto/Go-style names not idiomatic in TS), 18 (long enum values), 17 (inconsistent `UNSPECIFIED`/`UNKNOWN`). +- **Suggested name:** Drop the `*_UNSPECIFIED` and `*_UNKNOWN` zero-values; rely on `field?: EnumType | undefined`. If kept, normalize all to one convention (`UNSPECIFIED` per AIP-126: https://google.aip.dev/126). +- **Rationale:** Sentinel zero-values exist in TS only to round-trip proto-buf default-zero semantics, which the wire JSON does not need. + +## Medium severity + +### 14. Redundant enum prefixes — `src/v1/model.ts:5-52` +- **Why weird:** Three enums duplicate the enum name in every value: + - `Behavior.BEHAVIOR_UNSPECIFIED` (line 6) + - `ServedModelDeploymentState.DEPLOYMENT_*` (lines 13-19) — six values, every one starts with `DEPLOYMENT_`. + - `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED` (line 30) — the `HTTP_METHOD_` prefix is doubled because the enum is *already* named `HttpMethod`. + - `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED` (line 40) — three layers of redundancy. + - `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED` (line 49) — two layers. + + At the call site you write `Behavior.BEHAVIOR_UNSPECIFIED`, `ServedModelDeploymentState.DEPLOYMENT_READY`. TS enums are already namespaced. +- **Category:** 2 (redundant enum prefixes), 18 (long enum values). +- **Suggested name:** Drop the redundant prefix: `Behavior.UNSPECIFIED`, `ServedModelDeploymentState.CREATING/RECOVERING/READY/FAILED/ABORTED/STOPPED`, `HttpMethod.GET/POST/...` (already correct for non-UNSPECIFIED), `ConfigUpdateState.NOT_UPDATING/IN_PROGRESS/...`, `ReadyState.READY/NOT_READY`. +- **Rationale:** `ServedModelDeploymentState.DEPLOYMENT_READY` is twelve characters of redundant prefix per value. + +### 15. `ServedModelDeploymentState` enum name contains `Deployment` AND values are `DEPLOYMENT_*` AND it lives on `ServedModelState.deployment` — `src/v1/model.ts:12, 1025-1028` +- **Why weird:** Triple redundancy: the type is `ServedModelDeploymentState`, the field is `ServedModelState.deployment: ServedModelDeploymentState`, the values are `DEPLOYMENT_*`. At a call site: `state.deployment === ServedModelDeploymentState.DEPLOYMENT_READY` — the word "deployment" appears three times. +- **Category:** 2 (redundant enum prefix), 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). +- **Suggested name:** Drop `Deployment` from the enum name (`ServedModelState`); drop `DEPLOYMENT_` from values. Field becomes `state.deployment === ServedModelState.READY`. But that collides with the *type* name `ServedModelState` (which wraps both `deployment` and `deploymentStateMessage`). Hence: rename type `ServedModelState` → `ServedModelDeployment`, and enum `ServedModelDeploymentState` → `DeploymentState`. Now: `served.state.deployment === DeploymentState.READY`. Clean. +- **Rationale:** The current names tangle three concepts in a way that resists reading. + +### 16. `InferenceEndpointState_ConfigUpdateState` enum — triple-encoded — `src/v1/model.ts:38-45` +- **Why weird:** Two-level proto-style nesting (`InferenceEndpointState_ConfigUpdateState`) with redundant value prefixes (`CONFIG_UPDATE_STATE_UNSPECIFIED`) — see #12, #13, #14. Used as `state.configUpdate: InferenceEndpointState_ConfigUpdateState` (line 660). Call site: `inferenceEndpoint.state.configUpdate === InferenceEndpointState_ConfigUpdateState.UPDATE_FAILED` — 78 characters to ask "is it failed?". +- **Category:** 4, 14, 18 (combo of all three). +- **Suggested name:** Top-level enum `ConfigUpdateState`. Values without prefix: `NOT_UPDATING | IN_PROGRESS | UPDATE_FAILED | UPDATE_CANCELED`. (Note `UPDATE_FAILED` keeps the `UPDATE_` because there are multiple state-like enums; otherwise just `FAILED`.) +- **Rationale:** Cuts the call-site length by half. + +### 17. Method `httpRequest` (already flagged in #6) duplicate pattern with `getInferenceEndpointSchema` — `src/v1/client.ts:230, 487` +- **Why weird:** Both `getInferenceEndpointSchema` and `httpRequest` set `resp.contents = httpResp.body ?? undefined` — they are the only two methods that bypass the marshal/unmarshal pipeline and return a raw `ReadableStream`. The pattern is duplicated verbatim. The naming is also inconsistent: one method is named for the URL noun (`schema`), the other for the HTTP verb (`request`). A consumer cannot tell from the names that both return raw streams. +- **Category:** 17 (inconsistent verb convention), 12 (duplicate pattern). +- **Suggested name:** Rename consistently: `getInferenceEndpointSchema` → `openApiSchema`; `httpRequest` → `invokeExternalFunction` (per #6). Or extract a `*Raw` suffix: `getInferenceEndpointSchemaRaw`, `invokeExternalFunctionRaw` — at least signal the "raw stream return". +- **Rationale:** Reading the client should tell the user which methods consume the body and which hand back a stream. + +### 18. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:377, 393, 411` +- **Why weird:** Three types describe "the config of a serving endpoint": + - `EndpointCoreConfig`: input shape (`servedEntities: ServedModel[]`, `servedModels: ServedModel[]`, `trafficConfig`, `autoCaptureConfig`). + - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. + - `EndpointCoreConfigSummary`: lite shape (`servedEntities: ServedModelLite[]`, `servedModels: ServedModelLite[]` — no `trafficConfig`, no `autoCaptureConfig`, no `configVersion`). + + Together with `PendingConfig` (which is `EndpointCoreConfigOutput` plus `startTime`) and `PtEndpointCoreConfig` (the PT variant of `EndpointCoreConfig`), there are five overlapping config types. The naming makes the differences invisible: `Output` adds one field; `Summary` removes three. +- **Category:** 12 (duplicate concept), 7 (overly verbose suffixes), 17 (inconsistent suffix semantics). +- **Suggested name:** Either (a) collapse into one type with optional fields, or (b) give the types names that reflect their *purpose*: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). +- **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. + +### 19. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:580, 609` +- **Why weird:** Two near-duplicate types: + - `InferenceEndpoint` (line 580-607): used in `ListInferenceEndpoints_Response.endpoints`. Has 13 fields. + - `InferenceEndpointDetailed` (line 609-646): returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. Has 18 fields. + + The "Detailed" version adds `pendingConfig`, `permissionLevel`, `routeOptimized`, `endpointUrl`, `dataPlaneInfo`, `emailNotifications` and changes `config` from `EndpointCoreConfigSummary` to `EndpointCoreConfigOutput`. So `InferenceEndpoint` is really the *list-summary* projection, but its name says "the endpoint". `InferenceEndpointDetailed` is *the* endpoint, but its name says "more detail than usual". +- **Category:** 12 (duplicate concept), 7 (overly verbose suffix), 17 (inconsistent: which one is "the endpoint"?). +- **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. +- **Rationale:** Currently consumers writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. + +### 20. `ServedModelLite` lite-variant — `src/v1/model.ts:1013-1023` +- **Why weird:** Same pattern as #19 at the entity level. `ServedModel` (line 960) has 21 fields. `ServedModelLite` (line 1013-1023) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). +- **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). +- **Suggested name:** `ServedEntitySummary` (paired with #2 type rename). +- **Rationale:** Inconsistent suffix convention across the file. "Lite" is also an LLM-era term that clashes with the OpenAI/Anthropic-flavoured product space. + +### 21. `Pt` abbreviation everywhere — `src/v1/client.ts:137, 162, 415, 440` and `src/v1/model.ts:295, 837, 843, 937` +- **Why weird:** `Pt` is short for "provisioned throughput". The full term ("provisioned throughput") *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`), but the request/response *types* use the abbreviation (`CreatePtEndpoint`, `PutPtEndpointConfig`, `PtEndpointCoreConfig`, `PtServedModel`). So the public surface has: + - `client.createProvisionedThroughputInferenceEndpoint(req: CreatePtEndpoint)` — method-full, type-abbreviated. + - URL: `/api/2.0/serving-endpoints/pt` — wire-abbreviated. + + Three different names for one concept, in one call. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistent abbreviation across method/type/URL). +- **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpoint`, `PutProvisionedThroughputEndpointConfig`, etc. — long but searchable) or contract all (`createPtEndpoint`, `putPtEndpointConfig` — short but cryptic). Pick one. The current half-and-half is the worst option. +- **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). + +### 22. `CreatePtEndpoint` method-type asymmetry with `CreateInferenceEndpoint` — `src/v1/model.ts:272, 295` +- **Why weird:** Sister request types: + - `CreateInferenceEndpoint` (full name). + - `CreatePtEndpoint` (abbreviated). + + The PT variant is *not* called `CreateProvisionedThroughputInferenceEndpoint`; it is `CreatePtEndpoint`. The non-PT variant is not called `CreateEndpoint`; it is `CreateInferenceEndpoint`. So one type carries the qualifier `Inference`, the other carries the qualifier `Pt`. Mixed metaphor. +- **Category:** 17 (inconsistent qualifier choice). +- **Suggested name:** `CreateServingEndpoint` and `CreateProvisionedThroughputServingEndpoint` (paired with #1). +- **Rationale:** Sibling request types should differ only in the qualifier that actually differs. + +### 23. `PutInferenceEndpointConfig` vs `PutPtEndpointConfig` — request shape divergence — `src/v1/model.ts:906, 937` +- **Why weird:** Two "put endpoint config" requests: + - `PutInferenceEndpointConfig`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). + - `PutPtEndpointConfig`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). + + Same operation conceptually, two different request shapes. The naming makes both look symmetric (`Put*EndpointConfig`), but they are not. +- **Category:** 17 (inconsistent shape with consistent naming — worst case for the reader). +- **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. +- **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. + +### 24. `PatchInferenceEndpointTags.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:792-799` +- **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. That semantics is fine, but the field name does not convey it. +- **Category:** 6 (misleading), 15 (generic field name). +- **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). +- **Rationale:** When the element type changes, the field name should change too. + +### 25. `endpointUrl` field domain ambiguity — `src/v1/model.ts:634, 332` +- **Why weird:** `endpointUrl` appears twice: + - `InferenceEndpointDetailed.endpointUrl` (line 634): "Endpoint invocation url if route optimization is enabled for endpoint." + - `DataPlaneInfo.endpointUrl` (line 332): "The URL of the endpoint for this operation in the dataplane." + + Same field name, two completely different URLs (one is the public invocation URL; the other is the data-plane endpoint for one specific operation). Compare with #15 in the audit prompt: generic field names lose meaning across structs. +- **Category:** 15 (generic field name across types), 17 (inconsistent usage). +- **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). +- **Rationale:** A consumer JOINing the two by `endpointUrl` field name will mismatch them. + +### 26. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:581-596, 610-625` +- **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: + - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) + - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." + + The `name` is used in URLs; the `id` is used in the Permissions API. Same resource, two opaque strings. Neither is qualified (`endpointName`/`endpointId` would make grepping work). Compare to the audit prompt's rule 19. +- **Category:** 1 (vague), 19 (underspecified ID), 15 (generic field name). +- **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. +- **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources (e.g. logs that include a `name` that is something else entirely). + +### 27. Waiter classes have asymmetric naming — `src/v1/client.ts:515, 595, 675, 755` +- **Why weird:** Four waiter classes: + - `CreateInferenceEndpointWaiter` + - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters — the longest exported class in the file) + - `PutInferenceEndpointConfigWaiter` + - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) + + Three problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #21 where the type is `Pt`); the names communicate "this class waits for X" but the doc-comments on the classes say nothing about what is waited for. +- **Category:** 7 (overly verbose), 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). +- **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. +- **Rationale:** Four exported waiter classes, each 30+ characters long, each containing five+ identical method-name prefixes that grep the same way as the methods themselves. + +### 28. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:571-592, 651-672, 731-752, 811-832` +- **Why weird:** Waiter `done()` returns `true` for: + - `NOT_UPDATING` (success) + - `UPDATE_FAILED` (failure) + - `UPDATE_CANCELED` (cancellation) + + All three "terminal" states are treated as `done`. A consumer reading `if (await waiter.done()) { /* it succeeded */ }` will silently get failures and cancellations. The name `done()` does not convey "terminal but possibly failed". +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. +- **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. + +### 29. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:72` +- **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. +- **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). +- **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). +- **Rationale:** Minor; internal. + +### 30. `marshalRequest` / `parseResponse` verb asymmetry — `src/v1/utils.ts:113, 119` +- **Why weird:** `parseResponse` (response inbound) vs `marshalRequest` (request outbound). Inverse operations, different verbs. The model file uses `unmarshal*Schema` / `marshal*Schema` for the same pair (line 1053 vs 1813) — internally consistent within `model.ts`, but `utils.ts` uses `parse` not `unmarshal`. Same bug as customllms audit #22. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** Match: `unmarshalResponse` / `marshalRequest`. +- **Rationale:** Pair symmetry. + +### 31. `executeCall` and `executeHttpCall` — utils.ts:26, 65 +- **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + APIError check). Easy to confuse at the call site. Same as customllms audit #21. +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. +- **Rationale:** Names should differ in more than the `Http` infix. + +### 32. `HttpCallOptions` collides with `CallOptions` and `Options` and `ClientOptions` — `src/v1/utils.ts:15` +- **Why weird:** Four "options" types in scope in `utils.ts`: + - `Options` from `@databricks/sdk-core/api` (line 3) + - `CallOptions` from `@databricks/sdk-options/call` (line 12) + - `ClientOptions` (in `client.ts`) + - `HttpCallOptions` (this file, line 15) + + Each is conceptually different. The naming makes them look like a hierarchy (`ClientOptions` → `CallOptions` → `Options`), but they are not. `HttpCallOptions` in particular is an internal arg-bag (`{request, httpClient, logger}`), not a user-facing tuning object. +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `HttpCallContext` (it is a context object, not options). +- **Rationale:** Same as customllms audit #23. + +### 33. `EndpointTag` versus `tags` field — `src/v1/model.ts:418, 281, 304, 594, 628` +- **Why weird:** Tag type `EndpointTag` (key + value). Field `tags: EndpointTag[]` appears on 5 types. The type name carries the `Endpoint` qualifier even though tags are scoped to the endpoint already (the type only appears on endpoint types). Compare to `RateLimit` (no `Endpoint` prefix) and `Route` (no `Endpoint` prefix) on the same types. Inconsistent qualifier policy. +- **Category:** 7 (verbose qualifier), 17 (inconsistent: `EndpointTag` but `RateLimit`/`Route`). +- **Suggested name:** `Tag` (drop prefix) for consistency with `RateLimit` / `Route` siblings. +- **Rationale:** Either all child types carry the `Endpoint*` prefix or none do. + +### 34. `creationTimestamp` field is a `number` (Unix seconds) named like a string — `src/v1/model.ts:586, 614, 997` +- **Why weird:** `creationTimestamp?: number` with JSDoc "The timestamp when the endpoint was created in Unix time." The type is `number`; the name `creationTimestamp` does not communicate units (ms? s? ns?). The customllms audit (#11) flagged the same field as a candidate for `createdAt` or `createTime` per Google AIP-142 (https://google.aip.dev/142). Also the field is a *raw number*, not `Temporal.Instant` — inconsistent with the SDK's apparent move toward `Temporal` (the customllms package uses `Temporal.Instant`, this package uses raw number). +- **Category:** 17 (cross-package inconsistency), 19 (underspecified). +- **Suggested name:** `createTime: Temporal.Instant` (matches AIP-142 and customllms convention). +- **Rationale:** Two packages, two conventions for the same domain concept. + +### 35. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:943-950, 93-107` +- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:383 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #18: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. +- **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). +- **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimits*` types `@deprecated` in JSDoc. +- **Rationale:** Same pattern repeated; same fix. + +## Low severity + +### 36. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` +- **Why weird:** Field repeats the provider name (`ai21labs`) because the type is named `Ai21LabsConfig`. Reading `config.ai21labsApiKey` inside an `Ai21LabsConfig` is redundant — the only key here is going to be an AI21 Labs API key. Same pattern repeats for every provider config (`anthropicApiKey` inside `AnthropicConfig`, `cohereApiKey` inside `CohereConfig`, etc.). +- **Category:** 7 (overly verbose), 20 (type-suffix tautology). +- **Suggested name:** `apiKey` / `apiKeyPlaintext` inside `Ai21LabsConfig`. Wire stays `ai21labs_api_key`. +- **Rationale:** Compare to `OpenAiConfig.openaiApiKey` (same redundancy), `CohereConfig.cohereApiKey` (same), `AnthropicConfig.anthropicApiKey` (same), `PaLmConfig.palmApiKey` (same), `DatabricksModelServingConfig.databricksApiToken` (same). Six provider configs, six instances of the redundancy. The wire forces the prefix (`anthropic_api_key`); TS does not. + +### 37. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields +- **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. +- **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). +- **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. +- **Rationale:** The "must specify exactly one" constraint is invisible to the type system. + +### 38. `valid_topics` / `invalid_keywords` — `src/v1/model.ts:118, 123` +- **Why weird:** Two list fields on `AiGuardrailParameters`. `validTopics` is the list of *allowed* topics; `invalidKeywords` is the list of *blocked* keywords. So one is a denylist, one is an allowlist. The opposite-polarity naming (`valid*` for allowlist, `invalid*` for denylist) reads correctly *only* if you read both docs. A user skimming the fields will see "valid topics" and "invalid keywords" and not realise the polarity flipped. +- **Category:** 6 (misleading), 17 (inconsistent polarity). +- **Suggested name:** `allowedTopics` / `blockedKeywords`. +- **Rationale:** Allowlist/denylist naming convention is well-established (https://www.ncsc.gov.uk/blog-post/terminology-its-not-black-and-white). + +### 39. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` — `src/v1/model.ts:371, 373` +- **Why weird:** Field name reads as an event handler (`onUpdateSuccess` is a JS convention for "callback when update succeeds"). But the field is a `string[]` of email addresses. Not a callback. The `on*` prefix is borrowed from JS event-handler-naming and is misleading here. +- **Category:** 6 (misleading — `on*` implies callback). +- **Suggested name:** `notifyOnUpdateSuccess` / `notifyOnUpdateFailure` (verb), or `updateSuccessRecipients` / `updateFailureRecipients` (noun). +- **Rationale:** `on*` in a JS context is a strong signal of "event handler"; using it for email lists violates that signal. + +### 40. `Route.servedModelName` / `servedEntityName` — already flagged in #11 +- **Why weird:** Cross-reference. + +### 41. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +- **Why weird:** Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added (e.g. `mistralConfig`), the discriminated union types it correctly, but the marshal/unmarshal cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary (#9). This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. +- **Category:** Observation / 12. +- **Suggested name:** No rename; flag as generator review. +- **Rationale:** Names look clean; runtime is fragile. + +### 42. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:456` +- **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 962). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). +- **Category:** 1 (vague), 15 (generic name across types). +- **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. +- **Rationale:** Disambiguates from `ServedModel.name`. + +### 43. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:454` +- **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. +- **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). +- **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. +- **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. + +### 44. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:977` +- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #43: a string field with a documented but unenforced enum. +- **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). +- **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). +- **Rationale:** Type-narrowing fix; minor. + +### 45. `instanceProfileArn` on `ServedModel` AND `AmazonBedrockConfig` — `src/v1/model.ts:181, 993` +- **Why weird:** Same field name on two unrelated types with very different semantics: + - `AmazonBedrockConfig.instanceProfileArn`: "ARN of the instance profile that the *external model* will use to access AWS resources." (Used to authenticate to AWS Bedrock.) + - `ServedModel.instanceProfileArn`: "ARN of the instance profile that the *served entity* uses to access AWS resources." (Used by the Databricks runtime serving the model.) + + Two different ARNs, two different purposes, identical field names. +- **Category:** 15 (generic field name across types), 17 (inconsistent usage). +- **Suggested name:** `bedrockInstanceProfileArn` (on `AmazonBedrockConfig`) and `servingInstanceProfileArn` (on `ServedModel`). +- **Rationale:** Disambiguation; minor since the enclosing type makes it clear in IDE. + +### 46. `FoundationModel.docs` field name — `src/v1/model.ts:523` +- **Why weird:** `docs?: string` on `FoundationModel`. The field name "docs" reads as "documentation, plural". Likely a URL or a long-form doc string. The JSDoc is empty — the whole type has only the comment "All fields are not sensitive as they are hard-coded in the system and made available to customers." (line 519). No field-level doc. +- **Category:** 1 (vague), 19 (no documentation). +- **Suggested name:** `docsUrl` (if URL) or `documentation` (if prose). +- **Rationale:** Bare `docs` is the kind of field name that survives generator passes because no human reviews each field. + +### 47. Four waiter classes with identical bodies — `src/v1/client.ts:515-833` +- **Why weird:** `CreateInferenceEndpointWaiter`, `CreateProvisionedThroughputInferenceEndpointWaiter`, `PutInferenceEndpointConfigWaiter`, `PutProvisionedThroughputInferenceEndpointConfigWaiter` — four classes, each ~80 lines, each *byte-identical* except for the class name. Naming hides the duplication. +- **Category:** 12 (duplicate concept). +- **Suggested name:** Single `InferenceEndpointConfigUpdateWaiter` class; replace four with one. The four methods become factory functions on the client. +- **Rationale:** When four classes share 100% of their bodies, having four names is misdirection. + +## Observations + +### 48. Mixed naming convention for the same product across three sibling packages +The Databricks "Serving Endpoints" product spans three packages in this SDK: +- `modelservingmanagement`: types use `InferenceEndpoint*`. +- `modelservingdebug`: types use `Endpoint` (e.g. `GetExportEndpointMetrics`). +- `modelservingquery`: types use `Endpoint` (e.g. `QueryEndpointInput`, `QueryEndpointResponse`). + +No two packages agree on the noun. The wire uniformly uses `serving-endpoints`. SDK consumers chaining all three packages will see three different names for one concept. +- **Category:** 17 (cross-package inconsistency). + +### 49. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +Same as customllms #28 — every generated package carries this unused export. + +### 50. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:67` +Same as customllms #24 — internal user-agent constant. + +### 51. `Headers` constructor used four times in client.ts — `src/v1/client.ts:108, 145, 184, 213, ...` +Each method instantiates a `new Headers({'Content-Type': 'application/json'})` then `.set('User-Agent', this.userAgent)`. Naming-wise this is fine (Headers is the standard web API name), but the pattern is duplicated 11 times in the file. Not a naming bug; observation only. +- **Category:** 12 (duplicate pattern across methods). + +### 52. Verb-tense consistency in `Client` — observation of best practice +The client uses `create`/`delete`/`get`/`list`/`patch`/`put`/`update` plus the outlier `httpRequest` (see #6) and the four `*Waiter` factory methods. Apart from `httpRequest`, the verbs are consistent. Worth flagging as a positive. +- **Category:** 17 (reversed — explicit consistency). + +### 53. `httpRequest` is sole non-CRUD method +The client mixes serving-endpoint CRUD with one orthogonal "invoke through UC connection" operation. This is a structural smell more than a naming smell, but worth flagging because the misplaced method makes the package-level naming (`modelservingmanagement`) even less accurate. +- **Category:** Observation / 14. + +## Domain glossary +- `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names, abbreviated in type names. +- `ai gateway` — A Databricks-internal proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. +- `ai guardrails` — Input/output content filters applied via AI Gateway (`safety`, `pii`, `validTopics`, `invalidKeywords`). +- `pii` — Personally Identifiable Information. Rendered `Pii` throughout. +- `uc` — Unity Catalog. Rendered `Uc` (in `ucServiceCredentialName`) or written into JSDoc as "UC". +- `pat`/`m2m`/`u2m`/`oidc` — not encountered in this package. +- `iam` — not encountered. +- `arn` — Amazon Resource Name. Rendered `Arn` (suffix `instanceProfileArn`). +- `wkt` — Well-Known Types. Not imported (this package uses raw `number` for timestamps, not `Temporal.Instant`). +- `provider` enum keys (`ai21labs`, `anthropic`, `amazon-bedrock`, `cohere`, `databricks-model-serving`, `google-cloud-vertex-ai`, `openai`, `palm`, `custom`) — kebab-case on the wire, `Config` camelCase in TS. + +## File coverage +- `src/v1/model.ts` (2495 lines): read fully. +- `src/v1/client.ts` (834 lines): read fully. +- `src/v1/utils.ts` (186 lines): read fully. +- `src/v1/index.ts` (87 lines): read fully. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md new file mode 100644 index 00000000..e177a330 --- /dev/null +++ b/.agent/naming-audit/modelservingquery.md @@ -0,0 +1,663 @@ +# Naming Audit: `modelservingquery` (v1) + +**Package:** `@databricks/sdk-modelservingquery` +**Path:** `/home/parth.bansal/sdk-js/packages/modelservingquery/` +**Version audited:** `v1` +**Files audited:** +- `src/v1/model.ts` +- `src/v1/client.ts` +- `src/v1/utils.ts` +- `src/v1/index.ts` + +**Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. + +**Total weird names flagged:** 34 + +--- + +## Summary table + +| # | Severity | Location | Name | Category | +|----|----------|-----------------------------------|--------------------------------------------------------------|----------------------------------------------| +| 1 | High | package + dir | `modelservingquery` / `@databricks/sdk-modelservingquery` | Duplicate concept; "query" overloaded SDK-wide | +| 2 | High | `model.ts` interface | `QueryEndpointInput` / `QueryEndpointResponse` | Vague; mixes verb-as-noun ("Query") and 4 unrelated payload shapes | +| 3 | High | `model.ts` field | `QueryEndpointInput.name` | Generic field name losing meaning (= endpoint name) | +| 4 | High | `model.ts` field | `QueryEndpointInput.input` / `inputs` / `instances` / `prompt` / `messages` / `dataframeRecords` / `dataframeSplit` | 7 mutually-exclusive "input" fields, no oneof | +| 5 | High | `model.ts` field | `QueryEndpointInput.n` | Cryptic abbreviation (single letter) | +| 6 | High | `model.ts` enum | `EmbeddingsV1ResponseEmbeddingElementObject` | Overly verbose (5 nouns + version + suffix) | +| 7 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name | +| 8 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked + redundant word ("Embedding Element") | +| 9 | High | `model.ts` enum value | `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` | Enum value = type prefix; tautology | +| 10 | High | `model.ts` interface (×2) | `QueryEndpointInput_ExtraParamsEntry` / `QueryEndpointInput_UsageContextEntry` | Underscore in TS identifier; Go/Java-style nested-message names | +| 11 | High | `model.ts` enum values | `CHAT_MESSAGE_ROLE_UNSPECIFIED` / `QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED` / `EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED` | Long enum values (proto sentinel leak) | +| 12 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | +| 13 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | +| 14 | Medium | `model.ts` interface | `DataframeSplitInput` | Generic field names lose meaning (`index`, `columns`, `data`) | +| 15 | Medium | `model.ts` field | `QueryEndpointResponse.data` | Vague (it's the *embeddings* array, not arbitrary data) | +| 16 | Medium | `model.ts` field | `QueryEndpointResponse.object` | Reserved-word collision (`Object` is a JS built-in) | +| 17 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | +| 18 | Medium | `model.ts` field | `QueryEndpointResponse.created` | Verb-tense / underspecified ("created" timestamp typed as `number`) | +| 19 | Medium | `model.ts` field | `QueryEndpointResponse.servedModelName` | Generic name (wire form `served-model-name` with hyphen) | +| 20 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | +| 21 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | +| 22 | Medium | `model.ts` field | `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` | Type-suffix tautology — every field carries `Tokens` | +| 23 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | +| 24 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | +| 25 | Medium | `model.ts` field | `QueryEndpointInput.stop` | Reserved-word feel (verb-as-noun used as field) | +| 26 | Medium | `model.ts` field | `QueryEndpointInput.stream` | Reserved-word feel (collides with web-stream `ReadableStream`) and field is `boolean`, not a stream | +| 27 | Medium | `model.ts` field | `QueryEndpointInput.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | +| 28 | Medium | `model.ts` field | `QueryEndpointInput.usageContext` | Vague pair with `extraParams`; both `Record` | +| 29 | Medium | `model.ts` field | `QueryEndpointInput.maxTokens` | Inconsistent with wire form `max_tokens` re-exposed in marshal mapper | +| 30 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | +| 31 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 32 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | +| 33 | Low | `model.ts` schema | `marshalQueryEndpointInputSchema` / `unmarshalQueryEndpointResponseSchema` | Go/Java-style "marshal/unmarshal" verbs in TS (codified at generator) | +| 34 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | + +--- + +## High severity + +### 1. `modelservingquery` / `@databricks/sdk-modelservingquery` — duplicate concept + +**Location:** `package.json`, directory `packages/modelservingquery/` + +**Categories:** 1 (vague), 12 (duplicate concept across packages), 7 (overly verbose) + +``` +packages/modelservingquery/ ← model inference path +packages/queries/ ← SQL alert queries +packages/queryexecution/ ← published-dashboard SQL execution +packages/queryhistory/ ← SQL query history +packages/servingendpoints/ ← CRUD for serving endpoints +``` + +The word **query** is reused across four unrelated SDK packages. In SQL-land (`queries`, `queryexecution`, `queryhistory`) a "query" is a SQL statement. In this package a "query" is *inference against an LLM/MLflow model* — i.e., a single HTTP POST to `/invocations`. The two meanings have nothing in common, but `import { Client } from '@databricks/sdk-modelservingquery/v1'` and `import { Client } from '@databricks/sdk-queryexecution/v1'` will appear side-by-side in user code. + +The Go SDK calls the corresponding service `serving.QueryEndpoint` (a verb-prefixed call inside the `serving` package, not a standalone package). The TS port hoists `QueryEndpoint` to a top-level package and concatenates the prefix `modelserving` + the verb `query`, producing a name that reads as a noun ("model serving query") but is actually verb-phrase. A clearer split would be either: + +- Fold into `servingendpoints` as a method (matches Go). +- Rename the package to `inference`, `invocations`, or `modelservinginvoke` — names that nobody else in the SDK uses. + +The package name is the most consequential naming choice in the audit; every type below inherits its ambiguity. + +### 2. `QueryEndpointInput` / `QueryEndpointResponse` — vague type name + verb-as-noun + +**Location:** `src/v1/model.ts:76-139`, `153-183` + +**Categories:** 1 (vague), 7 (overly verbose), 14 (Go/Java-style) + +```ts +export interface QueryEndpointInput { + name?: string | undefined; + prompt?: JsonValue | undefined; + input?: JsonValue | undefined; + messages?: ChatMessage[] | undefined; + // ... 14 more fields, mutually exclusive across 4 payload shapes +} +``` + +The single request type encodes **four** different request shapes: + +- **Chat:** `messages`, `temperature`, `stop`, `maxTokens`, `n`, `stream`, `extraParams`. +- **Completions:** `prompt`, same modifiers. +- **Embeddings:** `input`, `extraParams`. +- **Traditional ML:** `dataframeRecords` / `dataframeSplit` / `instances` / `inputs`. + +`QueryEndpointInput` is the *whole envelope*, not a single input. The name says "input" but the field `input` also exists, and `inputs` exists, and `instances` exists. The user constructing this type has to know which combination is valid — TS gives no help. + +Better: split into `ChatQueryRequest`, `CompletionsQueryRequest`, `EmbeddingsQueryRequest`, `TraditionalModelQueryRequest`, and have the client expose four methods (or a discriminated union). + +`QueryEndpointResponse` has the same problem in mirror image: `choices` (chat/completions), `data` (embeddings), `predictions` (traditional), `outputs` (feature serving). The Go SDK has the same union, so the smell is inherited from the wire protocol. + +### 3. `QueryEndpointInput.name` — generic field name losing meaning + +**Location:** `src/v1/model.ts:77-78` + +**Categories:** 15 (generic field names), 19 (underspecified IDs) + +```ts +/** The name of the serving endpoint. This field is required and is provided via the path parameter. */ +name?: string | undefined; +``` + +`name` on a `QueryEndpointInput` is unrelated to the *model* name, the *served-model* name (which appears in the response), the *user* name, or the *organisation* name — it's specifically the *serving endpoint* name, which then becomes a URL path segment. JSDoc clarifies but the field doesn't. `endpointName` would match the existing `servedModelName` field in `QueryEndpointResponse`. Also: the field is typed `string | undefined` but is required by JSDoc — and the client falls back to `req.name ?? ''`, silently producing a malformed URL when missing. + +### 4. Seven mutually-exclusive "input" fields with no discriminator + +**Location:** `src/v1/model.ts:79-134` + +**Categories:** 4 (singular/plural confusion), 15 (generic field name), 17 (inconsistent verbs/nouns) + +| Field | Used by | Type | +|-------------------|--------------|---------------------------| +| `prompt` | completions | `JsonValue` | +| `input` | embeddings | `JsonValue` | +| `messages` | chat | `ChatMessage[]` | +| `dataframeRecords`| traditional | `JsonValue[]` | +| `dataframeSplit` | traditional | `DataframeSplitInput` | +| `instances` | traditional | `JsonValue[]` | +| `inputs` | traditional | `JsonValue` | + +Note the singular/plural near-collision `input` (embeddings) vs `inputs` (tensor columnar) — the *plural* refers to a single object (columnar map), and the *singular* refers to potentially a list of strings. This is the textbook trap the audit checklist calls out as "Singular/plural mismatches." + +A user writing TS sees seven optional fields and has to read four JSDoc paragraphs to figure out which one to set. A discriminated union (`payload: { kind: 'chat'; messages: ... } | { kind: 'completions'; prompt: ... } | ...`) would make invalid combinations impossible. + +### 5. `QueryEndpointInput.n` — cryptic single-letter field + +**Location:** `src/v1/model.ts:110-115` + +**Category:** 5 (cryptic abbreviation) + +```ts +/** + * The n (number of candidates) field used ONLY for __completions__ and __chat external & foundation model__ + * serving endpoints. This is an integer between 1 and 5 with a default of 1 ... + */ +n?: number | undefined; +``` + +`n` is the wire-format shorthand inherited from the OpenAI API. In TS it parses as a counter loop variable. `numCandidates`, `candidateCount`, or even `numChoices` (matching the response's `choices` field) would be self-describing. The JSDoc literally has to explain what `n` means ("(number of candidates)"). + +### 6. `EmbeddingsV1ResponseEmbeddingElementObject` — overly verbose enum + +**Location:** `src/v1/model.ts:25-29` + +**Categories:** 7 (overly verbose), 8 (redundant suffixes) + +```ts +/** This will always be 'embedding'. */ +export enum EmbeddingsV1ResponseEmbeddingElementObject { + EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED = 'EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED', + EMBEDDING = 'EMBEDDING', +} +``` + +The name parses as 6 concatenated words: `Embeddings` + `V1` + `Response` + `Embedding` + `Element` + `Object`. "Embedding" appears twice; the version segment `V1` is leaked from the directory hierarchy into the type name; the `Element` suffix adds no semantic content. The same redundancy will recur in any future enum generated against this wire shape. + +### 7. `V1ResponseChoiceElement` — version segment in type name + +**Location:** `src/v1/model.ts:185-196` + +**Categories:** 7 (overly verbose), 14 (Go/Java-style names) + +```ts +export interface V1ResponseChoiceElement { ... } +``` + +The `V1` prefix duplicates the directory it lives in (`src/v1/`). When a hypothetical v2 ships, the type will be either `V2ResponseChoiceElement` (now-impossible name collision with whatever the new shape is called) or renamed (breaking change). The `Element` suffix is also empty — the type is the choice itself, not an "element of a choice." `Choice` (no prefix, no suffix) would suffice — `QueryEndpointResponse.choices: Choice[]` reads cleanly. v2-style versioning should live exclusively in the import path, not in identifiers. + +### 8. `EmbeddingsV1ResponseEmbeddingElement` — version leak + double "Embedding" + +**Location:** `src/v1/model.ts:58-65` + +**Categories:** 7 (overly verbose), 8 (redundant suffixes) + +```ts +export interface EmbeddingsV1ResponseEmbeddingElement { + embedding?: number[] | undefined; + index?: number | undefined; + object?: EmbeddingsV1ResponseEmbeddingElementObject | undefined; +} +``` + +Same `V1` leak as finding #7, plus the word "Embedding" appears in `EmbeddingsV1` (plural prefix), `EmbeddingElement` (suffix), and in the field name `embedding` (singular). `Embedding` (the type name) and `vector` (the field name) would convey the same data without repetition. Pairs with finding #6 — the same enum sits inside this type. + +### 9. `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` — enum value = prefix tautology + +**Location:** `src/v1/model.ts:27-28` + +**Category:** 20 (type-suffix tautology in enums) + +```ts +EMBEDDING = 'EMBEDDING', +``` + +The only real enum value spells the same word that opens the enum's name. The path to use this is `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` — five "embedding"-derived tokens to express a constant. + +### 10. `QueryEndpointInput_ExtraParamsEntry` / `QueryEndpointInput_UsageContextEntry` — Go/Java nested-message names + +**Location:** `src/v1/model.ts:141-151` + +**Categories:** 4 (underscores in TS identifiers), 14 (Go/Java-style names) + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface QueryEndpointInput_ExtraParamsEntry { + key?: string | undefined; + value?: string | undefined; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface QueryEndpointInput_UsageContextEntry { + key?: string | undefined; + value?: string | undefined; +} +``` + +These two types: + +1. Use underscores in their names, which requires a lint suppression on every declaration. +2. Are the proto-generated `map` entry types — they only ever appear in the wire format, never in TS user code (the marshal/unmarshal schemas correctly use `Record`). +3. Are byte-for-byte clones (`key?: string; value?: string;`). +4. Are exported from `index.ts` (line 17-18) — visible to every consumer who imports `@databricks/sdk-modelservingquery/v1`. + +They should not appear in TS at all. They are generator artefacts. + +### 11. Long enum sentinels (`*_UNSPECIFIED`) + +**Location:** `src/v1/model.ts:19`, `27`, `36` + +**Categories:** 18 (long enum values), 14 (proto sentinels leak) + +```ts +CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', +EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED = 'EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED', +QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED = 'QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED', +``` + +Three enums each carry a `*_UNSPECIFIED` value whose wire form repeats the full type name. The longest is 56 characters. These are protobuf-required sentinels that have no meaning in TS — `undefined` is the natural absent value. They appear in the exhaustive list a user must handle in a `switch` over `ChatMessageRole`. The pattern is generator-wide; flag at generator. + +### 12. `ExternalModelUsageElement` — misleading scope + meaningless suffix + +**Location:** `src/v1/model.ts:67-74` + +**Categories:** 6 (misleading names), 8 (redundant suffixes), 16 (field contradicting type domain) + +```ts +export interface ExternalModelUsageElement { + /** The number of tokens in the prompt. */ + promptTokens?: number | undefined; + /** The number of tokens in the chat/completions response. */ + completionTokens?: number | undefined; + /** The total number of tokens in the prompt and response. */ + totalTokens?: number | undefined; +} +``` + +Two problems: + +1. **"External" is misleading.** This type is the OpenAI-spec `usage` block, returned by Databricks Foundation Model and Databricks Provisioned Throughput endpoints — both of which are **internal** Databricks-managed models. JSDoc in `QueryEndpointResponse.usage` even says "external/foundation model", but Databricks Foundation Models are explicitly *first-party*. The "External" prefix mislabels its scope. +2. **"Element" is meaningless.** The type is the single usage block, not "an element of a list." `TokenUsage`, `Usage`, or `ModelUsage` would suffice. + +Pairs with finding #22 (every field redundantly ends in `Tokens`). + +--- + +## Medium severity + +### 13. `query()` — verb-tense / reserved-word feel + +**Location:** `src/v1/client.ts:58-81` + +**Categories:** 13 (verb-tense), 10 (reserved-word collision), 17 (inconsistent action verb) + +```ts +/** Query a serving endpoint */ +async query(req: QueryEndpointInput, options?: CallOptions): Promise { ... } +``` + +The method is named `query` — a verb that doubles as the common SQL noun, and that already exists as a method on `IDBDatabase` and on the unrelated `queries` package. `invoke`, `predict`, or `call` would match the underlying REST verb (`POST /invocations`) and would not collide with SQL nomenclature. Also: the method signature omits `endpointName` as a first arg — it has to be supplied inside the input as `req.name`, which conflates the URL parameter with the request body. + +### 14. `DataframeSplitInput` — generic field names lose meaning + +**Location:** `src/v1/model.ts:49-56` + +**Categories:** 15 (generic field name), 14 (Pandas-style names) + +```ts +export interface DataframeSplitInput { + index?: number[] | undefined; + columns?: JsonValue[] | undefined; + data?: JsonValue[] | undefined; +} +``` + +The three field names `index`, `columns`, `data` are pulled verbatim from `pandas.DataFrame.to_dict(orient='split')`. In TS they read as a generic key-value bag with no hint that they form a tightly-coupled triple. `index` collides with `EmbeddingsV1ResponseEmbeddingElement.index` and `V1ResponseChoiceElement.index` (three different "index" fields in the same package, all `number`-typed). `columns` is `JsonValue[]` (column *names*, despite the JSON-value type). `data` is the row data. `rowIndex`, `columnNames`, `rows` would each carry meaning. + +### 15. `QueryEndpointResponse.data` — vague field + +**Location:** `src/v1/model.ts:156-157` + +**Categories:** 15 (generic), 16 (field contradicting type domain) + +```ts +/** The list of the embeddings returned by the __embeddings external/foundation model__ serving endpoint. */ +data?: EmbeddingsV1ResponseEmbeddingElement[] | undefined; +``` + +A response with seven other typed fields (`choices`, `predictions`, `outputs`, `usage`, etc.) and one of them is called `data`. Without JSDoc the field is meaningless. `embeddings` matches the OpenAI spec naming and the element type. + +### 16. `QueryEndpointResponse.object` — JS built-in collision + +**Location:** `src/v1/model.ts:172-176` + +**Category:** 10 (reserved-word collision) + +```ts +object?: QueryEndpointResponseObject | undefined; +``` + +`object` is a JS keyword (the type `object`, used in `typeof x === 'object'`). Field-name access `resp.object` doesn't break, but `const { object } = resp` shadows the global type. The OpenAI wire format uses `object` for the same field; idiomatic TS would rename to `objectType`, `kind`, or `responseType`. + +### 17. Four mutually-exclusive output fields, no oneof + +**Location:** `src/v1/model.ts:153-183` + +**Categories:** 4 (singular/plural), 17 (inconsistent verbs/nouns), 15 (generic names) + +| Field | Used by | Element type | +|---------------|----------------------|-------------------------------------------| +| `choices` | chat / completions | `V1ResponseChoiceElement[]` | +| `data` | embeddings | `EmbeddingsV1ResponseEmbeddingElement[]` | +| `predictions` | traditional ML | `JsonValue[]` | +| `outputs` | feature serving | `JsonValue[]` | + +Mirror of finding #4 on the response side. The TS user has to know which field will be populated given which input was sent. A discriminated union would be more honest. + +### 18. `QueryEndpointResponse.created` — verb tense + underspecified + +**Location:** `src/v1/model.ts:170-171` + +**Categories:** 13 (verb-tense inconsistency), 15 (generic field name) + +```ts +/** The timestamp in seconds when the query was created in Unix time returned by a __completions or chat external/foundation model__ serving endpoint. */ +created?: number | undefined; +``` + +`created` is a past-tense verb used as a noun. Most TS codebases use `createdAt` / `createTime`. Typed `number` (Unix seconds), not `Temporal.Instant` like the rest of the SDK uses for timestamps. Pairs poorly with the response shape — `resp.created` reads as a boolean assertion. + +### 19. `QueryEndpointResponse.servedModelName` — wire format leak + +**Location:** `src/v1/model.ts:181-183`, marshalled from `'served-model-name'` (line 252, 264) + +**Categories:** 4 (wire-format-driven naming), 19 (underspecified IDs) + +```ts +servedModelName?: string | undefined; +``` + +JSON wire field is `served-model-name` (with hyphens) — the only hyphenated field in the whole package. In TS, "served model name" parses ambiguously: is it the *name* of the served-model resource, the *served-model identifier*, the *display name*, or the *model URI*? `servedEntityName` matches the `servingendpoints` package's `ServedEntity` type; `servedModelId` would explicitly mark it as a foreign key. + +### 20. `V1ResponseChoiceElement.text` / `.message` — singular vs plural mismatch + +**Location:** `src/v1/model.ts:185-196` + +**Categories:** 9 (singular/plural mismatches) + +```ts +export interface V1ResponseChoiceElement { + text?: string | undefined; // completions response + message?: ChatMessage | undefined; // chat response + ... +} +``` + +The *request* uses `messages: ChatMessage[]` (plural array). The *response* `Choice` carries a singular `message: ChatMessage`. That's correct because each choice is one message — but `messageS` request and `message` response with the same element type invites confusion. Pair this with `text` (chat completions response) vs `prompt` (completions request) and the asymmetry is real. + +### 21. `ChatMessageRole` enum — singular/plural odd + +**Location:** `src/v1/model.ts:17-23` + +**Category:** 9 (singular/plural mismatches) + +```ts +/** The role of the message. One of [system, user, assistant]. */ +export enum ChatMessageRole { + CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', + SYSTEM = 'SYSTEM', + USER = 'USER', + ASSISTANT = 'ASSISTANT', +} +``` + +The values are not types of "chat message" — they are types of speaker / agent. `ChatRole` (drop `Message`) would parse more naturally because the *role* belongs to the *speaker*, not the *message*. The OpenAI vocabulary that this mirrors uses `role` (not `messageRole`) for the same reason. + +### 22. `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` — tautology + +**Location:** `src/v1/model.ts:67-74` + +**Category:** 20 (type-suffix tautology in fields) + +```ts +export interface ExternalModelUsageElement { + promptTokens?: number | undefined; + completionTokens?: number | undefined; + totalTokens?: number | undefined; +} +``` + +Every field carries the `Tokens` suffix. Once you've established the type is `TokenUsage`, the inner fields can be `prompt`, `completion`, `total`. The unit is implicit. The current shape is `usage.promptTokens` (10 chars), the cleaner form is `usage.prompt` (5 chars). When *every* field repeats the unit, the unit is part of the type, not the field. + +### 23. `V1ResponseChoiceElement.logprobs` — cryptic + wrong type + +**Location:** `src/v1/model.ts:194-195` + +**Categories:** 5 (cryptic abbreviation), 6 (misleading types) + +```ts +/** The logprobs returned only by the __completions__ endpoint. */ +logprobs?: number | undefined; +``` + +`logprobs` is a verbatim OpenAI shorthand for "log probabilities." Two issues: + +1. `logProbabilities` would be readable. +2. Typed `number` (a single number). The OpenAI spec for `logprobs` returns an *object* containing per-token log probabilities, top-k alternatives, and text offsets. The wire response is being shoe-horned into a scalar — either the type is wrong, or the field name is wrong. + +### 24. `V1ResponseChoiceElement.finishReason` — underspecified + +**Location:** `src/v1/model.ts:192-193` + +**Categories:** 4 (string-typed enum) + +```ts +/** The finish reason returned by the endpoint. */ +finishReason?: string | undefined; +``` + +In practice the value is always one of `"stop"`, `"length"`, `"content_filter"`, `"tool_calls"`, `"function_call"`. Typed as `string` instead of an enum — the user has no IDE help. The field name itself is fine; the absence of an enum is the smell. + +### 25. `QueryEndpointInput.stop` — reserved-word feel + +**Location:** `src/v1/model.ts:100-104` + +**Category:** 10 (reserved-word collisions) + +```ts +stop?: string[] | undefined; +``` + +`stop` is an imperative verb used as a noun. `stopSequences` (which the JSDoc literally calls them — "The stop sequences field") would be self-describing. The naming inherits from the OpenAI wire spec. + +### 26. `QueryEndpointInput.stream` — collides with web streams + +**Location:** `src/v1/model.ts:117-120` + +**Category:** 10 (reserved-word collisions), 16 (field contradicting type domain) + +```ts +stream?: boolean | undefined; +``` + +The field is a boolean ("do you want a streamed response?"). The name `stream` in TS evokes `ReadableStream` / `WritableStream`. The client method doesn't actually implement streaming — there's no `AsyncIterable` return type — so setting `stream: true` will produce a malformed buffered response. `useStreamingResponse` or `streaming` (adjective, not noun) would avoid the type collision. + +### 27. `QueryEndpointInput.extraParams` — vague + +**Location:** `src/v1/model.ts:121-126` + +**Categories:** 1 (vague), 6 (misleading types) + +```ts +/** The extra parameters field used ONLY for __completions, chat,__ and __embeddings external & foundation + * model__ serving endpoints. ... */ +extraParams?: Record | undefined; +``` + +"Extra" relative to what? The 8 other fields already on `QueryEndpointInput` are the "main" params; everything else falls through to here. `passthroughParams`, `modelParams`, or `externalParamsOverride` would be clearer. Also: typed `Record` — but OpenAI's "extra params" semantically include `top_p` (number), `presence_penalty` (number), and `tools` (array). The string-only typing forces stringification of values that should be passed through as JSON. + +### 28. `QueryEndpointInput.usageContext` — vague pair + +**Location:** `src/v1/model.ts:135-138` + +**Category:** 1 (vague) + +```ts +/** Optional user-provided context that will be recorded in the usage tracking table. */ +usageContext?: Record | undefined; +``` + +Pairs with #27 (both are open-ended string maps). "Usage context" is ambiguous: usage of what? Context for what? The JSDoc says "recorded in the usage tracking table" — a clearer name would be `usageMetadata` or `trackingContext`. + +### 29. `QueryEndpointInput.maxTokens` — inconsistent wire mapping + +**Location:** `src/v1/model.ts:105-109`; mapped to wire `max_tokens` on line 332 + +**Categories:** 4 (underscores), 9 (singular/plural) + +```ts +maxTokens?: number | undefined; // TS +// → max_tokens // wire JSON +``` + +The TS form is camelCase, the wire form is snake_case (correct). The TS field is plural `maxTokens`, but it accepts a single number (the maximum *count* of tokens). Plural-counter naming is conventional in OpenAI-land, so this is a low-grade issue, but it pairs poorly with `promptTokens` / `completionTokens` / `totalTokens` (all counts of tokens, also plural — at least the package is internally consistent here). + +--- + +## Low severity + +### 30. JSDoc `/** Query a serving endpoint */` — verb tense / no period + +**Location:** `src/v1/client.ts:57` + +**Categories:** 13 (verb-tense inconsistency), project rule (sentences end with period) + +```ts +/** Query a serving endpoint */ +async query(...) { ... } +``` + +Imperative verb, no terminal punctuation. Project rule (`CLAUDE.md`) requires comments to be sentences ending with a period. `/** Queries a serving endpoint. */` would match the v2-style JSDoc in other packages (`alerts/src/v2/client.ts` uses third-person singular present). + +### 31. `ChatMessageRole.ASSISTANT` — incomplete enum + +**Location:** `src/v1/model.ts:17-23` + +**Category:** 6 (misleading names), 9 (singular/plural) + +```ts +export enum ChatMessageRole { + ... + SYSTEM = 'SYSTEM', + USER = 'USER', + ASSISTANT = 'ASSISTANT', +} +``` + +Three values, but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 3 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. + +### 32. `EmbeddingsV1ResponseEmbeddingElement.index` — underspecified + +**Location:** `src/v1/model.ts:62-63` + +**Category:** 19 (underspecified IDs) + +```ts +/** The index of the embedding in the response. */ +index?: number | undefined; +``` + +`index` without qualification: index inside what? `responseIndex`, `embeddingIndex`, or `position` would be specific. Pairs with `V1ResponseChoiceElement.index` and `DataframeSplitInput.index` — three "index" fields with three different meanings. + +### 33. `marshal*Schema` / `unmarshal*Schema` — Go/Java idiom + +**Location:** `src/v1/model.ts:198-342` + +**Category:** 14 (Go/Java-style names) + +```ts +export const unmarshalChatMessageSchema: z.ZodType = ... +export const marshalChatMessageSchema: z.ZodType = ... +``` + +`marshal`/`unmarshal` are Go-flavoured verbs. Idiomatic TS uses `serialize`/`deserialize` or `encode`/`decode` (Zod itself uses `parse` / `safeParse`). The pattern is codified across the entire generated SDK, so this is a generator-level concern rather than a per-package fix. Also note the `Schema` suffix on Zod consts is tautological — `unmarshalChatMessage` would be enough, or simply colocate the zod schema with the type. + +### 34. `flattenQueryParams` — orphaned export with conflicting "Query" + +**Location:** `src/v1/utils.ts:123-150` + +**Categories:** 1 (vague), 12 (duplicate concept), 17 (orphan) + +```ts +export function flattenQueryParams( + prefix: string, + value: unknown, + params: URLSearchParams +): void { ... } +``` + +Two issues: + +1. **Not used by the client** — `client.ts` only POSTs a body, never sets URL query parameters. The function is dead code at the package level (generator artefact). +2. **"Query" is conflated.** Inside this package the word "query" refers to *inference*, but here it means *URL query string parameters*. A reader who has just internalised "query = inference" will misread the function's purpose. `flattenUrlSearchParams` would dodge the collision. + +--- + +## Observations + +1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (4, 17, 20). + +2. **Wire-format leakage is severe.** Wire-format names show up almost verbatim in TS: `n`, `stop`, `stream`, `logprobs`, `object`, `data`, `extra_params`, `served-model-name`, `*_UNSPECIFIED`, `EmbeddingsV1ResponseEmbeddingElement`. The Go SDK shares the smell, but Go's `query_endpoint` request becomes `QueryEndpointInput` in TS, where TS users have no way to distinguish the four valid combinations. + +3. **Version-segment leak.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, and `EmbeddingsV1ResponseEmbeddingElementObject` all carry the literal string `V1` in the *type* name. The directory is already `src/v1/`. Other packages in the SDK (e.g., `alerts`) do not carry `V1`/`V2` segments in type names — those have explicit `v1` / `v2` directories instead, with the version expressed at the package-import path level. This package is inconsistent with that convention. + +4. **Proto-style nested-message clones.** The two `_Entry` types (`QueryEndpointInput_ExtraParamsEntry`, `QueryEndpointInput_UsageContextEntry`) are the protobuf "map entry" wire types leaking through. They are dead code in TS — the marshal/unmarshal schemas use `Record`. They should not be exported from `index.ts`. + +5. **"Element" is the canonical empty suffix.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, `ExternalModelUsageElement` all carry the suffix `Element`. None of them are array elements in any structural sense — they are first-class types. The suffix is a Go convention for "value type inside a repeated field"; it adds noise in TS. + +6. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInput` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. + +7. **`utils.ts` is identical across packages.** The file is byte-for-byte the same as in `alerts/src/v1/utils.ts`, `endpoints/src/v1/utils.ts`, etc. The single domain-specific export, `flattenQueryParams`, is dead in this package. + +8. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInput, options?: CallOptions)` would catch the missing path parameter at the type level. + +9. **No streaming support despite `stream: boolean`.** `QueryEndpointInput.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. + +--- + +## v1-only + +This package has only `v1`. There is no v2 to diff against. Several names visibly anticipate a v2 (`V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`), but the version is also baked into the directory and package export path. If/when v2 ships, those leaked version segments will have to be renamed *and* moved. + +--- + +## Domain glossary + +| Term | Meaning in this package | +|--------------------------------|--------------------------------------------------------------------------------------------| +| Serving endpoint | A deployed Databricks model serving resource (an "/endpoints/{name}/invocations" URL). | +| Query (verb) | A single inference call (POST). **Not** a SQL query. | +| Query endpoint | The "/invocations" REST resource; the only method in the package. | +| External model | Confusingly, this includes Databricks Foundation Models (which are first-party). Used to distinguish from user-deployed MLflow models. | +| Foundation model | A first-party (typically open-source, hosted by Databricks) LLM. | +| Choice | One generated response in a chat or completions reply (mirrors OpenAI). | +| Embedding | A vector of floats representing the input text (mirrors OpenAI). | +| Logprobs | Log probabilities of generated tokens. Mistyped as `number` in this package. | +| `n` (in `QueryEndpointInput`) | "Number of candidates" (mirrors OpenAI's `n`). | +| Usage context | Free-form metadata recorded in the model-serving usage tracking table. | +| Extra params | Free-form parameters passed through to the underlying model API. | +| Served model | One model behind a serving endpoint (an endpoint can host several with traffic split). | +| Dataframe split / records | Two of `pandas.DataFrame.to_dict`'s orientations, used for traditional MLflow models. | +| Instances / inputs | Tensor-input shapes — `instances` is row-major, `inputs` is column-major. | + +--- + +## File coverage + +| File | Lines | Read in full | +|-------------------|-------|--------------| +| `src/v1/model.ts` | 343 | yes | +| `src/v1/client.ts`| 83 | yes | +| `src/v1/utils.ts` | 151 | yes | +| `src/v1/index.ts` | 22 | yes | diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md new file mode 100644 index 00000000..2e82b928 --- /dev/null +++ b/.agent/naming-audit/notificationdestinations.md @@ -0,0 +1,383 @@ +# Naming Audit: notificationdestinations + +**Path:** `packages/notificationdestinations/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. +**Total weird names flagged:** 26 + +## Summary + +| Severity | Count | +| --- | --- | +| High | 6 | +| Medium | 9 | +| Low | 7 | +| Observation | 4 | + +## Summary table + +| # | Severity | Location | Name | Category | +|---|----------|----------|------|----------| +| 1 | High | `model.ts:5-11` | `DestinationType` | 1 (vague), 2 (redundant enum prefix) | +| 2 | High | `model.ts:5-11` | `DestinationType.PAGERDUTY` / `MICROSOFT_TEAMS` | 3 (acronym casing inconsistency) | +| 3 | High | `model.ts:8` | `DestinationType.WEBHOOK` (vs `GenericWebhookConfig`) | 6 (misleading), 12 (duplicate concept name mismatch) | +| 4 | High | `model.ts:13-21` | `Config` (type) and `Config.config` (field) | 1 (vague), 9 (self-referential) | +| 5 | High | `model.ts:117` | `PagerdutyConfig` (type) and `pagerduty` ($case) | 3 (acronym casing inconsistency) | +| 6 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | +| 7 | Medium | `model.ts:46`, `:50`, `:54`, `:87` etc. | `urlSet` / `usernameSet` / `passwordSet` / `appIdSet` / `authSecretSet` / `channelUrlSet` / `tenantIdSet` / `integrationKeySet` / `oauthTokenSet` / `channelIdSet` | 6 (misleading), 15 (generic field naming pattern) | +| 8 | Medium | `model.ts:23-28` / `:139-146` | `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` | 7 (overly verbose), 8 (redundant `Request` suffix conjoined with full noun phrase) | +| 9 | Medium | `model.ts:66-70` | `ListNotificationDestinationsResponse` | 7 (overly verbose), 8 (redundant `Response` suffix) | +| 10 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | +| 11 | Medium | `client.ts:186-201` | `listNotificationDestinationsIter` | 5 (cryptic abbreviation `Iter`) | +| 12 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | +| 13 | Medium | `model.ts:73`, `:107` | `id` (UUID) | 19 (underspecified ID) | +| 14 | Medium | `model.ts:118` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | +| 15 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | +| 16 | Low | `model.ts:5-11` | enum values are SCREAMING_SNAKE_CASE in TS | 4 (underscores in TS identifier strings) | +| 17 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | +| 18 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | +| 19 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | +| 20 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | +| 21 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | +| 22 | Low | `utils.ts:113`, `:119` | `parseResponse` / `marshalRequest` verb mismatch | 17 (inconsistent action verbs) | +| 23 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 24 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 25 | Obs | `index.ts:5-23` | Re-exports the verbose names verbatim, no friendlier aliases | — | +| 26 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | + +## High severity + +### 1. `DestinationType` — vague enum name lacks domain anchor — `src/v1/model.ts:5-11` +- **Code:** + ```ts + export enum DestinationType { + SLACK = 'SLACK', + EMAIL = 'EMAIL', + WEBHOOK = 'WEBHOOK', + PAGERDUTY = 'PAGERDUTY', + MICROSOFT_TEAMS = 'MICROSOFT_TEAMS', + } + ``` +- **Why weird:** Exported at package root as just `DestinationType`. The word "destination" is overloaded across the SDK — there is a `destination` concept in jobs (`webhook destination`), workflows (`sink destination`), and infra (`DBFS destination`). A user `import { DestinationType } from '@databricks/sdk-notificationdestinations/v1'` and then mixing it with `import { DestinationType } from '@databricks/sdk-pipelines/v1'` (if it existed) will get a name collision. Also, the values are not "destination types" but "notification channels"; the enum mixes the term-of-art ("destination" = the addressable target) with the type-of-target. Compare with `notification-destinations` REST path: the enum could be `NotificationChannel` or `NotificationDestinationKind`. +- **Category:** 1 (vague/generic), 2 (the enum prefix `Destination` is redundant with the field name `destinationType` — see also finding 15). +- **Suggested name:** `NotificationChannel` (mirrors how the Go SDK names protobuf enums for kindred resources) or, less invasive, `NotificationDestinationType`. +- **Rationale:** Domain-anchored enum names protect users from cross-package collisions and read better in IDE autocomplete (`NotificationChannel.SLACK` vs `DestinationType.SLACK`). + +### 2. `DestinationType.PAGERDUTY` and `.MICROSOFT_TEAMS` — acronym/brand casing inconsistency — `src/v1/model.ts:9-10` +- **Code:** + ```ts + PAGERDUTY = 'PAGERDUTY', + MICROSOFT_TEAMS = 'MICROSOFT_TEAMS', + ``` +- **Why weird:** Inside this package the brand "PagerDuty" appears in **five** different casings: + - `DestinationType.PAGERDUTY` (all caps, no separator) — enum value (line 9). + - `{$case: 'pagerduty', pagerduty: ...}` (all lower) — oneof discriminant + field (line 18). + - `PagerdutyConfig` (TitleCase but **not** `PagerDutyConfig`) — interface name (line 117). + - `pagerduty` (wire) — JSON key (lines 155, 172, 282). + - `PagerDuty` (TitleCase with internal D) — JSDoc prose only (line 118 "Integration key for PagerDuty"). + + The same applies to Microsoft Teams: `MICROSOFT_TEAMS`, `microsoftTeams` ($case), `MicrosoftTeamsConfig`, `microsoft_teams` (wire). Only the wire and JSDoc are externally fixed; the TS identifier choices `Pagerduty` (vs `PagerDuty`) and `MicrosoftTeams` (already correct) are an internal choice — and they are not consistent with the brand. The TS Style Guide is explicit: brand acronyms keep their canonical casing in identifiers (PagerDuty, GitHub, GraphQL). `Pagerduty` reads as a typo. +- **Category:** 3 (acronym casing inconsistency). +- **Suggested name:** `PagerDutyConfig` (interface), `PagerDuty = 'PAGERDUTY'` (enum value can keep wire string but the **identifier** should be `PagerDuty` if mixed-case enum names were used; SCREAMING_SNAKE is wire-faithful, see finding 16). For consistency at minimum rename `PagerdutyConfig` → `PagerDutyConfig` and the `$case: 'pagerduty'` → `$case: 'pagerDuty'`. +- **Rationale:** Brand names are part of the public API surface; users reading IDE autocomplete should see `PagerDutyConfig` matching the company's own capitalisation. The cost is one schema rename across `unmarshalConfigSchema`'s discriminator strings — the wire JSON key stays `pagerduty`. + +### 3. `DestinationType.WEBHOOK` corresponds to `GenericWebhookConfig` — misleading enum vs config asymmetry — `src/v1/model.ts:8`, `:42-55`, `:17` +- **Code:** + ```ts + // enum value + WEBHOOK = 'WEBHOOK', + // config type + export interface GenericWebhookConfig { ... } + // discriminator + | {$case: 'genericWebhook'; genericWebhook: GenericWebhookConfig} + ``` +- **Why weird:** Of the five channels, four have an enum value that matches their config name in lowercase (`SLACK`/`SlackConfig`, `EMAIL`/`EmailConfig`, `PAGERDUTY`/`PagerdutyConfig`, `MICROSOFT_TEAMS`/`MicrosoftTeamsConfig`). Only the webhook case introduces an unexplained qualifier: the enum says `WEBHOOK`, the config type says `GenericWebhookConfig`. A user is left wondering whether "generic" means "the default kind of webhook" or whether there's a future non-generic webhook config coming. The `$case` discriminant uses `'genericWebhook'`, the wire uses `'generic_webhook'`, but the enum value drops the qualifier entirely. Either the enum should be `GENERIC_WEBHOOK` (matching the config name) or the config should be `WebhookConfig` (matching the enum). +- **Category:** 6 (misleading — name asymmetry across the same channel), 12 (the same conceptual channel has two different names in the same file). +- **Suggested name:** Pick one: rename the enum value to `GENERIC_WEBHOOK` (preferred, preserves the qualifier that distinguishes from MS-Teams' webhook URL), or rename `GenericWebhookConfig` → `WebhookConfig`. +- **Rationale:** The `MicrosoftTeamsConfig` and `GenericWebhookConfig` both have a `url` field that is "a webhook URL" (lines 44, 85), so the qualifier "generic" is genuinely meaningful — it distinguishes the channel-agnostic incoming-webhook target from the Teams-branded webhook. Keep the qualifier, but propagate it to the enum. + +### 4. `Config` (interface) and its `config` field — vague top-level name + self-referential field — `src/v1/model.ts:13-21` +- **Code:** + ```ts + export interface Config { + config?: + | {$case: 'slack'; slack: SlackConfig} + | {$case: 'email'; email: EmailConfig} + | {$case: 'genericWebhook'; genericWebhook: GenericWebhookConfig} + | {$case: 'pagerduty'; pagerduty: PagerdutyConfig} + | {$case: 'microsoftTeams'; microsoftTeams: MicrosoftTeamsConfig} + | undefined; + } + ``` +- **Why weird:** The type name `Config` is one of the most generic identifiers in software. A package-root `Config` export means an app barrel re-exporting `@databricks/sdk-notificationdestinations/v1` collides instantly with any other `Config` (web framework configs, app configs, build configs, …). The user must alias it. Compounding the vagueness, the field inside `Config` is also named `config`, so you read `notificationDestination.config.config.email.addresses` — the same identifier appears twice along the path. +- **Category:** 1 (vague/generic top-level name), 9 (self-referential field name). +- **Suggested name:** Rename the type to `NotificationDestinationConfig` (matches the package's domain prefix). The `$case` discriminator is a generator-specific convention (proto-loader's oneof shape) — a hand-written API would use `kind` or `type`. Flagging because it's user-visible. +- **Rationale:** Discriminated unions are first-class in TS; protobuf oneof wrappers are not. The 1:1 port philosophy preserves the wrapper for marshalling fidelity, but the *name* of the wrapper should at least not be `Config`. + +### 5. `PagerdutyConfig` and `pagerduty` — see #2, separate finding because the `$case` discriminant is also visible to users — `src/v1/model.ts:18`, `:117`, `:280` +- **Code:** see #2. +- **Why weird:** The `$case: 'pagerduty'` string literal is what users *write* when constructing a `Config`: + ```ts + const cfg: Config = { config: { $case: 'pagerduty', pagerduty: { integrationKey: '...' } } }; + ``` + So both the type name `PagerdutyConfig` and the literal `'pagerduty'` are part of the API surface. The lowercase form is fixed (it's the JSON key); the camelCase TS identifier is a choice — and the choice was made to ignore the brand's internal capital. +- **Category:** 3 (acronym casing). +- **Suggested name:** `PagerDutyConfig` (type) and `$case: 'pagerDuty'` (discriminant). Wire JSON stays `pagerduty`. +- **Rationale:** Same as #2 — flagged separately because the discriminant literal is a distinct API element from the interface name. + +### 6. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:42-55` +- **Code:** + ```ts + export interface GenericWebhookConfig { + /** [Input-Only] URL for webhook. */ + url?: string | undefined; + /** [Output-Only] Whether URL is set. */ + urlSet?: boolean | undefined; + /** [Input-Only][Optional] Username for webhook. */ + username?: string | undefined; + ... + } + ``` +- **Why weird:** The qualifier "generic" tells the user nothing concrete. It means "this is the webhook config that is *not* the Microsoft Teams webhook config" — a knowledge that requires reading the whole file. A user looking at IDE autocomplete sees `GenericWebhookConfig` and `MicrosoftTeamsConfig` side-by-side and has to guess that MS-Teams is also a webhook channel that just has more fields. The Go SDK likely also names this type `GenericWebhook` for proto symmetry, but in TS this needs better disambiguation. +- **Category:** 1 (vague — "generic" carries no positive information). +- **Suggested name:** `WebhookConfig` (and rename the enum value to `GENERIC_WEBHOOK` per #3 if you want to preserve the disambiguation from the MS-Teams-webhook). Or be honest and call it `IncomingWebhookConfig` (the actual term-of-art used by Slack/Teams/Discord for this shape). +- **Rationale:** "Generic" is a code smell whenever it appears in a public type name. It usually means "this is the default, but there might be variants" — and TypeScript already has `extends`, intersections, and unions for variants. If the shape is the default, drop the qualifier; if there are real variants, name them after what makes them different (`AuthenticatedWebhookConfig`, etc.). + +## Medium severity + +### 7. `*Set: boolean` companion fields — pervasive pattern with confusing optionality — `src/v1/model.ts:46, 50, 54, 87, 91, 95, 99, 103, 121, 128, 132, 136` +- **Code (representative):** + ```ts + /** [Input-Only] URL for webhook. */ + url?: string | undefined; + /** [Output-Only] Whether URL is set. */ + urlSet?: boolean | undefined; + ``` +- **Why weird:** Every secret field (URL, username, password, OAuth token, integration key, app ID, auth secret, channel URL, tenant ID, channel ID) has a paired `*Set` boolean. The pattern exists because the server cannot echo secrets back, so it tells the client "the secret is set" without disclosing the value. Three problems with the names: + 1. `urlSet` reads as "URL of a set" or "set of URLs" — not "URL is set." Idiomatic TS would be `isUrlSet` or `hasUrl`. + 2. The `*Set` field is `boolean | undefined` — three-valued logic on a property that should be binary. The undefined case is ambiguous: not set, server didn't return it, or you're not an admin? JSDoc doesn't say. + 3. The paired fields are **modal** — on input you set `url`, on output you read `urlSet`. The type system has no way to express this; both fields are simultaneously optional, so a user could try to set `urlSet: true` on input and the server will silently ignore it. +- **Category:** 6 (misleading — three-valued boolean), 15 (generic field-naming pattern losing meaning). +- **Suggested name:** Rename the pattern to `hasUrl`, `hasUsername`, etc. (English-correct boolean predicates). Better: split the input and output types so input has `url` only and output has `hasUrl` only. Or merge into a union: `url?: { write: string } | { read: { isSet: boolean } }`. +- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 24) hint that the type was originally split in the API spec and was flattened for TS. + +### 8. `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` — overly verbose — `src/v1/model.ts:23-28`, `:139-146` +- **Code:** + ```ts + export interface CreateNotificationDestinationRequest { + displayName?: string | undefined; + config?: Config | undefined; + } + export interface UpdateNotificationDestinationRequest { + id?: string | undefined; + displayName?: string | undefined; + config?: Config | undefined; + } + ``` +- **Why weird:** 39 and 40 character identifiers respectively. Inside the package, the verb is already redundant with the method name (`createNotificationDestination(req: CreateNotificationDestinationRequest)`) — the request type name repeats the verb the method also carries. Compare to leaner conventions: `Create(input: NotificationDestination)` or, in TS, just accepting the partial `NotificationDestination` shape and dropping the `Request` types. +- **Category:** 7 (overly verbose), 8 (redundant `Request` suffix conjoined with full noun phrase that is already specific). +- **Suggested name:** Shorter alternatives: `CreateInput`, `UpdateInput` (scoped to the package; relies on `import * as nd from '@databricks/sdk-notificationdestinations/v1'` for disambiguation). Or merge with the response: `accept Partial`. Or, if keeping verbose names, at least drop the `Request` suffix (already implied by being the input to a request). +- **Rationale:** Even in `alerts` (which is heavier), the create/update request types were criticised for this pattern. Worth normalising at the SDK level. + +### 9. `ListNotificationDestinationsResponse` — overly verbose response wrapper — `src/v1/model.ts:66-70` +- **Code:** + ```ts + export interface ListNotificationDestinationsResponse { + results?: ListNotificationDestinationsResult[] | undefined; + /** Page token for next of results. */ + nextPageToken?: string | undefined; + } + ``` +- **Why weird:** Two fields, 41-character type name. The JSDoc says "Page token for next of results" — broken English (should be "Page token for next page of results" or "Page token for the next set of results"). And see #12 for `results`. +- **Category:** 7 (verbose), 8 (`Response` suffix added on top of the verb-prefixed noun phrase). +- **Suggested name:** `ListPage` — a generic page wrapper used across the SDK. Or `NotificationDestinationPage`. + +### 10. `Client` — unprefixed class — `src/v1/client.ts:45` +- **Code:** `export class Client { ... }` +- **Why weird:** Every package in the SDK exports a class named `Client`. A user wiring up two packages (`notificationdestinations` + `alerts`, say) writes: + ```ts + import { Client as NotificationDestinationsClient } from '@databricks/sdk-notificationdestinations/v1'; + import { Client as AlertsClient } from '@databricks/sdk-alerts/v1'; + ``` + every time. The aliasing is universal — every audit raises this finding. +- **Category:** 1 (vague), 12 (cross-package duplication). +- **Suggested name:** `NotificationDestinationsClient`, or expose only the namespace import (`import * as notificationDestinations from '@databricks/sdk-notificationdestinations/v1'`). +- **Rationale:** Cross-SDK consistency, but every consumer pays the rename cost. Worth a generator-level fix. + +### 11. `listNotificationDestinationsIter` — cryptic `Iter` suffix — `src/v1/client.ts:186-201` +- **Code:** + ```ts + async *listNotificationDestinationsIter( + req: ListNotificationDestinationsRequest, + options?: CallOptions + ): AsyncGenerator { ... } + ``` +- **Why weird:** "Iter" is a Go-ism (`Iterator()` method, `iter.Seq2` etc.). In TS the conventional name for an async iterator method is `*` syntax with no special suffix, or `stream*`, or just the verb in the imperative form. `listIter` reads as a typo or an abbreviation; the canonical TS name would be `listAll` (eagerly), `iterAll`, or simply expose it as `[Symbol.asyncIterator]`. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `iterateNotificationDestinations` or `listAllNotificationDestinations` (eager) or `streamNotificationDestinations`. +- **Rationale:** Same finding appears in every paginated client across the SDK (`listAlertsIter`, `listClustersIter`, ...). Generator-level rename. + +### 12. `ListNotificationDestinationsResponse.results` — vague field name — `src/v1/model.ts:67` +- **Code:** + ```ts + results?: ListNotificationDestinationsResult[] | undefined; + ``` +- **Why weird:** "results" is a placeholder name. The field holds notification destinations, so it should be named `destinations` or `notificationDestinations` or `items`. "Results" is what a generator emits when it doesn't know what the list contains; users read it as "search results" or "test results" and have to look at the type to confirm. Compare to the broader SDK convention where list responses use `items` (jobs, runs) or the domain-qualified plural (clusters, alerts). +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `destinations` (drop the `notification` qualifier since the package context supplies it) or `items`. + +### 13. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 73, 107, 140` +- **Code:** + ```ts + /** UUID identifying notification destination. */ + id?: string | undefined; + ``` +- **Why weird:** A bare `id` field at the top of `NotificationDestination`, `ListNotificationDestinationsResult`, and three request types. The JSDoc clarifies it's a UUID, but the field name does not. In a multi-resource SDK, `destinationId` or `notificationDestinationId` would survive a refactor that combines several resources in one collection. Also the field is `string | undefined` even though every endpoint requires it on output and three of four endpoints require it on input — see finding 5 of the billableusagedownload audit for the same issue. +- **Category:** 19 (underspecified ID). +- **Suggested name:** `destinationId` (within the package context the qualifier "notification" is implicit). Or `id` is acceptable if the type is always accessed as `destination.id`. +- **Rationale:** Bare `id` is conventional and tolerated; the optionality is the real bug. Demoted to medium. + +### 14. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:118-122` +- **Code:** + ```ts + export interface PagerdutyConfig { + /** [Input-Only] Integration key for PagerDuty. */ + integrationKey?: string | undefined; + /** [Output-Only] Whether integration key is set. */ + integrationKeySet?: boolean | undefined; + } + ``` +- **Why weird:** Same as #7 in the specific case. The field is `string | undefined` on input but always `undefined` on output (the server never echoes it). The companion `integrationKeySet: boolean | undefined` carries the output information. A reader sees two optional fields and has to know the modal convention. +- **Category:** 6 (misleading optionality). +- **Suggested name:** see #7. +- **Rationale:** Listed separately because PagerDuty is the simplest case (one secret field) and best illustrates the pattern. + +### 15. `destinationType` field — type-suffix tautology — `src/v1/model.ts:78`, `:112` +- **Code:** + ```ts + destinationType?: DestinationType | undefined; + ``` +- **Why weird:** Field name "destinationType" of type "DestinationType". Tautology — the suffix `Type` is doing double duty as both a noun ("kind of destination") and a TS type marker. Inside the package's `NotificationDestination` type, naming the field `type` or `channel` would be self-evident from context (`destination.type === 'slack'`). Compare to `ec2-style` `instanceType: InstanceType` which has the same smell but is conventional in cloud SDKs. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `type` (with the parent type name supplying the context) or `channel`. If the enum is renamed `NotificationChannel` (per #1), then the field becomes `channel: NotificationChannel` which reads cleanly. + +## Low severity + +### 16. SCREAMING_SNAKE_CASE enum values — `src/v1/model.ts:5-11` +- **Code:** + ```ts + SLACK = 'SLACK', + EMAIL = 'EMAIL', + WEBHOOK = 'WEBHOOK', + PAGERDUTY = 'PAGERDUTY', + MICROSOFT_TEAMS = 'MICROSOFT_TEAMS', + ``` +- **Why weird:** The TS Style Guide section "Enums" prefers UpperCamelCase identifiers for both name and members; SCREAMING_SNAKE values are a wire-format leak. `MICROSOFT_TEAMS` has an underscore in a TS identifier, which is also discouraged. +- **Category:** 4 (underscores in TS identifiers — strictly speaking, both identifier and value). +- **Suggested name:** `Slack = 'SLACK'`, `Email = 'EMAIL'`, `Webhook = 'WEBHOOK'`, `PagerDuty = 'PAGERDUTY'`, `MicrosoftTeams = 'MICROSOFT_TEAMS'`. The string literals (the wire representation) stay; only the TS identifier changes. +- **Rationale:** Generator-level decision. Hand-written SDKs typically use UpperCamelCase enum members; the SCREAMING_SNAKE form makes it look like the type is C/Java. Demoted to low because it's a global convention and changing it would break every existing user. + +### 17. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` +- See #3 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. +- **Category:** 9 (qualifier mismatch). +- **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #3 for the rationale. + +### 18. `createNotificationDestination` / etc. — overly verbose method names — `src/v1/client.ts:71, 100, 125, 150, 204` +- **Code:** + ```ts + async createNotificationDestination(...) + async deleteNotificationDestination(...) + async getNotificationDestination(...) + async listNotificationDestinations(...) + async updateNotificationDestination(...) + ``` +- **Why weird:** Method names repeat the package name (`@databricks/sdk-notificationdestinations`) and the request-type name. A user writes `client.createNotificationDestination(...)` — 30 characters before the args. Shorter conventions: `client.create(...)`, `client.list(...)`, `client.get(...)` — relying on the package import to provide context. +- **Category:** 7 (overly verbose). +- **Suggested name:** Drop the suffix: `create`, `delete`, `get`, `list`, `update`. The class name (`Client` or `NotificationDestinationsClient`) supplies the domain context. +- **Rationale:** Conventions differ across SDKs. AWS uses verbose method names; GCP / Azure use shorter. Demoted to low because the existing convention is consistent across the SDK and changing it is disruptive. Flagging for completeness. + +### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` +- **Code:** + ```ts + // Package identity segment for this client to be used in the User-Agent header. + const PACKAGE_SEGMENT = { + key: pkgJson.name.replace(/^@[^/]+\//, ''), + value: pkgJson.version, + }; + ``` +- **Why weird:** "Segment" is a generic computer-science term. The comment disambiguates ("for this client to be used in the User-Agent header"), but the constant name does not. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `USER_AGENT_PACKAGE_INFO` or `PACKAGE_USER_AGENT`. +- **Rationale:** Cross-package — same finding appears in every audited file. + +### 20. `HttpCallOptions` — `src/v1/utils.ts:15-19` +- **Code:** + ```ts + export interface HttpCallOptions { + readonly request: HttpRequest; + readonly httpClient: HttpClient; + readonly logger: Logger; + } + ``` +- **Why weird:** Word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` imported from `@databricks/sdk-core/api`). Within `utils.ts` this local interface name collides with the imported `Options` symbol on line 3. +- **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). +- **Suggested name:** `HttpCallContext` (it is an internal context bag, not user-tunable options). + +### 21. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` +- **Code:** lines 26-38 and 65-94. +- **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. +- **Category:** 1 (vague), 17 (inconsistent layer naming). +- **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). + +### 22. `parseResponse` vs `marshalRequest` — verb asymmetry — `src/v1/utils.ts:113`, `:119` +- **Code:** lines 113 and 119. +- **Why weird:** Inverse functions named with different verbs (`parse` vs `marshal`). The schema constants use `marshal`/`unmarshal`. Pair-wise consistency would suggest `unmarshalResponse` and `marshalRequest`, or `parseResponse` and `serializeRequest`. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest`. + +### 23. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 88, 105, 130, 165, 187, 190, 209` +- **Code:** parameter and local-variable names throughout the client. +- **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `request`, `response`, `options`, `httpRequest`. Cost is trivial. + +## Observations + +### 24. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. +- **Category:** 6 (type-level dishonesty). +- **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). +- **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. + +### 25. `index.ts` re-exports verbose names verbatim — `src/v1/index.ts:5-23` +The barrel re-exports every type with its long generated name. An opportunity to expose friendlier aliases: +```ts +export type { + NotificationDestination as Destination, + CreateNotificationDestinationRequest as CreateRequest, + ... +} from './model'; +``` +Not done. So consumers always work with the verbose names. The 1:1 port philosophy probably prohibits this, but flagging as an observation — the barrel could improve ergonomics without removing the underlying names. +- **Category:** 7 (verbose), Observation. + +### 26. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows +Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. + +### 27. JSDoc inconsistency in `[Input-Only][Optional]` markers +The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the marker `[Input-Only][Optional]` — concatenating two brackets — while every other field uses single-bracket markers. The `[Optional]` is also redundant because the TS type already shows `?: undefined`. Minor doc inconsistency. + +## Domain glossary +- `notification destination` — the persistent record being managed. Always paired with a `displayName` and one `Config`. +- `channel` — implicit term-of-art for the kind of destination (Slack, Email, etc.). Not used in any identifier here; encoded as `DestinationType`. +- `integration key` — PagerDuty term for the API key used to post events. +- `webhook` — incoming HTTPS endpoint that receives a POST when the notification fires. +- `oauth token` — Slack Bot user OAuth token. +- `app id` / `tenant id` / `channel url` / `auth secret` — Microsoft Teams app-registration fields. +- `pageToken` / `pageSize` / `nextPageToken` — standard SDK pagination triplet; not specific to this package. + +## File coverage +- `src/v1/model.ts` (448 lines): read fully. +- `src/v1/client.ts` (231 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (24 lines): read fully. diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md new file mode 100644 index 00000000..97409853 --- /dev/null +++ b/.agent/naming-audit/oauthcustomappintegration.md @@ -0,0 +1,173 @@ +# Naming Audit: oauthcustomappintegration + +**Path:** `packages/oauthcustomappintegration/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level CRUD for OAuth App Integrations. Two flavours of integration are managed by the same service: *Custom* (caller-owned OAuth clients with their own redirect URLs and scopes) and *Published* (catalog of Databricks-blessed third-party apps such as Power BI or Tableau Desktop, identified by a stable `appId`). Both share the `TokenAccessPolicy` configuration. The package is the Databricks account-side complement of the `RFC 6749`/`OAuth 2.0` client registration concept. +**Total weird names flagged:** 18 + +## Summary +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 5 | +| Low | 4 | +| Observation | 4 | + +## High severity + +### 1. Package name `oauthcustomappintegration` mis-scopes the package — `package.json:2` +- **Why weird:** The package is named `@databricks/sdk-oauthcustomappintegration`, but only roughly half the surface concerns *custom* integrations (`CreateCustomOAuthAppIntegration`, `CustomOAuthAppIntegration`, etc.). The other half is *published* integrations (`CreatePublishedOAuthAppIntegration`, `PublishedOAuthAppIntegration`, etc.). The package's `Client` is a single mixed service handling both. Naming the package `…customappintegration` leads any developer reading `import { Client } from '@databricks/sdk-oauthcustomappintegration/v1'` to assume Published is in a different package — but it is not. There is also no separator: it reads as one 25-character unbroken token, harder to skim than `oauth-app-integrations` or `oauth_app_integrations`. +- **Category:** 6, 7, 9 (misleading scope; overly verbose; singular when it represents N integration types) +- **Suggested name:** `@databricks/sdk-oauthappintegrations` (plural; drops the misleading "custom" since the package also covers published). Or split into two packages: `oauthcustomappintegrations` and `oauthpublishedappintegrations`, each plural. +- **Rationale:** The Go SDK reference path is `databricks/api/oauth2` (umbrella for all OAuth concerns), which suggests the cross-service grouping is the natural one. The current TS name picks one half of the surface and elevates it to the package title, which is actively misleading. Pluralizing avoids the "what does one integration mean?" confusion at the import line. + +### 2. Every domain type re-states `OAuthAppIntegration` — model.ts:6, 29, 41, 46, 73, 92, 100, 108, 115, 120, 128, 134, 141, 147, 185, 206, 208, 216 +- **Why weird:** Inside a package called `oauthcustomappintegration`, *every* type name still spells "OAuthAppIntegration" in full. Imports look like this: + ```ts + import { + CreateCustomOAuthAppIntegration, + CreatePublishedOAuthAppIntegration, + CreatePublishedOAuthAppIntegration_Response, + CustomOAuthAppIntegration, + CustomOAuthAppIntegrationSecret, + DeleteCustomOAuthAppIntegration, + DeleteCustomOAuthAppIntegration_Response, + DeletePublishedOAuthAppIntegration, + DeletePublishedOAuthAppIntegration_Response, + GetCustomOAuthAppIntegration, + GetPublishedOAuthAppIntegration, + ListCustomOAuthAppIntegrations, + ListCustomOAuthAppIntegrations_Response, + ListPublishedOAuthAppIntegrations, + ListPublishedOAuthAppIntegrations_Response, + PublishedOAuthAppIntegration, + UpdateCustomOAuthAppIntegration, + UpdateCustomOAuthAppIntegration_Response, + UpdatePublishedOAuthAppIntegration, + UpdatePublishedOAuthAppIntegration_Response, + } from '@databricks/sdk-oauthcustomappintegration/v1'; + ``` + Eighteen of the 21 exported types are >25 characters long; nine are >35 characters. The package name already declares the namespace, so the type names need not re-declare it. Compare what the same code would look like with shorter names: `CreateCustom`, `CreatePublished`, `Custom`, `Published`, `CustomSecret`, `DeleteCustom`, … (still readable when paired with the package import). +- **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) +- **Suggested name:** Drop the `OAuthAppIntegration` suffix from every type. With a namespace import the call site reads `oauth.CreateCustom`, `oauth.Custom`, `oauth.CustomSecret`, `oauth.ListPublished_Response`. With named imports, alias if needed. +- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it 19 times in type names produces walls of identifiers where the eye has to skip 19 redundant characters to find the discriminator (`Create` vs `Update` vs `Delete` vs `List` vs `Get`, and `Custom` vs `Published`). The redundancy is a Go convention port: in Go `oauthcustomappintegration.CreateCustomAppIntegrationRequest` is necessary because Go has no struct-level method namespacing. TS does not have that constraint. See the Go reference at `databricks/api/oauth2/oauthcustomappintegration` where the Go names are necessarily fully qualified — but a 1:1 port should adapt to TS naming, not blindly copy. + +### 3. Type names use `OAuthAppIntegration` but methods use `OAuthAppIntegration` while doc cross-refs use `CustomAppIntegration` / `PublishedAppIntegration` — `client.ts:97, 133, 168, 199` +- **Why weird:** JSDoc on `createCustomOAuthAppIntegration` says: + > You can retrieve the custom OAuth app integration via `:method:CustomAppIntegration/get`. + + Same pattern on `createPublishedOAuthAppIntegration` → `:method:PublishedAppIntegration/get`. But there is no `CustomAppIntegration` or `PublishedAppIntegration` service exposed by this package — the actual method is `getCustomOAuthAppIntegration` on `Client`. The doc references are stale from a previous naming scheme (the Go SDK has separate `CustomAppIntegrations` and `PublishedAppIntegrations` sub-services). Anyone clicking through will hit a broken reference. +- **Category:** 6 (misleading) +- **Suggested name:** Fix the JSDoc cross-references to point to the real method (`Client.getCustomOAuthAppIntegration` / `Client.getPublishedOAuthAppIntegration`). The `:method:Foo/get` proto-doc directive should be processed to TypeScript-link form during generation. +- **Rationale:** Documentation lying to the reader is worse than verbose-but-correct documentation. + +### 4. `appId` on Published refers to a slug, not an ID — `model.ts:33, 149` +- **Why weird:** `CreatePublishedOAuthAppIntegration.appId` and `PublishedOAuthAppIntegration.appId` are documented as `For example power-bi, tableau-deskop` (note also: typo `deskop`). These are human-readable slugs, not opaque IDs. Calling them `appId` and typing as `string` collides with the convention that `xId` is an opaque UUID-like identifier (cf. `accountId`, `integrationId`, `clientId`, `principalId`). The Go reference (`databricks/api/oauth2/published`) calls it `AppID` too, but the value is clearly a published-catalog key like `power-bi`. The typo `tableau-deskop` in the doc comment is also untracked. +- **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) +- **Suggested name:** `appSlug` or `publishedAppKey` with type narrowed to a string literal union or enum: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, fix the `tableau-deskop` typo and document the format ("dash-separated lowercase slug from the Databricks published-app catalog"). +- **Rationale:** "ID" in this codebase otherwise means opaque UUID/integer (`integrationId`, `clientId`, `principalId`, `accountId`). Mixing in a human-readable slug under the same suffix is a teaching trap for callers. + +### 5. `_Response` underscore convention violates TS naming rules — `model.ts:41, 98, 106, 128, 141, 206, 216` +- **Why weird:** Seven types use the `_Response` suffix: `CreatePublishedOAuthAppIntegration_Response`, `DeleteCustomOAuthAppIntegration_Response`, `DeletePublishedOAuthAppIntegration_Response`, `ListCustomOAuthAppIntegrations_Response`, `ListPublishedOAuthAppIntegrations_Response`, `UpdateCustomOAuthAppIntegration_Response`, `UpdatePublishedOAuthAppIntegration_Response`. Each one is preceded by an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment, acknowledging the violation. The underscore is a proto-message nesting convention (`CreatePublished.Response` in proto → `CreatePublished_Response` in the generated Go), but TS does not have a "nested message" concept and the underscore form is alien to TS idioms. +- **Category:** 4, 20 (underscores in TS identifiers; type-suffix tautology — `…AppIntegration_Response`) +- **Suggested name:** Two options: + - `CreatePublishedOAuthAppIntegrationResponse` (drop underscore, accept verbosity). + - `CreatePublishedResponse` (drop underscore and the redundant domain suffix; pair with category 2 simplification). +- **Rationale:** The escape-hatch ESLint disables show the codebase already knows these names violate convention. Pick a TS-native form. + +## Medium severity + +### 6. `createdBy: number` is a user ID hidden as a numeric — `model.ts:60, 156` +- **Why weird:** Used in both `CustomOAuthAppIntegration` and `PublishedOAuthAppIntegration`. The field doc is empty, but it pairs with `creatorUsername: string` on `CustomOAuthAppIntegration`, so `createdBy` is the *user ID* of the creator. Calling it `createdBy` and typing it as `number` (rather than `creatorUserId` typed as `number` or `string`) hides the meaning. `principalId: number` next door has the same problem. +- **Category:** 1, 15, 19 (vague; generic field; underspecified ID) +- **Suggested name:** `createdByUserId: number` or just `creatorUserId: number`. Document explicitly that this is the numeric Databricks user ID (note: many other places in the codebase use `string` for user IDs). +- **Rationale:** A bare `createdBy: number` is the worst kind of numeric ID — no type information, no doc, and a name that reads as an activity verb. The asymmetry with `creatorUsername: string` (which sits 2 lines below in `CustomOAuthAppIntegration` but is missing from `PublishedOAuthAppIntegration`) compounds the confusion. + +### 7. `createTime: string` vs `clientSecretExpireTime: Temporal.Instant` — type inconsistency — `model.ts:61, 89, 157` +- **Why weird:** Both fields are timestamps. `createTime` is typed as `string` (raw ISO 8601, unparsed). `clientSecretExpireTime` is typed as `Temporal.Instant` (parsed via `Temporal.Instant.from`). Same package, same wire format, two different deserialization choices. Callers have to remember which fields are parsed and which are not. Looking at the unmarshal code at line 270, `client_secret_expire_time` gets `.transform(s => Temporal.Instant.from(s))` while `create_time` (line 241, 327) does not. +- **Category:** 16 (field contradicting type domain — both timestamps, different types) +- **Suggested name:** Names are fine; the *types* are inconsistent. Either both `Temporal.Instant` (preferred — this is the post-Temporal TS world) or both `string`. Apply consistently across the package. +- **Rationale:** A consumer doing `if (integration.createTime < other.createTime)` will get string comparison silently; if they did the same with `Temporal.Instant` they would get a type error and use `Temporal.Instant.compare`. The current state is a footgun. + +### 8. `clientSecretExpireTime` verb tense — `model.ts:89` +- **Why weird:** "Expire" is the bare infinitive — should be "expires" (third-person singular: "the secret expires at T") or "expiry"/"expiration" (noun). The Go side likely has `ClientSecretExpireTime` because Go traditionally uses verb-first compound nouns (`expireTime`, `createTime`), but TS/JS naming tends to use either the noun (`expirationTime`, `expirationDate`) or the inflected verb (`expiresAt`). `createTime`/`createdBy` next door have the same issue (should be `createdAt`/`creator`). +- **Category:** 13, 14 (verb-tense inconsistency; Go/Java-style names) +- **Suggested name:** `clientSecretExpiresAt`, `createdAt`, `creator` (or `creatorUserId`). +- **Rationale:** TypeScript ecosystem standard is `xAt` for timestamps and inflected verbs in field names. The Go form `xTime` reads as a Go transliteration. + +### 9. `confidential: boolean` — too generic for "requires-secret" flag — `model.ts:13, 56` +- **Why weird:** The doc comment is informative ("indicates whether an OAuth client secret is required to authenticate this client"), but the field name `confidential` is ambiguous outside RFC 6749 context. A reader has to know OAuth specifically (RFC 6749 §2.1 distinguishes "confidential" vs "public" clients) to decode this. The field doesn't follow a `requires…` or `is…` convention used elsewhere in the codebase. +- **Category:** 1, 5 (vague/generic; cryptic abbreviation of a spec term) +- **Suggested name:** `isConfidentialClient`, `requiresClientSecret`, or `confidentialClient`. If keeping `confidential`, add the RFC 6749 link in the doc. +- **Rationale:** Half of OAuth API consumers will not recognize "confidential" as the RFC 6749 client-type discriminator. + +### 10. `userAuthorizedScopes` vs `scopes` overlap — `model.ts:20, 26, 59, 68, 196, 202` +- **Why weird:** Two scope fields that look unrelated by name but the doc explicitly says `userAuthorizedScopes` "must be a subset of `scopes`". The relationship is invisible from the type — a caller could set `scopes = ["all-apis"]` and `userAuthorizedScopes = ["sql"]` and the type system won't help. `scopes` is the *requested* scope set, `userAuthorizedScopes` is the *user-consent gate* subset. Names do not encode this subset relationship. +- **Category:** 1, 6 (vague; misleading — `scopes` doesn't say "requested") +- **Suggested name:** `requestedScopes` (rename `scopes`) and `consentRequiredScopes` (rename `userAuthorizedScopes`). Or document the subset relationship inline on `scopes` with a backreference. +- **Rationale:** Bug class: caller assumes `userAuthorizedScopes` is "what the user actually consented to" (a state) rather than "what we *will* ask the user to consent to" (a config). The current name reads past-tense and is easily misread. + +## Low severity + +### 11. `OAuth` casing is consistent — `model.ts:throughout` +- **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants appear. This matches Google TS style guide guidance for trade-mark casing and matches RFC 6749 ("OAuth 2.0"). No action. +- **Category:** 3 (acronym casing — flagged as compliant) +- **Suggested name:** None — confirm the project-wide policy is `OAuth`. +- **Rationale:** Documenting the convention. Other audits should check sibling packages for `OAuth2` vs `Oauth2` vs `OAUTH2`. + +### 12. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix bloat — `model.ts:162, 168, 182` +- **Why weird:** Three TTL fields, two named `…InMinutes`, one named `…LifetimeInMinutes`. The "InMinutes" suffix is verbose. Three options to consider: + - Adopt `Temporal.Duration` for the type (no unit in the name needed). + - Keep the unit in the name but standardise on `Minutes` suffix (`accessTokenTtlMinutes`, `refreshTokenTtlMinutes`, `sessionTtlMinutes`). + - Document the unit in JSDoc only and use bare names (`accessTokenTtl`, `refreshTokenTtl`). +- **Category:** 7 (overly verbose) +- **Suggested name:** `accessTokenTtl: Temporal.Duration`, `refreshTokenTtl: Temporal.Duration`, `absoluteSessionLifetime: Temporal.Duration`. +- **Rationale:** The project already uses `Temporal.Instant` for `clientSecretExpireTime`. Extending to `Temporal.Duration` here removes the need to encode the unit in the field name, and removes the asymmetry between `TtlInMinutes` and `LifetimeInMinutes` (one is "TTL", the other "lifetime" — same concept). + +### 13. `enableSingleUseRefreshTokens` boolean naming inconsistency with `confidential` — `model.ts:175` +- **Why weird:** `enableSingleUseRefreshTokens` uses the verb-first `enableX` convention, but `confidential` uses no prefix. Other boolean conventions in the codebase favour `isX`/`hasX`. Three competing patterns on one type. +- **Category:** 13, 17 (verb-tense inconsistency; inconsistent action verbs) +- **Suggested name:** Align to one of `singleUseRefreshTokensEnabled` (state), `useSingleUseRefreshTokens` (config), or `rotateRefreshTokens` (behaviour). +- **Rationale:** "Enable X" reads as an action and slightly suggests a method/mutator. State booleans typically use predicate suffix `isEnabled`/`enabled` or domain noun. + +### 14. `includeCreatorUsername: boolean` query param on List Custom only — `model.ts:124` +- **Why weird:** `ListCustomOAuthAppIntegrations` has `includeCreatorUsername` but `ListPublishedOAuthAppIntegrations` does not (line 134). The asymmetry is fine for the API (Published integrations don't track creator the same way) but the type-level discoverability is poor. A caller writing both list calls in sequence will not understand why the option is missing from one. The name itself is also a query-flag for *server-side join inclusion*, which is unusual for an SDK to expose verbatim. +- **Category:** 5 (cryptic — the flag's semantics are non-obvious) +- **Suggested name:** Keep the field but document explicitly: "When true, the server resolves `createdBy` to `creatorUsername` in the response (extra database lookup)." +- **Rationale:** The default behaviour (omit username) is a performance optimization; callers should know enabling this is a server-side join. + +## Observations + +### O1. JSDoc literal templating leaks `` and `` markup — `model.ts:80, 82, 172, 178` and `client.ts:281, 341` +- The literal tokens `` and `` appear in seven places in this package. They are proto-doc templating tokens that should have been substituted to "Databricks" / "account" during generation. They render as broken-HTML angle-bracket sequences in TypeScript hover popups. This is a generator bug, not a per-package naming issue, but worth tagging at the project level. + +### O2. `_Response` suffix is the only naming-convention violation — `model.ts: throughout` +- All seven `_Response` types carry an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` Comment. No other naming violations in the package require ESLint disables. This is a single, removable wart that the generator could fix in one place. See finding #5. + +### O3. `executeCall` / `executeHttpCall` / `marshalRequest` / `parseResponse` utility-name asymmetry — `utils.ts:26, 65, 113, 119` +- Same observation across every package: the utility names do not pair symmetrically. `marshalRequest` ↔ `parseResponse` (verb mismatch: `marshal` vs `parse`, and `Request` vs `Response`). `executeCall` ↔ `executeHttpCall` (one wraps the other). Generated code, flag for upstream. + +### O4. `flattenQueryParams` is exported but unused — `utils.ts:123` +- This package never builds nested query parameters (`ListCustomOAuthAppIntegrations` uses three flat scalars), so `flattenQueryParams` is dead in this build. Same as in many sibling packages. Either drop the `export` or move the helper to `@databricks/sdk-core`. + +## Domain glossary +- `accountId` — Databricks account UUID (top-level tenant), distinct from a workspace ID. +- `appId` — Slug key into the Databricks published-app catalog (`power-bi`, `tableau-desktop`, …). Despite the `Id` suffix, this is a human-readable name, not an opaque ID. +- `clientId` — RFC 6749 client identifier (the OAuth "client_id" returned by the server). +- `clientSecret` — RFC 6749 client secret. Only returned at creation time for confidential clients. +- `confidential` — RFC 6749 §2.1 client type: `true` means the client has a secret and can authenticate itself. +- `Custom` integration — Caller-defined OAuth client (their own redirect URLs, scopes, secret). +- `integrationId` — Opaque server-issued ID for an OAuth app integration row. Distinct from `clientId`. +- `OAuth` — IETF OAuth 2.0 (RFC 6749), the authorization framework. Always cased `OAuth` in this package. +- `principalId` — Databricks service-principal ID auto-created alongside the integration. +- `Published` integration — Databricks-blessed third-party app (Power BI, Tableau, …) the account has enabled. +- `scopes` — RFC 6749 scope strings that the integration may request. Documented values: `all-apis`, `sql`, `offline_access`, `openid`, `profile`, `email`. +- `TokenAccessPolicy` — Per-integration token TTL and refresh-rotation policy. +- `userAuthorizedScopes` — Subset of `scopes` requiring end-user consent. Misleading: this is *will-ask*, not *did-grant*. + +## File coverage +- `src/v1/model.ts` (435 lines): read fully — 21 type exports, 13 schema exports. +- `src/v1/client.ts` (468 lines): read fully — 1 class, 10 async methods, 2 async generators. +- `src/v1/utils.ts` (151 lines): read fully — generic across packages. +- `src/v1/index.ts` (30 lines): read fully — re-exports. +- `package.json` (41 lines): read for context. diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md new file mode 100644 index 00000000..b55f6252 --- /dev/null +++ b/.agent/naming-audit/oauthpublishedapp.md @@ -0,0 +1,155 @@ +# Naming Audit: oauthpublishedapp + +**Path:** `packages/oauthpublishedapp/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level read-only catalog of Databricks-blessed third-party OAuth applications (e.g. Power BI, Tableau Desktop) that can be enabled for an account. The package exposes a single endpoint that lists the published-app catalog rows. Each `PublishedOAuthApp` is a *catalog entry* (template) — not an *integration row* (which is the realised binding tracked by the sibling `oauthcustomappintegration` package). The package therefore plays "catalog index" to `oauthcustomappintegration`'s "registration manager". Domain underpinning is RFC 6749 (OAuth 2.0) client-type "published" applications, augmented by a Databricks-owned catalog of vetted third-party clients. +**Total weird names flagged:** 19 + +## Summary +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 6 | +| Low | 4 | +| Observation | 4 | + +## High severity + +### 1. Package name `oauthpublishedapp` is singular but the package only exposes a *list* endpoint — `package.json:2`, `client.ts:62` +- **Why weird:** The package is `@databricks/sdk-oauthpublishedapp` (singular `app`). It exposes exactly one user-facing method, `listPublishedOAuthApps`, which returns a paginated *collection* of catalog rows. There is no `get`/`create`/`update`/`delete` — the package only ever operates over the plural set. The singular package name reads as "a thing that represents one published app", but the API contract is "the catalog of all published apps". Compare to the sibling `oauthcustomappintegration` (also incorrectly singular, audit finding #1 there). Both packages share the singular/plural mismatch. +- **Category:** 9 (singular/plural mismatch — package and class names suggest one entity, surface is purely collection-oriented) +- **Suggested name:** `@databricks/sdk-oauthpublishedapps` (plural), or `@databricks/sdk-oauthappcatalog` (re-cast as a catalog concept). +- **Rationale:** Reading `import { Client } from '@databricks/sdk-oauthpublishedapp/v1'` suggests there is a per-app client. A reader will land on the file expecting `getPublishedOAuthApp(id)`, `createPublishedOAuthApp(…)`, etc., and find only `listPublishedOAuthApps`. Pluralizing the package would set correct expectations. The Go reference at `databricks/api/oauth2/oauthpublishedapp` carries the same wart; a 1:1 port should still resolve it for TS since Go's package-vs-method namespacing rules don't apply. + +### 2. Package name fragments without separators — `package.json:2` +- **Why weird:** `oauthpublishedapp` is one unbroken 17-character token combining four concepts: OAuth + published + app. Compare to siblings: `oauthcustomappintegration` (25 chars, also unbroken — five concepts) and `apps` (4 chars). The npm scope name does not have to follow Go's no-separator-in-package convention. Several other Databricks SDK packages already use hyphenated names (`@databricks/sdk-core`, `@databricks/sdk-auth`, `@databricks/sdk-databricks`, `@databricks/sdk-options`). +- **Category:** 7 (overly verbose without natural break-points) +- **Suggested name:** `@databricks/sdk-oauth-published-apps` (hyphenated, plural). npm package naming permits dashes (https://docs.npmjs.com/cli/v10/configuring-npm/package-json#name). +- **Rationale:** Imports are read by humans; a four-word run-on identifier is harder to skim than a hyphen-separated one. The codebase already uses hyphens for some packages, so the precedent exists. + +### 3. Every domain type re-states `PublishedOAuthApp` in full — `model.ts:5, 15, 22` +- **Why weird:** Inside a package named `oauthpublishedapp`, every type still spells "PublishedOAuthApp" or "PublishedOAuthApps" inside its name: `ListPublishedOAuthApps`, `ListPublishedOAuthApps_Response`, `PublishedOAuthApp`. The package import already declares the namespace; the type names re-declare it. The same pattern appears (more egregiously) in `oauthcustomappintegration` — finding #2 there. + ```ts + import { + ListPublishedOAuthApps, + ListPublishedOAuthApps_Response, + PublishedOAuthApp, + } from '@databricks/sdk-oauthpublishedapp/v1'; + ``` + Every type repeats 16+ characters of "PublishedOAuthApp" that are already in the import path. +- **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) +- **Suggested name:** Drop the `PublishedOAuthApps?` qualifier from every type. With a namespace import the call site reads `published.List`, `published.List_Response`, `published.App`. With named imports, alias if needed: `import { App as PublishedOAuthApp }`. +- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it in type names produces walls of identifiers where the eye has to skip the redundant prefix to find the discriminator (`List` vs the single payload type). Pattern is a 1:1 port from Go (`oauthpublishedapp.PublishedOAuthApp` is necessary in Go because Go has no struct-level method namespacing); TS does not share that constraint. + +### 4. `_Response` underscore suffix violates TS naming rules — `model.ts:14-15` +- **Why weird:** `ListPublishedOAuthApps_Response` uses the `_Response` underscore suffix, preceded by an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment, acknowledging the violation. The underscore is a proto-message nesting convention (`ListPublishedOAuthApps.Response` in proto → `ListPublishedOAuthApps_Response` in generated Go), but TS does not have a "nested message" concept and the underscore form is alien to TS idioms. Same finding appears in `oauthcustomappintegration` #6. +- **Category:** 4, 14, 20 (underscores in TS identifiers; Go/Java-style names; type-suffix tautology — `…PublishedOAuthApps_Response`) +- **Suggested name:** `ListPublishedOAuthAppsResponse` (drop underscore), or after applying finding #3, `List_Response` → `ListResponse`. +- **Rationale:** The ESLint escape-hatch on this single type shows the codebase already knows the underscore violates convention. The only such violation in this package; trivial to fix. Pick a TS-native form. + +### 5. `appId` on `PublishedOAuthApp` is a slug, not an opaque ID — `model.ts:24` +- **Why weird:** `PublishedOAuthApp.appId` is documented as "Unique ID of the published OAuth app". The doc gives no examples here, but the sibling `oauthcustomappintegration` package's `CreatePublishedOAuthAppIntegration.appId` (which is the same value used to enable a published app in that account) is documented as `For example power-bi, tableau-deskop` (sic — typo carried in original). The appId is therefore a human-readable slug like `power-bi`, not an opaque UUID. Calling it `appId` and typing it as `string` collides with the convention that `xId` is an opaque opaque-ID (cf. `accountId`, `integrationId`, `clientId`, `principalId`). Same finding as `oauthcustomappintegration` #5; the value flows between the two packages and should be named consistently across both. +- **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) +- **Suggested name:** `appSlug` or `publishedAppKey` with the type narrowed to a literal union: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, document the format inline ("dash-separated lowercase slug from the Databricks published-app catalog") and cross-reference `CreatePublishedOAuthAppIntegration.appId` in the sibling package. +- **Rationale:** Every other `xId` in this codebase (`accountId`, `clientId`) is an opaque identifier. Mixing in a slug under the same suffix is a teaching trap. Two packages disagree by silence on what `appId` is. + +## Medium severity + +### 6. `clientId` field lacks the convention-matching closing period — `model.ts:25` +- **Why weird:** Doc comment reads `Client ID of the published OAuth app. It is the client_id in the OAuth flow` — missing trailing period (`flow` ends the sentence). Every other doc comment in the file ends with a period. Also, the wire-form `client_id` is hardcoded into the JSDoc text, which leaks generator-side terminology into TS docs that should describe the TS field. Repository CLAUDE.md rule: "Every comment must be a proper sentence ending with a period." +- **Category:** Not strictly a name finding, but a generator-side text issue — included because it sits on a name field and is visible at every hover. +- **Suggested name:** Doc text only; field name `clientId` is correct. Fix to: `Client ID of the published OAuth app. Matches the OAuth 2.0 \`client_id\` parameter (RFC 6749 §2.2).` +- **Rationale:** Comment-style rule on the project. The reference to RFC 6749 §2.2 gives the term a spec anchor instead of leaving "client_id in the OAuth flow" as a vague pointer. + +### 7. `isConfidentialClient` named inconsistently across packages — `model.ts:31-32` +- **Why weird:** The sibling `oauthcustomappintegration` exposes the same OAuth concept under the field name `confidential` (no `is…Client` prefix). The two packages model the same RFC 6749 §2.1 client-type flag with different identifiers, so a consumer juggling both has to remember that `customIntegration.confidential` and `publishedApp.isConfidentialClient` are the same flag. Audit finding #12 in `oauthcustomappintegration` recommends renaming that side to `isConfidentialClient` — so the *name* here is the right one; the sibling is the side to align. +- **Category:** 12 (duplicate concept across packages, inconsistent naming) +- **Suggested name:** Keep `isConfidentialClient` here. Cross-package fix lives in the sibling audit (#12 there). +- **Rationale:** The flag's value space and meaning are identical across the two packages; the identifier should be too. Resolve at the sibling, not here. + +### 8. `redirectUrls: string[]` field stutter with `URI`/`URL` spec language — `model.ts:33-34` +- **Why weird:** OAuth 2.0 spec (RFC 6749 §3.1.2) calls these *redirection URIs*. The TS field uses `redirectUrls` (lowercase `rl`); the JSDoc reads "Redirect URLs of the published OAuth app." matching the field name. The sibling `oauthcustomappintegration` finding #13 documents that the package mixes URI / URL in JSDoc and field names; here the package uses `URLs` consistently within itself but contradicts spec language. The casing `Urls` (lowercase `rl`) follows Google TS style guide § Identifiers (acronyms ≥3 chars are PascalCase, but `URL` historically is exempted in many guides — TypeScript ecosystem standard is `Url`). +- **Category:** 3 (acronym casing — `URL` lowercased as `Url` while `OAuth` keeps `Auth` mid-token uppercase, inconsistent acronym treatment within the same identifier set) +- **Suggested name:** Keep `redirectUrls` (matches Google TS style guide https://google.github.io/styleguide/tsguide.html#identifiers), but cross-reference RFC 6749 §3.1.2 in the JSDoc so the spec term is visible: "Redirect URLs of the published OAuth app (RFC 6749 §3.1.2 \"redirection URIs\")." +- **Rationale:** Consistent with sibling package finding #13. The doc-term mismatch (URI in spec, URL in code) is the real issue; the casing is correct per Google TS. + +### 9. `scopes: string[]` carries no enum/union — `model.ts:35-36` +- **Why weird:** Sibling `oauthcustomappintegration` documents the supported scope set inline: `Supported scopes: all-apis, sql, offline_access, openid, profile, email`. Here the same field is typed `string[]` with no JSDoc enumeration: just "Required scopes for the published OAuth app." Both packages share the same scope vocabulary (it is the Databricks OAuth scope set), and one documents it, the other does not. +- **Category:** 1, 12 (vague — string[] could be anything; duplicate concept across packages, inconsistent treatment) +- **Suggested name:** Keep `scopes`, but type as `Array<'all-apis' | 'sql' | 'offline_access' | 'openid' | 'profile' | 'email'>` to match the sibling package's documented vocabulary. At minimum, JSDoc the supported scopes. +- **Rationale:** Two packages model the same wire field. The custom package documents the value space; the published package leaves it open. A consumer reading `app.scopes` has no in-IDE way to learn the valid values. + +### 10. `pageSize: number` lacks bounds and unit context — `model.ts:11` +- **Why weird:** Doc says "The max number of OAuth published apps to return in one page." but does not document the maximum-permitted value, default, or whether `0` means "unset" or "zero results". `pageSize` is the most common cross-API pagination footgun; some Databricks APIs reject `pageSize > 1000`, others treat `0` as "use default", others as "return zero". A consumer doing `req.pageSize = 0` gets undefined behaviour. The name `pageSize` itself is fine and consistent with Databricks API conventions (and Google AIP-158 https://google.aip.dev/158). +- **Category:** 1 (vague — `number` with no bounds reads as "any int", but isn't) +- **Suggested name:** Name is fine; doc should be "The maximum number of published OAuth apps to return in one page. Defaults to server-side default (typically 100). Maximum: 1000." +- **Rationale:** Same field exists in many sibling packages; document once at the source of truth (the generator's pagination template). + +### 11. `pageToken: string` reuses the previous-response `nextPageToken` — implicit cross-field contract — `model.ts:8-9`, `model.ts:18-19` +- **Why weird:** Request `pageToken` and response `nextPageToken` are two halves of one pagination contract. The names use different roots (`page…` vs `nextPage…`), so the connection is invisible. A new reader has to read both shapes and the iterator to understand `req.pageToken = resp.nextPageToken`. This is the Google AIP-158 convention (https://google.aip.dev/158) and shared by every paginated Databricks API, but worth flagging at project level since the naming asymmetry repeats everywhere. +- **Category:** 17 (inconsistent action verbs — `pageToken` is a noun, `nextPageToken` is a noun; the asymmetry is in the prefix `next…`) +- **Suggested name:** Keep names (they match AIP-158); document the relationship in JSDoc: "Pass `nextPageToken` from the previous response as `pageToken` to fetch the next page." +- **Rationale:** Convention-bound, but the doc is silent — every list endpoint in the SDK silently shares this contract. + +## Low severity + +### 12. `OAuth` casing is consistent — `model.ts:throughout` +- **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants. Matches Google TS style guide guidance and matches RFC 6749. Matches sibling `oauthcustomappintegration`. No action. +- **Category:** 3 (acronym casing — flagged compliant) +- **Suggested name:** None — confirm the project-wide policy is `OAuth`. +- **Rationale:** Documenting compliance. + +### 13. `Client` class — generic single export, common to all generated packages — `client.ts:32` +- **Why weird:** Same pattern as every other package in this SDK. `import { Client } from '@databricks/sdk-oauthpublishedapp/v1'` produces an unqualified `Client` symbol. Consumers using multiple packages must alias: `import { Client as OAuthPublishedAppClient }`. Project-wide pattern, not specific to this package. +- **Category:** 1 (vague/generic) +- **Suggested name:** `OAuthPublishedAppClient` (still inside `…/v1`). Project-wide change. +- **Rationale:** Defer to the project-wide naming-audit summary. Same as sibling finding #19. + +### 14. Async-iterator method named `…Iter` — `client.ts:98` +- **Why weird:** `listPublishedOAuthAppsIter` (Go-style `…Iter` suffix). TypeScript convention for an `AsyncGenerator` is to use no suffix and have the type signature express it, or to use the verb form `iterate…` / `walk…`. The `Iter` suffix is a Go transliteration (Go has `…Iter()` from `golang.org/x/iter`). Sibling packages with the same generator method use the same `Iter` suffix. +- **Category:** 14 (Go/Java-style name) +- **Suggested name:** `listPublishedOAuthAppsAsync` (matches the JS ecosystem `…Async` convention when the non-async variant doesn't exist — but here only the async variant is present, so this is debatable), or rename the page-returning variant `listPublishedOAuthAppsPage` and the streaming variant `listPublishedOAuthApps` (the iterator is the more natural default in a TS world with `for await`). +- **Rationale:** The `Iter` suffix is invisible to TypeScript ecosystem readers. Compare modern Node APIs: `fs.opendir().readdir()` returns a `Dir` directly iterable; no `…Iter` suffix. Defer to project-wide pattern but flag. + +### 15. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:17` +- **Why weird:** `ListPublishedOAuthApps_Response.apps` is the collection field. Unlike the sibling package's `apps` field finding (`oauthcustomappintegration` #4) where the field carried *integrations* and the name was misleading, here the field genuinely is published apps. The name is correct *but* it duplicates the type name (`apps: PublishedOAuthApp[]` — "apps of type App"). Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). Acceptable. +- **Category:** 15 (generic field — `apps` is the maximally-generic plural of `app`) — flagged for completeness +- **Suggested name:** Keep `apps`. Or rename `publishedApps` to make plural+domain explicit. No strong action. +- **Rationale:** Within the response type, the field name is unambiguous. Cross-package consistency with `oauthcustomappintegration` is broken (that package's `apps` field is misleading), but renaming this one would not fix that — the sibling rename is the right place. + +## Observations + +### O1. JSDoc literal templating: this package has **no** `` / `` leaks +- Sibling `oauthcustomappintegration` has six JSDoc strings containing literal `` / `` tokens (their finding O1). This package has zero such leaks — the JSDoc on `listPublishedOAuthApps` ("Get all the available published OAuth apps in ``") *does* contain the token at `client.ts:61`. Update: this *does* have one such leak. Same generator bug. + +### O2. `_Response` suffix is the only naming-convention violation — `model.ts:14-15` +- The one `_Response` type has an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment. No other naming violations in the package require ESLint disables. Single, removable wart that the generator could fix. See finding #4. + +### O3. `executeCall` / `executeHttpCall` / `marshalRequest` / `parseResponse` utility-name asymmetry — `utils.ts:26, 65, 113, 119` +- Same observation across every package: the utility names do not pair symmetrically. `marshalRequest` ↔ `parseResponse` (verb mismatch: `marshal` vs `parse`, and `Request` vs `Response`). `executeCall` ↔ `executeHttpCall` (one wraps the other). Generated code, flag for upstream. + +### O4. `flattenQueryParams` and `marshalRequest` are exported but unused — `utils.ts:113, 119, 123` +- This package only `GET`s a list endpoint with three flat scalar query params and never marshals a request body. So `flattenQueryParams` and `marshalRequest` are dead in this build. Same as in sibling packages. Either drop the `export`, gate on per-package generation, or move these helpers to `@databricks/sdk-core` and have packages import only what they use. + +## Domain glossary +- `accountId` — Databricks account UUID (top-level tenant). Distinct from a workspace ID. +- `appId` — Slug key into the Databricks published-app catalog (e.g. `power-bi`, `tableau-desktop`). Despite the `Id` suffix, this is a human-readable name. Same value space as `oauthcustomappintegration.CreatePublishedOAuthAppIntegration.appId`. +- `clientId` — RFC 6749 client identifier (OAuth `client_id`). Stable per published app. +- `OAuth` — IETF OAuth 2.0 (RFC 6749). Always cased `OAuth` in this package. +- `Published` app — Databricks-blessed third-party application (Power BI, Tableau Desktop, …) available to be enabled in an account. Distinct from a `Custom` integration (caller-defined OAuth client, lives in `oauthcustomappintegration`). +- `redirectUrls` — RFC 6749 §3.1.2 "redirection URIs" registered for the published app. +- `scopes` — RFC 6749 scope strings the published app may request (`all-apis`, `sql`, `offline_access`, `openid`, `profile`, `email`). + +## Cross-package coupling notes +- `appId` value space is shared with `oauthcustomappintegration.CreatePublishedOAuthAppIntegration.appId`. Renaming on one side must rename on the other. +- `isConfidentialClient` here ↔ `confidential` on the sibling — same underlying concept, inconsistent boolean naming. +- `scopes: string[]` here ↔ `scopes: string[]` on the sibling — same vocabulary, only the sibling documents the literal value set. +- Both packages share the `OAuth` casing convention and the `_Response` underscore suffix violation. +- Suggested cross-package action: lift `PublishedOAuthApp` (catalog row) into a shared module imported by both packages, so `oauthcustomappintegration` can reference the canonical row when an account enables a published app. + +## File coverage +- `src/v1/model.ts` (69 lines): read fully — 3 type exports, 2 schema exports. +- `src/v1/client.ts` (114 lines): read fully — 1 class, 1 async method, 1 async generator. +- `src/v1/utils.ts` (150 lines): read fully — generic across packages, identical to sibling's `utils.ts`. +- `src/v1/index.ts` (11 lines): read fully — re-exports `Client` and three types. +- `package.json` (38 lines): read for context. diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md new file mode 100644 index 00000000..b94244ba --- /dev/null +++ b/.agent/naming-audit/onlinetables.md @@ -0,0 +1,1043 @@ +# Naming Audit: `onlinetables` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/onlinetables/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts` +**Package import path:** `@databricks/sdk-onlinetables/v1` +**Cross-package references:** + +- `featurestore/v1` — also defines `DeleteOnlineTableRequest`, also references + `OnlineTable` semantics via `PublishSpec.onlineTableName` / + `PublishTableResponse`. +- `database/v1` — defines `SyncedTableState`, `SyncedTablePipelineProgress`, + `SyncedTableSchedulingPolicy`, `ProvisioningInfo_State`, `ProvisioningInfo`, + `SyncedTableContinuousUpdateStatus`, `SyncedTableFailedStatus`, + `SyncedTableTriggeredUpdateStatus`, `SyncedTableProvisioningStatus`, + `SyncedTableStatus` — all of which are *renames of identical concepts* with + a `SyncedTable` prefix. +- `postgres/v1` — same shape as `database`, also forks the type set. +- `catalogs/v1`, `connections/v1` — re-export `ProvisioningInfo_State` and + `ProvisioningInfo` from their own modules. + +**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). + +--- + +## Inventory + +### Enums (model.ts) + +1. `OnlineTableState` (model.ts:7) — 12 values: `ONLINE_TABLE_STATE_UNSPECIFIED`, + `PROVISIONING`, `PROVISIONING_PIPELINE_RESOURCES`, + `PROVISIONING_INITIAL_SNAPSHOT`, `ONLINE`, `ONLINE_CONTINUOUS_UPDATE`, + `ONLINE_TRIGGERED_UPDATE`, `ONLINE_NO_PENDING_UPDATE`, `OFFLINE`, + `OFFLINE_FAILED`, `ONLINE_PIPELINE_FAILED`, + `ONLINE_UPDATING_PIPELINE_RESOURCES`. +2. `ProvisioningInfo_State` (model.ts:57) — 7 values: `STATE_UNSPECIFIED`, + `PROVISIONING`, `ACTIVE`, `FAILED`, `DELETING`, `UPDATING`, `DEGRADED`. + +### Interfaces / Types (model.ts) + +1. `ContinuousUpdateStatus` (model.ts:71) — fields: + `lastProcessedCommitVersion`, `timestamp`, `initialPipelineSyncProgress`. +2. `CreateOnlineTableRequest` (model.ts:87) — fields: `table`. +3. `DeleteOnlineTableRequest` (model.ts:93) — fields: `name`. +4. `FailedStatus` (model.ts:102) — fields: `lastProcessedCommitVersion`, + `timestamp`. +5. `GetOnlineTableRequest` (model.ts:117) — fields: `name`. +6. `OnlineTable` (model.ts:123) — fields: `name`, `spec`, `status`, + `tableServingUrl`, `unityCatalogProvisioningState`. +7. `OnlineTableSpec` (model.ts:141) — fields: `schedulingPolicy` (discriminated + union with `runContinuously` / `runTriggered`), `sourceTableFullName`, + `primaryKeyColumns`, `timeseriesKey`, `performFullCopy`, `pipelineId`. +8. `OnlineTableSpec_ContinuousSchedulingPolicy` (model.ts:175) — empty + interface. +9. `OnlineTableSpec_TriggeredSchedulingPolicy` (model.ts:178) — empty + interface. +10. `OnlineTableStatus` (model.ts:181) — fields: `detailedState`, `message`, + `detailedStatus` (discriminated union). +11. `PipelineProgress` (model.ts:202) — fields: + `latestVersionCurrentlyProcessing`, `syncedRowCount`, `totalRowCount`, + `syncProgressCompletion`, `estimatedCompletionTimeSeconds`. +12. `ProvisioningInfo` (model.ts:220) — empty interface. +13. `ProvisioningStatus` (model.ts:226) — fields: + `initialPipelineSyncProgress`. +14. `TriggeredUpdateStatus` (model.ts:238) — fields: + `lastProcessedCommitVersion`, `timestamp`, `triggeredUpdateProgress`. + +### Zod schemas (model.ts) + +- Unmarshal: `unmarshalContinuousUpdateStatusSchema`, + `unmarshalFailedStatusSchema`, `unmarshalOnlineTableSchema`, + `unmarshalOnlineTableSpecSchema`, + `unmarshalOnlineTableSpec_ContinuousSchedulingPolicySchema`, + `unmarshalOnlineTableSpec_TriggeredSchedulingPolicySchema`, + `unmarshalOnlineTableStatusSchema`, `unmarshalPipelineProgressSchema`, + `unmarshalProvisioningStatusSchema`, `unmarshalTriggeredUpdateStatusSchema`. +- Marshal: identical list with `marshal` prefix. + +### Client (client.ts) + +- Class `Client` (client.ts:41). +- Methods: `createOnlineTable`, `createOnlineTableWaiter`, `deleteOnlineTable`, + `getOnlineTable`. +- Class `CreateOnlineTableWaiter` (client.ts:152) — methods: `wait`, `done`. +- Internal `class StillRunningError extends Error` (client.ts:39). +- Private fields: `host`, `httpClient`, `logger`, `userAgent`. +- Module constant: `PACKAGE_SEGMENT` (client.ts:34). + +### Utils (utils.ts) + +- Interface: `HttpCallOptions`. +- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`. + +### Index (index.ts) + +- Re-exports `Client`, `CreateOnlineTableWaiter`, enum values, and 14 + interfaces. + +--- + +## Summary (counts) + +| Severity | Count | +| --------------------- | ----- | +| High | 7 | +| Medium | 14 | +| Low / SDK-wide note | 11 | +| Pass / acceptable | 9 | +| **Total findings** | **41** | + +(Several findings touch multiple audit categories; counts above are unique +findings.) + +--- + +## Findings + +### 1. `ProvisioningInfo_State` underscore in type name — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) + +**Symbol:** `ProvisioningInfo_State` (model.ts:57). + +**Issue:** The enum name carries a `_` underscore separating the parent +message name (`ProvisioningInfo`) and the nested-enum name (`State`). This is +a proto-buf code-generator artefact for nested messages/enums (`ParentMessage.NestedEnum` +in `.proto` becomes `ParentMessage_NestedEnum` in some Go codegens) and is not +idiomatic TypeScript. The Google TS Style Guide § 5.3 mandates `UpperCamelCase` +for type names with no underscores; the project's own lint rule +(`.agent/rules/typescript.mdc` § *Identifiers*) enforces the same. The file +even has to suppress the lint for this identifier (model.ts:56): + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. +export enum ProvisioningInfo_State { +``` + +The suppression comment is itself the audit signal: lint disagrees, and the +suppression is hard-coded across the SDK for every proto-nested enum. + +**Suggested:** `ProvisioningState`. Folding the nested-enum name to a flat +`ProvisioningState` loses no information. + +**Note on inconsistency *within this file*:** the file uses *both* the flat +name (`OnlineTableState`, model.ts:7) and the underscored form +(`ProvisioningInfo_State`, model.ts:57). Same generator, same package, two +conventions in 50 lines. **Flag for generator-wide cleanup.** + +--- + +### 2. `OnlineTableSpec_ContinuousSchedulingPolicy` and `OnlineTableSpec_TriggeredSchedulingPolicy` underscored type names — category 4 (Underscores in TS identifiers) + +**Symbols:** `OnlineTableSpec_ContinuousSchedulingPolicy` (model.ts:175), +`OnlineTableSpec_TriggeredSchedulingPolicy` (model.ts:178). + +**Issue:** Underscored type names (same root cause as finding 1). Lint +suppression at model.ts:174 and 177 marks the violation. The proto-namespace +underscore separates the parent message name (`OnlineTableSpec`) from the +nested-message name (`ContinuousSchedulingPolicy` / `TriggeredSchedulingPolicy`). +This is a proto-buf code-generator artefact, not idiomatic TypeScript. + +**Suggested at the TS level:** strip the proto namespace, yielding flat type +names `ContinuousSchedulingPolicy` and `TriggeredSchedulingPolicy`. **Flag for +generator-wide cleanup.** + +--- + +### 3. `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) + +**Symbol:** `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` (model.ts:9). + +**Issue:** Members are already namespaced under `OnlineTableState`. The +`ONLINE_TABLE_STATE_` segment duplicates the enum name. Reads as: +```ts +if (table.status?.detailedState === OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED) { ... } +// ^^^^^^^^^^^^^^^^^^^^ +// duplicates the enum name +``` + +Note: the values double as on-the-wire JSON strings (`z.enum(OnlineTableState)` +at model.ts:341 parses raw API strings directly into these identifiers), so +renaming the wire string requires server acceptance and is a behavioural +change. The TS-side identifier can be split from the wire string (see +finding 5) for a safe local fix. + +**Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. +**Suggested TS-level only (safe — see finding 5):** `Unspecified = +'ONLINE_TABLE_STATE_UNSPECIFIED'`. + +--- + +### 4. `ProvisioningInfo_State.STATE_UNSPECIFIED` value prefix repeats half the enum name — category 2 (Redundant enum prefixes) + +**Symbol:** `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58). + +**Issue:** Same family as finding 3. The `STATE_` prefix repeats the trailing +half of the enum name. After applying finding 1 (rename to +`ProvisioningState`), the duplication is even more visible: +`ProvisioningState.STATE_UNSPECIFIED`. + +**Suggested:** TS-side identifier `Unspecified`. Wire string remains +`STATE_UNSPECIFIED` if upstream still emits it. + +--- + +### 5. SCREAMING_SNAKE_CASE enum members — category 4 (Underscores in TS identifiers) + +**Symbols:** Every value in both enums (model.ts:9–53 and 58–64). + +**Issue:** The project's `.agent/skills/google-ts-styleguide` (and Google TS +Style Guide § 5.3) mandates `UpperCamelCase` for enum members, not +`SCREAMING_SNAKE_CASE`. The project's own `typescript.mdc` enforces no +underscores in TS identifiers. Every enum value here contains underscores +and is SCREAMING-cased. + +Enum string *values* double as the on-the-wire representation here (the Zod +schemas parse raw API strings into these identifiers — `z.enum(OnlineTableState)` +at model.ts:341 and `z.enum(ProvisioningInfo_State)` at model.ts:290). The +TS-side identifier can be split from the wire literal — e.g. +`ProvisioningPipelineResources = 'PROVISIONING_PIPELINE_RESOURCES'` — which +is the canonical TS fix while preserving wire compatibility. + +**Suggested (TS side only, no wire change):** + +```ts +export enum OnlineTableState { + Unspecified = 'ONLINE_TABLE_STATE_UNSPECIFIED', + Provisioning = 'PROVISIONING', + ProvisioningPipelineResources = 'PROVISIONING_PIPELINE_RESOURCES', + ProvisioningInitialSnapshot = 'PROVISIONING_INITIAL_SNAPSHOT', + Online = 'ONLINE', + OnlineContinuousUpdate = 'ONLINE_CONTINUOUS_UPDATE', + OnlineTriggeredUpdate = 'ONLINE_TRIGGERED_UPDATE', + OnlineNoPendingUpdate = 'ONLINE_NO_PENDING_UPDATE', + Offline = 'OFFLINE', + OfflineFailed = 'OFFLINE_FAILED', + OnlinePipelineFailed = 'ONLINE_PIPELINE_FAILED', + OnlineUpdatingPipelineResources = 'ONLINE_UPDATING_PIPELINE_RESOURCES', +} + +export enum ProvisioningState { + Unspecified = 'STATE_UNSPECIFIED', + Provisioning = 'PROVISIONING', + Active = 'ACTIVE', + Failed = 'FAILED', + Deleting = 'DELETING', + Updating = 'UPDATING', + Degraded = 'DEGRADED', +} +``` + +**Flag as SDK-wide cleanup.** Same observation as `featurestore.md` finding 4 +and `database.md` finding 6. + +--- + +### 6. `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` value too long — category 18 (Long enum values) + +**Symbol:** `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` (model.ts:53) +and `PROVISIONING_PIPELINE_RESOURCES` (model.ts:16). + +**Issue:** 35–37 character enum members. Even allowing for the wire-level +prefix, the values pack three concepts (online/provisioning + transition + +"pipeline-resources"). The JSDoc explains them; the identifier itself is +hard to read. + +**Suggested:** at the TS level, `OnlineUpdatingPipelineResources` shortens to +30 chars while preserving meaning. The wire form is fixed by upstream. **Pass +in isolation if finding 5 is applied; flag as a long-name observation.** + +--- + +### 7. `OnlineTableState` modelled as one enum, two semantic groups — category 6 (Misleading names) and category 12 (Duplicate concepts) + +**Symbol:** `OnlineTableState` (model.ts:7), 12 values. + +**Issue:** The 12 values mix *lifecycle* states (`PROVISIONING`, +`PROVISIONING_PIPELINE_RESOURCES`, `PROVISIONING_INITIAL_SNAPSHOT`, `OFFLINE`, +`OFFLINE_FAILED`) with *ongoing-state* substates that are specific to the +"online" lifecycle (`ONLINE_CONTINUOUS_UPDATE`, `ONLINE_TRIGGERED_UPDATE`, +`ONLINE_NO_PENDING_UPDATE`, `ONLINE_PIPELINE_FAILED`, +`ONLINE_UPDATING_PIPELINE_RESOURCES`). The `OnlineTableStatus` interface +already has a `detailedStatus` discriminated union (model.ts:187) that +overlaps with these substates. So the same information is modelled twice: +once flat in the enum, once in the structured `detailedStatus`. + +This is a wire-level concern, but in TS it reads as a single enum doing two +jobs — top-level lifecycle and one-level-down detail. Compare to +`database.SyncedTableState` which has the same 12 values prefixed +`SYNCED_TABLE_…` (with a famous typo `SYNCED_TABLED_OFFLINE`). The duplication +*across packages* is also a flag — see finding 8. + +**Suggested:** push back upstream — split into `OnlineTableLifecycle` (a few +top-level states) and use `detailedStatus.$case` as the substate identifier. +**Pass at the TS level**, flag at the protocol level. + +--- + +### 8. Cross-package collision: `OnlineTableState` ↔ `database.SyncedTableState` — category 12 (Duplicate concepts) and category 17 (Inconsistent action verbs) + +**Symbol:** `OnlineTableState` (here, model.ts:7) and `SyncedTableState` +(`database/v1/model.ts:55`, `postgres/v1/model.ts`). + +**Issue:** Two SDK packages model essentially the same lifecycle concept — +the state of a UC-managed Delta-to-managed-store sync table — with two +*different enum names* and one is misspelled (`SYNCED_TABLED_OFFLINE`). +Looking at the values: + +- `onlinetables.OnlineTableState`: 12 values, prefix `ONLINE_TABLE_STATE_…` + on `UNSPECIFIED` only. +- `database.SyncedTableState`: 12 values, prefix `SYNCED_TABLE_…` on **all + values** plus the famous typo `SYNCED_TABLED_OFFLINE`. + +These enums describe the *same machine*. A consumer who uses both packages +will write a lookup table or branch on `$case` differently in each package. + +**Suggested at the SDK level:** harmonise the type names (drop one in favour +of the other, with an alias for backward compatibility). The wire-level +fix is a protocol-team decision. **Strongly flag for SDK-wide alignment**; +do not fix unilaterally in this package. + +--- + +### 9. Cross-package collision: `PipelineProgress` ↔ `database.SyncedTablePipelineProgress` — category 12 (Duplicate concepts) + +**Symbol:** `PipelineProgress` (here, model.ts:202) and +`database.SyncedTablePipelineProgress` (`database/v1/model.ts:744`, +`postgres/v1/model.ts:2547`). + +**Issue:** Identical concept (progress information for the data +synchronization pipeline of an online/synced table) modelled with two +different type names and identical fields (`latestVersionCurrentlyProcessing`, +`syncedRowCount`, `totalRowCount`, `syncProgressCompletion`, +`estimatedCompletionTimeSeconds`). + +**Suggested:** keep the shorter `PipelineProgress` (this package) as +canonical; rename `database.SyncedTablePipelineProgress` to +`PipelineProgress` and import from a shared `@databricks/sdk-onlinetables/v1` +or extract both into `@databricks/sdk-core` if the dependency is acceptable. +**SDK-wide cleanup.** + +--- + +### 10. Cross-package collision: `ProvisioningInfo_State` defined in 4+ packages — category 12 (Duplicate concepts) + +**Symbol:** `ProvisioningInfo_State` (here, model.ts:57). Also defined in: + +- `database/v1/model.ts:148` +- `postgres/v1/model.ts:654` +- `catalogs/v1/model.ts:57` +- `connections/v1/model.ts:131` + +**Issue:** Five separate copies of an enum with mostly-identical values +(`PROVISIONING`, `ACTIVE`, `FAILED`, `DELETING`, `UPDATING`, `DEGRADED` — +`onlinetables` is missing `STATE_UNSPECIFIED` placeholder behaviour vs. +others; pairwise identical in shape). Each carries its own underscore-style +name (finding 1). + +**Suggested:** hoist to a shared `@databricks/sdk-core/provisioning` module +(if cross-cutting), or keep duplicates with **value-level type-checked** +union to guarantee parity. **SDK-wide cleanup.** + +--- + +### 11. Cross-package collision: `DeleteOnlineTableRequest` defined in two packages with different fields — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) + +**Symbol:** `DeleteOnlineTableRequest` (here, model.ts:93) and +`featurestore.DeleteOnlineTableRequest` (`featurestore/v1/model.ts:57`). + +**Issue:** Both packages define a type with the *same name* but different +fields: + +```ts +// onlinetables/v1/model.ts:93 +export interface DeleteOnlineTableRequest { + name?: string | undefined; // Full three-part name of the table. +} +``` + +```ts +// featurestore/v1/model.ts:57 +export interface DeleteOnlineTableRequest { + onlineTableName?: string | undefined; // Full three-part name of the table. +} +``` + +A caller who imports both packages must alias them (namespacing handles the +type-name collision but the field name differs). The URL paths also differ: +`/api/2.0/online-tables/{name}` here vs. +`/api/2.0/feature-store/online-tables/{onlineTableName}` in featurestore. + +**Suggested:** harmonise the field name. `name` is shorter and idiomatic for +URL-path resource identifiers, matches REST conventions, and matches the +sibling `GetOnlineTableRequest.name` (model.ts:119) in this very package. +**Pin `name` as canonical, push back on `featurestore`.** + +--- + +### 12. `CreateOnlineTableRequest.table` field name is too generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) + +**Symbol:** `CreateOnlineTableRequest.table?: OnlineTable | undefined` +(model.ts:89). + +**Issue:** The field name `table` is generic. Compare to +`featurestore.CreateOnlineStoreRequest.onlineStore` (specific). The field's +*type* is `OnlineTable` so the descriptive name would be `onlineTable`. + +**Suggested:** `onlineTable` (matches the type, matches +`featurestore.publishTable.publishSpec.onlineTableName`). **Flag at port +time.** + +--- + +### 13. `OnlineTable.name` is a three-part UC name, not a free-text name — category 19 (Underspecified IDs) and category 1 (Vague/generic) + +**Symbol:** `OnlineTable.name?: string | undefined` (model.ts:125). JSDoc: +"Full three-part (catalog, schema, table) name of the table." + +**Issue:** A field called `name` carries a structured identifier of the form +`catalog.schema.table`. The same shape appears as: +- `OnlineTable.name` (here, model.ts:125) +- `DeleteOnlineTableRequest.name` (model.ts:95) +- `GetOnlineTableRequest.name` (model.ts:119) +- `OnlineTableSpec.sourceTableFullName` (model.ts:156) — note: this one is + more descriptive + +Three of four use `name` (with the constraint in JSDoc); one uses +`sourceTableFullName`. The naming is inconsistent *within this very file* +for the same conceptual shape (a three-part UC name). + +**Suggested:** either: +1. Rename `OnlineTable.name` to `fullName` (mirrors `sourceTableFullName`), + *and* rename `*Request.name` to `*Request.fullName`. This loses the AIP + resource-name convention. +2. Or, rename `OnlineTableSpec.sourceTableFullName` to `sourceTableName` + (drops `Full`, matches all other `*.name` shapes) and accept that the + JSDoc is the only place that documents the three-part constraint. + +Option 2 is the cheaper cleanup and aligns with REST `{name}` path +conventions. Cross-reference the identical `featurestore.PublishSpec.onlineTableName` +which also lacks `Full` prefix. **Pick one and apply SDK-wide.** + +This finding *also* hits category 19 (underspecified IDs): the field is a +**structured string** (`catalog.schema.table`) — neither the field name nor +the type enforces the format. A typed wrapper (e.g. +`type ThreePartName = string & { __brand: 'three-part' }`) is an option but +cross-SDK convention keeps it as a `string`. **Pass on the wrapper, flag the +inconsistency.** + +--- + +### 14. `OnlineTable.tableServingUrl` repeats "table" — category 8 (Redundant suffixes) + +**Symbol:** `OnlineTable.tableServingUrl?: string | undefined` (model.ts:131). + +**Issue:** Inside `OnlineTable`, the prefix `table…` is implicit. The field +name `tableServingUrl` repeats "table" — `servingUrl` (or `dataServingUrl`, +matching the JSDoc "Data serving REST API URL") would suffice. Compare to +`pipelineId` (model.ts:171) which lives in `OnlineTableSpec` and does *not* +prefix `tableTable…` or `onlineTable…`. + +**Suggested:** `servingUrl`. The JSDoc says "Data serving REST API URL for +this table" — `servingUrl` reads the same. + +--- + +### 15. `OnlineTable.unityCatalogProvisioningState` is overly verbose — category 7 (Overly verbose) + +**Symbol:** `OnlineTable.unityCatalogProvisioningState?: ProvisioningInfo_State | undefined` +(model.ts:137). 31 characters. + +**Issue:** The JSDoc explains the field is "The provisioning state of the +online table entity in Unity Catalog. This is distinct from the state of the +data synchronization pipeline (i.e. the table may be in 'ACTIVE' but the +pipeline may be in 'PROVISIONING' as it runs asynchronously)." That's the +*reason* the field exists — to disambiguate from the data-sync state. The +field name spells out "unityCatalogProvisioningState" which is descriptive +but long. + +The companion `OnlineTable.status` (model.ts:129) is the data-sync state. +Reasonable parallel names would be: +- `OnlineTable.ucState` / `OnlineTable.dataState` — too cryptic. +- `OnlineTable.provisioningState` / `OnlineTable.status` — `provisioningState` + is shorter and the JSDoc covers the UC scoping. + +**Suggested:** `provisioningState`. The JSDoc retains the disambiguation. +This also lines up with finding 1 (rename of the enum type to +`ProvisioningState`) — the field and type names become naturally consistent. + +--- + +### 16. `OnlineTable.status` vs `OnlineTable.unityCatalogProvisioningState` — category 17 (Inconsistent action verbs) and category 6 (Misleading names) + +**Symbols:** `OnlineTable.status` (model.ts:129), +`OnlineTable.unityCatalogProvisioningState` (model.ts:137). + +**Issue:** Two state-like fields on the same type: + +- `status: OnlineTableStatus` — the "data synchronization status." +- `unityCatalogProvisioningState: ProvisioningInfo_State` — the "provisioning + state of the online table entity in Unity Catalog." + +A reader sees `status` and `…State` side by side. Both are conceptually +"the state of the table"; the suffix difference (`Status` vs `State`) is not +a meaningful discriminator. The waiter (`CreateOnlineTableWaiter`, +client.ts:174) reads `unityCatalogProvisioningState` to decide done-ness, +not `status` — surprising. + +**Suggested:** rename `status` to `syncStatus` or `dataSyncStatus` to make +clear it is about the *data pipeline*, not the entity. Pair with +`provisioningState` (finding 15) for the UC-side entity state. + +--- + +### 17. `OnlineTableStatus.detailedState` vs `OnlineTableStatus.detailedStatus` — category 17 (Inconsistent action verbs) and category 12 (Duplicate concepts) + +**Symbols:** `OnlineTableStatus.detailedState` (model.ts:183), +`OnlineTableStatus.detailedStatus` (model.ts:187). + +**Issue:** Two fields named `detailed…` on the same type, distinguished only +by the singular/perfect noun suffix (`State` vs `Status`). `detailedState` +is an enum (`OnlineTableState`); `detailedStatus` is a discriminated union +of `ProvisioningStatus | ContinuousUpdateStatus | TriggeredUpdateStatus | +FailedStatus`. They are *related* — `detailedState` indicates which +`$case` of `detailedStatus` will be present — but the names provide zero +hint of the relationship. + +**Suggested:** rename `detailedState` to `state` and `detailedStatus` to +`statusDetails` or `details`. Reads more naturally: +```ts +const { state, details, message } = onlineTable.status!; +``` + +`OnlineTableStatus.message` (model.ts:185) is also descriptive — it is the +plain-text version of the state. The trio `state` / `details` / `message` +forms a coherent shape. **Flag at port time.** + +--- + +### 18. `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` all share `…Status` suffix — category 20 (Type-suffix tautology) — *pass with note* + +**Symbols:** `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, +`FailedStatus`, `ProvisioningStatus` (model.ts:71, 238, 102, 226). + +The four types all end with `Status`. Inside `OnlineTableStatus.detailedStatus` +(model.ts:187) the `$case` literals are `'continuousUpdateStatus'`, +`'triggeredUpdateStatus'`, `'failedStatus'`, `'provisioningStatus'` — also +`…Status`. The pattern is **consistent**. Suffix is repetitive but does +disambiguate from `OnlineTableSpec`/state enums. + +The `Failed` and `Provisioning` variants are also generic when read in +isolation — there could be many "failed status" or "provisioning status" +types in the SDK (and there are — see `database.SyncedTableProvisioningStatus`, +finding 19 below). + +**Suggested:** consider prefixing with the parent concept — e.g. +`OnlineTableContinuousUpdate`, `OnlineTableTriggeredUpdate`, +`OnlineTableFailed`, `OnlineTableProvisioning`. But this is verbose. **Pass +with note**, flag cross-package overlap below. + +--- + +### 19. Cross-package overlap: `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` ↔ `database.SyncedTable*Status` — category 12 (Duplicate concepts) + +**Symbols:** +- `onlinetables.ContinuousUpdateStatus` ↔ `database.SyncedTableContinuousUpdateStatus` +- `onlinetables.TriggeredUpdateStatus` ↔ `database.SyncedTableTriggeredUpdateStatus` +- `onlinetables.FailedStatus` ↔ `database.SyncedTableFailedStatus` +- `onlinetables.ProvisioningStatus` ↔ `database.SyncedTableProvisioningStatus` + +**Issue:** All four pairs model the same shape (fields are identical or +near-identical). `database` adds a `SyncedTable` prefix to each — disambiguates +within `@databricks/sdk-core` if these were merged, but creates a duplicate +type surface across packages. Same root cause as finding 8 (`OnlineTableState` +↔ `SyncedTableState`). + +**Suggested:** harmonise — define once in `@databricks/sdk-onlinetables` or +in `@databricks/sdk-core` and re-export. **SDK-wide cleanup.** + +--- + +### 20. `PipelineProgress.latestVersionCurrentlyProcessing` is awkward — category 7 (Overly verbose) and category 13 (Verb-tense inconsistency) + +**Symbol:** `PipelineProgress.latestVersionCurrentlyProcessing?: number | undefined` +(model.ts:207). 32 characters. + +**Issue:** "currently processing" packs a present-progressive verb into a +field name, which is unusual for TS field naming. The JSDoc says "The source +table Delta version that was last processed by the pipeline. The pipeline +may not have completely processed this version yet." — so the *field* records +"the most recent version we've seen / started processing" and the JSDoc +notes processing may be incomplete. + +Compare to `ContinuousUpdateStatus.lastProcessedCommitVersion` (model.ts:76) +which describes essentially the same idea with a participle (`Processed`) — +and is *clearer*: it's the version that was processed. + +So the same package has two different names for the same Delta-version idea: +- `latestVersionCurrentlyProcessing` (PipelineProgress) +- `lastProcessedCommitVersion` (ContinuousUpdateStatus, FailedStatus, + TriggeredUpdateStatus) + +The JSDoc on `lastProcessedCommitVersion` (model.ts:73) even says "may not +be completely synced to the online table yet" — same caveat as +`latestVersionCurrentlyProcessing`'s JSDoc. So they describe the same thing. + +**Suggested:** rename `latestVersionCurrentlyProcessing` to +`lastProcessedVersion` (consistency with `lastProcessedCommitVersion` — and +even simpler since `PipelineProgress` does not refer to Delta commit +versions specifically). Or unify on `lastProcessedCommitVersion`. **Flag for +upstream and port-time fix.** + +--- + +### 21. `PipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` mixed nouns — category 17 (Inconsistent action verbs) and category 8 (Redundant suffixes) + +**Symbols:** `PipelineProgress.syncedRowCount` (model.ts:209), +`PipelineProgress.totalRowCount` (model.ts:211), +`PipelineProgress.syncProgressCompletion` (model.ts:213). + +**Issue:** Three fields about the progress of a sync: + +- `syncedRowCount` — past participle "synced" + noun "rowCount". OK. +- `totalRowCount` — adjective "total" + noun "rowCount". OK. +- `syncProgressCompletion` — noun "sync" + noun "progress" + noun + "completion". Triple nominalisation. The JSDoc says "The completion ratio + of this update. This is a number between 0 and 1." — so the field is the + *ratio* or *fraction* of completion. + +`syncProgressCompletion` is verbose. A consumer would write: +```ts +const pct = progress.syncProgressCompletion! * 100; +``` +when `progress.completion` or `progress.completionRatio` would read the +same. + +**Suggested:** `completionRatio` (matches the unit) or `progress` (matches +the parent type name `PipelineProgress` — though circular). +`completionRatio` is the clearer pick. Alternative: model as a percentage +(0–100) and call it `percentComplete`. + +--- + +### 22. `PipelineProgress.estimatedCompletionTimeSeconds` unit-suffix is fine — *pass* + +**Symbol:** `PipelineProgress.estimatedCompletionTimeSeconds` (model.ts:215). + +`…Seconds` unit suffix is the right move when the field is a raw number. +TypeScript has no unit type system. **Pass.** + +(One nit: `estimatedTimeRemainingSeconds` or `secondsUntilComplete` would +read more naturally — "estimatedCompletionTimeSeconds" parses as "estimated +completion-time, in seconds" which is the same. But this is a stylistic +preference. **Pass.**) + +--- + +### 23. `OnlineTableSpec.sourceTableFullName` — category 8 (Redundant suffixes) and category 19 (Underspecified IDs) — see finding 13 + +**Symbol:** `OnlineTableSpec.sourceTableFullName?: string | undefined` +(model.ts:156). + +Already covered in finding 13. **Pass with note** — `Full` qualifier is +redundant when JSDoc already specifies "Three-part (catalog, schema, table) +name". `sourceTableName` would suffice. Cross-reference +`featurestore.PublishTableRequest.sourceTableName` (no `Full`). + +--- + +### 24. `OnlineTableSpec.timeseriesKey` vs `OnlineTableSpec.primaryKeyColumns` (singular vs plural) — category 9 (Singular/plural mismatch) + +**Symbols:** `OnlineTableSpec.primaryKeyColumns?: string[]` (model.ts:158), +`OnlineTableSpec.timeseriesKey?: string` (model.ts:160). + +**Issue:** Plural array vs. singular scalar — the names match the shapes: +plural noun for the array, singular noun for the scalar. The mismatch is +semantic: a *primary key* in databases is typically one composite key over +multiple columns; here it is modelled as an array (which is fine, the array +*is* the composite key). A *timeseries key* is one column. So the naming is +consistent with the semantics. + +However, the JSDoc on `timeseriesKey` (model.ts:159) says "Time series key +to deduplicate (tie-break) rows with the same primary key." — it does not +specify whether it accepts multi-column or single-column. Treat as +single-column scalar. + +**Pass** with a JSDoc note (state explicitly "single column name"). + +--- + +### 25. `OnlineTableSpec.performFullCopy` is a verb-as-field — category 13 (Verb-tense inconsistency) and category 6 (Misleading names) + +**Symbol:** `OnlineTableSpec.performFullCopy?: boolean | undefined` +(model.ts:169). + +**Issue:** Boolean fields typically use `is…`, `has…`, `…Enabled`, or +`enable…` prefixes. `performFullCopy` reads as a *command* — "perform a full +copy" — rather than a *state*. Compare to the family of booleans in +`database/v1` (`enableReadableSecondaries`, `enablePgNativeLogin`, +`stopped`) — `enable…` is the dominant pattern. + +The JSDoc is also long (model.ts:161–168), but the field name itself reads +imperatively. **Suggested:** `fullCopyOnly` or `enableFullCopy` (matches the +SDK-wide `enable*` boolean pattern). Cross-reference +`database.DatabaseInstance.enableReadableSecondaries` for the pattern. + +--- + +### 26. `OnlineTableSpec.pipelineId` is server-generated — category 6 (Misleading names) — *pass with note* + +**Symbol:** `OnlineTableSpec.pipelineId?: string | undefined` (model.ts:171). +JSDoc: "ID of the associated pipeline. Generated by the server - cannot be +set by the caller." + +**Issue:** The field appears in the request *spec* but the JSDoc says it is +output-only. Mixing input/output in the same struct is a wire-level +decision; the JSDoc captures the asymmetry. TS does not yet have a clean +way to model output-only fields in input types (e.g. `Readonly<…>` is +declarative not runtime-enforced). + +**Pass** — naming is fine; the misleadingness is structural (mixed +input/output), not a naming bug. + +--- + +### 27. `OnlineTableSpec.schedulingPolicy` discriminated-union case names use verb prefixes — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) + +**Symbol:** `OnlineTableSpec.schedulingPolicy` $case literals +`'runContinuously'` / `'runTriggered'` (model.ts:145, 150). + +**Issue:** Each `$case` literal is a verb phrase: `runContinuously` (verb + +adverb), `runTriggered` (verb + past-participle). The companion types are +`OnlineTableSpec_ContinuousSchedulingPolicy` and +`OnlineTableSpec_TriggeredSchedulingPolicy` (noun-suffixed). + +The mixed POS (case name is a verb-phrase, type name is a noun-phrase) is +ungrammatical. Reading code: +```ts +spec.schedulingPolicy = { $case: 'runContinuously', runContinuously: {} }; +// ^^^^^^^^^^^^^^^^^ +// verb phrase used as a literal key +``` + +The verb-phrase form mirrors the wire field names `run_continuously` / +`run_triggered` — which themselves model the operation ("run continuously +vs. run triggered"). + +**Suggested:** rename `$case` literals to noun-phrase form (`'continuous'` / +`'triggered'`) to match the companion type names. **Flag at port time.** + +--- + +### 28. `CreateOnlineTableRequest` and `GetOnlineTableRequest` and `DeleteOnlineTableRequest` repeat `OnlineTable` — category 7 (Overly verbose) — *pass, SDK-wide pattern* + +**Symbols:** `CreateOnlineTableRequest`, `DeleteOnlineTableRequest`, +`GetOnlineTableRequest` (model.ts:87, 93, 117). + +The Request/Response type names follow the SDK convention +`{Action}{Resource}Request`. Within the package scope `CreateRequest` / +`DeleteRequest` would suffice (only one resource), but every other TS +package qualifies. **Pass on package consistency.** + +--- + +### 29. `Client` class name — category 1 (Vague/generic) — *pass* + +Package convention. Every TS package exports a single `Client` class scoped +to its import path (e.g. `@databricks/sdk-onlinetables/v1.Client`). **Pass.** + +--- + +### 30. `Client.createOnlineTable` etc. — *pass* + +**Symbols:** `Client.createOnlineTable` (client.ts:67), +`Client.deleteOnlineTable` (client.ts:108), `Client.getOnlineTable` +(client.ts:127). + +Standard `{verb}{Resource}` method names. **Pass on style.** The +`OnlineTable` repetition (inside `@databricks/sdk-onlinetables/v1`) is +SDK-wide convention. **Pass.** + +(Cross-package note: `featurestore.deleteOnlineTable` and +`onlinetables.deleteOnlineTable` collide — see `featurestore.md` finding 22. +**Not a per-package fix.**) + +--- + +### 31. `Client.createOnlineTableWaiter` returns a `CreateOnlineTableWaiter` — category 14 (Go/Java-style names) + +**Symbol:** `Client.createOnlineTableWaiter` (client.ts:92), returns +`CreateOnlineTableWaiter` (client.ts:152). + +**Issue:** The Go SDK uses `…AndWait()` or `XXXWaiter()` methods; the JS +SDK port mirrors this. In TS, the canonical pattern would be a +`waitForCreation()` or `createAndWait()` method, possibly with a fluent +poller object. The current shape returns a `Waiter` object which the caller +must then call `.wait()` on. The double-step (`createOnlineTableWaiter` → +`.wait()`) is awkward — neither is the final operation. Compare to +`database.CreateDatabaseInstanceWaiter` (audited in `database.md` finding +14). + +Class name `CreateOnlineTableWaiter` is a verb-noun composite: +"the create-online-table waiter" — i.e. a waiter for the create operation. +Reads ambiguously: a waiter that creates? A waiter for creation? **Suggest** +`OnlineTableCreationWaiter` or `OnlineTablePoller`. **Flag for SDK-wide +waiter naming policy.** + +**Pass per project convention,** flag for SDK-wide cleanup. + +--- + +### 32. `CreateOnlineTableWaiter.wait` and `CreateOnlineTableWaiter.done` — *pass* + +**Symbols:** `CreateOnlineTableWaiter.wait` (client.ts:163), +`CreateOnlineTableWaiter.done` (client.ts:207). + +Standard. **Pass.** + +--- + +### 33. `StillRunningError` class is internal but module-scoped — category 4 (Underscores in TS identifiers) — *pass* + +**Symbol:** `class StillRunningError extends Error {}` (client.ts:39). + +Not exported. Named meaningfully ("the operation is still running, so +retry"). **Pass.** + +--- + +### 34. `host` / `httpClient` / `logger` / `userAgent` private fields — *pass* + +**Symbols:** Private fields on `Client` (client.ts:42–48). Acronym handling +matches the project rule (`HttpClient`, `Url` would be flagged, but +`HttpClient` matches the imported type). **Pass.** + +--- + +### 35. `PACKAGE_SEGMENT` constant SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) + +**Symbol:** `PACKAGE_SEGMENT` (client.ts:34). + +**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true +constants (primitive literal values like `MAX_LEN = 10`). `PACKAGE_SEGMENT` +is a runtime object literal (`{ key, value }`) constructed from a JSON +import. The value *is* constant per-process, but the identifier shape +violates the project rule. The same name is used in every package's +`client.ts` — project-wide convention. + +**Suggested:** `packageSegment` or `clientPackageSegment`. **Flag for +SDK-wide cleanup**, do not fix in isolation. + +--- + +### 36. Comment on `PACKAGE_SEGMENT` is a sentence-fragment in lowercase — category 14 (Go/Java-style names) — *pass* + +The JSDoc comment at client.ts:33 ("Package identity segment for this client +to be used in the User-Agent header.") is fine — proper sentence, ends with +a period (matches `.agent/rules` / user CLAUDE.md style). + +--- + +### 37. `unmarshal*Schema` / `marshal*Schema` Go vocabulary — category 14 (Go/Java-style names) + +**Symbols:** `unmarshalContinuousUpdateStatusSchema`, +`unmarshalFailedStatusSchema`, `unmarshalOnlineTableSchema`, +`unmarshalOnlineTableSpecSchema`, +`unmarshalOnlineTableSpec_ContinuousSchedulingPolicySchema`, +`unmarshalOnlineTableSpec_TriggeredSchedulingPolicySchema`, +`unmarshalOnlineTableStatusSchema`, `unmarshalPipelineProgressSchema`, +`unmarshalProvisioningStatusSchema`, `unmarshalTriggeredUpdateStatusSchema`, +and the parallel `marshal*Schema` set (model.ts:253–602). + +**Issue:** "Marshal" / "Unmarshal" is Go-ism vocabulary. The TS/JS ecosystem +uses "serialize" / "deserialize", or, working with Zod, "parse" / "stringify" +/ "schema". The whole SDK uses this convention; **flag for SDK-wide +cleanup, not this package alone.** + +The `*Schema` suffix is also redundant — `unmarshalOnlineTable` without +`Schema` would suffice since the value's type is `z.ZodType` +and there are no non-schema cousins. **Pass with note.** + +Additionally, the `unmarshalOnlineTableSpec_…Schema` chain compounds with +finding 1's underscore problem — each carries an explicit lint suppression +(model.ts:331, 335, 507, 511). + +--- + +### 38. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) + +**Symbol:** `HttpCallOptions` interface (utils.ts:15). + +**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the +neighbouring `CallOptions` exists in `@databricks/sdk-options/call`. Naming +both *in the same file* (`HttpCallOptions` here, `CallOptions` imported on +line 12) confuses readers — which "Call" do they mean? **Suggest** +`HttpRequestContext` or `ExecuteHttpArgs`. **Flag for SDK-wide cleanup** +(this `utils.ts` is generated boilerplate copied across every package, so +any fix must apply everywhere). + +--- + +### 39. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) + +**Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). + +**Issue:** Two functions named `execute…Call`. `executeCall` is a wrapper +that adapts public `CallOptions` to internal `Options` and calls `execute()` +from `@databricks/sdk-core/api`. `executeHttpCall` performs an HTTP request +and decodes the body. They do *different* things at *different* layers; the +names imply a hierarchical relationship that does not exist. The HTTP one +is roughly `sendAndDecode` or `doHttpRequest`. **Flag for SDK-wide cleanup;** +this file is generated boilerplate copied across every package. + +--- + +### 40. `readAll` — *pass* + +Helper does what its name says (reads a `ReadableStream` to +completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** + +--- + +### 41. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) + +**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). + +**Issue:** Two symmetric operations: response→object (parse) and +object→body-string (marshal). The verbs come from two different vocabularies +("parse" is generic TS/JS, "marshal" is Go). Internally consistent verb-pair +would be `parseResponse` / `serializeRequest` or `unmarshalResponse` / +`marshalRequest`. The current pair is awkward. + +**Suggested:** `serializeRequest` and `parseResponse` (TS-native vocabulary) +or commit fully to the Go terms: `unmarshalResponse` and `marshalRequest`. +**Flag for SDK-wide consistency.** + +--- + +## Cross-package alignment recommendations + +### A. `OnlineTable` ↔ `SyncedTable` duplication + +`onlinetables` and `database`/`postgres` model the same underlying concept +(a managed continuously-sync table from a Delta source to a backing +store) under two type families. Cross-package collisions in this audit: + +| `onlinetables` (this pkg) | `database` / `postgres` | +| ---------------------------------- | --------------------------------------------- | +| `OnlineTable` | `SyncedDatabaseTable` / `SyncedTable` | +| `OnlineTableSpec` | `SyncedTableSpec` | +| `OnlineTableState` | `SyncedTableState` (12 values, has a typo) | +| `OnlineTableStatus` | `SyncedTableStatus` | +| `ContinuousUpdateStatus` | `SyncedTableContinuousUpdateStatus` | +| `TriggeredUpdateStatus` | `SyncedTableTriggeredUpdateStatus` | +| `FailedStatus` | `SyncedTableFailedStatus` | +| `ProvisioningStatus` | `SyncedTableProvisioningStatus` | +| `PipelineProgress` | `SyncedTablePipelineProgress` | +| `ProvisioningInfo_State` | `ProvisioningInfo_State` (also in 4 pkgs) | +| `ProvisioningInfo` (empty) | `ProvisioningInfo` (empty) | + +This is the highest-cost duplication observed in the audit. **Strong P0 +recommendation:** consolidate. Options: + +1. **Pick one canonical package** (`onlinetables` is the shorter, cleaner + surface — no `SyncedTable` prefix, no spelling typos, no SCREAMING_SNAKE + on most values). Have `database` re-export from `onlinetables` with + deprecation notes. +2. **Hoist all `Online/Synced{Table…}` types** into + `@databricks/sdk-core/synctables` (or similar) and re-export from both + service packages. + +**Coordinate with SDK platform team.** + +--- + +### B. `DeleteOnlineTableRequest` field-name divergence + +`onlinetables.DeleteOnlineTableRequest.name` vs. +`featurestore.DeleteOnlineTableRequest.onlineTableName`. Already covered in +finding 11. Harmonise on `name`. + +--- + +### C. Enum-naming convention divergence: `OnlineTableState` (flat) vs `ProvisioningInfo_State` (underscored) + +Both enums in **the same file** use different naming conventions: + +```ts +export enum OnlineTableState { ... } // model.ts:7 — flat +export enum ProvisioningInfo_State { ... } // model.ts:57 — underscored +``` + +Same generator, same file. The right SDK-wide policy is to always emit flat +names (strip the proto namespace). **Flag for generator.** + +--- + +## Counts by severity + +| Severity | Count | Findings | +| -------- | ----- | -------- | +| **High** (style guide violations, cross-package collisions) | 7 | #1, #2, #5, #11, #17, #25, #35, **and** cross-package A | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 14 | #3, #4, #6, #7, #8, #12, #13, #14, #15, #16, #19, #20, #21, #23, #27, #41 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 11 | #9, #10, #18, #24, #26, #28, #31, #37, #38, #39, #41 | +| **Pass / acceptable** | 9 | #18, #22, #24, #26, #28, #29, #30, #32, #33, #34, #36, #40 | + +--- + +## Top fixes (highest local return) + +1. **#11** — harmonise `DeleteOnlineTableRequest.name` vs. + `featurestore.DeleteOnlineTableRequest.onlineTableName` field name. Quick + cross-package fix. +2. **#14** — rename `OnlineTable.tableServingUrl` → `servingUrl`. Local, + no other consumers. +3. **#15** — rename `OnlineTable.unityCatalogProvisioningState` → + `provisioningState`. Local. +4. **#12** — rename `CreateOnlineTableRequest.table` → `onlineTable`. Local + port-time fix. +5. **#17** — rename `OnlineTableStatus.detailedState` → `state` and + `detailedStatus` → `statusDetails` / `details`. Local readability win. +6. **#20** — rename `PipelineProgress.latestVersionCurrentlyProcessing` → + `lastProcessedVersion`. Matches sibling `lastProcessedCommitVersion`. +7. **#21** — rename `PipelineProgress.syncProgressCompletion` → + `completionRatio`. Local. +8. **#25** — rename `OnlineTableSpec.performFullCopy` → `enableFullCopy` + (matches SDK `enable*` boolean pattern). + +--- + +## Top fixes (SDK-wide) + +1. **Cross-package A** — consolidate `OnlineTable` vs `SyncedTable` type + families into one canonical surface. +2. **#1** — strip proto-namespace underscores from generated enum types + (`ProvisioningInfo_State` → `ProvisioningState`). +3. **#5** — `UpperCamelCase` enum members (string value preserved as wire + form). +4. **#37, #41** — settle marshal/unmarshal vs. parse/serialize vocabulary. +5. **#35** — `PACKAGE_SEGMENT` → `packageSegment`. +6. **#31** — settle waiter naming convention (`*Waiter` vs `*Poller` vs + inline `*AndWait`). + +--- diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md new file mode 100644 index 00000000..64f5169d --- /dev/null +++ b/.agent/naming-audit/permissions.md @@ -0,0 +1,269 @@ +# Naming Audit: permissions + +**Path:** `packages/permissions/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Workspace-object permissions — get, set, update, and inspect ACLs (access control lists) attached to Databricks workspace objects (clusters, jobs, notebooks, dashboards, pipelines, registered models, queries, repos, files, instance pools, etc.). Distinct from `grants` (Unity Catalog privileges on UC securables), though the two surfaces overlap conceptually and lexically. +**Total weird names flagged:** 40 + +## Summary +| Severity | Count | +| --- | --- | +| High | 12 | +| Medium | 14 | +| Low | 9 | +| Observation | 5 | + +The permissions package contains 9 generated types, 1 enum, and 4 client methods, plus utility helpers. Three thematic problems dominate. (1) The request-as-imperative-verb pattern (`GetObjectPermissions`, `SetObjectPermissions`, `UpdateObjectPermissions`, `GetPermissionLevels`) collides with the verb-noun methods on `Client`, so users write `client.setObjectPermissions(req: SetObjectPermissions)` and the type name looks like a command rather than a payload. (2) The `PermissionLevel` enum mixes acronym-prefix patterns (`CAN_*`, `IS_*`) with redundant suffixes (`CAN_MONITOR` vs `CAN_MONITOR_ONLY`, `CAN_MANAGE_RUN`, `CAN_CREATE_APP`) and includes a sentinel `UNSPECIFIED` whose semantics ("delete this principal") are only discoverable from JSDoc — the value name actively misleads. (3) The package overlaps heavily with `grants` in vocabulary (`Permission`, `PermissionsResponse`, `permissionLevels`) while modelling a completely different concept; the only public type distinguishing this package from its sibling is `AccessControlRequest`/`Response`, both of which use the IAM-style "access control list" pattern that's unique-in-the-SDK. + +Two structural warts surface as a result of mechanical proto-to-TS porting: `GetPermissionLevels_Response` uses an embedded underscore (proto FQN flattening) and requires `// eslint-disable` annotations, and every request type tags its path-parameter fields with a verbose `requestObjectType` / `requestObjectId` prefix (rather than `objectType`/`objectId` or just `type`/`id`) — the prefix is wire-format leakage. Finally, `requestObjectType` and `requestObjectId` are typed `string` with a documented closed enumeration of valid values listed verbatim in JSDoc (26 different object types in a single doc-comment), surfacing the "stringly-typed closed enum" anti-pattern that TypeScript's type system would otherwise prevent. + +--- + +## High severity + +### 1. `GetObjectPermissions` (type) — `src/v1/model.ts:79` +- **Why weird:** Top-level request type named with an imperative verb. `Get` is a verb; types are nouns. Used in `client.ts:67` as `getObjectPermissions(req: GetObjectPermissions)`, producing verb-noun-verb-noun. Reader cannot tell from `GetObjectPermissions` whether this is a request shape or a method name. +- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs). +- **Suggested name:** `GetObjectPermissionsRequest` (matches the SDK-wide `*Request` convention used in `accountaccesscontrol`, `grants` partially, etc.) or simpler `ObjectPermissionsQuery` / `ObjectRef`. +- **Rationale:** Same anti-pattern documented in `.agent/naming-audit/grants.md` #1. Verb-shaped type names are reserved for methods. + +### 2. `SetObjectPermissions` (type) — `src/v1/model.ts:115` +- **Why weird:** Same as #1. `Set` is a verb. Type is used at `client.ts:121` as `setObjectPermissions(req: SetObjectPermissions)`. +- **Category:** 7, 14, 17. +- **Suggested name:** `SetObjectPermissionsRequest` or `ObjectPermissionsAssignment`. +- **Rationale:** See #1. + +### 3. `UpdateObjectPermissions` (type) — `src/v1/model.ts:123` +- **Why weird:** Same as #1, #2. Verb-shaped type. Used at `client.ts:147` as `updateObjectPermissions(req: UpdateObjectPermissions)`. +- **Category:** 7, 14, 17. +- **Suggested name:** `UpdateObjectPermissionsRequest` or `ObjectPermissionsPatch` (since the HTTP method is PATCH, not PUT — see #35). +- **Rationale:** See #1. + +### 4. `GetPermissionLevels` (type) — `src/v1/model.ts:86` +- **Why weird:** Verb-shaped type AND singular/plural collision: the type wraps a request asking for the list of permission levels available, but `GetPermissionLevels` reads like "the operation of getting permission levels" — a method. Inside the package there are then four overlapping `Permission*` names with this one being the most easily misread: it's a request type, not a response type, despite having the word "Levels" plural (which would suggest a result). +- **Category:** 7, 9 (singular/plural mismatch), 14, 17. +- **Suggested name:** `GetPermissionLevelsRequest` or `PermissionLevelsQuery`. +- **Rationale:** Disambiguates request vs response; aligns with #5. + +### 5. `GetPermissionLevels_Response` — `src/v1/model.ts:93` +- **Why weird:** Proto-style nested message name with an embedded underscore (`MessageType_FieldName`), illegal under standard TS naming. The codegen has to emit `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directly above the declaration (line 92) and again above the schema declaration (line 158). The identifier is part of the public surface — `index.ts:11` re-exports it — so every downstream consumer is forced to write `GetPermissionLevels_Response` with the underscore in their own code. +- **Category:** 4 (underscores in TS identifier), 14 (proto/Go-style name). +- **Suggested name:** `GetPermissionLevelsResponse` (drop the underscore), or — cascading from #4 — `PermissionLevelsResponse`. +- **Rationale:** Google TypeScript Style Guide §5.2 mandates PascalCase without internal underscores. The proto FQN-flattening trick should be hidden by the generator, not surfaced to the public API. Same problem is documented in `.agent/naming-audit/grants.md` #4–6 for that package. + +### 6. `PermissionLevel.UNSPECIFIED` — `src/v1/model.ts:31` +- **Why weird:** The enum value `UNSPECIFIED` is overloaded into a sentinel meaning "delete this principal's permissions" — but the *name* says the opposite ("unspecified"). The JSDoc on lines 27–30 clarifies this, but the name itself actively misleads: callers reading `permissionLevel: PermissionLevel.UNSPECIFIED` will reasonably interpret it as "no value set / left blank", not "remove the principal". Worse, the side-effect semantics (mutation) are encoded in what looks like a null-equivalent. +- **Category:** 6 (misleading name), 1 (vague). Sentinel-as-enum-value is a Go pattern. +- **Suggested name:** Split into a dedicated `Remove` or `Revoke` value (`PermissionLevel.REMOVE` or `PermissionLevel.NONE`) — or, better, model deletion as an absent `permissionLevel` field in PATCH calls (the field is already `optional`) and remove the sentinel entirely. The current name guarantees that anyone reading a diff will be confused about whether `UNSPECIFIED` is a no-op or a destructive action. +- **Rationale:** Sentinel-encoded-as-enum-value is an idiom imported from protobuf/Go (`google.protobuf.UNSPECIFIED`) where every enum is required to have a zero value. TypeScript has no such constraint; explicit absence (`undefined`) is idiomatic. + +### 7. `PermissionLevel` enum has 20 inconsistently-named values — `src/v1/model.ts:7–32` +- **Why weird:** Mix of three naming patterns within a single enum: + - `CAN_*` (most common): `CAN_MANAGE`, `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`. + - `IS_*`: `IS_OWNER`. The lone `IS_*` value mixes copula+predicate, while everything else is modal verb+predicate. + - Pseudo-sentinel: `UNSPECIFIED` (see #6). +- The `CAN_*` prefix is implied by membership in `PermissionLevel` — a `PermissionLevel` is, by definition, what the principal can do. The redundant `CAN_` prefix on 19 of 20 values is purely a wire-format leak from the Go enum, which followed the same protobuf convention. +- **Category:** 2 (redundant enum prefix — flagged explicitly in the task prompt), 17 (inconsistent action verbs within the same enum). +- **Suggested name:** Drop the `CAN_` prefix: `MANAGE`, `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, `USE`, etc. `IS_OWNER` becomes `OWNER`. `UNSPECIFIED` becomes `REMOVE` per #6 (or eliminated). +- **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. The same logic applies here: `PermissionLevel.MANAGE` is shorter, more readable, and just as unambiguous as `PermissionLevel.CAN_MANAGE` (Google TS Style Guide §5.4 prefers concise enum members; protobuf-style prefixes are a wire concern that does not need to leak into the surface). + +### 8. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` +- **Why weird:** Two distinct values that differ in name only by the `_ONLY` suffix. The JSDoc (none provided) gives no clue what the difference is. From product context, `CAN_MONITOR` typically grants monitoring AND inherited subset privileges; `CAN_MONITOR_ONLY` strictly limits to monitoring. Cannot infer this from the names — must consult external API docs. +- **Category:** 6 (misleading: pair seems exhaustive but `_ONLY` semantics are non-obvious), 17 (inconsistent: no other value uses `_ONLY` to differentiate). +- **Suggested name:** Document inline what the difference is, OR rename to `MONITOR_FULL` / `MONITOR_READ_ONLY` / similar pair where the contrast is on the *predicate*, not on a vague `_ONLY` qualifier. +- **Rationale:** Whenever an enum exposes "X" and "X_ONLY" with no JSDoc, every caller hits a Stack Overflow question. + +### 9. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` — `src/v1/model.ts:17,18` +- **Why weird:** 28- and 30-character enum members. These values are specific to one object type (`registered-models` in MLflow Model Registry — staging vs production model versions) but live in a universal enum applicable to 25+ object types. Equivalent to having `CAN_MANAGE_DASHBOARD_DRAFTS` or `CAN_MANAGE_NOTEBOOK_REVISIONS` in the same enum: the values are scoped to one domain but visible to all. +- **Category:** 18 (long enum values — flagged explicitly in the task prompt), 17 (inconsistent — most values are object-type-agnostic, these two leak object-type semantics into the enum). +- **Suggested name:** Possibly `MANAGE_STAGING` / `MANAGE_PRODUCTION` with JSDoc clarifying applicability ("Applies to registered-models only"), or move these MLflow-specific levels into a separate enum. +- **Rationale:** Universal enum + object-specific values is a discoverability hazard; users browsing autocomplete will see these as valid choices for clusters/jobs/dashboards. + +### 10. `CAN_CREATE_APP` — `src/v1/model.ts:26` +- **Why weird:** Same problem as #9 — object-type-specific value in a universal enum. The `App` here refers to Databricks Apps (a specific object kind); other object types have no equivalent. The `_APP` suffix is also inconsistent with how the rest of the enum names the noun being created (most `CAN_CREATE` is unsuffixed; `CAN_CREATE_APP` is the only one with an explicit noun). +- **Category:** 18, 17. +- **Suggested name:** Same pattern as #9 — document scope, or partition. +- **Rationale:** See #9. + +### 11. Concept duplication with `grants` package — cross-package +- **Why weird:** A sibling package `packages/grants/src/v1/` also defines a `Permission*` vocabulary (`PermissionsChange`, `getPermissions`, `updatePermissions`, `GetPermissions_Response`) for a different operation (Unity Catalog privileges on securables). Both packages re-export `Permission`-prefixed types from their `index.ts`. A user reading `import { Permission } from '@databricks/sdk-permissions/v1'` vs `import { PrivilegeAssignment } from '@databricks/sdk-grants/v1'` has no surface-level cue that these belong to disjoint domains. The `permissions` package operates on workspace objects (clusters, jobs, notebooks) via `requestObjectType: string` paths; the `grants` package operates on UC securables (catalogs, schemas, tables) via `securableType: string` paths. The vocabulary overlap obscures this distinction. +- This same observation appears in `.agent/naming-audit/grants.md` #10 — flagged from the other side of the mirror. +- **Category:** 12 (duplicate concepts across packages), 1 (vague top-level package naming). +- **Suggested name:** Rename one or both for disambiguation: `permissions` → `workspace-permissions` or `workspace-acl`; `grants` → `unity-catalog-grants` or `uc-privileges`. At minimum the public exports should be non-overlapping (no `Permission` prefix in both). +- **Rationale:** The two packages cover non-overlapping concrete operations but use heavily overlapping vocabulary — an enormous discoverability hazard. + +### 12. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:81,88,116,124` +- **Why weird:** Every request type carries `requestObjectType?: string | undefined`. The JSDoc on line 80 (and identically on 87, 116, 124) lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, clusters, cluster-policies, dashboards, database-projects, dbsql-dashboards, directories, experiments, files, genie, instance-pools, jobs, knowledge-assistants, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, supervisor-agents, vector-search-endpoints, or warehouses"`. The set is closed, well-known to the server, and stable — a perfect fit for a `RequestObjectType` enum or string literal union. The TS SDK ships it as bare `string` with no autocomplete or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) silently 4xx's at runtime. +- **Category:** 19 (underspecified ID), 1 (vague: bare `string`), 15 (generic field name). +- **Suggested name:** Define `type RequestObjectType = 'alerts' | 'alertsv2' | 'authorization' | 'clusters' | 'cluster-policies' | ...` (string literal union, 26 entries), or an `enum RequestObjectType` with kebab-cased values. The JSDoc explicitly enumerates the values; TypeScript should encode that enumeration. +- **Rationale:** This is the single biggest TS-affordance miss in the package. The Go SDK uses `string` because Go enums are second-class; TS has first-class string literal unions that match this exact use case. See also `.agent/naming-audit/grants.md` #19, #28 (same problem with `Privilege` and `SecurableType`). + +--- + +## Medium severity + +### 13. `requestObjectType` / `requestObjectId` prefix — `src/v1/model.ts:81,83,88,89,117,119,125,127` +- **Why weird:** All four request types prefix their two path parameters with `request`: `requestObjectType` and `requestObjectId`. The `request` prefix is wire-format leakage (the Databricks REST path uses `:request_object_type` and `:request_object_id` as URL path placeholders, presumably from an older API spec). On the TypeScript surface, every field is by definition part of a *request* — the `request` prefix carries zero information. +- **Category:** 7 (overly verbose / redundant prefix), 14 (wire-format leak), 15 (generic field name). +- **Suggested name:** `objectType` and `objectId`. The doc-comment on `requestObjectId` already calls it "The id of the request object" — drop the wire-format jargon and just say "object id". +- **Rationale:** Compare `GetObjectPermissions { requestObjectType, requestObjectId }` to `GetObjectPermissions { objectType, objectId }`. The latter reads as plain English. The `request` prefix is the same kind of cruft that `requestId` would have if it appeared in a `Request` type. + +### 14. `principalName` discriminated union — `src/v1/model.ts:35–51,56–72` +- **Why weird:** The discriminated union pattern is elegant in TS, but the field name `principalName` is misleading because the values inside are not all "names" — `servicePrincipalName` is documented as "application ID of a service principal" (line 48), which is a UUID, not a name. Calling the carrier field `principalName` and the SP variant `servicePrincipalName` together imply "principal name = service principal name = the SP's name", but the SP variant is the application *ID*, distinct from the SP's display name. +- **Category:** 6 (misleading), 19 (underspecified ID), 15 (overloaded "name"). +- **Suggested name:** Rename outer field to `principal` (per `grants` package convention, see #15) and rename the SP variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or document explicitly that `servicePrincipalName` is "the SP's application UUID, not its display name". +- **Rationale:** Same field name leaks "name" semantics onto a value that's a UUID. Type system can encode this with proper variant naming. + +### 15. `principalName` vs `principal` cross-package — `src/v1/model.ts:35,56` (this package) vs `grants/src/v1/model.ts:22,33,69` (grants package) +- **Why weird:** `permissions` uses `principalName?: { $case: 'userName' | 'groupName' | 'servicePrincipalName' }` — a typed discriminated union. `grants` uses `principal: string` — a free-form string with a JSDoc-only constraint ("user email address or group name"). Same concept, two utterly different representations across sister packages. A user familiar with one will not be productive in the other. +- **Category:** 12 (duplicate concept), 17 (inconsistent shapes for the same domain object). +- **Suggested name:** Pick one across the SDK. The `permissions` package's discriminated union is strictly more type-safe and should be the canonical representation. +- **Rationale:** Consistency. Two packages, two ways to spell "who is this for". The audit on `grants` (#12) flagged this from the other side. + +### 16. `displayName` on `AccessControlResponse` — `src/v1/model.ts:74` +- **Why weird:** `displayName?: string | undefined` doc-comment "Display name of the user or service principal." (line 73). But the response also carries `principalName` (line 56) which is the carrier-by-identity. Two name-like fields on the same response and the relationship is JSDoc-only. Worse, the JSDoc *doesn't* say "Display name of the user **or group** or service principal" — it omits groups, possibly because groups don't have display names — but the type allows `principalName.$case === 'groupName'` paired with a `displayName` value, which then has no specified semantics. +- **Category:** 6 (misleading), 1 (vague: groups + displayName combo undocumented). +- **Suggested name:** Keep `displayName` but expand doc-comment to cover all three principal kinds. +- **Rationale:** Cross-checking variant + display-name semantics is an integration footgun. + +### 17. `allPermissions: Permission[]` field — `src/v1/model.ts:76` +- **Why weird:** `allPermissions?: Permission[] | undefined` with JSDoc "All permissions." — minimal information value in the comment. The qualifier "all" suggests there's a "some permissions" variant that doesn't exist. Internally, the type just lists every effective permission (direct + inherited) — so the `all` prefix is the wire-format way of saying "the merged result". Stripping `all` would lose nothing. +- **Category:** 7 (overly verbose), 1 (vague qualifier), 15 (generic field name on a typed array). +- **Suggested name:** `permissions: Permission[]` (matches the type-name plural). The field would read `AccessControlResponse.permissions` — natural English. +- **Rationale:** Field names that re-state the parent type or carry vague qualifiers add noise. The `all` qualifier here implies a `some`/`partial` companion that doesn't exist. + +### 18. `Permission` type — `src/v1/model.ts:98` +- **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance of `Permission` here is really an "effective permission" — a permission level paired with inheritance metadata. The name `Permission` alone is the second-most-overloaded noun in the SDK (after `Client`). +- **Category:** 1 (vague), 12 (cross-package collision: `grants` also exports `Permission`-prefixed types). +- **Suggested name:** `EffectivePermission` (matches the doc semantics) or `PermissionGrant` (clarifies that this is a grant, not the concept of permission abstractly). +- **Rationale:** `Permission` as a standalone PascalCase noun is so common across IAM systems that it's nearly content-free without qualification. + +### 19. `PermissionsDescription` — `src/v1/model.ts:104` +- **Why weird:** Type carries `permissionLevel?: PermissionLevel | undefined` and `description?: string | undefined`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. Should be `PermissionLevelDescription` (singular). Also, the suffix `Description` is generic — the type is effectively a tuple of (level, description-text); it's the "metadata about a single permission level" record. +- **Category:** 9 (singular/plural mismatch — `Permissions` plural for a single-level descriptor), 1 (generic suffix), 15 (vague field `description: string`). +- **Suggested name:** `PermissionLevelDescription` or `PermissionLevelInfo`. +- **Rationale:** Singular/plural matters; one descriptor = one level. + +### 20. `PermissionsResponse` — `src/v1/model.ts:109` +- **Why weird:** Returned from THREE different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, `accessControlList` — i.e. it's "an ACL with metadata", not "a Permissions response". Name is generic; the *content* is the more meaningful concept ("ObjectAcl" or "AccessControlList"). +- **Category:** 1 (vague), 7 (Response suffix tautology), 20 (type-suffix tautology — `Permissions` + `Response` adds no info beyond `AccessControlList`). +- **Suggested name:** `ObjectAcl`, `ObjectPermissions`, or `AccessControlList`. Drop the `Response` suffix per the SDK-wide convention that responses are returned values, not named-as-such types. +- **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental to it being a return value. + +### 21. `accessControlList` field — `src/v1/model.ts:112,120,128` +- **Why weird:** Appears in three types (`PermissionsResponse`, `SetObjectPermissions`, `UpdateObjectPermissions`). The field is typed `AccessControlRequest[]` in the two request types and `AccessControlResponse[]` in the response — asymmetric typing under one field name. The conventional shorthand for "access control list" is "ACL" — the field could be `acl` (3 chars vs 18). Or just `entries` since the surrounding type already says "permissions" / "object permissions". +- **Category:** 7 (overly verbose), 20 (type-suffix tautology — field repeats type info), 17 (asymmetric: same field, different element types). +- **Suggested name:** `acl: AccessControlEntry[]` or `entries: AccessControlEntry[]`. +- **Rationale:** "Access control list" is verbose; "ACL" is standard. The asymmetric typing pattern is worth flattening. + +### 22. `inherited` boolean field — `src/v1/model.ts:100` +- **Why weird:** Bare `inherited?: boolean | undefined` on `Permission`. Boolean fields starting with a verb (`is*`, `has*`, `was*`) are easier to read at call sites. The current name reads `if (permission.inherited)` — fine, but `if (permission.isInherited)` is more idiomatic. +- **Category:** 14 (Go/Java-style: Go boolean fields commonly drop the `is`/`has` prefix, TS convention varies). +- **Suggested name:** `isInherited`. +- **Rationale:** Google TS Style Guide §5.3 recommends boolean prefixes for readability. The codebase uses both conventions but `is*`-prefixed booleans are more common in IAM contexts. + +### 23. `inheritedFromObject: string[]` — `src/v1/model.ts:101` +- **Why weird:** Plural field name (`Object`) typed as `string[]` of object identifiers. The "Object" suffix is singular but the type is plural — minor mismatch. More importantly, the JSDoc is missing entirely (line 101 has no comment) so the reader has to infer that this is the chain of inheritance paths from which this permission was derived. Each element is presumably an object path; the typing is bare `string`. +- **Category:** 9 (singular/plural mismatch), 19 (underspecified ID), 1 (vague — no JSDoc). +- **Suggested name:** `inheritedFromObjects: string[]` (plural for plural), or `inheritanceChain: string[]`. Document the element format. +- **Rationale:** Plurality should match the type's plurality; semantics should be JSDoc'd. + +### 24. `Client` — `src/v1/client.ts:41` +- **Why weird:** Top-level class named `Client`. Generic across every generated package. Users importing `Client` from multiple permission-adjacent packages (`@databricks/sdk-permissions`, `@databricks/sdk-grants`, `@databricks/sdk-accountaccesscontrol`) must alias all three. +- **Category:** 1 (vague), 12 (cross-package name clash). +- **Suggested name:** `PermissionsClient`. +- **Rationale:** SDK convention in AWS, Azure, GitHub Octokit, etc. is service-prefixed client class names. + +### 25. `requestObjectType` doc-comment duplication — `src/v1/model.ts:80,87,116,124` +- **Why weird:** Four identical 1-line doc-comments listing all 26 valid object types. The list is 280 characters long and is copy-pasted verbatim into every request type. Any change requires four parallel edits. +- **Category:** Observation, 17 (consistency — all four are identical, so this isn't an inconsistency, but it is fragile). +- **Suggested name:** Define `type RequestObjectType` (see #12) and link to it from a single source of truth. +- **Rationale:** DRY for documentation, type-safe for callers. + +### 26. `flattenQueryParams` (utility) — `src/v1/utils.ts:123` +- **Why weird:** Exported but unused in this package — `permissions` client doesn't take query parameters in any of its four methods. Dead-looking export, identical to the same wart documented in `.agent/naming-audit/grants.md` #37. +- **Category:** 11 (effectively-internal exports), Observation. +- **Suggested name:** Remove (or move to a shared `@databricks/sdk-core` util). +- **Rationale:** Generator emits the same helper into every package even when unused. + +--- + +## Low severity + +### 27. `unmarshalAccessControlResponseSchema` and similar — `src/v1/model.ts:131,159,170,182,193` +- **Why weird:** Six exported `unmarshal*Schema` and three `marshal*Schema` (lines 208, 235, 249) constants. Long names with redundant `Schema` suffix; the `z.ZodType` type annotation already says they're Zod schemas. Plus `unmarshalGetPermissionLevels_ResponseSchema` (line 159) embeds the proto underscore and requires eslint-disable (line 158). +- **Category:** 8 (redundant `Schema` suffix), 4 (underscore), 20 (type-suffix tautology). +- **Suggested name:** Drop `Schema` suffix → `unmarshalAccessControlResponse`, `marshalSetObjectPermissions`, etc. +- **Rationale:** Naming consistency; type signature already conveys the schema-ness. + +### 28. `unmarshalGetPermissionLevels_ResponseSchema` — `src/v1/model.ts:159` +- **Why weird:** 47-character name combining #5 (`_Response` underscore), #27 (`Schema` suffix), and #4 (verbose request type name). Requires eslint-disable on the preceding line. +- **Category:** 4, 7, 8. +- **Suggested name:** `unmarshalPermissionLevelsResponse` (cascading from #5 and #27). +- **Rationale:** Cascade. + +### 29. `marshalSetObjectPermissionsSchema` / `marshalUpdateObjectPermissionsSchema` — `src/v1/model.ts:235,249` +- **Why weird:** 37- and 41-character names. Same `Schema` suffix issue (#27) plus the verbose `Set/UpdateObjectPermissions` name (#2, #3). +- **Category:** 4 (cascading), 7, 8. +- **Suggested name:** `marshalSetObjectPermissions` / `marshalUpdateObjectPermissions`. +- **Rationale:** Cascade. + +### 30. `marshalAccessControlRequestSchema` — `src/v1/model.ts:208` +- **Why weird:** Same as #27. The schema type annotation here is `z.ZodType` (no generic), not `z.ZodType` — so the schema is *less* typed than its companions (which use `z.ZodType`). Inconsistent. +- **Category:** 8, 17. +- **Suggested name:** `marshalAccessControlRequest` with a generic on the Zod type. +- **Rationale:** Internal consistency. + +### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +- **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Cross-package consistency. + +### 32. `readAll` (utility) — `src/v1/utils.ts:40` +- **Why weird:** Internal helper name generic to the point of meaninglessness; clashes cognitively with `Array.prototype` methods and Web Streams APIs. Same pattern called out in `.agent/naming-audit/grants.md` #38. The function name is also a direct Go-port of `io.ReadAll`. +- **Category:** 1 (vague), 14 (Go-style). +- **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. +- **Rationale:** Cross-package consistency. + +### 33. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same 152-line file. The `model.ts` file uses `marshal*` / `unmarshal*` consistently — `parseResponse` is the odd one out. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. +- **Rationale:** Same finding as `.agent/naming-audit/grants.md` #39. Mirroring helps readers map TS→wire/wire→TS at a glance. + +### 34. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Another `Options`-suffixed type; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. +- **Category:** 1 (vague suffix), 17 (inconsistent — internal struct shouldn't share a suffix with the user-facing CallOptions). +- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). +- **Rationale:** Distinguish internal context bags from user-facing option structs. Same finding as `grants.md` #40. + +### 35. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:146` +- **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 156). The request type `UpdateObjectPermissions` is symmetric in name to `SetObjectPermissions` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. A user reading both method names side-by-side (`set...` and `update...`) might reasonably assume both perform full replacement. +- **Category:** 17 (inconsistent action verbs), Observation. +- **Suggested name:** `patchObjectPermissions` for the PATCH method, OR explicit JSDoc on `update*` clarifying merge semantics. +- **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. + +--- + +## Observations + +### 36. Three response paths converge on `PermissionsResponse` +`getObjectPermissions`, `setObjectPermissions`, and `updateObjectPermissions` all return the same `PermissionsResponse` type (`client.ts:70,123,149`). This is fine functionally but means callers can't distinguish "the state I just wrote" from "the state I just read" by type — only by which method was called. For an audit log or comparison flow, this loses information. Naming-adjacent because the type carries no read/write/post-update distinction. +- **Category:** Observation. + +### 37. Sentinel value `UNSPECIFIED` in PATCH is the only mutation-state encoded in an enum +The `PermissionLevel.UNSPECIFIED` sentinel (see #6) is unique in the SDK: it's the only enum value across `permissions`, `grants`, `accountaccesscontrol`, and `iam` that doubles as a deletion marker when sent in a PATCH body. Most APIs model this with a separate request body shape (e.g. `removals: Principal[]`) or with HTTP DELETE. Encoding "remove me" as an enum value alongside "let me have this permission" is unusual. +- **Category:** Observation, 6 (misleading). + +### 38. Doc-comment list of object types is potentially stale +The hardcoded list in `requestObjectType` doc-comments includes `database-projects`, `genie`, `knowledge-assistants`, `supervisor-agents` — all relatively new product surfaces. The list will need updating with every new permission-able workspace object. As-is the SDK has 26; if not regularly synced with the server, the JSDoc will drift. +- **Category:** Observation. + +### 39. No pagination — all methods are unpaginated single-call +Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods, see `grants.md` #41), `permissions` has no listing operation. Every method here is by-object-id; there's no "list all permissioned objects" surface. This is correct for the API but worth noting because users coming from `grants` (or `accountaccesscontrol`) might expect parallel list semantics. Naming-adjacent because the absence of `list*` here aligns the method-vocabulary differently than its sibling packages. +- **Category:** Observation. + +### 40. `marshalAccessControlRequestSchema` type annotation lacks generic — `src/v1/model.ts:208` +The schema is typed `z.ZodType` (without ``) while every other schema in the file is typed `z.ZodType`. Inconsistent; reduces type-safety at the schema-usage sites. Naming-adjacent because a fully-typed schema would also make the generated `marshalRequest` calls type-safe. +- **Category:** Observation, 17. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md new file mode 100644 index 00000000..98364a74 --- /dev/null +++ b/.agent/naming-audit/pipelines.md @@ -0,0 +1,519 @@ +# Naming Audit: pipelines + +**Path:** `packages/pipelines/src/v2/` +**Versions audited:** v2 +**Inferred domain:** Lakeflow Declarative Pipelines (formerly Delta Live Tables / DLT) — create / clone / get / list / edit / delete / restore pipelines, start / stop / list / get pipeline **updates** ("a run of a pipeline"), and a vast catalog of ingestion connectors (Salesforce, Workday, Outlook, Kafka, RabbitMQ, TikTok Ads, ServiceNow, Confluence, Jira, ...). The API was renamed multiple times (DLT → Spark Declarative Pipelines → Lakeflow Declarative Pipelines); branding leakage and acronyms are abundant. + +**Files audited:** +- `src/v2/model.ts` (6,198 lines) — 31 enums, ~110 interfaces, ~80 marshal/unmarshal schemas. +- `src/v2/client.ts` (646 lines) — 13 RPC methods + 2 paginators + `StopWaiter`. +- `src/v2/utils.ts` (151 lines) — generic HTTP/marshal helpers (no domain names). +- `src/v2/index.ts` (172 lines) — re-exports. + +## Summary + +| Severity | Count | Notes | +| ------------ | ----- | ------------------------------------------------------------------------------------------- | +| High | 26 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions, plural `Pipelines` prefix. | +| Medium | 38 | Underscores, redundant prefixes/suffixes, vague names, acronym casing, generic IDs. | +| Low | 21 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| Observations | 7 | Patterns spanning the whole file (proto leakage, branding history). | +| **Total** | **92** | | + +Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. + +--- + +## High + +### H1. `Update` is a verb in every other Databricks SDK but the noun "pipeline run" here — pervasive overloading +- **Locations:** `model.ts:283` (`UpdateCause`), `model.ts:300` (`UpdateMode`), `model.ts:311` (`UpdateState`), `model.ts:1091` (`GetUpdate`), `model.ts:1099` (`GetUpdate_Response`), `model.ts:1689` (`ListUpdates`), `model.ts:1701` (`ListUpdates_Response`), `model.ts:2738` (`StartUpdate`), `model.ts:2789` (`StartUpdate_Response`), `model.ts:2879` (`UpdateInfo`), `model.ts:2934` (`UpdateStateInfo`), `client.ts:352` (`getUpdate`), `client.ts:434` (`listUpdates`), `client.ts:504` (`start`), plus every `updateId` field. +- **Category:** 1 (vague), 6 (misleading — rebrand history), 13 (verb/noun inconsistency), 17 (inconsistent action verbs). +- **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdate` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdate` → `GetRunRequest`, `ListUpdates` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateMode` → `RunMode`, `UpdateStateInfo` → `RunSummary`, `updateId` → `runId`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. +- **Rationale:** "Update" is the standard verb for `PUT`/`PATCH` (and `EditPipeline` already takes that slot — the client method is `edit()`, but the HTTP verb is `PUT`). Every JS/TS developer expects `update()` to mean "mutate". The DLT product feature historically named the unit-of-execution "Update" but Databricks itself renamed the concept to **"Pipeline run"** when the product became Lakeflow Declarative Pipelines. The SDK is on the wrong side of the rebrand. The same problem ripples through `start()` (the method that "starts an update"), `getUpdate()`, and `listUpdates()`. This is the single most confusing name in the package. + +### H2. `client.edit()` returns `EditPipeline_Response` instead of `UpdatePipeline_Response` — verb collision avoidance is leaking through +- **Locations:** `client.ts:241` (`edit`), `model.ts:830` (`EditPipeline`), `model.ts:929` (`EditPipeline_Response`). +- **Category:** 13 (verb-tense inconsistency: `Edit` vs `Update` vs `Modify`), 6 (misleading: HTTP verb is `PUT`). +- **Suggestion:** Rename `EditPipeline` → `UpdatePipelineRequest` and the client method `edit()` → `update()`. Then rename the "pipeline run" concept per H1 to free up the `Update` token. +- **Rationale:** The package uses `Edit` only because the `Update` noun was burned by DLT history. Once H1 is applied, `edit()` should follow the standard `create()`/`update()`/`delete()` REST pattern used by every other SDK (`jobs`, `clusters`, `instancepools`, etc., all use `update()`). + +### H3. `client.start()` is "start a pipeline update" — but it reads as "start a pipeline" +- **Location:** `client.ts:504`. +- **Category:** 6 (misleading), 17 (inconsistent action verbs). +- **Suggestion:** Rename `start(req: StartUpdate)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. +- **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipeline)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. + +### H4. `Pipelines*` prefix (plural) on a single-pipeline package — proto-package leakage +- **Locations:** `model.ts:212` (`PipelinesAwsAvailability`), `model.ts:225` (`PipelinesAzureAvailability`), `model.ts:241` (`PipelinesEbsVolumeType`), `model.ts:249` (`PipelinesGcpAvailability`), `model.ts:2224` (`PipelinesAutoScale`), `model.ts:2243` (`PipelinesAwsAttributes`), `model.ts:2332` (`PipelinesAzureAttributes`), `model.ts:2359` (`PipelinesClusterLogConf`), `model.ts:2373` (`PipelinesDbfsStorageInfo`), `model.ts:2382` (`PipelinesEnvironment`), `model.ts:2405` (`PipelinesGcpAttributes`), `model.ts:2446` (`PipelinesInitScriptInfo`), `model.ts:2474` (`PipelinesJobRunAs`), `model.ts:2489` (`PipelinesMavenLibrary`), `model.ts:2507` (`PipelinesS3StorageInfo`). +- **Category:** 8 (redundant suffix/prefix), 9 (singular/plural mismatch), 14 (Go/Java-style names). +- **Suggestion:** Drop the `Pipelines` prefix. The package itself is `@databricks/sdk-pipelines` and the import disambiguates from `@databricks/sdk-clusters`. The types become `AwsAvailability`, `AwsAttributes`, `AutoScale`, `ClusterLogConf`, `DbfsStorageInfo`, `Environment`, `GcpAttributes`, `InitScriptInfo`, `JobRunAs`, `MavenLibrary`, `S3StorageInfo`. If global collision is feared, use `PipelineCluster`-style singular: `PipelineEnvironment`, `PipelineAwsAttributes`, etc. +- **Rationale:** The proto package is `pipelines.proto`, so the generator prefixed every type with `Pipelines`. A consumer types `new PipelinesJobRunAs(...)` and the plural reads as "RunAs for many jobs in many pipelines" — neither is true. `PipelineCluster` (singular, `model.ts:1898`) shows the convention the package would have if generated consistently. + +### H5. `PipelinesJobRunAs` references `Job` from a `Pipelines` package +- **Location:** `model.ts:2474`. +- **Category:** 6 (misleading — `Job` is a separate Databricks product), 14 (Go-style). +- **Suggestion:** Rename to `RunAs` or `PipelineRunAs`. Drop the `Job` token entirely — this type is not used by `@databricks/sdk-jobs`. +- **Rationale:** `Job` belongs to the `jobs` API. A user reading `runAs: PipelinesJobRunAs` cannot tell whether the pipeline is associated with a job or just borrows the shape. The proto comment ("Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as.") confirms this is a pipeline-only concept. + +### H6. `Pipeline` is never used as a type name — the central domain entity is missing +- **Locations:** N/A — the package has `PipelineSpec`, `PipelineStateInfo`, `GetPipeline_Response`, `BaseJob`-style scattering, but no plain `Pipeline` type. +- **Category:** 1 (vague/generic alternative missing), 6 (misleading). +- **Suggestion:** Add an exported `Pipeline` type that consolidates the runtime view (`GetPipeline_Response` is the closest). Alternatively rename `GetPipeline_Response` → `Pipeline`. Keep `PipelineSpec` as the write-form (the "settings" sub-object). +- **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipeline_Response`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. + +### H7. `EditPipeline` / `CreatePipeline` / `ClonePipeline` / `PipelineSpec` all duplicate 26 of the same fields +- **Locations:** `model.ts:508` (`ClonePipeline`), `model.ts:672` (`CreatePipeline`), `model.ts:830` (`EditPipeline`), `model.ts:2108` (`PipelineSpec`). +- **Category:** 12 (duplicate concepts). +- **Suggestion:** Extract `PipelineSpec` as the shared base and have `CreatePipelineRequest`, `EditPipelineRequest`, `ClonePipelineRequest` use TS intersection: `type CreatePipelineRequest = PipelineSpec & {allowDuplicateNames?: boolean; dryRun?: boolean; ...}`. +- **Rationale:** Each of the four interfaces redeclares `id`, `name`, `storage`, `configuration`, `clusters`, `libraries`, `ingestionDefinition`, `gatewayDefinition`, `trigger`, `target`, `schema`, `filters`, `continuous`, `development`, `photon`, `edition`, `channel`, `catalog`, `notifications`, `serverless`, `deployment`, `restartWindow`, `budgetPolicyId`, `tags`, `eventLog`, `rootPath`, `environment`, `usagePolicyId`, `rewindGenerationInterval`. Drift between the four is silent. Counted manually — 26 identical fields × 4 types = 104 redundant declarations. + +### H8. `Update` field names on `Origin` reference the "pipeline run" sense of Update — silent overloading +- **Locations:** `model.ts:1791` (`updateId`), `model.ts:1816` (`graphId`), `model.ts:2879` (`UpdateInfo.updateId`), `model.ts:2934` (`UpdateStateInfo.updateId`). +- **Category:** 19 (underspecified IDs), 1 (vague). +- **Suggestion:** Rename `updateId` → `runId` (paired with H1). Document that the wire JSON key is `update_id` for compatibility. +- **Rationale:** A field named `updateId` on `Origin` (event source) leaves "update of what?" unanswered. Users wonder if it refers to the last-modification timestamp. + +### H9. `client.events()` method name is too generic +- **Location:** `client.ts:267`. +- **Category:** 1 (vague), 17 (inconsistent action verbs — should be `listEvents`). +- **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. +- **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). + +### H10. `client.list()` / `client.listIter()` — too generic for the package's bare-`list` slot +- **Locations:** `client.ts:377`, `client.ts:416`. +- **Category:** 1 (vague), 17 (inconsistent verbs). +- **Suggestion:** Rename to `listPipelines()` / `listPipelinesIter()` to match the request type `ListPipelines` and to disambiguate from `listUpdates`/`listEvents`. +- **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelines`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. + +### H11. `PipelineState_PipelineState` enum — underscore suffix tautology +- **Location:** `model.ts:392` (`export enum PipelineState_PipelineState`). +- **Category:** 20 (type-suffix tautology), 4 (underscores). +- **Suggestion:** Rename the enum to `PipelineState`. +- **Rationale:** `PipelineState_PipelineState.RUNNING` reads as "state.state.RUNNING". Same pattern as `ScdType_ScdType` (H12). + +### H12. `ScdType_ScdType` enum — underscore suffix tautology and cryptic acronym +- **Locations:** `model.ts:415` (`export enum ScdType_ScdType`), `index.ts:32`, `index.ts:150`. +- **Category:** 20 (suffix tautology), 4 (underscores), 5 (cryptic abbreviation). +- **Suggestion:** Rename `ScdType_ScdType` → `ScdType`. Better: rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — and the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). +- **Rationale:** Same issue as H11. SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). + +### H13. `StorageMode` enum is a parallel of `ScdType_ScdType` with three overlapping values — duplicate concept +- **Locations:** `model.ts:263` (`StorageMode.SCD_TYPE_1` / `SCD_TYPE_2` / `APPEND_ONLY`), `model.ts:415` (`ScdType_ScdType.SCD_TYPE_1` / `SCD_TYPE_2` / `APPEND_ONLY`). +- **Category:** 12 (duplicate concepts). +- **Suggestion:** Delete one. The JSDoc on `IngestionPipelineDefinition_TableSpecificConfig.storageMode` (`model.ts:1437-1440`) literally says "Mutually exclusive with scd_type — a 400 error is returned if both are set." This is two names for the same field. Pick one (probably `StorageMode` since it includes a meaningful `UNSPECIFIED`). +- **Rationale:** Forcing the client to choose between two synonymous enums based on which one the field is typed as is the worst possible API ergonomic. Users will set both and get a 400. + +### H14. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" +- **Location:** `model.ts:410`. +- **Category:** 6 (misleading — references method `run` that does not exist; the method is `start`). +- **Suggestion:** Fix JSDoc to reference `start()`. After H3, both will line up at `run()`. +- **Rationale:** Currently the user reads "call `run`" and finds no `run()` method on `Client`. + +### H15. `client.delete()` collides with JS `delete` keyword +- **Location:** `client.ts:204`. +- **Category:** 10 (reserved-word collision). +- **Suggestion:** Rename to `deletePipeline()` (matching `restorePipeline()` already at `client.ts:475`). Alternatively, `remove()`. +- **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. `restorePipeline()` already uses the verbose form, so the asymmetry is jarring (`client.delete` vs `client.restorePipeline`). + +### H16. `client.restorePipeline()` is verbose, but its siblings are short (`delete`, `get`, `clone`) +- **Location:** `client.ts:475`. +- **Category:** 7 (overly verbose), 17 (inconsistent verbs). +- **Suggestion:** Either shorten to `restore()` (parallel with `clone()`, `delete()`, `get()`) or lengthen the siblings to `deletePipeline()`, `getPipeline()`, `clonePipeline()`. The request type is already named `RestorePipelineRequest` — which is itself inconsistent with sibling request types (`DeletePipeline`, `GetPipeline`, `ClonePipeline` have no `Request` suffix). +- **Rationale:** Pick one suffix convention and apply it. Mixing methods on the same client is the smell. + +### H17. `RestorePipelineRequest` ends in `Request` but other request types do not +- **Locations:** `model.ts:2618` (`RestorePipelineRequest`), `model.ts:2624` (`RestorePipelineRequest_Response`), `model.ts:477` (`ApplyEnvironmentRequest`), `model.ts:482` (`ApplyEnvironmentRequest_Response`). +- **Category:** 8 (redundant suffix), 17 (inconsistent). +- **Suggestion:** Pick one convention and stick to it. Either drop `Request` everywhere (so this becomes `RestorePipeline`, `ApplyEnvironment`) or add it everywhere (`DeletePipelineRequest`, `EditPipelineRequest`, ...). +- **Rationale:** Two named conventions in the same file confuse every reader. `RestorePipelineRequest_Response` is doubly bad: the underscore says it is a proto-nested name (intended to be `RestorePipelineRequest.Response`) but a response shape suffixed `RequestRequest_Response` is bizarre. + +### H18. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +- **Location:** `model.ts:56`. +- **Category:** 6 (misleading), 16 (field contradicts type domain). +- **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. +- **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. + +### H19. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" +- **Location:** `model.ts:313` ("Update is waiting for previous update to finish."). +- **Category:** 6 (misleading). +- **Suggestion:** Doc rewrite (English) after H1: "Run is waiting for previous run to finish." +- **Rationale:** Same as H1 — once `Update` is renamed to `Run`, every JSDoc that mentions "update" in this enum needs to follow. + +### H20. `StartUpdate.fullRefresh` / `refreshSelection` / `fullRefreshSelection` / `resetCheckpointSelection` / `refreshFlowSelection` — 5 booleans-or-arrays describing overlapping concepts +- **Location:** `model.ts:2738-2780`. +- **Category:** 12 (duplicate concepts), 17 (inconsistent verbs). +- **Suggestion:** Collapse into a single discriminated union `refreshMode: FullGraph | FullRefresh | TableSelection | FlowSelection | RewindMode` (analogous to existing `RewindSpec`). At minimum, document the precedence rules in JSDoc. +- **Rationale:** The combinatorial space is currently five fields × two values each = 32 combinations, of which JSDoc clarifies only "if both refresh_selection and full_refresh_selection are empty, this is a full graph update." The other 30 combinations are undefined. + +### H21. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +- **Locations:** `model.ts:1746`, `model.ts:556` (`notifications?: Notifications[]`), etc. +- **Category:** 9 (singular/plural mismatch). +- **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. +- **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. + +### H22. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) +- **Locations:** `model.ts:644-670`, `model.ts:1323`, `model.ts:1357`. +- **Category:** 20 (type-suffix tautology), 12 (duplicate naming). +- **Suggestion:** Rename the outer interface to `ConnectorOptions` and the inner discriminator to `options` (or `payload`). Then `connectorOptions: {payload: {...}}` reads cleanly. +- **Rationale:** Currently `ConnectorOptions.connectorOptions.googleAdsOptions` requires four nested identifiers all containing "options". Marshaling code (`model.ts:4763-4875`) is illegible because of it. + +### H23. `PipelinesEnvironment` vs `IngestionPipelineDefinition` — two `Pipeline*` namespaces, only one is plural +- **Locations:** `model.ts:2382` (`PipelinesEnvironment`), `model.ts:1173` (`IngestionPipelineDefinition`). +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent prefix). +- **Suggestion:** Drop the prefix on `PipelinesEnvironment` (see H4). Or rename to `PipelineEnvironment` (singular). Match `PipelineCluster`, `PipelineDeployment`, `PipelineEvent`, `PipelineLibrary`, `PipelineSpec`, `PipelineStateInfo`, `PipelineTrigger` — all singular. +- **Rationale:** Out of 22 pipeline-prefixed types, 8 use plural (`Pipelines*`) and 14 use singular (`Pipeline*`). No domain reason for the split; pure generator artifact. + +### H24. Underscore-named proto nested types — 27 separate identifiers with `eslint-disable` +- **Locations:** 27 lines, each tagged `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` Notable: `ApplyEnvironmentRequest_Response` (`model.ts:482`), `ClonePipeline_ConfigurationEntry` (`model.ts:591`), `ClonePipeline_Response` (`model.ts:597`), `ClonePipeline_TagsEntry` (`model.ts:604`), `CommunityConnectorOptions_OptionsEntry` (`model.ts:622`), `CreatePipeline_ConfigurationEntry`, `CreatePipeline_ParametersEntry`, `CreatePipeline_Response`, `CreatePipeline_TagsEntry`, `DeletePipeline_Response`, `EditPipeline_ConfigurationEntry`, `EditPipeline_ParametersEntry`, `EditPipeline_Response`, `EditPipeline_TagsEntry`, `FileIngestionOptions_FileFormat`, `FileIngestionOptions_FormatOptionsEntry`, `FileIngestionOptions_SchemaEvolutionMode`, `GetPipeline_Response`, `GetPipeline_Response_ParametersEntry`, `GetUpdate_Response`, `GoogleDriveOptions_GoogleDriveEntityType`, `GoogleDriveOptions_GoogleDriveIngestionScope`, `IngestionPipelineDefinition_*` (10 nested), `KafkaOptions_ClientConfigEntry`, `ListPipelineEvents_Response`, `ListPipelines_Response`, `ListUpdates_Response`, `PeriodicTrigger_TimeUnit`, `PipelineCluster_CustomTagsEntry`, `PipelineCluster_SparkConfEntry`, `PipelineCluster_SparkEnvVarsEntry`, `PipelineSpec_ConfigurationEntry`, `PipelineSpec_TagsEntry`, `PipelineState_PipelineState`, `RestorePipelineRequest_Response`, `ScdType_ScdType`, `SharepointOptions_SharepointEntityType`, `StartUpdate_ParametersEntry`, `StartUpdate_Response`, `StopPipeline_Response`, `TikTokAdsOptions_TikTokDataLevel`, `TikTokAdsOptions_TikTokReportType`, `Transformer_Format`, `Truncation_TruncationDetail`, `UpdateInfo_ParametersEntry`. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/Java-style names). +- **Suggestion:** Flatten everywhere. `PipelineState_PipelineState` → `PipelineState`, `IngestionPipelineDefinition_TableSpec` → `IngestionTableSpec`, etc. Use TS namespace-style with dot notation only where it disambiguates (e.g., `IngestionPipelineDefinition.TableSpec` via namespace export — but TS namespace exports inside modules are non-idiomatic). +- **Rationale:** TS identifiers conventionally use camelCase / PascalCase; underscores are reserved for special names (private fields by convention). 27 `eslint-disable` lines = 27 fights with the linter. The Generator should be re-targeted. + +### H25. `Sequencing.controlPlaneSeqNo` — abbreviated/cryptic identifier +- **Locations:** `model.ts:2661` (`Sequencing`), `model.ts:2665` (`controlPlaneSeqNo`). +- **Category:** 5 (cryptic abbreviations), 15 (generic field names). +- **Suggestion:** Rename to `controlPlaneSequenceNumber`. The JSDoc already calls it "A sequence number" — TS has no character budget. Sibling type `DataPlaneId.seqNo` (`model.ts:792`) has the same issue. +- **Rationale:** "SeqNo" is a Go/Java abbreviation. The wire JSON is `seq_no`, so the TS field rename is purely a surface improvement. + +### H26. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` +- **Location:** `model.ts:788`. +- **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). +- **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. +- **Rationale:** Every other `*Id` type in the SDK is a string. Reading `dataPlaneId: DataPlaneId` then accessing `dataPlaneId.seqNo` is jarring. + +--- + +## Medium + +### M1. `ConnectorType.CONNECTOR_TYPE_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:16-25`. +- **Category:** 2 (redundant enum prefix). +- **Suggestion:** Rename values to `UNSPECIFIED`, `CDC`, `QUERY_BASED`. TS already namespaces enum members by enum. +- **Rationale:** `ConnectorType.CONNECTOR_TYPE_CDC` reads as "ConnectorType.Type.CDC". + +### M2. `DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:31-40`. +- **Category:** 2. +- **Suggestion:** Drop `DAY_OF_WEEK_` prefix from `UNSPECIFIED`. Other values (`MONDAY`...) are fine. +- **Rationale:** Same as M1. Inconsistency: `MONDAY` is unprefixed but `UNSPECIFIED` is prefixed. + +### M3. `IngestionSourceType.INGESTION_SOURCE_TYPE_UNSPECIFIED` — redundant prefix on 1 of 80 values +- **Location:** `model.ts:60`. +- **Category:** 2. +- **Suggestion:** Drop the prefix. +- **Rationale:** Same as M1. + +### M4. `OutlookAttachmentMode.OUTLOOK_ATTACHMENT_MODE_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:177`. +- **Category:** 2. +- **Suggestion:** Drop. + +### M5. `OutlookBodyFormat.OUTLOOK_BODY_FORMAT_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:190`. +- **Category:** 2. +- **Suggestion:** Drop. + +### M6. `ParseMode.PARSE_MODE_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:198`. +- **Category:** 2. +- **Suggestion:** Drop. + +### M7. `PublishingMode.PUBLISHING_MODE_UNSPECIFIED` / `LEGACY_PUBLISHING_MODE` / `DEFAULT_PUBLISHING_MODE` — three redundant prefixes +- **Location:** `model.ts:256-260`. +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggestion:** Rename to `UNSPECIFIED`, `LEGACY`, `DEFAULT`. + +### M8. `StorageMode.STORAGE_MODE_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:264`. +- **Category:** 2. +- **Suggestion:** Drop. + +### M9. `FileIngestionOptions_FileFormat.FILE_FORMAT_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:338`. +- **Category:** 2. + +### M10. `FileIngestionOptions_SchemaEvolutionMode.SCHEMA_EVOLUTION_MODE_UNSPECIFIED` — redundant + verbose +- **Location:** `model.ts:353`. +- **Category:** 2, 18. + +### M11. `GoogleDriveOptions_GoogleDriveEntityType.GOOGLE_DRIVE_ENTITY_TYPE_UNSPECIFIED` — quadruple-redundant +- **Location:** `model.ts:362-369`. +- **Category:** 2, 18. +- **Suggestion:** The proto-nested name already contains "GoogleDrive" twice. The enum members repeat the brand a third time. Strip down to `EntityType.{Unspecified, File, FileMetadata, Permission, FilePermission, GroupMembership}`. + +### M12. `GoogleDriveOptions_GoogleDriveIngestionScope.GOOGLE_DRIVE_INGESTION_SCOPE_UNSPECIFIED` — same problem +- **Location:** `model.ts:372-379`. +- **Category:** 2, 18. + +### M13. `PeriodicTrigger_TimeUnit.TIME_UNIT_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:384`. +- **Category:** 2, 18. + +### M14. `ScdType_ScdType.SCD_TYPE_UNSPECIFIED` / `SCD_TYPE_1` / `SCD_TYPE_2` — every value names the enum +- **Location:** `model.ts:415-424`. +- **Category:** 2, 18. + +### M15. `SharepointOptions_SharepointEntityType.SHAREPOINT_ENTITY_TYPE_UNSPECIFIED` — triple-redundant +- **Location:** `model.ts:428`. +- **Category:** 2, 18. + +### M16. `TikTokAdsOptions_TikTokDataLevel.TIK_TOK_DATA_LEVEL_UNSPECIFIED` — same problem +- **Location:** `model.ts:440`. +- **Category:** 2, 3 (the casing of `TIK_TOK` splits `TikTok` which is normally one word). + +### M17. `TikTokAdsOptions_TikTokReportType.TIK_TOK_REPORT_TYPE_UNSPECIFIED` — same +- **Location:** `model.ts:450`. + +### M18. `Transformer_Format.FORMAT_UNSPECIFIED` — redundant prefix +- **Location:** `model.ts:461`. +- **Category:** 2. + +### M19. `PipelinesAwsAvailability.SPOT_WITH_FALLBACK` — value spells "SPOT", which is already what the enum is about +- **Location:** `model.ts:212-222`. +- **Category:** 18 (long enum values). +- **Suggestion:** Just `FALLBACK`. + +### M20. `PipelinesAzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — suffix repeats the enum name +- **Location:** `model.ts:226-235`. +- **Category:** 2 (redundant enum prefix/suffix). +- **Suggestion:** Drop `_AZURE`. Sibling `PipelinesAwsAvailability` does not use `_AWS`, so the asymmetry is gratuitous. Same for `PipelinesGcpAvailability.*_GCP` (M21 below). + +### M21. `PipelinesGcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` — `_GCP` suffix asymmetry +- **Location:** `model.ts:249-253`. +- **Category:** 2. + +### M22. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level +- **Location:** `model.ts:170-173`. +- **Category:** 6 (misleading). +- **Suggestion:** Rename enum to `EventStability` or rename value `DEPRECATED` → `LEGACY`. +- **Rationale:** `DEPRECATED` is widely used as a TS/JSDoc tag for "do not use." Reading `maturityLevel: DEPRECATED` mis-suggests the EVENT is deprecated, not the schema field. + +### M23. `EventLogSpec` — `Spec` suffix on a small config object +- **Location:** `model.ts:951`. +- **Category:** 8 (redundant suffix). +- **Suggestion:** `EventLogConfig` or just `EventLog`. The `Spec` suffix is overused (`PipelineSpec`, `RewindSpec`, `RewindDatasetSpec`, `EventLogSpec`, `IngestionPipelineDefinition_SchemaSpec`, `_TableSpec`, `_ReportSpec`). +- **Rationale:** TS doesn't need `Spec` as a discriminator; the type's role is clear from its field name. + +### M24. `Filters` — pluralized name for a 2-field struct +- **Location:** `model.ts:1029-1034`. +- **Category:** 9 (singular/plural mismatch), 1 (vague). +- **Suggestion:** Rename to `PathFilter` (singular). The shape is `{include?: string[]; exclude?: string[]}`. + +### M25. `PathPattern` field is `include: string` (singular, no array) but it represents a glob +- **Location:** `model.ts:1885-1888`. +- **Category:** 15 (generic field names), 6 (misleading). +- **Suggestion:** Rename type to `GlobPattern` and field to `pattern`. JSDoc says "The source code to include for pipelines" — `pattern` describes the *what*, `include` describes the *intent*. + +### M26. `Origin` — too generic for "event source metadata" +- **Location:** `model.ts:1777`. +- **Category:** 1 (vague). +- **Suggestion:** Rename to `EventOrigin` or `EventSource`. +- **Rationale:** "Origin" is also a DOM type (`Window.origin`) and a CORS concept. Type contains 23 fields covering everything from cloud region to flow IDs. + +### M27. `Origin.flowId` and `Origin.batchId` — IDs from unrelated subsystems +- **Locations:** `model.ts:1802` (`flowId`), `model.ts:1806` (`batchId`). +- **Category:** 19 (underspecified IDs). +- **Suggestion:** Document inline that `flowId` is "id of the streaming flow within the pipeline" and `batchId` is "id of a microbatch within a flow." Better: prefix as `streamingFlowId`, `microbatchId`. + +### M28. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type +- **Location:** `model.ts:1231`. +- **Category:** 6 (misleading), 16 (field contradicts type domain). +- **Suggestion:** Move to `NetsuiteOptions` connector-specific type. +- **Rationale:** A generic ingestion-definition type carrying a `netsuiteJarPath` field implies every other connector is incomplete. JSDoc literally says "Netsuite only configuration." Belongs in a per-connector options struct. + +### M29. `IngestionSourceType.WORKDAY_RAAS` — undefined acronym +- **Location:** `model.ts:69`. +- **Category:** 5 (cryptic abbreviation). +- **Suggestion:** Document inline that RaaS = "Reports as a Service" (Workday terminology). The acronym is non-obvious. + +### M30. `IngestionSourceType.GA4_RAW_DATA` — vendor-numbered identifier +- **Location:** `model.ts:70`. +- **Category:** 5. +- **Suggestion:** Document inline that GA4 = "Google Analytics 4." Sibling `GOOGLE_ANALYTICS` (`model.ts:121`) is the broader connector. + +### M31. `IngestionSourceType.COMMUNITY` — non-obvious meaning, requires comment +- **Location:** `model.ts:88-92`. +- **Category:** 1 (vague), 6 (misleading). +- **Suggestion:** Rename to `CUSTOM_LAKEFLOW_CONNECT` or document inline. +- **Rationale:** The proto comment explains: "Named COMMUNITY instead of GENERIC_LAKEFLOW_CONNECT (the connection type name) because we do not want to include LAKEFLOW in the public API." This is a *naming-decision-by-marketing*, which is the exact category of "Misleading names" worth flagging. + +### M32. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator +- **Location:** `model.ts:165`. +- **Category:** 1 (vague). +- **Suggestion:** `UC_FOREIGN_CATALOG` or document inline. +- **Rationale:** "Foreign Catalog" is a Unity Catalog concept; without context this looks like a country-of-origin enum value. + +### M33. `Origin.ucResourceId` mixes acronym casing +- **Location:** `model.ts:1810`. +- **Category:** 3 (acronym casing inconsistency). +- **Suggestion:** Either `ucResourceId` (current) or `UCResourceId` — the Google TS style guide says treat acronyms as words, so `ucResourceId` is correct. But sibling fields use the same lowercase pattern (`workspaceId`, `pipelineId`), so this one is internally consistent. Flagged because it could be `unityCatalogResourceId` for clarity. + +### M34. `eventType?: string` on `PipelineEvent` — string-typed enum +- **Location:** `model.ts:2057`. +- **Category:** 16 (field contradicts type domain). +- **Suggestion:** Define an `EventType` enum (or union of string literals) and type the field with it. Right now consumers have no IDE help. +- **Rationale:** JSDoc says "The event type. Should always correspond to the details." The Go SDK has the same field as string (porting fidelity), but TS could improve. + +### M35. `PipelineEvent.timestamp: string` — typed string but holds an ISO date +- **Location:** `model.ts:2049`. +- **Category:** 16. +- **Suggestion:** Document the format in JSDoc, or use a `Date | string` union. + +### M36. `RewindSpec.rewindTimestamp` / `rewindPointId` — fields prefixed with the type name +- **Location:** `model.ts:2637-2655`. +- **Category:** 20 (type-suffix tautology). +- **Suggestion:** Drop the `rewind` prefix on fields inside `RewindSpec`: `timestamp`, `pointId`, `datasets`. + +### M37. `Sequencing` — singular noun for a 2-field record describing one event's position +- **Location:** `model.ts:2661`. +- **Category:** 1 (vague). +- **Suggestion:** `EventSequence` or `EventPosition`. "Sequencing" is the action of putting in order, not the position itself. + +### M38. `EditPipeline.expectedLastModified: number` — wire is millis since epoch, but no JSDoc +- **Location:** `model.ts:840`. +- **Category:** 16 (field contradicts type domain), 19 (underspecified ID). +- **Suggestion:** Either type as `Date | number` or document "milliseconds since Unix epoch" in JSDoc. + +--- + +## Low + +### L1. `client.start()` JSDoc mentions "If there is already an active update" — should say "active run" +- **Location:** `client.ts:503`. +- **Category:** 6. + +### L2. `client.stop()` JSDoc mentions "Stops the pipeline by canceling the active update" — same +- **Location:** `client.ts:529`. + +### L3. `client.list()` JSDoc says "Lists pipelines defined in the Spark Declarative Pipelines system" +- **Location:** `client.ts:376`. +- **Category:** 6 (misleading), branding inconsistency. +- **Rationale:** The product is "Lakeflow Declarative Pipelines" per the IngestionPipelineDefinition JSDoc (`model.ts:1175`). Internal naming: "Spark Declarative Pipelines" (SDP). Public marketing name: "Lakeflow Declarative Pipelines." The SDK uses both, sometimes in adjacent JSDoc. + +### L4. JSDoc references to "SDP" appear in three fields, undefined +- **Locations:** `model.ts:551` (`ClonePipeline.channel` — "SDP Release Channel"), `model.ts:714` (`CreatePipeline.channel`), `model.ts:879` (`EditPipeline.channel`), `model.ts:2141` (`PipelineSpec.channel`), `model.ts:2379` (`PipelinesEnvironment` — "SDP's environment"). +- **Category:** 5 (cryptic abbreviation), 6 (misleading). +- **Suggestion:** Expand SDP → "Spark Declarative Pipelines" on first mention, with parenthetical "(internal name for Lakeflow Declarative Pipelines)". + +### L5. `PipelineLibrary.lib` field uses an abbreviation +- **Location:** `model.ts:2070`. +- **Category:** 5. +- **Suggestion:** Either `library` (matching `lib` but spelled out) or `source` (the discriminator). The current `lib` is a Go SDK shortening. + +### L6. `PipelinesS3StorageInfo.cannedAcl` — undocumented S3 jargon +- **Location:** `model.ts:2542`. +- **Category:** 5. +- **Suggestion:** Document inline: "canned ACL = a predefined S3 access-control list, e.g., `bucket-owner-full-control`." Currently the field name is fine since it matches the S3 API; only the casing (`cannedAcl` not `cannedAcl` — should be `cannedACL` per Google TS style? actually `cannedAcl` is correct). + +### L7. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent +- **Location:** `model.ts:2532`. +- **Category:** 3. +- **Suggestion:** `kmsKey` is the correct casing per Google TS style. Just flagging for cross-check with other AWS fields in the file. + +### L8. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system +- **Locations:** `model.ts:2525`, `model.ts:2530`. +- **Category:** 16. +- **Suggestion:** Use a discriminated union: `encryption?: {kind: 'none'} | {kind: 'sse-s3'} | {kind: 'sse-kms'; key: string}`. + +### L9. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" +- **Location:** `model.ts:1899`. +- **Category:** 16. +- **Suggestion:** Make this an enum `ClusterLabel.{Default, Maintenance}`. + +### L10. `PipelineCluster.applyPolicyDefaultValues` JSDoc says "won't be persisted" — should be marked deprecated or transient +- **Location:** `model.ts:1901`. +- **Category:** 6. +- **Suggestion:** Add `@deprecated` JSDoc tag. + +### L11. `Truncation_TruncationDetail.fieldName: string` — looks like a meta field but is the data +- **Location:** `model.ts:2876`. +- **Category:** 6 (mildly misleading). +- **Suggestion:** `truncatedFieldName` or rename type to `TruncatedField`. + +### L12. `JsonTransformerOptions.asVariant: boolean` — boolean named with prefix `as` +- **Location:** `model.ts:1540`. +- **Category:** 17 (inconsistent boolean naming). +- **Suggestion:** Rename to `parseAsVariant` or `parseAsVariantColumn`. +- **Rationale:** Other boolean fields in the file use `is*`/`enable*`/`has*` (`development`, `serverless`, `photon`, `continuous`, `enableEncryption`, `enableAutoClustering`, `enabled`, `inferColumnTypes`, `readerCaseSensitive`, `ignoreCorruptFiles`, `fatal`, `force`, `cascade`, `dryRun`, `incremental`). + +### L13. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc +- **Location:** `model.ts:493`. +- **Category:** Generator artifact leakage. +- **Suggestion:** Express via TS optionality (`?:`) instead of repeating "Optional" in JSDoc. + +### L14. `(Required, Immutable)` / `(Optional, Mutable)` proto tags appear in 60+ JSDoc blocks +- **Locations:** searches: `(Required`, `(Optional` throughout `model.ts`. +- **Category:** Generator artifact leakage. +- **Suggestion:** Remove or move to a structured `@required` / `@mutable` tag. + +### L15. `Origin.host` — generic field on an event source struct +- **Location:** `model.ts:1812`. +- **Category:** 15 (generic field name). +- **Suggestion:** `originHostname` or document inline. + +### L16. `RewindDatasetSpec.identifier: string` — generic when `datasetName` would do +- **Location:** `model.ts:2629`. +- **Category:** 15. +- **Suggestion:** `datasetIdentifier` or `fullyQualifiedName`. +- **Rationale:** JSDoc says "The identifier of the dataset (e.g., 'main.foo.tbl1')" — this is a UC three-part name. + +### L17. `RewindDatasetSpec.resetCheckpoints: boolean` and `RewindSpec.datasets[i].cascade: boolean` — coupled flags with no type-level link +- **Locations:** `model.ts:2631`, `model.ts:2633`. +- **Category:** 16. +- **Suggestion:** Group into an `options` substruct or document interactions in JSDoc. + +### L18. `IngestionPipelineDefinition_TableSpec.enableAutoClustering` and `clusteringColumns` — mutually exclusive booleans not enforced +- **Locations:** `model.ts:1426`, `model.ts:1435`. +- **Category:** 12 (duplicate concepts), 16. +- **Suggestion:** Use a discriminated union: `clustering?: {kind: 'auto'} | {kind: 'columns'; columns: string[]}`. +- **Rationale:** JSDoc explicitly says "we can only provide enable_auto_clustering or clustering_columns, added as separate fields as we cannot have repeated field in oneof." TS *can* express this — porting fidelity is what blocks it. + +### L19. `KafkaOptions.startingOffset: string` — typed string but documented as enum +- **Location:** `model.ts:1576`. +- **Category:** 16. +- **Suggestion:** Define `KafkaStartingOffset.{Latest, Earliest}` enum. + +### L20. `MetaMarketingOptions.level: string` — typed string but documented as enum +- **Location:** `model.ts:1718`. +- **Category:** 16. +- **Suggestion:** Define `MetaAggregationLevel.{Account, Ad, AdSet, Campaign}` enum. + +### L21. `MetaMarketingOptions.actionReportTime: string` — string enum +- **Location:** `model.ts:1724`. +- **Category:** 16. +- **Suggestion:** Define enum. + +--- + +## Observations + +### O1. The whole file is one giant proto port — 27 `eslint-disable` lines for underscore-named nested types +- **Files:** `model.ts` throughout. +- **Cross-reference:** This is the same pattern flagged in `jobs.md`. The pipelines package compounds it with the plural `Pipelines*` prefix (H4 here). + +### O2. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into 6 different abbreviations across the public API +- **Search:** `DLT`, `SDP`, `LDP`, `Lakeflow`, `Spark Declarative Pipelines`, `Delta Live Tables`, `DAB`. +- **Locations:** `model.ts:48` (`DAB` in DeploymentKind comment), `model.ts:551` (`SDP` in `channel` JSDoc), `model.ts:804` (`Spark Declarative Pipelines` in JSDoc), `model.ts:1175` (`Lakeflow Connect`), `model.ts:2063` (`https://docs.databricks.com/en/ldp/`), `model.ts:2379` (`SDP's environment`), `client.ts:376` (`Spark Declarative Pipelines`). +- **Suggestion:** Settle on one product name in JSDoc. The TS types should be backwards-compatible (no rename) but the docstrings should agree. + +### O3. `Pipelines*` (plural) vs `Pipeline*` (singular) split: 8 plural-prefixed vs 14 singular-prefixed types +- **Cross-reference:** H4, H23. + +### O4. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested +- **Locations:** `IngestionPipelineDefinition.connectorType`, `IngestionPipelineDefinition.sourceConfigurations[].catalog.options`, `IngestionPipelineDefinition_SchemaSpec.sourceOptions`, `IngestionPipelineDefinition_SchemaSpec.connectorOptions`, `IngestionPipelineDefinition_TableSpec.sourceOptions`, `IngestionPipelineDefinition_TableSpec.connectorOptions`. +- **Suggestion:** Document the resolution order between schema-level and table-level options. JSDoc currently fragments the rules across multiple types. + +### O5. JSDoc uses `` placeholder — leak from the Go SDK's template substitution +- **Search:** `` appears 19 times in `model.ts`. +- **Suggestion:** Replace with literal "Databricks" before TS compilation. + +### O6. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` +- **Location:** `model.ts:1758`. +- **Category:** 16. +- **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. + +### O7. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side +- **Locations:** `model.ts:1831-1881`. +- **Category:** Generator artifact / Go-SDK fidelity issue. +- **Suggestion:** Mark deprecated fields with `@deprecated` JSDoc tag (currently only mentioned in plain text). diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md new file mode 100644 index 00000000..4d7d6116 --- /dev/null +++ b/.agent/naming-audit/policyfamilies.md @@ -0,0 +1,357 @@ +# Naming Audit: `policyfamilies` (v2) + +**Package:** `@databricks/sdk-policyfamilies` +**Path:** `/home/parth.bansal/sdk-js/packages/policyfamilies/` +**Version audited:** `v2` +**Files audited:** + +- `src/v2/model.ts` +- `src/v2/client.ts` +- `src/v2/utils.ts` +- `src/v2/index.ts` + +This audit catalogues every identifier (type, field, enum value, method, +constant) in the package and flags naming concerns against the 20-category +rubric. Issues are graded: + +- **High** — actively misleading, ambiguous, or violates a TS rule. +- **Medium** — friction; verbose, redundant, or stylistically off. +- **Low** — nit / consistency observation; safe to ignore. + +--- + +## 1. Inventory + +### 1.1 Enums (`model.ts`) + +| Name | Members | +| ----------- | ------- | +| (none) | — | + +The package defines no enums. + +### 1.2 Interfaces (`model.ts`) + +| Name | Purpose | +| --------------------------------- | -------------------------------------------------- | +| `GetPolicyFamily` | Request body for the single-resource GET endpoint. | +| `ListPolicyFamilies` | Request body for the list endpoint. | +| `ListPolicyFamilies_Response` | Response from list (proto-style nested name). | +| `PolicyFamily` | The policy-family entity itself. | + +### 1.3 Fields (entity / request / response — combined catalog) + +| Type | Field | Type / Notes | +| ------------------------------- | ----------------- | ----------------------------------------------------- | +| `GetPolicyFamily` | `policyFamilyId` | `string?` — path parameter (the resource identifier). | +| `GetPolicyFamily` | `version` | `number?` — version number to fetch (defaults to latest). | +| `ListPolicyFamilies` | `maxResults` | `number?` — page size. | +| `ListPolicyFamilies` | `pageToken` | `string?` — pagination cursor. | +| `ListPolicyFamilies_Response` | `policyFamilies` | `PolicyFamily[]?` — page of results. | +| `ListPolicyFamilies_Response` | `nextPageToken` | `string?` — pagination cursor for next page. | +| `PolicyFamily` | `policyFamilyId` | `string?` — unique identifier. | +| `PolicyFamily` | `name` | `string?` — display name. | +| `PolicyFamily` | `description` | `string?` — human-readable description. | +| `PolicyFamily` | `definition` | `string?` — Databricks Cluster Policy Definition Language JSON. | + +### 1.4 Methods (`client.ts`) + +| Method | Verb | Returns | +| ----------------------- | ---- | ----------------------------- | +| `getPolicyFamily` | GET | `PolicyFamily` | +| `listPolicyFamilies` | GET | `ListPolicyFamilies_Response` | +| `listPolicyFamiliesIter`| GET | `AsyncGenerator` (paginated) | + +### 1.5 Other identifiers + +- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private + fields `host`, `httpClient`, `logger`, `userAgent`. +- `client.ts` local variables in methods: `url`, `params`, `query`, + `fullUrl`, `resp`, `call`, `callSignal`, `headers`, `httpReq`, `respBody`, + `pageReq`, `item`, `info`. +- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, + `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`. +- Marshal / unmarshal schemas: `unmarshalPolicyFamilySchema`, + `unmarshalListPolicyFamilies_ResponseSchema`. No `marshal*` schemas + exist (read-only API). + +--- + +## 2. Findings by Category + +### 2.1 Vague / generic names — High & Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| V-01 | `PolicyFamily.definition` | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it is unclear whether this is a JSON document, a free-form string, or something else. Sibling field on the parent `clusterpolicies` package is `policyFamilyDefinitionOverrides` — so the convention within the SDK is `*Definition*`. `policyDefinition` would self-describe. (Codegen / API constraint.) | +| V-02 | `PolicyFamily.name` | Low | Generic but standard for entity types; meaning is preserved by the parent type. | +| V-03 | `PolicyFamily.description` | Low | Generic but standard across the SDK; acceptable. | +| V-04 | `GetPolicyFamily.version` | Medium | `version` is generic. The JSDoc says "version number for the family"; field could be `familyVersion` or `policyFamilyVersion` to make it self-describing when destructured (e.g. `const {version} = req` loses context). | +| V-05 | `parseResponse` (utils) | Low | Generic, but it's local to the package. Acceptable. | +| V-06 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-07 | `marshalRequest` (utils) | Low | Generic helper for "marshal arbitrary request body". OK in context. Note this package never calls it (read-only API). | + +### 2.2 Redundant enum prefixes — High + +| ID | Symbol | Severity | Issue | +| ---- | ------- | -------- | ----- | +| E-01 | (none) | — | The package defines no enums. | + +### 2.3 Acronym casing inconsistencies — High + +| ID | Symbol | Severity | Issue | +| ----- | --------------------- | -------- | ----- | +| A-01 | `httpClient`, `HttpClient`, `HttpCallOptions`, `HttpRequest`, `HttpResponse`, `httpReq` | Low | `Http` (lowercased) follows Google TS style for acronyms ≥3 chars. Consistent with the rest of the SDK. | +| A-02 | `URLSearchParams` (local in `client.ts`) | Low | DOM API; uses uppercase `URL` because that is the platform-defined identifier. Acceptable. | +| A-03 | `unmarshalListPolicyFamilies_ResponseSchema` | Low | "Marshal/unmarshal" is the chosen vocabulary; cf. § 2.13 (G-02). Not an acronym-case issue. | + +### 2.4 Underscores in TS identifiers — High + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| U-01 | `ListPolicyFamilies_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). The codebase even disables ESLint on the line: `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`. Should be `ListPolicyFamiliesResponse`. | +| U-02 | `unmarshalListPolicyFamilies_ResponseSchema` | High | Same as U-01; the underscore cascades into the schema constant and forces the same ESLint disable comment in `model.ts` (line 40-41). | +| U-03 | Imports/exports of `ListPolicyFamilies_Response` | High | `client.ts` and `index.ts` both import/re-export the underscored name, propagating the violation across the public surface (see `index.ts` line 10). | + +No enum-member identifiers exist in this package, so the +`SCREAMING_SNAKE_CASE` exception (which is permitted by Google style for +enum members) does not apply here. + +### 2.5 Cryptic abbreviations — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ------------------------------------------------- | -------- | ----- | +| C-01 | `req`, `resp` (locals in `client.ts`) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. Used in every CRUD method. | +| C-02 | `httpReq` (local in `client.ts`) | Low | Short for "HTTP request". OK in local scope. | +| C-03 | `respBody` (local in `client.ts`) | Low | Short for "response body". OK in local scope. | +| C-04 | `pageReq` (local in `client.ts`, `listPolicyFamiliesIter`) | Low | Short for "page request". OK. | +| C-05 | `opts` (`utils.ts` parameter, `executeHttpCall` and `executeCall`) | Low | Inside fn scope; minor. | +| C-06 | `pkgJson` (import in `client.ts`) | Low | Short for `packageJson`. Consistent with peer packages' codegen output. | +| C-07 | `acc` (local in `utils.ts` reduce callback) | Low | Standard reduce-accumulator name. OK. | + +### 2.6 Misleading names — High + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| M-01 | `getPolicyFamily()` JSDoc: "an policy family" | Low | Typo in the JSDoc ("an" should be "a"). Not a naming issue but a generator artifact worth fixing upstream. | +| M-02 | `listPolicyFamilies()` JSDoc: "list of policy definition types" | Medium | The method returns *policy families*, but the JSDoc paraphrases them as "policy definition types". Mismatched terminology between the method name (`PolicyFamily`) and its docstring will confuse readers. Method/type/route all say "family"; doc should too. | +| M-03 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | +| M-04 | `marshalRequest` (utils) | Low | Marshals to **JSON string**. `marshalJsonRequest` would be more accurate. Not used in this package. | +| M-05 | `GetPolicyFamily` JSDoc: "Returns the details of a policy family at a specific version" | Low | The JSDoc describes the *operation*, not the request body. The type is a request shape, not a response. Convention across the SDK, OK but slightly misleading on first read. | +| M-06 | `ListPolicyFamilies` JSDoc: "Returns the list of policy families…" | Low | Same as M-05 — the JSDoc describes the operation rather than the request shape. | +| M-07 | `Client` (class) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | + +### 2.7 Overly verbose / Redundant suffixes — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| O-01 | `policyFamilyId` (every occurrence) | Low | 14 chars but precise. Two `policyFamily*` fields would collapse to one once the type name (`PolicyFamily`) is in scope, but it remains unambiguous across the SDK and matches the upstream API field name. Accept. | +| O-02 | `unmarshalListPolicyFamilies_ResponseSchema` | High | 43 characters. Combines (a) underscore violation U-01, (b) proto-style nested-message tail `_Response`, (c) the `unmarshal*Schema` triple-statement pattern (cf. O-04 in `clusterpolicies`). Removing `_Response` saves one char and one ESLint disable; adopting `deserializeListPolicyFamiliesSchema` (or `*Codec`) would be even shorter and more idiomatic JS/TS. | +| O-03 | `unmarshalPolicyFamilySchema` | Medium | 28 chars. Pattern `unmarshalSchema` triple-states intent ("schema for unmarshalling X"). Repo-wide convention, but noted. | +| O-04 | `ListPolicyFamilies_Response` | Medium | The `_Response` suffix is a proto-import artifact; for a one-method list endpoint the suffix is redundant with the type's outer name (`ListPolicyFamilies`). Combined with U-01, the renaming to `ListPolicyFamiliesResponse` saves the disable comment. | +| O-05 | `listPolicyFamiliesIter` (method) | Medium | Three observations: (a) the `Iter` suffix is Go-style (`*Iter` convention from `databricks/sdk-go`). TypeScript convention is to leverage `Symbol.asyncIterator` on a custom iterable or name the method `*Iterator()` (matching DOM's `entries() / keys()`). (b) Without `Iter` the method name would collide with `listPolicyFamilies`. (c) `listAll` or `listPolicyFamiliesAll` would communicate "auto-page through everything" more clearly than `Iter`. Tracked under § 2.13 G-05. | +| O-06 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | + +### 2.8 Singular / plural mismatches — Low + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| P-01 | `getPolicyFamily()` (singular) | Low | Singular for a single-resource GET. Correct. | +| P-02 | `listPolicyFamilies()` (plural method) | Low | Plural for a collection endpoint. Correct. | +| P-03 | `ListPolicyFamilies` request type vs `listPolicyFamilies` method | Low | Both plural and matched. Correct. | +| P-04 | `ListPolicyFamilies_Response.policyFamilies` | Low | Plural field for an array of `PolicyFamily`. Correct. | +| P-05 | Package directory `policyfamilies` (lowercase) | Low | The npm package is `@databricks/sdk-policyfamilies` (lowercase, no separator). Compare with `clusterpolicies`, `clusterlibraries`, `instancepools`. Convention is consistent across this codebase — squashed lowercase. The directory and package name use plural ("families") which matches the dominant resource the package exposes. Acceptable but visually awkward (`policyfamilies` is hard to parse versus `policy-families`); a hyphenated path / scoped suffix would be more readable. (Pattern is repo-wide; flagged once.) | +| P-06 | `PolicyFamily` (entity, singular) vs `policyfamilies` (package directory, plural) | Low | Standard pattern — the package is plural, the entity it contains is singular. OK. | + +### 2.9 Reserved-word collisions — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ------- | -------- | ----- | +| R-01 | (none observed) | — | None of the field, type, or method names in this package collide with JS reserved or future-reserved words. | + +### 2.10 Empty / trivial wrapper types — Medium + +_None._ + +### 2.11 Duplicate concepts (vs `clusterpolicies`) — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| D-01 | `PolicyFamily.policyFamilyId` (here) and `Policy.policyFamilyId` (in `clusterpolicies`) | Low | The field name is consistent across packages — good. No duplication concern. | +| D-02 | `PolicyFamily.definition` vs `Policy.definition` / `Policy.policyFamilyDefinitionOverrides` (in `clusterpolicies`) | Medium | Three related "definition" concepts spread across two packages: `PolicyFamily.definition` (the canonical CPDL doc), `Policy.definition` (custom override), and `Policy.policyFamilyDefinitionOverrides` (delta). The current package has only one of the three, but the field name `definition` does not communicate which of the three roles it plays. Adding a JSDoc cross-link to the `clusterpolicies` `*Overrides` field would help; a rename to `policyDefinition` would align with the sibling field names. | +| D-03 | `PolicyFamily` vs `Policy` (cross-package) | Low | Distinct concepts: a `PolicyFamily` is a template, a `Policy` is an instance. Cross-package linking (JSDoc `{@link}`) would help readers understand the relationship. Out of scope for naming. | +| D-04 | `parseResponse`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`, `readAll` (`utils.ts`) | Medium | All six helpers are byte-identical duplicates of the helpers in every other API package's `utils.ts` (`clusterpolicies`, `clusters`, `accounts`, etc.). The codegen emits the same file per package. Should be hoisted into `@databricks/sdk-core/api` or similar to eliminate the duplication. Per-package naming impact: none, but the duplication is a maintenance hazard. | +| D-05 | `HttpCallOptions` (utils) | Medium | Same interface re-declared per package — see D-04. | + +### 2.12 Verb-tense inconsistency — Low + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| T-01 | `getPolicyFamily`, `listPolicyFamilies` | Low | Both imperative present-tense — consistent. | +| T-02 | `listPolicyFamiliesIter` | Low | Imperative + Go-style noun suffix. Verb tense is consistent. | +| T-03 | `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` | Low | All imperative present-tense — consistent. | + +### 2.13 Go / Java-style names — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| G-01 | `ListPolicyFamilies_Response` (proto nested-message style) | High | Direct port of Go's `pb.ListPolicyFamiliesResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `ListPolicyFamiliesResponse`. | +| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**). New TS readers will look up "marshal" before they recognise it. Repo-wide convention; flagged once per package. | +| G-03 | `HttpClient`, `HttpRequest`, `HttpResponse` | Low | Google TS style uses `Http` (lowercased acronym) — consistent. Not a Go-style violation. | +| G-04 | `listPolicyFamiliesIter` (`*Iter` suffix) | Medium | The `Iter` suffix is the Go SDK's idiomatic naming for `iter.Seq[T]`-returning helpers. TypeScript convention is to (a) implement `Symbol.asyncIterator` directly on a custom iterable, or (b) name the method `entries()` / `values()` matching the DOM/Map APIs. The current naming is faithful to the Go port but reads as foreign in TS. | +| G-05 | `executeCall`, `executeHttpCall` | Medium | The dual-naming (`Call` vs `HttpCall`) communicates the wrapping relationship in a Go-style "the inner one is HTTP-specific, the outer one is a generic retry/timeout decorator" idiom. Acceptable; common pattern in the Go SDK at `databricks/sdk-go/transport/`. | +| G-06 | `marshalRequest`, `parseResponse` | Medium | Same as G-02 — the JS-idiomatic verbs would be `serialize` / `parse` (or `stringify` / `parse`). | +| G-07 | `buildHttpRequest` | Low | "Build" is fine in TS; the naming is broadly used. | + +### 2.14 Generic field names losing meaning — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| F-01 | `version` (on `GetPolicyFamily`) | Medium | When destructured (`const {version} = req`) the meaning collapses to "some version number". Within the SDK there are also `Catalog.version`, `Volume.version`, `Schema.version` etc.; the field is overloaded in name space if not in scope. Renaming to `familyVersion` (or matching what the wire JSON key actually is — `version`) is a tradeoff between SDK-internal consistency and on-wire fidelity. Cf. V-04. | +| F-02 | `name` (on `PolicyFamily`) | Low | Universal noun; meaning is preserved through type context. OK. | +| F-03 | `description` (on `PolicyFamily`) | Low | Same as F-02. | +| F-04 | `definition` (on `PolicyFamily`) | Medium | See V-01 / D-02. Generic and overloaded — losing parent-type context makes it unclear whether this is JSON, YAML, or a free-form string. | +| F-05 | `url`, `params`, `query`, `fullUrl`, `headers`, `body` (locals in `client.ts`) | Low | Locals only; standard naming. OK. | + +### 2.15 Field contradicting type domain — Low + +| ID | Symbol | Severity | Issue | +| ----- | ------- | -------- | ----- | +| FC-01 | (none observed) | — | All fields are domain-appropriate for the policy-family context. | + +### 2.16 Inconsistent action verbs — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| AV-01 | `getPolicyFamily()` (singular get) vs `listPolicyFamilies()` (plural list) | Low | Correct convention: singular `get` for one-resource, plural `list` for many. Consistent. | +| AV-02 | `listPolicyFamiliesIter()` — the verb is `list`, the suffix `Iter` repurposes the same verb | Low | The two list-style methods share the verb `list` and differ only in suffix. Acceptable but slightly confusing (one returns a page, the other yields a stream). A TS-idiomatic alternative such as `iterPolicyFamilies()` or `policyFamilies()` (returning an `AsyncIterable`) would separate concerns. | +| AV-03 | The package exposes only **read** verbs — `get`, `list`. There are no `create` / `update` / `delete` methods (the API is read-only). The verb set is consistent with the API's read-only nature. | Low | OK. | + +### 2.17 Long enum values — Medium + +| ID | Symbol | Severity | Issue | +| ---- | ------- | -------- | ----- | +| L-01 | (none) | — | The package defines no enums. | + +### 2.18 Underspecified IDs — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------- | -------- | ----- | +| I-01 | `policyFamilyId` | Low | Well-specified: scope = policy family. No collision with workspace / account / cluster / policy IDs in this package or in cross-package usage. Good. | +| I-02 | No bare `id` field anywhere. | — | The package consistently uses the scoped form `policyFamilyId`. Compliant with the "no bare `id`" guideline. | + +### 2.19 Type-suffix tautology — Medium + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| TS-01 | `PolicyFamily` — does the `Family` suffix double up with `Policy`? | Low | `PolicyFamily` is the domain term used in the Databricks docs (cf. https://docs.databricks.com/en/admin/clusters/policy-families.html). The "Family" here means *grouping/template*, not a `*Family` type-suffix tautology. OK. | +| TS-02 | `GetPolicyFamily`, `ListPolicyFamilies`, `ListPolicyFamilies_Response` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | +| TS-03 | `HttpCallOptions` (utils) | Low | The `Options` suffix is a standard TS pattern (`fetch` accepts `RequestInit`, but `Options` is widespread). OK. | + +### 2.20 Other observations + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| X-01 | `version` typed as `number` (`GetPolicyFamily.version`) | Low | The API contract uses an integer version. `number` is fine; flagged for completeness. No `bigint` is needed (versions won't exceed `Number.MAX_SAFE_INTEGER`). | +| X-02 | `pageToken` / `nextPageToken` (cross-pagination field naming) | Low | Standard Databricks SDK pagination shape. The request-side cursor is `pageToken`, the response-side cursor is `nextPageToken` — consistent with `clusterpolicies`, `instancepools`, etc. OK. | +| X-03 | `maxResults` (`ListPolicyFamilies.maxResults`) | Low | Standard pagination field name. OK. | +| X-04 | `Client.host` is mutated post-construction via `replace(/\/$/, '')` only at constructor entry | Low | Naming-wise neutral; not strictly a naming issue. The field name `host` (rather than `baseUrl` or `endpoint`) is consistent with peer packages. | +| X-05 | `Client.userAgent` (private) | Low | Standard naming; HTTP `User-Agent` is the wire-format identifier. OK. | +| X-06 | `executeCall` parameter `call: Call` | Low | The type `Call` is generic from `@databricks/sdk-core/api` and overloads the verb; readers may briefly wonder which "call" is meant (function callback vs. RPC call). Imported from the core package; flagged once. | +| X-07 | `callSignal` (local in `client.ts`) | Low | Distinct from `req.signal` / `options?.signal` — the qualifier `call` disambiguates. Good. | +| X-08 | `parseResponse` is generic (``) but `marshalRequest` is not (`schema: z.ZodType` without inference) | Low | Type asymmetry: `parseResponse` returns `T`, `marshalRequest` accepts `unknown` and returns `string`. A symmetric design would type both generically. Not a name issue; flagged for code-quality follow-up. | +| X-09 | `flattenQueryParams` (utils, exported) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | +| X-10 | `listPolicyFamiliesIter` body uses a `for (;;)` infinite loop | Low | Naming-neutral; the `for (;;)` idiom (instead of `while (true)`) is consistent with the rest of the codebase. | +| X-11 | `pageReq` (local in `client.ts`, `listPolicyFamiliesIter`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | +| X-12 | `index.ts` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | +| X-13 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | +| X-14 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-07. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | + +--- + +## 3. Summary + +### 3.1 Findings by severity + +| Severity | Count | +| -------- | ----- | +| High | 6 | +| Medium | 20 | +| Low | 39 | +| **Total**| **65**| + +(Counted unique IDs across all categories. The total double-counts cross-referenced symbols +intentionally — e.g. `ListPolicyFamilies_Response` appears in U-01, U-02, U-03, O-04, and G-01.) + +### 3.2 Top themes + +1. **Proto-style `_Response` suffix.** `ListPolicyFamilies_Response` and its + schema `unmarshalListPolicyFamilies_ResponseSchema` violate Google TS style + (no underscores in `UpperCamelCase` identifiers) and each requires an + `eslint-disable @typescript-eslint/naming-convention` annotation. Renaming + to `ListPolicyFamiliesResponse` would remove the disables and align with + TS conventions. This is the package's only **High**-severity cluster. + +2. **Read-only API ⇒ minimal naming surface.** With only two endpoints + (`getPolicyFamily`, `listPolicyFamilies`) and one entity (`PolicyFamily`), + the package introduces almost no domain-specific naming. The vast + majority of issues are repo-wide patterns (Go-style verbs, the + marshal/unmarshal idiom, the bare `Client` class name, the underscored + `_Response` suffix) rather than per-package mistakes. + +3. **`definition` and `version` are over-generic on a generic entity.** + `PolicyFamily.definition` and `GetPolicyFamily.version` are the two + fields whose meaning is best inferred from the JSDoc rather than from + the field name itself. Renaming to `policyDefinition` / + `familyVersion` (or `policyFamilyVersion`) would self-describe. + +4. **`Iter` suffix is Go-style.** `listPolicyFamiliesIter` mirrors the Go SDK + `iter.Seq[T]` naming. TS-idiomatic alternatives would use + `Symbol.asyncIterator` or `entries()`-style naming. + +5. **Cross-package duplication.** Every helper in `utils.ts` + (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`, `readAll`) is byte-identical to + the same helper across all other API packages. Hoist to + `@databricks/sdk-core/api`. Naming-neutral but architecturally + significant. + +### 3.3 Suggested quick wins +(non-breaking renames are not possible — this section is advisory for the +codegen owners) + +- Drop `_Response` suffix → `ListPolicyFamiliesResponse`. Removes one + ESLint-disable comment and one Google-style violation. +- Rename `unmarshalListPolicyFamilies_ResponseSchema` → + `unmarshalListPolicyFamiliesResponseSchema`. Cascading from the above. +- Rename `PolicyFamily.definition` → `policyDefinition` (matches the + sibling field `policyFamilyDefinitionOverrides` in the + `clusterpolicies` package). +- Rename `listPolicyFamiliesIter()` → `iterPolicyFamilies()` or have the + client class implement `Symbol.asyncIterator` directly on a paginated + iterable wrapper. +- Fix the JSDoc on `getPolicyFamily()` ("an policy family" → "a policy + family") and on `listPolicyFamilies()` ("policy definition types" → + "policy families"). +- Rename `Client` → `PolicyFamiliesClient` for cross-package + disambiguation. (Repo-wide pattern; flag at codegen layer.) + +### 3.4 Cross-package consistency notes + +- The `marshal*` / `unmarshal*` schema-naming convention is consistent + with peer packages (`clusters`, `clusterpolicies`, etc.) and is + therefore a repo-wide concern, not a per-package fix. +- The `_Response` proto-style suffix is consistent with peers; addressing + at the codegen level would fix all packages in one sweep. +- The bare `Client` class name is consistent with peers; a codegen-level + rename to `Client` would help all packages. +- The `*Iter` suffix is consistent with `clusters.listClustersIter`, + `clusterpolicies.listPoliciesIter`, etc. — a repo-wide TS-idiomatic + rework (e.g. `Symbol.asyncIterator`) would benefit all packages. +- `PolicyFamily.policyFamilyId` matches `Policy.policyFamilyId` in the + `clusterpolicies` package — cross-package field naming is consistent. +- `PolicyFamily.definition` does **not** match the more-qualified + `Policy.policyFamilyDefinitionOverrides` — partial inconsistency, + but defensible since the override is a delta and the canonical + definition lives on the family. diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md new file mode 100644 index 00000000..5f364da4 --- /dev/null +++ b/.agent/naming-audit/postgres.md @@ -0,0 +1,613 @@ +# Naming Audit: postgres + +**Path:** `packages/postgres/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `ComputeInstance`s (the individual compute nodes inside an endpoint group), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Table`s (non-synced PG tables), `Catalog`s (Unity Catalog mirrors of logical PG databases), Forward ETL (PG→UC reverse-ETL), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Waiter`-style classes. +**Total weird names flagged:** 92 + +## Summary +| Severity | Count | +| --- | --- | +| High | 22 | +| Medium | 47 | +| Low | 17 | +| Observation | 6 | + +## High severity + +### 1. Package name `postgres` does not say "Lakebase" / "autoscaling" / "managed-PG" — `packages/postgres/` +- **Why weird:** Generic single-word name for a Databricks-specific service. The actual product is "Lakebase Autoscaling Postgres" (see JSDoc `createProject`, `client.ts:363`). Sibling package `database` covers earlier-generation Lakebase (`DatabaseInstance` / V1), and `postgres` is V2 — see `database/naming-audit/database.md` finding #2. Neither package name says "Lakebase" or makes the V1/V2 lineage discoverable. +- **Category:** 1 (vague/generic), 12 (duplicate concept across packages). +- **Suggested name:** `lakebase` (and merge with `database`), or `lakebase-autoscaling`, or `lakebase-v2`. At minimum, add an `index.ts` JSDoc declaring "Lakebase Autoscaling Postgres (V2 OLTP)". +- **Rationale:** `postgres` is too broad — Databricks also has Postgres-backed services elsewhere (DBSQL, query history, etc.). Naming should encode the product. + +### 2. `postgres` and `database` packages overlap heavily — `packages/postgres/` vs `packages/database/` +- **Why weird:** Many duplicate type names: `DeltaTableSyncInfo` (`model.ts:1295` vs `database/v1/model.ts:477`), `SyncedTablePosition` (`model.ts:2563` vs `database:762`), `SyncedTablePipelineProgress` (`model.ts:2547` vs `database:744`), `NewPipelineSpec` (`model.ts:1963` vs `database:598`), `DatabaseCredential` (`model.ts:1167` vs `database:228`), `GenerateDatabaseCredentialRequest` (`model.ts:1591` vs `database:499`), `RequestedClaims` (`model.ts:2232` vs `database:630`), `RequestedResource` (`model.ts:2237` vs `database:635`), `ProvisioningInfo` (`model.ts:2230` vs `database:628`), `ProvisioningPhase`/`SyncedTableState`/`ProvisioningInfo_State`/`RequestedClaims_PermissionSet`/`SyncedTableSpec_PgSpecificType`/`SyncedTableSpec_SecondaryIndex_CreationPoint`. Identical signatures but exported from two packages — a TS user importing both gets noisy alias-juggling. +- **Category:** 12 (duplicate concept across packages), 6 (misleading: same name, two definitions). +- **Suggested name:** Pick one as canonical; the other re-exports from the canonical or marks itself deprecated. Cross-reference each shared type with a JSDoc note like "Equivalent to `database/v1.DeltaTableSyncInfo`; see go/lakebase-v2 for the migration." +- **Rationale:** Same as `database` finding #2 — `postgres` is V2 and `database` is V1; nothing in the names says so. + +### 3. 18 enum/interface names contain underscores `_` — `src/v1/model.ts` throughout +- **Why weird:** Every "nested message" or "nested enum" comes out as `Parent_Child` because of proto's nested-message convention. Each needs `eslint-disable-next-line @typescript-eslint/naming-convention`. Full list: + - Enums: `BranchStatus_State` (line 581), `ComputeInstance_ComputeState` (599), `ComputeInstance_ComputeType` (607), `EndpointStatus_State` (628), `NewPipelineSpec_PipelineChannel` (644), `ProvisioningInfo_State` (654), `RequestedClaims_PermissionSet` (665), `Role_AuthMethod` (672), `Role_IdentityType` (690), `Role_MembershipRole` (703), `SyncedTable_SyncedTableSpec_PgSpecificType` (712), `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` (721), `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` (730). + - Interfaces: `Catalog_CatalogSpec` (893), `Catalog_CatalogStatus` (929), `Database_DatabaseSpec` (1123), `Database_DatabaseStatus` (1146), `EndpointSettings_PgSettingsEntry` (1421), `ProjectDefaultEndpointSettings_PgSettingsEntry` (2136), `Role_Attributes` (2275), `Role_RoleSpec` (2282), `Role_RoleStatus` (2338), `SyncedTable_SyncedTableSpec` (2387), `SyncedTable_SyncedTableSpec_ExtraColumnDefinition` (2468), `SyncedTable_SyncedTableSpec_SecondaryIndex` (2484), `SyncedTable_SyncedTableSpec_TypeOverride` (2500), `SyncedTable_SyncedTableStatus` (2513). +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). +- **Suggested name:** Flatten with descriptive prefixes/suffixes (no double-underscore chains). E.g. `BranchState`, `ComputeState`, `ComputeType`, `EndpointState`, `PipelineChannel`, `ProvisioningState`, `PermissionSet`, `RoleAuthMethod`, `RoleIdentityType`, `RoleMembershipRole`, `PgColumnType`, `IndexCreationPoint`, `SchedulingPolicy`, `CatalogSpec`, `CatalogStatus`, `DatabaseSpec`, `DatabaseStatus`, `PgSettingsEntry`, `RoleAttributes`, `RoleSpec`, `RoleStatus`, `SyncedTableSpec`, `ExtraColumnDefinition`, `SecondaryIndex`, `TypeOverride`, `SyncedTableStatus`. Alternatively, use TS namespaces (`namespace SyncedTable { export type Spec = … }`). +- **Rationale:** Each underscore identifier requires a lint suppression and forces consumers to type underscores. The triple-underscore beast `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` is 56 characters of leaked proto encoding. + +### 4. `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` — 56-char triple-tautology — `src/v1/model.ts:730` +- **Why weird:** Type sits nested inside `SyncedTable` → `SyncedTableSpec` → `SyncedTableSchedulingPolicy`. Each level repeats `SyncedTable`. Three repetitions = once at parent (`SyncedTable_`), once at child (`SyncedTableSpec_`), once at the leaf (`SyncedTableSchedulingPolicy`). +- **Category:** 4 (underscore-nested), 20 (type-suffix tautology), 7 (overly verbose). +- **Suggested name:** `SchedulingPolicy` (the context is obvious from the field site). +- **Rationale:** The fully qualified name is longer than most file paths. + +### 5. `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` — quad-level naming — `src/v1/model.ts:721` +- **Why weird:** Four `_`-separated segments: `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint`. Two of the four words are `SyncedTable*`. +- **Category:** 4 (underscores), 20 (tautology), 7 (verbose). +- **Suggested name:** `IndexCreationPoint`. +- **Rationale:** Same as #4 but worse — quad-level. + +### 6. `SyncedTable_SyncedTableSpec_PgSpecificType` — 41-char nested type — `src/v1/model.ts:712` +- **Why weird:** Three `_` segments where the first two re-state `SyncedTable`. Equivalent to `database`'s `SyncedTableSpec_PgSpecificType` (which itself is two segments). Postgres SDK is more nested than the V1. +- **Category:** 4 (underscores), 7 (verbose). +- **Suggested name:** `PgColumnTypeOverride` (descriptive) or `PgColumnType`. +- **Rationale:** Same as #4. + +### 7. `SyncedTable_SyncedTableSpec` field/type tautology — `src/v1/model.ts:2387`, used at `SyncedTable.spec` (2380) +- **Why weird:** `SyncedTable` has `spec?: SyncedTable_SyncedTableSpec`. The wrapper type re-says `SyncedTable` twice. Read site: `syncedTable.spec` already inside the type — the type qualifier `SyncedTable_` is pure noise. +- **Category:** 4 (underscore-nested), 20 (type-suffix tautology), 7 (verbose). +- **Suggested name:** `SyncedTableSpec` (flat) or nested `SyncedTable.Spec`. +- **Rationale:** `SyncedTable_SyncedTableSpec` is a triple-tautology against `SyncedTable.spec`. + +### 8. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` +- **Why weird:** Huge enum (~100 entries) referenced exactly once via `DatabricksServiceExceptionWithDetailsProto.errorCode` (1179). Most entries are explicitly marked "NOTE: Deprecated and kept to maintain backwards compatibility for public APIs that use it, avoid using it in the new APIs" (e.g. `IO_ERROR`, `INVALID_STATE`, `UNPARSEABLE_HTTP_ERROR`, `QUOTA_EXCEEDED`, `MAX_BLOCK_SIZE_EXCEEDED`, `DRY_RUN_FAILED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, all the `GIT_*`, `IPYNB_FILE_IN_REPO`, `INSECURE_PARTNER_RESPONSE`, `METASTORE_*_EXISTS`, `CATALOG_NOT_EMPTY`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, etc. — at least 40 entries). The enum re-exports the entire Databricks-platform error vocabulary into a Postgres-specific SDK package. +- **Category:** 7 (overly verbose), 11 (empty/trivial wrappers for deprecated values), 14 (Go/proto leak — all deprecated values exist only "for public APIs that use it"), 18 (long enum values). +- **Suggested name:** Move `ErrorCode` to a shared `core/apierror` package (already exists per CLAUDE.md), drop deprecated values from the public TS surface (or mark them `@deprecated` so TS tooling can warn). +- **Rationale:** Every consumer of this package gets a 100-entry deprecated-warning bundle. The fact that it's exported from `postgres/v1/index.ts` (line 30) means it's part of the public surface. + +### 9. `DatabricksServiceExceptionWithDetailsProto` — 41-char Java-style type — `src/v1/model.ts:1178` +- **Why weird:** Six concatenated words: `Databricks` + `Service` + `Exception` + `With` + `Details` + `Proto`. The `Proto` suffix says "this is from a `.proto` file" — a wire-format implementation detail. The `WithDetails` suffix is Java-style ("BuilderWithRoom"). The whole thing is a tagged struct holding `{errorCode, message, stackTrace, details}` — a plain error. +- **Category:** 7 (overly verbose), 14 (Java/proto-style name), 20 (type-suffix tautology — `Exception` and `Proto` both redundant), 8 (redundant suffix `Proto`). +- **Suggested name:** `ServiceError` or `ApiError` (and re-use the shared apierror type if one exists). +- **Rationale:** Six-word type names are an anti-pattern; the `Proto` suffix is a build-system leak. + +### 10. `BranchStatus_State`, `EndpointStatus_State`, `ComputeInstance_ComputeState`, `ProvisioningInfo_State` — three different "State" enum patterns — `src/v1/model.ts:581, 628, 599, 654` +- **Why weird:** Four state enums, each named differently: + - `BranchStatus_State` (qualifier is the status struct) + - `EndpointStatus_State` (same as Branch) + - `ComputeInstance_ComputeState` (qualifier is the resource, leaf is `ComputeState`) + - `ProvisioningInfo_State` (qualifier is the unrelated wrapper type) + - All four enums share values like `STATE_UNSPECIFIED`, `INIT`, `ACTIVE`, etc. The TypeScript user can't tell which enum to use for which resource without reading the JSDoc. +- **Category:** 17 (inconsistent action verb / naming pattern), 4 (underscores). +- **Suggested name:** Standardise to `State`: `BranchState`, `EndpointState`, `ComputeState`, `ProvisioningState`. +- **Rationale:** Four state enums with three naming conventions across one package. + +### 11. Enum values all carry redundant resource prefix — `src/v1/model.ts` (multiple enums) +- **Why weird:** Every enum's `UNSPECIFIED` sentinel duplicates the enum name: + - `EndpointType.ENDPOINT_TYPE_UNSPECIFIED` / `ENDPOINT_TYPE_READ_WRITE` / `ENDPOINT_TYPE_READ_ONLY` (line 11-13) + - `ProvisioningPhase.PROVISIONING_PHASE_*` (520-526) + - `SyncedTableState.SYNCED_TABLE_*` (532-576, 14 entries, each re-stating `SYNCED_TABLE`) + - `BranchStatus_State.STATE_UNSPECIFIED` (only one with the prefix; others don't, see #12) + - `ComputeInstance_ComputeState.COMPUTE_STATE_UNSPECIFIED` + - `ComputeInstance_ComputeType.COMPUTE_TYPE_UNSPECIFIED` + - `EndpointStatus_State.STATE_UNSPECIFIED` + - `NewPipelineSpec_PipelineChannel.PIPELINE_CHANNEL_UNSPECIFIED` + - `ProvisioningInfo_State.STATE_UNSPECIFIED` + - `RequestedClaims_PermissionSet.PERMISSION_SET_UNSPECIFIED` + - `Role_AuthMethod.AUTH_METHOD_UNSPECIFIED` + - `Role_IdentityType.IDENTITY_TYPE_UNSPECIFIED` + - `Role_MembershipRole.MEMBERSHIP_ROLE_UNSPECIFIED` +- **Category:** 2 (redundant enum prefixes), 18 (long enum values). +- **Suggested name:** Drop the prefix everywhere — `EndpointType.Unspecified | ReadWrite | ReadOnly` etc. +- **Rationale:** `EndpointType.ENDPOINT_TYPE_READ_WRITE` is 41 chars to say "read-write". + +### 12. `SyncedTableState` — 14 enum values each prefixed `SYNCED_TABLE_*` — `src/v1/model.ts:532-576` +- **Why weird:** Worst offender. 14 values: + `SYNCED_TABLE_STATE_UNSPECIFIED`, `SYNCED_TABLE_PROVISIONING`, `SYNCED_TABLE_PROVISIONING_PIPELINE_RESOURCES` (45 chars), `SYNCED_TABLE_PROVISIONING_INITIAL_SNAPSHOT` (42 chars), `SYNCED_TABLE_ONLINE`, `SYNCED_TABLE_ONLINE_CONTINUOUS_UPDATE` (38 chars), `SYNCED_TABLE_ONLINE_TRIGGERED_UPDATE` (37 chars), `SYNCED_TABLE_ONLINE_NO_PENDING_UPDATE` (38 chars), `SYNCED_TABLE_OFFLINE`, `SYNCED_TABLE_OFFLINE_FAILED`, `SYNCED_TABLE_ONLINE_PIPELINE_FAILED` (36 chars), `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES` (47 chars). All re-state `SYNCED_TABLE_` to no benefit. Note: this enum is duplicated in `database/v1/model.ts:55` (with one typo, `SYNCED_TABLED_OFFLINE`) — not duplicated here, but the divergence is itself a smell. +- **Category:** 2 (redundant prefixes), 18 (long enum values). +- **Suggested name:** `SyncedTableState.Unspecified | Provisioning | ProvisioningPipelineResources | ProvisioningInitialSnapshot | Online | OnlineContinuousUpdate | OnlineTriggeredUpdate | OnlineNoPendingUpdate | Offline | OfflineFailed | OnlinePipelineFailed | OnlineUpdatingPipelineResources`. +- **Rationale:** Same as #11 but most severe enum. + +### 13. `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy.SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` — 41-char enum value on top of 56-char enum name — `src/v1/model.ts:731` +- **Why weird:** Enum name itself is 56 chars (#4); first value adds another 41 chars: total qualified reference is `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy.SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` — 97 chars. The other three values are bare (`CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`). +- **Category:** 2 (redundant prefix), 17 (inconsistent — `UNSPECIFIED` carries the prefix, others don't), 18 (long enum values). +- **Suggested name:** Pair with #4: rename type to `SchedulingPolicy`; values `Unspecified | Continuous | Triggered | Snapshot`. +- **Rationale:** Same as #11. + +### 14. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:2276-2278` +- **Why weird:** Three lowercase run-together field names. Doc comment (lines 2269-2272) acknowledges the choice ("The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words"). That's a wire-format justification (Postgres keywords). The TypeScript identifier should still be camelCase. `createrole` is especially confusing — could read as `createRole` (verb) or `creator_ole`. +- **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS), 17 (inconsistent — every other field in the package is camelCase). +- **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; wire stays `createdb`/`createrole`/`bypassrls`. +- **Rationale:** Same finding as `database` audit #5 — both packages share this bug. + +### 15. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:677, 682` +- **Why weird:** Implementation details (SCRAM-SHA-256 mechanism, OAuth `_V1`) leak into the public enum. The `_V1` suffix begs the question: what happens at V2? Should the SDK consumer have to migrate from `LAKEBASE_OAUTH_V1` to `LAKEBASE_OAUTH_V2` when the wire format changes? Worse, the `SCRAM_SHA_256` qualifier is a specific hash function — consumers picking an auth method shouldn't have to know about hash schemes. +- **Category:** 1 (vague at the wrong level — too specific), 6 (misleading: `LAKEBASE_OAUTH_V1` versioning leaks), 14 (Postgres/auth-spec internal naming), 18 (long enum values). +- **Suggested name:** `Password` (replacing `PG_PASSWORD_SCRAM_SHA_256`) and `OAuth` (replacing `LAKEBASE_OAUTH_V1`). Keep `NoLogin`. Push the wire-protocol-specific names into the marshal layer. +- **Rationale:** Public enums should describe the *concept* (password vs OAuth vs no-login), not the wire-protocol mechanism. + +### 16. `Forward ETL` types use a Java/Kotlin-style adjective phrase — `src/v1/model.ts:1229-1325` (multiple types), `client.ts:670-882` (methods) +- **Why weird:** "Forward ETL" is product-marketing terminology baked into 11 type/method names: + - `DeleteForwardEtlConfigurationRequest` / `DeleteForwardEtlConfigurationResponse` (1229, 1246) + - `DisableForwardEtlRequest` / `DisableForwardEtlResponse` (1306, 1323) + - `ForwardEtlConfig` (1520) + - `ForwardEtlDatabase` (1544) + - `ForwardEtlMetadata` (1552) + - `ForwardEtlSchema` (1560) + - `ForwardEtlStatus` (1568) + - `ForwardEtlTableMapping` (1576) + - `GetForwardEtlMetadataRequest` (1672) / `GetForwardEtlStatusRequest` (1685) + - Methods: `deleteForwardEtlConfiguration` (672), `disableForwardEtl` (845), `getForwardEtlMetadata` (1042), `getForwardEtlStatus` (1076). + - "ETL" is consistent capitalised acronym but is camelCased as `Etl` (lowercase tl), violating common style guides (TypeScript Google style: prefer `URL` over `Url` for known acronyms ≥3 chars). +- **Category:** 3 (acronym casing — `Etl` vs `ETL`), 7 (verbose — repeating "Forward ETL" 11 times), 14 (marketing-name leak), 1 (vague — "Forward" is a direction qualifier without context). +- **Suggested name:** Group under a `ReverseEtl` namespace (since "Forward ETL" from PG's perspective is reverse-ETL from Lakehouse's perspective — choose one direction language and stick to it). Use `ETL` casing per acronym convention or rename to `Replication` if that's the intent. Re-export under a single top-level type bundle. +- **Rationale:** "Forward" / "Reverse" terminology is consumer-facing direction labelling that can backfire — one company's "forward" is another's "reverse". 11 types prefixed with the same product-marketing string is verbose. + +### 17. `ForwardEtlConfig.createTimeMillis` / `updateTimeMillis` — millis-suffixed timestamps as `number` — `src/v1/model.ts:1538, 1540` +- **Why weird:** Every other timestamp in the package is `Temporal.Instant` (see `Branch.createTime`, `Catalog.createTime`, `DatabaseCredential.expireTime`, etc.). Only the ForwardEtl types use `number` with `Millis` suffix, breaking the package-wide convention. The unmarshal at `model.ts:3148-3149` confirms they stay as plain `number`. +- **Category:** 16 (field type contradicts the established package convention), 17 (inconsistent — every other timestamp is `Temporal.Instant`), 14 (Java-style epoch-millis convention). +- **Suggested name:** `createTime: Temporal.Instant` (parse `_millis` into Instant in unmarshal). +- **Rationale:** Mixing `Temporal.Instant` and raw millis numbers in the same SDK forces consumers to remember per-type rules. + +### 18. `Forward ETL` `pgDatabaseOid` / `pgSchemaOid` / `pgTableOid` — Postgres-internal IDs without doc — `src/v1/model.ts:1240, 1242, 1317, 1319, 1528, 1530, 1578` +- **Why weird:** `Oid` is Postgres slang for "object identifier" (a `pg_class.oid`-style integer). Field doc is minimal: "PostgreSQL database OID." Consumers unfamiliar with Postgres internals don't know how to *obtain* a `pgDatabaseOid` (it's not in the API for fetching a database). The fields appear in 4+ types: `DeleteForwardEtlConfigurationRequest`, `DisableForwardEtlRequest`, `ForwardEtlConfig`, `ForwardEtlTableMapping`. +- **Category:** 5 (cryptic abbreviation — `Oid`), 14 (Postgres-internal jargon in public API). +- **Suggested name:** `postgresDatabaseObjectId` / `postgresSchemaObjectId` / `postgresTableObjectId`. Or surface the wire format `Oid` but expand the doc with "(obtain via `psql -c \"SELECT oid FROM pg_database WHERE datname = '...'\"`)". +- **Rationale:** `Oid` is one of those abbreviations DBAs know cold but TS consumers do not. + +### 19. `tenantId` / `timelineId` in Forward ETL request types — `src/v1/model.ts:1236, 1238, 1313, 1315, 1524, 1526, 1679, 1681, 1692, 1694` +- **Why weird:** `tenantId` and `timelineId` appear without explanation — only "Tenant ID (dashless UUID format)" and "Timeline ID (dashless UUID format)" doc. What's a Lakebase "tenant"? What's a "timeline"? These appear nowhere else in the SDK as concept-level types. Consumers can't discover what to put here. +- **Category:** 19 (underspecified ID — what entity does the tenant ID identify?), 1 (vague), 6 (misleading — "tenant" and "timeline" are not exposed concepts elsewhere). +- **Suggested name:** `lakebaseTenantId` / `lakebaseTimelineId` with doc explaining what they reference. Or fold into existing resource refs (e.g. branch resource name). +- **Rationale:** Same as #18 — Postgres-storage-internal terms (the timeline is a Neon/Lakebase storage concept) leaking into the SDK. + +### 20. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1182` +- **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The `Proto` type itself only matters because `Operation.result` references it (line 2031) — the SDK's primary error type. Forcing every error consumer to cast. +- **Category:** 1 (vague), 15 (generic), 16 (type contradicts domain — details have structure, just unmodelled). +- **Suggested name:** Add typed discriminator: `details: ErrorDetail[]` with `ErrorDetail = ResourceInfo | RetryInfo | …` aligned to `google.rpc.Status`. +- **Rationale:** Errors are the most-handled values in any SDK; opaque `unknown` arrays force every caller to write defensive code. + +### 21. 22 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1845-3680` +- **Why weird:** The package exports 22 boilerplate poller classes (each ~80 lines, near-identical): `CreateBranchOperation`, `CreateCatalogOperation`, `CreateDatabaseOperation`, `CreateEndpointOperation`, `CreateProjectOperation`, `CreateRoleOperation`, `CreateSyncedTableOperation`, `DeleteBranchOperation`, `DeleteCatalogOperation`, `DeleteDatabaseOperation`, `DeleteEndpointOperation`, `DeleteProjectOperation`, `DeleteRoleOperation`, `DeleteSyncedTableOperation`, `UndeleteBranchOperation`, `UndeleteProjectOperation`, `UpdateBranchOperation`, `UpdateDatabaseOperation`, `UpdateEndpointOperation`, `UpdateProjectOperation`, `UpdateRoleOperation`. Each has identical `name()` / `metadata()` / `wait()` / `done()` methods, differing only in return type (`Branch` vs `Catalog` vs `Database` etc.). All 22 are exported from `index.ts:5-26`. +- **Category:** 7 (overly verbose), 11 (trivial wrappers), 14 (Go-style poll-helper pattern), 17 (22-way redundancy). +- **Suggested name:** Single generic `Operation` class with `wait(): Promise` and `metadata(): Promise`. Drop all 22 named exports; expose factory methods on `Client` like `createBranchOperation()` that return `Operation`. +- **Rationale:** Comparable to `database/v1/client.ts`'s `CreateDatabaseInstanceWaiter` — but here the pattern is repeated 22 times. This bloats the bundle, the public surface, and the autocomplete list. + +### 22. `*Operation` classes mix verb prefix with noun suffix — e.g. `CreateBranchOperation` — `src/v1/client.ts:1845, …` +- **Why weird:** Class name reads as "the *create branch* operation" — i.e. a long-running operation produced by creating a branch. JS convention for poller helpers tends to be `Poller`, `Waiter`, or a verb-form factory. Calling it `CreateBranchOperation` (verb + noun + noun-suffix `Operation`) parses ambiguously: a `CreateBranchOperation` could be "an operation that creates a branch" (active) or "an in-flight operation tracking branch creation" (passive). The latter is the intent. +- **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming), 11 (wrapper-class pattern). +- **Suggested name:** `BranchCreation` / `BranchCreationOperation` (passive form), or factor into a single generic `Operation` (see #21). +- **Rationale:** Same as `database` audit #14. Class names should be unambiguous noun phrases. + +## Medium severity + +### 23. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` / `Table` / `ComputeInstance` — 9 generic top-level resource names — `src/v1/model.ts` (multiple) +- **Why weird:** Most of these names are single-word generic English (`Branch`, `Catalog`, `Database`, `Endpoint`, `Project`, `Role`, `Table`). Multiple are *already-taken* concepts in Databricks-land: + - `Catalog` collides with Unity Catalog `Catalog` (in `catalogs` package) + - `Database` collides with the `database` package's `DatabaseInstance` / `DatabaseCatalog` + - `Endpoint` collides with `endpoints` package (Model Serving endpoints) and `vector-search endpoints` + - `Project` is a generic word — Lakebase Projects are not the same as Bundle projects or Genie projects. + - `Role` collides with workspace IAM roles and instance-profile roles. + - `Table` collides with `tables` (Unity Catalog tables), `onlinetables`, `database.DatabaseTable`. + - `ComputeInstance` collides with `database.DatabaseInstance` (the older equivalent). +- **Category:** 1 (vague/generic), 12 (duplicate concept across packages). +- **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`, `LakebaseTable`, `LakebaseComputeInstance`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). +- **Rationale:** With 100+ packages in the workspace, single-word resource names guarantee collisions. + +### 24. `Branch.uid` / `Endpoint.uid` / `Project.uid` / `SyncedTable.uid` — bare `uid` fields, sometimes vs `name` — `src/v1/model.ts:757, 1335, 2048, 2375` +- **Why weird:** Same problem as `database` finding #18: two identifier-like fields. `name` is a resource path (`projects/{id}/branches/{id}`), `uid` is "System-generated unique ID". Caller can't tell which to pass to `getBranch` (answer: `name`). Bare `uid` is non-descriptive — what scope (project? branch? UC table?). +- **Category:** 19 (underspecified id), 1 (vague `uid`). +- **Suggested name:** `branchUid` / `endpointUid` / `projectUid` / `syncedTableUid` (and add docs). +- **Rationale:** Same as `database` audit #18. + +### 25. `Branch.name` / `Catalog.name` / etc. — `name` is a full resource path — `src/v1/model.ts:755, 878, 1106, 1333, 2046, 2254` +- **Why weird:** Field is `name?: string` but the doc constrains it to a multi-segment path like `projects/{project_id}/branches/{branch_id}`. There is a separate `branchId` / `catalogId` / `databaseId` / `endpointId` / `projectId` / `roleId` field in each status sub-type. Caller has to read JSDoc to know which to use. +- **Category:** 1 (vague), 19 (underspecified id), 6 (misleading — `name` reads as a human-readable name, actually a resource path). +- **Suggested name:** `resourceName` / `fullName` / `resourcePath` for the path-style field; keep the short ID where present. +- **Rationale:** `name` is the most ambiguous field name possible. + +### 26. `Branch.parent` — string-typed parent path — `src/v1/model.ts:765` +- **Why weird:** `parent?: string` doc'd as "The project containing this branch (API resource hierarchy). Format: `projects/{project_id}`". Generic name; the type doesn't enforce the format. Same pattern repeats on `Database.parent` (1111), `Endpoint.parent` (1340), `Role.parent` (2259), `CreateBranchRequest.parent`, `CreateDatabaseRequest.parent`, etc. +- **Category:** 1 (vague), 15 (generic), 19 (underspecified — what kind of parent?). +- **Suggested name:** `projectName` / `branchName` / specific to the parent type. Or `parentResourceName`. +- **Rationale:** Parents differ per child type; `parent` is too generic. + +### 27. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:798-824` +- **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. +- **Category:** 16 (type allows `false` but spec rejects it). +- **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. +- **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. + +### 28. `BranchSpec.isProtected` vs `BranchStatus.isProtected` vs `BranchStatus.default` — same struct, two booleans — `src/v1/model.ts:791, 838, 840` +- **Why weird:** `BranchStatus.default: boolean | undefined` field clashes with the JS `default` keyword in `import { default } from …` contexts. While not a reserved word in object-property position, it's syntactically irritating and a JS lint hot spot. +- **Category:** 10 (reserved-word collision), 1 (vague — `default` of what?). +- **Suggested name:** `isDefault: boolean` (matches sibling `isProtected`). +- **Rationale:** `branch.default = true` reads weirdly; `branch.isDefault = true` aligns with `branch.isProtected`. + +### 29. `Catalog_CatalogSpec.createDatabaseIfMissing` — `src/v1/model.ts:918` +- **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF MISSING`). Same as `database` audit #30 (`createDatabaseIfNotExists`) but with the variant wording "If Missing". Inconsistent with `database` package's "If Not Exists". +- **Category:** 14 (SQL-style name), 7 (verbose), 17 (inconsistent with sister package's `createDatabaseIfNotExists`). +- **Suggested name:** `ensureDatabaseExists` or `autoCreateDatabase`. +- **Rationale:** Two packages, two variants of the same SQL-DDL leak. + +### 30. `Catalog_CatalogStatus.catalogId` / `Database_DatabaseStatus.databaseId` / `BranchStatus.branchId` / `EndpointStatus.endpointId` / `ProjectStatus.projectId` / `Role_RoleStatus.roleId` — duplicated ID with parent-type prefix — `src/v1/model.ts:952, 1164, 859, 1516, 2220, 2358` +- **Why weird:** Each status type repeats the parent type's name as a field prefix. `Catalog_CatalogStatus.catalogId` is `Catalog.status.catalogId` — three "catalog"s. Same problem as `database` audit #31 but here the redundancy is *inside* the status type, not just the parent. JSDoc on every field says identical boilerplate: "The short identifier of the X, suitable for showing to the users." +- **Category:** 7 (verbose), 17 (boilerplate JSDoc), 20 (type-suffix tautology). +- **Suggested name:** `id: string` (the wrapping type name is already the resource). +- **Rationale:** `catalog.status.catalogId` is "catalog status catalog id" — verbose. + +### 31. `ComputeInstance.computeInstanceId` field — `src/v1/model.ts:965` +- **Why weird:** Self-tautology: `ComputeInstance.computeInstanceId`. Three `compute`/`instance` repetitions in a single member reference. +- **Category:** 20 (type-suffix tautology), 7 (verbose). +- **Suggested name:** `id: string` or just `computeId`. +- **Rationale:** Same as #30 but more egregious because both the type and field repeat both words. + +### 32. `ComputeInstance.computeHost` — `src/v1/model.ts:973` +- **Why weird:** `computeHost` is a `string` that's actually a hostname. "Host" already means hostname; the "compute" qualifier is redundant (we're already inside `ComputeInstance`). +- **Category:** 20 (type-prefix tautology), 7 (verbose). +- **Suggested name:** `host: string` (or `hostname`). +- **Rationale:** Same as #30. + +### 33. `ComputeInstance.role: ComputeInstance_ComputeType` field — `src/v1/model.ts:971` +- **Why weird:** Field is `role`; type is `ComputeInstance_ComputeType`. So `role` is a `ComputeType`, not a Postgres role. Two unrelated concepts (Postgres `Role` and compute `Role`) share the field name. Confusing inside the same package. +- **Category:** 6 (misleading — `role` here is *not* a Postgres role), 12 (duplicate concept — `Role` vs `ComputeInstance.role`). +- **Suggested name:** `kind: ComputeType` or `computeRole: ComputeType`. +- **Rationale:** A field named `role` inside a package that *also* has a `Role` type is asking for trouble. + +### 34. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:991, 993` +- **Why weird:** `CreateBranchRequest` has `parent`, `branchId`, `branch`, `replaceExisting`. `branchId` is the path-component id; `branch.name` (inside `Branch`) is the full resource path; `branch` is the body. Three fields all involved in identifying the branch. +- **Category:** 17 (inconsistency — same operation, three id-like fields), 19 (underspecified id semantics). +- **Suggested name:** Document the relationship clearly in JSDoc; or accept just `branch: Branch` and derive the id from `branch.name`. +- **Rationale:** Same shape repeats on `CreateCatalogRequest`, `CreateDatabaseRequest`, `CreateEndpointRequest`, `CreateProjectRequest`, `CreateRoleRequest`, `CreateSyncedTableRequest`. Caller must read multiple field docs to know which ID to set. + +### 35. `CreateBranchRequest.replaceExisting` / `CreateEndpointRequest.replaceExisting` — request-shaped name on a create call — `src/v1/model.ts:995, 1043` +- **Why weird:** `replaceExisting?: boolean` on a `Create*` request is essentially "upsert mode". Doc: "If true, update the branch if it already exists instead of returning an error." Many SDKs call this `upsert: true` or `ifExists: 'update'`. Verb is also imperative on a request body. +- **Category:** 17 (inconsistent — `create` verb + `replaceExisting` flag conflate two operations), 1 (vague — "replace" how?). +- **Suggested name:** `upsert: boolean` or `mode: 'create' | 'upsert'`. +- **Rationale:** "Create-or-update" is a common API pattern that deserves a clearer name. + +### 36. `Database.parent` is a branch path, `Database.spec.role` is a role path, `Database.status.role` is *also* a role path — `src/v1/model.ts:1111, 1132, 1151` +- **Why weird:** Two `role` fields on the spec and status sub-structs, both holding full resource paths like `projects/{}/branches/{}/roles/{}`. `Database.spec.role` is the *desired owner role*; `Database.status.role` is the *observed owner role*. Doc clarifies but the field-name overlap is jarring. +- **Category:** 19 (underspecified id — `role` is actually a role resource path), 1 (vague — `role` could be many things). +- **Suggested name:** `ownerRole` or `ownerRoleName`. Use the same name on spec and status. +- **Rationale:** Inside a `Database` struct, a bare `role: string` reads as "what role does this database have" — but it's specifically the *owner* role. + +### 37. `Database_DatabaseSpec.postgresDatabase` / `Database_DatabaseStatus.postgresDatabase` — `Database` containing `postgresDatabase` — `src/v1/model.ts:1142, 1153` +- **Why weird:** `Database.spec.postgresDatabase` is "the name of the Postgres database" — but the surrounding type is *already* `Database`. Three repetitions of "database" in one member access. +- **Category:** 20 (type-suffix tautology), 7 (verbose). +- **Suggested name:** `pgName` / `pgIdentifier` or just `name` (with a JSDoc note: "matches the Postgres database identifier"). +- **Rationale:** Same as #30, #31, #32. + +### 38. `Database` (Postgres) vs `Database_DatabaseSpec.postgresDatabase` (Postgres-side identifier) — same name, two meanings — `src/v1/model.ts:1100, 1142` +- **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. +- **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). +- **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). +- **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. + +### 39. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:269-313`, `model.ts:1023` +- **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. +- **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). +- **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. +- **Rationale:** Three identifier slots is too many. + +### 40. `DatabaseCredential.token: string` carries no doc on format — `src/v1/model.ts:1169` +- **Why weird:** "The OAuth token that can be used as a password when connecting to a database." Plain `string`. Sibling `expireTime: Temporal.Instant` does carry a type. The token doc doesn't say whether it's a JWT, opaque, format `:`, etc. Same issue exists in `database/v1.DatabaseCredential.token`. +- **Category:** 15 (generic field name), 1 (vague). +- **Suggested name:** `accessToken` (and document the format/lifetime in JSDoc). +- **Rationale:** Tokens carry semantics; consumers need to know the format. + +### 41. `Endpoint.endpointType` field of type `EndpointType` — `src/v1/model.ts:1428` +- **Why weird:** `endpoint.endpointType` is type-suffix tautology again: three "endpoint"s. The field of type `EndpointType` could just be `type` since the surrounding type is `Endpoint`. +- **Category:** 20 (type-suffix tautology), 7 (verbose). +- **Suggested name:** `type: EndpointType` (or `kind`). +- **Rationale:** Same as #31. + +### 42. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1430, 1435` +- **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. +- **Category:** 5 (cryptic abbreviation), 1 (vague suffix). +- **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. +- **Rationale:** "CU" is Lakebase-internal slang. + +### 43. `EndpointGroupSpec.min` / `max` with `min === max` constraint — `src/v1/model.ts:1356, 1362` +- **Why weird:** Two bare fields `min: number` / `max: number` (and `enableReadableSecondaries`) on a group spec. JSDoc says "Currently, this must be equal to max" — meaning callers must set min === max. Type system doesn't enforce; bare `min`/`max` doesn't suggest "group size". +- **Category:** 1 (vague), 16 (type contradicts spec — allows min ≠ max). +- **Suggested name:** `size: number` (until min ≠ max becomes supported, then introduce `minSize`/`maxSize`). +- **Rationale:** Pseudo-flexibility leaks proto future-proofing. + +### 44. `EndpointHosts` — type holds 4 hostname fields — `src/v1/model.ts:1390-1409` +- **Why weird:** Fields are `host` (generic), `readOnlyHost`, `readWritePooledHost`, `readOnlyPooledHost`. The first is "the hostname"; the others narrow by direction/pooling. `host` reads as "the only host" but is just *one* of four. JSDoc clarifies but the field name doesn't. +- **Category:** 1 (vague — `host` is the catch-all), 15 (generic). +- **Suggested name:** `primaryHost` / `readOnlyHost` / `readWritePooledHost` / `readOnlyPooledHost` (i.e. give the first one a qualifier). +- **Rationale:** Reader doesn't know which is "the" host. + +### 45. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1449-1468` +- **Why weird:** Same pattern as #27 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. +- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #27). +- **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. +- **Rationale:** Same as #27. + +### 46. `EndpointSettings.pgSettings: Record` field — `src/v1/model.ts:1417` +- **Why weird:** `pgSettings` is a map of Postgres GUC settings (e.g. `{ work_mem: '4MB' }`). Generic value type `string`. No validation. Field name `pgSettings` is itself ambiguous — could be any kind of setting. +- **Category:** 14 (proto map-entry shape leaks into TS), 1 (vague — `pgSettings` could be any kind of setting). +- **Suggested name:** `postgresGucSettings: Record` (more specific). +- **Rationale:** Field name should encode the domain (Postgres GUC parameters). + +### 47. `ForwardEtlConfig.workspaceId: number` typed as integer — `src/v1/model.ts:1522` +- **Why weird:** `workspaceId` is a `number` (also see `ForwardEtlConfig.createTimeMillis` — same numeric type for two unrelated concepts). Databricks workspace IDs are 64-bit integers — TS `number` can't represent the full int64 range above 2^53. Should be `bigint` or string. +- **Category:** 16 (field type contradicts domain — int64 wire vs JS number). +- **Suggested name:** `workspaceId: string` (or `bigint`). +- **Rationale:** Same precision pitfall as Java's `Long` going to JSON. + +### 48. `GenerateDatabaseCredentialRequest.endpoint` field "not yet supported" — `src/v1/model.ts:1595-1598` +- **Why weird:** Field doc says "This field is not yet supported." Field is exposed in the public TS type without an `@deprecated` or `@unsupported` JSDoc marker. +- **Category:** 6 (misleading — looks usable but isn't). +- **Suggested name:** Mark with `@deprecated` JSDoc and/or rename to `endpointReserved`. +- **Rationale:** Same as `database` audit #56. + +### 49. `GenerateDatabaseCredentialRequest.expiration` discriminated union — `src/v1/model.ts:1610-1627` +- **Why weird:** Same `oneof` pattern as #27 — `ttl` or `expireTime`. But here `noExpiry` doesn't exist; just two variants. The variant order in the union is `ttl` then `expireTime`, but on `BranchSpec.expiration` (#27) it's `expireTime` then `ttl`. Inconsistent variant ordering within the same package. +- **Category:** 17 (inconsistent variant ordering across two siblings). +- **Suggested name:** Standardise order across both unions. +- **Rationale:** Minor but a generator/consistency check would catch it. + +### 50. `InitialBranchSpec` / `InitialDatabaseSpec` / `InitialEndpointSpec` / `InitialRoleSpec` — 4 "Initial*Spec" types duplicate the corresponding `Spec` — `src/v1/model.ts:1734, 1746, 1757, 1776` +- **Why weird:** Four types named `InitialSpec`, each carrying the same field set as the corresponding `Spec`. The `Initial` prefix is documentation, not semantics — these are spec values for the *initial* default resources created with a project. `InitialRoleSpec` has nearly identical body to `Role_RoleSpec` (5 of 5 fields match). Duplicating the shape per-context multiplies the public surface. +- **Category:** 12 (duplicate concept). +- **Suggested name:** Use the regular `Spec` types directly with a JSDoc note on `Project.initialBranchSpec` saying "use a `BranchSpec` value here; it applies only to the initial default branch". +- **Rationale:** Doubles the type count for a docs-only distinction. + +### 51. `NewPipelineSpec` (top-level) vs the comment "Specification for creating a new pipeline" — `src/v1/model.ts:1963` +- **Why weird:** Type name carries the verb "new" (`NewPipelineSpec`). Reads as "the new pipeline spec" (a noun phrase about a *new* type of pipeline) or "spec for a new pipeline" (the actual intent). Java/C# call these `CreatePipelineSpec` or `PipelineCreate`. The type holds 4 fields (`storageCatalog`, `storageSchema`, `budgetPolicyId`, `pipelineChannel`). +- **Category:** 13 (verb-tense — `new` as adjective for a type name), 6 (misleading). +- **Suggested name:** `PipelineCreationSpec` or `NewPipelineConfig`. +- **Rationale:** Type names with embedded verbs are awkward; consider `Spec` only when the type *configures* something. + +### 52. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:2014` +- **Why weird:** Plain `Record`. The 22 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1862-1865` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. +- **Category:** 15 (generic), 16 (loose typing). +- **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. +- **Rationale:** Same root cause as #20 — opaque records on the public surface. + +### 53. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:2027-2038` +- **Why weird:** Variant `response` carries `Record` (line 2036). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) +- **Category:** 16 (asymmetric typing), 15 (generic on success arm). +- **Suggested name:** Same as #52 — generic `Operation` with both arms typed. +- **Rationale:** Same as #20, #52. + +### 54. `Project.spec` / `Project.status` / `Project.initialBranchSpec` / `Project.initialRoleSpec` / `Project.initialDatabaseSpec` / `Project.initialEndpointSpec` — six spec/status fields on one type, four are write-only — `src/v1/model.ts:2054-2095` +- **Why weird:** Single `Project` type carries spec + status + four initial-* sub-specs. The four `initial*` fields are create-time-only inputs but exposed on the response type too — a read-flow consumer sees four fields that are always empty. +- **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). +- **Suggested name:** Hoist the `initial*` fields onto `CreateProjectRequest` only (where they belong); leave `Project` to spec/status. +- **Rationale:** Same as `database` audit #11 — input/output shape confusion. + +### 55. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:2098`, `database:206` +- **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. +- **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). +- **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. +- **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. + +### 56. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:2148, 2191` +- **Why weird:** Doc says "The major Postgres version number. Supported versions are 16 and 17." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. +- **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). +- **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. +- **Rationale:** Aligns documented constraints with the type system. + +### 57. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:2150, 2193` +- **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. +- **Category:** 17 (inconsistent with sister package). +- **Suggested name:** Pick one convention across the two packages. +- **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. + +### 58. `ProjectSpec.workspaceKeyEncrypted: boolean` — `src/v1/model.ts:2170` +- **Why weird:** Field doc admits the flag is temporary: "Since we need to do an end to end perf bench using BSS API to A/B test the performance impact of CMK encryption, we need to be able to control this flag in the API. This flag will be removed once we find a better way…" Flag is exposed on the public SDK surface. +- **Category:** 14 (internal-jargon leak — "BSS API", "CMK"), 6 (misleading — flag is benchmark-temporary). +- **Suggested name:** Either hide behind an internal beta-flag mechanism, or rename to `workspaceCmkEnabled` and document it neutrally. +- **Rationale:** Benchmark scaffolding on the public surface. + +### 59. `ProjectSpec.enablePgNativeLogin` / `ProjectStatus.enablePgNativeLogin` — request-shaped verb on response — `src/v1/model.ts:2172, 2208` +- **Why weird:** Same problem as `database` audit #25: `enableX: boolean` reads as imperative on a response type. `ProjectStatus.enablePgNativeLogin` should read "is PG native login enabled". +- **Category:** 6 (misleading verb form), 17 (input/output asymmetry). +- **Suggested name:** Input: `enablePgNativeLogin`. Output: `pgNativeLoginEnabled`. +- **Rationale:** Same as `database` audit #25. + +### 60. `RequestedResource.resourceName` discriminated union with `unspecifiedResourceName` and `tableName` — `src/v1/model.ts:2237-2246` +- **Why weird:** Same as `database` audit #16 — discriminated union whose `unspecifiedResourceName` variant exists only because the proto generator emits sentinel branches. `tableName` is the only useful variant. +- **Category:** 1 (vague), 6 (misleading — `unspecifiedResourceName` exists in TS but shouldn't). +- **Suggested name:** Top-level `RequestedResource = {kind: 'table', tableName: string}`. +- **Rationale:** Same as `database` audit #16. + +### 61. `SyncedTable_SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:2419` +- **Why weird:** Same as `database` audit #35: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. +- **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). +- **Suggested name:** `timeSeriesKey`. +- **Rationale:** Same as `database` audit #35. + +### 62. `SyncedTable_SyncedTableSpec.acceleratedSync` / `createDatabaseObjectsIfMissing` / `extraIndexDefinitions` / `extraColumnDefinitions` / `typeOverrides` — same fields, same issues as `database` package — `src/v1/model.ts:2447, 2434, 2454, 2458, 2452` +- **Why weird:** Identical to `database` audit findings #37–#42. Won't re-state at length; flag that the duplication exists across both packages with identical naming. +- **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). +- **Suggested name:** Same suggestions as `database` audit. +- **Rationale:** Two SDKs, same problems. + +### 63. `Table` (non-synced) — generic single-word type — `src/v1/model.ts:2586` +- **Why weird:** `Table` is the most generic possible name. Doc: "Table represents a non-synced database table in a Lakebase project. Unlike SyncedTable, this does not have a data synchronization pipeline." Sibling `SyncedTable` has the "Synced" qualifier; this one should have "NonSynced" or "Native" qualifier. Bare `Table` is also confusable with UC `Table`, online `Table`, etc. +- **Category:** 1 (vague/generic), 12 (duplicate concept — `Table` exists in multiple SDK packages). +- **Suggested name:** `LakebaseTable` or `NativeTable` or `PgTable`. +- **Rationale:** Same as #23. + +### 64. `Table.database` / `Table.project` / `Table.branch` — three string fields, each a different resource path — `src/v1/model.ts:2594-2598` +- **Why weird:** Three sibling string fields, each holding a different multi-segment path. `database` is `projects/{}/branches/{}/databases/{}`, `project` is `projects/{}`, `branch` is `projects/{}/branches/{}`. Two of them (`project` and `branch`) are prefixes of `database`. No discriminator. +- **Category:** 19 (underspecified ids), 1 (vague — bare `project` could be many things). +- **Suggested name:** `databaseName` / `projectName` / `branchName` (and prefix each with the resource type the path identifies). +- **Rationale:** Three resource paths under generic field names. + +### 65. `Table.tableServingUrl` / `DatabaseTable.tableServingUrl` (in `database` package) — same field, same issue — `src/v1/model.ts:2600` +- **Why weird:** `tableServingUrl` is opaque (see `database` audit #33). "Serving" is feature-store jargon for "REST endpoint for reads". On a Postgres table, the meaning is "REST API to read this table". Field doc: "REST API URL for serving data from this table." +- **Category:** 1 (vague), 6 (misleading — `Serving` is feature-store terminology). +- **Suggested name:** `restEndpointUrl` / `apiEndpointUrl`. +- **Rationale:** Same as `database` audit #33. + +### 66. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2629` +- **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. +- **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). +- **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. +- **Rationale:** AIP `FieldMask` is an industry pattern, but it should not be the only update affordance. + +### 67. `DeleteForwardEtlConfigurationResponse.deletedConfigs` / `deletedMappings` — count fields without singular form — `src/v1/model.ts:1247-1250` +- **Why weird:** Field is `deletedConfigs: number | undefined` — a count, not a list. The name reads as a plural array (`deletedConfigs: Config[]`). JSDoc clarifies "Number of configuration rows deleted (0 or 1)". +- **Category:** 9 (singular/plural mismatch — plural name on a `number`), 1 (vague). +- **Suggested name:** `deletedConfigCount` / `deletedMappingCount`. +- **Rationale:** Reader sees `deletedConfigs` and expects an array. + +### 68. `getOperation` / `Operation.name` — operation name is a resource path — `src/v1/client.ts:1109`, `model.ts:1699` +- **Why weird:** `getOperation({name: ...})` takes a `string` that is actually a path like `operations/{unique_id}`. The doc on `Operation.name` says "If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`." But it doesn't validate. +- **Category:** 19 (underspecified id), 6 (misleading — `name` reads like a label). +- **Suggested name:** `operationResourceName` / `operationPath` / `id`. +- **Rationale:** Same as #25. + +### 69. `createTable` / `deleteTable` / `getTable` — operate on `Table`, not the synced version — `src/v1/client.ts:502, 826, 1207` +- **Why weird:** Method names `createTable` are generic; consumer must read the JSDoc to know they target the `Table` (non-synced) resource. Sibling `createSyncedTable` is explicit. `Table` operations are CRUD over native PG tables; the method name should signal that. +- **Category:** 1 (vague — `createTable` is generic), 12 (duplicate concept — also `CreateDatabaseTableRequest` in `database` package). +- **Suggested name:** `createNativeTable` / `createLakebaseTable` (mirror the `createSyncedTable` pattern). +- **Rationale:** Lakebase has two table flavors; both deserve explicit method names. + +## Low severity + +### 70. `BranchSpec.sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` — `src/v1/model.ts:785, 787, 789` +- **Why weird:** Three sibling fields on `BranchSpec`. `sourceBranch` is a path; `sourceBranchLsn` and `sourceBranchTime` are alternative cutover specifiers (one or the other). Bare `branchTime` repeats from `database/v1.DatabaseInstanceRef.branchTime` (see `database` audit #28). +- **Category:** 1 (vague — `branchTime` is a cutover instant, not a time-of-branch). +- **Suggested name:** `sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` are OK; consider `sourceBranchAtLsn` / `sourceBranchAtTime` for clarity. +- **Rationale:** Same as `database` audit #28. + +### 71. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:805, 850` +- **Why weird:** Field name `expireTime` appears twice: once as a discriminated-union variant on `BranchSpec` (input), once as a top-level field on `BranchStatus` (output). Reader has to track that the input shape collapses `expireTime`/`ttl`/`noExpiry` to a single output value `expireTime`. +- **Category:** 17 (input/output shape mismatch). +- **Suggested name:** Document the asymmetry in JSDoc; or expose the same union shape on output. +- **Rationale:** Generator-driven asymmetry. + +### 72. `BranchSpec.ttl: Temporal.Duration` and `BranchSpec.expireTime` — `ttl` is a duration, `expireTime` is a timestamp — `src/v1/model.ts:813, 805` +- **Why weird:** `ttl` (time-to-live) and `expireTime` are sibling variants. `ttl` is duration-shaped; `expireTime` is timestamp-shaped. Bare `ttl` is a Unix-cache-style abbreviation. +- **Category:** 5 (cryptic abbreviation — `ttl`). +- **Suggested name:** `lifetime: Duration` or `expireAfter: Duration`. +- **Rationale:** `TTL` is widely understood but expansion improves grep-ability. + +### 73. `CreateBranchRequest.replaceExisting` vs `DeleteBranchRequest.allowMissing` — verb-tense asymmetry across CRUD — `src/v1/model.ts:995, 1200` +- **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete uses `allowMissing: boolean` (tolerant). Two different conventions for the "if it does/doesn't exist" behaviour. Update has no such field; Get doesn't either. Inconsistent. +- **Category:** 17 (inconsistent action verbs across CRUD). +- **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. +- **Rationale:** Inconsistent options across CRUD operations is a small papercut. + +### 74. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1195` +- **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete. Soft deletion (purge=false) is not supported yet." So the value of `false` is rejected. Same `purge` field on `DeleteProjectRequest` (line 1263). +- **Category:** 16 (type allows `false` but spec rejects), 6 (misleading — purge implies cleanup, not the *only* delete mode). +- **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. Add `@deprecated` until soft-delete is supported. +- **Rationale:** Boolean toggle for a future-3-state field. + +### 75. `DeleteForwardEtlConfigurationRequest` vs `DisableForwardEtlRequest` — two near-identical types — `src/v1/model.ts:1229, 1306` +- **Why weird:** Both types carry `parent`, `tenantId`, `timelineId`, `pgDatabaseOid`, `pgSchemaOid`. Doc on `DeleteForwardEtlConfigurationRequest`: "Unlike DisableForwardEtl, this permanently removes the config and mapping rows." The distinction is `Delete` (hard) vs `Disable` (soft) — same boolean-toggle pattern as `purge` (#74) but split into two types. +- **Category:** 12 (duplicate concept), 17 (different verbs for the same shape). +- **Suggested name:** Merge into one request type with a `mode: 'delete' | 'disable'` field. +- **Rationale:** Two methods carrying identical fields suggests one method with a flag. + +### 76. `ForwardEtlMetadata.databases` / `schemas` — bare plurals — `src/v1/model.ts:1554, 1556` +- **Why weird:** `databases: ForwardEtlDatabase[]` and `schemas: ForwardEtlSchema[]` — bare plurals. Inside a `ForwardEtl` context, these are PG OID-to-name maps, not regular databases/schemas. Reader expects `Database` (the SDK type) but gets `ForwardEtlDatabase` (a name+OID pair). +- **Category:** 1 (vague — `databases` is too generic in a `ForwardEtl` context), 17 (`Database` SDK type vs `ForwardEtlDatabase` ad-hoc type). +- **Suggested name:** `databaseOids` / `schemaOids` (matches the underlying domain), or keep plurals but document. +- **Rationale:** Mild — context disambiguates. + +### 77. `ForwardEtlTableMapping.lastSyncedLsn: string` — LSN as bare string — `src/v1/model.ts:1582` +- **Why weird:** Postgres LSN is `XX/YY` string. Field name uses `Lsn` abbreviation without expansion. Sibling `pgTableOid` already a Postgres-internal. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `lastSyncedLogSequenceNumber` (or `walLsn`). +- **Rationale:** Same as `database` audit #27. + +### 78. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1593` +- **Why weird:** Same as `database` audit #53 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** Same as `database` audit #53 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. +- **Rationale:** Same as `database` audit #53. + +### 79. `GenerateDatabaseCredentialRequest.groupName: string` — `src/v1/model.ts:1604` +- **Why weird:** Doc: "Databricks workspace group name. When provided, credentials are generated with permissions scoped to this group." Bare `groupName` reads as a Postgres role name; actually a Databricks workspace group. Field is sibling to `claims` and `endpoint`; the relationship between them isn't spelled out (do you set all three? one? two?). +- **Category:** 1 (vague — `groupName` could be PG or DB workspace), 17 (multi-field request without clear mutex docs). +- **Suggested name:** `workspaceGroupName`. +- **Rationale:** Disambiguate from Postgres role names. + +### 80. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:2020` +- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1885`). +- **Category:** 16 (type allows three values but spec only documents two). +- **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. +- **Rationale:** Tri-state booleans always confuse callers. + +### 81. `Project.deleteTime` / `Project.purgeTime` — two delete-related timestamps — `src/v1/model.ts:2067, 2072` +- **Why weird:** `deleteTime` = "when soft-deleted"; `purgeTime` = "when scheduled for permanent deletion". Bare verbs `delete` / `purge` are similar; the distinction matters for the consumer but the field names alone don't communicate the lifecycle. +- **Category:** 1 (vague), 6 (misleading — `purge` could mean "purged at" or "scheduled to purge"). +- **Suggested name:** `softDeletedAt` / `scheduledPurgeAt`. +- **Rationale:** Lifecycle-related fields benefit from clearer past/future tense. + +### 82. `ProjectStatus.syntheticStorageSizeBytes` — "synthetic" qualifier — `src/v1/model.ts:2199` +- **Why weird:** `syntheticStorageSizeBytes` — what's "synthetic" about storage? Doc says "The current space occupied by the project in storage." JSDoc doesn't explain "synthetic". Likely Lakebase internal billing concept. +- **Category:** 1 (vague), 14 (internal-jargon leak). +- **Suggested name:** `storageSizeBytes` or `billingStorageSizeBytes`. +- **Rationale:** Internal-jargon leak. + +### 83. `ProjectStatus.computeLastActiveTime` — `src/v1/model.ts:2201` +- **Why weird:** Doc: "The most recent time when any endpoint of this project was active." Field name is `compute` + `lastActiveTime` — reads as "the compute last active time" with an implicit possessive. Awkward grammar. +- **Category:** 1 (vague), 17 (irregular grammar). +- **Suggested name:** `lastComputeActiveTime` or `lastActivityTime` or `lastEndpointActivityTime`. +- **Rationale:** Word ordering in compound field names matters for grep-ability. + +### 84. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:797, 803, 811, 820, 1447, 1455, 1465` +- **Why weird:** JSDoc references update mask in snake_case (e.g. "When updating this field, use `spec.expiration` in the update_mask"). Update mask field on the request is `updateMask: FieldMask<...>` (camelCase) but docs reference the wire-format name. Consumer reading the JSDoc and writing TS code has to translate. +- **Category:** 17 (inconsistent — JSDoc snake_case, TS camelCase). +- **Suggested name:** Use TS field name in JSDoc. +- **Rationale:** Doc/code drift. + +### 85. `ListBranchesRequest.showDeleted` / `ListProjectsRequest.showDeleted` — pair of duplicate optional flags — `src/v1/model.ts:1844, 1934` +- **Why weird:** Two structs carry identical `showDeleted?: boolean` with similar JSDoc. Not bad on its own, but the option name `showDeleted` is itself an imperative-shaped name on a request type (compare to `includeDeleted` or `deletedOnly`). +- **Category:** 1 (vague — `show` is presentation-layer language for a server request). +- **Suggested name:** `includeDeleted` or `includeSoftDeleted`. +- **Rationale:** Same as `database` audit #25 — request shapes prefer descriptive booleans over imperative ones. + +### 86. `listComputeInstances`'s doc reads "The parent, which owns the compute instances" — `src/v1/model.ts:1855` +- **Why weird:** `ListComputeInstancesRequest.parent` doc is sparse: "The parent, which owns the compute instances." No format given. Compare to sibling `ListBranchesRequest.parent` which specifies "Format: `projects/{project_id}`". +- **Category:** 6 (misleading — doc missing). +- **Suggested name:** Fix the doc; add the format. +- **Rationale:** Documentation copy-paste oversight. + +## Observation + +### 87. Method JSDoc inconsistency — `src/v1/client.ts` throughout +- **Why weird:** Some methods have rich JSDoc ("Creates a new database branch in the project.", "Register a Postgres database in the Unity Catalog."). Others are terse ("Create a Database.", "Get a Database.", "List Databases."). Inconsistency in doc depth across CRUD methods of the same resource. +- **Category:** Observation (doc quality, not naming). +- **Suggested name:** Standardise to the richer template. +- **Rationale:** Naming-adjacent. + +### 88. `Operation` is a separate type, not a generic — `src/v1/model.ts:2002` +- **Why weird:** All 22 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#21) or reads `Operation.result.response` (untyped `Record`). +- **Category:** Observation (architecture, not naming per se). +- **Suggested name:** `Operation` generic. +- **Rationale:** Connects #20, #21, #52, #53. + +### 89. `marshalRequest` / `parseResponse` / `executeCall` are exported from `utils.ts` only inside the package — `src/v1/utils.ts` +- **Why weird:** Utility names are generic (`buildHttpRequest`, `executeHttpCall`, `flattenQueryParams`, `marshalRequest`, `parseResponse`). They're not in the `index.ts` public exports, so this is internal naming. No naming bug per se; flag that they're all generic and could collide if ever exposed. +- **Category:** Observation (internal generics). +- **Suggested name:** N/A (internal). +- **Rationale:** Not actionable but worth noting. + +### 90. `flattenQueryParams` in `utils.ts` has the comment "// arrays of objects are not yet supported" — `src/v1/utils.ts:132` +- **Why weird:** Code comment admits a gap. Not naming-related, but indicates the marshal layer is incomplete; future array-of-objects fields will silently misbehave. +- **Category:** Observation. +- **Suggested name:** Fix the gap (TODO) or document the constraint at the public layer. +- **Rationale:** Not naming. + +### 91. `EndpointSettings_PgSettingsEntry` and `ProjectDefaultEndpointSettings_PgSettingsEntry` are duplicated, dead types — `src/v1/model.ts:1421, 2136` +- **Why weird:** Both types are identical (`{key, value}`) and unused. They are proto-generated map-entry types. They are exported from `index.ts:91, 135`. +- **Category:** Observation (related to #46, #55). +- **Suggested name:** Remove (and also `ProjectCustomTag` could merge with `database.CustomTag`). +- **Rationale:** Public surface bloat. + +### 92. `ProvisioningInfo_State` is exported from both `database` and `postgres` packages with identical members — `src/v1/model.ts:654`, `database/v1/model.ts:148` +- **Why weird:** Same enum, two packages, identical members. Reader importing both packages has to alias one. +- **Category:** Observation (cross-package duplication). +- **Suggested name:** Move to a shared `core/lakebase-common` or `core/enums`. +- **Rationale:** Related to #2. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md new file mode 100644 index 00000000..8ad75751 --- /dev/null +++ b/.agent/naming-audit/qualitymonitor.md @@ -0,0 +1,318 @@ +# Naming Audit: qualitymonitor + +**Path:** `packages/qualitymonitor/src/v2/` +**Versions audited:** v2 +**Inferred domain:** Quality monitoring on Unity Catalog objects (currently only `schema`). The package defines a single `QualityMonitor` entity that wraps `AnomalyDetectionConfig` (last-run telemetry plus excluded tables) and a list of `ValidityCheckConfiguration` arms (percent-null, range, uniqueness). A nested concept (`CustomCheckConfiguration` -> `CustomScalarCheck`) lets callers attach templated SQL checks with per-column matchers. Every operation is marked `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., this entire package is a deprecated shim that has been superseded by the `dataquality` package. +**Total weird names flagged:** 47 + +## Summary +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 17 | +| Low | 11 | +| Observation | 6 | + +## CRITICAL: Two packages, same domain +This package (`@databricks/sdk-qualitymonitor`, exporting `./v2`) and its sibling `@databricks/sdk-qualitymonitors` (plural, exporting `./v1`) **both exist** in this repo. They model overlapping data-quality concepts but with completely different shapes: +- `qualitymonitor` (singular, v2): schema-level monitor with `AnomalyDetectionConfig` and a list of `ValidityCheckConfiguration` arms. Wire path: `/api/2.0/quality-monitors`. +- `qualitymonitors` (plural, v1): table-level monitor with `DataMonitorInfo`, `Refresh` runs, `MonitorCronSchedule`, etc. Wire path: `/api/2.1/unity-catalog/tables/{full_table_name_arg}/monitor`. + +The singular-vs-plural naming gives the reader no hint that these are different APIs over different UC resource types. Worse, both clients are deprecated in favour of the newer `dataquality` package (`/api/data-quality/v1/monitors`). Three packages, three vocabularies, one underlying business problem. + +**Category:** 9 (singular/plural mismatch in a sibling), 12 (duplicate concept across packages), 6 (misleading — the singular/plural distinction does not communicate the actual API split). + +**Recommendation:** Consolidate or rename. Possible options: (a) collapse both into `dataquality` (which is the deprecation target anyway) and remove the two deprecated packages from the SDK surface; (b) if both must be kept temporarily, rename to `qualitymonitorschema` (singular focuses on schemas) and `qualitymonitortables` (plural focuses on tables) so the directory name encodes the resource type, not a grammatical accident; (c) at minimum, surface a top-level `@deprecated` JSDoc on the `Client` class and on every exported type that points to `@databricks/sdk-dataquality`. None of the three options is done today. + +## High severity + +### 1. Package directory name `qualitymonitor` (singular) vs sibling `qualitymonitors` (plural) — repo layout +- **Why weird:** Two npm packages, two different sub-APIs, distinguished only by an `s`. A user with both installed will tab-complete `@databricks/sdk-qualitymonitor` and `@databricks/sdk-qualitymonitors` and have no obvious way to tell them apart from the import alone. The singular/plural form does not encode anything semantic (the singular package also returns lists of monitors; the plural package also returns single monitors). +- **Category:** 9 (singular/plural mismatch as the only differentiator), 1 (vague — neither name conveys the schema-vs-table split), 12 (duplicate concept). +- **Suggested name:** Rename one or both packages so the difference is on a meaningful dimension. Candidates: `qualitymonitor-schema` + `qualitymonitor-table`, or fold both into `dataquality` and delete these two. +- **Rationale:** Sibling packages must be distinguishable from the import string. Pluralisation alone is not enough. + +### 2. `Client` class — `src/v2/client.ts:41` +- **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing both `@databricks/sdk-qualitymonitor` and `@databricks/sdk-qualitymonitors` (very likely during migration off the deprecated APIs) cannot import both as `Client`. The package name does namespace via the import path, but in IDE go-to-symbol the name appears unqualified — every audited package in this SDK has the same `Client` collision. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). +- **Suggested name:** `QualityMonitorClient`. +- **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but especially acute here because three sibling packages (this, `qualitymonitors`, `dataquality`) all expose `Client`. + +### 3. `ListQualityMonitorRequest` / `ListQualityMonitorResponse` / `listQualityMonitor` / `listQualityMonitorIter` — `src/v2/model.ts:92-100`, `src/v2/client.ts:152,185` +- **Why weird:** Singular noun on a list operation. The response holds `qualityMonitors?: QualityMonitor[]` (plural), the paginator yields a single `QualityMonitor`, and the wire path is `/api/2.0/quality-monitors` (plural) — every concrete signal is plural; only the type/method name uses the singular `QualityMonitor`. Same singular-on-list bug as `dataquality` finding #1. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `ListQualityMonitorsRequest` / `ListQualityMonitorsResponse` / `listQualityMonitors` / `listQualityMonitorsIter`. +- **Rationale:** REST conventions, the package's own field naming (`qualityMonitors`), and the URL path all use plural. The singular form is generator template noise. + +### 4. `QualityMonitor.objectType` + `QualityMonitor.objectId` — `src/v2/model.ts:109-113` (and copied into 4 request types) +- **Why weird:** `objectType` is a free-form `string` typed as values like `"schema"` (JSDoc says "Can be one of the following: schema." — one option in a one-element set is barely an enumeration). The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("the uuid of the request object. For example, schema id."). This is a stringly-typed sum type with one current arm. Five separate types (`QualityMonitor`, `DeleteQualityMonitorRequest`, `GetQualityMonitorRequest`, `UpdateQualityMonitorRequest`, the response of any GET) all duplicate these two fields with copy-pasted JSDoc. +- **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). +- **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string}`. With one arm today, a literal type `objectType: 'schema'` plus `schemaId: string` is enough. +- **Rationale:** TypeScript's strength is exhaustive discriminated unions. Leaving these as `string` defeats the type system and forces every caller to read the JSDoc. The "could be one of: schema" doc text strongly hints that the API team plans to add more arms — the type should be ready for them. + +### 5. `QualityMonitor.objectId` doc text "The uuid of the request object" — `src/v2/model.ts:113` +- **Why weird:** `QualityMonitor` is the response shape too (the GET handler returns it), but the JSDoc says "uuid of the **request** object" — wording that is right only for the request types. Field is also typed `string` with no UUID brand. JSDoc says "For example, schema id" — example-driven docs on a stringly-typed field are a smell. +- **Category:** 6 (misleading — doc refers to request when type is dual-purpose), 19 (underspecified — `Id` says nothing about UUID format). +- **Suggested name:** Doc: "The UUID of the monitored object (e.g. the schema's `schema_id`)." Field: rename to `schemaId` once #4 is applied. +- **Rationale:** Doc-style accuracy and signalling that the value is a UUID. + +### 6. `QualityMonitor.anomalyDetectionConfig` and `QualityMonitor.validityCheckConfigurations` co-existing — `src/v2/model.ts:114-116` +- **Why weird:** `QualityMonitor` has both an `anomalyDetectionConfig?` field and a `validityCheckConfigurations?` field, even though `AnomalyDetectionConfig` already contains its own `validityCheckConfigurations?` (line 40). The same data is reachable two ways: `monitor.anomalyDetectionConfig.validityCheckConfigurations` and `monitor.validityCheckConfigurations`. Either it is duplicated (and one is authoritative — but which?) or the field at the top level overrides the nested one, but the JSDoc says nothing. +- **Category:** 12 (duplicate concept — same array exposed at two levels), 6 (misleading — silently ambiguous). +- **Suggested name:** Document the relationship in JSDoc — clarify which location is authoritative when both are set. +- **Rationale:** A reader cannot tell which one is the source of truth, which one is read-only, or whether both must match. The data model embeds ambiguity that callers have to test by experiment. + +### 7. Enum members `ANOMALY_DETECTION_JOB_TYPE_*` — `src/v2/model.ts:5-9` +- **Why weird:** Enum is called `AnomalyDetectionJobType`, but every member is prefixed `ANOMALY_DETECTION_JOB_TYPE_` — at the call site users write `AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_NORMAL` (6 redundant tokens). +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names), 18 (overly long enum values). +- **Suggested name:** `AnomalyDetectionJobType.{Normal, InternalHidden}` and drop the unset sentinel (rely on `jobType?: ... | undefined`). Or strip just the prefix: `ANOMALY_DETECTION_JOB_TYPE_NORMAL` -> `NORMAL`. +- **Rationale:** TS enums namespace their values, so the `ANOMALY_DETECTION_JOB_TYPE_` prefix is dead context. + +### 8. Enum members `ANOMALY_DETECTION_RUN_STATUS_*` — `src/v2/model.ts:12-21` +- **Why weird:** Eight values, every one prefixed with `ANOMALY_DETECTION_RUN_STATUS_`, including `ANOMALY_DETECTION_RUN_STATUS_WORKSPACE_MISMATCH_ERROR` — a 51-character symbol. Sentinel is `_UNKNOWN` while the sibling enum (`AnomalyDetectionJobType`, #7) uses `_UNSPECIFIED` — inconsistent sentinel naming inside the same file. Also: `_FAILED` and `_WORKSPACE_MISMATCH_ERROR` are both error states with no documented difference. +- **Category:** 2 (redundant prefix), 14 (proto-style), 17 (sentinel inconsistency — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 18 (long enum values), 12 (likely duplicate concept — two error states). +- **Suggested name:** `AnomalyDetectionRunStatus.{Running, Pending, Canceled, Success, Failed, JobDeleted, WorkspaceMismatchError}`. Drop the sentinel. Resolve whether `Failed` and `WorkspaceMismatchError` are siblings or whether the latter is a `Failed` sub-state. +- **Rationale:** Same as #7. Cross-enum sentinel inconsistency will trip users who write `=== AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_UNSPECIFIED` and find that the run-status enum uses `_UNKNOWN` instead. + +### 9. Enum members `THRESHOLD_TYPE_*` — `src/v2/model.ts:23-28` +- **Why weird:** Four-value enum with proto-style `THRESHOLD_TYPE_UNSPECIFIED` / `_AUTO` / `_UNBOUNDED` / `_MANUAL`. The field that uses it is `Threshold.thresholdType` (line 131) — meaning at the call site you'd write `threshold.thresholdType === ThresholdType.THRESHOLD_TYPE_MANUAL` — "threshold" appears four times in the same expression. Also: the enum is *external* to the `Threshold` interface, even though it is used only by that one field, on that one interface — perfect candidate for a string-literal union (`'auto' | 'unbounded' | 'manual'`). +- **Category:** 2 (redundant enum prefix), 14 (proto-style), 18 (long enum values), 20 (type-suffix tautology — `Threshold.thresholdType: ThresholdType`). +- **Suggested name:** Replace the enum with a string-literal union on the field directly: `kind?: 'auto' | 'unbounded' | 'manual'`. Or, if keeping the enum, drop the prefix: `ThresholdType.{Auto, Unbounded, Manual}`. +- **Rationale:** Three-value, locally-used "kind" indicators are exactly where TS string-literal unions excel. + +### 10. `CustomScalarCheck.checkName` / `.sqlQuery` / `.columnMatchers` / `.thresholds` — `src/v2/model.ts:67-76` +- **Why weird:** The type is called `CustomScalarCheck`, but its first field is `checkName` (the type already says "Check"). Same redundancy as `ValidityCheckConfiguration.name` (#12). The four fields are: a name, a SQL query, a list of matchers, and a thresholds object — there is no internal qualifier that justifies `check` on `checkName`. +- **Category:** 8 (redundant suffix — `check` is already in the type name). +- **Suggested name:** `name`, `sqlQuery`, `columnMatchers`, `thresholds`. Or, if the rest of the family follows the pattern, accept and standardise on `check*`. +- **Rationale:** Redundant prefixes are dead context — readers know they are looking at a `CustomScalarCheck` from the type. + +### 11. `ValidityCheckConfiguration` + `PercentNullValidityCheck` / `RangeValidityCheck` / `UniquenessValidityCheck` — `src/v2/model.ts:102-160` +- **Why weird:** Identical to `dataquality` finding #14. Four sibling types all carry the `ValidityCheck` suffix, and the wrapping discriminated-union container type is `ValidityCheckConfiguration` — adding `Configuration` on top of `Check`. The wire-style discriminator names (`percentNullValidityCheck`, etc.) re-state the `ValidityCheck` suffix again. Combined, the path `monitor.validityCheckConfigurations[0].checkType.$case === 'percentNullValidityCheck'` repeats "validity-check" three times within nine identifier-positions. +- **Category:** 8 (redundant suffix), 20 (type-suffix tautology), 18 (effectively-long discriminator strings). +- **Suggested name:** Drop `ValidityCheck` from each arm type -> `PercentNullCheck` / `RangeCheck` / `UniquenessCheck`. Drop `Configuration` from container -> `ValidityCheck` (the container). Discriminator: `kind: 'percentNull' | 'range' | 'uniqueness'`. +- **Rationale:** A `ValidityCheck.kind === 'range'` reads cleanly; the current form is "validity check configuration that has a check type whose case is range validity check" — five repetitions of "check". + +### 12. `ValidityCheckConfiguration.name` JSDoc "Can be set by system. Does not need to be user facing." — `src/v2/model.ts:148-149` +- **Why weird:** A field whose own JSDoc admits it "does not need to be user facing" — yet it is part of the public TS type. The doc is also self-contradictory: "Can be set by system" implies output-only, but the field is plain optional (no `@readonly`). A user reading this has no idea whether to set it, what it does, or whether the server will ignore it. +- **Category:** 1 (vague — `name` is generic), 6 (misleading — output-only not typed as such), 15 (generic field name on a non-public-facing concept). +- **Suggested name:** Rename to `internalName` (matches the JSDoc), or mark with `@readonly` and rename to `systemAssignedName`. +- **Rationale:** Public types should not contain "system-set, not user-facing" fields without clear scoping. + +### 13. `QualityMonitor` field-name irregularity: `anomalyDetectionConfig` (singular `Config`) vs `validityCheckConfigurations` (plural `Configurations`) — `src/v2/model.ts:114,116` +- **Why weird:** The two configuration fields on `QualityMonitor` use different singular/plural forms of "Config(uration)". `anomalyDetectionConfig` is a single object; `validityCheckConfigurations` is an array. The plural form follows from the array shape, but the *word* differs (`Config` vs `Configuration`). A reader scanning the type sees two near-synonyms within three lines. +- **Category:** 17 (inconsistent word choice between sibling fields), 7 (verbose — `Configurations` is longer than necessary). +- **Suggested name:** Pick one: `anomalyDetectionConfig` + `validityCheckConfigs` (both abbreviated), or rename the array to `validityChecks` and the object to `anomalyDetection` (drop the Config suffix entirely — the type names already say "Config"). +- **Rationale:** Inconsistent word forms within the same type lose information. + +## Medium severity + +### 14. `AnomalyDetectionConfig.lastRunId` and `.latestRunStatus` (`Last` vs `Latest`) — `src/v2/model.ts:32,34` +- **Why weird:** Two adjacent fields use different superlative adjectives for the same concept: `lastRunId` and `latestRunStatus`. Both refer to the most recent run. JSDoc reinforces the mismatch: "Run id of the last run of the workflow" and "The status of the last run of the workflow." — same noun, different field-name modifier. +- **Category:** 17 (inconsistent vocabulary), 12 (duplicate concept across siblings). +- **Suggested name:** Pick one. `lastRunId` + `lastRunStatus`, or `latestRunId` + `latestRunStatus`. +- **Rationale:** Sibling fields describing properties of the same entity should use the same word. + +### 15. `AnomalyDetectionConfig.jobType` doc text "The type of the last run of the workflow." — `src/v2/model.ts:36` +- **Why weird:** Field name says `jobType`, doc says "The type of the **last run** of the workflow." That is conflating two things: the type of the workflow/job (a config property) vs the type of the last run (a per-run property). A reader cannot tell which it is. Looking at the enum (`AnomalyDetectionJobType` with `_NORMAL` and `_INTERNAL_HIDDEN`), these look like job classifications, not per-run modes — so the doc is probably wrong. +- **Category:** 6 (misleading — name and doc contradict), 1 (vague — `jobType` could be either). +- **Suggested name:** If this is a workflow-level property: keep `jobType`, fix the doc to "The classification of the anomaly-detection job." If per-run: rename to `lastRunJobType` and keep the doc. +- **Rationale:** Field-name vs doc disagreement forces callers to test by experiment. + +### 16. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v2/model.ts:38` +- **Why weird:** Same as `dataquality` finding #19. "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning. Other Databricks SDK packages use `fullName` consistently for UC three-part names — here the suffix is `FullNames` (plural of FullName), making this the only field that says "full" then "names". +- **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). +- **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or document the format in JSDoc. +- **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary. The field at minimum should be `excludedTableFullyQualifiedNames` for accuracy, or `excludedTables` for brevity. + +### 17. `Threshold.boundValue` JSDoc says "Meaningful only if threshold_type is MANUAL" — `src/v2/model.ts:129-130` +- **Why weird:** Two fields, one of which is meaningful only when the other has a specific value. This is again the discriminated-union pattern modelled as plain optional fields. Reads as: when `thresholdType === MANUAL`, you must provide `boundValue`; when `thresholdType === AUTO` or `UNBOUNDED`, you must not. The type does not encode this. +- **Category:** 6 (misleading — type allows nonsensical combinations), 11 (missing union — should be discriminated). +- **Suggested name:** Model as: `Threshold = {kind: 'auto'} | {kind: 'unbounded'} | {kind: 'manual', value: number}`. +- **Rationale:** Same anti-pattern as `objectType`/`objectId` (#4). Wire-driven shape rather than TS-friendly modelling. + +### 18. `Threshold.thresholdType` — `src/v2/model.ts:131` +- **Why weird:** Type-suffix tautology. `Threshold.thresholdType: ThresholdType` — three "threshold" tokens in one line. Compare with the parallel pattern in `AnomalyDetectionConfig.jobType: AnomalyDetectionJobType` and `validityCheckConfigurations[i].checkType: ...`. Repetition runs throughout the package. +- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). +- **Suggested name:** `kind: ThresholdKind` or `mode: ThresholdMode`. Or, with #9 applied: `kind: 'auto' | 'unbounded' | 'manual'`. +- **Rationale:** "Kind" / "Mode" reads cleanly when a discriminator is required. + +### 19. `CustomScalarCheck.checkName` doc "Name of the custom check" — `src/v2/model.ts:68-69` +- **Why weird:** Field is on `CustomScalarCheck` (already a custom-check); the doc says "Name of the custom check". Both the type name and the doc say "custom check" — but the discriminator `$case: 'scalarCheck'` says "scalar check". The doc is one step abstracted from the actual type — readers see "custom check" and have to map it back to `CustomScalarCheck`. +- **Category:** 8 (redundant suffix — `check` is in the type name), 17 (inconsistent vocabulary — "scalar" vs "custom"). +- **Suggested name:** Field: `name`. Doc: "Name of the scalar check definition." +- **Rationale:** Drop the redundant prefix; align the doc with the actual type name. + +### 20. `CustomScalarCheck.sqlQuery` doc "Templated SQL query for this check" — `src/v2/model.ts:70-71` +- **Why weird:** "Templated" appears in the doc but not the field name — a caller looking at autocomplete sees only `sqlQuery: string` and has no hint that templating syntax is allowed (or expected). The JSDoc carries the only signal. Other SDK packages with templated SQL fields (e.g. `dataquality.CustomMetric.definition`) call them out as Jinja templates explicitly. +- **Category:** 1 (vague — `sqlQuery` undersells the template syntax), 6 (misleading — looks like raw SQL). +- **Suggested name:** `sqlQueryTemplate`, or `templatedSql`, or keep the name and expand the JSDoc to spell out the templating language (Jinja? Mustache? proprietary?). +- **Rationale:** Templates and raw SQL are very different inputs; the type signature should hint at the distinction. + +### 21. `CustomScalarCheck.columnMatchers` and `ColumnMatcher.variableName` — `src/v2/model.ts:43-48,72-73` +- **Why weird:** `ColumnMatcher` is a pair `{variableName, columnNames}`. The JSDoc on `variableName` says "Variable name within a custom sql query that this matcher applies to" — so `variableName` is the template variable from #20. Then `columnNames` is "List of column names (in target tables) to match." So the data flow is: `sqlQuery` references template variables, each `ColumnMatcher` maps one variable to a list of candidate column names. None of this is obvious from the type names alone. `ColumnMatcher.variableName` looks like a TS variable name, not a template placeholder. +- **Category:** 1 (vague — `variableName` could mean many things), 5 (jargon — `Matcher` is itself a generic word). +- **Suggested name:** Rename `ColumnMatcher` -> `TemplateColumnBinding` (or `SqlVariableBinding`). Field `variableName` -> `templateVariable` or `placeholder`. Field `columnNames` -> `candidateColumns`. +- **Rationale:** Template binding is the concept here; the current naming hides it. + +### 22. `CustomCheckThresholds.lowerBound` / `.upperBound` vs `RangeValidityCheck.lowerBound` / `.upperBound` — `src/v2/model.ts:62-64,123-125` +- **Why weird:** Two unrelated types use the same field name pair (`lowerBound`/`upperBound`) for very different things. In `CustomCheckThresholds`, the bounds are `Threshold` objects (i.e. `{boundValue, thresholdType}`). In `RangeValidityCheck`, the bounds are `number`. Same field name, different types — a reader pattern-matching on `lowerBound` cannot rely on it being a number anywhere. +- **Category:** 17 (inconsistent type for identical field name), 15 (generic field name — `lowerBound` of what?). +- **Suggested name:** `CustomCheckThresholds.lower: Threshold` + `.upper: Threshold` (drop `Bound` since `Threshold` is the type). `RangeValidityCheck.lowerBound: number` + `.upperBound: number` (keep). +- **Rationale:** Identical field names across sibling types should imply identical semantics. Differentiate the threshold-wrapping case by dropping `Bound`. + +### 23. `PercentNullValidityCheck.upperBound` doc "Optional upper bound; we should use auto determined bounds for now" — `src/v2/model.ts:105-106` +- **Why weird:** Doc text reads like an internal TODO ("we should use auto determined bounds for now"). The "we" is the API team; "for now" implies the field's semantics are in flux. Public SDK documentation should be definitive, not provisional. Also: field is typed `number` with no unit hint — is this 0-100 or 0-1? +- **Category:** 6 (misleading — provisional doc text in a stable type), 1 (vague — `upperBound` of what units? percentage? fraction?). +- **Suggested name:** Field stays; doc should clarify units ("Optional upper bound on the null-percentage (0-100). If unset, the server auto-determines a bound."). Strip the internal TODO. +- **Rationale:** Doc-style cleanliness and unit precision. + +### 24. `PercentNullValidityCheck.columnNames` (and `RangeValidityCheck.columnNames`, `UniquenessValidityCheck.columnNames`) — `src/v2/model.ts:103,120,135` +- **Why weird:** Three sibling check types each have an independent `columnNames: string[]` field with the same shape and meaning ("the columns to check"). Each carries its own near-identical JSDoc. The three checks could share a base type or a single field, but the wire-driven type model duplicates them. +- **Category:** 12 (duplicate concept across siblings). +- **Suggested name:** Either extract a `BaseValidityCheck { columnNames: string[] }` parent, or accept the duplication (one-line JSDoc each). Generator-emitted. +- **Rationale:** DRY at the type level; per-arm doc cost is small. + +### 25. Method `listQualityMonitor` doc text "(Unimplemented) List quality monitors." — `src/v2/client.ts:150,203` +- **Why weird:** The method is implemented (has a complete body that constructs a URL, paginates, calls the server) — but the JSDoc literally says `(Unimplemented)`. Either (a) the server side is unimplemented and the doc is propagating a server-side TODO, or (b) this is a stale doc from when the method was a stub. Same comment appears on `updateQualityMonitor` (line 203-204: "(Unimplemented) Update a quality monitor on UC object.") — but the body of `updateQualityMonitor` is a complete `PUT` call. +- **Category:** 6 (misleading — body says implemented, doc says unimplemented). +- **Suggested name:** N/A. Fix the doc — either drop "(Unimplemented)" or move it to a server-side `@throws NotImplemented` annotation. +- **Rationale:** Method docs that lie about implementation status are worse than no docs. + +### 26. `listQualityMonitor` parameter is non-optional, but `req` is empty in normal use — `src/v2/client.ts:152-154` +- **Why weird:** `listQualityMonitor(req: ListQualityMonitorRequest, options?: CallOptions)` requires the caller to pass `req` even when they want all defaults. `ListQualityMonitorRequest` is `{pageToken?, pageSize?}` — both optional. So the only "no special args" call is `listQualityMonitor({})` — an empty object placeholder. The paginator wrapper (`listQualityMonitorIter`) has the same shape. +- **Category:** 6 (misleading — looks like there's a required input but there isn't). +- **Suggested name:** Make `req?: ListQualityMonitorRequest` optional: `listQualityMonitor(req?: ListQualityMonitorRequest, options?: CallOptions)`. Same for the iterator. +- **Rationale:** Optionality on the wire should match optionality at the TS surface. Generator-wide concern. + +### 27. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,202` +- **Why weird:** Every method JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (...)` — but the TS-standard JSDoc tag is `@deprecated`. The text is in the description body, not in the tag, so IDEs that read `@deprecated` (VS Code, TS LSP) will not strike through these methods or warn the user. The deprecation is documented but not enforced. +- **Category:** 14 (Go-style — Go doc comments use a leading word like "Deprecated:" by convention; TS uses `@deprecated`), 6 (misleading — looks deprecated but does not surface as deprecated in tooling). +- **Suggested name:** Use `@deprecated Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` so IDE tooling strikes through call sites. +- **Rationale:** A whole package marked deprecated should advertise the deprecation through TS conventions, not Go conventions. + +### 28. Method names `createQualityMonitor` / `deleteQualityMonitor` / `getQualityMonitor` / `listQualityMonitor` / `updateQualityMonitor` — `src/v2/client.ts:70,102,124,152,206` +- **Why weird:** Five methods, all of which repeat "QualityMonitor" in the name even though they are members of a `Client` class whose package (`qualitymonitor`) already encodes that domain. Compare with sister packages where methods are `create` / `get` / `delete` / `list` (verbs only). The "QualityMonitor" suffix is dead context — calling `client.createQualityMonitor(...)` from a package literally called `qualitymonitor` is reading the noun twice. +- **Category:** 7 (overly verbose), 8 (redundant suffix). +- **Suggested name:** `create` / `delete` / `get` / `list` / `update` (drop the noun). With `listIter` as the paginator. +- **Rationale:** When the class is `Client` and the package is `qualitymonitor`, the only entity to act on is the quality monitor; the noun adds no signal. + +### 29. `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` — `src/v2/model.ts:139-145` +- **Why weird:** Three top-level fields where the relationship is implicit. The `objectType`/`objectId` pair identifies the target (also redundant with `qualityMonitor.objectType`/`qualityMonitor.objectId`). The `qualityMonitor` field carries the new state — including its own `objectType`/`objectId`. So the same identifiers are present twice on the request. Per the URL builder, only the top-level `req.objectType` and `req.objectId` are used to construct the path; the values inside `qualityMonitor` are sent in the body. Nothing checks that they match. +- **Category:** 12 (duplicate concept — identifiers at two levels), 6 (misleading — silent overwriting possibility). +- **Suggested name:** Either: (a) move identifiers entirely to the nested `qualityMonitor` (server reads them from the body and the path is derived from the body in TS land), or (b) move identifiers entirely to top-level and let `qualityMonitor` be just the mutable fields. +- **Rationale:** Same identifier surfaced twice on the same request is an invitation to bugs. + +### 30. `marshalQualityMonitorSchema` and 9 other `marshal*Schema` / `unmarshal*Schema` names — `src/v2/model.ts:163-512` +- **Why weird:** Generator-emitted Zod schemas all carry the awkward double-`Schema` suffix at the call site (`z.lazy(() => unmarshalQualityMonitorSchema)`) — "lazy unmarshal Quality Monitor Schema" reads as four nouns. Same as `dataquality` finding #47. +- **Category:** 14 (Go-style), 17 (verb-naming mismatch with Zod's own `parse`). +- **Suggested name:** `encodeQualityMonitor` / `decodeQualityMonitor`. +- **Rationale:** Generator-wide. + +## Low severity + +### 31. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` +- **Why weird:** Exported helper that is never called from `client.ts`. The package's one list endpoint handles pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. Same as `dataquality` finding #35. +- **Category:** 6 (misleading — looks like it's used; isn't). +- **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). +- **Rationale:** Same as other audited packages. + +### 32. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` +- **Why weird:** Layering not visible from names; identical to `dataquality` finding #36. +- **Category:** 1, 12, 17. +- **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). +- **Rationale:** Layering should be readable from the names without opening the source. + +### 33. `buildHttpRequest` — `src/v2/utils.ts:96` +- **Why weird:** Same as `dataquality` finding #37; "build" suggests builder pattern, the function spreads literals. +- **Category:** 1, 6. +- **Suggested name:** `makeHttpRequest`. +- **Rationale:** "Make" matches the simpler reality. + +### 34. `marshalRequest` and `parseResponse` — `src/v2/utils.ts:113,119` +- **Why weird:** Names imply request/response but the functions work on any payload + schema; identical to `dataquality` findings. +- **Category:** 1, 6. +- **Suggested name:** `encodeToJson` / `decodeFromJson`. +- **Rationale:** Symmetric verb pair removes the "Request"/"Response" mis-promise. + +### 35. `readAll` — `src/v2/utils.ts:40` +- **Why weird:** Identical to `dataquality` finding #39; "readAll" does not say "drain a stream". +- **Category:** 1, 5. +- **Suggested name:** `drainStream`. +- **Rationale:** Self-describing name. + +### 36. `HttpCallOptions` — `src/v2/utils.ts:15` +- **Why weird:** Same as `dataquality` finding #40; internal context bag called `Options`. +- **Category:** 1, 8. +- **Suggested name:** `HttpCallContext`. +- **Rationale:** Reserve `Options` for user-tunable knobs. + +### 37. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` +- **Why weird:** Same as `dataquality` finding #41; unspecific noun for a User-Agent identity object. +- **Category:** 1. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Add the missing domain word. + +### 38. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` +- **Why weird:** Same as `dataquality` finding #42; variable named `call` of type `Call` repeated 5 times across the client. +- **Category:** 1, 12. +- **Suggested name:** `request` (variable) — reserve `Call` for the type. +- **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. + +### 39. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` +- **Why weird:** Same as `dataquality` finding #43 — `objectType`/`objectId` typed optional but required in practice for the URL path. Silently substitutes empty string producing malformed URLs like `/api/2.0/quality-monitors//`. Three call sites here. +- **Category:** 6. +- **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. +- **Rationale:** Type shape should match runtime requirement. + +### 40. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 218-231` +- **Why weird:** Same as `dataquality` finding #44; two variables differ by `Body` only. +- **Category:** 5, 17. +- **Suggested name:** `rawBody` + `result`. +- **Rationale:** Distinguish by meaningful nouns. + +### 41. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` +- **Why weird:** Same as `dataquality` finding #45. +- **Category:** 5, 12. +- **Suggested name:** `httpRequest` (no abbreviation). +- **Rationale:** Avoid two `req`-rooted identifiers in the same scope. + +## Observations + +### 42. Heavy boilerplate dominates the file +`model.ts` is 512 lines for **15 user-facing types and 3 enums**; **350 lines (~68%)** are `marshal*` / `unmarshal*` Zod scaffolding. Higher boilerplate-to-content ratio than `dataquality` (~46%) because this package has fewer types but the same generator overhead per type. + +### 43. Action verbs in `Client` +The client uses `Create` / `Get` / `Update` / `Delete` / `List` for monitor operations. Verbs are consistent within the package. Listed per rule 17 to note the absence of inconsistency (relative to `qualitymonitors` plural, which adds `Cancel` / `Run` / `Regenerate`). + +### 44. Acronym casing +Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `lastRunId`), `URL` (only via the web-standard `URLSearchParams`), `Sql` (capital-then-lower in `sqlQuery`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`). No within-package collisions. +- **Category:** 3 (acronym casing). + +### 45. No `wkt` (well-known types), `FieldMask`, or `time` imports +Unlike `dataquality` and other newer packages, this package has no `Timestamp`, `FieldMask`, or `Duration` fields. The lack of these is consistent with the package being older and frozen (deprecated) — newer features were added to `dataquality` instead. + +### 46. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types +Same shape as the `dataquality` casing observation: directory is one collapsed word (`qualitymonitor`), wire path is kebab-plural (`/quality-monitors`), TS types are PascalCase singular (`QualityMonitor`). The directory plural-vs-singular question (relative to `qualitymonitors`) is unique to this package family. +- **Category:** 3 (casing inconsistency), 9 (singular/plural mismatch). + +### 47. Entire package is `@deprecated` per JSDoc +Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#27), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. + +## Domain glossary +- `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema). +- `quality monitor` — the long-lived configuration entity (one per UC schema) holding anomaly-detection config and validity checks. +- `anomaly detection` — periodic workflow that compares incoming data against historical patterns to flag anomalies. +- `validity check` — an input-data constraint (null %, range, uniqueness) evaluated during anomaly detection. +- `custom scalar check` — a templated SQL query that produces a single value, compared against per-column thresholds. +- `column matcher` — a binding from a template variable in the SQL query to a list of candidate column names. +- `threshold` — a `{boundValue, thresholdType}` pair where `thresholdType ∈ {AUTO, UNBOUNDED, MANUAL}` and `boundValue` is meaningful only when type is `MANUAL`. +- `job type` — classifies an anomaly-detection job as `NORMAL` or `INTERNAL_HIDDEN`. +- `run status` — eight-value lifecycle: `RUNNING`, `PENDING`, `CANCELED`, `SUCCESS`, `FAILED`, `JOB_DELETED`, `WORKSPACE_MISMATCH_ERROR` (+ sentinel `UNKNOWN`). +- `object type` / `object id` — stringly-typed reference to a UC object (currently always a schema). +- `refresh`, `monitor cron schedule`, `dashboard`, `notifications`, `data classification config` — none of these appear in this package; they all live in the sibling `qualitymonitors` (plural, v1) package. + +## File coverage +- `src/v2/model.ts` (512 lines): read fully. +- `src/v2/client.ts` (233 lines): read fully. +- `src/v2/utils.ts` (150 lines): read fully. +- `src/v2/index.ts` (29 lines): read fully. diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md new file mode 100644 index 00000000..4ec1dd42 --- /dev/null +++ b/.agent/naming-audit/qualitymonitors.md @@ -0,0 +1,375 @@ +# Naming Audit: qualitymonitors + +**Path:** `packages/qualitymonitors/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Lakehouse Monitoring on Unity Catalog tables (legacy/deprecated surface). The package models a `Monitor` per UC table with an `analysisConfig` chosen from `InferenceLog` / `TimeSeries` / `Snapshot`, scheduled refreshes (`Cancel` / `Get` / `List` / `Run`), Quartz cron scheduling, custom metric definitions (`Aggregate`/`Derived`/`Drift`), data classification toggles, dashboard regeneration, and notification routing on failure and on new classification tags. **Every** client method JSDoc starts with "Deprecated: Use Data Quality Monitors API instead (/api/data-quality/v1/monitors)" — this entire package is a deprecated wire-compatible facade for the `dataquality` package. +**Total weird names flagged:** 52 + +## CRITICAL: TWO co-existing packages with the same domain + +Three packages in this repository overlap on the same domain at the wire level: + +| Package directory | npm name | Version(s) | Wire path | Resource type | Domain object | +| --- | --- | --- | --- | --- | --- | +| `qualitymonitors` (plural, **this audit**) | `@databricks/sdk-qualitymonitors` | v1 | `/api/2.1/unity-catalog/tables/{name}/monitor` and `/api/2.1/quality-monitoring/...` | `DataMonitorInfo` | `Monitor` (per UC table) | +| `qualitymonitor` (singular) | `@databricks/sdk-qualitymonitor` | v2 | undetermined (anomaly-detection oriented) | `QualityMonitor` | `QualityMonitor` (per UC schema, anomaly detection) | +| `dataquality` | `@databricks/sdk-dataquality` | v1 | `/api/data-quality/v1/monitors` | `Monitor` | `Monitor` (per UC schema or table, both flavours) | + +**Why this matters:** + +1. **Singular/plural mismatch between packages.** Every other package in this repo (e.g. `apps`, `alerts`, `clusters`, `jobs`) uses plural for the package name. The fact that we have *both* `qualitymonitor` and `qualitymonitors` co-existing is a violation of any consistent convention. One of them is wrong. (Audit-rule category 9: singular/plural mismatch at the package level.) +2. **Domain duplication.** `dataquality` is documented in its own client JSDoc as the *replacement* for `qualitymonitors`. Both packages are exported to users today. A consumer of the SDK who installs `@databricks/sdk-qualitymonitors` and `@databricks/sdk-dataquality` gets two `Client` classes for the same domain with subtly different shapes. +3. **Three names for the "monitor" entity in three sibling packages.** `qualitymonitors.DataMonitorInfo`, `qualitymonitor.QualityMonitor`, `dataquality.Monitor`. The same wire concept (a monitor on a UC table) is named three different ways across the SDK. (Audit-rule category 12: duplicate concept, surfaced across packages.) +4. **All client methods in this package carry a "Deprecated" prefix in their JSDoc.** Yet the package is shipped, exported from `index.ts`, and has its own client class — a deprecation marker in the doc string is not a TypeScript-level deprecation. There is no `@deprecated` JSDoc tag, so editors will not flag usage. + +**Recommendation:** Decide on one package name and merge / dual-publish. Rename `qualitymonitors` → either retired (and `dataquality` becomes the sole source of truth) or renamed to `qualitymonitorslegacy`. The current state is the worst of all worlds: two near-identical packages with names that differ by a single letter, neither flagged as deprecated at the TS level. + +## Summary +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 21 | +| Low | 11 | +| Observation | 7 | + +## High severity + +### 1. Package name `qualitymonitors` collides with sibling `qualitymonitor` (singular) +- **Why weird:** Two npm packages, `@databricks/sdk-qualitymonitors` and `@databricks/sdk-qualitymonitor`, both ship from this repository, on different versions (v1 vs v2), differing by one trailing `s`. The two packages handle overlapping wire surfaces (this one targets UC tables; the singular targets UC schemas with anomaly detection). A package consumer scanning npm sees two near-identical names with no human-readable cue as to which to pick. +- **Category:** 9 (singular/plural mismatch — at the package boundary), 12 (duplicate concept). +- **Suggested name:** Pick one (`qualitymonitor` or `qualitymonitors`) and consolidate. If both must remain, rename this one to `qualitymonitorslegacy` to make the deprecation visible at the package boundary. +- **Rationale:** Package-level naming is the first cue a user gets. Singular vs plural in two npm names is a UX trap. + +### 2. `DataMonitorInfo` — `src/v1/model.ts:213` +- **Why weird:** The package's central response type is named `DataMonitorInfo`, but no other type in the package uses the `Data` prefix. The companion request types are `CreateMonitor`, `UpdateMonitor`, `DeleteMonitor`, `GetMonitor` — all plain `Monitor`. The response alone is `DataMonitorInfo`, with `Data` and `Info` as filler. The `Info` suffix is Go-style ("XYZInfo" is a Go idiom for "details of an XYZ"). +- **Category:** 1 (vague — `Data` and `Info` are noise), 8 (redundant suffix — `Info`), 14 (Go-style naming), 17 (inconsistent — every other type in the package uses `Monitor`, only this one uses `DataMonitorInfo`), 20 (type-suffix tautology — `Info` adds no semantic content). +- **Suggested name:** `Monitor`. +- **Rationale:** Every API in the client (`createMonitor`, `getMonitor`, `updateMonitor`) returns this type. Naming it `Monitor` aligns with the API verbs and with the sister `dataquality` package which already calls it `Monitor`. The `Data` and `Info` syllables are dead context. + +### 3. `Client` class — `src/v1/client.ts:57` +- **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing two SDK packages (e.g., `@databricks/sdk-qualitymonitors` and `@databricks/sdk-dataquality`) cannot import both as `Client` without aliasing. There is no domain word in the name. The same problem exists across the entire generator and is called out in every audit, but it is especially acute here because two packages with similar names ship the same class name. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). +- **Suggested name:** `QualityMonitorsClient` (or, after consolidation per #1, `QualityMonitorClient`). +- **Rationale:** Cross-package import collisions force users to alias. + +### 4. `fullTableNameArg` field — `src/v1/model.ts:95,107,286,302,307,334,379,399,423` +- **Why weird:** The field name carries the `_Arg` suffix which is a generator artefact — the doc clarifies "This field corresponds to the {full_table_name_arg} arg in the endpoint path." `Arg` is a Go/proto convention for "this is a URL path parameter, not a body field." In TS the body/path distinction is invisible to the caller; the suffix leaks the wire model. The same field appears identically in 9 of the 13 request types in the package, copy-pasted with the same JSDoc. +- **Category:** 5 (cryptic abbreviation — `Arg` for "argument"), 14 (Go/proto-style suffix that leaks wire details), 15 (generic naming via `Arg`). +- **Suggested name:** `tableFullName` (matches the rest of the SDK's UC fully-qualified name convention; e.g. `dataquality.AnomalyDetectionConfig.excludedTableFullNames`). +- **Rationale:** The `Arg` suffix advertises a wire artefact that has zero meaning at the TypeScript boundary. `tableFullName` is the established UC vocabulary across the SDK for three-part `catalog.schema.table` references. + +### 5. `CustomMetricType` enum members `CUSTOM_METRIC_TYPE_*` — `src/v1/model.ts:14-19` +- **Why weird:** Five-token names per member, with the enum name re-stated as a prefix on every value. At the call site you write `CustomMetricType.CUSTOM_METRIC_TYPE_AGGREGATE` — three repetitions of "custom metric type" before getting to the discriminating word (`AGGREGATE`). Also: the enum has an `_UNSPECIFIED` zero value carried over from protobuf that has no real-world meaning in TS (an unset value is already represented by `undefined`). +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names), 18 (overly long enum values). +- **Suggested name:** `CustomMetricType.{Aggregate, Derived, Drift}` (drop the prefix and the `_UNSPECIFIED` sentinel; rely on `type?: CustomMetricType | undefined`). +- **Rationale:** TS enums already namespace values via the enum name. The wire string can remain `CUSTOM_METRIC_TYPE_AGGREGATE` (kept in the `z.enum(...)` literal) while the TS-side name is short. Same pattern is recommended in every other audited package (cf. `dataquality` #6). + +### 6. `MonitorStatus` enum members `MONITOR_STATUS_*` — `src/v1/model.ts:21-28` +- **Why weird:** Same pattern as #5 — four-token names where the enum name already provides the namespace. `MonitorStatus.MONITOR_STATUS_DELETE_PENDING` reads as "monitor status monitor status delete pending". Also: this enum has both `MONITOR_STATUS_ERROR` and `MONITOR_STATUS_FAILED` — two terminal failure values where the difference is unclear (the same pattern flagged in `dataquality.DataProfilingStatus`). +- **Category:** 2 (redundant enum prefix), 12 (duplicate concept — `ERROR` vs `FAILED`), 14 (proto-style), 18 (overly long enum values). +- **Suggested name:** `MonitorStatus.{Active, Pending, PendingDelete, Error, Failed}` (and ideally collapse `Error` and `Failed` to one value). +- **Rationale:** Same as #5. The `ERROR`/`FAILED` ambiguity is a separate concern called out in JSDoc nowhere. + +### 7. `ProblemType` enum members `PROBLEM_TYPE_*` — `src/v1/model.ts:30-34` +- **Why weird:** Same pattern as #5/#6. Three values, all carrying the redundant prefix; also includes the `_UNSPECIFIED` zero value. Also: `ProblemType` is a generic name for "what kind of ML problem is this table's data about". Without the JSDoc on `InferenceLogAnalysisConfig.problemType` ("Problem type the model aims to solve"), the reader cannot tell that `ProblemType` is ML-specific (vs the more general English meaning of "problem"). +- **Category:** 1 (vague — `ProblemType` is generic), 2 (redundant prefix), 14 (proto-style), 18 (long values). +- **Suggested name:** `MlProblemType.{Classification, Regression}` or `InferenceProblemType.{Classification, Regression}` (matches `dataquality.InferenceProblemType`). +- **Rationale:** Sibling package `dataquality` already uses `InferenceProblemType`; this package should match. The generic `ProblemType` could mean anything outside ML. + +### 8. `RefreshState` enum + sentinel `UNKNOWN` vs `_UNSPECIFIED` elsewhere — `src/v1/model.ts:37-66` +- **Why weird:** `RefreshState` uses unprefixed values (`PENDING`, `RUNNING`, `SUCCESS`, `FAILED`, `CANCELED`) plus `UNKNOWN` — which is *inconsistent* with the prefix-everywhere style used by `CustomMetricType`, `MonitorStatus`, `ProblemType`, and `SchedulePauseStatus` in the same file. Three flavors of "unset" sentinel coexist in this one file: `_UNSPECIFIED` (3 enums), `UNKNOWN` (1 enum, this one), `UNKNOWN_TRIGGER` (1 enum, `RefreshTrigger`). +- **Category:** 17 (inconsistent sentinel naming across sibling enums). +- **Suggested name:** Pick one sentinel name and apply uniformly. The `dataquality` audit suggests dropping all `_UNSPECIFIED` / `UNKNOWN` zero values and relying on `state?: RefreshState | undefined`. If kept, normalise to `_UNSPECIFIED` everywhere or `Unknown` everywhere. +- **Rationale:** A user writing `if (refresh.state === RefreshState.UNKNOWN)` and `if (refresh.trigger === RefreshTrigger.UNKNOWN_TRIGGER)` in the same code block has to remember that the second has a suffix and the first does not. + +### 9. `RefreshTrigger.UNKNOWN_TRIGGER` — `src/v1/model.ts:73` +- **Why weird:** The "unset" sentinel is uniquely named `UNKNOWN_TRIGGER` (with the `_TRIGGER` suffix), while sibling `RefreshState` uses `UNKNOWN` (no suffix). Inside the namespace of the enum the suffix is redundant; outside the namespace it does not appear. Result: three different unset-sentinel conventions in this one file (`_UNSPECIFIED`, `UNKNOWN`, `UNKNOWN_TRIGGER`). +- **Category:** 2 (redundant enum prefix on a sentinel), 17 (inconsistent sentinels). +- **Suggested name:** `Unknown` (or drop sentinel — see #8). +- **Rationale:** Same as #8. + +### 10. `SchedulePauseStatus` — `src/v1/model.ts:84-88` +- **Why weird:** Three-value enum (`UNSPECIFIED`, `UNPAUSED`, `PAUSED`) for a binary on/off concept. Sibling `dataquality.CronSchedulePauseStatus` has the same shape and was flagged there. Boolean would suffice. Also: the `UNSPECIFIED` sentinel has no clear semantics (is a schedule with `pauseStatus = UNSPECIFIED` running or stopped?). +- **Category:** 2 (redundant prefix), 11 (trivial enum where boolean would suffice), 18 (long values). +- **Suggested name:** Collapse to `paused?: boolean` on `MonitorCronSchedule`, or rename to `PauseStatus.{Paused, Unpaused}`. +- **Rationale:** "Paused" is binary. Other packages (`jobs`, `alerts`) already use `paused: boolean`. + +### 11. `CancelRefresh_Response` / `DeleteMonitor_Response` / `ListRefreshes_Response` / `RegenerateDashboard_Response` — `src/v1/model.ts:100,290,338,388` +- **Why weird:** Four interfaces use the `_` underscore separator in their identifier (`CancelRefresh_Response`). The eslint comments on each (`@typescript-eslint/naming-convention`) confirm that this style violates the project's own naming rules and is whitelisted only because the proto generator emits "nested message" names this way. In TS, underscores in PascalCase identifiers are wrong — the convention is camelCase/PascalCase, no separators. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style "nested message" names). +- **Suggested name:** `CancelRefreshResponse` / `DeleteMonitorResponse` / `ListRefreshesResponse` / `RegenerateDashboardResponse`. +- **Rationale:** The eslint disable comment is a smoking gun that the names violate the project's own rules. Sister packages (e.g., `dataquality`) use unsuffixed PascalCase like `CancelRefreshResponse`. + +### 12. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` +- **Why weird:** Same shape as `dataquality.DataProfilingConfig.analysisConfig` (audit #10 in that package). The field is named `analysisConfig`, but its arms are types named `InferenceLogAnalysisConfig`, `TimeSeriesAnalysisConfig`, `SnapshotAnalysisConfig` — three names ending in `AnalysisConfig`. The discriminator is `$case`, the arm key matches the arm payload type's prefix (e.g., `inferenceLog` for `InferenceLogAnalysisConfig`). Naming the variants `$case` is a ts-proto convention foreign to TypeScript culture; the more idiomatic discriminator is `kind` or `type`. +- **Category:** 1 (vague — `$case` is unusual TS), 12 (duplicate concept — `AnalysisConfig` repeated 3 times), 14 (ts-proto-style discriminator), 20 (type-suffix tautology — `AnalysisConfig` on every arm). +- **Suggested name:** Field name: `analysis`. Discriminator: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. Arm payloads: keep `InferenceLogAnalysisConfig` or rename to `InferenceLogAnalysis` / `TimeSeriesAnalysis` / `SnapshotAnalysis`. +- **Rationale:** `$case` is a ts-proto idiom; in idiomatic TS you write `if (config.analysis.kind === 'inferenceLog')`, not `if (config.analysisConfig?.$case === 'inferenceLog')`. + +### 13. `CreateMonitor`, `UpdateMonitor`, `DataMonitorInfo` carry **17 duplicated fields** — `src/v1/model.ts:102-180,213-279,418-489` +- **Why weird:** Three types share a 17-field overlap (outputSchemaName, assetsDir, analysisConfig, slicingExprs, customMetrics, baselineTableName, schedule, notifications, dataClassificationConfig, tableName, status, latestMonitorFailureMsg, profileMetricsTableName, driftMetricsTableName, dashboardId, monitorVersion, fullTableNameArg). Each is copy-pasted with the same JSDoc and the same `[Create:REQ Update:REQ]`-style annotation in the comment. The "annotation in the comment" tells the reader which fields are required at create vs update vs read — but is never enforced by the type system. +- **Category:** 6 (misleading — type says optional, semantics say required-at-create), 7 (overly verbose — three nearly-identical types where one with a generic param could do). +- **Suggested name:** One `Monitor` interface for the read shape; `CreateMonitor` and `UpdateMonitor` carry only their differences (e.g., `CreateMonitor` has the input-only `skipBuiltinDashboard` and `warehouseId`). Or use TypeScript's `Pick`/`Omit`/`Partial` to derive types from a base. Encode `[Create:REQ Update:IGN]` in the type system (not the doc): non-optional in `CreateMonitor`, omitted in `UpdateMonitor`. +- **Rationale:** The current state is a maintenance hazard — adding a field requires editing three places. Worse, the wire-side `[Create:REQ ...]` semantics live only in comments. + +## Medium severity + +### 14. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitor`) +- **Why weird:** Every field on `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo` has a prefix annotation in its JSDoc — `[Create:REQ Update:REQ]`, `[Create:OPT Update:OPT]`, `[Create:ERR Update:IGN]` — that encodes per-operation requirement semantics in the comment. These are generator markers, not human-friendly. A user opening the JSDoc tooltip sees `[Create:ERR Update:IGN]` and must decode "ERR means errors if you pass this, IGN means it's ignored on update". The TypeScript type does not enforce any of this. +- **Category:** 6 (misleading — comment marker pretends to be authoritative but is not enforced), 14 (Go/proto-style annotation), 18 (long, noisy comment prefix). +- **Suggested name:** Remove the markers from comments. Encode the semantics in the type (separate `CreateMonitor` vs `UpdateMonitor` vs `Monitor` types with the right optionality and field presence). +- **Rationale:** Doc markers are not type-checked. They look like type annotations but are inert. + +### 15. `latestMonitorFailureMsg` — `src/v1/model.ts:164,263,473` +- **Why weird:** Three problems in one field name. (a) `Msg` is an abbreviation for `Message` — sister field on `RefreshInfo` is `message` (full word), and `dataquality.DataProfilingConfig` uses `latestMonitorFailureMessage` (full word). Inconsistency within the SDK. (b) `Monitor` is in the path — `monitor.latestMonitorFailureMsg` repeats "monitor". (c) The field is documented as `[Create:ERR Update:IGN]` (read-only, server-populated), but the type does not mark it. +- **Category:** 5 (cryptic abbreviation — `Msg`), 7 (overly verbose), 8 (redundant `Monitor` in path), 17 (inconsistent with sibling `message` and with `dataquality`). +- **Suggested name:** `latestFailureMessage`. +- **Rationale:** Full word, no redundant prefix; matches `dataquality`. + +### 16. `profileMetricsTableName` and `driftMetricsTableName` — `src/v1/model.ts:166,168,265,267,475,477` +- **Why weird:** Pair of fields with the suffix `TableName`. Sibling Zod field is `profile_metrics_table_name` — six tokens on the wire. JSDoc on both: identical except for the leading noun. The naming pattern is consistent within the pair but verbose. Compare with `dataquality.DataProfilingConfig.{profileMetricsTableName, driftMetricsTableName}` (same names — at least consistent across packages). +- **Category:** 7 (overly verbose). +- **Suggested name:** `profileMetricsTable` / `driftMetricsTable` (drop `Name` — these are reference fields, not column names). +- **Rationale:** "Table" is sufficient context. + +### 17. `outputSchemaName` field — `src/v1/model.ts:116,215,425` +- **Why weird:** JSDoc says "Schema where output tables are created. Needs to be in 2-level format `{catalog}.{schema}`." So `outputSchemaName` is a two-part UC reference, not just a name. Sister field `baselineTableName` is a three-part UC reference; `tableName` is also three-part. The naming gives no cue about which "name" shape applies. +- **Category:** 19 (underspecified — name vs full name vs two-part), 15 (generic name). +- **Suggested name:** `outputSchemaFullName` (matches UC vocabulary; the value is `catalog.schema`). +- **Rationale:** The "Name" suffix is ambiguous in UC contexts where the term `FullName` is reserved for fully qualified references. + +### 18. `assetsDir` — `src/v1/model.ts:121,220,430` +- **Why weird:** Identical to `dataquality.DataProfilingConfig.assetsDir` (audit #12 in that package). `assets` is generic ("which assets?"), and `Dir` is an abbreviation. JSDoc says "absolute path to a custom directory to store data-monitoring assets". +- **Category:** 1 (vague), 5 (cryptic abbreviation — `Dir`). +- **Suggested name:** `assetsDirectory` or `monitoringAssetsPath`. +- **Rationale:** Same as `dataquality` #12. + +### 19. `slicingExprs` — `src/v1/model.ts:144,243,453` +- **Why weird:** Identical to `dataquality.DataProfilingConfig.slicingExprs` (audit #25 in that package). `Exprs` truncates "Expressions". +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `slicingExpressions` (or, for clarity, `columnSlicingExpressions`). +- **Rationale:** Same as `dataquality` #25. + +### 20. `skipBuiltinDashboard` (negative boolean) — `src/v1/model.ts:109` +- **Why weird:** Same pattern as `dataquality.DataProfilingConfig.skipBuiltinDashboard` (audit #11 in that package). Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. +- **Category:** 6 (misleading), 13 (verb-tense — `skip` is action-y, field is state-y). +- **Suggested name:** `disableBuiltinDashboard` or invert to `createBuiltinDashboard: boolean`. +- **Rationale:** Same as `dataquality` #11. + +### 21. `baselineTableName` — `src/v1/model.ts:152,251,461` +- **Why weird:** A three-part UC reference (per JSDoc: "Baseline table name") but the name says only `Name`. Same shape concern as #17. +- **Category:** 19 (underspecified ID — wire-side three-part name, not flagged as such). +- **Suggested name:** `baselineTableFullName`. +- **Rationale:** UC vocabulary uses `FullName` for three-part references. + +### 22. `tableName` — `src/v1/model.ts:160,259,469` +- **Why weird:** Three-part UC reference per JSDoc ("UC table to monitor. Format: `catalog.schema.table_name`"), but the name says only `Name`. Compare with `fullTableNameArg` on the same types — *two* fields representing essentially the same UC table reference, one called `tableName` (`[Create:ERR Update:IGN]`) and one called `fullTableNameArg` (the URL path param). This is the same data appearing under two field names in the same interface. +- **Category:** 12 (duplicate concept — two fields for the same table reference), 19 (underspecified — three-part wire format hidden behind `Name`). +- **Suggested name:** Drop one of the two. If `tableName` (the body field) is truly read-only and copied from the URL path, remove it. Otherwise, rename to `tableFullName`. +- **Rationale:** Having both `tableName` and `fullTableNameArg` in the same type forces a caller to choose which to populate. + +### 23. `dashboardId` is read-only at create, optional at update — `src/v1/model.ts:173,272,482` +- **Why weird:** JSDoc reads `[Create:ERR Update:OPT]`, meaning the field errors if set on create but is optional on update. Type marks both as optional. A caller writing `createMonitor({dashboardId: 'x', ...})` gets a runtime error from the API but no type-time signal. Same pattern as #14 in general; called out separately because `dashboardId` is one of the most likely fields to be mistakenly set. +- **Category:** 6 (misleading optionality). +- **Suggested name:** Move `dashboardId` out of `CreateMonitor` entirely. Keep in `UpdateMonitor` and `DataMonitorInfo`. +- **Rationale:** Type-level enforcement of "ERR" semantics. + +### 24. `monitorVersion: number` — `src/v1/model.ts:179,278,488` +- **Why weird:** Field name says "monitor version" but on a type called `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo`, the `monitor` part is dead context. JSDoc also notes the field "has flexibility to take on negative values, which can indicate corrupted monitor_version numbers" — using a magic-value (negative) to indicate corruption is a code smell (the type should be `number | 'corrupted'` or split into `version: number` + `corrupted: boolean`). +- **Category:** 7 (overly verbose — `monitor` in path), 6 (misleading — magic-value encoding of corruption state). +- **Suggested name:** `version: number`. +- **Rationale:** Field path already gives Monitor context. + +### 25. `warehouseId` only on `CreateMonitor` and `RegenerateDashboard`, not on `DataMonitorInfo` — `src/v1/model.ts:114,384` +- **Why weird:** `warehouseId` is an input-only field for picking a SQL warehouse to render the dashboard. Not on the response (`DataMonitorInfo`) — so a caller has no way to see which warehouse was actually chosen if they left this blank. Sibling `dataquality.DataProfilingConfig` has both `warehouseId` (input) and `effectiveWarehouseId` (output) — the latter is missing here. Inconsistent across two near-identical packages. +- **Category:** 17 (inconsistent — input-only vs input+output across sibling packages). +- **Suggested name:** Add `effectiveWarehouseId` to `DataMonitorInfo` to match `dataquality`. +- **Rationale:** Cross-package parity. + +### 26. `Notifications` vs `dataquality.NotificationSettings` — `src/v1/model.ts:352` +- **Why weird:** Sister package uses `NotificationSettings`; this package uses just `Notifications`. The plural noun is fine, but the sister naming differs. Also: only one nested type, `Destination` (vs `dataquality.NotificationDestination`) — again one is shorter and one is longer. +- **Category:** 17 (inconsistent — sibling package uses different type names for the same concept). +- **Suggested name:** Pick one: either `Notifications` + `Destination` (this package's form) or `NotificationSettings` + `NotificationDestination` (sibling's form), and apply uniformly across both packages. +- **Rationale:** Consistency across sibling packages. + +### 27. `Destination` — `src/v1/model.ts:292` +- **Why weird:** The `Destination` type holds only `emailAddresses?: string[]`. Naming a type for an email recipient list as `Destination` is generic. Compare with sister `dataquality.NotificationDestination` which has the same shape. The name `Destination` reads as "a place"; the content is "a list of email addresses". +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `EmailDestination` (matches content), or merge with `Notifications` if there's only one channel. +- **Rationale:** Generic noun for a specific data shape. + +### 28. `onNewClassificationTagDetected` field — `src/v1/model.ts:356` +- **Why weird:** Five-word field name (`on` + `New` + `Classification` + `Tag` + `Detected`) — past-tense verb at the end of a noun phrase. The doc says "Destinations to send notifications on new classification tag detected." The grammatical structure is awkward English. Sister `Notifications.onFailure` is concise (two words, no verb tense problem). +- **Category:** 7 (overly verbose), 13 (verb tense — past-participle at the end of a field name). +- **Suggested name:** `onNewClassificationTag` (drop `Detected`; the field is on `Notifications` so the verb is implicit). +- **Rationale:** Length and clarity. The `Detected` adds no information. + +### 29. `Notifications.onFailure: Destination` — `src/v1/model.ts:354` +- **Why weird:** Field name says only "failure"; the comment hints at more ("notifications on failure/timeout") — same caveat as `dataquality.NotificationSettings.onFailure` (audit #33 in that package). Field name and JSDoc disagree on whether timeouts are included. +- **Category:** 1 (vague), 17 (inconsistent doc/name). +- **Suggested name:** `onFailureOrTimeout` (matches doc) or `onFailure` (matches name; update doc). +- **Rationale:** Same as `dataquality` #33. + +### 30. `Notifications` field name uses plural but each value is a single `Destination` — `src/v1/model.ts:352-357` +- **Why weird:** The type is plural (`Notifications`) but each field (`onFailure`, `onNewClassificationTagDetected`) holds a single `Destination`, not an array. The plural-vs-singular doesn't match the content. Compare: `dataquality.NotificationSettings` (singular type, singular fields). +- **Category:** 9 (singular/plural mismatch — type plural, content singular). +- **Suggested name:** `NotificationSettings` (matches `dataquality`). +- **Rationale:** Same as `dataquality` parity. + +### 31. `InferenceLogAnalysisConfig.problemType: ProblemType` — `src/v1/model.ts:314` +- **Why weird:** Field name does not say "ML"; type is the generic `ProblemType` (#7). The reader has no cue from the field name that this is ML-specific. +- **Category:** 1 (vague — `problemType` alone is generic). +- **Suggested name:** `mlProblemType: MlProblemType` (or rely on rename of the enum to `InferenceProblemType` per #7). +- **Rationale:** Disambiguate from generic English meaning. + +### 32. `predictionProbaCol` — `src/v1/model.ts:326` +- **Why weird:** `Proba` is a Python ML idiom for "probability" — sklearn `predict_proba` etc. In a TS API, the name leaks the upstream Python convention. JSDoc says "Column for prediction probabilities" — uses the full word. +- **Category:** 5 (cryptic Python-ML abbreviation), 14 (foreign-ecosystem idiom). +- **Suggested name:** `predictionProbabilityCol` (or `predictionProbabilitiesCol`). +- **Rationale:** Python's `predict_proba` is sklearn vocabulary; a TS SDK should not require knowing sklearn to read field names. + +### 33. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` +- **Why weird:** `Col` is an abbreviation for `Column`. Five fields on `InferenceLogAnalysisConfig` use it. Same in `TimeSeriesAnalysisConfig.timestampCol`. The Go SDK uses `Col` (matches the wire `_col` suffix). TS has no length constraint. +- **Category:** 5 (cryptic abbreviation — `Col`). +- **Suggested name:** `timestampColumn`, `predictionColumn`, `labelColumn`, `modelIdColumn`, `predictionProbabilityColumn`. +- **Rationale:** Full words; matches `dataquality.InferenceLogConfig` if that package has the same pattern (worth cross-checking). + +### 34. `modelIdCol` — `src/v1/model.ts:324` +- **Why weird:** `Id` ambiguity flagged across the SDK. `modelIdCol` — the column in the user's table that holds a model identifier — could be any UC ID or a free-form model version string. JSDoc says only "Column for the model identifier." +- **Category:** 19 (underspecified ID — what *kind* of model ID?). +- **Suggested name:** Document, or rename to `modelVersionColumn` if that is what the wire expects. +- **Rationale:** "Model ID" in Databricks could mean MLflow run ID, MLflow model version, registered model name, or a customer-chosen string. + +### 35. `MonitorCronSchedule` vs `dataquality.CronSchedule` — `src/v1/model.ts:343` +- **Why weird:** Same wire shape, different type names. Sister `dataquality.CronSchedule` drops the `Monitor` prefix. The prefix here is dead context — this type only ever lives on a `Monitor`. +- **Category:** 8 (redundant prefix — `Monitor` is in the access path). +- **Suggested name:** `CronSchedule` (matches `dataquality`). +- **Rationale:** Cross-package consistency. + +### 36. `quartzCronExpression` (leaks library name) — `src/v1/model.ts:345` +- **Why weird:** Same as `dataquality.CronSchedule.quartzCronExpression` (audit #30 in that package). `Quartz` is a Java scheduling library; users do not need to know that. +- **Category:** 14 (implementation-detail leak). +- **Suggested name:** `cronExpression`. +- **Rationale:** Same as `dataquality` #30. + +### 37. `timezoneId` — `src/v1/model.ts:347` +- **Why weird:** Same as `dataquality.CronSchedule.timezoneId` (audit #30 in that package). `Id` for what is in fact an IANA timezone name (e.g., `America/New_York`) — the field is a tz name, not an "ID" in the database sense. +- **Category:** 19 (misnamed — calling a tz name an `Id`), 5 (jargon). +- **Suggested name:** `timezone` (matches JS-standard `Intl.DateTimeFormat.timeZone`). +- **Rationale:** IANA tz names are not IDs in the UUID sense. + +## Low severity + +### 38. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Same as `dataquality` audit #35. Helper exported but never called from `client.ts`. +- **Category:** 6 (misleading — looks used; isn't). +- **Suggested name:** N/A — unexport. +- **Rationale:** Dead exported surface. + +### 39. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Same as `dataquality` audit #36. +- **Category:** 1, 12, 17. +- **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). +- **Rationale:** Layering should be readable from names. + +### 40. `buildHttpRequest` — `src/v1/utils.ts:96` +- **Why weird:** Same as `dataquality` audit #37 — "build" hints at builder pattern, function spreads literals. +- **Category:** 1, 6. +- **Suggested name:** `makeHttpRequest`. +- **Rationale:** "Make" matches the reality. + +### 41. `marshalRequest` and `parseResponse` — `src/v1/utils.ts:113,119` +- **Why weird:** Same as `dataquality` audit #38. Names promise request/response but work on any payload + schema. +- **Category:** 1, 6. +- **Suggested name:** `encodeToJson` / `decodeFromJson`. +- **Rationale:** Symmetric verbs. + +### 42. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Same as `dataquality` audit #39. "ReadAll" does not say "drain a stream". +- **Category:** 1, 5. +- **Suggested name:** `drainStream`. +- **Rationale:** Self-describing. + +### 43. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Same as `dataquality` audit #40. Internal context bag named `Options` — collides with the public `CallOptions` / `ClientOptions` semantics. +- **Category:** 1, 8. +- **Suggested name:** `HttpCallContext`. +- **Rationale:** Reserve `Options` for user-tunable knobs. + +### 44. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` +- **Why weird:** Same as `dataquality` audit #41. +- **Category:** 1. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Domain-word missing. + +### 45. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,133,174,214,252,290,330,373,415` +- **Why weird:** Same as `dataquality` audit #42. Variable `call: Call` in 9 methods. +- **Category:** 1, 12. +- **Suggested name:** `request` (variable). +- **Rationale:** Type/variable collision. + +### 46. `respBody` vs `resp` — every method in `client.ts` +- **Why weird:** Same as `dataquality` audit #44. Two variables differ only by `Body`. +- **Category:** 5, 17. +- **Suggested name:** `rawBody` + `result`. +- **Rationale:** Distinguish by meaningful nouns. + +### 47. `httpReq` local — every method in `client.ts` +- **Why weird:** Same as `dataquality` audit #45. +- **Category:** 5, 12. +- **Suggested name:** `httpRequest`. +- **Rationale:** No abbreviation. + +### 48. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,130,172,212,250,288,327,370,412` +- **Why weird:** Same as `dataquality` audit #43. `fullTableNameArg` typed optional but required in practice; silent empty-string substitution yields URLs like `/api/2.1/unity-catalog/tables//monitor`. +- **Category:** 6. +- **Suggested name:** Make `fullTableNameArg` non-optional on every request type. +- **Rationale:** Type should match runtime requirement. + +## Observations + +### 49. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" +- **Note:** All 9 client methods (`cancelRefresh`, `createMonitor`, `deleteMonitor`, `getMonitor`, `getRefresh`, `listRefreshes`, `regenerateDashboard`, `runRefresh`, `updateMonitor`) start their JSDoc with that sentence. None uses the `@deprecated` JSDoc tag, so editors do not render the deprecation visually. The package is deprecated in spirit, but live in build. + +### 50. Acronym casing +- `Id` (capital-then-lower in `refreshId`, `dashboardId`, `warehouseId`, `monitorVersion`); `Ms` (`startTimeMs`, `endTimeMs`); `Http` (in imported types). No within-package collisions, all generator-emitted. +- **Category:** 3 (acronym casing). + +### 51. URL paths mix `unity-catalog` and `quality-monitoring` +- **Note:** Eight of nine methods use `/api/2.1/unity-catalog/tables/{}/monitor[/...]`; one (`regenerateDashboard`) uses `/api/2.1/quality-monitoring/tables/{}/monitor/dashboard`. The package name does not match either prefix. The sister `dataquality` package uses `/api/data-quality/v1/monitors`. +- **Category:** 17 (inconsistent — package name vs wire path). + +### 52. Boilerplate ratio +- `model.ts` is 935 lines for ~17 user-facing types and 6 enums; ~440 lines (47%) are `marshal*` / `unmarshal*Schema` scaffolding. Same shape as `dataquality`. + +### 53. No `FieldMask` types +- This package does not have any `FieldMask<...>` types (unlike `dataquality`). The deprecated API does not support partial updates via field masks; the entire monitor body is replaced on `PUT`. (Listed as observation to contrast with sibling packages.) + +### 54. Verb consistency +- `Cancel`, `Create`, `Delete`, `Get`, `List`, `Regenerate`, `Run`, `Update` — eight different verbs in nine methods. Within the package the verbs are appropriate and consistent. The unusual one is `Regenerate` (vs `Recreate` or `RebuildDashboard`) — generator-driven choice, fine in context. +- **Category:** 17 (verb inventory, none inconsistent). + +### 55. `Notifications` is a slim type with two channel fields +- Two-channel `Notifications` (`onFailure`, `onNewClassificationTagDetected`) follows the proto / Go SDK shape. A TS-idiomatic shape might be `notifications: Array<{channel: 'failure' | 'newClassificationTag', destination: Destination}>` to allow future expansion. Listed as observation, not a flag. + +## Domain glossary +- `uc` / Unity Catalog — the resource container for the monitored table. +- `inference log` — predictions + labels + (optional) probabilities for a deployed ML model. +- `time series` — analysis configuration where rows have a timestamp column and are bucketed by granularity. +- `snapshot` — analysis configuration with no time dimension; the table is treated as a single snapshot. +- `refresh` — a single run of the monitoring pipeline; produces metric rows in `profileMetricsTableName` / `driftMetricsTableName`. +- `monitor` — the long-lived per-table configuration entity. +- `baseline table` — a separate table whose statistics drift is computed against. +- `profile metrics` / `drift metrics` — two distinct output tables; profile = per-window distribution stats, drift = stats compared against baseline or previous window. +- `quartz` — Apache Quartz Scheduler (Java library); leaks via `quartzCronExpression`. +- `assets dir` — workspace directory holding the dashboard and other monitor assets. +- `slicing exprs` — column expressions to group data by for targeted analysis. +- `data classification` — automated tagging of columns by data type / PII / etc.; controlled by `dataClassificationConfig.enabled` and `Notifications.onNewClassificationTagDetected`. +- `proba` — Python ML idiom for "probability" (sklearn `predict_proba`). +- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered. + +## File coverage +- `src/v1/model.ts` (935 lines): read fully. +- `src/v1/client.ts` (433 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (39 lines): read fully. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md new file mode 100644 index 00000000..98936296 --- /dev/null +++ b/.agent/naming-audit/queries.md @@ -0,0 +1,625 @@ +# Naming Audit: queries + +**Path:** `packages/queries/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. +**Total weird names flagged:** 39 + +## Summary table + +| # | Severity | Location | Name | Category | +|---|----------|----------|------|----------| +| 1 | High | `model.ts` interface | `Query` | Vague/generic — top-level name for what is really a "workspace SQL query" | +| 2 | High | `model.ts` interfaces | `CreateQueryRequestQuery`, `UpdateQueryRequestQuery`, `ListQueryObjectsResponseQuery` | Go/Java-style nested-message names | +| 3 | High | `model.ts` interface | `ListQueryObjectsResponseQuery` | Cryptic/Go-style: leaking proto inner-message + `Objects` filler word | +| 4 | High | package vs siblings | `queries` package vs `queryexecution`, `queryhistory`, `modelservingquery` | Duplicate concept across 4 packages, no shared prefix | +| 5 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashQuery` | Inconsistent verb — most of the SDK uses `delete`; only the SQL surface uses `trash` | +| 6 | High | `model.ts` enum names | `LifecycleState`, `RunAsMode`, `DatePrecision` | Missing domain prefix (no `Query*`) — collide with identical enums in `alerts` package | +| 7 | High | `model.ts` enum names | `DateRangeValue_DynamicDateRange`, `DateValue_DynamicDate` | Proto-style `_` underscores in TypeScript identifiers | +| 8 | High | `model.ts` field | `Query.queryText` | Type-suffix tautology (`Query.queryText`) | +| 9 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | +| 10 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | +| 11 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | +| 12 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | +| 13 | High | `model.ts` field | `Query.schema` | Reserved-word collision (`schema` is a top-level keyword in JSON Schema/Zod terminology used throughout this file) | +| 14 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | +| 15 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | +| 16 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 17 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 18 | Medium | `client.ts` method | `listQueriesIter`, `listVisualizationsForQueryIter` | Cryptic abbreviation (`Iter` from Go/Rust) | +| 19 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 20 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 21 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | +| 22 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | +| 23 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | +| 24 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | +| 25 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 26 | Medium | `model.ts` enum values | `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` | Redundant enum prefix (enum already named `DatePrecision`) | +| 27 | Medium | `model.ts` enum | `DateRangeValue_DynamicDateRange` | Long enum values + Go/Java-style `_` separator | +| 28 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | +| 29 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | +| 30 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | +| 31 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | +| 32 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | +| 33 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | +| 34 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | +| 35 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | +| 36 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | +| 37 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | +| 38 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | +| 39 | Low | `model.ts` enum value | `DateValue_DynamicDate.NOW` and `YESTERDAY` | Singular/plural mismatch with sibling `DateRangeValue_DynamicDateRange.YESTERDAY` (same value lives in both enums) | +| 40 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | + +## High severity + +### 1. `Query` — vague/generic top-level name + +**Location:** `src/v1/model.ts:223-257` + +```ts +export interface Query { + /** UUID identifying the query. */ + id?: string | undefined; + /** Display name of the query that appears in list views, widget headings, and on the query page. */ + displayName?: string | undefined; + ... +} +``` + +`Query` is the single most generic noun in a SQL SDK. Every Databricks consumer eventually has its own `Query` type. The same package also exposes `QueryParameter`, `QueryBackedValue`, and the sibling packages `queryexecution`, `queryhistory`, `modelservingquery` all surface `Query*` concepts. A user importing `Query` from `@databricks/sdk-queries` and another `Query` from `@databricks/sdk-queryhistory` faces an immediate naming collision. + +A domain-anchored name like `WorkspaceQuery` or `SavedQuery` (this is, in fact, a *saved/stored* SQL query, not a runtime query execution) would distinguish it from the runtime `Query` concept in `queryexecution`. + +### 2. Go/Java-style nested-message types + +**Location:** `src/v1/model.ts:57-91`, `163-197`, `324-358` + +- `CreateQueryRequestQuery` +- `UpdateQueryRequestQuery` +- `ListQueryObjectsResponseQuery` + +These three interfaces share the bulk of `Query`'s fields and originate from protobuf's `MessageA_MessageB` flattening. The naming forces the user to choose which `Query`-like type to construct depending on which call they want to make. This is the exact problem `alerts` v2 solved by collapsing back to `Alert`. + +### 3. `ListQueryObjectsResponseQuery` — Go-style + filler word + +**Location:** `src/v1/model.ts:163-197` + +```ts +export interface ListQueryObjectsResponseQuery { ... } +``` + +The "Objects" infix between `Query` and `Response` is filler — the RPC is `ListQueries`, the response wraps a list of queries; there is no separate "QueryObject" concept. Combined with the trailing `Query` repeat, this is one of the most verbose generated names in the package (29 chars, four query-related morphemes). + +### 4. Duplicate concept across 4 packages — `queries`, `queryexecution`, `queryhistory`, `modelservingquery` + +**Location:** package boundaries + +The Databricks SDK ships four query-flavoured packages with no shared prefix: + +- `queries` — *saved* SQL queries (this package). +- `queryexecution` — running a query against a published dashboard. +- `queryhistory` — past query executions (with metrics, timing). +- `modelservingquery` — querying a served ML model. + +There is no obvious entry point for "I want to run a SQL query" — the user has to guess which package owns which verb. A namespace like `sql.queries`, `sql.executions`, `sql.history` (and `ml.servingQueries`) would group them. Inside this package, `Query` returned by `getQuery` is *not* the same `Query`-prefixed type that `queryhistory.ListQueries` returns (which is named `ListQueries` — see below). + +### 5. `LifecycleState.TRASHED` vs method `trashQuery` — verb/state inconsistency + +**Location:** `src/v1/model.ts:14-17`, `src/v1/client.ts:227-249` + +```ts +export enum LifecycleState { + ACTIVE = 'ACTIVE', + TRASHED = 'TRASHED', +} + +/** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, ... A trashed query is permanently deleted after 30 days. */ +async trashQuery(req: TrashQueryRequest, options?: CallOptions): Promise { + ... +} +``` + +The HTTP verb is `DELETE`, the docstring talks about "permanently deleted after 30 days," but the method is `trashQuery` and the resulting enum value is `TRASHED`. Across the SDK, `trash` is unique to the SQL surface (queries, alerts); every other resource uses `deleteX`. A v2 of `alerts` already broke this consistency (it renamed `TRASHED` → `DELETED` but kept `trashAlert`); `queries` v1 may face the same trap. + +### 6. Missing domain prefix on enums + +**Location:** `src/v1/model.ts:8-22` + +```ts +export enum DatePrecision { ... } +export enum LifecycleState { ... } +export enum RunAsMode { ... } +``` + +Three top-level enums in a domain-specific package, none prefixed with `Query*`. The same package also indirectly uses an identical `LifecycleState` concept that exists with the same values (`ACTIVE`/`TRASHED`) in `alerts` v1; when a user imports both they collide by name. `QueryLifecycleState`, `QueryRunAsMode`, `QueryDatePrecision` (or simply re-using shared `LifecycleState` from a common package) would address this; the current state is the worst of both worlds. + +### 7. Proto-style underscores in TS identifiers — `DateRangeValue_DynamicDateRange`, `DateValue_DynamicDate` + +**Location:** `src/v1/model.ts:24-49` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. +export enum DateRangeValue_DynamicDateRange { ... } + +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. +export enum DateValue_DynamicDate { ... } +``` + +TS exports two enums whose names contain underscores. The eslint suppression comment acknowledges this is non-idiomatic. The names are direct ports of protobuf's nested-message naming (parent message `DateRangeValue`, nested enum `DynamicDateRange`). In hand-written TS this would be `DateRangeValueDynamicDateRange` or, better, simply `DynamicDateRange` (since `DateRangeValue` is the only consumer). The underscores will also confuse downstream tooling (autocomplete will treat them as snake_case constants). + +### 8. `Query.queryText` — type-suffix tautology + +**Location:** `src/v1/model.ts:234-235`, `model.ts:175-176`, `model.ts:235` + +```ts +export interface Query { + ... + /** Text of the query to be run. */ + queryText?: string | undefined; + ... +} +``` + +A field on `Query` named `queryText` — the access pattern is `q.queryText` where the `q` already implies "query." Inside an `Alert`, `queryText` is meaningful (it disambiguates from `alertText`). Inside `Query`, the `query` prefix is redundant. `text`, `sql`, or `statement` would suffice. + +### 9. `QueryParameter` vs sibling value types — inconsistent prefixing + +**Location:** `src/v1/model.ts:268-306`, `308-310`, `219-221`, `140-147` + +```ts +export interface QueryParameter { ... } // prefixed +export interface TextValue { ... } // unprefixed +export interface NumericValue { ... } // unprefixed +export interface EnumValue { ... } // unprefixed +export interface DateValue { ... } // unprefixed +export interface DateRangeValue { ... } // unprefixed +export interface QueryBackedValue { ... } // prefixed +``` + +Some value-type wrappers are prefixed (`Query*`), others are not. The choice appears to be based on whether the type "feels generic" — but `EnumValue`, `DateValue`, `DateRange` are arguably even more generic than `QueryParameter`. The package picks `QueryParameter` and `QueryBackedValue` for prefixing, while leaving `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRangeValue` unprefixed. Result: importing this package brings ambient types like `EnumValue` and `TextValue` into the user's scope. + +### 10. `QueryBackedValue` — misleading + +**Location:** `src/v1/model.ts:259-266` + +```ts +export interface QueryBackedValue { + /** List of selected query parameter values. */ + values?: string[] | undefined; + /** UUID of the query that provides the parameter values. */ + queryId?: string | undefined; + /** If specified, allows multiple values to be selected for this parameter. */ + multiValuesOptions?: MultiValuesOptions | undefined; +} +``` + +The name reads as "a value that is backed by a query" — implying the value itself comes from query state. The actual semantics, per JSDoc, is: a dropdown widget whose options are populated by running another saved query. `QuerySourcedDropdownParameter`, `QueryBackedDropdown`, or `DropdownFromQuery` would describe the actual concept. As written, the name is at the same abstraction level as `QueryBackedView` or `QueryBackedTable` — neither of which describes what this is. + +### 11. `QueryParameter.parameterValue` (oneof key) — type-suffix tautology + +**Location:** `src/v1/model.ts:268-306` + +```ts +export interface QueryParameter { + ... + /** Only one of the following fields may be set, depending on the type of parameter. */ + parameterValue?: + | { $case: 'textValue'; textValue: TextValue } + | { $case: 'numericValue'; numericValue: NumericValue } + | { $case: 'enumValue'; enumValue: EnumValue } + | { $case: 'dateValue'; dateValue: DateValue } + | { $case: 'dateRangeValue'; dateRangeValue: DateRangeValue } + | { $case: 'queryBackedValue'; queryBackedValue: QueryBackedValue } + | undefined; +} +``` + +`QueryParameter.parameterValue` repeats "parameter" — access pattern `p.parameterValue` where `p` is already `QueryParameter`. The plain `value` would suffice (mirroring `AlertOperand.operand` from the alerts audit — same anti-pattern, opposite name). + +### 12. `EnumValue` — vague/generic top-level name + +**Location:** `src/v1/model.ts:140-147` + +```ts +export interface EnumValue { + /** List of selected query parameter values. */ + values?: string[] | undefined; + /** List of valid query parameter values, newline delimited. */ + enumOptions?: string | undefined; + /** If specified, allows multiple values to be selected for this parameter. */ + multiValuesOptions?: MultiValuesOptions | undefined; +} +``` + +`EnumValue` exported at the package root. `enum` is a TypeScript keyword and a generic concept; the type is in fact a *dropdown* parameter source (a list of valid options + the selected subset). `DropdownParameter`, `EnumParameter`, or `QueryEnumParameter` would name the actual concept. + +### 13. `Query.schema` — reserved-word/local-keyword collision + +**Location:** `src/v1/model.ts:255-256` + +```ts +/** Name of the schema where this query will be executed. */ +schema?: string | undefined; +``` + +`schema` is a Unity-Catalog *schema* name. But the same file uses the word `schema` ~30 times to mean `z.ZodType` (`marshalQuerySchema`, `unmarshalQuerySchema`, `updateQueryRequestQueryFieldMaskSchema`). The collision is internal-only, but for a reader the noun `schema` ambiguously means UC-schema OR Zod-schema depending on context. `databaseSchema` or `unityCatalogSchema` would disambiguate. (Same package has `catalog` as a sibling field — together they would be `query.unityCatalogCatalog` which is itself ridiculous; the right fix is to keep `catalog` and `schema` but rename the Zod schemas.) + +### 14. `QueryParameter.title` vs `.name` — misleading pair + +**Location:** `src/v1/model.ts:268-272` + +```ts +export interface QueryParameter { + /** Text displayed in the user-facing parameter widget in the UI. */ + title?: string | undefined; + /** Literal parameter marker that appears between double curly braces in the query text. */ + name?: string | undefined; + ... +} +``` + +Reading the field names alone, `name` is the identifier and `title` is a richer/longer display string. The JSDoc inverts this: `name` is the literal `{{marker}}` text that appears in the SQL, and `title` is the human-readable widget label. The conventional pairing in this codebase (and most others) is `(name, displayName)`. Here it is `(name, title)` *and* `name` plays the role most SDK shapes give to `key`/`marker`/`identifier` and `title` plays the role of `displayName`. A reader has to consult JSDoc to tell which is which. + +### 15. `Query.queryText` JSDoc — "Text of the query to be run" on a type already called `Query` + +**Location:** `src/v1/model.ts:68-69`, `174-175`, `234-235`, `335-336` + +```ts +export interface Query { + ... + /** Text of the query to be run. */ + queryText?: string | undefined; + ... +} +``` + +Both the field name and the JSDoc embed the word "query" on a type called `Query`. The field exists on four near-identical interfaces (see #2), so the redundancy multiplies. The same field is the *only* part of `Query` that is actually a SQL statement — pulling it up as `Query.text` or `Query.sql` would simplify both name and doc. + +## Medium severity + +### 16. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) + +**Location:** `src/v1/client.ts:227-250` + +```ts +/** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, and cannot be used for alerts. You can restore a trashed query through the UI. A trashed query is permanently deleted after 30 days. */ +async trashQuery( + req: TrashQueryRequest, + options?: CallOptions +): Promise { ... DELETE ... } +``` + +The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). + +### 17. `TrashQueryRequest` — same as #16, in the type layer + +**Location:** `src/v1/model.ts:312-314` + +```ts +export interface TrashQueryRequest { + id?: string | undefined; +} +``` + +Same verb inconsistency at the type layer. Carries only `id`. + +### 18. `listQueriesIter`, `listVisualizationsForQueryIter` — cryptic abbreviation + +**Location:** `src/v1/client.ts:156-171`, `210-225` + +```ts +async *listQueriesIter( + req: ListQueriesRequest, + options?: CallOptions +): AsyncGenerator { ... } + +async *listVisualizationsForQueryIter( + req: ListVisualizationsForQueryRequest, + options?: CallOptions +): AsyncGenerator { ... } +``` + +`Iter` reads as a Go/Rust port (Go SDK uses `*Iterator`, Rust uses `iter()`). Idiomatic TS would name this `listAllQueries`, `iterateQueries`, or simply make `listQueries` return an async iterable. + +### 19. `listVisualizationsForQuery` — overly verbose + +**Location:** `src/v1/client.ts:173-208` + +```ts +async listVisualizationsForQuery( + req: ListVisualizationsForQueryRequest, + options?: CallOptions +): Promise { ... } +``` + +`For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. + +### 20. `Visualization` — vague/generic top-level name + +**Location:** `src/v1/model.ts:360-377` + +```ts +export interface Visualization { ... } +``` + +`Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. + +### 21. `Query.warehouseId` — underspecified ID + +**Location:** `src/v1/model.ts:66-67`, `172-173`, `232-233`, `333-334` + +```ts +/** ID of the SQL warehouse attached to the query. */ +warehouseId?: string | undefined; +``` + +The JSDoc says "SQL warehouse"; the field says `warehouseId`. Databricks has data warehouses, Lakehouse, SQL warehouses, etc. `sqlWarehouseId` would self-document. + +### 22. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar + +**Location:** `src/v1/model.ts:64-65`, `74-75` + +```ts +/** Username of the user that owns the query. */ +ownerUserName?: string | undefined; +... +/** Username of the user who last saved changes to this query. */ +lastModifierUserName?: string | undefined; +``` + +`owner` is a noun. `lastModifier` is an agent noun constructed from the verb "modify." The pairing is mismatched — either both should be agent nouns (`ownerUserName`, `lastModifierUserName`) or both should be participial (`ownedBy`, `lastModifiedBy`). The Go convention is the former; idiomatic TS leans toward the latter. Also note the JSDoc inconsistency: "the user that owns" vs "the user who last saved" — different relative pronouns. + +### 23. `Query.lastModifierUserName` — overly verbose + +**Location:** `src/v1/model.ts:74-75` + +```ts +lastModifierUserName?: string | undefined; +``` + +21 characters for what is, semantically, "last-modified-by." `lastModifiedBy` is 14 characters and more natural English. + +### 24. `LifecycleState.TRASHED` — verb-tense inconsistency + +**Location:** `src/v1/model.ts:14-17` + +The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). + +### 25. `RunAsMode` — verb-as-noun, filler `Mode` + +**Location:** `src/v1/model.ts:19-22` + +```ts +export enum RunAsMode { + OWNER = 'OWNER', + VIEWER = 'VIEWER', +} +``` + +`RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. + +### 26. `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` — redundant enum prefix + +**Location:** `src/v1/model.ts:8-12` + +```ts +export enum DatePrecision { + DAY_PRECISION = 'DAY_PRECISION', + MINUTE_PRECISION = 'MINUTE_PRECISION', + SECOND_PRECISION = 'SECOND_PRECISION', +} +``` + +Access is `DatePrecision.DAY_PRECISION` — the enum name already says "precision." `DAY`/`MINUTE`/`SECOND` would suffice. + +### 27. `DateRangeValue_DynamicDateRange` — long enum + Go-style underscore + +**Location:** `src/v1/model.ts:24-43` + +The enum *name* has a `_` separator (see #7 high). Beyond that, the enum *values* like `LAST_8_HOURS`, `LAST_24_HOURS` discretize a continuous space — only 16 fixed buckets. + +### 28. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... + +**Location:** `src/v1/model.ts:25-42` + +```ts +LAST_HOUR = 'LAST_HOUR', +LAST_8_HOURS = 'LAST_8_HOURS', +LAST_24_HOURS = 'LAST_24_HOURS', +LAST_7_DAYS = 'LAST_7_DAYS', +LAST_14_DAYS = 'LAST_14_DAYS', +LAST_30_DAYS = 'LAST_30_DAYS', +LAST_60_DAYS = 'LAST_60_DAYS', +LAST_90_DAYS = 'LAST_90_DAYS', +LAST_12_MONTHS = 'LAST_12_MONTHS', +``` + +The user gets 16 hard-coded time windows. If they want "last 45 days," there is no value. A `{ unit: 'DAY' | 'HOUR' | ...; n: number }` shape would express the same thing without the enum-value explosion. (Acknowledged that the underlying API likely accepts only these buckets — but the API design itself is the smell.) + +### 29. `Query.applyAutoLimit` — misleading verb predicate + +**Location:** `src/v1/model.ts:85-87` + +```ts +/** Whether to apply a 1000 row limit to the query result. */ +applyAutoLimit?: boolean | undefined; +``` + +The name reads as an imperative action ("apply the auto limit!") rather than a flag. `autoLimit` (boolean) or `autoLimitRows` (number) would parse more naturally as state. The "1000" rule is in the JSDoc, not the type — `autoLimit: number` with the convention "1000 if true, 0 if disabled" would surface the magic number. + +### 30. `Query.runAsMode` — type-suffix tautology + +**Location:** `src/v1/model.ts:70-71` + +```ts +/** Sets the "Run as" role for the object. */ +runAsMode?: RunAsMode | undefined; +``` + +Field of type `RunAsMode` named `runAsMode`. `runAs` would suffice (the type already encodes "mode"). + +### 31. `Query.parentPath` — underspecified + +**Location:** `src/v1/model.ts:76-77` + +```ts +/** Workspace path of the workspace folder containing the object. */ +parentPath?: string | undefined; +``` + +"Parent" of what? The JSDoc clarifies it is the workspace-folder path. `workspaceFolderPath` would self-document. `parentPath` reads like a filesystem path or a Git ref to first-time readers. (The same field appears in `alerts` — flagged there too.) + +### 32. `MultiValuesOptions` — singular/plural mismatch + +**Location:** `src/v1/model.ts:210-217` + +```ts +export interface MultiValuesOptions { + /** Character that prefixes each selected parameter value. */ + prefix?: string | undefined; + /** Character that separates each selected parameter value. Defaults to a comma. */ + separator?: string | undefined; + /** Character that suffixes each selected parameter value. */ + suffix?: string | undefined; +} +``` + +`MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). + +### 33. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context + +**Location:** `src/v1/model.ts:210-217` + +`prefix`, `separator`, `suffix` are completely generic outside the surrounding type. The JSDoc says "Character that prefixes each selected parameter value" — they are not characters, they are arbitrary strings (typed `string`). `valuePrefix`, `valueSeparator`, `valueSuffix` would be self-documenting and the type-level `MultiValuesOptions` could drop the leading "Multi-Values" altogether. + +### 34. `Visualization.type` — reserved-word collision + +**Location:** `src/v1/model.ts:365-366` + +```ts +/** The type of visualization: counter, table, funnel, and so on. */ +type?: string | undefined; +``` + +`type` is a TS keyword (used in `type Foo = …`) and a generic field name. The JSDoc admits it is "counter, table, funnel, and so on" — i.e., an open-ended string enum (no domain enum is defined). `visualizationType` or `kind` would avoid the keyword issue. + +### 35. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading + +**Location:** `src/v1/model.ts:371-374` + +```ts +/** The visualization query plan varies widely from one visualization type to the next and is unsupported. Databricks does not recommend modifying the visualization query plan directly. */ +serializedQueryPlan?: string | undefined; +/** The visualization options varies widely from one visualization type to the next and is unsupported. Databricks does not recommend modifying visualization options directly. */ +serializedOptions?: string | undefined; +``` + +Field names imply "the data, in serialized form." JSDoc admits the format is undocumented and the field should not be modified. If users are not supposed to construct these, they should not be on a public type (or they should be typed `Readonly` with a clear name like `internalQueryPlan`/`opaqueOptions`). + +### 36. `DateRangeValue.startDayOfWeek` — underspecified type + +**Location:** `src/v1/model.ts:113` + +```ts +startDayOfWeek?: number | undefined; +``` + +`number` with no JSDoc — is this 0-indexed or 1-indexed? Monday-first (ISO) or Sunday-first (US)? A `DayOfWeek` enum (`MONDAY`, `TUESDAY`, ...) or a typed alias would be self-documenting. + +## Low severity + +### 37. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency + +**Location:** `src/v1/model.ts:58-59`, `362-363`, `262-263` + +Top-level types use bare `id`; cross-referencing types use `queryId`. `Query.queryId` would be consistent with `Visualization.queryId` and `QueryBackedValue.queryId`. Currently `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` means there are two conventions side-by-side. + +### 38. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination + +**Location:** `src/v1/model.ts:153-156`, `158-161` + +Standard Google AIP-158 names. Flagged for completeness; no action recommended. + +### 39. `DateValue_DynamicDate.NOW`, `YESTERDAY` — sibling enum overlap + +**Location:** `src/v1/model.ts:45-49` + +```ts +export enum DateValue_DynamicDate { + NOW = 'NOW', + YESTERDAY = 'YESTERDAY', +} +``` + +`YESTERDAY` appears here *and* in `DateRangeValue_DynamicDateRange`. The two enums share at least one literal value but are not assignable to each other (TS enums are nominal). A shared `RelativeDate` enum (`NOW`, `YESTERDAY`, `LAST_HOUR`, ...) with sub-grouping would avoid the duplication. + +### 40. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. + +**Location:** `src/v1/model.ts:292`, `297` + +```ts +/** Date query parameter value. Can only specify one of `dynamic_date_value` or `date_value`. */ +dateValue: DateValue; +/** Date-range query parameter value. Can only specify one of `dynamic_date_range_value` or `date_range_value`. */ +dateRangeValue: DateRangeValue; +``` + +The JSDoc references wire-format field names (snake_case) but the user is writing TS code that uses camelCase (`dynamicDateValue`, `dateValue`). Wire-format leakage; doc should reference the TS oneof discriminator names. + +## Cross-package overlap + +The four query-flavoured packages share concept space without sharing types: + +| Package | Top-level `Query`-prefixed types | +|---------|----------------------------------| +| `queries` (this) | `Query`, `QueryParameter`, `QueryBackedValue`, `CreateQueryRequest`, `UpdateQueryRequest`, `ListQueriesRequest`, `GetQueryRequest`, `TrashQueryRequest`, `ListQueriesResponse`, `ListQueryObjectsResponseQuery`, `ListVisualizationsForQueryRequest`, `ListVisualizationsForQueryResponse` | +| `queryexecution` | `CancelQueryExecutionResponse`, `CancelQueryExecutionResponseStatus`, `ExecuteQueryResponse`, `PollQueryStatusResponse`, `PollQueryStatusResponseData`, `QueryResponseStatus`, `ExecutePublishedDashboardQueryRequest`, `PollPublishedQueryStatusRequest`, `CancelPublishedQueryExecutionRequest` | +| `queryhistory` | `QueryStatementType`, `QueryStatus`, `ListQueries`, `ListQueries_Response`, `QueryFilter`, `QueryInfo`, `QueryMetrics`, `QueryTag`, `ExternalQuerySource`, `ExternalQuerySource_JobInfo` | +| `modelservingquery` | `QueryEndpointInput`, `QueryEndpointInput_ExtraParamsEntry`, `QueryEndpointInput_UsageContextEntry`, `QueryEndpointResponse`, `QueryEndpointResponseObject` | + +Observations: + +- **`Query` is overloaded.** This package's `Query` is a saved SQL artefact. `queryhistory.QueryInfo` is a runtime execution record. `queryexecution`'s nameless concept (no `Query` type) is a dashboard parameterised query run. The four packages do not cross-reference each other's types. +- **`ListQueries` collides cross-package.** `queries.ListQueriesRequest` and `queryhistory.ListQueries` are entirely different shapes returning entirely different data, both with the same human-readable name. +- **No shared enums.** `queries.LifecycleState`, `queryhistory.QueryStatus`, `queryexecution.PendingStatus` / `SuccessStatus` are unrelated. A consumer building a query dashboard would have to manually correlate them. +- **Proto `_` leakage.** `queryhistory.ListQueries_Response`, `queryhistory.ExternalQuerySource_JobInfo`, `modelservingquery.QueryEndpointInput_ExtraParamsEntry` all use the same underscore-naming as `queries.DateRangeValue_DynamicDateRange`. The pattern is package-wide; flag at the generator level. + +## Observations + +1. **`Query` overload.** `Query` is one of the broadest words in any SQL SDK. This package's `Query` is a *saved* configuration; `queryexecution`'s implicit "query" is a *running statement*; `queryhistory`'s `QueryInfo` is a *historical record*. None reference each other. A future cleanup might rename this package's `Query` → `SavedQuery` or `WorkspaceQuery`. + +2. **Wire-format leakage.** Direct proto-to-TS port shows in `DateRangeValue_DynamicDateRange`, `DateValue_DynamicDate` and snake_case identifiers in JSDoc. The "1:1 port" rule is satisfied but TypeScript ergonomics suffer. + +3. **Soft-delete verb is `trash`, not `delete`.** `trashQuery` and `LifecycleState.TRASHED` are the only places in the SDK using "trash." This will diverge from the rest of the resource lifecycle vocabulary as the SDK grows. + +4. **Top-level type pollution.** `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRange`, `DateRangeValue`, `MultiValuesOptions`, `Visualization` are all unprefixed and exported. A user importing `import { TextValue } from '@databricks/sdk-queries'` gets a generically-named type that competes with their own code. + +5. **`utils.ts` is well-named and unchanged.** Exports (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are domain-neutral and not flagged. `flattenQueryParams` is exported but unused in `client.ts` (orphaned export) — not a naming issue, but worth noting. + +6. **`Iter` suffix.** `listQueriesIter`, `listVisualizationsForQueryIter` — Go/Rust-flavoured method names. Will appear in every generated package; flag at the generator level. + +7. **`schema` ambiguity.** The file uses `schema` to mean both a Unity-Catalog schema (field on `Query`) and a Zod schema (`marshalQuerySchema`, etc.). The two never collide at the type level but the prose-level overloading hurts code review. + +## Domain glossary + +| Term | Meaning in this package | +|------|------------------------| +| Query | A stored, named SQL statement saved in the workspace (not a running execution). | +| Query text | The raw SQL of the saved query. | +| Parameter | A placeholder in the SQL text (between `{{ }}` markers) that gets substituted at run time; has a typed value (text / numeric / enum / date / date-range / query-backed). | +| Query-backed value | A dropdown parameter whose options come from running another saved query. | +| Visualization | A view definition (counter, table, funnel, etc.) attached to a query. | +| Run-as | The identity (`OWNER` of the query or current `VIEWER`) under which the SQL executes. | +| Lifecycle state | `ACTIVE` (visible) or `TRASHED` (soft-deleted; permanently deleted after 30 days). | +| Auto-limit | A 1000-row cap automatically applied to query results when `applyAutoLimit=true`. | +| Parent path | The workspace folder path containing the saved query. | +| Catalog / schema | Unity-Catalog three-part-name prefix (`catalog.schema.table`) used as the default for unqualified table references in the SQL. | + +## File coverage + +| File | Lines | Read in full | +|------|-------|--------------| +| `src/v1/model.ts` | 996 | yes | +| `src/v1/client.ts` | 278 | yes | +| `src/v1/utils.ts` | 151 | yes | +| `src/v1/index.ts` | 38 | yes | diff --git a/.agent/naming-audit/queryexecution.md b/.agent/naming-audit/queryexecution.md new file mode 100644 index 00000000..36f8f931 --- /dev/null +++ b/.agent/naming-audit/queryexecution.md @@ -0,0 +1,260 @@ +# Naming Audit: queryexecution + +**Path:** `packages/queryexecution/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Execute, cancel, and poll SQL queries for *published, embedded +Lakeview dashboards*. All three endpoints hit the same URL +(`/api/2.0/lakeview-query/query/published`) and only differ by HTTP verb (POST = execute, +GET = poll, DELETE = cancel). The package name (`queryexecution`) is much broader than +what it actually does (lakeview-dashboard query lifecycle). Confusing overlap with +sibling packages `statementexecution` (general SQL Statement Execution API), +`queryhistory` (history of executed queries), and `queries` (saved query definitions). +**Total weird names flagged:** 36 + +## Summary +| Severity | Count | +| --- | --- | +| High | 8 | +| Medium | 15 | +| Low | 9 | +| Observation | 4 | + +## High severity + +### 1. Package name `queryexecution` is far broader than its scope — `package.json`, directory name +- **Why weird:** The package operates exclusively on *published, embedded Lakeview dashboards* (see every JSDoc and the URL `/api/2.0/lakeview-query/query/published`). A user importing `@databricks/sdk-queryexecution` would reasonably expect general "query execution" — i.e. `statementexecution`, which is the SDK's actual general-purpose SQL execution API. The two packages have wildly different scopes but near-identical names. +- **Category:** 1 (vague — `queryexecution` is the generic term), 6 (misleading — implies general query API, is dashboard-scoped), 12 (duplicate concept — overlaps `statementexecution` and `queryhistory`). +- **Suggested name:** `lakeviewquery` or `publisheddashboardquery` or fold into `lakeview`/`dashboards` packages. If staying separate, every type name should be prefixed `PublishedDashboard*` to make scope obvious. +- **Rationale:** The first and most damaging naming problem here is that the package name promises a generic capability and silently delivers a specialised one. Compare: `commandexecution` (executes Python/SQL via REPL) vs. `statementexecution` (executes SQL via SQL Warehouse) vs. `queryexecution` (re-runs *already-saved* queries inside *published* dashboards). A user looking at the three would have to read every method to know which one they want. + +### 2. `CancelQueryExecutionResponse` / `CancelQueryExecutionResponseStatus` vs. request `CancelPublishedQueryExecutionRequest` — `src/v1/model.ts:11,18,22` +- **Why weird:** The request type prefixes `Published` (correctly identifying the scope) but the two response types drop the prefix. The package only handles published-dashboard cancels, yet the type names alternate between `*PublishedQueryExecution*` and `*QueryExecution*` for what is fundamentally the same operation. The asymmetric stripping suggests the response types are reused, but they aren't — there is only one cancel endpoint. +- **Category:** 6 (misleading — strips the `Published` qualifier from response types), 12 (duplicate concept — looks like two unrelated cancel APIs), 17 (asymmetric request/response naming). +- **Suggested name:** `CancelPublishedQueryResponse` / `CancelPublishedQueryResponseStatus` (or drop `Published` from both for consistency, since the whole package is scoped to published dashboards). +- **Rationale:** Symmetric request/response pairs are the SDK norm (`CreateCatalogConfigRequest`/`CreateCatalogConfigResponse` etc.). The mismatch here suggests that the response types might be shared, which they aren't, and forces callers to mentally translate between two near-identical names. + +### 3. `ExecutePublishedDashboardQueryRequest` vs. `ExecuteQueryResponse` — `src/v1/model.ts:46,58` +- **Why weird:** Asymmetric naming: the request name says "Execute **Published Dashboard** Query", while the response is the generic `ExecuteQueryResponse`. A user reading just the model file would think `ExecuteQueryResponse` is some shared type used by multiple Execute*Request types, but it's only used here. +- **Category:** 6 (misleading — response name doesn't match request), 12 (duplicate concept). +- **Suggested name:** `ExecutePublishedQueryResponse` (matching scope). +- **Rationale:** The asymmetric prefix forces callers to mentally translate between two near-identical names. Symmetric request/response pairs are the SDK norm. + +### 4. `CancelQueryExecutionResponseStatus.status` discriminated union — `src/v1/model.ts:22-32` +- **Why weird:** The type is named `CancelQueryExecutionResponseStatus` (so `Status`-the-suffix), but its main payload is *also* called `status` (a discriminated union over `success`/`pending`). So you write `responseStatus.status` to access the status of the status. +- **Category:** 1 (vague — `status.status` reads as redundant), 12 (duplicate concept — same word twice in one expression), 20 (type-suffix tautology). +- **Suggested name:** Rename outer type to `CancelTokenResult` (or `CancelOutcome`). +- **Rationale:** When the same word appears at two adjacent levels of a structure (`x.status.status`), it usually means one of them is misnamed. Here the inner one is the actual discriminant; the outer "Status" is a redundant suffix. + +### 5. `PollQueryStatusResponse.data` — `src/v1/model.ts:82` +- **Why weird:** Top-level field named `data` on a response object. `data` is the most generic possible field name (rule 15 in the prompt: "Generic field names losing meaning"). It happens to hold *per-token statuses*, but the name gives a reader zero hint of that. +- **Category:** 1 (vague), 15 (generic field name losing meaning). +- **Suggested name:** `statuses` (plural, matches the array shape) or `tokenStatuses`. +- **Rationale:** `data` should never be the name of the only field on a response. The wire calls it `data`, but a TS SDK can do better. + +### 6. `QueryResponseStatus` vs. `CancelQueryExecutionResponseStatus` — `src/v1/model.ts:22,89` +- **Why weird:** Two near-identical types differ only by the verbs they accept (`CancelQueryExecutionResponseStatus` has `success`/`pending`, `QueryResponseStatus` has `success`/`pending`/`canceled`/`closed`). Both wrap discriminated unions over the same vocabulary. They could be unified by making the cancel response use a subset of `QueryResponseStatus`. The fact that the names are *different but parallel* makes the duplication harder to spot. +- **Category:** 12 (duplicate concept — two types modelling the same idea), 17 (inconsistent action-verb prefix — one uses `Cancel*ResponseStatus`, the other uses `*ResponseStatus`). +- **Suggested name:** Collapse into one `QueryResponseStatus`, drop the `Cancel*ResponseStatus` and use the unified type with only the arms that apply. +- **Rationale:** Two types with the same purpose is a maintenance hazard. The names actively conceal the duplication by spelling things differently. + +### 7. `Client` class name — `src/v1/client.ts:41` +- **Why weird:** A class literally named `Client` at the top level of the package's API surface, re-exported as just `Client`. Identical to `dataclassification.md` Finding #11 and a repeated pattern across the SDK. A user importing `Client` from `@databricks/sdk-queryexecution` and another `Client` from `@databricks/sdk-statementexecution` collides on the namespace. +- **Category:** 1 (vague — `Client` is the most generic name possible), 15 (generic name). +- **Suggested name:** `QueryExecutionClient` (or, per #1, `PublishedDashboardQueryClient`). +- **Rationale:** Same as the cross-SDK pattern: every API package has a `Client`, and combined imports require renaming. The collision risk grows with each added package. + +### 8. `unmarshalPollQueryStatusResponseDataSchema` — `src/v1/model.ts:167` +- **Why weird:** Five stacked words: `unmarshal` + `Poll` + `QueryStatus` + `Response` + `Data` + `Schema`. The triple-`Schema`-like suffix repeats both `Status` (from inner) and `Schema` (from zod-helper convention). The variable definition spans three lines just by signature. Worst-offender length in the file. +- **Category:** 5 (cryptic — hard to parse), 7 (overly verbose), 8 (redundant suffix — `Response` + `Data` are both meta-suffixes), 14 (Go-style `marshal`/`unmarshal`). +- **Suggested name:** `decodeTokenStatusEntrySchema`. +- **Rationale:** A function name should fit a short line. Five stacked qualifiers is a sign that several layers of abstraction are leaking into the identifier. + +## Medium severity + +### 9. `PendingStatus` and `SuccessStatus` types — `src/v1/model.ts:60,105` +- **Why weird:** Two types share the `Status` suffix, but only one of them ("Success") carries the `truncated` boolean. Their names suggest they are siblings of an enum (`Pending` vs `Success`), but `Pending` only has `dataToken`, while `Success` has `dataToken` + `truncated`. This means the *only* thing that distinguishes a "success" from a "pending" at the type level is the *presence* of `truncated` — but since `truncated` is `optional`, neither type's instance can be reliably distinguished from the other. +- **Category:** 6 (misleading — types are technically distinguishable but in practice not), 16 (field contradicts type domain — `truncated` is meaningless on `Pending` but exists structurally), 17 (asymmetric). +- **Suggested name:** Keep names but make `truncated` required (non-optional) on `SuccessStatus`, or merge them: `interface QueryToken { dataToken?: string; truncated?: boolean }` with the state encoded by the discriminator only. +- **Rationale:** When two state-variant types differ only by one optional field, they shouldn't be separate types. + +### 10. `dataToken` field — `src/v1/model.ts:27,65,110` +- **Why weird:** The field is described inline as "The token to poll for result asynchronously". The name `dataToken` doesn't communicate that — it sounds like a token that wraps data. The JSDoc even admits that `data_token` and `statement_id` (in the parent type) are the *same value* on the wire ("The statement_id should be identical to data_token in SuccessStatus and PendingStatus."). The fact that the wire has two names for the same value (one is the polling cursor, the other is the audit-log identifier) is a wire-protocol decision that leaks into the TS surface. +- **Category:** 1 (vague — `dataToken` could mean anything), 5 (cryptic abbreviation — "data" of what?), 12 (duplicate concept — `dataToken` and `statementId` are the same value), 19 (underspecified ID — see also #11). +- **Suggested name:** `pollToken` or `pollingToken` (matches its purpose). If the duplication with `statementId` is fixed at the wire level, drop entirely. +- **Rationale:** A field whose JSDoc says "this is identical to another field" is screaming for a rename. `pollToken` describes its function; `dataToken` describes its construction. + +### 11. `statementId` field — `src/v1/model.ts:102` +- **Why weird:** A field called `statementId` appearing on `QueryResponseStatus`, accompanied by a 4-line JSDoc explaining that it is "created for audit logging purpose to record the statement_id of all QueryResponseStatus". So this is an audit-only field that duplicates `dataToken`. In a typed API, an audit-only field is something the client should *never* set or rely on — but the type doesn't say `readonly` and there's no convention enforcing that. +- **Category:** 6 (misleading — looks like a regular ID, is audit-only), 12 (duplicate concept), 19 (underspecified — what kind of "statement"? Compare to `statementexecution` package's `statementId` which means the SQL Statement Execution API ID). +- **Suggested name:** `auditStatementId` (or remove from the public surface). If kept, document `@readonly`. +- **Rationale:** Audit/log-only fields on a typed response are a footgun. The current name promises usability; the doc explains it isn't. + +### 12. `tokens` field — `src/v1/model.ts:13,76` +- **Why weird:** Field called `tokens` with example value `EC0A..ChAB7WCEn_4...`. The JSDoc only shows one example; no plural-form documentation. The wire spec apparently allows multiple tokens (since the field is `string[]`), and the SDK serializes the array via `String(req.tokens)` — which means JS does `tokens.join(',')` (the array's default `toString`). This is fragile: if a token ever contains a comma, the URL becomes corrupt. The name `tokens` doesn't communicate "comma-separated on the wire". +- **Category:** 1 (vague — `tokens` of what?), 5 (cryptic — token value example dominates over a description), 6 (misleading — the array-to-string conversion is implicit). +- **Suggested name:** `pollTokens` (matches the proposal in #10). If the wire really expects comma-separated, document that on the field; otherwise use `URLSearchParams.append` per-token. +- **Rationale:** The name `tokens` is too generic for a top-level request field. The hidden join-on-comma is a bug magnet. + +### 13. `dashboardName` field — `src/v1/model.ts:14,51,77` +- **Why weird:** Field is `dashboardName` but appears alongside `dashboardRevisionId`. The pairing `Name` + `Id` is inconsistent — they should be either both names or both IDs. The wire calls the first one `dashboard_name` and the second `dashboard_revision_id`, so the asymmetry is upstream — but a TS SDK could rename for symmetry. The JSDoc says: "Dashboard name and revision_id is required to retrieve PublishedDatasetDataModel". The casual `_id`/`Id` shift is jarring. +- **Category:** 17 (asymmetric pair naming — `Name` vs `Id`). +- **Suggested name:** `dashboardId` + `dashboardRevisionId` (if both are IDs on the wire) or document why one is "name" while the other is "ID". +- **Rationale:** Symmetric pair fields should have symmetric naming. A user looking at the request would assume `Name` is human-readable and `RevisionId` is opaque — but typically both are opaque identifiers in published-dashboard URLs. + +### 14. `overrideWarehouseId` field — `src/v1/model.ts:54` +- **Why weird:** Field name is fine in isolation, but unusual that there is no plain `warehouseId` field for context. The JSDoc explains: "A dashboard schedule can override the warehouse used as compute for processing the published dashboard queries". Reading the model in isolation, a user has no way to know that *not* setting `overrideWarehouseId` means the dashboard's *configured* warehouse is used. The name carries baggage that requires reading the JSDoc to decode. +- **Category:** 1 (vague — "override" of what?), 6 (misleading — implies a write to a property, is actually an optional override). +- **Suggested name:** Keep but make sure the JSDoc is exhaustive about the fallback behaviour. Alternatively `warehouseIdOverride` (English noun order — read "the override of warehouseId"). +- **Rationale:** Override-fields are common; the only fix is documentation. Flagged for consistency. + +### 15. `dashboardRevisionId` field — `src/v1/model.ts:15,52,78` +- **Why weird:** The wire format on the published dashboard URL uses `dashboard_revision_id`. The TS name flatten-converts. But internally this is the "version" of the dashboard, and the broader SDK uses `revision` and `version` inconsistently (e.g., `apps` package uses `currentRevision`, etc.). Verifying SDK-wide vocabulary would be valuable. +- **Category:** 17 (potential inconsistency with sibling SDK packages — flagged for review). +- **Suggested name:** Keep as-is unless a wider SDK convention dictates `version`. +- **Rationale:** Low confidence; flagged to ensure SDK consistency check. + +### 16. `marshalExecutePublishedDashboardQueryRequestSchema` — `src/v1/model.ts:209` +- **Why weird:** Single longest exported name in the model file (50 characters). Six stacked qualifiers: `marshal`+`Execute`+`PublishedDashboardQuery`+`Request`+`Schema`. Required to be camelCase to fit ESLint. Almost impossible to read aloud. +- **Category:** 5 (cryptic — visual density), 7 (overly verbose), 8 (redundant suffix — `Request`+`Schema` is two layers of meta). +- **Suggested name:** `encodePublishedQueryRequest` (drop `Execute`, `Dashboard`, `Schema` — the function takes a `PublishedQueryRequest` and the input/output are obvious). +- **Rationale:** A function name should fit a short line. 50 characters of qualifiers is a sign that several layers of abstraction are leaking into the identifier. + +### 17. `marshalRequest` vs. `parseResponse` — `src/v1/utils.ts:119,113` +- **Why weird:** Same problem as `dataclassification.md` Findings #17, #18. The asymmetric verb pair (`marshal` vs. `parse`) doesn't say what they do (encode/decode JSON). Both functions are generic — they accept any payload, not specifically requests/responses. The names lie about the constraint. +- **Category:** 1 (vague), 14 (Go-style `marshal`), 17 (asymmetric verb pair). +- **Suggested name:** `encodeJson(data, schema)` + `decodeJson(body, schema)`. +- **Rationale:** Same as in `dataclassification.md`. The generator emits these into every package, so the fix is generator-wide. + +### 18. `executeCall` / `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Same as `dataclassification.md` Finding #15. Two `execute*` functions for two layers (retry/rate-limit shell vs. actual HTTP). The name `executeCall` doesn't say what about the call is being executed. +- **Category:** 1, 12, 17. +- **Suggested name:** `runWithPolicies` (outer) + `sendHttpRequest` (inner). +- **Rationale:** Generator-wide pattern, fix once. + +### 19. `buildHttpRequest` — `src/v1/utils.ts:96` +- **Why weird:** Same as `dataclassification.md` Finding #16. "Build" implies builder pattern; this is a 16-line object-literal helper used 4× per client method. +- **Category:** 1, 6. +- **Suggested name:** `makeHttpRequest` or inline. +- **Rationale:** Generator-wide. + +### 20. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Same as `dataclassification.md` Finding #20. Generic name for a stream-drain helper. +- **Category:** 1, 5. +- **Suggested name:** `drainStream`. + +### 21. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Same as `dataclassification.md` Finding #21. Type called `Options` but is an internal context bag. +- **Category:** 1, 8. +- **Suggested name:** `HttpCallContext`. + +### 22. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +- **Why weird:** Same as `dataclassification.md` Finding #22. Generic constant name. +- **Category:** 1. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. + +### 23. `Call` type and `call` variable — `src/v1/client.ts:85,117,157` +- **Why weird:** Same as `dataclassification.md` Finding #24. Three-way collision: `Call` type, `call` variable, "the API call" semantics. +- **Category:** 1, 12. +- **Suggested name:** `sendRequest` for the variable. + +## Low severity + +### 24. `Client` constructor — `src/v1/client.ts:50-64` +- **Why weird:** The constructor accepts `ClientOptions` but doesn't validate the options beyond `host`. Other fields (`logger`, `credentials`) use `??`-default and never warn about missing values. Naming is fine; behaviour is worth flagging for consistency with other SDK packages. +- **Category:** N/A (behavioural). + +### 25. `respBody` vs `resp` locals — `src/v1/client.ts:89,94,121,126,161,166` +- **Why weird:** Same as `dataclassification.md` Finding #26. Stage names are abbreviated and similar. +- **Category:** 5, 17. +- **Suggested name:** `rawBody` + `result`. + +### 26. `httpReq` local — `src/v1/client.ts:88,120,160` +- **Why weird:** Same as `dataclassification.md` Finding #27. Two `req`s in scope: `req: CancelPublishedQueryExecutionRequest` and `httpReq: HttpRequest`. +- **Category:** 5, 12. +- **Suggested name:** `httpRequest` (no abbreviation). + +### 27. `cancelPublishedQueryExecution` method — `src/v1/client.ts:67` +- **Why weird:** The method is verbose (29 characters) and contains the package name `queryExecution` already. Once `Client` is renamed `QueryExecutionClient`, the package context becomes explicit and the method name should shrink to `cancelPublished` or `cancelPublishedQuery`. The current form reads as `QueryExecutionClient.cancelPublishedQueryExecution(...)` — "queryExecution" twice. +- **Category:** 7 (overly verbose), 12 (duplicate concept — `QueryExecution` in both class and method). +- **Suggested name:** `cancelPublishedQuery` (or `cancel` if the package is renamed per #1). + +### 28. `executePublishedDashboardQuery` method — `src/v1/client.ts:107` +- **Why weird:** Same redundancy as #27 — `executePublishedDashboardQuery` repeats the package's domain. After renaming class to `PublishedDashboardQueryClient`, the method should just be `execute`. +- **Category:** 7 (overly verbose). +- **Suggested name:** `execute` (in renamed client) or `executePublishedQuery`. + +### 29. `pollPublishedQueryStatus` method — `src/v1/client.ts:139` +- **Why weird:** Inconsistency: `cancelPublishedQueryExecution` uses `QueryExecution` while `pollPublishedQueryStatus` uses `QueryStatus`. So the cancel-side mirrors the *operation* word, the poll-side mirrors the *response* word. The three method names all sound like sibling operations but use three different stems: + - `cancelPublishedQueryExecution` + - `executePublishedDashboardQuery` + - `pollPublishedQueryStatus` +- **Category:** 17 (inconsistent action-verb stem — three different patterns for three sibling methods). +- **Suggested name:** Make the stem identical: `cancelPublishedQuery` / `executePublishedQuery` / `pollPublishedQueryStatus` (or remove the `Status` suffix to match: `pollPublishedQuery`). + +### 30. `truncated` field on `SuccessStatus` — `src/v1/model.ts:112` +- **Why weird:** Field called `truncated`. The JSDoc says "Whether the query result is truncated (either by byte limit or row limit)". The naming is OK in context, but the field stands alone on `SuccessStatus` and tells the user nothing about *what* limit was hit. Compare: `statementexecution` package uses the same name (`truncated`) with the same vagueness — so the inconsistency is cross-package, not local. +- **Category:** 1 (vague — truncated by what?), 12 (cross-package duplicate of `statementexecution`'s `truncated`). +- **Suggested name:** Document on the type, or split into `truncatedByByteLimit?: boolean` / `truncatedByRowLimit?: boolean`. + +### 31. Lowercase `c` in JSDoc comment opening — `src/v1/model.ts:6,42,68` +- **Why weird:** The JSDoc starts with lowercase: "cancel query request for published Dashboards" (line 6), "Execute query request for published Dashboards" (line 42 — that one starts uppercase, inconsistent), "poll query request..." (line 68). Inconsistent comment style and lowercase sentence openings. Project convention is "Comments should always be proper sentences ending with a period" — these violate it. +- **Category:** N/A (style, not naming) — flagged because the prompt requested "EVERY type, field, ... and method"; the JSDoc affects the type's apparent name. +- **Suggested name:** N/A (fix prose, not name). + +### 32. `$case` discriminator field — `src/v1/model.ts:29-31,91-95` +- **Why weird:** The dollar-sign-prefixed discriminator `$case` is non-standard JS/TS convention. It mimics protobuf-ts and ts-proto outputs. To a TS developer not coming from protobuf, the `$` prefix is jarring (and clashes with `$`-prefixed special properties in many libraries like jQuery). The discriminator should follow standard TS tagged-union convention (`kind`/`type`/`tag`). +- **Category:** 14 (Go/proto-style import — `$case` is a ts-proto convention). +- **Suggested name:** `kind` or `tag`. The standard TS pattern is `{kind: 'success'; success: ...}` (no `$`). +- **Rationale:** Other parts of the SDK may already use `$case` — this is a generator-wide concern. Flagged here for completeness. + +## Observations + +### 33. Cross-package vocabulary drift — `statementexecution` / `queryhistory` / `queries` overlap +- **Description:** Five overlapping concepts span four packages: + - **`statementexecution.StatementStatus_State`** = `PENDING | RUNNING | SUCCEEDED | FAILED | CANCELED | CLOSED` (6 states) + - **`queryexecution.QueryResponseStatus`** = `success | pending | canceled | closed` (4 arms — no `running` or `failed`) + - **`queryhistory.QueryStatus`** = `QUEUED | STARTED | COMPILING | COMPILED | RUNNING | CANCELED | ...` (many more) + - **`statementexecution.statementId`** = SQL Statement Execution API ID + - **`queryexecution.statementId`** = "audit logging" field that duplicates `dataToken` + - **`queryhistory.QueryFilter.statement_ids`** = filter by statement IDs + + Three packages each have a `Status`/`State` enum, none of them compatible, all describing roughly the same SQL execution lifecycle. +- **Category:** 12 (duplicate concepts across packages), 17 (inconsistent vocabulary). +- **Recommendation:** Document the relationship in a shared glossary. Long-term, unify the status types or at least the state names. + +### 34. Vocabulary collision: `query` vs. `statement` vs. `execution` +- **Description:** The SDK uses three near-synonymous nouns: + - **`query`** — appears in `queryexecution`, `queryhistory`, `queries`. Generally means a SQL query (often a saved one). + - **`statement`** — appears in `statementexecution` and as `statementId` in `queryexecution`. Means a SQL statement (the SQL Execution API's unit of work). + - **`execution`** — appended to both above (`queryexecution`, `statementexecution`). + And the wire layer adds a fourth: `lakeview-query` (the URL in this package). +- **Category:** 12 (duplicate concepts), 14 (vocabulary inconsistency). +- **Recommendation:** Pick a vocabulary and use it consistently. SQL Statement Execution API uses "statement"; published dashboard queries use "query". Document the distinction in the SDK README. + +### 35. JSDoc grammar errors / wire-layer leakage +- **Description:** Multiple JSDocs reference internal wire terminology not relevant to a TS user: + - "rpc calls to sql-exec-api" (lines 10, 73 — internal service name) + - "PublishedDatasetDataModel" (line 48 — Java class name) + - "lakeview-config" (line 45 — internal service) + - "google.protobuf.Empty" (line 36 — proto definition leak) +- **Category:** N/A (documentation leakage). +- **Recommendation:** Generator should strip wire-layer references from public JSDoc. + +### 36. Comment style violations +- **Description:** Per the project rule "Comments should always be proper sentences ending with a period", many JSDocs in this file start lowercase ("cancel query request..."), are sentence fragments ("Example: EC0A..."), or omit terminal periods. Generator-wide. +- **Category:** N/A (style). + +## Domain glossary +- **Lakeview** — Databricks' notebook-style published dashboards product. +- **Published dashboard** — A dashboard configured to run "as the publisher" (publisher's identity, publisher's warehouse) rather than the viewer's. This is the entire reason this package exists. +- **Embedded dashboard** — A dashboard rendered outside the Databricks UI (e.g., in a customer's site). Triggers the "publisher mode". +- **`sql-exec-api`** — Internal service that runs the SQL; referenced in JSDoc but not in TS names. +- **`lakeview-config`** — Internal service that stores the dashboard configuration (warehouse, datasets, embedded credentials); referenced in JSDoc. +- **`dataToken`** / **`statementId`** — Same value on the wire, two field names: `dataToken` is for polling, `statementId` is for audit-logging. +- **`PublishedDatasetDataModel`** — Internal Java class referenced in JSDoc; holds the published-dashboard datasets, warehouse_id, and embedded_credentials. + +## File coverage +- `src/v1/model.ts` (220 lines): read fully. +- `src/v1/client.ts` (175 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (21 lines): read fully. diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md new file mode 100644 index 00000000..a6b59cac --- /dev/null +++ b/.agent/naming-audit/queryhistory.md @@ -0,0 +1,360 @@ +# Naming Audit: queryhistory + +**Path:** `packages/queryhistory/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. +**Total weird names flagged:** 47 + +## Summary +| Severity | Count | +| --- | --- | +| High | 8 | +| Medium | 19 | +| Low | 16 | +| Observation | 4 | + +## High severity + +### 1. `ListQueries` — request type named with a verb — `src/v1/model.ts:131` +- **Why weird:** Top-level interface called `ListQueries`. Verb-as-noun: `ListQueries` is grammatically a command (the *action*), not a *thing*. Every other Databricks SDK package uses `ListRequest` (e.g. `ListAlertsRequest`, `ListJobsRequest`) for the request body. The mismatch shows up at the call site: + ```ts + async listQueries(req: ListQueries, options?: CallOptions) + ``` + reads as "list queries, given a thing called listQueries", which is circular. The companion response is `ListQueries_Response` (see #2), which makes the pair look like a single message split into req/resp halves — but the request half drops the `Request` suffix. +- **Category:** 13, 14, 17 (verb-tense inconsistency; Go/Java-style name; inconsistent action verbs) +- **Suggested name:** `ListQueriesRequest`. +- **Rationale:** Aligns with every other package in the SDK and removes the verb-as-noun footgun. Pair becomes `ListQueriesRequest` / `ListQueriesResponse`, matching `alerts`, `jobs`, etc. + +### 2. `ListQueries_Response` — proto-style nested message — `src/v1/model.ts:153` +- **Why weird:** Identifier with an underscore (`ListQueries_Response`). TypeScript identifier convention is camelCase / PascalCase — no underscores. The file silences the lint with an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive. This is a leak of the upstream proto schema (`ListQueries.Response` nested message) into the TS surface. Consumers writing `import type { ListQueries_Response }` see an obvious foreign convention. +- **Category:** 4, 14 (underscores in TS identifiers; Go/Java-style names) +- **Suggested name:** `ListQueriesResponse` (drop the underscore; align with `ListQueriesRequest` from #1). +- **Rationale:** TypeScript Handbook & Google TS style guide both forbid underscores in identifier names except for unused-arg `_` and well-known constants. The proto nesting is an implementation detail of the wire schema; the public TS surface should not carry the underscore. Two of the three `_`-bearing identifiers in this package come from the same proto pattern (see also `ExternalQuerySource_JobInfo`). + +### 3. `ExternalQuerySource_JobInfo` — proto-style nested message — `src/v1/model.ts:116` +- **Why weird:** Same as #2. Underscore in identifier, lint disabled with the same `Proto-style nested message name.` comment. Also: the name `JobInfo` is generic ("info" is a category-1 vague suffix — "info about what state?"), and it duplicates the concept of a "job source" already implied by the outer field name `jobInfo: ExternalQuerySource_JobInfo`. Three "info" tokens stack up: `ExternalQuerySource.jobInfo: ExternalQuerySource_JobInfo`. +- **Category:** 1, 4, 14, 8 (vague suffix; underscore; Go/Java-style; redundant suffix `Info`) +- **Suggested name:** `ExternalQuerySourceJob` (drop `_` and `Info`). Or, if the type is only ever used as the nested shape, inline it directly into `ExternalQuerySource` and remove the wrapper entirely. +- **Rationale:** A plain `ExternalQuerySource.job: { jobId, jobRunId, jobTaskRunId }` is clearer than a top-level companion type. If a named type is needed, `ExternalQuerySourceJob` reads as "the job-source variant of an external query source." The current name puts `Info` in two places (parent field + type suffix) and reads as if it were a generic settings struct. + +### 4. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:179` +- **Why weird:** The most central type in the package — the value returned from `listQueries` — is named `QueryInfo`. "Info" is a category-1 vague suffix; almost every field on it is a first-class property of a *query* (`queryId`, `queryText`, `status`, `userId`, `queryStartTimeMs`, ...). The type *is* the query — there is no other `Query` type for `QueryInfo` to disambiguate from. Compare with Go SDK convention where `*Info` types are common, but in TS the suffix is non-idiomatic; e.g. `alerts.Alert`, `jobs.Job`, `clusters.ClusterInfo` (this last one is the exception, also flagged in another audit). The endpoint URL is `/api/2.0/sql/history/queries` — the resource is "queries", so the response item should be `Query`. +- **Category:** 8, 14, 1 (redundant `Info` suffix; Go/Java-style; vague suffix) +- **Suggested name:** `Query`. +- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #5) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. + +### 5. `ListQueries_Response.res` — cryptic field — `src/v1/model.ts:158` +- **Why weird:** A top-level response field named `res`. Two characters. Could mean *result*, *resource*, *response*, *reservation*, *reservoir*. The doc comment is empty. Every comparable list response in this SDK names its payload field something like `alerts`, `clusters`, `dashboards`, etc. (matching the resource); the Databricks public docs page for this endpoint calls it `res` too — so this is a wire-format leak, not a TS naming choice. +- **Category:** 5, 1 (cryptic abbreviation; vague/generic) +- **Suggested name:** `queries`. +- **Rationale:** The field is `QueryInfo[]` (or `Query[]` after #4). `queries` is the obvious idiomatic name. Even keeping the wire form `res`, the TS surface can map `res` → `queries` in the unmarshal transform (the file already does property-renames everywhere — `query_id` → `queryId`, etc.). + +### 6. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:207` +- **Why weird:** `QueryInfo` has both `endpointId` (line 207) and `warehouseId` (line 234) and the doc on `endpointId` reads `Alias for warehouse_id.` Two fields, one underlying ID, both present on every response. Callers will pick one and silently miss the other if the server only fills one. The wire form has the same problem: `endpoint_id` and `warehouse_id` are independent JSON properties on the response. "Endpoint" is also outdated SQL Warehouse vocabulary (Databricks renamed SQL endpoints to SQL warehouses years ago); keeping it for backwards compatibility belongs in the wire layer, not the public TS type. +- **Category:** 12, 6 (duplicate concepts; misleading) +- **Suggested name:** Drop `endpointId`. If the server still returns it, alias inside the unmarshal: `warehouseId: d.warehouse_id ?? d.endpoint_id`. +- **Rationale:** Two fields with identical meaning is a perpetual source of `if (q.warehouseId !== undefined) ... else if (q.endpointId !== undefined) ...` chains in consumer code. The Go SDK already exposes both because it cannot collapse them without API breakage; TS can collapse and document the legacy wire name. + +### 7. `CHANNEL_NAME_*` redundant enum prefix — `src/v1/model.ts:5-11` +- **Why weird:** Every value of the `ChannelName` enum is prefixed with `CHANNEL_NAME_`: + ```ts + enum ChannelName { + CHANNEL_NAME_UNSPECIFIED = 'CHANNEL_NAME_UNSPECIFIED', + CHANNEL_NAME_PREVIEW = 'CHANNEL_NAME_PREVIEW', + CHANNEL_NAME_CURRENT = 'CHANNEL_NAME_CURRENT', + CHANNEL_NAME_PREVIOUS = 'CHANNEL_NAME_PREVIOUS', + CHANNEL_NAME_CUSTOM = 'CHANNEL_NAME_CUSTOM', + } + ``` + Call sites read `ChannelName.CHANNEL_NAME_PREVIEW`, doubling the token. The wire form preserves the prefix because protobuf requires globally unique enum value names, but TS enum values are already namespaced by their enum. +- **Category:** 2 (redundant enum prefix) +- **Suggested name:** `ChannelName.UNSPECIFIED | PREVIEW | CURRENT | PREVIOUS | CUSTOM` — keep the string value on the wire (`"CHANNEL_NAME_PREVIEW"`), strip the prefix from the TS member name. +- **Rationale:** Other enums in this very file — `QueryStatus`, `QueryStatementType`, `PlansState` — do not have this prefix. The inconsistency is jarring. Compare `QueryStatus.QUEUED` to `ChannelName.CHANNEL_NAME_PREVIEW`. + +### 8. `ChannelName.CHANNEL_NAME_UNSPECIFIED` — proto-style sentinel exposed — `src/v1/model.ts:6` +- **Why weird:** `UNSPECIFIED` is protobuf's zero-value sentinel — it exists to satisfy proto3's "default value" rule. Exposing it in the public TypeScript surface forces consumers to handle a value that means "the server forgot to set this field." In TS the equivalent is `undefined`, which the field already permits (`name?: ChannelName | undefined`). So a `ChannelName` value can be `undefined`, `'CHANNEL_NAME_UNSPECIFIED'`, or one of the real channel names — three states where two would suffice. +- **Category:** 6, 14 (misleading; Go/Java-style) +- **Suggested name:** Drop `CHANNEL_NAME_UNSPECIFIED`. If the server sends it, unmarshal it to `undefined`. +- **Rationale:** Clean TS surface. Same comment applies to other `_UNSPECIFIED` sentinels that might appear elsewhere in the SDK (not present in this file's other enums, which is correct). + +## Medium severity + +### 9. `PlansState` — vague type name — `src/v1/model.ts:14` +- **Why weird:** "Plans state" — state of what? The JSDoc clarifies: "Possible Reasons for which we have not saved plans in the database." So the enum is really an "outcome" or "save status" — not a runtime state of a plan. The values include `EXISTS`, `EMPTY`, `IGNORED_*`, `UNKNOWN` — these are storage outcomes, not lifecycle states. Calling them a "state" is misleading. +- **Category:** 1, 6 (vague; misleading) +- **Suggested name:** `PlanStorageStatus` or `QueryPlansAvailability`. +- **Rationale:** Reflects what the value actually represents. Also fixes the singular/plural smell: `PlansState` (plural noun + singular state) reads oddly; `PlanStorageStatus` is uniformly singular. + +### 10. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` +- **Why weird:** Within the same enum: `EXISTS` is a verb (present tense), `EMPTY` is an adjective, `IGNORED_*` is a past participle, `UNKNOWN` is an adjective. Four grammatical categories for the same set of states. A consumer using one value learns the wrong pattern for the next. +- **Category:** 13 (verb-tense inconsistency) +- **Suggested name:** Normalize on adjectives/past participles: `AVAILABLE`, `EMPTY`, `IGNORED_SMALL_DURATION`, `IGNORED_LARGE_SIZE`, `IGNORED_SPARK_PLAN_TYPE`, `UNKNOWN`. +- **Rationale:** Internal consistency. `AVAILABLE` is also more accurate than `EXISTS` (the plans exist *somewhere*; the value means they exist *in storage*). + +### 11. `PlansState.IGNORED_LARGE_PLANS_SIZE` — overly verbose and grammatically off — `src/v1/model.ts:18` +- **Why weird:** The token `PLANS_SIZE` reads as "size of plans" but in the same enum's context (`PlansState`), the *plans* are already implied. So the value is "plans state: ignored because the plans size is too large for the plans" — redundant. Also `LARGE_PLANS_SIZE` is awkward English: "large plans size" vs "large plan size" or just "large size". +- **Category:** 7, 18 (overly verbose; long enum values) +- **Suggested name:** `IGNORED_LARGE_SIZE` (or `IGNORED_TOO_LARGE`). +- **Rationale:** Removes the redundant `PLANS` and fixes the grammar. + +### 12. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` +- **Why weird:** The value mentions "Spark plan type" — Spark is a Databricks implementation detail and the doc comment references three internal flags: `isIgnoredSparkPlanType`, `isIgnoredSparkPlanName`, `isDeltaLogScan`. SDK consumers shouldn't need to know about Spark's plan taxonomy. Also, the value name only references one of the three reasons — what if it's `isDeltaLogScan` or `isIgnoredSparkPlanName`? The value is one enum entry for three distinct causes. +- **Category:** 1, 6 (vague; misleading) +- **Suggested name:** `IGNORED_FILTERED_TYPE` (broader, doesn't leak Spark vocabulary), or split into three values matching the three internal flags. +- **Rationale:** Either generalize or specialize — but not both. + +### 13. `QueryStatementType.OTHER` and `CALL` — `src/v1/model.ts:30,53` +- **Why weird:** `OTHER` (line 30) is a vague catch-all. `CALL` (line 53) has a JSDoc comment "SQL Script" — so `CALL` doesn't mean what it says (SQL `CALL` statement); it means "SQL Script". The doc/value mismatch is misleading. +- **Category:** 1, 6 (vague; misleading) +- **Suggested name:** Keep `OTHER`. Rename `CALL` → `SCRIPT` (matches the JSDoc); alternatively keep `CALL` and remove the misleading JSDoc. +- **Rationale:** Either the value name should match its meaning or the comment is wrong. + +### 14. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:84` +- **Why weird:** `CANCELED` (single-l, US) where most JavaScript ecosystems use `cancelled` (double-l) and at minimum should be consistent with the rest of the codebase. More importantly: every other `QueryStatus` value is a past participle (`QUEUED`, `STARTED`, `COMPILED`, `FAILED`, `FINISHED`) or `-ING` (`COMPILING`, `RUNNING`). `CANCELED` fits the past-participle pattern — flag only for spelling. +- **Category:** 13 (verb-tense — minor) plus orthographic +- **Suggested name:** Keep `CANCELED` if that matches the wire (and project-wide policy); flag for cross-package consistency. +- **Rationale:** The W3C HTML spec uses `cancelled`; Node.js, the DOM, and most npm packages use `canceled`. The wire form here is `"CANCELED"`, so the TS surface should match. Just record the choice. + +### 15. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:67,77` +- **Why weird:** Both enum values are documented as `DEPRECATED: to be removed once runtime side change is picked up.` Yet they're exported in `index.ts` (since `QueryStatus` is) and have no JSDoc `@deprecated` tag. IDE autocomplete will offer them indistinguishably from current values. +- **Category:** 11 (effectively dead) plus tooling concern +- **Suggested name:** No rename. Add `@deprecated` JSDoc on each so IDEs show the strikethrough and the doc surfaces in tooltips. +- **Rationale:** TypeScript honors `@deprecated` in completions; the current comment is informational only. + +### 16. `QueryStatementType` — verbose discriminator — `src/v1/model.ts:29` +- **Why weird:** Type name pairs the resource word (`QueryStatement`) with the discriminator suffix (`Type`). Three nouns stack: a query has a *statement* which has a *type*. The actual values are SQL keywords (`SELECT`, `INSERT`, ...), which are statement *kinds*, not types in the TS sense. Compare `Aggregation` in `alerts/v2`, which uses a single domain noun. +- **Category:** 8, 7, 20 (redundant suffix; verbose; type-suffix tautology) +- **Suggested name:** `StatementKind`. (`Type` is reserved by TypeScript's own `type` keyword for type aliases, so `Kind` is conventional in enums representing categories of a thing.) +- **Rationale:** Disambiguates from TS's `type` and shortens the name. + +### 17. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:197,199` +- **Why weird:** Two `*End*Ms` fields next to each other. The doc comments are: `The time execution of the query ended.` (executionEndTimeMs) and `The time the query ended.` (queryEndTimeMs). Are these different? When? The metrics type later splits time into `compilationTimeMs`, `executionTimeMs`, `resultFetchTimeMs` — so plausibly "execution end" is after spark execution but before fetch, while "query end" is after fetch. The TS types do not encode this. A reader has to guess. +- **Category:** 1, 6, 19 (vague; misleading; underspecified time field) +- **Suggested name:** Keep both names but rewrite the docs to spell out the relationship and the relative ordering (`queryStartTimeMs ≤ executionEndTimeMs ≤ queryEndTimeMs`). Optionally rename to `executionEndTimeMs` / `resultsDeliveredTimeMs`. +- **Rationale:** This is the kind of field that turns into a billing/SLA bug if confused. The audit is naming-only, but the names *here* are the source of the confusion. + +### 18. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:213` +- **Why weird:** Field documented as `A key that can be used to look up query details.` Look up *where*, with *what API*, returning *what*? `queryId` already serves that purpose. The two coexist on the same response with no explanation. `lookupKey` is vague (lookup what?), undefined-purpose, and parallel to `queryId`. +- **Category:** 1, 12 (vague; duplicate concepts) +- **Suggested name:** Rename to indicate destination — e.g. `detailsLookupKey` or `historyLookupKey`, plus a doc that references the related API. +- **Rationale:** Without an explanation, this looks like a synonym for `queryId`. Drop it from public surface if it has no consumer use. + +### 19. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:217,219` +- **Why weird:** Four user-identity fields on one type: `userId`, `userName`, `executedAsUserId`, `executedAsUserName`. The "executed as" pair models impersonation/run-as. Good intent, but the field names don't make the relationship clear (user1 ran-as user2). Compare `alerts.v2.Alert.runAsUserName` vs `Alert.runAs.userName` for a different (also problematic) approach to the same concept. +- **Category:** 12, 1 (duplicate concepts; vague) +- **Suggested name:** Group into a sub-object: `submitter: { id, name }`, `runAs?: { id, name }`. Or rename to `submittedByUserId/Name` + `executedAsUserId/Name`. +- **Rationale:** Pairing the two roles symmetrically (submitter / runAs) makes the relationship explicit at the type level. The current names ("user" without qualifier on one pair, "executedAsUser" on the other) implies the bare `user*` is the *original* user, but doesn't say so. + +### 20. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:203` +- **Why weird:** Field documented as `The email address or username of the user who ran the query.` So `userName` is a union of two unrelated identifier formats with no way to tell them apart at the type level. Same problem on `executedAsUserName`. +- **Category:** 6, 15 (misleading; generic field losing meaning) +- **Suggested name:** `userIdentifier` or `userPrincipal`, with the doc noting it can be either. Or split into `userEmail?` / `userLoginName?`. +- **Rationale:** `userName` strongly implies a `username` (login handle), not an email. Half of integration code will assume that and break. + +### 21. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:205` +- **Why weird:** `sparkUiUrl` exposes an internal Spark UI URL. "Spark UI" is a Databricks Runtime implementation detail; SDK consumers shouldn't need to know that the link goes to "Spark UI" specifically. The URL is functionally "query plan / execution diagnostics UI" — the name pins it to one particular implementation. +- **Category:** 14 (Go/Java-style; leaks internal taxonomy) +- **Suggested name:** `queryPlanUrl` or `executionPlanUrl`. +- **Rationale:** Decouples the public API from Spark's internal nomenclature. + +### 22. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:207,234` +- **Why weird:** Cross-reference of #6: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). +- **Category:** 19, 16 (underspecified ID; field contradicting type domain) +- **Suggested name:** See #6. + +### 23. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:224` +- **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. +- **Category:** 15, 19 (generic field; underspecified ID) +- **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. +- **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. + +### 24. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:226` +- **Why weird:** Field doc: `Whether more updates for the query are expected.` So `isFinal: true` means the query result is *complete and won't change*. The name `isFinal` is conventionally used for things like inheritance ("can't be subclassed") or compilation ("final pass"). `isComplete`, `isTerminal`, or `isSettled` would be clearer. +- **Category:** 1, 6 (vague; misleading) +- **Suggested name:** `isSettled` or `isTerminal` (matches the `QueryStatus` terminal states). +- **Rationale:** The name should describe the state, not the absence of updates. + +### 25. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:228` +- **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #4 / general pattern). Reads as "channel-used info" — three nouns. +- **Category:** 8, 7 (redundant `Info`; verbose; verb-as-modifier) +- **Suggested name:** `channel: Channel`. (Rename type `ChannelInfo` → `Channel`.) +- **Rationale:** Symmetry with `warehouseId`, `userId`, etc. — bare noun. + +### 26. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:215,239` +- **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. +- **Category:** 12, 1 (duplicate concepts; vague) +- **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. +- **Rationale:** Two times on one type, both unitless in the name (`duration` doesn't say ms), invites confusion. + +### 27. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:239` +- **Why weird:** Every other time field has a `Ms` suffix (`queryStartTimeMs`, `executionEndTimeMs`, `queryEndTimeMs`, `totalTimeMs`, etc.). `duration` does not. The type is `number`. The doc says "Total time of the statement execution" with no unit. Reader must guess. +- **Category:** 15, 19 (generic field losing meaning; underspecified) +- **Suggested name:** `durationMs`. (See also #26.) +- **Rationale:** Internal consistency with every other time field in the file. + +## Low severity + +### 28. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:245` +- **Why weird:** `clientApplication: string` returns names like "Databricks SQL Editor, Tableau, and Power BI" — these are *application names*, not application IDs. The doc even disclaims "values are expected to remain static over time, this cannot be guaranteed." So the field is a free-text label, not a stable identifier. Name doesn't reflect that. +- **Category:** 15 (generic field losing meaning) +- **Suggested name:** `clientApplicationName` or `clientAppLabel`. +- **Rationale:** Marks the field as a display label rather than an ID. + +### 29. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:250,252` +- **Why weird:** "Query source" / "external query source" / "cache query ID" — three different ways the type talks about the origin of a query. `querySource` is the *upstream entity* (dashboard, notebook, alert, job, ...); `cacheQueryId` is the *prior query that supplied a cached result*. Conceptually unrelated, but the field names rhyme. +- **Category:** 12 (duplicate concepts — only superficial) +- **Suggested name:** Keep `querySource`. Rename `cacheQueryId` → `cachedFromQueryId`. +- **Rationale:** Makes the semantic distinction explicit. + +### 30. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:101,103` +- **Why weird:** Two dashboard-related ID fields on the same type. `legacyDashboardId` implies pre-Lakeview dashboards (the JSDoc on `dashboardId` is "this Lakeview dashboard"). Both can be set simultaneously? The semantics are not encoded — should be a discriminated union (`{ kind: 'lakeview', id } | { kind: 'legacy', id }`). +- **Category:** 12, 19 (duplicate concept; underspecified) +- **Suggested name:** Keep the names; consider a `kind` discriminator. At minimum, document the mutual exclusivity. +- **Rationale:** Documentation fix more than naming. + +### 31. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:105,109,112` +- **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. +- **Category:** 19 (underspecified) +- **Suggested name:** As above — convert to discriminated union. +- **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. + +### 32. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:122` +- **Why weird:** Three IDs on one type: `jobId`, `jobRunId`, `jobTaskRunId`. The naming is consistent and self-documenting. `jobTaskRunId` (one identifier for "task run within a job run") could be ambiguous: is it the run-ID of a *task* (with `jobRunId` being the run-ID of the whole job), or vice versa? The doc says `The canonical identifier of the task run.` — confirms the former. +- **Category:** 19 (underspecified) +- **Suggested name:** Acceptable; if confusion arises, rename to `taskRunIdWithinJobRun`. +- **Rationale:** Documentation is sufficient. + +### 33. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:263,271,281,287` +- **Why weird:** Four time fields; the relationship is `totalTime ≥ compilationTime + executionTime + resultFetchTime` (roughly), and `executionTime` aggregates `taskTotalTime` and `photonTotalTime`. The names don't encode the hierarchy; a developer must read all four docs to understand. Individually each name is OK. +- **Category:** 1 (vague — collectively) +- **Suggested name:** Keep, but add a JSDoc on `QueryMetrics` summarizing the hierarchy. +- **Rationale:** Documentation > rename. + +### 34. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:321` +- **Why weird:** Phrase rather than a noun. Doc says "remaining work to be done... deprecated: using projected_remaining_task_total_time_ms instead". So this is a deprecated field with a name that reads like English prose ("work to be done") rather than a TS identifier. Reads awkwardly: `metrics.workToBeDone`. +- **Category:** 7, 14 (verbose; Go/Java-style phrase) +- **Suggested name:** Already deprecated. If kept for back-compat, that's fine. New consumers should use `projectedRemainingTaskTotalTimeMs`. +- **Rationale:** Will be removed; flag for awareness only. + +### 35. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:326` +- **Why weird:** Doc says `number of remaining tasks to complete, calculated by autoscaler StatementAnalysis.scala. deprecated: use remaining_task_count instead`. So `runnableTasks` actually means "remaining tasks" — name and meaning don't align. Also deprecated. +- **Category:** 6, 1 (misleading; vague) +- **Suggested name:** Deprecated. Use `remainingTaskCount`. Flag for awareness. +- **Rationale:** Same as #34. + +### 36. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:328,335` +- **Why weird:** 32-char and 33-char field names. Five tokens each (`projected/remaining/task/totalTime/Ms`). Long enough that they wrap in editors and IDE tooltips. The doc on the second one says `projected lower bound on remaining total task time based on projected_remaining_task_total_time_ms / maximum concurrency` — the *name* doesn't say "wall-clock" is the divided-by-concurrency version. `WallclockTime` is the differentiator from `TaskTotalTime`. +- **Category:** 7 (overly verbose) +- **Suggested name:** Acceptable given the precision required. Could shorten `projectedRemainingWallclockTimeMs` → `projectedRemainingWallTimeMs`. +- **Rationale:** Marginal. + +### 37. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:273,275,277,279,293,297,337` +- **Why weird:** Seven `*Bytes` fields, each with subtly different scopes (remote vs cache vs disk vs network vs file vs pruned vs spill). Each individual name is OK; together they form a glossary the reader has to internalize. Also: `spillToDiskBytes` is a verb phrase (`spill to disk`) where peers are noun phrases (`read remote`, `write remote`). Inconsistent grammatical shape. +- **Category:** 13 (verb-tense — minor) +- **Suggested name:** `diskSpillBytes` (noun phrase, parallels `prunedBytes`, `readCacheBytes`). +- **Rationale:** Symmetry. + +### 38. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:265,337` +- **Why weird:** Two read-bytes fields. Doc on `readBytes`: `Total size of data read by the query, in bytes.` Doc on `readFilesBytes`: `Total number of file bytes in all tables read`. The difference is "file bytes" vs general "bytes" — possibly identical, possibly not. Names don't disambiguate. +- **Category:** 12, 1 (duplicate concepts; vague) +- **Suggested name:** Rename `readBytes` → `totalReadBytes` and `readFilesBytes` → `readFileBytes` (singular "file" since each row counts). +- **Rationale:** Distinguishes scope. + +### 39. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:283,297,299,337` +- **Why weird:** Inconsistent pluralization: `readFilesCount` (plural files) vs `prunedFilesCount` (plural files). OK, consistent there. But `readFilesBytes` is also plural where `readFilesCount` follows the same form — consistent. Then we have `readPartitionsCount` (plural). All consistent. Then `taskTotalTimeMs` is singular. The pattern across the type isn't uniform. +- **Category:** 9 (singular/plural mismatch — across fields) +- **Suggested name:** Pick one form. `readFileBytes` / `readFileCount` / `readPartitionCount` (singular, the way English does for counts) reads more naturally. +- **Rationale:** Minor consistency win. + +### 40. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:267, 209` +- **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. +- **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) +- **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. +- **Rationale:** Same value reachable through two paths is a maintenance hazard. + +### 41. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:304,309,311` +- **Why weird:** Three time fields use `*Timestamp` suffix; everywhere else in the file the convention is `*TimeMs`. The `Timestamp` fields are documented as Unix-epoch-milliseconds too, so the unit is the same — just the naming convention differs. Mixing two suffixes for the same kind of value is a category-13 inconsistency. +- **Category:** 13, 19 (verb-tense / convention inconsistency; underspecified — timestamp vs duration) +- **Suggested name:** `provisioningQueueStartTimeMs`, `overloadingQueueStartTimeMs`, `queryCompilationStartTimeMs`. +- **Rationale:** Consistent suffix across all time-valued fields. + +### 42. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:316` +- **Why weird:** Field name has "OverTimeRange"; type is `TaskTimeOverRange`. Different naming. Field is `taskTimeOver` + `TimeRange`; type is `TaskTime` + `OverRange`. Semantically the same, named differently. +- **Category:** 9, 20 (singular/plural; type-suffix tautology) +- **Suggested name:** Align: `taskTimeOverRange: TaskTimeOverRange` (drop second `Time`). +- **Rationale:** Field name should match type name shape. + +### 43. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:351,360` +- **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. +- **Category:** 1 (vague — `Entry`) +- **Suggested name:** Optional rename to domain names. +- **Rationale:** Marginal. + +### 44. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:362` +- **Why weird:** Only field on the type. The doc says "total task completion time in this time range" — name reads as "task completed time" (past participle). `taskCompletionTimeMs` would be a noun-phrase form and match peer fields. +- **Category:** 13 (verb-tense — past participle vs noun) +- **Suggested name:** `taskCompletionTimeMs`. +- **Rationale:** Noun form is more conventional. + +### 45. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:367,369` +- **Why weird:** Generic type name `TimeRange` lives in a domain package. It's used once (`QueryFilter.queryStartTimeRange: TimeRange`). The field name `queryStartTimeRange` then re-introduces "queryStart" — odd because the `TimeRange` is *for filtering* on query start time, but a `TimeRange` is just (start, end). Reading `queryStartTimeRange.startTimeMs` is "the start of the query-start-time range, in ms" — three "start"s in one expression. +- **Category:** 1, 7 (vague type name; verbose) +- **Suggested name:** Rename field to `submittedDuring: TimeRange` or `queryStartedBetween: TimeRange`. Or rename type to `MsRange` / `TimestampRange` (since the type is unit-specific). +- **Rationale:** Reduces "start" noise. + +### 46. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:172` +- **Why weird:** Doc says `Filtering for multiple statuses is not recommended. Instead, opt to filter by a single status multiple times and then combine the results.` This is a behaviour quirk; field name is fine. Flag for documentation polish. +- **Category:** observation +- **Suggested name:** Keep `statuses`; document why multi-filter is discouraged on the type, not just on the field. +- **Rationale:** Surfaces the constraint. + +### 47. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:346,347` +- **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. +- **Category:** 1 (vague) +- **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. +- **Rationale:** Minor. + +## Observations + +### O1. `Client` is the only exported class — `src/v1/client.ts:32` +- The class is just `Client`. Consistent across the SDK (so a project-level concern), but worth noting that `import { Client } from '@databricks/sdk-queryhistory/v1'` produces a bare name that collides with every other package's `Client`. Consumers must rename on import. + +### O2. `flattenQueryParams` exported but only used internally — `src/v1/utils.ts:123` +- `flattenQueryParams` is `export`ed from `utils.ts`, used in `client.ts`, and not re-exported from `index.ts`. Module-private would suffice, but the helper has to be cross-file. This is a generated-code pattern; flag at the generator level. (Identical to #15 in the `accountaccesscontrol` audit, suggesting this is package-wide.) + +### O3. `executeCall` and `executeHttpCall` — overlapping verb pair — `src/v1/utils.ts:26,65` +- Two functions, similar names, different purposes. `executeCall` is the public-`CallOptions` adapter; `executeHttpCall` is the wire-level executor. Names don't signal that one wraps the other. Could be `applyCallOptions` + `sendHttpRequest`. Generated-code concern. (See also the `accountaccesscontrol` audit O2.) + +### O4. `marshalRequest` exported but unused — `src/v1/utils.ts:119` +- `marshalRequest` is `export`ed but `listQueries` doesn't use it (it marshals inline using `marshalQueryFilterSchema.parse(...)`). Either the helper is dead in this package or the generator emits it preemptively for other shapes. Should be removed if unused. + +## Cross-cutting themes + +1. **Proto-style identifiers leak through.** Underscored type names (`ListQueries_Response`, `ExternalQuerySource_JobInfo`), prefix-stuttering enum values (`CHANNEL_NAME_CHANNEL_NAME_PREVIEW`-style usage), and the `UNSPECIFIED` sentinel all read as proto and not TS. + +2. **The `Info` / `State` suffix habit.** `QueryInfo`, `ChannelInfo`, `PlansState` — bare-noun renames (`Query`, `Channel`, `PlanStorageStatus`) would be cleaner. `Info` is a category-1 vague suffix doing no work. + +3. **Time-field naming is inconsistent.** `*TimeMs` is the dominant convention, but `*Timestamp` appears three times and `duration` once with no unit. Same hierarchy across `QueryInfo` and `QueryMetrics` is hard to read without docs. + +4. **Multiple ways to identify one thing.** `endpointId` / `warehouseId`, `userName` (email-or-handle), `sessionId` (Spark Connect or DBSQL or SDP), `lookupKey` vs `queryId`. Each is a "two-fields-one-concept" or "one-field-multiple-concepts" smell. + +5. **Verbose generated-code residue.** `getAssignableRolesForResource`-style verbosity is mostly absent here (only one endpoint), but enum-value verbosity is high (`IGNORED_LARGE_PLANS_SIZE`, `CHANNEL_NAME_*`, `projectedRemainingTaskTotalTimeMs`). + +## Domain glossary +- **DBSQL** — Databricks SQL, the serverless warehouse engine. The SDK package targets `/api/2.0/sql/history/...`. +- **SDP** — Streaming/Serverless Data Pipelines (per the `sessionId` doc) — internal Databricks runtime. +- **Spark Connect** — Apache Spark's gRPC-based client/server protocol, distinct from DBSQL. +- **Channel** — A versioned SQL warehouse runtime track (Preview/Current/Previous/Custom). `ChannelInfo.dbsqlVersion` is the underlying version string. +- **Photon** — Databricks' native vectorized query engine; `photonTotalTimeMs` measures time spent in Photon-native execution. +- **Plans** — Query execution plans (logical/physical/spark). `PlansState` reports whether and why plans are stored. +- **Statement** — A SQL statement (one query). Aliased with "query" throughout this package; the `statementType` field captures `SELECT`/`INSERT`/etc. +- **Warehouse / Endpoint** — Same concept, two legacy names. SQL Warehouses (current) were originally called SQL Endpoints (legacy); the wire format keeps both fields. +- **Lakeview** — Databricks' newer dashboard product; `ExternalQuerySource.dashboardId` references it. `legacyDashboardId` references the older dashboards. +- **Genie space** — Databricks AI/BI assistant workspace; identified by `genieSpaceId`. +- **Provisioning queue / Overloading queue** — Two queue states a query passes through: waiting for a warehouse to spin up; waiting because the warehouse is overloaded. + +## File coverage +- `src/v1/model.ts` (615 lines): read fully. +- `src/v1/client.ts` (107 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (26 lines): read fully. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md new file mode 100644 index 00000000..94ddc0ba --- /dev/null +++ b/.agent/naming-audit/registeredmodels.md @@ -0,0 +1,521 @@ +# Naming Audit: `registeredmodels` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/registeredmodels/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Unity Catalog (UC) Model Registry — the UC-resident successor +to the legacy workspace-level `modelregistry` (MLflow-style) Model Registry. + +--- + +## Summary + +The `registeredmodels` package exposes ten UC model-registry operations +(`createRegisteredModel`, `deleteRegisteredModel`, `deleteModelVersion`, +`deleteRegisteredModelAlias`, `getRegisteredModel`, `getModelVersion`, +`getModelVersionByAlias`, `listRegisteredModels`, `listModelVersions`, +`setRegisteredModelAlias`, `updateRegisteredModel`, `updateModelVersion`) +plus two paginated iterators. The model layer is a verbatim 1:1 port of +the Go SDK, and most defects derive from upstream definitions. + +The dominant naming issues are (1) the path-parameter `*Arg` suffix +applied to fields that already encode their role through documentation +(`fullNameArg`, `versionArg`, `aliasArg`), (2) proto-style underscore +nested-message names leaking into TypeScript identifiers +(`DeleteModelVersion_Response`, `ListRegisteredModels_Response`, etc.), +(3) extremely heavy `Create*`/`Update*` request shapes that include +server-populated read-only fields (`createdAt`, `createdBy`, `updatedAt`, +`updatedBy`, `fullName`, `metastoreId`, `storageLocation`, `browseOnly`), +(4) collision-prone parallel concept naming versus the legacy +`modelregistry` package, and (5) singular/plural and redundant-prefix +problems on field names such as `versionNum`, `aliasName`, and +`modelName` inside `RegisteredModelAliasInfo`. + +--- + +## Findings + +### 1. Vague / generic names + +#### 1.1 `Dependency.value` (model.ts:91) +The discriminated-union body is wrapped in a generic `value` field — the +field carries the entire payload yet conveys no semantics. Most other +discriminated unions in the SDK either inline the `$case`/payload at the +top level or use a domain noun (`dependency`, `target`, `subject`). The +double-nesting (`d.value.$case === 'table'`, then `.table`) compounds the +opacity. Either drop the wrapper (move `$case` to the top of +`Dependency`) or rename to `dependency` so the access path reads +`dep.dependency.$case`. + +#### 1.2 `ModelVersionInfo.source` (model.ts:228) +`source` is a free-form string whose documentation reveals it is "URI +indicating the location of the source artifacts (files) for the model +version". A field named `source` on a model object is ambiguous — +`sourceUri`, `artifactUri`, or `artifactLocation` would communicate type +and purpose. The same misnaming appears on `UpdateModelVersion.source` +(model.ts:347). + +#### 1.3 `RegisteredModelAliasInfo.id` (model.ts:274), `ModelVersionInfo.id` (model.ts:263) +Both `RegisteredModelInfo`-adjacent payloads use bare `id` for two +*different* identifier kinds (the alias and the model version). The +reader cannot tell from the call site whether `info.id` is the alias's +identifier or the model version's identifier. Prefer `aliasId` and +`modelVersionId` to disambiguate (see also §16.1, §16.2). + +#### 1.4 `ModelVersionInfo.version` (model.ts:251), `UpdateModelVersion.version` (model.ts:370) +A field on a "model version" type called `version` is doubly redundant +*and* generic. The doc clarifies it is the "integer model version +number"; a name such as `versionNumber` (or the field already used +elsewhere, `versionNum`) would distinguish it from a semver-style version +string. Worse, `RegisteredModelAliasInfo` uses `versionNum` (line 272) +for the same concept — the inconsistency is internal (see §11.1). + +#### 1.5 `CreateRegisteredModel.name` (model.ts:23), `RegisteredModelInfo.name` (model.ts:285) +Bare `name` on a `RegisteredModel*` shape is informationless given the +surrounding type. The doc clarifies it is "the name of the registered +model" — `modelName` or `registeredModelName` would carry the type with +the field, especially since `fullName` and `catalogName` and `schemaName` +are siblings on the same shape. + +--- + +### 2. Redundant enum prefixes + +#### 2.1 `ModelVersionStatus.MODEL_VERSION_STATUS_UNKNOWN` (model.ts:6) +The only variant prefixed with `MODEL_VERSION_STATUS_` is the unknown +sentinel; the other three variants are bare (`PENDING_REGISTRATION`, +`FAILED_REGISTRATION`, `READY`). Read aloud: +`ModelVersionStatus.MODEL_VERSION_STATUS_UNKNOWN` repeats +`MODEL_VERSION_STATUS` twice. Should be `UNKNOWN` (or `UNSPECIFIED`, +the more common proto sentinel). The inconsistency between this variant +and the others is also a §3-class problem. + +--- + +### 3. Acronym casing inconsistencies (URI, UC, MLflow, ID) + +#### 3.1 `runId` versus `Id` (model.ts:235, model.ts:263, model.ts:382) +"ID" is a two-letter initialism. Google TS style guide states that +identifiers should follow `camelCase` and treat acronyms as words. The +package uses both `runId` (one-letter run + Id, fine) and `id` (lowercase +standalone), but for `runWorkspaceId` it lowercases `Id` correctly. The +issue is that `metastoreId`, `id`, and `runId` are all lowercase, while +`URI` appears nowhere as a field name (the `source` field would have +been a candidate, see §1.2). + +#### 3.2 `MLflow` in doc comments (model.ts:232-234, 351-353) +Doc comments spell it `MLflow` (correct trademark casing). No identifier +exists for MLflow here, but if one were added, follow the trademark +casing (`Mlflow*` would be wrong). + +#### 3.3 `` placeholder leakage (model.ts:237, 356) +JSDoc contains the literal token `` — clearly an +unresolved template marker from the upstream generator. It will render +poorly in IDE tooltips. Not a naming issue per se, but visible in the +audit surface; documentation hygiene. + +--- + +### 4. Underscores in TypeScript identifiers + +#### 4.1 `DeleteModelVersion_Response` (model.ts:66) +Proto-style nested-message naming converted to TS verbatim. Suppressed by +an `eslint-disable` for `@typescript-eslint/naming-convention`. TS +convention is `DeleteModelVersionResponse` (no underscore). The same +pattern appears on `DeleteRegisteredModel_Response` (model.ts:74), +`DeleteRegisteredModelAlias_Response` (model.ts:84), +`ListModelVersions_Response` (model.ts:168), and +`ListRegisteredModels_Response` (model.ts:211). + +Five distinct identifiers in this single file violate the naming +convention. The eslint suppression is acknowledged tech debt; the audit +must flag it nonetheless. + +#### 4.2 `unmarshalDeleteModelVersion_ResponseSchema` (model.ts:447) +The schema name carries the underscore through, since schemas are named +`unmarshalSchema`. Four additional instances: +`unmarshalDeleteRegisteredModel_ResponseSchema` (line 451), +`unmarshalDeleteRegisteredModelAlias_ResponseSchema` (line 455), +`unmarshalListModelVersions_ResponseSchema` (line 502), and +`unmarshalListRegisteredModels_ResponseSchema` (line 516). + +#### 4.3 Wire-format field names embedded as object keys +Throughout the marshal/unmarshal schemas (model.ts:431-905), the input +side uses `snake_case` keys (`connection_name`, `model_version_dependencies`, +`run_workspace_id`, `next_page_token`, etc.). This is correct — these +are wire-format keys, not TS identifiers, so they are exempt. Documenting +here for completeness. + +--- + +### 5. Cryptic abbreviations + +#### 5.1 `fullNameArg`, `versionArg`, `aliasArg` (model.ts:60, 62, 70, 78, 80, 123, 125, 134, 136, 143, 152, 322, 324, 337, 339, 389) +The `Arg` suffix is utterly cryptic to anyone outside the SDK team. It +hails from the upstream Go generator marking path-parameter fields. In +TypeScript identifiers like `fullNameArg`, `versionArg`, and `aliasArg` +read like leftover scaffolding. The path-parameter nature is invisible +to users and already documented prose-style ("The three-level (fully +qualified) name of the registered model"). Recommended names: +`fullName`, `version`, and `alias` — but those collide with response +fields, which is the actual problem (see §13.1 below). The right fix is +to drop the path-parameter fields from the request type entirely and +accept them as method positional arguments (mirroring how `getModelVersion` +already URL-encodes them). + +#### 5.2 `runId`, `runWorkspaceId` (model.ts:235, 240) +`runId` is conventional (MLflow run identifier), but in TS the +abbreviation chain `run` + `Id` reads oddly when paired with +`runWorkspaceId`. Consider `mlflowRunId` and `mlflowRunWorkspaceId` since +the doc comments already qualify these as MLflow-specific. + +#### 5.3 `versionNum` (model.ts:272, 326, 588, 798) +`Num` is a cryptic abbreviation for `Number`. Either spell out (`versionNumber`) +or drop entirely (`version` — but that collides with the model-version +field; see §11.1). + +--- + +### 6. Misleading names + +#### 6.1 `RegisteredModelAliasInfo.modelName` (model.ts:276) +The doc says "The name of the parent registered model of the model +version, relative to parent schema". This field is the *parent registered +model's* name, but the property is called `modelName` and lives on an +*alias* type that already nests under `RegisteredModelInfo`. A reader +sees `aliasInfo.modelName` and reasonably assumes it is the alias's own +model handle. Better: `parentModelName` or, since the alias is *on* the +registered model, simply omit the field (the parent is already known +from context). + +#### 6.2 `RegisteredModelAliasInfo.id` versus `RegisteredModelAliasInfo.aliasName` (model.ts:270, 274) +Two identifier-shaped fields on the same shape; the doc on `id` ("unique +identifier of the alias") suggests an internal opaque UUID, while +`aliasName` is the human-readable handle the API uses elsewhere. Calling +both "identifier" makes intent unclear. Rename `id` to `aliasUuid` or +`aliasId` (see §16.1). + +#### 6.3 `ModelVersionInfo.version` (model.ts:251) +The field name suggests a string/identifier ("v2", "v3"), but the type +is `number` and the doc clarifies it is the integer version number used +to reference the model version in API requests. The collision with +typical semantic versioning expectations is a real footgun. Rename +`versionNumber`. + +--- + +### 7. Overly verbose names + +#### 7.1 `marshalSetRegisteredModelAliasSchema` (model.ts:789) +Forty-character marshal-schema name. The verbosity flows from the +`SetRegisteredModelAlias` request type name, which itself is fine, but +worth noting that every marshal/unmarshal schema name carries this +verbosity tax. + +#### 7.2 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 504) +Method names hover around 30 characters. Java/Go style. In TS prefer +`setAlias` / `deleteAlias` on a `RegisteredModelsClient` whose role is +already established. The current names imply you could also call +`setUnregisteredModelAlias` or `setExperimentAlias` from the same client, +which you cannot. See also §12.1. + +--- + +### 8. Redundant suffixes + +#### 8.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) +The `*Info` suffix is a verbatim Go-ism. In TS the suffix adds nothing — +`RegisteredModel`, `ModelVersion`, and `RegisteredModelAlias` would be +the natural names. `*Info` is leftover from the proto/Go convention of +distinguishing a wire DTO from an in-memory entity in the same file. +TypeScript does not need the distinction. Compare with the legacy +`modelregistry` package, which uses bare names (`RegisteredModel`, +`ModelVersion`) — see §10.1. + +--- + +### 9. Singular / plural mismatches + +#### 9.1 `ListModelVersions` request, `ListModelVersions_Response.modelVersions` (model.ts:150, 169) +The request type is *plural* (`ListModelVersions`), the response +collection field is *plural* (`modelVersions`). Internally consistent. +However, the iterator method is `listModelVersionsIter` returning an +`AsyncGenerator` (singular) — the singular/plural +mismatch between the iterator's name (`listModelVersions*`, plural) and +its yield type (`ModelVersionInfo`, singular) is conventional but worth +noting. Same pattern on `listRegisteredModelsIter`. + +#### 9.2 `ListRegisteredModels` request paginates registered models; field is `registeredModels` (model.ts:212) +Same as 9.1; flagged for completeness. + +--- + +### 10. Reserved-word collisions + +#### 10.1 `Dependency.value.$case: 'function'` (model.ts:91-93) +`function` is a TS reserved keyword. The discriminant value happens to +be a string literal so it parses, but the projected `function` field +inside the union arm (`{$case: 'function'; function: FunctionDependency}`) +shadows the keyword. Valid TS, but it forces consumers to write +`if (dep.value.$case === 'function') { dep.value.function ... }` — +syntactically legal, ergonomically poor. The Go SDK uses +`Function FunctionDependency` (capitalized), avoiding the collision. + +#### 10.2 No other reserved words observed. +`name`, `version`, `comment`, `owner`, `aliases`, `dependencies`, etc. +are all safe. + +--- + +### 11. Duplicate concepts versus modelregistry / MLflow + +#### 11.1 `RegisteredModel` (modelregistry) versus `RegisteredModelInfo` (registeredmodels) +The legacy workspace-level package `modelregistry` already exports a +`RegisteredModel` type and a `ModelVersion` type (verified in +`/home/parth.bansal/sdk-js/packages/modelregistry/src/v1/model.ts:411-420`). +The UC-resident package re-uses the same domain noun with an `Info` +suffix (`RegisteredModelInfo`, `ModelVersionInfo`). A consumer +importing both packages will hold both `RegisteredModel` (from +modelregistry) and `RegisteredModelInfo` (from registeredmodels) for +fundamentally different APIs that nonetheless model the same concept. + +This is the single most confusing parallel-concept issue. Mitigations: +- Drop the `Info` suffix here so the types collide visibly and force + an import alias (`import {RegisteredModel as UcRegisteredModel}`), or +- Adopt distinct domain nouns (`UcRegisteredModel`, `CatalogModel`). + +#### 11.2 `CreateRegisteredModel` (registeredmodels) versus `CreateRegisteredModel` (modelregistry) +Same exact type name in both packages. Path-disambiguated only. +`grep -rn "CreateRegisteredModel" packages/` returns two identical +identifiers in two different namespaces; both are documented as +"Create a registered model" but mean different things. The collision +risk is identical for `DeleteRegisteredModel`, `GetModelVersion`, +`ListRegisteredModels`, and `ModelVersionStatus` (all share names with +the legacy `modelregistry` exports). + +#### 11.3 `ModelVersionStatus` collision (model.ts:5) +Identical enum name in `modelregistry/src/v1/model.ts:67-77`. The +*variants* are almost identical (`PENDING_REGISTRATION`, +`FAILED_REGISTRATION`, `READY`), except `registeredmodels` adds the +sentinel `MODEL_VERSION_STATUS_UNKNOWN`. A consumer who imports both +will see two enums of the same name describing nearly-the-same lifecycle +on two different APIs. This is high-risk for runtime bugs (passing one +package's enum value into the other compiles but does not match). + +#### 11.4 MLflow run linkage (`runId`, `runWorkspaceId`) +The UC model registry borrows MLflow concepts but uses generic field +names. A user familiar with MLflow's run IDs will recognise these; +others may not. Prefer `mlflowRunId` and `mlflowRunWorkspaceId` to +signal the foreign-concept boundary. + +--- + +### 12. Verb tense / parallel inconsistency + +#### 12.1 `versionNum` versus `version` (model.ts:251, 272, 326, 370) +`RegisteredModelAliasInfo.versionNum` and +`SetRegisteredModelAlias.versionNum` use `Num`. `ModelVersionInfo.version` +and `UpdateModelVersion.version` drop the suffix entirely. All four +fields are the same concept (integer model-version pointer). Pick one +spelling and apply uniformly. + +#### 12.2 `name` versus `modelName` versus `fullName` (model.ts:23, 222, 285, 299, 341) +On `RegisteredModelInfo`, `name` is the *short* registered-model name, +`fullName` is the three-level identifier, and `catalogName`/`schemaName` +are the parents. On `ModelVersionInfo`, `modelName` is the parent +registered model's short name. Three different conventions for the same +class of concept (name vs modelName vs fullName). A consistent scheme — +say, `shortName`, `fullName`, `parentModelName` — would help. + +#### 12.3 `nextPageToken` versus `pageToken` (model.ts:162, 174, 207, 217) +Request types use `pageToken`; response types use `nextPageToken`. This +asymmetry is conventional for cursored pagination, but the convention +should be documented somewhere (it isn't, here). Not a defect, but +flagged because it is a common reader stumbling block. + +--- + +### 13. Go / Java-style names + +#### 13.1 `Client.createRegisteredModel`, `Client.deleteRegisteredModel`, etc. +Verb + full-noun method names mirror the Go SDK's +`WorkspaceClient.RegisteredModels.Create` style. In idiomatic TS, the +client itself is namespaced (you import from `registeredmodels/v1`), so +the methods could be `create`, `delete`, `get`, `list`, `update`. The +current `createRegisteredModel` is doubly redundant with the package +name. Same for `getModelVersion`, `listRegisteredModels`, +`setRegisteredModelAlias`, `updateRegisteredModel`, +`updateModelVersion`, and so on (12 methods total). + +#### 13.2 `Info` suffix everywhere +Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §8.1. + +#### 13.3 PascalCase exported `Client` (client.ts:63) +The exported `Client` class is named bare-`Client`. Most TS SDKs export +a context-qualified name like `RegisteredModelsClient` or +`UcRegisteredModelsClient`. The bare `Client` works with the +`registeredmodels/v1` import path but causes name clashes if a consumer +imports from multiple SDK packages without aliases. Conventional Go +SDK pattern leaking into TS. + +--- + +### 14. Generic field names losing meaning + +#### 14.1 `Dependency.value` (model.ts:91) +See §1.1. + +#### 14.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 118, 317, 332, 425) +Four of the six dependency wrapper types use a `FullName` suffix on +their single string field (`tableFullName`, `functionFullName`, +`volumeFullName`, `secretFullName`), while two do not +(`connectionName`, `credentialName`). The docs claim all six are +fully-qualified names ("Full name of the dependent connection, in the +form of `__connection_name__`"). The naming should be uniform — either +add `FullName` to `connectionName` and `credentialName`, or drop the +suffix from the other four. + +#### 14.3 `CreateRegisteredModel.aliases` (model.ts:48), `UpdateRegisteredModel.aliases` (model.ts:417) +A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. +Aliases are normally set on already-existing models, not at create +time. The field is also marked optional. The name `aliases` is +descriptive; the problem is that its presence in the create-request +shape is semantically odd. Flagged for shape, not just naming. + +--- + +### 15. Field contradicting type domain + +#### 15.1 `CreateRegisteredModel.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId}` (model.ts:37-45) +`CreateRegisteredModel` is a *request* shape, yet it includes six +server-populated fields that the client cannot meaningfully set: +- `fullName` (computed from `catalogName.schemaName.name`) +- `createdAt`, `createdBy`, `updatedAt`, `updatedBy` (server-stamped) +- `metastoreId` (resolved server-side from the host) +- `browseOnly` (response-only flag) + +These fields belong on `RegisteredModelInfo` (the response). Their +presence on the create request misleads users into thinking they can +set creation timestamps or override the metastore. Same defect on +`UpdateRegisteredModel` (model.ts:387-419): all six are present plus +`name`, `catalogName`, `schemaName`, `storageLocation`, `aliases`, and +`browseOnly` — most of which are not actually updatable per the JSDoc +which says "only the name, the owner or the comment of the registered +model can be updated". + +#### 15.2 `UpdateModelVersion.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:335-385) +`UpdateModelVersion` carries *every* field from `ModelVersionInfo`. The +JSDoc says "Currently only the comment of the model version can be +updated". The shape is therefore deeply misleading: it presents 17 +optional fields where 16 are silently no-ops on the server. A user +setting `updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` +will see no effect from `status` but no error either. + +#### 15.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:276-281) +Three parent-locator fields on an alias type. The alias is already +nested inside `RegisteredModelInfo.aliases`, so the parent is known +from context. Embedding these makes the alias serialisable in +isolation but pollutes the shape. + +--- + +### 16. Underspecified IDs + +#### 16.1 `RegisteredModelAliasInfo.id` (model.ts:274) +"The unique identifier of the alias". No format constraint, no +mention of whether it is a UUID, a server-generated opaque token, or a +human-friendly slug. Type is `string`. Compare with the well-typed +`metastoreId` (which is also `string` but at least bound to a known +domain). Recommend `aliasId` and adding format hints in the doc. + +#### 16.2 `ModelVersionInfo.id` (model.ts:263) +"The unique identifier of the model version". Same issues as 16.1. +Recommend `modelVersionId`. + +#### 16.3 `RegisteredModelInfo.metastoreId` (model.ts:297) and `ModelVersionInfo.metastoreId` (model.ts:254) +"The unique identifier of the metastore". Acceptable name but worth +flagging that the format (UUID? slug?) is not specified anywhere in +the doc. + +#### 16.4 `ModelVersionInfo.runWorkspaceId` (model.ts:240) +`number` typed. The doc says "ID of the Databricks workspace". Workspace +IDs in Databricks are 64-bit integers — TS `number` is only safe up to +2^53. This is a *type* concern, but the name `runWorkspaceId` does not +flag the underlying integer-width risk; consider `string` per Go's +`json:",string"` tag treatment. + +--- + +### 17. Type-suffix tautology + +#### 17.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) +See §8.1. The `Info` suffix is tautological because the type already +*is* the info; it does not need to be marked as such. Compare with the +parallel `modelregistry` package which uses bare `RegisteredModel` / +`ModelVersion`. + +#### 17.2 `*Schema` suffix on every marshal/unmarshal export +`marshalCreateRegisteredModelSchema`, `unmarshalRegisteredModelInfoSchema`, +etc. (35+ exports). The `Schema` suffix is tautological with the +prefix `marshal`/`unmarshal` (these are always schemas). Could be +`marshalCreateRegisteredModel` and `unmarshalRegisteredModelInfo`. Not +a high-impact finding; consistency note. + +--- + +## Cross-cutting observations + +### A. Doc-comment typos + +Two instances of `recieve` (sic) in `client.ts:356` and `client.ts:426`, +both in `listModelVersions` and `listRegisteredModels` JSDoc. Not a +naming issue but visible in IDE tooltips alongside every flagged +identifier. + +### B. Parallel package collision risk + +A consumer that imports both `modelregistry` and `registeredmodels` will +encounter colliding identifiers for: `ModelVersionStatus`, +`CreateRegisteredModel`, `DeleteModelVersion`, `DeleteModelVersion_Response`, +`DeleteRegisteredModel`, `DeleteRegisteredModel_Response`, +`GetModelVersion`, `ListRegisteredModels`, `ListRegisteredModels_Response`, +and the `Client` class. Importing both *requires* aliasing on every +single one of those names. This is the biggest practical naming defect +of the package. + +### C. Request shapes leak response/server fields + +`CreateRegisteredModel`, `UpdateRegisteredModel`, and especially +`UpdateModelVersion` carry the entire response shape on the request side. +This is a *type-design* defect surfaced via *naming* (a field called +`createdAt` on a "create" request is meaningless). See §15. + +### D. Path-parameter fields with `Arg` suffix + +`fullNameArg`, `versionArg`, `aliasArg` appear on every request type +that hits a parameterised URL. Fifteen occurrences across `model.ts`. +The suffix is incomprehensible to anyone who hasn't read the generator +source. Should either (1) drop the suffix and accept the collision with +response fields, (2) lift these fields to positional method arguments, +or (3) document the convention package-wide. See §5.1. + +--- + +## Recommendations (priority-ordered) + +1. **Drop `*Arg` suffix** on path-parameter fields; lift to positional + method arguments where they conflict with response fields. (§5.1, §D) +2. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, + `RegisteredModelAliasInfo`. (§8.1, §17.1) +3. **Disambiguate parallel-package collisions** with `modelregistry` — + either re-namespace or rename types. (§11, §B) +4. **Strip server-populated fields** from `CreateRegisteredModel`, + `UpdateRegisteredModel`, `UpdateModelVersion` request shapes. (§15, §C) +5. **Unify `versionNum` versus `version`** on a single spelling. + (§12.1) +6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§16) +7. **Rename `source`** to `artifactUri` or `sourceUri`. (§1.2) +8. **Drop `MODEL_VERSION_STATUS_` prefix** from + `ModelVersionStatus.UNKNOWN`. (§2.1) +9. **Fix `recieve` typos** in client.ts JSDoc. (§A) + +--- diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md new file mode 100644 index 00000000..d348c61d --- /dev/null +++ b/.agent/naming-audit/repos.md @@ -0,0 +1,496 @@ +# Naming Audit: repos + +**Path:** `packages/repos/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-repos` (the `repos` directory + module name +use the abbreviation, while the JSDoc throughout the file consistently spells +the resource as "Git folder (repo)"). +**Inferred domain:** Databricks "Repos" API — a workspace-level CRUD surface +for "Git folders" (formerly "Repos"): linkable workspace mount points that +track a remote Git repository at a given branch/tag/commit, optionally with +sparse-checkout configuration. Five operations: +`create/get/list/update/delete`. The API endpoint stays `POST /api/2.0/repos` +even though the product was rebranded to "Git folders". One resource type +(`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, +`SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set +`provider` values appearing in JSDoc on five fields. +**Total weird names flagged:** 41 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". Every JSDoc string in the package uses the form "Git folder (repo)". The package, type, method, and field names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | +| 2 | `Repo` as the resource noun | model.ts (throughout) | concept | High | 1 Vague/generic, 5 Cryptic abbreviations | The TS resource type is `RepoInfo`. The JSDoc clarifies: "Git folder (repo) information". The product UI calls it "Git folder". The Go SDK source uses `Repo`. JS-side could use the rebranded name (`GitFolder`/`GitFolderInfo`) or at least spell out the abbreviation (`Repository`). The wire URL still says `repos` so URL renaming is not possible, but the TS types are free. | +| 3 | `RepoInfo` interface | model.ts:111 | interface | Medium | 20 Type-suffix tautology, 1 Vague/generic | The `Info` suffix is a Java/proto idiom that does not match TS norms. The interface *is* the repo — there is no `Repo` type that `RepoInfo` is "info about". `Repo` (or `GitFolder` per H1) without `Info` would be cleaner. (See also `CredentialInfo` in the `credentials` audit, M-pattern.) | +| 4 | `CreateRepo_Response` (proto-style underscore) | model.ts:29 | interface | High | 4 Underscores in TS identifiers | Proto-message-nested-message-encoded-as-underscore. Carries an inline `// eslint-disable-next-line @typescript-eslint/naming-convention` comment — the generator already knows the name violates the project's own convention. Standard TS idiom would be `CreateRepoResponse` (no underscore), or — since the response is a `RepoInfo` shape — `RepoInfo` directly. | +| 5 | `GetRepo_Response` (proto-style underscore) | model.ts:64 | interface | High | 4 Underscores in TS identifiers, 12 Duplicate concepts | Field-for-field identical to `CreateRepo_Response` and `RepoInfo`. Same eslint-disable. | +| 6 | `ListRepos_Response` (proto-style underscore) | model.ts:100 | interface | High | 4 Underscores in TS identifiers | Same eslint-disable. The body is `{repos: RepoInfo[], nextPageToken}` — the only `_Response` type with a non-redundant shape. | +| 7 | Five `*_Response` types each carry inline `// eslint-disable-next-line @typescript-eslint/naming-convention` | model.ts:28, 55, 63, 99, 170 | interface set | High | 4 Underscores in TS identifiers | Five disables in one file. Plus another five on the marshal/unmarshal schemas (model.ts:173, 195, 199, 220, 260) — ten total disables. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. | +| 8 | `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 232-250 — sixty lines of duplicated logic). `CreateRepo_Response` and `GetRepo_Response` should be type aliases of `RepoInfo`. | +| 9 | `DeleteProject` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProject` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project` name in the entire package — every other operation uses `*Repo`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | +| 10 | `Client.deleteProject` (method name on a `repos` client) | client.ts:105 | method | High | 6 Misleading names, 17 Inconsistent action verbs | The client method is `deleteProject` even though the package is `repos`, the URL is `/repos/{id}`, the JSDoc says "Deletes the specified repo", and the four sibling methods are `createRepo`, `getRepo`, `listRepos`, `updateRepo`. Should be `deleteRepo`. Reads as: `client.createRepo(...)`, `client.getRepo(...)`, `client.deleteProject(...)`, `client.updateRepo(...)` — the inconsistency is loud. | +| 11 | `provider` field typed as `string` (should be enum) | model.ts:15, 41, 76, 123 | field | High | 6 Misleading names, 15 Generic field names | JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. Mirrors `gitProvider` in the `gitcredentials` audit (H6, #12). | +| 12 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` wire values (in JSDoc) | model.ts:9-13, 37-39, 72-75, 119-121 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Same as `gitcredentials` audit #13. Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (lower-case G at the boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" TS field-name convention. Values dictated by the API server. | +| 13 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | +| 14 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | +| 15 | `awsCodeCommit` wire value (deprecated, untagged) | model.ts:13, 40, 76, 122 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Same as `gitcredentials` audit #16. | +| 16 | `path` field (resource location, no qualifier) | model.ts:20, 33, 68, 115 | field | Medium | 1 Vague/generic, 15 Generic field names | Workspace path of the Git folder. JSDoc on `CreateRepo.path` describes it as "Desired path for the repo in the workspace". On `RepoInfo.path` it says "Root path of the git folder (repo) in the Workspace". The bare `path` is ambiguous — could be a filesystem path, a URL path, a remote-side path. `workspacePath` would self-document and distinguishes from `url` (the remote-side address). | +| 17 | `url` field | model.ts:7, 35, 70, 117 | field | Medium | 1 Vague/generic, 15 Generic field names | The remote Git repository URL. JSDoc: "URL of the Git repository to be linked" / "URL of the linked Git repository" / "URL of the remote git repository". `gitRepositoryUrl` or `remoteUrl` would self-document; bare `url` is generic enough that a reader unfamiliar with the API has to read the doc to know which URL. (`pathPrefix` and `path` already live nearby, both string-typed.) | +| 18 | `id` field (`number` type, no qualifier) | model.ts:31, 52, 60, 66, 113, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter for delete/get/update is `id`. The JSDoc on each clarifies it is "the ID for the corresponding repo to delete" / "ID of the Git folder (repo) object in the workspace". The same value never appears as `repoId` or `gitFolderId` — bare `id` everywhere. Same problem as `gitcredentials` audit H5 / #24, but here even the response types call it `id` (model.ts:31, 66, 113), not the cross-naming `credentialId` pattern. So at least it's internally consistent — just underspecified. `repoId` or `gitFolderId` would self-document. | +| 19 | `headCommitId` field | model.ts:45, 80, 127 | field | Low | 5 Cryptic abbreviations | "Head Commit ID" is fine, but "head" is a Git term that requires knowing Git internals to parse. JSDoc says "SHA-1 hash representing the commit ID of the current HEAD of the Git folder (repo)". The "ID" suffix is also slightly misleading because the value is a SHA-1 hash, not a numeric/UUID identifier. `headSha` / `currentCommitSha` would be more honest. (Listing as Low because Git users will read this fine.) | +| 20 | `branch` field on `UpdateRepo` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepo` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 21 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:252-258 vs 286-292 — duplicated marshal logic). One is used in `CreateRepo`/responses; the other only in `UpdateRepo`. The shapes have no semantic difference. Should be one type. | +| 22 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | +| 23 | `pathPrefix` field on `ListRepos` | model.ts:91 | field | Low | (none) | Standard list-filter field. JSDoc clarifies the semantics. Listing for completeness. | +| 24 | `nextPageToken` field on `ListRepos` / `ListRepos_Response` | model.ts:96, 107 | field | Low | (none) | Standard pagination token. Internally consistent. Listing for completeness. | +| 25 | `repos` field on `ListRepos_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | +| 26 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | +| 27 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 130, 158, 212, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #9/#10, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | +| 28 | `Client.listReposIter` (iter suffix vs full word) | client.ts:191 | method | Medium | 5 Cryptic abbreviations, 17 Inconsistent action verbs | The `*Iter` suffix is a Go/Rust idiom; TS idiom for async-generator iteration is to either:
- Use `*Stream` / `*All` / `*AsObservable`, or
- Just expose an `[Symbol.asyncIterator]()` method on the result.
The `Iter` abbreviation is also opaque — readers will think "is it `iter` (iterator) or `iter` (iterate)?" Full word `iterate` or `pages`/`stream` would clarify. (Generator-wide pattern; flag once.) | +| 29 | `listReposIter` returns `AsyncGenerator` (per-item) but the underlying call is per-page | client.ts:191 | method | Low | 6 Misleading names | The user sees a single async generator of items but each `for await` of `next` may quietly trigger an HTTP call (every Nth iteration). Memory consumption and latency depend on page size, but the caller has no signal of that. JSDoc is absent. Recommendation: at least document the per-page behavior. (Same finding repeated across iterator audits.) | +| 30 | `unmarshalCreateRepo_ResponseSchema` (and four siblings) | model.ts:174, 196, 200, 221, 261 | const set | High | 4 Underscores in TS identifiers, 14 Go/Java-style names, 20 Type-suffix tautology | Five `unmarshal*_ResponseSchema` consts plus three `unmarshal*Schema` consts (`unmarshalRepoInfoSchema`, `unmarshalSparseCheckoutSchema`) plus the matching marshal-side consts. Each `*_Response*` schema carries `// eslint-disable-next-line @typescript-eslint/naming-convention`. The names pile up three type-suffix words: `CreateRepo_ResponseSchema` is "Repo" + "Response" + "Schema", each implying the others. | +| 31 | `marshal*Schema` / `unmarshal*Schema` const naming | model.ts:174, 196, 200, 221, 232, 252, 261, 264, 278, 286, 294 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go idioms; `Schema` is tautological with `z.ZodType`. TS-canonical pair is `encode`/`decode`. Generator-wide pattern (also flagged in every prior audit). | +| 32 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | +| 33 | `parseResponse` vs `marshalRequest` (mixed action verbs) | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | One side says `parse`, the other says `marshal`. Should be either `parse`/`format` or `marshal`/`unmarshal`. | +| 34 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | +| 35 | `PACKAGE_SEGMENT` const | client.ts:44 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. Same flag as every prior audit. | +| 36 | `host` field replacement (`replace(/\/$/, '')`) | client.ts:62 | (logic, not name) | Low | 6 Misleading names | The `host` field actually holds a base URL with trailing slash stripped — not just a host. `baseUrl` would be more honest. (Same misnomer as in the other clients.) | +| 37 | `userAgent` private field | client.ts:56 | field | Low | (none) | Standard, consistent. Listing for completeness. | +| 38 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 134, 216 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 39 | `CreateRepo` (no body wrapper for fields) | model.ts:5 | interface | Medium | 9 Singular/plural mismatches | The endpoint is `POST /api/2.0/repos` (plural collection URL). The request type is `CreateRepo` (singular noun). The response is `CreateRepo_Response`. Singular naming matches Go-SDK convention but reads inconsistently with the wire URL. Compare to the `gitcredentials` audit (H2), which has the opposite problem — there the wire URL is plural and the request type is also plural for a single-resource op. Here the wire URL is plural and the request is singular. Pick one rule. | +| 40 | `RepoInfo` doc says "Git folder (repo) information" | model.ts:110 | doc | Low | 6 Misleading names | The doc consistently uses the form "Git folder (repo)" (e.g., model.ts:30, 32, 42, 44, 46, 59, 65, 81, 89, 101, 110, 112, 114, 124, 126, 128). The type name says only "Repo". Either the doc is overspecified (parenthetical "(repo)" is redundant) or the type name is underspecified. Pick one. | +| 41 | `RepoInfo.path` doc says "Root path" but `CreateRepo.path` and `GetRepo_Response.path` say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo`/`GetRepo_Response`/`CreateRepo_Response` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | +| 42 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types (e.g., `CreateRepo_Response`) consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | +| 43 | `provider` field doc enumerates eight values inline (each ~25 chars) | model.ts:9-13, 37-39, 72-75, 119-121 | doc | Low | 7 Overly verbose | The JSDoc for `provider` on `CreateRepo`, `CreateRepo_Response`, `GetRepo_Response`, and `RepoInfo` enumerates 6-8 values inline. The enumeration is duplicated four times (the generator emits the same text four times in one file). If it were a typed enum (H4), the JSDoc could be on the enum once. | +| 44 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepo`/`UpdateRepo`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | +| 45 | `path` collides with Node.js global `path` module | model.ts:20, 33, 68, 91, 115 | field | Low | 10 Reserved-word collisions | `path` is a common identifier name in TS/Node (`import * as path from 'node:path'`). Local field `path` shadows the import in many codebases. Not a TS reserved word, but a high-shadowing-risk identifier. | + +--- + +## High severity (must fix) + +### H1. "Repos" is the legacy term; the product is "Git folders" + +The package name (`repos`), the resource type (`RepoInfo`), the five client +methods (`createRepo`, `getRepo`, `listRepos`, `updateRepo`, +`deleteProject` (!)), and the response field (`repos`) all use the legacy +term "Repos". The Databricks product UI, marketing, and docs have rebranded +this resource to "Git folders". + +The JSDoc *throughout the file* uses the form "Git folder (repo)" — i.e., +the generator already knows the rebrand happened. Twenty-three doc strings +use "Git folder (repo)". Zero doc strings use only "Repo". + +Two possible fixes: + +1. **Rename the TS surface to `GitFolder`** — preserve the wire URL + (`/api/2.0/repos`) but expose `GitFolder`, `GitFoldersClient`, + `createGitFolder`, etc. on the TS side. The zod transform layer can map + `gitFolder` ↔ JSON keys. This costs one breaking SDK change for one + product alignment that reads honestly. +2. **Keep `Repo` but at least make it consistent** — drop `_Response` types, + stop using the legacy word "Project" (see H2), and decide on `Repo` (not + "Repository") everywhere. + +The package can also adopt the gitcredentials-style hyphenation: rename to +`@databricks/sdk-git-folders` (or just `@databricks/sdk-gitfolders`). + +### H2. `DeleteProject` — leftover "Project" name on one operation + +```ts +export interface DeleteProject { + /** The ID for the corresponding repo to delete. */ + id?: number | undefined; +} +export interface DeleteProject_Response {} +``` + +```ts +async deleteProject(req: DeleteProject, options?: CallOptions): Promise +``` + +The Databricks API endpoint is `DELETE /api/2.0/repos/{id}`. The doc says +"Deletes the specified **repo**". Every sibling type/method uses `Repo`: +`CreateRepo` / `GetRepo` / `ListRepos` / `UpdateRepo`. Only `DeleteProject` +uses the legacy word "Project". + +The likely history: `Repos` was internally called "Workspace Projects" at +one point, and the `Delete` operation's request envelope was never renamed +on the Go SDK side. The JS SDK is a 1:1 port, so the legacy name leaks +through. + +Reads to a consumer as: + +```ts +// Surreal because deleteProject deletes a repo, not a project. +const client = new ReposClient(opts); +await client.createRepo({...}); // OK +await client.deleteProject({id: 1}); // Wait, what? +``` + +Recommendation: rename `DeleteProject` → `DeleteRepo`, method +`deleteProject` → `deleteRepo`. The wire URL doesn't change. This is a +pure TS-side rename that fixes a readability footgun. If the Go SDK keeps +the legacy name (likely it does), file an upstream cleanup request. + +### H3. Five `_Response` types use proto-style underscores + +`CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, +`ListRepos_Response`, `UpdateRepo_Response` — plus the five +`*_ResponseSchema` consts — all carry inline `// eslint-disable-next-line +@typescript-eslint/naming-convention` comments (ten disables total in one +model.ts file). The presence of those disables is the loudest possible +signal that the names violate the project's own conventions. + +Standard TS idiom would be `CreateRepoResponse` (PascalCase, no +underscore), nested in a namespace. + +### H4. Three field-for-field-identical "Repo" shapes + +`RepoInfo`, `CreateRepo_Response`, and `GetRepo_Response` all have the same +seven fields with the same types, the same optionality, the same JSDoc +text, and three copies of the same zod transform body +(model.ts:174-193 vs 200-218 vs 232-250). Two of the three are redundant. + +Recommendation: + +```ts +// Before +export interface CreateRepo_Response { /* 7 fields */ } +export interface GetRepo_Response { /* same 7 fields */ } +export interface RepoInfo { /* same 7 fields */ } + +// After +export interface Repo { /* 7 fields */ } +// Return Repo directly from create() and get(). +``` + +### H5. `provider` is typed `string` but is closed-set + +```ts +provider?: string | undefined; +``` + +JSDoc enumerates eight values: `gitHub`, `bitbucketCloud`, `gitLab`, +`azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, +`gitLabEnterpriseEdition`, `awsCodeCommit`. The set is closed; the API +server rejects other values. But the TS-side surfaces it as `string`, so: + +- No autocomplete on the value list. +- No compile-time check for typos (`gitub` will type-check). +- The JSDoc casing inconsistencies (`gitHub` vs `gitLabEnterpriseEdition`) + cannot be fixed at the call site, only by the API server. + +Recommendation: emit a string-literal union or enum. The casing problem +(#12) gets handled there. This is identical to the `gitcredentials` audit +H6 — the same field appears in both packages, neither has an enum, both +duplicate the eight-value enumeration inline. + +### H6. `id` is underspecified + +`id?: number` appears on `DeleteProject`, `GetRepo`, `UpdateRepo`, +`RepoInfo`, `CreateRepo_Response`, and `GetRepo_Response`. JSDoc on each +says "ID of the Git folder (repo) object in the workspace". The name is +just `id`. + +When a caller writes: + +```ts +const repo = await client.getRepo({id: 42}); +const cred = await gitCredClient.getCredential({id: 42}); +const someThirdThing = {id: 42}; +``` + +— the `42` is type-checked as `number` everywhere, but `42`-the-repo and +`42`-the-credential are not the same domain. `repoId` would catch the +cross-resource confusion in TS. (The wire format uses `id` in path +parameters; TS can rename in the zod transform.) + +### H7. `Client.deleteProject` mid-CRUD-set + +The package's `Client` class exposes: + +```ts +client.createRepo(req) // ✓ +client.getRepo(req) // ✓ +client.listRepos(req) // ✓ +client.listReposIter(req) // ✓ +client.deleteProject(req) // 🚨 different noun +client.updateRepo(req) // ✓ +``` + +Five methods read uniformly; one does not. Renaming `deleteProject` → +`deleteRepo` is a one-line fix on the TS side that materially improves +readability. See H2 for the full discussion. + +### H8. `SparseCheckout` vs `SparseCheckoutUpdate` (identical shapes) + +```ts +interface SparseCheckout { patterns?: string[] | undefined } +interface SparseCheckoutUpdate { patterns?: string[] | undefined } +``` + +Both have the same doc string ("Sparse checkout configuration, it contains +options like cone patterns."), both zod transforms are identical +(model.ts:252-258 vs 286-292). The only difference is which top-level +request type holds them — `CreateRepo` holds `SparseCheckout`; `UpdateRepo` +holds `SparseCheckoutUpdate`. + +Recommendation: one type, used by both. The Go-SDK likely keeps the two +separate because the proto generator emits them; the TS-side is free to +collapse. + +### H9. `Client` is unqualified + +`export class Client` (client.ts:49). Every package in this SDK exports +its own `Client`. Once imported in user code: + +```ts +import {Client as ReposClient} from '@databricks/sdk-repos/v1'; +``` + +— the consumer has to do the renaming. The generator should produce +`ReposClient` directly (or `GitFoldersClient` per H1, matching the package +noun). This is a pattern-wide issue and was flagged in every audit so far. + +--- + +## Medium severity (worth pushing back on) + +### M1. `RepoInfo` suffix is a Java/proto idiom + +The type is called `RepoInfo` — but there is no `Repo` type that +`RepoInfo` is "info about". The `Info` suffix is residue from the +proto/Go-SDK ancestry; TS canonical naming would just be `Repo` (or +`GitFolder` per H1). The same critique was made in the `credentials` audit +(`CredentialInfo` vs `Credential`). + +### M2. `branch` and `tag` should be discriminated + +```ts +interface UpdateRepo { + id?: number; + branch?: string; + tag?: string; + sparseCheckout?: SparseCheckoutUpdate; +} +``` + +JSDoc on `tag`: "Updating the repo to a tag puts the repo in a detached +HEAD state. Before committing new changes, you must update the repo to a +branch instead of the detached HEAD." So the caller must specify *either* +a branch *or* a tag — but the TS type allows neither, either, or both. + +Idiomatic TS would be: + +```ts +type GitRef = + | {kind: 'branch'; name: string} + | {kind: 'tag'; name: string} + | {kind: 'commit'; sha: string}; + +interface UpdateRepo { + id?: number; + ref?: GitRef; + sparseCheckout?: SparseCheckoutUpdate; +} +``` + +This is a wire-compatible rename; the zod transform can flatten back to +`{branch, tag}` on the way out. + +### M3. `path` is generic — could be `workspacePath` + +Five fields named `path`, all meaning "the workspace path where this Git +folder is mounted". Bare `path` is ambiguous (filesystem path? URL path? +remote-side checkout path?). `workspacePath` would self-document. The +JSDoc says "in the workspace" each time. + +### M4. `url` is generic — could be `remoteUrl` or `gitUrl` + +Four fields named `url`, all meaning "the URL of the remote Git +repository". Bare `url` is generic. `remoteUrl` (Git terminology) or +`gitUrl` would self-document. The JSDoc says "URL of the [linked|remote] +Git repository" each time. + +### M5. `listReposIter` uses Go-idiom `Iter` suffix + +```ts +async *listReposIter(req: ListRepos, options?: CallOptions): AsyncGenerator +``` + +`Iter` is a Go convention. TS-native options: +- `listAllRepos(req)` returning `AsyncIterable` +- `listRepos(req)` returning the pager that exposes `[Symbol.asyncIterator]` +- `streamRepos(req)` + +Pick a JS convention. + +### M6. `parseResponse` / `marshalRequest` / `executeCall` / `executeHttpCall` (action-verb soup) + +`utils.ts` exposes: + +- `parseResponse(body, schema)` +- `marshalRequest(data, schema)` +- `executeCall(call, options)` +- `executeHttpCall(opts)` +- `buildHttpRequest(method, url, headers, signal?, body?)` + +Four different action verbs across the file (`parse`, `marshal`, +`execute`, `build`). The `parse`/`marshal` mismatch is the loudest one +(both functions are zod-schema invocations that go in opposite +directions). Either: + +- `marshalRequest` / `unmarshalResponse` (Go idiom, matches + `marshal*Schema`/`unmarshal*Schema`), or +- `encodeRequest` / `decodeResponse` (TS idiom). + +The `execute*` pair (`executeCall` wraps the retry/rate-limit executor; +`executeHttpCall` is a single HTTP round-trip) has been flagged in every +audit so far. + +### M7. `repos` plural field is fine, but inconsistent with the singular-resource convention used everywhere else + +The list-response wraps `repos: RepoInfo[]`. That part is fine +(`listRepos` → `{repos: [...]}`). But the singular `RepoInfo` and the +plural `repos` co-exist in the same file — and once you rename +`RepoInfo` to `Repo` (per M1) or `GitFolder` (per H1), the response +field needs to follow (`gitFolders: GitFolder[]`). + +### M8. `req.id ?? ''` URL-builder bug-shape + +```ts +const url = `${this.host}/api/2.0/repos/${String(req.id ?? '')}`; +``` + +When `req.id` is `undefined` (the type allows it — `id?: number`), this +produces `/api/2.0/repos/` (trailing slash, no ID). The server responds +404. Idiomatic TS would mark `id` as required for paths that need it, or +throw before issuing the call. The pattern repeats in +`client.ts:109, 134, 216`. + +--- + +## Low severity (style polish) + +### L1. `headCommitId` is named after the Git internal "HEAD" + +The field name `headCommitId` uses the Git term "HEAD". Readers unfamiliar +with Git internals will not parse "head commit". The value is a SHA-1 +hash. `headSha` or `currentCommitSha` would be more direct. See #19. + +### L2. `parseResponse` vs `marshalRequest` action-verb mismatch + +See M6. Lowest priority of the action-verb-soup findings. See #33. + +### L3. `PACKAGE_SEGMENT` could be more specific + +"Segment" is vague — it is a user-agent segment, specifically. The +constant is used once (in the User-Agent string). `USER_AGENT_PACKAGE_SEGMENT` +would tie it to its only consumer. See #35. + +### L4. `host` field stores a base URL, not a host + +`this.host = options.host.replace(/\/$/, '')` — the field is a base URL +with trailing slash stripped, not a host (a host has no scheme, no path). +`baseUrl` would be the honest name. See #36. + +### L5. `awsCodeCommit` is documented as deprecated but not tagged + +The JSDoc on `provider` says "`awsCodeCommit` (deprecated by AWS, not +accepting new customers)". But the model has no `@deprecated` tag on +either the field's documentation or on a typed enum value (which doesn't +exist — see H5). Callers cannot programmatically detect deprecated values. +See #15. + +### L6. `SparseCheckout` doc has a comma splice + +```ts +/** Sparse checkout configuration, it contains options like cone patterns. */ +``` + +"Sparse checkout configuration, it contains options like cone patterns." +— "configuration, it contains" is a comma splice (independent clauses +joined by a comma). Should be "Sparse checkout configuration." or +"Sparse checkout configuration. The `patterns` array specifies cone-mode +patterns." See #22. + +### L7. `RepoInfo` doc text inconsistencies + +"Git folder" vs "git folder" within `RepoInfo` (model.ts:110, 112, 114, +116, 118, 124, 126, 128). "Workspace" vs "workspace". Generator-introduced +text inconsistency. See #42. + +### L8. `RepoInfo.path` doc says "Root path"; the other three `path` docs say "Path" + +The `RepoInfo` interface describes `path` as "Root path of the git folder +(repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` / +`GetRepo_Response` / `CreateRepo_Response` says "Path of the Git folder +(repo) in the workspace." Different qualifier ("root path" vs "path"), +different casing ("Workspace" vs "workspace"). Generator-introduced. See +#41. + +### L9. `path` field name collides with Node.js `path` module + +`import * as path from 'node:path'` is common; local field also named +`path` shadows the import. Not a TS reserved word, but a known footgun. +See #45. + +--- + +## Notes + +### Wire-protocol values that the audit cannot fix + +The `provider` wire values (`gitHub`, `bitbucketCloud`, etc.) are dictated +by the API server. The casing inconsistencies (#12) and legacy renames +(#13, #14) are baked in. The TS-side cannot change them without breaking +the wire. The audit flags them for awareness — fixing requires an +API-server change. + +The `DELETE /api/2.0/repos/{id}` URL also cannot change. But the *TS-side* +method name (`deleteProject`) and the *TS-side* request type +(`DeleteProject`) can both rename freely (see H2). + +### Identifier zoo summary + +| Identifier kind | Count | +|---|---| +| Total exported interfaces | 10 | +| Underscored (proto-style) interfaces | 5 (`CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, `ListRepos_Response`, `UpdateRepo_Response`) | +| Underscored (proto-style) const schemas | 5 (the matching `unmarshal*_ResponseSchema`) | +| Identical-shape interface trios | 1 (`RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | +| Identical-shape interface pairs | 1 (`SparseCheckout` ≡ `SparseCheckoutUpdate`) | +| Inline ESLint disables required by these names | 10 | +| Enums | 0 (despite an 8-value closed set on `provider`) | +| Legacy-name leaks | 1 (`DeleteProject*` on a "repos" client) | +| Rebranding leaks | All identifiers (the resource is now "Git folder" everywhere in JSDoc and product UI, but the type/method names still say "Repo") | + +### Comparison to other audits + +| Issue | This package | `gitcredentials` audit | `credentials` audit | +|---|---|---|---| +| Bare `Client` class | Yes (H9) | Yes (H7) | Yes (#10) | +| `_Response` underscore types | Yes (H3) | Yes (H3) | Yes (#18) | +| Three identical resource/response shapes | Yes (H4: `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | +| `string`-typed enum-domain field (`provider`) | Yes (H5) | Yes (H6 — same field!) | No (uses real enums) | +| `marshal*Schema` / `unmarshal*Schema` consts | Yes (#30, #31) | Yes (#28, #29) | Yes (#53) | +| `executeCall` / `executeHttpCall` vocabulary clash | Yes (M6) | Yes (#31) | Yes (#55) | +| `parseResponse` / `marshalRequest` action mismatch | Yes (M6, L2) | Yes (#32) | Yes (#56) | +| `PACKAGE_SEGMENT` generic const | Yes (L3) | Yes (#35) | Yes (#58) | +| `host` field stores a URL | Yes (L4) | Yes (#36) | Common | +| Bare `id` on requests | Yes (H6) | Yes (#24 — but with `credentialId` divergence on responses) | Yes (`nameArg` divergence) | +| Plural/singular mismatch | Mild (#39 — singular request type for plural endpoint) | Severe (H2 — plural request type for singular op) | Mixed | +| Legacy-name leak | **Yes (H2 — `DeleteProject*` on a "repos" client)** | No | No | +| Product-rebrand leak | **Yes (H1 — TS surface says "Repo", product/doc says "Git folder")** | Partial (Bitbucket Data Center rename, GitLab Self-Managed rename — wire values only) | No | + +The `DeleteProject` legacy leak (H2) is unique to this package — no other +audited package has a single mismatched-noun operation in an otherwise- +uniform CRUD client. The product-rebrand-vs-API-name divergence (H1) is +also pronounced: every JSDoc string in the file uses "Git folder (repo)", +while every type and method name uses only "Repo". The generator already +has the new terminology in the doc strings; only the names have not +followed. diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md new file mode 100644 index 00000000..072cc6a1 --- /dev/null +++ b/.agent/naming-audit/resourcequotas.md @@ -0,0 +1,339 @@ +# Naming Audit: `resourcequotas` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/resourcequotas/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Unity Catalog — resource quota inspection (count vs. limit for child securables under a parent). + +Notation: file paths are absolute. Findings reference `file:line`. + +--- + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 4 | +| Medium | 7 | +| Low | 6 | +| Observation | 8 | +| **Total** | **25** | + +Headline themes: + +1. **Singular/plural mismatch on the `listQuota` method and `ListQuotas` request type.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotas`, `ListQuotas_Response`) are all plural, but the client method is `listQuota` (singular). The companion iterator is `listQuotaIter`, doubling down on the singular. This is the most user-visible naming defect. +2. **Proto-style `Parent_Response` identifiers leaking into the TypeScript public API.** `GetQuota_Response` and `ListQuotas_Response` retain the underscore from Go/proto nesting, and `index.ts` re-exports them verbatim. The `unmarshalGetQuota_ResponseSchema` / `unmarshalListQuotas_ResponseSchema` symbols carry the same underscore into the schema layer. +3. **Verb-phrase request types collide semantically with client methods.** `interface GetQuota` reads as an action; `client.getQuota(req: GetQuota)` forces readers to mentally distinguish the verb-phrase function from the verb-phrase type. Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix to remove this collision. +4. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuota` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuota`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. +5. **`SecurableType` is duplicated as a `string` on `GetQuota` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H4 below. + +--- + +## High Severity + +### H1. Method name `listQuota` is singular but returns / paginates a list + +- **File / line:** `src/v1/client.ts:98` (`async listQuota(...)`); also `client.ts:131` (`listQuotaIter`). +- **Category:** #9 singular/plural mismatch; #15 generic-name losing meaning. +- **Current:** `async listQuota(req: ListQuotas, options?): Promise`. +- **Suggestion:** `listQuotas` (and `listQuotasIter`). +- **Rationale:** The request type is `ListQuotas` (plural), the response is `ListQuotas_Response` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:92`). Every neighbouring signal is plural except the method name. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact. + +### H2. `GetQuota_Response` and `ListQuotas_Response` violate TypeScript identifier convention + +- **File / line:** `src/v1/model.ts:37` (`GetQuota_Response`), `src/v1/model.ts:50` (`ListQuotas_Response`); also re-exported from `src/v1/index.ts:9, 11`. +- **Category:** #4 underscore in TypeScript identifier; #14 Go/Java-style name. +- **Current:** `GetQuota_Response`, `ListQuotas_Response`, `unmarshalGetQuota_ResponseSchema` (`model.ts:76`), `unmarshalListQuotas_ResponseSchema` (`model.ts:85`). +- **Suggestion:** `GetQuotaResponse`, `ListQuotasResponse`, `unmarshalGetQuotaResponseSchema`, `unmarshalListQuotasResponseSchema`. +- **Rationale:** Proto nested-message convention `Parent_Child` is being mechanically transposed into TypeScript. The codebase itself acknowledges the convention is wrong by disabling ESLint at four separate sites (`model.ts:36`, `model.ts:49`, `model.ts:75`, `model.ts:84`) with the comment "Proto-style nested message name." Every disable is a vote against the name. This is the same defect noted in `catalogs.md` §4.6–4.8 and is repo-wide; flagged here at high severity because there are only two model types in this package and *both* are affected. See also Observation O2. + +### H3. `GetQuota` is a verb-phrase used as a request data type + +- **File / line:** `src/v1/model.ts:27`; cross-ref `src/v1/client.ts:67`. +- **Category:** #6 misleading name; #14 Go-style name. +- **Current:** `interface GetQuota { parentSecurableType?: …; parentFullName?: …; quotaName?: … }`. +- **Suggestion:** `GetQuotaRequest`. +- **Rationale:** `GetQuota` reads as a *method*, not a *type*. The user signature `client.getQuota(req: GetQuota)` parses as "call getQuota with a GetQuota" — the verb appears in two roles. The `ListQuotas` type has the same problem but mitigates it slightly with the plural noun. The `…Request` suffix is the standard remedy (see `accountsettings.GetAccountSettingRequest`, `budgetpolicy.GetBudgetPolicyRequest`). + +### H4. `GetQuota.parentSecurableType: string` vs. `QuotaInfo.parentSecurableType: SecurableType` + +- **File / line:** `src/v1/model.ts:29` (request, `string`); `src/v1/model.ts:62` (response, `SecurableType`). +- **Category:** #6 misleading name; #16 field contradicting type domain. +- **Current:** The same logical field is typed as a free-form `string` on the request and as the typed `SecurableType` enum on the response. +- **Suggestion:** Type both as `SecurableType`. If the API genuinely accepts arbitrary strings on input, document that explicitly in the field-level JSDoc. +- **Rationale:** A caller cannot intuit that the `parentSecurableType` they pass into `getQuota` must match a `SecurableType` enum value — the type system promises nothing. The URL substitution (`client.ts:71`) drops the string straight into the path, so a typo like `CATELOG` produces a 404 the user has to debug. Either the enum is the source of truth and the request should reuse it, or the enum is wrong. Today they disagree, which is the worst of both worlds. + +--- + +## Medium Severity + +### M1. `QuotaInfo` carries the redundant `Info` suffix + +- **File / line:** `src/v1/model.ts:60`. +- **Category:** #8 redundant suffix; #14 Go/Java-style name. +- **Current:** `interface QuotaInfo`. +- **Suggestion:** `Quota`. +- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O4. + +### M2. `quotaName`, `quotaCount`, `quotaLimit` — every field prefixed with the enclosing type + +- **File / line:** `src/v1/model.ts:66, 68, 70`; mirrored on `GetQuota.quotaName` (`model.ts:33`). +- **Category:** #20 type-suffix tautology (here: type-prefix tautology); #1 vague/generic root nouns. +- **Current:** `quotaName`, `quotaCount`, `quotaLimit` inside `QuotaInfo`. +- **Suggestion:** Drop the `quota` prefix → `name`, `count`, `limit`. +- **Rationale:** In Go the enclosing struct doesn't appear in the field's qualified name (`info.QuotaName` reads `QuotaName`). In TypeScript the access already includes the type via the variable: `quota.name`, `quota.count`, `quota.limit`. The current names produce `quotaInfo.quotaName`, which double-states the domain. (`parentSecurableType` and `parentFullName` legitimately need the `parent` prefix — they refer to a different entity.) + +### M3. `parentSecurableType` and `parentFullName` reference the *parent* of the quota — but a quota's parent is the resource it limits, not its container + +- **File / line:** `src/v1/model.ts:29, 31, 62, 64`. +- **Category:** #6 misleading name (depending on reader's mental model). +- **Current:** `parentSecurableType`, `parentFullName`. +- **Suggestion:** Confirm whether `parent` here means "the securable the quota counts children of" (the documented meaning) versus "the parent of the quota object itself." Possible rename: `scopeSecurableType` / `scopeFullName` or `containerSecurableType` / `containerFullName`. +- **Rationale:** The JSDoc on `model.ts:28, 30` says "Securable type of the quota parent" and "Full name of the parent resource. Provide the metastore ID if the parent is a metastore." A reader could plausibly think `parent` refers to the parent entity of *the quota record*, when it actually refers to the parent that *owns* the quota (i.e., the catalog/schema whose children are being counted). The doc's explanation that the metastore ID is acceptable as a `parentFullName` is the only reliable clue. Note: matches the Go SDK convention, so rename would diverge from the 1:1 port. + +### M4. `quotaName` carries a "follows the pattern of the quota type, with `-quota` added as a suffix" rule that is not enforced or documented in the type + +- **File / line:** `src/v1/model.ts:32` (JSDoc); field `model.ts:33, 66`. +- **Category:** #5 cryptic abbreviation (the "-quota" suffix); #15 generic name losing meaning; #19 underspecified ID. +- **Current:** `quotaName?: string`. +- **Suggestion:** Either expose the quota *type* as an enum (`QuotaKind`?) and compute the suffix server-side, or rename to `quotaSlug` / `quotaIdentifier` and document the format inline. +- **Rationale:** The JSDoc says the value "follows the pattern of the quota type, with `-quota` added as a suffix." Today the user must build the string by hand, e.g. `"schema-quota"` or `"table-quota"`. The naming gives no hint of this format; the type is plain `string`. Either the format should be encoded (enum or branded type) or the name should signal that this is a constructed slug. Compare: `lastFailoverTimeMs` (in `catalogs`) correctly carries the unit; `quotaName` carries no analogous hint. + +### M5. `quotaCount` and `quotaLimit` carry no unit / type signal — counts of *what*? + +- **File / line:** `src/v1/model.ts:68, 70`. +- **Category:** #1 vague/generic; #19 underspecified. +- **Current:** `quotaCount?: number`, `quotaLimit?: number`. +- **Suggestion:** Inline-doc the unit and reference what is being counted (number of *child securables*). +- **Rationale:** From the field names alone, a reader doesn't know whether these are counts of children, megabytes, requests, etc. The package-level JSDoc on `client.ts:62` clarifies that quotas count child entities (e.g. tables under a schema), but the field-level doc says only "current usage of the resource quota" and "current limit of the resource quota." Names like `currentUsage` / `currentLimit` or doc-strings citing "number of child securables" would close the gap. + +### M6. `lastRefreshedAt` is `number` (epoch ms) but the name doesn't communicate units + +- **File / line:** `src/v1/model.ts:72`. +- **Category:** #19 underspecified IDs (units of time). +- **Current:** `lastRefreshedAt?: number`. +- **Suggestion:** `lastRefreshedAtMs` or `lastRefreshedAtEpochMs`. +- **Rationale:** The doc says only "The timestamp that indicates when the quota count was last updated." A reader doesn't know if the unit is seconds, milliseconds, or an ISO string. The Go SDK uses `int64`, but TS callers benefit from the `Ms` suffix convention used elsewhere in the codebase (e.g. `catalogs.DrReplicationInfo.lastFailoverTimeMs`). See `catalogs.md` §19.6 / §19.7. + +### M7. `nextPageToken` doc references `__page_token__` with double underscores + +- **File / line:** `src/v1/model.ts:55` (JSDoc on `ListQuotas_Response.nextPageToken`). +- **Category:** #5 cryptic abbreviation; documentation defect more than naming defect, but mentions identifier syntax that doesn't exist. +- **Current:** `"__page_token__ should be set to this value for the next request."` +- **Suggestion:** Reference the actual TS field name `pageToken` (camelCase) in prose. +- **Rationale:** The double-underscore markdown bolding for `page_token` (the wire form) leaks the snake_case wire field into the public TS docs. Callers don't see `page_token`; they see `pageToken`. The doc misleads. + +--- + +## Low Severity + +### L1. `req` parameter name on every client method + +- **File / line:** `src/v1/client.ts:68, 99, 132`. +- **Category:** #5 cryptic abbreviation; #14 Go-style name. +- **Current:** `req: GetQuota`, `req: ListQuotas`. +- **Suggestion:** `request`. +- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:72, 77, 82, 112, 117, 122, 137` — same shorthand, lower priority. + +### L2. `Client` is the bare type name (no `ResourceQuotasClient`) + +- **File / line:** `src/v1/client.ts:37`. +- **Category:** #14 Go-style name. +- **Current:** `export class Client`. +- **Suggestion:** `ResourceQuotasClient` (or a re-export of `Client as ResourceQuotasClient`). +- **Rationale:** TS imports often need disambiguation: `import {Client} from '@databricks/sdk-resourcequotas/v1'` forces aliasing on any consumer that uses multiple packages. Repo-wide convention, see `catalogs.md` §14.2. + +### L3. `call` local variable shadows the imported `Call` type + +- **File / line:** `src/v1/client.ts:73` (`const call: Call = …`); `client.ts:113` (same). +- **Category:** #1 vague/generic; #10 type/identifier shadowing. +- **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. +- **Suggestion:** `httpCall` or `doRequest`. +- **Rationale:** `call` collides with `Function.prototype.call` and with the imported `Call` type from `@databricks/sdk-core/api`. The expression `await executeCall(call, options)` reads as "execute call call options" — three uses of the verb in one line. Repo-wide port-style convention. + +### L4. `resp` local variable + `respBody` shadowed concept + +- **File / line:** `src/v1/client.ts:72, 77, 82, 112, 117, 122`. +- **Category:** #1 vague/generic. +- **Current:** `let resp: GetQuota_Response | undefined`, `const respBody = …`. +- **Suggestion:** `response`, `responseBytes` / `responseBody`. +- **Rationale:** Same JS-vs-Go shorthand issue as L1. `respBody` is a `Uint8Array` (bytes), not a parsed body — the name promises the parsed thing. + +### L5. `pkgJson` constant name + +- **File / line:** `src/v1/client.ts:18`. +- **Category:** #5 cryptic abbreviation. +- **Current:** `import pkgJson from '../../package.json' …`. +- **Suggestion:** `packageJson` or `manifest`. +- **Rationale:** Minor and internal; the `Json` part is obvious from the import target. Listed because the file is small enough to track every identifier. Repo-wide. + +### L6. `data` parameter on `marshalRequest` + +- **File / line:** `src/v1/utils.ts:119`. +- **Category:** #15 generic field name losing meaning. +- **Current:** `function marshalRequest(data: unknown, schema: z.ZodType): string`. +- **Suggestion:** `request` or `payload`. +- **Rationale:** The function is named `marshalRequest` but the parameter is named `data` — the request semantic is lost in the helper. Repo-wide port-style convention (same defect noted in `artifactallowlists.md` §L4). + +--- + +## Observations (repo-wide conventions, not local defects) + +### O1. `SecurableType` enum values are bare and free of redundant prefixes + +- **File / line:** `src/v1/model.ts:6-25`. +- **Observation:** Variants are `CATALOG`, `SCHEMA`, `TABLE`, … rather than `SECURABLE_TYPE_CATALOG`. **Passes** the audit for #2 (redundant enum prefix) and #18 (long enum values). This is a positive example to cite back to packages that fail. The single TODO-bearing variant `STAGING_TABLE` is appropriately marked as provisional in the JSDoc (`model.ts:23-24`). + +### O2. Proto-style `Parent_Response` identifiers are repo-wide + +`GetQuota_Response` and `ListQuotas_Response` follow the same `Parent_Child` underscore convention as `ConversionInfo_State`, `DatabaseInstance_State`, `EndpointStatus_State`, etc. across the workspace (see `catalogs.md` §4 and `artifactallowlists.md` O2). The four ESLint disable comments in `model.ts` confirm the convention is mechanically applied. Flag for awareness; fix is repo-wide. + +### O3. Bare `Get*` / `List*` request shapes are a repo-wide pattern + +`interface GetQuota` / `interface ListQuotas` follow the same bare verb-phrase convention used by `catalogs`, `connections`, `clusters`, `externallocations`. Some sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix. The decision is repo-wide — flagged as a local high-severity issue (H3) only because the verb/method collision is especially loud when there are only two methods. + +### O4. `…Info` suffix repeated across UC types + +`QuotaInfo` mirrors `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo`. If the codebase decides to drop the `Info` suffix, this is one of many. + +### O5. `URL` constants are inlined + +- **File / line:** `src/v1/client.ts:71, 102`. +- **Observation:** `${this.host}/api/2.1/unity-catalog/resource-quotas/...` appears in both methods without a named constant. Not a naming defect, but typical audits flag unnamed magic strings. + +### O6. `PACKAGE_SEGMENT.key` computed via regex from `pkgJson.name` + +- **File / line:** `src/v1/client.ts:32-35`. +- **Observation:** `key: pkgJson.name.replace(/^@[^/]+\//, '')` strips the `@databricks/` org prefix. The constant name `PACKAGE_SEGMENT` is OK but the `key`/`value` shape is generic — readers don't immediately know `key="resourcequotas"` and `value=version`. Cosmetic. Identical to `artifactallowlists.md` O7. + +### O7. `flattenQueryParams` is exported but unused in this package + +- **File / line:** `src/v1/utils.ts:123`. +- **Observation:** Both `getQuota` (`client.ts:71`) and `listQuota` (`client.ts:102-111`) build URLs/query strings inline. The `flattenQueryParams` helper is dead code from the package's standpoint. Same finding as `catalogs.md` cross-cutting §A and `artifactallowlists.md` L5 — repo-wide template artifact. + +### O8. Marshal helper `marshalRequest` is exported but unused + +- **File / line:** `src/v1/utils.ts:119`. +- **Observation:** Both methods are `GET` with no body, so `marshalRequest` is never called. Same template-artifact category as O7. Not a local naming defect. + +--- + +## Domain glossary + +| Term | Meaning in this package | +| -------------------- | ------------------------------------------------------------------------------------ | +| Quota | A `(count, limit)` pair tracking how many child securables exist under a parent. | +| Parent securable | The container whose children are being counted (e.g. metastore → catalog, catalog → schema). | +| `parentFullName` | The dotted full name of the parent securable; or the metastore ID when parent is a metastore. | +| `quotaName` | A slug built from the quota kind plus the `-quota` suffix (e.g. `schemas-quota`). Format under-documented. | +| `quotaCount` | Current number of child securables. | +| `quotaLimit` | Maximum allowed before further creation is rejected. | +| `lastRefreshedAt` | Epoch-ms timestamp of last server-side count refresh; refreshes are asynchronous. | +| SecurableType | One of 17 Unity Catalog securable kinds (CATALOG, SCHEMA, TABLE, …). | + +--- + +## File coverage + +| File | Lines | Audited | +| -------------- | ----- | ---------------------------------------------------------------------- | +| `src/v1/model.ts` | 113 | 1 enum (17 members), 4 interfaces (12 fields total), 3 schemas. | +| `src/v1/client.ts` | 148 | `Client` class + constructor + 3 methods + all locals + `PACKAGE_SEGMENT`. | +| `src/v1/utils.ts` | 151 | All 7 exported / private functions, the `HttpCallOptions` interface, `readAll`. | +| `src/v1/index.ts` | 14 | All 7 re-exports. | + +Type & symbol checklist: + +- [x] `SecurableType` enum (17 members) → O1 (positive). +- [x] `SecurableType.STAGING_TABLE` (with TODO comment) → no defect (already flagged in source). +- [x] `GetQuota` interface (3 fields) → H3, H4, M3, M4; per-field below. Wrapper preserved for forward compatibility. +- [x] `GetQuota.parentSecurableType` (`string`) → H4 (type mismatch with response). +- [x] `GetQuota.parentFullName` → M3. +- [x] `GetQuota.quotaName` → M2, M4. +- [x] `GetQuota_Response` interface (1 field) → H2. Wrapper preserved for forward compatibility. +- [x] `GetQuota_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). +- [x] `ListQuotas` interface (2 fields) → H3 (verb-phrase), no per-field defects beyond M7. +- [x] `ListQuotas.maxResults` → no defect. +- [x] `ListQuotas.pageToken` → no defect. +- [x] `ListQuotas_Response` interface (2 fields) → H2, M7. +- [x] `ListQuotas_Response.quotas` → no defect; correctly plural. +- [x] `ListQuotas_Response.nextPageToken` → M7. +- [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix); per-field below. +- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H4, M3. +- [x] `QuotaInfo.parentFullName` → M3. +- [x] `QuotaInfo.quotaName` → M2, M4. +- [x] `QuotaInfo.quotaCount` → M2, M5. +- [x] `QuotaInfo.quotaLimit` → M2, M5. +- [x] `QuotaInfo.lastRefreshedAt` → M6. +- [x] `unmarshalGetQuota_ResponseSchema` → H2. +- [x] `unmarshalListQuotas_ResponseSchema` → H2. +- [x] `unmarshalQuotaInfoSchema` → no defect. +- [x] `Client` class → L2. +- [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. +- [x] `PACKAGE_SEGMENT` constant → O6. +- [x] `getQuota(req, options)` method → H3, L1. +- [x] `listQuota(req, options)` method → H1, L1, L3, L4. +- [x] `listQuotaIter(req, options)` method → H1. +- [x] `HttpCallOptions` interface → no defect. +- [x] `executeCall` function → no defect (consistent with sibling packages; same minor concern as `catalogs.md` §6.9 if duplicated naming is considered defect). +- [x] `readAll` private function → no defect. +- [x] `executeHttpCall` function → no defect. +- [x] `buildHttpRequest` function → no defect. +- [x] `parseResponse` function → no defect. +- [x] `marshalRequest` function → L6 (`data` param); O8 (unused). +- [x] `flattenQueryParams` function → O7 (unused). +- [x] `index.ts` re-exports → no extra defects; mirrors model exports faithfully, but propagates H2 underscore identifiers. + +--- + +## File / line index for fast lookup + +| Identifier | Location | Finding | +| ------------------------------------------------- | ----------------- | ------------------------ | +| `SecurableType` | model.ts:6 | O1 (positive) | +| `SecurableType.STAGING_TABLE` | model.ts:24 | — (annotated TODO) | +| `GetQuota` | model.ts:27 | H3 | +| `GetQuota.parentSecurableType` (`string`) | model.ts:29 | H4, M3 | +| `GetQuota.parentFullName` | model.ts:31 | M3 | +| `GetQuota.quotaName` | model.ts:33 | M2, M4 | +| `GetQuota_Response` | model.ts:37 | H2, O2 | +| `ListQuotas` | model.ts:42 | H3 (verb-phrase) | +| `ListQuotas.maxResults` | model.ts:44 | — | +| `ListQuotas.pageToken` | model.ts:46 | — | +| `ListQuotas_Response` | model.ts:50 | H2, O2 | +| `ListQuotas_Response.quotas` | model.ts:52 | — (correct plural) | +| `ListQuotas_Response.nextPageToken` (doc) | model.ts:55-57 | M7 | +| `QuotaInfo` | model.ts:60 | M1, O4 | +| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H4, M3 | +| `QuotaInfo.parentFullName` | model.ts:64 | M3 | +| `QuotaInfo.quotaName` | model.ts:66 | M2, M4 | +| `QuotaInfo.quotaCount` | model.ts:68 | M2, M5 | +| `QuotaInfo.quotaLimit` | model.ts:70 | M2, M5 | +| `QuotaInfo.lastRefreshedAt` | model.ts:72 | M6 | +| `unmarshalGetQuota_ResponseSchema` | model.ts:76 | H2 | +| `unmarshalListQuotas_ResponseSchema` | model.ts:85 | H2 | +| `unmarshalQuotaInfoSchema` | model.ts:96 | — | +| `Client` (bare name) | client.ts:37 | L2 | +| `PACKAGE_SEGMENT` | client.ts:32 | O6 | +| `pkgJson` import alias | client.ts:18 | L5 | +| `Client.getQuota` parameter `req` | client.ts:68 | L1 | +| `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | +| `Client.listQuotaIter` | client.ts:131 | H1 | +| `const call: Call` | client.ts:73, 113 | L3 | +| `let resp: …_Response` | client.ts:72, 112 | L4 | +| `const respBody` | client.ts:77, 117 | L4 | +| `marshalRequest(data, schema)` | utils.ts:119 | L6, O8 | +| `flattenQueryParams` | utils.ts:123 | O7 | +| `index.ts` re-exports propagate `_Response` types | index.ts:9, 11 | H2 | + +--- + +## Recommended priority order + +1. **Rename `listQuota` → `listQuotas` (and `listQuotaIter` → `listQuotasIter`)** — single-character defect, highest user impact. (H1) +2. **Add `…Request` / `…Response` suffix uniformly and drop the underscore.** (H2, H3) +3. **Reconcile `parentSecurableType` type — make `GetQuota.parentSecurableType: SecurableType`.** (H4) +4. **Drop `quota` prefix on `quotaName` / `quotaCount` / `quotaLimit` inside `QuotaInfo`.** (M2) +5. **Document units on `lastRefreshedAt` (Ms) and counts on `quotaCount`/`quotaLimit`.** (M5, M6) +6. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M7) +7. **Drop `Info` suffix on `QuotaInfo`.** (M1, O4) +8. **Spell out `req` → `request` (repo-wide policy).** (L1) diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md new file mode 100644 index 00000000..138862fc --- /dev/null +++ b/.agent/naming-audit/rfa.md @@ -0,0 +1,313 @@ +# Naming Audit: rfa + +**Path:** `packages/rfa/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. +**Total weird names flagged:** 46 + +## Summary +| Severity | Count | +| --- | --- | +| High | 10 | +| Medium | 18 | +| Low | 13 | +| Observation | 5 | + +## High severity + +### 1. Package name `rfa` — `packages/rfa/`, `.package.json:2`, `client.ts:78,117,151` +- **Why weird:** Three-letter cryptic acronym used as the npm package name (`@databricks/sdk-rfa`), the package directory, the import path (`packages/rfa/src/v1/`), and the URL segment (`/api/3.0/rfa/...`). Nothing in the source files spells out what `rfa` stands for — no doc comment, no README description (`package.json` description is empty string), no module-level JSDoc in `index.ts`. From the model alone, the user has to reverse-engineer that `rfa` means "Request For Access" by reading the type names (`CreateAccessRequest`, `AccessRequestDestinations`). The Databricks Go SDK (`databricks/sdk-go`) does not yet contain this code path either — there's no upstream reference. +- **Category:** 5 (cryptic abbreviation), 1 (vague). +- **Suggested name:** `accessrequests` or `accessrequestdestinations`. The npm package would be `@databricks/sdk-accessrequests`. The wire URL `/api/3.0/rfa/...` can stay locked while the SDK surface uses the spelled-out name. +- **Rationale:** TS SDK names are user-typed in import statements (`import {Client} from '@databricks/sdk-rfa/v1';`). A user reading that import line has no way to guess the package's purpose. Compare to neighbour packages — `abacpolicies`, `accountaccesscontrol`, `alerts`, `cleanrooms`, `gitcredentials` — all spell out the domain. `rfa` is the only opaque acronym among ~70 packages. + +### 2. `DestinationType.URL` — `model.ts:13` +- **Why weird:** `URL` collides with the JavaScript built-in global `URL` (the WHATWG URL class). The enum member is therefore syntactically `DestinationType.URL` which is fine, but importing/destructuring is error-prone (`const {URL} = DestinationType` would shadow the global). Worse, the value `'URL'` is a misleading category — `DestinationType.URL` is documented as a webhook delivery to an arbitrary URL, but `DestinationType.GENERIC_WEBHOOK` is *also* a delivery to a URL. The semantic difference between `URL` and `GENERIC_WEBHOOK` is invisible from the names. +- **Category:** 10 (reserved-word/global collision), 6 (misleading — two members both denote webhook-URL deliveries). +- **Suggested name:** Rename `URL` to `URL_NOTIFICATION` or `PLAIN_URL`, or rename `GENERIC_WEBHOOK` to clarify what makes it "generic" relative to `URL`. Document the wire-level difference between the two. +- **Rationale:** Two enum members for "send to a URL" is a discoverability bug. Future callers will guess one and silently get the wrong webhook semantics. + +### 3. `DestinationType.DESTINATION_TYPE_UNSPECIFIED` — `model.ts:8` +- **Why weird:** Enum sentinel re-states the enum name (`DestinationType.DESTINATION_TYPE_UNSPECIFIED`). The corresponding field is already `destinationType?: DestinationType | undefined`, so "unspecified" is encoded twice: as `undefined` (TS-native) and as `DESTINATION_TYPE_UNSPECIFIED` (proto-native). +- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). +- **Suggested name:** Drop the sentinel; rely on `undefined`. +- **Rationale:** TS enum members are namespaced by the enum itself. `Foo.FOO_BAR` is pure protobuf noise. Same finding recurs in `connections`, `abacpolicies`, and most generated packages. + +### 4. `PrincipalType.PRINCIPAL_TYPE_UNSPECIFIED` — `model.ts:17` +- **Why weird:** Same pattern as #3 — sentinel re-states enum name. +- **Category:** 2, 14. +- **Suggested name:** Drop the sentinel; rely on `undefined`. +- **Rationale:** Identical to #3. + +### 5. `SpecialDestination.SPECIAL_DESTINATION_UNSPECIFIED` — `model.ts:46` +- **Why weird:** Same pattern as #3. Compounded because every other member of the same enum *also* repeats the `SPECIAL_DESTINATION_` prefix (see #6). +- **Category:** 2, 14. +- **Suggested name:** Drop the sentinel. +- **Rationale:** Same as #3. + +### 6. `SpecialDestination` members repeat `SPECIAL_DESTINATION_` prefix — `model.ts:46-51` +- **Why weird:** Every member of `SpecialDestination` is prefixed with `SPECIAL_DESTINATION_`. Reads as `SpecialDestination.SPECIAL_DESTINATION_CATALOG_OWNER`, `SpecialDestination.SPECIAL_DESTINATION_EXTERNAL_LOCATION_OWNER`, etc. Six members, all redundantly prefixed. +- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). +- **Suggested name:** `SpecialDestination.CATALOG_OWNER`, `SpecialDestination.EXTERNAL_LOCATION_OWNER`, etc. (drop the prefix). Even better, since the enum models "owner of which UC securable type" the name should be `OwnerDestination` and members can be `CATALOG`, `EXTERNAL_LOCATION`, `CONNECTION`, `CREDENTIAL`, `METASTORE`. +- **Rationale:** Five non-sentinel members all begin with the same 23-character prefix that re-states the enum name. Member access reads `SpecialDestination.SPECIAL_DESTINATION_CATALOG_OWNER` (44 chars to reference "catalog owner"). This is the worst case in the package. + +### 7. `Securable.type` field collides with reserved word & loses meaning — `model.ts:160` +- **Why weird:** Bare `type` is the most generic identifier in the language. `type` is also a contextual reserved word (used in `type X = ...`, `import type`, `typeof`). Within `Securable`, the field is documented as "The type of securable (catalog/schema/table)" — its value is a `SecurableType` enum. Caller writes `securable.type` which gives no hint that the value is one of nine UC securable kinds. The same struct also has a `fullName` field, so reading `securable.type` and `securable.fullName` together reads like a TS metadata bag, not a UC entity descriptor. +- **Category:** 10 (reserved-word collision in casual reading), 1 (vague), 15 (generic field name losing meaning), 20 (type-suffix tautology between field `type` and enum `SecurableType`). +- **Suggested name:** `kind` or `securableType` (the latter matches sibling types: `AccessRequestDestinations.securableType`). +- **Rationale:** `securable.kind` (or `securable.securableType`) communicates the domain. `securable.type` reads as a TS construct. + +### 8. `Securable.fullName` doc says "catalog/schema/table" but reality is broader — `model.ts:162-165` +- **Why weird:** The doc comment for `fullName` reads "The full name of the catalog/schema/table". But the `type` field's enum `SecurableType` supports 17 different securables: CATALOG, SCHEMA, TABLE, STORAGE_CREDENTIAL, EXTERNAL_LOCATION, FUNCTION, SHARE, PROVIDER, RECIPIENT, CLEAN_ROOM, METASTORE, PIPELINE, VOLUME, CONNECTION, CREDENTIAL, EXTERNAL_METADATA, STAGING_TABLE. The doc is misleading by selective enumeration — implies the field is only for three securable types. +- **Category:** 6 (misleading doc on a name-bearing field). +- **Suggested name:** Keep field name; fix doc to say "The full name of the securable, e.g. `catalog.schema.table` for a table, `catalog.schema.view` for a view, etc." +- **Rationale:** Name itself is fine; the documentation undermines the field's apparent applicability. + +### 9. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` +- **Why weird:** `AccessRequestDestinations` has both: + - `securable?: Securable` (which has `type` and `fullName`), and + - top-level `securableType?: string` and `fullName?: string`. + The inline JSDoc says "Redundant with the type in the securable object, but necessary for Terraform integration" and "Redundant with the name in the securable object, but necessary for Terraform integration". Three problems: + 1. Two fields hold the same data — easy to set inconsistently (`securable.type === 'CATALOG'` while `securableType === 'TABLE'`). + 2. The redundant `securableType` is typed `string` while `securable.type` is typed `SecurableType` — *different types* for the same data. + 3. The reason ("Terraform integration") is implementation detail leaking onto the public SDK surface for every non-Terraform caller. +- **Category:** 12 (duplicate concepts), 6 (misleading — which one is authoritative?), 16 (type contradiction: `string` vs enum `SecurableType`). +- **Suggested name:** Drop `securableType` and `fullName` from `AccessRequestDestinations` for non-Terraform callers; expose them under a `terraformShim` namespace if needed, or model with `Pick`/conditional types. Wire stays unchanged. +- **Rationale:** Two-field duplication invites bugs (a caller might set one and not the other). The "necessary for Terraform integration" rationale is exactly the kind of generator artefact that should not surface here. + +### 10. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` +- **Why weird:** The request type for `getAccessRequestDestinations` has `securableType?: string`, but the response type `AccessRequestDestinations` has `securable?: { type?: SecurableType }` — a typed enum. So the request is untyped string, while the response is enum. A caller writing `req.securableType = 'catalogue'` (typo or wrong case) gets no compile-time error. +- **Category:** 16 (field type contradicts domain — should be `SecurableType`), 6 (misleading — looks like free text but server demands an enum value). +- **Suggested name:** Keep name, change type to `SecurableType`. +- **Rationale:** Same data model, two field types. Type narrowing is the whole point of TS — losing it on the request side is a regression. + +## Medium severity + +### 11. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` +- **Why weird:** The type is plural (`Destinations`) but each instance describes the destinations *for one securable* (`securable?: Securable`, singular). The plural belongs only to the inner `destinations?: NotificationDestination[]` array. Compare: `AccessRequestDestination` (singular) would describe one route; `AccessRequestDestinations` (plural) implies multiple route configs. The current name is the latter but holds the former. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `AccessRequestRouting` or `AccessRequestDestinationConfig` (singular) — captures "the routing configuration for one securable". +- **Rationale:** The pluralization is for the inner array, not the outer concept. Today the type-name reader gets the wrong mental model. + +### 12. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` +- **Why weird:** Verbose type names (32 / 33 chars). `Batch` + `Create` + `AccessRequests` + `Request`/`Response`. Also: `Batch` prefix is the *only* signal that the endpoint accepts an array — but the client method is just `batchCreateAccessRequests`, and the field inside is `requests?: CreateAccessRequest[]`. Three levels of "batchness". +- **Category:** 7 (overly verbose), 8 (redundant suffix `Request`). +- **Suggested name:** `CreateAccessRequestsRequest` (drop `Batch`; the plural already implies batching). Or even better: `CreateAccessRequestsInput` / `CreateAccessRequestsOutput`. Pair with method `createAccessRequests`. +- **Rationale:** `Batch` doubles as marketing copy ("look, batched!") rather than naming. TS plural-`s` already says "multiple". + +### 13. `BatchCreateAccessRequestsResponse.responses` — `model.ts:85-88` +- **Why weird:** Field `responses` on a type called `BatchCreateAccessRequestsResponse`. Reads `batchCreateAccessRequestsResponse.responses[0]`. Compounds "response" three times. The actual value is an array of `CreateAccessRequestResponse`. +- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). +- **Suggested name:** `results` or `created` instead of `responses`. +- **Rationale:** Field-name "responses" inside a "Response" type is a tautology that confuses the call site reader. + +### 14. `CreateAccessRequest.behalfOf` field — `model.ts:90-97` +- **Why weird:** Wire is `behalf_of`, TS is `behalfOf`. The doc says "The principal this request is for. Empty `behalf_of` defaults to the requester's identity." The name reads as a preposition ("on behalf of …") rather than a noun. Reads `request.behalfOf = principal` instead of `request.principal = principal` (with a docstring that says default is the caller). Compare with: `recipient`, `subject`, `principal`, `requestee`. +- **Category:** 14 (Go/proto-style name — `behalf_of` is the wire convention), 1 (preposition as field name). +- **Suggested name:** `principal` or `requester` or `subjectPrincipal`. Wire stays `behalf_of`. +- **Rationale:** Field-name as preposition is awkward in TS. `request.behalfOf` parses as a fragment of an English sentence; the value is a noun (`Principal`). + +### 15. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` +- **Why weird:** `CreateAccessRequest` has `securablePermissions?: SecurablePermissions[]` (plural array, type `SecurablePermissions` itself plural). `SecurablePermissions` holds `securable: Securable` (singular) and `permissions: string[]` (plural). So `request.securablePermissions[0].securable` reads as "the singular securable inside the plural securable-permissions". The type name `SecurablePermissions` doesn't say "pairs of securable + permissions list". +- **Category:** 9 (singular/plural mismatch), 1 (vague — what does `SecurablePermissions` model?). +- **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). Field becomes `securablePermissionRequests?: SecurablePermissionRequest[]` — long but readable. +- **Rationale:** The type-name pluralization is hiding what the type actually models (one securable + a permissions list). + +### 16. `CreateAccessRequestResponse.requestDestinations` — `model.ts:114-119` +- **Why weird:** Field `requestDestinations` on a type called `CreateAccessRequestResponse`. The type already says it's a response *to a create request*; the field name re-states "request" and uses an unusual compound. The actual value is an array of `AccessRequestDestinations` (the routing configs the request will fire to). +- **Category:** 20 (tautology), 1 (vague — what makes it `request`Destinations vs `accessRequest`Destinations?), 12 (duplicate concept — the type name is `AccessRequestDestinations` but the field name drops the `Access` prefix). +- **Suggested name:** `destinations: AccessRequestDestinations[]` or `routing: AccessRequestDestinations[]`. +- **Rationale:** Field name should match the type element being held. + +### 17. `NotificationDestination.destinationId` — `model.ts:128-134` +- **Why weird:** Type-suffix tautology — field `destinationId` on a type called `NotificationDestination`. Reads `notificationDestination.destinationId`. Also: the doc explains the value is *overloaded* — email address for EMAIL, URL for URL, Databricks notification ID for everything else. Three different shapes packed into one untyped string field. +- **Category:** 20 (type-suffix tautology), 19 (underspecified ID — three different schemes hidden behind one name), 6 (misleading — "Id" implies opaque token, not e.g. an email). +- **Suggested name:** Field as `id` (since the containing type already says `NotificationDestination`). Alternatively, model the overload as a discriminated union: `{ type: 'EMAIL'; email: string } | { type: 'URL'; url: string } | { type: 'SLACK'; notificationId: string } | ...`. +- **Rationale:** A field named `Id` that sometimes holds an email and sometimes a URL is the canonical example of an underspecified identifier. + +### 18. `NotificationDestination.destinationType` — `model.ts:135` +- **Why weird:** Type-suffix tautology — field `destinationType` of type `DestinationType` on a type called `NotificationDestination`. Reads `notificationDestination.destinationType`. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `type` (the containing type already says `NotificationDestination`). Reads `notificationDestination.type`. +- **Rationale:** Wire stays `destination_type`; TS can drop the prefix the same way `Securable.type` does (model.ts:160) — note the inconsistency with the same project. + +### 19. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` +- **Why weird:** A single `NotificationDestination` has both `destinationType?: DestinationType` and `specialDestination?: SpecialDestination`. The doc says `specialDestination`'s `destination_type` is "always EMAIL". So we have two enums that *cannot both be expressive at once* — if `specialDestination` is set, `destinationType` is constrained to `EMAIL`. The type system doesn't enforce this. +- **Category:** 12 (duplicate concept — two enums encode overlapping info), 6 (misleading — looks like independent fields). +- **Suggested name:** Either (a) collapse: extend `DestinationType` with new members (`CATALOG_OWNER_EMAIL`, `EXTERNAL_LOCATION_OWNER_EMAIL`, ...) and drop `SpecialDestination`; or (b) model as a discriminated union: `{ kind: 'normal'; destinationType, destinationId } | { kind: 'special'; specialDestination }`. +- **Rationale:** Two parallel enums for a constrained relationship is exactly the kind of latent-bug field name pair that a strict type system can prevent. + +### 20. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` +- **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape is fine, but the bare `id` doesn't communicate "the meaning depends on `principalType`". +- **Category:** 19 (underspecified ID), 1 (vague). +- **Suggested name:** Keep `id` paired with `principalType`, OR (more aggressive) make the type a discriminated union: `{ kind: 'user'; userId: string } | { kind: 'group'; groupId: string } | { kind: 'service'; servicePrincipalId: string }`. +- **Rationale:** Tagged unions express the constraint at the type level. The current shape is a Go-port idiom. + +### 21. `Securable.providerShare` — `model.ts:166-170` +- **Why weird:** Field name `providerShare` on type `Securable`. Doc says it's "the name of the Share object that contains the securable when the securable is getting shared in D2D Delta Sharing". The name confuses two concepts: a `Share` securable type (already exists in `SecurableType.SHARE`) and a "provider" prefix that disambiguates Delta Sharing flows. +- **Category:** 5 (cryptic abbreviation: `D2D` is in doc but never expanded), 1 (vague — what makes the share `provider`?). +- **Suggested name:** `sharingProviderName` or `deltaShareName` with a clearer doc. +- **Rationale:** `providerShare` reads as "the share of the provider" (genitive). The actual semantic is "the Delta Share that grants access to this securable when it's a shared object". The current name doesn't disambiguate. + +### 22. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` +- **Why weird:** Enum value pinned by inline TODO: `/** TODO: [UC-2980] Staging tables aren't full-fleged securables yet. */`. The TODO leaks an internal JIRA ticket (`UC-2980`) and the typo "full-fleged" into the public SDK surface. The presence of the value tells callers it works; the comment tells them it doesn't. +- **Category:** 18 (questionable enum value). +- **Suggested name:** Either hide until promotion (`@experimental`), or remove the inline TODO and document the constraint in the doc-comment proper. +- **Rationale:** Public SDK enums shouldn't carry internal JIRA references. Same pattern as `connections#29` and `dataclassification`. + +### 23. `SecurableType.CLEAN_ROOM` with underscore vs `STORAGE_CREDENTIAL`, `EXTERNAL_LOCATION` etc — `model.ts:24-43` +- **Why weird:** Mostly consistent SCREAMING_SNAKE, but `CLEAN_ROOM` is one of several where the underlying domain noun is two words. Compare `STORAGE_CREDENTIAL` (two-word: "storage credential"), `EXTERNAL_LOCATION` (two-word: "external location"), `CLEAN_ROOM` (two-word: "clean room"), `STAGING_TABLE` (two-word: "staging table"), `EXTERNAL_METADATA` (two-word: "external metadata"). All these are consistent — flagging only because the package surfaces the same SCREAMING_SNAKE compound style without a TS-flavour alternative. The two-word compound makes member access very long: `SecurableType.STORAGE_CREDENTIAL` reads 27 chars. +- **Category:** Observation / 18 (long enum value set). +- **Suggested name:** PascalCase variant would shorten: `SecurableType.StorageCredential`, `SecurableType.CleanRoom`. Generator-locked. +- **Rationale:** Naming is internally consistent; flagging only as a style observation versus PascalCase TS conventions. + +### 24. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` +- **Why weird:** `EXTERNAL_METADATA` is undocumented. Neighbouring `STAGING_TABLE` carries a TODO/comment, but `EXTERNAL_METADATA` doesn't even say what it is. Unity Catalog has `externalmetadata` as its own package (`packages/externalmetadata/`), but this RFA enum member exists in isolation. +- **Category:** 1 (vague; no doc disambiguating). +- **Suggested name:** Keep name; add doc comment. +- **Rationale:** Naming OK, but undocumented enum members in a 17-element enum mean readers must cross-reference to other packages. + +### 25. `Principal` is exported but `principalType` field has no doc — `model.ts:148` +- **Why weird:** `principalType?: PrincipalType | undefined` has no JSDoc. Sibling `id` has a doc. The PrincipalType enum has only an `_UNSPECIFIED` sentinel + three values, none of which clarify when each applies. Caller has to guess by inspecting the IAM service. +- **Category:** 1 (vague). +- **Suggested name:** Keep name; add doc. +- **Rationale:** Mechanical. + +### 26. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` +- **Why weird:** `permissions` is `string[]` rather than an enum. Doc says "List of requested Unity Catalog permissions" — UC permissions are a known closed set (`SELECT`, `MODIFY`, `USAGE`, `READ_VOLUME`, etc.), so this should be a typed enum or branded string. Bare `string[]` loses any compile-time guard against typos. +- **Category:** 16 (field type contradicts domain — should be enum or branded string). +- **Suggested name:** Keep name; type as `UnityCatalogPermission[]` (new enum). Or document the closed set inline. +- **Rationale:** Same problem as #10. The wire is string, but TS could narrow it. + +### 27. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` +- **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. +- **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). +- **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). +- **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. + +### 28. Three Client methods, three different domain entity names — `client.ts:74,113,147` +- **Why weird:** `Client.batchCreateAccessRequests` works on `requests`. `Client.getAccessRequestDestinations` works on `destinations`. `Client.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. +- **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). +- **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). +- **Rationale:** A class with three methods that cover two disjoint resources is hiding the resource boundary. + +## Low severity + +### 29. `unmarshalAccessRequestDestinationsSchema` (and 6 other `unmarshal*Schema` / `marshal*Schema`) — `model.ts:189,212,223,236,249,259,271,291,301,315,327,337,349` +- **Why weird:** 12 marshal/unmarshal schemas, all suffixed `Schema`. Names get long (`unmarshalAccessRequestDestinationsSchema` = 38 chars). The suffix repeats info already captured by the `z.ZodType<...>` typing. +- **Category:** 8 (redundant suffix `Schema`). +- **Suggested name:** Drop `Schema` (`unmarshalAccessRequestDestinations`, `marshalCreateAccessRequest`), or shorten to `decode*`/`encode*` verbs. +- **Rationale:** Internal/generator style; same finding as `connections#33`, recurs across the SDK. + +### 30. `marshalRequest` / `parseResponse` verb asymmetry — `utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same file. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. +- **Rationale:** Cross-package: same finding as `connections#39`. + +### 31. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. +- **Category:** 1 (vague), 17. +- **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. +- **Rationale:** Same as `connections#40`. + +### 32. `HttpCallOptions` — `utils.ts:15` +- **Why weird:** Yet another `Options` suffix; the file imports `Options` from `@databricks/sdk-core/api` and `CallOptions` from `@databricks/sdk-options/call`. Three `Options` types in scope. `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). +- **Rationale:** Same as `connections#41`. + +### 33. `readAll` — `utils.ts:40` +- **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `readStreamToEnd` / `drainStream`. +- **Rationale:** Same as `connections#38`. + +### 34. `flattenQueryParams` — `utils.ts:123` +- **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Remove from utils if it's a generator default. +- **Rationale:** Generator emits the same helper into every package even when unused. Same as `connections#37`. + +### 35. `PACKAGE_SEGMENT` constant — `client.ts:35` +- **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Same as `connections#36`. + +### 36. `Client` class — `client.ts:40` +- **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). +- **Category:** 1 (vague). +- **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). +- **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. + +### 37. `buildHttpRequest` parameter list — `utils.ts:96-102` +- **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. The function name `buildHttpRequest` doesn't communicate the parameter order; callers in `client.ts:87,122,166` pass them positionally. Easy to confuse `signal` and `body` (both optional, both at the end). +- **Category:** 1 (vague — five-positional builder). +- **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. +- **Rationale:** Five-positional builders without object syntax are an anti-pattern in modern TS. + +### 38. `marshalRequest(data: unknown, schema: z.ZodType): string` — `utils.ts:119` +- **Why weird:** The function parses `data` against `schema` and returns a JSON string. The name says "marshal request", but it's used for *any* outbound body, including update bodies that aren't strictly "requests" in the sense of "user-facing request DTO" (e.g. line 158 marshals `accessRequestDestinations` which is the payload of an update, not the wrapping `UpdateAccessRequestDestinationsRequest`). +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `marshalJson` or `serializeBody`. +- **Rationale:** Mechanical; not blocking. + +### 39. `parseResponse` typed return — `utils.ts:113` +- **Why weird:** Returns `T` where `T` is the schema's inferred type. The name "parse" overloads with `JSON.parse` (called inside) and with `schema.parse` (also called inside). Three layers of "parse" in nine lines. +- **Category:** 1 (vague). +- **Suggested name:** `decodeResponse` or `unmarshalJson`. +- **Rationale:** Mechanical. + +### 40. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` +- **Why weird:** The `Options` shape is built with a series of `...(options?.foo !== undefined && {foo: options.foo})` spreads. The pattern is a TS-idiom for conditional spread of optional fields. Naming-wise: the local `opts` variable is intentionally one letter shorter than `options` to disambiguate — but the shadowing convention isn't documented. +- **Category:** Observation. +- **Suggested name:** Rename inner `opts` → `internalOptions` (or the outer parameter to `callOptions`). +- **Rationale:** Mechanical. + +### 41. `accessRequestDestinationsFieldMaskSchema` and `securableFieldMaskSchema` — `model.ts:359,380` +- **Why weird:** Internal `*FieldMaskSchema` constants (not exported). Names are 41 / 26 chars. Inconsistent capitalization with other helpers (`unmarshal*Schema` is exported, `*FieldMaskSchema` is not — yet both end with `Schema`). +- **Category:** 8 (redundant suffix `Schema`). +- **Suggested name:** `accessRequestDestinationsFieldMask` (drop trailing `Schema`). +- **Rationale:** Generator-emitted; cross-package consistency issue. + +## Observations + +### 42. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` +The index file exports the `Client`, all four enums, and all nine model interfaces (`AccessRequestDestinations`, `BatchCreateAccessRequestsRequest`, `BatchCreateAccessRequestsResponse`, `CreateAccessRequest`, `CreateAccessRequestResponse`, `GetAccessRequestDestinationsRequest`, `NotificationDestination`, `Principal`, `Securable`, `SecurablePermissions`, `UpdateAccessRequestDestinationsRequest`). It does *not* export the `marshal*`/`unmarshal*` schemas or the `accessRequestDestinationsFieldMask` helper. Consistent with the other packages but means the field-mask helper isn't available to consumers. +- **Category:** Observation. + +### 43. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. +- **Category:** Observation. + +### 44. No tests in the package +`package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. The package ships untested. Not a naming issue, but cross-package noise — same as several other newly generated packages. +- **Category:** Observation. + +### 45. Action-verb conventions on `Client` +`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #28). +- **Category:** Observation. + +### 46. `package.json` description is empty string — `package.json:4` +`"description": ""`. The npm package has no public description string. Combined with the cryptic `rfa` name (see #1), this leaves users with no metadata to identify the package's purpose when browsing npm. +- **Category:** Observation. + +## Domain glossary +- **`rfa`** — **R**equest **F**or **A**ccess. The Databricks Unity Catalog API for managing access-request notifications to UC securables. There are two distinct concerns: + 1. **Access Requests** (`POST /api/3.0/rfa/requests`) — a *user* (or principal on whose behalf) is requesting permissions (`SELECT`, `MODIFY`, etc.) on a list of Unity Catalog securables (catalogs, schemas, tables, etc.). The response tells the caller *where* the request was routed (which destinations). + 2. **Access Request Destinations** (`GET`/`PATCH /api/3.0/rfa/destinations/...`) — administrative configuration of *which* destinations (email addresses, Slack channels, MS Teams webhooks, generic webhooks, URLs) receive notifications when end-users file an access request against a given securable. +- **`uc`** — Unity Catalog. Referenced indirectly in `CreateAccessRequest` doc comments ("requested UC privileges"). Not in field names. +- **`d2d`** — Delta-to-Delta (Delta Sharing peer-to-peer). Appears in `Securable.providerShare` doc comment ("D2D Delta Sharing"). Not expanded inline. +- **`UC-2980`** — internal JIRA ticket referenced in `SecurableType.STAGING_TABLE` TODO comment. Should not appear on public SDK surface. +- **`Securable`** — Unity Catalog term-of-art for any object that can be granted permissions: catalog, schema, table, view, volume, function, model, connection, credential, external location, share, recipient, clean-room, metastore, pipeline, external-metadata, staging-table. The full taxonomy lives in `SecurableType` (17 values incl. sentinel). +- **`Principal`** — Unity Catalog/IAM term for "an entity that can hold permissions": a user, a group, or a service principal. The `PrincipalType` enum disambiguates which kind. Used here as the "on behalf of" actor in `CreateAccessRequest`. +- **`SpecialDestination`** — five enum members denoting "the owner of the metastore/catalog/external-location/connection/credential" as an implicit email destination. These cannot be assigned; they're a default fallback. +- **`FieldMask`** — Google protobuf convention (re-used in Databricks API) for sparse-field updates in PATCH semantics. `accessRequestDestinationsFieldMask(...)` builds the wire-format paths. +- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #9). + +## File coverage +- `src/v1/model.ts` (385 lines): read fully. +- `src/v1/client.ts` (187 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (24 lines): read fully. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md new file mode 100644 index 00000000..1b2e7ae3 --- /dev/null +++ b/.agent/naming-audit/schemas.md @@ -0,0 +1,678 @@ +# Naming Audit: `schemas` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/schemas/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Domain:** Unity Catalog (UC) — schemas (the level beneath catalogs, parents of tables/views/functions). + +--- + +## Summary + +The `schemas` package exposes the standard five UC schema operations +(`createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, +`updateSchema`) plus a paginated iterator. The package is small (one +enum, one nested-flag type, the schema info type, five request types, +two response types, six map-entry wrapper types). Because it is a 1:1 +port of the Go SDK, most issues are inherited from upstream proto +definitions: the most pervasive problems are (1) proto-style +underscore-suffixed identifiers in the public TS surface +(`DeleteSchema_Response`, `ListSchemas_Response`, six `*_OptionsEntry`/ +`*_PropertiesEntry` wrappers), (2) `fullNameArg` as a cryptic path +parameter that coexists with `fullName` on the same type, (3) +`CreateSchema`/`UpdateSchema` carrying read-only server-populated +fields, and (4) the `CatalogType` enum living on a schema-only type +even though every variant duplicates the `_CATALOG` suffix that the +enum name already provides. There is also significant duplicate-concept +overlap with the sibling `systemschemas` package (separate types +`SchemaInfo` vs `SystemSchemaInfo`, separate clients, separate methods) +that the audit calls out at the package boundary. + +--- + +## Findings + +### 1. Vague / generic names + +#### 1.1 `EffectivePredictiveOptimizationFlag.value` (model.ts:81) +The flag wrapper exposes a single payload field named `value` — the +doc comment says "Whether predictive optimization should be enabled for +this object and objects under it". The name conveys nothing about +*what kind of value*; the type is `string` but the semantic is a +tri-state (enable / disable / inherit). A reader has to read the doc +to discover what is in it. Better: `enabled`, `setting`, or +`predictiveOptimization`. Same name appears in marshal/unmarshal +transforms (lines 243, 248, 361, 366). + +#### 1.2 `*_OptionsEntry.value` / `*_PropertiesEntry.value` (model.ts:59-66, 167-175, 225-232) +Six proto-generated map-entry wrappers exporting `{ key?: string; +value?: string }`. The field names `key` and `value` are maximally +generic. The wrapper types themselves are dead in the v1 surface +(`SchemaInfo.options`/`.properties` are typed as +`Record`, not arrays of these wrappers). See also §11.1. + +#### 1.3 `EffectivePredictiveOptimizationFlag.inheritedFromType` and `.inheritedFromName` (model.ts:83, 85) +`inheritedFromType` is `string`, not an enum — the name suggests a +typed handle but the value is human-readable text. Same problem for +`inheritedFromName`: "the name of the object" — of *what* object? +Without context (`catalog`, `schema`, `metastore`?) the field is +opaque. See also §6.1. + +#### 1.4 `name` on `CreateSchema`, `SchemaInfo`, `UpdateSchema` (model.ts:17, 126, 184) +`name` alone is generic in the context of UC where there's also +`fullName`, `catalogName`, `newName`, and `metastoreId`. The doc +qualifies it as "Name of schema, relative to parent catalog", but the +identifier itself doesn't say that. Compare to `catalogName` on the +same shape which is unambiguous. See also §10.2 and §12.2. + +--- + +### 2. Redundant enum prefixes + +#### 2.1 `CatalogType.*_CATALOG` (model.ts:6-13) +All six variants end in `_CATALOG`: + +- `MANAGED_CATALOG` +- `DELTASHARING_CATALOG` +- `SYSTEM_CATALOG` +- `INTERNAL_CATALOG` +- `FOREIGN_CATALOG` +- `MANAGED_ONLINE_CATALOG` + +Read aloud: `CatalogType.MANAGED_CATALOG`. The `_CATALOG` suffix is +redundant — `MANAGED`, `DELTA_SHARING`, `SYSTEM`, `INTERNAL`, +`FOREIGN`, `MANAGED_ONLINE` carries the same meaning. (`DELTASHARING` +also runs two words together — see §3.1.) The enum is duplicated +verbatim from the `catalogs` package — even though *this* package is +about schemas, it imports the catalog-type enum and exposes it as +`SchemaInfo.catalogType`. See §12.4 for the duplication. + +--- + +### 3. Acronym casing inconsistencies + +#### 3.1 `DELTASHARING_CATALOG` enum variant (model.ts:8) +"Delta Sharing" is two words; the variant runs them together as +`DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` — or just +`DELTA_SHARING` after stripping the `_CATALOG` suffix (§2.1). + +#### 3.2 "UC" / "Unity Catalog" inconsistency in URLs and doc text +The endpoint path is `/api/2.1/unity-catalog/schemas` (client.ts:77, +106, etc.) and the package docs spell out "Unity Catalog" / "the +Metastore" (client.ts:71). No identifier in the package uses `UC` — +only doc comments. Minor inconsistency, but flagged for cross-package +review. + +--- + +### 4. Underscores in TypeScript identifiers + +The package's most widespread cosmetic issue. Six exported types and +several schema exports use proto-style `Parent_Child` names with +`@typescript-eslint/naming-convention` suppression comments — i.e. the +lint rule already disagrees with these names. + +#### 4.1 `CreateSchema_OptionsEntry` (model.ts:58) +Proto map-entry. Should be `CreateSchemaOptionsEntry`, but the wrapper +itself should not exist (see §11.1). + +#### 4.2 `CreateSchema_PropertiesEntry` (model.ts:64) +Same as 4.1. + +#### 4.3 `DeleteSchema_Response` (model.ts:77) +Proto-style underscore identifier. Should be `DeleteSchemaResponse`. + +#### 4.4 `ListSchemas_Response` (model.ts:113) +Should be `ListSchemasResponse`. (Standard top-level response type; +underscore is a Go/proto artefact.) + +#### 4.5 `SchemaInfo_OptionsEntry` (model.ts:167) +Same as 4.1. + +#### 4.6 `SchemaInfo_PropertiesEntry` (model.ts:173) +Same as 4.1. + +#### 4.7 `UpdateSchema_OptionsEntry` (model.ts:225) +Same as 4.1. + +#### 4.8 `UpdateSchema_PropertiesEntry` (model.ts:231) +Same as 4.1. + +#### 4.9 `unmarshalDeleteSchema_ResponseSchema` (model.ts:237) +The underscore propagates into the schema export name. Should be +`unmarshalDeleteSchemaResponseSchema`. + +#### 4.10 `unmarshalListSchemas_ResponseSchema` (model.ts:254) +Same as 4.9. Should be `unmarshalListSchemasResponseSchema`. + +--- + +### 5. Cryptic abbreviations + +#### 5.1 `fullNameArg` (model.ts:71, 90, 180) +Path-parameter field on `DeleteSchema`, `GetSchema`, and +`UpdateSchema`. The `Arg` suffix is Go-generator jargon distinguishing +path arguments from request-body fields with the same key. TypeScript +callers have no need for this distinction — the field *is* the schema +identifier and should just be `fullName` (or `name`). Even worse: +`UpdateSchema` has *both* `fullNameArg` (path) and `fullName` (body) +on the same type, with no obvious difference in semantics. See §16.1. + +#### 5.2 `pkgJson` (client.ts:19) +Variable name `pkgJson` for `package.json` import. Mostly internal — +minor — but worth noting for consistency. + +#### 5.3 `req`, `resp`, `opts` (client.ts and utils.ts throughout) +Internal abbreviations. Conventional, but worth flagging for the +broader audit. + +--- + +### 6. Misleading names + +#### 6.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) +Field is typed `string | undefined` but the doc comment ("Whether +predictive optimization should be enabled…") implies a small discrete +set of values (enable / disable / inherit). Either expose an enum or +rename the field to make it clear it's a setting key. See also §1.1. + +#### 6.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:139) +The doc is honest: "Full name of schema, in form of +__catalog_name__.__schema_name__". But the field name `fullName` +suggests it might carry additional information not available from +`name`+`catalogName`. It doesn't. See also §12.2. + +#### 6.3 `SchemaInfo.options` vs `SchemaInfo.properties` (model.ts:161-164) +Both are `Record` with identical doc comments ("A map +of key-value properties attached to the securable."). There is no way +for a caller to know which to use for what. The doc duplication recurs +verbatim in `CreateSchema` (model.ts:51-54) and `UpdateSchema` +(model.ts:218-221). Either is underspecified or one of them is +misnamed. See §12.1. + +#### 6.4 `marshalRequest` parses the input before marshalling (utils.ts:119) +The function is named `marshalRequest` but its body is +`JSON.stringify(schema.parse(data))` — the schema's `.parse` step is +*validation*, not parsing. Not a schemas-specific issue, but the name +hides validation behaviour. (Inherited from sibling packages.) + +#### 6.5 `parseResponse` does parsing + validation (utils.ts:113) +Similar to 6.4: the name `parseResponse` understates that it also +validates with `schema.parse`. Defensible. + +--- + +### 7. Overly verbose + +#### 7.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) +39 characters. Compounded by `effectivePredictiveOptimizationFlag` as +a field name on three different request/response shapes (model.ts:44, +153, 211). Consider `EffectivePredictiveOptimization` (drop the +`Flag` suffix — the type already wraps the flag) or +`EffectivePOSetting` if shortening is acceptable. See also §8.4. + +#### 7.2 `enablePredictiveOptimization: string` (model.ts:27, 136, 194) +Long field name for what is effectively a flag value. Acceptable, but +pairs with §7.1 to make every schema shape verbose. + +#### 7.3 `unmarshalEffectivePredictiveOptimizationFlagSchema` / +`marshalEffectivePredictiveOptimizationFlagSchema` (model.ts:240, 359) +Schema exports of ~50 characters. Hard to read. + +#### 7.4 `MANAGED_ONLINE_CATALOG` enum value (model.ts:12) — 22 characters; redundant `_CATALOG` per §2.1. + +--- + +### 8. Redundant suffixes + +#### 8.1 `SchemaInfo` type name (model.ts:124) +"Info" is a non-suffix — it carries no semantic content. In the Go SDK +this distinguishes the entity type from a resource handle; in TS the +convention is to drop it (`Schema`). Compare with `Catalog`, `Table`, +etc. in other packages. + +#### 8.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) +The whole type *is* the flag; the suffix is redundant. See §7.1. + +#### 8.3 `Arg` suffix on `fullNameArg` — see §5.1 and §16.1. + +#### 8.4 `…Schema` suffix on every zod schema export (`unmarshalSchemaInfoSchema`, `marshalCreateSchemaSchema`, etc.) +Defensible (signals it's a zod schema), but the schema-ness is already +conveyed by the `marshal…`/`unmarshal…` prefix. Note the unfortunate +double-`Schema` in `unmarshalSchemaInfoSchema` and +`marshalCreateSchemaSchema` — once for "Schema" (the resource) and once +for "Schema" (the zod artefact). See also §20.4. + +#### 8.5 `unmarshal…Schema` / `marshal…Schema` double-`Schema` collision +The single most jarring identifier in the package is +`marshalCreateSchemaSchema` (model.ts:312) — both halves of the +compound carry the word "Schema". Unique to this package because the +domain entity is itself called "schema". + +--- + +### 9. Singular / plural mismatches + +#### 9.1 `Client.listSchemasIter` returns `AsyncGenerator` (client.ts:213) +Method name `listSchemasIter` implies "list of schemas iterator"; the +generator actually yields single `SchemaInfo` items one at a time. +Consistent with neighbouring packages. Worth a sanity check — +`iterSchemas` (verb-first) reads more naturally for an iterator and +avoids the singular/plural conflict. + +#### 9.2 No other plural mismatches noticed. + +--- + +### 10. Reserved-word collisions + +#### 10.1 `options` field on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:54, 163, 221) +`options` collides with the SDK's own `CallOptions` parameter name +used throughout the client (`createSchema(req, options)`, client.ts:74, +etc.). Not a compile error but creates cognitive load — inside +`createSchema(req, options)` the reader sees both `req.options` +(schema metadata) and `options` (call options). The cleanest fix is to +rename the client parameter to `callOptions`. See also §12.1 for the +duplicate-with-`properties` concern. + +#### 10.2 `name` field is generic and shadows `Function.prototype.name` +Used on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:17, 184, +126). Not a reserved word, but commonly shadows the standard +`Function.prototype.name` and routinely confuses callers who spread +request objects. See also §1.4. + +#### 10.3 `value` field on `EffectivePredictiveOptimizationFlag.value` (model.ts:81) +Generic field name, frequently shadows local variables. See §1.1. + +#### 10.4 `properties` is not reserved but conflicts with `Object` semantics +`SchemaInfo.properties` (model.ts:161) is fine but worth noting that +`properties` is a heavily-overloaded term in JS (object properties, +descriptor properties, etc.). Combined with the duplicate-with-`options` +problem in §12.1, the name is doubly overloaded. + +--- + +### 11. Empty / trivial wrapper types + +_None._ + +--- + +### 12. Duplicate concepts + +#### 12.1 `properties` vs `options` (model.ts:51-54, 161-164, 218-221) +Both `Record` on every schema shape, with identical +doc comments ("A map of key-value properties attached to the +securable."). Either the documentation needs to differentiate them or +one is redundant. See also §6.4. + +#### 12.2 `name` vs `fullName` on `SchemaInfo` (model.ts:126, 139) +`name` is the schema name "relative to parent catalog"; `fullName` is +"in form of __catalog_name__.__schema_name__". These two fields are +deterministically derivable from each other (given `catalogName`). +Mirror issue in `CreateSchema` (model.ts:17, 31) and `UpdateSchema` +(model.ts:184, 197). See also §6.2. + +#### 12.3 `fullName` vs `fullNameArg` on `UpdateSchema` (model.ts:180, 197) +The `UpdateSchema` request has **both** `fullNameArg` (the existing +schema identifier, path param) and `fullName` (the same field name on +the body) — plus `newName` for renaming. Three fields all touching +the schema's identity. See §16.1. + +#### 12.4 `CatalogType` is re-implemented across packages +The exact `CatalogType` enum (with all six variants) is defined here +(model.ts:6-13) and also in `catalogs` (and likely in several other UC +packages). A consumer touching both packages gets two unrelated TS +types named `CatalogType`. Cross-package duplication — flagged in +this audit for the broader review. + +#### 12.5 `EffectivePredictiveOptimizationFlag` may be duplicated +This type is identical to the one in `catalogs` (and probably in any +UC securable package). Cross-package duplication. + +#### 12.6 `CreateSchema`, `UpdateSchema`, and `SchemaInfo` share ~21 fields verbatim +All three types are 95% identical with identical doc strings. This is +a generator artefact, but any rename of `storageRoot` must happen in +three places. Recommend basing `CreateSchema`/`UpdateSchema` on +`Partial` or a shared `SchemaProperties` mixin. + +#### 12.7 Overlap with `systemschemas` package +The sibling `systemschemas` package operates on a completely different +shape (`SystemSchemaInfo` has only `schema` and `state` — no overlap +with `SchemaInfo`). Same noun, different types, different clients, +different methods. A consumer might reasonably expect one client to +handle both kinds of schemas; instead they must import two packages. +At minimum, the type names should be sufficiently distinguishable — +`SchemaInfo` vs `SystemSchemaInfo` is fine, but the *package* names +(`@databricks/sdk-schemas` vs `@databricks/sdk-systemschemas`) are +trap-shaped: a consumer who imports the first expecting "all schemas" +will be surprised to find that system schemas live elsewhere. + +--- + +### 13. Verb-tense inconsistency + +#### 13.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. + +#### 13.2 `unmarshal…` / `marshal…` schema-export prefixes are consistent. No issues. + +#### 13.3 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. + +No verb-tense inconsistencies found across the package. + +--- + +### 14. Go / Java-style names + +#### 14.1 `…_Response` suffix on response types (`DeleteSchema_Response`, `ListSchemas_Response`) +Proto / gRPC convention `Method_Response`. In TS this should be +`DeleteSchemaResponse` / `ListSchemasResponse`. See §4.3-4.4. + +#### 14.2 `…_OptionsEntry` / `…_PropertiesEntry` map-entry wrappers (six occurrences) +Proto map-entry idiom doesn't exist in TS. See §4.1-4.8. + +#### 14.3 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +Java/Go style. TS convention is to drop it. See §8.1. + +#### 14.4 `Client` class name (client.ts:44) +Bare `Client` (rather than `SchemasClient`) is a Go-idiom: package +qualifies the type. JS consumers commonly import as +`import {Client} from '@databricks/sdk-schemas/v1'` and have to alias. +Package-wide convention; flagged for the broader review. + +#### 14.5 `fullNameArg` — Go-generator naming. See §5.1. + +#### 14.6 `unmarshal…` / `marshal…` (Go's `encoding/json` verbs) +Direct Go ports. TS ecosystem typically uses `parse` / `serialize` or +`decode` / `encode`. Defensible because they're internal to the +generated layer. + +#### 14.7 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) +Constant naming is fine; flagged for completeness. + +--- + +### 15. Generic field names losing meaning + +#### 15.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. + +#### 15.2 `key`, `value` on map-entry wrappers — see §1.2. + +#### 15.3 `name` on three different schema shapes — see §1.4. + +#### 15.4 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §6.3, §12.1. + +#### 15.5 `comment` (model.ts:23, 132, 190) +"User-provided free-form text description." `comment` is too informal +for a documented free-text description on a metadata API. +`description` would be more honest about its purpose. + +--- + +### 16. Field contradicting type domain + +#### 16.1 `UpdateSchema` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 197, 182) +Four name-bearing fields on a single update request: + +- `fullNameArg` — existing schema identifier (path param). +- `name` — "Name of schema, relative to parent catalog" (body). +- `fullName` — "Full name of schema, in form of catalog.schema" (body). +- `newName` — "New name for the schema" (body). + +A caller staring at this struct cannot reasonably intuit which to set +to rename the schema. (The answer is `newName`, with `fullNameArg` +identifying the existing schema; the others are vestigial in the +update context.) This is the single most user-hostile naming pattern +in the package — and it sits on the most-used mutation method. + +#### 16.2 `CreateSchema` contains read-only output fields (model.ts:32-50) +`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, +`fullName`, `catalogType`, `effectivePredictiveOptimizationFlag`, +`schemaId`, `browseOnly`. These are server-populated; a creator +setting them is at best ignored. The type's domain is "create +request", but its shape contradicts that. Same mirror issue in +`UpdateSchema` (model.ts:199-217). + +#### 16.3 `DeleteSchema.fullNameArg` — see §5.1. + +#### 16.4 `GetSchema.fullNameArg` (model.ts:90) +Same as 16.3. + +--- + +### 17. Inconsistent action verbs + +Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, +`listSchemas`, `updateSchema`, `listSchemasIter`. Verbs are consistent +— standard CRUD plus a `…Iter` paginator. No `fetch…` / `retrieve…` / +`read…` outliers. No issues found. + +--- + +### 18. Long enum values + +#### 18.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:12) +22-character enum value. Should be `MANAGED_ONLINE` after dropping the +redundant `_CATALOG` suffix (§2.1). + +#### 18.2 `CatalogType.DELTASHARING_CATALOG` (model.ts:8) +20-character value; redundant suffix + run-together words. See §3.1. + +#### 18.3 Other `CatalogType` variants +`MANAGED_CATALOG` (15), `SYSTEM_CATALOG` (14), `INTERNAL_CATALOG` +(16), `FOREIGN_CATALOG` (15). All have redundant `_CATALOG` suffix. +See §2.1. + +--- + +### 19. Underspecified IDs + +#### 19.1 `metastoreId` (model.ts:29, 138, 196) +Documented as "unique identifier of parent metastore". Format opaque +(UUID? slug?). Acceptable but unspecified. + +#### 19.2 `schemaId` (model.ts:48, 157, 215) +"The unique identifier of the schema." No format hint (UUID?). The +field exists alongside `fullName` (which is also a unique identifier +in a different sense). Two simultaneous IDs without disambiguation. + +#### 19.3 `createdAt` / `updatedAt` (model.ts:33, 37, 142, 146, 200, 204) +Type is `number` (epoch milliseconds, per the doc). The unit is not +encoded in the field name. `createdAtMs` / `updatedAtMs` would be +more honest. (Compare to `lastFailoverTimeMs` in `catalogs`, which +gets this right — see catalogs.md §19.7.) + +#### 19.4 `createdBy` / `updatedBy` (model.ts:35, 39, 144, 148, 202, 206) +Type is `string` — "Username of schema creator" / "Username of user +who last modified schema". Underspecified: is this a username, an +email, a principal ID? `createdByUsername` would be clearer. + +#### 19.5 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) +Both `string`. `inheritedFromType` could be one of the UC securable +types, but the field is not enum-typed. `inheritedFromName` is opaque +text. See also §1.3, §1.5. + +--- + +### 20. Type-suffix tautology + +#### 20.1 `CatalogType` enum with field `catalogType: CatalogType` +(model.ts:6, 41, 150, 208) — field name tautological with type name. +Defensible (field carries the dynamic value) but worth flagging. + +#### 20.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. + +#### 20.3 `EffectivePredictiveOptimizationFlag` with field `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` +(model.ts:44, 153, 211) — field repeats type name verbatim, 35 +characters each. Severe tautology, but defensible because the field +is the only instance of that type in each parent. Could be shortened +to `predictiveOptimization: EffectivePredictiveOptimization` (drop +"Flag" per §8.3 and "effective" per §7.1). + +#### 20.4 Schema-export tautology +`unmarshalSchemaInfoSchema: z.ZodType` (model.ts:265), +`marshalCreateSchemaSchema` (model.ts:312) — the `Schema` suffix +duplicates `z.ZodType<…>`. Worse, the *resource* is also called +"Schema", so identifiers like `marshalCreateSchemaSchema` mean +"marshal-schema for the CreateSchema schema". Maximal `Schema`-pile-up +in the SDK. See also §8.5, §8.6. + +--- + +## Additional / cross-cutting observations + +### A. `flattenQueryParams` is defined but unused (utils.ts:123) +Each `listSchemas` / `getSchema` / `deleteSchema` handler builds query +strings inline with `URLSearchParams.append` (client.ts:107-110, +138-141, 179-191). The exported helper `flattenQueryParams` is never +referenced by `client.ts`. Either it's intentionally exported for +consumer use (then it should be documented and reside in `utils` +proper) or it's dead code. Same pattern as `catalogs` package. + +### B. `fullNameArg` URL substitution silently allows empty string (client.ts:106, 137, 239) +`${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL +silently becomes `/api/2.1/unity-catalog/schemas/` and the request +will fail on the server. The naming (`fullNameArg`) and the +substitution behaviour together hide what should be a required +parameter. The type marks it `string | undefined` even though it is +operationally required. + +### C. `marshalUpdateSchemaSchema` serialises `fullNameArg`/`newName` into the body (model.ts:398-399) +`fullNameArg` is a path parameter, but the marshal transform produces +JSON fields `full_name_arg` and `new_name` in the body. Either the +server tolerates extra fields or this is a bug. The naming choice +(`Arg`) lets the bug hide. + +### D. Marshal/unmarshal exports lack consistent generic types (model.ts) +`marshalCreateSchemaSchema: z.ZodType` (no generic) versus +`unmarshalSchemaInfoSchema: z.ZodType` (with generic). The +marshal side is implicitly untyped. Not a naming issue per se, but +worth surfacing. + +### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +"Host is required." — bare `Error`. Not a naming issue, flagged in +passing for the broader review. + +### F. `index.ts` re-exports proto-style names verbatim (lines 9, 10, 11, 12, 14, 15, 16, 19, 20, 21) +Every underscore-bearing identifier surfaces in the package's public +API. A consumer of `@databricks/sdk-schemas/v1` sees +`CreateSchema_OptionsEntry`, `CreateSchema_PropertiesEntry`, +`DeleteSchema_Response`, `ListSchemas_Response`, +`SchemaInfo_OptionsEntry`, `SchemaInfo_PropertiesEntry`, +`UpdateSchema_OptionsEntry`, `UpdateSchema_PropertiesEntry` as +first-class exports. This is the highest-leverage place to clean +naming. + +### G. The package name is plural; the entity types are singular +The package is `schemas` (plural); the model types are `Schema` (well, +`SchemaInfo` — singular). The five client methods mix: +`createSchema`/`deleteSchema`/`getSchema`/`updateSchema` (singular — +they act on one) and `listSchemas`/`listSchemasIter` (plural — they +return many). This is the same pattern as `catalogs`, `tables`, etc. +— consistent across the SDK. + +### H. `SchemaInfo`'s "Next ID: 45" comment (model.ts:123) +The doc comment is a leftover proto field-number management note. It +has no consumer-facing meaning. Should be stripped on the way to TS. + +### I. Doc comment for `effectivePredictiveOptimizationFlag` is missing (model.ts:44-46, 153-155, 211-213) +The field has no JSDoc, even though the type has a doc. Three +occurrences. Consistency: every other field has a doc comment. + +### J. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) +The field name says "enable" — suggesting boolean — but the type is +`string`. The actual value is presumably `'ENABLE' | 'DISABLE' | +'INHERIT'` or similar. The name lies about the type. See also §6.1 +for the related `EffectivePredictiveOptimizationFlag.value`. + +### K. Overlap with `systemschemas` package — see §12.7 +A consumer reading "schemas" reasonably expects to find all schema +operations here. They will not find `disableSystemSchema`, +`enableSystemSchema`, or `listSystemSchemas` — those live in +`@databricks/sdk-systemschemas`. Package boundaries follow the +upstream API surface, but the seam is non-obvious to discover. + +--- + +## File / line index for fast lookup + +| Identifier | Location | Finding | +| ----------------------------------------------------------- | --------------------- | -------------------- | +| `CatalogType` | model.ts:6 | 2.1, 12.4, 18.x, 20.1| +| `CatalogType.MANAGED_CATALOG` | model.ts:7 | 2.1, 18.3 | +| `CatalogType.DELTASHARING_CATALOG` | model.ts:8 | 2.1, 3.1, 18.2 | +| `CatalogType.SYSTEM_CATALOG` | model.ts:9 | 2.1, 18.3 | +| `CatalogType.INTERNAL_CATALOG` | model.ts:10 | 2.1, 18.3 | +| `CatalogType.FOREIGN_CATALOG` | model.ts:11 | 2.1, 18.3 | +| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:12 | 2.1, 18.1 | +| `CreateSchema` | model.ts:15 | 12.6, 16.2 | +| `CreateSchema.name` | model.ts:17 | 1.4, 10.2 | +| `CreateSchema.catalogType` | model.ts:41 | 20.1 | +| `CreateSchema.effectivePredictiveOptimizationFlag` | model.ts:44 | 7.1, 7.3, 20.3, I | +| `CreateSchema.properties` / `.options` | model.ts:52, 54 | 6.3, 10.1, 12.1, 15.4| +| `CreateSchema_OptionsEntry` | model.ts:58 | 1.2, 4.1, 14.2 | +| `CreateSchema_PropertiesEntry` | model.ts:64 | 1.2, 4.2, 14.2 | +| `DeleteSchema` | model.ts:69 | 16.3 | +| `DeleteSchema.fullNameArg` | model.ts:71 | 5.1, 14.5, 16.3, B | +| `DeleteSchema_Response` | model.ts:77 | 4.3, 14.1 | +| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 7.1, 7.3, 8.2, 14.3, 20.3 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 6.1, 10.3, 15.1 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.3, 19.5 | +| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.3, 19.5 | +| `GetSchema.fullNameArg` | model.ts:90 | 5.1, 14.5, 16.4, B | +| `ListSchemas` | model.ts:95 | — | +| `ListSchemas.maxResults` | model.ts:105 | — | +| `ListSchemas.pageToken` | model.ts:107 | — | +| `ListSchemas.includeBrowse` | model.ts:109 | — | +| `ListSchemas_Response` | model.ts:113 | 4.4, 14.1 | +| `SchemaInfo` | model.ts:124 | 8.1, 12.6, 14.3, H | +| `SchemaInfo.name` | model.ts:126 | 1.4, 10.2 | +| `SchemaInfo.fullName` | model.ts:139 | 6.2, 12.2 | +| `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 19.3 | +| `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 19.4 | +| `SchemaInfo.catalogType` | model.ts:150 | 20.1 | +| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 7.1, 20.3, I | +| `SchemaInfo.schemaId` | model.ts:157 | 19.2 | +| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 6.3, 10.1, 12.1, 15.4| +| `SchemaInfo_OptionsEntry` | model.ts:167 | 1.2, 4.5, 14.2 | +| `SchemaInfo_PropertiesEntry` | model.ts:173 | 1.2, 4.6, 14.2 | +| `UpdateSchema` | model.ts:178 | 12.3, 12.6, 16.1, 16.2 | +| `UpdateSchema.fullNameArg` | model.ts:180 | 5.1, 12.3, 14.5, 16.1, B | +| `UpdateSchema.newName` | model.ts:182 | 16.1 | +| `UpdateSchema.name` | model.ts:184 | 1.4, 10.2, 16.1 | +| `UpdateSchema.fullName` | model.ts:197 | 12.2, 12.3, 16.1 | +| `UpdateSchema.effectivePredictiveOptimizationFlag` | model.ts:211 | 7.1, 20.3, I | +| `UpdateSchema_OptionsEntry` | model.ts:225 | 1.2, 4.7, 14.2 | +| `UpdateSchema_PropertiesEntry` | model.ts:231 | 1.2, 4.8, 14.2 | +| `unmarshalDeleteSchema_ResponseSchema` | model.ts:237 | 4.9 | +| `unmarshalEffectivePredictiveOptimizationFlagSchema` | model.ts:240 | 7.3, 8.4 | +| `unmarshalListSchemas_ResponseSchema` | model.ts:254 | 4.10 | +| `unmarshalSchemaInfoSchema` | model.ts:265 | 8.4, 8.5, 20.4 | +| `marshalCreateSchemaSchema` | model.ts:312 | 8.4, 8.5, 20.4 | +| `marshalEffectivePredictiveOptimizationFlagSchema` | model.ts:359 | 7.3, 8.4 | +| `marshalUpdateSchemaSchema` | model.ts:371 | 8.4, 8.5, 20.4, C | +| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | J | +| `comment` field | model.ts:23, 132, 190 | 15.5 | +| `Client` (bare name) | client.ts:44 | 14.4 | +| `Client.listSchemasIter` | client.ts:213 | 9.1 | +| `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 137, 239 | B | +| `flattenQueryParams` (unused export) | utils.ts:123 | A | +| `marshal…` / `unmarshal…` verbs | model.ts (many) | 14.6 | +| `…Schema` suffix on schema exports | model.ts (many) | 8.4, 8.5, 20.4 | +| `index.ts` re-exports | index.ts:7-23 | F | +| Cross-package overlap with `systemschemas` | (package boundary) | 12.7, K | + +--- + +## Recommended priority order + +1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchema`** — four name-like fields on the same request, the worst user-facing trap in the package. (§16.1, §5.1, §12.3) +2. **Strip the redundant `_CATALOG` suffix from every `CatalogType` variant.** (§2.1, §18.x) +3. **Drop proto-style `Parent_Child` identifiers** (`DeleteSchema_Response`, `ListSchemas_Response`, six `*_OptionsEntry`/`*_PropertiesEntry`). (§4) +4. **Distinguish or merge `options` and `properties`.** (§12.1, §6.3) +5. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§6.1, J) +6. **Strip read-only fields from `CreateSchema`/`UpdateSchema`.** (§16.2) +7. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +8. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§19.3) +9. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§19.2, §12.2) +10. **Drop the `Next ID: 45` proto leftover from `SchemaInfo` JSDoc.** (H) +11. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§12.7, K) diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md new file mode 100644 index 00000000..fa42c7c4 --- /dev/null +++ b/.agent/naming-audit/secrets.md @@ -0,0 +1,657 @@ +# Naming Audit: `secrets` package (v1) + +**Package path:** `/home/parth.bansal/sdk-js/packages/secrets/` +**Module name:** `@databricks/sdk-secrets` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts` +**Inferred domain:** Workspace-level "Secret Manager" (Databricks Secrets API, +`/api/2.0/secrets/...`). Provides three resources: secret scopes (containers, +either Databricks-managed or Azure KeyVault-backed), secrets (key/value +entries inside a scope, value stored as bytes), and ACLs (per-principal +read/write/manage permissions on a scope). + +Notation: file paths are relative to the package root. Findings reference +`file:line`. + +--- + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 8 | +| Medium | 15 | +| Low | 11 | +| Observation | 5 | +| **Total** | **39** | + +Headline themes: + +1. **Cross-package namespace collision with three sibling "secret" packages.** + The repo ships four `*secret*` packages — `secrets` (this one, workspace + Secret Manager), `secretsuc` (Unity Catalog secrets, three-level + namespace), `serviceprincipalsecrets` (account-level OAuth client secrets), + and `serviceprincipalsecretsproxy` (workspace-level proxy for the same). + All four export a class literally named `Client` and types with the noun + `Secret`. Cross-package usage is opaque without aliasing. +2. **Pervasive proto-style `Parent_Response` underscore identifiers.** Every + non-`Get` operation produces an empty `_Response` envelope + (`CreateScope_Response`, `DeleteAcl_Response`, ...). Eleven of the + thirteen public types in `model.ts` carry an underscore, and every one of + them sits behind an `eslint-disable @typescript-eslint/naming-convention` + comment. +3. **Action-verb request types collide with same-named client methods.** + `interface CreateScope` describes the request body; `client.createScope` + performs the action. The reader has to mentally distinguish the noun-from- + verb each time. Six pairs in this file (`CreateScope`, `DeleteAcl`, + `DeleteScope`, `DeleteSecret`, `GetAcl`, `GetSecret`, `ListAcls`, + `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret`). +4. **Inconsistent action verb across mutating operations.** `Put` for + creating/updating ACLs and secrets, `Create` for scopes, `Delete` for + all three. There is no `Update`. Go's REST SDK adopts the same shape, but + `Put` reads as Go/HTTP-method jargon rather than a TS-side action verb. +5. **`scope: string | undefined` everywhere — but required in practice.** + Eleven of twelve operation request types have `scope?: string | undefined` + as their primary identifier. Every server endpoint will reject an absent + scope. The "optional" marker is a generator artifact (all proto fields + are optional), not a real contract. Same pattern for `key` and + `principal`. + +--- + +## High Severity + +### H1. Package collision: four "secret" packages, opaque imports + +- **Affected:** `package.json:2` (`@databricks/sdk-secrets`); compare + `@databricks/sdk-secretsuc`, `@databricks/sdk-serviceprincipalsecrets`, + `@databricks/sdk-serviceprincipalsecretsproxy`. +- **Category:** #1 vague/generic, #12 duplicate concepts. +- **Issue:** All four packages legitimately deal with "secrets" but at very + different layers: + - `secrets` (this package) — workspace-level Secret Manager. Key/value + secrets inside named scopes, with per-scope ACLs. + Endpoint: `/api/2.0/secrets/...`. Domain noun: `SecretScope`. + - `secretsuc` — Unity Catalog secrets. Three-level namespace + (catalog.schema.secret). Domain noun: `Secret` (UC-style). + - `serviceprincipalsecrets` — account-level OAuth M2M client secrets for + service principals. + - `serviceprincipalsecretsproxy` — the same API exposed at the workspace + level via a proxy endpoint. +- The literal symbol `Client` is exported by all four (`index.ts:3`). An + importer writing `import {Client} from '@databricks/sdk-secrets'` cannot + visually distinguish from the other three without aliasing + (`import {Client as SecretsClient}`). Compare to the sibling + `serviceprincipalsecrets` vs `serviceprincipalsecretsproxy` collision + flagged in the `credentials` audit H1. +- **Suggestion:** rename the exported class to `SecretsClient` (and the + three siblings to `SecretsUCClient`, `ServicePrincipalSecretsClient`, + `ServicePrincipalSecretsProxyClient`), so the `Client` symbol does not + appear bare in any of them. Document the four-package matrix in each + package's README. + +### H2. `Client` is unqualified; collides on import with every other package + +- **File / line:** `src/v1/client.ts:70` (`export class Client`); re-exported + from `src/v1/index.ts:3`. +- **Category:** #1 vague/generic. +- **Current:** `export class Client`. +- **Suggestion:** `export class SecretsClient`. +- **Rationale:** Per repo-wide pattern, every package exports `Client`. Once + two such packages are imported into the same file the user must alias one + of them. Same defect flagged in `credentials.md` #10, `resourcequotas.md` + (implicit), and others. Self-identifying class names eliminate the alias + dance entirely. + +### H3. Eleven proto-style `Parent_Response` types violate TS identifier convention + +- **Files / lines:** `src/v1/model.ts:63, 73, 81, 91, 108, 121, 130, 141, + 156, 178`. Schema constants mirror them: `model.ts:227, 231, 235, 239, + 243, 258, 267, 277, 287, 291`. All eleven sit behind + `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. +- **Category:** #4 underscore in TS identifier, #14 Go/Java-style name. +- **Current:** `CreateScope_Response`, `DeleteAcl_Response`, + `DeleteScope_Response`, `DeleteSecret_Response`, `GetSecret_Response`, + `ListAcls_Response`, `ListScopes_Response`, `ListSecrets_Response`, + `PutAcl_Response`, `PutSecret_Response`. Schemas + `unmarshalCreateScope_ResponseSchema`, etc. +- **Suggestion:** `CreateScopeResponse`, ..., `unmarshalCreateScopeResponseSchema`, + etc. (collapse the underscore). +- **Rationale:** Same defect class as `resourcequotas.md` H2 and + `credentials.md` #18. The codebase itself rejects this convention — every + declaration carries an ESLint disable annotation. Eleven disables in one + file is a strong signal that the generator is producing wrong identifiers. + +### H4. Six request types are verb phrases (action collision with client methods) + +- **Files / lines:** `src/v1/model.ts:51` (`CreateScope`), `:65` (`DeleteAcl`), + `:75` (`DeleteScope`), `:83` (`DeleteSecret`), `:93` (`GetAcl`), `:100` + (`GetSecret`), `:115` (`ListAcls`), `:127` (`ListScopes`), `:135` + (`ListSecrets`), `:146` (`PutAcl`), `:158` (`PutSecret`). +- **Category:** #14 Go/Java-style name (action used as data type). +- **Current example:** `client.createScope(req: CreateScope)`. +- **Suggestion:** `CreateScopeRequest`, `DeleteAclRequest`, + `DeleteScopeRequest`, `DeleteSecretRequest`, `GetAclRequest`, + `GetSecretRequest`, `ListAclsRequest`, `ListScopesRequest`, + `ListSecretsRequest`, `PutAclRequest`, `PutSecretRequest`. (See sibling + package `secretsuc` which already uses the `…Request` suffix — + `CreateSecretRequest`, `DeleteSecretRequest`, etc.) +- **Rationale:** Reading `client.createScope(req: CreateScope)` requires + the reader to distinguish noun-from-verb each time. `secretsuc/model.ts` + is the live counter-example for the correct convention within this very + repo: `CreateSecretRequest`, `GetSecretRequest`, `ListSecretsRequest`, + etc. Two sibling packages, two conventions. Pick one. + +### H5. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` + +- **Files / lines:** `src/v1/client.ts:584` (`putAcl`), `:638` (`putSecret`); + contrast `:137` (`createScope`), `:262` (`deleteSecret`), `:220` + (`deleteScope`), `:180` (`deleteAcl`). +- **Category:** #17 inconsistent action verbs. +- **Current:** `Put` for ACLs and secrets, `Create` for scopes, `Delete` + for all three. No `Update`. +- **Issue:** A consumer who learned `createScope` will not guess that the + way to create or update a secret is `putSecret`, not `createSecret` or + `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:607) and + "Creates or overwrites the ACL" (client.ts:551) — three different verbs + for the same upsert semantic. +- **Suggestion:** unify on one verb pair: either + (a) `Create*` for new + `Update*` for existing, or + (b) `Put*` (upsert) consistently, also renaming `createScope` → `putScope`. + Picking either gets rid of the asymmetry. Note that the underlying REST + endpoints are `/secrets/scopes/create`, `/secrets/acls/put`, + `/secrets/put` — so the wire format is *also* inconsistent and the + generator is faithfully reproducing it. + +### H6. Scope name field `scope` is severely overloaded across types + +- **Files / lines:** `src/v1/model.ts:53` (`CreateScope.scope`), `:67` + (`DeleteAcl.scope`), `:77` (`DeleteScope.scope`), `:85` + (`DeleteSecret.scope`), `:95` (`GetAcl.scope`), `:102` (`GetSecret.scope`), + `:117` (`ListAcls.scope`), `:137` (`ListSecrets.scope`), `:148` + (`PutAcl.scope`), `:160` (`PutSecret.scope`). Then `SecretScope.name` + (`:198`) names the same value, and the *type* `SecretScope` describes + what `scope` actually contains. Then `ScopeBackendType` describes the + scope's backend. +- **Category:** #1 vague/generic, #15 generic field names losing meaning, + #6 misleading names. +- **Issue:** `scope` is the *string name* of a `SecretScope`. The naming + is ambiguous in three ways: + - The type `SecretScope` calls its own identifier `name` (not `scope`). + - Every request type calls the same identifier `scope` (not `scopeName` + or `secretScopeName`). + - The word "scope" in TS frequently refers to lexical scope or + permission scope (OAuth). A casual reader sees `req.scope = '...'` and + has to read the JSDoc to learn it is a *secret scope name*. +- **Suggestion:** rename the field on request types to `scopeName` and on + `SecretScope` keep `name`. This matches the disambiguation pattern the + sibling `serviceprincipalsecrets` uses (`ServicePrincipalSecret.secretId` + vs request `id`). The Go SDK uses the same `Scope` field name, but TS + conventions favour explicitness over brevity. + +### H7. `PutSecret.value` discriminated union has cryptic `$case` discriminator field + +- **File / line:** `src/v1/model.ts:163-174`. +- **Category:** #14 Go/Java-style name, #15 generic field names. +- **Current:** + ```ts + value?: + | { $case: 'stringValue'; stringValue: string } + | { $case: 'bytesValue'; bytesValue: Uint8Array } + | undefined; + ``` +- **Issue:** `$case` is the ts-proto-style discriminator marker, not a TS + convention. Idiomatic TS uses a domain-specific tag (`type`, `kind`, + `format`). Worse, the *case names* (`stringValue`, `bytesValue`) duplicate + the *property names* (`stringValue`, `bytesValue`) — so + `value.stringValue` is the read path, `value.$case === 'stringValue'` is + the guard. The redundancy makes the union three things in one (`$case`, + the value, the type) where one would suffice. +- **Suggestion:** either a plain union + `value: { format: 'string'; data: string } | { format: 'bytes'; data: Uint8Array }` + or, since at the wire level the server expects one of two top-level + fields `string_value` / `bytes_value`, model it as two optional fields + with an exactly-one-of constraint enforced at runtime. +- **See also:** Repo-wide pattern; the `credentials` audit catalogues the + same `$case` discriminator in many places. + +### H8. `value` field on `PutSecret` and `GetSecret_Response` carries no domain hint + +- **Files / lines:** `src/v1/model.ts:112` (`GetSecret_Response.value: + Uint8Array`); `:163-174` (`PutSecret.value`). +- **Category:** #1 vague/generic, #15 generic field names. +- **Issue:** A field literally named `value` on a `Uint8Array` is the + flattest possible name. With nothing to disambiguate, the reader has to + read the JSDoc to know it is *the secret payload* (not a metadata value, + a hash, etc.). Compare with `SecretMetadata.lastUpdatedTimestamp` (#L10 + below) which is fully qualified. +- **Suggestion:** `secretValue` or `secretBytes`. The JSDoc itself says + "The value of the secret" — fold that into the identifier. + +--- + +## Medium Severity + +### M1. `AclPermission` enum values are bare verbs + +- **File / line:** `src/v1/model.ts:6-13`. +- **Category:** #2 redundant enum prefixes (inverse: no prefix at all). +- **Current:** `READ = 'READ'`, `WRITE = 'WRITE'`, `MANAGE = 'MANAGE'`. +- **Suggestion:** as-is is acceptable since the enum name (`AclPermission`) + contributes the noun; `AclPermission.READ` reads as + "ACL-permission-read". Flagging only because three other places in + `model.ts` (the JSDoc) refer to the values as `"READ"`, `"WRITE"`, + `"MANAGE"` — string-literal style. The TS enum auto-stringifies, so + the wire-level value matches. Acceptable as-is. + +### M2. `ScopeBackendType` enum values stutter `_KEYVAULT` + +- **File / line:** `src/v1/model.ts:19-30`. +- **Category:** #2 redundant enum prefixes, #18 long enum values. +- **Current:** `DATABRICKS = 'DATABRICKS'`, `AZURE_KEYVAULT = 'AZURE_KEYVAULT'`. +- **Suggestion:** values are externally-mandated wire strings; cannot + change. The enum *member identifier* could be `AzureKeyvault` (PascalCase) + while keeping the wire value `'AZURE_KEYVAULT'`. Flagging because: + - The string casing of `KEYVAULT` (one word) clashes with surrounding + code (`AzureKeyVault` — two-word casing in type names like + `AzureKeyVaultSecretScopeMetadata`). + - Three different spellings of "key vault" in one file: `KEYVAULT` (enum + value), `KeyVault` (type names), and `keyvault` (field names like + `keyvaultMetadata`, `backendAzureKeyvault`). +- **See also:** M3 below. + +### M3. `KeyVault` / `KeyvaultMetadata` / `keyvault` casing inconsistency + +- **Files / lines:** + - `model.ts:29` `AZURE_KEYVAULT` (one word, upper). + - `model.ts:44` `AzureKeyVaultSecretScopeMetadata` (two words, "Vault"). + - `model.ts:59` `backendAzureKeyvault` (one word, lower-camel). + - `model.ts:202` `keyvaultMetadata` (one word, lower-camel). + - `model.ts:215` `unmarshalAzureKeyVaultSecretScopeMetadataSchema` (two + words, "Vault"). + - `model.ts:308` `keyvault_metadata` (the *wire* form). + - `model.ts:333` `marshalAzureKeyVaultSecretScopeMetadataSchema`. +- **Category:** #3 acronym casing inconsistency, #4 underscores (in wire + names — acceptable, but interacts). +- **Current:** simultaneously `KeyVault`, `Keyvault`, `keyvault`, + `KEYVAULT`. +- **Suggestion:** pick one. Microsoft's official product name is + "Azure Key Vault" (two words; see + `https://azure.microsoft.com/en-us/products/key-vault`). Standardize on + `KeyVault` in types and `keyVault` in fields: + - Type: `AzureKeyVaultSecretScopeMetadata` (already correct). + - Field: `keyVaultMetadata` (currently `keyvaultMetadata`), + `backendAzureKeyVault` (currently `backendAzureKeyvault`). +- **Rationale:** the type name is already two-word and follows the + Microsoft-canonical spelling. The fields just need to match the type + names they describe. + +### M4. `AzureKeyVaultSecretScopeMetadata` is 33 characters long + +- **File / line:** `src/v1/model.ts:44`. +- **Category:** #7 overly verbose. +- **Current:** `AzureKeyVaultSecretScopeMetadata`. +- **Suggestion:** since the type only appears in the context of + `SecretScope.keyvaultMetadata` and `CreateScope.backendAzureKeyvault`, + it could be `KeyVaultBackend` or `AzureKeyVaultBackend` — both shorter + and clearer that it's the backend configuration, not arbitrary metadata. +- **Rationale:** "Metadata" is the most generic possible suffix and tells + the reader nothing the surrounding name doesn't. The field `resourceId` + and `dnsName` are the two real pieces of information — they're + *configuration*, not metadata about anything. + +### M5. `AzureKeyVaultSecretScopeMetadata.resourceId` is underspecified + +- **File / line:** `src/v1/model.ts:46`. +- **Category:** #19 underspecified IDs. +- **Current:** `resourceId?: string | undefined`. +- **JSDoc:** "The resource id of the azure KeyVault that user wants to + associate the scope with." +- **Suggestion:** `azureResourceId` or `keyVaultResourceId`. As-is, a + reader sees `metadata.resourceId` and has no idea it's an Azure ARM + Resource ID — it could be a Databricks resource ID, a UC resource ID, + etc. + +### M6. `AzureKeyVaultSecretScopeMetadata.dnsName` is underspecified + +- **File / line:** `src/v1/model.ts:48`. +- **Category:** #1 vague/generic, #15 generic field name. +- **Current:** `dnsName?: string | undefined`. +- **JSDoc:** "The DNS of the KeyVault" — incidentally grammatically wrong + ("the DNS" should be "the DNS name" or "the URL"). +- **Suggestion:** `vaultUri` or `keyVaultUri`. The Azure SDK names this + field `vaultUri` and the value is a full URI + (`https://xxxx.vault.azure.net/`) not just a DNS name. +- **Rationale:** `dnsName` suggests a hostname like `xxxx.vault.azure.net`, + but the example value in `client.ts:113` is the full URI + `https://xxxx.vault.azure.net/`. The field name lies about its content. + +### M7. `AclItem` is generic-suffix tautology + +- **File / line:** `src/v1/model.ts:36`. +- **Category:** #20 type-suffix tautology, #15 generic field names. +- **Current:** `AclItem` describes "an ACL rule". The `Item` suffix is + meaningless. +- **Suggestion:** rename to `Acl` or `AclEntry` or `AclRule`. The + enclosing `ListAcls_Response.items: AclItem[]` is then + `ListAcls_Response.acls: Acl[]`. The Go SDK uses `AclItem`, but in TS + the suffix doesn't carry weight: `AclItem` and `AclRule` carry exactly + the same information. +- **Rationale:** Look at the surrounding code: + - `ListAcls_Response.items` (`model.ts:123`) — the field is `items`, not + `acls`. Generic name lost the domain. + - JSDoc on `:122` says "The associated ACLs rule applied to principals" + — so the type is conceptually "an ACL rule", but it's spelled + "AclItem". The doc disagrees with the name. + +### M8. `SecretMetadata` describes a list-item, not metadata + +- **File / line:** `src/v1/model.ts:184`. +- **Category:** #1 vague/generic, #20 type-suffix tautology. +- **Current:** `SecretMetadata { key, lastUpdatedTimestamp }`. The JSDoc + says "The metadata about a secret. Returned when listing secrets. Does + not contain the actual secret value." +- **Suggestion:** `SecretSummary`, `SecretListItem`, or `SecretInfo` (to + match the codebase-wide `*Info` pattern from `credentials`, `catalogs`, + etc.). `SecretMetadata` is misleading: the type carries the secret's + *name* (`key`) and *timestamp*, which is the secret itself sans value, + not "metadata about" it. +- **Rationale:** `Metadata` typically denotes auxiliary descriptive data + (tags, schema, labels). Here the type *is* the secret as exposed by + list — it lacks only the value. `SecretSummary` reads correctly. + +### M9. `SecretMetadata.lastUpdatedTimestamp` carries unit in name but not type + +- **File / line:** `src/v1/model.ts:188`. +- **Category:** #6 misleading names, #15 generic field names. +- **Current:** `lastUpdatedTimestamp?: number | undefined` — JSDoc says + "The last updated timestamp (in milliseconds) for the secret." +- **Suggestion:** `lastUpdatedAt` (epoch-ms) or `lastUpdatedMs` (carries + the unit). Compare to other audits in the repo: `expirationTime` was + flagged for the same defect in `credentials.md` #50. +- **Rationale:** `Timestamp` doesn't say whether it's ms or s, ISO string, + or `Date`. The codebase elsewhere uses `*At` (`createdAt`, `updatedAt`) + for epoch-ms ints; this field breaks the pattern. + +### M10. `SecretScope.backendType` vs `CreateScope.scopeBackendType` + +- **Files / lines:** `src/v1/model.ts:200` (`SecretScope.backendType`), + `:57` (`CreateScope.scopeBackendType`). +- **Category:** #1 vague/generic, #13 verb-tense inconsistency (form). +- **Current:** the very same enum-typed field appears as `backendType` on + the response shape and `scopeBackendType` on the request shape. +- **Suggestion:** pick one. `backendType` is sufficient since both types + are scope-related and the prefix `scope` is redundant. +- **Rationale:** Inconsistent naming for the same conceptual field is + pure noise; a consumer mapping a `SecretScope` back to a `CreateScope` + re-creation will trip on the field-name mismatch. + +### M11. `CreateScope.backendAzureKeyvault` vs `SecretScope.keyvaultMetadata` + +- **Files / lines:** `src/v1/model.ts:59`, `:202`. +- **Category:** #12 duplicate concepts, #1 vague/generic. +- **Current:** the same conceptual field (`AzureKeyVaultSecretScopeMetadata` + payload, the backend configuration for an Azure KeyVault scope) is named + `backendAzureKeyvault` on `CreateScope` and `keyvaultMetadata` on + `SecretScope`. Both names describe the same payload at the same role + (the KeyVault backend config) but use different framings. +- **Suggestion:** rename both to the same — `keyVaultBackend` (preferred, + short, describes role) or `azureKeyVaultBackend`. Then `CreateScope` and + `SecretScope` round-trip naturally. + +### M12. `CreateScope.initialManagePrincipal` is verbose + +- **File / line:** `src/v1/model.ts:55`. +- **Category:** #7 overly verbose. +- **Current:** `initialManagePrincipal` (22 chars). +- **JSDoc:** "The principal that is initially granted ``MANAGE`` permission + to the created scope." +- **Suggestion:** `manageOwner` (10) or `initialOwner` (12); rests on the + fact that MANAGE permission is owner-equivalent. As-is, the name reads + as "initial manage principal" which is grammatically odd — `initial` + modifies `principal`, but the reader first sees "initial manage" as a + unit. Acceptable as-is if alternates feel too clever; flagging only the + verbosity. + +### M13. `GetSecret_Response` returned by `getSecret` carries `key` redundantly + +- **File / line:** `src/v1/model.ts:108-113`. +- **Category:** #12 duplicate concepts (request → response). +- **Current:** `GetSecret_Response { key?: string; value?: Uint8Array }`. + The caller has just passed `key` in via `GetSecret.key`, so they have it. +- **Issue:** the response echoes the key. Two interpretations: + - The server is *confirming* which key was returned, useful for any + callers using multi-stage pipelines. + - The server's response may rewrite the key in some way (e.g. + normalization), but the JSDoc gives no such hint. +- **Suggestion:** consider whether `key` is load-bearing on the response. + If not, drop it; if so, document why. As a TS shape, `Promise` + for `getSecret` would be simpler than a `{key, value}` envelope. As-is, + callers writing `(await client.getSecret({scope, key: 'foo'})).value` + spell `foo` twice. + +### M14. `ListAcls_Response.items` should be `ListAcls_Response.acls` + +- **File / line:** `src/v1/model.ts:123`. +- **Category:** #15 generic field name losing meaning. +- **Current:** `items?: AclItem[] | undefined`. +- **Suggestion:** `acls: Acl[]` (combined with M7). +- **Rationale:** Compare to `ListScopes_Response.scopes` (`:132`) and + `ListSecrets_Response.secrets` (`:143`) which both use the domain-typed + plural. `items` is the odd-one-out; the field name should match the + pattern. + +### M15. `marshalXxxSchema` / `unmarshalXxxSchema` const naming is Go-style + +- **File / line:** `src/v1/model.ts:205, 215, 227, 231, 235, 239, 243, + 258, 267, 277, 287, 291, 294, 304, 318, 328, 344, 354, 362, 372, 384`. +- **Category:** #14 Go/Java-style names, #20 type-suffix tautology. +- **Current:** `marshalCreateScopeSchema: z.ZodType`, + `unmarshalAclItemSchema: z.ZodType`, etc. +- **Suggestion:** TS idiom is `encode`/`decode` or `serialize`/`deserialize`. + `Schema` is also tautological since the value is a `z.ZodType` — + `aclItemDecoder`, `createScopeEncoder` would be type-self-describing. +- **Rationale:** Generator-wide convention (same defect cited in many + audits, e.g. `credentials.md` #53). Cannot be fixed in isolation. + +--- + +## Low Severity + +### L1. `unmarshalAclItemSchema` parses `permission: z.enum(AclPermission)` without strictness + +- **File / line:** `src/v1/model.ts:208`. +- **Category:** observation; not a naming defect strictly, but worth noting. +- **Issue:** `z.enum(AclPermission)` accepts the *string values* of the + enum (`'READ' | 'WRITE' | 'MANAGE'`). If the server adds a new permission + level, zod will throw at decode. Not a name issue, just notable. + +### L2. `PutSecret.value` discriminator names duplicate property names + +- **File / line:** `src/v1/model.ts:165-174`. +- **Category:** #15 generic field names, #20 type-suffix tautology. +- **Current:** `{ $case: 'stringValue', stringValue: string }`. The + discriminator value is the same string as the property name. +- **Issue:** `value.stringValue` is the access path; `value.$case` is the + guard, also `'stringValue'`. The redundancy bloats every read site. +- **Suggestion:** `{ $case: 'string', value: string } | { $case: 'bytes', + value: Uint8Array }`. The discriminator becomes a clean enum-of-strings, + the value field has a uniform name. + +### L3. `PutSecret.value` `stringValue` JSDoc references "UTF-8 (MB4)" + +- **File / line:** `src/v1/model.ts:167`. +- **Category:** #5 cryptic abbreviations. +- **Current JSDoc:** "If specified, note that the value will be stored in + UTF-8 (MB4) form." +- **Issue:** "MB4" likely means "MySQL utf8mb4" (4-byte UTF-8); an opaque + abbreviation outside the MySQL ecosystem. A TS API consumer has no + reason to know MySQL trivia. +- **Suggestion:** clarify or drop. "UTF-8 with full BMP support" or just + "UTF-8". This is a doc issue, not a name issue per se, but a naming + audit notices it. + +### L4. `principal` is a single field used for both users and groups + +- **Files / lines:** `model.ts:38, 69, 97, 150`. +- **Category:** #1 vague/generic. +- **Current:** `principal?: string | undefined` — JSDoc says "The principal + in which the permission is applied." `client.ts:550-583` clarifies: + "user or group name". +- **Suggestion:** acceptable as-is, as "principal" is the Databricks + platform-wide term for user-or-group; consistent with other packages. + Flagging only because a casual reader sees `principal` and may not + realize they should pass either a username or group name. JSDoc on the + request types could explicitly say "(user or group name)". + +### L5. `req.scope` is documented inconsistently across types + +- **Files / lines:** `model.ts:52, 67, 77, 85, 95, 102, 117, 137, 148, 160`. +- **Category:** observation; documentation only. +- **Current:** various JSDoc: + - `CreateScope.scope`: "Scope name requested by the user. Scope names + are unique." + - `DeleteAcl.scope`: "The name of the scope to remove permissions from." + - `DeleteScope.scope`: "Name of the scope to delete." (no "the") + - `DeleteSecret.scope`: "The name of the scope that contains the secret + to delete." +- **Suggestion:** the JSDocs are written by hand per-operation, with minor + grammar variation. Not a naming defect; flagging because it makes + cross-reference annoying. + +### L6. `ScopeBackendType` values include only two cases despite the JSDoc + +- **File / line:** `src/v1/model.ts:16-30`. +- **Category:** observation. +- **JSDoc:** "Azure KeyVault backed secret scopes will be supported in a + later release." The release shipped; the doc string is stale. Not a + naming issue but indicates the file is not maintained tightly. + +### L7. `marshal*Schema` types use bare `z.ZodType` (no type argument) + +- **Files / lines:** `model.ts:318, 328, 344, 354, 362, 372, 384`. +- **Category:** asymmetry; #20 type-suffix tautology. +- **Current:** `marshalCreateScopeSchema: z.ZodType = ...` — no type + parameter. Compare with `unmarshalAclItemSchema: z.ZodType`. +- **Suggestion:** mirror the input shape on the marshal side + (`marshalCreateScopeSchema: z.ZodType`). As-is, the + marshal path has no type guarantee — `marshalCreateScopeSchema.parse({ + scope: 123 })` would not type-check the input. + +### L8. `flattenQueryParams` is dead code in this package + +- **File / line:** `src/v1/utils.ts:123`. +- **Category:** #21 dead code. +- **Issue:** function defined but not imported in `client.ts`. The client + builds query strings inline (`client.ts:307-315, :370-377, :425-429, + :525-528`). Same defect noted in `credentials.md` #57 — appears + generator-wide. +- **Suggestion:** drop dead code, or move it to a shared utils package. + +### L9. `executeCall` vs `executeHttpCall` name collision + +- **Files / lines:** `src/v1/utils.ts:26, 65`. +- **Category:** #17 inconsistent action verbs. +- **Current:** two `execute*` functions with overlapping vocabulary: + `executeCall` (sets options + dispatches retries) and `executeHttpCall` + (one HTTP roundtrip). Same defect cataloged in other audits. + +### L10. `parseResponse` vs `marshalRequest` mix verbs + +- **Files / lines:** `src/v1/utils.ts:113, 119`. +- **Category:** #17 inconsistent action verbs. +- **Current:** mixing `parse`/`marshal` for symmetric encode/decode + responsibilities. Should be `parseResponse` + `formatRequest`, or + `unmarshalResponse` + `marshalRequest`. + +### L11. `PACKAGE_SEGMENT` constant is vague + +- **File / line:** `src/v1/client.ts:65`. +- **Category:** #1 vague/generic. +- **Current:** `const PACKAGE_SEGMENT = {key, value}` — used to compose + the User-Agent header. +- **Suggestion:** `USER_AGENT_PACKAGE_SEGMENT`. The JSDoc on the line + above already says "Package identity segment for this client to be used + in the User-Agent header" — fold the comment into the name. + +--- + +## Observations + +### O1. `scope` is optional on every request type, but required at the server + +- **Files / lines:** see H6. +- The generator marks every proto field optional. The runtime contract + requires `scope` for ten of eleven operations. Not a naming defect but + worth noting: the type is wider than the API allows. + +### O2. `CreateScope` request fields are out of order vs. domain intuition + +- **File / line:** `src/v1/model.ts:51-60`. +- The order is `scope`, `initialManagePrincipal`, `scopeBackendType`, + `backendAzureKeyvault`. The example in `client.ts:104-115` orders them + differently (`scope`, `initial_manage_principal`, `scope_backend_type`, + `backend_azure_keyvault` — same order, but the JSON example also has + `tenant_id` which the type doesn't have). +- The JSDoc example references `tenant_id` (`client.ts:112`) but the + type `AzureKeyVaultSecretScopeMetadata` has no `tenantId` field. The + example is out of sync with the type. + +### O3. `AclPermission.MANAGE` is owner-equivalent but not named that way + +- **File / line:** `src/v1/model.ts:11-12`. +- The JSDoc says "Allowed to read/write ACLs, and read/write secrets to + this secret scope" — i.e., MANAGE is full control. In the rest of the + Databricks platform, this level is often called OWNER. Naming + inconsistency with the wider platform; the wire format is fixed. + +### O4. `marshalPutSecretSchema` does a `btoa` on the bytes value + +- **File / line:** `src/v1/model.ts:393-397`. +- The `bytesValue` field is encoded via `btoa(Array.from(d, b => + String.fromCharCode(b)).join(''))`. This is the legacy Web base64 path + (not name-related). Modern code would use `Buffer.from(d).toString( + 'base64')` (Node) or a polyfill. Not a naming defect. + +### O5. The `Secret` noun is absent from this package's exports + +- **Files / lines:** `src/v1/index.ts`, `model.ts`. +- The package is called `secrets` but exports `SecretScope`, + `SecretMetadata`, and various `Secret*` operations. There is no bare + `Secret` type. The closest is `GetSecret_Response { key, value }` — + the actual full secret. Compare to the sibling `secretsuc` package + which exports a top-level `Secret` type (`secretsuc/model.ts:89`). +- Naming the type would help: e.g., `Secret { key, value }`. As-is, the + package's primary domain entity has no named type. + +--- + +## Recommended renames (high-confidence, in priority order) + +1. `Client` → `SecretsClient` (H2). +2. `CreateScope_Response`, `DeleteAcl_Response`, `DeleteScope_Response`, + `DeleteSecret_Response`, `GetSecret_Response`, `ListAcls_Response`, + `ListScopes_Response`, `ListSecrets_Response`, `PutAcl_Response`, + `PutSecret_Response` → strip underscore (H3). +3. `CreateScope`, `DeleteAcl`, `DeleteScope`, `DeleteSecret`, `GetAcl`, + `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, + `PutSecret` → suffix with `Request` to match sibling + `secretsuc` (H4). +4. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply + consistently across all mutating methods (H5). +5. `scope: string` field on every request type → `scopeName: string` (H6). +6. `AclItem` → `Acl` or `AclEntry`; `ListAcls_Response.items` → + `ListAclsResponse.acls` (M7, M14). +7. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M8). +8. `SecretMetadata.lastUpdatedTimestamp` → `lastUpdatedAt` (M9). +9. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, + `backendAzureKeyVault`) (M3). +10. `AzureKeyVaultSecretScopeMetadata.dnsName` → `vaultUri` (M6). +11. `AzureKeyVaultSecretScopeMetadata.resourceId` → `azureResourceId` or + `keyVaultResourceId` (M5). +12. `SecretScope.backendType` ↔ `CreateScope.scopeBackendType` → pick one + (`backendType`) (M10). +13. `CreateScope.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` + → pick one (`keyVaultBackend`) (M11). +14. `marshalXxxSchema` / `unmarshalXxxSchema` → `encodeXxx` / `decodeXxx` + (M15, repo-wide; not isolated to this package). diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md new file mode 100644 index 00000000..38ab8289 --- /dev/null +++ b/.agent/naming-audit/secretsuc.md @@ -0,0 +1,220 @@ +# Naming Audit: secretsuc + +**Path:** `packages/secretsuc/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. +**Total weird names flagged:** 32 + +## Summary +| Severity | Count | +| --- | --- | +| High | 8 | +| Medium | 10 | +| Low | 9 | +| Observation | 5 | + +## High severity + +### 1. Package name `secretsuc` — `packages/secretsuc/`, `package.json:2` +- **Why weird:** Two words mashed together with no separator: `secrets` + `uc`. The result reads as "secret-suc" or a single nonsense word. `uc` is a two-letter cryptic abbreviation that is never expanded anywhere in the public TypeScript surface — neither the `Client` class, the `Secret` interface, nor any field or constant mentions "UnityCatalog" or "Uc". The only places "Unity Catalog" appears at all are (a) JSDoc prose, (b) the URL path `/api/2.1/unity-catalog/secrets`, and (c) the `Secret` interface JSDoc. The package directory is the only carrier of the disambiguator, and it's silent in code. +- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept against `packages/secrets/`), 6 (misleading — `secretsuc` looks like a typo or a verb suffix). +- **Suggested name:** `secrets-unity-catalog`, `unitycatalogsecrets`, or `ucsecrets` (all worse than expanding fully). Best: rename package to `unitycatalogsecrets` (matching pattern of `unitycatalogvolumes` etc. used elsewhere) or move the secrets type into a sub-namespace of a unified `unitycatalog` package. At a minimum, separate the words: `secrets-uc` or `secretsUc` is still wrong; the actual readable form is **`secrets-unitycatalog`** or **`unitycatalog-secrets`**. +- **Rationale:** A package name is the most user-facing identifier in any SDK — it appears in every `import` line and every `package.json` dependency entry. `secretsuc` fails three tests at once: (a) it is unreadable on first sight (where does the word boundary fall?); (b) it hides the disambiguator that separates it from `secrets`; (c) it embeds an undefined two-letter token. Compare with workspace-level peer `secrets`: a user installing both gets `@databricks/sdk-secrets` and `@databricks/sdk-secretsuc`, with no hint from the names which one targets workspaces and which targets Unity Catalog. The `uc` suffix is the entire semantic load and it's mute. The Go SDK can lean on package paths like `service/catalog/secrets` to add context; npm package names are flat strings and have to carry the disambiguator themselves. + +### 2. `Client` class name — `src/v1/client.ts:41` +- **Why weird:** Bare `Client` for the secret-management API. After `import {Client} from '@databricks/sdk-secretsuc/v1'` the caller has a symbol named `Client` with no domain hint. If the caller also imports from `@databricks/sdk-secrets/v1`, they get two identifiers both called `Client` — they must alias both at import. Inconsistent with packages elsewhere in this SDK that name their main class after the domain. +- **Category:** 1 (vague), 12 (duplicate concept — every package exports `Client`), 6 (misleading — no hint of which domain it serves). +- **Suggested name:** `SecretsClient`, or better, `UnityCatalogSecretsClient`. +- **Rationale:** Every generated package in this SDK exports `Client`; auditing one package can't fix the convention. But the pain is sharpest for `secrets` vs `secretsuc`: both export `Client` from the same overall scope, so a user with both deps has to write `import {Client as UcSecretsClient} from '@databricks/sdk-secretsuc/v1'`. The rename is upstream-wide; flagging here because this package is one of the worst offenders for the duplicate-name collision. + +### 3. `Secret` interface — `src/v1/model.ts:89` +- **Why weird:** Same word used by the sibling `@databricks/sdk-secrets` package's `SecretMetadata`/`PutSecret` types. A consumer with both packages cannot import `Secret` from either without aliasing. The type also doubles as both the entity (returned from `getSecret`) and the input shape (the `Secret` embedded in `CreateSecretRequest.secret` and `UpdateSecretRequest.secret`) — its fields mix read-only (`createTime`, `metastoreId`, `effectiveOwner`) with write-only (`value`) with read-write (`comment`, `owner`). +- **Category:** 12 (duplicate concept — different `Secret` exists at workspace level), 6 (misleading — single type for create-input + read-output + update-input means many fields are conditionally valid). +- **Suggested name:** `UnityCatalogSecret` for the type. (Splitting into `CreateSecretInput` / `Secret` / `UpdateSecretInput` is a deeper change beyond a naming audit.) +- **Rationale:** Even if the package rename happens, the type name `Secret` carries no UC-specific signal. Users wiring up both APIs will collide. The Go SDK has the same problem but disambiguates via Go's package-qualified types (`secretsuc.Secret` vs `secrets.SecretMetadata`); TS imports are commonly unqualified at the call site, so the type itself needs to carry the disambiguator. + +### 4. `externalSecretId` — `src/v1/model.ts:143` +- **Why weird:** Completely undocumented field (no JSDoc comment, unlike every other field on `Secret`). The wire field exists in marshal/unmarshal (`model.ts:203,222,252,271`) and in the field-mask schema (`model.ts:283`) but is not in the field-mask's documented "Supported fields" list (`value, comment, owner, expire_time` — `client.ts:238`). The field's existence and semantics are entirely opaque to a reader of the model file. +- **Category:** 1 (vague — what is "external"?), 6 (misleading — undocumented field that is presumably real), 19 (underspecified id — alongside `metastoreId` and `fullName`). +- **Suggested name:** Keep the name but ship JSDoc; or `externalSecretReference` / `externalProviderSecretId` if the field points at an external secret manager (AWS Secrets Manager, etc.). +- **Rationale:** A bare `externalSecretId` next to `metastoreId` and `fullName` invites the reader to guess. JSDoc is the cheapest fix; renaming to disclose the "external store" intent is the better one. This may be a generator gap (missing API description), worth flagging upstream so the description is included. + +### 5. `value` field on `Secret` doubles as both input and output — `src/v1/model.ts:126` +- **Why weird:** Doc says "This field is input-only and is not returned in responses". Same struct has `effectiveValue` (`model.ts:131`) for the output. Two near-identical fields, one input-only, one output-only, both meaning "the secret value". Generic name `value` is also category-1 vague — without the doc, "value" could mean any value in any struct. +- **Category:** 1 (vague), 6 (misleading — same name covers both write-only-input and a sibling read-only-output), 11 (input-only field on a shared input/output type forces the reader to know the direction). +- **Suggested name:** `secretValue` (for symmetry with `effectiveValue`), or split into `CreateSecretInput.value` / `Secret.effectiveValue` so the asymmetry surfaces in the type system. Alternatively rename `effectiveValue` -> `value` and have a separate write-only `newValue` on update. +- **Rationale:** The current shape relies entirely on the JSDoc to inform the reader which field to set on input and which to read on output. The Zod marshal schema happily round-trips both fields (`model.ts:246,268`), so a buggy caller can set `effectiveValue` on a create call and the SDK will serialise it to the wire (where the server presumably ignores it). The TS type system should keep the asymmetry visible. + +### 6. `effectiveValue` / `effectiveOwner` "effective" prefix — `src/v1/model.ts:101,131` +- **Why weird:** Two unrelated `effective*` fields used with two different meanings. `effectiveOwner` is documented as "the effective owner of the secret, which may differ from the directly-set **owner** due to inheritance" — so "effective" = "after inheritance resolution". `effectiveValue` is documented as "the secret value. Only populated in responses when you have the **READ_SECRET** privilege" — so "effective" = "the actual readable value, not what was sent in". Two distinct semantics under one prefix. +- **Category:** 6 (misleading — "effective" implies inheritance everywhere but here doubles as "actually readable"). +- **Suggested name:** Rename `effectiveValue` -> `currentValue` or `readValue` to free `effective*` for the inheritance sense; or rename `effectiveOwner` -> `inheritedOwner` / `resolvedOwner`. +- **Rationale:** Same prefix, two meanings, within five lines of each other. A reader scanning the struct picks up the first definition and applies it to the second, leading to a wrong mental model. The fact that `effectiveValue` is documented to be populated based on a privilege (not inheritance) makes the prefix actively misleading. + +### 7. `fullName` is the primary key but optional — `src/v1/model.ts:23,32,115,152` +- **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:109,136,244`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. +- **Category:** 6 (misleading — looks optional, isn't), 16 (field type contradicts domain — required key marked optional). +- **Suggested name:** Keep the name, drop `| undefined` on the three request DTOs (or split: `Secret.fullName?` for responses, `SecretRef.fullName` required for requests). +- **Rationale:** This is a routing identifier; the TS type system can prevent a whole class of "I forgot the name" bugs and the SDK can stop substituting empty strings. The Go SDK uses pointer-with-nil-check or empty-string sentinel by convention; TS should be strict. + +### 8. `includeBrowse` parameter — `src/v1/model.ts:37,56` +- **Why weird:** Boolean flag named `includeBrowse` reads as "include browse" with no clarification of what "browse" means. JSDoc clarifies it gates returning secrets the caller only has BROWSE privilege on. Without the doc, the field name is opaque. Same pattern (`browseOnly` on `Secret`, `model.ts:136`) reuses the bare verb. `BROWSE` here is a permission name, not an action. +- **Category:** 1 (vague — "browse" is undefined without ACL context), 5 (cryptic without docs). +- **Suggested name:** `includeBrowseOnlySecrets` / `includeMetadataOnly` for the request flag; `metadataOnly` for the response field (`browseOnly` reads as a constraint, but is actually a "you only got metadata back" marker). +- **Rationale:** "Browse" is jargon from the Unity Catalog access-control vocabulary. Cross-package consistency matters more than internal cleverness — but the name is the first thing a consumer sees, before the JSDoc. Expanding to "browse-only" or "metadata-only" makes the field self-documenting. + +## Medium severity + +### 9. `Secret` mixes input-only and output-only fields — `src/v1/model.ts:126,225-272` +- **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. `marshalSecretSchema` (`model.ts:225`) round-trips every field, so it is shared between create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output. +- **Category:** 11 (single type wearing two hats), 6 (misleading). +- **Suggested name:** Split into `WritableSecret` / `Secret`, or `SecretCreateInput` / `SecretUpdateInput` / `Secret`. +- **Rationale:** The single-type approach is a generator artefact (Go SDK uses one struct with pointer fields to elide zeros); TS lacks that ergonomic and forces every consumer to know which fields are write-permitted. The field-mask on update (`updateMask` — `model.ts:162`) partially mitigates but doesn't substitute for type-level intent. + +### 10. `UpdateSecretRequest.secret` is the *update payload* with `fullName` as routing key — `src/v1/model.ts:147-163` +- **Why weird:** `UpdateSecretRequest` has both `fullName` (routing) and `secret` (payload). The nested `secret.fullName` is meaningless — what if it differs from the outer `fullName`? The Zod marshalRequest serialises the whole `secret`, including its own optional `fullName`, into the PATCH body even though the path is keyed by the outer `req.fullName`. +- **Category:** 6 (misleading — two `fullName`s can disagree), 17 (inconsistency — same field appearing twice in one logical operation). +- **Suggested name:** Either define `SecretUpdate` (omits `fullName`, `createTime`, etc.) or rely on the field-mask to ignore non-listed fields. Naming-wise: rename the outer to `name`/`secretFullName` to emphasise it's the routing key, not part of the payload. +- **Rationale:** This is a real bug surface: callers will write `{fullName: 'a.b.c', secret: {fullName: 'x.y.z', ...}}` and wonder why renames don't work. + +### 11. `ListSecretsRequest.catalogName` + `schemaName` as filters but documented as required-when-paired — `src/v1/model.ts:46,51` +- **Why weird:** JSDoc says "Both **catalog_name** and **schema_name** must be specified together". TS type marks both optional. The "must be specified together" constraint is enforced at the server, not in the type. A more honest shape would be `{ scope?: {catalogName: string; schemaName: string} | undefined }` so the pair must be set atomically. +- **Category:** 16 (field type contradicts domain — "must be together" not expressible). +- **Suggested name:** Keep names, group into a `scope` sub-object so paired-ness is type-enforced. +- **Rationale:** Internal grouping fix; not strictly a naming finding. Listed because the field names alone don't communicate the constraint, and the type system isn't carrying the weight. + +### 12. `createTime` / `updateTime` / `expireTime` vs `createdBy` / `updatedBy` verb tense — `src/v1/model.ts:105,107,109,111,142` +- **Why weird:** Past-tense participle on the principal fields (`createdBy`, `updatedBy`) but plain noun on the timestamps (`createTime`, `updateTime`). A consistent convention would be either `createdAt` + `createdBy` (both past-tense, both anchored to event) or `createTime` + `creator` (both noun forms). Mixed forms read as inconsistent. `expireTime` is future tense ("will expire") so isn't symmetrical with `created`/`updated`. +- **Category:** 13 (verb-tense inconsistency). +- **Suggested name:** `createdAt` / `updatedAt` / `expiresAt` (or `expireAt`) for timestamps; keep `createdBy` / `updatedBy` for principals. Wire fields stay `create_time` / `update_time` / `expire_time` for backwards compatibility. +- **Rationale:** Common JS convention is `*At` for instant fields. The Go SDK uses `CreateTime`/`UpdateTime` for proto compatibility; TS has no such constraint and can adopt the idiomatic form. + +### 13. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` +- **Why weird:** Request uses `pageToken`, response uses `nextPageToken`. Internally consistent with conventions across the SDK, but the asymmetry between "what I send" and "what I receive next time" is something the type system can't help with. The pagination iterator (`client.ts:227`) bridges them via `pageReq.pageToken = resp.nextPageToken`. +- **Category:** 17 (action-verb / qualifier asymmetry between request and response). +- **Suggested name:** Accept the convention (`nextPageToken` is the next page; you copy it to `pageToken` on the next request). Listed for completeness. +- **Rationale:** Generator convention; this isn't really a naming defect — flagged because rules 14 and 17 both ask about cross-DTO consistency. + +### 14. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` +- **Why weird:** JSDoc enumerates four meanings of `pageSize`: unset = 10000, positive = min(value, 10000), zero = 10000, negative = error. The field type is `number | undefined` which expresses none of those. A reader of the type signature alone would believe any number works. +- **Category:** 16 (type contradicts domain — should be `positive integer | undefined`), 6 (misleading — zero has special meaning). +- **Suggested name:** Keep the name; consider a Zod refinement (`z.number().int().nonnegative()`) and document the zero-means-default specially. +- **Rationale:** API-level concern (the upstream API conflates "use default" and "0"); flagging at the SDK level because the type system is silent. + +### 15. `metastoreId` field naming — `src/v1/model.ts:103` +- **Why weird:** `metastoreId` alongside `fullName`, `name`, `catalogName`, `schemaName`, `externalSecretId`, and (implied via comments) the policy id. Multiple identifier-like fields in one struct; bare `id` would be ambiguous, but `metastoreId` is fine in isolation. Flagged because the unqualified `externalSecretId` next to it gets less context. +- **Category:** 19 (underspecified id when multiple ids exist — applies to its neighbour, not this field). +- **Suggested name:** Keep `metastoreId`. Pair with renaming `externalSecretId` -> `externalSecretRef` or fully documenting it. +- **Rationale:** Borderline; raised because the struct already has too many distinct identifiers and clarity matters. + +### 16. `name` (relative name) vs `fullName` (qualified name) on `Secret` — `src/v1/model.ts:91,115` +- **Why weird:** `name` is "The name of the secret, relative to its parent schema" and `fullName` is "The three-level (fully qualified) name". Two name fields, one short and one long; the bare `name` doesn't say "relative". An incoming consumer who sees `name` and `fullName` may write the relative name where the fully qualified one is expected and the request silently hits the wrong endpoint (see finding #7). +- **Category:** 1 (vague — `name` doesn't disclose its relative scope), 19 (multiple identifier-like fields). +- **Suggested name:** `relativeName` for `name`, or `schemaRelativeName`. Wire stays `name`. +- **Rationale:** When `fullName` is the routing key, `name` should disclose that it's the inferior, scope-relative one. Failing that, JSDoc must always be read. + +### 17. `comment` vs documented "description" mismatch — `src/v1/model.ts:113` +- **Why weird:** Field named `comment` with JSDoc "User-provided free-form text description of the secret." The doc calls it a description; the field is called a comment. Same mismatch pattern as `abacpolicies.PolicyInfo.comment` (audit #28). +- **Category:** 6 (misleading — doc says description, name says comment), 17 (cross-package inconsistency). +- **Suggested name:** `description`. +- **Rationale:** SQL DDL leak; TS should adopt the noun the human-readable doc uses. + +### 18. `owner` vs `effectiveOwner` shadowing — `src/v1/model.ts:96,101` +- **Why weird:** Both fields present on `Secret`. `owner` is what was set; `effectiveOwner` is what resolves through inheritance. Caller updating `owner` later reads back `effectiveOwner` and is surprised it didn't change (if a higher-scope owner is inherited). A reader without the doc cannot tell them apart by the name alone. +- **Category:** 17 (inconsistent — same logical concept exposed twice). +- **Suggested name:** Rename `owner` -> `explicitOwner` or `directOwner` to mirror `effectiveOwner`'s "resolved" framing. +- **Rationale:** Sibling pair should be obviously a pair. Reading `owner` and `effectiveOwner` side-by-side, the user has to consult the JSDoc to discover one is the raw input and one is the resolved output. Wire stays `owner`. + +## Low severity + +### 19. `Client.createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — `src/v1/client.ts:75,105,132,172,240` +- **Why weird:** Method names redundantly include `Secret` even though the class is already secret-scoped. `client.createSecret(req)` reads okay, but inside a UC-secrets-only file `client.create(req)` would be cleaner. Compare with `pkgJson.scripts` ("build", "test") — context-scoped commands omit the noun. +- **Category:** 8 (redundant suffix — name repeats the class scope). +- **Suggested name:** Within the class, `create` / `delete` / `get` / `list` / `update` would be tighter. (But it would break a cross-package convention — every generated client uses ``.) +- **Rationale:** Cross-package convention wins here; flagging because rule 8 asks for redundant suffixes. The Go SDK uses `Create` / `Delete` etc. because Go method calls are scoped by receiver (`secretsuc.Create`). TS does the same implicitly (`client.create`). Worth raising at the SDK-design level. + +### 20. `listSecretsIter` — `src/v1/client.ts:214` +- **Why weird:** `Iter` suffix is a Go convention. JS/TS convention is to return an `AsyncIterable` (or named explicit iterator helper) — the method already returns `AsyncGenerator`, so the `Iter` is redundant after the return-type annotation. Compare with `Symbol.asyncIterator` ecosystem (`for await...of` consumes any `AsyncGenerator` directly; users don't expect to call `.iter()`). +- **Category:** 14 (Go-style name), 8 (redundant suffix — return type already says it's an iterator). +- **Suggested name:** `streamSecrets`, `secretsStream`, or hoist into a `listSecrets[Symbol.asyncIterator]()`-style method. +- **Rationale:** TS callers write `for await (const s of client.listSecretsIter(req)) {}` which is fine, but the `Iter` adds nothing the type signature doesn't. Cross-SDK convention again; not worth fixing in isolation. + +### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +- **Why weird:** Same constant repeated in every generated package. `Segment` is generic; reader needs the comment to learn it's the User-Agent identity segment. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `USER_AGENT_PACKAGE_ID` or `PACKAGE_USER_AGENT_SEGMENT`. +- **Rationale:** Same flag as in other generated packages; flagged for consistency. + +### 22. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Function is exported but not called from `client.ts` in this package — all query strings are built manually with `URLSearchParams.append`. Dead-looking surface area. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Either remove or document why it ships per-package. +- **Rationale:** Same observation as in other audits. Each generated package carries this helper unused. + +### 23. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Generic name for "read response body stream into a Uint8Array". Could be confused with `Array.prototype.readAll`-like operations. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` / `readStreamToEnd` / `collectStream`. +- **Rationale:** Internal helper; low cost; skip if generated. + +### 24. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (unmarshal) vs `marshalRequest` (marshal). Two different verbs for inverse operations. +- **Category:** 17 (inconsistent verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` (symmetry), or `parseResponse` / `serializeRequest`. +- **Rationale:** Pair-wise consistency aids reading. + +### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Near-identical names for different layers — `executeCall` wraps retry/rate-limit/timeout, `executeHttpCall` does raw HTTP send + logging. Distinguishing `Http` infix is a fragile cue. +- **Category:** 1 (vague), 17 (inconsistent — should differ in more than `Http`). +- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). +- **Rationale:** Eases call-site reading. + +### 26. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** `Options` reused throughout the SDK (`ClientOptions`, `CallOptions`, etc.). Within `utils.ts` there's also `Options` imported from `@databricks/sdk-core/api` (`utils.ts:3`). +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. +- **Rationale:** Distinguish internal context bags from user-tunable options. + +### 27. `secretFieldMask` helper function — `src/v1/model.ts:294` +- **Why weird:** Helper that builds a typed `FieldMask` from string paths. Name is fine, but inconsistent with `marshalSecretSchema` / `unmarshalSecretSchema` which are nouns; this is a verb-style camelCase function. Lower-case-first is correct, but the pattern "what is X" (`secretFieldMask`) vs "what does X do" (`marshalSecretSchema` as a Zod schema object) shows mixed conventions in the file. +- **Category:** 17 (inconsistent — neighbouring exports mix function/value forms). +- **Suggested name:** Keep as-is (function names *should* be verb-first by JS convention, but `secretFieldMask` is a builder — `buildSecretFieldMask` would clarify). +- **Rationale:** Minor stylistic inconsistency. + +## Observations + +### 28. Wire/TS divergence is heavy +The model file is 296 lines for *one* user-facing type (`Secret`) plus four request DTOs and one response DTO; ~130 lines are marshal/unmarshal/FieldMaskSchema scaffolding. The Zod schema duplicates the field list three times (interface, marshal schema, unmarshal schema, FieldMaskSchema). Not a naming problem, but the redundancy means a rename touches four places. + +### 29. Action-verb convention in `Client` +`createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) + +### 30. Acronym casing for `Http` / `Url` +Same as other audited packages: `Http` (PascalCase capital-then-lower) coexists with `URLSearchParams` (ALLCAPS from Web standard). Convention inherited from broader JS ecosystem; not worth changing. +- **Category:** 3. + +### 31. `Uc` abbreviation never expanded in code +Tracked thoroughly. The string "Uc" (in any case) does not appear in any identifier, type name, field name, constant, or enum value. "Unity Catalog" appears only in (a) JSDoc on `Secret` (`model.ts:85`), (b) JSDoc on `createSecret` / `listSecrets` / `updateSecret` (`client.ts:67,163,232`), and (c) the URL path string `/api/2.1/unity-catalog/secrets` (`client.ts:79,109,136,176,244`). The package name `secretsuc` is the **only** carrier of the disambiguator at the import level, and it's silent everywhere else. A consumer importing `Client` and `Secret` from this package, then opening their editor's symbol view, will see no hint that this is Unity-Catalog-scoped. See finding #1. +- **Category:** 5. + +### 32. No enums in this package +No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; `secretsuc` exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. + +## Domain glossary +- `uc` — Unity Catalog. Used in the **package name only**. Never expanded in any TS identifier. Spelled out in JSDoc prose ("Unity Catalog") and the URL path (`unity-catalog`). +- `BROWSE` / `MANAGE` / `READ_SECRET` / `CREATE_SECRET` / `USE SCHEMA` / `USE CATALOG` — Unity Catalog privilege names, referenced in JSDoc only (`client.ts:69,127,165`). +- `metastore` — Unity Catalog metastore (top of the catalog hierarchy). Referenced via `metastoreId` field. +- `securable` — Not used in this package, despite being core to UC. The hierarchy here (`catalog.schema.secret`) does not surface the term. +- `wkt` — Well-Known Types (`@databricks/sdk-core/wkt`), used for `FieldMask`. +- `oss`, `m2m`, `u2m`, `pat`, `iam`, `abac` — not encountered. + +## File coverage +- `src/v1/model.ts` (296 lines): read fully. +- `src/v1/client.ts` (276 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (15 lines): read fully. +- `package.json`: spot-checked for package metadata. + +## Cross-package notes +- `packages/secrets/` (workspace-level Secrets API): exports `AclPermission`, `AclItem`, `CreateScope`, `DeleteAcl`, `DeleteSecret`, `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret`, `SecretMetadata`, `SecretScope`, `ScopeBackendType`. **Same concept noun (`Secret`) exists in both packages with incompatible shapes.** A consumer with both deps faces name collisions on `Client`, `DeleteSecret`/`DeleteSecretRequest`, `GetSecret`/`GetSecretRequest`, `ListSecrets`/`ListSecretsRequest`, and the workspace-side `PutSecret` vs UC-side `Secret`. +- The workspace-level `secrets` package has its own naming problems (`PutSecret`, `DeleteAcl_Response` empty wrappers, the `key` / `value` flat shape vs UC's three-level `Secret` shape). Out of scope for this audit; flagged because the SDK design choice to have two separate packages multiplies the surface area. diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md new file mode 100644 index 00000000..e3415ceb --- /dev/null +++ b/.agent/naming-audit/serviceprincipalsecrets.md @@ -0,0 +1,469 @@ +# Naming Audit: serviceprincipalsecrets + +**Path:** `packages/serviceprincipalsecrets/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level CRUD over OAuth client secrets attached to +a service principal. Endpoints sit under +`/api/2.0/accounts//servicePrincipals//credentials/secrets`. +**Total weird names flagged:** 33 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `serviceprincipalsecrets` | (package) | package | High | 12 Duplicate concepts | Byte-for-byte identical to sibling `serviceprincipalsecretsproxy` (same model, client, utils, index). `Proxy` is encoded nowhere in code or URL. | +| 2 | package `serviceprincipalsecrets` | (package) | package | Medium | 14 Go/Java-style names not idiomatic TS | Long undelimited compound name; `service-principal-secrets` would parse, and the cousin `serviceprincipalsecretsproxy` makes it worse (28-char npm path). | +| 3 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names | Request type named after the verb-noun phrase. TS norm is `CreateServicePrincipalSecretRequest` (which is what every other generated package uses — see `*Request` convention). Bare `CreateServicePrincipalSecret` reads like a resource, not an action. | +| 4 | `DeleteServicePrincipalSecret` | model.ts:32 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names | Same as #3 — verb-name without `Request` suffix; collides semantically with `ServicePrincipalSecret` (the resource). | +| 5 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names, 9 Singular/plural mismatches | Same as #3. Plural `Secrets` further blurs the request/resource boundary — caller sees `ListServicePrincipalSecrets` and the response type `ServicePrincipalSecret[]`. | +| 6 | `DeleteServicePrincipalSecret_Response` | model.ts:42 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names | Underscore-separated identifier (only of its kind in the file). Should be `DeleteServicePrincipalSecretResponse`. Flagged in `naming-convention` eslint disable comment so the generator knows it's odd. | +| 7 | `ListServicePrincipalSecrets_Response` | model.ts:59 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names | Same underscore issue as #6. The TS convention is `ListServicePrincipalSecretsResponse` (matching `CreateServicePrincipalSecretResponse`). Generator deliberately retains the proto-message nesting (`Foo_Response`); consumer-facing types should not leak that. | +| 8 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 1 Vague/generic without domain context, 15 Generic field names losing meaning, 19 Underspecified IDs | Field is the service principal **ID** (per JSDoc `The service principal ID.`) but the field name implies the principal object itself. Should be `servicePrincipalId`. Same problem in `DeleteServicePrincipalSecret` (model.ts:35) and `ListServicePrincipalSecrets` (model.ts:47). | +| 9 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — fine, but the default ("730 days") is documented in JSDoc only; no constant exposed. Marshal converts to a lower-case ISO duration string (model.ts:155). `secretLifetime` would tie the field to the resource it bounds. | +| 10 | `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` | model.ts:15, 66 | interface pair | High | 12 Duplicate concepts | Both interfaces have identical fields (`id`, `secret`, `secretHash`, `createTime`, `updateTime`, `status`, `expireTime`). Their unmarshallers (model.ts:83 vs 125) are byte-identical. One of them is redundant — `CreateServicePrincipalSecretResponse` could `extends ServicePrincipalSecret` or be a type alias. | +| 11 | `ServicePrincipalSecret.secret` | model.ts:69 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret.secret` is a stutter. JSDoc says `Secret Value`. Rename to `value` or `clearTextValue`; `ServicePrincipalSecret.value` is unambiguous. Same field appears in `CreateServicePrincipalSecretResponse.secret` (model.ts:19). | +| 12 | `ServicePrincipalSecret.secretHash` | model.ts:71 | field | Low | 1 Vague/generic without domain context | `secret.secretHash` is also a stutter. `hash` is enough. (Both `secret` and `secretHash` then need renaming; otherwise drop just the `secret` prefix here.) | +| 13 | `ServicePrincipalSecret.id` | model.ts:68 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | Top-level `id: string` is the secret's ID. Should be `secretId` to match `DeleteServicePrincipalSecret.secretId` (model.ts:38), which refers to the same value. The asymmetry forces callers to remember the mapping. | +| 14 | `ServicePrincipalSecret.status` | model.ts:78 | field | High | 1 Vague/generic without domain context, 18 Long enum values | `status: string` — open string with no enum, no JSDoc enumeration of possible values. The Go SDK likely encodes this as `ACTIVE`/`PENDING`/`REVOKED` etc. but TS is left with a stringly-typed field. Should be a `ServicePrincipalSecretStatus` string-literal union. | +| 15 | `ServicePrincipalSecret.createTime` | model.ts:74 | field | Medium | 1 Vague/generic without domain context, 16 Field contradicting type domain | Typed `string \| undefined` but JSDoc says `UTC time when the secret was created`. Sibling `expireTime` (model.ts:80) is `Temporal.Instant`. The two date fields have **different runtime types** for the same semantic. Pick one (likely `Temporal.Instant` for both). | +| 16 | `ServicePrincipalSecret.updateTime` | model.ts:76 | field | Medium | 16 Field contradicting type domain | Same problem as #15 — `string` instead of `Temporal.Instant`. | +| 17 | `CreateServicePrincipalSecretResponse.createTime` / `.updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Mirrors #15/#16 in the response shape (since the two shapes are duplicates). | +| 18 | `ServicePrincipalSecret.expireTime` | model.ts:80 | field | Low | 13 Verb-tense inconsistency | Sibling fields use past tense (`createTime`, `updateTime` — when the action happened). `expireTime` is future tense. Either rename to `expiresAt` / `expirationTime`, or keep all three with consistent grammar (`createdAt`/`updatedAt`/`expiresAt`). | +| 19 | `ListServicePrincipalSecrets.accountId` / `.servicePrincipal` | model.ts:46, 48 | field | Medium | 16 Field contradicting type domain | These are URL path parameters, not list filters. Other SDK packages document this; here the request shape mixes path params (`accountId`, `servicePrincipal`) and query params (`pageToken`, `pageSize`) with no distinction. Caller sees one bag-of-fields. | +| 20 | `ListServicePrincipalSecrets_Response.secrets` | model.ts:61 | field | Low | 9 Singular/plural mismatches | Plural is correct (`secrets: ServicePrincipalSecret[]`), but the wire form is `secrets` (model.ts:115) — no underscore split. Clean. (Flagged only because nextPageToken below is the underscore case.) | +| 21 | `ListServicePrincipalSecrets_Response.nextPageToken` | model.ts:63 | field | Low | 3 Acronym casing inconsistencies | Field is `nextPageToken` (camelCase) and the wire form is `next_page_token` (model.ts:118, 122). Consistent with the SDK norm; no real issue. Listed only because the JSDoc (model.ts:62) uses backticked `page_token` not `pageToken`, which is the wire spelling — confusing for TS consumers. | +| 22 | `ListServicePrincipalSecrets.pageToken` JSDoc | model.ts:50-54 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc says `next_page_token`, `page_token`, and `nextPageToken` — three spellings of two fields in one comment. Doc generator should normalise to the TS field names. | +| 23 | `unmarshalCreateServicePrincipalSecretResponseSchema` | model.ts:83 | const | Medium | 7 Overly verbose, 20 Type-suffix tautology | 50-char identifier. `Schema` suffix duplicates the `z.ZodType<...>` annotation. Across the SDK; not unique here. | +| 24 | `unmarshalDeleteServicePrincipalSecret_ResponseSchema` | model.ts:108 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | 52-char identifier with an underscore preserved verbatim from the proto message nesting. ESLint-disabled at model.ts:107. | +| 25 | `unmarshalListServicePrincipalSecrets_ResponseSchema` | model.ts:112 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | Same as #24 — 51 chars + underscore. | +| 26 | `unmarshalCreateServicePrincipalSecretResponseSchema` body vs `unmarshalServicePrincipalSecretSchema` body | model.ts:83, 125 | const pair | High | 12 Duplicate concepts | The two zod schemas are byte-identical (same fields, same transforms). One should be defined and the other should alias. | +| 27 | `marshalCreateServicePrincipalSecretSchema` | model.ts:149 | const | Low | 17 Inconsistent action verbs, 20 Type-suffix tautology | Lone `marshal*` const (no other marshal in the file). The pairing is `marshal*` / `unmarshal*`. JS/TS conventions favour `encode`/`decode` or `serialize`/`deserialize` — `marshal`/`unmarshal` is a Go transliteration. | +| 28 | `marshalCreateServicePrincipalSecretSchema` typing | model.ts:149 | const | Low | 1 Vague/generic without domain context | Declared as `z.ZodType` (no generic). Sibling unmarshallers are `z.ZodType<...>`. The asymmetry hides what `marshalRequest(req, marshalCreateServicePrincipalSecretSchema)` (client.ts:77) actually validates. | +| 29 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. A consumer that imports `{Client}` from this package and from any other SDK package has to alias each one. Suggest `ServicePrincipalSecretsClient` (or a namespace re-export). | +| 30 | `Client.createServicePrincipalSecret` etc. | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Method names repeat the package name (`createServicePrincipalSecret` inside the `serviceprincipalsecrets` package). After namespacing it becomes `serviceprincipalsecrets.Client.createServicePrincipalSecret(...)` — `create(req)` would suffice if the package boundary is preserved. | +| 31 | `Client.listServicePrincipalSecretsIter` | client.ts:165 | method | Medium | 14 Go/Java-style names not idiomatic TS, 7 Overly verbose | `Iter` suffix is a Go idiom. TS convention for `AsyncGenerator` is to omit the suffix and rely on `for await … of` — or use `[Symbol.asyncIterator]` on the result itself. Also the method does not appear in `index.ts` (only `Client` is re-exported, which exposes it transitively). | +| 32 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Same shared-utils issue across the SDK: two `execute*` functions in one file with overlapping vocabulary. `executeCall` orchestrates retries/timeouts via the public `CallOptions`; `executeHttpCall` does one HTTP roundtrip and converts errors. Names should distinguish them — e.g. `runWithOptions` / `sendRequest`. | +| 33 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 10 Dead code | Exported from `utils.ts` but never imported in `client.ts` (which builds query strings inline via `URLSearchParams` at client.ts:134-142). Either remove or use it. | + +--- + +## High severity (must fix) + +### H1. Whole-package duplication: `serviceprincipalsecrets` vs `serviceprincipalsecretsproxy` + +The two packages have: + +- **Identical files.** `diff` across all four files (`model.ts`, `client.ts`, + `utils.ts`, `index.ts`) produces zero output. +- **The same** seven exported types: `CreateServicePrincipalSecret`, + `CreateServicePrincipalSecretResponse`, `DeleteServicePrincipalSecret`, + `DeleteServicePrincipalSecret_Response`, `ListServicePrincipalSecrets`, + `ListServicePrincipalSecrets_Response`, `ServicePrincipalSecret`. +- **The same** four client methods: `createServicePrincipalSecret`, + `deleteServicePrincipalSecret`, `listServicePrincipalSecrets`, + `listServicePrincipalSecretsIter`. +- **The same** URL path: + `/api/2.0/accounts//servicePrincipals//credentials/secrets`. + +The string `proxy` (or `Proxy`) appears **nowhere** in the model, client, +URL, or JSDoc. The only differentiator is the `package.json#name` +(`@databricks/sdk-serviceprincipalsecretsproxy`) and the directory name. + +This is a category 12 (duplicate concepts) failure at the package level. +Either: + +- Merge the two packages and let one Client serve both deployment surfaces. +- Or surface the proxy semantics in the types/URL (`ProxyClient`, different + base path, different headers, etc.) so the proxy variant is recognisable + in code. + +Until that is done, every consumer must read the docs to decide which +package to import. Once both are imported, all symbols collide on +re-export. + +### H2. `*_Response` underscore types + +Three public symbols carry a literal underscore, retained from +proto-message nesting and ESLint-disabled at each site: + +```ts +// model.ts:42 +export interface DeleteServicePrincipalSecret_Response {} + +// model.ts:59 +export interface ListServicePrincipalSecrets_Response { ... } + +// model.ts:108, 112 +export const unmarshalDeleteServicePrincipalSecret_ResponseSchema = ... +export const unmarshalListServicePrincipalSecrets_ResponseSchema = ... +``` + +These are the only underscored identifiers in the package and the generator +already flags them with `eslint-disable @typescript-eslint/naming-convention`. +The Google TypeScript style guide explicitly disallows underscores in +identifiers (§5.3.1). Rename to camelCase: +`DeleteServicePrincipalSecretResponse`, +`ListServicePrincipalSecretsResponse`. + +### H3. `CreateServicePrincipalSecretResponse` is structurally `ServicePrincipalSecret` + +```ts +// model.ts:15 +export interface CreateServicePrincipalSecretResponse { + id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? +} + +// model.ts:66 +export interface ServicePrincipalSecret { + id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? +} +``` + +The two interfaces have the **same** seven fields with the **same** types +and the **same** JSDoc. Their unmarshallers (model.ts:83 vs 125) are +byte-identical (same `z.object`, same `transform`). One of them is +redundant. Options: + +- `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret;` +- `interface CreateServicePrincipalSecretResponse extends ServicePrincipalSecret {}` +- Inline `ServicePrincipalSecret` into the create method's return type. + +Either way the duplicated schema is wasted bundle size. + +### H4. `*.servicePrincipal` is misleading + +```ts +// model.ts:10, 35, 48 +servicePrincipal?: string | undefined; // JSDoc: "The service principal ID." +``` + +The field is the service principal **ID** (a string), but the name reads +as if the value is the `ServicePrincipal` object. The wire form is +`service_principal` (model.ts:160) — the wire is the misleading source. +Rename the TS field to `servicePrincipalId` and let the marshal +`transform` keep the wire spelling. Same fix is needed for the URL +parameter use at client.ts:76, 105, 133. + +### H5. `ServicePrincipalSecret.status: string` should be a string-literal union + +```ts +status?: string | undefined; // JSDoc: "Status of the secret" +``` + +No enum, no documented values. A consumer who switches on the status has +to guess what strings are possible. The Go SDK almost certainly types +this as an `enum`. The TS port loses that information and types it as +arbitrary `string`. Recover the enum (`'ACTIVE' | 'PENDING' | 'REVOKED'` +or whatever the spec says) so the type system can help. + +--- + +## Medium severity (worth pushing back on) + +### M1. Request types lack a `Request` suffix + +Across the SDK the request convention is `Request`. Here the +generator drops `Request`: + +```ts +export interface CreateServicePrincipalSecret { ... } +export interface DeleteServicePrincipalSecret { ... } +export interface ListServicePrincipalSecrets { ... } +``` + +So `CreateServicePrincipalSecret` could plausibly be either the request +payload **or** an action (think `function createServicePrincipalSecret`). +Compare to the response side which **does** carry the suffix: +`CreateServicePrincipalSecretResponse`. The asymmetry is the giveaway. +Suggested: `CreateServicePrincipalSecretRequest` etc. + +### M2. Date fields are typed inconsistently + +```ts +createTime?: string | undefined; // model.ts:74 +updateTime?: string | undefined; // model.ts:76 +expireTime?: Temporal.Instant | undefined; // model.ts:80 +``` + +The same shape uses `string` for two date fields and `Temporal.Instant` +for the third. The unmarshaller (model.ts:92-95, 134-137) reinforces this: +`expire_time` is `Temporal.Instant.from(s)`, but `create_time` / +`update_time` are passed through as raw strings. Pick one — Temporal for +all three is the principled fix. + +### M3. `ServicePrincipalSecret.secret` stutters + +```ts +secret: ServicePrincipalSecret = { id, secret, secretHash, ... }; +secret.secret // the secret of the secret +secret.secretHash // the hash of the secret of the secret +``` + +Inside a `ServicePrincipalSecret` value, the `secret` and `secretHash` +fields are stutter. Rename to `value` and `hash`: + +```ts +secret.value +secret.hash +``` + +Naturally reads "the secret's value" / "the secret's hash". + +### M4. `id` vs `secretId` + +`ServicePrincipalSecret.id` (model.ts:68) and +`DeleteServicePrincipalSecret.secretId` (model.ts:38) are the same value +under two different names. The caller who reads from the create response +gets `id`; the caller who builds the delete request must rename to +`secretId`. Pick one (`secretId` is clearer at the model level since +`ServicePrincipalSecret` is the resource and only its ID is the ID). + +### M5. `Client` is unqualified + +```ts +export class Client { ... } +``` + +A consumer that imports `{Client}` from this and any sibling package has +to alias each one. Suggest `ServicePrincipalSecretsClient` or rely on +namespace imports +(`import * as serviceprincipalsecrets from '@databricks/sdk-serviceprincipalsecrets/v1'`). + +### M6. `listServicePrincipalSecretsIter` is a Go idiom + +```ts +async *listServicePrincipalSecretsIter(...): AsyncGenerator +``` + +The `Iter` suffix is Go-style (cf. `databricks/sdk-go` listers that +return iterators with `*Iter` types). TS convention is either: + +- Method returns `AsyncIterable` and is named without a suffix + (e.g. `listServicePrincipalSecrets()` returns the iterable; the + page-fetch version is named `listServicePrincipalSecretsPage()`), or +- Method is named `listAll` / `listPages` etc. + +### M7. Method names duplicate the package name + +```ts +client.createServicePrincipalSecret(...) +client.deleteServicePrincipalSecret(...) +client.listServicePrincipalSecrets(...) +``` + +After namespacing the call site reads +`serviceprincipalsecrets.client.createServicePrincipalSecret(...)`. Inside +a `ServicePrincipalSecretsClient`, `create(req)` / `delete(req)` / +`list(req)` are sufficient. (`delete` is a reserved word in JS, but legal +as a method name.) This is consistent across the SDK; not unique here. + +### M8. `executeCall` vs `executeHttpCall` + +Identical to sibling packages. Two `execute*` functions in `utils.ts`: + +- `executeCall` (utils.ts:26): orchestrates retries/timeouts. +- `executeHttpCall` (utils.ts:65): does one HTTP roundtrip and converts + errors. + +Two near-identical names within one file is a navigation hazard. +Suggested: `runWithOptions` / `sendRequest`. + +### M9. `ListServicePrincipalSecrets` mixes path and query parameters + +```ts +export interface ListServicePrincipalSecrets { + accountId?, servicePrincipal?, // path params + pageToken?, pageSize?, // query params +} +``` + +No structural cue tells the caller which fields end up in the URL path +vs the query string. The client treats them differently +(`accountId`/`servicePrincipal` are interpolated into the URL, the others +go through `URLSearchParams`). Not a naming problem per se, but the field +names give no hint. + +--- + +## Low severity (nits) + +### L1. `Schema` suffix tautology on all zod consts + +`unmarshalServicePrincipalSecretSchema: z.ZodType` — +the `Schema` suffix duplicates the type annotation. Pattern is consistent +across the SDK, so this is a generator-wide concern. The same suffix +pushes the longest identifier in this file to 52 chars +(`unmarshalDeleteServicePrincipalSecret_ResponseSchema`). + +### L2. `marshal`/`unmarshal` is a Go transliteration + +JS/TS conventions are `encode`/`decode` (most TS data libraries) or +`serialize`/`deserialize`. `marshal`/`unmarshal` matches Go's +`encoding/json` package idiom (`json.Marshal`/`json.Unmarshal`) but is +not idiomatic TS. + +### L3. `expireTime` verb tense vs `createTime` / `updateTime` + +`createTime` and `updateTime` are past-tense ("when the create happened"), +but `expireTime` is future-tense. Consistent options are +`createdAt`/`updatedAt`/`expiresAt` (idiomatic TS) or +`createTime`/`updateTime`/`expirationTime`. + +### L4. `lifetime` could be `secretLifetime` + +`lifetime: Temporal.Duration` reads fine in context, but as a standalone +field name carries no domain. `secretLifetime` ties the field to the +resource. Minor. + +### L5. `pageToken` JSDoc uses three different spellings + +```ts +// model.ts:50-54 +/** + * An opaque page token which was the `next_page_token` in the response of + * the previous request to list the secrets for this service principal. + * Provide this token to retrieve the next page of secret entries. + * When providing a `page_token`, all other parameters provided to the + * request must match the previous request. + * To list all of the secrets for a service principal, it is necessary to + * continue requesting pages of entries until the response contains no + * `next_page_token`. Note that the number of entries returned must not be + * used to determine when the listing is complete. + */ +pageToken?: string | undefined; +``` + +The comment mixes `next_page_token` (wire), `page_token` (wire), and the +TS field is `pageToken`. A TS-facing JSDoc should use the TS spellings. + +### L6. `marshalCreateServicePrincipalSecretSchema` is untyped + +```ts +// model.ts:149 +export const marshalCreateServicePrincipalSecretSchema: z.ZodType = ... +``` + +Compare to siblings (e.g. `unmarshalServicePrincipalSecretSchema: +z.ZodType`). The marshal const lacks the generic. +At the call site (client.ts:77) the caller can't see what shape is being +parsed. Tighten to `z.ZodType`. + +### L7. `flattenQueryParams` is exported but unused + +`utils.ts:123` exports `flattenQueryParams`. `client.ts` never imports it +(query strings are built inline via `URLSearchParams` at client.ts:134-142). +Either delete it or use it. Either way the dead export pollutes the API +surface that `index.ts` does not re-export. + +### L8. `HttpCallOptions` is generic + +Internal `interface` with `{request, httpClient, logger}`. Inside one +file this is fine. If it ever leaks out, `ExecuteHttpCallParams` would +self-document and avoid collision with the public `CallOptions`. + +### L9. `PACKAGE_SEGMENT` + +```ts +// client.ts:37 +const PACKAGE_SEGMENT = {...}; +``` + +Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes +the call site (`createDefault().with(PACKAGE_SEGMENT)`) self-explanatory. + +### L10. `req` vs `request` + +Method parameters are named `req` (client.ts:73, 102, 130, 166). TS code +in the wider ecosystem more commonly uses `request` or `params`. `req` +leans Go-idiomatic. Minor stylistic point. + +### L11. `'Host is required.'` + +```ts +// client.ts:56 +throw new Error('Host is required.'); +``` + +Not a naming issue, but the package throws plain `Error` rather than a +typed `ConfigError`/`MissingOptionError`. Consistent with sibling +packages. + +### L12. `'API call completed without a result.'` + +```ts +// client.ts:95, 123, 160 +throw new Error('API call completed without a result.'); +``` + +Unreachable branch for `delete*` (response is always parseable as +`{}`), and arguably "result" is misleading when the API returns nothing. + +--- + +## Observations (not flags) + +- **Generator marker.** Every file is prefixed with `// Code generated + from API definition by Databricks SDK Generator. DO NOT EDIT.` so all + naming issues must be fixed upstream in the generator/spec, not in + this file. +- **No enums.** The package has zero `enum` types, so categories 2 + (redundant enum prefixes) and 18 (long enum values) apply only to + `ServicePrincipalSecret.status` which is a `string`, not a literal + union (flagged as H5). +- **Underscores in identifiers.** Only the `*_Response` types use them + (model.ts:42, 59, 108, 112). The generator already flags each one + with `eslint-disable @typescript-eslint/naming-convention`. See H2. +- **Acronym casing.** Only `accountId` (camelCase, idiomatic) and + `nextPageToken` (camelCase, idiomatic) appear. No `Url`/`URL`, + `Sql`/`SQL`, `Json`/`JSON`, `Oauth`/`OAuth` collisions. +- **Reserved-word collisions.** None. (`delete` is a method name on + `Client`, but `client.delete` would be legal; here the method is + `deleteServicePrincipalSecret` so the question doesn't arise.) +- **Singular/plural mismatches.** `ListServicePrincipalSecrets` (request + is plural, response field is `secrets`, items are + `ServicePrincipalSecret`). Mostly clean but the request name `List…s` + is the one stutter. +- **Optionality model.** Every field is `T | undefined`. Consistent + with the rest of the SDK and `exactOptionalPropertyTypes`. No issue. +- **Versioning.** Only `v1` exists; nothing to compare across versions. +- **Tests.** No `tests/` directory for this package; `package.json` + scripts return `'no tests'`. +- **`index.ts` re-export style.** All seven types are re-exported as + `export type {...}`, which is correct for `verbatimModuleSyntax`. No + issue. The line `export {} from './model';` (index.ts:5) is a no-op + side-effect re-export — not a naming problem but slightly odd. +- **`Client` constructor throws plain `Error`** for missing `host` + (client.ts:55). Consistent with sibling packages, but not a naming + concern. + +--- + +## Domain glossary (as inferred from this code) + +| Term | Meaning in this package | +|------|-------------------------| +| **Account ID** | The numeric Databricks account identifier (path parameter `` in every URL). | +| **Service principal** | The owning identity for the secret; addressed by ID even though the field is named `servicePrincipal`. | +| **Service principal secret** | The unit resource: an OAuth client secret attached to a service principal, with an `id`, opaque `secret` value, hash, status, and lifecycle timestamps (`createTime`, `updateTime`, `expireTime`). | +| **Lifetime** | A `Temporal.Duration` (default 730 days / 63072000s) controlling when the secret expires. Marshalled to a lower-case ISO duration string (`'p730d'` etc.). | +| **Secret value** | The plaintext secret returned at creation time (`secret`), opaque on read. | +| **Secret hash** | A hash of the plaintext secret (`secretHash`); typed `string`, no algorithm documented. | +| **Status** | A string label (probably one of `ACTIVE`/`PENDING`/`REVOKED`) — but the field is plain `string`. | +| **Page token** | An opaque continuation cursor for pagination over `listServicePrincipalSecrets`. | +| **Proxy** | Not visible anywhere in the API surface — the sibling package name is the only signal. See H1. | + +--- + +## File coverage + +| File | Lines | Exports counted | Audited | +|------|-------|-----------------|---------| +| `src/v1/model.ts` | 163 | 7 interfaces, 5 zod consts | yes | +| `src/v1/client.ts` | 181 | 1 class, 4 public methods (1 async generator) | yes | +| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 16 | 1 class re-export, 7 type re-exports | yes | + +Every type, field, enum value (none), and method enumerated above is +accounted for. diff --git a/.agent/naming-audit/serviceprincipalsecretsproxy.md b/.agent/naming-audit/serviceprincipalsecretsproxy.md new file mode 100644 index 00000000..9776e10b --- /dev/null +++ b/.agent/naming-audit/serviceprincipalsecretsproxy.md @@ -0,0 +1,385 @@ +# Naming Audit: serviceprincipalsecretsproxy + +**Path:** `packages/serviceprincipalsecretsproxy/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level CRUD over OAuth client secrets attached to a +service principal (create, list, delete), exposed as a "proxy" variant whose +surface area is byte-identical to the sibling `serviceprincipalsecrets` +package. +**Total weird names flagged:** 33 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 1 | package `serviceprincipalsecretsproxy` | (package) | package | High | 12 Duplicate concepts | Byte-identical to sibling `serviceprincipalsecrets` — every v1 source file (`client.ts`, `model.ts`, `utils.ts`, `index.ts`) has the same MD5; only the npm package name differs. | +| 2 | package `serviceprincipalsecretsproxy` | (package) | package | High | 7 Overly verbose, 14 Go/Java-style names not idiomatic TS | 33-character, undelimited compound. Already the longest package name in the SDK; the "proxy" suffix piles onto an already-long base. Consider `sp-secrets-proxy` or a subpath of `serviceprincipalsecrets`. | +| 3 | package `serviceprincipalsecretsproxy` | (package) | package | Medium | 6 Misleading names | "Proxy" appears nowhere in the model, client, or URL (`/api/2.0/accounts/.../servicePrincipals/.../credentials/secrets` is the same path used by the non-proxy package). The package name promises a different transport that does not exist in the code. | +| 4 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | 29-char identifier; lacks the `Request` suffix that the rest of the SDK uses for input shapes (`DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets` have the same problem — see #11/#16). The name reads like an action (verb phrase) rather than a request payload. | +| 5 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning, 16 Field contradicting type domain | Field is `servicePrincipal: string` but the JSDoc says "The service principal ID" — the value is an ID, not the full SP object. Should be `servicePrincipalId`. Same offender in `DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets`. | +| 6 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — generic; `secretLifetime` or `ttl` would be clearer. The default-730-days note is essential and lives only in JSDoc. | +| 7 | `CreateServicePrincipalSecretResponse` | model.ts:15 | interface | Medium | 7 Overly verbose, 12 Duplicate concepts | 37-char identifier and structurally identical to `ServicePrincipalSecret` (model.ts:66) — same seven fields in the same order with the same JSDoc. One of the two is redundant; the response wrapper could be `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret`. | +| 8 | `CreateServicePrincipalSecretResponse.id` | model.ts:17 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | `id?: string` — what is the ID of? The JSDoc clarifies "ID of the secret"; rename to `secretId` to match `DeleteServicePrincipalSecret.secretId`. Same issue in `ServicePrincipalSecret.id`. | +| 9 | `CreateServicePrincipalSecretResponse.secret` | model.ts:19 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret?: string` inside `ServicePrincipalSecret` reads as `ServicePrincipalSecret.secret` — meaningless self-reference. Rename to `secretValue` (the JSDoc already calls it "Secret Value"). | +| 10 | `CreateServicePrincipalSecretResponse.secretHash` | model.ts:21 | field | Low | 1 Vague/generic without domain context | Plain `secretHash: string` — no hash algorithm noted. The wire JSON sends `secret_hash`; doc does not specify SHA-256, SHA-512, etc. | +| 11 | `CreateServicePrincipalSecretResponse.status` | model.ts:27 | field | Medium | 1 Vague/generic without domain context, 4 Underscores in TS identifiers (wire) | `status?: string` — completely untyped. Likely an enum on the server (`ACTIVE`/`REVOKED`/`EXPIRED`), but TS callers see a free-form string with zero discoverability. | +| 12 | `CreateServicePrincipalSecretResponse.createTime` / `updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Typed as `string` while the sibling `expireTime` (model.ts:29) is `Temporal.Instant`. Wire form is the same ISO-8601 timestamp for all three — the asymmetric typing is a generator bug, not an intentional API choice. | +| 13 | `CreateServicePrincipalSecretResponse.expireTime` | model.ts:29 | field | Low | 3 Acronym casing inconsistencies | Inconsistent with `createTime` / `updateTime` typing (see #12). | +| 14 | `DeleteServicePrincipalSecret` | model.ts:32 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | Same problem as #4: name is a verb phrase ("Delete a SP secret"), not a payload type; lacks `Request` suffix. | +| 15 | `DeleteServicePrincipalSecret.secretId` | model.ts:38 | field | Low | 19 Underspecified IDs | Good in isolation, but the request also carries `servicePrincipal: string` which is *also* an ID — naming asymmetry: one field has `Id`, the other doesn't (see #5). | +| 16 | `DeleteServicePrincipalSecret_Response` | model.ts:42 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names not idiomatic TS | Protobuf-style underscore in the TS identifier; requires `eslint-disable-next-line @typescript-eslint/naming-convention`. Should be `DeleteServicePrincipalSecretResponse` (PascalCase, no underscore). | +| 17 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency, 9 Singular/plural mismatches | Plural form ("ListServicePrincipalSecret*s*") is a verb phrase, not a request payload type. Singular vs plural inconsistency with the other two requests in the same file. Rename to `ListServicePrincipalSecretsRequest`. | +| 18 | `ListServicePrincipalSecrets.pageToken` | model.ts:54 | field | Low | 18 Long enum values (analogous) | Field is fine, but the JSDoc is 358 chars long for one field — out of proportion. Worth surfacing on the type itself or in package docs. | +| 19 | `ListServicePrincipalSecrets.pageSize` | model.ts:55 | field | Low | 1 Vague/generic without domain context | Field has no JSDoc at all (unlike `pageToken` which has 4 lines). Inconsistent within the same interface. | +| 20 | `ListServicePrincipalSecrets_Response` | model.ts:59 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names not idiomatic TS | Protobuf-style underscore in TS identifier; needs an `eslint-disable-next-line` for `@typescript-eslint/naming-convention`. Should be `ListServicePrincipalSecretsResponse`. | +| 21 | `ListServicePrincipalSecrets_Response.secrets` | model.ts:61 | field | Low | 9 Singular/plural mismatches | Plural is correct. JSDoc says "List of the secrets" — phrasing nit, "List of secrets" would read better. | +| 22 | `ServicePrincipalSecret` | model.ts:66 | interface | Medium | 12 Duplicate concepts | Structurally identical to `CreateServicePrincipalSecretResponse` (see #7). Two names for one shape. | +| 23 | `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` | model.ts:68, 70, 72, 78 | field | Medium | 1 Vague/generic without domain context | Same vague-field issues as the response copy (#8-#11). | +| 24 | `unmarshalCreateServicePrincipalSecretResponseSchema` | model.ts:83 | const | Medium | 7 Overly verbose, 20 Type-suffix tautology | 50-char identifier. `Schema` suffix is redundant with the `z.ZodType<...>` annotation; the leading `unmarshal` is Go-idiom (see #29). | +| 25 | `unmarshalDeleteServicePrincipalSecret_ResponseSchema` | model.ts:108 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | 52-char identifier that includes an embedded underscore; needs `eslint-disable-next-line @typescript-eslint/naming-convention`. | +| 26 | `unmarshalListServicePrincipalSecrets_ResponseSchema` | model.ts:112 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | Same underscore + verbosity issue as #25. | +| 27 | `unmarshalServicePrincipalSecretSchema` | model.ts:125 | const | Low | 20 Type-suffix tautology | `Schema` suffix is tautological with the `z.ZodType` annotation. | +| 28 | `marshalCreateServicePrincipalSecretSchema` | model.ts:149 | const | Low | 17 Inconsistent action verbs, 20 Type-suffix tautology | Same as #27, plus: pairing is `marshal*`/`unmarshal*` (Go-idiom — TS norm would be `encode`/`decode` or `serialize`/`deserialize`). Note this const has type `z.ZodType` *without* a generic argument while every sibling unmarshal const supplies one. | +| 29 | `marshal`/`unmarshal` verbs (whole file) | model.ts:83, 108, 112, 125, 149 | naming pattern | Low | 14 Go/Java-style names not idiomatic TS, 17 Inconsistent action verbs | Direct Go transliteration. TS ecosystem uses `JSON.stringify` / `JSON.parse`, `encode` / `decode`, or `serialize` / `deserialize`. | +| 30 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. Once two Databricks clients are imported in the same module, every one is just `Client`. Should be `ServicePrincipalSecretsProxyClient` or aliased on export. | +| 31 | `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Inside a class named `Client` (let alone a class that should be `ServicePrincipalSecretsClient`), repeating `ServicePrincipalSecret` in every method name is stutter. `create(req)` / `delete(req)` / `list(req)` would read cleanly. | +| 32 | `Client.listServicePrincipalSecretsIter` | client.ts:165 | method | Medium | 7 Overly verbose, 14 Go/Java-style names not idiomatic TS, 5 Cryptic abbreviations | `Iter` suffix is a Go-idiom (`func ListSomethingIter()`). TS `AsyncGenerator` returns are conventionally named without suffixes, or with `*All` / `*Stream`. Combined with the already-verbose method root, this is a 37-character identifier. | +| 33 | `PACKAGE_SEGMENT` | client.ts:37 | const | Low | 1 Vague/generic without domain context | Used only to assemble the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory. | + +--- + +## High severity (must fix) + +### H1. Whole-package duplication: `serviceprincipalsecretsproxy` vs `serviceprincipalsecrets` + +The two packages are **byte-identical** for every v1 source file: + +``` +0ba0e7b4804049f95901c6ab28544f4c serviceprincipalsecretsproxy/src/v1/client.ts +0ba0e7b4804049f95901c6ab28544f4c serviceprincipalsecrets/src/v1/client.ts + +646849b8cf7ab85f40ddf9b739edfada serviceprincipalsecretsproxy/src/v1/index.ts +646849b8cf7ab85f40ddf9b739edfada serviceprincipalsecrets/src/v1/index.ts + +f9014e9e042313f049de187a2cd772d1 serviceprincipalsecretsproxy/src/v1/model.ts +f9014e9e042313f049de187a2cd772d1 serviceprincipalsecrets/src/v1/model.ts + +0a0a7cd6d9c9e2d5424595de5ffb3630 serviceprincipalsecretsproxy/src/v1/utils.ts +0a0a7cd6d9c9e2d5424595de5ffb3630 serviceprincipalsecrets/src/v1/utils.ts +``` + +Same seven exported types +(`CreateServicePrincipalSecret`, +`CreateServicePrincipalSecretResponse`, +`DeleteServicePrincipalSecret`, +`DeleteServicePrincipalSecret_Response`, +`ListServicePrincipalSecrets`, +`ListServicePrincipalSecrets_Response`, +`ServicePrincipalSecret`), same four client methods (`createServicePrincipalSecret`, +`deleteServicePrincipalSecret`, `listServicePrincipalSecrets`, +`listServicePrincipalSecretsIter`), same URL path +(`/api/2.0/accounts//servicePrincipals//credentials/secrets`). + +The user instruction calls out: *"Pay extra attention: the 'proxy' variant +should be flagged for being a duplicate of `serviceprincipalsecrets`."* +Confirmed in the strongest possible way — there is literally no code-level +difference. The only thing distinguishing the two packages is the npm name +(`@databricks/sdk-serviceprincipalsecrets` vs +`@databricks/sdk-serviceprincipalsecretsproxy`). Either: + +- Merge the two packages, or +- Surface the proxy semantics in the types/URL (`ProxyClient`, a different + path, additional fields). + +Until that is done, every consumer must guess which package to import; once +imported, the symbols collide on re-export. + +### H2. `servicePrincipal: string` is an ID, not the principal + +```ts +export interface CreateServicePrincipalSecret { + servicePrincipal?: string | undefined; // JSDoc: "The service principal ID." +} +``` + +Same field appears in `DeleteServicePrincipalSecret` (model.ts:35) and +`ListServicePrincipalSecrets` (model.ts:48). The field's name asserts the +value is a `ServicePrincipal` object but it is actually an ID string. This is +also internally inconsistent with `DeleteServicePrincipalSecret.secretId` +(model.ts:38) — same file, one ID field has `Id`, another doesn't. + +Rename to `servicePrincipalId` everywhere. + +### H3. Protobuf-style underscore identifiers leak into TS + +Three identifiers carry an embedded `_` that requires `eslint-disable-next-line` +comments at every declaration: + +- `DeleteServicePrincipalSecret_Response` (model.ts:42) +- `ListServicePrincipalSecrets_Response` (model.ts:59) +- `unmarshalDeleteServicePrincipalSecret_ResponseSchema` (model.ts:108) +- `unmarshalListServicePrincipalSecrets_ResponseSchema` (model.ts:112) + +This is category 4 (underscores in TS identifiers) and category 14 +(Go/Java-style names not idiomatic TS). The inline comments +(`// Proto-style nested message name.`) acknowledge that the names exist only +to preserve the wire-message hierarchy from protobuf — there is no TS-side +reason to keep them. Rename to PascalCase +(`DeleteServicePrincipalSecretResponse`, `ListServicePrincipalSecretsResponse`) +and drop the eslint disables. + +--- + +## Medium severity (worth pushing back on) + +### M1. Request types lack the `Request` suffix + +Every input payload in this package is named as a verb phrase, not a payload: + +- `CreateServicePrincipalSecret` (model.ts:6) +- `DeleteServicePrincipalSecret` (model.ts:32) +- `ListServicePrincipalSecrets` (model.ts:44) + +Most of the rest of the Databricks SDK uses a `*Request` suffix for input +payloads (e.g. `GetRuleSetRequest` in `accountaccesscontrol`). The +`*Response` siblings here use the suffix; only the request side omits it. +Suggested: `CreateServicePrincipalSecretRequest`, +`DeleteServicePrincipalSecretRequest`, +`ListServicePrincipalSecretsRequest`. + +### M2. `CreateServicePrincipalSecretResponse` and `ServicePrincipalSecret` are duplicates + +```ts +export interface CreateServicePrincipalSecretResponse { + id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? +} + +export interface ServicePrincipalSecret { + id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? +} +``` + +Seven fields each, same names, same JSDoc, same wire decoders. Reduce to one +type or `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret`. + +### M3. `id` and `secret` are vague + +`ServicePrincipalSecret.id` is the secret's ID; rename to `secretId`. +`ServicePrincipalSecret.secret` is the secret's value; rename to `secretValue`. +The current shape forces every callsite to read +`secret.secret` and `secret.id`, which is unhelpful. + +### M4. `status: string` is an undocumented enum + +The field is typed as a free-form string but is almost certainly an enum on +the server side (`ACTIVE` / `EXPIRED` / `REVOKED` is the typical pattern for +secret lifecycle). The TS surface gives callers no discoverability — no enum, +no JSDoc enumeration of values, no link to backend docs. + +### M5. `createTime` / `updateTime` are `string` while `expireTime` is `Temporal.Instant` + +```ts +createTime?: string | undefined; +updateTime?: string | undefined; +expireTime?: Temporal.Instant | undefined; +``` + +Wire format is the same ISO-8601 timestamp for all three. The typing +asymmetry forces callers to handle three timestamps three different ways. Pick +one (presumably `Temporal.Instant`) and apply consistently. + +### M6. `Client` is unqualified + +```ts +export class Client { ... } +``` + +A consumer that imports `{Client}` from `@databricks/sdk-serviceprincipalsecretsproxy` +*and* from `@databricks/sdk-serviceprincipalsecrets` *and* from +`@databricks/sdk-accountaccesscontrol` has to alias every one. Export as +`ServicePrincipalSecretsProxyClient` or rely on namespace imports. + +### M7. Method names stutter + +```ts +class Client { + createServicePrincipalSecret(req, ...) + deleteServicePrincipalSecret(req, ...) + listServicePrincipalSecrets(req, ...) + listServicePrincipalSecretsIter(req, ...) +} +``` + +The receiver is already the secrets client. Methods could be `create`, +`delete`, `list`, `listAll` (or `list` returning an iterable). Even keeping +the long names, the consistent stutter is worth flagging since the package +name is already 33 characters. + +### M8. `listServicePrincipalSecretsIter` uses a Go-idiom suffix + +`*Iter` is Go convention (`func ListSomethingIter() iter.Seq`). TS code +typically returns `AsyncIterable` without suffix, or uses `*Stream` / +`iter*()`. Other audited packages have flagged the same pattern. + +--- + +## Low severity (nits) + +### L1. `lifetime` is generic + +`CreateServicePrincipalSecret.lifetime: Temporal.Duration` — `secretLifetime` +or `ttl` would make the call site self-documenting. + +### L2. `secretHash` does not name the algorithm + +The wire field is `secret_hash` and the doc is "Secret Hash". Callers cannot +verify hashes without knowing the algorithm (almost certainly SHA-256 given +Databricks norms, but the SDK does not say). + +### L3. `Schema` suffix tautology + +Every zod constant is named `unmarshal*Schema` / `marshal*Schema`. The +`Schema` suffix duplicates the `z.ZodType<...>` annotation. Cross-SDK +generator concern, not unique to this package. + +### L4. `marshal` / `unmarshal` are Go-idioms + +```ts +unmarshalCreateServicePrincipalSecretResponseSchema = z.object(...).transform(...) +marshalCreateServicePrincipalSecretSchema = z.object(...).transform(...) +``` + +TS ecosystem norm is `encode` / `decode`, `serialize` / `deserialize`, or +just `parse` / `stringify`. Go's `encoding/json` uses `Marshal`/`Unmarshal`; +TS does not. + +### L5. `marshalCreateServicePrincipalSecretSchema` lacks a generic argument + +```ts +export const marshalCreateServicePrincipalSecretSchema: z.ZodType = z.object(...); +``` + +Every sibling unmarshal const supplies a generic argument +(`z.ZodType`). The marshal const drops it, weakening +type safety on the call to `marshalRequest(req, marshalCreateServicePrincipalSecretSchema)`. + +### L6. `PACKAGE_SEGMENT` + +Used only for the User-Agent header. Rename to +`USER_AGENT_PACKAGE_SEGMENT` so the call site +(`createDefault().with(PACKAGE_SEGMENT)` → `.with(USER_AGENT_PACKAGE_SEGMENT)`) +is self-explanatory. + +### L7. `HttpCallOptions` + +Internal `interface` with `{request, httpClient, logger}`. Generic name. If +it ever leaks beyond `utils.ts`, `ExecuteHttpCallParams` would self-document. +(This shape and name is shared verbatim with sibling packages — generator-wide.) + +### L8. `parseResponse` vs `marshalRequest` + +`utils.ts` mixes `parse` / `marshal` action verbs. Pick one pair +(`parse` / `format`, or `marshal` / `unmarshal`) and stay consistent. + +### L9. `flattenQueryParams` exported but never imported + +`utils.ts:123` exports `flattenQueryParams`. `client.ts` builds query strings +inline via `URLSearchParams` (client.ts:134-141). Either: +- Use it (current inline code reproduces a subset of its logic), or +- Remove it (dead code). + +### L10. `req` parameter naming in client methods + +Every public method uses `req: ` — Go-idiom. TS conventions +prefer `request` or `params`. Stylistic only. + +### L11. `pageToken` JSDoc is enormous + +```ts +/** + * An opaque page token which was the `next_page_token` in the response of + * the previous request to list the secrets for this service principal. + * Provide this token to retrieve the next page of secret entries. + * When providing a `page_token`, all other parameters provided to the + * request must match the previous request. + * To list all of the secrets for a service principal, it is necessary to + * continue requesting pages of entries until the response contains no + * `next_page_token`. Note that the number of entries returned must not be + * used to determine when the listing is complete. + */ +pageToken?: string | undefined; +``` + +A four-sentence pagination contract attached to a single field. `pageSize` +on the very next line has zero JSDoc. Move the contract to the type-level +JSDoc or package docs; keep the field-level note short. + +### L12. `accountId` in path templates falls back silently + +```ts +const url = `${this.host}/api/2.0/accounts/${req.accountId ?? this.accountId ?? ''}/servicePrincipals/${req.servicePrincipal ?? ''}/credentials/secrets`; +``` + +If neither `req.accountId` nor `this.accountId` is provided, the URL is +emitted with an empty segment — a 404-bound HTTP call rather than an SDK +validation error. Not a naming issue per se, but a result of the underspecified +`accountId` field. (Same pattern across all sibling packages.) + +--- + +## Observations (not flags) + +- **Generator marker:** Every file is prefixed with `// Code generated from + API definition by Databricks SDK Generator. DO NOT EDIT.`, so all + naming issues must be fixed upstream in the generator / OpenAPI spec. +- **No enums.** The package has zero enum types, so categories 2 (redundant + enum prefixes) and 18 (long enum values) do not apply. The `status` field + (#11/#23) is a likely enum that was generated as a free-form string. +- **No `Url`/`URL`, `Sql`, `Json`, `Oauth` casing collisions.** `accountId` + (camelCase) and `secretId` are the only acronyms in the public surface. +- **No reserved-word collisions** — no `delete`, `class`, `new`, etc. as + field names. Note `Client.deleteServicePrincipalSecret` is a method + (not a field) so `delete` is not a collision here. +- **Optionality model:** every field is `T | undefined`. Matches the rest of + the SDK and `exactOptionalPropertyTypes`. No issue. +- **Versioning:** only `v1` exists; nothing to compare across versions. +- **Tests:** there is no `tests/` directory; `package.json` declares + `"test": "echo 'no tests'"`. +- **`index.ts` re-export style:** All seven types are re-exported as + `export type {...}`, which is correct under `verbatimModuleSyntax`. + There is a stray `export {} from './model';` (index.ts:5) — a no-op + re-export that does nothing. Either dead code or generator residue. +- **`Client` constructor throws plain `Error`** for missing `host` + (client.ts:55-57). Consistent with sibling packages, but not a naming + concern. + +--- + +## Domain glossary (as inferred from this code) + +| Term | Meaning in this package | +|------|-------------------------| +| **Account ID** | The numeric Databricks account identifier (path parameter ``). | +| **Service principal** | Modeled as a string ID field (`servicePrincipal: string`) — the field name asserts an object but the value is the SP's ID. | +| **Secret** | An OAuth client secret bound to a service principal. Has an `id`, a one-time-visible `secret` value, a `secretHash`, lifecycle timestamps (`createTime`, `updateTime`, `expireTime`), and a `status`. | +| **Lifetime** | Server-side TTL for a newly-created secret, supplied as a `Temporal.Duration`; default is 730 days when omitted. | +| **Status** | Free-form string on the TS side; presumed to be an enum on the server (likely `ACTIVE` / `EXPIRED` / `REVOKED`). | +| **Secret hash** | Server-computed digest of the secret value; algorithm not stated by the SDK. | +| **Page token** | Opaque continuation cursor returned as `nextPageToken` and sent back as `pageToken`. | +| **Proxy** | Not visible anywhere in the API surface — the package name is the only signal. See H1. | + +--- + +## File coverage + +| File | Lines | Exports counted | Audited | +|------|-------|-----------------|---------| +| `src/v1/model.ts` | 162 | 7 interfaces, 5 zod consts | yes | +| `src/v1/client.ts` | 181 | 1 class, 4 public methods (3 request + 1 iterator) | yes | +| `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 15 | 1 class re-export, 7 type re-exports, 1 no-op `export {}` | yes | + +Every type, field, enum value (none), and method enumerated above is +accounted for. diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md new file mode 100644 index 00000000..a064c5c3 --- /dev/null +++ b/.agent/naming-audit/settings.md @@ -0,0 +1,639 @@ +# Naming Audit: settings + +**Path:** `/home/parth.bansal/sdk-js/packages/settings/` +**Versions audited:** v2 +**Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). +**Total weird names flagged:** 111 + +--- + +## CRITICAL: Cross-package collision + +Within the JS SDK there are now **four** packages with overlapping responsibilities: + +| Package | Versions | Style | Surface | +|---------|----------|-------|---------| +| `settings` (this) | v2 | Generic key/value | `Setting` with polymorphic `value`/`effectiveValue` | +| `accountsettings` | v1 | Per-feature endpoints | `CspEnablementAccountSetting`, `PersonalComputeSetting`, etc. | +| `workspacesettings` | v1 | Per-feature endpoints | `DefaultNamespaceSetting`, `AutomaticClusterUpdateSetting`, etc. | +| `workspaceconf` | v1 | Free-form key/value | `WorkspaceConf {key,value}` (single string-string map) | + +The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `PersonalComputeMessage`, `BooleanMessage`, `StringMessage`, `IntegerMessage` — appears verbatim in both `settings/v2/model.ts` and `workspacesettings/v1/model.ts` (and is referenced from `accountsettings/v1`). Same TS identifier, defined twice, in two packages, with two `unmarshal*Schema`s. Consumers using both packages will get two distinct types named the same thing. + +> Flag the entire package layout for re-design (or, at minimum, hoist shared message types into a single `@databricks/sdk-settings-shared` package). The "settings vs workspacesettings vs accountsettings vs workspaceconf" naming gives the reader no way to predict which one to import. + +--- + +## Summary table + +| # | Severity | Category | Identifier | File:line | +|---|----------|----------|------------|-----------| +| 1 | Critical | Vague package name | `settings` (package) | package level | +| 2 | Critical | Duplicate concept (4-package overlap) | `settings` vs `accountsettings` vs `workspacesettings` vs `workspaceconf` | package level | +| 3 | Critical | Duplicated TS identifier across packages | `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage` | `model.ts:88-100,102,288,294,98,171,414,284` (and the workspacesettings dup) | +| 4 | High | Vague/generic type | `Setting` | `model.ts:297` | +| 5 | High | Vague/generic type | `SettingsMetadata` | `model.ts:396` | +| 6 | High | Vague/generic type | `UserPreference` | `model.ts:424` | +| 7 | High | Underscore in TS identifier | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` | `model.ts:30` | +| 8 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek` | `model.ts:38` | +| 9 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency` | `model.ts:50` | +| 10 | High | Underscore in TS identifier | `PersonalComputeMessage_PersonalComputeMessageEnum` | `model.ts:66` | +| 11 | High | Underscore in TS identifier | `RestrictWorkspaceAdminsMessage_Status` | `model.ts:73` | +| 12 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_EnablementDetails` | `model.ts:119` | +| 13 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow` | `model.ts:129` | +| 14 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` | `model.ts:136` | +| 15 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` | `model.ts:147` | +| 16 | High | Redundant enum prefix | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | +| 17 | High | Redundant enum prefix | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | +| 18 | High | Redundant enum prefix | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | +| 19 | High | Redundant enum prefix | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | +| 20 | High | Redundant enum prefix | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | +| 21 | High | Redundant enum prefix | `STATUS_UNSPECIFIED` | `model.ts:75` | +| 22 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:98-103, 171, 284, 288, 414` | +| 23 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | +| 24 | High | Cryptic abbreviation (undefined) | `Gov` in `disableGovTagCreation` | `model.ts:294` | +| 25 | High | Generic field name | `value` (on `BooleanMessage`, `IntegerMessage`, `StringMessage`, `PersonalComputeMessage`) | `model.ts:99, 172, 285, 416` | +| 26 | High | Generic field name | `name` (across `Setting`, `SettingsMetadata`, `UserPreference`, `GetPublicAccountSettingRequest`, ...) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | +| 27 | High | Generic field name | `type?: string` on `SettingsMetadata` | `model.ts:402` | +| 28 | High | Generic field name | `setting?: Setting` on update requests | `model.ts:266, 275, 281` | +| 29 | High | Generic field name | `setting?: UserPreference` (note: type is UserPreference, field name is `setting`) | `model.ts:275` | +| 30 | High | Generic discriminator value | `booleanVal`, `stringVal`, `integerVal` | `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` | +| 31 | High | Generic discriminator value | `effectiveBooleanVal`, `effectiveStringVal`, `effectiveIntegerVal` | `model.ts:354, 359, 364, 444, 445` | +| 32 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:153, 159, 177, 206, 264, 271` | +| 33 | High | Underspecified ID | `userId` | `model.ts:161, 208, 273, 428` | +| 34 | High | Misleading type name | `UserPreference` field named `setting` (on PatchPublicAccountUserPreferenceRequest) | `model.ts:275` | +| 35 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:303, 305, 351, 352` | +| 36 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:288` | +| 37 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:102` | +| 38 | High | Verb-tense | `disableGovTagCreation` (imperative verb as state field) | `model.ts:294` | +| 39 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | +| 40 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:152, 157, 166, 262, 269, 278`; `client.ts:83, 112, 137, 346, 378, 409` | +| 41 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | +| 42 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | +| 43 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | +| 44 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:225` | +| 45 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:204` | +| 46 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:269` | +| 47 | Medium | Long type name | `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` (64 chars) | `model.ts:136` | +| 48 | Medium | Long type name | `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` (59 chars) | `model.ts:147` | +| 49 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:194, 196`; `client.ts:166` | +| 50 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:225-227`; `client.ts:226` | +| 51 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:252-254` | +| 52 | Medium | Method name redundancy | `listAccountSettingsMetadataIter` ("Iter" suffix vs neighbouring `listAccountSettingsMetadata`) | `client.ts:202, 262, 323` | +| 53 | Medium | Cryptic abbreviation | `Iter` (Go iterator idiom in JS — should be implicit on AsyncGenerator) | `client.ts:202, 262, 323` | +| 54 | Medium | Overly verbose | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` (when accessed as enum member) | `model.ts:13` | +| 55 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | +| 56 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | +| 57 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:294` | +| 58 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:322` | +| 59 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:337` | +| 60 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:104` | +| 61 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:148-149` | +| 62 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:369` | +| 63 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:374` | +| 64 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:379` | +| 65 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:384` | +| 66 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:389` | +| 67 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:411` | +| 68 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:404` | +| 69 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:398` | +| 70 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:404`; `utils.ts:69, 71, 100, 103` | +| 71 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:107` | +| 72 | Low | Long enum value | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | +| 73 | Low | Long enum value | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | +| 74 | Low | Long enum value | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | +| 75 | Low | Long enum value | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | +| 76 | Low | Long enum value | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | +| 77 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | +| 78 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | +| 79 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | +| 80 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:79` | +| 81 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:79` | +| 82 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:79, 83` | +| 83 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:79` | +| 84 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:99, 172, 285, 305, 416, 434` | +| 85 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:402` | +| 86 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | +| 87 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:153, 161, ...` | +| 88 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | +| 89 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:275` | +| 90 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:624, 959` | +| 91 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | +| 92 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:172` | +| 93 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:305, 99` | +| 94 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:327-329` | +| 95 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:374` | +| 96 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:103` | +| 97 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:137` | +| 98 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:289` | +| 99 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | +| 100 | Low | Inconsistent verb | `Iter` suffix (Go idiom in TS) | `client.ts:202, 262, 323` | +| 101 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:160-161` | +| 102 | Low | Empty default | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED = 'PREVIEW_PHASE_UNSPECIFIED'` doc says unset-OR-not-a-preview (two distinct meanings) | `model.ts:12-13` | +| 103 | Low | Long type | `ClusterAutoRestartMessage_EnablementDetails` containing three `unavailable_for_*` booleans | `model.ts:119-126` | +| 104 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:121` | +| 105 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:123` | +| 106 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:125` | +| 107 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | +| 108 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | +| 109 | Low | Reserved-word adjacency | `signal` (uses Web/Node `AbortSignal` standard name — okay, just noting) | `client.ts:89, 118, 143, ...` | +| 110 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | +| 111 | Low | Type-suffix tautology | `*Schema` suffix on every zod schema (`unmarshalSettingSchema`, `marshalSettingSchema`, etc.) — Zod variables don't need the suffix; `import {z} from 'zod'` already conveys this | `model.ts:449, 460, 469, 477, ...` | + +--- + +## Critical findings + +### 1. `settings` — vague package name + +- **File:line:** package level +- **Category:** Vague/generic — extreme risk +- **Suggestion:** `settingsv2` (or `unified-settings`, or `settingskv`). A user-facing package name of literally `"settings"` collides with most "settings" concepts in any application. +- **Rationale:** The wire path is `/api/2.1/settings/{name}` and `/api/2.1/accounts/{accountId}/settings/{name}`. The Go SDK uses `settingsv2`. The TS package elides the `v2` suffix from the package name (it only appears in the subpath import `@databricks/sdk-settings/v2`), which gives the impression of a generic catch-all when in fact this is the new key/value flavor that supersedes `accountsettings`/`workspacesettings` per-feature endpoints. + +### 2. Four-package overlap: `settings` vs `accountsettings` vs `workspacesettings` vs `workspaceconf` + +- **File:line:** repo-wide +- **Category:** Duplicate concept +- **Suggestion:** Either (a) merge into one `@databricks/sdk-settings` package with sub-paths `/v1` (legacy per-feature) and `/v2` (unified KV), or (b) rename to make the distinction explicit: `legacy-account-settings`, `legacy-workspace-settings`, `unified-settings`, `legacy-workspace-conf`. Today, a user wanting to read/write the `automatic_cluster_update_workspace` setting must guess which package: `workspacesettings/v1` (specific endpoint), `settings/v2` (generic endpoint), or `workspaceconf/v1` (free-form). The packages give no signal of preference. +- **Rationale:** A naming audit cannot fix the underlying API design but must surface it. The collision is the dominant naming issue in this package. + +### 3. Duplicated TS identifiers across packages: `*Message` family + +- **File:line:** `model.ts` (this) vs `workspacesettings/v1/model.ts` +- **Category:** Duplicate concept — same TS identifier defined twice +- **Identifiers:** `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage`, plus all their nested types (`*_MaintenanceWindow`, `*_DayOfWeek`, `*_WeekDayFrequency`, `*_EnablementDetails`, `*_WindowStartTime`, `*_WeekDayBasedSchedule`, `_AccessPolicyType`, `_Status`, `_PersonalComputeMessageEnum`). +- **Suggestion:** Hoist these into a shared `@databricks/sdk-settings-shared` package (or just `@databricks/sdk-common` if the messages stabilize). A consumer who imports `{ClusterAutoRestartMessage}` from both `settings` and `workspacesettings` gets two structurally-identical-but-nominally-distinct types and any function expecting one rejects the other. +- **Rationale:** Verified by grepping both packages — the type declarations are byte-for-byte the same. The Go SDK upstream uses the same proto definition for both, so the duplication is faithful to the source, but in TypeScript it manifests as a real collision. + +--- + +## High severity + +### 4. `Setting` — extreme generic risk + +- **File:line:** `model.ts:297-394` +- **Category:** Vague/generic, reserved-word risk +- **Suggestion:** `UnifiedSetting`, `SettingValue`, or `KeyedSetting`. The Setting concept here is "a name plus a polymorphic value plus a polymorphic effective value" — none of those properties match the bare word "Setting" without context. +- **Rationale:** `Setting` is one of the most overloaded single words in software (UI settings, settings menu, settings file, configuration setting, etc.). Inside a "settings" package, the type `Setting` reads like "the thing this package is about" — but the package has three other top-level types (`UserPreference`, `SettingsMetadata`, and the wrapper messages). The bare name encourages a `import {Setting}` that competes with React UI `Setting` types, Node `process.config` settings, etc. + +### 5. `SettingsMetadata` — plural type, singular use + +- **File:line:** `model.ts:396-412` +- **Category:** Vague + singular/plural mismatch +- **Suggestion:** `SettingMetadata` (singular). The type describes metadata about *one* setting; lists are `SettingMetadata[]`. The current `SettingsMetadata` reads as "all metadata about all settings" which is what the *array* of these things represents — not the element. +- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:196`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). + +### 6. `UserPreference` — vague + collides with `Setting` + +- **File:line:** `model.ts:424-447` +- **Category:** Vague/generic +- **Suggestion:** Either fold into `Setting` (since the structure differs only in which `$case` payloads are allowed) or rename to `UserSetting` for parallelism with the package theme. The doc comment at `model.ts:419-423` already says "user-specific setting scoped to an individual user" — the word "preference" then competes with "setting" for the same concept. +- **Rationale:** Three top-level structural types — `Setting`, `UserPreference`, `SettingsMetadata` — that all model "name + value(s)" with slightly different shapes. A user reading just type names cannot predict which to use. + +### 7–15. `Type_NestedType` underscore-bearing identifiers — Go/Java-style names in TS + +- **File:line:** `model.ts:30, 38, 50, 66, 73, 119, 129, 136, 147` +- **Category:** Underscore in TS identifier +- **Identifiers:** + - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` + - `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek` + - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency` + - `PersonalComputeMessage_PersonalComputeMessageEnum` + - `RestrictWorkspaceAdminsMessage_Status` + - `ClusterAutoRestartMessage_EnablementDetails` + - `ClusterAutoRestartMessage_MaintenanceWindow` + - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` + - `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` +- **Suggestion:** Hoist as siblings (e.g. `AccessPolicyType`, `MaintenanceWindow`, `MaintenanceWindowDayOfWeek`, `RestrictWorkspaceAdminsStatus`) or use a TS namespace if you need scoping. The codebase already disables ESLint for these (`@typescript-eslint/naming-convention`), tagging them as a known violation. +- **Rationale:** Google TypeScript style guide forbids underscores in `PascalCase` identifiers. The disable comments on every such identifier ("Proto-style nested message name") confirm the team knows these are non-idiomatic but kept for proto fidelity. In a JS SDK consumer-facing surface, this leaks proto plumbing. + +### 16–21. Redundant enum prefixes ("X_X_UNSPECIFIED" pattern) + +- **File:line:** `model.ts:13, 31, 39, 51, 67, 75` +- **Category:** Redundant enum prefix +- **Identifiers:** + - `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` + - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType.ACCESS_POLICY_TYPE_UNSPECIFIED` + - `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` + - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency.WEEK_DAY_FREQUENCY_UNSPECIFIED` + - `PersonalComputeMessage_PersonalComputeMessageEnum.PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` + - `RestrictWorkspaceAdminsMessage_Status.STATUS_UNSPECIFIED` +- **Suggestion:** Just `UNSPECIFIED` everywhere — the enum identifier already conveys scope. `PreviewPhase.UNSPECIFIED` reads better than `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED`. +- **Rationale:** The prefix duplicates the enum name — `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` mentions "preview phase" three times. This is a proto3 wire artefact (proto3 requires enum values to be globally unique within a `.proto` file). TypeScript enums are namespaced; the prefix adds zero disambiguation. `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` is especially egregious — five words to mean "default". + +### 22. `*Message` suffix — Go/proto-style + +- **File:line:** `model.ts:98, 102, 171, 284, 288, 414` +- **Category:** Suffix tautology / Go-style +- **Identifiers:** `BooleanMessage`, `ClusterAutoRestartMessage`, `IntegerMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`, `StringMessage`, and the workspacesettings duplicates. +- **Suggestion:** Drop `Message`. Rename `ClusterAutoRestartMessage → ClusterAutoRestart`, `RestrictWorkspaceAdminsMessage → RestrictWorkspaceAdmins`, etc. The "Message" suffix is the protobuf convention for "everything is a Message"; in TS where "everything is an interface", the suffix is noise. +- **Rationale:** No other TS-idiomatic SDK uses `*Message` as a suffix. The classes are not messages in any TS-visible sense (they don't extend a `Message` base, they have no serialization methods — the marshal/unmarshal functions are external). + +### 23. `Aibi` — undefined cryptic abbreviation (AI/BI) + +- **File:line:** `model.ts:30, 88, 94, 327-329, 374` and method-name appearances in `client.ts` +- **Category:** Cryptic abbreviation, acronym casing +- **Suggestion:** `AIBI` (acronym casing) or spell out `AiBi` for the AI/BI Genie embedding feature. Add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." +- **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. + +### 24. `Gov` in `disableGovTagCreation` — undocumented abbreviation + +- **File:line:** `model.ts:294` +- **Category:** Cryptic abbreviation +- **Suggestion:** `disableGovernanceTagCreation`. The full word adds five characters and removes ambiguity (`Gov` could be government, governance, governor, ...). +- **Rationale:** The doc says "workspace admins cannot create governance tags" — so "Gov" abbreviates "Governance". The wire key is `disable_gov_tag_creation` (`model.ts:624`), but the TS surface can be more verbose. + +### 25. `value` field everywhere — generic field name + +- **File:line:** `model.ts:99, 172, 285, 416` on the message wrappers; `model.ts:305, 434` on the discriminated unions; nested deep inside (`Setting.value.booleanVal.value`). +- **Category:** Generic field name + reserved-word adjacency +- **Suggestion:** For the discriminated unions (`Setting.value`), `payload` would be slightly clearer. +- **Rationale:** `setting.value.booleanVal.value` is four levels of `.value`/`.someVal` indirection to access one boolean. The naming makes auto-complete useless. `value` is a member of many JS built-ins (Map entries, Symbol.iterator results, DOM events, IndexedDB cursors), so it has soft reserved-word risk. + +### 26. `name` everywhere — generic field name + +- **File:line:** `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` +- **Category:** Generic field name +- **Suggestion:** `settingKey` or `settingName` would convey purpose. The current `name` is so generic the JSDoc has to repeat "Name of the setting" everywhere. +- **Rationale:** The field is in fact the *key* — the unique identifier used in the URL path (`/settings/${req.name ?? ''}`) — not a human display name. The actual display name is `displayName` on `SettingsMetadata`. Naming the key "name" and the human name "displayName" inverts intuition (typically "name" is the display name and "id"/"key" is the identifier). + +### 27. `type?: string` on `SettingsMetadata` — generic + misleading + +- **File:line:** `model.ts:402` +- **Category:** Generic field name, reserved-word adjacency, misleading +- **Suggestion:** `valueTypeMessage` or `sampleTypeMessage`. The JSDoc says "Sample message depicting the type of the setting. To set this setting, the value sent must match this type." +- **Rationale:** A field called `type` returning a *sample message* (not a type-id or schema URI) is misleading. Combined with the JS-builtin overlap (`typeof obj.type === 'string'`), the field name invites confusion. + +### 28–29. `setting?: Setting` and `setting?: UserPreference` — generic field name + misleading + +- **File:line:** `model.ts:266, 275, 281` +- **Category:** Generic field name + misleading +- **Suggestion:** Rename to match the typed payload: `setting?: Setting` is okay; `setting?: UserPreference` is wrong — should be `userPreference?: UserPreference`. +- **Rationale:** On `PatchPublicAccountUserPreferenceRequest`, the field is named `setting` but typed `UserPreference`. The whole package's distinction between "setting" and "user preference" depends on these being separate concepts — so calling the user-preference field "setting" undoes that distinction at the request level. + +### 30–31. `booleanVal`, `stringVal`, `integerVal`, `effective*Val` — generic discriminator values + +- **File:line:** `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` +- **Category:** Generic field name +- **Suggestion:** Drop the `*Val` suffix (it duplicates the parent field `value`) and name by domain: instead of `value: {$case: 'booleanVal', booleanVal: BooleanMessage}`, prefer `value: {kind: 'boolean', boolean: boolean}`. +- **Rationale:** A user writing `setting.value?.$case === 'booleanVal'` then accessing `setting.value.booleanVal.value` does three discriminations to read a single bool. The "Val" abbreviation is the only naming variation between the discriminator tag ("booleanVal") and the type name ("BooleanMessage"); the abbreviation contributes nothing. + +### 32–33. `accountId`, `userId` — underspecified IDs + +- **File:line:** `model.ts:153, 159, 161, 177, 206, 208, 264, 271, 273, 428` +- **Category:** Underspecified ID +- **Suggestion:** Document the ID format (UUID, opaque-string, numeric, ...) in JSDoc consistently. Currently only some occurrences have a doc (" account ID of the account being managed"), and the format isn't specified anywhere. +- **Rationale:** Users have no way to know whether the SDK accepts `"acct-12345"`, `"abc...uuid"`, or an integer-as-string. The Go SDK's pattern of relying on type-level documentation isn't carried over. + +### 34. `setting` field on `PatchPublicAccountUserPreferenceRequest` (covered in #29) + +### 35. `effectiveValue` vs `value` — undocumented distinction + +- **File:line:** `model.ts:303-345 (value) vs 351-393 (effectiveValue)` +- **Category:** Misleading +- **Suggestion:** Add a JSDoc explaining the relationship at the `Setting` type level. Currently the distinction is only documented as "The user-set value that goes into storage" (302) vs "The final effective value from server as per the policy evaluation" (350) — a reader has to read both blocks to understand they're a get/set asymmetry. +- **Rationale:** This is a non-obvious feature where the user sets `value` but the server might return a different `effectiveValue` after applying policy. Worth a top-level doc, not just per-block. + +### 36–38. Verb-tense action-as-noun naming + +- **File:line:** `model.ts:288 (RestrictWorkspaceAdminsMessage), 102 (ClusterAutoRestartMessage), 294 (disableGovTagCreation field)` +- **Category:** Verb-tense inconsistency +- **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`), `governanceTagCreationDisabled: boolean`. +- **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. `disableGovTagCreation` is a verb-phrase as a field name suggesting "do the action of disabling", which is misleading for a boolean state. + +--- + +## Medium severity + +### 39. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use + +- **File:line:** `model.ts:94-96` +- **Category:** Singular/plural mismatch +- **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. + +### 40. `*Public*` qualifier — redundant + +- **File:line:** `model.ts:152, 157, 166, 262, 269, 278` +- **Category:** Redundant qualifier +- **Suggestion:** Drop `Public` from request type names (and method names — #41). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. + +### 41. Method names: `getPublic*`, `patchPublic*` — redundant `Public` + +- **File:line:** `client.ts:83, 112, 137, 346, 378, 409` +- **Category:** Redundant qualifier + verbose +- **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. + +### 42. `patch*` vs `update*` — inconsistent action verb across SDK + +- **File:line:** `client.ts:346, 378, 409` (use `patch`) +- **Category:** Inconsistent action verbs +- **Suggestion:** Pick one verb. `update` is the verb in `accountsettings/v1/client.ts` and `workspacesettings/v1/client.ts` for the equivalent operation; `patch` is used here. Cross-package consistency matters. +- **Rationale:** Same operation (PATCH HTTP verb against a settings endpoint) named `update*` in the v1 packages and `patch*` in this v2 package. Users will look for `update*` first based on muscle memory. + +### 43. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action + +- **File:line:** `client.ts:378` +- **Category:** Inconsistent + verbose +- **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. +- **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. + +### 44–48. Long type names + +- **File:line:** `model.ts:225, 204, 269, 136, 147` +- **Category:** Overly verbose +- **Identifiers:** + - `ListAccountUserPreferencesMetadataResponse` (42 chars) + - `ListAccountUserPreferencesMetadataRequest` (41 chars) + - `PatchPublicAccountUserPreferenceRequest` (39 chars) + - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` (64 chars) + - `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` (59 chars) +- **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`, drop nested-underscore style), names shorten naturally: `ListUserPreferencesMetadataResponse`, `WeekDayBasedSchedule`, `WindowStartTime`. + +### 49–51. `settingsMetadata` field name vs sibling list semantics + +- **File:line:** `model.ts:194, 196, 225-227, 252-254` +- **Category:** Singular/plural mismatch + field naming +- **Suggestion:** On `ListAccountUserPreferencesMetadataResponse`, the field should be `userPreferencesMetadata`, not `settingsMetadata`. Currently the response field for "list of user preferences" is typed as `SettingsMetadata[]` and named `settingsMetadata` — which is technically the same metadata type but linguistically misleading. +- **Rationale:** A consumer reading `resp.settingsMetadata` on a `ListAccountUserPreferencesMetadataResponse` will be confused why "settings" appears on a "user preferences" response. + +### 52–53. `*Iter` suffix on AsyncGenerator methods — Go-style + +- **File:line:** `client.ts:202, 262, 323` +- **Category:** Go/Java-style naming, cryptic abbreviation +- **Suggestion:** Drop the suffix or use TS conventions. AsyncGenerator return-type already differentiates from the page-returning variant. Common TS patterns: `listX()` returns a page, `listXAll()` or `[Symbol.asyncIterator]` returns an iterator. +- **Rationale:** "Iter" mimics Go's `func (c *Client) ListAccountSettingsMetadataAll(...)` iterator helper. In TS, returning `AsyncGenerator` is already idiomatic; the suffix is noise. + +### 54. `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` access stutters + +- **File:line:** `model.ts:13` +- **Category:** Overly verbose enum access +- **Suggestion:** See #16. + +### 55. `PreviewPhase` enum — mixed temporal/qualitative members + +- **File:line:** `model.ts:11-27` +- **Category:** Verb-tense / categorisation inconsistency +- **Members:** `PREVIEW_PHASE_UNSPECIFIED`, `PRIVATE_PREVIEW`, `PUBLIC_PREVIEW`, `BETA`, `GA_SOON`, `GA` +- **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. +- **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. + +### 56–57. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` + +- **File:line:** `model.ts:30, 88, 94, 294` +- **Category:** Acronym casing +- **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. + +### 58–59. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope + +- **File:line:** `model.ts:322 (auto-cluster on a unified Setting), 337 (restrict-admins on Setting)` +- **Category:** Field contradicting type domain +- **Suggestion:** Either drop the `Workspace` suffix from `automaticClusterUpdateWorkspace` (the parent `Setting` type is scope-agnostic) or always include the scope (then `personalCompute` should be `personalComputeAccount`). +- **Rationale:** Some payload discriminators mention scope (`automaticClusterUpdateWorkspace`), others don't (`personalCompute`, `restrictWorkspaceAdmins`). A reader can't predict the rule. + +### 60. `canToggle?: boolean` on `ClusterAutoRestartMessage` + +- **File:line:** `model.ts:104` +- **Category:** Generic field +- **Suggestion:** `userCanToggle: boolean` or `togglePermitted: boolean`. "Toggle what?" is unclear from the field alone (presumably toggle the `enabled` field, but that's implicit). + +### 61. `hours`, `minutes` with no timezone + +- **File:line:** `model.ts:148-149` +- **Category:** Generic field name, missing constraint +- **Suggestion:** Add doc specifying the time-zone interpretation, or rename `utcHours`/`utcMinutes` if UTC, or add a `timezone?: string` field. +- **Rationale:** A "maintenance window start time" without timezone is ambiguous (workspace TZ? customer TZ? UTC?). + +### 62–66. Overly verbose `effective*` discriminator names + +- **File:line:** `model.ts:369, 374, 379, 384, 389` +- **Category:** Overly verbose +- **Suggestion:** Either drop the `effective` prefix on the discriminator value (the parent field is `effectiveValue`, so the prefix is redundant) or split into two top-level discriminated unions (`Setting.value: {$case: 'automaticClusterUpdateWorkspace', ...}` and `Setting.effectiveValue: {$case: 'automaticClusterUpdateWorkspace', ...}`). +- **Rationale:** `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) is the longest discriminator in the package and stutters `effective`/`Effective` with its parent field name. + +### 67–69. `name` (key) vs `displayName` (human name) — inverted intuition + +- **File:line:** `model.ts:398, 411` +- **Category:** Generic name + misleading +- **Suggestion:** Rename `name` → `key`, then `displayName` → `name` (or `label`). +- **Rationale:** Across most data-modelling traditions, `name` is the human-readable name and `key`/`id` is the identifier. This package inverts the convention. + +### 70. `Url` vs `URL` vs `Link` + +- **File:line:** `model.ts:404 (docsLink)`; `utils.ts:69, 71, 100, 103 (url)` +- **Category:** Acronym casing inconsistency +- **Suggestion:** `docsUrl` for parity with `request.url` already used elsewhere. "Link" is HTML-flavoured; "URL" is the data. + +### 71. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name + +- **File:line:** `model.ts:107` +- **Category:** Field name verb-as-noun, overly verbose +- **Suggestion:** `forceRestart: boolean` (the semantics — restart even when not needed for updates). Or `restartOnSchedule: boolean`. +- **Rationale:** 31-character field name encoding a clause is awkward; a one-word semantic name reads better. + +--- + +## Low severity + +### 72–79. Long enum values + +- **File:line:** `model.ts:13, 31, 39, 51, 67, 75, 56, 57, 85` +- **Category:** Long enum value +- **Identifiers:** `PREVIEW_PHASE_UNSPECIFIED` (24c), `ACCESS_POLICY_TYPE_UNSPECIFIED` (30c), `DAY_OF_WEEK_UNSPECIFIED` (23c), `WEEK_DAY_FREQUENCY_UNSPECIFIED` (30c), `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` (40c), `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) +- **Suggestion:** See #16–21. For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. + +### 80–83. Undocumented abbreviations in JSDoc + +- **File:line:** `model.ts:79, 83` +- **Category:** Cryptic abbreviation +- **Tokens:** "WS" (workspace), "OBO" (on-behalf-of token), "SPs" (service principals) +- **Suggestion:** Spell out in the JSDoc. +- **Rationale:** Users reading the IDE tooltip will see "WS admins to create OBO tokens for all SPs" without expansions. + +### 84–86. Reserved-word adjacency: `value`, `type`, `name` + +- **File:line:** `model.ts` passim +- **Category:** Reserved-word risk +- **Suggestion:** See #25–27. + +### 87–88. Acronym casing notes + +- **File:line:** `model.ts:153, 78` +- **Category:** Acronym casing +- **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). + +### 89. `setting?: UserPreference` doc mismatch + +- Already covered in #29; flagged again here for the JSDoc inconsistency (`model.ts:275` field is "setting" but type is "UserPreference"). + +### 90. `disable_gov_tag_creation` wire key + +- **File:line:** `model.ts:624, 959` +- **Category:** Cryptic abbreviation (server-controlled) +- **Suggestion:** N/A — wire format is fixed. Note for documentation. + +### 91. `restrict_tokens_and_job_run_as` enum string value + +- **File:line:** `model.ts:85` +- **Category:** Wire value +- **Suggestion:** N/A — wire-fixed. + +### 92. `IntegerMessage` misleading in JS + +- **File:line:** `model.ts:171-173` +- **Category:** Misleading +- **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. +- **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. + +### 93. Nested `.value.value` + +- **File:line:** `model.ts:305, 99` +- **Category:** Singular naming collision +- **Suggestion:** See #25. + +### 94–95. Long discriminator strings + +- **File:line:** `model.ts:327-329, 374` +- **Category:** Long string identifier +- **Suggestion:** See #30, #62. + +### 96–98. Vague field names + +- **File:line:** `model.ts:103 (enabled), 137 (frequency), 289 (status)` +- **Category:** Vague +- **Suggestion:** Add domain context: `clusterRestartEnabled`, `restartFrequency`, `workspaceAdminRestrictionStatus`. +- **Rationale:** Inside their parent types the meaning is somewhat clear but auto-complete shows only the field name, which is generic. + +### 99–100. `patch*` vs `update*`, `*Iter` suffix + +- See #42, #52. + +### 101. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" + +- **File:line:** `model.ts:160-161` +- **Category:** Misleading +- **Suggestion:** Use the same vocabulary as the type — "preference" for user-preference endpoints. + +### 102. `PreviewPhase` UNSPECIFIED doc — two meanings + +- **File:line:** `model.ts:12-13` +- **Category:** Empty/ambiguous default +- **Doc:** "Default value. Indicates the preview phase is unknown or the setting is not a feature preview." +- **Suggestion:** Use two separate enum values (one for "unknown phase", one for "not a preview at all") or pick one definition. + +### 103. `ClusterAutoRestartMessage_EnablementDetails` — long type + +- See #12. + +### 104–106. Double-negative / passive booleans on `EnablementDetails` + +- **File:line:** `model.ts:121, 123, 125` +- **Category:** Misleading / cognitive load +- **Identifiers:** `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement`, `forcedForComplianceMode` +- **Suggestion:** Phrase positively where possible: `availableForEnterpriseTier?: boolean`, `availableForEntitlement?: boolean`, `forceEnabledByComplianceMode?: boolean`. Double-negatives ("unavailable for non-enterprise") slow comprehension. +- **Rationale:** "Unavailable for non-enterprise tier" requires the reader to parse two negatives ("un-" and "non-") to conclude "this is only available for enterprise". Worth one extra second of think-time on every field access. + +### 107. Cross-package `Dbfs` casing + +- **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) +- **Category:** Cross-package acronym casing +- **Suggestion:** Note for the cross-package audit, not actionable here. + +### 108. `host` — generic class field + +- **File:line:** `client.ts:54` +- **Category:** Generic +- **Suggestion:** `baseUrl` (consistent with `fetch` API conventions). "Host" can mean DNS host, host machine, etc. + +### 109. `signal: AbortSignal` field — okay, just noting + +- **File:line:** `client.ts:89, 118, 143, ...` +- **Category:** Reserved-word adjacency (web standard) +- **Suggestion:** Keep — matches Web API. + +### 110. `BETA` member adjacent to `PUBLIC_PREVIEW` + +- See #55. + +### 111. `*Schema` suffix on every zod schema + +- **File:line:** `model.ts:449, 460, 469, 477, 499, 513, 528, 551, 562, 570, 583, 596, 609, 620, 631, 766, 784, 792, 826, 836, 844, 852, 873, 887, 902, 925, 936, 944, 952, 962, 1112, 1120` +- **Category:** Type-suffix tautology +- **Suggestion:** Drop `Schema` — the variables are imported from a file that already imports zod, and the convention `unmarshal*` / `marshal*` already labels them. Currently `unmarshalSettingSchema` reads as "unmarshal-the-setting-schema" rather than the intended "schema for unmarshalling Setting". Renaming to `unmarshalSetting` / `marshalSetting` would be tighter, though it does collide with hypothetical function-style imports. +- **Rationale:** Minor — convention-only concern. Currently consistent within the package. + +--- + +## Observations + +1. **`settings` v2 is the latest in a sprawl of overlapping packages.** The same user functionality (e.g. configure cluster auto-restart, restrict workspace admins) is reachable via at least three packages with three different shapes: + - `workspacesettings/v1`: per-feature endpoints, typed payloads (`AutomaticClusterUpdateSetting.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage`). + - `settings/v2`: unified `Setting` with polymorphic `value` field (`Setting.value.$case === 'automaticClusterUpdateWorkspace'`). + - `workspaceconf/v1`: untyped `{key: string, value: string}` map. + The package naming gives the user zero guidance on which to use. A user-facing index / migration guide is critical. + +2. **`Setting`, `SettingsMetadata`, `UserPreference` are all underspecific.** The package theme is "settings v2", but the central types use the bare word "Setting" without qualification. This is the single biggest naming risk in the package — a user importing `Setting` from `@databricks/sdk-settings/v2` will clash with any application-level `Setting` type in seconds. + +3. **Four layers of proto plumbing leak into the TS surface.** + 1. Underscore-bearing nested type names (`X_Y_Z`). + 2. `*Message` suffix on every payload wrapper. + 3. Redundant `X_X_UNSPECIFIED` enum prefixes. + 4. The whole `value`/`effectiveValue` get/set asymmetry exists at the proto level for forward-compat, but in TS it could be modelled as two narrower types. + Each layer individually is defensible as "1:1 with proto"; together they make the package feel like generated boilerplate. + +4. **Cross-package duplication of `*Message` types is a real type-system hazard.** `RestrictWorkspaceAdminsMessage` declared in both `settings/v2/model.ts` and `workspacesettings/v1/model.ts` is the most concrete example. A function in user code typed as `(m: RestrictWorkspaceAdminsMessage) => void` will accept one import but not the other — and the TS error message will say "Type 'RestrictWorkspaceAdminsMessage' is not assignable to type 'RestrictWorkspaceAdminsMessage'" with no further hint. Hoisting these to a shared module is the highest-ROI fix. + +5. **`patch` vs `update` cross-package inconsistency.** The v1 SDKs use `update*`; the v2 SDK uses `patch*`. Same wire verb (PATCH HTTP). The verb mismatch will trip muscle-memory across the surface. + +6. **`*Iter` suffix is a Go idiom.** The Go SDK's `*All` helper for AsyncGenerator-equivalent iteration is named with `Iter` here. TS-idiomatic patterns are returning `AsyncIterable` directly or implementing `[Symbol.asyncIterator]`. Three method names carry the suffix. + +7. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. + +8. **Field-vs-discriminator name divergence on `value`.** A consumer constructing a `Setting` writes: + ``` + { name: 'restrict_workspace_admins', + value: { $case: 'restrictWorkspaceAdmins', + restrictWorkspaceAdmins: { status: '...' } } } + ``` + — three repetitions of the variant name. This is the proto3 `oneof` wire model leaking. A TS-native model would be: + ``` + { name: 'restrict_workspace_admins', + restrictWorkspaceAdmins: { status: '...' } } + ``` + — same expressivity, half the typing. + +9. **`name` field's role swings.** On `Setting`/`UserPreference`/`SettingsMetadata` it is the *key* of the setting (used in URL paths). On most other Databricks resources `name` is the human-readable label. The inverted convention is a small but real footgun. + +10. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. + +--- + +## Domain glossary + +| Acronym / token | Expansion | Mentioned in code? | +|-----------------|-----------|--------------------| +| **Aibi / AIBI** | AI/BI (Databricks's AI- and BI-powered Genie dashboards) | No (only as part of type names) | +| **Gov** | Governance (in `disableGovTagCreation`) | Inferred from field doc | +| **OBO** | On-behalf-of (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | Yes (one-time, undefined) | +| **WS** | Workspace (in same doc) | Inferred | +| **SP / SPs** | Service Principal(s) (in same doc) | Inferred | +| **GA / GA_SOON** | Generally Available | Implicit via doc | +| **DCP / Dcp** | Default Personal Compute policy (only in `accountsettings`, not here) | N/A | +| **CSP** | Compliance Security Profile (cross-package) | N/A here | +| **ESM** | Enhanced Security Monitoring (cross-package) | N/A here | +| **DBFS** | Databricks File System (cross-package) | N/A here | +| **LLM** | Large Language Model (cross-package) | N/A here | +| **Id** | Identifier | Implicit | +| **etag** | Entity tag (HTTP cache validator, RFC 7232) | Not in this package | + +--- + +## File coverage + +| File | Lines read | Coverage | +|------|-----------|----------| +| `src/v2/index.ts` | 42 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | +| `src/v2/model.ts` | 1160 (full) | 100% — 6 enums, 23 interfaces (incl. all nested message types), 15 unmarshal-zod schemas, 15 marshal-zod schemas audited. | +| `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor, 9 client methods (`getPublic*`, `patchPublic*`, `list*`, `list*Iter` x 3 each), and private fields (`host`, `accountId`, `httpClient`, `logger`, `userAgent`) audited. | +| `src/v2/utils.ts` | 150 (full) | 100% — `HttpCallOptions`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` audited. Shared utility code; no naming issues unique to this package (the same scaffolding appears in every package). | diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md new file mode 100644 index 00000000..c816f8de --- /dev/null +++ b/.agent/naming-audit/statementexecution.md @@ -0,0 +1,413 @@ +# Naming Audit: statementexecution + +**Package:** `@databricks/sdk-statementexecution` +**Path:** `packages/statementexecution/src/v1/` +**Versions audited:** v1 +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts`. + +**Inferred domain.** The Databricks SQL Statement Execution API. Submit a SQL +`statement`, await a `status`, then fetch result `data` either inline or via +`external_links` chunked from cloud storage. Four methods: +`executeStatement`, `cancelStatement`, `getStatementResult` (poll a submitted +statement), and `getResultData` (fetch a single result chunk by index). HTTP +prefix `/api/2.0/sql/statements/`. + +**Direct overlap with sibling packages.** + +| Package | What it is | Overlap source | +| --- | --- | --- | +| `statementexecution` (this) | Run arbitrary SQL on a SQL Warehouse. Public general-purpose SQL execution API. | — | +| `queryexecution` | Re-run *saved* queries inside *published Lakeview dashboards*. Hits `/api/2.0/lakeview-query/query/published`. | Vocabulary collides (`statementId` exists in both; `truncated` field in both; both have a `cancel` method). | +| `queryhistory` | List historical query executions. | Shares `Channel`, `Status`, `Warehouse`, `WarehouseId`. | +| `commandexecution` | Run Python/SQL via REPL on a cluster. | Both call themselves "execution". | +| `queries` | Saved query definitions. | Naming collision: `queries` vs `statements`. | + +The package name `statementexecution` is reasonable in isolation, but the SDK +*already* has `queryexecution`, `commandexecution`, and `queries`. A user +opening the marketplace sees four packages whose names overlap heavily and has +to read every one to pick the right tool. See finding #1. + +**Total weird names flagged:** 47 + +## Summary + +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 20 | +| Low | 10 | +| Observation | 4 | + +## High severity + +### 1. Package name `statementexecution` overlaps three sibling packages — `package.json`, directory name +- **Why weird:** The SDK ships `statementexecution`, `queryexecution`, `commandexecution`, and `queries`. The English words "query", "statement", and "command" are near-synonyms in casual usage, so a user installing the SDK can't pick the right one without reading docs. Concretely: this package is the *only* one that runs ad-hoc SQL on a SQL Warehouse, yet its name doesn't reveal that. The Databricks SQL Statement Execution API itself is documented at `docs.databricks.com/api/workspace/statementexecution`, so the wire-level name is "statement execution" — but the *user-facing* TS-import surface should distinguish itself from `queryexecution`. +- **Category:** 1 (vague — "statement" overlaps "query"/"command"), 12 (duplicate concept — three execution packages). +- **Suggested name:** `sqlstatements`, `sqlexec`, or `warehouseexec` — anything that signals "SQL on a SQL Warehouse". If staying with `statementexecution`, every type name should keep its `Statement*` prefix and the package docstring should call out the contrast with `queryexecution` and `commandexecution`. +- **Rationale:** Naming should disambiguate. Today the four packages are differentiable only by URL prefix and resource. Compare to e.g. `clusterlibraries` vs `clusterpolicies`: both clearly cluster-scoped but each names its sub-resource. + +### 2. `StatementStatus_State` proto-style nested enum — `src/v1/model.ts:84` +- **Why weird:** Type name uses an underscore — `StatementStatus_State` — and a comment-level ESLint disable (`@typescript-eslint/naming-convention -- Proto-style nested enum name.`). The name is a literal proto/Java carry-over: in proto-3 a nested enum on `StatementStatus` would be `StatementStatus.State`; in TypeScript there is no nested-enum syntax, so the codegen flattens with an underscore. The result is the only identifier in the file (other than `ExternalLink_HttpHeadersEntry`) that uses an underscore. The convention disagrees with every other type in the package. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/Java-style names), 17 (inconsistent — every other type is PascalCase without underscores). +- **Suggested name:** `StatementState`. The parent type `StatementStatus` already carries the "Status" semantics; the nested `State` collapses cleanly to a top-level `StatementState` without any loss of meaning. The `StatementStatus.state` field would then be `state: StatementState`. +- **Rationale:** TypeScript has no protobuf-nested-enum syntax. Forcing one with an underscore creates a name that violates ESLint and looks foreign at every use site. The same flaw exists in many SDK packages and is generator-wide. + +### 3. `ExternalLink_HttpHeadersEntry` proto-style nested message — `src/v1/model.ts:376` +- **Why weird:** Same pathology as #2: underscore-separated, ESLint-disabled "proto-style nested message name". The identifier is the only one in the file besides `StatementStatus_State` that uses an underscore separator. The convention disagrees with every other type in the package and forces a per-symbol ESLint disable comment. +- **Category:** 4 (underscores), 14 (proto-style). +- **Suggested name:** `ExternalLinkHttpHeadersEntry` (drop the underscore) or fold into the surrounding type per the wire shape. +- **Rationale:** TypeScript has no protobuf-nested-message syntax. Forcing one with an underscore creates a name that violates ESLint and looks foreign at every use site. Generator-wide. + +### 4. `ServiceErrorCode` enum members duplicate generic HTTP/gRPC vocabulary — `src/v1/model.ts:53` +- **Why weird:** The enum lists 14 generic codes: `UNKNOWN`, `INTERNAL_ERROR`, `TEMPORARILY_UNAVAILABLE`, `IO_ERROR`, `BAD_REQUEST`, `SERVICE_UNDER_MAINTENANCE`, `WORKSPACE_TEMPORARILY_UNAVAILABLE`, `DEADLINE_EXCEEDED`, `CANCELLED`, `RESOURCE_EXHAUSTED`, `ABORTED`, `NOT_FOUND`, `ALREADY_EXISTS`, `UNAUTHENTICATED`. These are direct gRPC `google.rpc.Code` carry-overs. The SDK already has a canonical apierror codes module (`packages/databricks/src/apierror/codes/`); duplicating them inside one package's enum is wrong on three axes: it's redundant, it pulls gRPC vocabulary into a HTTP/JSON SDK, and it pollutes per-package type surfaces. +- **Category:** 1 (vague — `IO_ERROR`, `ABORTED` give no context), 2 (redundant: `ServiceErrorCode.ABORTED` reads `ServiceErrorCode = ABORTED` twice), 12 (duplicate concept — apierror module owns these codes), 14 (gRPC-style names). +- **Suggested name:** Eliminate the enum. Map the wire code into the canonical `apierror/codes` enum; expose `ServiceError.errorCode` as that type. +- **Rationale:** Per-package error-code enums diverge over time. The SDK already commits to canonical codes elsewhere; this package should use them. + +### 5. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` +- **Why weird:** Enum name is `Disposition` — a generic noun (`Content-Disposition` header? business "disposition"?). The single sentinel value `FETCH_DISPOSITION_UNSPECIFIED` reveals the intended scope: this is *fetch* disposition. The enum members `INLINE` and `EXTERNAL_LINKS` are recognisable, but the type name doesn't say "fetch" or "result". A reader who skims `disposition?: Disposition` in `ExecuteStatementRequest` won't know it means "where the result data goes". +- **Category:** 1 (vague — "Disposition" of what?), 2 (redundant: `FETCH_DISPOSITION_UNSPECIFIED` reveals the missing word), 8 (the sentinel reveals the missing prefix). +- **Suggested name:** `ResultDisposition` or `FetchDisposition`. Matching field rename: `resultDisposition?: ResultDisposition`. +- **Rationale:** The enum member's `FETCH_*` prefix is a code smell — when a sentinel value carries a qualifier the type name omits, the type name is under-qualified. + +### 6. `Format` enum is dangerously generic — `src/v1/model.ts:46` +- **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #5: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). +- **Category:** 1 (vague — `Format` is the most generic possible name), 2 (the sentinel `FORMAT_UNSPECIFIED` reveals the gap), 10 (reserved-word-ish — `format` is a builtin function name in many ecosystems), 15 (generic name losing meaning at use sites). +- **Suggested name:** `ResultFormat`. Same pattern as #5. +- **Rationale:** Top-level enum names should self-describe at use sites. `result.format: Format` reads as "format format"; `result.format: ResultFormat` reads correctly. The collision risk for a single-word `Format` import is high. + +### 7. `TimeoutAction` enum members `CONTINUE`/`CANCEL` are too generic — `src/v1/model.ts:77` +- **Why weird:** A small enum with three values: `TIMEOUT_ACTION_UNSPECIFIED`, `CONTINUE`, `CANCEL`. The two real values are bare English verbs that don't say *what* they continue or cancel. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously (`CONTINUE`) or is cancelled (`CANCEL`). The relationship between the verbs and the timeout is invisible at the type level. +- **Category:** 1 (vague — `CONTINUE` what?), 14 (gRPC/proto-style upper-case verbs), 15 (generic verb-only names). +- **Suggested name:** `OnTimeout.ContinueAsync` and `OnTimeout.CancelExecution` (or rename the enum to `OnTimeout` to match the field `onWaitTimeout`). Drop the `TIMEOUT_ACTION_UNSPECIFIED` sentinel per #14. +- **Rationale:** Enum members should self-document; bare verbs require the reader to chase the field's JSDoc. + +### 8. `ColumnTypeName` enum embeds `USER_DEFINED_TYPE` — `src/v1/model.ts:37` +- **Why weird:** The enum represents SQL base types: `BOOLEAN`, `BYTE`, ..., `MAP`, `CHAR`, `NULL`, `USER_DEFINED_TYPE`. The last value breaks the pattern: every other member is a recognisable SQL type name; `USER_DEFINED_TYPE` is a meta-category covering all UDT instances. It also creates a redundant `ColumnTypeName.USER_DEFINED_TYPE` — "type" appears twice in the qualified name. +- **Category:** 2 (redundant: `*TypeName.*TYPE` repeats "type"), 13 (verb-tense — every other member is a noun like `INT`; this one is past-participial), 16 (field-vs-type-domain — UDT isn't a "base data type" per the JSDoc). +- **Suggested name:** Either `UDT` or `UserDefined` (drop `_TYPE`). Or split: keep base types in the enum; carry UDT info in `typeText`. +- **Rationale:** When one enum member breaks the pattern of the others, it signals an enum that does two jobs. + +### 9. `GetResultDataRequest` vs. `GetStatementResultRequest` — `src/v1/model.ts:381,390` +- **Why weird:** Two near-identical request types, one with `chunkIndex` and one without. Their names break apart suspiciously: + - `GetResultDataRequest` fetches *one chunk* of the result data. + - `GetStatementResultRequest` polls the entire statement (`statementId` only). + + Read aloud, they look like they swap word order arbitrarily (`Result Data` vs `Statement Result`). A user can't tell from the type names which one fetches what. The method names amplify the issue: `getResultData` (fetches a chunk) and `getStatementResult` (polls status + first chunk). +- **Category:** 1 (vague — "ResultData" vs "StatementResult"), 6 (misleading — names suggest interchangeable concepts), 17 (inconsistent ordering of qualifiers). +- **Suggested name:** `GetResultChunkRequest` (carries `chunkIndex`) + `GetStatementRequest` (polls by `statementId`). Methods: `getResultChunk` + `getStatement`. This matches the URL paths `/result/chunks/{chunkIndex}` and `/{statementId}`. +- **Rationale:** Type names should mirror the resource being addressed. The wire makes the distinction explicit; the TS surface obscures it. + +### 10. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:219` +- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. Combine with #9: there are now two `getResult*` methods, one of which doesn't actually fetch results (it polls), and one of which does (`getResultData`). +- **Category:** 6 (misleading — name implies result-fetch, primary purpose is poll), 12 (duplicate concept — both methods carry "Result" but mean different things), 17 (inconsistent verb usage — `cancel`, `execute`, `getStatementResult`, `getResultData`). +- **Suggested name:** `getStatement` (matches the URL path `/{statementId}`). The Go SDK calls this `GetStatement`. The result is *part* of the response; foregrounding it in the method name misleads. +- **Rationale:** The Databricks API docs name the operation "Get statement" (https://docs.databricks.com/api/workspace/statementexecution/getstatement). The TS SDK should match. + +### 11. `getResultData` method asymmetric with `getStatementResult` — `src/v1/client.ts:183` +- **Why weird:** Companion to #10. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. +- **Category:** 1 (vague — "result data" is too generic), 6 (misleading — drops the chunk-indexing semantic), 17 (asymmetric with sibling method). +- **Suggested name:** `getResultChunk` (or `getStatementResultChunk` to match Go). Field rename: `chunkIndex` stays. +- **Rationale:** Names should match the official API where possible. Compare to `getStatementResultChunkN` in the Go SDK. + +### 12. `Client` class name — `src/v1/client.ts:43` +- **Why weird:** A class literally named `Client`, re-exported as `Client` from `index.ts:3`. A user importing this from `@databricks/sdk-statementexecution` and another `Client` from `@databricks/sdk-queryexecution` will collide on the namespace. Identical to `queryexecution.md` Finding #9. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `StatementExecutionClient`. +- **Rationale:** Repeated SDK-wide pattern. + +### 13. `dataArray` field on `ResultData` — `src/v1/model.ts:422` +- **Why weird:** Field name `dataArray` on a type already called `ResultData`. The two `data` tokens stack: `resultData.dataArray`. The JSDoc explains it carries a `JSON_ARRAY` formatted payload, so the name is gesturing at the wire format. But the type name is the *outer* wrapper, so saying "data" inside "Data" reads as redundant. +- **Category:** 1 (vague — `data`, `array` both generic), 12 (duplicate concept — `Data.dataArray`), 20 (type-suffix tautology). +- **Suggested name:** `rows` (matches the SQL semantics: each entry of the array is a row). Or rename the outer type to `ResultChunk` so `chunk.data` is meaningful. +- **Rationale:** When `outerType.innerField` stutters the same noun, one of them is misnamed. + +## Medium severity + +### 14. Every enum carries a `*_UNSPECIFIED` sentinel — `src/v1/model.ts:41, 47, 78, 85` +- **Why weird:** All four "open" enums carry `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, and `STATE_UNSPECIFIED`. These are protobuf-style "default value" sentinels. In TypeScript, absence is represented by `undefined` (the fields are already optional). The sentinels add noise to enum members and force callers to handle a meaningless value. +- **Category:** 11 (trivial value — no behaviour), 14 (proto-style), 18 (long enum value — e.g. `FETCH_DISPOSITION_UNSPECIFIED` is 28 chars). +- **Suggested name:** Drop all `*_UNSPECIFIED` members. The field's `| undefined` already encodes "not set". +- **Rationale:** Generator-wide pattern; same as `commandexecution.md` Finding #4. + +### 15. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` +- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #26 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. +- **Category:** 13 (verb-tense inconsistency), 17 (US/UK spelling inconsistency for "cancel"). +- **Suggested name:** Pick one cancel spelling. The wire is `CANCELED` (single-l) per this enum and `CANCELLED` per `ServiceErrorCode`. Resolve at wire level. +- **Rationale:** Twin spellings of the same English word in adjacent enums in the same file is a maintenance hazard. Compare `StatementStatus_State.CANCELED` to `ServiceErrorCode.CANCELLED`. + +### 16. `httpHeaders` typed as `Record` contradicts `ExternalLink_HttpHeadersEntry` — `src/v1/model.ts:349` +- **Why weird:** Field type is `Record`, but the same file defines an `ExternalLink_HttpHeadersEntry` type for the same wire map. Two different surface representations of the same wire shape live side by side, and the underscore-named entry type is never referenced. +- **Category:** 12 (duplicate concept), 17 (inconsistent — Entry type vs Record). +- **Suggested name:** Pick one representation. Either drop the `ExternalLink_HttpHeadersEntry` export or use it consistently. +- **Rationale:** Parallel encodings of the same map type force readers to pick one and ignore the other. + +### 17. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` +- **Why weird:** A user importing from both `statementexecution` and `queryexecution` finds a `statementId` field on responses from both packages. In `statementexecution` it identifies the SQL Statement Execution submission. In `queryexecution` (a published-dashboard query) the JSDoc explicitly says "The statement_id should be identical to data_token in SuccessStatus and PendingStatus" — i.e. it's an audit copy, not a primary key. The same name means different things in two adjacent packages. +- **Category:** 12 (duplicate concept — same name, different meaning), 19 (underspecified ID — what kind of statement?). +- **Suggested name:** Keep `statementId` here (primary identifier); rename the audit-only copy in `queryexecution` (see `queryexecution.md` Finding #14). +- **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. + +### 18. `warehouseId` field — `src/v1/model.ts:158` +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #41. +- **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). +- **Suggested name:** Make required: `warehouseId: string`. +- **Rationale:** Wire requirements should propagate into TS types where possible. + +### 19. `statement` field name is the package name — `src/v1/model.ts:153` +- **Why weird:** The request type `ExecuteStatementRequest` carries a field literally called `statement`. The package name is `statementexecution`. The class name is `Client` (per #12). So a call reads: + ```ts + client.executeStatement({statement: 'SELECT 1', warehouseId: '...'}) + ``` + `statement` is the SQL text; the package name promises `statement execution`; the method is `executeStatement`. The word "statement" appears three times to mean three slightly different things: the package scope, the operation, and the SQL string. At use sites this looks like stutter. +- **Category:** 1 (vague — `statement` could be anything), 12 (duplicate concept — overloaded word), 15 (generic field name). +- **Suggested name:** Rename the field to `sql` (or `query` if not colliding with `queryexecution`). The wire is `statement`, so a marshaller maps `sql -> statement`. +- **Rationale:** The package, the class, and the field shouldn't all spell the same word three times. + +### 20. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` +- **Why weird:** Two parallel "limit" fields; `rowLimit` has no default mentioned; `byteLimit` mentions a "100 GiB default if not explicitly set" for `EXTERNAL_LINKS` disposition. The asymmetric defaults aren't captured by the types. JSDoc encodes them; users have to read both. +- **Category:** 16 (field-vs-domain — domain has implicit defaults the type doesn't show), 17 (asymmetric defaults). +- **Suggested name:** Names are fine; consolidate JSDoc so both fields document defaults symmetrically. +- **Rationale:** Pair-fields should have parallel JSDoc structure. + +### 21. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` +- **Why weird:** Field name is `parameters`. Element type is `StatementParameter`. The element name is more specific (statement parameter) than the field (parameters). At the JSDoc level, the field describes "parameter markers" — which is yet a third name for the same concept. So users see: `parameters` (field) vs `StatementParameter` (element type) vs "parameter markers" (docs). Pick one vocabulary. +- **Category:** 12 (duplicate concept — three names for one idea), 17 (inconsistent vocabulary). +- **Suggested name:** Either rename the element type to `Parameter` (less qualified than field) or rename the field to `statementParameters`. The wire shape probably matters; pick the less verbose option. +- **Rationale:** Multiple synonyms for one concept burns reader attention. + +### 22. `queryTags` field on `ExecuteStatementRequest` — `src/v1/model.ts:326` +- **Why weird:** Field is `queryTags`, element type is `QueryTag`. The user is *executing a statement*, but the metadata tags are called *query* tags. There's no `Query` type in this package; the prefix `Query` here is a Databricks billing/observability term (queries get tagged for analytics). For a TS user who hasn't seen the bigger picture, the mismatch between `executeStatement` and `QueryTag[]` reads as inconsistent. +- **Category:** 12 (duplicate concept — `statement` vs `query`), 17 (inconsistent vocabulary). +- **Suggested name:** Rename to `tags` + `Tag` (the surrounding context already says "statement", so the qualifier is redundant). Wire mapping can keep `query_tags`. +- **Rationale:** Tagging in this SDK is a cross-cutting concern; `Tag` would be the natural top-level name. Within the statement-execution context, `tags` suffices. + +### 23. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` +- **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `APIError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `APIError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. +- **Category:** 12 (duplicate concept — overlaps `APIError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). +- **Suggested name:** `StatementError` (or fold into `APIError` extensions). The errorCode should reuse the canonical apierror codes per #4. +- **Rationale:** Multiple error type shapes per SDK is a cognitive tax. + +### 24. `StatementStatus.sqlState` field — `src/v1/model.ts:522` +- **Why weird:** Field name `sqlState`. The JSDoc says "SQLSTATE error code returned when the statement execution fails." The all-caps acronym SQLSTATE is the SQL-standard 5-character status code (e.g. `42S22`). The TS field uses camelCase `sqlState`. Compare to elsewhere in the SDK where SQL is also lowercased (`sqlExpression`, `sqlText`). This is consistent SDK-wide. +- **Category:** 3 (acronym casing — `SQL` becoming `sql` is debatable; SDK has settled on lowercase, so this matches). +- **Suggested name:** Keep `sqlState`. Flagged for completeness. +- **Rationale:** TS convention varies on multi-letter acronyms; google-ts-style says lowercase initial; SDK follows the convention. + +### 25. `ServiceError.errorCode` field — `src/v1/model.ts:474` +- **Why weird:** Field name stutters with type name: `ServiceError.errorCode`. "Error" appears at both levels. A reader sees `err.errorCode` and wonders if there's a non-error code too. +- **Category:** 20 (type-suffix tautology), 12 (duplicate concept). +- **Suggested name:** `code` (since the type is already `ServiceError`). +- **Rationale:** Stutter — `error.error*` — is a code smell. + +### 26. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` +- **Why weird:** Same English word, two spellings, in two enums in the same file. `CANCELLED` is British; `CANCELED` is American. The wire chose differently for the two enums; the SDK mirrors the wire. End users have to remember "cancel with one or two Ls". +- **Category:** 13 (spelling/tense inconsistency — see #15), 17 (asymmetric pair). +- **Suggested name:** Normalise upstream. If kept, document the spelling difference in `@databricks/sdk-databricks` README. +- **Rationale:** The spelling difference is invisible in casual scanning but breaks copy/paste. + +### 27. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` +- **Why weird:** `waitTimeout?: string` with JSDoc explaining it must be formatted as `"Ns"` where N is 0 or 5-50. So a *typed string* with a private DSL inside. Users will write `"5s"` and hope, or worse: `5` (number, won't compile). The wire format is a proto Duration, but the TS surface could parse `number` (seconds) or `Duration` (ms) and emit `Ns`. +- **Category:** 1 (vague — `string`-typed numeric), 6 (misleading — a "timeout" with arbitrary string content), 14 (proto/Go-style — Duration carry-over). +- **Suggested name:** Keep `waitTimeout` but change the type to `number` (seconds) and let the marshaller produce `Ns`. Or `Duration` from `@databricks/sdk-core/wkt`. +- **Rationale:** Letting users pass arbitrary strings into a numeric field is a contract violation waiting to happen. + +### 28. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` +- **Why weird:** Field is `onWaitTimeout`, type is `TimeoutAction`. The two names don't share the prefix `Wait*` even though they're tightly coupled. A reader sees `onWaitTimeout?: TimeoutAction` and has to chase the docs to learn the enum members are about wait-timeouts. +- **Category:** 17 (asymmetric field/type naming), 12 (duplicate concept — `Wait`/`Timeout` overloaded). +- **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #7, `OnTimeout`. +- **Rationale:** Field/type symmetry is a strong signal. + +### 29. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` +- **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. +- **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). +- **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. +- **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. + +### 30. `nextChunkInternalLink` field — `src/v1/model.ts:128` +- **Why weird:** The field is documented as: "an absolute `path` to be joined with your `$DATABRICKS_HOST`, and should be treated as an opaque link. This is an alternative to using `next_chunk_index`." The word "Internal" is doing a lot here — it's not internal as in "private to Databricks"; it means "internal-link, as opposed to a presigned cloud link". The naming is opaque without the JSDoc. +- **Category:** 1 (vague — "Internal" is too generic), 5 (cryptic — needs JSDoc to decode). +- **Suggested name:** `nextChunkRelativePath` (matches its semantics: a path relative to the workspace host). Or `nextChunkUrlPath`. +- **Rationale:** Names should not lean on JSDoc to communicate the *kind* of identifier. + +### 31. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +- **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. +- **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). +- **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). +- **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. + +### 32. `totalChunkCount`, `totalRowCount`, `totalByteCount` triple — `src/v1/model.ts:453, 457, 462` +- **Why weird:** Three parallel `total*Count` fields. Each ends in `Count` (singular noun) and starts with `total` (qualifier). The triple is consistent but verbose — `totalChunkCount` is 16 characters for an integer count. +- **Category:** 7 (overly verbose), 8 (redundant suffix — `Count` is implied for an integer). +- **Suggested name:** `chunks` / `rows` / `bytes` (drop `total*Count` and let the integer-ness be implicit). Or keep `total*Count` and document that the per-chunk `*Count` fields are partial sums. +- **Rationale:** Verbose triplets across a type can usually be compressed. + +### 33. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` +- **Why weird:** `ResultManifest.chunks` is an array of `ChunkInfo`; `totalChunkCount` is `chunks.length`. The two carry the same information; on the wire there is a sender-receiver invariant, but TS users can compute one from the other. The naming gives no hint of the redundancy. +- **Category:** 12 (duplicate concept), 1 (vague — both fields are about the same property). +- **Suggested name:** Drop `totalChunkCount`; users compute via `chunks?.length`. +- **Rationale:** Two fields that mean the same thing should not both be public. + +### 34. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` +- **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. +- **Category:** 16 (field-vs-format contradicts domain when format differs). +- **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. +- **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. + +### 35. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +- **Why weird:** Companion to #34. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. +- **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). +- **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. +- **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. + +### 36. `unmarshal*Schema` and `marshal*Schema` naming chain — `src/v1/model.ts:525-740` +- **Why weird:** Same pattern as in `queryexecution.md` Finding #19. `unmarshalChunkInfoSchema`, `unmarshalColumnInfoSchema`, etc. — `unmarshal` (Go) + `Schema` (zod helper) — two layers of meta around one operation. Longest is `unmarshalStatementResponseSchema` (32 chars) and `marshalExecuteStatementRequestSchema` (37 chars). +- **Category:** 5 (cryptic), 7 (verbose), 8 (redundant suffix), 14 (Go-style `marshal`). +- **Suggested name:** `decodeChunkInfo`, `decodeColumnInfo`, etc. (drop `Schema`; rename to `decode/encode`). Generator-wide. +- **Rationale:** Recurring SDK pattern; same fix as other audits. + +### 37. `marshalRequest` and `parseResponse` in utils — `src/v1/utils.ts:119, 113` +- **Why weird:** Verb pair `marshal` (Go) + `parse` (JS) — asymmetric, identical to `queryexecution.md` Finding #20. The two functions are generic JSON encode/decode but named differently and asymmetrically. +- **Category:** 1, 14, 17. +- **Suggested name:** `encodeJson` / `decodeJson`. +- **Rationale:** Generator-wide. + +### 38. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` +- **Why weird:** Two `execute*` functions in the same file, one wraps retry/rate-limit policy and one does the actual HTTP. Same as `queryexecution.md` Finding #21. +- **Category:** 1, 12, 17. +- **Suggested name:** `runWithPolicies` + `sendHttpRequest`. +- **Rationale:** Generator-wide. + +### 39. `buildHttpRequest` helper — `src/v1/utils.ts:96` +- **Why weird:** "Build" implies builder pattern; this is a 16-line object literal. Same as `queryexecution.md` Finding #22. +- **Category:** 1, 6. +- **Suggested name:** `makeHttpRequest` or inline. + +### 40. `readAll` stream-drain helper — `src/v1/utils.ts:40` +- **Why weird:** Generic verb. Same as `queryexecution.md` Finding #23. +- **Category:** 1, 5. +- **Suggested name:** `drainStream`. + +### 41. Every field on every request type is optional — `src/v1/model.ts` (every interface) +- **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. +- **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). +- **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). +- **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. + +### 42. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` +- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #17) suggests this is the wrong abstraction. +- **Category:** 6 (misleading — type is overloaded), 12 (duplicate concept — two operations). +- **Suggested name:** Keep `StatementResponse` but document that it's polymorphic. Or split into `StatementSubmissionResponse` + `StatementStateResponse`. +- **Rationale:** Shared response types are acceptable but should be flagged for documentation. + +## Low severity + +### 43. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +- **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. +- **Category:** 17 (acceptable asymmetry). +- **Suggested name:** Keep. + +### 44. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:108, 111, 116` +- **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. +- **Category:** 12 (duplicate concept — three types carry the same fields). +- **Suggested name:** Extract `ChunkMetrics` shared interface. +- **Rationale:** Trio-replicated types are a tell. + +### 45. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` +- **Why weird:** `typeText` is "the full SQL type specification" (e.g. `DECIMAL(10,2)`). `typeName` is the base type name (`DECIMAL`). The pair is intentional but the names don't make the relationship obvious — `typeText` and `typeName` sound interchangeable. +- **Category:** 17 (asymmetric pair — `Text` vs `Name`), 1 (vague — `Text` of what?). +- **Suggested name:** `typeSql` (the wire SQL text) + `typeBase` (the base type) — but the wire is canonical, so keep names. Document the relationship. + +### 46. `position` field on `ColumnInfo` — `src/v1/model.ts:139` +- **Why weird:** Top-level field literally `position` with JSDoc "The ordinal position of the column (starting at position 0)." `position` is generic. `ordinalPosition` (matches the JSDoc) or `columnIndex` would be more precise. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `ordinalPosition` or `index`. + +### 47. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` +- **Why weird:** A string field whose JSDoc says "Indicates the date-time that the given external link will expire and becomes invalid". Two issues: the name `expiration` is ambiguous (an expiry timestamp? a TTL?), and the type is `string` (presumably ISO8601 — the JSDoc doesn't say). A reader can't tell from the type or name how to interpret the value. +- **Category:** 1 (vague), 6 (misleading — could be TTL). +- **Suggested name:** `expiresAt` (ISO8601 timestamp) — matches modern JS/TS convention. + +### 48. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +- **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. +- **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). +- **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. +- **Rationale:** Optional/low-priority but worth noting. + +### 49. `Schema` type is overloaded with zod `*Schema` helpers — `src/v1/model.ts:468` +- **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (zod schemas, validation schemas, database schemas). Inside this file zod schemas are also named `*Schema` (unmarshal/marshal helpers). So `Schema` (type) coexists with `unmarshalSchemaSchema` (helper) — and yes, that line literally exists at `model.ts:634`: `export const unmarshalSchemaSchema: z.ZodType = ...`. +- **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 12 (duplicate concept — zod `*Schema` everywhere). +- **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from validation schemas. Then `unmarshalResultSchemaSchema` becomes only mildly stuttery but at least no longer self-referential. + +### 50. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` +- **Why weird:** Three single-word fields on a single type, all `string | undefined`. The JSDoc explains: name is the marker name; value is the substituted text; type is the SQL type. The names work fine in this context but are maximally generic — `name`, `value`, `type` could mean anything. The `type` field collides with the TS keyword visually (though `type` isn't actually reserved in object-position). +- **Category:** 1 (vague), 10 (reserved-word collision — `type` is contextually meaningful), 15 (generic names). +- **Suggested name:** `parameterName`, `parameterValue`, `sqlType` — but local names are fine inside a clear-context type. Flagged for completeness. + +### 51. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` +- **Why weird:** Generic key-value pair. Same as #50 but for tags. `tagKey` + `tagValue` are common alternatives. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** Acceptable in context. + +### 52. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +- **Why weird:** Generic name. Same as `queryexecution.md` Finding #25. +- **Category:** 1. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. + +## Observations (non-fixable here) + +### O-1. URL string concatenation handles `undefined` silently — `src/v1/client.ts:76, 187, 223` +- The URL is built via template literals like + ``${this.host}/api/2.0/sql/statements/${req.statementId ?? ''}/cancel``. + If `statementId` is `undefined`, the URL becomes + `.../sql/statements//cancel`, which the server will return 404 for. The + fallback to empty string is a silent-failure pattern. Names are fine; the + fallback semantics are wrong. + +### O-2. `*_UNSPECIFIED` sentinels exist on every enum — see #14. +- Generator-wide; the fix is in codegen. + +### O-3. Statement IDs share a vocabulary with `queryexecution` and `queryhistory`. +- All three packages emit some flavour of `statementId`. The naming should be + unified at the apierror / statement-vocabulary layer if it matters. + +### O-4. Module-level JSDoc lives in leaf files instead of `index.ts`. +- `index.ts` has no module-level JSDoc; `model.ts` has none either. Other + packages document scope and the API at `index.ts`. The naming choices flagged + above (e.g. `Format`, `Disposition`, `Client`) would be less confusing if + `index.ts` explained the package scope and contrasts with sibling packages. + +--- + +## Overlap with `queryexecution` — explicit comparison + +The audit prompt asked specifically to flag the overlap. Here's the explicit +mapping of vocabulary shared between the two packages: + +| Concept | statementexecution | queryexecution | +| --- | --- | --- | +| Primary identifier | `statementId` (primary) | `statementId` (audit-only copy of `dataToken`) | +| "Truncated" boolean | `ResultManifest.truncated` (truncation of result set) | `SuccessStatus.truncated` (truncation of dashboard query result) | +| Cancel operation | `cancelStatement()` | `cancelPublishedQueryExecution()` | +| Execute operation | `executeStatement()` | `executePublishedDashboardQuery()` | +| Poll operation | `getStatementResult()` (also returns first chunk) | `pollPublishedQueryStatus()` | +| State terminology | `StatementStatus_State.{PENDING, RUNNING, SUCCEEDED, FAILED, CANCELED, CLOSED}` | `QueryResponseStatus.{success, pending, canceled, closed}` (discriminated union) | +| Cancellation spelling | `CANCELED` (single-l) | `canceled` (single-l, lowercase) | +| Generic `Client` name | yes | yes | +| Verb-tense | `cancelStatement` | `cancelPublishedQueryExecution` | + +The two packages model semantically distinct operations (general SQL Statement +Execution vs Lakeview-dashboard query lifecycle) but share enough vocabulary +(`Statement`, `Query`, `Cancel`, `Execute`, `Status`) that a user importing +both will be confused. The fix is at the naming/package level (see #1) and +the cross-package vocabulary alignment (#17, #26). + +--- + +## Themes + +1. **Proto/Go leakage.** `StatementStatus_State`, `ExternalLink_HttpHeadersEntry`, `*_UNSPECIFIED` sentinels, `marshal/unmarshal` verb pair, `ServiceErrorCode` mimicking `google.rpc.Code`. Every leakage point requires an ESLint disable or a special-casing in zod. Generator-wide. +2. **Word stutter.** `ServiceError.errorCode`, `ResultData.dataArray`, `*ResultData` vs `*StatementResult`, `executeStatement` / `getStatementResult` / `statement` field, `Schema` vs `unmarshalSchemaSchema`. The wire shape doesn't help here; the TS surface could compress. +3. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). +4. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md new file mode 100644 index 00000000..e008b163 --- /dev/null +++ b/.agent/naming-audit/supervisoragents.md @@ -0,0 +1,336 @@ +# Naming Audit: supervisoragents + +**Path:** `packages/supervisoragents/src/v1/` +**Versions audited:** v1 +**Inferred domain:** "Supervisor Agent" is an orchestrator resource that +routes user questions to one or more child tools (genie spaces, knowledge +assistants, UC functions, UC connections, apps, volumes, dashboards, +serving endpoints, UC tables, vector-search indexes, catalogs, schemas, +nested supervisor agents, public web search). CRUD on three resource types: +`SupervisorAgent` (top-level), `Tool` (child of `SupervisorAgent`, +discriminated union over 14 tool kinds), and `Example` (child of +`SupervisorAgent`, question + guidelines pair used for in-context steering). +Every list endpoint paginates via `pageSize`/`pageToken`. No state enums +exist in this package; the entire surface is data plus references to other +Databricks resources. +**Total weird names flagged:** 49 + +## Summary +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 18 | +| Low | 11 | +| Observation | 7 | + +## High severity + +### 1. `SupervisorAgent` — `Supervisor` and `Agent` are both extremely generic — `src/v1/model.ts:219` +- **Why weird:** The package name + entity name combines two of the most overloaded nouns in the AI space. `Agent` alone could mean anything from "browser user-agent" to "autonomous LLM agent" to "service-account principal." `Supervisor` is even worse — in computing it usually refers to a process supervisor (systemd, OpenRC, supervisord) or a kernel privilege ring. Together they read as "a process supervisor that supervises an agent process." The actual domain is an LLM orchestrator: a top-level agent that routes user prompts to a set of registered sub-tools. The doc on the `Tool` field type mentions it is "Nested Supervisor Agent tool" (model.ts:245) for recursion, which reinforces that this is in fact a router. The Databricks docs (https://docs.databricks.com/en/generative-ai/agent-framework/index.html) call this style "AI agent" / "agent system" — but not "supervisor agent." The package would be far less ambiguous as `agentorchestrators`, `routeragents`, or `supervisoragents` with `SupervisorAgent` renamed to `RouterAgent` or `OrchestratorAgent`. +- **Category:** 1 (vague/generic — both nouns), 17 (no SDK-wide policy on `Agent` terminology). +- **Suggested name:** `RouterAgent` or `OrchestratorAgent` (then package `routeragents` / `agentorchestrators`). If the backend wire name `supervisor-agents` cannot change, keep the package name but document the routing semantics on the type-level JSDoc. +- **Rationale:** The first sentence of the package's only JSDoc-relevant type is "The resource name of the SupervisorAgent." That tautological doc is a tell — the team did not have a good one-line description for the type, which is exactly what a vague name produces. A self-describing name would seed an obvious one-liner ("A `RouterAgent` routes user prompts to a set of registered tools."). + +### 2. `Tool` — bare generic name for a discriminated union over 14 resource kinds — `src/v1/model.ts:251` +- **Why weird:** The `Tool` type is the most generic name in any AI SDK. It does not say *which* tools, *whose* tools, or *how* the tool is invoked. The discriminated union has 14 variants spanning unrelated resource domains: vector search, dashboards, model-serving endpoints, UC functions, web search, etc. Compare to `customllms.Dataset` (audited as flagged for being a single-field wrapper — at least it had domain specificity); `Tool` here is genuinely a 14-kind tagged union that needs a name explaining what kind of tool. A reader importing `import {Tool} from '@databricks/sdk-supervisoragents/v1'` will see `Tool` as a top-level name in their module and be unable to guess whether it's a CLI tool, a build tool, a python tool, or a function-call tool. Other LLM-tool conventions: OpenAI calls them `function` (https://platform.openai.com/docs/guides/function-calling); Anthropic calls them `tool_use` (https://docs.anthropic.com/en/docs/build-with-claude/tool-use); LangChain calls them `Tool` (where the package context disambiguates). +- **Category:** 1 (vague/generic), 12 (duplicate of `SupervisorAgentTool`, which is one variant of `Tool`). +- **Suggested name:** `AgentTool`, `SupervisorTool`, or `RegisteredTool`. The qualifier disambiguates against generic `Tool` collisions in a multi-package import set. +- **Rationale:** Same reasoning as #1; specificity in type names prevents alias collisions and makes import lists self-documenting. The package already calls one tool kind `SupervisorAgentTool` (the recursion case), so the bare `Tool` lacks a parallel qualifier. + +### 3. `Tool.toolType: string` — stringly-typed when it is a closed set of 14 — `src/v1/model.ts:259-260` +- **Why weird:** The JSDoc enumerates the allowed values: `"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "lakeview_dashboard", "serving_endpoint", "uc_table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`. The type is `string`, so a caller writing `toolType: 'GENIE_SPACE'` (wrong case), `'genieSpace'` (camelCase), or `'web-search'` (kebab) gets no compiler help. The same struct *already* carries the discriminant in the `spec` discriminated union: `spec.$case` ranges over `'genieSpace' | 'knowledgeAssistant' | ...` — covering the exact same 14 kinds. So the SDK declares the type domain twice, in two incompatible casings (snake on `toolType`, camel on `spec.$case`). This is the same anti-pattern flagged in `knowledgeassistants.md` #10 (`sourceType: string` vs `spec.$case`). +- **Category:** 16 (field contradicts type domain — `string` for a closed set), 6 (misleading — two declarations of the same enum), 12 (duplicate of `spec.$case`), 17 (snake vs camel for the same enum). +- **Suggested name:** Either (a) convert `toolType` to a string-literal union `'genieSpace' | 'knowledgeAssistant' | ...` matching `spec.$case`, or (b) drop `toolType` entirely because `spec.$case` already encodes it (recommended). +- **Rationale:** Stringly-typed enums in TypeScript are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals). The duplicate declaration in two casings is a generator artifact from the proto definition and a tax on every consumer. + +### 4. `Tool.toolType` casing disagrees with every other discriminator value on the wire — `src/v1/model.ts:259` +- **Why weird:** The 14 enumerated values inside the doc string are snake_case: `"genie_space"`, `"knowledge_assistant"`, `"lakeview_dashboard"`, `"serving_endpoint"`, `"uc_function"`, `"uc_connection"`, `"uc_table"`, `"vector_search_index"`, `"supervisor_agent"`, `"web_search"` (singletons `"app"`, `"volume"`, `"catalog"`, `"schema"` work in both). But the TypeScript `spec.$case` field uses camelCase variants of the same set: `'genieSpace'`, `'knowledgeAssistant'`, etc. The marshal/unmarshal pair around lines 765-865 keeps `toolType` as a *string* in both directions, so the wire format for `toolType` is snake_case — but the consumer must know to write `toolType: 'genie_space'` while paying attention to camelCase `spec.$case`. A TypeScript-only consumer who never reads JSDoc will think the values are camelCase to match `$case` and get HTTP 400 on the first request. +- **Category:** 17 (casing inconsistency within the same struct), 4 (snake_case in a string-literal value, even though the value is on the wire). +- **Suggested name:** If `toolType` survives (see #3), document inline that values are snake_case wire-side, or normalize to camelCase to match `spec.$case`. +- **Rationale:** The mismatch is exactly what causes the most painful bugs in generated SDKs — the type checker says it is fine, the runtime fails. A naming audit must call this out even though it is a *value* mismatch rather than an *identifier* mismatch. + +### 5. `KnowledgeAssistant` package name collision — `src/v1/model.ts:127` +- **Why weird:** The package `@databricks/sdk-supervisoragents` exports a type `KnowledgeAssistant` that represents *one variant of a Tool.spec discriminated union*, not the actual knowledge assistant resource. The actual `KnowledgeAssistant` resource lives in `@databricks/sdk-knowledgeassistants/v1`. A consumer importing both packages will collide on the same identifier in TS source — and the supervisor-agents type only has two fields (`servingEndpointName`, `knowledgeAssistantId`) while the real one has 12+. This is the same problem as #1/#2 but at the cross-package level. Compare with `LakeviewDashboard`, `Catalog`, `Schema`, `UcTable`, `VectorSearchIndex` — every variant uses an unqualified bare name that collides with the canonical resource type elsewhere in the SDK. +- **Category:** 12 (duplicate concept across packages), 6 (misleading — same name, different shape). +- **Suggested name:** `KnowledgeAssistantToolSpec`, `KnowledgeAssistantRef`, or `ToolKnowledgeAssistant`. Apply the suffix uniformly to all 14 variants (`GenieSpaceRef`, `LakeviewDashboardRef`, etc.). This is the same pattern the same package *already uses* for one variant: `SupervisorAgentTool` (the nested case), which uniquely calls out that it is a tool wrapper, not the resource itself. +- **Rationale:** Cross-package name collisions are the worst kind of naming bug because the import path lies about the type's identity. A `Ref`/`ToolSpec` suffix on every variant solves this uniformly. + +### 6. `SupervisorAgentTool` is the *only* variant with a name disambiguation — `src/v1/model.ts:246` +- **Why weird:** Of the 14 tool variants, exactly one uses the qualified naming convention: `SupervisorAgentTool` (the recursion case — a nested supervisor agent as a tool). Every other variant is bare: `GenieSpace`, `KnowledgeAssistant`, `UcFunction`, `LakeviewDashboard`, `App`, `Volume`, `ServingEndpoint`, `UcTable`, `VectorSearchIndex`, `UcConnection`, `Catalog`, `Schema`, `WebSearch`. The author of `SupervisorAgentTool` clearly recognized the collision problem (since `SupervisorAgent` is the top-level type in this very file) — but did not apply the same logic to the other 13 variants. This is inconsistency-by-omission. +- **Category:** 17 (inconsistency across sibling types), 8 (asymmetric suffix application). +- **Suggested name:** Either drop the `Tool` suffix from `SupervisorAgentTool` and find another way to disambiguate (probably not workable since it collides), or apply `*Tool` (or `*Ref`, `*ToolSpec`) to all 14 variants. See #5 for the recommended pattern. +- **Rationale:** When a generator picks one of two options for a single case, you can be sure the other 13 cases will look wrong. + +### 7. `Tool.spec` discriminated union name is generic — `src/v1/model.ts:262` +- **Why weird:** `Tool.spec?: { $case: 'genieSpace'; genieSpace: GenieSpace } | ... | undefined`. The discriminator field is called `spec` — a generic CS term that does not convey *what kind* of specification this is. Same anti-pattern flagged in `knowledgeassistants.md` #12 (`KnowledgeSource.spec`). At a call site, `tool.spec.$case` is competing with the redundant `tool.toolType` (see #3) for "which kind of tool is this" semantics. Worse, `spec` is too short to autocomplete cleanly in many IDEs — and it collides with `Tool.toolType` JSDoc that calls the variants "tool types." +- **Category:** 1 (vague/generic), 12 (duplicate of `toolType` discriminant). +- **Suggested name:** `tool` (so `tool.tool.$case` — awkward) or `config` (matches the doc "Specification for the tool type") or `payload` or `kind` (a literal pun on the discriminant role). The cleanest fix is to flatten: drop `toolType` (per #3), rename `spec` → `tool`, and the type reads `agentTool.tool.$case`. +- **Rationale:** A discriminated union should self-describe via its tag, not via a generic wrapper field. `spec` is the kind of name that survives only because nobody on the review can think of anything better. + +### 8. `name` field overloaded — every CRUD request and every entity — `src/v1/model.ts:30,45,59,67,76,88,108,116,124,146,196,224,254,330` — fourteen sites +- **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`supervisor-agents/{id}` or `.../tools/{id}` or `.../examples/{id}`). Three different resource types share the same field name with three different formats — a consumer chaining operations across `SupervisorAgent`, `Tool`, and `Example` will have three `name`s in scope, all meaning different things. `DeleteToolRequest.name` and `DeleteSupervisorAgentRequest.name` have the same field name with disjoint URL contracts. Same problem documented in `knowledgeassistants.md` #7. Plus three sub-entity types (`Catalog`, `Schema`, `UcTable`, `Volume`, `UcFunction`, `UcConnection`, `App`, `ServingEndpoint`, `VectorSearchIndex`) each have a `name` field meaning "the wire identifier of the wrapped Databricks resource" — *not* a supervisor-agent resource name. So `tool.spec.catalog.name` and `tool.name` and `parent` (a resource path) are three different `name`-semantics in the same call site. +- **Category:** 1 (vague/generic), 15 (generic field name losing meaning), 19 (underspecified id). +- **Suggested name:** Type-qualify resource names: `supervisorAgentName` on `SupervisorAgent` and the supervisor-agent CRUD requests; `toolName` on `Tool` and tool requests; `exampleName` on `Example` and example requests. On the sub-resource types (`Catalog`, `Schema`, etc.), rename `name` → `fullName` (Unity Catalog convention) or `qualifiedName`. Alternatively follow AIP-122 (https://google.aip.dev/122) and keep `name` only on the type the request operates on; rename to `parent` when it identifies a parent (the package already does this for create/list — see #9). +- **Rationale:** This is the highest-frequency naming bug in the package — 14 sites use the same field name for at least four different semantic roles. + +### 9. `parent` and `name` describe the same wire concept inconsistently — `src/v1/model.ts:30,45,59,76,108,146,196` vs `src/v1/model.ts:67,116,124` +- **Why weird:** `CreateExampleRequest.parent`, `CreateToolRequest.parent`, `DeleteExampleRequest.name`, `DeleteSupervisorAgentRequest.name`, `DeleteToolRequest.name`, `GetExampleRequest.name`, `GetSupervisorAgentRequest.name`, `GetToolRequest.name`, `ListExamplesRequest.parent`, `ListToolsRequest.parent` all reference resource paths under `/supervisor-agents/{id}`. The Create + List requests correctly use `parent` per AIP-132 (https://google.aip.dev/132). The Delete + Get requests use `name`. So far consistent with AIP. But: `CreateExampleRequest.parent` is the *supervisor-agent* path, while `CreateExampleRequest.example.name` is the *new example* path. Reading the type, both fields are `string` and the JSDoc explains which is which — but the field names are not self-documenting. Compare with the audit on `knowledgeassistants.md` #8 (same pattern, same finding). +- **Category:** 17 (parent vs name inconsistency for related wire concepts). +- **Suggested name:** Keep AIP-132 (`parent` on create/list, `name` on get/delete/update). Rename `parent` more specifically: `supervisorAgentName` on tool/example requests. The bigger fix is to use typed name strings (template-literal types) so `parent: ${SupervisorAgentName}` is checked at compile time. +- **Rationale:** Same as `knowledgeassistants` — AIP-132 is the right convention, but the bare names lose type discipline. + +### 10. `SupervisorAgent.id` is deprecated but still in the public TS surface — `src/v1/model.ts:231-232` +- **Why weird:** `id?: string` carries the JSDoc "Deprecated: Use supervisor_agent_id instead." (mind the wire-format leaking into the doc — `supervisor_agent_id` is the snake_case version, but the actual TS field is `supervisorAgentId`). The field is *not* marked `@deprecated` for the IDE, so consumers using IntelliSense will not see the strikethrough. The same issue applies to `Tool.id` (model.ts:257-258, same wording "Deprecated: Use tool_id instead.") and `KnowledgeAssistant.servingEndpointName` (model.ts:128-129, "Deprecated: use knowledge_assistant_id instead."). +- **Category:** 6 (misleading — deprecation is documented but not annotated), 8 (redundant suffix: keeping deprecated `id` *and* `supervisorAgentId` causes name clutter), 14 (the doc references the snake_case wire name rather than the TS name). +- **Suggested name:** Add `@deprecated` JSDoc tag so IDEs render it; doc should reference `supervisorAgentId` (the TS name) not `supervisor_agent_id` (the wire name); long-term plan for removal. Same fix on `Tool.id` and `KnowledgeAssistant.servingEndpointName`. +- **Rationale:** Public-API deprecation has a standard JSDoc tag (https://jsdoc.app/tags-deprecated.html) that triggers IDE warnings. Free-text comment does not. + +### 11. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:128-129` +- **Why weird:** The `KnowledgeAssistant` variant type (one of 14 tool kinds) has two fields: + - `servingEndpointName?: string` — doc "Deprecated: use knowledge_assistant_id instead." + - `knowledgeAssistantId?: string` — doc "The ID of the knowledge assistant." + Both fields are optional. A consumer setting both gets an ambiguous wire payload (the backend has to pick one). Plus, the field name `servingEndpointName` does not even *imply* "knowledge assistant" — it implies a model-serving endpoint. The naming of the deprecation target is also misleading: a knowledge assistant *id* is not necessarily the same wire value as a serving-endpoint *name*. The doc-comment claim that one replaces the other is suspect. +- **Category:** 6 (misleading — name and replacement don't obviously equate), 16 (field name from wrong domain — "serving endpoint" applies to a different resource). +- **Suggested name:** Apply `@deprecated`; consider dropping the field entirely if `knowledgeAssistantId` fully supplants it. Document the migration mapping precisely. +- **Rationale:** This is a deprecation transition mid-flight; the public TS surface should signal it correctly. + +### 12. `SupervisorAgentTool.supervisorAgentId` doc says "tile ID" — `src/v1/model.ts:247-248` +- **Why weird:** Doc reads "The ID of the supervisor agent (tile ID)." The parenthetical "(tile ID)" refers to "tile" — a UI concept from Databricks Lakeview dashboards. A *Supervisor Agent* tool variant should not reference a dashboard concept. This appears to be a copy-paste from the dashboard tool spec (cf. `LakeviewDashboard.dashboardId`, model.ts:136). Same kind of doc-bug as flagged in `customllms.md` #5. +- **Category:** 6 (misleading — doc contradicts domain). +- **Suggested name:** Field name `supervisorAgentId` is fine; fix the JSDoc to drop "(tile ID)" and explain that this is the recursive reference to a child supervisor agent. +- **Rationale:** Doc-text bugs on identifiers are within scope of a naming audit; consumers learn semantics from JSDoc. + +### 13. `Catalog` / `Schema` collide with built-in TS and broader Databricks concepts — `src/v1/model.ts:19,210` +- **Why weird:** Two unqualified types `Catalog` and `Schema` represent UC catalog/schema *asset-search scopes* (a permissions concept), not the actual `catalog.CatalogInfo` / `catalog.SchemaInfo` resources from `@databricks/sdk-catalog`. The names are extremely overloaded: `Schema` is also a generic CS term (and shadows Zod's `z.ZodType`-related schema metadata), `Catalog` is a UC primary resource. A consumer importing this package + `catalog` will have to alias one of them. Same family of problem as #5 (cross-package collision). +- **Category:** 12 (duplicate concept across packages), 10 (reserved-word-ish; `Schema` is a near-reserved JS identifier in many libraries), 1 (vague). +- **Suggested name:** `CatalogAssetSearchScope` / `SchemaAssetSearchScope` (verbose but accurate), or `CatalogToolSpec` / `SchemaToolSpec` for the *Ref* convention from #5. +- **Rationale:** The current names lie about the type's identity. They look like the canonical UC resources but represent a permissions scope. + +## Medium severity + +### 14. `SupervisorAgent.endpointName` is the agent's serving endpoint, not user-supplied — `src/v1/model.ts:239-240` +- **Why weird:** Doc reads "The name of the supervisor agent's serving endpoint." This is a server-populated read-only field (the supervisor-agents backend creates a model-serving endpoint behind the scenes). The name `endpointName` does not tell the reader which kind of endpoint (model serving? vector search? SQL warehouse?). Same problem flagged in `knowledgeassistants.md` #21 and `customllms.md` #7. +- **Category:** 1 (vague), 19 (underspecified id). +- **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or `agentServingEndpointName`. The variant type `KnowledgeAssistant` in this same file already uses `servingEndpointName` (model.ts:129) — so renaming here would *align* the two fields. +- **Rationale:** Cross-package and within-package alignment; `servingEndpointName` is the canonical term. + +### 15. `SupervisorAgent.experimentId` — what kind of experiment? — `src/v1/model.ts:241-242` +- **Why weird:** Doc reads "The MLflow experiment ID." A bare `experimentId` is fine *if* the consumer knows the SDK only integrates with MLflow. But the consumer reading `SupervisorAgent.experimentId` could reasonably guess this is an A/B-test experiment, a feature-flag experiment, or a generic experiment. Same problem flagged in `knowledgeassistants.md` #22 — and there the audit suggested `mlflowExperimentId`. +- **Category:** 1 (vague), 19 (underspecified id), 17 (inconsistency with sibling SDK). +- **Suggested name:** `mlflowExperimentId`. +- **Rationale:** Cross-package consistency. The doc clarifies but the name does not. + +### 16. `SupervisorAgent.creator: string` — what is a creator? — `src/v1/model.ts:235-236` +- **Why weird:** Doc reads "The creator of the Supervisor Agent." Could be a username, email, UUID, Databricks principal id, or service-principal client id. The type is `string`. Same field, same problem flagged in `knowledgeassistants.md` #24 and `customllms.md` #10. +- **Category:** 1 (vague), 19 (underspecified id), 17 (SDK-wide inconsistency). +- **Suggested name:** `createdBy` (AIP-148 standard, https://google.aip.dev/148, also matches `unitycatalog`). +- **Rationale:** Match the most-used convention. Same recommendation as in three sibling audits. + +### 17. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:237-238` +- **Why weird:** `Temporal.Instant` is correct (good!) but the field name `createTime` follows AIP-142 (https://google.aip.dev/142). Compare with `customllms.CustomLlm.creationTime: Temporal.Instant` (audited as inconsistent) — the supervisor-agents package uses the AIP form, the customllms package does not. This is positive consistency on supervisor-agents and negative on customllms. Flagging here because the audit covers SDK-wide consistency. +- **Category:** Observation / 17 (cross-package inconsistency). +- **Suggested name:** Keep `createTime`; flag `customllms` to align. +- **Rationale:** Note positive precedent; pair with the audit on `customllms` to align it. + +### 18. `SupervisorAgent.displayName` doc claims uniqueness — `src/v1/model.ts:225-226` +- **Why weird:** Doc reads "The display name of the Supervisor Agent, unique at workspace level." Display names being unique at workspace level is a *semantic* claim — it might be enforced by the backend (with a 409 response on collision) or it might just be a soft convention. The type signature (`string`) gives no hint. AIP-122 reserves `displayName` for human-readable names that are explicitly *not* unique (https://google.aip.dev/122); a unique name is usually `name` or `id`. So this field is doing double duty: it is human-readable *and* uniquely identifying. Either rename or split. +- **Category:** 6 (misleading — `displayName` implies non-unique). +- **Suggested name:** If the uniqueness is enforced: rename to `key` or `humanReadableId` to communicate the uniqueness contract. If it is convention only: keep the name but soften the JSDoc. +- **Rationale:** A field whose contract contradicts its conventional meaning is a footgun. + +### 19. `SupervisorAgent.description` "user-facing" annotation — `src/v1/model.ts:227-228` +- **Why weird:** Doc reads "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Same observation flagged in `knowledgeassistants.md` #42. The same parenthetical appears on `Tool.description` (model.ts:298-299). +- **Category:** Observation / 17 (inconsistent JSDoc style across SDK). +- **Suggested name:** Drop "(user-facing)" from the two sites; flag for cross-package style review. +- **Rationale:** Minor; cosmetic but worth aligning. + +### 20. `SupervisorAgent.instructions` vs `Example.guidelines` — same overlap as flagged in `customllms.md` and `knowledgeassistants.md` — `src/v1/model.ts:229-230,91-92` +- **Why weird:** `SupervisorAgent.instructions: string` (single, global) and `Example.guidelines: string[]` (array, per-example) follow the exact same naming doublet as `customllms.CustomLlm.instructions`/`guidelines` and `knowledgeassistants.KnowledgeAssistant.instructions`/`Example.guidelines`. Three packages, three near-identical confusing field-name pairs. The naming pattern is now SDK-wide. +- **Category:** 6 (misleading), 12 (duplicate concept across SDK), 15 (generic field name). +- **Suggested name:** Rename `SupervisorAgent.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerGuidelines` or `responseRules`. Apply uniformly across all three packages. +- **Rationale:** Three packages flagged independently for the same pattern. SDK-wide cleanup opportunity. + +### 21. `Tool.description` "user-facing" repeated annotation — `src/v1/model.ts:298-299` +- **Why weird:** Same as #19; the `Tool.description` has the same "(user-facing)" parenthetical. The doc reads "Description of what this tool does (user-facing)." If the audit prompt cares about consistency, both descriptions should match. +- **Category:** Observation / 17. +- **Suggested name:** Same as #19. + +### 22. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:300-301` +- **Why weird:** Doc reads "User specified id of the Tool." Comparing with `CreateToolRequest.toolId` (model.ts:48-51, "The ID to use for the tool, which will become the final component of the tool's resource name."), the two `toolId` fields are *the same wire concept* — but on `Tool` it is the persisted id, while on `CreateToolRequest` it is the request-time supplied id. The same field name is doing two semantic jobs depending on context. Plus, comparing with `Example.exampleId` (model.ts:93-94, "The universally unique identifier (UUID) of the example."), the format claim differs: `Tool.toolId` is *user-specified*, `Example.exampleId` is a *UUID*. The two id formats are not aligned across sibling types in the same package. +- **Category:** 17 (inconsistency across sibling types), 6 (misleading — different format claims). +- **Suggested name:** Keep `toolId` and `exampleId` but expand the JSDoc on each to disambiguate the id-format contract. Or rename `Tool.toolId` → `toolKey` to mirror that it is a user-supplied identifier (as opposed to a server-generated UUID). +- **Rationale:** A naming audit must flag fields whose format contract is silent in the type signature. + +### 23. `SupervisorAgent.supervisorAgentId` vs `SupervisorAgent.id` (deprecated) — both UUIDs — `src/v1/model.ts:231-234` +- **Why weird:** Two id fields on `SupervisorAgent`: the deprecated `id` and the canonical `supervisorAgentId`. Both are `string`, both UUIDs per the doc on line 233 ("The universally unique identifier (UUID) of the Supervisor Agent."). The deprecation is in JSDoc only (no `@deprecated` tag — see #10). Same situation on `Tool.id` vs `Tool.toolId` (model.ts:257-258, 300-301). Carrying the deprecated alias on the type forces consumers to handle both; the SDK should pick one. +- **Category:** 8 (redundant alias suffix), 12 (duplicate concept within the same type). +- **Suggested name:** Mark `id` `@deprecated`; document that `supervisorAgentId` is canonical. Future major version removes `id` entirely. +- **Rationale:** Carrying a deprecated alias on a TS type is a tax on every reader. Mark it loudly. + +### 24. `SupervisorAgent.supervisorAgentId` type-suffix tautology — `src/v1/model.ts:233-234` +- **Why weird:** `SupervisorAgent.supervisorAgentId` repeats `SupervisorAgent` in the type name and field. The pattern is correct AIP-style (every entity has `*Id` matching its type) but extremely verbose. Once `SupervisorAgent` is renamed to `RouterAgent` (per #1), the field becomes `routerAgentId` — slightly shorter, still type-tautological. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** Keep current (tradeoff with cross-type disambiguation), but document the convention in `typescript.mdc`. +- **Rationale:** This is a convention question, not a bug. The verbose form *does* disambiguate from `Tool.toolId` and `Example.exampleId` when passed to a generic function. Flagged for awareness. + +### 25. `Example.exampleId` type-suffix tautology — `src/v1/model.ts:93-94` +- **Why weird:** Same shape as #24, but the field is `exampleId` and the type is `Example`. The redundancy is identical. Note: every sibling SDK package follows the same convention (`knowledgeassistants.Example.exampleId` is the same pattern). +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** Keep current; document the convention. + +### 26. `Tool.toolId` type-suffix tautology — `src/v1/model.ts:300-301` +- **Why weird:** Same pattern as #24, #25. +- **Category:** 20. +- **Suggested name:** Keep current; document the convention. + +### 27. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:48-51` +- **Why weird:** The create request takes both `tool: Tool` (the body) *and* `toolId: string` (the URL/query param). The wire form is `POST /supervisor-agents/{id}/tools?tool_id={user-supplied}`. So `req.toolId` flows into the query string and `req.tool.toolId` is *not used* on creation — but TypeScript does not enforce this. A consumer who writes `{tool: {toolId: 'foo'}}` and leaves `req.toolId` undefined gets unexpected behavior. The two-fields-for-one-concept pattern is also documented in `customllms.md` #20. +- **Category:** 12 (duplicate concept on the same request), 6 (misleading — `tool.toolId` looks usable on creation but isn't), 17. +- **Suggested name:** Either remove `tool.toolId` from the body shape (TypeScript can enforce this via a discriminated `Omit` type for create), or document the precedence rule on the JSDoc. +- **Rationale:** Generated request types with duplicate fields are a well-known footgun. + +### 28. `unmarshal*Schema` and `marshal*Schema` `Schema` suffix — `src/v1/model.ts:378,386,394,408,416,427,435,446,459,469,477,485,514,523,612,620,628,636,646,654,656,664,672,686,694,704,712,720,728,757,765,867,875,883,891,901,909` +- **Why weird:** All marshal/unmarshal Zod schemas suffix `*Schema`. Same pattern documented in `knowledgeassistants.md` #28: every export reads `unmarshalXSchema`, which is 20+ characters of pure suffix. SDK-wide convention; flagging for cross-cutting review rather than local fix. Total of ~37 marshal/unmarshal sites in this file. +- **Category:** 7 (overly verbose), 8 (redundant suffix). +- **Suggested name:** `unmarshalSupervisorAgent` (Zod schemas are obviously schemas; the suffix is type-system redundancy). Flagged for SDK-wide convention review. +- **Rationale:** Cross-package convention; no local fix. + +### 29. `*FieldMaskSchema` private constants and `*FieldMask` public builder — `src/v1/model.ts:911-1042` +- **Why weird:** Two parallel naming families: + - Private (file-scope) constants: `appFieldMaskSchema`, `catalogFieldMaskSchema`, `exampleFieldMaskSchema`, `genieSpaceFieldMaskSchema`, `knowledgeAssistantFieldMaskSchema`, `lakeviewDashboardFieldMaskSchema`, `schemaFieldMaskSchema`, `servingEndpointFieldMaskSchema`, `supervisorAgentFieldMaskSchema`, `supervisorAgentToolFieldMaskSchema`, `toolFieldMaskSchema`, `ucConnectionFieldMaskSchema`, `ucFunctionFieldMaskSchema`, `ucTableFieldMaskSchema`, `vectorSearchIndexFieldMaskSchema`, `volumeFieldMaskSchema`, `webSearchFieldMaskSchema`. + - Public builders: `exampleFieldMask`, `supervisorAgentFieldMask`, `toolFieldMask`. + Only three types get a builder (`Example`, `SupervisorAgent`, `Tool`) — the others are private. But the convention puts `Schema` as the suffix on the constants and bare on the builder, which is the opposite of the `unmarshalXSchema` convention. Also: every field-mask constant exists *whether or not* the type is exposed via a builder — so for tool spec variants the field-mask schema is dead weight. +- **Category:** 7 (verbose), 8 (suffix), 17. +- **Suggested name:** Drop the `Schema` suffix from the private constants (`appFieldMask`, `catalogFieldMask`, etc., with the builders renamed to `buildAppFieldMask`, `buildToolFieldMask`). +- **Rationale:** Cross-package convention; no local fix. + +### 30. `listExamplesIter`/`listSupervisorAgentsIter`/`listToolsIter` — `Iter` suffix Go-style — `src/v1/client.ts:342,396,447` +- **Why weird:** The `Iter` suffix on async iterators is a direct port from Go's `*Iter` convention, same as `knowledgeassistants.md` #29 and applies SDK-wide. The audit prompt's rule 14 (Go/Java-style names) calls this out. +- **Category:** 14 (Go-style name), 8 (redundant suffix — return type already says it's an iterator). +- **Suggested name:** Drop the suffix and make auto-paging the default (`listExamples` returns an `AsyncIterable`, and a separate `listExamplesPage` returns one page). Or swap the names: `listExamples` (current paged) becomes `listExamplesPage`, and `listExamplesIter` becomes `listExamples`. +- **Rationale:** Modern TypeScript convention is that the default form is auto-paging; the suffix is a Go/Java carryover. + +### 31. `Client` class name — bare, no scoping — `src/v1/client.ts:61` +- **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-supervisoragents/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as SAClient} from '@databricks/sdk-supervisoragents/v1'`. Same SDK-wide issue flagged in `knowledgeassistants.md` #30. +- **Category:** 1 (vague), 17 (SDK-wide inconsistency). +- **Suggested name:** `SupervisorAgentsClient` (matches the Go SDK's `WorkspaceClient.SupervisorAgents` and AWS SDK's `S3Client`, `IAMClient` pattern). +- **Rationale:** Bare `Client` is convenient until you import two SDK packages; then it's a tax. + +## Low severity + +### 32. `Volume`/`UcFunction`/`UcConnection`/`UcTable` — `Uc` prefix on some, bare on others — `src/v1/model.ts:304,308,318,364` +- **Why weird:** Of the variant types, four are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`, `UcTable`. The `Uc` prefix is applied to three but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). +- **Category:** 3 (acronym casing — `Uc` vs `UC`), 17 (inconsistent prefix application — `Volume` should be `UcVolume`). +- **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection`, `UcTable` (with the acronym-casing question decided once SDK-wide). +- **Rationale:** Consistency wins; the audit prompt rule 3 (acronym casing) and rule 17 (consistent action verbs / family naming) both flag this. + +### 33. `LakeviewDashboard` — product name leaks into type name — `src/v1/model.ts:135` +- **Why weird:** "Lakeview" is the marketing name for Databricks SQL dashboards (https://docs.databricks.com/en/dashboards/index.html). The type name carries the product name. If the product is renamed (as has happened — "Lakeview" has been deprecated in some Databricks branding in favor of "Dashboards"), the SDK will be stuck with the old name. Cross-package: the dashboards SDK at `packages/dashboards/` uses `LakeviewDashboard` too — so the SDK is consistent, but the question is whether the canonical name should propagate. +- **Category:** Observation / 6 (potentially misleading if product is rebranded). +- **Suggested name:** Keep `LakeviewDashboard` (the wire name is fixed) but document the marketing-name origin. +- **Rationale:** Naming audits should flag product-name leakage even if there's no fix. + +### 34. `Catalog`, `Schema`, `UcTable` fields all named `name` but doc differently — `src/v1/model.ts:21,212,321` +- **Why weird:** Three variant types with a single `name` field carrying three subtly different format claims: + - `Catalog.name`: "Bare UC catalog name this tool is authorized to search (no `.`)." — one component. + - `Schema.name`: "Full UC schema name (catalog.schema) this tool is authorized to search." — two components. + - `UcTable.name`: "Full UC table name (catalog.schema.table) this tool is authorized to access." — three components. + Three sibling types use the same field name `name` to mean three different cardinalities (1-, 2-, 3-part UC names). A consumer scripting "set the tool name from a user input" gets no compiler help. +- **Category:** 15 (generic field name losing meaning), 6 (misleading — same name, different format), 17. +- **Suggested name:** Differentiate: `Catalog.catalogName` (one part), `Schema.schemaFullName` (two parts), `UcTable.tableFullName` (three parts). Or use AIP-style `fullName` on each but document the cardinality explicitly. +- **Rationale:** Three types with the same field name representing different formats is exactly the kind of inconsistency that bites at code-review time. + +### 35. `VectorSearchIndex.columns` semantic ambiguity — `src/v1/model.ts:357-361` +- **Why weird:** Doc reads "Optional columns to return from the index. If unset, discovered from index schema at query time." So `columns` is a list of column names to *project* in the response — but the field name does not communicate "to return" vs "to filter on" vs "to embed." A consumer scanning the type sees `columns?: string[]` and reasonably wonders whether these are the *output* columns or the *input* columns to vectorize. The doc is the only disambiguator. +- **Category:** 1 (vague), 6 (misleading — name does not encode return-vs-filter direction). +- **Suggested name:** `returnedColumns` or `outputColumns` (or `projection`, a SQL term). +- **Rationale:** The doc gives the contract; the field name should too. + +### 36. `parseResponse` / `marshalRequest` asymmetric verbs — `src/v1/utils.ts:113,119` +- **Why weird:** Same as `customllms.md` #22 and `knowledgeassistants.md` #33: `parseResponse` and `marshalRequest` use two different verbs for inverse operations. The model file uses `unmarshal*Schema` / `marshal*Schema` consistently, but `utils.ts` breaks the pattern with `parse`. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry. +- **Rationale:** Pair-wise consistency aids reading. + +### 37. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21 and `knowledgeassistants.md` #34. Each generated package carries the same pair. +- **Category:** 1 (vague), 17 (inconsistency). +- **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. +- **Rationale:** Names should differ in more than one infix. + +### 38. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +- **Why weird:** Same as `customllms.md` #23 and `knowledgeassistants.md` #35: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in scope simultaneously. Three things named `Options`. +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` or `HttpCallParams`. +- **Rationale:** Distinguish internal context bags from user-facing options. + +### 39. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Same as `customllms.md` #28 and `knowledgeassistants.md` #36: exported but not used by `client.ts`. Generator-mechanical surface area. +- **Category:** Observation / (unused export). +- **Suggested name:** Either remove the export or document why it ships per-package. +- **Rationale:** Generated artifact; flag for cross-package cleanup. + +### 40. `readAll` helper generic name — `src/v1/utils.ts:40` +- **Why weird:** Same as `customllms.md` #29 and `knowledgeassistants.md` #37: helper reads an entire response body stream; name is generic. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` or `readStreamToEnd`. +- **Rationale:** Internal helper, low cost. Skip if generated. + +### 41. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` +- **Why weird:** Same as `customllms.md` #24 and `knowledgeassistants.md` #38: `Segment` is a generic CS term. +- **Category:** 1 (vague). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** SDK-wide consistency review. + +### 42. `resp` local variable in every method — `src/v1/client.ts:93,122,154,242,267,289,323,374,428,477,521,562` +- **Why weird:** Same as `customllms.md` #33 and `knowledgeassistants.md` #39: `resp` is the response. 12 methods repeat the same pattern. +- **Category:** 12 (duplicate pattern). +- **Suggested name:** Refactor away the pattern, not the name. +- **Rationale:** Refactor opportunity surfaced by audit. + +## Observations + +### 43. `pageReq` local in iterator methods — `src/v1/client.ts:346,400,451` +- **Why weird:** Same as `knowledgeassistants.md` #40: three async generator methods declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. +- **Category:** 5 (abbreviation). +- **Suggested name:** `pageRequest` or `nextPageReq`. + +### 44. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:977-1015` +- **Why weird:** `toolFieldMaskSchema` carries top-level entries for each variant of the `spec` union — `app`, `catalog`, `genieSpace`, `knowledgeAssistant`, `lakeviewDashboard`, `schema`, `servingEndpoint`, `supervisorAgent`, `ucConnection`, `ucFunction`, `ucTable`, `vectorSearchIndex`, `volume`, `webSearch`. The field-mask schema flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. +- **Category:** 17 (inconsistency between TS shape and field-mask schema). +- **Suggested name:** No rename; document on the JSDoc. + +### 45. The 14 tool kinds + 1 nested = effectively 15 kinds — `src/v1/model.ts:262-297` +- **Why weird:** The doc on `Tool.toolType` (model.ts:259) lists 14 kinds, but the discriminated union on `Tool.spec` (model.ts:262-297) also has 14 cases. Counting carefully: `genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `lakeviewDashboard`, `servingEndpoint`, `ucTable`, `vectorSearchIndex`, `ucConnection`, `catalog`, `schema`, `supervisorAgent`, `webSearch` — that is 14, and matches the doc. So the count is correct; flagged here as a *positive* observation. + +### 46. `unmarshalToolSchema` deep ternary chain — `src/v1/model.ts:557-607` +- **Why weird:** The unmarshal logic for `Tool.spec` is a 50-line nested ternary picking which variant case applies. Not a naming issue; flagging because the readability of generated code at this depth is hostile. +- **Category:** Observation. + +### 47. `marshalToolSchema` discriminated union explicit `$case` literals — `src/v1/model.ts:765-828` +- **Why weird:** The marshal-side Zod schema enumerates each `$case` as a string literal in `z.discriminatedUnion('$case', [...])`. The 14 explicit `z.literal('genieSpace')` etc. lines duplicate the data already in the unmarshal-side ternary chain. Not a naming bug; flagging for codegen review. +- **Category:** Observation. + +### 48. Action verbs in `Client` are consistent — `src/v1/client.ts` +- **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. +- **Category:** 17 (reversed — consistency note). + +### 49. Method-name verb conventions match resource targets — `src/v1/client.ts:87,113,142,180,199,218,237,262,287,309,360,414,465,506,550` +- **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. +- **Category:** 17 (positive observation). + +## Domain glossary +- `supervisor agent` — the LLM router resource that orchestrates calls to tools (sub-agents). The package name and primary resource. Per the audit's prompt: `Supervisor + Agent` together describe "a top-level routing agent that delegates user requests to specialized child tools." Each agent has a serving endpoint and an MLflow experiment. +- `tool` — a typed reference to another Databricks resource (or a built-in capability like web search) that the supervisor agent can invoke. 14 kinds via `Tool.spec` discriminated union. +- `example` — a question + guidelines pair that steers the agent's response on similar questions. Sub-resource of a supervisor agent. +- `uc` — Unity Catalog. Used as a prefix for four variant types (`UcFunction`, `UcConnection`, `UcTable`) and referenced in doc strings for `Catalog`, `Schema`, `Volume`, `VectorSearchIndex`. +- `genie` — Databricks Genie, the AI-driven analytics product. `GenieSpace` is the container resource. +- `lakeview` — the historical name for Databricks SQL Dashboards. `LakeviewDashboard` carries the product name. +- `asset_search` — a UC permission scope (per `Catalog` / `Schema` doc strings): a search capability over catalogs/schemas. +- `mcp` — Model Context Protocol (referenced in `App` doc "Supported app: custom mcp, custom agent."). MCP servers can be deployed as Databricks Apps. + +## File coverage +- `src/v1/model.ts` (1043 lines): read fully. +- `src/v1/client.ts` (587 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (44 lines): read fully. diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md new file mode 100644 index 00000000..b5fa27a3 --- /dev/null +++ b/.agent/naming-audit/systemschemas.md @@ -0,0 +1,189 @@ +# Naming Audit: systemschemas + +**Path:** `packages/systemschemas/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. +**Total weird names flagged:** 27 + +## Summary +| Severity | Count | +| --- | --- | +| High | 9 | +| Medium | 9 | +| Low | 5 | +| Observation | 4 | + +## High severity + +### 1. Package name `systemschemas` collides with the sibling `schemas` package — `packages/systemschemas/` vs `packages/schemas/` +- **Why weird:** Two top-level packages for closely related Unity Catalog concepts: `schemas` (user-defined schemas: full CRUD with `CreateSchema`, `DeleteSchema`, etc.) and `systemschemas` (server-managed schemas: only enable/disable/list). A consumer searching `npm ls @databricks/sdk-*` sees two near-identical names; an import alias of `schemas` from either package shadows the other. +- **Category:** 12 (duplicate concept across packages). +- **Suggested name:** Either fold `systemschemas` into `schemas` as a `system` sub-namespace (`@databricks/sdk-schemas/system`), or rename to something less collision-prone such as `unityCatalogSystemSchemas` / `metastoreSystemSchemas`. +- **Rationale:** The two packages export different `Client` classes; the domain word `Schema` appears in both with overlapping vocabulary. Anything that lessens that overlap — even just keeping them under one package — would reduce caller confusion. + +### 2. `DisableSystemSchema` — `src/v1/model.ts:5` +- **Why weird:** Type name is a verb phrase that looks like a function. The same broken pattern is repeated for `EnableSystemSchema` (model.ts:15) and `ListSystemSchemas` (model.ts:27). Index re-exports these as types, so consumers write `import type {DisableSystemSchema}` which reads as "import a function". +- **Category:** 6 (misleading: name implies behaviour, actually a request DTO), 14 (Go-style naming). +- **Suggested name:** `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, `ListSystemSchemasRequest`. +- **Rationale:** TS convention names request DTOs with a `Request` suffix; verb-phrase nouns mislead. This mirrors the same audit finding in every other generated package. + +### 3. `DisableSystemSchema_Response` — `src/v1/model.ts:13` +- **Why weird:** Underscore in identifier (proto-style nested type). Requires `@typescript-eslint/naming-convention` to be disabled. +- **Category:** 4 (underscores in TS identifiers). +- **Suggested name:** `DisableSystemSchemaResponse`. +- **Rationale:** TS strict-type-checked flags the underscore; the disable means the name is fighting the language. + +### 4. `EnableSystemSchema_Response` — `src/v1/model.ts:25` +- **Why weird:** Same as #3 — underscore identifier requiring `eslint-disable`. +- **Category:** 4. +- **Suggested name:** `EnableSystemSchemaResponse`. +- **Rationale:** Identical to #3. + +### 5. `ListSystemSchemas_Response` — `src/v1/model.ts:43` +- **Why weird:** Underscore identifier (proto-style nested type). Requires `eslint-disable` for `@typescript-eslint/naming-convention`. +- **Category:** 4 (underscores in TS identifiers). +- **Suggested name:** `ListSystemSchemasResponse`. +- **Rationale:** Same as the other two `_Response` types; underscore is a proto leak that does not survive TS lint without a disable. + +### 6. `SystemSchemaInfo` — `src/v1/model.ts:53` +- **Why weird:** `Info` is a generic, content-free suffix on the package's central domain entity. This is *the* system schema — it should just be `SystemSchema`. The `Info` suffix is on the vague-suffix list in `typescript.mdc`. It also infects the field name (`schemas: SystemSchemaInfo[]`) which awkwardly reads as "an array of info". +- **Category:** 1 (vague `Info`), 8 (redundant type suffix). +- **Suggested name:** `SystemSchema`. +- **Rationale:** `SystemSchema` is the noun consumers think about. `schemas: SystemSchema[]` reads cleanly; `schemas: SystemSchemaInfo[]` does not. + +### 7. `SystemSchemaInfo.state: string` — `src/v1/model.ts:60` +- **Why weird:** Typed as `string` despite the doc enumerating six concrete values (`AVAILABLE | ENABLE_INITIALIZED | ENABLE_COMPLETED | DISABLE_INITIALIZED | UNAVAILABLE | MANAGED`). This is the package's only enum-shaped field and the only piece of state the consumer reads back, yet it ships as a stringly-typed value. Every other package in the SDK exposes such fields as TS enums. The comment "An empty string means the system schema is available and ready for opt-in" further muddles things — it contradicts `AVAILABLE` being one of the listed values. +- **Category:** 16 (field type contradicts the documented domain), 6 (misleading — doc says enum, type says `string`). +- **Suggested name:** Introduce `SystemSchemaState` enum with members `Available | EnableInitialized | EnableCompleted | DisableInitialized | Unavailable | Managed` and type the field `state: SystemSchemaState`. +- **Rationale:** Almost certainly a generator/upstream-API miss; the wire surface is enum-shaped and should round-trip through a TS enum. Worth raising upstream. + +### 8. `EnableSystemSchema.catalogName` lowercase doc-prefix — `src/v1/model.ts:20-21` +- **Why weird:** JSDoc on `catalogName` reads `the catalog for which the system schema is to enabled in` — both grammatically broken ("to enabled" instead of "to be enabled") *and* starts with a lowercase letter, unlike every other field's doc in the file. Naming-adjacent because the doc is the only place that explains what `catalogName` means versus `metastoreId`. +- **Category:** Observation / 15 (the field name `catalogName` is generic in a struct that also carries `metastoreId` and `schema`; doc carries the disambiguation burden). +- **Suggested name:** Keep `catalogName` (it's correct) but rewrite the doc to a proper sentence: "Name of the catalog in which the system schema should be enabled." +- **Rationale:** Naming includes the docstring; a broken doc on the only field that distinguishes `EnableSystemSchema` from `DisableSystemSchema` is a meaningful naming-quality issue. + +### 9. `schema` field on every request/response — `src/v1/model.ts:7,17,55` +- **Why weird:** Field is bare `schema: string` on `DisableSystemSchema`, `EnableSystemSchema`, and `SystemSchemaInfo`. Doc on the first two says "Full name of the system schema" while the doc on `SystemSchemaInfo` (model.ts:54) says "Name of the system schema". So the same field name carries two different semantics (full-qualified vs short name) across two types that ship in the same module. Also collides with the type name (`SystemSchema`) and the package name (`systemschemas`), making greps unhelpful. +- **Category:** 1 (vague — what kind of "schema"?), 6 (misleading — same field name, different meaning), 19 (underspecified id). +- **Suggested name:** Pick one of `schemaName` / `systemSchemaName` / `name` and apply it consistently. If the wire is `schema` (string), keep the wire and rename the TS surface; the marshaller already handles the gap for other fields. +- **Rationale:** The URL template `.../systemschemas/${req.schema ?? ''}` (client.ts:75) confirms `schema` is in fact an identifier slug. Calling it `schemaName` or `name` makes intent obvious; bare `schema` collides with everything. + +## Medium severity + +### 10. `DisableSystemSchema.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` +- **Why weird:** Marked optional, but `client.ts:75` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchema.metastoreId`, `DisableSystemSchema.schema`, `EnableSystemSchema.schema`, `ListSystemSchemas.metastoreId`. +- **Category:** 6 (misleading optionality), 16 (field type contradicts domain — these are mandatory path params). +- **Suggested name:** Keep names; change type to non-optional. (Out of scope for a *naming* audit, but the optionality leaks into how the names should be interpreted.) +- **Rationale:** Path-required fields must be required. Treating them as optional weakens the contract; the name `metastoreId` reads as "the metastore id" but the type says "you can omit this". + +### 11. `SystemSchemaInfo.schema: string` (required) vs `EnableSystemSchema.schema: string | undefined` (optional) — `src/v1/model.ts:55,17` +- **Why weird:** Same field name, opposite optionality, same module. The reader has to keep two mental versions of `schema` in their head. +- **Category:** 17 (inconsistency in field shape between sibling types). +- **Suggested name:** Same as #9 — rename one or both and unify optionality where possible. +- **Rationale:** Symmetry across request/response pairs improves readability; identical names with diverging contracts do not. + +### 12. `marshalEnableSystemSchemaSchema` constant — `src/v1/model.ts:95` +- **Why weird:** Double `Schema` suffix: it's a zod **Schema** that marshals the `EnableSystemSchema` request. Reads as `marshal-EnableSystemSchema-Schema`. Same problem with `unmarshalSystemSchemaInfoSchema` (model.ts:85), `unmarshalListSystemSchemas_ResponseSchema` (model.ts:72), etc. — every zod schema constant carries the word `Schema` *and* sits in a file already named for `SystemSchema`, leading to three nested meanings of "schema": the domain entity, the request type, and the zod validator. +- **Category:** 17 (verb/word reuse), 20 (type-suffix tautology — the zod object is already a schema, no need to spell it). +- **Suggested name:** Drop the trailing `Schema` and adopt a clearer suffix: `marshalEnableSystemSchemaCodec`, or move them to a `codecs.ts` namespace that supplies the `Schema` semantics by location. +- **Rationale:** The "schema" overload is unique to this package — most other generated packages have a single `Schema` meaning (zod). Here all three collide. + +### 13. `marshalEnableSystemSchemaSchema: z.ZodType` lacks a type parameter — `src/v1/model.ts:95` +- **Why weird:** Declared as `z.ZodType` (no generic argument), unlike the sibling `unmarshalSystemSchemaInfoSchema: z.ZodType` (model.ts:85). The marshalled output is therefore typed as `unknown` and the `parse` call on it loses static guarantees. +- **Category:** 17 (inconsistency with sibling exports), 6 (misleading — looks just like the unmarshal helpers but is weaker). +- **Suggested name:** Either rename to clarify the asymmetry, or fix the signature to `z.ZodType` (or to the wire-shape type). Not strictly a naming finding, but the name implies parity that isn't there. +- **Rationale:** Mechanical fallout from the marshal/unmarshal verb split (#21). + +### 14. `listSystemSchemas` vs `listSystemSchemasIter` — `src/v1/client.ts:139,172` +- **Why weird:** `Iter` is a Go-SDK loanword (`...Iterator`). TS convention is to name an iterator after what it yields or to use a verb like `iterate`. The current pair names a page-fetching method and a streaming method with a three-letter abbreviation tacked on, making the difference at the call site (`client.listSystemSchemas` vs `client.listSystemSchemasIter`) inscrutable. +- **Category:** 5 (cryptic abbreviation), 14 (Go-style naming). +- **Suggested name:** `iterSystemSchemas` (verb-first), `listAllSystemSchemas`, or split into `listSystemSchemasPage` (current `list...`) and `listSystemSchemas` (current `list...Iter`). +- **Rationale:** Async generators are common enough in TS that the language has its own conventions (`for await (const x of obj.foos())`); naming the generator with the visible "stream" verb communicates better than `Iter`. + +### 15. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` +- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate intent. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Minor; flagged for cross-SDK consistency since the same constant appears in every generated client. + +### 16. `Client` — `src/v1/client.ts:42` +- **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `SystemSchemasClient`. +- **Rationale:** Forces consumers to alias on import (`import {Client as SystemSchemasClient}`) if they ever combine clients. Every generated package has this issue; flagged for consistency. + +### 17. `ListSystemSchemas.maxResults` doc semantics — `src/v1/model.ts:31-36` +- **Why weird:** Field is named `maxResults` but the doc describes three semantically distinct modes (0 = server default, >0 = bounded, <0 = error) and one quirky default (not set = "all", "not recommended"). The name "maxResults" implies an upper bound, not a tri-state control. Same pattern in every other List request, but here the doc highlights how overloaded the name is. +- **Category:** 6 (misleading — name suggests a single integer cap), 1 (vague). +- **Suggested name:** `pageSize` (matching most modern paginated APIs) and let the value 0 mean "server default". Drop the negative-error branch entirely. +- **Rationale:** Worth raising upstream; the JS SDK's name should describe what consumers do, not the wire's quirks. + +### 18. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:182` +- **Why weird:** `listSystemSchemasIter` (client.ts:182) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. +- **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). +- **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. +- **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. + +## Low severity + +### 19. `unmarshalDisableSystemSchema_ResponseSchema` — `src/v1/model.ts:64` +- **Why weird:** Schema constant carries the underscore from the type plus an `eslint-disable`. +- **Category:** 4 (underscore identifier). +- **Suggested name:** Falls out once `DisableSystemSchema_Response` is renamed (#3): `unmarshalDisableSystemSchemaResponseSchema` — though `Schema` triple-tautology (#12) still applies. +- **Rationale:** Mechanical cascade. + +### 20. `unmarshalEnableSystemSchema_ResponseSchema` — `src/v1/model.ts:68` +- **Why weird:** Same as #19. +- **Category:** 4. +- **Suggested name:** Cascade from #4. +- **Rationale:** Same. + +### 21. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (effectively unmarshal) is the inverse of `marshalRequest`. Two different verbs (`parse` vs `marshal`) for opposite operations. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. +- **Rationale:** Pair-wise consistency aids reading. Same finding shows up in every generated `utils.ts`. + +### 22. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions whose names differ by a single `Http` infix, handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). +- **Category:** 1 (vague), 17 (inconsistent). +- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). +- **Rationale:** Same pattern across the SDK; collected for the cross-package sweep. + +### 23. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** The word `Options` is reused across the SDK for many unrelated things (`ClientOptions`, `CallOptions`, etc.); within this file `Options` is also imported from `@databricks/sdk-core/api` (line 3). +- **Category:** 1 (vague suffix), 17 (collision with imported `Options`). +- **Suggested name:** `HttpCallContext` — it's an internal bag of args, not user-tunable options. +- **Rationale:** Distinguish internal context bags from user-tunable option structs. + +## Observations + +### 24. `flattenQueryParams` — `src/v1/utils.ts:123` +Function is exported but has no caller within this package — `client.ts` does its own simple query-param assembly (`client.ts:144-150`). Dead surface area imported from the generator's shared template. +- **Category:** Observation / 11 (unused public helper). +- Recommend either removing the export or documenting why it ships per-package. + +### 25. `readAll` — `src/v1/utils.ts:40` +Reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Internal helper, low impact. + +### 26. Action-verb consistency in `Client` +Methods are `disable`, `enable`, `list`, `listSystemSchemasIter` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. + +### 27. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod +The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), a type suffix (`...Schema_Response`), the package name (`systemschemas`), and a library term (zod's `Schema`). Five overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. +- **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). + +## Domain glossary +- `metastore` — Unity Catalog metastore (container that owns catalogs/schemas). +- `system schema` — curated, Databricks-managed schema (e.g. `access`, `billing`, `lineage`) attached to a metastore via opt-in enablement. +- `catalog` — Unity Catalog catalog; the namespace that the enabled system schema appears under. +- `state` (enum-shaped string field): `AVAILABLE`, `ENABLE_INITIALIZED`, `ENABLE_COMPLETED`, `DISABLE_INITIALIZED`, `UNAVAILABLE`, `MANAGED` — undocumented externally; the source comment in `model.ts:57-58` is the only place these values are listed. +- `uc` — Unity Catalog (appears in URL paths only: `/api/2.1/unity-catalog/...`). +- `abac` / `oss` / `m2m` / `u2m` / `pat` / `wkt` — not encountered in this package. + +## File coverage +- `src/v1/model.ts` (106 lines): read fully. +- `src/v1/client.ts` (188 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md new file mode 100644 index 00000000..47a51326 --- /dev/null +++ b/.agent/naming-audit/tables.md @@ -0,0 +1,1658 @@ +# Naming Audit: `tables` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/tables/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts` +**Package import path:** `@databricks/sdk-tables/v1` +**Domain:** Unity Catalog tables (`/api/2.1/unity-catalog/tables`, +`/api/2.1/unity-catalog/constraints`, `/api/2.1/unity-catalog/table-summaries`). + +**Cross-package references:** + +- `catalogs/v1`, `connections/v1` — also export `SecurableType`. +- `volumes/v1`, `externallocations/v1` — also export `EncryptionDetails`, + `SseEncryptionAlgorithm`, `SseEncryptionDetails`. +- `catalogs/v1` — also defines `EffectivePredictiveOptimizationFlag`. +- `functions/v1`, `registeredmodels/v1` — also define the entire + `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / + `ConnectionDependency` / `CredentialDependency` / `VolumeDependency` / + `SecretDependency` family. +- `functions/v1` — also exports `ColumnTypeName`. +- `abacpolicies/v1` — defines `RowFilterOptions` / `ColumnMaskOptions` which + duplicate the role of this package's `RowFilter` / `ColumnMask`. +- `schemas/v1`, `functions/v1`, `registeredmodels/v1` — also use the + `fullNameArg` request-field pattern. +- `onlinetables/v1`, `database/v1`, `postgres/v1`, `featurestore/v1` — also + use the table-name modelling and the `MATERIALIZED_VIEW` / + `STREAMING_TABLE` / `MANAGED` lifecycle vocabulary. + +**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). + +--- + +## Inventory + +### Enums (model.ts) + +1. `ColumnTypeName` (model.ts:5) — 27 values: `BOOLEAN`, `BYTE`, `SHORT`, + `INT`, `LONG`, `FLOAT`, `DOUBLE`, `DATE`, `TIMESTAMP`, `STRING`, `BINARY`, + `DECIMAL`, `INTERVAL`, `ARRAY`, `STRUCT`, `MAP`, `CHAR`, `NULL`, + `USER_DEFINED_TYPE`, `TIMESTAMP_NTZ`, `VARIANT`, `GEOMETRY`, `GEOGRAPHY`, + `TIME`, `FILE`, `TABLE_TYPE`, `TABLEREF_TYPE`. +2. `DataSourceFormat` (model.ts:36) — 26 values, most suffixed `_FORMAT`: + `DELTA`, `CSV`, `JSON`, `AVRO`, `PARQUET`, `ORC`, `TEXT`, `UNITY_CATALOG`, + `DELTASHARING`, `DATABRICKS_FORMAT`, `MYSQL_FORMAT`, `ORACLE_FORMAT`, + `POSTGRESQL_FORMAT`, `REDSHIFT_FORMAT`, `SNOWFLAKE_FORMAT`, `SQLDW_FORMAT`, + `SQLSERVER_FORMAT`, `SALESFORCE_FORMAT`, `SALESFORCE_DATA_CLOUD_FORMAT`, + `TERADATA_FORMAT`, `BIGQUERY_FORMAT`, `NETSUITE_FORMAT`, + `WORKDAY_RAAS_FORMAT`, `MONGODB_FORMAT`, `HIVE`, `VECTOR_INDEX_FORMAT`, + `DATABRICKS_ROW_STORE_FORMAT`, `DELTA_UNIFORM_HUDI`, + `DELTA_UNIFORM_ICEBERG`, `ICEBERG`. +3. `SecurableKind` (model.ts:81) — 70+ values, all prefixed with one of + `TABLE_`, `RECIPIENT_`, `CONNECTION_`, `CATALOG_`, `SCHEMA_`. +4. `SecurableType` (model.ts:182) — 17 values: `CATALOG`, `SCHEMA`, `TABLE`, + `STORAGE_CREDENTIAL`, `EXTERNAL_LOCATION`, `FUNCTION`, `SHARE`, `PROVIDER`, + `RECIPIENT`, `CLEAN_ROOM`, `METASTORE`, `PIPELINE`, `VOLUME`, `CONNECTION`, + `CREDENTIAL`, `EXTERNAL_METADATA`, `STAGING_TABLE`. +5. `SseEncryptionAlgorithm` (model.ts:203) — 3 values: + `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`, `AWS_SSE_S3`, `AWS_SSE_KMS`. +6. `TableType` (model.ts:209) — 9 values: `MANAGED`, `EXTERNAL`, `VIEW`, + `MATERIALIZED_VIEW`, `STREAMING_TABLE`, `MANAGED_SHALLOW_CLONE`, `FOREIGN`, + `EXTERNAL_SHALLOW_CLONE`, `METRIC_VIEW`. +7. `OptionSpec_OauthStage` (model.ts:229) — 3 values: + `OAUTH_STAGE_UNSPECIFIED`, `BEFORE_AUTHORIZATION_CODE`, + `BEFORE_ACCESS_TOKEN`. +8. `OptionSpec_OptionType` (model.ts:242) — 9 values: + `OPTION_TYPE_UNSPECIFIED`, `OPTION_BOOLEAN`, `OPTION_NUMBER`, + `OPTION_BIGINT`, `OPTION_STRING`, `OPTION_ENUM`, + `OPTION_SERVICE_CREDENTIAL`, `OPTION_MULTILINE_STRING`, + `OPTION_STORAGE_CREDENTIAL`. + +### Interfaces (model.ts) + +1. `ColumnInfo` (model.ts:254) — 12 fields (`name`, `typeText`, `typeName`, + `position`, `typePrecision`, `typeScale`, `typeIntervalType`, `typeJson`, + `comment`, `nullable`, `partitionIndex`, `mask`). +2. `ColumnMask` (model.ts:279) — 3 fields. +3. `ConditionalDisplay` (model.ts:305) — 2 fields. +4. `ConnectionDependency` (model.ts:317) — 1 field. +5. `CreateTable` (model.ts:322) — 38 fields. +6. `CreateTable_PropertiesEntry` (model.ts:394) — 2 fields. +7. `CreateTableConstraint` (model.ts:399) — 2 fields. +8. `CredentialDependency` (model.ts:406) — 1 field. +9. `DeleteTable` (model.ts:411) — 1 field. +10. `DeleteTable_Response` (model.ts:417) — empty body. +11. `DeleteTableConstraint` (model.ts:419) — 3 fields. +12. `DeleteTableConstraint_Response` (model.ts:432) — empty body. +13. `DeltaRuntimePropertiesKvPairs` (model.ts:438) — 1 field. +14. `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` + (model.ts:444) — 2 fields. +15. `Dependency` (model.ts:453) — discriminated union (table / function / + connection / credential / volume / secret). +16. `DependencyList` (model.ts:473) — 1 field. +17. `EffectivePredictiveOptimizationFlag` (model.ts:478) — 3 fields. +18. `EncryptionDetails` (model.ts:488) — discriminated union (one variant: + `sseEncryptionDetails`). +19. `ForeignKeyConstraint` (model.ts:498) — 5 fields (`name`, `childColumns`, + `parentTable`, `parentColumns`, `rely`). +20. `FunctionDependency` (model.ts:512) — 1 field. +21. `GetTable` (model.ts:517) — 4 fields. +22. `ListTableSummaries` (model.ts:528) — 6 fields. +23. `ListTableSummaries_Response` (model.ts:556) — 2 fields. +24. `ListTables` (model.ts:566) — 9 fields. +25. `ListTables_Response` (model.ts:594) — 2 fields. +26. `NamedTableConstraint` (model.ts:604) — 1 field. +27. `OptionSpec` (model.ts:614) — 15 fields. +28. `PolicyFunctionArgument` (model.ts:661) — discriminated union (column / + constant). +29. `PrimaryKeyConstraint` (model.ts:676) — 4 fields. +30. `RowFilter` (model.ts:687) — 3 fields. +31. `SecretDependency` (model.ts:704) — 1 field. +32. `SecurableKindManifest` (model.ts:710) — 5 fields. +33. `SseEncryptionDetails` (model.ts:724) — 2 fields. +34. `TableConstraint` (model.ts:738) — discriminated union (primary key / + foreign key / named). +35. `TableDependency` (model.ts:756) — 1 field. +36. `TableExists` (model.ts:761) — 1 field. +37. `TableExists_Response` (model.ts:767) — 1 field (`tableExists`). +38. `TableInfo` (model.ts:772) — 36 fields (duplicates `CreateTable` / + `UpdateTable` field-by-field). +39. `TableInfo_PropertiesEntry` (model.ts:844) — 2 fields. +40. `TableSummary` (model.ts:849) — 3 fields. +41. `UpdateTable` (model.ts:857) — 37 fields (`fullNameArg` + the same set as + `CreateTable`). +42. `UpdateTable_PropertiesEntry` (model.ts:931) — 2 fields. +43. `UpdateTable_Response` (model.ts:937) — empty body. +44. `VolumeDependency` (model.ts:940) — 1 field. + +### Zod schemas (model.ts) + +- Unmarshal: 25 schemas — `unmarshalColumnInfoSchema`, + `unmarshalColumnMaskSchema`, `unmarshalConditionalDisplaySchema`, + `unmarshalConnectionDependencySchema`, `unmarshalCredentialDependencySchema`, + `unmarshalDeleteTable_ResponseSchema`, + `unmarshalDeleteTableConstraint_ResponseSchema`, + `unmarshalDeltaRuntimePropertiesKvPairsSchema`, `unmarshalDependencySchema`, + `unmarshalDependencyListSchema`, + `unmarshalEffectivePredictiveOptimizationFlagSchema`, + `unmarshalEncryptionDetailsSchema`, `unmarshalForeignKeyConstraintSchema`, + `unmarshalFunctionDependencySchema`, + `unmarshalListTableSummaries_ResponseSchema`, + `unmarshalListTables_ResponseSchema`, + `unmarshalNamedTableConstraintSchema`, `unmarshalOptionSpecSchema`, + `unmarshalPolicyFunctionArgumentSchema`, + `unmarshalPrimaryKeyConstraintSchema`, `unmarshalRowFilterSchema`, + `unmarshalSecretDependencySchema`, `unmarshalSecurableKindManifestSchema`, + `unmarshalSseEncryptionDetailsSchema`, `unmarshalTableConstraintSchema`, + `unmarshalTableDependencySchema`, `unmarshalTableExists_ResponseSchema`, + `unmarshalTableInfoSchema`, `unmarshalTableSummarySchema`, + `unmarshalUpdateTable_ResponseSchema`, `unmarshalVolumeDependencySchema`. +- Marshal: a near-parallel set of `marshal…Schema` symbols (no + `marshalDeleteTable_*` /`marshalGetTableSchema` since requests there have + no body). + +### Client (client.ts) + +- Class `Client` (client.ts:60). +- Public methods: `createTable`, `createTableConstraint`, `deleteTable`, + `deleteTableConstraint`, `getTable`, `listTableSummaries`, + `listTableSummariesIter`, `listTables`, `listTablesIter`, `tableExists`, + `updateTable`. +- Private fields: `host`, `httpClient`, `logger`, `userAgent`. +- Module constant: `PACKAGE_SEGMENT` (client.ts:55). + +### Utils (utils.ts) + +- Interface: `HttpCallOptions`. +- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`. + +### Index (index.ts) + +- Re-exports `Client`, 8 enums (5 flat + 2 underscored — see findings 1 and + 2), and 41 interfaces. + +--- + +## Summary (counts) + +| Severity | Count | +| --------------------- | ----- | +| High | 16 | +| Medium | 26 | +| Low / SDK-wide note | 14 | +| Pass / acceptable | 10 | +| **Total findings** | **66** | + +(Findings often span multiple audit categories; counts above are unique +findings.) + +--- + +## Findings + +### 1. `OptionSpec_OauthStage` / `OptionSpec_OptionType` underscore in type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) + +**Symbols:** `OptionSpec_OauthStage` (model.ts:229), +`OptionSpec_OptionType` (model.ts:242). + +**Issue:** Both enum type names carry an internal `_` to model nested-enum +namespacing from `.proto` source. The Google TS Style Guide § 5.3 mandates +`UpperCamelCase` for type names with no underscores; the project's lint rule +(`.agent/rules/typescript.mdc` § *Identifiers*) enforces the same. The file +suppresses the lint for each (model.ts:228, 241): + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. +export enum OptionSpec_OauthStage { ... } +``` + +The suppression comment is the audit signal: lint disagrees, and the +suppression is hard-coded across the SDK for every proto-nested enum. + +**Note on inconsistency *within this file*:** the file uses *both* the flat +form (`ColumnTypeName`, `DataSourceFormat`, `SecurableKind`, `SecurableType`, +`SseEncryptionAlgorithm`, `TableType` — all flat) and the underscored form +(`OptionSpec_*`). Same generator, same package, two conventions in the same +file. + +**Suggested:** `OauthStage` and `OptionType` if the parent `OptionSpec` +namespace can be dropped; or fold to `OptionSpecOauthStage` / +`OptionSpecOptionType` to keep the parent prefix without the underscore. +Cross-reference `featurestore.PublishSpec_PublishMode` for the same problem. +**Flag for SDK-wide generator cleanup.** + +--- + +### 2. `CreateTable_PropertiesEntry` / `TableInfo_PropertiesEntry` / `UpdateTable_PropertiesEntry` / `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` underscore in type names — category 4 (Underscores in TS identifiers) + +**Symbols:** +- `CreateTable_PropertiesEntry` (model.ts:394). +- `TableInfo_PropertiesEntry` (model.ts:844). +- `UpdateTable_PropertiesEntry` (model.ts:931). +- `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` (model.ts:444). +- The response wrappers `DeleteTable_Response`, `DeleteTableConstraint_Response`, + `UpdateTable_Response`, `ListTables_Response`, `ListTableSummaries_Response`, + `TableExists_Response` (model.ts:417, 432, 937, 594, 556, 767). + +**Issue:** Twelve type names carry `_` to mirror proto-message namespacing. +Each is preceded by an `eslint-disable-next-line` comment. The Google TS +Style Guide § 5.3 mandates `UpperCamelCase` for type names with no +underscores; the project's lint rule (`.agent/rules/typescript.mdc` § +*Identifiers*) enforces the same. Every one of these exports requires a +hard-coded lint suppression to keep the proto-nested form. + +**Suggested:** fold the parent prefix without the underscore — e.g. +`CreateTablePropertiesEntry`, `TableInfoPropertiesEntry`, +`DeleteTableResponse`, etc. Wire payloads are unaffected; only the TS +identifier changes. + +**Coordinate with generator.** Cross-reference +`onlinetables.OnlineTableSpec_ContinuousSchedulingPolicy` (audited in +`onlinetables.md` finding 2) for the same family of wrapper-with-underscore +issues. + +--- + +### 3. `DeltaRuntimePropertiesKvPairs` type name vs. `deltaRuntimePropertiesKvpairs` field name acronym-casing mismatch — category 3 (Acronym casing inconsistencies) + +**Symbols:** +- Type: `DeltaRuntimePropertiesKvPairs` (model.ts:438) — `KvPairs` (capital + `P`). +- Field: `deltaRuntimePropertiesKvpairs` (model.ts:374, 824, 911) — `Kvpairs` + (lowercase `p`). + +**Issue:** The same word ("KvPairs") is cased differently across type and +field names *within the same generated package*: + +```ts +// type name +export interface DeltaRuntimePropertiesKvPairs { ... } // KvPairs + +// field name on TableInfo / CreateTable / UpdateTable +deltaRuntimePropertiesKvpairs?: DeltaRuntimePropertiesKvPairs | undefined; +// ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ +// Kvpairs (field) KvPairs (type) +``` + +The wire form is `delta_runtime_properties_kvpairs` (model.ts:1353, 1565, +1894, 1936) — snake_case with two underscores around `kvpairs` (not three). +The field-name camelCase conversion turns `kvpairs` into one camelCase +token; the type-name PascalCase keeps `KvPairs` as two tokens. The mismatch +is purely a generator quirk: it tokenizes the wire string differently for +struct names vs. field names. + +**Suggested:** unify casing. +- Either `DeltaRuntimePropertiesKvpairs` (field-consistent — but breaks the + acronym-rule from the Google style guide which keeps multi-letter + acronyms readable, e.g. `xmlHttpRequest`). +- Or `deltaRuntimePropertiesKvPairs` (type-consistent — and "Kv" / "Pairs" + read naturally as two words). + +**Prefer the type-consistent form.** Apply on the field. Cross-reference +the proto-source field naming convention. **Flag for SDK-wide generator +cleanup.** + +--- + +### 4. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) + +**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:438). + +**Issue:** `Kv` (key-value) is borderline cryptic for a TypeScript API; the +"Pairs" suffix is redundant if `Kv` already means key-value. The type holds +a single `Record` field — both the prefix `Kv` and the +suffix `Pairs` redundantly state what the field's type already says. + +**Suggested:** `DeltaRuntimeProperties` (drop `KvPairs` entirely; the field +content `deltaRuntimeProperties: Record` makes it +self-describing). + +--- + +### 5. `OptionSpec_OauthStage` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) + +**Symbol:** `OptionSpec_OauthStage.OAUTH_STAGE_UNSPECIFIED` (model.ts:230). + +**Issue:** Member is already namespaced under `OptionSpec_OauthStage`. The +`OAUTH_STAGE_` segment duplicates the enum name. Reads as: + +```ts +spec.oauthStage === OptionSpec_OauthStage.OAUTH_STAGE_UNSPECIFIED +// ^^^^^^^^^^^^^^^^^^^^^^^ +// duplicates the enum name +``` + +Companion values `BEFORE_AUTHORIZATION_CODE` / `BEFORE_ACCESS_TOKEN` do not +repeat the prefix — they break the pattern, so only the `UNSPECIFIED` value +is verbose. This is the classic protobuf "first enum is the unspecified +placeholder with the type name as its prefix" pattern. + +**Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. +**Suggested TS-level only:** `Unspecified = 'OAUTH_STAGE_UNSPECIFIED'`. + +--- + +### 6. `OptionSpec_OptionType` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) + +**Symbol:** `OptionSpec_OptionType.OPTION_TYPE_UNSPECIFIED` (model.ts:243) +and every other value (`OPTION_BOOLEAN`, `OPTION_NUMBER`, etc.). + +**Issue:** Every member is prefixed `OPTION_` — repeating the enum name +`OptionType`. The 9 values are: +- `OPTION_TYPE_UNSPECIFIED` +- `OPTION_BOOLEAN`, `OPTION_NUMBER`, `OPTION_BIGINT`, `OPTION_STRING`, + `OPTION_ENUM` +- `OPTION_SERVICE_CREDENTIAL`, `OPTION_MULTILINE_STRING`, + `OPTION_STORAGE_CREDENTIAL` + +Reads as: +```ts +spec.type === OptionSpec_OptionType.OPTION_BOOLEAN // "the OptionType is OPTION_BOOLEAN" +``` + +`OptionType.Boolean` would be far cleaner. The wire form is fixed; the TS +identifier can be split (`Boolean = 'OPTION_BOOLEAN'`). + +**Suggested:** drop `OPTION_` prefix on the TS identifiers. Combined with +finding 1's rename (`OptionType` instead of `OptionSpec_OptionType`): +```ts +export enum OptionType { + Unspecified = 'OPTION_TYPE_UNSPECIFIED', + Boolean = 'OPTION_BOOLEAN', + Number = 'OPTION_NUMBER', + Bigint = 'OPTION_BIGINT', + // ... +} +``` + +--- + +### 7. `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` member value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) + +**Symbol:** `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` +(model.ts:204). 37 characters. + +**Issue:** Identical pattern to findings 5 and 6 — the leading +`SSE_ENCRYPTION_ALGORITHM_` segment duplicates the enum name. The other two +values (`AWS_SSE_S3`, `AWS_SSE_KMS`) do not include the prefix, so only +`UNSPECIFIED` is overly verbose. + +**Suggested:** TS-side `Unspecified = 'SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED'`. +Wire string remains. + +--- + +### 8. SSE acronym casing in `SseEncryptionAlgorithm` / `SseEncryptionDetails` — category 3 (Acronym casing inconsistencies) + +**Symbols:** `SseEncryptionAlgorithm` (model.ts:203), +`SseEncryptionDetails` (model.ts:724), `sseEncryptionDetails` (field name in +`EncryptionDetails` discriminator at model.ts:491). + +**Issue:** "SSE" is a three-letter acronym (Server-Side Encryption). Google +TS Style Guide § 5.1 says multi-letter acronyms should be cased like +ordinary words (e.g. `xmlHttpRequest`, not `XMLHTTPRequest`). The current +form `Sse…` is *correct* under that rule. However, all enum members use +`AWS_SSE_S3` / `AWS_SSE_KMS` / `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` — +keeping the full upper-case acronym in the wire values. The split makes the +TS identifier rule and the wire value rule diverge: `Sse` in code, +`SSE` on the wire. + +This is consistent with the rest of the SDK (`HttpClient`, `JsonStringify` +etc.) but is worth flagging for anyone reviewing this file fresh. + +**Pass** under Google's rule; **note** the inconsistency for SDK-wide review. + +--- + +### 9. `SseEncryptionDetails.awsKmsKeyArn` is the only field that names the cloud — category 3 (Acronym casing inconsistencies) and category 16 (Field contradicting type domain) + +**Symbol:** `SseEncryptionDetails.awsKmsKeyArn` (model.ts:731). + +**Issue:** `AWS`, `KMS`, and `ARN` are three back-to-back acronyms. The +field is `awsKmsKeyArn`. The JSDoc explains it's "The ARN of the SSE-KMS +key used with the S3 location, when algorithm = 'SSE-KMS'". Under the +Google rule, `AwsKmsKeyArn` would become `awsKmsKeyArn` in camelCase form — +which the code already uses. So far OK. + +But this is the *only* AWS-specific field in `tables`. `accessPoint` +(model.ts:381) is also AWS S3-specific (JSDoc: "The AWS access point to +use when accesing s3 for this external location") — but the field name +does not say `awsAccessPoint`. The two AWS-specific fields in `TableInfo` +use different naming conventions for their AWS-ness. + +**Suggested:** either rename `accessPoint` → `awsAccessPoint`, or drop the +`aws` prefix on `awsKmsKeyArn` if it's understood to be AWS-only (the +enclosing `SseEncryptionAlgorithm` already says `AWS_SSE_KMS`). + +(One JSDoc typo: "accesing" — single `s`, model.ts:381 — likely also in +the upstream `.proto`.) + +--- + +### 10. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) + +**Symbol:** `SecurableType` (model.ts:182). + +**Issue:** `SecurableType` is also exported from `catalogs/v1/model.ts:28`, +`connections/v1/model.ts:109`, and at least two other audited packages. +Each definition is the same enum with the same 17 values. Five copies of +the same enum across the SDK. The values overlap with `SecurableKind` (see +finding 11) but are at a different level of granularity (a `TABLE` of +`SecurableType` maps to ~50 `TABLE_*` `SecurableKind` values). + +Within the `tables` package, `SecurableType` only appears on +`SecurableKindManifest.securableType` (model.ts:712) — a single field on a +single type. The enum's *value* to this package is marginal: a consumer +who already has a `TableInfo` knows it's a `TABLE`. + +**Suggested:** hoist to `@databricks/sdk-core/securable` or similar. +**SDK-wide cleanup.** + +--- + +### 11. `SecurableKind` is a 70+ value enum with `TABLE_` prefix on most values — category 2 (Redundant enum prefixes) and category 18 (Long enum values) + +**Symbol:** `SecurableKind` (model.ts:81) — 70+ members, 50+ with `TABLE_` +prefix. + +**Issue:** The enum mixes two concerns: + +1. Table-specific kinds: `TABLE_STANDARD`, `TABLE_EXTERNAL`, `TABLE_DELTA`, + `TABLE_VIEW`, `TABLE_FOREIGN_HIVE_METASTORE_DBFS_SHALLOW_CLONE_EXTERNAL` + (60+ chars!). +2. Non-table kinds: `RECIPIENT_*`, `CONNECTION_*`, `CATALOG_*`, `SCHEMA_*`. + +The longest values (`TABLE_DELTA_UNIFORM_ICEBERG_FOREIGN_HIVE_METASTORE_EXTERNAL`, +`TABLE_FOREIGN_SALESFORCE_DATA_CLOUD_FILE_SHARING_VIEW`, +`TABLE_FOREIGN_HIVE_METASTORE_DBFS_SHALLOW_CLONE_EXTERNAL`) are 50–60 +characters each. As enum members they are functional but exceed Google's +90-column line cap when used in expressions. + +The two-concerns problem is structural: `SecurableKind` is generated for the +whole UC `Securable` taxonomy. In `tables` only the `TABLE_*` half matters, +but the enum exports all values. The non-`TABLE_*` values are unreachable +through any field on this package's types. + +**Suggested:** +- For local TS readability: rename TS identifiers to `UpperCamelCase` + (`TableStandard`, `TableExternal`, …) without changing the wire string. +- For SDK-wide structure: hoist `SecurableKind` to a shared module and let + service packages re-export, so consumers don't see the entire taxonomy in + every type-import location. +- Consider splitting `SecurableKind` into `SecurableKind` + `TableKind` if + the API surface allows. **Coordinate with protocol team.** + +--- + +### 12. `SecurableKind` lint suppressions for SCREAMING_SNAKE_CASE — category 4 (Underscores in TS identifiers) + +**Symbol:** Every value in `SecurableKind` (model.ts:82–179). + +**Issue:** All values are SCREAMING_SNAKE_CASE with underscores in TS +identifiers. The wire string and the TS identifier are the same value +(`'TABLE_DELTA'`, etc.). Even at default lint settings the file does *not* +suppress these — meaning the lint rule is permissive about enum *values* +but not enum *names* (findings 1 and 2). This is an enforcement gap. + +**Suggested (TS side only, no wire change):** +```ts +export enum SecurableKind { + TableStandard = 'TABLE_STANDARD', + TableExternal = 'TABLE_EXTERNAL', + TableDelta = 'TABLE_DELTA', + // ... +} +``` + +**Pass with note** if the project policy chose to accept SCREAMING_SNAKE for +enum *values* as a wire-compatibility shortcut. **Flag for SDK-wide +cleanup** otherwise. + +--- + +### 13. `ColumnTypeName.TABLE_TYPE` and `TABLEREF_TYPE` collide with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) + +**Symbols:** `ColumnTypeName.TABLE_TYPE` (model.ts:31), +`ColumnTypeName.TABLEREF_TYPE` (model.ts:32). + +**Issue:** Two values in `ColumnTypeName` are named the same as the +*type-name* of another enum in this file: + +- `ColumnTypeName.TABLE_TYPE` — a column-data-type value of "table". +- `TableType` (model.ts:209) — the *enum* describing kinds of UC tables + (`MANAGED`, `EXTERNAL`, `VIEW`, …). + +A reader scanning the file sees `TABLE_TYPE` as a `ColumnTypeName` value +and `TableType` as a separate enum — but the names overlap, suggesting they +are related. They are not: one is about Spark column SQL types ("the column +holds a table"), the other is about UC table classifications. + +`TABLEREF_TYPE` is also cryptic — the `REF` suffix is unclear (table +reference type? table-ref?), and the field has no JSDoc to disambiguate. + +**Suggested:** +- Rename `TABLE_TYPE` → `TABLE` (matches the pattern: `ARRAY`, `STRUCT`, + `MAP` are the same kind of compound type). +- Rename `TABLEREF_TYPE` → `TABLE_REFERENCE` (matches `USER_DEFINED_TYPE`). +- Or document the relationship in JSDoc. + +**Coordinate with protocol.** + +--- + +### 14. `ColumnTypeName.USER_DEFINED_TYPE` and `TIMESTAMP_NTZ` cryptic value forms — category 5 (Cryptic abbreviations) and category 18 (Long enum values) + +**Symbols:** `ColumnTypeName.USER_DEFINED_TYPE` (model.ts:24), +`ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25). + +**Issue:** +- `USER_DEFINED_TYPE` — 17 characters. The companion values (`BOOLEAN`, + `INT`, `STRING`) are short. The `_TYPE` suffix is redundant inside an + enum already named `ColumnTypeName`. +- `TIMESTAMP_NTZ` — "NTZ" is "no time zone" (a Spark/Delta abbreviation). + Has no JSDoc. + +**Suggested:** +- `USER_DEFINED_TYPE` → `USER_DEFINED` (drop the `_TYPE` suffix). +- Add JSDoc to `TIMESTAMP_NTZ` clarifying `NTZ = "no time zone"`. + +--- + +### 15. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) + +**Symbols:** `DataSourceFormat` values (model.ts:36–78). + +**Issue:** 18 of the 26 values carry a `_FORMAT` suffix +(`DATABRICKS_FORMAT`, `MYSQL_FORMAT`, etc.), but 8 are bare (`DELTA`, `CSV`, +`JSON`, `AVRO`, `PARQUET`, `ORC`, `TEXT`, `UNITY_CATALOG`, `HIVE`, +`DELTASHARING`, `DELTA_UNIFORM_HUDI`, `DELTA_UNIFORM_ICEBERG`, `ICEBERG`). +The split is along provenance: the bare values are the "native" Databricks +formats; the `_FORMAT` suffix marks query-federation source formats (added +later, per the `BEGIN`/`END` comments at model.ts:47, 66). + +So the suffix carries semantic information (source-federation vs. native). +But that distinction should be expressed *outside* the wire string — e.g. a +boolean `isFederationSource` on a richer type, or two enums. The current +form has the suffix as a soft tag inside one enum. + +For consumers, this means writing: +```ts +if (format === 'DELTA' || format === 'PARQUET') {} // bare +if (format === 'MYSQL_FORMAT' || format === 'POSTGRESQL_FORMAT') {} // suffix +``` + +**Suggested:** drop `_FORMAT` suffixes on the TS identifiers +(`MYSQL = 'MYSQL_FORMAT'`); the wire string remains. Cross-reference +`connections.ConnectionType` for the same domain. + +--- + +### 16. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) + +**Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:46), +`DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:73). + +**Issue:** Inconsistent tokenisation within the same enum: +- `DELTASHARING` — single token ("delta sharing" without separator). +- `DELTA_UNIFORM_HUDI` — three tokens. + +The wire form for "delta sharing" *should* be `DELTA_SHARING` to follow the +pattern, but the protocol team chose `DELTASHARING`. Same problem exists +across `SecurableKind` (`TABLE_DELTASHARING`, `TABLE_DELTA_ICEBERG_DELTASHARING`, +etc.). + +**Suggested:** push back upstream — `DELTA_SHARING` would be more +consistent. **Not a per-package fix.** + +--- + +### 17. `TableType` enum — category 18 (Long enum values) — *pass with note* + +**Symbol:** `TableType` (model.ts:209) — 9 values: `MANAGED`, `EXTERNAL`, +`VIEW`, `MATERIALIZED_VIEW`, `STREAMING_TABLE`, `MANAGED_SHALLOW_CLONE`, +`FOREIGN`, `EXTERNAL_SHALLOW_CLONE`, `METRIC_VIEW`. + +**Issue:** +- `STREAMING_TABLE` — 15 chars, ends in `_TABLE` (already inside `TableType` + — minor redundancy). +- `MANAGED_SHALLOW_CLONE`, `EXTERNAL_SHALLOW_CLONE` — 21–22 chars, no + redundant prefix. +- `MATERIALIZED_VIEW`, `METRIC_VIEW` — clean. + +The `_TABLE` suffix on `STREAMING_TABLE` is the only redundancy (compare +to `MANAGED`, `EXTERNAL` which don't say `MANAGED_TABLE` / `EXTERNAL_TABLE`). +But it documents that a streaming table is a kind of table (vs. a view or +materialized view). + +**Suggested:** consider `STREAMING` for the TS identifier; wire string +remains. **Pass with note.** + +(Cross-package: `SecurableKind.TABLE_STREAMING_LIVE_TABLE` (model.ts:106) +and the deprecated `TABLE_STREAMING_LIVE_TABLE_DELTASHARING` use the +phrase "streaming live table" — older vocabulary. `TableType.STREAMING_TABLE` +is the newer name. The two enums in the same file disagree on the +streaming-table label.) + +--- + +### 18. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) + +**Symbol:** `SecurableKind.TABLE_DELTASHARING_OPEN_DIR_BASED` (model.ts:96). + +**Issue:** "OPEN DIR BASED" abbreviates "open-directory-based" — i.e. a +delta-sharing table backed by an open directory listing. The acronym is +unique to delta-sharing internals. No JSDoc. + +The value sits among 70+ others, most also opaque without internal +knowledge (e.g. `TABLE_DELTA_UNIFORM_ICEBERG_EXTERNAL_DELTASHARING` has +JSDoc, `TABLE_DELTASHARING_OPEN_DIR_BASED` does not). + +**Suggested:** add JSDoc to clarify. **Pass on naming** (wire-string +constraint), **flag for documentation cleanup.** + +--- + +### 19. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) + +**Symbols:** +- `SecurableKind.TABLE_FEATURE_STORE` (model.ts:104) and + `TABLE_FEATURE_STORE_EXTERNAL` (model.ts:105) — both marked "deprecated" + in JSDoc (model.ts:103). +- `SecurableKind.TABLE_FOREIGN_HIVE_METASTORE` (model.ts:129) — also + marked deprecated. + +**Issue:** Five+ deprecated values left in the enum without `@deprecated` +JSDoc tags (only inline comments). Consumers code-completing on +`SecurableKind` see all values equally — no syntactic signal of deprecation. + +**Suggested:** +- Add `@deprecated` JSDoc tags so IDEs strike through the symbol. +- Or, more aggressively, drop the deprecated values when the next breaking + release happens. + +**Flag for SDK-wide deprecation policy.** + +--- + +### 20. `fullNameArg` field name across multiple request types — category 14 (Go/Java-style names) and category 5 (Cryptic abbreviations) + +**Symbols:** `fullNameArg` on `DeleteTable` (model.ts:413), +`DeleteTableConstraint` (model.ts:421), `GetTable` (model.ts:519), +`TableExists` (model.ts:763), `UpdateTable` (model.ts:859), +`CreateTableConstraint` (model.ts:401). 7 occurrences in this file alone; +also used in `schemas/v1`, `functions/v1`, `registeredmodels/v1`. + +**Issue:** The `Arg` suffix on a field name is a Go convention (Go SDK uses +`FullNameArg` to mark a URL-path-argument vs. a query/body field). In TS, +the convention is to use the bare field name (`fullName`) since the +distinction between URL-path / query / body is handled by the client code +and JSDoc. The wire form is `full_name_arg` (model.ts:1583, 1911) — the +suffix even reaches the wire, which is unusual. + +The same package also has a `fullName` field on response/struct types +(`CreateTable.fullName` model.ts:360, `TableInfo.fullName` model.ts:810, +`TableSummary.fullName` model.ts:851). So the package has both `fullName` +(noun) and `fullNameArg` (with `Arg` suffix) — distinguishing input from +output by suffix, which is a Go-ism. + +**Suggested:** rename `fullNameArg` → `fullName` SDK-wide. The URL-path +argument vs. response field distinction can be inferred from the request +type (e.g. `DeleteTable.fullName` is obviously a path argument because +`DeleteTable` is a delete request). Cross-reference Google AIP-122 +(resource name in REST methods uses `name`, not `nameArg`). + +**Flag for SDK-wide cleanup.** + +--- + +### 21. `TableExists` request type is a verb-as-noun — category 6 (Misleading names) + +**Symbol:** `TableExists` (model.ts:761) request type. + +**Issue:** The request type is named `TableExists` — a verb-as-noun. Inside +`tables` the implicit verb "does this table exist?" reads as the type name. +Awkward but matches Go. Code-completing on the package surface shows +`TableExists` alongside the noun-shaped `TableInfo` and `TableSummary`, +without a `Request` suffix or other syntactic hint that this is a request +input. + +**Suggested:** rename to `TableExistsRequest` (would *not* match other +request types in this package — none of them carry the `Request` suffix — +but resolves the verb-as-noun reading). + +**Flag at port time.** + +--- + +### 22. Request type naming pattern is inconsistent (`CreateTable`, `DeleteTable`, no `Request` suffix) — category 17 (Inconsistent action verbs) and category 20 (Type-suffix tautology) + +**Symbols:** All request types in this package (`CreateTable`, `DeleteTable`, +`DeleteTableConstraint`, `GetTable`, `ListTables`, `ListTableSummaries`, +`TableExists`, `UpdateTable`, `CreateTableConstraint`). + +**Issue:** None carry the `Request` suffix that some sister packages do +(`featurestore.CreateOnlineStoreRequest`, +`onlinetables.CreateOnlineTableRequest`, etc.). Within `tables`, the same +type names also clash with the *response* concept — e.g. `CreateTable` is +sometimes interpreted as "an action: create the table" and sometimes as +"the type representing a table to be created." + +The same problem extends to the marshal/unmarshal schema names: +- `marshalCreateTableSchema` (model.ts:1496) — schema for the + request-input shape. +- `unmarshalTableInfoSchema` (model.ts:1325) — schema for the response. + +There is **no** `unmarshalCreateTableSchema` because the response of +`createTable` is `TableInfo`. The asymmetry between marshal (input) and +unmarshal (output) is the right structure but the naming makes it hard to +spot. + +**Suggested:** rename to `CreateTableRequest`, `GetTableRequest`, etc., or +keep the current convention and document that "verb-noun" types are always +input. Pick one. **Flag SDK-wide.** + +(Note that `onlinetables` uses `Request` suffix; `tables` does not. Same +SDK, same generator, two conventions.) + +--- + +### 23. `CreateTable` and `TableInfo` and `UpdateTable` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) + +**Symbols:** `CreateTable` (model.ts:322, 38 fields), `TableInfo` +(model.ts:772, 36 fields), `UpdateTable` (model.ts:857, 37 fields). + +**Issue:** Three types describe essentially the same shape: +- `CreateTable` — fields a caller sets when creating a table. +- `TableInfo` — fields the server returns about a table. +- `UpdateTable` — fields a caller sets when updating a table (the only + delta is `fullNameArg` added at the top). + +Comparing field lists: +- `CreateTable.fullName` vs `UpdateTable.fullName`: both fields exist in + both types. `UpdateTable` *also* has `fullNameArg`. The `fullName` field + on `CreateTable` is server-output (the server fills it). The same field + on `UpdateTable` is also server-output. +- `CreateTable.createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `tableId`, + `deletedAt`, `metastoreId` — all server-populated. They appear in + `CreateTable` *because* the type is also used as the response shape of + `createTable()`. The client.ts code confirms (client.ts:117) — the + response is parsed as `TableInfo`, but `CreateTable` carries the same + fields anyway as part of the "fields you *could* set" surface. + +So `CreateTable` is *both* an input and an output type, with the same set +of fields. Same for `UpdateTable`. `TableInfo` is the response shape but +shares the field set. Three types that are *almost* identical. + +**Suggested:** collapse to one `Table` type, with optional fields for the +output-only segments (or use `Pick`/`Omit` types if input-only / output-only +need to be distinct). The current shape is generator-driven (proto-source +messages map 1:1). + +**Strong flag for generator cleanup.** Cross-reference the same problem in +`featurestore`, `database`, `postgres`. + +--- + +### 24. `CreateTable.fullName` is server-generated — category 6 (Misleading names) + +**Symbol:** `CreateTable.fullName?: string | undefined` (model.ts:360). +JSDoc: "Full name of table, in form of __catalog_name__.__schema_name__.__table_name__". + +**Issue:** The field appears in the request *input* type but is server-output +(derived from `catalogName`, `schemaName`, `name`). A caller writing +`createTable({ fullName: 'foo.bar.baz' })` would believe they are setting +the full name; the server ignores it. No JSDoc marks the field as +output-only. + +Same applies to `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, +`tableId`, `metastoreId`, `deletedAt`, `pipelineId`, `dataAccessConfigurationId`, +`deltaRuntimePropertiesKvpairs`, `effectivePredictiveOptimizationFlag` — +all server-output but exposed on the input type. Same critique applies to +`UpdateTable`. + +**Suggested:** mark with JSDoc `@readonly` and add a sentence "Output only; +ignored on input." Or restructure types (finding 23). **Coordinate with +generator.** + +--- + +### 25. `CreateTable.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) + +**Symbol:** `CreateTable.tableConstraints?: TableConstraint[] | undefined` +(model.ts:352). JSDoc: "List of table constraints. Note: this field is not +set in the output of the __listTables__ API." + +**Issue:** The JSDoc note is structured oddly: it explains the field's +*output* behaviour, but the field appears in the *input* type. Combined +with the existence of a separate `createTableConstraint` method +(client.ts:147), the typical workflow is: +1. Call `createTable` (without constraints). +2. Call `createTableConstraint` (one per constraint). + +So `CreateTable.tableConstraints` is also an unusual input — the server +might or might not honour it depending on the deployment. + +**Suggested:** clarify JSDoc on input behaviour; possibly mark deprecated. + +--- + +### 26. `CreateTable.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) + +**Symbol:** `CreateTable.enablePredictiveOptimization?: string | undefined` +(model.ts:356). Same field on `TableInfo` (model.ts:806) and `UpdateTable` +(model.ts:893). No JSDoc. + +**Issue:** The `enable…` prefix strongly suggests a boolean. The type is +`string`. A caller writing +`createTable({ enablePredictiveOptimization: true })` gets a TS error and +must look up the JSDoc to learn the field accepts string enum values +(typically `'ENABLE'`, `'DISABLE'`, `'INHERIT'` per UC). The +companion `effectivePredictiveOptimizationFlag.value` (model.ts:480) is +also a `string` with the same domain. + +**Suggested:** +- Type as an enum (e.g. `PredictiveOptimizationFlag = 'ENABLE' | 'DISABLE' + | 'INHERIT'`) and rename to `predictiveOptimization`. +- Or document the accepted values in JSDoc. + +**Coordinate with protocol.** Cross-reference `catalogs/v1` which has the +same field. + +--- + +### 27. `CreateTable.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) + +**Symbol:** `CreateTable.dataAccessConfigurationId?: string | undefined` +(model.ts:362). 28 chars. Same field on `TableInfo` (model.ts:812) and +`UpdateTable` (model.ts:899). + +**Issue:** A `string` field with no type discrimination. The JSDoc says +"Unique ID of the Data Access Configuration to use with the table data." +A consumer cannot know the ID's format (UUID? snowflake? human-readable?). +Same applies to: +- `metastoreId` (model.ts:358) — UC metastore identifier. +- `pipelineId` (model.ts:355) — DLT pipeline identifier. +- `tableId` (model.ts:372) — UC table identifier. + +All are bare strings. The TS SDK has no typed IDs; that is an SDK-wide +choice. **Pass with note.** + +--- + +### 28. `CreateTable.accessPoint` (S3-specific) leaks AWS into a generic-looking field — category 6 (Misleading names) and category 16 (Field contradicting type domain) + +**Symbol:** `CreateTable.accessPoint?: string | undefined` (model.ts:381). +JSDoc: "The AWS access point to use when accesing s3 for this external +location." (Note also the JSDoc typo "accesing".) + +**Issue:** A field named `accessPoint` reads like a generic concept (the +endpoint at which the table is accessed?). In reality it is AWS S3–specific. +The JSDoc clarifies, but the field name does not. A caller targeting Azure +or GCP will not know to skip the field. + +**Suggested:** rename to `awsAccessPoint` or `s3AccessPoint` (matches the +JSDoc). + +**Cross-reference:** `SseEncryptionDetails.awsKmsKeyArn` (finding 9) takes +the AWS prefix; `accessPoint` does not. Inconsistent within this file. + +--- + +### 29. `CreateTable.browseOnly` is server-output but appears in request — category 6 (Misleading names) + +**Symbol:** `CreateTable.browseOnly?: boolean | undefined` (model.ts:383). +JSDoc: "Indicates whether the principal is limited to retrieving metadata +for the associated object through the BROWSE privilege when include_browse +is enabled in the request." + +**Issue:** Server-output field on an input type, again. The JSDoc is also +describing the server's behaviour ("when include_browse is enabled in the +request") which is a different request entirely. Confusing because the +field's *meaning* depends on context. + +**Suggested:** mark `@readonly` and add a one-line "Output only." Or move +to `TableInfo` only. + +--- + +### 30. `ListTables.omitColumns` / `omitProperties` / `omitUsername` use negative form — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) + +**Symbols:** `ListTables.omitColumns?: boolean` (model.ts:582), +`omitProperties?: boolean` (model.ts:584), `omitUsername?: boolean` +(model.ts:586). Same package also has `includeBrowse?: boolean` +(model.ts:588), `includeManifestCapabilities?: boolean` (model.ts:589). + +**Issue:** Five boolean flags on the same request type: +- Three positive `include…` (which add output). +- Three negative `omit…` (which subtract output). + +The mixing of positive and negative forms is unusual. Code completion +shows both `omitColumns` and `includeBrowse` on the same type — a reader +might miss that `omitColumns: false` is the default-include state, while +`includeBrowse: false` is the default-exclude state. + +**Suggested:** unify on `include…` (the SDK-wide convention) — e.g. +`includeColumns: boolean | undefined` defaulting to `true`. **Flag at port +time.** + +(Note: `omitUsername` is also a singular — "username", not "usernames" — +even though the JSDoc lists three fields (owner, updated_by, created_by). +Should be `omitUsernames`. See finding 31.) + +--- + +### 31. `ListTables.omitUsername` singular but covers three fields — category 9 (Singular/plural mismatch) + +**Symbol:** `ListTables.omitUsername?: boolean | undefined` (model.ts:586). +JSDoc: "Whether to omit the username of the table (e.g. owner, updated_by, +created_by) from the response or not." + +**Issue:** Singular `Username` but the JSDoc lists three fields. Plural +`omitUsernames` would match the impact ("omit *all* the username fields"). + +**Suggested:** `omitUsernames`. Wire form (`omit_username`) is the +single-token version; the TS-side identifier can be pluralised without +changing the wire string. **Coordinate with protocol team.** + +--- + +### 32. `ListTables.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* + +**Symbol:** `ListTables.maxResults?: number | undefined` (model.ts:578), +JSDoc: "Maximum number of tables to return. If not set, all the tables +are returned (not recommended)." + +The pagination docstring is long and warns that unpaginated calls will be +deprecated. The naming is fine; the API behaviour is the issue. + +**Pass on naming.** + +--- + +### 33. `ListTableSummaries.schemaNamePattern` / `tableNamePattern` vs. `ListTables.schemaName` field-name inconsistency — category 17 (Inconsistent action verbs) + +**Symbols:** `ListTableSummaries.schemaNamePattern` (model.ts:535) and +`ListTableSummaries.tableNamePattern` (model.ts:540) vs. `ListTables.schemaName` +(model.ts:570). + +**Issue:** Two sibling list endpoints accept the schema name as different +shapes: +- `ListTables.schemaName` — an exact string match. +- `ListTableSummaries.schemaNamePattern` — a SQL LIKE pattern. + +JSDoc explains the difference. But the *callers* must remember which +endpoint uses which form. There is no naming hint that one is a pattern. + +**Suggested:** rename `ListTables.schemaName` to `schemaNameExact` or +`schemaNameEquals` to surface the contrast — or rename +`ListTableSummaries.schemaNamePattern` to `schemaName` with JSDoc clarifying +the pattern syntax. The former is the cleaner pick (less ambiguous on the +input side). + +**Flag at port time.** + +--- + +### 34. `ListTableSummaries_Response.tables` returns `TableSummary[]` not `TableInfo[]` — category 6 (Misleading names) and category 15 (Generic field names losing meaning) + +**Symbol:** `ListTableSummaries_Response.tables?: TableSummary[] | undefined` +(model.ts:558). + +**Issue:** A field named `tables` returns *summaries*, not full table info. +The companion `ListTables_Response.tables` returns `TableInfo[]`. So +`tables` on one response type vs. another means a different shape. + +**Suggested:** rename `ListTableSummaries_Response.tables` to `summaries` +(matches the response type name). Or rename to `tableSummaries`. Both +expose the shape difference at the field name. + +**Flag at port time.** + +--- + +### 35. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` / `VolumeDependency` / `SecretDependency` defined in three packages — category 12 (Duplicate concepts) + +**Symbols:** +- This file: `Dependency` (model.ts:453), `DependencyList` (model.ts:473), + and the six leaf-types (model.ts:317, 406, 512, 704, 756, 940). +- `functions/v1/model.ts:74–407` — full duplicate. +- `registeredmodels/v1/model.ts:16–423` — full duplicate. + +**Issue:** Three packages export the same eight types. Each defines its own +`Dependency` discriminated union with the same six cases. The field shapes +are identical (e.g. `TableDependency.tableFullName` is `tableFullName` in +all three). A consumer who uses `tables.TableDependency` and +`functions.TableDependency` will get two different (but structurally +identical) types from the type checker. + +**Suggested:** hoist to `@databricks/sdk-core/dependency` and re-export +from each service package. **Strong SDK-wide cleanup.** + +--- + +### 36. `Dependency.value` field name is generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) + +**Symbol:** `Dependency.value` (model.ts:454). Type is the discriminated +union. + +**Issue:** `value` is the maximally generic field name. The proto source +likely models `Dependency` as `oneof`; the generator wraps each case in a +`value` discriminator. In TS, the consumer writes: + +```ts +if (dep.value?.$case === 'table') { + console.log(dep.value.table.tableFullName); +} +``` + +`value` adds noise without distinguishing the shape. Compare to +`EncryptionDetails.encryptionDetailsType` (model.ts:489) — same pattern, +non-generic name. Compare to `TableConstraint.constraint` (model.ts:739) — +same pattern, more descriptive name. Within this file, **three different +naming conventions for the same generator pattern.** + +**Suggested:** `Dependency.dependency` (matches the type name) or +`Dependency.kind` (consistent with discriminated-union nomenclature). +**Flag at port time.** + +--- + +### 37. `EncryptionDetails.encryptionDetailsType` repeats the type name as the field name — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) + +**Symbol:** `EncryptionDetails.encryptionDetailsType` (model.ts:489). + +**Issue:** Inside the type `EncryptionDetails`, the field name +`encryptionDetailsType` repeats two of the three tokens of the type name. +A consumer writes: +```ts +encDetails.encryptionDetailsType?.$case +``` +when `encDetails.kind?.$case` or `encDetails.details?.$case` would +suffice. + +Compare to `Dependency.value` (finding 36) — same pattern, generic name. +Compare to `TableConstraint.constraint` — same pattern, name is the type +*concept* without `Type` suffix. + +**Suggested:** `EncryptionDetails.kind`. + +--- + +### 38. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) + +**Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:261). +JSDoc: "Ordinal position of column (starting at position 0)." + +**Issue:** Bare `position` (number) — a consumer cannot tell from the +field name that it's 0-indexed. The JSDoc clarifies. + +**Suggested:** `ColumnInfo.ordinal` (matches the JSDoc "Ordinal position") +or `columnIndex`. **Pass with note** — the field is short and conventional. + +--- + +### 39. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — six `type*` fields — category 12 (Duplicate concepts) + +**Symbols:** `ColumnInfo.typeText` (model.ts:258), `typeName` (model.ts:259), +`typePrecision` (model.ts:262), `typeScale` (model.ts:263), +`typeIntervalType` (model.ts:267), `typeJson` (model.ts:269). + +**Issue:** Six fields all describing the column's data type, prefixed +`type…`. The JSDoc says: +- `typeText` — full SQL catalogString text. +- `typeName` — the enum. +- `typePrecision` — required for `DECIMAL`. +- `typeScale` — required for `DECIMAL`. +- `typeIntervalType` — for `INTERVAL`. +- `typeJson` — full JSON serialisation of the type. + +The shape mirrors Spark's `StructField.dataType` (which is a tree). The +six-field flat form is a wire encoding; in TS, a single `type` field of an +algebraic type would be clearer. + +**Suggested:** group into a sub-object: +```ts +export interface ColumnInfo { + type?: { + name?: ColumnTypeName; + text?: string; + precision?: number; + scale?: number; + intervalType?: string; + json?: string; + }; + // ... +} +``` + +**Flag at port time.** Wire-level decision. + +--- + +### 40. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) + +**Symbols:** `RowFilter.functionName?: string` (model.ts:689), +`RowFilter.inputColumnNames?: string[]` (model.ts:694), +`RowFilter.inputArguments?: PolicyFunctionArgument[]` (model.ts:700). + +**Issue:** Naming is consistent for arrays (`columnNames`, `arguments` — +both plural). But: +- `inputColumnNames` is **deprecated** per JSDoc ("This is the replacement + of the deprecated input_column_names field" — model.ts:697); the + replacement is `inputArguments`. +- The deprecated field name still exists in the TS surface and is + generated/marshalled. + +**Suggested:** mark `inputColumnNames` with `@deprecated`. Cross-reference +`ColumnMask.usingColumnNames` (model.ts:287) which has the same +deprecation note. + +--- + +### 41. `ColumnMask.usingArguments` vs `RowFilter.inputArguments` action-verb difference — category 17 (Inconsistent action verbs) + +**Symbols:** `ColumnMask.usingArguments?: PolicyFunctionArgument[]` +(model.ts:293), `RowFilter.inputArguments?: PolicyFunctionArgument[]` +(model.ts:700). + +**Issue:** Both fields have the same purpose (positional arguments to a +SQL UDF), the same type (`PolicyFunctionArgument[]`), and the same JSDoc +shape ("This is the replacement of the deprecated …_column_names field"). +But the verb prefix differs: `using…` for masks, `input…` for filters. + +**Suggested:** unify on one verb. `inputArguments` is more conventional +(matches "input parameters" common in DB systems). **Flag at port time.** + +--- + +### 42. `PolicyFunctionArgument.arg` field name is too short — category 1 (Vague/generic) + +**Symbol:** `PolicyFunctionArgument.arg` (model.ts:662). Discriminated +union of `column` / `constant`. + +**Issue:** `arg` is three letters — too short for a public field. The +proto source likely uses `oneof arg`; the generator preserves the field +name. Consumer writes: +```ts +if (positionalArg.arg?.$case === 'column') { ... } +``` + +Compare to `Dependency.value` (finding 36) and +`EncryptionDetails.encryptionDetailsType` (finding 37) — same pattern, +three different naming conventions. The `arg` here is the most cryptic. + +**Suggested:** `argument` (full word) or `kind`. + +--- + +### 43. `PrimaryKeyConstraint.childColumns` vs `ForeignKeyConstraint.childColumns` semantic mismatch — category 6 (Misleading names) and category 12 (Duplicate concepts) + +**Symbols:** `PrimaryKeyConstraint.childColumns?: string[]` +(model.ts:680), `ForeignKeyConstraint.childColumns?: string[]` +(model.ts:502). + +**Issue:** Both types use `childColumns` for "the columns of this table +participating in the constraint." But: +- For a primary key, "child" is wrong vocabulary — there's no parent. A + primary key has no parent table. +- For a foreign key, "child" matches the FK domain (child references + parent). `ForeignKeyConstraint` has both `childColumns` and + `parentColumns` (model.ts:506) — natural pair. + +The `PrimaryKeyConstraint.childColumns` field name is misleading — in PK +context, the columns are simply *the* columns. Cross-reference the wire +form `child_columns` (model.ts:1102, 1214) which inherits the same issue +from upstream. + +**Suggested:** rename `PrimaryKeyConstraint.childColumns` to +`PrimaryKeyConstraint.columns`. **Coordinate with protocol team.** + +--- + +### 44. `PrimaryKeyConstraint.timeseriesColumns` vs `ColumnMask.usingColumnNames` plural-vs-singular inconsistency — category 9 (Singular/plural mismatch) + +**Symbols:** `PrimaryKeyConstraint.timeseriesColumns?: string[]` +(model.ts:682), `ColumnMask.usingColumnNames?: string[]` (model.ts:287), +`ColumnMask.functionName?: string` (model.ts:281). + +**Issue:** Within the same file: +- `columns` (plural): `PrimaryKeyConstraint.childColumns`, + `PrimaryKeyConstraint.timeseriesColumns`, `ForeignKeyConstraint.childColumns`, + `ForeignKeyConstraint.parentColumns`. +- `columnNames` (plural with `Names`): `ColumnMask.usingColumnNames`, + `RowFilter.inputColumnNames`. + +Both refer to lists of column-name strings (`string[]`). The shape is +identical; the names differ in whether the `Names` suffix is included. + +**Suggested:** unify on one form. `columns` is shorter and matches the +constraint vocabulary; `columnNames` is more explicit but verbose. Pick +one. **Flag at port time.** + +--- + +### 45. `ForeignKeyConstraint.rely` boolean is cryptic — category 5 (Cryptic abbreviations) + +**Symbol:** `ForeignKeyConstraint.rely?: boolean | undefined` (model.ts:508). +JSDoc: "True if the constraint is RELY, false or unset if NORELY." + +**Issue:** "RELY" / "NORELY" are SQL keywords (Spark's `ALTER TABLE ... RELY` +hint). The JSDoc explains them; the field name alone is opaque. Same +critique applies to `PrimaryKeyConstraint.rely` (model.ts:684). + +**Suggested:** rename to `relyEnabled` or `enableRely` — the boolean form +needs an `is…` / `enable…` prefix to match SDK convention. **Coordinate +with protocol team.** + +--- + +### 46. `OptionSpec.isCopiable` typo or unusual spelling — category 5 (Cryptic abbreviations) and category 6 (Misleading names) + +**Symbol:** `OptionSpec.isCopiable?: boolean | undefined` (model.ts:649). +JSDoc: "Indicates whether an option should be displayed with copy button +on the UI." + +**Issue:** "Copiable" is an unusual spelling — the standard English forms +are "copyable" or "copy-able". The generator picked the less-common form +(likely from the upstream `.proto`). + +**Suggested:** `isCopyable`. Wire form `is_copiable` stays for back-compat. +**Coordinate with protocol team.** + +--- + +### 47. `OptionSpec` has 9 `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* + +**Symbols:** `OptionSpec.isRequired` (model.ts:635), +`OptionSpec.isSecret` (model.ts:637), `OptionSpec.isHidden` (model.ts:639), +`OptionSpec.isUpdatable` (model.ts:641), `OptionSpec.isLoggable` +(model.ts:645), `OptionSpec.isCreatable` (model.ts:647), +`OptionSpec.isCopiable` (model.ts:649). + +The boolean fields all use the `is…` prefix, which is the right convention +for booleans. **Pass on naming.** + +(The number of booleans on `OptionSpec` (7+) is itself a code smell — the +type packs configuration for a UI form, with each boolean controlling a +different aspect of display. A consumer struggling to set all of these +correctly may want a richer type. **Note for upstream.**) + +--- + +### 48. `ConditionalDisplay.dependsOnOption` vs `hiddenWhenValues` field naming asymmetry — category 17 (Inconsistent action verbs) + +**Symbols:** `ConditionalDisplay.dependsOnOption?: string` (model.ts:307), +`ConditionalDisplay.hiddenWhenValues?: string[]` (model.ts:313). + +**Issue:** Two fields modelling the same relation (option-A's value +determines option-B's visibility): +- `dependsOnOption` — singular, identifies the "watched" option. +- `hiddenWhenValues` — plural, the values that trigger hiding. + +The verb forms differ: "depends on…" vs. "hidden when…". A reader skimming +the type sees them as unrelated. The pair would be cleaner as e.g. +`{watchOption, hideOnValues}` or `{trigger: {option, hideOnValues}}`. + +**Suggested:** rename `dependsOnOption` to `watchOption` or +`triggerOption`. **Flag at port time.** + +--- + +### 49. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) + +**Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` +(model.ts:480). JSDoc: "Whether predictive optimization should be enabled +for this object and objects under it." + +**Issue:** The type's *purpose* is to indicate whether PO is enabled. The +field name `value` says nothing about that. The type is also a `string` +(not a `boolean`) — same problem as finding 26. + +**Suggested:** rename `value` → `enabled` (boolean) or `state` (matching +the JSDoc's "enabled" sense). **Coordinate with protocol team.** + +--- + +### 50. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) + +**Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` +(model.ts:482), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` +(model.ts:484). + +**Issue:** Two fields describing the source of inheritance — the object +type ("CATALOG"|"SCHEMA"|…) and the object's name. Naming is OK, but the +suffix pair `…Type` / `…Name` repeats inside one struct that has only +three fields. Could be folded: +```ts +inheritedFrom?: { type?: string; name?: string }; +``` + +**Suggested:** flatten to a sub-object. **Pass with note** — the current +flat form is wire-faithful. + +--- + +### 51. `TableConstraint.constraint` and `TableConstraint` discriminated-union shape — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) + +**Symbol:** `TableConstraint.constraint` (model.ts:739). + +**Issue:** Same problem as finding 37 (`EncryptionDetails.encryptionDetailsType`). +Field repeats the type name's primary token. The discriminated union of +three constraint shapes is wrapped in a field literally named `constraint`. + +**Suggested:** rename to a non-repeating field (`kind`, `variant`). + +--- + +### 52. `Client` class name — category 1 (Vague/generic) — *pass* + +Package convention. **Pass.** + +--- + +### 53. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* + +Standard `{verb}{Resource}` shape. Convention. **Pass.** + +(Note: `Client.tableExists` (client.ts:472) breaks the verb-first pattern — +it reads `noun-verb` instead of `verb-noun`. The corresponding shape in +other SDKs is `existsTable` or `checkTableExists`. The current form mirrors +the request type name `TableExists` which is itself unusual — see finding +21. **Flag at SDK-wide level.**) + +--- + +### 54. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* + +Same `{verb}{Resource}` pattern. **Pass.** + +--- + +### 55. `Client.listTableSummariesIter` / `listTablesIter` `Iter` suffix — category 14 (Go/Java-style names) + +**Symbols:** `Client.listTableSummariesIter` (client.ts:357), +`Client.listTablesIter` (client.ts:444). + +**Issue:** The `Iter` suffix is a Go-ism (Go's `…All()` / `…Iter()` +convention for paginated lists). In TS, the conventional name is +`listTablesAsyncIterator()` or simply `listTables()` returning an +`AsyncIterable`. The `Iter` suffix is also borderline cryptic. + +**Suggested:** `listAllTables` or simply have the non-iter version return +an `AsyncIterable`. The current dual API +(`listTables` + `listTablesIter`) is a Go-port artefact. + +**Flag for SDK-wide cleanup.** + +--- + +### 56. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* + +Standard. **Pass.** + +--- + +### 57. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) + +**Symbol:** `PACKAGE_SEGMENT` (client.ts:55). + +**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true +primitive constants (`MAX_LEN = 10`). `PACKAGE_SEGMENT` is a runtime +object literal `{ key, value }` constructed from a JSON import. The same +identifier is used in every package's `client.ts`. + +**Suggested:** `packageSegment` or `clientPackageSegment`. **Flag for +SDK-wide cleanup.** + +--- + +### 58. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) + +**Symbol:** `HttpCallOptions` (utils.ts:15). + +**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; +the file also imports `CallOptions` from `@databricks/sdk-options/call` +(utils.ts:12). Two `…CallOptions` types side by side, with one being the +HTTP-layer context and the other the public retry/rate-limit options. + +**Suggested:** `HttpRequestContext` or `ExecuteHttpArgs`. **Flag for +SDK-wide cleanup** — generated boilerplate. + +--- + +### 59. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) + +**Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). + +**Issue:** Two functions named `execute…Call` that operate at different +layers. The names imply a hierarchical relationship that does not exist. + +**Suggested:** rename `executeHttpCall` to `sendAndDecode` or +`doHttpRequest`. **Flag for SDK-wide cleanup.** + +--- + +### 60. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) and category 14 (Go/Java-style names) + +**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). + +**Issue:** Two symmetric operations with verbs from two vocabularies — +"parse" is TS/JS, "marshal" is Go. Internally consistent verb-pair would +be `parseResponse` / `serializeRequest` or `unmarshalResponse` / +`marshalRequest`. + +**Suggested:** `serializeRequest` and `parseResponse` (TS-native). **Flag +for SDK-wide consistency.** + +--- + +### 61. `unmarshal*` / `marshal*` Go vocabulary — category 14 (Go/Java-style names) + +**Symbols:** All 50+ Zod schemas (e.g. `unmarshalColumnInfoSchema`, +`marshalCreateTableSchema`). + +**Issue:** "Marshal" / "unmarshal" is Go-ism vocabulary. TS/JS use +"serialize" / "deserialize" or "parse" / "stringify". The whole SDK uses +the Go convention. + +**Suggested:** `serialize*Schema` / `parse*Schema` (TS-native). **Flag for +SDK-wide cleanup, not this package alone.** + +The `*Schema` suffix is also redundant — the value's type is +`z.ZodType<…>` and there are no non-schema cousins. `parseColumnInfo` / +`serializeColumnInfo` would suffice. **Pass with note.** + +--- + +### 62. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* + +Verb-prefixed. Naming is fine. `flattenQueryParams` is used by the +multi-query-param list methods (client.ts:357, 444). + +(Cross-check: this package *does* use `flattenQueryParams` indirectly via +the manual `URLSearchParams` construction in `listTables`/`listTableSummaries` +client.ts:311/393. Hmm, actually it doesn't import the helper. Manual +construction with `params.append(...)` is duplicated 14 times across the +file.) + +--- + +### 63. `index.ts` re-exports underscored type names — category 4 (Underscores in TS identifiers) + +**Symbols:** index.ts re-exports include `CreateTable_PropertiesEntry`, +`DeleteTable_Response`, `DeleteTableConstraint_Response`, +`DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry`, +`ListTableSummaries_Response`, `ListTables_Response`, `TableExists_Response`, +`TableInfo_PropertiesEntry`, `UpdateTable_PropertiesEntry`, +`UpdateTable_Response`, `OptionSpec_OauthStage`, `OptionSpec_OptionType`. + +**Issue:** Twelve public-API exports carry an `_` in their name. Consumers +see the underscored names in auto-imports, in violation of the Google TS +Style Guide § 5.3 and the project's lint rule on identifiers. + +**Suggested:** rename to the underscore-free `UpperCamelCase` form (e.g. +`CreateTablePropertiesEntry`, `DeleteTableResponse`, `OptionSpecOauthStage`). +**Flag for generator cleanup.** + +--- + +### 64. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* + +Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, +`TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide +pattern. **Pass.** + +--- + +### 65. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`, `'volume'`, `'secret'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* + +**Symbols:** `Dependency.value.$case` literals (model.ts:455–467). + +**Issue:** The six `$case` literals are plain nouns. Within the file: +- `TableConstraint.constraint.$case` literals (model.ts:741, 745, 749) are + `'primaryKeyConstraint'` / `'foreignKeyConstraint'` / `'namedTableConstraint'` — + i.e. *suffixed* with `Constraint`. +- `EncryptionDetails.encryptionDetailsType.$case` literal (model.ts:491) is + `'sseEncryptionDetails'` — suffixed with `Details`. +- `PolicyFunctionArgument.arg.$case` literals (model.ts:664, 669) are + `'column'` / `'constant'` — plain nouns, like `Dependency.value`. + +So **four discriminated unions, two different naming conventions** for +their $case literals. + +**Suggested:** unify on one form. `Dependency`'s short-form literals +(plain nouns) are the cleanest — apply elsewhere. **Flag at port time.** + +--- + +### 66. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* + +**Symbol:** `parseResponse` (utils.ts:113) does `JSON.parse(text)` +unconditionally. The name implies it can handle any response shape; in +practice it only handles JSON. + +**Suggested:** rename `parseJsonResponse` to set caller expectations. +**Pass — generated boilerplate.** + +--- + +## Cross-package alignment recommendations + +### A. `Dependency` family duplicated in three packages + +`tables`, `functions`, and `registeredmodels` each export the same eight +types: `Dependency`, `DependencyList`, `TableDependency`, `FunctionDependency`, +`ConnectionDependency`, `CredentialDependency`, `VolumeDependency`, +`SecretDependency`. Same shape, same fields, three copies. Strong P0 +candidate for hoisting to `@databricks/sdk-core/dependency`. + +--- + +### B. `EncryptionDetails` / `SseEncryptionAlgorithm` / `SseEncryptionDetails` duplicated in three packages + +`tables`, `volumes`, and `externallocations` each define the same encryption +types with the same fields and the same enum values. Three copies. + +**Suggested:** hoist to `@databricks/sdk-core/encryption` or +`@databricks/sdk-core/storage`. + +--- + +### C. `SecurableType` defined in 5+ packages + +`tables`, `catalogs`, `connections`, plus the unaudited +`grants`/`abacpolicies`/etc. Same 17 values, same names. + +**Suggested:** hoist to `@databricks/sdk-core/securable`. + +--- + +### D. `EffectivePredictiveOptimizationFlag` defined in `tables` and `catalogs` + +`catalogs/v1/model.ts:240` defines the same type as +`tables/v1/model.ts:478`. Three fields (`value`, `inheritedFromType`, +`inheritedFromName`). + +**Suggested:** hoist or pick a canonical home. + +--- + +### E. `ColumnTypeName` defined in `tables` and `functions` + +`functions/v1/model.ts:5` defines the same enum. 27 SQL/Spark data-type +values shared. + +**Suggested:** hoist to `@databricks/sdk-core/sql-types`. + +--- + +### F. `RowFilter` / `ColumnMask` vs. `abacpolicies.RowFilterOptions` / `abacpolicies.ColumnMaskOptions` shape divergence + +`tables/v1/model.ts:687` defines `RowFilter` and `tables/v1/model.ts:279` +defines `ColumnMask`. `abacpolicies/v1/model.ts:38, 295` defines +`ColumnMaskOptions` / `RowFilterOptions`. Same domain, different shapes +and naming. + +**Suggested:** harmonise. + +--- + +### G. `fullNameArg` Go-style argument suffix used across many packages + +`tables`, `schemas`, `functions`, `registeredmodels` all use the `Arg` +suffix on URL-path arguments. Drop SDK-wide. + +--- + +### H. Three-tier table-type confusion + +This package, `onlinetables`, `database`, `postgres`, and `featurestore` +all model "table" concepts at different layers: +- `tables.TableType` (model.ts:209) — 9 values for UC table classifications. +- `tables.SecurableKind` (model.ts:81) — 70+ values, mostly `TABLE_*` + prefixes for finer-grained UC kinds. +- `onlinetables.OnlineTableState` — the lifecycle/sync state of an + online table (overlaps with `TableType.MATERIALIZED_VIEW`, + `STREAMING_TABLE`). +- `database.SyncedTableState`, `postgres.SyncedTableState` — same as + `OnlineTableState`, renamed. + +The relationships between `TableType.MATERIALIZED_VIEW`, +`SecurableKind.TABLE_MATERIALIZED_VIEW`, `OnlineTableState.ONLINE`, etc., +are non-obvious without reading the JSDoc on each enum. **SDK-wide +documentation pass needed.** + +--- + +## Counts by severity + +| Severity | Count | Findings | +| -------- | ----- | -------- | +| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics) | 16 | #1, #2, #3, #10, #11, #20, #23, #24, #26, #28, #35, #36, #43, #49, #57, #63 | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 26 | #4, #5, #6, #7, #9, #13, #14, #15, #16, #18, #19, #21, #22, #25, #27, #30, #31, #33, #34, #37, #39, #40, #41, #45, #48, #51 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 14 | #8, #12, #29, #42, #44, #46, #50, #55, #58, #59, #60, #61, #65, #66 | +| **Pass / acceptable** | 10 | #17, #32, #38, #47, #52, #53, #54, #56, #62, #64 | + +--- + +## Top fixes (highest local return) + +1. **#2 / #63** — drop the underscored `*_PropertiesEntry` / `*_Response` + type names from the public surface. Removes lint suppressions and + eliminates the proto-style naming. +2. **#3** — fix `DeltaRuntimePropertiesKvpairs` (field) / + `DeltaRuntimePropertiesKvPairs` (type) casing mismatch. Local, mechanical + rename. +3. **#20** — drop the `Arg` suffix from `fullNameArg` SDK-wide. Higher + impact (changes wire field name) but eliminates a Go-style convention. +4. **#26** — type `enablePredictiveOptimization` as a real enum instead of + a free-form string. Improves type safety. +5. **#36 / #37 / #42 / #51** — unify discriminated-union container field + names (`value` vs `encryptionDetailsType` vs `arg` vs `constraint`). + Within-file consistency fix. +6. **#34** — rename `ListTableSummaries_Response.tables` to `summaries` + (or `tableSummaries`). Easy local fix. +7. **#11 / #12** — `SecurableKind` SCREAMING_SNAKE → UpperCamelCase on TS + side. Local mechanical change (does not affect wire compatibility if + string values are kept). diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md new file mode 100644 index 00000000..635a433f --- /dev/null +++ b/.agent/naming-audit/tagassignments.md @@ -0,0 +1,244 @@ +# Naming Audit: tagassignments + +**Path:** `packages/tagassignments/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. +**Total weird names flagged:** 35 + +## Summary +| Severity | Count | +| --- | --- | +| High | 11 | +| Medium | 13 | +| Low | 6 | +| Observation | 5 | + +## High severity + +### 1. Package directory `tagassignments` vs. sister `entitytagassignments` and wire path `/entity-tag-assignments` — `package directory name` +- **Why weird:** This package is called `tagassignments` (no `entity` prefix). Its sister `entitytagassignments` shares the same wire path *prefix* and the same five operations. But its own HTTP path (line `client.ts:71`) is `/api/2.0/entity-tag-assignments` — so this package is named *without* `entity` even though the URL is *with* `entity`. The sister package is named *with* `entity` and its URL is `/api/2.1/unity-catalog/entity-tag-assignments`. The directory tokens do not predict the wire shape. Worse, both packages have a `Client` and the resource shape `(entityType, entityId-or-name, tagKey, tagValue)` is conceptually identical — only the entity universe (UC vs. apps/dashboards/etc.) differs. +- **Category:** 12 (duplicate concept across two packages), 1 (vague — what does `tagassignments` mean without `entity`?), 6 (misleading — name suggests "any tag assignment" but the package only covers four platform entity kinds). +- **Suggested name:** Rename to `platformtagassignments` or `appdashtags` to mark the scope, while renaming the sister `entitytagassignments` to `uctagassignments`. Alternatively, merge both into a unified `tagassignments` package with a discriminating `entityKind` field. +- **Rationale:** Two sister packages whose names diverge from their wire paths force users to memorize a name-to-API mapping. Without `entity` in this directory, the type `TagAssignment` here and `EntityTagAssignment` there look like different kinds of objects when they are not. Generator-level concern. + +### 2. `TagAssignment` field shape vs. sister `EntityTagAssignment` shape — `src/v1/model.ts:46-55` vs. `entitytagassignments/src/v1/model.ts:32-49` +- **Why weird:** The two sister types model the same conceptual object using divergent identifiers. This package has `entityId: string` (with doc "For apps, the entity_id is the app name"). Sister has `entityName: string` (with doc "fully qualified name"). The wire-side names are `entity_id` vs. `entity_name`. The doc for `entityId` admits it can be a name — so it is sometimes an id and sometimes a name. A user porting code between the two packages must change every field reference even though the data is the same. +- **Category:** 12 (duplicate concept with divergent naming), 17 (inconsistency between siblings), 16 (field name contradicts type domain — calling it `entityId` when it is "the app name" is misleading). +- **Suggested name:** Unify on `entityRef`, `entity`, or `entityKey` for both packages. At minimum, rename one to match the other. The doc-confessed "id is actually a name" case is exactly why a neutral identifier name is needed. +- **Rationale:** Splitting "name vs id" by sister package, when both fields hold the same logical thing (an entity identifier — sometimes literally a name), is poor cross-package developer experience. + +### 3. `TagAssignment` — `src/v1/model.ts:46` +- **Why weird:** The primary type `TagAssignment` is a tag assigned to an *entity* — every field on it (`entityType`, `entityId`, `tagKey`, `tagValue`) presupposes an entity. The name says "tag assignment" but the type really is "entity tag assignment". Yet sister package `entitytagassignments` does include the `Entity` prefix on its type. So the SDK has both `TagAssignment` and `EntityTagAssignment` for the same conceptual shape. +- **Category:** 1 (vague — assignment to what?), 12 (duplicate concept naming across siblings), 16 (no `Entity` prefix when sister package has it for the same concept). +- **Suggested name:** Either pick `EntityTagAssignment` here too (and rename type-collisions out at re-export), or rename the sister to drop `Entity` and use package-scoped imports. Pick one. +- **Rationale:** The naming asymmetry between sister types is the actual bug. Both should be the same name, with disambiguation via import. + +### 4. `entityType: string` — `src/v1/model.ts:13,22,31,48` +- **Why weird:** Four occurrences of `entityType?: string | undefined`. The JSDoc lists allowed values inline: "apps, dashboards, geniespaces, notebooks". A closed set of four values lives in plain prose, not in the type. Users will pass typos with no compile-time check. +- **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what values are valid?), 6 (misleading — looks free-form, is actually constrained), 16 (field contradicts type — closed set typed as open string). +- **Suggested name:** Introduce `EntityKind = 'apps' | 'dashboards' | 'geniespaces' | 'notebooks'` and type the field as `entityKind?: EntityKind`. `Kind` reads cleaner than `Type` in TS (cf. `SyntaxKind` in TS compiler API). +- **Rationale:** The valid set is closed and documented; the type should reflect that. Generator anti-pattern: stringly-typed enums. + +### 5. `entityId: string` doc inconsistency — `src/v1/model.ts:15,23,33,49` +- **Why weird:** Four occurrences of `entityId?: string | undefined`. The JSDoc reads: "The identifier of the entity to which the tag is assigned. For apps, the entity_id is the app name." So `entityId` is sometimes a name, sometimes an id, and the doc carves out one of the four entity kinds explicitly. There is no rule for what `entityId` looks like for `dashboards`/`geniespaces`/`notebooks`. +- **Category:** 6 (misleading — labelled `Id` but is "the app name" for apps), 19 (underspecified — what does it look like for the other three kinds?), 16 (field contradicts type domain — "id" suggests an opaque handle, but for apps it is a human-readable name). +- **Suggested name:** `entityRef` or `entity` (neutral). Combined with `EntityKind` from #4, the meaning of `entityRef` is "the identifier appropriate for this kind". +- **Rationale:** A field whose semantics changes per `entityType` should not be named after one of those semantics. + +### 6. `Client` class — `src/v1/client.ts:41` +- **Why weird:** A class literally named `Client` re-exported through `index.ts:3` as plain `Client`. Sister packages `entitytagassignments` and `tagpolicies` ship `Client` classes of the same name. Three `Client`s across the tag-related sibling packages. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name losing meaning), 12 (duplicate concept across sister packages). +- **Suggested name:** `TagAssignmentsClient`. Forces aliasing only when co-imported, but reads as "the client for the tag-assignments surface". +- **Rationale:** Three `Client`s in three sister packages will collide on combined imports. + +### 7. `createTagAssignment` / `deleteTagAssignment` / `getTagAssignment` / `listTagAssignments` / `updateTagAssignment` method names — `src/v1/client.ts:67,93,112,137,188` +- **Why weird:** Every method repeats the package's subject in the identifier. `client.createTagAssignment(...)` on a `Client` whose only job is tag assignments reads as "package.subject.create.subject". Sister package does the same with `createEntityTagAssignment`. +- **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `TagAssignment` on every method when the client only manages `TagAssignment`). +- **Suggested name:** `create`, `delete`, `get`, `list`, `update`, `listIter` (drop the noun). Or `createAssignment` / `deleteAssignment` if the noun is desired. +- **Rationale:** Single-purpose clients should not repeat the subject. `TagAssignmentsClient.create()` reads cleaner. + +### 8. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` +- **Why weird:** Same concept, two different field names across sister packages. This package: `pageSize?: number`. Sister: `maxResults?: number`. The wire-side names also diverge (`page_size` here, `max_results` there). Within a single SDK, the page-size parameter has two names depending on which tag flavor you use. +- **Category:** 12 (duplicate concept named differently across siblings), 17 (inconsistency between sibling fields). +- **Suggested name:** Pick one. `pageSize` is the more conventional name (matches `nextPageToken` here). `maxResults` is older. +- **Rationale:** Cross-SDK pagination naming consistency. Worth flagging upstream — generator-wide concern. + +### 9. `tagKey` and `tagValue` on `TagAssignment` — `src/v1/model.ts:52,54` +- **Why weird:** The type is `TagAssignment` and the fields are `tagKey`/`tagValue`. Inside a `TagAssignment`, the `tag` prefix is redundant: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. Same in sister packages. +- **Category:** 8 (redundant prefix — `tag` within `TagAssignment`). +- **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. +- **Rationale:** Fields should not re-state their container's noun. `assignment.key` reads cleaner. + +### 10. `tagKey` validation rules in doc but not type — `src/v1/model.ts:17,26,52` +- **Why weird:** The JSDoc reads: "The key of the tag. The characters `,` `.` `:` `/` `-` `=` and leading/trailing spaces are not allowed". This is a strict character-class constraint that lives in prose, not in the type. The TS type is just `string`. A user concatenating `${prefix}.${name}` produces an invalid `tagKey` with no compile-time signal. +- **Category:** 6 (misleading — type permits values that the API rejects), 19 (underspecified ID). +- **Suggested name:** Keep `tagKey: string` but document the constraint in a way the generator could surface (e.g. via a `TagKey` branded type). At minimum, both `Create` and `Get`/`Delete` request docs should be consistent. +- **Rationale:** Validation rules in JSDoc only are an asymmetric SDK contract. + +### 11. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` +- **Why weird:** The list URL is `/api/2.0/entity-tag-assignments/${entityType ?? ''}/${entityId ?? ''}/tags`. When either is undefined, the URL becomes `.../entity-tag-assignments///tags`. Both fields are typed `string | undefined`, but `entityType` and `entityId` are clearly required to address an entity. Same issue on `Get`/`Delete`/`Update`. The SDK silently produces malformed URLs. +- **Category:** 6 (misleading — optional in type but required in practice). +- **Suggested name:** Make path-component fields required (non-optional) on the request types. +- **Rationale:** The shape `req.entityType ?? ''` betrays the contract: nullable input cannot legally produce a valid URL. Generator-wide concern. + +## Medium severity + +### 12. `CreateTagAssignmentRequest` etc. — five request DTOs share a 17-char prefix — `src/v1/model.ts:7,11,20,29,57` +- **Why weird:** `CreateTagAssignmentRequest`, `DeleteTagAssignmentRequest`, `GetTagAssignmentRequest`, `ListTagAssignmentsRequest`, `UpdateTagAssignmentRequest`. Every request type re-states `TagAssignment` in a package whose only subject *is* the tag assignment. +- **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). +- **Suggested name:** `CreateRequest`, `DeleteRequest`, `GetRequest`, `ListRequest`, `UpdateRequest`. Or drop the noun. +- **Rationale:** Single-subject packages do not need to repeat the subject on every request DTO. + +### 13. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` +- **Why weird:** The plural appears only on list types. The HTTP resource on the wire is `/entity-tag-assignments` (plural) while the item type is singular `TagAssignment`. List response is `ListTagAssignmentsResponse` (plural). +- **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). +- **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. +- **Rationale:** Rule 9 demands the flag even when intentional. + +### 14. `tagAssignmentFieldMask` / `tagAssignmentFieldMaskSchema` — `src/v1/model.ts:103,110` +- **Why weird:** A function and a lookup table share a stem and differ only by the `Schema` suffix. The function reads as a noun (no verb). 28+ characters. Compare sister `entityTagAssignmentFieldMask`. +- **Category:** 17 (function and noun share the same stem), 7 (overly verbose). +- **Suggested name:** `buildTagAssignmentFieldMask(...)` (verb-prefixed), or shorten to `fieldMask(...)` (the surrounding package and `TagAssignment` generic do the rest). +- **Rationale:** Functions should be verb-prefixed; otherwise they read as nouns. Generator-wide concern. + +### 15. `marshalTagAssignmentSchema` / `unmarshalTagAssignmentSchema` / `unmarshalListTagAssignmentsResponseSchema` — `src/v1/model.ts:62,75,89` +- **Why weird:** These are Zod schemas (47-char identifier on `unmarshalListTagAssignmentsResponseSchema`) using Go verbs `marshal`/`unmarshal`. TS reaches for `serialize`/`parse` or Zod's own `.parse()`. The TS-Go vocab mix is jarring; Zod schemas already have `.parse()`. +- **Category:** 14 (Go-style verbs in TS code), 17 (verb inconsistency with Zod's `.parse()`). +- **Suggested name:** `encodeTagAssignment` / `decodeTagAssignment` / `decodeListResponse`. Or drop `Schema` since the value *is* a Zod schema. +- **Rationale:** `marshal`/`unmarshal` is Go vocabulary; this is a TS file with Zod. Generator-wide concern. + +### 16. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions named "execute". `executeCall` wraps retry/rate-limit policy; `executeHttpCall` does the actual HTTP send. In every client method both appear: + ```ts + const call: Call = async (callSignal?: AbortSignal): Promise => { + ... + const respBody = await executeHttpCall({...}); + }; + await executeCall(call, options); + ``` + Names do not reveal the layering. +- **Category:** 1 (vague), 12 (duplicate concept — both "execute"), 17 (inconsistent layering name). +- **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. +- **Rationale:** Layering should be readable from names. Generator-wide concern. + +### 17. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` +- **Why weird:** Variable `call` of type `Call`, passed to `executeCall`. Same word as variable, type, and verb. Inside one method scope we have `req`, `call`, `httpReq`, `resp` — four roles, three of which abbreviate. +- **Category:** 1 (vague), 12 (duplicate concept), 4 (no underscore — but the name collision compensates). +- **Suggested name:** `runRequest`/`sendRequest` for the variable; keep `Call` as the type. +- **Rationale:** Variable-type collisions are tolerable but obscure prose. + +### 18. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` +- **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. +- **Category:** 6 (misleading — silent malformed URLs). +- **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. +- **Rationale:** See #11. Generator-wide concern. + +### 19. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` +- **Why weird:** `respBody: Uint8Array` and `resp: TagAssignment` differ only by suffix. Both abbreviate "response"; the reader must remember which is bytes and which is parsed. There is no `reqBody` sibling for symmetry. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — only response abbreviates with `Body`). +- **Suggested name:** `rawBody`/`result`, or `responseBytes`/`response`. +- **Rationale:** Stage differences should be communicated by meaningful nouns, not suffix variations. + +### 20. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` +- **Why weird:** Inside methods that already have `req: `, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. +- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). +- **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. +- **Rationale:** Forking the same identifier across layers is hard to read. + +### 21. `pageReq` in `listTagAssignmentsIter` — `src/v1/client.ts:174` +- **Why weird:** Inside `listTagAssignmentsIter`, a clone of `req` is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; outer `req` is the parameter. +- **Category:** 5 (cryptic), 8 (redundant prefix — `page` on a paginated iter is implicit). +- **Suggested name:** `current` or `cursor` (describes its role as iterator state). +- **Rationale:** A variable that mutates a clone of the input should describe its role. + +### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. +- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal bags should not be called `Options`). +- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. +- **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. + +### 23. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` +- **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. +- **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern). +- **Suggested name:** `makeHttpRequest` or inline at call sites. +- **Rationale:** "Build" carries Java/JS Builder-pattern connotations. + +### 24. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` +- **Why weird:** Takes `unknown` value plus Zod schema; returns JSON string. The name says "Request" but the function works for any payload. +- **Category:** 1 (vague — `Request` does not constrain), 6 (misleading — works for any payload). +- **Suggested name:** `marshalToJson` / `encodeToJson`. +- **Rationale:** Function name should reflect actual function. Same problem in sister packages. + +## Low severity + +### 25. `parseResponse(body, schema)` — `src/v1/utils.ts:113` +- **Why weird:** Symmetric to `marshalRequest`. Parses any JSON `Uint8Array` against a Zod schema; "Response" in the name does not constrain. +- **Category:** 1 (vague), 6 (misleading). +- **Suggested name:** `parseJsonBody` / `decodeFromJson`. +- **Rationale:** Asymmetric verb pair `marshal`/`parse` AND inaccurate naming. + +### 26. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Exported but unused in `client.ts`. This package's `listTagAssignments` uses individual `params.append(...)` calls (line 142-148) instead. Dead-shaped helper in shared scaffolding. +- **Category:** 6 (misleading — implies the package uses it). +- **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. +- **Rationale:** Generator-wide concern: every package duplicates this helper. + +### 27. `readAll(body)` — `src/v1/utils.ts:40` +- **Why weird:** `readAll` is too generic; the function specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". +- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). +- **Suggested name:** `drainStream` or `readStreamToUint8Array`. +- **Rationale:** Reads like it might take a file path or array. + +### 28. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The single word "segment" provides no domain context. +- **Category:** 1 (vague — `Segment` of what?). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. +- **Rationale:** Comment above the constant does the work the name should. + +### 29. `tagValue` field doc empty — `src/v1/model.ts:53,54` +- **Why weird:** `tagValue?: string | undefined` is documented as "The value of the tag" — a tautology. Compare the rich docs on `entityType`/`entityId`/`tagKey` (with character-class rules). The doc is doing zero work. +- **Category:** 1 (vague — doc says nothing the field name does not), 15 (generic field doc). +- **Suggested name:** Document what makes a `tagValue` valid (max length? character set? same restrictions as `tagKey`?). +- **Rationale:** Asymmetric documentation: three fields have rules, one is silent. + +### 30. `tagAssignments` vs. `nextPageToken` field-naming style on `ListTagAssignmentsResponse` — `src/v1/model.ts:41,43` +- **Why weird:** Response has `tagAssignments?: TagAssignment[] | undefined` and `nextPageToken?: string | undefined`. The latter is consistent with the convention (`nextPageToken`), the former carries the redundant `tag` prefix on the array of a `TagAssignment[]`. Inside the response type, `assignments?: TagAssignment[]` would also unambiguously be a list of tag assignments. +- **Category:** 8 (redundant prefix — `tag` within a TagAssignment array). +- **Suggested name:** `assignments` (drop the `tag` prefix). Wire stays `tag_assignments`. +- **Rationale:** Field names should not duplicate their element-type's noun. + +## Observations + +### 31. Wire/TS divergence dominates the file +The `model.ts` file is 115 lines for ~7 user-facing types; ~50 lines are `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as sister packages. + +### 32. Action verb consistency +The client uses `create`/`get`/`update`/`delete`/`list`/`listIter` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. + +### 33. Acronym casing +The file uses `HttpRequest`/`HttpResponse`/`HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. +- **Category:** 3 (acronym casing — consistent within file, ecosystem-divergent overall). + +### 34. `tagassignments` lowercase package name vs. types and HTTP path +The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. +- **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). + +### 35. Domain leakage between sister packages +Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. +- **Category:** 12 (duplicate concept across siblings). + +## Domain glossary +- `entity` — a Databricks platform resource being tagged. In this package, restricted to `apps`, `dashboards`, `geniespaces`, `notebooks` (per the JSDoc). +- `entity type` — string discriminator naming the kind of entity (closed set of 4 values, typed as open string). +- `entity id` — identifier of the entity. For apps, this is the app name. For the other three kinds, not documented in this package. +- `tag key` — string with character-class restrictions (no `,` `.` `:` `/` `-` `=` and no leading/trailing spaces). +- `tag value` — string with no documented constraints in this file. +- `tag assignment` — the (entityType, entityId, tagKey) -> tagValue triple. +- `tag policy` — a separate governed-tag concept; see sister package `tagpolicies`. +- `unity catalog entity tag assignment` — a separate but conceptually identical assignment over UC entities; see sister package `entitytagassignments`. + +## File coverage +- `src/v1/model.ts` (115 lines): read fully. +- `src/v1/client.ts` (224 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md new file mode 100644 index 00000000..3fa19c19 --- /dev/null +++ b/.agent/naming-audit/tagpolicies.md @@ -0,0 +1,249 @@ +# Naming Audit: tagpolicies + +**Path:** `packages/tagpolicies/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and optional `propagationConfig` (with conflict-resolution rules) so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. +**Total weird names flagged:** 37 + +## Summary +| Severity | Count | +| --- | --- | +| High | 8 | +| Medium | 13 | +| Low | 11 | +| Observation | 5 | + +## High severity + +### 1. Three sister packages (`tagpolicies`, `tagassignments`, `entitytagassignments`) split the noun "tag" — package directory name +- **Why weird:** Three sibling packages each carry one slice of the "tag" domain — definitions (this package), assignments to platform entities (`tagassignments`), assignments to Unity Catalog entities (`entitytagassignments`) — and each ships its own `Client` class, its own primary type, and its own `tagKey` field. A user who wants to "manage tags" must import three packages and alias three `Client`s. The split mirrors backend RPC groupings, not a user mental model. +- **Category:** 12 (duplicate concept split across three packages), 1 (`tag*` as a package-name fragment is vague — which slice of tags?). +- **Suggested name:** Merge into a single `tags` (or `taxonomy`) package with sub-namespaces `tags.policies`, `tags.assignments.platform`, `tags.assignments.uc`. As a smaller fix, rename to `governedtags` (this package) and `governedtagvalues` (or similar) to make the role explicit. +- **Rationale:** Three `Client`s in three packages collide on combined imports. The user-facing surface should follow the user mental model ("I want to manage tags"), not the wire-side `/api/2.1/tag-policies` vs. `/api/2.0/tag-assignments` vs. `/api/2.1/unity-catalog/entity-tag-assignments` partition. Worth flagging as a generator-level structural concern. + +### 2. `TagPolicy` — `src/v1/model.ts:62` +- **Why weird:** The primary type is "a policy for a tag", which is fine — but the type is keyed by `tagKey` (line 63) and the package is *named* after the tag's policy. Every reference is "the tag policy's tag key", "the tag policy's account ID", "the tag policy's values". The `Tag` prefix on the type is doing the work that the package directory already does. Sister types `TagAssignment` / `EntityTagAssignment` repeat the `Tag` noun identically. The name reads like Go. +- **Category:** 8 (redundant prefix — `Tag` repeats the universal subject of this package), 12 (duplicate concept naming pattern with sister types), 14 (Go-style — Go SDK needs the `Tag` prefix to distinguish from other `Policy` structs in the same Go package; TS module imports already do that disambiguation). +- **Suggested name:** `Policy` (rely on package-import disambiguation), or `GovernedTag` (since "governed" is the term used throughout the JSDoc — `client.ts:66,92,111,136,187`). +- **Rationale:** "Governed tag" is the canonical domain term that appears in every method's docstring; "tag policy" is the wire/proto-side term. SDK should expose the domain term. + +### 3. Doubled `Policy` suffix in the conflict-resolution path — `src/v1/model.ts:9,11,13` +- **Why weird:** The outer type is `ConflictResolutionPolicy`, its field is named `policy`, and the only case-payload type is `DefaultValueOverridePolicy`. The token "policy" appears on the outer type, on the field, and on the payload — three uses of "Policy" in one tree to express "use this default when there's a conflict". +- **Category:** 8 (redundant suffix — `Policy` appears on the outer type, on the field, and on the payload), 20 (type-suffix tautology — `Policy` on the field of a `*Policy` of a `*Policy`). +- **Suggested name:** Drop one of the three. For example, rename the outer type to `ConflictResolution`, the field to `strategy`, and the payload to `DefaultValueOverride`. +- **Rationale:** `propagationConfig.conflictResolution.policy.$case === 'defaultValueOverride'` reads as type-noise; reducing the `Policy` repetition makes the path read naturally. + +### 4. `Client` class — `src/v1/client.ts:41` +- **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The sister packages (`tagassignments`, `entitytagassignments`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages, plus this `Client` in the rest of the SDK's ~70 other packages. +- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages and the entire SDK). +- **Suggested name:** `TagPoliciesClient` (matches the package name) or `GovernedTagsClient` (matches domain language). +- **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing on every co-use (`import {Client as TagPoliciesClient} from '@databricks/sdk-tagpolicies'`). Generator-level concern. + +### 5. Method names `createTagPolicy` / `deleteTagPolicy` / `getTagPolicy` / `listTagPolicies` / `updateTagPolicy` — `src/v1/client.ts:67,93,112,137,188` +- **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createTagPolicy(...)` reads as "package.subject.create.subject" — the noun is doubled. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. Sister packages do the same. +- **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `TagPolicy` five times when the client only manages `TagPolicy`). +- **Suggested name:** `create`, `delete`, `get`, `list`, `update` (and `listIter`). +- **Rationale:** A client class that ships exactly five methods all named after the same subject is repeating the subject. `TagPoliciesClient.create()` reads better than `client.createTagPolicy()`. + +### 6. `tagKey` is both the resource identifier and a field on `TagPolicy` — `src/v1/model.ts:63` and `model.ts:31,35` +- **Why weird:** The thing that uniquely identifies a `TagPolicy` is its `tagKey` (string), but the same type *also* has an `id: string` field (`model.ts:64`). The wire URL is `/api/2.1/tag-policies/{tagKey}` — i.e., the path key is `tagKey`, not `id`. Two identifiers, no JSDoc saying which one is authoritative. Compare to `BudgetPolicy` (`policyId`, `policyName`) which has the same split — same problem. +- **Category:** 1 (vague — which field actually identifies the resource?), 6 (misleading — `id` looks like a primary key, but the URL uses `tagKey`), 19 (underspecified ID — what does `id` mean if the path uses `tagKey`?), 16 (field contradicts type domain). +- **Suggested name:** Document both fields explicitly. `tagKey` is the user-chosen primary key (the tag name itself); `id` is presumably an opaque server-generated handle. Suggest: keep both but JSDoc each, OR collapse to just `tagKey` if `id` is dead. +- **Rationale:** Two unlabeled IDs in a type is a recipe for caller confusion. The SDK should make plain which is the resource key. + +### 7. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:31,35` +- **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${this.host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:97,116`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). +- **Category:** 6 (misleading — type says optional, semantics says required), 19 (underspecified ID — what should `tagKey` look like? Constraints? Encoding?). +- **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) on get/delete/update. Add JSDoc describing valid keys. +- **Rationale:** Optional path parameters in REST clients are a generator anti-pattern. Honest required-ness should travel through the type, not through a `?? ''` fallback that produces a malformed URL. + +### 8. `Value.name` field — `src/v1/model.ts:83` +- **Why weird:** Field on `Value` is `name?: string | undefined` (line 83), but conceptually the field holds the *value text* of an allowed tag value (e.g., `"prod"`, `"dev"`). Calling that text `name` collides with the domain meaning of "tag value": the value's `name` is the value. JSDoc is empty. There is no `displayName` or other field to disambiguate — `name` is the *only* field. +- **Category:** 1 (vague/generic — `name` for a string that is the value itself), 6 (misleading — `name` suggests a label distinct from the value), 15 (generic field name losing meaning), 16 (field name contradicts type domain — `Value.name` reads "the name of a value", but the value's name *is* the value). +- **Suggested name:** Rename to `Value.value` (still awkward) or `AllowedValue.text`. +- **Rationale:** `tagPolicy.values[0].name` reads as "the name of the first value of this tag policy", which is structurally absurd. + +## Medium severity + +### 9. `PropagationConfig` type — `src/v1/model.ts:55` +- **Why weird:** The type's two fields (`enabled?: boolean`, `conflictResolution?: ConflictResolutionPolicy`) describe how a tag's *value* propagates through lineage. The name `PropagationConfig` is generic — any system can have a propagation config. The JSDoc context "automatically propagated through data lineage" disappears once a user lands on the type. +- **Category:** 1 (vague — `PropagationConfig` could mean anything), 15 (generic name losing meaning), 20 (type-suffix tautology — `Config` on a config-shaped struct). +- **Suggested name:** `LineagePropagation` (carries the domain), `TagPropagation`, or `TagPolicyPropagation`. +- **Rationale:** Bare `PropagationConfig` is too thin to discover what it propagates. The wire field is `propagation_config`; the TS type can be more specific. + +### 10. `propagationConfig.enabled` boolean shape — `src/v1/model.ts:57` +- **Why weird:** A boolean field literally named `enabled`. The pattern is `propagationConfig.enabled = true`. JS/TS booleans are conventionally `is*`/`has*` or scoped (`enabledForPropagation`). On a config object whose entire purpose is to describe propagation, a field called `enabled` is missing its scope qualifier — enabled to do *what*? (The answer is "propagate", but the field name is silent on that.) +- **Category:** 1 (vague), 15 (generic name), 17 (verb-tense/predicate inconsistency). +- **Suggested name:** `propagate?: boolean` (collapse the wrapper) or `isEnabled` if the wrapper stays. +- **Rationale:** `propagationConfig.enabled` reads as "the propagation config is enabled". A clearer shape would be `tagPolicy.propagate = true` directly. + +### 11. `CreateTagPolicyRequest` / `DeleteTagPolicyRequest` / `GetTagPolicyRequest` / `ListTagPoliciesRequest` / `UpdateTagPolicyRequest` — `src/v1/model.ts:20,30,34,38,77` +- **Why weird:** Five request DTOs share a 12-char prefix `TagPolicy*Request`. Each is 24–32 characters; the common substring is repetition. In the package whose only subject is `TagPolicy`, every request type re-states that subject. +- **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). +- **Suggested name:** `CreateRequest` / `DeleteRequest` / `GetRequest` / `ListRequest` / `UpdateRequest`, or drop the `Request` suffix when the method signature is self-documenting. +- **Rationale:** Single-subject packages don't need to repeat the subject on every request DTO. Cross-SDK convention, but worth flagging. + +### 12. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:38` vs. `model.ts:62` +- **Why weird:** Plural only on list endpoint; singular elsewhere. The list response is `ListTagPoliciesResponse` (plural). The wire path is `/tag-policies` (plural). The convention is consistent with the Go SDK, but worth flagging that the resource name on the wire is plural while the item type is singular. +- **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary within one type family). +- **Suggested name:** Keep as is (cross-SDK convention). Listed for completeness under rule 9. +- **Rationale:** Same as in `entitytagassignments` audit — flagged because rule 9 demands it. + +### 13. `ListTagPoliciesResponse.tagPolicies` field — `src/v1/model.ts:50` +- **Why weird:** Response wraps the items in `tagPolicies: TagPolicy[]`. Re-states the type name on the field. Common pattern but mechanically dense: `resp.tagPolicies.forEach(p => p.tagKey)`. Alternatives like `items` or `policies` reads more cleanly. +- **Category:** 8 (redundant prefix — `Tag` repeats on the field of a response in `ListTagPolicies*Response`), 7 (overly verbose). +- **Suggested name:** `items: TagPolicy[]` or `policies: TagPolicy[]`. +- **Rationale:** Once the response type is `ListTagPoliciesResponse`, the field name doesn't need to re-state "tag policies". + +### 14. `tagPolicies` / `tagPolicy` field naming asymmetry between Create/Update and List response — `src/v1/model.ts:21,50,78` +- **Why weird:** `CreateTagPolicyRequest.tagPolicy: TagPolicy` (singular field for singular subject), `UpdateTagPolicyRequest.tagPolicy: TagPolicy`, `ListTagPoliciesResponse.tagPolicies: TagPolicy[]`. The naming is consistent in form (singular/plural matches type cardinality), but in both cases the field re-states the type. Adding a body wrapper at create/update is asymmetric with the response side: the response has the array directly, the request has the singular wrapped — and the response *also* wraps in a separate `tagPolicies` field. +- **Category:** 17 (inconsistency — wrappers on request and response with different cardinality semantics). +- **Suggested name:** `policy` (request) and `policies` (response). Drop the `tag` prefix; preserve cardinality. +- **Rationale:** Reduces typing and makes the symmetry visible. + +### 15. `defaultValueOverride` case identifier vs. type name — `src/v1/model.ts:13,15` +- **Why weird:** The discriminator case is `'defaultValueOverride'` (a string literal), the field that carries the payload is also `defaultValueOverride`, and the payload type is `DefaultValueOverridePolicy`. Three identifiers in one switch (`$case === 'defaultValueOverride'` ⇒ `defaultValueOverride.defaultValue`) that say the same thing. +- **Category:** 8 (redundant repetition — case literal, field name, and type all share a prefix), 7 (overly verbose). +- **Suggested name:** Drop the `Policy` suffix on the payload type (-> `DefaultValueOverride`). +- **Rationale:** Three identifiers in one switch (`$case === 'defaultValueOverride'` ⇒ `defaultValueOverride.defaultValue`) that say the same thing make for noisy type checks. + +### 16. `tagPolicyFieldMask(...paths: string[])` exported helper — `src/v1/model.ts:281` +- **Why weird:** A free function `tagPolicyFieldMask` exported alongside the type system, with no class namespace. The user types `tagPolicyFieldMask('description', 'values')`. The lowercase camelCase clashes with the PascalCase convention for type-related exports. Re-stated in sister packages with the same shape (`tagAssignmentFieldMask`, etc.). Belongs in a `TagPolicy.fieldMask` static method or in a shared helper module. +- **Category:** 8 (redundant prefix `tagPolicy` on a function exported only from the `tagpolicies` package), 14 (Go-style top-level functions instead of class statics). +- **Suggested name:** `fieldMask` (let the import path supply scope), or `TagPolicy.fieldMask` (static method). +- **Rationale:** Free functions with the type name as prefix replicate Go's lack of methods on structs. TS supports static methods natively. + +### 17. `marshalRequest` / `parseResponse` asymmetric verb pair — `src/v1/utils.ts:113,119` +- **Why weird:** Two functions that form a logical pair, named with mismatched verbs: `marshalRequest` (serialize TS → wire) and `parseResponse` (deserialize wire → TS). The corresponding inverse pair would be `marshalRequest`/`unmarshalResponse` or `serializeRequest`/`deserializeResponse`. Currently asymmetric: `marshal` ↔ `parse`. +- **Category:** 17 (inconsistent action verbs — marshal/unmarshal vs. marshal/parse). +- **Suggested name:** `marshalRequest` / `unmarshalResponse`, or `serializeRequest` / `deserializeResponse`. +- **Rationale:** Sibling helpers should use mirrored verbs. The mismatch is a generator-wide pattern but worth flagging. + +### 18. `marshalRequest` is mis-named — `src/v1/utils.ts:119` +- **Why weird:** The function `marshalRequest(data, schema)` takes *any* data (not a "request"), parses it through the schema, and returns a JSON string. It is a generic JSON encoder; the name implies it only handles request bodies. +- **Category:** 6 (misleading — handles arbitrary data, not just requests), 1 (vague — `marshal` is non-specific in JS, where `JSON.stringify` is the convention). +- **Suggested name:** `toJsonString` or `marshal` (no `Request` suffix). +- **Rationale:** A name that overstates the function's coupling to "request" misleads callers who'd reuse it for response prep. + +### 19. `parseResponse` is mis-named — `src/v1/utils.ts:113` +- **Why weird:** Same problem as `marshalRequest` — the function `parseResponse(body, schema)` parses *any* `Uint8Array` body, not specifically a response. Used to validate request bodies during testing as well. +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `parseJson` or `unmarshal`. +- **Rationale:** Drops the false coupling to "response". + +### 20. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` +- **Why weird:** Two near-identical names with different purposes. `executeCall(call, options)` runs a `Call` through the retrier/rate-limiter; `executeHttpCall(opts)` issues a single HTTP request and reads the body. The names differ by one word (`Http`) but the responsibilities are radically different (orchestrator vs. transport). A user grepping for "execute" can't tell which one to use. +- **Category:** 1 (vague — the disambiguator is too thin), 17 (inconsistent verb scoping). +- **Suggested name:** `executeCall` (orchestrator) and `sendHttpRequest` (single-request transport). +- **Rationale:** Distinct responsibilities should have distinct verb roots, not a same-verb-different-noun split. + +### 21. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Exported helper that this client does not invoke (the list endpoint uses individual `params.append(...)` calls instead — see `client.ts:143,146`). Dead-code-shaped helper. +- **Category:** 6 (misleading — implies the package uses it), 1 (vague — `flatten` is generic; this specific one only handles a subset of types). +- **Suggested name:** N/A — should live in a shared utils package, not be copied into every package. +- **Rationale:** Generator-wide concern: every package duplicates this helper, often without using it. + +## Low severity + +### 22. `createTime` and `updateTime` naming on `TagPolicy` — `src/v1/model.ts:68,70` +- **Why weird:** Verb tense / noun pair where the natural English is "created at" / "updated at". `createTime` reads as "the time to create" (a verb-noun); `createdAt` is the cross-language convention for "timestamp when it was created". Cross-SDK convention is `createTime`/`updateTime`, so this is consistent with the rest of the codebase, but is non-idiomatic JS/TS. +- **Category:** 13 (verb-tense inconsistency — `create` (infinitive) vs. `created` (past participle)), 14 (Go-style naming — Go uses `CreateTime`). +- **Suggested name:** `createdAt` / `updatedAt`. +- **Rationale:** Established SDK pattern, but rule 13/14 demand the flag. Mongo, PostgREST, Rails, GraphQL conventions all use `createdAt`. + +### 23. `accountId: string` on `TagPolicy` — `src/v1/model.ts:74` +- **Why weird:** "The account ID that owns this tag policy." — generic. `accountId` is consistent across the SDK, but the SDK's bound to an account already (via `ClientOptions.accountId`), so this field is redundant *output* (the server tells you the account that owns the policy, which the client already knows). +- **Category:** 1 (vague — what kind of ID? account number? UUID?), 19 (underspecified ID — no format documented), 15 (generic field name losing meaning in the SDK context). +- **Suggested name:** Keep `accountId`; document that it's the Databricks account UUID. +- **Rationale:** Minor; flagged because all `*Id` fields without docs trigger rule 19. + +### 24. `Temporal.Instant` for timestamps — `src/v1/model.ts:68,70` +- **Why weird:** Uses `Temporal.Instant` (from `@js-temporal/polyfill`), which is a great future-proof choice — but `Instant` is unfamiliar to most JS devs (who expect `Date` or string). The doc says "Timestamp when the tag policy was created" without explaining why it's an `Instant`. +- **Category:** 1 (slightly vague choice without doc support), 5 (cryptic to readers unfamiliar with Temporal proposal). +- **Suggested name:** Keep `Temporal.Instant`; add JSDoc explaining the type choice. +- **Rationale:** Generator-wide; flagged once. + +### 25. `nextPageToken: string` empty-string semantics — `src/v1/client.ts:180,183` +- **Why weird:** The pagination loop terminates on `resp.nextPageToken === undefined || resp.nextPageToken === ''`. Two sentinel values for "end of pages": `undefined` (TS-native missing field) and `''` (proto-side default). Callers must remember the two cases. The schema converts both to `string | undefined`, but the wire emits `""` rather than dropping the field. +- **Category:** 6 (misleading — `nextPageToken: ''` looks like a valid token but means "no more pages"), 17 (inconsistent sentinel — two values mean the same thing). +- **Suggested name:** Keep `nextPageToken`; normalize empty string to `undefined` in the unmarshaller. The field is purely a continuation token; "" is not a token, it's a missing token. +- **Rationale:** Generator-wide pattern. Each `*Iter` method has to handle both sentinels. + +### 26. `listTagPoliciesIter` method name — `src/v1/client.ts:170` +- **Why weird:** `Iter` suffix is Go-style (sister `listTagPoliciesIter` matches `Go ListTagPoliciesIterator`). In JS/TS, the standard is to expose `[Symbol.asyncIterator]()` on a class, or to name a generator function with a noun phrase (e.g., `tagPolicies()`). `Iter` is also a cryptic three-letter abbreviation. +- **Category:** 14 (Go-style naming), 5 (cryptic abbreviation — `Iter` shortens `Iterator`). +- **Suggested name:** `listAll(...)` or `iterateTagPolicies(...)`, or make the class an `AsyncIterable` directly. +- **Rationale:** TS has built-in support for `for await...of`; the iterator method should match those expectations. + +### 27. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:43-44` +- **Why weird:** JSDoc says "The maximum value is 1000; values above 1000 will be coerced down to 1000." but the field is typed `number | undefined`. A caller passing `pageSize: 100000` silently gets clipped to 1000. The constraint travels only via the docstring. +- **Category:** 6 (misleading — type does not match contract). +- **Suggested name:** Keep `pageSize`; consider a branded type or a runtime validator. At minimum, restate the limit clearly. +- **Rationale:** Generator-wide; flagged because docs lie about wire behaviour. + +### 28. `pageSize` and `pageToken` are camelCase but wire is `page_size` / `page_token` — `src/v1/client.ts:144,147` +- **Why weird:** The TS request shape uses `pageSize` / `pageToken`, but the URL builder hard-codes the wire names `page_size` / `page_token` (`client.ts:144,147`) — i.e., the client serializes TS field names *manually* into snake_case query strings. If a future request adds new query params, every new param requires another two-name mapping. +- **Category:** 17 (inconsistency — request fields camelCase, URL builder snake_case, no shared mapping table). +- **Suggested name:** N/A; flag as generator-side smell. A field-mask or marshal-schema-driven URL builder would avoid the dual-name maintenance. +- **Rationale:** Each new query param doubles the bug surface. + +### 29. `updateMask` field type `FieldMask` — `src/v1/model.ts:79` +- **Why weird:** `FieldMask` is a generic type carrying the masked-shape as a type parameter. The name `updateMask` is wire-standard (proto FieldMask) but cryptic to TS users — "mask" usually means a bitmask. The JSDoc is missing. +- **Category:** 5 (cryptic — `mask` for TS users means bitmask), 14 (proto-style — FieldMask is a proto concept). +- **Suggested name:** Keep `updateMask`; add JSDoc explaining it's a path-based selector for partial updates. +- **Rationale:** Generator-wide name; flag once. + +### 30. `id` field on `TagPolicy` — `src/v1/model.ts:64` +- **Why weird:** Field name `id` with no JSDoc on what it represents — server-generated UUID? Hashed `tagKey`? Path key for some other endpoint? See #6 for the duplicate-identifier critique; this is the underspecified-`id`-name flag separately. +- **Category:** 1 (vague), 19 (underspecified ID), 15 (generic name). +- **Suggested name:** `policyId` or `governedTagId`; add JSDoc. +- **Rationale:** Sibling `BudgetPolicy.policyId` uses the prefix; `TagPolicy.id` does not. Cross-SDK inconsistency. + +### 31. `description` field doc missing — `src/v1/model.ts:65` +- **Why weird:** Just `description?: string | undefined` with no JSDoc. Width limits? Mandatory? Format? +- **Category:** 1 (vague — no contract on the field). +- **Suggested name:** Keep `description`; add JSDoc. +- **Rationale:** Common pattern, but flagged because rule 1 demands it. + +### 32. `host` constructor field with trailing-slash stripping — `src/v1/client.ts:42,54` +- **Why weird:** The constructor strips trailing `/` from `options.host` (`client.ts:54`). Field is `host`, not `baseUrl` or `endpoint`. The TS field `host` is a string like `https://workspace.cloud.databricks.com`, which is by convention "the base URL" not "the host" (the host would be `workspace.cloud.databricks.com` without scheme). +- **Category:** 6 (misleading — "host" usually means hostname-only). +- **Suggested name:** `baseUrl` or `endpoint`. +- **Rationale:** RFC 3986 §3.2 defines "host" as the authority component without scheme. The SDK's `host` is the full URL. + +## Observations + +### 33. Wire/TS divergence dominates the file +The `model.ts` file is 284 lines for ~9 user-facing types; ~140 lines are `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. + +### 34. Action verb consistency +The client uses `create`/`get`/`update`/`delete`/`list` (plus `listIter`) — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. + +### 35. Acronym casing +File uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri` casing clashes encountered within the file. +- **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). + +### 36. `tagpolicies` lowercase package name +Package directory is `tagpolicies` (single token, no separator), but every type uses `TagPolicy*` and the HTTP path uses `tag-policies`. Same problem as `dataclassification`, `tagassignments`, `entitytagassignments` — SDK-wide convention issue. +- **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). + +### 37. Domain leakage from sister packages +Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — all collide on the noun "tag". Each ships its own `Client`, its own `tag*` types, and its own `tagKey`. Co-import requires extensive aliasing. `tagpolicies` differs in that it defines the *policy* over the tag, while the assignment packages attach a `tagKey` + `tagValue` to entities — but a user can't tell from the name; "tag policies" sounds like it could be policies *for* tag assignments. +- **Category:** 12 (duplicate concept across siblings). + +## Domain glossary +- `tag policy` — a governed-tag definition with allowed values and propagation rules. +- `governed tag` — a tag whose key has an active `TagPolicy` (JSDoc on every method mentions this). +- `tag key` — the user-chosen identifier of a tag (e.g., `"environment"`). Doubles as the path-key for the resource (`/tag-policies/{tagKey}`). +- `tag value` — one of the allowed strings for a tag (e.g., `"prod"`, `"dev"`) — wrapped in a `Value` type that has a single `name` field. +- `propagation` — automatic carry-over of a tag from one entity to another via Unity Catalog lineage. +- `conflict resolution` — the rule applied when multiple upstream entities provide different tag values during propagation. +- `default value override` — the only currently supported conflict-resolution strategy: use a specified default value. +- `account id` — Databricks account UUID; tag policies are account-scoped. +- `Terraform documentation` — JSDoc on every method links to the matching `terraform-provider-databricks` page. + +## File coverage +- `src/v1/model.ts` (284 lines): read fully. +- `src/v1/client.ts` (224 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (20 lines): read fully. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md new file mode 100644 index 00000000..7afdd2c9 --- /dev/null +++ b/.agent/naming-audit/tokenmanagement.md @@ -0,0 +1,261 @@ +# Naming Audit: tokenmanagement + +**Path:** `packages/tokenmanagement/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/update/delete arbitrary user tokens, plus create on-behalf-of-service-principal tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. +**Total weird names flagged:** 36 + +## Summary +| Severity | Count | +| --- | --- | +| High | 12 | +| Medium | 13 | +| Low | 8 | +| Observation | 3 | + +## High severity + +### 1. Package name `tokenmanagement` duplicates `tokens` — overlap with sibling package +- **Why weird:** Two packages, `tokens` and `tokenmanagement`, both manage Databricks personal access tokens (PATs). They share the same `AutoscopeState` enum (copy-pasted byte-for-byte, model.ts:13-21 in both), both expose `ListTokens`, `RevokeToken`, `UpdateToken`, `RevokeToken_Response`, and `ListTokens_Response` request/response types, and both publish a `Client` class with `listTokens`/`updateToken` methods. The only structural differences are (a) the admin variant adds `getToken`, `createOnBehalfOfToken`, and admin-only fields on its token info, (b) the per-user variant has `createToken` (no on-behalf-of), and (c) the entity type is named `AdminTokenInfo` here vs. `PublicTokenInfo` in `tokens`. URL paths also differ: `/api/2.0/token-management/...` vs `/api/2.0/token/...`. From a TS user's perspective the namespaces collide: `import {Client, ListTokens} from '@databricks/sdk-tokenmanagement/v1'` and `import {Client, ListTokens} from '@databricks/sdk-tokens/v1'` clash on every public name. +- **Category:** 12 (duplicate concepts across `tokens` vs `tokenmanagement` packages). +- **Suggested name:** Keep the directory split (the API is split upstream) but in the public exports prefix admin types: `AdminListTokensRequest`, `AdminRevokeTokenRequest`, etc., or alternatively rename the package to `tokenadmin` so the call-site distinction is unmistakable (`@databricks/sdk-tokenadmin`). +- **Rationale:** Today consumers who import both packages cannot do so by named import without aliasing every type. The shared enum (`AutoscopeState`) is also duplicated; one of the two packages should re-export the other's enum, or the enum should live in a shared core/identity module. + +### 2. `AutoscopeState` enum values — redundant prefix on every member +- **Why weird:** Every member re-states the enum name: `AUTOSCOPE_STATE_UNSPECIFIED`, `AUTOSCOPE_STATE_DISABLED`, `AUTOSCOPE_STATE_RUNNING`, `AUTOSCOPE_STATE_COMPLETED`, `AUTOSCOPE_STATE_BACKFILLED`, `AUTOSCOPE_STATE_USER_SELECTED`, `AUTOSCOPE_STATE_API_NOT_COVERED` — `src/v1/model.ts:13-21`. Plus `UNSPECIFIED` is a proto-buf sentinel that idiomatic TS expresses with `undefined`. Also: shouty SCREAMING_SNAKE_CASE with underscores violates TS identifier conventions (rule 4). +- **Category:** 2 (redundant enum prefix), 4 (underscores in TS identifiers), 14 (proto/Go-style enum values not idiomatic in TS). +- **Suggested name:** `AutoscopeState.Unspecified | Disabled | Running | Completed | Backfilled | UserSelected | ApiNotCovered` — or drop `Unspecified` and rely on `autoscopeState?: AutoscopeState | undefined`. +- **Rationale:** TS enum members are already namespaced by the enum (`AutoscopeState.Disabled`). The `AUTOSCOPE_STATE_` prefix is pure protobuf noise. This enum is also a copy of the identical enum in the `tokens` package; the prefix problem is doubled. + +### 3. `AdminTokenInfo` — `Info` is a vague suffix, package-specific prefix is misleading +- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. +- **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix), 15 (generic suffix that loses meaning). +- **Suggested name:** `Token` (or `ManagedToken` if `Token` would clash with a class on the consumer side; given this is exported from `@databricks/sdk-tokenmanagement/v1`, `Token` is fine — see also finding #1 about cross-package name collisions). +- **Rationale:** `Token` is the noun the user thinks about. `Info` is a Go-SDK tic; TS does not need it. + +### 4. `CreateOnBehalfOfToken` — verb-phrase type name reads as a function +- **Why weird:** Request DTO named with a verb phrase looks like a method or command, not data. Same broken pattern as `GetToken`, `ListTokens`, `RevokeToken`, `UpdateToken`. With `index.ts` re-exporting these as `type {…}`, `import type {CreateOnBehalfOfToken}` looks at the call site like importing a function. +- **Category:** 6 (misleading — verb-phrase noun), 14 (Go-style request type names). +- **Suggested name:** `CreateOnBehalfOfTokenRequest` (and cascading `GetTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`). +- **Rationale:** TypeScript convention names request DTOs with a `Request` suffix; bare verb-phrase nouns read as actions. + +### 5. `CreateOnBehalfOfToken_Response`, `GetToken_Response`, `ListTokens_Response`, `RevokeToken_Response` — underscore identifiers +- **Why weird:** Underscores inside TS type names are unidiomatic; every declaration requires `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` (model.ts:62, 82, 103, 115). The `eslint-disable` is itself a tell that the name fights the language. +- **Category:** 4 (underscores in TS identifiers). +- **Suggested name:** `CreateOnBehalfOfTokenResponse`, `GetTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`. +- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`. The proto-nested-message convention is a leaky abstraction. + +### 6. Client method `deleteToken` wraps request type `RevokeToken` — verb-tense inconsistency +- **Why weird:** `client.deleteToken(req: RevokeToken)` at client.ts:103-104. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently (tokens client.ts:131 + request type `RevokeToken`). +- **Category:** 13 (verb-tense inconsistency between method and request type), 17 (inconsistent action verbs across the two packages: `tokenmanagement.deleteToken` vs `tokens.revokeToken` for the same kind of operation). +- **Suggested name:** Either rename method to `revokeToken` (matches type and matches sibling package) or rename type to `DeleteTokenRequest` (matches HTTP verb). Recommend the former so both packages share a verb. +- **Rationale:** "Revoke" carries a security/lifecycle meaning that "delete" loses; tokens aren't deleted from history, they're invalidated. + +### 7. `UpdateToken.token: AdminTokenInfo` field — type-suffix tautology and id placement diverges from sibling +- **Why weird:** `UpdateToken` (the request type) has a single semantic field `token` of type `AdminTokenInfo` plus an `updateMask`. The field name `token` paired with type `AdminTokenInfo` works only because `AdminTokenInfo` has the `Info` suffix; rename to `Token` (per finding #3) and `token: Token` becomes type-suffix tautology. The client signature `updateToken(req: UpdateToken)` and then `req.token?.tokenId ?? ''` (client.ts:191) means a caller must construct `{token: {tokenId: ...}, updateMask: ...}`. The sibling `tokens` package hoists `tokenId` to the top level (tokens model.ts:87-93), so consumers of both packages see different ergonomics for the same operation. +- **Category:** 20 (type-suffix tautology if `Info` is removed). +- **Suggested name:** Reuse the cleaner sibling-package pattern in `tokens`: `UpdateToken { tokenId; token; updateMask }` where `tokenId` is hoisted (tokens model.ts:87-93). +- **Rationale:** The admin variant forces the id into the nested body while the sibling `tokens` package hoists it. This is a real ergonomic delta worth flagging upstream; consumers of both packages will trip on it. + +### 8. `client.updateToken` returns `AdminTokenInfo`, sibling returns `UpdateTokenResponse` — inconsistent response handling +- **Why weird:** `tokenmanagement.Client.updateToken` returns `Promise` (client.ts:190) — the bare entity. The sibling `tokens.Client.updateToken` returns `Promise`. Worse: the `tokenmanagement` version doesn't even have a response type declared in `model.ts`; the client just unmarshals into the entity using `unmarshalAdminTokenInfoSchema`. So in one package `updateToken` returns the updated row; in the other it returns a different shape. +- **Category:** 12 (duplicate concept inconsistently implemented), 17 (inconsistent client return shapes). +- **Suggested name:** Pick one — either always return the updated entity (preferred; useful) or always return void. If returning the entity, name the type `Token`/`UpdateTokenResponse` rather than reusing the raw entity, so it can evolve. +- **Rationale:** Cross-package consistency. A user who learns one client will be surprised by the other. + +### 9. `tokenInfo` field on `CreateOnBehalfOfToken_Response` and `GetToken_Response` — `Info` tautology +- **Why weird:** Field `tokenInfo: AdminTokenInfo` (model.ts:66, 84). Field name re-states the type's redundant suffix. Cascades from the `AdminTokenInfo` → `Token` rename (finding #3). +- **Category:** 20 (type-suffix tautology), 1 (`Info` vague). +- **Suggested name:** `token: Token` (paired with rename in finding #3). +- **Rationale:** Mechanical cascade. `response.token.tokenId` reads more naturally than `response.tokenInfo.tokenId`. + +### 10. `tokenInfos` field on `ListTokens_Response` — plural of `Info`, doc-string mismatch +- **Why weird:** Field `tokenInfos: AdminTokenInfo[]` (model.ts:106). Same `Info` tautology as #9 but plural. Also: the JSDoc says "Token metadata of each user-created token in the workspace" — "metadata" implies summary info, but `AdminTokenInfo` is the full row. The field name should be `tokens` not `tokenInfos`. +- **Category:** 20 (type-suffix tautology), 9 (plural-of-`Info` is unidiomatic), 1 (`Info` vague), 15 (field name "tokenInfos" loses meaning). +- **Suggested name:** `tokens: Token[]` (paired with rename in finding #3). +- **Rationale:** Same as #9. Sibling `tokens.ListTokens_Response` has the identical issue (tokens model.ts:55). + +### 11. `PAT` acronym never appears, autoscope comments reference it tacitly +- **Why weird:** The doc comments on `AutoscopeState` (model.ts:8) say "State of inferred scope collection (autoscope) for an external PAT." But nowhere else in the file does the abbreviation `PAT` (Personal Access Token) appear — and `Token` is used everywhere as a stand-in. A user grepping for `PAT` (an industry-standard term in security tooling) finds nothing. Inversely, `Token` could mean OAuth, ID, refresh, etc., but in this package it always means PAT. The package would be unambiguous if named `pats` or `personalaccesstokens`. +- **Category:** 5 (cryptic abbreviation in comment only), 15 (`Token` is too generic for the domain). +- **Suggested name:** Add `PAT` aliases or document at the package level. Consider renaming `Token` → `PersonalAccessToken` or, less verbosely, keep `Token` but clarify in JSDoc. +- **Rationale:** Discoverability. This package is the admin PAT API; calling that out beats hiding it. + +### 12. `applicationId` on `CreateOnBehalfOfToken` — generic field name in a security-sensitive context +- **Why weird:** `applicationId: string` (model.ts:51) is the OAuth client ID of the service principal the on-behalf-of token will represent. "Application ID" is Azure terminology; on AWS/GCP it's "service principal ID" or "client ID". This is the *target* identity for a privileged token-mint operation; `applicationId` undersells the security implication and overloads "application" with three different meanings across Databricks clouds. +- **Category:** 1 (vague — "application" is overloaded), 14 (Azure-style naming leaks), 15 (generic name in security context), 19 (underspecified ID — application ID of what?). +- **Suggested name:** `servicePrincipalApplicationId` or `servicePrincipalClientId` (the JSDoc literally says "Application ID of the service principal", so the field name should too). +- **Rationale:** The field documentation already names the concept correctly; the field name should follow. Mistaking this for "Databricks Apps application id" would mint a token for the wrong principal. + +## Medium severity + +### 13. `ListTokens` request fields `createdById` and `createdByUsername` — duplicate filter slots +- **Why weird:** `ListTokens { createdById?, createdByUsername? }` (model.ts:96-100). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type even says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (client.ts:159-164) which means callers can submit both at once and get undefined server behavior. +- **Category:** 1 (vague — relationship unspecified), 6 (misleading — looks like two filters, possibly redundant). +- **Suggested name:** Either expose a single `filter` string or document mutual exclusivity. At minimum, JSDoc the AND/OR semantics. +- **Rationale:** Consumer-facing API ambiguity. + +### 14. `AdminTokenInfo.scopes`, `AdminTokenInfo.autoscopeState`, `CreateOnBehalfOfToken.scopes`, `CreateOnBehalfOfToken.autoscopeEnabled` — `scopes`/`autoscope*` naming triplet inconsistency +- **Why weird:** Within the same `AdminTokenInfo`, `scopes: string[]` is one thing, `autoscopeState` is another (output-only), and the comment on `CreateOnBehalfOfToken.autoscopeEnabled` (model.ts:57) implies autoscope is a *mode*. So users have to learn: `scopes` (the explicit list), `autoscopeEnabled` (request-side bool), `autoscopeState` (response-side enum), with no `autoscopedScopes` field — the `scopes` field is overloaded as both the input list and the result after autoscope completes. Compare with `tokens.PublicTokenInfo` which has `scopes`, `autoscopeState`, `inferredScopes`, and `backfillScopes` (tokens model.ts:72-77) — i.e., the per-user package separates inferred from explicit scopes; the admin package does not. +- **Category:** 12 (duplicate concept implemented differently than sibling), 1 (vague overloading of `scopes`). +- **Suggested name:** Mirror the `tokens` package by adding `inferredScopes` / `backfillScopes` (or document the overload explicitly). +- **Rationale:** Cross-package inconsistency. Worth pushing upstream. + +### 15. `creationTime` / `expiryTime` / `lastUsedDay` — three time fields with three units and no unit suffix +- **Why weird:** `AdminTokenInfo` (model.ts:27-41) has `creationTime: number`, `expiryTime: number`, `lastUsedDay: number`. The first two are described as "Timestamp" (likely epoch ms, by convention). The third is described as "Approximate timestamp for the day the token was last used. Accurate up to 1 day." But the field is named `lastUsedDay` (not `lastUsedTime` or `lastUsedDate`), and the doc says it is *still* a timestamp — so the suffix `Day` here means "with day-level granularity" not "as a calendar day index". A reader who skims the type and not the doc could easily believe `lastUsedDay` is a 1-31 day-of-month integer or a number-of-days-since-epoch integer. +- **Category:** 5 (cryptic — `Day` is ambiguous), 6 (misleading — "Day" implies a date, value is a timestamp), 15 (generic name without unit). +- **Suggested name:** `lastUsedTimeMs` (or split into `lastUsedTime: number` + a JSDoc note). At minimum, document the unit on all three fields. +- **Rationale:** Compare with `tokens.PublicTokenInfo.lastAccessedTime` (tokens model.ts:69) which uses `Time` consistently. The admin variant breaks the pattern. + +### 16. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc +- **Why weird:** `AdminTokenInfo` has `createdById` ("User ID of the user that created the token") and `ownerId` ("User ID of the user that owns the token"). What's the difference? In the sibling `tokens` package, the type has no `ownerId`. This appears to be admin-only metadata where ownership can transfer (e.g., on-behalf-of tokens). A reader has no way to know without external docs whether the two are usually equal. +- **Category:** 1 (vague — relationship unstated), 19 (underspecified IDs in same struct). +- **Suggested name:** Keep names but add JSDoc clarifying when they diverge (e.g., on-behalf-of tokens: creator is the principal who called the API, owner is the service principal). +- **Rationale:** Discoverability. + +### 17. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope +- **Why weird:** `workspaceId?: number | undefined` (model.ts:39) is documented "If applicable, the ID of the workspace that the token was created in." So it's optional and only meaningful at the account level. But the package and the URL path `/api/2.0/token-management/...` is a workspace endpoint. The field thus carries no useful signal at this endpoint, yet it's exposed. +- **Category:** 6 (misleading — looks pertinent, often vestigial). +- **Suggested name:** Keep; document under what circumstances it is populated (e.g., when the same model is reused at the account API). +- **Rationale:** Generator artefact from sharing models across workspace/account scopes. Flag for upstream cleanup. + +### 18. `lastUsedDay` vs sibling `tokens.PublicTokenInfo.lastAccessedTime` — different field names for "last use" +- **Why weird:** Same concept, two field names: `lastUsedDay` (admin) vs `lastAccessedTime` (per-user). Different unit precision too. Already partially covered in #15 but worth its own bullet for cross-package consistency. +- **Category:** 12 (duplicate concept across packages), 17 (inconsistent verb — used vs accessed). +- **Suggested name:** Align to one. Recommend `lastUsedTime` everywhere; "accessed" is a synonym but inconsistent. +- **Rationale:** Cross-package consistency. + +### 19. `autoscopeEnabled` on `CreateOnBehalfOfToken` but `autoscopeState` on `AdminTokenInfo` — verb/state mix +- **Why weird:** Request input: `autoscopeEnabled: boolean` (boolean toggle). Response output: `autoscopeState: AutoscopeState` (enum). Two different shapes for what is one feature (autoscope). The field-prefix is consistent, but a user must learn that "I set it as a bool" and "I read it back as an enum". +- **Category:** 6 (misleading — write-side bool, read-side enum), 17 (inconsistent shapes for the same feature). +- **Suggested name:** Document the asymmetry, or accept it as an upstream protocol fact. No good rename without breaking the wire. +- **Rationale:** Observation more than action; flagged because it surfaces in two places in this small file. + +### 20. `comment` field — vague, overloaded between SDK comment vs DDL comment vs user note +- **Why weird:** Three of the four user-facing types have a `comment: string` field (`AdminTokenInfo.comment`, `CreateOnBehalfOfToken.comment`). JSDoc says "Comment that describes the purpose of the token" — i.e., a description. Yet the field is called `comment`, which in TS/JS conjures up code comments. Same SQL-DDL leak as in `abacpolicies` (audit finding #28 there). +- **Category:** 6 (misleading — `comment` is overloaded), 14 (SQL-DDL-style naming). +- **Suggested name:** `description` (matches the JSDoc). +- **Rationale:** SQL DDL uses `COMMENT ON ...`; SDK consumers don't. `description` is the standard noun. + +### 21. `CreateOnBehalfOfToken` — preposition phrase inside type name +- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token" (parse: VP(NP(token))) when the intent is "create [on-behalf-of token]" (parse: a kind of token). Industry shorthand is "OBO" but the SDK avoids the acronym. +- **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). +- **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. +- **Rationale:** This is the only operation in the package whose name relies on the preposition; surfacing the intent (mint a token for someone else) helps. Defensible as-is. + +### 22. Single-source-of-truth comments leaking proto file names +- **Why weird:** Top-of-type comments on `GetToken` (model.ts:69-75) and `ListTokens` (model.ts:87-94) say "!! KEEP THIS IN-SYNC WITH THE WORKSPACE PROTO DEFINITIONS IN SERVICE.PROTO !!" and similar. Generator artifacts leaking into the generated TS. Not a name per se but suggests the type names themselves may be tightly bound to proto choices made for inter-service-team reasons rather than for SDK ergonomics. +- **Category:** Observation, 14 (proto/Go-style leaking). +- **Suggested name:** Strip these comments from generated TS; keep in generator metadata. +- **Rationale:** Quality-of-life. Public SDK comments shouldn't reference Databricks-internal proto files. + +### 23. `AutoscopeState` doc comment leaks proto package paths +- **Why weird:** "Mirrored in databricks.identity.AutoscopeState in common/principal-context/api/proto/tokendetails.proto. ... Principal context proto should NOT depend on this proto definitions because too many services depend on the principal context proto." (model.ts:8-12). Inside-baseball that nobody outside Databricks needs. +- **Category:** Observation, 14 (proto leaks). +- **Suggested name:** Replace with one-sentence user-facing doc: "Lifecycle state of automatic scope inference for a personal access token." +- **Rationale:** Same as #22. + +### 24. `tokenValue` is a secret but the field name doesn't hint at it +- **Why weird:** `CreateOnBehalfOfToken_Response.tokenValue: string` (model.ts:65). This is the bearer token plaintext, returned exactly once. The field name `tokenValue` doesn't signal "this is a secret; persist immediately; we will never return it again". Compare with cryptographic SDKs that name such fields `secret`, `tokenSecret`, or `bearerToken`. +- **Category:** 1 (vague), 6 (misleading — `value` is the most generic suffix imaginable for the most sensitive field in the package). +- **Suggested name:** `tokenSecret` or `bearerToken`, and add a JSDoc warning ("Returned once. Store immediately."). +- **Rationale:** Defensive naming for security-critical fields helps users not log/leak the value. + +### 25. `lifetimeSeconds` field — unit-suffix while sibling has same name and unit but adjacent fields differ +- **Why weird:** `CreateOnBehalfOfToken.lifetimeSeconds: number` (model.ts:53) matches sibling `tokens.CreateToken.lifetimeSeconds` (tokens model.ts:29) — good consistency. But within the same file, `AdminTokenInfo.expiryTime: number` lacks a `Ms` unit suffix despite being epoch ms. Mixed convention. +- **Category:** 17 (inconsistent unit-suffix conventions). +- **Suggested name:** Either `lifetimeSeconds` + `expiryTimeMs` (specify both) or `lifetime: number` + `expiryTime: number` (specify neither). Recommend the former. +- **Rationale:** When some fields encode units and others don't, readers can't tell which to trust. + +## Low severity + +### 26. `unmarshalCreateOnBehalfOfToken_ResponseSchema`, `unmarshalGetToken_ResponseSchema`, `unmarshalListTokens_ResponseSchema`, `unmarshalRevokeToken_ResponseSchema` — schema constants carry underscores +- **Why weird:** Each constant name carries the underscore from the corresponding type plus an `eslint-disable`. Mechanical cascade from finding #5. +- **Category:** 4 (underscore identifier). +- **Suggested name:** Falls out if response types lose the underscore. +- **Rationale:** Mechanical. + +### 27. `marshalCreateOnBehalfOfTokenSchema` — long mouthful +- **Why weird:** Schema constant name is 32 characters. Verbose but accurate. +- **Category:** 7 (verbosity), Observation. +- **Suggested name:** Acceptable as-is. +- **Rationale:** Convention is consistent across all generated packages; no fix needed. + +### 28. `adminTokenInfoFieldMaskSchema` and `adminTokenInfoFieldMask()` — `Info` cascade +- **Why weird:** Both names carry the `Info` suffix from `AdminTokenInfo`. Mechanical cascade from finding #3. +- **Category:** 1 (vague suffix `Info`). +- **Suggested name:** `tokenFieldMaskSchema` / `tokenFieldMask()` if entity is renamed. +- **Rationale:** Mechanical. + +### 29. `marshalUpdateTokenSchema` second parameter `updateMask` uses `z.any()` +- **Why weird:** The zod schema for `updateMask` is `z.any().transform((m: FieldMask) => m.toString())` (model.ts:236-238). Not a naming issue per se, but `z.any()` defeats type-checking on this field. The schema infers `any` and the marshal accepts anything; only the cast inside the transform restores typing. +- **Category:** Observation, 6 (misleading — schema typed `any`, code expects `FieldMask`). +- **Suggested name:** N/A (logic concern). +- **Rationale:** Same `z.any()` pattern is in the sibling `tokens` marshal. Worth flagging at generator level. + +### 30. `Client` class is named `Client` (no namespacing) +- **Why weird:** `export class Client` (client.ts:48). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. +- **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). +- **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). +- **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. + +### 31. `host` field on `Client` — workspace URL is more specific +- **Why weird:** `private readonly host: string;` (client.ts:49). The constructor accepts `options.host` which is actually the workspace URL (e.g., `https://my-workspace.cloud.databricks.com`). "Host" is HTTP-level jargon; `workspaceUrl` is the domain-level term users learn first. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `workspaceUrl` (and `options.workspaceUrl`). +- **Rationale:** This is a shared concern across all generated clients; flagged here as it appears in this client. + +### 32. `PACKAGE_SEGMENT` constant — vague label +- **Why weird:** `const PACKAGE_SEGMENT = {...}` (client.ts:43). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `USER_AGENT_PKG`. +- **Rationale:** Minor; identical issue in every generated package. + +### 33. `executeCall` / `executeHttpCall` / `buildHttpRequest` — utility verb pairs without obvious distinction +- **Why weird:** `executeCall` (utils.ts:26) is the public-options-to-internal-options bridge that calls `execute()`. `executeHttpCall` (utils.ts:65) actually issues the HTTP request. The verb is the same ("execute") and the disambiguator is "Http" — a layer below "Call". A reader has to read both to know which to call when. +- **Category:** 1 (vague — `executeCall` is unspecific), 17 (inconsistent layering convention). +- **Suggested name:** `runWithRetry` / `runHttp`, or `executeWithOptions` / `executeHttpRequest`. +- **Rationale:** Same pattern in every generated client; flagging once. + +## Observations + +### 34. Type-suffix tautology pattern repeats: `tokenInfo: AdminTokenInfo`, `tokenInfos: AdminTokenInfo[]` +- These are mechanical consequences of the `Info` suffix on the central entity (finding #3). Listed separately in findings #9 and #10. If the entity is renamed to `Token`, the field names also need to lose the `Info` cascade (`token` and `tokens`). +- **Category:** 20 (type-suffix tautology). + +### 35. Heavy marshal/unmarshal scaffolding ratio +- Model.ts is 265 lines; only ~120 are user-facing type declarations. The rest is zod schemas, transform pairs, FieldMaskSchema, and `eslint-disable` comments. Generator-output bloat per package; not a naming issue. + +### 36. Verb-tense and action-verb summary across the client +- `Client` methods: `createOnBehalfOfToken`, `deleteToken`, `getToken`, `listTokens`, `updateToken`. The set is `create/delete/get/list/update` — consistent CRUDish. The mismatch is only with the request types (`RevokeToken` for `deleteToken`, finding #6). +- **Category:** 13 (verb-tense inconsistency between method and type). + +## Domain glossary +- `PAT` — Personal Access Token (only in `AutoscopeState` doc comment; the term the package is about but never names directly). +- `OBO` — On-Behalf-Of (spelled out in `CreateOnBehalfOfToken`). +- `autoscope` — Automatic API-path scope inference for a token; enum in `AutoscopeState`. +- `service principal` — Non-human identity that a token can be minted for via on-behalf-of. +- `workspace` — Mentioned in `workspaceId` and in proto comments; the scope of this admin API. +- `m2m`/`u2m` — not encountered. +- `iam` — not encountered. +- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`); used for `FieldMask`. + +## Cross-package overlap with `tokens` +- **Shared enum:** `AutoscopeState` is duplicated byte-for-byte (model.ts:13-21 in both packages). +- **Shared request types:** `ListTokens`, `RevokeToken`, `UpdateToken` exist in both packages with different fields. `ListTokens` in `tokenmanagement` has `createdById`/`createdByUsername`; in `tokens` it is `{}`. +- **Shared response types:** `ListTokens_Response`, `RevokeToken_Response` exist in both packages. Both pull from a `*TokenInfo[]` array (`AdminTokenInfo[]` vs `PublicTokenInfo[]`). +- **Different entity name:** `AdminTokenInfo` (this package) vs `PublicTokenInfo` (`tokens` package). +- **Different create operation:** `createOnBehalfOfToken` (admin) vs `createToken` (per-user). +- **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #6. +- **Different update response shape:** Admin returns `AdminTokenInfo`; per-user returns a different shape — flagged in finding #8. +- **Different `lastUsed` field:** `lastUsedDay` (admin) vs `lastAccessedTime` (per-user) — flagged in findings #15/#18. +- **Different scope-related fields:** Admin has `scopes` + `autoscopeState`; per-user adds `inferredScopes` + `backfillScopes` — flagged in #14. +- **Different URL prefix:** `/api/2.0/token-management/...` vs `/api/2.0/token/...`. + +The two packages are conceptual siblings (PAT lifecycle) split by audience (admin-of-others vs self), but the SDK surface is split inconsistently — naming, return types, and method verbs diverge for no obvious reason. Worth raising at the SDK-design level. + +## File coverage +- `src/v1/model.ts` (265 lines): read fully. +- `src/v1/client.ts` (211 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (18 lines): read fully. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md new file mode 100644 index 00000000..01f4965c --- /dev/null +++ b/.agent/naming-audit/tokens.md @@ -0,0 +1,258 @@ +# Naming Audit: tokens + +**Path:** `packages/tokens/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share an `AutoscopeState` enum and a near-identical "token info" record, but the auth/audience boundary makes them distinct services. +**Total weird names flagged:** 35 + +## Summary +| Severity | Count | +| --- | --- | +| High | 9 | +| Medium | 11 | +| Low | 10 | +| Observation | 5 | + +## High severity + +### 1. Package name `tokens` overlaps with sibling `tokenmanagement` and is sub-domain-vague — `packages/tokens/`, `package.json:2`, `client.ts:80,106,135,165` +- **Why weird:** Two npm packages co-exist in `sdk-js/packages/`: `@databricks/sdk-tokens` (this package) and `@databricks/sdk-tokenmanagement` (admin surface). Both manage *the same kind of resource* (Databricks PATs) and both expose a `Client` class with a `listTokens(req, options)` and a `revokeToken(req, options)` method. From the npm name alone, a caller cannot tell which package is the end-user surface and which is the admin surface — `tokens` reads as "the token API" while `tokenmanagement` reads as "manage tokens". Both are accurate descriptions of the other. Compounding: the `package.json` `description` field is empty (line 4) for both packages, so npm registry browsers see only the name. +- **Category:** 12 (duplicate concepts across packages), 1 (vague), 6 (misleading — neither name expresses which audience it serves). +- **Suggested name:** Rename `tokens` → `usertokens` (or `mytokens`, `selftokens`) to mark the end-user surface; keep `tokenmanagement` for the admin surface. Or invert: rename `tokenmanagement` → `admintokens`. The wire URL `/api/2.0/token/...` can stay locked while npm/import paths use the disambiguated names. Worst case, document the audience boundary in each `package.json` description string. +- **Rationale:** A caller writing `import {Client} from '@databricks/sdk-tokens/v1'` has no signal that they're getting the workspace-self surface, not the admin surface. The same problem applies to `import {Client} from '@databricks/sdk-tokenmanagement/v1'`. Two distinct OpenAPI services with overlapping resource models and overlapping method names should not be named with this much ambiguity. + +### 2. Shared `AutoscopeState` enum is duplicated verbatim between `tokens` and `tokenmanagement` — `model.ts:13-21` +- **Why weird:** The exact same `AutoscopeState` enum (same name, same 7 members, same wire values, same doc comment referring to the same `tokendetails.proto`) is defined in both `packages/tokens/src/v1/model.ts:13-21` and `packages/tokenmanagement/src/v1/model.ts:13-21`. Identical Zod registration (`z.enum(AutoscopeState)`) at both `tokens/src/v1/model.ts:130` and `tokenmanagement/src/v1/model.ts:136`. A consumer that imports `AutoscopeState` from both packages gets two distinct TS enum types with the same name — assignment between them works at runtime (both are string-valued) but TS treats them as nominally different in strict mode. +- **Category:** 12 (duplicate concepts across packages), 14 (Go/proto-style — the duplication reflects the generator's per-service code emission). +- **Suggested name:** Hoist `AutoscopeState` into a shared package (e.g. `@databricks/sdk-databricks/wkt` or a new `@databricks/sdk-databricks/auth-models`), and have both `tokens` and `tokenmanagement` re-export it. The Go SDK has this problem too, but TS makes it more painful because of nominal typing on `import type` boundaries. +- **Rationale:** Two enums named `AutoscopeState` in two packages is the textbook duplicate-concept smell. Keeps drifting risk low (today they're identical, tomorrow someone could edit one and not the other). + +### 3. `AUTOSCOPE_STATE_*` members all repeat the enum-name prefix — `model.ts:14-20` +- **Why weird:** Every member of `AutoscopeState` is prefixed with `AUTOSCOPE_STATE_`. Reads as `AutoscopeState.AUTOSCOPE_STATE_RUNNING`, `AutoscopeState.AUTOSCOPE_STATE_BACKFILLED`, `AutoscopeState.AUTOSCOPE_STATE_API_NOT_COVERED` (44 chars to reference "API not covered"). Seven members, all redundantly prefixed. +- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). +- **Suggested name:** `AutoscopeState.UNSPECIFIED`, `AutoscopeState.DISABLED`, `AutoscopeState.RUNNING`, `AutoscopeState.COMPLETED`, `AutoscopeState.BACKFILLED`, `AutoscopeState.USER_SELECTED`, `AutoscopeState.API_NOT_COVERED`. Even better in TS: PascalCase (`AutoscopeState.Running`, etc.). +- **Rationale:** TS enums are namespaced by the enum itself. `Foo.FOO_BAR` is pure protobuf noise — same finding recurs in every generated package in this audit family (see `rfa#3`, `connections#...`). + +### 4. `AutoscopeState.AUTOSCOPE_STATE_UNSPECIFIED` sentinel re-states enum name — `model.ts:14` +- **Why weird:** The corresponding field is `autoscopeState?: AutoscopeState | undefined` (line 72). "Unspecified" is encoded twice: as `undefined` (TS-native), and as `AUTOSCOPE_STATE_UNSPECIFIED` (proto-native). The TS surface should rely on `undefined` for absence. +- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). +- **Suggested name:** Drop the sentinel; rely on `undefined`. +- **Rationale:** Generated boilerplate. Same pattern as `rfa#3`, recurs across all packages. + +### 5. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:58-77` +- **Why weird:** Type is named `PublicTokenInfo` but the surrounding context contains no `PrivateTokenInfo`, `InternalTokenInfo`, or any other counterpart. The "Public" qualifier therefore communicates nothing to a TS reader. From the wire perspective, the Go SDK presumably has a parallel internal type that *isn't* exposed; in TS, that distinction is invisible. Compare to `tokenmanagement.AdminTokenInfo` (also "TokenInfo"-flavoured) — the package uses `Admin` to clarify the audience, but `Public` here doesn't. +- **Category:** 1 (vague qualifier), 6 (misleading — "Public" implies a public-vs-private dichotomy that doesn't surface in the SDK). +- **Suggested name:** `TokenInfo` (drop the `Public` prefix) or `UserTokenInfo` (parallel to `AdminTokenInfo` in `tokenmanagement`). The wire field `token_info` is bare anyway — the qualifier is purely cosmetic. +- **Rationale:** "Public" reads as a security qualifier (public-key, public-API) when the value is just "token metadata visible to the token owner". `UserTokenInfo` makes the audience explicit. + +### 6. `PublicTokenInfo` vs `AdminTokenInfo` divergence — same conceptual resource, different shapes — `tokens/model.ts:58-77`, `tokenmanagement/model.ts:23-46` +- **Why weird:** Two parallel "token info" records describe the *same wire resource* (a Databricks PAT) with overlapping but non-identical field sets: + - `PublicTokenInfo`: `tokenId, creationTime, expiryTime, comment, scopes, lastAccessedTime, autoscopeState, inferredScopes, backfillScopes` (9 fields). + - `AdminTokenInfo`: `tokenId, creationTime, expiryTime, comment, createdById, createdByUsername, ownerId, workspaceId, lastUsedDay, scopes, autoscopeState` (11 fields). + - **Public has 3 fields admin doesn't:** `lastAccessedTime`, `inferredScopes`, `backfillScopes`. + - **Admin has 5 fields public doesn't:** `createdById`, `createdByUsername`, `ownerId`, `workspaceId`, `lastUsedDay`. + - **`lastAccessedTime` (epoch ms, Public) and `lastUsedDay` (day count, Admin) describe the same concept at different fidelity.** Type-naming hides this: Public is millisecond-precise, Admin is day-precise. +- **Category:** 12 (duplicate concepts), 6 (misleading — `lastAccessedTime` vs `lastUsedDay` use different units for the same fact), 1 (vague qualifier on both type names). +- **Suggested name:** Two options: + 1. Document the public-vs-admin partition inline so readers know which fields appear where. + 2. Merge to a single `TokenInfo` with all fields optional, and document which subset the server populates for each endpoint. +- **Rationale:** A caller doing token introspection on the workspace needs to pick a package; the type-name doesn't tell them which fields they'll get. + +### 7. `CreateToken_Response` and `RevokeToken_Response` with proto-style underscore — `model.ts:42, 85` +- **Why weird:** Type names `CreateToken_Response`, `ListTokens_Response`, `RevokeToken_Response` use proto-style nested-message underscores. Each carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` to silence the linter. Compare with `UpdateTokenResponse` (`model.ts:96`) — same package, same generator, *no* underscore. Generator inconsistency: three methods get `Foo_Response`, one gets `FooResponse`. (The Go SDK convention exposes `CreateTokenResponse`-style names in `*Service.Response` pattern; here the TS port has reproduced the underscore literally.) +- **Category:** 4 (underscores in TS identifiers), 13 (inconsistency — same package mixes `_Response` and `Response`), 14 (Go/proto-style name). +- **Suggested name:** Drop underscore consistently: `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`. The `eslint-disable` line vanishes with the underscore. +- **Rationale:** Mixing `CreateToken_Response` (underscore) with `UpdateTokenResponse` (no underscore) in the same `index.ts` export block is a discoverability bug — a reader autocompleting `CreateTokenR...` gets nothing because the actual name has an underscore. + +### 8. `ListTokens` and `RevokeToken` request types are misnamed as actions, not requests — `model.ts:50, 79` +- **Why weird:** Type names `ListTokens` and `RevokeToken` are bare verbs/verb-phrases that *look like methods*. A TS reader sees `import type {ListTokens, RevokeToken} from './model'` and reasonably guesses these are *functions or actions*. Instead, they're request DTOs. (`CreateToken` and `UpdateToken` have the same problem.) The corresponding response types correctly carry the `_Response` suffix; the request types should carry `Request`. The `tokenmanagement` package does the same. The Go SDK uses `CreateTokenRequest`/`RevokeTokenRequest` in idiomatic Go. +- **Category:** 8 (missing/asymmetric suffix), 6 (misleading — looks like a callable), 13 (asymmetry — response types are suffixed but request types aren't). +- **Suggested name:** `CreateTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`. Pairs symmetrically with `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`, `UpdateTokenResponse`. +- **Rationale:** Most TS SDKs (AWS, GCP, Azure) name request DTOs with an explicit `*Request` suffix or `*Input`. The current asymmetry is a Go-port artefact. + +### 9. `Client.revokeToken` method paired with URL `/api/2.0/token/delete` — `client.ts:131,135` +- **Why weird:** Method on `Client` is `revokeToken`, but the wire URL it hits is `/api/2.0/token/delete`. Sibling `tokenmanagement.Client.deleteToken` (line 103) maps `RevokeToken`/`RevokeToken_Response` to URL `/api/2.0/token-management/tokens/{id}` via HTTP `DELETE`. So: + - `tokens.revokeToken` → request type `RevokeToken` → URL ends in `/delete` → HTTP `POST` (revoke = delete on wire, named "revoke" in SDK). + - `tokenmanagement.deleteToken` → request type `RevokeToken` → URL ends in `/tokens/{id}` → HTTP `DELETE` (delete on wire, named "delete" in SDK, request type still `Revoke*`). +- **Category:** 17 (inconsistent action verbs for the same conceptual operation), 13 (inconsistency between packages), 6 (misleading — the request type doesn't match the method verb). +- **Suggested name:** Pick one verb (`revoke` or `delete`) and use it for the method, the request type, and ideally the URL. The Go SDK uses `Delete` consistently, so the TS port should too. Or pick `revoke` consistently. Today, `RevokeToken` is the *request type* in both packages but only the `tokens` package method is called `revokeToken`. +- **Rationale:** Calling the same operation `revokeToken` in one package and `deleteToken` in another (with the *same request type* `RevokeToken`) is a recipe for confusion. A user code-completing on a client typed as "either of the two" cannot rely on method names. + +## Medium severity + +### 10. `CreateToken.lifetimeSeconds` — unit smuggled into name, not type — `model.ts:29` +- **Why weird:** `lifetimeSeconds?: number | undefined`. Unit (seconds) lives in the field name, not the type. The doc says "in seconds". TS has no native duration type, so a unit-bearing field name is conventional, but the rest of the package uses `*Time` (`creationTime`, `expiryTime`, `lastAccessedTime`) which are *epoch milliseconds* (verified by doc strings on `model.ts:62-69`). Same `number` type, two different units, two different naming conventions. +- **Category:** 15 (unit-bearing field-name vs typed wrapper), 13 (intra-package inconsistency — `lifetimeSeconds` vs `creationTime`). +- **Suggested name:** Acceptable as-is, but consider `lifetimeMs` (or `lifetime: Duration`) for parity with `creationTime` etc. The Temporal API (`@js-temporal/polyfill` is already a package.json dep) has `Temporal.Duration` which would be domain-correct. +- **Rationale:** Within one struct, two number fields use different time units. Caller must read docs to avoid bugs. + +### 11. `CreateToken.autoscopeEnabled` — naming inconsistent with response — `model.ts:38` +- **Why weird:** Request flag is `autoscopeEnabled?: boolean` ("enabled" suffix). The response carries `autoscopeState?: AutoscopeState` (a state enum, not a boolean). Same conceptual feature, different abstraction levels and names. A TS user thinking "I'll just check the value I set" would write `req.autoscopeEnabled` then later expect `info.autoscopeEnabled` but instead has to translate via `info.autoscopeState === 'AUTOSCOPE_STATE_RUNNING' || …`. The mapping (which states correspond to "enabled") is undocumented in the SDK surface. +- **Category:** 12 (duplicate concept — `autoscopeEnabled` ↔ `autoscopeState`), 17 (boolean vs enum for the same feature), 1 (vague — what counts as "enabled"?). +- **Suggested name:** Either accept the asymmetry but document the mapping, or rename request to `autoscopeMode?: AutoscopeMode` with an enum (`ENABLED` / `DISABLED`), so the surface is symmetric. +- **Rationale:** A boolean request and an enum response for "the same setting" is a known leaky abstraction. + +### 12. `PublicTokenInfo.scopes` doc grammar — singular vs plural — `model.ts:67-68` +- **Why weird:** Doc reads "Scope of the token was created with, if applicable" — but the field is `scopes?: string[] | undefined` (plural, array). The doc says "Scope" (singular) and "the token was created with" (drops the "that"). Compare with `CreateToken.scopes` doc: "Optional scopes of the token." — different wording, different singular/plural usage. +- **Category:** 9 (singular/plural mismatch), 6 (misleading doc), 13 (inconsistency — same field documented differently across types). +- **Suggested name:** Fix doc to "The scopes the token was created with, if applicable." Same in `AdminTokenInfo.scopes` (`tokenmanagement/model.ts:42-43` has the same typo). +- **Rationale:** Doc grammar shapes the mental model. Singular "scope" suggests a single value; the type is an array. + +### 13. `PublicTokenInfo.inferredScopes` and `backfillScopes` — overlapping arrays of strings — `model.ts:73-76` +- **Why weird:** Three different scope arrays in one struct: + - `scopes?: string[]` — "Scope of the token was created with, if applicable." + - `inferredScopes?: string[]` — "Inferred API path scopes collected for this token when autoscope is enabled." + - `backfillScopes?: string[]` — "Scopes inferred from offline backfill processing." + + All three are `string[]` carrying the same conceptual content (scope identifiers) but produced by different machinery (user-declared, runtime-inferred, offline-backfilled). There's no shared type alias, no enum, no narrowing. A caller wanting "the effective scopes" must union all three (or pick) without compile-time help. +- **Category:** 12 (duplicate concepts), 1 (vague — what's the relationship between the three?), 16 (string[] should be a `Scope[]` enum or branded string array). +- **Suggested name:** Group them: `declaredScopes`, `inferredScopes`, `backfillInferredScopes`. Add an `effectiveScopes` computed-on-server field that the caller actually wants. Or model as `{ source: 'declared' | 'inferred' | 'backfill'; value: string }[]` so the source is part of the data. +- **Rationale:** Three string-array fields with overlapping semantics is a discoverability bug. A new user has to read all three docs to understand the policy. + +### 14. `UpdateToken.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:88` +- **Why weird:** Doc on `UpdateToken.tokenId`: "The SHA-256 hash of the token to be updated." But every other `tokenId` doc in the package (and in `tokenmanagement`) says variants of "The ID of the token". So readers comparing the types see: + - `CreateToken_Response.tokenInfo.tokenId` (line 46+59) — "The ID of this token." + - `PublicTokenInfo.tokenId` (line 60) — "The ID of this token." + - `RevokeToken.tokenId` (line 81) — "The ID of the token to be revoked." + - `UpdateToken.tokenId` (line 89) — "The SHA-256 hash of the token to be updated." +- **Category:** 6 (misleading doc — same field, different meaning), 13 (inconsistency), 19 (underspecified ID — what is it actually?). +- **Suggested name:** Either (a) reconcile the docs — if `tokenId` is the SHA-256 hash everywhere, say so consistently; or (b) if `UpdateToken.tokenId` actually expects a different format than the others, rename or document the divergence loudly. +- **Rationale:** The doc disagreement implies either a stale comment or a real wire-protocol quirk. Either way, a caller can't tell which. + +### 15. `UpdateToken.token` field name shadows the package name — `model.ts:90` +- **Why weird:** `UpdateToken.token?: PublicTokenInfo`. The field `token` inside the type `UpdateToken` in the package `tokens` carries the entire updated payload. Reads `updateReq.token.tokenId` — the word "token" appears three times in five characters. The same package has `Client.updateToken` method which takes `UpdateToken` which has a `token` field of type `PublicTokenInfo`. Layer cake. +- **Category:** 20 (type-suffix tautology), 1 (vague). +- **Suggested name:** Field as `info` (since the inner type is `PublicTokenInfo`/`TokenInfo`) or `data`. Wire stays `token`. So `updateReq.info.tokenId`. +- **Rationale:** The wire field is `token` because the proto message wraps a `TokenInfo`; in TS, the field name can clarify intent without changing the wire. + +### 16. `UpdateToken` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:87-93` +- **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:165`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenSchema` on `model.ts:200-202`). +- **Category:** 12 (duplicate concept), 6 (misleading — which one is authoritative?), 11 (the inner one is dead-ish data). +- **Suggested name:** Drop one. Either: (a) make `token` exclude `tokenId` (`Omit`) and keep the top-level; or (b) drop the top-level and use `req.token.tokenId` in the client. +- **Rationale:** Two fields for the same identifier invite subtle bugs (server may pick the inner one if the top-level is empty). + +### 17. `Client` class name — colliding namespace — `client.ts:46` +- **Why weird:** Top-level class literally named `Client`. Re-exported in `index.ts` as just `Client`. A consumer importing from both `@databricks/sdk-tokens/v1` and `@databricks/sdk-tokenmanagement/v1` faces an identical name clash: + ``` + import {Client} from '@databricks/sdk-tokens/v1'; + import {Client as AdminTokensClient} from '@databricks/sdk-tokenmanagement/v1'; + ``` + Worse, both packages export a class with method `listTokens(req, options)` where `req` is a *different* `ListTokens` type. Strong TS types catch the assignment error, but the duplication forces an alias at every dual import. +- **Category:** 1 (vague), 12 (duplicate name across packages). +- **Suggested name:** `TokensClient`, `UserTokensClient`, or `MyTokensClient`. Mirror with `TokenManagementClient`/`AdminTokensClient`. +- **Rationale:** Same finding as `rfa#37`, recurs across all packages — but particularly painful here given the `tokens`/`tokenmanagement` overlap. + +### 18. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site (`client.ts:87,114` use them within four lines of each other). +- **Category:** 1 (vague), 17 (inconsistent action verbs). +- **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. +- **Rationale:** Cross-package: same as `rfa#32`, recurs everywhere. + +### 19. `marshalRequest` / `parseResponse` verb asymmetry — `utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations in the same file. The rest of the package consistently uses `marshal*`/`unmarshal*` (the schemas: `marshalCreateTokenSchema`, `unmarshalPublicTokenInfoSchema`, etc.), so the function-level utility breaks the package's own convention. +- **Category:** 17 (inconsistent action verbs), 13 (intra-package inconsistency). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. +- **Rationale:** Cross-package: same as `rfa#31`. + +### 20. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` +- **Why weird:** The file imports `Options` from `@databricks/sdk-core/api` (line 3) and `CallOptions` from `@databricks/sdk-options/call` (line 12). Three `Options`-suffixed types in scope. `HttpCallOptions` is internal — purely a context bag passed to `executeHttpCall`. +- **Category:** 1 (vague suffix). +- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). +- **Rationale:** Same as `rfa#33`. + +## Low severity + +### 21. `marshalCreateTokenSchema` etc. — redundant `Schema` suffix on every codec — `model.ts:99-212` +- **Why weird:** Seven marshal/unmarshal schemas, all suffixed `Schema`. Names get long (`unmarshalCreateToken_ResponseSchema` = 35 chars including the `_`). The suffix repeats info already captured by the `z.ZodType<...>` typing. +- **Category:** 8 (redundant suffix `Schema`). +- **Suggested name:** Drop `Schema` (`unmarshalCreateTokenResponse`, `marshalRevokeToken`), or shorten to `decode*`/`encode*` verbs. +- **Rationale:** Same as `rfa#30`. + +### 22. `publicTokenInfoFieldMaskSchema` internal const + `publicTokenInfoFieldMask` exported helper — `model.ts:214,226` +- **Why weird:** Two helpers with near-identical names: an internal `publicTokenInfoFieldMaskSchema` (the lookup table) and an exported `publicTokenInfoFieldMask(...)` (the builder). The `Schema` suffix on one, no suffix on the other, while both relate to field-mask handling. +- **Category:** 8 (redundant suffix), 13 (intra-package inconsistency). +- **Suggested name:** Either `publicTokenInfoFieldMaskPaths` (the static map) and `publicTokenInfoFieldMask` (the builder), or hoist into a single object exposing both. +- **Rationale:** Generator artefact; mechanical fix. + +### 23. `readAll` — generic helper name — `utils.ts:40` +- **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `readStreamToEnd` / `drainStream`. +- **Rationale:** Same as `rfa#34`. + +### 24. `flattenQueryParams` — `utils.ts:123` +- **Why weird:** Exported but unused in this package (`client.ts` only ever builds JSON bodies). Dead-looking export. +- **Category:** Observation / 11 (unused public helper). +- **Suggested name:** Remove from utils if it's a generator default; or keep, but stop emitting it for body-only services. +- **Rationale:** Same as `rfa#35`. + +### 25. `PACKAGE_SEGMENT` constant — `client.ts:41` +- **Why weird:** `Segment` is a generic word; without the inline comment the constant doesn't communicate User-Agent identity. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Same as `rfa#36`. + +### 26. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` +- **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,111,141,171` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). +- **Category:** 1 (vague — five-positional builder). +- **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. +- **Rationale:** Same as `rfa#38`. + +### 27. `marshalRequest(data: unknown, schema: z.ZodType): string` — `utils.ts:119` +- **Why weird:** The function parses `data` against `schema` and returns a JSON string. The name says "marshal request", but it's used for *any* outbound body, including update bodies that aren't strictly "request DTOs" in the sense of "request type". Mechanical. +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** `marshalJson` or `serializeBody`. +- **Rationale:** Same as `rfa#39`. + +### 28. `parseResponse` overloads with `JSON.parse` and `schema.parse` — `utils.ts:113` +- **Why weird:** Returns `T` where `T` is the schema's inferred type. The name "parse" overloads with `JSON.parse` (called inside) and with `schema.parse` (also called inside). Three layers of "parse" in five lines. +- **Category:** 1 (vague). +- **Suggested name:** `decodeResponse` or `unmarshalJson`. +- **Rationale:** Same as `rfa#40`. + +### 29. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` +- **Why weird:** Local `opts` variable is one letter shorter than the parameter `options` to disambiguate. The shadowing convention isn't documented. +- **Category:** Observation. +- **Suggested name:** Rename inner `opts` → `internalOptions`. +- **Rationale:** Same as `rfa#41`. + +### 30. `unmarshalRevokeToken_ResponseSchema` — proto-style underscore propagates into schema constant — `model.ts:147-148` +- **Why weird:** The `_Response` underscore from finding #7 propagates into the schema constant: `unmarshalRevokeToken_ResponseSchema` is 37 chars including the underscore, and the underscore *inside the identifier* makes IDE autocomplete jagged. +- **Category:** 4 (underscore in TS identifier). +- **Suggested name:** Combine with #7 (drop underscore everywhere). +- **Rationale:** Mechanical. + +## Observations + +### 31. `index.ts` re-exports interfaces but not marshal/unmarshal schemas +The index file exports the `Client`, the `AutoscopeState` enum, and nine model interfaces. It does *not* export the `marshal*Schema`/`unmarshal*Schema` constants or the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. + +### 32. `package.json` description is empty string — `package.json:4` +`"description": ""`. The npm package has no public description string. Combined with the ambiguous `tokens` name (see #1) and the parallel `tokenmanagement` package, this leaves users without any registry-level metadata to disambiguate the two packages. + +### 33. No tests in the package +`package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees (`AutoscopeState` proto-link in the doc) deserve a contract test. + +### 34. Doc comments leak proto file paths and internal commentary +The `AutoscopeState` doc (model.ts:7-12) references `common/principal-context/api/proto/tokendetails.proto` and `Principal context proto should NOT depend on this proto definitions` — internal architecture commentary that leaks into the public SDK surface. Similar pattern in `tokenmanagement`. Acceptable for now, but a polish pass should strip internal proto-tree paths from the user-facing JSDoc. + +### 35. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:165` +`const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:89`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. + +## Domain glossary +- **`tokens`** — npm package name; represents the *workspace user* PAT surface (create / list / revoke / update one's own tokens). Wire: `/api/2.0/token/...`. +- **`tokenmanagement`** — sibling npm package; represents the *workspace admin* PAT surface (inspect / revoke any user's tokens, create service-principal on-behalf-of tokens). Wire: `/api/2.0/token-management/...`. +- **`PAT`** — Personal Access Token. Databricks workspace bearer tokens issued to users or service principals. Referenced in the `AutoscopeState` doc. +- **`autoscope`** — Inferred-scope collection: a token-store feature that learns which API paths a token actually hits and either records them (`inferredScopes`) or backfills them offline (`backfillScopes`). +- **`scopes`** — Permission/API-path scopes attached to a PAT. Closed set per `principal-context` definitions; SDK types them as bare `string[]`. +- **`PublicTokenInfo`** — The token-metadata record visible to the *owner* of the token (no `createdBy*`, no `ownerId`, no `workspaceId`). +- **`AdminTokenInfo`** — (`tokenmanagement` package) the token-metadata record visible to a *workspace admin* (carries `createdById`, `createdByUsername`, `ownerId`, `workspaceId`, `lastUsedDay`). +- **`FieldMask`** — Google protobuf convention for sparse-field updates in PATCH semantics. `publicTokenInfoFieldMask(...)` builds the wire-format paths for `UpdateToken.updateMask`. +- **`AutoscopeState`** — 7-member enum (incl. sentinel) defined identically in both `tokens` and `tokenmanagement`. Per the doc, mirrored in `databricks.identity.AutoscopeState` proto. + +## File coverage +- `src/v1/model.ts` (234 lines): read fully. +- `src/v1/client.ts` (186 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (18 lines): read fully. +- Cross-referenced `packages/tokenmanagement/src/v1/model.ts`, `client.ts`, `index.ts` for overlap analysis (see findings #1, #2, #6, #9, #17). diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md new file mode 100644 index 00000000..38d47caa --- /dev/null +++ b/.agent/naming-audit/usagedashboards.md @@ -0,0 +1,181 @@ +# Naming Audit: usagedashboards + +**Path:** `packages/usagedashboards/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). +**Total weird names flagged:** 26 + +## Summary +| Severity | Count | +| --- | --- | +| High | 7 | +| Medium | 9 | +| Low | 6 | +| Observation | 4 | + +## High severity + +### 1. Package name `usagedashboards` is plural but the API is singular — `packages/usagedashboards/` +- **Why weird:** The package is named with a plural noun (`usagedashboards`), but the API surface manages **one** dashboard per (workspace, account, type) tuple — there is no list endpoint, no collection semantics, no `dashboardId`-scoped path (URL is `/dashboard`, singular). The Go SDK source path `databricks/api/usage_dashboards/v1` is plural; the REST endpoint is singular. The TypeScript package mirrors the Go *path* rather than the API's *cardinality*. +- **Category:** 9 (singular/plural mismatch), 14 (Go/proto-style — name follows the Go package path rather than English usage). +- **Suggested name:** `usagedashboard` (singular) — or, better, fold into a `billing` package alongside `billableusagedownload` (which has the same parent `/api/2.0/accounts/{account_id}` namespace). +- **Rationale:** A user discovering the SDK would expect a "list" operation from a plural package name and be surprised by the lack of one. The singular form also matches the REST path `/dashboard`. The fold-into-`billing` move is a generator-level concern but worth flagging: both `usagedashboards` and `billableusagedownload` are about account-level billing data and live under the same URL prefix. + +### 2. `UsageDashboardMajorVersion` enum has redundant prefix on every member — `src/v1/model.ts:5-9` +- **Why weird:** Every member of the enum is prefixed with the enum name in screaming snake case: `USAGE_DASHBOARD_MAJOR_VERSION_UNSPECIFIED`, `USAGE_DASHBOARD_MAJOR_VERSION_1`, `USAGE_DASHBOARD_MAJOR_VERSION_2`. The qualified usage at a call site reads `UsageDashboardMajorVersion.USAGE_DASHBOARD_MAJOR_VERSION_1` — 51 characters of pure stutter for a value that means "1". +- **Category:** 2 (redundant enum prefix), 4 (`UPPER_SNAKE_CASE` underscores in TS identifiers), 7 (overly verbose), 18 (long enum values). +- **Suggested name:** Either TS-idiomatic `UsageDashboardMajorVersion.Unspecified` / `.V1` / `.V2` (PascalCase, no prefix) or numeric union `type UsageDashboardMajorVersion = 1 | 2`. The JSDoc on the field (line 24) even mentions "VERSION_1" as the default, implying the wire format is what matters and the enum is just bookkeeping. +- **Rationale:** Two real values (`1` and `2`) plus a sentinel `Unspecified` does not need a 28-character prefix per member. The proto-style `_UNSPECIFIED` zero value is a Go/proto3 convention with no TS equivalent (TS uses `undefined`). See the typescript.mdc § 5 rule about avoiding `UPPER_SNAKE_CASE` for non-constants. Same finding applies to **every** enum in the codebase — but this one is particularly egregious because the values are integers. + +### 3. `UsageDashboardType` enum has the same redundant-prefix problem — `src/v1/model.ts:11-15` +- **Why weird:** Members `USAGE_DASHBOARD_TYPE_UNSPECIFIED`, `USAGE_DASHBOARD_TYPE_WORKSPACE`, `USAGE_DASHBOARD_TYPE_GLOBAL`. Same pattern as #2. +- **Category:** 2, 4, 7, 18. +- **Suggested name:** `UsageDashboardType.Workspace` / `.Global` / `.Unspecified`. Or, since the enum is binary in practice (Workspace vs Global), a `'workspace' | 'global'` union type would be smaller and more idiomatic for TS. +- **Rationale:** Same as #2. Bonus issue: the wire values are the bare strings `WORKSPACE` and `GLOBAL` (after the `USAGE_DASHBOARD_TYPE_` prefix), so the prefix exists *only* in the TS layer — it is not part of the on-wire enum. + +### 4. `_Response` suffix with literal underscore — `src/v1/model.ts:29, 44` +- **Why weird:** The types `CreateBillingUsageDashboard_Response` and `GetBillingUsageDashboard_Response` use a literal underscore — a proto-style nested message convention transplanted directly into TypeScript. Every reference to these types triggers an ESLint suppression comment (`// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`) — see lines 28, 43, 51, 61. Six lint suppressions in a 86-line file is a strong signal the naming convention is wrong. +- **Category:** 4 (underscore in TS identifier), 14 (proto/Go-style), 8 (redundant suffix — `Response` is already a suffix). +- **Suggested name:** `CreateBillingUsageDashboardResponse` and `GetBillingUsageDashboardResponse` (no underscore). Or drop the suffix entirely and rename request types to `CreateBillingUsageDashboardRequest` / `GetBillingUsageDashboardRequest` so the response types can claim the un-suffixed name (`CreateBillingUsageDashboard` / `GetBillingUsageDashboard`) — though that's a bigger refactor. +- **Rationale:** The proto-style nested-message convention is dead surface area in TS; the lint suppressions prove it. ESLint's `naming-convention` rule is correctly flagging an inappropriate identifier — the fix is to rename, not to suppress. + +### 5. Request type names omit `Request` suffix while response types include `Response` — `src/v1/model.ts:17,34 vs 29,44` +- **Why weird:** Asymmetric suffixing: `CreateBillingUsageDashboard` (no `Request`) paired with `CreateBillingUsageDashboard_Response` (has `Response`). Reading the types in isolation, `CreateBillingUsageDashboard` looks like a domain entity (the dashboard itself) not the *request* to create one — a user might reasonably expect it to have fields like `id`, `createdAt`, `etag`, etc. The asymmetry forces the nested `_Response` suffix to disambiguate, which is what causes finding #4. +- **Category:** 6 (misleading — name implies a domain entity but is actually a request DTO), 8 (asymmetric suffixing), 9 (singular/plural — verb without object/request suffix reads as imperative). +- **Suggested name:** Either `CreateBillingUsageDashboardRequest` + `CreateBillingUsageDashboardResponse` (both suffixed) or drop the request suffix and rename responses (see finding #4 alternate). +- **Rationale:** Either pattern works; the SDK should pick one. The current Go-port has request types named after the RPC method (verb-prefixed) and response types named `*Response`. In TS, suffix-consistency aids autocomplete and reading. Same finding applies to every RPC type pair in the codebase. + +### 6. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 40` / `src/v1/client.ts:106-108` +- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:106`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. +- **Category:** 6 (misleading — TS type says optional, API likely requires it), 16 (field type contradicts domain reality), 17 (inconsistent transport: same field is body on POST, query on GET). +- **Suggested name:** Keep the name but type as `UsageDashboardType` (required). Or split the DTO into `CreateBillingUsageDashboardRequest` (body) and `GetBillingUsageDashboardRequest` (query params), since the GET endpoint conceptually has different parameter semantics from the POST. +- **Rationale:** `dashboardType` is the field that distinguishes Workspace from Global dashboards — it is *the* selector for the resource. Treating it as optional with no default is type-level dishonesty. + +### 7. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` +- **Why weird:** Databricks workspace IDs are 64-bit integers (the Go SDK uses `int64`); JavaScript's `number` type is IEEE-754 double which loses precision above 2^53. The TS field is typed `number | undefined`. Same finding applies to `metastores` and most workspace-scoped packages in the SDK, but worth flagging because every audit cycle compounds the risk. Compare with `accountId: string` (line 21) which correctly uses `string` for an account UUID. +- **Category:** 16 (field type contradicts domain — `number` cannot represent a 64-bit ID), 6 (misleading — type appears safe but is lossy). +- **Suggested name:** Keep the field name, change type to `string` (and update `marshalCreateBillingUsageDashboardSchema` to allow string→number marshalling, or have the wire send it as a string — the Databricks REST API generally accepts both for `workspace_id`). +- **Rationale:** Most workspace IDs are below 2^53 in practice, so this rarely bites. But the type contract claims something the runtime can't honour for the high end of the ID space. This is a systemic SDK-level issue worth raising at the generator. + +## Medium severity + +### 8. `CreateBillingUsageDashboard` / `GetBillingUsageDashboard` include `Billing` but the package is `usagedashboards` — `src/v1/model.ts:17, 34` +- **Why weird:** The package is `@databricks/sdk-usagedashboards` (no "billing"); the types prefix `Billing` (no "Usage" alone). A user who imported the package by its `usage`-themed name then sees `Billing`-prefixed types and `Client.createBillingUsageDashboard()` method must mentally bridge `usage` ↔ `billing`. The package name and type names disagree on which noun is primary. +- **Category:** 17 (inconsistent action verbs / nouns across naming layers), 7 (overly verbose — `BillingUsage` is two synonyms for the same concept). +- **Suggested name:** Pick one noun. Either rename the package to `billingusagedashboards` (matches types) or drop `Billing` from the type names (`CreateUsageDashboard` / `GetUsageDashboard`). The Go SDK calls this domain "Billing → UsageDashboards" so types match Go; the TS package name is the outlier. +- **Rationale:** Cross-layer consistency. The simplest fix is `CreateUsageDashboard*` / `GetUsageDashboard*` since the package name is already `usagedashboards`. "Billing" is implied by the account-level endpoint path. + +### 9. `Client` class is unprefixed — `src/v1/client.ts:38` +- **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-usagedashboards/v1'`, then has to rename it (`import {Client as UsageDashboardsClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Cross-SDK consistency — but worth flagging. +- **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). +- **Suggested name:** `UsageDashboardsClient` or `BillingUsageDashboardClient`. +- **Rationale:** Same finding as `billableusagedownload` audit #8. The SDK could expose a namespace export pattern (`import * as usageDashboards from '@databricks/sdk-usagedashboards/v1'`) and remove the `Client` symbol entirely, letting `usageDashboards.Client` be the qualified name. Not a blocker. + +### 10. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:68, 97` +- **Why weird:** Method name and request-type name are textually identical (modulo case): `createBillingUsageDashboard(req: CreateBillingUsageDashboard)`. The repetition is so close that the type name reads like a misnamed method import. Compare with `lakeview` where `Client.createDashboard(req: CreateDashboardRequest)` keeps the type-noun separate from the method-verb. +- **Category:** 7 (overly verbose), 8 (redundant — method verb is already implicit in the type's verb prefix). +- **Suggested name:** `createDashboard` / `getDashboard` (drop `BillingUsage` since the package name disambiguates) or `create` / `get` (since there are only two methods). Type stays as `CreateBillingUsageDashboardRequest`. +- **Rationale:** A method on `usageDashboardsClient` is already in the usage-dashboards namespace; restating `BillingUsageDashboard` in the method name is pure stutter. The Go SDK does this because Go has package-flat method tables; TS classes provide their own namespace. + +### 11. URL hard-codes the empty-string fallback for accountId — `src/v1/client.ts:72, 101` +- **Why weird:** `${req.accountId ?? this.accountId ?? ''}` — if both the request and the client have no `accountId`, the URL becomes `/api/2.0/accounts//dashboard`. The server will 4xx, but the *client* is happy to send a malformed URL. Not strictly a naming issue but it surfaces because `accountId` is duplicated between `ClientOptions.accountId` and the DTO field (same issue as `billableusagedownload` audit #7). +- **Category:** 12 (duplicate concept), 19 (underspecified ID — silently produces empty path segment). +- **Suggested name:** Remove `accountId` from the request DTOs. Make it a client-level concern only; throw a clear error if it is missing. Or keep both but throw `Error('accountId is required')` instead of silently producing `/accounts//...`. +- **Rationale:** Same as `billableusagedownload` finding. The duplicated-with-fallback pattern is a footgun; the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. + +### 12. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72` +- **Why weird:** `accountId` lives on `CreateBillingUsageDashboard` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshal schema (lines 73-85) does emit `account_id` in the body though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. +- **Category:** 6 (misleading — body shape implies body field, but it's a path param), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree?). +- **Suggested name:** Either segregate path params into a separate type (`PathParams` / `RouteParams`) or document the field's dual role. Or omit it from the body via the marshal schema (`d.account_id` would not appear) and keep it as a path-param-only field. Most idiomatic: remove from request DTO entirely (see #11). +- **Rationale:** The current shape misleads callers about the wire format. The field appears in two URL segments simultaneously, which is suspicious. + +### 13. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` +- **Why weird:** Both response types include `dashboardId?: string` (always optional). But there is no `GetByDashboardId` method, and the request types use `(workspaceId, accountId, dashboardType)` to identify the dashboard, not the `dashboardId`. So `dashboardId` is a returned-but-never-accepted identifier — informational only. The field is also typed optional, but a successful 2xx response should always have an ID; the `?` is again type-level dishonesty. +- **Category:** 6 (misleading optionality), 19 (underspecified id — present in responses but not accepted as a request key). +- **Suggested name:** Keep the name; make it required (`dashboardId: string`). Or document that it is a read-only side-channel identifier (not a primary key from the API's POV). Or expose a `getByDashboardId` method that round-trips the value. +- **Rationale:** If the API returns an ID, the SDK should either let you use it or document why you can't. The current state — return-only, never-accepted — is API-design noise that the SDK faithfully echoes. + +### 14. `dashboardUrl` field is a `string` — should be `URL` or branded — `src/v1/model.ts:48` +- **Why weird:** `dashboardUrl?: string | undefined` — a URL is typed as a bare string. Callers must `new URL(resp.dashboardUrl)` defensively. Compare with `accountId`/`dashboardId` which are also strings but represent IDs, not URLs. No branded type distinguishes them. Also optional on a success response (same dishonesty as #13). +- **Category:** 15 (generic field name losing meaning), 6 (misleading optionality), 1 (vague — `string` for a URL). +- **Suggested name:** Keep the field name; consider a branded type (`type Url = string & {readonly _urlBrand: unique symbol}`) or `URL` (the WHATWG class). At minimum, make it non-optional on a 2xx response. +- **Rationale:** SDK-wide concern (every URL field in every package is `string`); flag once per audit. Branded URLs are a TS idiom precisely for this case. + +### 15. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:33` +- **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. +- **Category:** 1 (vague), 15 (generic field name losing meaning). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Cross-package consistency — same finding appears in every audited package. Worth normalising at the generator level. + +### 16. `marshalCreateBillingUsageDashboardSchema` / `unmarshalCreateBillingUsageDashboard_ResponseSchema` schema names are 40+ chars — `src/v1/model.ts:52, 62, 73` +- **Why weird:** The schema identifiers are mouthfuls: `unmarshalCreateBillingUsageDashboard_ResponseSchema` is 51 characters; the `Schema` suffix and `unmarshal`/`marshal` prefix together inflate already-long type names. The `_Response` underscore appears in the schema name too (same lint suppression). +- **Category:** 7 (overly verbose), 4 (underscore), 20 (type-suffix tautology — `Schema` suffix on a zod schema is redundant given the value's `z.ZodType` type). +- **Suggested name:** Group schemas in a namespace or object: `schemas.createBillingUsageDashboard` / `schemas.createBillingUsageDashboardResponse`. Or accept the verbosity but at least drop `_Response` (see #4). +- **Rationale:** Tree-shaking concerns aside, the current names are read-once, write-many. Worth simplifying. + +## Low severity + +### 17. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` +- **Why weird:** The exact same multi-sentence JSDoc ("Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account.") appears on `CreateBillingUsageDashboard.dashboardType` (line 22) and `GetBillingUsageDashboard.dashboardType` (line 39). The duplication suggests the underlying enum (`UsageDashboardType`) should carry the doc, not each field. +- **Category:** Observation — not strictly a name issue but flagged because it implies fragmentation. JSDoc duplication is a generator artefact. +- **Suggested name:** Move the doc to the `UsageDashboardType` enum (or its members). + +### 18. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:68, 74, 78, 97, 111, 115, 117` +- **Why weird:** Local variables use three-letter abbreviations (`req`, `resp`, `opts`, `httpReq`). The codebase guideline (typescript.mdc § 5) discourages cryptic short abbreviations. Compare with `httpClient` (full word) in the same file. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `request`, `response`, `options`, `httpRequest`. +- **Rationale:** Inexpensive readability win. + +### 19. `req: CreateBillingUsageDashboard` parameter name — `src/v1/client.ts:69, 98` +- **Why weird:** The method parameter is named `req` (the abbreviation from #18). It is also the request DTO whose type name doesn't end in `Request` (see #5). The parameter name `req` clashes with the natural reading where the type name suggests an entity ("a usage dashboard to create") not a request envelope. +- **Category:** 5 (cryptic), 6 (misleading paired with type name). +- **Suggested name:** `params` or `input` (since the type is not literally a Request). Or fix the type name (`CreateBillingUsageDashboardRequest`) and keep `request`. + +### 20. `params` shadowed across files — `src/v1/client.ts:102` +- **Why weird:** Local `params: URLSearchParams` — fine in isolation, but `flattenQueryParams(prefix, value, params)` in `utils.ts:123` exposes the same `params` name in public API. The repeated use of `params` for both `URLSearchParams` and "named function parameters" is mildly confusing in audit traces. +- **Category:** 1 (vague). +- **Suggested name:** `queryParams` / `urlSearchParams`. + +### 21. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:109` +- **Why weird:** `const query = params.toString();` — the variable is the serialized query *string*, but `query` reads as a query expression/object. Compare with `fullUrl` on the next line (which is clear about what it is). +- **Category:** 1 (vague), 6 (misleading — name implies a query, value is a string). +- **Suggested name:** `queryString`. + +### 22. `httpClient: HttpClient` field — `src/v1/client.ts:43` +- **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention widespread in this SDK. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the outer `Client` class in the same file. + +## Observations + +### 23. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` +The exported `flattenQueryParams` helper is never called from `client.ts` — the GET method does its own `params.append()` (lines 103-108) inline because there are only two query params. The helper is dead surface area in this package; same finding as `billableusagedownload` audit #11. Worth pruning at the generator level when the consuming methods don't need it. + +### 24. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` +Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. Both are used in `client.ts:79, 89, 117, 126`. The verb-pair is fine, but the cognitive distance between "wrap with retry options" and "send an HTTP request and check for API errors" is large enough that one name should be different (e.g., `runWithCallOptions` / `sendHttp`). Same finding appears in every audited package's `utils.ts`. + +### 25. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency +- The enum names are `UsageDashboardMajorVersion`, `UsageDashboardType` — `Usage` first, no "Billing". +- The request types are `CreateBillingUsageDashboard` — `Billing` first, with `Usage`. +- The package is `usagedashboards` — `usage` only, no "billing". +- The Go SDK service is "Billing → UsageDashboards" — both nouns in two layers. + +Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #8. + +### 26. The package has no list/page operations +There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. + +## Domain glossary +- `usage dashboard` — A Databricks-managed dashboard (DBSQL or AI/BI Lakeview) that visualises account-level billing/usage data. Two flavours: **Workspace** (per-workspace) and **Global** (all workspaces in an account). +- `DBU` — Databricks Unit; the standard unit of compute consumption. Notably absent from this package's types and JSDoc — verified via grep that the literal "DBU" never appears, even though DBUs are the unit the dashboard would visualise. +- `account ID` — Databricks account identifier (UUID); surfaces as `accountId: string` on both request types and on `ClientOptions.accountId`. +- `workspace ID` — Databricks workspace identifier (64-bit int); surfaces as `workspaceId: number` — see finding #7 about the precision issue. +- `major version` — Template version of the dashboard (1 or 2). Per the JSDoc, defaults to `VERSION_1` if unspecified at create time. +- `dashboard ID` — Identifier of the created dashboard (returned, not accepted as input). See finding #13. +- `E2` — Databricks deployment architecture; not mentioned in this package but implicit (account-level endpoints are E2-only). + +## File coverage +- `src/v1/model.ts` (86 lines): read fully. +- `src/v1/client.ts` (133 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. +- `src/v1/index.ts` (13 lines): read fully. diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md new file mode 100644 index 00000000..d3df6c7d --- /dev/null +++ b/.agent/naming-audit/usagepolicy.md @@ -0,0 +1,277 @@ +# Naming Audit: usagepolicy + +**Path:** `packages/usagepolicy/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). +**Total weird names flagged:** 41 + +## Summary +| Severity | Count | +| --- | --- | +| High | 10 | +| Medium | 15 | +| Low | 11 | +| Observation | 5 | + +## High severity + +### 1. Whole package duplicates `budgetpolicy` with a renamed entity — `src/v1/model.ts` (entire file) vs `packages/budgetpolicy/src/v1/model.ts` +- **Why weird:** `UsagePolicy` is `BudgetPolicy` with `Usage` substituted for `Budget`. The shared types (`CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`) are textually identical between the two packages. The `UsagePolicy.policyId` JSDoc even confirms: "(same structure as BudgetPolicy)" (line 120). Same `/accounts/{accountId}/{verb}-policies` URL shape, same wire fields. The only material difference is the API version (`/api/2.1` vs `/api/2.0`) and the URL segment (`usage-policies` vs `budget-policies`). +- **Category:** 12 (duplicate concept — two sibling packages with the same shape and overlapping name), 1 (vague — `usage` and `budget` both modify the same underlying tag-policy concept). +- **Suggested name:** Either (a) collapse `usagepolicy` and `budgetpolicy` into a single package with a versioned entity, or (b) ensure both publish under distinct, non-overlapping type names. As shipped, a consumer importing both packages cannot disambiguate `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`, `CustomPolicyTag`, or `Client` without aliasing. +- **Rationale:** This is the headline finding for the package. The duplication is a 1:1 clone, and the API team did not even bother to rename the reserved custom-tag keys: `CustomPolicyTag.key` JSDoc in `usagepolicy` still says `"budget-policy-name"`, `"budget-policy-id"`, `"budget-policy-resolution-result"` (line 27, copied from `budgetpolicy`). Two clones in one SDK with collidable names is a real usability problem. + +### 2. `SortSpec_Field` enum (`Foo_Bar` identifier) — `src/v1/model.ts:6` +- **Why weird:** Underscore in TypeScript identifier — proto-style nested-enum notation. Requires an explicit `eslint-disable-next-line @typescript-eslint/naming-convention` because TS strict rules reject `Foo_Bar`. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names not idiomatic in TS). +- **Suggested name:** `SortField` (hoist out of the nested namespace), or a string-literal union `'POLICY_NAME' | undefined`. +- **Rationale:** TS has no nested-enum concept; the only reason this exists is to mirror the `SortSpec.Field` proto message. The eslint-disable is a tell that the name fights the language. Mirrors the same finding in `budgetpolicy`. + +### 3. `SortSpec_Field.FIELD_UNSPECIFIED` — `src/v1/model.ts:8` +- **Why weird:** A `FIELD_UNSPECIFIED` sentinel imported from protobuf semantics. Idiomatic TS uses `undefined` (the field is already `field?: SortSpec_Field | undefined`). +- **Category:** 2 (redundant enum prefix re-stating the enum name), 14 (proto sentinel leak). +- **Suggested name:** Drop the value and rely on `field?: SortField | undefined`. +- **Rationale:** Optional + `undefined` already expresses "unspecified" in TS; a `FIELD_UNSPECIFIED` literal forces every caller to handle two "no choice" states (`undefined` and the sentinel string). + +### 4. `Filter` (bare top-level type) — `src/v1/model.ts:47` +- **Why weird:** Re-exported from `index.ts:11` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (`Array#filter`, RxJS `filter`, content filters, etc.) and the type is package-scoped — but the re-export under this name *directly collides* with the same bare `Filter` in `packages/budgetpolicy/src/v1/model.ts:77`. Any user importing both packages will hit a name clash. +- **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). +- **Suggested name:** `UsagePolicyFilter` (and rename the sibling to `BudgetPolicyFilter`). +- **Rationale:** A bare `Filter` provides zero discoverability and forces a collision with `budgetpolicy.Filter`. Both packages target the same account-level API; consumers will frequently import both. This finding is doubly bad because the two `Filter` types have identical structure but are not type-compatible from TS's structural-typing perspective at the import boundary if a consumer aliases one (`import {Filter as BudgetFilter}`). + +### 5. `UpdateUsagePolicyRequest.limitConfig` field doc references a non-existent successor — `src/v1/model.ts:117` +- **Why weird:** JSDoc reads: "DEPRECATED. This is redundant field as LimitConfig is part of the UsagePolicy". But `UsagePolicy` itself (line 121–130) does **not** have a `limitConfig` member, so the JSDoc claim ("LimitConfig is part of the UsagePolicy") is wrong about its successor — the field has nowhere to migrate to within this package. +- **Category:** 6 (misleading — doc points to a non-existent replacement). +- **Suggested name:** Fix the JSDoc to either point at the real successor or drop the migration hint. +- **Rationale:** A new-language SDK should not inherit other-language migration warts on day one, and the warning is broken because the documented successor doesn't exist in this package's `UsagePolicy`. + +### 6. `CreateUsagePolicyRequest.requestId` documented as idempotency-ish key — `src/v1/model.ts:14-21` +- **Why weird:** JSDoc: "A unique identifier for this request. Restricted to 36 ASCII characters." — `requestId` is a vague field name that does not signal "idempotency key" to callers. The doc says nothing about idempotency (unlike `budgetpolicy`'s `CreateBudgetPolicyRequest.requestId` doc at `packages/budgetpolicy/src/v1/model.ts:37-42` which explicitly mentions idempotency). The semantic is unclear: trace id? correlation id? idempotency key? +- **Category:** 1 (vague — `requestId` could mean anything), 15 (generic field name losing meaning), 17 (inconsistent across sibling packages — sibling spells out idempotency, this one doesn't). +- **Suggested name:** `idempotencyKey` (matches Stripe/Square/most REST APIs) and expand the JSDoc to clarify semantics. +- **Rationale:** Sibling-package divergence is worse than either choice alone: a caller flipping between `usagepolicy` and `budgetpolicy` cannot rely on identical semantics for the same-named field. Either both packages should call it `idempotencyKey` or both `requestId`, and both docs should state idempotency. + +### 7. `UsagePolicy.policyId` / `UsagePolicy.policyName` field naming inside `UsagePolicy` type — `src/v1/model.ts:123,125` +- **Why weird:** Fields on the `UsagePolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. +- **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `UsagePolicy.id` is `policyId`). +- **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). +- **Rationale:** `usagePolicy.id` reads better than `usagePolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. Mirrors `budgetpolicy` finding #9. + +### 8. `UsagePolicy.bindingWorkspaceIds` — `src/v1/model.ts:129` +- **Why weird:** `binding` as a noun-prefix reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this usage policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). Additionally, the JSDoc here is shorter than in `budgetpolicy` (which adds "An empty binding implies that this budget policy is open to any workspace in the account.") — the empty-binding semantic is silently dropped from `usagepolicy`, creating yet another inter-package documentation divergence. +- **Category:** 1 (vague — `binding` is generic: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists), 17 (inconsistent doc across siblings). +- **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. +- **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. + +### 9. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` +- **Why weird:** Workspace IDs are typed as `number[]`. Databricks workspace IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so workspace IDs `>2^53` will silently lose precision. Same problem on `Filter.creatorUserId: number` (line 57). +- **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). +- **Suggested name:** `bindingWorkspaceIds: bigint[]` or `string[]` (matches Databricks REST API serialisation of large IDs). +- **Rationale:** Generator/policy issue across the SDK. Worth flagging at every usage site. + +### 10. Filter operator semantics undocumented — `src/v1/model.ts:47-63` +- **Why weird:** The `Filter` type has three optional fields whose names imply singular match (`policyName`, `creatorUserId`, `creatorUserName`), but the JSDoc on `policyName` says "The partial name of policies to be filtered on" — implying substring match. The other two fields don't document their operator (equality? prefix? substring?). When multiple fields are set, the JSDoc on the type says "All specified filters will be applied in conjunction" — i.e. AND — but the per-field docs each repeat "If unspecified, all policies will be returned", which is confusing in the presence of the conjunction rule. +- **Category:** 6 (misleading — singular noun for what is likely a substring/multi-match filter), 1 (vague — no operator spelled in the name). +- **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to lists where appropriate). +- **Rationale:** Filter DSLs benefit from explicit operators. Bare singular names with conjunction semantics buried in the type JSDoc force readers to puzzle through three short paragraphs to know what "set both fields" actually does. Mirrors `budgetpolicy` finding #14. + +## Medium severity + +### 11. `CustomPolicyTag` type name — `src/v1/model.ts:23` +- **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. Also colliding with the same `CustomPolicyTag` exported from `budgetpolicy/src/v1/model.ts:53`. +- **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location), 12 (duplicate concept across siblings with identical name). +- **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. +- **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". + +### 12. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` +- **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling **from the budget-policy domain** — copy-pasted verbatim from the `budgetpolicy` package without renaming to the usage-policy equivalents (one would expect `usage-policy-name` etc.). Either (a) the wire really *does* use the `budget-policy-*` prefix (which is a Databricks API design issue worth surfacing), or (b) the JSDoc was lazily duplicated and the actual reserved keys are different. +- **Category:** 6 (misleading: cross-domain magic strings that callers must memorise), 12 (duplicate across siblings — but here it's a *bug*, because the reserved keys are not surfaced as constants and may differ from `budgetpolicy`), 18 (long magic string sentinels). +- **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate in marshal step and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. +- **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Either way the verbatim duplication smells. + +### 13. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` +- **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. +- **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). +- **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). +- **Rationale:** Same as finding #9 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. + +### 14. `Filter.creatorUserId` + `Filter.creatorUserName` — two ways to filter on the same creator — `src/v1/model.ts:57,62` +- **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number`, `creatorUserName` is `string`. +- **Category:** 12 (duplicate concept), 19 (underspecified id), 6 (misleading — caller wonders which one to use). +- **Suggested name:** Collapse to `creator?: {id?: number; name?: string}`, or split into named composite types. +- **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine, and the per-field doc ("If unspecified, all policies will be returned") fails to define the AND/OR rule between them. + +### 15. `SortSpec` type — `src/v1/model.ts:103` +- **Why weird:** `SortSpec` (specification) and `Field` together build the "what to sort by" structure. `Spec` is generic — every type is a spec of something. The wrapping type holds two fields (`field` + `descending`); a one-or-two-field pair could be inlined into the request. +- **Category:** 1 (vague suffix `Spec`), 11 (trivial wrapper holding two fields). +- **Suggested name:** `SortOptions`, or inline as `sortField?: SortField; sortDescending?: boolean` on the request. +- **Rationale:** `Spec` adds no information. `sortBy: SortField` plus a boolean is more direct. Mirrors `budgetpolicy` finding #17. + +### 16. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:104` +- **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. +- **Category:** Observation (typo). +- **Suggested name:** Fix spelling. +- **Rationale:** Surfaces in IntelliSense. Same typo as `budgetpolicy/src/v1/model.ts:150` — the two packages even share generator typos. + +### 17. `ListUsagePoliciesResponse.policies` field name — `src/v1/model.ts:96` +- **Why weird:** Field `policies` of type `UsagePolicy[]`. Within the `usagepolicy` package, `policies` is fine — but within a multi-package consumer with `budgetpolicy.policies` and other policy-emitting packages, the bare name is ambiguous when copy-pasted. +- **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on the create/update requests), 12 (duplicate field name across siblings). +- **Suggested name:** `usagePolicies: UsagePolicy[]`. +- **Rationale:** Tied to type rename considerations. If the entity-type were renamed (per finding #1), `policies` could stay; otherwise `usagePolicies` makes the field self-documenting at any depth. + +### 18. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` +- **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listUsagePoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. +- **Category:** Observation / 12 (duplicate-but-asymmetric concept). +- **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. +- **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. Mirrors `budgetpolicy` finding #20. + +### 19. `UsagePolicy.customTags` plural field paired with singular `CustomPolicyTag` type — `src/v1/model.ts:127` +- **Why weird:** Plural field `customTags: CustomPolicyTag[]` plus the singular type with `Tag` suffix produces `customTags: CustomPolicyTag[]` — same word twice (`Tags`/`Tag`). +- **Category:** 8 (redundant prefix `custom`), 20 (`customTags: CustomPolicyTag[]` is type-suffix tautology). +- **Suggested name:** `tags: Tag[]` (with type rename per #11). Wire form stays `custom_tags`. +- **Rationale:** Linked to the type-rename above; if `CustomPolicyTag` becomes `Tag`, field naturally becomes `tags`. + +### 20. `CreateUsagePolicyRequest.policy` field with wire-name leak in JSDoc — `src/v1/model.ts:19-20` +- **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated" — wire-name leak (`policy_id`) in the docs of a TS field. Also: the doc is *shorter* than the sibling `budgetpolicy.CreateBudgetPolicyRequest.policy` doc (which adds: "`policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional."). So the usage-policy version silently drops the "policyName must be provided" and the cloud-provider-conditional tag note. +- **Category:** 14 (wire-style identifiers in TS docs), 17 (inconsistent docs across sibling packages for the same conceptual request). +- **Suggested name:** Fix the doc to reference TS field names; align with sibling-package doc content. +- **Rationale:** Editing UX: hovers should show TS, not proto. The sibling-divergence also matters: a developer reading both packages should see consistent requirements unless they actually differ. + +### 21. `UpdateUsagePolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:112` +- **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `UsagePolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. Exact same bug as `budgetpolicy.UpdateBudgetPolicyRequest.policy` JSDoc. +- **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `UsagePolicy`, model says otherwise), 14 (Go-SDK paste from a richer struct). +- **Suggested name:** Fix doc; remove the spurious reference or add the missing field to the model. +- **Rationale:** Real bug, twice (once here, once in `budgetpolicy`). + +### 22. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` +- **Why weird:** `budgetpolicy.UpdateBudgetPolicyRequest` (`packages/budgetpolicy/src/v1/model.ts:165`) carries an `updateMask?: FieldMask` plus a `budgetPolicyFieldMask(...paths)` builder. `usagepolicy.UpdateUsagePolicyRequest` does not. Either (a) the usage-policy API genuinely uses replace-on-PATCH semantics (no partial updates) — in which case the JSDoc should say so — or (b) the SDK is missing field-mask support that the API offers. Without inspection of the OpenAPI source, either is plausible, and the absence of a doc note is itself a finding. +- **Category:** 17 (inconsistency across near-clone sibling packages), Observation (potential missing surface). +- **Suggested name:** If full-replace: document on `UpdateUsagePolicyRequest`. If partial-update: add `updateMask?: FieldMask` and a `usagePolicyFieldMask(...paths)` helper to match the sibling. +- **Rationale:** A user toggling between the two clones will expect parity. The divergence is silent and unjustified by either docstring. + +### 23. `unmarshalUsagePolicySchema` / `marshalUsagePolicySchema` naming pair — `src/v1/model.ts:155,217` +- **Why weird:** "Marshal" and "unmarshal" terms come from Go encoding semantics. JS/TS world uses "serialize" / "deserialize" (or "parse" / "stringify"). Note also `parseResponse`/`marshalRequest` in `utils.ts:113,119` already mix `parse` and `marshal` for the same operation pair. +- **Category:** 14 (Go-style names not idiomatic in TS), 17 (`parseResponse` vs `marshalRequest` mix `parse` and `marshal` for inverse operations). +- **Suggested name:** `serializeUsagePolicy` / `deserializeUsagePolicy`, or `usagePolicyToWire` / `usagePolicyFromWire`. +- **Rationale:** Aligns with broader JS ecosystem (`JSON.parse`/`JSON.stringify`, Zod's `parse`/`safeParse`). Generator-wide concern. + +### 24. `UsagePolicy` lacks the rich constraints documented on `BudgetPolicy.policyName` — `src/v1/model.ts:125` vs `packages/budgetpolicy/src/v1/model.ts:20-25` +- **Why weird:** `BudgetPolicy.policyName` has a four-line JSDoc enumerating constraints: uniqueness, ISO 8859-1 (latin1) charset, reserved-keyword prefix ban. `UsagePolicy.policyName` says only "The name of the policy." If both APIs share the same backend (likely), the usage-policy doc is silently incomplete. If the constraints genuinely differ, the doc should call out the difference. +- **Category:** 17 (sibling-package doc divergence for what is plausibly the same constraint), 15 (generic name losing meaning when the constraint set is undocumented). +- **Suggested name:** Restore the full constraint doc, or document the deviation. +- **Rationale:** This is the kind of divergence that bites users who copy code from one package to the other. + +### 25. `ListUsagePoliciesResponse.nextPageToken` / `previousPageToken` docs trimmed vs sibling — `src/v1/model.ts:97-100` +- **Why weird:** Docs read: "A token that can be sent as `page_token` to retrieve the next page." and "A token that can be sent as `page_token` to retrieve the previous page." The sibling `budgetpolicy.ListBudgetPoliciesResponse` adds: "If this field is omitted, there are no subsequent pages." / "In this field is omitted, there are no previous pages." Both omission notes are missing here. +- **Category:** 17 (inconsistent doc across siblings), 14 (wire-name `page_token` leak in TS doc). +- **Suggested name:** Restore the omission notes and fix `page_token` → `pageToken`. +- **Rationale:** Two sibling packages with the same pagination contract should not diverge in pagination docs. Even though the budgetpolicy docs have their own typo ("In this field is omitted"), at least they tell the reader what an absent token means. + +## Low severity + +### 26. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions with nearly identical names handle different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. +- **Category:** 1 (vague), 17 (names differ only by `Http` infix). +- **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. +- **Rationale:** Same pair flagged in `abacpolicies` and `budgetpolicy` audits. Generator-wide. + +### 27. `HttpCallOptions` — `src/v1/utils.ts:15` +- **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. +- **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). +- **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). +- **Rationale:** Generator-wide; same as `budgetpolicy` finding #29. + +### 28. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. +- **Rationale:** Pair-wise consistency aids reading. Identical to `budgetpolicy` finding #30; the `utils.ts` files are byte-for-byte clones (same 4012-byte size, same code). + +### 29. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. +- **Category:** 1 (vague). +- **Suggested name:** `drainStream` or `readStreamToEnd`. +- **Rationale:** Internal helper. Generator-wide. + +### 30. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Used by `client.ts:158,165,217` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package (12+ identical copies in this monorepo). +- **Category:** Observation / 12 (duplicate utility across packages). +- **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. +- **Rationale:** Naming is fine; flagging duplication. + +### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. +- **Category:** 1 (vague), 15 (generic name losing meaning). +- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. +- **Rationale:** Same as `budgetpolicy` finding #33; generator-wide. + +### 32. `Client` class plain name — `src/v1/client.ts:46` +- **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-usagepolicy/v1`, they will almost certainly alias it (`import {Client as UsagePolicyClient}`) to avoid collision with `Client` from every other package — including the byte-identical class from `@databricks/sdk-budgetpolicy/v1`. +- **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages, *especially* this one and `budgetpolicy`). +- **Suggested name:** `UsagePolicyClient`. +- **Rationale:** Each generated package emits a `Client`. With `usagepolicy`/`budgetpolicy` being near-clones, the importer who needs both will be forced into double-aliasing. + +### 33. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +- **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. +- **Category:** 5 (cryptic abbreviation when the long form fits comfortably). +- **Suggested name:** `request`. +- **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. Same as `budgetpolicy` finding #35. + +### 34. `listUsagePoliciesIter` method name — `src/v1/client.ts:193` +- **Why weird:** `Iter` is a cryptic abbreviation for "iterator" / "iterable". Mirrors Go SDK's `Iterator` style. TS convention is to spell out (`...Iterator`) or use a stronger naming convention (`paginate*`, `list*All`). +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `listUsagePoliciesIterator`, or `listAllUsagePolicies`. +- **Rationale:** `Iter` is a Go-style truncation that JS/TS users rarely use. + +### 35. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` +- **Why weird:** "it's" should be "its" (possessive). Same grammatical mistake appears in `budgetpolicy/src/v1/client.ts:120` ("Retrieves a policy by it's ID.") — copy-pasted across the clones. +- **Category:** Observation (grammar). +- **Suggested name:** Fix to "its". +- **Rationale:** Surfaces in editor hovers; small but persistent. + +### 36. `listUsagePolicies` JSDoc verbatim duplicates sibling — `src/v1/client.ts:145` +- **Why weird:** "Lists all usage policies. Policies are returned in the alphabetically ascending order of their names." Word-for-word translation of the budgetpolicy version with `usage` substituted. Same finding for the rest of the method docstrings — they're all `s/budget/usage/` substitutions with no domain-specific guidance. +- **Category:** Observation, 12 (cross-package boilerplate). +- **Suggested name:** Keep, but worth flagging that the package ships zero domain-specific guidance — every per-method doc is a clone with substitution. +- **Rationale:** The duplication compounds the "is this really two separate APIs?" question raised in finding #1. + +## Observations + +### 37. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference +The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. +- **Category:** 12 (duplicate concept), 1 (vague package boundary). + +### 38. No `FieldMask` import in `usagepolicy/src/v1/model.ts` +Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #22 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. +- **Category:** Observation / 17 (cross-package inconsistency). + +### 39. Action-verb conventions in `Client` +The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. +- **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). + +### 40. Acronym casing `Id` consistently used as `Id`, not `ID` +`policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). +- **Category:** 3 (observation — internal acronym style is consistent). + +### 41. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) +The same identifier appears in three forms in the same client file: +- `usage_policies` — wire form (in the Zod schemas via snake_case keys). +- `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). +- `usagePolicies` — TS type/method names. + +Readers must mentally translate. Worth flagging because the kebab-case form does not appear in the audit findings unless one inspects the URL building code. +- **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). + +## Domain glossary +- `usage policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. Same structure as `budgetpolicy.BudgetPolicy` per the JSDoc on `UsagePolicy` (line 120). Despite "usage" in the name, no usage-data concept (rows/metrics/period) lives on the model — only tags and workspace bindings. +- `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `UsagePolicy.bindingWorkspaceIds: number[]`. +- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #12). +- `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.1/accounts/{accountId}/usage-policies`). +- `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. + +## File coverage +- `src/v1/model.ts` (230 lines): read fully. +- `src/v1/client.ts` (252 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. Byte-identical to `budgetpolicy/src/v1/utils.ts` (same 4012-byte file size). +- `src/v1/index.ts` (20 lines): read fully. +- Cross-referenced: `packages/budgetpolicy/src/v1/model.ts`, `packages/budgetpolicy/src/v1/client.ts`, `packages/budgetpolicy/src/v1/index.ts` (the near-clone sibling), and previously-audited `.agent/naming-audit/budgetpolicy.md` for consistency. diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md new file mode 100644 index 00000000..7d1b7e96 --- /dev/null +++ b/.agent/naming-audit/volumes.md @@ -0,0 +1,493 @@ +# Naming Audit: `volumes` (v1) + +Package path: `/home/parth.bansal/sdk-js/packages/volumes/` +Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, +`src/v1/index.ts`. + +Notation: file paths are absolute. Findings reference `file:line`. + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 4 | +| Medium | 7 | +| Low | 7 | +| Observation | 8 | +| **Total** | **26** | + +Headline themes: + +1. **`fullNameArg` is a cryptic, Go/proto-generator-driven name** that leaks + internal path-parameter terminology into the public TypeScript API. The + `Arg` suffix is meaningless to TS users and inconsistent with the + `fullName` field on the response/info shapes. Appears on `GetVolume`, + `DeleteVolume`, and `UpdateVolume` (model.ts:56, 75, 126). +2. **Operation request types are bare verb-phrases** (`CreateVolume`, + `DeleteVolume`, `GetVolume`, `ListVolumes`, `UpdateVolume`) that collide + semantically with the client methods of the same camel-case names. This + is a repo-wide pattern but worth flagging here for documentation. +3. **`Create*` / `Update*` request types include read-only output fields** + (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, + `volumeId`, `fullName`, `browseOnly`). These belong only on + `VolumeInfo`. They appear on the request shapes because the upstream + proto reuses the same message — but on the TypeScript surface they + misleadingly invite users to "set" server-managed values. +4. **`SseEncryptionAlgorithm` repeats `SSE_ENCRYPTION_ALGORITHM_` in its + single zero-valued member** and shouts `AWS_SSE_S3` / `AWS_SSE_KMS` in + SCREAMING_SNAKE on the two real values — the SDK-wide proto-mirror + convention but jarring for TS readers. +5. **`DeleteVolume_Response`** uses an underscore separator that breaks + TypeScript naming convention, mirroring the proto-style nested message + name. + +--- + +## High Severity + +### H1. `fullNameArg` — cryptic `Arg` suffix on path-parameter fields + +- **File / line:** `src/v1/model.ts:56` (`DeleteVolume.fullNameArg`), + `src/v1/model.ts:75` (`GetVolume.fullNameArg`), + `src/v1/model.ts:126` (`UpdateVolume.fullNameArg`); cross-ref + `src/v1/client.ts:125, 154, 268`. +- **Category:** #5 cryptic abbreviation; #6 misleading name; #20 type- + suffix tautology (inverse — `Arg` is a non-domain suffix). +- **Current:** `fullNameArg?: string`. +- **Suggestion:** `fullName: string` (drop both the `Arg` suffix and the + unnecessary `?:` — this is a required path parameter). +- **Rationale:** `Arg` is a proto/grpc-generator artifact that signals "this + field maps to a URL path argument." TypeScript callers have no concept + of "Arg" — they just see two fields named `fullNameArg` and (on the + related `VolumeInfo` / `UpdateVolume` payload) `fullName`, with no way + to know they refer to the same volume identifier. The marshal schema + (`model.ts:358, 379`) further serializes this as `full_name_arg`, which + is a non-standard JSON key the server is unlikely to consume — the URL + templating in `client.ts:125, 154, 268` interpolates it into the path + directly, so the marshal entry is dead. The `?: | undefined` is also a + semantic lie — without this value the path becomes + `/api/2.1/unity-catalog/volumes/` and the call cannot succeed. + +### H2. `Create*` / `Update*` request types include server-only fields + +- **File / line:** `src/v1/model.ts:16–52` (`CreateVolume`), + `src/v1/model.ts:124–164` (`UpdateVolume`). +- **Category:** #6 misleading name; #16 field contradicting type domain; + #12 duplicate concepts. +- **Current:** `CreateVolume` and `UpdateVolume` both carry every field on + `VolumeInfo`: `volumeId`, `metastoreId`, `createdAt`, `createdBy`, + `updatedAt`, `updatedBy`, `fullName`, `browseOnly`. +- **Suggestion:** Trim the request shapes to the fields the server + actually accepts (per the Go SDK / OpenAPI). For `CreateVolume`: + `name`, `catalogName`, `schemaName`, `volumeType`, `storageLocation`, + `comment`. For `UpdateVolume`: `fullNameArg` (the path identifier), + `newName`, `owner`, `comment` (per the method docstring at + `client.ts:262`). +- **Rationale:** A request type named `CreateVolume` whose fields include + `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, and `volumeId` + invites users to populate them — but the server ignores or rejects + them. The `client.ts:262` doc itself says "Currently only the name, the + owner or the comment of the volume could be updated." Marshal schemas + at `model.ts:289–328` and `model.ts:356–398` faithfully serialize these + fields, padding every request body. Compare with the Go SDK + `databricks/sdk-go/databricks/api/volumes/v1/` to confirm the + upstream split. (Caveat: if the upstream proto truly reuses the same + message for request + response, the audit recommends a TS-specific + request type — name suggestions: `CreateVolumeRequest`, + `UpdateVolumeRequest`.) + +### H3. `DeleteVolume_Response` — underscore in TS identifier + +- **File / line:** `src/v1/model.ts:59–60`; cross-ref + `src/v1/client.ts:122, 124` (return type), `src/v1/index.ts:10`. +- **Category:** #4 underscores in TS identifiers; #14 Go/Java-style name. +- **Current:** `export interface DeleteVolume_Response {}` returned by + `deleteVolume(...)`. +- **Suggestion:** Rename to `DeleteVolumeResponse` (no underscore). Today + the lint rule has to be silenced inline (`// eslint-disable-next-line + @typescript-eslint/naming-convention`) which is itself a smell that the + name is wrong. +- **Rationale:** `Foo_Bar` is the proto-buf-generator idiom for nested + messages. TypeScript naming convention is PascalCase with no + underscores (Google TypeScript Style Guide §5.3.1). The same pattern is + used across the workspace (e.g. `catalogs.DeleteCatalog_Response`, + `connections.DeleteConnection_Response`) so this is a repo-wide call. + +### H4. `ListVolumes_Response` — underscore in TS identifier + +- **File / line:** `src/v1/model.ts:103–111`; cross-ref + `src/v1/client.ts:199`, `src/v1/index.ts:14`. +- **Category:** #4 underscores in TS identifiers; #14 Go/Java-style name. +- **Current:** `export interface ListVolumes_Response { volumes?: + VolumeInfo[]; nextPageToken?: string }`. +- **Suggestion:** `ListVolumesResponse` (no underscore). The inline + `eslint-disable-next-line @typescript-eslint/naming-convention` + acknowledges the violation. +- **Rationale:** Same as H3. Note also that the `ListVolumes` request + type and `ListVolumes_Response` response type share a stem — naming + them `ListVolumesRequest` / `ListVolumesResponse` would also resolve + the request-type-as-verb-phrase issue (M1 below). + +--- + +## Medium Severity + +### M1. Bare verb-phrase request type names collide with client methods + +- **File / line:** `src/v1/model.ts:16` (`CreateVolume`), `54` + (`DeleteVolume`), `73` (`GetVolume`), `80` (`ListVolumes`), `124` + (`UpdateVolume`); cross-ref `src/v1/client.ts:89, 121, 153, 196, 264`. +- **Category:** #6 misleading name; #14 Go/Java-style name. +- **Current:** Types named `CreateVolume`, `DeleteVolume`, etc., consumed + as `client.createVolume(req: CreateVolume)`. +- **Suggestion:** `CreateVolumeRequest`, `DeleteVolumeRequest`, + `GetVolumeRequest`, `ListVolumesRequest`, `UpdateVolumeRequest`. +- **Rationale:** The verb-phrase form reads like a function name. A + reader sees `function createVolume(req: CreateVolume): Promise<…>` and + must distinguish the verb-method from the verb-type. Sibling + packages `accountsettings`, `budgetpolicy`, `bundle` use the `Request` + suffix. `volumes` (and many sibling UC packages) omit it. Audit + observation, not a local defect — recorded as Medium because the + collision is most acute in `volumes` where every operation has a + matching type. + +### M2. `VolumeInfo` — redundant `Info` suffix + +- **File / line:** `src/v1/model.ts:166`. +- **Category:** #8 redundant suffix; #14 Go/Java-style name. +- **Current:** `VolumeInfo`. +- **Suggestion:** `Volume`. +- **Rationale:** `Info` adds no semantic content; the type *is* the + volume record. The `Info` suffix is a Go/proto idiom (cf. `CatalogInfo`, + `SchemaInfo`, `FunctionInfo`, `ConnectionInfo`) and is uniformly + applied across UC types. Renaming to `Volume` also frees the natural + domain noun — note that `volumes` has no type with the bare name + `Volume`, even though it is literally the "volumes" package. + +### M3. `SseEncryptionDetails` and `SseEncryptionAlgorithm` — uppercase +"Sse" acronym casing inconsistent across the type system + +- **File / line:** `src/v1/model.ts:5` (enum), `113` (interface), + `model.ts:68, 218, 219, 236, 332, 335` (field/usage). +- **Category:** #3 acronym casing inconsistencies; #14 Go/Java-style name. +- **Current:** `Sse` is rendered as a three-letter title-case acronym + (`Sse`, `sseEncryptionDetails`), but the enum member values use + SCREAMING_SNAKE (`AWS_SSE_S3`, `AWS_SSE_KMS`, + `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`). +- **Suggestion:** Per the Google TypeScript Style Guide §5.3.5 (acronyms + are treated as words: PascalCase or camelCase, not all-caps in identifiers), + `Sse` is the correct rendering for types and fields. The enum values + are correct as-is (the proto convention is SCREAMING_SNAKE_CASE for + values). Flagged here because some sibling packages in the codebase + use `SSE` or `SSEEncryption` — verify consistency. Today this package + is internally consistent (good). +- **Rationale:** Acronym casing is the single most common naming + inconsistency in TS codebases. `Sse` is the right choice; record this + as an observation in case a future audit flips it. + +### M4. `SseEncryptionDetails.algorithm` — generic field name on a +single-purpose type + +- **File / line:** `src/v1/model.ts:116`; cross-ref `model.ts:239, 243, + 348, 351`. +- **Category:** #1 vague/generic; #15 generic field name losing meaning. +- **Current:** `algorithm?: SseEncryptionAlgorithm`. +- **Suggestion:** `encryptionAlgorithm` — though, in context, the parent + type already says "SseEncryption", so `algorithm` is acceptable. This + is a borderline call. +- **Rationale:** Inside `SseEncryptionDetails`, `algorithm` is fine. The + flag stands only if the field is ever exposed in flatter scopes (it + isn't, locally). Listed for completeness; lower priority than M3. + +### M5. `awsKmsKeyArn` vs. `accessPoint` — inconsistent AWS-specific +field-naming style + +- **File / line:** `src/v1/model.ts:121` (`awsKmsKeyArn`); cross-ref + `model.ts:48, 159, 198` (`accessPoint`). +- **Category:** #1 vague/generic; #3 acronym casing inconsistencies; #6 + misleading name. +- **Current:** `awsKmsKeyArn?: string` lives on `SseEncryptionDetails` + (AWS-specific). `accessPoint?: string` lives on `CreateVolume` / + `UpdateVolume` / `VolumeInfo` but is also AWS-specific (the doc + comment at `model.ts:47, 159, 197` reads "The AWS access point to use + when accesing s3 for this external location."). +- **Suggestion:** Either prefix the latter as `awsAccessPoint` (matching + `awsKmsKeyArn`) or drop the prefix from both (`kmsKeyArn` and + `accessPoint`). Inconsistency is the issue. +- **Rationale:** Two AWS-only fields side-by-side, one prefixed, one not. + The doc comment also has a typo ("accesing" → "accessing"). + +### M6. `browseOnly` is a server-derived flag on request types + +- **File / line:** `src/v1/model.ts:51` (`CreateVolume.browseOnly`), + `163` (`UpdateVolume.browseOnly`), `201` (`VolumeInfo.browseOnly`). +- **Category:** #6 misleading name; #16 field contradicting type domain. +- **Current:** `browseOnly?: boolean | undefined` — present on the + request types but described in the doc as "Indicates whether the + principal is limited to retrieving metadata for the associated object + through the BROWSE privilege when include_browse is enabled in the + request." +- **Suggestion:** Remove from request types (see H2). On the response + type, the name itself is fine but the JSDoc should say "Read-only. + Set by the server when include_browse is true." +- **Rationale:** Sub-issue of H2; called out separately because the name + also reads ambiguously — `browseOnly: true` could be misread as "I + want browse-only access" rather than "the server has limited me to + browse-only." + +### M7. `req` parameter name on all client methods + +- **File / line:** `src/v1/client.ts:90, 122, 153, 197, 239, 265`. +- **Category:** #5 cryptic abbreviation; #14 Go-style name. +- **Current:** `req: CreateVolume`, `req: DeleteVolume`, etc. +- **Suggestion:** `request` (matches Go-port readability without + abbreviation). +- **Rationale:** Throughout the JS/TS ecosystem, function parameters are + spelled out (`request`, `response`) rather than abbreviated. The Go + `req`/`resp` idiom is fine in Go where short identifiers are + encouraged; in TS this reads as Go-translated code. Pervasive in this + package (every method uses `req`) and across the repo. + +--- + +## Low Severity + +### L1. `executeCall` vs. `executeHttpCall` — overlapping verbs + +- **File / line:** `src/v1/utils.ts:26, 65`. +- **Category:** #6 misleading name; #12 duplicate concepts. +- **Current:** Two functions in the same file with very similar names. + `executeCall` is the public-options translator delegating to `execute` + from `@databricks/sdk-core/api`. `executeHttpCall` is the low-level + HTTP send + parse helper. +- **Suggestion:** Rename `executeCall` to `runCallWithOptions` / + `dispatchCall` (or to match the JSDoc, `translateAndExecute`). The + JSDoc on line 22 already calls this a *translator* — the name should + match. +- **Rationale:** Two functions named `execute*Call` in 100 lines of + code, with different return shapes (`Promise` vs. + `Promise`), is a readability hazard. + +### L2. `Call` (imported, not local) and `call` local variable share names + +- **File / line:** `src/v1/client.ts:96, 127, 162, 220, 271`. +- **Category:** #1 vague/generic. +- **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. +- **Suggestion:** `httpCall` or `doRequest`. +- **Rationale:** `call` is a built-in word in JS (`.call()` on + functions), so a variable named `call` inside a method that is itself + a call is ambiguous. Caveat: this is a 1:1 port of Go SDK convention. + +### L3. `body` shadowed across `executeHttpCall` / `buildHttpRequest` / +`parseResponse` + +- **File / line:** `src/v1/utils.ts:81` (`body`, response bytes), `101` + (`body`, request body parameter), `113` (`body`, response bytes + again). +- **Category:** #1 vague generic name. +- **Current:** Single name `body` used for both request body and + response body, with different types + (`Uint8Array`, `string | ReadableStream`). +- **Suggestion:** `responseBody` / `requestBody`. +- **Rationale:** In `client.ts:94, 269` we see `const body = + marshalRequest(...)` (a request body) passed into `buildHttpRequest` + while inside `executeHttpCall` the `body` is a response payload. + Differentiating helps readers track direction. + +### L4. `marshalRequest` accepts `data: unknown` — the parameter name +contradicts the function's purpose + +- **File / line:** `src/v1/utils.ts:119`. +- **Category:** #15 generic field name losing meaning. +- **Current:** `function marshalRequest(data: unknown, schema: z.ZodType)`. +- **Suggestion:** `function marshalRequest(request: unknown, schema)` or + `(payload, schema)`. +- **Rationale:** The function name says "request"; the first argument + is named `data`. Calling at `client.ts:94, 269` reads + `marshalRequest(req, marshalCreateVolumeSchema)` — `req` → `data` loses + the request semantics in the helper. + +### L5. `flattenQueryParams` is dead code in this package + +- **File / line:** `src/v1/utils.ts:123`. +- **Category:** dead code. +- **Current:** Exported but not used by `client.ts` (the list / get + methods build params inline via `URLSearchParams.append` calls at + `client.ts:156–215`). +- **Suggestion:** Drop the export or move to a shared util package. +- **Rationale:** Unused exports become accidental public API. Out of + scope for pure naming but flagged because the name promises a feature + that no method exercises. + +### L6. `fullName` (on `VolumeInfo`) vs. `fullNameArg` (on path-param +requests) + +- **File / line:** `model.ts:36, 75, 126, 148, 186` (`fullName` on + `CreateVolume`, `UpdateVolume.fullName` in payload, `VolumeInfo.fullName`), + `model.ts:56, 75, 126` (`fullNameArg` as path param). +- **Category:** #6 misleading name; #19 underspecified IDs. +- **Current:** Two different fields naming the same logical concept + (the three-level volume identifier) differently depending on + request/response position. +- **Suggestion:** Resolve in concert with H1 — use `fullName` everywhere. + If proto generation requires the `_Arg` discriminator, then bury it + internally (in the marshal schema) and surface only `fullName` to + callers. +- **Rationale:** A user reading the API sees `fullName` on + `VolumeInfo` and `fullNameArg` on `DeleteVolume` and has to ask: why + are they different? The answer ("one is a request path parameter") + is generator-internal and should not bleed onto the public surface. + +### L7. `pageReq` and `pageReq.pageToken` mutation in `listVolumesIter` + +- **File / line:** `src/v1/client.ts:242–252`. +- **Category:** #1 vague/generic. +- **Current:** `const pageReq: ListVolumes = {...req};` then mutates + `pageReq.pageToken = resp.nextPageToken;` on each loop iteration. +- **Suggestion:** `currentPageRequest` or `nextPageRequest`. +- **Rationale:** `pageReq` is fine as a Go-ism, but the variable is + reassigned across iterations — `pageRequest` makes the mutation site + more legible. Minor. + +--- + +## Observations (repo-wide conventions, not local defects) + +### O1. Bare `Get*` / `Create*` / `Update*` / `Delete*` / `List*` request +shapes are a repo-wide pattern + +Sibling packages `catalogs`, `connections`, `clusters`, `externallocations`, +`clusterpolicies`, and most UC packages use bare verb-phrases for request +types. Changing this package alone would create asymmetry. See +`grep -rE "^export interface (Get|Set|Create|Update|Delete|List)" packages/` +for the workspace inventory. (M1 above flags it locally.) + +### O2. Proto-style nested message names with underscores are repo-wide + +`DeleteVolume_Response` and `ListVolumes_Response` follow the same pattern +as `ArtifactMatcher_MatchType`, `BudgetConfigurationFilter_Operator`, +`CleanRoomAutoApprovalRule_AuthorScope`, `ConversionInfo_State`, +`DatabaseInstance_State`, `EndpointStatus_State`, and 20+ other types +across the workspace. This violates TypeScript naming convention but is +the agreed mirror of the Go SDK's `Parent_Field` proto idiom. The file +disables the lint rules explicitly at `model.ts:59, 103, 204, 224`. Flag +for awareness only. + +### O3. `*_UNSPECIFIED` zero values repeated across enums + +`SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` +(`model.ts:6`) repeats the enum domain (`SSE_ENCRYPTION_ALGORITHM_`) in +the member name. This is a proto-buf default and is consistent with +sibling packages. The duplication makes `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` +60 characters long for what should read as `UNSPECIFIED`. Not a local +defect; would need a workspace-wide convention change. + +### O4. `…Info` suffix repeated across UC types + +`VolumeInfo` follows the `CatalogInfo`, `ConnectionInfo`, +`FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the +codebase decides to drop the `Info` suffix, this is one of many to fix +(M2 above flags it locally). + +### O5. `_Arg` suffix on path parameter fields is a generator-wide artifact + +`fullNameArg` (H1) is not unique to volumes — the workspace contains +fields like `nameArg`, `idArg`, `fullNameArg` across packages that take a +URL path parameter. Search: +`grep -rE "fullNameArg|nameArg|idArg" packages/*/src/`. Documented here +because the fix has cross-package implications. + +### O6. `VolumeType` enum members are clean + +`VolumeType.MANAGED` and `VolumeType.EXTERNAL` (`model.ts:11–14`) avoid +the SCREAMING_SNAKE_CASE long-form variant (no `VOLUME_TYPE_*` prefix). +This enum is the cleanest in the file and shows that the proto-mirror +pattern is not mandatory — `SseEncryptionAlgorithm` could have been +written this way too. + +### O7. URL path string repeated across methods without a named constant + +The base path `/api/2.1/unity-catalog/volumes` (and the suffixed +variant with `${req.fullNameArg ?? ''}`) appears five times in +`client.ts:93, 125, 154, 200, 268`. Not a naming defect, but typical +naming-audit findings include "unnamed magic strings." Worth a note. + +### O8. `PACKAGE_SEGMENT.key` / `.value` carry no descriptive name + +`client.ts:39–42`: `{key: pkgJson.name.replace(/^@[^/]+\//, ''), value: +pkgJson.version}`. The variable name `PACKAGE_SEGMENT` reads fine but +the `key`/`value` shape is generic — readers may not know `key` is +"package name" and `value` is "package version" without inspecting +`createDefault().with(...)`. No action required; cosmetic. Pattern is +identical across every generated client in the workspace. + +--- + +## Domain glossary + +| Term | Meaning in this package | +| -------------------------- | ---------------------------------------------------------- | +| Volume | A Unity Catalog securable representing a directory of files in cloud object storage. | +| Managed volume | Volume located in the default storage location specified by the parent schema, catalog, or metastore. | +| External volume | Volume located in a user-specified external location (S3 / ADLS / GCS path). | +| Catalog / Schema | Two outer levels of the UC three-level namespace; a volume's full name is `catalog.schema.volume`. | +| Full name (`fullName`) | The three-level (fully qualified) identifier `catalog.schema.volume`. | +| `fullNameArg` | Generator-internal name for the same three-level identifier when bound as a URL path parameter. | +| SSE | Server-Side Encryption (AWS S3). One of `AWS_SSE_S3` or `AWS_SSE_KMS`. | +| KMS ARN | AWS KMS Key ARN used by `AWS_SSE_KMS`. Sent via the `x-amz-server-side-encryption-aws-kms-key-id` S3 header. | +| Access point | AWS S3 access point used when accessing S3 for an external volume location. | +| Browse-only | A retrieval mode where the caller has only the `BROWSE` privilege on the volume and sees only metadata. | +| Metastore | Unity Catalog top-level container that owns the volume's catalog and schema. | +| Page token | Opaque pagination cursor. `nextPageToken` is server-emitted; absence signals end of results. | + +--- + +## File coverage + +| File | Lines | Audited | +| -------------- | ----- | ------------------------------------------------ | +| `src/v1/model.ts` | 399 | All 2 enums + 9 interfaces + 9 schemas + every field. | +| `src/v1/client.ts` | 289 | Class, constructor, 5 public methods + 1 iterator, all locals. | +| `src/v1/utils.ts` | 151 | All exported / private functions and types. | +| `src/v1/index.ts` | 19 | All re-exports. | + +Type & symbol checklist: + +- [x] `SseEncryptionAlgorithm` enum (3 members) → O3. +- [x] `VolumeType` enum (2 members) → O6 (clean). +- [x] `CreateVolume` interface (17 fields) → H2, M1, M5, M6. +- [x] `DeleteVolume` interface (1 field) → H1, M1, L6. +- [x] `DeleteVolume_Response` empty interface → H3. +- [x] `EncryptionDetails` interface → no additional defect. +- [x] `GetVolume` interface (2 fields) → H1, M1, L6. +- [x] `ListVolumes` interface (5 fields) → M1. +- [x] `ListVolumes_Response` interface (2 fields) → H4. +- [x] `SseEncryptionDetails` interface (2 fields) → M3, M4, M5. +- [x] `UpdateVolume` interface (18 fields) → H1, H2, M1, M5, M6, L6. +- [x] `VolumeInfo` interface (16 fields) → M2, M5, M6, L6, O4. +- [x] `unmarshalDeleteVolume_ResponseSchema` → H3. +- [x] `unmarshalEncryptionDetailsSchema` → no additional defect. +- [x] `unmarshalListVolumes_ResponseSchema` → H4. +- [x] `unmarshalSseEncryptionDetailsSchema` → no additional defect. +- [x] `unmarshalVolumeInfoSchema` → no additional defect. +- [x] `marshalCreateVolumeSchema` → H2. +- [x] `marshalEncryptionDetailsSchema` → no additional defect. +- [x] `marshalSseEncryptionDetailsSchema` → no additional defect. +- [x] `marshalUpdateVolumeSchema` → H1 (`full_name_arg` key), H2. +- [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. +- [x] `PACKAGE_SEGMENT` constant → O8. +- [x] `createVolume(req, options)` method → H2, M1, M7, L2. +- [x] `deleteVolume(req, options)` method → H1, H3, M1, M7, L2. +- [x] `getVolume(req, options)` method → H1, M1, M7, L2. +- [x] `listVolumes(req, options)` method → H4, M1, M7, L2. +- [x] `listVolumesIter(req, options)` async generator → M1, M7, L7. +- [x] `updateVolume(req, options)` method → H1, H2, M1, M7, L2. +- [x] `HttpCallOptions` interface → no defect. +- [x] `executeCall` function → L1. +- [x] `readAll` private function → no defect (name fits idiom). +- [x] `executeHttpCall` function → L1, L3. +- [x] `buildHttpRequest` function → L3. +- [x] `parseResponse` function → no defect. +- [x] `marshalRequest` function → L4. +- [x] `flattenQueryParams` function → L5 (unused). +- [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md new file mode 100644 index 00000000..74d5fa05 --- /dev/null +++ b/.agent/naming-audit/warehouses.md @@ -0,0 +1,1346 @@ +# Naming Audit: `warehouses` (v1) + +**Package:** `@databricks/sdk-warehouses` +**Path:** `/home/parth.bansal/sdk-js/packages/warehouses/` +**Version audited:** `v1` +**Files audited:** +- `src/v1/model.ts` +- `src/v1/client.ts` +- `src/v1/utils.ts` +- `src/v1/index.ts` + +This audit applies the 20 numbered concern categories from the audit +checklist. Each finding lists the offending identifier(s), the +category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete +rename suggestion. Findings are grouped by category. Generator-driven +items (such as `_Response` underscore on proto-style nested messages +and the `marshal`/`unmarshal` schema prefixes) are flagged as `LOW` +because they are codified across the entire generated SDK surface — +they should be fixed at the generator, not by hand-editing this +package. + +**Special historical context:** SQL Warehouses were renamed from +"SQL Endpoints" (legacy term). The proto definitions still use +`Endpoint`/`endpoint` extensively (state, health, security policy, +tags, conf pairs, info). The current customer-facing brand is +"warehouse", so leftover `Endpoint*` identifiers are misleading. +This is the dominant theme of the audit (see F0). + +--- + +## Inventory + +### Package identity + +| Item | Value | +| --------------- | ------------------------------------------- | +| Package name | `@databricks/sdk-warehouses` | +| Directory | `packages/warehouses/` | +| Subpath export | `./v1` | +| REST base paths | `/api/2.0/sql/warehouses`, `/api/2.0/sql/config/warehouses`, `/api/warehouses/v1/default-warehouse-overrides` | +| Concept | SQL Warehouses (formerly SQL Endpoints) and default warehouse overrides | + +### Enums (`model.ts`) + +| Name | Members | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `ChannelName` | `CHANNEL_NAME_UNSPECIFIED`, `CHANNEL_NAME_PREVIEW`, `CHANNEL_NAME_CURRENT`, `CHANNEL_NAME_PREVIOUS`, `CHANNEL_NAME_CUSTOM` | +| `DefaultWarehouseOverrideType` | `DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED`, `LAST_SELECTED`, `CUSTOM` | +| `EndpointSecurityPolicy` | `NONE`, `DATA_ACCESS_CONTROL`, `PASSTHROUGH` | +| `EndpointSpotInstancePolicy` | `POLICY_UNSPECIFIED`, `COST_OPTIMIZED`, `RELIABILITY_OPTIMIZED` | +| `EndpointState` | `STARTING`, `RUNNING`, `STOPPING`, `STOPPED`, `DELETING`, `DELETED` | +| `TerminationCode` | ~150 values (`UNKNOWN`, `USER_REQUEST`, `JOB_FINISHED`, `INACTIVITY`, ... `CERT_ROTATION`) | +| `TerminationType` | `SUCCESS`, `CLIENT_ERROR`, `SERVICE_FAULT`, `CLOUD_FAILURE` | +| `WarehouseType` | `TYPE_UNSPECIFIED`, `CLASSIC`, `PRO`, `REYDEN` | +| `EndpointHealth_Status` | `STATUS_UNSPECIFIED`, `HEALTHY`, `DEGRADED`, `FAILED` | + +### Interfaces (`model.ts`) + +`Channel`, `CreateDefaultWarehouseOverrideRequest`, `CreateWarehouse`, +`CreateWarehouse_Response`, `DefaultWarehouseOverride`, +`DeleteDefaultWarehouseOverrideRequest`, `EditWarehouseRequest`, +`EditWarehouseRequest_Response`, `EndpointConfPair`, `EndpointHealth`, +`EndpointInfo`, `EndpointTagPair`, `EndpointTags`, +`GetDefaultWarehouseOverrideRequest`, `GetWarehouse`, +`GetWarehouse_Response`, `GetWorkspaceWarehouseConfigRequest`, +`GetWorkspaceWarehouseConfigRequest_Response`, +`ListDefaultWarehouseOverridesRequest`, +`ListDefaultWarehouseOverridesResponse`, `OdbcParams`, +`RepeatedEndpointConfPairs`, `SetWorkspaceWarehouseConfigRequest`, +`SetWorkspaceWarehouseConfigRequest_Response`, `TerminationReason`, +`TerminationReason_ParametersEntry`, +`UpdateDefaultWarehouseOverrideRequest`, `WarehouseTypePair`, +`DeleteWarehouseRequest`, `DeleteWarehouseRequest_Response`, +`ListWarehousesRequest`, `ListWarehousesRequest_Response`, +`StartRequest`, `StartRequest_Response`, `StopRequest`, +`StopRequest_Response`. + +### Schemas (`model.ts`) + +`unmarshalChannelSchema`, `unmarshalCreateWarehouse_ResponseSchema`, +`unmarshalDefaultWarehouseOverrideSchema`, +`unmarshalEditWarehouseRequest_ResponseSchema`, +`unmarshalEndpointConfPairSchema`, `unmarshalEndpointHealthSchema`, +`unmarshalEndpointInfoSchema`, `unmarshalEndpointTagPairSchema`, +`unmarshalEndpointTagsSchema`, `unmarshalGetWarehouse_ResponseSchema`, +`unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema`, +`unmarshalListDefaultWarehouseOverridesResponseSchema`, +`unmarshalOdbcParamsSchema`, `unmarshalRepeatedEndpointConfPairsSchema`, +`unmarshalSetWorkspaceWarehouseConfigRequest_ResponseSchema`, +`unmarshalTerminationReasonSchema`, `unmarshalWarehouseTypePairSchema`, +`unmarshalDeleteWarehouseRequest_ResponseSchema`, +`unmarshalListWarehousesRequest_ResponseSchema`, +`unmarshalStartRequest_ResponseSchema`, +`unmarshalStopRequest_ResponseSchema`, `marshalChannelSchema`, +`marshalCreateWarehouseSchema`, `marshalDefaultWarehouseOverrideSchema`, +`marshalEditWarehouseRequestSchema`, `marshalEndpointConfPairSchema`, +`marshalEndpointTagPairSchema`, `marshalEndpointTagsSchema`, +`marshalRepeatedEndpointConfPairsSchema`, +`marshalSetWorkspaceWarehouseConfigRequestSchema`, +`marshalWarehouseTypePairSchema`, `marshalStartRequestSchema`, +`marshalStopRequestSchema`. Also exports +`defaultWarehouseOverrideFieldMask` helper and +`defaultWarehouseOverrideFieldMaskSchema` (private). + +### Client methods (`client.ts`) + +`createDefaultWarehouseOverride`, `createWarehouse`, +`createWarehouseWaiter`, `deleteDefaultWarehouseOverride`, +`deleteWarehouse`, `editWarehouse`, `editWarehouseWaiter`, +`getDefaultWarehouseOverride`, `getWarehouse`, +`getWorkspaceWarehouseConfig`, `listDefaultWarehouseOverrides`, +`listDefaultWarehouseOverridesIter`, `listWarehouses`, +`listWarehousesIter`, `setWorkspaceWarehouseConfig`, `startWarehouse`, +`startWarehouseWaiter`, `stopWarehouse`, `stopWarehouseWaiter`, +`updateDefaultWarehouseOverride`. + +### Client classes (`client.ts`) + +`Client`, `CreateWarehouseWaiter`, `EditWarehouseWaiter`, +`StartWarehouseWaiter`, `StopWarehouseWaiter`, +`StillRunningError` (private). + +### Utility functions (`utils.ts`) + +`executeCall`, `readAll` (private), `executeHttpCall`, +`buildHttpRequest`, `parseResponse`, `marshalRequest`, +`flattenQueryParams`. + +### Utility types/interfaces (`utils.ts`) + +`HttpCallOptions`. + +--- + +## F0 — Package-level: legacy "Endpoint" terminology leaks through the warehouse package + +This is the dominant finding for this package and should be read +before the categorized findings below. The package brand is +"warehouse" — every URL is `/sql/warehouses` and customer JSDoc uses +"SQL warehouse" — yet the proto types still use `Endpoint*` as a +prefix for state, health, tags, conf pairs, security policy, spot +instance policy, and the row record (`EndpointInfo`). The result is +a public surface in which `listWarehouses` returns +`EndpointInfo[]`, `getWarehouse` returns a value with an `endpoint`- +flavored health type, and the per-warehouse state machine is +`EndpointState`. This is historical baggage: SQL Warehouses were +formerly called SQL Endpoints, and the legacy names persist in the +proto. Every `Endpoint*` identifier in this package is flagged +below (F1.1, F1.2, F1.3, F1.4, F1.5, F12.x, F15.x). Renames should +happen at the proto / spec level to preserve wire-format +compatibility while updating the customer-visible type names. + +### F0.1 — Two product surfaces conflated under one package (HIGH) +- **Where:** `client.ts` exposes both `*Warehouse(s)` methods on + `/api/2.0/sql/warehouses` and `*DefaultWarehouseOverride(s)` + methods on `/api/warehouses/v1/default-warehouse-overrides`. +- **Why flagged:** These are two distinct resource families with + two distinct API base paths and two distinct API contracts (the + warehouse APIs are `/api/2.0/...` legacy; the override APIs are + `/api/warehouses/v1/...` AIP-compliant). The combined surface + forces a single client to carry 20 methods over two unrelated + resource trees. +- **Suggestion:** Either (a) split into `@databricks/sdk-warehouses` + and `@databricks/sdk-defaultwarehouseoverrides` (matches the + per-resource split in jobs/clusters), or (b) keep combined and + add a JSDoc on `Client` clearly explaining the two resource + families. Cross-cutting decision. + +### F0.2 — Conflict with `endpoints` package across the monorepo (MEDIUM, cross-package) +- **Where:** `packages/endpoints/` exports `Endpoint`, + `EndpointType`, `EndpointStatus`, `EndpointThroughputInfo`, etc. + for vector-search endpoints. This package exports + `EndpointInfo`, `EndpointHealth`, `EndpointState`, + `EndpointTags`, `EndpointTagPair`, `EndpointConfPair`, + `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy`, + `EndpointHealth_Status`, `RepeatedEndpointConfPairs` for SQL + warehouses. +- **Why flagged:** Three packages overload "Endpoint": + vector-search, model-serving, and SQL warehouses. An import line + `import {EndpointState, EndpointInfo} from '@databricks/sdk-warehouses'` + is misleading — the symbol name says "endpoint" while the package + name says "warehouses". A reader cannot grep for "endpoint" and + know which subsystem matches. +- **Suggestion:** Rename all `Endpoint*` types in this package to + `Warehouse*` (see F1.x, F12.x). Reconcile with the package brand. + +--- + +## Findings + +### 1. Vague / generic names + +#### F1.1 — `EndpointInfo` type name (HIGH) +- **Where:** `model.ts:1006`, `index.ts:33`, return field + `warehouses?: EndpointInfo[]` on `ListWarehousesRequest_Response` + (`model.ts:1482`), yield type of `listWarehousesIter` + (`client.ts:460`). +- **Why flagged:** Misleading legacy name. The type represents + a SQL warehouse (it has `clusterSize`, `warehouseType`, + `jdbcUrl`, `numClusters`, etc.), but the type is named + `EndpointInfo`. Same root concept as `GetWarehouse_Response`, + which has identical field set — so the type name should + match. "Info" is a Go-ism (see F14.2). +- **Suggestion:** Rename to `Warehouse` (the resource itself) or + `WarehouseInfo` if backward parity matters. Mirror + `GetWarehouse_Response` shape into a single canonical type + (see F12.1). + +#### F1.2 — `EndpointState` enum name (HIGH) +- **Where:** `model.ts:87`, `index.ts:16`. Used in + `EndpointInfo.state`, `GetWarehouse_Response.state`, and as the + poll-target inside every Waiter (`client.ts:656, 659, 660, 698, + ...`). +- **Why flagged:** The states themselves (`RUNNING`, `STOPPING`, + `STOPPED`, `DELETING`, `DELETED`, `STARTING`) are warehouse + states. JSDoc on the enum says "State of a warehouse." but the + type is named `EndpointState`. The mismatch forces every + customer-facing waiter to import `EndpointState` then check + `EndpointState.RUNNING` on a value whose type is warehouse. +- **Suggestion:** Rename to `WarehouseState`. The wire string can + remain identical (server expects `"RUNNING"`, etc., not + `"ENDPOINT_RUNNING"`), so this is a zero-cost rename at the + spec level. + +#### F1.3 — `EndpointHealth` interface and `EndpointHealth_Status` enum (HIGH) +- **Where:** `model.ts:993`, `model.ts:713`, `index.ts:20`. + Field on `EndpointInfo.health` and + `GetWarehouse_Response.health`. JSDoc says "Health status of + the endpoint" (`model.ts:994`). +- **Why flagged:** Same root issue as F1.1/F1.2. The health is + of a warehouse, not an endpoint. The waiters use + `pollResp.health?.summary` (`client.ts:661`) — a warehouse + health message. +- **Suggestion:** Rename to `WarehouseHealth` / + `WarehouseHealth_Status`. The proto-nested style of + `_Status` is a separate finding (F4.x). + +#### F1.4 — `EndpointTags`, `EndpointTagPair` interface names (HIGH) +- **Where:** `model.ts:1115, 1120`, `index.ts:31, 32`. Field + `tags?: EndpointTags` on `CreateWarehouse`, + `EditWarehouseRequest`, `EndpointInfo`, + `GetWarehouse_Response`. +- **Why flagged:** Same legacy naming. Tags are on warehouses, + not endpoints. JSDoc says "key-value pairs that will be + tagged on all resources … associated with this SQL warehouse" + (`model.ts:815, 959, 1077, 1212`). +- **Suggestion:** Rename to `WarehouseTags` / `WarehouseTagPair`. + +#### F1.5 — `EndpointConfPair`, `RepeatedEndpointConfPairs` (HIGH) +- **Where:** `model.ts:988, 1336`, `index.ts:30, 41`. +- **Why flagged:** Workspace-level SQL configuration parameters + (`globalParam`, `sqlConfigurationParameters`, etc.) are not + per-endpoint. They are workspace-scoped. The current name + conflates the legacy "endpoint" term with workspace config. +- **Suggestion:** Rename `EndpointConfPair` → `ConfigPair` or + `WarehouseConfigPair`. `RepeatedEndpointConfPairs` → + `RepeatedConfigPairs` (the "Repeated" prefix is also a + Go/proto-ism — see F14.3). + +#### F1.6 — `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` (HIGH) +- **Where:** `model.ts:26, 55`, `index.ts:14, 15`. Field on + `SetWorkspaceWarehouseConfigRequest.securityPolicy`, + `GetWorkspaceWarehouseConfigRequest_Response.securityPolicy`, + and `spotInstancePolicy` on each warehouse. +- **Why flagged:** Same legacy term. JSDoc on + `EndpointSecurityPolicy` reads "Security policy to be used for + warehouses". JSDoc on `EndpointSpotInstancePolicy` extensively + uses "endpoint" — see F0 above. +- **Suggestion:** Rename to `WarehouseSecurityPolicy` / + `WarehouseSpotInstancePolicy`. + +#### F1.7 — `Channel` type and `ChannelName` enum (MEDIUM) +- **Where:** `model.ts:728, 7`, `index.ts:12, 24`. +- **Why flagged:** "Channel" alone is a generic term (HTTP + channel, communication channel, marketing channel). In this + domain it means "DBSQL release channel" — `CHANNEL_NAME_PREVIEW`, + `CHANNEL_NAME_CURRENT`, `CHANNEL_NAME_PREVIOUS`, + `CHANNEL_NAME_CUSTOM`. The JSDoc says "Configures the channel + name and DBSQL version of the warehouse" but the type name + itself does not signal this. +- **Suggestion:** Rename to `WarehouseChannel` / + `WarehouseChannelName` (or `DbsqlChannel` / + `DbsqlChannelName`). Note: the enum name `ChannelName` + duplicates "name" — see F8.2. + +#### F1.8 — `name` field used both as a human name and as a path identifier (HIGH) +- **Where:** `name` appears on `CreateWarehouse` (`model.ts:754`, + "Logical name for the cluster"), `EditWarehouseRequest` + (`model.ts:898`), `EndpointInfo` (`model.ts:1016`), + `GetWarehouse_Response` (`model.ts:1151`), + `DefaultWarehouseOverride` (`model.ts:861`, + `default-warehouse-overrides/{default_warehouse_override_id}`), + `DeleteDefaultWarehouseOverrideRequest` (`model.ts:880`), + `GetDefaultWarehouseOverrideRequest` (`model.ts:1131`). +- **Why flagged:** Two semantically different things share the + field name `name`. On warehouses, `name` is a human-readable + display name ("My SQL warehouse"). On default-warehouse- + overrides, `name` is the resource-name path identifier + (`default-warehouse-overrides/123`). The latter is functionally + an ID. Caller code paths in `client.ts:196, 287, 588` use + `req.name` as the URL path segment for the override APIs. +- **Suggestion:** On the override types, rename `name` to + `resourceName` and document the path-id role. Alternatively, + document the dual role in JSDoc to make the contract explicit. + +#### F1.9 — `req` parameter name on every client method (LOW, Go-ism) +- **Where:** `client.ts:108, 152, 177, 193, 212, 240, 268, 284, + 309, 334, 365, 401, 419, 458, 476, 508, 533, 545, 570, 585`. +- **Why flagged:** `req` is a Go-ism (see category 14). It is + also generic. +- **Suggestion:** Use `request` for stylistic consistency with + `options` (which is spelled out). Cross-package decision. + +#### F1.10 — `resp` local variable everywhere (LOW) +- **Where:** `client.ts` throughout (e.g. `resp: + CreateWarehouse_Response | undefined`). +- **Why flagged:** Same Go abbreviation as `req`. See F14.1. +- **Suggestion:** `response` for consistency. Generator-level. + +#### F1.11 — `Client` class name (MEDIUM, cross-cutting) +- **Where:** `client.ts:78`, `index.ts:4`. +- **Why flagged:** Every package in this SDK exports a `Client`. + `import {Client} from '@databricks/sdk-warehouses'` is + unqualified and routinely needs aliasing at the call site. +- **Suggestion:** Either keep `Client` and document the alias + convention, or rename to `WarehousesClient` consistently + across packages. Cross-cutting decision. + +#### F1.12 — `code` field on `TerminationReason` (LOW) +- **Where:** `model.ts:1393`. +- **Why flagged:** `code` is generic; disambiguated by container + type, but `terminationCode` would be clearer in isolation. +- **Suggestion:** Acceptable as-is given the containing type. + Already typed against the `TerminationCode` enum, so renaming + introduces redundancy. Leave. + +#### F1.13 — `type` field on `TerminationReason` and `DefaultWarehouseOverride` (LOW) +- **Where:** `model.ts:865, 1395`. +- **Why flagged:** `type` is one of the most generic identifier + names possible. Both are typed against domain-specific enums, + but the field name alone gives no hint. +- **Suggestion:** Acceptable given typing; `terminationType` / + `overrideType` would be more self-documenting. + +#### F1.14 — `parameters` field on `TerminationReason` (LOW) +- **Where:** `model.ts:1397`. +- **Why flagged:** `parameters` is generic. JSDoc says "list of + parameters that provide additional information about why the + cluster was terminated" — these are debug context, not request + parameters. +- **Suggestion:** Rename to `details` or `context`. Currently + conflicts with the `parameters` URL-query terminology used + elsewhere in the SDK. + +#### F1.15 — `details`, `message`, `summary` fields on `EndpointHealth` (LOW) +- **Where:** `model.ts:997, 1001, 1003`. +- **Why flagged:** Three generic prose fields. JSDoc clarifies: + `message` is deprecated; `summary` is short; `details` is long. + Their relationship is not obvious from names. +- **Suggestion:** Rename `details` → `errorDetails`. Keep `summary` + and `message` (deprecated). Or merge `summary`+`details` into + a single nested structure. + +#### F1.16 — `customTags` field on `EndpointTags` (LOW) +- **Where:** `model.ts:1121`. +- **Why flagged:** "custom" is implied by the container type + `EndpointTags` (vs. a more specific name). The field is just + a list of tags, so the `custom` prefix adds no information + the container does not already supply. +- **Suggestion:** Rename to `tags` (the container already + conveys the "custom" scope). + +#### F1.17 — `Call`, `Options` (imported, cross-package) (acceptable) +- **Where:** `utils.ts:3`, `client.ts:4`. +- These come from `@databricks/sdk-core/api`. Generic but + intentional. Out of scope for this package's audit. + +--- + +### 2. Redundant enum prefixes + +#### F2.1 — `ChannelName.CHANNEL_NAME_*` (HIGH) +- **Where:** `model.ts:7-13`. + ```ts + export enum ChannelName { + CHANNEL_NAME_UNSPECIFIED = 'CHANNEL_NAME_UNSPECIFIED', + CHANNEL_NAME_PREVIEW = 'CHANNEL_NAME_PREVIEW', + CHANNEL_NAME_CURRENT = 'CHANNEL_NAME_CURRENT', + CHANNEL_NAME_PREVIOUS = 'CHANNEL_NAME_PREVIOUS', + CHANNEL_NAME_CUSTOM = 'CHANNEL_NAME_CUSTOM', + } + ``` +- **Why flagged:** Every member prefixed with `CHANNEL_NAME_` — + exactly the enum name. Reads `ChannelName.CHANNEL_NAME_PREVIEW` + ("channel name . channel name preview"). Worst form of the + category. +- **Suggestion:** Strip prefix on TS identifier; keep wire + strings: + ```ts + export enum ChannelName { + UNSPECIFIED = 'CHANNEL_NAME_UNSPECIFIED', + PREVIEW = 'CHANNEL_NAME_PREVIEW', + CURRENT = 'CHANNEL_NAME_CURRENT', + PREVIOUS = 'CHANNEL_NAME_PREVIOUS', + CUSTOM = 'CHANNEL_NAME_CUSTOM', + } + ``` + +#### F2.2 — `DefaultWarehouseOverrideType.DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED` (HIGH) +- **Where:** `model.ts:16-23`. + ```ts + DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED = '...', + LAST_SELECTED = 'LAST_SELECTED', + CUSTOM = 'CUSTOM', + ``` +- **Why flagged:** Only the unspecified member carries the + redundant prefix; the other members do not. Inconsistent + within the enum. +- **Suggestion:** Strip prefix on the unspecified member: + `UNSPECIFIED = 'DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED'`. + Wire string preserved. + +#### F2.3 — `EndpointSpotInstancePolicy.POLICY_UNSPECIFIED` (MEDIUM) +- **Where:** `model.ts:76`. +- **Why flagged:** `POLICY_` is redundant — the enum is + `EndpointSpotInstancePolicy`. The JSDoc explicitly explains + this choice as a compromise to "avoid customer-facing JSON … + `ENDPOINT_SPOT_INSTANCE_POLICY_UNSPECIFIED`". So `POLICY_` was + picked as a shorter prefix — but it is still partially + redundant. +- **Suggestion:** On the TS identifier, drop the `POLICY_` + prefix: `UNSPECIFIED = 'POLICY_UNSPECIFIED'`. Wire string + preserved. Other members are already prefix-free. + +#### F2.4 — `WarehouseType.TYPE_UNSPECIFIED` (MEDIUM) +- **Where:** `model.ts:703`. +- **Why flagged:** `TYPE_` prefix duplicates the type-noun in + the enum name (`WarehouseType`). Other members + (`CLASSIC`, `PRO`, `REYDEN`) carry no prefix — so inconsistent. +- **Suggestion:** Strip prefix on TS identifier: + `UNSPECIFIED = 'TYPE_UNSPECIFIED'`. Or rename wire to + `WAREHOUSE_TYPE_UNSPECIFIED` for symmetry, then strip on TS. + +#### F2.5 — `EndpointHealth_Status.STATUS_UNSPECIFIED` (MEDIUM) +- **Where:** `model.ts:715`. +- **Why flagged:** `STATUS_` prefix duplicates the type-noun. + Other members (`HEALTHY`, `DEGRADED`, `FAILED`) carry no + prefix. Inconsistent. +- **Suggestion:** `UNSPECIFIED = 'STATUS_UNSPECIFIED'`. + +#### F2.6 — No prefix on `TerminationCode` (~150 enum members) (acceptable) +- **Where:** `model.ts:103-687`. +- **Why flagged:** Members are domain-specific + (`USER_REQUEST`, `JOB_FINISHED`, `INACTIVITY`, + `CLOUD_PROVIDER_SHUTDOWN`, etc.) without a "TERMINATION_" + prefix. This is correct. +- **Suggestion:** No change. Good pattern; other enums should + follow. + +#### F2.7 — No prefix on `TerminationType` (acceptable) +- **Where:** `model.ts:690-699`. Members `SUCCESS`, + `CLIENT_ERROR`, `SERVICE_FAULT`, `CLOUD_FAILURE`. +- **Suggestion:** No change. + +#### F2.8 — No prefix on `EndpointState` (acceptable) +- **Where:** `model.ts:87-100`. +- **Suggestion:** No change. + +#### F2.9 — No prefix on `EndpointSecurityPolicy` (acceptable) +- **Where:** `model.ts:26-33`. Members `NONE`, + `DATA_ACCESS_CONTROL`, `PASSTHROUGH`. +- **Suggestion:** No change. + +--- + +### 3. Acronym casing inconsistencies + +#### F3.1 — `Id` vs `ID` (acceptable, SDK-wide) +- **Where:** `id`, `defaultWarehouseOverrideId`, `warehouseId`, + `runAsUserId`. Consistent lower-camel `Id`. +- **Suggestion:** No change. + +#### F3.2 — `SQL` rendered as `Sql` in `sqlConfigurationParameters` (LOW) +- **Where:** `model.ts:1281, 1370`. +- **Why flagged:** `sqlConfigurationParameters` uses lowercase + `sql`. The SDK applies "first letter cap, rest lower" for + TLAs in camelCase — but the field starts the identifier and + is rendered all lowercase. This is internally consistent with + the rest of the SDK (`url`, `http`, `id` all lowercase when + leading). Flag because the JSDoc and prose use uppercase + "SQL" throughout — only the identifier deviates. +- **Suggestion:** No change to identifier. SDK-wide pattern. + +#### F3.3 — `DBSQL` rendered as `Dbsql` in `dbsqlVersion` (LOW) +- **Where:** `model.ts:730`, `Channel.dbsqlVersion`. +- **Why flagged:** `DBSQL` is a Databricks-internal product + name. Wire form is `dbsql_version` (all lowercase). TS form + `dbsqlVersion` lowercases the whole acronym. Consistent with + `sql`, `jdbc`, `odbc` elsewhere in this package. +- **Suggestion:** Acceptable; consistent with adjacent fields. + +#### F3.4 — `JDBC` rendered as `jdbc` in `jdbcUrl` (acceptable) +- **Where:** `model.ts:1108, 1243`. Field `jdbcUrl`. +- **Why flagged:** Consistent with `http`, `url`. Lowercase + acronyms in lower-camel. Note `Url` not `URL` (also lowercase + TLA). Internally consistent. +- **Suggestion:** No change. + +#### F3.5 — `ODBC` rendered in mixed forms (LOW) +- **Where:** `model.ts:1110, 1245, 1329`. Type `OdbcParams` + (Pascal case, "Odbc" mixed); field `odbcParams` (lower-camel + "odbc"). +- **Why flagged:** Type uses `Odbc` (first letter cap, rest + lowercase); field uses `odbc` (all lowercase, leading + position). This is consistent with the SDK convention for + TLAs in identifier-leading vs. middle positions, but a careful + reader will notice the asymmetry. +- **Suggestion:** Acceptable; consistent with `HttpClient` vs. + `httpClient` pattern. Leave. + +#### F3.6 — `IAM` casing (acceptable, JSDoc only) +- **Where:** `model.ts:812, 956, 1074, 1209, 1267, 1356`. +- **Why flagged:** "IAM role" appears in JSDoc only; no + identifier rendering. +- **Suggestion:** No change. + +#### F3.7 — `URL` / `Url` (acceptable) +- **Where:** `client.ts` uses `url` consistently (leading + position). Type `jdbcUrl` uses `Url`. Internally consistent. +- **Suggestion:** No change. + +--- + +### 4. Underscores in TS identifiers + +#### F4.1 — Proto-nested message naming with underscore (HIGH, generator-driven) +- **Where:** + - `CreateWarehouse_Response` (`model.ts:842`) + - `EditWarehouseRequest_Response` (`model.ts:986`) + - `GetWarehouse_Response` (`model.ts:1141`) + - `GetWorkspaceWarehouseConfigRequest_Response` (`model.ts:1258`) + - `SetWorkspaceWarehouseConfigRequest_Response` (`model.ts:1389`) + - `DeleteWarehouseRequest_Response` (`model.ts:1453`) + - `ListWarehousesRequest_Response` (`model.ts:1480`) + - `StartRequest_Response` (`model.ts:1500`) + - `StopRequest_Response` (`model.ts:1512`) + - `TerminationReason_ParametersEntry` (`model.ts:1401`) + - `EndpointHealth_Status` (`model.ts:713`) +- **Why flagged:** Underscores are not idiomatic in TS + identifiers. The `Foo_Response` convention is leaked from the + protobuf nested-message representation. Each affected line has + an `eslint-disable @typescript-eslint/naming-convention` comment + acknowledging this. +- **Suggestion:** Generator-level. Replace with namespaces: + ```ts + export namespace CreateWarehouse { + export interface Response { id?: string } + } + ``` + Or pure name concatenation: `CreateWarehouseResponse`, + `EditWarehouseResponse`, etc. — this matches the convention + used by the rest of the JS SDK for top-level types. + +#### F4.2 — Schema names inherit the underscore (HIGH, generator-driven) +- **Where:** + - `unmarshalCreateWarehouse_ResponseSchema` (`model.ts:1525`) + - `unmarshalEditWarehouseRequest_ResponseSchema` (`model.ts:1550`) + - `unmarshalGetWarehouse_ResponseSchema` (`model.ts:1646`) + - `unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema` (`model.ts:1694`) + - `unmarshalSetWorkspaceWarehouseConfigRequest_ResponseSchema` (`model.ts:1774`) + - `unmarshalDeleteWarehouseRequest_ResponseSchema` (`model.ts:1800`) + - `unmarshalListWarehousesRequest_ResponseSchema` (`model.ts:1804`) + - `unmarshalStartRequest_ResponseSchema` (`model.ts:1816`) + - `unmarshalStopRequest_ResponseSchema` (`model.ts:1820`) +- **Why flagged:** Same root cause as F4.1. Schema identifiers + carry the underscore. +- **Suggestion:** Generator-level. Drop underscore when + generating schema names. + +--- + +### 5. Cryptic abbreviations + +#### F5.1 — `Mins` for minutes (`autoStopMins`) (LOW) +- **Where:** `model.ts:809, 953, 1071, 1206`. +- **Why flagged:** "Mins" is mildly informal. Compare to other + duration fields in the SDK that use `Seconds`, `Hours`. JSDoc + always spells out "minutes" in prose. +- **Suggestion:** Rename to `autoStopMinutes`. Wire stays + `auto_stop_mins` for compatibility. + +#### F5.2 — `Conf` for configuration (`EndpointConfPair`, `configPair`, `dataAccessConfig`) (MEDIUM) +- **Where:** `model.ts:988, 1265, 1338, 1354`. +- **Why flagged:** "Conf" is an abbreviation. Inconsistent + within the package: `RepeatedEndpointConfPairs` has both + `configPair` and `configurationPairs` (the latter is + spelled out). The package alternates between `Conf`, + `Config`, `Configuration`. +- **Suggestion:** Standardize on `Config` (already in + `dataAccessConfig`). Rename `EndpointConfPair` → `ConfigPair`, + `configPair` → `configPairs` (also plural; see F9.x). + +#### F5.3 — `Param` for parameter (`globalParam`, `configParam`) (MEDIUM) +- **Where:** `model.ts:1277, 1279, 1366, 1368, 1724-1725, 1962-1967`. +- **Why flagged:** "Param" is a cryptic abbreviation when the + full word "parameter" is also in use in this package + (`sqlConfigurationParameters`, `TerminationReason.parameters`, + `TerminationReason_ParametersEntry`). Inconsistent. +- **Suggestion:** Rename to `globalParameter`, `configParameter` + (or pluralize, see F9.x). JSDoc on both says "Deprecated: Use + sql_configuration_parameters" — they are slated for removal, + so the rename can be paired with deprecation removal. + +#### F5.4 — `Num` for number (`numClusters`, `numActiveSessions`, `maxNumClusters`, `minNumClusters`) (LOW) +- **Where:** `model.ts:787, 798, 1049, 1060, 1102, 1104, 1184, 1195, 1237, 1239`. +- **Why flagged:** "Num" is a programmer-ism. SDK and other + packages occasionally spell it out as `count` or `number`. +- **Suggestion:** Acceptable; widely used across the API. Note + that `numActiveSessions` is deprecated. Consider + `clusterCount`, `activeSessionCount`, `maxClusterCount`, + `minClusterCount` for clarity, but consistency with wire + takes priority. Leave. + +#### F5.5 — `Arn` for AWS Resource Name (`instanceProfileArn`) (acceptable) +- **Where:** `model.ts:813, 957, 1075, 1210, 1271, 1360`. +- **Why flagged:** `ARN` is a well-known AWS acronym. Casing + matches `instanceProfileArn` (first letter cap, rest lower). + No issue. +- **Suggestion:** No change. + +#### F5.6 — `Conf` vs. `Config` vs. `Configuration` (MEDIUM, internal inconsistency) +- **Where:** Repeated across `EndpointConfPair`, + `dataAccessConfig`, `sqlConfigurationParameters`, + `configPair`, `configurationPairs`, `globalParam`, + `configParam`. +- **Why flagged:** Three different ways to write the same word + in the same file. Confusing. +- **Suggestion:** Pick one. Suggest `Config` for short field + names, `Configuration` for spelled-out prose. Or fully + spell out everywhere. + +#### F5.7 — `req`, `resp` Go-ism abbreviations (LOW) +- **Where:** `client.ts` throughout. +- Already covered in F1.9 and F1.10. + +--- + +### 6. Misleading names + +#### F6.1 — `EndpointInfo` for a warehouse record (HIGH) +- **Where:** `model.ts:1006`. +- Covered in F1.1 / F0. The most glaring example: a value of + type `EndpointInfo` is a warehouse, not an endpoint. +- **Suggestion:** Rename to `Warehouse` or `WarehouseInfo`. + +#### F6.2 — `EndpointState` for warehouse states (HIGH) +- Covered in F1.2 / F0. + +#### F6.3 — `EndpointHealth` for warehouse health (HIGH) +- Covered in F1.3 / F0. + +#### F6.4 — `EndpointTags` / `EndpointTagPair` for warehouse tags (HIGH) +- Covered in F1.4 / F0. + +#### F6.5 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) +- **Where:** `model.ts:988, 1336`. Used inside + `GetWorkspaceWarehouseConfigRequest_Response.dataAccessConfig` + (workspace-scoped) and `globalParam` (also workspace-scoped). +- **Why flagged:** Field name says "endpoint conf" but the + scope is workspace. +- **Suggestion:** Rename to `WorkspaceConfigPair` or + `ConfigPair`. + +#### F6.6 — `ChannelName` enum used for the channel's "version selector" (LOW) +- **Where:** `model.ts:7`. +- **Why flagged:** Enum is named `ChannelName` (suggesting just + the "name"), but the values include `CUSTOM` and a + release-channel concept. `ChannelType` would be more + accurate. +- **Suggestion:** Rename to `ChannelType` or `WarehouseChannel`. + +#### F6.7 — `Channel.dbsqlVersion` as the override mechanism (LOW) +- **Where:** `model.ts:730`. +- **Why flagged:** Field is required only when `name` is + `CHANNEL_NAME_CUSTOM`. JSDoc on the parent says so. Name + itself does not convey the conditional contract. +- **Suggestion:** Add JSDoc; field name is fine. + +#### F6.8 — `instanceProfileArn` JSDoc says "Deprecated" but field remains (LOW) +- **Where:** `model.ts:812, 956, 1074, 1209`. +- **Why flagged:** Identifier carries no `_DEPRECATED` marker; + only JSDoc. Customer code completion shows it as a normal + field. +- **Suggestion:** Add `@deprecated` JSDoc tag (separate from + prose) so IDEs strike it through. + +#### F6.9 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) +- **Where:** `model.ts:811, 955, 1073, 1208`. +- **Why flagged:** The field is settable on + `CreateWarehouse`/`EditWarehouseRequest`, but its meaning is + read-only on the server side ("creator" never changes after + create). Surfacing it as settable on `Edit` is misleading. +- **Suggestion:** Spec-level. Mark read-only on response types + only. + +#### F6.10 — `EndpointHealth.message` is "Deprecated" prose but no marker (LOW) +- **Where:** `model.ts:997`. +- Same pattern as F6.8. + +#### F6.11 — Waiter `done` returns true on terminal failure states (MEDIUM) +- **Where:** `client.ts:684, 764, 844, 919` (the `done()` of + each Waiter). +- **Why flagged:** `done()` returns `true` for `RUNNING`, + `STOPPED`, `DELETED` indiscriminately. A caller who reads + "done()" expects success, but `DELETED` is a failure for + `CreateWarehouseWaiter`/`StartWarehouseWaiter`. The wait() + method correctly distinguishes (throws on + STOPPED/DELETED), but done() does not. +- **Suggestion:** Either rename `done()` to `terminal()` / + `settled()` (clearly signals "stopped progressing", not + "succeeded"), or split into `done()` (succeeded) and + `terminal()` (any terminal state). Cross-cutting waiter API + decision. + +--- + +### 7. Overly verbose + +#### F7.1 — `CreateDefaultWarehouseOverrideRequest`, `GetDefaultWarehouseOverrideRequest`, `UpdateDefaultWarehouseOverrideRequest`, `DeleteDefaultWarehouseOverrideRequest`, `ListDefaultWarehouseOverridesRequest`, `ListDefaultWarehouseOverridesResponse` (MEDIUM) +- **Where:** `model.ts:734, 1125, 1407, 874, 1300, 1319`. +- **Why flagged:** All AIP-style "DefaultWarehouseOverride" + resources. The names are accurate but very long + (39-48 characters). The matching client methods + (`createDefaultWarehouseOverride`, + `listDefaultWarehouseOverridesIter`) inherit the same length. +- **Suggestion:** Acceptable; AIP-compliant. Aliasing at the + call site is the typical workaround. + +#### F7.2 — `marshalSetWorkspaceWarehouseConfigRequestSchema` and +`unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema` (LOW) +- **Where:** `model.ts:1694, 1953`. 51 and 51 characters + respectively. +- **Why flagged:** Schema names approach 60 chars and contain + every part of the wire name. Generator-driven; readability is + poor. +- **Suggestion:** Generator-level. Could shorten by dropping + the `Request_Response` chain to just `Response`: + `unmarshalGetWorkspaceWarehouseConfigResponseSchema`. + +#### F7.3 — `defaultWarehouseOverrideFieldMaskSchema`, +`defaultWarehouseOverrideFieldMask` (LOW) +- **Where:** `model.ts:2015, 2022`. +- **Why flagged:** Long, but consistent with the AIP-style + resource name. Acceptable. + +--- + +### 8. Redundant suffixes + +#### F8.1 — `Request` suffix on every request interface (HIGH, generator-driven) +- **Where:** `CreateDefaultWarehouseOverrideRequest`, + `DeleteDefaultWarehouseOverrideRequest`, + `EditWarehouseRequest`, `GetDefaultWarehouseOverrideRequest`, + `GetWorkspaceWarehouseConfigRequest`, + `ListDefaultWarehouseOverridesRequest`, + `SetWorkspaceWarehouseConfigRequest`, + `UpdateDefaultWarehouseOverrideRequest`, + `DeleteWarehouseRequest`, `ListWarehousesRequest`, + `StartRequest`, `StopRequest`. +- **Why flagged:** Caller already supplies the request via the + parameter type position — the `Request` suffix is a + belt-and-suspenders signal. Note the inconsistency: some types + drop the suffix entirely (`CreateWarehouse`, `GetWarehouse`), + others keep it. +- **Suggestion:** Standardize. The `_Response` underscore type + pattern (F4.1) ties the request name to the response name — + if request is `Foo`, response is `Foo_Response`. So + `EditWarehouseRequest` should be `EditWarehouse` for symmetry + with `CreateWarehouse` / `GetWarehouse`. Generator-level. + +#### F8.2 — `Name` suffix on `ChannelName` enum (MEDIUM) +- **Where:** `model.ts:7`. +- **Why flagged:** Both `ChannelName.CHANNEL_NAME_PREVIEW` (the + enum) and the `name` field on `Channel` of type `ChannelName` + — three layers of "name". The enum is more accurately a + "Channel Type". +- **Suggestion:** Rename enum to `ChannelType`. Field + `Channel.name` → `Channel.type` (this also clarifies + intent — Custom vs. Preview is the *type* of channel). + +#### F8.3 — `Pair` suffix on `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair` (MEDIUM) +- **Where:** `model.ts:1115, 988, 1434`. +- **Why flagged:** "Pair" is a generic suffix that adds little + information when the type's two fields are obvious. For + `EndpointTagPair` (`key`, `value`), the suffix duplicates the + shape already evident from the fields. +- **Suggestion:** Rename `EndpointTagPair` → `Tag`, + `EndpointConfPair` → `Config`, `WarehouseTypePair` → + `WarehouseTypeAvailability` (or similar) — wire-aligned but + semantically clearer than the `Pair` suffix. + +#### F8.4 — `Info` suffix on `EndpointInfo` (HIGH, Go-ism) +- **Where:** `model.ts:1006`. +- **Why flagged:** "Info" is a Go-ism — it carries no + semantic value in TS. See category 14. +- **Suggestion:** Rename to `Warehouse`. Aligns with F1.1. + +#### F8.5 — `_Response` underscore suffix (HIGH, generator-driven) +- Covered in F4.1. + +#### F8.6 — `Request_Response` chain in schema names (HIGH, generator-driven) +- Covered in F4.2. + +#### F8.7 — `Schema` suffix on every schema (LOW, generator-driven) +- **Where:** All `marshal*Schema`, `unmarshal*Schema` exports. +- **Why flagged:** `Schema` is a Zod-specific convention; not + inherently bad, but redundant with the `marshal`/`unmarshal` + prefix. Acceptable. + +#### F8.8 — `Params` suffix on `OdbcParams` (LOW) +- **Where:** `model.ts:1329`. +- **Why flagged:** Mild noise. Type has `hostname`, `path`, + `protocol`, `port` — `OdbcConnectionInfo` would be more + accurate. +- **Suggestion:** Acceptable as-is; `OdbcParams` follows + the standard "parameters" terminology. + +--- + +### 9. Singular / plural mismatches + +#### F9.1 — `RepeatedEndpointConfPairs.configPair` is plural-content singular-name (HIGH) +- **Where:** `model.ts:1338`. +- **Why flagged:** Field type is `EndpointConfPair[]` (array) + but field name is singular `configPair`. The wire form is + `config_pair`. Compare to sibling `configurationPairs` (same + type, but plural name). Inconsistent within the type. +- **Suggestion:** Rename to `configPairs`. Wire stays + `config_pair` if deprecated, or rename wire to `config_pairs`. + +#### F9.2 — `TerminationReason.parameters` is a map, not a list (LOW) +- **Where:** `model.ts:1397`. Type `Record`. +- **Why flagged:** `parameters` is plural but typed as a map. + Plural maps are fine but inconsistent — compare to + `globalParam` / `configParam` which are singular. +- **Suggestion:** Acceptable; map semantics are clear from the + type. Plural is correct. + +#### F9.3 — `globalParam`, `configParam` are singular names for list-valued fields (MEDIUM) +- **Where:** `model.ts:1277, 1279, 1366, 1368`. +- **Why flagged:** Both fields are of type + `RepeatedEndpointConfPairs` — a list. Singular name on a + list-valued field is misleading. Compare to + `sqlConfigurationParameters` (plural) for the same concept. +- **Suggestion:** Rename to `globalParams` / `configParams` + (also pair with the `Param`/`Parameter` expansion in F5.3). + +#### F9.4 — `enabledWarehouseTypes` plural array (acceptable) +- **Where:** `model.ts:1296, 1385`. +- **Why flagged:** Plural name + array type. Correct. +- **Suggestion:** No change. + +#### F9.5 — `defaultWarehouseOverrides` plural array (acceptable) +- **Where:** `model.ts:1321`. +- **Why flagged:** Correct. +- **Suggestion:** No change. + +#### F9.6 — `warehouses` plural array (acceptable) +- **Where:** `model.ts:1482`. Correct. + +#### F9.7 — `customTags` plural array (acceptable) +- **Where:** `model.ts:1121`. Correct. + +--- + +### 10. Reserved-word collisions + +#### F10.1 — `type` field (LOW) +- **Where:** `DefaultWarehouseOverride.type` (`model.ts:865`), + `TerminationReason.type` (`model.ts:1395`). +- **Why flagged:** `type` is a TS keyword in certain positions + (the `type` modifier in type imports), but valid as a + property name. No actual collision. Some linters warn. +- **Suggestion:** Acceptable; common pattern in TS APIs. + +#### F10.2 — `name`, `id` (acceptable) +- Common property names; not reserved. + +#### F10.3 — `delete` not used as identifier (acceptable) +- Used only as method name `deleteWarehouse`, + `deleteDefaultWarehouseOverride` — fine in TS (verb prefix). + +#### F10.4 — `default-warehouse-overrides` URL segment vs. `default` TS keyword (acceptable) +- **Where:** Path string only. Not an identifier. + +--- + +### 11. Empty / trivial wrapper types + +_None. Wrappers are retained for forward compatibility._ + +--- + +### 12. Duplicate concepts / historical baggage + +#### F12.1 — `EndpointInfo` and `GetWarehouse_Response` are the same record (HIGH) +- **Where:** `model.ts:1006` and `model.ts:1141`. +- **Why flagged:** Both types have identical field sets (~20 + identical fields). One is the per-warehouse record in + `listWarehouses`, the other is the result of `getWarehouse`. + Duplicating the shape across two types means every change has + to happen in two places. Note also `unmarshalEndpointInfoSchema` + (`model.ts:1579`) and `unmarshalGetWarehouse_ResponseSchema` + (`model.ts:1646`) are nearly identical Zod schemas. +- **Suggestion:** Collapse into one type (call it `Warehouse`). + `GetWarehouse_Response = Warehouse`. `EndpointInfo` removed. + Generator-level. + +#### F12.2 — `CreateWarehouse` and `EditWarehouseRequest` are nearly identical (HIGH) +- **Where:** `model.ts:746` and `model.ts:888`. +- **Why flagged:** `EditWarehouseRequest` is `CreateWarehouse + + id`. All other fields identical. Duplicating the shape. +- **Suggestion:** Have `EditWarehouseRequest` extend + `CreateWarehouse` with `id` added. Reduces drift. + +#### F12.3 — `SetWorkspaceWarehouseConfigRequest` and +`GetWorkspaceWarehouseConfigRequest_Response` are identical (HIGH) +- **Where:** `model.ts:1347` and `model.ts:1258`. +- **Why flagged:** Same field set on both. Same legacy + `globalParam`, `configParam` deprecated pair on both. +- **Suggestion:** Generate as `WorkspaceWarehouseConfig` type + used by both methods. Generator-level. + +#### F12.4 — Legacy `Endpoint*` naming for a `Warehouse*` concept (HIGH) +- Covered in F0 and F1.x. Listed here for completeness in + category 12: the entire `Endpoint*` family is historical + baggage from the rename of "SQL Endpoints" to "SQL Warehouses". + +#### F12.5 — `numActiveSessions` deprecated field still on response types (LOW) +- **Where:** `model.ts:1104, 1239`. +- **Why flagged:** JSDoc says "Deprecated. current number of + active sessions for the warehouse". Carries no `@deprecated` + tag. +- **Suggestion:** Add `@deprecated`. Schedule for removal. + +#### F12.6 — `EndpointHealth.message` deprecated (LOW) +- **Where:** `model.ts:997`. Same pattern. + +#### F12.7 — `instanceProfileArn` deprecated (LOW) +- **Where:** `model.ts:813, 957, 1075, 1210`. Same. + +#### F12.8 — `globalParam`, `configParam` deprecated in favor of +`sqlConfigurationParameters` (LOW) +- **Where:** `model.ts:1277, 1279, 1366, 1368`. Same. + +#### F12.9 — `ListWarehousesRequest.runAsUserId` deprecated and ignored (LOW) +- **Where:** `model.ts:1465`. JSDoc says "Deprecated: this field + is ignored by the server." +- **Suggestion:** Add `@deprecated` and consider removal. + +#### F12.10 — Workspace config endpoint duplicates per-warehouse fields (MEDIUM) +- **Where:** `instanceProfileArn`, `channel`, + `enableServerlessCompute` all appear in both per-warehouse + (`CreateWarehouse`) and workspace + (`SetWorkspaceWarehouseConfigRequest`) types. +- **Why flagged:** The same field name maps to two different + conceptual levels (per-warehouse override vs. workspace + default). A reader can't tell from the field name alone. +- **Suggestion:** Document the dual presence in JSDoc. + +--- + +### 13. Verb-tense inconsistency + +#### F13.1 — `Create*`, `Delete*`, `Edit*`, `Update*`, `Get*`, `Set*`, +`List*`, `Start*`, `Stop*` (acceptable + inconsistency) +- **Where:** Method names across `client.ts`. +- **Why flagged:** All imperatives, present tense. Consistent + *within tense*. But mixed verbs across the same resource: + - Warehouses: `createWarehouse`, `editWarehouse`, + `deleteWarehouse`. `editWarehouse` is the odd one — uses + "edit" instead of the conventional "update". + - Default overrides: `createDefaultWarehouseOverride`, + `updateDefaultWarehouseOverride`, + `deleteDefaultWarehouseOverride`. Standard CRUD verbs. +- **Suggestion:** See F17 below — same root cause. + +#### F13.2 — `Repeated` adjective on `RepeatedEndpointConfPairs` (LOW, proto-ism) +- **Where:** `model.ts:1336`. +- **Why flagged:** "Repeated" is proto vocabulary; not English + vocabulary. It means "list of". Reads as "repeated endpoint + conf pairs". +- **Suggestion:** Drop the `Repeated` prefix. Rename to + `EndpointConfPairList` (or `ConfigPairList` per F1.5). + +--- + +### 14. Go/Java-style names + +#### F14.1 — `req`, `resp`, `opts` Go abbreviations (LOW) +- **Where:** `client.ts` throughout; `utils.ts:30, 47, 60, 66`. +- **Why flagged:** Go convention is `req`, `resp`, `opts`; TS + convention is `request`, `response`, `options`. SDK already + uses `options` (full word) so the abbreviation is inconsistent + within the same method signature. +- **Suggestion:** Generator-level. + +#### F14.2 — `Info` suffix on types (Go-ism) (HIGH) +- **Where:** `EndpointInfo` (`model.ts:1006`). +- **Why flagged:** Go has `ClusterInfo`, `JobInfo`, etc. TS + prefers the bare noun (`Cluster`, `Job`). `Info` is a + Go-ism. +- **Suggestion:** Rename to `Warehouse`. + +#### F14.3 — `Repeated` proto-prefix (LOW) +- Covered in F13.2. + +#### F14.4 — `Params` suffix on types (Java-ish) (LOW) +- `OdbcParams` — minor. See F8.8. + +#### F14.5 — `Pair` suffix (Java-ish) (LOW) +- `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair`. + Covered in F8.3. + +#### F14.6 — `marshal*` / `unmarshal*` prefixes are protobuf/Go vocabulary (LOW, generator-driven) +- **Where:** All schema exports. +- **Why flagged:** JS/TS commonly uses `serialize`/`deserialize`, + `encode`/`decode`, or `toJson`/`fromJson`. "Marshal" is + Go/protobuf. +- **Suggestion:** Cross-cutting; generator-level. Out of scope + for this package's audit. + +#### F14.7 — `for (;;)` C-style infinite loop (LOW, generator-driven) +- **Where:** `client.ts:405, 462`, `utils.ts:48`. +- **Why flagged:** `for (;;)` is C/Go idiom; TS prefers + `while (true)` for readability. Minor. +- **Suggestion:** Generator-level. + +--- + +### 15. Generic field names losing meaning + +#### F15.1 — `name` overloaded with three meanings (HIGH) +- **Where:** `Channel.name` (channel selector enum value), + `CreateWarehouse.name` (human display name), + `DefaultWarehouseOverride.name` (path identifier). +- **Why flagged:** Three completely different concepts share + the field name `name`. +- **Suggestion:** See F1.8. Rename + `DefaultWarehouseOverride.name` → `resourceName`. Rename + `Channel.name` → `channelType` (also F8.2). + +#### F15.2 — `state` field on `EndpointInfo` / `GetWarehouse_Response` (LOW) +- **Where:** `model.ts:1106, 1241`. +- **Why flagged:** Disambiguated by type + (`EndpointState`), but `warehouseState` would be clearer in + isolation. +- **Suggestion:** Leave. + +#### F15.3 — `status` field on `EndpointHealth` (LOW) +- **Where:** `model.ts:995`. Type `EndpointHealth_Status`. +- **Why flagged:** Reads "endpoint health . status . + endpoint health status". Three layers of "status". +- **Suggestion:** Acceptable given typing. + +#### F15.4 — `enabled` field on `WarehouseTypePair` (LOW) +- **Where:** `model.ts:1440`. +- **Why flagged:** Generic, but disambiguated by container. +- **Suggestion:** Leave. + +#### F15.5 — `summary` field on `EndpointHealth` (LOW) +- **Where:** `model.ts:1001`. +- **Why flagged:** Generic. JSDoc says "short summary of the + health status". Could be `summaryMessage` or + `healthSummary`, but field is rarely used in isolation. +- **Suggestion:** Leave. + +#### F15.6 — `key`, `value` on every `*Pair` type (LOW) +- **Where:** `EndpointConfPair`, `EndpointTagPair`, + `TerminationReason_ParametersEntry`. +- **Why flagged:** Maximally generic. Domain is in the + container type name. +- **Suggestion:** Acceptable; conventional for key-value pair + types. + +#### F15.7 — `code`, `type`, `parameters` on `TerminationReason` (LOW) +- **Where:** `model.ts:1393, 1395, 1397`. +- **Why flagged:** All three are generic words. Disambiguated + by container. +- **Suggestion:** Leave. + +#### F15.8 — `host`, `path`, `protocol`, `port` on `OdbcParams` (LOW) +- **Where:** `model.ts:1330-1333`. +- **Why flagged:** Generic connection-string fields. Standard. +- **Suggestion:** Leave. + +--- + +### 16. Field contradicting type domain + +#### F16.1 — `cluster*` fields on warehouse types (HIGH) +- **Where:** `CreateWarehouse.clusterSize` (`model.ts:773`), + `minNumClusters` (`model.ts:787`), `maxNumClusters` + (`model.ts:798`), `numClusters` (`model.ts:1102`); same on + `EditWarehouseRequest`, `EndpointInfo`, + `GetWarehouse_Response`. JSDoc: "Logical name for the + cluster" (`model.ts:748`). +- **Why flagged:** A SQL Warehouse exposes "cluster" terminology + internally because the warehouse is implemented atop Spark + clusters. To the customer, this is "warehouse size", + "warehouse cluster count", etc. The names leak + implementation. +- **Suggestion:** Rename for clarity: + - `clusterSize` → `warehouseSize` (the literal customer doc + term). + - `minNumClusters` → `minWarehouseInstances`? + - This is a wire-level rename. Considered intentional — + cluster terminology is documented externally. Leave with + a JSDoc note. Flag for future spec consideration. + +#### F16.2 — `creatorName` references the cluster (LOW) +- **Where:** `model.ts:810, 954, 1072, 1207`. +- **Why flagged:** JSDoc says "warehouse creator name"; field + name `creatorName` doesn't conflict but doesn't say what + resource is being created either. +- **Suggestion:** Acceptable. + +#### F16.3 — `EndpointSpotInstancePolicy.RELIABILITY_OPTIMIZED` is misnamed (LOW) +- **Where:** `model.ts:80`. +- **Why flagged:** Per JSDoc, on Azure it makes no difference + (both On Demand) — only AWS distinguishes. The name implies + reliability is universally improved, but on Azure it is a + no-op. +- **Suggestion:** Document; rename optional. + +--- + +### 17. Inconsistent action verbs + +#### F17.1 — `Edit` vs. `Update` (HIGH) +- **Where:** `editWarehouse` (`client.ts:239`) vs. + `updateDefaultWarehouseOverride` (`client.ts:584`). Same + package, two different "modify resource" verbs. +- **Why flagged:** Warehouses use `edit`; default warehouse + overrides use `update`. CRUD-style APIs across the SDK use + "update"; the warehouse `edit` is a legacy form. Compounded + by `Editor`-ish naming on types: `EditWarehouseRequest`, + `EditWarehouseRequest_Response`, `EditWarehouseWaiter`. +- **Suggestion:** Standardize on `update` across the SDK. + Rename `editWarehouse` → `updateWarehouse`, + `EditWarehouseRequest` → `UpdateWarehouseRequest`, + `EditWarehouseWaiter` → `UpdateWarehouseWaiter`. Note: this is + a wire/API-level rename — coordinate with backend. + +#### F17.2 — `Start` and `Stop` as method names (acceptable) +- **Where:** `startWarehouse`, `stopWarehouse`. +- **Why flagged:** Pair of opposites; standard for state + machines. Good. +- **Suggestion:** No change. + +#### F17.3 — `Set` (`setWorkspaceWarehouseConfig`) vs. `Update` (LOW) +- **Where:** `client.ts:475`. +- **Why flagged:** `set` semantically means "replace entire + resource"; `update` means "patch fields". Both apply here. + `setWorkspaceWarehouseConfig` uses PUT (full replace) — + `set` is correct. +- **Suggestion:** No change. But document the PUT semantics in + JSDoc. + +#### F17.4 — `Create` and `Delete` (acceptable) +- Standard CRUD. No issue. + +--- + +### 18. Long enum values + +#### F18.1 — `TerminationCode` — many >40-char identifiers (HIGH) +- **Where:** `model.ts:103-687`. Examples: + - `AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` (50) + - `AZURE_UNEXPECTED_DEPLOYMENT_TEMPLATE_FAILURE` (44) + - `AZURE_PACKED_DEPLOYMENT_PARTIAL_FAILURE` (38) + - `BOOTSTRAP_TIMEOUT_CLOUD_PROVIDER_EXCEPTION` (42) + - `BUDGET_POLICY_LIMIT_ENFORCEMENT_ACTIVATED` (41) + - `ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` (52) + - `NETWORK_CHECK_METADATA_ENDPOINT_FAILURE_DUE_TO_MISCONFIG` (56) + - `SECURITY_AGENTS_FAILED_INITIAL_VERIFICATION` (43) +- **Why flagged:** Identifier readability suffers; switch + statements become unwieldy. Some have `_DUE_TO_MISCONFIG` + suffix that is essentially a sub-category. +- **Suggestion:** Acceptable for backwards compat. Consider + refactoring to a nested enum (category + subcategory) at the + spec level. Generator-driven. + +#### F18.2 — `EndpointSpotInstancePolicy.RELIABILITY_OPTIMIZED` / `COST_OPTIMIZED` (LOW) +- **Where:** `model.ts:78, 80`. +- **Why flagged:** 21-22 char values. Acceptable; descriptive. + +#### F18.3 — `ChannelName.CHANNEL_NAME_*` (LOW, covered by F2.1) +- **Where:** `model.ts:9-12`. +- **Why flagged:** With the prefix stripped (per F2.1), values + become short. Otherwise 23-25 chars. + +#### F18.4 — `DefaultWarehouseOverrideType.DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED` (LOW, covered by F2.2) +- 43 chars. Strip prefix to fix. + +--- + +### 19. Underspecified IDs + +#### F19.1 — `id` on `CreateWarehouse_Response`, `EndpointInfo`, +`GetWarehouse_Response`, `DeleteWarehouseRequest`, +`EditWarehouseRequest`, `GetWarehouse`, `StartRequest`, +`StopRequest` (MEDIUM) +- **Where:** Many places. Caller writes + `client.startWarehouse({id: '...'})` — but `id` here is the + warehouse id, not a generic id. +- **Why flagged:** Bare `id` is acceptable in context, but + across the SDK, packages typically use the qualified form + (`pipelineId`, `clusterId`, `endpointId`). `id` is + underspecified. +- **Suggestion:** Rename to `warehouseId` for self-documentation. + Wire stays `id` (path segment). + +#### F19.2 — `defaultWarehouseOverrideId` vs. `warehouseId` on +`DefaultWarehouseOverride` (LOW) +- **Where:** `model.ts:863, 870`. +- **Why flagged:** Two ID fields on one type: + `defaultWarehouseOverrideId` (the override's own ID) and + `warehouseId` (the warehouse referenced *by* the override). + Both are clearly named, but a reader has to look carefully. +- **Suggestion:** Acceptable; both names are explicit. + +#### F19.3 — `name` is functionally an ID on +`DefaultWarehouseOverride` (HIGH) +- **Where:** `model.ts:861`. Path form `default-warehouse-overrides/{id}`. +- **Why flagged:** AIP-style "resource name" as a string — + conventional in Google APIs but unconventional in TS. + Customer sees `{name: 'default-warehouse-overrides/123'}` and + may try `{name: 'my-override-name'}`. Field name `name` + encourages misuse. +- **Suggestion:** Rename to `resourceName` on the type and + request types. AIP convention is `name` on the wire — keep + wire, rename TS. + +#### F19.4 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) +- **Where:** `model.ts:1465`. Already deprecated. Numeric (`number`), + not string — unusual; most IDs in the SDK are string. +- **Suggestion:** Already deprecated. Leave. + +#### F19.5 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) +- **Where:** `model.ts:1326`. Standard pagination identifier. + +--- + +### 20. Type-suffix tautology + +#### F20.1 — `Channel.name: ChannelName` (HIGH) +- **Where:** `model.ts:728-729`. + ```ts + export interface Channel { + name?: ChannelName | undefined; + dbsqlVersion?: string | undefined; + } + ``` +- **Why flagged:** Field `name` typed as `ChannelName`. The + field is `channel.name: ChannelName`. Trying to read + `channel.name.toString()` returns `'CHANNEL_NAME_PREVIEW'` + — three layers of "name". +- **Suggestion:** Rename enum to `ChannelType`; rename field + to `type`. See F6.6 / F8.2. + +#### F20.2 — `EndpointHealth.status: EndpointHealth_Status` (LOW) +- **Where:** `model.ts:995`. +- **Why flagged:** Field name `status` + enum suffix `Status` + + interface "Health Status" namespace. Disambiguated by + typing. +- **Suggestion:** Acceptable; standard pattern. + +#### F20.3 — `WarehouseTypePair.warehouseType: WarehouseType` (HIGH) +- **Where:** `model.ts:1434-1440`. + ```ts + export interface WarehouseTypePair { + warehouseType?: WarehouseType | undefined; + enabled?: boolean | undefined; + } + ``` +- **Why flagged:** Field name and type name are nearly + identical. Reads "warehouse-type pair . warehouse type = + WarehouseType.PRO". Two layers of "warehouse type". +- **Suggestion:** Rename field to `type` (or rename type to + `Type`). E.g. `WarehouseTypeAvailability { type, enabled }`. + +#### F20.4 — `TerminationReason.code: TerminationCode` (LOW) +- **Where:** `model.ts:1393`. Field `code` + enum suffix `Code` + on `TerminationCode`. Generic field name with specific enum + — acceptable per F1.12. + +#### F20.5 — `TerminationReason.type: TerminationType` (LOW) +- **Where:** `model.ts:1395`. Same pattern. Acceptable. + +#### F20.6 — `DefaultWarehouseOverride.type: DefaultWarehouseOverrideType` (LOW) +- **Where:** `model.ts:865`. +- **Why flagged:** Field `type` typed as + `DefaultWarehouseOverrideType`. Container type already says + "DefaultWarehouseOverride", so the field's type duplicates + the container's name + adds "Type". Acceptable in practice. + +--- + +## Cross-cutting summary + +### Highest-leverage fixes + +1. **Resolve the `Endpoint*` legacy naming (F0, F1.1-F1.6, + F6.1-F6.5, F8.4, F14.2, F12.4)** — rename every `Endpoint*` + type to `Warehouse*` to align with the customer brand. Single + biggest fix; cleans up ~10 type names and the entire + marshal/unmarshal schema family. +2. **Resolve `Edit` vs. `Update` (F17.1)** — pick one verb for + "modify resource" across the SDK; standardize wire and TS. +3. **Strip redundant enum prefixes (F2.1, F2.2, F2.3, F2.4, + F2.5)** — `ChannelName.CHANNEL_NAME_PREVIEW` etc. Trivial + generator-level fix; massive readability win. +4. **Drop `_Response` underscore convention (F4.1, F4.2)** — + namespace or naked concatenation. Generator-level. +5. **Collapse duplicate types (F12.1, F12.2, F12.3)** — + `EndpointInfo` + `GetWarehouse_Response`, + `CreateWarehouse` + `EditWarehouseRequest`, + `Set*Config` + `Get*Config_Response`. + +### Recurring themes + +- **Generator-driven proto-isms** (`Repeated`, `_Response`, + `marshal`/`unmarshal`, `req`/`resp`, `for(;;)`) are the + largest single category. Most are LOW because they are + consistent across the entire SDK; fix at the generator. +- **Legacy `Endpoint*` naming** is the package-specific issue. + It causes the most readability harm because the package + brand is "warehouse" while half the types still say + "endpoint". HIGH severity; spec-level rename. +- **Duplicate enum prefixes** are pervasive but easily fixable + generator-side. +- **Two unrelated resource families** (warehouses + + default-warehouse-overrides) coexist in one package, with + different REST base paths and different API conventions. + Splitting could simplify. diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md new file mode 100644 index 00000000..6ba019d5 --- /dev/null +++ b/.agent/naming-audit/workspace.md @@ -0,0 +1,587 @@ +# Naming Audit: workspace + +**Path:** `packages/workspace/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks workspace filesystem-style operations on notebooks, folders, and files: import, export, delete, list, get-status, and mkdirs against absolute paths under `/Workspace`. +**Total weird names flagged:** 32 + +## Scope note: `workspace` vs sibling packages + +The Databricks SDK ships five packages whose names begin with "workspace". This audit covers only the first one; the others differ in scope: + +| Package | Domain | Wire prefix | +|---------|--------|-------------| +| `workspace` (this audit) | Workspace filesystem (notebooks/folders/files) | `/api/2.0/workspace/` | +| `workspaceassignment` | Account-level principal-to-workspace permission assignments | account API | +| `workspacebindings` | Securable-to-workspace bindings (catalog/credential/location) | Unity Catalog API | +| `workspaceconf` | Untyped key/value workspace configuration | `/api/2.0/workspace-conf` | +| `workspacesettings` | Strongly-typed workspace settings (compliance security profile, automatic cluster update, etc.) | various `/api/2.0/settings/*` | + +The package name `workspace` is the most overloaded of the five — every Databricks API operates "in a workspace," so a package literally called `workspace` provides almost no scope signal. A name like `workspacefiles`, `workspacefs`, or `workspacenotebooks` would convey that this is the filesystem-style API and would not collide conceptually with the other four "workspace*" packages. See finding 1. + +## Summary table + +| # | Severity | Location | Name | Category | +|---|----------|----------|------|----------| +| 1 | High | package | `workspace` | Vague/generic package name (overloaded across 5+ "workspace*" packages) | +| 2 | High | `model.ts` interface | `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` | Verb-as-type, reserved-word collisions | +| 3 | High | `model.ts` interface | `Delete_Response`, `Export_Response`, `Import_Response`, `List_Response`, `Mkdirs_Response` | Underscore in TS identifier (Go/proto-style nested message names) | +| 4 | High | `model.ts` enum | `ExportFormat` used as the `format` field of `Import` | Misleading name (an "ExportFormat" governs imports too) | +| 5 | High | `model.ts` enum value | `ExportFormat.AUTO` | Misleading enum value (server inspects content) | +| 6 | High | `model.ts` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | +| 7 | High | `model.ts` enum value | `ObjectType.OBJECT_TYPE_UNSPECIFIED` | Redundant enum prefix + proto sentinel leak | +| 8 | High | `model.ts` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | +| 9 | High | `model.ts` enum | `Language` | Vague/generic, no domain prefix | +| 10 | Medium | `model.ts` enum value | `ObjectType.LIBRARY` | Misleading (library notebooks are an obsolete concept; deprecated in product) | +| 11 | Medium | `model.ts` field | `List.notebooksModifiedAfter` | Field contradicts type domain (list of all objects, filter only on notebooks) | +| 12 | Medium | `model.ts` field | `Export.directDownload` | Verb-as-noun field + boolean named like a noun | +| 13 | Medium | `model.ts` field | `Export_Response.fileType` | Underspecified (raw extension? MIME type? format enum?) | +| 14 | Medium | `model.ts` field | `Export_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | +| 15 | Medium | `model.ts` field | `Import.content` typed `Uint8Array` | Same type/JSDoc mismatch as 14 in the reverse direction | +| 16 | Medium | `model.ts` field | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Underspecified time fields (mtime/ctime? wall clock?) and unit ambiguity (epoch millis as number) | +| 17 | Medium | `model.ts` field | `ObjectInfo.size` | Underspecified (file size in bytes per JSDoc, but no unit in the name) | +| 18 | Medium | `model.ts` field | `Mkdirs.path` | Singular/plural mismatch — type name plural (`Mkdirs`), field singular (`path`) | +| 19 | Medium | `model.ts` type | `Mkdirs` | Cryptic abbreviation (Unix-ism, "mkdirs" not "createDirectory") | +| 20 | Medium | `model.ts` enum value | `Language.R` | Single-letter identifier (clashes with `package R Markdown`) | +| 21 | Medium | `model.ts` enum value | `Language.SCALA`, `PYTHON`, `SQL`, `R` | Missing `LANGUAGE_` prefix elsewhere, raw values overlap with cluster/job runtime names | +| 22 | Medium | `client.ts` method | `getStatus` | Vague verb (status of what?), inconsistent with `list`/`export` | +| 23 | Medium | `model.ts` interface | `GetStatus` | Verb-as-type with no `Request` suffix (whole SDK is inconsistent on this) | +| 24 | Medium | `model.ts` field | `Delete.recursive` | Underspecified boolean (verbatim Unix flag, no domain reading) | +| 25 | Low | `model.ts` enum value | `ExportFormat.R_MARKDOWN` | Underscore inside enum value matches wire, but mixes shape with `JUPYTER`/`HTML` (single tokens) | +| 26 | Low | `model.ts` enum value | `ExportFormat.DBC` | Cryptic abbreviation (Databricks archive) | +| 27 | Low | `model.ts` enum | `ExportOutputs` | Singular/plural — type is `Outputs` (plural), field on `Export` is also `outputs`, values `ALL`/`NONE` describe whether outputs are included | +| 28 | Low | `model.ts` field | `Export.outputs` typed `ExportOutputs` | Field name == type-suffix tautology | +| 29 | Low | `model.ts` interface | `ObjectInfo` | Generic name ("info" suffix used inconsistently across SDK) | +| 30 | Low | `model.ts` field | `List_Response.objects` | Generic field (`objects`) for `ObjectInfo[]` | +| 31 | Low | `client.ts` method | `mkdirs` | Verb-tense / casing inconsistency vs `createDirectory` analog elsewhere in SDK | +| 32 | Low | docstrings | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | + +## High severity + +### 1. `workspace` — vague/generic package name (overloaded) + +**Location:** `package.json` → `@databricks/sdk-workspace` + +The package is named after a noun every Databricks user already associates with "the whole product." Five other npm packages also start with `workspace`. Without reading `client.ts`, nothing in the name tells a TS consumer that this package's scope is "files and folders under `/Workspace` in the workspace tree." The wire URL prefix `/api/2.0/workspace/` is the only clue. + +A name that conveys scope: + +- `workspacefiles` — already exists conceptually (there is a separate `files` package for `/Files/`); but matches the canonical product wording "Workspace Files." +- `workspacefs` — matches the filesystem metaphor of `list`/`mkdirs`/`getStatus`. +- `workspacenotebooks` — narrowest, but `Import`/`Export` also handle files and DBC archives, so this would undersell. + +Cross-package collision: a user typing `import { ... } from '@databricks/sdk-workspace/v1'` gets `Client`, but so does every other "workspace*" package. The TS class is also called `Client` (see finding 24 in the SDK-wide patterns). + +### 2. `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` — verb-as-type & reserved-word collisions + +**Location:** `model.ts:65`, `:79`, `:121`, `:126`, `:163`, `:176` + +```ts +export interface Delete { ... } +export interface Export { ... } +export interface GetStatus { ... } +export interface Import { ... } +export interface List { ... } +export interface Mkdirs { ... } +``` + +Three of these are JavaScript reserved or contextually reserved words: + +- `Delete` shadows the `delete` operator (case-different but visually confusing). +- `Export` and `Import` collide with ES module syntax; the file already does `import type { Import } from './model'` which reads as a syntax error at a glance. +- `List` shadows `Array`/`List` from common stdlib vocabulary. +- `Mkdirs` is a Unix verb fragment. +- `GetStatus` is verb+noun. + +Every other request type in the SDK follows the pattern `Request` (e.g. `CreateAlertRequest`, `DeleteCatalogRequest`). This package omits both the `Request` suffix and the noun. The interfaces are also bare verbs, which makes type signatures like `async delete(req: Delete)` unreadable — at the call site you cannot tell whether `Delete` is the request type, the response type, the verb, or a builtin. + +Idiomatic TS would be `DeleteRequest` / `DeleteWorkspaceObjectRequest` (matching the rest of the SDK), or shorter: `DeleteRequest` / `ExportRequest` / `ImportRequest` / `ListRequest` / `MkdirsRequest` / `GetStatusRequest`. The current names are 1:1 with the Go SDK's `workspace.Delete`/`workspace.Export` Go struct names — in Go, package-prefixing makes `workspace.Delete` unambiguous; in TS, after `import {Delete} from '@databricks/sdk-workspace/v1'`, the prefix is gone. + +### 3. `Delete_Response`, `Export_Response`, `Import_Response`, `List_Response`, `Mkdirs_Response` — underscore in TS identifier + +**Location:** `model.ts:77`, `:111`, `:161`, `:171`, `:185` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention, ... -- Proto-style nested message name. +export interface Delete_Response {} +``` + +Five exported interfaces use a `Foo_Response` shape. The underscore is a proto-style separator for nested message types (`Delete.Response` on the wire). TypeScript naming convention is PascalCase with no underscores; every one of these names triggers `@typescript-eslint/naming-convention` and requires an inline disable. + +Idiomatic TS: `DeleteResponse`, `ExportResponse`, etc. The wire format does not care what the TS type is called. + +The five eslint-disable comments are themselves a smell: a generator producing names that need to be silenced on every line is a sign the generator template is wrong, not that the language is wrong. + +### 4. `ExportFormat` reused for `Import.format` — misleading enum + +**Location:** `model.ts:6-25`; used as `Import.format` at `:143` + +```ts +export enum ExportFormat { + SOURCE = 'SOURCE', + HTML = 'HTML', + ... +} + +export interface Import { + ... + format?: ExportFormat | undefined; + ... +} +``` + +The enum is named `ExportFormat` but is used as the format for both `Import.format` and `Export.format`. The Go SDK's name (`ExportFormat`) leaks here. A neutral name like `WorkspaceObjectFormat` or `NotebookFormat` would describe both directions. The JSDoc on `Import.format` even lists the values (SOURCE, HTML, JUPYTER, DBC, R_MARKDOWN) as if they were import-specific, while the enum description says "for workspace import and export." + +There is also a subtle asymmetry: `Import.format` documents AUTO as "depending on extension," `Export.format` documents AUTO as "depending on object type." Same enum value, different server behaviour per direction. + +### 5. `ExportFormat.AUTO` — misleading enum value + +**Location:** `model.ts:17-18` + +```ts +/** We will inspect the content of the payload to determine the type */ +AUTO = 'AUTO', +``` + +`AUTO` reads as "automatic file selection," but the value means "server inspects payload bytes to guess the file type." For an export request, "AUTO" means "decide based on the object's type." The single token serves two different inferred behaviors. `DETECT_FROM_CONTENT` / `DETECT_FROM_OBJECT` (split into two enums) would be honest. + +### 6. `ExportFormat.RAW` — vague enum value + +**Location:** `model.ts:19-24` + +```ts +/** + * This is introduced to unblock a DR use case importing .zip file as is. + * If you import .zip file with AUTO format, it will be imported as a folder. + * In workspace 3.0 folder import will be supported via a different API. + */ +RAW = 'RAW', +``` + +`RAW` does not name a format — it names a behavior ("no decoding, store as-is"). The JSDoc is a story about why the value exists, not what it represents. The value's existence is conditional on "workspace 3.0," a server-side roadmap item the SDK user does not see. + +`ZIP_PASSTHROUGH` or `BINARY` would describe the actual data path. Right now a reader sees `ExportFormat.RAW` and has to read three lines of JSDoc to understand it. + +### 7. `ObjectType.OBJECT_TYPE_UNSPECIFIED` — redundant enum prefix + proto sentinel leak + +**Location:** `model.ts:48-52` + +```ts +export enum ObjectType { + /** + * As of 2023-10 this is used only by list-repo API so that repos can gracefully handle errors + * for unsupported types. + */ + OBJECT_TYPE_UNSPECIFIED = 'OBJECT_TYPE_UNSPECIFIED', + NOTEBOOK = 'NOTEBOOK', + ... +} +``` + +Two problems in one value: + +1. Enum prefix repetition: the enum is `ObjectType`, the value is `OBJECT_TYPE_UNSPECIFIED`. Every value would be readable as `ObjectType.NOTEBOOK` — the others (good) drop the prefix; this one (bad) retains it. The proto-style `_UNSPECIFIED` is documented as a proto convention, not a TS one. +2. Proto sentinel leak: the JSDoc explicitly says this value is only used by `list-repo` for graceful unsupported-type handling. It is a server implementation detail. A TS consumer constructing an `ObjectInfo` should never set this. Like `Aggregation.UNKNOWN` and similar leaks elsewhere, this is the proto default-value mechanism surfacing into the SDK. + +### 8. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names + +**Location:** `model.ts:209-214` + +```ts +/** Unique identifier for the object. */ +objectId?: number | undefined; +... +/** A unique identifier for the object that is consistent across all Databricks APIs. */ +resourceId?: string | undefined; +``` + +The same `ObjectInfo` carries two distinct identifiers, both documented as "unique identifier for the object," differing only by JSDoc adjective ("consistent across all Databricks APIs"). The names do not encode the difference: a reader sees `objectId` (number) and `resourceId` (string) and cannot tell which one to pass into another API. + +Likely truth: `objectId` is the legacy 64-bit workspace-local numeric ID; `resourceId` is the new UUID-shaped string ID used by the unified resources API. The names should be `legacyObjectId` (deprecated) and `resourceId`, or `localObjectId` and `globalResourceId`, or one should be dropped. + +Also, `objectId` is typed `number` — JavaScript numbers are 64-bit float; if the server ID exceeds 2^53, precision is lost. Other SDK types use `bigint` or string for similar IDs. + +### 9. `Language` — vague/generic, no domain prefix + +**Location:** `model.ts:35-44` + +```ts +/** The language of notebook. */ +export enum Language { + SCALA = 'SCALA', + PYTHON = 'PYTHON', + SQL = 'SQL', + R = 'R', +} +``` + +A top-level export named `Language` in a domain package. Many other SDK packages reference "language" (`apps` runtimes, `jobs` task language, `clusters` runtime languages, `pipelines` SQL/Python). The package re-exports `Language` without a `Notebook` or `Workspace` qualifier. A user importing two SDK packages can get `Language` from `workspace` and a different `Language` from `apps` or `jobs` (when those add similar enums). + +`NotebookLanguage` is the natural domain prefix; the wire field is `notebook.language`. + +## Medium severity + +### 10. `ObjectType.LIBRARY` — obsolete concept + +**Location:** `model.ts:55` + +```ts +NOTEBOOK = 'NOTEBOOK', +DIRECTORY = 'DIRECTORY', +LIBRARY = 'LIBRARY', +FILE = 'FILE', +REPO = 'REPO', +DASHBOARD = 'DASHBOARD', +``` + +Workspace "libraries" (as a top-level object type) are obsolete — Databricks moved libraries to cluster-level and job-level configurations. The value is exported without a deprecation marker and without JSDoc explanation. Consumers writing `if (obj.objectType === ObjectType.LIBRARY)` are coding against a dead branch. + +### 11. `List.notebooksModifiedAfter` — field contradicts type domain + +**Location:** `model.ts:163-168` + +```ts +export interface List { + /** The absolute path of the notebook or directory. */ + path?: string | undefined; + /** UTC timestamp in milliseconds */ + notebooksModifiedAfter?: number | undefined; +} +``` + +`list` returns all object types (notebooks, directories, files, repos, dashboards), but the filter parameter is named `notebooksModifiedAfter` — i.e., the filter only applies to objects of type `NOTEBOOK`. The asymmetry is invisible from the field name. A non-notebook object's last-modified value is silently not filtered, and a user expecting `modifiedAfter` semantics will see directories whose contents post-date the filter. + +`modifiedAfterMillis` (without the `notebooks` prefix) or `notebookModifiedAfterMillis` (with the singular subject matching the filter's actual scope) would describe what the server does. + +The unit (`milliseconds`) is in JSDoc only, not in the field name. Other timestamp fields in the same file are documented in milliseconds but named `createdAt` / `modifiedAt`. Inconsistent — see finding 17. + +### 12. `Export.directDownload` — verb-as-noun field, weak boolean + +**Location:** `model.ts:96-99` + +```ts +/** + * Flag to enable direct download. If it is `true`, the response is the exported file itself. + * Otherwise, by default, the response contains content in the form of a base64 encoded string. + */ +directDownload?: boolean | undefined; +``` + +`directDownload` reads as a noun phrase ("the direct download"), but it's a boolean flag controlling response shape. Booleans are usually named with `is`/`has`/`should` prefixes or as adjectives. `streamBinary` or `responseAsBinary` would parse as a flag. + +The flag also has a semantic problem: when `true`, the response body is raw bytes; when `false`, the response body is a JSON object with base64. So the field changes the entire response content type, but the generated client (`export` method) parses the response identically in both cases (via `unmarshalExport_ResponseSchema`). The schema only handles the base64 case. Setting `directDownload: true` would crash the parser. + +### 13. `Export_Response.fileType` — underspecified + +**Location:** `model.ts:117-119` + +```ts +/** The file type of the exported file. */ +fileType?: string | undefined; +``` + +The doc says "the file type" but doesn't say in what form. Is it the extension (`.ipynb`)? A MIME type (`application/x-ipynb+json`)? An `ExportFormat` enum value (`JUPYTER`)? An object kind (`NOTEBOOK`)? Typed as `string` so any of the four is possible. The name `fileType` is one of the most overloaded strings in software. + +`mimeType`, `extension`, or `format: ExportFormat` would commit. + +### 14. `Export_Response.content` typed `Uint8Array` with "base64-encoded" doc + +**Location:** `model.ts:112-116` + +```ts +/** + * The base64-encoded content. + * If the limit (10MB) is exceeded, exception with error code **MAX_NOTEBOOK_SIZE_EXCEEDED** is thrown. + */ +content?: Uint8Array | undefined; +``` + +The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw bytes). The unmarshaller (`unmarshalExport_ResponseSchema:225`) does the base64 decode itself, so the field actually holds decoded bytes, contradicting the JSDoc. The JSDoc was lifted from the wire format documentation and not updated for the post-decode TS shape. A reader holding the type sees "Uint8Array of base64-encoded data," which is technically meaningless (Uint8Arrays are bytes, not base64). + +### 15. `Import.content` typed `Uint8Array` with "base64-encoded" doc + +**Location:** `model.ts:146-152` + +```ts +/** + * The base64-encoded content. This has a limit of 10 MB. + * ... + * This parameter might be absent, and instead a posted file is used. + */ +content?: Uint8Array | undefined; +``` + +Mirror of finding 14 in the reverse direction. The marshaller (`marshalImportSchema:289-293`) encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. + +### 16. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision + +**Location:** `model.ts:204-208` + +```ts +/** Only applicable to files. The creation UTC timestamp. */ +createdAt?: number | undefined; +/** Only applicable to files, the last modified UTC timestamp. */ +modifiedAt?: number | undefined; +``` + +Two issues: + +1. The names use the `At` suffix (TS-friendly) but the type is `number`. Unit (milliseconds vs seconds) is documented nowhere in this type. The companion `List.notebooksModifiedAfter` is documented as milliseconds; one infers consistency, but the type does not declare it. Most of the SDK uses `Temporal.Instant` for `At`-suffixed timestamps; here it's `number`. +2. "Only applicable to files" — the field is on `ObjectInfo`, which also describes notebooks, directories, etc. Setting expectations via "only applicable" in JSDoc is a code smell: the field shape doesn't change based on object type. + +### 17. `ObjectInfo.size` — underspecified + +**Location:** `model.ts:210-211` + +```ts +/** Only applicable to files. The file size in bytes can be returned. */ +size?: number | undefined; +``` + +`size` is a unit-less name. JSDoc says "file size in bytes can be returned" (the "can be" is also ambiguous — is it always returned for files?). `sizeBytes` or `sizeInBytes` is the convention used elsewhere in Databricks SDKs (`clusters.clusterMemoryMb`, `pipelines.storageBytes`). At scale-up time (>4GiB) `number` loses precision; `bigint` or `string` would be safer. + +### 18. `Mkdirs.path` — singular/plural mismatch with the type name + +**Location:** `model.ts:176-182` + +```ts +export interface Mkdirs { + /** + * The absolute path of the directory. If the parent directories do not exist, it will also create them. + * ... + */ + path?: string | undefined; +} +``` + +The type is plural (`Mkdirs` — "make directories"), but it takes one path. The pluralization comes from the Unix `mkdir -p` semantics ("makes the directory and any missing parent directories"), but the input is a single path. A user reading `Mkdirs` expects to pass an array. + +### 19. `Mkdirs` — Unix-ism + +**Location:** `model.ts:176`; `client.ts:254` + +`mkdirs` is a Unix verb. The convention in TS SDKs is `createDirectory` (matches the Files API's `createDirectory`). The Databricks SDK's own `files` package uses `createDirectory` for a similar operation. Inconsistent verb across packages. + +Also: the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the request body holds one path. So even at the wire level, the name is misleading. + +### 20. `Language.R` — single-letter identifier + +**Location:** `model.ts:43` + +```ts +export enum Language { + SCALA = 'SCALA', + PYTHON = 'PYTHON', + SQL = 'SQL', + R = 'R', +} +``` + +`Language.R` is the only single-character enum value in the package. Auto-import tools, grep, and refactoring tools handle one-letter identifiers poorly. The wire format also uses just `R`, so a rename in the SDK would need a string mapping; nonetheless, `Language.R_LANG` (matching the `R_MARKDOWN` format value) or simply documenting `R` more thoroughly would help. + +### 21. `Language` values — no `LANGUAGE_` prefix, overlap with runtime names + +**Location:** `model.ts:35-44` + +```ts +SCALA = 'SCALA', +PYTHON = 'PYTHON', +SQL = 'SQL', +R = 'R', +``` + +The enum values are bare language names that collide with cluster runtime IDs (`DBR-15.4-SCALA-2.12`), job task types (`SQL`, `PYTHON_WHEEL_TASK`), and library types. A user querying `notebook.language === 'PYTHON'` may also see `task.taskType === 'PYTHON_WHEEL_TASK'` and not realize the two `PYTHON` strings come from different enums. + +Other SDK enums add a prefix (`TaskType.PYTHON_WHEEL_TASK`); this one does not. + +### 22. `getStatus` — vague verb on the client + +**Location:** `client.ts:154` + +```ts +async getStatus(req: GetStatus, options?: CallOptions): Promise +``` + +"Status" of what? In TS SDKs, `getStatus` usually returns a status enum or a small status object (e.g., job run status). Here it returns full `ObjectInfo` metadata — a filesystem `stat`, not a status. The Files API uses `getMetadata`. The Go SDK uses `GetStatus` (from `os.Stat` ancestry). Either `getMetadata` or `stat` would describe the actual operation. + +The method also returns `Promise` while `list` returns `Promise` — inconsistent shape (one returns the bare entity, one returns a wrapper). See finding 30. + +### 23. `GetStatus` — verb-as-type without `Request` suffix + +**Location:** `model.ts:121-124` + +```ts +export interface GetStatus { + /** The absolute path of the notebook or directory. */ + path?: string | undefined; +} +``` + +Combined with finding 2, `GetStatus` is the only request type whose name is composed of two verbs. The other request types (`Delete`, `Export`, `Import`, `List`, `Mkdirs`) are single verbs. The package mixes the two patterns. `GetStatusRequest` is what the rest of the SDK uses. + +### 24. `Delete.recursive` — Unix flag, no domain reading + +**Location:** `model.ts:69-73` + +```ts +/** + * The flag that specifies whether to delete the object recursively. It is `false` by default. + * Please note this deleting directory is not atomic. If it fails in the middle, some of objects + * under this directory may be deleted and cannot be undone. + */ +recursive?: boolean | undefined; +``` + +`recursive` is a verbatim port of `rm -r`. For a single-object delete, "recursive" only matters when the path is a directory. The flag would read better as `deleteContents` or `force` for the destructive intent. The JSDoc admits the deletion is non-atomic, a meaningful caveat hidden behind a one-word flag. + +## Low severity + +### 25. `ExportFormat.R_MARKDOWN` — shape mismatch within enum + +**Location:** `model.ts:15-16` + +```ts +SOURCE = 'SOURCE', +HTML = 'HTML', +JUPYTER = 'JUPYTER', +DBC = 'DBC', +R_MARKDOWN = 'R_MARKDOWN', +AUTO = 'AUTO', +RAW = 'RAW', +``` + +Five of the seven values are single tokens; one is `R_MARKDOWN` with an underscore. SQL convention would also be `RMARKDOWN` or `RMD`. Inconsistent shape inside the same enum. + +### 26. `ExportFormat.DBC` — cryptic abbreviation + +**Location:** `model.ts:13-14` + +```ts +/** The notebook will be imported/exported as Databricks archive format. */ +DBC = 'DBC', +``` + +DBC = "Databricks Archive." The acronym is product-specific. `DATABRICKS_ARCHIVE` would be readable. Wire-format compatibility (`DBC` is what the server expects) means the rename has to happen in the enum-key layer, not the enum-value layer — which TS supports cleanly. + +### 27. `ExportOutputs` — plural enum type for ALL/NONE values + +**Location:** `model.ts:27-32` + +```ts +export enum ExportOutputs { + /** All outputs will be exported */ + ALL = 'ALL', + /** No outputs will be exported */ + NONE = 'NONE', +} +``` + +The enum models "which outputs to include" but is named `ExportOutputs` (plural). `OutputsFilter`, `OutputInclusion`, or `IncludeOutputs` (boolean) would read better. The two values `ALL` and `NONE` could equally be a boolean. + +Also: JSDoc on `Export.outputs` says "only ALL or NONE is documented publically, DATABRICKS is internal only" — admits there's a hidden third value, which means the enum is not exhaustive. + +### 28. `Export.outputs` typed `ExportOutputs` — type-suffix tautology + +**Location:** `model.ts:104-106` + +```ts +outputs?: ExportOutputs | undefined; +``` + +Field and type both spell `outputs`. The user types `req.outputs = ExportOutputs.ALL`. Idiomatic phrasing would be `req.outputInclusion = OutputInclusion.ALL` or `req.includeOutputs = true`. + +### 29. `ObjectInfo` — `Info` suffix used inconsistently across SDK + +**Location:** `model.ts:188-214` + +The `Info` suffix is a Go/Java convention for "POJO that describes a thing." TS SDKs vary: some use bare entity names (`Catalog`, `Cluster`), some use `Info`/`Details`. This package's only entity type is `ObjectInfo`. There is no companion `Object` — so the name reads consistently with itself, but the suffix is purely a hat-tip to Go. + +### 30. `List_Response.objects` — generic field for `ObjectInfo[]` + +**Location:** `model.ts:171-174` + +```ts +export interface List_Response { + /** List of objects. */ + objects?: ObjectInfo[] | undefined; +} +``` + +`objects` is the most generic JavaScript noun; it tells the reader nothing. `items`, `entries`, `paths`, or `workspaceObjects` would convey scope. The Go SDK has the same `Objects` field; transferring the name without adaptation gives a TS user a `resp.objects` access that reads like "the objects of the response." + +### 31. `mkdirs` — verb-tense / casing inconsistency + +**Location:** `client.ts:254` + +```ts +async mkdirs(req: Mkdirs, options?: CallOptions): Promise +``` + +Other client methods read as verb-noun (`export`, `import`, `list`) or compound verb (`getStatus`). `mkdirs` is the only Unix-style contraction. The class also has a `delete` method (matches HTTP verb) but no `make` or `create` method. `createDirectory` would align with `delete` semantically. + +### 32. First-person and ticket-driven prose in public JSDoc + +**Location:** `model.ts:17-18`, `:19-24` + +```ts +/** We will inspect the content of the payload to determine the type */ +AUTO = 'AUTO', +/** + * This is introduced to unblock a DR use case importing .zip file as is. + * If you import .zip file with AUTO format, it will be imported as a folder. + * In workspace 3.0 folder import will be supported via a different API. + */ +RAW = 'RAW', +``` + +"We will inspect" and "This is introduced to unblock a DR use case" are not customer-facing language. They read as commit messages or design-doc fragments. JSDoc is rendered into TS IDE tooltips that customers see. Naming-adjacent but flagged. + +## Observations + +1. **Filesystem package without filesystem vocabulary.** The package implements filesystem-style operations (`list`, `delete`, `mkdirs`, `getStatus`) but does not use the canonical filesystem nouns (`File`, `Directory`, `Path`, `Stat`). Instead it uses `ObjectInfo`/`ObjectType`/`path: string`. A user familiar with `fs.stat` or POSIX has to mentally translate. Meanwhile the sibling `files` package (`/api/2.0/fs/`) uses `DirectoryEntry`/`FileInfo` — different vocabulary for the same concept. + +2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) and `ObjectInfo.resourceId` (string, unified-resource) are both returned, both documented as "unique identifier for the object," with no naming clue about which one to pass where. This is the single most user-hostile naming issue in the file. + +3. **The `Foo_Response` underscore is a generator template error.** Five interfaces named `_Response` each need a `@typescript-eslint/naming-convention` disable for the underscore. The names exist only because the Go SDK declares `Delete.Response` as a nested struct that proto/Go renders as `Delete_Response`. In TS, the underscore is not necessary — `DeleteResponse` would satisfy the naming convention and read the same. + +4. **`ExportFormat` is the import format.** The single enum services both `Import` and `Export` (good — DRY), but the name says only "Export." A neutral name (`NotebookFormat` or `WorkspaceObjectFormat`) would describe what it actually is. + +5. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` on `Import` means "detect from file extension + header," and `AUTO` on `Export` means "decide from object type." Same enum value, different server-side algorithm. + +6. **Verb-as-type request names without `Request` suffix.** Six request interfaces (`Delete`, `Export`, `GetStatus`, `Import`, `List`, `Mkdirs`) ship without the `Request` suffix that the rest of the SDK uses. Combined with collisions against ES reserved-context words (`import`, `export`, `delete`), this makes the type names unusable without the package qualifier — which is exactly what TS users lose at import time. + +7. **`content: Uint8Array` documented as base64 in both directions.** Two fields hold post-decode bytes but their JSDoc reads as if they still hold base64 strings. A defensive user reading the JSDoc and base64-encoding their bytes will double-encode on the way in. The mismatch is silent and the failure mode is data corruption. + +8. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear elsewhere in the SDK.** The `files` package uses `createDirectory` and `getMetadata`. The `repos` package uses `getRepo`. Picking one verb per concept and applying it across packages would let users transfer knowledge. + +9. **Sentinel `OBJECT_TYPE_UNSPECIFIED` documented as "only used by list-repo."** The enum exports a value that the package consumers should never set but cannot remove without breaking the read side. A separate response-only enum or a `null` for "unknown" would be cleaner. + +10. **`utils.ts` is shared boilerplate.** The exported helpers (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are not flagged — they are well-named. `flattenQueryParams` is exported but unused in `client.ts` (this package has no nested-object query parameters); orphaned export. No domain naming surface in this file. + +## Domain glossary + +| Term | Meaning in this package | +|------|------------------------| +| Workspace object | Anything that lives in the workspace filesystem tree: notebooks, directories, files, repos, dashboards, (legacy) libraries. | +| Path | An absolute string starting with `/Workspace/` that names a workspace object. | +| Notebook | A workspace object containing runnable code cells and prose; carries a `Language`. | +| Directory | A workspace folder; can be listed and made via `mkdirs`. | +| File | An arbitrary blob in the workspace (not a notebook). | +| Repo | A Git-linked directory; appears in `ObjectType` but managed by a different package. | +| DBC | Databricks archive format — a `.zip`-like bundle of one or more notebooks. | +| Import | Upload an object (or DBC archive) into the workspace at a path. | +| Export | Download an object (or DBC archive) from the workspace at a path. | +| Mkdirs | Create a directory and any missing parents at a path (single-path operation despite the plural verb). | +| Get-status | Return metadata (path, type, language, ID, size, timestamps) for the object at a path — equivalent to `stat`. | +| Object ID | Legacy numeric workspace-local identifier (typed `number`, vulnerable to JS precision at >2^53). | +| Resource ID | Newer string identifier consistent across Databricks resource APIs. | +| Direct download | An `Export` mode where the response body is raw bytes instead of a base64-wrapped JSON object. | + +## File coverage + +| File | Lines | Read in full | +|------|-------|--------------| +| `src/v1/model.ts` | 311 | yes | +| `src/v1/client.ts` | 276 | yes | +| `src/v1/utils.ts` | 151 | yes | +| `src/v1/index.ts` | 21 | yes | diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md new file mode 100644 index 00000000..ea0d7e9f --- /dev/null +++ b/.agent/naming-audit/workspaceassignment.md @@ -0,0 +1,248 @@ +# Naming Audit: workspaceassignment + +**Path:** `packages/workspaceassignment/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level workspace permission assignments — list/get/update/delete the `USER`/`ADMIN` permissions a principal (user / service principal / group) has on a single workspace, plus list the catalog of workspace-level permission values supported. +**Total weird names flagged:** 36 + +## Summary +| Severity | Count | +| --- | --- | +| High | 11 | +| Medium | 14 | +| Low | 8 | +| Observation | 3 | + +## High severity + +### 1. Package name `workspaceassignment` (singular) vs API path `/permissionassignments` — package directory / `src/v1/client.ts:78,106,146,174` +- **Why weird:** The npm package is named `@databricks/sdk-workspaceassignment`, but every type in it is about a `PermissionAssignment` (`DeleteWorkspacePermissionAssignment`, `GetWorkspacePermissionAssignments`, `WorkspacePermissionAssignmentOutput`, ...), every URL ends in `permissionassignments`, and the conceptually equivalent type in the `iam` package is `WorkspaceAssignmentDetail`. So the package is called "workspace assignment" (singular, no qualifier) while the contents are uniformly "workspace permission assignment(s)" and the upstream iam port models the same domain object under a third name entirely. The singular package name is also a singular/plural mismatch with the operations it exposes (`getWorkspacePermissionAssignments`, plural). +- **Category:** 8 (redundant/inconsistent suffix), 9 (singular/plural), 12 (duplicate concept — `iam.WorkspaceAssignmentDetail`). +- **Suggested name:** Rename the package to `workspacepermissions` (matches the listWorkspacePermissions surface and the `permissionassignments` URL fragment), or merge into `iam` since `iam.WorkspaceAssignmentDetail` already covers the same conceptual entity. At minimum align with the route: `workspacepermissionassignments`. +- **Rationale:** Three different names for one concept across the SDK (`workspaceassignment` package, `WorkspacePermissionAssignment*` types, `iam.WorkspaceAssignmentDetail`) is a Discovery footgun — users searching for "workspace assignment" will hit the iam package first and miss this one. + +### 2. `Permission` enum name — `src/v1/model.ts:5` +- **Why weird:** Top-level export named simply `Permission` is dangerously generic in a multi-package SDK. The iam package already defines `WorkspacePermission` (`packages/iam/src/v2/model.ts:58`) — three values (`USER_PERMISSION`/`ADMIN_PERMISSION`/`WORKSPACE_PERMISSION_UNSPECIFIED`) for the exact same domain concept. Importing both as `Permission` from `@databricks/sdk-workspaceassignment` and `WorkspacePermission` from `@databricks/sdk-iam` will leave users wondering whether they are interchangeable (they functionally are — both encode `USER` vs `ADMIN` workspace-level access). +- **Category:** 1 (vague/generic — `Permission` says nothing about scope), 12 (duplicate concept with `iam.WorkspaceAssignmentDetail` + `iam.WorkspacePermission`). +- **Suggested name:** `WorkspacePermission` (and reconcile with `iam.WorkspacePermission` — same shape, fewer values here). +- **Rationale:** Pick one name for the concept. `Permission` alone is the kind of name a user would shadow with a local variable and then bug-hunt for hours. + +### 3. `Permission.UNKNOWN` — `src/v1/model.ts:6` +- **Why weird:** Sentinel value for "permission not set" leaks from protobuf semantics into the public TS surface. Idiomatic TS uses `undefined` for "not present". Every other enum in this codebase that has a sentinel uses `*_UNSPECIFIED` (e.g., `WORKSPACE_PERMISSION_UNSPECIFIED`, `PRINCIPAL_TYPE_UNSPECIFIED` in iam), so even the sentinel form is inconsistent. +- **Category:** 2 (redundant enum value not needed in TS), 14 (proto-style name). +- **Suggested name:** Remove `UNKNOWN` entirely; rely on `permissionLevel?: WorkspacePermission | undefined` for the not-set case. If a wire value must be representable, prefer `Unspecified` (PascalCase) to align with the rest of TS conventions or `WORKSPACE_PERMISSION_UNSPECIFIED` to align with iam. +- **Rationale:** `UNKNOWN` is *not* on the wire spec (the iam mirror uses `WORKSPACE_PERMISSION_UNSPECIFIED`), so this value is a TS-side invention that adds a third encoding of the same concept. + +### 4. `DeleteWorkspacePermissionAssignment` — `src/v1/model.ts:13` +- **Why weird:** Type whose name is a verb phrase (`Delete...`). Same pattern repeats for `GetWorkspacePermissionAssignments`, `ListWorkspacePermissions`, `UpdateWorkspacePermissionAssignment`. Reads as an action / command, not as the request body. The `index.ts` re-exports them as `type DeleteWorkspacePermissionAssignment` — consumers see `import type {DeleteWorkspacePermissionAssignment}` and expect a method. +- **Category:** 6 (misleading: verb phrase as type name), 14 (Go-style naming where Go uses request type names directly), 17 (inconsistent verb form vs. iam package which uses `DeleteWorkspaceAssignmentDetailRequest`). +- **Suggested name:** `DeleteWorkspacePermissionAssignmentRequest` (and the parallel `Get…Request`, `List…Request`, `Update…Request`). +- **Rationale:** The iam package uses the `Request` suffix consistently (`DeleteWorkspaceAssignmentDetailRequest`, `UpdateWorkspaceAssignmentDetailRequest`, ...). The local convention here disagrees with the sibling package modelling the same domain. + +### 5. `DeleteWorkspacePermissionAssignment_Response` underscored name — `src/v1/model.ts:23` +- **Why weird:** Underscore in identifier (proto-style nested type). Requires `eslint-disable @typescript-eslint/naming-convention` (line 22). +- **Category:** 4 (underscores), 14 (Go/proto-style names). +- **Suggested name:** `DeleteWorkspacePermissionAssignmentResponse`. +- **Rationale:** TS naming rule rejects `Foo_Bar`. The ESLint suppression is a tell that the name fights the language. + +### 6. `GetWorkspacePermissionAssignments_Response` / `ListWorkspacePermissions_Response` underscored names — `src/v1/model.ts:40,58` +- **Why weird:** Same `Foo_Response` underscore proto pattern, both flagged with `eslint-disable @typescript-eslint/naming-convention`. The unmarshal schemas (lines 125, 129, 145) also share the underscore. +- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). +- **Suggested name:** `GetWorkspacePermissionAssignmentsResponse`, `ListWorkspacePermissionsResponse` (and the corresponding `unmarshal…ResponseSchema`). +- **Rationale:** TS naming rule rejects `Foo_Bar`. The ESLint suppressions are tells that the names fight the language. Other sibling packages have already moved off the underscore convention in their newer versions; this one trails. + +### 7. `GetWorkspacePermissionAssignments` request type for an HTTP `GET` that returns a *list* — `src/v1/model.ts:26`, `src/v1/client.ts:102` +- **Why weird:** The method `getWorkspacePermissionAssignments` returns a paginated list (`permissionAssignments`, `nextPageToken`, `prevPageToken`) — that is a `list` operation, not a `get`. Compare to `iam.ListWorkspaceAssignmentDetailsRequest` (same domain, different verb). Mislabelling pagination as "get" leads users to expect a single object back. +- **Category:** 6 (misleading verb), 13 (verb-tense inconsistency — `Get` for a list result), 17 (verb inconsistency with iam mirror). +- **Suggested name:** `ListWorkspacePermissionAssignmentsRequest` / `…Response`, method `listWorkspacePermissionAssignments`. +- **Rationale:** Pagination fields make this unambiguously a list. The current name reads as "get the assignments for this workspace" — singular intent, plural body — and is inconsistent with `iam.ListWorkspaceAssignmentDetails`. + +### 8. `ListWorkspacePermissions` returns a static catalog, not data — `src/v1/model.ts:50`, `src/v1/client.ts:142` +- **Why weird:** `listWorkspacePermissions` returns the (fixed) catalog of `PermissionOutput` values (`USER`, `ADMIN`, ...) that the workspace supports. The Go SDK has identical confusion: every method called `list…` looks like it lists user data, but here it lists the *types of permissions that exist*. Plus the method appears side-by-side with `getWorkspacePermissionAssignments` (which actually lists assignments), so users will wire the wrong one. +- **Category:** 6 (misleading — name implies data, returns metadata), 15 (generic field `permissions` losing meaning). +- **Suggested name:** `ListAssignablePermissionsRequest` / `listAssignablePermissions`, or `GetSupportedWorkspacePermissions` / `getSupportedWorkspacePermissions`. Either makes the metadata nature explicit. +- **Rationale:** `listWorkspacePermissions(req)` vs `getWorkspacePermissionAssignments(req)` are visually similar enough that someone scanning autocomplete will pick the wrong one. The semantic gulf between them (catalog vs assignments) demands distinct verbs. + +### 9. `PermissionOutput` / `PrincipalOutput` / `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:63,70,115` +- **Why weird:** `Output` suffix is a generic noise word that adds zero information — every response shape is "output". The Go SDK uses `Output` because protobuf service definitions use `Output` as a request/response naming convention; in TS this surfaces as `Permission` vs `PermissionOutput`, two near-identical types differing only by the field semantics. The doc comment on `WorkspacePermissionAssignmentOutput` even spells it out: "The output format for existing workspace PermissionAssignment records". A name that needs the doc string to say "this is the output type" is the symptom. +- **Category:** 1 (vague suffix), 8 (redundant type suffix), 14 (proto/Go naming). +- **Suggested name:** Drop the `Output` suffix. `Permission` (the enum) and `PermissionDetail`/`PermissionDescription` (the wrapper carrying `description`) is one option; `WorkspacePermissionAssignment`, `Principal`, `PermissionDescriptor` is another. The iam mirror dropped `Output` already (`WorkspaceAssignmentDetail`, not `WorkspaceAssignmentDetailOutput`). +- **Rationale:** Cf. rule 1 of the audit list ("vague/generic"). `Output` carries no semantics and conflicts with the sibling type in the same package. + +### 10. `WorkspacePermissionAssignmentOutput` vs `iam.WorkspaceAssignmentDetail` duplicate concept — `src/v1/model.ts:115` vs `packages/iam/src/v2/model.ts:983` +- **Why weird:** Two TS types modelling the same conceptual record: + - `WorkspacePermissionAssignmentOutput` (here): `{ principal: PrincipalOutput, permissions: Permission[], error: string }`. + - `iam.WorkspaceAssignmentDetail`: `{ principalId, workspaceId, accountId, principalType, entitlements }`. + + Both encode "what permissions does this principal have on this workspace?", but with different field sets and different field names. Users will not know which is canonical. The two packages share zero types. +- **Category:** 12 (duplicate concept), 1 (vague — `…Detail` vs `…Output` vs no suffix). +- **Suggested name:** Reconcile with iam. If the workspaceassignment API is older/account-level and iam is workspace-level, document that explicitly; if they overlap functionally, ship one shape and re-export from both packages. +- **Rationale:** This package is a tiny 4-method surface; living without a consistent type with iam is sustainable, but every SDK consumer will need to bridge the two by hand. + +### 11. `PrincipalOutput.principalName` discriminated union — `src/v1/model.ts:71-87` +- **Why weird:** The discriminator field is named `principalName` and each variant carries its own typed sub-field (`userName`, `groupName`, `servicePrincipalName`). The variant tag values are also full identifier strings (`'userName' | 'groupName' | 'servicePrincipalName'`). The result is access like `principal.principalName.userName` — three name-words in a row. The actual `displayName` is a *separate* sibling field two lines down, so the structure conflates "what kind of principal is it?" with "what is its identifier?". The iam package handles the same idea more cleanly via a `principalType: PrincipalType` enum + a single `principalId: number` field. +- **Category:** 5 (cryptic / redundant), 11 (wrapper around oneof), 12 (duplicate of `iam.PrincipalType` mechanism), 15 (generic field names lose meaning when nested). +- **Suggested name:** `principalType: PrincipalType` enum + flatten the identifier to a single string field (or per-variant fields at the top level). Match the iam approach. +- **Rationale:** `principal.principalName.userName` is three nested name tokens when the encoding is "this principal is a user named X". A flatter `principalType: 'USER' | 'GROUP' | 'SERVICE_PRINCIPAL', principalName: string, displayName: string` reads far better. + +## Medium severity + +### 12. `accountId` doc comment "The account ID." — `src/v1/model.ts:14,28,51,95` +- **Why weird:** Doc is uniformly terse — "The account ID." Doesn't say whether it's a UUID, an integer, that it falls back to `ClientOptions.accountId` (per `client.ts:46-48`), that it's required for the URL path, or that it gets URL-injected and not query-parameterised. The same field appears in four request types with the same too-thin doc. +- **Category:** 19 (underspecified ID). +- **Suggested name:** Keep `accountId`, rewrite doc to `"Databricks account ID (UUID). If omitted on the request, falls back to ClientOptions.accountId. Required at request time — the SDK substitutes an empty string into the URL path if neither is set."` +- **Rationale:** This is the only ID that has a client-side fallback mechanism. Hiding that in a comment three files away is a footgun. + +### 13. `workspaceId?: number` typed as `number` — `src/v1/model.ts:17,30,53,97` +- **Why weird:** Workspace IDs in Databricks are 64-bit integers; JS `number` loses precision above 2^53. Same problem on `principalId` (`number` too — model.ts:19,89,99). The client also unconditionally `String(req.workspaceId ?? '')`s the value into the URL (`client.ts:78,106,146,174`), implying string semantics are sufficient — meaning `number` was the wrong primitive to begin with. +- **Category:** 16 (field type contradicts domain), 19 (underspecified ID). +- **Suggested name:** Keep `workspaceId`, type as `bigint | string` (or `string` to match the URL serialisation). +- **Rationale:** Public Databricks workspace IDs cross 2^53 in account-level deployments; silent rounding bugs are a real risk. Same concern applies to `principalId`. + +### 14. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:42 vs 60,119` +- **Why weird:** `GetWorkspacePermissionAssignments_Response.permissionAssignments` is the list of assigned-principal records (with role). `ListWorkspacePermissions_Response.permissions` is the list of *permission types*. `WorkspacePermissionAssignmentOutput.permissions` is the *roles a single principal holds*. Three different things, two of them just called `permissions`. +- **Category:** 1 (vague), 15 (generic field name loses meaning), 17 (inconsistent label across siblings). +- **Suggested name:** On `ListWorkspacePermissions_Response`, rename `permissions` to `supportedPermissions` or `availablePermissions`. On `WorkspacePermissionAssignmentOutput`, rename `permissions` to `permissionLevels` or `grantedPermissions` to match the singular `permissionLevel` in `PermissionOutput`. +- **Rationale:** A user holding the response sees `.permissions` and can't tell whether it's "permissions held" or "permission types defined". + +### 15. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:64 vs 119` +- **Why weird:** The same `Permission` enum is held as singular on one type (`permissionLevel: Permission`) and plural on another (`permissions: Permission[]`). The lexical difference is significant (`level` vs no suffix) and inconsistent across the package. Internal users won't know whether to think of permissions as a scalar or set. +- **Category:** 9 (singular/plural inconsistency), 17 (inconsistent action verb / field name). +- **Suggested name:** Settle on one shape: if a principal can hold multiple levels, use `permissionLevels: Permission[]` everywhere. If `PermissionOutput` is really just describing a single level, name it `permission` (singular, matching the type). +- **Rationale:** `permissionLevel` and `permissions` are both `Permission`-typed; the asymmetry has no semantic justification visible in this file. + +### 16. `WorkspacePermissionAssignmentOutput.error?: string` — `src/v1/model.ts:121` +- **Why weird:** Embedding an opaque error string inside the success response body. The pattern is "we succeeded enough to return data, but here's a per-record error message". This is unusual: typical SDK design surfaces errors as exceptions or as a typed error union. A bare `string` carrying potentially structured error content forces the user to parse strings. Also, `error` is a reserved-ish JS identifier (global `Error` class, `try/catch` `error` parameter) and clashes with style. +- **Category:** 1 (vague), 10 (reserved-word-adjacent), 15 (generic field loses meaning), 16 (field contradicting type — a success response carrying error data). +- **Suggested name:** `errorMessage` or `partialFailureReason`, typed as `string | undefined`. Better: model the assignment as `{ ok: true, data: ... } | { ok: false, error: ... }`. +- **Rationale:** The current shape leaks the per-record-error nature of the upstream API. At minimum rename to make the partial-failure semantics explicit. + +### 17. `PermissionOutput.description` doc comment "The results of a permissions query." — `src/v1/model.ts:65-66` +- **Why weird:** Doc string is meaningless — "description" labelled as "results of a permissions query" gives the reader zero signal about what the string contains. Looking at the upstream this likely contains a human-readable description like "Allows full access" or "Read-only access". +- **Category:** 1 (vague — both field and doc). +- **Suggested name:** Keep `description`, rewrite doc to `"Human-readable description of what this permission grants (for example, 'Allows full administrative access to the workspace')."`. +- **Rationale:** The current JSDoc is worse than no doc at all because it suggests the field is a query-result wrapper. + +### 18. `PrincipalOutput.principalName` discriminator tag values use camelCase — `src/v1/model.ts:73,78,83` +- **Why weird:** `$case` values are `'userName' | 'groupName' | 'servicePrincipalName'` — those are *field names*, not discriminator tags. A discriminator value should describe the *type* of the variant (`'user' | 'group' | 'servicePrincipal'`), not duplicate the field name. The current shape forces `principalName.userName` ("user name's user name"). +- **Category:** 5 (cryptic — discriminator tag duplicates the field), 11 (trivial wrapper-around-oneof). +- **Suggested name:** Tag values `'user' | 'group' | 'servicePrincipal'`, payload field `name: string` across all three variants. Or flatten to enum + single string. +- **Rationale:** Discriminator should let `switch (p.principalName.$case)` read as `case 'user':` rather than `case 'userName':`. + +### 19. `PrincipalOutput.principalId: number` opaque ID doc — `src/v1/model.ts:88-89` +- **Why weird:** Doc reads "The unique, opaque id of the principal." with `id` lowercase mid-sentence and no casing on the field. The same field on `DeleteWorkspacePermissionAssignment` / `UpdateWorkspacePermissionAssignment` (model.ts:19,99) is documented as `"The ID of the user, service principal, or group."` — same concept, two different docs. Also `number` typing same precision issue as workspaceId. +- **Category:** 16 (field type contradicts domain), 17 (inconsistent doc across sibling types), 19 (underspecified ID). +- **Suggested name:** Keep `principalId`, type as `bigint | string`, and use one consistent doc: `"Unique numeric identifier of the principal (user / service principal / group)."`. +- **Rationale:** Three call sites for the same field, three slightly different definitions, plus a precision risk. + +### 20. `UpdateWorkspacePermissionAssignment.permissions` doc paragraph — `src/v1/model.ts:101-107` +- **Why weird:** A six-line JSDoc smuggling validation semantics into a public field comment: "If both 'USER' and 'ADMIN' are provided, 'ADMIN' takes precedence. Other values will be ignored. Note that excluding this field, or providing unsupported values, will have the same effect as providing an empty list, which will result in the deletion of all permissions for the principal." That last clause is a *destructive* behaviour hidden in a paragraph. Field name `permissions` plus this doc gives the field a meaning of "set or delete" depending on contents — too much overloading for one field. +- **Category:** 1 (vague — overloaded semantics), 6 (misleading — looks like an additive update, can be destructive). +- **Suggested name:** Either split into `setPermissions: Permission[]` / `clearPermissions: boolean`, or rename to `replacePermissions` with explicit doc "Replaces all permissions on the principal. Pass an empty array (or omit) to revoke all permissions." +- **Rationale:** Hiding a "delete everything" behaviour behind an empty/missing field is a destructive-by-omission API. Type signature should make it visible. + +### 21. `PrincipalOutput.principalName.servicePrincipalName: string` — `src/v1/model.ts:83-86` +- **Why weird:** A service principal's name is here typed as `string`, but the `iam` package treats service principals as either a `principalType: PrincipalType.SERVICE_PRINCIPAL` enum value or by `applicationId`. The string-only name representation here disagrees with iam's identifier model. +- **Category:** 12 (duplicate concept with iam.PrincipalType.SERVICE_PRINCIPAL), 17 (inconsistent representation across siblings). +- **Suggested name:** Align with iam: principalType enum + a single name/id field. If kept, rename the variant to `name` so it reads `principal.principalName.$case === 'servicePrincipal' && principal.principalName.name`. +- **Rationale:** Two packages, two shapes for "the name of a service principal" — pick one. + +### 22. `nextPageToken` / `prevPageToken` asymmetric naming — `src/v1/model.ts:44,46` +- **Why weird:** `nextPageToken` spells "next" out, `prevPageToken` abbreviates "prev". One or the other — `prev` vs `next` is a length mismatch with no win. +- **Category:** 5 (cryptic abbreviation `prev`), 17 (inconsistent abbreviation rule). +- **Suggested name:** `previousPageToken` (matches `nextPageToken`'s full-word style) or `prevPageToken` + `nextPageToken` paired (but then "next" is the outlier). Spell out both: `previousPageToken` / `nextPageToken`. +- **Rationale:** Symmetry — paired pagination tokens deserve paired naming. + +### 23. `GetWorkspacePermissionAssignments.filter?: string` — `src/v1/model.ts:36` +- **Why weird:** A bare `filter: string` field documented as "Filter string to search principals." Server-side query DSL hidden behind a `string`. Users must know what filter syntax to type. Same problem any time a public SDK exposes "filter" without typing the filter language. +- **Category:** 1 (vague), 15 (generic field loses meaning). +- **Suggested name:** `principalFilter` (more specific) plus a JSDoc snippet of the supported syntax. +- **Rationale:** Naming alone won't solve this, but `filter` is the worst-case name. + +### 24. `GetWorkspacePermissionAssignments.maxResults` plural-confusing — `src/v1/model.ts:34` +- **Why weird:** "Maximum number of permission assignments to return." Field name uses a generic `maxResults` while the response field is `permissionAssignments`. Pair them: `maxAssignments` would read better, or document explicitly. Compare `accountaccesscontrolproxy` and other sibling packages — usage of `pageSize` is common. +- **Category:** 1 (vague), 17 (inconsistent paging field naming across packages). +- **Suggested name:** `pageSize` to align with REST list conventions (which is also what the wire param `max_results` carries in many Databricks APIs). +- **Rationale:** Consistency across the SDK; the same concept should not be `pageSize` in one package, `maxResults` in another, and `limit` in a third. + +### 25. `DeleteWorkspacePermissionAssignment` 51-character type name — `src/v1/model.ts:13` +- **Why weird:** `DeleteWorkspacePermissionAssignment_Response` is a 53-character type name. `WorkspacePermissionAssignmentOutput` is 35 characters. Every type in the file is 30+ characters. Verbose for a four-method package. Suggest a shorter umbrella prefix. +- **Category:** 7 (overly verbose). +- **Suggested name:** Drop `Workspace` prefix when the entire package scope is workspace (e.g., `DeletePermissionAssignmentRequest`) — the package name already says workspace. Or shorten to `Assignment`. +- **Rationale:** `await client.deleteWorkspacePermissionAssignment(req)` is 41 characters before the open paren. The package scope already conveys "workspace". + +## Low severity + +### 26. `permissionassignments` URL fragment is one word — `src/v1/client.ts:78,106,146,174` +- **Why weird:** REST path uses `/permissionassignments/` (no separator), while every other Databricks REST resource in this SDK uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). This is a wire-format problem, not a TS naming problem, but it spills into the visual feel of the client URLs. +- **Category:** 3 (casing/separator inconsistency). +- **Suggested name:** N/A for TS, but flag upstream: prefer `permission-assignments`. +- **Rationale:** Cross-API consistency. + +### 27. `accountId?: string | undefined` doc placement — `src/v1/model.ts:14,15` +- **Why weird:** Doc above `accountId` says "The account ID." but the equally important fallback semantics live in `client.ts:46-48` ("Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins."). Doc is on the wrong side. +- **Category:** 19 (underspecified ID). +- **Suggested name:** Move/duplicate the fallback semantics into the model.ts JSDoc. +- **Rationale:** Most users read model.ts, not client.ts. + +### 28. `displayName` doc terseness — `src/v1/model.ts:91` +- **Why weird:** Doc "The display name of the principal." while the discriminated union variants above carry their own names (`userName`, `groupName`, `servicePrincipalName`). Relationship between `displayName` and the variant names is undocumented (the variant names are the canonical identifier; `displayName` is the human-friendly label — but a reader has to guess). +- **Category:** 1 (vague doc). +- **Suggested name:** Keep field name, expand doc. +- **Rationale:** A two-field name model deserves explicit roles. + +### 29. `Permission.USER` doc string — `src/v1/model.ts:7-8` +- **Why weird:** Doc "The most basic workspace permission" on `USER` but no doc on `ADMIN`. Asymmetric annotation; reader concludes `ADMIN` has no doc because it's "obvious", but `USER` does because — what? The same enum in iam (`WorkspacePermission`) also docs `USER_PERMISSION` and nothing else. Pattern is consistent, but still strange. +- **Category:** 17 (inconsistent annotation across enum members). +- **Suggested name:** Document both, or document neither. +- **Rationale:** Hover docs read better with parity. + +### 30. `URL path interpolation uses unencoded segments` — `src/v1/client.ts:78,106,146,174` +- **Why weird:** Not a naming finding strictly, but worth flagging: paths interpolate `${req.accountId ?? ''}` / `${String(req.workspaceId ?? '')}` directly into URLs without `encodeURIComponent`. If a malicious or weird `accountId` ever lands in here, path injection is possible. Sibling packages use the same pattern, so it's project-wide. +- **Category:** N/A (security/correctness, not naming). +- **Suggested name:** N/A. Flag for hardening. +- **Rationale:** Belongs in a different audit, but caught in passing. + +### 31. `unmarshalGetWorkspacePermissionAssignments_ResponseSchema` 56-char symbol name — `src/v1/model.ts:129` +- **Why weird:** Schema name combining `unmarshal` prefix + camelCase type + `_Response` underscore + `Schema` suffix. A single identifier carrying four naming conventions. +- **Category:** 4 (underscore), 7 (verbose), 8 (redundant suffix). +- **Suggested name:** `listWorkspacePermissionAssignmentsResponseSchema` (after renaming Get→List and dropping the underscore). +- **Rationale:** Same cleanup as the type rename. + +### 32. `marshalUpdateWorkspacePermissionAssignmentSchema` — `src/v1/model.ts:203` +- **Why weird:** Same prefix/suffix concern. Naming inconsistency: the `unmarshal*` schemas are typed `z.ZodType`; the `marshal*` schema is untyped (`z.ZodType` without parameter, model.ts:203). Asymmetry in the generated code. +- **Category:** 17 (inconsistent typing across marshal/unmarshal pair). +- **Suggested name:** Type as `z.ZodType` to match the read-side symbol shape. +- **Rationale:** Better IDE inference. + +### 33. `executeCall` / `executeHttpCall` near-duplicate function names — `src/v1/utils.ts:26,65` +- **Why weird:** Same package exports two top-level functions named `executeCall` and `executeHttpCall`. One unwraps `Options`; the other actually sends the request and parses. The names give no hint of the layering. +- **Category:** 1 (vague), 6 (misleading). +- **Suggested name:** `executeWithOptions` (or just `runCall`) for the first, `sendHttpRequest` / `dispatchAndParse` for the second. +- **Rationale:** Visual disambiguation; today both look identical at the import-name level. + +## Observations + +### 34. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +- **Why weird:** Exported helper function for nested query-param flattening, but the client only uses `params.append('page_token', req.pageToken)` style calls (`client.ts:108-115`) — never calls `flattenQueryParams`. Dead code in the public surface or boilerplate generator output. The export bloats the package surface. +- **Category:** 11 (dead code / unused export). +- **Suggested name:** Remove the export, or use it. +- **Rationale:** Public API surface should match what is actually used. + +### 35. `parseResponse` / `marshalRequest` are general utilities exported per-package — `src/v1/utils.ts:113,119` +- **Why weird:** These two functions are domain-agnostic JSON marshalling helpers; identical (or nearly identical) versions almost certainly exist in every sibling package's `utils.ts`. Duplicated boilerplate per package. +- **Category:** 12 (duplicate concept across packages). +- **Suggested name:** Hoist to `@databricks/sdk-core` and import. +- **Rationale:** Generator output for every API package likely repeats this. Cf. the same pattern in `accountaccesscontrol` etc. + +### 36. Side-by-side `getWorkspacePermissionAssignments` and `listWorkspacePermissions` — `src/v1/client.ts:102,142` +- **Why weird:** Two list-like methods, one named `get*` (returns paginated list), one named `list*` (returns a static catalog). Naming inverts the more usual REST convention where `list*` is paginated and `get*` is singular. +- **Category:** 17 (inconsistent action verbs), 13 (verb-tense inconsistency). +- **Suggested name:** `getWorkspacePermissionAssignments` → `listWorkspacePermissionAssignments`; `listWorkspacePermissions` → `getSupportedWorkspacePermissions`. Now `list*` always paginates, `get*` is a one-shot. +- **Rationale:** Cf. finding 7 + 8. Worth flagging once more as a pair-level observation. + +## Cross-cutting themes +1. **Proto/Go-style names leak through generation.** Eight findings (1, 3, 4, 5, 6, 9, 14, 31) trace to the upstream Go SDK's protobuf-derived shapes: `*_Response` underscore types, `*_UNSPECIFIED` / `UNKNOWN` enum sentinels, `*Output` suffixes, verb-phrase request type names, and double-wrapped oneof discriminators. None are idiomatic TS. +2. **Duplicated domain modelling with `iam` package.** Findings 1, 2, 10, 11, 21 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. +3. **Misleading verb assignment for list vs get.** Findings 7, 8, 36 — the paginated method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. +4. **Underspecified IDs and weak typing.** Findings 12, 13, 19, 27 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md new file mode 100644 index 00000000..681c74f0 --- /dev/null +++ b/.agent/naming-audit/workspacebindings.md @@ -0,0 +1,310 @@ +# Naming Audit: workspacebindings + +**Path:** `packages/workspacebindings/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). +**Total weird names flagged:** 47 + +## Summary +| Severity | Count | +| --- | --- | +| High | 14 | +| Medium | 18 | +| Low | 10 | +| Observation | 5 | + +The package contains 9 generated types (1 enum + 8 message/response shapes), 4 client methods (plus 1 paginated iterator), and the generator's standard set of marshal/unmarshal schema helpers. The pervasive issues are (1) **proto-style nested-message names** like `GetWorkspaceBindings_Response` leaking into the TS surface and requiring `eslint-disable` directives at every declaration and at every use site; (2) **the request-type-as-verb pattern** (`GetWorkspaceBindings`, `UpdateWorkspaceBindings`, `GetCatalogWorkspaceBindings`, `UpdateCatalogWorkspaceBindings`) producing the awkward `getWorkspaceBindings(req: GetWorkspaceBindings)` verb-noun-verb-noun signature; (3) **enum values that bake the type name back into every member** (`BindingType.BINDING_TYPE_READ_WRITE` etc.); (4) **stringly-typed `securableType`** that should be a closed enum; (5) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (6) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction. + +--- + +## High severity + +### 1. `BindingType.BINDING_TYPE_UNSPECIFIED` / `BINDING_TYPE_READ_WRITE` / `BINDING_TYPE_READ_ONLY` (enum members) — `src/v1/model.ts:7-9` +- **Why weird:** Every enum value redundantly embeds the enum-type name (`BINDING_TYPE_`) as a prefix. At call sites this becomes `BindingType.BINDING_TYPE_READ_WRITE`, repeating the word "binding type" twice in one expression. The generator comment on line 5 explains the prefix exists to avoid wire-level conflict with a `TableOperation` enum in `credentials_common.proto` — but that is a proto-namespace concern that should not leak into the TS surface. +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggested name:** `BindingType.UNSPECIFIED`, `BindingType.READ_WRITE`, `BindingType.READ_ONLY` (drop the embedded `BINDING_TYPE_` prefix; the enum-type already provides the namespace at every use site). +- **Rationale:** Google TS style guide § 5.4 (enums) recommends `EnumName.MEMBER`, not `EnumName.ENUMNAME_MEMBER`. The proto FQN-flattening trick should be hidden by the marshal layer (which already maps to/from the wire string), not surfaced to consumers. + +### 2. `BindingType.BINDING_TYPE_UNSPECIFIED` — `src/v1/model.ts:7` +- **Why weird:** Beyond #1, the `UNSPECIFIED` member itself is a proto-3 convention (proto3 enums require a zero value, conventionally `*_UNSPECIFIED`). In TS, a field of type `BindingType | undefined` already encodes "unspecified" via `undefined`. The enum member is unreachable in practice — a server returning `BINDING_TYPE_UNSPECIFIED` would be a protocol bug — and bloats the public API with a value users should never pass. +- **Category:** 2 (redundant enum value), 14 (proto/Go-style naming), 11 (trivial/unused value). +- **Suggested name:** Remove `UNSPECIFIED` from the TS enum; let `undefined` express the same state. +- **Rationale:** The TS `| undefined` modifier on `bindingType?: BindingType | undefined` already provides the absent state. Keeping `UNSPECIFIED` as an enum member duplicates that information. + +### 3. `GetCatalogWorkspaceBindings` (type) — `src/v1/model.ts:12` +- **Why weird:** Top-level request type whose name is an imperative verb phrase ("Get Catalog Workspace Bindings"). TS types should be nouns; verbs are reserved for methods. The Client also has a method `getCatalogWorkspaceBindings` (`client.ts:75`) that takes this type as input, producing the verb-noun-verb-noun signature `getCatalogWorkspaceBindings(req: GetCatalogWorkspaceBindings)`. Readers cannot tell from the type whether the identifier names the operation or the request shape. +- **Category:** 7 (overly verbose), 14 (Go-style request-type naming), 17 (inconsistent action verbs). +- **Suggested name:** `GetCatalogWorkspaceBindingsRequest` or `CatalogWorkspaceBindingsQuery`. Best: rename to noun form (e.g. `CatalogBindingsLookup`) to break the verb collision entirely. +- **Rationale:** Sibling SDK packages already adopt the `*Request` suffix convention. Internal consistency. + +### 4. `GetWorkspaceBindings` (type) — `src/v1/model.ts:23` +- **Why weird:** Same problem as #3. Verb-shaped request type collides with `getWorkspaceBindings` method (`client.ts:111`). +- **Category:** 7, 14, 17. +- **Suggested name:** `GetWorkspaceBindingsRequest` or `WorkspaceBindingsListRequest`. +- **Rationale:** See #3. + +### 5. `UpdateCatalogWorkspaceBindings` (type) — `src/v1/model.ts:51` +- **Why weird:** Same problem as #3. Verb-shaped request type collides with `updateCatalogWorkspaceBindings` method (`client.ts:168`). +- **Category:** 7, 14, 17. +- **Suggested name:** `UpdateCatalogWorkspaceBindingsRequest` or `CatalogWorkspaceBindingsPatch`. +- **Rationale:** See #3. + +### 6. `UpdateWorkspaceBindings` (type) — `src/v1/model.ts:66` +- **Why weird:** Same problem as #3. Verb-shaped request type collides with `updateWorkspaceBindings` method (`client.ts:203`). +- **Category:** 7, 14, 17. +- **Suggested name:** `UpdateWorkspaceBindingsRequest` or `WorkspaceBindingsPatch`. +- **Rationale:** See #3. + +### 7. `GetCatalogWorkspaceBindings_Response` — `src/v1/model.ts:18` +- **Why weird:** Proto-style nested message name (`MessageType_FieldName`) with an embedded underscore — non-idiomatic in TS. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` to compile (line 17). The wart is fully visible in the public API: consumers must write `GetCatalogWorkspaceBindings_Response` with the underscore at every use site (`client.ts:22`, `client.ts:78`, `index.ts:9`). +- **Category:** 4 (underscore in TS identifier), 14 (proto/Go-style name). +- **Suggested name:** `GetCatalogWorkspaceBindingsResponse` (drop the underscore) — or, combined with #3, `CatalogWorkspaceBindingsResponse`. +- **Rationale:** Google TS style guide § 5.2 forbids internal underscores in PascalCase identifiers. The proto FQN-flattening hack should be hidden by the generator. + +### 8. `GetWorkspaceBindings_Response` — `src/v1/model.ts:41` +- **Why weird:** Same as #7. +- **Category:** 4, 14. +- **Suggested name:** `GetWorkspaceBindingsResponse` or `WorkspaceBindingsPage` (since this is the paginated response shape). +- **Rationale:** See #7. + +### 9. `UpdateCatalogWorkspaceBindings_Response` — `src/v1/model.ts:61` +- **Why weird:** Same as #7. Particularly long: 39 characters. +- **Category:** 4, 7 (verbose), 14. +- **Suggested name:** `UpdateCatalogWorkspaceBindingsResponse` (drop the underscore). +- **Rationale:** See #7. + +### 10. `UpdateWorkspaceBindings_Response` — `src/v1/model.ts:83` +- **Why weird:** Same as #7. +- **Category:** 4, 14. +- **Suggested name:** `UpdateWorkspaceBindingsResponse` or `WorkspaceBindingsResponse`. +- **Rationale:** See #7. + +### 11. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` +- **Why weird:** Free-form `string` for what is a closed set of values. The doc-comment explicitly lists them: "(catalog, storage_credential, credential, or external_location)" — meaning the API author *knows* the set is closed but chose not to type it. A typo like `"caatalog"` will silently 4xx at the server. Also, the path is constructed via `${req.securableType ?? ''}` (`client.ts:115`, `client.ts:207`) which means an undefined value will produce a URL like `/api/2.1/unity-catalog/bindings//...` — a routing-incidental 404. +- **Category:** 19 (underspecified ID/discriminator), 1 (vague), 16 (field contradicts type domain). +- **Suggested name:** Define a `SecurableType` enum (`CATALOG`, `STORAGE_CREDENTIAL`, `CREDENTIAL`, `EXTERNAL_LOCATION`) and type both fields accordingly. +- **Rationale:** Type-safety is the entire point of TypeScript. Other UC packages in the SDK also use bare `string` for securable types — same fix should apply across all of them. + +### 12. `securableFullName` vs `catalogName` inconsistency — `src/v1/model.ts:14,53` vs `27,69` +- **Why weird:** The same conceptual value (the fully-qualified name of the securable being bound) is named two different ways depending on which request type you're looking at. `Get/UpdateCatalogWorkspaceBindings` use `catalogName` (because the legacy endpoint is catalog-specific). `Get/UpdateWorkspaceBindings` use `securableFullName` (because the generic endpoint accepts any securable). For a catalog binding, both names refer to the same string. Users porting from one variant to the other must change the field name. +- **Category:** 17 (inconsistent naming), 15 (one is a special case of the other). +- **Suggested name:** Use `fullName` everywhere (or `name`), since `securableType` already provides the discriminator. Drop the special-case `catalogName` field once the legacy API is gone. +- **Rationale:** Two field names for one logical value is a documentation and onboarding tax. + +### 13. Concept duplication: catalog-specific vs generic securable APIs — entire file +- **Why weird:** The package ships two parallel surfaces: + - `Get/UpdateCatalogWorkspaceBindings` operate on `/workspace-bindings/catalogs/{name}` (catalog-only legacy). + - `Get/UpdateWorkspaceBindings` operate on `/bindings/{securable_type}/{full_name}` (generic). +- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes (#12), different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). +- The legacy methods cannot express `READ_ONLY` bindings (they only return/accept workspace IDs, no `BindingType`) — meaning the catalog-specific API is strictly less expressive than the generic one. Yet both are shipped. +- **Category:** 12 (duplicate concept within one package), 17 (inconsistency), Observation. +- **Suggested name:** Either deprecate the catalog-specific surface (mark with `@deprecated`) and direct users to `getWorkspaceBindings({securableType: 'catalog', securableFullName: name})`, or rename the catalog-specific variant to make its legacy status explicit (e.g. `getCatalogWorkspaceBindingsLegacy`). +- **Rationale:** Two surfaces for one operation, where one is strictly weaker, is a footgun. + +### 14. Concept overlap with sibling package `workspaceassignment` — cross-package +- **Why weird:** A sibling package `packages/workspaceassignment/src/v1/` covers `WorkspacePermissionAssignment` — assigning **principals** (users, groups, service principals) to **workspaces**. The current package `workspacebindings` covers `WorkspaceBindingInfo` — assigning **securables** (catalogs, credentials, etc.) to **workspaces**. Both use the noun "workspace" and an "assign"/"bind" verb. A user searching the SDK for "how do I associate X with a workspace" will find both packages and must read both READMEs to disambiguate. There is no surface-level disambiguation in the type or method names. `workspaceassignment` even has an `assign_workspaces` / `unassign_workspaces` field in `UpdateCatalogWorkspaceBindings` (line 55, 57) — using the verb "assign" inside the *bindings* package. +- **Category:** 12 (duplicate concept across packages), 17 (inconsistent verbs: "bind" vs "assign" used for adjacent operations). +- **Suggested name:** Either align the verbs (both as "assign" or both as "bind") or rename one package to disambiguate directionally — e.g. `workspacebindings` → `securableworkspacebindings` or `ucbindings`; `workspaceassignment` → `workspaceprincipalassignment`. At minimum, pick one verb across the two packages. +- **Rationale:** Two packages with overlapping vocabulary and adjacent semantics is a discoverability hazard. The verb mix ("bind"/"assign") within a single request type (`UpdateCatalogWorkspaceBindings.assignWorkspaces`) actively misleads. + +--- + +## Medium severity + +### 15. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` +- **Why weird:** `Info` suffix is a Go-style convention (`*Info` types in `databricks/sdk-go` are pervasive: `CatalogInfo`, `TableInfo`, `SchemaInfo`...). In TS the suffix carries no information — the type *is* the binding, not a separate "info-about-the-binding" record. Just two fields: `workspaceId` and `bindingType`. +- **Category:** 14 (Go-style name), 8 (redundant suffix). +- **Suggested name:** `WorkspaceBinding`. +- **Rationale:** Drop Go suffixes when porting; sibling packages have already done this for some types but not consistently. + +### 16. `workspaces?: number[]` (field, multiple) — `src/v1/model.ts:20,63` +- **Why weird:** Generic field name "workspaces" for what is actually a list of workspace IDs (not workspace objects). The doc-comment says "A list of workspace IDs" — so the wire/value is IDs, but the field is named after the entity. A consumer might reasonably expect `workspaces: Workspace[]` and be surprised by `number[]`. +- **Category:** 6 (misleading: name implies entity, value is ID), 15 (generic field name), 16 (field contradicts type domain), 19 (underspecified ID). +- **Suggested name:** `workspaceIds`. +- **Rationale:** Pair with `assignWorkspaces`/`unassignWorkspaces` (which have the same problem, #17, #18) for consistency. + +### 17. `assignWorkspaces?: number[]` — `src/v1/model.ts:55` +- **Why weird:** Same problem as #16 — the field is a list of workspace IDs but is named after the entity ("workspaces"). The leading verb "assign" turns the field into a verb-phrase ("assign workspaces"), which reads as an imperative ("please assign workspaces") rather than a noun ("the set of workspace IDs to assign"). Additionally, the verb "assign" is inconsistent with the package noun "bindings" (see #14). +- **Category:** 6 (misleading), 17 (verb inconsistency), 19 (underspecified ID), 15 (generic field). +- **Suggested name:** `workspaceIdsToBind` or `addWorkspaceIds`, matching the `add` / `remove` pattern used in the generic `UpdateWorkspaceBindings` (lines 76, 78). +- **Rationale:** Aligns vocabulary with package noun (binding, not assign) and clarifies the field is IDs. + +### 18. `unassignWorkspaces?: number[]` — `src/v1/model.ts:57` +- **Why weird:** Same problems as #17, plus: "unassign" is a verb invented for this pair (it isn't a real English word in most dictionaries — "unassign" appears in software contexts but is dispreferred to "remove" or "revoke"). The companion field is `assignWorkspaces`, so the prefix matters here. +- **Category:** 6, 17, 5 (cryptic neologism), 19. +- **Suggested name:** `workspaceIdsToUnbind` or `removeWorkspaceIds`. +- **Rationale:** See #17. + +### 19. `bindings?: WorkspaceBindingInfo[]` (field, multiple) — `src/v1/model.ts:43,85` +- **Why weird:** Field name `bindings` on a `WorkspaceBindings` response type — repeats the type-name fragment. The surrounding context already says "this is the workspace bindings response", so the field could safely be `items`. +- **Category:** 20 (type-suffix tautology), 15 (generic). +- **Suggested name:** `items` or `workspaceBindings` (more specific). +- **Rationale:** A field on `XResponse` named after `X` is redundant. + +### 20. `add?: WorkspaceBindingInfo[]` / `remove?: WorkspaceBindingInfo[]` — `src/v1/model.ts:76,78` +- **Why weird:** Bare verb-shaped field names (`add`, `remove`). On a `UpdateWorkspaceBindings` payload, these are *what* gets added/removed (a list of bindings), but the field names read as imperatives. The doc-comments clarify, but the field names themselves carry no noun. +- **Category:** 1 (vague), 15 (generic), 17 (verb inconsistency with the catalog-specific `assignWorkspaces`/`unassignWorkspaces`). +- **Suggested name:** `addBindings` / `removeBindings`, or `bindingsToAdd` / `bindingsToRemove`, or `granted` / `revoked`. +- **Rationale:** A bare `add: WorkspaceBindingInfo[]` carries no noun. Common in change-set APIs but typically paired with a typed item collection. + +### 21. `workspaceId?: number` — `src/v1/model.ts:90` +- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` (#16) and `assignWorkspaces?: number[]` (#17) — all three would need to migrate together. +- **Category:** 16 (field contradicts type domain: 64-bit IDs typed as JS number), 19 (underspecified). +- **Suggested name:** Keep the name `workspaceId` but consider `bigint` or `string` for the type. This is a project-wide concern. +- **Rationale:** Cross-cutting JS interop issue; not unique to this package, but flagged for completeness. + +### 22. `bindingType?: BindingType` — `src/v1/model.ts:92` +- **Why weird:** Field name `bindingType` on a type called `WorkspaceBindingInfo` repeats the type-name fragment "binding". Combined with #1, the call site reads `binding.bindingType === BindingType.BINDING_TYPE_READ_WRITE` — "binding"/"binding"/"binding type"/"binding type" four times in one expression. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `accessLevel` (more descriptive — the value indicates read/write vs read-only access), or just `type` (since context is clear). +- **Rationale:** Field on `XBindingInfo` named `xBindingType` is doubly redundant. + +### 23. `maxResults?: number` — `src/v1/model.ts:35` +- **Why weird:** 12 lines of doc-comment for one field explain its conditional behaviour ("set to 0" / "set to a value greater than 0" / "set to a value less than 0" / "if not set"). The field name `maxResults` doesn't hint at the magic-value semantics. Also, sibling packages use `pageSize` for the same concept (see grants audit #18) — naming inconsistency across the SDK. +- **Category:** 17 (cross-package inconsistency), 6 (misleading: name implies a strict cap but actually has magic-value semantics). +- **Suggested name:** `pageSize` (matching sibling packages) or `pageLength`. Document the magic values via a `@see` link rather than copy-pasting 12 lines. +- **Rationale:** Cross-package consistency. + +### 24. `pageToken?: string` doc — `src/v1/model.ts:36-37` +- **Why weird:** Doc-comment "Opaque pagination token to go to next page based on previous query" is OK, but in the response side `nextPageToken` (line 45-48) the doc refers to "__page_token__" with double-underscores — a documentation hangover from a wire-format spec. Inconsistent with the TS field name `pageToken`. +- **Category:** 6 (misleading docs), Observation. +- **Suggested name:** Field name is fine; fix the doc to use TS field name `pageToken`. +- **Rationale:** Doc-comment consistency. + +### 25. `nextPageToken?: string` — `src/v1/model.ts:48` +- **Why weird:** The doc-comment includes `__page_token__` (double-underscore) referring to the request field. The actual TS field is named `pageToken` — the doc is documenting wire format, not TS. +- **Category:** 6 (misleading docs). +- **Suggested name:** Field name is fine; fix the doc text. +- **Rationale:** See #24. + +### 26. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:75` +- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #13). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 71-74 makes no mention of the generic alternative. +- **Category:** 12 (duplicate concept), Observation. +- **Suggested name:** Mark with `@deprecated` JSDoc and reference `getWorkspaceBindings`. +- **Rationale:** IDE strike-through requires the `@deprecated` tag. + +### 27. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:168` +- **Why weird:** Same as #26. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. +- **Category:** 12, Observation. +- **Suggested name:** Mark with `@deprecated`. +- **Rationale:** See #26. + +### 28. `getWorkspaceBindingsIter` (method) — `src/v1/client.ts:147` +- **Why weird:** `Iter` suffix is Go-style (Go uses `*Iterator` types). TS uses `AsyncGenerator` / `AsyncIterable` whose syntax `async *foo()` already communicates iteration. The suffix adds nothing. Plus: `getWorkspaceBindingsIter` reads as "get-workspace-bindings-iter" — five words to say "iterate workspace bindings". +- **Category:** 5 (cryptic abbreviation: `Iter`), 14 (Go-style name), 7 (verbose). +- **Suggested name:** `iterateWorkspaceBindings` (verb-first), or `workspaceBindings` (with iterator semantics implied by `AsyncGenerator` return type). +- **Rationale:** Idiomatic TS naming for async generators is verb-first or noun-only; the Go `*Iter`/`*Iterator` suffix doesn't translate. + +### 29. `Client` — `src/v1/client.ts:46` +- **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). +- **Category:** 1 (vague), 12 (duplicate across packages). +- **Suggested name:** `WorkspaceBindingsClient`. +- **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. + +### 30. `executeCall` — `src/v1/utils.ts:26` +- **Why weird:** Generic verb-noun name. Two `execute` functions in scope (`execute` imported on line 4, `executeCall` defined on line 26, `executeHttpCall` defined on line 65). The discriminator between them is just "Call" vs "HttpCall" — and both ultimately wrap the imported `execute()`. +- **Category:** 1 (vague), 17 (inconsistent action verbs). +- **Suggested name:** `executeRetryableCall` (since this one applies the retrier/rateLimiter/timeout options) or `executeWithOptions`. +- **Rationale:** Distinguishes the two wrappers semantically. + +### 31. `executeHttpCall` — `src/v1/utils.ts:65` +- **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `APIError` on 4xx/5xx (line 88-91) — a non-obvious side effect. +- **Category:** 1 (vague), 6 (misleading: "execute" sounds neutral but throws). +- **Suggested name:** `sendAndParseResponse` or `sendOrThrow`. +- **Rationale:** Naming should hint at error semantics. + +### 32. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` +- **Why weird:** Yet another `*Options` suffix in a file that already imports `Options` (line 3) and `CallOptions` (line 12) — three `Options` types in scope. `HttpCallOptions` is purely an internal context bag for `executeHttpCall` (request + httpClient + logger) — it isn't user-tunable, so `Options` is misleading. +- **Category:** 1 (vague suffix), 8 (redundant suffix), 17 (inconsistency). +- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). +- **Rationale:** Distinguish internal context bags from user-facing option structs. + +--- + +## Low severity + +### 33. `unmarshalGetCatalogWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:96` +- **Why weird:** 53-character constant name combining the redundant `Schema` suffix (#39), the proto underscore (#7), and the verb-shaped request type name (#3). Requires `eslint-disable` on line 95. +- **Category:** 4 (underscore), 7 (verbose), 8 (redundant `Schema` suffix), 14. +- **Suggested name:** `unmarshalCatalogWorkspaceBindingsResponse` (cascading from #7 and #39). +- **Rationale:** Cascades from upstream fixes. + +### 34. `unmarshalGetWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:106` +- **Why weird:** Same as #33. +- **Category:** 4, 7, 8, 14. +- **Suggested name:** `unmarshalWorkspaceBindingsResponse`. +- **Rationale:** Cascades. + +### 35. `unmarshalUpdateCatalogWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:120` +- **Why weird:** Same as #33. 56 characters. +- **Category:** 4, 7, 8, 14. +- **Suggested name:** `unmarshalUpdateCatalogWorkspaceBindingsResponse`. +- **Rationale:** Cascades. + +### 36. `unmarshalUpdateWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:130` +- **Why weird:** Same as #33. +- **Category:** 4, 7, 8, 14. +- **Suggested name:** `unmarshalUpdateWorkspaceBindingsResponse`. +- **Rationale:** Cascades. + +### 37. `unmarshalWorkspaceBindingInfoSchema` — `src/v1/model.ts:141` +- **Why weird:** Redundant `Schema` suffix (the `z.ZodType` annotation already states the kind). Combined with #15 (`*Info` Go-style suffix), the constant is `unmarshalWorkspaceBindingInfoSchema` — 35 characters of which 10 are redundant suffix. +- **Category:** 8 (redundant suffix), 14 (Go-style). +- **Suggested name:** `unmarshalWorkspaceBinding`. +- **Rationale:** Both `Info` and `Schema` add zero information beyond the type signature. + +### 38. `marshalUpdateCatalogWorkspaceBindingsSchema` — `src/v1/model.ts:152` +- **Why weird:** 43 characters with redundant `Schema` suffix and the verb-shaped request type name (#5). +- **Category:** 7, 8. +- **Suggested name:** `marshalUpdateCatalogWorkspaceBindings`. +- **Rationale:** Drop `Schema` suffix. + +### 39. `*Schema` constants (all) — `src/v1/model.ts:96,106,120,130,141,152,164,178` +- **Why weird:** Every marshal/unmarshal helper carries a `Schema` suffix. The TS type annotation `z.ZodType` already says it's a Zod schema. The suffix is redundant and contributes 6 characters to every export name. +- **Category:** 8 (redundant suffix), 20 (type-suffix tautology). +- **Suggested name:** Drop `Schema` everywhere — `unmarshalWorkspaceBinding`, `marshalUpdateCatalogWorkspaceBindings`, etc. +- **Rationale:** Naming consistency; the suffix carries no info beyond the type annotation. + +### 40. `flattenQueryParams` — `src/v1/utils.ts:123` +- **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append` on `client.ts:117-122`). Dead-looking export from the standard generator template. +- **Category:** Observation, 11 (unused public helper). +- **Suggested name:** Remove if generator default; or move to a shared utility package and not emit per-package. +- **Rationale:** Cross-package consistency. + +### 41. `readAll` — `src/v1/utils.ts:40` +- **Why weird:** Internal helper name is generic and conflicts cognitively with `Array` and `ReadableStream` APIs. The function reads a `ReadableStream` into a single `Uint8Array` buffer. The Go SDK uses `io.ReadAll` (the standard library) — direct Go-port artifact. +- **Category:** 1 (vague), 14 (Go-style: `io.ReadAll` is the Go convention). +- **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. +- **Rationale:** Cross-package consistency. + +### 42. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` +- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); but the model file uses `marshal*` / `unmarshal*` consistently — so `parseResponse` is the odd one out. Three verbs (`parse`, `marshal`, `unmarshal`) for two operations (encode, decode). +- **Category:** 17 (inconsistent action verbs). +- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry with the rest of the file. +- **Rationale:** Mirroring helps readers map TS↔wire at a glance. + +### 43. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +- **Why weird:** `Segment` is a generic word; without the inline doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. +- **Category:** 1 (vague), 15 (generic name). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Cross-package consistency. + +--- + +## Observations + +### 44. Client `Host is required.` error message — `src/v1/client.ts:57` +The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. +- **Category:** Observation. + +### 45. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` +The marshal/unmarshal helpers are exported from `model.ts` (via `export const`) but `index.ts` (lines 7-17) only re-exports types and `Client`. So the schemas are part of the package's effective import surface (`import {...} from '@databricks/sdk-workspacebindings/v1/model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). +- **Category:** Observation, 11 (effectively-internal exports). + +### 46. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` +The single word "Required" appears as a doc-comment on `workspaceId?: number`. But the field is *optional* in the TypeScript type (`workspaceId?: number | undefined`). The annotation contradicts the type modifier. Either: (a) the field is genuinely required by the server and the optional TS type is generator-wide policy (proto3 fields are all optional in TS); or (b) the doc is stale. Either way, readers can't tell. +- **Category:** Observation, 6 (misleading docs). + +### 47. `BindingType` doc-comment surfaces proto comment as TS doc — `src/v1/model.ts:5` +The comment "Using `BINDING_TYPE_` prefix here to avoid conflict with `TableOperation` enum in `credentials_common.proto`." is a wire-implementation note that has been promoted to a TS doc-comment. TS consumers should not need to know about proto namespaces. This is naming-adjacent — the comment exists *because* of the redundant prefix (#1, #2). Removing the prefix would also remove the need for the explanation. +- **Category:** Observation, 14 (proto-style naming surfaced in docs). diff --git a/.agent/naming-audit/workspaceconf.md b/.agent/naming-audit/workspaceconf.md new file mode 100644 index 00000000..c915bd70 --- /dev/null +++ b/.agent/naming-audit/workspaceconf.md @@ -0,0 +1,245 @@ +# Naming Audit: workspaceconf + +**Path:** `/home/parth.bansal/sdk-js/packages/workspaceconf/` +**Versions audited:** v1 +**Inferred domain:** Reads and writes a workspace's "known configuration" key/value entries — a generic `map[string]string` bag of advanced workspace toggles served from `/api/2.0/workspace-conf`. The legacy Go SDK calls this surface `WorkspaceConf` with methods `GetStatus`/`SetStatus`. +**Total weird names flagged:** 23 + +--- + +## Top themes (read this first) + +1. **The package name `workspaceconf` is the single biggest offense in this audit.** + - `conf` is an undocumented, cryptic abbreviation of `configuration`. Spelling it out costs four characters and removes ambiguity (cf. *config* vs *conference* vs *confidence*). + - The package's *entire surface area* is two types and two methods — yet "conf" is repeated in: package name, every type name, every method name, and the JSDoc on every public symbol. The cost of fixing it is low; the benefit is high. + - Naming-rule literature (Google TS style guide §5.4 "Abbreviations") and Databricks' own JS SDK convention (see `packages/clusters`, `packages/jobs`, `packages/cleanrooms` — all spelled out) say the right name is **`workspaceconfig`** or **`workspaceconfiguration`**. + +2. **`workspaceconf` semantically overlaps with `workspacesettings`, `settings`, and `accountsettings` — and the overlap is hidden by the cryptic name.** + - `workspacesettings` (the sibling package) exposes ~80 typed setting toggles (CSP, ESM, default warehouse, auto-restart, …) — i.e. the *typed* workspace configuration API. + - `workspaceconf` exposes the *legacy untyped* workspace configuration API, where everything is `string`/`string` and toggles are referenced by string key (e.g. `"enableIpAccessLists"`). + - In the legacy Go SDK both APIs live in *the same package* (`service/settings`) and share documentation; in the JS SDK they are split into two packages whose names do not telegraph the typed-vs-untyped distinction. The cryptic abbreviation `conf` makes the relationship invisible. + - A reader landing on `@databricks/sdk-workspaceconf` cannot tell from the name whether to use it or `workspacesettings`. The right answer ("legacy untyped string-bag for advanced toggles") should be in the package name and/or the module JSDoc — currently it is in neither. + +3. **The TS port silently changed `WorkspaceConf` from a `map` to a single `{key, value}` pair.** This is the most consequential single-name finding in the audit. See §6 below — it is not just a naming bug, it is a wire-shape bug that makes the call useless for the standard multi-toggle pattern. + +--- + +## Summary table + +| # | Severity | Category | Identifier | File:line | +|---|----------|----------|------------|-----------| +| 1 | High | Cryptic abbreviation (package-wide) | package name `workspaceconf` / `@databricks/sdk-workspaceconf` | `package.json:2` | +| 2 | High | Cryptic abbreviation, Type-suffix tautology | `WorkspaceConf` (interface) | `model.ts:9-12` | +| 3 | High | Cryptic abbreviation, Overly verbose | `GetWorkspaceConfRequest` | `model.ts:5-7` | +| 4 | High | Misleading / inconsistent action verb | `updateWorkspaceConf` method (PATCH that actually replaces / `SetStatus` upstream) | `client.ts:89` | +| 5 | High | Misleading / generic field name | `keys?: string` (single CSV string, not an array) | `model.ts:6` | +| 6 | High | Misleading / wire-shape regression vs Go SDK | `WorkspaceConf = {key, value}` (Go is `map[string]string`) | `model.ts:9-12` | +| 7 | High | Duplicate concept | `workspaceconf` vs `workspacesettings` | package level | +| 8 | High | Generic field name losing meaning | `key?` / `value?` fields | `model.ts:10-11` | +| 9 | Medium | Method name redundancy | `Client.getWorkspaceConf` / `Client.updateWorkspaceConf` | `client.ts:58, 89` | +| 10 | Medium | Verb-tense inconsistency cross-package | TS `getWorkspaceConf`/`updateWorkspaceConf` vs Go `GetStatus`/`SetStatus` | `client.ts` vs Go SDK | +| 11 | Medium | Singular/plural mismatch | `keys` (plural query arg) on a request that returns *one* `{key, value}` | `model.ts:6` vs `model.ts:9-12` | +| 12 | Medium | Singular/plural mismatch | `WorkspaceConf` (singular type) but the endpoint accepts/returns a *map* | `model.ts:9-12` | +| 13 | Medium | Overly verbose / module JSDoc missing | no `index.ts` module-level JSDoc explaining the package's scope | `index.ts:1-8` | +| 14 | Medium | Reserved-word adjacency | `key` (TS-friendly but shadows builtin `Map.prototype.keys`) | `model.ts:10` | +| 15 | Medium | Misleading | TS `WorkspaceConf` is also the *request* body of `updateWorkspaceConf` *and* the *response* of `getWorkspaceConf` — single name, two roles | `client.ts:58-86, 89-106` | +| 16 | Medium | Misleading PATCH semantics | "Sets the configuration status … including enabling or disabling it." | `client.ts:88` | +| 17 | Low | Acronym casing inconsistency | `Conf` vs spelled-out `Config` across SDK packages | cross-package | +| 18 | Low | Verbose JSDoc | "Gets the configuration status for a workspace." / "Sets the configuration status …" | `client.ts:57, 88` | +| 19 | Low | Underspecified ID | `keys` accepts comma-separated string of unspecified vocabulary | `model.ts:6` | +| 20 | Low | Type-suffix tautology | `WorkspaceConf` inside package `workspaceconf` → triple stutter | `model.ts:9` | +| 21 | Low | Module-doc location | no top-of-file JSDoc on `index.ts` (per CLAUDE.md §10.6) | `index.ts` | +| 22 | Low | Field contradicting type domain | `WorkspaceConf.value` typed `string`, but actual values are stringified booleans/numbers | `model.ts:11` | +| 23 | Low | Inconsistent action verb | `updateWorkspaceConf` (TS) corresponds to HTTP `PATCH` with **full-bag-replace** server semantics | `client.ts:98` | + +--- + +## High severity + +### 1. Package name `workspaceconf` — cryptic abbreviation +- **File:line:** `package.json:2` (`"name": "@databricks/sdk-workspaceconf"`); directory path; every import site. +- **Category:** Cryptic abbreviation. +- **Suggestion:** **`workspaceconfig`** (or `workspaceconfiguration` if the SDK is verbose-friendly). Equivalently, scoped name `@databricks/sdk-workspaceconfig`. +- **Rationale:** "conf" is not a standard abbreviation of "configuration" in any major TS/JS style guide. The Google TS style guide explicitly forbids non-conventional abbreviations (§5.4 *Abbreviations*: "Treat abbreviations like acronyms in names as whole words … Don't use abbreviations that are not widely accepted within the team or community"). The TS SDK already uses fully spelled-out forms in sibling packages (`workspacesettings`, `workspaceassignment`, `workspacebindings`) so "workspaceconf" stands out as the lone abbreviated package. The legacy Go SDK is *also* fully spelled-out — `WorkspaceConf` is the legacy type name in `service/settings`, but the *package* there is `settings`, not `workspaceconf`. This package name is a JS-SDK invention and could be fixed at the generator level with no Go-SDK churn. + +### 2. `WorkspaceConf` (interface) — cryptic + tautological +- **File:line:** `model.ts:9-12` +- **Category:** Cryptic abbreviation, type-suffix tautology, duplicate-concept. +- **Suggestion:** Rename the interface to `WorkspaceConfigEntry` (because it represents *one* key/value pair — see §6) and rename the package to `workspaceconfig` (§1). Then the type read by the consumer becomes `workspaceconfig.Entry` — semantically clear, no abbreviation. +- **Rationale:** Three problems at once. (a) "Conf" is cryptic (§1). (b) Inside a package literally named `workspaceconf`, the type `WorkspaceConf` triple-stutters when consumed (`workspaceconf.WorkspaceConf`). (c) The name does not describe the shape: in the TS port it is a single key/value pair, *not* the workspace configuration as a whole (see §6 for why this is also wrong). + +### 3. `GetWorkspaceConfRequest` — cryptic + verbose +- **File:line:** `model.ts:5-7` +- **Category:** Cryptic abbreviation, overly verbose. +- **Suggestion:** Rename to `GetWorkspaceConfigRequest` once the package is spelled out (§1). If the SDK ever moves to short package-scoped names, `GetRequest` within the package context is unambiguous. +- **Rationale:** The full name `GetWorkspaceConfRequest` is 24 characters of which 12 ("WorkspaceConf") are package-redundant and 7 ("Request") are convention noise. The legacy Go SDK calls the same shape `GetStatusRequest` (16 chars, single field `Keys`). The cryptic `Conf` abbreviation (§1) compounds the verbosity — the type appears in every consumer's import list and method signature, so a 4-character savings is real. + +### 4. `updateWorkspaceConf` method name — misleading +- **File:line:** `client.ts:89-106` +- **Category:** Misleading / inconsistent action verb. +- **Suggestion:** Either `setConfig` (matches the upstream `SetStatus` semantics — the body is a full replacement, not a partial update), or `patchConfig` (matches the HTTP verb). The current name lies about both. +- **Rationale:** The JSDoc reads "Sets the configuration status for a workspace, including enabling or disabling it." — i.e. the canonical action is **set**, not **update**. The HTTP verb is PATCH (which conventionally implies partial update) but the body shape is the entire WorkspaceConf payload; the doc and the upstream Go method name (`SetStatus`) confirm full-replace semantics. The TS verb `update` is overloaded in the rest of the SDK to mean "partial mutation by field-mask," so users will reasonably assume this method merges into the existing config — and it does not. + +### 5. `keys?: string` — misleading / generic / singular-plural confusion +- **File:line:** `model.ts:6` +- **Category:** Misleading + generic field name + singular/plural mismatch. +- **Suggestion:** Rename to `configKeys?: readonly string[]` (true array, not a CSV string) and let `flattenQueryParams` / `URLSearchParams` handle list-style query encoding. If the backend genuinely takes a CSV string, document that in a JSDoc on the field; do not make the SDK type lie. +- **Rationale:** Three problems. (a) Generic: "keys" on a request type without context means nothing — *which* keys, of *what*? Compare `configKeys` which immediately answers. (b) Plural form `keys` is a TS-array idiom that the type contradicts (`string`, not `string[]`). (c) The upstream API accepts a comma-separated string, but a strongly-typed SDK should accept `string[]` and serialize the comma-join itself; the current `keys?: string` punts string-encoding to the caller. The Go SDK has the same shape (`Keys string`) — that's a Go-SDK limitation worth fixing in the JS port, not faithfully reproducing. + +### 6. `WorkspaceConf = {key, value}` — wire-shape regression vs Go SDK (CRITICAL) +- **File:line:** `model.ts:9-12` +- **Category:** Misleading / Generic field names losing meaning / wire-shape divergence. +- **Suggestion:** Change the type to match upstream semantics: `WorkspaceConfig = Readonly>` (or `Map`). The endpoint `/api/2.0/workspace-conf` accepts and returns a map of multiple key/value pairs; the current `{key?: string; value?: string}` cannot represent that. +- **Rationale (the single most important finding in this audit):** + - In the legacy Go SDK (`databricks/databricks-sdk-go @ service/settings/model.go`): + ```go + type WorkspaceConf map[string]string + ``` + and the methods are: + ```go + GetStatus(ctx, GetStatusRequest) (*map[string]string, error) + SetStatus(ctx, WorkspaceConf) error + ``` + i.e. the request and response are *both* a map of arbitrary keys to string values. + - The TS port has: + ```ts + export interface WorkspaceConf { + key?: string | undefined; + value?: string | undefined; + } + ``` + i.e. a single optional key/value *pair*. This: + 1. Cannot represent the multi-entry response that the API actually returns (e.g. fetching multiple keys via `keys=k1,k2` returns `{"k1":"v1","k2":"v2"}`, not `{key:"k1",value:"v1"}`). + 2. Cannot update more than one toggle at a time, while the legacy semantics permit a single PATCH to flip many. + 3. Will round-trip through zod and either fail validation or silently drop fields on every realistic payload. + - The bug is *naming-shaped* — the wire format is a string→string map; the type and its fields name a single pair — so it qualifies as a naming audit finding (the type name `WorkspaceConf` promises the whole config and delivers one pair). It is also a correctness bug that should be filed against the generator. This is the *single most important* finding in this audit. + +### 7. `workspaceconf` vs `workspacesettings` — duplicate concept, undisclosed +- **File:line:** package level +- **Category:** Duplicate concept (vs workspacesettings, settings, accountsettings). +- **Suggestion:** Either: + (a) merge `workspaceconf` into `workspacesettings` as a sub-module (`workspacesettings/legacy` or `workspacesettings/raw`), since they target the same physical workspace-configuration surface, or + (b) add an unmissable `index.ts` JSDoc that says: "This package wraps the legacy untyped workspace configuration API (`/api/2.0/workspace-conf`). For typed setting toggles (CSP, ESM, default warehouse, auto-restart, etc.) use `@databricks/sdk-workspacesettings`." +- **Rationale:** A user reading the package list cannot tell what differentiates `workspaceconf` from `workspacesettings` — and the legacy Go SDK confirms they are the same logical domain (both live in `service/settings/`). The cryptic name `conf` actively hides the relationship. The package's `README` / `index.ts` says nothing to disambiguate. In a multi-package SDK this is a usability hazard: a user searching for "set workspace setting" might pick the wrong package and never realize the right typed API exists. + +### 8. `key` / `value` — generic field names losing meaning +- **File:line:** `model.ts:10-11` +- **Category:** Generic field name losing meaning. +- **Suggestion:** Once §6 is fixed (`WorkspaceConfig = Record`), the generic names go away: a map has named keys at runtime. If the wire-shape is genuinely a singleton pair (it is not, per §6), rename to `configKey` / `configValue` to add domain context. +- **Rationale:** Within a single package, every public type/method ends up reading `WorkspaceConf.key` / `WorkspaceConf.value` — but there is no signal of *what* the key is keyed by or *what* the value represents. Domain-bearing field names (e.g. `configKey: string`, `configValue: string`) make IDE hover meaningful. + +--- + +## Medium severity + +### 9. `Client.getWorkspaceConf` / `Client.updateWorkspaceConf` — method-name redundancy +- **File:line:** `client.ts:58, 89` +- **Category:** Method name redundancy / duplicate concept. +- **Suggestion:** `Client.get` / `Client.set` (matches Go `GetStatus`/`SetStatus` shorn of the redundant `Status` suffix), since the `Client` is already package-scoped. So `workspaceconfig.Client.get()` and `workspaceconfig.Client.set()`. +- **Rationale:** `workspaceconf.Client.getWorkspaceConf()` triple-stutters "workspace conf." Compare other SDK packages where the client carries the namespace (`clusters.Client.list()`, not `clusters.Client.listClusters()`). + +### 10. `getWorkspaceConf` / `updateWorkspaceConf` (TS) vs `GetStatus` / `SetStatus` (Go) — cross-package verb inconsistency +- **File:line:** TS `client.ts:58, 89`; Go `service/settings/api.go`. +- **Category:** Verb-tense / cross-SDK inconsistency. +- **Suggestion:** Standardize on one pair across SDKs. The cleanest is `get` / `set` (paired verbs), which matches the Go SDK and accurately describes the PATCH-as-replace semantics (§4). +- **Rationale:** A user reading both SDKs will notice the verb mismatch. "update" in particular is a foreign verb here (no other Get/Update verb pair in the Go SDK for this endpoint). + +### 11. `keys` (plural query arg) → returns *one* `{key, value}` — singular/plural mismatch +- **File:line:** `model.ts:6` vs `model.ts:9-12` +- **Category:** Singular/plural mismatch (intertwined with §6). +- **Suggestion:** Once §6 is fixed (return-type becomes a map), the plural request shape matches the plural response shape and this finding dissolves. +- **Rationale:** This is the surface symptom of §6. The request says "give me values for these keys (plural)" but the response can only carry one key. This is internally contradictory. + +### 12. `WorkspaceConf` (singular type) used for a map endpoint — singular/plural mismatch +- **File:line:** `model.ts:9-12` +- **Category:** Singular/plural mismatch. +- **Suggestion:** See §6. If the type stays a single entry, rename it `WorkspaceConfigEntry` (singular noun matching singular shape). +- **Rationale:** "WorkspaceConf" (or "WorkspaceConfig") names the whole bag; "WorkspaceConfigEntry" names a single pair. The current name promises the bag, delivers the entry. + +### 13. Missing module-level JSDoc on `index.ts` +- **File:line:** `index.ts:1-8` +- **Category:** Documentation absence (relates to "module doc in index" memory rule). +- **Suggestion:** Add a top-of-file JSDoc explaining what this package wraps (legacy untyped workspace configuration), how it relates to `workspacesettings`, and giving an example invocation. +- **Rationale:** Per project rule (typescript.mdc §10.6, also in user memory), module-level JSDoc belongs in `index.ts`. The package's role is unique and easily confused with `workspacesettings`; the lack of a module-level doc maximises that confusion. + +### 14. Field name `key` — adjacent to reserved patterns +- **File:line:** `model.ts:10` +- **Category:** Reserved-word adjacency. +- **Suggestion:** Rename to `configKey` (clearer, no collision risk). +- **Rationale:** `key` is not strictly reserved, but it collides with `Map.prototype.keys`, `Object.keys`, React's `key` prop, etc., so type-narrowing in user code can become ambiguous. A package-specific prefix removes the collision. + +### 15. `WorkspaceConf` overloaded as request *and* response type — misleading +- **File:line:** `client.ts:61, 90` (used as both `Promise` return and `req: WorkspaceConf` argument). +- **Category:** Misleading / duplicate concept. +- **Suggestion:** Split into `WorkspaceConfig` (response — the full map) and `UpdateWorkspaceConfigRequest` (request — a `Partial` or `Record` of just the keys to set). The Go SDK gets away with the overload because the type *is* the map, but the TS port's `{key, value}` shape (§6) makes this overload doubly confusing. +- **Rationale:** Using the same type for the request and the response works only when the wire shape is symmetric *and* the type name is shape-accurate. Here it's neither. + +### 16. PATCH but full-replace — misleading HTTP semantics +- **File:line:** `client.ts:88` (JSDoc: "Sets the configuration status …"), `client.ts:98` (HTTP `PATCH`). +- **Category:** Misleading. +- **Suggestion:** Document that PATCH is *full-bag-replace* for unspecified keys (or that absent keys retain their value — whichever is actually true). Currently the user has to inspect the upstream Go SDK to know. +- **Rationale:** HTTP PATCH conventionally merges; this endpoint's verb is `Set`. The semantic difference matters for any caller writing safe code. + +--- + +## Low severity + +### 17. `Conf` vs `Config` — acronym/abbreviation casing inconsistency cross-SDK +- **File:line:** cross-package +- **Category:** Acronym/abbreviation casing inconsistency. +- **Suggestion:** Pick `Config` everywhere (§1). +- **Rationale:** Other SDK packages spell it out; only `workspaceconf` abbreviates. + +### 18. JSDoc redundancy on the two methods +- **File:line:** `client.ts:57` ("Gets the configuration status for a workspace."), `client.ts:88` ("Sets the configuration status for a workspace, including enabling or disabling it."). +- **Category:** Overly verbose / repetitive. +- **Suggestion:** Move "the configuration status for a workspace" into the module-level JSDoc (§13); per-method docs can be one-liners ("Returns the current config." / "Replaces the config."). +- **Rationale:** Both method docs lead with the same phrase; the body of the method already implies it. + +### 19. `keys` parameter accepts an unspecified vocabulary +- **File:line:** `model.ts:6` +- **Category:** Underspecified ID / generic field. +- **Suggestion:** Either link to the Databricks docs that enumerate the valid keys ("enableIpAccessLists", "maxTokenLifetimeDays", "enableProjectTypeInWorkspace", …) or accept a typed union of known string-literal keys. +- **Rationale:** A user can't construct a valid request without finding the key vocabulary somewhere external. Documenting the legal set is a 10-minute fix and dramatically improves usability. + +### 20. Type-suffix tautology `workspaceconf.WorkspaceConf` +- **File:line:** `model.ts:9` (and every consumer importing `workspaceconf.WorkspaceConf`). +- **Category:** Type-suffix tautology. +- **Suggestion:** Drop the package prefix from the type name (per §2 — once §1 is done, `WorkspaceConfig` -> `Entry` or `Config`). +- **Rationale:** Same pattern as `accountsettings.PersonalComputeSetting` flagged in the `accountsettings` audit (severity #12-15 there). TS users access via package; the package prefix on the type name is gratuitous. + +### 21. No module-level JSDoc per project rule +- **File:line:** `index.ts:1-8` +- **Category:** Convention violation. +- **Suggestion:** Add `@module` / file-leading JSDoc summary. +- **Rationale:** Project memory references `feedback_module_doc_in_index.md` and `typescript.mdc` §10.6 — module-level JSDoc must live in `index.ts`. The current `index.ts` is comment-free. + +### 22. `value: string` typing — field contradicts domain +- **File:line:** `model.ts:11` +- **Category:** Field contradicting type domain / underspecified. +- **Suggestion:** Document (in a JSDoc on `value`) that the value is always a *stringified* primitive — even toggles are `"true"`/`"false"` strings, not booleans. Or, in the wrapper layer, deserialize known boolean/integer keys into their TS-native types. +- **Rationale:** The legacy Go SDK preserves the wire-shape `map[string]string`. In TypeScript, presenting a `value: string` field where the value is actually a JSON-encoded bool or number leaks the wire format to the user. Either document or transform. + +### 23. `updateWorkspaceConf` method body uses HTTP `PATCH` — verb mismatch with name +- **File:line:** `client.ts:98` +- **Category:** Inconsistent action verb (relates to §4). +- **Suggestion:** Either rename the method to `patchConfig` (verb matches HTTP) or change the underlying call to `PUT` (semantics match). Since the upstream Go calls this `SetStatus` (i.e. canonically a SET, not a partial update), `setConfig` is closest to truth. +- **Rationale:** Three different names ("update" / "PATCH" / "Set") describe the same operation across the three layers — TS method, HTTP layer, Go SDK. Pick one verb for the user-visible name. + +--- + +## Cross-package observations (informational) + +- The new Go SDK (`databricks/sdk-go`) does **not** have a top-level `workspaceconf` package — the workspace configuration surface in the new SDK lives under `settings/v2`. So the `workspaceconf` JS package's name is a JS-port choice and is *not* directly inherited from the new Go SDK; renaming costs the JS port nothing on the Go-port-correspondence axis. +- The legacy Go SDK (`databricks/databricks-sdk-go @ service/settings/`) is the source for the type names `WorkspaceConf`, `GetStatusRequest`, `SetStatus`, etc. The legacy Go shape `WorkspaceConf = map[string]string` is the **canonical wire shape** — the TS port diverged from it (§6). +- `workspacesettings`, `accountsettings`, `settings`, and `workspaceconf` are four packages with overlapping responsibilities. A single-page comparison doc (in the JS SDK's README) would dramatically reduce confusion. This is out of scope for a naming audit but recommended. + +--- + +## Recommendations (priority order) + +1. **Fix §6** (wire-shape regression). This is a correctness bug, not just a naming bug; file it against the generator. +2. **Rename the package** `workspaceconf` → `workspaceconfig` (§1). Update `package.json`, directory name, every import site, the index doc. +3. **Add module-level JSDoc** to `index.ts` (§7, §13, §21) explaining the package's role and its relationship to `workspacesettings`. +4. **Rename the method pair** to `get` / `set` (or `getConfig` / `setConfig`) for cross-SDK and HTTP-semantic accuracy (§4, §9, §10, §23). +5. **Type `keys` as `string[]`** (§5) and have the client serialize the CSV. diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md new file mode 100644 index 00000000..23cffd68 --- /dev/null +++ b/.agent/naming-audit/workspacesettings.md @@ -0,0 +1,445 @@ +# Naming Audit: workspacesettings + +**Path:** `/home/parth.bansal/sdk-js/packages/workspacesettings/` +**Versions audited:** v1 +**Inferred domain:** Workspace-scoped Databricks settings: AI/BI dashboard embedding policy, automatic cluster update, compliance security profile (CSP), dashboard email subscriptions, default namespace, default warehouse ID, legacy access/DBFS disablement, notebook/file export, notebook table clipboard, results download (notebook and SQL), enhanced security monitoring (ESM), LLM proxy partner-powered AI, and restrict-workspace-admins. +**Total weird names flagged:** 56 + +## Summary table + +| # | Severity | Category | Identifier | File:line | +|---|----------|----------|------------|-----------| +| 1 | Critical | Duplicate concept across packages | `workspacesettings` vs `settings` vs `accountsettings` vs `workspaceconf` | package boundary | +| 2 | Critical | Duplicate type | `BooleanMessage`, `StringMessage` (also in `accountsettings`, `settings/v2`) | `model.ts:186, 1034` | +| 3 | Critical | Duplicate type | `ComplianceStandard` (also in `accountsettings`) | `model.ts:8` | +| 4 | Critical | Duplicate type | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_*`, `RestrictWorkspaceAdminsMessage_Status` (also in `settings/v2`) | `model.ts:57, 65, 77, 89` | +| 5 | Critical | Duplicate concept | `RestrictWorkspaceAdminsSetting`, `AibiDashboardEmbeddingAccessPolicySetting` etc. mirror types in `settings/v2` | `model.ts:991, 104` and `settings/v2` | +| 6 | High | Cryptic abbreviation | `Aibi` (`AI/BI`) family of types/methods | `model.ts:57-160, 104-160`; `client.ts:335,377,752,792,1257,1292` | +| 7 | High | Cryptic abbreviation | `Csp` (Compliance Security Profile) | `model.ts:244-273`; `client.ts:872, 1365`; URL `shield_csp_enablement_ws_db` | +| 8 | High | Cryptic abbreviation | `Esm` (Enhanced Security Monitoring) | `model.ts:706-733`; `client.ts:1100,1556`; URL `shield_esm_enablement_ws_db` | +| 9 | High | Cryptic abbreviation | `Llm` (LLM Proxy Partner-Powered Workspace) | `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624,1140,1588` | +| 10 | High | Cryptic abbreviation | `Dbfs` casing (`disableLegacyDbfs`) | `model.ts:514-541, 651-670, 855-868, 1122-1129`; `client.ts:584,1063,1521` | +| 11 | High | Underscore in TS identifier | Eight `*_*_*` proto-style nested names (e.g. `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`) | `model.ts:57, 65, 77, 89, 207, 217, 224, 235` | +| 12 | High | Generic / cryptic enum sentinel | `STATUS_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10, 58, 66, 78, 91` | +| 13 | High | Redundant enum prefix | All five enums prefix the type name into every value | `model.ts:8-102` | +| 14 | High | Domain-redundant suffix | `*Setting` suffix duplicates package name `workspacesettings` | passim — most types | +| 15 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` | +| 16 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:340-345, 382-387, 425-430, 469-474, ...` | +| 17 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:321-338` | +| 18 | High | Type-suffix tautology | `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, etc. | `model.ts:302, 991` and 11 more | +| 19 | High | Method-name redundancy | `getDefaultNamespaceSetting`, `getRestrictWorkspaceAdminsSetting`, etc. | `client.ts:952, 1180, 1100, 872, 832, 752, 792` and more | +| 20 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | +| 21 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | +| 22 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:630-649` | +| 23 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:651-670` | +| 24 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:672-680` | +| 25 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:682-690` | +| 26 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:692-700` | +| 27 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:692, 1015` | +| 28 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:692 vs 1015`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | +| 29 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:939-956` | +| 30 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:181, 1248` | +| 31 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:269, 729` | +| 32 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:195` | +| 33 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:192` | +| 34 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:213` | +| 35 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:209, 211` | +| 36 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | +| 37 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:321, 1102` | +| 38 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:71, 102` | +| 39 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:672, 682, 692, 630, 651` | +| 40 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:672, 682` | +| 41 | Medium | Type-suffix tautology | `AibiDashboardEmbeddingAccessPolicySetting` (94-character type name) | `model.ts:110` | +| 42 | Medium | Type-suffix tautology | `AibiDashboardEmbeddingApprovedDomainsSetting` | `model.ts:138` | +| 43 | Medium | Verbose / type-suffix tautology | `DeleteAibiDashboardEmbeddingApprovedDomainsSettingResponse` (58 chars) | `model.ts:385` | +| 44 | Medium | Overly verbose | `UpdateAibiDashboardEmbeddingApprovedDomainsSettingRequest` (54 chars) | `model.ts:1050` | +| 45 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | +| 46 | Medium | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS`, `SECOND_AND_FOURTH_OF_MONTH`, `FIRST_AND_THIRD_OF_MONTH`, `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `FEDRAMP_MODERATE`, etc. | `model.ts:19-53, 83, 84, 101` | +| 47 | Medium | Long enum value | `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`, `ALLOW_ALL_DOMAINS` | `model.ts:59-61` | +| 48 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:988` | +| 49 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | +| 50 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 1104, 956, 1369, 1560` | +| 51 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:112-117, 252-259, 1024` | +| 52 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:248` | +| 53 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:135` | +| 54 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | +| 55 | Low | Verb-tense inconsistency | `Patch*` request types vs `Update*` request types for same HTTP verb | `model.ts:959, 967, 975 vs 1040, 1050, 1062, ...` | +| 56 | Low | Duplicate type | `Delete*Response` (10 types) duplicated across sibling settings packages | `model.ts:356-628` | + +--- + +## Critical severity + +### 1. Four overlapping settings packages: `workspacesettings`, `settings`, `accountsettings`, `workspaceconf` +- **Category:** Duplicate concept across packages +- **Suggestion:** Consolidate. The user-facing settings model on Databricks is one thing scoped two ways (account vs workspace). The TS SDK should expose `settings` with sub-namespaces `workspace.*` and `account.*`, and a single discoverable client per scope. The fourth (`workspaceconf`) is a tiny legacy key/value API that should either fold into `workspacesettings` or be marked clearly legacy. +- **Rationale:** A consumer trying to "set a workspace property" today has to know that: + - Default-namespace, AI/BI embedding, automatic-cluster-update, CSP, ESM, LLM-proxy, dashboard-email-subs, default-warehouse, disable-legacy-access, disable-legacy-DBFS, enable-export-notebook, enable-notebook-table-clipboard, enable-results-downloading, restrict-workspace-admins, sql-results-download → `workspacesettings`. + - Generic public-setting CRUD (the umbrella API) → `settings/v2`. + - Account-IP-access, CSP/ESM at account scope, disable-legacy-features, LLM-proxy at account scope, personal compute → `accountsettings`. + - Arbitrary workspace conf KV → `workspaceconf`. + No documentation surfaces this taxonomy; the consumer has to guess. The four packages share types verbatim (`BooleanMessage`, `ComplianceStandard`, `RestrictWorkspaceAdminsMessage_Status`, `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_*`) and the `settings/v2` package already exposes a generic `Setting`/`SettingsMetadata` shape that *can* represent any of these. The split is purely a wire-routing artefact. + +### 2. `BooleanMessage`, `StringMessage` — duplicated in three sibling packages +- **File:line:** `model.ts:186-188, 1034-1037` +- **Category:** Duplicate type +- **Suggestion:** Hoist into `@databricks/sdk-core/wkt` (or similar shared location) alongside `FieldMask`. These are `google.protobuf.BoolValue` and `google.protobuf.StringValue` analogues and belong with `FieldMask`, which the package already imports from `wkt`. +- **Rationale:** Three packages (`workspacesettings`, `accountsettings`, `settings/v2`) all define identical types — same one boolean/string field, same wrapping. Consumers cannot pass a `BooleanMessage` from one package to a sibling method that takes a `BooleanMessage`. The duplication is wire-bookkeeping leaking through the API surface. + +### 3. `ComplianceStandard` enum — duplicated in `accountsettings` +- **File:line:** `model.ts:8-54` (here) and identical in `accountsettings/src/v1/model.ts` +- **Category:** Duplicate type +- **Suggestion:** Hoist into a shared `compliance` module. The enum has 15 values, all canonical regulatory standards (HIPAA, PCI_DSS, FEDRAMP_*, etc.) that do not differ by setting scope. +- **Rationale:** HIPAA at the account level *is* HIPAA at the workspace level. Two enums with identical members means type-incompatible values for the same regulatory concept. + +### 4. Proto-style nested enums duplicated in `settings/v2` +- **File:line:** `model.ts:57, 65, 77, 89` (here) vs same names in `settings/v2` +- **Category:** Duplicate type +- **Suggestion:** Same as #3 — share. `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, and `RestrictWorkspaceAdminsMessage_Status` all appear identically in `settings/v2/model.ts`. +- **Rationale:** Same justification as #3: enums whose semantics are identical across packages should be defined once. Today, `workspacesettings.AibiDashboardEmbeddingAccessPolicy_AccessPolicyType.ALLOW_ALL_DOMAINS` is not assignable to `settings.AibiDashboardEmbeddingAccessPolicy_AccessPolicyType.ALLOW_ALL_DOMAINS`. + +### 5. Whole types mirrored in `settings/v2` +- **File:line:** `model.ts:104, 138, 244, 251, 691, 711, 982, 991` vs `settings/v2/model.ts` +- **Category:** Duplicate concept +- **Suggestion:** Pick one canonical home. `settings/v2` is clearly the generic surface (it exposes `Setting`, `SettingsMetadata`, `PatchPublicWorkspaceSettingRequest`). The specific-typed methods in `workspacesettings` are a sister API for the same backend data. Either fold the specific methods into `settings/v2` (preferred) or document which one is canonical. +- **Rationale:** `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage`, `BooleanMessage`, `StringMessage` all live in both packages with identical fields. The consumer cannot pass instances across the package boundary, despite naming/structure being byte-identical. + +--- + +## High severity + +### 6. `Aibi*` family — cryptic acronym not expanded in identifier +- **File:line:** `model.ts:57-160`; client.ts six methods +- **Category:** Cryptic abbreviation, acronym casing +- **Suggestion:** Either spell as `AiBiDashboardEmbedding*` (matching Databricks marketing) or `AIBIDashboardEmbedding*` (strict acronym casing). The current `Aibi` parses as one token, hiding the AI + BI = analytics-product structure. +- **Rationale:** "AI/BI dashboards" is the user-facing product name (confirmed in the JSDoc on `client.ts:749`). The wire path even uses `aibi_dash_embed_ws_acc_policy` — itself heavily abbreviated. A new reader cannot guess that `Aibi` means "AI + BI." TS style guide prefers acronym capitalization for known acronyms (`URL`, `HTTP`, `AI`, `BI`). + +### 7. `Csp*` family — undocumented acronym +- **File:line:** `model.ts:244-273`; URL slug `shield_csp_enablement_ws_db` +- **Category:** Cryptic abbreviation +- **Suggestion:** `ComplianceSecurityProfile*` everywhere (it's already spelled out in the JSDoc on line 243). The class methods are already named `ComplianceSecurityProfile`; only the wire slug is `csp`, which is fine on the wire but should not be exposed. +- **Rationale:** Identical issue to `accountsettings`. CSP overloads catastrophically with web "Content Security Policy." Outside this codebase, that is the dominant meaning. The TS-side type name is `ComplianceSecurityProfile` (good!) but the wire and the `_workspace` suffix in `complianceSecurityProfileWorkspace` discriminator is still cryptic-adjacent. + +### 8. `Esm*` family — undocumented acronym +- **File:line:** `model.ts:706-733`; URL slug `shield_esm_enablement_ws_db`; `client.ts:1100, 1556` +- **Category:** Cryptic abbreviation +- **Suggestion:** `EnhancedSecurityMonitoring*` everywhere on TS side. Wire `esm` is fine. +- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #31). + +### 9. `Llm*` family — acronym casing + verb stacking +- **File:line:** `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624, 1140, 1588` +- **Category:** Cryptic abbreviation + Acronym casing +- **Suggestion:** Spell out: `ModelProxyPartnerPoweredWorkspace` or `LargeLanguageModelProxyPartnerPoweredWorkspace` (admittedly long). Better: drop "Workspace" since the package name already scopes it → `LlmProxyPartnerPowered`. Better still: collapse to `PartnerPoweredAi` (the doc on `client.ts:1139` explicitly calls it "partner powered AI features"). +- **Rationale:** `LlmProxyPartnerPoweredWorkspace` is 31 characters parsing as five concepts: LLM-Proxy-Partner-Powered-Workspace. Without context, a reader cannot tell whether "PartnerPowered" modifies "Llm" or modifies "Workspace." `Llm` (one word) violates TS acronym casing. + +### 10. `Dbfs` casing +- **File:line:** `model.ts:514-541, 651-670, 855-868, 1122-1129` +- **Category:** Acronym casing +- **Suggestion:** `DBFS` (it's an acronym — Databricks File System). Apply consistently: `DisableLegacyDBFS`, `disableLegacyDBFS`, `GetDisableLegacyDBFSRequest`. +- **Rationale:** TS style for known acronyms is uppercase. The wire is `disable_legacy_dbfs` (lowercase) which is fine, but the TS surface should be `DBFS`. The codebase is internally consistent in using `Dbfs` everywhere, so this is a global rename. + +### 11. Eight proto-style nested-name types with underscores +- **File:line:** `model.ts:57, 65, 77, 89, 207, 217, 224, 235` +- **Category:** Underscore in TS identifier, Go/Java-style names +- **Suggestion:** Hoist nested types to top-level with concatenated names: `MaintenanceWindow`, `MaintenanceWindowWeekDayFrequency`, `MaintenanceWindowDayOfWeek`, `MaintenanceWindowWeekDayBasedSchedule`, `MaintenanceWindowWindowStartTime`, `ClusterAutoRestartEnablementDetails`, etc. — or scope them as a TS `namespace ClusterAutoRestartMessage { ... }`. +- **Rationale:** TS identifiers conventionally use PascalCase without underscores. Each of these eight identifiers has an `// eslint-disable-next-line @typescript-eslint/naming-convention` comment, which is the codebase admitting the violation. The deepest nesting (`ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`) is 54 characters — and contains "Window" twice. This is generator-level technical debt visible to the consumer. + +### 12. Sentinel enum values: `*_UNSPECIFIED` +- **File:line:** `model.ts:10, 58, 66, 78, 91` +- **Category:** Redundant enum prefix, long enum value +- **Suggestion:** Either omit the sentinel entirely (TS-idiomatic; use `undefined`) or rename to `UNSPECIFIED`. The current `COMPLIANCE_STANDARD_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `STATUS_UNSPECIFIED` triple-stutter the enum name. +- **Rationale:** TS enum members are accessed via `EnumName.MEMBER`, so `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` reads as `ComplianceStandard.ComplianceStandard.Unspecified`. The doc comment on line 9 explicitly says "Sentinel value, should not be used in prod" — yet the type forces the consumer to consider it. Idiomatic TS represents "unspecified" with `T | undefined`. + +### 13. All enum values prefixed with the enum-name token +- **File:line:** `model.ts:8-102` +- **Category:** Redundant enum prefix +- **Suggestion:** Strip prefixes. `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.MONDAY` is fine; `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` only adds noise — the `DAY_OF_WEEK_` is the enum-name token bleeding into the member. +- **Rationale:** Symmetrical with #12 — the noise is the proto3 convention of prefixing every member name with the enum name (to avoid C++ enum-scope collisions). TS scopes enums; the prefix is redundant. + +### 14. `*Setting` suffix vs package name `workspacesettings` +- **File:line:** All `*Setting`-suffixed types +- **Category:** Domain-redundant suffix +- **Suggestion:** Drop `Setting` from the type names. Consumers reach them via `workspacesettings.X`, so `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` quadruple-stutters the domain. The inner type `AibiDashboardEmbeddingAccessPolicy` already exists *without* the suffix; the outer wrapper is purely the protobuf envelope. +- **Rationale:** Compare `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` (the envelope) vs `workspacesettings.AibiDashboardEmbeddingAccessPolicy` (the data). A consumer cannot tell them apart by name; the only difference is the `Setting` suffix means "I have an etag." If the envelope is unavoidable, name it `Envelope`/`Versioned` or hide it behind an SDK helper. + +### 15. `settingName` documented as not respected on requests +- **File:line:** `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` +- **Category:** Misleading +- **Suggestion:** Mark `settingName` `readonly` on the response-only path; remove it from request bodies; or split request/response types so it is only present where meaningful. At minimum, the docstring should not say "this field is populated in the response, but it will not be respected even if it's set in the request body." +- **Rationale:** A 17-times-repeated 240-character JSDoc admits that the field is server-ignored on PATCH/UPDATE. The field is forced to `"default"` server-side. Exposing it in the public API surface only invites users to set it, expect it to take effect, and then debug why it didn't. + +### 16. `settingTypeName` query parameter ignored +- **File:line:** `client.ts:340-345, 382-387, 425-430, 469-474, 510-515, 550-555, 590-595, 630-635, 675-680, 715-720, 758-763, 798-803, 838-843, 878-883, 918-923, 958-963, 994-999, 1032-1037, 1068-1073, 1106-1111, 1146-1151, 1186-1191, 1226-1231` +- **Category:** Misleading +- **Suggestion:** Drop from the request type — the path parameter (`/api/2.0/settings/types/aibi_dash_embed_ws_acc_policy/names/default`) makes the query parameter redundant. The client serializes the path slug for the user; there is no reason to also expose the slug as a `settingTypeName` query param. +- **Rationale:** Every Get/Delete/Update sets the URL path to a hard-coded slug (e.g. `aibi_dash_embed_ws_acc_policy`) and then *also* lets the user populate `settingTypeName` and `settingName` as query params. If a user sets `settingTypeName: 'foo'`, the path still wins; the field is window dressing. + +### 17. `DefaultWarehouseId` envelope holds no warehouse-ID field directly +- **File:line:** `model.ts:321-338` +- **Category:** Underspecified ID, type-suffix tautology, misleading +- **Suggestion:** `interface DefaultWarehouse { id?: string; etag?: string; }` — a flat, non-envelope, no-wrapper type. Or hide the envelope completely and let the client method return `string | undefined`. +- **Rationale:** A reader sees `DefaultWarehouseId` and expects a `string` (or numeric ID). What they get is a four-layer struct: `defaultWarehouseId.value.stringVal.value` is the actual ID. Plus the type lacks any documentation about whether the warehouse ID is numeric (e.g. `1234`) or string-shaped (e.g. `0abc...d`). The Databricks warehouse-ID convention is opaque alphanumeric; this should be documented. + +### 18. `*Setting` type-suffix tautology in many types +- **File:line:** `model.ts:104, 110, 138, 162, 244, 251, 275, 302, 321, 630, 651, 672, 682, 692, 706, 711, 939, 982, 991, 1015` +- **Category:** Type-suffix tautology +- **Suggestion:** Drop `Setting` from the names that have an inner non-`Setting` sibling. E.g. `AibiDashboardEmbeddingAccessPolicySetting` ↔ `AibiDashboardEmbeddingAccessPolicy` should collapse to a single type, since the suffix only adds `etag` + `settingName` (both of which are envelope concerns). +- **Rationale:** Same as #14. The combination of package-name (`workspacesettings`) + type-suffix (`Setting`) + the existence of a sibling type without the suffix is *triple* redundancy at the API surface. + +### 19. Method-name redundancy in client class +- **File:line:** `client.ts:752, 792, 832, 872, 912, 952, 989, 1026, 1063, 1100, 1140, 1180, 1220, 1257, 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657` +- **Category:** Method-name redundancy +- **Suggestion:** Drop `Setting` suffix from method names: `getAibiDashboardEmbeddingAccessPolicySetting` → `getAibiDashboardEmbeddingAccessPolicy` (or, with #6, `getAiBiDashboardEmbeddingAccessPolicy`). Method already lives on `workspacesettings.Client`; the suffix is again the third stutter. +- **Rationale:** Compare `client.updateRestrictWorkspaceAdminsSetting(req)` vs `client.updateRestrictWorkspaceAdmins(req)` — the latter is unambiguous in context. + +### 20. `patch*` vs `update*` methods for the same PATCH HTTP verb +- **File:line:** `client.ts:192 (patchEnableExportNotebook), 249 (patchEnableNotebookTableClipboard), 306 (patchEnableResultsDownloading)` vs `client.ts:1257 (updateAibi...), 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657 (update*)` +- **Category:** Inconsistent action verbs +- **Suggestion:** Standardize on `update*`. The three `patch*` methods are anomalies — every other PATCH method in the package is named `update*` and every API in the SDK reading from CRUD elsewhere uses `update*`. +- **Rationale:** Three of 26 methods (`patchEnableExportNotebook`, `patchEnableNotebookTableClipboard`, `patchEnableResultsDownloading`) use the verb `patch` instead of `update`, even though all 14 PATCH-method-using siblings use `update`. The HTTP verb is the same (`PATCH`). The naming inconsistency causes consumer discovery problems. + +### 21. `delete*` methods that actually "revert" to default +- **File:line:** `client.ts:335 (deleteAibi...AccessPolicySetting), 377, 419, 464, 504, 544, 584, 624, 669, 709` +- **Category:** Inconsistent action verbs / misleading +- **Suggestion:** `resetToDefault*` or `reset*`. The doc literally reads "Reverts the SQL Results Download setting to its default value" (line 708), "Reverts the Dashboard Email Subscriptions setting to its default value" (line 418), "Reverts the enable partner powered AI features workspace setting to its default value" (line 623), etc. — the semantic is reset, not delete. +- **Rationale:** A `delete` method that doesn't delete is the worst kind of misleading verb. The HTTP verb is `DELETE` but that is the *server's* idiom for "remove the override and fall back to default." The SDK can wrap with `reset*` and hide the wire detail. + +--- + +## Medium severity + +### 22. `DisableLegacyAccess` — verb-phrase as type name +- **File:line:** `model.ts:630-649` +- **Category:** Verb-tense / verb-in-noun position +- **Suggestion:** `LegacyAccessDisablement` or `LegacyAccessToggle`. Types describing settings should be nouns. +- **Rationale:** `DisableLegacyAccess` reads as an imperative ("perform the action of disabling legacy access") rather than a state ("the legacy-access-disabled toggle setting"). The discriminator name `disableLegacyAccess` inside `.value.disableLegacyAccess: BooleanMessage` doubles the verb. + +### 23. `DisableLegacyDbfs` — verb-phrase as type name +- **File:line:** `model.ts:651-670` +- **Category:** Verb-tense / verb-in-noun position +- **Suggestion:** `LegacyDBFSDisablement` or `LegacyDBFSToggle`. +- **Rationale:** Same as #22. + +### 24. `EnableExportNotebook` — verb-phrase as type name +- **File:line:** `model.ts:672-680` +- **Category:** Verb-tense / verb-in-noun position +- **Suggestion:** `NotebookExportToggle` or `NotebookExportEnabled`. +- **Rationale:** Same as #22 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. + +### 25. `EnableNotebookTableClipboard` — verb-phrase as type name +- **File:line:** `model.ts:682-690` +- **Category:** Verb-tense / verb-in-noun position +- **Suggestion:** `NotebookTableClipboardToggle`. +- **Rationale:** Same as #22. + +### 26. `EnableResultsDownloading` — verb + gerund mash +- **File:line:** `model.ts:692-700` +- **Category:** Verb-tense / verb-in-noun position + gerund mismatch +- **Suggestion:** `NotebookResultsDownloadToggle` (matches the doc on `client.ts:280` "Notebook results download setting"). +- **Rationale:** `EnableResultsDownloading` mixes imperative `Enable` with gerund `Downloading`. The sibling type `SqlResultsDownload` (no `-ing`, no `Enable`) does the same thing for SQL. The inconsistency is severe — same domain, two different naming conventions. + +### 27. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package +- **File:line:** `model.ts:692, 1015` +- **Category:** Verb-tense / -ing gerund inconsistency +- **Suggestion:** Pick one form. Either both as `*Toggle` or both as `Enable*Downloading`. +- **Rationale:** Both control downloading of query results. The notebook variant is `EnableResultsDownloading` (gerund). The SQL variant is `SqlResultsDownload` (noun). The pair was authored at different times by different teams and the inconsistency leaked into the API. + +### 28. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap +- **File:line:** `model.ts:692, 1015` +- **Category:** Misleading / parallel naming +- **Suggestion:** Unify under one type with a discriminator: `ResultsDownloadToggle { context: 'notebook' | 'sql', enabled: boolean }`. +- **Rationale:** The doc on `client.ts:280` calls one "Notebook results download" and the doc on `client.ts:1219` calls the other "SQL Results Download." They have the same shape and similar semantics — but the methods, types, and wire slugs are all separate. This is duplicated wiring at the API surface. + +### 29. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix +- **File:line:** `model.ts:939-956` +- **Category:** Misleading +- **Suggestion:** Drop `Workspace`. The package name is `workspacesettings`, so every type is workspace-scoped. The suffix exists only to mirror `LlmProxyPartnerPoweredAccount` in `accountsettings` — which is symmetrical but ill-justified (both should drop their scope suffix). +- **Rationale:** Compare to siblings: `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, `SqlResultsDownload`, `EnableExportNotebook` — none of them carry the "Workspace" suffix despite being workspace-scoped. `LlmProxyPartnerPoweredWorkspace` is the outlier. + +### 30. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" +- **File:line:** `model.ts:181, 1248` +- **Category:** Misleading +- **Suggestion:** `clusterAutoRestart` (matches the actual data type, `ClusterAutoRestartMessage`). +- **Rationale:** Inside `AutomaticClusterUpdateSetting.value.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage` — the discriminator name uses one phrase ("automatic cluster update workspace") while the type uses another ("ClusterAutoRestartMessage"). The reader must mentally bridge "automatic cluster update" with "cluster auto restart." + +### 31. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" +- **File:line:** `model.ts:269, 729` +- **Category:** Misleading +- **Suggestion:** Drop "Workspace" suffix: `complianceSecurityProfile`, `enhancedSecurityMonitoring`. +- **Rationale:** Same as #29. + +### 32. `restartEvenIfNoUpdatesAvailable` — double negative +- **File:line:** `model.ts:195` +- **Category:** Misleading +- **Suggestion:** `restartUnconditionally` (or invert: `skipIfNoUpdates` with opposite default). +- **Rationale:** "Restart even if no updates available" is a triple-conditional that takes effort to parse. The semantics are "restart regardless of update availability." Boolean fields should read as clean predicates. + +### 33. `canToggle` — vague boolean +- **File:line:** `model.ts:192` +- **Category:** Misleading +- **Suggestion:** `isToggleable` or `canBeDisabledByCustomer`. +- **Rationale:** `canToggle` on its own does not specify *what* can be toggled or by *whom*. From context (`ClusterAutoRestartMessage`), this likely means "can the customer toggle the auto-restart setting." The name does not convey that. + +### 34. `forcedForComplianceMode` — past-participle as flag +- **File:line:** `model.ts:213` +- **Category:** Misleading +- **Suggestion:** `isForcedByComplianceMode` or `forcedDueToComplianceMode`. +- **Rationale:** `forcedFor` reads ambiguously — "for the purpose of" or "due to"? The doc on line 212 ("The feature is force enabled if compliance mode is active") confirms the meaning is "due to." + +### 35. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative +- **File:line:** `model.ts:209, 211` +- **Category:** Misleading +- **Suggestion:** Invert: `requiresEnterpriseTier`, `requiresEntitlement` — read more naturally. +- **Rationale:** "Unavailable for non-enterprise" requires reasoning over two negatives. "Requires enterprise" is a positive predicate. + +### 36. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` +- **File:line:** Throughout model.ts and client.ts +- **Category:** Acronym casing +- **Suggestion:** Apply TS-conventional casing — `DBFS`, `AIBI` (or `AiBi`), `LLM`, `CSP`, `ESM`, `SQL` — or, where they are domain acronyms, document expansion. The codebase is internally consistent in using `Pascal-token-case` for all of them, but this contradicts the TS style guide and the JSDoc which uses correct casing (`AI/BI`, `LLM`, `SQL`, etc. in prose). +- **Rationale:** JSDoc has it right; identifiers don't. + +### 37. `Id` vs `ID` casing +- **File:line:** `model.ts:321, 1102` (`DefaultWarehouseId`, `UpdateDefaultWarehouseIdRequest`, `defaultWarehouseId` method) +- **Category:** Acronym casing +- **Suggestion:** `DefaultWarehouseID`, `UpdateDefaultWarehouseIDRequest` — or, if `Id` is house style, document it explicitly. Pick one and apply globally. +- **Rationale:** Established TS code is split — some major SDKs use `Id` (consistent with `Pascal-token-case`), others use `ID` (matches HTTP/spec convention). The Go SDK uses `Id`. The Databricks JS SDK should pick one and apply it everywhere; today, "Id" is used here but "ESM/CSP/LLM" suggests acronym capitalization is house style. + +### 38. `Url` casing +- **File:line:** `utils.ts:71, 102` +- **Category:** Acronym casing +- **Suggestion:** Match the upstream `HttpRequest.url` field; if upstream uses `url`, leave it. Note inconsistency for the audit reviewer. +- **Rationale:** Minor — flagged because the rule applies. + +### 39. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns +- **File:line:** `model.ts:672 (EnableExportNotebook), 682 (EnableNotebookTableClipboard), 692 (EnableResultsDownloading), 630 (DisableLegacyAccess), 651 (DisableLegacyDbfs)` +- **Category:** Verb-tense inconsistency +- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #22–26. +- **Rationale:** Five types here use three different inflection patterns. + +### 40. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap +- **File:line:** `model.ts:672, 682` +- **Category:** Verb-tense inconsistency +- **Suggestion:** Pick word-order convention: noun-verb-noun (`EnableNotebookExport`, `EnableNotebookTableClipboard`) or verb-noun-noun (`EnableExportNotebook`, `EnableClipboardTable`). +- **Rationale:** "Enable Export Notebook" puts the noun ("Notebook") last; "Enable Notebook Table Clipboard" puts it first. The cognitive cost of two siblings in the same package using opposite orders is non-trivial. + +### 41. `AibiDashboardEmbeddingAccessPolicySetting` — 41-character type-suffix tautology +- **File:line:** `model.ts:110` +- **Category:** Type-suffix tautology, overly verbose +- **Suggestion:** `EmbeddingAccessPolicy` (drop `Aibi` → covered by package context; drop `Dashboard` → covered by the embedding scope; drop `Setting` → covered by `*Setting` cleanup). +- **Rationale:** Five tokens, each redundant against context. The TS surface area is paying for proto-name verbosity. + +### 42. `AibiDashboardEmbeddingApprovedDomainsSetting` — 44-character type-suffix tautology +- **File:line:** `model.ts:138` +- **Category:** Type-suffix tautology, overly verbose +- **Suggestion:** `EmbeddingApprovedDomains`. +- **Rationale:** Same as #41. + +### 43. `DeleteAibiDashboardEmbeddingApprovedDomainsSettingResponse` — 58-character verbose name +- **File:line:** `model.ts:385` +- **Category:** Overly verbose, type-suffix tautology +- **Suggestion:** `ResetEmbeddingApprovedDomainsResult` (still long). +- **Rationale:** 58 characters is a noise tax on every consumer. + +### 44. `UpdateAibiDashboardEmbeddingApprovedDomainsSettingRequest` — 56-character verbose name +- **File:line:** `model.ts:1050` +- **Category:** Overly verbose, type-suffix tautology +- **Suggestion:** `UpdateEmbeddingApprovedDomainsRequest` (or after #5, no separate request — use a generic shape from `settings/v2`). +- **Rationale:** Same as #43. + +### 45. `delete*` method names — reserved-word adjacency +- **File:line:** `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` +- **Category:** Reserved-word collision (soft) +- **Suggestion:** `reset*` (which also fixes #21). +- **Rationale:** `delete` is a JS reserved word (`delete obj.prop`). Using it as a method prefix is technically fine but creates parsing-cost ambiguity in mental models, especially when the operation doesn't *actually* delete. + +### 46. Long enum values +- **File:line:** `model.ts:19-53, 83, 84, 101` +- **Category:** Long enum value +- **Suggestion:** Most are unavoidable (regulatory standard names like `FEDRAMP_MODERATE` are canonical). For `RESTRICT_TOKENS_AND_JOB_RUN_AS` consider `RESTRICT_TOKEN_AND_JOB_RUN_AS` (singular `TOKEN`); for `SECOND_AND_FOURTH_OF_MONTH` consider abbreviation (this is a maintenance-window pattern). +- **Rationale:** Length is unavoidable for proper nouns but `RESTRICT_TOKENS_AND_JOB_RUN_AS` mixes plural noun + singular verb-phrase awkwardly. + +### 47. Enum values for domain-allow lists +- **File:line:** `model.ts:59-61` (`ALLOW_ALL_DOMAINS`, `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`) +- **Category:** Long enum value +- **Suggestion:** `ALLOW_ALL`, `ALLOW_APPROVED`, `DENY_ALL` — drop `_DOMAINS` since the enum is already named `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` and the domain context is established. +- **Rationale:** Redundant tail. Compare with `STATUS_UNSPECIFIED`, `ALLOW_ALL`, `RESTRICT_TOKENS_AND_JOB_RUN_AS` in `RestrictWorkspaceAdminsMessage_Status` — none carry a redundant noun. + +### 48. `disableGovTagCreation` — verb-as-field +- **File:line:** `model.ts:988` +- **Category:** Verb-tense inconsistency, cryptic abbreviation +- **Suggestion:** `governanceTagCreationDisabled` or `restrictsGovernanceTagCreation`. `Gov` is also cryptic abbreviation. +- **Rationale:** The field is a boolean predicate that, when `true`, disables tag creation. A noun-phrase reads more naturally. `Gov` short for "governance" is non-standard — "Gov" usually means "government" — and is documented only by the comment on lines 985-987. + +--- + +## Low severity + +### 49. Cryptic wire-key abbreviations in URL slugs +- **File:line:** `client.ts:339 (aibi_dash_embed_ws_acc_policy), 381 (aibi_dash_embed_ws_apprvd_domains), 756, 796, 1261, 1296` +- **Category:** Cryptic abbreviation +- **Suggestion:** Wire keys are server-controlled; the SDK can't unilaterally rename. Worth flagging for the broader Databricks-platform team — these URL paths are exposed in logs and SDK telemetry. `apprvd` for `approved` saves 1 character. +- **Rationale:** Wire keys aren't strictly in scope for naming audits, but they bleed into log lines and error messages. `dash_embed` for "dashboard embedding" is also non-obvious. + +### 50. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix +- **File:line:** `client.ts:468 (default_namespace_ws), 876 (shield_csp_enablement_ws_db), 1104 (shield_esm_enablement_ws_db)` +- **Category:** Cryptic abbreviation +- **Suggestion:** Wire-team concern. `ws` is workspace, `db` is database (?), `ac` is account (in `accountsettings`). These two-letter suffixes are dense. +- **Rationale:** `shield_csp_enablement_ws_db` mixes three abbreviated tokens (`shield` is fine, `csp` and `ws_db` are cryptic). + +### 51. `eTag` (doc) vs `etag` (field) +- **File:line:** `model.ts:112-117, 252-259, 1024` (every `etag` doc block) +- **Category:** Acronym casing +- **Suggestion:** Standardize either `etag` or `eTag`. RFC 7232 spells it "ETag" in HTTP headers; Databricks docs spell it `eTag` in prose and `etag` as the JSON field. +- **Rationale:** Internal-doc inconsistency. The JSDoc on every type says "etag used for versioning. The response is at least as fresh as the eTag provided." — the same paragraph uses two casings. + +### 52. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope +- **File:line:** `model.ts:248` +- **Category:** Singular/plural mismatch (mild — correct in context) +- **Suggestion:** No change. Flagged only because the audit checklist asks for it. The field is correctly plural because it holds an array; the parent type is correctly singular because there is one profile. +- **Rationale:** Consistent. No action needed. + +### 53. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` +- **File:line:** `model.ts:135` +- **Category:** Singular/plural +- **Suggestion:** None needed for this field. Flagging the parent type name — `AibiDashboardEmbeddingApprovedDomains` is plural (because it holds a list) while sibling `AibiDashboardEmbeddingAccessPolicy` is singular. The asymmetry is fine but inconsistent stylistically. +- **Rationale:** Minor; preserved for completeness. + +### 54. Wire-key length in shorter slugs +- **File:line:** `client.ts:836 (automatic_cluster_update), 423 (dashboard_email_subscriptions), 673 (restrict_workspace_admins)` +- **Category:** Verbose / could be shorter +- **Suggestion:** Wire-team concern. +- **Rationale:** These three slugs are 24+ characters but spell every word out (unlike `aibi_dash_embed_ws_acc_policy` which abbreviates aggressively). The inconsistency in wire-side abbreviation conventions is itself a flag. + +### 55. `Patch*Request` types vs `Update*Request` types for same PATCH HTTP verb +- **File:line:** `model.ts:959 (PatchEnableExportNotebookRequest), 967 (PatchEnableNotebookTableClipboardRequest), 975 (PatchEnableResultsDownloadingRequest)` vs `model.ts:1040, 1050, 1062, 1072, 1082, 1092, 1102, 1112, 1122, 1132, 1142, 1152, 1162 (Update*Request)` +- **Category:** Verb-tense inconsistency +- **Suggestion:** Match #20 — standardize on `Update*Request`. +- **Rationale:** 3 of 17 request types use `Patch*`, the other 14 use `Update*`. + +### 56. `Delete*Response` types duplicated across sibling settings packages +- **File:line:** `model.ts:356, 385, 414, 443, 472, 501, 530, 559, 588, 617` +- **Category:** Duplicate type +- **Suggestion:** Hoist to a shared module alongside `BooleanMessage`/`StringMessage` (see #2), or use a single canonical `EtagResponse` type across all settings packages. +- **Rationale:** Ten types with identical one-field shape repeat across `workspacesettings`, `accountsettings`, and `settings/v2`. Each is a distinct TS type to satisfy proto naming, so a `Delete*Response` from one package is not assignable to a sibling's. + +--- + +## Cross-cutting themes + +1. **Four overlapping settings packages.** `workspacesettings` + `settings` + `accountsettings` + `workspaceconf` is a confusing taxonomy with literal type duplication. Almost every type in `workspacesettings` has a doppelganger in `settings/v2`. (Severity #1, #2, #3, #4, #5.) + +2. **`*Setting` triple stutter.** Package is `workspacesettings`, types are `*Setting`, methods are `get*Setting()`. Three layers of "setting" in every consumer call. (Severities #14, #18, #19.) + +3. **Proto-style nested-name underscores.** Eight identifiers use proto-IDL underscore nesting (`Foo_Bar_Baz`), each with an eslint-disable comment. (Severity #11.) + +4. **Sentinel `*_UNSPECIFIED` and redundant enum-name prefixes.** Proto3 convention bleeds into TS enums. (Severities #12, #13.) + +5. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #6, #7, #8, #9, #10, #36, #37, #38.) + +6. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #22-26, #39-40.) + +7. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #20, #21, #45.) + +8. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #15, #16.) + +9. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #49, #50.) diff --git a/AGENTS.md b/AGENTS.md index 10b54bce..46494751 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -114,3 +114,133 @@ npm run clean `.github/PULL_REQUEST_TEMPLATE.md`. When writing or improving a PR description, follow the workflow in `.agent/skills/write-pr-description.mdc`. + +## Naming Audit Maintenance + +The naming audit lives at `.agent/naming-audit/`: + +- One `.md` per API package in `packages/` (~98 files). +- A cross-package synthesis at `_SUMMARY.md`. + +Each per-package audit follows a fixed structure: a summary table, then +`High`/`Medium`/`Low`/`Observation` sections with one numbered finding per +issue. Each finding cites `file:line`, the category, a suggested name, and +the rationale. + +Two reduction workflows keep the audit current. Both spawn one +`general-purpose` agent per API package in parallel batches of ~20 to +avoid collision in reasoning. Always omit the `model` parameter so +subagents inherit the parent model. + +### A. Rescan after the generator runs + +**Trigger:** the user regenerated client code under `packages/*/src/v*/` +and asks to re-validate the audit. Phrasings like "rescan the audit", +"re-run the naming audit", or "the generated client changed". + +**Per-package agent task:** + +1. List the package's source files (`src/v*/model.ts`, `client.ts`, + `utils.ts`, `index.ts`) and read each in full. +2. Read the existing audit at `.agent/naming-audit/.md`. +3. For every numbered finding, locate the cited symbol in the current + source and classify it as: + - **Fixed** — the symbol is gone, has been renamed to the suggested + name, or the underlying issue (e.g. underscore identifier, redundant + enum prefix) no longer applies. + - **Still present** — same symbol, same problem, possibly at a new + line number; update the line number in place. + - **Superseded** — the symbol exists but the original concern shifted + into a different category; rewrite the finding. +4. Delete fixed findings from the active `High`/`Medium`/`Low` sections. + Append them to a `## Fixed` section at the bottom of the file with a + one-line note (`Fixed in regeneration on YYYY-MM-DD`). +5. Recompute the summary table totals. + +**After every agent finishes:** regenerate `_SUMMARY.md` so the +cross-package totals, theme counts, and by-the-numbers table reflect the +new state. Do not edit `_SUMMARY.md` by hand; spawn a synthesis agent +that re-reads every per-package audit. + +### B. Prune a recommendation category + +**Trigger:** the user pushes back on a class of finding as not a real +issue. Examples: "underscore `_Response` identifiers are fine", "redundant +enum prefixes are intentional for proto compatibility", "`marshal` / +`unmarshal` verb names are deliberate". + +**Per-package agent task:** + +1. Read `.agent/naming-audit/.md`. +2. Identify every finding whose category, rationale, or suggested-name + pattern matches the user-described class. Be exhaustive — the same + category may appear in `High`, `Medium`, `Low`, and `Observation` + sections and may be phrased differently across packages. +3. Remove those findings cleanly. Renumber remaining findings so the + numbering stays sequential. +4. Recompute the summary table totals. +5. If pruning empties a section, leave the section header with a single + line saying `_None._` rather than deleting the header. + +The agent prompt must spell out the disqualifying criterion verbatim from +the user. Do not generalize. If the user says "stop flagging `_Response` +underscores", the agent removes findings about `Foo_Response` underscored +identifiers — not findings about underscores in other contexts (e.g., +`Foo_BarType` proto-nested type names). + +**After every agent finishes:** regenerate `_SUMMARY.md` the same way as +in workflow A. + +### C. Promote to a generator-only recommendation + +**Trigger:** the user explicitly tells you a class of finding is only +fixable at the generator/template level and is not worth carrying in 98 +per-package audits. Phrasings like "this is a generator-only fix", "only +add this to the summary", "this is generator-only, prune it from every +package". + +**Never invoke this workflow autonomously.** Claude must not decide that +something is "generator-level" on its own — only the user can promote a +finding to this category. If Claude believes a category looks like it +fits, it can suggest workflow C, but must wait for explicit confirmation +before spawning agents. + +**Per-package agent task:** + +1. Read `.agent/naming-audit/.md`. +2. Remove every finding matching the user's verbatim criterion (same + precision rules as workflow B). +3. Renumber remaining findings and recompute the summary table totals. +4. If pruning empties a section, leave the section header with a single + line saying `_None._`. + +**Summary recording (once, not per-package):** after all per-package +agents finish, spawn a synthesis agent that edits `_SUMMARY.md` to add +the rule under a `## Generator-only recommendations` section (create the +section if it does not exist). Each entry must record: + +- The rule, in one line (e.g., "Drop the `_Response` underscore suffix + on response types"). +- Why it is generator-only (one line). +- The approximate package count where it appeared before pruning + (read from git diff of the per-package files, or count from the prior + `_SUMMARY.md` themes table). +- One illustrative example (`` — `Foo_Response`). + +This ensures the recommendation is not lost — the user reads it once in +`_SUMMARY.md` instead of 98 times in per-package files. After adding, +regenerate the rest of `_SUMMARY.md` (themes, by-the-numbers table, +totals) so cross-package counts stay consistent. + +### Operational notes + +- The list of API packages is everything under `packages/` that has a + `src/v*/` subdirectory. Generate it with: + `for d in packages/*/; do [ -d "$d/src" ] && ls "$d/src" 2>/dev/null | grep -qE '^v[0-9]' && echo "${d#packages/}"; done`. +- Batch parallel agent calls at ~20-25 per message. +- Agents must always write back to the existing audit file path. Never + create new files in `.agent/naming-audit/` outside of `_SUMMARY.md` + and the one-per-package `.md`. +- The `auth`, `core`, `databricks`, `sdk`, and `options` packages are + hand-written, not generated. They are out of scope for the naming + audit — do not create or update audit files for them. From 4cd5fdc5a907b76cbdb7e764408855929c9f81bb Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Mon, 18 May 2026 16:03:29 +0000 Subject: [PATCH 02/12] mark pagination as generator change --- .agent/naming-audit/_SUMMARY.md | 304 ++++++++-------- .agent/naming-audit/abacpolicies.md | 22 +- .agent/naming-audit/accountaccesscontrol.md | 21 +- .../naming-audit/accountaccesscontrolproxy.md | 45 +-- .agent/naming-audit/alerts.md | 57 ++- .agent/naming-audit/apps.md | 113 ++---- .agent/naming-audit/artifactallowlists.md | 60 +--- .agent/naming-audit/billableusagedownload.md | 40 +-- .agent/naming-audit/budgetpolicy.md | 67 +--- .agent/naming-audit/budgets.md | 141 +------- .agent/naming-audit/bundle.md | 48 +-- .agent/naming-audit/catalogs.md | 238 +++++-------- .agent/naming-audit/cleanroomassets.md | 147 ++------ .../cleanroomautoapprovalrules.md | 66 ++-- .agent/naming-audit/cleanrooms.md | 80 +---- .agent/naming-audit/cleanroomtaskruns.md | 153 ++------ .agent/naming-audit/clusterlibraries.md | 169 ++++----- .agent/naming-audit/clusterpolicies.md | 45 +-- .agent/naming-audit/clusters.md | 42 +-- .agent/naming-audit/commandexecution.md | 111 +++--- .agent/naming-audit/connections.md | 56 +-- .agent/naming-audit/credentials.md | 35 +- .agent/naming-audit/customllms.md | 86 ++--- .agent/naming-audit/database.md | 21 +- .agent/naming-audit/dataclassification.md | 80 +---- .agent/naming-audit/dataquality.md | 120 ++----- .agent/naming-audit/disasterrecovery.md | 49 +-- .agent/naming-audit/endpoints.md | 100 ++---- .agent/naming-audit/entitytagassignments.md | 85 ++--- .agent/naming-audit/environments.md | 42 +-- .agent/naming-audit/experiments.md | 221 +++++------- .agent/naming-audit/externallineage.md | 72 ++-- .agent/naming-audit/externallocations.md | 36 +- .agent/naming-audit/externalmetadata.md | 73 ++-- .agent/naming-audit/features.md | 62 ++-- .agent/naming-audit/featurestore.md | 147 ++------ .agent/naming-audit/files.md | 91 ++--- .agent/naming-audit/forecasting.md | 114 +----- .agent/naming-audit/functions.md | 41 +-- .agent/naming-audit/genie.md | 9 +- .agent/naming-audit/gitcredentials.md | 120 ++----- .agent/naming-audit/globalinitscripts.md | 72 +--- .agent/naming-audit/grants.md | 92 +---- .agent/naming-audit/iam.md | 44 +-- .agent/naming-audit/indexes.md | 120 +++---- .agent/naming-audit/instancepools.md | 83 ++--- .agent/naming-audit/instanceprofiles.md | 57 +-- .agent/naming-audit/jobs.md | 21 +- .agent/naming-audit/knowledgeassistants.md | 58 ++- .agent/naming-audit/lakeview.md | 39 +- .../naming-audit/logdeliveryconfigurations.md | 101 +++--- .agent/naming-audit/marketplaces.md | 71 +--- .agent/naming-audit/materializedfeatures.md | 206 ++--------- .agent/naming-audit/metastores.md | 332 ++++++------------ .agent/naming-audit/modelregistry.md | 49 +-- .agent/naming-audit/modelservingdebug.md | 189 ++-------- .agent/naming-audit/modelservingmanagement.md | 134 +++---- .agent/naming-audit/modelservingquery.md | 20 +- .../naming-audit/notificationdestinations.md | 93 ++--- .../naming-audit/oauthcustomappintegration.md | 9 +- .agent/naming-audit/oauthpublishedapp.md | 20 +- .agent/naming-audit/onlinetables.md | 81 +---- .agent/naming-audit/permissions.md | 58 +-- .agent/naming-audit/pipelines.md | 8 +- .agent/naming-audit/policyfamilies.md | 108 ++---- .agent/naming-audit/postgres.md | 20 +- .agent/naming-audit/qualitymonitor.md | 74 ++-- .agent/naming-audit/qualitymonitors.md | 65 ++-- .agent/naming-audit/queries.md | 141 +++----- .agent/naming-audit/queryexecution.md | 103 ++---- .agent/naming-audit/queryhistory.md | 7 +- .agent/naming-audit/registeredmodels.md | 121 +++---- .agent/naming-audit/repos.md | 113 ++---- .agent/naming-audit/resourcequotas.md | 61 +--- .agent/naming-audit/rfa.md | 60 +--- .agent/naming-audit/schemas.md | 142 ++------ .agent/naming-audit/secrets.md | 46 +-- .agent/naming-audit/secretsuc.md | 77 +--- .../naming-audit/serviceprincipalsecrets.md | 114 ++---- .../serviceprincipalsecretsproxy.md | 82 +---- .agent/naming-audit/settings.md | 213 +++++------ .agent/naming-audit/statementexecution.md | 60 ++-- .agent/naming-audit/supervisoragents.md | 85 ++--- .agent/naming-audit/systemschemas.md | 64 +--- .agent/naming-audit/tables.md | 90 +---- .agent/naming-audit/tagassignments.md | 99 ++---- .agent/naming-audit/tagpolicies.md | 89 ++--- .agent/naming-audit/tokenmanagement.md | 69 +--- .agent/naming-audit/tokens.md | 70 ++-- .agent/naming-audit/usagedashboards.md | 38 +- .agent/naming-audit/usagepolicy.md | 60 ++-- .agent/naming-audit/volumes.md | 71 ++-- .agent/naming-audit/warehouses.md | 106 ++---- .agent/naming-audit/workspace.md | 8 +- .agent/naming-audit/workspaceassignment.md | 120 ++----- .agent/naming-audit/workspacebindings.md | 90 +---- .agent/naming-audit/workspacesettings.md | 231 +++++------- AGENTS.md | 5 +- 98 files changed, 2522 insertions(+), 5966 deletions(-) diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index 9535acb8..a10b097b 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,10 +1,10 @@ # Cross-Package Naming Audit — Executive Summary **Packages audited:** 98 (every API package under `packages//src//`) -**Total findings across all audits:** **5,001** (down from 5,322; **321 findings pruned**) +**Total findings across all audits:** **4,502** (down from 5,322 originally, then 5,001 after the first prune pass, then 4,544 after the second; **42 additional findings pruned in this third pass**, **820 cumulative**) **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` -> **Prune note.** The original audit included a cross-cutting theme +> **Prune note 1.** The original audit included a cross-cutting theme > "Empty / trivial wrapper interfaces" (empty `*_Response` interfaces, > single-field-primitive wrapper types, and proto outer-message wrappers > retained only to anchor a nested enum). Per user direction these have @@ -15,6 +15,30 @@ > primitive. The 321 pruned findings are reflected in the totals, > theme list, and Top-50 below. +> **Prune note 2.** A second cross-cutting theme, +> "`marshal` / `unmarshal` / `Schema` suffix vocabulary is Go-isms" +> (`marshalCreatePolicySchema`, `unmarshalGetMetastoreSummary_ResponseSchema`, +> etc.), has now also been pruned per user direction. These Zod +> encoder/decoder helpers are SDK-internal — they are emitted into +> per-package `utils.ts` and `model.ts` but are not part of the public +> contract that callers import against. Renaming them carries zero +> external risk and is therefore not a public-surface naming concern. +> The 457 pruned findings from this pass are reflected in the totals, +> theme list (Theme 8 removed), generator recommendations (§8.7 +> removed), and by-the-numbers table below. + +> **Prune note 3.** A third cross-cutting theme, +> "Pagination `Iter` suffix on every paginating method" +> (`listPoliciesIter`, `listCatalogsIter`, `listWarehousesIter`, etc.), +> has now been promoted to a generator-only recommendation per user +> direction. The duplicate-method pattern is emitted by every generated +> package; the fix is one template change, not per-package work. Rather +> than carry the same finding in 98 per-package audits, the rule is +> recorded once in the new `## Generator-only recommendations` section +> below. The 42 pruned findings from this pass are reflected in the +> totals, theme list (the former Theme 8 removed), generator +> recommendations (§8.10 removed), and by-the-numbers table below. + This document synthesises the per-package audits into the patterns that the upstream generator (and a smaller number of API team decisions) should fix to deliver an idiomatic TypeScript SDK. The vast majority of the findings are @@ -206,44 +230,6 @@ generator-wide. The two consistent options are: The choice matters less than the consistency; today the SDK has both. -### Theme 8. `marshal` / `unmarshal` / `Schema` suffix vocabulary is Go-isms — ~90/98 packages - -Every package exports `marshal*Schema` / `unmarshal*Schema` Zod helpers -(`unmarshalPolicySchema`, `marshalCreatePolicySchema`, etc.). The TS -ecosystem uses `serialize`/`deserialize` or `encode`/`decode`, and the -`Schema` suffix is redundant with the `z.ZodType<>` type annotation. The -`unmarshalGetMetastoreSummary_ResponseSchema`-style identifiers can reach -50+ characters. - -Examples: -- `unmarshalGetAssignableRolesForResourceResponseSchema` (52 chars) — `packages/accountaccesscontrolproxy/src/v1/model.ts:113`. -- `unmarshalCreateServicePrincipalSecretResponseSchema` (50 chars). -- Every `parseResponse` / `marshalRequest` pair in `utils.ts` uses - asymmetric verbs (`parse` vs `marshal`). - -**Generator fix:** Rename `marshal*Schema` → `encode*` (or `serialize*`), -`unmarshal*Schema` → `decode*` (or `deserialize*`), and drop the redundant -`Schema` suffix. These are SDK-internal helpers — renaming has zero -external risk. - -### Theme 9. Pagination `Iter` suffix on every paginating method — ~57/98 packages - -Every paginating list method is emitted twice: `list*()` returning the -first page, plus `list*Iter()` returning an `AsyncIterator`. The `Iter` -suffix is a Go-ism (`ListPoliciesIter` in Go = `for it.Next() {...}`). -TypeScript ecosystems either: -- Make the list method itself return an `AsyncIterable` (Octokit, Azure - SDK), or -- Expose `.list()` and `.listAll()` (AWS SDK v3). - -Examples: every package with a list endpoint — `listPoliciesIter`, -`listCatalogsIter`, `listWarehousesIter`, `listEndpointsIter`, etc. The -duplicate methods double the method-count noise in `client.ts`. - -**Generator fix:** Pick one pagination shape. The most TS-native option is -to have `list*()` return `AsyncIterable` and add a `.firstPage()` -escape hatch for callers who need the raw response page. - --- ## 2. Cross-package duplication & overlap @@ -653,104 +639,104 @@ generator pattern it exemplifies. | # | Package | Findings | Top theme | |---|---|---|---| -| 1 | jobs | 194 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes | -| 2 | warehouses | 124 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | -| 3 | endpoints | 118 | `Endpoint*` (vector search) vs `endpoints` (other products); brand-name collision | -| 4 | settings | 111 | Cross-package duplication with `accountsettings`/`workspacesettings`/`workspaceconf` | -| 5 | catalogs | 97 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | -| 6 | postgres | 92 | 18 underscore type names; quad-nested `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` | -| 7 | pipelines | 92 | `Update` noun = pipeline run; `Pipelines*` prefix on every type | -| 8 | schemas | 89 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | -| 9 | budgets | 89 | Budget vs `budgetpolicy` duplication | -| 10 | metastores | 87 | `Get*Summary_Response` underscores; structural duplicate of `MetastoreInfo` | -| 11 | clusters | 87 | `ClusterState_ClusterState`; per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | -| 12 | functions | 86 | `function` reserved-word; proto-nested `FunctionInfo_*`; `fullNameArg` | -| 13 | forecasting | 80 | `Forecasting*` prefix; underscored type names | -| 14 | cleanroomassets | 80 | 18 underscore identifiers; `CleanRoom*` re-prefix on every type | -| 15 | clusterlibraries | 79 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 16 | apps | 78 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | -| 17 | genie | 73 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | -| 18 | instancepools | 68 | Massive structural duplication of `Create*`/`Edit*`/`*_Response`/`*AndStats` | -| 19 | instanceprofiles | 67 | Bare verb request types; vague identifiers | -| 20 | tables | 66 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 21 | policyfamilies | 65 | "Family" + "Policy Family" mixed; underscored enums | -| 22 | modelregistry | 65 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | -| 23 | marketplaces | 65 | 14× `_Response` proto underscores | -| 24 | iam | 65 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | -| 25 | globalinitscripts | 65 | Verb-as-noun requests; proto `_Response` wrappers | -| 26 | experiments | 63 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | -| 27 | externallocations | 62 | `IsolationMode_*`/`SseEncryptionAlgorithm_*` enum prefixing; cross-cloud queue type naming inconsistency | -| 28 | cleanrooms | 60 | 4-level proto nesting; redundant enum prefixes throughout | -| 29 | clusterpolicies | 57 | Underscore types; verb-as-noun requests | -| 30 | workspacesettings | 56 | Cross-package duplicates with `settings`/`accountsettings`/`workspaceconf` | -| 31 | database | 56 | Package name overlaps `postgres`; deep proto nesting | -| 32 | files | 54 | `Read`/`Move`/`Put`/`Delete`/`Close`/`Create`/`MkDirs`/`AddBlock` — verb-as-noun (legacy DBFS) | -| 33 | modelservingmanagement | 53 | `InferenceEndpoint` vs `ServingEndpoint` vs `serving-endpoints` URL — three names | -| 34 | credentials | 53 | 4× duplicate type pairs (`Credential*` vs `StorageCredential*`); cross-package with `auth/credentials` | -| 35 | qualitymonitors | 52 | Plural vs singular `qualitymonitor`; both deprecated | -| 36 | dataquality | 52 | `ListMonitorRequest` singular for list of monitors | -| 37 | registeredmodels | 51 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | -| 38 | features | 50 | Three sibling feature packages with blurry boundaries | -| 39 | supervisoragents | 49 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | -| 40 | workspacebindings | 47 | Bare verb requests; underscore identifiers | -| 41 | statementexecution | 47 | Package name overlaps `queryexecution`/`commandexecution`/`queries` | -| 42 | queryhistory | 47 | Vague `Query` types; cross-package overlap with `queries`/`queryexecution` | -| 43 | qualitymonitor | 47 | Sibling-package collision with `qualitymonitors` | -| 44 | rfa | 46 | 3-letter cryptic package name | -| 45 | connections | 46 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 46 | grants | 45 | Verb-phrase request types; underscore identifiers | -| 47 | lakeview | 43 | Old codename (rebrand to "AI/BI Dashboards") | -| 48 | indexes | 43 | Package name not "vector search"; `MiniVectorIndex` duplicates `VectorIndex` | -| 49 | commandexecution | 43 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | -| 50 | accountsettings | 43 | `Csp`/`Esm`/`Llm`/`Dcp` cryptic acronyms; generic `value` discriminator | -| 51 | knowledgeassistants | 42 | `KnowledgeAssistant_State` underscore identifier | -| 52 | usagepolicy | 41 | 1:1 clone of `budgetpolicy` | -| 53 | repos | 41 | "Repos" legacy term; product is "Git folders" | -| 54 | onlinetables | 41 | `ProvisioningInfo_State`; underscore identifiers | -| 55 | materializedfeatures | 41 | Package name doesn't match contents | -| 56 | permissions | 40 | Cross-package overlap with `iam`/`accountaccesscontrol`/`grants` | -| 57 | externalmetadata | 40 | `SystemType.*_UNSPECIFIED`; brand-value casing (`POWER_BI`, `STREAM_NATIVE`) | -| 58 | abacpolicies | 40 | `PolicyInfo`; `_Response` underscores; verb-as-noun requests | -| 59 | secrets | 39 | 11/13 types with proto underscore; mutation-verb inconsistency | -| 60 | queries | 39 | Three-package overlap with `queryhistory`/`queryexecution` | -| 61 | featurestore | 39 | `OnlineStore_State` underscore identifier | -| 62 | bundle | 39 | Generic package name (`bundle`); verb-as-noun requests | -| 63 | budgetpolicy | 38 | Sibling clone in `usagepolicy` | -| 64 | tagpolicies | 37 | Three sibling tag packages with overlapping vocab | -| 65 | entitytagassignments | 37 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 66 | workspaceassignment | 36 | Cross-package overlap with `iam` | -| 67 | tokenmanagement | 36 | Overlap with `tokens`; duplicate `AutoscopeState` enum | -| 68 | queryexecution | 36 | Package name far broader than scope (dashboards-only) | -| 69 | logdeliveryconfigurations | 36 | Long verbose names | -| 70 | customllms | 36 | `Llm` casing throughout | -| 71 | alerts | 36 | Mixed v1/v2 | -| 72 | tokens | 35 | Cross-package duplicate of `tokenmanagement` | -| 73 | tagassignments | 35 | Three-package tag split; sibling field-name drift | -| 74 | modelservingquery | 34 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | -| 75 | environments | 34 | `Environment` generic name | -| 76 | serviceprincipalsecrets | 33 | Identical to `serviceprincipalsecretsproxy` | -| 77 | serviceprincipalsecretsproxy | 33 | Byte-identical to non-proxy version | -| 78 | workspace | 32 | Most overloaded of 5 `workspace*` packages | -| 79 | secretsuc | 32 | `uc` cryptic suffix; collides with `secrets` | -| 80 | modelservingdebug | 32 | Tiny package, mostly proto underscores | -| 81 | disasterrecovery | 32 | `FailoverFailoverGroupRequest` stutter | -| 82 | gitcredentials | 31 | Three "Credentials" packages with different meanings | -| 83 | externallineage | 31 | `Direction_LineageDirection` underscore; `tpe` typo | -| 84 | dataclassification | 29 | Tag-domain overlap | -| 85 | accountaccesscontrolproxy | 29 | 1:1 surface duplicate of `accountaccesscontrol` | -| 86 | systemschemas | 27 | Sibling-package collision with `schemas` | -| 87 | volumes | 26 | `fullNameArg`; verb-as-noun requests | -| 88 | usagedashboards | 26 | Vague type names | -| 89 | notificationdestinations | 26 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 90 | resourcequotas | 25 | Underscore identifiers | -| 91 | cleanroomtaskruns | 24 | `LifeCycle` casing; one of four cleanroom packages | -| 92 | workspaceconf | 23 | `conf` cryptic abbreviation; wire-shape regression | -| 93 | billableusagedownload | 21 | Verb in package name (`download`) | -| 94 | artifactallowlists | 20 | Vague type names | -| 95 | oauthpublishedapp | 19 | Singular but only `list*` endpoints | -| 96 | cleanroomautoapprovalrules | 19 | 26-char package name; `CleanRoomAutoApprovalRule` re-prefix | -| 97 | oauthcustomappintegration | 18 | Package covers Custom AND Published despite name | -| 98 | accountaccesscontrol | 18 | Sibling duplicate `accountaccesscontrolproxy` | +| 1 | jobs | 193 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes | +| 2 | warehouses | 119 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 3 | endpoints | 114 | `Endpoint*` (vector search) vs `endpoints` (other products); brand-name collision | +| 4 | settings | 106 | Cross-package duplication with `accountsettings`/`workspacesettings`/`workspaceconf` | +| 5 | pipelines | 92 | `Update` noun = pipeline run; `Pipelines*` prefix on every type | +| 6 | postgres | 90 | 18 underscore type names; quad-nested `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` | +| 7 | clusters | 84 | `ClusterState_ClusterState`; per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | +| 8 | catalogs | 84 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | +| 9 | budgets | 84 | Budget vs `budgetpolicy` duplication | +| 10 | functions | 75 | `function` reserved-word; proto-nested `FunctionInfo_*`; `fullNameArg` | +| 11 | forecasting | 73 | `Forecasting*` prefix; underscored type names | +| 12 | genie | 72 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 13 | clusterlibraries | 72 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 14 | apps | 72 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | +| 15 | cleanroomassets | 71 | 18 underscore identifiers; `CleanRoom*` re-prefix on every type | +| 16 | schemas | 68 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | +| 17 | tables | 63 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 18 | metastores | 62 | `Get*Summary_Response` underscores; structural duplicate of `MetastoreInfo` | +| 19 | marketplaces | 62 | 14× `_Response` proto underscores | +| 20 | modelregistry | 61 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | +| 21 | iam | 61 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | +| 22 | instancepools | 59 | Massive structural duplication of `Create*`/`Edit*`/`*_Response`/`*AndStats` | +| 23 | instanceprofiles | 58 | Bare verb request types; vague identifiers | +| 24 | externallocations | 57 | `IsolationMode_*`/`SseEncryptionAlgorithm_*` enum prefixing; cross-cloud queue type naming inconsistency | +| 25 | experiments | 55 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 26 | database | 53 | Package name overlaps `postgres`; deep proto nesting | +| 27 | features | 52 | Three sibling feature packages with blurry boundaries | +| 28 | workspacesettings | 51 | Cross-package duplicates with `settings`/`accountsettings`/`workspaceconf` | +| 29 | credentials | 51 | 4× duplicate type pairs (`Credential*` vs `StorageCredential*`); cross-package with `auth/credentials` | +| 30 | clusterpolicies | 51 | Underscore types; verb-as-noun requests | +| 31 | statementexecution | 50 | Package name overlaps `queryexecution`/`commandexecution`/`queries` | +| 32 | qualitymonitors | 50 | Plural vs singular `qualitymonitor`; both deprecated | +| 33 | globalinitscripts | 50 | Verb-as-noun requests; proto `_Response` wrappers | +| 34 | files | 49 | `Read`/`Move`/`Put`/`Delete`/`Close`/`Create`/`MkDirs`/`AddBlock` — verb-as-noun (legacy DBFS) | +| 35 | cleanrooms | 49 | 4-level proto nesting; redundant enum prefixes throughout | +| 36 | queryhistory | 47 | Vague `Query` types; cross-package overlap with `queries`/`queryexecution` | +| 37 | modelservingmanagement | 47 | `InferenceEndpoint` vs `ServingEndpoint` vs `serving-endpoints` URL — three names | +| 38 | policyfamilies | 44 | "Family" + "Policy Family" mixed; underscored enums | +| 39 | dataquality | 44 | `ListMonitorRequest` singular for list of monitors | +| 40 | supervisoragents | 43 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 41 | registeredmodels | 43 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | +| 42 | accountsettings | 43 | `Csp`/`Esm`/`Llm`/`Dcp` cryptic acronyms; generic `value` discriminator | +| 43 | qualitymonitor | 42 | Sibling-package collision with `qualitymonitors` | +| 44 | lakeview | 42 | Old codename (rebrand to "AI/BI Dashboards") | +| 45 | rfa | 41 | 3-letter cryptic package name | +| 46 | connections | 41 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 47 | commandexecution | 41 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | +| 48 | repos | 40 | "Repos" legacy term; product is "Git folders" | +| 49 | knowledgeassistants | 39 | `KnowledgeAssistant_State` underscore identifier | +| 50 | abacpolicies | 39 | `PolicyInfo`; `_Response` underscores; verb-as-noun requests | +| 51 | usagepolicy | 38 | 1:1 clone of `budgetpolicy` | +| 52 | queries | 38 | Three-package overlap with `queryhistory`/`queryexecution` | +| 53 | onlinetables | 38 | `ProvisioningInfo_State`; underscore identifiers | +| 54 | indexes | 38 | Package name not "vector search"; `MiniVectorIndex` duplicates `VectorIndex` | +| 55 | workspacebindings | 37 | Bare verb requests; underscore identifiers | +| 56 | externalmetadata | 37 | `SystemType.*_UNSPECIFIED`; brand-value casing (`POWER_BI`, `STREAM_NATIVE`) | +| 57 | secrets | 36 | 11/13 types with proto underscore; mutation-verb inconsistency | +| 58 | bundle | 36 | Generic package name (`bundle`); verb-as-noun requests | +| 59 | alerts | 35 | Mixed v1/v2 | +| 60 | permissions | 34 | Cross-package overlap with `iam`/`accountaccesscontrol`/`grants` | +| 61 | logdeliveryconfigurations | 34 | Long verbose names | +| 62 | grants | 34 | Verb-phrase request types; underscore identifiers | +| 63 | modelservingquery | 33 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 64 | materializedfeatures | 33 | Package name doesn't match contents | +| 65 | workspace | 32 | Most overloaded of 5 `workspace*` packages | +| 66 | featurestore | 32 | `OnlineStore_State` underscore identifier | +| 67 | environments | 32 | `Environment` generic name | +| 68 | customllms | 32 | `Llm` casing throughout | +| 69 | budgetpolicy | 32 | Sibling clone in `usagepolicy` | +| 70 | tokens | 31 | Cross-package duplicate of `tokenmanagement` | +| 71 | entitytagassignments | 31 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 72 | tagpolicies | 30 | Three sibling tag packages with overlapping vocab | +| 73 | queryexecution | 30 | Package name far broader than scope (dashboards-only) | +| 74 | tokenmanagement | 29 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 75 | workspaceassignment | 28 | Cross-package overlap with `iam` | +| 76 | disasterrecovery | 28 | `FailoverFailoverGroupRequest` stutter | +| 77 | tagassignments | 27 | Three-package tag split; sibling field-name drift | +| 78 | serviceprincipalsecretsproxy | 26 | Byte-identical to non-proxy version | +| 79 | serviceprincipalsecrets | 26 | Identical to `serviceprincipalsecretsproxy` | +| 80 | externallineage | 26 | `Direction_LineageDirection` underscore; `tpe` typo | +| 81 | volumes | 25 | `fullNameArg`; verb-as-noun requests | +| 82 | usagedashboards | 25 | Vague type names | +| 83 | accountaccesscontrolproxy | 25 | 1:1 surface duplicate of `accountaccesscontrol` | +| 84 | secretsuc | 24 | `uc` cryptic suffix; collides with `secrets` | +| 85 | notificationdestinations | 24 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 86 | workspaceconf | 23 | `conf` cryptic abbreviation; wire-shape regression | +| 87 | resourcequotas | 23 | Underscore identifiers | +| 88 | gitcredentials | 23 | Three "Credentials" packages with different meanings | +| 89 | modelservingdebug | 22 | Tiny package, mostly proto underscores | +| 90 | systemschemas | 21 | Sibling-package collision with `schemas` | +| 91 | dataclassification | 21 | Tag-domain overlap | +| 92 | billableusagedownload | 20 | Verb in package name (`download`) | +| 93 | cleanroomautoapprovalrules | 19 | 26-char package name; `CleanRoomAutoApprovalRule` re-prefix | +| 94 | cleanroomtaskruns | 18 | `LifeCycle` casing; one of four cleanroom packages | +| 95 | artifactallowlists | 18 | Vague type names | +| 96 | oauthcustomappintegration | 17 | Package covers Custom AND Published despite name | +| 97 | oauthpublishedapp | 16 | Singular but only `list*` endpoints | +| 98 | accountaccesscontrol | 16 | Sibling duplicate `accountaccesscontrolproxy` | --- @@ -810,13 +796,7 @@ field names (`webhookUrl` vs `webhookURL`), enum values (`URL` vs `Url` — the latter avoids JS-global collision). Affects 98/98 packages. -### 8.7 Replace `marshal`/`unmarshal`/`Schema` vocabulary - -Emit `encode*` / `decode*` (or `serialize*` / `deserialize*`) and drop the -`Schema` suffix on Zod helpers. Pair `parseResponse` with `serializeRequest` -in `utils.ts` for symmetry. Affects ~90/98 packages. - -### 8.8 Rename `Client` per package +### 8.7 Rename `Client` per package Every package exports a class literally named `Client`. Imagine a user with `jobs`, `clusters`, `pipelines` all importing `Client`. Rename to @@ -824,7 +804,7 @@ with `jobs`, `clusters`, `pipelines` all importing `Client`. Rename to `WarehousesClient`. Removes the most common cross-package alias-on-import pattern. Affects 98/98 packages. -### 8.9 Strip the package-name prefix from type names +### 8.8 Strip the package-name prefix from type names When a type name begins with the package's domain noun and the unprefixed name does not clash with another type in the same package, drop the @@ -832,7 +812,7 @@ prefix. `Pipelines*` → drop, `Genie*` → drop, `CleanRoom*` → drop, `OAuthAppIntegration*` → drop where unambiguous, `Tag*` → drop in single-domain packages. Affects ~70/98 packages. -### 8.10 (Bonus) Surface deprecations as `@deprecated` JSDoc tags +### 8.9 (Bonus) Surface deprecations as `@deprecated` JSDoc tags Today the audits found dozens of fields whose JSDoc text says "deprecated" in prose but does not carry the `@deprecated` tag, so IDEs do not strike @@ -842,11 +822,33 @@ in `qualitymonitor`/`qualitymonitors`. A simple template change — when the proto description starts with "Deprecated", emit `@deprecated` — catches all of them. -### 8.11 (Bonus) Adopt `AsyncIterable` for pagination +--- -Make `list*()` return `AsyncIterable` and add `.firstPage()` for callers -who need raw pages. Removes 60+ `*Iter` companion methods. Affects ~57/98 -packages. +## 9. Generator-only recommendations + +The following recommendations are template-level fixes that the +generator emits identically across every package. Rather than carry the +same finding in 98 per-package audits, each rule is recorded once here. +Each item names the rule, why it is generator-only, the approximate +package count it appeared in before promotion, and an illustrative +example. + +### 9.1 Drop the duplicate `list*Iter()` paginator method + +**Rule:** Drop the duplicate `list*Iter()` paginator method. Make +`list*()` return `AsyncIterable` natively and add a `.firstPage()` +escape hatch for callers who need the raw page response. Modeled on +Octokit, Azure SDK, AWS SDK v3. + +**Why it's generator-only:** The duplicate-method pattern is emitted by +every generated package; the fix is one template change, not per-package +work. + +**Approximate package count where it appeared before pruning:** ~57/98 +packages (every package that has a paginating list endpoint). + +**Illustrative example:** `listCatalogsIter` in `catalogs/v1/client.ts` +(and parallel methods in `endpoints`, `warehouses`, `jobs`, etc.). --- diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index 54446ab5..bd67e14d 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -3,14 +3,14 @@ **Path:** `packages/abacpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter, column-mask, deny, and grant policies. -**Total weird names flagged:** 40 +**Total weird names flagged:** 39 ## Summary | Severity | Count | | --- | --- | | High | 11 | | Medium | 17 | -| Low | 8 | +| Low | 7 | | Observation | 4 | ## High severity @@ -217,19 +217,13 @@ - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 34. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry, or `parseResponse` / `serializeRequest`. -- **Rationale:** Pair-wise consistency aids reading. - -### 35. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 34. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). - **Rationale:** Names should differ in more than the `Http` infix. -### 36. `HttpCallOptions` — `src/v1/utils.ts:15` +### 35. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused throughout the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, `RowFilterOptions`, ...). Within this file there's also `Options` imported from `@databricks/sdk-core/api` (line 3). - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of args). @@ -237,17 +231,17 @@ ## Observations -### 37. Wire/TS divergence is heavy +### 36. Wire/TS divergence is heavy The model file is ~796 lines for ~15 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. -### 38. Action-verb conventions in `Client` +### 37. Action-verb conventions in `Client` The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) -### 39. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` +### 38. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` The codebase uses `Http` (`HttpClient`, `HttpRequest`, `executeHttpCall`) and `URLSearchParams` (Web standard) and `url` (lowercase) and `userAgent`. Mixing `Http` (PascalCase capital-then-lower) with the imported `URLSearchParams` (ALLCAPS) is inconsistent — common across JS ecosystem and probably not worth changing, but worth noting. - **Category:** 3 (acronym casing). -### 40. `abac` abbreviation only appears in package name +### 39. `abac` abbreviation only appears in package name The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. Comments on `useSessionIdentity` (model.ts:286) mention "ABAC" once. May confuse users searching by acronym. - **Category:** 5 (cryptic abbreviation in package name). diff --git a/.agent/naming-audit/accountaccesscontrol.md b/.agent/naming-audit/accountaccesscontrol.md index 0c3e6efd..06c7275e 100644 --- a/.agent/naming-audit/accountaccesscontrol.md +++ b/.agent/naming-audit/accountaccesscontrol.md @@ -3,15 +3,15 @@ **Path:** `packages/accountaccesscontrol/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Databricks IAM rule sets — list assignable roles for a resource and read/replace the grant rules attached to that resource. -**Total weird names flagged:** 18 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | | High | 3 | | Medium | 7 | -| Low | 5 | -| Observation | 3 | +| Low | 4 | +| Observation | 2 | ## High severity @@ -85,25 +85,19 @@ - **Suggested name:** Confirm the project-wide policy. If the codebase uses `eTag` elsewhere, align here. - **Rationale:** Defer to global policy. -### 12. `accountId` vs `account_id` snake-case duality — `src/v1/model.ts:7` -- **Why weird:** The TS interface uses `accountId`, but the marshal/unmarshal transforms (line 181) convert to `account_id`. This is intentional and standard for a generated SDK; flagging only because it means the public surface is camelCase but logs and wire bodies are snake_case. Nothing to do. -- **Category:** 14 (Go/Java-style name parallel) -- **Suggested name:** None — this is correct. -- **Rationale:** Documenting the convention. - -### 13. `GetRuleSetRequest.name` ambiguity with `RuleSet.name` — `src/v1/model.ts:38` +### 12. `GetRuleSetRequest.name` ambiguity with `RuleSet.name` — `src/v1/model.ts:38` - **Why weird:** A request type and a response type both have a `name` field with subtly different semantics: the request `name` is the *lookup key* the caller supplies; the response `name` is the *canonical name* the server returns. Same word, two roles. Common pattern, but worth flagging. - **Category:** 1 (vague) - **Suggested name:** Acceptable, but consider `GetRuleSetRequest.resourceName` for clarity. - **Rationale:** Minor readability win. -### 14. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +### 13. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` - **Why weird:** This helper is `export`ed from `utils.ts`. It is not used by `client.ts` and is not re-exported from `index.ts`. Either it is dead code or the export modifier is wrong. - **Category:** 11 (effectively trivial / dead) - **Suggested name:** Drop the `export` keyword if internal-only; if it is meant for other generated clients, move it to a shared core package. - **Rationale:** Hygiene. -### 15. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` +### 14. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` - **Why weird:** The package imports `CallOptions` from `@databricks/sdk-options/call` and defines its own `HttpCallOptions` here. The names suggest the latter is a subtype/extension of the former, but they actually describe different concerns — `CallOptions` is retry/signal/timeout policy; `HttpCallOptions` is request + client + logger bundle. The naming makes them look related. - **Category:** 1 (vague/generic) - **Suggested name:** `HttpExecutionContext` or `HttpCallContext`. @@ -117,9 +111,6 @@ ### O2. `executeCall` / `executeHttpCall` naming — `src/v1/utils.ts:26,65` - Two functions with overlapping names. `executeCall` is the public-CallOptions translator; `executeHttpCall` is the wire-level request executor. The names do not signal that `executeCall` wraps the `Call` callback (which itself wraps `executeHttpCall`). Could be `applyCallOptions` and `sendHttpRequest` respectively. Generated code; flag for upstream. -### O3. `parseResponse` / `marshalRequest` asymmetry — `src/v1/utils.ts:113,119` -- The pair are conceptual inverses (decode wire → typed; encode typed → wire) but use different verbs. `parseResponse`/`serializeRequest` or `unmarshalResponse`/`marshalRequest` would pair better. Generated code. - ## Domain glossary - `accountId` — Databricks account UUID (the top-level tenant container, distinct from a workspace). - `etag` — HTTP entity tag used here both as a freshness floor on GET and as an optimistic concurrency token on PUT. diff --git a/.agent/naming-audit/accountaccesscontrolproxy.md b/.agent/naming-audit/accountaccesscontrolproxy.md index 9f230b20..1a287aa1 100644 --- a/.agent/naming-audit/accountaccesscontrolproxy.md +++ b/.agent/naming-audit/accountaccesscontrolproxy.md @@ -6,7 +6,7 @@ to principals (users, groups, service principals, tag policies), exposed as a "proxy" variant whose surface area is indistinguishable from the sibling `accountaccesscontrol` package. -**Total weird names flagged:** 29 +**Total weird names flagged:** 25 --- @@ -28,21 +28,17 @@ to principals (users, groups, service principals, tag policies), exposed as a | 12 | `RuleSet` | model.ts:73 | interface | High | 12 Duplicate concepts | Has identical shape to `RuleSetUpdateRequest` (model.ts:89): `name`, `etag`, `grantRules`. One of them is redundant. | | 13 | `RuleSet.name` | model.ts:75 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning | Same problem as #6 — this is a fully-qualified path, not a human-readable name. Rename to `ruleSetName` or `resourceName`. | | 14 | `RuleSet.etag` | model.ts:85 | field | Low | 3 Acronym casing inconsistencies | Same `etag` vs `ETag` (RFC 7232) issue as #7. | -| 15 | `RuleSet.grantRules` | model.ts:86 | field | Low | 9 Singular/plural mismatches | Plural is correct, but the wire form is `grant_rules` (model.ts:144) — underscore vs camelCase split is a real coupling point. Worth checking that the marshal/unmarshal pair is the only place that needs to know. | +| 15 | `RuleSet.grantRules` | model.ts:86 | field | Low | 9 Singular/plural mismatches | Plural is correct, but the wire form is `grant_rules` (model.ts:144) — underscore vs camelCase split is a real coupling point worth verifying is centralized. | | 16 | `RuleSetUpdateRequest` | model.ts:89 | interface | High | 12 Duplicate concepts, 13 Verb-tense inconsistency | Same fields as `RuleSet`. The "UpdateRequest" suffix collides naming with the outer `UpdateRuleSetRequest` (model.ts:105), giving two overlapping `*UpdateRequest`/`Update*Request` shapes for the same operation. | | 17 | `RuleSetUpdateRequest` vs `UpdateRuleSetRequest` | model.ts:89, 105 | interface pair | High | 13 Verb-tense inconsistency, 12 Duplicate concepts | Two side-by-side request types whose names invert noun/verb order (`RuleSetUpdateRequest` vs `UpdateRuleSetRequest`). Inevitable confusion; one is the outer envelope (`{accountId, name, ruleSet}`), the other is the inner payload. Inner should be named `RuleSetPayload`, `RuleSetSpec`, or merged with `RuleSet`. | | 18 | `UpdateRuleSetRequest.name` | model.ts:109 | field | High | 12 Duplicate concepts | `name` appears at the outer level AND inside `ruleSet.name`. Which one wins? The Go-style nesting is preserved verbatim, but a TS consumer has to guess. | | 19 | `UpdateRuleSetRequest.ruleSet` | model.ts:110 | field | Low | 7 Overly verbose | Outer envelope wraps a `ruleSet: RuleSetUpdateRequest`. Could be flattened. | -| 20 | `unmarshalGetAssignableRolesForResourceResponseSchema` | model.ts:113 | const | Medium | 7 Overly verbose | 50-char identifier. Generator should drop `Schema` (tautology with `z.ZodType`) or fold into `Codec` namespace. | -| 21 | `unmarshalRoleSchema`, `unmarshalRuleSetSchema`, `unmarshalGrantRuleSchema` | model.ts:122, 132, 140 | const | Low | 20 Type-suffix tautology | The `Schema` suffix is redundant with the `z.ZodType<...>` annotation. `unmarshalRole`/`roleDecoder` would be cleaner. | -| 22 | `marshalGrantRuleSchema`, `marshalRuleSetUpdateRequestSchema`, `marshalUpdateRuleSetRequestSchema` | model.ts:152, 162, 174 | const | Low | 20 Type-suffix tautology, 17 Inconsistent action verbs | Same as #21. Also: pairing is `marshal*` / `unmarshal*` (Go-idiom). TS convention would be `encode*` / `decode*` or `serialize*` / `deserialize*`. | -| 23 | `Client` | client.ts:39 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier; once imported into a consumer that uses multiple Databricks clients, every one is just `Client`. Should be `AccessControlProxyClient` or aliased on export. | -| 24 | `Client.getAssignableRolesForResource` | client.ts:72 | method | Medium | 7 Overly verbose | "ForResource" is implicit (only one parameter is the resource); `getAssignableRoles(req)` reads cleanly. | -| 25 | `HttpCallOptions` | utils.ts:15 | interface | Low | 1 Vague/generic without domain context | Bundle of `{request, httpClient, logger}` named generically. Inside a single file this is fine; if it ever leaks out, `ExecuteHttpCallParams` would self-document. | -| 26 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions in the same file with overlapping vocabulary. `executeCall` (orchestrates retries/timeouts) and `executeHttpCall` (does one HTTP roundtrip) are two different concepts — name them so. e.g. `runWithOptions` / `sendRequest`. | -| 27 | `parseResponse` | utils.ts:113 | function | Low | 17 Inconsistent action verbs | Naming pair is `parseResponse` (decode) and `marshalRequest` (encode). Either `parse`/`format` or `marshal`/`unmarshal`, not a mix. | -| 28 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 21 Dead code | Exported from `utils.ts` but never imported in `client.ts`. Either dead code or for future generated calls. | -| 29 | `PACKAGE_SEGMENT` | client.ts:34 | const | Low | 1 Vague/generic without domain context | Could be `USER_AGENT_PACKAGE_SEGMENT` to clarify what "segment" means at the call site. | +| 20 | `Client` | client.ts:39 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier; once imported into a consumer that uses multiple Databricks clients, every one is just `Client`. Should be `AccessControlProxyClient` or aliased on export. | +| 21 | `Client.getAssignableRolesForResource` | client.ts:72 | method | Medium | 7 Overly verbose | "ForResource" is implicit (only one parameter is the resource); `getAssignableRoles(req)` reads cleanly. | +| 22 | `HttpCallOptions` | utils.ts:15 | interface | Low | 1 Vague/generic without domain context | Bundle of `{request, httpClient, logger}` named generically. Inside a single file this is fine; if it ever leaks out, `ExecuteHttpCallParams` would self-document. | +| 23 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions in the same file with overlapping vocabulary. `executeCall` (orchestrates retries/timeouts) and `executeHttpCall` (does one HTTP roundtrip) are two different concepts — name them so. e.g. `runWithOptions` / `sendRequest`. | +| 24 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 21 Dead code | Exported from `utils.ts` but never imported in `client.ts`. Either dead code or for future generated calls. | +| 25 | `PACKAGE_SEGMENT` | client.ts:34 | const | Low | 1 Vague/generic without domain context | Could be `USER_AGENT_PACKAGE_SEGMENT` to clarify what "segment" means at the call site. | --- @@ -162,44 +158,27 @@ The wire and field name is `etag` (lowercase). The JSDoc in the same comment block uses `eTag`, `Etag`, and `ETag` interchangeably. RFC 7232 §2.3 defines the header as `ETag`. Pick one. -### L2. `Schema` suffix tautology - -`unmarshalRoleSchema: z.ZodType` — the `Schema` suffix duplicates the -type annotation. Pattern is consistent across the SDK, so this is a -generator-wide concern, not unique to this package. - -### L3. `marshal`/`unmarshal` are Go-idioms - -JS/TS conventions are `JSON.stringify`/`JSON.parse`, `encode`/`decode`, or -`serialize`/`deserialize`. `marshal`/`unmarshal` is a Go transliteration. (Go -SDK `encoding/json` uses `Marshal`/`Unmarshal`. TS ecosystem does not.) - -### L4. `parseResponse` vs `marshalRequest` - -Mixing `parse`/`marshal` action verbs in the same file. Either both -`parse`/`format` or both `marshal`/`unmarshal`. - -### L5. `flattenQueryParams` is exported but never imported +### L2. `flattenQueryParams` is exported but never imported `utils.ts:123` exports `flattenQueryParams`. `client.ts` never imports it (it builds query strings inline via `URLSearchParams`). Either: - Remove it (dead code), or - Use it (current inline code reproduces a subset of its logic). -### L6. `PACKAGE_SEGMENT` +### L3. `PACKAGE_SEGMENT` Used only for the User-Agent header. Renaming to `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory: `createDefault().with(USER_AGENT_PACKAGE_SEGMENT)`. -### L7. `HttpCallOptions` +### L4. `HttpCallOptions` Internal `interface` with `{request, httpClient, logger}`. Could be inlined into `executeHttpCall` as positional parameters, or renamed `ExecuteHttpCallParams` to disambiguate from `CallOptions` (which is a public type). -### L8. `req` parameter naming in client methods +### L5. `req` parameter naming in client methods ```ts async getAssignableRolesForResource(req: GetAssignableRolesForResourceRequest, ...) diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md index d141b7d3..7f8ccfbc 100644 --- a/.agent/naming-audit/alerts.md +++ b/.agent/naming-audit/alerts.md @@ -3,7 +3,7 @@ **Path:** `packages/alerts/src/{v1,v2}/` **Versions audited:** v1, v2 **Inferred domain:** SQL/Databricks alerts: a stored configuration that periodically evaluates a query result against a threshold and notifies subscribers when it triggers. -**Total weird names flagged:** 36 +**Total weird names flagged:** 35 ## Summary table @@ -34,17 +34,16 @@ | 23 | Medium | v2 | `model.ts` field | `AlertSubscription.subscriptionType` | Type-suffix tautology | | 24 | Low | both | `model.ts` field | `pageToken` / `pageSize` / `nextPageToken` | Conventional; flagged only for completeness | | 25 | Low | both | `model.ts` field | `ListAlertsRequest`/`ListAlertsResponse` plural vs `GetAlertRequest` singular | Consistent with REST norms | -| 26 | Low | both | `client.ts` method | `listAlertsIter` | Cryptic abbreviation (`Iter`) | -| 27 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | -| 28 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | -| 29 | Low | v1 | `model.ts` field | `AlertCondition.emptyResultState` | Underspecified (state of what when empty) | -| 30 | Low | v2 | `model.ts` field | `AlertEvaluation.source` | Vague/generic | -| 31 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | -| 32 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | -| 33 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | -| 34 | Low | v2 | `model.ts` field | `Alert.parentPath` and `effectiveParentPath` | "Effective" prefix unexplained at first read | -| 35 | Low | v2 | `model.ts` field | `Alert.id`, `Alert.queryText` co-located | "id" alone underspecified at field level (docs clarify) | -| 36 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | +| 26 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | +| 27 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | +| 28 | Low | v1 | `model.ts` field | `AlertCondition.emptyResultState` | Underspecified (state of what when empty) | +| 29 | Low | v2 | `model.ts` field | `AlertEvaluation.source` | Vague/generic | +| 30 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | +| 31 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | +| 32 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | +| 33 | Low | v2 | `model.ts` field | `Alert.parentPath` and `effectiveParentPath` | "Effective" prefix unexplained at first read | +| 34 | Low | v2 | `model.ts` field | `Alert.id`, `Alert.queryText` co-located | "id" alone underspecified at field level (docs clarify) | +| 35 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | ## v1 vs v2 comparison @@ -383,17 +382,7 @@ Conventional Google AIP-158 pagination names. Flagged only because the rule list Consistent with REST norms (`GET /alerts/{id}` singular, `GET /alerts` plural). No action recommended. -### 26. `listAlertsIter` — cryptic abbreviation (both) - -**Location:** v1 `client.ts:152-167`, v2 `client.ts:150-165` - -```ts -async *listAlertsIter(...) : AsyncGenerator<...> { ... } -``` - -`Iter` for "iterator" reads as a Go/Rust port. Idiomatic TS would name this method `listAllAlerts` (or simply drop the paginated overload entirely and have callers use the async generator pattern returned from `listAlerts`). - -### 27. `Aggregation.STDDEV` — cryptic abbreviation (v2) +### 26. `Aggregation.STDDEV` — cryptic abbreviation (v2) ```ts STDDEV = 'STDDEV', @@ -401,11 +390,11 @@ STDDEV = 'STDDEV', `STANDARD_DEVIATION` or `STDEV` would be clearer; `STDDEV` is a SQL-server-ism. -### 28. `Aggregation.AVG` — cryptic abbreviation (v2) +### 27. `Aggregation.AVG` — cryptic abbreviation (v2) `AVERAGE` would be consistent with `SUM`, `COUNT`, `MEDIAN`, `MIN`, `MAX`. The mix of short and full names inside one enum is the issue. -### 29. `AlertCondition.emptyResultState` — underspecified (v1) +### 28. `AlertCondition.emptyResultState` — underspecified (v1) ```ts /** Alert state if result is empty. */ @@ -414,7 +403,7 @@ emptyResultState?: AlertState | undefined; Reads as "the empty-result state." `stateWhenEmptyResult` or `emptyResultBehavior` parses left-to-right. Minor. -### 30. `AlertEvaluation.source` — vague (v2) +### 29. `AlertEvaluation.source` — vague (v2) ```ts /** Source column from result to use to evaluate alert */ @@ -423,7 +412,7 @@ source?: AlertOperandColumn | undefined; `source` is generic; `operandColumn` (matching the type), `inputColumn`, or `column` would be clearer. -### 31. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) +### 30. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) ```ts /** Threshold to user for alert evaluation, can be a column or a value. */ @@ -434,15 +423,15 @@ The JSDoc admits the threshold can be a column — i.e., not actually a threshol Also note the typo "Threshold to user" (should be "to use") — content, not naming, but worth fixing. -### 32. `LifecycleState` — missing domain prefix (v1) +### 31. `LifecycleState` — missing domain prefix (v1) v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycleState`. -### 33. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) +### 32. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) Same data, different vocabulary. v1 = email metaphor, v2 = generic content metaphor. Users porting from v1 to v2 need a translation table. -### 34. `effectiveParentPath` / `effectiveRunAs` (v2) +### 33. `effectiveParentPath` / `effectiveRunAs` (v2) ```ts /** The actual workspace path of the folder containing the alert. This is an output-only field. */ @@ -451,11 +440,11 @@ effectiveParentPath?: string | undefined; The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. -### 35. `Alert.id` (both) +### 34. `Alert.id` (both) The name alone (`id`) is underspecified at type level — `alertId` would be clearer when constructing a request that takes both `req.id` and the alert's id. The JSDoc covers it; the field doesn't. -### 36. JSDoc verb/casing inconsistency (both) +### 35. JSDoc verb/casing inconsistency (both) **Location:** v2 `client.ts:68`, `client.ts:198` @@ -480,10 +469,6 @@ async updateAlert(...) { ... } 5. **Top-level type pollution in v2.** v2 exports `Aggregation`, `ComparisonOperator`, `CronSchedule`, `SchedulePauseStatus`, `AlertEvaluationState`, `AlertLifecycleState` plus 9 message types from a single package. Several have no `Alert` prefix and read as if they belong to a shared domain library. Prefixing them all uniformly (`AlertAggregation`, `AlertScheduleCron`, `AlertSchedulePauseStatus`) would isolate the package. -6. **`utils.ts` is identical across v1 and v2** and contains no domain names. The exported helpers (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are well-named and not flagged. (`flattenQueryParams` is exported but unused in `client.ts` — orphaned export, not a naming issue.) - -7. **`Iter` suffix.** `listAlertsIter` is the only client method whose name carries a Go/Rust-flavoured abbreviation. TS idiom would use the method name as the iterable (or `listAllAlerts`). This will surface in every generated package; flag at the generator level. - ## Domain glossary | Term | Meaning in this package | diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index 5f8f2eba..40f5b8ca 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -10,10 +10,10 @@ with deployments, custom templates, app spaces, and resource bindings. | Severity | Count | | -------- | ----- | | High | 14 | -| Medium | 28 | -| Low | 24 | -| Observation | 12 | -| **Total** | **78** | +| Medium | 26 | +| Low | 21 | +| Observation | 11 | +| **Total** | **72** | The audit found two dominant themes. First, the package leaks proto/Go conventions deep into the public surface: every nested message keeps its @@ -484,26 +484,7 @@ versus Genie Space). `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name promises nothing. -### M21. `marshalRequest`, `marshalAppSchema`, ..., `marshal` vs `unmarshal` -- **File:** `model.ts:2306, 2404, ...`, `utils.ts:119` -- **Category:** Inconsistent action verbs (17) -- **Issue:** `marshal`/`unmarshal` is gRPC-/Go-vernacular. JavaScript's - baseline vocabulary is `serialize`/`deserialize` or `toJSON`/`fromJSON`. -- **Suggestion:** Either keep the Go names (for porting consistency) or - rename across the SDK. Documenting the convention in `porting.mdc` is the - easier path. - -### M22. `parseResponse` / `marshalRequest` - inconsistent verb pairing -- **File:** `utils.ts:113, 119` -- **Category:** Inconsistent action verbs (17) -- **Issue:** Adjacent helpers use different verb conventions: `parseResponse` - (parse/serialize convention) and `marshalRequest` (marshal/unmarshal - convention). The natural pair would be `unmarshalResponse` and - `marshalRequest`, or `parseResponse` and `serializeRequest`. -- **Suggestion:** Rename `marshalRequest` -> `serializeRequest` or - `parseResponse` -> `unmarshalResponse`. - -### M23. `flattenQueryParams` — what does it flatten? +### M21. `flattenQueryParams` — what does it flatten? - **File:** `utils.ts:123` - **Category:** Vague/generic (1) - **Issue:** `flattenQueryParams(prefix, value, params)` — the function @@ -512,7 +493,7 @@ versus Genie Space). - **Suggestion:** Rename to `encodeNestedQueryParams` or `appendObjectAsQueryParams`. -### M24. `readAll` — local helper exported as `readAll` +### M22. `readAll` — local helper exported as `readAll` - **File:** `utils.ts:40` - **Category:** Vague/generic (1) - **Issue:** `readAll(body: ReadableStream | null)` — reads-all of @@ -520,7 +501,7 @@ versus Genie Space). - **Suggestion:** Rename to `readStreamToBytes` or `consumeStream`. (It's not exported, so impact is local.) -### M25. `executeCall` vs `executeHttpCall` — pair drifts in meaning +### M23. `executeCall` vs `executeHttpCall` — pair drifts in meaning - **File:** `utils.ts:26, 65` - **Category:** Inconsistent action verbs (17) - **Issue:** `executeCall` is the *outer* retry/rate-limit wrapper; @@ -530,7 +511,7 @@ versus Genie Space). would help. - **Suggestion:** Rename to `runWithRetries`/`sendHttp`, or `runCall`/`sendOne`. -### M26. `StillRunningError` — internal sentinel class, named ambiguously +### M24. `StillRunningError` — internal sentinel class, named ambiguously - **File:** `client.ts:93` - **Category:** Misleading names (6) - **Issue:** `class StillRunningError extends Error {}` — used as a sentinel @@ -539,7 +520,7 @@ versus Genie Space). - **Suggestion:** Rename to `pollAgainSentinel` (as a typed Error subclass) or `RetryablePollError`, and add a comment that it never escapes the file. -### M27. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +### M25. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too - **File:** `client.ts:121, 914` - **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) - **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, @@ -550,7 +531,7 @@ versus Genie Space). - **Suggestion:** Drop the `async` prefix from `asyncUpdateApp` to match `updateSpace`, or add `asyncUpdateSpace` for symmetry. -### M28. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +### M26. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type - **File:** `client.ts:309, 408, 951` - **Category:** Type-suffix tautology (20) - **Issue:** Methods named `createSpaceOperation()` return a @@ -621,26 +602,7 @@ versus Genie Space). - **Suggestion:** Drop or rephrase the reference to `app.proto`; in TS the reference is meaningless. -### L10. `unmarshalAppManifest_AppResourceServingEndpointSpecSchema` — extremely long Zod variable name -- **File:** `model.ts:1690, 2532` -- **Category:** Overly verbose (7) -- **Issue:** 60-character private const. Inherited from H3. -- **Suggestion:** Rename via H3. - -### L11. `unmarshalListAppsResponseSchema` etc. — verb `unmarshal` repeated -- **File:** `model.ts:2133, 2146, 2156, 2169, 2180, 2202, 2246, 2256, ...` -- **Category:** Verbosity (7) -- **Suggestion:** Group under a namespace - `unmarshal.ListAppsResponse`, `unmarshal.Operation`, etc., or shorten with - `parseListAppsResponse`. - -### L12. `appFieldMaskSchema` / `appDeploymentFieldMaskSchema` etc. — every type gets a parallel `*FieldMaskSchema` -- **File:** `model.ts:3075, 3135, 3152, 3156, 3161, 3167, 3173, 3180, 3192, 3215` -- **Category:** Verbose / repetitive -- **Suggestion:** Consider a `fieldMasks.app`, `fieldMasks.appDeployment` - namespace object rather than 10 individually named consts. - -### L13. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers +### L10. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers - **File:** `model.ts:3131, 3211` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — @@ -649,21 +611,21 @@ versus Genie Space). - **Suggestion:** Either expose helpers for every entity with a field-mask schema, or none. -### L14. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models +### L11. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models - **File:** `model.ts:783-784, 1032-1035` - **Category:** Duplicate concepts (12) - **Suggestion:** Document that `thumbnailUrl` is the display URL and `AppThumbnail.thumbnail` is the byte content (used in update/delete-thumbnail requests). -### L15. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` +### L12. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` - **File:** `model.ts:1156-1166` - **Category:** Vague/generic (1) - **Suggestion:** Discriminator `'value'` and `'valueFrom'` are short; consider `'literal'` and `'reference'` to make intent clearer. (Wire field names unchanged.) -### L16. `Space` interface — same name as the Genie product `AppResourceGenieSpace` +### L13. `Space` interface — same name as the Genie product `AppResourceGenieSpace` - **File:** `model.ts:1357, 978-982` - **Category:** Duplicate concepts (12) - **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share @@ -675,25 +637,25 @@ versus Genie Space). is the outlier. This realignment also clarifies the wire URLs (`/api/2.0/app-spaces/...`). -### L17. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, +### L14. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, `ListSpacesRequest`, etc., do not mention "App" - **File:** `model.ts:1101, 1147, 1197, 1301`, also `index.ts:82-88, 105` - **Category:** Vague/generic (1) -- **Suggestion:** Tied to L16 — rename these to `CreateAppSpaceRequest`, etc. +- **Suggestion:** Tied to L13 — rename these to `CreateAppSpaceRequest`, etc. -### L18. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? +### L15. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? - **File:** `model.ts:1308-1312, 1282-1286` -- **Category:** Observation — both follow the same pattern. Tied to L16 again +- **Category:** Observation — both follow the same pattern. Tied to L13 again for the entity rename. -### L19. `CreateAppDeploymentRequest.autoDeploy` doc: "Whether to enable automatic deployments on push events to the git repository" +### L16. `CreateAppDeploymentRequest.autoDeploy` doc: "Whether to enable automatic deployments on push events to the git repository" - **File:** `model.ts:1086-1089` - **Category:** Misleading names (6) - **Issue:** The field name suggests "deploy automatically now". The doc says it sets up a webhook. These are very different ideas. - **Suggestion:** Rename to `enableAutoDeploy` or `webhookAutoDeploy`. -### L20. `GitRepository.autoDeploy` vs `CreateAppDeploymentRequest.autoDeploy` +### L17. `GitRepository.autoDeploy` vs `CreateAppDeploymentRequest.autoDeploy` - **File:** `model.ts:1086, 1211` - **Category:** Duplicate concepts (12) - **Issue:** Two `autoDeploy` fields in the same file: one on the deployment @@ -702,7 +664,7 @@ versus Genie Space). - **Suggestion:** Document the relationship in JSDoc; if they're the same state, only one should exist. -### L21. `Operation.name` — server-assigned UNIQUE name, not human-readable +### L18. `Operation.name` — server-assigned UNIQUE name, not human-readable - **File:** `model.ts:1319-1324` - **Category:** Misleading names (6) - **Issue:** `Operation.name` is the operation *identifier* path @@ -711,7 +673,7 @@ versus Genie Space). package. - **Suggestion:** Rename to `operationName` or, given the format, just `path`. -### L22. `Client` class — exported as bare `Client` +### L19. `Client` class — exported as bare `Client` - **File:** `client.ts:95`, also `index.ts:4` - **Category:** Vague/generic (1) - **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the @@ -719,7 +681,7 @@ versus Genie Space). `@databricks/sdk-jobs`, they need an alias. - **Suggestion:** Rename to `AppsClient`. Common SDK convention. -### L23. `host` (private field on `Client`) +### L20. `host` (private field on `Client`) - **File:** `client.ts:96` - **Category:** Vague/generic (1) - **Issue:** `private readonly host: string`. The doc on the workspace @@ -727,7 +689,7 @@ versus Genie Space). - **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, cosmetic. -### L24. `getSpaceOperation` (method) vs `GetOperationRequest` +### L21. `getSpaceOperation` (method) vs `GetOperationRequest` - **File:** `client.ts:536-558` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells @@ -760,39 +722,34 @@ visible. `AppDeployment` etc. are not. Probably intentional (only `App` and `Space` have an update endpoint that takes a mask), but worth confirming. -### O4. Every nested message has both `marshal*` and `unmarshal*` schemas -This doubles every name. If the project goal is 1:1 with Go's -`MarshalJSON`/`UnmarshalJSON`, this is correct; otherwise, a single bi-directional -`*Schema` would halve the API surface. - -### O5. Discriminated unions use `$case` — borrowed from `ts-proto` oneof +### O4. Discriminated unions use `$case` — borrowed from `ts-proto` oneof The `$case` discriminator is non-idiomatic in hand-written TS (most consumers use plain `kind: 'X'`). Documenting this in the package README would help. -### O6. `CustomTemplate` doesn't carry "App" in its name, but it's an app template +### O5. `CustomTemplate` doesn't carry "App" in its name, but it's an app template The doc and methods make this clear (`createCustomTemplate` -> `/api/2.0/apps-settings/templates`), but the type name is ambiguous. Consider `AppTemplate` or `CustomAppTemplate`. -### O7. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter +### O6. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter Asymmetry but probably intentional. -### O8. `ApplicationStatus.runningInstances` vs `ComputeStatus.activeInstances` +### O7. `ApplicationStatus.runningInstances` vs `ComputeStatus.activeInstances` Two related counts, different verbs. `runningInstances` for app process, `activeInstances` for compute resources. Document the distinction. -### O9. `ListAppsRequest.space` filters by space name (string), not by +### O8. `ListAppsRequest.space` filters by space name (string), not by `Space` object — consistent with H8 issue. -### O10. The package re-exports the `apierr` enum locally +### O9. The package re-exports the `apierr` enum locally Per H5, this enum should live in `@databricks/sdk-databricks/apierror/codes`. The project memory note already calls this out (`packages/databricks/src/apierror/codes/`). -### O11. Files use `// eslint-disable-next-line` for every Proto-style nested name +### O10. Files use `// eslint-disable-next-line` for every Proto-style nested name 60+ disables across `model.ts`. Fixing H3 eliminates the disables. -### O12. `index.ts` exports +### O11. `index.ts` exports - 18 enums - 51 type aliases - 8 named exports from `./client` (1 class + 7 wrapper classes) @@ -812,13 +769,13 @@ detail. | `AppDeployment` | A specific deployment (source-code + config snapshot) | Has its own `id`, status, lifecycle. | | `AppManifest` | Schema describing required resources for an app | Used by `CustomTemplate`. | | `AppResource` | A binding from an App to another Databricks resource | Discriminated union of 10 cases. | -| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L16. | -| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L16. | +| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L13. | +| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L13. | | `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | | `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H7. | | `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | | `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M15/M16. | -| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L14. | +| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L11. | | `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M6. | | `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | | `GitSource` | Specific commit/branch/tag + path within a `GitRepository` | Used by deployments. | diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index 9e9f85e0..1d2803f2 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -10,11 +10,11 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | -| High | 3 | +| High | 2 | | Medium | 6 | -| Low | 4 | +| Low | 3 | | Observation | 7 | -| **Total** | **20** | +| **Total** | **18** | Headline themes: @@ -67,25 +67,8 @@ Allowlist casing is **consistent** throughout the package (always API truly accepts them — clarify in the doc that the server ignores them. - **Rationale:** A request type whose name reads as a verb ("Set the allowlist") but whose fields include response-only metadata is misleading. - This causes the marshal schema (`marshalSetArtifactAllowlistSchema`, - lines 94–110) to emit `created_by`/`created_at` keys back to the server - unnecessarily. Even if the server tolerates them, exposing them on the - request shape invites misuse. - -### H3. `marshalSetArtifactAllowlistSchema` typed `z.ZodType` (no parameter) - -- **File / line:** `src/v1/model.ts:94`; `marshalArtifactMatcherSchema` at - line 84 has the same shape. -- **Category:** #15 generic field name losing meaning; #20 type-suffix - tautology (the `Schema` suffix is intentional, but the parameter - `z.ZodType` is left untyped — this is a *naming via type* issue). -- **Current:** `export const marshalSetArtifactAllowlistSchema: z.ZodType = …`. -- **Suggestion:** Parameterize to `z.ZodType` (mirror - the unmarshal sibling at line 57: `z.ZodType`). -- **Rationale:** Without a generic parameter, the symbol's name promises a - typed schema for `SetArtifactAllowlist` but its compile-time signature is - `ZodType`. Readers must trust the name. The unmarshal variant - models this correctly; the marshal variants do not. + Even if the server tolerates them, exposing them on the request shape + invites misuse. --- @@ -211,32 +194,17 @@ unique prefix style so a variable named `call` inside a method that is itself a call is ambiguous. Caveat: this is a 1:1 port of Go SDK convention. -### L3. `body` shadowed twice in `executeHttpCall` +### L3. `body` shadowed across helpers in `executeHttpCall` -- **File / line:** `src/v1/utils.ts:81` and parameter `body` of - `buildHttpRequest` (line 101) / `parseResponse` (line 113) / - `marshalRequest` (line 119 — `data`). +- **File / line:** `src/v1/utils.ts:81`, `buildHttpRequest` (line 101), + `parseResponse` (line 113). - **Category:** #1 vague generic name. - **Current:** `body: Uint8Array` (response body) vs. `body: string | ReadableStream` (request body, in `buildHttpRequest`). - **Suggestion:** `responseBody` / `requestBody`. -- **Rationale:** Within `client.ts` line 101 we already see - `const body = marshalRequest(…)` (a request body) being passed into a - function that internally also reasons about response bodies. Differentiating - with `requestBody` / `responseBody` would help readers. - -### L4. `marshalRequest` accepts `data: unknown` — the parameter name -contradicts the function's purpose - -- **File / line:** `src/v1/utils.ts:119`. -- **Category:** #15 generic field name losing meaning. -- **Current:** `function marshalRequest(data: unknown, schema: z.ZodType)`. -- **Suggestion:** `function marshalRequest(request: unknown, schema)` or - `(payload, schema)`. -- **Rationale:** The function name says "request", but the first argument - is named `data`. Calling at `client.ts:101` reads - `marshalRequest(req, marshalSetArtifactAllowlistSchema)` — `req` → - `data` loses the request semantics in the helper. +- **Rationale:** Within `client.ts` line 101 a request body flows into a + function that internally also reasons about response bodies. + Differentiating with `requestBody` / `responseBody` would help readers. --- @@ -329,10 +297,6 @@ Type & symbol checklist: - [x] `ArtifactMatcher` interface (2 fields) → M3, M4. - [x] `GetArtifactAllowlist` interface (1 field) → H1, O1. - [x] `SetArtifactAllowlist` interface (5 fields) → H2, O1. -- [x] `unmarshalArtifactAllowlistInfoSchema` → no defect. -- [x] `unmarshalArtifactMatcherSchema` → no defect. -- [x] `marshalArtifactMatcherSchema` → H3 (untyped `z.ZodType`). -- [x] `marshalSetArtifactAllowlistSchema` → H3. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → O7. - [x] `getArtifactAllowlist(req, options)` method → H1, M2, M6. @@ -342,7 +306,5 @@ Type & symbol checklist: - [x] `readAll` private function → no defect (name fits idiom). - [x] `executeHttpCall` function → L1, L3. - [x] `buildHttpRequest` function → L3. -- [x] `parseResponse` function → no defect. -- [x] `marshalRequest` function → L4. - [x] `flattenQueryParams` function → no defect. - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). diff --git a/.agent/naming-audit/billableusagedownload.md b/.agent/naming-audit/billableusagedownload.md index 3b2ce112..7df6bd63 100644 --- a/.agent/naming-audit/billableusagedownload.md +++ b/.agent/naming-audit/billableusagedownload.md @@ -3,13 +3,13 @@ **Path:** `packages/billableusagedownload/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CSV export of billable Databricks usage logs for a given month range. Single endpoint: `GET /api/2.0/accounts/{account_id}/usage/download`. No CRUD surface, no enums, no list/page semantics — just one streaming download method. -**Total weird names flagged:** 21 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | | High | 5 | -| Medium | 7 | +| Medium | 6 | | Low | 5 | | Observation | 4 | @@ -73,49 +73,43 @@ ### 10. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` - **Why weird:** `client.ts` does its own query-param construction inline (lines 70-79) using `new URLSearchParams()` and three `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called. -- **Category:** 1 (vague), 11 (unused public helper — dead surface area). +- **Category:** 11 (unused public helper — dead surface area). - **Suggested name:** Remove the export, or drop the function entirely if no caller in this package needs it. - **Rationale:** Every generated package ships this helper; in `billableusagedownload` (which has zero list/page operations and only three query params), the inline approach is clearly what the generator chose. The unused export is a generator artefact that should be pruned. -### 11. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (the inverse of `marshalRequest`) uses `parse` while the request side uses `marshal`. The verbs do not pair — they read as different layers. Neither function is used in this package; both are dead exports. -- **Category:** 17 (inconsistent action verbs), 11 (unused public helpers). -- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. Or delete both since the package has no JSON request/response (only query-string + streaming CSV). -- **Rationale:** Pair-wise consistency aids reading. More importantly, this package shouldn't ship JSON-marshalling helpers at all — it has no JSON I/O. - -### 12. `executeCall` / `executeHttpCall` near-duplicate names — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. Plus only `executeCall` is used in `client.ts:96`; `executeHttpCall` is another unused dead export (`sendAndCheckError` is used instead). -- **Category:** 1 (vague), 11 (unused export), 17 (inconsistent layer naming). -- **Suggested name:** `runWithCallOptions` / `sendHttp` — or just delete `executeHttpCall` since `sendAndCheckError` supersedes it. -- **Rationale:** `utils.ts` has *two* HTTP-send variants exported (`executeHttpCall` and `sendAndCheckError`) — the client uses only the latter, and the existence of both with subtly different return types (`Uint8Array` vs `HttpResponse`) is confusing. +### 11. `executeHttpCall` is exported but unused — `src/v1/utils.ts:65` +- **Why weird:** `utils.ts` exports both `executeHttpCall` and `sendAndCheckError`; only the latter is used in `client.ts:96`. `executeHttpCall` is dead surface area. +- **Category:** 11 (unused public helper — dead surface area). +- **Suggested name:** Remove `executeHttpCall`; the package only needs `sendAndCheckError`. +- **Rationale:** Two HTTP-send variants with subtly different return types (`Uint8Array` vs `HttpResponse`) is confusing. The unused export should be pruned. ## Low severity -### 13. `HttpCallOptions` — `src/v1/utils.ts:15` +### 12. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, ...). Within this file the imported `Options` from `@databricks/sdk-core/api` (line 3) collides with this local interface name. - **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). - **Suggested name:** `HttpCallContext` (it is not user-facing options; it is an internal bag of args). - **Rationale:** Distinguish internal context bags from user-tunable option structs. Same finding as `abacpolicies` audit #37. -### 14. `readAll` helper — `src/v1/utils.ts:40` +### 13. `readAll` helper — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Also reads the body twice in `sendAndCheckError` (lines 176-181) — once for body content, once for error parsing — though this is fine because non-2xx is handled separately. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 15. `buildHttpRequest` parameter order — `src/v1/utils.ts:96-102` +### 14. `buildHttpRequest` parameter order — `src/v1/utils.ts:96-102` - **Why weird:** `(method, url, headers, signal?, body?)` — positional 5-arg function with two optional trailing params. Calling site (`client.ts:86`) passes `('GET', fullUrl, headers, callSignal)` — fine — but a caller adding a body has to remember the order. An options object would be clearer. - **Category:** 1 (no name issue per se), Observation. - **Suggested name:** Take `{method, url, headers, signal?, body?}` as an options object. - **Rationale:** Less of a naming issue, more of an API shape concern. Not a blocker. -### 16. `req` / `resp` / `opts` / `httpReq` / `httpResp` abbreviations — `src/v1/client.ts:66,68,86,87,...` +### 15. `req` / `resp` / `opts` / `httpReq` / `httpResp` abbreviations — `src/v1/client.ts:66,68,86,87,...` - **Why weird:** Three-letter abbreviations for local variables (`req`, `resp`, `opts`). The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling out four-letter names costs nothing and improves readability. -### 17. `httpClient: HttpClient` field — `src/v1/client.ts:27` / `src/v1/utils.ts:17` +### 16. `httpClient: HttpClient` field — `src/v1/client.ts:27` / `src/v1/utils.ts:17` - **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention is widespread in this SDK. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the (different) outer `Client` class in the same file. @@ -123,18 +117,18 @@ ## Observations -### 18. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` +### 17. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` The field is typed `ReadableStream` (no type parameter) rather than `ReadableStream`. Every other use in the codebase (`packages/files/src/v1/model.ts`, `utils.ts:42`, `utils.ts:101`) uses `ReadableStream` explicitly. The unparameterised version is the global lib type which is structurally `ReadableStream`, weakening type safety for callers. - **Category:** 6 (misleading — type appears typed but is in fact `any`-typed), 17 (inconsistent across the SDK). - **Suggested name:** `contents?: ReadableStream | undefined`. -### 19. Wire/TS mapping is correct +### 18. Wire/TS mapping is correct The TS field `personalData` maps to wire `personal_data`, `startMonth` -> `start_month`, etc. The query-param construction in `client.ts:70-79` does it manually and correctly. Good — no naming bug here, just noting that no schema/codec layer is needed because this is a query-string-only request. -### 20. No enums, no list-types, no FieldMask +### 19. No enums, no list-types, no FieldMask This package is one of the simplest in the SDK: zero enums, zero list/paginated types, zero proto-nested `_Response` types. Audit-rule categories 2 (redundant enum prefix), 4 (underscore identifiers from proto nesting), 18 (long enum values), and 13 (verb tense inconsistency) do not apply here. That's why the finding count is comparatively low. -### 21. CSV body is undocumented in types +### 20. CSV body is undocumented in types `DownloadResponse.contents` is `ReadableStream` (untyped) but the JSDoc on `Client.download` (`client.ts:51-64`) makes clear the body is CSV. There is no type-level hint or branded type to mark this — a caller might treat the stream as JSON. Worth considering a documented branded type (`type CsvStream = ReadableStream & {readonly _csvBrand: unique symbol}`) or, more practically, a Content-Type assertion. Not a name problem; flagged because the response shape is uninformative. ## Domain glossary diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index bf24b519..378df61c 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,14 +3,14 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 38 +**Total weird names flagged:** 32 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 14 | -| Low | 11 | +| Medium | 11 | +| Low | 8 | | Observation | 5 | ## High severity @@ -125,112 +125,79 @@ - **Suggested name:** Fix doc. - **Rationale:** Generated; surfaces in IntelliSense. -### 19. `BudgetPolicy.customTags` plural field — `src/v1/model.ts:27` -- **Why weird:** Plural field `customTags: CustomPolicyTag[]` plus the singular type with `Tag` suffix produces `customTags: CustomPolicyTag[]` which reads with the same word twice (`Tags`/`Tag`). Compare to better naming where the field is `tags: Tag[]` (in this package, "policy tags" is self-evident). -- **Category:** 8 (redundant prefix `custom`), 20 (`customTags: CustomPolicyTag[]` is type-suffix tautology). -- **Suggested name:** `tags: Tag[]` (with type rename per #9). Wire form stays `custom_tags`. -- **Rationale:** Linked to type-rename #9; if `CustomPolicyTag` becomes `Tag`, field naturally becomes `tags`. - -### 20. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:46-50` +### 19. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:46-50` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. - **Category:** Observation, 14 (wire-style identifiers in TS docs). - **Suggested name:** Fix the doc to reference TS field names. - **Rationale:** Editing UX: hovers should show TS, not proto. -### 21. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:159` +### 20. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:159` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). - **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. - **Rationale:** Real bug. -### 22. `unmarshalBudgetPolicySchema` / `marshalBudgetPolicySchema` naming pair — `src/v1/model.ts:172,211` -- **Why weird:** "Marshal" and "unmarshal" terms come from Go encoding semantics. JS/TS world uses "serialize" / "deserialize" (or "parse" / "stringify"). -- **Category:** 14 (Go-style names not idiomatic in TS), 17 (across the file, `parseResponse`/`marshalRequest` in utils.ts:113,119 mix `parse` and `marshal`). -- **Suggested name:** `serializeBudgetPolicy` / `deserializeBudgetPolicy`, or `budgetPolicyToWire` / `budgetPolicyFromWire`. -- **Rationale:** Aligns with broader JS ecosystem (`JSON.parse`/`JSON.stringify`, Zod's `parse`/`safeParse`). Generator-wide concern. - ## Low severity -### 23. `budgetPolicyFieldMaskSchema` constant — `src/v1/model.ts:271` -- **Why weird:** `*Schema` suffix on a non-Zod object (it's a `FieldMaskSchema` map describing wire-name aliases). Reuses `Schema` (which everywhere else in this file means a Zod schema) for a different concept. -- **Category:** 1 (vague suffix overloaded), 17 (inconsistent — `Schema` used for two different things in one file). -- **Suggested name:** `budgetPolicyFieldMaskFields` or `budgetPolicyFieldMaskMap`. -- **Rationale:** Hover help becomes ambiguous; reader must disambiguate by inspecting the value. - -### 24. `budgetPolicyFieldMask` function — `src/v1/model.ts:278` +### 21. `budgetPolicyFieldMask` function — `src/v1/model.ts:278` - **Why weird:** Exported helper for building a `FieldMask`. The export is not surfaced from `index.ts:5-19`, so it cannot be used by consumers of the package. - **Category:** Observation (unused public surface — dead export). - **Suggested name:** Either re-export from `index.ts`, or mark internal. - **Rationale:** Dead export. -### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 22. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. -### 26. `HttpCallOptions` — `src/v1/utils.ts:15` +### 23. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. -### 27. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. -- **Rationale:** Pair-wise consistency aids reading. Same as `abacpolicies` finding #35. - -### 28. `readAll` — `src/v1/utils.ts:40` +### 24. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 29. `flattenQueryParams` — `src/v1/utils.ts:123` +### 25. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Same as `abacpolicies` finding #32; generator-wide. -### 31. `Client` class plain name — `src/v1/client.ts:46` +### 27. `Client` class plain name — `src/v1/client.ts:46` - **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 32. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 28. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` - **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. -### 33. `listBudgetPoliciesIter` method name — `src/v1/client.ts:193` -- **Why weird:** `Iter` is a cryptic abbreviation for "iterator" / "iterable". Mirrors Go SDK's `Iterator` style. TS convention is to spell out (`...Iterator`) or use a stronger naming convention (`paginate*`, `list*All`). -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `listBudgetPoliciesIterator`, or rename pair: `listBudgetPolicies` (single page) + `listAllBudgetPolicies` (async iterable). -- **Rationale:** `Iter` is a Go-style truncation that JS/TS users rarely use. - ## Observations -### 34. Action-verb conventions in `Client` +### 29. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 35. Wire/TS divergence dominates the file -`src/v1/model.ts` is 283 lines for ~10 user-facing types; >40% is marshal/unmarshal/FieldMask scaffolding. Not a naming defect, but the audit surfaces how much generator boilerplate ships per package. - -### 36. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +### 30. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. - **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). -### 37. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 31. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. @@ -240,7 +207,7 @@ The three together blur the boundary between "policy that classifies usage" (bud - **Category:** 12 (duplicate concept), 1 (vague package names). - **Rationale:** Worth raising at the SDK / API design level. From the TS-user perspective, three near-clones makes the import surface confusing. -### 38. Acronym casing `Id` consistently used as `Id`, not `ID` +### 32. Acronym casing `Id` consistently used as `Id`, not `ID` `policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken` (no id) — file consistently uses `Id` (Title-case lower). Inconsistent only with `URLSearchParams` (Web API; out of our control). Good internal consistency. - **Category:** 3 (observation — internal acronym style is consistent). diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 2ac3b517..babc2f74 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -46,35 +46,11 @@ fixed at the generator, not by hand-editing this package. `UpdateBudgetConfiguration_Response`, `UpdateBudgetConfigurationBudget`. -### Schemas (`model.ts`) - -`unmarshalActionConfigurationSchema`, -`unmarshalAlertConfigurationSchema`, -`unmarshalBudgetConfigurationSchema`, -`unmarshalBudgetConfigurationFilterSchema`, -`unmarshalBudgetConfigurationFilter_ClauseSchema`, -`unmarshalBudgetConfigurationFilter_TagClauseSchema`, -`unmarshalBudgetConfigurationFilter_WorkspaceIdClauseSchema`, -`unmarshalCreateBudgetConfiguration_ResponseSchema`, -`unmarshalDeleteBudgetConfiguration_ResponseSchema`, -`unmarshalGetBudgetConfiguration_ResponseSchema`, -`unmarshalListBudgetConfigurations_ResponseSchema`, -`unmarshalUpdateBudgetConfiguration_ResponseSchema`, -`marshalActionConfigurationSchema`, `marshalAlertConfigurationSchema`, -`marshalBudgetConfigurationFilterSchema`, -`marshalBudgetConfigurationFilter_ClauseSchema`, -`marshalBudgetConfigurationFilter_TagClauseSchema`, -`marshalBudgetConfigurationFilter_WorkspaceIdClauseSchema`, -`marshalCreateBudgetConfigurationSchema`, -`marshalCreateBudgetConfigurationBudgetSchema`, -`marshalUpdateBudgetConfigurationSchema`, -`marshalUpdateBudgetConfigurationBudgetSchema`. - ### Client methods (`client.ts`) `createBudgetConfiguration`, `deleteBudgetConfiguration`, `getBudgetConfiguration`, `listBudgetConfigurations`, -`listBudgetConfigurationsIter`, `updateBudgetConfiguration`. +`updateBudgetConfiguration`. ### Utility functions (`utils.ts`) @@ -258,7 +234,6 @@ fixed at the generator, not by hand-editing this package. - `GetBudgetConfiguration_Response` `model.ts:152` - `ListBudgetConfigurations_Response` `model.ts:169` - `UpdateBudgetConfiguration_Response` `model.ts:183` - - All `marshal*` / `unmarshal*` schema constants of the above. - Re-exported through `index.ts:10, 18-31`. - **Why flagged:** Each of these requires an `eslint-disable-next-line @typescript-eslint/naming-convention` @@ -462,27 +437,10 @@ fixed at the generator, not by hand-editing this package. `updateBudgetConfiguration`. Inside a `Budgets` client, the `Budget`/`Budgets` suffix is repetitive. Compare typical TS SDK shape: `budgets.create(...)`, `budgets.list(...)`. -- **Suggestion:** `create`, `delete`, `get`, `list`, `listIter`, +- **Suggestion:** `create`, `delete`, `get`, `list`, `update`. The class itself already conveys "budgets". This is a cross-package convention to decide once. -#### F7.5 — `listBudgetConfigurationsIter` (MEDIUM) -- **Where:** `client.ts:212`. -- **Why flagged:** 30 characters, with `Configurations` repeated. The - `Iter` suffix is also Go-style; in TS the idiomatic alternative - is an async iterator method (`[Symbol.asyncIterator]`) or a name - like `listAll` / `streamBudgets`. -- **Suggestion:** Tied to F7.4: collapse to `listIter` or - better, `iterate`/`stream`/`listAll` — and decide cross-package. - -#### F7.6 — `BudgetConfigurationFilter_WorkspaceIdClause` (LOW) -- **Where:** `model.ts:93`. -- **Why flagged:** 43 characters. Even after un-underscoring it remains - `BudgetConfigurationFilterWorkspaceIdClause` — readable but heavy. -- **Suggestion:** Inside a renamed `Budget.Filter` namespace, - `WorkspaceIdClause` is fine. If kept flat, `BudgetFilterWorkspaceClause` - is shorter and equally clear (drop `Id`). - --- ### 8. Redundant suffixes @@ -567,10 +525,6 @@ fixed at the generator, not by hand-editing this package. (acceptable) - Plural, correct. -#### F9.6 — `listBudgetConfigurations` vs `listBudgetConfigurationsIter` - (acceptable) -- Plural form is correct here. - --- ### 10. Reserved-word / built-in collisions @@ -699,23 +653,7 @@ _None._ - `create*`, `delete*`, `get*`, `list*`, `update*` — uniform imperative present. Good. -#### F13.2 — `marshalRequest` / `parseResponse` (acceptable) -- `marshalRequest` (utils.ts:119) is imperative; `parseResponse` - (utils.ts:113) is imperative. Consistent. - -#### F13.3 — `unmarshalXSchema` constants (LOW, code style) -- **Where:** `model.ts:208, 221, 242, …` and all `marshal…Schema`. -- **Why flagged:** Naming pattern is correct (verb + noun + Schema), - but the verb form makes them read like functions, not constants. - They *are* values (`z.ZodType` objects). The Zod community - conventionally exports schemas as PascalCase nouns - (`BudgetSchema`) or `budgetSchema` in camelCase. Verb prefix is - unusual. -- **Suggestion:** Rename to `budgetWireSchema` / `budgetReadSchema` - or pair `budgetEncoder` / `budgetDecoder`. Cross-cutting; tied to - generator. - -#### F13.4 — `createTime`, `updateTime` vs `created_at`/`updated_at` +#### F13.2 — `createTime`, `updateTime` vs `created_at`/`updated_at` conventions (LOW) - **Where:** `model.ts:56-58, 115-117, 194-196`. - **Why flagged:** Past-tense `createdTime` / `updatedTime` (or @@ -731,41 +669,27 @@ _None._ ### 14. Go / Java-style names -#### F14.1 — `req`, `resp`, `err`, `Iter`, `httpReq`, `apiErr`, +#### F14.1 — `req`, `resp`, `err`, `httpReq`, `apiErr`, `pkgJson`, `opts` (HIGH, but cross-cutting) - **Where:** - `req` everywhere in `client.ts` - `resp` everywhere in `client.ts` and `utils.ts:73, 81` - `e` in `utils.ts:76` (with rethrow) - - `Iter` suffix in `listBudgetConfigurationsIter` - `httpReq` in client.ts - `apiErr` in utils.ts:88 - `pkgJson` in client.ts:19 - `opts` in utils.ts:30, 68 - **Why flagged:** These are all classic Go idioms ported verbatim. TS convention favors spelled-out names (`request`, `response`, - `error`, `iterator`/`stream`/`listAll`, `httpRequest`, - `apiError`, `packageJson`, `options`). + `error`, `httpRequest`, `apiError`, `packageJson`, `options`). - **Suggestion:** Spell them out. Trivial diff, large readability gain. This is a porting-convention decision and should be made globally at the generator level. -#### F14.2 — `unmarshal*` / `marshal*` schema prefixes (LOW) -- **Where:** All schema exports. -- **Why flagged:** `marshal`/`unmarshal` is a Go term - (encoding/json). The JS/TS world says "serialize"/"deserialize" - or "encode"/"decode". `JSON.parse`/`JSON.stringify` is the - vernacular. `marshal` is recognizable but Go-flavored. -- **Suggestion:** Rename to `encode`/`decode` or - `serialize`/`deserialize`. Generator-level decision. - -#### F14.3 — `Schema` suffix on Zod constants (acceptable) -- The `…Schema` suffix matches Zod community convention. - -#### F14.4 — `_Response` (and other) underscore-pseudo-nesting (HIGH) +#### F14.2 — `_Response` (and other) underscore-pseudo-nesting (HIGH) - See F4.1. Underscores are foreign to TS. -#### F14.5 — Comment style (acceptable) +#### F14.3 — Comment style (acceptable) - Comments are sentences. Good — but the file-top comment is the generator banner. @@ -827,26 +751,6 @@ _None._ #### F17.1 — `Get` vs `List` for read endpoints (acceptable) - `get` for single, `list` for collection. Standard REST verbs. -#### F17.2 — `listBudgetConfigurationsIter` (MEDIUM) -- **Where:** `client.ts:212`. -- **Why flagged:** `Iter` is not a verb; it is a suffix attached to - `list`. In TS the pattern `list` returns a single page, `listAll` - or `stream*` returns an async iterator. `listIter` is fine but - inconsistent across SDKs. -- **Suggestion:** Pick `listAll` or `iterate` or expose - `[Symbol.asyncIterator]` on a paginator object. Cross-cutting. - -#### F17.3 — `marshal` / `unmarshal` (Go-style verbs, LOW) -- See F14.2. - -#### F17.4 — `parseResponse` vs `marshalRequest` (LOW, asymmetry) -- **Where:** `utils.ts:113, 119`. -- **Why flagged:** `parse` vs `marshal` use different verbs for the - same kind of operation (JSON conversion). Inconsistent verb - choice. -- **Suggestion:** Use the same axis throughout: either - `marshal/unmarshal` or `encode/decode` or `serialize/deserialize`. - --- ### 18. Long enum values @@ -925,14 +829,6 @@ _None._ (LOW) - **Where:** `model.ts:13, 39`. Same pattern. -#### F20.5 — Generic `_ResponseSchema` on every wrap (LOW) -- **Where:** `model.ts:319, 329, 333, 343, 357`. -- **Why flagged:** `unmarshalCreateBudgetConfiguration_ResponseSchema` - is 51 characters with "Schema" suffixed onto an already-typed - `z.ZodType<...>`. The `Schema` suffix is conventional in Zod - ecosystems though. -- **Suggestion:** Acceptable; tied to generator. - --- ## Package overlap: `budgets` vs `budgetpolicy` @@ -990,20 +886,20 @@ This SDK exposes two separate packages whose names both start with | 4 | Underscores in TS identifiers | 2 | | 5 | Cryptic abbreviations | 7 | | 6 | Misleading names | 5 | -| 7 | Overly verbose | 6 | +| 7 | Overly verbose | 4 | | 8 | Redundant suffixes | 4 | -| 9 | Singular / plural mismatch | 6 (4 acceptable) | +| 9 | Singular / plural mismatch | 5 (3 acceptable) | | 10 | Reserved-word collisions | 5 (3 acceptable) | | 11 | Empty / trivial wrappers | 0 | | 12 | Duplicate concepts | 5 | -| 13 | Verb-tense inconsistency | 4 (2 acceptable) | -| 14 | Go / Java-style names | 5 | +| 13 | Verb-tense inconsistency | 2 (1 acceptable) | +| 14 | Go / Java-style names | 3 (1 acceptable) | | 15 | Generic field names | 5 | | 16 | Field contradicting type domain | 3 | -| 17 | Inconsistent action verbs | 4 (1 acceptable) | +| 17 | Inconsistent action verbs | 1 (1 acceptable) | | 18 | Long enum values | 3 | | 19 | Underspecified IDs | 4 (1 acceptable) | -| 20 | Type-suffix tautology | 5 | +| 20 | Type-suffix tautology | 4 | | OVERLAP | budgets vs budgetpolicy | 3 | --- @@ -1026,12 +922,12 @@ This SDK exposes two separate packages whose names both start with (`CreateBudgetRequest`) and method names (`budgets.create(...)`); document explicit `Request`/`Response` suffix convention. -6. **F4.1 / F14.4:** Replace underscored proto-style names with +6. **F4.1:** Replace underscored proto-style names with flat PascalCase or namespaces; eliminates all `eslint-disable-next-line` for `naming-convention`. 7. **F12.4:** Lift `accountId` to top-level on all request types (currently nested under `budget` for create/update only). -8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`Iter`/`opts`/ +8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson` etc. across all generated code. --- @@ -1042,12 +938,5 @@ This SDK exposes two separate packages whose names both start with "Code generated from API definition by Databricks SDK Generator. DO NOT EDIT." The fixes belong upstream in the generator and spec. This audit is a backlog for that generator. -- The `utils.ts` file contains the same generic helpers - (`executeCall`, `parseResponse`, `marshalRequest`, - `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, - `readAll`) that every generated package duplicates. The - duplication itself is not a naming issue, but the *names* - (`marshal/unmarshal`) are Go-flavored and inconsistent - (`parseResponse` vs `marshalRequest`). - This package has no `tests/` directory (verified by repo structure check), so the audit does not cover test naming. diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md index d3387ccb..9b3b8c4f 100644 --- a/.agent/naming-audit/bundle.md +++ b/.agent/naming-audit/bundle.md @@ -12,9 +12,9 @@ | ------------ | ----- | | High | 7 | | Medium | 13 | -| Low | 11 | -| Observation | 8 | -| **Total** | **39** | +| Low | 10 | +| Observation | 6 | +| **Total** | **36** | Dominant themes: 1. **Pervasive redundant enum prefixes.** All seven enums repeat the type name on every member (`DEPLOYMENT_STATUS_ACTIVE`, `VERSION_TYPE_DEPLOY`, etc.) — 50+ values affected — which is a Go/Protobuf carry-over that hurts TS ergonomics. @@ -308,15 +308,7 @@ No issue, just noting these names are uniform and correct. --- -### L7. `*Iter` suffix on async generators (Category: 5 — cryptic abbreviation) - -**Location:** `Client.listDeploymentsIter`, `Client.listOperationsIter`, `Client.listResourcesIter`, `Client.listVersionsIter` (`client.ts:457`, `508`, `559`, `613`). - -`Iter` is a Go-style abbreviation for "iterator". The Go SDK uses `Iterator(...)` or `Iter(...)` similarly. In TS the convention is more often `listDeploymentsAsyncIterator` or `iterateDeployments` (or, if the existing list method returns the page, an overload). `Iter` is short but cryptic to JS-native developers. Not load-bearing because there is a comment-free convention across the SDK — verify with the wider SDK before changing. - ---- - -### L8. `Operation` interface name collides with `Operation` from `@databricks/sdk-databricks` long-running-ops (Category: 12 — duplicate concepts) +### L7. `Operation` interface name collides with `Operation` from `@databricks/sdk-databricks` long-running-ops (Category: 12 — duplicate concepts) **Location:** `Operation` (`model.ts:441-481`). @@ -324,7 +316,7 @@ In many Databricks/Google APIs, `Operation` is the LRO (Long-Running Operation) --- -### L9. `Resource.resourceKey` vs `Operation.resourceKey` — same name, same role (good) +### L8. `Resource.resourceKey` vs `Operation.resourceKey` — same name, same role (good) **Location:** `model.ts:497`, `model.ts:458`. @@ -332,7 +324,7 @@ This is correct re-use — both reference the same bundle config path. No issue. --- -### L10. `deployments` request method names vs URL path consistency +### L9. `deployments` request method names vs URL path consistency **Location:** `Client.listDeployments` → `/api/2.0/bundle/deployments` (`client.ts:428`). @@ -340,7 +332,7 @@ The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The --- -### L11. Acronym casing in `cliVersion`, `versionId`, `expireTime` — check SDK-wide +### L10. Acronym casing in `cliVersion`, `versionId`, `expireTime` — check SDK-wide **Location:** `Version.cliVersion` (`model.ts:535`), `Version.versionId` (`model.ts:527`), `HeartbeatResponse.expireTime` (`model.ts:315`). @@ -350,35 +342,27 @@ The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The ## Observations (Non-Defects) -### O1. Marshal/unmarshal schemas use snake_case keys to match wire format - -`marshal*` schemas write `display_name`, `created_by`, etc. while the TS-side interfaces use `displayName`, `createdBy`. This is the correct pattern for a 1:1 port and is not a naming defect — just noting the boundary. - -### O2. `unmarshalListDeploymentsResponseSchema` etc. are long but well-structured - -The `unmarshal{Type}Schema` and `marshal{Type}Schema` exports are verbose but completely predictable. No findings — they read like generator output (which they are). - -### O3. JSDoc on the `state` fields is good +### O1. JSDoc on the `state` fields is good `Resource.state` and `Operation.state` both clearly say "Serialized local config state". Naming could improve (M12) but doc-level disambiguation is solid. -### O4. Pagination naming is uniform and correct +### O2. Pagination wire shape is uniform and correct -`pageSize`, `pageToken`, `nextPageToken`, `*Iter` (modulo L7) — all four `List*Request`/`List*Response` pairs are mechanically identical, with parallel `List*Iter` async generators on the client. +`pageSize`, `pageToken`, `nextPageToken` — all four `List*Request`/`List*Response` pairs are mechanically identical on the wire. -### O5. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing +### O3. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is correct; the *name* is what is generic (see M12). -### O6. Method `getResource` returns `Resource`, no naming collision +### O4. Method `getResource` returns `Resource`, no naming collision `client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level — only at the *interface* level (H5). -### O7. Comment on the `name`-vs-`destroy` divergence is appreciated +### O5. Comment on the `name`-vs-`destroy` divergence is appreciated `Deployment.destroyTime` has an in-code justification (`model.ts:255-258`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H4). -### O8. The `HeartbeatResponse.expireTime` field has no `Lease`/`Lock` prefix +### O6. The `HeartbeatResponse.expireTime` field has no `Lease`/`Lock` prefix The docstring says "new lock expiry time", but the field is just `expireTime`. Calling it `lockExpireTime` or `lockExpiresAt` would self-document. Marginal because of H7 (rename the whole method to `renewLock` and the field name becomes obvious from context). @@ -407,8 +391,8 @@ The docstring says "new lock expiry time", but the field is just `expireTime`. C | File | Lines | Findings | | ----------------- | ----- | --------------------------------------------------------------------------------- | -| `src/v1/model.ts` | 843 | H1, H2, H3, H4, H5, H6, H7, M1-M13, L1-L5, L8, L9, L11, O1, O2, O3, O5, O7, O8 | -| `src/v1/client.ts`| 630 | H4 (request types), H7 (method name), M9, L7, L10, O6 | +| `src/v1/model.ts` | 843 | H1, H2, H3, H4, H5, H6, H7, M1-M13, L1-L5, L7, L8, L10, O1, O3, O5, O6 | +| `src/v1/client.ts`| 630 | H4 (request types), H7 (method name), M9, L9, O4 | | `src/v1/utils.ts` | 151 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | | `src/v1/index.ts` | 40 | Re-exports — inherits findings from `model.ts` and `client.ts`. | diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index f36db272..1dc2f9e3 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -33,8 +33,7 @@ is doubly redundant — the field is the only payload-bearing scalar on the type and conveys no semantics. The doc comment reveals it actually holds the enable/disable string ("Whether predictive optimization should be enabled..."). Better: `enabled`, `predictiveOptimizationEnabled`, or -mirror the upstream `flagValue` if present. Same issue surfaces in the -marshal/unmarshal schemas (lines 489, 494, 636, 641). +mirror the upstream `flagValue` if present. #### 1.2 `*_OptionsEntry.value` / `*_PropertiesEntry.value` (model.ts:133, 139, 208, 214, 372, 378) Single-character-like generic names (`key`, `value`) on the exported @@ -144,7 +143,7 @@ working around it. #### 4.1 `ConversionInfo_State` (model.ts:50) Proto nested-enum convention `Parent_Child`. TypeScript convention is `ConversionInfoState` (or, better, top-level `ConversionState` because -there is no real nesting in TS — see §13.1). +there is no real nesting in TS — see §12.1). #### 4.2 `ProvisioningInfo_State` (model.ts:57) Same as 4.1. Should be `ProvisioningState`. @@ -164,10 +163,6 @@ Should be `DeleteCatalogResponse`. #### 4.7 `ListCatalogs_Response` (model.ts:292) Should be `ListCatalogsResponse`. -#### 4.8 `unmarshalDeleteCatalog_ResponseSchema`, `unmarshalListCatalogs_ResponseSchema` (model.ts:468, 515) -The underscores propagate into the schema exports. Should be -`unmarshalDeleteCatalogResponseSchema`, `unmarshalListCatalogsResponseSchema`. - --- ### 5. Cryptic abbreviations @@ -180,7 +175,7 @@ TypeScript callers have no need for this distinction — the field is the catalog name and should be named `name` (or `catalogName` if a sibling `name` field is required for body symmetry). Today, `UpdateCatalog` has *both* `nameArg` (path) and `name` (body) — virtually guaranteeing user -confusion. See also §15.1. +confusion. See also §14.1. #### 5.2 `Dr` prefix throughout (`DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo`, `lastFailoverTimeMs` doc) — see §3.1. @@ -229,8 +224,6 @@ A field on `EncryptionSettings` named `azureEncryptionSettings` whose type is also `AzureEncryptionSettings` reads like a copy-paste error. Drop the prefix: `azure: AzureEncryptionSettings` is clearer. -#### 6.7 `executeHttpCall` accepts an `HttpCallOptions` containing an `HttpRequest` (utils.ts:65) — internal, but the function name and its options bag both repeat "HttpCall". - --- ### 7. Overly verbose @@ -251,12 +244,7 @@ it pairs with §7.1 to make every `CatalogInfo`-style object verbose. Three-word field name on a securable that already implies "managed". Consider `encryption` or `encryptionSettings`. -#### 7.4 `unmarshalEffectivePredictiveOptimizationFlagSchema` / -`marshalEffectivePredictiveOptimizationFlagSchema` (model.ts:486, 634) -Schema exports are 51+ characters. Hard to read, especially in a -generated transform chain. - -#### 7.5 `MANAGED_ONLINE_CATALOG` enum value (model.ts:18) — see §17.1. +#### 7.4 `MANAGED_ONLINE_CATALOG` enum value (model.ts:18) — see §16.1. --- @@ -273,77 +261,61 @@ convention is to drop it (`Catalog`, `Conversion`, `Provisioning`, #### 8.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` The whole type *is* the flag; the suffix is redundant. See §7.1. -#### 8.4 `…Arg` suffix on `nameArg` — see §5.1 and §15.1. - -#### 8.5 `…Schema` suffix on every zod schema export (`unmarshalCatalogInfoSchema`, `marshalCreateCatalogSchema`, etc.) -Defensible (signals it's a zod schema), but verbose when paired with -`unmarshal…`/`marshal…` prefixes. Consider `unmarshalCatalogInfo` / -`marshalCreateCatalog` (the schema-ness is conveyed by the prefix). - ---- - -### 9. Singular / plural mismatches - -#### 9.1 `Client.listCatalogsIter` returns `AsyncGenerator` (client.ts:210) -Method name implies plural results; the generator yields singular items -one at a time. Consistent with neighbouring packages, but worth a sanity -check — `iterCatalogs` (verb-first) reads more naturally for an iterator. - -#### 9.2 `DrReplicationInfo.replicatedEntities` is a single `Uint8Array` — see §1.3, §6.3. +#### 8.4 `…Arg` suffix on `nameArg` — see §5.1 and §14.1. --- -### 10. Reserved-word collisions +### 9. Reserved-word collisions -#### 10.1 `options` field on `CatalogInfo`, `CreateCatalog`, `UpdateCatalog` (model.ts:127, 202, 366) +#### 9.1 `options` field on `CatalogInfo`, `CreateCatalog`, `UpdateCatalog` (model.ts:127, 202, 366) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (e.g. `createCatalog(req, options)`). The collision is not a compile error but creates cognitive load — inside `updateCatalog(req, options)` the reader sees both `req.options` (catalog metadata) and `options` (call options). Rename one. The least invasive fix is renaming the second client parameter to `callOptions`. See also -§11.1 for the duplicate-with-`properties` concern. +§10.1 for the duplicate-with-`properties` concern. -#### 10.2 `name` keyword-ish field +#### 9.2 `name` keyword-ish field `name` is used as a non-path-param body field on `Create*` / `Update*` / `CatalogInfo`, and also as a path arg via `nameArg`. This isn't a reserved word but it routinely shadows `Function.prototype.name` and is a common source of confusion when callers spread request objects. See also §5.1. -#### 10.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:242) — generic, frequently shadows local variables. See §1.1. +#### 9.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:242) — generic, frequently shadows local variables. See §1.1. --- -### 11. Duplicate concepts +### 10. Duplicate concepts -#### 11.1 `properties` and `options` (model.ts:124-127, 199-202, 363-366) +#### 10.1 `properties` and `options` (model.ts:124-127, 199-202, 363-366) Both `Record` on every catalog shape, with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know which to use for what. Either the docs need to differentiate them or one is redundant. See also §6.5. -#### 11.2 `name` vs `fullName` on `CatalogInfo` +#### 10.2 `name` vs `fullName` on `CatalogInfo` `fullName` is documented as "the full name of the catalog. Corresponds with the name field" (model.ts:115-116). The same data lives in `name` for catalogs because catalogs are top-level. The duplicate field exists to satisfy a polymorphic Securable shape — but for the catalog-specific type, it's redundant. See also §6.4. -#### 11.3 `name` vs `nameArg` on `UpdateCatalog` +#### 10.3 `name` vs `nameArg` on `UpdateCatalog` The `UpdateCatalog` request has *both* `nameArg` (the existing catalog identifier, used in the URL path) and `name` (the new desired name, used in the body). It also has `newName` for the same concept. See -§15.1 below — three name-like fields on one request shape. +§14.1 below — three name-like fields on one request shape. -#### 11.4 `securableType` on `CatalogInfo` (model.ts:117) duplicates the type identity +#### 10.4 `securableType` on `CatalogInfo` (model.ts:117) duplicates the type identity `CatalogInfo` represents a catalog; its `securableType` field will always be `SecurableType.CATALOG`. The field exists for polymorphism across UC types but is meaningless when the surrounding type already identifies the securable. Not a renaming issue — but worth flagging as a duplicated concept. -#### 11.5 `CreateCatalog`, `UpdateCatalog`, and `CatalogInfo` share ~25 fields verbatim +#### 10.5 `CreateCatalog`, `UpdateCatalog`, and `CatalogInfo` share ~25 fields verbatim The three types are 95% identical and have largely identical doc strings. This is a generator artifact, but it bleeds into naming: any rename of `storageRoot` must happen in three places. Recommend basing @@ -352,69 +324,62 @@ This is a generator artifact, but it bleeds into naming: any rename of --- -### 12. Verb-tense inconsistency +### 11. Verb-tense inconsistency -#### 12.1 Client methods are well-aligned: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`, `listCatalogsIter`. No tense issues. +#### 11.1 Client methods are well-aligned: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`. No tense issues. -#### 12.2 `unmarshal…` / `marshal…` schema-export prefixes are consistent. No issues. +#### 11.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65) — both imperative present, consistent. -#### 12.3 `executeCall`, `executeHttpCall` (utils.ts:26, 65) — both imperative present, consistent. +#### 11.3 `buildHttpRequest`, `parseResponse`, `marshalRequest` (utils.ts:96, 113, 119) — imperative present, consistent. -#### 12.4 `buildHttpRequest`, `parseResponse`, `marshalRequest` (utils.ts:96, 113, 119) — imperative present, consistent. - -#### 12.5 `flattenQueryParams` (utils.ts:123) — imperative, consistent. +#### 11.4 `flattenQueryParams` (utils.ts:123) — imperative, consistent. No verb-tense inconsistencies found across the package. --- -### 13. Go / Java-style names +### 12. Go / Java-style names -#### 13.1 `ConversionInfo_State`, `ProvisioningInfo_State` (model.ts:50, 57) +#### 12.1 `ConversionInfo_State`, `ProvisioningInfo_State` (model.ts:50, 57) Proto nested-enum naming `Parent_Child`. In TS this should be a top-level type with a meaningful prefix: `ConversionState`, `ProvisioningState`. See §4.1-4.2. -#### 13.2 `Client` class name (client.ts:44) +#### 12.2 `Client` class name (client.ts:44) Bare `Client` (rather than `CatalogsClient`) is a Go-idiom: package qualifies the type. JS consumers commonly import as `import {Client} from '@databricks/sdk-catalogs/v1'` and have to alias. This is a package-wide convention, but worth flagging in this audit for consistency with the broader review. -#### 13.3 `nameArg` (model.ts:219, 264, 310) — Go generator naming. See §5.1. - -#### 13.4 `…_Response` suffix is a proto / Go-RPC idiom. See §4.6, §4.7. +#### 12.3 `nameArg` (model.ts:219, 264, 310) — Go generator naming. See §5.1. -#### 13.5 `…Info` suffix — Java/Go style. See §8.1. +#### 12.4 `…_Response` suffix is a proto / Go-RPC idiom. See §4.6, §4.7. -#### 13.6 `unmarshal…` / `marshal…` (Go's `encoding/json` verbs) -These are direct Go ports. The TS ecosystem typically uses `parse` / -`serialize` or `decode` / `encode`. Defensible because they're internal -to the generated layer, but identifies as Go-style naming. +#### 12.5 `…Info` suffix — Java/Go style. See §8.1. --- -### 14. Generic field names losing meaning +### 13. Generic field names losing meaning -#### 14.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. +#### 13.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. -#### 14.2 `key`, `value` on map-entry wrappers (`*_OptionsEntry`, `*_PropertiesEntry`) — see §1.2. +#### 13.2 `key`, `value` on map-entry wrappers (`*_OptionsEntry`, `*_PropertiesEntry`) — see §1.2. -#### 14.3 `state` on `ConversionInfo`, `ProvisioningInfo` (model.ts:145, 305) +#### 13.3 `state` on `ConversionInfo`, `ProvisioningInfo` (model.ts:145, 305) Whose state? Bound to its container — but if the container is ever inlined, the field stands alone. See §1.4. -#### 14.4 `status` on `DrReplicationInfo` (model.ts:229) +#### 13.4 `status` on `DrReplicationInfo` (model.ts:229) Generic in isolation; works in context. Less severe than `state`. -#### 14.5 `properties`, `options` (model.ts:125, 127, etc.) — see §6.5, §11.1. +#### 13.5 `properties`, `options` (model.ts:125, 127, etc.) — see §6.5, §10.1. --- -### 15. Field contradicting type domain +### 14. Field contradicting type domain -#### 15.1 `UpdateCatalog` has `nameArg`, `name`, and `newName` (model.ts:310, 312, 314) +#### 14.1 `UpdateCatalog` has `nameArg`, `name`, and `newName` (model.ts:310, 312, 314) Three name-bearing fields on a single update request: - `nameArg` — existing catalog (path param). - `newName` — new desired name (body). @@ -424,7 +389,7 @@ A caller staring at this struct cannot intuit which to set. This is the single most user-hostile naming pattern in the package — and it sits on the most-used method. -#### 15.2 `CreateCatalog` contains read-only output fields +#### 14.2 `CreateCatalog` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `provisioningInfo`, `conversionInfo`, `drReplicationInfo`, `fullName`, `securableType`, `effectivePredictiveOptimizationFlag`, `browseOnly` @@ -432,9 +397,9 @@ the most-used method. is at best ignored. The type's domain is "create request", but its shape contradicts that. Mirror issue in `UpdateCatalog`. -#### 15.3 `DeleteCatalog.nameArg` — see §5.1. +#### 14.3 `DeleteCatalog.nameArg` — see §5.1. -#### 15.4 `EncryptionSettings.azureEncryptionSettings` +#### 14.4 `EncryptionSettings.azureEncryptionSettings` The outer type's domain is "all encryption settings"; the field is named as if scoped to Azure. The contradiction (parent claims breadth, child name claims specificity) is resolved by reading the type definition @@ -442,85 +407,84 @@ but is initially confusing. See §6.6. --- -### 16. Inconsistent action verbs +### 15. Inconsistent action verbs Method verbs in `Client`: `createCatalog`, `deleteCatalog`, `getCatalog`, -`listCatalogs`, `updateCatalog`, `listCatalogsIter`. Verbs are -consistent: standard CRUD plus a `…Iter` paginator. No `fetch…` / -`retrieve…` / `read…` outliers. No issues found. +`listCatalogs`, `updateCatalog`. Verbs are consistent: standard CRUD. +No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- -### 17. Long enum values +### 16. Long enum values -#### 17.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:18) +#### 16.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:18) 22-character enum value. Should be `MANAGED_ONLINE` after dropping the redundant `_CATALOG` suffix (§2.4). -#### 17.2 `DrReplicationStatus.DR_REPLICATION_STATUS_SECONDARY` (model.ts:24) +#### 16.2 `DrReplicationStatus.DR_REPLICATION_STATUS_SECONDARY` (model.ts:24) 33-character enum value, of which the first 22 are redundant. See §2.1. -#### 17.3 `ConversionInfo_State.STATE_UNSPECIFIED` (model.ts:51) +#### 16.3 `ConversionInfo_State.STATE_UNSPECIFIED` (model.ts:51) 17 characters; redundant `STATE_` prefix. See §2.2. -#### 17.4 `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58) — same. +#### 16.4 `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58) — same. --- -### 18. Underspecified IDs +### 17. Underspecified IDs -#### 18.1 `metastoreId` (model.ts:96, 171, 335) +#### 17.1 `metastoreId` (model.ts:96, 171, 335) Documented as "unique identifier of parent metastore". Format opaque (UUID? slug?). Acceptable but unspecified. -#### 18.2 `azureTenantId` (model.ts:68) +#### 17.2 `azureTenantId` (model.ts:68) GUID, implied by Azure context. Doc-less — not specified anywhere. -#### 18.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) +#### 17.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) Doc-less. Format is an Azure resource ID (`/subscriptions/…/providers/…`), not signalled by the name or documentation. -#### 18.4 `customerManagedKeyId` (model.ts:255) +#### 17.4 `customerManagedKeyId` (model.ts:255) Doc: "the CMK uuid in AWS and GCP, null otherwise." So the field is a UUID on AWS/GCP but `azureCmkAccessConnectorId` is an Azure resource ID elsewhere — same conceptual ID, two formats, no unifying name. -#### 18.5 `azureKeyVaultKeyId` (model.ts:257) +#### 17.5 `azureKeyVaultKeyId` (model.ts:257) Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See §6.2. -#### 18.6 `created_at` / `updated_at` (model.ts:98, 102) +#### 17.6 `created_at` / `updated_at` (model.ts:98, 102) Type is `number` (epoch milliseconds). Conventional, but the field name doesn't convey unit. Pairs `createdAtMs` or `createdAtEpochMs` would be more honest. -#### 18.7 `lastFailoverTimeMs` (model.ts:237) +#### 17.7 `lastFailoverTimeMs` (model.ts:237) Counter-example: this field correctly includes the `Ms` unit suffix. Demonstrates that the codebase *can* express units in names — the other timestamps simply don't. --- -### 19. Type-suffix tautology +### 18. Type-suffix tautology -#### 19.1 `SecurableType` enum with field `securableType: SecurableType` +#### 18.1 `SecurableType` enum with field `securableType: SecurableType` (model.ts:28, 117, 192, 356) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 19.2 `CatalogType` enum with field `catalogType: CatalogType` +#### 18.2 `CatalogType` enum with field `catalogType: CatalogType` (model.ts:12, 84, 159, 323) — same pattern. -#### 19.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` +#### 18.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` (model.ts:5, 108, 183, 347) — field-name shortened, type-name keeps the prefix. Reasonable. -#### 19.4 `DrReplicationStatus` enum with field `status: DrReplicationStatus` +#### 18.4 `DrReplicationStatus` enum with field `status: DrReplicationStatus` (model.ts:21, 229) — generic field name (`status`) on a typed value. Either expand the field (`drReplicationStatus`) or shorten the type (`ReplicationStatus`). -#### 19.5 `…Info` types with `…info` fields +#### 18.5 `…Info` types with `…info` fields - `provisioningInfo: ProvisioningInfo` - `conversionInfo: ConversionInfo` - `drReplicationInfo: DrReplicationInfo` @@ -530,10 +494,6 @@ Either expand the field (`drReplicationStatus`) or shorten the type The first four are tautological. Acceptable convention; flagged for completeness. -#### 19.6 Schema-export tautology -`unmarshalCatalogInfoSchema: z.ZodType` (model.ts:394) — the -`Schema` suffix duplicates `z.ZodType<…>`. See §8.5. - --- ## Additional / cross-cutting observations @@ -553,22 +513,11 @@ the server. The naming (`nameArg`) and the substitution behaviour together hide what should be a required parameter. Worth surfacing via a non-optional type or a typed assertion. -### C. `marshalUpdateCatalogSchema` serialises `nameArg`/`newName` into the body (model.ts:703-705) -`nameArg` is a path parameter — but the marshal schema produces a JSON -field `name_arg`. Either the server tolerates the extra field or this -is a bug. The naming choice (`Arg`) lets the bug hide. - -### D. Marshal/unmarshal exports lack proper TS types (model.ts:534, 546, etc.) -`marshalAzureEncryptionSettingsSchema: z.ZodType` (no generic) versus -`unmarshalAzureEncryptionSettingsSchema: z.ZodType` -(with generic). The marshal side is implicitly untyped. Not a naming -issue per se, but inconsistent with the unmarshal naming/typing. - -### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +### C. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### F. `index.ts` re-exports proto-style names verbatim (lines 10, 11, 17, 18, 21, 22, 24, 30, 33, 34) +### D. `index.ts` re-exports proto-style names verbatim (lines 10, 11, 17, 18, 21, 22, 24, 30, 33, 34) Every underscore-bearing identifier surfaces in the package's public API. A consumer of `@databricks/sdk-catalogs/v1` sees `ConversionInfo_State`, `DeleteCatalog_Response`, @@ -581,65 +530,60 @@ single highest-leverage place to clean naming. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | -| `CatalogIsolationMode` | model.ts:5 | 19.3 | -| `CatalogType` | model.ts:12 | 2.4, 17.1, 19.2 | +| `CatalogIsolationMode` | model.ts:5 | 18.3 | +| `CatalogType` | model.ts:12 | 2.4, 16.1, 18.2 | | `CatalogType.DELTASHARING_CATALOG` | model.ts:14 | 3.4 | -| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:18 | 17.1 | -| `DrReplicationStatus` | model.ts:21 | 2.1, 3.1, 17.2 | -| `SecurableType` | model.ts:28 | 19.1 | +| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:18 | 16.1 | +| `DrReplicationStatus` | model.ts:21 | 2.1, 3.1, 16.2 | +| `SecurableType` | model.ts:28 | 18.1 | | `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:46 | — | -| `ConversionInfo_State` | model.ts:50 | 2.2, 4.1, 13.1, 17.3 | -| `ProvisioningInfo_State` | model.ts:57 | 2.3, 4.2, 13.1, 17.4 | -| `AzureEncryptionSettings` | model.ts:67 | 3.2, 18.2 | +| `ConversionInfo_State` | model.ts:50 | 2.2, 4.1, 12.1, 16.3 | +| `ProvisioningInfo_State` | model.ts:57 | 2.3, 4.2, 12.1, 16.4 | +| `AzureEncryptionSettings` | model.ts:67 | 3.2, 17.2 | | `CatalogInfo` | model.ts:73 | 8.1 | -| `CatalogInfo.options` / `.properties` | model.ts:127, 125 | 6.5, 10.1, 11.1, 14.5 | -| `CatalogInfo.fullName` | model.ts:116 | 6.4, 11.2 | -| `CatalogInfo.securableType` | model.ts:117 | 11.4, 19.1 | +| `CatalogInfo.options` / `.properties` | model.ts:127, 125 | 6.5, 9.1, 10.1, 13.5 | +| `CatalogInfo.fullName` | model.ts:116 | 6.4, 10.2 | +| `CatalogInfo.securableType` | model.ts:117 | 10.4, 18.1 | | `CatalogInfo_OptionsEntry` | model.ts:131 | 1.2, 4.3 | | `CatalogInfo_PropertiesEntry` | model.ts:137 | 1.2, 4.3 | | `ConversionInfo` | model.ts:143 | 1.4, 8.1 | -| `CreateCatalog` | model.ts:148 | 11.5, 15.2 | +| `CreateCatalog` | model.ts:148 | 10.5, 14.2 | | `CreateCatalog_OptionsEntry/PropertiesEntry` | model.ts:206, 212 | 4.4 | -| `DeleteCatalog.nameArg` | model.ts:219 | 5.1, 13.3, 15.3 | +| `DeleteCatalog.nameArg` | model.ts:219 | 5.1, 12.3, 14.3 | | `DeleteCatalog_Response` | model.ts:225 | 4.6 | | `DrReplicationInfo` | model.ts:228 | 3.1, 8.1 | -| `DrReplicationInfo.replicatedEntities` | model.ts:231 | 1.3, 6.3, 9.2 | -| `DrReplicationInfo.lastFailoverTimeMs` | model.ts:237 | 18.7 (positive) | -| `EffectivePredictiveOptimizationFlag` | model.ts:240 | 7.1, 7.4, 8.3 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:242 | 1.1, 6.1, 10.3, 14.1 | +| `DrReplicationInfo.replicatedEntities` | model.ts:231 | 1.3, 6.3 | +| `DrReplicationInfo.lastFailoverTimeMs` | model.ts:237 | 17.7 (positive) | +| `EffectivePredictiveOptimizationFlag` | model.ts:240 | 7.1, 8.3 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:242 | 1.1, 6.1, 9.3, 13.1 | | `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:244 | 1.5 | | `EncryptionSettings` | model.ts:253 | 8.2 | -| `EncryptionSettings.customerManagedKeyId` | model.ts:255 | 3.2, 18.4 | -| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:257 | 3.3, 6.2, 18.5 | -| `EncryptionSettings.azureEncryptionSettings` | model.ts:259 | 6.6, 15.4 | -| `GetCatalog.nameArg` | model.ts:264 | 5.1, 13.3 | +| `EncryptionSettings.customerManagedKeyId` | model.ts:255 | 3.2, 17.4 | +| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:257 | 3.3, 6.2, 17.5 | +| `EncryptionSettings.azureEncryptionSettings` | model.ts:259 | 6.6, 14.4 | +| `GetCatalog.nameArg` | model.ts:264 | 5.1, 12.3 | | `ListCatalogs.maxResults` | model.ts:281 | — | | `ListCatalogs.pageToken` | model.ts:283 | — | | `ListCatalogs.includeUnbound` | model.ts:288 | — | | `ListCatalogs_Response` | model.ts:292 | 4.7 | | `ProvisioningInfo` | model.ts:303 | 1.4, 8.1 | -| `UpdateCatalog.nameArg/newName/name` | model.ts:310-314 | 5.1, 11.3, 15.1 | +| `UpdateCatalog.nameArg/newName/name` | model.ts:310-314 | 5.1, 10.3, 14.1 | | `UpdateCatalog_OptionsEntry/PropertiesEntry` | model.ts:370, 376 | 4.5 | -| `unmarshalDeleteCatalog_ResponseSchema` | model.ts:468 | 4.8 | -| `unmarshalListCatalogs_ResponseSchema` | model.ts:515 | 4.8 | -| `Client` (bare name) | client.ts:44 | 13.2 | -| `Client.listCatalogsIter` | client.ts:210 | 9.1 | +| `Client` (bare name) | client.ts:44 | 12.2 | | `${req.nameArg ?? ''}` URL substitution | client.ts:100,134,235 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `marshal…` / `unmarshal…` verbs | model.ts (many) | 13.6 | -| `…Schema` suffix | model.ts (many) | 8.5, 19.6 | -| `index.ts` re-exports | index.ts:5-35 | F | +| `index.ts` re-exports | index.ts:5-35 | D | --- ## Recommended priority order -1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalog`** — biggest user-facing trap. (§15.1, §5.1) +1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalog`** — biggest user-facing trap. (§14.1, §5.1) 2. **Strip `STATE_` / `DR_REPLICATION_STATUS_` / `_CATALOG` redundant prefixes from enum values.** (§2.1, §2.2, §2.3, §2.4) 3. **Drop proto-style `Parent_Child` identifiers** (`ConversionInfo_State`, `DeleteCatalog_Response`, `ListCatalogs_Response`, `*_OptionsEntry`, `*_PropertiesEntry`). (§4) -4. **Distinguish or merge `options` and `properties`.** (§11.1) +4. **Distinguish or merge `options` and `properties`.** (§10.1) 5. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§3.3, §6.2) -6. **Strip read-only fields from `CreateCatalog`/`UpdateCatalog`.** (§15.2) -7. **Decide CMK casing and apply uniformly.** (§3.2, §18.4) +6. **Strip read-only fields from `CreateCatalog`/`UpdateCatalog`.** (§14.2) +7. **Decide CMK casing and apply uniformly.** (§3.2, §17.4) 8. **Rename `replicatedEntities` to reflect that it's a byte blob.** (§1.3) 9. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md index 6d609c91..6888d05d 100644 --- a/.agent/naming-audit/cleanroomassets.md +++ b/.agent/naming-audit/cleanroomassets.md @@ -17,28 +17,28 @@ cleanroom packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules | # | Category | Count | | -- | ----------------------------------------- | ----- | -| 1 | Vague / generic names | 8 | +| 1 | Vague / generic names | 7 | | 2 | Redundant enum prefixes | 5 | | 3 | Acronym casing inconsistencies | 0 | -| 4 | Underscores in TS identifiers | 18 | +| 4 | Underscores in TS identifiers | 17 | | 5 | Cryptic abbreviations | 2 | | 6 | Misleading names | 3 | -| 7 | Overly verbose names | 9 | -| 8 | Redundant suffixes | 3 | +| 7 | Overly verbose names | 6 | +| 8 | Redundant suffixes | 2 | | 9 | Singular / plural mismatches | 2 | | 10 | Reserved-word / built-in collisions | 1 | | 11 | Empty / trivial wrapper types | 0 | | 12 | Duplicate concepts | 4 | | 13 | Verb-tense inconsistency | 1 | -| 14 | Go / Java-style names | 3 | +| 14 | Go / Java-style names | 1 | | 15 | Generic field names losing meaning | 5 | | 16 | Field contradicting type domain | 2 | | 17 | Inconsistent action verbs | 1 | | 18 | Long enum values | 6 | | 19 | Underspecified IDs | 2 | -| 20 | Type-suffix tautology | 4 | +| 20 | Type-suffix tautology | 3 | | -- | Cross-cutting: `CleanRoom` redundancy | 1 | -| -- | **Total findings** | **80** | +| -- | **Total findings** | **71** | --- @@ -91,12 +91,6 @@ Inside the discriminated union we have keys `table`, `notebook`, `view`, things (e.g. "this asset *is* a table"). Suggested rename: explicit suffix — `tableDetails`, `notebookDetails`, etc. — matches the `*LocalDetails` siblings. -### 1.8 `data` parameter in `marshalRequest` (utils.ts:119) - -`data: unknown` is the canonical anti-pattern. Replace with `value` (Zod's own -naming) or, better, parameterize: `function marshalRequest(value: T, schema: -z.ZodType): string`. - --- ## 2. Redundant enum prefixes @@ -110,8 +104,7 @@ Suggested rename: `UNSPECIFIED`. ### 2.2 `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` (model.ts:47) The literal `ENUM_UNSPECIFIED` carries the word "ENUM" — meaningless without -the type. The enum name `CleanRoomAsset_Status_Enum` itself has a redundant -`_Enum` suffix (see 8.1). Suggested rename: literal `UNSPECIFIED`. +the type. Suggested rename: literal `UNSPECIFIED`. ### 2.3 `CleanRoomNotebookReview_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (model.ts:55) @@ -167,8 +160,7 @@ The following identifiers should be reviewed at the porting layer: | 4.14 | `CleanRoomAsset_VolumeLocalDetails` | model.ts:246 | | 4.15 | `PartitionSpecification_Partition` | model.ts:428 | | 4.16 | `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | -| 4.17 | All `marshal*_*` / `unmarshal*_*` schema constants (model.ts:551–984, ~20 names) | model.ts (various) | -| 4.18 | All proto `$case` discriminator values use camelCase (good), but underlying serialized fields use `snake_case` (e.g. `clean_room_name`, `notebook_review_state`) — fine for wire format, just calling out the boundary | model.ts:484+ | +| 4.17 | All proto `$case` discriminator values use camelCase (good), but underlying serialized fields use `snake_case` (e.g. `clean_room_name`, `notebook_review_state`) — fine for wire format, just calling out the boundary | model.ts:484+ | Suggested approach: drop the underscore and concatenate (`CleanRoomAssetAssetType` → still ugly; `CleanRoomAssetTableLocalDetails` is @@ -227,64 +219,42 @@ only `EQUAL` / `LIKE` — those are not arithmetic *operators* but partition rename: `PartitionMatchOperator`. In a flattened namespace, the parent context adds no value here. -### 7.2 `unmarshalPartitionSpecification_Partition_PartitionValueSchema` (model.ts:780) - -Schema variable name reaching 62 characters. Combined with the chained Zod -calls it dominates a screen. - -### 7.3 `marshalPartitionSpecification_Partition_PartitionValueSchema` (model.ts:1099) - -Same critique as 7.2. - -### 7.4 `unmarshalCleanRoomAsset_ForeignTableLocalDetailsSchema` (model.ts:561) - -55 characters; the `ForeignTable` qualifier could vanish if nested under -`CleanRoomAsset`. See also `unmarshalCleanRoomAsset_TableLocalDetailsSchema` -(607), `unmarshalCleanRoomAsset_ViewLocalDetailsSchema` (631), -`unmarshalCleanRoomAsset_VolumeLocalDetailsSchema` (641), -`unmarshalCleanRoomAsset_NotebookSchema` (571). Five sibling offenders. - -### 7.5 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator key (model.ts:330) +### 7.2 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator key (model.ts:330) The discriminated-union variant name *and* the inner property name are both `notebookReviewState`. Redundancy of `notebookReviewState` against the parent `reviewState` field could be elided. Suggested: `{$case: 'notebook', state: NotebookReviewState}`. -### 7.6 `runnerCollaboratorAliases` (model.ts:196) +### 7.3 `runnerCollaboratorAliases` (model.ts:196) Long composite, but accurate. Acceptable. -### 7.7 `reviewerCollaboratorAlias` (model.ts:256) +### 7.4 `reviewerCollaboratorAlias` (model.ts:256) Same. Acceptable. -### 7.8 `ownerCollaboratorAlias` (model.ts:98) +### 7.5 `ownerCollaboratorAlias` (model.ts:98) Same. Acceptable. -### 7.9 `recipientPropertyKey` (model.ts:446) +### 7.6 `recipientPropertyKey` (model.ts:446) Acceptable; needs the `recipient`/`property`/`key` qualifiers for accuracy. -(7.6–7.9 are kept under this category for completeness, but only flagged as +(7.3–7.6 are kept under this category for completeness, but only flagged as borderline — none should change.) --- ## 8. Redundant suffixes -### 8.1 `CleanRoomAsset_Status_Enum` (model.ts:46) - -The `_Enum` suffix is a Go-protobuf habit. The bare name `CleanRoomAsset_Status` -would be more idiomatic on the TS surface. - -### 8.2 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) +### 8.1 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) `NotebookReview` is repeated immediately after the underscore. Suggested rename: `CleanRoomNotebookReview_State`. -### 8.3 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) +### 8.2 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) Same redundancy. Suggested: `CleanRoomNotebookReview_SubReason`. @@ -302,10 +272,9 @@ but the type is plain `CleanRoomAsset`. Either the field should be `assets` ### 9.2 `listCleanRoomAssetRevisions` returning `revisions: CleanRoomAsset[]` (client.ts:255–270) -The iterator `listCleanRoomAssetRevisionsIter` yields `CleanRoomAsset` — same -mismatch as 9.1. Suggested either rename method to `listCleanRoomAsset` (which -collides with `getCleanRoomAsset`'s revision case) or introduce a wrapper -type. +The method yields `CleanRoomAsset` values — same mismatch as 9.1. Suggested +either rename method to `listCleanRoomAsset` (which collides with +`getCleanRoomAsset`'s revision case) or introduce a wrapper type. --- @@ -367,23 +336,12 @@ or both `*AtMillis`. ## 14. Go / Java-style names -### 14.1 `marshalCleanRoomAssetSchema` / `unmarshalCleanRoomAssetSchema` (model.ts:482, 812, plus ~20 siblings) - -`marshal` / `unmarshal` are Go's `encoding/json` vocabulary. TypeScript / -JavaScript convention is `serialize`/`deserialize`, `encode`/`decode`, or with -Zod simply `*Schema` / `*OutputSchema`. The generated TS surface re-exports -these helpers, so consumers see "unmarshal" in autocomplete — un-idiomatic. - -### 14.2 Snake-case wire keys in the schema bodies (`clean_room_name`, +### 14.1 Snake-case wire keys in the schema bodies (`clean_room_name`, `asset_type`, etc., model.ts:484–488 and elsewhere) — necessary for wire format, but they appear next to camelCase TS properties in the same `.transform(...)` call. The schema-level inputs intentionally look like Go field tags. Acceptable; flagging it for readers to know. -### 14.3 `Call` / `Options` types and `executeCall` (utils.ts:26) borrowed -verbatim from the Go SDK's `transport/call.go` style. The TS equivalent -would be `RequestFn` / `RequestOptions` / `runRequest`. Low-priority. - --- ## 15. Generic field names losing meaning @@ -473,17 +431,13 @@ Suggested rename: `assetName` everywhere — eliminates the cross-reference. ### 20.1 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) Enum *name* contains the type-suffix `State` while the parent already conveys -that this is the *state* of a notebook review. See 8.2. +that this is the *state* of a notebook review. See 8.1. ### 20.2 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) Same — `SubReason` is suffix-tautology with the parent's `Review`. -### 20.3 `CleanRoomAsset_Status_Enum` (model.ts:46) - -`_Enum` suffix is tautological with the keyword `enum`. See 8.1. - -### 20.4 `ColumnTypeName` (model.ts:5) +### 20.3 `ColumnTypeName` (model.ts:5) `TypeName` is *almost* tautology with `Column`; a column's type-name is just its *type*. Suggested rename: `ColumnType`. @@ -545,20 +499,20 @@ If the codegen template can't drop the prefix everywhere uniformly, the | Symbol | File:line | Issues | | ------ | --------- | ------ | -| `ColumnTypeName` | model.ts:5 | 20.4 (TypeName tautology), 16.1 (`TABLE_TYPE` / `TABLEREF_TYPE` contradict domain) | +| `ColumnTypeName` | model.ts:5 | 20.3 (TypeName tautology), 16.1 (`TABLE_TYPE` / `TABLEREF_TYPE` contradict domain) | | `ColumnTypeName.BOOLEAN`..`GEOGRAPHY` | model.ts:6–28 | clean | | `ColumnTypeName.TABLE_TYPE` | model.ts:31 | 16.1 | | `ColumnTypeName.TABLEREF_TYPE` | model.ts:32 | 16.1, also redundant `_TYPE` suffix on a value inside `ColumnTypeName` | | `CleanRoomAsset_AssetType` | model.ts:36 | 4.1, 20.x cross-cutting `CleanRoom` | | `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` | model.ts:37 | 2.1, 18.3 | | `CleanRoomAsset_AssetType.TABLE`..`FOREIGN_TABLE` | model.ts:38–42 | clean | -| `CleanRoomAsset_Status_Enum` | model.ts:46 | 8.1, 20.3, cross-cutting | +| `CleanRoomAsset_Status_Enum` | model.ts:46 | cross-cutting | | `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` | model.ts:47 | 2.2, 18.4 | | `CleanRoomAsset_Status_Enum.ACTIVE`/`PERMISSION_DENIED`/`PENDING` | model.ts:48–50 | clean | -| `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | 8.2, 20.1, cross-cutting | +| `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | 8.1, 20.1, cross-cutting | | `…_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` | model.ts:55 | 2.3, 18.1 | | `…_NotebookReviewState.APPROVED`/`REJECTED`/`PENDING` | model.ts:56–58 | clean | -| `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | 8.3, 20.2, cross-cutting | +| `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | 8.2, 20.2, cross-cutting | | `…_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` | model.ts:63 | 2.4, 18.2 | | `…_NotebookReviewSubReason.BACKFILLED`/`AUTO_APPROVED` | model.ts:64–65 | clean | | `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | 7.1 | @@ -573,7 +527,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `CleanRoomAsset.name` | model.ts:90 | 1.3, 15.1, 19.2 | | `CleanRoomAsset.assetType` | model.ts:92 | clean (but see 12.2) | | `CleanRoomAsset.addedAt` | model.ts:94 | 13.1 | -| `CleanRoomAsset.status` | model.ts:96 | typed `CleanRoomAsset_Status_Enum` — naming carries over (8.1) | +| `CleanRoomAsset.status` | model.ts:96 | clean | | `CleanRoomAsset.ownerCollaboratorAlias` | model.ts:98 | clean | | `CleanRoomAsset.localDetails` | model.ts:100 | 1.2, 12.4 | | `CleanRoomAsset.details` | model.ts:135 | 1.1, 1.7, 12.4 | @@ -582,7 +536,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `CleanRoomAsset_ForeignTableLocalDetails.localName` | model.ts:183 | clean (would be `ownerLocalName` to match `localDetails` semantics) | | `CleanRoomAsset_Notebook.notebookContent` | model.ts:192 | redundant `notebook` prefix inside `…_Notebook` — `content` suffices | | `CleanRoomAsset_Notebook.etag` | model.ts:194 | 19.1 | -| `CleanRoomAsset_Notebook.runnerCollaboratorAliases` | model.ts:196 | clean (verbose 7.6, acceptable) | +| `CleanRoomAsset_Notebook.runnerCollaboratorAliases` | model.ts:196 | clean (verbose 7.3, acceptable) | | `CleanRoomAsset_Notebook.reviews` | model.ts:198 | clean | | `CleanRoomAsset_Notebook.reviewState` | model.ts:200 | clean | | `CleanRoomAsset_Notebook.description` | model.ts:202 | clean | @@ -594,7 +548,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `CleanRoomAsset_ViewLocalDetails.localName` | model.ts:242 | clean | | `CleanRoomAsset_VolumeLocalDetails.localName` | model.ts:251 | clean | | `CleanRoomNotebookReview` | model.ts:254 | cross-cutting | -| `CleanRoomNotebookReview.reviewerCollaboratorAlias` | model.ts:256 | clean (verbose 7.7) | +| `CleanRoomNotebookReview.reviewerCollaboratorAlias` | model.ts:256 | clean (verbose 7.4) | | `CleanRoomNotebookReview.createdAtMillis` | model.ts:258 | 13.1 | | `CleanRoomNotebookReview.reviewState` | model.ts:260 | clean | | `CleanRoomNotebookReview.comment` | model.ts:262 | 15.5 | @@ -602,7 +556,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `ColumnInfo` | model.ts:267 | clean | | `ColumnInfo.name` | model.ts:269 | 1.4, 15.2 | | `ColumnInfo.typeText` | model.ts:271 | clean | -| `ColumnInfo.typeName` | model.ts:272 | 20.4 (carries from enum) | +| `ColumnInfo.typeName` | model.ts:272 | 20.3 (carries from enum) | | `ColumnInfo.position` | model.ts:274 | clean | | `ColumnInfo.typePrecision` | model.ts:276 | clean | | `ColumnInfo.typeScale` | model.ts:278 | clean | @@ -625,7 +579,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `…ReviewRequest.review` | model.ts:320 | discriminated union with one variant (`notebookReview`); see 6.1 | | `CreateCleanRoomAssetReviewResponse` | model.ts:325 | cross-cutting | | `…ReviewResponse.notebookReviews` | model.ts:327 | clean | -| `…ReviewResponse.reviewState` | model.ts:328 | discriminated union with one variant (`notebookReviewState`); see 7.5 | +| `…ReviewResponse.reviewState` | model.ts:328 | discriminated union with one variant (`notebookReviewState`); see 7.2 | | `DeleteCleanRoomAssetRequest` | model.ts:337 | cross-cutting | | `…DeleteRequest.cleanRoomName`/`assetType`/`name` | model.ts:339–343 | 12.x, 19.2 | | `GetCleanRoomAssetRequest` / `…RevisionRequest` | model.ts:353, 362 | cross-cutting | @@ -642,21 +596,12 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | 4.x, 7.1 | | `…PartitionValue.name` | model.ts:436 | 1.5, 15.3 | | `…PartitionValue.value` | model.ts:441 | 1.6, 15.4 | -| `…PartitionValue.recipientPropertyKey` | model.ts:446 | clean (verbose 7.9) | +| `…PartitionValue.recipientPropertyKey` | model.ts:446 | clean (verbose 7.6) | | `…PartitionValue.op` | model.ts:448 | 5.2, 6.3, 10.1 | | `PolicyFunctionArgument` | model.ts:457 | name "Argument" inside `PolicyFunction*` could be `PolicyFunctionArg` to align with field name `arg` (line 458) — currently inconsistent | | `PolicyFunctionArgument.arg` | model.ts:458 | abbreviation `arg` vs. parent `Argument`; pick one | | `UpdateCleanRoomAssetRequest.cleanRoomName` / `.asset` | model.ts:474–479 | 12.x | -### Schemas (model.ts:482 onward) - -All `marshal*Schema` / `unmarshal*Schema` constants inherit the issues of -their wrapped type (cross-cutting CleanRoom redundancy, `_` underscores, -verbose names — see 4.x and 7.x). Additionally: - -- The schemas use `clean_room_name` / `notebook_review_state` etc. as wire - names — that's the protocol layer and not a TS naming concern. - ### `client.ts` | Symbol | File:line | Issues | @@ -670,29 +615,11 @@ verbose names — see 4.x and 7.x). Additionally: | `deleteCleanRoomAsset` | client.ts:141 | cross-cutting | | `getCleanRoomAsset` | client.ts:169 | cross-cutting | | `getCleanRoomAssetRevision` | client.ts:194 | cross-cutting | -| `listCleanRoomAssetRevisions` / `…Iter` | client.ts:219, 255 | 9.2, cross-cutting | -| `listCleanRoomAssets` / `…Iter` | client.ts:273, 306 | cross-cutting | +| `listCleanRoomAssetRevisions` | client.ts:219 | 9.2, cross-cutting | +| `listCleanRoomAssets` | client.ts:273 | cross-cutting | | `updateCleanRoomAsset` | client.ts:327 | cross-cutting | | local helpers `call`, `httpReq`, `respBody`, `resp`, `url`, `fullUrl`, `params`, `query`, `headers`, `pageReq`, `item` | client.ts (various) | clean (short-scoped) | -### `utils.ts` - -| Symbol | File:line | Issues | -| ------ | --------- | ------ | -| `interface HttpCallOptions` | utils.ts:15 | clean | -| `HttpCallOptions.request` / `httpClient` / `logger` | utils.ts:16–18 | clean | -| `function executeCall(call, options?)` | utils.ts:26 | 14.3 (Go-style `executeCall`/`Call`/`Options`) | -| local `opts` | utils.ts:30 | clean | -| `function readAll(body)` | utils.ts:40 | clean | -| local `reader`, `chunks`, `done`, `value`, `totalLength`, `result`, `offset`, `chunk` | utils.ts (various) | clean | -| `function executeHttpCall(opts)` | utils.ts:65 | 14.3 | -| local `resp`, `body`, `apiErr` | utils.ts:73–88 | `apiErr` is the only abbreviation; matches the rest of the SDK | -| `function buildHttpRequest(method, url, headers, signal?, body?)` | utils.ts:96 | clean | -| local `req` | utils.ts:103 | clean | -| `function parseResponse(body, schema)` | utils.ts:113 | clean — though pairs awkwardly with `marshalRequest`/`unmarshal*Schema` vocabulary (14.1) | -| `function marshalRequest(data, schema)` | utils.ts:119 | 1.8, 14.1 | -| `function flattenQueryParams(prefix, value, params)` | utils.ts:123 | clean — but the function is exported and unused in `client.ts` (no caller in this package). Dead code / dead export. | - ### `index.ts` Re-exports only. All concerns flow from `model.ts` / `client.ts`. @@ -707,7 +634,7 @@ Re-exports only. All concerns flow from `model.ts` / `client.ts`. `index.ts`. Pick one. (Cross-cutting redundancy is the single biggest source of name length.) 2. **Collapse proto-nested types under namespaces or rename without - underscores.** All 18 `_`-bearing identifiers should follow the same + underscores.** All 17 `_`-bearing identifiers should follow the same convention as the rest of `@databricks/sdk-databricks`. 3. **Reconcile the `revisions: CleanRoomAsset[]` mismatch on `ListCleanRoomAssetRevisionsResponse`.** Either rename to `assets` or @@ -718,5 +645,3 @@ Re-exports only. All concerns flow from `model.ts` / `client.ts`. etc.) — six enum literals become two-word strings. 6. **Rename `op` → `operator` and `etag` → `revisionEtag`** in user-facing request types. -7. **Replace `marshal`/`unmarshal` with `encode`/`decode`** at the SDK - surface to align with JS idiom (Go vocabulary leak). diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md index 435e7057..4ee57a86 100644 --- a/.agent/naming-audit/cleanroomautoapprovalrules.md +++ b/.agent/naming-audit/cleanroomautoapprovalrules.md @@ -40,13 +40,6 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, - `UpdateCleanRoomAutoApprovalRuleRequest` (`autoApprovalRule?: CleanRoomAutoApprovalRule`) -### Schemas / marshalling helpers (exported from `model.ts`) - -- `unmarshalCleanRoomAutoApprovalRuleSchema` -- `unmarshalListCleanRoomAutoApprovalRulesResponseSchema` -- `marshalCleanRoomAutoApprovalRuleSchema` -- `marshalCreateCleanRoomAutoApprovalRuleRequestSchema` - ### `client.ts` - `class Client` @@ -61,8 +54,8 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### `utils.ts` - `interface HttpCallOptions` -- `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`, internal `readAll` +- Internal HTTP helpers (request building, response handling, query + flattening, etc.). ### `index.ts` @@ -242,19 +235,7 @@ export a more specific name (`AutoApprovalRulesClient`, `CleanRoomAutoApprovalRulesClient`). Either way, this is a *package-wide* decision; this audit just flags that the bare `Client` name is generic. -### 12. `listCleanRoomAutoApprovalRulesIter` — Category 7 (overly verbose) / Category 14 (Go-style name) - -The `Iter` suffix is a Go-ism (Go iterators historically end in `Iter`). -For async generators in TS, the idiomatic name is plural-of-resource (the -method already returns an `AsyncGenerator`), e.g., `listAllRules` / -`rulesIterator` / overload `list()` to return `AsyncIterable`. Even keeping -the suffix, dropping the long resource prefix (`listIter(...)` / -`iterRules(...)`) would shave 24 characters. JS callers do not need the -"Iter" disambiguator because `for await (const r of client.list(...))` -already signals iteration; a separate `listRulesPage(...)` could carry the -single-page behaviour if both shapes are needed. - -### 13. `nextPageToken` / `pageToken` are duplicated across the response and request — Category 12 (duplicate concepts) [informational] +### 12. `nextPageToken` / `pageToken` are duplicated across the response and request — Category 12 (duplicate concepts) [informational] `ListCleanRoomAutoApprovalRulesResponse.nextPageToken` and `ListCleanRoomAutoApprovalRulesRequest.pageToken` are wire-mandated and @@ -262,7 +243,7 @@ match the Databricks pagination convention. This is *not* a finding to act on — it is the standard pagination shape used across all packages. Logged for completeness because the prompt asks for an exhaustive scan. -### 14. Doc references undefined casing — Category 16 (field contradicting type domain) [minor] +### 13. Doc references undefined casing — Category 16 (field contradicting type domain) [minor] The JSDoc on `authorCollaboratorAlias` says: @@ -279,32 +260,30 @@ arm of `authors` should be populated"). Same issue on line 25 of `ListCleanRoomAutoApprovalRulesResponse.nextPageToken` says "`page_token` should be set", which should read `pageToken`. -### 15. Docs say "a auto-approval rule" — typo (not naming, but on JSDoc) [minor] +### 14. Docs say "a auto-approval rule" — typo (not naming, but on JSDoc) [minor] `client.ts:96`, `client.ts:115`, `client.ts:194` use `Delete a auto-approval`, `Get a auto-approval`, `Update a auto-approval`. The article should be `an`. This is generated text; flag it for the generator. Not strictly a naming issue, but it sits in the same area. -### 16. `Client` constructor field `userAgent` — Category 1 (vague) [minor] +### 15. `Client` constructor field `userAgent` — Category 1 (vague) [minor] `private readonly userAgent: string` (`client.ts:49`) holds the *value* of the `User-Agent` header. The name reads as a thing rather than a header value. `userAgentHeader` or `userAgentValue` is unambiguous. Minor — the JSDoc above the field explains it — but consistent with the audit's brief. -### 17. `utils.ts` is a kitchen-sink module name — Category 1 (vague/generic) +### 16. `utils.ts` is a kitchen-sink module name — Category 1 (vague/generic) -`utils.ts` houses `executeCall`, `executeHttpCall`, `buildHttpRequest`, -`parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, and -`HttpCallOptions`. Per the SDK's existing breakdown (see -`@databricks/sdk-core/api`, `.../apierror`, `.../http`, `.../logger`), these -helpers would normally live in a named module (e.g., `http.ts`, -`request.ts`). All sibling API packages emit the same `utils.ts`, so this is -a generator-level concern, not a per-package one. Flagged because the brief -asks about generic names. +The package's internal helpers all live in a single `utils.ts`. Per the SDK's +existing breakdown (see `@databricks/sdk-core/api`, `.../apierror`, +`.../http`, `.../logger`), these helpers would normally live in a named +module (e.g., `http.ts`, `request.ts`). All sibling API packages emit the +same `utils.ts`, so this is a generator-level concern, not a per-package +one. Flagged because the brief asks about generic names. -### 18. Method docstrings use "rule ID" inconsistently with field name — Category 6 (misleading names) [minor] +### 17. Method docstrings use "rule ID" inconsistently with field name — Category 6 (misleading names) [minor] JSDocs say "Delete a auto-approval rule by rule ID", "Get a auto-approval rule by rule ID", "Update a auto-approval rule by rule ID". The request @@ -312,7 +291,7 @@ fields are `ruleId` (camelCase). A reader scanning the docs sees "rule ID" and may search for a field called "rule ID" or "ID". Either keep "ruleId" verbatim in the prose or just say "by ID". -### 19. `cleanRoomName` is the identifier doing double duty — Category 19 (underspecified ID) [minor] +### 18. `cleanRoomName` is the identifier doing double duty — Category 19 (underspecified ID) [minor] The path identifier is the `cleanRoomName` (a URL segment). In other packages this is sometimes `cleanRoomId` (UUID) or a `metastoreId`. Here it @@ -327,24 +306,23 @@ finding 10. ## Themes / suggested resolution priority 1. **Verbosity from the package name leaking into every symbol.** Findings - 1, 2, 3, 4, 12. This is the dominant issue: `CleanRoomAutoApproval` + 1, 2, 3, 4. This is the dominant issue: `CleanRoomAutoApproval` appears in every type and method name even though it is already in the package import path. Strip the prefix and the surface area becomes about half as wide on screen. -2. **Proto/Go ergonomics surfacing in TS.** Findings 3, 4, 5, 6, 12. - `_`-joined enum names, `_UNSPECIFIED` sentinels, and `Iter`-suffixed - iterators are conventions imported from protobuf/Go that have no payoff - in TypeScript. +2. **Proto/Go ergonomics surfacing in TS.** Findings 3, 4, 5, 6. + `_`-joined enum names and `_UNSPECIFIED` sentinels are conventions + imported from protobuf/Go that have no payoff in TypeScript. 3. **Field-name ambiguity around identifiers and aliases.** Findings 7, 8, - 9, 10, 19. `authors`/`runners` are plural but always single; + 9, 10, 18. `authors`/`runners` are plural but always single; collaborator aliases are typed `string`; `ruleId` is a UUID typed `string`. Type aliases plus singular field names would cover all of these. -4. **Doc/identifier drift from the wire format.** Findings 14, 15, 18. JSDoc +4. **Doc/identifier drift from the wire format.** Findings 13, 14, 17. JSDoc text references `snake_case` field names and includes generated-text typos. These are docs-only fixes but they bear on naming clarity. 5. **Module-shape concerns** (only logged for awareness because the prompt - asked for an exhaustive sweep): findings 11, 16, 17. + asked for an exhaustive sweep): findings 11, 15, 16. --- diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index 3de2a400..8202bb23 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -12,7 +12,7 @@ grouped by category, and each finding cites the file/line where it appears. ## Summary -- **Total findings:** 60 +- **Total findings:** 49 - **Highest-impact themes:** 1. Proto-style nested enum/message names with embedded underscores (`CleanRoom_Status_Enum`, @@ -189,18 +189,6 @@ Same. Triple-segment Go-style nested enum name. - `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode` (model.ts:321) - `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination` (model.ts:332) -### 4.11 Marshal/unmarshal schema constants -- `unmarshalEgressNetworkPolicy_InternetAccessPolicySchema` (model.ts:494) -- `unmarshalEgressNetworkPolicy_InternetAccessPolicy_InternetDestinationSchema` - (model.ts:531) -- `unmarshalEgressNetworkPolicy_InternetAccessPolicy_LogOnlyModeSchema` (model.ts:553) -- `unmarshalEgressNetworkPolicy_InternetAccessPolicy_StorageDestinationSchema` - (model.ts:575) -- `marshalEgressNetworkPolicy_InternetAccessPolicySchema` (model.ts:718) -- `marshalEgressNetworkPolicy_InternetAccessPolicy_InternetDestinationSchema` (model.ts:755) -- `marshalEgressNetworkPolicy_InternetAccessPolicy_LogOnlyModeSchema` (model.ts:777) -- `marshalEgressNetworkPolicy_InternetAccessPolicy_StorageDestinationSchema` (model.ts:799) - The underscore-bearing identifiers radiate from the model file into the public re-exports in `index.ts` (lines 7–13, 20, 30–33), so the API surface is contaminated. @@ -299,20 +287,14 @@ Worst offenders: The same enums also have `UNSPECIFIED` members reaching 36 characters (`INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED`). -### 7.2 Marshal/unmarshal schema identifiers (model.ts:494, 531, 553, 575, -718, 755, 777, 799) -The constants `unmarshalEgressNetworkPolicy_InternetAccessPolicy_InternetDestinationSchema` -and its marshal mirror each weigh in at **84 characters**. They are -exported and survive in source as long lines that already wrap awkwardly. - -### 7.3 `CreateCleanRoomOutputCatalogResponse` (model.ts:263) / +### 7.2 `CreateCleanRoomOutputCatalogResponse` (model.ts:263) / `CreateCleanRoomOutputCatalogRequest` (model.ts:257) 36 characters each, but the underlying response body has a single field (`outputCatalog`). Could be `OutputCatalogResponse` if the operation context is unambiguous from the method signature. Probably keep — RPC naming convention. -### 7.4 `centralCleanRoomId?: string` (model.ts:228) +### 7.3 `centralCleanRoomId?: string` (model.ts:228) Inside `CleanRoomRemoteDetail`, the `central` adjective is redundant — the type itself describes the central clean room. `id` would suffice (subject to §1 generic-name caveat — perhaps `remoteId` if we keep the structure). @@ -321,28 +303,21 @@ to §1 generic-name caveat — perhaps `remoteId` if we keep the structure). ## 8. Redundant Suffixes -### 8.1 `CleanRoom_Status_Enum` (model.ts:61) -The `_Enum` suffix is tautological with the `enum` keyword. - -### 8.2 `CleanRoomOutputCatalog_OutputCatalogStatus` (model.ts:70) -The `OutputCatalogStatus` segment repeats `OutputCatalog`. `Status` alone -would work given the enclosing scope. - -### 8.3 `_InternetDestinationFilteringProtocol` (model.ts:87) and +### 8.1 `_InternetDestinationFilteringProtocol` (model.ts:87) and `_InternetDestinationType` (model.ts:93) Both append `InternetDestination*` to a type whose Go-style nested path already says `…_InternetDestination_…`. Pure repetition. -### 8.4 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) +### 8.2 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) `LogOnlyMode` appears twice in the same identifier. Same for `_StorageDestination_StorageDestinationType`. -### 8.5 `complianceSecurityProfile?: ComplianceSecurityProfile` (model.ts:246) +### 8.3 `complianceSecurityProfile?: ComplianceSecurityProfile` (model.ts:246) Field name is identical to the type name — repetition but consistent with the rest of the SDK style. (Mild — many ports do this.) -### 8.6 `outputCatalog?: CleanRoomOutputCatalog` (model.ts:164, 260, 264) -Same field-name-equals-type pattern as §8.5. +### 8.4 `outputCatalog?: CleanRoomOutputCatalog` (model.ts:164, 260, 264) +Same field-name-equals-type pattern as §8.3. --- @@ -381,7 +356,7 @@ Note: TypeScript's discriminated-union pattern often uses literal `type` — so this is a soft flag. ### 10.2 `status` field appears on `CleanRoom` and `CleanRoomOutputCatalog` -Not a reserved word; raised here to highlight the duplication. See §12. +Not a reserved word; raised here to highlight the duplication. See §11. --- @@ -437,27 +412,15 @@ positive example. ## 13. Go / Java / Proto-Style Names in TS ### 13.1 The nine `*_*_*` enum names and five `*_*_*` interface names -already enumerated in §4.1–§4.11 are direct Go/proto carryovers. The +already enumerated in §4.1–§4.10 are direct Go/proto carryovers. The `eslint-disable-next-line` comments explicitly acknowledge this with the phrase "Proto-style nested enum name" / "Proto-style nested message name." They are *the* defining stylistic deviation of this file. -### 13.2 The marshal/unmarshal naming -`marshalCleanRoomSchema`, `unmarshalCleanRoomSchema` (model.ts:371, 613) -follow Go naming (`Marshal` / `Unmarshal`). JS/TS idiom is -`serialize`/`deserialize`, `encode`/`decode`, or `to{Json,Wire}` / -`from{Json,Wire}`. This is a system-wide SDK choice and not unique to -cleanrooms, but worth flagging once. - -### 13.3 `CreateCleanRoomWaiter` (client.ts:289) +### 13.2 `CreateCleanRoomWaiter` (client.ts:289) "Waiter" is the Go SDK convention; in TS, `Poller` / `Watcher` / `Operation` (Azure-style) are more idiomatic. Inherited convention. -### 13.4 `req` parameter convention (client.ts:86, 111, 123, 160, 179, -207, 240, 264) -`req` is a Go SDK convention. TS norms favor explicit parameter names -(`request`) or destructuring. Minor. - --- ## 14. Generic Field Names Losing Meaning Out of Context @@ -522,10 +485,6 @@ same wart, but it surfaces here as inconsistent ergonomics: `(await c.createCleanRoom(...)).name` vs. `(await c.createCleanRoomOutputCatalog(...)).outputCatalog?.catalogName`. -### 16.2 `listCleanRoomsIter` (client.ts:239) -The `*Iter` suffix matches the Go SDK's iterator naming. TS norms suggest -`*Iterator`, `*AsyncIterable`, or returning a `Pager` object. Minor. - --- ## 17. Long Enum Values @@ -582,16 +541,12 @@ predicate. Combined with the field `accessRestricted: CleanRoom_AccessRestricted the result is `accessRestricted: AccessRestricted` — pure echo (the field adds no information beyond what the type name supplies). -### 19.2 `CleanRoom_Status_Enum` (model.ts:61) -The `_Enum` suffix is the canonical example of type-suffix tautology. -TS's `enum` keyword already conveys "this is an enum." - -### 19.3 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) and +### 19.2 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) and `_StorageDestination_StorageDestinationType` (model.ts:129) Type name segment appears twice. See §8. -### 19.4 `complianceSecurityProfile: ComplianceSecurityProfile` (model.ts:246) -See §8.5 — common pattern. +### 19.3 `complianceSecurityProfile: ComplianceSecurityProfile` (model.ts:246) +See §8.3 — common pattern. --- @@ -639,9 +594,6 @@ generic code. use correct plurality. - JSDoc is generally comprehensive — references to UC naming rules and external compliance documents are well-linked. -- The `executeCall`, `executeHttpCall`, `marshalRequest`, `parseResponse`, - `buildHttpRequest`, `flattenQueryParams` utilities in `utils.ts` have - short, clear, verb-driven names that survive idiomatically. - The `StillRunningError` class (client.ts:48) is concise and self-documenting. - The package-level segment naming (`PACKAGE_SEGMENT` in client.ts:43) @@ -662,8 +614,8 @@ output that this audit catalogs. If the SDK adopts a TS-idiomatic alias layer, the most leverage comes from: 1. Flattening or shortening the seven `EgressNetworkPolicy_*` enums - (eliminates §4.4–§4.9, §7.1, §17.3–§17.6, §19.2–§19.3). -2. Renaming `CleanRoom_Status_Enum` to `CleanRoomStatus` (§4.2, §8.1, §19.2). + (eliminates §4.4–§4.9, §7.1, §17.3–§17.6, §19.2). +2. Renaming `CleanRoom_Status_Enum` to `CleanRoomStatus` (§4.2). 3. Renaming `accessRestricted` -> `accessRestriction` and `CleanRoom_AccessRestricted` -> `AccessRestriction` (§6.2, §12.2, §19.1). 4. Renaming `remoteDetailedInfo` -> `details` or `remoteDetail` (§6.1) diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md index 1bb328ba..10f7965e 100644 --- a/.agent/naming-audit/cleanroomtaskruns.md +++ b/.agent/naming-audit/cleanroomtaskruns.md @@ -76,24 +76,7 @@ surface a TS consumer calls. It is also inconsistent across the SDK; this is a **P0 fix** for cross-package consistency (audit category 14: every other package uses camelCase `listX` style without Java/Go-style `Handler` decoration). -### 2. Redundant `RUN_` prefix on enum values — category 2 (Redundant enum prefixes) - -**Symbol:** `CleanRoomTaskRunLifeCycleState.RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, -`CleanRoomTaskRunResultState.RUN_RESULT_STATE_UNSPECIFIED` (model.ts:10, 27). - -**Issue:** Both enums are scoped under `…TaskRun…`. The leading `RUN_` repeats the -parent type's `Run` concept. The full reference `CleanRoomTaskRunLifeCycleState.RUN_LIFE_CYCLE_STATE_UNSPECIFIED` -contains `Run` twice and `LifeCycleState` twice. Same applies to -`RUN_RESULT_STATE_UNSPECIFIED`. - -**Suggested:** `UNSPECIFIED` (or `LIFE_CYCLE_STATE_UNSPECIFIED` / `RESULT_STATE_UNSPECIFIED` -if proto-wire compatibility forbids dropping more). Most other enums in the SDK use -the plain `UNSPECIFIED` form. Note however the values are also used as on-the-wire -JSON strings (see `z.enum(CleanRoomTaskRunLifeCycleState)` in model.ts:155), so -renaming requires the server to also accept the new spelling, and is a behavioural -change — record this as a request to the API team, not a unilateral TS change. - -### 3. `SCREAMING_SNAKE_CASE` enum values — category 4 (Underscores in TS identifiers) +### 2. `SCREAMING_SNAKE_CASE` enum values — category 4 (Underscores in TS identifiers) **Symbols:** Every value in both enums (model.ts:10–19, 27–40). @@ -127,18 +110,7 @@ Same shape for `CleanRoomTaskRunResultState`. This is consistent with the way th project's `.agent/rules/typescript.mdc` treats other enums (e.g. status enums in `apierror/codes`). -### 4. Long enum values — category 18 (Long enum values) - -**Symbols:** `MAXIMUM_CONCURRENT_RUNS_REACHED` (model.ts:32), `SUCCESS_WITH_FAILURES` -(model.ts:37), `RUN_LIFE_CYCLE_STATE_UNSPECIFIED` (model.ts:10), -`RUN_RESULT_STATE_UNSPECIFIED` (model.ts:27). - -**Issue:** Wire-format values can be left as-is, but TS identifiers should be -shorter. `MAXIMUM_CONCURRENT_RUNS_REACHED` → `MaxConcurrentRunsReached`. -`SUCCESS_WITH_FAILURES` → `SuccessWithFailures` (15 chars vs 21 with underscores). -Combine with finding 3. - -### 5. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) +### 3. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) **Symbols:** Enum `CleanRoomTaskRunLifeCycleState` and field `CleanRoomTaskRunState.lifeCycleState` (model.ts:9, 80). @@ -154,7 +126,7 @@ midword capital. Cross-check: the same `LifeCycle` casing exists in `jobs/v2/model.ts` (line 389) and other "Run" types across the SDK, so a fix must be globally coordinated. -### 6. `TIMEDOUT` is a non-word — category 6 (Misleading names) and category 13 +### 4. `TIMEDOUT` is a non-word — category 6 (Misleading names) and category 13 (Verb tense inconsistency) **Symbol:** `CleanRoomTaskRunResultState.TIMEDOUT` (model.ts:30). @@ -163,9 +135,9 @@ and other "Run" types across the SDK, so a fix must be globally coordinated. forming a real word. Adjacent values use correct past-tense English (`CANCELED`, `EVICTED`, `FAILED`, `SUCCEEDED`-style). The Go reference also uses `TIMEDOUT`, so this originates upstream; flag for protocol fix. The TS identifier -should be `TimedOut` regardless (combine with finding 3). +should be `TimedOut` regardless (combine with finding 2). -### 7. `etag` lowercase abbreviation — category 3 (Acronym casing) +### 5. `etag` lowercase abbreviation — category 3 (Acronym casing) **Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65) and wire field `notebook_etag` (line 133). @@ -179,7 +151,7 @@ elsewhere in the codebase (search `Etag|ETag` in `cleanrooms/v1`) the same lowercase form is used for the `etag` field on `CleanRoomsNotebookTask`. Mark as consistent within the codebase but worth re-examining at the SDK level. -### 8. `notebookEtag` belongs to the notebook, not the task run — category 16 +### 6. `notebookEtag` belongs to the notebook, not the task run — category 16 (Field contradicting type domain) **Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65). @@ -191,7 +163,7 @@ struct is mixing notebook metadata with run metadata. Consider whether these should live under a nested `notebook` sub-object (`notebook.etag`, `notebook.updatedAt`) in a future revision. Flag only — current shape mirrors Go. -### 9. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 +### 7. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 (Duplicate concepts) **Symbol:** `CleanRoomNotebookTaskRun.notebookJobRunState` (model.ts:52). @@ -213,7 +185,7 @@ inherited). (jobs/v2/model.ts:1158) which has the same shape with yet *another* spelling — flag both for coordinated renaming. -### 10. `runDuration` vs implicit "task run" — category 15 (Generic field names +### 8. `runDuration` vs implicit "task run" — category 15 (Generic field names losing meaning) **Symbol:** `CleanRoomNotebookTaskRun.runDuration` (model.ts:50). @@ -226,7 +198,7 @@ yet duration carries it. Inconsistent. milliseconds"). Or rename `startTime` → `runStartTime` for consistency — pick one side. -### 11. `outputSchemaExpirationTime` / `sharedOutputSchemaExpirationTime` — +### 9. `outputSchemaExpirationTime` / `sharedOutputSchemaExpirationTime` — verbose — category 7 (Overly verbose) **Symbols:** model.ts:63, model.ts:73. @@ -241,7 +213,7 @@ coexist: `…Time`, `…At`, and `runDuration` (numeric duration). Pick one. `startedAt` — or normalise all three to `…Time`. The `Run` pattern in other Databricks APIs leans toward `…At`. -### 12. `sharedOutputSchemaName` doc references missing `enable_shared_output` +### 10. `sharedOutputSchemaName` doc references missing `enable_shared_output` flag — category 6 (Misleading names) **Symbol:** `CleanRoomNotebookTaskRun.sharedOutputSchemaName` (model.ts:72). @@ -252,7 +224,7 @@ on the run struct. Either the doc references state stored elsewhere (probably on the clean-room asset config), or the field is missing. Not a naming bug, but flag for a doc rewording. -### 13. `CollaboratorJobRunInfo` repeats "collaborator" in every field — +### 11. `CollaboratorJobRunInfo` repeats "collaborator" in every field — category 8 (Redundant suffixes) and category 2 (Redundant prefixes) **Symbol:** `CollaboratorJobRunInfo` (model.ts:85). Fields: `collaboratorJobId`, @@ -269,7 +241,7 @@ where the prefix is meaningful at the *top* level (`run.collaboratorJobRunInfo.c TS access lands one level deeper than the natural reading; the prefix is duplicate. Match the JS idiom: drop the prefix on the nested fields. -### 14. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the +### 12. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 (Singular/plural mismatch on the broader concept) @@ -284,7 +256,7 @@ the struct *name* is therefore misleading; a more accurate name is `CollaboratorTaskRunRef` or `CollaboratorRunRef`. Flag for coordination with API team — the Go SDK has the same name. Cross-reference `jobs/v2` to align. -### 15. `Etag` doc text — category 4 (Underscores) and category 17 (Inconsistent +### 13. `Etag` doc text — category 4 (Underscores) and category 17 (Inconsistent action verbs) **Symbol:** Doc comment for `notebookEtag` (model.ts:64): "used to identify the @@ -293,7 +265,7 @@ notebook version". Not a naming issue per se, but the wire field is `notebook_etag`, surface field `notebookEtag`, and JSDoc uses "Etag" — three spellings in one field. Minor. -### 16. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type +### 14. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type `CleanRoomTaskRunState` — category 6 (Misleading names) **Symbols:** model.ts:78, model.ts:52. @@ -307,7 +279,7 @@ calls the same thing `NotebookTaskRunOutput.runState`. Suggest aligning on keep the type name as-is (the wider SDK uses `…State` types throughout, e.g. `RunState`, `JobState`). -### 17. `pageSize` doc contradicts behaviour — category 6 (Misleading names) +### 15. `pageSize` doc contradicts behaviour — category 6 (Misleading names) **Symbol:** `ListCleanRoomNotebookTaskRunsRequest.pageSize` (model.ts:104). @@ -319,7 +291,7 @@ in JSDoc with a `@deprecated` tag so IDEs show strike-through. Naming-wise: `pageSize` is fine *if* it works; document the no-op via the deprecation tag, not just a sentence inside the doc. -### 18. `runs` field in response — category 15 (Generic field names losing +### 16. `runs` field in response — category 15 (Generic field names losing meaning) — borderline acceptable **Symbol:** `ListCleanRoomNotebookTaskRunsResponse.runs` (model.ts:111). @@ -330,47 +302,16 @@ of the clean room.") is *wrong* — copy-paste error from the request struct's `cleanRoomName` doc. Doc-text bug, not a naming bug, but worth flagging during a naming pass since reviewers will notice the field while reading docs. -### 19. `nextPageToken` is the canonical name — pass. +### 17. `nextPageToken` is the canonical name — pass. No issue. Matches all other listing responses in the SDK. -### 20. `ListCleanRoomNotebookTaskRunsRequest` / `…Response` — category 7 -(Overly verbose) - -**Symbols:** model.ts:98, 109. - -**Issue:** At 36 / 37 characters these are among the longest type names in the -package. The names are accurate but heavy; within the package scope, just -`ListRequest` / `ListResponse` would suffice. However, the Go SDK pattern (mirrored -across the entire TS SDK) qualifies every request/response with the full operation -name, so this is consistent with the wider convention. Flag only — do not change -in isolation. - -### 21. Method name `listCleanRoomNotebookTaskRunsHandlerIter` is 41 chars — -category 7 (Overly verbose) - -**Symbol:** `Client.listCleanRoomNotebookTaskRunsHandlerIter` (client.ts:97). - -**Issue:** Combine with finding 1: drop `Handler` to land at -`listCleanRoomNotebookTaskRunsIter` (33 chars). The `Iter` suffix is the project's -canonical name for the async-iterator paginator (used in `cleanrooms`, -`cleanroomassets`, etc.) and should stay. Note: TS-idiomatic alternatives include -naming the iterator method without a suffix and using JSDoc to indicate it's an -iterator, but project convention is `Iter`. - -### 22. Function `listCleanRoomNotebookTaskRunsHandlerIter` plural "runs" inside -the async generator yielding singular `CleanRoomNotebookTaskRun` — category 9 -(Singular/plural mismatch) — *pass* - -The convention in the SDK is `list…Iter()` returns an `AsyncGenerator`, -so plural method name + singular yield is intentional and consistent. No fix. - -### 23. `Client` class name — category 1 (Vague/generic) — *pass* +### 18. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-cleanroomtaskruns/v1`). -### 24. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 19. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:27). @@ -383,56 +324,24 @@ used in every package's client.ts (verify: ran into it in `cleanrooms`, `cleanroomassets`, …) — it is a convention. Flag only for consistency, do not fix in isolation. -### 25. `userAgent` and `httpClient` — *pass* +### 20. `userAgent` and `httpClient` — *pass* Standard names; acronym handling is consistent (`Url` would be flagged but `HttpClient` is acceptable under the project rule and matches the imported type). -### 26. `marshalRequest` / `unmarshal*Schema` — category 14 (Go/Java-style names) - -**Symbols:** `marshalRequest` (utils.ts:119), the four `unmarshal*Schema` -constants (model.ts:119, 152, 163, 180). - -**Issue:** "Marshal" / "Unmarshal" is Go vocabulary. The TS ecosystem uses -"serialize" / "deserialize" or, when working with Zod, "parse" / "stringify". -This is a project-wide convention copied from Go; it is consistent here, but it -is a Go-ism. Flag for the broader SDK review, not this package alone. - -### 27. `flattenQueryParams` — *pass*, but unused (dead code) +### 21. `flattenQueryParams` — *pass*, but unused (dead code) **Symbol:** `flattenQueryParams` (utils.ts:123). **Issue:** Imported nowhere within this package's client (the `list` method builds its querystring inline at client.ts:64–72). The helper is dead code in this package. Naming itself is fine. Suggest deleting or extracting to a shared utility -in `@databricks/sdk-core/http`. (Same applies to `marshalRequest` — declared but -unused inside the package.) +in `@databricks/sdk-core/http`. -### 28. `executeCall` vs `executeHttpCall` — category 17 (Inconsistent action verbs) - -**Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). - -**Issue:** Two functions named `execute…Call`. `executeCall` is the public API -wrapper that calls `execute()` from `@databricks/sdk-core/api`. `executeHttpCall` -performs an HTTP request and decodes the body. They do *different* things at -*different* layers — but the names imply a hierarchical relationship that does not -exist. The HTTP one is roughly `sendAndDecode` or `doHttpRequest`. Flag for SDK-wide -naming cleanup; this file is generated boilerplate copied across every package. - -### 29. `readAll(body)` — *pass* +### 22. `readAll(body)` — *pass* Helper does what its name says. -### 30. `HttpCallOptions` (utils.ts:15) — category 1 (Vague) and category 20 -(Type-suffix tautology) - -**Symbol:** `HttpCallOptions` interface. - -**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the -neighbouring `CallOptions` exists in `@databricks/sdk-options/call`. Naming both -in the same file confuses readers — which "Call" do they mean? Suggest -`HttpRequestContext` or `ExecuteHttpArgs`. Flag for SDK-wide cleanup. - --- ## Cross-package notes (per audit instructions) @@ -473,12 +382,12 @@ service name — but a reader is left to guess. ## Summary (counts) - **Critical / cross-package consistency:** 1 finding (#1 `Handler` suffix). -- **High (style guide violations):** 3 findings (#3 enum casing, #5 LifeCycle - casing, #13 collaborator prefix repetition). -- **Medium (naming clarity):** 8 findings (#2, #6, #9, #10, #11, #14, #16, #17). -- **Low / project-wide convention notes:** 11 findings (#4, #7, #8, #12, #15, - #18, #19, #21, #24, #26, #27, #28, #29, #30) — some inherited from generator. -- **Pass / acceptable as-is:** 4 findings (#19, #22, #23, #25, #29). - -**Total flagged findings: 24** distinct items across 20 categories (some +- **High (style guide violations):** 3 findings (#2 enum casing, #3 LifeCycle + casing, #11 collaborator prefix repetition). +- **Medium (naming clarity):** 7 findings (#4, #7, #8, #9, #12, #14, #15). +- **Low / project-wide convention notes:** 7 findings (#5, #6, #10, #13, #16, + #19, #21) — some inherited from generator. +- **Pass / acceptable as-is:** 4 findings (#17, #18, #20, #22). + +**Total flagged findings: 18** distinct items across audit categories (some findings touch multiple categories). diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index 6ad9ebcd..a190403a 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -131,7 +131,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### 4.2 `InstallLibraries_Response` — `model.ts:156, 417` - Same pattern: proto-style nested name flattened by underscore. The eslint - comment acknowledges it. See also §20 (suffix redundancy). + comment acknowledges it. See also §19 (suffix redundancy). - Severity: high. ### 4.3 `UninstallLibraries_Response` — `model.ts:319, 536` @@ -140,11 +140,6 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### 4.4 `ListAllClusterLibraryStatuses_Response` — `model.ts:235, 467` - Same. Severity: high. -### 4.5 Marshal/unmarshal schema constants — `model.ts:417, 467, 536` -- `unmarshalInstallLibraries_ResponseSchema` and similar embed the - underscore. These follow the type names so they propagate the issue. -- Severity: medium (internal helpers, but still exported). - --- ## 5. Cryptic abbreviations @@ -189,10 +184,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### 6.2 `UpdateDefaultDefaultBaseEnvironmentRequest` — `model.ts:326` - Same problem on the request type. Severity: high. -### 6.3 `marshalUpdateDefaultDefaultBaseEnvironmentRequestSchema` — `model.ts:736` -- Same. Severity: high. - -### 6.4 `ClusterStatus` — `model.ts:63` +### 6.3 `ClusterStatus` — `model.ts:63` - The type holds only a `clusterId` and is used as the request body for `clusterStatus()`. Naming it `ClusterStatus` suggests it *is* the status, but it is a request that fetches status. Better: `ClusterStatusRequest` @@ -200,26 +192,26 @@ means it is awkward or inconsistent; "low" means a minor blemish. `ClusterLibraryStatuses` (correct). - Severity: high (the type name lies about its role). -### 6.5 `LibraryFullStatus` — `model.ts:220` +### 6.4 `LibraryFullStatus` — `model.ts:220` - "Full" implies there is a "Partial" or "Short" counterpart, but there is none in this package. The type is "the status of a library on a cluster" per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. - Severity: medium. -### 6.6 `LibraryInstallStatus` value `RESTORED` — `model.ts:42` +### 6.5 `LibraryInstallStatus` value `RESTORED` — `model.ts:42` - The docstring says "Library installation is restored and can be used." But `RESTORED` overlaps semantically with `INSTALLED`. Without further context (cache restore vs. fresh install), consumers cannot distinguish. Name is technically accurate but underspecified. - Severity: low. -### 6.7 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:35` +### 6.6 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:35` - This is the only value that is an action+condition (rather than a state noun). Surrounding values are `PENDING`, `INSTALLED`, `FAILED`. A noun form like `PENDING_UNINSTALL` would line up. - Severity: medium. -### 6.8 `allClusterStatuses()` — `client.ts:91` +### 6.7 `allClusterStatuses()` — `client.ts:91` - Method is the GET for `all-cluster-statuses`. The TS method name reads like an adjective ("all-cluster statuses") and is not verb-prefixed. Sibling method is `clusterStatus()` (also verb-less). Compare with the @@ -227,29 +219,29 @@ means it is awkward or inconsistent; "low" means a minor blemish. `createDefaultBaseEnvironment`, etc. (all verb-prefixed). The two GET methods alone are exempt. Should be `listAllClusterStatuses` or `getAllClusterStatuses`, and `getClusterStatus` respectively. -- Severity: medium. See also §16. +- Severity: medium. See also §15. -### 6.9 `Environment` — `model.ts:114` +### 6.8 `Environment` — `model.ts:114` - Type name is generic but the comment makes clear it is the "environment spec" used in serverless side-panel / job-task / pipeline contexts. A more specific name like `EnvironmentSpec` or `WorkspaceEnvironment` would avoid collisions with the JS global `process.env` mental model. - Severity: low. -### 6.10 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` +### 6.9 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` - The JSDoc says "when the materialized env is updated" — sufficient but the type itself does not carry the materialized payload (e.g., a hash, ID, or contents). The name overpromises relative to the contents; `EnvironmentCacheEntry` would be more honest. - Severity: medium. -### 6.11 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` — `model.ts:101` +### 6.10 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` — `model.ts:101` - "Indefinite" is unexplained anywhere in the file. It pairs with `materializedEnvironment` but the semantic distinction is opaque. The name needs a doc or rename. - Severity: medium. -### 6.12 `Environment.baseEnvironment` — `model.ts:131` +### 6.11 `Environment.baseEnvironment` — `model.ts:131` - A field inside `Environment` is also named `baseEnvironment` (same root word), which makes the relationship between the type and the field recursive-looking even though the field is just a path/ID string. @@ -260,18 +252,14 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 7. Overly verbose names -### 7.1 `marshalUpdateDefaultDefaultBaseEnvironmentRequestSchema` — `model.ts:736` -- 50 characters of identifier, of which much is redundant ("Default" twice). - See §6.1. Severity: medium. - -### 7.2 `unmarshalListAllClusterLibraryStatuses_ResponseSchema` — `model.ts:467` -- 53 characters and includes both an underscore (§4) and "All" (which is - also encoded in the URL `/api/2.0/libraries/all-cluster-statuses`). The - type name `ListAllClusterLibraryStatuses` is itself verbose — `ListLibraryStatuses` or - `ListClusterStatuses` would suffice. +### 7.1 `ListAllClusterLibraryStatuses_Response` — `model.ts:235` +- Underscored response type whose name embeds "All" (which is also encoded + in the URL `/api/2.0/libraries/all-cluster-statuses`). The type name + `ListAllClusterLibraryStatuses` is itself verbose — `ListLibraryStatuses` + or `ListClusterStatuses` would suffice. See also §4.4. - Severity: medium. -### 7.3 `UninstallLibraries_Response`, `InstallLibraries_Response` — `model.ts:156, 319` +### 7.2 `UninstallLibraries_Response`, `InstallLibraries_Response` — `model.ts:156, 319` - Verbose, underscored names. See §4. - Severity: medium. @@ -279,26 +267,18 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 8. Redundant suffixes -### 8.1 Marshal/unmarshal schemas — `model.ts:331-746` -- All schemas end with `Schema`, but they are typed `z.ZodType<...>` which - already conveys their schema nature. Inside the file the suffix may aid - reading, but on a wide API surface `unmarshalLibrarySchema` reads as - "Schema schema". Common enough in zod codebases that this is borderline - acceptable; flagged for completeness. -- Severity: low. - -### 8.2 `LibraryFullStatus` — `model.ts:220` -- "Full" is a vestigial qualifier with no counterpart. See §6.5. +### 8.1 `LibraryFullStatus` — `model.ts:220` +- "Full" is a vestigial qualifier with no counterpart. See §6.4. - Severity: medium. -### 8.3 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +### 8.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` - Field name repeats the parent's middle word (Library). Could simply be `statuses`. Borderline acceptable for clarity. - Severity: low. -### 8.4 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` +### 8.3 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` - Field is just `statuses` while the type bakes in `LibraryStatuses` - plurality and `ClusterLibrary` qualifier. Inconsistent with §8.3 which + plurality and `ClusterLibrary` qualifier. Inconsistent with §8.2 which uses `libraryStatuses`. - Severity: low. @@ -316,7 +296,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. — `model.ts:232, 237` - Singular method name `allClusterStatuses` (`client.ts:91`) for what is semantically a list operation. Compare `listDefaultBaseEnvironments` - (`client.ts:276`). The action verb should be `list` for both. See §16. + (`client.ts:276`). The action verb should be `list` for both. See §15. - Severity: medium. ### 9.3 `DefaultBaseEnvironment.baseEnvironmentCache` — `model.ts:93` @@ -366,12 +346,6 @@ means it is awkward or inconsistent; "low" means a minor blemish. consumers face a name-soup. No surface fix; flagged for awareness. - Severity: low. -### 11.4 `marshalRequest` vs implicit `JSON.stringify` — `utils.ts:119` -- Helper validates with zod then stringifies. Name suggests it could be - used for any "request", but it is generic enough to marshal any value. - Misleading-by-narrowing. `marshalToJson` would be clearer. (Utility scope.) -- Severity: low. - --- ## 12. Verb-tense inconsistency @@ -385,13 +359,13 @@ means it is awkward or inconsistent; "low" means a minor blemish. use verb-prefixed forms. - Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: `listAllClusterStatuses` (or `getAllClusterStatuses`) and - `getClusterStatus`. See §6.8 and §16. + `getClusterStatus`. See §6.7 and §15. - Severity: high (consistency of the verb-prefix is a Java/TS SDK convention that consumers rely on). ### 12.2 `LibraryInstallStatus` action vs state values — `model.ts:13` - Values mostly nouns (`PENDING`, `INSTALLED`, `FAILED`) but one verb - imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §6.7. + imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §6.6. - Severity: medium. --- @@ -409,14 +383,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### 13.2 `DefaultBaseEnvironmentCache_Status` — `model.ts:46` - Same. Severity: high. -### 13.3 `marshalRequest` / `parseResponse` / `executeHttpCall` — `utils.ts` -- Function names follow Go/Java SDK convention (verbs). Fine for TS too. - -### 13.4 Schema variable casing — `model.ts:331+` -- `marshalXxxSchema` / `unmarshalXxxSchema` constants follow Go SDK casing - conventions. Idiomatic enough in TS but the lengths get long (§7.2). - -### 13.5 `Library.lib` discriminator field — `model.ts:159` +### 13.3 `Library.lib` discriminator field — `model.ts:159` - `$case` literal on the discriminator is a ts-proto / nanopb-style emission (e.g., the same pattern as ts-proto's discriminated union output). Not unidiomatic for TS, but `kind`, `type`, or `tag` would be more readable @@ -455,39 +422,15 @@ means it is awkward or inconsistent; "low" means a minor blemish. --- -## 15. Field contradicting type domain - -### 15.1 `Environment.client` — `model.ts:116` -- "Client" inside an Environment spec is unexpected; the doc clarifies it - is a deprecated stand-in for `environment_version`. The name belongs to - a different semantic domain (clients connect to environments, they are - not part of them). -- Severity: medium (deprecated, but exposed). - -### 15.2 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:228` -- Inside `LibraryFullStatus` (per-cluster status), a field that describes - whether the library is configured cluster-wide. The name reads like a - global property but the type belongs to a single cluster's view. Better: - `installedOnAllClusters` or `isClusterWideLibrary`. -- Severity: medium. - -### 15.3 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` -- Type is "materialized environment metadata"; the only field is a - timestamp. The materialization payload is missing — see §6.10. The - timestamp belongs in a cache-entry type, not a materialization type. -- Severity: medium. - ---- - -## 16. Inconsistent action verbs +## 15. Inconsistent action verbs -### 16.1 GET vs `list` vs `all` — `client.ts:91, 276` +### 15.1 GET vs `list` vs `all` — `client.ts:91, 276` - `allClusterStatuses()` (verb `all`) is structurally identical to `listDefaultBaseEnvironments()` (verb `list`). Pick one. The Go SDK uses the same naming, but the TS port has the opportunity to normalize. - Severity: medium (see §12.1). -### 16.2 `refreshDefaultBaseEnvironments` — `client.ts:333` +### 15.2 `refreshDefaultBaseEnvironments` — `client.ts:333` - `refresh` is a TS-idiomatic verb meaning re-fetch / re-compute. The operation here regenerates a cache asynchronously. Borderline OK, but consumers may expect `refresh()` to return updated data; this returns @@ -495,25 +438,49 @@ means it is awkward or inconsistent; "low" means a minor blemish. reflect the side-effect more honestly. - Severity: low. -### 16.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL — `client.ts:433` +### 15.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL — `client.ts:433` - The URL says `:setDefault` but the method says `updateDefaultDefault`. `setDefaultBaseEnvironment` or `setWorkspaceDefault` would mirror the URL semantics. See §6.1. - Severity: high. -### 16.4 `installLibraries` / `uninstallLibraries` — `client.ts:250, 368` +### 15.4 `installLibraries` / `uninstallLibraries` — `client.ts:250, 368` - Symmetric pair, good. Mirror request types `InstallLibraries` / `UninstallLibraries` (named after the operation, not the resource). Consistent. --- +## 16. Field contradicting type domain + +### 16.1 `Environment.client` — `model.ts:116` +- "Client" inside an Environment spec is unexpected; the doc clarifies it + is a deprecated stand-in for `environment_version`. The name belongs to + a different semantic domain (clients connect to environments, they are + not part of them). +- Severity: medium (deprecated, but exposed). + +### 16.2 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:228` +- Inside `LibraryFullStatus` (per-cluster status), a field that describes + whether the library is configured cluster-wide. The name reads like a + global property but the type belongs to a single cluster's view. Better: + `installedOnAllClusters` or `isClusterWideLibrary`. +- Severity: medium. + +### 16.3 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` +- Type is "materialized environment metadata"; the only field is a + timestamp. The materialization payload is missing — see §6.9. The + timestamp belongs in a cache-entry type, not a materialization type. +- Severity: medium. + +--- + ## 17. Long enum values ### 17.1 `LibraryInstallStatus.UNINSTALL_ON_RESTART` — `model.ts:35` - 20 characters; the only multi-word value. Acceptable since it conveys semantics, but combined with the prefix `LibraryInstallStatus.` the - full reference is 41 characters. See also §6.7. + full reference is 41 characters. See also §6.6. - Severity: low. ### 17.2 `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — `model.ts:7` @@ -583,7 +550,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: low. ### 19.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` -- Already noted in §8.3. +- Already noted in §8.2. - Severity: low. ### 19.3 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` @@ -604,40 +571,38 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### High-severity (consumer-facing surprises) - `updateDefaultDefaultBaseEnvironment` / `UpdateDefaultDefaultBaseEnvironmentRequest` - / `marshalUpdateDefaultDefaultBaseEnvironmentRequestSchema` (§6.1, §6.2, - §6.3): the "Default Default" doubling is the most jarring naming in the - package. Best resolved by renaming the public API to + (§6.1, §6.2): the "Default Default" doubling is the most jarring naming + in the package. Best resolved by renaming the public API to `setWorkspaceDefaultBaseEnvironment`. - All `_Response` and `_Status` underscore types (§4, §13.1): non-idiomatic in TS, repeatedly exported, every importer sees them. - `PythonPyPiLibrary` brand-casing inconsistency (§3.1): "PyPi" misspells the PyPI brand. -- `ClusterStatus` request type misleading-as-response (§6.4). +- `ClusterStatus` request type misleading-as-response (§6.3). - `baseEnvironmentCache: DefaultBaseEnvironmentCache[]` singular-on-array (§9.3). - `package` reserved-word collision on PyPI and CRAN libraries (§10.1). - Verb-tense gap: `allClusterStatuses()` and `clusterStatus()` break the - client's prevailing verb-prefix convention (§12.1, §16.1). + client's prevailing verb-prefix convention (§12.1, §15.1). ### Medium-severity - Enum values embedding the enum name (§2.1, §2.2). -- `LibraryFullStatus` with no "non-full" counterpart (§6.5). +- `LibraryFullStatus` with no "non-full" counterpart (§6.4). - `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state - (§6.7, §12.2). -- `MaterializedEnvironment` containing only a timestamp (§6.10). + (§6.6, §12.2). +- `MaterializedEnvironment` containing only a timestamp (§6.9). - `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` - unexplained (§6.11). + unexplained (§6.10). - `isLibraryForAllClusters` field name awkwardly straddles per-cluster - and global domains (§15.2). + and global domains (§16.2). ### Low-severity / stylistic - `repo` vs `repository` short form (§1.5). - `whl`, `jar`, `egg` extension-as-field-name (§5.1). - `filepath` one-word concatenation (§5.4). -- Schema constants' `Schema` suffix (§8.1). -- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§6.6). +- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§6.5). - "dependences" typo in `MavenLibrary.exclusions` doc (§9.1). --- diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index 42224c35..a54c2729 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -126,8 +126,7 @@ rubric. Issues are graded: | V-02 | `MavenLibrary.repo`, `RCranLibrary.repo`, `PythonPyPiLibrary.repo` | Medium | `repo` is generic and overloaded across types. For Maven it is a Maven repository URL; for CRAN it is a CRAN mirror; for PyPI it is a pip index. Renaming to `repositoryUrl` (or even `mavenRepoUrl` / `cranMirrorUrl` / `pipIndexUrl`) would be more self-describing. | | V-03 | `Policy.definition`, `CreatePolicy.definition`, `EditPolicy.definition` | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it's unclear it's a JSON document. `policyDefinition` (matches `policyFamilyDefinitionOverrides`) would be self-consistent. | | V-04 | `Policy.description`, `CreatePolicy.description`, `EditPolicy.description` | Low | Generic but standard across the SDK; acceptable. | -| V-05 | `parseResponse` (utils) | Low | Generic, but it's local to the package. Acceptable. | -| V-06 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | ### 2.2 Redundant enum prefixes — High @@ -143,7 +142,7 @@ abbreviations and don't repeat the enum prefix. | ID | Symbol | Severity | Issue | | ----- | --------------------- | -------- | ----- | -| A-01 | `PythonPyPiLibrary` | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. Also affects the schema names `unmarshalPythonPyPiLibrarySchema` / `marshalPythonPyPiLibrarySchema`. | +| A-01 | `PythonPyPiLibrary` | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. | | A-02 | `RCranLibrary` | Medium | "CRAN" is an acronym ("Comprehensive R Archive Network"). The type uses `Cran` (PascalCase) which is acceptable under Google TS style (acronyms ≥3 chars → only first letter capitalised). However, the JSDoc and surrounding usage refers to "CRAN library". Consistent with the rule but worth noting — peer types like `PolicySortColumn` keep full uppercase in member names. Leave as-is for Google style compliance. | | A-03 | `RCranLibrary` — prefix `R` | Low | The leading lone `R` (the language) is awkward; the Go SDK uses the same name so this is a porting constraint. | | A-04 | `pypi` discriminator case (`Library.lib.$case === 'pypi'`) | Low | Lowercased, matching API wire format; consistent with `jar`, `egg`, `cran`, `maven`. Acceptable. | @@ -156,8 +155,7 @@ abbreviations and don't repeat the enum prefix. | U-02 | `DeletePolicy_Response` | High | Same as U-01. | | U-03 | `EditPolicy_Response` | High | Same as U-01. | | U-04 | `ListPolicies_Response` | High | Same as U-01. | -| U-05 | `unmarshalCreatePolicy_ResponseSchema` (and 3 siblings) | High | Same naming-convention violation cascades through the schema constants. | -| U-06 | Enum member identifiers (`POLICY_CREATION_TIME`, `POLICY_NAME`) | Low | `SCREAMING_SNAKE_CASE` is acceptable for enum members under Google style (matches API wire values). Not a violation, just noted. | +| U-05 | Enum member identifiers (`POLICY_CREATION_TIME`, `POLICY_NAME`) | Low | `SCREAMING_SNAKE_CASE` is acceptable for enum members under Google style (matches API wire values). Not a violation, just noted. | ### 2.5 Cryptic abbreviations — Medium @@ -176,7 +174,6 @@ abbreviations and don't repeat the enum prefix. | ----- | ----------------------------------- | -------- | ----- | | M-01 | `EditPolicy` / `editPolicy()` | High | Standard CRUD verbs in TS/REST are **create / read / update / delete**. The Databricks "Cluster Policies 2.0" API uses `/edit` as the wire path, but the SDK could still expose `updatePolicy` (with `UpdatePolicy` request type) which is the conventional REST verb. Compare with the newer `policies` API surface and most other Databricks SDK resources that expose `update*`. As-is, the SDK exposes `editPolicy` while peer packages (e.g. `clusters`) often expose `editCluster` too — there is precedent — but it remains inconsistent with the broader CRUD vocabulary. Tracked here as a discrepancy worth raising upstream. | | M-02 | `MavenLibrary.exclusions` (JSDoc says "List of dependences to exclude") | Low | Typo in the JSDoc ("dependences"); not a name issue per se. | -| M-03 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | ### 2.7 Overly verbose / Redundant suffixes — Medium @@ -185,9 +182,8 @@ abbreviations and don't repeat the enum prefix. | O-01 | `policyFamilyDefinitionOverrides` | Medium | Five-word camel-case identifier. Inherited from the API; very long but no shorter form is unambiguous. Accept as upstream constraint. | | O-02 | `createdAtTimestamp` | High | "Timestamp" is redundant — `createdAt` is the universal convention for epoch-millisecond fields (and the JSDoc says "in millisecond"). `createdAtTimestamp` is a tautology (`*-At` already implies a time value). | | O-03 | `creatorUserName` | Medium | Three words for "creator". `creator` alone would suffice if the value is a username; `createdBy` is the convention used elsewhere in the Databricks SDK. | -| O-04 | `unmarshalCreatePolicy_ResponseSchema` | Medium | The pattern `unmarshalSchema` triple-states intent ("schema for unmarshalling X"). The repo-wide convention probably can't change here, but each constant runs ~38 chars. | -| O-05 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | -| O-06 | `Policy.maxClustersPerUser` | Low | Long but precise. | +| O-04 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-05 | `Policy.maxClustersPerUser` | Low | Long but precise. | ### 2.8 Singular / plural mismatches — Low @@ -230,9 +226,8 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `CreatePolicy_Response` (proto nested-message style) | High | This is a direct port of Go's `pb.CreatePolicyResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `CreatePolicyResponse`. | -| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**). New TS readers will look up "marshal" before they recognise it. Repo-wide convention; flagged once per package. | -| G-03 | `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.20 for the type-suffix tautology angle. | -| G-04 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | +| G-02 | `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | +| G-03 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | ### 2.14 Generic field names losing meaning — Medium @@ -290,9 +285,8 @@ _None._ | X-02 | `Library.lib.$case` literal `'requirements'` | Low | The discriminator value `'requirements'` is the longest in the union (12 chars) and contrasts with three-letter peers (`jar`, `egg`, `whl`). Consistent with wire format, OK. | | X-03 | `HttpCallOptions` (utils) | Low | Local interface; precise. | | X-04 | `executeHttpCall`, `executeCall` | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | -| X-05 | `marshalRequest` (utils) | Low | Generic for "marshal arbitrary request body". OK in context. | -| X-06 | `readAll` (utils, private) | Low | Reads a `ReadableStream` to a `Uint8Array`. Standard name. | -| X-07 | `flattenQueryParams` (utils, exported but unused in this package?) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | +| X-05 | `readAll` (utils, private) | Low | Reads a `ReadableStream` to a `Uint8Array`. Standard name. | +| X-06 | `flattenQueryParams` (utils, exported but unused in this package?) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | --- @@ -302,19 +296,19 @@ _None._ | Severity | Count | | -------- | ----- | -| High | 11 | -| Medium | 21 | -| Low | 25 | -| **Total**| **57**| +| High | 10 | +| Medium | 18 | +| Low | 23 | +| **Total**| **51**| ### 3.2 Top themes 1. **Proto-style `_Response` suffix pollutes every CRUD response type.** - Five interfaces (`CreatePolicy_Response`, `DeletePolicy_Response`, - `EditPolicy_Response`, `ListPolicies_Response`, plus the schema constants) - each require an `eslint-disable` for the naming-convention rule. Renaming - to TS-idiomatic `CreatePolicyResponse` etc. would eliminate ~9 - disable-comments and a Google-style violation in one sweep. + Four interfaces (`CreatePolicy_Response`, `DeletePolicy_Response`, + `EditPolicy_Response`, `ListPolicies_Response`) each require an + `eslint-disable` for the naming-convention rule. Renaming to TS-idiomatic + `CreatePolicyResponse` etc. would eliminate disable-comments and a + Google-style violation in one sweep. 2. **`Library.lib` repeats the type stem in its discriminator field.** Callers write `library.lib?.$case` — `lib` adds no information the type @@ -343,9 +337,6 @@ section is advisory for the codegen owners) ### 3.4 Cross-package consistency notes -- The `marshal*` / `unmarshal*` schema-naming convention is consistent with - peer packages (e.g. `clusters`, `clusterlibraries`) and is therefore a - repo-wide concern, not a per-package fix. - The `Proto-style nested message name` `_Response` suffix is consistent with peers and should be addressed at the codegen level. - `editPolicy` (vs `updatePolicy`) is a per-API decision driven by the diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index cc1b2750..87879fe9 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -3,15 +3,15 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 **Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 87 +**Total weird names flagged:** 84 ## Summary | Severity | Count | | --- | --- | | High | 19 | | Medium | 32 | -| Low | 26 | -| Observation | 10 | +| Low | 24 | +| Observation | 9 | ## High severity @@ -102,7 +102,7 @@ ### 15. `ClusterInfo_ComputeSpec_CustomTagsEntry`, `ClusterInfo_SparkConfEntry`, etc. — 16 underscore-laden map-entry types - **Why weird:** 16 interfaces with names like `ClusterInfo_ComputeSpec_CustomTagsEntry` (`model.ts:1412`), `ClusterInfo_ComputeSpec_SparkConfEntry` (`model.ts:1429`), `ClusterInfo_ComputeSpec_SparkEnvVarsEntry` (`model.ts:1436`), `ClusterInfo_CustomTagsEntry`, `ClusterInfo_DefaultTagsEntry`, `ClusterInfo_SparkConfEntry`, `ClusterInfo_SparkEnvVarsEntry`, `CreateCluster_CustomTagsEntry`, `CreateCluster_SparkConfEntry`, `CreateCluster_SparkEnvVarsEntry`, `EditCluster_CustomTagsEntry`, `EditCluster_SparkConfEntry`, `EditCluster_SparkEnvVarsEntry`, `UpdateCluster_UpdateClusterResource_CustomTagsEntry`, `UpdateCluster_UpdateClusterResource_SparkConfEntry`, `UpdateCluster_UpdateClusterResource_SparkEnvVarsEntry`. Each carries the same `{key?: string; value?: string}` shape — sixteen distinct names for one concept. - **Category:** 4 (underscores), 12 (duplicate concepts — same `{key, value}` shape 16 times). -- **Suggested name:** Consolidate around the wire-equivalent `Record` form already used by the parent fields and marshal/unmarshal schemas. +- **Suggested name:** Consolidate around the wire-equivalent `Record` form already used by the parent fields. - **Rationale:** These types exist only because protobuf models maps as repeated `Entry` messages. TypeScript has built-in `Record<>` — sixteen separate `{key, value}` types for the same concept is pure proto-style duplication. ### 16. `UpdateCluster_UpdateClusterResource` — `src/v2/model.ts:2590` @@ -469,59 +469,43 @@ - **Suggested name:** `Autoscale` (one word, matching the field). - **Rationale:** Matches sibling naming (`autoscale: Autoscale`). -### 76. `*FieldMaskSchema` constants — `src/v2/model.ts:4247-4413` -- **Why weird:** 13 lowerCase-starting consts named `autoScaleFieldMaskSchema`, `awsAttributesFieldMaskSchema`, etc. These are internal to the package. `updateCluster_UpdateClusterResourceFieldMaskSchema` (line 4329) carries the underscore from its parent type. Pure scaffolding. -- **Category:** 4 (underscore), Observation (internal scaffolding). -- **Suggested name:** No public API impact; flagged for completeness. -- **Rationale:** Generated content. - -### 77. `marshalX` / `unmarshalX` verb asymmetry — `utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) and `marshalRequest` (encode) — same pair-asymmetry noted in `abacpolicies.md` audit. `parseResponse` reads the body, `marshalRequest` writes it. Names are non-mirrored verbs. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse`/`marshalRequest` or `parseResponse`/`serializeRequest`. -- **Rationale:** Pair-wise verb consistency aids reading. - ## Observations -### 78. Seven Waiter classes with identical shape — `client.ts:879-1435` +### 76. Seven Waiter classes with identical shape — `client.ts:879-1435` The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState_ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. - **Category:** 12 (duplicate concept across seven classes), Observation. - **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. -### 79. `_req` parameter for empty request types — `client.ts:343,422,447` +### 77. `_req` parameter for empty request types — `client.ts:343,422,447` Several methods take a `_req: ListAvailableZones` / `_req: ListNodeTypes` / `_req: GetSparkVersions` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. - **Category:** Observation (generator artefact). -### 80. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` +### 78. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` - **Why weird:** Three sibling booleans use `enable*` prefix. `is*` is the more idiomatic JS boolean convention. Inconsistent with `isSingleNode`, `isCompliant`, `isDeprecated`. - **Category:** 17 (mixed `enable*` and `is*` for booleans). - **Rationale:** Naming-convention drift. -### 81. `ResizeCluster` / `RestartCluster` requests are partial overlaps +### 79. `ResizeCluster` / `RestartCluster` requests are partial overlaps `ResizeCluster` carries `clusterId` and `size`; `RestartCluster` carries `clusterId` and `restartUser`; `StartCluster` carries only `clusterId`. Three near-identical types; could be one. - **Category:** 12 (duplicate concept), Observation. -### 82. `marshal*Schema` / `unmarshal*Schema` constants are individually named per type — 35 marshal + 35 unmarshal exports -Naming follows `marshalXxxSchema` / `unmarshalXxxSchema`. Convention is consistent but the underscored proto-style nesting carries over (`unmarshalEnforcePolicyComplianceForCluster_Response_ClusterSettingsChangeSchema` is a 67-character identifier). -- **Category:** 7 (overly verbose), Observation. - -### 83. `_req` unused vs `req` used — inconsistency in method-signature lint +### 80. `_req` unused vs `req` used — inconsistency in method-signature lint Five client methods use `_req` (where the request type is empty), 15 use `req` (where it's not). Pure mechanical. - **Category:** Observation. -### 84. `clusterId?: string | undefined` shape +### 81. `clusterId?: string | undefined` shape Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:204,246,296,565,604,651,729`). - **Category:** 6 (misleading optional — should be required), Observation. -### 85. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) +### 82. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). - **Category:** 1 (vague), 17 (inconsistent), Observation. -### 86. `flattenQueryParams` exported but unused (`utils.ts:123`) +### 83. `flattenQueryParams` exported but unused (`utils.ts:123`) The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. - **Category:** Observation (dead public surface). -### 87. JSDoc placeholder `` — pervasive +### 84. JSDoc placeholder `` — pervasive Throughout the model, JSDocs say `` (e.g., `model.ts:1097` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. - **Category:** Observation (doc-quality artefact in generator). diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index 31dfc36c..d83ea30d 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -44,26 +44,24 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | 21 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to present participle or to noun (e.g. `Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, `Running`) | | 22 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | | 23 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | -| 24 | medium | 14. Go/Java-style names | `model.ts:74,156` | `DestroyContextRequest` / `unmarshalDestroyResponseSchema` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 25 | medium | 14. Go/Java-style names | `model.ts:145-253` | `marshal*Schema`, `unmarshal*Schema` | Go-isms; TS audiences use `serialize`/`deserialize` or `encode`/`decode`. Schema-level only, low blast radius. | -| 26 | medium | 8. Redundant suffixes | `model.ts:145,148,156,159,172,183` | `unmarshal*Schema`, `marshal*Schema` | Both `marshal`+`Schema` suffixes; one is enough | -| 27 | medium | 8. Redundant suffix | `client.ts:333,417,498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 28 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 29 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 30 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 31 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 32 | medium | 18. Long enum values | `model.ts:22-28` | `COMMAND_STATUS_UNSPECIFIED` | Drop the `*_UNSPECIFIED` sentinel in TS (TS represents absence via `undefined`) | -| 33 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | -| 34 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | -| 35 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | -| 36 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | -| 37 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | -| 38 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #16 | -| 39 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | -| 40 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #10 | -| 41 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 42 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | -| 43 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #14 | +| 24 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 25 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 26 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 27 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 28 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 29 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 30 | medium | 18. Long enum values | `model.ts:22-28` | `COMMAND_STATUS_UNSPECIFIED` | Drop the `*_UNSPECIFIED` sentinel in TS (TS represents absence via `undefined`) | +| 31 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | +| 32 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | +| 33 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | +| 34 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | +| 35 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | +| 36 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #16 | +| 37 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | +| 38 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #10 | +| 39 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 40 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 41 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #14 | --- @@ -423,39 +421,15 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 25 — Medium — Cat 14 (Go/Java-style) -**Location:** `src/v2/model.ts:145-253` -```ts -unmarshalCancelResponseSchema, marshalCreateContextRequestSchema, ... -``` -**Issue:** `marshal` / `unmarshal` are Go terms. The TS audience reads -`serialize` / `deserialize` or `encode` / `decode`. These names are -exported and surface in stack traces. -**Proposed:** `serializeCreateContextRequest` / `deserializeCancelResponse` -(without `Schema` suffix — see #26). Since these are internal to the -generated layer, the blast radius is small. - ---- - -### Finding 26 — Medium — Cat 8 (Redundant suffixes) -**Location:** `src/v2/model.ts:145, 148, 156, 159, 172, 183, 209, 221, 231, 241` -**Issue:** `marshal*Schema` and `unmarshal*Schema` carry two role suffixes -(both the action verb and the artefact type). A schema is implied by zod's -`z.ZodType`. -**Proposed:** drop `Schema` suffix once #25 is applied: -`serializeCreateContextRequest`, `deserializeResult`, etc. - ---- - -### Finding 27 — Medium — Cat 8 (Redundant suffix) — call-out +### Finding 25 — Medium — Cat 8 (Redundant suffix) — call-out **Location:** `src/v2/client.ts:333, 417, 498` **Issue:** Three classes named `*Waiter`. Acceptable if waiter is a recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #28-#30. +issue is what they wait *for*: see #26-#28. --- -### Finding 28 — Medium — Cat 6 (Misleading name) +### Finding 26 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:417` ```ts export class CreateWaiter { ... } @@ -470,21 +444,21 @@ target endpoint). --- -### Finding 29 — Medium — Cat 6 (Misleading name) +### Finding 27 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:333` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 30 — Medium — Cat 6 (Misleading name) +### Finding 28 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:498` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. --- -### Finding 31 — Medium — Cat 17 (Inconsistent action verbs) — call-out +### Finding 29 — Medium — Cat 17 (Inconsistent action verbs) — call-out **Location:** `src/v2/client.ts:86, 256` **Issue:** This package uses three lifecycle verbs: - `cancel()` on a command, @@ -497,7 +471,7 @@ Go-SDK alignment decision. --- -### Finding 32 — Medium — Cat 18 (Long enum values) +### Finding 30 — Medium — Cat 18 (Long enum values) **Location:** `src/v2/model.ts:22, 32, 39, 47` **Issue:** `COMMAND_STATUS_UNSPECIFIED`, `CONTEXT_STATUS_UNSPECIFIED`, `LANGUAGE_UNSPECIFIED`, `RESULT_TYPE_UNSPECIFIED`. Long sentinel value @@ -507,7 +481,7 @@ strings expose the protobuf convention to JS consumers. TS uses --- -### Finding 33 — Low — Cat 1 (Vague/generic) +### Finding 31 — Low — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:117-118` ```ts /** The cause of the error */ @@ -521,18 +495,18 @@ sub-object; or keep flat and document conditional presence. --- -### Finding 34 — Low — Cat 1 (Vague/generic) +### Finding 32 — Low — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:139-140` ```ts /** The summary of the error */ summary?: string | undefined; ``` -Same as #33. The field is generic; the JSDoc reveals it's +Same as #31. The field is generic; the JSDoc reveals it's error-specific. --- -### Finding 35 — Low — Cat 1 (Underspecified) +### Finding 33 — Low — Cat 1 (Underspecified) **Location:** `src/v2/model.ts:141-142` ```ts /** true if partial results are returned. */ @@ -543,7 +517,7 @@ Acceptable but ambiguous: truncated *what*? table rows? text length? --- -### Finding 36 — Low — Cat 1 (Vague/generic) — call-out +### Finding 34 — Low — Cat 1 (Vague/generic) — call-out **Location:** `src/v2/client.ts:54` ```ts class StillRunningError extends Error {} @@ -552,7 +526,7 @@ Private, OK. Idiomatic for waiter polling patterns. --- -### Finding 37 — Low — Cat 3 (Acronym casing) — non-issue +### Finding 35 — Low — Cat 3 (Acronym casing) — non-issue **Location:** `src/v2/client.ts:49-52` ```ts const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; @@ -563,33 +537,33 @@ correctly cased per the project rules. --- -### Finding 38 — Low — Cat 10 (Reserved-word collision) — borderline +### Finding 36 — Low — Cat 10 (Reserved-word collision) — borderline **Location:** `src/v2/model.ts:138` **Issue:** `schema` is not a TS reserved word but is heavily aliased across libraries (zod, JSON schema, table schema, GraphQL schema). See #16. --- -### Finding 39 — Low — Cat 14 — non-issue +### Finding 37 — Low — Cat 14 — non-issue **Location:** `src/v2/client.ts:54` **Issue:** `StillRunningError` is named in idiomatic TS style (`*Error` suffix on classes extending Error). --- -### Finding 40 — Low — duplicate of #10 +### Finding 38 — Low — duplicate of #10 **Location:** `src/v2/model.ts:89` Same finding as #10. --- -### Finding 41 — Low — Cat 15 (Generic field) — call-out +### Finding 39 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. --- -### Finding 42 — Low — Cat 3 (Acronym casing in enum string values) +### Finding 40 — Low — Cat 3 (Acronym casing in enum string values) **Location:** `src/v2/model.ts:42-43` ```ts SQL = 'SQL', @@ -603,7 +577,7 @@ caps. Apply the casing rule (#5) and these become `Sql` (if the rule is --- -### Finding 43 — Low — duplicate of #14 +### Finding 41 — Low — duplicate of #14 **Location:** `src/v2/model.ts:131` `fileNames?: string[]` for images — same as #14. @@ -612,17 +586,16 @@ caps. Apply the casing rule (#5) and these become `Sql` (if the rule is ## Top Themes 1. **Wire-format leakage** — protobuf casing, `*_UNSPECIFIED` sentinels, - `marshal`/`unmarshal` Go verbs, and redundant enum-prefix members all - bleed from the source IDL into the public TS surface. The fix is a - project-wide style rule applied at the generator level: + and redundant enum-prefix members all bleed from the source IDL into + the public TS surface. The fix is a project-wide style rule applied at + the generator level: - PascalCase enum identifiers with wire-string values preserved; - - drop `*_UNSPECIFIED`; - - rename `marshal`/`unmarshal` to `serialize`/`deserialize`. + - drop `*_UNSPECIFIED`. 2. **Three-resource ambiguity** — `Cluster`, `Context`, `Command` are easy to confuse, but the public types use the generic field `id` and reuse `CreateResponse` for two unrelated operations. Findings #6, #7, #10, - #11, #12, #14, #17, #19, #28-#30 all stem from one decision: **never + #11, #12, #14, #17, #19, #26-#28 all stem from one decision: **never say "id" when "commandId" or "contextId" would do, and never reuse a response shape across resources**. Splitting `CreateResponse` into `CreateContextResponse` and `ExecuteCommandResponse` cascades to fix diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 2b5666c1..c9ec05f4 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -3,14 +3,14 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 46 +**Total weird names flagged:** 41 ## Summary | Severity | Count | | --- | --- | | High | 13 | | Medium | 17 | -| Low | 11 | +| Low | 6 | | Observation | 5 | ## High severity @@ -205,67 +205,37 @@ ## Low severity -### 32. `unmarshalConnectionInfoSchema` / `marshalCreateConnectionSchema` / `marshalUpdateConnectionSchema` and related — `src/v1/model.ts:386,471,539` -- **Why weird:** Three different verb prefixes (`marshal`/`unmarshal`) used as schema-name prefix. Function names communicate direction (`marshalX` = TS→wire, `unmarshalX` = wire→TS), but the resulting names are long (e.g. `unmarshalListConnections_ResponseSchema`). -- **Category:** 8 (redundant suffix `Schema`). -- **Suggested name:** Drop `Schema` suffix (`unmarshalConnectionInfo`, `marshalCreateConnection`), or shorten to `decode`/`encode` verbs. -- **Rationale:** Internal-style; the `Schema` suffix repeats info already captured by the `z.ZodType` typing. - -### 33. `unmarshalDeleteConnection_ResponseSchema` — `src/v1/model.ts:435` -- **Why weird:** Underscore inherited from the type name; eslint-disable required. -- **Category:** 4. -- **Suggested name:** Cascades from #10. -- **Rationale:** Mechanical. - -### 34. `unmarshalListConnections_ResponseSchema` — `src/v1/model.ts:450` -- **Why weird:** Same as #33. -- **Category:** 4. -- **Suggested name:** Cascades from #11. -- **Rationale:** Mechanical. - -### 35. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` +### 32. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. -### 36. `flattenQueryParams` — `src/v1/utils.ts:123` +### 33. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if generator default. - **Rationale:** Generator emits the same helper into every package even when unused. -### 37. `readAll` — `src/v1/utils.ts:40` +### 34. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Trivial; flagged for cross-package consistency. -### 38. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same file. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. -- **Rationale:** Mirroring helps readers map TS→wire/wire→TS at a glance. - -### 39. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 35. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should encode the layer, not just the protocol. -### 40. `HttpCallOptions` — `src/v1/utils.ts:15` +### 36. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 41. `listConnectionsIter` — `src/v1/client.ts:194` -- **Why weird:** `Iter` is a Go-style abbreviation for `Iterator`. TS convention is to spell out, or to use the `*` (async generator) syntax to communicate iteration. Consumer code reads `for await (const c of client.listConnectionsIter(...))`, the `Iter` adds nothing. -- **Category:** 5 (cryptic abbreviation), 14 (Go-style name). -- **Suggested name:** `listConnectionsPaginated` or just `iterateConnections`. -- **Rationale:** TS code typically uses verb-form for generators (`iterate`, `walk`) or describes the pagination behaviour (`paginated`). - -### 42. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:164-165` +### 37. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:164-165` - **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. - **Category:** Observation only. - **Suggested name:** None — this is the marshalling boundary by design. @@ -273,11 +243,11 @@ ## Observations -### 43. ~50 vendor names baked into `ConnectionType` enum +### 38. ~50 vendor names baked into `ConnectionType` enum The enum lists ~70 vendors (`MYSQL` ... `MARKETO`), all SCREAMING_SNAKE. This makes `model.ts` 84 lines of enum just for connection types. Worth raising with API design whether the type should be `string` with vendor metadata living in a separate registry — adding a new connection type today requires releasing a new SDK version. - **Category:** 18 (long enum value set). -### 44. Casing inconsistency in vendor name decomposition +### 39. Casing inconsistency in vendor name decomposition Within `ConnectionType`: - `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). - `MYSQL` (joined) vs `MICROSOFT_ENTRA_ID` (split). @@ -285,14 +255,14 @@ Within `ConnectionType`: No discoverable rule. Wire-locked, but worth surfacing. - **Category:** 3 (acronym/casing inconsistency). -### 45. Action-verb conventions on `Client` +### 40. Action-verb conventions on `Client` `createConnection`, `getConnection`, `listConnections`, `updateConnection`, `deleteConnection` — uniform. (Listed as observation since the audit asks us to flag inconsistencies; here we explicitly note consistency.) -### 46. `Client` constructor throws for missing host +### 41. `Client` constructor throws for missing host `if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. - **Category:** Observation. -### 47. `index.ts` re-exports proto-map entry types +### 42. `index.ts` re-exports proto-map entry types `ConnectionInfo_OptionsEntry`, `ConnectionInfo_PropertiesEntry`, `ConnectionInfo_SecretsEntry`, plus the same for `CreateConnection_*` and `UpdateConnection_*` — nine types whose only purpose is to model proto map entries. None are usable as `Record` consumers expect. These should not be on the public surface. - **Category:** 12 (duplicate concepts). diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index 36206e82..36c9da4b 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -13,7 +13,7 @@ cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure Managed Identity, GCP Service Account Key, Databricks-managed GCP Service Account, Cloudflare API token) and yields one of six temporary-credential shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). -**Total weird names flagged:** 53 +**Total weird names flagged:** 51 --- @@ -71,9 +71,7 @@ shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). | 48 | `expirationTime` (epoch milliseconds) | model.ts:467 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | | 49 | `createdAt`, `updatedAt`, `createdBy`, `updatedBy` | model.ts:205, 209, 207, 211 | field set | Low | (none) | Standard, consistent across the file. (Listing for completeness.) | | 50 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:107-110 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredential`/`CredentialInfo`/`UpdateCredential`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | -| 51 | `marshalXxxSchema` / `unmarshalXxxSchema` const naming | model.ts:1070-2293 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go-idioms; `Schema` is tautological with `z.ZodType`. TS idiom is `encode`/`decode`. Generator-wide pattern. | -| 52 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | -| 53 | `parseResponse` vs `marshalRequest` | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | Mixing `parse`/`marshal`. Either `parse`/`format` or `marshal`/`unmarshal`. | +| 51 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | --- @@ -202,8 +200,7 @@ Names affected: `ValidateCredential_Result`, `ValidateStorageCredential_FileOper `GenerateTemporaryServiceCredential_GcpOptions`, `ListCredentials_Response`, `ListStorageCredentials_Response`, `ValidateCredential_Response`, `ValidateCredential_ValidationResult`, `ValidateStorageCredential_Response`, -`ValidateStorageCredential_ValidationResult`, and the corresponding -`marshal*Schema`/`unmarshal*Schema` constants. +`ValidateStorageCredential_ValidationResult`. Standard TS idiom would nest these inside namespaces (`ValidateCredential.Result`) or give them top-level domain names (`ValidationOutcome`, @@ -255,9 +252,8 @@ and from any sibling package collides. Either: ### M3. Eight `client.ts` method pairs duplicate work Sixteen methods, eight pairs. Each pair differs only in the URL it hits. -Cf. #11. The class is 707 lines, the marshaling/unmarshaling roundtrips -inside each method add ~30 lines of boilerplate per method. Half of that is -generated for the legacy storage-credentials path. +Cf. #11. The class is 707 lines, with ~30 lines of boilerplate per method. +Half of that is generated for the legacy storage-credentials path. ### M4. `IsolationMode` enum values stutter the enum name @@ -382,36 +378,27 @@ RFC 6749 (OAuth 2.0) titles the term as "OAuth". The code uses "Oauth". Minor. "Used" reads as historical state. The doc says it is current state ("is this the root storage credential"). `isManagedStorageRoot` reads as state. -### L7. `marshal`/`unmarshal` are Go-idioms - -JS/TS ecosystem uses `encode`/`decode`, `parse`/`stringify`, or -`serialize`/`deserialize`. Generator-wide. - -### L8. `parseResponse` vs `marshalRequest` mix - -`utils.ts` has both verbs. Either `parse`/`format` or `marshal`/`unmarshal`. - -### L9. `PACKAGE_SEGMENT` is undescriptive +### L7. `PACKAGE_SEGMENT` is undescriptive Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` is self-documenting. -### L10. `HttpCallOptions` +### L8. `HttpCallOptions` Generic name, internal-only. Same pattern as in sibling packages. Fine inside the file; would warrant a better name if it leaked out. -### L11. `req` parameter naming in client methods +### L9. `req` parameter naming in client methods Standard across the SDK. Go-idiomatic, but consistent. -### L12. `Generate*Credential` method names are 30+ chars +### L10. `Generate*Credential` method names are 30+ chars `generateTemporaryServiceCredential` is 35 chars. Combined with `await client.generateTemporaryServiceCredential(req)` the call site is 60+ chars before the args. Cannot shorten without breaking the resource hierarchy. -### L13. Acronym casing review +### L11. Acronym casing review - `Aws` (PascalCase first letter) — `AwsCredentials`, `AwsIamRole`, `awsIamRole`. Internally consistent. @@ -523,7 +510,7 @@ Class re-exported with `export {Client}`; types and enums re-exported with | File | Lines | Exports counted | Audited | |------|-------|-----------------|---------| -| `src/v1/model.ts` | 2293 | 7 enums, 32 interfaces, 33 zod consts (15 unmarshal + 18 marshal) | yes | +| `src/v1/model.ts` | 2293 | 7 enums, 32 interfaces | yes | | `src/v1/client.ts` | 707 | 1 class, 18 public methods (16 RPC + 2 async generators) | yes | | `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | | `src/v1/index.ts` | 60 | 1 class re-export, 6 enum re-exports, 39 type re-exports | yes | diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 842f8f97..5a3b42e5 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -3,20 +3,20 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 **Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. -**Total weird names flagged:** 36 +**Total weird names flagged:** 32 ## Summary | Severity | Count | | --- | --- | -| High | 10 | -| Medium | 13 | -| Low | 9 | +| High | 9 | +| Medium | 12 | +| Low | 7 | | Observation | 4 | ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, `unmarshalCustomLlmSchema`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #36). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #34). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. @@ -52,24 +52,18 @@ - **Rationale:** When grepping logs or stack-traces for `customLlmId`, you'll find the right call site. Today you'll grep for `id` and get 50 false positives across the SDK. ### 7. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` -- **Why weird:** The `FieldMaskSchema` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the schema being machine-generated rather than designed. Worth a sanity check with the upstream API team. +- **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. - **Category:** Observation / 6 (misleading — field-mask implies updatable). - **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. - **Rationale:** This is the kind of thing a careful TS API designer would notice; a generator running over the proto schema will not. -### 8. `endpoint_name` field appears in `unmarshalCustomLlmSchema` but not in marshal counterpart correctly — `src/v1/model.ts:105,193` -- **Why weird:** The wire field for the marshaller is set via `endpoint_name: d.endpointName` (line 193) but the inner zod object types it as `endpointName` (camelCase, line 178). The marshal schema reads camelCase keys then emits snake_case — but the *input* the marshal schema validates is the already-camelCased `CustomLlm`, so the input shape is `endpointName`. That actually does work because the marshal schema is `z.object({endpointName: ...})`. However, all other marshallers in the same file accept camelCase input (cf. `marshalUpdateCustomLlmRequestSchema` at line 232 — `customLlm`). This is *internally* consistent but the naming feels accidental given the unmarshal schema (line 105) reads snake_case. Not strictly a name bug but the asymmetry is jarring. -- **Category:** 17 (inconsistent: unmarshal reads `endpoint_name`, marshal also writes `endpoint_name` but the schema validator key is `endpointName`). -- **Suggested name:** No rename; flag for upstream generator review. -- **Rationale:** Generator artefact; reading the two schemas side-by-side suggests the marshal validator-key should match the wire key, not the TS field name. - -### 9. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` +### 8. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` - **Why weird:** `UpdateCustomLlmRequest.customLlm: CustomLlm | undefined`. The TS naming convention makes the field/type distinction work via casing — but at a call site you'll write `req.customLlm = {...} satisfies CustomLlm`, and `customLlm` (the field) is one character of casing away from `CustomLlm` (the type). Type-suffix tautology under rule 20. - **Category:** 20 (type-suffix tautology). - **Suggested name:** Rename `customLlm` field → `llm` (paired with type rename `CustomLlm` → `Llm` per #2). Even without the type rename, the field can be `target` or `update`. - **Rationale:** `req.llm` reads cleanly; `req.customLlm` is the kind of name that survives code review only because nobody wants to argue with the generator. -### 10. `CustomLlm.creator: string` — `src/v1/model.ts:58` +### 9. `CustomLlm.creator: string` — `src/v1/model.ts:58` - **Why weird:** "Creator of the custom LLM" — but a `creator` could be a username, an email, a UUID, a Databricks principal-id, or a service-principal client-id. The type is `string` so there is no help. Other Databricks SDK packages (catalog, jobs) use `createdBy` or `creator` similarly inconsistently. The name does not say *what kind* of identifier it is. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `createdBy` if it is a user/principal id (matches Unity Catalog convention); add `@format` JSDoc clarifying whether it is an email or a UUID. @@ -77,79 +71,73 @@ ## Medium severity -### 11. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` +### 10. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` - **Why weird:** `creationTime` is named with the type-suffix convention (`*Time`), while peer fields on the same struct use bare nouns (`creator`, `name`, `instructions`). The other generated SDKs sometimes use `createdAt` or `createTime`. Naming `creationTime` is fine, but it is the *only* type-suffix field on `CustomLlm`. - **Category:** 17 (inconsistency within the same struct). - **Suggested name:** `createdAt` (Stripe/GitHub convention, https://stripe.com/docs/api/charges/object) or `createTime` (Google AIP-142, https://google.aip.dev/142). Either is more standard than `creationTime`. - **Rationale:** AIP-142 (Google API design) says: "Fields representing the time at which a resource was created should be of type google.protobuf.Timestamp and called `create_time`." The Go SDK and Java SDK tend to mirror this; TS should too. -### 12. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` +### 11. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` - **Why weird:** Two near-synonyms with different cardinalities. `instructions` is a single string, `guidelines` is a string array. The semantic difference is not obvious from the names; both feel like "things the model should follow". This is an API-design issue more than a naming issue, but the names amplify the confusion. - **Category:** 6 (misleading), 12 (duplicate concept). - **Suggested name:** `systemPrompt` (or `instruction`) for the single-string case; `rules` or `constraints` for the array. The bigger fix is to consolidate at the API level. - **Rationale:** Reading `instructions` + `guidelines` side-by-side, a consumer cannot guess which goes where without reading the prose docs. -### 13. `Table.tablePath` — `src/v1/model.ts:85` +### 12. `Table.tablePath` — `src/v1/model.ts:85` - **Why weird:** Type-suffix tautology (`Table.tablePath`). Doc says "Full UC table path in catalog.schema.table_name format" — but the field name does not communicate that it's a *fully qualified* three-part name. Compare with sibling SDK packages where the same concept is called `fullName` or `qualifiedName`. - **Category:** 20 (type-suffix tautology), 1 (vague — "path" is generic; a filesystem path? a JSON pointer?). - **Suggested name:** `fullName` (matches `catalog.TableInfo.full_name`) or `qualifiedName`. - **Rationale:** Unity Catalog already has a canonical term for three-part names (`full_name`); reusing it makes cross-API code less surprising. -### 14. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` +### 13. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` - **Why weird:** `Col` is a cryptic abbreviation for `Column`. The same package spells out `endpointName` and `agentArtifactPath` and `optimizationState`, so `Col` is inconsistent. Doc strings even use the full word: "Name of the request column". - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling fields). - **Suggested name:** `requestColumn` / `responseColumn`. - **Rationale:** Three saved characters is not worth the cognitive split between the doc ("column") and the identifier ("col"). -### 15. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` +### 14. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` - **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. - **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). - **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. - **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. -### 16. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` +### 15. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` - **Why weird:** Field `optimizationState` of type `State`. If `State` is renamed to `OptimizationRunState` per #3, the field can be renamed `optimization: OptimizationRunState` or `runState: OptimizationRunState`. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `optimization` (if type renamed) or just `state` with `State` more specific. Best is the pair `optimization: OptimizationRunState`. - **Rationale:** Reduces the noise once the enum name is specific. -### 17. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` +### 16. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `creationTime` reads as a `Date` and many callers will accidentally `new Date(customLlm.creationTime)`, which throws because `Temporal.Instant` does not coerce. Worth a comment in JSDoc; not a rename. - **Category:** Observation. - **Suggested name:** Keep `creationTime`; expand JSDoc to mention `Temporal.Instant`. - **Rationale:** Friction is from the type more than the name, but the name does not warn the reader of the unusual type. -### 18. Method names mix `Llm` and verb tense — `src/v1/client.ts:69,92,118,137,162,191` +### 17. Method names mix `Llm` and verb tense — `src/v1/client.ts:69,92,118,137,162,191` - **Why weird:** Methods are `cancelCustomLlmOptimizationRun`, `createCustomLlm`, `deleteCustomLlm`, `getCustomLlm`, `startCustomLlmOptimizationRun`, `updateCustomLlm`. They are verb-noun and consistent — but the noun is *always* `CustomLlm` which doubles the package name. After the fix in #2 these collapse to `cancelOptimizationRun`, `createLlm`, `deleteLlm`, `getLlm`, `startOptimizationRun`, `updateLlm` — much shorter. - **Category:** 7 (overly verbose). - **Suggested name:** Drop the redundant `CustomLlm` infix on the client methods; the package namespace already supplies it. - **Rationale:** Compare to `accountSettings.Client.deleteLlmProxyPartnerPoweredWorkspace` (accountsettings package) — that name is 41 chars long. SDK ergonomics suffer. Worth a project-wide convention question. -### 19. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +### 18. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 20. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair +### 19. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than the `Http` infix. -### 21. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. The model file uses `unmarshalCustomLlmSchema` / `marshalCustomLlmSchema` for the same pairing — so `parseResponse` should be `unmarshalResponse` for consistency. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry, or `parseResponse` / `serializeRequest`. -- **Rationale:** Pair-wise consistency aids reading. - -### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). - **Rationale:** Distinguish internal context bags from user-tunable option structs. -### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -157,55 +145,43 @@ ## Low severity -### 24. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +### 22. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` - **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. - **Category:** Observation / 9 (reversed — correctly singular). - **Suggested name:** No change. - **Rationale:** Note for consistency reviews. -### 25. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 23. `customLlmFieldMask` function name — `src/v1/model.ts:259` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). - **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. -### 26. `unmarshalCustomLlmSchema` schema variable naming — `src/v1/model.ts:101` -- **Why weird:** Verb-prefixed (`unmarshal*Schema`). The variable is *a schema*, not the act of unmarshalling. Reads as "the schema you use to unmarshal a CustomLlm" — which is precise, but the prefix is heavy. Five other `marshal*Schema` exports follow the same pattern, so this is consistent within the file; consistent vs. concise tradeoff. -- **Category:** 7 (verbose). -- **Suggested name:** `customLlmIn` / `customLlmOut`, or keep current convention if SDK-wide. Flagged for consistency review. -- **Rationale:** Internal consistency wins over local concision; only flag if SDK-wide convention is up for review. - -### 27. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 24. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it is an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 28. `readAll` helper — `src/v1/utils.ts:40` +### 25. `readAll` helper — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 29. Capitalization mismatch `endpoint_name` vs `endpointName` in `unmarshalCustomLlmSchema` — `src/v1/model.ts:105,193` -- **Why weird:** Cosmetic but worth noting: the marshal schema validator uses camelCase keys (`endpointName`, `agentArtifactPath`), and the unmarshal schema validator uses snake_case keys (`endpoint_name`, `agent_artifact_path`). The two halves are symmetric (the *output* of unmarshal is camelCase, the *input* of marshal is camelCase) but the validator-key choice is asymmetric. This is a generator quirk, not a name bug. Listed under Low for completeness. -- **Category:** Observation / 17. -- **Suggested name:** No rename. -- **Rationale:** Generator-mechanical. - -### 30. `Call` import alias — `src/v1/client.ts:4` +### 26. `Call` import alias — `src/v1/client.ts:4` - **Why weird:** `import type {Call}` — `Call` is a one-word generic noun. Used for the inner async function. Could be `RetryableCall`, `HttpCallback`, etc. Not local to this package (it is from `@databricks/sdk-core/api`), but worth flagging. - **Category:** 1 (vague type name). - **Suggested name:** Imported type; rename upstream if appropriate. - **Rationale:** Generic noun in core API surface. -### 31. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` +### 27. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` - **Why weird:** Three-letter local names. `info` for the client-info builder, `host` for the URL host, `body` for the request body. Conventional and short, but `info` is especially vague. - **Category:** 1 (vague). - **Suggested name:** Keep `host` and `body` (universal); rename `info` to `clientInfo`. - **Rationale:** Localized; cosmetic. -### 32. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` +### 28. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` - **Why weird:** `resp` is the response. Four methods declare `let resp: CustomLlm | undefined;` then assign in a closure and `throw` if undefined. The pattern is repetitive *and* uses the same short name. Consider extracting a helper that returns `T | never`. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. @@ -213,19 +189,19 @@ ## Observations -### 33. Action verbs in `Client` are consistent +### 29. Action verbs in `Client` are consistent The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. - **Category:** 17 (reversed — explicit *consistency* note). -### 34. No `list` operation +### 30. No `list` operation The package exposes singleton CRUD plus optimization start/cancel, but no `listCustomLlms`. Unusual for a Databricks resource SDK. Not a naming issue, but worth flagging because the typical resource SDK has `list` and users will look for it. - **Category:** Observation. -### 35. Mixed acronym casing in core types +### 31. Mixed acronym casing in core types The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `APIError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `API` (all-caps), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. - **Category:** 3 (acronym casing). -### 36. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` +### 32. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` Comment "// arrays of objects are not yet supported" inside a generated utility. Not a name issue, but the public-export status of this function makes the TODO load-bearing. - **Category:** Observation. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index b515dc50..e4461301 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,7 +3,7 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 56 +**Total weird names flagged:** 53 ## Summary | Severity | Count | @@ -11,7 +11,7 @@ | High | 16 | | Medium | 20 | | Low | 14 | -| Observation | 6 | +| Observation | 3 | ## High severity @@ -417,29 +417,18 @@ ## Observations -### 67. Wire/TS divergence is enormous in this package -File `model.ts` is 2,217 lines. ~270 lines are the actual user-facing TS interfaces and enums; the rest is unmarshal schemas (~520 lines), marshal schemas (~490 lines), and `FieldMaskSchema` definitions (~200 lines), plus paired exports. This is a generator-shape observation, not a naming bug — but it dwarfs the public surface 7x. - -### 68. `client.ts` has a 6-line block-comment at line 666-671 explaining that the role APIs will never reach Public Preview +### 67. `client.ts` has a 6-line block-comment at line 666-671 explaining that the role APIs will never reach Public Preview The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. - **Category:** 6 (misleading: client exposes APIs that won't stabilise). - **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. -### 69. `findDatabaseInstanceByUid` is the only `findBy*` method +### 68. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 70. `marshal*` / `unmarshal*` schemas are exported even though no consumer should use them -All `marshal*` and `unmarshal*` schemas in `model.ts` are `export`. They are used internally by `client.ts` but are public surface. Same as the abacpolicies audit observation. -- **Category:** Observation. - -### 71. Action-verb conventions in `Client` are consistent +### 69. Action-verb conventions in `Client` are consistent `create*` / `delete*` / `get*` / `list*` / `update*` / `failover*` / `findBy*` / `upgrade*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. -### 72. `index.ts` re-exports both types and value enums but does not re-export `marshal*` / `unmarshal*` schemas -Good hygiene — only the user-facing surface is re-exported. The `*FieldMaskSchema` constants are not exported (they're file-private). The `databaseCatalogFieldMask` / `databaseInstanceFieldMask` / `syncedDatabaseTableFieldMask` builder functions are exported from `model.ts` (lines 2025, 2068, 2116) but NOT re-exported in `index.ts` — so they exist on the package boundary but are not visible to consumers. Inconsistency. -- **Category:** 17 (inconsistent export surface). - ## Domain glossary - `Lakebase` — Databricks' managed Postgres-as-a-service product (mentioned only in the buried client.ts:666 comment). - `PG` / `pg` / `Postgres` / `PostgreSQL` — Postgres database; appears as `pgVersion`, `pgType`, `enablePgNativeLogin`, `PG_ONLY`, `PG_SPECIFIC_TYPE_*`, and as `PostgreSQL` in JSDoc. diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md index 60d2773b..ccca0263 100644 --- a/.agent/naming-audit/dataclassification.md +++ b/.agent/naming-audit/dataclassification.md @@ -3,14 +3,14 @@ **Path:** `packages/dataclassification/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 29 +**Total weird names flagged:** 21 ## Summary | Severity | Count | | --- | --- | | High | 7 | -| Medium | 11 | -| Low | 7 | +| Medium | 4 | +| Low | 6 | | Observation | 4 | ## High severity @@ -71,117 +71,69 @@ - **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`, or keep `Catalog` and drop `Config`: `CreateCatalogRequest`/... - **Rationale:** The whole package operates on exactly one entity. Repeating its name in four request types is pure noise. (However, the inconsistency with the entire rest of the SDK matters — proposing as a per-package fix is risky. Listed medium not high.) -### 10. `marshalCatalogConfigSchema` / `unmarshalCatalogConfigSchema` etc. — `src/v1/model.ts:113,125,161,173` -- **Why weird:** These are Zod schemas, but the names use `marshal`/`unmarshal` (Go terminology) where TS / JS users would say `encode`/`decode` or `serialize`/`parse`. Within Zod's own docs the verb is `parse`. Mixing Go vocabulary with a TS library is jarring. -- **Category:** 14 (Go-style names imported into TS), 17 (verb inconsistency — Zod's own API is `.parse()`, not `.unmarshal()`). -- **Suggested name:** `encodeCatalogConfigSchema` / `decodeCatalogConfigSchema`, or `catalogConfigToWireSchema` / `catalogConfigFromWireSchema`. -- **Rationale:** Marshal/unmarshal is a Go term of art; TS developers reach for `JSON.stringify`/`JSON.parse` or Zod's `parse`/`safeParse`. The current name forces a vocabulary translation. - -### 11. `catalogConfigFieldMaskSchema` and `catalogConfigFieldMask(...)` — `src/v1/model.ts:209,219` -- **Why weird:** Two exports differ only by the `Schema` suffix; the helper function and its lookup table share a stem. A reader has to look up which is the runtime config vs. which is the factory. Function/data naming should be more distinguishable. -- **Category:** 17 (inconsistent action verbs — schema is a noun, but the function uses the same name as a verbless noun). -- **Suggested name:** `buildCatalogConfigFieldMask(...)` for the function, leave the schema with `Schema` suffix. -- **Rationale:** Functions should be verb-prefixed; the schema-vs-builder distinction should jump off the page. Sister packages share this problem (generator-wide). - -### 12. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (`call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. -- **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). -- **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. -- **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. - -### 13. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 10. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. -### 14. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` -- **Why weird:** The function takes an arbitrary `unknown` value plus a Zod schema and returns a JSON string. The name says "Request" but the function does not know whether `data` is a request, response, or anything else. -- **Category:** 1 (vague — `Request` in the name does not constrain), 6 (misleading — works for any payload, not specifically requests). -- **Suggested name:** `marshalToJson` / `encodeToJson` / `toWireJson`. -- **Rationale:** The function is symmetric to `parseResponse`, which has the same problem in reverse. `Request`/`Response` should be specific to their meaning. - -### 15. `parseResponse(body, schema)` — `src/v1/utils.ts:113` -- **Why weird:** Symmetric problem to `marshalRequest`. The function parses any JSON `Uint8Array` against a Zod schema. The name says "Response" but the function does not check that. -- **Category:** 1, 6. -- **Suggested name:** `parseJsonBody` / `decodeFromJson` / `fromWireJson`. -- **Rationale:** Same as #14. `marshalRequest` + `parseResponse` are an asymmetric verb pair (`marshal` vs. `parse`) AND inaccurate. Either fix both. - -### 16. `flattenQueryParams` — `src/v1/utils.ts:123` +### 11. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 17. `readAll(body)` — `src/v1/utils.ts:40` -- **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". -- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). -- **Suggested name:** `drainStream` or `readStreamToUint8Array`. -- **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. - -### 18. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. -- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). -- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. -- **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. - ## Low severity -### 19. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` +### 12. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 20. `userAgent` field — `src/v1/client.ts:45` +### 13. `userAgent` field — `src/v1/client.ts:45` - **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. - **Category:** N/A (verification, no issue). - **Suggested name:** unchanged. - **Rationale:** Listed only to confirm canonical naming is preserved. -### 21. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` +### 14. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 22. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` +### 15. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` - **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. - **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. -### 23. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` +### 16. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 24. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` +### 17. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` - **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest` solves it. -### 25. `unmarshalCatalogConfig_SchemaNamesSchema` — `src/v1/model.ts:152` -- **Why weird:** Underscore in the identifier (proto-style nesting carried into the Zod schema name) plus type-suffix tautology — the trailing `Schema` is the Zod marker, but the inner `Schema` in `SchemaNames` is the field semantics, producing a hard-to-parse `..._SchemaNamesSchema` triple. Required `eslint-disable`. -- **Category:** 4 (underscore in TS identifier), 14 (Go/proto-style names), 20 (type-suffix tautology). -- **Suggested name:** Drop the underscore segment and choose distinct stems for the wrapper and the Zod marker, e.g., `schemaNameListSchema`. -- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`; the `eslint-disable` directive shows the name is fighting the language. Repeating `Schema` for two different concepts in one identifier also forces the reader to disambiguate by position. - ## Observations -### 26. Wire/TS divergence is heavy -The model file is 229 lines for ~5 user-facing types; >half is `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. +### 18. Wire/TS divergence is heavy +The model file is 229 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. -### 27. Action-verb conventions in `Client` +### 19. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) -### 28. Acronym casing +### 20. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 29. `dataclassification` lowercase package name +### 21. `dataclassification` lowercase package name The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 300ff267..56bbda08 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -3,28 +3,28 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, validity checks (`PercentNull`, `Range`, `Uniqueness`), and notification routing on failure. -**Total weird names flagged:** 52 +**Total weird names flagged:** 44 ## Summary | Severity | Count | | --- | --- | | High | 14 | -| Medium | 20 | -| Low | 13 | +| Medium | 17 | +| Low | 8 | | Observation | 5 | ## High severity -### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` / `listMonitorIter` — `src/v1/model.ts:366,372`, `src/v1/client.ts:316,349` +### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:366,372`, `src/v1/client.ts:316` - **Why weird:** Singular noun on a list operation. A list returns many monitors but the type and method names use the singular `Monitor`. The wire path is `/api/data-quality/v1/monitors` (plural), the response holds `monitors?: Monitor[]`, and the paginator yields a single `Monitor` — every concrete signal says plural; only the type/method name disagrees. - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** `ListMonitorsRequest` / `ListMonitorsResponse` / `listMonitors` / `listMonitorsIter`. +- **Suggested name:** `ListMonitorsRequest` / `ListMonitorsResponse` / `listMonitors`. - **Rationale:** REST conventions, the package's own field naming (`monitors`, `refreshes`), and the URL path all use plural. The singular form here is generator template noise, not intent. Same fix applies to refreshes (#2). -### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` / `listRefreshIter` — `src/v1/model.ts:378,398`, `src/v1/client.ts:378,411` +### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:378,398`, `src/v1/client.ts:378` - **Why weird:** Same singular-on-list problem as #1. The wire path is `/refreshes` and the response holds `refreshes?: Refresh[]`. - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** `ListRefreshesRequest` / `ListRefreshesResponse` / `listRefreshes` / `listRefreshesIter`. +- **Suggested name:** `ListRefreshesRequest` / `ListRefreshesResponse` / `listRefreshes`. - **Rationale:** Internal consistency: every other place in this file uses the plural `refreshes`. Only the type and method name break the pattern. ### 3. `RefreshState` enum members `MONITOR_REFRESH_STATE_*` — `src/v1/model.ts:80-90` @@ -113,109 +113,91 @@ - **Suggested name:** Doc should read "Request to delete a refresh." - **Rationale:** Generator-emitted typo. Listed because the doc is the first thing IDE users see. -### 17. `marshalCancelRefreshRequestSchema` exists but no `marshalCancelRefreshResponseSchema` (and conversely no `unmarshalCancelRefreshRequestSchema`) — `src/v1/model.ts:587,883` -- **Why weird:** Asymmetric coverage: requests get `marshal*` (outbound), responses get `unmarshal*` (inbound). That's correct for HTTP, but the import in `client.ts:38-47` reads as if both directions exist; readers have to mentally fill in the asymmetry. The naming `marshal*Schema` for *one* side and `unmarshal*Schema` for the *other* is not self-documenting unless you already know the convention. -- **Category:** 17 (inconsistent verb pairing — marshal/unmarshal across DTOs). -- **Suggested name:** N/A (rename to `encode*` / `decode*` would help — sister packages have the same problem). -- **Rationale:** Generator-level concern. Listed here because the dataquality package has the largest number of marshal/unmarshal pairs in this audit batch (10 each). - -### 18. `AnomalyDetectionConfig.anomalyDetectionWorkflowId` — `src/v1/model.ts:111` +### 17. `AnomalyDetectionConfig.anomalyDetectionWorkflowId` — `src/v1/model.ts:111` - **Why weird:** Three repetitions of "anomaly detection" in one field path: `monitor.anomalyDetectionConfig.anomalyDetectionWorkflowId`. The outer type already says "anomaly detection". Inside it, the `workflowId` field could be just `workflowId`. - **Category:** 7 (overly verbose), 8 (redundant suffix — `anomaly_detection_` inside `AnomalyDetectionConfig`). - **Suggested name:** `workflowId`. - **Rationale:** Repeating the parent type name in the field is a Go SDK habit (Go does not have struct-prefix scoping the way nested TS access does). -### 19. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v1/model.ts:117` +### 18. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v1/model.ts:117` - **Why weird:** "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning ("full" alone is ambiguous — full path? full description?). Other Databricks SDK packages use `fullName` consistently for UC three-part names. - **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). - **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or `excludedTableFullyQualifiedNames` for absolute clarity. - **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary, so the proposal is the *minor* rename to `excludedTables` since the type (string[]) plus parent context (anomaly detection on UC objects) already implies fully-qualified. -### 20. `DataProfilingConfig.outputSchemaId` vs `monitoredTableName` vs `dashboardId` vs `warehouseId` — `src/v1/model.ts:177,229,243,228` +### 19. `DataProfilingConfig.outputSchemaId` vs `monitoredTableName` vs `dashboardId` vs `warehouseId` — `src/v1/model.ts:177,229,243,228` - **Why weird:** Identifier fields mix three reference styles in one type: `Id` (UC UUIDs: schema, dashboard, warehouse), `FullName` (table), and bare `Name` (output schema is by ID, but `assetsDir` is a path). The user reading `DataProfilingConfig` must remember that to set the *target* of the monitor you use `monitoredTableName` (a three-part name) but to set the *destination* of the metric tables you use `outputSchemaId` (a UUID). The pattern is wire-driven, not user-led. - **Category:** 17 (inconsistent reference styles), 19 (underspecified IDs — `outputSchemaId` is a UUID but `monitoredTableName` is a three-part qualified name). - **Suggested name:** Document both clearly in the JSDoc; consider a normalised pair `outputSchema: {id?: string, fullName?: string}` and `monitoredTable: {fullName: string}`. Or rename `monitoredTableName` to `monitoredTableFullName` (matches the JSDoc). - **Rationale:** UC has a stable convention: `*FullName` for three-part references, `*Id` for UUIDs. Following that convention everywhere reduces caller errors. -### 21. `DataProfilingConfig.warehouseId` and `DataProfilingConfig.effectiveWarehouseId` — `src/v1/model.ts:228,251` +### 20. `DataProfilingConfig.warehouseId` and `DataProfilingConfig.effectiveWarehouseId` — `src/v1/model.ts:228,251` - **Why weird:** Two parallel fields: user-provided `warehouseId` (optional input — falls back to "the first running warehouse" per doc) and `effectiveWarehouseId` (the warehouse actually used). Same shape as `dataclassification.autoTagConfigs` vs `effectiveAutoTagConfigs` (audited finding #6 in that package). The "effective" prefix is not marked output-only; a caller can set `effectiveWarehouseId` thinking it overrides `warehouseId`. Also: `effectiveWarehouseId` has no JSDoc trailer period ("The warehouse for dashboard creation" — missing period). - **Category:** 1 (vague — "effective" undermarked), 6 (misleading — output-only not enforced by typing), and (style nit) missing period. - **Suggested name:** Mark with JSDoc `@readonly`; or rename to `resolvedWarehouseId`. The minor doc-style miss (no period) is a CLAUDE.md rule violation: "Comments should always be proper sentences ending with a period." - **Rationale:** Same pattern as the `effective*` audit findings in other packages. Output-only state should be visually distinct from input state. -### 22. `DataProfilingConfig.monitoredTableName` — `src/v1/model.ts:230` +### 21. `DataProfilingConfig.monitoredTableName` — `src/v1/model.ts:230` - **Why weird:** Half-redundant. `DataProfilingConfig` is a per-table config; the table being configured is "the monitored table". JSDoc says "Format: `catalog.schema.table_name`" — confirming this is a UC three-part name. Calling it `monitoredTableName` is fine, but it's the only "monitored" field on the type, so the prefix gives little signal. Compare with `Monitor.objectId` which holds the same data conceptually. - **Category:** 1 (vague modifier — `monitored` adds nothing), 7 (overly verbose). - **Suggested name:** `tableFullName` (or rely on `Monitor.objectId` and remove the duplicate field entirely). - **Rationale:** The package already carries the target identity on `Monitor.objectId`. Duplicating it inside the config is a wire artifact, not a TS-level design choice. -### 23. `DataProfilingConfig.latestMonitorFailureMessage` — `src/v1/model.ts:234` +### 22. `DataProfilingConfig.latestMonitorFailureMessage` — `src/v1/model.ts:234` - **Why weird:** Five-word field name on a type whose name is `DataProfilingConfig` — "latest" + "monitor" + "failure" + "message" + field is on `Monitor`. "Monitor" appears in the path: `monitor.dataProfilingConfig.latestMonitorFailureMessage`. - **Category:** 7 (overly verbose), 8 (redundant suffix — `Monitor` is in the access path). - **Suggested name:** `latestFailureMessage`. - **Rationale:** Field path already gives the Monitor context; the field's own name should drop it. -### 24. `DataProfilingConfig.profileMetricsTableName` / `driftMetricsTableName` — `src/v1/model.ts:236,238` +### 23. `DataProfilingConfig.profileMetricsTableName` / `driftMetricsTableName` — `src/v1/model.ts:236,238` - **Why weird:** A pair where one is "profile metrics" and the other is "drift metrics", but the JSDoc is identical down to the punctuation ("Table that stores [profile|drift] metrics data. Format: `catalog.schema.table_name`."). The only diff between the field names is the leading noun, but the type name `DataProfilingConfig` already says "profiling" — so `profileMetricsTableName` reads slightly redundant. - **Category:** 7 (overly verbose), 17 (inconsistent — drop "profile" prefix to match `driftMetricsTableName` shape, or add a profile/drift prefix universally). - **Suggested name:** `profileMetricsTable` + `driftMetricsTable` (drop `Name` since wire is the same, and the type itself names a wire reference). - **Rationale:** Consistent prefixing within a paired feature. Listed medium because the rename is risky for back-compat reasons. -### 25. `DataProfilingConfig.slicingExprs` — `src/v1/model.ts:209` +### 24. `DataProfilingConfig.slicingExprs` — `src/v1/model.ts:209` - **Why weird:** `Exprs` abbreviation. The JSDoc is 8 lines explaining what `slicing_exprs` does; the field name reduces "expressions" to four characters of cryptic shorthand. Mixed-case: would be `slicingExprs` in TS but the wire field is `slicing_exprs` (Python-style). - **Category:** 5 (cryptic abbreviation — `Exprs` for `Expressions`). - **Suggested name:** `slicingExpressions` (or, given the doc explains they are "column expressions", `columnSlicingExpressions`). - **Rationale:** Length is rarely an issue in TS — modern IDEs autocomplete. Cryptic abbreviation, however, costs readability forever. -### 26. `DataProfilingConfig.customMetrics: DataProfilingCustomMetric[]` — `src/v1/model.ts:211` +### 25. `DataProfilingConfig.customMetrics: DataProfilingCustomMetric[]` — `src/v1/model.ts:211` - **Why weird:** Type name `DataProfilingCustomMetric` repeats the parent type's prefix (`DataProfiling`). Same field/type-name asymmetry called out in `dataclassification` (autoTag vs AutoTagging). Field `customMetrics` is fine; the type's prefix is the noise. - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `CustomMetric` (drop the `DataProfiling` prefix) — namespace via TS module if needed. - **Rationale:** Inside the `dataquality` package, "custom metric" can only mean one thing (a profiling metric definition). The `DataProfiling` prefix is dead context. -### 27. `DataProfilingCustomMetric.outputDataType: string` — `src/v1/model.ts:266` +### 26. `DataProfilingCustomMetric.outputDataType: string` — `src/v1/model.ts:266` - **Why weird:** Field name is `outputDataType` and JSDoc says "The output type of the custom metric." — the JSDoc drops `Data`. Field is typed `string`, no enum. Compare with `type: DataProfilingCustomMetricType` which is enum and is the *kind* of metric, not its *data type*. The reader must parse two `type` fields on the same type. - **Category:** 1 (vague — `outputDataType` vs `type`), 12 (duplicate concept — two `type`s), 17 (inconsistent — one is enum, one is string). - **Suggested name:** `outputSqlType` (since the value is a SQL type like `DOUBLE`), or `outputColumnType`. - **Rationale:** Two `type`-like fields on the same struct is a code-smell; making one specifically `Sql` or `Column` removes the ambiguity. -### 28. `DataProfilingStatus.DATA_PROFILING_STATUS_DELETE_PENDING` — `src/v1/model.ts:64` +### 27. `DataProfilingStatus.DATA_PROFILING_STATUS_DELETE_PENDING` — `src/v1/model.ts:64` - **Why weird:** Five-word enum value with the order "DELETE PENDING" (verb-then-state) — most languages would write `PENDING_DELETE` (state-modified-by-action). Also: this enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately. - **Category:** 2 (redundant prefix), 12 (duplicate concept — `ERROR` and `FAILED`), 18 (long enum values). - **Suggested name:** Members: `DataProfilingStatus.{Active, Pending, PendingDelete, Error, Failed}`. Or, if `ERROR`/`FAILED` are truly distinct, document the difference. - **Rationale:** Sentinel naming conventions and the implicit duplicate of `ERROR`/`FAILED` both make this enum harder to reason about than it should be. -### 29. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:420,425` +### 28. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:420,425` - **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #8). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). - **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). - **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. -### 30. `CronSchedule.quartzCronExpression` and `CronSchedule.timezoneId` — `src/v1/model.ts:163,169` +### 29. `CronSchedule.quartzCronExpression` and `CronSchedule.timezoneId` — `src/v1/model.ts:163,169` - **Why weird:** Field is qualified with `Quartz` (the scheduling library) leaking implementation detail; users do not need to know the schedule is parsed by Quartz on the server side. `timezoneId` collides with the IANA tz database vocabulary ("timezone ID" is not standard; "IANA timezone name" or just "timezone" is). - **Category:** 14 (implementation-detail leak — `Quartz` is a Java library reference), 5 (jargon — `timezoneId` vs the JS-standard `timeZone`). - **Suggested name:** `cronExpression` + `timezone`. - **Rationale:** The doc already says "Java timezone id"; the field name should be neutral. -### 31. `unmarshalListMonitorResponseSchema` — `src/v1/model.ts:702` -- **Why weird:** Compound: List + Monitor (singular) + Response + Schema, 35 characters before the equals sign, mirroring the underlying singular-on-list bug from #1. Once #1 is fixed, this becomes `unmarshalListMonitorsResponseSchema`. -- **Category:** 9 (singular/plural mismatch), 7 (overly verbose Zod schema name). -- **Suggested name:** Fix at #1. -- **Rationale:** Compounds amplify the underlying bug. - -### 32. `unmarshalListRefreshResponseSchema` — `src/v1/model.ts:713` -- **Why weird:** Same as #31 for refreshes. -- **Category:** 9 (singular/plural mismatch). -- **Suggested name:** Fix at #2. -- **Rationale:** Compound name surfaces underlying singular/plural mismatch. - -### 33. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:437` -- **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. Same pattern as `AnomalyDetectionConfig.anomalyDetectionWorkflowId` (#18). The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. +### 30. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:437` +- **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. Same pattern as `AnomalyDetectionConfig.anomalyDetectionWorkflowId` (#17). The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. - **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). - **Suggested name:** Field: `onFailureOrTimeout` (matches doc), or `onFailure` (matches name; update doc). Type: `Destination` (drop the `Notification` prefix since the type is only used here). - **Rationale:** Field name and JSDoc should agree on whether timeouts are included. -### 34. `Refresh.message` — `src/v1/model.ts:477` +### 31. `Refresh.message` — `src/v1/model.ts:477` - **Why weird:** `message` is the most generic possible name on a `Refresh` object. JSDoc clarifies: "An optional message to give insight into the current state of the refresh (e.g. FAILURE messages)" — so this is really an error message or status message, not just any message. - **Category:** 1 (vague — `message` could be anything), 15 (generic field name). - **Suggested name:** `statusMessage` or `stateMessage`. @@ -223,100 +205,70 @@ ## Low severity -### 35. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 32. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's two list endpoints handle pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as `dataclassification` finding #19. -### 36. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +### 33. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataclassification` finding #15. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 37. `buildHttpRequest` — `src/v1/utils.ts:96` +### 34. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataclassification` finding #16; "build" suggests builder pattern, the function spreads literals. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the simpler reality. -### 38. `marshalRequest` and `parseResponse` — `src/v1/utils.ts:113,119` -- **Why weird:** Names imply request/response but the functions work on any payload + schema; identical to `dataclassification` findings #17 and #18. -- **Category:** 1, 6. -- **Suggested name:** `encodeToJson` / `decodeFromJson`. -- **Rationale:** Symmetric verb pair removes the "Request"/"Response" mis-promise. - -### 39. `readAll` — `src/v1/utils.ts:40` +### 35. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Identical to `dataclassification` finding #20; "readAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing name for stream draining. -### 40. `HttpCallOptions` — `src/v1/utils.ts:15` +### 36. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataclassification` finding #21; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 41. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` +### 37. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` - **Why weird:** Same as `dataclassification` finding #22; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 42. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` +### 38. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` - **Why weird:** Same as `dataclassification` finding #24; variable named `call` of type `Call` repeated 11 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 43. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +### 39. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` - **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. - **Rationale:** Type shape should match runtime requirement. -### 44. `respBody` vs `resp` — `src/v1/client.ts:101-111, 139-150, 173-184, 220-237, 266-276, 302-312, 335-346, 397-408, 463-474, 501-512` -- **Why weird:** Same as `dataclassification` finding #26; two variables differ by `Body` only. -- **Category:** 5, 17. -- **Suggested name:** `rawBody` + `result`. -- **Rationale:** Distinguish by meaningful nouns. - -### 45. `httpReq` local — `src/v1/client.ts:99, 138, 172, 210, 229, 264, 300, 334, 396, 456, 494` -- **Why weird:** Same as `dataclassification` finding #27. -- **Category:** 5, 12. -- **Suggested name:** `httpRequest` (no abbreviation). -- **Rationale:** Avoid two `req`-rooted identifiers in the same scope. - -### 46. `pageReq` local in `listMonitorIter` / `listRefreshIter` — `src/v1/client.ts:353, 415` -- **Why weird:** Yet another `req` variant in a scope that already has `req: ListMonitorRequest` as the outer parameter, plus `pageReq: ListMonitorRequest` for the mutable copy used per-page. Three layers of `req` (the user's, the per-page mutation, and inside each call the `httpReq`) in one method. -- **Category:** 5 (abbreviated), 12 (duplicate concept). -- **Suggested name:** `pageRequest` (full word), or restructure so only one `req` exists per scope. -- **Rationale:** Pagination wrappers compound abbreviation noise. - -### 47. `marshalAnomalyDetectionConfigSchema` and 18 other `marshal*Schema` / `unmarshal*Schema` names — `src/v1/model.ts:568-863, 865-1146` -- **Why weird:** Generator-emitted Zod schemas all carry the awkward double-`Schema` suffix at the call site (`z.lazy(() => unmarshalRefreshSchema)`) — "lazy unmarshal Refresh Schema" reads as three nouns and an adjective. Same as `dataclassification` finding #13. -- **Category:** 14 (Go-style), 17 (verb-naming mismatch with Zod's own `parse`). -- **Suggested name:** `encodeAnomalyDetectionConfig` / `decodeAnomalyDetectionConfig`. -- **Rationale:** Generator-wide. - ## Observations -### 48. Heavy boilerplate dominates the file +### 40. Heavy boilerplate dominates the file `model.ts` is 1252 lines for ~16 user-facing types; 575 lines (~46%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. -### 49. Action verbs in `Client` +### 41. Action verbs in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) -### 50. Acronym casing +### 42. Acronym casing Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. - **Category:** 3 (acronym casing). -### 51. Tense / nominalisation drift in enum naming +### 43. Tense / nominalisation drift in enum naming `AnomalyDetection` (gerund), `DataProfiling` (gerund), `DataClassification` (noun) — at the package boundary the gerund/noun choice tracks the API team's preference. Within `dataquality` the choice is consistent (both gerunds), good. -### 52. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types +### 44. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types Same shape as the `dataclassification` casing observation (#32 in that package): directory is one collapsed word, types are PascalCase compounded, wire path is kebab. SDK-wide convention question, not local. - **Category:** 3 (casing inconsistency). diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index 107020d3..34e4bbf5 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -3,15 +3,15 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 32 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | | High | 9 | | Medium | 11 | -| Low | 8 | -| Observation | 4 | +| Low | 5 | +| Observation | 3 | ## High severity @@ -46,10 +46,10 @@ - **Rationale:** Optional `state?: FailoverGroupState` encodes the unset case. PascalCase members align with TS conventions while leaving the SCREAMING_SNAKE_CASE wire values intact via the Zod schema. ### 6. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,317` -- **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`, `listStableUrlsIter`. +- **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #31 — same issue applies in `utils.ts` field `url` on `StableUrl`.) +- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #28 — same issue applies in `utils.ts` field `url` on `StableUrl`.) ### 7. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` - **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: @@ -143,49 +143,31 @@ ## Low severity -### 21. `marshalFailoverFailoverGroupRequestSchema` — `src/v1/model.ts:457` -- **Why weird:** Stutter inherited from `FailoverFailoverGroupRequest`. Schema name is `marshal` + `FailoverFailoverGroupRequest` + `Schema`, four words and a doubled word. -- **Category:** 7 (overly verbose), 4 (cascaded from #1). -- **Suggested name:** Falls out if `FailoverFailoverGroupRequest` becomes `FailoverRequest`. Result: `marshalFailoverRequestSchema`. -- **Rationale:** Mechanical cascade from finding #1. - -### 22. `unmarshalUcCatalogSchema`, `marshalUcCatalogSchema`, `unmarshalUcReplicationConfigSchema`, `marshalUcReplicationConfigSchema` — `src/v1/model.ts:420,544,428,552` -- **Why weird:** `Uc` prefix in schema names cascades from `UcCatalog` / `UcReplicationConfig`. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** Cascades from #11 and #12 (`unmarshalCatalogSchema`, `unmarshalUnityCatalogReplicationConfigSchema`). -- **Rationale:** Mechanical cascade. - -### 23. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +### 21. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. -### 24. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` +### 22. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` - **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Same as other packages in the audit. Flag once per package. -### 25. `flattenQueryParams` — `src/v1/utils.ts:123` +### 23. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (generator default) or document why it ships per-package. - **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. -### 26. `readAll` — `src/v1/utils.ts:40` +### 24. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToBuffer`. - **Rationale:** Internal helper. Skip if generated identically across all packages. -### 27. `parseResponse` vs `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** Inverse operations named with two different verbs (`parse` vs `marshal`). -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` (symmetric pair). -- **Rationale:** Pair-wise consistency aids reading. - -### 28. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + APIError lift). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -193,13 +175,10 @@ ## Observations -### 29. Wire-format ratio is unusually high -`model.ts` is ~608 lines; of those, ~290 are TS types/enums and the remaining ~320 are marshal/unmarshal/FieldMaskSchema scaffolding. For nine user-facing types this is heavy. Not a naming issue per se but worth raising at the SDK-design level for the same reason flagged in the `abacpolicies` audit. - -### 30. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#23), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. +### 26. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#21), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. -### 31. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +### 27. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` Within this package: - `stableUrl`/`StableUrl` (PascalCase capital-then-lower). - `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). @@ -207,7 +186,7 @@ Within this package: Three different casings for two acronyms (URL/URI). The Web platform uses `URL` (ALLCAPS) globally; the TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) - **Category:** 3 (acronym casing). -### 32. Cryptic acronyms left undefined in the source +### 28. Cryptic acronyms left undefined in the source The file mentions `UCDR` and `CPDR` in one comment (line 113) and `spog_host` in a URL example (line 256). Of these, only `CPDR` is decoded via a parenthetical ("control plane DR") elsewhere (line 308). `UCDR` and `spog` appear once each with no expansion in the source. A reader without internal Databricks context cannot decode them. This isn't a name-quality issue on a TS identifier, but the comments are part of the user-facing JSDoc surface (they appear in IDE hovers), so flagged here. - **Category:** 5 (cryptic abbreviation in JSDoc), 14 (internal jargon leak). diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md index 402db729..4fa911f9 100644 --- a/.agent/naming-audit/endpoints.md +++ b/.agent/naming-audit/endpoints.md @@ -15,10 +15,10 @@ the single most problematic naming choice in the whole package. Each finding lists the offending identifier(s), the category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename suggestion. Findings are grouped by category. Generator-driven items -(such as the `_State` underscore on proto-style nested enums and the -`marshal`/`unmarshal` schema prefixes) are flagged as `LOW` because -they are codified across the entire generated SDK surface — they -should be fixed at the generator, not by hand-editing this package. +(such as the `_State` underscore on proto-style nested enums) are +flagged as `LOW` because they are codified across the entire +generated SDK surface — they should be fixed at the generator, not by +hand-editing this package. --- @@ -595,7 +595,7 @@ each category. containing class is *already* the endpoints client (or will be after F0 rename — `VectorSearchEndpointsClient`). Compare typical TS SDK shape: `endpoints.create(...)`, `endpoints.patchBudgetPolicy(...)`. -- **Suggestion:** `create`, `delete`, `get`, `list`, `listIter`, +- **Suggestion:** `create`, `delete`, `get`, `list`, `patch`, `patchBudgetPolicy`, `patchThroughput`. Cross-package convention. @@ -629,18 +629,9 @@ each category. - Rename to `createEndpointAndWait` (verbose but explicit), or - Inline the polling into `createEndpoint` and remove the waiter type entirely. - See F17.5. - -#### F7.8 — `listEndpointIter` (MEDIUM) -- **Where:** `client.ts:199-214`. -- **Why flagged:** `Iter` suffix is Go-style; in TS the idiomatic - alternative is an async iterator method - (`[Symbol.asyncIterator]`) or a name like `listAll` / - `streamEndpoints`. -- **Suggestion:** Tied to F17.4: `listIter` (drop the singular - `Endpoint`) or `iterate` / `stream` / `listAll`. Cross-package. - -#### F7.9 — `STILL_RUNNING` / `StillRunningError` (LOW) + See F17.3. + +#### F7.8 — `STILL_RUNNING` / `StillRunningError` (LOW) - **Where:** `client.ts:54`. - **Why flagged:** Private error class used as a control-flow signal for `retryOn`. Three concepts in one name ("still" + "running" + @@ -696,8 +687,7 @@ each category. - **Where:** `client.ts:169`. - **Why flagged:** Method returns `ListEndpointResponse` whose `endpoints` field is `Endpoint[]`. The method should be - `listEndpoints` (plural). Same applies to its iterator and - request type: `listEndpointIter` should be `listEndpointsIter`, + `listEndpoints` (plural). Same applies to its request type: `ListEndpointRequest` should be `ListEndpointsRequest`, `ListEndpointResponse` should be `ListEndpointsResponse`. - **Suggestion:** Pluralize throughout. The wire path is @@ -898,15 +888,7 @@ each category. applied consistently across the SDK; flag for cross-cutting decision. -#### F13.4 — `unmarshalXSchema` constants (LOW, code style) -- **Where:** `model.ts:267, 280, 290, 293, 329, 340, 350, 376, 387, 398`. -- **Why flagged:** Naming pattern `verb + noun + Schema` makes them - read like functions; they are Zod constants. Same finding as - in `budgets` audit (F13.3 there). -- **Suggestion:** Generator-level rename to `endpointWireSchema` or - `endpointDecoderSchema`. Cross-cutting. - -#### F13.5 — `creationTimestamp` / `lastUpdatedTimestamp` past-tense +#### F13.4 — `creationTimestamp` / `lastUpdatedTimestamp` past-tense asymmetry (LOW) - **Where:** `model.ts:117, 119`. - **Why flagged:** "creation" (noun) vs "lastUpdated" (past @@ -922,13 +904,12 @@ each category. ### 14. Go / Java-style names -#### F14.1 — `req`, `resp`, `err`, `Iter`, `httpReq`, `apiErr`, +#### F14.1 — `req`, `resp`, `err`, `httpReq`, `apiErr`, `pkgJson`, `opts`, `msg` (HIGH, cross-cutting) - **Where:** - `req` in every client method - `resp`, `respBody`, `pollResp` in `client.ts` - `e` in `utils.ts:76` - - `Iter` suffix in `listEndpointIter` - `httpReq` in `client.ts` - `apiErr` in `utils.ts:88` - `pkgJson` in `client.ts:20, 50` @@ -936,31 +917,20 @@ each category. - `msg` in `client.ts:339` - **Why flagged:** All classic Go idioms ported verbatim. TS convention favors spelled-out names: `request`, `response`, - `error`, `iterator`/`stream`/`listAll`, `httpRequest`, - `apiError`, `packageJson`, `options`, `message`. + `error`, `httpRequest`, `apiError`, `packageJson`, `options`, + `message`. - **Suggestion:** Spell them out. Trivial diff, large readability gain. Generator-level decision; identical to the recommendation in the `budgets` audit. -#### F14.2 — `unmarshal*` / `marshal*` schema prefixes (LOW) -- **Where:** All schema exports. -- **Why flagged:** `marshal`/`unmarshal` is a Go term (`encoding/json`). - The JS/TS world says "serialize"/"deserialize" or "encode"/"decode"; - `JSON.parse`/`JSON.stringify` is the vernacular. -- **Suggestion:** Generator-level rename to `encode`/`decode` or - `serialize`/`deserialize`. Cross-cutting. - -#### F14.3 — `Schema` suffix on Zod constants (acceptable) -- The `…Schema` suffix matches Zod community convention. - -#### F14.4 — `for (;;)` infinite loop (acceptable) +#### F14.2 — `for (;;)` infinite loop (acceptable) - **Where:** `client.ts:204`, `utils.ts:48`. - **Why flagged:** Style; this is a `for (;;)` Go-idiom (the Go form is `for { … }`). TS prefers `while (true)` or `do { … } while (…)`. But `for (;;)` is also legal and idiomatic in C-derived languages. - **Suggestion:** Acceptable; consistent within the SDK. -#### F14.5 — `Waiter` suffix (Go-style) (MEDIUM) +#### F14.3 — `Waiter` suffix (Go-style) (MEDIUM) - **Where:** `client.ts:107-116, 307`. Exported as `CreateEndpointWaiter` (`index.ts:3`). - **Why flagged:** "Waiter" is an AWS SDK / Go SDK pattern. TS @@ -973,7 +943,7 @@ each category. for parity with other Databricks SDKs (Go has Waiters; users porting may expect them). -#### F14.6 — `numIndexes`, `numReplicas` `num` prefix (LOW) +#### F14.4 — `numIndexes`, `numReplicas` `num` prefix (LOW) - **Where:** `model.ts:87, 129, 177, 179, 252`. - **Why flagged:** `num` is shortened from "number of". TS often uses the bare noun (`replicas`, `indexCount`) or `count` suffix. @@ -1070,24 +1040,12 @@ each category. - `getEndpoint` for single, `listEndpoint` for collection. Standard REST verbs. (Plural issue covered in F9.1.) -#### F17.3 — `listEndpointIter` (MEDIUM) -- **Where:** `client.ts:199`. Already flagged in F7.8 / F14.1. - -#### F17.4 — `marshal` / `unmarshal` / `parseResponse` / - `marshalRequest` (LOW) -- **Where:** `utils.ts:113, 119`, all schema names. -- **Why flagged:** `parse` vs `marshal` use different verbs for the - same kind of operation (JSON conversion). Inconsistent verb - choice. Same finding as `budgets` F17.4. -- **Suggestion:** Use the same axis throughout: either - `marshal/unmarshal` or `encode/decode` or `serialize/deserialize`. - -#### F17.5 — `createEndpoint` returns `Endpoint`, +#### F17.3 — `createEndpoint` returns `Endpoint`, `createEndpointWaiter` returns `CreateEndpointWaiter` (MEDIUM) - **Where:** `client.ts:82, 107`. - See F7.7 / F13.3. -#### F17.6 — `wait` vs `done` on `CreateEndpointWaiter` (acceptable) +#### F17.4 — `wait` vs `done` on `CreateEndpointWaiter` (acceptable) - **Where:** `client.ts:318, 362`. - Both verbs are well-chosen. `wait` is blocking-until-terminal; `done` is a non-blocking check. Symmetric and clear. @@ -1237,22 +1195,22 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling | 4 | Underscores in TS identifiers | 2 | | 5 | Cryptic abbreviations | 10 | | 6 | Misleading names | 9 | -| 7 | Overly verbose | 9 | +| 7 | Overly verbose | 8 | | 8 | Redundant suffixes | 5 | | 9 | Singular / plural mismatch | 5 (3 acceptable) | | 10 | Reserved-word collisions | 5 (3 acceptable) | | 11 | Empty / trivial wrappers | 1 | | 12 | Duplicate concepts | 7 | -| 13 | Verb-tense inconsistency | 5 (1 acceptable) | -| 14 | Go / Java-style names | 6 | +| 13 | Verb-tense inconsistency | 4 (1 acceptable) | +| 14 | Go / Java-style names | 4 (1 acceptable) | | 15 | Generic field names | 6 | | 16 | Field contradicting type domain | 4 | -| 17 | Inconsistent action verbs | 6 (2 acceptable) | +| 17 | Inconsistent action verbs | 4 (2 acceptable) | | 18 | Long enum values | 5 (1 acceptable) | | 19 | Underspecified IDs | 3 (2 acceptable) | | 20 | Type-suffix tautology | 6 (3 acceptable) | | OVERLAP | endpoints vs warehouses vs serving | 4 | -| **Total** | | **118** | +| **Total** | | **112** | --- @@ -1268,9 +1226,8 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling `ThroughputChangeRequestState` (`CHANGE_*`), and `ThroughputPatchStatus` (`PATCH_*`). 3. **F9.1 / F9.2:** Pluralize the list method, request, and response: - `listEndpoints`, `ListEndpointsRequest`, `ListEndpointsResponse`, - `listEndpointsIter`. -4. **F4.1 / F14.4:** Replace `EndpointStatus_State` with namespace + `listEndpoints`, `ListEndpointsRequest`, `ListEndpointsResponse`. +4. **F4.1:** Replace `EndpointStatus_State` with namespace nesting or flat PascalCase (`EndpointStatusState`); eliminate the `eslint-disable-next-line` for `naming-convention`. 5. **F6.5:** Rename `minimalConcurrencyAllowed → @@ -1282,7 +1239,7 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling 7. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from `Endpoint.endpointType` and `Endpoint.endpointStatus` to bare `type` / `status`. -8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`Iter`/`opts`/ +8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson`/`msg` across the generated code. 9. **F12.2:** Resolve the `targetQps` / `replicationFactor` / `numReplicas` overlap at the API spec level — three names for @@ -1301,9 +1258,8 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling (`executeCall`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, `readAll`) that every generated package duplicates. The - duplication itself is not a naming issue, but the *names* - (`marshal/unmarshal`) are Go-flavored and inconsistent with - `parseResponse`. + duplication itself is not a naming issue and is out of scope for + this audit. - This package has no `tests/` directory (verified by repo structure check), so the audit does not cover test naming. - The `Waiter` pattern (`CreateEndpointWaiter`) is a Go SDK idiom diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index 1bf71dba..6206755b 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -3,15 +3,15 @@ **Path:** `packages/entitytagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) and inheritance (`inherited` / `includeInherited`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). -**Total weird names flagged:** 37 +**Total weird names flagged:** 31 ## Summary | Severity | Count | | --- | --- | | High | 11 | -| Medium | 13 | -| Low | 8 | -| Observation | 5 | +| Medium | 10 | +| Low | 6 | +| Observation | 4 | ## High severity @@ -78,7 +78,7 @@ ### 11. Method names `createEntityTagAssignment` / `deleteEntityTagAssignment` / `getEntityTagAssignment` / `listEntityTagAssignments` / `updateEntityTagAssignment` — `src/v1/client.ts:76,114,133,169,235` - **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createEntityTagAssignment(...)` reads as "package.subject.create.subject" — the noun is doubled. Sister package `tagassignments` does the same with `createTagAssignment`. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. - **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `EntityTagAssignment` four/five times when the client only manages `EntityTagAssignment`). -- **Suggested name:** `create`, `delete`, `get`, `list`, `update` (and `listIter`). Or shorter `createAssignment` / `deleteAssignment` / etc. +- **Suggested name:** `create`, `delete`, `get`, `list`, `update`. Or shorter `createAssignment` / `deleteAssignment` / etc. - **Rationale:** A client class that ships exactly five methods all named after the same subject is repeating the subject. `EntityTagAssignmentsClient.create()` is the more readable shape. ## Medium severity @@ -95,19 +95,7 @@ - **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. - **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. -### 14. `entityTagAssignmentFieldMask` / `entityTagAssignmentFieldMaskSchema` — `src/v1/model.ts:154,165` -- **Why weird:** Same long prefix on the schema constant and the helper function (40+ char identifier). The two exports differ only by suffix (`Schema` vs. no `Schema`). Function vs. lookup-table naming should be more distinguishable, and `entityTagAssignment` is the same redundant prefix flagged in #2. -- **Category:** 17 (inconsistent action verbs — function and noun share a stem), 7 (overly verbose). -- **Suggested name:** `tagAssignmentFieldMask(...)` and `tagAssignmentFieldMaskSchema` (drop `Entity` prefix), or rename the function to `buildTagAssignmentFieldMask(...)` for verb-prefixing. -- **Rationale:** Function should be verb-prefixed; otherwise it reads as a noun. Sister packages (`tagassignments/src/v1/model.ts:110`) suffer the same. - -### 15. `marshalEntityTagAssignmentSchema` / `unmarshalEntityTagAssignmentSchema` / `unmarshalListEntityTagAssignmentsResponseSchema` — `src/v1/model.ts:90,116,129` -- **Why weird:** These are Zod schemas (53-char identifier on `unmarshalListEntityTagAssignmentsResponseSchema`!), but the verbs are `marshal`/`unmarshal` (Go terminology). TS users would say `encode`/`decode` or `serialize`/`parse`. Zod's own API verb is `.parse()`. The TS+Go vocab mix is jarring. -- **Category:** 14 (Go-style verbs in TS code), 17 (verb inconsistency with Zod's own `.parse()`). -- **Suggested name:** `encodeTagAssignmentSchema` / `decodeTagAssignmentSchema` / `decodeListResponseSchema`. Or stick with `marshal`/`unmarshal` but apply uniformly — the audit's role is to flag the mismatch. -- **Rationale:** `marshal`/`unmarshal` is a Go term of art; TS reaches for `serialize`/`parse` or Zod's parse. Generator-wide concern. - -### 16. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 14. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — `executeCall` runs the retry/rate-limit shell, `executeHttpCall` does the actual HTTP send. They appear together in every client method: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -122,99 +110,81 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Names should reveal the layering, not require code-diving. Generator-wide concern. -### 17. `Call` type and `call` variable — `src/v1/client.ts:86,119,145,187,251` and `src/v1/utils.ts:27` +### 15. `Call` type and `call` variable — `src/v1/client.ts:86,119,145,187,251` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, called inside `executeCall(call, options)`. The same word is the variable, the type, and the verb. Inside one method scope we have `req`, `call`, `httpReq` — three layered names where one of them collides with its type. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions are tolerable but obscure prose-style code. -### 18. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,173,239` +### 16. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,173,239` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. -### 19. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 149-155, 194-199, 261-266` +### 17. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 149-155, 194-199, 261-266` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: EntityTagAssignment`. The names differ only by `Body`. Both are short for "response". The reader has to track which is bytes, which is parsed. Compare `req` (parameter, request) — also abbreviated, but no `reqBody` sibling. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result`, or `responseBytes` + `response`. - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 20. `httpReq` local variable — `src/v1/client.ts:89,122,148,190,254` +### 18. `httpReq` local variable — `src/v1/client.ts:89,122,148,190,254` - **Why weird:** Inside a method that already has `req: CreateEntityTagAssignmentRequest`, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in one scope. -### 21. `pageReq` in `listEntityTagAssignmentsIter` — `src/v1/client.ts:212` -- **Why weird:** Same pattern: inside a method receiving `req: ListEntityTagAssignmentsRequest`, a copy is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; meanwhile the outer `req` is the parameter. Three identifiers — `req`, `pageReq`, the iter's bound — for the same shape over the iteration's lifetime. -- **Category:** 5 (cryptic), 8 (redundant prefix — `page` on a paginated iter is implicit). -- **Suggested name:** `current` or `next` (the iter's evolving cursor state). -- **Rationale:** A variable that mutates a clone of the input parameter usually wants a name that describes *its role* (cursor state), not a casual prefix on the parameter name. - -### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +### 19. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 23. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 20. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just shorthand. -### 24. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` -- **Why weird:** Function takes an arbitrary `unknown` value plus a Zod schema and returns a JSON string. The name says "Request" but the function does not know whether `data` is a request, response, or anything else. Same problem as in `dataclassification`. -- **Category:** 1 (vague — `Request` in the name does not constrain), 6 (misleading — works for any payload). -- **Suggested name:** `marshalToJson` / `encodeToJson`. -- **Rationale:** Symmetric problem to `parseResponse`. Either is fine; both should be specific to actual meaning. - -## Low severity - -### 25. `parseResponse(body, schema)` — `src/v1/utils.ts:113` -- **Why weird:** Symmetric problem to `marshalRequest`. The function parses any JSON `Uint8Array` against a Zod schema. The name says "Response" but the function does not check that. -- **Category:** 1 (vague), 6 (misleading). -- **Suggested name:** `parseJsonBody` / `decodeFromJson`. -- **Rationale:** Same as #24. `marshalRequest` + `parseResponse` are an asymmetric verb pair (`marshal` vs `parse`) AND inaccurate. Either fix both. - -### 26. `flattenQueryParams` — `src/v1/utils.ts:123` +### 21. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package's list endpoint uses individual `params.append(...)` calls instead). Dead-code-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. -### 27. `readAll(body)` — `src/v1/utils.ts:40` +## Low severity + +### 22. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path or array. -### 28. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. Casing is appropriate for a module constant; the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain; the comment above it does the work the name should. -### 29. `inherited` (boolean) on `EntityTagAssignment` — `src/v1/model.ts:48` +### 24. `inherited` (boolean) on `EntityTagAssignment` — `src/v1/model.ts:48` - **Why weird:** A boolean called `inherited`. The participle works (the tag is in an inherited state), but boolean fields are conventionally `is*`/`has*` in TS (`isInherited`). The sibling filter `includeInherited` uses a verb prefix; the marker drops the prefix. Asymmetric. - **Category:** 17 (inconsistent — `inherited` (no prefix) vs. `includeInherited` (verb-prefixed) in same file). - **Suggested name:** `isInherited` on the result type. - **Rationale:** TS booleans usually carry an `is`/`has` prefix to read as predicates. The current name reads grammatically as an adjective on the assignment. -### 30. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` +### 25. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` - **Why weird:** The pair encodes a `(key, value)` tag — that part is fine. But the type is *already* called `EntityTagAssignment`, so the `tag` prefix on each field is redundant within scope: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. - **Category:** 8 (redundant prefix — `tag` within `EntityTagAssignment`). - **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. - **Rationale:** Field names should not re-state their containing type's noun. `assignment.key` / `assignment.value` reads cleaner. -### 31. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` +### 26. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` - **Why weird:** Verb tense pair: `updateTime` (noun-noun, gerund stripped) vs. `updatedBy` (past participle). Cross-SDK convention should pick one. Compare: `createTime` (noun-noun) often pairs with `createdBy` (past participle) in Databricks — the same asymmetry. It is consistent across the SDK, but worth noting under rule 13. - **Category:** 13 (verb-tense inconsistency within a paired field). - **Suggested name:** `updateTime`/`updateBy` or `updatedTime`/`updatedBy`. Either works; the asymmetry is the issue. - **Rationale:** Established SDK pattern, but rule 13 demands the flag. -### 32. `sourceType` vs. `source` (on the enum) — `src/v1/model.ts:46` and `src/v1/model.ts:9` +### 27. `sourceType` vs. `source` (on the enum) — `src/v1/model.ts:46` and `src/v1/model.ts:9` - **Why weird:** Field is `sourceType: TagAssignmentSourceType`. The field name re-states `Type`, and the type name re-states `SourceType`. The user types "source", "Type", "Source", "Type" — four times in one declaration: `sourceType?: TagAssignmentSourceType | undefined`. - **Category:** 20 (type-suffix tautology), 8 (redundant suffix). - **Suggested name:** `source: TagSource` (drop both `Type`s). @@ -222,21 +192,18 @@ ## Observations -### 33. Wire/TS divergence dominates the file -The `model.ts` file is 173 lines for ~7 user-facing types; ~84 lines are `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. - -### 34. Action verb consistency -The client uses `create`/`get`/`update`/`delete`/`list` (plus `listIter`) — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. +### 28. Action verb consistency +The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 35. Acronym casing +### 29. Acronym casing The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 36. `entitytagassignments` lowercase package name +### 30. `entitytagassignments` lowercase package name The package directory is `entitytagassignments` (single token, no separator), but every type uses `EntityTagAssignment` and the HTTP path uses `entity-tag-assignments`. Same problem as `dataclassification`. SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 37. Domain leakage from sister packages +### 31. Domain leakage from sister packages Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index b3283c64..73cbd641 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -5,13 +5,13 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 34 +**Total weird names flagged:** 32 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 15 | +| Medium | 13 | | Low | 8 | | Observation | 2 | @@ -35,7 +35,7 @@ - **Rationale:** Same shape, redefined in two packages, with subtly different naming (`DefaultBaseEnvironment` vs `WorkspaceBaseEnvironment`). Consumers will hit type-incompatibility errors when passing a value from one package into the other. ### 3. `WorkspaceBaseEnvironment` — name is a 26-character noun phrase with three adjectives stacked — `model.ts:727` -- **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. The longest exported identifier is `unmarshalWorkspaceBaseEnvironmentOperationMetadataSchema` at 57 characters (`model.ts:870`). +- **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. - **Category:** 7 (overly verbose), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). - **Suggested name:** Drop one of the prefixes. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. - **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. @@ -74,7 +74,7 @@ - **Rationale:** The name has the worst of every world: Java verb + Proto codegen tag + length. No piece of the name helps a TS consumer. ### 9. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:689, 692` -- **Why weird:** The request type is `RefreshWorkspaceBaseEnvironmentRequest` (singular), but its JSDoc says: "Request message for RefreshWorkspaceBaseEnviro**ments**" (plural). The same type's `name` field doc says: "Required. The resource name of the workspace base environment **to delete**" — i.e. copy-pasted from the delete request and never edited. The `marshalRefreshWorkspaceBaseEnvironmentRequestSchema` (model.ts:885) only emits `name`, confirming the type was forked from the delete request. +- **Why weird:** The request type is `RefreshWorkspaceBaseEnvironmentRequest` (singular), but its JSDoc says: "Request message for RefreshWorkspaceBaseEnviro**ments**" (plural). The same type's `name` field doc says: "Required. The resource name of the workspace base environment **to delete**" — i.e. copy-pasted from the delete request and never edited. - **Category:** 9 (singular/plural mismatch — type vs doc), 6 (misleading doc — says delete). - **Suggested name:** Fix the docstrings — say "Refresh a workspace base environment. The resource name of the environment to refresh." Either keep the type singular (matches the client method `refreshWorkspaceBaseEnvironment`) or move to plural everywhere. - **Rationale:** Wrong action verb in a doc that an IDE will display when the user hovers a parameter. The package was generated from a proto where the message-name was singular but the doc-string copied from elsewhere — the SDK is propagating the bug. @@ -155,71 +155,59 @@ - **Suggested name:** `environmentId`, `id`, or `resourceId`. - **Rationale:** Consumers writing `{workspaceBaseEnvironment: env, workspaceBaseEnvironmentId: 'foo'}` is awkward; `{environment: env, environmentId: 'foo'}` reads better. -### 22. `listWorkspaceBaseEnvironments` and `listWorkspaceBaseEnvironmentsIter` — two list methods, only one paginates — `client.ts:248, 284` -- **Why weird:** `listWorkspaceBaseEnvironments` returns a single page (`ListWorkspaceBaseEnvironmentsResponse` with `nextPageToken`); `listWorkspaceBaseEnvironmentsIter` is an async generator that traverses all pages. The `Iter` suffix is a Go-style hint (Go's `iter.Seq`); in TS the idiomatic distinction is between "returns a Response" vs "returns an AsyncIterable", typically named `listX` (auto-paginating) vs `listXPage` (single page). -- **Category:** 14 (Go-style suffix `Iter`), 17 (inconsistent — `Iter` not used anywhere else and not idiomatic in TS). -- **Suggested name:** `listWorkspaceBaseEnvironmentsPage` (single page) and `listWorkspaceBaseEnvironments` (auto-paginating async iterable). Flip the default to the paginated one. -- **Rationale:** Consumers should fall into the pit of success: by default they want all pages. - -### 23. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:715` +### 22. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:715` - **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:715) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 720) is documented and even references `name`: "The name field is used to identify the environment to update." - **Category:** 19 (underspecified ID), 6 (misleading by omission). - **Suggested name:** Add JSDoc. The field is the resource name to update; say so. Or drop the field entirely if it duplicates `workspaceBaseEnvironment.name`. - **Rationale:** Inconsistent doc coverage in a generated file is a tell that the source proto field has no comment — should be fixed upstream. -### 24. `unmarshal*Schema` / `marshal*Schema` function names use a Go-style verb pair — `model.ts:768, 873` -- **Why weird:** The package uses `unmarshal*Schema` (from wire) and `marshal*Schema` (to wire). The verbs `marshal`/`unmarshal` are Go/Java terminology. JS/TS overwhelmingly uses `parse`/`stringify`, `serialize`/`deserialize`, `encode`/`decode`, or `fromJson`/`toJson`. The names also have a trailing `Schema` suffix that is misleading: `unmarshalXSchema` is in fact a `z.ZodType` *schema*, not a function — its name should reflect that it can be used like `XSchema.parse(...)`. But `marshalXSchema` is *also* a Zod schema with a `.transform` that turns TS→wire — also misleading because consumers might expect `marshalXSchema.parse(x)` to return wire JSON, not a parsed object. -- **Category:** 14 (Go-style names — marshal/unmarshal), 6 (misleading — these are schemas, but they have a `Schema` suffix already; the `marshal`/`unmarshal` prefix tells the user a direction but consumers may not know which). -- **Suggested name:** `xWireSchema` (for wire-format), `xModelSchema` (for TS-format), or split: `decodeX` / `encodeX` as standalone functions wrapping the schemas. -- **Rationale:** A TS consumer doesn't think in `marshal`/`unmarshal`; they think in `parse`/`format`/`fromJSON`/`toJSON`. - --- ## Low severity -### 25. `WorkspaceBaseEnvironmentProvider` — name says "Provider" but values are "ADMIN" / "DATABRICKS" — `model.ts:517` +### 23. `WorkspaceBaseEnvironmentProvider` — name says "Provider" but values are "ADMIN" / "DATABRICKS" — `model.ts:517` - **Why weird:** The enum's name describes a *role* dimension ("who provides this"), but the values are not consistent in part-of-speech: `ADMIN` is a noun-role-type, `DATABRICKS` is an organization name. The docstring at model.ts:516 says "Identifies *who* provides and manages a WorkspaceBaseEnvironment" — and the docstring for `ADMIN` says "Created and managed by workspace admins". So `Provider` is really `Owner` or `ProvidedBy`. Mixing `ADMIN` (a role) with `DATABRICKS` (a company) is the same kind of category-mixing as `User` / `System`. - **Category:** 17 (inconsistency within the enum), 6 (slight misnomer). - **Suggested name:** `WorkspaceBaseEnvironmentOwner` or `BaseEnvironmentProvidedBy`. Values: `Admin | DatabricksManaged`. - **Rationale:** Minor. The intent is clear from context. -### 26. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:750` +### 24. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:750` - **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:750). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:573) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. - **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). - **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. - **Rationale:** Two representations of "is this the default" invite drift. -### 27. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:628` +### 25. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:628` - **Why weird:** Page-size doc says only "Default is 1000". No documented min/max, no behavior on `0`, no behavior on values exceeding server cap. - **Category:** 19 (underspecified). - **Suggested name:** Add doc bounds. - **Rationale:** Doc-only nit; not a name issue per se but worth flagging in a naming audit because `pageSize` is a known naming convention with known semantics that this doc partially undermines. -### 28. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:638` +### 26. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:638` - **Why weird:** Field name is 27 characters; type is a list of 27-character-typed items. Reading `resp.workspaceBaseEnvironments?.[0]?.workspaceBaseEnvironment...` is a chore. (No sub-field of this exact name; included to illustrate the chain length.) - **Category:** 7 (overly verbose), 8 (redundant suffix — same as the type name pluralised). - **Suggested name:** `environments` (the response type is already `ListWorkspaceBaseEnvironmentsResponse`, so the plural field doesn't need to re-state the qualifier). Wire stays `workspace_base_environments`. - **Rationale:** Matches the `clusterlibraries`/`database` audit critique that list responses don't need to repeat their qualifier. -### 29. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:555` +### 27. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:555` - **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. - **Category:** 19 (underspecified), 6 (slightly misleading). - **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. - **Rationale:** Doc-implied invariants that aren't in the type. -### 30. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:740, 744` +### 28. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:740, 744` - **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #20) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. - **Category:** 14 (Google-AIP/Go-style), 13 (verb tense inconsistency), 17 (inconsistent with `lastUpdated` sibling). - **Suggested name:** `createdAt` / `updatedAt`, or align with `creator`/`lastUpdater` — pick one verb tense and apply across the type. - **Rationale:** Stylistic; consistent with the broader codebase critique. -### 31. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:734` +### 29. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:734` - **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:552) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. - **Category:** 19 (underspecified), 1 (slightly generic). - **Suggested name:** Keep but document constraints. - **Rationale:** Minor. -### 32. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:736` +### 30. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:736` - **Why weird:** Doc says "The WSFS or UC Volumes path to the environment YAML file." But the field is `string`. WSFS paths and UC Volume paths have different syntaxes (`/Workspace/...` vs `/Volumes/...`). The type permits any string. A union of the two path types would be more precise but probably not worth the porting effort. - **Category:** 19 (underspecified — the doc lists two valid path types but the type doesn't distinguish). - **Suggested name:** Keep `filepath`/`filePath` (see #17), but document the allowed prefixes. @@ -229,13 +217,13 @@ ## Observation -### 33. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` +### 31. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` - **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. - **Category:** 12 (duplicate concept), 6 (misleading lineage signal). - **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. - **Rationale:** Generator-level; not actionable in TS alone, but worth recording. -### 34. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` +### 32. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` - **Why noteworthy:** The comment on `BaseEnvironmentType` references an internal proto path that public SDK consumers cannot see, cannot navigate to, and have no use for. It's a generator-cycle reminder to Databricks engineers that shouldn't have made it through the porting/codegen scrub. - **Category:** 6 (misleading — refers to a non-public artefact in a doc comment public users see). - **Suggested action:** Strip internal references from generated comments at codegen time. diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index 02118324..3771821d 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -3,15 +3,15 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 **Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 63 +**Total weird names flagged:** 55 ## Summary | Severity | Count | | --- | --- | -| High | 18 | -| Medium | 25 | -| Low | 14 | -| Observation | 6 | +| High | 17 | +| Medium | 24 | +| Low | 9 | +| Observation | 5 | ## High severity @@ -39,85 +39,79 @@ - **Suggested name:** `MlflowMetric`, `MlflowParam`, `MlflowRun`, `MlflowExperiment` — or namespace under `Mlflow.{Metric, Param, Run, Experiment}`. - **Rationale:** Even MLflow's own protobuf calls these `mlflow.Run`, `mlflow.Experiment`, `mlflow.Metric` — they assume a namespace. Flattening them into TS without one loses that disambiguation. -### 5. `Run`, `Experiment`, `LoggedModel`, `Metric` types vs `mlflowRun`, `mlflowMetric`, `mlflowParam` symbols in docs — `client.ts:256, 1231` -- **Why weird:** The `createRun` JSDoc at `client.ts:255-257` says: "MLflow uses runs to track the `mlflowParam`, `mlflowMetric`, and `mlflowRunTag` associated with a single execution." The names `mlflowParam`, `mlflowMetric`, `mlflowRunTag` do **not exist anywhere in the package** — the exported types are `Param`, `Metric`, `RunTag`. The docstring references symbols (probably from the Go SDK's `mlflowParam` Go type names) that the TS port no longer has. -- **Category:** 6 (misleading documentation), 14 (Go-style naming reference left in TS docs). -- **Suggested name:** Either rename the TS types to `MlflowParam` / `MlflowMetric` / `MlflowRunTag` (recommended; see #4) **or** strip the `mlflow` prefix from the docstrings to match the actual TS surface. Same problem on `searchRuns` (`client.ts:1230-1232`): "Search expressions can use `mlflowMetric` and `mlflowParam` keys". -- **Rationale:** The doc references unresolvable symbols. A reader who tries to import `mlflowParam` from the package will fail. - -### 6. `LoggedModel` — `src/v1/model.ts:560` +### 5. `LoggedModel` — `src/v1/model.ts:560` - **Why weird:** `LoggedModel` is a noun-phrase made of past-participle adjective + noun. The "logged" prefix is doing the disambiguation against `RegisteredModel`, `ServingModel`, `MlflowModel` etc. But (a) past-tense adjectives in type names read awkwardly (`LoggedModel`, `DeletedExperiment`, `FinishedRun` would all be similarly weird), and (b) `Logged` does not describe what the type *is* — it describes the verb history that produced it. - **Category:** 6 (misleading: "Logged" describes history, not identity), 13 (verb-tense in noun-phrase). - **Suggested name:** `MlflowModel`, `TrackedModel`, or `RunModel` (since every `LoggedModel` belongs to a Run via `sourceRunId`). -- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #7). +- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #6). -### 7. `LoggedModel` family — 8 separate types — `src/v1/model.ts:560, 568, 579, 607, 615` + 4 request/response — `model.ts:72, 161, 169, 257, 303, 314, 475, 932` +### 6. `LoggedModel` family — 8 separate types — `src/v1/model.ts:560, 568, 579, 607, 615` + 4 request/response — `model.ts:72, 161, 169, 257, 303, 314, 475, 932` - **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModel`, `DeleteLoggedModel`, `DeleteLoggedModelTag`, `FinalizeLoggedModel`, `GetLoggedModel`, `GetLoggedModelsRequest`, `LogLoggedModelParamsRequest`, `SetLoggedModelTags`, `SearchLoggedModels`. The `LoggedModel` prefix is repeated 14 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. - **Category:** 7 (overly verbose), 12 (duplicate concept against `Model*` family that may exist in `modelregistry` package). - **Suggested name:** Either drop the `Logged` and call the family `MlflowModel` / `MlflowModelData` / `MlflowModelInfo` / `MlflowModelParameter` / `MlflowModelTag` / `MlflowModelStatus`, or nest under a namespace. - **Rationale:** 14 occurrences of "LoggedModel" in 12 identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. -### 8. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:607` vs `model.ts:667` +### 7. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:607` vs `model.ts:667` - **Why weird:** Two distinct types both model `{key: string, value: string}` parameter pairs: `LoggedModelParameter` (for a `LoggedModel`) and `Param` (for a `Run`). JSDoc at line 606-612 says "Parameter associated with a `LoggedModel`" and at 666-672 "Param associated with a run". Why one type is spelled out (`Parameter`) and the other abbreviated (`Param`) is unexplained. - **Category:** 12 (duplicate concept), 17 (inconsistent abbreviation: `Parameter` vs `Param`). - **Suggested name:** Align the abbreviation: either both `Parameter` or both `Param`. -- **Rationale:** The difference between `Run.params: Param[]` and `LoggedModel.data.params: LoggedModelParameter[]` forces two zod schemas (`marshalParamSchema` and `marshalLoggedModelParameterSchema` at `model.ts:1819, 1759`) where the names diverge cosmetically. +- **Rationale:** The difference between `Run.params: Param[]` and `LoggedModel.data.params: LoggedModelParameter[]` is cosmetic — the underlying shape is identical. -### 9. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 374, 615, 775` -- **Why weird:** Four `{key: string, value: string}` types, one per parent entity. All four have identical schemas (`marshalExperimentTagSchema`, `marshalRunTagSchema`, `marshalInputTagSchema`, `marshalLoggedModelTagSchema` at `model.ts:1635, 1655, 1769, 1857`). The only differentiator is the parent entity — but the type itself is indistinguishable. +### 8. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 374, 615, 775` +- **Why weird:** Four `{key: string, value: string}` types, one per parent entity. All four have identical shapes. The only differentiator is the parent entity — but the type itself is indistinguishable. - **Category:** 12 (duplicate concept × 4). - **Suggested name:** Adopt a single parent prefix convention so `MlflowTag` (or `Mlflow.Tag`) carries the shared shape, with parent-specific variants only when fields actually diverge. - **Rationale:** An end-user picking the wrong tag type (`InputTag` vs `RunTag` etc.) will not get a compile error because they have the same shape. -### 10. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:712, 722, 732, 768` +### 9. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:712, 722, 732, 768` - **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:721-729`), `RunInfo` is "id, name, status, times, user" (`model.ts:732-765`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:768-773`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. - **Category:** 1 (vague: `Data`/`Info`/`Inputs`), 15 (generic field name). - **Suggested name:** Flatten into `Run` (one object). If they must stay split, name them by content: `RunMetadata` (instead of `RunInfo`), `RunMeasurements` (instead of `RunData`), `RunDatasetsAndModels` (instead of `RunInputs`). - **Rationale:** `RunInfo` vs `RunData` requires the reader to look up the schema to know which fields go where. Naming by content removes that lookup. -### 11. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:579, 568` -- **Why weird:** Same `Info`/`Data` split as `Run` (#10). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. +### 10. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:579, 568` +- **Why weird:** Same `Info`/`Data` split as `Run` (#9). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. -- **Rationale:** Same as #10. +- **Rationale:** Same as #9. -### 12. `GetLoggedModelsRequest` — only request type with a `Request` suffix — `src/v1/model.ts:314, client.ts:578` +### 11. `GetLoggedModelsRequest` — only request type with a `Request` suffix — `src/v1/model.ts:314, client.ts:578` - **Why weird:** Every other request type drops the `Request` suffix: `GetExperiment`, `GetRun`, `CreateRun`, `DeleteRuns`, `SearchRuns`, etc. Then `GetLoggedModelsRequest` (and its response `GetLoggedModelsRequest_Response` — note the double "Request" in the response name) breaks the pattern. `LogLoggedModelParamsRequest` (model.ts:475) and its `Request_Response` companion break it the same way. - **Category:** 20 (type-suffix tautology), 17 (inconsistent action verbs / suffix policy), 7 (verbose). - **Suggested name:** `GetLoggedModels` + `GetLoggedModels_Response`. `LogLoggedModelParams` + `LogLoggedModelParams_Response`. - **Rationale:** Inconsistency within the same file. `GetLoggedModelsRequest_Response` literally reads "request's response" which is a tautology — the request shape and the response shape are different objects. -### 13. `GetLoggedModelsRequest_Response` (and `LogLoggedModelParamsRequest_Response`) double-tautology — `src/v1/model.ts:320, 483` -- **Why weird:** Combining #12 with the proto `_Response` convention produces these absurd names. The exported identifier `GetLoggedModelsRequest_Response` contains both the `Request` suffix (#12) and the `_Response` suffix — "the request's response". +### 12. `GetLoggedModelsRequest_Response` (and `LogLoggedModelParamsRequest_Response`) double-tautology — `src/v1/model.ts:320, 483` +- **Why weird:** Combining #11 with the proto `_Response` convention produces these absurd names. The exported identifier `GetLoggedModelsRequest_Response` contains both the `Request` suffix (#11) and the `_Response` suffix — "the request's response". - **Category:** 20 (suffix tautology), 4 (underscore). - **Suggested name:** `GetLoggedModels_Response` (drop the `Request`). - **Rationale:** Pure word salad. -### 14. `_Response` underscore convention — 32 types — `src/v1/model.ts` throughout +### 13. `_Response` underscore convention — 32 types — `src/v1/model.ts` throughout - **Why weird:** Every response type uses `Foo_Response` with a literal underscore: `CreateExperiment_Response`, `CreateLoggedModel_Response`, `CreateRun_Response`, `DeleteExperiment_Response`, `DeleteLoggedModel_Response`, `DeleteLoggedModelTag_Response`, `DeleteRun_Response`, `DeleteRuns_Response`, `DeleteTag_Response`, `FinalizeLoggedModel_Response`, `GetExperiment_Response`, `GetExperimentByName_Response`, `GetLoggedModel_Response`, `GetLoggedModelsRequest_Response`, `GetMetricHistory_Response`, `GetRun_Response`, `ListArtifacts_Response`, `ListExperiments_Response`, `LogBatch_Response`, `LogInputs_Response`, `LogLoggedModelParamsRequest_Response`, `LogMetric_Response`, `LogModel_Response`, `LogOutputs_Response`, `LogParam_Response`, `RestoreExperiment_Response`, `RestoreRun_Response`, `RestoreRuns_Response`, `SearchExperiments_Response`, `SearchLoggedModels_Response`, `SearchRuns_Response`, `SetExperimentTag_Response`, `SetLoggedModelTags_Response`, `SetTag_Response`, `UpdateExperiment_Response`, `UpdateRun_Response`. Each carries an `eslint-disable-next-line @typescript-eslint/naming-convention` comment, and many that are empty also disable `@typescript-eslint/no-empty-object-type`. - **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names), 7 (verbose). - **Suggested name:** `CreateExperimentResponse` (no underscore). Or, in TS, declare them as a namespace: `namespace CreateExperiment { export interface Response {…} }`. Or flatten with descriptive suffix: `CreateExperimentResult`, `CreateRunResult`. - **Rationale:** 32 lint suppressions in a single file. The convention is leaking proto naming into TS. Google TS style guide § 9.2 forbids underscores in type names. -### 15. `LoggedModelStatus` enum members all prefixed `LOGGED_MODEL_` — `src/v1/model.ts:9-23` +### 14. `LoggedModelStatus` enum members all prefixed `LOGGED_MODEL_` — `src/v1/model.ts:9-23` - **Why weird:** Enum `LoggedModelStatus` has members `LOGGED_MODEL_STATUS_UNSPECIFIED`, `LOGGED_MODEL_PENDING`, `LOGGED_MODEL_READY`, `LOGGED_MODEL_UPLOAD_FAILED`. The enum is already `LoggedModelStatus` — every member re-states `LOGGED_MODEL_`. The first member doubles down: `LOGGED_MODEL_STATUS_UNSPECIFIED`. The others lose the `STATUS_` infix but still keep `LOGGED_MODEL_`. - **Category:** 2 (redundant enum prefix), 17 (inconsistency: only `UNSPECIFIED` carries the full `LOGGED_MODEL_STATUS_` prefix), 18 (long enum values). - **Suggested name:** `LoggedModelStatus.Unspecified | Pending | Ready | UploadFailed`. Or drop `Unspecified` entirely (TS supports optional fields natively). - **Rationale:** `LoggedModelStatus.LOGGED_MODEL_UPLOAD_FAILED` reads as "logged model status: logged model upload failed" — the type name is repeated twice. Inconsistent prefix between `UNSPECIFIED` and the rest is jarring. -### 16. `RunStatus` enum has no `UNSPECIFIED` value — inconsistent with `LoggedModelStatus` and `ViewType` — `src/v1/model.ts:26-37` +### 15. `RunStatus` enum has no `UNSPECIFIED` value — inconsistent with `LoggedModelStatus` and `ViewType` — `src/v1/model.ts:26-37` - **Why weird:** Two of the three enums in the file follow the proto-style "include UNSPECIFIED sentinel" pattern. `RunStatus` does not. Five values: `RUNNING`, `SCHEDULED`, `FINISHED`, `FAILED`, `KILLED`. Either the Run state machine has no "unknown" — fine — but the inconsistency reduces grep-ability. - **Category:** 17 (inconsistency across enums in same file). - **Suggested name:** Either drop `UNSPECIFIED` from `LoggedModelStatus` and `ViewType` too (best — TS uses `undefined`), or add `RunStatus.UNSPECIFIED` for symmetry. - **Rationale:** Pick one policy. Sibling enums disagreeing on the sentinel makes patterns hard to learn. -### 17. `KILLED` enum value — `src/v1/model.ts:36` +### 16. `KILLED` enum value — `src/v1/model.ts:36` - **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." - **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). - **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. - **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). -### 18. `ViewType` enum — generic name + redundant value names — `src/v1/model.ts:40-47` +### 17. `ViewType` enum — generic name + redundant value names — `src/v1/model.ts:40-47` - **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). Three values are `ACTIVE_ONLY`, `DELETED_ONLY`, `ALL` — all SCREAMING_SNAKE_CASE TS identifiers when most TS enums use PascalCase. Plus `ALL` is a built-in reserved-feeling word and a poor key. The same enum is used as `viewType` on `ListExperiments` (model.ts:416), `runViewType` on `SearchRuns` (model.ts:897), and `viewType` on `SearchExperiments` (model.ts:800) — two fields named `viewType` and one named `runViewType` for the same enum. - **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). - **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Values: `ActiveOnly | DeletedOnly | All`. Field name: pick one (`viewType` everywhere, or rename uniformly). @@ -125,113 +119,107 @@ ## Medium severity -### 19. `GetLoggedModels` method returns `GetLoggedModelsRequest_Response` — `src/v1/client.ts:577-608` +### 18. `GetLoggedModels` method returns `GetLoggedModelsRequest_Response` — `src/v1/client.ts:577-608` - **Why weird:** The method is `getLoggedModels(req: GetLoggedModelsRequest)`. Method name has no `Request` suffix, but the parameter type does. Compare to `getExperiment(req: GetExperiment)` two methods up. Same problem with `logLoggedModelParams(req: LogLoggedModelParamsRequest)` (`client.ts:921`). - **Category:** 17 (inconsistency), 20 (suffix tautology). -- **Suggested name:** Drop the `Request` suffix on the type names to match the method names. Already raised in #12. +- **Suggested name:** Drop the `Request` suffix on the type names to match the method names. Already raised in #11. -### 20. `getMetricHistory` / `GetMetricHistory` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:325, client.ts:611` +### 19. `getMetricHistory` / `GetMetricHistory` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:325, client.ts:611` - **Why weird:** Type name `GetMetricHistory` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRun`, `DeleteExperiment`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". - **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). - **Suggested name:** `GetMetricValues` / `getMetricValues`, or `ListMetricHistory` / `listMetricHistory` (since it paginates). - **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. -### 21. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:978-984` -- **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModel`, `LogModel_Response`, and `marshalLogModelSchema`. The method `createLoggedModel` is the replacement. +### 20. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:978-984` +- **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModel` and `LogModel_Response`. The method `createLoggedModel` is the replacement. - **Category:** 6 (misleading — exported as if it were current). - **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModel`, `LogModel_Response`. - **Rationale:** A linter or IDE that reads `@deprecated` will warn users; a plaintext note in the markdown JSDoc body will not. -### 22. `runUuid` deprecated field appears on 6 types — `src/v1/model.ts:332, 365, 389, 492, 546, 739, 949, 976` +### 21. `runUuid` deprecated field appears on 6 types — `src/v1/model.ts:332, 365, 389, 492, 546, 739, 949, 976` - **Why weird:** Eight different types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. - **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). - **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. - **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. -### 23. `userId` deprecated — `src/v1/model.ts:101, 749` -- **Why weird:** Same problem as #22 but for `userId` on `CreateRun.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. +### 22. `userId` deprecated — `src/v1/model.ts:101, 749` +- **Why weird:** Same problem as #21 but for `userId` on `CreateRun.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. - **Category:** 6. -- **Suggested name:** Add `@deprecated`. Same as #22. +- **Suggested name:** Add `@deprecated`. Same as #21. -### 24. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 587-589` +### 23. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 587-589` - **Why weird:** `Experiment` uses `lastUpdateTime` and `creationTime` (no unit suffix). `LoggedModelInfo` uses `creationTimestampMs` and `lastUpdatedTimestampMs` (with unit suffix). Both are Unix ms timestamps. Three things vary: (a) `Time` vs `Timestamp`, (b) `Update` vs `Updated`, (c) presence of `Ms` unit suffix. - **Category:** 17 (inconsistency in field naming for the same concept), 3 (casing inconsistency), 9 (singular/plural-ish noun tense `Update` vs `Updated`). - **Suggested name:** Pick one: `createdAt` / `updatedAt` (typical JS), or `creationTimeMs` / `lastUpdateTimeMs` (explicit unit). Match across `Experiment`, `LoggedModelInfo`, `RunInfo`, etc. - **Rationale:** Three timestamp formats in one package means users guess which type uses which. -### 25. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:753, 755` +### 24. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:753, 755` - **Why weird:** Adds a fourth timestamp naming style to the package: bare `startTime` / `endTime` with no unit. JSDoc says "Unix timestamp of when the run started in milliseconds" — buried in prose. - **Category:** 17 (inconsistency). -- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #24. +- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #23. -### 26. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 697` +### 25. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 697` - **Why weird:** Fifth style: `DeleteRuns.maxTimestampMillis` and `RestoreRuns.minTimestampMillis` use `Millis` suffix (not `Ms`, not unsuffixed). Same package. Five different naming choices for unix-ms timestamps: `creationTime`, `lastUpdateTime`, `startTime`/`endTime`, `creationTimestampMs`/`lastUpdatedTimestampMs`, `maxTimestampMillis`/`minTimestampMillis`. - **Category:** 17 (inconsistency × 5), 3 (casing inconsistency — `Ms` vs `Millis`). - **Suggested name:** Pick one suffix (`Ms` is common, `Millis` is rarer) and apply uniformly. -- **Rationale:** Same as #24. +- **Rationale:** Same as #23. -### 27. `creatorId: number` (not string) — `src/v1/model.ts:595` +### 26. `creatorId: number` (not string) — `src/v1/model.ts:595` - **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." - **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). - **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. - **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). -### 28. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout -- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:622`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#27). +### 27. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout +- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:622`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#26). - **Category:** 19 (underspecified IDs coexist), 16 (`creatorId` is `number`, others `string`). - **Suggested name:** Add prefix discipline: the model's own ID is `id` (or `modelId` everywhere); a referenced ID is `Id` (`sourceRunId`, `parentExperimentId`). Document the convention. - **Rationale:** Today, every type has its own private convention; users must check each schema. -### 29. `modelId` ambiguity in `Metric` — `src/v1/model.ts:643-647` +### 28. `modelId` ambiguity in `Metric` — `src/v1/model.ts:643-647` - **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. - **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). - **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). - **Rationale:** Heterogeneous string ID fields are debugging traps. -### 30. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:560-565, 579-583` -- **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#11) buries the ID one level deep. +### 29. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:560-565, 579-583` +- **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#10) buries the ID one level deep. - **Category:** 15 (generic field name losing meaning), 7 (verbose access). - **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). - **Rationale:** Awkward access pattern. -### 31. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:741, 583` +### 30. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:741, 583` - **Why weird:** Two fields named `experimentId`, two completely different relationships. On `RunInfo` the field connects the run to its parent experiment. On `LoggedModelInfo` it connects the model to its owning experiment. JSDoc only on one of them. - **Category:** 15 (generic name losing meaning across contexts). - **Suggested name:** Both are fine as `experimentId` if doc consistently says "parent experiment". The issue is uneven JSDoc. -### 32. `marshalLogMetricSchema` includes deprecated `runUuid` in output — `src/v1/model.ts:1701-1723` -- **Why weird:** `marshalLogMetricSchema` writes `run_uuid: d.runUuid` to the wire, even though the field is marked deprecated. Future MLflow versions may reject this. The marshaller has no way to suppress the deprecated field unless the user explicitly leaves `runUuid` undefined. -- **Category:** 6 (misleading: TS surface lets you set a field that the API has deprecated). -- **Suggested name:** Strip `runUuid` from the marshal schema. -- **Rationale:** Defensive output filtering belongs at the SDK layer. - -### 33. Method names `getLoggedModels` / `getLoggedModelsRequest` mismatch — type is `GetLoggedModelsRequest`, method is `getLoggedModels` — `src/v1/client.ts:577` +### 31. Method names `getLoggedModels` / `getLoggedModelsRequest` mismatch — type is `GetLoggedModelsRequest`, method is `getLoggedModels` — `src/v1/client.ts:577` - **Why weird:** Caller writes `client.getLoggedModels({...})` — but the type the request maps to is `GetLoggedModelsRequest`. Looking at the method name alone you wouldn't guess the type carries the `Request` suffix. - **Category:** 17 (inconsistency). -- **Suggested name:** Already covered by #12 — drop `Request`. +- **Suggested name:** Already covered by #11 — drop `Request`. -### 34. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:475` +### 32. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:475` - **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:921`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). -- **Suggested name:** `AddMlflowModelParams` + `addMlflowModelParams`, or `LogParamsForModel` + `logParamsForModel`, or drop `Logged` once the rename in #7 is applied: `LogMlflowModelParams`. +- **Suggested name:** `AddMlflowModelParams` + `addMlflowModelParams`, or `LogParamsForModel` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParams`. - **Rationale:** The double-Log is jarring on read. -### 35. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1276, 1302` +### 33. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1276, 1302` - **Why weird:** `setExperimentTag(req: SetExperimentTag)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTags)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 36. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` +### 34. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` - **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. - **Category:** Observation (URL design upstream). -### 37. `logBatch` does not say "log run batch" — `src/v1/client.ts:865` +### 35. `logBatch` does not say "log run batch" — `src/v1/client.ts:865` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 38. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 36. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -245,131 +233,86 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 39. `LogInputs.datasets` vs `LogInputs.models` field names — `src/v1/model.ts:463-470` +### 37. `LogInputs.datasets` vs `LogInputs.models` field names — `src/v1/model.ts:463-470` - **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. - **Category:** 15 (generic field name losing structure). -### 40. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:770, 772` +### 38. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:770, 772` - **Why weird:** `RunInputs.datasetInputs: DatasetInput[]` and `RunInputs.modelInputs: ModelInput[]`. The field name and the element type both carry `Input`. So a user reads `runInputs.datasetInputs[0].tags` — the word "input" appears three times in a single access path. - **Category:** 20 (suffix tautology), 7 (verbose). - **Suggested name:** `RunInputs.datasets: DatasetInput[]` and `RunInputs.models: ModelInput[]`. -### 41. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` +### 39. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` - **Why weird:** Both fields are typed `string` and named with generic English words. JSDoc shows the wire format is freeform JSON-stringified content. The field types don't help. - **Category:** 15 (generic field name losing meaning), 6 (misleading: schema is freeform stringified JSON, not a real schema). - **Suggested name:** `schemaJson` / `profileJson` (mirrors `LogModel.modelJson`) so the user knows to JSON-parse them. Already see the pattern at `LogModel.modelJson` (model.ts:523). -### 42. `LogModel.modelJson` — bare json string field — `src/v1/model.ts:519-524` +### 40. `LogModel.modelJson` — bare json string field — `src/v1/model.ts:519-524` - **Why weird:** `LogModel.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. - **Category:** Observation (an opaque blob field could carry doc). -### 43. `Dataset.digest` — `src/v1/model.ts:124-124` +### 41. `Dataset.digest` — `src/v1/model.ts:124-124` - **Why weird:** `digest` is technical jargon (cryptographic hash). MLflow uses it; consumers may not. JSDoc: "Dataset digest, e.g. an md5 hash". Could be `contentHash` or `fingerprint`. - **Category:** 5 (cryptic abbreviation — `digest` is industry-specific). -### 44. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:764` +## Low severity + +### 42. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:764` - **Why weird:** `RunInfo.lifecycleStage` JSDoc says: "Current life cycle stage of the experiment : OneOf("active", "deleted")". But this is a `Run`'s `lifecycleStage`, not the experiment's. Same field on `Experiment.lifecycleStage` (model.ts:230) is correctly described. - **Category:** 6 (misleading doc — wrong entity name in description). - **Suggested name:** Fix doc to say "Current life cycle stage of the run". -### 45. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 603, 728` -- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #9. The field is consistently `tags`, but the element type is not unifiable in TS without changes. +### 43. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 603, 728` +- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #8. The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 46. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 44. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 47. `FileInfo` itself is a generic name — `src/v1/model.ts:247` +### 45. `FileInfo` itself is a generic name — `src/v1/model.ts:247` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. -## Low severity - -### 48. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` +### 46. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` - **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. - **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). - **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). -### 49. `HttpCallOptions` — `src/v1/utils.ts:15` +### 47. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). - **Category:** 17 (collision risk with `CallOptions`). -### 50. `marshalRequest` / `parseResponse` — verbs are inconsistent — `src/v1/utils.ts:113, 119` -- **Why weird:** `marshalRequest` (verb=marshal, suffix=Request) and `parseResponse` (verb=parse, suffix=Response). Marshal is the wire-out; parse is the wire-in. The verbs (`marshal` vs `parse`) and the suffixes (`Request` vs `Response`) are split. Counterparts would be `marshal`/`unmarshal` (Go style) or `encode`/`decode`, or `serialize`/`deserialize`. -- **Category:** 17 (inconsistent verb pairing). -- **Suggested name:** `marshalRequest` / `unmarshalResponse`, matching the `unmarshal*Schema` zod schemas in `model.ts:992-1521`. - -### 51. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` +### 48. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` - **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) - **Category:** Observation (dead export). -### 52. `marshal*Schema` constants are not actually `Schema` objects — `src/v1/model.ts:1523-2009` -- **Why weird:** Constants like `marshalDatasetSchema` carry the `Schema` suffix and are typed `z.ZodType`, but the suffix in JS-land would more naturally be `Codec` or `Serializer`. `Schema` reads as "the shape definition", but these objects also perform the transformation (camelCase → snake_case). -- **Category:** 6 (slightly misleading — `Schema` implies pure shape). -- **Suggested name:** `marshalDatasetCodec` / `unmarshalDatasetCodec`. Or just keep `Schema` consistently. - -### 53. `marshalCreateExperimentSchema` etc. — Generated zod schemas with no type parameter — `src/v1/model.ts:1523` -- **Why weird:** Many `marshal*Schema` constants are typed `z.ZodType` (no type parameter). The unmarshal counterparts are typed `z.ZodType` with the target type. So the input side is unchecked. -- **Category:** Observation (looser typing on marshal vs unmarshal). - -### 54. `PACKAGE_SEGMENT` constant in `client.ts:164` — `src/v1/client.ts:164` +### 49. `PACKAGE_SEGMENT` constant in `client.ts:164` — `src/v1/client.ts:164` - **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. - **Category:** 17 (inconsistency in identifier case across the file). - **Suggested name:** `packageSegment` per TS conventions. -### 55. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:165` +### 50. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:165` - **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. - **Category:** 1 (generic name leaking into observability). -### 56. `getMetricHistoryIter`, `listArtifactsIter`, `listExperimentsIter`, `searchExperimentsIter`, `searchRunsIter` — `Iter` suffix — `src/v1/client.ts:653, 752, 806, 1182, 1258` -- **Why weird:** Five paginating async-generators named `*Iter`. JS convention is `*Iterator` or simply `for-await-of`-friendly methods returning AsyncGenerator without a suffix. `Iter` is a Go/Rust convention. -- **Category:** 14 (Go-style suffix), 7 (cryptic abbreviation). -- **Suggested name:** `getMetricHistoryAll`, `listExperimentsAll` (returns AsyncGenerator), or `iterateExperiments`, or no suffix and use the method overload pattern. - -### 57. `searchLoggedModels` has no `*Iter` counterpart — `src/v1/client.ts:1200` -- **Why weird:** Every other search/list method has a paginating helper (`searchExperimentsIter`, `searchRunsIter`, etc.). `searchLoggedModels` is paginated (the response has `nextPageToken: model.ts:874`) but the client lacks a `searchLoggedModelsIter`. -- **Category:** 17 (inconsistency in client surface). -- **Suggested name:** Add `searchLoggedModelsIter`. - -### 58. `getLoggedModels` (batch get) has no `*Iter` — `src/v1/client.ts:577` -- **Why weird:** A batch endpoint that takes a list of IDs and returns a list. No pagination → no `Iter`. Fine. Worth noting that this is `getLoggedModels` (plural) — but `getLoggedModel` (singular, line 552) is the single-fetch. Two methods that differ only by `s` is grep-hostile. -- **Category:** Observation (grep-hostile pair `getLoggedModel` vs `getLoggedModels`). - -### 59. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 504, 633` -- **Why weird:** JSDoc on `Dataset.name`, `LogMetric.datasetName`, `Metric.datasetName` includes the literal example `“fantastic-elk-3”` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. -- **Category:** Observation (smart quotes + boilerplate example). - -### 60. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-129` -- **Why weird:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. -- **Category:** 6 (misleading — field name suggests truth, doc admits not). - -### 61. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` -- **Why weird:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. -- **Category:** 16 (field contradicting type domain — should be a 2-value enum). -- **Suggested name:** `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. - ## Observations (non-actionable but noted) -### 62. Marshal/unmarshal schema asymmetry — only unmarshal types are exported — `src/v1/model.ts:992 vs 1523` -- **Note:** Both directions exist. Only unmarshal schemas are typed (`z.ZodType`); marshal schemas are `z.ZodType` (untyped). Cross-package consumers cannot validate request bodies type-safely. +### 51. `getLoggedModels` (batch get) has no `*Iter` — `src/v1/client.ts:577` +- **Note:** A batch endpoint that takes a list of IDs and returns a list. No pagination → no `Iter`. Fine. Worth noting that this is `getLoggedModels` (plural) — but `getLoggedModel` (singular, line 552) is the single-fetch. Two methods that differ only by `s` is grep-hostile. -### 63. No `experimentId` namespace prefix on most fields — generic ID pattern — `src/v1/model.ts` throughout -- **Note:** Every type that references an experiment uses `experimentId: string`; same for runs (`runId`) and models (`modelId`). When two ID kinds coexist on the same type (e.g. `Metric.modelId` + `Metric.runId`, `LoggedModelInfo.modelId` + `LoggedModelInfo.experimentId` + `LoggedModelInfo.sourceRunId`), the prefix discipline works. The naming convention is consistent — note that no `id` (bare) is ever used as a primary key, which is the right call. +### 52. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 504, 633` +- **Note:** JSDoc on `Dataset.name`, `LogMetric.datasetName`, `Metric.datasetName` includes the literal example `“fantastic-elk-3”` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. -### 64. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` -- **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). - -### 65. `runViewType: ViewType` on `SearchRuns` — uses ViewType enum but renames it — `src/v1/model.ts:897` -- **Note:** Already covered in #18. The wire field is `run_view_type` (model.ts:1943); the TS field is `runViewType`. Two other usages (`ListExperiments.viewType`, `SearchExperiments.viewType`) use just `viewType`. The renaming on `SearchRuns` is unique and likely a wire-protocol legacy. +### 53. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-129` +- **Note:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. -### 66. `package.json` description is empty string — `package.json:4` -- **Note:** Every sister package has a description. Not a naming issue, but flagged for completeness. +### 54. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +- **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. -### 67. No `accountId` plumbing in `Client` constructor — `src/v1/client.ts:178-192` -- **Note:** Comparing to recent commit `81c7569 Add accountId to ClientOptions` — the experiments client passes the entire `ClientOptions` to `newHttpClient` so it inherits whatever account-level handling there is, but does not expose it. Not a naming issue. - -### 68. `_Response` _ underscore vs PascalCase pair — naming convention inconsistency — `src/v1/model.ts` throughout -- **Note:** Adopting a TS-friendly response naming would also require migrating the eslint suppression comments (currently `// eslint-disable-next-line @typescript-eslint/naming-convention` on every Response). 32 such suppressions in `model.ts` would all go away. +### 55. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` +- **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). + + \ No newline at end of file diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index b2cb083c..22b352cd 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -3,15 +3,15 @@ **Path:** `packages/externallineage/src/v1/` **Versions audited:** v1 **Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 31 +**Total weird names flagged:** 26 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 11 | +| Medium | 7 | | Low | 8 | -| Observation | 4 | +| Observation | 3 | ## High severity @@ -77,61 +77,37 @@ - **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. -### 11. `marshalCreateRequestExternalLineageSchema` / `marshalDeleteRequestExternalLineageSchema` / `marshalUpdateRequestExternalLineageSchema` — `src/v1/model.ts:477, 497, 588` -- **Why weird:** Three Zod schemas named with the inverted `*RequestExternalLineage` naming (see #3). They are structurally identical — same five fields. The names burn ~37 characters each. -- **Category:** 7 (overly verbose), 12 (duplicate concept — three identical schemas), 14 (Go-style verb `marshal`). -- **Suggested name:** Collapse to one schema `marshalExternalLineageRelationshipSchema` and reuse for all three call sites. Or, if separation must be preserved for future divergence, name them `marshalCreate…RelationshipSchema` to match the entity-first convention. -- **Rationale:** Three identical schemas is generator overhead. The names re-state what the type system already says. - -### 12. `unmarshalExternalLineageRelationshipSchema` and 9 sibling Zod schemas — `src/v1/model.ts:257-465` -- **Why weird:** All Zod schemas use `marshal`/`unmarshal` (Go terminology) where TS / JS users say `encode`/`decode` or `serialize`/`parse`. Within Zod's own docs the verb is `parse`. Mixing Go vocabulary with a TS library is jarring. -- **Category:** 14 (Go-style names imported into TS), 17 (verb inconsistency — Zod's own API is `.parse()`). -- **Suggested name:** `decodeExternalLineageRelationship` / `encodeExternalLineageRelationship`, or `externalLineageRelationshipFromWire` / `externalLineageRelationshipToWire`. -- **Rationale:** Marshal/unmarshal is a Go term of art (`encoding/json` package); TS developers reach for `JSON.stringify`/`JSON.parse` or Zod's `parse`/`safeParse`. The current name forces a vocabulary translation. - -### 13. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` +### 11. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. - **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. -### 14. `marshalRequest(data, schema)` and `parseResponse(body, schema)` — `src/v1/utils.ts:119, 113` -- **Why weird:** The functions take an arbitrary `unknown` and a Zod schema and return JSON string / typed object. The names say "Request"/"Response" but the functions are content-agnostic. The pair also uses inconsistent verbs: `marshal` (Go) for the encode side and `parse` (TS/Zod) for the decode side. -- **Category:** 1 (vague — `Request`/`Response` does not constrain), 6 (misleading — works for any payload), 17 (asymmetric verb pair). -- **Suggested name:** `encodeJson` / `decodeJson`, or `toWireJson` / `fromWireJson`. Pair the verbs so they're symmetric. -- **Rationale:** `Request`/`Response` should refer to a request or response specifically. Symmetric verbs make the pair readable. - -### 15. `updateRequestExternalLineageFieldMaskSchema` and `updateRequestExternalLineageFieldMask(...)` — `src/v1/model.ts:646, 660` -- **Why weird:** Two exports differ only by the `Schema` suffix; the helper function and its lookup table share a stem. A reader has to look up which is the runtime schema vs. the factory function. Function/data naming should be more distinguishable. -- **Category:** 17 (inconsistent action verbs — schema is a noun, but the function uses the same name as a verbless noun). -- **Suggested name:** `buildUpdateRequestExternalLineageFieldMask(...)` for the function, leave the schema with `Schema` suffix. -- **Rationale:** Functions should be verb-prefixed; the schema-vs-builder distinction should jump off the page. Sister packages share this problem (generator-wide). - -### 16. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 12. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` +### 13. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 18. `flattenQueryParams` — `src/v1/utils.ts:123` +### 14. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. - **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). - **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. - **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). -### 19. `LineageTableInfo.name` — `src/v1/model.ts:201` +### 15. `LineageTableInfo.name` — `src/v1/model.ts:201` - **Why weird:** Field literally called `name` with JSDoc "Name of Table." (capitalised "Table" mid-sentence). The neighbour fields are `catalogName` and `schemaName` — so the type has `(name, catalogName, schemaName)`. Inconsistent: two fields use the `*Name` suffix while the table name itself drops it. Most readers will reach for `tableName`. - **Category:** 1 (vague — `name` of what?), 15 (generic field name losing meaning), 17 (inconsistent within the same type — `name` vs `catalogName` vs `schemaName`). - **Suggested name:** `tableName: string` (and JSDoc punctuation fix). - **Rationale:** Within `LineageTableInfo`, the canonical name for "the table's name" is `tableName`. Mixing `name`, `catalogName`, `schemaName` makes the table's own name look special when it isn't. -### 20. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` +### 16. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` - **Why weird:** Field is `name?: string` with no JSDoc. Type is named to encode "external metadata object on the external-lineage edge". Given the wider package uses `name` for tables, models, external metadata, paths-via-`url`, the field gives up domain meaning to be terse. - **Category:** 1 (vague `name`), 15 (generic field name), 19 (underspecified ID — for `ExternalMetadata`, the `name` is actually a fully-qualified resource path including the metastore). - **Suggested name:** `externalMetadataName: string` with a JSDoc clarifying the expected format (mirror the `ExternalMetadata.name` JSDoc on the externalmetadata package). @@ -139,49 +115,49 @@ ## Low severity -### 21. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` +### 17. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` - **Why weird:** Field is `url?: string` on a type called `*Path`. A `Path` whose only field is a `url` — two different nouns for the same thing. Compare with `LineageFileInfo.path` and `ExternalLineageRelationshipPath.url`: the file `path` and the lineage-path `url` carry the same kind of value. - **Category:** 1 (vague), 6 (misleading — `Path` and `url` are not the same), 12 (duplicate concept — `path` and `url` interchangeable across the package), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the type to `LineagePathObject` and call the field `path: string`, or rename the field to keep the type name: `path?: string`. - **Rationale:** Pick one of `path` or `url` for storage location strings and stick to it. -### 22. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +### 18. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` - **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#8) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. - **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). - **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) - **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. -### 23. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 19. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). - **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. - **Rationale:** Type name should reflect the dominant content; current name is misleading. -### 24. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +### 20. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` - **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. - **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). - **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. - **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. -### 25. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 85-92, 107, 134-186, 202-235` +### 21. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 85-92, 107, 134-186, 202-235` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. - **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 26. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` +### 22. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` - **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in the same scope. -### 27. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` +### 23. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 28. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` +### 24. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. @@ -189,29 +165,23 @@ ## Observations -### 29. Method names re-state the entity verbosely +### 25. Method names re-state the entity verbosely All four methods (`createExternalLineageRelationship`, `updateExternalLineageRelationship`, `deleteExternalLineageRelationship`, `listExternalLineageRelationships`) end with `ExternalLineageRelationship`. The package is *named* `externallineage`, so the entity is obvious from the import path. `client.create(...)` / `client.list(...)` would be both terser and more readable, but generator-wide consistency probably wins. - **Category:** 7 (overly verbose) — generator-wide pattern, listed as observation only. -### 30. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +### 26. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #6. - **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). -### 31. Wire-format singular `external_lineage_info` +### 27. Wire-format singular `external_lineage_info` The unmarshal schema at `model.ts:279` maps the wire key `external_lineage_info` (singular) onto the TS field `externalLineageInfo`. The wire is consistent with the TS muddle. Worth flagging as upstream: the API itself names the edge-metadata field `external_lineage_info` when it would more accurately be `relationship`. - **Category:** 6 (misleading), generator-wide concern. -### 32. `listExternalLineageRelationshipsIter` — `src/v1/client.ts:180` -- **Why weird:** Suffix `Iter` is Go-style (Go uses `*Iterator` types). TS has no `Iter` convention — typical names are `AsyncIterable`, `*Stream`, or just verb-only with the return type tagged as `AsyncGenerator`. Also the method takes the same request the non-`Iter` variant takes and silently mutates the local clone of `pageReq.pageToken` to walk pages. -- **Category:** 14 (Go-style name), 17 (action-verb inconsistency — non-iter method is `listExternalLineageRelationships`, no `List` prefix needed on the async-generator twin). -- **Suggested name:** `streamExternalLineageRelationships` or `iterateExternalLineageRelationships` (returns `AsyncIterable`). -- **Rationale:** `Iter` is Go terminology. TS convention prefers `stream`/`iterate`/`*Iterable`. - ## Domain glossary - `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. - `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). - `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #22. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #18. - `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). - `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index a394b808..c5db02a2 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -11,7 +11,7 @@ update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting sub-structure is `FileEventQueue` — an oneof-of-oneofs across four cloud providers (Azure AQS, AWS SQS, GCP Pub/Sub, OneLake Fabric Eventstream) with a parallel "provided" vs "managed" axis (8 cases total). -**Total weird names flagged:** 62 +**Total weird names flagged:** 57 --- @@ -33,12 +33,9 @@ parallel "provided" vs "managed" axis (8 cases total). | 12 | `OneLakeEventQueue` vs `OneLake` (no Azure/Fabric prefix) | model.ts:240 | type | Low | 3 Acronym casing, 1 Vague/generic | OneLake is a Microsoft Fabric product. Other Azure-side types in the file lead with `Azure`. `OneLake` requires Fabric product knowledge to recognize. | | 13 | `Pubsub` casing inside `GcpPubsub` | model.ts:186 | type | Low | 3 Acronym casing | GCP's product brand is "Pub/Sub". The TS type uses `Pubsub`. Consistent with field names but not with marketing. Same applies to `providedPubsub`/`managedPubsub`. | | 14 | `DeleteExternalLocation_Response` underscore | model.ts:109 | interface | High | 4 Underscores in TS identifiers | Proto-style nested-message encoded as `Parent_Child` with a literal underscore. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` (file already has the disable on line 108). | -| 15 | `ListExternalLocations_Response` underscore | model.ts:224 | interface | High | 4 Underscores in TS identifiers | Same as #14. Disable on line 223. Underscore identifiers also propagate to `unmarshalListExternalLocations_ResponseSchema` (line 467) and `unmarshalDeleteExternalLocation_ResponseSchema` (line 343). | +| 15 | `ListExternalLocations_Response` underscore | model.ts:224 | interface | High | 4 Underscores in TS identifiers | Same as #14. Disable on line 223. Underscore identifiers also propagate to related helpers downstream. | | 16 | `nameArg` field | model.ts:103, 198, 263 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocation`, `GetExternalLocation`, `UpdateExternalLocation`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | | 17 | `providedOnelake` / `managedOnelake` (case key spelling) | model.ts:176, 182 | field | Medium | 3 Acronym casing | OneLake is officially "OneLake" (camelCase capitalized "L"). The case key spells it `Onelake` (one capital). The interface name uses `OneLake` (two capitals). Inconsistent within the same file. | -| 18 | `marshal*Schema` / `unmarshal*Schema` constants | model.ts:318-746 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go idioms; JS uses `encode`/`decode` or `serialize`/`deserialize`. `Schema` is tautological with the `z.ZodType` type. Generator-wide pattern. | -| 19 | `marshalXxxSchema: z.ZodType` (no type parameter) | model.ts:501-746 | const set | Medium | (typing asymmetry) | All `marshal*Schema` exports are typed `z.ZodType` (no type argument), while `unmarshal*Schema` exports are typed `z.ZodType`. Asymmetric. The marshal side loses input-type guarantees. | -| 20 | `parseResponse` vs `marshalRequest` | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | Mixed verbs within one file: `parse`/`marshal`. Pair them as `parse`/`format`, `marshal`/`unmarshal`, or `decode`/`encode`. | --- @@ -187,22 +184,6 @@ GCP's product is "Pub/Sub" (with slash and two capitals). The TS type is `GcpPubsub` (one capital). Internally consistent (the discriminator cases `providedPubsub`/`managedPubsub` match), but not the canonical GCP spelling. -### M6. `marshal*Schema: z.ZodType` (no type parameter) - -```ts -export const marshalCreateExternalLocationSchema: z.ZodType = z.object({ ... }); -``` - -vs - -```ts -export const unmarshalExternalLocationInfoSchema: z.ZodType = ... -``` - -Asymmetric. The marshal side loses input-type guarantees. A consumer who -passes the wrong shape to `marshalRequest(data, marshalCreateExternalLocationSchema)` -gets a runtime error instead of a TS error. - --- ## Low severity (nits) @@ -249,22 +230,21 @@ The following acronyms appear: ## Summary -20 findings: +17 findings: - **3 High severity** — enum stutter, `nameArg` artifact, underscore TS identifiers. -- **6 Medium severity** — `AQS` JSDoc copy-paste error in AWS type, +- **5 Medium severity** — `AQS` JSDoc copy-paste error in AWS type, naming-pattern inconsistency across the four queue types, OneLake casing - inconsistency, AQS abbreviation, Pubsub casing, `marshal*Schema` type-parameter - asymmetry. + inconsistency, AQS abbreviation, Pubsub casing. - **0 Low severity (nits)**. Primary themes: 1. **Generator-encoded proto patterns dominate**: underscore-named nested - message types, SCREAMING_SNAKE enum members, the `marshal`/`unmarshal` - verbs, and the `nameArg` path-vs-body disambiguation are all proto/Go-SDK - artifacts that idiomatic TS would express differently. + message types, SCREAMING_SNAKE enum members, and the `nameArg` path-vs-body + disambiguation are all proto/Go-SDK artifacts that idiomatic TS would + express differently. 2. **Cloud-provider naming is internally inconsistent**: four queue-config types with four different naming conventions, OneLake spelled three ways, AQS abbreviation that isn't Microsoft canonical, copy-paste error mixing diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index 539f8a98..dd443b13 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -3,15 +3,15 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 40 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | | High | 11 | -| Medium | 13 | -| Low | 11 | -| Observation | 5 | +| Medium | 12 | +| Low | 10 | +| Observation | 4 | ## High severity @@ -149,99 +149,69 @@ - **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. - **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. -### 23. `marshalExternalMetadataSchema` / `unmarshalExternalMetadataSchema` — `src/v1/model.ts:157,104` -- **Why weird:** Zod schemas, but named with Go terminology (`marshal`/`unmarshal`) where TS / JS users say `encode`/`decode` or `serialize`/`parse`. Within Zod's own docs the verb is `parse`. Mixing Go vocabulary with a TS library is jarring. -- **Category:** 14 (Go-style names imported into TS), 17 (verb inconsistency — Zod's own API is `.parse()`, not `.unmarshal()`). -- **Suggested name:** `encodeExternalMetadataSchema` / `decodeExternalMetadataSchema`, or `externalMetadataToWireSchema` / `externalMetadataFromWireSchema`. -- **Rationale:** Marshal/unmarshal is a Go term of art; TS developers reach for `JSON.stringify`/`JSON.parse` or Zod's `parse`/`safeParse`. The current name forces a vocabulary translation. - -### 24. `externalMetadataFieldMaskSchema` and `externalMetadataFieldMask(...)` — `src/v1/model.ts:197,214` -- **Why weird:** Two exports differ only by the `Schema` suffix; the helper function and its lookup table share a stem. A reader has to look up which is the runtime config vs. the factory. Function/data naming should be more distinguishable. -- **Category:** 17 (inconsistent action verbs — schema is a noun, but the function uses the same name as a verbless noun). -- **Suggested name:** `buildExternalMetadataFieldMask(...)` for the function, leave the schema with `Schema` suffix. -- **Rationale:** Functions should be verb-prefixed; the schema-vs-builder distinction should jump off the page. Sister packages share this problem (generator-wide). - -### 25. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 23. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. - **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. Same pattern across sister packages — generator-wide concern. -### 26. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` -- **Why weird:** The function takes an arbitrary `unknown` value plus a Zod schema and returns a JSON string. The name says "Request" but the function does not know whether `data` is a request, response, or anything else — it is a generic JSON-encoder against a Zod schema. -- **Category:** 1 (vague — `Request` in the name does not constrain), 6 (misleading — works for any payload, not specifically requests). -- **Suggested name:** `marshalToJson` / `encodeToJson` / `toWireJson`. -- **Rationale:** The function is symmetric to `parseResponse`, which has the same problem in reverse. `Request`/`Response` should be specific to their meaning. - -### 27. `parseResponse(body, schema)` — `src/v1/utils.ts:113` -- **Why weird:** Symmetric problem to `marshalRequest`. The function parses any JSON `Uint8Array` against a Zod schema. The name says "Response" but the function does not check that. -- **Category:** 1, 6. -- **Suggested name:** `parseJsonBody` / `decodeFromJson` / `fromWireJson`. -- **Rationale:** Same as #26. `marshalRequest` + `parseResponse` are an asymmetric verb pair (`marshal` vs. `parse`) AND inaccurate. Either fix both. - -### 28. `Client.listExternalMetadataV2Iter` — `src/v1/client.ts:190` -- **Why weird:** The `Iter` suffix is Go SDK convention for "returns an iterator". In TS, async iterators are a first-class language feature with their own conventions; the canonical name would be `listExternalMetadataV2()` returning `AsyncIterable` (a single iterator method, not a parallel `Iter` variant). Pairing the page-returning `listExternalMetadataV2` with an `Iter` cousin is a Go pattern leaking through. -- **Category:** 14 (Go-style name), 5 (cryptic abbreviation — `Iter`), 12 (duplicate concept — two methods that differ only by what they return). -- **Suggested name:** `iterateExternalMetadata` (clear) or rename the pair: `listExternalMetadataPage(...)` (returns one page) + `listExternalMetadata(...)` (returns iterator). Or use a single dual-purpose method. -- **Rationale:** Generator-wide concern; the `Iter` suffix is a direct Go-SDK port. TS has `for await (...)` and would idiomatically expect either a single method returning an iterable, or `iterate*` / `*Stream` / `*Pages` to distinguish from the page-returning method. - ## Low severity -### 29. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` +### 24. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` - **Why weird:** Four (five) request DTOs repeat the noun `ExternalMetadata` even though the entire package operates on exactly one entity (the only thing this package does is CRUD `ExternalMetadata`). In context, `CreateRequest`/`UpdateRequest` would be plenty. - **Category:** 7 (overly verbose), 8 (redundant suffix and infix). - **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`/`ListRequest`, or drop the `Request` suffix entirely if request DTOs follow a sibling-naming pattern (`Create`, `Update`, etc.). Cross-SDK consistency makes this a low rather than high. - **Rationale:** The whole package operates on one entity; repeating it in every request type is pure noise. SDK-wide pattern means a local fix risks inconsistency. -### 30. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` +### 25. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` - **Why weird:** Singular/plural mismatch. The field holds an array but is named `externalMetadata` (singular). Convention is plural for arrays (e.g., `connections: Connection[]` in sister packages). Compare: `nextPageToken` is singular because it's a single token. - **Category:** 9 (singular/plural mismatch), 20 (type-suffix tautology — `externalMetadata: ExternalMetadata[]`). - **Suggested name:** `items: ExternalMetadata[]` or `externalMetadataObjects: ExternalMetadata[]` or `assets`. Wire stays `external_metadata`. - **Rationale:** "Metadata" is a mass noun (uncountable), which is why the generator left it singular. A plural-aware name like `items` or `assets` reads naturally. -### 31. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 26. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 32. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` +### 27. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 33. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` +### 28. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` - **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. -### 34. `pageReq` — `src/v1/client.ts:194` +### 29. `pageReq` — `src/v1/client.ts:194` - **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). - **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). - **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. -### 35. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +### 30. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` - **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. - **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). - **Suggested name:** `requestBody: string | ReadableStream`. - **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. -### 36. `flattenQueryParams` — `src/v1/utils.ts:123` +### 31. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 37. `readAll(body)` — `src/v1/utils.ts:40` +### 32. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. -### 38. `HttpCallOptions` — `src/v1/utils.ts:15` +### 33. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. @@ -249,20 +219,17 @@ ## Observations -### 39. Wire/TS divergence is heavy -The `model.ts` file is 222 lines for ~7 user-facing types (one entity + five request types + one response). Roughly 60% of the file is `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. Not a naming problem per se, but the audit consistently surfaces how much generator boilerplate dominates each package. - -### 40. Identifier doubling for path + UUID +### 34. Identifier doubling for path + UUID The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #6 and #7. -### 41. Action-verb conventions in `Client` -The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Iter` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. The `Iter` suffix (see #28) is the only outlier on verb choice. +### 35. Action-verb conventions in `Client` +The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. -### 42. Acronym casing +### 36. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 43. `externalmetadata` lowercase package name +### 37. `externalmetadata` lowercase package name The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index ac9f24e7..fcc0dd76 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -15,7 +15,7 @@ computes a feature on a schedule and writes results to an offline or online store). Feature transformations are a discriminated union over 13 aggregation functions and 3 data sources (Delta, Kafka, request-time), composed under three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 50 +**Total weird names flagged:** 52 --- @@ -27,7 +27,7 @@ three flavors of time window (continuous, tumbling, sliding). | 2 | three sibling packages: `features` / `featurestore` / `materializedfeatures` | (across packages) | package set | High | 12 Duplicate concepts | The Feature Engineering surface is split across three top-level packages whose names overlap at the prefix. Boundaries: `features` defines feature *definitions* (this package); `materializedfeatures` is **misnamed** — it actually owns feature **lineage and tags** (`FeatureLineage`, `FeatureTag`), not materialized features (which live here); `featurestore` owns **online stores**. The names do not align with their contents. Either rename `materializedfeatures` to `featuremetadata` / `featurelineage`, or move `MaterializedFeature` and its client methods out of this package into the (misnamed) `materializedfeatures` package. | | 3 | `Feature` interface | model.ts:279 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | | 4 | `Client` | client.ts:65 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `FeaturesClient` or `FeatureEngineeringClient` would self-identify and disambiguate from `featurestore.Client` and `materializedfeatures.Client`. | -| 5 | `Client.createFeature` / `getFeature` / `updateFeature` / `deleteFeature` / `listFeatures` / `listFeaturesIter` plus `Client.create/get/update/delete/list/listIterKafkaConfig*` plus `Client.batchCreate/create/get/update/delete/list/listIterMaterializedFeatures*` (3 resource families on one client) | client.ts:91-628 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature` (21 methods total). The class is 631 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | +| 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-628 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 631 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | | 6 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` and 11 sibling values | model.ts:13-24 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | Only one value (`SCALAR_DATA_TYPE_UNSPECIFIED`) stutters the enum name; the other eleven (`INTEGER`, `FLOAT`, `BOOLEAN`, etc.) are reasonable. Just remove the sentinel or rename to `Unspecified`. The wire format is dictated by the API; TS keys can be Pascal-cased via the zod transform. | | 7 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` (sentinel) | model.ts:13 | enum value | Medium | 6 Misleading names, 18 Long enum values | Proto-style "Unspecified" sentinel. The field is already `dataType?: ScalarDataType \| undefined` (FieldDefinition:325) — omitting the field communicates "unspecified" naturally. Sentinel is dead in TS. | | 8 | `Function_FunctionType` enum name | model.ts:29 | enum | High | 4 Underscores in TS identifiers, 8 Redundant suffixes, 20 Type-suffix tautology | `Function_FunctionType` is a proto-nested-message-encoded-as-underscore name and is internally tautological (`Function`+`FunctionType`). It also requires an inline `// eslint-disable-next-line @typescript-eslint/naming-convention`. The TS idiom would be `FunctionKind` or `AggregationKind`, nested as `Function.Kind` under a namespace. | @@ -71,13 +71,10 @@ three flavors of time window (continuous, tumbling, sliding). | 46 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:285-288 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | | 47 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:241-245 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | | 48 | `Feature.timeseries_column` (snake_case in JSDoc) | model.ts:243 | doc | Low | 4 Underscores | JSDoc references "Feature.timeseries_column" — wire-format name in user-facing TS docs. Should be `Feature.timeseriesColumn`. (Multiple occurrences across model.ts JSDoc texts.) | -| 49 | `unmarshalAggregationFunctionSchema` `$case === 'countFunction'` vs all others (`avg`, `sum`, ...) | model.ts:849 | const | High | 12 Duplicate concepts, 17 Inconsistent action verbs | The 13-case discriminated union for `AggregationFunction.operation` uses `$case` strings that mostly correspond to the math operation (`avg`, `sum`, `min`, `max`, `first`, `last`, `approxCountDistinct`, `approxPercentile`, `stddevPop`, `stddevSamp`, `varPop`, `varSamp`) — *except* for `countFunction`, which retains the `Function` suffix. The wire string is `count_function` while the wire strings for the others are `avg`, `sum`, etc. The asymmetry comes from the spec ("count" is a reserved word in some surfaces) but reads as a bug in TS code. | -| 50 | `marshal*Schema` / `unmarshal*Schema` const naming | model.ts:822-2274 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go-idioms; `Schema` is tautological with `z.ZodType`. TS idiom is `encode`/`decode`. Generator-wide pattern, no per-package fix. | -| 51 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | -| 52 | `parseResponse` vs `marshalRequest` | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | Mixing `parse`/`marshal`. Either `parse`/`format` or `marshal`/`unmarshal`. Sibling-package pattern. | -| 53 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | -| 54 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2396, 2446, 2491 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 55 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:170, 702, 781 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 49 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | +| 50 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | +| 51 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2396, 2446, 2491 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 52 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:170, 702, 781 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | --- @@ -178,8 +175,7 @@ inline `// eslint-disable-next-line @typescript-eslint/naming-convention`: - `Function_ExtraParameter` (interface) — model.ts:373 - `MaterializedFeature_PipelineScheduleState` (enum) — model.ts:47 -And the corresponding `unmarshal*` / `marshal*` constants below. The -existence of those eslint-disable comments is the loudest possible signal +The existence of those eslint-disable comments is the loudest possible signal that the names violate the codebase's own conventions. Standard TS idiom: lift to top-level (`FunctionType`, @@ -245,14 +241,12 @@ within the file *and* potentially unsafe at the `2^53` boundary. ### M1. One `Client` owning three resource families -The `Client` class is 631 lines and exposes 21 methods over three resource +The `Client` class is 631 lines and exposes methods over three resource families: -- `Feature` (5 RPCs + 1 iterator): create, get, list, listIter, update, delete. -- `KafkaConfig` (5 RPCs + 1 iterator): create, get, list, listIter, update, - delete. -- `MaterializedFeature` (5 RPCs + 1 iterator + 1 batch): batchCreate, create, - get, list, listIter, update, delete. +- `Feature`: create, get, list, update, delete. +- `KafkaConfig`: create, get, list, update, delete. +- `MaterializedFeature`: batchCreate, create, get, list, update, delete. The URL groupings hint that they are distinct sub-resources: @@ -373,68 +367,60 @@ types. Only the sentinel `SCALAR_DATA_TYPE_UNSPECIFIED` is a problem. Sibling-package pattern. -### L3. `parseResponse` vs `marshalRequest` verb mix - -Sibling-package pattern. - -### L4. `MtlsConfig.disableHostnameVerification` reasonable +### L3. `MtlsConfig.disableHostnameVerification` reasonable Boolean named in negative ("disable") to match the underlying Kafka option (`kafka.ssl.endpoint.identification.algorithm`). JSDoc warns about security implications. Fine. -### L5. `bootstrapServers` is conventional Kafka +### L4. `bootstrapServers` is conventional Kafka Fine. -### L6. `cronSchedule` field on `MaterializedFeature` +### L5. `cronSchedule` field on `MaterializedFeature` `MaterializedFeature.cronSchedule: string` is a Quartz cron expression. The field name is fine; the type could be a branded `CronExpression` for stronger typing, but flagging only for completeness. -### L7. `req` parameter naming in client methods +### L6. `req` parameter naming in client methods Standard SDK-wide convention. Fine. -### L8. `marshal`/`unmarshal` are Go-idioms - -Generator-wide. Cf. credentials audit L7. - -### L9. `Function_FunctionType` enum values use SQL-conventional uppercase +### L7. `Function_FunctionType` enum values use SQL-conventional uppercase `AVG`, `COUNT`, `SUM`, etc. Match SQL/Spark idioms. Fine for the wire format; TS keys could be PascalCase. -### L10. `ContinuousWindow.offset` allows non-positive +### L8. `ContinuousWindow.offset` allows non-positive Note in JSDoc: "must be non-positive" — i.e., 0 or negative duration. The type is `Temporal.Duration` which doesn't constrain sign. Documentation-only constraint; not enforced. Same critique as `SlidingWindow.slideDuration` ("must be positive and less than duration"). -### L11. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text +### L9. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text A `string` containing potentially many KB of source text. Naming is fine; the data shape is the design choice. Listing for completeness. -### L12. JSDoc typo on `JobContext.jobId` +### L10. JSDoc typo on `JobContext.jobId` "The job ID where this API invoked." → "where this API was invoked." Minor. -### L13. `SecretScopeReference { scope, key }` +### L11. `SecretScopeReference { scope, key }` Two-field reference to a Databricks secret. Standard. Fine. -### L14. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` +### L12. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` Four Spark Structured Streaming idioms. Standard. Fine. -### L15. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` +### L13. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` Three field-mask builders. Standard generator pattern. Fine. -### L16. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` +### L14. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` The list endpoint filters by feature name (full UC name). Field is `featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` @@ -555,7 +541,7 @@ who know the upstream API; opaque otherwise. | File | Lines | Exports counted | Audited | |------|-------|-----------------|---------| | `src/v1/model.ts` | 2499 | 3 enums, 50 interfaces, 60 zod consts (30 unmarshal + 30 marshal), 3 field-mask helpers | yes | -| `src/v1/client.ts` | 631 | 1 class, 21 public methods (15 RPCs + 3 paging iterators + 1 batch) | yes | +| `src/v1/client.ts` | 631 | 1 class, public methods covering 3 resource families (Feature, KafkaConfig, MaterializedFeature) | yes | | `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | | `src/v1/index.ts` | 78 | 1 class re-export, 3 enum re-exports, 60 type re-exports | yes | diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index 43ca8398..d5755095 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -213,8 +213,7 @@ fine under finding 4. **Pass at the TS level**, flag at the wire level. ### 6. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) **Symbol:** `DeleteOnlineTableRequest.onlineTableName` (model.ts:59), wire -field `online_table_name` (per `marshalPublishSpecSchema:207` style; here the -field appears in the URL path, not JSON). +field `online_table_name` (the field appears in the URL path, not JSON). **Issue:** The neighbouring `onlinetables/v1` package defines an *identical* operation with a *different* field name: @@ -413,11 +412,10 @@ suffix. **Suggested:** rename to `onlineStoreName` to match `sourceTableName`, `onlineTableName`, and the wire field `online_store` (or -`online_store_name` — see finding 24). This is a *symbol-level* -inconsistency *within the same file* and is the single highest-confidence -fix in this audit. The Go SDK uses `OnlineStore` (capitalised, but a -string), so this is a port-time correctness opportunity, not a coordination -issue with upstream Go fields. +`online_store_name`). This is a *symbol-level* inconsistency *within the +same file* and is the single highest-confidence fix in this audit. The Go +SDK uses `OnlineStore` (capitalised, but a string), so this is a port-time +correctness opportunity, not a coordination issue with upstream Go fields. **P1 fix candidate.** @@ -457,7 +455,7 @@ is a coupled fix; do not change in isolation. ### 18. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) -**Symbol:** `PublishTableRequest.publishSpec.onlineTableName`, +**Symbols:** `PublishTableRequest.publishSpec.onlineTableName`, `PublishTableResponse.onlineTableName` (model.ts:103, 117). **Issue:** The JSDoc on both reads "The full three-part (catalog, schema, @@ -545,46 +543,7 @@ the *request types* are also identically named but field-incompatible. --- -### 23. `Client.listOnlineStoresIter` async-iterator naming — *pass* - -`Iter` suffix is the project's canonical name for paginator generators -(`cleanrooms`, `cleanroomassets`, etc., per audit history). Consistent. -**Pass.** - ---- - -### 24. Wire field `online_store` vs. field name `onlineStore` referring to a string — category 5 (Cryptic abbreviations) and category 15 (Generic field names losing meaning) - -**Symbol:** `marshalPublishSpecSchema` (model.ts:206) maps -`onlineStore → online_store`. The wire field is `online_store` (a string -name), not `online_store_name`. This is a wire-level decision — the Go SDK -also uses `online_store` for this string field — but it amplifies finding 15: -even at the wire level, the field name suggests a *struct*, not a string. - -**Pass at the SDK level, flag upstream.** - ---- - -### 25. `unmarshal*Schema` / `marshal*Schema` Go vocabulary — category 14 (Go/Java-style names) - -**Symbols:** `unmarshalListOnlineStoresResponseSchema`, -`unmarshalOnlineStoreSchema`, `unmarshalPublishTableResponseSchema`, -`marshalOnlineStoreSchema`, `marshalPublishSpecSchema`, -`marshalPublishTableRequestSchema` (model.ts:129, 142, 165, 176, 199, 211). - -**Issue:** "Marshal" / "Unmarshal" is Go-ism vocabulary. TS ecosystem uses -"serialize" / "deserialize" or, when working with Zod, "parse" / "stringify" -/ "schema". The full SDK uses this convention; **flag for SDK-wide cleanup, -not this package alone.** - -The `*Schema` suffix is also somewhat redundant — `unmarshalOnlineStore` -without `Schema` would suffice since the value's type is -`z.ZodType` and there are no non-schema cousins. But this is a -naming-pattern decision applied SDK-wide. **Pass with note.** - ---- - -### 26. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* +### 23. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* **Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and `onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the @@ -593,14 +552,14 @@ Google AIP-134 update-mask vocabulary. **Pass.** --- -### 27. `Client` class name — category 1 (Vague/generic) — *pass* +### 24. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** --- -### 28. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 25. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:41). @@ -616,7 +575,7 @@ do not fix in isolation.** --- -### 29. `userAgent` / `httpClient` / `host` / `logger` — *pass* +### 26. `userAgent` / `httpClient` / `host` / `logger` — *pass* Standard private field names. Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported @@ -624,58 +583,14 @@ type `HttpClient`). **Pass.** --- -### 30. `HttpCallOptions` (utils.ts:15) — category 1 (Vague/generic) and category 20 (Type-suffix tautology) - -**Symbol:** `HttpCallOptions` interface. - -**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the -neighbouring `CallOptions` exists in `@databricks/sdk-options/call`. Naming -both *in the same file* (`HttpCallOptions` here, `CallOptions` imported on -line 12) confuses readers — which "Call" do they mean? Suggest -`HttpRequestContext` or `ExecuteHttpArgs`. **Flag for SDK-wide cleanup** -(this utils.ts is generated boilerplate copied across every package, so any -fix must apply everywhere). - ---- - -### 31. `executeCall` vs `executeHttpCall` — category 17 (Inconsistent action verbs) - -**Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). - -**Issue:** Two functions named `execute…Call`. `executeCall` is the public -API wrapper that calls `execute()` from `@databricks/sdk-core/api`. -`executeHttpCall` performs an HTTP request and decodes the body. They do -*different* things at *different* layers — but the names imply a -hierarchical relationship that does not exist. The HTTP one is roughly -`sendAndDecode` or `doHttpRequest`. **Flag for SDK-wide naming cleanup;** -this file is generated boilerplate copied across every package. - ---- - -### 32. `readAll` — *pass* +### 27. `readAll` — *pass* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 33. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) - -**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). - -**Issue:** Two symmetric operations: response→object (parse) and -object→body-string (marshal). The verbs come from two different vocabularies -("parse" is generic TS/JS, "marshal" is Go). Internally consistent verb-pair -would be `parseResponse` / `serializeRequest` or `unmarshalResponse` / -`marshalRequest`. The current pair is awkward. - -**Suggested:** `serializeRequest` and `parseResponse` (TS-native vocabulary) -or commit fully to the Go terms: `unmarshalResponse` and `marshalRequest`. -**Flag for SDK-wide consistency.** - ---- - -### 34. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* +### 28. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. Note however the *file* mixes `build…`, @@ -684,21 +599,7 @@ seven functions. Not unique to this package. **Pass.** --- -### 35. `flattenQueryParams` (utils.ts:123) — *dead code* - -**Symbol:** `flattenQueryParams` (utils.ts:123). - -**Issue:** Imported nowhere within this package's client (the `list` method -builds its query string inline at client.ts:166–173, and `update` does -similar at client.ts:243–247). The helper is dead code in this package, and -`marshalRequest` is also declared and unused in some methods that emit raw -bodies. Naming itself is fine. **Suggest** deleting from this package, or -extracting all utils into a shared helper module -(`@databricks/sdk-core/http`). **Flag generator behaviour.** - ---- - -### 36. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* +### 29. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -710,7 +611,7 @@ package qualifies. **Pass on package consistency.** --- -### 37. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) +### 30. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) **Symbol:** `Client.listOnlineStores` (client.ts:160). @@ -738,14 +639,14 @@ and update JSDocs to drop "Feature" (already redundant since the package is --- -### 38. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* +### 31. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 39. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* +### 32. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* `pipelineId` correctly camelCases the two-letter "ID"; `creator` is a plain word. **Pass.** @@ -834,16 +735,16 @@ approaches (string enum vs. discriminated union). Plus there is no `DeleteOnlineTableRequest` shape collision with `onlinetables`). - **High (style guide violations):** 4 findings (#1 `OnlineStore_State` underscore; #2 `PublishSpec_PublishMode` doubled noun; #4 enum SCREAMING - casing; #28 `PACKAGE_SEGMENT` casing). + casing; #25 `PACKAGE_SEGMENT` casing). - **Medium (naming clarity, JSDoc drift):** 10 findings (#3, #7, #8, #11, - #12, #14, #16, #21, #22, #37). -- **Low / project-wide convention notes (generator-level):** 10 findings - (#9, #13, #17, #18, #24, #25, #30, #31, #33, #35). -- **Pass / acceptable as-is:** 13 findings (#5, #10, #19, #20, #23, #26, - #27, #29, #32, #34, #36, #38, #39 — partial pass with notes). + #12, #14, #16, #21, #22, #30). +- **Low / project-wide convention notes (generator-level):** 4 findings + (#9, #13, #17, #29). +- **Pass / acceptable as-is:** 11 findings (#5, #10, #18, #19, #20, #23, + #24, #26, #27, #28, #31, #32 — partial pass with notes). -**Total flagged findings: 39** distinct items across 20 audit categories +**Total flagged findings: 32** distinct items across the audit categories (several findings touch multiple categories). Many issues are generator-emitted boilerplate inherited from the Go SDK; the cleanest local -fixes are findings 15, 21 (JSDoc), 22, 37 (JSDoc), and the cross-package +fixes are findings 15, 21 (JSDoc), 22, 30 (JSDoc), and the cross-package alignments noted above. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index c84bb345..d5a6688d 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -4,14 +4,14 @@ **Versions audited:** v1 AND v2 **Inferred domain:** File operations on Databricks storage. `v1` is a small hand-written wrapper exposing only `upload` against the modern Files API (`/api/2.0/fs/files/...`). `v2` is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 54 +**Total weird names flagged:** 49 ## Summary | Severity | Count | | --- | --- | | High | 17 | -| Medium | 20 | -| Low | 11 | +| Medium | 17 | +| Low | 9 | | Observation | 6 | ## v1 vs v2 comparison @@ -423,25 +423,11 @@ Doc says don't set the field. Then why is the field public? Name is fine; flaggi Every legacy `Foo_Response` type carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive because the underscore violates TS PascalCase. Modern API peers (`CreateDirectoryResponse`, `DownloadFileResponse`) need no such directive. Two conventions, one file — surface friction every time the generator runs. -### 29. v2 `listDirectoryContentsIter` — naming inconsistency with `listDirectoryContents` — `src/v2/client.ts:689` - -```ts -async listDirectoryContents(...): Promise -async *listDirectoryContentsIter(...): AsyncGenerator -``` - -`...Iter` is a Go-style suffix (the Go SDK has `ListAll` / `Iter` helpers). TS convention would be `listDirectoryContents` (returns one page) and `iterateDirectoryContents` / `listDirectoryEntries` (yields each item). The `Iter` suffix also collides with TS iterator conventions where the method is just `[Symbol.asyncIterator]()` on the result. - -### 30. `Read_Response.data: Uint8Array` is base64 on the wire — `src/v2/model.ts:273,419-424` - -```ts -unmarshalRead_ResponseSchema: ... - data: z.string().transform(s => Uint8Array.from(atob(s), c => c.charCodeAt(0))).optional() -``` +### 29. `Read_Response.data: Uint8Array` is base64 on the wire — `src/v2/model.ts:273` The field is decoded from base64 on read; doc says "The base64-encoded contents of the file read." but the TS type is already `Uint8Array` (decoded). Consumers reading the docstring may think they have to decode themselves. Name could clarify: `bytes: Uint8Array` with doc "Already base64-decoded". -### 31. v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export `DownloadRequest`/`DownloadResponse`-as-used — `src/v1/index.ts:3` +### 30. v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export `DownloadRequest`/`DownloadResponse`-as-used — `src/v1/index.ts:3` ```ts export type {DownloadRequest, DownloadResponse, UploadRequest} from './model'; @@ -449,34 +435,15 @@ export type {DownloadRequest, DownloadResponse, UploadRequest} from './model'; v1 exports `DownloadRequest`/`DownloadResponse` but the v1 client has NO download method. Dangling types — see net assessment. -### 32. `marshalRequest` returns a `string` — name implies object — `src/v2/utils.ts:119` - -```ts -export function marshalRequest(data: unknown, schema: z.ZodType): string { - return JSON.stringify(schema.parse(data)); -} -``` - -The verb "marshal" typically returns a marshalled object, not its serialised form. Name suggests "convert object to wire shape" but actually does "convert to wire JSON string". `serializeRequest` or `marshalRequestJson` would be more honest. - -### 33. `parseResponse` is asymmetric with `marshalRequest` — `src/v2/utils.ts:113` - -```ts -export function parseResponse(body: Uint8Array, schema: z.ZodType): T -export function marshalRequest(data: unknown, schema: z.ZodType): string -``` - -`parseResponse` and `marshalRequest` are inverse operations, but the verb pair is non-symmetric: `parse` ↔ `format` (or `marshal` ↔ `unmarshal`). Should be `marshalRequest`/`unmarshalResponse` OR `serializeRequest`/`parseResponse` — not the mix. - -### 34. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` +### 31. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. -### 35. `readAll` is duplicated — `src/v1/utils.ts:23` and `src/v2/utils.ts:40` +### 32. `readAll` is duplicated — `src/v1/utils.ts:23` and `src/v2/utils.ts:40` Same conceptual helper, two implementations (v1 uses `new Response(body).arrayBuffer()`, v2 walks the reader manually). Name OK; flagged as cross-version duplication. -### 36. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` +### 33. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` ```ts const PACKAGE_SEGMENT = { @@ -487,7 +454,7 @@ const PACKAGE_SEGMENT = { SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. This is a plain object; `packageSegment` is fine. -### 37. `HttpCallOptions` duplicated across files — `src/v1/utils.ts:13`, `src/v2/utils.ts:15` +### 34. `HttpCallOptions` duplicated across files — `src/v1/utils.ts:13`, `src/v2/utils.ts:15` ```ts export interface HttpCallOptions { @@ -501,23 +468,23 @@ Same name, same shape, in two files in the same package. Should be shared / re-e ## Low severity -### 38. v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` — `src/v1/utils.ts:36`, `src/v2/utils.ts:156` +### 35. v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` — `src/v1/utils.ts:36`, `src/v2/utils.ts:156` Same function, renamed in v2. Good rename (v2's is more accurate), but the rename means a v1 user upgrading sees an unexplained name change. -### 39. `Move.sourcePath` / `Move.destinationPath` — could be `source` / `destination` — `src/v2/model.ts:233-236` +### 36. `Move.sourcePath` / `Move.destinationPath` — could be `source` / `destination` — `src/v2/model.ts:233-236` The type name is `Move`; the fields are `sourcePath`/`destinationPath`. Inside a `Move` request, the `Path` suffix is redundant — `source: string; destination: string`. Acceptable; flagged because it's the longer form against the rest of the file's `path: string`. -### 40. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` +### 37. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) -### 41. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` +### 38. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. -### 42. v2 `index.ts` exports neither `Client` constants nor `VERSION` — `src/v2/index.ts:3-6` +### 39. v2 `index.ts` exports neither `Client` constants nor `VERSION` — `src/v2/index.ts:3-6` ```ts export {Client} from './client'; @@ -526,11 +493,11 @@ export {} from './model'; // <-- empty named export Line 5 (`export {} from './model';`) is a no-op. Not a name bug, just dead syntax. -### 43. `directoryPath ?? ''` fallback in client — `src/v2/client.ts:462,492,517,546,595,626,660,716` +### 40. `directoryPath ?? ''` fallback in client — `src/v2/client.ts:462,492,517,546,595,626,660,716` 8 places where `directoryPath` is coerced to empty string. Field is typed optional but the URL must have it. Either type the field as required, or document the fallback. Name OK. -### 44. v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" — `src/v1/client.ts:33-36` +### 41. v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" — `src/v1/client.ts:33-36` ```ts /** @@ -543,33 +510,25 @@ async upload(req: UploadRequest, options?: CallOptions): Promise { `upload` is the name; the JSDoc tells you it doesn't retry. v2 inherits the same property for `uploadFile` but the doc on `client.ts:706` doesn't say so. Inconsistent docs across versions. -### 45. `unmarshal*Schema` constant names — `src/v2/model.ts:290-431` - -19 exported constants named `unmarshalSchema`. Verbose but consistent. Acceptable. - -### 46. `marshal*Schema` constant names — `src/v2/model.ts:433-510` - -7 exported constants. Acceptable; mirror of unmarshal. - -### 47. `pkgJson.name.replace(/^@[^/]+\//, '')` — `src/v2/client.ts:90` +### 42. `pkgJson.name.replace(/^@[^/]+\//, '')` — `src/v2/client.ts:90` Inlined regex to strip `@scope/` prefix. Should be a helper named `packageName`. Not a naming issue per se. -### 48. v1 imports `@databricks/sdk-core/http` (not `@databricks/sdk-databricks/http`) — `src/v1/client.ts:9` +### 43. v1 imports `@databricks/sdk-core/http` (not `@databricks/sdk-databricks/http`) — `src/v1/client.ts:9` Different package than the audit but worth flagging: v1 still uses `sdk-core` while v2 uses `sdk-databricks` for some imports — internal inconsistency. ## Observations -### 49. The empty `export {} from './model';` line — `src/v2/index.ts:5` +### 44. The empty `export {} from './model';` line — `src/v2/index.ts:5` Likely a generator artifact; no impact. -### 50. v1 has 78 lines of utils for one operation; v2 has 196 lines of utils for ten operations — files are well-sized. +### 45. v1 has 78 lines of utils for one operation; v2 has 196 lines of utils for ten operations — files are well-sized. -### 51. `Client` constructor's User-Agent code is duplicated across packages — out of scope here. +### 46. `Client` constructor's User-Agent code is duplicated across packages — out of scope here. -### 52. `'head'` HTTP method passed in lowercase to `buildHttpRequest` — `src/v2/client.ts:600,637` +### 47. `'head'` HTTP method passed in lowercase to `buildHttpRequest` — `src/v2/client.ts:600,637` ```ts const httpReq = buildHttpRequest('head', url, headers, callSignal); @@ -577,10 +536,10 @@ const httpReq = buildHttpRequest('head', url, headers, callSignal); Other calls use `'POST'`/`'GET'`/`'PUT'`/`'DELETE'` uppercase. Cosmetic — actual bug because `buildHttpRequest` does not normalise — but flagged here as casing inconsistency. -### 53. `read()` JSDoc references `RESOURCE_DOES_NOT_EXIST`, `MAX_READ_SIZE_EXCEEDED`, `INVALID_PARAMETER_VALUE` — strings, not enums — `src/v2/client.ts:412-418` +### 48. `read()` JSDoc references `RESOURCE_DOES_NOT_EXIST`, `MAX_READ_SIZE_EXCEEDED`, `INVALID_PARAMETER_VALUE` — strings, not enums — `src/v2/client.ts:412-418` Error codes are referenced as freeform strings in JSDoc. Out of naming scope. -### 54. `listDirectoryContentsIter` is the only iterator method on the client — `src/v2/client.ts:689` +### 49. Legacy DBFS `list` lacks pagination wire shape — `src/v2/model.ts:160,178` -The legacy `list` does not have an `Iter` variant (it doesn't paginate). Asymmetry of pagination support across the legacy/modern surfaces, reflected in method naming. +The modern Files API `listDirectoryContents` carries `pageSize` / `pageToken` on the request and `nextPageToken` on the response. The legacy DBFS `list` (`ListStatus` request) has only `path` and returns `ListStatus_Response` with no paging cursor — the JSDoc on `list` even warns of a 10 K file cap. Two list shapes for the same conceptual operation, one with pagination wire fields and one without. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index 897326d2..cfa6d849 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -13,10 +13,10 @@ This audit applies the 20 numbered concern categories from the audit checklist. Each finding lists the offending identifier(s), the category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename suggestion. Findings are grouped by category. Generator-driven -items (such as the proto-style underscored nested-message names and -`marshal`/`unmarshal` schema prefixes) are flagged as `LOW` because -they are codified across the entire generated SDK surface — they -should be fixed at the generator, not by hand-editing this package. +items (such as the proto-style underscored nested-message names) are +flagged as `LOW` because they are codified across the entire generated +SDK surface — they should be fixed at the generator, not by +hand-editing this package. --- @@ -34,12 +34,6 @@ should be fixed at the generator, not by hand-editing this package. `CreateForecastingExperimentResponse`, `ForecastingExperiment`, `GetForecastingExperimentRequest`. -### Schemas (`model.ts`) - -`unmarshalCreateForecastingExperimentResponseSchema`, -`unmarshalForecastingExperimentSchema`, -`marshalCreateForecastingExperimentRequestSchema`. - ### Client classes and methods (`client.ts`) - Class `Client` @@ -189,16 +183,7 @@ should be fixed at the generator, not by hand-editing this package. Approach (1) is more straightforward for tree-shaking and module re-exports; approach (2) more closely mirrors the proto nesting. -#### F4.2 — Wire-protocol snake_case in `marshal`/`unmarshal` body - (acceptable) -- **Where:** `model.ts:89, 98-99, 110-145`. -- **Why flagged:** Field names like `experiment_id`, `train_data_path` - inside the `z.object({...})` are wire shapes, not identifiers. - Required for JSON parsing. -- **Suggestion:** Leave as-is. They are correctly scoped to the - schema definition. - -#### F4.3 — JSDoc comment "double-slash" artifact in +#### F4.2 — JSDoc comment "double-slash" artifact in `splitColumn` (LOW) - **Where:** `model.ts:41`. - **Why flagged:** The JSDoc reads `/** // The column ... */` — an @@ -415,17 +400,7 @@ should be fixed at the generator, not by hand-editing this package. `get`. The class itself already conveys "forecasting". Cross-cutting convention. -#### F7.6 — `marshalCreateForecastingExperimentRequestSchema` and - `unmarshalCreateForecastingExperimentResponseSchema` (LOW) -- **Where:** `model.ts:86, 108`. -- **Why flagged:** 47 / 51 character schema constant names. Long - but mechanical. Inherits length from the underlying type name - plus `marshal`/`Schema` affixes. -- **Suggestion:** Once F7.1/F7.2 are applied at generator level, - these collapse to `marshalCreateExperimentRequestSchema` etc. - Cross-cutting. - -#### F7.7 — `timeseriesIdentifierColumns` (LOW) +#### F7.6 — `timeseriesIdentifierColumns` (LOW) - **Where:** `model.ts:50`. - **Why flagged:** 27 character field name. "Time series identifier columns" is long-form; "series ID columns" or `seriesIdColumns` @@ -458,10 +433,6 @@ should be fixed at the generator, not by hand-editing this package. - **Suggestion:** Rename suffix to `Operation` or `Run` (e.g. `ExperimentRun`). See F7.3. -#### F8.3 — `Schema` suffix on Zod constants (acceptable) -- **Where:** `model.ts:86, 95, 108`. -- The `…Schema` suffix matches Zod community convention. No issue. - --- ### 9. Singular / plural mismatches @@ -593,23 +564,7 @@ should be fixed at the generator, not by hand-editing this package. #### F13.1 — Method verbs (acceptable) - `create*`, `get*` — uniform imperative present. Good. -#### F13.2 — `marshalRequest` / `parseResponse` (LOW, asymmetry) -- **Where:** `utils.ts:113, 119`. -- **Why flagged:** `parse` vs `marshal` use different verbs for the - same kind of operation (JSON conversion). -- **Suggestion:** Use the same axis: either `marshal/unmarshal` - or `encode/decode` or `serialize/deserialize`. Cross-cutting. - -#### F13.3 — `unmarshalXSchema` / `marshalXSchema` constants (LOW) -- **Where:** `model.ts:86, 95, 108`. -- **Why flagged:** Naming pattern is correct (verb + noun + Schema), - but the verb form makes them read like functions, not constants. - They *are* values (`z.ZodType` objects). -- **Suggestion:** Rename to nouns: `createExperimentRequestSchema` - for marshalling, `experimentSchema` for unmarshalling. Cross- - cutting; tied to generator. - -#### F13.4 — `wait` vs `done` on the waiter (acceptable) +#### F13.2 — `wait` vs `done` on the waiter (acceptable) - Both are imperative single-word verbs. Match. Subject to F6.2 / F10.2. @@ -639,25 +594,13 @@ should be fixed at the generator, not by hand-editing this package. gain. This is a porting-convention decision and should be made globally at the generator level. -#### F14.2 — `marshal*` / `unmarshal*` schema prefixes (LOW) -- **Where:** `model.ts:86, 95, 108`. -- **Why flagged:** `marshal`/`unmarshal` is a Go term - (encoding/json). The JS/TS world says "serialize"/"deserialize" - or "encode"/"decode". `JSON.parse`/`JSON.stringify` is the - vernacular. `marshal` is recognizable but Go-flavored. -- **Suggestion:** Rename to `encode`/`decode` or - `serialize`/`deserialize`. Generator-level decision. - -#### F14.3 — `Schema` suffix on Zod constants (acceptable) -- The `…Schema` suffix matches Zod community convention. - -#### F14.4 — `_State` underscore-pseudo-nesting (HIGH) +#### F14.2 — `_State` underscore-pseudo-nesting (HIGH) - See F4.1. Underscores are foreign to TS. -#### F14.5 — `Public RPC to get forecasting experiment` JSDoc (LOW) +#### F14.3 — `Public RPC to get forecasting experiment` JSDoc (LOW) - See F3.4. -#### F14.6 — `terminal state` error message style (LOW) +#### F14.4 — `terminal state` error message style (LOW) - **Where:** `client.ts:172`. - **Why flagged:** "terminal state" is Go-flavored language; TS/JS user-facing errors more commonly say "operation failed" or @@ -758,9 +701,6 @@ should be fixed at the generator, not by hand-editing this package. - **Suggestion:** Rename second to `startForecastingExperiment` or `createAndWaitForecastingExperiment`. -#### F17.4 — `marshal` / `unmarshal` vs `parse` (LOW) -- See F13.2 / F14.2. - --- ### 18. Long enum values @@ -808,15 +748,6 @@ should be fixed at the generator, not by hand-editing this package. `Experiment.state: ExperimentState`. Tolerable. - **Suggestion:** Tie to F4.1 / F7.1. -#### F20.2 — Generic `*Schema` suffix (LOW) -- **Where:** `model.ts:86, 95, 108`. -- **Why flagged:** - `unmarshalCreateForecastingExperimentResponseSchema` is 51 - characters with "Schema" suffixed onto an already-typed - `z.ZodType<...>`. The `Schema` suffix is conventional in Zod - ecosystems though. -- **Suggestion:** Acceptable; tied to generator. - --- ## Package overlap: `forecasting` vs `experiments` @@ -853,30 +784,30 @@ generic experiment but uses the same term and the same ID name. | 1 | Vague / generic | 5 (1 acceptable note) | | 2 | Redundant enum prefixes | 1 (acceptable) | | 3 | Acronym casing | 4 (2 acceptable) | -| 4 | Underscores in TS identifiers | 3 (1 acceptable) | +| 4 | Underscores in TS identifiers | 2 | | 5 | Cryptic abbreviations | 9 | | 6 | Misleading names | 6 | -| 7 | Overly verbose | 7 | -| 8 | Redundant suffixes | 3 (2 acceptable) | +| 7 | Overly verbose | 6 | +| 8 | Redundant suffixes | 2 (1 acceptable) | | 9 | Singular / plural mismatch | 5 (3 acceptable + 1 note) | | 10 | Reserved-word collisions | 4 (2 acceptable) | | 11 | Empty / trivial wrappers | 1 | | 12 | Duplicate concepts | 4 | -| 13 | Verb-tense inconsistency | 4 (2 acceptable) | -| 14 | Go / Java-style names | 6 | +| 13 | Verb-tense inconsistency | 2 (2 acceptable) | +| 14 | Go / Java-style names | 4 | | 15 | Generic field names | 6 | | 16 | Field contradicting type domain | 3 (1 acceptable) | -| 17 | Inconsistent action verbs | 4 (1 acceptable) | +| 17 | Inconsistent action verbs | 3 (1 acceptable) | | 18 | Long enum values | 1 (acceptable) | | 19 | Underspecified IDs | 2 (1 acceptable) | -| 20 | Type-suffix tautology | 2 | +| 20 | Type-suffix tautology | 1 | | OVERLAP | forecasting vs experiments | 2 | --- ## Top 10 highest-impact renames (recommended order) -1. **F4.1 / F14.4:** Replace underscored `ForecastingExperiment_State` +1. **F4.1 / F14.2:** Replace underscored `ForecastingExperiment_State` with flat PascalCase `ForecastingExperimentState` or namespace nesting. Eliminates the `eslint-disable` comment. 2. **F6.3 / F7.4 / F17.3:** Rename @@ -921,16 +852,9 @@ generic experiment but uses the same term and the same ID name. "Code generated from API definition by Databricks SDK Generator. DO NOT EDIT." The fixes belong upstream in the generator and spec. This audit is a backlog for that generator. -- The `utils.ts` file contains the same generic helpers - (`executeCall`, `parseResponse`, `marshalRequest`, - `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, - `readAll`) that every generated package duplicates. The - duplication itself is not a naming issue, but the *names* - (`marshal/unmarshal`) are Go-flavored and inconsistent - (`parseResponse` vs `marshalRequest`). - This package has no `tests/` directory (verified by repo structure check), so the audit does not cover test naming. - The `flattenQueryParams` helper in `utils.ts` is exported but never used in this package — see F6.5. - The JSDoc on `splitColumn` (`model.ts:41`) has a stray `//` - prefix from the source — generator bug, see F4.3. + prefix from the source — generator bug, see F4.2. diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index 2f218ed1..3d6fcc88 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -364,11 +364,9 @@ artefact, but it inflates the cognitive load of reading the model. ### 9. Verb-tense inconsistency -#### 9.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`, `listFunctionsIter`. No tense issues. +#### 9.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`. No tense issues. -#### 9.2 `unmarshal…` / `marshal…` schema-export prefixes are consistent. - -#### 9.3 `executeCall`, `executeHttpCall` (utils.ts:26, 65), `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams` (utils.ts:96, 113, 119, 123) — all imperative present, consistent. +#### 9.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65), `buildHttpRequest`, `flattenQueryParams` (utils.ts:96, 123) — all imperative present, consistent. No verb-tense inconsistencies found across the package. @@ -390,12 +388,7 @@ alias. Package-wide convention; flagged for consistency. #### 10.3 `fullNameArg` (model.ts:155, 294, 343) — Go generator naming. See §5.2. -#### 10.4 `unmarshal…` / `marshal…` (Go's `encoding/json` verbs) -Direct Go ports. The TS ecosystem typically uses `parse` / `serialize` -or `decode` / `encode`. Internal to the generated layer; identified -as Go-style for completeness. - -#### 10.5 `Dependency.value.$case` discriminated union encoding (model.ts:168-184) +#### 10.4 `Dependency.value.$case` discriminated union encoding (model.ts:168-184) The `$case` discriminator with `value`-keyed payload is a ts-proto serialiser idiom. TS-native discriminated unions usually keep the discriminator at the top level (`{type: 'function', function: {…}}`) @@ -469,9 +462,9 @@ also §2.1. ### 13. Inconsistent action verbs Method verbs in `Client`: `createFunction`, `deleteFunction`, -`getFunction`, `listFunctions`, `updateFunction`, `listFunctionsIter`. -Verbs are consistent: standard CRUD plus a `…Iter` paginator. No -`fetch…` / `retrieve…` / `read…` outliers. No issues found. +`getFunction`, `listFunctions`, `updateFunction`. Verbs are +consistent: standard CRUD. No `fetch…` / `retrieve…` / `read…` +outliers. No issues found. --- @@ -574,18 +567,11 @@ schema produces a JSON field `full_name_arg`. Either the server tolerates the extra field or this is a bug. The `Arg` suffix lets the bug hide. -### D. Marshal/unmarshal exports have inconsistent TS types -(model.ts:627, 635, etc.) — every `marshal…Schema` is typed -`z.ZodType` (no generic) versus every `unmarshal…Schema` typed -`z.ZodType<…>` (with generic). The marshal side is implicitly -untyped. Not a naming issue per se, but inconsistent with the -unmarshal naming/typing. - -### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +### D. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) "Host is required." — bare `Error`. Not a naming issue, flagged for consistency with the catalogs audit. -### F. `index.ts` re-exports proto-style names verbatim +### E. `index.ts` re-exports proto-style names verbatim (index.ts:9-12, 21) — every underscore-bearing identifier surfaces in the package's public API. A consumer of `@databricks/sdk-functions/v1` sees `FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, @@ -593,7 +579,7 @@ sees `FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, `DeleteFunction_Response`, `ListFunctions_Response` as first-class exports. -### G. Package-name collision with JavaScript reserved word +### F. Package-name collision with JavaScript reserved word The package is named `@databricks/sdk-functions` and the npm workspace path is `packages/functions/`. `function` is a JS reserved word; `functions` is not, but the proximity is jarring. Importers @@ -604,12 +590,12 @@ shadows nothing, but the `Dependency.value.$case === 'function'` pattern (§7.1) combined with the package name creates a vocabulary where "function" is overloaded. -### H. `FunctionInfo.routineDependencies` is described as "function dependencies." +### G. `FunctionInfo.routineDependencies` is described as "function dependencies." (model.ts:122, 241, 386) Comment text starts with lowercase and uses "function" instead of "routine"; field name uses "routine". See §6.1 and §6.3. -### I. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` +### H. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` The most extreme case of a single-purpose API surface: a long enum type holding a one-letter variant, only ever set to `S`, marshaled as the JSON string `"S"`. Three layers of indirection for a constant. @@ -644,7 +630,7 @@ See §2.2, §5.1. | `DeleteFunction.force` | model.ts:157 | 1.1, 6.2 | | `DeleteFunction_Response` | model.ts:161 | 4.5 | | `Dependency.value.function` arm | model.ts:170 | 7.1 | -| `Dependency.value.$case` | model.ts:168 | 10.5 | +| `Dependency.value.$case` | model.ts:168 | 10.4 | | `FunctionDependency` | model.ts:193 | 7.2 | | `FunctionInfo` | model.ts:198 | 7.3, 8.1 | | `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:212/214/242 | 6.3 | @@ -669,8 +655,7 @@ See §2.2, §5.1. | `Client` (bare name) | client.ts:44 | 10.2 | | `${req.fullNameArg ?? ''}` URL substitution | client.ts:114, 152, 260 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `marshal…` / `unmarshal…` verbs | model.ts (many) | 10.4 | -| `index.ts` re-exports | index.ts:5-35 | F | +| `index.ts` re-exports | index.ts:5-35 | E | --- diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index bce4b296..1372aa50 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -3,7 +3,7 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 73 +**Total weird names flagged:** 72 ## Summary | Severity | Count | @@ -11,7 +11,7 @@ | High | 21 | | Medium | 27 | | Low | 19 | -| Observation | 6 | +| Observation | 5 | ## High severity @@ -443,8 +443,5 @@ - **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. - **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. -### 72. `unmarshalGenieMessageSchema` returns a `GenieMessage` but the input keys are snake_case — `src/v1/model.ts:2188` -- **Observation:** Standard generator pattern. Worth noting that the package has 50 `unmarshalXSchema` exports and 14 `marshalXSchema` exports — generator-faithful. Not a naming bug per se. - -### 73. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,1000,1004,1008` +### 72. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,1000,1004,1008` - **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index 9a92dea1..98a90f8d 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -13,7 +13,7 @@ creation and returns it everywhere else. Five operations: `create/get/list/update/delete`. No enums, no discriminated unions, no pagination, no list filtering beyond an optional `principalId` query parameter, no version negotiation. -**Total weird names flagged:** 31 +**Total weird names flagged:** 23 --- @@ -23,35 +23,27 @@ parameter, no version negotiation. |---|------|------|------|----------|----------|-------------------| | 1 | package `gitcredentials` / module `@databricks/sdk-gitcredentials` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 12 Duplicate concepts | Lowercased compound noun runs `git` and `credentials` together with no separator. The npm registry has packages literally called `git-credentials`/`@gitcredentials` (different ecosystem). Also collides conceptually with `@databricks/sdk-credentials` (Unity Catalog cloud-storage credentials) and `@databricks/sdk-auth/credentials` (SDK auth credentials). Three packages with "Credentials" in the name, three different meanings. | | 2 | `Credential` (interface) | model.ts:68 | interface | High | 1 Vague/generic, 12 Duplicate concepts | Bare `Credential` clashes with `@databricks/sdk-credentials`'s `Credential` (UC credentials) and with the auth package's `Credentials` interface. None of them say "Git" or "auth" or "UC" on the type name. Should be `GitCredential`. | -| 3 | `Credential` vs `CreateCredentials_Response` vs `GetCredentials_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. They share the same zod transform body (lines 195-212 vs 214-230 vs 237-254 — three copies). `CreateCredentials_Response` and `GetCredentials_Response` should be type aliases of `Credential`, or `Credential` should be the response type directly. | +| 3 | `Credential` vs `CreateCredentials_Response` vs `GetCredentials_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. `CreateCredentials_Response` and `GetCredentials_Response` should be type aliases of `Credential`, or `Credential` should be the response type directly. | | 4 | `CreateCredentials` vs `UpdateCredentials` (request envelopes) | model.ts:5, 152 | interface pair | High | 12 Duplicate concepts | The two request envelopes differ by exactly one field: `UpdateCredentials` adds `id` (path parameter). Otherwise field-for-field identical: `gitProvider`, `gitUsername`, `personalAccessToken`, `principalId`, `name`, `isDefaultForProvider`, `gitEmail`. The JSDoc text on every shared field is duplicated verbatim across both. Should share a base type (`GitCredentialMutation`) and only differ on the path key. | | 5 | `CreateCredentials` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The response is `CreateCredentials_Response` — also plural. The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredential` / `CreateCredentialResponse`. (Compare `Credential` itself — the resource singular is already chosen.) | | 6 | `UpdateCredentials`, `DeleteCredentials`, `GetCredentials` named with plural | model.ts:152, 98, 108 | interface set | High | 9 Singular/plural mismatches | Same as #5 — three more cases. `UpdateCredentials` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentials` deletes one. `GetCredentials` gets one. All three should be singular. | | 7 | `ListCredentials_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | -| 8 | `CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response` (proto-style underscore identifiers) | model.ts:43, 106, 116, 147, 192 | interface set | High | 4 Underscores in TS identifiers | Five proto-style `Parent_Response` types each carrying their own `// eslint-disable-next-line @typescript-eslint/naming-convention` comment. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. Standard TS idiom would be `CreateCredentialResponse` (PascalCase without underscore), or `Credential` directly (no separate response type at all — see #3, #17, #18). | +| 8 | `CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response` (proto-style underscore identifiers) | model.ts:43, 106, 116, 147, 192 | interface set | High | 4 Underscores in TS identifiers | Five proto-style `Parent_Response` types each carrying their own `// eslint-disable-next-line @typescript-eslint/naming-convention` comment. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. Standard TS idiom would be `CreateCredentialResponse` (PascalCase without underscore), or `Credential` directly (no separate response type at all — see #3, #15, #16). | | 9 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | | 10 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | | 11 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | | 12 | `bitbucketServer` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Same problem as #11 — wire value is the legacy name. | | 13 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | | 14 | `gitUsername`, `gitEmail`, `gitProvider` prefixed with `git` | model.ts:20, 39, 13, 54, 65, 84, 95, 127, 138, 175, 188 | field set | Medium | 1 Vague/generic, 6 Misleading names | The package is *gitcredentials*; every field already lives under the package namespace. Re-prefixing each field with `git` is stuttering. `req.gitProvider`, `req.gitUsername`, `req.gitEmail` could be `req.provider`, `req.username`, `req.email`. The wire format requires the `git_` prefix on the JSON keys (see the zod schemas), but the TS field can be renamed in the zod `transform`. | -| 15 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | -| 16 | `isDefaultForProvider` field | model.ts:32, 58, 88, 131, 181 | field | Medium | 7 Overly verbose | 20-character field name. "For Provider" is implicit (a credential's provider is fixed; "default" only makes sense relative to it). `isDefault` would be sufficient. | -| 17 | `CreateCredentials_Response` vs `GetCredentials_Response` (identical shapes) | model.ts:43, 116 | interface pair | High | 12 Duplicate concepts | Same six fields, same types, same optionality, same JSDoc text. Should be a single `Credential` type (see #3). | -| 18 | `Credential` vs the two response types (identical shapes) | model.ts:68, 43, 116 | interface trio | High | 12 Duplicate concepts | The `Credential` resource type and the two `*_Response` types are field-for-field identical (see #3). The pattern is uniform across the file: the create-response and get-response should be `Credential`. The list-response is `{credentials: Credential[]}` — that one is fine; the response wrappers around a single credential are not. | -| 19 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | -| 20 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 104, 135, 166, 197 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | -| 21 | `DeleteCredentials.id` and `GetCredentials.id` and `UpdateCredentials.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | -| 22 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | -| 23 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | -| 24 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | -| 25 | `unmarshalCreateCredentials_ResponseSchema` (and four siblings) | model.ts:195, 214, 233, 237, 257, 267 | const set | High | 4 Underscores in TS identifiers, 14 Go/Java-style names, 20 Type-suffix tautology | Generator-emitted const names embed the underscore-bearing parent type name and append `Schema`. Five marshal/unmarshal schemas all carry `// eslint-disable-next-line @typescript-eslint/naming-convention`. The names also pile up three type-suffix words: `Credentials_ResponseSchema` is "Credentials" + "Response" + "Schema", each implying the others. | -| 26 | `marshal*Schema` / `unmarshal*Schema` const naming | model.ts:195, 214, 233, 237, 257, 267, 270, 290 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go idioms; `Schema` is tautological with `z.ZodType`. TS-canonical pair is `encode`/`decode`. Generator-wide pattern (also flagged in the credentials audit, #53). | -| 27 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials` and `accountaccesscontrolproxy` audits — repeated boilerplate. | -| 28 | `parseResponse` vs `marshalRequest` (mixed action verbs) | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | One side says `parse`, the other says `marshal`. Should be either `parse`/`format` or `marshal`/`unmarshal`. | -| 29 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | (none) | Exported but never imported in `client.ts` (which builds query strings inline at line 109-114, 140-145, 171-176). Dead code or future-use. | -| 30 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | -| 31 | `PACKAGE_SEGMENT` const | client.ts:43 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. (Same flag as the credentials audit, #58.) | +| 15 | `CreateCredentials_Response` vs `GetCredentials_Response` (identical shapes) | model.ts:43, 116 | interface pair | High | 12 Duplicate concepts | Same six fields, same types, same optionality, same JSDoc text. Should be a single `Credential` type (see #3). | +| 16 | `Credential` vs the two response types (identical shapes) | model.ts:68, 43, 116 | interface trio | High | 12 Duplicate concepts | The `Credential` resource type and the two `*_Response` types are field-for-field identical (see #3). The pattern is uniform across the file: the create-response and get-response should be `Credential`. The list-response is `{credentials: Credential[]}` — that one is fine; the response wrappers around a single credential are not. | +| 17 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | +| 18 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 104, 135, 166, 197 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 19 | `DeleteCredentials.id` and `GetCredentials.id` and `UpdateCredentials.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | +| 20 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | +| 21 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | +| 22 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | +| 23 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | --- @@ -101,17 +93,16 @@ await client.createCredential({gitProvider: 'gitHub', ...}); Recommendation: keep `listCredentials` (plural — list returns many) but rename the four single-resource methods and their request types to -singular. See #5, #6, #20. +singular. See #5, #6, #18. ### H3. Five `_Response` types use proto-style underscores `CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, -`UpdateCredentials_Response` plus the five `*_ResponseSchema` consts all -carry inline `// eslint-disable-next-line @typescript-eslint/naming-convention` -disables (a total of ten in this one model.ts file). The presence of -those disables is the loudest possible signal that the names violate the -project's own conventions. +`UpdateCredentials_Response` all carry inline +`// eslint-disable-next-line @typescript-eslint/naming-convention` +disables. The presence of those disables is the loudest possible signal +that the names violate the project's own conventions. Standard TS idiom would be `CreateCredentialResponse` (PascalCase, no underscore), nested in a namespace, or — as is appropriate here — *removed @@ -120,9 +111,8 @@ entirely* in favor of returning the resource type directly (see H4). ### H4. Three field-for-field-identical "Credential" shapes `Credential`, `CreateCredentials_Response`, and `GetCredentials_Response` -all have the same six fields with the same types, the same optionality, the -same JSDoc text, and three copies of the same zod transform body -(model.ts:195-212 vs 214-230 vs 237-254). Two of the three are redundant. +all have the same six fields with the same types, the same optionality, and +the same JSDoc text. Two of the three are redundant. Recommendation: @@ -160,7 +150,7 @@ between the two spellings. JSDoc on the request `id` field even says "the ID for the corresponding *credential* to access" — i.e., it is logically a credential ID. The wire format uses `id` (path parameter) on requests and `credential_id` (body field) on responses — the *server* mints the -divergence; the TS-side should normalize to one spelling. See #21, #24. +divergence; the TS-side should normalize to one spelling. See #19, #22. ### H6. `gitProvider` is typed `string` but is closed-set @@ -230,7 +220,7 @@ JSDoc says "the name of the git credential, used for identification and ease of lookup". So `name` is a *display* name. The actual lookup key is `id`. Callers reading the type signature will assume `name` is a primary key (because it is on most Databricks resources — e.g., `clusters/{name}`). -`displayName` or `label` would clarify. See #23. +`displayName` or `label` would clarify. See #21. ### M4. `principalId` is a service-principal ID, not a user ID @@ -238,31 +228,9 @@ JSDoc on every `principalId` field says "The ID of the service principal whose credentials will be modified. Only service principal managers can perform this action." The field name says only "Principal" — which is overloaded in security/auth contexts. `servicePrincipalId` would -self-document. See #22. +self-document. See #20. -### M5. `parseResponse` / `marshalRequest` / `executeCall` / `executeHttpCall` (action-verb soup) - -`utils.ts` exposes: - -- `parseResponse(body, schema)` -- `marshalRequest(data, schema)` -- `executeCall(call, options)` -- `executeHttpCall(opts)` -- `buildHttpRequest(method, url, headers, signal?, body?)` - -Three different action verbs across the file (`parse`, `marshal`, -`execute`, `build`). The `parse`/`marshal` mismatch is the loudest one -(both functions are zod-schema invocations that go in opposite -directions). Either: - -- `marshalRequest` / `unmarshalResponse` (Go idiom, matches `marshal*Schema`/`unmarshal*Schema`), or -- `encodeRequest` / `decodeResponse` (TS idiom). - -The `execute*` pair (`executeCall` wraps the retry/rate-limit executor; -`executeHttpCall` is a single HTTP round-trip) has been flagged in every -audit so far. See #27, #28, #30. - -### M6. `personalAccessToken` field name is narrower than its accepted values +### M5. `personalAccessToken` field name is narrower than its accepted values JSDoc: @@ -273,9 +241,9 @@ JSDoc: So the field accepts more than just "personal access tokens" — also "fine- grained tokens", "deploy keys", etc. depending on the provider. The name `personalAccessToken` lies about that. `accessToken` (or `token`) is -honest. See #15. +honest. See #23. -### M7. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term +### M6. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term The model has one *singular* type — `Credential` (the resource) — and five *plural* request/response types around it. Within one file the same @@ -302,30 +270,7 @@ URL `/credentials`), singular for resource ops (`getCredential`, ## Low severity (style polish) -### L1. `isDefaultForProvider` is verbose - -20 chars. "For Provider" is implied (a credential's provider is fixed, -"default" only has meaning relative to it). `isDefault` is sufficient. See -#16. - -### L2. `flattenQueryParams` is dead code - -Exported from `utils.ts:123`, never imported in `client.ts`. Either remove -or use. The four client methods that take query parameters all build the -query string inline. See #29. - -### L3. `parseResponse` vs `marshalRequest` action-verb mismatch - -See M5. The `parse`/`marshal` mismatch is the worst of the action-verb -soup. See #28. - -### L4. `PACKAGE_SEGMENT` could be more specific - -"Segment" is vague — it is a user-agent segment, specifically. The -constant is used once (in the User-Agent string). `USER_AGENT_PACKAGE_SEGMENT` -would tie it to its only consumer. See #31. - -### L5. `awsCodeCommit` is documented as deprecated but not tagged +### L1. `awsCodeCommit` is documented as deprecated but not tagged The JSDoc on `gitProvider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on @@ -349,23 +294,20 @@ them for awareness — fixing requires an API-server change. | Identifier kind | Count | |---|---| | Total exported interfaces | 10 | -| Underscored (proto-style) interfaces | 7 (`CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response`, and the schema consts) | +| Underscored (proto-style) interfaces | 5 (`CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response`) | | Plural request envelopes for single-resource ops | 4 | | Identical-shape interface trios | 1 (`Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | -| Inline ESLint disables required by these names | 10 | +| Inline ESLint disables required by these names | 5 | | Enums | 0 (despite an 8-value closed set on `gitProvider`) | ### Comparison to other audits | Issue | This package | `credentials` audit | `oauthcustomappintegration` (typical) | |---|---|---|---| -| Bare `Client` class | Yes (#19) | Yes (#10) | Yes | +| Bare `Client` class | Yes (#17) | Yes (#10) | Yes | | `_Response` underscore types | Yes (#8) | Yes (#18) | Yes | -| `marshal*Schema` / `unmarshal*Schema` consts | Yes (#25, #26) | Yes (#53) | Yes | -| `executeCall` / `executeHttpCall` vocabulary clash | Yes (#27) | Yes (#55) | Yes | -| `flattenQueryParams` dead code | Yes (#29) | Yes (#57) | Yes | -| Bare `id` field on requests vs `Id` on responses | Yes (#21, #24) | Partial (#12, `nameArg`) | Common | -| Plural request envelopes on single-resource ops | Yes (#5, #6, #20) | No (uses `nameArg`/singular shapes) | Mixed | +| Bare `id` field on requests vs `Id` on responses | Yes (#19, #22) | Partial (#12, `nameArg`) | Common | +| Plural request envelopes on single-resource ops | Yes (#5, #6, #18) | No (uses `nameArg`/singular shapes) | Mixed | | `string`-typed enum-domain field | Yes (#9) | No (uses real enums) | Rare | The `string`-typed `gitProvider` despite a documented closed set (#9, H6) diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index 6ccd4470..2cb4c039 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -84,30 +84,18 @@ None. This package defines no enums. - `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`. -- Marshal / unmarshal schemas: - `unmarshalCreateGlobalInitScript_ResponseSchema`, - `unmarshalDeleteGlobalInitScript_ResponseSchema`, - `unmarshalGlobalInitScriptDetailsSchema`, - `unmarshalListGlobalInitScripts_ResponseSchema`, - `unmarshalUpdateGlobalInitScript_ResponseSchema`, - `marshalCreateGlobalInitScriptSchema`, - `marshalUpdateGlobalInitScriptSchema`. --- ## 2. Findings by Category -### 2.1 Vague / generic names — High & Medium +### 2.1 Vague / generic names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `CreateGlobalInitScript.script` / `UpdateGlobalInitScript.script` | High | The field name `script` is overloaded inside a type whose entity name is already "script". A `CreateGlobalInitScript` whose payload field is `script` reads as "the script of the script". Worse, the JSDoc says it carries "Base64-encoded content". A name like `content`, `body`, or `scriptContent` would convey what the bytes actually are. | | V-02 | `GlobalInitScriptDetails.position` | Medium | `position` is generic. Without the JSDoc the reader cannot tell whether it is an array index, a UI ordering hint, a priority, or an execution-order rank. `executionOrder`, `runOrder`, or `priority` would be more self-describing. | | V-03 | `GlobalInitScriptDetails.name` | Low | Generic but standard across the SDK; acceptable in entity context. | -| V-04 | `parseResponse` (utils) | Low | Generic, but local to the package. Acceptable. | -| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | -| V-06 | `executeCall` / `executeHttpCall` (utils) | Low | Generic but precise: one wraps the other. Acceptable. | -| V-07 | `readAll` (utils, local) | Low | Local helper for draining a `ReadableStream`. Acceptable. | ### 2.2 Redundant enum prefixes — None @@ -129,11 +117,7 @@ No enums are declared in this package; this rubric category does not apply. | U-02 | `DeleteGlobalInitScript_Response` | High | Same as U-01. | | U-03 | `ListGlobalInitScripts_Response` | High | Same as U-01. | | U-04 | `UpdateGlobalInitScript_Response` | High | Same as U-01. | -| U-05 | `unmarshalCreateGlobalInitScript_ResponseSchema` | High | Underscore in a constant identifier — same naming-convention violation as the interfaces cascades through the schema constants. Disable comment required. | -| U-06 | `unmarshalDeleteGlobalInitScript_ResponseSchema` | High | Same as U-05. | -| U-07 | `unmarshalListGlobalInitScripts_ResponseSchema` | High | Same as U-05. | -| U-08 | `unmarshalUpdateGlobalInitScript_ResponseSchema` | High | Same as U-05. | -| U-09 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | +| U-05 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | ### 2.5 Cryptic abbreviations — Low @@ -142,8 +126,6 @@ No enums are declared in this package; this rubric category does not apply. | C-01 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`) | Low | Short-lived local identifiers; OK for short scope but `request` / `response` would be clearer at no cost. | | C-02 | `opts` (`utils.ts` parameter) | Low | Inside fn scope; minor. | | C-03 | `pkgJson` (`client.ts`) | Low | Abbreviation of "packageJson". Local import alias; OK. | -| C-04 | `b` (lambda in marshal schema: `Array.from(d, b => ...)`) | Low | Single-letter loop variable; OK in tight scope. | -| C-05 | `d` (lambda parameter in `.transform(d => ...)`, repeated) | Low | Same as C-04; idiomatic for Zod transforms but `data` would be clearer. | ### 2.6 Misleading names — High @@ -152,8 +134,6 @@ No enums are declared in this package; this rubric category does not apply. | M-01 | `CreateGlobalInitScript.script` (field type `Uint8Array`) | High | The field is documented as "Base64-encoded content" but its TS type is `Uint8Array` — the marshal schema converts the bytes to Base64 via `btoa`. Callers therefore supply **raw bytes**, not Base64. The JSDoc is misleading: it describes the wire format, not what the caller hands in. A better split would be either rename to `scriptBytes` (matching the runtime type) or change the doc to "Raw bytes; the SDK Base64-encodes before sending." | | M-02 | `UpdateGlobalInitScript.script` | High | Same as M-01. | | M-03 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | -| M-04 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | -| M-05 | `executeCall` vs `executeHttpCall` | Low | The pair is layered correctly; precise. | ### 2.7 Overly verbose / Redundant suffixes — Medium @@ -161,10 +141,6 @@ No enums are declared in this package; this rubric category does not apply. | ----- | ----------------------------------------------- | -------- | ----- | | O-01 | `CreateGlobalInitScript` / `DeleteGlobalInitScript` / `GetGlobalInitScript` / `UpdateGlobalInitScript` / `ListGlobalInitScripts` | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full, producing ~22-25-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `Create`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | | O-02 | `GlobalInitScriptDetails` (entity name) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | -| O-03 | `unmarshalGlobalInitScriptDetailsSchema` | Medium | 38 chars. Combination of `unmarshal*Schema` triple-statement plus the long entity name. The pattern is repo-wide. | -| O-04 | `unmarshalCreateGlobalInitScript_ResponseSchema` | Medium | 47 chars — among the longest identifiers in the package. Pattern is repo-wide; flagged once. | -| O-05 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | -| O-06 | `buildHttpRequest`, `executeHttpCall` (utils) | Low | Descriptive; OK. | ### 2.8 Singular / plural mismatches — Low @@ -191,8 +167,6 @@ _None._ | ----- | ----------------------------------- | -------- | ----- | | D-01 | `CreateGlobalInitScript` vs `UpdateGlobalInitScript` | Medium | Update adds only one field (`scriptId`); otherwise identical to create. Two near-duplicate 4-field interfaces. Codegen constraint, but readers see them side by side. | | D-02 | `GlobalInitScriptDetails` vs `CreateGlobalInitScript` / `UpdateGlobalInitScript` | Medium | Same `name`, `position`, `enabled` fields appear in three types. The entity adds audit fields (`createdBy`, `createdAt`, etc.) but omits `script`. A shared base / fragment would reduce duplication. | -| D-03 | `unmarshalDeleteGlobalInitScript_ResponseSchema` and `unmarshalUpdateGlobalInitScript_ResponseSchema` | Medium | Both `z.object({})` — two identically empty schemas. The duplication is forced by the typed-distinct-interfaces pattern. | -| D-04 | Identical Zod schema bodies inside `marshalCreateGlobalInitScriptSchema` and `marshalUpdateGlobalInitScriptSchema` | Low | Marshal schemas overlap heavily; update adds only `scriptId`. Codegen constraint. | ### 2.12 Verb-tense inconsistency — Low @@ -207,9 +181,8 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `CreateGlobalInitScript_Response` (proto nested-message style) | High | Direct port of Go / protobuf `pb.CreateGlobalInitScriptResponse` naming. TypeScript ecosystems do not use `_` between message and nested-message names; the file disables ESLint for each occurrence. Should adopt the TS-idiomatic `CreateGlobalInitScriptResponse`. Applies to all four `*_Response` interfaces. | -| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**). Newcomers to TS will look up "marshal" before recognising it. Repo-wide convention. | -| G-03 | `GlobalInitScriptDetails` (Java-style "Details" suffix) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | -| G-04 | `req: CreateGlobalInitScript` (parameter named `req`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | +| G-02 | `GlobalInitScriptDetails` (Java-style "Details" suffix) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | +| G-03 | `req: CreateGlobalInitScript` (parameter named `req`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | ### 2.14 Generic field names losing meaning — Medium @@ -248,7 +221,7 @@ No enums declared; not applicable. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `GlobalInitScriptDetails` | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-03. | +| TS-01 | `GlobalInitScriptDetails` | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-02. | | TS-02 | `HttpCallOptions` (utils) | Low | "Options" is conventional for option-bag types; not tautological. | | TS-03 | `CallOptions` (imported) | Low | Same. | @@ -257,14 +230,11 @@ No enums declared; not applicable. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | X-01 | `GlobalInitScriptDetails.createdAt` / `updatedAt` (`number`, epoch ms) | Low | Acceptable for ms timestamps; the SDK exposes these as plain numbers. JS `Date` safe-integer range covers epoch-ms beyond year 285,000. Flagged for parity with other audits. | -| X-02 | `marshalRequest` (utils) | Low | Generic for "marshal arbitrary request body". OK in context. | -| X-03 | `flattenQueryParams` (utils, exported but unused in `client.ts`) | Low | `client.ts` builds no query strings — all parameters are body or path. Either drop the export or move to a shared helper module. Not strictly a naming issue. | -| X-04 | `executeHttpCall` vs `executeCall` (utils) | Low | Two-level wrapper: `executeCall` (transport-agnostic) wraps `executeHttpCall` (HTTP-specific). Naming communicates the layering; OK. | -| X-05 | `PACKAGE_SEGMENT` constant | Low | `SCREAMING_SNAKE_CASE` for a module-level constant — Google TS style permits this for "module-level constants … that are deeply immutable and used like enum constants" (https://google.github.io/styleguide/tsguide.html#constants). OK. | -| X-06 | `Client` (class name) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | -| X-07 | `VERSION as AUTH_VERSION` (imported alias) | Low | Aliasing on import is fine; communicates which version is being referenced. OK. | -| X-08 | `HttpClient`, `HttpRequest`, `HttpResponse` (imported) | Low | Consistent Google-style acronym casing. OK. | -| X-09 | `NoOpLogger` (imported) | Low | `NoOp` casing is correct for "no-op" (the term `no-op` is itself a contracted form). OK. | +| X-02 | `PACKAGE_SEGMENT` constant | Low | `SCREAMING_SNAKE_CASE` for a module-level constant — Google TS style permits this for "module-level constants … that are deeply immutable and used like enum constants" (https://google.github.io/styleguide/tsguide.html#constants). OK. | +| X-03 | `Client` (class name) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | +| X-04 | `VERSION as AUTH_VERSION` (imported alias) | Low | Aliasing on import is fine; communicates which version is being referenced. OK. | +| X-05 | `HttpClient`, `HttpRequest`, `HttpResponse` (imported) | Low | Consistent Google-style acronym casing. OK. | +| X-06 | `NoOpLogger` (imported) | Low | `NoOp` casing is correct for "no-op" (the term `no-op` is itself a contracted form). OK. | --- @@ -274,21 +244,20 @@ No enums declared; not applicable. | Severity | Count | | -------- | ----- | -| High | 12 | -| Medium | 17 | -| Low | 36 | -| **Total**| **65**| +| High | 11 | +| Medium | 12 | +| Low | 27 | +| **Total**| **50**| ### 3.2 Top themes 1. **Proto-style `_Response` suffix pollutes every CRUD response type.** Four interfaces (`CreateGlobalInitScript_Response`, `DeleteGlobalInitScript_Response`, `ListGlobalInitScripts_Response`, - `UpdateGlobalInitScript_Response`) and their corresponding schema - constants each require an `eslint-disable` for the naming-convention - rule. Renaming to TS-idiomatic `CreateGlobalInitScriptResponse` etc. - would eliminate ~8 disable-comments and a Google-style violation in - one sweep. + `UpdateGlobalInitScript_Response`) each require an `eslint-disable` + for the naming-convention rule. Renaming to TS-idiomatic + `CreateGlobalInitScriptResponse` etc. would eliminate the + disable-comments and a Google-style violation in one sweep. 2. **`script` field overload conflates "script bytes" with "the entity".** The field is typed as `Uint8Array` (raw bytes), documented as @@ -312,7 +281,7 @@ No enums declared; not applicable. - Drop the `_Response` underscore: `CreateGlobalInitScriptResponse`, `DeleteGlobalInitScriptResponse`, `ListGlobalInitScriptsResponse`, - `UpdateGlobalInitScriptResponse`. Removes 8 ESLint disables. + `UpdateGlobalInitScriptResponse`. Removes ESLint disables. - Rename `script` field to `content` (or `scriptContent`). - Rename entity `GlobalInitScriptDetails` -> `GlobalInitScript`. - Add the missing content field on the entity (or fix the JSDoc on @@ -320,9 +289,6 @@ No enums declared; not applicable. ### 3.4 Cross-package consistency notes -- The `marshal*` / `unmarshal*` schema-naming convention is consistent - with peer packages (e.g. `clusterpolicies`, `clusters`) and is therefore - a repo-wide concern, not a per-package fix. - The `Proto-style nested message name` `_Response` suffix is consistent with peers and should be addressed at the codegen level. - `position` field semantics are unique to this resource; no other diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md index 63752723..e2b2abf0 100644 --- a/.agent/naming-audit/grants.md +++ b/.agent/naming-audit/grants.md @@ -3,15 +3,15 @@ **Path:** `packages/grants/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. -**Total weird names flagged:** 45 +**Total weird names flagged:** 34 ## Summary | Severity | Count | | --- | --- | | High | 14 | -| Medium | 17 | -| Low | 9 | -| Observation | 5 | +| Medium | 15 | +| Low | 4 | +| Observation | 1 | The grants package contains 12 generated types and 5 client methods (plus 2 paginated iterators) covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive issues are (1) the request-type-as-verb naming pattern (`GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions`) which collides with the verb-noun method naming on `Client` and is doubly confusing because the API mixes "permissions" and "privileges" terminology in the same file, (2) proto-style `_Response` underscore-suffixed identifiers leaking into TypeScript (`GetPermissions_Response`, `GetEffectivePermissions_Response`, `UpdatePermissions_Response`) requiring eslint-disable directives, (3) significant duplication of concept between `GetPermissions` / `ListPrivilegeAssignmentsRequest` and `GetEffectivePermissions` / `ListEffectivePrivilegeAssignmentsRequest` — four request types for two operations, plus inconsistent field naming (`securableFullName` vs `fullName`, `maxResults` vs `pageSize`) — and (4) hard-conceptual overlap with the separate `permissions` package, which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation. @@ -168,49 +168,37 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi - **Suggested name:** `assignments`. - **Rationale:** See #22. -### 24. `listEffectivePrivilegeAssignmentsIter` — `src/v1/client.ts:220` -- **Why weird:** 38-character method name on `Client`. `Iter` suffix is Go-style (Go uses `*Iterator` types; TS uses `AsyncGenerator` / `AsyncIterable`). The async generator syntax `async *foo()` is already iterating — `Iter` adds nothing the language doesn't communicate. Plus the noun pile-up: `list` + `Effective` + `Privilege` + `Assignments` + `Iter`. -- **Category:** 5 (cryptic abbreviation: `Iter`), 14 (Go-style name), 7 (overly verbose). -- **Suggested name:** `iterateEffectivePrivilegeAssignments` (verb-first for generators), or `effectiveAssignments` (with the iterator semantics implied). -- **Rationale:** TS convention is `for await` over async generators with verb-first naming. - -### 25. `listPrivilegeAssignmentsIter` — `src/v1/client.ts:289` -- **Why weird:** Same problem as #24. -- **Category:** 5, 14, 7. -- **Suggested name:** `iteratePrivilegeAssignments` or `assignments`. -- **Rationale:** See #24. - -### 26. `getEffectivePermissions` (method) — `src/v1/client.ts:82` +### 24. `getEffectivePermissions` (method) — `src/v1/client.ts:82` - **Why weird:** Method returns `GetEffectivePermissions_Response` (note the underscore — see #4). The method-name-as-verb is fine, but the type contract has the proto-style wart. Also, the doc-comment notes "Unpaginated calls will be deprecated soon" — so this method exists as a soon-to-be-deprecated mirror of `listEffectivePrivilegeAssignments`. Why ship both in the same v1? - **Category:** 12 (duplicate concept — see #9), Observation. - **Suggested name:** Mark as `@deprecated` in JSDoc (currently the deprecation note is just plain text inside the doc-comment, lines 77-78 — not an actual `@deprecated` tag). - **Rationale:** Tooling like IDEs and ts-doc strikes through deprecated methods only when the `@deprecated` tag is used. -### 27. `getPermissions` (method) — `src/v1/client.ts:129` -- **Why weird:** Same as #26 — soon-to-be-deprecated unpaginated mirror of `listPrivilegeAssignments`. +### 25. `getPermissions` (method) — `src/v1/client.ts:129` +- **Why weird:** Same as #24 — soon-to-be-deprecated unpaginated mirror of `listPrivilegeAssignments`. - **Category:** 12, Observation. - **Suggested name:** Add `@deprecated` JSDoc tag. -- **Rationale:** See #26. +- **Rationale:** See #24. -### 28. `securableType: string` — model-wide (5 occurrences) +### 26. `securableType: string` — model-wide (5 occurrences) - **Why weird:** Same concept as #19 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. - **Category:** 19 (underspecified), 1 (vague). - **Suggested name:** Define a `SecurableType` enum. - **Rationale:** See #19. -### 29. `nextPageToken` (field, multiple) — `src/v1/model.ts:58,96,123,162` +### 27. `nextPageToken` (field, multiple) — `src/v1/model.ts:58,96,123,162` - **Why weird:** Same identifier appears in 4 response types. Fine in isolation, but the doc-comment "__page_token__ should be set to this value for the next request (for the next page of results)" is copy-pasted verbatim 4 times — including the suspicious `__page_token__` (double-underscore, suggesting wire-format documentation) which makes no sense for TS consumers using `pageToken`. - **Category:** Observation (mostly consistency), 6 (misleading: `__page_token__` in doc). - **Suggested name:** No rename needed, but doc-comments should reference TS field name `pageToken`, not `__page_token__`. - **Rationale:** Doc string consistency. -### 30. `includeDeletedPrincipals` — `src/v1/model.ts:87,109,136` +### 28. `includeDeletedPrincipals` — `src/v1/model.ts:87,109,136` - **Why weird:** Verbose camelCase boolean. Reasonable but flagged because it's missing from `GetEffectivePermissions` (where the analogous feature would also make sense) but present on `GetPermissions` and both `List*Request` types. Inconsistent feature parity (see also #9). - **Category:** 17 (inconsistency), 7 (verbose). - **Suggested name:** `includeDeleted` (shorter). - **Rationale:** Consistency issue more than naming issue. -### 31. `Client` — `src/v1/client.ts:49` +### 29. `Client` — `src/v1/client.ts:49` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts` re-exports `Client` (line 3), so users write `import { Client } from '@databricks/sdk-grants/v1'`. Same name appears in every generated package — you can't have multiple grants/catalogs/etc. clients in one import without aliasing. - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `GrantsClient` (or whatever the package-specific name is). @@ -220,55 +208,25 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi ## Low severity -### 32. `unmarshalEffectivePrivilegeSchema` / `marshalUpdatePermissionsSchema` and related — `src/v1/model.ts:212,225,239,253,266,279,292,306,317,331` -- **Why weird:** Eight `unmarshal*Schema` and two `marshal*Schema` exports. Long names with redundant `Schema` suffix; the `z.ZodType` type annotation already says they're Zod schemas. Plus three of them (`unmarshalGetEffectivePermissions_ResponseSchema`, `unmarshalGetPermissions_ResponseSchema`, `unmarshalUpdatePermissions_ResponseSchema`) embed proto underscores and require eslint-disable directives (lines 238, 252, 305). -- **Category:** 8 (redundant `Schema` suffix), 4 (underscores), 20 (type-suffix tautology). -- **Suggested name:** Drop `Schema` suffix → `unmarshalEffectivePrivilege`, `marshalUpdatePermissions`, etc. -- **Rationale:** Naming consistency with the rest of the SDK; the suffix carries no info beyond the type signature. - -### 33. `unmarshalGetEffectivePermissions_ResponseSchema` — `src/v1/model.ts:239` -- **Why weird:** 49-character name; combines #32 (`Schema` suffix), #4 (proto underscore), and the verbose `GetEffectivePermissions` (#3). Requires eslint-disable. -- **Category:** 4, 7, 8. -- **Suggested name:** `unmarshalEffectivePermissionsResponse` (cascading from #4 and #32). -- **Rationale:** Cascades. - -### 34. `unmarshalGetPermissions_ResponseSchema` — `src/v1/model.ts:253` -- **Why weird:** Same as #33. -- **Category:** 4, 7, 8. -- **Suggested name:** `unmarshalPermissionsResponse`. -- **Rationale:** Cascades. - -### 35. `unmarshalUpdatePermissions_ResponseSchema` — `src/v1/model.ts:306` -- **Why weird:** Same as #33. -- **Category:** 4, 7, 8. -- **Suggested name:** `unmarshalUpdatePermissionsResponse`. -- **Rationale:** Cascades. - -### 36. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:44` +### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:44` - **Why weird:** `Segment` is a generic word; without the doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 37. `flattenQueryParams` — `src/v1/utils.ts:123` +### 31. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove if generator default. - **Rationale:** Generator emits the same helper into every package even when unused. -### 38. `readAll` — `src/v1/utils.ts:40` +### 32. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / Web Streams. The function reads a `ReadableStream` into a single buffer. - **Category:** 1 (vague), 14 (Go-style: `io.ReadAll` is a Go idiom). - **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. - **Rationale:** Cross-package consistency. -### 39. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same file. The model file uses `marshal*` / `unmarshal*` consistently — `parseResponse` is the odd one out. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. -- **Rationale:** Mirroring helps readers map TS→wire/wire→TS at a glance. - -### 40. `HttpCallOptions` — `src/v1/utils.ts:15` +### 33. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix), 17 (inconsistent). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -278,22 +236,6 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi ## Observations -### 41. Five client methods cover effectively two operations -`getPermissions`, `getEffectivePermissions`, `listPrivilegeAssignments`, `listEffectivePrivilegeAssignments`, `updatePermissions`. The two Get-style methods are documented as soon-to-be-deprecated mirrors of the List-style methods, leaving the steady-state SDK with three operations: list, list-effective, update. The 5-method surface is a transitional artefact. -- **Category:** 12 (duplicate concept), Observation. - -### 42. Wire vs. TS field-name churn -TS `securableFullName` → wire `securable_full_name`; TS `securableType` → wire `securable_type`; TS `principalId` → wire `principal_id`; TS `pageSize` → wire `page_size`. All consistent snake_case ↔ camelCase translations — flagged only because the `marshalPermissionsChangeSchema` (line 317) marshals `principalId` to `principal_id` but the doc-comment on `PermissionsChange` refers to it as "principal_id" (line 180), which mixes wire-format vocabulary into the TS surface doc. -- **Category:** Observation, 6 (misleading docs). - -### 43. `Client` constructor: `Host is required.` — `src/v1/client.ts:60` +### 34. `Client` constructor: `Host is required.` — `src/v1/client.ts:60` Error message thrown but no client name in the message. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. - **Category:** Observation. - -### 44. `GetEffectivePermissions.maxResults` doc — `src/v1/model.ts:35-46` -The doc-comment is 12 lines of conditional behaviour ("If not set / If set to lesser than 0 / equal to 0 / lesser than 150 ...") — appropriate detail but copy-pasted verbatim into `GetPermissions.maxResults` (lines 71-82) and partially into `ListPrivilegeAssignmentsRequest.pageSize` (lines 139-150). Three near-identical 10+ line blocks. Naming-adjacent — flag for doc DRY-ness. -- **Category:** Observation. - -### 45. `unmarshal*Schema` and `marshal*Schema` exported but only used internally -All schemas are re-imported by `client.ts` from the same `./model` module; they aren't re-exported from `index.ts` (lines 7-22 list only the types). So the schemas are part of the package's effective surface (importable as `'./model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). Naming-adjacent. -- **Category:** Observation, 11 (effectively-internal exports). diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md index 7e0ecf8f..90b955c4 100644 --- a/.agent/naming-audit/iam.md +++ b/.agent/naming-audit/iam.md @@ -14,8 +14,8 @@ and resolve-by-external-id flows that bridge the customer IdP to Databricks. | High | 18 | | Medium | 22 | | Low | 16 | -| Observation | 9 | -| **Total** | **65** | +| Observation | 5 | +| **Total** | **61** | Three dominant themes emerged. **First, the package ships every method, request, and a handful of enums in two parallel forms — `*` and `*Proxy` — @@ -151,9 +151,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Category:** 4, 14 (underscore in TS identifier; proto-style) - **Issue:** `User_Name` is a nested message type carrying `givenName` and `familyName`. The name violates TS conventions (requires - `// eslint-disable-next-line` to compile). The corresponding - `unmarshalUser_NameSchema` and `user_NameFieldMaskSchema` propagate the - same underscored identifier downward through the file. + `// eslint-disable-next-line` to compile). - **Suggestion:** Rename to `UserName` or, better, `PersonName` (since `userName` is overloaded with `username` two lines up — see H7). Even inlining `givenName?: string; familyName?: string` onto `User` would be @@ -803,48 +801,20 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / generator falls back to when the upstream API definition lacks documentation. The fix is in the upstream spec, not the SDK. -### O3. `marshal*ProxyRequestSchema` vs `marshal*RequestSchema` — schema-level Proxy variants -- **File:** `model.ts:1342, 1350, 1360, 1368, 1378, 1386` -- **Issue:** Each Resolve request has both marshal schemas; the proxy - variant is identical to the non-proxy minus `accountId`. Same H1 pattern - at the schema layer. - -### O4. `FieldMaskSchema` is defined per resource type -- **File:** `model.ts:1473, 1484, 1502, 1521, 1538` -- **Issue:** Five `FieldMaskSchema`s defined for Group, ServicePrincipal, - User, WorkspaceAssignmentDetail, WorkspaceIdentityDetail. Pattern is - consistent across the SDK — flagging for completeness only. - -### O5. Marshal/unmarshal schema pairs exist for all types but Direct/Transitive -- **File:** `model.ts:1006-1471` -- **Issue:** Unmarshal schemas exist for all response shapes including - `TransitiveParentGroup`, but marshal schemas only exist for shapes that - appear in request bodies (no marshal for `TransitiveParentGroup`, - `WorkspaceAccessDetail`). Consistent with the request/response split, but - worth confirming this is intentional and not generator skew. - -### O6. `User_NameFieldMaskSchema` (lowercase initial) — naming inconsistency -- **File:** `model.ts:1516` -- **Issue:** Variable name is `user_NameFieldMaskSchema` (snake_case initial - segment, then camelCase). The eslint disable comment says - `naming-convention -- Proto-style nested message name.`. The - inconsistency is `User_Name` (type, PascalCase + underscore) vs - `user_NameFieldMaskSchema` (variable, camelCase first + underscore). - -### O7. Method name `getAccountAccessIdentityRule` is 35 characters +### O3. Method name `getAccountAccessIdentityRule` is 35 characters - **File:** `client.ts:241` - **Issue:** All four rule-endpoint method names hover around 30–37 chars. Not actionable on its own — flagging because long names compound the H1 problem. -### O8. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) +### O4. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) - **File:** `model.ts:411, 677`, `client.ts:1715, 1783` - **Issue:** Only WorkspaceAccessDetail has a `Local` variant; the parallel `WorkspaceAssignmentDetail` uses `Proxy` instead, and `WorkspaceIdentityDetail` has neither. Inconsistent presence of the Local/Proxy variants across sibling Detail types. -### O9. The `accountId` fallback comment in `client.ts:151-152` only applies to non-proxy methods +### O5. The `accountId` fallback comment in `client.ts:151-152` only applies to non-proxy methods - **File:** `client.ts:151-152` - **Issue:** "Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins." This is true @@ -857,7 +827,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / ## Cross-cutting recommendations (priority order) -1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O3, O8, O9).** This +1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O4, O5).** This is the largest single improvement and ~halves the public type surface. 2. **Drop `_UNSPECIFIED` enum members (H10, H4).** 9 dead enum values removed; users no longer write `=== State.STATE_UNSPECIFIED` accidentally. diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md index 6e76349f..86d63ec3 100644 --- a/.agent/naming-audit/indexes.md +++ b/.agent/naming-audit/indexes.md @@ -3,15 +3,15 @@ **Path:** `packages/indexes/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Vector Search index management — CRUD for `VectorIndex` (Delta-Sync or Direct-Access subtypes), data upsert/delete on direct-access indexes, vector/text/hybrid query, scan, pagination, and sync trigger. Routes under `/api/2.0/vector-search/indexes`. -**Total weird names flagged:** 43 +**Total weird names flagged:** 38 ## Summary | Severity | Count | | --- | --- | -| High | 14 | +| High | 13 | | Medium | 17 | -| Low | 9 | -| Observation | 3 | +| Low | 6 | +| Observation | 2 | ## High severity @@ -37,7 +37,7 @@ - **Why weird:** Both types declare exactly the same nine fields with the same types and (where present) the same JSDoc lines. They are duplicates. The only signal of intent is the prefix "Mini". If they are meant to be the same, one should be an alias; if they differ, the difference must be documented. - **Category:** 12 (duplicate concept). - **Suggested name:** Either `export type VectorIndexSummary = VectorIndex;` (with a comment noting wire-format identity), or drop one entirely. If the API intends them to diverge later, document the upcoming difference. -- **Rationale:** Duplicating ~25 lines of type definition with no semantic distinction is a maintenance hazard. The unmarshalers (`unmarshalMiniVectorIndexSchema` model.ts:595 and `unmarshalVectorIndexSchema` model.ts:735) are also byte-for-byte identical. +- **Rationale:** Duplicating ~25 lines of type definition with no semantic distinction is a maintenance hazard. ### 5. `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:109-142` vs `model.ts:144-177` - **Why weird:** Two distinct exported types with the same ten fields, same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream protobuf quirk that should be flattened in TS. @@ -63,37 +63,31 @@ - **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.list()` paginator, `client.query()`, `client.queryNextPage()`, `client.scan()`, `client.sync()`, `client.upsertData()`, `client.deleteData()`, `client.delete()`. Some collide with reserved words (`delete`) — those few can keep the `...Index` suffix. - **Rationale:** The repetition is mechanical Go-port baggage. Other SDK packages in the workspace expose `client.get()`, `client.list()` directly. -### 9. `listVectorIndexIter` suffix `Iter` — `client.ts:242` -- **Why weird:** `Iter` is a cryptic abbreviation. The method returns an `AsyncGenerator` — JS convention is `iter*` prefix (Python-style), or `*Iterator`, or a generator method with no suffix relying on `Symbol.asyncIterator`. `Iter` is Rust/Go-style. -- **Category:** 5 (cryptic abbreviation), 14 (Rust/Go-style), 17 (inconsistent with `listVectorIndex` — same verb, different return shape). -- **Suggested name:** `listVectorIndexIterator` or expose as `listAll()` / iterate via `for await (const i of client.list())`. -- **Rationale:** `Iter` does not appear in the JS standard library; `Iterator` does. The convention here is set in the SDK and is consistent across packages — flagged as a cross-package issue, but worth recording. - -### 10. `name` is the resource identifier on every Request type — meaning is overloaded — multiple sites +### 9. `name` is the resource identifier on every Request type — meaning is overloaded — multiple sites - **Why weird:** Fifteen Request/response types use a bare `name?: string` for what is actually the full index identifier (typically a Unity Catalog qualified name like `main.schema.index`). Types affected: `CreateVectorIndexRequest.name` (model.ts:64), `DeleteDataVectorIndexRequest.name` (model.ts:89), `DeleteVectorIndexRequest.name` (model.ts:103), `GetVectorIndexRequest.name` (model.ts:216), `MiniVectorIndex.name`, `QueryVectorIndexNextPageRequest.name` (model.ts:280), `QueryVectorIndexRequest.name` (model.ts:289), `ScanVectorIndexRequest.name` (model.ts:365), `SyncVectorIndexRequest.name` (model.ts:387), `UpsertDataVectorIndexRequest.name` (model.ts:395), `VectorIndex.name` (model.ts:427). JSDoc on every one says "Name of the index" — but a UC three-part name is more than a "name", it's a path/identifier. - **Category:** 15 (generic field name losing meaning), 19 (underspecified ID). - **Suggested name:** `indexFullName`, `indexId`, or at least add JSDoc clarifying the expected format ("three-part Unity Catalog identifier `..`"). - **Rationale:** `name` is too generic when the value is a structured path. Users reading `req.name = "foo"` may send a bare name and get a 404. -### 11. `endpointName` field for the *index endpoint* — generic name shared across packages — `model.ts:65, 233, 256, 282, 429` +### 10. `endpointName` field for the *index endpoint* — generic name shared across packages — `model.ts:65, 233, 256, 282, 429` - **Why weird:** Five sites use `endpointName?: string`. There is no JSDoc disambiguation between "vector search endpoint", "model serving endpoint", "external endpoint", "AI gateway endpoint" — all are Databricks concepts. The `EmbeddingSourceColumn.embeddingModelEndpointName` (model.ts:200) shows the SDK *does* qualify endpoint references when ambiguous, but here it does not. - **Category:** 15 (generic field name), 19 (underspecified ID). - **Suggested name:** `vectorSearchEndpointName` or add JSDoc clarifying it is "the Vector Search endpoint serving this index". The terse `endpointName` is fine *if* combined with type-level JSDoc. - **Rationale:** The package owns a `VectorIndex` resource that is hosted on a *vector-search* endpoint — but a reader who jumps to a method signature sees only `endpointName` and may guess wrong. -### 12. `RerankerConfig_RerankerParameters` — underscore-separated type — `src/v1/model.ts:343` +### 11. `RerankerConfig_RerankerParameters` — underscore-separated type — `src/v1/model.ts:343` - **Why weird:** Underscore in a TypeScript type identifier. The file has an `eslint-disable-next-line @typescript-eslint/naming-convention` directive on it (line 342, with the comment "Proto-style nested message name") confirming the lint rule is being suppressed. Same suppression at line 953 for the marshal schema. The type's only field is `columnsToRerank` (already present on the parent's `QueryVectorIndexRequest.columnsToRerank` — model.ts:315). - **Category:** 4 (underscore in TS identifier), 14 (proto-style name leaking). - **Suggested name:** `RerankerParameters` (drop the redundant `RerankerConfig_` prefix), or namespace it: `namespace RerankerConfig { export type Parameters = ... }`. -- **Rationale:** The underscore costs a lint suppression in two locations and is a leaky proto abstraction. The `RerankerConfig_` prefix is also redundant with the wrapping type — duplicate name (see #13). +- **Rationale:** The underscore costs a lint suppression in two locations and is a leaky proto abstraction. The `RerankerConfig_` prefix is also redundant with the wrapping type — duplicate name (see #12). -### 13. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:315` vs `model.ts:344` +### 12. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:315` vs `model.ts:344` - **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 315, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 344) inside the nested `RerankerConfig`. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:316-321) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. - **Category:** 12 (duplicate concept), 6 (misleading — which one wins?). - **Suggested name:** Drop one, or document the precedence. If one is for input and the other for output/echo, name them accordingly. - **Rationale:** Users will set the wrong field. Worth raising upstream. -### 14. `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` — `model.ts:133-134, 168-169` +### 13. `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` — `model.ts:133-134, 168-169` - **Why weird:** `effective*` prefix usually marks a *response-only* computed field that reflects the inherited/resolved value from policies (see `database` package finding #11). But here these fields appear on the **Request** variant too (`DeltaSyncVectorIndexSpecRequest` lines 167-169). They cannot be both client-supplied *and* server-computed. Also `effectiveUsagePolicyId` has zero JSDoc — line 134/169 are bare. - **Category:** 6 (misleading — "effective" implies output-only on a request type), 17 (inconsistent: budget has JSDoc, usage does not). - **Suggested name:** Either remove the `effective*` fields from the Request variant, or document the read-only contract. Add the missing JSDoc on `effectiveUsagePolicyId`. @@ -101,103 +95,103 @@ ## Medium severity -### 15. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:23-27` +### 14. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:23-27` - **Why weird:** Enum exposes a sentinel value `VECTOR` whose JSDoc reads "Not supported. Use `HYBRID` instead." Exporting unsupported values inflates the enum and forces every consumer to filter or document them away. - **Category:** 6 (misleading: present but not supported), 18 (the value `VECTOR` is also a tautology when inside an enum called `IndexSubtype` describing a vector-search index — every value is a kind of "vector"). - **Suggested name:** Remove `VECTOR` from the enum, or rename the enum to `VectorIndexSubtype` and call the values `FullText | Hybrid`. Either way, eliminate the dead value. - **Rationale:** Unused enum members are bug magnets. -### 16. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:23, 50` +### 15. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:23, 50` - **Why weird:** `IndexSubtype` = `{VECTOR, FULL_TEXT, HYBRID}` (search semantics). `VectorIndexType` = `{DELTA_SYNC, DIRECT_ACCESS}` (data residency / sync model). Both are exposed as `index*Type*` fields. Same prefix word, different axes. Beginner users will conflate them. - **Category:** 6 (misleading: both look like "the type" of the index), 17 (inconsistent naming for two type axes). - **Suggested name:** Rename to disambiguate: `IndexSearchMode` (for subtype) and `IndexBackingType` / `IndexStorageType` (for the DELTA_SYNC/DIRECT_ACCESS axis). Or `IndexSearchKind` and `IndexSyncMode`. - **Rationale:** Two parallel `*Type` enums make the API harder to learn. The current names are technically correct but functionally ambiguous. -### 17. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:34-37` +### 16. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:34-37` - **Why weird:** All four enums (`IndexSubtype`, `PipelineType`, `UpsertDeleteDataStatus`, `VectorIndexType`) use `UPPER_SNAKE_CASE` for member names. Google TS Style Guide §9.3 recommends `UpperCamelCase` for enum members. The codebase is mixed (some enums use camelCase elsewhere). The values are also the wire-protocol strings — wire is `UPPER_SNAKE` legitimately, but the TS *identifier* can be `Triggered` mapping to wire `'TRIGGERED'`. - **Category:** 3 (acronym/casing inconsistency), 14 (Go/proto-style). - **Suggested name:** `PipelineType.Triggered | Continuous`, with explicit `= 'TRIGGERED'` wire values. Or accept the wire-form names and apply them consistently across all packages. - **Rationale:** Style consistency across the workspace; preference for camelCase enum members aligns with the Google TS Style Guide. -### 18. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:204` +### 17. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:204` - **Why weird:** Field name reads as a sentence (`modelEndpointName ForQuery`). JS field-naming convention is noun phrases, not "for"-clauses. Compare with adjacent `embeddingModelEndpointName` (also long, but a noun phrase). - **Category:** 14 (Java-ish "ForX" suffix), 7 (verbose). - **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. - **Rationale:** `for`-clauses in identifiers are uncommon in JS. The renaming aligns it with the adjacent field. -### 19. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:113-115, 149-150, 181, 189` +### 18. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:113-115, 149-150, 181, 189` - **Why weird:** Two parallel array fields on three different types (`DeltaSyncVectorIndexSpec`, `DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`). One holds source text columns to be embedded; the other holds pre-computed vector columns. Both arrays use *different* element types (`EmbeddingSourceColumn` vs `EmbeddingVectorColumn`) — good — but the field names look near-identical at a glance. - **Category:** 6 (visually confusable pair), 15 (the qualifier "Source"/"Vector" is doing all the work). - **Suggested name:** `textColumns` + `vectorColumns`, or `embeddingTextColumns` + `embeddingVectorColumns`. Anything to widen the gap between the two names. - **Rationale:** Pairs of similarly named array fields are a known footgun. A user typing `embedding` will autocomplete the wrong one. -### 20. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:127-141, 161-176` +### 19. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:127-141, 161-176` - **Why weird:** Two fields on the same type, JSDoc says they are aliases ("[Optional] Alias for columns_to_sync. Select the columns to include in the vector index. ... Only one of columns_to_sync or columns_to_index may be specified.") Having two fields that mean the same thing in one struct, where the API expects exactly one to be set, is a recipe for runtime errors. - **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). - **Suggested name:** Deprecate one in the SDK (mark `columnsToSync` as `@deprecated` if `columnsToIndex` is the new canonical), or merge them with a runtime validation. - **Rationale:** API-level aliases are upstream policy, but the SDK should clearly mark the deprecated alias. -### 21. `pipelineId` is an underspecified ID — `model.ts:123, 158` +### 20. `pipelineId` is an underspecified ID — `model.ts:123, 158` - **Why weird:** Field type is `string` with JSDoc "The ID of the pipeline that is used to sync the index." No format documented — is it a UUID, a numeric ID, a path? Compare with `effectiveBudgetPolicyId` which uses the same generic `string` but at least the policy ID is a known Databricks pattern. - **Category:** 19 (underspecified ID), 15 (generic). - **Suggested name:** Keep the name but improve the JSDoc with the expected ID format and a link to the Pipelines API. - **Rationale:** Without format hints, users will struggle to construct the value. -### 22. `effectiveBudgetPolicyId` on a *request* type without JSDoc explanation — `model.ts:133, 168` -- **Why weird:** See finding #14. Specifically, the field is on `DeltaSyncVectorIndexSpec` (response side) *and* `DeltaSyncVectorIndexSpecRequest` (request side). On the request side, "effective" is incoherent — there is no "effective" until the server resolves it. +### 21. `effectiveBudgetPolicyId` on a *request* type without JSDoc explanation — `model.ts:133, 168` +- **Why weird:** See finding #13. Specifically, the field is on `DeltaSyncVectorIndexSpec` (response side) *and* `DeltaSyncVectorIndexSpecRequest` (request side). On the request side, "effective" is incoherent — there is no "effective" until the server resolves it. - **Category:** 6 (misleading on the request side), 14 (proto leak: same field appears in both, even when only meaningful on one). - **Suggested name:** On `DeltaSyncVectorIndexSpecRequest`, drop the field (it cannot be set), or rename to `budgetPolicyIdOverride`. -- **Rationale:** See #14. +- **Rationale:** See #13. -### 23. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:397` +### 22. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:397` - **Why weird:** `UpsertDataVectorIndexRequest.inputsJson: string` is "JSON string representing the data to be upserted." The TS surface forces the caller to call `JSON.stringify()` themselves, then the marshaling layer wraps the request body in `JSON.stringify(...)` *again*. Double-encoded payloads are a well-known JSON antipattern. - **Category:** 6 (misleading — the field is JSON-in-JSON), 1 (generic — "inputs" tells you nothing about *what*). - **Suggested name:** Expose as `inputs: JsonValue[]` (or whatever the row shape is) and let the SDK serialize, OR keep `inputsJson` but rename to `inputsJsonString` and document the double-encoding. -- **Rationale:** Same problem with `filtersJson` (see #24) and `schemaJson` (see #25). All three are wire-protocol leaks that should be normalized at the SDK boundary. +- **Rationale:** Same problem with `filtersJson` (see #23) and `schemaJson` (see #24). All three are wire-protocol leaks that should be normalized at the SDK boundary. -### 24. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:305` -- **Why weird:** Same JSON-in-JSON pattern as #23. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. +### 23. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:305` +- **Why weird:** Same JSON-in-JSON pattern as #22. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. - **Category:** 6 (misleading), 1 (generic). - **Suggested name:** Expose as `filters?: Record` and serialize internally. Or rename `filtersJsonString`. -- **Rationale:** Same as #23. +- **Rationale:** Same as #22. -### 25. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:187` +### 24. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:187` - **Why weird:** Same pattern. The field is "The schema of the index in JSON format. Supported types are `integer`, `long`, `float`, `double`, `boolean`, `string`, `date`, `timestamp`." A typed schema descriptor would be far more discoverable. - **Category:** 6 (misleading), 1 (generic). - **Suggested name:** Expose as a typed shape, or rename `schemaJsonString` and add JSDoc warning. -- **Rationale:** Same as #23. +- **Rationale:** Same as #22. -### 26. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:125, 160` +### 25. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:125, 160` - **Why weird:** "Writeback" run together with "embedding" plus "Table" forms a hard-to-parse triple-noun. Pronunciation: "embed-ding-write-back-table". JSDoc clarifies meaning ("[Optional] Name of the Delta table to sync the vector index contents and computed embeddings to") — but the field name is opaque without it. - **Category:** 7 (overly verbose), 14 (Go-style smushed identifier). - **Suggested name:** `writebackTableName`, `embeddingsTableName`, or `computedEmbeddingsTable`. - **Rationale:** Readability of compound nouns degrades fast past 2 words. -### 27. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:223` +### 26. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:223` - **Why weird:** JSDoc says: "If true, the URL returned for the index is guaranteed to be compatible with the reranker. Currently this means we return the CP URL regardless of how the index is being accessed. If not set or set to false, the URL may still be compatible with the reranker depending on what URL we return." So the flag toggles *which URL is returned*, not whether the index itself is reranker-compatible. The name suggests the operation *ensures compatibility*, but it actually just changes URL format. - **Category:** 6 (misleading), 1 (vague boolean). - **Suggested name:** `useControlPlaneUrl`, `returnControlPlaneUrl`, or `rerankerCompatibleUrl`. - **Rationale:** Boolean names should describe the side effect, not an aspirational outcome. -### 28. `numResults` field name in two places — `model.ts:291, 367` +### 27. `numResults` field name in two places — `model.ts:291, 367` - **Why weird:** Two unrelated requests (`QueryVectorIndexRequest`, `ScanVectorIndexRequest`) both name the result-count field `numResults`. JS convention is `limit` (matching SQL `LIMIT`, REST `?limit=`) or `pageSize`. `numResults` is Python/SQL-ish. - **Category:** 14 (Python/SQL-style), 17 (cross-package inconsistency — other paged APIs use `pageSize` or `limit`). - **Suggested name:** `limit` (matches HTTP query param and most JS libs) or `pageSize`. - **Rationale:** Aligning with `limit`/`pageSize` reduces friction. -### 29. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:313` +### 28. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:313` - **Why weird:** JSDoc says: "The query type to use. Choices are `ANN` and `HYBRID` and `FULL_TEXT`. Defaults to `ANN`." Three known values, but typed as `string` — not an enum. Users get no autocomplete, no compile-time check. - **Category:** 1 (generic typing), 6 (misleading typing). - **Suggested name:** Introduce an enum `QueryType.Ann | Hybrid | FullText` (these overlap with `IndexSubtype` values but represent different concepts). - **Rationale:** `string` for a closed set of values is a known antipattern. -### 30. `RerankerConfig.model` field — generic name "model" — `model.ts:338` +### 29. `RerankerConfig.model` field — generic name "model" — `model.ts:338` - **Why weird:** Bare `model?: string` with no JSDoc. In ML SDKs "model" is overloaded (ML model, data model, type model). The field probably holds a model endpoint name or model identifier. - **Category:** 1 (generic), 15 (generic field losing meaning). - **Suggested name:** `modelEndpointName`, `modelName`, or `rerankerModel`. - **Rationale:** Document what kind of identifier this is. -### 31. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:382` +### 30. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:382` - **Why weird:** `Struct` is the SDK's wire-format for a JSON-like map, and `MapStringValueEntry` is `{key: string, value: Value}`. The TS shape is "an array of key-value entries" rather than `Record`. This is a direct port of protobuf's map-as-repeated-message-entry encoding. Idiomatic JS would use a plain object or `Map`. - **Category:** 14 (proto-style). - **Suggested name:** Flatten to `Record` at the TS boundary; keep the entry-array shape on the wire. @@ -205,81 +199,51 @@ ## Low severity -### 32. `Value` — single-word generic name for a discriminated union — `model.ts:414-423` +### 31. `Value` — single-word generic name for a discriminated union — `model.ts:414-423` - **Why weird:** A bare type called `Value` is uninformative. It is the SDK's wire-form scalar wrapper (number/string/bool/struct/list). Stronger candidates: `ScalarValue`, `WireValue`, `VectorIndexValue`. - **Category:** 1 (generic). - **Suggested name:** `ScalarValue` or move to the core wkt package and rename `wkt.Value`. - **Rationale:** `Value` collides with too many concepts. -### 33. `Struct` — generic single-word type name — `model.ts:380` +### 32. `Struct` — generic single-word type name — `model.ts:380` - **Why weird:** "Struct" is a language keyword in many languages (Go, C, Rust). In JS/TS it is a vague C-style holdover. The type is "a row of a vector index" (per the JSDoc). - **Category:** 1 (generic), 14 (C/Go/proto-style), 10 (potential reserved-word collision in TS-flow tools). - **Suggested name:** `IndexRow` or `VectorIndexRow`. - **Rationale:** A more domain-specific name is more discoverable. -### 34. `MapStringValueEntry` — verbose proto-style name — `model.ts:245` +### 33. `MapStringValueEntry` — verbose proto-style name — `model.ts:245` - **Why weird:** Reads as "Map of String to Value Entry". JSDoc says "Key-value pair." Just call it that. - **Category:** 7 (verbose), 14 (proto-style). - **Suggested name:** `KeyValue` or `StructField`. - **Rationale:** Less verbose, more idiomatic. -### 35. `ResultManifest` — Java/Spring-flavored noun — `model.ts:356-361` +### 34. `ResultManifest` — Java/Spring-flavored noun — `model.ts:356-361` - **Why weird:** "Manifest" in a query-result context is unusual JS phrasing. JSDoc says "Metadata about the result set." More common in JS: `Metadata`, `Schema`, `Info`. - **Category:** 14 (Java-style), 1 (mildly generic). - **Suggested name:** `ResultMetadata` or `ResultSchema`. - **Rationale:** Aligns with idiomatic JS. -### 36. `ResultData` — generic two-word noun — `model.ts:348-353` +### 35. `ResultData` — generic two-word noun — `model.ts:348-353` - **Why weird:** Type is "Data returned in the query result." `ResultData` is generic; `QueryResultData` or just `Rows` would be more specific. - **Category:** 1 (generic). - **Suggested name:** `QueryResultData` or `ResultRows`. - **Rationale:** Disambiguate. -### 37. `dataArray` field — generic + type-suffix tautology — `model.ts:352` -- **Why weird:** `dataArray: JsonValue[][]` — the field name says "Array", and the type is already an array. Tautology. The field is "Data rows returned in the query." -- **Category:** 20 (type-suffix tautology), 1 (generic prefix). -- **Suggested name:** `rows` or `data`. -- **Rationale:** Drop the `Array` suffix; the type already says it. - -### 38. `data` field in `ScanVectorIndexResponse` — `model.ts:375` -- **Why weird:** `data: Struct[]` — JSDoc "List of data entries". Field name `data` is the same level of generic as #36/#37. `entries`, `rows`, or `structs` would be more specific. -- **Category:** 1 (generic). -- **Suggested name:** `rows` or `entries`. -- **Rationale:** Match the JSDoc terminology. - -### 39. `lastPrimaryKey` field on request + response — `model.ts:369, 377` +### 36. `lastPrimaryKey` field on request + response — `model.ts:369, 377` - **Why weird:** Same field name used as a cursor on both request (input) and response (output). On the response it is fine ("last primary key in this page"), on the request it is a pagination cursor named after its expected source rather than its role. JS convention would be `pageToken` / `cursor` / `afterKey`. - **Category:** 17 (inconsistency with `pageToken` used elsewhere — model.ts:235, 284), 14 (database-cursor-style name). - **Suggested name:** Both could use `cursor` or `afterPrimaryKey` (request) + `lastPrimaryKey` (response). - **Rationale:** The package uses `pageToken` for pagination elsewhere; `lastPrimaryKey` is a one-off naming convention for scan. -### 40. `RerankerConfig` and `RerankerConfig_RerankerParameters` — `Reranker` × 3 — `model.ts:337, 343` -- **Why weird:** The string "Reranker" appears three times in the nested type name `RerankerConfig_RerankerParameters`. Drop the inner `Reranker` to `RerankerConfig_Parameters` or `Reranker.Parameters` (namespaced). -- **Category:** 8 (redundant suffix). -- **Suggested name:** `RerankerConfig.Parameters` (namespaced) or `RerankerParameters`. -- **Rationale:** Concision. - -### 41. `kind` field with deprecation comment `(--The kind of value.--)` — `Value.kind` — `model.ts:415` -- **Why weird:** JSDoc reads `(--The kind of value.--)` — the `(-- ... --)` markers look like an unprocessed proto comment annotation (proto3 internal-comment syntax). Visible to SDK consumers. -- **Category:** 14 (raw proto syntax leaked into TS docs). -- **Suggested name:** Strip the markers, leave plain "The kind of value." -- **Rationale:** Cosmetic but visible in editor tooltips. - ## Observation -### 42. `unmarshal*Schema` / `marshal*Schema` naming — `model.ts:461-991` -- **Why weird:** Helper schemas are named `unmarshalSchema` / `marshalSchema`. JS terms are usually `parse`/`stringify` or `decode`/`encode`. `marshal/unmarshal` is Go-style. -- **Category:** 14 (Go-style), 17 (inconsistent with JS conventions). -- **Suggested name:** `decodeSchema` / `encodeSchema`. Or accept Go-style consistently across all packages. -- **Rationale:** Cross-package decision — flagged as an observation. - -### 43. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` +### 37. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` - **Why weird:** Cross-package import. `Call` is the most generic possible name for "a network operation". - **Category:** 1 (generic), cross-package observation. - **Suggested name:** `RetryableCall`, `SdkCall`. Out of scope for this audit. - **Rationale:** Tracked for cross-package consistency. -### 44. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:29` +### 38. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:29` - **Why weird:** The mini variant (see #3, #4) is re-exported as part of the public API. If the intent is for it to be an internal implementation detail, it should not be in `index.ts`. - **Category:** Observation on the public surface. - **Suggested name:** Either rename per #3 or remove from the public surface. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 716fca22..2c139054 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -21,11 +21,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 18 | -| Medium | 22 | -| Low | 20 | -| Observation | 8 | -| **Total** | **68**| +| High | 16 | +| Medium | 18 | +| Low | 18 | +| Observation | 7 | +| **Total** | **59**| ### Top themes @@ -108,37 +108,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. - `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields `host`, `httpClient`, `logger`, `userAgent`. - `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`. -- Marshal / unmarshal schema constants (line numbers in `model.ts`): - `unmarshalCreateInstancePool_ResponseSchema` (779), - `unmarshalDeleteInstancePool_ResponseSchema` (789), - `unmarshalDiskSpecSchema` (792), - `unmarshalDiskTypeSchema` (808), - `unmarshalDockerBasicAuthSchema` (825), - `unmarshalDockerImageSchema` (835), - `unmarshalEditInstancePool_ResponseSchema` (849), - `unmarshalGetInstancePool_ResponseSchema` (853), - `unmarshalInstancePoolAndStatsSchema` (915), - `unmarshalInstancePoolAwsAttributesSchema` (977), - `unmarshalInstancePoolAzureAttributesSchema` (992), - `unmarshalInstancePoolGcpAttributesSchema` (1003), - `unmarshalInstancePoolStatsSchema` (1016), - `unmarshalInstancePoolStatusSchema` (1030), - `unmarshalListInstancePools_ResponseSchema` (1042), - `unmarshalNodeTypeFlexibilitySchema` (1053), - `unmarshalPendingInstanceErrorSchema` (1062), - `marshalCreateInstancePoolSchema` (1073), - `marshalDeleteInstancePoolSchema` (1123), - `marshalDiskSpecSchema` (1131), - `marshalDiskTypeSchema` (1147), - `marshalDockerBasicAuthSchema` (1171), - `marshalDockerImageSchema` (1181), - `marshalEditInstancePoolSchema` (1200), - `marshalInstancePoolAwsAttributesSchema` (1252), - `marshalInstancePoolAzureAttributesSchema` (1266), - `marshalInstancePoolGcpAttributesSchema` (1276), - `marshalNodeTypeFlexibilitySchema` (1288). + `readAll`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`. --- @@ -150,11 +120,9 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ----- | ----------------------------------- | -------- | ----- | | V-01 | `DockerImage.credsOneof` | High | `credsOneof` is a Go/proto-codegen leak — TS readers do not know what "Oneof" means in this context (the wire field uses a protobuf `oneof`). The "creds" abbreviation is also generic. Should be `credentials` (and the union shape itself satisfies the discriminator). | | V-02 | `PendingInstanceError.message` | Medium | `message` is generic. Could be `errorMessage` to match the type's purpose, or the type itself could be flattened. | -| V-03 | `parseResponse` (`utils.ts:113`) | Low | Local helper; OK in scope. Parses JSON specifically — `parseJsonResponse` would be more accurate. | -| V-04 | `marshalRequest` (`utils.ts:119`) | Low | Generic but local. OK. | -| V-05 | `readAll` (`utils.ts:40`) | Low | Standard name for a read-to-end helper. | -| V-06 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | -| V-07 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | +| V-03 | `readAll` (`utils.ts:40`) | Low | Standard name for a read-to-end helper. | +| V-04 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | +| V-05 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | ### 2.2 Redundant enum prefixes — High @@ -190,7 +158,6 @@ configuration, idle / used statistics, and pending-instance failure reporting. | U-09 | `InstancePoolAndStats_CustomTagsEntry` (`model.ts:629`) | High | Same as U-01. | | U-10 | `InstancePoolAndStats_DefaultTagsEntry` (`model.ts:645`) | High | Same as U-01. | | U-11 | `ListInstancePools_Response` (`model.ts:762`) | High | Same as U-01. | -| U-12 | `unmarshalCreateInstancePool_ResponseSchema` (and 4 sibling schemas) | High | Underscore cascades through every generated schema constant. | ### 2.5 Cryptic abbreviations — Medium @@ -227,12 +194,10 @@ configuration, idle / used statistics, and pending-instance failure reporting. | O-01 | `idleInstanceAutoterminationMinutes` (5-word identifier, present in 4 types) | Medium | 33-char field. Inside a type called `CreateInstancePool` etc., `idleAutoterminationMinutes` or `idleTimeoutMinutes` would be 27 / 18 chars. The wire uses `idle_instance_autotermination_minutes` so any change is generator-side. | | O-02 | `enableAutoAlternateNodeTypes` | Medium | "Enable auto alternate node types" — five concept words. With node-type-flexibility being the modern replacement, the field is also deprecated (see M-04). | | O-03 | `InstancePool*` prefix on `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`, `InstancePoolAwsAttributes`, `InstancePoolAzureAttributes`, `InstancePoolGcpAttributes`, `InstancePoolState` | High | The package is already `@databricks/sdk-instancepools`. Inside the package, the prefix is redundant. `Stats`, `Status`, `AwsAttributes` would all suffice and remove ~12 chars from each name. Compare `clusters` (`clusters.md` #75) and `apps` packages, which face the same recurring issue. | -| O-04 | `unmarshalInstancePoolGcpAttributesSchema` (40 chars) — and 7 sibling schema names | Medium | `marshal`/`unmarshal` + the verbose type-name + `Schema` triple-states intent. Repo-wide convention. | -| O-05 | `unmarshalGetInstancePool_ResponseSchema` (39 chars) | Medium | Compound proto-nesting + `Schema` suffix yields long identifiers. | -| O-06 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | -| O-07 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | -| O-08 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | -| O-09 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | +| O-04 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | +| O-05 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | +| O-06 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | +| O-07 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | ### 2.8 Singular / plural mismatches — Low / High @@ -282,10 +247,9 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `CreateInstancePool_Response`, `EditInstancePool_Response`, ... (proto-nested message style) | High | Direct port of Go `pb.CreateInstancePoolResponse`. Every occurrence requires `eslint-disable`. Repo-wide concern; flagged here. | -| G-02 | `marshal*Schema` / `unmarshal*Schema` | High | Go (and gRPC) verb pair. JS/TS code uses **serialize / deserialize** (or **encode / decode**, or **parse / stringify**). Required `import` for new TS readers to look up. | -| G-03 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | -| G-04 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | -| G-05 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | +| G-02 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | +| G-03 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | +| G-04 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | ### 2.14 Generic field names losing meaning — Medium @@ -342,7 +306,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | TS-02 | `InstancePoolStats` | Medium | `Stats` is already abbreviated; the `InstancePool` prefix is redundant inside this package. | | TS-03 | `InstancePoolStatus` | Medium | Same as TS-02. | | TS-04 | `InstancePoolState` (enum) | Medium | Same. Could be `State` or `PoolState`. | -| TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-04). Doubly off. | +| TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-03). Doubly off. | | TS-06 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | | TS-07 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-05) the type-name still echoes. | | TS-08 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | @@ -357,8 +321,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | X-04 | `client.ts:165-167` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | | X-05 | `client.ts:191` `_req: ListInstancePools` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | | X-06 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | -| X-07 | The schema constants use the same name as the type with an `unmarshal`/`marshal` prefix and `Schema` suffix — e.g., `unmarshalInstancePoolAndStatsSchema`. Constants are not assignable types but the naming mirrors them. | Observation | OK; documented as repo-wide convention. | -| X-08 | `index.ts` re-exports 28 type symbols and 6 enum symbols but **not** any of the 13 marshal/unmarshal schemas | Observation | Schemas are package-internal — good encapsulation. The `_CustomTagsEntry`/`_DefaultTagsEntry` types (8 names) *are* re-exported under proto-style underscore names. See W-01. | +| X-07 | `index.ts` re-exports 28 type symbols and 6 enum symbols. The `_CustomTagsEntry`/`_DefaultTagsEntry` types (8 names) *are* re-exported under proto-style underscore names. See W-01. | Observation | Public surface area carries the underscore-named entry types. | --- @@ -366,11 +329,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 18 | -| Medium | 22 | -| Low | 20 | -| Observation | 8 | -| **Total** | **68**| +| High | 16 | +| Medium | 18 | +| Low | 18 | +| Observation | 7 | +| **Total** | **59**| ## 4. Cross-package consistency notes diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index 05a9302a..f1adad79 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -81,12 +81,6 @@ are graded: - `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`. -- Marshal / unmarshal schemas: `unmarshalAddInstanceProfile_ResponseSchema`, - `unmarshalEditInstanceProfile_ResponseSchema`, `unmarshalInstanceProfileSchema`, - `unmarshalListInstanceProfiles_ResponseSchema`, - `unmarshalRemoveInstanceProfile_ResponseSchema`, - `marshalAddInstanceProfileSchema`, `marshalEditInstanceProfileSchema`, - `marshalRemoveInstanceProfileSchema`. --- @@ -98,10 +92,8 @@ are graded: | ----- | ----------------------------------- | -------- | ----- | | V-01 | `InstanceProfile` (interface) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | | V-02 | `AddInstanceProfile.skipValidation` | Medium | `skipValidation` is generic — *which* validation? Reading the JSDoc reveals it specifically skips the AWS `RunInstances` dry-run permission check. `skipIamValidation` or `skipPermissionDryRun` would self-document. | -| V-03 | `parseResponse` (utils) | Low | Generic name. Parses JSON specifically; `parseJsonResponse` would be more accurate. Local to the package — acceptable. | -| V-04 | `marshalRequest` (utils) | Low | Generic but local. OK. | -| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | -| V-06 | `readAll` (utils, private) | Low | Standard name for "read all bytes from a stream". OK. | +| V-03 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-04 | `readAll` (utils, private) | Low | Standard name for "read all bytes from a stream". OK. | ### 2.2 Redundant enum prefixes — N/A @@ -126,11 +118,7 @@ are graded: | U-02 | `EditInstanceProfile_Response` | High | Same as U-01. | | U-03 | `ListInstanceProfiles_Response` | High | Same as U-01. | | U-04 | `RemoveInstanceProfile_Response` | High | Same as U-01. | -| U-05 | `unmarshalAddInstanceProfile_ResponseSchema` | High | Same naming-convention violation cascades through the schema constants. | -| U-06 | `unmarshalEditInstanceProfile_ResponseSchema` | High | Same as U-05. | -| U-07 | `unmarshalListInstanceProfiles_ResponseSchema` | High | Same as U-05. | -| U-08 | `unmarshalRemoveInstanceProfile_ResponseSchema` | High | Same as U-05. | -| U-09 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | +| U-05 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | ### 2.5 Cryptic abbreviations — Medium @@ -150,10 +138,9 @@ are graded: | M-01 | `AddInstanceProfile` / `addInstanceProfile()` | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | | M-02 | `RemoveInstanceProfile` / `removeInstanceProfile()` | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | | M-03 | `EditInstanceProfile` / `editInstanceProfile()` | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | -| M-04 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | -| M-05 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | -| M-06 | `skipValidation` (`AddInstanceProfile`) | Medium | The name implies skipping *all* validation; the JSDoc clarifies it only skips the AWS dry-run permission check. See V-02. | -| M-07 | `isMetaInstanceProfile` | Medium | The boolean's semantics ("for credential passthrough scenarios where the instance profile contains a meta-IAM role that can assume a wide range of roles") is much narrower than "is this a meta instance profile". Calling it `isCredentialPassthrough` or `isMetaIamRole` would describe the actual behaviour. | +| M-04 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | +| M-05 | `skipValidation` (`AddInstanceProfile`) | Medium | The name implies skipping *all* validation; the JSDoc clarifies it only skips the AWS dry-run permission check. See V-02. | +| M-06 | `isMetaInstanceProfile` | Medium | The boolean's semantics ("for credential passthrough scenarios where the instance profile contains a meta-IAM role that can assume a wide range of roles") is much narrower than "is this a meta instance profile". Calling it `isCredentialPassthrough` or `isMetaIamRole` would describe the actual behaviour. | ### 2.7 Overly verbose / Redundant suffixes — Medium @@ -161,9 +148,8 @@ are graded: | ----- | ----------------------------------- | -------- | ----- | | O-01 | `instanceProfileArn` (in `InstanceProfile`) | Medium | Inside a type already called `InstanceProfile`, prefixing the field with `instanceProfile` is redundant — `arn` alone (or `instanceProfileArn` only on request types, with `arn` on the entity) would suffice. Tautology pattern: `instanceProfile.instanceProfileArn`. | | O-02 | `isMetaInstanceProfile` (in `InstanceProfile`) | Medium | Same tautology: `instanceProfile.isMetaInstanceProfile`. `isMeta` alone (or `isMetaRole`) would suffice within the entity. | -| O-03 | `unmarshalAddInstanceProfile_ResponseSchema` and 3 siblings | Medium | The pattern `unmarshalSchema` triple-states intent ("schema for unmarshalling X"). ~44 chars per constant; repeated across the codebase. Repo-wide convention; not local-fix territory. | -| O-04 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | -| O-05 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Inside `ListInstanceProfiles_Response`, the field `instanceProfiles` re-states the type prefix. `items` or `profiles` would suffice. Per-API codegen output. | +| O-03 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-04 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Inside `ListInstanceProfiles_Response`, the field `instanceProfiles` re-states the type prefix. `items` or `profiles` would suffice. Per-API codegen output. | ### 2.8 Singular / plural mismatches — Low @@ -207,15 +193,14 @@ revisions can add fields without breaking the type signature. Not flagged. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `AddInstanceProfile_Response` (proto nested-message style) | High | Direct port of Go's `pb.AddInstanceProfileResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `AddInstanceProfileResponse`. | -| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**) — see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON. New TS readers will look up "marshal" before they recognise it. Repo-wide convention; flagged once per package. | -| G-03 | `RemoveInstanceProfile` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | +| G-02 | `RemoveInstanceProfile` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | ### 2.14 Generic field names losing meaning — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | -| F-02 | `isMetaInstanceProfile` | Medium | Without the JSDoc, "meta instance profile" is a Databricks-internal term and conveys little. See C-03 / M-07. | +| F-02 | `isMetaInstanceProfile` | Medium | Without the JSDoc, "meta instance profile" is a Databricks-internal term and conveys little. See C-03 / M-06. | | F-03 | `skipValidation` | Medium | Without the JSDoc, unclear which validation. See V-02. | | F-04 | `instanceProfiles` (in `ListInstanceProfiles_Response`) | Low | Self-describing. Good. | | F-05 | `httpReq`, `respBody`, `body` (locals in `client.ts`) | Low | Locals only. | @@ -261,7 +246,7 @@ package is exemplary in using ARNs as identifiers.) | ----- | ----------------------------------- | -------- | ----- | | TS-01 | `InstanceProfile.instanceProfileArn` | Medium | Inside a type called `InstanceProfile`, the `instanceProfile` prefix on the field is tautological. See O-01. | | TS-02 | `InstanceProfile.isMetaInstanceProfile` | Medium | Same tautology: `isMeta` inside `InstanceProfile`. See O-02. | -| TS-03 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Field re-states the entity type that fills the array. `items` or `profiles` would suffice. See O-05. | +| TS-03 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Field re-states the entity type that fills the array. `items` or `profiles` would suffice. See O-04. | ### 2.20 Other observations @@ -273,7 +258,6 @@ package is exemplary in using ARNs as identifiers.) | X-04 | `Client` (the class name itself) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | | X-05 | `pkgJson` (import alias) | Low | Standard short alias for `package.json`. OK. | | X-06 | `PACKAGE_SEGMENT.key` derives from `pkgJson.name.replace(/^@[^/]+\//, '')` (string transform on a constant) | Low | Identifier semantics OK; observation only. | -| X-07 | Schema field `skip_validation` in `marshalAddInstanceProfileSchema` (line 147) | Low | The wire-format snake_case is correct. Note `skipValidation` doesn't appear in the `unmarshal` schema (it's a request-only flag) — also correct. | --- @@ -283,19 +267,19 @@ package is exemplary in using ARNs as identifiers.) | Severity | Count | | -------- | ----- | -| High | 15 | -| Medium | 22 | -| Low | 30 | -| **Total**| **67**| +| High | 14 | +| Medium | 19 | +| Low | 25 | +| **Total**| **58**| ### 3.2 Top themes 1. **Proto-style `_Response` suffix pollutes every response type.** Four interfaces (`AddInstanceProfile_Response`, `EditInstanceProfile_Response`, - `ListInstanceProfiles_Response`, `RemoveInstanceProfile_Response`) plus - four schema constants each require an `eslint-disable` for the naming - rule. Renaming to TS-idiomatic `AddInstanceProfileResponse` etc. would - eliminate 8 disable-comments and a Google-style violation in one sweep. + `ListInstanceProfiles_Response`, `RemoveInstanceProfile_Response`) each + require an `eslint-disable` for the naming rule. Renaming to TS-idiomatic + `AddInstanceProfileResponse` etc. would eliminate the disable-comments and + the Google-style violation in one sweep. 2. **`add` / `remove` verbs mislead about scope.** The methods **register** / **unregister** an existing AWS instance profile with Databricks — neither @@ -333,9 +317,6 @@ package is exemplary in using ARNs as identifiers.) ### 3.4 Cross-package consistency notes -- The `marshal*` / `unmarshal*` schema-naming convention is consistent with - peer packages (e.g. `clusters`, `clusterpolicies`) and is therefore a - repo-wide concern, not a per-package fix. - The proto-style `_Response` suffix is consistent with peers and should be addressed at the codegen level. - `editInstanceProfile` (vs `updateInstanceProfile`) is a per-API decision diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index cdf40af6..6d2fdb38 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -11,8 +11,8 @@ the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. | High | 37 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions. | | Medium | 87 | Underscores, redundant prefixes/suffixes, vague names, acronym casing. | | Low | 53 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 17 | Patterns spanning the entire file (proto leakage, oneof wrappers, etc.). | -| **Total** | **194** | | +| Observations | 16 | Patterns spanning the entire file (proto leakage, oneof wrappers, etc.). | +| **Total** | **193** | | Issues are catalogued below by severity, then by file/line. @@ -870,29 +870,26 @@ Issues are catalogued below by severity, then by file/line. - `client.submitRun(SubmitRun)`: verb-noun matches. - See H33. -### O10. Schema export naming -- `marshalCancelAllRunsSchema` / `unmarshalCancelAllRuns_ResponseSchema` are public; the `_Response` underscore is exposed through TS identifiers. Consider TypeScript-native names for non-wire identifiers. - -### O11. The waiters duplicate ~80 lines of code each +### O10. The waiters duplicate ~80 lines of code each - `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. - Suggestion: `RepairRunWaiter` for consistency. -### O12. `client.ts:594` declares `repair()` method (not `repairRun()`) — see H33, O9. +### O11. `client.ts:594` declares `repair()` method (not `repairRun()`) — see H33, O9. -### O13. `index.ts` re-exports both the value classes and types in two blocks +### O12. `index.ts` re-exports both the value classes and types in two blocks - Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. -### O14. `Format` and `Source` are top-level public enums named with single English words +### O13. `Format` and `Source` are top-level public enums named with single English words - These specific names collide with global and tooling identifiers — see H3, H4. -### O15. Acronym-casing rule should be documented +### O14. Acronym-casing rule should be documented - `Sql`, `Dbt`, `Jvm`, `Adls`, `Aws`, `Azure`, `Gcp`, `Gcs`, `Powerbi` (mixed), `Ml`, `Mlflow`, `Gpu`, `Lakeview`, `Dbfs`, `Ebs`, `Vm`. - The pattern is mostly "first letter of acronym capitalized only", with a few exceptions. Codify. -### O16. Wire-shape vs SDK-shape concept leakage +### O15. Wire-shape vs SDK-shape concept leakage - `numberInJob`, `originalAttemptRunId`, `Run_JobLevelParameters` are wire artifacts the TS layer should hide or rename. -### O17. Inconsistent abbreviations: `Params` vs `Parameters` +### O16. Inconsistent abbreviations: `Params` vs `Parameters` - Within the same parent type (e.g., `RunNow`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. - Standardize on `Parameters`. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 3212fae4..27096cea 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -9,14 +9,14 @@ volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and `KnowledgeSource` each carry their own proto-style nested lifecycle enum (`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). -**Total weird names flagged:** 42 +**Total weird names flagged:** 39 ## Summary | Severity | Count | | --- | --- | | High | 12 | -| Medium | 14 | -| Low | 10 | +| Medium | 12 | +| Low | 9 | | Observation | 6 | ## High severity @@ -108,7 +108,7 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ### 14. `IndexSpec.textCol` / `IndexSpec.docUriCol` cryptic abbreviation — `src/v1/model.ts:145,147` - **Why weird:** Same `Col` abbreviation as #13, plus `docUri` truncates "document URI" awkwardly. Reading `docUriCol`, your eye parses `doc-Uri-Col` — three abbreviations stacked. The doc reads "The column that specifies a link or reference to where the information came from" — a much friendlier name would be `sourceUriColumn` or `referenceColumn`. - **Category:** 5 (cryptic abbreviation), 3 (acronym casing: `Uri` vs `URI`). -- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #41). +- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #38). - **Rationale:** The savings are minimal; the readability cost is real. ### 15. `IndexSpec.indexName` type-suffix tautology — `src/v1/model.ts:143` @@ -173,19 +173,7 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** Both should use `PROCESSING` or `IN_PROGRESS` — operation-agnostic in-flight markers. If lifecycle stages matter, both should split into `CREATING` / `UPDATING` consistently. - **Rationale:** The asymmetry suggests the API team modeled the two resources separately and never unified the lifecycle vocabulary. -### 24. `unmarshalListExamplesResponseSchema` / `marshalKnowledgeSourceSchema` etc. — `*Schema` suffix is verbose — `src/v1/model.ts:377,463,539,624` -- **Why weird:** All marshal/unmarshal schemas suffix `*Schema`. The variables are Zod schemas, so the suffix is *literally* accurate — but every export reads `unmarshalKnowledgeAssistantSchema`, 32 characters. The same pattern is universal across this SDK; flagging for cross-cutting review rather than local fix. -- **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `unmarshalKnowledgeAssistant` (Zod schemas are obviously schemas; the suffix is type-system redundancy). Or namespace: `KnowledgeAssistantCodec.in` / `.out`. -- **Rationale:** Flagged as SDK-wide convention to revisit. Not a per-package fix. - -### 25. `listExamplesIter` / `listKnowledgeAssistantsIter` / `listKnowledgeSourcesIter` — `Iter` suffix Go-style — `src/v1/client.ts:338,392,446` -- **Why weird:** The `Iter` suffix on async iterators is a direct port from Go's `*Iter` convention. In TS, async iterators are first-class via `Symbol.asyncIterator`; the convention is to expose them as the *default* iteration form (`for await (const x of client.listExamples(req))` works directly if the method returns an `AsyncIterable`). The `*Iter` suffix is a Go/Java carryover. -- **Category:** 14 (Go-style name), 8 (redundant suffix — return type already says it's an iterator). -- **Suggested name:** Drop the suffix and overload on return type, or rename `listExamples` (paged) → `listExamplesPage` and `listExamplesIter` → `listExamples` (auto-paging is the default). -- **Rationale:** Modern TS APIs prefer that the default form is auto-paging. The `Iter` suffix is a code smell from the Go port. - -### 26. `Client` class name — bare, no scoping — `src/v1/client.ts:63` +### 24. `Client` class name — bare, no scoping — `src/v1/client.ts:63` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-knowledgeassistants/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as KAClient} from '@databricks/sdk-knowledgeassistants/v1'`. Other SDKs in the Databricks ecosystem name the class `KnowledgeAssistantsClient` (or `KnowledgeAssistantsApi`), avoiding the alias dance. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `KnowledgeAssistantsClient`. Sibling SDK packages (Go SDK reference uses `WorkspaceClient.KnowledgeAssistants`; AWS JS SDK uses `S3Client`, `IAMClient`) follow this pattern. @@ -193,61 +181,55 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Low severity -### 27. `KnowledgeAssistant_State.CREATING` vs `KnowledgeSource_State.UPDATING` — `src/v1/model.ts:11,19` +### 25. `KnowledgeAssistant_State.CREATING` vs `KnowledgeSource_State.UPDATING` — `src/v1/model.ts:11,19` - **Why weird:** See #23; flagged again at low severity as a *style* concern (the higher-severity finding is the verb-mismatch). - **Category:** 13 (verb tense). - **Suggested name:** See #23. - **Rationale:** Cosmetic but consistent with audit's "verb-tense inconsistency" category. -### 28. `parseResponse` / `marshalRequest` asymmetric verbs — `src/v1/utils.ts:113,119` -- **Why weird:** Same as `customllms` audit #22: `parseResponse` and `marshalRequest` use two different verbs for inverse operations. The model file uses `unmarshal*Schema` / `marshal*Schema` consistently, but `utils.ts` breaks the pattern with `parse`. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry. -- **Rationale:** Pair-wise consistency aids reading. - -### 29. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +### 26. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21. - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than one infix. -### 30. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +### 27. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` - **Why weird:** Same as `customllms.md` #23: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in the same file. Three things named `Options`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams`. - **Rationale:** Distinguish internal context bags from user-facing options. -### 31. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 28. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `customllms.md` #28: exported but not used by `client.ts`. - **Category:** Observation / 11 (unused export). - **Suggested name:** Either remove the export or document why it ships per-package. - **Rationale:** Generated artifact; flag for cross-package cleanup. -### 32. `readAll` helper generic name — `src/v1/utils.ts:40` +### 29. `readAll` helper generic name — `src/v1/utils.ts:40` - **Why weird:** Same as `customllms.md` #29: helper reads an entire response body stream; name is generic. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 33. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` +### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` - **Why weird:** Same as `customllms.md` #24: `Segment` is a generic CS term. - **Category:** 1 (vague). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** SDK-wide consistency review. -### 34. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` +### 31. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` - **Why weird:** Same as `customllms.md` #33: `resp` is the response. 12 methods repeat the same pattern. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. - **Rationale:** Refactor opportunity surfaced by audit. -### 35. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` +### 32. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` - **Why weird:** Three async generator methods each declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. Minor abbreviation inconsistency: `request` would be clearer in the iterator context, where the variable's purpose ("the request used to fetch each page") differs from the input `req`. - **Category:** 5 (abbreviation). - **Suggested name:** `pageRequest` or `nextPageReq`. - **Rationale:** Local clarity for readability. -### 36. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` +### 33. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` - **Why weird:** `knowledgeSourceFieldMaskSchema` carries top-level entries `fileTable`, `files`, `index` — matching the `$case` keys, but the wire serialization uses `file_table`/`files`/`index`. Reading the schema, a consumer might write `knowledgeSourceFieldMask('spec.files')` expecting the variant-aware path; the field-mask schema has no `spec` key at all. The discriminated union variants are flattened to top-level field-mask paths, which is correct AIP-161 (https://google.aip.dev/161) behavior — but jarring if you've read the TS type. - **Category:** 17 (inconsistency between TS shape and field-mask schema). - **Suggested name:** Not a rename; flag for documentation. @@ -255,29 +237,29 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Observations -### 37. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` +### 34. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` - **Why weird:** Doc says "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Either every `description` should carry this annotation, or none should. Flagged for cross-package style review. - **Category:** Observation. -### 38. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` +### 35. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` - **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. - **Category:** 17 (reversed — consistency note). -### 39. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +### 36. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` - **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #7, #8). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. -### 40. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` +### 37. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` - **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `APIError` usage. Cross-cutting observation from `customllms.md` #36. - **Category:** 3 (acronym casing — SDK-wide). - **Suggested name:** SDK-wide policy decision. -### 41. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +### 38. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` - **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. - **Category:** Observation. -### 42. `Example` lacks `state` field — `src/v1/model.ts:79-98` +### 39. `Example` lacks `state` field — `src/v1/model.ts:79-98` - **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. - **Category:** Observation. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index 8e000175..e57f75c1 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,7 +3,7 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 43 +**Total weird names flagged:** 42 ## Summary @@ -11,7 +11,7 @@ | ----------- | ----- | | High | 8 | | Medium | 17 | -| Low | 12 | +| Low | 11 | | Observation | 6 | ## Summary table @@ -55,13 +55,12 @@ | 35 | Low | `model.ts` field | `PublishDashboardRequest.embedCredentials` | 7 | | 36 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | | 37 | Low | `model.ts` field | `DashboardView.DASHBOARD_VIEW_BASIC` | 2, 18 | -| 38 | Low | `client.ts` methods | `listDashboardsIter`, `listSchedulesIter`, `listSubscriptionsIter` | 5 | -| 39 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | -| 40 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | -| 41 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | -| 42 | Observation | `model.ts` field | `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` | 8, 20 | -| 43 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | -| 44 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | +| 38 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | +| 39 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | +| 40 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | +| 41 | Observation | `model.ts` field | `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` | 8, 20 | +| 42 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | +| 43 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | --- @@ -693,21 +692,11 @@ Member is `DASHBOARD_VIEW_BASIC = 'DASHBOARD_VIEW_BASIC'` — both Pascal-prefix **Suggested name:** `DashboardView.BASIC = 'DASHBOARD_VIEW_BASIC'`. -### 38. `listDashboardsIter`, `listSchedulesIter`, `listSubscriptionsIter` — `Iter` is cryptic - -**Location:** `src/v1/client.ts:455,506,557` - -Same as `alerts.md` #31. `Iter` is a Go/Rust idiom for "iterator generator". In JS/TS the natural name is `*Async` or `*Stream` or `*All`. Consistency across the SDK is preferable. - -**Category:** 5 (cryptic). - -**Suggested name:** `listAllDashboards`/`listDashboardsAsync` (the existing return type is `AsyncGenerator` so `Async` is descriptive). - --- ## Observations -### 39. `Dashboard.dashboardId` — tautology at use site +### 38. `Dashboard.dashboardId` — tautology at use site **Location:** `src/v1/model.ts:95` @@ -724,7 +713,7 @@ Caller writes `dashboard.dashboardId`. Inside a type already named `Dashboard`, **Suggested name:** `Dashboard.id` (and similarly `Schedule.id`, `Subscription.id`). Marshal/unmarshal already remaps to/from `dashboard_id`. -### 40. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix +### 39. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix **Location:** `src/v1/model.ts:61,67` @@ -737,7 +726,7 @@ datasetSchema?: string | undefined; **Suggested name:** Keep. Add JSDoc clarifying "this is the Unity Catalog *catalog* / *schema* applied to dataset queries". Done already in the JSDoc, but worth flagging. -### 41. `ListSchedulesRequest.dashboardId` doc typo +### 40. `ListSchedulesRequest.dashboardId` doc typo **Location:** `src/v1/model.ts:250` @@ -750,7 +739,7 @@ dashboardId?: string | undefined; **Category:** 9 (plural verb agreement). -### 42. `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` — field name == type-tail +### 41. `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` — field name == type-tail **Location:** `src/v1/model.ts:409,414` @@ -763,7 +752,7 @@ Field name suffix `Subscriber` echoes the parent type `Subscriber`. If the paren **Category:** 8 (field name overlap with parent), 20. -### 43. `index.ts` — mixed `export {...}` and `export type {...}` +### 42. `index.ts` — mixed `export {...}` and `export type {...}` **Location:** `src/v1/index.ts:5,7-47` @@ -774,7 +763,7 @@ export type {AuthorizationDetails, ...} from './model'; Enums are exported as values (correct — they have runtime representation); interfaces are exported as types (correct — type-only). The pattern is right; flagging only because a reader scanning the index file might miss the distinction. Consistent with other SDK packages. -### 44. URL paths still use `lakeview` +### 43. URL paths still use `lakeview` **Location:** Every method's URL constant in `client.ts`, e.g. line 112: `/api/2.0/lakeview/dashboards` diff --git a/.agent/naming-audit/logdeliveryconfigurations.md b/.agent/naming-audit/logdeliveryconfigurations.md index dd76130d..525429cd 100644 --- a/.agent/naming-audit/logdeliveryconfigurations.md +++ b/.agent/naming-audit/logdeliveryconfigurations.md @@ -17,16 +17,16 @@ A log delivery configuration ties a `credentialsId` (AWS IAM role) and a endpoint by design — the API only supports disabling via the update method. -**Total weird names flagged: 36** +**Total weird names flagged: 34** ## Summary | Severity | Count | | --- | --- | | High | 7 | -| Medium | 12 | +| Medium | 11 | | Low | 10 | -| Observation | 7 | +| Observation | 6 | --- @@ -42,7 +42,7 @@ method. ### H2. `LogDeliveryStatusEnum` — type-name carries `Enum` suffix — `model.ts:39` - **File:** `model.ts:39-50`, exported in `index.ts:8`. - **Category:** 20 (type-suffix tautology), 12 (duplicate concept — two enums with overlapping prefixes). -- **Why weird:** `LogDeliveryStatusEnum` is the *only* type in the audited package (and one of the few across the workspace) whose name ends in `Enum`. Every other enum here is just `LogDeliveryConfigStatus`, `LogDeliveryType`, `LogDeliveryOutputFormat` — no suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` was already claimed by the wrapper *interface* at `model.ts:208`. The wire-side schemas use `z.enum(LogDeliveryStatusEnum)` and `z.lazy(() => unmarshalLogDeliveryStatusSchema)` — the cognitive load of remembering which is enum, which is interface, and which is `Schema` is high. +- **Why weird:** `LogDeliveryStatusEnum` is the *only* type in the audited package (and one of the few across the workspace) whose name ends in `Enum`. Every other enum here is just `LogDeliveryConfigStatus`, `LogDeliveryType`, `LogDeliveryOutputFormat` — no suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` was already claimed by the wrapper *interface* at `model.ts:208`. - **Suggested name:** Rename the wrapper interface to `LogDeliveryAttempt` (it actually holds attempt fields: `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, `status`), freeing `LogDeliveryStatus` for the enum. Alternatively, rename the enum to `LogDeliveryAttemptStatus` (drops `Enum`, matches the fields it describes). - **Rationale:** A field typed `attempt.status: LogDeliveryAttemptStatus` reads better than `logDeliveryStatus.status: LogDeliveryStatusEnum`. The `Enum` suffix is type-suffix tautology and is unique to this one type — a clear smell that the underlying noun is overloaded. @@ -85,25 +85,25 @@ method. - **Suggested name:** Rename "of customer" away (`The unique UUID of the log delivery configuration to fetch`). Drop `| undefined` on `configId` — it is required. `accountId` is fine as optional only if the client falls back to `ClientOptions.accountId` (which it does at `client.ts:126`); document that explicitly. - **Rationale:** The current design type-checks fine but blows up at runtime with an unintuitive URL. Required path params should be required types. The "of customer" prose is generator-emitted boilerplate worth removing. -### H7. `unmarshal*_ResponseSchema` and `marshal*Schema` — underscore in TS identifiers — `model.ts:243,255,267,332` -- **File:** `model.ts:243,255,267,332` (also interface names `CreateLogDeliveryConfiguration_Response` at `model.ts:72`, `GetLogDeliveryConfiguration_Response` at `model.ts:132`, `ListLogDeliveryConfiguration_Response` at `model.ts:158`, `UpdateLogDeliveryConfiguration_Response` at `model.ts:240`). +### H7. Underscore in TS identifiers on nested `_Response` types — `model.ts:72,132,158,240` +- **File:** `model.ts:72` (`CreateLogDeliveryConfiguration_Response`), `model.ts:132` (`GetLogDeliveryConfiguration_Response`), `model.ts:158` (`ListLogDeliveryConfiguration_Response`), `model.ts:240` (`UpdateLogDeliveryConfiguration_Response`). - **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names — these are protobuf `Nested.Response` messages). - **Why weird:** TypeScript convention is PascalCase / camelCase — no underscores. The generator emits `CreateLogDeliveryConfiguration_Response` because the wire proto has `message CreateLogDeliveryConfiguration { message Response {...} }`. Every offending type carries an eslint-disable comment (`// eslint-disable-next-line @typescript-eslint/naming-convention`). This is the same generator-level concern flagged in every prior audit, here amplified because every response type is underscored. -- **Suggested name:** Flatten the nested message: `CreateLogDeliveryConfigurationResponse` (no underscore). Same for `Get*Response`, `List*Response`, `Update*Response` and their schemas. +- **Suggested name:** Flatten the nested message: `CreateLogDeliveryConfigurationResponse` (no underscore). Same for `Get*Response`, `List*Response`, `Update*Response`. - **Rationale:** Fix at generator level — applies to every package. The eslint-disable suppression is itself a clue that the generator is fighting the TS convention rather than respecting it. --- ## Medium severity -### M10. `Client` class is unprefixed — `client.ts:46` +### M8. `Client` class is unprefixed — `client.ts:46` - **File:** `client.ts:46`, exported at `index.ts:3`. - **Category:** 1 (vague), 12 (duplicate concept across packages — every Databricks SDK package exports its own `Client`). - **Why weird:** A user importing this package writes `import {Client} from '@databricks/sdk-logdeliveryconfigurations/v1'` and immediately must alias (`import {Client as LogDeliveryClient}`) to compose multiple Databricks clients. Consistent across the SDK but worth flagging. - **Suggested name:** `LogDeliveryClient` or `LogDeliveryConfigurationsClient`. Or expose only a namespace (`import * as logDelivery from '@databricks/sdk-logdeliveryconfigurations/v1'` then `logDelivery.Client`). - **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. Same finding as `billableusagedownload` audit #8. -### M11. Client method names embed the noun three times — `client.ts:90,122,150,214` +### M9. Client method names embed the noun three times — `client.ts:90,122,150,214` - **File:** `client.ts:90,122,150,192,214`. - **Category:** 7 (overly verbose), 17 (inconsistent action verbs vs sibling packages). - **Why weird:** `client.createLogDeliveryConfiguration(...)` is 27 characters. With the package prefix and the request type, a single call line reads: @@ -112,30 +112,30 @@ method. ``` That is "logDeliveryConfiguration" repeated three times in one expression. The Go SDK uses short method names (`Create`, `Get`, `List`, `PatchStatus`) because the noun comes from the receiver type. The TS port replicates the full noun. Sibling packages like `billableusagedownload.Client.download()` and `accountsettings.Client.disableLegacyFeatures()` use shorter names. - **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.listIter()`, `client.updateStatus()`. The receiver type (`LogDeliveryClient`) already provides the noun. -- **Rationale:** TS method names should not repeat the type they live on. Once `Client` is renamed `LogDeliveryClient` (M10), the shorter forms are unambiguous. Note that the Go SDK uses `PatchStatus` (the actual HTTP verb is `PATCH`) — the TS `updateLogDeliveryConfiguration` is already a paraphrase, so consistency with Go is partly already lost. +- **Rationale:** TS method names should not repeat the type they live on. Once `Client` is renamed `LogDeliveryClient` (M8), the shorter forms are unambiguous. Note that the Go SDK uses `PatchStatus` (the actual HTTP verb is `PATCH`) — the TS `updateLogDeliveryConfiguration` is already a paraphrase, so consistency with Go is partly already lost. -### M12. `updateLogDeliveryConfiguration` does not actually "update" — it only patches status — `client.ts:209-243` +### M10. `updateLogDeliveryConfiguration` does not actually "update" — it only patches status — `client.ts:209-243` - **File:** `client.ts:209-243`, `UpdateLogDeliveryConfiguration` at `model.ts:230`. - **Category:** 6 (misleading), 17 (inconsistent verb — Go uses `PatchStatus`, TS uses `update`). - **Why weird:** The method name `updateLogDeliveryConfiguration` suggests "update arbitrary fields of the config". In reality the request body only contains `configId`, `accountId`, and `status` (see `UpdateLogDeliveryConfiguration` interface at `model.ts:230-237`) — you can only flip ENABLED <-> DISABLED. The JSDoc on the method (`client.ts:209-212`) calls it out: "Enables or disables a log delivery configuration." The Go SDK method is named `PatchStatus`, which is honest. - **Suggested name:** `patchStatus`, or `setStatus`, or `updateStatus`. The current name oversells the surface. - **Rationale:** "Update" implies multi-field mutation. If a caller writes `client.updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new-prefix'})` they will be silently surprised — the `deliveryPathPrefix` is not part of the request DTO so it will not type-check (in TS strict mode), but they would have to read the type to learn that. The verb is a footgun. -### M13. `listLogDeliveryConfigurationIter` — singular noun on a method returning multiple — `client.ts:192` -- **File:** `client.ts:192`. -- **Category:** 9 (singular/plural mismatch), 1 (vague — `Iter` suffix is opaque). -- **Why weird:** `listLogDeliveryConfigurationIter` is singular ("Configuration") but the iterator yields multiple configurations one by one (returns `AsyncGenerator`). Sibling packages use `list*sIter` (plural) — e.g., `listBudgetConfigurationsIter` in `budgets/src/v1/client.ts`. Also, `Iter` is an unhelpful abbreviation — TS users expect `AsyncIterable` or `streamAll` or `pageThrough`. -- **Suggested name:** `iterateLogDeliveryConfigurations` (plural noun, verb-prefix); or simply `listAll` (clean, returns generator). -- **Rationale:** Adjacent package `budgets` uses `listBudgetConfigurationsIter` (plural). Within this package, the non-iterator `listLogDeliveryConfiguration` is also singular but returns a `*Response` whose body field is `logDeliveryConfigurations` (plural — `model.ts:160`). The singular method name fights the plural data shape. +### M11. `listLogDeliveryConfiguration` — singular noun on a method returning multiple — `client.ts:150,192` +- **File:** `client.ts:150,192`. +- **Category:** 9 (singular/plural mismatch). +- **Why weird:** `listLogDeliveryConfiguration` is singular ("Configuration") but the method yields multiple configurations (the response body field is `logDeliveryConfigurations` — plural — at `model.ts:160`). Sibling packages use plural — e.g., `listBudgetConfigurations` in `budgets/src/v1/client.ts`. The singular method name fights the plural data shape. +- **Suggested name:** `listLogDeliveryConfigurations` (plural noun). +- **Rationale:** Adjacent package `budgets` uses `listBudgetConfigurations` (plural). Within this package, the response body field is plural while the method name is singular — pluralisation should match the collection it returns. -### M14. `ListLogDeliveryConfiguration` (request type) is singular — `model.ts:141` +### M12. `ListLogDeliveryConfiguration` (request type) is singular — `model.ts:141` - **File:** `model.ts:141-155`. - **Category:** 9 (singular/plural mismatch). -- **Why weird:** Same issue as M13 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. +- **Why weird:** Same issue as M11 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. - **Suggested name:** `ListLogDeliveryConfigurationsRequest` (plural + `Request` suffix for clarity). - **Rationale:** Naming should match data shape. Pluralisation is the standard signal that a method returns a collection. Cross-package inconsistency. -### M15. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:117,205,217` +### M13. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:117,205,217` - **File:** `model.ts:117,205` (field `logDeliveryStatus: LogDeliveryStatus`), `model.ts:208` (interface `LogDeliveryStatus`), `model.ts:217` (`status?: LogDeliveryStatusEnum`). - **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). - **Why weird:** A reader looking at `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types: @@ -146,116 +146,109 @@ method. - **Suggested name:** Field: `lastAttempt: LogDeliveryAttempt`. Wrapper type: `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message` — drop `last` prefix once nested). Enum: `LogDeliveryAttemptStatus`. Result reads as `config.lastAttempt.status === 'SUCCEEDED'`. - **Rationale:** "Status" is too generic to triple-stack. Renaming the wrapper to "Attempt" (its actual semantics) breaks the conflation cleanly. -### M16. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:113-115,201-203` +### M14. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:113-115,201-203` - **File:** `model.ts:113-115,201-203`. - **Category:** 13 (verb-tense inconsistency — `creation` is a noun, `update` is a verb), 6 (misleading — `number` type with JSDoc "epoch milliseconds"). - **Why weird:** `creationTime: number` and `updateTime: number`. The first is noun-form ("creation"), the second is verb-form ("update"). Pair-wise they should match: `createdTime`/`updatedTime` (past participle) or `creationTime`/`updateTime` (noun). Also, both are `number` (epoch ms) but neither type signals "this is a unix timestamp in milliseconds"; the JSDoc carries that information. Across the SDK, audited packages have flagged similar issues. - **Suggested name:** `createdAt: number` / `updatedAt: number` (canonical SaaS convention — Stripe/GitHub/Salesforce/Atlassian all use *At). Brand the type as `EpochMillis` for compile-time safety. - **Rationale:** "*At" is the industry standard for timestamps. Same finding in many other audited packages (`budgets`, `apps`, etc.) — fix at generator level. -### M17. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:109,197` +### M15. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:109,197` - **File:** `model.ts:108-109,196-197`. - **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" sounds like a timestamp). - **Why weird:** The field is `string`, but the JSDoc says "specified in YYYY-MM format". That is a year-month string, not a time. Compare with `creationTime: number` (which is an epoch-ms timestamp). The same word "Time" is used for two different formats. A `string` for "YYYY-MM" should be branded or use a `Temporal.YearMonth` from `@js-temporal/polyfill` (already a dependency at `package.json:23`). - **Suggested name:** `deliveryStartMonth` (clarifies granularity), typed `Temporal.PlainYearMonth | string`. - **Rationale:** "Time" implies high-resolution. The domain is monthly billing buckets, so "Month" is the right granularity. Same convention as `Stripe.Invoice.period_start` (epoch) vs `Stripe.UsageRecord.period.start` (date-only). -### M18. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:105,193` +### M16. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:105,193` - **File:** `model.ts:104-105,192-193`. - **Category:** 7 (overly verbose), 9 (singular/plural mix), 15 (generic suffix). - **Why weird:** The field is `workspaceIdsFilter: number[]`. The plural `Ids` says "this is a list of IDs". The `Filter` suffix says "this is a filter". A `number[]` already conveys "list of ints". Calling it `workspaceIdsFilter` adds redundant `Filter` noise; calling it just `workspaceIds` (the actual content) would be clearer. Compare with `ListLogDeliveryConfiguration.credentialsId: string` (singular, no `Filter` suffix at `model.ts:145`) which serves the same conceptual role. - **Suggested name:** `workspaceIds: number[]` (drop `Filter`). Or `filterByWorkspaceIds` if intent must be made explicit. - **Rationale:** Type-driven inference: a `number[]` named after the entity is unambiguous. `Filter` is generic ceremony. -### M19. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:105,193` +### M17. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:105,193` - **File:** `model.ts:104-105,192-193`. - **Category:** 6 (misleading), 19 (underspecified ID). - **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double precision float — only safe up to 2^53 - 1. Databricks workspace IDs are int64 server-side; sending an ID greater than 2^53 will silently lose precision in the JSON wire. The TS type should be `bigint[]` or `(number | bigint)[]` or branded. - **Suggested name:** `workspaceIds: bigint[]` (matches the int64 wire). Or `workspaceIds: WorkspaceId[]` with a branded `type WorkspaceId = number & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package issue. Same finding will recur on every `*Id: number` field that maps to an int64 wire. Fix at generator level: emit `bigint` for `int64`. -### M20. `host` field on `Client` lacks domain context — `client.ts:47` +### M18. `host` field on `Client` lacks domain context — `client.ts:47` - **File:** `client.ts:47,62`. - **Category:** 1 (vague), 15 (generic field name). - **Why weird:** `private readonly host: string` — without context, `host` could be any URL or hostname. The setter at line 62 trims trailing slash. The semantically correct name is `databricksHost` or `workspaceUrl` or `baseUrl` (the actual content is `https://.../`, not just a hostname like `example.com`). - **Suggested name:** `baseUrl` (matches the actual content — a URL including scheme). - **Rationale:** Same pattern across every package's `Client`. Fix at generator. Same finding as `billableusagedownload` audit #?. -### M21. `parseResponse` / `marshalRequest` verb asymmetry — `utils.ts:113,119` -- **File:** `utils.ts:113-117` (`parseResponse`), `utils.ts:119-121` (`marshalRequest`). -- **Category:** 17 (inconsistent action verbs). -- **Why weird:** `parseResponse` (the inverse of `marshalRequest`) uses `parse`; the request side uses `marshal`. The verbs do not pair — they read as different layers. Pair would be `unmarshalResponse`/`marshalRequest` or `parseResponse`/`serializeRequest`. -- **Suggested name:** `unmarshalResponse`/`marshalRequest` (already the verb used on the schema names: `unmarshal*Schema` / `marshal*Schema`). -- **Rationale:** The schemas are already named `unmarshal*Schema`/`marshal*Schema` (lines 243, 280, 335). The utility functions should match. - --- ## Low severity -### L22. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` +### L19. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` - **File:** `model.ts:56-61`. - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered. They should match — either `BILLABLE_USAGE_LOGS` / `AUDIT_LOGS` (both plural) or `BILLABLE_USAGE` / `AUDIT` (both singular). - **Suggested name:** `BILLABLE_USAGE` / `AUDIT` (drop the `_LOGS` — the enum is `LogDeliveryType` so "logs" is implied). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the type name) is cleaner. -### L23. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` +### L20. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` - **File:** `model.ts:23-28`. - **Category:** 3 (acronym casing — fine here since it matches the wire), Observation. - **Why weird:** Two-value enum where `log_type === 'BILLABLE_USAGE'` forces `output_format === 'CSV'` and `log_type === 'AUDIT_LOGS'` forces `'JSON'` (see JSDoc on `outputFormat` at `model.ts:93-96`). The field is therefore *always* derivable from `logType` — making it a redundant field, not a redundant enum, but worth flagging. - **Suggested name:** Drop `outputFormat` from the request DTO (it can be derived server-side). Keep on the response DTO for clarity. - **Rationale:** Not strictly a naming issue, but reduces API surface area. -### L24. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` +### L21. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` - **File:** `model.ts:13-16`. - **Category:** 1 (vague). - **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the doc says exactly what the name says. JSDoc should add information, not echo identifiers. - **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured S3 bucket." - **Rationale:** Cross-cutting generator concern. -### L25. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` +### L22. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` - **File:** `model.ts:48-49`. - **Category:** 6 (misleading). - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc says it actually means "configuration has been disabled since the release of this feature or there are no workspaces in the account". That's not "not found"; it's "no logs to deliver because account state". - **Suggested name:** `NO_DATA` or `NOT_APPLICABLE` or `DISABLED_AT_RELEASE` — anything that doesn't sound like a 404. - **Rationale:** API value names should not collide with HTTP semantics that mean something different. A monitoring dashboard surfacing `status === 'NOT_FOUND'` will mislead an operator into thinking the config was deleted. -### L26. `PACKAGE_SEGMENT` constant — `client.ts:41` +### L23. `PACKAGE_SEGMENT` constant — `client.ts:41` - **File:** `client.ts:41-44`. - **Category:** 1 (vague), 15 (generic). - **Why weird:** `Segment` is a generic CS term. The comment "Package identity segment for this client to be used in the User-Agent header" (`client.ts:40`) is the disambiguator; without it the constant name does not communicate what it is. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency — same finding in every audited package. Worth normalising at generator level. Same as `billableusagedownload` audit #10. -### L27. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` +### L24. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` - **File:** `client.ts:51,72`. - **Category:** 20 (type-suffix tautology). - **Why weird:** Field name and type both end in `Client`. Convention is widespread but flagged per rule 20. - **Suggested name:** `transport: HttpClient` (matches the imported package `@databricks/sdk-databricks/transport`). - **Rationale:** `transport` is what HTTP layers are usually named in language-agnostic SDK terminology (gRPC, GraphQL clients, etc.). It avoids the `Client/Client` echo. Tolerable as-is. -### L28. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` +### L25. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` - **File:** `client.ts:91,99,103,...` (every method). - **Category:** 5 (cryptic abbreviation). - **Why weird:** Three-letter abbreviations for parameter and local names. The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling out costs nothing and improves readability. Same finding across every audit. -### L29. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` +### L26. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` - **File:** `client.ts:196`. - **Category:** 5 (cryptic), 1 (vague — `pageReq` is shorthand for "request for next page"). - **Why weird:** Variable holds the *modified* request for each page (with `pageToken` updated). `pageReq` reads as "page request" — a noun describing the page itself. - **Suggested name:** `currentRequest` or `paginatedRequest`. Or unify with `request` if you adopt option-bag style. - **Rationale:** Low; loop-local variable. -### L30. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` +### L27. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` - **File:** `utils.ts:26-38,65-94`. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Why weird:** Two functions named almost identically doing very different things. `executeCall` wraps the call in retry/rate-limit; `executeHttpCall` does the raw HTTP send + decode + APIError. Within the same file the naming distinction is too subtle. - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `dispatchHttp`). Or just `wrapRetry` / `sendHttp`. - **Rationale:** Same finding as `billableusagedownload` audit #13. Cross-package generator concern. -### L31. `HttpCallOptions` — `utils.ts:15` +### L28. `HttpCallOptions` — `utils.ts:15` - **File:** `utils.ts:15-19`. - **Category:** 1 (vague suffix `Options`), 12 (duplicate `Options` naming). - **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` from `@databricks/sdk-core/api` imported at line 3). The local interface shadows the imported one cognitively. The field is not user-facing — it is an internal bag. @@ -266,25 +259,21 @@ method. ## Observations -### O32. `flattenQueryParams` is exported but unused — `utils.ts:123` +### O29. `flattenQueryParams` is exported but unused — `utils.ts:123` `client.ts` does its own query-param construction inline (lines 155-167) using `new URLSearchParams()` and four `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called by this package. This is a generator artefact — every generated package ships this helper. -### O33. `parseResponse` is unused — `utils.ts:113` +### O30. `parseResponse` is unused — `utils.ts:113` Actually, `parseResponse` *is* used (4 call sites in `client.ts:109,137,180,233`). Not dead. Correction to prior packages' findings: in `logdeliveryconfigurations`, parseResponse is actively in use. -### O34. `marshalRequest` is used twice — `client.ts:95,219` +### O31. `marshalRequest` is used twice — `client.ts:95,219` Used for `createLogDeliveryConfiguration` and `updateLogDeliveryConfiguration`. Not dead. -### O35. `accountId` URL fallback — `client.ts:94,126,154,218` +### O32. `accountId` URL fallback — `client.ts:94,126,154,218` `createLogDeliveryConfiguration` (line 94) reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client fallback!), while the other three methods do `req.accountId ?? this.accountId ?? ''`. The create path silently differs — if `ClientOptions.accountId` is set but the caller forgets to put it inside `logDeliveryConfiguration`, the URL becomes `/api/2.0/accounts//log-delivery`. This is a correctness bug surfaced by a naming/structure inconsistency: the request DTO nests the account ID one level deeper than the others. - **Category:** 6 (misleading), 16 (field placement contradicts wire-level convention). - **Suggested fix:** Make `req.accountId ?? this.accountId ?? ''` consistent across all four methods (the create path should reach the top-level `accountId` and the client-options fallback, not just the nested wrapper field). -### O36. `marshalCreateLogDeliveryConfigurationSchema` typed as bare `z.ZodType` (not parameterised) — `model.ts:335,345,379,393` -None of the four marshal schemas carry a type parameter: `z.ZodType` instead of `z.ZodType`. The unmarshal schemas *are* parameterised (`z.ZodType` at line 280, etc.). The asymmetry is invisible to callers but means `marshal*Schema.parse(input)` returns `unknown` rather than a known type. Generator concern. -- **Category:** 6 (misleading — type appears typed but is in fact `any`-equivalent). - -### O37. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,32,53,64,77,120,137,165,225` +### O33. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,32,53,64,77,120,137,165,225` Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the first line (e.g., line 6: ``` * * @@ -292,15 +281,15 @@ Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the fir ``` ). Looks like the generator emits an empty paragraph break that renders as `*`. Also, `` appears in raw form throughout (e.g., `model.ts:98,127,142,186`); it should be a literal "Databricks" or substituted at generation time. Neither is a name issue per se but both pollute the docs. -### O38. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` -The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O35). The naming of `accountId` as "optional" in the type lies about the runtime requirement. +### O34. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` +The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O32). The naming of `accountId` as "optional" in the type lies about the runtime requirement. --- ## Domain glossary - **`account`** — Databricks account; the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) in every interface and as `ClientOptions.accountId` (`client.ts:50,63`). -- **`workspace`** — A Databricks workspace under an account; `int64` ID on the wire (lossy as `number` in TS — see M19). +- **`workspace`** — A Databricks workspace under an account; `int64` ID on the wire (lossy as `number` in TS — see M17). - **`credentials`** — Refers to `Credentials.Create` (cross-package) — a stored AWS IAM role with policy/trust relationship. The `credentialsId` field (`model.ts:101,189`) links a log delivery config to a previously-created credentials resource. - **`storage configuration`** — Refers to `Storage.Create` (cross-package) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:103,191`) links a log delivery config to a bucket. - **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` that tells Databricks to write certain logs to a bucket. @@ -311,8 +300,8 @@ The constructor throws if `options.host` is undefined (`client.ts:59-61`) but ha - **`config status`** — `ENABLED` / `DISABLED`. The config is never deleted — only disabled (see `client.ts:88,211`). - **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND`. Reflects the state of the most recent delivery attempt; surfaced as `LogDeliveryStatus.status` (i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`). - **`E2`** — Databricks deployment architecture (newer multi-region account model). Mentioned in `UpdateLogDeliveryConfiguration.accountId` JSDoc (`model.ts:233`). -- **`int64`** — Wire-level 64-bit signed integer; appears in `workspaceIdsFilter` JSDoc but typed `number` in TS (M19). -- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`); the Go SDK calls this method `PatchStatus`, the TS port renames it `updateLogDeliveryConfiguration` (M12). +- **`int64`** — Wire-level 64-bit signed integer; appears in `workspaceIdsFilter` JSDoc but typed `number` in TS (M17). +- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`); the Go SDK calls this method `PatchStatus`, the TS port renames it `updateLogDeliveryConfiguration` (M10). --- diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index e0aff49e..cdce3803 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,15 +3,15 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 65 +**Total weird names flagged:** 62 ## Summary | Severity | Count | | --- | --- | | High | 16 | | Medium | 32 | -| Low | 10 | -| Observation | 7 | +| Low | 8 | +| Observation | 6 | The marketplaces package is one of the more naming-distressed surfaces in the SDK. The single dominant problem is the proto-style `MessageType_Response` underscore-suffixed identifier pattern — present on 14 of the 24 request types and infecting `client.ts`, `index.ts`, and every transitive importer with `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. Closely behind it is the **inconsistent request-type convention** within a single file: some request types follow the verb-shaped Go style (`CreateFile`, `DeleteFile`, `GetListing`, `GetListings`, `UpdateListing`, `ListFiles`, `CreateProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders`, `CreateProviderAnalyticsDashboard`, `UpdateProviderAnalyticsDashboard`, `GetLatestVersionProviderAnalyticsDashboard`, `ListProviderAnalyticsDashboard`, `GetPersonalizationRequestsForProvider`, `UpdatePersonalizationRequestStatus`) while others follow the more idiomatic `*Request`/`*Response` suffix (`CreateExchangeRequest`, `DeleteExchangeRequest`, `GetExchangeRequest`, `UpdateExchangeRequest`, `ListExchangesRequest`, `CreateExchangeFilterRequest`, `DeleteExchangeFilterRequest`, `UpdateExchangeFilterRequest`, `ListExchangeFiltersRequest`, `AddExchangeForListingRequest`, `RemoveExchangeForListingRequest`, `ListExchangesForListingRequest`, `ListListingsForExchangeRequest`) — split almost perfectly down the provider/exchange axis but not advertised that way. Other notable issues are the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListings` request and `GetListings_Response` payload field both use `listings`, while `CreateListing` and `DeleteListing` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service", `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` exposing an internal commit-drawdown workflow with a 33-character enum value, and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). @@ -943,36 +943,7 @@ providerRegion?: RegionInfo | undefined; ## Low severity -### 49. `unmarshal*Schema` / `marshal*Schema` exports — `Schema` suffix tautology - -**Location:** `src/v1/model.ts:679, 690, 704, 713, 723, 735, 745, 755, 764, 774, 777, 781, 785, 789, 792, 818, 842, 862, 888, 898, 908, 917, 927, 937, 949, 963, 972, 983, 996, 1008, 1019, 1033, 1047, 1058, 1070, 1118, 1126, 1170, 1180, 1219, 1253, 1263, 1266, 1274, 1284, 1293, 1302, 1313, 1323, 1333, 1346, 1356, 1364, 1372, 1386, 1394, 1402, 1405, 1415, 1441, 1465, 1485, 1511, 1521, 1533, 1581, 1589, 1633, 1643, 1677, 1687, 1695, 1705, 1715, 1725, 1735, 1751, 1761` - -```ts -export const unmarshalContactInfoSchema: z.ZodType = ... -export const unmarshalCreateExchangeFilterResponseSchema: ... -export const marshalProviderInfoSchema: z.ZodType = ... -``` - -~78 exports. Every name combines `marshal|unmarshal` + the type name + `Schema`. The `Schema` suffix is redundant — the `z.ZodType` type annotation already says it's a Zod schema. -- **Category:** 8 (redundant `Schema` suffix), 7 (overly verbose). -- **Suggested name:** Drop `Schema` suffix: `unmarshalContactInfo`, `marshalProviderInfo`, etc. -- **Rationale:** Cross-package consistency / verbosity. - -### 50. `unmarshal*_ResponseSchema` — proto-underscore + Schema-suffix combo - -**Location:** `src/v1/model.ts:723, 735, 745, 755, 781, 785, 789, 908, 917, 927, 937, 949, 963, 1008, 1033, 1047, 1302, 1313, 1323, 1333` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export const unmarshalCreateFile_ResponseSchema: z.ZodType = ... -``` - -Same as #1 but for the schema exports — 14 schemas embed the proto underscore plus the redundant `Schema` suffix. Each requires its own `// eslint-disable-next-line` comment. -- **Category:** 4 (underscore), 8 (Schema suffix), 14 (proto/Go-style names). -- **Suggested name:** `unmarshalCreateFileResponse`, etc. -- **Rationale:** Cascades from #1 and #49. - -### 51. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization +### 49. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization **Location:** `src/v1/model.ts:457, 467, 533` @@ -981,14 +952,14 @@ Mixed singular/plural id fields: - `ListingDetail.fileIds: string[]` — many file ids. - `ListingSummary.exchangeIds: string[]` — many exchange ids. - `ListingSummary.providerId: string` — single provider id. -- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #52). +- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #50). Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #52). +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #50). - **Suggested name:** Pick one — `*Id`/`*Ids` is standard. - **Rationale:** Observation; flagged for completeness. -### 52. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number +### 50. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number **Location:** `src/v1/model.ts:530-531` @@ -1002,7 +973,7 @@ User ids are typed as `number`. JS `number` only safely represents integers up t - **Suggested name:** `createdById: string` or `bigint`. - **Rationale:** Lossy representation; consistency with other id fields (all `string`). -### 53. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` +### 51. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` **Location:** `src/v1/model.ts:136-139` @@ -1018,7 +989,7 @@ Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal ty - **Suggested name:** Could be `'public' | 'private'` literal union. - **Rationale:** Observation. -### 54. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun +### 52. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun **Location:** `src/v1/model.ts:90-93` @@ -1034,7 +1005,7 @@ export enum ListingShareType { - **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). - **Rationale:** Internal consistency. -### 55. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values +### 53. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values **Location:** `src/v1/model.ts:109-112` @@ -1050,7 +1021,7 @@ Two adjective values. Fine. Flagged because the package also has `Personalizatio - **Suggested name:** No rename. - **Rationale:** Internal consistency check. -### 56. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located +### 54. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located **Location:** `src/v1/model.ts:572, 580` @@ -1065,7 +1036,7 @@ Same icon represented two ways — `iconFilePath` (a URL or storage path) and `i - **Suggested name:** No rename; flag for doc clarification. - **Rationale:** Observation. -### 57. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode +### 55. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode **Location:** `src/v1/model.ts:583-584` @@ -1079,7 +1050,7 @@ The `darkMode` prefix encodes a UI rendering mode in a server-side data type. Th - **Suggested name:** `iconDarkFileId` / `iconDarkFilePath` or just `darkIcon*`. - **Rationale:** Observation. -### 58. Method docstring inconsistency — `client.ts` +### 56. Method docstring inconsistency — `client.ts` **Location:** `src/v1/client.ts:178, 207, 232, 261, 287, 313, 339, 371, 396, 424, 449, 474, 499, 524, 549, 577, 602, 656, 713, 738, 795, 846, 903, 961, 1018, 1046, 1097, 1125, 1151, 1180, 1206, 1238, 1264` @@ -1106,29 +1077,25 @@ Inconsistent docstring style: ## Observations -### 59. v1-only audit +### 57. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 60. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:147` +### 58. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:147` Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. - **Category:** 1 (vague), 15 (generic name). -### 61. `flattenQueryParams` — `src/v1/utils.ts:123` +### 59. `flattenQueryParams` — `src/v1/utils.ts:123` The helper is used by `client.ts:911-915` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. - **Category:** Observation. -### 62. `readAll` — `src/v1/utils.ts:40` +### 60. `readAll` — `src/v1/utils.ts:40` Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. - **Category:** 1 (vague), 14 (Go-style name). -### 63. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113, 119` -`parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within one file. The model file uses `marshal*` / `unmarshal*` consistently — `parseResponse` is the odd one out. -- **Category:** 17 (inconsistent action verbs). - -### 64. `HttpCallOptions` — `src/v1/utils.ts:15` +### 61. `HttpCallOptions` — `src/v1/utils.ts:15` Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. - **Category:** 1 (vague suffix), 17 (inconsistent). -### 65. Exported but not in `index.ts` +### 62. Exported but not in `index.ts` `index.ts` exports types but not the `*_Response` schemas, marshal/unmarshal functions, or the `*_Response` types fully (note: `CreateFile_Response` is exported via `index.ts:32` — so the underscore wart reaches the public surface). The fact that consumers do see the underscore form via the index export means every change to remove the underscore would be a breaking change. - **Category:** Observation. diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md index 3d22bba4..2949398f 100644 --- a/.agent/naming-audit/materializedfeatures.md +++ b/.agent/naming-audit/materializedfeatures.md @@ -155,9 +155,7 @@ disambiguation is needed: - `FeatureLineage_OnlineFeature` → `FeatureLineageOnlineFeature` (or `LineageOnlineFeature`, or `OnlineFeatureRef`). -This is a generator-level fix coordinated SDK-wide. The unmarshal helpers -inherit the same underscore (`unmarshalFeatureLineage_ModelSchema`, etc.), -which compounds the issue. +This is a generator-level fix coordinated SDK-wide. --- @@ -373,18 +371,7 @@ Pass on naming, **fix the JSDoc** ("Response message for ListFeatureTags."). --- -### 12. `ListFeatureTagsRequest` and `Response` could be `ListRequest`/`ListResponse` — category 7 (Overly verbose) — *pass* - -**Symbols:** `ListFeatureTagsRequest` (model.ts:76), `ListFeatureTagsResponse` -(model.ts:86). - -**Issue:** Names are long (21/22 chars) but match the SDK-wide pattern for -paginated list endpoints. Within this package only `FeatureTag` is listable, -so `ListRequest` would suffice — but uniformity across packages wins. **Pass.** - ---- - -### 13. `UpdateFeatureTagRequest.featureTag.key` is also the path key — category 16 (Field contradicting type domain) and category 19 (Underspecified IDs) +### 12. `UpdateFeatureTagRequest.featureTag.key` is also the path key — category 16 (Field contradicting type domain) and category 19 (Underspecified IDs) **Symbol:** `UpdateFeatureTagRequest.featureTag` (model.ts:96) + `client.updateFeatureTag` URL builder (client.ts:220). @@ -416,7 +403,7 @@ The naming is fine; the structural choice is misleading. **Flag for upstream.** --- -### 14. `GetFeatureLineageRequest` has fields ordered `featureName, tableName` — category 10 (Reserved-word collisions, by association) and JSDoc drift +### 13. `GetFeatureLineageRequest` has fields ordered `featureName, tableName` — category 10 (Reserved-word collisions, by association) and JSDoc drift **Symbol:** `GetFeatureLineageRequest` (model.ts:61). @@ -431,7 +418,7 @@ This is a cosmetic but reader-facing inconsistency. --- -### 15. `Client.getFeatureLineage` JSDoc reads "Get Feature Lineage." with title case — JSDoc drift and category 17 (Inconsistent action verbs) +### 14. `Client.getFeatureLineage` JSDoc reads "Get Feature Lineage." with title case — JSDoc drift and category 17 (Inconsistent action verbs) **Symbol:** `Client.getFeatureLineage` (client.ts:115). @@ -452,17 +439,7 @@ name, fix JSDoc** to read "Gets a FeatureLineage." or "Gets feature lineage." --- -### 16. `Client.listFeatureTagsIter` async-iterator naming — *pass* - -**Symbol:** `Client.listFeatureTagsIter` (client.ts:198). - -`Iter` suffix is the project's canonical name for paginator generators -(`cleanrooms`, `cleanroomassets`, `featurestore`, etc.). Consistent across -the SDK. **Pass.** - ---- - -### 17. Method-name verbs `creates`/`deletes`/`gets`/`lists`/`updates` are consistent — category 17 (Inconsistent action verbs) — *pass* +### 15. Method-name verbs `creates`/`deletes`/`gets`/`lists`/`updates` are consistent — category 17 (Inconsistent action verbs) — *pass* **Symbols:** `createFeatureTag`, `deleteFeatureTag`, `getFeatureLineage`, `getFeatureTag`, `listFeatureTags`, `updateFeatureTag` (client.ts). @@ -472,14 +449,14 @@ or `remove…` mixed in. **Pass.** --- -### 18. `Client` class name — category 1 (Vague/generic) — *pass* +### 16. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-materializedfeatures/v1`). **Pass.** --- -### 19. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 17. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:39). @@ -494,89 +471,21 @@ for SDK-wide cleanup, do not fix in isolation.** --- -### 20. `userAgent` / `httpClient` / `host` / `logger` — *pass* +### 18. `userAgent` / `httpClient` / `host` / `logger` — *pass* Standard private field names. Acronym handling matches the project rule. **Pass.** --- -### 21. `HttpCallOptions` (utils.ts:15) — category 1 (Vague/generic) and category 20 (Type-suffix tautology) - -**Symbol:** `HttpCallOptions` interface. - -**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the -neighbouring `CallOptions` is imported on line 12 of the same file. Two -"Call"-suffixed names in one file — which one does the reader mean? Suggest -`HttpRequestContext` or `ExecuteHttpArgs`. **Flag for SDK-wide cleanup** — -`utils.ts` is generated boilerplate copied across every package. - ---- - -### 22. `executeCall` vs `executeHttpCall` — category 17 (Inconsistent action verbs) - -**Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). - -**Issue:** Two functions named `execute…Call`. `executeCall` is the public -API wrapper that calls `execute()` from `@databricks/sdk-core/api`; -`executeHttpCall` performs an HTTP request and decodes the body. They do -*different* things at *different* layers — but the names imply a hierarchical -relationship that does not exist. The HTTP one is roughly `sendAndDecode` or -`doHttpRequest`. **Flag for SDK-wide naming cleanup;** this file is generated -boilerplate copied across every package. - ---- - -### 23. `readAll` — *pass* +### 19. `readAll` — *pass* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 24. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) - -**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). - -**Issue:** Two symmetric operations: response→object (`parse`) and -object→body-string (`marshal`). The verbs come from two different vocabularies -("parse" is generic TS/JS, "marshal" is Go). Internally consistent verb-pair -would be `parseResponse` / `serializeRequest`, or fully commit to Go terms: -`unmarshalResponse` / `marshalRequest`. The current pair is awkward. - -**Suggested:** `serializeRequest` and `parseResponse` (TS-native vocabulary) -or commit fully to Go terms: `unmarshalResponse` and `marshalRequest`. **Flag -for SDK-wide consistency.** - ---- - -### 25. `unmarshal*Schema` / `marshal*Schema` Go vocabulary — category 14 (Go/Java-style names) - -**Symbols:** `unmarshalFeatureLineageSchema` (model.ts:101), -`unmarshalFeatureLineage_FeatureSpecSchema` (model.ts:120), -`unmarshalFeatureLineage_ModelSchema` (model.ts:130), -`unmarshalFeatureLineage_OnlineFeatureSchema` (model.ts:142), -`unmarshalFeatureTagSchema` (model.ts:153), -`unmarshalListFeatureTagsResponseSchema` (model.ts:163), -`marshalFeatureTagSchema` (model.ts:174). - -**Issue:** "Marshal" / "Unmarshal" is Go-ism vocabulary. TS ecosystem uses -"serialize" / "deserialize" or, when working with Zod, "parse" / -"stringify" / "schema". The full SDK uses this convention; **flag for SDK-wide -cleanup, not this package alone.** - -The `*Schema` suffix is also somewhat redundant — `unmarshalFeatureTag` -without `Schema` would suffice since the value's type is -`z.ZodType` and there are no non-schema cousins. But this is a -naming-pattern decision applied SDK-wide. **Pass with note.** - -Additionally, the underscore from finding 2 propagates here: -`unmarshalFeatureLineage_ModelSchema` is doubly bad — both underscores *and* -the Go vocabulary. - ---- - -### 26. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* +### 20. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. The file mixes `build…`, `execute…`, `marshal…`, `parse…`, @@ -585,21 +494,7 @@ for its purpose. **Pass.** --- -### 27. `flattenQueryParams` (utils.ts:123) — dead code in this package - -**Symbol:** `flattenQueryParams` (utils.ts:123). - -**Issue:** Imported nowhere within this package. The `listFeatureTags` method -builds its query string inline at client.ts:170–177, and `updateFeatureTag` -does similar at client.ts:221–225. The helper is dead code in this package. - -The name itself is fine. **Suggest** deleting from this package, or extracting -all utils into a shared helper module (`@databricks/sdk-core/http`). **Flag -generator behaviour** — this is boilerplate-copy noise. - ---- - -### 28. `featureTagFieldMaskSchema` private but exported via `featureTagFieldMask()` — *pass* +### 21. `featureTagFieldMaskSchema` private but exported via `featureTagFieldMask()` — *pass* **Symbols:** `featureTagFieldMaskSchema` (model.ts:184, internal) and `featureTagFieldMask()` (model.ts:189, public). Clean separation: schema is @@ -608,7 +503,7 @@ update-mask vocabulary. **Pass.** --- -### 29. `UpdateFeatureTagRequest.updateMask` — category 7 (Overly verbose) — *pass* +### 22. `UpdateFeatureTagRequest.updateMask` — category 7 (Overly verbose) — *pass* **Symbol:** `UpdateFeatureTagRequest.updateMask: FieldMask` (model.ts:98). @@ -619,14 +514,14 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 30. Singular `FeatureTag` ⇔ plural `featureTags` — category 9 (Singular/plural mismatch) — *pass* +### 23. Singular `FeatureTag` ⇔ plural `featureTags` — category 9 (Singular/plural mismatch) — *pass* `ListFeatureTagsResponse.featureTags: FeatureTag[]` (model.ts:87) is the canonical pattern. **Pass.** --- -### 31. `FeatureLineage.models` field name does not describe content — category 6 (Misleading names) and category 15 (Generic field names losing meaning) +### 24. `FeatureLineage.models` field name does not describe content — category 6 (Misleading names) and category 15 (Generic field names losing meaning) **Symbol:** `FeatureLineage.models?: FeatureLineage_Model[]` (model.ts:26). @@ -642,7 +537,7 @@ Pairs with the finding-5 rename of `FeatureLineage_Model` → --- -### 32. `FeatureLineage.featureSpecs` vs `FeatureLineage.onlineFeatures` plural-singular mismatch — category 9 (Singular/plural mismatch) — *partial pass* +### 25. `FeatureLineage.featureSpecs` vs `FeatureLineage.onlineFeatures` plural-singular mismatch — category 9 (Singular/plural mismatch) — *partial pass* **Symbols:** `FeatureLineage.featureSpecs`, `FeatureLineage.onlineFeatures` (model.ts:28, 30). @@ -651,7 +546,7 @@ Both are arrays — plural form is consistent. No issue. **Pass.** --- -### 33. `LineageContext` from `features` package vs `FeatureLineage` from this package — category 12 (Duplicate concepts) +### 26. `LineageContext` from `features` package vs `FeatureLineage` from this package — category 12 (Duplicate concepts) **Symbol:** `FeatureLineage` (model.ts:24); compare `features.LineageContext` (`packages/features/src/v1/model.ts:465`). @@ -676,18 +571,18 @@ vs. dependents (Lineage). **Flag for upstream Go SDK / generator.** --- -### 34. `GetFeatureLineageRequest` is `GetFeature…`, returns `FeatureLineage` — *pass* +### 27. `GetFeatureLineageRequest` is `GetFeature…`, returns `FeatureLineage` — *pass* **Symbol:** `Client.getFeatureLineage` (client.ts:115), return type `FeatureLineage` (model.ts:24). The method name uses verb `get` consistently; the return type name is the resource. No issue at the method-name layer. (Underlying naming smells of -`FeatureLineage` itself are covered in findings 31, 33.) **Pass.** +`FeatureLineage` itself are covered in findings 25, 27.) **Pass.** --- -### 35. `BatchCreateMaterializedFeatures*` types live in `features` not this package — category 12 (Duplicate concepts) — cross-package +### 28. `BatchCreateMaterializedFeatures*` types live in `features` not this package — category 12 (Duplicate concepts) — cross-package **Symbols (cross-package):** `BatchCreateMaterializedFeaturesRequest`, `BatchCreateMaterializedFeaturesResponse` live in `features/v1/model.ts:146, @@ -701,21 +596,7 @@ coordination.** --- -### 36. `marshalFeatureTagSchema` returns `z.ZodType` (no generic) but `unmarshalFeatureTagSchema` returns `z.ZodType` — category 17 (Inconsistent action verbs) - -**Symbols:** `unmarshalFeatureTagSchema: z.ZodType` (model.ts:153) -vs. `marshalFeatureTagSchema: z.ZodType` (model.ts:174). - -**Issue:** The unmarshal schema declares its parsed type as -`z.ZodType`; the marshal one declares only `z.ZodType` (i.e. -`z.ZodType`). Naming inconsistency mirrored in typing inconsistency. -This pattern is SDK-wide and presumably intentional (the marshal direction -produces wire-format objects without a TS shape), but symmetrically named -helpers should probably share a generic shape. **Flag for SDK-wide cleanup.** - ---- - -### 37. `index.ts` re-exports underscore types — category 4 (Underscores in TS identifiers) +### 29. `index.ts` re-exports underscore types — category 4 (Underscores in TS identifiers) **Symbol:** `index.ts:7–20`. @@ -740,7 +621,7 @@ consumer sees them. **Pass at the index.ts layer**, fix follows from finding 2. --- -### 38. `index.ts:5` empty re-export — *pass with note* +### 30. `index.ts:5` empty re-export — *pass with note* **Symbol:** `export {} from './model';` (index.ts:5). @@ -750,7 +631,7 @@ on naming**, flag for generator cleanup. --- -### 39. URL path constants spread inline in `Client` methods — code-quality (out of scope) — *pass* +### 31. URL path constants spread inline in `Client` methods — code-quality (out of scope) — *pass* **Symbols:** every method constructs a URL via template literal embedding `req.tableName ?? ''` and `req.featureName ?? ''` (client.ts:74, 100, 119, @@ -761,7 +642,7 @@ concern, not naming. **Pass.** --- -### 40. `req`/`resp`/`pageReq` Go-style short variable names — category 14 (Go/Java-style names) +### 32. `req`/`resp`/`pageReq` Go-style short variable names — category 14 (Go/Java-style names) **Symbols:** local variables `req` (every method parameter), `resp` (every method local), `pageReq` (client.ts:202). @@ -773,7 +654,7 @@ convention is mixed. **Pass with note — flag for SDK-wide style decision.** --- -### 41. Generator-comment "DO NOT EDIT." header — *pass* +### 33. Generator-comment "DO NOT EDIT." header — *pass* Every file begins with `// Code generated from API definition by Databricks SDK Generator. DO NOT EDIT.` Naming-irrelevant, but informs the scope of any @@ -882,39 +763,26 @@ guidance.** --- -### Wire-format vs TS field-name divergence - -Same as every package: every request/response type has both a TS interface -and a Zod schema that maps `snake_case` wire fields to `camelCase` TS fields. -This pattern is fine and consistent. The `marshal`/`unmarshal` Go vocabulary -is a separate (SDK-wide) concern — see finding 25. - ---- - ## Summary (counts) - **Critical / cross-package consistency:** 2 findings (#1 package name mis-scope `materializedfeatures` does not contain materialized features; #7 `FeatureLineage_OnlineFeature.tableName` should be `onlineTableName`). -- **High (style guide violations):** 5 findings (#2 three underscore types - `FeatureLineage_FeatureSpec/Model/OnlineFeature`; #19 `PACKAGE_SEGMENT` - casing; #25 unmarshal/marshal Go vocab on schemas; #37 surface re-exports - underscore types; #36 generic-shape inconsistency between marshal and - unmarshal). -- **Medium (naming clarity, JSDoc drift):** 11 findings (#3, #4, #5, #6, #8, - #9, #10, #11, #13, #14, #15, #31, #33). -- **Low / project-wide convention notes (generator-level):** 6 findings (#21, - #22, #24, #27, #35, #40). -- **Pass / acceptable as-is:** 14 findings (#12, #16, #17, #18, #20, #23, - #26, #28, #29, #30, #32, #34, #38, #39, #41 — many partial passes with - notes). - -**Total flagged findings: 41** distinct items across 20 audit categories -(many findings touch multiple categories). The dominant theme is **package +- **High (style guide violations):** 3 findings (#2 three underscore types + `FeatureLineage_FeatureSpec/Model/OnlineFeature`; #17 `PACKAGE_SEGMENT` + casing; #29 surface re-exports underscore types). +- **Medium (naming clarity, JSDoc drift):** 13 findings (#3, #4, #5, #6, #8, + #9, #10, #11, #12, #13, #14, #24, #26). +- **Low / project-wide convention notes (generator-level):** 2 findings (#28, + #32). +- **Pass / acceptable as-is:** 13 findings (#15, #16, #18, #19, #20, #21, + #22, #23, #25, #27, #30, #31, #33 — many partial passes with notes). + +**Total flagged findings: 33** distinct items. The dominant theme is **package mis-naming** (the package does not contain what its name advertises) and **proto-style underscore identifier names** for nested types (`FeatureLineage_*`). Many issues are generator-emitted boilerplate inherited from the Go SDK; the cleanest local fixes are findings 1 (package rename), 7 (`onlineTableName` field), 10 (JSDoc on `tableName`/`featureName`), 11 -(JSDoc plural form), 13 (top-level `key` for update), 14 (field order in -`GetFeatureLineageRequest`), and 15 (`getFeatureLineage` JSDoc casing). +(JSDoc plural form), 12 (top-level `key` for update), 13 (field order in +`GetFeatureLineageRequest`), and 14 (`getFeatureLineage` JSDoc casing). diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index fa088bcb..3e5fc010 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -12,11 +12,11 @@ The `metastores` package exposes nine Unity Catalog metastore operations (`createMetastore`, `createMetastoreAssignment`, `deleteMetastore`, `deleteMetastoreAssignment`, `getCurrentMetastoreAssignment`, `getMetastore`, `getMetastoreSummary`, `listMetastores`, -`listMetastoresIter`, `updateMetastore`, `updateMetastoreAssignment`). +`updateMetastore`, `updateMetastoreAssignment`). The naming issues split into two broad classes: 1. **Proto-style identifiers leaking into TypeScript** — - `DeltaSharingScope_Enum`, `*_Response`, `unmarshal…_ResponseSchema`. + `DeltaSharingScope_Enum`, `*_Response`. 2. **Massive structural duplication** — `CreateMetastore`, `UpdateMetastore`, and `MetastoreInfo` share 18 fields verbatim, including read-only output fields (`createdAt`, `createdBy`, @@ -27,7 +27,7 @@ The naming issues split into two broad classes: `DeltaSharingScope_Enum` is the single most visible cosmetic violation (underscore identifier and `_Enum` suffix tautology), and it shows up -on three different types and in both marshal/unmarshal schemas. +on three different types. --- @@ -44,7 +44,7 @@ everywhere else in the package (model.ts:42, 64, 91, 113, 213, 258, etc.), so the bare `id` is inconsistent and ambiguous in isolation (e.g. spreading `{...req, id: someValue}` is brittle). Recommend `metastoreId` (or, if the goal is to mark it as the path param, see -§5.1 / §13.1). +§5.1 / §12.1). #### 1.2 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:181, 183) Acceptable in isolation — but the *type* `MetastoreAssignment` is just @@ -68,7 +68,7 @@ A bare `cloud: string` with a single example list in the doc (`aws`, #### 1.5 `owner` field (model.ts:36, 140, 207, 252) "The owner of the metastore." — generic. Owner of what kind? Username? Email? Group? Service principal? Documented as a free-form string with -no format hint. See §16.4. +no format hint. See §15.4. #### 1.6 `region` (model.ts:40, 124, 211, 256) Bare `region: string` with examples (`us-west-2`, `westus`). Acceptable @@ -84,7 +84,7 @@ heterogeneity isn't reflected in the name or doc. Variants are `INTERNAL` and `INTERNAL_AND_EXTERNAL`. The enum name already says "DeltaSharingScope" — the variants do not repeat that prefix, which is good. However, `INTERNAL_AND_EXTERNAL` is verbose -(see §15.1) — a single canonical name like `ALL` or a pair like +(see §14.1) — a single canonical name like `ALL` or a pair like `INTERNAL` / `EXTERNAL` would be clearer. (No `*_DELTA_SHARING_SCOPE_*` prefix issue here — variants are clean. @@ -128,7 +128,7 @@ i.e. the lint rule already objects. #### 4.1 `DeltaSharingScope_Enum` (model.ts:6) Should be `DeltaSharingScope`. The `_Enum` suffix is a proto-port -artifact (see also §8.3 and §17.1). The enum is referenced in five +artifact (see also §8.2 and §16.1). The enum is referenced in five places (lines 30, 132, 201, 246, 318, 385, 434, 493) — every reference inherits the awkward name. @@ -151,17 +151,6 @@ Should be `ListMetastoresResponse`. #### 4.7 `UpdateMetastoreAssignment_Response` (model.ts:291) Should be `UpdateMetastoreAssignmentResponse`. -#### 4.8 Schema export names propagate underscores (model.ts:294, 298, 302, 306, 353, 425) -- `unmarshalCreateMetastoreAssignment_ResponseSchema` -- `unmarshalDeleteMetastore_ResponseSchema` -- `unmarshalDeleteMetastoreAssignment_ResponseSchema` -- `unmarshalGetMetastoreSummary_ResponseSchema` -- `unmarshalListMetastores_ResponseSchema` -- `unmarshalUpdateMetastoreAssignment_ResponseSchema` - -Should drop the underscore: `unmarshalDeleteMetastoreResponseSchema`, -etc. - --- ### 5. Cryptic abbreviations @@ -170,23 +159,10 @@ etc. Cryptic because it loses the entity context. `metastoreId` is used elsewhere. -#### 5.2 `req` parameter name in `Client.*` methods (client.ts:93, 123, 152, 183, 217, 242, 270, 306, 339, 361, 391) -`req` is the canonical Go-SDK parameter name. In TS it would more -typically be `request` or `params`. Defensible (internal to the call -site, every method has the same shape), but a Go idiom that has been -ported verbatim — see §11.3. - -#### 5.3 `resp` local variable name (client.ts:98, 128, 162, 193, etc.) -Same pattern as §5.2 — `resp` for `response`. Go-style abbreviation. - -#### 5.4 `pkgJson` (client.ts:19) -Import alias for `package.json`. Minor — internal — and matches the -peer packages' convention. - -#### 5.5 `Ms` suffix absent on timestamp fields +#### 5.2 `Ms` suffix absent on timestamp fields Counter-example: timestamp fields are documented as "epoch milliseconds" but the names omit the unit suffix (`createdAt`, -`updatedAt`). See §16.5. +`updatedAt`). See §15.5. --- @@ -213,7 +189,7 @@ Doc says "Unique identifier of the metastore's (Default) Data Access Configuration." The parenthetical "Default" duplicates the `default` prefix in the name, but the field is described as both the default data-access-config and as a unique identifier. Slightly self-referential -and unclear whether this is mutable or static. See also §16.3. +and unclear whether this is mutable or static. See also §15.3. #### 6.5 `cloud: string` (model.ts:54, 122, 225, 270) Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as @@ -240,30 +216,13 @@ includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" omits the "current-workspace" semantics. Cf. `getCurrentMetastoreAssignment`, which spells out "current". See also -§14.1. +§13.1. --- ### 7. Overly verbose -#### 7.1 `deltaSharingRecipientTokenLifetimeInSeconds` (model.ts:32, 134, 203, 248) -46-character field name. The `InSeconds` unit suffix is good (see §16.5), -but the field gets used as a top-level property of three different -types and bleeds into every marshal/unmarshal schema (also 46 chars, -plus snake-case form). Acceptable for clarity; flagged because it's -the longest field name in the package. - -#### 7.2 `deltaSharingOrganizationName` (model.ts:34, 136, 205, 250) -28 characters. Same pattern as 7.1 — repeated on every metastore type. - -#### 7.3 `unmarshalCreateMetastoreAssignment_ResponseSchema` (model.ts:294) -49 characters. With the underscore stripped (§4.8), it's 48 — -unavoidable given the underlying naming, but worth flagging as a long -identifier. - -#### 7.4 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) — see §15.1. - -#### 7.5 `getCurrentMetastoreAssignment` (client.ts:216) +#### 7.1 `getCurrentMetastoreAssignment` (client.ts:216) 28-character method name. Acceptable — describes the semantics — but combined with `getMetastoreSummary` (which is also "current-workspace" in practice, §6.8) one of them carries redundant prefixing. @@ -274,18 +233,12 @@ in practice, §6.8) one of them carries redundant prefixing. #### 8.1 `…Info` suffix on `MetastoreInfo` (model.ts:191) "Info" carries no semantic content. Go-SDK convention; TS would just -say `Metastore`. See §11.4. +say `Metastore`. See §10.3. #### 8.2 `…_Enum` suffix on `DeltaSharingScope_Enum` (model.ts:6) — see §4.1. TypeScript enums are already enums; the suffix tautological. -#### 8.3 `…Schema` suffix on every zod schema export -Every export is named `marshal…Schema` / `unmarshal…Schema`. The -`Schema` suffix is conventional but redundant when paired with the -`marshal…`/`unmarshal…` prefix (which already says "this is a -zod-using helper"). Cf. catalogs audit §8.6. - -#### 8.4 `…Assignment` suffix on `MetastoreAssignment` and four request types +#### 8.3 `…Assignment` suffix on `MetastoreAssignment` and four request types `CreateMetastoreAssignment`, `DeleteMetastoreAssignment`, `UpdateMetastoreAssignment`, `GetCurrentMetastoreAssignment`, `MetastoreAssignment`. The suffix is justified because "metastore @@ -296,13 +249,7 @@ completeness. ### 9. Singular / plural mismatches -#### 9.1 `listMetastoresIter` returns `AsyncGenerator` (client.ts:338) -Method name pluralizes ("Metastores") but yields singular items. Same -pattern as `listCatalogsIter` (catalogs §9.1). Consider `iterMetastores` -(verb-first) — but consistency across the SDK matters more than the -nominal/verbal split. - -#### 9.2 `ListMetastores_Response.metastores` (model.ts:171) +#### 9.1 `ListMetastores_Response.metastores` (model.ts:171) Field is plural and correctly typed `MetastoreInfo[]` — no mismatch. Flagged as a counter-example. @@ -312,7 +259,7 @@ Flagged as a counter-example. #### 10.1 `name` field on `CreateMetastore`, `MetastoreInfo`, `UpdateMetastore`, `GetMetastoreSummary_Response` (model.ts:22, 116, 193, 238) Routinely shadows `Function.prototype.name`. Common SDK convention; not -fixable in isolation. See also §13.1. +fixable in isolation. See also §12.1. #### 10.2 `id` field on `DeleteMetastore`, `GetMetastore`, `UpdateMetastore` (model.ts:79, 105, 234) Collides with `Element.id` and other web-platform-y identifiers when @@ -323,35 +270,19 @@ a cognitive one. See §1.1. --- -### 11. Go / Java-style names - -#### 11.1 `DeltaSharingScope_Enum` (model.ts:6) — proto nested-enum convention. See §4.1. +### 11. Duplicate concepts -#### 11.2 `…_Response` suffix (model.ts:75, 85, 95, 112, 169, 291) — proto/Go-RPC idiom. See §4.2-4.7. - -#### 11.3 `req` / `resp` parameter and local names (client.ts throughout) — Go style. See §5.2, §5.3. - -#### 11.4 `…Info` suffix on `MetastoreInfo` — Go/Java style. See §6.1, §8.1. - -#### 11.5 `unmarshal…` / `marshal…` prefix verbs — Go's `encoding/json` vocabulary. TS would use `parse`/`serialize` or `decode`/`encode`. Defensible for internal generated code; identifies as Go-style. - -#### 11.6 `Client` bare class name (client.ts:61) — Go idiom (package qualifies the type). TS consumers commonly alias to `MetastoresClient`. Same pattern as catalogs §14.2. - ---- - -### 12. Duplicate concepts - -#### 12.1 `DeltaSharingScope` interface vs `DeltaSharingScope_Enum` enum (model.ts:6, 98) +#### 11.1 `DeltaSharingScope` interface vs `DeltaSharingScope_Enum` enum (model.ts:6, 98) Two distinct exports with near-identical names — one is the enum, the other a separate type. A user importing `DeltaSharingScope` will get the non-enum export and silently get the wrong shape. The naming is maximally hostile and the `_Enum` suffix on the enum exists solely to disambiguate from this sibling. -#### 12.2 `MetastoreInfo` vs `GetMetastoreSummary_Response` (model.ts:112, 191) +#### 11.2 `MetastoreInfo` vs `GetMetastoreSummary_Response` (model.ts:112, 191) Same 18 fields, same docs, different names. See §6.7. -#### 12.3 `CreateMetastore` vs `MetastoreInfo` vs `UpdateMetastore` (model.ts:20, 191, 232) +#### 11.3 `CreateMetastore` vs `MetastoreInfo` vs `UpdateMetastore` (model.ts:20, 191, 232) Massive structural duplication — `CreateMetastore` has 19 fields, `MetastoreInfo` has 19 fields, `UpdateMetastore` has 20 fields. The extra field on `UpdateMetastore` is `id` (path param) plus `newName`. @@ -360,36 +291,36 @@ shared `MetastoreCommon` (or `Partial`) would let renames happen in one place. Note that all three contain the same read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `globalMetastoreId`) — these have no business on a -request shape (§13.3). +request shape (§12.3). -#### 12.4 `CreateMetastoreAssignment` vs `MetastoreAssignment` vs `UpdateMetastoreAssignment` (model.ts:61, 179, 277) +#### 11.4 `CreateMetastoreAssignment` vs `MetastoreAssignment` vs `UpdateMetastoreAssignment` (model.ts:61, 179, 277) Three structurally identical types with three workspace-id / metastore-id / default-catalog-name fields. Could be unified. -#### 12.5 `id` (on `DeleteMetastore`/`GetMetastore`/`UpdateMetastore`) vs `metastoreId` (everywhere else) +#### 11.5 `id` (on `DeleteMetastore`/`GetMetastore`/`UpdateMetastore`) vs `metastoreId` (everywhere else) Same concept, two names. See §1.1. -#### 12.6 `name` (CreateMetastore body) vs metastore identity +#### 11.6 `name` (CreateMetastore body) vs metastore identity `CreateMetastore.name` is "the user-specified name of the metastore" — but `MetastoreInfo` also exposes `metastoreId` as the canonical unique identifier. The naming pretends `name` is unique but in fact the server creates `metastoreId` as the immutable key and `name` is mutable. The doc could disclose this; the name doesn't. -#### 12.7 `name` vs `newName` on `UpdateMetastore` (model.ts:236, 238) +#### 11.7 `name` vs `newName` on `UpdateMetastore` (model.ts:236, 238) Two name-like fields on the update request: - `newName` — "New name for the metastore." (model.ts:236). - `name` — "The user-specified name of the metastore." (model.ts:238). Per the doc, both fields can hold a name. The intent is presumably that `newName` is the rename target and `name` is left over from the -shared shape; in practice, callers cannot tell. See §13.1. +shared shape; in practice, callers cannot tell. See §12.1. --- -### 13. Field contradicting type domain +### 12. Field contradicting type domain -#### 13.1 `UpdateMetastore` has `id`, `name`, `newName`, and `metastoreId` (model.ts:234, 236, 238, 258) +#### 12.1 `UpdateMetastore` has `id`, `name`, `newName`, and `metastoreId` (model.ts:234, 236, 238, 258) Four name/id-like fields on a single update request: - `id` — path parameter; the existing metastore to update. - `metastoreId` — leftover from the shared shape; not used by the @@ -404,11 +335,11 @@ A caller staring at this struct cannot intuit which field controls what. This is the package's single most user-hostile naming pattern, mirroring the `UpdateCatalog` issue (catalogs §16.1). -#### 13.2 `UpdateMetastore.metastoreId` shadows `UpdateMetastore.id` (model.ts:234, 258) -Same as 13.1 — two id-like fields whose roles are not differentiated +#### 12.2 `UpdateMetastore.metastoreId` shadows `UpdateMetastore.id` (model.ts:234, 258) +Same as 12.1 — two id-like fields whose roles are not differentiated by name. -#### 13.3 `CreateMetastore` and `UpdateMetastore` carry read-only output fields (model.ts:42-58, 258-274) +#### 12.3 `CreateMetastore` and `UpdateMetastore` carry read-only output fields (model.ts:42-58, 258-274) `metastoreId`, `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `globalMetastoreId`, `cloud`, `storageRootCredentialName`. These are server-populated; a creator/updater setting them is at best ignored. @@ -416,13 +347,13 @@ The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of catalogs §16.2. -#### 13.4 `GetMetastoreSummary_Response` returns the full metastore (model.ts:112) — see §6.7. The type name promises a summary; the value is the entity. +#### 12.4 `GetMetastoreSummary_Response` returns the full metastore (model.ts:112) — see §6.7. The type name promises a summary; the value is the entity. --- -### 14. Inconsistent action verbs +### 13. Inconsistent action verbs -#### 14.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:241, 269, 216) +#### 13.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:241, 269, 216) Three "get"-style methods, each with a different qualifier: - `getMetastore(req)` — get by id. - `getMetastoreSummary()` — get the current metastore (no id). @@ -435,81 +366,74 @@ qualifier vocabulary. Either rename `getMetastoreSummary` to `getCurrentMetastore` (which would also fix §6.8) or drop "Current" from `getCurrentMetastoreAssignment`. -#### 14.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. - -#### 14.3 `listMetastoresIter` uses a suffix-style iter marker rather than a verb prefix. Consistent with the rest of the SDK; flagged for completeness. +#### 13.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. --- -### 15. Long enum values +### 14. Long enum values -#### 15.1 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) +#### 14.1 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) 20 characters. Two of two variants is verbose. A pair `INTERNAL` / `EXTERNAL` (where `EXTERNAL` implies "in addition to internal") would be punchier. The current name doubles as a poor man's bit-flag. See §2.1. --- -### 16. Underspecified IDs +### 15. Underspecified IDs -#### 16.1 `metastoreId` (model.ts:42, 64, 91, 113, 183, 213, 258, 281) +#### 15.1 `metastoreId` (model.ts:42, 64, 91, 113, 183, 213, 258, 281) Documented as "Unique identifier of metastore" / "The unique ID of the metastore." Format is opaque — likely a UUID, but never specified in the doc. -#### 16.2 `workspaceId` (model.ts:63, 89, 181, 279) +#### 15.2 `workspaceId` (model.ts:63, 89, 181, 279) `number` — that's specified by the type, but the doc just says "A workspace ID." with no range or stability guarantee. Acceptable for a numeric id; flagged because the format isn't documented in the field. -#### 16.3 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +#### 15.3 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) "Unique identifier of the metastore's (Default) Data Access Configuration." No format hint (UUID? slug?). See §6.4. -#### 16.4 `storageRootCredentialId` (model.ts:28, 120, 199, 244) +#### 15.4 `storageRootCredentialId` (model.ts:28, 120, 199, 244) Doc says "UUID of storage credential" — at least the doc says UUID here, but the field name doesn't carry the type. Counter-example to -§16.1: when the doc *does* specify UUID, the field still doesn't carry +§15.1: when the doc *does* specify UUID, the field still doesn't carry it. -#### 16.5 `createdAt`, `updatedAt` (model.ts:44, 48, 142, 146, 215, 219, 260, 264) +#### 15.5 `createdAt`, `updatedAt` (model.ts:44, 48, 142, 146, 215, 219, 260, 264) Doc says "epoch milliseconds" but the names lack the `Ms` unit -suffix. Counter-example: `deltaSharingRecipientTokenLifetimeInSeconds` -(model.ts:32) *does* carry the `InSeconds` unit. Inconsistent. +suffix. Inconsistent across the package. -#### 16.6 `globalMetastoreId` (model.ts:56, 126, 227, 271) +#### 15.6 `globalMetastoreId` (model.ts:56, 126, 227, 271) Documented as a composite `cloud:region:metastore_id` string — not a simple ID. The name promises an ID; the value is a structured locator. See §6.3. -#### 16.7 `owner`, `createdBy`, `updatedBy` (model.ts:36, 46, 50, 140, 144, 148, 207, 217, 221, 252, 262, 266) +#### 15.7 `owner`, `createdBy`, `updatedBy` (model.ts:36, 46, 50, 140, 144, 148, 207, 217, 221, 252, 262, 266) Documented as "username", "Username of metastore creator", etc. Format (email? user id? group?) is unspecified. The names imply identity; the doc only narrows to "username". --- -### 17. Type-suffix tautology +### 16. Type-suffix tautology -#### 17.1 `DeltaSharingScope_Enum` enum with field `deltaSharingScope: DeltaSharingScope_Enum` (model.ts:6, 30, 132, 201, 246) +#### 16.1 `DeltaSharingScope_Enum` enum with field `deltaSharingScope: DeltaSharingScope_Enum` (model.ts:6, 30, 132, 201, 246) Field name `deltaSharingScope` is identical to the enum *minus* the `_Enum` suffix. The `_Enum` suffix exists solely to disambiguate the -enum from the sibling `DeltaSharingScope` interface (§12.1). Were the +enum from the sibling `DeltaSharingScope` interface (§11.1). Were the sibling renamed, the enum could simply be `DeltaSharingScope` and the field name would be exactly the enum name (a true tautology). Today, the workaround is the `_Enum` suffix. -#### 17.2 `MetastoreInfo` exposes `metastoreId` (model.ts:191, 213) +#### 16.2 `MetastoreInfo` exposes `metastoreId` (model.ts:191, 213) The type's domain is the metastore; the field redundantly carries the entity name in its identifier. Acceptable convention; flagged for completeness. -#### 17.3 Schema-export tautology -`unmarshalMetastoreInfoSchema: z.ZodType` (model.ts:379) -— the `Schema` suffix duplicates `z.ZodType<…>`. See §8.3. - -#### 17.4 `MetastoreAssignment` carries `metastoreId` (model.ts:179, 183) -Same pattern as 17.2 — entity name in field. +#### 16.3 `MetastoreAssignment` carries `metastoreId` (model.ts:179, 183) +Same pattern as 16.2 — entity name in field. --- @@ -545,17 +469,11 @@ metastore to delete.") only via the leading word "Query" — the field name itself does not signal that the value is a query parameter, not a path one. -### E. Marshal/unmarshal exports lack proper TS types for marshal side (model.ts:428, 473, 485, 534) -`marshalCreateMetastoreSchema: z.ZodType` (no generic) versus -`unmarshalMetastoreInfoSchema: z.ZodType` (with -generic). The marshal side is implicitly untyped. Not a naming issue -per se, but inconsistent with the unmarshal naming/typing. - -### F. `Client` constructor throws bare `Error` for missing `host` (client.ts:72) +### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:72) "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### G. `index.ts` re-exports proto-style names verbatim (lines 5, 7-27) +### F. `index.ts` re-exports proto-style names verbatim (lines 5, 7-27) Every underscore-bearing identifier surfaces in the package's public API. A consumer of `@databricks/sdk-metastores/v1` sees `DeltaSharingScope_Enum`, `CreateMetastoreAssignment_Response`, @@ -563,12 +481,12 @@ API. A consumer of `@databricks/sdk-metastores/v1` sees `GetMetastoreSummary_Response`, `ListMetastores_Response`, and `UpdateMetastoreAssignment_Response` as first-class exports. -### H. `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` (index.ts:5, 15) +### G. `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` (index.ts:5, 15) A consumer importing `DeltaSharingScope` gets the sibling export, not the enum. There is no compile-time or runtime hint that they should -have used the `_Enum`-suffixed export. See §12.1. +have used the `_Enum`-suffixed export. See §11.1. -### I. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies +### H. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies This package's `workspaceId` is `number`. Some peer packages model workspace IDs as strings (e.g. when forwarded through URL params). The type inconsistency is across packages, not within this one; @@ -580,114 +498,94 @@ flagged in passing. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | -| `DeltaSharingScope_Enum` | model.ts:6 | 2.1, 4.1, 8.2, 11.1, 15.1, 17.1 | +| `DeltaSharingScope_Enum` | model.ts:6 | 2.1, 4.1, 8.2, 14.1, 16.1 | | `DeltaSharingScope_Enum.INTERNAL` | model.ts:12 | — | -| `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` | model.ts:17 | 2.1, 15.1 | -| `CreateMetastore` | model.ts:20 | 12.3, 13.3 | -| `CreateMetastore.name` | model.ts:22 | 10.1, 12.6 | +| `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` | model.ts:17 | 2.1, 14.1 | +| `CreateMetastore` | model.ts:20 | 11.3, 12.3 | +| `CreateMetastore.name` | model.ts:22 | 10.1, 11.6 | | `CreateMetastore.storageRoot` | model.ts:24 | 6.2 | -| `CreateMetastore.defaultDataAccessConfigId` | model.ts:26 | 6.4, 16.3 | -| `CreateMetastore.storageRootCredentialId` | model.ts:28 | 16.4 | -| `CreateMetastore.deltaSharingScope` | model.ts:30 | 17.1 | -| `CreateMetastore.deltaSharingRecipientTokenLifetimeInSeconds` | model.ts:32 | 7.1 | -| `CreateMetastore.deltaSharingOrganizationName` | model.ts:34 | 7.2 | -| `CreateMetastore.owner` | model.ts:36 | 1.5, 16.7 | +| `CreateMetastore.defaultDataAccessConfigId` | model.ts:26 | 6.4, 15.3 | +| `CreateMetastore.storageRootCredentialId` | model.ts:28 | 15.4 | +| `CreateMetastore.deltaSharingScope` | model.ts:30 | 16.1 | +| `CreateMetastore.owner` | model.ts:36 | 1.5, 15.7 | | `CreateMetastore.region` | model.ts:40 | 1.6, 6.6 | -| `CreateMetastore.metastoreId` (read-only on Create) | model.ts:42 | 13.3, 16.1, 17.2 | -| `CreateMetastore.createdAt` (read-only on Create) | model.ts:44 | 13.3, 16.5 | -| `CreateMetastore.createdBy` (read-only on Create) | model.ts:46 | 13.3, 16.7 | -| `CreateMetastore.updatedAt` (read-only on Create) | model.ts:48 | 13.3, 16.5 | -| `CreateMetastore.updatedBy` (read-only on Create) | model.ts:50 | 13.3, 16.7 | -| `CreateMetastore.storageRootCredentialName` (read-only) | model.ts:52 | 13.3 | +| `CreateMetastore.metastoreId` (read-only on Create) | model.ts:42 | 12.3, 15.1, 16.2 | +| `CreateMetastore.createdAt` (read-only on Create) | model.ts:44 | 12.3, 15.5 | +| `CreateMetastore.createdBy` (read-only on Create) | model.ts:46 | 12.3, 15.7 | +| `CreateMetastore.updatedAt` (read-only on Create) | model.ts:48 | 12.3, 15.5 | +| `CreateMetastore.updatedBy` (read-only on Create) | model.ts:50 | 12.3, 15.7 | +| `CreateMetastore.storageRootCredentialName` (read-only) | model.ts:52 | 12.3 | | `CreateMetastore.cloud` | model.ts:54 | 1.4, 6.5 | -| `CreateMetastore.globalMetastoreId` (read-only) | model.ts:56 | 6.3, 13.3, 16.6 | +| `CreateMetastore.globalMetastoreId` (read-only) | model.ts:56 | 6.3, 12.3, 15.6 | | `CreateMetastore.externalAccessEnabled` | model.ts:58 | 3.1 (doc) | -| `CreateMetastoreAssignment` | model.ts:61 | 12.4 | -| `CreateMetastoreAssignment.workspaceId` | model.ts:63 | 16.2, I | -| `CreateMetastoreAssignment.metastoreId` | model.ts:65 | 16.1 | +| `CreateMetastoreAssignment` | model.ts:61 | 11.4 | +| `CreateMetastoreAssignment.workspaceId` | model.ts:63 | 15.2, H | +| `CreateMetastoreAssignment.metastoreId` | model.ts:65 | 15.1 | | `CreateMetastoreAssignment.defaultCatalogName` | model.ts:71 | — | -| `CreateMetastoreAssignment_Response` | model.ts:75 | 4.2, 11.2 | +| `CreateMetastoreAssignment_Response` | model.ts:75 | 4.2 | | `DeleteMetastore` | model.ts:77 | — | -| `DeleteMetastore.id` | model.ts:79 | 1.1, 5.1, 10.2, 12.5 | +| `DeleteMetastore.id` | model.ts:79 | 1.1, 5.1, 10.2, 11.5 | | `DeleteMetastore.force` | model.ts:81 | 1.3 | -| `DeleteMetastore_Response` | model.ts:85 | 4.3, 11.2 | -| `DeleteMetastoreAssignment` | model.ts:87 | 12.4 | -| `DeleteMetastoreAssignment.workspaceId` | model.ts:89 | 16.2 | -| `DeleteMetastoreAssignment.metastoreId` | model.ts:91 | 16.1, D | -| `DeleteMetastoreAssignment_Response` | model.ts:95 | 4.4, 11.2 | -| `DeltaSharingScope` | model.ts:98 | 12.1, H | +| `DeleteMetastore_Response` | model.ts:85 | 4.3 | +| `DeleteMetastoreAssignment` | model.ts:87 | 11.4 | +| `DeleteMetastoreAssignment.workspaceId` | model.ts:89 | 15.2 | +| `DeleteMetastoreAssignment.metastoreId` | model.ts:91 | 15.1, D | +| `DeleteMetastoreAssignment_Response` | model.ts:95 | 4.4 | +| `DeltaSharingScope` | model.ts:98 | 11.1, G | | `GetCurrentMetastoreAssignment` | model.ts:101 | — | | `GetMetastore` | model.ts:103 | — | -| `GetMetastore.id` | model.ts:105 | 1.1, 5.1, 10.2, 12.5 | +| `GetMetastore.id` | model.ts:105 | 1.1, 5.1, 10.2, 11.5 | | `GetMetastoreSummary` | model.ts:109 | — | -| `GetMetastoreSummary_Response` | model.ts:112 | 4.5, 6.7, 12.2, 13.4 | +| `GetMetastoreSummary_Response` | model.ts:112 | 4.5, 6.7, 11.2, 12.4 | | `ListMetastores` | model.ts:153 | — | | `ListMetastores.maxResults` | model.ts:163 | — | | `ListMetastores.pageToken` | model.ts:165 | — | -| `ListMetastores_Response` | model.ts:169 | 4.6, 11.2 | -| `ListMetastores_Response.metastores` | model.ts:171 | 9.2 (positive) | +| `ListMetastores_Response` | model.ts:169 | 4.6 | +| `ListMetastores_Response.metastores` | model.ts:171 | 9.1 (positive) | | `ListMetastores_Response.nextPageToken` | model.ts:176 | — | -| `MetastoreAssignment` | model.ts:179 | 1.2, 8.4, 12.4 | -| `MetastoreAssignment.workspaceId` | model.ts:181 | 1.2, 16.2, I | -| `MetastoreAssignment.metastoreId` | model.ts:183 | 16.1, 17.4 | +| `MetastoreAssignment` | model.ts:179 | 1.2, 8.3, 11.4 | +| `MetastoreAssignment.workspaceId` | model.ts:181 | 1.2, 15.2, H | +| `MetastoreAssignment.metastoreId` | model.ts:183 | 15.1, 16.3 | | `MetastoreAssignment.defaultCatalogName` | model.ts:188 | — | -| `MetastoreInfo` | model.ts:191 | 6.1, 8.1, 12.3, 11.4 | -| `MetastoreInfo.metastoreId` | model.ts:213 | 16.1, 17.2 | -| `MetastoreInfo.globalMetastoreId` | model.ts:227 | 6.3, 16.6 | -| `UpdateMetastore` | model.ts:232 | 12.3, 13.1, 13.3 | -| `UpdateMetastore.id` | model.ts:234 | 1.1, 5.1, 13.1, 13.2 | -| `UpdateMetastore.newName` | model.ts:236 | 12.7, 13.1 | -| `UpdateMetastore.name` | model.ts:238 | 12.7, 13.1 | -| `UpdateMetastore.metastoreId` | model.ts:258 | 13.1, 13.2 | -| `UpdateMetastoreAssignment` | model.ts:277 | 12.4 | -| `UpdateMetastoreAssignment.workspaceId` | model.ts:279 | 16.2 | -| `UpdateMetastoreAssignment_Response` | model.ts:291 | 4.7, 11.2 | -| `unmarshalCreateMetastoreAssignment_ResponseSchema` | model.ts:294 | 4.8, 7.3 | -| `unmarshalDeleteMetastore_ResponseSchema` | model.ts:298 | 4.8 | -| `unmarshalDeleteMetastoreAssignment_ResponseSchema` | model.ts:302 | 4.8 | -| `unmarshalGetMetastoreSummary_ResponseSchema` | model.ts:306 | 4.8 | -| `unmarshalListMetastores_ResponseSchema` | model.ts:353 | 4.8 | -| `unmarshalMetastoreAssignmentSchema` | model.ts:366 | 17.3 | -| `unmarshalMetastoreInfoSchema` | model.ts:379 | 17.3 | -| `unmarshalUpdateMetastoreAssignment_ResponseSchema` | model.ts:425 | 4.8 | -| `marshalCreateMetastoreSchema` (untyped) | model.ts:428 | E | -| `marshalCreateMetastoreAssignmentSchema` (untyped) | model.ts:473 | E | -| `marshalUpdateMetastoreSchema` (untyped) | model.ts:485 | E | -| `marshalUpdateMetastoreAssignmentSchema` (untyped) | model.ts:534 | E | -| `Client` (bare name) | client.ts:61 | 11.6 | +| `MetastoreInfo` | model.ts:191 | 6.1, 8.1, 11.3 | +| `MetastoreInfo.metastoreId` | model.ts:213 | 15.1, 16.2 | +| `MetastoreInfo.globalMetastoreId` | model.ts:227 | 6.3, 15.6 | +| `UpdateMetastore` | model.ts:232 | 11.3, 12.1, 12.3 | +| `UpdateMetastore.id` | model.ts:234 | 1.1, 5.1, 12.1, 12.2 | +| `UpdateMetastore.newName` | model.ts:236 | 11.7, 12.1 | +| `UpdateMetastore.name` | model.ts:238 | 11.7, 12.1 | +| `UpdateMetastore.metastoreId` | model.ts:258 | 12.1, 12.2 | +| `UpdateMetastoreAssignment` | model.ts:277 | 11.4 | +| `UpdateMetastoreAssignment.workspaceId` | model.ts:279 | 15.2 | +| `UpdateMetastoreAssignment_Response` | model.ts:291 | 4.7 | | `Client.createMetastore` | client.ts:92 | — | | `Client.createMetastoreAssignment` | client.ts:122 | — | | `Client.deleteMetastore` | client.ts:151 | C | | `Client.deleteMetastoreAssignment` | client.ts:182 | B, D | -| `Client.getCurrentMetastoreAssignment` | client.ts:216 | 14.1 | -| `Client.getMetastore` | client.ts:241 | 14.1, C | -| `Client.getMetastoreSummary` | client.ts:269 | 6.8, 14.1 | +| `Client.getCurrentMetastoreAssignment` | client.ts:216 | 13.1 | +| `Client.getMetastore` | client.ts:241 | 13.1, C | +| `Client.getMetastoreSummary` | client.ts:269 | 6.8, 13.1 | | `Client.listMetastores` | client.ts:305 | — | -| `Client.listMetastoresIter` | client.ts:338 | 9.1, 14.3 | | `Client.updateMetastore` | client.ts:360 | C | | `Client.updateMetastoreAssignment` | client.ts:390 | B | -| `req` / `resp` parameter and locals | client.ts (many) | 5.2, 5.3, 11.3 | -| `pkgJson` import alias | client.ts:19 | 5.4 | | `${req.id ?? ''}` URL substitution | client.ts:155, 245, 364 | C | | `${req.workspaceId ?? ''}` URL substitution | client.ts:126, 186, 394 | B | -| `Host is required.` bare Error | client.ts:72 | F | +| `Host is required.` bare Error | client.ts:72 | E | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `marshal…` / `unmarshal…` verbs | model.ts (many) | 11.5 | -| `…Schema` suffix | model.ts (many) | 8.3, 17.3 | -| `index.ts` re-exports underscored names | index.ts:5, 9, 12, 14, 17, 19, 21, 26 | G | -| `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` | index.ts:5, 15 | H | +| `index.ts` re-exports underscored names | index.ts:5, 9, 12, 14, 17, 19, 21, 26 | F | +| `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` | index.ts:5, 15 | G | --- ## Recommended priority order -1. **Disambiguate the four name/id-like fields on `UpdateMetastore`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§13.1, §12.7, §1.1) -2. **Drop the `_Enum` suffix from `DeltaSharingScope_Enum` and rename the sibling `DeltaSharingScope` export to resolve the naming collision.** (§12.1, §4.1, §17.1, §H) +1. **Disambiguate the four name/id-like fields on `UpdateMetastore`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§12.1, §11.7, §1.1) +2. **Drop the `_Enum` suffix from `DeltaSharingScope_Enum` and rename the sibling `DeltaSharingScope` export to resolve the naming collision.** (§11.1, §4.1, §16.1, §G) 3. **Drop proto-style `_Response` identifiers** (`CreateMetastoreAssignment_Response`, `DeleteMetastore_Response`, `DeleteMetastoreAssignment_Response`, `GetMetastoreSummary_Response`, `ListMetastores_Response`, `UpdateMetastoreAssignment_Response`). (§4.2-4.7) -4. **Strip read-only fields from `CreateMetastore` / `UpdateMetastore`.** (§13.3, §12.3) -5. **Decide whether `GetMetastoreSummary_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§6.7, §12.2) -6. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§6.8, §14.1) -7. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §12.5) +4. **Strip read-only fields from `CreateMetastore` / `UpdateMetastore`.** (§12.3, §11.3) +5. **Decide whether `GetMetastoreSummary_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§6.7, §11.2) +6. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§6.8, §13.1) +7. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §11.5) 8. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) -9. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match the precedent set by `deltaSharingRecipientTokenLifetimeInSeconds`. (§16.5) +9. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match common conventions. (§15.5) 10. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index 172b6f20..1d16ec2f 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,15 +8,15 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 65 +**Total weird names flagged:** 61 ## Summary | Severity | Count | | --- | --- | | High | 21 | | Medium | 24 | -| Low | 14 | -| Observation | 6 | +| Low | 12 | +| Observation | 4 | ## High severity @@ -718,33 +718,16 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; fix doc-comment. - **Rationale:** Generator bug; users will read the doc. -### 63. `unmarshalActivitySchema`, `unmarshalCommentObjectSchema`, - `unmarshalTransitionRequestSchema` — `model.ts:1141, 1177, 1664` -- **Why weird:** Three near-identical Zod schemas for three identical - types (#7). -- **Category:** 12 (duplicate concept). -- **Suggested name:** Single `unmarshalActivitySchema` once #7 collapses - the types. -- **Rationale:** Mechanical cascade from #7. - -### 64. `marshalRegisteredModelTagSchema` / - `marshalModelVersionTagSchema` — `model.ts:1856, 1866` -- **Why weird:** Two schemas for two identical-shape types (#35). -- **Category:** 12 (duplicate concept). -- **Suggested name:** Single `marshalTagSchema` once #35 collapses. -- **Rationale:** Mechanical cascade from #35. - ## Observations -### 65. Wire/TS divergence is massive -The model file is ~2000 lines for ~33 user-facing types. ~870 lines are -type declarations, ~860 lines are unmarshal schemas, ~270 lines are -marshal schemas. Plus 33 `*_Response` types with `eslint-disable` lints. -This is the highest disable-count-per-type density I've seen — a sign -the generator's Go/proto idioms are fighting TS conventions throughout. +### 63. `*_Response` underscore lint-disable density +The model file has 33 `*_Response` types, each carrying an +`eslint-disable @typescript-eslint/naming-convention` comment to permit +the underscore. This is the highest disable-count-per-type density I've +seen — a sign the generator's proto idioms are fighting TS conventions. - **Category:** Observation. -### 66. Both `modelregistry` and `registeredmodels` exist as packages +### 64. Both `modelregistry` and `registeredmodels` exist as packages The user instruction calls out this duplication. Cross-package overlap: - `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` (registeredmodels) — same concept, different names. @@ -762,7 +745,7 @@ The user instruction calls out this duplication. Cross-package overlap: Documentation does not direct users to one or the other. - **Category:** 12 (duplicate concepts — across packages). -### Action-verb conventions in `Client` +### 65. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -771,17 +754,7 @@ reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). -### `flattenQueryParams` (`utils.ts:123`) is unused in this package -Same observation as in other audits: a generator-shipped helper is -exported even though only `marshalRequest` is consumed by the client. -- **Category:** Observation. - -### `parseResponse` / `marshalRequest` verb asymmetry (`utils.ts:113, 119`) -Same generator-level observation: opposite operations use mismatched -verbs (`parse` vs `marshal`). -- **Category:** 17. - -### Acronym casing inside doc-comments +### 66. Acronym casing inside doc-comments `MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` (`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md index d185315b..9cca94ee 100644 --- a/.agent/naming-audit/modelservingdebug.md +++ b/.agent/naming-audit/modelservingdebug.md @@ -4,15 +4,15 @@ **Package name:** `@databricks/sdk-modelservingdebug` **Versions audited:** v1 **Inferred domain:** Diagnostic / troubleshooting endpoints carved out of the Model Serving API. Three HTTP GETs hanging off `/api/2.0/serving-endpoints/{name}`: `GET /metrics` returns a Prometheus/OpenMetrics text blob (streamed body), `GET /served-models/{servedModelName}/logs` returns the most recent server stdout lines, and `GET /served-models/{servedModelName}/build-logs` returns the served-entity environment build logs. -**Total weird names flagged:** 32 +**Total weird names flagged:** 22 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 13 | -| Low | 8 | -| Observation | 2 | +| High | 8 | +| Medium | 7 | +| Low | 6 | +| Observation | 1 | ## Inventory @@ -223,26 +223,7 @@ suggestion below. Guide § Identifiers (https://google.github.io/styleguide/tsguide.html#identifiers). -### 5. Request types lack `Request` suffix; response types have `_Response` — `model.ts:19,24,37` -- **Why weird:** Asymmetric: `GetServedModelLogs` (request, no suffix) - paired with `GetServedModelLogs_Response` (response, suffixed). The - bare `GetServedModelLogs` reads like a verb-as-type — "do the action - GetServedModelLogs". Reading - `function f(req: GetServedModelLogs)` is jarring; the type *is* the - action, not a value. Compare to other audited packages - (`endpoints.GetEndpointRequest`, `customllms.GetCustomLlmRequest`) - where the convention is `*Request`/`*Response`. -- **Category:** 17 (inconsistent action verb-form between request and - response), 14 (Go-style `Get*` as type name). -- **Suggested name:** Add `Request` suffix to all three: - `GetExportEndpointMetricsRequest`, - `GetServedModelBuildLogsRequest`, - `GetServedModelLogsRequest`. Pair with `*Response` (no underscore, - per #4) on the response side. -- **Rationale:** Symmetry. `Request`/`Response` is the project - precedent set by `endpoints`, `customllms`, and others. - -### 6. `name` field on every request — `model.ts:21,26,39` +### 5. `name` field on every request — `model.ts:21,26,39` - **Why weird:** All three request types have `name?: string` and the JSDoc has to spell out "The name of the serving endpoint" each time. Bare `name` is the most generic identifier possible — readers without @@ -262,7 +243,7 @@ suggestion below. makes the pairing with `servedModelName` parallel (`endpointName` + `servedModelName`). -### 7. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:69,96,124` +### 6. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:69,96,124` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — meaning if the caller @@ -281,7 +262,7 @@ suggestion below. (https://google.aip.dev/122) which mandates path parameters be required. -### 8. `servedModelName` doc echoes the field name three times — `model.ts:27-28,40-41` +### 7. `servedModelName` doc echoes the field name three times — `model.ts:27-28,40-41` - **Why weird:** JSDoc on `GetServedModelBuildLogs.servedModelName` reads "The name of the served model that build logs will be retrieved for. This field is required." The field name already @@ -299,7 +280,7 @@ suggestion below. identifier + JSDoc; the doc carrying no information beyond what the name says is a footgun for consumers. -### 9. `GetServedModelLogs_Response.logs: string` is a single blob — `model.ts:47` +### 8. `GetServedModelLogs_Response.logs: string` is a single blob — `model.ts:47` - **Why weird:** The field is named `logs` (plural) but typed as a single `string`. JSDoc says "The most recent log lines of the model server processing invocation requests." So it's many log *lines* @@ -318,7 +299,7 @@ suggestion below. ## Medium severity -### 10. `GetServedModelBuildLogs.name` clashes with `GetServedModelBuildLogs.servedModelName` — `model.ts:26,28` +### 9. `GetServedModelBuildLogs.name` clashes with `GetServedModelBuildLogs.servedModelName` — `model.ts:26,28` - **Why weird:** Two name fields on one struct: `name` (endpoint name) and `servedModelName` (served model name). The bare `name` looks like *the* name of the request entity (which a reader would assume is the @@ -331,7 +312,7 @@ suggestion below. - **Rationale:** When two `*Name` fields exist on one struct, neither should be bare `name`. -### 11. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:16` +### 10. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:16` - **Why weird:** The only field is `contents?: ReadableStream | undefined`. Web Fetch standard (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own @@ -345,7 +326,7 @@ suggestion below. - **Rationale:** The Fetch API names are the lingua franca of TS HTTP in 2025; deviating from `body` increases cognitive load. -### 12. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:65-68` +### 11. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:65-68` - **Why weird:** The method name says `EndpointMetrics`, the response type says `ExportMetricsResponse` (no `Endpoint`). Inconsistent qualifier between method and return type. A reader greping for @@ -360,7 +341,7 @@ suggestion below. - **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. -### 13. `Get*` prefix on three of three methods — `client.ts:65,92,120` +### 12. `Get*` prefix on three of three methods — `client.ts:65,92,120` - **Why weird:** Every method here is a GET. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations @@ -377,7 +358,7 @@ suggestion below. (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. -### 14. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:92,120` +### 13. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:92,120` - **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a @@ -394,7 +375,7 @@ suggestion below. and `getServedModelBuildLogs` is the special case; the API doesn't advertise the asymmetry. -### 15. `GetServedModelLogs.servedModelName` doc says "The name of the served model that logs will be retrieved for" — passive voice — `model.ts:41` +### 14. `GetServedModelLogs.servedModelName` doc says "The name of the served model that logs will be retrieved for" — passive voice — `model.ts:41` - **Why weird:** Passive voice "that logs will be retrieved for" reads like a phrase translated from a proto comment. Active voice is shorter: "The served model whose logs to retrieve." Pure JSDoc @@ -405,30 +386,7 @@ suggestion below. - **Suggested name:** No rename; rewrite JSDoc in active voice. - **Rationale:** API surface clarity. Not blocking. -### 16. `unmarshalGetServedModelBuildLogs_ResponseSchema` is 41 characters of noise — `model.ts:51` -- **Why weird:** Schema names embed the *full* request type name - including the `_Response` underscore artefact. `unmarshal` + nested - type name = 41 chars for one symbol. Three eslint-disable directives - in a row (model.ts:31, 44, 50, 60) make the readability worse. -- **Category:** 7 (overly verbose), 4 (underscore in TS identifier), - 20 (type-suffix tautology — the schema's `` argument already - says `Response`). -- **Suggested name:** `unmarshalServedModelBuildLogs` (drop `Get`, - drop `_Response` — the symbol with no suffix is a fine name for - "the unmarshal for the build-logs response"). Pair with the - `Request`/`Response` symmetry fix in #5. -- **Rationale:** Schema names ride on type names; fixing the type - names cascades. - -### 17. `unmarshalX_ResponseSchema` violates camelCase — `model.ts:51,61` -- **Why weird:** The capital `R` in `_ResponseSchema` is half-word - inside what should be camelCase. Same eslint suppression pattern - as #4. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** See #16. -- **Rationale:** Same as #4 / #16. - -### 18. `PACKAGE_SEGMENT` const is unsized — `client.ts:34-37` +### 15. `PACKAGE_SEGMENT` const is unsized — `client.ts:34-37` - **Why weird:** SCREAMING_SNAKE_CASE in TS is a Go/Python carryover. Google TS Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) @@ -442,67 +400,9 @@ suggestion below. `PACKAGE_SEGMENT` const, so this is a cross-package finding — fix at the generator. -### 19. `HttpCallOptions` and `executeHttpCall` vs `executeCall` overlap — `utils.ts:15,26,65` -- **Why weird:** Three callable surfaces with overlapping names: - - `executeCall(call: Call, options?: CallOptions)` — wraps the retrier. - - `executeHttpCall(opts: HttpCallOptions): Promise` — - sends one HTTP request and reads the body. - - `sendAndCheckError(opts: HttpCallOptions): Promise` — - sends one HTTP request and returns the response (body untouched). - All three "execute calls" but at different abstraction levels. - `executeHttpCall` *also* checks errors and reads the body; - `sendAndCheckError` checks errors but doesn't read the body. The - names don't communicate the body-reading behaviour. -- **Category:** 12 (duplicate concept), 1 (vague), 17 (inconsistent - verbs — `execute*` vs `sendAndCheckError`). -- **Suggested name:** Rename to convey the body behaviour: - - `executeHttpCall` → `sendAndReadBody` (or `executeAndReadBody`). - - `sendAndCheckError` stays (it's the most-specific name). - - `executeCall` → `runWithRetries` or `runCall`. -- **Rationale:** Today a reader has to read both function bodies to - pick the right one. Names should describe the side effect on the - body stream. - -### 20. `marshalRequest` is unused inside this package — `utils.ts:119` -- **Why weird:** `marshalRequest(data, schema)` is exported from - `utils.ts` but the only call site in this package's `client.ts` is - none (all three methods are GETs with no body). The function exists - because `utils.ts` is generator-copied verbatim across packages. - Dead code is a naming smell because it inflates the surface area - the reader has to keep in their head. -- **Category:** Observation (cross-package generator artefact). -- **Suggested name:** No rename; flag for generator-level dead-code - pruning. -- **Rationale:** Public utility surface in a package that doesn't use - it is dead weight. - -### 21. `flattenQueryParams` is unused inside this package — `utils.ts:123` -- **Why weird:** Same as #20. None of the three GETs construct query - params (all data is in the URL path). Exported function with zero - internal users. -- **Category:** Observation (cross-package generator artefact). -- **Suggested name:** No rename; flag for generator-level dead-code - pruning. -- **Rationale:** Same as #20. - -### 22. `executeCall` second parameter `options?` is shadowed by `opts` inside — `utils.ts:26-38` -- **Why weird:** `options?: CallOptions` parameter is mapped onto a - local `const opts: Options = {...}`. The name shift `options` → - `opts` happens inline. Both are valid, but inside one 13-line - function they alternate, e.g., `options?.retrier` and - `opts.retrier` would mean different things. Today the code - carefully translates one into the other. -- **Category:** 1 (vague), 17 (inconsistent shortening — `options` vs - `opts`). -- **Suggested name:** Pick one. Either rename the parameter to `opts` - (and use `internalOpts` for the translated value) or keep `options` - and `internalOptions`. -- **Rationale:** Three-letter `opts` shorthand inside a function that - takes `options` is a category-5 cryptic-abbreviation finding. - ## Low severity -### 23. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` +### 16. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` - **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` @@ -516,8 +416,8 @@ suggestion below. that survives review only because nobody wants to argue with the framework. -### 24. `Options` type aliased to internal options shape — `utils.ts:3,30` -- **Why weird:** Same as #23 but for `Options`. `Options` is generic +### 17. `Options` type aliased to internal options shape — `utils.ts:3,30` +- **Why weird:** Same as #16 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen @@ -529,7 +429,7 @@ suggestion below. - **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. -### 25. `userAgent` is built once in the constructor and never refreshed — `client.ts:46,60` +### 18. `userAgent` is built once in the constructor and never refreshed — `client.ts:46,60` - **Why weird:** Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If @@ -540,16 +440,16 @@ suggestion below. freeze in the JSDoc on line 43-46. - **Rationale:** Worth a comment; not a rename target. -### 26. `host` is normalised by trailing-slash strip — `client.ts:52` +### 19. `host` is normalised by trailing-slash strip — `client.ts:52` - **Why weird:** `this.host = options.host.replace(/\/$/, '');` silently rewrites the input. The field name `host` doesn't tell the consumer "we normalise this to no trailing slash". If a debug log later prints `client.host`, it won't match what was passed in. - **Category:** Observation, 6 (mildly misleading). - **Suggested name:** No rename. Add a JSDoc note. -- **Rationale:** Same pattern as #25; cross-package. +- **Rationale:** Same pattern as #18; cross-package. -### 27. `info` local var in the constructor — `client.ts:54,56,57,58,60` +### 20. `info` local var in the constructor — `client.ts:54,56,57,58,60` - **Why weird:** `let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 @@ -561,7 +461,7 @@ suggestion below. `createDefault` factory and the SDK convention). - **Rationale:** Local-scope, low-impact rename. Cross-package. -### 28. `pkgJson` import alias for package.json — `client.ts:19,35,36` +### 21. `pkgJson` import alias for package.json — `client.ts:19,35,36` - **Why weird:** `import pkgJson from '../../package.json' with {type: 'json'};`. The alias name `pkgJson` is cryptic; readers who don't know `pkg` is "package" will guess. The line is unique-per-package @@ -570,30 +470,9 @@ suggestion below. - **Suggested name:** `packageManifest` or `packageJson` (camelCase). - **Rationale:** Trivial fix; cross-package. -### 29. `httpReq` and `httpResp` shorthand inside methods — `client.ts:74,75,99,101,128,129` -- **Why weird:** `const httpReq = buildHttpRequest(...)` and - `const httpResp = await sendAndCheckError(...)`. The `Req`/`Resp` - truncation is shorter by 4 characters and a touch less readable. - TypeScript can autocomplete the longer form, so the savings are - illusory. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `httpRequest`, `httpResponse`. Cross-package - pattern. -- **Rationale:** Minor. Worth normalising at the generator. - -### 30. `e: unknown` catch parameter — `utils.ts:76,167` -- **Why weird:** `} catch (e: unknown) {` — single-letter `e` for the - exception. TS 4.0+ requires the explicit `: unknown`; the variable - name is style. Most codebases use `err` or `error` because `e` is - too overloaded (event handlers also use `e`). -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — sibling - utils.ts files would all need to match). -- **Suggested name:** `error` or `cause`. -- **Rationale:** Low impact, generator-fix only. - ## Observation -### 31. `getReader()` chunk-accumulator in `readAll` is a hot-path candidate — `utils.ts:46-62` +### 22. `getReader()` chunk-accumulator in `readAll` is a hot-path candidate — `utils.ts:46-62` - **Why weird:** `readAll` is the buffering implementation used by every method (including `getServedModelLogs` which can return many KB of text). The chunk-collection loop allocates many intermediate @@ -606,21 +485,3 @@ suggestion below. consumers can iterate the stream. - **Rationale:** Not a naming bug, but the audit covers the function by virtue of its inclusion in `utils.ts`. Worth a note. - -### 32. `getExportEndpointMetrics` returns the raw `httpResp.body` (a stream) — `client.ts:80-82` -- **Why weird:** Method-level inconsistency: of the three methods, - *only* `getExportEndpointMetrics` returns the body stream (the - others read-and-parse). The asymmetry isn't communicated by the - return-type name `ExportMetricsResponse` vs the others' - `GetServedModelLogs_Response`. A reader has to inspect both type - declarations to discover that one is streaming and two are buffered. -- **Category:** 6 (misleading — return type doesn't advertise - streaming). -- **Suggested name:** Either rename the return type to include - `Stream` (e.g., `EndpointMetricsStream` with a `body: ReadableStream`) - or buffer the body inside the SDK (consistent with the other two - methods). The choice depends on consumer needs — metrics blobs - can be large, so the stream is the right shape but it must be - named accordingly. -- **Rationale:** Sibling consistency or explicit streaming naming; - pick one. diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md index 097e1d7c..5a65789d 100644 --- a/.agent/naming-audit/modelservingmanagement.md +++ b/.agent/naming-audit/modelservingmanagement.md @@ -3,15 +3,15 @@ **Path:** `packages/modelservingmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** "Serving endpoint" management — CRUD over inference (model-serving) endpoints, plus a parallel "PT" (provisioned-throughput) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Sibling packages: `modelservingdebug` (logs/metrics), `modelservingquery` (inference). Three packages share the noun "serving endpoint" with no cross-package alignment of how the noun is rendered (this package: `InferenceEndpoint`; debug: `Endpoint`; query: `Endpoint`). -**Total weird names flagged:** 53 +**Total weird names flagged:** 47 ## Summary | Severity | Count | | --- | --- | | High | 13 | -| Medium | 22 | -| Low | 12 | -| Observation | 6 | +| Medium | 18 | +| Low | 11 | +| Observation | 5 | ## High severity @@ -24,13 +24,13 @@ ### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:960` - **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 963) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 965) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. - **Category:** 6 (misleading), 15 (generic field name vs specific type name). -- **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is (the unmarshal maps `served_entities`/`served_models` to either field — see #3). For users, `servedEntities: ServedEntity[]` reads correctly. +- **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. For users, `servedEntities: ServedEntity[]` reads correctly. - **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. ### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:377-391, 393-409, 411-416, 812-830, 906-922` -- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]`. The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." Today the marshal/unmarshal happily round-trip both keys (model.ts:1276-1280, 1297-1302). For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. +- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]`. The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. - **Category:** 12 (duplicate concept), 6 (misleading — deprecated not marked). -- **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely, have the marshaller still read it for back-compat but not surface it. +- **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely. - **Rationale:** Five types times two fields equals ten redundant deprecation lookalikes; every one of them is a footgun. ### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins — `src/v1/model.ts:988, 989, 1013-1023` @@ -158,13 +158,7 @@ - **Suggested name:** Top-level enum `ConfigUpdateState`. Values without prefix: `NOT_UPDATING | IN_PROGRESS | UPDATE_FAILED | UPDATE_CANCELED`. (Note `UPDATE_FAILED` keeps the `UPDATE_` because there are multiple state-like enums; otherwise just `FAILED`.) - **Rationale:** Cuts the call-site length by half. -### 17. Method `httpRequest` (already flagged in #6) duplicate pattern with `getInferenceEndpointSchema` — `src/v1/client.ts:230, 487` -- **Why weird:** Both `getInferenceEndpointSchema` and `httpRequest` set `resp.contents = httpResp.body ?? undefined` — they are the only two methods that bypass the marshal/unmarshal pipeline and return a raw `ReadableStream`. The pattern is duplicated verbatim. The naming is also inconsistent: one method is named for the URL noun (`schema`), the other for the HTTP verb (`request`). A consumer cannot tell from the names that both return raw streams. -- **Category:** 17 (inconsistent verb convention), 12 (duplicate pattern). -- **Suggested name:** Rename consistently: `getInferenceEndpointSchema` → `openApiSchema`; `httpRequest` → `invokeExternalFunction` (per #6). Or extract a `*Raw` suffix: `getInferenceEndpointSchemaRaw`, `invokeExternalFunctionRaw` — at least signal the "raw stream return". -- **Rationale:** Reading the client should tell the user which methods consume the body and which hand back a stream. - -### 18. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:377, 393, 411` +### 17. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:377, 393, 411` - **Why weird:** Three types describe "the config of a serving endpoint": - `EndpointCoreConfig`: input shape (`servedEntities: ServedModel[]`, `servedModels: ServedModel[]`, `trafficConfig`, `autoCaptureConfig`). - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. @@ -175,7 +169,7 @@ - **Suggested name:** Either (a) collapse into one type with optional fields, or (b) give the types names that reflect their *purpose*: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). - **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. -### 19. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:580, 609` +### 18. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:580, 609` - **Why weird:** Two near-duplicate types: - `InferenceEndpoint` (line 580-607): used in `ListInferenceEndpoints_Response.endpoints`. Has 13 fields. - `InferenceEndpointDetailed` (line 609-646): returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. Has 18 fields. @@ -185,13 +179,13 @@ - **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. - **Rationale:** Currently consumers writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. -### 20. `ServedModelLite` lite-variant — `src/v1/model.ts:1013-1023` -- **Why weird:** Same pattern as #19 at the entity level. `ServedModel` (line 960) has 21 fields. `ServedModelLite` (line 1013-1023) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). +### 19. `ServedModelLite` lite-variant — `src/v1/model.ts:1013-1023` +- **Why weird:** Same pattern as #18 at the entity level. `ServedModel` (line 960) has 21 fields. `ServedModelLite` (line 1013-1023) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). - **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). - **Suggested name:** `ServedEntitySummary` (paired with #2 type rename). - **Rationale:** Inconsistent suffix convention across the file. "Lite" is also an LLM-era term that clashes with the OpenAI/Anthropic-flavoured product space. -### 21. `Pt` abbreviation everywhere — `src/v1/client.ts:137, 162, 415, 440` and `src/v1/model.ts:295, 837, 843, 937` +### 20. `Pt` abbreviation everywhere — `src/v1/client.ts:137, 162, 415, 440` and `src/v1/model.ts:295, 837, 843, 937` - **Why weird:** `Pt` is short for "provisioned throughput". The full term ("provisioned throughput") *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`), but the request/response *types* use the abbreviation (`CreatePtEndpoint`, `PutPtEndpointConfig`, `PtEndpointCoreConfig`, `PtServedModel`). So the public surface has: - `client.createProvisionedThroughputInferenceEndpoint(req: CreatePtEndpoint)` — method-full, type-abbreviated. - URL: `/api/2.0/serving-endpoints/pt` — wire-abbreviated. @@ -201,7 +195,7 @@ - **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpoint`, `PutProvisionedThroughputEndpointConfig`, etc. — long but searchable) or contract all (`createPtEndpoint`, `putPtEndpointConfig` — short but cryptic). Pick one. The current half-and-half is the worst option. - **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). -### 22. `CreatePtEndpoint` method-type asymmetry with `CreateInferenceEndpoint` — `src/v1/model.ts:272, 295` +### 21. `CreatePtEndpoint` method-type asymmetry with `CreateInferenceEndpoint` — `src/v1/model.ts:272, 295` - **Why weird:** Sister request types: - `CreateInferenceEndpoint` (full name). - `CreatePtEndpoint` (abbreviated). @@ -211,7 +205,7 @@ - **Suggested name:** `CreateServingEndpoint` and `CreateProvisionedThroughputServingEndpoint` (paired with #1). - **Rationale:** Sibling request types should differ only in the qualifier that actually differs. -### 23. `PutInferenceEndpointConfig` vs `PutPtEndpointConfig` — request shape divergence — `src/v1/model.ts:906, 937` +### 22. `PutInferenceEndpointConfig` vs `PutPtEndpointConfig` — request shape divergence — `src/v1/model.ts:906, 937` - **Why weird:** Two "put endpoint config" requests: - `PutInferenceEndpointConfig`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). - `PutPtEndpointConfig`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). @@ -221,13 +215,13 @@ - **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. - **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. -### 24. `PatchInferenceEndpointTags.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:792-799` +### 23. `PatchInferenceEndpointTags.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:792-799` - **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. That semantics is fine, but the field name does not convey it. - **Category:** 6 (misleading), 15 (generic field name). - **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). - **Rationale:** When the element type changes, the field name should change too. -### 25. `endpointUrl` field domain ambiguity — `src/v1/model.ts:634, 332` +### 24. `endpointUrl` field domain ambiguity — `src/v1/model.ts:634, 332` - **Why weird:** `endpointUrl` appears twice: - `InferenceEndpointDetailed.endpointUrl` (line 634): "Endpoint invocation url if route optimization is enabled for endpoint." - `DataPlaneInfo.endpointUrl` (line 332): "The URL of the endpoint for this operation in the dataplane." @@ -237,7 +231,7 @@ - **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). - **Rationale:** A consumer JOINing the two by `endpointUrl` field name will mismatch them. -### 26. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:581-596, 610-625` +### 25. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:581-596, 610-625` - **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." @@ -247,19 +241,19 @@ - **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. - **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources (e.g. logs that include a `name` that is something else entirely). -### 27. Waiter classes have asymmetric naming — `src/v1/client.ts:515, 595, 675, 755` +### 26. Waiter classes have asymmetric naming — `src/v1/client.ts:515, 595, 675, 755` - **Why weird:** Four waiter classes: - `CreateInferenceEndpointWaiter` - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters — the longest exported class in the file) - `PutInferenceEndpointConfigWaiter` - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) - Three problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #21 where the type is `Pt`); the names communicate "this class waits for X" but the doc-comments on the classes say nothing about what is waited for. -- **Category:** 7 (overly verbose), 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). + Two problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #20 where the type is `Pt`). Sibling request types should differ only in the qualifier that actually differs. +- **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). - **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. - **Rationale:** Four exported waiter classes, each 30+ characters long, each containing five+ identical method-name prefixes that grep the same way as the methods themselves. -### 28. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:571-592, 651-672, 731-752, 811-832` +### 27. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:571-592, 651-672, 731-752, 811-832` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -270,108 +264,72 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 29. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:72` +### 28. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:72` - **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. - **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). - **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). - **Rationale:** Minor; internal. -### 30. `marshalRequest` / `parseResponse` verb asymmetry — `src/v1/utils.ts:113, 119` -- **Why weird:** `parseResponse` (response inbound) vs `marshalRequest` (request outbound). Inverse operations, different verbs. The model file uses `unmarshal*Schema` / `marshal*Schema` for the same pair (line 1053 vs 1813) — internally consistent within `model.ts`, but `utils.ts` uses `parse` not `unmarshal`. Same bug as customllms audit #22. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** Match: `unmarshalResponse` / `marshalRequest`. -- **Rationale:** Pair symmetry. - -### 31. `executeCall` and `executeHttpCall` — utils.ts:26, 65 -- **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + APIError check). Easy to confuse at the call site. Same as customllms audit #21. -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. -- **Rationale:** Names should differ in more than the `Http` infix. - -### 32. `HttpCallOptions` collides with `CallOptions` and `Options` and `ClientOptions` — `src/v1/utils.ts:15` -- **Why weird:** Four "options" types in scope in `utils.ts`: - - `Options` from `@databricks/sdk-core/api` (line 3) - - `CallOptions` from `@databricks/sdk-options/call` (line 12) - - `ClientOptions` (in `client.ts`) - - `HttpCallOptions` (this file, line 15) - - Each is conceptually different. The naming makes them look like a hierarchy (`ClientOptions` → `CallOptions` → `Options`), but they are not. `HttpCallOptions` in particular is an internal arg-bag (`{request, httpClient, logger}`), not a user-facing tuning object. -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `HttpCallContext` (it is a context object, not options). -- **Rationale:** Same as customllms audit #23. - -### 33. `EndpointTag` versus `tags` field — `src/v1/model.ts:418, 281, 304, 594, 628` -- **Why weird:** Tag type `EndpointTag` (key + value). Field `tags: EndpointTag[]` appears on 5 types. The type name carries the `Endpoint` qualifier even though tags are scoped to the endpoint already (the type only appears on endpoint types). Compare to `RateLimit` (no `Endpoint` prefix) and `Route` (no `Endpoint` prefix) on the same types. Inconsistent qualifier policy. -- **Category:** 7 (verbose qualifier), 17 (inconsistent: `EndpointTag` but `RateLimit`/`Route`). -- **Suggested name:** `Tag` (drop prefix) for consistency with `RateLimit` / `Route` siblings. -- **Rationale:** Either all child types carry the `Endpoint*` prefix or none do. - -### 34. `creationTimestamp` field is a `number` (Unix seconds) named like a string — `src/v1/model.ts:586, 614, 997` -- **Why weird:** `creationTimestamp?: number` with JSDoc "The timestamp when the endpoint was created in Unix time." The type is `number`; the name `creationTimestamp` does not communicate units (ms? s? ns?). The customllms audit (#11) flagged the same field as a candidate for `createdAt` or `createTime` per Google AIP-142 (https://google.aip.dev/142). Also the field is a *raw number*, not `Temporal.Instant` — inconsistent with the SDK's apparent move toward `Temporal` (the customllms package uses `Temporal.Instant`, this package uses raw number). -- **Category:** 17 (cross-package inconsistency), 19 (underspecified). -- **Suggested name:** `createTime: Temporal.Instant` (matches AIP-142 and customllms convention). -- **Rationale:** Two packages, two conventions for the same domain concept. - -### 35. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:943-950, 93-107` -- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:383 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #18: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. +### 29. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:943-950, 93-107` +- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:383 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #17: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. - **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). - **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimits*` types `@deprecated` in JSDoc. - **Rationale:** Same pattern repeated; same fix. ## Low severity -### 36. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` +### 30. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` - **Why weird:** Field repeats the provider name (`ai21labs`) because the type is named `Ai21LabsConfig`. Reading `config.ai21labsApiKey` inside an `Ai21LabsConfig` is redundant — the only key here is going to be an AI21 Labs API key. Same pattern repeats for every provider config (`anthropicApiKey` inside `AnthropicConfig`, `cohereApiKey` inside `CohereConfig`, etc.). - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** `apiKey` / `apiKeyPlaintext` inside `Ai21LabsConfig`. Wire stays `ai21labs_api_key`. - **Rationale:** Compare to `OpenAiConfig.openaiApiKey` (same redundancy), `CohereConfig.cohereApiKey` (same), `AnthropicConfig.anthropicApiKey` (same), `PaLmConfig.palmApiKey` (same), `DatabricksModelServingConfig.databricksApiToken` (same). Six provider configs, six instances of the redundancy. The wire forces the prefix (`anthropic_api_key`); TS does not. -### 37. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields +### 31. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields - **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. - **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). - **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. - **Rationale:** The "must specify exactly one" constraint is invisible to the type system. -### 38. `valid_topics` / `invalid_keywords` — `src/v1/model.ts:118, 123` +### 32. `valid_topics` / `invalid_keywords` — `src/v1/model.ts:118, 123` - **Why weird:** Two list fields on `AiGuardrailParameters`. `validTopics` is the list of *allowed* topics; `invalidKeywords` is the list of *blocked* keywords. So one is a denylist, one is an allowlist. The opposite-polarity naming (`valid*` for allowlist, `invalid*` for denylist) reads correctly *only* if you read both docs. A user skimming the fields will see "valid topics" and "invalid keywords" and not realise the polarity flipped. - **Category:** 6 (misleading), 17 (inconsistent polarity). - **Suggested name:** `allowedTopics` / `blockedKeywords`. - **Rationale:** Allowlist/denylist naming convention is well-established (https://www.ncsc.gov.uk/blog-post/terminology-its-not-black-and-white). -### 39. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` — `src/v1/model.ts:371, 373` +### 33. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` — `src/v1/model.ts:371, 373` - **Why weird:** Field name reads as an event handler (`onUpdateSuccess` is a JS convention for "callback when update succeeds"). But the field is a `string[]` of email addresses. Not a callback. The `on*` prefix is borrowed from JS event-handler-naming and is misleading here. - **Category:** 6 (misleading — `on*` implies callback). - **Suggested name:** `notifyOnUpdateSuccess` / `notifyOnUpdateFailure` (verb), or `updateSuccessRecipients` / `updateFailureRecipients` (noun). - **Rationale:** `on*` in a JS context is a strong signal of "event handler"; using it for email lists violates that signal. -### 40. `Route.servedModelName` / `servedEntityName` — already flagged in #11 +### 34. `Route.servedModelName` / `servedEntityName` — already flagged in #11 - **Why weird:** Cross-reference. -### 41. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` -- **Why weird:** Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added (e.g. `mistralConfig`), the discriminated union types it correctly, but the marshal/unmarshal cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary (#9). This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. +### 35. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +- **Why weird:** Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added (e.g. `mistralConfig`), the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary (#9). This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. - **Category:** Observation / 12. - **Suggested name:** No rename; flag as generator review. - **Rationale:** Names look clean; runtime is fragile. -### 42. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:456` +### 36. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:456` - **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 962). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). - **Category:** 1 (vague), 15 (generic name across types). - **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. - **Rationale:** Disambiguates from `ServedModel.name`. -### 43. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:454` +### 37. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:454` - **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. - **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). - **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. - **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. -### 44. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:977` -- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #43: a string field with a documented but unenforced enum. +### 38. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:977` +- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #37: a string field with a documented but unenforced enum. - **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). - **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). - **Rationale:** Type-narrowing fix; minor. -### 45. `instanceProfileArn` on `ServedModel` AND `AmazonBedrockConfig` — `src/v1/model.ts:181, 993` +### 39. `instanceProfileArn` on `ServedModel` AND `AmazonBedrockConfig` — `src/v1/model.ts:181, 993` - **Why weird:** Same field name on two unrelated types with very different semantics: - `AmazonBedrockConfig.instanceProfileArn`: "ARN of the instance profile that the *external model* will use to access AWS resources." (Used to authenticate to AWS Bedrock.) - `ServedModel.instanceProfileArn`: "ARN of the instance profile that the *served entity* uses to access AWS resources." (Used by the Databricks runtime serving the model.) @@ -381,21 +339,15 @@ - **Suggested name:** `bedrockInstanceProfileArn` (on `AmazonBedrockConfig`) and `servingInstanceProfileArn` (on `ServedModel`). - **Rationale:** Disambiguation; minor since the enclosing type makes it clear in IDE. -### 46. `FoundationModel.docs` field name — `src/v1/model.ts:523` +### 40. `FoundationModel.docs` field name — `src/v1/model.ts:523` - **Why weird:** `docs?: string` on `FoundationModel`. The field name "docs" reads as "documentation, plural". Likely a URL or a long-form doc string. The JSDoc is empty — the whole type has only the comment "All fields are not sensitive as they are hard-coded in the system and made available to customers." (line 519). No field-level doc. - **Category:** 1 (vague), 19 (no documentation). - **Suggested name:** `docsUrl` (if URL) or `documentation` (if prose). - **Rationale:** Bare `docs` is the kind of field name that survives generator passes because no human reviews each field. -### 47. Four waiter classes with identical bodies — `src/v1/client.ts:515-833` -- **Why weird:** `CreateInferenceEndpointWaiter`, `CreateProvisionedThroughputInferenceEndpointWaiter`, `PutInferenceEndpointConfigWaiter`, `PutProvisionedThroughputInferenceEndpointConfigWaiter` — four classes, each ~80 lines, each *byte-identical* except for the class name. Naming hides the duplication. -- **Category:** 12 (duplicate concept). -- **Suggested name:** Single `InferenceEndpointConfigUpdateWaiter` class; replace four with one. The four methods become factory functions on the client. -- **Rationale:** When four classes share 100% of their bodies, having four names is misdirection. - ## Observations -### 48. Mixed naming convention for the same product across three sibling packages +### 41. Mixed naming convention for the same product across three sibling packages The Databricks "Serving Endpoints" product spans three packages in this SDK: - `modelservingmanagement`: types use `InferenceEndpoint*`. - `modelservingdebug`: types use `Endpoint` (e.g. `GetExportEndpointMetrics`). @@ -404,21 +356,21 @@ The Databricks "Serving Endpoints" product spans three packages in this SDK: No two packages agree on the noun. The wire uniformly uses `serving-endpoints`. SDK consumers chaining all three packages will see three different names for one concept. - **Category:** 17 (cross-package inconsistency). -### 49. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 42. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` Same as customllms #28 — every generated package carries this unused export. -### 50. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:67` +### 43. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:67` Same as customllms #24 — internal user-agent constant. -### 51. `Headers` constructor used four times in client.ts — `src/v1/client.ts:108, 145, 184, 213, ...` +### 44. `Headers` constructor used four times in client.ts — `src/v1/client.ts:108, 145, 184, 213, ...` Each method instantiates a `new Headers({'Content-Type': 'application/json'})` then `.set('User-Agent', this.userAgent)`. Naming-wise this is fine (Headers is the standard web API name), but the pattern is duplicated 11 times in the file. Not a naming bug; observation only. - **Category:** 12 (duplicate pattern across methods). -### 52. Verb-tense consistency in `Client` — observation of best practice +### 45. Verb-tense consistency in `Client` — observation of best practice The client uses `create`/`delete`/`get`/`list`/`patch`/`put`/`update` plus the outlier `httpRequest` (see #6) and the four `*Waiter` factory methods. Apart from `httpRequest`, the verbs are consistent. Worth flagging as a positive. - **Category:** 17 (reversed — explicit consistency). -### 53. `httpRequest` is sole non-CRUD method +### 46. `httpRequest` is sole non-CRUD method The client mixes serving-endpoint CRUD with one orthogonal "invoke through UC connection" operation. This is a structural smell more than a naming smell, but worth flagging because the misplaced method makes the package-level naming (`modelservingmanagement`) even less accurate. - **Category:** Observation / 14. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index e177a330..e1adf5e2 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -11,7 +11,7 @@ **Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. -**Total weird names flagged:** 34 +**Total weird names flagged:** 33 --- @@ -51,8 +51,7 @@ | 30 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | | 31 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | | 32 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | -| 33 | Low | `model.ts` schema | `marshalQueryEndpointInputSchema` / `unmarshalQueryEndpointResponseSchema` | Go/Java-style "marshal/unmarshal" verbs in TS (codified at generator) | -| 34 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | +| 33 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | --- @@ -570,20 +569,7 @@ index?: number | undefined; `index` without qualification: index inside what? `responseIndex`, `embeddingIndex`, or `position` would be specific. Pairs with `V1ResponseChoiceElement.index` and `DataframeSplitInput.index` — three "index" fields with three different meanings. -### 33. `marshal*Schema` / `unmarshal*Schema` — Go/Java idiom - -**Location:** `src/v1/model.ts:198-342` - -**Category:** 14 (Go/Java-style names) - -```ts -export const unmarshalChatMessageSchema: z.ZodType = ... -export const marshalChatMessageSchema: z.ZodType = ... -``` - -`marshal`/`unmarshal` are Go-flavoured verbs. Idiomatic TS uses `serialize`/`deserialize` or `encode`/`decode` (Zod itself uses `parse` / `safeParse`). The pattern is codified across the entire generated SDK, so this is a generator-level concern rather than a per-package fix. Also note the `Schema` suffix on Zod consts is tautological — `unmarshalChatMessage` would be enough, or simply colocate the zod schema with the type. - -### 34. `flattenQueryParams` — orphaned export with conflicting "Query" +### 33. `flattenQueryParams` — orphaned export with conflicting "Query" **Location:** `src/v1/utils.ts:123-150` diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 2e82b928..d777b807 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,15 +3,15 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 26 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 9 | -| Low | 7 | +| Medium | 8 | +| Low | 6 | | Observation | 4 | ## Summary table @@ -28,22 +28,20 @@ | 8 | Medium | `model.ts:23-28` / `:139-146` | `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` | 7 (overly verbose), 8 (redundant `Request` suffix conjoined with full noun phrase) | | 9 | Medium | `model.ts:66-70` | `ListNotificationDestinationsResponse` | 7 (overly verbose), 8 (redundant `Response` suffix) | | 10 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | -| 11 | Medium | `client.ts:186-201` | `listNotificationDestinationsIter` | 5 (cryptic abbreviation `Iter`) | -| 12 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | -| 13 | Medium | `model.ts:73`, `:107` | `id` (UUID) | 19 (underspecified ID) | -| 14 | Medium | `model.ts:118` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | -| 15 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | -| 16 | Low | `model.ts:5-11` | enum values are SCREAMING_SNAKE_CASE in TS | 4 (underscores in TS identifier strings) | -| 17 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | -| 18 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | -| 19 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | -| 20 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | -| 21 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | -| 22 | Low | `utils.ts:113`, `:119` | `parseResponse` / `marshalRequest` verb mismatch | 17 (inconsistent action verbs) | -| 23 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 24 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | -| 25 | Obs | `index.ts:5-23` | Re-exports the verbose names verbatim, no friendlier aliases | — | -| 26 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | +| 11 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | +| 12 | Medium | `model.ts:73`, `:107` | `id` (UUID) | 19 (underspecified ID) | +| 13 | Medium | `model.ts:118` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | +| 14 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | +| 15 | Low | `model.ts:5-11` | enum values are SCREAMING_SNAKE_CASE in TS | 4 (underscores in TS identifier strings) | +| 16 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | +| 17 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | +| 18 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | +| 19 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | +| 20 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | +| 21 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 22 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 23 | Obs | `index.ts:5-23` | Re-exports the verbose names verbatim, no friendlier aliases | — | +| 24 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | ## High severity @@ -59,7 +57,7 @@ } ``` - **Why weird:** Exported at package root as just `DestinationType`. The word "destination" is overloaded across the SDK — there is a `destination` concept in jobs (`webhook destination`), workflows (`sink destination`), and infra (`DBFS destination`). A user `import { DestinationType } from '@databricks/sdk-notificationdestinations/v1'` and then mixing it with `import { DestinationType } from '@databricks/sdk-pipelines/v1'` (if it existed) will get a name collision. Also, the values are not "destination types" but "notification channels"; the enum mixes the term-of-art ("destination" = the addressable target) with the type-of-target. Compare with `notification-destinations` REST path: the enum could be `NotificationChannel` or `NotificationDestinationKind`. -- **Category:** 1 (vague/generic), 2 (the enum prefix `Destination` is redundant with the field name `destinationType` — see also finding 15). +- **Category:** 1 (vague/generic), 2 (the enum prefix `Destination` is redundant with the field name `destinationType` — see also finding 14). - **Suggested name:** `NotificationChannel` (mirrors how the Go SDK names protobuf enums for kindred resources) or, less invasive, `NotificationDestinationType`. - **Rationale:** Domain-anchored enum names protect users from cross-package collisions and read better in IDE autocomplete (`NotificationChannel.SLACK` vs `DestinationType.SLACK`). @@ -78,7 +76,7 @@ The same applies to Microsoft Teams: `MICROSOFT_TEAMS`, `microsoftTeams` ($case), `MicrosoftTeamsConfig`, `microsoft_teams` (wire). Only the wire and JSDoc are externally fixed; the TS identifier choices `Pagerduty` (vs `PagerDuty`) and `MicrosoftTeams` (already correct) are an internal choice — and they are not consistent with the brand. The TS Style Guide is explicit: brand acronyms keep their canonical casing in identifiers (PagerDuty, GitHub, GraphQL). `Pagerduty` reads as a typo. - **Category:** 3 (acronym casing inconsistency). -- **Suggested name:** `PagerDutyConfig` (interface), `PagerDuty = 'PAGERDUTY'` (enum value can keep wire string but the **identifier** should be `PagerDuty` if mixed-case enum names were used; SCREAMING_SNAKE is wire-faithful, see finding 16). For consistency at minimum rename `PagerdutyConfig` → `PagerDutyConfig` and the `$case: 'pagerduty'` → `$case: 'pagerDuty'`. +- **Suggested name:** `PagerDutyConfig` (interface), `PagerDuty = 'PAGERDUTY'` (enum value can keep wire string but the **identifier** should be `PagerDuty` if mixed-case enum names were used; SCREAMING_SNAKE is wire-faithful, see finding 15). For consistency at minimum rename `PagerdutyConfig` → `PagerDutyConfig` and the `$case: 'pagerduty'` → `$case: 'pagerDuty'`. - **Rationale:** Brand names are part of the public API surface; users reading IDE autocomplete should see `PagerDutyConfig` matching the company's own capitalisation. The cost is one schema rename across `unmarshalConfigSchema`'s discriminator strings — the wire JSON key stays `pagerduty`. ### 3. `DestinationType.WEBHOOK` corresponds to `GenericWebhookConfig` — misleading enum vs config asymmetry — `src/v1/model.ts:8`, `:42-55`, `:17` @@ -159,7 +157,7 @@ 3. The paired fields are **modal** — on input you set `url`, on output you read `urlSet`. The type system has no way to express this; both fields are simultaneously optional, so a user could try to set `urlSet: true` on input and the server will silently ignore it. - **Category:** 6 (misleading — three-valued boolean), 15 (generic field-naming pattern losing meaning). - **Suggested name:** Rename the pattern to `hasUrl`, `hasUsername`, etc. (English-correct boolean predicates). Better: split the input and output types so input has `url` only and output has `hasUrl` only. Or merge into a union: `url?: { write: string } | { read: { isSet: boolean } }`. -- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 24) hint that the type was originally split in the API spec and was flattened for TS. +- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 22) hint that the type was originally split in the API spec and was flattened for TS. ### 8. `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` — overly verbose — `src/v1/model.ts:23-28`, `:139-146` - **Code:** @@ -188,7 +186,7 @@ nextPageToken?: string | undefined; } ``` -- **Why weird:** Two fields, 41-character type name. The JSDoc says "Page token for next of results" — broken English (should be "Page token for next page of results" or "Page token for the next set of results"). And see #12 for `results`. +- **Why weird:** Two fields, 41-character type name. The JSDoc says "Page token for next of results" — broken English (should be "Page token for next page of results" or "Page token for the next set of results"). And see #11 for `results`. - **Category:** 7 (verbose), 8 (`Response` suffix added on top of the verb-prefixed noun phrase). - **Suggested name:** `ListPage` — a generic page wrapper used across the SDK. Or `NotificationDestinationPage`. @@ -204,20 +202,7 @@ - **Suggested name:** `NotificationDestinationsClient`, or expose only the namespace import (`import * as notificationDestinations from '@databricks/sdk-notificationdestinations/v1'`). - **Rationale:** Cross-SDK consistency, but every consumer pays the rename cost. Worth a generator-level fix. -### 11. `listNotificationDestinationsIter` — cryptic `Iter` suffix — `src/v1/client.ts:186-201` -- **Code:** - ```ts - async *listNotificationDestinationsIter( - req: ListNotificationDestinationsRequest, - options?: CallOptions - ): AsyncGenerator { ... } - ``` -- **Why weird:** "Iter" is a Go-ism (`Iterator()` method, `iter.Seq2` etc.). In TS the conventional name for an async iterator method is `*` syntax with no special suffix, or `stream*`, or just the verb in the imperative form. `listIter` reads as a typo or an abbreviation; the canonical TS name would be `listAll` (eagerly), `iterAll`, or simply expose it as `[Symbol.asyncIterator]`. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `iterateNotificationDestinations` or `listAllNotificationDestinations` (eager) or `streamNotificationDestinations`. -- **Rationale:** Same finding appears in every paginated client across the SDK (`listAlertsIter`, `listClustersIter`, ...). Generator-level rename. - -### 12. `ListNotificationDestinationsResponse.results` — vague field name — `src/v1/model.ts:67` +### 11. `ListNotificationDestinationsResponse.results` — vague field name — `src/v1/model.ts:67` - **Code:** ```ts results?: ListNotificationDestinationsResult[] | undefined; @@ -226,7 +211,7 @@ - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `destinations` (drop the `notification` qualifier since the package context supplies it) or `items`. -### 13. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 73, 107, 140` +### 12. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 73, 107, 140` - **Code:** ```ts /** UUID identifying notification destination. */ @@ -237,7 +222,7 @@ - **Suggested name:** `destinationId` (within the package context the qualifier "notification" is implicit). Or `id` is acceptable if the type is always accessed as `destination.id`. - **Rationale:** Bare `id` is conventional and tolerated; the optionality is the real bug. Demoted to medium. -### 14. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:118-122` +### 13. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:118-122` - **Code:** ```ts export interface PagerdutyConfig { @@ -252,7 +237,7 @@ - **Suggested name:** see #7. - **Rationale:** Listed separately because PagerDuty is the simplest case (one secret field) and best illustrates the pattern. -### 15. `destinationType` field — type-suffix tautology — `src/v1/model.ts:78`, `:112` +### 14. `destinationType` field — type-suffix tautology — `src/v1/model.ts:78`, `:112` - **Code:** ```ts destinationType?: DestinationType | undefined; @@ -263,7 +248,7 @@ ## Low severity -### 16. SCREAMING_SNAKE_CASE enum values — `src/v1/model.ts:5-11` +### 15. SCREAMING_SNAKE_CASE enum values — `src/v1/model.ts:5-11` - **Code:** ```ts SLACK = 'SLACK', @@ -277,12 +262,12 @@ - **Suggested name:** `Slack = 'SLACK'`, `Email = 'EMAIL'`, `Webhook = 'WEBHOOK'`, `PagerDuty = 'PAGERDUTY'`, `MicrosoftTeams = 'MICROSOFT_TEAMS'`. The string literals (the wire representation) stay; only the TS identifier changes. - **Rationale:** Generator-level decision. Hand-written SDKs typically use UpperCamelCase enum members; the SCREAMING_SNAKE form makes it look like the type is C/Java. Demoted to low because it's a global convention and changing it would break every existing user. -### 17. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` +### 16. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` - See #3 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. - **Category:** 9 (qualifier mismatch). - **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #3 for the rationale. -### 18. `createNotificationDestination` / etc. — overly verbose method names — `src/v1/client.ts:71, 100, 125, 150, 204` +### 17. `createNotificationDestination` / etc. — overly verbose method names — `src/v1/client.ts:71, 100, 125, 150, 204` - **Code:** ```ts async createNotificationDestination(...) @@ -296,7 +281,7 @@ - **Suggested name:** Drop the suffix: `create`, `delete`, `get`, `list`, `update`. The class name (`Client` or `NotificationDestinationsClient`) supplies the domain context. - **Rationale:** Conventions differ across SDKs. AWS uses verbose method names; GCP / Azure use shorter. Demoted to low because the existing convention is consistent across the SDK and changing it is disruptive. Flagging for completeness. -### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` +### 18. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` - **Code:** ```ts // Package identity segment for this client to be used in the User-Agent header. @@ -310,7 +295,7 @@ - **Suggested name:** `USER_AGENT_PACKAGE_INFO` or `PACKAGE_USER_AGENT`. - **Rationale:** Cross-package — same finding appears in every audited file. -### 20. `HttpCallOptions` — `src/v1/utils.ts:15-19` +### 19. `HttpCallOptions` — `src/v1/utils.ts:15-19` - **Code:** ```ts export interface HttpCallOptions { @@ -323,19 +308,13 @@ - **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). - **Suggested name:** `HttpCallContext` (it is an internal context bag, not user-tunable options). -### 21. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` +### 20. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` - **Code:** lines 26-38 and 65-94. - **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). -### 22. `parseResponse` vs `marshalRequest` — verb asymmetry — `src/v1/utils.ts:113`, `:119` -- **Code:** lines 113 and 119. -- **Why weird:** Inverse functions named with different verbs (`parse` vs `marshal`). The schema constants use `marshal`/`unmarshal`. Pair-wise consistency would suggest `unmarshalResponse` and `marshalRequest`, or `parseResponse` and `serializeRequest`. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest`. - -### 23. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 88, 105, 130, 165, 187, 190, 209` +### 21. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 88, 105, 130, 165, 187, 190, 209` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -343,13 +322,13 @@ ## Observations -### 24. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +### 22. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). - **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. -### 25. `index.ts` re-exports verbose names verbatim — `src/v1/index.ts:5-23` +### 23. `index.ts` re-exports verbose names verbatim — `src/v1/index.ts:5-23` The barrel re-exports every type with its long generated name. An opportunity to expose friendlier aliases: ```ts export type { @@ -361,10 +340,10 @@ export type { Not done. So consumers always work with the verbose names. The 1:1 port philosophy probably prohibits this, but flagging as an observation — the barrel could improve ergonomics without removing the underlying names. - **Category:** 7 (verbose), Observation. -### 26. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows +### 24. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. -### 27. JSDoc inconsistency in `[Input-Only][Optional]` markers +### 25. JSDoc inconsistency in `[Input-Only][Optional]` markers The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the marker `[Input-Only][Optional]` — concatenating two brackets — while every other field uses single-bracket markers. The `[Optional]` is also redundant because the TS type already shows `?: undefined`. Minor doc inconsistency. ## Domain glossary diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md index 97409853..aaa16d01 100644 --- a/.agent/naming-audit/oauthcustomappintegration.md +++ b/.agent/naming-audit/oauthcustomappintegration.md @@ -3,7 +3,7 @@ **Path:** `packages/oauthcustomappintegration/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for OAuth App Integrations. Two flavours of integration are managed by the same service: *Custom* (caller-owned OAuth clients with their own redirect URLs and scopes) and *Published* (catalog of Databricks-blessed third-party apps such as Power BI or Tableau Desktop, identified by a stable `appId`). Both share the `TokenAccessPolicy` configuration. The package is the Databricks account-side complement of the `RFC 6749`/`OAuth 2.0` client registration concept. -**Total weird names flagged:** 18 +**Total weird names flagged:** 17 ## Summary | Severity | Count | @@ -11,7 +11,7 @@ | High | 5 | | Medium | 5 | | Low | 4 | -| Observation | 4 | +| Observation | 3 | ## High severity @@ -144,10 +144,7 @@ ### O2. `_Response` suffix is the only naming-convention violation — `model.ts: throughout` - All seven `_Response` types carry an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` Comment. No other naming violations in the package require ESLint disables. This is a single, removable wart that the generator could fix in one place. See finding #5. -### O3. `executeCall` / `executeHttpCall` / `marshalRequest` / `parseResponse` utility-name asymmetry — `utils.ts:26, 65, 113, 119` -- Same observation across every package: the utility names do not pair symmetrically. `marshalRequest` ↔ `parseResponse` (verb mismatch: `marshal` vs `parse`, and `Request` vs `Response`). `executeCall` ↔ `executeHttpCall` (one wraps the other). Generated code, flag for upstream. - -### O4. `flattenQueryParams` is exported but unused — `utils.ts:123` +### O3. `flattenQueryParams` is exported but unused — `utils.ts:123` - This package never builds nested query parameters (`ListCustomOAuthAppIntegrations` uses three flat scalars), so `flattenQueryParams` is dead in this build. Same as in many sibling packages. Either drop the `export` or move the helper to `@databricks/sdk-core`. ## Domain glossary diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md index b55f6252..c86c0dc4 100644 --- a/.agent/naming-audit/oauthpublishedapp.md +++ b/.agent/naming-audit/oauthpublishedapp.md @@ -3,15 +3,15 @@ **Path:** `packages/oauthpublishedapp/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level read-only catalog of Databricks-blessed third-party OAuth applications (e.g. Power BI, Tableau Desktop) that can be enabled for an account. The package exposes a single endpoint that lists the published-app catalog rows. Each `PublishedOAuthApp` is a *catalog entry* (template) — not an *integration row* (which is the realised binding tracked by the sibling `oauthcustomappintegration` package). The package therefore plays "catalog index" to `oauthcustomappintegration`'s "registration manager". Domain underpinning is RFC 6749 (OAuth 2.0) client-type "published" applications, augmented by a Databricks-owned catalog of vetted third-party clients. -**Total weird names flagged:** 19 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | | High | 5 | | Medium | 6 | -| Low | 4 | -| Observation | 4 | +| Low | 3 | +| Observation | 2 | ## High severity @@ -105,13 +105,7 @@ - **Suggested name:** `OAuthPublishedAppClient` (still inside `…/v1`). Project-wide change. - **Rationale:** Defer to the project-wide naming-audit summary. Same as sibling finding #19. -### 14. Async-iterator method named `…Iter` — `client.ts:98` -- **Why weird:** `listPublishedOAuthAppsIter` (Go-style `…Iter` suffix). TypeScript convention for an `AsyncGenerator` is to use no suffix and have the type signature express it, or to use the verb form `iterate…` / `walk…`. The `Iter` suffix is a Go transliteration (Go has `…Iter()` from `golang.org/x/iter`). Sibling packages with the same generator method use the same `Iter` suffix. -- **Category:** 14 (Go/Java-style name) -- **Suggested name:** `listPublishedOAuthAppsAsync` (matches the JS ecosystem `…Async` convention when the non-async variant doesn't exist — but here only the async variant is present, so this is debatable), or rename the page-returning variant `listPublishedOAuthAppsPage` and the streaming variant `listPublishedOAuthApps` (the iterator is the more natural default in a TS world with `for await`). -- **Rationale:** The `Iter` suffix is invisible to TypeScript ecosystem readers. Compare modern Node APIs: `fs.opendir().readdir()` returns a `Dir` directly iterable; no `…Iter` suffix. Defer to project-wide pattern but flag. - -### 15. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:17` +### 14. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:17` - **Why weird:** `ListPublishedOAuthApps_Response.apps` is the collection field. Unlike the sibling package's `apps` field finding (`oauthcustomappintegration` #4) where the field carried *integrations* and the name was misleading, here the field genuinely is published apps. The name is correct *but* it duplicates the type name (`apps: PublishedOAuthApp[]` — "apps of type App"). Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). Acceptable. - **Category:** 15 (generic field — `apps` is the maximally-generic plural of `app`) — flagged for completeness - **Suggested name:** Keep `apps`. Or rename `publishedApps` to make plural+domain explicit. No strong action. @@ -125,12 +119,6 @@ ### O2. `_Response` suffix is the only naming-convention violation — `model.ts:14-15` - The one `_Response` type has an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment. No other naming violations in the package require ESLint disables. Single, removable wart that the generator could fix. See finding #4. -### O3. `executeCall` / `executeHttpCall` / `marshalRequest` / `parseResponse` utility-name asymmetry — `utils.ts:26, 65, 113, 119` -- Same observation across every package: the utility names do not pair symmetrically. `marshalRequest` ↔ `parseResponse` (verb mismatch: `marshal` vs `parse`, and `Request` vs `Response`). `executeCall` ↔ `executeHttpCall` (one wraps the other). Generated code, flag for upstream. - -### O4. `flattenQueryParams` and `marshalRequest` are exported but unused — `utils.ts:113, 119, 123` -- This package only `GET`s a list endpoint with three flat scalar query params and never marshals a request body. So `flattenQueryParams` and `marshalRequest` are dead in this build. Same as in sibling packages. Either drop the `export`, gate on per-package generation, or move these helpers to `@databricks/sdk-core` and have packages import only what they use. - ## Domain glossary - `accountId` — Databricks account UUID (top-level tenant). Distinct from a workspace ID. - `appId` — Slug key into the Databricks published-app catalog (e.g. `power-bi`, `tableau-desktop`). Despite the `Id` suffix, this is a human-readable name. Same value space as `oauthcustomappintegration.CreatePublishedOAuthAppIntegration.appId`. diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md index b94244ba..8c3eea04 100644 --- a/.agent/naming-audit/onlinetables.md +++ b/.agent/naming-audit/onlinetables.md @@ -65,17 +65,6 @@ 14. `TriggeredUpdateStatus` (model.ts:238) — fields: `lastProcessedCommitVersion`, `timestamp`, `triggeredUpdateProgress`. -### Zod schemas (model.ts) - -- Unmarshal: `unmarshalContinuousUpdateStatusSchema`, - `unmarshalFailedStatusSchema`, `unmarshalOnlineTableSchema`, - `unmarshalOnlineTableSpecSchema`, - `unmarshalOnlineTableSpec_ContinuousSchedulingPolicySchema`, - `unmarshalOnlineTableSpec_TriggeredSchedulingPolicySchema`, - `unmarshalOnlineTableStatusSchema`, `unmarshalPipelineProgressSchema`, - `unmarshalProvisioningStatusSchema`, `unmarshalTriggeredUpdateStatusSchema`. -- Marshal: identical list with `marshal` prefix. - ### Client (client.ts) - Class `Client` (client.ts:41). @@ -104,10 +93,10 @@ | Severity | Count | | --------------------- | ----- | | High | 7 | -| Medium | 14 | -| Low / SDK-wide note | 11 | +| Medium | 13 | +| Low / SDK-wide note | 9 | | Pass / acceptable | 9 | -| **Total findings** | **41** | +| **Total findings** | **38** | (Several findings touch multiple audit categories; counts above are unique findings.) @@ -858,33 +847,7 @@ a period (matches `.agent/rules` / user CLAUDE.md style). --- -### 37. `unmarshal*Schema` / `marshal*Schema` Go vocabulary — category 14 (Go/Java-style names) - -**Symbols:** `unmarshalContinuousUpdateStatusSchema`, -`unmarshalFailedStatusSchema`, `unmarshalOnlineTableSchema`, -`unmarshalOnlineTableSpecSchema`, -`unmarshalOnlineTableSpec_ContinuousSchedulingPolicySchema`, -`unmarshalOnlineTableSpec_TriggeredSchedulingPolicySchema`, -`unmarshalOnlineTableStatusSchema`, `unmarshalPipelineProgressSchema`, -`unmarshalProvisioningStatusSchema`, `unmarshalTriggeredUpdateStatusSchema`, -and the parallel `marshal*Schema` set (model.ts:253–602). - -**Issue:** "Marshal" / "Unmarshal" is Go-ism vocabulary. The TS/JS ecosystem -uses "serialize" / "deserialize", or, working with Zod, "parse" / "stringify" -/ "schema". The whole SDK uses this convention; **flag for SDK-wide -cleanup, not this package alone.** - -The `*Schema` suffix is also redundant — `unmarshalOnlineTable` without -`Schema` would suffice since the value's type is `z.ZodType` -and there are no non-schema cousins. **Pass with note.** - -Additionally, the `unmarshalOnlineTableSpec_…Schema` chain compounds with -finding 1's underscore problem — each carries an explicit lint suppression -(model.ts:331, 335, 507, 511). - ---- - -### 38. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 37. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` interface (utils.ts:15). @@ -898,7 +861,7 @@ any fix must apply everywhere). --- -### 39. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 38. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). @@ -912,29 +875,6 @@ this file is generated boilerplate copied across every package. --- -### 40. `readAll` — *pass* - -Helper does what its name says (reads a `ReadableStream` to -completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** - ---- - -### 41. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) - -**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). - -**Issue:** Two symmetric operations: response→object (parse) and -object→body-string (marshal). The verbs come from two different vocabularies -("parse" is generic TS/JS, "marshal" is Go). Internally consistent verb-pair -would be `parseResponse` / `serializeRequest` or `unmarshalResponse` / -`marshalRequest`. The current pair is awkward. - -**Suggested:** `serializeRequest` and `parseResponse` (TS-native vocabulary) -or commit fully to the Go terms: `unmarshalResponse` and `marshalRequest`. -**Flag for SDK-wide consistency.** - ---- - ## Cross-package alignment recommendations ### A. `OnlineTable` ↔ `SyncedTable` duplication @@ -999,9 +939,9 @@ names (strip the proto namespace). **Flag for generator.** | Severity | Count | Findings | | -------- | ----- | -------- | | **High** (style guide violations, cross-package collisions) | 7 | #1, #2, #5, #11, #17, #25, #35, **and** cross-package A | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 14 | #3, #4, #6, #7, #8, #12, #13, #14, #15, #16, #19, #20, #21, #23, #27, #41 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 11 | #9, #10, #18, #24, #26, #28, #31, #37, #38, #39, #41 | -| **Pass / acceptable** | 9 | #18, #22, #24, #26, #28, #29, #30, #32, #33, #34, #36, #40 | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 13 | #3, #4, #6, #7, #8, #12, #13, #14, #15, #16, #19, #20, #21, #23, #27 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 9 | #9, #10, #18, #24, #26, #28, #31, #37, #38 | +| **Pass / acceptable** | 9 | #18, #22, #24, #26, #28, #29, #30, #32, #33, #34, #36 | --- @@ -1035,9 +975,8 @@ names (strip the proto namespace). **Flag for generator.** (`ProvisioningInfo_State` → `ProvisioningState`). 3. **#5** — `UpperCamelCase` enum members (string value preserved as wire form). -4. **#37, #41** — settle marshal/unmarshal vs. parse/serialize vocabulary. -5. **#35** — `PACKAGE_SEGMENT` → `packageSegment`. -6. **#31** — settle waiter naming convention (`*Waiter` vs `*Poller` vs +4. **#35** — `PACKAGE_SEGMENT` → `packageSegment`. +5. **#31** — settle waiter naming convention (`*Waiter` vs `*Poller` vs inline `*AndWait`). --- diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md index 64f5169d..c6433d47 100644 --- a/.agent/naming-audit/permissions.md +++ b/.agent/naming-audit/permissions.md @@ -3,15 +3,15 @@ **Path:** `packages/permissions/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-object permissions — get, set, update, and inspect ACLs (access control lists) attached to Databricks workspace objects (clusters, jobs, notebooks, dashboards, pipelines, registered models, queries, repos, files, instance pools, etc.). Distinct from `grants` (Unity Catalog privileges on UC securables), though the two surfaces overlap conceptually and lexically. -**Total weird names flagged:** 40 +**Total weird names flagged:** 34 ## Summary | Severity | Count | | --- | --- | | High | 12 | | Medium | 14 | -| Low | 9 | -| Observation | 5 | +| Low | 4 | +| Observation | 4 | The permissions package contains 9 generated types, 1 enum, and 4 client methods, plus utility helpers. Three thematic problems dominate. (1) The request-as-imperative-verb pattern (`GetObjectPermissions`, `SetObjectPermissions`, `UpdateObjectPermissions`, `GetPermissionLevels`) collides with the verb-noun methods on `Client`, so users write `client.setObjectPermissions(req: SetObjectPermissions)` and the type name looks like a command rather than a payload. (2) The `PermissionLevel` enum mixes acronym-prefix patterns (`CAN_*`, `IS_*`) with redundant suffixes (`CAN_MONITOR` vs `CAN_MONITOR_ONLY`, `CAN_MANAGE_RUN`, `CAN_CREATE_APP`) and includes a sentinel `UNSPECIFIED` whose semantics ("delete this principal") are only discoverable from JSDoc — the value name actively misleads. (3) The package overlaps heavily with `grants` in vocabulary (`Permission`, `PermissionsResponse`, `permissionLevels`) while modelling a completely different concept; the only public type distinguishing this package from its sibling is `AccessControlRequest`/`Response`, both of which use the IAM-style "access control list" pattern that's unique-in-the-SDK. @@ -36,7 +36,7 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get ### 3. `UpdateObjectPermissions` (type) — `src/v1/model.ts:123` - **Why weird:** Same as #1, #2. Verb-shaped type. Used at `client.ts:147` as `updateObjectPermissions(req: UpdateObjectPermissions)`. - **Category:** 7, 14, 17. -- **Suggested name:** `UpdateObjectPermissionsRequest` or `ObjectPermissionsPatch` (since the HTTP method is PATCH, not PUT — see #35). +- **Suggested name:** `UpdateObjectPermissionsRequest` or `ObjectPermissionsPatch` (since the HTTP method is PATCH, not PUT — see #29). - **Rationale:** See #1. ### 4. `GetPermissionLevels` (type) — `src/v1/model.ts:86` @@ -190,55 +190,25 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get ## Low severity -### 27. `unmarshalAccessControlResponseSchema` and similar — `src/v1/model.ts:131,159,170,182,193` -- **Why weird:** Six exported `unmarshal*Schema` and three `marshal*Schema` (lines 208, 235, 249) constants. Long names with redundant `Schema` suffix; the `z.ZodType` type annotation already says they're Zod schemas. Plus `unmarshalGetPermissionLevels_ResponseSchema` (line 159) embeds the proto underscore and requires eslint-disable (line 158). -- **Category:** 8 (redundant `Schema` suffix), 4 (underscore), 20 (type-suffix tautology). -- **Suggested name:** Drop `Schema` suffix → `unmarshalAccessControlResponse`, `marshalSetObjectPermissions`, etc. -- **Rationale:** Naming consistency; type signature already conveys the schema-ness. - -### 28. `unmarshalGetPermissionLevels_ResponseSchema` — `src/v1/model.ts:159` -- **Why weird:** 47-character name combining #5 (`_Response` underscore), #27 (`Schema` suffix), and #4 (verbose request type name). Requires eslint-disable on the preceding line. -- **Category:** 4, 7, 8. -- **Suggested name:** `unmarshalPermissionLevelsResponse` (cascading from #5 and #27). -- **Rationale:** Cascade. - -### 29. `marshalSetObjectPermissionsSchema` / `marshalUpdateObjectPermissionsSchema` — `src/v1/model.ts:235,249` -- **Why weird:** 37- and 41-character names. Same `Schema` suffix issue (#27) plus the verbose `Set/UpdateObjectPermissions` name (#2, #3). -- **Category:** 4 (cascading), 7, 8. -- **Suggested name:** `marshalSetObjectPermissions` / `marshalUpdateObjectPermissions`. -- **Rationale:** Cascade. - -### 30. `marshalAccessControlRequestSchema` — `src/v1/model.ts:208` -- **Why weird:** Same as #27. The schema type annotation here is `z.ZodType` (no generic), not `z.ZodType` — so the schema is *less* typed than its companions (which use `z.ZodType`). Inconsistent. -- **Category:** 8, 17. -- **Suggested name:** `marshalAccessControlRequest` with a generic on the Zod type. -- **Rationale:** Internal consistency. - -### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 27. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 32. `readAll` (utility) — `src/v1/utils.ts:40` +### 28. `readAll` (utility) — `src/v1/utils.ts:40` - **Why weird:** Internal helper name generic to the point of meaninglessness; clashes cognitively with `Array.prototype` methods and Web Streams APIs. Same pattern called out in `.agent/naming-audit/grants.md` #38. The function name is also a direct Go-port of `io.ReadAll`. - **Category:** 1 (vague), 14 (Go-style). - **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. - **Rationale:** Cross-package consistency. -### 33. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same 152-line file. The `model.ts` file uses `marshal*` / `unmarshal*` consistently — `parseResponse` is the odd one out. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. -- **Rationale:** Same finding as `.agent/naming-audit/grants.md` #39. Mirroring helps readers map TS→wire/wire→TS at a glance. - -### 34. `HttpCallOptions` — `src/v1/utils.ts:15` +### 29. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Another `Options`-suffixed type; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix), 17 (inconsistent — internal struct shouldn't share a suffix with the user-facing CallOptions). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. Same finding as `grants.md` #40. -### 35. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:146` +### 30. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:146` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 156). The request type `UpdateObjectPermissions` is symmetric in name to `SetObjectPermissions` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. A user reading both method names side-by-side (`set...` and `update...`) might reasonably assume both perform full replacement. - **Category:** 17 (inconsistent action verbs), Observation. - **Suggested name:** `patchObjectPermissions` for the PATCH method, OR explicit JSDoc on `update*` clarifying merge semantics. @@ -248,22 +218,18 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get ## Observations -### 36. Three response paths converge on `PermissionsResponse` +### 31. Three response paths converge on `PermissionsResponse` `getObjectPermissions`, `setObjectPermissions`, and `updateObjectPermissions` all return the same `PermissionsResponse` type (`client.ts:70,123,149`). This is fine functionally but means callers can't distinguish "the state I just wrote" from "the state I just read" by type — only by which method was called. For an audit log or comparison flow, this loses information. Naming-adjacent because the type carries no read/write/post-update distinction. - **Category:** Observation. -### 37. Sentinel value `UNSPECIFIED` in PATCH is the only mutation-state encoded in an enum +### 32. Sentinel value `UNSPECIFIED` in PATCH is the only mutation-state encoded in an enum The `PermissionLevel.UNSPECIFIED` sentinel (see #6) is unique in the SDK: it's the only enum value across `permissions`, `grants`, `accountaccesscontrol`, and `iam` that doubles as a deletion marker when sent in a PATCH body. Most APIs model this with a separate request body shape (e.g. `removals: Principal[]`) or with HTTP DELETE. Encoding "remove me" as an enum value alongside "let me have this permission" is unusual. - **Category:** Observation, 6 (misleading). -### 38. Doc-comment list of object types is potentially stale +### 33. Doc-comment list of object types is potentially stale The hardcoded list in `requestObjectType` doc-comments includes `database-projects`, `genie`, `knowledge-assistants`, `supervisor-agents` — all relatively new product surfaces. The list will need updating with every new permission-able workspace object. As-is the SDK has 26; if not regularly synced with the server, the JSDoc will drift. - **Category:** Observation. -### 39. No pagination — all methods are unpaginated single-call +### 34. No pagination — all methods are unpaginated single-call Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods, see `grants.md` #41), `permissions` has no listing operation. Every method here is by-object-id; there's no "list all permissioned objects" surface. This is correct for the API but worth noting because users coming from `grants` (or `accountaccesscontrol`) might expect parallel list semantics. Naming-adjacent because the absence of `list*` here aligns the method-vocabulary differently than its sibling packages. - **Category:** Observation. - -### 40. `marshalAccessControlRequestSchema` type annotation lacks generic — `src/v1/model.ts:208` -The schema is typed `z.ZodType` (without ``) while every other schema in the file is typed `z.ZodType`. Inconsistent; reduces type-safety at the schema-usage sites. Naming-adjacent because a fully-typed schema would also make the generated `marshalRequest` calls type-safe. -- **Category:** Observation, 17. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index 98364a74..e522f69e 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -80,10 +80,10 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. - **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). -### H10. `client.list()` / `client.listIter()` — too generic for the package's bare-`list` slot -- **Locations:** `client.ts:377`, `client.ts:416`. +### H10. `client.list()` — too generic for the package's bare-`list` slot +- **Location:** `client.ts:377`. - **Category:** 1 (vague), 17 (inconsistent verbs). -- **Suggestion:** Rename to `listPipelines()` / `listPipelinesIter()` to match the request type `ListPipelines` and to disambiguate from `listUpdates`/`listEvents`. +- **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelines` and to disambiguate from `listUpdates`/`listEvents`. - **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelines`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. ### H11. `PipelineState_PipelineState` enum — underscore suffix tautology @@ -156,7 +156,7 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Locations:** `model.ts:644-670`, `model.ts:1323`, `model.ts:1357`. - **Category:** 20 (type-suffix tautology), 12 (duplicate naming). - **Suggestion:** Rename the outer interface to `ConnectorOptions` and the inner discriminator to `options` (or `payload`). Then `connectorOptions: {payload: {...}}` reads cleanly. -- **Rationale:** Currently `ConnectorOptions.connectorOptions.googleAdsOptions` requires four nested identifiers all containing "options". Marshaling code (`model.ts:4763-4875`) is illegible because of it. +- **Rationale:** Currently `ConnectorOptions.connectorOptions.googleAdsOptions` requires four nested identifiers all containing "options". ### H23. `PipelinesEnvironment` vs `IngestionPipelineDefinition` — two `Pipeline*` namespaces, only one is plural - **Locations:** `model.ts:2382` (`PipelinesEnvironment`), `model.ts:1173` (`IngestionPipelineDefinition`). diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index 4d7d6116..1d1beb36 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -70,11 +70,7 @@ The package defines no enums. `fullUrl`, `resp`, `call`, `callSignal`, `headers`, `httpReq`, `respBody`, `pageReq`, `item`, `info`. - `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`. -- Marshal / unmarshal schemas: `unmarshalPolicyFamilySchema`, - `unmarshalListPolicyFamilies_ResponseSchema`. No `marshal*` schemas - exist (read-only API). + `readAll`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`. --- @@ -88,9 +84,7 @@ The package defines no enums. | V-02 | `PolicyFamily.name` | Low | Generic but standard for entity types; meaning is preserved by the parent type. | | V-03 | `PolicyFamily.description` | Low | Generic but standard across the SDK; acceptable. | | V-04 | `GetPolicyFamily.version` | Medium | `version` is generic. The JSDoc says "version number for the family"; field could be `familyVersion` or `policyFamilyVersion` to make it self-describing when destructured (e.g. `const {version} = req` loses context). | -| V-05 | `parseResponse` (utils) | Low | Generic, but it's local to the package. Acceptable. | -| V-06 | `flattenQueryParams` (utils) | Low | Reasonable. | -| V-07 | `marshalRequest` (utils) | Low | Generic helper for "marshal arbitrary request body". OK in context. Note this package never calls it (read-only API). | +| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | ### 2.2 Redundant enum prefixes — High @@ -104,15 +98,13 @@ The package defines no enums. | ----- | --------------------- | -------- | ----- | | A-01 | `httpClient`, `HttpClient`, `HttpCallOptions`, `HttpRequest`, `HttpResponse`, `httpReq` | Low | `Http` (lowercased) follows Google TS style for acronyms ≥3 chars. Consistent with the rest of the SDK. | | A-02 | `URLSearchParams` (local in `client.ts`) | Low | DOM API; uses uppercase `URL` because that is the platform-defined identifier. Acceptable. | -| A-03 | `unmarshalListPolicyFamilies_ResponseSchema` | Low | "Marshal/unmarshal" is the chosen vocabulary; cf. § 2.13 (G-02). Not an acronym-case issue. | ### 2.4 Underscores in TS identifiers — High | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | U-01 | `ListPolicyFamilies_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). The codebase even disables ESLint on the line: `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`. Should be `ListPolicyFamiliesResponse`. | -| U-02 | `unmarshalListPolicyFamilies_ResponseSchema` | High | Same as U-01; the underscore cascades into the schema constant and forces the same ESLint disable comment in `model.ts` (line 40-41). | -| U-03 | Imports/exports of `ListPolicyFamilies_Response` | High | `client.ts` and `index.ts` both import/re-export the underscored name, propagating the violation across the public surface (see `index.ts` line 10). | +| U-02 | Imports/exports of `ListPolicyFamilies_Response` | High | `client.ts` and `index.ts` both import/re-export the underscored name, propagating the violation across the public surface (see `index.ts` line 10). | No enum-member identifiers exist in this package, so the `SCREAMING_SNAKE_CASE` exception (which is permitted by Google style for @@ -125,7 +117,7 @@ enum members) does not apply here. | C-01 | `req`, `resp` (locals in `client.ts`) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. Used in every CRUD method. | | C-02 | `httpReq` (local in `client.ts`) | Low | Short for "HTTP request". OK in local scope. | | C-03 | `respBody` (local in `client.ts`) | Low | Short for "response body". OK in local scope. | -| C-04 | `pageReq` (local in `client.ts`, `listPolicyFamiliesIter`) | Low | Short for "page request". OK. | +| C-04 | `pageReq` (local in `client.ts`) | Low | Short for "page request". OK. | | C-05 | `opts` (`utils.ts` parameter, `executeHttpCall` and `executeCall`) | Low | Inside fn scope; minor. | | C-06 | `pkgJson` (import in `client.ts`) | Low | Short for `packageJson`. Consistent with peer packages' codegen output. | | C-07 | `acc` (local in `utils.ts` reduce callback) | Low | Standard reduce-accumulator name. OK. | @@ -136,22 +128,16 @@ enum members) does not apply here. | ----- | ---------------------------------------------------- | -------- | ----- | | M-01 | `getPolicyFamily()` JSDoc: "an policy family" | Low | Typo in the JSDoc ("an" should be "a"). Not a naming issue but a generator artifact worth fixing upstream. | | M-02 | `listPolicyFamilies()` JSDoc: "list of policy definition types" | Medium | The method returns *policy families*, but the JSDoc paraphrases them as "policy definition types". Mismatched terminology between the method name (`PolicyFamily`) and its docstring will confuse readers. Method/type/route all say "family"; doc should too. | -| M-03 | `parseResponse` (utils) | Low | Parses **JSON** specifically — `parseJsonResponse` would be more accurate. | -| M-04 | `marshalRequest` (utils) | Low | Marshals to **JSON string**. `marshalJsonRequest` would be more accurate. Not used in this package. | -| M-05 | `GetPolicyFamily` JSDoc: "Returns the details of a policy family at a specific version" | Low | The JSDoc describes the *operation*, not the request body. The type is a request shape, not a response. Convention across the SDK, OK but slightly misleading on first read. | -| M-06 | `ListPolicyFamilies` JSDoc: "Returns the list of policy families…" | Low | Same as M-05 — the JSDoc describes the operation rather than the request shape. | -| M-07 | `Client` (class) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | +| M-03 | `GetPolicyFamily` JSDoc: "Returns the details of a policy family at a specific version" | Low | The JSDoc describes the *operation*, not the request body. The type is a request shape, not a response. Convention across the SDK, OK but slightly misleading on first read. | +| M-04 | `ListPolicyFamilies` JSDoc: "Returns the list of policy families…" | Low | Same as M-03 — the JSDoc describes the operation rather than the request shape. | +| M-05 | `Client` (class) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | ### 2.7 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | O-01 | `policyFamilyId` (every occurrence) | Low | 14 chars but precise. Two `policyFamily*` fields would collapse to one once the type name (`PolicyFamily`) is in scope, but it remains unambiguous across the SDK and matches the upstream API field name. Accept. | -| O-02 | `unmarshalListPolicyFamilies_ResponseSchema` | High | 43 characters. Combines (a) underscore violation U-01, (b) proto-style nested-message tail `_Response`, (c) the `unmarshal*Schema` triple-statement pattern (cf. O-04 in `clusterpolicies`). Removing `_Response` saves one char and one ESLint disable; adopting `deserializeListPolicyFamiliesSchema` (or `*Codec`) would be even shorter and more idiomatic JS/TS. | -| O-03 | `unmarshalPolicyFamilySchema` | Medium | 28 chars. Pattern `unmarshalSchema` triple-states intent ("schema for unmarshalling X"). Repo-wide convention, but noted. | -| O-04 | `ListPolicyFamilies_Response` | Medium | The `_Response` suffix is a proto-import artifact; for a one-method list endpoint the suffix is redundant with the type's outer name (`ListPolicyFamilies`). Combined with U-01, the renaming to `ListPolicyFamiliesResponse` saves the disable comment. | -| O-05 | `listPolicyFamiliesIter` (method) | Medium | Three observations: (a) the `Iter` suffix is Go-style (`*Iter` convention from `databricks/sdk-go`). TypeScript convention is to leverage `Symbol.asyncIterator` on a custom iterable or name the method `*Iterator()` (matching DOM's `entries() / keys()`). (b) Without `Iter` the method name would collide with `listPolicyFamilies`. (c) `listAll` or `listPolicyFamiliesAll` would communicate "auto-page through everything" more clearly than `Iter`. Tracked under § 2.13 G-05. | -| O-06 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-02 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | ### 2.8 Singular / plural mismatches — Low @@ -181,28 +167,22 @@ _None._ | D-01 | `PolicyFamily.policyFamilyId` (here) and `Policy.policyFamilyId` (in `clusterpolicies`) | Low | The field name is consistent across packages — good. No duplication concern. | | D-02 | `PolicyFamily.definition` vs `Policy.definition` / `Policy.policyFamilyDefinitionOverrides` (in `clusterpolicies`) | Medium | Three related "definition" concepts spread across two packages: `PolicyFamily.definition` (the canonical CPDL doc), `Policy.definition` (custom override), and `Policy.policyFamilyDefinitionOverrides` (delta). The current package has only one of the three, but the field name `definition` does not communicate which of the three roles it plays. Adding a JSDoc cross-link to the `clusterpolicies` `*Overrides` field would help; a rename to `policyDefinition` would align with the sibling field names. | | D-03 | `PolicyFamily` vs `Policy` (cross-package) | Low | Distinct concepts: a `PolicyFamily` is a template, a `Policy` is an instance. Cross-package linking (JSDoc `{@link}`) would help readers understand the relationship. Out of scope for naming. | -| D-04 | `parseResponse`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`, `readAll` (`utils.ts`) | Medium | All six helpers are byte-identical duplicates of the helpers in every other API package's `utils.ts` (`clusterpolicies`, `clusters`, `accounts`, etc.). The codegen emits the same file per package. Should be hoisted into `@databricks/sdk-core/api` or similar to eliminate the duplication. Per-package naming impact: none, but the duplication is a maintenance hazard. | -| D-05 | `HttpCallOptions` (utils) | Medium | Same interface re-declared per package — see D-04. | ### 2.12 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | T-01 | `getPolicyFamily`, `listPolicyFamilies` | Low | Both imperative present-tense — consistent. | -| T-02 | `listPolicyFamiliesIter` | Low | Imperative + Go-style noun suffix. Verb tense is consistent. | -| T-03 | `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` | Low | All imperative present-tense — consistent. | +| T-02 | `executeCall`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`, `readAll` | Low | All imperative present-tense — consistent. | ### 2.13 Go / Java-style names — Medium | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | G-01 | `ListPolicyFamilies_Response` (proto nested-message style) | High | Direct port of Go's `pb.ListPolicyFamiliesResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `ListPolicyFamiliesResponse`. | -| G-02 | `unmarshalXxxSchema` / `marshalXxxSchema` | Medium | "Marshal/unmarshal" is the Go (and gRPC) verb pair. JS/TS code overwhelmingly uses **serialize / deserialize** (or **parse / stringify**). New TS readers will look up "marshal" before they recognise it. Repo-wide convention; flagged once per package. | -| G-03 | `HttpClient`, `HttpRequest`, `HttpResponse` | Low | Google TS style uses `Http` (lowercased acronym) — consistent. Not a Go-style violation. | -| G-04 | `listPolicyFamiliesIter` (`*Iter` suffix) | Medium | The `Iter` suffix is the Go SDK's idiomatic naming for `iter.Seq[T]`-returning helpers. TypeScript convention is to (a) implement `Symbol.asyncIterator` directly on a custom iterable, or (b) name the method `entries()` / `values()` matching the DOM/Map APIs. The current naming is faithful to the Go port but reads as foreign in TS. | -| G-05 | `executeCall`, `executeHttpCall` | Medium | The dual-naming (`Call` vs `HttpCall`) communicates the wrapping relationship in a Go-style "the inner one is HTTP-specific, the outer one is a generic retry/timeout decorator" idiom. Acceptable; common pattern in the Go SDK at `databricks/sdk-go/transport/`. | -| G-06 | `marshalRequest`, `parseResponse` | Medium | Same as G-02 — the JS-idiomatic verbs would be `serialize` / `parse` (or `stringify` / `parse`). | -| G-07 | `buildHttpRequest` | Low | "Build" is fine in TS; the naming is broadly used. | +| G-02 | `HttpClient`, `HttpRequest`, `HttpResponse` | Low | Google TS style uses `Http` (lowercased acronym) — consistent. Not a Go-style violation. | +| G-03 | `executeCall`, `executeHttpCall` | Medium | The dual-naming (`Call` vs `HttpCall`) communicates the wrapping relationship in a Go-style "the inner one is HTTP-specific, the outer one is a generic retry/timeout decorator" idiom. Acceptable; common pattern in the Go SDK at `databricks/sdk-go/transport/`. | +| G-04 | `buildHttpRequest` | Low | "Build" is fine in TS; the naming is broadly used. | ### 2.14 Generic field names losing meaning — Medium @@ -225,8 +205,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | AV-01 | `getPolicyFamily()` (singular get) vs `listPolicyFamilies()` (plural list) | Low | Correct convention: singular `get` for one-resource, plural `list` for many. Consistent. | -| AV-02 | `listPolicyFamiliesIter()` — the verb is `list`, the suffix `Iter` repurposes the same verb | Low | The two list-style methods share the verb `list` and differ only in suffix. Acceptable but slightly confusing (one returns a page, the other yields a stream). A TS-idiomatic alternative such as `iterPolicyFamilies()` or `policyFamilies()` (returning an `AsyncIterable`) would separate concerns. | -| AV-03 | The package exposes only **read** verbs — `get`, `list`. There are no `create` / `update` / `delete` methods (the API is read-only). The verb set is consistent with the API's read-only nature. | Low | OK. | +| AV-02 | The package exposes only **read** verbs — `get`, `list`. There are no `create` / `update` / `delete` methods (the API is read-only). The verb set is consistent with the API's read-only nature. | Low | OK. | ### 2.17 Long enum values — Medium @@ -260,13 +239,11 @@ _None._ | X-05 | `Client.userAgent` (private) | Low | Standard naming; HTTP `User-Agent` is the wire-format identifier. OK. | | X-06 | `executeCall` parameter `call: Call` | Low | The type `Call` is generic from `@databricks/sdk-core/api` and overloads the verb; readers may briefly wonder which "call" is meant (function callback vs. RPC call). Imported from the core package; flagged once. | | X-07 | `callSignal` (local in `client.ts`) | Low | Distinct from `req.signal` / `options?.signal` — the qualifier `call` disambiguates. Good. | -| X-08 | `parseResponse` is generic (``) but `marshalRequest` is not (`schema: z.ZodType` without inference) | Low | Type asymmetry: `parseResponse` returns `T`, `marshalRequest` accepts `unknown` and returns `string`. A symmetric design would type both generically. Not a name issue; flagged for code-quality follow-up. | -| X-09 | `flattenQueryParams` (utils, exported) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | -| X-10 | `listPolicyFamiliesIter` body uses a `for (;;)` infinite loop | Low | Naming-neutral; the `for (;;)` idiom (instead of `while (true)`) is consistent with the rest of the codebase. | -| X-11 | `pageReq` (local in `client.ts`, `listPolicyFamiliesIter`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | -| X-12 | `index.ts` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | -| X-13 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | -| X-14 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-07. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | +| X-08 | `flattenQueryParams` (utils, exported) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | +| X-09 | `pageReq` (local in `client.ts`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | +| X-10 | `index.ts` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | +| X-11 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | +| X-12 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-05. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | --- @@ -276,29 +253,28 @@ _None._ | Severity | Count | | -------- | ----- | -| High | 6 | -| Medium | 20 | -| Low | 39 | -| **Total**| **65**| +| High | 4 | +| Medium | 12 | +| Low | 28 | +| **Total**| **44**| (Counted unique IDs across all categories. The total double-counts cross-referenced symbols -intentionally — e.g. `ListPolicyFamilies_Response` appears in U-01, U-02, U-03, O-04, and G-01.) +intentionally — e.g. `ListPolicyFamilies_Response` appears in U-01, U-02, and G-01.) ### 3.2 Top themes -1. **Proto-style `_Response` suffix.** `ListPolicyFamilies_Response` and its - schema `unmarshalListPolicyFamilies_ResponseSchema` violate Google TS style - (no underscores in `UpperCamelCase` identifiers) and each requires an - `eslint-disable @typescript-eslint/naming-convention` annotation. Renaming - to `ListPolicyFamiliesResponse` would remove the disables and align with - TS conventions. This is the package's only **High**-severity cluster. +1. **Proto-style `_Response` suffix.** `ListPolicyFamilies_Response` + violates Google TS style (no underscores in `UpperCamelCase` identifiers) + and requires an `eslint-disable @typescript-eslint/naming-convention` + annotation. Renaming to `ListPolicyFamiliesResponse` would remove the + disables and align with TS conventions. This is the package's only + **High**-severity cluster. 2. **Read-only API ⇒ minimal naming surface.** With only two endpoints (`getPolicyFamily`, `listPolicyFamilies`) and one entity (`PolicyFamily`), the package introduces almost no domain-specific naming. The vast - majority of issues are repo-wide patterns (Go-style verbs, the - marshal/unmarshal idiom, the bare `Client` class name, the underscored - `_Response` suffix) rather than per-package mistakes. + majority of issues are repo-wide patterns (the bare `Client` class name, + the underscored `_Response` suffix) rather than per-package mistakes. 3. **`definition` and `version` are over-generic on a generic entity.** `PolicyFamily.definition` and `GetPolicyFamily.version` are the two @@ -306,31 +282,15 @@ intentionally — e.g. `ListPolicyFamilies_Response` appears in U-01, U-02, U-03 the field name itself. Renaming to `policyDefinition` / `familyVersion` (or `policyFamilyVersion`) would self-describe. -4. **`Iter` suffix is Go-style.** `listPolicyFamiliesIter` mirrors the Go SDK - `iter.Seq[T]` naming. TS-idiomatic alternatives would use - `Symbol.asyncIterator` or `entries()`-style naming. - -5. **Cross-package duplication.** Every helper in `utils.ts` - (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`, `readAll`) is byte-identical to - the same helper across all other API packages. Hoist to - `@databricks/sdk-core/api`. Naming-neutral but architecturally - significant. - ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) - Drop `_Response` suffix → `ListPolicyFamiliesResponse`. Removes one ESLint-disable comment and one Google-style violation. -- Rename `unmarshalListPolicyFamilies_ResponseSchema` → - `unmarshalListPolicyFamiliesResponseSchema`. Cascading from the above. - Rename `PolicyFamily.definition` → `policyDefinition` (matches the sibling field `policyFamilyDefinitionOverrides` in the `clusterpolicies` package). -- Rename `listPolicyFamiliesIter()` → `iterPolicyFamilies()` or have the - client class implement `Symbol.asyncIterator` directly on a paginated - iterable wrapper. - Fix the JSDoc on `getPolicyFamily()` ("an policy family" → "a policy family") and on `listPolicyFamilies()` ("policy definition types" → "policy families"). @@ -339,16 +299,10 @@ codegen owners) ### 3.4 Cross-package consistency notes -- The `marshal*` / `unmarshal*` schema-naming convention is consistent - with peer packages (`clusters`, `clusterpolicies`, etc.) and is - therefore a repo-wide concern, not a per-package fix. - The `_Response` proto-style suffix is consistent with peers; addressing at the codegen level would fix all packages in one sweep. - The bare `Client` class name is consistent with peers; a codegen-level rename to `Client` would help all packages. -- The `*Iter` suffix is consistent with `clusters.listClustersIter`, - `clusterpolicies.listPoliciesIter`, etc. — a repo-wide TS-idiomatic - rework (e.g. `Symbol.asyncIterator`) would benefit all packages. - `PolicyFamily.policyFamilyId` matches `Policy.policyFamilyId` in the `clusterpolicies` package — cross-package field naming is consistent. - `PolicyFamily.definition` does **not** match the more-qualified diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index 5f364da4..bad4a0cf 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -3,7 +3,7 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `ComputeInstance`s (the individual compute nodes inside an endpoint group), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Table`s (non-synced PG tables), `Catalog`s (Unity Catalog mirrors of logical PG databases), Forward ETL (PG→UC reverse-ETL), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Waiter`-style classes. -**Total weird names flagged:** 92 +**Total weird names flagged:** 90 ## Summary | Severity | Count | @@ -11,7 +11,7 @@ | High | 22 | | Medium | 47 | | Low | 17 | -| Observation | 6 | +| Observation | 4 | ## High severity @@ -588,25 +588,13 @@ - **Suggested name:** `Operation` generic. - **Rationale:** Connects #20, #21, #52, #53. -### 89. `marshalRequest` / `parseResponse` / `executeCall` are exported from `utils.ts` only inside the package — `src/v1/utils.ts` -- **Why weird:** Utility names are generic (`buildHttpRequest`, `executeHttpCall`, `flattenQueryParams`, `marshalRequest`, `parseResponse`). They're not in the `index.ts` public exports, so this is internal naming. No naming bug per se; flag that they're all generic and could collide if ever exposed. -- **Category:** Observation (internal generics). -- **Suggested name:** N/A (internal). -- **Rationale:** Not actionable but worth noting. - -### 90. `flattenQueryParams` in `utils.ts` has the comment "// arrays of objects are not yet supported" — `src/v1/utils.ts:132` -- **Why weird:** Code comment admits a gap. Not naming-related, but indicates the marshal layer is incomplete; future array-of-objects fields will silently misbehave. -- **Category:** Observation. -- **Suggested name:** Fix the gap (TODO) or document the constraint at the public layer. -- **Rationale:** Not naming. - -### 91. `EndpointSettings_PgSettingsEntry` and `ProjectDefaultEndpointSettings_PgSettingsEntry` are duplicated, dead types — `src/v1/model.ts:1421, 2136` +### 89. `EndpointSettings_PgSettingsEntry` and `ProjectDefaultEndpointSettings_PgSettingsEntry` are duplicated, dead types — `src/v1/model.ts:1421, 2136` - **Why weird:** Both types are identical (`{key, value}`) and unused. They are proto-generated map-entry types. They are exported from `index.ts:91, 135`. - **Category:** Observation (related to #46, #55). - **Suggested name:** Remove (and also `ProjectCustomTag` could merge with `database.CustomTag`). - **Rationale:** Public surface bloat. -### 92. `ProvisioningInfo_State` is exported from both `database` and `postgres` packages with identical members — `src/v1/model.ts:654`, `database/v1/model.ts:148` +### 90. `ProvisioningInfo_State` is exported from both `database` and `postgres` packages with identical members — `src/v1/model.ts:654`, `database/v1/model.ts:148` - **Why weird:** Same enum, two packages, identical members. Reader importing both packages has to alias one. - **Category:** Observation (cross-package duplication). - **Suggested name:** Move to a shared `core/lakebase-common` or `core/enums`. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md index 8ad75751..f802fba9 100644 --- a/.agent/naming-audit/qualitymonitor.md +++ b/.agent/naming-audit/qualitymonitor.md @@ -3,15 +3,16 @@ **Path:** `packages/qualitymonitor/src/v2/` **Versions audited:** v2 **Inferred domain:** Quality monitoring on Unity Catalog objects (currently only `schema`). The package defines a single `QualityMonitor` entity that wraps `AnomalyDetectionConfig` (last-run telemetry plus excluded tables) and a list of `ValidityCheckConfiguration` arms (percent-null, range, uniqueness). A nested concept (`CustomCheckConfiguration` -> `CustomScalarCheck`) lets callers attach templated SQL checks with per-column matchers. Every operation is marked `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., this entire package is a deprecated shim that has been superseded by the `dataquality` package. -**Total weird names flagged:** 47 +**Total weird names flagged:** 42 ## Summary | Severity | Count | | --- | --- | | High | 13 | -| Medium | 17 | -| Low | 11 | -| Observation | 6 | +| Medium | 16 | +| Low | 8 | +| Observation | 5 | + ## CRITICAL: Two packages, same domain This package (`@databricks/sdk-qualitymonitor`, exporting `./v2`) and its sibling `@databricks/sdk-qualitymonitors` (plural, exporting `./v1`) **both exist** in this repo. They model overlapping data-quality concepts but with completely different shapes: @@ -38,10 +39,10 @@ The singular-vs-plural naming gives the reader no hint that these are different - **Suggested name:** `QualityMonitorClient`. - **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but especially acute here because three sibling packages (this, `qualitymonitors`, `dataquality`) all expose `Client`. -### 3. `ListQualityMonitorRequest` / `ListQualityMonitorResponse` / `listQualityMonitor` / `listQualityMonitorIter` — `src/v2/model.ts:92-100`, `src/v2/client.ts:152,185` -- **Why weird:** Singular noun on a list operation. The response holds `qualityMonitors?: QualityMonitor[]` (plural), the paginator yields a single `QualityMonitor`, and the wire path is `/api/2.0/quality-monitors` (plural) — every concrete signal is plural; only the type/method name uses the singular `QualityMonitor`. Same singular-on-list bug as `dataquality` finding #1. +### 3. `ListQualityMonitorRequest` / `ListQualityMonitorResponse` / `listQualityMonitor` — `src/v2/model.ts:92-100`, `src/v2/client.ts:152` +- **Why weird:** Singular noun on a list operation. The response holds `qualityMonitors?: QualityMonitor[]` (plural), and the wire path is `/api/2.0/quality-monitors` (plural) — every concrete signal is plural; only the type/method name uses the singular `QualityMonitor`. Same singular-on-list bug as `dataquality` finding #1. - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** `ListQualityMonitorsRequest` / `ListQualityMonitorsResponse` / `listQualityMonitors` / `listQualityMonitorsIter`. +- **Suggested name:** `ListQualityMonitorsRequest` / `ListQualityMonitorsResponse` / `listQualityMonitors`. - **Rationale:** REST conventions, the package's own field naming (`qualityMonitors`), and the URL path all use plural. The singular form is generator template noise. ### 4. `QualityMonitor.objectType` + `QualityMonitor.objectId` — `src/v2/model.ts:109-113` (and copied into 4 request types) @@ -179,9 +180,9 @@ The singular-vs-plural naming gives the reader no hint that these are different - **Rationale:** Method docs that lie about implementation status are worse than no docs. ### 26. `listQualityMonitor` parameter is non-optional, but `req` is empty in normal use — `src/v2/client.ts:152-154` -- **Why weird:** `listQualityMonitor(req: ListQualityMonitorRequest, options?: CallOptions)` requires the caller to pass `req` even when they want all defaults. `ListQualityMonitorRequest` is `{pageToken?, pageSize?}` — both optional. So the only "no special args" call is `listQualityMonitor({})` — an empty object placeholder. The paginator wrapper (`listQualityMonitorIter`) has the same shape. +- **Why weird:** `listQualityMonitor(req: ListQualityMonitorRequest, options?: CallOptions)` requires the caller to pass `req` even when they want all defaults. `ListQualityMonitorRequest` is `{pageToken?, pageSize?}` — both optional. So the only "no special args" call is `listQualityMonitor({})` — an empty object placeholder. - **Category:** 6 (misleading — looks like there's a required input but there isn't). -- **Suggested name:** Make `req?: ListQualityMonitorRequest` optional: `listQualityMonitor(req?: ListQualityMonitorRequest, options?: CallOptions)`. Same for the iterator. +- **Suggested name:** Make `req?: ListQualityMonitorRequest` optional: `listQualityMonitor(req?: ListQualityMonitorRequest, options?: CallOptions)`. - **Rationale:** Optionality on the wire should match optionality at the TS surface. Generator-wide concern. ### 27. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,202` @@ -193,7 +194,7 @@ The singular-vs-plural naming gives the reader no hint that these are different ### 28. Method names `createQualityMonitor` / `deleteQualityMonitor` / `getQualityMonitor` / `listQualityMonitor` / `updateQualityMonitor` — `src/v2/client.ts:70,102,124,152,206` - **Why weird:** Five methods, all of which repeat "QualityMonitor" in the name even though they are members of a `Client` class whose package (`qualitymonitor`) already encodes that domain. Compare with sister packages where methods are `create` / `get` / `delete` / `list` (verbs only). The "QualityMonitor" suffix is dead context — calling `client.createQualityMonitor(...)` from a package literally called `qualitymonitor` is reading the noun twice. - **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `create` / `delete` / `get` / `list` / `update` (drop the noun). With `listIter` as the paginator. +- **Suggested name:** `create` / `delete` / `get` / `list` / `update` (drop the noun). - **Rationale:** When the class is `Client` and the package is `qualitymonitor`, the only entity to act on is the quality monitor; the noun adds no signal. ### 29. `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` — `src/v2/model.ts:139-145` @@ -202,75 +203,51 @@ The singular-vs-plural naming gives the reader no hint that these are different - **Suggested name:** Either: (a) move identifiers entirely to the nested `qualityMonitor` (server reads them from the body and the path is derived from the body in TS land), or (b) move identifiers entirely to top-level and let `qualityMonitor` be just the mutable fields. - **Rationale:** Same identifier surfaced twice on the same request is an invitation to bugs. -### 30. `marshalQualityMonitorSchema` and 9 other `marshal*Schema` / `unmarshal*Schema` names — `src/v2/model.ts:163-512` -- **Why weird:** Generator-emitted Zod schemas all carry the awkward double-`Schema` suffix at the call site (`z.lazy(() => unmarshalQualityMonitorSchema)`) — "lazy unmarshal Quality Monitor Schema" reads as four nouns. Same as `dataquality` finding #47. -- **Category:** 14 (Go-style), 17 (verb-naming mismatch with Zod's own `parse`). -- **Suggested name:** `encodeQualityMonitor` / `decodeQualityMonitor`. -- **Rationale:** Generator-wide. - ## Low severity -### 31. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` +### 30. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's one list endpoint handles pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. Same as `dataquality` finding #35. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as other audited packages. -### 32. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` +### 31. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataquality` finding #36. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 33. `buildHttpRequest` — `src/v2/utils.ts:96` -- **Why weird:** Same as `dataquality` finding #37; "build" suggests builder pattern, the function spreads literals. -- **Category:** 1, 6. -- **Suggested name:** `makeHttpRequest`. -- **Rationale:** "Make" matches the simpler reality. - -### 34. `marshalRequest` and `parseResponse` — `src/v2/utils.ts:113,119` -- **Why weird:** Names imply request/response but the functions work on any payload + schema; identical to `dataquality` findings. -- **Category:** 1, 6. -- **Suggested name:** `encodeToJson` / `decodeFromJson`. -- **Rationale:** Symmetric verb pair removes the "Request"/"Response" mis-promise. - -### 35. `readAll` — `src/v2/utils.ts:40` -- **Why weird:** Identical to `dataquality` finding #39; "readAll" does not say "drain a stream". -- **Category:** 1, 5. -- **Suggested name:** `drainStream`. -- **Rationale:** Self-describing name. - -### 36. `HttpCallOptions` — `src/v2/utils.ts:15` +### 32. `HttpCallOptions` — `src/v2/utils.ts:15` - **Why weird:** Same as `dataquality` finding #40; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 37. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` +### 33. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` - **Why weird:** Same as `dataquality` finding #41; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 38. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` +### 34. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` - **Why weird:** Same as `dataquality` finding #42; variable named `call` of type `Call` repeated 5 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 39. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` +### 35. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` - **Why weird:** Same as `dataquality` finding #43 — `objectType`/`objectId` typed optional but required in practice for the URL path. Silently substitutes empty string producing malformed URLs like `/api/2.0/quality-monitors//`. Three call sites here. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. - **Rationale:** Type shape should match runtime requirement. -### 40. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 218-231` +### 36. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 218-231` - **Why weird:** Same as `dataquality` finding #44; two variables differ by `Body` only. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. - **Rationale:** Distinguish by meaningful nouns. -### 41. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` +### 37. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` - **Why weird:** Same as `dataquality` finding #45. - **Category:** 5, 12. - **Suggested name:** `httpRequest` (no abbreviation). @@ -278,24 +255,21 @@ The singular-vs-plural naming gives the reader no hint that these are different ## Observations -### 42. Heavy boilerplate dominates the file -`model.ts` is 512 lines for **15 user-facing types and 3 enums**; **350 lines (~68%)** are `marshal*` / `unmarshal*` Zod scaffolding. Higher boilerplate-to-content ratio than `dataquality` (~46%) because this package has fewer types but the same generator overhead per type. - -### 43. Action verbs in `Client` +### 38. Action verbs in `Client` The client uses `Create` / `Get` / `Update` / `Delete` / `List` for monitor operations. Verbs are consistent within the package. Listed per rule 17 to note the absence of inconsistency (relative to `qualitymonitors` plural, which adds `Cancel` / `Run` / `Regenerate`). -### 44. Acronym casing +### 39. Acronym casing Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `lastRunId`), `URL` (only via the web-standard `URLSearchParams`), `Sql` (capital-then-lower in `sqlQuery`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`). No within-package collisions. - **Category:** 3 (acronym casing). -### 45. No `wkt` (well-known types), `FieldMask`, or `time` imports +### 40. No `wkt` (well-known types), `FieldMask`, or `time` imports Unlike `dataquality` and other newer packages, this package has no `Timestamp`, `FieldMask`, or `Duration` fields. The lack of these is consistent with the package being older and frozen (deprecated) — newer features were added to `dataquality` instead. -### 46. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types +### 41. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types Same shape as the `dataquality` casing observation: directory is one collapsed word (`qualitymonitor`), wire path is kebab-plural (`/quality-monitors`), TS types are PascalCase singular (`QualityMonitor`). The directory plural-vs-singular question (relative to `qualitymonitors`) is unique to this package family. - **Category:** 3 (casing inconsistency), 9 (singular/plural mismatch). -### 47. Entire package is `@deprecated` per JSDoc +### 42. Entire package is `@deprecated` per JSDoc Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#27), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. ## Domain glossary diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md index 4ec1dd42..dba0982a 100644 --- a/.agent/naming-audit/qualitymonitors.md +++ b/.agent/naming-audit/qualitymonitors.md @@ -3,7 +3,7 @@ **Path:** `packages/qualitymonitors/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakehouse Monitoring on Unity Catalog tables (legacy/deprecated surface). The package models a `Monitor` per UC table with an `analysisConfig` chosen from `InferenceLog` / `TimeSeries` / `Snapshot`, scheduled refreshes (`Cancel` / `Get` / `List` / `Run`), Quartz cron scheduling, custom metric definitions (`Aggregate`/`Derived`/`Drift`), data classification toggles, dashboard regeneration, and notification routing on failure and on new classification tags. **Every** client method JSDoc starts with "Deprecated: Use Data Quality Monitors API instead (/api/data-quality/v1/monitors)" — this entire package is a deprecated wire-compatible facade for the `dataquality` package. -**Total weird names flagged:** 52 +**Total weird names flagged:** 50 ## CRITICAL: TWO co-existing packages with the same domain @@ -29,8 +29,8 @@ Three packages in this repository overlap on the same domain at the wire level: | --- | --- | | High | 13 | | Medium | 21 | -| Low | 11 | -| Observation | 7 | +| Low | 10 | +| Observation | 6 | ## High severity @@ -41,8 +41,8 @@ Three packages in this repository overlap on the same domain at the wire level: - **Rationale:** Package-level naming is the first cue a user gets. Singular vs plural in two npm names is a UX trap. ### 2. `DataMonitorInfo` — `src/v1/model.ts:213` -- **Why weird:** The package's central response type is named `DataMonitorInfo`, but no other type in the package uses the `Data` prefix. The companion request types are `CreateMonitor`, `UpdateMonitor`, `DeleteMonitor`, `GetMonitor` — all plain `Monitor`. The response alone is `DataMonitorInfo`, with `Data` and `Info` as filler. The `Info` suffix is Go-style ("XYZInfo" is a Go idiom for "details of an XYZ"). -- **Category:** 1 (vague — `Data` and `Info` are noise), 8 (redundant suffix — `Info`), 14 (Go-style naming), 17 (inconsistent — every other type in the package uses `Monitor`, only this one uses `DataMonitorInfo`), 20 (type-suffix tautology — `Info` adds no semantic content). +- **Why weird:** The package's central response type is named `DataMonitorInfo`, but no other type in the package uses the `Data` prefix. The companion request types are `CreateMonitor`, `UpdateMonitor`, `DeleteMonitor`, `GetMonitor` — all plain `Monitor`. The response alone is `DataMonitorInfo`, with `Data` and `Info` as filler. +- **Category:** 1 (vague — `Data` and `Info` are noise), 8 (redundant suffix — `Info`), 17 (inconsistent — every other type in the package uses `Monitor`, only this one uses `DataMonitorInfo`), 20 (type-suffix tautology — `Info` adds no semantic content). - **Suggested name:** `Monitor`. - **Rationale:** Every API in the client (`createMonitor`, `getMonitor`, `updateMonitor`) returns this type. Naming it `Monitor` aligns with the API verbs and with the sister `dataquality` package which already calls it `Monitor`. The `Data` and `Info` syllables are dead context. @@ -53,26 +53,26 @@ Three packages in this repository overlap on the same domain at the wire level: - **Rationale:** Cross-package import collisions force users to alias. ### 4. `fullTableNameArg` field — `src/v1/model.ts:95,107,286,302,307,334,379,399,423` -- **Why weird:** The field name carries the `_Arg` suffix which is a generator artefact — the doc clarifies "This field corresponds to the {full_table_name_arg} arg in the endpoint path." `Arg` is a Go/proto convention for "this is a URL path parameter, not a body field." In TS the body/path distinction is invisible to the caller; the suffix leaks the wire model. The same field appears identically in 9 of the 13 request types in the package, copy-pasted with the same JSDoc. -- **Category:** 5 (cryptic abbreviation — `Arg` for "argument"), 14 (Go/proto-style suffix that leaks wire details), 15 (generic naming via `Arg`). +- **Why weird:** The field name carries the `_Arg` suffix which is a generator artefact — the doc clarifies "This field corresponds to the {full_table_name_arg} arg in the endpoint path." `Arg` is a proto convention for "this is a URL path parameter, not a body field." In TS the body/path distinction is invisible to the caller; the suffix leaks the wire model. The same field appears identically in 9 of the 13 request types in the package, copy-pasted with the same JSDoc. +- **Category:** 5 (cryptic abbreviation — `Arg` for "argument"), 15 (generic naming via `Arg`). - **Suggested name:** `tableFullName` (matches the rest of the SDK's UC fully-qualified name convention; e.g. `dataquality.AnomalyDetectionConfig.excludedTableFullNames`). - **Rationale:** The `Arg` suffix advertises a wire artefact that has zero meaning at the TypeScript boundary. `tableFullName` is the established UC vocabulary across the SDK for three-part `catalog.schema.table` references. ### 5. `CustomMetricType` enum members `CUSTOM_METRIC_TYPE_*` — `src/v1/model.ts:14-19` - **Why weird:** Five-token names per member, with the enum name re-stated as a prefix on every value. At the call site you write `CustomMetricType.CUSTOM_METRIC_TYPE_AGGREGATE` — three repetitions of "custom metric type" before getting to the discriminating word (`AGGREGATE`). Also: the enum has an `_UNSPECIFIED` zero value carried over from protobuf that has no real-world meaning in TS (an unset value is already represented by `undefined`). -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names), 18 (overly long enum values). +- **Category:** 2 (redundant enum prefix), 18 (overly long enum values). - **Suggested name:** `CustomMetricType.{Aggregate, Derived, Drift}` (drop the prefix and the `_UNSPECIFIED` sentinel; rely on `type?: CustomMetricType | undefined`). - **Rationale:** TS enums already namespace values via the enum name. The wire string can remain `CUSTOM_METRIC_TYPE_AGGREGATE` (kept in the `z.enum(...)` literal) while the TS-side name is short. Same pattern is recommended in every other audited package (cf. `dataquality` #6). ### 6. `MonitorStatus` enum members `MONITOR_STATUS_*` — `src/v1/model.ts:21-28` - **Why weird:** Same pattern as #5 — four-token names where the enum name already provides the namespace. `MonitorStatus.MONITOR_STATUS_DELETE_PENDING` reads as "monitor status monitor status delete pending". Also: this enum has both `MONITOR_STATUS_ERROR` and `MONITOR_STATUS_FAILED` — two terminal failure values where the difference is unclear (the same pattern flagged in `dataquality.DataProfilingStatus`). -- **Category:** 2 (redundant enum prefix), 12 (duplicate concept — `ERROR` vs `FAILED`), 14 (proto-style), 18 (overly long enum values). +- **Category:** 2 (redundant enum prefix), 12 (duplicate concept — `ERROR` vs `FAILED`), 18 (overly long enum values). - **Suggested name:** `MonitorStatus.{Active, Pending, PendingDelete, Error, Failed}` (and ideally collapse `Error` and `Failed` to one value). - **Rationale:** Same as #5. The `ERROR`/`FAILED` ambiguity is a separate concern called out in JSDoc nowhere. ### 7. `ProblemType` enum members `PROBLEM_TYPE_*` — `src/v1/model.ts:30-34` - **Why weird:** Same pattern as #5/#6. Three values, all carrying the redundant prefix; also includes the `_UNSPECIFIED` zero value. Also: `ProblemType` is a generic name for "what kind of ML problem is this table's data about". Without the JSDoc on `InferenceLogAnalysisConfig.problemType` ("Problem type the model aims to solve"), the reader cannot tell that `ProblemType` is ML-specific (vs the more general English meaning of "problem"). -- **Category:** 1 (vague — `ProblemType` is generic), 2 (redundant prefix), 14 (proto-style), 18 (long values). +- **Category:** 1 (vague — `ProblemType` is generic), 2 (redundant prefix), 18 (long values). - **Suggested name:** `MlProblemType.{Classification, Regression}` or `InferenceProblemType.{Classification, Regression}` (matches `dataquality.InferenceProblemType`). - **Rationale:** Sibling package `dataquality` already uses `InferenceProblemType`; this package should match. The generic `ProblemType` could mean anything outside ML. @@ -96,13 +96,13 @@ Three packages in this repository overlap on the same domain at the wire level: ### 11. `CancelRefresh_Response` / `DeleteMonitor_Response` / `ListRefreshes_Response` / `RegenerateDashboard_Response` — `src/v1/model.ts:100,290,338,388` - **Why weird:** Four interfaces use the `_` underscore separator in their identifier (`CancelRefresh_Response`). The eslint comments on each (`@typescript-eslint/naming-convention`) confirm that this style violates the project's own naming rules and is whitelisted only because the proto generator emits "nested message" names this way. In TS, underscores in PascalCase identifiers are wrong — the convention is camelCase/PascalCase, no separators. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style "nested message" names). +- **Category:** 4 (underscores in TS identifiers). - **Suggested name:** `CancelRefreshResponse` / `DeleteMonitorResponse` / `ListRefreshesResponse` / `RegenerateDashboardResponse`. - **Rationale:** The eslint disable comment is a smoking gun that the names violate the project's own rules. Sister packages (e.g., `dataquality`) use unsuffixed PascalCase like `CancelRefreshResponse`. ### 12. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` - **Why weird:** Same shape as `dataquality.DataProfilingConfig.analysisConfig` (audit #10 in that package). The field is named `analysisConfig`, but its arms are types named `InferenceLogAnalysisConfig`, `TimeSeriesAnalysisConfig`, `SnapshotAnalysisConfig` — three names ending in `AnalysisConfig`. The discriminator is `$case`, the arm key matches the arm payload type's prefix (e.g., `inferenceLog` for `InferenceLogAnalysisConfig`). Naming the variants `$case` is a ts-proto convention foreign to TypeScript culture; the more idiomatic discriminator is `kind` or `type`. -- **Category:** 1 (vague — `$case` is unusual TS), 12 (duplicate concept — `AnalysisConfig` repeated 3 times), 14 (ts-proto-style discriminator), 20 (type-suffix tautology — `AnalysisConfig` on every arm). +- **Category:** 1 (vague — `$case` is unusual TS), 12 (duplicate concept — `AnalysisConfig` repeated 3 times), 20 (type-suffix tautology — `AnalysisConfig` on every arm). - **Suggested name:** Field name: `analysis`. Discriminator: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. Arm payloads: keep `InferenceLogAnalysisConfig` or rename to `InferenceLogAnalysis` / `TimeSeriesAnalysis` / `SnapshotAnalysis`. - **Rationale:** `$case` is a ts-proto idiom; in idiomatic TS you write `if (config.analysis.kind === 'inferenceLog')`, not `if (config.analysisConfig?.$case === 'inferenceLog')`. @@ -116,7 +116,7 @@ Three packages in this repository overlap on the same domain at the wire level: ### 14. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitor`) - **Why weird:** Every field on `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo` has a prefix annotation in its JSDoc — `[Create:REQ Update:REQ]`, `[Create:OPT Update:OPT]`, `[Create:ERR Update:IGN]` — that encodes per-operation requirement semantics in the comment. These are generator markers, not human-friendly. A user opening the JSDoc tooltip sees `[Create:ERR Update:IGN]` and must decode "ERR means errors if you pass this, IGN means it's ignored on update". The TypeScript type does not enforce any of this. -- **Category:** 6 (misleading — comment marker pretends to be authoritative but is not enforced), 14 (Go/proto-style annotation), 18 (long, noisy comment prefix). +- **Category:** 6 (misleading — comment marker pretends to be authoritative but is not enforced), 18 (long, noisy comment prefix). - **Suggested name:** Remove the markers from comments. Encode the semantics in the type (separate `CreateMonitor` vs `UpdateMonitor` vs `Monitor` types with the right optionality and field presence). - **Rationale:** Doc markers are not type-checked. They look like type annotations but are inert. @@ -229,7 +229,7 @@ Three packages in this repository overlap on the same domain at the wire level: - **Rationale:** Python's `predict_proba` is sklearn vocabulary; a TS SDK should not require knowing sklearn to read field names. ### 33. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` -- **Why weird:** `Col` is an abbreviation for `Column`. Five fields on `InferenceLogAnalysisConfig` use it. Same in `TimeSeriesAnalysisConfig.timestampCol`. The Go SDK uses `Col` (matches the wire `_col` suffix). TS has no length constraint. +- **Why weird:** `Col` is an abbreviation for `Column`. Five fields on `InferenceLogAnalysisConfig` use it. Same in `TimeSeriesAnalysisConfig.timestampCol`. TS has no length constraint. - **Category:** 5 (cryptic abbreviation — `Col`). - **Suggested name:** `timestampColumn`, `predictionColumn`, `labelColumn`, `modelIdColumn`, `predictionProbabilityColumn`. - **Rationale:** Full words; matches `dataquality.InferenceLogConfig` if that package has the same pattern (worth cross-checking). @@ -278,49 +278,43 @@ Three packages in this repository overlap on the same domain at the wire level: - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the reality. -### 41. `marshalRequest` and `parseResponse` — `src/v1/utils.ts:113,119` -- **Why weird:** Same as `dataquality` audit #38. Names promise request/response but work on any payload + schema. -- **Category:** 1, 6. -- **Suggested name:** `encodeToJson` / `decodeFromJson`. -- **Rationale:** Symmetric verbs. - -### 42. `readAll` — `src/v1/utils.ts:40` +### 41. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Same as `dataquality` audit #39. "ReadAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing. -### 43. `HttpCallOptions` — `src/v1/utils.ts:15` +### 42. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataquality` audit #40. Internal context bag named `Options` — collides with the public `CallOptions` / `ClientOptions` semantics. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 44. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` +### 43. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` - **Why weird:** Same as `dataquality` audit #41. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Domain-word missing. -### 45. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,133,174,214,252,290,330,373,415` +### 44. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,133,174,214,252,290,330,373,415` - **Why weird:** Same as `dataquality` audit #42. Variable `call: Call` in 9 methods. - **Category:** 1, 12. - **Suggested name:** `request` (variable). - **Rationale:** Type/variable collision. -### 46. `respBody` vs `resp` — every method in `client.ts` +### 45. `respBody` vs `resp` — every method in `client.ts` - **Why weird:** Same as `dataquality` audit #44. Two variables differ only by `Body`. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. - **Rationale:** Distinguish by meaningful nouns. -### 47. `httpReq` local — every method in `client.ts` +### 46. `httpReq` local — every method in `client.ts` - **Why weird:** Same as `dataquality` audit #45. - **Category:** 5, 12. - **Suggested name:** `httpRequest`. - **Rationale:** No abbreviation. -### 48. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,130,172,212,250,288,327,370,412` +### 47. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,130,172,212,250,288,327,370,412` - **Why weird:** Same as `dataquality` audit #43. `fullTableNameArg` typed optional but required in practice; silent empty-string substitution yields URLs like `/api/2.1/unity-catalog/tables//monitor`. - **Category:** 6. - **Suggested name:** Make `fullTableNameArg` non-optional on every request type. @@ -328,29 +322,26 @@ Three packages in this repository overlap on the same domain at the wire level: ## Observations -### 49. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" +### 48. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" - **Note:** All 9 client methods (`cancelRefresh`, `createMonitor`, `deleteMonitor`, `getMonitor`, `getRefresh`, `listRefreshes`, `regenerateDashboard`, `runRefresh`, `updateMonitor`) start their JSDoc with that sentence. None uses the `@deprecated` JSDoc tag, so editors do not render the deprecation visually. The package is deprecated in spirit, but live in build. -### 50. Acronym casing +### 49. Acronym casing - `Id` (capital-then-lower in `refreshId`, `dashboardId`, `warehouseId`, `monitorVersion`); `Ms` (`startTimeMs`, `endTimeMs`); `Http` (in imported types). No within-package collisions, all generator-emitted. - **Category:** 3 (acronym casing). -### 51. URL paths mix `unity-catalog` and `quality-monitoring` +### 50. URL paths mix `unity-catalog` and `quality-monitoring` - **Note:** Eight of nine methods use `/api/2.1/unity-catalog/tables/{}/monitor[/...]`; one (`regenerateDashboard`) uses `/api/2.1/quality-monitoring/tables/{}/monitor/dashboard`. The package name does not match either prefix. The sister `dataquality` package uses `/api/data-quality/v1/monitors`. - **Category:** 17 (inconsistent — package name vs wire path). -### 52. Boilerplate ratio -- `model.ts` is 935 lines for ~17 user-facing types and 6 enums; ~440 lines (47%) are `marshal*` / `unmarshal*Schema` scaffolding. Same shape as `dataquality`. - -### 53. No `FieldMask` types +### 51. No `FieldMask` types - This package does not have any `FieldMask<...>` types (unlike `dataquality`). The deprecated API does not support partial updates via field masks; the entire monitor body is replaced on `PUT`. (Listed as observation to contrast with sibling packages.) -### 54. Verb consistency +### 52. Verb consistency - `Cancel`, `Create`, `Delete`, `Get`, `List`, `Regenerate`, `Run`, `Update` — eight different verbs in nine methods. Within the package the verbs are appropriate and consistent. The unusual one is `Regenerate` (vs `Recreate` or `RebuildDashboard`) — generator-driven choice, fine in context. - **Category:** 17 (verb inventory, none inconsistent). -### 55. `Notifications` is a slim type with two channel fields -- Two-channel `Notifications` (`onFailure`, `onNewClassificationTagDetected`) follows the proto / Go SDK shape. A TS-idiomatic shape might be `notifications: Array<{channel: 'failure' | 'newClassificationTag', destination: Destination}>` to allow future expansion. Listed as observation, not a flag. +### 53. `Notifications` is a slim type with two channel fields +- Two-channel `Notifications` (`onFailure`, `onNewClassificationTagDetected`) follows the proto shape. A TS-idiomatic shape might be `notifications: Array<{channel: 'failure' | 'newClassificationTag', destination: Destination}>` to allow future expansion. Listed as observation, not a flag. ## Domain glossary - `uc` / Unity Catalog — the resource container for the monitored table. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index 98936296..8cea4a70 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 39 +**Total weird names flagged:** 38 ## Summary table @@ -21,34 +21,32 @@ | 10 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | | 11 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | | 12 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | -| 13 | High | `model.ts` field | `Query.schema` | Reserved-word collision (`schema` is a top-level keyword in JSON Schema/Zod terminology used throughout this file) | -| 14 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | -| 15 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | -| 16 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | -| 17 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | -| 18 | Medium | `client.ts` method | `listQueriesIter`, `listVisualizationsForQueryIter` | Cryptic abbreviation (`Iter` from Go/Rust) | -| 19 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | -| 20 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 21 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | -| 22 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | -| 23 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | -| 24 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | -| 25 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | -| 26 | Medium | `model.ts` enum values | `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` | Redundant enum prefix (enum already named `DatePrecision`) | -| 27 | Medium | `model.ts` enum | `DateRangeValue_DynamicDateRange` | Long enum values + Go/Java-style `_` separator | -| 28 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | -| 29 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | -| 30 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | -| 31 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | -| 32 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | -| 33 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | -| 34 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | -| 35 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | -| 36 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | -| 37 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | -| 38 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | -| 39 | Low | `model.ts` enum value | `DateValue_DynamicDate.NOW` and `YESTERDAY` | Singular/plural mismatch with sibling `DateRangeValue_DynamicDateRange.YESTERDAY` (same value lives in both enums) | -| 40 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | +| 13 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | +| 14 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | +| 15 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 16 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 17 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 18 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 19 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | +| 20 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | +| 21 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | +| 22 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | +| 23 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 24 | Medium | `model.ts` enum values | `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` | Redundant enum prefix (enum already named `DatePrecision`) | +| 25 | Medium | `model.ts` enum | `DateRangeValue_DynamicDateRange` | Long enum values + Go/Java-style `_` separator | +| 26 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | +| 27 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | +| 28 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | +| 29 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | +| 30 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | +| 31 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | +| 32 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | +| 33 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | +| 34 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | +| 35 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | +| 36 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | +| 37 | Low | `model.ts` enum value | `DateValue_DynamicDate.NOW` and `YESTERDAY` | Singular/plural mismatch with sibling `DateRangeValue_DynamicDateRange.YESTERDAY` (same value lives in both enums) | +| 38 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | ## High severity @@ -233,18 +231,7 @@ export interface EnumValue { `EnumValue` exported at the package root. `enum` is a TypeScript keyword and a generic concept; the type is in fact a *dropdown* parameter source (a list of valid options + the selected subset). `DropdownParameter`, `EnumParameter`, or `QueryEnumParameter` would name the actual concept. -### 13. `Query.schema` — reserved-word/local-keyword collision - -**Location:** `src/v1/model.ts:255-256` - -```ts -/** Name of the schema where this query will be executed. */ -schema?: string | undefined; -``` - -`schema` is a Unity-Catalog *schema* name. But the same file uses the word `schema` ~30 times to mean `z.ZodType` (`marshalQuerySchema`, `unmarshalQuerySchema`, `updateQueryRequestQueryFieldMaskSchema`). The collision is internal-only, but for a reader the noun `schema` ambiguously means UC-schema OR Zod-schema depending on context. `databaseSchema` or `unityCatalogSchema` would disambiguate. (Same package has `catalog` as a sibling field — together they would be `query.unityCatalogCatalog` which is itself ridiculous; the right fix is to keep `catalog` and `schema` but rename the Zod schemas.) - -### 14. `QueryParameter.title` vs `.name` — misleading pair +### 13. `QueryParameter.title` vs `.name` — misleading pair **Location:** `src/v1/model.ts:268-272` @@ -260,7 +247,7 @@ export interface QueryParameter { Reading the field names alone, `name` is the identifier and `title` is a richer/longer display string. The JSDoc inverts this: `name` is the literal `{{marker}}` text that appears in the SQL, and `title` is the human-readable widget label. The conventional pairing in this codebase (and most others) is `(name, displayName)`. Here it is `(name, title)` *and* `name` plays the role most SDK shapes give to `key`/`marker`/`identifier` and `title` plays the role of `displayName`. A reader has to consult JSDoc to tell which is which. -### 15. `Query.queryText` JSDoc — "Text of the query to be run" on a type already called `Query` +### 14. `Query.queryText` JSDoc — "Text of the query to be run" on a type already called `Query` **Location:** `src/v1/model.ts:68-69`, `174-175`, `234-235`, `335-336` @@ -277,7 +264,7 @@ Both the field name and the JSDoc embed the word "query" on a type called `Query ## Medium severity -### 16. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) +### 15. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) **Location:** `src/v1/client.ts:227-250` @@ -291,7 +278,7 @@ async trashQuery( The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 17. `TrashQueryRequest` — same as #16, in the type layer +### 16. `TrashQueryRequest` — same as #15, in the type layer **Location:** `src/v1/model.ts:312-314` @@ -303,25 +290,7 @@ export interface TrashQueryRequest { Same verb inconsistency at the type layer. Carries only `id`. -### 18. `listQueriesIter`, `listVisualizationsForQueryIter` — cryptic abbreviation - -**Location:** `src/v1/client.ts:156-171`, `210-225` - -```ts -async *listQueriesIter( - req: ListQueriesRequest, - options?: CallOptions -): AsyncGenerator { ... } - -async *listVisualizationsForQueryIter( - req: ListVisualizationsForQueryRequest, - options?: CallOptions -): AsyncGenerator { ... } -``` - -`Iter` reads as a Go/Rust port (Go SDK uses `*Iterator`, Rust uses `iter()`). Idiomatic TS would name this `listAllQueries`, `iterateQueries`, or simply make `listQueries` return an async iterable. - -### 19. `listVisualizationsForQuery` — overly verbose +### 17. `listVisualizationsForQuery` — overly verbose **Location:** `src/v1/client.ts:173-208` @@ -334,7 +303,7 @@ async listVisualizationsForQuery( `For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. -### 20. `Visualization` — vague/generic top-level name +### 18. `Visualization` — vague/generic top-level name **Location:** `src/v1/model.ts:360-377` @@ -344,7 +313,7 @@ export interface Visualization { ... } `Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. -### 21. `Query.warehouseId` — underspecified ID +### 19. `Query.warehouseId` — underspecified ID **Location:** `src/v1/model.ts:66-67`, `172-173`, `232-233`, `333-334` @@ -355,7 +324,7 @@ warehouseId?: string | undefined; The JSDoc says "SQL warehouse"; the field says `warehouseId`. Databricks has data warehouses, Lakehouse, SQL warehouses, etc. `sqlWarehouseId` would self-document. -### 22. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar +### 20. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar **Location:** `src/v1/model.ts:64-65`, `74-75` @@ -369,7 +338,7 @@ lastModifierUserName?: string | undefined; `owner` is a noun. `lastModifier` is an agent noun constructed from the verb "modify." The pairing is mismatched — either both should be agent nouns (`ownerUserName`, `lastModifierUserName`) or both should be participial (`ownedBy`, `lastModifiedBy`). The Go convention is the former; idiomatic TS leans toward the latter. Also note the JSDoc inconsistency: "the user that owns" vs "the user who last saved" — different relative pronouns. -### 23. `Query.lastModifierUserName` — overly verbose +### 21. `Query.lastModifierUserName` — overly verbose **Location:** `src/v1/model.ts:74-75` @@ -379,13 +348,13 @@ lastModifierUserName?: string | undefined; 21 characters for what is, semantically, "last-modified-by." `lastModifiedBy` is 14 characters and more natural English. -### 24. `LifecycleState.TRASHED` — verb-tense inconsistency +### 22. `LifecycleState.TRASHED` — verb-tense inconsistency **Location:** `src/v1/model.ts:14-17` The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). -### 25. `RunAsMode` — verb-as-noun, filler `Mode` +### 23. `RunAsMode` — verb-as-noun, filler `Mode` **Location:** `src/v1/model.ts:19-22` @@ -398,7 +367,7 @@ export enum RunAsMode { `RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. -### 26. `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` — redundant enum prefix +### 24. `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` — redundant enum prefix **Location:** `src/v1/model.ts:8-12` @@ -412,13 +381,13 @@ export enum DatePrecision { Access is `DatePrecision.DAY_PRECISION` — the enum name already says "precision." `DAY`/`MINUTE`/`SECOND` would suffice. -### 27. `DateRangeValue_DynamicDateRange` — long enum + Go-style underscore +### 25. `DateRangeValue_DynamicDateRange` — long enum + Go-style underscore **Location:** `src/v1/model.ts:24-43` The enum *name* has a `_` separator (see #7 high). Beyond that, the enum *values* like `LAST_8_HOURS`, `LAST_24_HOURS` discretize a continuous space — only 16 fixed buckets. -### 28. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... +### 26. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... **Location:** `src/v1/model.ts:25-42` @@ -436,7 +405,7 @@ LAST_12_MONTHS = 'LAST_12_MONTHS', The user gets 16 hard-coded time windows. If they want "last 45 days," there is no value. A `{ unit: 'DAY' | 'HOUR' | ...; n: number }` shape would express the same thing without the enum-value explosion. (Acknowledged that the underlying API likely accepts only these buckets — but the API design itself is the smell.) -### 29. `Query.applyAutoLimit` — misleading verb predicate +### 27. `Query.applyAutoLimit` — misleading verb predicate **Location:** `src/v1/model.ts:85-87` @@ -447,7 +416,7 @@ applyAutoLimit?: boolean | undefined; The name reads as an imperative action ("apply the auto limit!") rather than a flag. `autoLimit` (boolean) or `autoLimitRows` (number) would parse more naturally as state. The "1000" rule is in the JSDoc, not the type — `autoLimit: number` with the convention "1000 if true, 0 if disabled" would surface the magic number. -### 30. `Query.runAsMode` — type-suffix tautology +### 28. `Query.runAsMode` — type-suffix tautology **Location:** `src/v1/model.ts:70-71` @@ -458,7 +427,7 @@ runAsMode?: RunAsMode | undefined; Field of type `RunAsMode` named `runAsMode`. `runAs` would suffice (the type already encodes "mode"). -### 31. `Query.parentPath` — underspecified +### 29. `Query.parentPath` — underspecified **Location:** `src/v1/model.ts:76-77` @@ -469,7 +438,7 @@ parentPath?: string | undefined; "Parent" of what? The JSDoc clarifies it is the workspace-folder path. `workspaceFolderPath` would self-document. `parentPath` reads like a filesystem path or a Git ref to first-time readers. (The same field appears in `alerts` — flagged there too.) -### 32. `MultiValuesOptions` — singular/plural mismatch +### 30. `MultiValuesOptions` — singular/plural mismatch **Location:** `src/v1/model.ts:210-217` @@ -486,13 +455,13 @@ export interface MultiValuesOptions { `MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). -### 33. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context +### 31. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context **Location:** `src/v1/model.ts:210-217` `prefix`, `separator`, `suffix` are completely generic outside the surrounding type. The JSDoc says "Character that prefixes each selected parameter value" — they are not characters, they are arbitrary strings (typed `string`). `valuePrefix`, `valueSeparator`, `valueSuffix` would be self-documenting and the type-level `MultiValuesOptions` could drop the leading "Multi-Values" altogether. -### 34. `Visualization.type` — reserved-word collision +### 32. `Visualization.type` — reserved-word collision **Location:** `src/v1/model.ts:365-366` @@ -503,7 +472,7 @@ type?: string | undefined; `type` is a TS keyword (used in `type Foo = …`) and a generic field name. The JSDoc admits it is "counter, table, funnel, and so on" — i.e., an open-ended string enum (no domain enum is defined). `visualizationType` or `kind` would avoid the keyword issue. -### 35. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading +### 33. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading **Location:** `src/v1/model.ts:371-374` @@ -516,7 +485,7 @@ serializedOptions?: string | undefined; Field names imply "the data, in serialized form." JSDoc admits the format is undocumented and the field should not be modified. If users are not supposed to construct these, they should not be on a public type (or they should be typed `Readonly` with a clear name like `internalQueryPlan`/`opaqueOptions`). -### 36. `DateRangeValue.startDayOfWeek` — underspecified type +### 34. `DateRangeValue.startDayOfWeek` — underspecified type **Location:** `src/v1/model.ts:113` @@ -528,19 +497,19 @@ startDayOfWeek?: number | undefined; ## Low severity -### 37. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency +### 35. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency **Location:** `src/v1/model.ts:58-59`, `362-363`, `262-263` Top-level types use bare `id`; cross-referencing types use `queryId`. `Query.queryId` would be consistent with `Visualization.queryId` and `QueryBackedValue.queryId`. Currently `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` means there are two conventions side-by-side. -### 38. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination +### 36. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination **Location:** `src/v1/model.ts:153-156`, `158-161` Standard Google AIP-158 names. Flagged for completeness; no action recommended. -### 39. `DateValue_DynamicDate.NOW`, `YESTERDAY` — sibling enum overlap +### 37. `DateValue_DynamicDate.NOW`, `YESTERDAY` — sibling enum overlap **Location:** `src/v1/model.ts:45-49` @@ -553,7 +522,7 @@ export enum DateValue_DynamicDate { `YESTERDAY` appears here *and* in `DateRangeValue_DynamicDateRange`. The two enums share at least one literal value but are not assignable to each other (TS enums are nominal). A shared `RelativeDate` enum (`NOW`, `YESTERDAY`, `LAST_HOUR`, ...) with sub-grouping would avoid the duplication. -### 40. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. +### 38. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. **Location:** `src/v1/model.ts:292`, `297` @@ -596,10 +565,6 @@ Observations: 5. **`utils.ts` is well-named and unchanged.** Exports (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are domain-neutral and not flagged. `flattenQueryParams` is exported but unused in `client.ts` (orphaned export) — not a naming issue, but worth noting. -6. **`Iter` suffix.** `listQueriesIter`, `listVisualizationsForQueryIter` — Go/Rust-flavoured method names. Will appear in every generated package; flag at the generator level. - -7. **`schema` ambiguity.** The file uses `schema` to mean both a Unity-Catalog schema (field on `Query`) and a Zod schema (`marshalQuerySchema`, etc.). The two never collide at the type level but the prose-level overloading hurts code review. - ## Domain glossary | Term | Meaning in this package | diff --git a/.agent/naming-audit/queryexecution.md b/.agent/naming-audit/queryexecution.md index 36f8f931..baccb52a 100644 --- a/.agent/naming-audit/queryexecution.md +++ b/.agent/naming-audit/queryexecution.md @@ -9,14 +9,14 @@ GET = poll, DELETE = cancel). The package name (`queryexecution`) is much broade what it actually does (lakeview-dashboard query lifecycle). Confusing overlap with sibling packages `statementexecution` (general SQL Statement Execution API), `queryhistory` (history of executed queries), and `queries` (saved query definitions). -**Total weird names flagged:** 36 +**Total weird names flagged:** 30 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 15 | -| Low | 9 | +| High | 6 | +| Medium | 12 | +| Low | 8 | | Observation | 4 | ## High severity @@ -39,151 +39,122 @@ sibling packages `statementexecution` (general SQL Statement Execution API), - **Suggested name:** `ExecutePublishedQueryResponse` (matching scope). - **Rationale:** The asymmetric prefix forces callers to mentally translate between two near-identical names. Symmetric request/response pairs are the SDK norm. -### 4. `CancelQueryExecutionResponseStatus.status` discriminated union — `src/v1/model.ts:22-32` -- **Why weird:** The type is named `CancelQueryExecutionResponseStatus` (so `Status`-the-suffix), but its main payload is *also* called `status` (a discriminated union over `success`/`pending`). So you write `responseStatus.status` to access the status of the status. -- **Category:** 1 (vague — `status.status` reads as redundant), 12 (duplicate concept — same word twice in one expression), 20 (type-suffix tautology). -- **Suggested name:** Rename outer type to `CancelTokenResult` (or `CancelOutcome`). -- **Rationale:** When the same word appears at two adjacent levels of a structure (`x.status.status`), it usually means one of them is misnamed. Here the inner one is the actual discriminant; the outer "Status" is a redundant suffix. - -### 5. `PollQueryStatusResponse.data` — `src/v1/model.ts:82` +### 4. `PollQueryStatusResponse.data` — `src/v1/model.ts:82` - **Why weird:** Top-level field named `data` on a response object. `data` is the most generic possible field name (rule 15 in the prompt: "Generic field names losing meaning"). It happens to hold *per-token statuses*, but the name gives a reader zero hint of that. - **Category:** 1 (vague), 15 (generic field name losing meaning). - **Suggested name:** `statuses` (plural, matches the array shape) or `tokenStatuses`. - **Rationale:** `data` should never be the name of the only field on a response. The wire calls it `data`, but a TS SDK can do better. -### 6. `QueryResponseStatus` vs. `CancelQueryExecutionResponseStatus` — `src/v1/model.ts:22,89` +### 5. `QueryResponseStatus` vs. `CancelQueryExecutionResponseStatus` — `src/v1/model.ts:22,89` - **Why weird:** Two near-identical types differ only by the verbs they accept (`CancelQueryExecutionResponseStatus` has `success`/`pending`, `QueryResponseStatus` has `success`/`pending`/`canceled`/`closed`). Both wrap discriminated unions over the same vocabulary. They could be unified by making the cancel response use a subset of `QueryResponseStatus`. The fact that the names are *different but parallel* makes the duplication harder to spot. - **Category:** 12 (duplicate concept — two types modelling the same idea), 17 (inconsistent action-verb prefix — one uses `Cancel*ResponseStatus`, the other uses `*ResponseStatus`). - **Suggested name:** Collapse into one `QueryResponseStatus`, drop the `Cancel*ResponseStatus` and use the unified type with only the arms that apply. - **Rationale:** Two types with the same purpose is a maintenance hazard. The names actively conceal the duplication by spelling things differently. -### 7. `Client` class name — `src/v1/client.ts:41` +### 6. `Client` class name — `src/v1/client.ts:41` - **Why weird:** A class literally named `Client` at the top level of the package's API surface, re-exported as just `Client`. Identical to `dataclassification.md` Finding #11 and a repeated pattern across the SDK. A user importing `Client` from `@databricks/sdk-queryexecution` and another `Client` from `@databricks/sdk-statementexecution` collides on the namespace. - **Category:** 1 (vague — `Client` is the most generic name possible), 15 (generic name). - **Suggested name:** `QueryExecutionClient` (or, per #1, `PublishedDashboardQueryClient`). - **Rationale:** Same as the cross-SDK pattern: every API package has a `Client`, and combined imports require renaming. The collision risk grows with each added package. -### 8. `unmarshalPollQueryStatusResponseDataSchema` — `src/v1/model.ts:167` -- **Why weird:** Five stacked words: `unmarshal` + `Poll` + `QueryStatus` + `Response` + `Data` + `Schema`. The triple-`Schema`-like suffix repeats both `Status` (from inner) and `Schema` (from zod-helper convention). The variable definition spans three lines just by signature. Worst-offender length in the file. -- **Category:** 5 (cryptic — hard to parse), 7 (overly verbose), 8 (redundant suffix — `Response` + `Data` are both meta-suffixes), 14 (Go-style `marshal`/`unmarshal`). -- **Suggested name:** `decodeTokenStatusEntrySchema`. -- **Rationale:** A function name should fit a short line. Five stacked qualifiers is a sign that several layers of abstraction are leaking into the identifier. - ## Medium severity -### 9. `PendingStatus` and `SuccessStatus` types — `src/v1/model.ts:60,105` +### 7. `PendingStatus` and `SuccessStatus` types — `src/v1/model.ts:60,105` - **Why weird:** Two types share the `Status` suffix, but only one of them ("Success") carries the `truncated` boolean. Their names suggest they are siblings of an enum (`Pending` vs `Success`), but `Pending` only has `dataToken`, while `Success` has `dataToken` + `truncated`. This means the *only* thing that distinguishes a "success" from a "pending" at the type level is the *presence* of `truncated` — but since `truncated` is `optional`, neither type's instance can be reliably distinguished from the other. - **Category:** 6 (misleading — types are technically distinguishable but in practice not), 16 (field contradicts type domain — `truncated` is meaningless on `Pending` but exists structurally), 17 (asymmetric). - **Suggested name:** Keep names but make `truncated` required (non-optional) on `SuccessStatus`, or merge them: `interface QueryToken { dataToken?: string; truncated?: boolean }` with the state encoded by the discriminator only. - **Rationale:** When two state-variant types differ only by one optional field, they shouldn't be separate types. -### 10. `dataToken` field — `src/v1/model.ts:27,65,110` +### 8. `dataToken` field — `src/v1/model.ts:27,65,110` - **Why weird:** The field is described inline as "The token to poll for result asynchronously". The name `dataToken` doesn't communicate that — it sounds like a token that wraps data. The JSDoc even admits that `data_token` and `statement_id` (in the parent type) are the *same value* on the wire ("The statement_id should be identical to data_token in SuccessStatus and PendingStatus."). The fact that the wire has two names for the same value (one is the polling cursor, the other is the audit-log identifier) is a wire-protocol decision that leaks into the TS surface. -- **Category:** 1 (vague — `dataToken` could mean anything), 5 (cryptic abbreviation — "data" of what?), 12 (duplicate concept — `dataToken` and `statementId` are the same value), 19 (underspecified ID — see also #11). +- **Category:** 1 (vague — `dataToken` could mean anything), 5 (cryptic abbreviation — "data" of what?), 12 (duplicate concept — `dataToken` and `statementId` are the same value), 19 (underspecified ID — see also #9). - **Suggested name:** `pollToken` or `pollingToken` (matches its purpose). If the duplication with `statementId` is fixed at the wire level, drop entirely. - **Rationale:** A field whose JSDoc says "this is identical to another field" is screaming for a rename. `pollToken` describes its function; `dataToken` describes its construction. -### 11. `statementId` field — `src/v1/model.ts:102` +### 9. `statementId` field — `src/v1/model.ts:102` - **Why weird:** A field called `statementId` appearing on `QueryResponseStatus`, accompanied by a 4-line JSDoc explaining that it is "created for audit logging purpose to record the statement_id of all QueryResponseStatus". So this is an audit-only field that duplicates `dataToken`. In a typed API, an audit-only field is something the client should *never* set or rely on — but the type doesn't say `readonly` and there's no convention enforcing that. - **Category:** 6 (misleading — looks like a regular ID, is audit-only), 12 (duplicate concept), 19 (underspecified — what kind of "statement"? Compare to `statementexecution` package's `statementId` which means the SQL Statement Execution API ID). - **Suggested name:** `auditStatementId` (or remove from the public surface). If kept, document `@readonly`. - **Rationale:** Audit/log-only fields on a typed response are a footgun. The current name promises usability; the doc explains it isn't. -### 12. `tokens` field — `src/v1/model.ts:13,76` +### 10. `tokens` field — `src/v1/model.ts:13,76` - **Why weird:** Field called `tokens` with example value `EC0A..ChAB7WCEn_4...`. The JSDoc only shows one example; no plural-form documentation. The wire spec apparently allows multiple tokens (since the field is `string[]`), and the SDK serializes the array via `String(req.tokens)` — which means JS does `tokens.join(',')` (the array's default `toString`). This is fragile: if a token ever contains a comma, the URL becomes corrupt. The name `tokens` doesn't communicate "comma-separated on the wire". - **Category:** 1 (vague — `tokens` of what?), 5 (cryptic — token value example dominates over a description), 6 (misleading — the array-to-string conversion is implicit). -- **Suggested name:** `pollTokens` (matches the proposal in #10). If the wire really expects comma-separated, document that on the field; otherwise use `URLSearchParams.append` per-token. +- **Suggested name:** `pollTokens` (matches the proposal in #8). If the wire really expects comma-separated, document that on the field; otherwise use `URLSearchParams.append` per-token. - **Rationale:** The name `tokens` is too generic for a top-level request field. The hidden join-on-comma is a bug magnet. -### 13. `dashboardName` field — `src/v1/model.ts:14,51,77` +### 11. `dashboardName` field — `src/v1/model.ts:14,51,77` - **Why weird:** Field is `dashboardName` but appears alongside `dashboardRevisionId`. The pairing `Name` + `Id` is inconsistent — they should be either both names or both IDs. The wire calls the first one `dashboard_name` and the second `dashboard_revision_id`, so the asymmetry is upstream — but a TS SDK could rename for symmetry. The JSDoc says: "Dashboard name and revision_id is required to retrieve PublishedDatasetDataModel". The casual `_id`/`Id` shift is jarring. - **Category:** 17 (asymmetric pair naming — `Name` vs `Id`). - **Suggested name:** `dashboardId` + `dashboardRevisionId` (if both are IDs on the wire) or document why one is "name" while the other is "ID". - **Rationale:** Symmetric pair fields should have symmetric naming. A user looking at the request would assume `Name` is human-readable and `RevisionId` is opaque — but typically both are opaque identifiers in published-dashboard URLs. -### 14. `overrideWarehouseId` field — `src/v1/model.ts:54` +### 12. `overrideWarehouseId` field — `src/v1/model.ts:54` - **Why weird:** Field name is fine in isolation, but unusual that there is no plain `warehouseId` field for context. The JSDoc explains: "A dashboard schedule can override the warehouse used as compute for processing the published dashboard queries". Reading the model in isolation, a user has no way to know that *not* setting `overrideWarehouseId` means the dashboard's *configured* warehouse is used. The name carries baggage that requires reading the JSDoc to decode. - **Category:** 1 (vague — "override" of what?), 6 (misleading — implies a write to a property, is actually an optional override). - **Suggested name:** Keep but make sure the JSDoc is exhaustive about the fallback behaviour. Alternatively `warehouseIdOverride` (English noun order — read "the override of warehouseId"). - **Rationale:** Override-fields are common; the only fix is documentation. Flagged for consistency. -### 15. `dashboardRevisionId` field — `src/v1/model.ts:15,52,78` +### 13. `dashboardRevisionId` field — `src/v1/model.ts:15,52,78` - **Why weird:** The wire format on the published dashboard URL uses `dashboard_revision_id`. The TS name flatten-converts. But internally this is the "version" of the dashboard, and the broader SDK uses `revision` and `version` inconsistently (e.g., `apps` package uses `currentRevision`, etc.). Verifying SDK-wide vocabulary would be valuable. - **Category:** 17 (potential inconsistency with sibling SDK packages — flagged for review). - **Suggested name:** Keep as-is unless a wider SDK convention dictates `version`. - **Rationale:** Low confidence; flagged to ensure SDK consistency check. -### 16. `marshalExecutePublishedDashboardQueryRequestSchema` — `src/v1/model.ts:209` -- **Why weird:** Single longest exported name in the model file (50 characters). Six stacked qualifiers: `marshal`+`Execute`+`PublishedDashboardQuery`+`Request`+`Schema`. Required to be camelCase to fit ESLint. Almost impossible to read aloud. -- **Category:** 5 (cryptic — visual density), 7 (overly verbose), 8 (redundant suffix — `Request`+`Schema` is two layers of meta). -- **Suggested name:** `encodePublishedQueryRequest` (drop `Execute`, `Dashboard`, `Schema` — the function takes a `PublishedQueryRequest` and the input/output are obvious). -- **Rationale:** A function name should fit a short line. 50 characters of qualifiers is a sign that several layers of abstraction are leaking into the identifier. - -### 17. `marshalRequest` vs. `parseResponse` — `src/v1/utils.ts:119,113` -- **Why weird:** Same problem as `dataclassification.md` Findings #17, #18. The asymmetric verb pair (`marshal` vs. `parse`) doesn't say what they do (encode/decode JSON). Both functions are generic — they accept any payload, not specifically requests/responses. The names lie about the constraint. -- **Category:** 1 (vague), 14 (Go-style `marshal`), 17 (asymmetric verb pair). -- **Suggested name:** `encodeJson(data, schema)` + `decodeJson(body, schema)`. -- **Rationale:** Same as in `dataclassification.md`. The generator emits these into every package, so the fix is generator-wide. - -### 18. `executeCall` / `executeHttpCall` — `src/v1/utils.ts:26,65` +### 14. `executeCall` / `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Same as `dataclassification.md` Finding #15. Two `execute*` functions for two layers (retry/rate-limit shell vs. actual HTTP). The name `executeCall` doesn't say what about the call is being executed. - **Category:** 1, 12, 17. - **Suggested name:** `runWithPolicies` (outer) + `sendHttpRequest` (inner). - **Rationale:** Generator-wide pattern, fix once. -### 19. `buildHttpRequest` — `src/v1/utils.ts:96` +### 15. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataclassification.md` Finding #16. "Build" implies builder pattern; this is a 16-line object-literal helper used 4× per client method. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest` or inline. - **Rationale:** Generator-wide. -### 20. `readAll` — `src/v1/utils.ts:40` +### 16. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Same as `dataclassification.md` Finding #20. Generic name for a stream-drain helper. - **Category:** 1, 5. - **Suggested name:** `drainStream`. -### 21. `HttpCallOptions` — `src/v1/utils.ts:15` +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataclassification.md` Finding #21. Type called `Options` but is an internal context bag. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. -### 22. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 18. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** Same as `dataclassification.md` Finding #22. Generic constant name. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -### 23. `Call` type and `call` variable — `src/v1/client.ts:85,117,157` -- **Why weird:** Same as `dataclassification.md` Finding #24. Three-way collision: `Call` type, `call` variable, "the API call" semantics. -- **Category:** 1, 12. -- **Suggested name:** `sendRequest` for the variable. - ## Low severity -### 24. `Client` constructor — `src/v1/client.ts:50-64` +### 19. `Client` constructor — `src/v1/client.ts:50-64` - **Why weird:** The constructor accepts `ClientOptions` but doesn't validate the options beyond `host`. Other fields (`logger`, `credentials`) use `??`-default and never warn about missing values. Naming is fine; behaviour is worth flagging for consistency with other SDK packages. - **Category:** N/A (behavioural). -### 25. `respBody` vs `resp` locals — `src/v1/client.ts:89,94,121,126,161,166` +### 20. `respBody` vs `resp` locals — `src/v1/client.ts:89,94,121,126,161,166` - **Why weird:** Same as `dataclassification.md` Finding #26. Stage names are abbreviated and similar. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. -### 26. `httpReq` local — `src/v1/client.ts:88,120,160` +### 21. `httpReq` local — `src/v1/client.ts:88,120,160` - **Why weird:** Same as `dataclassification.md` Finding #27. Two `req`s in scope: `req: CancelPublishedQueryExecutionRequest` and `httpReq: HttpRequest`. - **Category:** 5, 12. - **Suggested name:** `httpRequest` (no abbreviation). -### 27. `cancelPublishedQueryExecution` method — `src/v1/client.ts:67` +### 22. `cancelPublishedQueryExecution` method — `src/v1/client.ts:67` - **Why weird:** The method is verbose (29 characters) and contains the package name `queryExecution` already. Once `Client` is renamed `QueryExecutionClient`, the package context becomes explicit and the method name should shrink to `cancelPublished` or `cancelPublishedQuery`. The current form reads as `QueryExecutionClient.cancelPublishedQueryExecution(...)` — "queryExecution" twice. - **Category:** 7 (overly verbose), 12 (duplicate concept — `QueryExecution` in both class and method). - **Suggested name:** `cancelPublishedQuery` (or `cancel` if the package is renamed per #1). -### 28. `executePublishedDashboardQuery` method — `src/v1/client.ts:107` -- **Why weird:** Same redundancy as #27 — `executePublishedDashboardQuery` repeats the package's domain. After renaming class to `PublishedDashboardQueryClient`, the method should just be `execute`. +### 23. `executePublishedDashboardQuery` method — `src/v1/client.ts:107` +- **Why weird:** Same redundancy as #22 — `executePublishedDashboardQuery` repeats the package's domain. After renaming class to `PublishedDashboardQueryClient`, the method should just be `execute`. - **Category:** 7 (overly verbose). - **Suggested name:** `execute` (in renamed client) or `executePublishedQuery`. -### 29. `pollPublishedQueryStatus` method — `src/v1/client.ts:139` +### 24. `pollPublishedQueryStatus` method — `src/v1/client.ts:139` - **Why weird:** Inconsistency: `cancelPublishedQueryExecution` uses `QueryExecution` while `pollPublishedQueryStatus` uses `QueryStatus`. So the cancel-side mirrors the *operation* word, the poll-side mirrors the *response* word. The three method names all sound like sibling operations but use three different stems: - `cancelPublishedQueryExecution` - `executePublishedDashboardQuery` @@ -191,25 +162,19 @@ sibling packages `statementexecution` (general SQL Statement Execution API), - **Category:** 17 (inconsistent action-verb stem — three different patterns for three sibling methods). - **Suggested name:** Make the stem identical: `cancelPublishedQuery` / `executePublishedQuery` / `pollPublishedQueryStatus` (or remove the `Status` suffix to match: `pollPublishedQuery`). -### 30. `truncated` field on `SuccessStatus` — `src/v1/model.ts:112` +### 25. `truncated` field on `SuccessStatus` — `src/v1/model.ts:112` - **Why weird:** Field called `truncated`. The JSDoc says "Whether the query result is truncated (either by byte limit or row limit)". The naming is OK in context, but the field stands alone on `SuccessStatus` and tells the user nothing about *what* limit was hit. Compare: `statementexecution` package uses the same name (`truncated`) with the same vagueness — so the inconsistency is cross-package, not local. - **Category:** 1 (vague — truncated by what?), 12 (cross-package duplicate of `statementexecution`'s `truncated`). - **Suggested name:** Document on the type, or split into `truncatedByByteLimit?: boolean` / `truncatedByRowLimit?: boolean`. -### 31. Lowercase `c` in JSDoc comment opening — `src/v1/model.ts:6,42,68` +### 26. Lowercase `c` in JSDoc comment opening — `src/v1/model.ts:6,42,68` - **Why weird:** The JSDoc starts with lowercase: "cancel query request for published Dashboards" (line 6), "Execute query request for published Dashboards" (line 42 — that one starts uppercase, inconsistent), "poll query request..." (line 68). Inconsistent comment style and lowercase sentence openings. Project convention is "Comments should always be proper sentences ending with a period" — these violate it. - **Category:** N/A (style, not naming) — flagged because the prompt requested "EVERY type, field, ... and method"; the JSDoc affects the type's apparent name. - **Suggested name:** N/A (fix prose, not name). -### 32. `$case` discriminator field — `src/v1/model.ts:29-31,91-95` -- **Why weird:** The dollar-sign-prefixed discriminator `$case` is non-standard JS/TS convention. It mimics protobuf-ts and ts-proto outputs. To a TS developer not coming from protobuf, the `$` prefix is jarring (and clashes with `$`-prefixed special properties in many libraries like jQuery). The discriminator should follow standard TS tagged-union convention (`kind`/`type`/`tag`). -- **Category:** 14 (Go/proto-style import — `$case` is a ts-proto convention). -- **Suggested name:** `kind` or `tag`. The standard TS pattern is `{kind: 'success'; success: ...}` (no `$`). -- **Rationale:** Other parts of the SDK may already use `$case` — this is a generator-wide concern. Flagged here for completeness. - ## Observations -### 33. Cross-package vocabulary drift — `statementexecution` / `queryhistory` / `queries` overlap +### 27. Cross-package vocabulary drift — `statementexecution` / `queryhistory` / `queries` overlap - **Description:** Five overlapping concepts span four packages: - **`statementexecution.StatementStatus_State`** = `PENDING | RUNNING | SUCCEEDED | FAILED | CANCELED | CLOSED` (6 states) - **`queryexecution.QueryResponseStatus`** = `success | pending | canceled | closed` (4 arms — no `running` or `failed`) @@ -222,7 +187,7 @@ sibling packages `statementexecution` (general SQL Statement Execution API), - **Category:** 12 (duplicate concepts across packages), 17 (inconsistent vocabulary). - **Recommendation:** Document the relationship in a shared glossary. Long-term, unify the status types or at least the state names. -### 34. Vocabulary collision: `query` vs. `statement` vs. `execution` +### 28. Vocabulary collision: `query` vs. `statement` vs. `execution` - **Description:** The SDK uses three near-synonymous nouns: - **`query`** — appears in `queryexecution`, `queryhistory`, `queries`. Generally means a SQL query (often a saved one). - **`statement`** — appears in `statementexecution` and as `statementId` in `queryexecution`. Means a SQL statement (the SQL Execution API's unit of work). @@ -231,7 +196,7 @@ sibling packages `statementexecution` (general SQL Statement Execution API), - **Category:** 12 (duplicate concepts), 14 (vocabulary inconsistency). - **Recommendation:** Pick a vocabulary and use it consistently. SQL Statement Execution API uses "statement"; published dashboard queries use "query". Document the distinction in the SDK README. -### 35. JSDoc grammar errors / wire-layer leakage +### 29. JSDoc grammar errors / wire-layer leakage - **Description:** Multiple JSDocs reference internal wire terminology not relevant to a TS user: - "rpc calls to sql-exec-api" (lines 10, 73 — internal service name) - "PublishedDatasetDataModel" (line 48 — Java class name) @@ -240,7 +205,7 @@ sibling packages `statementexecution` (general SQL Statement Execution API), - **Category:** N/A (documentation leakage). - **Recommendation:** Generator should strip wire-layer references from public JSDoc. -### 36. Comment style violations +### 30. Comment style violations - **Description:** Per the project rule "Comments should always be proper sentences ending with a period", many JSDocs in this file start lowercase ("cancel query request..."), are sentence fragments ("Example: EC0A..."), or omit terminal periods. Generator-wide. - **Category:** N/A (style). diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index a6b59cac..208e66b2 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -10,8 +10,8 @@ | --- | --- | | High | 8 | | Medium | 19 | -| Low | 16 | -| Observation | 4 | +| Low | 20 | +| Observation | 3 | ## High severity @@ -325,9 +325,6 @@ ### O3. `executeCall` and `executeHttpCall` — overlapping verb pair — `src/v1/utils.ts:26,65` - Two functions, similar names, different purposes. `executeCall` is the public-`CallOptions` adapter; `executeHttpCall` is the wire-level executor. Names don't signal that one wraps the other. Could be `applyCallOptions` + `sendHttpRequest`. Generated-code concern. (See also the `accountaccesscontrol` audit O2.) -### O4. `marshalRequest` exported but unused — `src/v1/utils.ts:119` -- `marshalRequest` is `export`ed but `listQueries` doesn't use it (it marshals inline using `marshalQueryFilterSchema.parse(...)`). Either the helper is dead in this package or the generator emits it preemptively for other shapes. Should be removed if unused. - ## Cross-cutting themes 1. **Proto-style identifiers leak through.** Underscored type names (`ListQueries_Response`, `ExternalQuerySource_JobInfo`), prefix-stuttering enum values (`CHANNEL_NAME_CHANNEL_NAME_PREVIEW`-style usage), and the `UNSPECIFIED` sentinel all read as proto and not TS. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index 94ddc0ba..09014b17 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -13,9 +13,9 @@ The `registeredmodels` package exposes ten UC model-registry operations (`createRegisteredModel`, `deleteRegisteredModel`, `deleteModelVersion`, `deleteRegisteredModelAlias`, `getRegisteredModel`, `getModelVersion`, `getModelVersionByAlias`, `listRegisteredModels`, `listModelVersions`, -`setRegisteredModelAlias`, `updateRegisteredModel`, `updateModelVersion`) -plus two paginated iterators. The model layer is a verbatim 1:1 port of -the Go SDK, and most defects derive from upstream definitions. +`setRegisteredModelAlias`, `updateRegisteredModel`, `updateModelVersion`). +The model layer is a verbatim 1:1 port of the Go SDK, and most defects +derive from upstream definitions. The dominant naming issues are (1) the path-parameter `*Arg` suffix applied to fields that already encode their role through documentation @@ -59,7 +59,7 @@ Both `RegisteredModelInfo`-adjacent payloads use bare `id` for two *different* identifier kinds (the alias and the model version). The reader cannot tell from the call site whether `info.id` is the alias's identifier or the model version's identifier. Prefer `aliasId` and -`modelVersionId` to disambiguate (see also §16.1, §16.2). +`modelVersionId` to disambiguate (see also §14.1, §14.2). #### 1.4 `ModelVersionInfo.version` (model.ts:251), `UpdateModelVersion.version` (model.ts:370) A field on a "model version" type called `version` is doubly redundant @@ -130,21 +130,6 @@ Five distinct identifiers in this single file violate the naming convention. The eslint suppression is acknowledged tech debt; the audit must flag it nonetheless. -#### 4.2 `unmarshalDeleteModelVersion_ResponseSchema` (model.ts:447) -The schema name carries the underscore through, since schemas are named -`unmarshalSchema`. Four additional instances: -`unmarshalDeleteRegisteredModel_ResponseSchema` (line 451), -`unmarshalDeleteRegisteredModelAlias_ResponseSchema` (line 455), -`unmarshalListModelVersions_ResponseSchema` (line 502), and -`unmarshalListRegisteredModels_ResponseSchema` (line 516). - -#### 4.3 Wire-format field names embedded as object keys -Throughout the marshal/unmarshal schemas (model.ts:431-905), the input -side uses `snake_case` keys (`connection_name`, `model_version_dependencies`, -`run_workspace_id`, `next_page_token`, etc.). This is correct — these -are wire-format keys, not TS identifiers, so they are exempt. Documenting -here for completeness. - --- ### 5. Cryptic abbreviations @@ -192,7 +177,7 @@ Two identifier-shaped fields on the same shape; the doc on `id` ("unique identifier of the alias") suggests an internal opaque UUID, while `aliasName` is the human-readable handle the API uses elsewhere. Calling both "identifier" makes intent unclear. Rename `id` to `aliasUuid` or -`aliasId` (see §16.1). +`aliasId` (see §14.1). #### 6.3 `ModelVersionInfo.version` (model.ts:251) The field name suggests a string/identifier ("v2", "v3"), but the type @@ -205,13 +190,7 @@ typical semantic versioning expectations is a real footgun. Rename ### 7. Overly verbose names -#### 7.1 `marshalSetRegisteredModelAliasSchema` (model.ts:789) -Forty-character marshal-schema name. The verbosity flows from the -`SetRegisteredModelAlias` request type name, which itself is fine, but -worth noting that every marshal/unmarshal schema name carries this -verbosity tax. - -#### 7.2 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 504) +#### 7.1 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 504) Method names hover around 30 characters. Java/Go style. In TS prefer `setAlias` / `deleteAlias` on a `RegisteredModelsClient` whose role is already established. The current names imply you could also call @@ -238,11 +217,6 @@ TypeScript does not need the distinction. Compare with the legacy #### 9.1 `ListModelVersions` request, `ListModelVersions_Response.modelVersions` (model.ts:150, 169) The request type is *plural* (`ListModelVersions`), the response collection field is *plural* (`modelVersions`). Internally consistent. -However, the iterator method is `listModelVersionsIter` returning an -`AsyncGenerator` (singular) — the singular/plural -mismatch between the iterator's name (`listModelVersions*`, plural) and -its yield type (`ModelVersionInfo`, singular) is conventional but worth -noting. Same pattern on `listRegisteredModelsIter`. #### 9.2 `ListRegisteredModels` request paginates registered models; field is `registeredModels` (model.ts:212) Same as 9.1; flagged for completeness. @@ -359,12 +333,39 @@ SDK pattern leaking into TS. --- -### 14. Generic field names losing meaning +### 14. Underspecified IDs + +#### 14.1 `RegisteredModelAliasInfo.id` (model.ts:274) +"The unique identifier of the alias". No format constraint, no +mention of whether it is a UUID, a server-generated opaque token, or a +human-friendly slug. Type is `string`. Compare with the well-typed +`metastoreId` (which is also `string` but at least bound to a known +domain). Recommend `aliasId` and adding format hints in the doc. + +#### 14.2 `ModelVersionInfo.id` (model.ts:263) +"The unique identifier of the model version". Same issues as 14.1. +Recommend `modelVersionId`. + +#### 14.3 `RegisteredModelInfo.metastoreId` (model.ts:297) and `ModelVersionInfo.metastoreId` (model.ts:254) +"The unique identifier of the metastore". Acceptable name but worth +flagging that the format (UUID? slug?) is not specified anywhere in +the doc. + +#### 14.4 `ModelVersionInfo.runWorkspaceId` (model.ts:240) +`number` typed. The doc says "ID of the Databricks workspace". Workspace +IDs in Databricks are 64-bit integers — TS `number` is only safe up to +2^53. This is a *type* concern, but the name `runWorkspaceId` does not +flag the underlying integer-width risk; consider `string` per Go's +`json:",string"` tag treatment. + +--- + +### 15. Generic field names losing meaning -#### 14.1 `Dependency.value` (model.ts:91) +#### 15.1 `Dependency.value` (model.ts:91) See §1.1. -#### 14.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 118, 317, 332, 425) +#### 15.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 118, 317, 332, 425) Four of the six dependency wrapper types use a `FullName` suffix on their single string field (`tableFullName`, `functionFullName`, `volumeFullName`, `secretFullName`), while two do not @@ -374,7 +375,7 @@ form of `__connection_name__`"). The naming should be uniform — either add `FullName` to `connectionName` and `credentialName`, or drop the suffix from the other four. -#### 14.3 `CreateRegisteredModel.aliases` (model.ts:48), `UpdateRegisteredModel.aliases` (model.ts:417) +#### 15.3 `CreateRegisteredModel.aliases` (model.ts:48), `UpdateRegisteredModel.aliases` (model.ts:417) A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. Aliases are normally set on already-existing models, not at create time. The field is also marked optional. The name `aliases` is @@ -383,9 +384,9 @@ shape is semantically odd. Flagged for shape, not just naming. --- -### 15. Field contradicting type domain +### 16. Field contradicting type domain -#### 15.1 `CreateRegisteredModel.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId}` (model.ts:37-45) +#### 16.1 `CreateRegisteredModel.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId}` (model.ts:37-45) `CreateRegisteredModel` is a *request* shape, yet it includes six server-populated fields that the client cannot meaningfully set: - `fullName` (computed from `catalogName.schemaName.name`) @@ -402,7 +403,7 @@ set creation timestamps or override the metastore. Same defect on which says "only the name, the owner or the comment of the registered model can be updated". -#### 15.2 `UpdateModelVersion.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:335-385) +#### 16.2 `UpdateModelVersion.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:335-385) `UpdateModelVersion` carries *every* field from `ModelVersionInfo`. The JSDoc says "Currently only the comment of the model version can be updated". The shape is therefore deeply misleading: it presents 17 @@ -410,7 +411,7 @@ optional fields where 16 are silently no-ops on the server. A user setting `updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` will see no effect from `status` but no error either. -#### 15.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:276-281) +#### 16.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:276-281) Three parent-locator fields on an alias type. The alias is already nested inside `RegisteredModelInfo.aliases`, so the parent is known from context. Embedding these makes the alias serialisable in @@ -418,33 +419,6 @@ isolation but pollutes the shape. --- -### 16. Underspecified IDs - -#### 16.1 `RegisteredModelAliasInfo.id` (model.ts:274) -"The unique identifier of the alias". No format constraint, no -mention of whether it is a UUID, a server-generated opaque token, or a -human-friendly slug. Type is `string`. Compare with the well-typed -`metastoreId` (which is also `string` but at least bound to a known -domain). Recommend `aliasId` and adding format hints in the doc. - -#### 16.2 `ModelVersionInfo.id` (model.ts:263) -"The unique identifier of the model version". Same issues as 16.1. -Recommend `modelVersionId`. - -#### 16.3 `RegisteredModelInfo.metastoreId` (model.ts:297) and `ModelVersionInfo.metastoreId` (model.ts:254) -"The unique identifier of the metastore". Acceptable name but worth -flagging that the format (UUID? slug?) is not specified anywhere in -the doc. - -#### 16.4 `ModelVersionInfo.runWorkspaceId` (model.ts:240) -`number` typed. The doc says "ID of the Databricks workspace". Workspace -IDs in Databricks are 64-bit integers — TS `number` is only safe up to -2^53. This is a *type* concern, but the name `runWorkspaceId` does not -flag the underlying integer-width risk; consider `string` per Go's -`json:",string"` tag treatment. - ---- - ### 17. Type-suffix tautology #### 17.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) @@ -453,13 +427,6 @@ See §8.1. The `Info` suffix is tautological because the type already parallel `modelregistry` package which uses bare `RegisteredModel` / `ModelVersion`. -#### 17.2 `*Schema` suffix on every marshal/unmarshal export -`marshalCreateRegisteredModelSchema`, `unmarshalRegisteredModelInfoSchema`, -etc. (35+ exports). The `Schema` suffix is tautological with the -prefix `marshal`/`unmarshal` (these are always schemas). Could be -`marshalCreateRegisteredModel` and `unmarshalRegisteredModelInfo`. Not -a high-impact finding; consistency note. - --- ## Cross-cutting observations @@ -487,7 +454,7 @@ of the package. `CreateRegisteredModel`, `UpdateRegisteredModel`, and especially `UpdateModelVersion` carry the entire response shape on the request side. This is a *type-design* defect surfaced via *naming* (a field called -`createdAt` on a "create" request is meaningless). See §15. +`createdAt` on a "create" request is meaningless). See §16. ### D. Path-parameter fields with `Arg` suffix @@ -509,10 +476,10 @@ or (3) document the convention package-wide. See §5.1. 3. **Disambiguate parallel-package collisions** with `modelregistry` — either re-namespace or rename types. (§11, §B) 4. **Strip server-populated fields** from `CreateRegisteredModel`, - `UpdateRegisteredModel`, `UpdateModelVersion` request shapes. (§15, §C) + `UpdateRegisteredModel`, `UpdateModelVersion` request shapes. (§16, §C) 5. **Unify `versionNum` versus `version`** on a single spelling. (§12.1) -6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§16) +6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§14) 7. **Rename `source`** to `artifactUri` or `sourceUri`. (§1.2) 8. **Drop `MODEL_VERSION_STATUS_` prefix** from `ModelVersionStatus.UNKNOWN`. (§2.1) diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index d348c61d..946afb6a 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -14,7 +14,7 @@ even though the product was rebranded to "Git folders". One resource type (`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, `SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set `provider` values appearing in JSDoc on five fields. -**Total weird names flagged:** 41 +**Total weird names flagged:** 40 --- @@ -28,7 +28,7 @@ even though the product was rebranded to "Git folders". One resource type | 4 | `CreateRepo_Response` (proto-style underscore) | model.ts:29 | interface | High | 4 Underscores in TS identifiers | Proto-message-nested-message-encoded-as-underscore. Carries an inline `// eslint-disable-next-line @typescript-eslint/naming-convention` comment — the generator already knows the name violates the project's own convention. Standard TS idiom would be `CreateRepoResponse` (no underscore), or — since the response is a `RepoInfo` shape — `RepoInfo` directly. | | 5 | `GetRepo_Response` (proto-style underscore) | model.ts:64 | interface | High | 4 Underscores in TS identifiers, 12 Duplicate concepts | Field-for-field identical to `CreateRepo_Response` and `RepoInfo`. Same eslint-disable. | | 6 | `ListRepos_Response` (proto-style underscore) | model.ts:100 | interface | High | 4 Underscores in TS identifiers | Same eslint-disable. The body is `{repos: RepoInfo[], nextPageToken}` — the only `_Response` type with a non-redundant shape. | -| 7 | Five `*_Response` types each carry inline `// eslint-disable-next-line @typescript-eslint/naming-convention` | model.ts:28, 55, 63, 99, 170 | interface set | High | 4 Underscores in TS identifiers | Five disables in one file. Plus another five on the marshal/unmarshal schemas (model.ts:173, 195, 199, 220, 260) — ten total disables. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. | +| 7 | Five `*_Response` types each carry inline `// eslint-disable-next-line @typescript-eslint/naming-convention` | model.ts:28, 55, 63, 99, 170 | interface set | High | 4 Underscores in TS identifiers | Five disables in one file. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. | | 8 | `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 232-250 — sixty lines of duplicated logic). `CreateRepo_Response` and `GetRepo_Response` should be type aliases of `RepoInfo`. | | 9 | `DeleteProject` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProject` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project` name in the entire package — every other operation uses `*Repo`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | | 10 | `Client.deleteProject` (method name on a `repos` client) | client.ts:105 | method | High | 6 Misleading names, 17 Inconsistent action verbs | The client method is `deleteProject` even though the package is `repos`, the URL is `/repos/{id}`, the JSDoc says "Deletes the specified repo", and the four sibling methods are `createRepo`, `getRepo`, `listRepos`, `updateRepo`. Should be `deleteRepo`. Reads as: `client.createRepo(...)`, `client.getRepo(...)`, `client.deleteProject(...)`, `client.updateRepo(...)` — the inconsistency is loud. | @@ -49,24 +49,19 @@ even though the product was rebranded to "Git folders". One resource type | 25 | `repos` field on `ListRepos_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | | 26 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | | 27 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 130, 158, 212, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #9/#10, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | -| 28 | `Client.listReposIter` (iter suffix vs full word) | client.ts:191 | method | Medium | 5 Cryptic abbreviations, 17 Inconsistent action verbs | The `*Iter` suffix is a Go/Rust idiom; TS idiom for async-generator iteration is to either:
- Use `*Stream` / `*All` / `*AsObservable`, or
- Just expose an `[Symbol.asyncIterator]()` method on the result.
The `Iter` abbreviation is also opaque — readers will think "is it `iter` (iterator) or `iter` (iterate)?" Full word `iterate` or `pages`/`stream` would clarify. (Generator-wide pattern; flag once.) | -| 29 | `listReposIter` returns `AsyncGenerator` (per-item) but the underlying call is per-page | client.ts:191 | method | Low | 6 Misleading names | The user sees a single async generator of items but each `for await` of `next` may quietly trigger an HTTP call (every Nth iteration). Memory consumption and latency depend on page size, but the caller has no signal of that. JSDoc is absent. Recommendation: at least document the per-page behavior. (Same finding repeated across iterator audits.) | -| 30 | `unmarshalCreateRepo_ResponseSchema` (and four siblings) | model.ts:174, 196, 200, 221, 261 | const set | High | 4 Underscores in TS identifiers, 14 Go/Java-style names, 20 Type-suffix tautology | Five `unmarshal*_ResponseSchema` consts plus three `unmarshal*Schema` consts (`unmarshalRepoInfoSchema`, `unmarshalSparseCheckoutSchema`) plus the matching marshal-side consts. Each `*_Response*` schema carries `// eslint-disable-next-line @typescript-eslint/naming-convention`. The names pile up three type-suffix words: `CreateRepo_ResponseSchema` is "Repo" + "Response" + "Schema", each implying the others. | -| 31 | `marshal*Schema` / `unmarshal*Schema` const naming | model.ts:174, 196, 200, 221, 232, 252, 261, 264, 278, 286, 294 | const set | Low | 14 Go/Java-style names, 20 Type-suffix tautology | `marshal`/`unmarshal` are Go idioms; `Schema` is tautological with `z.ZodType`. TS-canonical pair is `encode`/`decode`. Generator-wide pattern (also flagged in every prior audit). | -| 32 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | -| 33 | `parseResponse` vs `marshalRequest` (mixed action verbs) | utils.ts:113, 119 | function pair | Low | 17 Inconsistent action verbs | One side says `parse`, the other says `marshal`. Should be either `parse`/`format` or `marshal`/`unmarshal`. | -| 34 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | -| 35 | `PACKAGE_SEGMENT` const | client.ts:44 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. Same flag as every prior audit. | -| 36 | `host` field replacement (`replace(/\/$/, '')`) | client.ts:62 | (logic, not name) | Low | 6 Misleading names | The `host` field actually holds a base URL with trailing slash stripped — not just a host. `baseUrl` would be more honest. (Same misnomer as in the other clients.) | -| 37 | `userAgent` private field | client.ts:56 | field | Low | (none) | Standard, consistent. Listing for completeness. | -| 38 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 134, 216 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | -| 39 | `CreateRepo` (no body wrapper for fields) | model.ts:5 | interface | Medium | 9 Singular/plural mismatches | The endpoint is `POST /api/2.0/repos` (plural collection URL). The request type is `CreateRepo` (singular noun). The response is `CreateRepo_Response`. Singular naming matches Go-SDK convention but reads inconsistently with the wire URL. Compare to the `gitcredentials` audit (H2), which has the opposite problem — there the wire URL is plural and the request type is also plural for a single-resource op. Here the wire URL is plural and the request is singular. Pick one rule. | -| 40 | `RepoInfo` doc says "Git folder (repo) information" | model.ts:110 | doc | Low | 6 Misleading names | The doc consistently uses the form "Git folder (repo)" (e.g., model.ts:30, 32, 42, 44, 46, 59, 65, 81, 89, 101, 110, 112, 114, 124, 126, 128). The type name says only "Repo". Either the doc is overspecified (parenthetical "(repo)" is redundant) or the type name is underspecified. Pick one. | -| 41 | `RepoInfo.path` doc says "Root path" but `CreateRepo.path` and `GetRepo_Response.path` say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo`/`GetRepo_Response`/`CreateRepo_Response` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | -| 42 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types (e.g., `CreateRepo_Response`) consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | -| 43 | `provider` field doc enumerates eight values inline (each ~25 chars) | model.ts:9-13, 37-39, 72-75, 119-121 | doc | Low | 7 Overly verbose | The JSDoc for `provider` on `CreateRepo`, `CreateRepo_Response`, `GetRepo_Response`, and `RepoInfo` enumerates 6-8 values inline. The enumeration is duplicated four times (the generator emits the same text four times in one file). If it were a typed enum (H4), the JSDoc could be on the enum once. | -| 44 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepo`/`UpdateRepo`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | -| 45 | `path` collides with Node.js global `path` module | model.ts:20, 33, 68, 91, 115 | field | Low | 10 Reserved-word collisions | `path` is a common identifier name in TS/Node (`import * as path from 'node:path'`). Local field `path` shadows the import in many codebases. Not a TS reserved word, but a high-shadowing-risk identifier. | +| 28 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | +| 29 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | +| 30 | `PACKAGE_SEGMENT` const | client.ts:44 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. Same flag as every prior audit. | +| 31 | `host` field replacement (`replace(/\/$/, '')`) | client.ts:62 | (logic, not name) | Low | 6 Misleading names | The `host` field actually holds a base URL with trailing slash stripped — not just a host. `baseUrl` would be more honest. (Same misnomer as in the other clients.) | +| 32 | `userAgent` private field | client.ts:56 | field | Low | (none) | Standard, consistent. Listing for completeness. | +| 33 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 134, 216 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 34 | `CreateRepo` (no body wrapper for fields) | model.ts:5 | interface | Medium | 9 Singular/plural mismatches | The endpoint is `POST /api/2.0/repos` (plural collection URL). The request type is `CreateRepo` (singular noun). The response is `CreateRepo_Response`. Singular naming matches Go-SDK convention but reads inconsistently with the wire URL. Compare to the `gitcredentials` audit (H2), which has the opposite problem — there the wire URL is plural and the request type is also plural for a single-resource op. Here the wire URL is plural and the request is singular. Pick one rule. | +| 35 | `RepoInfo` doc says "Git folder (repo) information" | model.ts:110 | doc | Low | 6 Misleading names | The doc consistently uses the form "Git folder (repo)" (e.g., model.ts:30, 32, 42, 44, 46, 59, 65, 81, 89, 101, 110, 112, 114, 124, 126, 128). The type name says only "Repo". Either the doc is overspecified (parenthetical "(repo)" is redundant) or the type name is underspecified. Pick one. | +| 36 | `RepoInfo.path` doc says "Root path" but `CreateRepo.path` and `GetRepo_Response.path` say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo`/`GetRepo_Response`/`CreateRepo_Response` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | +| 37 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types (e.g., `CreateRepo_Response`) consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | +| 38 | `provider` field doc enumerates eight values inline (each ~25 chars) | model.ts:9-13, 37-39, 72-75, 119-121 | doc | Low | 7 Overly verbose | The JSDoc for `provider` on `CreateRepo`, `CreateRepo_Response`, `GetRepo_Response`, and `RepoInfo` enumerates 6-8 values inline. The enumeration is duplicated four times (the generator emits the same text four times in one file). If it were a typed enum (H4), the JSDoc could be on the enum once. | +| 39 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepo`/`UpdateRepo`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | +| 40 | `path` collides with Node.js global `path` module | model.ts:20, 33, 68, 91, 115 | field | Low | 10 Reserved-word collisions | `path` is a common identifier name in TS/Node (`import * as path from 'node:path'`). Local field `path` shadows the import in many codebases. Not a TS reserved word, but a high-shadowing-risk identifier. | --- @@ -217,12 +212,11 @@ The package's `Client` class exposes: client.createRepo(req) // ✓ client.getRepo(req) // ✓ client.listRepos(req) // ✓ -client.listReposIter(req) // ✓ client.deleteProject(req) // 🚨 different noun client.updateRepo(req) // ✓ ``` -Five methods read uniformly; one does not. Renaming `deleteProject` → +Four methods read uniformly; one does not. Renaming `deleteProject` → `deleteRepo` is a one-line fix on the TS side that materially improves readability. See H2 for the full discussion. @@ -316,43 +310,21 @@ repository". Bare `url` is generic. `remoteUrl` (Git terminology) or `gitUrl` would self-document. The JSDoc says "URL of the [linked|remote] Git repository" each time. -### M5. `listReposIter` uses Go-idiom `Iter` suffix - -```ts -async *listReposIter(req: ListRepos, options?: CallOptions): AsyncGenerator -``` - -`Iter` is a Go convention. TS-native options: -- `listAllRepos(req)` returning `AsyncIterable` -- `listRepos(req)` returning the pager that exposes `[Symbol.asyncIterator]` -- `streamRepos(req)` - -Pick a JS convention. - -### M6. `parseResponse` / `marshalRequest` / `executeCall` / `executeHttpCall` (action-verb soup) +### M5. `executeCall` / `executeHttpCall` (overlapping vocabulary) `utils.ts` exposes: -- `parseResponse(body, schema)` -- `marshalRequest(data, schema)` - `executeCall(call, options)` - `executeHttpCall(opts)` - `buildHttpRequest(method, url, headers, signal?, body?)` -Four different action verbs across the file (`parse`, `marshal`, -`execute`, `build`). The `parse`/`marshal` mismatch is the loudest one -(both functions are zod-schema invocations that go in opposite -directions). Either: - -- `marshalRequest` / `unmarshalResponse` (Go idiom, matches - `marshal*Schema`/`unmarshal*Schema`), or -- `encodeRequest` / `decodeResponse` (TS idiom). - The `execute*` pair (`executeCall` wraps the retry/rate-limit executor; `executeHttpCall` is a single HTTP round-trip) has been flagged in every -audit so far. +audit so far. The `*HttpRequest`/`*HttpCall` vocabulary is also mixed — +"Call" and "Request" used interchangeably across `buildHttpRequest` and +`executeHttpCall`. -### M7. `repos` plural field is fine, but inconsistent with the singular-resource convention used everywhere else +### M6. `repos` plural field is fine, but inconsistent with the singular-resource convention used everywhere else The list-response wraps `repos: RepoInfo[]`. That part is fine (`listRepos` → `{repos: [...]}`). But the singular `RepoInfo` and the @@ -360,7 +332,7 @@ plural `repos` co-exist in the same file — and once you rename `RepoInfo` to `Repo` (per M1) or `GitFolder` (per H1), the response field needs to follow (`gitFolders: GitFolder[]`). -### M8. `req.id ?? ''` URL-builder bug-shape +### M7. `req.id ?? ''` URL-builder bug-shape ```ts const url = `${this.host}/api/2.0/repos/${String(req.id ?? '')}`; @@ -382,23 +354,19 @@ The field name `headCommitId` uses the Git term "HEAD". Readers unfamiliar with Git internals will not parse "head commit". The value is a SHA-1 hash. `headSha` or `currentCommitSha` would be more direct. See #19. -### L2. `parseResponse` vs `marshalRequest` action-verb mismatch - -See M6. Lowest priority of the action-verb-soup findings. See #33. - -### L3. `PACKAGE_SEGMENT` could be more specific +### L2. `PACKAGE_SEGMENT` could be more specific "Segment" is vague — it is a user-agent segment, specifically. The constant is used once (in the User-Agent string). `USER_AGENT_PACKAGE_SEGMENT` -would tie it to its only consumer. See #35. +would tie it to its only consumer. See #30. -### L4. `host` field stores a base URL, not a host +### L3. `host` field stores a base URL, not a host `this.host = options.host.replace(/\/$/, '')` — the field is a base URL with trailing slash stripped, not a host (a host has no scheme, no path). -`baseUrl` would be the honest name. See #36. +`baseUrl` would be the honest name. See #31. -### L5. `awsCodeCommit` is documented as deprecated but not tagged +### L4. `awsCodeCommit` is documented as deprecated but not tagged The JSDoc on `provider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on @@ -406,7 +374,7 @@ either the field's documentation or on a typed enum value (which doesn't exist — see H5). Callers cannot programmatically detect deprecated values. See #15. -### L6. `SparseCheckout` doc has a comma splice +### L5. `SparseCheckout` doc has a comma splice ```ts /** Sparse checkout configuration, it contains options like cone patterns. */ @@ -418,26 +386,26 @@ joined by a comma). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." See #22. -### L7. `RepoInfo` doc text inconsistencies +### L6. `RepoInfo` doc text inconsistencies "Git folder" vs "git folder" within `RepoInfo` (model.ts:110, 112, 114, 116, 118, 124, 126, 128). "Workspace" vs "workspace". Generator-introduced -text inconsistency. See #42. +text inconsistency. See #37. -### L8. `RepoInfo.path` doc says "Root path"; the other three `path` docs say "Path" +### L7. `RepoInfo.path` doc says "Root path"; the other three `path` docs say "Path" The `RepoInfo` interface describes `path` as "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` / `GetRepo_Response` / `CreateRepo_Response` says "Path of the Git folder (repo) in the workspace." Different qualifier ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Generator-introduced. See -#41. +#36. -### L9. `path` field name collides with Node.js `path` module +### L8. `path` field name collides with Node.js `path` module `import * as path from 'node:path'` is common; local field also named `path` shadows the import. Not a TS reserved word, but a known footgun. -See #45. +See #40. --- @@ -461,10 +429,9 @@ method name (`deleteProject`) and the *TS-side* request type |---|---| | Total exported interfaces | 10 | | Underscored (proto-style) interfaces | 5 (`CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, `ListRepos_Response`, `UpdateRepo_Response`) | -| Underscored (proto-style) const schemas | 5 (the matching `unmarshal*_ResponseSchema`) | | Identical-shape interface trios | 1 (`RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | | Identical-shape interface pairs | 1 (`SparseCheckout` ≡ `SparseCheckoutUpdate`) | -| Inline ESLint disables required by these names | 10 | +| Inline ESLint disables required by these names | 5 | | Enums | 0 (despite an 8-value closed set on `provider`) | | Legacy-name leaks | 1 (`DeleteProject*` on a "repos" client) | | Rebranding leaks | All identifiers (the resource is now "Git folder" everywhere in JSDoc and product UI, but the type/method names still say "Repo") | @@ -477,13 +444,11 @@ method name (`deleteProject`) and the *TS-side* request type | `_Response` underscore types | Yes (H3) | Yes (H3) | Yes (#18) | | Three identical resource/response shapes | Yes (H4: `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | | `string`-typed enum-domain field (`provider`) | Yes (H5) | Yes (H6 — same field!) | No (uses real enums) | -| `marshal*Schema` / `unmarshal*Schema` consts | Yes (#30, #31) | Yes (#28, #29) | Yes (#53) | -| `executeCall` / `executeHttpCall` vocabulary clash | Yes (M6) | Yes (#31) | Yes (#55) | -| `parseResponse` / `marshalRequest` action mismatch | Yes (M6, L2) | Yes (#32) | Yes (#56) | -| `PACKAGE_SEGMENT` generic const | Yes (L3) | Yes (#35) | Yes (#58) | -| `host` field stores a URL | Yes (L4) | Yes (#36) | Common | +| `executeCall` / `executeHttpCall` vocabulary clash | Yes (M5) | Yes (#31) | Yes (#55) | +| `PACKAGE_SEGMENT` generic const | Yes (L2) | Yes (#35) | Yes (#58) | +| `host` field stores a URL | Yes (L3) | Yes (#36) | Common | | Bare `id` on requests | Yes (H6) | Yes (#24 — but with `credentialId` divergence on responses) | Yes (`nameArg` divergence) | -| Plural/singular mismatch | Mild (#39 — singular request type for plural endpoint) | Severe (H2 — plural request type for singular op) | Mixed | +| Plural/singular mismatch | Mild (#34 — singular request type for plural endpoint) | Severe (H2 — plural request type for singular op) | Mixed | | Legacy-name leak | **Yes (H2 — `DeleteProject*` on a "repos" client)** | No | No | | Product-rebrand leak | **Yes (H1 — TS surface says "Repo", product/doc says "Git folder")** | Partial (Bitbucket Data Center rename, GitLab Self-Managed rename — wire values only) | No | diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 072cc6a1..abf02323 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -14,14 +14,15 @@ Notation: file paths are absolute. Findings reference `file:line`. | ----------- | ----- | | High | 4 | | Medium | 7 | -| Low | 6 | -| Observation | 8 | -| **Total** | **25** | +| Low | 5 | +| Observation | 7 | +| **Total** | **23** | + Headline themes: -1. **Singular/plural mismatch on the `listQuota` method and `ListQuotas` request type.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotas`, `ListQuotas_Response`) are all plural, but the client method is `listQuota` (singular). The companion iterator is `listQuotaIter`, doubling down on the singular. This is the most user-visible naming defect. -2. **Proto-style `Parent_Response` identifiers leaking into the TypeScript public API.** `GetQuota_Response` and `ListQuotas_Response` retain the underscore from Go/proto nesting, and `index.ts` re-exports them verbatim. The `unmarshalGetQuota_ResponseSchema` / `unmarshalListQuotas_ResponseSchema` symbols carry the same underscore into the schema layer. +1. **Singular/plural mismatch on the `listQuota` method and `ListQuotas` request type.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotas`, `ListQuotas_Response`) are all plural, but the client method is `listQuota` (singular). This is the most user-visible naming defect. +2. **Proto-style `Parent_Response` identifiers leaking into the TypeScript public API.** `GetQuota_Response` and `ListQuotas_Response` retain the underscore from Go/proto nesting, and `index.ts` re-exports them verbatim. 3. **Verb-phrase request types collide semantically with client methods.** `interface GetQuota` reads as an action; `client.getQuota(req: GetQuota)` forces readers to mentally distinguish the verb-phrase function from the verb-phrase type. Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix to remove this collision. 4. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuota` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuota`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. 5. **`SecurableType` is duplicated as a `string` on `GetQuota` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H4 below. @@ -32,19 +33,19 @@ Headline themes: ### H1. Method name `listQuota` is singular but returns / paginates a list -- **File / line:** `src/v1/client.ts:98` (`async listQuota(...)`); also `client.ts:131` (`listQuotaIter`). +- **File / line:** `src/v1/client.ts:98` (`async listQuota(...)`). - **Category:** #9 singular/plural mismatch; #15 generic-name losing meaning. - **Current:** `async listQuota(req: ListQuotas, options?): Promise`. -- **Suggestion:** `listQuotas` (and `listQuotasIter`). +- **Suggestion:** `listQuotas`. - **Rationale:** The request type is `ListQuotas` (plural), the response is `ListQuotas_Response` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:92`). Every neighbouring signal is plural except the method name. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact. ### H2. `GetQuota_Response` and `ListQuotas_Response` violate TypeScript identifier convention - **File / line:** `src/v1/model.ts:37` (`GetQuota_Response`), `src/v1/model.ts:50` (`ListQuotas_Response`); also re-exported from `src/v1/index.ts:9, 11`. - **Category:** #4 underscore in TypeScript identifier; #14 Go/Java-style name. -- **Current:** `GetQuota_Response`, `ListQuotas_Response`, `unmarshalGetQuota_ResponseSchema` (`model.ts:76`), `unmarshalListQuotas_ResponseSchema` (`model.ts:85`). -- **Suggestion:** `GetQuotaResponse`, `ListQuotasResponse`, `unmarshalGetQuotaResponseSchema`, `unmarshalListQuotasResponseSchema`. -- **Rationale:** Proto nested-message convention `Parent_Child` is being mechanically transposed into TypeScript. The codebase itself acknowledges the convention is wrong by disabling ESLint at four separate sites (`model.ts:36`, `model.ts:49`, `model.ts:75`, `model.ts:84`) with the comment "Proto-style nested message name." Every disable is a vote against the name. This is the same defect noted in `catalogs.md` §4.6–4.8 and is repo-wide; flagged here at high severity because there are only two model types in this package and *both* are affected. See also Observation O2. +- **Current:** `GetQuota_Response`, `ListQuotas_Response`. +- **Suggestion:** `GetQuotaResponse`, `ListQuotasResponse`. +- **Rationale:** Proto nested-message convention `Parent_Child` is being mechanically transposed into TypeScript. The codebase itself acknowledges the convention is wrong by disabling ESLint at the model sites (`model.ts:36`, `model.ts:49`) with the comment "Proto-style nested message name." Every disable is a vote against the name. This is the same defect noted in `catalogs.md` §4.6–4.8 and is repo-wide; flagged here at high severity because there are only two model types in this package and *both* are affected. See also Observation O2. ### H3. `GetQuota` is a verb-phrase used as a request data type @@ -128,11 +129,11 @@ Headline themes: ### L1. `req` parameter name on every client method -- **File / line:** `src/v1/client.ts:68, 99, 132`. +- **File / line:** `src/v1/client.ts:68, 99`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. - **Current:** `req: GetQuota`, `req: ListQuotas`. - **Suggestion:** `request`. -- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:72, 77, 82, 112, 117, 122, 137` — same shorthand, lower priority. +- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:72, 77, 82, 112, 117, 122` — same shorthand, lower priority. ### L2. `Client` is the bare type name (no `ResourceQuotasClient`) @@ -166,14 +167,6 @@ Headline themes: - **Suggestion:** `packageJson` or `manifest`. - **Rationale:** Minor and internal; the `Json` part is obvious from the import target. Listed because the file is small enough to track every identifier. Repo-wide. -### L6. `data` parameter on `marshalRequest` - -- **File / line:** `src/v1/utils.ts:119`. -- **Category:** #15 generic field name losing meaning. -- **Current:** `function marshalRequest(data: unknown, schema: z.ZodType): string`. -- **Suggestion:** `request` or `payload`. -- **Rationale:** The function is named `marshalRequest` but the parameter is named `data` — the request semantic is lost in the helper. Repo-wide port-style convention (same defect noted in `artifactallowlists.md` §L4). - --- ## Observations (repo-wide conventions, not local defects) @@ -185,7 +178,7 @@ Headline themes: ### O2. Proto-style `Parent_Response` identifiers are repo-wide -`GetQuota_Response` and `ListQuotas_Response` follow the same `Parent_Child` underscore convention as `ConversionInfo_State`, `DatabaseInstance_State`, `EndpointStatus_State`, etc. across the workspace (see `catalogs.md` §4 and `artifactallowlists.md` O2). The four ESLint disable comments in `model.ts` confirm the convention is mechanically applied. Flag for awareness; fix is repo-wide. +`GetQuota_Response` and `ListQuotas_Response` follow the same `Parent_Child` underscore convention as `ConversionInfo_State`, `DatabaseInstance_State`, `EndpointStatus_State`, etc. across the workspace (see `catalogs.md` §4 and `artifactallowlists.md` O2). The ESLint disable comments in `model.ts` confirm the convention is mechanically applied. Flag for awareness; fix is repo-wide. ### O3. Bare `Get*` / `List*` request shapes are a repo-wide pattern @@ -210,11 +203,6 @@ Headline themes: - **File / line:** `src/v1/utils.ts:123`. - **Observation:** Both `getQuota` (`client.ts:71`) and `listQuota` (`client.ts:102-111`) build URLs/query strings inline. The `flattenQueryParams` helper is dead code from the package's standpoint. Same finding as `catalogs.md` cross-cutting §A and `artifactallowlists.md` L5 — repo-wide template artifact. -### O8. Marshal helper `marshalRequest` is exported but unused - -- **File / line:** `src/v1/utils.ts:119`. -- **Observation:** Both methods are `GET` with no body, so `marshalRequest` is never called. Same template-artifact category as O7. Not a local naming defect. - --- ## Domain glossary @@ -236,9 +224,9 @@ Headline themes: | File | Lines | Audited | | -------------- | ----- | ---------------------------------------------------------------------- | -| `src/v1/model.ts` | 113 | 1 enum (17 members), 4 interfaces (12 fields total), 3 schemas. | +| `src/v1/model.ts` | 113 | 1 enum (17 members), 4 interfaces (12 fields total). | | `src/v1/client.ts` | 148 | `Client` class + constructor + 3 methods + all locals + `PACKAGE_SEGMENT`. | -| `src/v1/utils.ts` | 151 | All 7 exported / private functions, the `HttpCallOptions` interface, `readAll`. | +| `src/v1/utils.ts` | 151 | All exported / private functions, the `HttpCallOptions` interface, `readAll`. | | `src/v1/index.ts` | 14 | All 7 re-exports. | Type & symbol checklist: @@ -264,22 +252,12 @@ Type & symbol checklist: - [x] `QuotaInfo.quotaCount` → M2, M5. - [x] `QuotaInfo.quotaLimit` → M2, M5. - [x] `QuotaInfo.lastRefreshedAt` → M6. -- [x] `unmarshalGetQuota_ResponseSchema` → H2. -- [x] `unmarshalListQuotas_ResponseSchema` → H2. -- [x] `unmarshalQuotaInfoSchema` → no defect. - [x] `Client` class → L2. - [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → O6. - [x] `getQuota(req, options)` method → H3, L1. - [x] `listQuota(req, options)` method → H1, L1, L3, L4. -- [x] `listQuotaIter(req, options)` method → H1. - [x] `HttpCallOptions` interface → no defect. -- [x] `executeCall` function → no defect (consistent with sibling packages; same minor concern as `catalogs.md` §6.9 if duplicated naming is considered defect). -- [x] `readAll` private function → no defect. -- [x] `executeHttpCall` function → no defect. -- [x] `buildHttpRequest` function → no defect. -- [x] `parseResponse` function → no defect. -- [x] `marshalRequest` function → L6 (`data` param); O8 (unused). - [x] `flattenQueryParams` function → O7 (unused). - [x] `index.ts` re-exports → no extra defects; mirrors model exports faithfully, but propagates H2 underscore identifiers. @@ -309,19 +287,14 @@ Type & symbol checklist: | `QuotaInfo.quotaCount` | model.ts:68 | M2, M5 | | `QuotaInfo.quotaLimit` | model.ts:70 | M2, M5 | | `QuotaInfo.lastRefreshedAt` | model.ts:72 | M6 | -| `unmarshalGetQuota_ResponseSchema` | model.ts:76 | H2 | -| `unmarshalListQuotas_ResponseSchema` | model.ts:85 | H2 | -| `unmarshalQuotaInfoSchema` | model.ts:96 | — | | `Client` (bare name) | client.ts:37 | L2 | | `PACKAGE_SEGMENT` | client.ts:32 | O6 | | `pkgJson` import alias | client.ts:18 | L5 | | `Client.getQuota` parameter `req` | client.ts:68 | L1 | | `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | -| `Client.listQuotaIter` | client.ts:131 | H1 | | `const call: Call` | client.ts:73, 113 | L3 | | `let resp: …_Response` | client.ts:72, 112 | L4 | | `const respBody` | client.ts:77, 117 | L4 | -| `marshalRequest(data, schema)` | utils.ts:119 | L6, O8 | | `flattenQueryParams` | utils.ts:123 | O7 | | `index.ts` re-exports propagate `_Response` types | index.ts:9, 11 | H2 | @@ -329,7 +302,7 @@ Type & symbol checklist: ## Recommended priority order -1. **Rename `listQuota` → `listQuotas` (and `listQuotaIter` → `listQuotasIter`)** — single-character defect, highest user impact. (H1) +1. **Rename `listQuota` → `listQuotas`** — single-character defect, highest user impact. (H1) 2. **Add `…Request` / `…Response` suffix uniformly and drop the underscore.** (H2, H3) 3. **Reconcile `parentSecurableType` type — make `GetQuota.parentSecurableType: SecurableType`.** (H4) 4. **Drop `quota` prefix on `quotaName` / `quotaCount` / `quotaLimit` inside `QuotaInfo`.** (M2) diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index 138862fc..ddf1b6fb 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -3,14 +3,14 @@ **Path:** `packages/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 46 +**Total weird names flagged:** 41 ## Summary | Severity | Count | | --- | --- | | High | 10 | | Medium | 18 | -| Low | 13 | +| Low | 8 | | Observation | 5 | ## High severity @@ -193,103 +193,73 @@ ## Low severity -### 29. `unmarshalAccessRequestDestinationsSchema` (and 6 other `unmarshal*Schema` / `marshal*Schema`) — `model.ts:189,212,223,236,249,259,271,291,301,315,327,337,349` -- **Why weird:** 12 marshal/unmarshal schemas, all suffixed `Schema`. Names get long (`unmarshalAccessRequestDestinationsSchema` = 38 chars). The suffix repeats info already captured by the `z.ZodType<...>` typing. -- **Category:** 8 (redundant suffix `Schema`). -- **Suggested name:** Drop `Schema` (`unmarshalAccessRequestDestinations`, `marshalCreateAccessRequest`), or shorten to `decode*`/`encode*` verbs. -- **Rationale:** Internal/generator style; same finding as `connections#33`, recurs across the SDK. - -### 30. `marshalRequest` / `parseResponse` verb asymmetry — `utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations within the same file. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. -- **Rationale:** Cross-package: same finding as `connections#39`. - -### 31. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +### 29. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17. - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Same as `connections#40`. -### 32. `HttpCallOptions` — `utils.ts:15` +### 30. `HttpCallOptions` — `utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file imports `Options` from `@databricks/sdk-core/api` and `CallOptions` from `@databricks/sdk-options/call`. Three `Options` types in scope. `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Same as `connections#41`. -### 33. `readAll` — `utils.ts:40` +### 31. `readAll` — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `connections#38`. -### 34. `flattenQueryParams` — `utils.ts:123` +### 32. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default. - **Rationale:** Generator emits the same helper into every package even when unused. Same as `connections#37`. -### 35. `PACKAGE_SEGMENT` constant — `client.ts:35` +### 33. `PACKAGE_SEGMENT` constant — `client.ts:35` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `connections#36`. -### 36. `Client` class — `client.ts:40` +### 34. `Client` class — `client.ts:40` - **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). - **Category:** 1 (vague). - **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). - **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. -### 37. `buildHttpRequest` parameter list — `utils.ts:96-102` +### 35. `buildHttpRequest` parameter list — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. The function name `buildHttpRequest` doesn't communicate the parameter order; callers in `client.ts:87,122,166` pass them positionally. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Five-positional builders without object syntax are an anti-pattern in modern TS. -### 38. `marshalRequest(data: unknown, schema: z.ZodType): string` — `utils.ts:119` -- **Why weird:** The function parses `data` against `schema` and returns a JSON string. The name says "marshal request", but it's used for *any* outbound body, including update bodies that aren't strictly "requests" in the sense of "user-facing request DTO" (e.g. line 158 marshals `accessRequestDestinations` which is the payload of an update, not the wrapping `UpdateAccessRequestDestinationsRequest`). -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `marshalJson` or `serializeBody`. -- **Rationale:** Mechanical; not blocking. - -### 39. `parseResponse` typed return — `utils.ts:113` -- **Why weird:** Returns `T` where `T` is the schema's inferred type. The name "parse" overloads with `JSON.parse` (called inside) and with `schema.parse` (also called inside). Three layers of "parse" in nine lines. -- **Category:** 1 (vague). -- **Suggested name:** `decodeResponse` or `unmarshalJson`. -- **Rationale:** Mechanical. - -### 40. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` +### 36. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` - **Why weird:** The `Options` shape is built with a series of `...(options?.foo !== undefined && {foo: options.foo})` spreads. The pattern is a TS-idiom for conditional spread of optional fields. Naming-wise: the local `opts` variable is intentionally one letter shorter than `options` to disambiguate — but the shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions` (or the outer parameter to `callOptions`). - **Rationale:** Mechanical. -### 41. `accessRequestDestinationsFieldMaskSchema` and `securableFieldMaskSchema` — `model.ts:359,380` -- **Why weird:** Internal `*FieldMaskSchema` constants (not exported). Names are 41 / 26 chars. Inconsistent capitalization with other helpers (`unmarshal*Schema` is exported, `*FieldMaskSchema` is not — yet both end with `Schema`). -- **Category:** 8 (redundant suffix `Schema`). -- **Suggested name:** `accessRequestDestinationsFieldMask` (drop trailing `Schema`). -- **Rationale:** Generator-emitted; cross-package consistency issue. - ## Observations -### 42. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` +### 37. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` The index file exports the `Client`, all four enums, and all nine model interfaces (`AccessRequestDestinations`, `BatchCreateAccessRequestsRequest`, `BatchCreateAccessRequestsResponse`, `CreateAccessRequest`, `CreateAccessRequestResponse`, `GetAccessRequestDestinationsRequest`, `NotificationDestination`, `Principal`, `Securable`, `SecurablePermissions`, `UpdateAccessRequestDestinationsRequest`). It does *not* export the `marshal*`/`unmarshal*` schemas or the `accessRequestDestinationsFieldMask` helper. Consistent with the other packages but means the field-mask helper isn't available to consumers. - **Category:** Observation. -### 43. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +### 38. Comment-tag inconsistency — `client.ts:78,117,151` vs URL The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. - **Category:** Observation. -### 44. No tests in the package +### 39. No tests in the package `package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. The package ships untested. Not a naming issue, but cross-package noise — same as several other newly generated packages. - **Category:** Observation. -### 45. Action-verb conventions on `Client` +### 40. Action-verb conventions on `Client` `batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #28). - **Category:** Observation. -### 46. `package.json` description is empty string — `package.json:4` +### 41. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the cryptic `rfa` name (see #1), this leaves users with no metadata to identify the package's purpose when browsing npm. - **Category:** Observation. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index 1b2e7ae3..ca16e695 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -10,7 +10,7 @@ The `schemas` package exposes the standard five UC schema operations (`createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, -`updateSchema`) plus a paginated iterator. The package is small (one +`updateSchema`). The package is small (one enum, one nested-flag type, the schema info type, five request types, two response types, six map-entry wrapper types). Because it is a 1:1 port of the Go SDK, most issues are inherited from upstream proto @@ -40,8 +40,7 @@ this object and objects under it". The name conveys nothing about *what kind of value*; the type is `string` but the semantic is a tri-state (enable / disable / inherit). A reader has to read the doc to discover what is in it. Better: `enabled`, `setting`, or -`predictiveOptimization`. Same name appears in marshal/unmarshal -transforms (lines 243, 248, 361, 366). +`predictiveOptimization`. #### 1.2 `*_OptionsEntry.value` / `*_PropertiesEntry.value` (model.ts:59-66, 167-175, 225-232) Six proto-generated map-entry wrappers exporting `{ key?: string; @@ -106,8 +105,8 @@ review. ### 4. Underscores in TypeScript identifiers -The package's most widespread cosmetic issue. Six exported types and -several schema exports use proto-style `Parent_Child` names with +The package's most widespread cosmetic issue. Six exported types use +proto-style `Parent_Child` names with `@typescript-eslint/naming-convention` suppression comments — i.e. the lint rule already disagrees with these names. @@ -137,13 +136,6 @@ Same as 4.1. #### 4.8 `UpdateSchema_PropertiesEntry` (model.ts:231) Same as 4.1. -#### 4.9 `unmarshalDeleteSchema_ResponseSchema` (model.ts:237) -The underscore propagates into the schema export name. Should be -`unmarshalDeleteSchemaResponseSchema`. - -#### 4.10 `unmarshalListSchemas_ResponseSchema` (model.ts:254) -Same as 4.9. Should be `unmarshalListSchemasResponseSchema`. - --- ### 5. Cryptic abbreviations @@ -189,16 +181,6 @@ verbatim in `CreateSchema` (model.ts:51-54) and `UpdateSchema` (model.ts:218-221). Either is underspecified or one of them is misnamed. See §12.1. -#### 6.4 `marshalRequest` parses the input before marshalling (utils.ts:119) -The function is named `marshalRequest` but its body is -`JSON.stringify(schema.parse(data))` — the schema's `.parse` step is -*validation*, not parsing. Not a schemas-specific issue, but the name -hides validation behaviour. (Inherited from sibling packages.) - -#### 6.5 `parseResponse` does parsing + validation (utils.ts:113) -Similar to 6.4: the name `parseResponse` understates that it also -validates with `schema.parse`. Defensible. - --- ### 7. Overly verbose @@ -214,11 +196,7 @@ a field name on three different request/response shapes (model.ts:44, Long field name for what is effectively a flag value. Acceptable, but pairs with §7.1 to make every schema shape verbose. -#### 7.3 `unmarshalEffectivePredictiveOptimizationFlagSchema` / -`marshalEffectivePredictiveOptimizationFlagSchema` (model.ts:240, 359) -Schema exports of ~50 characters. Hard to read. - -#### 7.4 `MANAGED_ONLINE_CATALOG` enum value (model.ts:12) — 22 characters; redundant `_CATALOG` per §2.1. +#### 7.3 `MANAGED_ONLINE_CATALOG` enum value (model.ts:12) — 22 characters; redundant `_CATALOG` per §2.1. --- @@ -235,31 +213,11 @@ The whole type *is* the flag; the suffix is redundant. See §7.1. #### 8.3 `Arg` suffix on `fullNameArg` — see §5.1 and §16.1. -#### 8.4 `…Schema` suffix on every zod schema export (`unmarshalSchemaInfoSchema`, `marshalCreateSchemaSchema`, etc.) -Defensible (signals it's a zod schema), but the schema-ness is already -conveyed by the `marshal…`/`unmarshal…` prefix. Note the unfortunate -double-`Schema` in `unmarshalSchemaInfoSchema` and -`marshalCreateSchemaSchema` — once for "Schema" (the resource) and once -for "Schema" (the zod artefact). See also §20.4. - -#### 8.5 `unmarshal…Schema` / `marshal…Schema` double-`Schema` collision -The single most jarring identifier in the package is -`marshalCreateSchemaSchema` (model.ts:312) — both halves of the -compound carry the word "Schema". Unique to this package because the -domain entity is itself called "schema". - --- ### 9. Singular / plural mismatches -#### 9.1 `Client.listSchemasIter` returns `AsyncGenerator` (client.ts:213) -Method name `listSchemasIter` implies "list of schemas iterator"; the -generator actually yields single `SchemaInfo` items one at a time. -Consistent with neighbouring packages. Worth a sanity check — -`iterSchemas` (verb-first) reads more naturally for an iterator and -avoids the singular/plural conflict. - -#### 9.2 No other plural mismatches noticed. +_None._ --- @@ -353,9 +311,7 @@ will be surprised to find that system schemas live elsewhere. #### 13.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. -#### 13.2 `unmarshal…` / `marshal…` schema-export prefixes are consistent. No issues. - -#### 13.3 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. +#### 13.2 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. No verb-tense inconsistencies found across the package. @@ -381,12 +337,7 @@ Package-wide convention; flagged for the broader review. #### 14.5 `fullNameArg` — Go-generator naming. See §5.1. -#### 14.6 `unmarshal…` / `marshal…` (Go's `encoding/json` verbs) -Direct Go ports. TS ecosystem typically uses `parse` / `serialize` or -`decode` / `encode`. Defensible because they're internal to the -generated layer. - -#### 14.7 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) +#### 14.6 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) Constant naming is fine; flagged for completeness. --- @@ -442,9 +393,8 @@ Same as 16.3. ### 17. Inconsistent action verbs Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, -`listSchemas`, `updateSchema`, `listSchemasIter`. Verbs are consistent -— standard CRUD plus a `…Iter` paginator. No `fetch…` / `retrieve…` / -`read…` outliers. No issues found. +`listSchemas`, `updateSchema`. Verbs are consistent — standard CRUD. +No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- @@ -508,14 +458,6 @@ is the only instance of that type in each parent. Could be shortened to `predictiveOptimization: EffectivePredictiveOptimization` (drop "Flag" per §8.3 and "effective" per §7.1). -#### 20.4 Schema-export tautology -`unmarshalSchemaInfoSchema: z.ZodType` (model.ts:265), -`marshalCreateSchemaSchema` (model.ts:312) — the `Schema` suffix -duplicates `z.ZodType<…>`. Worse, the *resource* is also called -"Schema", so identifiers like `marshalCreateSchemaSchema` mean -"marshal-schema for the CreateSchema schema". Maximal `Schema`-pile-up -in the SDK. See also §8.5, §8.6. - --- ## Additional / cross-cutting observations @@ -536,23 +478,11 @@ substitution behaviour together hide what should be a required parameter. The type marks it `string | undefined` even though it is operationally required. -### C. `marshalUpdateSchemaSchema` serialises `fullNameArg`/`newName` into the body (model.ts:398-399) -`fullNameArg` is a path parameter, but the marshal transform produces -JSON fields `full_name_arg` and `new_name` in the body. Either the -server tolerates extra fields or this is a bug. The naming choice -(`Arg`) lets the bug hide. - -### D. Marshal/unmarshal exports lack consistent generic types (model.ts) -`marshalCreateSchemaSchema: z.ZodType` (no generic) versus -`unmarshalSchemaInfoSchema: z.ZodType` (with generic). The -marshal side is implicitly untyped. Not a naming issue per se, but -worth surfacing. - -### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +### C. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### F. `index.ts` re-exports proto-style names verbatim (lines 9, 10, 11, 12, 14, 15, 16, 19, 20, 21) +### D. `index.ts` re-exports proto-style names verbatim (lines 9, 10, 11, 12, 14, 15, 16, 19, 20, 21) Every underscore-bearing identifier surfaces in the package's public API. A consumer of `@databricks/sdk-schemas/v1` sees `CreateSchema_OptionsEntry`, `CreateSchema_PropertiesEntry`, @@ -562,29 +492,29 @@ API. A consumer of `@databricks/sdk-schemas/v1` sees first-class exports. This is the highest-leverage place to clean naming. -### G. The package name is plural; the entity types are singular +### E. The package name is plural; the entity types are singular The package is `schemas` (plural); the model types are `Schema` (well, `SchemaInfo` — singular). The five client methods mix: `createSchema`/`deleteSchema`/`getSchema`/`updateSchema` (singular — -they act on one) and `listSchemas`/`listSchemasIter` (plural — they -return many). This is the same pattern as `catalogs`, `tables`, etc. -— consistent across the SDK. +they act on one) and `listSchemas` (plural — returns many). This is +the same pattern as `catalogs`, `tables`, etc. — consistent across +the SDK. -### H. `SchemaInfo`'s "Next ID: 45" comment (model.ts:123) +### F. `SchemaInfo`'s "Next ID: 45" comment (model.ts:123) The doc comment is a leftover proto field-number management note. It has no consumer-facing meaning. Should be stripped on the way to TS. -### I. Doc comment for `effectivePredictiveOptimizationFlag` is missing (model.ts:44-46, 153-155, 211-213) +### G. Doc comment for `effectivePredictiveOptimizationFlag` is missing (model.ts:44-46, 153-155, 211-213) The field has no JSDoc, even though the type has a doc. Three occurrences. Consistency: every other field has a doc comment. -### J. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) +### H. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) The field name says "enable" — suggesting boolean — but the type is `string`. The actual value is presumably `'ENABLE' | 'DISABLE' | 'INHERIT'` or similar. The name lies about the type. See also §6.1 for the related `EffectivePredictiveOptimizationFlag.value`. -### K. Overlap with `systemschemas` package — see §12.7 +### I. Overlap with `systemschemas` package — see §12.7 A consumer reading "schemas" reasonably expects to find all schema operations here. They will not find `disableSystemSchema`, `enableSystemSchema`, or `listSystemSchemas` — those live in @@ -607,14 +537,14 @@ upstream API surface, but the seam is non-obvious to discover. | `CreateSchema` | model.ts:15 | 12.6, 16.2 | | `CreateSchema.name` | model.ts:17 | 1.4, 10.2 | | `CreateSchema.catalogType` | model.ts:41 | 20.1 | -| `CreateSchema.effectivePredictiveOptimizationFlag` | model.ts:44 | 7.1, 7.3, 20.3, I | +| `CreateSchema.effectivePredictiveOptimizationFlag` | model.ts:44 | 7.1, 20.3, G | | `CreateSchema.properties` / `.options` | model.ts:52, 54 | 6.3, 10.1, 12.1, 15.4| | `CreateSchema_OptionsEntry` | model.ts:58 | 1.2, 4.1, 14.2 | | `CreateSchema_PropertiesEntry` | model.ts:64 | 1.2, 4.2, 14.2 | | `DeleteSchema` | model.ts:69 | 16.3 | | `DeleteSchema.fullNameArg` | model.ts:71 | 5.1, 14.5, 16.3, B | | `DeleteSchema_Response` | model.ts:77 | 4.3, 14.1 | -| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 7.1, 7.3, 8.2, 14.3, 20.3 | +| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 7.1, 8.2, 14.3, 20.3 | | `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 6.1, 10.3, 15.1 | | `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.3, 19.5 | | `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.3, 19.5 | @@ -624,13 +554,13 @@ upstream API surface, but the seam is non-obvious to discover. | `ListSchemas.pageToken` | model.ts:107 | — | | `ListSchemas.includeBrowse` | model.ts:109 | — | | `ListSchemas_Response` | model.ts:113 | 4.4, 14.1 | -| `SchemaInfo` | model.ts:124 | 8.1, 12.6, 14.3, H | +| `SchemaInfo` | model.ts:124 | 8.1, 12.6, 14.3, F | | `SchemaInfo.name` | model.ts:126 | 1.4, 10.2 | | `SchemaInfo.fullName` | model.ts:139 | 6.2, 12.2 | | `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 19.3 | | `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 19.4 | | `SchemaInfo.catalogType` | model.ts:150 | 20.1 | -| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 7.1, 20.3, I | +| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 7.1, 20.3, G | | `SchemaInfo.schemaId` | model.ts:157 | 19.2 | | `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 6.3, 10.1, 12.1, 15.4| | `SchemaInfo_OptionsEntry` | model.ts:167 | 1.2, 4.5, 14.2 | @@ -640,26 +570,16 @@ upstream API surface, but the seam is non-obvious to discover. | `UpdateSchema.newName` | model.ts:182 | 16.1 | | `UpdateSchema.name` | model.ts:184 | 1.4, 10.2, 16.1 | | `UpdateSchema.fullName` | model.ts:197 | 12.2, 12.3, 16.1 | -| `UpdateSchema.effectivePredictiveOptimizationFlag` | model.ts:211 | 7.1, 20.3, I | +| `UpdateSchema.effectivePredictiveOptimizationFlag` | model.ts:211 | 7.1, 20.3, G | | `UpdateSchema_OptionsEntry` | model.ts:225 | 1.2, 4.7, 14.2 | | `UpdateSchema_PropertiesEntry` | model.ts:231 | 1.2, 4.8, 14.2 | -| `unmarshalDeleteSchema_ResponseSchema` | model.ts:237 | 4.9 | -| `unmarshalEffectivePredictiveOptimizationFlagSchema` | model.ts:240 | 7.3, 8.4 | -| `unmarshalListSchemas_ResponseSchema` | model.ts:254 | 4.10 | -| `unmarshalSchemaInfoSchema` | model.ts:265 | 8.4, 8.5, 20.4 | -| `marshalCreateSchemaSchema` | model.ts:312 | 8.4, 8.5, 20.4 | -| `marshalEffectivePredictiveOptimizationFlagSchema` | model.ts:359 | 7.3, 8.4 | -| `marshalUpdateSchemaSchema` | model.ts:371 | 8.4, 8.5, 20.4, C | -| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | J | +| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | H | | `comment` field | model.ts:23, 132, 190 | 15.5 | | `Client` (bare name) | client.ts:44 | 14.4 | -| `Client.listSchemasIter` | client.ts:213 | 9.1 | | `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 137, 239 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `marshal…` / `unmarshal…` verbs | model.ts (many) | 14.6 | -| `…Schema` suffix on schema exports | model.ts (many) | 8.4, 8.5, 20.4 | -| `index.ts` re-exports | index.ts:7-23 | F | -| Cross-package overlap with `systemschemas` | (package boundary) | 12.7, K | +| `index.ts` re-exports | index.ts:7-23 | D | +| Cross-package overlap with `systemschemas` | (package boundary) | 12.7, I | --- @@ -669,10 +589,10 @@ upstream API surface, but the seam is non-obvious to discover. 2. **Strip the redundant `_CATALOG` suffix from every `CatalogType` variant.** (§2.1, §18.x) 3. **Drop proto-style `Parent_Child` identifiers** (`DeleteSchema_Response`, `ListSchemas_Response`, six `*_OptionsEntry`/`*_PropertiesEntry`). (§4) 4. **Distinguish or merge `options` and `properties`.** (§12.1, §6.3) -5. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§6.1, J) +5. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§6.1, H) 6. **Strip read-only fields from `CreateSchema`/`UpdateSchema`.** (§16.2) 7. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) 8. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§19.3) 9. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§19.2, §12.2) -10. **Drop the `Next ID: 45` proto leftover from `SchemaInfo` JSDoc.** (H) -11. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§12.7, K) +10. **Drop the `Next ID: 45` proto leftover from `SchemaInfo` JSDoc.** (F) +11. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§12.7, I) diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index fa42c7c4..f6c2b5d7 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -20,10 +20,10 @@ Notation: file paths are relative to the package root. Findings reference | Severity | Count | | ----------- | ----- | | High | 8 | -| Medium | 15 | -| Low | 11 | +| Medium | 14 | +| Low | 9 | | Observation | 5 | -| **Total** | **39** | +| **Total** | **36** | Headline themes: @@ -441,19 +441,6 @@ Headline themes: plural. `items` is the odd-one-out; the field name should match the pattern. -### M15. `marshalXxxSchema` / `unmarshalXxxSchema` const naming is Go-style - -- **File / line:** `src/v1/model.ts:205, 215, 227, 231, 235, 239, 243, - 258, 267, 277, 287, 291, 294, 304, 318, 328, 344, 354, 362, 372, 384`. -- **Category:** #14 Go/Java-style names, #20 type-suffix tautology. -- **Current:** `marshalCreateScopeSchema: z.ZodType`, - `unmarshalAclItemSchema: z.ZodType`, etc. -- **Suggestion:** TS idiom is `encode`/`decode` or `serialize`/`deserialize`. - `Schema` is also tautological since the value is a `z.ZodType` — - `aclItemDecoder`, `createScopeEncoder` would be type-self-describing. -- **Rationale:** Generator-wide convention (same defect cited in many - audits, e.g. `credentials.md` #53). Cannot be fixed in isolation. - --- ## Low Severity @@ -527,18 +514,7 @@ Headline themes: later release." The release shipped; the doc string is stale. Not a naming issue but indicates the file is not maintained tightly. -### L7. `marshal*Schema` types use bare `z.ZodType` (no type argument) - -- **Files / lines:** `model.ts:318, 328, 344, 354, 362, 372, 384`. -- **Category:** asymmetry; #20 type-suffix tautology. -- **Current:** `marshalCreateScopeSchema: z.ZodType = ...` — no type - parameter. Compare with `unmarshalAclItemSchema: z.ZodType`. -- **Suggestion:** mirror the input shape on the marshal side - (`marshalCreateScopeSchema: z.ZodType`). As-is, the - marshal path has no type guarantee — `marshalCreateScopeSchema.parse({ - scope: 123 })` would not type-check the input. - -### L8. `flattenQueryParams` is dead code in this package +### L7. `flattenQueryParams` is dead code in this package - **File / line:** `src/v1/utils.ts:123`. - **Category:** #21 dead code. @@ -548,7 +524,7 @@ Headline themes: generator-wide. - **Suggestion:** drop dead code, or move it to a shared utils package. -### L9. `executeCall` vs `executeHttpCall` name collision +### L8. `executeCall` vs `executeHttpCall` name collision - **Files / lines:** `src/v1/utils.ts:26, 65`. - **Category:** #17 inconsistent action verbs. @@ -556,15 +532,7 @@ Headline themes: `executeCall` (sets options + dispatches retries) and `executeHttpCall` (one HTTP roundtrip). Same defect cataloged in other audits. -### L10. `parseResponse` vs `marshalRequest` mix verbs - -- **Files / lines:** `src/v1/utils.ts:113, 119`. -- **Category:** #17 inconsistent action verbs. -- **Current:** mixing `parse`/`marshal` for symmetric encode/decode - responsibilities. Should be `parseResponse` + `formatRequest`, or - `unmarshalResponse` + `marshalRequest`. - -### L11. `PACKAGE_SEGMENT` constant is vague +### L9. `PACKAGE_SEGMENT` constant is vague - **File / line:** `src/v1/client.ts:65`. - **Category:** #1 vague/generic. @@ -653,5 +621,3 @@ Headline themes: (`backendType`) (M10). 13. `CreateScope.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` → pick one (`keyVaultBackend`) (M11). -14. `marshalXxxSchema` / `unmarshalXxxSchema` → `encodeXxx` / `decodeXxx` - (M15, repo-wide; not isolated to this package). diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index 38ab8289..91a6a9a3 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -3,15 +3,15 @@ **Path:** `packages/secretsuc/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. -**Total weird names flagged:** 32 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 10 | -| Low | 9 | -| Observation | 5 | +| Medium | 8 | +| Low | 4 | +| Observation | 4 | ## High severity @@ -34,7 +34,7 @@ - **Rationale:** Even if the package rename happens, the type name `Secret` carries no UC-specific signal. Users wiring up both APIs will collide. The Go SDK has the same problem but disambiguates via Go's package-qualified types (`secretsuc.Secret` vs `secrets.SecretMetadata`); TS imports are commonly unqualified at the call site, so the type itself needs to carry the disambiguator. ### 4. `externalSecretId` — `src/v1/model.ts:143` -- **Why weird:** Completely undocumented field (no JSDoc comment, unlike every other field on `Secret`). The wire field exists in marshal/unmarshal (`model.ts:203,222,252,271`) and in the field-mask schema (`model.ts:283`) but is not in the field-mask's documented "Supported fields" list (`value, comment, owner, expire_time` — `client.ts:238`). The field's existence and semantics are entirely opaque to a reader of the model file. +- **Why weird:** Completely undocumented field (no JSDoc comment, unlike every other field on `Secret`). The wire field exists in the field-mask but is not in the field-mask's documented "Supported fields" list (`value, comment, owner, expire_time` — `client.ts:238`). The field's existence and semantics are entirely opaque to a reader of the model file. - **Category:** 1 (vague — what is "external"?), 6 (misleading — undocumented field that is presumably real), 19 (underspecified id — alongside `metastoreId` and `fullName`). - **Suggested name:** Keep the name but ship JSDoc; or `externalSecretReference` / `externalProviderSecretId` if the field points at an external secret manager (AWS Secrets Manager, etc.). - **Rationale:** A bare `externalSecretId` next to `metastoreId` and `fullName` invites the reader to guess. JSDoc is the cheapest fix; renaming to disclose the "external store" intent is the better one. This may be a generator gap (missing API description), worth flagging upstream so the description is included. @@ -43,7 +43,7 @@ - **Why weird:** Doc says "This field is input-only and is not returned in responses". Same struct has `effectiveValue` (`model.ts:131`) for the output. Two near-identical fields, one input-only, one output-only, both meaning "the secret value". Generic name `value` is also category-1 vague — without the doc, "value" could mean any value in any struct. - **Category:** 1 (vague), 6 (misleading — same name covers both write-only-input and a sibling read-only-output), 11 (input-only field on a shared input/output type forces the reader to know the direction). - **Suggested name:** `secretValue` (for symmetry with `effectiveValue`), or split into `CreateSecretInput.value` / `Secret.effectiveValue` so the asymmetry surfaces in the type system. Alternatively rename `effectiveValue` -> `value` and have a separate write-only `newValue` on update. -- **Rationale:** The current shape relies entirely on the JSDoc to inform the reader which field to set on input and which to read on output. The Zod marshal schema happily round-trips both fields (`model.ts:246,268`), so a buggy caller can set `effectiveValue` on a create call and the SDK will serialise it to the wire (where the server presumably ignores it). The TS type system should keep the asymmetry visible. +- **Rationale:** The current shape relies entirely on the JSDoc to inform the reader which field to set on input and which to read on output. A buggy caller can set `effectiveValue` on a create call and the SDK will serialise it to the wire (where the server presumably ignores it). The TS type system should keep the asymmetry visible. ### 6. `effectiveValue` / `effectiveOwner` "effective" prefix — `src/v1/model.ts:101,131` - **Why weird:** Two unrelated `effective*` fields used with two different meanings. `effectiveOwner` is documented as "the effective owner of the secret, which may differ from the directly-set **owner** due to inheritance" — so "effective" = "after inheritance resolution". `effectiveValue` is documented as "the secret value. Only populated in responses when you have the **READ_SECRET** privilege" — so "effective" = "the actual readable value, not what was sent in". Two distinct semantics under one prefix. @@ -65,14 +65,14 @@ ## Medium severity -### 9. `Secret` mixes input-only and output-only fields — `src/v1/model.ts:126,225-272` -- **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. `marshalSecretSchema` (`model.ts:225`) round-trips every field, so it is shared between create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output. +### 9. `Secret` mixes input-only and output-only fields — `src/v1/model.ts:126` +- **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. The shared type is used on both create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output. - **Category:** 11 (single type wearing two hats), 6 (misleading). - **Suggested name:** Split into `WritableSecret` / `Secret`, or `SecretCreateInput` / `SecretUpdateInput` / `Secret`. - **Rationale:** The single-type approach is a generator artefact (Go SDK uses one struct with pointer fields to elide zeros); TS lacks that ergonomic and forces every consumer to know which fields are write-permitted. The field-mask on update (`updateMask` — `model.ts:162`) partially mitigates but doesn't substitute for type-level intent. ### 10. `UpdateSecretRequest.secret` is the *update payload* with `fullName` as routing key — `src/v1/model.ts:147-163` -- **Why weird:** `UpdateSecretRequest` has both `fullName` (routing) and `secret` (payload). The nested `secret.fullName` is meaningless — what if it differs from the outer `fullName`? The Zod marshalRequest serialises the whole `secret`, including its own optional `fullName`, into the PATCH body even though the path is keyed by the outer `req.fullName`. +- **Why weird:** `UpdateSecretRequest` has both `fullName` (routing) and `secret` (payload). The nested `secret.fullName` is meaningless — what if it differs from the outer `fullName`? The whole `secret`, including its own optional `fullName`, is serialised into the PATCH body even though the path is keyed by the outer `req.fullName`. - **Category:** 6 (misleading — two `fullName`s can disagree), 17 (inconsistency — same field appearing twice in one logical operation). - **Suggested name:** Either define `SecretUpdate` (omits `fullName`, `createTime`, etc.) or rely on the field-mask to ignore non-listed fields. Naming-wise: rename the outer to `name`/`secretFullName` to emphasise it's the routing key, not part of the payload. - **Rationale:** This is a real bug surface: callers will write `{fullName: 'a.b.c', secret: {fullName: 'x.y.z', ...}}` and wonder why renames don't work. @@ -113,6 +113,8 @@ - **Suggested name:** `relativeName` for `name`, or `schemaRelativeName`. Wire stays `name`. - **Rationale:** When `fullName` is the routing key, `name` should disclose that it's the inferior, scope-relative one. Failing that, JSDoc must always be read. +## Low severity + ### 17. `comment` vs documented "description" mismatch — `src/v1/model.ts:113` - **Why weird:** Field named `comment` with JSDoc "User-provided free-form text description of the secret." The doc calls it a description; the field is called a comment. Same mismatch pattern as `abacpolicies.PolicyInfo.comment` (audit #28). - **Category:** 6 (misleading — doc says description, name says comment), 17 (cross-package inconsistency). @@ -125,79 +127,32 @@ - **Suggested name:** Rename `owner` -> `explicitOwner` or `directOwner` to mirror `effectiveOwner`'s "resolved" framing. - **Rationale:** Sibling pair should be obviously a pair. Reading `owner` and `effectiveOwner` side-by-side, the user has to consult the JSDoc to discover one is the raw input and one is the resolved output. Wire stays `owner`. -## Low severity - ### 19. `Client.createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — `src/v1/client.ts:75,105,132,172,240` - **Why weird:** Method names redundantly include `Secret` even though the class is already secret-scoped. `client.createSecret(req)` reads okay, but inside a UC-secrets-only file `client.create(req)` would be cleaner. Compare with `pkgJson.scripts` ("build", "test") — context-scoped commands omit the noun. - **Category:** 8 (redundant suffix — name repeats the class scope). - **Suggested name:** Within the class, `create` / `delete` / `get` / `list` / `update` would be tighter. (But it would break a cross-package convention — every generated client uses ``.) - **Rationale:** Cross-package convention wins here; flagging because rule 8 asks for redundant suffixes. The Go SDK uses `Create` / `Delete` etc. because Go method calls are scoped by receiver (`secretsuc.Create`). TS does the same implicitly (`client.create`). Worth raising at the SDK-design level. -### 20. `listSecretsIter` — `src/v1/client.ts:214` -- **Why weird:** `Iter` suffix is a Go convention. JS/TS convention is to return an `AsyncIterable` (or named explicit iterator helper) — the method already returns `AsyncGenerator`, so the `Iter` is redundant after the return-type annotation. Compare with `Symbol.asyncIterator` ecosystem (`for await...of` consumes any `AsyncGenerator` directly; users don't expect to call `.iter()`). -- **Category:** 14 (Go-style name), 8 (redundant suffix — return type already says it's an iterator). -- **Suggested name:** `streamSecrets`, `secretsStream`, or hoist into a `listSecrets[Symbol.asyncIterator]()`-style method. -- **Rationale:** TS callers write `for await (const s of client.listSecretsIter(req)) {}` which is fine, but the `Iter` adds nothing the type signature doesn't. Cross-SDK convention again; not worth fixing in isolation. - -### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** Same constant repeated in every generated package. `Segment` is generic; reader needs the comment to learn it's the User-Agent identity segment. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE_ID` or `PACKAGE_USER_AGENT_SEGMENT`. - **Rationale:** Same flag as in other generated packages; flagged for consistency. -### 22. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Function is exported but not called from `client.ts` in this package — all query strings are built manually with `URLSearchParams.append`. Dead-looking surface area. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Either remove or document why it ships per-package. -- **Rationale:** Same observation as in other audits. Each generated package carries this helper unused. - -### 23. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Generic name for "read response body stream into a Uint8Array". Could be confused with `Array.prototype.readAll`-like operations. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` / `readStreamToEnd` / `collectStream`. -- **Rationale:** Internal helper; low cost; skip if generated. - -### 24. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (unmarshal) vs `marshalRequest` (marshal). Two different verbs for inverse operations. -- **Category:** 17 (inconsistent verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` (symmetry), or `parseResponse` / `serializeRequest`. -- **Rationale:** Pair-wise consistency aids reading. - -### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Near-identical names for different layers — `executeCall` wraps retry/rate-limit/timeout, `executeHttpCall` does raw HTTP send + logging. Distinguishing `Http` infix is a fragile cue. -- **Category:** 1 (vague), 17 (inconsistent — should differ in more than `Http`). -- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). -- **Rationale:** Eases call-site reading. - -### 26. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** `Options` reused throughout the SDK (`ClientOptions`, `CallOptions`, etc.). Within `utils.ts` there's also `Options` imported from `@databricks/sdk-core/api` (`utils.ts:3`). -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. -- **Rationale:** Distinguish internal context bags from user-tunable options. - -### 27. `secretFieldMask` helper function — `src/v1/model.ts:294` -- **Why weird:** Helper that builds a typed `FieldMask` from string paths. Name is fine, but inconsistent with `marshalSecretSchema` / `unmarshalSecretSchema` which are nouns; this is a verb-style camelCase function. Lower-case-first is correct, but the pattern "what is X" (`secretFieldMask`) vs "what does X do" (`marshalSecretSchema` as a Zod schema object) shows mixed conventions in the file. -- **Category:** 17 (inconsistent — neighbouring exports mix function/value forms). -- **Suggested name:** Keep as-is (function names *should* be verb-first by JS convention, but `secretFieldMask` is a builder — `buildSecretFieldMask` would clarify). -- **Rationale:** Minor stylistic inconsistency. - ## Observations -### 28. Wire/TS divergence is heavy -The model file is 296 lines for *one* user-facing type (`Secret`) plus four request DTOs and one response DTO; ~130 lines are marshal/unmarshal/FieldMaskSchema scaffolding. The Zod schema duplicates the field list three times (interface, marshal schema, unmarshal schema, FieldMaskSchema). Not a naming problem, but the redundancy means a rename touches four places. - -### 29. Action-verb convention in `Client` +### 21. Action-verb convention in `Client` `createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) -### 30. Acronym casing for `Http` / `Url` +### 22. Acronym casing for `Http` / `Url` Same as other audited packages: `Http` (PascalCase capital-then-lower) coexists with `URLSearchParams` (ALLCAPS from Web standard). Convention inherited from broader JS ecosystem; not worth changing. - **Category:** 3. -### 31. `Uc` abbreviation never expanded in code +### 23. `Uc` abbreviation never expanded in code Tracked thoroughly. The string "Uc" (in any case) does not appear in any identifier, type name, field name, constant, or enum value. "Unity Catalog" appears only in (a) JSDoc on `Secret` (`model.ts:85`), (b) JSDoc on `createSecret` / `listSecrets` / `updateSecret` (`client.ts:67,163,232`), and (c) the URL path string `/api/2.1/unity-catalog/secrets` (`client.ts:79,109,136,176,244`). The package name `secretsuc` is the **only** carrier of the disambiguator at the import level, and it's silent everywhere else. A consumer importing `Client` and `Secret` from this package, then opening their editor's symbol view, will see no hint that this is Unity-Catalog-scoped. See finding #1. - **Category:** 5. -### 32. No enums in this package +### 24. No enums in this package No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; `secretsuc` exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. ## Domain glossary diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md index e3415ceb..9e3ecf11 100644 --- a/.agent/naming-audit/serviceprincipalsecrets.md +++ b/.agent/naming-audit/serviceprincipalsecrets.md @@ -5,7 +5,7 @@ **Inferred domain:** Account-level CRUD over OAuth client secrets attached to a service principal. Endpoints sit under `/api/2.0/accounts//servicePrincipals//credentials/secrets`. -**Total weird names flagged:** 33 +**Total weird names flagged:** 26 --- @@ -21,8 +21,8 @@ a service principal. Endpoints sit under | 6 | `DeleteServicePrincipalSecret_Response` | model.ts:42 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names | Underscore-separated identifier (only of its kind in the file). Should be `DeleteServicePrincipalSecretResponse`. Flagged in `naming-convention` eslint disable comment so the generator knows it's odd. | | 7 | `ListServicePrincipalSecrets_Response` | model.ts:59 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names | Same underscore issue as #6. The TS convention is `ListServicePrincipalSecretsResponse` (matching `CreateServicePrincipalSecretResponse`). Generator deliberately retains the proto-message nesting (`Foo_Response`); consumer-facing types should not leak that. | | 8 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 1 Vague/generic without domain context, 15 Generic field names losing meaning, 19 Underspecified IDs | Field is the service principal **ID** (per JSDoc `The service principal ID.`) but the field name implies the principal object itself. Should be `servicePrincipalId`. Same problem in `DeleteServicePrincipalSecret` (model.ts:35) and `ListServicePrincipalSecrets` (model.ts:47). | -| 9 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — fine, but the default ("730 days") is documented in JSDoc only; no constant exposed. Marshal converts to a lower-case ISO duration string (model.ts:155). `secretLifetime` would tie the field to the resource it bounds. | -| 10 | `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` | model.ts:15, 66 | interface pair | High | 12 Duplicate concepts | Both interfaces have identical fields (`id`, `secret`, `secretHash`, `createTime`, `updateTime`, `status`, `expireTime`). Their unmarshallers (model.ts:83 vs 125) are byte-identical. One of them is redundant — `CreateServicePrincipalSecretResponse` could `extends ServicePrincipalSecret` or be a type alias. | +| 9 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — fine, but the default ("730 days") is documented in JSDoc only; no constant exposed. `secretLifetime` would tie the field to the resource it bounds. | +| 10 | `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` | model.ts:15, 66 | interface pair | High | 12 Duplicate concepts | Both interfaces have identical fields (`id`, `secret`, `secretHash`, `createTime`, `updateTime`, `status`, `expireTime`). One of them is redundant — `CreateServicePrincipalSecretResponse` could `extends ServicePrincipalSecret` or be a type alias. | | 11 | `ServicePrincipalSecret.secret` | model.ts:69 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret.secret` is a stutter. JSDoc says `Secret Value`. Rename to `value` or `clearTextValue`; `ServicePrincipalSecret.value` is unambiguous. Same field appears in `CreateServicePrincipalSecretResponse.secret` (model.ts:19). | | 12 | `ServicePrincipalSecret.secretHash` | model.ts:71 | field | Low | 1 Vague/generic without domain context | `secret.secretHash` is also a stutter. `hash` is enough. (Both `secret` and `secretHash` then need renaming; otherwise drop just the `secret` prefix here.) | | 13 | `ServicePrincipalSecret.id` | model.ts:68 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | Top-level `id: string` is the secret's ID. Should be `secretId` to match `DeleteServicePrincipalSecret.secretId` (model.ts:38), which refers to the same value. The asymmetry forces callers to remember the mapping. | @@ -35,17 +35,10 @@ a service principal. Endpoints sit under | 20 | `ListServicePrincipalSecrets_Response.secrets` | model.ts:61 | field | Low | 9 Singular/plural mismatches | Plural is correct (`secrets: ServicePrincipalSecret[]`), but the wire form is `secrets` (model.ts:115) — no underscore split. Clean. (Flagged only because nextPageToken below is the underscore case.) | | 21 | `ListServicePrincipalSecrets_Response.nextPageToken` | model.ts:63 | field | Low | 3 Acronym casing inconsistencies | Field is `nextPageToken` (camelCase) and the wire form is `next_page_token` (model.ts:118, 122). Consistent with the SDK norm; no real issue. Listed only because the JSDoc (model.ts:62) uses backticked `page_token` not `pageToken`, which is the wire spelling — confusing for TS consumers. | | 22 | `ListServicePrincipalSecrets.pageToken` JSDoc | model.ts:50-54 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc says `next_page_token`, `page_token`, and `nextPageToken` — three spellings of two fields in one comment. Doc generator should normalise to the TS field names. | -| 23 | `unmarshalCreateServicePrincipalSecretResponseSchema` | model.ts:83 | const | Medium | 7 Overly verbose, 20 Type-suffix tautology | 50-char identifier. `Schema` suffix duplicates the `z.ZodType<...>` annotation. Across the SDK; not unique here. | -| 24 | `unmarshalDeleteServicePrincipalSecret_ResponseSchema` | model.ts:108 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | 52-char identifier with an underscore preserved verbatim from the proto message nesting. ESLint-disabled at model.ts:107. | -| 25 | `unmarshalListServicePrincipalSecrets_ResponseSchema` | model.ts:112 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | Same as #24 — 51 chars + underscore. | -| 26 | `unmarshalCreateServicePrincipalSecretResponseSchema` body vs `unmarshalServicePrincipalSecretSchema` body | model.ts:83, 125 | const pair | High | 12 Duplicate concepts | The two zod schemas are byte-identical (same fields, same transforms). One should be defined and the other should alias. | -| 27 | `marshalCreateServicePrincipalSecretSchema` | model.ts:149 | const | Low | 17 Inconsistent action verbs, 20 Type-suffix tautology | Lone `marshal*` const (no other marshal in the file). The pairing is `marshal*` / `unmarshal*`. JS/TS conventions favour `encode`/`decode` or `serialize`/`deserialize` — `marshal`/`unmarshal` is a Go transliteration. | -| 28 | `marshalCreateServicePrincipalSecretSchema` typing | model.ts:149 | const | Low | 1 Vague/generic without domain context | Declared as `z.ZodType` (no generic). Sibling unmarshallers are `z.ZodType<...>`. The asymmetry hides what `marshalRequest(req, marshalCreateServicePrincipalSecretSchema)` (client.ts:77) actually validates. | -| 29 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. A consumer that imports `{Client}` from this package and from any other SDK package has to alias each one. Suggest `ServicePrincipalSecretsClient` (or a namespace re-export). | -| 30 | `Client.createServicePrincipalSecret` etc. | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Method names repeat the package name (`createServicePrincipalSecret` inside the `serviceprincipalsecrets` package). After namespacing it becomes `serviceprincipalsecrets.Client.createServicePrincipalSecret(...)` — `create(req)` would suffice if the package boundary is preserved. | -| 31 | `Client.listServicePrincipalSecretsIter` | client.ts:165 | method | Medium | 14 Go/Java-style names not idiomatic TS, 7 Overly verbose | `Iter` suffix is a Go idiom. TS convention for `AsyncGenerator` is to omit the suffix and rely on `for await … of` — or use `[Symbol.asyncIterator]` on the result itself. Also the method does not appear in `index.ts` (only `Client` is re-exported, which exposes it transitively). | -| 32 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Same shared-utils issue across the SDK: two `execute*` functions in one file with overlapping vocabulary. `executeCall` orchestrates retries/timeouts via the public `CallOptions`; `executeHttpCall` does one HTTP roundtrip and converts errors. Names should distinguish them — e.g. `runWithOptions` / `sendRequest`. | -| 33 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 10 Dead code | Exported from `utils.ts` but never imported in `client.ts` (which builds query strings inline via `URLSearchParams` at client.ts:134-142). Either remove or use it. | +| 23 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. A consumer that imports `{Client}` from this package and from any other SDK package has to alias each one. Suggest `ServicePrincipalSecretsClient` (or a namespace re-export). | +| 24 | `Client.createServicePrincipalSecret` etc. | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Method names repeat the package name (`createServicePrincipalSecret` inside the `serviceprincipalsecrets` package). After namespacing it becomes `serviceprincipalsecrets.Client.createServicePrincipalSecret(...)` — `create(req)` would suffice if the package boundary is preserved. | +| 25 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Same shared-utils issue across the SDK: two `execute*` functions in one file with overlapping vocabulary. `executeCall` orchestrates retries/timeouts via the public `CallOptions`; `executeHttpCall` does one HTTP roundtrip and converts errors. Names should distinguish them — e.g. `runWithOptions` / `sendRequest`. | +| 26 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 10 Dead code | Exported from `utils.ts` but never imported in `client.ts` (which builds query strings inline via `URLSearchParams` at client.ts:134-142). Either remove or use it. | --- @@ -61,9 +54,8 @@ The two packages have: `CreateServicePrincipalSecretResponse`, `DeleteServicePrincipalSecret`, `DeleteServicePrincipalSecret_Response`, `ListServicePrincipalSecrets`, `ListServicePrincipalSecrets_Response`, `ServicePrincipalSecret`. -- **The same** four client methods: `createServicePrincipalSecret`, - `deleteServicePrincipalSecret`, `listServicePrincipalSecrets`, - `listServicePrincipalSecretsIter`. +- **The same** client methods: `createServicePrincipalSecret`, + `deleteServicePrincipalSecret`, `listServicePrincipalSecrets`. - **The same** URL path: `/api/2.0/accounts//servicePrincipals//credentials/secrets`. @@ -85,7 +77,7 @@ re-export. ### H2. `*_Response` underscore types -Three public symbols carry a literal underscore, retained from +Two public symbols carry a literal underscore, retained from proto-message nesting and ESLint-disabled at each site: ```ts @@ -94,10 +86,6 @@ export interface DeleteServicePrincipalSecret_Response {} // model.ts:59 export interface ListServicePrincipalSecrets_Response { ... } - -// model.ts:108, 112 -export const unmarshalDeleteServicePrincipalSecret_ResponseSchema = ... -export const unmarshalListServicePrincipalSecrets_ResponseSchema = ... ``` These are the only underscored identifiers in the package and the generator @@ -122,15 +110,13 @@ export interface ServicePrincipalSecret { ``` The two interfaces have the **same** seven fields with the **same** types -and the **same** JSDoc. Their unmarshallers (model.ts:83 vs 125) are -byte-identical (same `z.object`, same `transform`). One of them is -redundant. Options: +and the **same** JSDoc. One of them is redundant. Options: - `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret;` - `interface CreateServicePrincipalSecretResponse extends ServicePrincipalSecret {}` - Inline `ServicePrincipalSecret` into the create method's return type. -Either way the duplicated schema is wasted bundle size. +Either way the duplicated shape is wasted bundle size. ### H4. `*.servicePrincipal` is misleading @@ -142,8 +128,8 @@ servicePrincipal?: string | undefined; // JSDoc: "The service principal ID." The field is the service principal **ID** (a string), but the name reads as if the value is the `ServicePrincipal` object. The wire form is `service_principal` (model.ts:160) — the wire is the misleading source. -Rename the TS field to `servicePrincipalId` and let the marshal -`transform` keep the wire spelling. Same fix is needed for the URL +Rename the TS field to `servicePrincipalId` and let the wire spelling be +preserved at the transport layer. Same fix is needed for the URL parameter use at client.ts:76, 105, 133. ### H5. `ServicePrincipalSecret.status: string` should be a string-literal union @@ -188,10 +174,7 @@ expireTime?: Temporal.Instant | undefined; // model.ts:80 ``` The same shape uses `string` for two date fields and `Temporal.Instant` -for the third. The unmarshaller (model.ts:92-95, 134-137) reinforces this: -`expire_time` is `Temporal.Instant.from(s)`, but `create_time` / -`update_time` are passed through as raw strings. Pick one — Temporal for -all three is the principled fix. +for the third. Pick one — Temporal for all three is the principled fix. ### M3. `ServicePrincipalSecret.secret` stutters @@ -231,21 +214,7 @@ to alias each one. Suggest `ServicePrincipalSecretsClient` or rely on namespace imports (`import * as serviceprincipalsecrets from '@databricks/sdk-serviceprincipalsecrets/v1'`). -### M6. `listServicePrincipalSecretsIter` is a Go idiom - -```ts -async *listServicePrincipalSecretsIter(...): AsyncGenerator -``` - -The `Iter` suffix is Go-style (cf. `databricks/sdk-go` listers that -return iterators with `*Iter` types). TS convention is either: - -- Method returns `AsyncIterable` and is named without a suffix - (e.g. `listServicePrincipalSecrets()` returns the iterable; the - page-fetch version is named `listServicePrincipalSecretsPage()`), or -- Method is named `listAll` / `listPages` etc. - -### M7. Method names duplicate the package name +### M6. Method names duplicate the package name ```ts client.createServicePrincipalSecret(...) @@ -259,7 +228,7 @@ a `ServicePrincipalSecretsClient`, `create(req)` / `delete(req)` / `list(req)` are sufficient. (`delete` is a reserved word in JS, but legal as a method name.) This is consistent across the SDK; not unique here. -### M8. `executeCall` vs `executeHttpCall` +### M7. `executeCall` vs `executeHttpCall` Identical to sibling packages. Two `execute*` functions in `utils.ts`: @@ -270,7 +239,7 @@ Identical to sibling packages. Two `execute*` functions in `utils.ts`: Two near-identical names within one file is a navigation hazard. Suggested: `runWithOptions` / `sendRequest`. -### M9. `ListServicePrincipalSecrets` mixes path and query parameters +### M8. `ListServicePrincipalSecrets` mixes path and query parameters ```ts export interface ListServicePrincipalSecrets { @@ -289,35 +258,20 @@ names give no hint. ## Low severity (nits) -### L1. `Schema` suffix tautology on all zod consts - -`unmarshalServicePrincipalSecretSchema: z.ZodType` — -the `Schema` suffix duplicates the type annotation. Pattern is consistent -across the SDK, so this is a generator-wide concern. The same suffix -pushes the longest identifier in this file to 52 chars -(`unmarshalDeleteServicePrincipalSecret_ResponseSchema`). - -### L2. `marshal`/`unmarshal` is a Go transliteration - -JS/TS conventions are `encode`/`decode` (most TS data libraries) or -`serialize`/`deserialize`. `marshal`/`unmarshal` matches Go's -`encoding/json` package idiom (`json.Marshal`/`json.Unmarshal`) but is -not idiomatic TS. - -### L3. `expireTime` verb tense vs `createTime` / `updateTime` +### L1. `expireTime` verb tense vs `createTime` / `updateTime` `createTime` and `updateTime` are past-tense ("when the create happened"), but `expireTime` is future-tense. Consistent options are `createdAt`/`updatedAt`/`expiresAt` (idiomatic TS) or `createTime`/`updateTime`/`expirationTime`. -### L4. `lifetime` could be `secretLifetime` +### L2. `lifetime` could be `secretLifetime` `lifetime: Temporal.Duration` reads fine in context, but as a standalone field name carries no domain. `secretLifetime` ties the field to the resource. Minor. -### L5. `pageToken` JSDoc uses three different spellings +### L3. `pageToken` JSDoc uses three different spellings ```ts // model.ts:50-54 @@ -338,32 +292,20 @@ pageToken?: string | undefined; The comment mixes `next_page_token` (wire), `page_token` (wire), and the TS field is `pageToken`. A TS-facing JSDoc should use the TS spellings. -### L6. `marshalCreateServicePrincipalSecretSchema` is untyped - -```ts -// model.ts:149 -export const marshalCreateServicePrincipalSecretSchema: z.ZodType = ... -``` - -Compare to siblings (e.g. `unmarshalServicePrincipalSecretSchema: -z.ZodType`). The marshal const lacks the generic. -At the call site (client.ts:77) the caller can't see what shape is being -parsed. Tighten to `z.ZodType`. - -### L7. `flattenQueryParams` is exported but unused +### L4. `flattenQueryParams` is exported but unused `utils.ts:123` exports `flattenQueryParams`. `client.ts` never imports it (query strings are built inline via `URLSearchParams` at client.ts:134-142). Either delete it or use it. Either way the dead export pollutes the API surface that `index.ts` does not re-export. -### L8. `HttpCallOptions` is generic +### L5. `HttpCallOptions` is generic Internal `interface` with `{request, httpClient, logger}`. Inside one file this is fine. If it ever leaks out, `ExecuteHttpCallParams` would self-document and avoid collision with the public `CallOptions`. -### L9. `PACKAGE_SEGMENT` +### L6. `PACKAGE_SEGMENT` ```ts // client.ts:37 @@ -373,13 +315,13 @@ const PACKAGE_SEGMENT = {...}; Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site (`createDefault().with(PACKAGE_SEGMENT)`) self-explanatory. -### L10. `req` vs `request` +### L7. `req` vs `request` Method parameters are named `req` (client.ts:73, 102, 130, 166). TS code in the wider ecosystem more commonly uses `request` or `params`. `req` leans Go-idiomatic. Minor stylistic point. -### L11. `'Host is required.'` +### L8. `'Host is required.'` ```ts // client.ts:56 @@ -390,7 +332,7 @@ Not a naming issue, but the package throws plain `Error` rather than a typed `ConfigError`/`MissingOptionError`. Consistent with sibling packages. -### L12. `'API call completed without a result.'` +### L9. `'API call completed without a result.'` ```ts // client.ts:95, 123, 160 @@ -447,7 +389,7 @@ Unreachable branch for `delete*` (response is always parseable as | **Account ID** | The numeric Databricks account identifier (path parameter `` in every URL). | | **Service principal** | The owning identity for the secret; addressed by ID even though the field is named `servicePrincipal`. | | **Service principal secret** | The unit resource: an OAuth client secret attached to a service principal, with an `id`, opaque `secret` value, hash, status, and lifecycle timestamps (`createTime`, `updateTime`, `expireTime`). | -| **Lifetime** | A `Temporal.Duration` (default 730 days / 63072000s) controlling when the secret expires. Marshalled to a lower-case ISO duration string (`'p730d'` etc.). | +| **Lifetime** | A `Temporal.Duration` (default 730 days / 63072000s) controlling when the secret expires. | | **Secret value** | The plaintext secret returned at creation time (`secret`), opaque on read. | | **Secret hash** | A hash of the plaintext secret (`secretHash`); typed `string`, no algorithm documented. | | **Status** | A string label (probably one of `ACTIVE`/`PENDING`/`REVOKED`) — but the field is plain `string`. | diff --git a/.agent/naming-audit/serviceprincipalsecretsproxy.md b/.agent/naming-audit/serviceprincipalsecretsproxy.md index 9776e10b..7ca09360 100644 --- a/.agent/naming-audit/serviceprincipalsecretsproxy.md +++ b/.agent/naming-audit/serviceprincipalsecretsproxy.md @@ -6,7 +6,7 @@ service principal (create, list, delete), exposed as a "proxy" variant whose surface area is byte-identical to the sibling `serviceprincipalsecrets` package. -**Total weird names flagged:** 33 +**Total weird names flagged:** 26 --- @@ -37,16 +37,9 @@ package. | 21 | `ListServicePrincipalSecrets_Response.secrets` | model.ts:61 | field | Low | 9 Singular/plural mismatches | Plural is correct. JSDoc says "List of the secrets" — phrasing nit, "List of secrets" would read better. | | 22 | `ServicePrincipalSecret` | model.ts:66 | interface | Medium | 12 Duplicate concepts | Structurally identical to `CreateServicePrincipalSecretResponse` (see #7). Two names for one shape. | | 23 | `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` | model.ts:68, 70, 72, 78 | field | Medium | 1 Vague/generic without domain context | Same vague-field issues as the response copy (#8-#11). | -| 24 | `unmarshalCreateServicePrincipalSecretResponseSchema` | model.ts:83 | const | Medium | 7 Overly verbose, 20 Type-suffix tautology | 50-char identifier. `Schema` suffix is redundant with the `z.ZodType<...>` annotation; the leading `unmarshal` is Go-idiom (see #29). | -| 25 | `unmarshalDeleteServicePrincipalSecret_ResponseSchema` | model.ts:108 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | 52-char identifier that includes an embedded underscore; needs `eslint-disable-next-line @typescript-eslint/naming-convention`. | -| 26 | `unmarshalListServicePrincipalSecrets_ResponseSchema` | model.ts:112 | const | High | 4 Underscores in TS identifiers, 7 Overly verbose | Same underscore + verbosity issue as #25. | -| 27 | `unmarshalServicePrincipalSecretSchema` | model.ts:125 | const | Low | 20 Type-suffix tautology | `Schema` suffix is tautological with the `z.ZodType` annotation. | -| 28 | `marshalCreateServicePrincipalSecretSchema` | model.ts:149 | const | Low | 17 Inconsistent action verbs, 20 Type-suffix tautology | Same as #27, plus: pairing is `marshal*`/`unmarshal*` (Go-idiom — TS norm would be `encode`/`decode` or `serialize`/`deserialize`). Note this const has type `z.ZodType` *without* a generic argument while every sibling unmarshal const supplies one. | -| 29 | `marshal`/`unmarshal` verbs (whole file) | model.ts:83, 108, 112, 125, 149 | naming pattern | Low | 14 Go/Java-style names not idiomatic TS, 17 Inconsistent action verbs | Direct Go transliteration. TS ecosystem uses `JSON.stringify` / `JSON.parse`, `encode` / `decode`, or `serialize` / `deserialize`. | -| 30 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. Once two Databricks clients are imported in the same module, every one is just `Client`. Should be `ServicePrincipalSecretsProxyClient` or aliased on export. | -| 31 | `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Inside a class named `Client` (let alone a class that should be `ServicePrincipalSecretsClient`), repeating `ServicePrincipalSecret` in every method name is stutter. `create(req)` / `delete(req)` / `list(req)` would read cleanly. | -| 32 | `Client.listServicePrincipalSecretsIter` | client.ts:165 | method | Medium | 7 Overly verbose, 14 Go/Java-style names not idiomatic TS, 5 Cryptic abbreviations | `Iter` suffix is a Go-idiom (`func ListSomethingIter()`). TS `AsyncGenerator` returns are conventionally named without suffixes, or with `*All` / `*Stream`. Combined with the already-verbose method root, this is a 37-character identifier. | -| 33 | `PACKAGE_SEGMENT` | client.ts:37 | const | Low | 1 Vague/generic without domain context | Used only to assemble the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory. | +| 24 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. Once two Databricks clients are imported in the same module, every one is just `Client`. Should be `ServicePrincipalSecretsProxyClient` or aliased on export. | +| 25 | `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Inside a class named `Client` (let alone a class that should be `ServicePrincipalSecretsClient`), repeating `ServicePrincipalSecret` in every method name is stutter. `create(req)` / `delete(req)` / `list(req)` would read cleanly. | +| 26 | `PACKAGE_SEGMENT` | client.ts:37 | const | Low | 1 Vague/generic without domain context | Used only to assemble the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory. | --- @@ -77,9 +70,8 @@ Same seven exported types `DeleteServicePrincipalSecret_Response`, `ListServicePrincipalSecrets`, `ListServicePrincipalSecrets_Response`, -`ServicePrincipalSecret`), same four client methods (`createServicePrincipalSecret`, -`deleteServicePrincipalSecret`, `listServicePrincipalSecrets`, -`listServicePrincipalSecretsIter`), same URL path +`ServicePrincipalSecret`), same client methods (`createServicePrincipalSecret`, +`deleteServicePrincipalSecret`, `listServicePrincipalSecrets`), same URL path (`/api/2.0/accounts//servicePrincipals//credentials/secrets`). The user instruction calls out: *"Pay extra attention: the 'proxy' variant @@ -114,13 +106,11 @@ Rename to `servicePrincipalId` everywhere. ### H3. Protobuf-style underscore identifiers leak into TS -Three identifiers carry an embedded `_` that requires `eslint-disable-next-line` +Two identifiers carry an embedded `_` that requires `eslint-disable-next-line` comments at every declaration: - `DeleteServicePrincipalSecret_Response` (model.ts:42) - `ListServicePrincipalSecrets_Response` (model.ts:59) -- `unmarshalDeleteServicePrincipalSecret_ResponseSchema` (model.ts:108) -- `unmarshalListServicePrincipalSecrets_ResponseSchema` (model.ts:112) This is category 4 (underscores in TS identifiers) and category 14 (Go/Java-style names not idiomatic TS). The inline comments @@ -208,20 +198,12 @@ class Client { createServicePrincipalSecret(req, ...) deleteServicePrincipalSecret(req, ...) listServicePrincipalSecrets(req, ...) - listServicePrincipalSecretsIter(req, ...) } ``` The receiver is already the secrets client. Methods could be `create`, -`delete`, `list`, `listAll` (or `list` returning an iterable). Even keeping -the long names, the consistent stutter is worth flagging since the package -name is already 33 characters. - -### M8. `listServicePrincipalSecretsIter` uses a Go-idiom suffix - -`*Iter` is Go convention (`func ListSomethingIter() iter.Seq`). TS code -typically returns `AsyncIterable` without suffix, or uses `*Stream` / -`iter*()`. Other audited packages have flagged the same pattern. +`delete`, `list`. Even keeping the long names, the consistent stutter is +worth flagging since the package name is already 33 characters. --- @@ -238,64 +220,32 @@ The wire field is `secret_hash` and the doc is "Secret Hash". Callers cannot verify hashes without knowing the algorithm (almost certainly SHA-256 given Databricks norms, but the SDK does not say). -### L3. `Schema` suffix tautology - -Every zod constant is named `unmarshal*Schema` / `marshal*Schema`. The -`Schema` suffix duplicates the `z.ZodType<...>` annotation. Cross-SDK -generator concern, not unique to this package. - -### L4. `marshal` / `unmarshal` are Go-idioms - -```ts -unmarshalCreateServicePrincipalSecretResponseSchema = z.object(...).transform(...) -marshalCreateServicePrincipalSecretSchema = z.object(...).transform(...) -``` - -TS ecosystem norm is `encode` / `decode`, `serialize` / `deserialize`, or -just `parse` / `stringify`. Go's `encoding/json` uses `Marshal`/`Unmarshal`; -TS does not. - -### L5. `marshalCreateServicePrincipalSecretSchema` lacks a generic argument - -```ts -export const marshalCreateServicePrincipalSecretSchema: z.ZodType = z.object(...); -``` - -Every sibling unmarshal const supplies a generic argument -(`z.ZodType`). The marshal const drops it, weakening -type safety on the call to `marshalRequest(req, marshalCreateServicePrincipalSecretSchema)`. - -### L6. `PACKAGE_SEGMENT` +### L3. `PACKAGE_SEGMENT` Used only for the User-Agent header. Rename to `USER_AGENT_PACKAGE_SEGMENT` so the call site (`createDefault().with(PACKAGE_SEGMENT)` → `.with(USER_AGENT_PACKAGE_SEGMENT)`) is self-explanatory. -### L7. `HttpCallOptions` +### L4. `HttpCallOptions` Internal `interface` with `{request, httpClient, logger}`. Generic name. If it ever leaks beyond `utils.ts`, `ExecuteHttpCallParams` would self-document. (This shape and name is shared verbatim with sibling packages — generator-wide.) -### L8. `parseResponse` vs `marshalRequest` - -`utils.ts` mixes `parse` / `marshal` action verbs. Pick one pair -(`parse` / `format`, or `marshal` / `unmarshal`) and stay consistent. - -### L9. `flattenQueryParams` exported but never imported +### L5. `flattenQueryParams` exported but never imported `utils.ts:123` exports `flattenQueryParams`. `client.ts` builds query strings inline via `URLSearchParams` (client.ts:134-141). Either: - Use it (current inline code reproduces a subset of its logic), or - Remove it (dead code). -### L10. `req` parameter naming in client methods +### L6. `req` parameter naming in client methods Every public method uses `req: ` — Go-idiom. TS conventions prefer `request` or `params`. Stylistic only. -### L11. `pageToken` JSDoc is enormous +### L7. `pageToken` JSDoc is enormous ```ts /** @@ -316,7 +266,7 @@ A four-sentence pagination contract attached to a single field. `pageSize` on the very next line has zero JSDoc. Move the contract to the type-level JSDoc or package docs; keep the field-level note short. -### L12. `accountId` in path templates falls back silently +### L8. `accountId` in path templates falls back silently ```ts const url = `${this.host}/api/2.0/accounts/${req.accountId ?? this.accountId ?? ''}/servicePrincipals/${req.servicePrincipal ?? ''}/credentials/secrets`; @@ -377,7 +327,7 @@ validation error. Not a naming issue per se, but a result of the underspecified | File | Lines | Exports counted | Audited | |------|-------|-----------------|---------| | `src/v1/model.ts` | 162 | 7 interfaces, 5 zod consts | yes | -| `src/v1/client.ts` | 181 | 1 class, 4 public methods (3 request + 1 iterator) | yes | +| `src/v1/client.ts` | 181 | 1 class, 3 public methods | yes | | `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | | `src/v1/index.ts` | 15 | 1 class re-export, 7 type re-exports, 1 no-op `export {}` | yes | diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index a064c5c3..890831c1 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 **Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). -**Total weird names flagged:** 111 +**Total weird names flagged:** 106 --- @@ -79,66 +79,61 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | 49 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:194, 196`; `client.ts:166` | | 50 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:225-227`; `client.ts:226` | | 51 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:252-254` | -| 52 | Medium | Method name redundancy | `listAccountSettingsMetadataIter` ("Iter" suffix vs neighbouring `listAccountSettingsMetadata`) | `client.ts:202, 262, 323` | -| 53 | Medium | Cryptic abbreviation | `Iter` (Go iterator idiom in JS — should be implicit on AsyncGenerator) | `client.ts:202, 262, 323` | -| 54 | Medium | Overly verbose | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` (when accessed as enum member) | `model.ts:13` | -| 55 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | -| 56 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | -| 57 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:294` | -| 58 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:322` | -| 59 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:337` | -| 60 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:104` | -| 61 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:148-149` | -| 62 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:369` | -| 63 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:374` | -| 64 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:379` | -| 65 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:384` | -| 66 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:389` | -| 67 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:411` | -| 68 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:404` | -| 69 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:398` | -| 70 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:404`; `utils.ts:69, 71, 100, 103` | -| 71 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:107` | -| 72 | Low | Long enum value | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | -| 73 | Low | Long enum value | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | -| 74 | Low | Long enum value | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | -| 75 | Low | Long enum value | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | -| 76 | Low | Long enum value | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | -| 77 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | -| 78 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | -| 79 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | -| 80 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:79` | -| 81 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:79` | -| 82 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:79, 83` | -| 83 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:79` | -| 84 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:99, 172, 285, 305, 416, 434` | -| 85 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:402` | -| 86 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | -| 87 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:153, 161, ...` | -| 88 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | -| 89 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:275` | -| 90 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:624, 959` | -| 91 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | -| 92 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:172` | -| 93 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:305, 99` | -| 94 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:327-329` | -| 95 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:374` | -| 96 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:103` | -| 97 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:137` | -| 98 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:289` | -| 99 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | -| 100 | Low | Inconsistent verb | `Iter` suffix (Go idiom in TS) | `client.ts:202, 262, 323` | -| 101 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:160-161` | -| 102 | Low | Empty default | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED = 'PREVIEW_PHASE_UNSPECIFIED'` doc says unset-OR-not-a-preview (two distinct meanings) | `model.ts:12-13` | -| 103 | Low | Long type | `ClusterAutoRestartMessage_EnablementDetails` containing three `unavailable_for_*` booleans | `model.ts:119-126` | -| 104 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:121` | -| 105 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:123` | -| 106 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:125` | -| 107 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | -| 108 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | -| 109 | Low | Reserved-word adjacency | `signal` (uses Web/Node `AbortSignal` standard name — okay, just noting) | `client.ts:89, 118, 143, ...` | -| 110 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | -| 111 | Low | Type-suffix tautology | `*Schema` suffix on every zod schema (`unmarshalSettingSchema`, `marshalSettingSchema`, etc.) — Zod variables don't need the suffix; `import {z} from 'zod'` already conveys this | `model.ts:449, 460, 469, 477, ...` | +| 52 | Medium | Overly verbose | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` (when accessed as enum member) | `model.ts:13` | +| 53 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | +| 54 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | +| 55 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:294` | +| 56 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:322` | +| 57 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:337` | +| 58 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:104` | +| 59 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:148-149` | +| 60 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:369` | +| 61 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:374` | +| 62 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:379` | +| 63 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:384` | +| 64 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:389` | +| 65 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:411` | +| 66 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:404` | +| 67 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:398` | +| 68 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:404`; `utils.ts:69, 71, 100, 103` | +| 69 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:107` | +| 70 | Low | Long enum value | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | +| 71 | Low | Long enum value | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | +| 72 | Low | Long enum value | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | +| 73 | Low | Long enum value | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | +| 74 | Low | Long enum value | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | +| 75 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | +| 76 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | +| 77 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | +| 78 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:79` | +| 79 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:79` | +| 80 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:79, 83` | +| 81 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:79` | +| 82 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:99, 172, 285, 305, 416, 434` | +| 83 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:402` | +| 84 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | +| 85 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:153, 161, ...` | +| 86 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | +| 87 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:275` | +| 88 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:624, 959` | +| 89 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | +| 90 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:172` | +| 91 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:305, 99` | +| 92 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:327-329` | +| 93 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:374` | +| 94 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:103` | +| 95 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:137` | +| 96 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:289` | +| 97 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | +| 98 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:160-161` | +| 99 | Low | Empty default | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED = 'PREVIEW_PHASE_UNSPECIFIED'` doc says unset-OR-not-a-preview (two distinct meanings) | `model.ts:12-13` | +| 100 | Low | Long type | `ClusterAutoRestartMessage_EnablementDetails` containing three `unavailable_for_*` booleans | `model.ts:119-126` | +| 101 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:121` | +| 102 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:123` | +| 103 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:125` | +| 104 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | +| 105 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | +| 106 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | --- @@ -358,20 +353,13 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** On `ListAccountUserPreferencesMetadataResponse`, the field should be `userPreferencesMetadata`, not `settingsMetadata`. Currently the response field for "list of user preferences" is typed as `SettingsMetadata[]` and named `settingsMetadata` — which is technically the same metadata type but linguistically misleading. - **Rationale:** A consumer reading `resp.settingsMetadata` on a `ListAccountUserPreferencesMetadataResponse` will be confused why "settings" appears on a "user preferences" response. -### 52–53. `*Iter` suffix on AsyncGenerator methods — Go-style - -- **File:line:** `client.ts:202, 262, 323` -- **Category:** Go/Java-style naming, cryptic abbreviation -- **Suggestion:** Drop the suffix or use TS conventions. AsyncGenerator return-type already differentiates from the page-returning variant. Common TS patterns: `listX()` returns a page, `listXAll()` or `[Symbol.asyncIterator]` returns an iterator. -- **Rationale:** "Iter" mimics Go's `func (c *Client) ListAccountSettingsMetadataAll(...)` iterator helper. In TS, returning `AsyncGenerator` is already idiomatic; the suffix is noise. - -### 54. `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` access stutters +### 52. `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` access stutters - **File:line:** `model.ts:13` - **Category:** Overly verbose enum access - **Suggestion:** See #16. -### 55. `PreviewPhase` enum — mixed temporal/qualitative members +### 53. `PreviewPhase` enum — mixed temporal/qualitative members - **File:line:** `model.ts:11-27` - **Category:** Verb-tense / categorisation inconsistency @@ -379,53 +367,53 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. - **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. -### 56–57. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` +### 54–55. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` - **File:line:** `model.ts:30, 88, 94, 294` - **Category:** Acronym casing - **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. -### 58–59. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope +### 56–57. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope - **File:line:** `model.ts:322 (auto-cluster on a unified Setting), 337 (restrict-admins on Setting)` - **Category:** Field contradicting type domain - **Suggestion:** Either drop the `Workspace` suffix from `automaticClusterUpdateWorkspace` (the parent `Setting` type is scope-agnostic) or always include the scope (then `personalCompute` should be `personalComputeAccount`). - **Rationale:** Some payload discriminators mention scope (`automaticClusterUpdateWorkspace`), others don't (`personalCompute`, `restrictWorkspaceAdmins`). A reader can't predict the rule. -### 60. `canToggle?: boolean` on `ClusterAutoRestartMessage` +### 58. `canToggle?: boolean` on `ClusterAutoRestartMessage` - **File:line:** `model.ts:104` - **Category:** Generic field - **Suggestion:** `userCanToggle: boolean` or `togglePermitted: boolean`. "Toggle what?" is unclear from the field alone (presumably toggle the `enabled` field, but that's implicit). -### 61. `hours`, `minutes` with no timezone +### 59. `hours`, `minutes` with no timezone - **File:line:** `model.ts:148-149` - **Category:** Generic field name, missing constraint - **Suggestion:** Add doc specifying the time-zone interpretation, or rename `utcHours`/`utcMinutes` if UTC, or add a `timezone?: string` field. - **Rationale:** A "maintenance window start time" without timezone is ambiguous (workspace TZ? customer TZ? UTC?). -### 62–66. Overly verbose `effective*` discriminator names +### 60–64. Overly verbose `effective*` discriminator names - **File:line:** `model.ts:369, 374, 379, 384, 389` - **Category:** Overly verbose - **Suggestion:** Either drop the `effective` prefix on the discriminator value (the parent field is `effectiveValue`, so the prefix is redundant) or split into two top-level discriminated unions (`Setting.value: {$case: 'automaticClusterUpdateWorkspace', ...}` and `Setting.effectiveValue: {$case: 'automaticClusterUpdateWorkspace', ...}`). - **Rationale:** `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) is the longest discriminator in the package and stutters `effective`/`Effective` with its parent field name. -### 67–69. `name` (key) vs `displayName` (human name) — inverted intuition +### 65–67. `name` (key) vs `displayName` (human name) — inverted intuition - **File:line:** `model.ts:398, 411` - **Category:** Generic name + misleading - **Suggestion:** Rename `name` → `key`, then `displayName` → `name` (or `label`). - **Rationale:** Across most data-modelling traditions, `name` is the human-readable name and `key`/`id` is the identifier. This package inverts the convention. -### 70. `Url` vs `URL` vs `Link` +### 68. `Url` vs `URL` vs `Link` - **File:line:** `model.ts:404 (docsLink)`; `utils.ts:69, 71, 100, 103 (url)` - **Category:** Acronym casing inconsistency - **Suggestion:** `docsUrl` for parity with `request.url` already used elsewhere. "Link" is HTML-flavoured; "URL" is the data. -### 71. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name +### 69. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name - **File:line:** `model.ts:107` - **Category:** Field name verb-as-noun, overly verbose @@ -436,14 +424,14 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ## Low severity -### 72–79. Long enum values +### 70–77. Long enum values - **File:line:** `model.ts:13, 31, 39, 51, 67, 75, 56, 57, 85` - **Category:** Long enum value - **Identifiers:** `PREVIEW_PHASE_UNSPECIFIED` (24c), `ACCESS_POLICY_TYPE_UNSPECIFIED` (30c), `DAY_OF_WEEK_UNSPECIFIED` (23c), `WEEK_DAY_FREQUENCY_UNSPECIFIED` (30c), `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` (40c), `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) - **Suggestion:** See #16–21. For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. -### 80–83. Undocumented abbreviations in JSDoc +### 78–81. Undocumented abbreviations in JSDoc - **File:line:** `model.ts:79, 83` - **Category:** Cryptic abbreviation @@ -451,82 +439,82 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Spell out in the JSDoc. - **Rationale:** Users reading the IDE tooltip will see "WS admins to create OBO tokens for all SPs" without expansions. -### 84–86. Reserved-word adjacency: `value`, `type`, `name` +### 82–84. Reserved-word adjacency: `value`, `type`, `name` - **File:line:** `model.ts` passim - **Category:** Reserved-word risk - **Suggestion:** See #25–27. -### 87–88. Acronym casing notes +### 85–86. Acronym casing notes - **File:line:** `model.ts:153, 78` - **Category:** Acronym casing - **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). -### 89. `setting?: UserPreference` doc mismatch +### 87. `setting?: UserPreference` doc mismatch - Already covered in #29; flagged again here for the JSDoc inconsistency (`model.ts:275` field is "setting" but type is "UserPreference"). -### 90. `disable_gov_tag_creation` wire key +### 88. `disable_gov_tag_creation` wire key - **File:line:** `model.ts:624, 959` - **Category:** Cryptic abbreviation (server-controlled) - **Suggestion:** N/A — wire format is fixed. Note for documentation. -### 91. `restrict_tokens_and_job_run_as` enum string value +### 89. `restrict_tokens_and_job_run_as` enum string value - **File:line:** `model.ts:85` - **Category:** Wire value - **Suggestion:** N/A — wire-fixed. -### 92. `IntegerMessage` misleading in JS +### 90. `IntegerMessage` misleading in JS - **File:line:** `model.ts:171-173` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 93. Nested `.value.value` +### 91. Nested `.value.value` - **File:line:** `model.ts:305, 99` - **Category:** Singular naming collision - **Suggestion:** See #25. -### 94–95. Long discriminator strings +### 92–93. Long discriminator strings - **File:line:** `model.ts:327-329, 374` - **Category:** Long string identifier -- **Suggestion:** See #30, #62. +- **Suggestion:** See #30, #60. -### 96–98. Vague field names +### 94–96. Vague field names - **File:line:** `model.ts:103 (enabled), 137 (frequency), 289 (status)` - **Category:** Vague - **Suggestion:** Add domain context: `clusterRestartEnabled`, `restartFrequency`, `workspaceAdminRestrictionStatus`. - **Rationale:** Inside their parent types the meaning is somewhat clear but auto-complete shows only the field name, which is generic. -### 99–100. `patch*` vs `update*`, `*Iter` suffix +### 97. `patch*` vs `update*` -- See #42, #52. +- See #42. -### 101. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" +### 98. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" - **File:line:** `model.ts:160-161` - **Category:** Misleading - **Suggestion:** Use the same vocabulary as the type — "preference" for user-preference endpoints. -### 102. `PreviewPhase` UNSPECIFIED doc — two meanings +### 99. `PreviewPhase` UNSPECIFIED doc — two meanings - **File:line:** `model.ts:12-13` - **Category:** Empty/ambiguous default - **Doc:** "Default value. Indicates the preview phase is unknown or the setting is not a feature preview." - **Suggestion:** Use two separate enum values (one for "unknown phase", one for "not a preview at all") or pick one definition. -### 103. `ClusterAutoRestartMessage_EnablementDetails` — long type +### 100. `ClusterAutoRestartMessage_EnablementDetails` — long type - See #12. -### 104–106. Double-negative / passive booleans on `EnablementDetails` +### 101–103. Double-negative / passive booleans on `EnablementDetails` - **File:line:** `model.ts:121, 123, 125` - **Category:** Misleading / cognitive load @@ -534,34 +522,21 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Phrase positively where possible: `availableForEnterpriseTier?: boolean`, `availableForEntitlement?: boolean`, `forceEnabledByComplianceMode?: boolean`. Double-negatives ("unavailable for non-enterprise") slow comprehension. - **Rationale:** "Unavailable for non-enterprise tier" requires the reader to parse two negatives ("un-" and "non-") to conclude "this is only available for enterprise". Worth one extra second of think-time on every field access. -### 107. Cross-package `Dbfs` casing +### 104. Cross-package `Dbfs` casing - **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) - **Category:** Cross-package acronym casing - **Suggestion:** Note for the cross-package audit, not actionable here. -### 108. `host` — generic class field +### 105. `host` — generic class field - **File:line:** `client.ts:54` - **Category:** Generic - **Suggestion:** `baseUrl` (consistent with `fetch` API conventions). "Host" can mean DNS host, host machine, etc. -### 109. `signal: AbortSignal` field — okay, just noting - -- **File:line:** `client.ts:89, 118, 143, ...` -- **Category:** Reserved-word adjacency (web standard) -- **Suggestion:** Keep — matches Web API. - -### 110. `BETA` member adjacent to `PUBLIC_PREVIEW` +### 106. `BETA` member adjacent to `PUBLIC_PREVIEW` -- See #55. - -### 111. `*Schema` suffix on every zod schema - -- **File:line:** `model.ts:449, 460, 469, 477, 499, 513, 528, 551, 562, 570, 583, 596, 609, 620, 631, 766, 784, 792, 826, 836, 844, 852, 873, 887, 902, 925, 936, 944, 952, 962, 1112, 1120` -- **Category:** Type-suffix tautology -- **Suggestion:** Drop `Schema` — the variables are imported from a file that already imports zod, and the convention `unmarshal*` / `marshal*` already labels them. Currently `unmarshalSettingSchema` reads as "unmarshal-the-setting-schema" rather than the intended "schema for unmarshalling Setting". Renaming to `unmarshalSetting` / `marshalSetting` would be tighter, though it does collide with hypothetical function-style imports. -- **Rationale:** Minor — convention-only concern. Currently consistent within the package. +- See #53. --- @@ -586,11 +561,9 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess 5. **`patch` vs `update` cross-package inconsistency.** The v1 SDKs use `update*`; the v2 SDK uses `patch*`. Same wire verb (PATCH HTTP). The verb mismatch will trip muscle-memory across the surface. -6. **`*Iter` suffix is a Go idiom.** The Go SDK's `*All` helper for AsyncGenerator-equivalent iteration is named with `Iter` here. TS-idiomatic patterns are returning `AsyncIterable` directly or implementing `[Symbol.asyncIterator]`. Three method names carry the suffix. - -7. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. +6. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. -8. **Field-vs-discriminator name divergence on `value`.** A consumer constructing a `Setting` writes: +7. **Field-vs-discriminator name divergence on `value`.** A consumer constructing a `Setting` writes: ``` { name: 'restrict_workspace_admins', value: { $case: 'restrictWorkspaceAdmins', @@ -603,9 +576,9 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ``` — same expressivity, half the typing. -9. **`name` field's role swings.** On `Setting`/`UserPreference`/`SettingsMetadata` it is the *key* of the setting (used in URL paths). On most other Databricks resources `name` is the human-readable label. The inverted convention is a small but real footgun. +8. **`name` field's role swings.** On `Setting`/`UserPreference`/`SettingsMetadata` it is the *key* of the setting (used in URL paths). On most other Databricks resources `name` is the human-readable label. The inverted convention is a small but real footgun. -10. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. +9. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. --- @@ -635,5 +608,5 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess |------|-----------|----------| | `src/v2/index.ts` | 42 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | | `src/v2/model.ts` | 1160 (full) | 100% — 6 enums, 23 interfaces (incl. all nested message types), 15 unmarshal-zod schemas, 15 marshal-zod schemas audited. | -| `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor, 9 client methods (`getPublic*`, `patchPublic*`, `list*`, `list*Iter` x 3 each), and private fields (`host`, `accountId`, `httpClient`, `logger`, `userAgent`) audited. | +| `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor and 9 client methods audited (paginated page-returning and iterator-returning variants both reviewed). Private fields (`host`, `accountId`, `httpClient`, `logger`, `userAgent`) audited. | | `src/v2/utils.ts` | 150 (full) | 100% — `HttpCallOptions`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` audited. Shared utility code; no naming issues unique to this package (the same scaffolding appears in every package). | diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index c816f8de..bfda206c 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -28,14 +28,14 @@ The package name `statementexecution` is reasonable in isolation, but the SDK opening the marketplace sees four packages whose names overlap heavily and has to read every one to pick the right tool. See finding #1. -**Total weird names flagged:** 47 +**Total weird names flagged:** 50 ## Summary | Severity | Count | | --- | --- | | High | 13 | -| Medium | 20 | +| Medium | 27 | | Low | 10 | | Observation | 4 | @@ -150,7 +150,7 @@ to read every one to pick the right tool. See finding #1. - **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. ### 18. `warehouseId` field — `src/v1/model.ts:158` -- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #41. +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #39. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. @@ -261,41 +261,29 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. - **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. -### 36. `unmarshal*Schema` and `marshal*Schema` naming chain — `src/v1/model.ts:525-740` -- **Why weird:** Same pattern as in `queryexecution.md` Finding #19. `unmarshalChunkInfoSchema`, `unmarshalColumnInfoSchema`, etc. — `unmarshal` (Go) + `Schema` (zod helper) — two layers of meta around one operation. Longest is `unmarshalStatementResponseSchema` (32 chars) and `marshalExecuteStatementRequestSchema` (37 chars). -- **Category:** 5 (cryptic), 7 (verbose), 8 (redundant suffix), 14 (Go-style `marshal`). -- **Suggested name:** `decodeChunkInfo`, `decodeColumnInfo`, etc. (drop `Schema`; rename to `decode/encode`). Generator-wide. -- **Rationale:** Recurring SDK pattern; same fix as other audits. - -### 37. `marshalRequest` and `parseResponse` in utils — `src/v1/utils.ts:119, 113` -- **Why weird:** Verb pair `marshal` (Go) + `parse` (JS) — asymmetric, identical to `queryexecution.md` Finding #20. The two functions are generic JSON encode/decode but named differently and asymmetrically. -- **Category:** 1, 14, 17. -- **Suggested name:** `encodeJson` / `decodeJson`. -- **Rationale:** Generator-wide. - -### 38. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` +### 36. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` - **Why weird:** Two `execute*` functions in the same file, one wraps retry/rate-limit policy and one does the actual HTTP. Same as `queryexecution.md` Finding #21. - **Category:** 1, 12, 17. - **Suggested name:** `runWithPolicies` + `sendHttpRequest`. - **Rationale:** Generator-wide. -### 39. `buildHttpRequest` helper — `src/v1/utils.ts:96` +### 37. `buildHttpRequest` helper — `src/v1/utils.ts:96` - **Why weird:** "Build" implies builder pattern; this is a 16-line object literal. Same as `queryexecution.md` Finding #22. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest` or inline. -### 40. `readAll` stream-drain helper — `src/v1/utils.ts:40` +### 38. `readAll` stream-drain helper — `src/v1/utils.ts:40` - **Why weird:** Generic verb. Same as `queryexecution.md` Finding #23. - **Category:** 1, 5. - **Suggested name:** `drainStream`. -### 41. Every field on every request type is optional — `src/v1/model.ts` (every interface) +### 39. Every field on every request type is optional — `src/v1/model.ts` (every interface) - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). - **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. -### 42. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` +### 40. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` - **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #17) suggests this is the wrong abstraction. - **Category:** 6 (misleading — type is overloaded), 12 (duplicate concept — two operations). - **Suggested name:** Keep `StatementResponse` but document that it's polymorphic. Or split into `StatementSubmissionResponse` + `StatementStateResponse`. @@ -303,54 +291,54 @@ to read every one to pick the right tool. See finding #1. ## Low severity -### 43. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +### 41. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` - **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. - **Category:** 17 (acceptable asymmetry). - **Suggested name:** Keep. -### 44. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:108, 111, 116` +### 42. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:108, 111, 116` - **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. - **Category:** 12 (duplicate concept — three types carry the same fields). - **Suggested name:** Extract `ChunkMetrics` shared interface. - **Rationale:** Trio-replicated types are a tell. -### 45. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` +### 43. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` - **Why weird:** `typeText` is "the full SQL type specification" (e.g. `DECIMAL(10,2)`). `typeName` is the base type name (`DECIMAL`). The pair is intentional but the names don't make the relationship obvious — `typeText` and `typeName` sound interchangeable. - **Category:** 17 (asymmetric pair — `Text` vs `Name`), 1 (vague — `Text` of what?). - **Suggested name:** `typeSql` (the wire SQL text) + `typeBase` (the base type) — but the wire is canonical, so keep names. Document the relationship. -### 46. `position` field on `ColumnInfo` — `src/v1/model.ts:139` +### 44. `position` field on `ColumnInfo` — `src/v1/model.ts:139` - **Why weird:** Top-level field literally `position` with JSDoc "The ordinal position of the column (starting at position 0)." `position` is generic. `ordinalPosition` (matches the JSDoc) or `columnIndex` would be more precise. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `ordinalPosition` or `index`. -### 47. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` +### 45. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` - **Why weird:** A string field whose JSDoc says "Indicates the date-time that the given external link will expire and becomes invalid". Two issues: the name `expiration` is ambiguous (an expiry timestamp? a TTL?), and the type is `string` (presumably ISO8601 — the JSDoc doesn't say). A reader can't tell from the type or name how to interpret the value. - **Category:** 1 (vague), 6 (misleading — could be TTL). - **Suggested name:** `expiresAt` (ISO8601 timestamp) — matches modern JS/TS convention. -### 48. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +### 46. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` - **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. - **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). - **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 49. `Schema` type is overloaded with zod `*Schema` helpers — `src/v1/model.ts:468` -- **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (zod schemas, validation schemas, database schemas). Inside this file zod schemas are also named `*Schema` (unmarshal/marshal helpers). So `Schema` (type) coexists with `unmarshalSchemaSchema` (helper) — and yes, that line literally exists at `model.ts:634`: `export const unmarshalSchemaSchema: z.ZodType = ...`. -- **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 12 (duplicate concept — zod `*Schema` everywhere). -- **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from validation schemas. Then `unmarshalResultSchemaSchema` becomes only mildly stuttery but at least no longer self-referential. +### 47. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +- **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. +- **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). +- **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. -### 50. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` +### 48. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` - **Why weird:** Three single-word fields on a single type, all `string | undefined`. The JSDoc explains: name is the marker name; value is the substituted text; type is the SQL type. The names work fine in this context but are maximally generic — `name`, `value`, `type` could mean anything. The `type` field collides with the TS keyword visually (though `type` isn't actually reserved in object-position). - **Category:** 1 (vague), 10 (reserved-word collision — `type` is contextually meaningful), 15 (generic names). - **Suggested name:** `parameterName`, `parameterValue`, `sqlType` — but local names are fine inside a clear-context type. Flagged for completeness. -### 51. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` -- **Why weird:** Generic key-value pair. Same as #50 but for tags. `tagKey` + `tagValue` are common alternatives. +### 49. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` +- **Why weird:** Generic key-value pair. Same as #48 but for tags. `tagKey` + `tagValue` are common alternatives. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** Acceptable in context. -### 52. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 50. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** Generic name. Same as `queryexecution.md` Finding #25. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -407,7 +395,7 @@ the cross-package vocabulary alignment (#17, #26). ## Themes -1. **Proto/Go leakage.** `StatementStatus_State`, `ExternalLink_HttpHeadersEntry`, `*_UNSPECIFIED` sentinels, `marshal/unmarshal` verb pair, `ServiceErrorCode` mimicking `google.rpc.Code`. Every leakage point requires an ESLint disable or a special-casing in zod. Generator-wide. -2. **Word stutter.** `ServiceError.errorCode`, `ResultData.dataArray`, `*ResultData` vs `*StatementResult`, `executeStatement` / `getStatementResult` / `statement` field, `Schema` vs `unmarshalSchemaSchema`. The wire shape doesn't help here; the TS surface could compress. +1. **Proto/Go leakage.** `StatementStatus_State`, `ExternalLink_HttpHeadersEntry`, `*_UNSPECIFIED` sentinels, `ServiceErrorCode` mimicking `google.rpc.Code`. Every leakage point requires an ESLint disable or a special-casing in zod. Generator-wide. +2. **Word stutter.** `ServiceError.errorCode`, `ResultData.dataArray`, `*ResultData` vs `*StatementResult`, `executeStatement` / `getStatementResult` / `statement` field. The wire shape doesn't help here; the TS surface could compress. 3. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). 4. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md index e008b163..d0e86896 100644 --- a/.agent/naming-audit/supervisoragents.md +++ b/.agent/naming-audit/supervisoragents.md @@ -13,15 +13,15 @@ discriminated union over 14 tool kinds), and `Example` (child of Every list endpoint paginates via `pageSize`/`pageToken`. No state enums exist in this package; the entire surface is data plus references to other Databricks resources. -**Total weird names flagged:** 49 +**Total weird names flagged:** 43 ## Summary | Severity | Count | | --- | --- | | High | 13 | -| Medium | 18 | -| Low | 11 | -| Observation | 7 | +| Medium | 15 | +| Low | 9 | +| Observation | 6 | ## High severity @@ -44,7 +44,7 @@ Databricks resources. - **Rationale:** Stringly-typed enums in TypeScript are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals). The duplicate declaration in two casings is a generator artifact from the proto definition and a tax on every consumer. ### 4. `Tool.toolType` casing disagrees with every other discriminator value on the wire — `src/v1/model.ts:259` -- **Why weird:** The 14 enumerated values inside the doc string are snake_case: `"genie_space"`, `"knowledge_assistant"`, `"lakeview_dashboard"`, `"serving_endpoint"`, `"uc_function"`, `"uc_connection"`, `"uc_table"`, `"vector_search_index"`, `"supervisor_agent"`, `"web_search"` (singletons `"app"`, `"volume"`, `"catalog"`, `"schema"` work in both). But the TypeScript `spec.$case` field uses camelCase variants of the same set: `'genieSpace'`, `'knowledgeAssistant'`, etc. The marshal/unmarshal pair around lines 765-865 keeps `toolType` as a *string* in both directions, so the wire format for `toolType` is snake_case — but the consumer must know to write `toolType: 'genie_space'` while paying attention to camelCase `spec.$case`. A TypeScript-only consumer who never reads JSDoc will think the values are camelCase to match `$case` and get HTTP 400 on the first request. +- **Why weird:** The 14 enumerated values inside the doc string are snake_case: `"genie_space"`, `"knowledge_assistant"`, `"lakeview_dashboard"`, `"serving_endpoint"`, `"uc_function"`, `"uc_connection"`, `"uc_table"`, `"vector_search_index"`, `"supervisor_agent"`, `"web_search"` (singletons `"app"`, `"volume"`, `"catalog"`, `"schema"` work in both). But the TypeScript `spec.$case` field uses camelCase variants of the same set: `'genieSpace'`, `'knowledgeAssistant'`, etc. The wire format for `toolType` is snake_case — but the consumer must know to write `toolType: 'genie_space'` while paying attention to camelCase `spec.$case`. A TypeScript-only consumer who never reads JSDoc will think the values are camelCase to match `$case` and get HTTP 400 on the first request. - **Category:** 17 (casing inconsistency within the same struct), 4 (snake_case in a string-literal value, even though the value is on the wire). - **Suggested name:** If `toolType` survives (see #3), document inline that values are snake_case wire-side, or normalize to camelCase to match `spec.$case`. - **Rationale:** The mismatch is exactly what causes the most painful bugs in generated SDKs — the type checker says it is fine, the runtime fails. A naming audit must call this out even though it is a *value* mismatch rather than an *identifier* mismatch. @@ -189,28 +189,7 @@ Databricks resources. - **Suggested name:** Either remove `tool.toolId` from the body shape (TypeScript can enforce this via a discriminated `Omit` type for create), or document the precedence rule on the JSDoc. - **Rationale:** Generated request types with duplicate fields are a well-known footgun. -### 28. `unmarshal*Schema` and `marshal*Schema` `Schema` suffix — `src/v1/model.ts:378,386,394,408,416,427,435,446,459,469,477,485,514,523,612,620,628,636,646,654,656,664,672,686,694,704,712,720,728,757,765,867,875,883,891,901,909` -- **Why weird:** All marshal/unmarshal Zod schemas suffix `*Schema`. Same pattern documented in `knowledgeassistants.md` #28: every export reads `unmarshalXSchema`, which is 20+ characters of pure suffix. SDK-wide convention; flagging for cross-cutting review rather than local fix. Total of ~37 marshal/unmarshal sites in this file. -- **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `unmarshalSupervisorAgent` (Zod schemas are obviously schemas; the suffix is type-system redundancy). Flagged for SDK-wide convention review. -- **Rationale:** Cross-package convention; no local fix. - -### 29. `*FieldMaskSchema` private constants and `*FieldMask` public builder — `src/v1/model.ts:911-1042` -- **Why weird:** Two parallel naming families: - - Private (file-scope) constants: `appFieldMaskSchema`, `catalogFieldMaskSchema`, `exampleFieldMaskSchema`, `genieSpaceFieldMaskSchema`, `knowledgeAssistantFieldMaskSchema`, `lakeviewDashboardFieldMaskSchema`, `schemaFieldMaskSchema`, `servingEndpointFieldMaskSchema`, `supervisorAgentFieldMaskSchema`, `supervisorAgentToolFieldMaskSchema`, `toolFieldMaskSchema`, `ucConnectionFieldMaskSchema`, `ucFunctionFieldMaskSchema`, `ucTableFieldMaskSchema`, `vectorSearchIndexFieldMaskSchema`, `volumeFieldMaskSchema`, `webSearchFieldMaskSchema`. - - Public builders: `exampleFieldMask`, `supervisorAgentFieldMask`, `toolFieldMask`. - Only three types get a builder (`Example`, `SupervisorAgent`, `Tool`) — the others are private. But the convention puts `Schema` as the suffix on the constants and bare on the builder, which is the opposite of the `unmarshalXSchema` convention. Also: every field-mask constant exists *whether or not* the type is exposed via a builder — so for tool spec variants the field-mask schema is dead weight. -- **Category:** 7 (verbose), 8 (suffix), 17. -- **Suggested name:** Drop the `Schema` suffix from the private constants (`appFieldMask`, `catalogFieldMask`, etc., with the builders renamed to `buildAppFieldMask`, `buildToolFieldMask`). -- **Rationale:** Cross-package convention; no local fix. - -### 30. `listExamplesIter`/`listSupervisorAgentsIter`/`listToolsIter` — `Iter` suffix Go-style — `src/v1/client.ts:342,396,447` -- **Why weird:** The `Iter` suffix on async iterators is a direct port from Go's `*Iter` convention, same as `knowledgeassistants.md` #29 and applies SDK-wide. The audit prompt's rule 14 (Go/Java-style names) calls this out. -- **Category:** 14 (Go-style name), 8 (redundant suffix — return type already says it's an iterator). -- **Suggested name:** Drop the suffix and make auto-paging the default (`listExamples` returns an `AsyncIterable`, and a separate `listExamplesPage` returns one page). Or swap the names: `listExamples` (current paged) becomes `listExamplesPage`, and `listExamplesIter` becomes `listExamples`. -- **Rationale:** Modern TypeScript convention is that the default form is auto-paging; the suffix is a Go/Java carryover. - -### 31. `Client` class name — bare, no scoping — `src/v1/client.ts:61` +### 28. `Client` class name — bare, no scoping — `src/v1/client.ts:61` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-supervisoragents/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as SAClient} from '@databricks/sdk-supervisoragents/v1'`. Same SDK-wide issue flagged in `knowledgeassistants.md` #30. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `SupervisorAgentsClient` (matches the Go SDK's `WorkspaceClient.SupervisorAgents` and AWS SDK's `S3Client`, `IAMClient` pattern). @@ -218,19 +197,19 @@ Databricks resources. ## Low severity -### 32. `Volume`/`UcFunction`/`UcConnection`/`UcTable` — `Uc` prefix on some, bare on others — `src/v1/model.ts:304,308,318,364` +### 29. `Volume`/`UcFunction`/`UcConnection`/`UcTable` — `Uc` prefix on some, bare on others — `src/v1/model.ts:304,308,318,364` - **Why weird:** Of the variant types, four are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`, `UcTable`. The `Uc` prefix is applied to three but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). - **Category:** 3 (acronym casing — `Uc` vs `UC`), 17 (inconsistent prefix application — `Volume` should be `UcVolume`). - **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection`, `UcTable` (with the acronym-casing question decided once SDK-wide). - **Rationale:** Consistency wins; the audit prompt rule 3 (acronym casing) and rule 17 (consistent action verbs / family naming) both flag this. -### 33. `LakeviewDashboard` — product name leaks into type name — `src/v1/model.ts:135` +### 30. `LakeviewDashboard` — product name leaks into type name — `src/v1/model.ts:135` - **Why weird:** "Lakeview" is the marketing name for Databricks SQL dashboards (https://docs.databricks.com/en/dashboards/index.html). The type name carries the product name. If the product is renamed (as has happened — "Lakeview" has been deprecated in some Databricks branding in favor of "Dashboards"), the SDK will be stuck with the old name. Cross-package: the dashboards SDK at `packages/dashboards/` uses `LakeviewDashboard` too — so the SDK is consistent, but the question is whether the canonical name should propagate. - **Category:** Observation / 6 (potentially misleading if product is rebranded). - **Suggested name:** Keep `LakeviewDashboard` (the wire name is fixed) but document the marketing-name origin. - **Rationale:** Naming audits should flag product-name leakage even if there's no fix. -### 34. `Catalog`, `Schema`, `UcTable` fields all named `name` but doc differently — `src/v1/model.ts:21,212,321` +### 31. `Catalog`, `Schema`, `UcTable` fields all named `name` but doc differently — `src/v1/model.ts:21,212,321` - **Why weird:** Three variant types with a single `name` field carrying three subtly different format claims: - `Catalog.name`: "Bare UC catalog name this tool is authorized to search (no `.`)." — one component. - `Schema.name`: "Full UC schema name (catalog.schema) this tool is authorized to search." — two components. @@ -240,82 +219,68 @@ Databricks resources. - **Suggested name:** Differentiate: `Catalog.catalogName` (one part), `Schema.schemaFullName` (two parts), `UcTable.tableFullName` (three parts). Or use AIP-style `fullName` on each but document the cardinality explicitly. - **Rationale:** Three types with the same field name representing different formats is exactly the kind of inconsistency that bites at code-review time. -### 35. `VectorSearchIndex.columns` semantic ambiguity — `src/v1/model.ts:357-361` +### 32. `VectorSearchIndex.columns` semantic ambiguity — `src/v1/model.ts:357-361` - **Why weird:** Doc reads "Optional columns to return from the index. If unset, discovered from index schema at query time." So `columns` is a list of column names to *project* in the response — but the field name does not communicate "to return" vs "to filter on" vs "to embed." A consumer scanning the type sees `columns?: string[]` and reasonably wonders whether these are the *output* columns or the *input* columns to vectorize. The doc is the only disambiguator. - **Category:** 1 (vague), 6 (misleading — name does not encode return-vs-filter direction). - **Suggested name:** `returnedColumns` or `outputColumns` (or `projection`, a SQL term). - **Rationale:** The doc gives the contract; the field name should too. -### 36. `parseResponse` / `marshalRequest` asymmetric verbs — `src/v1/utils.ts:113,119` -- **Why weird:** Same as `customllms.md` #22 and `knowledgeassistants.md` #33: `parseResponse` and `marshalRequest` use two different verbs for inverse operations. The model file uses `unmarshal*Schema` / `marshal*Schema` consistently, but `utils.ts` breaks the pattern with `parse`. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for symmetry. -- **Rationale:** Pair-wise consistency aids reading. - -### 37. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +### 33. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21 and `knowledgeassistants.md` #34. Each generated package carries the same pair. - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than one infix. -### 38. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +### 34. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` - **Why weird:** Same as `customllms.md` #23 and `knowledgeassistants.md` #35: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in scope simultaneously. Three things named `Options`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams`. - **Rationale:** Distinguish internal context bags from user-facing options. -### 39. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 35. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `customllms.md` #28 and `knowledgeassistants.md` #36: exported but not used by `client.ts`. Generator-mechanical surface area. - **Category:** Observation / (unused export). - **Suggested name:** Either remove the export or document why it ships per-package. - **Rationale:** Generated artifact; flag for cross-package cleanup. -### 40. `readAll` helper generic name — `src/v1/utils.ts:40` +### 36. `readAll` helper generic name — `src/v1/utils.ts:40` - **Why weird:** Same as `customllms.md` #29 and `knowledgeassistants.md` #37: helper reads an entire response body stream; name is generic. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 41. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` +### 37. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` - **Why weird:** Same as `customllms.md` #24 and `knowledgeassistants.md` #38: `Segment` is a generic CS term. - **Category:** 1 (vague). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** SDK-wide consistency review. -### 42. `resp` local variable in every method — `src/v1/client.ts:93,122,154,242,267,289,323,374,428,477,521,562` +## Observations + +### 38. `resp` local variable in every method — `src/v1/client.ts:93,122,154,242,267,289,323,374,428,477,521,562` - **Why weird:** Same as `customllms.md` #33 and `knowledgeassistants.md` #39: `resp` is the response. 12 methods repeat the same pattern. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. - **Rationale:** Refactor opportunity surfaced by audit. -## Observations - -### 43. `pageReq` local in iterator methods — `src/v1/client.ts:346,400,451` +### 39. `pageReq` local in iterator methods — `src/v1/client.ts:346,400,451` - **Why weird:** Same as `knowledgeassistants.md` #40: three async generator methods declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. - **Category:** 5 (abbreviation). - **Suggested name:** `pageRequest` or `nextPageReq`. -### 44. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:977-1015` -- **Why weird:** `toolFieldMaskSchema` carries top-level entries for each variant of the `spec` union — `app`, `catalog`, `genieSpace`, `knowledgeAssistant`, `lakeviewDashboard`, `schema`, `servingEndpoint`, `supervisorAgent`, `ucConnection`, `ucFunction`, `ucTable`, `vectorSearchIndex`, `volume`, `webSearch`. The field-mask schema flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. -- **Category:** 17 (inconsistency between TS shape and field-mask schema). +### 40. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:977-1015` +- **Why weird:** The field-mask carries top-level entries for each variant of the `spec` union — `app`, `catalog`, `genieSpace`, `knowledgeAssistant`, `lakeviewDashboard`, `schema`, `servingEndpoint`, `supervisorAgent`, `ucConnection`, `ucFunction`, `ucTable`, `vectorSearchIndex`, `volume`, `webSearch`. The field-mask flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. +- **Category:** 17 (inconsistency between TS shape and field-mask). - **Suggested name:** No rename; document on the JSDoc. -### 45. The 14 tool kinds + 1 nested = effectively 15 kinds — `src/v1/model.ts:262-297` +### 41. The 14 tool kinds + 1 nested = effectively 15 kinds — `src/v1/model.ts:262-297` - **Why weird:** The doc on `Tool.toolType` (model.ts:259) lists 14 kinds, but the discriminated union on `Tool.spec` (model.ts:262-297) also has 14 cases. Counting carefully: `genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `lakeviewDashboard`, `servingEndpoint`, `ucTable`, `vectorSearchIndex`, `ucConnection`, `catalog`, `schema`, `supervisorAgent`, `webSearch` — that is 14, and matches the doc. So the count is correct; flagged here as a *positive* observation. -### 46. `unmarshalToolSchema` deep ternary chain — `src/v1/model.ts:557-607` -- **Why weird:** The unmarshal logic for `Tool.spec` is a 50-line nested ternary picking which variant case applies. Not a naming issue; flagging because the readability of generated code at this depth is hostile. -- **Category:** Observation. - -### 47. `marshalToolSchema` discriminated union explicit `$case` literals — `src/v1/model.ts:765-828` -- **Why weird:** The marshal-side Zod schema enumerates each `$case` as a string literal in `z.discriminatedUnion('$case', [...])`. The 14 explicit `z.literal('genieSpace')` etc. lines duplicate the data already in the unmarshal-side ternary chain. Not a naming bug; flagging for codegen review. -- **Category:** Observation. - -### 48. Action verbs in `Client` are consistent — `src/v1/client.ts` +### 42. Action verbs in `Client` are consistent — `src/v1/client.ts` - **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. - **Category:** 17 (reversed — consistency note). -### 49. Method-name verb conventions match resource targets — `src/v1/client.ts:87,113,142,180,199,218,237,262,287,309,360,414,465,506,550` +### 43. Method-name verb conventions match resource targets — `src/v1/client.ts:87,113,142,180,199,218,237,262,287,309,360,414,465,506,550` - **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. - **Category:** 17 (positive observation). diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index b5fa27a3..a5d94ebe 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -3,14 +3,14 @@ **Path:** `packages/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 27 +**Total weird names flagged:** 21 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 9 | -| Low | 5 | +| Medium | 6 | +| Low | 2 | | Observation | 4 | ## High severity @@ -83,43 +83,25 @@ - **Suggested name:** Same as #9 — rename one or both and unify optionality where possible. - **Rationale:** Symmetry across request/response pairs improves readability; identical names with diverging contracts do not. -### 12. `marshalEnableSystemSchemaSchema` constant — `src/v1/model.ts:95` -- **Why weird:** Double `Schema` suffix: it's a zod **Schema** that marshals the `EnableSystemSchema` request. Reads as `marshal-EnableSystemSchema-Schema`. Same problem with `unmarshalSystemSchemaInfoSchema` (model.ts:85), `unmarshalListSystemSchemas_ResponseSchema` (model.ts:72), etc. — every zod schema constant carries the word `Schema` *and* sits in a file already named for `SystemSchema`, leading to three nested meanings of "schema": the domain entity, the request type, and the zod validator. -- **Category:** 17 (verb/word reuse), 20 (type-suffix tautology — the zod object is already a schema, no need to spell it). -- **Suggested name:** Drop the trailing `Schema` and adopt a clearer suffix: `marshalEnableSystemSchemaCodec`, or move them to a `codecs.ts` namespace that supplies the `Schema` semantics by location. -- **Rationale:** The "schema" overload is unique to this package — most other generated packages have a single `Schema` meaning (zod). Here all three collide. - -### 13. `marshalEnableSystemSchemaSchema: z.ZodType` lacks a type parameter — `src/v1/model.ts:95` -- **Why weird:** Declared as `z.ZodType` (no generic argument), unlike the sibling `unmarshalSystemSchemaInfoSchema: z.ZodType` (model.ts:85). The marshalled output is therefore typed as `unknown` and the `parse` call on it loses static guarantees. -- **Category:** 17 (inconsistency with sibling exports), 6 (misleading — looks just like the unmarshal helpers but is weaker). -- **Suggested name:** Either rename to clarify the asymmetry, or fix the signature to `z.ZodType` (or to the wire-shape type). Not strictly a naming finding, but the name implies parity that isn't there. -- **Rationale:** Mechanical fallout from the marshal/unmarshal verb split (#21). - -### 14. `listSystemSchemas` vs `listSystemSchemasIter` — `src/v1/client.ts:139,172` -- **Why weird:** `Iter` is a Go-SDK loanword (`...Iterator`). TS convention is to name an iterator after what it yields or to use a verb like `iterate`. The current pair names a page-fetching method and a streaming method with a three-letter abbreviation tacked on, making the difference at the call site (`client.listSystemSchemas` vs `client.listSystemSchemasIter`) inscrutable. -- **Category:** 5 (cryptic abbreviation), 14 (Go-style naming). -- **Suggested name:** `iterSystemSchemas` (verb-first), `listAllSystemSchemas`, or split into `listSystemSchemasPage` (current `list...`) and `listSystemSchemas` (current `list...Iter`). -- **Rationale:** Async generators are common enough in TS that the language has its own conventions (`for await (const x of obj.foos())`); naming the generator with the visible "stream" verb communicates better than `Iter`. - -### 15. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` +### 12. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate intent. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; flagged for cross-SDK consistency since the same constant appears in every generated client. -### 16. `Client` — `src/v1/client.ts:42` +### 13. `Client` — `src/v1/client.ts:42` - **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `SystemSchemasClient`. - **Rationale:** Forces consumers to alias on import (`import {Client as SystemSchemasClient}`) if they ever combine clients. Every generated package has this issue; flagged for consistency. -### 17. `ListSystemSchemas.maxResults` doc semantics — `src/v1/model.ts:31-36` +### 14. `ListSystemSchemas.maxResults` doc semantics — `src/v1/model.ts:31-36` - **Why weird:** Field is named `maxResults` but the doc describes three semantically distinct modes (0 = server default, >0 = bounded, <0 = error) and one quirky default (not set = "all", "not recommended"). The name "maxResults" implies an upper bound, not a tri-state control. Same pattern in every other List request, but here the doc highlights how overloaded the name is. - **Category:** 6 (misleading — name suggests a single integer cap), 1 (vague). - **Suggested name:** `pageSize` (matching most modern paginated APIs) and let the value 0 mean "server default". Drop the negative-error branch entirely. - **Rationale:** Worth raising upstream; the JS SDK's name should describe what consumers do, not the wire's quirks. -### 18. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:182` +### 15. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:182` - **Why weird:** `listSystemSchemasIter` (client.ts:182) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). - **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. @@ -127,31 +109,13 @@ ## Low severity -### 19. `unmarshalDisableSystemSchema_ResponseSchema` — `src/v1/model.ts:64` -- **Why weird:** Schema constant carries the underscore from the type plus an `eslint-disable`. -- **Category:** 4 (underscore identifier). -- **Suggested name:** Falls out once `DisableSystemSchema_Response` is renamed (#3): `unmarshalDisableSystemSchemaResponseSchema` — though `Schema` triple-tautology (#12) still applies. -- **Rationale:** Mechanical cascade. - -### 20. `unmarshalEnableSystemSchema_ResponseSchema` — `src/v1/model.ts:68` -- **Why weird:** Same as #19. -- **Category:** 4. -- **Suggested name:** Cascade from #4. -- **Rationale:** Same. - -### 21. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (effectively unmarshal) is the inverse of `marshalRequest`. Two different verbs (`parse` vs `marshal`) for opposite operations. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. -- **Rationale:** Pair-wise consistency aids reading. Same finding shows up in every generated `utils.ts`. - -### 22. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 16. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ by a single `Http` infix, handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). - **Rationale:** Same pattern across the SDK; collected for the cross-package sweep. -### 23. `HttpCallOptions` — `src/v1/utils.ts:15` +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** The word `Options` is reused across the SDK for many unrelated things (`ClientOptions`, `CallOptions`, etc.); within this file `Options` is also imported from `@databricks/sdk-core/api` (line 3). - **Category:** 1 (vague suffix), 17 (collision with imported `Options`). - **Suggested name:** `HttpCallContext` — it's an internal bag of args, not user-tunable options. @@ -159,18 +123,18 @@ ## Observations -### 24. `flattenQueryParams` — `src/v1/utils.ts:123` +### 18. `flattenQueryParams` — `src/v1/utils.ts:123` Function is exported but has no caller within this package — `client.ts` does its own simple query-param assembly (`client.ts:144-150`). Dead surface area imported from the generator's shared template. - **Category:** Observation / 11 (unused public helper). - Recommend either removing the export or documenting why it ships per-package. -### 25. `readAll` — `src/v1/utils.ts:40` +### 19. `readAll` — `src/v1/utils.ts:40` Reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Internal helper, low impact. -### 26. Action-verb consistency in `Client` -Methods are `disable`, `enable`, `list`, `listSystemSchemasIter` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. +### 20. Action-verb consistency in `Client` +Methods are `disable`, `enable`, `list` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. -### 27. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod +### 21. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), a type suffix (`...Schema_Response`), the package name (`systemschemas`), and a library term (zod's `Schema`). Five overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. - **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index 47a51326..7357ffe6 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -180,9 +180,9 @@ | --------------------- | ----- | | High | 16 | | Medium | 26 | -| Low / SDK-wide note | 14 | +| Low / SDK-wide note | 11 | | Pass / acceptable | 10 | -| **Total findings** | **66** | +| **Total findings** | **63** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -738,16 +738,6 @@ type names also clash with the *response* concept — e.g. `CreateTable` is sometimes interpreted as "an action: create the table" and sometimes as "the type representing a table to be created." -The same problem extends to the marshal/unmarshal schema names: -- `marshalCreateTableSchema` (model.ts:1496) — schema for the - request-input shape. -- `unmarshalTableInfoSchema` (model.ts:1325) — schema for the response. - -There is **no** `unmarshalCreateTableSchema` because the response of -`createTable` is `TableInfo`. The asymmetry between marshal (input) and -unmarshal (output) is the right structure but the naming makes it hard to -spot. - **Suggested:** rename to `CreateTableRequest`, `GetTableRequest`, etc., or keep the current convention and document that "verb-noun" types are always input. Pick one. **Flag SDK-wide.** @@ -1369,31 +1359,13 @@ Same `{verb}{Resource}` pattern. **Pass.** --- -### 55. `Client.listTableSummariesIter` / `listTablesIter` `Iter` suffix — category 14 (Go/Java-style names) - -**Symbols:** `Client.listTableSummariesIter` (client.ts:357), -`Client.listTablesIter` (client.ts:444). - -**Issue:** The `Iter` suffix is a Go-ism (Go's `…All()` / `…Iter()` -convention for paginated lists). In TS, the conventional name is -`listTablesAsyncIterator()` or simply `listTables()` returning an -`AsyncIterable`. The `Iter` suffix is also borderline cryptic. - -**Suggested:** `listAllTables` or simply have the non-iter version return -an `AsyncIterable`. The current dual API -(`listTables` + `listTablesIter`) is a Go-port artefact. - -**Flag for SDK-wide cleanup.** - ---- - -### 56. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* +### 55. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* Standard. **Pass.** --- -### 57. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) +### 56. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:55). @@ -1407,7 +1379,7 @@ SDK-wide cleanup.** --- -### 58. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 57. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` (utils.ts:15). @@ -1421,7 +1393,7 @@ SDK-wide cleanup** — generated boilerplate. --- -### 59. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 58. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). @@ -1433,39 +1405,7 @@ layers. The names imply a hierarchical relationship that does not exist. --- -### 60. `parseResponse` / `marshalRequest` verb inconsistency — category 17 (Inconsistent action verbs) and category 14 (Go/Java-style names) - -**Symbols:** `parseResponse` (utils.ts:113), `marshalRequest` (utils.ts:119). - -**Issue:** Two symmetric operations with verbs from two vocabularies — -"parse" is TS/JS, "marshal" is Go. Internally consistent verb-pair would -be `parseResponse` / `serializeRequest` or `unmarshalResponse` / -`marshalRequest`. - -**Suggested:** `serializeRequest` and `parseResponse` (TS-native). **Flag -for SDK-wide consistency.** - ---- - -### 61. `unmarshal*` / `marshal*` Go vocabulary — category 14 (Go/Java-style names) - -**Symbols:** All 50+ Zod schemas (e.g. `unmarshalColumnInfoSchema`, -`marshalCreateTableSchema`). - -**Issue:** "Marshal" / "unmarshal" is Go-ism vocabulary. TS/JS use -"serialize" / "deserialize" or "parse" / "stringify". The whole SDK uses -the Go convention. - -**Suggested:** `serialize*Schema` / `parse*Schema` (TS-native). **Flag for -SDK-wide cleanup, not this package alone.** - -The `*Schema` suffix is also redundant — the value's type is -`z.ZodType<…>` and there are no non-schema cousins. `parseColumnInfo` / -`serializeColumnInfo` would suffice. **Pass with note.** - ---- - -### 62. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* +### 59. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* Verb-prefixed. Naming is fine. `flattenQueryParams` is used by the multi-query-param list methods (client.ts:357, 444). @@ -1478,7 +1418,7 @@ file.) --- -### 63. `index.ts` re-exports underscored type names — category 4 (Underscores in TS identifiers) +### 60. `index.ts` re-exports underscored type names — category 4 (Underscores in TS identifiers) **Symbols:** index.ts re-exports include `CreateTable_PropertiesEntry`, `DeleteTable_Response`, `DeleteTableConstraint_Response`, @@ -1497,7 +1437,7 @@ Style Guide § 5.3 and the project's lint rule on identifiers. --- -### 64. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* +### 61. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, `TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide @@ -1505,7 +1445,7 @@ pattern. **Pass.** --- -### 65. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`, `'volume'`, `'secret'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* +### 62. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`, `'volume'`, `'secret'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `Dependency.value.$case` literals (model.ts:455–467). @@ -1526,7 +1466,7 @@ their $case literals. --- -### 66. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* +### 63. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* **Symbol:** `parseResponse` (utils.ts:113) does `JSON.parse(text)` unconditionally. The name implies it can handle any response shape; in @@ -1629,16 +1569,16 @@ documentation pass needed.** | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics) | 16 | #1, #2, #3, #10, #11, #20, #23, #24, #26, #28, #35, #36, #43, #49, #57, #63 | +| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics) | 16 | #1, #2, #3, #10, #11, #20, #23, #24, #26, #28, #35, #36, #43, #49, #56, #60 | | **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 26 | #4, #5, #6, #7, #9, #13, #14, #15, #16, #18, #19, #21, #22, #25, #27, #30, #31, #33, #34, #37, #39, #40, #41, #45, #48, #51 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 14 | #8, #12, #29, #42, #44, #46, #50, #55, #58, #59, #60, #61, #65, #66 | -| **Pass / acceptable** | 10 | #17, #32, #38, #47, #52, #53, #54, #56, #62, #64 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 11 | #8, #12, #29, #42, #44, #46, #50, #57, #58, #62, #63 | +| **Pass / acceptable** | 10 | #17, #32, #38, #47, #52, #53, #54, #55, #59, #61 | --- ## Top fixes (highest local return) -1. **#2 / #63** — drop the underscored `*_PropertiesEntry` / `*_Response` +1. **#2 / #60** — drop the underscored `*_PropertiesEntry` / `*_Response` type names from the public surface. Removes lint suppressions and eliminates the proto-style naming. 2. **#3** — fix `DeltaRuntimePropertiesKvpairs` (field) / diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 635a433f..85ffb586 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -3,15 +3,15 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. -**Total weird names flagged:** 35 +**Total weird names flagged:** 27 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 13 | -| Low | 6 | -| Observation | 5 | +| High | 10 | +| Medium | 10 | +| Low | 4 | +| Observation | 3 | ## High severity @@ -54,7 +54,7 @@ ### 7. `createTagAssignment` / `deleteTagAssignment` / `getTagAssignment` / `listTagAssignments` / `updateTagAssignment` method names — `src/v1/client.ts:67,93,112,137,188` - **Why weird:** Every method repeats the package's subject in the identifier. `client.createTagAssignment(...)` on a `Client` whose only job is tag assignments reads as "package.subject.create.subject". Sister package does the same with `createEntityTagAssignment`. - **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `TagAssignment` on every method when the client only manages `TagAssignment`). -- **Suggested name:** `create`, `delete`, `get`, `list`, `update`, `listIter` (drop the noun). Or `createAssignment` / `deleteAssignment` if the noun is desired. +- **Suggested name:** `create`, `delete`, `get`, `list`, `update` (drop the noun). Or `createAssignment` / `deleteAssignment` if the noun is desired. - **Rationale:** Single-purpose clients should not repeat the subject. `TagAssignmentsClient.create()` reads cleaner. ### 8. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` @@ -69,13 +69,7 @@ - **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. - **Rationale:** Fields should not re-state their container's noun. `assignment.key` reads cleaner. -### 10. `tagKey` validation rules in doc but not type — `src/v1/model.ts:17,26,52` -- **Why weird:** The JSDoc reads: "The key of the tag. The characters `,` `.` `:` `/` `-` `=` and leading/trailing spaces are not allowed". This is a strict character-class constraint that lives in prose, not in the type. The TS type is just `string`. A user concatenating `${prefix}.${name}` produces an invalid `tagKey` with no compile-time signal. -- **Category:** 6 (misleading — type permits values that the API rejects), 19 (underspecified ID). -- **Suggested name:** Keep `tagKey: string` but document the constraint in a way the generator could surface (e.g. via a `TagKey` branded type). At minimum, both `Create` and `Get`/`Delete` request docs should be consistent. -- **Rationale:** Validation rules in JSDoc only are an asymmetric SDK contract. - -### 11. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` +### 10. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` - **Why weird:** The list URL is `/api/2.0/entity-tag-assignments/${entityType ?? ''}/${entityId ?? ''}/tags`. When either is undefined, the URL becomes `.../entity-tag-assignments///tags`. Both fields are typed `string | undefined`, but `entityType` and `entityId` are clearly required to address an entity. Same issue on `Get`/`Delete`/`Update`. The SDK silently produces malformed URLs. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. @@ -83,31 +77,19 @@ ## Medium severity -### 12. `CreateTagAssignmentRequest` etc. — five request DTOs share a 17-char prefix — `src/v1/model.ts:7,11,20,29,57` +### 11. `CreateTagAssignmentRequest` etc. — five request DTOs share a 17-char prefix — `src/v1/model.ts:7,11,20,29,57` - **Why weird:** `CreateTagAssignmentRequest`, `DeleteTagAssignmentRequest`, `GetTagAssignmentRequest`, `ListTagAssignmentsRequest`, `UpdateTagAssignmentRequest`. Every request type re-states `TagAssignment` in a package whose only subject *is* the tag assignment. - **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). - **Suggested name:** `CreateRequest`, `DeleteRequest`, `GetRequest`, `ListRequest`, `UpdateRequest`. Or drop the noun. - **Rationale:** Single-subject packages do not need to repeat the subject on every request DTO. -### 13. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` +### 12. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` - **Why weird:** The plural appears only on list types. The HTTP resource on the wire is `/entity-tag-assignments` (plural) while the item type is singular `TagAssignment`. List response is `ListTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. - **Rationale:** Rule 9 demands the flag even when intentional. -### 14. `tagAssignmentFieldMask` / `tagAssignmentFieldMaskSchema` — `src/v1/model.ts:103,110` -- **Why weird:** A function and a lookup table share a stem and differ only by the `Schema` suffix. The function reads as a noun (no verb). 28+ characters. Compare sister `entityTagAssignmentFieldMask`. -- **Category:** 17 (function and noun share the same stem), 7 (overly verbose). -- **Suggested name:** `buildTagAssignmentFieldMask(...)` (verb-prefixed), or shorten to `fieldMask(...)` (the surrounding package and `TagAssignment` generic do the rest). -- **Rationale:** Functions should be verb-prefixed; otherwise they read as nouns. Generator-wide concern. - -### 15. `marshalTagAssignmentSchema` / `unmarshalTagAssignmentSchema` / `unmarshalListTagAssignmentsResponseSchema` — `src/v1/model.ts:62,75,89` -- **Why weird:** These are Zod schemas (47-char identifier on `unmarshalListTagAssignmentsResponseSchema`) using Go verbs `marshal`/`unmarshal`. TS reaches for `serialize`/`parse` or Zod's own `.parse()`. The TS-Go vocab mix is jarring; Zod schemas already have `.parse()`. -- **Category:** 14 (Go-style verbs in TS code), 17 (verb inconsistency with Zod's `.parse()`). -- **Suggested name:** `encodeTagAssignment` / `decodeTagAssignment` / `decodeListResponse`. Or drop `Schema` since the value *is* a Zod schema. -- **Rationale:** `marshal`/`unmarshal` is Go vocabulary; this is a TS file with Zod. Generator-wide concern. - -### 16. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 13. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute". `executeCall` wraps retry/rate-limit policy; `executeHttpCall` does the actual HTTP send. In every client method both appear: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -121,109 +103,84 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Layering should be readable from names. Generator-wide concern. -### 17. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` +### 14. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, passed to `executeCall`. Same word as variable, type, and verb. Inside one method scope we have `req`, `call`, `httpReq`, `resp` — four roles, three of which abbreviate. - **Category:** 1 (vague), 12 (duplicate concept), 4 (no underscore — but the name collision compensates). - **Suggested name:** `runRequest`/`sendRequest` for the variable; keep `Call` as the type. - **Rationale:** Variable-type collisions are tolerable but obscure prose. -### 18. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` +### 15. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` - **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. - **Category:** 6 (misleading — silent malformed URLs). - **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. -- **Rationale:** See #11. Generator-wide concern. +- **Rationale:** See #10. Generator-wide concern. -### 19. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` +### 16. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` - **Why weird:** `respBody: Uint8Array` and `resp: TagAssignment` differ only by suffix. Both abbreviate "response"; the reader must remember which is bytes and which is parsed. There is no `reqBody` sibling for symmetry. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — only response abbreviates with `Body`). - **Suggested name:** `rawBody`/`result`, or `responseBytes`/`response`. - **Rationale:** Stage differences should be communicated by meaningful nouns, not suffix variations. -### 20. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` +### 17. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` - **Why weird:** Inside methods that already have `req: `, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Forking the same identifier across layers is hard to read. -### 21. `pageReq` in `listTagAssignmentsIter` — `src/v1/client.ts:174` -- **Why weird:** Inside `listTagAssignmentsIter`, a clone of `req` is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; outer `req` is the parameter. -- **Category:** 5 (cryptic), 8 (redundant prefix — `page` on a paginated iter is implicit). +### 18. `pageReq` clone variable in paginated list — `src/v1/client.ts:174` +- **Why weird:** A clone of `req` is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; outer `req` is the parameter. +- **Category:** 5 (cryptic), 8 (redundant prefix — `page` in a pagination loop is implicit). - **Suggested name:** `current` or `cursor` (describes its role as iterator state). - **Rationale:** A variable that mutates a clone of the input should describe its role. -### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +### 19. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 23. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` +### 20. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries Java/JS Builder-pattern connotations. -### 24. `marshalRequest(data, schema)` — `src/v1/utils.ts:119` -- **Why weird:** Takes `unknown` value plus Zod schema; returns JSON string. The name says "Request" but the function works for any payload. -- **Category:** 1 (vague — `Request` does not constrain), 6 (misleading — works for any payload). -- **Suggested name:** `marshalToJson` / `encodeToJson`. -- **Rationale:** Function name should reflect actual function. Same problem in sister packages. - ## Low severity -### 25. `parseResponse(body, schema)` — `src/v1/utils.ts:113` -- **Why weird:** Symmetric to `marshalRequest`. Parses any JSON `Uint8Array` against a Zod schema; "Response" in the name does not constrain. -- **Category:** 1 (vague), 6 (misleading). -- **Suggested name:** `parseJsonBody` / `decodeFromJson`. -- **Rationale:** Asymmetric verb pair `marshal`/`parse` AND inaccurate naming. - -### 26. `flattenQueryParams` — `src/v1/utils.ts:123` +### 21. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in `client.ts`. This package's `listTagAssignments` uses individual `params.append(...)` calls (line 142-148) instead. Dead-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. -### 27. `readAll(body)` — `src/v1/utils.ts:40` +### 22. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is too generic; the function specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** Reads like it might take a file path or array. -### 28. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The single word "segment" provides no domain context. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Comment above the constant does the work the name should. -### 29. `tagValue` field doc empty — `src/v1/model.ts:53,54` +### 24. `tagValue` field doc empty — `src/v1/model.ts:53,54` - **Why weird:** `tagValue?: string | undefined` is documented as "The value of the tag" — a tautology. Compare the rich docs on `entityType`/`entityId`/`tagKey` (with character-class rules). The doc is doing zero work. - **Category:** 1 (vague — doc says nothing the field name does not), 15 (generic field doc). - **Suggested name:** Document what makes a `tagValue` valid (max length? character set? same restrictions as `tagKey`?). - **Rationale:** Asymmetric documentation: three fields have rules, one is silent. -### 30. `tagAssignments` vs. `nextPageToken` field-naming style on `ListTagAssignmentsResponse` — `src/v1/model.ts:41,43` -- **Why weird:** Response has `tagAssignments?: TagAssignment[] | undefined` and `nextPageToken?: string | undefined`. The latter is consistent with the convention (`nextPageToken`), the former carries the redundant `tag` prefix on the array of a `TagAssignment[]`. Inside the response type, `assignments?: TagAssignment[]` would also unambiguously be a list of tag assignments. -- **Category:** 8 (redundant prefix — `tag` within a TagAssignment array). -- **Suggested name:** `assignments` (drop the `tag` prefix). Wire stays `tag_assignments`. -- **Rationale:** Field names should not duplicate their element-type's noun. - ## Observations -### 31. Wire/TS divergence dominates the file -The `model.ts` file is 115 lines for ~7 user-facing types; ~50 lines are `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as sister packages. - -### 32. Action verb consistency -The client uses `create`/`get`/`update`/`delete`/`list`/`listIter` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. - -### 33. Acronym casing -The file uses `HttpRequest`/`HttpResponse`/`HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. -- **Category:** 3 (acronym casing — consistent within file, ecosystem-divergent overall). +### 25. Action verb consistency +The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 34. `tagassignments` lowercase package name vs. types and HTTP path +### 26. `tagassignments` lowercase package name vs. types and HTTP path The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). -### 35. Domain leakage between sister packages +### 27. Domain leakage between sister packages Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md index 3fa19c19..b135e2ea 100644 --- a/.agent/naming-audit/tagpolicies.md +++ b/.agent/naming-audit/tagpolicies.md @@ -3,15 +3,15 @@ **Path:** `packages/tagpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and optional `propagationConfig` (with conflict-resolution rules) so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. -**Total weird names flagged:** 37 +**Total weird names flagged:** 30 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 13 | -| Low | 11 | -| Observation | 5 | +| Medium | 10 | +| Low | 8 | +| Observation | 4 | ## High severity @@ -42,7 +42,7 @@ ### 5. Method names `createTagPolicy` / `deleteTagPolicy` / `getTagPolicy` / `listTagPolicies` / `updateTagPolicy` — `src/v1/client.ts:67,93,112,137,188` - **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createTagPolicy(...)` reads as "package.subject.create.subject" — the noun is doubled. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. Sister packages do the same. - **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `TagPolicy` five times when the client only manages `TagPolicy`). -- **Suggested name:** `create`, `delete`, `get`, `list`, `update` (and `listIter`). +- **Suggested name:** `create`, `delete`, `get`, `list`, `update`. - **Rationale:** A client class that ships exactly five methods all named after the same subject is repeating the subject. `TagPoliciesClient.create()` reads better than `client.createTagPolicy()`. ### 6. `tagKey` is both the resource identifier and a field on `TagPolicy` — `src/v1/model.ts:63` and `model.ts:31,35` @@ -108,36 +108,18 @@ - **Rationale:** Three identifiers in one switch (`$case === 'defaultValueOverride'` ⇒ `defaultValueOverride.defaultValue`) that say the same thing make for noisy type checks. ### 16. `tagPolicyFieldMask(...paths: string[])` exported helper — `src/v1/model.ts:281` -- **Why weird:** A free function `tagPolicyFieldMask` exported alongside the type system, with no class namespace. The user types `tagPolicyFieldMask('description', 'values')`. The lowercase camelCase clashes with the PascalCase convention for type-related exports. Re-stated in sister packages with the same shape (`tagAssignmentFieldMask`, etc.). Belongs in a `TagPolicy.fieldMask` static method or in a shared helper module. -- **Category:** 8 (redundant prefix `tagPolicy` on a function exported only from the `tagpolicies` package), 14 (Go-style top-level functions instead of class statics). -- **Suggested name:** `fieldMask` (let the import path supply scope), or `TagPolicy.fieldMask` (static method). -- **Rationale:** Free functions with the type name as prefix replicate Go's lack of methods on structs. TS supports static methods natively. - -### 17. `marshalRequest` / `parseResponse` asymmetric verb pair — `src/v1/utils.ts:113,119` -- **Why weird:** Two functions that form a logical pair, named with mismatched verbs: `marshalRequest` (serialize TS → wire) and `parseResponse` (deserialize wire → TS). The corresponding inverse pair would be `marshalRequest`/`unmarshalResponse` or `serializeRequest`/`deserializeResponse`. Currently asymmetric: `marshal` ↔ `parse`. -- **Category:** 17 (inconsistent action verbs — marshal/unmarshal vs. marshal/parse). -- **Suggested name:** `marshalRequest` / `unmarshalResponse`, or `serializeRequest` / `deserializeResponse`. -- **Rationale:** Sibling helpers should use mirrored verbs. The mismatch is a generator-wide pattern but worth flagging. - -### 18. `marshalRequest` is mis-named — `src/v1/utils.ts:119` -- **Why weird:** The function `marshalRequest(data, schema)` takes *any* data (not a "request"), parses it through the schema, and returns a JSON string. It is a generic JSON encoder; the name implies it only handles request bodies. -- **Category:** 6 (misleading — handles arbitrary data, not just requests), 1 (vague — `marshal` is non-specific in JS, where `JSON.stringify` is the convention). -- **Suggested name:** `toJsonString` or `marshal` (no `Request` suffix). -- **Rationale:** A name that overstates the function's coupling to "request" misleads callers who'd reuse it for response prep. - -### 19. `parseResponse` is mis-named — `src/v1/utils.ts:113` -- **Why weird:** Same problem as `marshalRequest` — the function `parseResponse(body, schema)` parses *any* `Uint8Array` body, not specifically a response. Used to validate request bodies during testing as well. -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `parseJson` or `unmarshal`. -- **Rationale:** Drops the false coupling to "response". - -### 20. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` +- **Why weird:** A free function `tagPolicyFieldMask` exported alongside the type system. The user types `tagPolicyFieldMask('description', 'values')` — the package name is already `tagpolicies`, so the `tagPolicy` prefix re-states the package scope. Sister packages do the same (`tagAssignmentFieldMask`, etc.). +- **Category:** 8 (redundant prefix `tagPolicy` on a function exported only from the `tagpolicies` package). +- **Suggested name:** `fieldMask` (let the import path supply scope). +- **Rationale:** Once a caller has imported from `@databricks/sdk-tagpolicies`, the `tagPolicy` prefix on the helper is noise. + +### 17. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` - **Why weird:** Two near-identical names with different purposes. `executeCall(call, options)` runs a `Call` through the retrier/rate-limiter; `executeHttpCall(opts)` issues a single HTTP request and reads the body. The names differ by one word (`Http`) but the responsibilities are radically different (orchestrator vs. transport). A user grepping for "execute" can't tell which one to use. - **Category:** 1 (vague — the disambiguator is too thin), 17 (inconsistent verb scoping). - **Suggested name:** `executeCall` (orchestrator) and `sendHttpRequest` (single-request transport). - **Rationale:** Distinct responsibilities should have distinct verb roots, not a same-verb-different-noun split. -### 21. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 18. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that this client does not invoke (the list endpoint uses individual `params.append(...)` calls instead — see `client.ts:143,146`). Dead-code-shaped helper. - **Category:** 6 (misleading — implies the package uses it), 1 (vague — `flatten` is generic; this specific one only handles a subset of types). - **Suggested name:** N/A — should live in a shared utils package, not be copied into every package. @@ -145,67 +127,49 @@ ## Low severity -### 22. `createTime` and `updateTime` naming on `TagPolicy` — `src/v1/model.ts:68,70` +### 19. `createTime` and `updateTime` naming on `TagPolicy` — `src/v1/model.ts:68,70` - **Why weird:** Verb tense / noun pair where the natural English is "created at" / "updated at". `createTime` reads as "the time to create" (a verb-noun); `createdAt` is the cross-language convention for "timestamp when it was created". Cross-SDK convention is `createTime`/`updateTime`, so this is consistent with the rest of the codebase, but is non-idiomatic JS/TS. - **Category:** 13 (verb-tense inconsistency — `create` (infinitive) vs. `created` (past participle)), 14 (Go-style naming — Go uses `CreateTime`). - **Suggested name:** `createdAt` / `updatedAt`. - **Rationale:** Established SDK pattern, but rule 13/14 demand the flag. Mongo, PostgREST, Rails, GraphQL conventions all use `createdAt`. -### 23. `accountId: string` on `TagPolicy` — `src/v1/model.ts:74` +### 20. `accountId: string` on `TagPolicy` — `src/v1/model.ts:74` - **Why weird:** "The account ID that owns this tag policy." — generic. `accountId` is consistent across the SDK, but the SDK's bound to an account already (via `ClientOptions.accountId`), so this field is redundant *output* (the server tells you the account that owns the policy, which the client already knows). - **Category:** 1 (vague — what kind of ID? account number? UUID?), 19 (underspecified ID — no format documented), 15 (generic field name losing meaning in the SDK context). - **Suggested name:** Keep `accountId`; document that it's the Databricks account UUID. - **Rationale:** Minor; flagged because all `*Id` fields without docs trigger rule 19. -### 24. `Temporal.Instant` for timestamps — `src/v1/model.ts:68,70` +### 21. `Temporal.Instant` for timestamps — `src/v1/model.ts:68,70` - **Why weird:** Uses `Temporal.Instant` (from `@js-temporal/polyfill`), which is a great future-proof choice — but `Instant` is unfamiliar to most JS devs (who expect `Date` or string). The doc says "Timestamp when the tag policy was created" without explaining why it's an `Instant`. - **Category:** 1 (slightly vague choice without doc support), 5 (cryptic to readers unfamiliar with Temporal proposal). - **Suggested name:** Keep `Temporal.Instant`; add JSDoc explaining the type choice. - **Rationale:** Generator-wide; flagged once. -### 25. `nextPageToken: string` empty-string semantics — `src/v1/client.ts:180,183` -- **Why weird:** The pagination loop terminates on `resp.nextPageToken === undefined || resp.nextPageToken === ''`. Two sentinel values for "end of pages": `undefined` (TS-native missing field) and `''` (proto-side default). Callers must remember the two cases. The schema converts both to `string | undefined`, but the wire emits `""` rather than dropping the field. -- **Category:** 6 (misleading — `nextPageToken: ''` looks like a valid token but means "no more pages"), 17 (inconsistent sentinel — two values mean the same thing). -- **Suggested name:** Keep `nextPageToken`; normalize empty string to `undefined` in the unmarshaller. The field is purely a continuation token; "" is not a token, it's a missing token. -- **Rationale:** Generator-wide pattern. Each `*Iter` method has to handle both sentinels. - -### 26. `listTagPoliciesIter` method name — `src/v1/client.ts:170` -- **Why weird:** `Iter` suffix is Go-style (sister `listTagPoliciesIter` matches `Go ListTagPoliciesIterator`). In JS/TS, the standard is to expose `[Symbol.asyncIterator]()` on a class, or to name a generator function with a noun phrase (e.g., `tagPolicies()`). `Iter` is also a cryptic three-letter abbreviation. -- **Category:** 14 (Go-style naming), 5 (cryptic abbreviation — `Iter` shortens `Iterator`). -- **Suggested name:** `listAll(...)` or `iterateTagPolicies(...)`, or make the class an `AsyncIterable` directly. -- **Rationale:** TS has built-in support for `for await...of`; the iterator method should match those expectations. - -### 27. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:43-44` +### 22. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:43-44` - **Why weird:** JSDoc says "The maximum value is 1000; values above 1000 will be coerced down to 1000." but the field is typed `number | undefined`. A caller passing `pageSize: 100000` silently gets clipped to 1000. The constraint travels only via the docstring. - **Category:** 6 (misleading — type does not match contract). - **Suggested name:** Keep `pageSize`; consider a branded type or a runtime validator. At minimum, restate the limit clearly. - **Rationale:** Generator-wide; flagged because docs lie about wire behaviour. -### 28. `pageSize` and `pageToken` are camelCase but wire is `page_size` / `page_token` — `src/v1/client.ts:144,147` -- **Why weird:** The TS request shape uses `pageSize` / `pageToken`, but the URL builder hard-codes the wire names `page_size` / `page_token` (`client.ts:144,147`) — i.e., the client serializes TS field names *manually* into snake_case query strings. If a future request adds new query params, every new param requires another two-name mapping. -- **Category:** 17 (inconsistency — request fields camelCase, URL builder snake_case, no shared mapping table). -- **Suggested name:** N/A; flag as generator-side smell. A field-mask or marshal-schema-driven URL builder would avoid the dual-name maintenance. -- **Rationale:** Each new query param doubles the bug surface. - -### 29. `updateMask` field type `FieldMask` — `src/v1/model.ts:79` +### 23. `updateMask` field type `FieldMask` — `src/v1/model.ts:79` - **Why weird:** `FieldMask` is a generic type carrying the masked-shape as a type parameter. The name `updateMask` is wire-standard (proto FieldMask) but cryptic to TS users — "mask" usually means a bitmask. The JSDoc is missing. - **Category:** 5 (cryptic — `mask` for TS users means bitmask), 14 (proto-style — FieldMask is a proto concept). - **Suggested name:** Keep `updateMask`; add JSDoc explaining it's a path-based selector for partial updates. - **Rationale:** Generator-wide name; flag once. -### 30. `id` field on `TagPolicy` — `src/v1/model.ts:64` +### 24. `id` field on `TagPolicy` — `src/v1/model.ts:64` - **Why weird:** Field name `id` with no JSDoc on what it represents — server-generated UUID? Hashed `tagKey`? Path key for some other endpoint? See #6 for the duplicate-identifier critique; this is the underspecified-`id`-name flag separately. - **Category:** 1 (vague), 19 (underspecified ID), 15 (generic name). - **Suggested name:** `policyId` or `governedTagId`; add JSDoc. - **Rationale:** Sibling `BudgetPolicy.policyId` uses the prefix; `TagPolicy.id` does not. Cross-SDK inconsistency. -### 31. `description` field doc missing — `src/v1/model.ts:65` +### 25. `description` field doc missing — `src/v1/model.ts:65` - **Why weird:** Just `description?: string | undefined` with no JSDoc. Width limits? Mandatory? Format? - **Category:** 1 (vague — no contract on the field). - **Suggested name:** Keep `description`; add JSDoc. - **Rationale:** Common pattern, but flagged because rule 1 demands it. -### 32. `host` constructor field with trailing-slash stripping — `src/v1/client.ts:42,54` +### 26. `host` constructor field with trailing-slash stripping — `src/v1/client.ts:42,54` - **Why weird:** The constructor strips trailing `/` from `options.host` (`client.ts:54`). Field is `host`, not `baseUrl` or `endpoint`. The TS field `host` is a string like `https://workspace.cloud.databricks.com`, which is by convention "the base URL" not "the host" (the host would be `workspace.cloud.databricks.com` without scheme). - **Category:** 6 (misleading — "host" usually means hostname-only). - **Suggested name:** `baseUrl` or `endpoint`. @@ -213,21 +177,18 @@ ## Observations -### 33. Wire/TS divergence dominates the file -The `model.ts` file is 284 lines for ~9 user-facing types; ~140 lines are `marshal`/`unmarshal`/`FieldMaskSchema` scaffolding. Same pattern as other audited packages. - -### 34. Action verb consistency -The client uses `create`/`get`/`update`/`delete`/`list` (plus `listIter`) — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. +### 27. Action verb consistency +The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 35. Acronym casing +### 28. Acronym casing File uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri` casing clashes encountered within the file. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 36. `tagpolicies` lowercase package name +### 29. `tagpolicies` lowercase package name Package directory is `tagpolicies` (single token, no separator), but every type uses `TagPolicy*` and the HTTP path uses `tag-policies`. Same problem as `dataclassification`, `tagassignments`, `entitytagassignments` — SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 37. Domain leakage from sister packages +### 30. Domain leakage from sister packages Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — all collide on the noun "tag". Each ships its own `Client`, its own `tag*` types, and its own `tagKey`. Co-import requires extensive aliasing. `tagpolicies` differs in that it defines the *policy* over the tag, while the assignment packages attach a `tagKey` + `tagValue` to entities — but a user can't tell from the name; "tag policies" sounds like it could be policies *for* tag assignments. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index 7afdd2c9..98c3b8ac 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -3,15 +3,15 @@ **Path:** `packages/tokenmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/update/delete arbitrary user tokens, plus create on-behalf-of-service-principal tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. -**Total weird names flagged:** 36 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | -| High | 12 | +| High | 11 | | Medium | 13 | -| Low | 8 | -| Observation | 3 | +| Low | 3 | +| Observation | 2 | ## High severity @@ -58,7 +58,7 @@ - **Rationale:** The admin variant forces the id into the nested body while the sibling `tokens` package hoists it. This is a real ergonomic delta worth flagging upstream; consumers of both packages will trip on it. ### 8. `client.updateToken` returns `AdminTokenInfo`, sibling returns `UpdateTokenResponse` — inconsistent response handling -- **Why weird:** `tokenmanagement.Client.updateToken` returns `Promise` (client.ts:190) — the bare entity. The sibling `tokens.Client.updateToken` returns `Promise`. Worse: the `tokenmanagement` version doesn't even have a response type declared in `model.ts`; the client just unmarshals into the entity using `unmarshalAdminTokenInfoSchema`. So in one package `updateToken` returns the updated row; in the other it returns a different shape. +- **Why weird:** `tokenmanagement.Client.updateToken` returns `Promise` (client.ts:190) — the bare entity. The sibling `tokens.Client.updateToken` returns `Promise`. Worse: the `tokenmanagement` version doesn't even have a response type declared in `model.ts`; the client just unmarshals into the entity. So in one package `updateToken` returns the updated row; in the other it returns a different shape. - **Category:** 12 (duplicate concept inconsistently implemented), 17 (inconsistent client return shapes). - **Suggested name:** Pick one — either always return the updated entity (preferred; useful) or always return void. If returning the entity, name the type `Token`/`UpdateTokenResponse` rather than reusing the raw entity, so it can evolve. - **Rationale:** Cross-package consistency. A user who learns one client will be surprised by the other. @@ -81,14 +81,14 @@ - **Suggested name:** Add `PAT` aliases or document at the package level. Consider renaming `Token` → `PersonalAccessToken` or, less verbosely, keep `Token` but clarify in JSDoc. - **Rationale:** Discoverability. This package is the admin PAT API; calling that out beats hiding it. +## Medium severity + ### 12. `applicationId` on `CreateOnBehalfOfToken` — generic field name in a security-sensitive context - **Why weird:** `applicationId: string` (model.ts:51) is the OAuth client ID of the service principal the on-behalf-of token will represent. "Application ID" is Azure terminology; on AWS/GCP it's "service principal ID" or "client ID". This is the *target* identity for a privileged token-mint operation; `applicationId` undersells the security implication and overloads "application" with three different meanings across Databricks clouds. - **Category:** 1 (vague — "application" is overloaded), 14 (Azure-style naming leaks), 15 (generic name in security context), 19 (underspecified ID — application ID of what?). - **Suggested name:** `servicePrincipalApplicationId` or `servicePrincipalClientId` (the JSDoc literally says "Application ID of the service principal", so the field name should too). - **Rationale:** The field documentation already names the concept correctly; the field name should follow. Mistaking this for "Databricks Apps application id" would mint a token for the wrong principal. -## Medium severity - ### 13. `ListTokens` request fields `createdById` and `createdByUsername` — duplicate filter slots - **Why weird:** `ListTokens { createdById?, createdByUsername? }` (model.ts:96-100). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type even says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (client.ts:159-164) which means callers can submit both at once and get undefined server behavior. - **Category:** 1 (vague — relationship unspecified), 6 (misleading — looks like two filters, possibly redundant). @@ -161,75 +161,36 @@ - **Suggested name:** `tokenSecret` or `bearerToken`, and add a JSDoc warning ("Returned once. Store immediately."). - **Rationale:** Defensive naming for security-critical fields helps users not log/leak the value. -### 25. `lifetimeSeconds` field — unit-suffix while sibling has same name and unit but adjacent fields differ -- **Why weird:** `CreateOnBehalfOfToken.lifetimeSeconds: number` (model.ts:53) matches sibling `tokens.CreateToken.lifetimeSeconds` (tokens model.ts:29) — good consistency. But within the same file, `AdminTokenInfo.expiryTime: number` lacks a `Ms` unit suffix despite being epoch ms. Mixed convention. -- **Category:** 17 (inconsistent unit-suffix conventions). -- **Suggested name:** Either `lifetimeSeconds` + `expiryTimeMs` (specify both) or `lifetime: number` + `expiryTime: number` (specify neither). Recommend the former. -- **Rationale:** When some fields encode units and others don't, readers can't tell which to trust. - ## Low severity -### 26. `unmarshalCreateOnBehalfOfToken_ResponseSchema`, `unmarshalGetToken_ResponseSchema`, `unmarshalListTokens_ResponseSchema`, `unmarshalRevokeToken_ResponseSchema` — schema constants carry underscores -- **Why weird:** Each constant name carries the underscore from the corresponding type plus an `eslint-disable`. Mechanical cascade from finding #5. -- **Category:** 4 (underscore identifier). -- **Suggested name:** Falls out if response types lose the underscore. -- **Rationale:** Mechanical. - -### 27. `marshalCreateOnBehalfOfTokenSchema` — long mouthful -- **Why weird:** Schema constant name is 32 characters. Verbose but accurate. -- **Category:** 7 (verbosity), Observation. -- **Suggested name:** Acceptable as-is. -- **Rationale:** Convention is consistent across all generated packages; no fix needed. - -### 28. `adminTokenInfoFieldMaskSchema` and `adminTokenInfoFieldMask()` — `Info` cascade -- **Why weird:** Both names carry the `Info` suffix from `AdminTokenInfo`. Mechanical cascade from finding #3. -- **Category:** 1 (vague suffix `Info`). -- **Suggested name:** `tokenFieldMaskSchema` / `tokenFieldMask()` if entity is renamed. -- **Rationale:** Mechanical. - -### 29. `marshalUpdateTokenSchema` second parameter `updateMask` uses `z.any()` -- **Why weird:** The zod schema for `updateMask` is `z.any().transform((m: FieldMask) => m.toString())` (model.ts:236-238). Not a naming issue per se, but `z.any()` defeats type-checking on this field. The schema infers `any` and the marshal accepts anything; only the cast inside the transform restores typing. -- **Category:** Observation, 6 (misleading — schema typed `any`, code expects `FieldMask`). -- **Suggested name:** N/A (logic concern). -- **Rationale:** Same `z.any()` pattern is in the sibling `tokens` marshal. Worth flagging at generator level. - -### 30. `Client` class is named `Client` (no namespacing) +### 25. `Client` class is named `Client` (no namespacing) - **Why weird:** `export class Client` (client.ts:48). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. - **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). - **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). - **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. -### 31. `host` field on `Client` — workspace URL is more specific +### 26. `host` field on `Client` — workspace URL is more specific - **Why weird:** `private readonly host: string;` (client.ts:49). The constructor accepts `options.host` which is actually the workspace URL (e.g., `https://my-workspace.cloud.databricks.com`). "Host" is HTTP-level jargon; `workspaceUrl` is the domain-level term users learn first. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `workspaceUrl` (and `options.workspaceUrl`). - **Rationale:** This is a shared concern across all generated clients; flagged here as it appears in this client. -### 32. `PACKAGE_SEGMENT` constant — vague label +### 27. `PACKAGE_SEGMENT` constant — vague label - **Why weird:** `const PACKAGE_SEGMENT = {...}` (client.ts:43). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `USER_AGENT_PKG`. - **Rationale:** Minor; identical issue in every generated package. -### 33. `executeCall` / `executeHttpCall` / `buildHttpRequest` — utility verb pairs without obvious distinction -- **Why weird:** `executeCall` (utils.ts:26) is the public-options-to-internal-options bridge that calls `execute()`. `executeHttpCall` (utils.ts:65) actually issues the HTTP request. The verb is the same ("execute") and the disambiguator is "Http" — a layer below "Call". A reader has to read both to know which to call when. -- **Category:** 1 (vague — `executeCall` is unspecific), 17 (inconsistent layering convention). -- **Suggested name:** `runWithRetry` / `runHttp`, or `executeWithOptions` / `executeHttpRequest`. -- **Rationale:** Same pattern in every generated client; flagging once. - ## Observations -### 34. Type-suffix tautology pattern repeats: `tokenInfo: AdminTokenInfo`, `tokenInfos: AdminTokenInfo[]` -- These are mechanical consequences of the `Info` suffix on the central entity (finding #3). Listed separately in findings #9 and #10. If the entity is renamed to `Token`, the field names also need to lose the `Info` cascade (`token` and `tokens`). -- **Category:** 20 (type-suffix tautology). - -### 35. Heavy marshal/unmarshal scaffolding ratio -- Model.ts is 265 lines; only ~120 are user-facing type declarations. The rest is zod schemas, transform pairs, FieldMaskSchema, and `eslint-disable` comments. Generator-output bloat per package; not a naming issue. - -### 36. Verb-tense and action-verb summary across the client +### 28. Verb-tense and action-verb summary across the client - `Client` methods: `createOnBehalfOfToken`, `deleteToken`, `getToken`, `listTokens`, `updateToken`. The set is `create/delete/get/list/update` — consistent CRUDish. The mismatch is only with the request types (`RevokeToken` for `deleteToken`, finding #6). - **Category:** 13 (verb-tense inconsistency between method and type). +### 29. Type-suffix tautology pattern repeats: `tokenInfo: AdminTokenInfo`, `tokenInfos: AdminTokenInfo[]` +- These are mechanical consequences of the `Info` suffix on the central entity (finding #3). Listed separately in findings #9 and #10. If the entity is renamed to `Token`, the field names also need to lose the `Info` cascade (`token` and `tokens`). +- **Category:** 20 (type-suffix tautology). + ## Domain glossary - `PAT` — Personal Access Token (only in `AutoscopeState` doc comment; the term the package is about but never names directly). - `OBO` — On-Behalf-Of (spelled out in `CreateOnBehalfOfToken`). diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index 01f4965c..6ce33779 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -3,14 +3,14 @@ **Path:** `packages/tokens/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share an `AutoscopeState` enum and a near-identical "token info" record, but the auth/audience boundary makes them distinct services. -**Total weird names flagged:** 35 +**Total weird names flagged:** 31 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 11 | -| Low | 10 | +| Medium | 10 | +| Low | 7 | | Observation | 5 | ## High severity @@ -148,13 +148,7 @@ - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Cross-package: same as `rfa#32`, recurs everywhere. -### 19. `marshalRequest` / `parseResponse` verb asymmetry — `utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); two different verbs for opposite operations in the same file. The rest of the package consistently uses `marshal*`/`unmarshal*` (the schemas: `marshalCreateTokenSchema`, `unmarshalPublicTokenInfoSchema`, etc.), so the function-level utility breaks the package's own convention. -- **Category:** 17 (inconsistent action verbs), 13 (intra-package inconsistency). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry. -- **Rationale:** Cross-package: same as `rfa#31`. - -### 20. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` +### 19. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` - **Why weird:** The file imports `Options` from `@databricks/sdk-core/api` (line 3) and `CallOptions` from `@databricks/sdk-options/call` (line 12). Three `Options`-suffixed types in scope. `HttpCallOptions` is internal — purely a context bag passed to `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -162,81 +156,57 @@ ## Low severity -### 21. `marshalCreateTokenSchema` etc. — redundant `Schema` suffix on every codec — `model.ts:99-212` -- **Why weird:** Seven marshal/unmarshal schemas, all suffixed `Schema`. Names get long (`unmarshalCreateToken_ResponseSchema` = 35 chars including the `_`). The suffix repeats info already captured by the `z.ZodType<...>` typing. -- **Category:** 8 (redundant suffix `Schema`). -- **Suggested name:** Drop `Schema` (`unmarshalCreateTokenResponse`, `marshalRevokeToken`), or shorten to `decode*`/`encode*` verbs. -- **Rationale:** Same as `rfa#30`. - -### 22. `publicTokenInfoFieldMaskSchema` internal const + `publicTokenInfoFieldMask` exported helper — `model.ts:214,226` -- **Why weird:** Two helpers with near-identical names: an internal `publicTokenInfoFieldMaskSchema` (the lookup table) and an exported `publicTokenInfoFieldMask(...)` (the builder). The `Schema` suffix on one, no suffix on the other, while both relate to field-mask handling. -- **Category:** 8 (redundant suffix), 13 (intra-package inconsistency). -- **Suggested name:** Either `publicTokenInfoFieldMaskPaths` (the static map) and `publicTokenInfoFieldMask` (the builder), or hoist into a single object exposing both. -- **Rationale:** Generator artefact; mechanical fix. +### 20. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:226` +- **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateToken` payloads must learn this helper. +- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #26 re-export gap). +- **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. +- **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. -### 23. `readAll` — generic helper name — `utils.ts:40` +### 21. `readAll` — generic helper name — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `rfa#34`. -### 24. `flattenQueryParams` — `utils.ts:123` +### 22. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` only ever builds JSON bodies). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default; or keep, but stop emitting it for body-only services. - **Rationale:** Same as `rfa#35`. -### 25. `PACKAGE_SEGMENT` constant — `client.ts:41` +### 23. `PACKAGE_SEGMENT` constant — `client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `rfa#36`. -### 26. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` +### 24. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,111,141,171` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Same as `rfa#38`. -### 27. `marshalRequest(data: unknown, schema: z.ZodType): string` — `utils.ts:119` -- **Why weird:** The function parses `data` against `schema` and returns a JSON string. The name says "marshal request", but it's used for *any* outbound body, including update bodies that aren't strictly "request DTOs" in the sense of "request type". Mechanical. -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `marshalJson` or `serializeBody`. -- **Rationale:** Same as `rfa#39`. - -### 28. `parseResponse` overloads with `JSON.parse` and `schema.parse` — `utils.ts:113` -- **Why weird:** Returns `T` where `T` is the schema's inferred type. The name "parse" overloads with `JSON.parse` (called inside) and with `schema.parse` (also called inside). Three layers of "parse" in five lines. -- **Category:** 1 (vague). -- **Suggested name:** `decodeResponse` or `unmarshalJson`. -- **Rationale:** Same as `rfa#40`. - -### 29. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` +### 25. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` - **Why weird:** Local `opts` variable is one letter shorter than the parameter `options` to disambiguate. The shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions`. - **Rationale:** Same as `rfa#41`. -### 30. `unmarshalRevokeToken_ResponseSchema` — proto-style underscore propagates into schema constant — `model.ts:147-148` -- **Why weird:** The `_Response` underscore from finding #7 propagates into the schema constant: `unmarshalRevokeToken_ResponseSchema` is 37 chars including the underscore, and the underscore *inside the identifier* makes IDE autocomplete jagged. -- **Category:** 4 (underscore in TS identifier). -- **Suggested name:** Combine with #7 (drop underscore everywhere). -- **Rationale:** Mechanical. - ## Observations -### 31. `index.ts` re-exports interfaces but not marshal/unmarshal schemas -The index file exports the `Client`, the `AutoscopeState` enum, and nine model interfaces. It does *not* export the `marshal*Schema`/`unmarshal*Schema` constants or the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. +### 26. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper +The index file exports the `Client`, the `AutoscopeState` enum, and nine model interfaces. It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. -### 32. `package.json` description is empty string — `package.json:4` +### 27. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the ambiguous `tokens` name (see #1) and the parallel `tokenmanagement` package, this leaves users without any registry-level metadata to disambiguate the two packages. -### 33. No tests in the package +### 28. No tests in the package `package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees (`AutoscopeState` proto-link in the doc) deserve a contract test. -### 34. Doc comments leak proto file paths and internal commentary +### 29. Doc comments leak proto file paths and internal commentary The `AutoscopeState` doc (model.ts:7-12) references `common/principal-context/api/proto/tokendetails.proto` and `Principal context proto should NOT depend on this proto definitions` — internal architecture commentary that leaks into the public SDK surface. Similar pattern in `tokenmanagement`. Acceptable for now, but a polish pass should strip internal proto-tree paths from the user-facing JSDoc. -### 35. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:165` +### 30. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:165` `const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:89`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. ## Domain glossary diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 38d47caa..65d23a8e 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -3,13 +3,13 @@ **Path:** `packages/usagedashboards/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). -**Total weird names flagged:** 26 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | | High | 7 | -| Medium | 9 | +| Medium | 8 | | Low | 6 | | Observation | 4 | @@ -54,7 +54,7 @@ ### 7. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` - **Why weird:** Databricks workspace IDs are 64-bit integers (the Go SDK uses `int64`); JavaScript's `number` type is IEEE-754 double which loses precision above 2^53. The TS field is typed `number | undefined`. Same finding applies to `metastores` and most workspace-scoped packages in the SDK, but worth flagging because every audit cycle compounds the risk. Compare with `accountId: string` (line 21) which correctly uses `string` for an account UUID. - **Category:** 16 (field type contradicts domain — `number` cannot represent a 64-bit ID), 6 (misleading — type appears safe but is lossy). -- **Suggested name:** Keep the field name, change type to `string` (and update `marshalCreateBillingUsageDashboardSchema` to allow string→number marshalling, or have the wire send it as a string — the Databricks REST API generally accepts both for `workspace_id`). +- **Suggested name:** Keep the field name, change type to `string`. - **Rationale:** Most workspace IDs are below 2^53 in practice, so this rarely bites. But the type contract claims something the runtime can't honour for the high end of the ID space. This is a systemic SDK-level issue worth raising at the generator. ## Medium severity @@ -84,9 +84,9 @@ - **Rationale:** Same as `billableusagedownload` finding. The duplicated-with-fallback pattern is a footgun; the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. ### 12. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72` -- **Why weird:** `accountId` lives on `CreateBillingUsageDashboard` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshal schema (lines 73-85) does emit `account_id` in the body though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. +- **Why weird:** `accountId` lives on `CreateBillingUsageDashboard` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. - **Category:** 6 (misleading — body shape implies body field, but it's a path param), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree?). -- **Suggested name:** Either segregate path params into a separate type (`PathParams` / `RouteParams`) or document the field's dual role. Or omit it from the body via the marshal schema (`d.account_id` would not appear) and keep it as a path-param-only field. Most idiomatic: remove from request DTO entirely (see #11). +- **Suggested name:** Either segregate path params into a separate type (`PathParams` / `RouteParams`) or document the field's dual role. Or omit it from the body and keep it as a path-param-only field. Most idiomatic: remove from request DTO entirely (see #11). - **Rationale:** The current shape misleads callers about the wire format. The field appears in two URL segments simultaneously, which is suspicious. ### 13. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` @@ -107,54 +107,48 @@ - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency — same finding appears in every audited package. Worth normalising at the generator level. -### 16. `marshalCreateBillingUsageDashboardSchema` / `unmarshalCreateBillingUsageDashboard_ResponseSchema` schema names are 40+ chars — `src/v1/model.ts:52, 62, 73` -- **Why weird:** The schema identifiers are mouthfuls: `unmarshalCreateBillingUsageDashboard_ResponseSchema` is 51 characters; the `Schema` suffix and `unmarshal`/`marshal` prefix together inflate already-long type names. The `_Response` underscore appears in the schema name too (same lint suppression). -- **Category:** 7 (overly verbose), 4 (underscore), 20 (type-suffix tautology — `Schema` suffix on a zod schema is redundant given the value's `z.ZodType` type). -- **Suggested name:** Group schemas in a namespace or object: `schemas.createBillingUsageDashboard` / `schemas.createBillingUsageDashboardResponse`. Or accept the verbosity but at least drop `_Response` (see #4). -- **Rationale:** Tree-shaking concerns aside, the current names are read-once, write-many. Worth simplifying. - ## Low severity -### 17. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` +### 16. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` - **Why weird:** The exact same multi-sentence JSDoc ("Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account.") appears on `CreateBillingUsageDashboard.dashboardType` (line 22) and `GetBillingUsageDashboard.dashboardType` (line 39). The duplication suggests the underlying enum (`UsageDashboardType`) should carry the doc, not each field. - **Category:** Observation — not strictly a name issue but flagged because it implies fragmentation. JSDoc duplication is a generator artefact. - **Suggested name:** Move the doc to the `UsageDashboardType` enum (or its members). -### 18. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:68, 74, 78, 97, 111, 115, 117` +### 17. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:68, 74, 78, 97, 111, 115, 117` - **Why weird:** Local variables use three-letter abbreviations (`req`, `resp`, `opts`, `httpReq`). The codebase guideline (typescript.mdc § 5) discourages cryptic short abbreviations. Compare with `httpClient` (full word) in the same file. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`. - **Rationale:** Inexpensive readability win. -### 19. `req: CreateBillingUsageDashboard` parameter name — `src/v1/client.ts:69, 98` -- **Why weird:** The method parameter is named `req` (the abbreviation from #18). It is also the request DTO whose type name doesn't end in `Request` (see #5). The parameter name `req` clashes with the natural reading where the type name suggests an entity ("a usage dashboard to create") not a request envelope. +### 18. `req: CreateBillingUsageDashboard` parameter name — `src/v1/client.ts:69, 98` +- **Why weird:** The method parameter is named `req` (the abbreviation from #17). It is also the request DTO whose type name doesn't end in `Request` (see #5). The parameter name `req` clashes with the natural reading where the type name suggests an entity ("a usage dashboard to create") not a request envelope. - **Category:** 5 (cryptic), 6 (misleading paired with type name). - **Suggested name:** `params` or `input` (since the type is not literally a Request). Or fix the type name (`CreateBillingUsageDashboardRequest`) and keep `request`. -### 20. `params` shadowed across files — `src/v1/client.ts:102` +### 19. `params` shadowed across files — `src/v1/client.ts:102` - **Why weird:** Local `params: URLSearchParams` — fine in isolation, but `flattenQueryParams(prefix, value, params)` in `utils.ts:123` exposes the same `params` name in public API. The repeated use of `params` for both `URLSearchParams` and "named function parameters" is mildly confusing in audit traces. - **Category:** 1 (vague). - **Suggested name:** `queryParams` / `urlSearchParams`. -### 21. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:109` +### 20. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:109` - **Why weird:** `const query = params.toString();` — the variable is the serialized query *string*, but `query` reads as a query expression/object. Compare with `fullUrl` on the next line (which is clear about what it is). - **Category:** 1 (vague), 6 (misleading — name implies a query, value is a string). - **Suggested name:** `queryString`. -### 22. `httpClient: HttpClient` field — `src/v1/client.ts:43` +### 21. `httpClient: HttpClient` field — `src/v1/client.ts:43` - **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention widespread in this SDK. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the outer `Client` class in the same file. ## Observations -### 23. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` +### 22. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` The exported `flattenQueryParams` helper is never called from `client.ts` — the GET method does its own `params.append()` (lines 103-108) inline because there are only two query params. The helper is dead surface area in this package; same finding as `billableusagedownload` audit #11. Worth pruning at the generator level when the consuming methods don't need it. -### 24. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` +### 23. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. Both are used in `client.ts:79, 89, 117, 126`. The verb-pair is fine, but the cognitive distance between "wrap with retry options" and "send an HTTP request and check for API errors" is large enough that one name should be different (e.g., `runWithCallOptions` / `sendHttp`). Same finding appears in every audited package's `utils.ts`. -### 25. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency +### 24. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency - The enum names are `UsageDashboardMajorVersion`, `UsageDashboardType` — `Usage` first, no "Billing". - The request types are `CreateBillingUsageDashboard` — `Billing` first, with `Usage`. - The package is `usagedashboards` — `usage` only, no "billing". @@ -162,7 +156,7 @@ Two functions named almost identically, doing very different things: `executeCal Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #8. -### 26. The package has no list/page operations +### 25. The package has no list/page operations There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. ## Domain glossary diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md index d3df6c7d..bcdb624c 100644 --- a/.agent/naming-audit/usagepolicy.md +++ b/.agent/naming-audit/usagepolicy.md @@ -3,14 +3,14 @@ **Path:** `packages/usagepolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). -**Total weird names flagged:** 41 +**Total weird names flagged:** 38 ## Summary | Severity | Count | | --- | --- | | High | 10 | -| Medium | 15 | -| Low | 11 | +| Medium | 14 | +| Low | 9 | | Observation | 5 | ## High severity @@ -86,7 +86,7 @@ ### 12. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling **from the budget-policy domain** — copy-pasted verbatim from the `budgetpolicy` package without renaming to the usage-policy equivalents (one would expect `usage-policy-name` etc.). Either (a) the wire really *does* use the `budget-policy-*` prefix (which is a Databricks API design issue worth surfacing), or (b) the JSDoc was lazily duplicated and the actual reserved keys are different. - **Category:** 6 (misleading: cross-domain magic strings that callers must memorise), 12 (duplicate across siblings — but here it's a *bug*, because the reserved keys are not surfaced as constants and may differ from `budgetpolicy`), 18 (long magic string sentinels). -- **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate in marshal step and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. +- **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate the wire payload and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Either way the verbatim duplication smells. ### 13. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` @@ -120,7 +120,7 @@ - **Rationale:** Tied to type rename considerations. If the entity-type were renamed (per finding #1), `policies` could stay; otherwise `usagePolicies` makes the field self-documenting at any depth. ### 18. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` -- **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listUsagePoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. +- **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but the iterator helper only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. Mirrors `budgetpolicy` finding #20. @@ -149,19 +149,13 @@ - **Suggested name:** If full-replace: document on `UpdateUsagePolicyRequest`. If partial-update: add `updateMask?: FieldMask` and a `usagePolicyFieldMask(...paths)` helper to match the sibling. - **Rationale:** A user toggling between the two clones will expect parity. The divergence is silent and unjustified by either docstring. -### 23. `unmarshalUsagePolicySchema` / `marshalUsagePolicySchema` naming pair — `src/v1/model.ts:155,217` -- **Why weird:** "Marshal" and "unmarshal" terms come from Go encoding semantics. JS/TS world uses "serialize" / "deserialize" (or "parse" / "stringify"). Note also `parseResponse`/`marshalRequest` in `utils.ts:113,119` already mix `parse` and `marshal` for the same operation pair. -- **Category:** 14 (Go-style names not idiomatic in TS), 17 (`parseResponse` vs `marshalRequest` mix `parse` and `marshal` for inverse operations). -- **Suggested name:** `serializeUsagePolicy` / `deserializeUsagePolicy`, or `usagePolicyToWire` / `usagePolicyFromWire`. -- **Rationale:** Aligns with broader JS ecosystem (`JSON.parse`/`JSON.stringify`, Zod's `parse`/`safeParse`). Generator-wide concern. - -### 24. `UsagePolicy` lacks the rich constraints documented on `BudgetPolicy.policyName` — `src/v1/model.ts:125` vs `packages/budgetpolicy/src/v1/model.ts:20-25` +### 23. `UsagePolicy` lacks the rich constraints documented on `BudgetPolicy.policyName` — `src/v1/model.ts:125` vs `packages/budgetpolicy/src/v1/model.ts:20-25` - **Why weird:** `BudgetPolicy.policyName` has a four-line JSDoc enumerating constraints: uniqueness, ISO 8859-1 (latin1) charset, reserved-keyword prefix ban. `UsagePolicy.policyName` says only "The name of the policy." If both APIs share the same backend (likely), the usage-policy doc is silently incomplete. If the constraints genuinely differ, the doc should call out the difference. - **Category:** 17 (sibling-package doc divergence for what is plausibly the same constraint), 15 (generic name losing meaning when the constraint set is undocumented). - **Suggested name:** Restore the full constraint doc, or document the deviation. - **Rationale:** This is the kind of divergence that bites users who copy code from one package to the other. -### 25. `ListUsagePoliciesResponse.nextPageToken` / `previousPageToken` docs trimmed vs sibling — `src/v1/model.ts:97-100` +### 24. `ListUsagePoliciesResponse.nextPageToken` / `previousPageToken` docs trimmed vs sibling — `src/v1/model.ts:97-100` - **Why weird:** Docs read: "A token that can be sent as `page_token` to retrieve the next page." and "A token that can be sent as `page_token` to retrieve the previous page." The sibling `budgetpolicy.ListBudgetPoliciesResponse` adds: "If this field is omitted, there are no subsequent pages." / "In this field is omitted, there are no previous pages." Both omission notes are missing here. - **Category:** 17 (inconsistent doc across siblings), 14 (wire-name `page_token` leak in TS doc). - **Suggested name:** Restore the omission notes and fix `page_token` → `pageToken`. @@ -169,67 +163,55 @@ ## Low severity -### 26. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handle different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in `abacpolicies` and `budgetpolicy` audits. Generator-wide. -### 27. `HttpCallOptions` — `src/v1/utils.ts:15` +### 26. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide; same as `budgetpolicy` finding #29. -### 28. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (unmarshal) is the inverse of `marshalRequest`. Naming uses two different verbs (`parse` vs `marshal`) for opposite operations. -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest`, or `parseResponse` / `serializeRequest`. -- **Rationale:** Pair-wise consistency aids reading. Identical to `budgetpolicy` finding #30; the `utils.ts` files are byte-for-byte clones (same 4012-byte size, same code). - -### 29. `readAll` — `src/v1/utils.ts:40` +### 27. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 30. `flattenQueryParams` — `src/v1/utils.ts:123` +### 28. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,217` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package (12+ identical copies in this monorepo). - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 29. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Same as `budgetpolicy` finding #33; generator-wide. -### 32. `Client` class plain name — `src/v1/client.ts:46` +### 30. `Client` class plain name — `src/v1/client.ts:46` - **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-usagepolicy/v1`, they will almost certainly alias it (`import {Client as UsagePolicyClient}`) to avoid collision with `Client` from every other package — including the byte-identical class from `@databricks/sdk-budgetpolicy/v1`. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages, *especially* this one and `budgetpolicy`). - **Suggested name:** `UsagePolicyClient`. - **Rationale:** Each generated package emits a `Client`. With `usagepolicy`/`budgetpolicy` being near-clones, the importer who needs both will be forced into double-aliasing. -### 33. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 31. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` - **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. Same as `budgetpolicy` finding #35. -### 34. `listUsagePoliciesIter` method name — `src/v1/client.ts:193` -- **Why weird:** `Iter` is a cryptic abbreviation for "iterator" / "iterable". Mirrors Go SDK's `Iterator` style. TS convention is to spell out (`...Iterator`) or use a stronger naming convention (`paginate*`, `list*All`). -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `listUsagePoliciesIterator`, or `listAllUsagePolicies`. -- **Rationale:** `Iter` is a Go-style truncation that JS/TS users rarely use. - -### 35. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` +### 32. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` - **Why weird:** "it's" should be "its" (possessive). Same grammatical mistake appears in `budgetpolicy/src/v1/client.ts:120` ("Retrieves a policy by it's ID.") — copy-pasted across the clones. - **Category:** Observation (grammar). - **Suggested name:** Fix to "its". - **Rationale:** Surfaces in editor hovers; small but persistent. -### 36. `listUsagePolicies` JSDoc verbatim duplicates sibling — `src/v1/client.ts:145` +### 33. `listUsagePolicies` JSDoc verbatim duplicates sibling — `src/v1/client.ts:145` - **Why weird:** "Lists all usage policies. Policies are returned in the alphabetically ascending order of their names." Word-for-word translation of the budgetpolicy version with `usage` substituted. Same finding for the rest of the method docstrings — they're all `s/budget/usage/` substitutions with no domain-specific guidance. - **Category:** Observation, 12 (cross-package boilerplate). - **Suggested name:** Keep, but worth flagging that the package ships zero domain-specific guidance — every per-method doc is a clone with substitution. @@ -237,23 +219,23 @@ ## Observations -### 37. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference +### 34. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. - **Category:** 12 (duplicate concept), 1 (vague package boundary). -### 38. No `FieldMask` import in `usagepolicy/src/v1/model.ts` +### 35. No `FieldMask` import in `usagepolicy/src/v1/model.ts` Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #22 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. - **Category:** Observation / 17 (cross-package inconsistency). -### 39. Action-verb conventions in `Client` +### 36. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 40. Acronym casing `Id` consistently used as `Id`, not `ID` +### 37. Acronym casing `Id` consistently used as `Id`, not `ID` `policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). - **Category:** 3 (observation — internal acronym style is consistent). -### 41. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) +### 38. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) The same identifier appears in three forms in the same client file: - `usage_policies` — wire form (in the Zod schemas via snake_case keys). - `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index 7d1b7e96..806efe94 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -12,9 +12,9 @@ Notation: file paths are absolute. Findings reference `file:line`. | ----------- | ----- | | High | 4 | | Medium | 7 | -| Low | 7 | +| Low | 6 | | Observation | 8 | -| **Total** | **26** | +| **Total** | **25** | Headline themes: @@ -60,13 +60,10 @@ Headline themes: field maps to a URL path argument." TypeScript callers have no concept of "Arg" — they just see two fields named `fullNameArg` and (on the related `VolumeInfo` / `UpdateVolume` payload) `fullName`, with no way - to know they refer to the same volume identifier. The marshal schema - (`model.ts:358, 379`) further serializes this as `full_name_arg`, which - is a non-standard JSON key the server is unlikely to consume — the URL - templating in `client.ts:125, 154, 268` interpolates it into the path - directly, so the marshal entry is dead. The `?: | undefined` is also a - semantic lie — without this value the path becomes - `/api/2.1/unity-catalog/volumes/` and the call cannot succeed. + to know they refer to the same volume identifier. The URL templating in + `client.ts:125, 154, 268` interpolates it into the path directly. The + `?: | undefined` is also a semantic lie — without this value the path + becomes `/api/2.1/unity-catalog/volumes/` and the call cannot succeed. ### H2. `Create*` / `Update*` request types include server-only fields @@ -87,10 +84,8 @@ Headline themes: `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, and `volumeId` invites users to populate them — but the server ignores or rejects them. The `client.ts:262` doc itself says "Currently only the name, the - owner or the comment of the volume could be updated." Marshal schemas - at `model.ts:289–328` and `model.ts:356–398` faithfully serialize these - fields, padding every request body. Compare with the Go SDK - `databricks/sdk-go/databricks/api/volumes/v1/` to confirm the + owner or the comment of the volume could be updated." Compare with the + Go SDK `databricks/sdk-go/databricks/api/volumes/v1/` to confirm the upstream split. (Caveat: if the upstream proto truly reuses the same message for request + response, the audit recommends a TS-specific request type — name suggestions: `CreateVolumeRequest`, @@ -289,25 +284,11 @@ field-naming style response body, with different types (`Uint8Array`, `string | ReadableStream`). - **Suggestion:** `responseBody` / `requestBody`. -- **Rationale:** In `client.ts:94, 269` we see `const body = - marshalRequest(...)` (a request body) passed into `buildHttpRequest` - while inside `executeHttpCall` the `body` is a response payload. +- **Rationale:** The same identifier `body` flows through helpers as a + request payload in one place and a response payload in another. Differentiating helps readers track direction. -### L4. `marshalRequest` accepts `data: unknown` — the parameter name -contradicts the function's purpose - -- **File / line:** `src/v1/utils.ts:119`. -- **Category:** #15 generic field name losing meaning. -- **Current:** `function marshalRequest(data: unknown, schema: z.ZodType)`. -- **Suggestion:** `function marshalRequest(request: unknown, schema)` or - `(payload, schema)`. -- **Rationale:** The function name says "request"; the first argument - is named `data`. Calling at `client.ts:94, 269` reads - `marshalRequest(req, marshalCreateVolumeSchema)` — `req` → `data` loses - the request semantics in the helper. - -### L5. `flattenQueryParams` is dead code in this package +### L4. `flattenQueryParams` is dead code in this package - **File / line:** `src/v1/utils.ts:123`. - **Category:** dead code. @@ -319,7 +300,7 @@ contradicts the function's purpose scope for pure naming but flagged because the name promises a feature that no method exercises. -### L6. `fullName` (on `VolumeInfo`) vs. `fullNameArg` (on path-param +### L5. `fullName` (on `VolumeInfo`) vs. `fullNameArg` (on path-param requests) - **File / line:** `model.ts:36, 75, 126, 148, 186` (`fullName` on @@ -331,14 +312,13 @@ requests) request/response position. - **Suggestion:** Resolve in concert with H1 — use `fullName` everywhere. If proto generation requires the `_Arg` discriminator, then bury it - internally (in the marshal schema) and surface only `fullName` to - callers. + internally and surface only `fullName` to callers. - **Rationale:** A user reading the API sees `fullName` on `VolumeInfo` and `fullNameArg` on `DeleteVolume` and has to ask: why are they different? The answer ("one is a request path parameter") is generator-internal and should not bleed onto the public surface. -### L7. `pageReq` and `pageReq.pageToken` mutation in `listVolumesIter` +### L6. `pageReq` and `pageReq.pageToken` mutation in `listVolumesIter` - **File / line:** `src/v1/client.ts:242–252`. - **Category:** #1 vague/generic. @@ -456,38 +436,27 @@ Type & symbol checklist: - [x] `SseEncryptionAlgorithm` enum (3 members) → O3. - [x] `VolumeType` enum (2 members) → O6 (clean). - [x] `CreateVolume` interface (17 fields) → H2, M1, M5, M6. -- [x] `DeleteVolume` interface (1 field) → H1, M1, L6. +- [x] `DeleteVolume` interface (1 field) → H1, M1, L5. - [x] `DeleteVolume_Response` empty interface → H3. - [x] `EncryptionDetails` interface → no additional defect. -- [x] `GetVolume` interface (2 fields) → H1, M1, L6. +- [x] `GetVolume` interface (2 fields) → H1, M1, L5. - [x] `ListVolumes` interface (5 fields) → M1. - [x] `ListVolumes_Response` interface (2 fields) → H4. - [x] `SseEncryptionDetails` interface (2 fields) → M3, M4, M5. -- [x] `UpdateVolume` interface (18 fields) → H1, H2, M1, M5, M6, L6. -- [x] `VolumeInfo` interface (16 fields) → M2, M5, M6, L6, O4. -- [x] `unmarshalDeleteVolume_ResponseSchema` → H3. -- [x] `unmarshalEncryptionDetailsSchema` → no additional defect. -- [x] `unmarshalListVolumes_ResponseSchema` → H4. -- [x] `unmarshalSseEncryptionDetailsSchema` → no additional defect. -- [x] `unmarshalVolumeInfoSchema` → no additional defect. -- [x] `marshalCreateVolumeSchema` → H2. -- [x] `marshalEncryptionDetailsSchema` → no additional defect. -- [x] `marshalSseEncryptionDetailsSchema` → no additional defect. -- [x] `marshalUpdateVolumeSchema` → H1 (`full_name_arg` key), H2. +- [x] `UpdateVolume` interface (18 fields) → H1, H2, M1, M5, M6, L5. +- [x] `VolumeInfo` interface (16 fields) → M2, M5, M6, L5, O4. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → O8. - [x] `createVolume(req, options)` method → H2, M1, M7, L2. - [x] `deleteVolume(req, options)` method → H1, H3, M1, M7, L2. - [x] `getVolume(req, options)` method → H1, M1, M7, L2. - [x] `listVolumes(req, options)` method → H4, M1, M7, L2. -- [x] `listVolumesIter(req, options)` async generator → M1, M7, L7. +- [x] `listVolumesIter(req, options)` async generator → M1, M7, L6. - [x] `updateVolume(req, options)` method → H1, H2, M1, M7, L2. - [x] `HttpCallOptions` interface → no defect. - [x] `executeCall` function → L1. - [x] `readAll` private function → no defect (name fits idiom). - [x] `executeHttpCall` function → L1, L3. - [x] `buildHttpRequest` function → L3. -- [x] `parseResponse` function → no defect. -- [x] `marshalRequest` function → L4. -- [x] `flattenQueryParams` function → L5 (unused). +- [x] `flattenQueryParams` function → L4 (unused). - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index 74d5fa05..13928f7a 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -13,11 +13,10 @@ This audit applies the 20 numbered concern categories from the audit checklist. Each finding lists the offending identifier(s), the category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename suggestion. Findings are grouped by category. Generator-driven -items (such as `_Response` underscore on proto-style nested messages -and the `marshal`/`unmarshal` schema prefixes) are flagged as `LOW` -because they are codified across the entire generated SDK surface — -they should be fixed at the generator, not by hand-editing this -package. +items (such as `_Response` underscore on proto-style nested messages) +are flagged as `LOW` because they are codified across the entire +generated SDK surface — they should be fixed at the generator, not by +hand-editing this package. **Special historical context:** SQL Warehouses were renamed from "SQL Endpoints" (legacy term). The proto definitions still use @@ -200,7 +199,7 @@ compatibility while updating the customer-visible type names. `jdbcUrl`, `numClusters`, etc.), but the type is named `EndpointInfo`. Same root concept as `GetWarehouse_Response`, which has identical field set — so the type name should - match. "Info" is a Go-ism (see F14.2). + match. - **Suggestion:** Rename to `Warehouse` (the resource itself) or `WarehouseInfo` if backward parity matters. Mirror `GetWarehouse_Response` shape into a single canonical type @@ -561,22 +560,6 @@ compatibility while updating the customer-visible type names. `EditWarehouseResponse`, etc. — this matches the convention used by the rest of the JS SDK for top-level types. -#### F4.2 — Schema names inherit the underscore (HIGH, generator-driven) -- **Where:** - - `unmarshalCreateWarehouse_ResponseSchema` (`model.ts:1525`) - - `unmarshalEditWarehouseRequest_ResponseSchema` (`model.ts:1550`) - - `unmarshalGetWarehouse_ResponseSchema` (`model.ts:1646`) - - `unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema` (`model.ts:1694`) - - `unmarshalSetWorkspaceWarehouseConfigRequest_ResponseSchema` (`model.ts:1774`) - - `unmarshalDeleteWarehouseRequest_ResponseSchema` (`model.ts:1800`) - - `unmarshalListWarehousesRequest_ResponseSchema` (`model.ts:1804`) - - `unmarshalStartRequest_ResponseSchema` (`model.ts:1816`) - - `unmarshalStopRequest_ResponseSchema` (`model.ts:1820`) -- **Why flagged:** Same root cause as F4.1. Schema identifiers - carry the underscore. -- **Suggestion:** Generator-level. Drop underscore when - generating schema names. - --- ### 5. Cryptic abbreviations @@ -736,20 +719,8 @@ compatibility while updating the customer-visible type names. - **Suggestion:** Acceptable; AIP-compliant. Aliasing at the call site is the typical workaround. -#### F7.2 — `marshalSetWorkspaceWarehouseConfigRequestSchema` and -`unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema` (LOW) -- **Where:** `model.ts:1694, 1953`. 51 and 51 characters - respectively. -- **Why flagged:** Schema names approach 60 chars and contain - every part of the wire name. Generator-driven; readability is - poor. -- **Suggestion:** Generator-level. Could shorten by dropping - the `Request_Response` chain to just `Response`: - `unmarshalGetWorkspaceWarehouseConfigResponseSchema`. - -#### F7.3 — `defaultWarehouseOverrideFieldMaskSchema`, -`defaultWarehouseOverrideFieldMask` (LOW) -- **Where:** `model.ts:2015, 2022`. +#### F7.2 — `defaultWarehouseOverrideFieldMask` (LOW) +- **Where:** `model.ts:2022`. - **Why flagged:** Long, but consistent with the AIP-style resource name. Acceptable. @@ -799,25 +770,10 @@ compatibility while updating the customer-visible type names. `WarehouseTypeAvailability` (or similar) — wire-aligned but semantically clearer than the `Pair` suffix. -#### F8.4 — `Info` suffix on `EndpointInfo` (HIGH, Go-ism) -- **Where:** `model.ts:1006`. -- **Why flagged:** "Info" is a Go-ism — it carries no - semantic value in TS. See category 14. -- **Suggestion:** Rename to `Warehouse`. Aligns with F1.1. - -#### F8.5 — `_Response` underscore suffix (HIGH, generator-driven) +#### F8.4 — `_Response` underscore suffix (HIGH, generator-driven) - Covered in F4.1. -#### F8.6 — `Request_Response` chain in schema names (HIGH, generator-driven) -- Covered in F4.2. - -#### F8.7 — `Schema` suffix on every schema (LOW, generator-driven) -- **Where:** All `marshal*Schema`, `unmarshal*Schema` exports. -- **Why flagged:** `Schema` is a Zod-specific convention; not - inherently bad, but redundant with the `marshal`/`unmarshal` - prefix. Acceptable. - -#### F8.8 — `Params` suffix on `OdbcParams` (LOW) +#### F8.5 — `Params` suffix on `OdbcParams` (LOW) - **Where:** `model.ts:1329`. - **Why flagged:** Mild noise. Type has `hostname`, `path`, `protocol`, `port` — `OdbcConnectionInfo` would be more @@ -909,9 +865,7 @@ _None. Wrappers are retained for forward compatibility._ identical fields). One is the per-warehouse record in `listWarehouses`, the other is the result of `getWarehouse`. Duplicating the shape across two types means every change has - to happen in two places. Note also `unmarshalEndpointInfoSchema` - (`model.ts:1579`) and `unmarshalGetWarehouse_ResponseSchema` - (`model.ts:1646`) are nearly identical Zod schemas. + to happen in two places. - **Suggestion:** Collapse into one type (call it `Warehouse`). `GetWarehouse_Response = Warehouse`. `EndpointInfo` removed. Generator-level. @@ -1005,32 +959,17 @@ _None. Wrappers are retained for forward compatibility._ within the same method signature. - **Suggestion:** Generator-level. -#### F14.2 — `Info` suffix on types (Go-ism) (HIGH) -- **Where:** `EndpointInfo` (`model.ts:1006`). -- **Why flagged:** Go has `ClusterInfo`, `JobInfo`, etc. TS - prefers the bare noun (`Cluster`, `Job`). `Info` is a - Go-ism. -- **Suggestion:** Rename to `Warehouse`. - -#### F14.3 — `Repeated` proto-prefix (LOW) +#### F14.2 — `Repeated` proto-prefix (LOW) - Covered in F13.2. -#### F14.4 — `Params` suffix on types (Java-ish) (LOW) -- `OdbcParams` — minor. See F8.8. +#### F14.3 — `Params` suffix on types (Java-ish) (LOW) +- `OdbcParams` — minor. See F8.5. -#### F14.5 — `Pair` suffix (Java-ish) (LOW) +#### F14.4 — `Pair` suffix (Java-ish) (LOW) - `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair`. Covered in F8.3. -#### F14.6 — `marshal*` / `unmarshal*` prefixes are protobuf/Go vocabulary (LOW, generator-driven) -- **Where:** All schema exports. -- **Why flagged:** JS/TS commonly uses `serialize`/`deserialize`, - `encode`/`decode`, or `toJson`/`fromJson`. "Marshal" is - Go/protobuf. -- **Suggestion:** Cross-cutting; generator-level. Out of scope - for this package's audit. - -#### F14.7 — `for (;;)` C-style infinite loop (LOW, generator-driven) +#### F14.5 — `for (;;)` C-style infinite loop (LOW, generator-driven) - **Where:** `client.ts:405, 462`, `utils.ts:48`. - **Why flagged:** `for (;;)` is C/Go idiom; TS prefers `while (true)` for readability. Minor. @@ -1312,16 +1251,15 @@ _None. Wrappers are retained for forward compatibility._ ### Highest-leverage fixes 1. **Resolve the `Endpoint*` legacy naming (F0, F1.1-F1.6, - F6.1-F6.5, F8.4, F14.2, F12.4)** — rename every `Endpoint*` - type to `Warehouse*` to align with the customer brand. Single - biggest fix; cleans up ~10 type names and the entire - marshal/unmarshal schema family. + F6.1-F6.5, F12.4)** — rename every `Endpoint*` type to + `Warehouse*` to align with the customer brand. Single biggest + fix; cleans up ~10 type names across the package. 2. **Resolve `Edit` vs. `Update` (F17.1)** — pick one verb for "modify resource" across the SDK; standardize wire and TS. 3. **Strip redundant enum prefixes (F2.1, F2.2, F2.3, F2.4, F2.5)** — `ChannelName.CHANNEL_NAME_PREVIEW` etc. Trivial generator-level fix; massive readability win. -4. **Drop `_Response` underscore convention (F4.1, F4.2)** — +4. **Drop `_Response` underscore convention (F4.1)** — namespace or naked concatenation. Generator-level. 5. **Collapse duplicate types (F12.1, F12.2, F12.3)** — `EndpointInfo` + `GetWarehouse_Response`, @@ -1331,9 +1269,9 @@ _None. Wrappers are retained for forward compatibility._ ### Recurring themes - **Generator-driven proto-isms** (`Repeated`, `_Response`, - `marshal`/`unmarshal`, `req`/`resp`, `for(;;)`) are the - largest single category. Most are LOW because they are - consistent across the entire SDK; fix at the generator. + `req`/`resp`, `for(;;)`) are the largest single category. + Most are LOW because they are consistent across the entire + SDK; fix at the generator. - **Legacy `Endpoint*` naming** is the package-specific issue. It causes the most readability harm because the package brand is "warehouse" while half the types still say diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md index 6ba019d5..c48c056a 100644 --- a/.agent/naming-audit/workspace.md +++ b/.agent/naming-audit/workspace.md @@ -269,7 +269,7 @@ directDownload?: boolean | undefined; `directDownload` reads as a noun phrase ("the direct download"), but it's a boolean flag controlling response shape. Booleans are usually named with `is`/`has`/`should` prefixes or as adjectives. `streamBinary` or `responseAsBinary` would parse as a flag. -The flag also has a semantic problem: when `true`, the response body is raw bytes; when `false`, the response body is a JSON object with base64. So the field changes the entire response content type, but the generated client (`export` method) parses the response identically in both cases (via `unmarshalExport_ResponseSchema`). The schema only handles the base64 case. Setting `directDownload: true` would crash the parser. +The flag also has a semantic problem: when `true`, the response body is raw bytes; when `false`, the response body is a JSON object with base64. So the field changes the entire response content type, but the generated client (`export` method) parses the response identically in both cases. Setting `directDownload: true` would crash the parser. ### 13. `Export_Response.fileType` — underspecified @@ -296,7 +296,7 @@ The doc says "the file type" but doesn't say in what form. Is it the extension ( content?: Uint8Array | undefined; ``` -The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw bytes). The unmarshaller (`unmarshalExport_ResponseSchema:225`) does the base64 decode itself, so the field actually holds decoded bytes, contradicting the JSDoc. The JSDoc was lifted from the wire format documentation and not updated for the post-decode TS shape. A reader holding the type sees "Uint8Array of base64-encoded data," which is technically meaningless (Uint8Arrays are bytes, not base64). +The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw bytes). The client decodes base64 before populating this field, so the field actually holds decoded bytes, contradicting the JSDoc. The JSDoc was lifted from the wire format documentation and not updated for the post-decode TS shape. A reader holding the type sees "Uint8Array of base64-encoded data," which is technically meaningless (Uint8Arrays are bytes, not base64). ### 15. `Import.content` typed `Uint8Array` with "base64-encoded" doc @@ -311,7 +311,7 @@ The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw byte content?: Uint8Array | undefined; ``` -Mirror of finding 14 in the reverse direction. The marshaller (`marshalImportSchema:289-293`) encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. +Mirror of finding 14 in the reverse direction. The client encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. ### 16. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision @@ -556,8 +556,6 @@ RAW = 'RAW', 9. **Sentinel `OBJECT_TYPE_UNSPECIFIED` documented as "only used by list-repo."** The enum exports a value that the package consumers should never set but cannot remove without breaking the read side. A separate response-only enum or a `null` for "unknown" would be cleaner. -10. **`utils.ts` is shared boilerplate.** The exported helpers (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are not flagged — they are well-named. `flattenQueryParams` is exported but unused in `client.ts` (this package has no nested-object query parameters); orphaned export. No domain naming surface in this file. - ## Domain glossary | Term | Meaning in this package | diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md index ea0d7e9f..ee1c7b52 100644 --- a/.agent/naming-audit/workspaceassignment.md +++ b/.agent/naming-audit/workspaceassignment.md @@ -3,15 +3,15 @@ **Path:** `packages/workspaceassignment/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level workspace permission assignments — list/get/update/delete the `USER`/`ADMIN` permissions a principal (user / service principal / group) has on a single workspace, plus list the catalog of workspace-level permission values supported. -**Total weird names flagged:** 36 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 14 | -| Low | 8 | -| Observation | 3 | +| High | 9 | +| Medium | 12 | +| Low | 6 | +| Observation | 1 | ## High severity @@ -39,37 +39,25 @@ - **Suggested name:** `DeleteWorkspacePermissionAssignmentRequest` (and the parallel `Get…Request`, `List…Request`, `Update…Request`). - **Rationale:** The iam package uses the `Request` suffix consistently (`DeleteWorkspaceAssignmentDetailRequest`, `UpdateWorkspaceAssignmentDetailRequest`, ...). The local convention here disagrees with the sibling package modelling the same domain. -### 5. `DeleteWorkspacePermissionAssignment_Response` underscored name — `src/v1/model.ts:23` -- **Why weird:** Underscore in identifier (proto-style nested type). Requires `eslint-disable @typescript-eslint/naming-convention` (line 22). -- **Category:** 4 (underscores), 14 (Go/proto-style names). -- **Suggested name:** `DeleteWorkspacePermissionAssignmentResponse`. -- **Rationale:** TS naming rule rejects `Foo_Bar`. The ESLint suppression is a tell that the name fights the language. - -### 6. `GetWorkspacePermissionAssignments_Response` / `ListWorkspacePermissions_Response` underscored names — `src/v1/model.ts:40,58` -- **Why weird:** Same `Foo_Response` underscore proto pattern, both flagged with `eslint-disable @typescript-eslint/naming-convention`. The unmarshal schemas (lines 125, 129, 145) also share the underscore. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). -- **Suggested name:** `GetWorkspacePermissionAssignmentsResponse`, `ListWorkspacePermissionsResponse` (and the corresponding `unmarshal…ResponseSchema`). -- **Rationale:** TS naming rule rejects `Foo_Bar`. The ESLint suppressions are tells that the names fight the language. Other sibling packages have already moved off the underscore convention in their newer versions; this one trails. - -### 7. `GetWorkspacePermissionAssignments` request type for an HTTP `GET` that returns a *list* — `src/v1/model.ts:26`, `src/v1/client.ts:102` +### 5. `GetWorkspacePermissionAssignments` request type for an HTTP `GET` that returns a *list* — `src/v1/model.ts:26`, `src/v1/client.ts:102` - **Why weird:** The method `getWorkspacePermissionAssignments` returns a paginated list (`permissionAssignments`, `nextPageToken`, `prevPageToken`) — that is a `list` operation, not a `get`. Compare to `iam.ListWorkspaceAssignmentDetailsRequest` (same domain, different verb). Mislabelling pagination as "get" leads users to expect a single object back. - **Category:** 6 (misleading verb), 13 (verb-tense inconsistency — `Get` for a list result), 17 (verb inconsistency with iam mirror). - **Suggested name:** `ListWorkspacePermissionAssignmentsRequest` / `…Response`, method `listWorkspacePermissionAssignments`. - **Rationale:** Pagination fields make this unambiguously a list. The current name reads as "get the assignments for this workspace" — singular intent, plural body — and is inconsistent with `iam.ListWorkspaceAssignmentDetails`. -### 8. `ListWorkspacePermissions` returns a static catalog, not data — `src/v1/model.ts:50`, `src/v1/client.ts:142` +### 6. `ListWorkspacePermissions` returns a static catalog, not data — `src/v1/model.ts:50`, `src/v1/client.ts:142` - **Why weird:** `listWorkspacePermissions` returns the (fixed) catalog of `PermissionOutput` values (`USER`, `ADMIN`, ...) that the workspace supports. The Go SDK has identical confusion: every method called `list…` looks like it lists user data, but here it lists the *types of permissions that exist*. Plus the method appears side-by-side with `getWorkspacePermissionAssignments` (which actually lists assignments), so users will wire the wrong one. - **Category:** 6 (misleading — name implies data, returns metadata), 15 (generic field `permissions` losing meaning). - **Suggested name:** `ListAssignablePermissionsRequest` / `listAssignablePermissions`, or `GetSupportedWorkspacePermissions` / `getSupportedWorkspacePermissions`. Either makes the metadata nature explicit. - **Rationale:** `listWorkspacePermissions(req)` vs `getWorkspacePermissionAssignments(req)` are visually similar enough that someone scanning autocomplete will pick the wrong one. The semantic gulf between them (catalog vs assignments) demands distinct verbs. -### 9. `PermissionOutput` / `PrincipalOutput` / `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:63,70,115` +### 7. `PermissionOutput` / `PrincipalOutput` / `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:63,70,115` - **Why weird:** `Output` suffix is a generic noise word that adds zero information — every response shape is "output". The Go SDK uses `Output` because protobuf service definitions use `Output` as a request/response naming convention; in TS this surfaces as `Permission` vs `PermissionOutput`, two near-identical types differing only by the field semantics. The doc comment on `WorkspacePermissionAssignmentOutput` even spells it out: "The output format for existing workspace PermissionAssignment records". A name that needs the doc string to say "this is the output type" is the symptom. - **Category:** 1 (vague suffix), 8 (redundant type suffix), 14 (proto/Go naming). - **Suggested name:** Drop the `Output` suffix. `Permission` (the enum) and `PermissionDetail`/`PermissionDescription` (the wrapper carrying `description`) is one option; `WorkspacePermissionAssignment`, `Principal`, `PermissionDescriptor` is another. The iam mirror dropped `Output` already (`WorkspaceAssignmentDetail`, not `WorkspaceAssignmentDetailOutput`). - **Rationale:** Cf. rule 1 of the audit list ("vague/generic"). `Output` carries no semantics and conflicts with the sibling type in the same package. -### 10. `WorkspacePermissionAssignmentOutput` vs `iam.WorkspaceAssignmentDetail` duplicate concept — `src/v1/model.ts:115` vs `packages/iam/src/v2/model.ts:983` +### 8. `WorkspacePermissionAssignmentOutput` vs `iam.WorkspaceAssignmentDetail` duplicate concept — `src/v1/model.ts:115` vs `packages/iam/src/v2/model.ts:983` - **Why weird:** Two TS types modelling the same conceptual record: - `WorkspacePermissionAssignmentOutput` (here): `{ principal: PrincipalOutput, permissions: Permission[], error: string }`. - `iam.WorkspaceAssignmentDetail`: `{ principalId, workspaceId, accountId, principalType, entitlements }`. @@ -79,7 +67,7 @@ - **Suggested name:** Reconcile with iam. If the workspaceassignment API is older/account-level and iam is workspace-level, document that explicitly; if they overlap functionally, ship one shape and re-export from both packages. - **Rationale:** This package is a tiny 4-method surface; living without a consistent type with iam is sustainable, but every SDK consumer will need to bridge the two by hand. -### 11. `PrincipalOutput.principalName` discriminated union — `src/v1/model.ts:71-87` +### 9. `PrincipalOutput.principalName` discriminated union — `src/v1/model.ts:71-87` - **Why weird:** The discriminator field is named `principalName` and each variant carries its own typed sub-field (`userName`, `groupName`, `servicePrincipalName`). The variant tag values are also full identifier strings (`'userName' | 'groupName' | 'servicePrincipalName'`). The result is access like `principal.principalName.userName` — three name-words in a row. The actual `displayName` is a *separate* sibling field two lines down, so the structure conflates "what kind of principal is it?" with "what is its identifier?". The iam package handles the same idea more cleanly via a `principalType: PrincipalType` enum + a single `principalId: number` field. - **Category:** 5 (cryptic / redundant), 11 (wrapper around oneof), 12 (duplicate of `iam.PrincipalType` mechanism), 15 (generic field names lose meaning when nested). - **Suggested name:** `principalType: PrincipalType` enum + flatten the identifier to a single string field (or per-variant fields at the top level). Match the iam approach. @@ -87,162 +75,126 @@ ## Medium severity -### 12. `accountId` doc comment "The account ID." — `src/v1/model.ts:14,28,51,95` +### 10. `accountId` doc comment "The account ID." — `src/v1/model.ts:14,28,51,95` - **Why weird:** Doc is uniformly terse — "The account ID." Doesn't say whether it's a UUID, an integer, that it falls back to `ClientOptions.accountId` (per `client.ts:46-48`), that it's required for the URL path, or that it gets URL-injected and not query-parameterised. The same field appears in four request types with the same too-thin doc. - **Category:** 19 (underspecified ID). - **Suggested name:** Keep `accountId`, rewrite doc to `"Databricks account ID (UUID). If omitted on the request, falls back to ClientOptions.accountId. Required at request time — the SDK substitutes an empty string into the URL path if neither is set."` - **Rationale:** This is the only ID that has a client-side fallback mechanism. Hiding that in a comment three files away is a footgun. -### 13. `workspaceId?: number` typed as `number` — `src/v1/model.ts:17,30,53,97` +### 11. `workspaceId?: number` typed as `number` — `src/v1/model.ts:17,30,53,97` - **Why weird:** Workspace IDs in Databricks are 64-bit integers; JS `number` loses precision above 2^53. Same problem on `principalId` (`number` too — model.ts:19,89,99). The client also unconditionally `String(req.workspaceId ?? '')`s the value into the URL (`client.ts:78,106,146,174`), implying string semantics are sufficient — meaning `number` was the wrong primitive to begin with. - **Category:** 16 (field type contradicts domain), 19 (underspecified ID). - **Suggested name:** Keep `workspaceId`, type as `bigint | string` (or `string` to match the URL serialisation). - **Rationale:** Public Databricks workspace IDs cross 2^53 in account-level deployments; silent rounding bugs are a real risk. Same concern applies to `principalId`. -### 14. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:42 vs 60,119` +### 12. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:42 vs 60,119` - **Why weird:** `GetWorkspacePermissionAssignments_Response.permissionAssignments` is the list of assigned-principal records (with role). `ListWorkspacePermissions_Response.permissions` is the list of *permission types*. `WorkspacePermissionAssignmentOutput.permissions` is the *roles a single principal holds*. Three different things, two of them just called `permissions`. - **Category:** 1 (vague), 15 (generic field name loses meaning), 17 (inconsistent label across siblings). - **Suggested name:** On `ListWorkspacePermissions_Response`, rename `permissions` to `supportedPermissions` or `availablePermissions`. On `WorkspacePermissionAssignmentOutput`, rename `permissions` to `permissionLevels` or `grantedPermissions` to match the singular `permissionLevel` in `PermissionOutput`. - **Rationale:** A user holding the response sees `.permissions` and can't tell whether it's "permissions held" or "permission types defined". -### 15. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:64 vs 119` +### 13. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:64 vs 119` - **Why weird:** The same `Permission` enum is held as singular on one type (`permissionLevel: Permission`) and plural on another (`permissions: Permission[]`). The lexical difference is significant (`level` vs no suffix) and inconsistent across the package. Internal users won't know whether to think of permissions as a scalar or set. - **Category:** 9 (singular/plural inconsistency), 17 (inconsistent action verb / field name). - **Suggested name:** Settle on one shape: if a principal can hold multiple levels, use `permissionLevels: Permission[]` everywhere. If `PermissionOutput` is really just describing a single level, name it `permission` (singular, matching the type). - **Rationale:** `permissionLevel` and `permissions` are both `Permission`-typed; the asymmetry has no semantic justification visible in this file. -### 16. `WorkspacePermissionAssignmentOutput.error?: string` — `src/v1/model.ts:121` +### 14. `WorkspacePermissionAssignmentOutput.error?: string` — `src/v1/model.ts:121` - **Why weird:** Embedding an opaque error string inside the success response body. The pattern is "we succeeded enough to return data, but here's a per-record error message". This is unusual: typical SDK design surfaces errors as exceptions or as a typed error union. A bare `string` carrying potentially structured error content forces the user to parse strings. Also, `error` is a reserved-ish JS identifier (global `Error` class, `try/catch` `error` parameter) and clashes with style. - **Category:** 1 (vague), 10 (reserved-word-adjacent), 15 (generic field loses meaning), 16 (field contradicting type — a success response carrying error data). - **Suggested name:** `errorMessage` or `partialFailureReason`, typed as `string | undefined`. Better: model the assignment as `{ ok: true, data: ... } | { ok: false, error: ... }`. - **Rationale:** The current shape leaks the per-record-error nature of the upstream API. At minimum rename to make the partial-failure semantics explicit. -### 17. `PermissionOutput.description` doc comment "The results of a permissions query." — `src/v1/model.ts:65-66` +### 15. `PermissionOutput.description` doc comment "The results of a permissions query." — `src/v1/model.ts:65-66` - **Why weird:** Doc string is meaningless — "description" labelled as "results of a permissions query" gives the reader zero signal about what the string contains. Looking at the upstream this likely contains a human-readable description like "Allows full access" or "Read-only access". - **Category:** 1 (vague — both field and doc). - **Suggested name:** Keep `description`, rewrite doc to `"Human-readable description of what this permission grants (for example, 'Allows full administrative access to the workspace')."`. - **Rationale:** The current JSDoc is worse than no doc at all because it suggests the field is a query-result wrapper. -### 18. `PrincipalOutput.principalName` discriminator tag values use camelCase — `src/v1/model.ts:73,78,83` +### 16. `PrincipalOutput.principalName` discriminator tag values use camelCase — `src/v1/model.ts:73,78,83` - **Why weird:** `$case` values are `'userName' | 'groupName' | 'servicePrincipalName'` — those are *field names*, not discriminator tags. A discriminator value should describe the *type* of the variant (`'user' | 'group' | 'servicePrincipal'`), not duplicate the field name. The current shape forces `principalName.userName` ("user name's user name"). - **Category:** 5 (cryptic — discriminator tag duplicates the field), 11 (trivial wrapper-around-oneof). - **Suggested name:** Tag values `'user' | 'group' | 'servicePrincipal'`, payload field `name: string` across all three variants. Or flatten to enum + single string. - **Rationale:** Discriminator should let `switch (p.principalName.$case)` read as `case 'user':` rather than `case 'userName':`. -### 19. `PrincipalOutput.principalId: number` opaque ID doc — `src/v1/model.ts:88-89` +### 17. `PrincipalOutput.principalId: number` opaque ID doc — `src/v1/model.ts:88-89` - **Why weird:** Doc reads "The unique, opaque id of the principal." with `id` lowercase mid-sentence and no casing on the field. The same field on `DeleteWorkspacePermissionAssignment` / `UpdateWorkspacePermissionAssignment` (model.ts:19,99) is documented as `"The ID of the user, service principal, or group."` — same concept, two different docs. Also `number` typing same precision issue as workspaceId. - **Category:** 16 (field type contradicts domain), 17 (inconsistent doc across sibling types), 19 (underspecified ID). - **Suggested name:** Keep `principalId`, type as `bigint | string`, and use one consistent doc: `"Unique numeric identifier of the principal (user / service principal / group)."`. - **Rationale:** Three call sites for the same field, three slightly different definitions, plus a precision risk. -### 20. `UpdateWorkspacePermissionAssignment.permissions` doc paragraph — `src/v1/model.ts:101-107` +### 18. `UpdateWorkspacePermissionAssignment.permissions` doc paragraph — `src/v1/model.ts:101-107` - **Why weird:** A six-line JSDoc smuggling validation semantics into a public field comment: "If both 'USER' and 'ADMIN' are provided, 'ADMIN' takes precedence. Other values will be ignored. Note that excluding this field, or providing unsupported values, will have the same effect as providing an empty list, which will result in the deletion of all permissions for the principal." That last clause is a *destructive* behaviour hidden in a paragraph. Field name `permissions` plus this doc gives the field a meaning of "set or delete" depending on contents — too much overloading for one field. - **Category:** 1 (vague — overloaded semantics), 6 (misleading — looks like an additive update, can be destructive). - **Suggested name:** Either split into `setPermissions: Permission[]` / `clearPermissions: boolean`, or rename to `replacePermissions` with explicit doc "Replaces all permissions on the principal. Pass an empty array (or omit) to revoke all permissions." - **Rationale:** Hiding a "delete everything" behaviour behind an empty/missing field is a destructive-by-omission API. Type signature should make it visible. -### 21. `PrincipalOutput.principalName.servicePrincipalName: string` — `src/v1/model.ts:83-86` +### 19. `PrincipalOutput.principalName.servicePrincipalName: string` — `src/v1/model.ts:83-86` - **Why weird:** A service principal's name is here typed as `string`, but the `iam` package treats service principals as either a `principalType: PrincipalType.SERVICE_PRINCIPAL` enum value or by `applicationId`. The string-only name representation here disagrees with iam's identifier model. - **Category:** 12 (duplicate concept with iam.PrincipalType.SERVICE_PRINCIPAL), 17 (inconsistent representation across siblings). - **Suggested name:** Align with iam: principalType enum + a single name/id field. If kept, rename the variant to `name` so it reads `principal.principalName.$case === 'servicePrincipal' && principal.principalName.name`. - **Rationale:** Two packages, two shapes for "the name of a service principal" — pick one. -### 22. `nextPageToken` / `prevPageToken` asymmetric naming — `src/v1/model.ts:44,46` +### 20. `nextPageToken` / `prevPageToken` asymmetric naming — `src/v1/model.ts:44,46` - **Why weird:** `nextPageToken` spells "next" out, `prevPageToken` abbreviates "prev". One or the other — `prev` vs `next` is a length mismatch with no win. - **Category:** 5 (cryptic abbreviation `prev`), 17 (inconsistent abbreviation rule). - **Suggested name:** `previousPageToken` (matches `nextPageToken`'s full-word style) or `prevPageToken` + `nextPageToken` paired (but then "next" is the outlier). Spell out both: `previousPageToken` / `nextPageToken`. - **Rationale:** Symmetry — paired pagination tokens deserve paired naming. -### 23. `GetWorkspacePermissionAssignments.filter?: string` — `src/v1/model.ts:36` +### 21. `GetWorkspacePermissionAssignments.filter?: string` — `src/v1/model.ts:36` - **Why weird:** A bare `filter: string` field documented as "Filter string to search principals." Server-side query DSL hidden behind a `string`. Users must know what filter syntax to type. Same problem any time a public SDK exposes "filter" without typing the filter language. - **Category:** 1 (vague), 15 (generic field loses meaning). - **Suggested name:** `principalFilter` (more specific) plus a JSDoc snippet of the supported syntax. - **Rationale:** Naming alone won't solve this, but `filter` is the worst-case name. -### 24. `GetWorkspacePermissionAssignments.maxResults` plural-confusing — `src/v1/model.ts:34` +## Low severity + +### 22. `GetWorkspacePermissionAssignments.maxResults` plural-confusing — `src/v1/model.ts:34` - **Why weird:** "Maximum number of permission assignments to return." Field name uses a generic `maxResults` while the response field is `permissionAssignments`. Pair them: `maxAssignments` would read better, or document explicitly. Compare `accountaccesscontrolproxy` and other sibling packages — usage of `pageSize` is common. - **Category:** 1 (vague), 17 (inconsistent paging field naming across packages). - **Suggested name:** `pageSize` to align with REST list conventions (which is also what the wire param `max_results` carries in many Databricks APIs). - **Rationale:** Consistency across the SDK; the same concept should not be `pageSize` in one package, `maxResults` in another, and `limit` in a third. -### 25. `DeleteWorkspacePermissionAssignment` 51-character type name — `src/v1/model.ts:13` -- **Why weird:** `DeleteWorkspacePermissionAssignment_Response` is a 53-character type name. `WorkspacePermissionAssignmentOutput` is 35 characters. Every type in the file is 30+ characters. Verbose for a four-method package. Suggest a shorter umbrella prefix. -- **Category:** 7 (overly verbose). -- **Suggested name:** Drop `Workspace` prefix when the entire package scope is workspace (e.g., `DeletePermissionAssignmentRequest`) — the package name already says workspace. Or shorten to `Assignment`. -- **Rationale:** `await client.deleteWorkspacePermissionAssignment(req)` is 41 characters before the open paren. The package scope already conveys "workspace". - -## Low severity - -### 26. `permissionassignments` URL fragment is one word — `src/v1/client.ts:78,106,146,174` +### 23. `permissionassignments` URL fragment is one word — `src/v1/client.ts:78,106,146,174` - **Why weird:** REST path uses `/permissionassignments/` (no separator), while every other Databricks REST resource in this SDK uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). This is a wire-format problem, not a TS naming problem, but it spills into the visual feel of the client URLs. - **Category:** 3 (casing/separator inconsistency). - **Suggested name:** N/A for TS, but flag upstream: prefer `permission-assignments`. - **Rationale:** Cross-API consistency. -### 27. `accountId?: string | undefined` doc placement — `src/v1/model.ts:14,15` +### 24. `accountId?: string | undefined` doc placement — `src/v1/model.ts:14,15` - **Why weird:** Doc above `accountId` says "The account ID." but the equally important fallback semantics live in `client.ts:46-48` ("Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins."). Doc is on the wrong side. - **Category:** 19 (underspecified ID). - **Suggested name:** Move/duplicate the fallback semantics into the model.ts JSDoc. - **Rationale:** Most users read model.ts, not client.ts. -### 28. `displayName` doc terseness — `src/v1/model.ts:91` +### 25. `displayName` doc terseness — `src/v1/model.ts:91` - **Why weird:** Doc "The display name of the principal." while the discriminated union variants above carry their own names (`userName`, `groupName`, `servicePrincipalName`). Relationship between `displayName` and the variant names is undocumented (the variant names are the canonical identifier; `displayName` is the human-friendly label — but a reader has to guess). - **Category:** 1 (vague doc). - **Suggested name:** Keep field name, expand doc. - **Rationale:** A two-field name model deserves explicit roles. -### 29. `Permission.USER` doc string — `src/v1/model.ts:7-8` +### 26. `Permission.USER` doc string — `src/v1/model.ts:7-8` - **Why weird:** Doc "The most basic workspace permission" on `USER` but no doc on `ADMIN`. Asymmetric annotation; reader concludes `ADMIN` has no doc because it's "obvious", but `USER` does because — what? The same enum in iam (`WorkspacePermission`) also docs `USER_PERMISSION` and nothing else. Pattern is consistent, but still strange. - **Category:** 17 (inconsistent annotation across enum members). - **Suggested name:** Document both, or document neither. - **Rationale:** Hover docs read better with parity. -### 30. `URL path interpolation uses unencoded segments` — `src/v1/client.ts:78,106,146,174` +### 27. `URL path interpolation uses unencoded segments` — `src/v1/client.ts:78,106,146,174` - **Why weird:** Not a naming finding strictly, but worth flagging: paths interpolate `${req.accountId ?? ''}` / `${String(req.workspaceId ?? '')}` directly into URLs without `encodeURIComponent`. If a malicious or weird `accountId` ever lands in here, path injection is possible. Sibling packages use the same pattern, so it's project-wide. - **Category:** N/A (security/correctness, not naming). - **Suggested name:** N/A. Flag for hardening. - **Rationale:** Belongs in a different audit, but caught in passing. -### 31. `unmarshalGetWorkspacePermissionAssignments_ResponseSchema` 56-char symbol name — `src/v1/model.ts:129` -- **Why weird:** Schema name combining `unmarshal` prefix + camelCase type + `_Response` underscore + `Schema` suffix. A single identifier carrying four naming conventions. -- **Category:** 4 (underscore), 7 (verbose), 8 (redundant suffix). -- **Suggested name:** `listWorkspacePermissionAssignmentsResponseSchema` (after renaming Get→List and dropping the underscore). -- **Rationale:** Same cleanup as the type rename. - -### 32. `marshalUpdateWorkspacePermissionAssignmentSchema` — `src/v1/model.ts:203` -- **Why weird:** Same prefix/suffix concern. Naming inconsistency: the `unmarshal*` schemas are typed `z.ZodType`; the `marshal*` schema is untyped (`z.ZodType` without parameter, model.ts:203). Asymmetry in the generated code. -- **Category:** 17 (inconsistent typing across marshal/unmarshal pair). -- **Suggested name:** Type as `z.ZodType` to match the read-side symbol shape. -- **Rationale:** Better IDE inference. - -### 33. `executeCall` / `executeHttpCall` near-duplicate function names — `src/v1/utils.ts:26,65` -- **Why weird:** Same package exports two top-level functions named `executeCall` and `executeHttpCall`. One unwraps `Options`; the other actually sends the request and parses. The names give no hint of the layering. -- **Category:** 1 (vague), 6 (misleading). -- **Suggested name:** `executeWithOptions` (or just `runCall`) for the first, `sendHttpRequest` / `dispatchAndParse` for the second. -- **Rationale:** Visual disambiguation; today both look identical at the import-name level. - ## Observations -### 34. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Exported helper function for nested query-param flattening, but the client only uses `params.append('page_token', req.pageToken)` style calls (`client.ts:108-115`) — never calls `flattenQueryParams`. Dead code in the public surface or boilerplate generator output. The export bloats the package surface. -- **Category:** 11 (dead code / unused export). -- **Suggested name:** Remove the export, or use it. -- **Rationale:** Public API surface should match what is actually used. - -### 35. `parseResponse` / `marshalRequest` are general utilities exported per-package — `src/v1/utils.ts:113,119` -- **Why weird:** These two functions are domain-agnostic JSON marshalling helpers; identical (or nearly identical) versions almost certainly exist in every sibling package's `utils.ts`. Duplicated boilerplate per package. -- **Category:** 12 (duplicate concept across packages). -- **Suggested name:** Hoist to `@databricks/sdk-core` and import. -- **Rationale:** Generator output for every API package likely repeats this. Cf. the same pattern in `accountaccesscontrol` etc. - -### 36. Side-by-side `getWorkspacePermissionAssignments` and `listWorkspacePermissions` — `src/v1/client.ts:102,142` +### 28. Side-by-side `getWorkspacePermissionAssignments` and `listWorkspacePermissions` — `src/v1/client.ts:102,142` - **Why weird:** Two list-like methods, one named `get*` (returns paginated list), one named `list*` (returns a static catalog). Naming inverts the more usual REST convention where `list*` is paginated and `get*` is singular. - **Category:** 17 (inconsistent action verbs), 13 (verb-tense inconsistency). - **Suggested name:** `getWorkspacePermissionAssignments` → `listWorkspacePermissionAssignments`; `listWorkspacePermissions` → `getSupportedWorkspacePermissions`. Now `list*` always paginates, `get*` is a one-shot. -- **Rationale:** Cf. finding 7 + 8. Worth flagging once more as a pair-level observation. +- **Rationale:** Cf. finding 5 + 6. Worth flagging once more as a pair-level observation. ## Cross-cutting themes -1. **Proto/Go-style names leak through generation.** Eight findings (1, 3, 4, 5, 6, 9, 14, 31) trace to the upstream Go SDK's protobuf-derived shapes: `*_Response` underscore types, `*_UNSPECIFIED` / `UNKNOWN` enum sentinels, `*Output` suffixes, verb-phrase request type names, and double-wrapped oneof discriminators. None are idiomatic TS. -2. **Duplicated domain modelling with `iam` package.** Findings 1, 2, 10, 11, 21 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. -3. **Misleading verb assignment for list vs get.** Findings 7, 8, 36 — the paginated method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. -4. **Underspecified IDs and weak typing.** Findings 12, 13, 19, 27 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. +1. **Proto/Go-style names leak through generation.** Findings 3, 4, 7, 9 trace to the upstream Go SDK's protobuf-derived shapes: `*_UNSPECIFIED` / `UNKNOWN` enum sentinels, `*Output` suffixes, verb-phrase request type names, and double-wrapped oneof discriminators. None are idiomatic TS. +2. **Duplicated domain modelling with `iam` package.** Findings 1, 2, 8, 9, 19 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. +3. **Misleading verb assignment for list vs get.** Findings 5, 6, 28 — the paginated method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. +4. **Underspecified IDs and weak typing.** Findings 10, 11, 17, 24 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index 681c74f0..456064a5 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -3,17 +3,17 @@ **Path:** `packages/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 47 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | | High | 14 | -| Medium | 18 | -| Low | 10 | -| Observation | 5 | +| Medium | 17 | +| Low | 2 | +| Observation | 4 | -The package contains 9 generated types (1 enum + 8 message/response shapes), 4 client methods (plus 1 paginated iterator), and the generator's standard set of marshal/unmarshal schema helpers. The pervasive issues are (1) **proto-style nested-message names** like `GetWorkspaceBindings_Response` leaking into the TS surface and requiring `eslint-disable` directives at every declaration and at every use site; (2) **the request-type-as-verb pattern** (`GetWorkspaceBindings`, `UpdateWorkspaceBindings`, `GetCatalogWorkspaceBindings`, `UpdateCatalogWorkspaceBindings`) producing the awkward `getWorkspaceBindings(req: GetWorkspaceBindings)` verb-noun-verb-noun signature; (3) **enum values that bake the type name back into every member** (`BindingType.BINDING_TYPE_READ_WRITE` etc.); (4) **stringly-typed `securableType`** that should be a closed enum; (5) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (6) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction. +The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **proto-style nested-message names** like `GetWorkspaceBindings_Response` leaking into the TS surface and requiring `eslint-disable` directives at every declaration and at every use site; (2) **the request-type-as-verb pattern** (`GetWorkspaceBindings`, `UpdateWorkspaceBindings`, `GetCatalogWorkspaceBindings`, `UpdateCatalogWorkspaceBindings`) producing the awkward `getWorkspaceBindings(req: GetWorkspaceBindings)` verb-noun-verb-noun signature; (3) **enum values that bake the type name back into every member** (`BindingType.BINDING_TYPE_READ_WRITE` etc.); (4) **stringly-typed `securableType`** that should be a closed enum; (5) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (6) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction. --- @@ -189,31 +189,25 @@ The package contains 9 generated types (1 enum + 8 message/response shapes), 4 c - **Suggested name:** Mark with `@deprecated`. - **Rationale:** See #26. -### 28. `getWorkspaceBindingsIter` (method) — `src/v1/client.ts:147` -- **Why weird:** `Iter` suffix is Go-style (Go uses `*Iterator` types). TS uses `AsyncGenerator` / `AsyncIterable` whose syntax `async *foo()` already communicates iteration. The suffix adds nothing. Plus: `getWorkspaceBindingsIter` reads as "get-workspace-bindings-iter" — five words to say "iterate workspace bindings". -- **Category:** 5 (cryptic abbreviation: `Iter`), 14 (Go-style name), 7 (verbose). -- **Suggested name:** `iterateWorkspaceBindings` (verb-first), or `workspaceBindings` (with iterator semantics implied by `AsyncGenerator` return type). -- **Rationale:** Idiomatic TS naming for async generators is verb-first or noun-only; the Go `*Iter`/`*Iterator` suffix doesn't translate. - -### 29. `Client` — `src/v1/client.ts:46` +### 28. `Client` — `src/v1/client.ts:46` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `WorkspaceBindingsClient`. - **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. -### 30. `executeCall` — `src/v1/utils.ts:26` +### 29. `executeCall` — `src/v1/utils.ts:26` - **Why weird:** Generic verb-noun name. Two `execute` functions in scope (`execute` imported on line 4, `executeCall` defined on line 26, `executeHttpCall` defined on line 65). The discriminator between them is just "Call" vs "HttpCall" — and both ultimately wrap the imported `execute()`. - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `executeRetryableCall` (since this one applies the retrier/rateLimiter/timeout options) or `executeWithOptions`. - **Rationale:** Distinguishes the two wrappers semantically. -### 31. `executeHttpCall` — `src/v1/utils.ts:65` +### 30. `executeHttpCall` — `src/v1/utils.ts:65` - **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `APIError` on 4xx/5xx (line 88-91) — a non-obvious side effect. - **Category:** 1 (vague), 6 (misleading: "execute" sounds neutral but throws). - **Suggested name:** `sendAndParseResponse` or `sendOrThrow`. - **Rationale:** Naming should hint at error semantics. -### 32. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` +### 31. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` - **Why weird:** Yet another `*Options` suffix in a file that already imports `Options` (line 3) and `CallOptions` (line 12) — three `Options` types in scope. `HttpCallOptions` is purely an internal context bag for `executeHttpCall` (request + httpClient + logger) — it isn't user-tunable, so `Options` is misleading. - **Category:** 1 (vague suffix), 8 (redundant suffix), 17 (inconsistency). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -223,67 +217,13 @@ The package contains 9 generated types (1 enum + 8 message/response shapes), 4 c ## Low severity -### 33. `unmarshalGetCatalogWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:96` -- **Why weird:** 53-character constant name combining the redundant `Schema` suffix (#39), the proto underscore (#7), and the verb-shaped request type name (#3). Requires `eslint-disable` on line 95. -- **Category:** 4 (underscore), 7 (verbose), 8 (redundant `Schema` suffix), 14. -- **Suggested name:** `unmarshalCatalogWorkspaceBindingsResponse` (cascading from #7 and #39). -- **Rationale:** Cascades from upstream fixes. - -### 34. `unmarshalGetWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:106` -- **Why weird:** Same as #33. -- **Category:** 4, 7, 8, 14. -- **Suggested name:** `unmarshalWorkspaceBindingsResponse`. -- **Rationale:** Cascades. - -### 35. `unmarshalUpdateCatalogWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:120` -- **Why weird:** Same as #33. 56 characters. -- **Category:** 4, 7, 8, 14. -- **Suggested name:** `unmarshalUpdateCatalogWorkspaceBindingsResponse`. -- **Rationale:** Cascades. - -### 36. `unmarshalUpdateWorkspaceBindings_ResponseSchema` — `src/v1/model.ts:130` -- **Why weird:** Same as #33. -- **Category:** 4, 7, 8, 14. -- **Suggested name:** `unmarshalUpdateWorkspaceBindingsResponse`. -- **Rationale:** Cascades. - -### 37. `unmarshalWorkspaceBindingInfoSchema` — `src/v1/model.ts:141` -- **Why weird:** Redundant `Schema` suffix (the `z.ZodType` annotation already states the kind). Combined with #15 (`*Info` Go-style suffix), the constant is `unmarshalWorkspaceBindingInfoSchema` — 35 characters of which 10 are redundant suffix. -- **Category:** 8 (redundant suffix), 14 (Go-style). -- **Suggested name:** `unmarshalWorkspaceBinding`. -- **Rationale:** Both `Info` and `Schema` add zero information beyond the type signature. - -### 38. `marshalUpdateCatalogWorkspaceBindingsSchema` — `src/v1/model.ts:152` -- **Why weird:** 43 characters with redundant `Schema` suffix and the verb-shaped request type name (#5). -- **Category:** 7, 8. -- **Suggested name:** `marshalUpdateCatalogWorkspaceBindings`. -- **Rationale:** Drop `Schema` suffix. - -### 39. `*Schema` constants (all) — `src/v1/model.ts:96,106,120,130,141,152,164,178` -- **Why weird:** Every marshal/unmarshal helper carries a `Schema` suffix. The TS type annotation `z.ZodType` already says it's a Zod schema. The suffix is redundant and contributes 6 characters to every export name. -- **Category:** 8 (redundant suffix), 20 (type-suffix tautology). -- **Suggested name:** Drop `Schema` everywhere — `unmarshalWorkspaceBinding`, `marshalUpdateCatalogWorkspaceBindings`, etc. -- **Rationale:** Naming consistency; the suffix carries no info beyond the type annotation. - -### 40. `flattenQueryParams` — `src/v1/utils.ts:123` +### 32. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append` on `client.ts:117-122`). Dead-looking export from the standard generator template. - **Category:** Observation, 11 (unused public helper). - **Suggested name:** Remove if generator default; or move to a shared utility package and not emit per-package. - **Rationale:** Cross-package consistency. -### 41. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Internal helper name is generic and conflicts cognitively with `Array` and `ReadableStream` APIs. The function reads a `ReadableStream` into a single `Uint8Array` buffer. The Go SDK uses `io.ReadAll` (the standard library) — direct Go-port artifact. -- **Category:** 1 (vague), 14 (Go-style: `io.ReadAll` is the Go convention). -- **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. -- **Rationale:** Cross-package consistency. - -### 42. `parseResponse` / `marshalRequest` verb asymmetry — `src/v1/utils.ts:113,119` -- **Why weird:** `parseResponse` (decode) is the inverse of `marshalRequest` (encode); but the model file uses `marshal*` / `unmarshal*` consistently — so `parseResponse` is the odd one out. Three verbs (`parse`, `marshal`, `unmarshal`) for two operations (encode, decode). -- **Category:** 17 (inconsistent action verbs). -- **Suggested name:** `unmarshalResponse` / `marshalRequest` for pair symmetry with the rest of the file. -- **Rationale:** Mirroring helps readers map TS↔wire at a glance. - -### 43. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 33. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -293,18 +233,18 @@ The package contains 9 generated types (1 enum + 8 message/response shapes), 4 c ## Observations -### 44. Client `Host is required.` error message — `src/v1/client.ts:57` +### 34. Client `Host is required.` error message — `src/v1/client.ts:57` The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. - **Category:** Observation. -### 45. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` +### 35. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` The marshal/unmarshal helpers are exported from `model.ts` (via `export const`) but `index.ts` (lines 7-17) only re-exports types and `Client`. So the schemas are part of the package's effective import surface (`import {...} from '@databricks/sdk-workspacebindings/v1/model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). - **Category:** Observation, 11 (effectively-internal exports). -### 46. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` +### 36. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` The single word "Required" appears as a doc-comment on `workspaceId?: number`. But the field is *optional* in the TypeScript type (`workspaceId?: number | undefined`). The annotation contradicts the type modifier. Either: (a) the field is genuinely required by the server and the optional TS type is generator-wide policy (proto3 fields are all optional in TS); or (b) the doc is stale. Either way, readers can't tell. - **Category:** Observation, 6 (misleading docs). -### 47. `BindingType` doc-comment surfaces proto comment as TS doc — `src/v1/model.ts:5` +### 37. `BindingType` doc-comment surfaces proto comment as TS doc — `src/v1/model.ts:5` The comment "Using `BINDING_TYPE_` prefix here to avoid conflict with `TableOperation` enum in `credentials_common.proto`." is a wire-implementation note that has been promoted to a TS doc-comment. TS consumers should not need to know about proto namespaces. This is naming-adjacent — the comment exists *because* of the redundant prefix (#1, #2). Removing the prefix would also remove the need for the explanation. - **Category:** Observation, 14 (proto-style naming surfaced in docs). diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md index 23cffd68..35b738d5 100644 --- a/.agent/naming-audit/workspacesettings.md +++ b/.agent/naming-audit/workspacesettings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/workspacesettings/` **Versions audited:** v1 **Inferred domain:** Workspace-scoped Databricks settings: AI/BI dashboard embedding policy, automatic cluster update, compliance security profile (CSP), dashboard email subscriptions, default namespace, default warehouse ID, legacy access/DBFS disablement, notebook/file export, notebook table clipboard, results download (notebook and SQL), enhanced security monitoring (ESM), LLM proxy partner-powered AI, and restrict-workspace-admins. -**Total weird names flagged:** 56 +**Total weird names flagged:** 51 ## Summary table @@ -22,49 +22,42 @@ | 11 | High | Underscore in TS identifier | Eight `*_*_*` proto-style nested names (e.g. `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`) | `model.ts:57, 65, 77, 89, 207, 217, 224, 235` | | 12 | High | Generic / cryptic enum sentinel | `STATUS_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10, 58, 66, 78, 91` | | 13 | High | Redundant enum prefix | All five enums prefix the type name into every value | `model.ts:8-102` | -| 14 | High | Domain-redundant suffix | `*Setting` suffix duplicates package name `workspacesettings` | passim — most types | -| 15 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` | -| 16 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:340-345, 382-387, 425-430, 469-474, ...` | -| 17 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:321-338` | -| 18 | High | Type-suffix tautology | `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, etc. | `model.ts:302, 991` and 11 more | -| 19 | High | Method-name redundancy | `getDefaultNamespaceSetting`, `getRestrictWorkspaceAdminsSetting`, etc. | `client.ts:952, 1180, 1100, 872, 832, 752, 792` and more | -| 20 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | -| 21 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | -| 22 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:630-649` | -| 23 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:651-670` | -| 24 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:672-680` | -| 25 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:682-690` | -| 26 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:692-700` | -| 27 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:692, 1015` | -| 28 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:692 vs 1015`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | -| 29 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:939-956` | -| 30 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:181, 1248` | -| 31 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:269, 729` | -| 32 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:195` | -| 33 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:192` | -| 34 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:213` | -| 35 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:209, 211` | -| 36 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | -| 37 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:321, 1102` | -| 38 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:71, 102` | -| 39 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:672, 682, 692, 630, 651` | -| 40 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:672, 682` | -| 41 | Medium | Type-suffix tautology | `AibiDashboardEmbeddingAccessPolicySetting` (94-character type name) | `model.ts:110` | -| 42 | Medium | Type-suffix tautology | `AibiDashboardEmbeddingApprovedDomainsSetting` | `model.ts:138` | -| 43 | Medium | Verbose / type-suffix tautology | `DeleteAibiDashboardEmbeddingApprovedDomainsSettingResponse` (58 chars) | `model.ts:385` | -| 44 | Medium | Overly verbose | `UpdateAibiDashboardEmbeddingApprovedDomainsSettingRequest` (54 chars) | `model.ts:1050` | -| 45 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | -| 46 | Medium | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS`, `SECOND_AND_FOURTH_OF_MONTH`, `FIRST_AND_THIRD_OF_MONTH`, `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `FEDRAMP_MODERATE`, etc. | `model.ts:19-53, 83, 84, 101` | -| 47 | Medium | Long enum value | `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`, `ALLOW_ALL_DOMAINS` | `model.ts:59-61` | -| 48 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:988` | -| 49 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | -| 50 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 1104, 956, 1369, 1560` | -| 51 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:112-117, 252-259, 1024` | -| 52 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:248` | -| 53 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:135` | -| 54 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | -| 55 | Low | Verb-tense inconsistency | `Patch*` request types vs `Update*` request types for same HTTP verb | `model.ts:959, 967, 975 vs 1040, 1050, 1062, ...` | -| 56 | Low | Duplicate type | `Delete*Response` (10 types) duplicated across sibling settings packages | `model.ts:356-628` | +| 14 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` | +| 15 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:340-345, 382-387, 425-430, 469-474, ...` | +| 16 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:321-338` | +| 17 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | +| 18 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | +| 19 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:630-649` | +| 20 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:651-670` | +| 21 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:672-680` | +| 22 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:682-690` | +| 23 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:692-700` | +| 24 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:692, 1015` | +| 25 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:692 vs 1015`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | +| 26 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:939-956` | +| 27 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:181, 1248` | +| 28 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:269, 729` | +| 29 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:195` | +| 30 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:192` | +| 31 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:213` | +| 32 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:209, 211` | +| 33 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | +| 34 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:321, 1102` | +| 35 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:71, 102` | +| 36 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:672, 682, 692, 630, 651` | +| 37 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:672, 682` | +| 38 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | +| 39 | Medium | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS`, `SECOND_AND_FOURTH_OF_MONTH`, `FIRST_AND_THIRD_OF_MONTH`, `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `FEDRAMP_MODERATE`, etc. | `model.ts:19-53, 83, 84, 101` | +| 40 | Medium | Long enum value | `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`, `ALLOW_ALL_DOMAINS` | `model.ts:59-61` | +| 41 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:988` | +| 42 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | +| 43 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 1104, 956, 1369, 1560` | +| 44 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:112-117, 252-259, 1024` | +| 45 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:248` | +| 46 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:135` | +| 47 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | +| 48 | Low | Verb-tense inconsistency | `Patch*` request types vs `Update*` request types for same HTTP verb | `model.ts:959, 967, 975 vs 1040, 1050, 1062, ...` | +| 49 | Low | Duplicate type | `Delete*Response` (10 types) duplicated across sibling settings packages | `model.ts:356-628` | --- @@ -124,7 +117,7 @@ - **File:line:** `model.ts:706-733`; URL slug `shield_esm_enablement_ws_db`; `client.ts:1100, 1556` - **Category:** Cryptic abbreviation - **Suggestion:** `EnhancedSecurityMonitoring*` everywhere on TS side. Wire `esm` is fine. -- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #31). +- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #28). ### 9. `Llm*` family — acronym casing + verb stacking - **File:line:** `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624, 1140, 1588` @@ -156,49 +149,31 @@ - **Suggestion:** Strip prefixes. `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.MONDAY` is fine; `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` only adds noise — the `DAY_OF_WEEK_` is the enum-name token bleeding into the member. - **Rationale:** Symmetrical with #12 — the noise is the proto3 convention of prefixing every member name with the enum name (to avoid C++ enum-scope collisions). TS scopes enums; the prefix is redundant. -### 14. `*Setting` suffix vs package name `workspacesettings` -- **File:line:** All `*Setting`-suffixed types -- **Category:** Domain-redundant suffix -- **Suggestion:** Drop `Setting` from the type names. Consumers reach them via `workspacesettings.X`, so `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` quadruple-stutters the domain. The inner type `AibiDashboardEmbeddingAccessPolicy` already exists *without* the suffix; the outer wrapper is purely the protobuf envelope. -- **Rationale:** Compare `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` (the envelope) vs `workspacesettings.AibiDashboardEmbeddingAccessPolicy` (the data). A consumer cannot tell them apart by name; the only difference is the `Setting` suffix means "I have an etag." If the envelope is unavoidable, name it `Envelope`/`Versioned` or hide it behind an SDK helper. - -### 15. `settingName` documented as not respected on requests +### 14. `settingName` documented as not respected on requests - **File:line:** `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` - **Category:** Misleading - **Suggestion:** Mark `settingName` `readonly` on the response-only path; remove it from request bodies; or split request/response types so it is only present where meaningful. At minimum, the docstring should not say "this field is populated in the response, but it will not be respected even if it's set in the request body." - **Rationale:** A 17-times-repeated 240-character JSDoc admits that the field is server-ignored on PATCH/UPDATE. The field is forced to `"default"` server-side. Exposing it in the public API surface only invites users to set it, expect it to take effect, and then debug why it didn't. -### 16. `settingTypeName` query parameter ignored +### 15. `settingTypeName` query parameter ignored - **File:line:** `client.ts:340-345, 382-387, 425-430, 469-474, 510-515, 550-555, 590-595, 630-635, 675-680, 715-720, 758-763, 798-803, 838-843, 878-883, 918-923, 958-963, 994-999, 1032-1037, 1068-1073, 1106-1111, 1146-1151, 1186-1191, 1226-1231` - **Category:** Misleading - **Suggestion:** Drop from the request type — the path parameter (`/api/2.0/settings/types/aibi_dash_embed_ws_acc_policy/names/default`) makes the query parameter redundant. The client serializes the path slug for the user; there is no reason to also expose the slug as a `settingTypeName` query param. - **Rationale:** Every Get/Delete/Update sets the URL path to a hard-coded slug (e.g. `aibi_dash_embed_ws_acc_policy`) and then *also* lets the user populate `settingTypeName` and `settingName` as query params. If a user sets `settingTypeName: 'foo'`, the path still wins; the field is window dressing. -### 17. `DefaultWarehouseId` envelope holds no warehouse-ID field directly +### 16. `DefaultWarehouseId` envelope holds no warehouse-ID field directly - **File:line:** `model.ts:321-338` -- **Category:** Underspecified ID, type-suffix tautology, misleading +- **Category:** Underspecified ID, misleading - **Suggestion:** `interface DefaultWarehouse { id?: string; etag?: string; }` — a flat, non-envelope, no-wrapper type. Or hide the envelope completely and let the client method return `string | undefined`. - **Rationale:** A reader sees `DefaultWarehouseId` and expects a `string` (or numeric ID). What they get is a four-layer struct: `defaultWarehouseId.value.stringVal.value` is the actual ID. Plus the type lacks any documentation about whether the warehouse ID is numeric (e.g. `1234`) or string-shaped (e.g. `0abc...d`). The Databricks warehouse-ID convention is opaque alphanumeric; this should be documented. -### 18. `*Setting` type-suffix tautology in many types -- **File:line:** `model.ts:104, 110, 138, 162, 244, 251, 275, 302, 321, 630, 651, 672, 682, 692, 706, 711, 939, 982, 991, 1015` -- **Category:** Type-suffix tautology -- **Suggestion:** Drop `Setting` from the names that have an inner non-`Setting` sibling. E.g. `AibiDashboardEmbeddingAccessPolicySetting` ↔ `AibiDashboardEmbeddingAccessPolicy` should collapse to a single type, since the suffix only adds `etag` + `settingName` (both of which are envelope concerns). -- **Rationale:** Same as #14. The combination of package-name (`workspacesettings`) + type-suffix (`Setting`) + the existence of a sibling type without the suffix is *triple* redundancy at the API surface. - -### 19. Method-name redundancy in client class -- **File:line:** `client.ts:752, 792, 832, 872, 912, 952, 989, 1026, 1063, 1100, 1140, 1180, 1220, 1257, 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657` -- **Category:** Method-name redundancy -- **Suggestion:** Drop `Setting` suffix from method names: `getAibiDashboardEmbeddingAccessPolicySetting` → `getAibiDashboardEmbeddingAccessPolicy` (or, with #6, `getAiBiDashboardEmbeddingAccessPolicy`). Method already lives on `workspacesettings.Client`; the suffix is again the third stutter. -- **Rationale:** Compare `client.updateRestrictWorkspaceAdminsSetting(req)` vs `client.updateRestrictWorkspaceAdmins(req)` — the latter is unambiguous in context. - -### 20. `patch*` vs `update*` methods for the same PATCH HTTP verb +### 17. `patch*` vs `update*` methods for the same PATCH HTTP verb - **File:line:** `client.ts:192 (patchEnableExportNotebook), 249 (patchEnableNotebookTableClipboard), 306 (patchEnableResultsDownloading)` vs `client.ts:1257 (updateAibi...), 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657 (update*)` - **Category:** Inconsistent action verbs - **Suggestion:** Standardize on `update*`. The three `patch*` methods are anomalies — every other PATCH method in the package is named `update*` and every API in the SDK reading from CRUD elsewhere uses `update*`. - **Rationale:** Three of 26 methods (`patchEnableExportNotebook`, `patchEnableNotebookTableClipboard`, `patchEnableResultsDownloading`) use the verb `patch` instead of `update`, even though all 14 PATCH-method-using siblings use `update`. The HTTP verb is the same (`PATCH`). The naming inconsistency causes consumer discovery problems. -### 21. `delete*` methods that actually "revert" to default +### 18. `delete*` methods that actually "revert" to default - **File:line:** `client.ts:335 (deleteAibi...AccessPolicySetting), 377, 419, 464, 504, 544, 584, 624, 669, 709` - **Category:** Inconsistent action verbs / misleading - **Suggestion:** `resetToDefault*` or `reset*`. The doc literally reads "Reverts the SQL Results Download setting to its default value" (line 708), "Reverts the Dashboard Email Subscriptions setting to its default value" (line 418), "Reverts the enable partner powered AI features workspace setting to its default value" (line 623), etc. — the semantic is reset, not delete. @@ -208,163 +183,139 @@ ## Medium severity -### 22. `DisableLegacyAccess` — verb-phrase as type name +### 19. `DisableLegacyAccess` — verb-phrase as type name - **File:line:** `model.ts:630-649` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `LegacyAccessDisablement` or `LegacyAccessToggle`. Types describing settings should be nouns. - **Rationale:** `DisableLegacyAccess` reads as an imperative ("perform the action of disabling legacy access") rather than a state ("the legacy-access-disabled toggle setting"). The discriminator name `disableLegacyAccess` inside `.value.disableLegacyAccess: BooleanMessage` doubles the verb. -### 23. `DisableLegacyDbfs` — verb-phrase as type name +### 20. `DisableLegacyDbfs` — verb-phrase as type name - **File:line:** `model.ts:651-670` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `LegacyDBFSDisablement` or `LegacyDBFSToggle`. -- **Rationale:** Same as #22. +- **Rationale:** Same as #19. -### 24. `EnableExportNotebook` — verb-phrase as type name +### 21. `EnableExportNotebook` — verb-phrase as type name - **File:line:** `model.ts:672-680` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `NotebookExportToggle` or `NotebookExportEnabled`. -- **Rationale:** Same as #22 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. +- **Rationale:** Same as #19 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. -### 25. `EnableNotebookTableClipboard` — verb-phrase as type name +### 22. `EnableNotebookTableClipboard` — verb-phrase as type name - **File:line:** `model.ts:682-690` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `NotebookTableClipboardToggle`. -- **Rationale:** Same as #22. +- **Rationale:** Same as #19. -### 26. `EnableResultsDownloading` — verb + gerund mash +### 23. `EnableResultsDownloading` — verb + gerund mash - **File:line:** `model.ts:692-700` - **Category:** Verb-tense / verb-in-noun position + gerund mismatch - **Suggestion:** `NotebookResultsDownloadToggle` (matches the doc on `client.ts:280` "Notebook results download setting"). - **Rationale:** `EnableResultsDownloading` mixes imperative `Enable` with gerund `Downloading`. The sibling type `SqlResultsDownload` (no `-ing`, no `Enable`) does the same thing for SQL. The inconsistency is severe — same domain, two different naming conventions. -### 27. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package +### 24. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package - **File:line:** `model.ts:692, 1015` - **Category:** Verb-tense / -ing gerund inconsistency - **Suggestion:** Pick one form. Either both as `*Toggle` or both as `Enable*Downloading`. - **Rationale:** Both control downloading of query results. The notebook variant is `EnableResultsDownloading` (gerund). The SQL variant is `SqlResultsDownload` (noun). The pair was authored at different times by different teams and the inconsistency leaked into the API. -### 28. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap +### 25. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap - **File:line:** `model.ts:692, 1015` - **Category:** Misleading / parallel naming - **Suggestion:** Unify under one type with a discriminator: `ResultsDownloadToggle { context: 'notebook' | 'sql', enabled: boolean }`. - **Rationale:** The doc on `client.ts:280` calls one "Notebook results download" and the doc on `client.ts:1219` calls the other "SQL Results Download." They have the same shape and similar semantics — but the methods, types, and wire slugs are all separate. This is duplicated wiring at the API surface. -### 29. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix +### 26. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix - **File:line:** `model.ts:939-956` - **Category:** Misleading - **Suggestion:** Drop `Workspace`. The package name is `workspacesettings`, so every type is workspace-scoped. The suffix exists only to mirror `LlmProxyPartnerPoweredAccount` in `accountsettings` — which is symmetrical but ill-justified (both should drop their scope suffix). - **Rationale:** Compare to siblings: `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, `SqlResultsDownload`, `EnableExportNotebook` — none of them carry the "Workspace" suffix despite being workspace-scoped. `LlmProxyPartnerPoweredWorkspace` is the outlier. -### 30. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" +### 27. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" - **File:line:** `model.ts:181, 1248` - **Category:** Misleading - **Suggestion:** `clusterAutoRestart` (matches the actual data type, `ClusterAutoRestartMessage`). -- **Rationale:** Inside `AutomaticClusterUpdateSetting.value.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage` — the discriminator name uses one phrase ("automatic cluster update workspace") while the type uses another ("ClusterAutoRestartMessage"). The reader must mentally bridge "automatic cluster update" with "cluster auto restart." +- **Rationale:** Inside `AutomaticClusterUpdateSetting.value.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage` — the discriminator name uses one phrase ("automatic cluster update workspace") while the type uses another ("cluster auto restart"). The reader must mentally bridge "automatic cluster update" with "cluster auto restart." -### 31. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" +### 28. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" - **File:line:** `model.ts:269, 729` - **Category:** Misleading - **Suggestion:** Drop "Workspace" suffix: `complianceSecurityProfile`, `enhancedSecurityMonitoring`. -- **Rationale:** Same as #29. +- **Rationale:** Same as #26. -### 32. `restartEvenIfNoUpdatesAvailable` — double negative +### 29. `restartEvenIfNoUpdatesAvailable` — double negative - **File:line:** `model.ts:195` - **Category:** Misleading - **Suggestion:** `restartUnconditionally` (or invert: `skipIfNoUpdates` with opposite default). - **Rationale:** "Restart even if no updates available" is a triple-conditional that takes effort to parse. The semantics are "restart regardless of update availability." Boolean fields should read as clean predicates. -### 33. `canToggle` — vague boolean +### 30. `canToggle` — vague boolean - **File:line:** `model.ts:192` - **Category:** Misleading - **Suggestion:** `isToggleable` or `canBeDisabledByCustomer`. - **Rationale:** `canToggle` on its own does not specify *what* can be toggled or by *whom*. From context (`ClusterAutoRestartMessage`), this likely means "can the customer toggle the auto-restart setting." The name does not convey that. -### 34. `forcedForComplianceMode` — past-participle as flag +### 31. `forcedForComplianceMode` — past-participle as flag - **File:line:** `model.ts:213` - **Category:** Misleading - **Suggestion:** `isForcedByComplianceMode` or `forcedDueToComplianceMode`. - **Rationale:** `forcedFor` reads ambiguously — "for the purpose of" or "due to"? The doc on line 212 ("The feature is force enabled if compliance mode is active") confirms the meaning is "due to." -### 35. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative +### 32. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative - **File:line:** `model.ts:209, 211` - **Category:** Misleading - **Suggestion:** Invert: `requiresEnterpriseTier`, `requiresEntitlement` — read more naturally. - **Rationale:** "Unavailable for non-enterprise" requires reasoning over two negatives. "Requires enterprise" is a positive predicate. -### 36. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` +### 33. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` - **File:line:** Throughout model.ts and client.ts - **Category:** Acronym casing - **Suggestion:** Apply TS-conventional casing — `DBFS`, `AIBI` (or `AiBi`), `LLM`, `CSP`, `ESM`, `SQL` — or, where they are domain acronyms, document expansion. The codebase is internally consistent in using `Pascal-token-case` for all of them, but this contradicts the TS style guide and the JSDoc which uses correct casing (`AI/BI`, `LLM`, `SQL`, etc. in prose). - **Rationale:** JSDoc has it right; identifiers don't. -### 37. `Id` vs `ID` casing +### 34. `Id` vs `ID` casing - **File:line:** `model.ts:321, 1102` (`DefaultWarehouseId`, `UpdateDefaultWarehouseIdRequest`, `defaultWarehouseId` method) - **Category:** Acronym casing - **Suggestion:** `DefaultWarehouseID`, `UpdateDefaultWarehouseIDRequest` — or, if `Id` is house style, document it explicitly. Pick one and apply globally. - **Rationale:** Established TS code is split — some major SDKs use `Id` (consistent with `Pascal-token-case`), others use `ID` (matches HTTP/spec convention). The Go SDK uses `Id`. The Databricks JS SDK should pick one and apply it everywhere; today, "Id" is used here but "ESM/CSP/LLM" suggests acronym capitalization is house style. -### 38. `Url` casing +### 35. `Url` casing - **File:line:** `utils.ts:71, 102` - **Category:** Acronym casing - **Suggestion:** Match the upstream `HttpRequest.url` field; if upstream uses `url`, leave it. Note inconsistency for the audit reviewer. - **Rationale:** Minor — flagged because the rule applies. -### 39. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns +### 36. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns - **File:line:** `model.ts:672 (EnableExportNotebook), 682 (EnableNotebookTableClipboard), 692 (EnableResultsDownloading), 630 (DisableLegacyAccess), 651 (DisableLegacyDbfs)` - **Category:** Verb-tense inconsistency -- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #22–26. +- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #19–23. - **Rationale:** Five types here use three different inflection patterns. -### 40. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap +### 37. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap - **File:line:** `model.ts:672, 682` - **Category:** Verb-tense inconsistency - **Suggestion:** Pick word-order convention: noun-verb-noun (`EnableNotebookExport`, `EnableNotebookTableClipboard`) or verb-noun-noun (`EnableExportNotebook`, `EnableClipboardTable`). - **Rationale:** "Enable Export Notebook" puts the noun ("Notebook") last; "Enable Notebook Table Clipboard" puts it first. The cognitive cost of two siblings in the same package using opposite orders is non-trivial. -### 41. `AibiDashboardEmbeddingAccessPolicySetting` — 41-character type-suffix tautology -- **File:line:** `model.ts:110` -- **Category:** Type-suffix tautology, overly verbose -- **Suggestion:** `EmbeddingAccessPolicy` (drop `Aibi` → covered by package context; drop `Dashboard` → covered by the embedding scope; drop `Setting` → covered by `*Setting` cleanup). -- **Rationale:** Five tokens, each redundant against context. The TS surface area is paying for proto-name verbosity. - -### 42. `AibiDashboardEmbeddingApprovedDomainsSetting` — 44-character type-suffix tautology -- **File:line:** `model.ts:138` -- **Category:** Type-suffix tautology, overly verbose -- **Suggestion:** `EmbeddingApprovedDomains`. -- **Rationale:** Same as #41. - -### 43. `DeleteAibiDashboardEmbeddingApprovedDomainsSettingResponse` — 58-character verbose name -- **File:line:** `model.ts:385` -- **Category:** Overly verbose, type-suffix tautology -- **Suggestion:** `ResetEmbeddingApprovedDomainsResult` (still long). -- **Rationale:** 58 characters is a noise tax on every consumer. - -### 44. `UpdateAibiDashboardEmbeddingApprovedDomainsSettingRequest` — 56-character verbose name -- **File:line:** `model.ts:1050` -- **Category:** Overly verbose, type-suffix tautology -- **Suggestion:** `UpdateEmbeddingApprovedDomainsRequest` (or after #5, no separate request — use a generic shape from `settings/v2`). -- **Rationale:** Same as #43. - -### 45. `delete*` method names — reserved-word adjacency +### 38. `delete*` method names — reserved-word adjacency - **File:line:** `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` - **Category:** Reserved-word collision (soft) -- **Suggestion:** `reset*` (which also fixes #21). +- **Suggestion:** `reset*` (which also fixes #18). - **Rationale:** `delete` is a JS reserved word (`delete obj.prop`). Using it as a method prefix is technically fine but creates parsing-cost ambiguity in mental models, especially when the operation doesn't *actually* delete. -### 46. Long enum values +### 39. Long enum values - **File:line:** `model.ts:19-53, 83, 84, 101` - **Category:** Long enum value - **Suggestion:** Most are unavoidable (regulatory standard names like `FEDRAMP_MODERATE` are canonical). For `RESTRICT_TOKENS_AND_JOB_RUN_AS` consider `RESTRICT_TOKEN_AND_JOB_RUN_AS` (singular `TOKEN`); for `SECOND_AND_FOURTH_OF_MONTH` consider abbreviation (this is a maintenance-window pattern). - **Rationale:** Length is unavoidable for proper nouns but `RESTRICT_TOKENS_AND_JOB_RUN_AS` mixes plural noun + singular verb-phrase awkwardly. -### 47. Enum values for domain-allow lists +### 40. Enum values for domain-allow lists - **File:line:** `model.ts:59-61` (`ALLOW_ALL_DOMAINS`, `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`) - **Category:** Long enum value - **Suggestion:** `ALLOW_ALL`, `ALLOW_APPROVED`, `DENY_ALL` — drop `_DOMAINS` since the enum is already named `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` and the domain context is established. - **Rationale:** Redundant tail. Compare with `STATUS_UNSPECIFIED`, `ALLOW_ALL`, `RESTRICT_TOKENS_AND_JOB_RUN_AS` in `RestrictWorkspaceAdminsMessage_Status` — none carry a redundant noun. -### 48. `disableGovTagCreation` — verb-as-field +### 41. `disableGovTagCreation` — verb-as-field - **File:line:** `model.ts:988` - **Category:** Verb-tense inconsistency, cryptic abbreviation - **Suggestion:** `governanceTagCreationDisabled` or `restrictsGovernanceTagCreation`. `Gov` is also cryptic abbreviation. @@ -374,49 +325,49 @@ ## Low severity -### 49. Cryptic wire-key abbreviations in URL slugs +### 42. Cryptic wire-key abbreviations in URL slugs - **File:line:** `client.ts:339 (aibi_dash_embed_ws_acc_policy), 381 (aibi_dash_embed_ws_apprvd_domains), 756, 796, 1261, 1296` - **Category:** Cryptic abbreviation - **Suggestion:** Wire keys are server-controlled; the SDK can't unilaterally rename. Worth flagging for the broader Databricks-platform team — these URL paths are exposed in logs and SDK telemetry. `apprvd` for `approved` saves 1 character. - **Rationale:** Wire keys aren't strictly in scope for naming audits, but they bleed into log lines and error messages. `dash_embed` for "dashboard embedding" is also non-obvious. -### 50. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix +### 43. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix - **File:line:** `client.ts:468 (default_namespace_ws), 876 (shield_csp_enablement_ws_db), 1104 (shield_esm_enablement_ws_db)` - **Category:** Cryptic abbreviation - **Suggestion:** Wire-team concern. `ws` is workspace, `db` is database (?), `ac` is account (in `accountsettings`). These two-letter suffixes are dense. - **Rationale:** `shield_csp_enablement_ws_db` mixes three abbreviated tokens (`shield` is fine, `csp` and `ws_db` are cryptic). -### 51. `eTag` (doc) vs `etag` (field) +### 44. `eTag` (doc) vs `etag` (field) - **File:line:** `model.ts:112-117, 252-259, 1024` (every `etag` doc block) - **Category:** Acronym casing - **Suggestion:** Standardize either `etag` or `eTag`. RFC 7232 spells it "ETag" in HTTP headers; Databricks docs spell it `eTag` in prose and `etag` as the JSON field. - **Rationale:** Internal-doc inconsistency. The JSDoc on every type says "etag used for versioning. The response is at least as fresh as the eTag provided." — the same paragraph uses two casings. -### 52. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope +### 45. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope - **File:line:** `model.ts:248` - **Category:** Singular/plural mismatch (mild — correct in context) - **Suggestion:** No change. Flagged only because the audit checklist asks for it. The field is correctly plural because it holds an array; the parent type is correctly singular because there is one profile. - **Rationale:** Consistent. No action needed. -### 53. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` +### 46. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` - **File:line:** `model.ts:135` - **Category:** Singular/plural - **Suggestion:** None needed for this field. Flagging the parent type name — `AibiDashboardEmbeddingApprovedDomains` is plural (because it holds a list) while sibling `AibiDashboardEmbeddingAccessPolicy` is singular. The asymmetry is fine but inconsistent stylistically. - **Rationale:** Minor; preserved for completeness. -### 54. Wire-key length in shorter slugs +### 47. Wire-key length in shorter slugs - **File:line:** `client.ts:836 (automatic_cluster_update), 423 (dashboard_email_subscriptions), 673 (restrict_workspace_admins)` - **Category:** Verbose / could be shorter - **Suggestion:** Wire-team concern. - **Rationale:** These three slugs are 24+ characters but spell every word out (unlike `aibi_dash_embed_ws_acc_policy` which abbreviates aggressively). The inconsistency in wire-side abbreviation conventions is itself a flag. -### 55. `Patch*Request` types vs `Update*Request` types for same PATCH HTTP verb +### 48. `Patch*Request` types vs `Update*Request` types for same PATCH HTTP verb - **File:line:** `model.ts:959 (PatchEnableExportNotebookRequest), 967 (PatchEnableNotebookTableClipboardRequest), 975 (PatchEnableResultsDownloadingRequest)` vs `model.ts:1040, 1050, 1062, 1072, 1082, 1092, 1102, 1112, 1122, 1132, 1142, 1152, 1162 (Update*Request)` - **Category:** Verb-tense inconsistency -- **Suggestion:** Match #20 — standardize on `Update*Request`. +- **Suggestion:** Match #17 — standardize on `Update*Request`. - **Rationale:** 3 of 17 request types use `Patch*`, the other 14 use `Update*`. -### 56. `Delete*Response` types duplicated across sibling settings packages +### 49. `Delete*Response` types duplicated across sibling settings packages - **File:line:** `model.ts:356, 385, 414, 443, 472, 501, 530, 559, 588, 617` - **Category:** Duplicate type - **Suggestion:** Hoist to a shared module alongside `BooleanMessage`/`StringMessage` (see #2), or use a single canonical `EtagResponse` type across all settings packages. @@ -428,18 +379,16 @@ 1. **Four overlapping settings packages.** `workspacesettings` + `settings` + `accountsettings` + `workspaceconf` is a confusing taxonomy with literal type duplication. Almost every type in `workspacesettings` has a doppelganger in `settings/v2`. (Severity #1, #2, #3, #4, #5.) -2. **`*Setting` triple stutter.** Package is `workspacesettings`, types are `*Setting`, methods are `get*Setting()`. Three layers of "setting" in every consumer call. (Severities #14, #18, #19.) - -3. **Proto-style nested-name underscores.** Eight identifiers use proto-IDL underscore nesting (`Foo_Bar_Baz`), each with an eslint-disable comment. (Severity #11.) +2. **Proto-style nested-name underscores.** Eight identifiers use proto-IDL underscore nesting (`Foo_Bar_Baz`), each with an eslint-disable comment. (Severity #11.) -4. **Sentinel `*_UNSPECIFIED` and redundant enum-name prefixes.** Proto3 convention bleeds into TS enums. (Severities #12, #13.) +3. **Sentinel `*_UNSPECIFIED` and redundant enum-name prefixes.** Proto3 convention bleeds into TS enums. (Severities #12, #13.) -5. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #6, #7, #8, #9, #10, #36, #37, #38.) +4. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #6, #7, #8, #9, #10, #33, #34, #35.) -6. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #22-26, #39-40.) +5. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #19-23, #36-37.) -7. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #20, #21, #45.) +6. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #17, #18, #38.) -8. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #15, #16.) +7. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #14, #15.) -9. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #49, #50.) +8. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #42, #43.) diff --git a/AGENTS.md b/AGENTS.md index 46494751..0c9f90de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -128,7 +128,7 @@ issue. Each finding cites `file:line`, the category, a suggested name, and the rationale. Two reduction workflows keep the audit current. Both spawn one -`general-purpose` agent per API package in parallel batches of ~20 to +`general-purpose` agent per API package in parallel batches of ~30-40 to avoid collision in reasoning. Always omit the `model` parameter so subagents inherit the parent model. @@ -237,7 +237,8 @@ totals) so cross-package counts stay consistent. - The list of API packages is everything under `packages/` that has a `src/v*/` subdirectory. Generate it with: `for d in packages/*/; do [ -d "$d/src" ] && ls "$d/src" 2>/dev/null | grep -qE '^v[0-9]' && echo "${d#packages/}"; done`. -- Batch parallel agent calls at ~20-25 per message. +- Batch parallel agent calls at ~30-40 per message. +- Real-world experience: ~25 sometimes hit transient socket errors on the longest single-agent runs; 30-40 has worked in practice as long as you accept the occasional retry. - Agents must always write back to the existing audit file path. Never create new files in `.agent/naming-audit/` outside of `_SUMMARY.md` and the one-per-package `.md`. From 4ff29152045e993a0a9d0b5c5032bdb670dc6960 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Wed, 20 May 2026 14:32:20 +0000 Subject: [PATCH 03/12] prune underscore identifier --- .agent/naming-audit/_SUMMARY.md | 387 +++++------ .agent/naming-audit/abacpolicies.md | 102 ++- .agent/naming-audit/accountsettings.md | 171 +++-- .agent/naming-audit/apps.md | 222 +++--- .agent/naming-audit/artifactallowlists.md | 74 +- .agent/naming-audit/billableusagedownload.md | 2 +- .agent/naming-audit/budgetpolicy.md | 98 ++- .agent/naming-audit/budgets.md | 135 +--- .agent/naming-audit/bundle.md | 103 +-- .agent/naming-audit/catalogs.md | 350 ++++------ .agent/naming-audit/cleanroomassets.md | 135 ++-- .../cleanroomautoapprovalrules.md | 65 +- .agent/naming-audit/cleanrooms.md | 339 ++-------- .agent/naming-audit/cleanroomtaskruns.md | 151 +---- .agent/naming-audit/clusterlibraries.md | 321 +++------ .agent/naming-audit/clusterpolicies.md | 41 +- .agent/naming-audit/clusters.md | 242 +++---- .agent/naming-audit/commandexecution.md | 222 +++--- .agent/naming-audit/connections.md | 112 ++- .agent/naming-audit/credentials.md | 119 ++-- .agent/naming-audit/customllms.md | 10 +- .agent/naming-audit/database.md | 210 ++---- .agent/naming-audit/dataclassification.md | 56 +- .agent/naming-audit/dataquality.md | 8 +- .agent/naming-audit/disasterrecovery.md | 84 +-- .agent/naming-audit/endpoints.md | 72 +- .agent/naming-audit/entitytagassignments.md | 10 +- .agent/naming-audit/environments.md | 80 +-- .agent/naming-audit/experiments.md | 124 ++-- .agent/naming-audit/externallineage.md | 84 +-- .agent/naming-audit/externallocations.md | 40 +- .agent/naming-audit/externalmetadata.md | 66 +- .agent/naming-audit/features.md | 197 ++---- .agent/naming-audit/featurestore.md | 189 ++---- .agent/naming-audit/files.md | 232 +++---- .agent/naming-audit/forecasting.md | 638 ++---------------- .agent/naming-audit/functions.md | 373 ++++------ .agent/naming-audit/genie.md | 225 +++--- .agent/naming-audit/gitcredentials.md | 92 +-- .agent/naming-audit/globalinitscripts.md | 46 +- .agent/naming-audit/grants.md | 138 ++-- .agent/naming-audit/iam.md | 171 ++--- .agent/naming-audit/indexes.md | 94 ++- .agent/naming-audit/instancepools.md | 97 +-- .agent/naming-audit/instanceprofiles.md | 39 +- .agent/naming-audit/jobs.md | 279 +++----- .agent/naming-audit/knowledgeassistants.md | 116 ++-- .agent/naming-audit/lakeview.md | 259 +++---- .../naming-audit/logdeliveryconfigurations.md | 71 +- .agent/naming-audit/marketplaces.md | 316 +++------ .agent/naming-audit/materializedfeatures.md | 206 ++---- .agent/naming-audit/metastores.md | 366 ++++------ .agent/naming-audit/modelregistry.md | 172 +++-- .agent/naming-audit/modelservingdebug.md | 99 +-- .agent/naming-audit/modelservingmanagement.md | 160 ++--- .agent/naming-audit/modelservingquery.md | 152 ++--- .../naming-audit/notificationdestinations.md | 76 +-- .../naming-audit/oauthcustomappintegration.md | 52 +- .agent/naming-audit/oauthpublishedapp.md | 58 +- .agent/naming-audit/onlinetables.md | 263 +++----- .agent/naming-audit/permissions.md | 86 ++- .agent/naming-audit/pipelines.md | 78 +-- .agent/naming-audit/policyfamilies.md | 48 +- .agent/naming-audit/postgres.md | 281 ++++---- .agent/naming-audit/qualitymonitor.md | 122 ++-- .agent/naming-audit/qualitymonitors.md | 96 ++- .agent/naming-audit/queries.md | 157 ++--- .agent/naming-audit/queryhistory.md | 126 ++-- .agent/naming-audit/registeredmodels.md | 165 ++--- .agent/naming-audit/repos.md | 149 ++-- .agent/naming-audit/resourcequotas.md | 89 +-- .agent/naming-audit/rfa.md | 48 +- .agent/naming-audit/schemas.md | 370 ++++------ .agent/naming-audit/secrets.md | 129 +--- .agent/naming-audit/secretsuc.md | 34 +- .../naming-audit/serviceprincipalsecrets.md | 72 +- .../serviceprincipalsecretsproxy.md | 43 +- .agent/naming-audit/settings.md | 362 +++++----- .agent/naming-audit/statementexecution.md | 157 ++--- .agent/naming-audit/systemschemas.md | 78 +-- .agent/naming-audit/tables.md | 289 +++----- .agent/naming-audit/tagassignments.md | 2 +- .agent/naming-audit/tokenmanagement.md | 102 ++- .agent/naming-audit/tokens.md | 66 +- .agent/naming-audit/usagedashboards.md | 95 +-- .agent/naming-audit/usagepolicy.md | 112 ++- .agent/naming-audit/volumes.md | 78 +-- .agent/naming-audit/warehouses.md | 110 +-- .agent/naming-audit/workspace.md | 154 ++--- .agent/naming-audit/workspaceassignment.md | 7 +- .agent/naming-audit/workspacebindings.md | 112 ++- .agent/naming-audit/workspacesettings.md | 250 +++---- 92 files changed, 4740 insertions(+), 8738 deletions(-) diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index a10b097b..bcf7572d 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,7 +1,7 @@ # Cross-Package Naming Audit — Executive Summary **Packages audited:** 98 (every API package under `packages//src//`) -**Total findings across all audits:** **4,502** (down from 5,322 originally, then 5,001 after the first prune pass, then 4,544 after the second; **42 additional findings pruned in this third pass**, **820 cumulative**) +**Total findings across all audits:** **3,918** (down from 5,322 originally, then 5,001 after the first prune pass, then 4,544 after the second, then 4,502 after the third; **584 additional findings pruned in this fourth pass**, **1,404 cumulative**) **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` > **Prune note 1.** The original audit included a cross-cutting theme @@ -39,6 +39,21 @@ > totals, theme list (the former Theme 8 removed), generator > recommendations (§8.10 removed), and by-the-numbers table below. +> **Prune note 4.** A fourth cross-cutting theme, +> "Underscore-in-identifier (proto `Outer_Inner` / `Foo_Response`)" — +> e.g. `ClusterState_ClusterState`, `PipelineState_PipelineState`, +> `DeletePolicy_Response`, `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` — +> has now been pruned per user direction. The proto-style underscored +> identifier convention is intentional and correct: it preserves the +> mapping between TS identifiers and protobuf nested-message paths, +> keeps codegen deterministic, and the `// eslint-disable` line that +> each identifier carries is acceptable cost. Renaming would break the +> wire ↔ TS correspondence that downstream tooling relies on. The 584 +> pruned findings from this pass are reflected in the totals, theme +> list (the former Theme 1 removed), generator recommendations (§8.2 +> removed), and by-the-numbers table below. This was the single +> largest category by package incidence (~85/98). + This document synthesises the per-package audits into the patterns that the upstream generator (and a smaller number of API team decisions) should fix to deliver an idiomatic TypeScript SDK. The vast majority of the findings are @@ -57,30 +72,7 @@ formats; the Databricks JS SDK currently does not. Ranked by approximate package incidence. Each theme is a generator-level defect — one template change fixes ~98 packages. -### Theme 1. Proto-style `_Response` (and other `_Suffix`) identifiers leak into TS — ~85/98 packages - -Every empty or short response message that protobuf wraps as a nested type -of the request is emitted as `_Response` in TypeScript. Each -identifier requires `// eslint-disable-next-line @typescript-eslint/naming-convention` -because the strict TS lint rules reject underscores in PascalCase -identifiers. The same pattern emits proto outer-message wrappers with an -underscored companion enum (`ClusterState_ClusterState`). - -Examples: -- `clusters.ClusterState_ClusterState` — `packages/clusters/src/v2/model.ts:777`. -- `pipelines.PipelineState_PipelineState` — `packages/pipelines/src/v2/model.ts:392`. -- `abacpolicies.DeletePolicy_Response`, `ListPolicies_Response` — `packages/abacpolicies/src/v1/model.ts:82, 173`. -- `cleanrooms.CleanRoom_Status_Enum`, `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` (4-level nesting). -- `jobs.RunLifecycleStateV2_State`, `TerminationCode_Code`, `QueueDetailsCode_Code`, `TerminationType_Type` — `packages/jobs/src/v2/model.ts:499, 532, 632, 717`. -- `postgres.SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` — 56-character triple-tautology, `packages/postgres/src/v1/model.ts:730`. - -**Generator fix:** Flatten nested proto messages to top-level types in TS, -mapping `Outer.Inner` → `OuterInner` (drop underscore). For `_Response` -specifically: emit `Response` (no underscore) regardless of -whether the body has fields — the wrapper itself stays, but the identifier -is clean. - -### Theme 2. Redundant enum-name prefix on every member (proto idiom) — ~84/98 packages +### Theme 1. Redundant enum-name prefix on every member (proto idiom) — ~84/98 packages Every enum is emitted with its members redundantly prefixed by the enum name: @@ -114,7 +106,7 @@ Examples: Either way the prefix that re-states the enum name should not survive into TS. Wire value can stay as-is via Zod transform. -### Theme 3. `*_UNSPECIFIED` proto sentinel values in every enum — ~60/98 packages +### Theme 2. `*_UNSPECIFIED` proto sentinel values in every enum — ~60/98 packages Every protobuf enum carries a zero value `XXX_UNSPECIFIED` that protobuf needs but TS does not. The corresponding field is already @@ -130,7 +122,7 @@ Examples in nearly every audit: `STATE_UNSPECIFIED`, `POLICY_TYPE_UNSPECIFIED`, to TypeScript `undefined` on the way in, and the field's `?:` optionality already expresses "not set" on the way out. -### Theme 4. Verb-phrase request types (no `Request` suffix) — ~80/98 packages +### Theme 3. Verb-phrase request types (no `Request` suffix) — ~80/98 packages Request DTOs are named with bare verb phrases: @@ -156,7 +148,7 @@ Examples: TS convention used by every other large SDK (AWS, Azure, Google Cloud). Wire shape unaffected. -### Theme 5. `Info` (and other vague) suffix on the canonical entity — ~70/98 packages +### Theme 4. `Info` (and other vague) suffix on the canonical entity — ~70/98 packages The Go SDK uses `Info` to name "details of an X" because Go does not have package-qualified imports for types. TS does, and `` alone @@ -164,7 +156,7 @@ suffices. Examples: - `RepoInfo` → `Repo` / `GitFolder` (and the field `repo?: RepoInfo` becomes `repo?: Repo`). - `PolicyInfo` → `Policy`. -- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 8). +- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 7). - `SchemaInfo` → `Schema`. - `CredentialInfo` → `Credential`. - `MetastoreInfo` → `Metastore`. @@ -182,7 +174,7 @@ domain entity. (Heuristic: if `Info` is the only `*` type that isn't a request/response, drop `Info`.) Same for redundant `Options`/`Spec` suffixes on tagged-union arms when the parent has a discriminator. -### Theme 6. Type-name prefix repeats the package — ~70/98 packages +### Theme 5. Type-name prefix repeats the package — ~70/98 packages Every type in a package is prefixed with the package's domain noun, even though the import path already provides namespace disambiguation: @@ -201,7 +193,7 @@ though the import path already provides namespace disambiguation: every type as long as the unprefixed name does not clash with another type in the same package. Wire shape is unaffected. -### Theme 7. Inconsistent acronym casing across the SDK — 98/98 packages +### Theme 6. Inconsistent acronym casing across the SDK — 98/98 packages The SDK currently mixes both `Pascal-then-lower` (`Http`, `Url`, `Json`, `Sql`, `Oauth`, `Pypi`, `Aws`, `Llm`, `Pii`, `Sse`, `Idp`, `Csp`, `Esm`, @@ -367,8 +359,8 @@ Two packages, two `Endpoint*` type families, different products. | `database` | Lakebase / managed Postgres (`DatabaseInstance`, etc.) | | `postgres` | Same Lakebase OLTP surface from a different angle | -Both expose `SyncedTable`, `DatabaseInstance`, `SyncedTable_SyncedTableSpec_*` -heavily-nested types. +Both expose `SyncedTable`, `DatabaseInstance`, and other heavily-nested +types covering the same wire object. ### 2.12 Features @@ -585,53 +577,53 @@ generator pattern it exemplifies. | 1 | `jobs` | `model.ts:3414, 3890` | `Run` overloaded across 7 shapes (`Run`, `BaseRun`, `RunTask`, `Run_JobLevelParameters`, `RunState`, `RunStatus`, `RunTriggerInfo`). | Vague/duplicate concepts | | 2 | `jobs` | `model.ts:150, 280, 1464, 1835` | `Format`, `Source`, `Compute`, `Environment` — top-level types collide with JS/TS built-ins and DOM globals. | Reserved-word collision | | 3 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | -| 4 | `clusters` | `model.ts:777` | `ClusterState_ClusterState` enum identifier — proto outer-message underscore leaks. | Proto outer-message + underscore | -| 5 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | -| 6 | `pipelines` | `model.ts:212-2507` | `Pipelines*` prefix on 15 types in a package called `pipelines` (singular). | Type-name prefix repeats package | -| 7 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | -| 8 | `abacpolicies` | `model.ts:7-14` | `PolicyType.POLICY_TYPE_UNSPECIFIED`/`POLICY_TYPE_ROW_FILTER`/etc. | Redundant enum prefix | -| 9 | `abacpolicies` | `model.ts:82, 173` | `DeletePolicy_Response`, `ListPolicies_Response` — underscore identifier. | Proto `_Response` | -| 10 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | -| 11 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | -| 12 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | -| 13 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | -| 14 | `apps` | `model.ts:606, 962` | `AppResourceApp_AppPermission.CAN_USE` — `App` token thrice. | Proto-nested + redundant prefix | -| 15 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | -| 16 | `genie` | `model.ts passim` | 40 of ~70 types prefixed `Genie*`; remaining have no prefix. | Inconsistent type prefix | -| 17 | `commandexecution` | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` is reused for both `create()` (context id) and `execute()` (command queued) — type repurposed across two semantically different operations. | Type repurposing | -| 18 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | -| 19 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | -| 20 | `secrets` | `model.ts:passim` | 11 of 13 public types carry proto underscore (`CreateScope_Response` etc.). | Proto `_Response` | -| 21 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | -| 22 | `qualitymonitor` | package + types | Singular `qualitymonitor` vs plural `qualitymonitors` — different APIs distinguished only by trailing `s`. | Package-name overlap | -| 23 | `qualitymonitors` | model + types | Both deprecated; `DataMonitorInfo` vs `Monitor` vs `QualityMonitor` — three names for one wire object. | Duplicate concept | -| 24 | `modelservingmanagement` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | -| 25 | `modelservingmanagement` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | -| 26 | `oauthcustomappintegration` | `model.ts:passim` | 18 types named `*OAuthAppIntegration*` — package name re-stated in every type. | Type-name prefix | -| 27 | `oauthcustomappintegration` | package | Name says "custom" but covers both Custom and Published integrations. | Misleading package name | -| 28 | `serviceprincipalsecretsproxy` | files | Byte-identical to `serviceprincipalsecrets` — "proxy" never in code/URL. | Duplicate package | -| 29 | `serviceprincipalsecrets` | `model.ts:42, 59` | `_Response` proto underscores; verb-phrase request types lacking `Request` suffix. | Proto + verb-as-noun | -| 30 | `accountaccesscontrol` | `model.ts:73, 89, 105` | `RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest` — three names for one shape with overlapping `name` fields. | Duplicate concept | -| 31 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | -| 32 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | -| 33 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | -| 34 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | -| 35 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | -| 36 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | -| 37 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | -| 38 | `cleanroomautoapprovalrules` | every type | `CleanRoomAutoApprovalRule` re-states the 26-char package name on every type. | Type-name prefix | -| 39 | `cleanrooms` | `model.ts:passim` | `CleanRoom_Status_Enum`, `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` (4-level proto nesting). | Proto deep-nesting | -| 40 | `database` + `postgres` | model.ts | `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` (56-char triple-tautology); two packages, one product. | Proto + duplicate package | -| 41 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | -| 42 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | -| 43 | `permissions` | `model.ts` | `GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions` — verb-phrase request types. | Verb-as-noun | -| 44 | `permissions` + `grants` + `iam` + `accountaccesscontrol` | passim | Permissions/grants/rule-sets fragmented across 4 packages with overlapping vocabularies. | Cross-package fragmentation | -| 45 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | -| 46 | `repos` | `model.ts:29, 56, 64, 111` | `CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, `RepoInfo` — duplicate shapes + proto underscores. | Proto + duplicate concept | -| 47 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | -| 48 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | -| 49 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | -| 50 | `materializedfeatures` | package | `materializedfeatures` does not match contents (contains feature-tag CRUD, not materialisation logic). | Misleading package name | +| 4 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | +| 5 | `pipelines` | `model.ts:212-2507` | `Pipelines*` prefix on 15 types in a package called `pipelines` (singular). | Type-name prefix repeats package | +| 6 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | +| 7 | `abacpolicies` | `model.ts:7-14` | `PolicyType.POLICY_TYPE_UNSPECIFIED`/`POLICY_TYPE_ROW_FILTER`/etc. | Redundant enum prefix | +| 8 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | +| 9 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | +| 10 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | +| 11 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | +| 12 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission.CAN_USE` — `App` token thrice; package-name re-prefix throughout. | Redundant prefix | +| 13 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | +| 14 | `genie` | `model.ts passim` | 40 of ~70 types prefixed `Genie*`; remaining have no prefix. | Inconsistent type prefix | +| 15 | `commandexecution` | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` is reused for both `create()` (context id) and `execute()` (command queued) — type repurposed across two semantically different operations. | Type repurposing | +| 16 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | +| 17 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | +| 18 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | +| 19 | `secrets` | `model.ts:passim` | `ListAcls_Response.items` should be `acls` (parallel to `ListScopes_Response.scopes` / `ListSecrets_Response.secrets`). | Field-name vocabulary drift | +| 20 | `qualitymonitor` | package + types | Singular `qualitymonitor` vs plural `qualitymonitors` — different APIs distinguished only by trailing `s`. | Package-name overlap | +| 21 | `qualitymonitors` | model + types | Both deprecated; `DataMonitorInfo` vs `Monitor` vs `QualityMonitor` — three names for one wire object. | Duplicate concept | +| 22 | `modelservingmanagement` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | +| 23 | `modelservingmanagement` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | +| 24 | `oauthcustomappintegration` | `model.ts:passim` | 18 types named `*OAuthAppIntegration*` — package name re-stated in every type. | Type-name prefix | +| 25 | `oauthcustomappintegration` | package | Name says "custom" but covers both Custom and Published integrations. | Misleading package name | +| 26 | `serviceprincipalsecretsproxy` | files | Byte-identical to `serviceprincipalsecrets` — "proxy" never in code/URL. | Duplicate package | +| 27 | `serviceprincipalsecrets` | `model.ts:42, 59` | Verb-phrase request types lacking `Request` suffix (`CreateServicePrincipalSecret`, etc.); 23-char package-noun re-stated on every type. | Verb-as-noun + Type-name prefix | +| 28 | `accountaccesscontrol` | `model.ts:73, 89, 105` | `RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest` — three names for one shape with overlapping `name` fields. | Duplicate concept | +| 29 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 30 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | +| 31 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | +| 32 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | +| 33 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | +| 34 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 35 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | +| 36 | `cleanroomautoapprovalrules` | every type | `CleanRoomAutoApprovalRule` re-states the 26-char package name on every type. | Type-name prefix | +| 37 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | +| 38 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | +| 39 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | +| 40 | `permissions` | `model.ts` | `GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions` — verb-phrase request types. | Verb-as-noun | +| 41 | `permissions` + `grants` + `iam` + `accountaccesscontrol` | passim | Permissions/grants/rule-sets fragmented across 4 packages with overlapping vocabularies. | Cross-package fragmentation | +| 42 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | +| 43 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | +| 44 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 45 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | +| 46 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 47 | `materializedfeatures` | package | `materializedfeatures` does not match contents (contains feature-tag CRUD, not materialisation logic). | Misleading package name | +| 48 | `marketplaces` | `model.ts:passim` | 14 verb-phrase request types (`Create`, `Update`, `Delete`, `Search`, `Get`, `List` variants) in a single file. | Verb-as-noun | +| 49 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | +| 50 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum has 22 values with inconsistent casing (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Acronym/brand-value casing | --- @@ -639,104 +631,104 @@ generator pattern it exemplifies. | # | Package | Findings | Top theme | |---|---|---|---| -| 1 | jobs | 193 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes | -| 2 | warehouses | 119 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | -| 3 | endpoints | 114 | `Endpoint*` (vector search) vs `endpoints` (other products); brand-name collision | -| 4 | settings | 106 | Cross-package duplication with `accountsettings`/`workspacesettings`/`workspaceconf` | -| 5 | pipelines | 92 | `Update` noun = pipeline run; `Pipelines*` prefix on every type | -| 6 | postgres | 90 | 18 underscore type names; quad-nested `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` | -| 7 | clusters | 84 | `ClusterState_ClusterState`; per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | -| 8 | catalogs | 84 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | -| 9 | budgets | 84 | Budget vs `budgetpolicy` duplication | -| 10 | functions | 75 | `function` reserved-word; proto-nested `FunctionInfo_*`; `fullNameArg` | -| 11 | forecasting | 73 | `Forecasting*` prefix; underscored type names | -| 12 | genie | 72 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | -| 13 | clusterlibraries | 72 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 14 | apps | 72 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | -| 15 | cleanroomassets | 71 | 18 underscore identifiers; `CleanRoom*` re-prefix on every type | -| 16 | schemas | 68 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | -| 17 | tables | 63 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 18 | metastores | 62 | `Get*Summary_Response` underscores; structural duplicate of `MetastoreInfo` | -| 19 | marketplaces | 62 | 14× `_Response` proto underscores | -| 20 | modelregistry | 61 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | -| 21 | iam | 61 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | -| 22 | instancepools | 59 | Massive structural duplication of `Create*`/`Edit*`/`*_Response`/`*AndStats` | -| 23 | instanceprofiles | 58 | Bare verb request types; vague identifiers | -| 24 | externallocations | 57 | `IsolationMode_*`/`SseEncryptionAlgorithm_*` enum prefixing; cross-cloud queue type naming inconsistency | -| 25 | experiments | 55 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | -| 26 | database | 53 | Package name overlaps `postgres`; deep proto nesting | -| 27 | features | 52 | Three sibling feature packages with blurry boundaries | -| 28 | workspacesettings | 51 | Cross-package duplicates with `settings`/`accountsettings`/`workspaceconf` | -| 29 | credentials | 51 | 4× duplicate type pairs (`Credential*` vs `StorageCredential*`); cross-package with `auth/credentials` | -| 30 | clusterpolicies | 51 | Underscore types; verb-as-noun requests | -| 31 | statementexecution | 50 | Package name overlaps `queryexecution`/`commandexecution`/`queries` | -| 32 | qualitymonitors | 50 | Plural vs singular `qualitymonitor`; both deprecated | -| 33 | globalinitscripts | 50 | Verb-as-noun requests; proto `_Response` wrappers | -| 34 | files | 49 | `Read`/`Move`/`Put`/`Delete`/`Close`/`Create`/`MkDirs`/`AddBlock` — verb-as-noun (legacy DBFS) | -| 35 | cleanrooms | 49 | 4-level proto nesting; redundant enum prefixes throughout | -| 36 | queryhistory | 47 | Vague `Query` types; cross-package overlap with `queries`/`queryexecution` | -| 37 | modelservingmanagement | 47 | `InferenceEndpoint` vs `ServingEndpoint` vs `serving-endpoints` URL — three names | -| 38 | policyfamilies | 44 | "Family" + "Policy Family" mixed; underscored enums | -| 39 | dataquality | 44 | `ListMonitorRequest` singular for list of monitors | -| 40 | supervisoragents | 43 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | -| 41 | registeredmodels | 43 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | -| 42 | accountsettings | 43 | `Csp`/`Esm`/`Llm`/`Dcp` cryptic acronyms; generic `value` discriminator | -| 43 | qualitymonitor | 42 | Sibling-package collision with `qualitymonitors` | -| 44 | lakeview | 42 | Old codename (rebrand to "AI/BI Dashboards") | -| 45 | rfa | 41 | 3-letter cryptic package name | -| 46 | connections | 41 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 47 | commandexecution | 41 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | -| 48 | repos | 40 | "Repos" legacy term; product is "Git folders" | -| 49 | knowledgeassistants | 39 | `KnowledgeAssistant_State` underscore identifier | -| 50 | abacpolicies | 39 | `PolicyInfo`; `_Response` underscores; verb-as-noun requests | -| 51 | usagepolicy | 38 | 1:1 clone of `budgetpolicy` | -| 52 | queries | 38 | Three-package overlap with `queryhistory`/`queryexecution` | -| 53 | onlinetables | 38 | `ProvisioningInfo_State`; underscore identifiers | -| 54 | indexes | 38 | Package name not "vector search"; `MiniVectorIndex` duplicates `VectorIndex` | -| 55 | workspacebindings | 37 | Bare verb requests; underscore identifiers | -| 56 | externalmetadata | 37 | `SystemType.*_UNSPECIFIED`; brand-value casing (`POWER_BI`, `STREAM_NATIVE`) | -| 57 | secrets | 36 | 11/13 types with proto underscore; mutation-verb inconsistency | -| 58 | bundle | 36 | Generic package name (`bundle`); verb-as-noun requests | -| 59 | alerts | 35 | Mixed v1/v2 | -| 60 | permissions | 34 | Cross-package overlap with `iam`/`accountaccesscontrol`/`grants` | -| 61 | logdeliveryconfigurations | 34 | Long verbose names | -| 62 | grants | 34 | Verb-phrase request types; underscore identifiers | -| 63 | modelservingquery | 33 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | -| 64 | materializedfeatures | 33 | Package name doesn't match contents | -| 65 | workspace | 32 | Most overloaded of 5 `workspace*` packages | -| 66 | featurestore | 32 | `OnlineStore_State` underscore identifier | -| 67 | environments | 32 | `Environment` generic name | -| 68 | customllms | 32 | `Llm` casing throughout | -| 69 | budgetpolicy | 32 | Sibling clone in `usagepolicy` | -| 70 | tokens | 31 | Cross-package duplicate of `tokenmanagement` | -| 71 | entitytagassignments | 31 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 72 | tagpolicies | 30 | Three sibling tag packages with overlapping vocab | -| 73 | queryexecution | 30 | Package name far broader than scope (dashboards-only) | -| 74 | tokenmanagement | 29 | Overlap with `tokens`; duplicate `AutoscopeState` enum | -| 75 | workspaceassignment | 28 | Cross-package overlap with `iam` | -| 76 | disasterrecovery | 28 | `FailoverFailoverGroupRequest` stutter | -| 77 | tagassignments | 27 | Three-package tag split; sibling field-name drift | -| 78 | serviceprincipalsecretsproxy | 26 | Byte-identical to non-proxy version | -| 79 | serviceprincipalsecrets | 26 | Identical to `serviceprincipalsecretsproxy` | -| 80 | externallineage | 26 | `Direction_LineageDirection` underscore; `tpe` typo | -| 81 | volumes | 25 | `fullNameArg`; verb-as-noun requests | -| 82 | usagedashboards | 25 | Vague type names | -| 83 | accountaccesscontrolproxy | 25 | 1:1 surface duplicate of `accountaccesscontrol` | -| 84 | secretsuc | 24 | `uc` cryptic suffix; collides with `secrets` | -| 85 | notificationdestinations | 24 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 86 | workspaceconf | 23 | `conf` cryptic abbreviation; wire-shape regression | -| 87 | resourcequotas | 23 | Underscore identifiers | -| 88 | gitcredentials | 23 | Three "Credentials" packages with different meanings | -| 89 | modelservingdebug | 22 | Tiny package, mostly proto underscores | -| 90 | systemschemas | 21 | Sibling-package collision with `schemas` | -| 91 | dataclassification | 21 | Tag-domain overlap | -| 92 | billableusagedownload | 20 | Verb in package name (`download`) | -| 93 | cleanroomautoapprovalrules | 19 | 26-char package name; `CleanRoomAutoApprovalRule` re-prefix | -| 94 | cleanroomtaskruns | 18 | `LifeCycle` casing; one of four cleanroom packages | -| 95 | artifactallowlists | 18 | Vague type names | -| 96 | oauthcustomappintegration | 17 | Package covers Custom AND Published despite name | -| 97 | oauthpublishedapp | 16 | Singular but only `list*` endpoints | -| 98 | accountaccesscontrol | 16 | Sibling duplicate `accountaccesscontrolproxy` | +| 1 | jobs | 177 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes | +| 2 | endpoints | 111 | `Endpoint*` (vector search) vs `endpoints` (other products); brand-name collision | +| 3 | warehouses | 109 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 4 | pipelines | 88 | `Update` noun = pipeline run; `Pipelines*` prefix on every type | +| 5 | settings | 87 | Cross-package duplication with `accountsettings`/`workspacesettings`/`workspaceconf` | +| 6 | postgres | 83 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | +| 7 | clusters | 76 | Per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | +| 8 | budgets | 73 | Budget vs `budgetpolicy` duplication | +| 9 | apps | 67 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | +| 10 | genie | 64 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 11 | catalogs | 60 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | +| 12 | tables | 59 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 13 | modelregistry | 59 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | +| 14 | iam | 56 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | +| 15 | clusterlibraries | 55 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 16 | schemas | 54 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | +| 17 | functions | 54 | `function` reserved-word; `fullNameArg`; cryptic single-letter enum variants | +| 18 | instanceprofiles | 53 | Bare verb request types; vague identifiers | +| 19 | experiments | 53 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 20 | qualitymonitors | 52 | Plural vs singular `qualitymonitor`; both deprecated | +| 21 | instancepools | 50 | Massive structural duplication of `Create*`/`Edit*`/`*AndStats` | +| 22 | statementexecution | 48 | Package name overlaps `queryexecution`/`commandexecution`/`queries` | +| 23 | metastores | 48 | Structural duplicate of `MetastoreInfo`; `*Summary` returning the entity | +| 24 | cleanroomassets | 48 | `CleanRoom*` re-prefix on every type; `details`/`localDetails` discriminated-union arms | +| 25 | marketplaces | 47 | 14 verb-phrase request types; `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | +| 26 | workspacesettings | 45 | Cross-package duplicates with `settings`/`accountsettings`/`workspaceconf` | +| 27 | queryhistory | 45 | Vague `Query` types; cross-package overlap with `queries`/`queryexecution` | +| 28 | clusterpolicies | 45 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | +| 29 | features | 44 | Three sibling feature packages with blurry boundaries | +| 30 | dataquality | 44 | `ListMonitorRequest` singular for list of monitors | +| 31 | supervisoragents | 43 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 32 | registeredmodels | 42 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | +| 33 | database | 42 | Package name overlaps `postgres`; deep proto nesting | +| 34 | accountsettings | 42 | `Csp`/`Esm`/`Llm`/`Dcp` cryptic acronyms; generic `value` discriminator | +| 35 | modelservingmanagement | 41 | `InferenceEndpoint` vs `ServingEndpoint` vs `serving-endpoints` URL — three names | +| 36 | rfa | 40 | 3-letter cryptic package name | +| 37 | globalinitscripts | 40 | Verb-as-noun requests; brittle `script_id` path-parameter handling | +| 38 | commandexecution | 39 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | +| 39 | qualitymonitor | 38 | Sibling-package collision with `qualitymonitors` | +| 40 | policyfamilies | 38 | "Family" + "Policy Family" mixed; underscored enums | +| 41 | knowledgeassistants | 37 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | +| 42 | indexes | 37 | Package name not "vector search"; `MiniVectorIndex` duplicates `VectorIndex` | +| 43 | files | 37 | `Read`/`Move`/`Put`/`Delete`/`Close`/`Create`/`MkDirs`/`AddBlock` — verb-as-noun (legacy DBFS) | +| 44 | onlinetables | 36 | Underspecified IDs; deprecation drift | +| 45 | externalmetadata | 36 | `SystemType.*_UNSPECIFIED`; brand-value casing (`POWER_BI`, `STREAM_NATIVE`) | +| 46 | queries | 35 | Three-package overlap with `queryhistory`/`queryexecution` | +| 47 | lakeview | 35 | Old codename (rebrand to "AI/BI Dashboards") | +| 48 | connections | 35 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 49 | alerts | 35 | Mixed v1/v2 | +| 50 | abacpolicies | 35 | `PolicyInfo`; verb-as-noun requests; redundant enum prefix | +| 51 | bundle | 34 | Generic package name (`bundle`); verb-as-noun requests | +| 52 | workspacebindings | 33 | Bare verb requests | +| 53 | usagepolicy | 33 | 1:1 clone of `budgetpolicy` | +| 54 | secrets | 33 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | +| 55 | repos | 33 | "Repos" legacy term; product is "Git folders" | +| 56 | permissions | 33 | Cross-package overlap with `iam`/`accountaccesscontrol`/`grants` | +| 57 | logdeliveryconfigurations | 33 | Long verbose names | +| 58 | credentials | 33 | 4× duplicate type pairs (`Credential*` vs `StorageCredential*`); cross-package with `auth/credentials` | +| 59 | customllms | 32 | `Llm` casing throughout | +| 60 | workspace | 31 | Most overloaded of 5 `workspace*` packages | +| 61 | modelservingquery | 31 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 62 | environments | 31 | `Environment` generic name | +| 63 | entitytagassignments | 31 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 64 | tokens | 30 | Cross-package duplicate of `tokenmanagement` | +| 65 | tagpolicies | 30 | Three sibling tag packages with overlapping vocab | +| 66 | queryexecution | 30 | Package name far broader than scope (dashboards-only) | +| 67 | materializedfeatures | 30 | Package name doesn't match contents | +| 68 | cleanrooms | 30 | Redundant enum prefixes throughout | +| 69 | budgetpolicy | 30 | Sibling clone in `usagepolicy` | +| 70 | workspaceassignment | 28 | Cross-package overlap with `iam` | +| 71 | grants | 28 | Verb-phrase request types | +| 72 | featurestore | 28 | Cross-package duplicates in feature trio | +| 73 | tagassignments | 27 | Three-package tag split; sibling field-name drift | +| 74 | externallineage | 25 | `Direction_LineageDirection`; `tpe` typo | +| 75 | disasterrecovery | 25 | `FailoverFailoverGroupRequest` stutter | +| 76 | accountaccesscontrolproxy | 25 | 1:1 surface duplicate of `accountaccesscontrol` | +| 77 | tokenmanagement | 24 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 78 | secretsuc | 24 | `uc` cryptic suffix; collides with `secrets` | +| 79 | workspaceconf | 23 | `conf` cryptic abbreviation; wire-shape regression | +| 80 | serviceprincipalsecrets | 23 | Identical to `serviceprincipalsecretsproxy`; verb-as-noun requests | +| 81 | volumes | 22 | `fullNameArg`; verb-as-noun requests | +| 82 | serviceprincipalsecretsproxy | 22 | Byte-identical to non-proxy version | +| 83 | notificationdestinations | 22 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 84 | usagedashboards | 21 | Vague type names | +| 85 | resourcequotas | 21 | Vague type names | +| 86 | modelservingdebug | 21 | Tiny package, narrow surface | +| 87 | billableusagedownload | 20 | Verb in package name (`download`) | +| 88 | dataclassification | 19 | Tag-domain overlap | +| 89 | gitcredentials | 17 | Three "Credentials" packages with different meanings | +| 90 | forecasting | 17 | Generic-named `Waiter` API; cross-package overlap with `experiments` | +| 91 | cleanroomautoapprovalrules | 17 | 26-char package name; `CleanRoomAutoApprovalRule` re-prefix | +| 92 | accountaccesscontrol | 16 | Sibling duplicate `accountaccesscontrolproxy` | +| 93 | oauthcustomappintegration | 15 | Package covers Custom AND Published despite name | +| 94 | externallocations | 15 | `IsolationMode_*`/`SseEncryptionAlgorithm_*` enum prefixing; cross-cloud queue type naming inconsistency | +| 95 | cleanroomtaskruns | 15 | `LifeCycle` casing; one of four cleanroom packages | +| 96 | systemschemas | 14 | Sibling-package collision with `schemas` | +| 97 | artifactallowlists | 14 | Vague type names | +| 98 | oauthpublishedapp | 12 | Singular but only `list*` endpoints | --- @@ -744,26 +736,7 @@ generator pattern it exemplifies. Ranked by impact across all 98 packages. Each item is one template change. -### 8.1 Stop emitting `_Response` underscore identifiers - -Emit `Response` (no underscore) for every response wrapper — -the wrapper itself remains (kept for forward compatibility), but the -identifier becomes a clean PascalCase token. This removes ~70 -`eslint-disable` comments per package and ~5,000 underscore identifiers -across the SDK. Affects ~85/98 packages. - -### 8.2 Flatten proto nested types - -Map proto `Outer.Inner` to TS `OuterInner` (clean PascalCase, no -underscore). Eliminates `ClusterState_ClusterState`, -`PipelineState_PipelineState`, `RunLifecycleStateV2_State`, -`TerminationCode_Code`, -`EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol`, -and ~200 other underscored identifiers. The outer-message wrapper -interface itself is retained (forward compatibility); only the -underscored identifier flattens. Affects ~85/98 packages. - -### 8.3 Drop the redundant enum-name prefix on members +### 8.1 Drop the redundant enum-name prefix on members `PolicyType.POLICY_TYPE_ROW_FILTER` → `PolicyType.RowFilter` (PascalCase preferred for new code; SCREAMING_SNAKE acceptable if the project policy @@ -771,14 +744,14 @@ chooses it). Map the wire value `POLICY_TYPE_ROW_FILTER` via Zod transform. Drop all `*_UNSPECIFIED` members and rely on the field's optional `?:`/`undefined` for "unset". Affects ~84/98 packages. -### 8.4 Append `Request` to every request DTO type +### 8.2 Append `Request` to every request DTO type `DeletePolicy` → `DeletePolicyRequest`. Eliminates verb-as-noun confusion in import lists and resolves the `client.delete(req: Delete)` collision patterns in `workspace`, `files`, `experiments`, `grants`, and ~75 other packages. Affects ~80/98 packages. -### 8.5 Drop the `Info`/`Spec`/`Details` suffix on canonical entities +### 8.3 Drop the `Info`/`Spec`/`Details` suffix on canonical entities `RepoInfo` → `Repo`, `PolicyInfo` → `Policy`, `SchemaInfo` → `Schema`, `CredentialInfo` → `Credential`, `MetastoreInfo` → `Metastore`, @@ -786,7 +759,7 @@ packages. Affects ~80/98 packages. both `Foo` and `FooInfo` and they mean different things.) Affects ~70/98 packages. -### 8.6 Adopt one acronym-casing policy +### 8.4 Adopt one acronym-casing policy Decide on `Pascal-then-lower` (`Url`, `Id`, `Json`, `Sql`, `Oauth`, `Pypi`, `Aws`, `Llm`) or `ALL_CAPS-for-≤2` (`URL`, `ID`, `Json`, `Sql`, @@ -796,7 +769,7 @@ field names (`webhookUrl` vs `webhookURL`), enum values (`URL` vs `Url` — the latter avoids JS-global collision). Affects 98/98 packages. -### 8.7 Rename `Client` per package +### 8.5 Rename `Client` per package Every package exports a class literally named `Client`. Imagine a user with `jobs`, `clusters`, `pipelines` all importing `Client`. Rename to @@ -804,7 +777,7 @@ with `jobs`, `clusters`, `pipelines` all importing `Client`. Rename to `WarehousesClient`. Removes the most common cross-package alias-on-import pattern. Affects 98/98 packages. -### 8.8 Strip the package-name prefix from type names +### 8.6 Strip the package-name prefix from type names When a type name begins with the package's domain noun and the unprefixed name does not clash with another type in the same package, drop the @@ -812,7 +785,7 @@ prefix. `Pipelines*` → drop, `Genie*` → drop, `CleanRoom*` → drop, `OAuthAppIntegration*` → drop where unambiguous, `Tag*` → drop in single-domain packages. Affects ~70/98 packages. -### 8.9 (Bonus) Surface deprecations as `@deprecated` JSDoc tags +### 8.7 (Bonus) Surface deprecations as `@deprecated` JSDoc tags Today the audits found dozens of fields whose JSDoc text says "deprecated" in prose but does not carry the `@deprecated` tag, so IDEs do not strike @@ -856,7 +829,8 @@ packages (every package that has a paginating list endpoint). The audits used a shared 20-category rubric. The most-cited categories across all 98 audits (Category 11 "Empty / trivial wrapper types" has -been retired — see prune note in the header): +been retired — see prune note in the header; Category 4 "Underscores +in TS identifiers" has been retired in this prune pass): | # | Category | Audits citing it | |---|---|---| @@ -872,11 +846,8 @@ been retired — see prune note in the header): | 14 | Go / Java-style names | 89 | | 5 | Cryptic abbreviations | 86 | | 2 | Redundant enum prefix | 84 | -| 4 | Underscores in TS identifiers | 84 | | 8 | Redundant suffix | 79 | | 9 | Singular/plural mismatches | 78 | | 16 | Field contradicting type domain | 77 | | 18 | Long enum values | 73 | | 13 | Verb-tense inconsistency | 66 | - - \ No newline at end of file diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index bd67e14d..3bcb8513 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -3,14 +3,14 @@ **Path:** `packages/abacpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter, column-mask, deny, and grant policies. -**Total weird names flagged:** 39 +**Total weird names flagged:** 35 ## Summary | Severity | Count | | --- | --- | -| High | 11 | +| High | 9 | | Medium | 17 | -| Low | 7 | +| Low | 5 | | Observation | 4 | ## High severity @@ -27,55 +27,43 @@ - **Suggested name:** `DeletePolicyRequest` (and `CreatePolicyRequest`, `GetPolicyRequest`, `ListPoliciesRequest`, `UpdatePolicyRequest`). - **Rationale:** TypeScript convention names request DTOs with a `Request` suffix; a bare verb-phrase noun reads as an action. Index.ts re-exports these as types, so consumers see `import type {DeletePolicy}` which looks like a function. -### 3. `DeletePolicy_Response` — `src/v1/model.ts:82` -- **Why weird:** Underscore in identifier (proto-style nested type). Requires an `eslint-disable` for `@typescript-eslint/naming-convention`. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** `DeletePolicyResponse`. -- **Rationale:** TS strict-type-checked rejects `Foo_Bar`. The `eslint-disable` is a tell that the name fights the language. - -### 4. `ListPolicies_Response` — `src/v1/model.ts:173` -- **Why weird:** Underscore in identifier (proto-style nested type). Required `eslint-disable`. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** `ListPoliciesResponse`. -- **Rationale:** Same as `DeletePolicy_Response`. The underscore convention is a leaky proto abstraction and is not standard TypeScript. - -### 5. `PolicyInfo` — `src/v1/model.ts:190` +### 3. `PolicyInfo` — `src/v1/model.ts:190` - **Why weird:** `Info` is a generic suffix that adds nothing — every type is "info about something". This is the central domain entity; it should just be called `Policy`. (See rule 1: `Info` is on the vague-suffix list.) - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix). - **Suggested name:** `Policy`. - **Rationale:** `Policy` is the noun the user actually thinks about. The `Info` suffix is a tic carried over from Go SDK naming conventions that does not apply in TS, where the namespace and import path already disambiguate. -### 6. `onSecurableType: string` on `DeletePolicy` / `GetPolicy` / `ListPolicies` / `UpdatePolicy` — `src/v1/model.ts:74,135,154,335` +### 4. `onSecurableType: string` on `DeletePolicy` / `GetPolicy` / `ListPolicies` / `UpdatePolicy` — `src/v1/model.ts:74,135,154,335` - **Why weird:** Typed as `string` everywhere on these request DTOs while the same field on `PolicyInfo` (`model.ts:198`) is typed as `SecurableType` enum. The values are the same domain (`CATALOG`, `SCHEMA`, ...) — the inconsistency is a bug. - **Category:** 6 (misleading — name implies enum, actual type is `string`), 16 (field type contradicts domain). - **Suggested name:** Keep the name but type it `SecurableType`. - **Rationale:** Same field name with two different types across four request DTOs forces callers to remember which one is loose. This is almost certainly a generator bug worth flagging upstream. -### 7. `onSecurableFullname` — `src/v1/model.ts:75,76,136,155,202,336` +### 5. `onSecurableFullname` — `src/v1/model.ts:75,76,136,155,202,336` - **Why weird:** `fullname` is one un-camelCased word. Should be `fullName` to match field-naming conventions used everywhere else in the same model (`functionName`, `tagKey`, `columnAlias`, `pageToken`, etc.). - **Category:** 3 (acronym/casing inconsistency — `name` is one word and should follow camelCase, so `Fullname` is wrong). - **Suggested name:** `onSecurableFullName` (wire stays `on_securable_fullname`). - **Rationale:** Internal consistency. JS/TS convention treats `fullName` as two words; the Go SDK collapses `Fullname` but TS shouldn't blindly inherit that. -### 8. `FunctionArgExpression` — `src/v1/model.ts:98` +### 6. `FunctionArgExpression` — `src/v1/model.ts:98` - **Why weird:** `Arg` is an abbreviation for `Argument` in a type name even though the sibling type `FunctionArgument` (model.ts:108) spells it out. Within five lines the SDK uses both forms. - **Category:** 5 (cryptic abbreviation when the long form is used right next door), 17 (inconsistency with sibling type). - **Suggested name:** `FunctionArgumentExpression`. - **Rationale:** Pick one. Right now `functionArgExpression` (field) shows up as a discriminator value while `functionArgument` is the containing type, which is jarring to read. -### 9. `useSessionIdentity` field — `src/v1/model.ts:292` +### 7. `useSessionIdentity` field — `src/v1/model.ts:292` - **Why weird:** Field documented as "Temporary for migrating customers to session identity. After a grace period, this field will be removed and all policies will use session identity." Shipping an explicitly temporary flag in the public SDK surface is risky — once removed, every caller breaks. - **Category:** 6 (misleading: appears stable but is explicitly a migration toggle). - **Suggested name:** Either omit from public type or mark `@deprecated` from day one. - **Rationale:** Public SDK fields should outlive the API; an "everyone will be on this in 6 months" boolean shouldn't live in a stable type. Worth pushing back upstream. -### 10. `MatchColumn` — `src/v1/model.ts:183` +### 8. `MatchColumn` — `src/v1/model.ts:183` - **Why weird:** Reads as a verb (`MatchColumn`) — could be a method or a type. The field that uses it is plural (`matchColumns: MatchColumn[]`), which then reads as "match columns are an array of `MatchColumn`", and a `MatchColumn` is actually a "column matcher / condition + alias pair". - **Category:** 6 (misleading verb-as-noun), 9 (singular noun whose meaning is unclear). - **Suggested name:** `ColumnMatcher` or `ColumnMatchCondition`. - **Rationale:** Type names should be nouns; the verb form misleads. `ColumnMatcher` makes `matchColumns: ColumnMatcher[]` clearly read as "the matchers". -### 11. `useSessionIdentity` and `forSecurableType` / `onSecurableType` field prefixes — `src/v1/model.ts:198,223,292` +### 9. `useSessionIdentity` and `forSecurableType` / `onSecurableType` field prefixes — `src/v1/model.ts:198,223,292` - **Why weird:** Three different prefixes for related concepts on the same struct: `on_securable_type`, `for_securable_type`, `use_session_identity`. The `on`/`for` split (carrier vs. target securable) is subtle and easily confused. Field names alone do not communicate which is which. - **Category:** 1 (vague — the preposition does the disambiguation), 6 (misleading without docs). - **Suggested name:** Rename `forSecurableType` to `appliesToSecurableType` (or similar) and `onSecurableType` to `definedOnSecurableType` to make the distinction explicit. @@ -83,103 +71,103 @@ ## Medium severity -### 12. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:35` +### 10. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:35` - **Why weird:** Enum value pinned by a comment that says it isn't a real securable yet: "TODO: [UC-2980] Staging tables aren't full-fleged securables yet." Internal TODOs in generated SDK enums leak abstraction. - **Category:** 18 (questionable enum value). - **Suggested name:** Remove until it actually is a securable, or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't contain TODO-tagged speculative values. -### 13. `ColumnMaskOptions.using: FunctionArgument[]` — `src/v1/model.ts:56` +### 11. `ColumnMaskOptions.using: FunctionArgument[]` — `src/v1/model.ts:56` - **Why weird:** Field named `using` — a SQL reserved word and a generic preposition. Doesn't say what is being used. - **Category:** 1 (vague), 10 (reserved-word-adjacent — `using` is a reserved-context keyword in JS dynamic import / TS). - **Suggested name:** `extraArguments` / `additionalArguments` / `argumentList`. - **Rationale:** `using` on its own carries no semantic load; readers must consult the doc to find out it's "additional positional args". Also appears on `RowFilterOptions` (model.ts:307) with the same problem. -### 14. `ColumnMaskOptions.onColumn` — `src/v1/model.ts:51` +### 12. `ColumnMaskOptions.onColumn` — `src/v1/model.ts:51` - **Why weird:** Preposition-prefixed field name (`onColumn`) that just identifies the masked column. Inconsistent with `functionName` (also on the same type, no preposition). - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `maskedColumnAlias` or `targetColumnAlias`. - **Rationale:** Names should describe what the field *is*, not its prepositional relationship. -### 15. `FunctionArgument.arg` discriminator field — `src/v1/model.ts:110` +### 13. `FunctionArgument.arg` discriminator field — `src/v1/model.ts:110` - **Why weird:** `FunctionArgument` has a field `arg` (one of three variants). Type name and field name are near-duplicates; the field name is also an abbreviation of the type. - **Category:** 5 (cryptic abbreviation), 11 (near-duplicate naming). - **Suggested name:** Rename the field to `value` or `kind`. - **Rationale:** `functionArgument.arg.$case === 'alias'` reads weirdly; the field name repeats an abbreviation of the type name. -### 16. `FunctionArgExpression.expr` discriminator field — `src/v1/model.ts:99` +### 14. `FunctionArgExpression.expr` discriminator field — `src/v1/model.ts:99` - **Why weird:** Field uses the three-letter abbreviation `expr` rather than spelling out `expression`. - **Category:** 5 (`expr` is a cryptic abbreviation). - **Suggested name:** `expression` (spell out). - **Rationale:** `expr` is the kind of three-letter abbreviation `typescript.mdc` discourages. -### 17. `TagIntrospectionExpression.expr` discriminator field — `src/v1/model.ts:313` +### 15. `TagIntrospectionExpression.expr` discriminator field — `src/v1/model.ts:313` - **Why weird:** Same `expr` problem as above. A `TagIntrospectionExpression.expr` reads as redundant — the type is already an expression. - **Category:** 5 (`expr` abbreviation), 17 (`expr` reused with two different meanings within model.ts). - **Suggested name:** `value` (since the type itself is already "an expression"), or `variant`. - **Rationale:** Reader hits `expression.expr.$case === 'tagValue'` which is noise on noise. -### 18. `ColumnTagValueExtraction` / `TagValueExtraction` — `src/v1/model.ts:60,328` +### 16. `ColumnTagValueExtraction` / `TagValueExtraction` — `src/v1/model.ts:60,328` - **Why weird:** Pair of near-identical types, named with a clunky `XExtraction` suffix. The two together describe "get tag value (on securable)" vs "get column tag value", but the names imply more weight than the types carry (each holds 1-2 strings). - **Category:** 7 (overly verbose), 8 (redundant `Extraction` suffix — these aren't extractions; they're parameters to a `getTagValue` introspection call). - **Suggested name:** `SecurableTagSelector` and `ColumnTagSelector` (or just `Tag` and `ColumnTag`). - **Rationale:** The "extraction" framing is a verb forced into a noun. `Selector`/`Tag` is shorter and more accurate. -### 19. `policyInfo` field on `CreatePolicy` / `UpdatePolicy` — `src/v1/model.ts:69,349` +### 17. `policyInfo` field on `CreatePolicy` / `UpdatePolicy` — `src/v1/model.ts:69,349` - **Why weird:** Field named after the entity's awkward type (`policyInfo: PolicyInfo`). If `PolicyInfo` is renamed to `Policy`, this becomes `policy: Policy` which is much cleaner. - **Category:** 20 (type-suffix tautology), 1 (`Info`). - **Suggested name:** `policy` (paired with type renamed to `Policy`). -- **Rationale:** Tied to the `PolicyInfo` -> `Policy` rename (finding #5). +- **Rationale:** Tied to the `PolicyInfo` -> `Policy` rename (finding #3). -### 20. `policyType: PolicyType` field on `PolicyInfo` — `src/v1/model.ts:227` +### 18. `policyType: PolicyType` field on `PolicyInfo` — `src/v1/model.ts:227` - **Why weird:** Type-suffix tautology (`policyType` field of type `PolicyType`). - **Category:** 20 (type-suffix tautology). - **Suggested name:** `type: PolicyType` if `PolicyInfo` is renamed to `Policy`; otherwise tolerate. - **Rationale:** Rule 20 in spec. The wire field is `policy_type` so the marshalled JSON stays unchanged. -### 21. `onSecurableType` / `forSecurableType` type-suffix tautology — `src/v1/model.ts:198,223` +### 19. `onSecurableType` / `forSecurableType` type-suffix tautology — `src/v1/model.ts:198,223` - **Why weird:** Same as above — fields named `onSecurableType` of type `SecurableType` and `forSecurableType` of type `SecurableType`. - **Category:** 20 (type-suffix tautology). -- **Suggested name:** Drop `Type` from the field once renaming (`onSecurable: SecurableType`, `forSecurable: SecurableType`) — though it conflicts with finding #11. Better to combine the two renames (`definedOnSecurable: SecurableType`, `appliesToSecurable: SecurableType`). +- **Suggested name:** Drop `Type` from the field once renaming (`onSecurable: SecurableType`, `forSecurable: SecurableType`) — though it conflicts with finding #9. Better to combine the two renames (`definedOnSecurable: SecurableType`, `appliesToSecurable: SecurableType`). - **Rationale:** Reduces tautology and clarifies semantics at once. -### 22. Inconsistent rename style for `*Options` types — `src/v1/model.ts:38,84,142,295` +### 20. Inconsistent rename style for `*Options` types — `src/v1/model.ts:38,84,142,295` - **Why weird:** `ColumnMaskOptions`, `DenyOptions`, `GrantOptions`, `RowFilterOptions` — four mostly-identical-shaped types describing variants of policy options. Each is a discriminator member; the `Options` suffix is redundant given the discriminator already says "this is the X options". - **Category:** 8 (redundant suffix), 12 (duplicate concept across four similar types). - **Suggested name:** Either keep current names but acknowledge as boilerplate, or rename to `RowFilter`, `ColumnMask`, `Deny`, `Grant` (the `$case` discriminator already disambiguates). - **Rationale:** Generator artefact; flagging because four near-identical types is the moment to ask whether the API surface should collapse. -### 23. `ListPolicies` request type — `src/v1/model.ts:152` -- **Why weird:** Plural type name for a singular request. Should be `ListPoliciesRequest`. Same issue as #2 but pluralisation collides with `policies: PolicyInfo[]` inside `ListPolicies_Response`, making it momentarily ambiguous which one is the type and which is the field. +### 21. `ListPolicies` request type — `src/v1/model.ts:152` +- **Why weird:** Plural type name for a singular request. Should be `ListPoliciesRequest`. Same issue as #2 but pluralisation collides with `policies: PolicyInfo[]` inside the list response, making it momentarily ambiguous which one is the type and which is the field. - **Category:** 6 (misleading), 9 (plural request vs singular response). - **Suggested name:** `ListPoliciesRequest`. - **Rationale:** Tied to finding #2. -### 24. `whenCondition` field — `src/v1/model.ts:225` +### 22. `whenCondition` field — `src/v1/model.ts:225` - **Why weird:** `when` prefix is a SQL keyword; the field is a free-form condition expression. Just `condition` would suffice given the field already lives on `PolicyInfo`. - **Category:** 1 (vague prefix), 10 (reserved-word-adjacent). - **Suggested name:** `condition` or `conditionExpression`. - **Rationale:** `when_condition` is wire-only; the TS name can drop the redundant `when_`. -### 25. `toPrincipals` / `exceptPrincipals` field names — `src/v1/model.ts:215,217` +### 23. `toPrincipals` / `exceptPrincipals` field names — `src/v1/model.ts:215,217` - **Why weird:** Preposition-prefixed names mirror SQL `TO`/`EXCEPT` syntax (this is an ABAC-on-UC policy, the API mimics SQL `GRANT ... TO ... EXCEPT ...`). For programmatic SDK consumers, `principals` and `excludedPrincipals` would read more naturally. - **Category:** 1 (vague), 14 (Go/SQL-style names not idiomatic for TS). - **Suggested name:** `appliedPrincipals` / `excludedPrincipals` (or `principals` and `excludePrincipals`). - **Rationale:** Consumers who don't know the SQL syntax will misread `to_principals` as "principal list to apply to" and miss that `except_principals` is the complement. -### 26. `MatchColumn.condition: string` — `src/v1/model.ts:185` +### 24. `MatchColumn.condition: string` — `src/v1/model.ts:185` - **Why weird:** A `MatchColumn` has a field called `condition` (matched column condition expression) and an `alias`. The condition could equally well be called `expression`; "condition" implies boolean, but it's actually a column-selector expression evaluated to a column. - **Category:** 6 (misleading). - **Suggested name:** `columnExpression` or `selector`. - **Rationale:** Domain reading: "match columns where condition = X" suggests filtering rows; here it actually selects which columns the policy applies to. Easy to misread. -### 27. `PolicyInfo.id` — `src/v1/model.ts:192` +### 25. `PolicyInfo.id` — `src/v1/model.ts:192` - **Why weird:** Bare `id` field on `PolicyInfo` alongside `name`, `onSecurableFullname`, etc. — multiple identifier-like fields; bare `id` is underspecified. - **Category:** 19 (underspecified id when multiple ids exist). - **Suggested name:** `policyId`. - **Rationale:** Disambiguates from securable identifiers in the same struct. -### 28. `PolicyInfo.comment` — `src/v1/model.ts:210` +### 26. `PolicyInfo.comment` — `src/v1/model.ts:210` - **Why weird:** Doc says "Optional description of the policy" but the field is named `comment`. SQL stores DDL comments, sure, but a TS-facing field that the JSDoc calls a description should be `description`. - **Category:** 6 (misleading — doc says description, name says comment). - **Suggested name:** `description`. @@ -187,43 +175,31 @@ ## Low severity -### 29. `unmarshalDeletePolicy_ResponseSchema` — `src/v1/model.ts:381` -- **Why weird:** Schema name carries the underscore from the type plus an `eslint-disable`. -- **Category:** 4 (underscore identifier). -- **Suggested name:** Falls out if `DeletePolicy_Response` -> `DeletePolicyResponse`. -- **Rationale:** Mechanical cascade from #3. - -### 30. `unmarshalListPolicies_ResponseSchema` — `src/v1/model.ts:440` -- **Why weird:** Same as #29. -- **Category:** 4. -- **Suggested name:** Mechanical cascade from #4. -- **Rationale:** Same. - -### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 27. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; only one place in the file but flagged for consistency review across the SDK. -### 32. `flattenQueryParams` — `src/v1/utils.ts:123` +### 28. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it's an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 33. `readAll` — `src/v1/utils.ts:40` +### 29. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 34. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 30. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). - **Rationale:** Names should differ in more than the `Http` infix. -### 35. `HttpCallOptions` — `src/v1/utils.ts:15` +### 31. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused throughout the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, `RowFilterOptions`, ...). Within this file there's also `Options` imported from `@databricks/sdk-core/api` (line 3). - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of args). @@ -231,17 +207,17 @@ ## Observations -### 36. Wire/TS divergence is heavy +### 32. Wire/TS divergence is heavy The model file is ~796 lines for ~15 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. -### 37. Action-verb conventions in `Client` +### 33. Action-verb conventions in `Client` The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) -### 38. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` +### 34. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` The codebase uses `Http` (`HttpClient`, `HttpRequest`, `executeHttpCall`) and `URLSearchParams` (Web standard) and `url` (lowercase) and `userAgent`. Mixing `Http` (PascalCase capital-then-lower) with the imported `URLSearchParams` (ALLCAPS) is inconsistent — common across JS ecosystem and probably not worth changing, but worth noting. - **Category:** 3 (acronym casing). -### 39. `abac` abbreviation only appears in package name +### 35. `abac` abbreviation only appears in package name The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. Comments on `useSessionIdentity` (model.ts:286) mention "ABAC" once. May confuse users searching by acronym. - **Category:** 5 (cryptic abbreviation in package name). diff --git a/.agent/naming-audit/accountsettings.md b/.agent/naming-audit/accountsettings.md index 8a46859a..0bf633a7 100644 --- a/.agent/naming-audit/accountsettings.md +++ b/.agent/naming-audit/accountsettings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/accountsettings/` **Versions audited:** v1 **Inferred domain:** Account-level Databricks settings governing compliance profiles, IP access toggles, legacy-feature flags, ESM/CSP enablement, LLM-proxy partner-powered AI, and the Personal Compute default policy. -**Total weird names flagged:** 43 +**Total weird names flagged:** 42 ## Summary table @@ -14,44 +14,43 @@ | 3 | High | Cryptic abbreviation | `Csp*` (CSP) family | `model.ts:92-124,286-300,454-463` | | 4 | High | Cryptic abbreviation | `Esm*` (ESM) family | `model.ts:242-268,318-332,478-487` | | 5 | High | Cryptic abbreviation | `Llm*` (LLM) family | `model.ts:334-364,382-418,490-511` | -| 6 | High | Underscore in TS identifier | `DcpAccountEnableMessage_Value` | `model.ts:61` | -| 7 | High | Generic field name | `value` (everywhere on `*Setting` types) | `model.ts:82-85, 118-124, 127, 236-239, 262-268, 398, 417, 436-439` | -| 8 | High | Generic + cryptic field | `acctIpAclEnable` | `model.ts:83-84` | -| 9 | High | Generic field name | `booleanVal` discriminator | `model.ts:398, 417` | -| 10 | High | Underspecified ID | `accountId` (no type/format hint) | `model.ts:131,161,191,271,...` | -| 11 | High | Domain-redundant suffix | `*Setting` suffix duplicating `Settings` package | `model.ts:102,246,420` and elsewhere | -| 12 | Medium | Type-suffix tautology | `CspEnablementAccountSetting` | `model.ts:102` | -| 13 | Medium | Type-suffix tautology | `EsmEnablementAccountSetting` | `model.ts:246` | -| 14 | Medium | Type-suffix tautology | `PersonalComputeSetting` | `model.ts:420` | -| 15 | Medium | Duplicate concept | `*Account` vs `*AccountSetting` parallel naming | `model.ts:92 vs 102; 242 vs 246` | -| 16 | Medium | Misleading | `LlmProxyPartnerPoweredEnforce` | `model.ts:401` | -| 17 | Medium | Misleading | `LlmProxyPartnerPoweredAccount` | `model.ts:382` | -| 18 | Medium | Verb-tense / action verb | `AccountIpAccessEnable` (verb as noun) | `model.ts:66` | -| 19 | Medium | Verb-tense / action verb | `DisableLegacyFeatures` (verb-phrase as noun) | `model.ts:220` | -| 20 | Medium | Verb-tense / action verb | `DcpAccountEnableMessage` (verb in noun position) | `model.ts:126` | -| 21 | Medium | Inconsistent action verbs | `delete*` reverts to default (not actual delete) | `client.ts:104,184` | -| 22 | Medium | Singular/plural mismatch | `complianceStandards` array on type named `CspEnablementAccount` (no list role implied) | `model.ts:99` | -| 23 | Medium | Misleading | `settingName` always coerced to `"default"` server-side | `model.ts:81,117,...; client.ts:109,...` | -| 24 | Medium | Misleading | `settingTypeName` ignored (path param wins) | `client.ts:111-113` (no doc) | -| 25 | Medium | Vague / overly verbose | `*EnablementAccount` family naming | `model.ts:92,242` | -| 26 | Medium | Overly verbose | `UpdateLlmProxyPartnerPoweredEnforceRequest` | `model.ts:502` | -| 27 | Medium | Overly verbose | `UpdateCspEnablementAccountSettingRequest` | `model.ts:454` | -| 28 | Medium | Acronym casing | `Ip` vs `IP` in `AccountIpAccessEnable` | `model.ts:66` | -| 29 | Medium | Acronym casing | `Id` vs `ID` in `accountId` | `model.ts:131,...` | -| 30 | Medium | Method name redundancy | `getCspEnablementAccountSetting` / etc. | `client.ts:262,302,...` | -| 31 | Medium | Method name redundancy | `updatePersonalComputeSetting` | `client.ts:682` | -| 32 | Medium | Duplicate concept | `Account` repeated in nearly every type | `model.ts` passim | -| 33 | Low | Acronym casing | `etag` field cased as `etag` everywhere but doc says "eTag" | `model.ts:68,75` | -| 34 | Low | Cryptic abbreviation | `acct_ip_acl_enable` wire key | `model.ts:530,541-543`; `client.ts:109,229,500` | -| 35 | Low | Cryptic abbreviation | `dcp_acct_enable` wire key | `client.ts:189,463,686` | -| 36 | Low | Cryptic abbreviation | `shield_csp_enablement_ac` / `shield_esm_enablement_ac` (trailing `_ac`) | `client.ts:266,343,529,590` | -| 37 | Low | Long enum value | `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10` | -| 38 | Low | Long enum value | `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE` | `model.ts:19-53` | -| 39 | Low | Verb-tense inconsistency | `Enable` (imperative) vs `Enablement` (noun) co-exist | `model.ts:66 vs 92,102` | -| 40 | Low | Singular/plural mismatch | `DisableLegacyFeatures` (plural type with singular boolean) | `model.ts:220-239` | -| 41 | Low | Acronym casing | `Url` vs `URL` in `httpReq.url` (field defined upstream) | `utils.ts:71,103` | -| 42 | Low | Inconsistent action verbs | `revert` semantics doc'd, but method named `delete*` | `client.ts:104,184` | -| 43 | Low | Vague / generic field | `setting?` on update requests | `model.ts:449,461,473,485,497,509,521` | +| 6 | High | Generic field name | `value` (everywhere on `*Setting` types) | `model.ts:82-85, 118-124, 127, 236-239, 262-268, 398, 417, 436-439` | +| 7 | High | Generic + cryptic field | `acctIpAclEnable` | `model.ts:83-84` | +| 8 | High | Generic field name | `booleanVal` discriminator | `model.ts:398, 417` | +| 9 | High | Underspecified ID | `accountId` (no type/format hint) | `model.ts:131,161,191,271,...` | +| 10 | High | Domain-redundant suffix | `*Setting` suffix duplicating `Settings` package | `model.ts:102,246,420` and elsewhere | +| 11 | Medium | Type-suffix tautology | `CspEnablementAccountSetting` | `model.ts:102` | +| 12 | Medium | Type-suffix tautology | `EsmEnablementAccountSetting` | `model.ts:246` | +| 13 | Medium | Type-suffix tautology | `PersonalComputeSetting` | `model.ts:420` | +| 14 | Medium | Duplicate concept | `*Account` vs `*AccountSetting` parallel naming | `model.ts:92 vs 102; 242 vs 246` | +| 15 | Medium | Misleading | `LlmProxyPartnerPoweredEnforce` | `model.ts:401` | +| 16 | Medium | Misleading | `LlmProxyPartnerPoweredAccount` | `model.ts:382` | +| 17 | Medium | Verb-tense / action verb | `AccountIpAccessEnable` (verb as noun) | `model.ts:66` | +| 18 | Medium | Verb-tense / action verb | `DisableLegacyFeatures` (verb-phrase as noun) | `model.ts:220` | +| 19 | Medium | Verb-tense / action verb | `DcpAccountEnableMessage` (verb in noun position) | `model.ts:126` | +| 20 | Medium | Inconsistent action verbs | `delete*` reverts to default (not actual delete) | `client.ts:104,184` | +| 21 | Medium | Singular/plural mismatch | `complianceStandards` array on type named `CspEnablementAccount` (no list role implied) | `model.ts:99` | +| 22 | Medium | Misleading | `settingName` always coerced to `"default"` server-side | `model.ts:81,117,...; client.ts:109,...` | +| 23 | Medium | Misleading | `settingTypeName` ignored (path param wins) | `client.ts:111-113` (no doc) | +| 24 | Medium | Vague / overly verbose | `*EnablementAccount` family naming | `model.ts:92,242` | +| 25 | Medium | Overly verbose | `UpdateLlmProxyPartnerPoweredEnforceRequest` | `model.ts:502` | +| 26 | Medium | Overly verbose | `UpdateCspEnablementAccountSettingRequest` | `model.ts:454` | +| 27 | Medium | Acronym casing | `Ip` vs `IP` in `AccountIpAccessEnable` | `model.ts:66` | +| 28 | Medium | Acronym casing | `Id` vs `ID` in `accountId` | `model.ts:131,...` | +| 29 | Medium | Method name redundancy | `getCspEnablementAccountSetting` / etc. | `client.ts:262,302,...` | +| 30 | Medium | Method name redundancy | `updatePersonalComputeSetting` | `client.ts:682` | +| 31 | Medium | Duplicate concept | `Account` repeated in nearly every type | `model.ts` passim | +| 32 | Low | Acronym casing | `etag` field cased as `etag` everywhere but doc says "eTag" | `model.ts:68,75` | +| 33 | Low | Cryptic abbreviation | `acct_ip_acl_enable` wire key | `model.ts:530,541-543`; `client.ts:109,229,500` | +| 34 | Low | Cryptic abbreviation | `dcp_acct_enable` wire key | `client.ts:189,463,686` | +| 35 | Low | Cryptic abbreviation | `shield_csp_enablement_ac` / `shield_esm_enablement_ac` (trailing `_ac`) | `client.ts:266,343,529,590` | +| 36 | Low | Long enum value | `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10` | +| 37 | Low | Long enum value | `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE` | `model.ts:19-53` | +| 38 | Low | Verb-tense inconsistency | `Enable` (imperative) vs `Enablement` (noun) co-exist | `model.ts:66 vs 92,102` | +| 39 | Low | Singular/plural mismatch | `DisableLegacyFeatures` (plural type with singular boolean) | `model.ts:220-239` | +| 40 | Low | Acronym casing | `Url` vs `URL` in `httpReq.url` (field defined upstream) | `utils.ts:71,103` | +| 41 | Low | Inconsistent action verbs | `revert` semantics doc'd, but method named `delete*` | `client.ts:104,184` | +| 42 | Low | Vague / generic field | `setting?` on update requests | `model.ts:449,461,473,485,497,509,521` | --- @@ -66,7 +65,7 @@ ### 2. `DcpAccountEnableMessage` — undocumented cryptic acronym ("DCP") - **File:line:** `model.ts:61, 126` - **Category:** Cryptic abbreviation -- **Suggestion:** `DefaultComputePolicy` or, at minimum, attach a doc comment explaining the acronym. The whole type is a proto wrapper around a 2-value enum and could be inlined as `PersonalComputeAccess` with values `ON | DELEGATE`. +- **Suggestion:** `DefaultComputePolicy` or, at minimum, attach a doc comment explaining the acronym. The whole type is a wrapper around a 2-value enum and could be inlined as `PersonalComputeAccess` with values `ON | DELEGATE`. - **Rationale:** "DCP" is not defined anywhere in this package. From the surrounding wire path `dcp_acct_enable` and the doc on `PersonalComputeSetting`, it appears to mean "default Personal Compute policy" — but a reader has to reverse-engineer that. A 1:1 port may have to keep the type for compatibility, but the JSDoc must explain the acronym. ### 3. `Csp*` family — undocumented cryptic acronym ("CSP") @@ -87,37 +86,31 @@ - **Suggestion:** `LargeLanguageModelProxyPartnerPowered*` is unwieldy, but a domain-specific short name like `AiProxyPartnerPowered*` or `ModelProxyPartnerPowered*` would at least drop the redundant "Llm" capitalization issue. Better: a single top-level type `PartnerPoweredAi*` with sub-fields. - **Rationale:** "Llm" mixes acronym + token-casing rules: TypeScript style says either `LLM` (acronym-case for known acronyms) or `Llm` (Pascal-token-case). The codebase consistently uses `Llm`, but the larger problem is stacking cryptic + cryptic + ambiguous — "LlmProxyPartnerPoweredEnforce" parses with several plausible bracketings. -### 6. `DcpAccountEnableMessage_Value` — underscore in TS identifier -- **File:line:** `model.ts:61` -- **Category:** Underscore in TS identifier, Go/Java-style name not idiomatic TS -- **Suggestion:** `DcpAccountEnableValue` (drop the proto `_Value` suffix), or hoist as a top-level enum like `PersonalComputeAccess`. The codebase already has an `eslint-disable` comment ("Proto-style nested enum name") on the line that highlights this is a known violation. -- **Rationale:** TypeScript identifiers conventionally use PascalCase without underscores; the `_Value` is a generator-level proto-to-TS holdover. The eslint disable confirms the codebase considers it a violation; the question is whether to clean it up at the generator level. - -### 7. `value` field on every `*Setting` discriminated union — generic field name losing meaning +### 6. `value` field on every `*Setting` discriminated union — generic field name losing meaning - **File:line:** `model.ts:82, 118, 127, 236, 262, 398, 417, 436` - **Category:** Generic field name losing meaning - **Suggestion:** Name the field after what it discriminates: `payload`, or after the specific domain concept (e.g. `enabled`, `personalCompute`) per use site. - **Rationale:** Eight different types in this package use a `value?: {...}` field, each with a discriminated union of `$case: ''`. Because the field name is identical across all of them, IDE autocomplete and code review provide no hint about what the field actually represents at any given use site — `setting.value` reads identically whether the underlying meaning is "IP ACL toggle", "legacy features disabled", or "partner-powered AI enforcement". -### 8. `acctIpAclEnable` — cryptic + abbreviated discriminator value +### 7. `acctIpAclEnable` — cryptic + abbreviated discriminator value - **File:line:** `model.ts:83-84` - **Category:** Cryptic abbreviation, generic field name - **Suggestion:** `accountIpAclEnabled` (or simply `enabled`). - **Rationale:** `acct` is a non-standard abbreviation of `account` that saves three characters. Inside a TypeScript SDK there is no length-budget reason to abbreviate. The fact that the parent type is already `AccountIpAccessEnable` makes the abbreviation noise. -### 9. `booleanVal` — generic discriminator value +### 8. `booleanVal` — generic discriminator value - **File:line:** `model.ts:398, 417` - **Category:** Generic field name losing meaning - **Suggestion:** `enabled` (it is, in fact, a boolean toggle of partner-powered AI features per the method doc). - **Rationale:** `booleanVal` describes the *type* not the *meaning* of the field. In a domain-specific union case, the case name should describe what it represents. (`acctIpAclEnable` and `disableLegacyFeatures` and `personalCompute` follow domain naming; `booleanVal` does not.) -### 10. `accountId` — underspecified ID +### 9. `accountId` — underspecified ID - **File:line:** `model.ts:131, 161, 191, 271, 287, 303, 319, 335, 351, 367, 443, 455, 467, 479, 491, 503, 515` - **Category:** Underspecified ID - **Suggestion:** Add a doc comment that names the type (UUID? numeric? Databricks-internal?). Currently the `UpdateAccountIpAccessEnableRequest.accountId` is documented (` account ID of the account being managed.`) but the others are not. - **Rationale:** "accountId" leaves the reader unsure whether to pass `"123"`, `"abcd-...-uuid"`, or `"my-account@databricks.com"`. The doc inconsistency (only the update variants document it) makes this worse. -### 11. `*Setting` suffix vs package name `accountsettings` +### 10. `*Setting` suffix vs package name `accountsettings` - **File:line:** package level - **Category:** Redundant suffix in domain - **Suggestion:** Drop the `Setting` suffix from type names within the `accountsettings` package, or drop the trailing `s` from the package name. (Compare: a package called `users` whose types are all `UserUser`, `UserAccountUser`.) E.g. `CspEnablementAccountSetting` -> `CspEnablementAccount` (which already exists as a sub-type). @@ -127,108 +120,108 @@ ## Medium severity -### 12–14. `CspEnablementAccountSetting`, `EsmEnablementAccountSetting`, `PersonalComputeSetting` — type-suffix tautology +### 11–13. `CspEnablementAccountSetting`, `EsmEnablementAccountSetting`, `PersonalComputeSetting` — type-suffix tautology - **File:line:** `model.ts:102, 246, 420` - **Category:** Type-suffix tautology -- **Suggestion:** Drop `Setting` (see #11). For ESM/CSP the inner type already drops it (`CspEnablementAccount`, `EsmEnablementAccount`). +- **Suggestion:** Drop `Setting` (see #10). For ESM/CSP the inner type already drops it (`CspEnablementAccount`, `EsmEnablementAccount`). - **Rationale:** The package is `accountsettings`, the method is `getCspEnablementAccountSetting`, returning a `CspEnablementAccountSetting`. The word "setting" appears three times in one call. This is the classic Go-port symptom — Go has no such namespace, so the redundancy is required there; in TS it is gratuitous. -### 15. `*Account` vs `*AccountSetting` — duplicate-concept parallel naming +### 14. `*Account` vs `*AccountSetting` — duplicate-concept parallel naming - **File:line:** `model.ts:92 vs 102; 242 vs 246` - **Category:** Duplicate concept - **Suggestion:** Rename one half of each pair so the two types describe distinct concepts at a glance, or document the relationship in both JSDocs. - **Rationale:** Two types differing by one suffix (`CspEnablementAccount` vs `CspEnablementAccountSetting`) invite bugs where the consumer references the wrong one — the distinction between "data" and "envelope" is invisible from the name alone. -### 16. `LlmProxyPartnerPoweredEnforce` — misleading +### 15. `LlmProxyPartnerPoweredEnforce` — misleading - **File:line:** `model.ts:401` - **Category:** Misleading / verb-tense in noun position - **Suggestion:** `LlmProxyPartnerPoweredEnforcement` (noun), and the method should be `getLlmProxyPartnerPoweredEnforcement`. - **Rationale:** `Enforce` is the imperative verb; the type represents the *enforcement setting state*. The doc on `client.ts:418` reads `Gets the enforcement status of partner powered AI features account setting` — confirming the type is a noun-of-enforcement, not the verb. -### 17. `LlmProxyPartnerPoweredAccount` — misleading +### 16. `LlmProxyPartnerPoweredAccount` — misleading - **File:line:** `model.ts:382` - **Category:** Misleading - **Suggestion:** `LlmProxyPartnerPoweredEnabled` (or drop "Account" — every type in the package is account-scoped, the qualifier adds no information). - **Rationale:** "Account" here doesn't refer to a sub-account or an account entity — it means "scoped to the account level," which is already true of every type in the package. The name suggests an Account *object* rather than an *enablement state*. -### 18. `AccountIpAccessEnable` — verb-as-noun +### 17. `AccountIpAccessEnable` — verb-as-noun - **File:line:** `model.ts:66` - **Category:** Verb-tense inconsistency - **Suggestion:** `AccountIpAccessToggle` (matches the method doc on `client.ts:104` "the account IP access toggle setting"), or `AccountIpAccessEnabled` (state). - **Rationale:** Types should be nouns. `Enable` is an imperative verb. The wire field name `acct_ip_acl_enable` likewise reads as a command, not a state. The doc itself calls this a "toggle setting" — that name would be far more idiomatic. -### 19. `DisableLegacyFeatures` — verb-phrase as type name +### 18. `DisableLegacyFeatures` — verb-phrase as type name - **File:line:** `model.ts:220` - **Category:** Verb-tense inconsistency - **Suggestion:** `LegacyFeaturesDisabled` or `LegacyFeaturesToggle`. - **Rationale:** `DisableLegacyFeatures` parses as "an action that disables legacy features." Types describing the *state of the toggle* should read as such. -### 20. `DcpAccountEnableMessage` — verb in noun position + `Message` suffix +### 19. `DcpAccountEnableMessage` — verb in noun position - **File:line:** `model.ts:126` -- **Category:** Verb-tense + Go/Java-style suffix -- **Suggestion:** `PersonalComputeAccess` (since this is in fact the personal compute policy state), drop both `Enable` (verb) and `Message` (proto-wire). -- **Rationale:** `Message` is a protobuf-isms suffix that TS does not need (everything is a message at the wire level). +- **Category:** Verb-tense inconsistency +- **Suggestion:** `PersonalComputeAccess` (since this is in fact the personal compute policy state); drop the `Enable` imperative verb. +- **Rationale:** `Enable` is an imperative verb; the type represents a state. Types describing the state of a toggle should read as nouns. -### 21 / 42. `delete*` methods that actually revert +### 20 / 41. `delete*` methods that actually revert - **File:line:** `client.ts:104 (deleteAccountIpAccessEnable doc: "Reverts the value..."), 184 (deletePersonalComputeSetting doc: "Reverts back ... to default (ON)")` - **Category:** Inconsistent action verbs / misleading - **Suggestion:** `reset*ToDefault()` (the semantics are reset-to-default, not destruction). At minimum, the method JSDoc and the verb should agree. - **Rationale:** A `delete` HTTP verb is being used to reset state — that is the *server's* idiom. The SDK can hide it with a more accurate verb. The doc literally says "Reverts" — a reader scanning method names will not see that. -### 22. `complianceStandards` array on `CspEnablementAccount` (singular type, plural field) +### 21. `complianceStandards` array on `CspEnablementAccount` (singular type, plural field) - **File:line:** `model.ts:99` - **Category:** Singular/plural mismatch (mild — the field is plural because it's a list, which is correct; the audit checklist asks me to flag interactions). Actually this is fine — flagged only to note it's *consistent*. - **Suggestion:** No change. -### 23. `settingName` documented to be ignored, "must be `default`" +### 22. `settingName` documented to be ignored, "must be `default`" - **File:line:** `model.ts:81, 117, 235, 261, 397, 416, 435` - **Category:** Misleading - **Suggestion:** Either remove the field from the TS surface (since the doc says it will not be respected on requests and is always `"default"` server-side) or rename to `settingName_readOnly` and mark it `readonly`. - **Rationale:** Exposing a field that the API explicitly ignores invites confused user code. The doc says verbatim: "This field is populated in the response, but it will not be respected even if it's set in the request body. The setting name in the path parameter will be respected instead." -### 24. `settingTypeName` query param has no purpose +### 23. `settingTypeName` query param has no purpose - **File:line:** `client.ts:111-113` (and every other method that appends it as a query param) - **Category:** Misleading / vague - **Suggestion:** Remove from request types (the actual type is hard-coded into the URL path) or document that it is informational only. - **Rationale:** The URL already encodes `types/acct_ip_acl_enable`; appending `?setting_type_name=acct_ip_acl_enable` is at best a no-op. If it's required for some legacy reason, that needs a comment. -### 25. `*EnablementAccount` family — verbose and weak +### 24. `*EnablementAccount` family — verbose and weak - **File:line:** `model.ts:92, 242` - **Category:** Vague / overly verbose - **Suggestion:** Drop `Enablement` — it adds no information beyond "this thing represents whether the feature is enabled," which is already implied by the boolean fields. `CspAccount` / `EsmAccount`, or better, `CspState` / `EsmState`. -- **Rationale:** "Enablement" is an awkward noun coined to allow protobuf to model "the state of enablement of X." Standard English would say "X enabled" (adjective) or just "X" with a bool field. +- **Rationale:** "Enablement" is an awkward noun coined to allow modeling "the state of enablement of X." Standard English would say "X enabled" (adjective) or just "X" with a bool field. -### 26–27. `UpdateLlmProxyPartnerPoweredEnforceRequest` / `UpdateCspEnablementAccountSettingRequest` — overly verbose +### 25–26. `UpdateLlmProxyPartnerPoweredEnforceRequest` / `UpdateCspEnablementAccountSettingRequest` — overly verbose - **File:line:** `model.ts:502, 454` - **Category:** Overly verbose -- **Suggestion:** Shorter forms like `UpdateLlmProxyEnforcementRequest` / `UpdateCspRequest`, paired with the renames in #15 and #25. +- **Suggestion:** Shorter forms like `UpdateLlmProxyEnforcementRequest` / `UpdateCspRequest`, paired with the renames in #14 and #24. - **Rationale:** 38 characters in `UpdateLlmProxyPartnerPoweredEnforceRequest` is too long to scan, and most of it is fixed boilerplate ("PartnerPowered", "Account", "Setting", "Request"). -### 28. `Ip` vs `IP` acronym casing +### 27. `Ip` vs `IP` acronym casing - **File:line:** `model.ts:66` (and references) - **Category:** Acronym casing inconsistency - **Suggestion:** Pick one. TypeScript's de-facto style (and the Google TS style guide) treats 2-letter acronyms as PascalCase tokens (`Ip`), so `AccountIpAccessEnable` is actually correct by that rule. But the Go SDK uses `IP`; the JS SDK is consistent with TS conventions here. Just note for the audit. - **Rationale:** Within this package the choice is consistent; cross-package consistency should be verified. -### 29. `Id` vs `ID` acronym casing +### 28. `Id` vs `ID` acronym casing - **File:line:** `model.ts:131, 161, 191, ...` - **Category:** Acronym casing inconsistency -- **Suggestion:** Same as #28 — `Id` matches TS conventions. -- **Rationale:** Same as #28. +- **Suggestion:** Same as #27 — `Id` matches TS conventions. +- **Rationale:** Same as #27. -### 30. Method-name redundancy: `getCspEnablementAccountSetting` +### 29. Method-name redundancy: `getCspEnablementAccountSetting` - **File:line:** `client.ts:262, 302, 339, 379, 419, 459` - **Category:** Method name redundancy - **Suggestion:** Drop `Setting` from method names (the `Client` is already account-settings-scoped; `client.getCsp()` is unambiguous in context). - **Rationale:** `accountsettings.Client.getCspEnablementAccountSetting()` repeats "setting" in package + method. Compare similar SDKs where `settings.Client.getCsp()` is the norm. -### 31. `updatePersonalComputeSetting` — same redundancy +### 30. `updatePersonalComputeSetting` — same redundancy - **File:line:** `client.ts:682` - **Category:** Method name redundancy - **Suggestion:** `updatePersonalCompute()`. -- **Rationale:** Same as #30. +- **Rationale:** Same as #29. -### 32. `Account` repeated in nearly every type +### 31. `Account` repeated in nearly every type - **File:line:** `model.ts` passim - **Category:** Duplicate concept (package scope already implies account-level) - **Suggestion:** Drop the `Account` prefix/suffix where the package name (`accountsettings`) already conveys it. @@ -238,57 +231,59 @@ ## Low severity -### 33. `etag` field cased as `etag` but JSDoc consistently says "eTag" +### 32. `etag` field cased as `etag` but JSDoc consistently says "eTag" - **File:line:** `model.ts:68 (field: `etag`), 75 (doc: "as the eTag provided")` - **Category:** Acronym casing inconsistency - **Suggestion:** Pick `etag` everywhere (HTTP standard is `ETag` per RFC 7232 but most code uses `etag`). - **Rationale:** Within a single JSDoc block, line 68 declares `etag?: string` and line 70 capitalizes it as `eTag`. Trivial inconsistency. -### 34. `acct_ip_acl_enable` wire key +### 33. `acct_ip_acl_enable` wire key - **File:line:** `model.ts:530, 541-543`; `client.ts:109, 229, 500` - **Category:** Cryptic abbreviation (server-controlled, but leaks via the discriminator `$case: 'acctIpAclEnable'`) - **Suggestion:** Server side can keep wire keys; the TS-facing discriminator `$case: 'acctIpAclEnable'` should be `accountIpAclEnable` or `enabled`. - **Rationale:** Users have to type the `$case` string literal, so abbreviations cost real ergonomics. -### 35. `dcp_acct_enable` wire key +### 34. `dcp_acct_enable` wire key - **File:line:** `client.ts:189, 463, 686` - **Category:** Cryptic abbreviation (server-side path) - **Suggestion:** N/A (server URL is fixed). Note for observability. -### 36. `shield_csp_enablement_ac` / `shield_esm_enablement_ac` wire keys +### 35. `shield_csp_enablement_ac` / `shield_esm_enablement_ac` wire keys - **File:line:** `client.ts:266, 343, 529, 590` - **Category:** Cryptic abbreviation (server-side path) - **Suggestion:** N/A. The trailing `_ac` (presumably "account") is an artefact of server naming. -### 37. `COMPLIANCE_STANDARD_UNSPECIFIED` — long enum value +### 36. `COMPLIANCE_STANDARD_UNSPECIFIED` — long enum value - **File:line:** `model.ts:10` - **Category:** Long enum value - **Suggestion:** See #1. -### 38. Long enum values (`CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5`, `ITAR_EAR`, `GERMANY_C5`, `ISMAP`, `HITRUST`, `K_FSI`, `ARC_AMPE`) +### 37. Long enum values (`CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5`, `ITAR_EAR`, `GERMANY_C5`, `ISMAP`, `HITRUST`, `K_FSI`, `ARC_AMPE`) - **File:line:** `model.ts:19-53` - **Category:** Long enum values - **Suggestion:** Keep — these are well-known compliance standard names where the string literal *is* the canonical form. Flagging only for completeness. - **Rationale:** Compliance standards have official names. Shortening `FEDRAMP_MODERATE` to `FEDRAMP_MOD` would be a regression. -### 39. `Enable` (verb) vs `Enablement` (noun) co-exist +### 38. `Enable` (verb) vs `Enablement` (noun) co-exist - **File:line:** `model.ts:66 (AccountIpAccessEnable) vs 92, 102 (CspEnablement...) vs 220 (DisableLegacyFeatures)` - **Category:** Verb-tense inconsistency - **Suggestion:** Standardize: either `*Enabled` (boolean adjective) or `*Toggle` (noun) across all toggle types. - **Rationale:** Within one package, three different lexical forms describe the same concept ("a boolean toggle"). A reader can't predict the form for a new toggle. -### 40. `DisableLegacyFeatures` — plural noun, singular boolean +### 39. `DisableLegacyFeatures` — plural noun, singular boolean - **File:line:** `model.ts:220-239` - **Category:** Singular/plural mismatch (mild) - **Suggestion:** `DisableLegacyFeaturesToggle` (it's a single bool, not a list of features). - **Rationale:** The bare plural reads as "a list of disable-legacy-feature entries"; the type body shows it's a single bool. -### 41. `Url` vs `URL` casing +### 40. `Url` vs `URL` casing - **File:line:** `utils.ts:71, 103` (HttpRequest field used as `url`) - **Category:** Acronym casing inconsistency - **Suggestion:** Conforms to TS convention (`url`/`Url`). Note for the audit. -### 43. `setting?` on every update request — vague +### 41. (see #20) + +### 42. `setting?` on every update request — vague - **File:line:** `model.ts:449, 461, 473, 485, 497, 509, 521` - **Category:** Vague / generic field name - **Suggestion:** Name the field after its type (`personalCompute?: PersonalComputeSetting`) — when there's exactly one payload type per request, the parameter name should reflect it. diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index 40f5b8ca..25b2aea4 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -9,25 +9,22 @@ with deployments, custom templates, app spaces, and resource bindings. | Severity | Count | | -------- | ----- | -| High | 14 | +| High | 11 | | Medium | 26 | -| Low | 21 | -| Observation | 11 | -| **Total** | **72** | - -The audit found two dominant themes. First, the package leaks proto/Go -conventions deep into the public surface: every nested message keeps its -Proto-style `Outer_Inner` name (`AppManifest_AppResourceSecretSpec_SecretPermission`, -`AppUpdate_UpdateStatus_UpdateState`), enums repeat the parent type in each -value (`SPACE_UPDATE_STATE_UNSPECIFIED`, `APPLICATION_STATE_UNSPECIFIED`), and -the package re-exports an `ErrorCode` enum with >70 cross-product codes whose -relevance to Apps is unclear. Second, the domain has two overlapping -"application" vocabularies — `App` vs `Application` (`ApplicationStatus`, -`ApplicationStatus_ApplicationState`) — and three overlapping "space" -vocabularies (`Space`, `AppResourceGenieSpace`, `space` as a string field on -`App`/`ListAppsRequest`). These collisions produce both type-suffix tautology -(`AppResourceApp.AppPermission.CAN_USE`) and outright ambiguity (`Space` -versus Genie Space). +| Low | 20 | +| Observation | 10 | +| **Total** | **67** | + +The audit found one dominant theme: the domain has overlapping vocabularies for +the same concept. `App` vs `Application` (`ApplicationStatus`, +`ApplicationStatus_ApplicationState`) collide on the same entity, and three +overlapping "space" vocabularies (`Space`, `AppResourceGenieSpace`, `space` as +a string field on `App`/`ListAppsRequest`) produce outright ambiguity (`Space` +versus Genie Space). Field-level confusion compounds the issue: `App.name` is +the primary key while `App.id` is a separate unique identifier, and a bare +`space` field sits next to `spaceId` on the same type. The package also +re-exports an `ErrorCode` enum with 76 cross-product values whose relevance to +Apps is unclear. --- @@ -49,46 +46,7 @@ versus Genie Space). - **Rationale:** A consumer reading `app.appStatus: ApplicationStatus` has to prove to themselves that "application" and "app" refer to the same thing. -### H2. `AppResourceApp` and `AppResourceApp_AppPermission.CAN_USE` — App-on-App tautology -- **File:** `model.ts:606, 962` -- **Category:** Type-suffix tautology (20), Redundant suffixes (8) -- **Issue:** A binding from one app to another app is `AppResourceApp` with - enum `AppResourceApp_AppPermission`. The `App` token appears three times. -- **Suggestion:** The outer wrapper is fine as-is (since other variants are - `AppResourceJob`, `AppResourceSecret`), but the inner enum should drop the - redundant `App` prefix: `AppResourceApp.Permission` with a single value - `CAN_USE`. Same treatment for every `AppResource_Permission` - pairing (Database, Experiment, GenieSpace, Job, Postgres, Secret, - ServingEndpoint, SqlWarehouse, UcSecurable). -- **Rationale:** The enum is reached as `AppResourceJob_JobPermission.CAN_VIEW` - — the `Job` is already implied by the outer enum's prefix. The repeated - token adds zero information. - -### H3. Proto-style nested names leaked into public TS API -- **File:** `model.ts:524, 540, 545, 552, 560, 566, 573, 580, 587, 598, 606, - 611, 616, 623, 631, 639, 645, 652, 659, 666, 676, 684, 693, 702, 714, 851, - 859, 866, 872, 881, 887, 896, 926, 934, 1037, 1049` -- **Category:** Underscores in TS identifiers (4), Go/Java-style names (14) -- **Issue:** Every nested proto type is exported with its `Outer_Inner` proto - name (e.g. `AppManifest_AppResourceUcSecurableSpec_UcSecurablePermission`, - `SpaceStatus_SpaceState`, `AppUpdate_UpdateStatus`, `AppDeployment_State`, - etc.). Each requires an eslint-disable for `naming-convention`. The names - combine three style violations: underscores in identifiers, length, and - proto-isms unfamiliar to TS consumers. The longest is 67 characters: - `AppManifest_AppResourceServingEndpointSpec_ServingEndpointPermission`. -- **Suggestion:** Either (a) flatten to a single top-level name - (`UcSecurablePermission`, `SpaceState`, `AppUpdateState`, - `AppDeploymentState`), or (b) use TS namespace nesting (`namespace - AppManifest { export interface ResourceUcSecurableSpec { ... } }`) to keep - the hierarchy without underscores. Option (a) matches how nested-message - types are typically projected into TS by `ts-proto`'s `useDeclaredAt = false` - mode and matches the style used elsewhere in the SDK. -- **Rationale:** TS naming conventions (PascalCase types, no underscores in - identifiers) are violated by every nested type. Each disable comment is a - symptom that the convention rules see the smell too. ts-proto and Buf's - ES code generators both produce flat names by default for this reason. - -### H4. Enum-value prefix repetition (proto-style) +### H2. Enum-value prefix repetition - **File:** `model.ts:516-521, 525-528, 685-690, 694-699, 703-711, 715-722` - **Category:** Redundant enum prefixes (2), Long enum values (18) - **Issue:** Multiple enums repeat their type name in every value: @@ -111,7 +69,7 @@ versus Genie Space). `@typescript-eslint/naming-convention` rule both prefer un-prefixed enum values. -### H5. `ErrorCode` (76 values) shipped from a package whose surface is Apps +### H3. `ErrorCode` (76 values) shipped from a package whose surface is Apps - **File:** `model.ts:15-513`, also `index.ts:17` - **Category:** Vague/generic without domain context (1), Duplicate concepts (12) - **Issue:** The `ErrorCode` enum has 76 values, the majority of which are @@ -129,20 +87,7 @@ versus Genie Space). is being inlined into a service-specific package. This is the canonical case the project's own `apierr/codes` directory was created to avoid. -### H6. `DatabricksServiceExceptionWithDetailsProto` — Java-/Proto-style verbose name -- **File:** `model.ts:1125`, also `index.ts:84` -- **Category:** Go/Java-style names (14), Overly verbose (7), Type-suffix tautology (20) -- **Issue:** Name is 41 chars and carries three artifacts of the underlying - wire format: `Service`, `Exception`, `WithDetailsProto`. In a TS API, - consumers don't think of failures as "Java service exceptions"; they think of - them as errors. -- **Suggestion:** Rename to `ApiError` or `OperationError` (the only use site - is `Operation.result.error`). If a wire-faithful name is needed in - marshal-only contexts, restrict its export. -- **Rationale:** The current name reads like a leaked Java class name; the - trailing `Proto` is a wire-format hint that has no meaning post-decoding. - -### H7. `Operation` — generic name with no domain prefix +### H4. `Operation` — generic name with no domain prefix - **File:** `model.ts:1318`, also `index.ts:106`, `client.ts:309, 408, 536, 951` - **Category:** Vague/generic without domain context (1) - **Issue:** `Operation` is exported as a top-level type. There is no Apps @@ -160,7 +105,7 @@ versus Genie Space). and they will collide on import. Either a shared canonical type or a domain-specific rename is required. -### H8. `space` string field on `App` vs `spaceId` — which is the identifier? +### H5. `space` string field on `App` vs `spaceId` — which is the identifier? - **File:** `model.ts:786-790`, `client.ts:624-626` - **Category:** Underspecified IDs (19), Misleading names (6), Generic field names (15) - **Issue:** `App` has two fields: @@ -176,7 +121,7 @@ versus Genie Space). - **Rationale:** A field literally named after a type (`space: string` next to `interface Space`) violates the "field contradicting type domain" rule. -### H9. `name` is the App's primary key, not `id` — ambiguous identifier +### H6. `name` is the App's primary key, not `id` — ambiguous identifier - **File:** `model.ts:725-729, 768-769, 1132-1135, 1176-1180` - **Category:** Underspecified IDs (19), Misleading names (6) - **Issue:** `App.name` is the URL-path identifier used by all client methods @@ -195,25 +140,26 @@ versus Genie Space). renamed via the marshal/unmarshal mapping. Mixing `name` and `appName` for the same role across request types makes the API harder to discover. -### H10. `AppDeployment_State` vs `AppUpdate_UpdateStatus_UpdateState` vs `SpaceUpdateState` — three different conventions for "state of an async op" +### H7. Inconsistent value sets across sibling "state of an async op" enums - **File:** `model.ts:524, 684, 515` - **Category:** Verb-tense inconsistency (13), Duplicate concepts (12) -- **Issue:** Three sibling state enums in the same file follow three different - naming conventions: - - `AppDeployment_State` — type nested under parent. - - `AppUpdate_UpdateStatus_UpdateState` — type doubly-nested. - - `SpaceUpdateState` — flat. - Their values are also inconsistent (`SUCCEEDED/FAILED/IN_PROGRESS/CANCELLED` - vs `SUCCEEDED/FAILED/IN_PROGRESS` vs `NOT_UPDATED/IN_PROGRESS/SUCCEEDED/FAILED`). -- **Suggestion:** Pick one shape for state enums and apply to all three. - Suggested target: `AppDeploymentState`, `AppUpdateState`, `SpaceUpdateState` - (all flat, no underscores). Consider sharing a `LongRunningState` enum if - the value sets actually align. -- **Rationale:** A consumer trying to discover the "state" enum of an Apps - async operation can't predict the spelling pattern from one example to the - next. - -### H11. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym +- **Issue:** Three sibling state enums in the same file have inconsistent + value sets: + - `AppDeployment_State` — `SUCCEEDED/FAILED/IN_PROGRESS/CANCELLED`. + - `AppUpdate_UpdateStatus_UpdateState` — + `SUCCEEDED/FAILED/IN_PROGRESS`. + - `SpaceUpdateState` — + `NOT_UPDATED/IN_PROGRESS/SUCCEEDED/FAILED`. + A consumer can't predict which terminal/non-terminal states are reachable + from one async op to the next. +- **Suggestion:** Align the value sets where the underlying state machines + actually agree. Consider sharing a `LongRunningState` enum if the lifecycles + truly match across the three operations. +- **Rationale:** Sibling state enums in the same domain should expose the + same value vocabulary unless the underlying state machines genuinely + differ — and if they differ, the doc should say why. + +### H8. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym - **File:** `model.ts:772-773` - **Category:** Acronym casing inconsistencies (3) - **Issue:** The fields use `oauth2` (all-lowercase) embedded with PascalCase. @@ -226,7 +172,7 @@ versus Genie Space). - **Rationale:** Inconsistent with how the SDK treats other acronyms (e.g. `Url` in `thumbnailUrl`, `Id` in many fields). -### H12. `defaultGitSource` / `defaultSourceCodePath` / `gitRepository` — three coexisting "source" concepts on `App` +### H9. `defaultGitSource` / `defaultSourceCodePath` / `gitRepository` — three coexisting "source" concepts on `App` - **File:** `model.ts:760-763, 776-781, 786-794` - **Category:** Duplicate concepts (12), Misleading names (6) - **Issue:** `App` has all of: @@ -245,7 +191,7 @@ versus Genie Space). registered repo. The Go doc comment on the field clarifies it tracks the last active deployment, but the name does not. -### H13. `noCompute` boolean on `CreateAppRequest` +### H10. `noCompute` boolean on `CreateAppRequest` - **File:** `model.ts:1091-1095` - **Category:** Misleading names (6) - **Issue:** `noCompute?: boolean` with doc "If true, the app will not be @@ -261,7 +207,7 @@ versus Genie Space). also describes a behaviour ("start") rather than its surface effect ("no compute"). -### H14. Singular `permission` field holding a single value but documented as plural permissions +### H11. Singular `permission` field holding a single value but documented as plural permissions - **File:** `model.ts:866-869, 984-989` - **Category:** Singular/plural mismatches (9) - **Issue:** `AppManifest_AppResourceJobSpec.permission?: ...JobPermission` @@ -417,18 +363,17 @@ versus Genie Space). semantic change; flag for discussion. Alternative: keep both and document which wins on conflict. -### M15. `AppManifest_AppResourceUcSecurableSpec_UcSecurableType` and - `AppResourceUcSecurable_UcSecurableType` — duplicated enum +### M15. `UcSecurableType` duplicated across manifest spec and runtime resource - **File:** `model.ts:598-603, 676-681` - **Category:** Duplicate concepts (12) - **Issue:** Two identical enums (`VOLUME`, `TABLE`, `FUNCTION`, `CONNECTION`) — one for the manifest spec, one for the runtime resource. Same value set, - different name. + different declaration. - **Suggestion:** Consolidate to a single `UcSecurableType` enum and reference - it from both `AppManifest_AppResourceUcSecurableSpec` and - `AppResourceUcSecurable`. + it from both the manifest UC securable spec and the runtime UC securable + resource. -### M16. `AppResourceUcSecurable_UcSecurablePermission` is a strict subset of `AppManifest_AppResourceUcSecurableSpec_UcSecurablePermission` +### M16. UC securable permission enum on the runtime resource is a strict subset of the manifest-spec enum - **File:** `model.ts:587-595, 666-673` - **Category:** Duplicate concepts (12) - **Issue:** Spec enum has 7 values (`READ_VOLUME`, `WRITE_VOLUME`, `MANAGE`, @@ -444,11 +389,9 @@ versus Genie Space). - **Category:** Type-suffix tautology (20) - **Issue:** Within the `AppDeployment` interface, `deploymentId` repeats the outer name. Inside `AppDeployment` the unqualified `id` would suffice and - matches the pattern in `App.id`, `Space.id`, `AppResourceExperiment.experimentId` - (also tautological), and `AppResourceJob.id` (correctly unqualified). -- **Suggestion:** Rename `AppDeployment.deploymentId` -> `id`. Same for - `AppResourceExperiment.experimentId` -> `id`, `AppResourceGenieSpace.spaceId` - -> `id`. + matches the pattern in `App.id`, `Space.id`, and `AppResourceJob.id` + (correctly unqualified). +- **Suggestion:** Rename `AppDeployment.deploymentId` -> `id`. ### M18. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types - **File:** `model.ts:1015, 769, 1368, 1900` @@ -546,63 +489,57 @@ versus Genie Space). ## Low-severity findings -### L1. `AppDeployment_Mode.MODE_UNSPECIFIED` — `MODE_` prefix redundant -- **File:** `model.ts:525` -- **Category:** Redundant enum prefixes (2) -- **Suggestion:** `MODE_UNSPECIFIED` -> `UNSPECIFIED`. Already covered in H4 - but called out separately for tracking. - -### L2. `AppDeployment.mode` doc: "The mode of which the deployment will manage the source code." +### L1. `AppDeployment.mode` doc: "The mode of which the deployment will manage the source code." - **File:** `model.ts:809` - **Category:** Grammar / clarity (not in numbered categories but flagged) - **Suggestion:** "of which" should be "in which" or "by which". A nit, not a rename, but flagged because it appears in the public API docs. -### L3. `App.creator` and `App.updater` — `updater` is a real English word but commonly used for libraries/tools +### L2. `App.creator` and `App.updater` — `updater` is a real English word but commonly used for libraries/tools - **File:** `model.ts:746-748` - **Category:** Misleading names (6) - **Issue:** Outside of CRUD-stamp contexts, "updater" often denotes a software-update agent (e.g. Sparkle). Pair with M1 — both should become `*Email` if that's the value type. -### L4. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` +### L3. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` - **File:** `model.ts:743-748` - **Category:** Field contradicting type domain (16) - **Suggestion:** No type change available short of a branded type; document the format in JSDoc. -### L5. `App.url` doc: "URL of the app once it is deployed" +### L4. `App.url` doc: "URL of the app once it is deployed" - **File:** `model.ts:734-735` - **Category:** Misleading names (6) - **Suggestion:** Rename `App.url` -> `App.appUrl` or `App.deploymentUrl` for clarity, especially because `GitRepository.url` is also called `url` in the same file. (Currently both are bare `url`.) -### L6. `GitRepository.url` — same generic `url` as `App.url` +### L5. `GitRepository.url` — same generic `url` as `App.url` - **File:** `model.ts:1205` - **Category:** Generic field names (15) - **Suggestion:** Rename to `repositoryUrl` (mirror with `GitRepository.provider` named more specifically). -### L7. `GitSource.resolvedCommit` — does it carry SHA or ref? +### L6. `GitSource.resolvedCommit` — does it carry SHA or ref? - **File:** `model.ts:1248-1253` - **Category:** Vague/generic (1) - **Suggestion:** Rename to `resolvedCommitSha` to match the doc, which says "the resolved commit SHA". -### L8. `GitSource.sourceCodePath` — verbose +### L7. `GitSource.sourceCodePath` — verbose - **File:** `model.ts:1242-1246` - **Category:** Overly verbose (7) - **Suggestion:** Inside `GitSource`, simply `path` would be unambiguous (the whole interface is about source location). -### L9. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" +### L8. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" - **File:** `model.ts:894-895` - **Category:** Doc / clarity - **Suggestion:** Drop or rephrase the reference to `app.proto`; in TS the reference is meaningless. -### L10. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers +### L9. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers - **File:** `model.ts:3131, 3211` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — @@ -611,21 +548,21 @@ versus Genie Space). - **Suggestion:** Either expose helpers for every entity with a field-mask schema, or none. -### L11. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models +### L10. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models - **File:** `model.ts:783-784, 1032-1035` - **Category:** Duplicate concepts (12) - **Suggestion:** Document that `thumbnailUrl` is the display URL and `AppThumbnail.thumbnail` is the byte content (used in update/delete-thumbnail requests). -### L12. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` +### L11. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` - **File:** `model.ts:1156-1166` - **Category:** Vague/generic (1) - **Suggestion:** Discriminator `'value'` and `'valueFrom'` are short; consider `'literal'` and `'reference'` to make intent clearer. (Wire field names unchanged.) -### L13. `Space` interface — same name as the Genie product `AppResourceGenieSpace` +### L12. `Space` interface — same name as the Genie product `AppResourceGenieSpace` - **File:** `model.ts:1357, 978-982` - **Category:** Duplicate concepts (12) - **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share @@ -637,25 +574,25 @@ versus Genie Space). is the outlier. This realignment also clarifies the wire URLs (`/api/2.0/app-spaces/...`). -### L14. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, +### L13. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, `ListSpacesRequest`, etc., do not mention "App" - **File:** `model.ts:1101, 1147, 1197, 1301`, also `index.ts:82-88, 105` - **Category:** Vague/generic (1) -- **Suggestion:** Tied to L13 — rename these to `CreateAppSpaceRequest`, etc. +- **Suggestion:** Tied to L12 — rename these to `CreateAppSpaceRequest`, etc. -### L15. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? +### L14. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? - **File:** `model.ts:1308-1312, 1282-1286` -- **Category:** Observation — both follow the same pattern. Tied to L13 again +- **Category:** Observation — both follow the same pattern. Tied to L12 again for the entity rename. -### L16. `CreateAppDeploymentRequest.autoDeploy` doc: "Whether to enable automatic deployments on push events to the git repository" +### L15. `CreateAppDeploymentRequest.autoDeploy` doc: "Whether to enable automatic deployments on push events to the git repository" - **File:** `model.ts:1086-1089` - **Category:** Misleading names (6) - **Issue:** The field name suggests "deploy automatically now". The doc says it sets up a webhook. These are very different ideas. - **Suggestion:** Rename to `enableAutoDeploy` or `webhookAutoDeploy`. -### L17. `GitRepository.autoDeploy` vs `CreateAppDeploymentRequest.autoDeploy` +### L16. `GitRepository.autoDeploy` vs `CreateAppDeploymentRequest.autoDeploy` - **File:** `model.ts:1086, 1211` - **Category:** Duplicate concepts (12) - **Issue:** Two `autoDeploy` fields in the same file: one on the deployment @@ -664,7 +601,7 @@ versus Genie Space). - **Suggestion:** Document the relationship in JSDoc; if they're the same state, only one should exist. -### L18. `Operation.name` — server-assigned UNIQUE name, not human-readable +### L17. `Operation.name` — server-assigned UNIQUE name, not human-readable - **File:** `model.ts:1319-1324` - **Category:** Misleading names (6) - **Issue:** `Operation.name` is the operation *identifier* path @@ -673,7 +610,7 @@ versus Genie Space). package. - **Suggestion:** Rename to `operationName` or, given the format, just `path`. -### L19. `Client` class — exported as bare `Client` +### L18. `Client` class — exported as bare `Client` - **File:** `client.ts:95`, also `index.ts:4` - **Category:** Vague/generic (1) - **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the @@ -681,7 +618,7 @@ versus Genie Space). `@databricks/sdk-jobs`, they need an alias. - **Suggestion:** Rename to `AppsClient`. Common SDK convention. -### L20. `host` (private field on `Client`) +### L19. `host` (private field on `Client`) - **File:** `client.ts:96` - **Category:** Vague/generic (1) - **Issue:** `private readonly host: string`. The doc on the workspace @@ -689,7 +626,7 @@ versus Genie Space). - **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, cosmetic. -### L21. `getSpaceOperation` (method) vs `GetOperationRequest` +### L20. `getSpaceOperation` (method) vs `GetOperationRequest` - **File:** `client.ts:536-558` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells @@ -739,17 +676,14 @@ Two related counts, different verbs. `runningInstances` for app process, `activeInstances` for compute resources. Document the distinction. ### O8. `ListAppsRequest.space` filters by space name (string), not by -`Space` object — consistent with H8 issue. +`Space` object — consistent with H5 issue. ### O9. The package re-exports the `apierr` enum locally -Per H5, this enum should live in `@databricks/sdk-databricks/apierror/codes`. +Per H3, this enum should live in `@databricks/sdk-databricks/apierror/codes`. The project memory note already calls this out (`packages/databricks/src/apierror/codes/`). -### O10. Files use `// eslint-disable-next-line` for every Proto-style nested name -60+ disables across `model.ts`. Fixing H3 eliminates the disables. - -### O11. `index.ts` exports +### O10. `index.ts` exports - 18 enums - 51 type aliases - 8 named exports from `./client` (1 class + 7 wrapper classes) @@ -769,13 +703,13 @@ detail. | `AppDeployment` | A specific deployment (source-code + config snapshot) | Has its own `id`, status, lifecycle. | | `AppManifest` | Schema describing required resources for an app | Used by `CustomTemplate`. | | `AppResource` | A binding from an App to another Databricks resource | Discriminated union of 10 cases. | -| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L13. | -| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L13. | +| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L12. | +| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L12. | | `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | -| `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H7. | +| `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H4. | | `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | | `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M15/M16. | -| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L11. | +| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L10. | | `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M6. | | `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | | `GitSource` | Specific commit/branch/tag + path within a `GitRepository` | Used by deployments. | diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index 1d2803f2..a5cde6e2 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -11,10 +11,10 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 2 | -| Medium | 6 | +| Medium | 5 | | Low | 3 | -| Observation | 7 | -| **Total** | **18** | +| Observation | 4 | +| **Total** | **14** | Headline themes: @@ -25,15 +25,9 @@ Headline themes: codebase-wide convention question rather than a defect local to this package; `accountsettings` and others use the `…Request` suffix while `catalogs`, `connections`, `clusters`, etc. omit it. -2. **Proto-style underscore in `ArtifactMatcher_MatchType`** breaks the - TypeScript identifier convention but is a deliberate, repo-wide pattern - (see Observation O5 for evidence). Flagged for visibility only. -3. **Redundant `Info` suffix on `ArtifactAllowlistInfo`** is the canonical +2. **Redundant `Info` suffix on `ArtifactAllowlistInfo`** is the canonical payload type for both `Get` and `Set` responses; the suffix adds no information beyond "this is a struct." -4. **Redundant `*_UNSPECIFIED` enum prefixes** repeat the enum domain - (`ARTIFACT_TYPE_UNSPECIFIED`, `MATCH_TYPE_UNSPECIFIED`) — but again this - is the universal proto-mirror convention across the SDK. Allowlist casing is **consistent** throughout the package (always `Allowlist`, never `AllowList` or `Whitelist`). @@ -134,21 +128,7 @@ type that is itself a noun-from-verb reflects that. Caveat: matches the Go SDK exactly, so a rename would break the 1:1 port. -### M5. `matchType` is contextless on `ArtifactMatcher` and the enum has a -unique prefix style - -- **File / line:** `src/v1/model.ts:36`; enum at line 15. -- **Category:** #2 redundant enum prefix; #18 long enum values. -- **Current:** `matchType?: ArtifactMatcher_MatchType` with values - `MATCH_TYPE_UNSPECIFIED`, `PREFIX_MATCH`. -- **Suggestion:** Drop the `MATCH_TYPE_` prefix from the unspecified value - (`UNSPECIFIED` — but see Observation O3 below for why this is repo-wide). - Otherwise the field name is fine as-is. -- **Rationale:** `MATCH_TYPE_UNSPECIFIED` repeats the enum name; in - TypeScript `ArtifactMatcher_MatchType.UNSPECIFIED` reads cleaner. This is - a SDK-wide convention so the change has cross-package implications. - -### M6. `req` parameter name on `Client.getArtifactAllowlist` / +### M5. `req` parameter name on `Client.getArtifactAllowlist` / `setArtifactAllowlist` - **File / line:** `src/v1/client.ts:67, 97`. @@ -217,31 +197,13 @@ Sibling packages `catalogs`, `connections`, `clusters`, `externallocations`, in `grep -rE "^export interface (Get|Set|Create|Update|Delete)…"` across the workspace. Changing this package alone would create asymmetry. -### O2. Proto-style nested enum names with underscores are repo-wide - -`ArtifactMatcher_MatchType` is one of 20+ enums of the form -`_` across the workspace (`BudgetConfigurationFilter_Operator`, -`CleanRoomAutoApprovalRule_AuthorScope`, `ConversionInfo_State`, -`DatabaseInstance_State`, `EndpointStatus_State`, etc.). This violates -TypeScript naming convention (PascalCase, no underscores) but is the agreed -mirror of the Go SDK's `Parent_Field` proto idiom. The file even disables -the lint rule explicitly at `model.ts:14`. Flag for awareness only. - -### O3. `*_UNSPECIFIED` zero values repeated across enums - -Both `ArtifactType.ARTIFACT_TYPE_UNSPECIFIED` and -`ArtifactMatcher_MatchType.MATCH_TYPE_UNSPECIFIED` repeat the enum domain -in the member name. This is a proto-buf default and is consistent with -sibling packages (`CleanRoomAutoApprovalRule_AuthorScope`, -`DatabaseInstance_State`, …). Not a local defect. - -### O4. `…Info` suffix repeated across UC types +### O2. `…Info` suffix repeated across UC types `ArtifactAllowlistInfo` follows the `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the codebase decides to drop the `Info` suffix, this is one of many to fix. -### O5. Allowlist terminology / casing is consistent +### O3. Allowlist terminology / casing is consistent `Allowlist` (single uppercase A, then lowercase `llowlist`) is used in every position in this package: type names, methods, schemas, comments, @@ -249,21 +211,13 @@ URL paths (`/artifact-allowlists/`), and the package name `@databricks/sdk-artifactallowlists`. No `AllowList`, `Allow_list`, or `Whitelist` anywhere. **Passes** the audit on this criterion. -### O6. URL path constant is inlined +### O4. URL path constant is inlined The string `/api/2.1/unity-catalog/artifact-allowlists/${artifactType}` appears twice (`client.ts:70` and `client.ts:100`) without a named constant. Not a naming defect, but typical naming-audit findings include "unnamed magic strings." Worth a note. -### O7. `PACKAGE_SEGMENT.key` is computed from `pkgJson.name` via regex - -`client.ts:31–34`: `key: pkgJson.name.replace(/^@[^/]+\//, '')` strips the -`@databricks/` org prefix. The variable name `PACKAGE_SEGMENT` reads fine -but the `key`/`value` shape is generic — readers may not know `key` is -"package name" and `value` is "package version" without inspecting -`createDefault().with(...)`. No action required; cosmetic. - --- ## Domain glossary @@ -291,16 +245,16 @@ but the `key`/`value` shape is generic — readers may not know `key` is Type & symbol checklist: -- [x] `ArtifactType` enum (4 members) → M5, O3. -- [x] `ArtifactMatcher_MatchType` enum (2 members) → M5, O2, O3. -- [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O4. +- [x] `ArtifactType` enum (4 members) → no defect. +- [x] `ArtifactMatcher_MatchType` enum (2 members) → no defect. +- [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O2. - [x] `ArtifactMatcher` interface (2 fields) → M3, M4. - [x] `GetArtifactAllowlist` interface (1 field) → H1, O1. - [x] `SetArtifactAllowlist` interface (5 fields) → H2, O1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O7. -- [x] `getArtifactAllowlist(req, options)` method → H1, M2, M6. -- [x] `setArtifactAllowlist(req, options)` method → H1, M2, M6. +- [x] `PACKAGE_SEGMENT` constant → no defect. +- [x] `getArtifactAllowlist(req, options)` method → H1, M2, M5. +- [x] `setArtifactAllowlist(req, options)` method → H1, M2, M5. - [x] `HttpCallOptions` interface → no defect. - [x] `executeCall` function → L1. - [x] `readAll` private function → no defect (name fits idiom). diff --git a/.agent/naming-audit/billableusagedownload.md b/.agent/naming-audit/billableusagedownload.md index 7df6bd63..a156f199 100644 --- a/.agent/naming-audit/billableusagedownload.md +++ b/.agent/naming-audit/billableusagedownload.md @@ -126,7 +126,7 @@ The field is typed `ReadableStream` (no type parameter) rather than `ReadableStr The TS field `personalData` maps to wire `personal_data`, `startMonth` -> `start_month`, etc. The query-param construction in `client.ts:70-79` does it manually and correctly. Good — no naming bug here, just noting that no schema/codec layer is needed because this is a query-string-only request. ### 19. No enums, no list-types, no FieldMask -This package is one of the simplest in the SDK: zero enums, zero list/paginated types, zero proto-nested `_Response` types. Audit-rule categories 2 (redundant enum prefix), 4 (underscore identifiers from proto nesting), 18 (long enum values), and 13 (verb tense inconsistency) do not apply here. That's why the finding count is comparatively low. +This package is one of the simplest in the SDK: zero enums, zero list/paginated types. Audit-rule categories 2 (redundant enum prefix), 18 (long enum values), and 13 (verb tense inconsistency) do not apply here. That's why the finding count is comparatively low. ### 20. CSV body is undocumented in types `DownloadResponse.contents` is `ReadableStream` (untyped) but the JSDoc on `Client.download` (`client.ts:51-64`) makes clear the body is CSV. There is no type-level hint or branded type to mark this — a caller might treat the stream as JSON. Worth considering a documented branded type (`type CsvStream = ReadableStream & {readonly _csvBrand: unique symbol}`) or, more practically, a Content-Type assertion. Not a name problem; flagged because the response shape is uninformative. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index 378df61c..adc1e6f8 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,61 +3,55 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 32 +**Total weird names flagged:** 30 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 11 | +| High | 7 | +| Medium | 10 | | Low | 8 | | Observation | 5 | ## High severity -### 1. `SortSpec_Field` enum (`Foo_Bar` identifier) — `src/v1/model.ts:8` -- **Why weird:** Underscore in TypeScript identifier — proto-style nested-enum notation. Requires an explicit `eslint-disable-next-line @typescript-eslint/naming-convention` because TS strict rules reject `Foo_Bar`. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names not idiomatic in TS). -- **Suggested name:** `SortField` (hoist out of the nested namespace), or use a string-literal union `'POLICY_NAME' | undefined`. -- **Rationale:** TS has no nested-enum concept; the only reason this exists is to mirror the `SortSpec.Field` proto message. The eslint-disable is a tell that the name fights the language. - -### 2. `SortSpec_Field.FIELD_UNSPECIFIED` — `src/v1/model.ts:10` -- **Why weird:** A `FIELD_UNSPECIFIED` sentinel imported from protobuf semantics. Idiomatic TS uses `undefined` (the field is already `field?: SortSpec_Field | undefined`). -- **Category:** 2 (redundant enum prefix re-stating the enum name), 14 (proto sentinel leak). -- **Suggested name:** Drop the value and rely on `field?: SortField | undefined`. +### 1. `SortSpec_Field.FIELD_UNSPECIFIED` sentinel — `src/v1/model.ts:10` +- **Why weird:** A `FIELD_UNSPECIFIED` sentinel value alongside the field already being declared optional (`field?: SortSpec_Field | undefined`). Idiomatic TS uses `undefined` for "unspecified". +- **Category:** 2 (redundant enum prefix re-stating the enum name `Field`). +- **Suggested name:** Drop the `FIELD_UNSPECIFIED` value and rely on `field?: ... | undefined`. - **Rationale:** Optional + `undefined` already expresses "unspecified" in TS; a `FIELD_UNSPECIFIED` literal forces every caller to handle two "no choice" states (`undefined` and the sentinel string). -### 3. `Filter` (bare top-level type) — `src/v1/model.ts:77` +### 2. `Filter` (bare top-level type) — `src/v1/model.ts:77` - **Why weird:** Re-exported from `index.ts` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (Array#filter, RxJS filter, content filters, etc.) and the type is package-scoped — but the re-export under this name collides with the same bare `Filter` in `packages/usagepolicy/src/v1/model.ts:81` and any user who imports both with `Filter` will hit a name clash. - **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). - **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). - **Rationale:** A bare `Filter` provides zero discoverability and the package directly forces a collision with `usagepolicy.Filter`. Both packages target the same account-level surface and a consumer will frequently import both. -### 4. `CreateBudgetPolicyRequest.requestId` documented as idempotency key — `src/v1/model.ts:42` +### 3. `CreateBudgetPolicyRequest.requestId` documented as idempotency key — `src/v1/model.ts:42` - **Why weird:** JSDoc: "This request is only idempotent if a `request_id` is provided." — wire-name leak (`request_id`) in the docs of the TS field `requestId`. Also, `requestId` is a generic field name that does not signal "idempotency key" to callers; the JSDoc is the only place that mentions idempotency. - **Category:** 1 (vague — `requestId` could mean anything: trace id, correlation id, idempotency key), 15 (generic field name losing meaning). - **Suggested name:** `idempotencyKey` (matches the conventional name used by Stripe, Square, and most REST APIs), and fix the JSDoc to use TS field name `requestId` rather than wire name `request_id`. - **Rationale:** A user reading the field name should know it controls idempotency. The current name + docstring split forces a doc-read for every caller. -### 5. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:118-123` +### 4. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:118-123` - **Why weird:** Docstring says: "A page token, received from a previous `ListServerlessPolicies` call ... When paginating, all other parameters provided to `ListServerlessPoliciesRequest` must match the call that provided the page token." — refers to an entirely different RPC name (`ListServerlessPolicies`) that does not exist in this SDK. The actual method is `listBudgetPolicies`. - **Category:** 6 (misleading — docs describe a different operation), 14 (Go-style internal proto name leaked). - **Suggested name:** Fix docstring to say `ListBudgetPolicies`/`ListBudgetPoliciesRequest`. - **Rationale:** Generator bug. Confusing for readers and grep-hostile (searching for `ListBudgetPolicies` won't surface the doc context). -### 6. `BudgetPolicy.policyId` / `BudgetPolicy.policyName` field naming inside `BudgetPolicy` type — `src/v1/model.ts:18,25` +### 5. `BudgetPolicy.policyId` / `BudgetPolicy.policyName` field naming inside `BudgetPolicy` type — `src/v1/model.ts:18,25` - **Why weird:** Fields on the `BudgetPolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. - **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `BudgetPolicy.id` is `policyId`). - **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). - **Rationale:** `budgetPolicy.id` reads better than `budgetPolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. -### 7. `BudgetPolicy.bindingWorkspaceIds` — `src/v1/model.ts:32` +### 6. `BudgetPolicy.bindingWorkspaceIds` — `src/v1/model.ts:32` - **Why weird:** `binding` as a noun-prefix is unusual; reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this budget policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). - **Category:** 1 (vague — `binding` is a generic noun: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists, but the field is just a list of workspace IDs). - **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. - **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. -### 8. Type-name collision with `budgets` package — `src/v1/model.ts:16` vs `packages/budgets/src/v1/model.ts:50` +### 7. Type-name collision with `budgets` package — `src/v1/model.ts:16` vs `packages/budgets/src/v1/model.ts:50` - **Why weird:** This package's central entity is `BudgetPolicy`; the sibling `budgets` package exports `BudgetConfiguration` (the spend-alert budget object). The two are semantically unrelated — `BudgetPolicy` is a tag-attachment policy that influences cost attribution, and `BudgetConfiguration` is a spend threshold + alert. A user importing both packages sees `BudgetPolicy` and `BudgetConfiguration` side by side and may reasonably wonder if `BudgetPolicy` is the policy *for* a `BudgetConfiguration`. The names do not differentiate clearly. - **Category:** 12 (duplicate concepts with confusing names), 1 (the `Budget` prefix overloads two unrelated domain ideas). - **Suggested name:** Consider `CostAttributionPolicy` or `UsageTaggingPolicy` for what `budgetpolicy` actually models (per the JSDoc on `BudgetPolicy`: "Contains the BudgetPolicy details" — tags + workspace bindings, no spend or threshold concept anywhere). @@ -65,152 +59,148 @@ ## Medium severity -### 9. `CustomPolicyTag` type name — `src/v1/model.ts:53` +### 8. `CustomPolicyTag` type name — `src/v1/model.ts:53` - **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. - **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location). - **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. - **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". -### 10. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:57-58` +### 9. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:57-58` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. - **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. -### 11. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:82,87,92` +### 10. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:82,87,92` - **Why weird:** `Filter` has three optional fields whose names imply they specify *one* policy, but the JSDoc says they apply as substring/equality filters across the list. Names like `policyName: 'foo'` read as "the policy named foo"; what it actually means is "policies whose name contains 'foo'". The JSDoc clarifies but the name misleads. - **Category:** 6 (misleading — singular noun for a substring/multi-match filter). - **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to `creatorUserNames: string[]`). - **Rationale:** Filter DSLs benefit from explicit operators. Bare names suggest exact match. -### 12. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:87,92` +### 11. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:87,92` - **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number` (a JS-unsafe representation for 64-bit IDs — but at least the Go SDK numeric type is `int64` here), while `creatorUserName` is `string`. - **Category:** 12 (duplicate concept — two ways to filter on the same domain object), 19 (underspecified ID — `creatorUserId` is a numeric id from an unknown id space). - **Suggested name:** Collapse to `creator?: Creator` with `{id?: number; name?: string}`, or document AND/OR. - **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine. Even the JSDoc says "If unspecified, all policies will be returned" on each one — but doesn't say what happens if both are set. -### 13. `Filter.creatorUserId: number` representation — `src/v1/model.ts:87` +### 12. `Filter.creatorUserId: number` representation — `src/v1/model.ts:87` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 32). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 32 and `Filter.creatorUserId` here. -### 14. `SortSpec` type — `src/v1/model.ts:149` +### 13. `SortSpec` type — `src/v1/model.ts:149` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 15. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:150` +### 14. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:150` - **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. - **Category:** Observation (typo). - **Suggested name:** Fix spelling. - **Rationale:** Minor; flagging because it surfaces in IntelliSense. -### 16. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:136` +### 15. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:136` - **Why weird:** Field `policies` of type `BudgetPolicy[]`. Within the `budgetpolicy` package, `policies` is fine — but within a multi-package consumer with `BudgetConfigurations.budgets` (line 170 of budgets) and `usagepolicy.policies`, the field `policies` becomes ambiguous when copy-pasted. - **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on request). - **Suggested name:** `budgetPolicies: BudgetPolicy[]`. -- **Rationale:** Tied to type rename suggestion #8. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. +- **Rationale:** Tied to type rename suggestion #5. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. -### 17. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:146` +### 16. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:146` - **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listBudgetPoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. -### 18. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:144` +### 17. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:144` - **Why weird:** Doc reads "In this field is omitted, there are no previous pages." — "In" should be "If". - **Category:** Observation (typo). - **Suggested name:** Fix doc. - **Rationale:** Generated; surfaces in IntelliSense. -### 19. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:46-50` +## Low severity + +### 18. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:46-50` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. - **Category:** Observation, 14 (wire-style identifiers in TS docs). - **Suggested name:** Fix the doc to reference TS field names. - **Rationale:** Editing UX: hovers should show TS, not proto. -### 20. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:159` +### 19. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:159` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). - **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. - **Rationale:** Real bug. -## Low severity - -### 21. `budgetPolicyFieldMask` function — `src/v1/model.ts:278` +### 20. `budgetPolicyFieldMask` function — `src/v1/model.ts:278` - **Why weird:** Exported helper for building a `FieldMask`. The export is not surfaced from `index.ts:5-19`, so it cannot be used by consumers of the package. - **Category:** Observation (unused public surface — dead export). - **Suggested name:** Either re-export from `index.ts`, or mark internal. - **Rationale:** Dead export. -### 22. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 21. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. -### 23. `HttpCallOptions` — `src/v1/utils.ts:15` +### 22. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. -### 24. `readAll` — `src/v1/utils.ts:40` +### 23. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 25. `flattenQueryParams` — `src/v1/utils.ts:123` +### 24. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 25. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Same as `abacpolicies` finding #32; generator-wide. -### 27. `Client` class plain name — `src/v1/client.ts:46` -- **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. +## Observations + +### 26. `Client` class plain name — `src/v1/client.ts:46` +Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 28. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` -- **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. +### 27. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. -## Observations - -### 29. Action-verb conventions in `Client` +### 28. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 30. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +### 29. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. - **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). -### 31. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 30. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. -- `usagepolicy` — has the identical model shape (`UsagePolicy`, `CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`) — i.e. it's a duplicate API surface with a different entity name. +- `usagepolicy` — has the identical model shape (`UsagePolicy`, `CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`) — i.e. it's a duplicate API surface with a different entity name. The three together blur the boundary between "policy that classifies usage" (budgetpolicy/usagepolicy) and "budget with alert thresholds" (budgets). The names themselves do not disambiguate which is which. - **Category:** 12 (duplicate concept), 1 (vague package names). - **Rationale:** Worth raising at the SDK / API design level. From the TS-user perspective, three near-clones makes the import surface confusing. -### 32. Acronym casing `Id` consistently used as `Id`, not `ID` -`policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken` (no id) — file consistently uses `Id` (Title-case lower). Inconsistent only with `URLSearchParams` (Web API; out of our control). Good internal consistency. -- **Category:** 3 (observation — internal acronym style is consistent). - ## Domain glossary - `budget policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. **Despite the name, it has no monetary "budget" semantics.** Compare with `budgets` package (real spend alerts). - `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `BudgetPolicy.bindingWorkspaceIds: number[]`. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index babc2f74..597ee678 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -12,11 +12,7 @@ This audit applies the 20 numbered concern categories from the audit checklist. Each finding lists the offending identifier(s), the category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete -rename suggestion. Findings are grouped by category. Generator-driven -items (such as the `_Response` suffix and underscored proto-style -nested-message names) are flagged as `LOW` because they are -codified across the entire generated SDK surface — they should be -fixed at the generator, not by hand-editing this package. +rename suggestion. Findings are grouped by category. --- @@ -141,18 +137,7 @@ fixed at the generator, not by hand-editing this package. ### 2. Redundant enum prefixes -#### F2.1 — `BudgetConfigurationFilter_Operator.IN` (LOW) -- **Where:** `model.ts:22-24`. -- **Why flagged:** Single value, so there is no real redundancy - *yet*. But the enum prefix `BudgetConfigurationFilter_Operator` - has 4 levels (`Budget`, `Configuration`, `Filter`, `Operator`) - before reaching the value. Consider whether `FilterOperator` (or - even just `Operator` inside a `Filter` namespace) is enough. -- **Suggestion:** If proto-style nested names are dropped (see - F4.1), this becomes `FilterOperator.IN`, which is fine. No member - rename needed; the redundancy is in the enum name not the values. - -#### F2.2 — `ActionConfigurationType.EMAIL_NOTIFICATION` (LOW) +#### F2.1 — `ActionConfigurationType.EMAIL_NOTIFICATION` (LOW) - **Where:** `model.ts:5-7`. - **Why flagged:** Not redundant with the enum name, but `EMAIL_NOTIFICATION` could be `EMAIL` since this enum is @@ -162,21 +147,21 @@ fixed at the generator, not by hand-editing this package. - **Suggestion:** Treat as wire-protocol value; do not rename in TS unless the API spec changes. Leave with a comment. -#### F2.3 — `AlertConfigurationTimePeriod.MONTH` (acceptable) +#### F2.2 — `AlertConfigurationTimePeriod.MONTH` (acceptable) - No redundancy. `MONTH` is concise. -#### F2.4 — `AlertConfigurationTriggerType.CUMULATIVE_SPENDING_EXCEEDED` (acceptable) +#### F2.3 — `AlertConfigurationTriggerType.CUMULATIVE_SPENDING_EXCEEDED` (acceptable) - Long but descriptive; the redundancy is not with the enum name. See F18. -#### F2.5 — `AlertConfigurationQuantityType.LIST_PRICE_DOLLARS_USD` (acceptable) +#### F2.4 — `AlertConfigurationQuantityType.LIST_PRICE_DOLLARS_USD` (acceptable) - Long; see F18. --- ### 3. Acronym casing inconsistencies -#### F3.1 — `Id` vs `ID` (HIGH, cross-cutting) +#### F3.1 — `Id` vs `ID` (acceptable) - **Where:** `model.ts:28, 37, 52, 54, 72, 111, 113, 135, 137, 145, 147, 157, 177, 190, 192`; `client.ts:53, 66, 83, 112, 140, 174, 234`. @@ -186,13 +171,6 @@ fixed at the generator, not by hand-editing this package. `nextPageToken`, `pageToken`). That is internally consistent and fine. The TS/JS community is split — DOM uses `nodeId`/`HTMLElement`, TypeScript itself uses `id`/`uuid` — so `Id` is defensible. - **The flag here is not against `Id`**, but against the *interaction* - with the proto-style `BudgetConfigurationFilter_WorkspaceIdClause` - identifier, where the suffix becomes - `WorkspaceIdClause`. Reading `WorkspaceIdClause` left-to-right - parses as "WorkspaceId-Clause", but a TS reader who is unfamiliar - with the type domain might parse it as "Workspace-IdClause" - (i.e. an "ID clause" for workspaces). Slight ambiguity. - **Suggestion:** Keep `Id`. Add a brief project-level note in `typescript.mdc` documenting the convention so reviewers stop re-litigating it. @@ -215,51 +193,7 @@ fixed at the generator, not by hand-editing this package. ### 4. Underscores in TS identifiers -> The TypeScript style guide (Google) and the SDK's own -> `typescript.mdc` disallow `snake_case` and underscores in -> identifiers. The generator emits proto-style "outer_inner" names -> as `Outer_Inner` to disambiguate nested messages — but TS would -> normally fold these into namespaces or flat PascalCase. - -#### F4.1 — Proto-style underscore types (HIGH, cross-cutting, - generator concern) -- **Where:** - - `BudgetConfigurationFilter_Operator` (enum) `model.ts:22` - - `BudgetConfigurationFilter_Clause` (interface) `model.ts:81` - - `BudgetConfigurationFilter_TagClause` (interface) `model.ts:87` - - `BudgetConfigurationFilter_WorkspaceIdClause` (interface) - `model.ts:93` - - `CreateBudgetConfiguration_Response` `model.ts:104` - - `DeleteBudgetConfiguration_Response` `model.ts:141` - - `GetBudgetConfiguration_Response` `model.ts:152` - - `ListBudgetConfigurations_Response` `model.ts:169` - - `UpdateBudgetConfiguration_Response` `model.ts:183` - - Re-exported through `index.ts:10, 18-31`. -- **Why flagged:** Each of these requires an - `eslint-disable-next-line @typescript-eslint/naming-convention` - comment. That alone is a smell. The TypeScript-idiomatic - equivalents would be either nested namespaces - (`namespace BudgetConfigurationFilter { export interface Clause … }`) - or flat PascalCase (`BudgetConfigurationFilterClause`). -- **Suggestion:** Drop underscores at the generator level. Two viable - shapes: - 1. **Flat PascalCase** — - `BudgetConfigurationFilterClause`, - `BudgetConfigurationFilterTagClause`, - `BudgetConfigurationFilterWorkspaceIdClause`, - `BudgetConfigurationFilterOperator`, - `CreateBudgetConfigurationResponse`, etc. - 2. **Namespace nesting** — keep parent name, drop underscore: - `BudgetConfigurationFilter.Clause`, etc. - Approach (1) is more straightforward for tree-shaking and module - re-exports; approach (2) more closely mirrors the proto nesting. - -#### F4.2 — Comment in `client.ts:52`: "Fallback for endpoints whose - path contains {account_id}." (LOW) -- **Where:** `client.ts:52`. -- **Why flagged:** This is a comment, not an identifier — but it - refers to the *wire* placeholder `{account_id}` in snake_case, - which is fine. No action. +_None._ --- @@ -271,7 +205,7 @@ fixed at the generator, not by hand-editing this package. #### F5.2 — `resp` (LOW, Go-ism) - **Where:** `client.ts:85, 113, 147, 190, 236`; `utils.ts:73, 81`. -- See F14.2. +- See F14.1. #### F5.3 — `respBody` (LOW) - **Where:** `client.ts:90, 118, 152, 195, 241`. @@ -397,9 +331,7 @@ fixed at the generator, not by hand-editing this package. patterns: `client.budgets.create(req: CreateBudgetRequest)`. - **Suggestion:** Drop the `Configuration` token from request types: `CreateBudgetRequest`, `GetBudgetRequest`, `UpdateBudgetRequest`, - `DeleteBudgetRequest`, `ListBudgetsRequest`. Note the addition of - an explicit `Request` suffix to match the existing `_Response` - pattern — see F8.1 / F20. + `DeleteBudgetRequest`, `ListBudgetsRequest`. #### F7.3 — `CreateBudgetConfigurationBudget` and `UpdateBudgetConfigurationBudget` (HIGH) @@ -445,28 +377,14 @@ fixed at the generator, not by hand-editing this package. ### 8. Redundant suffixes -#### F8.1 — `_Response` suffix on every response type (LOW, - cross-cutting generator concern) -- **Where:** `model.ts:104, 141, 152, 169, 183`. -- **Why flagged:** Every response type uses `_Response`. Underscore - aside (F4.1), `Response` on a type already on the return path is - partially redundant — but here it disambiguates from the - same-named request type, which is fine. The flag is on the - *underscore*, not the suffix itself. -- **Suggestion:** Drop the underscore (`CreateBudgetResponse`, - `DeleteBudgetResponse`, etc.) or drop the request token entirely - (just `BudgetResponse`, `BudgetListResponse`). With F7.2 the - request types become `CreateBudgetRequest` etc., so this - resolves naturally. - -#### F8.2 — `LIST_PRICE_DOLLARS_USD` (LOW) +#### F8.1 — `LIST_PRICE_DOLLARS_USD` (LOW) - **Where:** `model.ts:10`. - **Why flagged:** `DOLLARS_USD` is tautological — USD *is* dollars. This is a wire-protocol value, so the SDK cannot change it unilaterally, but worth noting upstream. - **Suggestion:** Wire protocol; leave with a comment. -#### F8.3 — `ActionConfigurationType` enum name (LOW) +#### F8.2 — `ActionConfigurationType` enum name (LOW) - **Where:** `model.ts:5`. - **Why flagged:** `ConfigurationType` is partially tautological with the wrapping `ActionConfiguration` type — `ActionConfiguration.actionType: @@ -477,10 +395,10 @@ fixed at the generator, not by hand-editing this package. `BudgetAlertAction`, the enum becomes `BudgetAlertAction.Type` or simply `BudgetAlertActionType`). -#### F8.4 — `AlertConfigurationQuantityType`, +#### F8.3 — `AlertConfigurationQuantityType`, `AlertConfigurationTimePeriod`, `AlertConfigurationTriggerType` (LOW) - **Where:** `model.ts:9, 13, 17`. -- **Why flagged:** Same pattern as F8.3 — `AlertConfiguration` parent + +- **Why flagged:** Same pattern as F8.2 — `AlertConfiguration` parent + `QuantityType`/`TimePeriod`/`TriggerType` suffix. With parent renamed to `BudgetAlert` (see F7), suffixes become reasonable: `BudgetAlertQuantityType`, `BudgetAlertTimePeriod`, @@ -686,10 +604,7 @@ _None._ gain. This is a porting-convention decision and should be made globally at the generator level. -#### F14.2 — `_Response` (and other) underscore-pseudo-nesting (HIGH) -- See F4.1. Underscores are foreign to TS. - -#### F14.3 — Comment style (acceptable) +#### F14.2 — Comment style (acceptable) - Comments are sentences. Good — but the file-top comment is the generator banner. @@ -764,7 +679,7 @@ _None._ #### F18.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) - **Where:** `model.ts:10`. - **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant - (F8.2). Could be `LIST_PRICE_USD` or `USD`. + (F8.1). Could be `LIST_PRICE_USD` or `USD`. - **Suggestion:** Wire value; report upstream. #### F18.3 — `EMAIL_NOTIFICATION` (LOW) @@ -881,19 +796,19 @@ This SDK exposes two separate packages whose names both start with | # | Category | Findings | | - | --------------------------------------- | -------- | | 1 | Vague / generic | 7 | -| 2 | Redundant enum prefixes | 5 (3 acceptable) | -| 3 | Acronym casing | 4 (3 acceptable) | -| 4 | Underscores in TS identifiers | 2 | +| 2 | Redundant enum prefixes | 4 (3 acceptable) | +| 3 | Acronym casing | 4 (4 acceptable) | +| 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 7 | | 6 | Misleading names | 5 | | 7 | Overly verbose | 4 | -| 8 | Redundant suffixes | 4 | +| 8 | Redundant suffixes | 3 | | 9 | Singular / plural mismatch | 5 (3 acceptable) | | 10 | Reserved-word collisions | 5 (3 acceptable) | | 11 | Empty / trivial wrappers | 0 | | 12 | Duplicate concepts | 5 | | 13 | Verb-tense inconsistency | 2 (1 acceptable) | -| 14 | Go / Java-style names | 3 (1 acceptable) | +| 14 | Go / Java-style names | 2 (1 acceptable) | | 15 | Generic field names | 5 | | 16 | Field contradicting type domain | 3 | | 17 | Inconsistent action verbs | 1 (1 acceptable) | @@ -920,14 +835,10 @@ This SDK exposes two separate packages whose names both start with `ActionConfigurationType` to `BudgetAlertActionType`. 5. **F7.2 / F7.4:** Drop "Configuration" from request type names (`CreateBudgetRequest`) and method names - (`budgets.create(...)`); document explicit `Request`/`Response` - suffix convention. -6. **F4.1:** Replace underscored proto-style names with - flat PascalCase or namespaces; eliminates all - `eslint-disable-next-line` for `naming-convention`. -7. **F12.4:** Lift `accountId` to top-level on all request types + (`budgets.create(...)`). +6. **F12.4:** Lift `accountId` to top-level on all request types (currently nested under `budget` for create/update only). -8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ +7. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson` etc. across all generated code. --- diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md index 9b3b8c4f..fe78e58b 100644 --- a/.agent/naming-audit/bundle.md +++ b/.agent/naming-audit/bundle.md @@ -10,17 +10,16 @@ | Severity | Count | | ------------ | ----- | -| High | 7 | +| High | 5 | | Medium | 13 | | Low | 10 | | Observation | 6 | -| **Total** | **36** | +| **Total** | **34** | Dominant themes: -1. **Pervasive redundant enum prefixes.** All seven enums repeat the type name on every member (`DEPLOYMENT_STATUS_ACTIVE`, `VERSION_TYPE_DEPLOY`, etc.) — 50+ values affected — which is a Go/Protobuf carry-over that hurts TS ergonomics. -2. **`VersionComplete` is a misleading type name.** It is a noun that reads like a boolean predicate, but it actually carries a completion *reason* enum; the type, the field that holds it (`completionReason`), and the values disagree on terminology. -3. **`Resource` / `Operation` `name` is the qualified path, not a display name** — semantic overload of `name` recurs on every entity, while a separate `displayName` field also exists on `Deployment`/`Version`. Pure Google-AIP carry-over that loses meaning in TS. -4. **"Bundle" is in the URL but absent from type names**, while `DeploymentResourceType` (the domain catalog) is unrelated to the `Resource` interface (the per-deployment tracked item) — two distinct concepts share a confusable root. +1. **`VersionComplete` is a misleading type name.** It is a noun that reads like a boolean predicate, but it actually carries a completion *reason* enum; the type, the field that holds it (`completionReason`), and the values disagree on terminology. +2. **`Resource` / `Operation` `name` is the qualified path, not a display name** — semantic overload of `name` recurs on every entity, while a separate `displayName` field also exists on `Deployment`/`Version`. Pure Google-AIP carry-over that loses meaning in TS. +3. **"Bundle" is in the URL but absent from type names**, while `DeploymentResourceType` (the domain catalog) is unrelated to the `Resource` interface (the per-deployment tracked item) — two distinct concepts share a confusable root. --- @@ -48,39 +47,7 @@ Compounding the issue: the `complete` action lives on a *method* called `complet --- -### H2. Redundant enum-member prefixes throughout (Category: 2 — redundant enum prefixes; 18 — long enum values) - -**Location:** every enum in `model.ts:19-155`. - -```ts -DeploymentResourceType.DEPLOYMENT_RESOURCE_TYPE_JOB -DeploymentStatus.DEPLOYMENT_STATUS_ACTIVE -OperationActionType.OPERATION_ACTION_TYPE_BIND_AND_UPDATE -OperationStatus.OPERATION_STATUS_SUCCEEDED -VersionComplete.VERSION_COMPLETE_LEASE_EXPIRED -VersionStatus.VERSION_STATUS_IN_PROGRESS -VersionType.VERSION_TYPE_DEPLOY -``` - -Every member of every enum re-states the enum name. This is a Protobuf/Go habit that does not survive the port: in TypeScript the call site is already `DeploymentStatus.X`. The most extreme cases are `OPERATION_ACTION_TYPE_INITIAL_REGISTER`, `DEPLOYMENT_RESOURCE_TYPE_MODEL_SERVING_ENDPOINT`, and `DEPLOYMENT_RESOURCE_TYPE_SYNCED_DATABASE_TABLE` (46+ characters). - -**Note:** because the enum *values* are sent on the wire (the schemas in `model.ts:728-842` use `z.enum(EnumName)` which preserves the string form), the string values themselves must remain `'DEPLOYMENT_RESOURCE_TYPE_MODEL'` etc. — but the *identifier* on the enum can be shortened (`DeploymentResourceType.Model = 'DEPLOYMENT_RESOURCE_TYPE_MODEL'`). This is the common TS solution but is not currently applied. - -**Affected enums:** all seven (`DeploymentResourceType`, `DeploymentStatus`, `OperationActionType`, `OperationStatus`, `VersionComplete`, `VersionStatus`, `VersionType`) — ~50 identifiers. - ---- - -### H3. Underscores in TypeScript identifiers (Category: 4 — underscores in TS) - -**Location:** all enum members in `model.ts:19-155`. - -All enum member identifiers use `SCREAMING_SNAKE_CASE` (`DEPLOYMENT_STATUS_ACTIVE`, `OPERATION_ACTION_TYPE_BIND_AND_UPDATE`, etc.). The Google TS style guide and ESLint `@typescript-eslint/naming-convention` rule both forbid underscores in identifiers (the convention is `PascalCase` for enum members). The wire-value strings on the right-hand side can keep the underscores, but the identifiers should be `Active`, `BindAndUpdate`, `InitialRegister`, etc. - -This is the same root cause as H2 but tracked separately because it is a hard style-guide violation regardless of redundancy. - ---- - -### H4. `name` field is semantically overloaded across every entity (Category: 6 — misleading; 12 — duplicate concepts) +### H2. `name` field is semantically overloaded across every entity (Category: 6 — misleading; 12 — duplicate concepts) **Location:** `model.ts` — `Deployment.name`, `Operation.name`, `Resource.name`, `Version.name`, and on every request type (`CompleteVersionRequest.name`, `DeleteDeploymentRequest.name`, `GetDeploymentRequest.name`, `GetOperationRequest.name`, `GetResourceRequest.name`, `GetVersionRequest.name`, `HeartbeatRequest.name`). @@ -98,7 +65,7 @@ A reader cannot tell what `name` means without consulting the docstring of each --- -### H5. `DeploymentResourceType` enum and `Resource` interface share a confusable root concept (Category: 12 — duplicate concepts; 1 — vague) +### H3. `DeploymentResourceType` enum and `Resource` interface share a confusable root concept (Category: 12 — duplicate concepts; 1 — vague) **Location:** `model.ts:19` (`DeploymentResourceType`) versus `model.ts:487-511` (`Resource`). @@ -114,13 +81,13 @@ Compounding this: `Resource.resourceKey` (a key *within the bundle config*, e.g. --- -### H6. "Bundle" is missing from every type name despite being the package name (Category: 14 — Go/Java-style; 15 — generic names losing meaning) +### H4. "Bundle" is missing from every type name despite being the package name (Category: 14 — Go/Java-style; 15 — generic names losing meaning) **Location:** all exported types in `model.ts`, `index.ts:5-39`. The package is `@databricks/sdk-bundle` and every URL has `/api/2.0/bundle/`, yet not one type is `Bundle*`. Instead, the top-level entity is `Deployment` — extremely generic in TypeScript, where "deployment" appears in dozens of unrelated packages (jobs, model serving, apps, etc.). Outside the namespace, `Deployment` says nothing. -Worse: `Deployment` also unrelatedly resembles `DeploymentResourceType` (see H5), and `DeploymentStatus` is used both on the top-level deployment *and* describes one of the lifecycle terms `DELETED` that does not match the more recent `destroyTime` lifecycle. From outside this package, the type `Deployment` is non-self-describing. +Worse: `Deployment` also unrelatedly resembles `DeploymentResourceType` (see H3), and `DeploymentStatus` is used both on the top-level deployment *and* describes one of the lifecycle terms `DELETED` that does not match the more recent `destroyTime` lifecycle. From outside this package, the type `Deployment` is non-self-describing. Note: the user-supplied glossary explicitly flags "Bundle" as overloaded. The package solves the overload by *avoiding the word*, but this swap is not free — it just moves the ambiguity from "Bundle" to "Deployment". @@ -128,7 +95,7 @@ Note: the user-supplied glossary explicitly flags "Bundle" as overloaded. The pa --- -### H7. `HeartbeatRequest` / `HeartbeatResponse` and `heartbeat()` use a bare noun where the verb is `renew` (Category: 6 — misleading; 17 — inconsistent action verbs) +### H5. `HeartbeatRequest` / `HeartbeatResponse` and `heartbeat()` use a bare noun where the verb is `renew` (Category: 6 — misleading; 17 — inconsistent action verbs) **Location:** `model.ts:304-316`, `client.ts:398-421`. @@ -192,7 +159,7 @@ Reads as "the type of action type of operation". One of "action" or "type" is re **Location:** `model.ts:19`. -Reads as "deployment resource type", but the enum is the *catalog of resource kinds*, not a property of deployment. Just `ResourceKind` (or `BundleResourceKind` if you want to disambiguate from the `Resource` interface) would suffice. See H5 for the broader confusion. +Reads as "deployment resource type", but the enum is the *catalog of resource kinds*, not a property of deployment. Just `ResourceKind` (or `BundleResourceKind` if you want to disambiguate from the `Resource` interface) would suffice. See H3 for the broader confusion. --- @@ -204,17 +171,17 @@ The field is `completionReason` (noun "reason" with "completion" adjective). The --- -### M8. `VersionComplete` enum value `VERSION_COMPLETE_FORCE_ABORT` is a verb phrase where others are nouns (Category: 13 — verb-tense) +### M8. `VersionComplete` enum values use inconsistent grammatical forms (Category: 13 — verb-tense) **Location:** `model.ts:133`. -The enum values are: -- `SUCCESS` — noun. -- `FAILURE` — noun. -- `FORCE_ABORT` — verb phrase ("force abort"). -- `LEASE_EXPIRED` — past-participle phrase. +The completion-reason values mix grammatical structures: +- `Success` — noun. +- `Failure` — noun. +- `ForceAbort` — verb phrase ("force abort"). +- `LeaseExpired` — past-participle phrase. -Three different grammatical structures for what should be parallel completion reasons. The docstring on `FORCE_ABORT` says "was force-aborted by another user" — so `FORCE_ABORTED` (past participle) would parallel `LEASE_EXPIRED`, and noun forms (`SUCCESS`, `FAILURE`, `FORCED_ABORT`, `LEASE_EXPIRATION`) would be even more parallel. +Three different grammatical structures for what should be parallel completion reasons. The docstring on the force-abort value says "was force-aborted by another user" — so `ForceAborted` (past participle) would parallel `LeaseExpired`, and noun forms (`Success`, `Failure`, `ForcedAbort`, `LeaseExpiration`) would be even more parallel. --- @@ -222,7 +189,7 @@ Three different grammatical structures for what should be parallel completion re **Location:** `client.ts:398`. -In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here it actively *mutates server state* (renews a lock). The verb suggests a read but it's a write. See H7 for suggested rename to `renewLock`. +In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here it actively *mutates server state* (renews a lock). The verb suggests a read but it's a write. See H5 for suggested rename to `renewLock`. --- @@ -234,7 +201,7 @@ In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here i --- -### M11. `VersionType` enum is generic, values prepended with `VERSION_TYPE_` (Category: 1 — vague) +### M11. `VersionType` enum is generic (Category: 1 — vague) **Location:** `model.ts:149`. @@ -272,7 +239,7 @@ All three are well-named (`createdBy`, `destroyedBy`, `completedBy`). However, ` **Location:** `Deployment.destroyTime` (`model.ts:259`), `Deployment.destroyedBy` (`model.ts:264`). -The comment on `destroyTime` explicitly justifies the divergence from `deleteTime` ("Named destroy_time (not delete_time) because this tracks the `databricks bundle destroy` command, not the API-level deletion"). That is a sensible choice, but worth noting that a reader scanning the field list sees `createTime`, `updateTime`, `destroyTime` and may mistakenly think it equals "delete time" (since `DeploymentStatus.DELETED` exists). Could keep `destroyTime` but rename the enum value to `DEPLOYMENT_STATUS_DESTROYED` for consistency. Currently the enum is `DELETED` while the lifecycle event is `destroy`. +The comment on `destroyTime` explicitly justifies the divergence from `deleteTime` ("Named destroy_time (not delete_time) because this tracks the `databricks bundle destroy` command, not the API-level deletion"). That is a sensible choice, but worth noting that a reader scanning the field list sees `createTime`, `updateTime`, `destroyTime` and may mistakenly think it equals "delete time" (since the `Deleted` lifecycle value on `DeploymentStatus` exists). Could keep `destroyTime` but rename the enum value to `Destroyed` for consistency. Currently the enum value is `Deleted` while the lifecycle event is `destroy`. --- @@ -296,7 +263,7 @@ The comment on `destroyTime` explicitly justifies the divergence from `deleteTim **Location:** `CreateOperationRequest.parent` (`model.ts:196`), `CreateVersionRequest.parent` (`model.ts:212`), `ListOperationsRequest.parent` (`model.ts:351`), `ListResourcesRequest.parent` (`model.ts:383`), `ListVersionsRequest.parent` (`model.ts:415`). -This is a Google AIP carry-over. `parent` is meaningful inside Google's resource hierarchy convention but loses meaning in TS where IDEs will surface it without context. Could be `deploymentName` (for `Create*Request`/`List*Request` whose parent is a deployment) or `versionName` (for `CreateOperationRequest`/`ListOperationsRequest` whose parent is a version). Different request types use `parent` for different scopes — same problem as `name` (see H4). +This is a Google AIP carry-over. `parent` is meaningful inside Google's resource hierarchy convention but loses meaning in TS where IDEs will surface it without context. Could be `deploymentName` (for `Create*Request`/`List*Request` whose parent is a deployment) or `versionName` (for `CreateOperationRequest`/`ListOperationsRequest` whose parent is a version). Different request types use `parent` for different scopes — same problem as `name` (see H2). --- @@ -328,7 +295,7 @@ This is correct re-use — both reference the same bundle config path. No issue. **Location:** `Client.listDeployments` → `/api/2.0/bundle/deployments` (`client.ts:428`). -The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The method `listDeployments` matches. No issue, just noting the package's external resource is named "deployment" and the package is named "bundle", reinforcing the H6 observation that "Bundle" is in the URL but absent from type names. +The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The method `listDeployments` matches. No issue, just noting the package's external resource is named "deployment" and the package is named "bundle", reinforcing the H4 observation that "Bundle" is in the URL but absent from type names. --- @@ -356,15 +323,15 @@ The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is ### O4. Method `getResource` returns `Resource`, no naming collision -`client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level — only at the *interface* level (H5). +`client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level — only at the *interface* level (H3). ### O5. Comment on the `name`-vs-`destroy` divergence is appreciated -`Deployment.destroyTime` has an in-code justification (`model.ts:255-258`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H4). +`Deployment.destroyTime` has an in-code justification (`model.ts:255-258`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H2). ### O6. The `HeartbeatResponse.expireTime` field has no `Lease`/`Lock` prefix -The docstring says "new lock expiry time", but the field is just `expireTime`. Calling it `lockExpireTime` or `lockExpiresAt` would self-document. Marginal because of H7 (rename the whole method to `renewLock` and the field name becomes obvious from context). +The docstring says "new lock expiry time", but the field is just `expireTime`. Calling it `lockExpireTime` or `lockExpiresAt` would self-document. Marginal because of H5 (rename the whole method to `renewLock` and the field name becomes obvious from context). --- @@ -372,18 +339,18 @@ The docstring says "new lock expiry time", but the field is just `expireTime`. C | Domain term | Meaning | Naming concerns? | | ------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------ | -| Bundle | Databricks Asset Bundle — a config-driven project deployed via `databricks bundle deploy`. | Absent from all type names (H6). | +| Bundle | Databricks Asset Bundle — a config-driven project deployed via `databricks bundle deploy`. | Absent from all type names (H4). | | Deployment | A registered bundle in the control plane. One per bundle target. Top-level entity in this API. | Overloaded with "deploy time" sense; generic outside the package. | | Version | A single deploy or destroy *run* of a bundle. Acquires an exclusive lock on the deployment. | OK; `Version` is clear within the package. | -| Operation | One resource action (create/update/delete/bind/...) recorded under a version. Append-only. | Collides with LRO `Operation` (L8). | -| Resource | A per-deployment record of one Databricks object the bundle manages (a job, a pipeline, etc.). | Confusable with `DeploymentResourceType` (H5). | -| `resource_key` | A dotted config path inside the bundle YAML (e.g. `"jobs.foo"`). | Generic name (M1, H5). | +| Operation | One resource action (create/update/delete/bind/...) recorded under a version. Append-only. | Collides with LRO `Operation` (L7). | +| Resource | A per-deployment record of one Databricks object the bundle manages (a job, a pipeline, etc.). | Confusable with `DeploymentResourceType` (H3). | +| `resource_key` | A dotted config path inside the bundle YAML (e.g. `"jobs.foo"`). | Generic name (M1, H3). | | `resource_id` | The workspace-scoped ID of the underlying Databricks object (e.g. a job ID, pipeline ID). | Mixes with control-plane IDs (M2). | -| Heartbeat | Lock renewal RPC sent by the active CLI while a version is in progress. | Misleading name; should be "renew lock" (H7). | +| Heartbeat | Lock renewal RPC sent by the active CLI while a version is in progress. | Misleading name; should be "renew lock" (H5). | | Target | A named profile within a bundle (e.g. `dev`, `staging`, `prod`). | `targetName` field on Deployment/Version is OK but could be `bundleTargetName` (L1). | | Destroy | The `databricks bundle destroy` command — undeploys a bundle. Distinct from API-level delete. | Named `destroyTime` (not `deleteTime`) intentionally (L2). | -| Force-abort | A user other than the version creator forcibly completes the version. | `VERSION_COMPLETE_FORCE_ABORT` is the verb form (M8). | -| Lease | The lock held by a version; renewed by Heartbeat; expires after timeout. | Surfaces only in `VERSION_COMPLETE_LEASE_EXPIRED`. | +| Force-abort | A user other than the version creator forcibly completes the version. | The `ForceAbort` completion value uses a verb phrase while siblings are nouns (M8). | +| Lease | The lock held by a version; renewed by Heartbeat; expires after timeout. | Surfaces only in the `LeaseExpired` completion value. | --- @@ -391,8 +358,8 @@ The docstring says "new lock expiry time", but the field is just `expireTime`. C | File | Lines | Findings | | ----------------- | ----- | --------------------------------------------------------------------------------- | -| `src/v1/model.ts` | 843 | H1, H2, H3, H4, H5, H6, H7, M1-M13, L1-L5, L7, L8, L10, O1, O3, O5, O6 | -| `src/v1/client.ts`| 630 | H4 (request types), H7 (method name), M9, L9, O4 | +| `src/v1/model.ts` | 843 | H1, H2, H3, H4, H5, M1-M13, L1-L5, L7, L8, L10, O1, O3, O5, O6 | +| `src/v1/client.ts`| 630 | H2 (request types), H5 (method name), M9, L9, O4 | | `src/v1/utils.ts` | 151 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | | `src/v1/index.ts` | 40 | Re-exports — inherits findings from `model.ts` and `client.ts`. | diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index 1dc2f9e3..6313d0ea 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -12,12 +12,9 @@ The `catalogs` package surfaces five UC catalog operations (`createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`) plus a paginated iterator. The model layer mostly mirrors the Go SDK 1:1, so most issues are inherited from the upstream definitions. -The most pervasive problems are (1) proto-style underscore-suffixed -identifiers leaking into TypeScript (`ConversionInfo_State`, -`DeleteCatalog_Response`, `ListCatalogs_Response`, `*_OptionsEntry`, -`*_PropertiesEntry`), (2) the cryptic `nameArg` path-parameter field, and -(3) massive `Create*`/`Update*` request shapes that include read-only -output fields (`createdAt`, `createdBy`, `provisioningInfo`, +The most pervasive problems are (1) the cryptic `nameArg` path-parameter +field, and (2) massive `Create*`/`Update*` request shapes that include +read-only output fields (`createdAt`, `createdBy`, `provisioningInfo`, `conversionInfo`, `drReplicationInfo`, `securableType`, `fullName`, etc.) that have no business in a write request. @@ -35,12 +32,7 @@ the enable/disable string ("Whether predictive optimization should be enabled..."). Better: `enabled`, `predictiveOptimizationEnabled`, or mirror the upstream `flagValue` if present. -#### 1.2 `*_OptionsEntry.value` / `*_PropertiesEntry.value` (model.ts:133, 139, 208, 214, 372, 378) -Single-character-like generic names (`key`, `value`) on the exported -map-entry types. These names carry no semantics on their own and only -make sense in the context of the parent map. - -#### 1.3 `DrReplicationInfo.replicatedEntities` (model.ts:231) +#### 1.2 `DrReplicationInfo.replicatedEntities` (model.ts:231) A `Uint8Array` named `replicatedEntities` is meaningless — the doc comment points at an internal Google Doc. The name promises a list of entities; the type is a byte blob. Consumers cannot guess what to do @@ -48,12 +40,12 @@ with it. Either rename to something signaling the opacity (`replicatedEntitiesProto`, `replicatedEntitiesPayload`) or expose a parsed shape. -#### 1.4 `ConversionInfo.state` and `ProvisioningInfo.state` (model.ts:145, 305) +#### 1.3 `ConversionInfo.state` and `ProvisioningInfo.state` (model.ts:145, 305) Generic field name `state` on both types. Whose state? The name only acquires meaning from its surrounding type — if the field is ever inlined or destructured, the meaning is lost. -#### 1.5 `inheritedFromType` / `inheritedFromName` (model.ts:244, 246) +#### 1.4 `inheritedFromType` / `inheritedFromName` (model.ts:244, 246) `Type` here is a free-form `string`, not the `SecurableType` enum that governs the rest of the package. The name `inheritedFromType` suggests an enum/typed handle but is in fact human-readable text. Misleading — see @@ -74,14 +66,7 @@ In TypeScript this becomes `DrReplicationStatus.DR_REPLICATION_STATUS_PRIMARY` `SECONDARY`. This is a verbatim port of proto `enum` style and is the single most jarring naming violation in the package. -#### 2.2 `ConversionInfo_State.STATE_UNSPECIFIED` (model.ts:51) -Same pattern — `ConversionInfo_State.STATE_UNSPECIFIED` repeats `STATE`. -Drop the `STATE_` prefix on the variant so it reads `UNSPECIFIED`. - -#### 2.3 `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58) -Same as 2.2. - -#### 2.4 `CatalogType.*_CATALOG` (model.ts:13-18) +#### 2.2 `CatalogType.*_CATALOG` (model.ts:13-18) Every variant ends in `_CATALOG`: `MANAGED_CATALOG`, `DELTASHARING_CATALOG`, `SYSTEM_CATALOG`, `INTERNAL_CATALOG`, `FOREIGN_CATALOG`, `MANAGED_ONLINE_CATALOG`. Read aloud: @@ -120,7 +105,7 @@ or an ID — they currently contradict each other. See also §6.2. #### 3.4 `DELTASHARING_CATALOG` enum variant (model.ts:14) "Delta Sharing" is two words. Variant runs them together as `DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` (or simply -`DELTA_SHARING` after stripping the `_CATALOG` suffix per §2.4). +`DELTA_SHARING` after stripping the `_CATALOG` suffix per §2.2). #### 3.5 "UC Native" in doc comments (model.ts:118, 193, 357 etc.) Doc comments use "UC Native" capitalisation, but the package never refers @@ -132,42 +117,9 @@ or pick one form. --- -### 4. Underscores in TypeScript identifiers - -This is the package's most widespread cosmetic issue. Proto-style -underscore separators appear in exported TS identifiers, and each one has -been silenced with `@typescript-eslint/naming-convention -- Proto-style…` -disable comments — the lint rule disagrees and we are deliberately -working around it. - -#### 4.1 `ConversionInfo_State` (model.ts:50) -Proto nested-enum convention `Parent_Child`. TypeScript convention is -`ConversionInfoState` (or, better, top-level `ConversionState` because -there is no real nesting in TS — see §12.1). - -#### 4.2 `ProvisioningInfo_State` (model.ts:57) -Same as 4.1. Should be `ProvisioningState`. - -#### 4.3 `CatalogInfo_OptionsEntry`, `CatalogInfo_PropertiesEntry` (model.ts:131, 137) -Proto map-entry types — see §1.2. - -#### 4.4 `CreateCatalog_OptionsEntry`, `CreateCatalog_PropertiesEntry` (model.ts:206, 212) -Same as 4.3. - -#### 4.5 `UpdateCatalog_OptionsEntry`, `UpdateCatalog_PropertiesEntry` (model.ts:370, 376) -Same as 4.3. - -#### 4.6 `DeleteCatalog_Response` (model.ts:225) -Should be `DeleteCatalogResponse`. - -#### 4.7 `ListCatalogs_Response` (model.ts:292) -Should be `ListCatalogsResponse`. +### 4. Cryptic abbreviations ---- - -### 5. Cryptic abbreviations - -#### 5.1 `nameArg` (model.ts:219, 264, 310) +#### 4.1 `nameArg` (model.ts:219, 264, 310) Used as the catalog name path-parameter on `DeleteCatalog`, `GetCatalog`, and `UpdateCatalog`. The `Arg` suffix is jargon from the Go generator distinguishing path arguments from request-body fields with the same key. @@ -175,60 +127,60 @@ TypeScript callers have no need for this distinction — the field is the catalog name and should be named `name` (or `catalogName` if a sibling `name` field is required for body symmetry). Today, `UpdateCatalog` has *both* `nameArg` (path) and `name` (body) — virtually guaranteeing user -confusion. See also §14.1. +confusion. See also §11.1. -#### 5.2 `Dr` prefix throughout (`DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo`, `lastFailoverTimeMs` doc) — see §3.1. +#### 4.2 `Dr` prefix throughout (`DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo`, `lastFailoverTimeMs` doc) — see §3.1. -#### 5.3 `Cmk` prefix — see §3.2. +#### 4.3 `Cmk` prefix — see §3.2. -#### 5.4 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:257) — see §3.3. +#### 4.4 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:257) — see §3.3. -#### 5.5 `pkgJson` (client.ts:19) +#### 4.5 `pkgJson` (client.ts:19) Variable name `pkgJson` for `package.json`. Mostly internal — minor — but worth noting for consistency. --- -### 6. Misleading names +### 5. Misleading names -#### 6.1 `EffectivePredictiveOptimizationFlag.value` "string" carries enum-like semantics +#### 5.1 `EffectivePredictiveOptimizationFlag.value` "string" carries enum-like semantics The field is typed `string | undefined` but the comment ("Whether predictive optimization should be enabled…") implies a tri-state (enabled / disabled / inherit). Either the type should be an enum (`PredictiveOptimizationFlag`) or the field should be named explicitly (`enabled: string`). See also §1.1. -#### 6.2 `azureKeyVaultKeyId` is described as a URL (model.ts:257-258) +#### 5.2 `azureKeyVaultKeyId` is described as a URL (model.ts:257-258) Field is named `…Id` but doc says "the AKV URL in Azure". Either rename to `azureKeyVaultKeyUri` or fix the doc to match. Today the name lies about what the field holds. -#### 6.3 `replicatedEntities: Uint8Array` (model.ts:231) +#### 5.3 `replicatedEntities: Uint8Array` (model.ts:231) A name with cardinal plural ("entities") implies an iterable collection; -the type is a single byte buffer. See also §1.3. +the type is a single byte buffer. See also §1.2. -#### 6.4 `CatalogInfo.fullName` "Corresponds with the name field" (model.ts:116) +#### 5.4 `CatalogInfo.fullName` "Corresponds with the name field" (model.ts:116) The doc explicitly states that `fullName` equals `name` for catalogs. The field exists only to satisfy the parent `Securable` contract. This is arguably acceptable (UC is column-uniform across securables) but the name misleads — it promises richer information than `name` provides. -#### 6.5 `CatalogInfo.options` vs `CatalogInfo.properties` (model.ts:124-127) +#### 5.5 `CatalogInfo.options` vs `CatalogInfo.properties` (model.ts:124-127) Both are `Record` with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know what distinguishes them. The doc duplication is verbatim in CreateCatalog (199-202) and UpdateCatalog (363-366). Either is underspecified or one of them is misnamed. -#### 6.6 `EncryptionSettings.azureEncryptionSettings: AzureEncryptionSettings` (model.ts:259) +#### 5.6 `EncryptionSettings.azureEncryptionSettings: AzureEncryptionSettings` (model.ts:259) A field on `EncryptionSettings` named `azureEncryptionSettings` whose type is also `AzureEncryptionSettings` reads like a copy-paste error. Drop the prefix: `azure: AzureEncryptionSettings` is clearer. --- -### 7. Overly verbose +### 6. Overly verbose -#### 7.1 `EffectivePredictiveOptimizationFlag` (model.ts:240) +#### 6.1 `EffectivePredictiveOptimizationFlag` (model.ts:240) Identifier is 39 characters. Compounded by the field name `effectivePredictiveOptimizationFlag` (model.ts:109, 184, 348) used on three different request/response types. `EffectivePOFlag` or @@ -236,86 +188,86 @@ three different request/response types. `EffectivePOFlag` or `EffectivePredictiveOptimization` (no `Flag` since the type already wraps the flag). -#### 7.2 `enablePredictiveOptimization: string` (model.ts:83, 158, 322) +#### 6.2 `enablePredictiveOptimization: string` (model.ts:83, 158, 322) Long field name for a single flag value. Acceptable, but tracked because -it pairs with §7.1 to make every `CatalogInfo`-style object verbose. +it pairs with §6.1 to make every `CatalogInfo`-style object verbose. -#### 7.3 `managedEncryptionSettings` (model.ts:123, 198, 362) +#### 6.3 `managedEncryptionSettings` (model.ts:123, 198, 362) Three-word field name on a securable that already implies "managed". Consider `encryption` or `encryptionSettings`. -#### 7.4 `MANAGED_ONLINE_CATALOG` enum value (model.ts:18) — see §16.1. +#### 6.4 `MANAGED_ONLINE_CATALOG` enum value (model.ts:18) — see §13.1. --- -### 8. Redundant suffixes +### 7. Redundant suffixes -#### 8.1 `…Info` types (`CatalogInfo`, `ConversionInfo`, `ProvisioningInfo`, `DrReplicationInfo`) +#### 7.1 `…Info` types (`CatalogInfo`, `ConversionInfo`, `ProvisioningInfo`, `DrReplicationInfo`) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from the resource handle; in JS/TS the convention is to drop it (`Catalog`, `Conversion`, `Provisioning`, `DrReplication`). -#### 8.2 `…Settings` repeated (`AzureEncryptionSettings`, `EncryptionSettings`, `azureEncryptionSettings`) — see §6.6. +#### 7.2 `…Settings` repeated (`AzureEncryptionSettings`, `EncryptionSettings`, `azureEncryptionSettings`) — see §5.6. -#### 8.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` -The whole type *is* the flag; the suffix is redundant. See §7.1. +#### 7.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` +The whole type *is* the flag; the suffix is redundant. See §6.1. -#### 8.4 `…Arg` suffix on `nameArg` — see §5.1 and §14.1. +#### 7.4 `…Arg` suffix on `nameArg` — see §4.1 and §11.1. --- -### 9. Reserved-word collisions +### 8. Reserved-word collisions -#### 9.1 `options` field on `CatalogInfo`, `CreateCatalog`, `UpdateCatalog` (model.ts:127, 202, 366) +#### 8.1 `options` field on `CatalogInfo`, `CreateCatalog`, `UpdateCatalog` (model.ts:127, 202, 366) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (e.g. `createCatalog(req, options)`). The collision is not a compile error but creates cognitive load — inside `updateCatalog(req, options)` the reader sees both `req.options` (catalog metadata) and `options` (call options). Rename one. The least invasive fix is renaming the second client parameter to `callOptions`. See also -§10.1 for the duplicate-with-`properties` concern. +§9.1 for the duplicate-with-`properties` concern. -#### 9.2 `name` keyword-ish field +#### 8.2 `name` keyword-ish field `name` is used as a non-path-param body field on `Create*` / `Update*` / `CatalogInfo`, and also as a path arg via `nameArg`. This isn't a reserved word but it routinely shadows `Function.prototype.name` and is a common source of confusion when callers spread request objects. See -also §5.1. +also §4.1. -#### 9.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:242) — generic, frequently shadows local variables. See §1.1. +#### 8.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:242) — generic, frequently shadows local variables. See §1.1. --- -### 10. Duplicate concepts +### 9. Duplicate concepts -#### 10.1 `properties` and `options` (model.ts:124-127, 199-202, 363-366) +#### 9.1 `properties` and `options` (model.ts:124-127, 199-202, 363-366) Both `Record` on every catalog shape, with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know which to use for what. Either the -docs need to differentiate them or one is redundant. See also §6.5. +docs need to differentiate them or one is redundant. See also §5.5. -#### 10.2 `name` vs `fullName` on `CatalogInfo` +#### 9.2 `name` vs `fullName` on `CatalogInfo` `fullName` is documented as "the full name of the catalog. Corresponds with the name field" (model.ts:115-116). The same data lives in `name` for catalogs because catalogs are top-level. The duplicate field exists to satisfy a polymorphic Securable shape — but for the catalog-specific -type, it's redundant. See also §6.4. +type, it's redundant. See also §5.4. -#### 10.3 `name` vs `nameArg` on `UpdateCatalog` +#### 9.3 `name` vs `nameArg` on `UpdateCatalog` The `UpdateCatalog` request has *both* `nameArg` (the existing catalog identifier, used in the URL path) and `name` (the new desired name, used in the body). It also has `newName` for the same concept. See -§14.1 below — three name-like fields on one request shape. +§11.1 below — three name-like fields on one request shape. -#### 10.4 `securableType` on `CatalogInfo` (model.ts:117) duplicates the type identity +#### 9.4 `securableType` on `CatalogInfo` (model.ts:117) duplicates the type identity `CatalogInfo` represents a catalog; its `securableType` field will always be `SecurableType.CATALOG`. The field exists for polymorphism across UC types but is meaningless when the surrounding type already identifies the securable. Not a renaming issue — but worth flagging as a duplicated concept. -#### 10.5 `CreateCatalog`, `UpdateCatalog`, and `CatalogInfo` share ~25 fields verbatim +#### 9.5 `CreateCatalog`, `UpdateCatalog`, and `CatalogInfo` share ~25 fields verbatim The three types are 95% identical and have largely identical doc strings. This is a generator artifact, but it bleeds into naming: any rename of `storageRoot` must happen in three places. Recommend basing @@ -324,62 +276,23 @@ This is a generator artifact, but it bleeds into naming: any rename of --- -### 11. Verb-tense inconsistency +### 10. Verb-tense inconsistency -#### 11.1 Client methods are well-aligned: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`. No tense issues. +#### 10.1 Client methods are well-aligned: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`. No tense issues. -#### 11.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65) — both imperative present, consistent. +#### 10.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65) — both imperative present, consistent. -#### 11.3 `buildHttpRequest`, `parseResponse`, `marshalRequest` (utils.ts:96, 113, 119) — imperative present, consistent. +#### 10.3 `buildHttpRequest`, `parseResponse`, `marshalRequest` (utils.ts:96, 113, 119) — imperative present, consistent. -#### 11.4 `flattenQueryParams` (utils.ts:123) — imperative, consistent. +#### 10.4 `flattenQueryParams` (utils.ts:123) — imperative, consistent. No verb-tense inconsistencies found across the package. --- -### 12. Go / Java-style names - -#### 12.1 `ConversionInfo_State`, `ProvisioningInfo_State` (model.ts:50, 57) -Proto nested-enum naming `Parent_Child`. In TS this should be a -top-level type with a meaningful prefix: `ConversionState`, -`ProvisioningState`. See §4.1-4.2. - -#### 12.2 `Client` class name (client.ts:44) -Bare `Client` (rather than `CatalogsClient`) is a Go-idiom: package -qualifies the type. JS consumers commonly import as -`import {Client} from '@databricks/sdk-catalogs/v1'` and have to alias. -This is a package-wide convention, but worth flagging in this audit -for consistency with the broader review. - -#### 12.3 `nameArg` (model.ts:219, 264, 310) — Go generator naming. See §5.1. - -#### 12.4 `…_Response` suffix is a proto / Go-RPC idiom. See §4.6, §4.7. - -#### 12.5 `…Info` suffix — Java/Go style. See §8.1. - ---- - -### 13. Generic field names losing meaning - -#### 13.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. - -#### 13.2 `key`, `value` on map-entry wrappers (`*_OptionsEntry`, `*_PropertiesEntry`) — see §1.2. - -#### 13.3 `state` on `ConversionInfo`, `ProvisioningInfo` (model.ts:145, 305) -Whose state? Bound to its container — but if the container is ever -inlined, the field stands alone. See §1.4. - -#### 13.4 `status` on `DrReplicationInfo` (model.ts:229) -Generic in isolation; works in context. Less severe than `state`. - -#### 13.5 `properties`, `options` (model.ts:125, 127, etc.) — see §6.5, §10.1. - ---- +### 11. Field contradicting type domain -### 14. Field contradicting type domain - -#### 14.1 `UpdateCatalog` has `nameArg`, `name`, and `newName` (model.ts:310, 312, 314) +#### 11.1 `UpdateCatalog` has `nameArg`, `name`, and `newName` (model.ts:310, 312, 314) Three name-bearing fields on a single update request: - `nameArg` — existing catalog (path param). - `newName` — new desired name (body). @@ -389,7 +302,7 @@ A caller staring at this struct cannot intuit which to set. This is the single most user-hostile naming pattern in the package — and it sits on the most-used method. -#### 14.2 `CreateCatalog` contains read-only output fields +#### 11.2 `CreateCatalog` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `provisioningInfo`, `conversionInfo`, `drReplicationInfo`, `fullName`, `securableType`, `effectivePredictiveOptimizationFlag`, `browseOnly` @@ -397,17 +310,17 @@ the most-used method. is at best ignored. The type's domain is "create request", but its shape contradicts that. Mirror issue in `UpdateCatalog`. -#### 14.3 `DeleteCatalog.nameArg` — see §5.1. +#### 11.3 `DeleteCatalog.nameArg` — see §4.1. -#### 14.4 `EncryptionSettings.azureEncryptionSettings` +#### 11.4 `EncryptionSettings.azureEncryptionSettings` The outer type's domain is "all encryption settings"; the field is named as if scoped to Azure. The contradiction (parent claims breadth, child name claims specificity) is resolved by reading the type definition -but is initially confusing. See §6.6. +but is initially confusing. See §5.6. --- -### 15. Inconsistent action verbs +### 12. Inconsistent action verbs Method verbs in `Client`: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`. Verbs are consistent: standard CRUD. @@ -415,76 +328,71 @@ No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- -### 16. Long enum values +### 13. Long enum values -#### 16.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:18) +#### 13.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:18) 22-character enum value. Should be `MANAGED_ONLINE` after dropping the -redundant `_CATALOG` suffix (§2.4). +redundant `_CATALOG` suffix (§2.2). -#### 16.2 `DrReplicationStatus.DR_REPLICATION_STATUS_SECONDARY` (model.ts:24) +#### 13.2 `DrReplicationStatus.DR_REPLICATION_STATUS_SECONDARY` (model.ts:24) 33-character enum value, of which the first 22 are redundant. See §2.1. -#### 16.3 `ConversionInfo_State.STATE_UNSPECIFIED` (model.ts:51) -17 characters; redundant `STATE_` prefix. See §2.2. - -#### 16.4 `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58) — same. - --- -### 17. Underspecified IDs +### 14. Underspecified IDs -#### 17.1 `metastoreId` (model.ts:96, 171, 335) +#### 14.1 `metastoreId` (model.ts:96, 171, 335) Documented as "unique identifier of parent metastore". Format opaque (UUID? slug?). Acceptable but unspecified. -#### 17.2 `azureTenantId` (model.ts:68) +#### 14.2 `azureTenantId` (model.ts:68) GUID, implied by Azure context. Doc-less — not specified anywhere. -#### 17.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) +#### 14.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) Doc-less. Format is an Azure resource ID (`/subscriptions/…/providers/…`), not signalled by the name or documentation. -#### 17.4 `customerManagedKeyId` (model.ts:255) +#### 14.4 `customerManagedKeyId` (model.ts:255) Doc: "the CMK uuid in AWS and GCP, null otherwise." So the field is a UUID on AWS/GCP but `azureCmkAccessConnectorId` is an Azure resource ID elsewhere — same conceptual ID, two formats, no unifying name. -#### 17.5 `azureKeyVaultKeyId` (model.ts:257) +#### 14.5 `azureKeyVaultKeyId` (model.ts:257) Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See -§6.2. +§5.2. -#### 17.6 `created_at` / `updated_at` (model.ts:98, 102) +#### 14.6 `created_at` / `updated_at` (model.ts:98, 102) Type is `number` (epoch milliseconds). Conventional, but the field name doesn't convey unit. Pairs `createdAtMs` or `createdAtEpochMs` would be more honest. -#### 17.7 `lastFailoverTimeMs` (model.ts:237) +#### 14.7 `lastFailoverTimeMs` (model.ts:237) Counter-example: this field correctly includes the `Ms` unit suffix. Demonstrates that the codebase *can* express units in names — the other timestamps simply don't. --- -### 18. Type-suffix tautology +### 15. Type-suffix tautology -#### 18.1 `SecurableType` enum with field `securableType: SecurableType` +#### 15.1 `SecurableType` enum with field `securableType: SecurableType` (model.ts:28, 117, 192, 356) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 18.2 `CatalogType` enum with field `catalogType: CatalogType` +#### 15.2 `CatalogType` enum with field `catalogType: CatalogType` (model.ts:12, 84, 159, 323) — same pattern. -#### 18.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` +#### 15.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` (model.ts:5, 108, 183, 347) — field-name shortened, type-name keeps the prefix. Reasonable. -#### 18.4 `DrReplicationStatus` enum with field `status: DrReplicationStatus` +#### 15.4 `DrReplicationStatus` enum with field `status: DrReplicationStatus` (model.ts:21, 229) — generic field name (`status`) on a typed value. Either expand the field (`drReplicationStatus`) or shorten the type (`ReplicationStatus`). -#### 18.5 `…Info` types with `…info` fields +#### 15.5 `…Info` types with `…info` fields - `provisioningInfo: ProvisioningInfo` - `conversionInfo: ConversionInfo` - `drReplicationInfo: DrReplicationInfo` @@ -496,6 +404,15 @@ completeness. --- +### 16. Bare `Client` class name (client.ts:44) +`Client` (rather than `CatalogsClient`) is a Go-idiom: package qualifies +the type. JS consumers commonly import as +`import {Client} from '@databricks/sdk-catalogs/v1'` and have to alias. +This is a package-wide convention, but worth flagging in this audit +for consistency with the broader review. + +--- + ## Additional / cross-cutting observations ### A. `flattenQueryParams` is defined but unused (utils.ts:123) @@ -517,73 +434,56 @@ a non-optional type or a typed assertion. "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### D. `index.ts` re-exports proto-style names verbatim (lines 10, 11, 17, 18, 21, 22, 24, 30, 33, 34) -Every underscore-bearing identifier surfaces in the package's public -API. A consumer of `@databricks/sdk-catalogs/v1` sees -`ConversionInfo_State`, `DeleteCatalog_Response`, -`CatalogInfo_OptionsEntry`, etc. as first-class exports. This is the -single highest-leverage place to clean naming. - --- ## File / line index for fast lookup | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | -| `CatalogIsolationMode` | model.ts:5 | 18.3 | -| `CatalogType` | model.ts:12 | 2.4, 16.1, 18.2 | +| `CatalogIsolationMode` | model.ts:5 | 15.3 | +| `CatalogType` | model.ts:12 | 2.2, 13.1, 15.2 | | `CatalogType.DELTASHARING_CATALOG` | model.ts:14 | 3.4 | -| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:18 | 16.1 | -| `DrReplicationStatus` | model.ts:21 | 2.1, 3.1, 16.2 | -| `SecurableType` | model.ts:28 | 18.1 | +| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:18 | 13.1 | +| `DrReplicationStatus` | model.ts:21 | 2.1, 3.1, 13.2 | +| `SecurableType` | model.ts:28 | 15.1 | | `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:46 | — | -| `ConversionInfo_State` | model.ts:50 | 2.2, 4.1, 12.1, 16.3 | -| `ProvisioningInfo_State` | model.ts:57 | 2.3, 4.2, 12.1, 16.4 | -| `AzureEncryptionSettings` | model.ts:67 | 3.2, 17.2 | -| `CatalogInfo` | model.ts:73 | 8.1 | -| `CatalogInfo.options` / `.properties` | model.ts:127, 125 | 6.5, 9.1, 10.1, 13.5 | -| `CatalogInfo.fullName` | model.ts:116 | 6.4, 10.2 | -| `CatalogInfo.securableType` | model.ts:117 | 10.4, 18.1 | -| `CatalogInfo_OptionsEntry` | model.ts:131 | 1.2, 4.3 | -| `CatalogInfo_PropertiesEntry` | model.ts:137 | 1.2, 4.3 | -| `ConversionInfo` | model.ts:143 | 1.4, 8.1 | -| `CreateCatalog` | model.ts:148 | 10.5, 14.2 | -| `CreateCatalog_OptionsEntry/PropertiesEntry` | model.ts:206, 212 | 4.4 | -| `DeleteCatalog.nameArg` | model.ts:219 | 5.1, 12.3, 14.3 | -| `DeleteCatalog_Response` | model.ts:225 | 4.6 | -| `DrReplicationInfo` | model.ts:228 | 3.1, 8.1 | -| `DrReplicationInfo.replicatedEntities` | model.ts:231 | 1.3, 6.3 | -| `DrReplicationInfo.lastFailoverTimeMs` | model.ts:237 | 17.7 (positive) | -| `EffectivePredictiveOptimizationFlag` | model.ts:240 | 7.1, 8.3 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:242 | 1.1, 6.1, 9.3, 13.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:244 | 1.5 | -| `EncryptionSettings` | model.ts:253 | 8.2 | -| `EncryptionSettings.customerManagedKeyId` | model.ts:255 | 3.2, 17.4 | -| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:257 | 3.3, 6.2, 17.5 | -| `EncryptionSettings.azureEncryptionSettings` | model.ts:259 | 6.6, 14.4 | -| `GetCatalog.nameArg` | model.ts:264 | 5.1, 12.3 | +| `AzureEncryptionSettings` | model.ts:67 | 3.2, 14.2 | +| `CatalogInfo` | model.ts:73 | 7.1 | +| `CatalogInfo.options` / `.properties` | model.ts:127, 125 | 5.5, 8.1, 9.1 | +| `CatalogInfo.fullName` | model.ts:116 | 5.4, 9.2 | +| `CatalogInfo.securableType` | model.ts:117 | 9.4, 15.1 | +| `ConversionInfo` | model.ts:143 | 1.3, 7.1 | +| `CreateCatalog` | model.ts:148 | 9.5, 11.2 | +| `DeleteCatalog.nameArg` | model.ts:219 | 4.1, 11.3 | +| `DrReplicationInfo` | model.ts:228 | 3.1, 7.1 | +| `DrReplicationInfo.replicatedEntities` | model.ts:231 | 1.2, 5.3 | +| `DrReplicationInfo.lastFailoverTimeMs` | model.ts:237 | 14.7 (positive) | +| `EffectivePredictiveOptimizationFlag` | model.ts:240 | 6.1, 7.3 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:242 | 1.1, 5.1, 8.3 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:244 | 1.4 | +| `EncryptionSettings` | model.ts:253 | 7.2 | +| `EncryptionSettings.customerManagedKeyId` | model.ts:255 | 3.2, 14.4 | +| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:257 | 3.3, 5.2, 14.5 | +| `EncryptionSettings.azureEncryptionSettings` | model.ts:259 | 5.6, 11.4 | +| `GetCatalog.nameArg` | model.ts:264 | 4.1 | | `ListCatalogs.maxResults` | model.ts:281 | — | | `ListCatalogs.pageToken` | model.ts:283 | — | | `ListCatalogs.includeUnbound` | model.ts:288 | — | -| `ListCatalogs_Response` | model.ts:292 | 4.7 | -| `ProvisioningInfo` | model.ts:303 | 1.4, 8.1 | -| `UpdateCatalog.nameArg/newName/name` | model.ts:310-314 | 5.1, 10.3, 14.1 | -| `UpdateCatalog_OptionsEntry/PropertiesEntry` | model.ts:370, 376 | 4.5 | -| `Client` (bare name) | client.ts:44 | 12.2 | +| `ProvisioningInfo` | model.ts:303 | 1.3, 7.1 | +| `UpdateCatalog.nameArg/newName/name` | model.ts:310-314 | 4.1, 9.3, 11.1 | +| `Client` (bare name) | client.ts:44 | 16 | | `${req.nameArg ?? ''}` URL substitution | client.ts:100,134,235 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `index.ts` re-exports | index.ts:5-35 | D | --- ## Recommended priority order -1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalog`** — biggest user-facing trap. (§14.1, §5.1) -2. **Strip `STATE_` / `DR_REPLICATION_STATUS_` / `_CATALOG` redundant prefixes from enum values.** (§2.1, §2.2, §2.3, §2.4) -3. **Drop proto-style `Parent_Child` identifiers** (`ConversionInfo_State`, `DeleteCatalog_Response`, `ListCatalogs_Response`, `*_OptionsEntry`, `*_PropertiesEntry`). (§4) -4. **Distinguish or merge `options` and `properties`.** (§10.1) -5. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§3.3, §6.2) -6. **Strip read-only fields from `CreateCatalog`/`UpdateCatalog`.** (§14.2) -7. **Decide CMK casing and apply uniformly.** (§3.2, §17.4) -8. **Rename `replicatedEntities` to reflect that it's a byte blob.** (§1.3) -9. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalog`** — biggest user-facing trap. (§11.1, §4.1) +2. **Strip `DR_REPLICATION_STATUS_` / `_CATALOG` redundant prefixes from enum values.** (§2.1, §2.2) +3. **Distinguish or merge `options` and `properties`.** (§9.1) +4. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§3.3, §5.2) +5. **Strip read-only fields from `CreateCatalog`/`UpdateCatalog`.** (§11.2) +6. **Decide CMK casing and apply uniformly.** (§3.2, §14.4) +7. **Rename `replicatedEntities` to reflect that it's a byte blob.** (§1.2) +8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md index 6888d05d..ca44de92 100644 --- a/.agent/naming-audit/cleanroomassets.md +++ b/.agent/naming-audit/cleanroomassets.md @@ -18,13 +18,13 @@ cleanroom packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules | # | Category | Count | | -- | ----------------------------------------- | ----- | | 1 | Vague / generic names | 7 | -| 2 | Redundant enum prefixes | 5 | +| 2 | Redundant enum prefixes | 4 | | 3 | Acronym casing inconsistencies | 0 | -| 4 | Underscores in TS identifiers | 17 | +| 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 2 | | 6 | Misleading names | 3 | -| 7 | Overly verbose names | 6 | -| 8 | Redundant suffixes | 2 | +| 7 | Overly verbose names | 5 | +| 8 | Redundant suffixes | 0 | | 9 | Singular / plural mismatches | 2 | | 10 | Reserved-word / built-in collisions | 1 | | 11 | Empty / trivial wrapper types | 0 | @@ -36,9 +36,9 @@ cleanroom packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules | 17 | Inconsistent action verbs | 1 | | 18 | Long enum values | 6 | | 19 | Underspecified IDs | 2 | -| 20 | Type-suffix tautology | 3 | +| 20 | Type-suffix tautology | 1 | | -- | Cross-cutting: `CleanRoom` redundancy | 1 | -| -- | **Total findings** | **71** | +| -- | **Total findings** | **48** | --- @@ -115,17 +115,13 @@ the suffix (`NotebookReviewState`). Suggested rename: `UNSPECIFIED`. Five words of prefix on a single literal. Suggested rename: `UNSPECIFIED`. -### 2.5 `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` (model.ts:69) - -Members `EQUAL` / `LIKE` are fine; the enum *name* repeats `Partition` three -times and `PartitionValue` twice (see 7.1). Members themselves are not -redundant. - --- ## 3. Acronym casing inconsistencies -None found. `etag` (lower-case in model.ts:194, 370, 410) is consistently +_None._ + +`etag` (lower-case in model.ts:194, 370, 410) is consistently lower-cased everywhere; `Json` is title-case in `typeJson` (model.ts:282) and appears nowhere else as `JSON`. `UDF` and `SQL` appear only in JSDoc prose, not in identifiers. `URL` appears only in helper variable names inside `client.ts` @@ -135,38 +131,12 @@ in identifiers. `URL` appears only in helper variable names inside `client.ts` ## 4. Underscores in TS identifiers -The proto-style `_` segregator is suppressed with explicit -`@typescript-eslint/naming-convention` exemptions. While this preserves -parity with the Go SDK, every such name is an underscore-in-identifier -violation by TypeScript conventions ([TypeScript Handbook — Names use camelCase -or PascalCase](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html)). -The following identifiers should be reviewed at the porting layer: - -| # | Identifier | File:line | -| ----- | -------------------------------------------------------------------------------- | ------------------ | -| 4.1 | `CleanRoomAsset_AssetType` | model.ts:36 | -| 4.2 | `CleanRoomAsset_Status_Enum` | model.ts:46 | -| 4.3 | `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | -| 4.4 | `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | -| 4.5 | `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | -| 4.6 | `CleanRoomAsset_ForeignTable` | model.ts:172 | -| 4.7 | `CleanRoomAsset_ForeignTableLocalDetails` | model.ts:178 | -| 4.8 | `CleanRoomAsset_Notebook` | model.ts:187 | -| 4.9 | `CleanRoomAsset_Status` | model.ts:211 | -| 4.10 | `CleanRoomAsset_Table` | model.ts:214 | -| 4.11 | `CleanRoomAsset_TableLocalDetails` | model.ts:220 | -| 4.12 | `CleanRoomAsset_View` | model.ts:231 | -| 4.13 | `CleanRoomAsset_ViewLocalDetails` | model.ts:237 | -| 4.14 | `CleanRoomAsset_VolumeLocalDetails` | model.ts:246 | -| 4.15 | `PartitionSpecification_Partition` | model.ts:428 | -| 4.16 | `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | -| 4.17 | All proto `$case` discriminator values use camelCase (good), but underlying serialized fields use `snake_case` (e.g. `clean_room_name`, `notebook_review_state`) — fine for wire format, just calling out the boundary | model.ts:484+ | - -Suggested approach: drop the underscore and concatenate -(`CleanRoomAssetAssetType` → still ugly; `CleanRoomAssetTableLocalDetails` is -acceptable). Alternative: extract nested types under a namespace -(`namespace CleanRoomAsset { export interface Notebook {} }`), eliminating both -the underscore and the parent-name repetition. +_None._ + +The serialized wire format uses `snake_case` field names +(e.g. `clean_room_name`, `notebook_review_state`); this is intentional and +required for protocol compatibility, and remains scoped to schema bodies, not +TypeScript identifiers. --- @@ -213,50 +183,37 @@ only `EQUAL` / `LIKE` — those are not arithmetic *operators* but partition ## 7. Overly verbose names -### 7.1 `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` (model.ts:69) - -47-character enum name with `Partition`/`PartitionValue` repeated. Suggested -rename: `PartitionMatchOperator`. In a flattened namespace, the parent context -adds no value here. - -### 7.2 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator key (model.ts:330) +### 7.1 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator key (model.ts:330) The discriminated-union variant name *and* the inner property name are both `notebookReviewState`. Redundancy of `notebookReviewState` against the parent `reviewState` field could be elided. Suggested: `{$case: 'notebook', state: NotebookReviewState}`. -### 7.3 `runnerCollaboratorAliases` (model.ts:196) +### 7.2 `runnerCollaboratorAliases` (model.ts:196) Long composite, but accurate. Acceptable. -### 7.4 `reviewerCollaboratorAlias` (model.ts:256) +### 7.3 `reviewerCollaboratorAlias` (model.ts:256) Same. Acceptable. -### 7.5 `ownerCollaboratorAlias` (model.ts:98) +### 7.4 `ownerCollaboratorAlias` (model.ts:98) Same. Acceptable. -### 7.6 `recipientPropertyKey` (model.ts:446) +### 7.5 `recipientPropertyKey` (model.ts:446) Acceptable; needs the `recipient`/`property`/`key` qualifiers for accuracy. -(7.3–7.6 are kept under this category for completeness, but only flagged as +(7.2–7.5 are kept under this category for completeness, but only flagged as borderline — none should change.) --- ## 8. Redundant suffixes -### 8.1 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) - -`NotebookReview` is repeated immediately after the underscore. Suggested -rename: `CleanRoomNotebookReview_State`. - -### 8.2 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) - -Same redundancy. Suggested: `CleanRoomNotebookReview_SubReason`. +_None._ --- @@ -428,16 +385,7 @@ Suggested rename: `assetName` everywhere — eliminates the cross-reference. ## 20. Type-suffix tautology -### 20.1 `CleanRoomNotebookReview_NotebookReviewState` (model.ts:54) - -Enum *name* contains the type-suffix `State` while the parent already conveys -that this is the *state* of a notebook review. See 8.1. - -### 20.2 `CleanRoomNotebookReview_NotebookReviewSubReason` (model.ts:62) - -Same — `SubReason` is suffix-tautology with the parent's `Review`. - -### 20.3 `ColumnTypeName` (model.ts:5) +### 20.1 `ColumnTypeName` (model.ts:5) `TypeName` is *almost* tautology with `Column`; a column's type-name is just its *type*. Suggested rename: `ColumnType`. @@ -464,7 +412,7 @@ collapses naturally into the *package* boundary. Affected exports (all in `model.ts` and re-exported by `index.ts`): - `CleanRoomAsset` → `Asset` -- `CleanRoomAsset_AssetType` → `AssetType` (which is itself redundant; see 8/20) +- `CleanRoomAsset_AssetType` → `AssetType` - `CleanRoomAsset_Status` / `_Status_Enum` → `Status` / `StatusEnum` - `CleanRoomAsset_ForeignTable` / `_ForeignTableLocalDetails` → `ForeignTable` / `ForeignTableLocalDetails` @@ -473,8 +421,6 @@ Affected exports (all in `model.ts` and re-exported by `index.ts`): - `CleanRoomAsset_View` / `_ViewLocalDetails` → `View` / `ViewLocalDetails` - `CleanRoomAsset_VolumeLocalDetails` → `VolumeLocalDetails` - `CleanRoomNotebookReview` → `NotebookReview` -- `CleanRoomNotebookReview_NotebookReviewState` → `NotebookReview.State` -- `CleanRoomNotebookReview_NotebookReviewSubReason` → `NotebookReview.SubReason` - `CreateCleanRoomAssetRequest` → `CreateAssetRequest` (or just `CreateRequest`) - `CreateCleanRoomAssetReviewRequest` / `Response` → `CreateAssetReviewRequest` - `DeleteCleanRoomAssetRequest` / `Response` → `DeleteAssetRequest` @@ -499,23 +445,23 @@ If the codegen template can't drop the prefix everywhere uniformly, the | Symbol | File:line | Issues | | ------ | --------- | ------ | -| `ColumnTypeName` | model.ts:5 | 20.3 (TypeName tautology), 16.1 (`TABLE_TYPE` / `TABLEREF_TYPE` contradict domain) | +| `ColumnTypeName` | model.ts:5 | 20.1 (TypeName tautology), 16.1 (`TABLE_TYPE` / `TABLEREF_TYPE` contradict domain) | | `ColumnTypeName.BOOLEAN`..`GEOGRAPHY` | model.ts:6–28 | clean | | `ColumnTypeName.TABLE_TYPE` | model.ts:31 | 16.1 | | `ColumnTypeName.TABLEREF_TYPE` | model.ts:32 | 16.1, also redundant `_TYPE` suffix on a value inside `ColumnTypeName` | -| `CleanRoomAsset_AssetType` | model.ts:36 | 4.1, 20.x cross-cutting `CleanRoom` | +| `CleanRoomAsset_AssetType` | model.ts:36 | cross-cutting `CleanRoom` | | `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` | model.ts:37 | 2.1, 18.3 | | `CleanRoomAsset_AssetType.TABLE`..`FOREIGN_TABLE` | model.ts:38–42 | clean | | `CleanRoomAsset_Status_Enum` | model.ts:46 | cross-cutting | | `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` | model.ts:47 | 2.2, 18.4 | | `CleanRoomAsset_Status_Enum.ACTIVE`/`PERMISSION_DENIED`/`PENDING` | model.ts:48–50 | clean | -| `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | 8.1, 20.1, cross-cutting | +| `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | cross-cutting | | `…_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` | model.ts:55 | 2.3, 18.1 | | `…_NotebookReviewState.APPROVED`/`REJECTED`/`PENDING` | model.ts:56–58 | clean | -| `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | 8.2, 20.2, cross-cutting | +| `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | cross-cutting | | `…_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` | model.ts:63 | 2.4, 18.2 | | `…_NotebookReviewSubReason.BACKFILLED`/`AUTO_APPROVED` | model.ts:64–65 | clean | -| `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | 7.1 | +| `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | clean | | `…_PartitionValueOp.EQUAL`/`LIKE` | model.ts:70–71 | clean | ### Interfaces @@ -536,7 +482,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `CleanRoomAsset_ForeignTableLocalDetails.localName` | model.ts:183 | clean (would be `ownerLocalName` to match `localDetails` semantics) | | `CleanRoomAsset_Notebook.notebookContent` | model.ts:192 | redundant `notebook` prefix inside `…_Notebook` — `content` suffices | | `CleanRoomAsset_Notebook.etag` | model.ts:194 | 19.1 | -| `CleanRoomAsset_Notebook.runnerCollaboratorAliases` | model.ts:196 | clean (verbose 7.3, acceptable) | +| `CleanRoomAsset_Notebook.runnerCollaboratorAliases` | model.ts:196 | clean (verbose 7.2, acceptable) | | `CleanRoomAsset_Notebook.reviews` | model.ts:198 | clean | | `CleanRoomAsset_Notebook.reviewState` | model.ts:200 | clean | | `CleanRoomAsset_Notebook.description` | model.ts:202 | clean | @@ -548,7 +494,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `CleanRoomAsset_ViewLocalDetails.localName` | model.ts:242 | clean | | `CleanRoomAsset_VolumeLocalDetails.localName` | model.ts:251 | clean | | `CleanRoomNotebookReview` | model.ts:254 | cross-cutting | -| `CleanRoomNotebookReview.reviewerCollaboratorAlias` | model.ts:256 | clean (verbose 7.4) | +| `CleanRoomNotebookReview.reviewerCollaboratorAlias` | model.ts:256 | clean (verbose 7.3) | | `CleanRoomNotebookReview.createdAtMillis` | model.ts:258 | 13.1 | | `CleanRoomNotebookReview.reviewState` | model.ts:260 | clean | | `CleanRoomNotebookReview.comment` | model.ts:262 | 15.5 | @@ -556,7 +502,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `ColumnInfo` | model.ts:267 | clean | | `ColumnInfo.name` | model.ts:269 | 1.4, 15.2 | | `ColumnInfo.typeText` | model.ts:271 | clean | -| `ColumnInfo.typeName` | model.ts:272 | 20.3 (carries from enum) | +| `ColumnInfo.typeName` | model.ts:272 | 20.1 (carries from enum) | | `ColumnInfo.position` | model.ts:274 | clean | | `ColumnInfo.typePrecision` | model.ts:276 | clean | | `ColumnInfo.typeScale` | model.ts:278 | clean | @@ -579,7 +525,7 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `…ReviewRequest.review` | model.ts:320 | discriminated union with one variant (`notebookReview`); see 6.1 | | `CreateCleanRoomAssetReviewResponse` | model.ts:325 | cross-cutting | | `…ReviewResponse.notebookReviews` | model.ts:327 | clean | -| `…ReviewResponse.reviewState` | model.ts:328 | discriminated union with one variant (`notebookReviewState`); see 7.2 | +| `…ReviewResponse.reviewState` | model.ts:328 | discriminated union with one variant (`notebookReviewState`); see 7.1 | | `DeleteCleanRoomAssetRequest` | model.ts:337 | cross-cutting | | `…DeleteRequest.cleanRoomName`/`assetType`/`name` | model.ts:339–343 | 12.x, 19.2 | | `GetCleanRoomAssetRequest` / `…RevisionRequest` | model.ts:353, 362 | cross-cutting | @@ -593,10 +539,10 @@ If the codegen template can't drop the prefix everywhere uniformly, the | `NotebookVersionReview` | model.ts:408 | name reads like a noun-from-Go (Java-style); `NotebookReviewSubmission` or `PendingReview` would feel more native. Single-use in `CreateCleanRoomAssetReviewRequest.review.notebookReview` | | `NotebookVersionReview.etag`/`reviewState`/`comment` | model.ts:410–414 | 19.1, 15.5 | | `PartitionSpecification_Partition.values` | model.ts:430 | clean | -| `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | 4.x, 7.1 | +| `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | clean | | `…PartitionValue.name` | model.ts:436 | 1.5, 15.3 | | `…PartitionValue.value` | model.ts:441 | 1.6, 15.4 | -| `…PartitionValue.recipientPropertyKey` | model.ts:446 | clean (verbose 7.6) | +| `…PartitionValue.recipientPropertyKey` | model.ts:446 | clean (verbose 7.5) | | `…PartitionValue.op` | model.ts:448 | 5.2, 6.3, 10.1 | | `PolicyFunctionArgument` | model.ts:457 | name "Argument" inside `PolicyFunction*` could be `PolicyFunctionArg` to align with field name `arg` (line 458) — currently inconsistent | | `PolicyFunctionArgument.arg` | model.ts:458 | abbreviation `arg` vs. parent `Argument`; pick one | @@ -633,15 +579,12 @@ Re-exports only. All concerns flow from `model.ts` / `client.ts`. or keep it in the canonical `model.ts` and provide unprefixed aliases in `index.ts`. Pick one. (Cross-cutting redundancy is the single biggest source of name length.) -2. **Collapse proto-nested types under namespaces or rename without - underscores.** All 17 `_`-bearing identifiers should follow the same - convention as the rest of `@databricks/sdk-databricks`. -3. **Reconcile the `revisions: CleanRoomAsset[]` mismatch on +2. **Reconcile the `revisions: CleanRoomAsset[]` mismatch on `ListCleanRoomAssetRevisionsResponse`.** Either rename to `assets` or introduce a distinct revision type. -4. **Fix the `JAR_ANALYSIS` / `assetType` JSDoc discrepancy.** Either the +3. **Fix the `JAR_ANALYSIS` / `assetType` JSDoc discrepancy.** Either the enum is missing a value or the doc is stale. -5. **Strip the `_UNSPECIFIED` boilerplate prefixes** (`NOTEBOOK_REVIEW_STATE_…` +4. **Strip the `_UNSPECIFIED` boilerplate prefixes** (`NOTEBOOK_REVIEW_STATE_…` etc.) — six enum literals become two-word strings. -6. **Rename `op` → `operator` and `etag` → `revisionEtag`** in user-facing +5. **Rename `op` → `operator` and `etag` → `revisionEtag`** in user-facing request types. diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md index 4ee57a86..e89f7dee 100644 --- a/.agent/naming-audit/cleanroomautoapprovalrules.md +++ b/.agent/naming-audit/cleanroomautoapprovalrules.md @@ -118,17 +118,7 @@ shorter `create`, `get`, `list`, `listIter`, `update`, `delete` (or the AWS JS SDK v3 uses `Send` of a single-purpose command rather than a verbose method name). -### 3. Enum name doubles up on its parent type — Category 2 (redundant enum prefix) / Category 14 (Go/Java-style names) - -`CleanRoomAutoApprovalRule_AuthorScope` carries the parent interface name -plus `CleanRoom` and `AutoApproval`. In TypeScript, the enum is referenced -as a top-level export from `model.ts` and re-exported from `index.ts`. It -does not need the parent-type prefix; `AuthorScope` (or, if disambiguation -is desired, `RuleAuthorScope`) is sufficient. The proto-style underscore -join already required disabling -`@typescript-eslint/naming-convention` (`model.ts:5`), which is a smell. - -### 4. Enum members repeat the enum name — Category 2 (redundant enum prefix) / Category 18 (long enum values) +### 3. Enum members repeat the enum name — Category 2 (redundant enum prefix) / Category 18 (long enum values) ```typescript export enum CleanRoomAutoApprovalRule_AuthorScope { @@ -144,7 +134,7 @@ within `AuthorScope` matters); when used at call sites they read `AuthorScope.UNSPECIFIED` / `AuthorScope.ANY`, which is clearer than `AuthorScope.AUTHOR_SCOPE_UNSPECIFIED`. -### 5. `AUTHOR_SCOPE_UNSPECIFIED` is a leaked-protobuf sentinel — Category 14 (Go/Java-style names) +### 4. `AUTHOR_SCOPE_UNSPECIFIED` is a leaked-protobuf sentinel — Category 14 (Go/Java-style names) The presence of an `_UNSPECIFIED` member is a protobuf-3 convention (every enum must have a `0` value). It has no meaning in JS — passing @@ -153,7 +143,7 @@ it from the public surface or document explicitly that it is a wire-only default no caller should pass. As written, IntelliSense advertises it as a real value alongside `ANY_AUTHOR`. -### 6. Discriminator-tag value duplicates the field name — Category 12 (duplicate concepts) +### 5. Discriminator-tag value duplicates the field name — Category 12 (duplicate concepts) ```typescript authors?: @@ -172,11 +162,11 @@ authors?: ``` This is at least a consistency concern: the field name `authors` is plural, -but the discriminant talks about a single author. (See finding 7.) The +but the discriminant talks about a single author. (See finding 6.) The inner `author` prefix is also redundant once the parent field is already named `authors`. -### 7. `authors` / `runners` are misleading plurals on a single-author/runner union — Category 9 (singular/plural mismatches) / Category 6 (misleading names) +### 6. `authors` / `runners` are misleading plurals on a single-author/runner union — Category 9 (singular/plural mismatches) / Category 6 (misleading names) The field types only ever carry one author or one runner per rule: @@ -189,13 +179,13 @@ The plural names imply a list. Reasonable singular alternatives: `author` and `runner`. If the intent is to keep the proto's `oneof` group name, document it; otherwise the plural reads as a bug. -### 8. `runnerCollaboratorAlias` doubles `runner` — Category 8 (redundant suffix) / Category 12 (duplicate concepts) +### 7. `runnerCollaboratorAlias` doubles `runner` — Category 8 (redundant suffix) / Category 12 (duplicate concepts) -Combined with finding 6, the variant's payload key restates the discriminant: +Combined with finding 5, the variant's payload key restates the discriminant: `{ $case: 'runnerCollaboratorAlias'; runnerCollaboratorAlias: string }`. Once inside the variant, just `value` or `alias` would do. -### 9. `ruleOwnerCollaboratorAlias` / `authorCollaboratorAlias` / `runnerCollaboratorAlias` — Category 7 (overly verbose) / Category 5 (cryptic abbreviation) +### 8. `ruleOwnerCollaboratorAlias` / `authorCollaboratorAlias` / `runnerCollaboratorAlias` — Category 7 (overly verbose) / Category 5 (cryptic abbreviation) Three different fields encode "this string is a collaborator alias". Two options: @@ -209,7 +199,7 @@ options: "alias" by itself is also a slightly cryptic term outside the clean-rooms context; a JSDoc note explaining it identifies a collaborator would help. -### 10. `ruleId` is underspecified — Category 19 (underspecified ID) +### 9. `ruleId` is underspecified — Category 19 (underspecified ID) Every `ruleId` in `Delete/Get/UpdateCleanRoomAutoApprovalRuleRequest` is just `string`. The comment on `CleanRoomAutoApprovalRule.ruleId` says "A generated @@ -218,7 +208,7 @@ JSDoc tag, or zod schema validating UUID format) or the doc should be elsewhere. Today every callsite has to know via documentation that it is a UUID, not an arbitrary string. -### 11. `Client` is a generic class name — Category 1 (vague/generic) +### 10. `Client` is a generic class name — Category 1 (vague/generic) `Client` collides conceptually with the `Client` in every other API package (`@databricks/sdk-cleanrooms/v1` also exports `Client`, etc.). Inside a @@ -235,7 +225,7 @@ export a more specific name (`AutoApprovalRulesClient`, `CleanRoomAutoApprovalRulesClient`). Either way, this is a *package-wide* decision; this audit just flags that the bare `Client` name is generic. -### 12. `nextPageToken` / `pageToken` are duplicated across the response and request — Category 12 (duplicate concepts) [informational] +### 11. `nextPageToken` / `pageToken` are duplicated across the response and request — Category 12 (duplicate concepts) [informational] `ListCleanRoomAutoApprovalRulesResponse.nextPageToken` and `ListCleanRoomAutoApprovalRulesRequest.pageToken` are wire-mandated and @@ -243,7 +233,7 @@ match the Databricks pagination convention. This is *not* a finding to act on — it is the standard pagination shape used across all packages. Logged for completeness because the prompt asks for an exhaustive scan. -### 13. Doc references undefined casing — Category 16 (field contradicting type domain) [minor] +### 12. Doc references undefined casing — Category 16 (field contradicting type domain) [minor] The JSDoc on `authorCollaboratorAlias` says: @@ -260,21 +250,21 @@ arm of `authors` should be populated"). Same issue on line 25 of `ListCleanRoomAutoApprovalRulesResponse.nextPageToken` says "`page_token` should be set", which should read `pageToken`. -### 14. Docs say "a auto-approval rule" — typo (not naming, but on JSDoc) [minor] +### 13. Docs say "a auto-approval rule" — typo (not naming, but on JSDoc) [minor] `client.ts:96`, `client.ts:115`, `client.ts:194` use `Delete a auto-approval`, `Get a auto-approval`, `Update a auto-approval`. The article should be `an`. This is generated text; flag it for the generator. Not strictly a naming issue, but it sits in the same area. -### 15. `Client` constructor field `userAgent` — Category 1 (vague) [minor] +### 14. `Client` constructor field `userAgent` — Category 1 (vague) [minor] `private readonly userAgent: string` (`client.ts:49`) holds the *value* of the `User-Agent` header. The name reads as a thing rather than a header value. `userAgentHeader` or `userAgentValue` is unambiguous. Minor — the JSDoc above the field explains it — but consistent with the audit's brief. -### 16. `utils.ts` is a kitchen-sink module name — Category 1 (vague/generic) +### 15. `utils.ts` is a kitchen-sink module name — Category 1 (vague/generic) The package's internal helpers all live in a single `utils.ts`. Per the SDK's existing breakdown (see `@databricks/sdk-core/api`, `.../apierror`, @@ -283,7 +273,7 @@ module (e.g., `http.ts`, `request.ts`). All sibling API packages emit the same `utils.ts`, so this is a generator-level concern, not a per-package one. Flagged because the brief asks about generic names. -### 17. Method docstrings use "rule ID" inconsistently with field name — Category 6 (misleading names) [minor] +### 16. Method docstrings use "rule ID" inconsistently with field name — Category 6 (misleading names) [minor] JSDocs say "Delete a auto-approval rule by rule ID", "Get a auto-approval rule by rule ID", "Update a auto-approval rule by rule ID". The request @@ -291,7 +281,7 @@ fields are `ruleId` (camelCase). A reader scanning the docs sees "rule ID" and may search for a field called "rule ID" or "ID". Either keep "ruleId" verbatim in the prose or just say "by ID". -### 18. `cleanRoomName` is the identifier doing double duty — Category 19 (underspecified ID) [minor] +### 17. `cleanRoomName` is the identifier doing double duty — Category 19 (underspecified ID) [minor] The path identifier is the `cleanRoomName` (a URL segment). In other packages this is sometimes `cleanRoomId` (UUID) or a `metastoreId`. Here it @@ -299,30 +289,30 @@ is consistently a name. The doc on `CleanRoomAutoApprovalRule.cleanRoomName` is clear, but the field type is `string`, so there is nothing stopping a caller from passing the UUID by mistake. A type-aliased name (`CleanRoomName`) would help. Same flag as -finding 10. +finding 9. --- ## Themes / suggested resolution priority 1. **Verbosity from the package name leaking into every symbol.** Findings - 1, 2, 3, 4. This is the dominant issue: `CleanRoomAutoApproval` + 1, 2, 3. This is the dominant issue: `CleanRoomAutoApproval` appears in every type and method name even though it is already in the package import path. Strip the prefix and the surface area becomes about half as wide on screen. -2. **Proto/Go ergonomics surfacing in TS.** Findings 3, 4, 5, 6. - `_`-joined enum names and `_UNSPECIFIED` sentinels are conventions - imported from protobuf/Go that have no payoff in TypeScript. -3. **Field-name ambiguity around identifiers and aliases.** Findings 7, 8, - 9, 10, 18. `authors`/`runners` are plural but always single; +2. **Proto/Go ergonomics surfacing in TS.** Findings 3, 4, 5. + `_UNSPECIFIED` sentinels and redundant enum-member prefixes are + conventions imported from protobuf/Go that have no payoff in TypeScript. +3. **Field-name ambiguity around identifiers and aliases.** Findings 6, 7, + 8, 9, 17. `authors`/`runners` are plural but always single; collaborator aliases are typed `string`; `ruleId` is a UUID typed `string`. Type aliases plus singular field names would cover all of these. -4. **Doc/identifier drift from the wire format.** Findings 13, 14, 17. JSDoc +4. **Doc/identifier drift from the wire format.** Findings 12, 13, 16. JSDoc text references `snake_case` field names and includes generated-text typos. These are docs-only fixes but they bear on naming clarity. 5. **Module-shape concerns** (only logged for awareness because the prompt - asked for an exhaustive sweep): findings 11, 15, 16. + asked for an exhaustive sweep): findings 10, 14, 15. --- @@ -333,6 +323,3 @@ finding 10. a package-shape decision, not a naming one. - Wire-format names (`page_token`, `next_page_token`, `clean_room_name`, etc.). These are dictated by the API and not part of the TS surface. -- The `_` underscore in `CleanRoomAutoApprovalRule_AuthorScope` is already - documented (and explicitly lint-disabled) as a proto-style nested enum - name; the *suffix* portion (`AuthorScope`) is what finding 3 targets. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index 8202bb23..7c0eeffc 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -12,19 +12,16 @@ grouped by category, and each finding cites the file/line where it appears. ## Summary -- **Total findings:** 49 +- **Total findings:** 30 - **Highest-impact themes:** - 1. Proto-style nested enum/message names with embedded underscores - (`CleanRoom_Status_Enum`, - `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol`, - etc.) violate TS identifier conventions and produce extremely long, - unreadable identifiers. - 2. Massive redundant enum-prefix tautology + 1. Massive redundant enum-prefix tautology (`INTERNET_DESTINATION_TYPE_UNSPECIFIED`, `LOG_ONLY_MODE_TYPE_UNSPECIFIED`, `OUTPUT_CATALOG_STATUS_UNSPECIFIED`, …) — each enum member repeats the enum-name domain. - 3. Several field names use vague or generic terms (`type`, `protocol`, + 2. Several field names use vague or generic terms (`type`, `protocol`, `name`, `destination`, `status`) that lose meaning out of context. + 3. Misleading field names (`remoteDetailedInfo`, boolean-shaped + `accessRestricted` enum, predicate-form `enableSharedOutput`). --- @@ -68,7 +65,7 @@ ambiguity is worth noting — `cloudRegion` / `bucketRegion` would disambiguate. ### 1.8 `workloads?: WorkloadType[]` (model.ts:325) On `LogOnlyMode`, the field `workloads` is plural-of-type. `workloadTypes` -would match the enum. (See also §9 — singular/plural mismatch.) +would match the enum. (See also §6 — singular/plural mismatch.) --- @@ -83,40 +80,37 @@ qualifier is already present at every call site. Should be `UNSPECIFIED`. Consumers write `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` which is doubly redundant. -### 2.2 `CleanRoom_Status_Enum.ENUM_UNSPECIFIED` (model.ts:62) -Should be `UNSPECIFIED`. The `_ENUM` re-suffix in both the type name **and** -the member compounds the redundancy. - -### 2.3 `CleanRoomOutputCatalog_OutputCatalogStatus.OUTPUT_CATALOG_STATUS_UNSPECIFIED` +### 2.2 `CleanRoomOutputCatalog_OutputCatalogStatus.OUTPUT_CATALOG_STATUS_UNSPECIFIED` (model.ts:71) Should be `UNSPECIFIED`. `OUTPUT_CATALOG_STATUS` is already in the enum name. -### 2.4 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol.INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED` +### 2.3 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol.INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED` (model.ts:88) -The enum name and the member share **the same 36-character substring**. +The enum member redundantly repeats the trailing +`INTERNET_DESTINATION_FILTERING_PROTOCOL` segment of the enum name. -### 2.5 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType.INTERNET_DESTINATION_TYPE_UNSPECIFIED` +### 2.4 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType.INTERNET_DESTINATION_TYPE_UNSPECIFIED` (model.ts:94) -Same pattern — full prefix tautology. +Same pattern — member repeats the `INTERNET_DESTINATION_TYPE` segment of +the enum name. -### 2.6 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType.LOG_ONLY_MODE_TYPE_UNSPECIFIED` +### 2.5 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType.LOG_ONLY_MODE_TYPE_UNSPECIFIED` (model.ts:100) Same pattern. -### 2.7 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_WorkloadType.WORKLOAD_TYPE_UNSPECIFIED` +### 2.6 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_WorkloadType.WORKLOAD_TYPE_UNSPECIFIED` (model.ts:108) Same pattern. -### 2.8 `EgressNetworkPolicy_InternetAccessPolicy_RestrictionMode.RESTRICTION_MODE_UNSPECIFIED` +### 2.7 `EgressNetworkPolicy_InternetAccessPolicy_RestrictionMode.RESTRICTION_MODE_UNSPECIFIED` (model.ts:122) Same pattern. -### 2.9 `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType.STORAGE_DESTINATION_TYPE_UNSPECIFIED` +### 2.8 `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType.STORAGE_DESTINATION_TYPE_UNSPECIFIED` (model.ts:130) Same pattern. -Cumulatively: every enum's `UNSPECIFIED` sentinel is redundantly prefixed, -and seven of nine enum types are nested-style names that compound the issue. +Cumulatively: every enum's `UNSPECIFIED` sentinel is redundantly prefixed. --- @@ -153,82 +147,40 @@ but worth noting the `_PROTECTED` suffix encodes a level — fine. --- -## 4. Underscores in TypeScript Identifiers - -TS naming conventions (`@typescript-eslint/naming-convention`) prohibit -underscores in type and member names. The file disables this rule globally -with `eslint-disable-next-line` for nine type definitions. - -### 4.1 `CleanRoom_AccessRestricted` (model.ts:55) -Snake-case-in-PascalCase identifier — Go/proto idiom, not TS idiom. - -### 4.2 `CleanRoom_Status_Enum` (model.ts:61) -Same. Triple-segment Go-style nested enum name. - -### 4.3 `CleanRoomOutputCatalog_OutputCatalogStatus` (model.ts:70) - -### 4.4 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` -(model.ts:87) — 86-character name with three underscores. - -### 4.5 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType` -(model.ts:93) - -### 4.6 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType` (model.ts:99) - -### 4.7 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_WorkloadType` (model.ts:107) - -### 4.8 `EgressNetworkPolicy_InternetAccessPolicy_RestrictionMode` (model.ts:121) - -### 4.9 `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType` -(model.ts:129) - -### 4.10 Interfaces (same pattern) -- `CleanRoom_Status` (model.ts:178) -- `EgressNetworkPolicy_InternetAccessPolicy` (model.ts:288) -- `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination` (model.ts:310) -- `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode` (model.ts:321) -- `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination` (model.ts:332) - -The underscore-bearing identifiers radiate from the model file into the -public re-exports in `index.ts` (lines 7–13, 20, 30–33), so the API surface -is contaminated. - ---- - -## 5. Cryptic Abbreviations +## 4. Cryptic Abbreviations -### 5.1 `K_FSI` (model.ts:42) +### 4.1 `K_FSI` (model.ts:42) Bare `K_FSI` is cryptic without the comment "Korea Financial Security Institute." See §3.5 above. -### 5.2 `ARC_AMPE` (model.ts:51) +### 4.2 `ARC_AMPE` (model.ts:51) "Acceptable Risk Controls for ACA, Medicaid, and Partner Entities" — five words compressed into eight characters. Without the doc-comment, opaque. -### 5.3 `ESC` in `ComplianceStandard.NONE` JSDoc (model.ts:11) +### 4.3 `ESC` in `ComplianceStandard.NONE` JSDoc (model.ts:11) Documentation acronym only — but ESC = Enhanced Security Compliance is unexplained at first reference. -### 5.4 `CSP` doc comment on `accessRestricted` (model.ts:166) +### 4.4 `CSP` doc comment on `accessRestricted` (model.ts:166) "CSP" abbreviation linked but not spelled. The enum constant `CSP_MISMATCH` (model.ts:57) also uses the bare acronym. -### 5.5 `FQDN` enum value (model.ts:95) +### 4.5 `FQDN` enum value (model.ts:95) "Fully Qualified Domain Name" — well-known enough in networking, OK. -### 5.6 `SEG`, `DP`, `UC`, `SNI` in JSDoc (model.ts:82, 117, 217) +### 4.6 `SEG`, `DP`, `UC`, `SNI` in JSDoc (model.ts:82, 117, 217) Doc-only abbreviations: SEG (Secure Egress Gateway?), DP (Data Plane?), UC (Unity Catalog), SNI (Server Name Indication). UC is well-established in this codebase; SEG/DP/SNI need expansion. -### 5.7 `DBSQL` (model.ts:109) +### 4.7 `DBSQL` (model.ts:109) "Databricks SQL" — familiar to Databricks customers, OK in context. --- -## 6. Misleading Names +## 5. Misleading Names -### 6.1 `remoteDetailedInfo` (model.ts:148) +### 5.1 `remoteDetailedInfo` (model.ts:148) Field name suggests "verbose info about a remote endpoint." Actually contains the central clean room state (collaborators, network policy, compliance) — the meaty payload of `CleanRoom`. JSON tag is @@ -236,37 +188,37 @@ compliance) — the meaty payload of `CleanRoom`. JSON tag is no "Info"). The name is **misleading** and **internally inconsistent with its type**: field says `remoteDetailedInfo`, type says `RemoteDetail`. -### 6.2 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:166) +### 5.2 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:166) Reads as a boolean ("is access restricted?"). It is actually an enum with values `NO_RESTRICTION` and `CSP_MISMATCH`. `accessRestrictedReason` or `accessRestriction` would not suggest a boolean. The JSDoc reinforces the miscommunication: "Whether clean room access is restricted…" — implying a yes/no. -### 6.3 `enableSharedOutput?: boolean` (model.ts:173) +### 5.3 `enableSharedOutput?: boolean` (model.ts:173) The verb `enable` reads as imperative/action. For a state field a participial/predicate name is clearer: `sharedOutputEnabled`. The JSDoc itself notes the field is slated for deprecation. -### 6.4 `isEnabled?: boolean` on `ComplianceSecurityProfile` (model.ts:252) +### 5.4 `isEnabled?: boolean` on `ComplianceSecurityProfile` (model.ts:252) The `is` prefix is acceptable, but inside an object literal one writes `profile.isEnabled` (reading "is enabled" of a non-question subject) which becomes awkward; simply `enabled` is more idiomatic and aligns with JavaScript norms (HTML `disabled`, `aria-disabled`, etc.). Note the inconsistency: `isEnabled` here vs. `enableSharedOutput` on `CleanRoom`. -### 6.5 `logOnlyMode?: ...LogOnlyMode` (model.ts:299) +### 5.5 `logOnlyMode?: ...LogOnlyMode` (model.ts:299) Field name and type name both have `LogOnlyMode`. But the field's container already declares "this is the LogOnlyMode submessage" — `logOnly` would suffice. -### 6.6 `localCollaboratorAlias?: string` (model.ts:159) vs. +### 5.6 `localCollaboratorAlias?: string` (model.ts:159) vs. `collaboratorAlias` on `CleanRoomCollaborator` (model.ts:206) The "local" prefix here is a fragment of metastore-domain jargon. A reader who does not already know about "single-metastore vs. x-metastore" clean rooms cannot tell what "local" means. -### 6.7 `CreateCleanRoomWaiter` class (client.ts:289) +### 5.7 `CreateCleanRoomWaiter` class (client.ts:289) The waiter polls `getCleanRoom` and resolves when status reaches `ACTIVE`. Naming it `CreateCleanRoomWaiter` ties it to `createCleanRoom`, but the waiter is operationally generic (any clean room name can be polled). A @@ -274,80 +226,33 @@ better name is `CleanRoomActivationWaiter` or `CleanRoomStatusWaiter`. --- -## 7. Overly Verbose Names - -### 7.1 Six of the nine enum type names exceed **50 characters** (model.ts:87–135). -Worst offenders: -- `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` - — **97** characters, by far the longest in the package. -- `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType` — 85. -- `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType` — 83. -- `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType` — 68. - -The same enums also have `UNSPECIFIED` members reaching 36 characters -(`INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED`). - -### 7.2 `CreateCleanRoomOutputCatalogResponse` (model.ts:263) / -`CreateCleanRoomOutputCatalogRequest` (model.ts:257) -36 characters each, but the underlying response body has a single field -(`outputCatalog`). Could be `OutputCatalogResponse` if the operation -context is unambiguous from the method signature. Probably keep — RPC -naming convention. - -### 7.3 `centralCleanRoomId?: string` (model.ts:228) -Inside `CleanRoomRemoteDetail`, the `central` adjective is redundant — the -type itself describes the central clean room. `id` would suffice (subject -to §1 generic-name caveat — perhaps `remoteId` if we keep the structure). - ---- - -## 8. Redundant Suffixes - -### 8.1 `_InternetDestinationFilteringProtocol` (model.ts:87) and -`_InternetDestinationType` (model.ts:93) -Both append `InternetDestination*` to a type whose Go-style nested path -already says `…_InternetDestination_…`. Pure repetition. - -### 8.2 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) -`LogOnlyMode` appears twice in the same identifier. Same for -`_StorageDestination_StorageDestinationType`. +## 6. Singular / Plural Mismatches -### 8.3 `complianceSecurityProfile?: ComplianceSecurityProfile` (model.ts:246) -Field name is identical to the type name — repetition but consistent with -the rest of the SDK style. (Mild — many ports do this.) - -### 8.4 `outputCatalog?: CleanRoomOutputCatalog` (model.ts:164, 260, 264) -Same field-name-equals-type pattern as §8.3. - ---- - -## 9. Singular / Plural Mismatches - -### 9.1 `workloads?: WorkloadType[]` (model.ts:325) +### 6.1 `workloads?: WorkloadType[]` (model.ts:325) Field is plural and array-typed, but the element type is **`WorkloadType`** (singular noun + `Type` suffix). Consumers write `mode.workloads[0]` which is a `WorkloadType` — readable, but the field could be `workloadTypes` to match the element. Alternative: rename the enum to `Workload`. -### 9.2 `cleanRooms?: CleanRoom[]` on `ListCleanRoomsResponse` (model.ts:357) +### 6.2 `cleanRooms?: CleanRoom[]` on `ListCleanRoomsResponse` (model.ts:357) Correctly plural — flagged only as a positive example. -### 9.3 `collaborators?: CleanRoomCollaborator[]` (model.ts:241) +### 6.3 `collaborators?: CleanRoomCollaborator[]` (model.ts:241) Correctly plural — positive example. -### 9.4 `complianceStandards?: ComplianceStandard[]` (model.ts:254) +### 6.4 `complianceStandards?: ComplianceStandard[]` (model.ts:254) Correctly plural. But `allowedInternetDestinations` and `allowedStorageDestinations` (model.ts:292, 295) inherit the `allowed` prefix; while the parent `restrictionMode` is singular. Mild inconsistency. -### 9.5 `allowedPaths?: string[]` (model.ts:339) +### 6.5 `allowedPaths?: string[]` (model.ts:339) Correctly plural. --- -## 10. Reserved-Word / Built-in Collisions +## 7. Reserved-Word / Built-in Collisions -### 10.1 `type` field on `InternetDestination` and `StorageDestination` +### 7.1 `type` field on `InternetDestination` and `StorageDestination` (model.ts:312, 335) `type` is not a reserved word in TS at field position, but it shadows the TS `typeof` semantics in conversation and may collide with linters that @@ -355,14 +260,14 @@ flag it. `kind` is the established alternative (tagged-union convention). Note: TypeScript's discriminated-union pattern often uses literal `type` — so this is a soft flag. -### 10.2 `status` field appears on `CleanRoom` and `CleanRoomOutputCatalog` -Not a reserved word; raised here to highlight the duplication. See §11. +### 7.2 `status` field appears on `CleanRoom` and `CleanRoomOutputCatalog` +Not a reserved word; raised here to highlight the duplication. See §8. --- -## 11. Duplicate Concepts +## 8. Duplicate Concepts -### 11.1 Two `Status` enums +### 8.1 Two `Status` enums - `CleanRoom.status: CleanRoom_Status_Enum` (model.ts:157) - `CleanRoomOutputCatalog.status: CleanRoomOutputCatalog_OutputCatalogStatus` (model.ts:216) @@ -371,7 +276,7 @@ Two distinct, non-overlapping `Status` enums. The two enum types should consider naming themselves unambiguously: `CleanRoomStatus`, `OutputCatalogStatus`. -### 11.2 `CleanRoomCollaborator` overlap with `cleanroomtaskruns.CollaboratorJobRunInfo` +### 8.2 `CleanRoomCollaborator` overlap with `cleanroomtaskruns.CollaboratorJobRunInfo` (cross-package) `cleanroomtaskruns/src/v1/model.ts` defines `CollaboratorJobRunInfo`. Both packages now have a "Collaborator-prefixed" surface; consumers must keep @@ -379,61 +284,39 @@ both straight. Not a rename target inside `cleanrooms`, but a cross-package risk: a third "collaborator" type in another package would make disambiguation tedious. -### 11.3 `creator?: CleanRoomCollaborator` (model.ts:243) vs. +### 8.3 `creator?: CleanRoomCollaborator` (model.ts:243) vs. `collaborators?: CleanRoomCollaborator[]` (model.ts:241) Per the JSDoc, `creator` is also **one of the collaborators in the collaborators list**. So we have the same logical entity reachable through two paths. Mild — not a renamed-target, but flagged as a shape concern. -### 11.4 `cleanRoomName` (model.ts:259) vs. `name` (model.ts:142, 273, 346, 367) +### 8.4 `cleanRoomName` (model.ts:259) vs. `name` (model.ts:142, 273, 346, 367) Two names for the same thing: the clean-room identifier. Picking one consistently would simplify call sites. --- -## 12. Verb-Tense Inconsistency +## 9. Verb-Tense Inconsistency -### 12.1 `enableSharedOutput` (verb, imperative) vs. `isEnabled` -(participle, predicate) — see §6.3 and §6.4 above. +### 9.1 `enableSharedOutput` (verb, imperative) vs. `isEnabled` +(participle, predicate) — see §5.3 and §5.4 above. -### 12.2 `accessRestricted` (participial, predicate) vs. -`CleanRoom_AccessRestricted` (the **enum** type name shares the predicate -form) (model.ts:55, 166) -Enums normally name a domain (`AccessRestriction`, `RestrictionReason`), -not a predicate. Reading `restriction: AccessRestricted = NO_RESTRICTION` -is semantically weird — "the access-restricted of this thing is no -restriction." - -### 12.3 Method verbs are consistent (create/get/list/update/delete) — +### 9.2 Method verbs are consistent (create/get/list/update/delete) — positive example. --- -## 13. Go / Java / Proto-Style Names in TS - -### 13.1 The nine `*_*_*` enum names and five `*_*_*` interface names -already enumerated in §4.1–§4.10 are direct Go/proto carryovers. The -`eslint-disable-next-line` comments explicitly acknowledge this with the -phrase "Proto-style nested enum name" / "Proto-style nested message name." -They are *the* defining stylistic deviation of this file. - -### 13.2 `CreateCleanRoomWaiter` (client.ts:289) -"Waiter" is the Go SDK convention; in TS, `Poller` / `Watcher` / -`Operation` (Azure-style) are more idiomatic. Inherited convention. - ---- - -## 14. Generic Field Names Losing Meaning Out of Context +## 10. Generic Field Names Losing Meaning Out of Context -### 14.1 `destination`, `type`, `protocol` on `InternetDestination` +### 10.1 `destination`, `type`, `protocol` on `InternetDestination` (model.ts:311–315) Read in isolation, these are completely opaque. Cross-reference §1.3–§1.6. -### 14.2 `name`, `comment`, `owner` on `CleanRoom` (model.ts:142, 151, 150) +### 10.2 `name`, `comment`, `owner` on `CleanRoom` (model.ts:142, 151, 150) `owner` is a username string; `comment` is a free-text description; `name` is a UC securable identifier. None of these self-describe. -### 14.3 `bucketName`, `region`, `type`, `azureStorageAccount`, +### 10.3 `bucketName`, `region`, `type`, `azureStorageAccount`, `allowedPaths`, `azureStorageService`, `azureDnsZone`, `azureContainer` on `StorageDestination` (model.ts:333–343) The same struct mixes AWS-, Azure-, and GCP-shaped fields. `bucketName` @@ -444,26 +327,26 @@ field naming inconsistently. --- -## 15. Field Contradicting Type Domain +## 11. Field Contradicting Type Domain -### 15.1 `CleanRoomRemoteDetail.region: string` (model.ts:232) +### 11.1 `CleanRoomRemoteDetail.region: string` (model.ts:232) Type is `string`, but the domain is "a cloud region identifier (`us-east-1`, `westeurope`, etc.)" — the type should be a tagged-string or a region enum. Minor. -### 15.2 `cloudVendor: string` (model.ts:230) +### 11.2 `cloudVendor: string` (model.ts:230) Same — should be an enum (the cloud SDK packages already have one). -### 15.3 `enableSharedOutput` (boolean) vs. the JSDoc "shared output PrPr" +### 11.3 `enableSharedOutput` (boolean) vs. the JSDoc "shared output PrPr" (private preview) — the field is a feature flag fronted as a permanent API, not labelled `experimental` (model.ts:173). Minor. -### 15.4 `createdAt`, `updatedAt: number` (model.ts:153, 155) +### 11.4 `createdAt`, `updatedAt: number` (model.ts:153, 155) Stored as **epoch milliseconds** per JSDoc but typed as `number` rather than a branded `EpochMillis` or `Timestamp`. Loses semantic information in the type system. (Repo-wide pattern; flag once.) -### 15.5 `inviteRecipientWorkspaceId: number` (model.ts:194) +### 11.5 `inviteRecipientWorkspaceId: number` (model.ts:194) Workspace IDs are int64 in Databricks; TS `number` is 53-bit. Latent precision loss for IDs above 2^53. The proto schema would use int64. Not a naming concern, but the field name does not warn (e.g., @@ -471,13 +354,13 @@ a naming concern, but the field name does not warn (e.g., --- -## 16. Inconsistent Action Verbs +## 12. Inconsistent Action Verbs The five RPC methods follow the standard CRUD verbs: `createCleanRoom`, `createCleanRoomOutputCatalog`, `deleteCleanRoom`, `getCleanRoom`, `listCleanRooms`, `updateCleanRoom`. -### 16.1 `createCleanRoom` returns the new clean room (client.ts:85); +### 12.1 `createCleanRoom` returns the new clean room (client.ts:85); `createCleanRoomOutputCatalog` returns a **response wrapper** (`CreateCleanRoomOutputCatalogResponse`) (client.ts:122). Inconsistent return shapes for two `create*` methods. The Go SDK has the @@ -487,69 +370,29 @@ same wart, but it surfaces here as inconsistent ergonomics: --- -## 17. Long Enum Values - -In addition to the prefix-redundant `UNSPECIFIED` values enumerated in §2: - -### 17.1 `COMPLIANCE_STANDARD_UNSPECIFIED` (model.ts:8) — 31 chars -### 17.2 `OUTPUT_CATALOG_STATUS_UNSPECIFIED` (model.ts:71) — 33 chars -### 17.3 `INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED` (model.ts:88) — 51 chars -### 17.4 `INTERNET_DESTINATION_TYPE_UNSPECIFIED` (model.ts:94) — 37 chars -### 17.5 `LOG_ONLY_MODE_TYPE_UNSPECIFIED` (model.ts:100) — 30 chars -### 17.6 `STORAGE_DESTINATION_TYPE_UNSPECIFIED` (model.ts:130) — 36 chars -### 17.7 `RESTRICTION_MODE_UNSPECIFIED` (model.ts:122) — 28 chars -### 17.8 `WORKLOAD_TYPE_UNSPECIFIED` (model.ts:108) — 25 chars -### 17.9 `GOOGLE_CLOUD_STORAGE` (model.ts:134) — 20 chars -(Reasonable for the data being modeled.) - -The cumulative cost is that switch-statements and equality checks on -these enums consume wide lines, e.g., -`EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType.LOG_ONLY_MODE_TYPE_UNSPECIFIED` -is **97** characters — exceeding the project's 90-char line limit -on its own. - ---- - -## 18. Underspecified IDs +## 13. Underspecified IDs -### 18.1 `centralCleanRoomId?: string` (model.ts:228) +### 13.1 `centralCleanRoomId?: string` (model.ts:228) String ID — no JSDoc explanation of format (UUID? Numeric? Free-form?). Per JSDoc on `globalMetastoreId`: "cloud:region:metastore-uuid" — at least that one is documented. -### 18.2 `globalMetastoreId?: string` (model.ts:183) — Documented; positive example. +### 13.2 `globalMetastoreId?: string` (model.ts:183) — Documented; positive example. -### 18.3 `inviteRecipientWorkspaceId?: number` (model.ts:194) -ID typed as `number` and undocumented format — see §15.5 on precision risk. +### 13.3 `inviteRecipientWorkspaceId?: number` (model.ts:194) +ID typed as `number` and undocumented format — see §11.5 on precision risk. -### 18.4 `bucketName?: string` (model.ts:333) +### 13.4 `bucketName?: string` (model.ts:333) Bucket name vs. ARN vs. URI — not specified. Could be S3 bucket name or GCS bucket name; both share the field. -### 18.5 `azureStorageAccount?: string` (model.ts:338), +### 13.5 `azureStorageAccount?: string` (model.ts:338), `azureStorageService?: string` (model.ts:340), `azureContainer?: string` (model.ts:342) Three Azure identifiers, no JSDoc explaining accepted formats. --- -## 19. Type-Suffix Tautology - -### 19.1 `CleanRoom_AccessRestricted` (model.ts:55) -The type name uses the participle predicate — but enums classify, not -predicate. Combined with the field `accessRestricted: CleanRoom_AccessRestricted`, -the result is `accessRestricted: AccessRestricted` — pure echo (the field -adds no information beyond what the type name supplies). - -### 19.2 `_LogOnlyMode_LogOnlyModeType` (model.ts:99) and -`_StorageDestination_StorageDestinationType` (model.ts:129) -Type name segment appears twice. See §8. - -### 19.3 `complianceSecurityProfile: ComplianceSecurityProfile` (model.ts:246) -See §8.3 — common pattern. - ---- - ## Cross-Package Overlap (cleanrooms vs. cleanroomassets / cleanroomautoapprovalrules / cleanroomtaskruns) @@ -567,19 +410,7 @@ The packages model different *aspects* of collaborators with different prefixes. Consistency would suggest `CleanRoomCollaboratorJobRunInfo` or moving the type into cleanrooms. Minor. -### CP.3 Status/state vocabulary divergence: -- `cleanrooms.CleanRoom_Status_Enum` — clean room lifecycle. -- `cleanroomtaskruns.CleanRoomTaskRunLifeCycleState` / - `CleanRoomTaskRunResultState` — task run lifecycle. -- `cleanroomassets.CleanRoomAsset_Status_Enum` — asset lifecycle. -- `cleanroomassets.CleanRoomNotebookReview_NotebookReviewState` — - review state. - -Five different *Status*/*State* enums across four packages. Each one is -locally correct, but readers must learn a new vocabulary per package. -Mild — cross-package theming, not actionable inside `cleanrooms`. - -### CP.4 Resource-name pattern repetition +### CP.3 Resource-name pattern repetition `cleanrooms` uses `name` as the clean room identifier in request/response shapes (§1.2). `cleanroomassets` and `cleanroomautoapprovalrules` will share the same `name` slot — risk of collision when shapes interact in @@ -598,27 +429,3 @@ generic code. self-documenting. - The package-level segment naming (`PACKAGE_SEGMENT` in client.ts:43) is appropriately namespaced. - ---- - -## Notes on Generation Artifacts - -Many findings above (especially §2, §4, §7, §8) are direct artifacts -of mechanical translation from the proto-defined Go SDK. The -`eslint-disable-next-line @typescript-eslint/naming-convention` comments -attached to each offender (and the comment "Proto-style nested enum -name" / "Proto-style nested message name") indicate these are recognized -deviations. They are not bugs in this file — they are systemic generator -output that this audit catalogs. - -If the SDK adopts a TS-idiomatic alias layer, the most leverage comes -from: -1. Flattening or shortening the seven `EgressNetworkPolicy_*` enums - (eliminates §4.4–§4.9, §7.1, §17.3–§17.6, §19.2). -2. Renaming `CleanRoom_Status_Enum` to `CleanRoomStatus` (§4.2). -3. Renaming `accessRestricted` -> `accessRestriction` and - `CleanRoom_AccessRestricted` -> `AccessRestriction` (§6.2, §12.2, §19.1). -4. Renaming `remoteDetailedInfo` -> `details` or `remoteDetail` (§6.1) - to align field and type names. - ---- diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md index 10f7965e..09a5f236 100644 --- a/.agent/naming-audit/cleanroomtaskruns.md +++ b/.agent/naming-audit/cleanroomtaskruns.md @@ -76,41 +76,7 @@ surface a TS consumer calls. It is also inconsistent across the SDK; this is a **P0 fix** for cross-package consistency (audit category 14: every other package uses camelCase `listX` style without Java/Go-style `Handler` decoration). -### 2. `SCREAMING_SNAKE_CASE` enum values — category 4 (Underscores in TS identifiers) - -**Symbols:** Every value in both enums (model.ts:10–19, 27–40). - -**Issue:** The Google TypeScript Style Guide (the project's `.agent/skills/google-ts-styleguide`) -mandates `UPPER_CAMEL_CASE` for enum members, not `SCREAMING_SNAKE_CASE`. The -project's own `.agent/rules/typescript.mdc` enforces "no underscores in TS -identifiers" (category 4). However, enum *string* values double as the on-the-wire -representation here (the `z.enum` parses raw API strings into these identifiers). -Splitting the TS-side identifier from the wire literal — e.g. -`Terminated = 'TERMINATED'` — is the idiomatic TS fix while preserving wire -compatibility. - -**Suggested (TS side only, no wire change):** - -```ts -export enum CleanRoomTaskRunLifeCycleState { - Unspecified = 'RUN_LIFE_CYCLE_STATE_UNSPECIFIED', - Pending = 'PENDING', - Running = 'RUNNING', - Terminating = 'TERMINATING', - Terminated = 'TERMINATED', - Skipped = 'SKIPPED', - InternalError = 'INTERNAL_ERROR', - Blocked = 'BLOCKED', - WaitingForRetry = 'WAITING_FOR_RETRY', - Queued = 'QUEUED', -} -``` - -Same shape for `CleanRoomTaskRunResultState`. This is consistent with the way the -project's `.agent/rules/typescript.mdc` treats other enums (e.g. status enums in -`apierror/codes`). - -### 3. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) +### 2. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) **Symbols:** Enum `CleanRoomTaskRunLifeCycleState` and field `CleanRoomTaskRunState.lifeCycleState` (model.ts:9, 80). @@ -126,18 +92,16 @@ midword capital. Cross-check: the same `LifeCycle` casing exists in `jobs/v2/model.ts` (line 389) and other "Run" types across the SDK, so a fix must be globally coordinated. -### 4. `TIMEDOUT` is a non-word — category 6 (Misleading names) and category 13 -(Verb tense inconsistency) +### 3. `TIMEDOUT` is a non-word — category 6 (Misleading names) and category 13 (Verb tense inconsistency) **Symbol:** `CleanRoomTaskRunResultState.TIMEDOUT` (model.ts:30). **Issue:** `TIMEDOUT` mashes "timed out" into one token and drops the space without forming a real word. Adjacent values use correct past-tense English (`CANCELED`, `EVICTED`, `FAILED`, `SUCCEEDED`-style). The Go reference also uses -`TIMEDOUT`, so this originates upstream; flag for protocol fix. The TS identifier -should be `TimedOut` regardless (combine with finding 2). +`TIMEDOUT`, so this originates upstream; flag for protocol fix. -### 5. `etag` lowercase abbreviation — category 3 (Acronym casing) +### 4. `etag` lowercase abbreviation — category 3 (Acronym casing) **Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65) and wire field `notebook_etag` (line 133). @@ -151,8 +115,7 @@ elsewhere in the codebase (search `Etag|ETag` in `cleanrooms/v1`) the same lowercase form is used for the `etag` field on `CleanRoomsNotebookTask`. Mark as consistent within the codebase but worth re-examining at the SDK level. -### 6. `notebookEtag` belongs to the notebook, not the task run — category 16 -(Field contradicting type domain) +### 5. `notebookEtag` belongs to the notebook, not the task run — category 16 (Field contradicting type domain) **Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65). @@ -163,8 +126,7 @@ struct is mixing notebook metadata with run metadata. Consider whether these should live under a nested `notebook` sub-object (`notebook.etag`, `notebook.updatedAt`) in a future revision. Flag only — current shape mirrors Go. -### 7. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 -(Duplicate concepts) +### 6. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 (Duplicate concepts) **Symbol:** `CleanRoomNotebookTaskRun.notebookJobRunState` (model.ts:52). @@ -181,12 +143,10 @@ the Go SDK source field is also `notebook_job_run_state` (i.e. the messiness is inherited). **Suggested:** `state` or `taskRunState`. Cross-reference with `jobs/v2` -`CleanRoomsNotebookTask_CleanRoomsNotebookTaskOutput.cleanRoomJobRunState` -(jobs/v2/model.ts:1158) which has the same shape with yet *another* spelling — -flag both for coordinated renaming. +`cleanRoomJobRunState` (jobs/v2/model.ts:1158) which has the same shape with yet +*another* spelling — flag both for coordinated renaming. -### 8. `runDuration` vs implicit "task run" — category 15 (Generic field names -losing meaning) +### 7. `runDuration` vs implicit "task run" — category 15 (Generic field names losing meaning) **Symbol:** `CleanRoomNotebookTaskRun.runDuration` (model.ts:50). @@ -198,8 +158,7 @@ yet duration carries it. Inconsistent. milliseconds"). Or rename `startTime` → `runStartTime` for consistency — pick one side. -### 9. `outputSchemaExpirationTime` / `sharedOutputSchemaExpirationTime` — -verbose — category 7 (Overly verbose) +### 8. `outputSchemaExpirationTime` / `sharedOutputSchemaExpirationTime` — verbose — category 7 (Overly verbose) **Symbols:** model.ts:63, model.ts:73. @@ -213,8 +172,7 @@ coexist: `…Time`, `…At`, and `runDuration` (numeric duration). Pick one. `startedAt` — or normalise all three to `…Time`. The `Run` pattern in other Databricks APIs leans toward `…At`. -### 10. `sharedOutputSchemaName` doc references missing `enable_shared_output` -flag — category 6 (Misleading names) +### 9. `sharedOutputSchemaName` doc references missing `enable_shared_output` flag — category 6 (Misleading names) **Symbol:** `CleanRoomNotebookTaskRun.sharedOutputSchemaName` (model.ts:72). @@ -224,8 +182,7 @@ on the run struct. Either the doc references state stored elsewhere (probably on the clean-room asset config), or the field is missing. Not a naming bug, but flag for a doc rewording. -### 11. `CollaboratorJobRunInfo` repeats "collaborator" in every field — -category 8 (Redundant suffixes) and category 2 (Redundant prefixes) +### 10. `CollaboratorJobRunInfo` repeats "collaborator" in every field — category 8 (Redundant suffixes) and category 2 (Redundant prefixes) **Symbol:** `CollaboratorJobRunInfo` (model.ts:85). Fields: `collaboratorJobId`, `collaboratorJobRunId`, `collaboratorTaskRunId`, `collaboratorWorkspaceId`, @@ -241,9 +198,7 @@ where the prefix is meaningful at the *top* level (`run.collaboratorJobRunInfo.c TS access lands one level deeper than the natural reading; the prefix is duplicate. Match the JS idiom: drop the prefix on the nested fields. -### 12. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the -package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 -(Singular/plural mismatch on the broader concept) +### 11. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 (Singular/plural mismatch on the broader concept) **Symbol:** `CollaboratorJobRunInfo` (model.ts:85). @@ -256,17 +211,7 @@ the struct *name* is therefore misleading; a more accurate name is `CollaboratorTaskRunRef` or `CollaboratorRunRef`. Flag for coordination with API team — the Go SDK has the same name. Cross-reference `jobs/v2` to align. -### 13. `Etag` doc text — category 4 (Underscores) and category 17 (Inconsistent -action verbs) - -**Symbol:** Doc comment for `notebookEtag` (model.ts:64): "used to identify the -notebook version". - -Not a naming issue per se, but the wire field is `notebook_etag`, surface field -`notebookEtag`, and JSDoc uses "Etag" — three spellings in one field. Minor. - -### 14. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type -`CleanRoomTaskRunState` — category 6 (Misleading names) +### 12. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type `CleanRoomTaskRunState` — category 6 (Misleading names) **Symbols:** model.ts:78, model.ts:52. @@ -279,7 +224,7 @@ calls the same thing `NotebookTaskRunOutput.runState`. Suggest aligning on keep the type name as-is (the wider SDK uses `…State` types throughout, e.g. `RunState`, `JobState`). -### 15. `pageSize` doc contradicts behaviour — category 6 (Misleading names) +### 13. `pageSize` doc contradicts behaviour — category 6 (Misleading names) **Symbol:** `ListCleanRoomNotebookTaskRunsRequest.pageSize` (model.ts:104). @@ -291,8 +236,7 @@ in JSDoc with a `@deprecated` tag so IDEs show strike-through. Naming-wise: `pageSize` is fine *if* it works; document the no-op via the deprecation tag, not just a sentence inside the doc. -### 16. `runs` field in response — category 15 (Generic field names losing -meaning) — borderline acceptable +### 14. `runs` field in response — category 15 (Generic field names losing meaning) — borderline acceptable **Symbol:** `ListCleanRoomNotebookTaskRunsResponse.runs` (model.ts:111). @@ -302,34 +246,21 @@ of the clean room.") is *wrong* — copy-paste error from the request struct's `cleanRoomName` doc. Doc-text bug, not a naming bug, but worth flagging during a naming pass since reviewers will notice the field while reading docs. -### 17. `nextPageToken` is the canonical name — pass. +### 15. `nextPageToken` is the canonical name — pass. No issue. Matches all other listing responses in the SDK. -### 18. `Client` class name — category 1 (Vague/generic) — *pass* +### 16. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-cleanroomtaskruns/v1`). -### 19. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) - -**Symbol:** `PACKAGE_SEGMENT` (client.ts:27). - -**Issue:** TS style for module-level constants is `camelCase` for runtime values -that aren't true primitive constants. Google TS Style Guide §5.1 -("const enums and constants must use UPPER_SNAKE_CASE only when they refer to -true constant values… else use camelCase"). `PACKAGE_SEGMENT` is a runtime object -(`{key, value}`) and is `const` only by declaration. However, the same name is -used in every package's client.ts (verify: ran into it in `cleanrooms`, -`cleanroomassets`, …) — it is a convention. Flag only for consistency, do not -fix in isolation. - -### 20. `userAgent` and `httpClient` — *pass* +### 17. `userAgent` and `httpClient` — *pass* Standard names; acronym handling is consistent (`Url` would be flagged but `HttpClient` is acceptable under the project rule and matches the imported type). -### 21. `flattenQueryParams` — *pass*, but unused (dead code) +### 18. `flattenQueryParams` — *pass*, but unused (dead code) **Symbol:** `flattenQueryParams` (utils.ts:123). @@ -338,7 +269,7 @@ its querystring inline at client.ts:64–72). The helper is dead code in this package. Naming itself is fine. Suggest deleting or extracting to a shared utility in `@databricks/sdk-core/http`. -### 22. `readAll(body)` — *pass* +### 19. `readAll(body)` — *pass* Helper does what its name says. @@ -346,25 +277,13 @@ Helper does what its name says. ## Cross-package notes (per audit instructions) -### `TaskRun` concept divergence between `cleanroomtaskruns` and `jobs/v2` - -| Aspect | `cleanroomtaskruns/v1` | `jobs/v2` | -|--------|------------------------|-----------| -| LifeCycle enum name | `CleanRoomTaskRunLifeCycleState` | `CleanRoomTaskRunLifeCycleState_CleanRoomTaskRunLifeCycleState` | -| Result enum name | `CleanRoomTaskRunResultState` | `CleanRoomTaskRunResultState_CleanRoomTaskRunResultState` | -| State struct | `CleanRoomTaskRunState` | `CleanRoomTaskRunState` (same name, identical shape) | -| Field referencing state | `notebookJobRunState` | `cleanRoomJobRunState` (jobs/v2/model.ts:1158) | - -The proto-style nested enum name `X_X` exists only in `jobs/v2`; the -`cleanroomtaskruns/v1` flat name is cleaner. Audit categories 12 (duplicate -concepts) and 2 (redundant prefixes) — strong recommendation: the generator -should reuse the `cleanroomtaskruns` flat names from `jobs/v2` (or both packages -should re-export from a single shared module) to avoid the doubled-prefix -oddity in `jobs`. This is a *generator* concern, not a `cleanroomtaskruns` -package concern — flag for the SDK platform team. +### `TaskRun` field-name divergence between `cleanroomtaskruns` and `jobs/v2` -Same goes for the state-field name: `notebookJobRunState` here, `cleanRoomJobRunState` -in jobs/v2 — two names for one wire-level concept. +The state field that holds a `CleanRoomTaskRunState` is named `notebookJobRunState` +in this package (model.ts:52) and `cleanRoomJobRunState` in `jobs/v2` +(jobs/v2/model.ts:1158). Two names for one wire-level concept across the two +packages that talk about the same run object. Audit category 12 (duplicate +concepts) — coordinate a single field name across both packages. ### `NotebookTask` concept @@ -382,12 +301,12 @@ service name — but a reader is left to guess. ## Summary (counts) - **Critical / cross-package consistency:** 1 finding (#1 `Handler` suffix). -- **High (style guide violations):** 3 findings (#2 enum casing, #3 LifeCycle - casing, #11 collaborator prefix repetition). -- **Medium (naming clarity):** 7 findings (#4, #7, #8, #9, #12, #14, #15). -- **Low / project-wide convention notes:** 7 findings (#5, #6, #10, #13, #16, - #19, #21) — some inherited from generator. -- **Pass / acceptable as-is:** 4 findings (#17, #18, #20, #22). - -**Total flagged findings: 18** distinct items across audit categories (some +- **High (style guide violations):** 2 findings (#2 LifeCycle casing, #10 + collaborator prefix repetition). +- **Medium (naming clarity):** 7 findings (#3, #6, #7, #8, #11, #12, #13). +- **Low / project-wide convention notes:** 5 findings (#4, #5, #9, #14, #18) — + some inherited from generator. +- **Pass / acceptable as-is:** 4 findings (#15, #16, #17, #19). + +**Total flagged findings: 15** distinct items across audit categories (some findings touch multiple categories). diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index a190403a..89a367e9 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -41,39 +41,21 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### 1.4 `RCranLibrary.package`, `PythonPyPiLibrary.package` — `model.ts:289, 299` - `package` is a reserved word in JavaScript (future-reserved, strict mode) and conveys little semantic content beyond "package". Consider - `coordinate`, `name`, or `packageName`. See also §10. + `coordinate`, `name`, or `packageName`. See also §8. - Severity: medium. ### 1.5 `MavenLibrary.repo`, `PythonPyPiLibrary.repo`, `RCranLibrary.repo` — `model.ts:274, 294, 301` - `repo` is an abbreviation. The companion `repo` documentation says "repository". `repository` (or `repositoryUrl`) would be more explicit. See - also §5. + also §4. - Severity: low. --- -## 2. Redundant enum prefixes +## 2. Acronym casing inconsistencies -### 2.1 `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — `model.ts:7` -- Enum value embeds the enum name as a prefix. In TS, the canonical access - is `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED`, which is - triply redundant ("BaseEnvironmentType" repeated). Value `UNSPECIFIED` - would suffice idiomatically; the prefix is a proto-enum convention that - does not survive the port intact. -- Severity: medium. - -### 2.2 `DefaultBaseEnvironmentCache_Status.STATUS_UNSPECIFIED` — `model.ts:47` -- Same pattern: enum value `STATUS_UNSPECIFIED` inside an enum already - carrying `Status` in its (compound) name. Bare `UNSPECIFIED` would be - unambiguous. -- Severity: medium. - ---- - -## 3. Acronym casing inconsistencies - -### 3.1 `PythonPyPiLibrary` — `model.ts:284, 512, 686` +### 2.1 `PythonPyPiLibrary` — `model.ts:284, 512, 686` - Mixed casing for the PyPI acronym. The canonical brand name is **PyPI** (Python Package Index, https://pypi.org). The TS identifier uses `PyPi` which is neither pure brand casing nor TS acronym convention. Should be @@ -88,7 +70,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: high (a brand-name spelling error visible in every consumer using PyPI packages). -### 3.2 `RCranLibrary` — `model.ts:297, 522, 696` +### 2.2 `RCranLibrary` — `model.ts:297, 522, 696` - "CRAN" (Comprehensive R Archive Network) is an all-caps acronym. The TS identifier renders it `Cran`. By TS/Google style guidance acronyms longer than two letters are typically PascalCased ("Cran"), but the resulting @@ -99,7 +81,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. - The discriminator `$case: 'cran'` is consistent with the type tag. - Severity: medium. -### 3.3 `Library.whl` — `model.ts:198, 206` +### 2.3 `Library.whl` — `model.ts:198, 206` - "Whl" is the file-extension shorthand for Python wheels. The wire format uses `whl`, but the TS type otherwise uses long-form names (`jar`, `requirements`, `egg`). `wheel` would be more readable in TS but is a @@ -107,7 +89,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: low (flagged for completeness — abbreviation, not strictly a casing issue). -### 3.4 `traceId` vs `trace_id` query param — `client.ts:222-224` +### 2.4 `traceId` vs `trace_id` query param — `client.ts:222-224` - Field is camelCase TS but serializes to snake_case on the wire. Consistent with all other fields; flagged only because the JSDoc on `traceId` (`model.ts:144`) hints at the deprecated nature of the param but uses @@ -118,49 +100,25 @@ means it is awkward or inconsistent; "low" means a minor blemish. --- -## 4. Underscores in TS identifiers - -### 4.1 `DefaultBaseEnvironmentCache_Status` — `model.ts:46` -- Underscore is non-idiomatic in TS PascalCase identifiers. This is a - proto-style nested name (`DefaultBaseEnvironmentCache.Status`) flattened - by underscore. The file already has an explicit eslint-disable comment - acknowledging this. A namespace or nested type would be more TS-native: - `namespace DefaultBaseEnvironmentCache { enum Status {...} }` or - rename to `DefaultBaseEnvironmentCacheStatus` (drop the underscore). -- Severity: high (every consumer importing this enum sees the underscore). - -### 4.2 `InstallLibraries_Response` — `model.ts:156, 417` -- Same pattern: proto-style nested name flattened by underscore. The eslint - comment acknowledges it. See also §19 (suffix redundancy). -- Severity: high. - -### 4.3 `UninstallLibraries_Response` — `model.ts:319, 536` -- Same. Severity: high. - -### 4.4 `ListAllClusterLibraryStatuses_Response` — `model.ts:235, 467` -- Same. Severity: high. - ---- +## 3. Cryptic abbreviations -## 5. Cryptic abbreviations - -### 5.1 `Library.jar`, `Library.egg`, `Library.whl` — `model.ts:158-217` +### 3.1 `Library.jar`, `Library.egg`, `Library.whl` — `model.ts:158-217` - Single-extension abbreviations as field names. Wire-locked, but the type surface would be more discoverable with `jarUri`, `wheelUri`, etc. The `requirements` field at the same level uses the long form, so the variants are inconsistent within one type. - Severity: low (wire compatibility constraint). -### 5.2 `repo` — multiple types +### 3.2 `repo` — multiple types - See §1.5. Short form of `repository`. Severity: low. -### 5.3 `Library.pypi`, `Library.cran` — `model.ts:177-196` +### 3.3 `Library.pypi`, `Library.cran` — `model.ts:177-196` - Lower-cased acronyms as field tags. Acceptable for wire compatibility, but the inconsistency with the (camelCased) type names (`PythonPyPiLibrary`, - `RCranLibrary`) is jarring. See §3. + `RCranLibrary`) is jarring. See §2. - Severity: low. -### 5.4 `filepath` — `model.ts:90` +### 3.4 `filepath` — `model.ts:90` - Single-word concatenation. TS convention prefers compound words like `filePath`. The wire uses `filepath` (one word) so the camelCase form mirrors it; arguably the wire spelling is also non-standard (most APIs @@ -169,9 +127,9 @@ means it is awkward or inconsistent; "low" means a minor blemish. --- -## 6. Misleading names +## 4. Misleading names -### 6.1 `updateDefaultDefaultBaseEnvironment` — `client.ts:429` +### 4.1 `updateDefaultDefaultBaseEnvironment` — `client.ts:429` - Method name contains "Default" twice ("the Default Default Base Environment"). The intent is clearer from the JSDoc: this method sets *which* DefaultBaseEnvironment (DBE) is the workspace's default. So the @@ -181,10 +139,10 @@ means it is awkward or inconsistent; "low" means a minor blemish. resource name. - Severity: high. This method name is the most surprising in the package. -### 6.2 `UpdateDefaultDefaultBaseEnvironmentRequest` — `model.ts:326` +### 4.2 `UpdateDefaultDefaultBaseEnvironmentRequest` — `model.ts:326` - Same problem on the request type. Severity: high. -### 6.3 `ClusterStatus` — `model.ts:63` +### 4.3 `ClusterStatus` — `model.ts:63` - The type holds only a `clusterId` and is used as the request body for `clusterStatus()`. Naming it `ClusterStatus` suggests it *is* the status, but it is a request that fetches status. Better: `ClusterStatusRequest` @@ -192,26 +150,26 @@ means it is awkward or inconsistent; "low" means a minor blemish. `ClusterLibraryStatuses` (correct). - Severity: high (the type name lies about its role). -### 6.4 `LibraryFullStatus` — `model.ts:220` +### 4.4 `LibraryFullStatus` — `model.ts:220` - "Full" implies there is a "Partial" or "Short" counterpart, but there is none in this package. The type is "the status of a library on a cluster" per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. - Severity: medium. -### 6.5 `LibraryInstallStatus` value `RESTORED` — `model.ts:42` +### 4.5 `LibraryInstallStatus` value `RESTORED` — `model.ts:42` - The docstring says "Library installation is restored and can be used." But `RESTORED` overlaps semantically with `INSTALLED`. Without further context (cache restore vs. fresh install), consumers cannot distinguish. Name is technically accurate but underspecified. - Severity: low. -### 6.6 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:35` +### 4.6 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:35` - This is the only value that is an action+condition (rather than a state noun). Surrounding values are `PENDING`, `INSTALLED`, `FAILED`. A noun form like `PENDING_UNINSTALL` would line up. - Severity: medium. -### 6.7 `allClusterStatuses()` — `client.ts:91` +### 4.7 `allClusterStatuses()` — `client.ts:91` - Method is the GET for `all-cluster-statuses`. The TS method name reads like an adjective ("all-cluster statuses") and is not verb-prefixed. Sibling method is `clusterStatus()` (also verb-less). Compare with the @@ -219,29 +177,29 @@ means it is awkward or inconsistent; "low" means a minor blemish. `createDefaultBaseEnvironment`, etc. (all verb-prefixed). The two GET methods alone are exempt. Should be `listAllClusterStatuses` or `getAllClusterStatuses`, and `getClusterStatus` respectively. -- Severity: medium. See also §15. +- Severity: medium. See also §11. -### 6.8 `Environment` — `model.ts:114` +### 4.8 `Environment` — `model.ts:114` - Type name is generic but the comment makes clear it is the "environment spec" used in serverless side-panel / job-task / pipeline contexts. A more specific name like `EnvironmentSpec` or `WorkspaceEnvironment` would avoid collisions with the JS global `process.env` mental model. - Severity: low. -### 6.9 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` +### 4.9 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` - The JSDoc says "when the materialized env is updated" — sufficient but the type itself does not carry the materialized payload (e.g., a hash, ID, or contents). The name overpromises relative to the contents; `EnvironmentCacheEntry` would be more honest. - Severity: medium. -### 6.10 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` — `model.ts:101` +### 4.10 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` — `model.ts:101` - "Indefinite" is unexplained anywhere in the file. It pairs with `materializedEnvironment` but the semantic distinction is opaque. The name needs a doc or rename. - Severity: medium. -### 6.11 `Environment.baseEnvironment` — `model.ts:131` +### 4.11 `Environment.baseEnvironment` — `model.ts:131` - A field inside `Environment` is also named `baseEnvironment` (same root word), which makes the relationship between the type and the field recursive-looking even though the field is just a path/ID string. @@ -250,56 +208,45 @@ means it is awkward or inconsistent; "low" means a minor blemish. --- -## 7. Overly verbose names +## 5. Overly verbose names -### 7.1 `ListAllClusterLibraryStatuses_Response` — `model.ts:235` -- Underscored response type whose name embeds "All" (which is also encoded - in the URL `/api/2.0/libraries/all-cluster-statuses`). The type name +### 5.1 `ListAllClusterLibraryStatuses` — `model.ts:232` +- The type name embeds "All" (which is also encoded in the URL + `/api/2.0/libraries/all-cluster-statuses`). The type name `ListAllClusterLibraryStatuses` is itself verbose — `ListLibraryStatuses` - or `ListClusterStatuses` would suffice. See also §4.4. -- Severity: medium. - -### 7.2 `UninstallLibraries_Response`, `InstallLibraries_Response` — `model.ts:156, 319` -- Verbose, underscored names. See §4. + or `ListClusterStatuses` would suffice. - Severity: medium. --- -## 8. Redundant suffixes +## 6. Redundant suffixes -### 8.1 `LibraryFullStatus` — `model.ts:220` -- "Full" is a vestigial qualifier with no counterpart. See §6.4. +### 6.1 `LibraryFullStatus` — `model.ts:220` +- "Full" is a vestigial qualifier with no counterpart. See §4.4. - Severity: medium. -### 8.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +### 6.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` - Field name repeats the parent's middle word (Library). Could simply be `statuses`. Borderline acceptable for clarity. - Severity: low. -### 8.3 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` -- Field is just `statuses` while the type bakes in `LibraryStatuses` - plurality and `ClusterLibrary` qualifier. Inconsistent with §8.2 which - uses `libraryStatuses`. -- Severity: low. - --- -## 9. Singular/plural mismatches +## 7. Singular/plural mismatches -### 9.1 `MavenLibrary.exclusions` — `model.ts:281` +### 7.1 `MavenLibrary.exclusions` — `model.ts:281` - Plural; field is a list. Doc says "List of dependences to exclude" — consistent. No issue (note: "dependences" is a typo for "dependencies", inherited from the API doc string). - Severity (typo): low. -### 9.2 `ListAllClusterLibraryStatuses` (request) vs `_Response.statuses` - — `model.ts:232, 237` +### 7.2 `ListAllClusterLibraryStatuses` (request) — `model.ts:232` - Singular method name `allClusterStatuses` (`client.ts:91`) for what is semantically a list operation. Compare `listDefaultBaseEnvironments` - (`client.ts:276`). The action verb should be `list` for both. See §15. + (`client.ts:276`). The action verb should be `list` for both. See §11. - Severity: medium. -### 9.3 `DefaultBaseEnvironment.baseEnvironmentCache` — `model.ts:93` +### 7.3 `DefaultBaseEnvironment.baseEnvironmentCache` — `model.ts:93` - Singular name but typed `DefaultBaseEnvironmentCache[]` (array). Should be `baseEnvironmentCaches` (or, if it really represents one cache lineage, the type definition is wrong). The Go SDK convention would surface this @@ -308,9 +255,9 @@ means it is awkward or inconsistent; "low" means a minor blemish. --- -## 10. Reserved-word collisions +## 8. Reserved-word collisions -### 10.1 `PythonPyPiLibrary.package`, `RCranLibrary.package` — `model.ts:289, 299` +### 8.1 `PythonPyPiLibrary.package`, `RCranLibrary.package` — `model.ts:289, 299` - `package` is a future-reserved word in ECMAScript (strict mode reserved). It is legal as an object property name and a parameter, but it is awkward to destructure: `const {package: pkg} = ...`. The wire field is `package`, @@ -319,26 +266,19 @@ means it is awkward or inconsistent; "low" means a minor blemish. `coordinate` (the same concept Maven uses). - Severity: high (forces renaming on destructure). -### 10.2 No other reserved-word issues observed. +### 8.2 No other reserved-word issues observed. --- -## 11. Duplicate concepts - -### 11.1 `LibraryInstallStatus` vs `DefaultBaseEnvironmentCache_Status` — `model.ts:13, 46` -- Two `Status` enums in the same file, each with `PENDING` / `FAILED` - members but different domains. Acceptable since they live in different - contexts, but consider naming differently to avoid import-site confusion - (e.g., `LibraryStatus` vs `DbeCacheStatus`). -- Severity: low. +## 9. Duplicate concepts -### 11.2 `InstallLibraries` (request) vs `installLibraries()` (method) +### 9.1 `InstallLibraries` (request) vs `installLibraries()` (method) — `model.ts:148, client.ts:250` - Method and request type share a name, distinguished only by case. TS convention works here because the type lives in the type namespace and the method in the value namespace. Fine. -### 11.3 `Environment` vs `MaterializedEnvironment` vs `DefaultBaseEnvironment` +### 9.2 `Environment` vs `MaterializedEnvironment` vs `DefaultBaseEnvironment` — `model.ts:78, 114, 262` - Three closely related types with overlapping names. The relationship (DBE contains an Environment; cache holds MaterializedEnvironment) is @@ -348,9 +288,9 @@ means it is awkward or inconsistent; "low" means a minor blemish. --- -## 12. Verb-tense inconsistency +## 10. Verb-tense inconsistency -### 12.1 Method verbs across the client — `client.ts:91-456` +### 10.1 Method verbs across the client — `client.ts:91-456` - `allClusterStatuses` and `clusterStatus` are verb-less (noun-only). - `installLibraries`, `uninstallLibraries`, `createDefaultBaseEnvironment`, `deleteDefaultBaseEnvironment`, `getDefaultBaseEnvironment`, @@ -359,78 +299,26 @@ means it is awkward or inconsistent; "low" means a minor blemish. use verb-prefixed forms. - Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: `listAllClusterStatuses` (or `getAllClusterStatuses`) and - `getClusterStatus`. See §6.7 and §15. + `getClusterStatus`. See §4.7 and §11. - Severity: high (consistency of the verb-prefix is a Java/TS SDK convention that consumers rely on). -### 12.2 `LibraryInstallStatus` action vs state values — `model.ts:13` +### 10.2 `LibraryInstallStatus` action vs state values — `model.ts:13` - Values mostly nouns (`PENDING`, `INSTALLED`, `FAILED`) but one verb - imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §6.6. + imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §4.6. - Severity: medium. --- -## 13. Go/Java-style names +## 11. Inconsistent action verbs -### 13.1 `_Response` suffix on types — `model.ts:156, 235, 319` -- The `Operation_Response` underscore pattern mirrors Go's nested message - generation (proto messages emit `Op.Response`). In TS, namespace nesting - or direct naming (`InstallLibrariesResponse`) is more idiomatic. The - generator's choice to use underscore loses the readability of the original - proto nesting without buying anything. -- Severity: high. - -### 13.2 `DefaultBaseEnvironmentCache_Status` — `model.ts:46` -- Same. Severity: high. - -### 13.3 `Library.lib` discriminator field — `model.ts:159` -- `$case` literal on the discriminator is a ts-proto / nanopb-style emission - (e.g., the same pattern as ts-proto's discriminated union output). Not - unidiomatic for TS, but `kind`, `type`, or `tag` would be more readable - to a consumer with no Go/proto background. -- Severity: low. - ---- - -## 14. Generic field names losing meaning - -### 14.1 `DefaultBaseEnvironment.environment` — `model.ts:89` -- A field named `environment` inside a type already named - `DefaultBaseEnvironment` is recursive-looking. The doc clarifies it is - the embedded `Environment` spec — but `environmentSpec` or - `inlineEnvironment` would convey "this is the actual environment - description, distinct from the wrapping metadata". -- Severity: medium. - -### 14.2 `DefaultBaseEnvironment.name`, `.id`, `.message` — `model.ts:79, 80, 92` -- Bare `id`, `name`, `message` are extremely generic. In context they are - unambiguous, but a programmer using auto-complete on a result list of - many resources may not be able to tell them apart. Cluster-level naming - would benefit from `dbeId`, `dbeName`. The Go SDK uses bare `Id` because - Go scopes them under the package; TS does too via the type, so the - generic forms are fine. -- Severity: low. - -### 14.3 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` - — `model.ts:75` -- An ID field named `workspaceBaseEnvironmentId` inside a "create DBE" - request. The `workspace` prefix implies a different resource (workspace - base environment) than the request's payload (`defaultBaseEnvironment`). - Documentation does not explain the relationship. The name is precise - but the role is unclear without docs. -- Severity: medium. - ---- - -## 15. Inconsistent action verbs - -### 15.1 GET vs `list` vs `all` — `client.ts:91, 276` +### 11.1 GET vs `list` vs `all` — `client.ts:91, 276` - `allClusterStatuses()` (verb `all`) is structurally identical to `listDefaultBaseEnvironments()` (verb `list`). Pick one. The Go SDK uses the same naming, but the TS port has the opportunity to normalize. -- Severity: medium (see §12.1). +- Severity: medium (see §10.1). -### 15.2 `refreshDefaultBaseEnvironments` — `client.ts:333` +### 11.2 `refreshDefaultBaseEnvironments` — `client.ts:333` - `refresh` is a TS-idiomatic verb meaning re-fetch / re-compute. The operation here regenerates a cache asynchronously. Borderline OK, but consumers may expect `refresh()` to return updated data; this returns @@ -438,71 +326,66 @@ means it is awkward or inconsistent; "low" means a minor blemish. reflect the side-effect more honestly. - Severity: low. -### 15.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL — `client.ts:433` +### 11.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL — `client.ts:433` - The URL says `:setDefault` but the method says `updateDefaultDefault`. `setDefaultBaseEnvironment` or `setWorkspaceDefault` would mirror the - URL semantics. See §6.1. + URL semantics. See §4.1. - Severity: high. -### 15.4 `installLibraries` / `uninstallLibraries` — `client.ts:250, 368` +### 11.4 `installLibraries` / `uninstallLibraries` — `client.ts:250, 368` - Symmetric pair, good. Mirror request types `InstallLibraries` / `UninstallLibraries` (named after the operation, not the resource). Consistent. --- -## 16. Field contradicting type domain +## 12. Field contradicting type domain -### 16.1 `Environment.client` — `model.ts:116` +### 12.1 `Environment.client` — `model.ts:116` - "Client" inside an Environment spec is unexpected; the doc clarifies it is a deprecated stand-in for `environment_version`. The name belongs to a different semantic domain (clients connect to environments, they are not part of them). - Severity: medium (deprecated, but exposed). -### 16.2 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:228` +### 12.2 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:228` - Inside `LibraryFullStatus` (per-cluster status), a field that describes whether the library is configured cluster-wide. The name reads like a global property but the type belongs to a single cluster's view. Better: `installedOnAllClusters` or `isClusterWideLibrary`. - Severity: medium. -### 16.3 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` +### 12.3 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` - Type is "materialized environment metadata"; the only field is a - timestamp. The materialization payload is missing — see §6.9. The + timestamp. The materialization payload is missing — see §4.9. The timestamp belongs in a cache-entry type, not a materialization type. - Severity: medium. --- -## 17. Long enum values +## 13. Long enum values -### 17.1 `LibraryInstallStatus.UNINSTALL_ON_RESTART` — `model.ts:35` +### 13.1 `LibraryInstallStatus.UNINSTALL_ON_RESTART` — `model.ts:35` - 20 characters; the only multi-word value. Acceptable since it conveys semantics, but combined with the prefix `LibraryInstallStatus.` the - full reference is 41 characters. See also §6.6. + full reference is 41 characters. See also §4.6. - Severity: low. -### 17.2 `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — `model.ts:7` -- Total reference: `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` - = 51 chars. See §2.1. -- Severity: medium. - --- -## 18. Underspecified IDs +## 14. Underspecified IDs -### 18.1 `CreateDefaultBaseEnvironmentRequest.requestId` — `model.ts:74` +### 14.1 `CreateDefaultBaseEnvironmentRequest.requestId` — `model.ts:74` - Idempotency UUID. Name is OK but generic; `idempotencyKey` would be more precise. - Severity: low. -### 18.2 `GetDefaultBaseEnvironmentRequest.traceId` — `model.ts:145` +### 14.2 `GetDefaultBaseEnvironmentRequest.traceId` — `model.ts:145` - Deprecated field. Name is OK; the comment hints at a missing replacement. Could be `traceId?: string` with a `@deprecated` JSDoc tag. - Severity: low. -### 18.3 `DefaultBaseEnvironment.creatorUserId`, `.lastUpdatedUserId` +### 14.3 `DefaultBaseEnvironment.creatorUserId`, `.lastUpdatedUserId` — `model.ts:81, 83` - Both are typed `number`. Databricks user IDs may exceed 2^53; bare `number` risks precision loss for very large IDs. (Naming-adjacent @@ -511,54 +394,53 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: medium (type, not name) — flagged because it bears on consumer expectations about ID identifiers. -### 18.4 `DefaultBaseEnvironment.principalIds` — `model.ts:94` +### 14.4 `DefaultBaseEnvironment.principalIds` — `model.ts:94` - `number[]` with no domain (workspace principals, account principals?). `Principal` is ambiguous in Databricks (user, SP, group). `principalIds` needs scope, like `workspacePrincipalIds`. - Severity: medium. -### 18.5 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` +### 14.5 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` — `model.ts:75` -- See §14.3. Underspecified relationship with the rest of the request. +- An ID field named `workspaceBaseEnvironmentId` inside a "create DBE" + request. The `workspace` prefix implies a different resource (workspace + base environment) than the request's payload (`defaultBaseEnvironment`). + Documentation does not explain the relationship. The name is precise + but the role is unclear without docs. - Severity: medium. -### 18.6 `ClusterLibraryStatuses.clusterId`, `ClusterStatus.clusterId`, +### 14.6 `ClusterLibraryStatuses.clusterId`, `ClusterStatus.clusterId`, `InstallLibraries.clusterId`, `UninstallLibraries.clusterId` — `model.ts:58, 65, 150, 313` - Bare `clusterId` everywhere. Good consistency. No issue. -### 18.7 `DefaultBaseEnvironment.id` — `model.ts:79` +### 14.7 `DefaultBaseEnvironment.id` — `model.ts:79` - Bare `id`. With sibling `creatorUserId` etc., a name like `dbeId` would be more grep-able. The Go SDK uses bare `Id` due to package scoping; TS scopes via the type so this is OK. - Severity: low. -### 18.8 `RefreshDefaultBaseEnvironmentsRequest.ids` — `model.ts:305` +### 14.8 `RefreshDefaultBaseEnvironmentsRequest.ids` — `model.ts:305` - Untyped collection of IDs of what? Doc-less. `dbeIds` or `defaultBaseEnvironmentIds` would be unambiguous. - Severity: medium. --- -## 19. Type-suffix tautology +## 15. Type-suffix tautology -### 19.1 `LibraryFullStatus` — `model.ts:220` +### 15.1 `LibraryFullStatus` — `model.ts:220` - "Status" appears in the type name and the field `status: LibraryInstallStatus` contains the noun again. Not a tautology per se, but the parent `LibraryFullStatus` could be `LibraryReport` or just `LibraryStatus` (with the inner field becoming `state` to avoid the duplicate). - Severity: low. -### 19.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` -- Already noted in §8.2. -- Severity: low. - -### 19.3 `ListAllClusterLibraryStatuses_Response.statuses` — `model.ts:237` -- Type name carries the suffix; field name is bare. Inconsistent with - §19.2 but otherwise fine. +### 15.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +- Already noted in §6.2. - Severity: low. -### 19.4 `ListDefaultBaseEnvironmentsResponse.defaultBaseEnvironments` +### 15.3 `ListDefaultBaseEnvironmentsResponse.defaultBaseEnvironments` — `model.ts:246` - Field name repeats the resource noun. Standard list-response pattern used across the SDK; no fix. @@ -571,39 +453,36 @@ means it is awkward or inconsistent; "low" means a minor blemish. ### High-severity (consumer-facing surprises) - `updateDefaultDefaultBaseEnvironment` / `UpdateDefaultDefaultBaseEnvironmentRequest` - (§6.1, §6.2): the "Default Default" doubling is the most jarring naming + (§4.1, §4.2): the "Default Default" doubling is the most jarring naming in the package. Best resolved by renaming the public API to `setWorkspaceDefaultBaseEnvironment`. -- All `_Response` and `_Status` underscore types (§4, §13.1): non-idiomatic - in TS, repeatedly exported, every importer sees them. -- `PythonPyPiLibrary` brand-casing inconsistency (§3.1): "PyPi" misspells +- `PythonPyPiLibrary` brand-casing inconsistency (§2.1): "PyPi" misspells the PyPI brand. -- `ClusterStatus` request type misleading-as-response (§6.3). +- `ClusterStatus` request type misleading-as-response (§4.3). - `baseEnvironmentCache: DefaultBaseEnvironmentCache[]` singular-on-array - (§9.3). -- `package` reserved-word collision on PyPI and CRAN libraries (§10.1). + (§7.3). +- `package` reserved-word collision on PyPI and CRAN libraries (§8.1). - Verb-tense gap: `allClusterStatuses()` and `clusterStatus()` break the - client's prevailing verb-prefix convention (§12.1, §15.1). + client's prevailing verb-prefix convention (§10.1, §11.1). ### Medium-severity -- Enum values embedding the enum name (§2.1, §2.2). -- `LibraryFullStatus` with no "non-full" counterpart (§6.4). +- `LibraryFullStatus` with no "non-full" counterpart (§4.4). - `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state - (§6.6, §12.2). -- `MaterializedEnvironment` containing only a timestamp (§6.9). + (§4.6, §10.2). +- `MaterializedEnvironment` containing only a timestamp (§4.9). - `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` - unexplained (§6.10). + unexplained (§4.10). - `isLibraryForAllClusters` field name awkwardly straddles per-cluster - and global domains (§16.2). + and global domains (§12.2). ### Low-severity / stylistic - `repo` vs `repository` short form (§1.5). -- `whl`, `jar`, `egg` extension-as-field-name (§5.1). -- `filepath` one-word concatenation (§5.4). -- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§6.5). -- "dependences" typo in `MavenLibrary.exclusions` doc (§9.1). +- `whl`, `jar`, `egg` extension-as-field-name (§3.1). +- `filepath` one-word concatenation (§3.4). +- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§4.5). +- "dependences" typo in `MavenLibrary.exclusions` doc (§7.1). --- diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index a54c2729..7f81f108 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -147,15 +147,9 @@ abbreviations and don't repeat the enum prefix. | A-03 | `RCranLibrary` — prefix `R` | Low | The leading lone `R` (the language) is awkward; the Go SDK uses the same name so this is a porting constraint. | | A-04 | `pypi` discriminator case (`Library.lib.$case === 'pypi'`) | Low | Lowercased, matching API wire format; consistent with `jar`, `egg`, `cran`, `maven`. Acceptable. | -### 2.4 Underscores in TS identifiers — High +### 2.4 Underscores in TS identifiers -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| U-01 | `CreatePolicy_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). Every occurrence requires an `eslint-disable @typescript-eslint/naming-convention` annotation. Should be `CreatePolicyResponse`. | -| U-02 | `DeletePolicy_Response` | High | Same as U-01. | -| U-03 | `EditPolicy_Response` | High | Same as U-01. | -| U-04 | `ListPolicies_Response` | High | Same as U-01. | -| U-05 | Enum member identifiers (`POLICY_CREATION_TIME`, `POLICY_NAME`) | Low | `SCREAMING_SNAKE_CASE` is acceptable for enum members under Google style (matches API wire values). Not a violation, just noted. | +_None._ ### 2.5 Cryptic abbreviations — Medium @@ -225,9 +219,8 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `CreatePolicy_Response` (proto nested-message style) | High | This is a direct port of Go's `pb.CreatePolicyResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `CreatePolicyResponse`. | -| G-02 | `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | -| G-03 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | +| G-01 | `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | +| G-02 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | ### 2.14 Generic field names losing meaning — Medium @@ -296,39 +289,31 @@ _None._ | Severity | Count | | -------- | ----- | -| High | 10 | -| Medium | 18 | -| Low | 23 | -| **Total**| **51**| +| High | 6 | +| Medium | 17 | +| Low | 22 | +| **Total**| **45**| ### 3.2 Top themes -1. **Proto-style `_Response` suffix pollutes every CRUD response type.** - Four interfaces (`CreatePolicy_Response`, `DeletePolicy_Response`, - `EditPolicy_Response`, `ListPolicies_Response`) each require an - `eslint-disable` for the naming-convention rule. Renaming to TS-idiomatic - `CreatePolicyResponse` etc. would eliminate disable-comments and a - Google-style violation in one sweep. - -2. **`Library.lib` repeats the type stem in its discriminator field.** +1. **`Library.lib` repeats the type stem in its discriminator field.** Callers write `library.lib?.$case` — `lib` adds no information the type name doesn't. A concrete name like `source` / `kind` / `spec` reads better at call sites. -3. **`PolicySortColumn.POLICY_*` repeats the enum prefix**; trimming to +2. **`PolicySortColumn.POLICY_*` repeats the enum prefix**; trimming to `CREATION_TIME` / `NAME` shortens call sites and matches enum-design guidance. -4. **`PyPi` casing should be `PyPI`** (acronym), and `package` fields collide +3. **`PyPi` casing should be `PyPI`** (acronym), and `package` fields collide with a JS strict-mode reserved word in `PythonPyPiLibrary` / `RCranLibrary`. -5. **`createdAtTimestamp` is a tautology**; `createdAt` is the SDK-wide and +4. **`createdAtTimestamp` is a tautology**; `createdAt` is the SDK-wide and ecosystem-wide convention for epoch-millisecond fields. ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) -- Drop `_Response` suffix in all four response interfaces. - Rename `Library.lib` -> `Library.source` (concrete discriminator name). - Trim `PolicySortColumn` members. - `PythonPyPiLibrary` -> `PythonPyPILibrary`. @@ -337,7 +322,5 @@ section is advisory for the codegen owners) ### 3.4 Cross-package consistency notes -- The `Proto-style nested message name` `_Response` suffix is consistent - with peers and should be addressed at the codegen level. - `editPolicy` (vs `updatePolicy`) is a per-API decision driven by the upstream REST verb; flag for upstream alignment but no per-package fix. diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index 87879fe9..4be667d6 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -3,321 +3,273 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 **Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 84 +**Total weird names flagged:** 76 ## Summary | Severity | Count | | --- | --- | -| High | 19 | -| Medium | 32 | +| High | 12 | +| Medium | 31 | | Low | 24 | | Observation | 9 | ## High severity -### 1. Cluster-State enum named `ClusterState_ClusterState` — `src/v2/model.ts:777` -- **Why weird:** Identifier doubles up the same word. Required `eslint-disable @typescript-eslint/naming-convention`. The user-visible enum is therefore `ClusterState_ClusterState.RUNNING`, which is almost cartoonishly verbose. -- **Category:** 4 (underscore in TS identifier), 6 (misleading — the doubled word reads as a typo), 14 (proto-style nested-enum noise). -- **Suggested name:** Re-export `ClusterState_ClusterState` as `ClusterState` from `index.ts`. (Note: the type declaration still leaks the proto-style name.) -- **Rationale:** TypeScript has no need to mirror the protobuf "outer message" wrapper at the call site. The current shape forces every caller to write `ClusterState_ClusterState.RUNNING`, which is jarring and forced the client to write `pollResp.state === ClusterState_ClusterState.RUNNING` (`client.ts:907`, `:949`, `:987`, etc.). - -### 2. `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — `src/v2/model.ts:29-37` +### 1. `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — `src/v2/model.ts:29-37` - **Why weird:** Every enum value redundantly re-states the enum's cloud (`_AZURE`). Same for `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` (`model.ts:146-148`). Compare with `AwsAvailability` (`model.ts:12-22`) where AWS-specific values are unprefixed (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`). Three sibling enums, three different conventions. - **Category:** 2 (redundant enum prefix), 17 (inconsistent across the AWS/Azure/GCP triplet). - **Suggested name:** `AzureAvailability.Spot | OnDemand | SpotWithFallback` and `GcpAvailability.Preemptible | OnDemand | PreemptibleWithFallback`. - **Rationale:** The enum name already states the cloud (`AzureAvailability`). Wire values can stay as-is; TS enum identifiers should not duplicate the type. AWS already does it correctly — Azure/GCP should follow. -### 3. `ComputeKind.COMPUTE_KIND_UNSPECIFIED` — `src/v2/model.ts:58` +### 2. `ComputeKind.COMPUTE_KIND_UNSPECIFIED` — `src/v2/model.ts:58` - **Why weird:** Member name re-states the enum name as a prefix. TypeScript enums are already namespaced; `ComputeKind.UNSPECIFIED` is the same wire string with no prefix duplication. - **Category:** 2 (redundant enum prefix), 14 (proto-style). - **Suggested name:** `ComputeKind.Unspecified | ClassicPreview`. Better yet, drop `Unspecified` entirely and use `kind?: ComputeKind | undefined`. -- **Rationale:** Same logic as #2. `COMPUTE_KIND_` is pure proto noise. +- **Rationale:** Same logic as #1. `COMPUTE_KIND_` is pure proto noise. -### 4. `ConfidentialComputeType.CONFIDENTIAL_COMPUTE_TYPE_UNSPECIFIED` / `CONFIDENTIAL_COMPUTE_TYPE_NONE` — `src/v2/model.ts:69-70` -- **Why weird:** Same redundant prefix as #3 but worse — the enum has three values, two of which carry the full prefix, while the third (`SEV_SNP`) does not. So readers see `CONFIDENTIAL_COMPUTE_TYPE_NONE` next to `SEV_SNP` and have to guess at the pattern. +### 3. `ConfidentialComputeType.CONFIDENTIAL_COMPUTE_TYPE_UNSPECIFIED` / `CONFIDENTIAL_COMPUTE_TYPE_NONE` — `src/v2/model.ts:69-70` +- **Why weird:** Same redundant prefix as #2 but worse — the enum has three values, two of which carry the full prefix, while the third (`SEV_SNP`) does not. So readers see `CONFIDENTIAL_COMPUTE_TYPE_NONE` next to `SEV_SNP` and have to guess at the pattern. - **Category:** 2 (redundant prefix), 17 (inconsistent within the same enum). - **Suggested name:** `ConfidentialComputeType.Unspecified | None | SevSnp`. Drop `Unspecified` to rely on `confidentialComputeType?: ConfidentialComputeType | undefined`. - **Rationale:** Enums should pick one prefix convention; this one mixes both within three values. -### 5. `DataSecurityMode.DATA_SECURITY_MODE_STANDARD` / `DATA_SECURITY_MODE_DEDICATED` / `DATA_SECURITY_MODE_AUTO` — `src/v2/model.ts:123-127` +### 4. `DataSecurityMode.DATA_SECURITY_MODE_STANDARD` / `DATA_SECURITY_MODE_DEDICATED` / `DATA_SECURITY_MODE_AUTO` — `src/v2/model.ts:123-127` - **Why weird:** Three values redundantly prefixed with `DATA_SECURITY_MODE_`. The other six values in the enum (`NONE`, `SINGLE_USER`, `USER_ISOLATION`, `LEGACY_TABLE_ACL`, `LEGACY_PASSTHROUGH`, `LEGACY_SINGLE_USER`, `LEGACY_SINGLE_USER_STANDARD`) are unprefixed. So the same enum mixes both styles. The JSDoc itself notes some are aliases: "`DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`". So the enum has duplicate values for the same concept and inconsistent naming. - **Category:** 2 (redundant prefix), 12 (duplicate concepts: STANDARD alias for USER_ISOLATION; DEDICATED alias for SINGLE_USER), 17 (mixed prefix/no-prefix in one enum). - **Suggested name:** Either align (`DataSecurityMode.Auto | Standard | Dedicated` and drop the long-form aliases) or normalise away the aliases. - **Rationale:** Public SDK enums should not ship both `USER_ISOLATION` and `DATA_SECURITY_MODE_STANDARD` if they mean the same thing — pick one, document deprecation on the other. -### 6. `CloudProviderNodeStatus` enum uses non-SCREAMING_SNAKE wire values — `src/v2/model.ts:40-43` +### 5. `CloudProviderNodeStatus` enum uses non-SCREAMING_SNAKE wire values — `src/v2/model.ts:40-43` - **Why weird:** `NOT_ENABLED_ON_SUBSCRIPTION = 'NotEnabledOnSubscription'` and `NOT_AVAILABLE_IN_REGION = 'NotAvailableInRegion'`. The TS identifier is `SCREAMING_SNAKE` (every other enum in this file follows that), but the wire value is `PascalCase`. Every other enum's wire value matches the TS identifier exactly. - **Category:** 17 (inconsistent wire-value casing). - **Suggested name:** Keep the SCREAMING_SNAKE TS identifier; this is an upstream wire-value inconsistency that the generator faithfully reproduces. - **Rationale:** Highlight to upstream — the API surface should be uniform. Flagged here so downstream consumers know to expect PascalCase strings for this one enum. -### 7. `TerminationCode.*` — 150+ enum values, many proto-style noisy — `src/v2/model.ts:164-748` +### 6. `TerminationCode.*` — 150+ enum values, many proto-style noisy — `src/v2/model.ts:164-748` - **Why weird:** The enum has ~150 values; many encode the same concept three or four times. Examples: `BOOTSTRAP_TIMEOUT` vs `BOOTSTRAP_TIMEOUT_DUE_TO_MISCONFIG` vs `BOOTSTRAP_TIMEOUT_CLOUD_PROVIDER_EXCEPTION`; `INSTANCE_UNREACHABLE` vs `INSTANCE_UNREACHABLE_DUE_TO_MISCONFIG`; `CONTROL_PLANE_REQUEST_FAILURE` vs `CONTROL_PLANE_REQUEST_FAILURE_DUE_TO_MISCONFIG` (whose JSDoc just says "CPRF, but due to misconfiguration on the customer's side"). Several values reference internal Databricks jargon: `NEPHOS_RESOURCE_MANAGEMENT`, `CHAUFFEUR`, `NPIP_TUNNEL`, `IN_PENALTY_BOX`, `CMv2`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT`, `GKE_BASED_CLUSTER_TERMINATION`. - **Category:** 5 (cryptic abbreviations — Nephos, CPRF, CPLF, CMv2, DBR, NPIP, CMK, K8s, IMv2), 12 (duplicate concepts — many `_DUE_TO_MISCONFIG` siblings duplicate the base reason), 18 (long enum values). - **Suggested name:** Out of scope for a rename, but flag upstream: collapse `_DUE_TO_MISCONFIG` siblings into a structured field (`misconfig: boolean` on `TerminationReason`) instead of doubling every code; document internal-jargon codes for external consumers. - **Rationale:** This is a public SDK; values like `IN_PENALTY_BOX` and `NEPHOS_RESOURCE_MANAGEMENT` leak internal-process names to customers and are unfit for external naming. Comments on `GCP_QUOTA_EXCEEDED` (`model.ts:410`) literally include a TODO about consolidating per-cloud reasons — the SDK is shipping the unconsolidated state. -### 8. `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` — `src/v2/model.ts:421` +### 7. `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` — `src/v2/model.ts:421` - **Why weird:** `BYOK` is "Bring Your Own Key". Abbreviation used without expansion in either the enum value or the JSDoc. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** Expand to `AZURE_CUSTOMER_KEY_PERMISSION_FAILURE` or document `BYOK` inline. - **Rationale:** External SDK users will not all know `BYOK` is a cloud-key acronym. -### 9. `TerminationCode.NPIP_TUNNEL_TOKEN_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE` — `src/v2/model.ts:309,350` +### 8. `TerminationCode.NPIP_TUNNEL_TOKEN_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE` — `src/v2/model.ts:309,350` - **Why weird:** `NPIP` ("No Public IP") is internal Databricks networking terminology. Not expanded in JSDoc. - **Category:** 5 (cryptic abbreviation), 8 (internal jargon in public surface). - **Suggested name:** Rename to `NO_PUBLIC_IP_TUNNEL_*` or document `NPIP` in the enum docstring. -- **Rationale:** Same as #8; SDK users should not need to know Databricks' internal acronyms. +- **Rationale:** Same as #7; SDK users should not need to know Databricks' internal acronyms. -### 10. `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` / `DBR_IMAGE_RESOLUTION_FAILURE` — `src/v2/model.ts:380,729` +### 9. `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` / `DBR_IMAGE_RESOLUTION_FAILURE` — `src/v2/model.ts:380,729` - **Why weird:** `DBR` ("Databricks Runtime") and `K8S` ("Kubernetes") used together with no expansion. JSDoc on line 380 says "DBR Cluster launched on K8s (i.e. CMv2)" — three acronyms in one sentence. - **Category:** 5 (cryptic abbreviation), 8 (jargon). - **Suggested name:** Expand acronyms in JSDoc minimum; consider renaming to `DATABRICKS_RUNTIME_CLUSTER_LAUNCH_TIMEOUT_KUBERNETES`. - **Rationale:** Internal SDK people read `DBR` daily; external consumers don't. -### 11. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` — `src/v2/model.ts:368` +### 10. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` — `src/v2/model.ts:368` - **Why weird:** Enum value is 52 characters long; says "AWS insufficient free addresses in subnet failure". GCP equivalent is `GCP_IP_SPACE_EXHAUSTED` (`model.ts:579`), 22 chars — same concept, very different length. JSDoc at line 410 explicitly TODOs consolidating these. - **Category:** 7 (overly verbose), 17 (inconsistent across clouds), 18 (long enum value). - **Suggested name:** `AWS_SUBNET_IP_EXHAUSTED` (mirror the GCP form). - **Rationale:** Per-cloud variants should follow the same shape; the AWS/GCP/Azure versions of the same condition should not differ in length by 30 characters. -### 12. `TerminationCode.AZURE_UNEXPECTED_DEPLOYMENT_TEMPLATE_FAILURE` / `AZURE_PACKED_DEPLOYMENT_PARTIAL_FAILURE` — `src/v2/model.ts:323,493` +### 11. `TerminationCode.AZURE_UNEXPECTED_DEPLOYMENT_TEMPLATE_FAILURE` / `AZURE_PACKED_DEPLOYMENT_PARTIAL_FAILURE` — `src/v2/model.ts:323,493` - **Why weird:** 45- and 41-character enum values. Both are Azure-deployment-template-specific. AWS and GCP do not have equivalents at this length. - **Category:** 7 (overly verbose), 18 (long enum value). - **Suggested name:** `AZURE_DEPLOYMENT_TEMPLATE_FAILURE`, `AZURE_PACKED_DEPLOYMENT_FAILURE` (drop the qualifier; let the JSDoc carry the nuance). - **Rationale:** Public enums should be readable at a glance. -### 13. `TerminationCode.ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` — `src/v2/model.ts:675` +### 12. `TerminationCode.ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` — `src/v2/model.ts:675` - **Why weird:** 53-character enum value. Eight `ALLOCATION_TIMEOUT_*` siblings (`model.ts:650-675`) all encode subtle internal scheduler states. - **Category:** 7 (overly verbose), 12 (duplicate concept across eight near-identical codes), 18 (long enum value). - **Suggested name:** Collapse the family into `ALLOCATION_TIMEOUT` with a structured sub-field (`reason: string`) on `TerminationReason.parameters`. - **Rationale:** Eight `ALLOCATION_TIMEOUT_*` codes look like the inverse of "values should be discriminator-friendly". External callers will hardly distinguish `NO_HEALTHY_CLUSTERS` from `NO_HEALTHY_AND_WARMED_UP_CLUSTERS`. -### 14. `_Response` suffix and Proto-style nested types — pervasive throughout -- **Why weird:** 14+ `_Response` interfaces (`ChangeClusterOwner_Response`, `CreateCluster_Response`, `DeleteCluster_Response`, `EditCluster_Response`, `EnforcePolicyComplianceForCluster_Response`, `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange`, `GetPolicyComplianceForCluster_Response`, `GetSparkVersions_Response`, `ListAvailableZones_Response`, `ListClusterComplianceForPolicy_Response`, `ListClusters_Response`, `ListNodeTypes_Response`, `PermanentDeleteCluster_Response`, `PinCluster_Response`, `ResizeCluster_Response`, `RestartCluster_Response`, `StartCluster_Response`, `UnpinCluster_Response`, `UpdateCluster_Response`). Each requires an `eslint-disable @typescript-eslint/naming-convention`. -- **Category:** 4 (underscores in TS identifier), 14 (proto-style naming). -- **Suggested name:** Rename to `CreateClusterResponse` etc. -- **Rationale:** Strict-type-checked ESLint rejects `Foo_Bar`. The `_Response` suffix is pure proto-style noise in a TypeScript identifier. - -### 15. `ClusterInfo_ComputeSpec_CustomTagsEntry`, `ClusterInfo_SparkConfEntry`, etc. — 16 underscore-laden map-entry types -- **Why weird:** 16 interfaces with names like `ClusterInfo_ComputeSpec_CustomTagsEntry` (`model.ts:1412`), `ClusterInfo_ComputeSpec_SparkConfEntry` (`model.ts:1429`), `ClusterInfo_ComputeSpec_SparkEnvVarsEntry` (`model.ts:1436`), `ClusterInfo_CustomTagsEntry`, `ClusterInfo_DefaultTagsEntry`, `ClusterInfo_SparkConfEntry`, `ClusterInfo_SparkEnvVarsEntry`, `CreateCluster_CustomTagsEntry`, `CreateCluster_SparkConfEntry`, `CreateCluster_SparkEnvVarsEntry`, `EditCluster_CustomTagsEntry`, `EditCluster_SparkConfEntry`, `EditCluster_SparkEnvVarsEntry`, `UpdateCluster_UpdateClusterResource_CustomTagsEntry`, `UpdateCluster_UpdateClusterResource_SparkConfEntry`, `UpdateCluster_UpdateClusterResource_SparkEnvVarsEntry`. Each carries the same `{key?: string; value?: string}` shape — sixteen distinct names for one concept. -- **Category:** 4 (underscores), 12 (duplicate concepts — same `{key, value}` shape 16 times). -- **Suggested name:** Consolidate around the wire-equivalent `Record` form already used by the parent fields. -- **Rationale:** These types exist only because protobuf models maps as repeated `Entry` messages. TypeScript has built-in `Record<>` — sixteen separate `{key, value}` types for the same concept is pure proto-style duplication. - -### 16. `UpdateCluster_UpdateClusterResource` — `src/v2/model.ts:2590` -- **Why weird:** Name doubles up: `UpdateCluster_UpdateClusterResource`. The field is `UpdateCluster.cluster: UpdateCluster_UpdateClusterResource` (`model.ts:2581`). So the user writes `req.cluster` and the type is `UpdateCluster_UpdateClusterResource`. Three underscores worth of proto noise. Same body across `CreateCluster`, `EditCluster`, `UpdateCluster_UpdateClusterResource` (they have 28 identical fields each). -- **Category:** 4 (underscore), 6 (misleading: shouldn't this just be `ClusterSpec` or `Cluster`?), 8 (redundant `Resource` suffix), 12 (duplicate concept with `CreateCluster`/`EditCluster`/`ClusterInfo_ComputeSpec`), 14 (proto-style nested message). -- **Suggested name:** `ClusterSpec` (and reuse for `CreateCluster`, `EditCluster`, `ClusterInfo.spec`). -- **Rationale:** The type holds cluster configuration — the same configuration four request types describe. Collapsing to a shared `ClusterSpec` removes duplication and naming weirdness in one move. - -### 17. `ClusterInfo_ComputeSpec` — `src/v2/model.ts:1229` -- **Why weird:** Underscored type name; near-identical to `UpdateCluster_UpdateClusterResource` (28 of 28 fields overlap). The JSDoc says "Contains a snapshot of the latest user specified settings". `Spec`/`ClusterSpec` would be sufficient. -- **Category:** 4 (underscore), 12 (duplicate of #16), 14 (proto-style nested). -- **Suggested name:** Use shared `ClusterSpec`. -- **Rationale:** Same as #16; one canonical spec type used in four places. - -### 18. `WorkloadType_ClientsTypes` — `src/v2/model.ts:2816` -- **Why weird:** Triple-misery: `WorkloadType` outer type has a single field `clients` of type `WorkloadType_ClientsTypes`. The nested type's name pluralises both nouns (`Clients`+`Types`). The two booleans inside (`notebooks`, `jobs`) are not "types" — they're "client flags". Field on parent is singular (`clients`) but type is plural+plural (`ClientsTypes`). -- **Category:** 1 (vague — "ClientsTypes" doesn't mean anything), 4 (underscore), 6 (misleading), 9 (singular vs plural inconsistency), 14 (proto-style nested). -- **Suggested name:** Rename to `WorkloadClients` and align the field's plural/singular shape with the type name. -- **Rationale:** Two-level nesting with an outer container adds no information; the wire form is `workload_type.clients.notebooks` which is also unnecessarily deep. - -### 19. `SparkInfo_SparkNode_SparkNodeAwsAttributes` — `src/v2/model.ts:2530` -- **Why weird:** `SparkInfo_SparkNode_SparkNodeAwsAttributes` repeats `SparkNode` twice. Contains one field, `isSpot`. The field on the parent type (`SparkInfo_SparkNode`) is called `nodeAwsAttributes` (`model.ts:2523`) — so the user writes `node.nodeAwsAttributes.isSpot`, and the type is `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Three `SparkNode`s, two underscores, one boolean. -- **Category:** 1 (vague, redundant), 4 (underscores), 7 (overly verbose), 14 (proto-style nested). -- **Suggested name:** Re-export as `SparkNodeAwsAttributes` from `index.ts` to give callers a sane identifier. -- **Rationale:** A name that repeats `SparkNode` twice and contains two underscores is unreadable; the proto-style nesting need not survive to the public TS surface. - ## Medium severity -### 20. `Adlsgen2Info` casing — `src/v2/model.ts:800` +### 13. `Adlsgen2Info` casing — `src/v2/model.ts:800` - **Why weird:** Type name is `Adlsgen2Info` — should be `AdlsGen2Info` to match acronym-casing rules. ADLS (Azure Data Lake Storage) Gen2 should retain the boundary between `Adls` and `Gen2`. - **Category:** 3 (acronym casing inconsistency), 1 (vague `Info` suffix). - **Suggested name:** `AdlsGen2Storage` (or just `AbfssStorage`, since the wire name is `abfss`). - **Rationale:** Compare to sibling types `DbfsStorageInfo`, `GcsStorageInfo`, `S3StorageInfo` — all use `Info` suffix and capitalize the storage product. `Adlsgen2Info` is the odd one out. -### 21. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:800,1745,2102,2290,2456,2801,2824` +### 14. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:800,1745,2102,2290,2456,2801,2824` - **Why weird:** `Adlsgen2Info` (no `Storage`), `DbfsStorageInfo`, `GcsStorageInfo`, `LocalFileInfo` (no `Storage`), `S3StorageInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. Seven sibling types; five say `StorageInfo`, two say `Info`. - **Category:** 17 (inconsistent suffix across siblings). - **Suggested name:** Standardise on `XStorage` (drop the redundant `Info`) — `AdlsGen2Storage`, `DbfsStorage`, `GcsStorage`, `LocalFileStorage`, `S3Storage`, `VolumesStorage`, `WorkspaceStorage`. - **Rationale:** All seven describe the same kind of thing (a storage destination). Either all of them get `StorageInfo` or none do. -### 22. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:946,2112,2118,2227,2244` +### 15. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:946,2112,2118,2227,2244` - **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForCluster` (a request), `GetPolicyComplianceForCluster_Response`, `EnforcePolicyComplianceForCluster` (request), `ListClusterComplianceForPolicy` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. - **Category:** 1 (vague — `For` is the only disambiguator), 6 (misleading — easy to mis-parse). - **Suggested name:** `GetClusterPolicyCompliance`, `EnforceClusterPolicyCompliance`, `ListPolicyCompliantClusters`, `ClusterPolicyCompliance`. - **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. -### 23. `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange` — `src/v2/model.ts:2025` -- **Why weird:** 56 characters, three underscores, four nested words. Used inside `EnforcePolicyComplianceForCluster_Response.changes`. -- **Category:** 4 (underscores), 7 (overly verbose), 14 (proto-style nested-nested message). -- **Suggested name:** `ClusterSettingsChange` (hoist to module level) or `PolicyComplianceChange`. -- **Rationale:** Nested-nested proto messages should not survive translation to TS. - -### 24. `validateOnly` field — `src/v2/model.ts:2001` +### 16. `validateOnly` field — `src/v2/model.ts:2001` - **Why weird:** Field on `EnforcePolicyComplianceForCluster`. Verb-prefixed boolean reads as a method; doc says "if set, previews the changes" — closer to a `previewOnly`/`dryRun` flag. - **Category:** 6 (misleading: name implies "validate", behaviour is "dry-run"). - **Suggested name:** `dryRun` or `previewOnly`. - **Rationale:** Common convention; matches what most cloud SDKs name this. Wire stays `validate_only`. -### 25. `hasChanges` field — `src/v2/model.ts:2010` +### 17. `hasChanges` field — `src/v2/model.ts:2010` - **Why weird:** Boolean named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. - **Category:** 12 (duplicate signal), 1 (vague). - **Suggested name:** Drop the field, infer from `changes.length`. - **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. -### 26. `restartUser` field on `RestartCluster` — `src/v2/model.ts:2449` +### 18. `restartUser` field on `RestartCluster` — `src/v2/model.ts:2449` - **Why weird:** No JSDoc. Field name alone doesn't say what it does. Is it "user who triggered the restart"? "User to attribute the restart to"? Inconsistent with the package's general style (`ownerUsername`, `creatorUserName`, `singleUserName` all spell out `Username`/`UserName`). - **Category:** 1 (vague — no doc, ambiguous semantics), 17 (sibling fields say `username` or `userName`, this one says `user`). - **Suggested name:** `restartUsername` or `restartedByUsername`. - **Rationale:** Match the field-naming patterns used elsewhere; even better, document the field. -### 27. `creatorUserName` / `singleUserName` / `ownerUsername` — `src/v2/model.ts:977,1150,930` +### 19. `creatorUserName` / `singleUserName` / `ownerUsername` — `src/v2/model.ts:977,1150,930` - **Why weird:** Three "user name" fields in the same model, two different camelCases: `creatorUserName` and `singleUserName` use `UserName` (two words), `ownerUsername` uses `Username` (one word). Wire is `creator_user_name`, `single_user_name`, `owner_username` — the wire is inconsistent too. - **Category:** 3 (casing inconsistency), 17 (sibling field inconsistency). - **Suggested name:** Pick one: `Username` is more conventional in modern web APIs. Go SDK and proto leave this inconsistent; TS could normalise. - **Rationale:** Three similar fields, three (sort of) similar names, two different ways of capitalising the same concept. -### 28. `kind: ComputeKind` field — `src/v2/model.ts:1173` -- **Why weird:** Field is called `kind` on `ClusterInfo`, `ClusterInfo_ComputeSpec`, `CreateCluster`, `EditCluster`, `UpdateCluster_UpdateClusterResource`. Sibling fields are very specific (`runtimeEngine`, `dataSecurityMode`, `workloadType`); `kind` is the odd vague one. +### 20. `kind: ComputeKind` field — `src/v2/model.ts:1173` +- **Why weird:** Field is called `kind` on `ClusterInfo`, `CreateCluster`, `EditCluster`, and the update-cluster spec. Sibling fields are very specific (`runtimeEngine`, `dataSecurityMode`, `workloadType`); `kind` is the odd vague one. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `computeKind` (matches the type and wire name `kind` can stay). - **Rationale:** `kind` alone is the JS-reserved-shape problem (`kind` is heavily overloaded in discriminated-union code). `computeKind` is unambiguous. -### 29. `size` discriminated union (`numWorkers` | `autoscale`) — `src/v2/model.ts:1201` -- **Why weird:** Field `size` is a discriminated union with two variants `numWorkers` (number) and `autoscale` (object). It appears on six types: `ClusterInfo`, `ClusterInfo_ComputeSpec`, `CreateCluster`, `EditCluster`, `ResizeCluster`, `UpdateCluster_UpdateClusterResource`. The literal `size` doesn't read as "either count or autoscaler" — calling code looks like `if (req.size?.$case === 'numWorkers')` which is awkward. +### 21. `size` discriminated union (`numWorkers` | `autoscale`) — `src/v2/model.ts:1201` +- **Why weird:** Field `size` is a discriminated union with two variants `numWorkers` (number) and `autoscale` (object). It appears on six cluster-spec-shaped types. The literal `size` doesn't read as "either count or autoscaler" — calling code looks like `if (req.size?.$case === 'numWorkers')` which is awkward. - **Category:** 1 (vague), 6 (misleading: a "size" sounds like an integer). - **Suggested name:** `capacity` (or just `workers`, since both variants describe how many workers). - **Rationale:** "size" suggests a number; this field is a tagged union. A different word avoids the contradiction. -### 30. `useMlRuntime` field — `src/v2/model.ts:1179` +### 22. `useMlRuntime` field — `src/v2/model.ts:1179` - **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. - **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). - **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. - **Rationale:** A boolean and an enum jointly describing one runtime selection is a smell. -### 31. `isSingleNode` field — `src/v2/model.ts:1185` +### 23. `isSingleNode` field — `src/v2/model.ts:1185` - **Why weird:** Boolean field that, when true, automatically sets `custom_tags`, `spark_conf`, and `num_workers`. Doc admits the surprise: "When set to true, Databricks will automatically set single node related custom_tags, spark_conf, and num_workers." A field that secretly mutates three others is a footgun. - **Category:** 6 (misleading — hidden side effects). - **Suggested name:** Name is fine, but document the side effects in the type-level JSDoc, not just the field doc. - **Rationale:** Flag for upstream — the boolean is doing more than the name suggests. -### 32. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields +### 24. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields - **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. - **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). - **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. - **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. -### 33. `nodeTypeId` vs `instanceTypeId` — `src/v2/model.ts:1076,2321,2350` +### 25. `nodeTypeId` vs `instanceTypeId` — `src/v2/model.ts:1076,2321,2350` - **Why weird:** `nodeTypeId` (string) and `instanceTypeId` (string) appear on different types. `NodeType.instanceTypeId` and `NodeInstanceType.instanceTypeId` are described as "hardware identifier (e.g., r3.2xlarge in AWS)" — i.e., the AWS instance class. `nodeTypeId` is the Databricks node type ID. Easy to confuse the two. - **Category:** 19 (underspecified IDs — multiple "type" IDs coexisting). - **Suggested name:** Either prefix one (`databricksNodeTypeId` / `cloudInstanceTypeId`) or rename `instanceTypeId` to `cloudInstanceTypeId` everywhere. - **Rationale:** Two `*TypeId` fields side by side, distinguished only by `node` vs `instance`. Real users will get this wrong. -### 34. `driverNodeTypeId` / `nodeTypeId` / `driverInstancePoolId` / `instancePoolId` — `src/v2/model.ts:1076,1085,1148,1160` +### 26. `driverNodeTypeId` / `nodeTypeId` / `driverInstancePoolId` / `instancePoolId` — `src/v2/model.ts:1076,1085,1148,1160` - **Why weird:** Pattern is "`driverX` and `X`" where `X` is the worker version. Four such pairs across the spec (`nodeTypeId`/`driverNodeTypeId`, `instancePoolId`/`driverInstancePoolId`, `nodeTypeFlexibility`/`driverNodeTypeFlexibility` — but the worker version is called `workerNodeTypeFlexibility` while the worker-`nodeTypeId` is just `nodeTypeId`). - **Category:** 17 (inconsistent pairing — sometimes worker is prefix-less, sometimes prefixed `worker`). - **Suggested name:** Either always prefix worker (`workerNodeTypeId`, `workerInstancePoolId`, `workerNodeTypeFlexibility`) or never (drop `worker` from `workerNodeTypeFlexibility`). - **Rationale:** Reader who sees `driverNodeTypeId` next to `nodeTypeId` has to remember that the un-prefixed one is "worker"; then sees `workerNodeTypeFlexibility` and gets thrown. -### 35. `NodeType.numCores` vs `ClusterInfo.clusterCores` — `src/v2/model.ts:2346,992` +### 27. `NodeType.numCores` vs `ClusterInfo.clusterCores` — `src/v2/model.ts:2346,992` - **Why weird:** Same concept (number of CPU cores) appears as `numCores` on `NodeType` and `clusterCores` on `ClusterInfo`. The `num` prefix is inconsistent with the bare `clusterCores`. - **Category:** 17 (inconsistent prefix), 1 (`num` is vague compared to the rest of the model). - **Suggested name:** `cores` (on `NodeType`) and `clusterCores` stays (or both `cores`/`totalCores`). - **Rationale:** Compare to `clusterMemoryMb` (no `num` prefix), `memoryMb` (no `num` prefix). `numCores` and `numGpus` are the outliers. -### 36. `NodeType.numGpus` — `src/v2/model.ts:2366` -- **Why weird:** Same `num` prefix issue as #35. Sibling fields don't carry a `num` prefix (`memoryMb`, `localDisks`, `category`). +### 28. `NodeType.numGpus` — `src/v2/model.ts:2366` +- **Why weird:** Same `num` prefix issue as #27. Sibling fields don't carry a `num` prefix (`memoryMb`, `localDisks`, `category`). - **Category:** 17 (inconsistent prefix), 1. - **Suggested name:** `gpus` (or `gpuCount`). - **Rationale:** Internal consistency. -### 37. `NodeInstanceType.localDisks` and `NodeInstanceType.localNvmeDisks` are counts — `src/v2/model.ts:2323,2329` +### 29. `NodeInstanceType.localDisks` and `NodeInstanceType.localNvmeDisks` are counts — `src/v2/model.ts:2323,2329` - **Why weird:** Plural noun `localDisks` is typed as `number`, but JSDoc says "Number of local disks that are present on this instance." Counting things should use `count`/`num` suffix, not the plural noun. - **Category:** 9 (singular vs plural confusion — the plural noun is actually a count). - **Suggested name:** `localDiskCount`, `localNvmeDiskCount`. - **Rationale:** A reader sees `localDisks: number` and might assume "array of local disks" — then realises it's a scalar. -### 38. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2325,2327` +### 30. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2325,2327` - **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. - **Category:** 17 (inconsistent grouping). - **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. - **Rationale:** Within the same type, related fields should sit together. -### 39. `ListAvailableZones_Response.defaultZone` — `src/v2/model.ts:2224` +### 31. `ListAvailableZonesResponse.defaultZone` — `src/v2/model.ts:2224` - **Why weird:** JSDoc says "The availability zone if no `zone_id` is provided in the cluster creation request." The doc references `zone_id` (the wire name) instead of the TS `zoneId`. Other docstrings in the package also reference `zone_id`, `cluster_id`, `cluster_log_conf`, `init_scripts`, etc. - **Category:** Observation — generated docs reference wire names rather than TS names. - **Suggested name:** Update doc-comment generation to use TS names. - **Rationale:** Inconsistent doc/identifier pairing makes IntelliSense suggestions look out-of-date. -### 40. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2295` +### 32. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2295` - **Why weird:** `LogAnalyticsInfo` has two fields (`logAnalyticsWorkspaceId`, `logAnalyticsPrimaryKey`), both un-documented. The type itself has no JSDoc. Used only by `AzureAttributes.logAnalyticsInfo`. - **Category:** Observation (no naming issue per se, but missing context). - **Suggested name:** Keep `LogAnalyticsInfo` (Azure Monitor terminology) but add a JSDoc; consider `AzureLogAnalyticsConfig`. - **Rationale:** Both fields are Azure-specific; naming should signal that. -### 41. `LogSyncStatus.lastException: string` — `src/v2/model.ts:2311` +### 33. `LogSyncStatus.lastException: string` — `src/v2/model.ts:2311` - **Why weird:** Field name is `lastException` (singular: the previous exception) but the type is `string`. JS exceptions are usually serialised as messages; a more accurate name would be `lastExceptionMessage`. - **Category:** 1 (vague — `Exception` is overloaded), 16 (type contradicts the name domain). - **Suggested name:** `lastErrorMessage` or `lastExceptionMessage`. - **Rationale:** Distinguishes an Error object reference from its serialised string form. -### 42. `LogSyncStatus.lastAttempted: number` — `src/v2/model.ts:2306` +### 34. `LogSyncStatus.lastAttempted: number` — `src/v2/model.ts:2306` - **Why weird:** `lastAttempted` is a verb-past-participle, type is `number` (epoch millis per JSDoc). Hard to tell from the name that this is a timestamp. - **Category:** 1 (vague), 6 (misleading — sounds like a boolean or count). - **Suggested name:** `lastAttemptedAt`, `lastAttemptTime`, `lastAttemptedMs`. - **Rationale:** Match the timestamp-suffix convention used elsewhere in this model (`startTime`, `terminatedTime`, `lastRestartedTime`, `lastStateLossTime`). -### 43. `ClusterInfo.startTime`/`terminatedTime`/`lastStateLossTime`/`lastRestartedTime` — `src/v2/model.ts:1194-1200` -- **Why weird:** Four sibling timestamps. `startTime` and `terminatedTime` use different shapes (`start` + `Time` vs `terminated` + `Time`); `lastStateLossTime` and `lastRestartedTime` use past participle + `Time`. Mix of forms. Also `LogSyncStatus.lastAttempted` (#42) drops the `Time` suffix entirely. +### 35. `ClusterInfo.startTime`/`terminatedTime`/`lastStateLossTime`/`lastRestartedTime` — `src/v2/model.ts:1194-1200` +- **Why weird:** Four sibling timestamps. `startTime` and `terminatedTime` use different shapes (`start` + `Time` vs `terminated` + `Time`); `lastStateLossTime` and `lastRestartedTime` use past participle + `Time`. Mix of forms. Also `LogSyncStatus.lastAttempted` (#34) drops the `Time` suffix entirely. - **Category:** 17 (inconsistent timestamp suffix), 13 (verb-tense inconsistency: `start` vs `terminated` vs `restarted`). - **Suggested name:** Choose one suffix (`-At`, `-Time`, `-Ms`) and apply uniformly: `startedAt`, `terminatedAt`, `lastStateLostAt`, `lastRestartedAt`, `lastAttemptedAt`. - **Rationale:** Timestamp suffixes are a high-impact, low-cost consistency win. -### 44. `SparkInfo_SparkNode.startTimestamp` — `src/v2/model.ts:2521` -- **Why weird:** Same node-related concept as `ClusterInfo.startTime` (#43) but uses `Timestamp` rather than `Time`. Different word for the same idea. +### 36. `SparkNode.startTimestamp` — `src/v2/model.ts:2521` +- **Why weird:** Same node-related concept as `ClusterInfo.startTime` (#35) but uses `Timestamp` rather than `Time`. Different word for the same idea. - **Category:** 17 (inconsistent across types). - **Suggested name:** `startTime` (or align all timestamps under one suffix). - **Rationale:** Two timestamp suffixes in the same file is two too many. -### 45. `creatorUserName` field — `src/v2/model.ts:977` +### 37. `creatorUserName` field — `src/v2/model.ts:977` - **Why weird:** TS camelCase splits `User` and `Name` (`creatorUserName`) but the conceptually-similar `singleUserName` does the same. Compare to `ownerUsername` (one word) on `ChangeClusterOwner`. Inconsistency between three sibling concepts. Documented behaviour: "The field won't be included in the response if the user has already been deleted" — but no `undefined` annotation distinguishes "absent because new" from "absent because deleted". -- **Category:** 3 (casing inconsistency), see also #27. +- **Category:** 3 (casing inconsistency), see also #19. - **Suggested name:** `creatorUsername`. -- **Rationale:** Already covered in #27; flagged again because it appears on the main `ClusterInfo` type which dominates user reading time. +- **Rationale:** Already covered in #19; flagged again because it appears on the main `ClusterInfo` type which dominates user reading time. -### 46. `clusterLogStatus` field — `src/v2/model.ts:1008` +### 38. `clusterLogStatus` field — `src/v2/model.ts:1008` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). - **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. - **Rationale:** Same concept, two different names in 5 lines. -### 47. `jdbcPort` field — `src/v2/model.ts:1036` +### 39. `jdbcPort` field — `src/v2/model.ts:1036` - **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). -- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #48). +- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #40). -### 48. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` +### 40. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` - **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. - **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. -### 49. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:2491` +### 41. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:2491` - **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. - **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). - **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. - **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. -### 50. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:2474,2479,2481` +### 42. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:2474,2479,2481` - **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. - **Category:** 12 (duplicate concepts), 17 (could be a tagged union). - **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). - **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. -### 51. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:2464,2469` +### 43. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:2464,2469` - **Why weird:** JSDoc explicitly says "Either region or endpoint needs to be set. If both are set, endpoint will be used." Mutually-exclusive fields not encoded in the type. - **Category:** 16 (field-pair constraint not in the type). - **Suggested name:** Could be a discriminated union `{kind: 'region', value: string} | {kind: 'endpoint', value: string}`. @@ -325,145 +277,145 @@ ## Low severity -### 52. `ClusterInfo.spec?: ClusterInfo_ComputeSpec` field name — `src/v2/model.ts:1018` -- **Why weird:** Field is just `spec`; type is `ClusterInfo_ComputeSpec`. Field name is very short. -- **Category:** 1 (vague — `spec` alone could mean anything), 8 (type-suffix tautology: `clusterInfo.spec` of type `ComputeSpec`). +### 44. `ClusterInfo.spec` field name — `src/v2/model.ts:1018` +- **Why weird:** Field is just `spec`. Very short for a top-level field on the main cluster type; reader has to follow the type to learn what kind of spec it is. +- **Category:** 1 (vague — `spec` alone could mean anything). - **Suggested name:** `computeSpec` or `clusterSpec`. -- **Rationale:** Once the type is renamed (#17), this falls out naturally. +- **Rationale:** A more specific field name documents intent at the call site without forcing the reader to chase the type. -### 53. `ClusterInfo.driver: SparkInfo_SparkNode` field — `src/v2/model.ts:1023` -- **Why weird:** Field name is `driver` (vague — could mean a person or an Apache driver concept). Type `SparkInfo_SparkNode` (which is itself awkward). Better: `driverNode: SparkNode`. +### 45. `ClusterInfo.driver` field — `src/v2/model.ts:1023` +- **Why weird:** Field name is `driver` — overloaded (could mean a person or an Apache Spark driver concept). Better: `driverNode`. - **Category:** 1 (vague). - **Suggested name:** `driverNode`. - **Rationale:** Reader sees `driver` and has to know to follow the type. -### 54. `ClusterInfo.executors: SparkInfo_SparkNode[]` field — `src/v2/model.ts:1025` -- **Why weird:** Same as #53. `executors` is fine in Spark vocabulary but better paired: `executorNodes: SparkNode[]`. +### 46. `ClusterInfo.executors` field — `src/v2/model.ts:1025` +- **Why weird:** Same as #45. `executors` is fine in Spark vocabulary but better paired with `driverNode`: `executorNodes`. - **Category:** 17 (inconsistent with `driver`). - **Suggested name:** `executorNodes`. - **Rationale:** Match the `driver`/`executor` pattern. -### 55. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1145,1340,1662,1914,2723` +### 47. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1145,1340,1662,1914,2723` - **Why weird:** JSDoc abbreviation `BYOC` (Bring Your Own Container) used without expansion. Appears five times in the model. - **Category:** 5 (cryptic abbreviation in JSDoc). - **Suggested name:** N/A — fix the comment, not the identifier. - **Rationale:** Quick doc fix. -### 56. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1031` +### 48. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1031` - **Why weird:** Field is named `sparkContextId` but typed as `number`. Other IDs in the model are strings (`clusterId`, `policyId`, `nodeTypeId`). Internal Spark context IDs are 64-bit ints — the type clash hints at potential JS number-precision issues for large IDs. - **Category:** 19 (underspecified ID — different type from sibling IDs). - **Suggested name:** Keep but consider `bigint` typing or document the precision risk. - **Rationale:** JS number safe-integer range is 2^53; if Spark uses 64-bit IDs, this is a latent bug. -### 57. `DockerImage.credsOneof` field name — `src/v2/model.ts:1768` +### 49. `DockerImage.credsOneof` field name — `src/v2/model.ts:1768` - **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. - **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). - **Suggested name:** `credentials` (singular). - **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. -### 58. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:1759,1761` +### 50. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:1759,1761` - **Why weird:** Doc strings are "Name of the user" and "Password of the user" — generic and add no information beyond the field names. - **Category:** Observation (low-quality docstrings). - **Suggested name:** No rename; flag doc-quality. - **Rationale:** Minor. -### 59. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:864` +### 51. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:864` - **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:924`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. - **Category:** 17 (sibling AWS/Azure shapes differ), 1 (`number` without unit suffix). - **Suggested name:** `spotBidPricePercent` is fine; flag for upstream — the AWS/Azure semantics should be more discoverable from the model. - **Rationale:** Cross-cloud asymmetry is a domain concern. -### 60. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:923` +### 52. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:923` - **Why weird:** Magic value `-1` overloaded as "do not evict on price basis". Encoded in JSDoc, not in the type. - **Category:** 16 (sentinel value in scalar field), Observation. - **Suggested name:** N/A; flag for upstream to consider a sentinel enum or `null`. - **Rationale:** Sentinels in scalar fields are old-school API design. -### 61. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2051` +### 53. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2051` - **Why weird:** JSDoc says "Note: Soon to be deprecated, use the 'availability' field instead." But the field is not actually marked `@deprecated`. - **Category:** Observation — missing `@deprecated`. - **Suggested name:** Add `@deprecated` JSDoc tag. - **Rationale:** Tooling can pick up `@deprecated`; "Note: Soon to be deprecated" is invisible to IDEs. -### 62. `GcpAttributes.googleServiceAccount: string` — `src/v2/model.ts:2058` +### 54. `GcpAttributes.googleServiceAccount: string` — `src/v2/model.ts:2058` - **Why weird:** Field `googleServiceAccount` lives on `GcpAttributes`. The `google` prefix is redundant — sibling fields don't say `googleZoneId`, `googleAvailability`, `googleBootDiskSize`. - **Category:** 17 (inconsistent prefix within `GcpAttributes`). - **Suggested name:** `serviceAccount` (drop the `google` prefix). - **Rationale:** Internal consistency; the type's name already says GCP. -### 63. `GcpAttributes.bootDiskSize: number` — `src/v2/model.ts:2060` +### 55. `GcpAttributes.bootDiskSize: number` — `src/v2/model.ts:2060` - **Why weird:** Doc says "Boot disk size in GB" but field has no unit suffix. Compare `ebsVolumeSize`/`ebsVolumeIops`/`ebsVolumeThroughput` (no unit suffixes either) and `remoteDiskThroughput` (`Mb/s` per doc, no suffix). Pattern is "no unit suffix" — but `clusterMemoryMb`, `memoryMb`, `localDiskSizeGb` DO have unit suffixes. Inconsistent. - **Category:** 17 (inconsistent unit-suffix convention). - **Suggested name:** `bootDiskSizeGb`. - **Rationale:** Match the `*Mb`, `*Gb` pattern used on the same struct hierarchy. -### 64. `GcpAttributes.localSsdCount: number` field with prose comment — `src/v2/model.ts:2082` +### 56. `GcpAttributes.localSsdCount: number` field with prose comment — `src/v2/model.ts:2082` - **Why weird:** Field is named `localSsdCount`; sibling `bootDiskSize` is unsuffixed; `firstOnDemand` is also unsuffixed. Three different "amount" fields, three different suffix conventions. - **Category:** 17 (inconsistent quantity suffix). - **Suggested name:** Either all carry `Count`/`Size`/`Mb` etc. or none do. - **Rationale:** Within `GcpAttributes`, `localSsdCount` carries a `Count` suffix while `firstOnDemand` (also a count) does not. -### 65. `firstOnDemand` field name — `src/v2/model.ts:829,911,2092` +### 57. `firstOnDemand` field name — `src/v2/model.ts:829,911,2092` - **Why weird:** Used on `AwsAttributes`, `AzureAttributes`, `GcpAttributes`. Reads as "first on-demand what?". Doc says "The first `first_on_demand` nodes of the cluster will be placed on on-demand instances" — meta-circular. - **Category:** 1 (vague), 7 (no noun). - **Suggested name:** `firstOnDemandNodes` or `onDemandNodeCount`. - **Rationale:** The name is missing the noun it describes. -### 66. `ChangeClusterOwner.ownerUsername` field docstring — `src/v2/model.ts:929` +### 58. `ChangeClusterOwner.ownerUsername` field docstring — `src/v2/model.ts:929` - **Why weird:** Doc says "New owner of the cluster_id after this RPC." `RPC` jargon leaks. `cluster_id` is the wire name; should be `clusterId`. - **Category:** Observation (doc quality), 5 (RPC jargon). - **Suggested name:** Update doc text. - **Rationale:** Minor doc fix. -### 67. `ClusterCompliance.violations: Record` — `src/v2/model.ts:956` +### 59. `ClusterCompliance.violations: Record` — `src/v2/model.ts:956` - **Why weird:** Map from string (policy field path) to string (error message). Field name `violations` doesn't communicate the shape. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `violationsByField` or `fieldViolations`. - **Rationale:** Clarifies the map's semantics. -### 68. `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange.field: string` — `src/v2/model.ts:2027` +### 60. `ClusterSettingsChange.field: string` — `src/v2/model.ts:2027` - **Why weird:** Field on a "ClusterSettingsChange" is itself named `field`. Reads as `change.field` — circular. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `fieldPath` or `settingName`. - **Rationale:** Minor; flags pile up. -### 69. `EnforcePolicyComplianceForCluster_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2034,2041` +### 61. `ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2034,2041` - **Why weird:** Both fields typed as `string`. JSDoc says values are "either a number, a boolean, or a string converted to a string." Pre-stringified union encoded as plain string — caller must re-parse. - **Category:** 16 (type contradicts domain — it's actually `number | boolean | string` flattened to string). - **Suggested name:** Type as `string | number | boolean`, or `previousValueRaw`. - **Rationale:** Documents the stringification rather than hiding it. -### 70. `SparkVersion.key` / `name` — `src/v2/model.ts:2542,2544` +### 62. `SparkVersion.key` / `name` — `src/v2/model.ts:2542,2544` - **Why weird:** Two very generic field names; from `SparkVersion`, `key` is the version string and `name` is the display name. Inversion of typical (`name`=identifier, `displayName`=human-readable). - **Category:** 1 (vague), 6 (misleading). - **Suggested name:** `version`/`displayName` or `versionKey`/`label`. - **Rationale:** `key` is one of the most overloaded names in software. -### 71. `NodeType.key`-like fields — `nodeTypeId`, `instanceTypeId`, `description`, `category` — `src/v2/model.ts:2338-2390` +### 63. `NodeType.key`-like fields — `nodeTypeId`, `instanceTypeId`, `description`, `category` — `src/v2/model.ts:2338-2390` - **Why weird:** 20 fields on `NodeType`, several with vague names: `description`, `category`. No JSDoc on `displayOrder` until line 2374. Some fields are `is*` booleans (`isDeprecated`, `isHidden`, `isIoCacheEnabled`, `isEncryptedInTransit`, `isGraviton`), others are `support*` booleans (`supportEbsVolumes`, `supportClusterTags`, `supportPortForwarding`), others are `*Capable` booleans (`photonWorkerCapable`, `photonDriverCapable`). - **Category:** 17 (inconsistent boolean prefix: `is*`/`support*`/`*Capable`). - **Suggested name:** Pick one convention (`is*Supported`). - **Rationale:** Three different boolean-naming patterns on one struct. -### 72. `NodeType.supportEbsVolumes` field name — `src/v2/model.ts:2362` +### 64. `NodeType.supportEbsVolumes` field name — `src/v2/model.ts:2362` - **Why weird:** Singular verb `support` (third-person plural would be "supports"). All siblings: `supportClusterTags`, `supportPortForwarding`. Three fields use the singular form. - **Category:** 13 (verb tense — should be `supports`). - **Suggested name:** `supportsEbsVolumes`, `supportsClusterTags`, `supportsPortForwarding`. - **Rationale:** Subject-verb agreement in field names is common (`hasFoo`, `isFoo`, `supportsFoo`). -### 73. `NodeType.photonWorkerCapable` / `photonDriverCapable` — `src/v2/model.ts:2382,2383` +### 65. `NodeType.photonWorkerCapable` / `photonDriverCapable` — `src/v2/model.ts:2382,2383` - **Why weird:** No JSDoc. `*Capable` suffix is a different boolean convention from `is*`/`support*`. - **Category:** 17 (inconsistent boolean shape), Observation (missing doc). - **Suggested name:** `isPhotonWorkerSupported`, `isPhotonDriverSupported` (or `supportsPhotonAsWorker`). -- **Rationale:** Same pattern as #71. +- **Rationale:** Same pattern as #63. -### 74. `TerminationReason.parameters: Record` — `src/v2/model.ts:2561` +### 66. `TerminationReason.parameters: Record` — `src/v2/model.ts:2561` - **Why weird:** Generic-named map. `parameters` could mean anything. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `details`, `metadata`, `errorContext`. - **Rationale:** Clarifies the role of the map. -### 75. `AutoScale` type name — `src/v2/model.ts:805` +### 67. `AutoScale` type name — `src/v2/model.ts:805` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). @@ -471,41 +423,41 @@ ## Observations -### 76. Seven Waiter classes with identical shape — `client.ts:879-1435` -The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState_ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. +### 68. Seven Waiter classes with identical shape — `client.ts:879-1435` +The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. - **Category:** 12 (duplicate concept across seven classes), Observation. - **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. -### 77. `_req` parameter for empty request types — `client.ts:343,422,447` +### 69. `_req` parameter for empty request types — `client.ts:343,422,447` Several methods take a `_req: ListAvailableZones` / `_req: ListNodeTypes` / `_req: GetSparkVersions` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. - **Category:** Observation (generator artefact). -### 78. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` +### 70. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` - **Why weird:** Three sibling booleans use `enable*` prefix. `is*` is the more idiomatic JS boolean convention. Inconsistent with `isSingleNode`, `isCompliant`, `isDeprecated`. - **Category:** 17 (mixed `enable*` and `is*` for booleans). - **Rationale:** Naming-convention drift. -### 79. `ResizeCluster` / `RestartCluster` requests are partial overlaps +### 71. `ResizeCluster` / `RestartCluster` requests are partial overlaps `ResizeCluster` carries `clusterId` and `size`; `RestartCluster` carries `clusterId` and `restartUser`; `StartCluster` carries only `clusterId`. Three near-identical types; could be one. - **Category:** 12 (duplicate concept), Observation. -### 80. `_req` unused vs `req` used — inconsistency in method-signature lint +### 72. `_req` unused vs `req` used — inconsistency in method-signature lint Five client methods use `_req` (where the request type is empty), 15 use `req` (where it's not). Pure mechanical. - **Category:** Observation. -### 81. `clusterId?: string | undefined` shape +### 73. `clusterId?: string | undefined` shape Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:204,246,296,565,604,651,729`). - **Category:** 6 (misleading optional — should be required), Observation. -### 82. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) +### 74. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). - **Category:** 1 (vague), 17 (inconsistent), Observation. -### 83. `flattenQueryParams` exported but unused (`utils.ts:123`) +### 75. `flattenQueryParams` exported but unused (`utils.ts:123`) The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. - **Category:** Observation (dead public surface). -### 84. JSDoc placeholder `` — pervasive +### 76. JSDoc placeholder `` — pervasive Throughout the model, JSDocs say `` (e.g., `model.ts:1097` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. - **Category:** Observation (doc-quality artefact in generator). diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index d83ea30d..8ca1efdd 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -24,44 +24,42 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | 1 | high | 2. Redundant enum prefix | `model.ts:21-29` | `CommandStatus.COMMAND_*` | `CommandStatus.Cancelled`, etc. | | 2 | high | 2. Redundant enum prefix | `model.ts:31-36` | `ContextStatus.CONTEXT_*` | `ContextStatus.Running`, etc. | | 3 | high | 2. Redundant enum prefix + 18. Long enum values | `model.ts:46-53` | `ResultType.*_RESULT` | `ResultType.Error`, etc. | -| 4 | high | 4. Underscores in TS identifiers | `model.ts:22,32,39,47` | `*_UNSPECIFIED` enum members | Omit altogether (idiomatic TS) | -| 5 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | -| 6 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | -| 7 | high | 15. Generic field on container | `model.ts:71`, `model.ts:100,112` | `id?: string` (three different IDs) | `contextId`, `commandId` (typed by domain) | -| 8 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | -| 9 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | -| 10 | high | 1. Vague/generic | `model.ts:89` | `command?: string` (field, inside `ExecuteCommandRequest`) | `code` | -| 11 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | -| 12 | medium | 9. Singular/plural mismatch | `model.ts:102,116-143` | `results?: Results` (`Results` is one object) | `result?: Result` | -| 13 | medium | 1. Vague/generic | `model.ts:119` | `data?: JsonValue` | Inline rename to domain (e.g. `tableData`), or document semantics | -| 14 | medium | 16. Field contradicts type domain | `model.ts:129,131` | `fileName`, `fileNames` (used for image data URLs) | `imageData`, `imageDataList` (or `image`, `images`) | -| 15 | medium | 1. Vague/generic | `model.ts:135` | `pos?: number` | `position` (also rename comment to public-friendly) | -| 16 | medium | 1. Vague/generic | `model.ts:138` | `schema?: JsonObject[]` | `tableSchema` (qualify what schema) | -| 17 | medium | 19. Underspecified IDs | `model.ts:71,100,112` | `id?: string` | `contextId` / `commandId` per response | -| 18 | medium | 19. Underspecified IDs | `client.ts:336,337,338` | `clusterId`, `contextId`, `commandId` (fine, but match in `Results.id`) | Audit pass for consistency | -| 19 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | -| 20 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | -| 21 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to present participle or to noun (e.g. `Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, `Running`) | -| 22 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | -| 23 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | -| 24 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 25 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 26 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 27 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 28 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 29 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 30 | medium | 18. Long enum values | `model.ts:22-28` | `COMMAND_STATUS_UNSPECIFIED` | Drop the `*_UNSPECIFIED` sentinel in TS (TS represents absence via `undefined`) | -| 31 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | -| 32 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | -| 33 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | -| 34 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | -| 35 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | -| 36 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #16 | -| 37 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | -| 38 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #10 | -| 39 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 40 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | -| 41 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #14 | +| 4 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | +| 5 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | +| 6 | high | 15. Generic field on container | `model.ts:71`, `model.ts:100,112` | `id?: string` (three different IDs) | `contextId`, `commandId` (typed by domain) | +| 7 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | +| 8 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | +| 9 | high | 1. Vague/generic | `model.ts:89` | `command?: string` (field, inside `ExecuteCommandRequest`) | `code` | +| 10 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | +| 11 | medium | 9. Singular/plural mismatch | `model.ts:102,116-143` | `results?: Results` (`Results` is one object) | `result?: Result` | +| 12 | medium | 1. Vague/generic | `model.ts:119` | `data?: JsonValue` | Inline rename to domain (e.g. `tableData`), or document semantics | +| 13 | medium | 16. Field contradicts type domain | `model.ts:129,131` | `fileName`, `fileNames` (used for image data URLs) | `imageData`, `imageDataList` (or `image`, `images`) | +| 14 | medium | 1. Vague/generic | `model.ts:135` | `pos?: number` | `position` (also rename comment to public-friendly) | +| 15 | medium | 1. Vague/generic | `model.ts:138` | `schema?: JsonObject[]` | `tableSchema` (qualify what schema) | +| 16 | medium | 19. Underspecified IDs | `model.ts:71,100,112` | `id?: string` | `contextId` / `commandId` per response | +| 17 | medium | 19. Underspecified IDs | `client.ts:336,337,338` | `clusterId`, `contextId`, `commandId` (fine, but match in `Results.id`) | Audit pass for consistency | +| 18 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | +| 19 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | +| 20 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to present participle or to noun (e.g. `Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, `Running`) | +| 21 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | +| 22 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | +| 23 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 24 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 25 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 26 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 27 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 28 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 29 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | +| 30 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | +| 31 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | +| 32 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | +| 33 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | +| 34 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #15 | +| 35 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | +| 36 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #9 | +| 37 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 38 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 39 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #13 | --- @@ -85,7 +83,7 @@ Every member begins with `COMMAND_`. At a callsite this becomes namespacing already makes the prefix redundant. **Proposed:** strip the `COMMAND_` prefix; use idiomatic PascalCase: `CommandStatus.Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, -`Running`. (See also #5 for casing.) +`Running`. (See also #4 for casing.) --- @@ -119,26 +117,11 @@ export enum ResultType { Members carry `_RESULT` suffix; the enum is *already* called `ResultType`. Tautology. **Proposed:** `ResultType.Error`, `Image`, `Images`, `Table`, `Text` (see also -#5 for casing; #4 for sentinel). +#4 for casing). --- -### Finding 4 — High — Cat 4 (Underscores) + redundancy -**Location:** all four enums. -**Issue:** `*_UNSPECIFIED` sentinel members on every enum -(`COMMAND_STATUS_UNSPECIFIED`, `CONTEXT_STATUS_UNSPECIFIED`, -`LANGUAGE_UNSPECIFIED`, `RESULT_TYPE_UNSPECIFIED`). Sentinel-style -"unspecified" values come from protobuf/Go and have no TypeScript audience -— TS uses `undefined` natively. They surface in `?: Status | undefined` -fields, so consumers will either ignore them or accidentally compare against -them. -**Proposed:** omit the `*_UNSPECIFIED` members from the TS-facing enum; the -wire-level deserialiser may still tolerate them, but the public type should -not advertise a "no value selected" *value*. - ---- - -### Finding 5 — High — Cat 4 (Underscores in TS identifiers) +### Finding 4 — High — Cat 4 (Underscores in TS identifiers) **Location:** every enum member in `model.ts:22-53`. **Issue:** TS identifier convention is PascalCase for type-namespace members. `COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`, `SCALA` are all @@ -160,7 +143,7 @@ export enum CommandStatus { --- -### Finding 6 — High — Cat 12 (Duplicate concepts) +### Finding 5 — High — Cat 12 (Duplicate concepts) **Location:** `src/v2/model.ts:70` and `src/v2/client.ts:289` ```ts export interface CreateResponse { @@ -176,11 +159,11 @@ shared shape is incidental, not semantic. Reusing the type forces a caller reading `response.id` to know the operation to interpret it. **Proposed:** split into `CreateContextResponse { contextId?: string }` and `ExecuteCommandResponse { commandId?: string }`. Each typed `id` field by -its true domain (see #7/#17). +its true domain (see #6/#16). --- -### Finding 7 — High — Cat 15 (Generic field loses meaning) +### Finding 6 — High — Cat 15 (Generic field loses meaning) **Location:** `src/v2/model.ts:71, 100, 112` ```ts export interface CreateResponse { id?: string | undefined; } @@ -189,14 +172,14 @@ export interface GetContextStatusResponse { id?: string | undefined; ... } ``` The field name `id` is meaning-free outside its container, and the container's name doesn't disambiguate (`CreateResponse` is used for two -different create-like operations — see #6). A caller writing `resp.id` +different create-like operations — see #5). A caller writing `resp.id` cannot tell whether it is a command id or a context id. **Proposed:** rename per-response: `contextId` / `commandId`. This couples the schema to the resource, eliminating ambiguity. --- -### Finding 8 — High — Cat 17 (Inconsistent action verbs) +### Finding 7 — High — Cat 17 (Inconsistent action verbs) **Location:** `src/v2/client.ts:256` ```ts /** Deletes an execution context. */ @@ -211,7 +194,7 @@ align with the Go SDK convention. At minimum, edit the JSDoc to say --- -### Finding 9 — High — Cat 17 (Inconsistent action verbs) +### Finding 8 — High — Cat 17 (Inconsistent action verbs) **Location:** `src/v2/client.ts:139, 176` ```ts async commandStatus(req: GetCommandStatusRequest, ...) @@ -226,7 +209,7 @@ the request-type name and is verb-led like the other methods. --- -### Finding 10 — High — Cat 1 & Cat 15 (Vague / generic field name) +### Finding 9 — High — Cat 1 & Cat 15 (Vague / generic field name) **Location:** `src/v2/model.ts:89` ```ts /** Executable code */ @@ -242,7 +225,7 @@ also matches the conceptual model: a `Command` *contains* `code`. --- -### Finding 11 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +### Finding 10 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) **Location:** `src/v2/model.ts:117-143` ```ts export interface Results { ... } @@ -252,22 +235,22 @@ result — a single `cause`, single `summary`, single `resultType`, single `data` object. The plurality comes from the wire-level `fileNames` array inside it, not from multiple results. **Proposed:** rename to `Result` (singular). The field -`GetCommandStatusResponse.results` becomes `result` (see #12). +`GetCommandStatusResponse.results` becomes `result` (see #11). --- -### Finding 12 — Medium — Cat 9 (Singular/plural mismatch) +### Finding 11 — Medium — Cat 9 (Singular/plural mismatch) **Location:** `src/v2/model.ts:102` (field) and `model.ts:116` (type) ```ts results?: Results | undefined; ``` -Pairs with #11. The field name and the type are both pluralised but +Pairs with #10. The field name and the type are both pluralised but represent a singular result. -**Proposed:** `result?: Result;` once #11 is applied. +**Proposed:** `result?: Result;` once #10 is applied. --- -### Finding 13 — Medium — Cat 1 (Vague/generic) +### Finding 12 — Medium — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:119` ```ts data?: JsonValue | undefined; @@ -281,7 +264,7 @@ returned by the command. --- -### Finding 14 — Medium — Cat 16 (Field contradicts type domain) +### Finding 13 — Medium — Cat 16 (Field contradicts type domain) **Location:** `src/v2/model.ts:129, 131` ```ts /** The image data in one of the following formats: @@ -301,7 +284,7 @@ is a public API; mis-named fields will outlive their fix window. --- -### Finding 15 — Medium — Cat 1 (Cryptic abbreviation / vague) +### Finding 14 — Medium — Cat 1 (Cryptic abbreviation / vague) **Location:** `src/v2/model.ts:135` ```ts /** internal field used by SDK */ @@ -314,7 +297,7 @@ public interface entirely. Internal fields belong on private types. --- -### Finding 16 — Medium — Cat 1 (Vague/generic) +### Finding 15 — Medium — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:138` ```ts /** The table schema */ @@ -328,25 +311,25 @@ populated for non-table result types. --- -### Finding 17 — Medium — Cat 19 (Underspecified IDs) +### Finding 16 — Medium — Cat 19 (Underspecified IDs) **Location:** `src/v2/model.ts:71, 100, 112` -**Issue:** Same as #7. Every response that carries an identifier uses +**Issue:** Same as #6. Every response that carries an identifier uses `id?: string` with no domain qualifier. **Proposed:** Rename per-response (`contextId`, `commandId`). Public-API clarity outweighs minor breakage. --- -### Finding 18 — Medium — Cat 19 (Underspecified IDs) — consistency only +### Finding 17 — Medium — Cat 19 (Underspecified IDs) — consistency only **Location:** `src/v2/client.ts:336-338, 417-422, 498-503` (Waiter fields) **Issue:** Waiter classes correctly use `clusterId`, `contextId`, -`commandId`. The inconsistency is only in `Results` / `*Response` (#7/#17). +`commandId`. The inconsistency is only in `Results` / `*Response` (#6/#16). **Proposed:** apply the same explicit-id pattern to all response types so the public surface is uniform. --- -### Finding 19 — Medium — Cat 7 (Overly verbose) +### Finding 18 — Medium — Cat 7 (Overly verbose) **Location:** `src/v2/model.ts:99, 111` ```ts export interface GetCommandStatusResponse { ... } @@ -360,7 +343,7 @@ returned", not "the response to a GET". --- -### Finding 20 — Medium — Cat 20 (Type-suffix tautology) — call-out only +### Finding 19 — Medium — Cat 20 (Type-suffix tautology) — call-out only **Location:** `src/v2/model.ts:55, 64, 74, 82, 93, 106` ```ts CancelCommandRequest, CreateContextRequest, DestroyContextRequest, @@ -373,7 +356,7 @@ convention is widely accepted across REST SDKs. --- -### Finding 21 — Medium — Cat 13 (Verb-tense inconsistency) +### Finding 20 — Medium — Cat 13 (Verb-tense inconsistency) **Location:** `src/v2/model.ts:23-28` ```ts COMMAND_CANCELLED // past participle @@ -390,7 +373,7 @@ COMMAND_RUNNING // present participle --- -### Finding 22 — Medium — Cat 3 (Acronym casing) +### Finding 21 — Medium — Cat 3 (Acronym casing) **Location:** `src/v2/model.ts:133` ```ts isJsonSchema?: boolean | undefined; @@ -403,14 +386,14 @@ recorded in `.agent/rules/typescript.mdc`. --- -### Finding 23 — Medium — Cat 12 (Duplicate concepts) +### Finding 22 — Medium — Cat 12 (Duplicate concepts) **Location:** `src/v2/client.ts:286-309` **Issue:** `execute()` returns `Promise`. The conflation -of "create a context" and "execute returns an id" is artificial. See #6. +of "create a context" and "execute returns an id" is artificial. See #5. --- -### Finding 24 — Medium — Cat 14 (Go/Java-style names) +### Finding 23 — Medium — Cat 14 (Go/Java-style names) **Location:** `src/v2/model.ts:74` + `client.ts:256` **Issue:** `destroy` is unusual for a REST SDK. JS conventions favour `delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend @@ -421,15 +404,15 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 25 — Medium — Cat 8 (Redundant suffix) — call-out +### Finding 24 — Medium — Cat 8 (Redundant suffix) — call-out **Location:** `src/v2/client.ts:333, 417, 498` **Issue:** Three classes named `*Waiter`. Acceptable if waiter is a recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #26-#28. +issue is what they wait *for*: see #25-#27. --- -### Finding 26 — Medium — Cat 6 (Misleading name) +### Finding 25 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:417` ```ts export class CreateWaiter { ... } @@ -444,21 +427,21 @@ target endpoint). --- -### Finding 27 — Medium — Cat 6 (Misleading name) +### Finding 26 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:333` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 28 — Medium — Cat 6 (Misleading name) +### Finding 27 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:498` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. --- -### Finding 29 — Medium — Cat 17 (Inconsistent action verbs) — call-out +### Finding 28 — Medium — Cat 17 (Inconsistent action verbs) — call-out **Location:** `src/v2/client.ts:86, 256` **Issue:** This package uses three lifecycle verbs: - `cancel()` on a command, @@ -471,17 +454,7 @@ Go-SDK alignment decision. --- -### Finding 30 — Medium — Cat 18 (Long enum values) -**Location:** `src/v2/model.ts:22, 32, 39, 47` -**Issue:** `COMMAND_STATUS_UNSPECIFIED`, `CONTEXT_STATUS_UNSPECIFIED`, -`LANGUAGE_UNSPECIFIED`, `RESULT_TYPE_UNSPECIFIED`. Long sentinel value -strings expose the protobuf convention to JS consumers. TS uses -`undefined` for unspecified. -**Proposed:** drop the members entirely (see #4). - ---- - -### Finding 31 — Low — Cat 1 (Vague/generic) +### Finding 29 — Low — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:117-118` ```ts /** The cause of the error */ @@ -495,18 +468,18 @@ sub-object; or keep flat and document conditional presence. --- -### Finding 32 — Low — Cat 1 (Vague/generic) +### Finding 30 — Low — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:139-140` ```ts /** The summary of the error */ summary?: string | undefined; ``` -Same as #31. The field is generic; the JSDoc reveals it's +Same as #29. The field is generic; the JSDoc reveals it's error-specific. --- -### Finding 33 — Low — Cat 1 (Underspecified) +### Finding 31 — Low — Cat 1 (Underspecified) **Location:** `src/v2/model.ts:141-142` ```ts /** true if partial results are returned. */ @@ -517,7 +490,7 @@ Acceptable but ambiguous: truncated *what*? table rows? text length? --- -### Finding 34 — Low — Cat 1 (Vague/generic) — call-out +### Finding 32 — Low — Cat 1 (Vague/generic) — call-out **Location:** `src/v2/client.ts:54` ```ts class StillRunningError extends Error {} @@ -526,7 +499,7 @@ Private, OK. Idiomatic for waiter polling patterns. --- -### Finding 35 — Low — Cat 3 (Acronym casing) — non-issue +### Finding 33 — Low — Cat 3 (Acronym casing) — non-issue **Location:** `src/v2/client.ts:49-52` ```ts const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; @@ -537,33 +510,33 @@ correctly cased per the project rules. --- -### Finding 36 — Low — Cat 10 (Reserved-word collision) — borderline +### Finding 34 — Low — Cat 10 (Reserved-word collision) — borderline **Location:** `src/v2/model.ts:138` **Issue:** `schema` is not a TS reserved word but is heavily aliased -across libraries (zod, JSON schema, table schema, GraphQL schema). See #16. +across libraries (zod, JSON schema, table schema, GraphQL schema). See #15. --- -### Finding 37 — Low — Cat 14 — non-issue +### Finding 35 — Low — Cat 14 — non-issue **Location:** `src/v2/client.ts:54` **Issue:** `StillRunningError` is named in idiomatic TS style (`*Error` suffix on classes extending Error). --- -### Finding 38 — Low — duplicate of #10 +### Finding 36 — Low — duplicate of #9 **Location:** `src/v2/model.ts:89` -Same finding as #10. +Same finding as #9. --- -### Finding 39 — Low — Cat 15 (Generic field) — call-out +### Finding 37 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. --- -### Finding 40 — Low — Cat 3 (Acronym casing in enum string values) +### Finding 38 — Low — Cat 3 (Acronym casing in enum string values) **Location:** `src/v2/model.ts:42-43` ```ts SQL = 'SQL', @@ -571,36 +544,35 @@ R = 'R', ``` Identifier `SQL` is all-caps (3 letters → standard "≤3 letter acronym all caps") in the language enum. `R` is single-letter — naturally all -caps. Apply the casing rule (#5) and these become `Sql` (if the rule is +caps. Apply the casing rule (#4) and these become `Sql` (if the rule is "acronyms PascalCase") or remain `SQL`/`R` (if "≤3 letters all caps"). **Proposed:** consult `typescript.mdc`; pick a rule and apply globally. --- -### Finding 41 — Low — duplicate of #14 +### Finding 39 — Low — duplicate of #13 **Location:** `src/v2/model.ts:131` -`fileNames?: string[]` for images — same as #14. +`fileNames?: string[]` for images — same as #13. --- ## Top Themes -1. **Wire-format leakage** — protobuf casing, `*_UNSPECIFIED` sentinels, - and redundant enum-prefix members all bleed from the source IDL into - the public TS surface. The fix is a project-wide style rule applied at - the generator level: - - PascalCase enum identifiers with wire-string values preserved; - - drop `*_UNSPECIFIED`. - -2. **Three-resource ambiguity** — `Cluster`, `Context`, `Command` are easy +1. **Three-resource ambiguity** — `Cluster`, `Context`, `Command` are easy to confuse, but the public types use the generic field `id` and reuse - `CreateResponse` for two unrelated operations. Findings #6, #7, #10, - #11, #12, #14, #17, #19, #26-#28 all stem from one decision: **never + `CreateResponse` for two unrelated operations. Findings #5, #6, #9, + #10, #11, #13, #16, #18, #25-#27 all stem from one decision: **never say "id" when "commandId" or "contextId" would do, and never reuse a response shape across resources**. Splitting `CreateResponse` into `CreateContextResponse` and `ExecuteCommandResponse` cascades to fix four other findings. +2. **Enum-value style** — SHOUTY_SNAKE_CASE enum identifiers with + redundant resource prefixes (`COMMAND_*`, `CONTEXT_*`, `*_RESULT`) + produce verbose callsites like `CommandStatus.COMMAND_CANCELLED`. + PascalCase identifiers with the wire string preserved as the value + restore idiomatic TS while keeping serialisation intact. + 3. **Verb inconsistency** — `cancel` (command), `destroy` (context), `commandStatus` (no verb), `contextStatus` (no verb), `execute` (vs `run`), `create`/`delete`/`destroy` mixing. Add `getCommandStatus` / diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index c9ec05f4..2286eb3a 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -3,27 +3,27 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 41 +**Total weird names flagged:** 35 ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 17 | +| High | 10 | +| Medium | 15 | | Low | 6 | -| Observation | 5 | +| Observation | 4 | ## High severity ### 1. `ConnectionType.UNKNOWN_CONNECTION_TYPE` — `src/v1/model.ts:7` - **Why weird:** Enum sentinel re-states the enum name (`ConnectionType.UNKNOWN_CONNECTION_TYPE`). Idiomatic TypeScript treats "unset" as `undefined` (the field is already `connectionType?: ConnectionType | undefined`), making an explicit `UNKNOWN_*` value redundant. -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names). +- **Category:** 2 (redundant enum prefix). - **Suggested name:** Drop the sentinel and rely on the optional field, or rename to `ConnectionType.Unknown`. -- **Rationale:** TS enum members are namespaced by the enum itself. `Foo.FOO_BAR` is pure protobuf noise that the language already solves. +- **Rationale:** TS enum members are namespaced by the enum itself, so the re-stated prefix is pure noise. ### 2. `CredentialType.UNKNOWN_CREDENTIAL_TYPE` — `src/v1/model.ts:88` - **Why weird:** Same problem as #1 — sentinel re-states enum name. -- **Category:** 2, 14. +- **Category:** 2. - **Suggested name:** `CredentialType.Unknown` or drop entirely. - **Rationale:** Identical to #1. @@ -59,145 +59,115 @@ ### 8. `DeleteConnection.nameArg` / `GetConnection.nameArg` / `UpdateConnection.nameArg` — `src/v1/model.ts:272,285,322` - **Why weird:** Field named `nameArg` rather than `name`. The `Arg` suffix is a generator artefact (denoting path-arg / required-arg in the proto), but it leaks into the TS surface — users see `req.nameArg` everywhere. `ConnectionInfo` and `CreateConnection` already have a `name` field, so the inconsistency is jarring. -- **Category:** 14 (Go/proto-style name leak), 5 (`Arg` is a cryptic abbreviation), 17 (inconsistency: `name` vs `nameArg` for the same thing). +- **Category:** 5 (`Arg` is a cryptic abbreviation), 17 (inconsistency: `name` vs `nameArg` for the same thing). - **Suggested name:** `name` everywhere. (Wire stays `name_arg` if the API truly requires that path param convention.) - **Rationale:** Three different request types have a `nameArg` field that semantically equals the connection name. Users will mistype `name` and get a runtime error. ### 9. `DeleteConnection` / `GetConnection` / `CreateConnection` / `UpdateConnection` / `ListConnections` types — `src/v1/model.ts:203,270,283,288,320` - **Why weird:** Request DTOs named as verb phrases (`DeleteConnection`, `GetConnection`). Reads as actions, not data. `import type {DeleteConnection}` looks like importing a function. Pattern is uniform across all five request types. -- **Category:** 6 (misleading: name implies behaviour), 14 (Go-style naming). +- **Category:** 6 (misleading: name implies behaviour). - **Suggested name:** `DeleteConnectionRequest`, `GetConnectionRequest`, etc. - **Rationale:** TS conventions append `Request` to request DTOs. Especially confusing because the package also exports a `Client.deleteConnection(req: DeleteConnection)` — type and method names are identical in lowercase. -### 10. `DeleteConnection_Response` — `src/v1/model.ts:276` -- **Why weird:** Underscore in identifier (proto-style nested type), requires `eslint-disable @typescript-eslint/naming-convention`. -- **Category:** 4 (underscore identifiers). -- **Suggested name:** `DeleteConnectionResponse`. -- **Rationale:** Mirror Go/proto naming with TS-idiomatic style. - -### 11. `ListConnections_Response` — `src/v1/model.ts:303-312` -- **Why weird:** Underscore in identifier. Required eslint disable. -- **Category:** 4 (underscore identifiers). -- **Suggested name:** `ListConnectionsResponse`. -- **Rationale:** Mirror Go/proto naming with TS-idiomatic style. - -### 12. `ConnectionInfo` — `src/v1/model.ts:141` +### 10. `ConnectionInfo` — `src/v1/model.ts:141` - **Why weird:** `Info` is the central domain entity — every type holds info about something. The Go SDK uses `XxxInfo` widely as a Go-style noun, but in TS the type would simply be `Connection`. `typescript.mdc` lists `Info` as a vague suffix. -- **Category:** 1 (vague suffix), 8 (redundant type suffix), 14 (Go-style name). +- **Category:** 1 (vague suffix), 8 (redundant type suffix). - **Suggested name:** `Connection`. - **Rationale:** The domain noun is "connection". Stripping `Info` improves every reference (`connection.connectionType` → `Connection.connectionType`). -### 13. `ProvisioningInfo_State` — `src/v1/model.ts:131` -- **Why weird:** Underscore in identifier (proto-style nested enum). Requires eslint disable. Idiomatic nested type access in TS is via namespaces (`ProvisioningInfo.State`). -- **Category:** 4 (underscore), 14 (proto-style). -- **Suggested name:** `ProvisioningInfo.State` via namespace, or top-level `ProvisioningState`. -- **Rationale:** Proto-style underscore-nested names leak generator output into the public surface. - ## Medium severity -### 14. `ConnectionInfo.connectionType: ConnectionType` — `src/v1/model.ts:145` +### 11. `ConnectionInfo.connectionType: ConnectionType` — `src/v1/model.ts:145` - **Why weird:** Type-suffix tautology — field `connectionType` of type `ConnectionType` on a type called `ConnectionInfo`. Reads `connectionInfo.connectionType`. - **Category:** 20. - **Suggested name:** `type: ConnectionType`. (If `ConnectionInfo` is renamed to `Connection`, becomes `connection.type`.) - **Rationale:** Wire stays `connection_type`; TS can drop the prefix. -### 15. `ConnectionInfo.credentialType: CredentialType` — `src/v1/model.ts:159` -- **Why weird:** Same tautology as #14. +### 12. `ConnectionInfo.credentialType: CredentialType` — `src/v1/model.ts:159` +- **Why weird:** Same tautology as #11. - **Category:** 20. - **Suggested name:** `credential: CredentialType` or simply keep as-is since `credential` would also be ambiguous. -- **Rationale:** Less clear than #14; the prefix carries some semantic load (distinguishes credential type from credential value). +- **Rationale:** Less clear than #11; the prefix carries some semantic load (distinguishes credential type from credential value). -### 16. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:172` +### 13. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:172` - **Why weird:** Type-suffix tautology. Also: the value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. - **Category:** 20 (tautology), 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). - **Suggested name:** Either drop the field (it's always `CONNECTION`), or rename to `securableKind: SecurableType` and document why a non-`CONNECTION` value would ever appear. - **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. -### 17. `ConnectionInfo.provisioningInfo: ProvisioningInfo` — `src/v1/model.ts:173` +### 14. `ConnectionInfo.provisioningInfo: ProvisioningInfo` — `src/v1/model.ts:173` - **Why weird:** Type-suffix tautology. - **Category:** 20. - **Suggested name:** `provisioning: ProvisioningInfo`. - **Rationale:** Wire stays `provisioning_info`; TS can drop the prefix since the containing type already names the concept. -### 18. `ConnectionInfo.connectionId` and `metastoreId` — `src/v1/model.ts:161-163` +### 15. `ConnectionInfo.connectionId` and `metastoreId` — `src/v1/model.ts:161-163` - **Why weird:** Bare `id` doesn't appear, but two `xxxId` fields coexist. `connectionId` is the type-prefix tautology (same struct already says "Connection"); `metastoreId` clarifies which parent. Mixed levels of specificity. - **Category:** 19 (underspecified id — `connectionId` is fine, but inconsistent with absence of just `id` somewhere). - **Suggested name:** `id` for the connection's own identifier (it's `connection.id`, not `connection.connectionId`); keep `metastoreId` (it identifies a parent). - **Rationale:** Self-id should be `id`; foreign-key ids should keep the prefix. This is the standard REST convention. -### 19. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:142-155` +### 16. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:142-155` - **Why weird:** Two name-like fields (`name` and `fullName`) with no inline doc explaining the difference. The wire pattern in Unity Catalog is "name within a parent" vs "catalog.schema.connection_name", but the type doesn't say that. - **Category:** 1 (vague — what makes a name "full"?), 17 (inconsistency: `name` is short, `fullName` is fully qualified but doc only says "Full name of connection"). - **Suggested name:** Keep names; improve doc to clarify `fullName` is the dot-qualified path (`catalog.schema.connection_name`). - **Rationale:** Naming is fine; documentation is the gap. Flagging because the readability of every field that pairs with `name` depends on knowing that `fullName` is the path-style form. -### 20. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:149` +### 17. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:149` - **Why weird:** Boolean field name doesn't begin with `is`/`has` as is common for TS booleans. Reads `connection.readOnly` (acceptable adjective form) but sibling enums and types use noun forms. JS naming conventions are split, but inside this SDK most booleans use the adjective form, so this is consistent — flagging at low-medium severity because the rule itself is debatable. - **Category:** 1 (vague form — `readOnly` could be a string of mode flags). - **Suggested name:** Keep as `readOnly` (matches Go SDK and is widely used in JS). Optionally `isReadOnly`. - **Rationale:** No strong convention either way; flagging because audit asked for booleans whose nature isn't obvious from the name. -### 21. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `ConnectionInfo_SecretsEntry` — `src/v1/model.ts:186-201` -- **Why weird:** Three near-identical interfaces (`key?: string; value?: string`), one per map field. Each requires an `eslint-disable` for the underscore. The actual field on `ConnectionInfo` is `Record`, so these `*_Entry` types are never used at the consumer surface — pure generator scaffolding that nonetheless gets exported (`index.ts:14-20`). -- **Category:** 4 (underscores), 12 (duplicate concepts). -- **Suggested name:** Stop exporting these. They are pure proto-map artefacts. -- **Rationale:** `index.ts` exports them as types, polluting the public surface. Six such types exist (`ConnectionInfo_*`, `CreateConnection_*`, `UpdateConnection_*` each with three). - -### 22. `CreateConnection_*Entry` / `UpdateConnection_*Entry` types — `src/v1/model.ts:252-268,368-383` -- **Why weird:** Same problem as #21 multiplied across request DTOs. Six entry types in total, each `eslint-disable`d for the underscore. -- **Category:** 4, 12. -- **Suggested name:** Remove from generator output. -- **Rationale:** Generator should not emit one map-entry interface per map field per containing type. - -### 23. `CreateConnection` / `UpdateConnection` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:203,320` +### 18. `CreateConnection` / `UpdateConnection` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:203,320` - **Why weird:** `CreateConnection` is `ConnectionInfo + parent`. `UpdateConnection` is `ConnectionInfo + nameArg + newName`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnection` and `UpdateConnection` even though they're server-only). - **Category:** 12 (duplicate concepts), 6 (misleading — user-settable vs server-set is invisible). - **Suggested name:** Split server-only metadata into a base type and compose. Better still, type create/update inputs as `Pick` or a dedicated `ConnectionInput` interface. - **Rationale:** Today a caller could set `connection.createdAt` on a create request and have no idea it's silently ignored. Type system can prevent this. -### 24. `UpdateConnection.newName` and `nameArg` — `src/v1/model.ts:322-324` +### 19. `UpdateConnection.newName` and `nameArg` — `src/v1/model.ts:322-324` - **Why weird:** `newName` (TS), wire `new_name`. Pair (`nameArg`, `newName`) means "rename connection X to Y". Function-style verb encoded in a field name (`new` + Name). - **Category:** 5 (`newName` reads as a temporal modifier), 17 (also inconsistent with the type's own `name` field). - **Suggested name:** `renameTo`, or split into a `RenameConnectionRequest` operation. - **Rationale:** Cleaner API: rename and update are distinct operations. -### 25. `UpdateConnection.name` field — `src/v1/model.ts:326` +### 20. `UpdateConnection.name` field — `src/v1/model.ts:326` - **Why weird:** `UpdateConnection` has THREE name-like fields: `nameArg` (path param, identifies which), `newName` (new name), AND `name` (also documented as "Name of the connection"). Both `nameArg` and `name` are documented identically and both refer to the existing connection. Easily mis-set; ambiguous which the server uses. - **Category:** 12 (duplicate concept), 6 (misleading — three fields mean "the name"). - **Suggested name:** Remove `name` from `UpdateConnection` (it duplicates `nameArg`). - **Rationale:** Three fields for one concept is a bug surface. Worth pushing to API design. -### 26. `parent` field on `CreateConnection` and `ListConnections` — `src/v1/model.ts:208,300` +### 21. `parent` field on `CreateConnection` and `ListConnections` — `src/v1/model.ts:208,300` - **Why weird:** Bare `parent` with the value encoded as a free-form string `"schemas/{catalog}.{schema}"`. Untyped wire format inside a field name that does not indicate a structured path. - **Category:** 1 (vague), 5 (cryptic — what shape is `parent`?). - **Suggested name:** `parentSchema`, with a clear doc that the format is `"schemas/{catalog}.{schema}"` (or model the catalog/schema pair as a structured type). - **Rationale:** Pattern of "rest-resource string with embedded slashes" is common in Google APIs but feels out of place in a TS SDK. At minimum the field should signal it's a schema reference. -### 27. `ListConnections.maxResults` semantics — `src/v1/model.ts:289-296` +### 22. `ListConnections.maxResults` semantics — `src/v1/model.ts:289-296` - **Why weird:** Three different behaviours encoded in the same field: "not set → all results", "0 → server default", ">0 → bound by min(value, server-default)", "<0 → error". Numeric overload that is invisible from the name. - **Category:** 6 (misleading — `maxResults` implies upper bound, but `0` actually requests server default). - **Suggested name:** Either two separate fields (`pageSize` and `useServerDefault`), or document inline tersely. Keep name; flag as observation. - **Rationale:** Name is fine; behaviour overloaded. Easy to call wrong. -### 28. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:127` +### 23. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:127` - **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. - **Category:** 18 (questionable enum value). - **Suggested name:** Hide until promotion or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. -### 29. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:102` +### 24. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:102` - **Why weird:** `SSWS` is cryptic. (Stands for "Single Sign-On Web Services" or Okta SSWS — Secure Single Sign-on. Either way, opaque.) Other tokens are named after their family (OAuth, OIDC, Bearer); SSWS is the only one with a literal product-specific acronym. - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling values). - **Suggested name:** `OKTA_SSWS_TOKEN` (if it's strictly Okta), or document in doc-comment. - **Rationale:** Future readers cannot guess what SSWS expands to. -### 30. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:103` +### 25. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:103` - **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while other vendor-coupled values put the vendor first (`OAUTH_GOOGLE_SERVICE_ACCOUNT`). Inconsistent word order. - **Category:** 17 (inconsistency). - **Suggested name:** `AKAMAI_EDGEGRID`. - **Rationale:** Consistency with the `OAUTH_GOOGLE_*` pattern (vendor-first). -### 31. `CredentialType.OAUTH_DCR` — `src/v1/model.ts:105` +### 26. `CredentialType.OAUTH_DCR` — `src/v1/model.ts:105` - **Why weird:** `DCR` is opaque (probably "Dynamic Client Registration", an OAuth concept). No doc. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `OAUTH_DYNAMIC_CLIENT_REGISTRATION` or document in a doc-comment. @@ -205,37 +175,37 @@ ## Low severity -### 32. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` +### 27. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. -### 33. `flattenQueryParams` — `src/v1/utils.ts:123` +### 28. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if generator default. - **Rationale:** Generator emits the same helper into every package even when unused. -### 34. `readAll` — `src/v1/utils.ts:40` +### 29. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Trivial; flagged for cross-package consistency. -### 35. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 30. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should encode the layer, not just the protocol. -### 36. `HttpCallOptions` — `src/v1/utils.ts:15` +### 31. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 37. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:164-165` +### 32. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:164-165` - **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. - **Category:** Observation only. - **Suggested name:** None — this is the marshalling boundary by design. @@ -243,11 +213,11 @@ ## Observations -### 38. ~50 vendor names baked into `ConnectionType` enum +### 33. ~50 vendor names baked into `ConnectionType` enum The enum lists ~70 vendors (`MYSQL` ... `MARKETO`), all SCREAMING_SNAKE. This makes `model.ts` 84 lines of enum just for connection types. Worth raising with API design whether the type should be `string` with vendor metadata living in a separate registry — adding a new connection type today requires releasing a new SDK version. - **Category:** 18 (long enum value set). -### 39. Casing inconsistency in vendor name decomposition +### 34. Casing inconsistency in vendor name decomposition Within `ConnectionType`: - `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). - `MYSQL` (joined) vs `MICROSOFT_ENTRA_ID` (split). @@ -255,17 +225,13 @@ Within `ConnectionType`: No discoverable rule. Wire-locked, but worth surfacing. - **Category:** 3 (acronym/casing inconsistency). -### 40. Action-verb conventions on `Client` +### 35. Action-verb conventions on `Client` `createConnection`, `getConnection`, `listConnections`, `updateConnection`, `deleteConnection` — uniform. (Listed as observation since the audit asks us to flag inconsistencies; here we explicitly note consistency.) -### 41. `Client` constructor throws for missing host +### 36. `Client` constructor throws for missing host `if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. - **Category:** Observation. -### 42. `index.ts` re-exports proto-map entry types -`ConnectionInfo_OptionsEntry`, `ConnectionInfo_PropertiesEntry`, `ConnectionInfo_SecretsEntry`, plus the same for `CreateConnection_*` and `UpdateConnection_*` — nine types whose only purpose is to model proto map entries. None are usable as `Record` consumers expect. These should not be on the public surface. -- **Category:** 12 (duplicate concepts). - ## Domain glossary - `uc` — Unity Catalog (referenced in `model.ts:178` doc comment "UC Secret"). - `raas` — Reporting as a Service (e.g. `WORKDAY_RAAS`). Doc-less. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index 36c9da4b..8661fe31 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -13,7 +13,7 @@ cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure Managed Identity, GCP Service Account Key, Databricks-managed GCP Service Account, Cloudflare API token) and yields one of six temporary-credential shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). -**Total weird names flagged:** 51 +**Total weird names flagged:** 33 --- @@ -36,42 +36,31 @@ shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). | 13 | `UpdateCredential.nameArg` and `UpdateCredential.name` coexist | model.ts:782, 797 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredential.name`'s text. Caller will pick wrong. | | 14 | `UpdateStorageCredential.nameArg` and `UpdateStorageCredential.name` coexist | model.ts:867, 881 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #13 for the storage variant. | | 15 | `CredentialInfo` discriminator field `credential` | model.ts:308 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `CredentialInfo`; the field that holds the credential payload is also `credential`. `Credential.credential.awsIamRole` reads as a stutter. Should be `cloudCredential` or `provider`. | -| 16 | `_Response` / `_Result` / `_ValidationResult` / `_FileOperation` / `_AzureOptions` / `_GcpOptions` (proto-style underscore names) | model.ts:30, 41, 51, 399, 413, 450, 489, 499, 519, 553, 620, 652, 990, 1001, 1053, 1061 | type/enum | High | 4 Underscores in TS identifiers | TS does not use underscores in PascalCase identifiers. The 16 `Parent_Child` names (proto-message-nested-message-encoded-as-underscore) all require `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. The hint is the surrounding ESLint disables — the generator already knows these violate the rule. | -| 17 | `ValidateCredential_Result` enum | model.ts:30 | enum | Medium | 4 Underscores in TS identifiers, 2 Redundant enum prefixes | The enum name says "Result", the values are `PASS`/`FAIL`/`SKIP`. Could be `ValidationResult` (no underscore) or `Outcome`. | -| 18 | `ValidateStorageCredential_Result` enum | model.ts:51 | enum | Medium | 4 Underscores in TS identifiers, 12 Duplicate concepts | Same shape as `ValidateCredential_Result` — `PASS`/`FAIL`/`SKIP`. Two enums with identical members differing only by name. Should be a shared type. | -| 19 | `ValidateStorageCredential_FileOperation` enum | model.ts:41 | enum | Medium | 4 Underscores in TS identifiers, 18 Long enum values | `LIST`/`READ`/`WRITE`/`DELETE`/`PATH_EXISTS`. The values are fine; the enum *name* is 39 chars. `FileOp` or merging with the validator's outer type would shorten. | -| 20 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` etc. | model.ts:5-10 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | All four values stutter the enum name (`ISOLATION_MODE_OPEN`, `ISOLATION_MODE_ISOLATED`, ...). TS idiom would be `IsolationMode.Unspecified`/`.Open`/`.Isolated`. The generator emits SCREAMING_SNAKE for both the keys and the string values. | -| 21 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` | model.ts:6 | enum value | Medium | 6 Misleading names, 18 Long enum values | "Unspecified" is the proto-style placeholder for "missing value". In TS the natural way to express this is `undefined`, not a sentinel string. The field type already is `IsolationMode \| undefined`. | -| 22 | `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` | model.ts:9 | enum value | Low | 18 Long enum values, 6 Misleading names | 30-char enum value; "OpenInAccount" is the contraction. The domain meaning ("open within a single account scope") is not obvious from either form. | -| 23 | `PathOperation` enum values | model.ts:13-15 | enum values | Medium | 2 Redundant enum prefixes, 18 Long enum values | `PATH_READ`, `PATH_READ_WRITE`, `PATH_CREATE_TABLE` — `PATH_` prefix duplicates the enum name. The third value (`PATH_CREATE_TABLE`) is a different category from the first two ("Path"-as-resource vs "create a table at this path"); the prefix obscures that. | -| 24 | `TableOperation` vs `VolumeOperation` enums | model.ts:18, 23 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write) expressed two different ways. The volume one uses prefixed values (#20 pattern), the table one does not — inconsistent within the same file. | -| 25 | `VolumeOperation.READ_VOLUME`/`WRITE_VOLUME` | model.ts:24-25 | enum value | Medium | 2 Redundant enum prefixes, 18 Long enum values | `_VOLUME` suffix stutters the enum name. Should be `READ`/`WRITE` (consistent with `TableOperation`). | -| 26 | `unityCatalogIamArn` | model.ts:83 | field | Medium | 7 Overly verbose, 6 Misleading names | 18-char field name embedded in `AwsIamRole`. The JSDoc says "AWS IAM user managed by Databricks". Caller has no way to know that "unityCatalog" here means "the Databricks-managed identity that assumes the customer role". Either `databricksManagedIamArn` or rename to clarify role. | -| 27 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:76, 117, 99, 427, 378, 139 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | -| 28 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:95, 93, 459 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | -| 29 | `awsTempCredentials` discriminator case | model.ts:453 | field | Low | 5 Cryptic abbreviations | "Temp" abbreviation for "Temporary". Other discriminator cases use full words (`azureUserDelegationSas`, `gcpOauthToken`). Inconsistent. | -| 30 | `r2TempCredentials` discriminator case | model.ts:460 | field | Low | 5 Cryptic abbreviations | Same as #29. | -| 31 | `ucEncryptedToken` discriminator case | model.ts:461 | field | Medium | 5 Cryptic abbreviations | "Uc" is the Databricks-internal abbreviation for "Unity Catalog". Outside Databricks the abbreviation is opaque. Compare to `unityCatalogIamArn` (#26) which spells it out. Inconsistent within the same model file. | -| 32 | `UcEncryptedToken` type | model.ts:775 | interface | Medium | 5 Cryptic abbreviations, 1 Vague/generic | Same "Uc" abbreviation problem at the type name. Spell out or contextualize. | -| 33 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:419, 420 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | -| 34 | `R2Credentials` type | model.ts:667 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | -| 35 | `CloudflareApiToken.accountId` | model.ts:145 | field | Low | 19 Underspecified IDs | This `accountId` is a *Cloudflare* account ID, not a Databricks account ID. The field name doesn't say. Compare `unityCatalogIamArn` (#26) which is annotated. | -| 36 | `AwsCredentials.accessPoint` | model.ts:72 | field | Low | 5 Cryptic abbreviations, 1 Vague/generic | A string containing an S3 Access Point ARN. `accessPointArn` would type itself. | -| 37 | `usedForManagedStorage` flag | model.ts:216 | field | Low | 6 Misleading names | Boolean named in past tense ("usedFor") suggests a historical record. The doc says it is the *current* state. `isManagedStorageRoot` or `isRootForManagedStorage` reads as state. | -| 38 | `isolationMode` vs `IsolationMode` (type alias collision risk) | model.ts:223 | field | Low | (none) | Standard generator pattern (field name lower-cased version of enum type). Already idiomatic; no issue. (Listing for completeness.) | -| 39 | `GenerateTemporaryPathCredential` / `GenerateTemporaryTableCredential` / `GenerateTemporaryVolumeCredential` / `GenerateTemporaryServiceCredential` | model.ts:436, 508, 542, 472 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 31-34 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | -| 40 | `GenerateTemporaryPathCredential_Response` / `..._TableCredential_Response` / `..._VolumeCredential_Response` | model.ts:450, 519, 553 | interface set | Medium | 4 Underscores, 7 Overly verbose, 12 Duplicate concepts | Three response shapes (39-42 char names) with **identical** fields: `credentials` union + `expirationTime` + `url`. They are also identical to `TemporaryCredentials` (model.ts:749). Four parallel definitions of the same shape. | -| 41 | `TemporaryCredentials` | model.ts:749 | interface | Medium | 12 Duplicate concepts | This and the three `Generate*_Response` types (#40) are the same shape. Only one should exist; the other three should re-export it. | -| 42 | `GenerateTemporaryServiceCredential_AzureOptions` | model.ts:489 | interface | High | 4 Underscores in TS identifiers, 7 Overly verbose | 47 chars. The `_AzureOptions` proto-style suffix is the third underscore-segment in the name. | -| 43 | `GenerateTemporaryServiceCredential_GcpOptions` | model.ts:499 | interface | High | 4 Underscores in TS identifiers, 7 Overly verbose | Same as #42 — 45 chars. | -| 44 | `GenerateTemporaryServiceCredential.options.$case` discriminator values | model.ts:477, 481 | field | Low | 1 Vague/generic | The discriminator is `azureOptions` / `gcpOptions`. "Options" gives no domain hint — could be query options, retry options, etc. Within the type they are token-generation parameters. | -| 45 | `ValidateCredential.credential` outer field with `credential.$case === 'credentialName'` | model.ts:951, 953 | field | High | 12 Duplicate concepts, 15 Generic field names | The discriminated-union *case* is `credentialName: string`, sitting under a field called `credential`. So `req.credential.credentialName` is the read path — `credential.credential...` stuttering. | -| 46 | `ValidateStorageCredential.credential.$case === 'storageCredentialName'` | model.ts:1011 | field | High | 12 Duplicate concepts, 15 Generic field names | Same as #45 — `req.credential.storageCredentialName`. The naming repeats the parent type. | -| 47 | `dryRun` on `GenerateTemporaryPathCredential` | model.ts:446 | field | Low | (none) | Camel-cased boolean, conventional. (Listing for completeness.) | -| 48 | `expirationTime` (epoch milliseconds) | model.ts:467 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | -| 49 | `createdAt`, `updatedAt`, `createdBy`, `updatedBy` | model.ts:205, 209, 207, 211 | field set | Low | (none) | Standard, consistent across the file. (Listing for completeness.) | -| 50 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:107-110 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredential`/`CredentialInfo`/`UpdateCredential`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | -| 51 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | +| 16 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` etc. | model.ts:5-10 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | All four values stutter the enum name (`ISOLATION_MODE_OPEN`, `ISOLATION_MODE_ISOLATED`, ...). TS idiom would be `IsolationMode.Unspecified`/`.Open`/`.Isolated`. The generator emits SCREAMING_SNAKE for both the keys and the string values. | +| 17 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` | model.ts:6 | enum value | Medium | 6 Misleading names, 18 Long enum values | "Unspecified" is the proto-style placeholder for "missing value". In TS the natural way to express this is `undefined`, not a sentinel string. The field type already is `IsolationMode \| undefined`. | +| 18 | `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` | model.ts:9 | enum value | Low | 18 Long enum values, 6 Misleading names | 30-char enum value; "OpenInAccount" is the contraction. The domain meaning ("open within a single account scope") is not obvious from either form. | +| 19 | `PathOperation` enum values | model.ts:13-15 | enum values | Medium | 2 Redundant enum prefixes, 18 Long enum values | `PATH_READ`, `PATH_READ_WRITE`, `PATH_CREATE_TABLE` — `PATH_` prefix duplicates the enum name. The third value (`PATH_CREATE_TABLE`) is a different category from the first two ("Path"-as-resource vs "create a table at this path"); the prefix obscures that. | +| 20 | `TableOperation` vs `VolumeOperation` enums | model.ts:18, 23 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write) expressed two different ways. The volume one uses prefixed values (#16 pattern), the table one does not — inconsistent within the same file. | +| 21 | `VolumeOperation.READ_VOLUME`/`WRITE_VOLUME` | model.ts:24-25 | enum value | Medium | 2 Redundant enum prefixes, 18 Long enum values | `_VOLUME` suffix stutters the enum name. Should be `READ`/`WRITE` (consistent with `TableOperation`). | +| 22 | `unityCatalogIamArn` | model.ts:83 | field | Medium | 7 Overly verbose, 6 Misleading names | 18-char field name embedded in `AwsIamRole`. The JSDoc says "AWS IAM user managed by Databricks". Caller has no way to know that "unityCatalog" here means "the Databricks-managed identity that assumes the customer role". Either `databricksManagedIamArn` or rename to clarify role. | +| 23 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:76, 117, 99, 427, 378, 139 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | +| 24 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:95, 93, 459 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | +| 25 | `awsTempCredentials` discriminator case | model.ts:453 | field | Low | 5 Cryptic abbreviations | "Temp" abbreviation for "Temporary". Other discriminator cases use full words (`azureUserDelegationSas`, `gcpOauthToken`). Inconsistent. | +| 26 | `r2TempCredentials` discriminator case | model.ts:460 | field | Low | 5 Cryptic abbreviations | Same as #25. | +| 27 | `ucEncryptedToken` discriminator case | model.ts:461 | field | Medium | 5 Cryptic abbreviations | "Uc" is the Databricks-internal abbreviation for "Unity Catalog". Outside Databricks the abbreviation is opaque. Compare to `unityCatalogIamArn` (#22) which spells it out. Inconsistent within the same model file. | +| 28 | `UcEncryptedToken` type | model.ts:775 | interface | Medium | 5 Cryptic abbreviations, 1 Vague/generic | Same "Uc" abbreviation problem at the type name. Spell out or contextualize. | +| 29 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:419, 420 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | +| 30 | `R2Credentials` type | model.ts:667 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | +| 31 | `CloudflareApiToken.accountId` | model.ts:145 | field | Low | 19 Underspecified IDs | This `accountId` is a *Cloudflare* account ID, not a Databricks account ID. The field name doesn't say. Compare `unityCatalogIamArn` (#22) which is annotated. | +| 32 | `AwsCredentials.accessPoint` | model.ts:72 | field | Low | 5 Cryptic abbreviations, 1 Vague/generic | A string containing an S3 Access Point ARN. `accessPointArn` would type itself. | +| 33 | `usedForManagedStorage` flag | model.ts:216 | field | Low | 6 Misleading names | Boolean named in past tense ("usedFor") suggests a historical record. The doc says it is the *current* state. `isManagedStorageRoot` or `isRootForManagedStorage` reads as state. | +| 34 | `GenerateTemporaryPathCredential` / `GenerateTemporaryTableCredential` / `GenerateTemporaryVolumeCredential` / `GenerateTemporaryServiceCredential` | model.ts:436, 508, 542, 472 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 31-34 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | +| 35 | `TemporaryCredentials` | model.ts:749 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | +| 36 | `ValidateCredential.credential` outer field with `credential.$case === 'credentialName'` | model.ts:951, 953 | field | High | 12 Duplicate concepts, 15 Generic field names | The discriminated-union *case* is `credentialName: string`, sitting under a field called `credential`. So `req.credential.credentialName` is the read path — `credential.credential...` stuttering. | +| 37 | `ValidateStorageCredential.credential.$case === 'storageCredentialName'` | model.ts:1011 | field | High | 12 Duplicate concepts, 15 Generic field names | Same as #36 — `req.credential.storageCredentialName`. The naming repeats the parent type. | +| 38 | `expirationTime` (epoch milliseconds) | model.ts:467 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | +| 39 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:107-110 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredential`/`CredentialInfo`/`UpdateCredential`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | +| 40 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | --- @@ -128,7 +117,7 @@ of each other: There is no behavioral difference. One should be a type alias. -### H4. `nameArg` field convention +### H4. Three-way name collision (`nameArg` + `name` + `newName`) Six request types (`DeleteCredential`, `DeleteStorageCredential`, `GetCredential`, `GetStorageCredential`, `UpdateCredential`, @@ -176,37 +165,9 @@ no `purpose` field anywhere on `CreateCredential`/`UpdateCredential`/ the model. In all cases the contract documented in JSDoc cannot be honored by a TS -caller. See #50. +caller. See #39. -### H7. Eighteen `_`-bearing TS identifiers - -Sixteen types and two enums use proto-style underscore-encoded nested -identifiers. Each requires an inline `// eslint-disable-next-line -@typescript-eslint/naming-convention` because the project's linter forbids -underscores. The presence of those disables is the loudest possible signal -that the names violate the codebase's own conventions: - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface DeleteCredential_Response {} -``` - -Names affected: `ValidateCredential_Result`, `ValidateStorageCredential_FileOperation`, -`ValidateStorageCredential_Result`, `DeleteCredential_Response`, -`DeleteStorageCredential_Response`, `GenerateTemporaryPathCredential_Response`, -`GenerateTemporaryTableCredential_Response`, -`GenerateTemporaryVolumeCredential_Response`, -`GenerateTemporaryServiceCredential_AzureOptions`, -`GenerateTemporaryServiceCredential_GcpOptions`, `ListCredentials_Response`, -`ListStorageCredentials_Response`, `ValidateCredential_Response`, -`ValidateCredential_ValidationResult`, `ValidateStorageCredential_Response`, -`ValidateStorageCredential_ValidationResult`. - -Standard TS idiom would nest these inside namespaces (`ValidateCredential.Result`) -or give them top-level domain names (`ValidationOutcome`, -`PathCredentialResponse`). - -### H8. Stuttering `ValidateCredential.credential.credentialName` +### H7. Stuttering `ValidateCredential.credential.credentialName` `req.credential` is the discriminated-union outer field. One of its cases is `{$case: 'credentialName', credentialName: string}` — so accessing the value @@ -291,22 +252,20 @@ enum VolumeOperation { READ_VOLUME, WRITE_VOLUME } ``` Three enums for the same domain (read/write a cloud-storage thing) with three -different prefixing conventions. Pick one. (See #23, #25.) +different prefixing conventions. Pick one. (See #19, #21.) -### M6. `TemporaryCredentials` shape duplicated four times +### M6. `TemporaryCredentials` shape duplicated across responses -`TemporaryCredentials`, `GenerateTemporaryPathCredential_Response`, -`GenerateTemporaryTableCredential_Response`, -`GenerateTemporaryVolumeCredential_Response` — four interfaces, identical -fields. The wire endpoints might differ (so each method returns its own -named type), but at the TS level there is no need to create four +`TemporaryCredentials` and the three `Generate*` response types carry the +same field set. The wire endpoints might differ (so each method returns its +own named type), but at the TS level there is no need to create multiple declarations. ### M7. `UcEncryptedToken` and `Uc*` discriminator case use unspelled-out abbreviation `Uc` = "Unity Catalog". A TS-side consumer outside Databricks won't recognize the abbreviation. The same model file uses `unityCatalog` spelled out on -`AwsIamRole.unityCatalogIamArn` (#26) — inconsistent within the file. Pick +`AwsIamRole.unityCatalogIamArn` (#22) — inconsistent within the file. Pick either `UnityCatalogEncryptedToken` everywhere or `Uc*` everywhere. ### M8. `R2Credentials` requires Cloudflare product knowledge @@ -406,13 +365,13 @@ before the args. Cannot shorten without breaking the resource hierarchy. - `Gcp` (PascalCase first letter) — `GcpOauthToken`, `gcpServiceAccountKey`. Internally consistent. - `Aad` (mixed) — `aadToken` (field, short), `AzureActiveDirectoryToken` - (type, long). Inconsistent. See #28. + (type, long). Inconsistent. See #24. - `Iam` — consistent with `Aws`/`Gcp` style. -- `R2` — special-cased product name. See M8/#34. +- `R2` — special-cased product name. See M8/#30. - `Sas` (PascalCase first letter) — `AzureUserDelegationSas`, `sasToken`. Consistent. -- `Uc` — see M7/#31/#32. -- `Oauth` — see L5/#33. +- `Uc` — see M7/#27/#28. +- `Oauth` — see L5/#29. The JSDoc *text* in the same file uses ALL-CAPS forms ("AWS", "GCP", "IAM", "AAD") because that is how the cloud providers write them. The Google TS diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 5a3b42e5..1f4f5f39 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -16,7 +16,7 @@ ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #34). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #31). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. @@ -33,11 +33,11 @@ - **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). - **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. -### 4. `State.STATE_UNSPECIFIED` — `src/v1/model.ts:10` -- **Why weird:** Redundant enum prefix (`State.STATE_*`) plus a proto-buf `_UNSPECIFIED` sentinel. TypeScript's enums are namespaced by the enum name — `STATE_UNSPECIFIED` becomes `State.STATE_UNSPECIFIED` at the call site, which is doubled. Idiomatic TS uses `undefined` for "not set" rather than a sentinel. -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names not idiomatic in TS), 18 (questionable enum value). +### 4. `State.STATE_UNSPECIFIED` redundant prefix — `src/v1/model.ts:10` +- **Why weird:** The enum value `STATE_UNSPECIFIED` repeats the enum name as a prefix — at the call site it reads `State.STATE_UNSPECIFIED`, which is doubled. The `_UNSPECIFIED` sentinel is also redundant in TypeScript, where `optimizationState?: State | undefined` already expresses "not set". +- **Category:** 2 (redundant enum prefix), 18 (questionable enum value). - **Suggested name:** Drop `STATE_UNSPECIFIED` (rely on `optimizationState?: State | undefined`); rename the remaining values to title-case: `OptimizationRunState.Created | Running | Completed | Failed | Pending | Cancelled`. -- **Rationale:** TS `enum` members carry SCREAMING_SNAKE only as a proto-buf artifact. The Google TS style guide treats enum members as constants, so SCREAMING_SNAKE is *also* defensible — but at minimum the redundant `STATE_` prefix should go. +- **Rationale:** The Google TS style guide treats enum members as constants, so SCREAMING_SNAKE is defensible — but at minimum the redundant `STATE_` prefix should go, and the unspecified sentinel duplicates what `undefined` already conveys. ### 5. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` - **Why weird:** Doc comment "The Id of the tile." refers to a "tile" that does not exist anywhere else in the package. This is almost certainly a copy-paste from another generated API (dashboards/tiles). Either the field name or the doc is wrong; reading the surrounding code, the field is the custom-LLM id (same as `CancelCustomLlmOptimizationRunRequest.id` on line 20). Public SDK doc bug. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index e4461301..32104c26 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,14 +3,14 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 53 +**Total weird names flagged:** 42 ## Summary | Severity | Count | | --- | --- | -| High | 16 | -| Medium | 20 | -| Low | 14 | +| High | 11 | +| Medium | 18 | +| Low | 10 | | Observation | 3 | ## High severity @@ -22,7 +22,7 @@ - **Rationale:** Package names are the first-line filter a user uses; "database" tells them nothing. The sister package `postgres` is more specific despite sitting at a lower level. ### 2. `database` and `postgres` packages overlap and confuse — `packages/database/` vs `packages/postgres/` -- **Why weird:** Two sibling packages model what is almost the same physical thing. `database` exposes `DatabaseInstance` / `SyncedDatabaseTable` / `DatabaseCatalog`; `postgres` exposes `ComputeInstance` / `SyncedTable` / `Catalog` / `Project` / `Branch` / `Endpoint`. Several types are textually duplicated (`DeltaTableSyncInfo`, `SyncedTablePosition`, `SyncedTablePipelineProgress`, `NewPipelineSpec`, `DatabaseCredential`, `GenerateDatabaseCredentialRequest`, `RequestedClaims`, `RequestedResource`, `ProvisioningInfo`, `ProvisioningPhase`, `SyncedTableState`, `RequestedClaims_PermissionSet`). Multiple enums share names (`ProvisioningPhase`, `SyncedTableState`, `ProvisioningInfo_State`, `RequestedClaims_PermissionSet`). +- **Why weird:** Two sibling packages model what is almost the same physical thing. `database` exposes `DatabaseInstance` / `SyncedDatabaseTable` / `DatabaseCatalog`; `postgres` exposes `ComputeInstance` / `SyncedTable` / `Catalog` / `Project` / `Branch` / `Endpoint`. Several types are textually duplicated (`DeltaTableSyncInfo`, `SyncedTablePosition`, `SyncedTablePipelineProgress`, `NewPipelineSpec`, `DatabaseCredential`, `GenerateDatabaseCredentialRequest`, `RequestedClaims`, `RequestedResource`, `ProvisioningInfo`, `ProvisioningPhase`, `SyncedTableState`). Multiple enums share names (`ProvisioningPhase`, `SyncedTableState`). - **Category:** 12 (duplicate concept across packages), 6 (misleading: user cannot infer which package owns what). - **Suggested name:** Either (a) merge into one `lakebase` package with versioning, (b) declare one package the public surface and mark the other internal, or (c) cross-reference each shared type and make the docstrings explicitly say "see postgres/v1 for the V2 API". - **Rationale:** Comment at `client.ts:666-671` says "Lakebase V2 plans" — i.e. `database` is V1 and `postgres` is V2 OLTP. The naming does not reflect that lineage; users picking a dependency have no breadcrumb. @@ -33,79 +33,49 @@ - **Suggested name:** `LakebaseInstance` or `PostgresInstance`. - **Rationale:** Reader sees `DatabaseInstance` and has no idea whether it's a SQL warehouse instance, a vector DB instance, or something else. Postgres SDK calls the same concept `ComputeInstance` (`postgres/v1/model.ts`), which is also generic — flagged separately under finding #2. -### 4. `DatabaseInstance_State` / `DatabaseInstanceRole_IdentityType` / `DatabaseInstanceRole_MembershipRole` / `ProvisioningInfo_State` / `RequestedClaims_PermissionSet` / `SyncedTableSpec_PgSpecificType` / `SyncedTableSpec_SecondaryIndex_CreationPoint` / `DatabaseInstanceRole_Attributes` / `SyncedTableSpec_ExtraColumnDefinition` / `SyncedTableSpec_SecondaryIndex` / `SyncedTableSpec_TypeOverride` — `src/v1/model.ts:105,125,140,148,160,167,176,411,847,863,877` -- **Why weird:** Eleven exported identifiers contain `_` underscores. Every one of them needs an `eslint-disable-next-line @typescript-eslint/naming-convention`. They are proto-generated names: `Foo_Bar` originated as `package.Foo.Bar` in protobuf. TypeScript convention (Google TS style guide §9.2; `typescript.mdc` rule on identifiers) forbids underscores in type names. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). -- **Suggested name:** Flatten with descriptive prefixes/suffixes: `DatabaseInstanceState`, `RoleIdentityType`, `RoleMembershipRole`, `ProvisioningState`, `PermissionSet`, `PgColumnType`, `IndexCreationPoint`, `RoleAttributes`, `ExtraColumnDefinition`, `SecondaryIndex`, `TypeOverride`. Or nest as namespaces (TS does not need the underscore: `namespace DatabaseInstance { export type State = ... }`). -- **Rationale:** Each underscore identifier costs a lint suppression and forces users to type the underscore. The naming convention is a leaky proto abstraction. - -### 5. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:412-414` +### 4. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:412-414` - **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:404-409) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; keep `createdb`/`createrole`/`bypassrls` on the wire (marshal/unmarshal handles the mapping). - **Rationale:** Every other field in the package is `camelCase`. Three boolean fields breaking the convention to honour Postgres SQL keywords is a leak. Postgres SDK at `postgres/v1/model.ts` solves this differently — worth aligning. -### 6. `SyncedTableState` — 12 enum members each prefixed with `SYNCED_TABLE_` — `src/v1/model.ts:55-102` -- **Why weird:** 12 members named `SYNCED_TABLE_PROVISIONING`, `SYNCED_TABLE_ONLINE`, `SYNCED_TABLE_ONLINE_CONTINUOUS_UPDATE`, `SYNCED_TABLE_ONLINE_TRIGGERED_UPDATE`, `SYNCED_TABLE_ONLINE_NO_PENDING_UPDATE`, `SYNCED_TABLE_OFFLINE_FAILED`, `SYNCED_TABLE_ONLINE_PIPELINE_FAILED`, `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES`, etc. The enum is already `SyncedTableState` — every member re-states `SYNCED_TABLE_`. One member is also misspelled: `SYNCED_TABLED_OFFLINE` (line 85) — extra `D` makes it `TABLED`. -- **Category:** 2 (redundant enum prefix), 18 (long enum values), 6 (misleading: `SYNCED_TABLED_OFFLINE` typo). -- **Suggested name:** `SyncedTableState.Provisioning | Online | OnlineContinuousUpdate | OnlineTriggeredUpdate | OnlineNoPendingUpdate | Offline | OfflineFailed | OnlinePipelineFailed | OnlineUpdatingPipelineResources | ProvisioningPipelineResources | ProvisioningInitialSnapshot | Unspecified`. Fix the typo regardless. -- **Rationale:** `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES` is 46 characters and contributes zero information beyond what the enum's name already says. The typo `SYNCED_TABLED_OFFLINE` is almost certainly a wire-protocol bug worth raising upstream. - -### 7. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:85` +### 5. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:85` - **Why weird:** Should be `SYNCED_TABLE_OFFLINE`. Spelled as `SYNCED_TABLED_OFFLINE` (`TABLED` past tense). - **Category:** 6 (misleading: typo). -- **Suggested name:** `SyncedTableState.Offline` (and fix the wire-string). +- **Suggested name:** Fix the wire-string to `SYNCED_TABLE_OFFLINE`. - **Rationale:** This is a protocol-level typo that the SDK is propagating. If fixed upstream this becomes a breaking change unless aliased — flag now. -### 8. `ProvisioningPhase` enum — every value prefixed `PROVISIONING_PHASE_` — `src/v1/model.ts:23-32` -- **Why weird:** 4 values: `PROVISIONING_PHASE_UNSPECIFIED`, `PROVISIONING_PHASE_MAIN`, `PROVISIONING_PHASE_INDEX_SCAN`, `PROVISIONING_PHASE_INDEX_SORT`. Same problem as #6. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** `ProvisioningPhase.Unspecified | Main | IndexScan | IndexSort`. -- **Rationale:** Same as #6. - -### 9. `SyncedTableSchedulingPolicy` enum — every value prefixed `SYNCED_TABLE_SCHEDULING_POLICY_` — `src/v1/model.ts:34-52` -- **Why weird:** Only one member (`SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED`) carries the prefix; the other three (`CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`) do not. Inconsistent within a single enum. -- **Category:** 2 (redundant prefix on the unspecified value), 17 (inconsistency within the same enum). -- **Suggested name:** Either drop the prefix everywhere (`Unspecified | Continuous | Triggered | Snapshot`) or apply it everywhere — pick one. -- **Rationale:** Mixed conventions within a single enum are jarring and make autocomplete results look broken. - -### 10. `PipelineChannel.PIPELINE_CHANNEL_UNSPECIFIED` — `src/v1/model.ts:16` -- **Why weird:** Same pattern: the `UNSPECIFIED` sentinel is prefixed (`PIPELINE_CHANNEL_UNSPECIFIED`) but the other two (`CURRENT`, `PREVIEW`) are not. -- **Category:** 2 (redundant prefix), 17 (inconsistency). -- **Suggested name:** Drop the prefix (`Unspecified | Current | Preview`). -- **Rationale:** Same as #9. - -### 11. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) +### 6. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) - **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+3 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. - **Category:** 7 (overly verbose), 12 (duplicate concept), 15 (generic prefix). - **Suggested name:** Hoist effective values onto a sub-struct or use a discriminated `{input, effective}` shape; or drop the `effective` fields and explain in docs that the same field is read-mostly on responses. - **Rationale:** This is a Lakebase API protocol pattern, not a naming bug per se, but the resulting TS surface is twice as wide as it needs to be. Worth pushing back upstream. -### 12. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:493`, `client.ts:428` +### 7. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:493`, `client.ts:428` - **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 494 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:518): "Name of the **cluster** to get". - **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). - **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. - **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. -### 13. `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` — `src/v1/model.ts:976`, `client.ts:998` +### 8. `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` — `src/v1/model.ts:976`, `client.ts:998` - **Why weird:** Inconsistent with the rest of the API surface: the type is `UpgradeInstance...` but every other type is `UpgradeDatabaseInstance...`. The method name is `upgradeInstanceToAutoscaling`, not `upgradeDatabaseInstance...`. Drops the `Database` namespace word that every other method preserves. - **Category:** 17 (inconsistency in action verb / type prefix), 7 (overly verbose suffix `ToAutoscaling`). - **Suggested name:** `UpgradeDatabaseInstanceRequest` (with an `autoscaling: true` toggle) or `EnableAutoscalingRequest` + `enableAutoscaling`. Pick one and match. - **Rationale:** All other CRUD methods are `xDatabaseInstance`; this method's shorter prefix is jarring. Also the request struct has only `name` — the verb `upgradeInstanceToAutoscaling` packs the full target state into the method name, which is awkward. -### 14. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:1017`, `index.ts:3` +### 9. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:1017`, `index.ts:3` - **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. - **Rationale:** The current name reads ambiguously; class names should be noun phrases describing *what they are*. The export at index.ts:3 means consumers see it directly. -### 15. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:393,399,411` +### 10. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:393,399,411` - **Why weird:** `attributes` is a generic field name; `effectiveAttributes` is a second copy; the type is a nested message that holds 3 Postgres role boolean flags. "Attributes" carries no information about what the attributes describe (Postgres `CREATEDB` / `CREATEROLE` / `BYPASSRLS` permission flags). - **Category:** 1 (vague — `attributes` is generic), 15 (generic field name). - **Suggested name:** `pgRoleFlags` / `PgRoleFlags`, or `permissions` / `RolePermissions`. - **Rationale:** Reader hits `role.attributes.createdb` and has to consult the type to find out it's a Postgres-flag bag. Postgres docs use the phrase "role attributes" so the alignment is intentional — but the SDK is for non-Postgres-experts too. -### 16. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:545,589` +### 11. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:545,589` - **Why weird:** The list-response field on catalogs is `databaseCatalogs: DatabaseCatalog[]` (matches type name), but on synced tables it's `syncedTables: SyncedDatabaseTable[]` (drops `Database`). On instance-roles it's `databaseInstanceRoles: DatabaseInstanceRole[]` (matches). On instances it's `databaseInstances: DatabaseInstance[]` (matches). The synced-tables one is the odd one out. - **Category:** 17 (inconsistent), 9 (singular/plural mismatch with the type). - **Suggested name:** `syncedDatabaseTables: SyncedDatabaseTable[]` (wire stays `synced_tables` if API requires it). @@ -113,217 +83,193 @@ ## Medium severity -### 17. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:236,238` +### 12. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:236,238` - **Why weird:** Two fields look like identifiers. `uid` is "immutable UUID identifier"; `name` is "unique identifier". Caller reading the struct can't tell at a glance which one to pass to `getDatabaseInstance` (answer: `name`, per client.ts:517). Bare `uid` is also non-descriptive — Lakebase uses both PG-side OIDs and Databricks-side UUIDs. - **Category:** 19 (underspecified id when multiple ids exist), 1 (vague `uid`). - **Suggested name:** `instanceUid` / `instanceName`, or `id` / `name` (collapse `uid` to `id`). - **Rationale:** Same field-disambiguation pattern as `PolicyInfo.id` in the abacpolicies audit. `uid` reads as a hash, not a Databricks UUID — and the JSDoc just says "UUID identifier". -### 18. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:240` +### 13. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:240` - **Why weird:** Field doc says "The email of the creator of the instance". Field name says `creator`. So is the value an email, a username, or an account id? Postgres SDK uses `createdBy` for the same concept (postgres/v1/model.ts). - **Category:** 1 (vague — `creator` could be a name, an id, or an email), 6 (misleading — doc says email, name says creator). - **Suggested name:** `creatorEmail` (or `createdBy` if the value can be a service-principal id too). - **Rationale:** The doc explicitly narrows the type; the field name should match. -### 19. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:250` +### 14. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:250` - **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. - **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). - **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". - **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. -### 20. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:248` +### 15. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:248` - **Why weird:** `pg` is two letters lowercase; the next word starts capitalised. Consistent with `pgType` (model.ts:881) but inconsistent with `Postgres`/`PostgreSQL` used in JSDoc. Acronym `PG` is widely written uppercase. - **Category:** 3 (acronym casing — `pg` should arguably be `Pg` per camelCase, `PG` per acronym preservation). - **Suggested name:** `postgresVersion` (spell out), or `pgVersion` (current). -- **Rationale:** The codebase elsewhere uses `Pg` (e.g. enum `SyncedTableSpec_PgSpecificType`). Current `pgVersion` is OK but `postgresVersion` would be clearer. +- **Rationale:** Current `pgVersion` is OK but `postgresVersion` would be clearer. -### 21. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:242,289` +### 16. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:242,289` - **Why weird:** `Dns` is a single word; `DNS` is the acronym. Field doc says "The DNS endpoint to connect to the instance"; the value is a hostname, not a DNS server. Misleading abbreviation. - **Category:** 3 (acronym casing), 6 (misleading — `dns` suggests a DNS server, not an endpoint). - **Suggested name:** `readWriteEndpoint` / `readOnlyEndpoint`, or `readWriteHost` / `readOnlyHost`. - **Rationale:** A "DNS endpoint" is a non-standard phrase; the field is just a hostname. -### 22. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:258,264` +### 17. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:258,264` - **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? - **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). - **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. - **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. -### 23. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:269` +### 18. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:269` - **Why weird:** Field name says "node count"; doc says "1 primary and 0 or more secondaries". `nodeCount = 3` means 1 primary + 2 secondaries — but also could be read as "3 nodes, role unspecified". Postgres standby/replica terminology would be clearer. - **Category:** 1 (vague), 6 (misleading without docs). - **Suggested name:** `replicaCount`, or pair `primaryCount` + `secondaryCount`, or `totalNodeCount` (and document). - **Rationale:** Confusing arithmetic — `1` means primary-only, `2` means 1 primary + 1 secondary, etc. -### 24. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:278` +### 19. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:278` - **Why weird:** `enableXyz: boolean` is a request-shaped name on a response-shaped type. `enableReadableSecondaries: true` reads as imperative ("please enable"), but it's also returned from server. The companion `effectiveEnableReadableSecondaries` reads as "the effective please-enable-readable-secondaries". The doc on `effectiveEnableReadableSecondaries` even rewords it: "Whether secondaries serving read-only traffic are enabled" — i.e. the read shape should just be `readableSecondariesEnabled` or `hasReadableSecondaries`. - **Category:** 6 (misleading verb form for a response), 17 (input/output asymmetry). - **Suggested name:** Input: `enableReadableSecondaries: boolean`. Output: `readableSecondariesEnabled: boolean` (or just merge: response carries the same `enableReadableSecondaries` and don't bother with the `effective_` twin). - **Rationale:** Generator artefact, but worth flagging. -### 25. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:309,314` +### 20. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:309,314` - **Why weird:** `Ref` is a cryptic abbreviation (cf. `typescript.mdc` "spell out short identifiers"). Same as `DatabaseInstanceRef` itself. Could be `Reference` or just `DatabaseInstancePointer`. The semantic ("a reference to an instance") doesn't need the abbreviation. - **Category:** 5 (cryptic abbreviation), 8 (redundant `Ref` suffix — these are already references). - **Suggested name:** `parentInstance: DatabaseInstanceReference` / `childInstances: DatabaseInstanceReference[]`. - **Rationale:** Mild — `Ref` is widely understood — but spelling out matches the project rule. -### 26. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:362` +### 21. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:362` - **Why weird:** `lsn` is a Postgres-internal acronym (Log Sequence Number) shown without expansion. JSDoc says "User-specified WAL LSN" — still abbreviated. - **Category:** 5 (cryptic abbreviation), 14 (Postgres-internal term in public TS API). - **Suggested name:** `walLsn` (mild improvement), or `walLogSequenceNumber` (verbose but unambiguous). - **Rationale:** Lakebase exposes this to schedule branch creation; consumers may not know `lsn` without consulting Postgres docs. -### 27. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:381` +### 22. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:381` - **Why weird:** `branchTime` is a noun-phrase that reads as "the time of a branch" but is documented as "the point in time on the parent instance from which the instance was created" — i.e. the PITR cutover instant. `branchTime` and `lsn` are alternatives for the same operation (PITR cutover specifier). - **Category:** 1 (vague), 6 (misleading — `branchTime` suggests an event time, actually a cutover specifier). - **Suggested name:** `branchPointTime` / `branchAt` / `pitrTimestamp`. - **Rationale:** Reads naturally as "when was this branch made" but actually means "what point in the source's history to branch from". -### 28. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:224` +### 23. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:224` - **Why weird:** Bare `uid?: string` with no comment, alongside `name`, `databaseInstanceName`, `databaseProjectId`, `databaseBranchId`, `databaseName`. Six identifier-like fields and one (`uid`) is undocumented and unprefixed. - **Category:** 19 (underspecified id), 1 (vague). - **Suggested name:** `catalogUid` (and add a doc comment). - **Rationale:** Reader cannot guess what scope the uid is for. -### 29. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:225` +### 24. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:225` - **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF NOT EXISTS`). Reads as a literal SQL DDL fragment in the type. Could be `ensureDatabase` / `autoCreateDatabase`. - **Category:** 14 (SQL-style name), 7 (verbose). - **Suggested name:** `ensureDatabaseExists` / `autoCreateDatabase`. - **Rationale:** Internal consistency with TS naming conventions. -### 30. `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` — `src/v1/model.ts:219-223` +### 25. `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` — `src/v1/model.ts:219-223` - **Why weird:** `databaseProjectId` reads as "project id of a database (entity)" but doc says "project_id of the database project". The `database` prefix on every field is redundant once you're already inside `DatabaseCatalog`. Postgres SDK has `Catalog` (no `database` prefix) with `project`, `branch`, `database` sub-references — cleaner. - **Category:** 7 (verbose prefix), 12 (duplicate concept across packages). - **Suggested name:** `projectId`, `branchId`, `name` on the catalog directly; or hoist to a sub-struct `database: {projectId, branchId, name}`. - **Rationale:** The struct is already a `DatabaseCatalog`; re-prefixing every field is noise. -### 31. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:419` +### 26. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:419` - **Why weird:** Bare `name` carries a complex format (`catalog.schema.table`). Postgres SDK calls the same concept `fullName` / `name` more explicitly. There is no validation in the type — the convention is doc-only. - **Category:** 1 (vague), 6 (misleading — name looks like a single identifier, actually 3-part). - **Suggested name:** `fullName` (matches Postgres SDK convention). - **Rationale:** Same field name `name` appears on `DatabaseCatalog`, `DatabaseInstance`, `DatabaseInstanceRef`, `DatabaseInstanceRole`, `DatabaseTable`, `SyncedDatabaseTable` — each carries different semantics (DNS-safe vs UC-3-part vs role-name). -### 32. `DatabaseTable.tableServingUrl` field — `src/v1/model.ts:437` +### 27. `DatabaseTable.tableServingUrl` field — `src/v1/model.ts:437` - **Why weird:** `tableServingUrl` on a `DatabaseTable` reads as "the URL where this table is served". Doc says "Data serving REST API URL for this table". The word `Serving` is ML/feature-store jargon; on a Postgres table it's confusing. - **Category:** 1 (vague), 6 (misleading — `Serving` is feature-store terminology, here means "REST endpoint"). - **Suggested name:** `restEndpointUrl` / `apiEndpointUrl`. - **Rationale:** Avoid leaking the internal "data serving" abstraction. -### 33. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:417,643` +### 28. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:417,643` - **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`, `tableServingUrl`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". - **Category:** 12 (duplicate concept), 1 (generic `Database`). - **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. - **Rationale:** Reader has to read both JSDocs to understand the partitioning. -### 34. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:802` +### 29. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:802` - **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`, `tableServingUrl`) split words at capital boundaries. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Trivia, but `time series` is two words in English. -### 35. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:798,419` +### 30. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:798,419` - **Why weird:** Same domain concept (UC 3-part name) named two different ways in the same package: `sourceTableFullName` here, bare `name` on `DatabaseTable`/`SyncedDatabaseTable`/`DatabaseCatalog`. - **Category:** 17 (inconsistent naming for the same concept). - **Suggested name:** Standardise on `fullName` (or `tableFullName`) across the package. -- **Rationale:** Pair with #31. +- **Rationale:** Pair with #26. -### 36. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:815` -- **Why weird:** Similar SQL-DDL leak as #29. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. +### 31. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:815` +- **Why weird:** Similar SQL-DDL leak as #24. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. - **Category:** 14 (SQL-style name), 6 (typo in cross-reference). - **Suggested name:** `ensureDatabaseAndSchema`. - **Rationale:** Internal consistency. -### 37. `SyncedTableSpec.acceleratedSync` — `src/v1/model.ts:830` +### 32. `SyncedTableSpec.acceleratedSync` — `src/v1/model.ts:830` - **Why weird:** Adjective-noun toggle; reads as "use accelerated sync" but unclear what "accelerated" means. JSDoc says "enables accelerated sync mode for the initial data load." - **Category:** 1 (vague — what *is* accelerated sync?), 15 (generic adjective). - **Suggested name:** `useAcceleratedInitialLoad` or `accelerateInitialLoad`. - **Rationale:** A consumer should not have to read JSDoc to know "accelerated" means "initial-load fast path". -### 38. `SyncedTableSpec.extraIndexDefinitions` vs `SyncedTableSpec_SecondaryIndex` (type) — `src/v1/model.ts:837,863` -- **Why weird:** Field is `extraIndexDefinitions` (plural noun, generic suffix), but the type is `SecondaryIndex`. Field-type mismatch: type says "secondary index"; field says "extra index definitions". Both are accurate, but using two different framings within five lines is confusing. -- **Category:** 17 (inconsistency between field name and type name), 1 (`extra` is vague). -- **Suggested name:** `secondaryIndexes: SecondaryIndex[]` (drop `Definitions` suffix — type already implies definition). -- **Rationale:** Type-name and field-name should align. - -### 39. `SyncedTableSpec.extraColumnDefinitions` vs `SyncedTableSpec_ExtraColumnDefinition` — `src/v1/model.ts:839,847` -- **Why weird:** Field `extraColumnDefinitions: ExtraColumnDefinition[]` — at least these align. But `ExtraColumnDefinition` itself is two redundant words (column definitions are themselves definitions). `Extra` modifier doesn't say what they're extra to. -- **Category:** 7 (verbose), 1 (`extra` is vague). -- **Suggested name:** `pgOnlyColumns: PgOnlyColumn[]` (doc says "additional PostgreSQL-only column"). -- **Rationale:** The doc has the better name buried in it. - -### 40. `SyncedTableSpec.typeOverrides: SyncedTableSpec_TypeOverride[]` — `src/v1/model.ts:835` -- **Why weird:** Plural list of nested `Foo_TypeOverride` types. Field name matches but the nested type has the `_` underscore problem (#4). Reads as "type overrides are type-override objects" — circular. -- **Category:** 17 (mirror name), 4 (underscore type). -- **Suggested name:** `columnTypeOverrides: ColumnTypeOverride[]` (the override is per-column, so be specific). -- **Rationale:** Plain `typeOverrides` is too generic; could be Delta types, JSON types, etc. - -### 41. `SyncedTableSpec_TypeOverride.pgType` field of type `SyncedTableSpec_PgSpecificType` — `src/v1/model.ts:881` -- **Why weird:** Type-suffix tautology: `pgType: PgSpecificType`. Wire is `pg_type`. Doc says "PostgreSQL-specific target type". -- **Category:** 20 (type-suffix tautology), 4 (nested underscore type as field type). -- **Suggested name:** `targetType: PgColumnType`. -- **Rationale:** Rule 20. - -### 42. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:892` +### 33. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:892` - **Why weird:** Field is `detailedState`; sibling field is `detailedStatus`. Both have `detailed` prefix; redundant against the wrapping type `SyncedTableStatus`. Easy to confuse `detailedState` (enum) with `detailedStatus` (oneof). - **Category:** 17 (two `detailed*` neighbours), 7 (verbose). - **Suggested name:** `state: SyncedTableState`, `status: SyncedTableStatusDetail` (or hoist the oneof). - **Rationale:** Reader hits `tableStatus.detailedState` and `tableStatus.detailedStatus` and has to read both to decide which is which. -### 43. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:896` +### 34. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:896` - **Why weird:** `detailedStatus` on a `SyncedTableStatus` type is doubly redundant. Holds one of four phase-shaped sub-statuses (`provisioningStatus`, `continuousUpdateStatus`, `triggeredUpdateStatus`, `failedStatus`). Each variant is named `*Status` again — `tableStatus.detailedStatus.continuousUpdateStatus.lastProcessedCommitVersion` is "status.status.status.version". -- **Category:** 7 (overly verbose chains), 20 (type-suffix tautology). +- **Category:** 7 (overly verbose chains). - **Suggested name:** Rename `detailedStatus` to `phase`, and strip the redundant `*Status` suffix off each sub-variant (`provisioning`, `continuousUpdate`, `triggeredUpdate`, `failed`). - **Rationale:** Reduces three `status` words to one without touching the wrapper itself. -### 44. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:928` +### 35. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:928` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 45. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:749` +### 36. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:749` - **Why weird:** Run-on field name — "latest version currently processing" is 4 words. Doc clarifies "may not have completely processed this version yet". Could be `inProgressDeltaVersion` or `currentDeltaVersion`. - **Category:** 7 (overly verbose), 1 (verbose adverb). - **Suggested name:** `processingDeltaVersion`. - **Rationale:** Verbose field names hurt readability. -### 46. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:751-757` +### 37. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:751-757` - **Why weird:** Mixed metric naming: `syncedRowCount` and `totalRowCount` use suffix `Count`; `syncProgressCompletion` uses suffix `Completion` (a number 0-1); `estimatedCompletionTimeSeconds` uses suffix `TimeSeconds` (unit-embedded). Three different conventions for "a number". - **Category:** 17 (inconsistent suffixes), 15 (generic field names). - **Suggested name:** `syncedRows`, `totalRows`, `progressFraction`, `etaSeconds`. - **Rationale:** The number-suffix conventions don't align with each other; pick one. -### 47. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:754-755` +### 38. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:754-755` - **Why weird:** Type is `number`; doc constrains to `[0, 1]`. Type system doesn't help. Field name `syncProgressCompletion` is also redundant — completion is what progress measures. - **Category:** 16 (type contradicts doc constraint), 7 (verbose). - **Suggested name:** `progressFraction` (or `progressRatio`), `number` in [0,1]. -- **Rationale:** Same as #46 plus a separate concern about the value range. +- **Rationale:** Same as #37 plus a separate concern about the value range. -### 48. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:477` +### 39. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:477` - **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. - **Category:** 20 (type-suffix tautology in field names), 7 (verbose). - **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. - **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. -### 49. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:510,630` +### 40. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:510,630` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 50. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:500` +### 41. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:500` - **Why weird:** Bare `requestId` with no doc. Other request types do not have `requestId`. Looks like an idempotency key but the type doesn't say. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `idempotencyKey` (and add docs). - **Rationale:** Without docs, callers can't tell whether to set it. -### 51. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:501-502` +### 42. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:501-502` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 52. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:453-456` +### 43. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:453-456` - **Why weird:** "Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. Setting a value of false will throw a bad request." Field is exposed in the public TS type but has no `@deprecated` JSDoc tag. - **Category:** 6 (misleading: deprecated field undocumented as deprecated). - **Suggested name:** Add `@deprecated` tag; consider removing in next major. @@ -331,85 +277,61 @@ ## Low severity -### 53. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:553` +### 44. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:553` - **Why weird:** Doc says "Pagination token to go to the next page of Database Instances" — but this is roles, not instances. Doc-copy bug. - **Category:** 6 (misleading doc). - **Suggested name:** Fix the doc to say "roles". - **Rationale:** Naming-adjacent bug worth flagging. -### 54. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:539` +### 45. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:539` - **Why weird:** Same bug: catalogs request says "synced database tables" in doc. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "catalogs". -- **Rationale:** Same as #53. +- **Rationale:** Same as #44. -### 55. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:562` +### 46. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:562` - **Why weird:** Doc says "next page of instances" for the roles response. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "roles". -- **Rationale:** Same as #53. +- **Rationale:** Same as #44. -### 56. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:192-196` +### 47. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:192-196` - **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:185-188). - **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). - **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. - **Rationale:** Caller has to know the wire-encoding accident to decide which to set. -### 57. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:462` +### 48. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:462` - **Why weird:** Postgres-isms (`REASSIGN OWNED BY ... TO ...`) collapsed into a single field. Field name reads as a verb phrase ("reassign owned [things] to"). - **Category:** 14 (SQL-style name). - **Suggested name:** `reassignOwnedObjectsTo` or `newOwner`. - **Rationale:** Mild — Postgres admins will get it. -### 58. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:463-464` +### 49. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:463-464` - **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. - **Category:** 14 (Google-AIP naming convention leak). - **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. - **Rationale:** Internal-jargon leak; flag for awareness. -### 59. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:474` +### 50. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:474` - **Why weird:** Boolean named after a side effect (`purge_data`). Doc says "the actual PostgreSQL table will be dropped from the database". Combination of `delete` + `purge` is also confusing — what does the no-purge case do? (Drop UC registration only.) - **Category:** 1 (vague), 6 (misleading). - **Suggested name:** `dropUnderlyingTable` / `cascade`. - **Rationale:** Minor — affects discoverability. -### 60. `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` — `src/v1/model.ts:490` +### 51. `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` — `src/v1/model.ts:490` - **Why weird:** 30-character field name on a 2-field request. Reads as "failover target database instance name" which is 5 nouns stacked. - **Category:** 7 (overly verbose). - **Suggested name:** `targetInstanceName`. - **Rationale:** Inside a `FailoverDatabaseInstanceRequest`, the `failover` and `databaseInstance` prefixes are implied. -### 61. `RequestedClaims_PermissionSet.PERMISSION_SET_UNSPECIFIED` redundant prefix — `src/v1/model.ts:161` -- **Why weird:** Same enum-prefix pattern as #9/#10 — `PERMISSION_SET_UNSPECIFIED` re-states the enum name. -- **Category:** 2 (redundant enum prefix). -- **Suggested name:** Drop the prefix. -- **Rationale:** Same. - -### 62. `SyncedTableSpec_PgSpecificType.PG_SPECIFIC_TYPE_UNSPECIFIED` / `PG_SPECIFIC_TYPE_VECTOR` — `src/v1/model.ts:169,171` -- **Why weird:** Both enum values prefixed `PG_SPECIFIC_TYPE_`. -- **Category:** 2 (redundant prefix), 18 (long enum values). -- **Suggested name:** `PgColumnType.Unspecified | Vector`. -- **Rationale:** Same. - -### 63. `SyncedTableSpec_SecondaryIndex_CreationPoint.CREATION_POINT_*` — `src/v1/model.ts:178,180` -- **Why weird:** `CREATION_POINT_UNSPECIFIED` / `CREATION_POINT_AFTER_DATA_LOAD`. Same redundant prefix. -- **Category:** 2 (redundant prefix). -- **Suggested name:** `IndexCreationPoint.Unspecified | AfterDataLoad` (drop `CREATION_POINT_`). -- **Rationale:** Same. - -### 64. `DatabaseInstanceRole_IdentityType.PG_ONLY` — `src/v1/model.ts:129` -- **Why weird:** All-caps acronym suffix `PG_ONLY` — the only non-`UNSPECIFIED` value that is not a full English word (`USER`, `SERVICE_PRINCIPAL`, `GROUP`). Reads as a flag, not an identity type. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistent with peers). -- **Suggested name:** `PostgresOnly` (spell out). -- **Rationale:** Aligns with peers. - -### 65. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:82` +### 52. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:82` - **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency. -### 66. `StillRunningError` private error class — `src/v1/client.ts:87` +### 53. `StillRunningError` private error class — `src/v1/client.ts:87` - **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. - **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). - **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). @@ -417,16 +339,16 @@ ## Observations -### 67. `client.ts` has a 6-line block-comment at line 666-671 explaining that the role APIs will never reach Public Preview +### 54. `client.ts` has a 6-line block-comment at line 666-671 explaining that the role APIs will never reach Public Preview The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. - **Category:** 6 (misleading: client exposes APIs that won't stabilise). - **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. -### 68. `findDatabaseInstanceByUid` is the only `findBy*` method +### 55. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 69. Action-verb conventions in `Client` are consistent +### 56. Action-verb conventions in `Client` are consistent `create*` / `delete*` / `get*` / `list*` / `update*` / `failover*` / `findBy*` / `upgrade*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. ## Domain glossary diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md index ccca0263..1bcbc426 100644 --- a/.agent/naming-audit/dataclassification.md +++ b/.agent/naming-audit/dataclassification.md @@ -3,55 +3,43 @@ **Path:** `packages/dataclassification/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 21 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | -| High | 7 | +| High | 5 | | Medium | 4 | | Low | 6 | | Observation | 4 | ## High severity -### 1. `AutoTaggingConfig_AutoTaggingMode` — `src/v1/model.ts:9` -- **Why weird:** Underscore in TS identifier (proto-style nested enum name). Required `eslint-disable @typescript-eslint/naming-convention`. The outer container `AutoTaggingConfig` is already in scope of import, so the prefix is redundant; the underscore is a leaky proto abstraction. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names not idiomatic in TS), 20 (type-suffix tautology — `AutoTaggingConfig_AutoTaggingMode` re-states `AutoTagging`). -- **Suggested name:** `AutoTaggingMode` (top-level), or namespace it under `AutoTaggingConfig` via TS namespace if nesting really must be preserved. -- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`. The `eslint-disable` directive is the smoking gun that the name fights the language. `AutoTaggingMode` is unambiguous on its own; the field that uses it is already named `autoTaggingMode`. - -### 2. `AutoTaggingConfig_AutoTaggingMode.AUTO_TAGGING_MODE_UNSPECIFIED` / `AUTO_TAGGING_DISABLED` / `AUTO_TAGGING_ENABLED` — `src/v1/model.ts:10-12` -- **Why weird:** Every enum value re-states the enum name (`AutoTaggingMode.AUTO_TAGGING_*`). The `UNSPECIFIED` sentinel is a protobuf import; idiomatic TS would use `undefined` for "not set". Also note that the unspecified value carries the `_MODE_` infix while the other two drop it — inconsistent. -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names), 17 (action-prefix inconsistency — `_MODE_` is present on `UNSPECIFIED` but missing on `DISABLED`/`ENABLED`). -- **Suggested name:** `AutoTaggingMode.Disabled | Enabled` (drop `Unspecified` and rely on `autoTaggingMode?: AutoTaggingMode | undefined`). -- **Rationale:** TS enum members are already namespaced by the enum (`AutoTaggingMode.Enabled`). The `AUTO_TAGGING_` prefix is pure protobuf noise. A binary on/off concept does not need a third "unset" sentinel when the field is already optional. - -### 3. `autoTagConfigs` field vs. `AutoTaggingConfig` type — `src/v1/model.ts:57,62` +### 1. `autoTagConfigs` field vs. `AutoTaggingConfig` type — `src/v1/model.ts:57,62` - **Why weird:** Field name uses abbreviated `autoTag` while the type it points to is the full `AutoTaggingConfig`. Within five lines the SDK uses both `tag`-noun and `tagging`-gerund for the same concept. - **Category:** 5 (cryptic abbreviation — `Tag` for `Tagging`), 17 (inconsistency with sibling type — `autoTagConfigs: AutoTaggingConfig[]`). - **Suggested name:** `autoTaggingConfigs: AutoTaggingConfig[]` (and `effectiveAutoTaggingConfigs`). Wire stays `auto_tag_configs` if upstream insists. - **Rationale:** A field of `Foo[]` should plural-ise the type name: `foos: Foo[]`. Mixing `autoTag` and `AutoTagging` makes the relationship unobvious and forces a mental translation on every read. -### 4. `effectiveAutoTagConfigs` — `src/v1/model.ts:62` +### 2. `effectiveAutoTagConfigs` — `src/v1/model.ts:62` - **Why weird:** Two parallel fields (`autoTagConfigs` for owned + `effectiveAutoTagConfigs` for owned-plus-inherited) on the same type. "Effective" is fine on its own, but the parent type does not say which is read-only vs. write — a caller can easily set `effectiveAutoTagConfigs` thinking it will take effect. - **Category:** 1 (vague — `effective` does not communicate "computed/read-only" on its own), 6 (misleading: looks settable but is server-computed). - **Suggested name:** `inheritedAutoTaggingConfigs` (or split into `autoTaggingConfigs` + `computedAutoTaggingConfigs` with a JSDoc `@readonly`). - **Rationale:** SDK fields without an output-only marker invite write-side mistakes. The current doc says "Computed from auto_tag_configs on this catalog and those inherited from the metastore" but the type does not enforce that. -### 5. `name` field on `CatalogConfig` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` — `src/v1/model.ts:42,88,94` +### 3. `name` field on `CatalogConfig` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` — `src/v1/model.ts:42,88,94` - **Why weird:** Field literally called `name` carries a structured resource path (`catalogs/{catalog_name}/config`), not a free-form name. `name` is the most generic possible identifier and gives no hint that it must follow a specific format. - **Category:** 1 (vague — `name` is the canonical too-generic field name), 6 (misleading — looks like a display name, is actually a structured resource path), 15 (generic field name losing meaning), 19 (underspecified ID). - **Suggested name:** `resourceName` or `configResourceName`. If staying with `name`, the JSDoc should at least be on the type rather than only on each field. - **Rationale:** A user importing `CatalogConfig` and seeing `name?: string` will almost certainly try to put `"my-catalog"` in there, not `"catalogs/my-catalog/config"`. The wire constraint is invisible from the type. -### 6. `parent` field on `CreateCatalogConfigRequest` — `src/v1/model.ts:77` +### 4. `parent` field on `CreateCatalogConfigRequest` — `src/v1/model.ts:77` - **Why weird:** Field called `parent` carries the structured value `catalogs/{catalog_name}`. The relationship "catalog is the parent of catalog-config" is a proto/AIP-160 convention that does not survive into a TS SDK where users do not see the resource hierarchy. - **Category:** 1 (vague — `parent` of what?), 15 (generic field name losing meaning), 19 (underspecified ID). - **Suggested name:** `catalogResourceName` or `parentCatalog`. - **Rationale:** `parent: string` is a Google-AIP idiom; outside that context a caller has no idea what shape to put in. A user-friendly TS SDK would either accept `{catalogName: 'my-catalog'}` directly or rename to make the constraint visible. -### 7. `classificationTag` and `classificationTagValue` — `src/v1/model.ts:25,32` +### 5. `classificationTag` and `classificationTagValue` — `src/v1/model.ts:25,32` - **Why weird:** The pair encodes a `(key, value)` tag, but the names are `tag` and `tagValue` instead of `tagKey` and `tagValue`. The first field actually holds the tag *key* per its doc ("For built-in classes this is a system tag (e.g., \"class.name\"...)"). Calling the key "the Classification Tag" while the value is "the Classification Tag Value" makes the parts asymmetric. - **Category:** 1 (vague — `classificationTag` is the key, not the whole tag), 6 (misleading — name suggests "the tag" but it is one half of one), 17 (asymmetric pair naming — `tag` vs `tagValue`). - **Suggested name:** `classificationTagKey` + `classificationTagValue` (or `tagKey` + `tagValue`). @@ -59,25 +47,25 @@ ## Medium severity -### 8. `Client` class — `src/v1/client.ts:38` +### 6. `Client` class — `src/v1/client.ts:38` - **Why weird:** A class literally named `Client` at the top level of the package's API surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). - **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. -### 9. `CreateCatalogConfigRequest` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` / `UpdateCatalogConfigRequest` — `src/v1/model.ts:75,86,92,103` +### 7. `CreateCatalogConfigRequest` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` / `UpdateCatalogConfigRequest` — `src/v1/model.ts:75,86,92,103` - **Why weird:** All four request DTOs repeat the noun `CatalogConfig` even though the only thing this package operates on is `CatalogConfig`. The package name itself is `dataclassification`. In context, `CreateRequest`/`UpdateRequest` would be plenty. - **Category:** 7 (overly verbose), 8 (redundant suffix and infix). - **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`, or keep `Catalog` and drop `Config`: `CreateCatalogRequest`/... - **Rationale:** The whole package operates on exactly one entity. Repeating its name in four request types is pure noise. (However, the inconsistency with the entire rest of the SDK matters — proposing as a per-package fix is risky. Listed medium not high.) -### 10. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 8. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. -### 11. `flattenQueryParams` — `src/v1/utils.ts:123` +### 9. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. @@ -85,37 +73,37 @@ ## Low severity -### 12. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` +### 10. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 13. `userAgent` field — `src/v1/client.ts:45` +### 11. `userAgent` field — `src/v1/client.ts:45` - **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. - **Category:** N/A (verification, no issue). - **Suggested name:** unchanged. - **Rationale:** Listed only to confirm canonical naming is preserved. -### 14. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` +### 12. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 15. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` +### 13. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` - **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. - **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. -### 16. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` +### 14. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 17. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` +### 15. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` - **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. @@ -123,24 +111,24 @@ ## Observations -### 18. Wire/TS divergence is heavy +### 16. Wire/TS divergence is heavy The model file is 229 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. -### 19. Action-verb conventions in `Client` +### 17. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) -### 20. Acronym casing +### 18. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 21. `dataclassification` lowercase package name +### 19. `dataclassification` lowercase package name The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). ## Domain glossary - `uc` / Unity Catalog — implicit across all types (the configured resource is a UC catalog). - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `auto-tagging` / `auto-tag` — automatic application of governance tags to columns classified by the scanner (used both as gerund `AutoTagging` in types and as noun `AutoTag` in field names — see #3). +- `auto-tagging` / `auto-tag` — automatic application of governance tags to columns classified by the scanner (used both as gerund `AutoTagging` in types and as noun `AutoTag` in field names — see #1). - `system tag` / `governance tag` — terminology in JSDoc for `classificationTag` (built-in vs. custom class tag keys). - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 56bbda08..eb6c8071 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -29,25 +29,25 @@ ### 3. `RefreshState` enum members `MONITOR_REFRESH_STATE_*` — `src/v1/model.ts:80-90` - **Why weird:** Enum is called `RefreshState`, but every member is prefixed `MONITOR_REFRESH_STATE_` — three levels of redundancy in one token (the enum name says it, the type appears as `state?: RefreshState`, and the value is fully namespaced as `RefreshState.MONITOR_REFRESH_STATE_RUNNING`). Members also include `MONITOR_REFRESH_STATE_UNKNOWN` while every other enum in this file uses `_UNSPECIFIED` — inconsistent sentinel naming. -- **Category:** 2 (redundant enum prefixes), 14 (proto/Go-style names), 17 (inconsistent sentinel — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 18 (overly long enum values). +- **Category:** 2 (redundant enum prefixes), 17 (inconsistent sentinel — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 18 (overly long enum values). - **Suggested name:** `RefreshState.{Pending, Running, Success, Failed, Canceled}` and drop the unset sentinel (rely on `state?: RefreshState | undefined`). At minimum, normalise to `REFRESH_STATE_*` (drop `MONITOR_`). - **Rationale:** The TS enum already namespaces values (`RefreshState.RUNNING`). `MONITOR_` is doubly redundant because the enum is only ever reached from `Refresh.state`, which is owned by a `Monitor`. The `UNKNOWN`/`UNSPECIFIED` inconsistency with `RefreshTrigger.MONITOR_REFRESH_TRIGGER_UNKNOWN` vs `AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_UNSPECIFIED` will trip API users who write `===` checks. ### 4. `RefreshTrigger` enum members `MONITOR_REFRESH_TRIGGER_*` — `src/v1/model.ts:94-101` - **Why weird:** Same shape as #3. Six-token names (`MONITOR_REFRESH_TRIGGER_DATA_CHANGE`) where two tokens (`DataChange`) would suffice. Also uses `_UNKNOWN` rather than the more common `_UNSPECIFIED`. -- **Category:** 2 (redundant enum prefix), 14 (proto-style), 17 (sentinel inconsistency), 18 (long enum values). +- **Category:** 2 (redundant enum prefix), 17 (sentinel inconsistency), 18 (long enum values). - **Suggested name:** `RefreshTrigger.{Manual, Schedule, DataChange}`. - **Rationale:** Same as #3. ### 5. `AggregationGranularity` enum members `AGGREGATION_GRANULARITY_N_*` — `src/v1/model.ts:8-30` - **Why weird:** Every value re-states the enum name and then mixes digits with words (`AGGREGATION_GRANULARITY_5_MINUTES`, `AGGREGATION_GRANULARITY_2_WEEKS`). The digit-then-unit form does not map to any TS identifier convention. `_UNSPECIFIED` is the bottom value, so a user must read past it to see `_5_MINUTES` is the smallest real granularity. -- **Category:** 2 (redundant enum prefix), 14 (proto-style), 18 (overly long enum values). +- **Category:** 2 (redundant enum prefix), 18 (overly long enum values). - **Suggested name:** `AggregationGranularity.{FiveMinutes, ThirtyMinutes, OneHour, OneDay, OneWeek, TwoWeeks, ThreeWeeks, FourWeeks, OneMonth, OneYear}` — or, better, drop the numeric quantum entirely and use an ISO-8601 duration string (`PT5M`, `P1D`) so the enum is open to new granularities without code changes. - **Rationale:** TS enums forbid leading digits in member names, which is why this enum carries the `AGGREGATION_GRANULARITY_` prefix — to make `_5_MINUTES` syntactically legal. That's a tell that the names are working around a language limit. Rename to spelled-out words. ### 6. `DataProfilingCustomMetricType` enum members — `src/v1/model.ts:49-57` - **Why weird:** Six tokens per member (`DATA_PROFILING_CUSTOM_METRIC_TYPE_AGGREGATE`). The enum itself is `DataProfilingCustomMetricType` — at the field site you'd write `DataProfilingCustomMetricType.DATA_PROFILING_CUSTOM_METRIC_TYPE_AGGREGATE`, six redundant tokens visible at the call site. -- **Category:** 2 (redundant enum prefix), 14 (proto-style), 18 (long enum values). +- **Category:** 2 (redundant enum prefix), 18 (long enum values). - **Suggested name:** `DataProfilingCustomMetricType.{Aggregate, Derived, Drift}`. - **Rationale:** Same as #3-#5. diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index 34e4bbf5..df1d886e 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -3,15 +3,15 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 28 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | -| High | 9 | +| High | 7 | | Medium | 11 | | Low | 5 | -| Observation | 3 | +| Observation | 2 | ## High severity @@ -21,37 +21,25 @@ - **Suggested name:** `FailoverRequest` (the resource is unambiguous in this package) or `TriggerFailoverRequest` (more explicit verb). - **Rationale:** No other request in the package re-states the resource word inside its verb. The wire path is `…/failover`, so a single `Failover` in the type name is sufficient. -### 2. `FailoverFailoverGroupRequest_FailoverType` — `src/v1/model.ts:10` -- **Why weird:** Underscore-bearing identifier (proto-style nested enum) **plus** stutter (`Failover` appears three times in one name: type, request, enum). Requires `eslint-disable @typescript-eslint/naming-convention`. -- **Category:** 4 (underscores in TS identifiers), 7 (overly verbose), 14 (proto/Go-style nested-type name). -- **Suggested name:** `FailoverType` at top level (hoist out of the request). With finding #1's rename, the alternative `FailoverRequest_FailoverType` still stutters and still needs an eslint-disable — so hoisting is the right fix. -- **Rationale:** TS namespaces nested enums via module + import path, not by underscore concatenation. The eslint-disable comment on line 9 is a tell that the name is fighting the language. - -### 3. `FailoverFailoverGroupRequest_FailoverType.FAILOVER_TYPE_UNSPECIFIED` / `.FORCED` — `src/v1/model.ts:11-12` +### 2. `FailoverFailoverGroupRequest_FailoverType.FAILOVER_TYPE_UNSPECIFIED` / `.FORCED` — `src/v1/model.ts:11-12` - **Why weird:** (a) `FAILOVER_TYPE_UNSPECIFIED` redundantly re-states the enum name; (b) shipping an `UNSPECIFIED` sentinel is a proto-import — idiomatic TS uses `undefined` for "not set"; (c) the actual content is a single real value (`FORCED`), which makes a two-member enum with one sentinel look like a placeholder. -- **Category:** 2 (redundant enum prefix), 14 (proto-style sentinel), 18 (long enum value). +- **Category:** 2 (redundant enum prefix), 18 (long enum value). - **Suggested name:** Drop `UNSPECIFIED`; keep `Forced` (or `Forced | Graceful` if the API ever grows a graceful mode). - **Rationale:** `failoverType?: FailoverType | undefined` already encodes "not set". Same rationale as the proto enum guidance applied across the SDK. -### 4. `FailoverGroup_State` — `src/v1/model.ts:17` -- **Why weird:** Underscore-bearing identifier (proto-style nested enum). Required `eslint-disable @typescript-eslint/naming-convention` on line 16. -- **Category:** 4 (underscores in TS identifiers), 14 (proto/Go-style). -- **Suggested name:** `FailoverGroupState` (PascalCase, no underscore). -- **Rationale:** Same as #2. Renaming removes the eslint disable and makes the type discoverable by IDE autocomplete on `FailoverGroupS…`. - -### 5. `FailoverGroup_State.STATE_UNSPECIFIED` — `src/v1/model.ts:18` -- **Why weird:** Redundant `STATE_` prefix on every value; `UNSPECIFIED` sentinel as in #3. The remaining values (`CREATING`, `CREATION_FAILED`, `INITIAL_REPLICATION`, `ACTIVE`, `FAILING_OVER`, `DELETING`, `FAILOVER_FAILED`, `DELETION_FAILED`) are reasonable, but the lone `STATE_UNSPECIFIED` is noise. -- **Category:** 2 (redundant enum prefix), 14 (proto sentinel). +### 3. `FailoverGroup_State.STATE_UNSPECIFIED` — `src/v1/model.ts:18` +- **Why weird:** Redundant `STATE_` prefix on every value; `UNSPECIFIED` sentinel as in #2. The remaining values (`CREATING`, `CREATION_FAILED`, `INITIAL_REPLICATION`, `ACTIVE`, `FAILING_OVER`, `DELETING`, `FAILOVER_FAILED`, `DELETION_FAILED`) are reasonable, but the lone `STATE_UNSPECIFIED` is noise. +- **Category:** 2 (redundant enum prefix). - **Suggested name:** Drop `STATE_UNSPECIFIED`. Keep the rest as-is or rename to PascalCase (`Creating`, `CreationFailed`, …) to match TS-style enum members. - **Rationale:** Optional `state?: FailoverGroupState` encodes the unset case. PascalCase members align with TS conventions while leaving the SCREAMING_SNAKE_CASE wire values intact via the Zod schema. -### 6. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,317` +### 4. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,317` - **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #28 — same issue applies in `utils.ts` field `url` on `StableUrl`.) +- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #25 — same issue applies in `utils.ts` field `url` on `StableUrl`.) -### 7. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` +### 5. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` - **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: - `effectivePrimaryRegion` — current truth; mutated by failover. - `initialPrimaryRegion` — create-only input; never returned. @@ -61,13 +49,13 @@ - **Suggested name:** Consider splitting: keep `primaryRegion` (effective) on `FailoverGroup`; lift `initialPrimaryRegion` into `CreateFailoverGroupRequest` as a sibling of `failoverGroup`; keep `targetPrimaryRegion` on `FailoverFailoverGroupRequest`. If the generator cannot split (since this mirrors a proto with output_only annotations), at minimum mark `initialPrimaryRegion` `@deprecated`-style write-only in JSDoc with a `WRITE-ONLY` tag. - **Rationale:** The current shape forces the user to read three different paragraphs to learn that the same-typed fields obey three different rules. This is the most user-hostile naming pattern in the file. -### 8. `replicationPoint: Temporal.Instant` — `src/v1/model.ts:144` +### 6. `replicationPoint: Temporal.Instant` — `src/v1/model.ts:144` - **Why weird:** `Point` is generic; this is a recovery-point timestamp (the data-loss bound aka RPO marker). The JSDoc says "The latest point in time to which data has been replicated", which is much clearer than the field name. A reader sees `failoverGroup.replicationPoint` and may guess "endpoint of replication" or "destination point". - **Category:** 1 (vague), 6 (misleading — `Point` suggests a location, not a time). - **Suggested name:** `replicationLagTime` / `lastReplicatedAt` / `recoveryPointTime` (the last matches Databricks DR docs and the well-known RPO term). - **Rationale:** Other timestamp fields on the same struct use the `…Time` suffix (`createTime`, `updateTime`). Consistency + clarity in one rename. -### 9. `replicateWorkspaceAssets` field on `WorkspaceSet` — `src/v1/model.ts:311` +### 7. `replicateWorkspaceAssets` field on `WorkspaceSet` — `src/v1/model.ts:311` - **Why weird:** Field documented as "Whether to enable control plane DR (notebooks, jobs, clusters, etc.) for this set." The field name says `replicateWorkspaceAssets` but the doc says "control plane DR" — those aren't synonyms. A user looking for "enable CPDR" will not find a `cpdr` field; a user looking for "replicate" will not realise this is the control-plane toggle vs the data-plane (UC) replication elsewhere on the parent. - **Category:** 6 (misleading — field name and doc disagree), 1 (vague — `workspaceAssets` is undefined jargon). - **Suggested name:** `enableControlPlaneReplication` (matches doc and matches the implied UCDR/CPDR split), or `replicateControlPlane`. @@ -75,67 +63,67 @@ ## Medium severity -### 10. `WorkspaceSet.name: string` (resource-name vs human-name ambiguity) — `src/v1/model.ts:301` +### 8. `WorkspaceSet.name: string` (resource-name vs human-name ambiguity) — `src/v1/model.ts:301` - **Why weird:** `name` on `WorkspaceSet` is documented only as "Resource name for this workspace set". `name` on `FailoverGroup` (line 120) is documented as a fully-qualified resource name (`accounts/{account_id}/failover-groups/{failover_group_id}`). `name` on `StableUrl` (line 252) is fully-qualified too. `name` on `LocationMapping` (line 227) is "Resource name for this location". A user can't tell from the field which `name`s are FQ resource names versus simple labels. - **Category:** 15 (generic field name losing meaning across types), 19 (under-specified identifier). - **Suggested name:** Where the value is FQ, prefer `resourceName`; where the value is a label, prefer `label` or `displayName`. Failing that, tighten every JSDoc to spell out the wire format like `FailoverGroup.name` does. - **Rationale:** The package has at least three different meanings for `name`. Searching IDE for `.name` in a `FailoverGroup` chain returns many hits with different semantics. -### 11. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:269` +### 9. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:269` - **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 131) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. - **Category:** 5 (cryptic abbreviation `Uc`), 8 (redundant `Uc` prefix inside Uc context), 17 (inconsistency — `unityCatalog` vs `Uc`). - **Suggested name:** `Catalog` (or `ReplicatedCatalog`), and field type `catalogs: Catalog[]`. - **Rationale:** `UcReplicationConfig.catalogs: UcCatalog[]` reads as "UC replication config's UC catalogs" — redundant. The full `unityCatalog` spelling is used adjacent in the file; either propagate that or drop the prefix entirely inside the UC-scoped type. -### 12. `UcReplicationConfig` — `src/v1/model.ts:275` +### 10. `UcReplicationConfig` — `src/v1/model.ts:275` - **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). -- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #13). +- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #11). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. -### 13. `unityCatalogAssets: UcReplicationConfig` — `src/v1/model.ts:131` +### 11. `unityCatalogAssets: UcReplicationConfig` — `src/v1/model.ts:131` - **Why weird:** Field named `unityCatalogAssets` but the type is `UcReplicationConfig`. "Assets" doesn't appear in the type name. The type contains location mappings + catalogs + a workspace-set reference — none of which are commonly called "assets". The sibling `replicateWorkspaceAssets` (line 311) uses "assets" with a completely different meaning (control-plane objects vs Unity Catalog config). - **Category:** 15 (generic word "assets" used in two different meanings within the file), 20 (type-suffix tautology since the field carries replication config of a `UcReplicationConfig`). - **Suggested name:** `unityCatalogReplication` or `unityCatalogConfig`. - **Rationale:** Field name should match the type's purpose; "assets" is a misleading umbrella here. -### 14. `WorkspaceSet.stableUrlNames: string[]` (with FQ-name semantics) — `src/v1/model.ts:317` +### 12. `WorkspaceSet.stableUrlNames: string[]` (with FQ-name semantics) — `src/v1/model.ts:317` - **Why weird:** Field is `string[]` of fully-qualified resource names (per JSDoc: `accounts/{account_id}/stable-urls/{stable_url_id}`). The name `stableUrlNames` implies a list of `StableUrl` objects' `name` field; the FQ-vs-id semantics are buried in the doc. - **Category:** 19 (under-specified identifier — strings that are actually FQ resource names), 6 (misleading singular/plural framing — these are references, not names). - **Suggested name:** `stableUrlRefs` or `stableUrlResourceNames` (matches the FQ semantics explicitly). - **Rationale:** Other places in the same SDK use `*Ref` or `*ResourceName` for FQ references; `*Names` is ambiguous (Could be display names? Could be IDs?). -### 15. `dataReplicationWorkspaceSet: string` — `src/v1/model.ts:284` +### 13. `dataReplicationWorkspaceSet: string` — `src/v1/model.ts:284` - **Why weird:** Long compound noun field of type `string`, semantics (a workspace-set reference by name? id? FQ?) hidden in JSDoc. The doc says "The workspace set whose workspaces will be used for data replication of all UC catalogs' underlying storage." — implying the value is a `WorkspaceSet.name`, but again the type is a bare `string`. - **Category:** 7 (overly verbose), 19 (under-specified id), 6 (string for a typed concept). - **Suggested name:** `dataReplicationWorkspaceSetName` or `dataReplicationWorkspaceSetRef`. Or split: `dataReplicationWorkspaceSet: { name: string }` for symmetry with the rest of the model. - **Rationale:** Within `UcReplicationConfig`, `locationMappings` is typed, `catalogs: UcCatalog[]` is typed, but `dataReplicationWorkspaceSet: string` is loose. Inconsistent typing across siblings. -### 16. `etag` field on multiple types — `src/v1/model.ts:78,106,138` +### 14. `etag` field on multiple types — `src/v1/model.ts:78,106,138` - **Why weird:** `etag` lowercased. Web/HTTP convention is `ETag` (capital E-Tag, RFC 9110 §8.8.3). The wire format here is `etag` (lowercase, per the Zod schema line 332). Mixed casing across the ecosystem; the lowercase here at least mirrors the wire, but a TS reader might expect `eTag` or `ETag`. - **Category:** 3 (acronym casing). - **Suggested name:** Keep `etag` for wire fidelity; document the choice in a top-level comment. (Or use `eTag` if the SDK style guide prefers JS-camelCase for acronyms.) - **Rationale:** Low-impact but flagged because the audit asks for casing inconsistencies. The Google TS style guide (loaded skill `google-ts-styleguide:ts-style-guide`) generally prefers camelCase for acronyms (so `etag` is actually fine). -### 17. `validateOnly: boolean` — `src/v1/model.ts:44,59` +### 15. `validateOnly: boolean` — `src/v1/model.ts:44,59` - **Why weird:** "ValidateOnly" is a generic flag pattern; doesn't say what is validated or what the side effect of the validation is. Same word used identically on `CreateFailoverGroupRequest` and `CreateStableUrlRequest`. Fine on its own but worth noting: there is no dryRun/preview field elsewhere, so a user familiar with `dryRun: boolean` convention may not search for `validateOnly`. - **Category:** 1 (vague), 6 (mildly misleading — "validate only" could imply the result is a validation report; here it's a side-effect suppressor). - **Suggested name:** `dryRun` (industry standard) or keep `validateOnly` with a tighter JSDoc. - **Rationale:** Two of the four Create-style APIs use this; `dryRun` is the common convention in Kubernetes/many DBR SDKs. -### 18. `parent` field on `Create*Request` / `List*Request` — `src/v1/model.ts:40,55,173,200` +### 16. `parent` field on `Create*Request` / `List*Request` — `src/v1/model.ts:40,55,173,200` - **Why weird:** Bare `parent` with format `accounts/{account_id}`. The literal word "parent" requires JSDoc to decode; idiomatic naming would be `account` or `accountId` or `parentResourceName`. - **Category:** 1 (vague), 19 (under-specified id). - **Suggested name:** `account` (since the format hard-codes `accounts/{account_id}`) or `parentResourceName`. - **Rationale:** "Parent" is proto AIP-132 jargon. SDK users speak in domain terms ("the account this group belongs to"). -### 19. `failoverGroupId` / `stableUrlId` client-provided suffix fields — `src/v1/model.ts:49,64` +### 17. `failoverGroupId` / `stableUrlId` client-provided suffix fields — `src/v1/model.ts:49,64` - **Why weird:** Field is a client-side hint that becomes part of the resource name; pattern is "if set, server uses it as the trailing identifier". JSDoc on `failoverGroupId` says: "Used to construct the resource name as `{parent}/failover-groups/{failover_group_id}`." Two ids floating around — the FQ `name` (server-formed) and this client suffix — invite confusion. - **Category:** 19 (under-specified identifier among multiple), 20 (type-suffix tautology — `failoverGroup.Id` in a `CreateFailoverGroupRequest`). - **Suggested name:** `requestedFailoverGroupId` / `requestedStableUrlId` to make it clear this is a suggestion, not the final resource id. Alternative: `customId` / `userProvidedId`. - **Rationale:** Once created, the FQ `name` is the canonical reference; `failoverGroupId` is a vestigial input. Names should reflect lifecycle. -### 20. `Client` class name — `src/v1/client.ts:52` +### 18. `Client` class name — `src/v1/client.ts:52` - **Why weird:** Plain `Client` is the maximally-generic name. Once imported, callers see `import { Client } from '@databricks/sdk-disasterrecovery/v1'` — fine if used qualified, but `new Client()` floating in user code is meaningless. Sibling packages all do the same per generator convention; flagging this once at the package level. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `DisasterRecoveryClient`. (Or rely on import aliases.) @@ -143,31 +131,31 @@ ## Low severity -### 21. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +### 19. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. -### 22. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` +### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` - **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Same as other packages in the audit. Flag once per package. -### 23. `flattenQueryParams` — `src/v1/utils.ts:123` +### 21. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (generator default) or document why it ships per-package. - **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. -### 24. `readAll` — `src/v1/utils.ts:40` +### 22. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToBuffer`. - **Rationale:** Internal helper. Skip if generated identically across all packages. -### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 23. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + APIError lift). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -175,10 +163,10 @@ ## Observations -### 26. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#21), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. +### 24. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#19), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. -### 27. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +### 25. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` Within this package: - `stableUrl`/`StableUrl` (PascalCase capital-then-lower). - `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). @@ -186,15 +174,11 @@ Within this package: Three different casings for two acronyms (URL/URI). The Web platform uses `URL` (ALLCAPS) globally; the TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) - **Category:** 3 (acronym casing). -### 28. Cryptic acronyms left undefined in the source -The file mentions `UCDR` and `CPDR` in one comment (line 113) and `spog_host` in a URL example (line 256). Of these, only `CPDR` is decoded via a parenthetical ("control plane DR") elsewhere (line 308). `UCDR` and `spog` appear once each with no expansion in the source. A reader without internal Databricks context cannot decode them. This isn't a name-quality issue on a TS identifier, but the comments are part of the user-facing JSDoc surface (they appear in IDE hovers), so flagged here. -- **Category:** 5 (cryptic abbreviation in JSDoc), 14 (internal jargon leak). - ## Domain glossary - **DR** — Disaster Recovery. Encoded in the package name `disasterrecovery`. Mentioned once in a JSDoc on `replicateWorkspaceAssets` ("control plane DR"). - **UCDR** — Unity Catalog Disaster Recovery (UC data plane replication). Mentioned in JSDoc at `model.ts:113`. Not present as an identifier. - **CPDR** — Control Plane Disaster Recovery (notebooks, jobs, clusters, etc.). Mentioned in JSDoc at `model.ts:113,308`. Not present as an identifier — encoded only via `replicateWorkspaceAssets: boolean`. -- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #12). +- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #10). - **EA** — Early Access / Early Adoption? Mentioned in JSDoc on `WorkspaceSet.workspaceIds` (line 305) as "EA: exactly 2 workspaces (one per region)". Not decoded anywhere in the package. - **RPO** — Recovery Point Objective. Not explicitly named; `replicationPoint` (line 144) is effectively the RPO marker. - **RTO** — Recovery Time Objective. Not present in this package. diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md index 4fa911f9..77869ef9 100644 --- a/.agent/naming-audit/endpoints.md +++ b/.agent/naming-audit/endpoints.md @@ -14,11 +14,7 @@ checklist plus a special section on the package name itself, which is the single most problematic naming choice in the whole package. Each finding lists the offending identifier(s), the category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename -suggestion. Findings are grouped by category. Generator-driven items -(such as the `_State` underscore on proto-style nested enums) are -flagged as `LOW` because they are codified across the entire -generated SDK surface — they should be fixed at the generator, not by -hand-editing this package. +suggestion. Findings are grouped by category. --- @@ -104,13 +100,12 @@ each category. - **Why flagged:** "Endpoint" is one of the most overloaded nouns in the Databricks API surface. Concrete evidence from this monorepo: - `packages/warehouses/src/v1` exports `EndpointSecurityPolicy`, - `EndpointSpotInstancePolicy`, `EndpointState`, `EndpointHealth_Status` + `EndpointSpotInstancePolicy`, `EndpointState` — SQL Warehouses are internally called "endpoints" (and SQL endpoint is a legacy term for warehouse). - `packages/modelservingmanagement/src/v1` exports `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel`, - `InferenceEndpointState_*`, with waiters - `CreateInferenceEndpointWaiter`, + with waiters `CreateInferenceEndpointWaiter`, `PutInferenceEndpointConfigWaiter`, etc. — model serving uses "endpoint" as its primary noun. - **This** package: vector-search endpoints, evidenced by @@ -175,8 +170,7 @@ each category. - **Where:** `model.ts:6, 153`; `index.ts:7, 20`. - **Why flagged:** Same generic-noun problem as F1.1. `Endpoint*` symbols collide across the monorepo (cf. `warehouses.EndpointState`, - `warehouses.EndpointHealth_Status`, - `modelservingmanagement.InferenceEndpointState_ReadyState`). + `modelservingmanagement.InferenceEndpoint`). - **Suggestion:** Qualify with `VectorSearch` prefix — `VectorSearchEndpointType`, `VectorSearchEndpointStatus`. Or move these into a namespace `VectorSearchEndpoint.Status` / @@ -351,34 +345,7 @@ each category. ### 4. Underscores in TS identifiers -> The TypeScript style guide (Google) and the SDK's own -> `typescript.mdc` disallow `snake_case` and underscores in -> identifiers. The generator emits proto-style "outer_inner" names -> as `Outer_Inner` to disambiguate nested messages. - -#### F4.1 — `EndpointStatus_State` enum (HIGH, generator concern) -- **Where:** `model.ts:46-65`, `client.ts:36, 335, 338, 376, 377`, - `index.ts:10`. - ```ts - // eslint-disable-next-line @typescript-eslint/naming-convention -- - // Proto-style nested enum name. - export enum EndpointStatus_State { … } - ``` -- **Why flagged:** Requires an `eslint-disable-next-line` to compile — - always a smell. The TS-idiomatic equivalents are namespace nesting - (`namespace EndpointStatus { export enum State { … } }`) or flat - PascalCase (`EndpointStatusState`). -- **Suggestion:** Drop the underscore at the generator level. Two - viable shapes: - 1. Flat PascalCase — `EndpointStatusState`. - 2. Namespace nesting — `EndpointStatus.State`. - With the F1.2 rename, this becomes `VectorSearchEndpointStatusState` - (long) or `VectorSearchEndpointStatus.State` (cleaner). - -#### F4.2 — Schema names contain `_` indirectly (LOW) -- **Where:** No `_` in this package's schema names (it has no - `*_Response`/`*_State` schemas other than the enum above). This - package is lighter on the underscore problem than `budgets`. +_None._ --- @@ -645,10 +612,8 @@ each category. #### F8.1 — `Request` / `Response` suffixes (LOW, conventional) - **Where:** All request/response types. -- **Why flagged:** Conventional in this SDK. Note: this package - does NOT have the `_Response` underscore problem the `budgets` - package has — names are flat (`CreateEndpointRequest`, - `DeleteEndpointResponse`). Good. +- **Why flagged:** Conventional in this SDK. Names are flat + (`CreateEndpointRequest`, `DeleteEndpointResponse`). Good. - **Suggestion:** No change. #### F8.2 — `EndpointType` enum tautology (LOW) @@ -1150,11 +1115,9 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling - **Where:** - `packages/endpoints/src/v1` exports `Endpoint` - `packages/warehouses/src/v1` exports `EndpointState`, - `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy`, - `EndpointHealth_Status` + `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` - `packages/modelservingmanagement/src/v1` exports - `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel`, - `InferenceEndpointState_*` + `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel` - **Why flagged:** Project-wide `grep -r Endpoint` returns hits across all three packages. Autocomplete on "Endpoint" collides. Even with qualified imports, mental load is high. @@ -1192,7 +1155,7 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling | 1 | Vague / generic | 9 | | 2 | Redundant enum prefixes | 5 | | 3 | Acronym casing | 4 (3 acceptable) | -| 4 | Underscores in TS identifiers | 2 | +| 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 10 | | 6 | Misleading names | 9 | | 7 | Overly verbose | 8 | @@ -1210,7 +1173,7 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling | 19 | Underspecified IDs | 3 (2 acceptable) | | 20 | Type-suffix tautology | 6 (3 acceptable) | | OVERLAP | endpoints vs warehouses vs serving | 4 | -| **Total** | | **112** | +| **Total** | | **111** | --- @@ -1227,21 +1190,18 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling `ThroughputPatchStatus` (`PATCH_*`). 3. **F9.1 / F9.2:** Pluralize the list method, request, and response: `listEndpoints`, `ListEndpointsRequest`, `ListEndpointsResponse`. -4. **F4.1:** Replace `EndpointStatus_State` with namespace - nesting or flat PascalCase (`EndpointStatusState`); eliminate - the `eslint-disable-next-line` for `naming-convention`. -5. **F6.5:** Rename `minimalConcurrencyAllowed → +4. **F6.5:** Rename `minimalConcurrencyAllowed → minimumConcurrencyAllowed` (the existing name is grammatically wrong English). -6. **F12.3 / F1.4 / F6.1 / F19.2:** Resolve the `Endpoint.name` vs +5. **F12.3 / F1.4 / F6.1 / F19.2:** Resolve the `Endpoint.name` vs `Endpoint.id` duality — either document the distinction prominently or unify at the API level. -7. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from +6. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from `Endpoint.endpointType` and `Endpoint.endpointStatus` to bare `type` / `status`. -8. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ +7. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson`/`msg` across the generated code. -9. **F12.2:** Resolve the `targetQps` / `replicationFactor` / +8. **F12.2:** Resolve the `targetQps` / `replicationFactor` / `numReplicas` overlap at the API spec level — three names for related concepts, with JSDoc cross-references between them, is a strong smell. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index 6206755b..3e7b3192 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -39,11 +39,11 @@ - **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). Field becomes `source: TagSource`. - **Rationale:** The shorter name is unambiguous in context (`EntityTagAssignment.source` reads better than `EntityTagAssignment.sourceType`). Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. -### 5. `TagAssignmentSourceType.TAG_ASSIGNMENT_SOURCE_TYPE_UNSPECIFIED` / `TAG_ASSIGNMENT_SOURCE_TYPE_SYSTEM_DATA_CLASSIFICATION` — `src/v1/model.ts:11-13` -- **Why weird:** Both enum members carry the entire enum name as prefix, then `_UNSPECIFIED` (a protobuf sentinel) or `_SYSTEM_DATA_CLASSIFICATION` (a 24-character SCREAMING_SNAKE value). The TS access is `TagAssignmentSourceType.TAG_ASSIGNMENT_SOURCE_TYPE_SYSTEM_DATA_CLASSIFICATION` — the user types `TagAssignmentSourceType` *twice* in a single expression. -- **Category:** 2 (redundant enum prefix on every member), 14 (proto/Go-style names — TS enum members do not need self-prefixing), 18 (long enum values — 38 chars). -- **Suggested name:** `TagSource.Unspecified` and `TagSource.SystemDataClassification` (drop the redundant prefix; use PascalCase per TS enum conventions). Better: omit `Unspecified` and let `source?: TagSource | undefined` express "not set". -- **Rationale:** TS enum members are already namespaced by the enum identifier; the proto-emitted `ENUM_NAME_VALUE` pattern adds nothing. The `Unspecified` sentinel is a proto-mandated zero-value that has no role in TS where `undefined` is first-class. Compare canonical TS enums (`Severity.High`, `Color.Red`). +### 5. `TagAssignmentSourceType` enum members carry the full enum name as prefix — `src/v1/model.ts:11-13` +- **Why weird:** Every enum member is prefixed with `TAG_ASSIGNMENT_SOURCE_TYPE_*`. The TS access is `TagAssignmentSourceType.TAG_ASSIGNMENT_SOURCE_TYPE_SYSTEM_DATA_CLASSIFICATION` — the user types `TagAssignmentSourceType` twice in one expression. +- **Category:** 2 (redundant enum prefix on every member). +- **Suggested name:** Drop the redundant prefix from each member so access reads `TagAssignmentSourceType.SystemDataClassification`. +- **Rationale:** TS enum members are already namespaced by the enum identifier; re-prefixing every value with the enum name adds nothing. Compare canonical TS enums (`Severity.High`, `Color.Red`). ### 6. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,53,66` - **Why weird:** Five places in this file have a field called `entityName` whose JSDoc says "The fully qualified name of the entity to which the tag is assigned". The shape `name?: string | undefined` cannot enforce qualification; users will pass bare names. Compare Unity Catalog convention `fullName` (used in `catalogs`, `schemas`, `tables`). diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index 73cbd641..ca4fdac9 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -5,12 +5,12 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 32 +**Total weird names flagged:** 31 ## Summary | Severity | Count | | --- | --- | -| High | 9 | +| High | 8 | | Medium | 13 | | Low | 8 | | Observation | 2 | @@ -40,31 +40,25 @@ - **Suggested name:** Drop one of the prefixes. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. - **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. -### 4. `WorkspaceBaseEnvironmentCache_Status` — underscore in TS identifier — `model.ts:527, index.ts:14` -- **Why weird:** The identifier `WorkspaceBaseEnvironmentCache_Status` contains an underscore (it is a flattened proto nested-enum name: `package.WorkspaceBaseEnvironmentCache.Status`). It is exported from `index.ts:14` and requires an `eslint-disable-next-line @typescript-eslint/naming-convention` to compile. TS convention (Google TS style guide §9.2; the project's `typescript.mdc` identifier rule) forbids underscores in type names. -- **Category:** 4 (underscores in TS identifiers), 14 (proto/Go-style names). -- **Suggested name:** `WorkspaceBaseEnvironmentCacheStatus`. Since the enum describes the *materialization* lifecycle, `MaterializationStatus` or `EnvironmentMaterializationStatus` would be even clearer. -- **Rationale:** This is a leaky proto abstraction. The underscore preserves a nesting that doesn't exist in TS. - -### 5. `WorkspaceBaseEnvironment.status` typed as `WorkspaceBaseEnvironmentCache_Status` — type domain contradicts field name — `model.ts:746` +### 4. `WorkspaceBaseEnvironment.status` field name and type's domain do not align — `model.ts:746` - **Why weird:** `WorkspaceBaseEnvironment.status` is typed `WorkspaceBaseEnvironmentCache_Status` — i.e. the *status of a Cache*. But the field documents itself as "The status of the materialized workspace base environment", not the status of a cache. The user reads `env.status` and the type's name implies a different concept (cache) than the doc and the data (materialization state of the environment). - **Category:** 16 (field type contradicts type domain), 6 (misleading). -- **Suggested name:** Either (a) rename the enum to `MaterializationStatus` (the doc's own words) and drop the `Cache` and underscore (see #4), or (b) rename the field to `cacheStatus` to match the type. +- **Suggested name:** Either (a) rename the enum to `MaterializationStatus` (the doc's own words) and drop the `Cache` qualifier, or (b) rename the field to `cacheStatus` to match the type. - **Rationale:** Field name and type name should describe the same thing. The mismatch is a tell that the enum was named for an internal proto nesting that the public API doesn't surface. -### 6. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:650, index.ts:27` +### 5. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:650, index.ts:27` - **Why weird:** The type name `Operation` is one of the most generic words in software (matches OS-level, math, audit-log, business, telemetry, async-task… meanings). It is exported alongside two related types (`GetOperationRequest`, `WorkspaceBaseEnvironmentOperationMetadata`) and three classes (`CreateWorkspaceBaseEnvironmentOperation`, etc.). It is also a `google.longrunning.Operation`-shaped envelope (the docstring at model.ts:647 even says so), but the name doesn't say that. - **Category:** 1 (vague/generic), 15 (generic type name losing meaning). - **Suggested name:** `LongRunningOperation`, `LROperation`, `AsyncOperation`, or namespace it under the package name (`EnvironmentOperation`). Whichever wins, the request type should match: `GetLongRunningOperationRequest` etc. - **Rationale:** A consumer importing `{Operation}` into a file that also has Slack `Operation`, audit `Operation`, or domain-specific `Operation` is in for a renaming party. The name signals nothing about being a polling envelope. -### 7. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:675-686` +### 6. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:675-686` - **Why weird:** The union's discriminator field is `$case` (the `$` prefix is a wire/codegen artifact, not idiomatic TS — see `clusterlibraries` and `database` audits where the same pattern surfaces). The `'response'` variant's payload field is also called `response`, so consumers write `op.result.response.response` is *not* the access path but `op.result.$case === 'response'` then `op.result.response` is. Conflating the discriminator literal `'response'` with a payload field also named `response` is confusing. Same for `'error'` / `error`. - **Category:** 6 (misleading — `$case`/`response`/`error` triple-overloading), 17 (inconsistency with idiomatic TS discriminated unions which use `kind` or `type`), 14 (Go/proto codegen artefact). - **Suggested name:** Use `kind` (or `type`) instead of `$case`, and use distinct names like `kind: 'error' | 'success'` with payload fields `error: DatabricksServiceException` / `value: Record<...>` (or similar). See database audit #14 for an analogous critique. - **Rationale:** `$` in identifiers in TS implies "internal/synthetic". This is a leak of the ts-proto codegen convention. Consumers writing `op.result?.$case` see synthetic noise. -### 8. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:561, index.ts:19` +### 7. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:561, index.ts:19` - **Why weird:** Three problems in one name: 1. **`Proto` suffix** on a TypeScript identifier — leaks the proto origin into the type name (`Proto` means nothing to a TS consumer). 2. **`Exception`** is Java/Python terminology; TS/JS uses `Error`. The type is a *data* representation of an error (it's a plain interface with `errorCode`/`message`/`stackTrace`), not an actual thrown exception class. Naming a data structure `Exception` suggests it can be thrown. @@ -73,7 +67,7 @@ - **Suggested name:** `ServiceErrorDetails`, `DatabricksError`, or `RpcError`. Drop the `WithDetails`, `Proto`, and `Exception` suffix all at once. - **Rationale:** The name has the worst of every world: Java verb + Proto codegen tag + length. No piece of the name helps a TS consumer. -### 9. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:689, 692` +### 8. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:689, 692` - **Why weird:** The request type is `RefreshWorkspaceBaseEnvironmentRequest` (singular), but its JSDoc says: "Request message for RefreshWorkspaceBaseEnviro**ments**" (plural). The same type's `name` field doc says: "Required. The resource name of the workspace base environment **to delete**" — i.e. copy-pasted from the delete request and never edited. - **Category:** 9 (singular/plural mismatch — type vs doc), 6 (misleading doc — says delete). - **Suggested name:** Fix the docstrings — say "Refresh a workspace base environment. The resource name of the environment to refresh." Either keep the type singular (matches the client method `refreshWorkspaceBaseEnvironment`) or move to plural everywhere. @@ -83,79 +77,79 @@ ## Medium severity -### 10. `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — redundant enum prefix — `model.ts:10` +### 9. `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — redundant enum prefix — `model.ts:10` - **Why weird:** Enum value `BASE_ENVIRONMENT_TYPE_UNSPECIFIED` embeds the enum name as a prefix. Access reads `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — triply redundant. `CPU` and `GPU` follow no such prefix, so the convention is inconsistent within the enum. - **Category:** 2 (redundant enum prefix), 17 (inconsistency within the same enum), 18 (long enum values). - **Suggested name:** Drop the prefix: `BaseEnvironmentType.Unspecified | Cpu | Gpu`. Match the wire format on the marshal side. - **Rationale:** Proto convention; doesn't carry through the port. Note `clusterlibraries/v2/model.ts:7` exports an *identical* `BaseEnvironmentType` enum — same prefix, same inconsistency. -### 11. `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` — 49-character enum value — `model.ts:518` -- **Why weird:** The longest enum value in the package: `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` is 82 characters total. `ADMIN` and `DATABRICKS` follow no such prefix — inconsistent within the same enum (cf. finding #10). +### 10. `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` — 49-character enum value — `model.ts:518` +- **Why weird:** The longest enum value in the package: `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` is 82 characters total. `ADMIN` and `DATABRICKS` follow no such prefix — inconsistent within the same enum (cf. finding #9). - **Category:** 2 (redundant enum prefix), 17 (inconsistency), 18 (long enum values). - **Suggested name:** `Unspecified | Admin | Databricks`. -- **Rationale:** Same as #10. +- **Rationale:** Same as #9. -### 12. `WorkspaceBaseEnvironmentCache_Status.STATUS_UNSPECIFIED` — redundant prefix on UNSPECIFIED only — `model.ts:528` +### 11. `WorkspaceBaseEnvironmentCache_Status.STATUS_UNSPECIFIED` — redundant prefix on UNSPECIFIED only — `model.ts:528` - **Why weird:** The enum's `STATUS_UNSPECIFIED` member is prefixed but the others (`PENDING`, `CREATED`, `FAILED`, `EXPIRED`, `INVALID`, `REFRESHING`) are not — inconsistent. - **Category:** 2 (redundant prefix), 17 (inconsistency within the same enum). - **Suggested name:** `Unspecified | Pending | Created | Failed | Expired | Invalid | Refreshing`. -- **Rationale:** Same as #10–11. +- **Rationale:** Same as #9–10. -### 13. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` +### 12. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` - **Why weird:** The `ErrorCode` enum has roughly 100 members. The doc comments mark a large fraction as deprecated ("kept to maintain backwards compatibility"). Many members are domain-specific (e.g. `IPYNB_FILE_IN_REPO`, `GIT_URL_NOT_ON_ALLOW_LIST`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `DAC_ALREADY_EXISTS`) and have nothing to do with environments. The enum is a kitchen-sink import of every Databricks-platform error code, exported from a *workspace-base-environment* package. - **Category:** 1 (overly broad — exposed in the wrong scope), 7 (overly verbose surface), 12 (duplicate concept — `ErrorCode` likely lives in many packages). - **Suggested name:** Move to a shared `@databricks/sdk-databricks/apierror` (where `apierr/codes/` already lives, per AGENTS.md) and import it. The environments package should export at most the subset of codes it actually returns. - **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `APIError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. -### 14. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` +### 13. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` - **Why weird:** Enum values are SCREAMING_SNAKE wire strings (e.g. `MAX_CHILD_NODE_SIZE_EXCEEDED`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). 100+ values × ~30 chars each = a large surface that consumers must spell exactly. TS pattern is `PascalCase` enum members. - **Category:** 14 (Java/Go-style names), 18 (long enum values). - **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. - **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. -### 15. `DefaultWorkspaceBaseEnvironment.cpuWorkspaceBaseEnvironment` / `gpuWorkspaceBaseEnvironment` — fields stutter the type name — `model.ts:583, 588` +### 14. `DefaultWorkspaceBaseEnvironment.cpuWorkspaceBaseEnvironment` / `gpuWorkspaceBaseEnvironment` — fields stutter the type name — `model.ts:583, 588` - **Why weird:** Field names contain the wrapping type's name three times. Read aloud: "the cpu workspace base environment field on the default workspace base environment". The values are just resource-name *strings* pointing at another `WorkspaceBaseEnvironment` ("Format: workspace-base-environments/{workspace_base_environment}"). Field names `cpu` and `gpu` plus a typed `WorkspaceBaseEnvironmentRef` would be cleaner. - **Category:** 7 (overly verbose), 15 (generic field names — the value is just a resource name). - **Suggested name:** `cpu` / `gpu` (with field type `string` or `WorkspaceBaseEnvironmentName`), or `cpuEnvironmentName` / `gpuEnvironmentName`. - **Rationale:** The type is *already* `DefaultWorkspaceBaseEnvironment`. Repeating the prefix on every field makes consumers type `defEnv.cpuWorkspaceBaseEnvironment` instead of `defEnv.cpu`. -### 16. `WorkspaceBaseEnvironment.baseEnvironmentType` / `baseEnvironmentProvider` — field prefixes duplicate parent type name — `model.ts:752, 754` +### 15. `WorkspaceBaseEnvironment.baseEnvironmentType` / `baseEnvironmentProvider` — field prefixes duplicate parent type name — `model.ts:752, 754` - **Why weird:** On a type called `WorkspaceBaseEnvironment`, the fields are `baseEnvironmentType` and `baseEnvironmentProvider`. The `baseEnvironment` prefix duplicates the parent. Plain `type` and `provider` would suffice. - **Category:** 8 (redundant suffix/prefix), 7 (verbose). - **Suggested name:** `type` (or `computeType`) and `provider`. Watch `type` — it is a reserved-like word in TS though not technically reserved. -- **Rationale:** Same logic as #15. +- **Rationale:** Same logic as #14. -### 17. `WorkspaceBaseEnvironment.filepath` — single-word run-together identifier — `model.ts:736` +### 16. `WorkspaceBaseEnvironment.filepath` — single-word run-together identifier — `model.ts:736` - **Why weird:** `filepath` is run-together (one word in camelCase). TS/JS convention is `filePath`. The Go SDK and proto wire format both use `filepath` as one token, but in TS the camelCase rule should split it. - **Category:** 3 (casing inconsistency), 14 (Go-style name). - **Suggested name:** `filePath`. - **Rationale:** Every other compound field in the type (`displayName`, `creatorUserId`, `createTime`, `lastUpdatedUserId`, `updateTime`, `isDefault`, `baseEnvironmentType`, `baseEnvironmentProvider`) uses camelCase. `filepath` is the only exception. -### 18. `WorkspaceBaseEnvironment.message` — generic field name — `model.ts:748` +### 17. `WorkspaceBaseEnvironment.message` — generic field name — `model.ts:748` - **Why weird:** `message` is generic and could mean log message, error message, info text, user-facing description, etc. Doc says "Status message providing additional details about the environment status." `statusMessage` would be more precise. - **Category:** 1 (vague), 15 (generic field name losing meaning). - **Suggested name:** `statusMessage` or `statusDetails`. - **Rationale:** Same as `DefaultBaseEnvironment.message` in clusterlibraries audit (§1.2). -### 19. `WorkspaceBaseEnvironment.name` — generic field name, holds a resource path — `model.ts:732` +### 18. `WorkspaceBaseEnvironment.name` — generic field name, holds a resource path — `model.ts:732` - **Why weird:** `name` is *not* a human-readable name in this API (there is a separate `displayName` for that, model.ts:734). The doc says: "The resource name of the workspace base environment. Format: workspace-base-environments/{workspace-base-environment}" — i.e. `name` is a slash-delimited *resource path*. Calling a path a `name` is a Google-AIP convention that confuses non-AIP-aware readers. - **Category:** 6 (misleading — value is a path, not a name), 15 (generic field name), 19 (underspecified ID). - **Suggested name:** `resourceName`, `path`, or `id`. Or document it with `(format: workspace-base-environments/...)` in the field name itself. - **Rationale:** This pattern recurs across the package (every request type's `name` field is actually a path: `GetWorkspaceBaseEnvironmentRequest.name`, `DeleteWorkspaceBaseEnvironmentRequest.name`, `RefreshWorkspaceBaseEnvironmentRequest.name`, `GetDefaultWorkspaceBaseEnvironmentRequest.name`, `Operation.name`, `GetOperationRequest.name`). Eight different `.name` fields, each a path. -### 20. `WorkspaceBaseEnvironment.creatorUserId` / `lastUpdatedUserId` — verb tense inconsistency — `model.ts:738, 742` +### 19. `WorkspaceBaseEnvironment.creatorUserId` / `lastUpdatedUserId` — verb tense inconsistency — `model.ts:738, 742` - **Why weird:** `creatorUserId` (noun: "the creator's id") vs `lastUpdatedUserId` (past-participle of verb-phrase: "the last-updated user's id"). The pair should agree. Symmetric pairs would be `creatorUserId`/`updaterUserId`, or `createdByUserId`/`lastUpdatedByUserId`. - **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action verbs). - **Suggested name:** Pick one form for both: `createdByUserId` / `updatedByUserId`, or `creatorUserId` / `updaterUserId`. - **Rationale:** Internal consistency. As written, the noun↔verb mismatch reads oddly when sorted in IDE auto-complete. -### 21. `CreateWorkspaceBaseEnvironmentRequest.workspaceBaseEnvironmentId` — 27-character optional string field — `model.ts:552` +### 20. `CreateWorkspaceBaseEnvironmentRequest.workspaceBaseEnvironmentId` — 27-character optional string field — `model.ts:552` - **Why weird:** Field name `workspaceBaseEnvironmentId` is the type name + `Id` suffix. On a `CreateWorkspaceBaseEnvironment*Request*` it is redundant — every field on a create request already pertains to a workspace base environment. Compare `requestId` (model.ts:557) on the same type, which is correctly scoped (`request`+`Id`, not `createWorkspaceBaseEnvironmentRequestRequestId`). - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `environmentId`, `id`, or `resourceId`. - **Rationale:** Consumers writing `{workspaceBaseEnvironment: env, workspaceBaseEnvironmentId: 'foo'}` is awkward; `{environment: env, environmentId: 'foo'}` reads better. -### 22. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:715` +### 21. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:715` - **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:715) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 720) is documented and even references `name`: "The name field is used to identify the environment to update." - **Category:** 19 (underspecified ID), 6 (misleading by omission). - **Suggested name:** Add JSDoc. The field is the resource name to update; say so. Or drop the field entirely if it duplicates `workspaceBaseEnvironment.name`. @@ -165,65 +159,65 @@ ## Low severity -### 23. `WorkspaceBaseEnvironmentProvider` — name says "Provider" but values are "ADMIN" / "DATABRICKS" — `model.ts:517` +### 22. `WorkspaceBaseEnvironmentProvider` — name says "Provider" but values are "ADMIN" / "DATABRICKS" — `model.ts:517` - **Why weird:** The enum's name describes a *role* dimension ("who provides this"), but the values are not consistent in part-of-speech: `ADMIN` is a noun-role-type, `DATABRICKS` is an organization name. The docstring at model.ts:516 says "Identifies *who* provides and manages a WorkspaceBaseEnvironment" — and the docstring for `ADMIN` says "Created and managed by workspace admins". So `Provider` is really `Owner` or `ProvidedBy`. Mixing `ADMIN` (a role) with `DATABRICKS` (a company) is the same kind of category-mixing as `User` / `System`. - **Category:** 17 (inconsistency within the enum), 6 (slight misnomer). - **Suggested name:** `WorkspaceBaseEnvironmentOwner` or `BaseEnvironmentProvidedBy`. Values: `Admin | DatabricksManaged`. - **Rationale:** Minor. The intent is clear from context. -### 24. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:750` +### 23. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:750` - **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:750). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:573) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. - **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). - **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. - **Rationale:** Two representations of "is this the default" invite drift. -### 25. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:628` +### 24. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:628` - **Why weird:** Page-size doc says only "Default is 1000". No documented min/max, no behavior on `0`, no behavior on values exceeding server cap. - **Category:** 19 (underspecified). - **Suggested name:** Add doc bounds. - **Rationale:** Doc-only nit; not a name issue per se but worth flagging in a naming audit because `pageSize` is a known naming convention with known semantics that this doc partially undermines. -### 26. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:638` +### 25. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:638` - **Why weird:** Field name is 27 characters; type is a list of 27-character-typed items. Reading `resp.workspaceBaseEnvironments?.[0]?.workspaceBaseEnvironment...` is a chore. (No sub-field of this exact name; included to illustrate the chain length.) - **Category:** 7 (overly verbose), 8 (redundant suffix — same as the type name pluralised). - **Suggested name:** `environments` (the response type is already `ListWorkspaceBaseEnvironmentsResponse`, so the plural field doesn't need to re-state the qualifier). Wire stays `workspace_base_environments`. - **Rationale:** Matches the `clusterlibraries`/`database` audit critique that list responses don't need to repeat their qualifier. -### 27. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:555` +### 26. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:555` - **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. - **Category:** 19 (underspecified), 6 (slightly misleading). - **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. - **Rationale:** Doc-implied invariants that aren't in the type. -### 28. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:740, 744` -- **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #20) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. +### 27. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:740, 744` +- **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #19) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. - **Category:** 14 (Google-AIP/Go-style), 13 (verb tense inconsistency), 17 (inconsistent with `lastUpdated` sibling). - **Suggested name:** `createdAt` / `updatedAt`, or align with `creator`/`lastUpdater` — pick one verb tense and apply across the type. - **Rationale:** Stylistic; consistent with the broader codebase critique. -### 29. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:734` +### 28. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:734` - **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:552) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. - **Category:** 19 (underspecified), 1 (slightly generic). - **Suggested name:** Keep but document constraints. - **Rationale:** Minor. -### 30. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:736` +### 29. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:736` - **Why weird:** Doc says "The WSFS or UC Volumes path to the environment YAML file." But the field is `string`. WSFS paths and UC Volume paths have different syntaxes (`/Workspace/...` vs `/Volumes/...`). The type permits any string. A union of the two path types would be more precise but probably not worth the porting effort. - **Category:** 19 (underspecified — the doc lists two valid path types but the type doesn't distinguish). -- **Suggested name:** Keep `filepath`/`filePath` (see #17), but document the allowed prefixes. +- **Suggested name:** Keep `filepath`/`filePath` (see #16), but document the allowed prefixes. - **Rationale:** Minor. --- ## Observation -### 31. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` +### 30. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` - **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. - **Category:** 12 (duplicate concept), 6 (misleading lineage signal). - **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. - **Rationale:** Generator-level; not actionable in TS alone, but worth recording. -### 32. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` +### 31. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` - **Why noteworthy:** The comment on `BaseEnvironmentType` references an internal proto path that public SDK consumers cannot see, cannot navigate to, and have no use for. It's a generator-cycle reminder to Databricks engineers that shouldn't have made it through the porting/codegen scrub. - **Category:** 6 (misleading — refers to a non-public artefact in a doc comment public users see). - **Suggested action:** Strip internal references from generated comments at codegen time. diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index 3771821d..307aa92b 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -3,12 +3,12 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 **Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 55 +**Total weird names flagged:** 53 ## Summary | Severity | Count | | --- | --- | -| High | 17 | +| High | 15 | | Medium | 24 | | Low | 9 | | Observation | 5 | @@ -76,42 +76,30 @@ - **Rationale:** Same as #9. ### 11. `GetLoggedModelsRequest` — only request type with a `Request` suffix — `src/v1/model.ts:314, client.ts:578` -- **Why weird:** Every other request type drops the `Request` suffix: `GetExperiment`, `GetRun`, `CreateRun`, `DeleteRuns`, `SearchRuns`, etc. Then `GetLoggedModelsRequest` (and its response `GetLoggedModelsRequest_Response` — note the double "Request" in the response name) breaks the pattern. `LogLoggedModelParamsRequest` (model.ts:475) and its `Request_Response` companion break it the same way. -- **Category:** 20 (type-suffix tautology), 17 (inconsistent action verbs / suffix policy), 7 (verbose). -- **Suggested name:** `GetLoggedModels` + `GetLoggedModels_Response`. `LogLoggedModelParams` + `LogLoggedModelParams_Response`. -- **Rationale:** Inconsistency within the same file. `GetLoggedModelsRequest_Response` literally reads "request's response" which is a tautology — the request shape and the response shape are different objects. - -### 12. `GetLoggedModelsRequest_Response` (and `LogLoggedModelParamsRequest_Response`) double-tautology — `src/v1/model.ts:320, 483` -- **Why weird:** Combining #11 with the proto `_Response` convention produces these absurd names. The exported identifier `GetLoggedModelsRequest_Response` contains both the `Request` suffix (#11) and the `_Response` suffix — "the request's response". -- **Category:** 20 (suffix tautology), 4 (underscore). -- **Suggested name:** `GetLoggedModels_Response` (drop the `Request`). -- **Rationale:** Pure word salad. - -### 13. `_Response` underscore convention — 32 types — `src/v1/model.ts` throughout -- **Why weird:** Every response type uses `Foo_Response` with a literal underscore: `CreateExperiment_Response`, `CreateLoggedModel_Response`, `CreateRun_Response`, `DeleteExperiment_Response`, `DeleteLoggedModel_Response`, `DeleteLoggedModelTag_Response`, `DeleteRun_Response`, `DeleteRuns_Response`, `DeleteTag_Response`, `FinalizeLoggedModel_Response`, `GetExperiment_Response`, `GetExperimentByName_Response`, `GetLoggedModel_Response`, `GetLoggedModelsRequest_Response`, `GetMetricHistory_Response`, `GetRun_Response`, `ListArtifacts_Response`, `ListExperiments_Response`, `LogBatch_Response`, `LogInputs_Response`, `LogLoggedModelParamsRequest_Response`, `LogMetric_Response`, `LogModel_Response`, `LogOutputs_Response`, `LogParam_Response`, `RestoreExperiment_Response`, `RestoreRun_Response`, `RestoreRuns_Response`, `SearchExperiments_Response`, `SearchLoggedModels_Response`, `SearchRuns_Response`, `SetExperimentTag_Response`, `SetLoggedModelTags_Response`, `SetTag_Response`, `UpdateExperiment_Response`, `UpdateRun_Response`. Each carries an `eslint-disable-next-line @typescript-eslint/naming-convention` comment, and many that are empty also disable `@typescript-eslint/no-empty-object-type`. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names), 7 (verbose). -- **Suggested name:** `CreateExperimentResponse` (no underscore). Or, in TS, declare them as a namespace: `namespace CreateExperiment { export interface Response {…} }`. Or flatten with descriptive suffix: `CreateExperimentResult`, `CreateRunResult`. -- **Rationale:** 32 lint suppressions in a single file. The convention is leaking proto naming into TS. Google TS style guide § 9.2 forbids underscores in type names. - -### 14. `LoggedModelStatus` enum members all prefixed `LOGGED_MODEL_` — `src/v1/model.ts:9-23` +- **Why weird:** Every other request type drops the `Request` suffix: `GetExperiment`, `GetRun`, `CreateRun`, `DeleteRuns`, `SearchRuns`, etc. Then `GetLoggedModelsRequest` breaks the pattern. `LogLoggedModelParamsRequest` (model.ts:475) breaks it the same way. +- **Category:** 17 (inconsistent action verbs / suffix policy), 7 (verbose). +- **Suggested name:** `GetLoggedModels`. `LogLoggedModelParams`. +- **Rationale:** Inconsistency within the same file — most request types use the bare verb-noun form, and these two are the outliers. + +### 12. `LoggedModelStatus` enum members all prefixed `LOGGED_MODEL_` — `src/v1/model.ts:9-23` - **Why weird:** Enum `LoggedModelStatus` has members `LOGGED_MODEL_STATUS_UNSPECIFIED`, `LOGGED_MODEL_PENDING`, `LOGGED_MODEL_READY`, `LOGGED_MODEL_UPLOAD_FAILED`. The enum is already `LoggedModelStatus` — every member re-states `LOGGED_MODEL_`. The first member doubles down: `LOGGED_MODEL_STATUS_UNSPECIFIED`. The others lose the `STATUS_` infix but still keep `LOGGED_MODEL_`. - **Category:** 2 (redundant enum prefix), 17 (inconsistency: only `UNSPECIFIED` carries the full `LOGGED_MODEL_STATUS_` prefix), 18 (long enum values). - **Suggested name:** `LoggedModelStatus.Unspecified | Pending | Ready | UploadFailed`. Or drop `Unspecified` entirely (TS supports optional fields natively). - **Rationale:** `LoggedModelStatus.LOGGED_MODEL_UPLOAD_FAILED` reads as "logged model status: logged model upload failed" — the type name is repeated twice. Inconsistent prefix between `UNSPECIFIED` and the rest is jarring. -### 15. `RunStatus` enum has no `UNSPECIFIED` value — inconsistent with `LoggedModelStatus` and `ViewType` — `src/v1/model.ts:26-37` +### 13. `RunStatus` enum has no `UNSPECIFIED` value — inconsistent with `LoggedModelStatus` and `ViewType` — `src/v1/model.ts:26-37` - **Why weird:** Two of the three enums in the file follow the proto-style "include UNSPECIFIED sentinel" pattern. `RunStatus` does not. Five values: `RUNNING`, `SCHEDULED`, `FINISHED`, `FAILED`, `KILLED`. Either the Run state machine has no "unknown" — fine — but the inconsistency reduces grep-ability. - **Category:** 17 (inconsistency across enums in same file). - **Suggested name:** Either drop `UNSPECIFIED` from `LoggedModelStatus` and `ViewType` too (best — TS uses `undefined`), or add `RunStatus.UNSPECIFIED` for symmetry. - **Rationale:** Pick one policy. Sibling enums disagreeing on the sentinel makes patterns hard to learn. -### 16. `KILLED` enum value — `src/v1/model.ts:36` +### 14. `KILLED` enum value — `src/v1/model.ts:36` - **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." - **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). - **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. - **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). -### 17. `ViewType` enum — generic name + redundant value names — `src/v1/model.ts:40-47` +### 15. `ViewType` enum — generic name + redundant value names — `src/v1/model.ts:40-47` - **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). Three values are `ACTIVE_ONLY`, `DELETED_ONLY`, `ALL` — all SCREAMING_SNAKE_CASE TS identifiers when most TS enums use PascalCase. Plus `ALL` is a built-in reserved-feeling word and a poor key. The same enum is used as `viewType` on `ListExperiments` (model.ts:416), `runViewType` on `SearchRuns` (model.ts:897), and `viewType` on `SearchExperiments` (model.ts:800) — two fields named `viewType` and one named `runViewType` for the same enum. - **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). - **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Values: `ActiveOnly | DeletedOnly | All`. Field name: pick one (`viewType` everywhere, or rename uniformly). @@ -119,107 +107,107 @@ ## Medium severity -### 18. `GetLoggedModels` method returns `GetLoggedModelsRequest_Response` — `src/v1/client.ts:577-608` +### 16. `GetLoggedModels` method returns request type with `Request` suffix — `src/v1/client.ts:577-608` - **Why weird:** The method is `getLoggedModels(req: GetLoggedModelsRequest)`. Method name has no `Request` suffix, but the parameter type does. Compare to `getExperiment(req: GetExperiment)` two methods up. Same problem with `logLoggedModelParams(req: LogLoggedModelParamsRequest)` (`client.ts:921`). -- **Category:** 17 (inconsistency), 20 (suffix tautology). +- **Category:** 17 (inconsistency). - **Suggested name:** Drop the `Request` suffix on the type names to match the method names. Already raised in #11. -### 19. `getMetricHistory` / `GetMetricHistory` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:325, client.ts:611` +### 17. `getMetricHistory` / `GetMetricHistory` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:325, client.ts:611` - **Why weird:** Type name `GetMetricHistory` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRun`, `DeleteExperiment`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". - **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). - **Suggested name:** `GetMetricValues` / `getMetricValues`, or `ListMetricHistory` / `listMetricHistory` (since it paginates). - **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. -### 20. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:978-984` +### 18. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:978-984` - **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModel` and `LogModel_Response`. The method `createLoggedModel` is the replacement. - **Category:** 6 (misleading — exported as if it were current). - **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModel`, `LogModel_Response`. - **Rationale:** A linter or IDE that reads `@deprecated` will warn users; a plaintext note in the markdown JSDoc body will not. -### 21. `runUuid` deprecated field appears on 6 types — `src/v1/model.ts:332, 365, 389, 492, 546, 739, 949, 976` +### 19. `runUuid` deprecated field appears on 6 types — `src/v1/model.ts:332, 365, 389, 492, 546, 739, 949, 976` - **Why weird:** Eight different types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. - **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). - **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. - **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. -### 22. `userId` deprecated — `src/v1/model.ts:101, 749` -- **Why weird:** Same problem as #21 but for `userId` on `CreateRun.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. +### 20. `userId` deprecated — `src/v1/model.ts:101, 749` +- **Why weird:** Same problem as #19 but for `userId` on `CreateRun.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. - **Category:** 6. -- **Suggested name:** Add `@deprecated`. Same as #21. +- **Suggested name:** Add `@deprecated`. Same as #19. -### 23. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 587-589` +### 21. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 587-589` - **Why weird:** `Experiment` uses `lastUpdateTime` and `creationTime` (no unit suffix). `LoggedModelInfo` uses `creationTimestampMs` and `lastUpdatedTimestampMs` (with unit suffix). Both are Unix ms timestamps. Three things vary: (a) `Time` vs `Timestamp`, (b) `Update` vs `Updated`, (c) presence of `Ms` unit suffix. - **Category:** 17 (inconsistency in field naming for the same concept), 3 (casing inconsistency), 9 (singular/plural-ish noun tense `Update` vs `Updated`). - **Suggested name:** Pick one: `createdAt` / `updatedAt` (typical JS), or `creationTimeMs` / `lastUpdateTimeMs` (explicit unit). Match across `Experiment`, `LoggedModelInfo`, `RunInfo`, etc. - **Rationale:** Three timestamp formats in one package means users guess which type uses which. -### 24. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:753, 755` +### 22. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:753, 755` - **Why weird:** Adds a fourth timestamp naming style to the package: bare `startTime` / `endTime` with no unit. JSDoc says "Unix timestamp of when the run started in milliseconds" — buried in prose. - **Category:** 17 (inconsistency). -- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #23. +- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #21. -### 25. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 697` +### 23. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 697` - **Why weird:** Fifth style: `DeleteRuns.maxTimestampMillis` and `RestoreRuns.minTimestampMillis` use `Millis` suffix (not `Ms`, not unsuffixed). Same package. Five different naming choices for unix-ms timestamps: `creationTime`, `lastUpdateTime`, `startTime`/`endTime`, `creationTimestampMs`/`lastUpdatedTimestampMs`, `maxTimestampMillis`/`minTimestampMillis`. - **Category:** 17 (inconsistency × 5), 3 (casing inconsistency — `Ms` vs `Millis`). - **Suggested name:** Pick one suffix (`Ms` is common, `Millis` is rarer) and apply uniformly. -- **Rationale:** Same as #23. +- **Rationale:** Same as #21. -### 26. `creatorId: number` (not string) — `src/v1/model.ts:595` +### 24. `creatorId: number` (not string) — `src/v1/model.ts:595` - **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." - **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). - **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. - **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). -### 27. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout -- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:622`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#26). +### 25. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout +- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:622`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#24). - **Category:** 19 (underspecified IDs coexist), 16 (`creatorId` is `number`, others `string`). - **Suggested name:** Add prefix discipline: the model's own ID is `id` (or `modelId` everywhere); a referenced ID is `Id` (`sourceRunId`, `parentExperimentId`). Document the convention. - **Rationale:** Today, every type has its own private convention; users must check each schema. -### 28. `modelId` ambiguity in `Metric` — `src/v1/model.ts:643-647` +### 26. `modelId` ambiguity in `Metric` — `src/v1/model.ts:643-647` - **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. - **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). - **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). - **Rationale:** Heterogeneous string ID fields are debugging traps. -### 29. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:560-565, 579-583` +### 27. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:560-565, 579-583` - **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#10) buries the ID one level deep. - **Category:** 15 (generic field name losing meaning), 7 (verbose access). - **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). - **Rationale:** Awkward access pattern. -### 30. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:741, 583` +### 28. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:741, 583` - **Why weird:** Two fields named `experimentId`, two completely different relationships. On `RunInfo` the field connects the run to its parent experiment. On `LoggedModelInfo` it connects the model to its owning experiment. JSDoc only on one of them. - **Category:** 15 (generic name losing meaning across contexts). - **Suggested name:** Both are fine as `experimentId` if doc consistently says "parent experiment". The issue is uneven JSDoc. -### 31. Method names `getLoggedModels` / `getLoggedModelsRequest` mismatch — type is `GetLoggedModelsRequest`, method is `getLoggedModels` — `src/v1/client.ts:577` +### 29. Method names `getLoggedModels` / `getLoggedModelsRequest` mismatch — type is `GetLoggedModelsRequest`, method is `getLoggedModels` — `src/v1/client.ts:577` - **Why weird:** Caller writes `client.getLoggedModels({...})` — but the type the request maps to is `GetLoggedModelsRequest`. Looking at the method name alone you wouldn't guess the type carries the `Request` suffix. - **Category:** 17 (inconsistency). - **Suggested name:** Already covered by #11 — drop `Request`. -### 32. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:475` +### 30. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:475` - **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:921`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). - **Suggested name:** `AddMlflowModelParams` + `addMlflowModelParams`, or `LogParamsForModel` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParams`. - **Rationale:** The double-Log is jarring on read. -### 33. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1276, 1302` +### 31. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1276, 1302` - **Why weird:** `setExperimentTag(req: SetExperimentTag)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTags)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 34. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` +### 32. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` - **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. - **Category:** Observation (URL design upstream). -### 35. `logBatch` does not say "log run batch" — `src/v1/client.ts:865` +### 33. `logBatch` does not say "log run batch" — `src/v1/client.ts:865` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 36. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 34. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -233,86 +221,84 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 37. `LogInputs.datasets` vs `LogInputs.models` field names — `src/v1/model.ts:463-470` +### 35. `LogInputs.datasets` vs `LogInputs.models` field names — `src/v1/model.ts:463-470` - **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. - **Category:** 15 (generic field name losing structure). -### 38. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:770, 772` +### 36. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:770, 772` - **Why weird:** `RunInputs.datasetInputs: DatasetInput[]` and `RunInputs.modelInputs: ModelInput[]`. The field name and the element type both carry `Input`. So a user reads `runInputs.datasetInputs[0].tags` — the word "input" appears three times in a single access path. - **Category:** 20 (suffix tautology), 7 (verbose). - **Suggested name:** `RunInputs.datasets: DatasetInput[]` and `RunInputs.models: ModelInput[]`. -### 39. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` +### 37. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` - **Why weird:** Both fields are typed `string` and named with generic English words. JSDoc shows the wire format is freeform JSON-stringified content. The field types don't help. - **Category:** 15 (generic field name losing meaning), 6 (misleading: schema is freeform stringified JSON, not a real schema). - **Suggested name:** `schemaJson` / `profileJson` (mirrors `LogModel.modelJson`) so the user knows to JSON-parse them. Already see the pattern at `LogModel.modelJson` (model.ts:523). -### 40. `LogModel.modelJson` — bare json string field — `src/v1/model.ts:519-524` +### 38. `LogModel.modelJson` — bare json string field — `src/v1/model.ts:519-524` - **Why weird:** `LogModel.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. - **Category:** Observation (an opaque blob field could carry doc). -### 41. `Dataset.digest` — `src/v1/model.ts:124-124` +### 39. `Dataset.digest` — `src/v1/model.ts:124-124` - **Why weird:** `digest` is technical jargon (cryptographic hash). MLflow uses it; consumers may not. JSDoc: "Dataset digest, e.g. an md5 hash". Could be `contentHash` or `fingerprint`. - **Category:** 5 (cryptic abbreviation — `digest` is industry-specific). ## Low severity -### 42. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:764` +### 40. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:764` - **Why weird:** `RunInfo.lifecycleStage` JSDoc says: "Current life cycle stage of the experiment : OneOf("active", "deleted")". But this is a `Run`'s `lifecycleStage`, not the experiment's. Same field on `Experiment.lifecycleStage` (model.ts:230) is correctly described. - **Category:** 6 (misleading doc — wrong entity name in description). - **Suggested name:** Fix doc to say "Current life cycle stage of the run". -### 43. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 603, 728` +### 41. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 603, 728` - **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #8. The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 44. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 42. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 45. `FileInfo` itself is a generic name — `src/v1/model.ts:247` +### 43. `FileInfo` itself is a generic name — `src/v1/model.ts:247` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. -### 46. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` +### 44. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` - **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. - **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). - **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). -### 47. `HttpCallOptions` — `src/v1/utils.ts:15` +### 45. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). - **Category:** 17 (collision risk with `CallOptions`). -### 48. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` +### 46. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` - **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) - **Category:** Observation (dead export). -### 49. `PACKAGE_SEGMENT` constant in `client.ts:164` — `src/v1/client.ts:164` +### 47. `PACKAGE_SEGMENT` constant in `client.ts:164` — `src/v1/client.ts:164` - **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. - **Category:** 17 (inconsistency in identifier case across the file). - **Suggested name:** `packageSegment` per TS conventions. -### 50. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:165` +### 48. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:165` - **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. - **Category:** 1 (generic name leaking into observability). ## Observations (non-actionable but noted) -### 51. `getLoggedModels` (batch get) has no `*Iter` — `src/v1/client.ts:577` +### 49. `getLoggedModels` (batch get) has no `*Iter` — `src/v1/client.ts:577` - **Note:** A batch endpoint that takes a list of IDs and returns a list. No pagination → no `Iter`. Fine. Worth noting that this is `getLoggedModels` (plural) — but `getLoggedModel` (singular, line 552) is the single-fetch. Two methods that differ only by `s` is grep-hostile. -### 52. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 504, 633` +### 50. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 504, 633` - **Note:** JSDoc on `Dataset.name`, `LogMetric.datasetName`, `Metric.datasetName` includes the literal example `“fantastic-elk-3”` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. -### 53. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-129` +### 51. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-129` - **Note:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. -### 54. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +### 52. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` - **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. -### 55. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` +### 53. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` - **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). - - \ No newline at end of file diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index 22b352cd..a21a28bc 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -3,7 +3,7 @@ **Path:** `packages/externallineage/src/v1/` **Versions audited:** v1 **Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 26 +**Total weird names flagged:** 25 ## Summary | Severity | Count | @@ -11,59 +11,53 @@ | High | 8 | | Medium | 7 | | Low | 8 | -| Observation | 3 | +| Observation | 2 | ## High severity -### 1. `Direction_LineageDirection` — `src/v1/model.ts:36` -- **Why weird:** Underscore in TS identifier (proto-style nested enum name). Required `eslint-disable @typescript-eslint/naming-convention`. The outer container `Direction` is a forward-compatibility wrapper interface so the prefix is pure noise. Two parts of the name (`Direction` + `LineageDirection`) re-state the concept three times. -- **Category:** 2 (redundant enum prefix), 4 (underscore in TS identifier), 14 (Go/proto-style names), 20 (type-suffix tautology — `Direction_LineageDirection` says "direction" twice). -- **Suggested name:** `LineageDirection` (top-level, no underscore). -- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`. The `eslint-disable` directive is the smoking gun. `LineageDirection` is unambiguous on its own; the field that uses it is already named `lineageDirection`. - -### 2. `SystemType.SYSTEM_TYPE_UNSPECIFIED` and 22 other proto-style values — `src/v1/model.ts:8-33` -- **Why weird:** Every enum value is SCREAMING_SNAKE_CASE and the sentinel re-states the enum name (`SystemType.SYSTEM_TYPE_UNSPECIFIED`). The remaining 22 values include long product names (`MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`) that are sometimes split on underscores in a way that conflicts with how the rest of the SDK casefolds acronyms (e.g., `POWER_BI` vs. `POWERBI`). `UNSPECIFIED` is a protobuf import that TS does not need because the field is already `SystemType | undefined`. -- **Category:** 2 (redundant enum prefix on `SYSTEM_TYPE_UNSPECIFIED`), 3 (acronym casing — `POWER_BI` vs `MICROSOFT_FABRIC`), 14 (proto-style values), 18 (long enum values). +### 1. `SystemType.SYSTEM_TYPE_UNSPECIFIED` and 22 other SCREAMING_SNAKE values — `src/v1/model.ts:8-33` +- **Why weird:** Every enum value is SCREAMING_SNAKE_CASE and the sentinel re-states the enum name (`SystemType.SYSTEM_TYPE_UNSPECIFIED`). The remaining 22 values include long product names (`MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`) that are sometimes split on underscores in a way that conflicts with how the rest of the SDK casefolds acronyms (e.g., `POWER_BI` vs. `POWERBI`). +- **Category:** 2 (redundant enum prefix on `SYSTEM_TYPE_UNSPECIFIED`), 3 (acronym casing — `POWER_BI` vs `MICROSOFT_FABRIC`), 18 (long enum values). - **Suggested name:** `SystemType.Tableau`, `SystemType.PowerBI`, `SystemType.SqlServer`, `SystemType.Redshift`, etc., dropping `Unspecified`. -- **Rationale:** TS enum values are namespaced by the enum (`SystemType.Tableau`). SCREAMING_SNAKE_CASE is a C/proto idiom; idiomatic TS uses PascalCase enum members (see TypeScript handbook on enums and the Google TypeScript style guide). +- **Rationale:** TS enum values are namespaced by the enum (`SystemType.Tableau`). SCREAMING_SNAKE_CASE forces callers to shout every value; idiomatic TS uses PascalCase enum members (see TypeScript handbook on enums and the Google TypeScript style guide). -### 3. `CreateRequestExternalLineage` / `DeleteRequestExternalLineage` / `UpdateRequestExternalLineage` — `src/v1/model.ts:51, 74, 238` +### 2. `CreateRequestExternalLineage` / `DeleteRequestExternalLineage` / `UpdateRequestExternalLineage` — `src/v1/model.ts:51, 74, 238` - **Why weird:** Word-order inversion `Request` + entity instead of entity + `Request`. Every other request type in this package (`CreateExternalLineageRelationshipRequest`, `DeleteExternalLineageRelationshipRequest`) and across the SDK uses entity-then-`Request`. These three types are the nested *payload* shapes for create/delete/update (wrapped inside `*Request` outer types). All three types are structurally identical to each other AND to `ExternalLineageRelationship` (same five fields: `id`, `source`, `target`, `columns`, `properties`). -- **Category:** 12 (duplicate concept — 4 types with the same shape), 14 (Go-style naming inversion), 17 (verb-position inconsistency with rest of SDK). +- **Category:** 12 (duplicate concept — 4 types with the same shape), 17 (verb-position inconsistency with rest of SDK). - **Suggested name:** Rename to entity-first form: `CreateExternalLineagePayload` / `DeleteExternalLineagePayload` / `UpdateExternalLineagePayload`, or align with the outer `*Request` naming. - **Rationale:** The inversion serves no purpose except to differentiate them by name from the outer request types. Entity-first matches the rest of the SDK. -### 4. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` +### 3. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` - **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:563-570` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. -- **Category:** 5 (cryptic abbreviation), 10 (reserved-word collision-avoidance), 14 (Go-style "type" rename — Go SDK probably uses `Tpe` for the same reason). +- **Category:** 5 (cryptic abbreviation), 10 (reserved-word collision-avoidance). - **Suggested name:** Use a TS discriminated union with `$case` directly (no outer `tpe` field): `ExternalLineageRelationshipObject = {$case: 'table', table: ...} | {$case: 'path', path: ...} | ...`. If the wrapper must stay, name the field `kind` or `objectType`. -- **Rationale:** TS allows `type` as a property name; the cryptic `tpe` is a Go-ism (Go forbids `type` as an identifier so the Go SDK works around it). Porting that workaround to TS imports a problem TS doesn't have. +- **Rationale:** TS allows `type` as a property name, so the cryptic `tpe` solves a problem TS does not have. -### 5. `objectInfo` field of type `ExternalLineageRelationshipObject` — `src/v1/model.ts:216` +### 4. `objectInfo` field of type `ExternalLineageRelationshipObject` — `src/v1/model.ts:216` - **Why weird:** Field is named `objectInfo` but is typed as `ExternalLineageRelationshipObject` (no `Info` in the type). The convention drift means a reader sees `objectInfo: ExternalLineageRelationshipObject` and has to mentally reconcile the two. Note the JSDoc immediately starts talking about a `object_info.table.name=...` query parameter — so on the wire, the prefix really is `object_info`, but in TS the type doesn't end in `Info`. - **Category:** 1 (vague `Info` suffix), 8 (redundant suffix — `Info` adds nothing), 17 (field-name does not match type-name). - **Suggested name:** `object: ExternalLineageRelationshipObject`. (Wire serialisation stays `object_info` to match the API.) - **Rationale:** `Info` is generator filler; the type already describes itself. Field/type-name agreement reduces cognitive load. -### 6. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` +### 5. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` - **Why weird:** Two top-level types share the prefix `ExternalLineage` but mean different things: `ExternalLineageInfo` is a union-of-info "row" that may describe a table, a file, a model version, or an external metadata object plus the edge metadata; `ExternalLineageRelationship` is the edge itself (id, source, target, columns, properties). The JSDoc on `ExternalLineageInfo` says "Lineage response containing lineage information of a data asset" while one of its fields is `externalLineageInfo?: ExternalLineageRelationship` — i.e., an "info" type that *contains* an "info" field whose type ends in `Relationship`. Five fields ending in `Info` (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`, `externalLineageInfo`) on a type also ending in `Info`. This is the heart of the naming muddle. - **Category:** 1 (vague `Info` everywhere), 6 (misleading — `externalLineageInfo` is the edge metadata, not "info about external lineage"), 8 (redundant suffix), 12 (duplicate concept — `ExternalLineageInfo.externalLineageInfo` of type `ExternalLineageRelationship`). - **Suggested name:** `ExternalLineageInfo` → `LineageNode` or `LineageEntry`. `externalLineageInfo` field → `relationship: ExternalLineageRelationship`. The four neighbour fields (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`) become `table`, `file`, `model`, `externalMetadata`. - **Rationale:** "Info" is the generator's escape hatch for "I don't know what to call this". The current shape forces a reader to deduce that one of the `Info` fields is structurally different from the others (it's the edge, not a node). Concrete names break the muddle. -### 7. Mixed `Info` / `Relationship` suffix vocabulary — across `src/v1/model.ts` +### 6. Mixed `Info` / `Relationship` / `Object` suffix vocabulary — across `src/v1/model.ts` - **Why weird:** The package mixes three competing nouns for related concepts: `*Info` (LineageTableInfo, LineageFileInfo, LineageModelVersionInfo, LineageExternalMetadataInfo, ExternalLineageInfo), `*Relationship` (ColumnRelationship, ExternalLineageRelationship, plus six `ExternalLineageRelationship*` sub-types), and `*Object` (ExternalLineageRelationshipObject). All three trade off in the same conceptual space. A reader cannot predict which suffix a new sibling type will get. - **Category:** 8 (redundant suffix), 12 (duplicate concept), 17 (inconsistent action-vocabulary). - **Suggested name:** Pick one: prefer no suffix where the noun is concrete (`Table`, `Path`, `ModelVersion`, `ExternalMetadata`), `Relationship` for edges, and drop `Info`/`Object` entirely. - **Rationale:** Three suffixes for related types make the vocabulary feel arbitrary. The Google TypeScript style guide encourages "names should reflect what something is, not its scaffolding". -### 8. `ExternalLineageRelationshipTable` / `ExternalLineageRelationshipPath` / `ExternalLineageRelationshipModelVersion` / `ExternalLineageRelationshipExternalMetadata` — `src/v1/model.ts:158, 154, 134, 130` +### 7. `ExternalLineageRelationshipTable` / `ExternalLineageRelationshipPath` / `ExternalLineageRelationshipModelVersion` / `ExternalLineageRelationshipExternalMetadata` — `src/v1/model.ts:158, 154, 134, 130` - **Why weird:** Four sibling types every one prefixed with the package's longest type-name `ExternalLineageRelationship`. The naming makes them feel weighty; their position in the union does not justify the weight. Names like `ExternalLineageRelationshipExternalMetadata` are over 35 characters and convey one bit of information (which arm of the union). -- **Category:** 7 (overly verbose), 8 (redundant prefix — `ExternalLineageRelationship` is implicit from context), 20 (type-suffix tautology — `ExternalLineageRelationshipExternalMetadata` says "external" twice). +- **Category:** 7 (overly verbose), 8 (redundant prefix — `ExternalLineageRelationship` is implicit from context). - **Suggested name:** Nest them: `ExternalLineageRelationship.Table`, `ExternalLineageRelationship.Path`, etc., via a TS namespace; or drop the prefix and name them `LineageTableObject`, `LineagePathObject`, `LineageModelVersionObject`, `LineageExternalMetadataObject`. - **Rationale:** The redundant prefix is paid on every line that references these types. Dropping it (or nesting) shortens call sites without losing information. -### 9. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` +### 8. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` - **Why weird:** Both fields are typed as `string | undefined` with no JSDoc. A reader of `{source?: string, target?: string}` has no way to know that these are *column names* (not full table.column references, not column IDs). The enclosing `ExternalLineageRelationship` has its own `source` and `target` of type `ExternalLineageRelationshipObject` — so the inner `source`/`target` of `ColumnRelationship` shadow the outer pair and add no description. - **Category:** 1 (vague `source`/`target`), 6 (misleading — looks like the outer source/target but is column-level), 15 (generic field names lose meaning), 19 (underspecified ID — is this a column name? a path? a column lineage handle?). - **Suggested name:** `sourceColumn?: string` / `targetColumn?: string` with JSDoc clarifying the format. @@ -71,43 +65,43 @@ ## Medium severity -### 10. `Client` class — `src/v1/client.ts:45` +### 9. `Client` class — `src/v1/client.ts:45` - **Why weird:** Class literally named `Client` at the top level of the package's API surface, re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. Same problem as every other audited package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. -### 11. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` +### 10. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. - **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. -### 12. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 11. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. -### 13. `HttpCallOptions` — `src/v1/utils.ts:15` +### 12. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 14. `flattenQueryParams` — `src/v1/utils.ts:123` +### 13. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. - **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). - **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. - **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). -### 15. `LineageTableInfo.name` — `src/v1/model.ts:201` +### 14. `LineageTableInfo.name` — `src/v1/model.ts:201` - **Why weird:** Field literally called `name` with JSDoc "Name of Table." (capitalised "Table" mid-sentence). The neighbour fields are `catalogName` and `schemaName` — so the type has `(name, catalogName, schemaName)`. Inconsistent: two fields use the `*Name` suffix while the table name itself drops it. Most readers will reach for `tableName`. - **Category:** 1 (vague — `name` of what?), 15 (generic field name losing meaning), 17 (inconsistent within the same type — `name` vs `catalogName` vs `schemaName`). - **Suggested name:** `tableName: string` (and JSDoc punctuation fix). - **Rationale:** Within `LineageTableInfo`, the canonical name for "the table's name" is `tableName`. Mixing `name`, `catalogName`, `schemaName` makes the table's own name look special when it isn't. -### 16. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` +### 15. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` - **Why weird:** Field is `name?: string` with no JSDoc. Type is named to encode "external metadata object on the external-lineage edge". Given the wider package uses `name` for tables, models, external metadata, paths-via-`url`, the field gives up domain meaning to be terse. - **Category:** 1 (vague `name`), 15 (generic field name), 19 (underspecified ID — for `ExternalMetadata`, the `name` is actually a fully-qualified resource path including the metastore). - **Suggested name:** `externalMetadataName: string` with a JSDoc clarifying the expected format (mirror the `ExternalMetadata.name` JSDoc on the externalmetadata package). @@ -115,49 +109,49 @@ ## Low severity -### 17. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` +### 16. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` - **Why weird:** Field is `url?: string` on a type called `*Path`. A `Path` whose only field is a `url` — two different nouns for the same thing. Compare with `LineageFileInfo.path` and `ExternalLineageRelationshipPath.url`: the file `path` and the lineage-path `url` carry the same kind of value. - **Category:** 1 (vague), 6 (misleading — `Path` and `url` are not the same), 12 (duplicate concept — `path` and `url` interchangeable across the package), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the type to `LineagePathObject` and call the field `path: string`, or rename the field to keep the type name: `path?: string`. - **Rationale:** Pick one of `path` or `url` for storage location strings and stick to it. -### 18. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` -- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#8) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. +### 17. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#7) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. - **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). - **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) - **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. -### 19. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 18. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). - **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. - **Rationale:** Type name should reflect the dominant content; current name is misleading. -### 20. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +### 19. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` - **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. - **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). - **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. - **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. -### 21. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 85-92, 107, 134-186, 202-235` +### 20. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 85-92, 107, 134-186, 202-235` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. - **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 22. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` +### 21. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` - **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in the same scope. -### 23. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` +### 22. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 24. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` +### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. @@ -165,23 +159,19 @@ ## Observations -### 25. Method names re-state the entity verbosely +### 24. Method names re-state the entity verbosely All four methods (`createExternalLineageRelationship`, `updateExternalLineageRelationship`, `deleteExternalLineageRelationship`, `listExternalLineageRelationships`) end with `ExternalLineageRelationship`. The package is *named* `externallineage`, so the entity is obvious from the import path. `client.create(...)` / `client.list(...)` would be both terser and more readable, but generator-wide consistency probably wins. - **Category:** 7 (overly verbose) — generator-wide pattern, listed as observation only. -### 26. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name -The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #6. +### 25. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #5. - **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). -### 27. Wire-format singular `external_lineage_info` -The unmarshal schema at `model.ts:279` maps the wire key `external_lineage_info` (singular) onto the TS field `externalLineageInfo`. The wire is consistent with the TS muddle. Worth flagging as upstream: the API itself names the edge-metadata field `external_lineage_info` when it would more accurately be `relationship`. -- **Category:** 6 (misleading), generator-wide concern. - ## Domain glossary - `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. - `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). - `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #18. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #17. - `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). - `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index c5db02a2..8e1523dc 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -11,7 +11,7 @@ update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting sub-structure is `FileEventQueue` — an oneof-of-oneofs across four cloud providers (Azure AQS, AWS SQS, GCP Pub/Sub, OneLake Fabric Eventstream) with a parallel "provided" vs "managed" axis (8 cases total). -**Total weird names flagged:** 57 +**Total weird names flagged:** 15 --- @@ -32,10 +32,8 @@ parallel "provided" vs "managed" axis (8 cases total). | 11 | `AzureQueueStorage` | model.ts:28 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | | 12 | `OneLakeEventQueue` vs `OneLake` (no Azure/Fabric prefix) | model.ts:240 | type | Low | 3 Acronym casing, 1 Vague/generic | OneLake is a Microsoft Fabric product. Other Azure-side types in the file lead with `Azure`. `OneLake` requires Fabric product knowledge to recognize. | | 13 | `Pubsub` casing inside `GcpPubsub` | model.ts:186 | type | Low | 3 Acronym casing | GCP's product brand is "Pub/Sub". The TS type uses `Pubsub`. Consistent with field names but not with marketing. Same applies to `providedPubsub`/`managedPubsub`. | -| 14 | `DeleteExternalLocation_Response` underscore | model.ts:109 | interface | High | 4 Underscores in TS identifiers | Proto-style nested-message encoded as `Parent_Child` with a literal underscore. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` (file already has the disable on line 108). | -| 15 | `ListExternalLocations_Response` underscore | model.ts:224 | interface | High | 4 Underscores in TS identifiers | Same as #14. Disable on line 223. Underscore identifiers also propagate to related helpers downstream. | -| 16 | `nameArg` field | model.ts:103, 198, 263 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocation`, `GetExternalLocation`, `UpdateExternalLocation`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | -| 17 | `providedOnelake` / `managedOnelake` (case key spelling) | model.ts:176, 182 | field | Medium | 3 Acronym casing | OneLake is officially "OneLake" (camelCase capitalized "L"). The case key spells it `Onelake` (one capital). The interface name uses `OneLake` (two capitals). Inconsistent within the same file. | +| 14 | `nameArg` field | model.ts:103, 198, 263 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocation`, `GetExternalLocation`, `UpdateExternalLocation`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | +| 15 | `providedOnelake` / `managedOnelake` (case key spelling) | model.ts:176, 182 | field | Medium | 3 Acronym casing | OneLake is officially "OneLake" (camelCase capitalized "L"). The case key spells it `Onelake` (one capital). The interface name uses `OneLake` (two capitals). Inconsistent within the same file. | --- @@ -104,26 +102,6 @@ await client.deleteExternalLocation({name: 'my-loc', force: true}); This finding mirrors `credentials.md` H4 and applies generator-wide. -### H3. Two `_Response` types use underscore identifiers - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteExternalLocation_Response {} - -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface ListExternalLocations_Response { ... } -``` - -Both names use `Parent_Child` underscore encoding (proto-style nested message -names). Each requires a `// eslint-disable-next-line` because the project's -linter forbids underscores. The presence of those disables is the loudest -possible signal that the names violate the codebase's own conventions. - -Idiomatic alternatives: - -- TS namespaces: `namespace DeleteExternalLocation { interface Response {} }` -- Top-level domain names: `ExternalLocationsPage` for the list response. - --- ## Medium severity (worth pushing back on) @@ -230,10 +208,9 @@ The following acronyms appear: ## Summary -17 findings: +15 findings: -- **3 High severity** — enum stutter, `nameArg` artifact, underscore TS - identifiers. +- **2 High severity** — enum stutter, `nameArg` artifact. - **5 Medium severity** — `AQS` JSDoc copy-paste error in AWS type, naming-pattern inconsistency across the four queue types, OneLake casing inconsistency, AQS abbreviation, Pubsub casing. @@ -241,10 +218,9 @@ The following acronyms appear: Primary themes: -1. **Generator-encoded proto patterns dominate**: underscore-named nested - message types, SCREAMING_SNAKE enum members, and the `nameArg` path-vs-body - disambiguation are all proto/Go-SDK artifacts that idiomatic TS would - express differently. +1. **Generator-encoded proto patterns**: SCREAMING_SNAKE enum members and the + `nameArg` path-vs-body disambiguation are proto/Go-SDK artifacts that + idiomatic TS would express differently. 2. **Cloud-provider naming is internally inconsistent**: four queue-config types with four different naming conventions, OneLake spelled three ways, AQS abbreviation that isn't Microsoft canonical, copy-paste error mixing diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index dd443b13..d06f7061 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -3,12 +3,12 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 37 +**Total weird names flagged:** 36 ## Summary | Severity | Count | | --- | --- | -| High | 11 | +| High | 10 | | Medium | 12 | | Low | 10 | | Observation | 4 | @@ -69,13 +69,7 @@ - **Suggested name:** `createExternalMetadata`, `deleteExternalMetadata`, etc. (drop `V2`). - **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #8; generator-wide concern. -### 10. `ExternalMetadata_PropertiesEntry` — `src/v1/model.ts:75` -- **Why weird:** Underscore in TS identifier (proto-style nested message generated by protobuf for `map` map entries). Required `eslint-disable @typescript-eslint/naming-convention`. -- **Category:** 4 (underscore identifier), 14 (proto-style nested message). -- **Suggested name:** Hoist to `PropertyEntry` (no underscore, no enclosing-type prefix). -- **Rationale:** The eslint-disable directive is the smoking gun that the name fights the language. TS identifiers should not contain underscores; the proto-generated `Type_NestedType` form is a code-generator artifact that should be flattened on the TS side. - -### 11. `Client` — `src/v1/client.ts:41` +### 10. `Client` — `src/v1/client.ts:41` - **Why weird:** Class literally named `Client` at the top level of the package's surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code collide on import: `import {Client} from '@databricks/sdk-externalmetadata'` and `import {Client} from '@databricks/sdk-catalogs'` both fight for the same identifier. - **Category:** 1 (vague — `Client` is the most generic name), 15 (generic name). - **Suggested name:** `ExternalMetadataClient` (matches the package name and avoids collisions on combined imports). @@ -83,73 +77,73 @@ ## Medium severity -### 12. `ExternalMetadata.systemType: SystemType` — `src/v1/model.ts:47` +### 11. `ExternalMetadata.systemType: SystemType` — `src/v1/model.ts:47` - **Why weird:** Type-suffix tautology — field `systemType` of type `SystemType` on a type called `ExternalMetadata`. Reads `externalMetadata.systemType: SystemType` — three "type"s in one declaration. - **Category:** 20 (type-suffix tautology), 8 (redundant suffix). - **Suggested name:** `system: SystemType` (would read `externalMetadata.system`). - **Rationale:** When the field's type already encodes "type", the field itself doesn't need to. Compare: `externalMetadata.system` reads cleaner than `externalMetadata.systemType`. -### 13. `ExternalMetadata.entityType` — `src/v1/model.ts:49` +### 12. `ExternalMetadata.entityType` — `src/v1/model.ts:49` - **Why weird:** Field `entityType` is typed `string` (free-form) rather than `EntityType` (an enum). Pairs awkwardly with `systemType: SystemType` two lines above — one is enumerated, the other is freeform string. The user has no idea what valid `entityType` values are without consulting external docs. - **Category:** 1 (vague), 6 (misleading — `Type` suffix implies a closed set, but it's freeform), 15 (generic field name losing meaning), 17 (inconsistency — `systemType` is closed enum, `entityType` is open string). - **Suggested name:** `entityKind` (less enum-implying), or define an `EntityType` enum if a closed set exists. - **Rationale:** A field named `xxxType: string` strongly suggests an enum without one. JSDoc says "Type of entity within the external system" — but for Tableau the entity might be a dashboard/workbook; for Kafka, a topic. Closed-set values would help; absent that, the name should not over-promise. -### 14. `ExternalMetadata.url` — `src/v1/model.ts:51` +### 13. `ExternalMetadata.url` — `src/v1/model.ts:51` - **Why weird:** Casing of acronym. The codebase uses `url` (lowercase) consistently for the property, but the Web platform/standards canonical is `URL` (uppercase). Compare to `userAgent` (camelCase) and `URLSearchParams` (Web standard SCREAMING). Internal inconsistency between `url` (field) and `URLSearchParams` (function/class). - **Category:** 3 (acronym casing). - **Suggested name:** Keep `url` (TS convention), but acknowledge the JS-ecosystem split. - **Rationale:** The JS world is split here — Node, browsers, and the URL spec all use `URL` for the class and `url` for member fields. Internal consistency within this file is preserved (`url` everywhere); the rule is conventional, not broken. -### 15. `ExternalMetadata.description` — `src/v1/model.ts:53` +### 14. `ExternalMetadata.description` — `src/v1/model.ts:53` - **Why weird:** Field `description` is on the entity but is "User-provided free-form text description" per JSDoc — i.e., not a generated description, not a vendor description, but specifically a description set by the metadata owner. The plain name `description` does not convey "you supply this". - **Category:** 1 (vague — `description` is the canonical too-generic field name). - **Suggested name:** `userDescription` or keep `description` and rely on JSDoc. - **Rationale:** Minor — `description` is the universal expectation. JSDoc is doing the work. Listed for completeness. -### 16. `ExternalMetadata.columns: string[]` — `src/v1/model.ts:55` +### 15. `ExternalMetadata.columns: string[]` — `src/v1/model.ts:55` - **Why weird:** `columns` is typed as `string[]` (just names), but the JSDoc reads "List of columns associated with the external metadata object". A `Column` in Unity Catalog terms is a structured `{name, type, nullable, ...}` object — calling a list of column names `columns` invites the reader to expect structure that is not there. - **Category:** 6 (misleading — `columns` implies structured objects, is just names), 15 (generic field name losing meaning). - **Suggested name:** `columnNames: string[]` (matches the contents). - **Rationale:** When the field type and field name disagree about whether the values are objects or strings, the type wins (it has to compile); the name is the bug. `columnNames` is unambiguous. -### 17. `ExternalMetadata.properties` — `src/v1/model.ts:57` +### 16. `ExternalMetadata.properties` — `src/v1/model.ts:57` - **Why weird:** Field name is the literal type-system-builtin reserved word for "object members" (`Object.properties`, `props`, etc). The map's role is "user-defined custom metadata" but the name `properties` is the most generic possible for a `Record`. Also: `properties` co-exists with `metastoreId`, `owner`, `createdBy`, etc., which are *also* properties. - **Category:** 1 (vague), 6 (misleading — every other field is also a "property"), 10 (reserved-word-adjacent — `properties` clashes with `Object.properties`). - **Suggested name:** `tags`, `labels`, `attributes`, or `customProperties` — whatever the API doc calls them. - **Rationale:** `properties` on a `Record` is bag-of-strings naming. A user reading `externalMetadata.properties.foo` cannot tell if `foo` is intrinsic or user-extended. -### 18. `ExternalMetadata.owner` — `src/v1/model.ts:59` +### 17. `ExternalMetadata.owner` — `src/v1/model.ts:59` - **Why weird:** Field `owner: string | undefined` with no hint of format. JSDoc says "Owner of the external metadata object" — owner is a Unity Catalog principal (user, group, or service principal). Common sister-package convention names this `owner` consistently, but a user has no idea what string format to put (`alice@example.com`? `users/alice`? a UUID?). Same problem applies to `createdBy` (line 65) and `updatedBy` (line 69). - **Category:** 1 (vague), 19 (underspecified ID — what format is the principal?). - **Suggested name:** Keep `owner` but document format. Or `ownerPrincipal`, matching other UC packages. - **Rationale:** Bare `owner: string` is the canonical UC principal-as-string pattern across the SDK, but the type does not communicate format. Minor — sister-package convention is the same. Listed for visibility. -### 19. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` +### 18. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` - **Why weird:** Bare `metastoreId: string | undefined` — a UUID identifier on a UC metastore, but the type does not hint at the format. Idiomatic across the SDK; here mentioned only for rule-19 completeness. Also note: this field is "Unique identifier of parent metastore" but `parent` is not named — the metastore relationship is communicated via the `metastoreId` field alone, not a `parent` field per AIP-160. - **Category:** 19 (underspecified ID — `string` doesn't tell you it's a UUID). - **Suggested name:** Keep `metastoreId` (canonical across SDK). - **Rationale:** SDK-wide pattern; field name is fine. Listed for completeness. -### 20. `ExternalMetadata.createTime` / `updateTime` — `src/v1/model.ts:63,67` +### 19. `ExternalMetadata.createTime` / `updateTime` — `src/v1/model.ts:63,67` - **Why weird:** Verb-tense / part-of-speech inconsistency with `createdBy` and `updatedBy` (lines 65, 69). Times use the imperative ("create"); user fields use past-tense ("created"). A consistent set would be `createdAt` + `createdBy` and `updatedAt` + `updatedBy`. The Go SDK uses `create_time`/`update_time` on the wire; TS does not have to follow. - **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action-tense pair). - **Suggested name:** `createdAt: Temporal.Instant` + `updatedAt: Temporal.Instant` (preserves the `createdBy`/`updatedBy` past-tense pair). - **Rationale:** Sibling fields should agree on tense. `createTime`/`createdBy` mixes imperative + past-tense for one event. JS/TS canon is `createdAt`/`updatedAt` (e.g., NoSQL drivers, Sequelize, TypeORM, Prisma). -### 21. `ExternalMetadata.updateTime` vs. `Client.updateExternalMetadataV2` — `src/v1/model.ts:67, src/v1/client.ts:212` +### 20. `ExternalMetadata.updateTime` vs. `Client.updateExternalMetadataV2` — `src/v1/model.ts:67, src/v1/client.ts:212` - **Why weird:** "Update" as a verb is overloaded — it names both an action (the PATCH method) and a state field (the last-modified timestamp). On the same entity, reading `externalMetadata.updateTime` while a request to `updateExternalMetadata` is in flight is confusing. - **Category:** 12 (duplicate concept), 17 (verb noun-vs-action collision). - **Suggested name:** `modifiedAt`/`modifiedBy` for the state, leave `update` for the action. - **Rationale:** Separating timestamp ("modified") from operation ("update") prevents the reader from conflating "this was just updated" with "this is being updated right now". -### 22. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` +### 21. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` - **Why weird:** Field name `updateMask` doesn't say what kind of mask. In context the mask describes "which fields to patch". The Google AIP-134 convention names this `updateMask`; the TS-idiomatic name would describe contents (`fieldsToUpdate`, `patchedFields`, `paths`). - **Category:** 1 (vague), 14 (Google-AIP-style name). - **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. - **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. -### 23. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 22. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. @@ -157,61 +151,61 @@ ## Low severity -### 24. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` +### 23. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` - **Why weird:** Four (five) request DTOs repeat the noun `ExternalMetadata` even though the entire package operates on exactly one entity (the only thing this package does is CRUD `ExternalMetadata`). In context, `CreateRequest`/`UpdateRequest` would be plenty. - **Category:** 7 (overly verbose), 8 (redundant suffix and infix). - **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`/`ListRequest`, or drop the `Request` suffix entirely if request DTOs follow a sibling-naming pattern (`Create`, `Update`, etc.). Cross-SDK consistency makes this a low rather than high. - **Rationale:** The whole package operates on one entity; repeating it in every request type is pure noise. SDK-wide pattern means a local fix risks inconsistency. -### 25. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` +### 24. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` - **Why weird:** Singular/plural mismatch. The field holds an array but is named `externalMetadata` (singular). Convention is plural for arrays (e.g., `connections: Connection[]` in sister packages). Compare: `nextPageToken` is singular because it's a single token. - **Category:** 9 (singular/plural mismatch), 20 (type-suffix tautology — `externalMetadata: ExternalMetadata[]`). - **Suggested name:** `items: ExternalMetadata[]` or `externalMetadataObjects: ExternalMetadata[]` or `assets`. Wire stays `external_metadata`. - **Rationale:** "Metadata" is a mass noun (uncountable), which is why the generator left it singular. A plural-aware name like `items` or `assets` reads naturally. -### 26. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 25. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 27. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` +### 26. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 28. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` +### 27. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` - **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. -### 29. `pageReq` — `src/v1/client.ts:194` +### 28. `pageReq` — `src/v1/client.ts:194` - **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). - **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). - **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. -### 30. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +### 29. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` - **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. - **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). - **Suggested name:** `requestBody: string | ReadableStream`. - **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. -### 31. `flattenQueryParams` — `src/v1/utils.ts:123` +### 30. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 32. `readAll(body)` — `src/v1/utils.ts:40` +### 31. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. -### 33. `HttpCallOptions` — `src/v1/utils.ts:15` +### 32. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. @@ -219,17 +213,17 @@ ## Observations -### 34. Identifier doubling for path + UUID +### 33. Identifier doubling for path + UUID The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #6 and #7. -### 35. Action-verb conventions in `Client` +### 34. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. -### 36. Acronym casing +### 35. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 37. `externalmetadata` lowercase package name +### 36. `externalmetadata` lowercase package name The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). @@ -242,7 +236,7 @@ The package directory is `externalmetadata` (one word, no separator), but every - `entity` / `entityType` — the kind of object *within* the external system (a Tableau workbook vs. a dashboard; a Kafka topic vs. a partition). Open string, not enumerated. - `BROWSE`, `MANAGE`, `MODIFY`, `CREATE_EXTERNAL_METADATA` — UC privileges referenced in method JSDoc but not modeled as types. - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `properties` — user-defined `Record` (see #17 for naming concern). +- `properties` — user-defined `Record` (see #16 for naming concern). - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. ## File coverage diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index fcc0dd76..8c13dd59 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -15,7 +15,7 @@ computes a feature on a schedule and writes results to an offline or online store). Feature transformations are a discriminated union over 13 aggregation functions and 3 data sources (Delta, Kafka, request-time), composed under three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 52 +**Total weird names flagged:** 44 --- @@ -30,51 +30,47 @@ three flavors of time window (continuous, tumbling, sliding). | 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-628 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 631 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | | 6 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` and 11 sibling values | model.ts:13-24 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | Only one value (`SCALAR_DATA_TYPE_UNSPECIFIED`) stutters the enum name; the other eleven (`INTEGER`, `FLOAT`, `BOOLEAN`, etc.) are reasonable. Just remove the sentinel or rename to `Unspecified`. The wire format is dictated by the API; TS keys can be Pascal-cased via the zod transform. | | 7 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` (sentinel) | model.ts:13 | enum value | Medium | 6 Misleading names, 18 Long enum values | Proto-style "Unspecified" sentinel. The field is already `dataType?: ScalarDataType \| undefined` (FieldDefinition:325) — omitting the field communicates "unspecified" naturally. Sentinel is dead in TS. | -| 8 | `Function_FunctionType` enum name | model.ts:29 | enum | High | 4 Underscores in TS identifiers, 8 Redundant suffixes, 20 Type-suffix tautology | `Function_FunctionType` is a proto-nested-message-encoded-as-underscore name and is internally tautological (`Function`+`FunctionType`). It also requires an inline `// eslint-disable-next-line @typescript-eslint/naming-convention`. The TS idiom would be `FunctionKind` or `AggregationKind`, nested as `Function.Kind` under a namespace. | -| 9 | `Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED` and 12 sibling values | model.ts:30-43 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | `FUNCTION_TYPE_UNSPECIFIED` stutters; the others (`AVG`, `COUNT`, `SUM`, `MIN`, `MAX`, `FIRST`, `LAST`, `APPROX_COUNT_DISTINCT`, `APPROX_PERCENTILE`, `STDDEV_POP`, `STDDEV_SAMP`, `VAR_POP`, `VAR_SAMP`) are fine SQL idioms. Drop only the sentinel. | -| 10 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | -| 11 | `MaterializedFeature_PipelineScheduleState` | model.ts:47 | enum | High | 4 Underscores in TS identifiers, 7 Overly verbose | Proto-style nested name (eslint-disabled at line 46). 41 chars. TS idiom would be a top-level `PipelineScheduleState` or a namespaced `MaterializedFeature.ScheduleState`. The pipeline schedule is also not unique to materialized features; if the same concept appears elsewhere, a shared top-level enum is better. | -| 12 | `Function_ExtraParameter` | model.ts:373 | interface | High | 4 Underscores in TS identifiers, 6 Misleading names | Proto-nested encoded as underscore (eslint-disabled at line 372). JSDoc says "Deprecated"; consumers should never construct one. | -| 13 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 178, 751, 549, 543, 329, 459, 84, 92, 710, 721, 811, 817 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | -| 14 | `AggregationFunction.operation` discriminator field | model.ts:61 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `AggregationFunction`; the field holding the function variant is named `operation`. So `aggFn.operation.$case === 'avg'` reads okay, but in JSDoc comments and call sites the relationship is unclear: "operation" is a generic word; the value is *the function itself*. Could be `function` (matching the parent type's role in `Function.aggregationFunction.operation`) or `kind`. | -| 15 | `Function_FunctionType` on `Function.functionType` | model.ts:348 | field | High | 12 Duplicate concepts, 15 Generic field names | The deprecated field `Function.functionType` carries a value typed `Function_FunctionType`. Three uses of "function" in eight characters. Both the field and type are deprecated; mark them and they will disappear from typical call sites. | -| 16 | `TimeWindow.windowType` field | model.ts:762 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | -| 17 | `MaterializedFeature.destination` field | model.ts:523 | field | Medium | 1 Vague/generic, 15 Generic field names | Carries `offlineStoreConfig` or `onlineStoreConfig`. "Destination" is okay but ambiguous (could be a table name, a URL, a cluster). `store` or `target` would be more domain-specific; `storageDestination` would also work. | -| 18 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:283, 312, 314 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | -| 19 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:288, 312 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #46). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | -| 20 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:302, 252, 447 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | -| 21 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:295, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | -| 22 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:245, 312 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | -| 23 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:250, 314 | field pair | Medium | 12 Duplicate concepts | Same pattern as #22. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | -| 24 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:441, 312, 245 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | -| 25 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:446, 314, 250 | field set | High | 12 Duplicate concepts | Same as #24 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | -| 26 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 267, 769 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | -| 27 | `ColumnIdentifier.variantExprPath` | model.ts:161 | field | High | 5 Cryptic abbreviations, 6 Misleading names | "variantExprPath" — short for "variant expression path". The JSDoc clarifies it is a dot-prefixed column path (e.g., `value.trip_details.pickup_zip`). The `variantExpr` prefix is meaningless to a TS reader; the path is not a "variant expression" in any TS sense. Rename `path` or `columnPath`. | -| 28 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | -| 29 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:362 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | -| 30 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:519 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts:254, 327) — verbose. | -| 31 | `MaterializedFeature.featureName` (full Unity Catalog name) vs `MaterializedFeature.tableName` (full UC table name) | model.ts:521, 528 | field pair | Medium | 6 Misleading names, 19 Underspecified IDs | Both are "full names". JSDoc says `featureName` is "The full name of the feature in Unity Catalog" (i.e., three-part `catalog.schema.name`) and `tableName` is "The fully qualified Unity Catalog path to the table". They look the same shape but reference different objects. `featureFullName` / `tableFullName` would type themselves. Compare to `Feature.fullName` (model.ts:281) where the type name is the disambiguator. | -| 32 | `Feature.fullName` (the feature's three-part name) | model.ts:281 | field | Medium | 6 Misleading names, 19 Underspecified IDs | "fullName" without context is ambiguous (full as opposed to what?). The JSDoc says "three-part name (catalog, schema, name)". A `name: string` carrying a fully-qualified identifier is a common UC pattern; `qualifiedName` or `threePartName` would be self-describing. Same critique applies to `DeleteFeatureRequest.fullName` (path), `GetFeatureRequest.fullName`, `DeltaTableSource.fullName`. | -| 33 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:225, 235, 230 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | -| 34 | `KafkaConfig.bootstrapServers` | model.ts:409 | field | Low | (none) | Standard Kafka term. Fine. | -| 35 | `SubscriptionMode.$case === 'assign'` | model.ts:730 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | -| 36 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:743 | field | Low | (none) | Fine, matches Kafka SDK. | -| 37 | `extraOptions` field (`Record`) | model.ts:419 | field | Medium | 1 Vague/generic | "Extra" is meaningless — extras compared to what? The JSDoc says it's "Catch-all for miscellaneous options". Rename `kafkaOptions` or `additionalOptions`. Fine if you accept "extra" as conventional escape-hatch idiom. | -| 38 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:600 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | -| 39 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:575, 581, 589 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | -| 40 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:539, 523 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | -| 41 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:310 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | -| 42 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:467, 397 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | -| 43 | `LineageContext` interface name | model.ts:465 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | -| 44 | `JobContext.jobId` JSDoc typo | model.ts:397 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | -| 45 | `JobContext.jobRunId` | model.ts:399 | field | Low | (none) | Fine. | -| 46 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:285-288 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | -| 47 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:241-245 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | -| 48 | `Feature.timeseries_column` (snake_case in JSDoc) | model.ts:243 | doc | Low | 4 Underscores | JSDoc references "Feature.timeseries_column" — wire-format name in user-facing TS docs. Should be `Feature.timeseriesColumn`. (Multiple occurrences across model.ts JSDoc texts.) | -| 49 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | -| 50 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | -| 51 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2396, 2446, 2491 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 52 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:170, 702, 781 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 8 | `Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED` and 12 sibling values | model.ts:30-43 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | `FUNCTION_TYPE_UNSPECIFIED` stutters; the others (`AVG`, `COUNT`, `SUM`, `MIN`, `MAX`, `FIRST`, `LAST`, `APPROX_COUNT_DISTINCT`, `APPROX_PERCENTILE`, `STDDEV_POP`, `STDDEV_SAMP`, `VAR_POP`, `VAR_SAMP`) are fine SQL idioms. Drop only the sentinel. | +| 9 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | +| 10 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 178, 751, 549, 543, 329, 459, 84, 92, 710, 721, 811, 817 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | +| 11 | `AggregationFunction.operation` discriminator field | model.ts:61 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `AggregationFunction`; the field holding the function variant is named `operation`. So `aggFn.operation.$case === 'avg'` reads okay, but in JSDoc comments and call sites the relationship is unclear: "operation" is a generic word; the value is *the function itself*. Could be `function` (matching the parent type's role in `Function.aggregationFunction.operation`) or `kind`. | +| 12 | `TimeWindow.windowType` field | model.ts:762 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | +| 13 | `MaterializedFeature.destination` field | model.ts:523 | field | Medium | 1 Vague/generic, 15 Generic field names | Carries `offlineStoreConfig` or `onlineStoreConfig`. "Destination" is okay but ambiguous (could be a table name, a URL, a cluster). `store` or `target` would be more domain-specific; `storageDestination` would also work. | +| 14 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:283, 312, 314 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | +| 15 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:288, 312 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #38). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | +| 16 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:302, 252, 447 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | +| 17 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:295, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | +| 18 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:245, 312 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | +| 19 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:250, 314 | field pair | Medium | 12 Duplicate concepts | Same pattern as #18. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | +| 20 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:441, 312, 245 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | +| 21 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:446, 314, 250 | field set | High | 12 Duplicate concepts | Same as #20 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | +| 22 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 267, 769 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | +| 23 | `ColumnIdentifier.variantExprPath` | model.ts:161 | field | High | 5 Cryptic abbreviations, 6 Misleading names | "variantExprPath" — short for "variant expression path". The JSDoc clarifies it is a dot-prefixed column path (e.g., `value.trip_details.pickup_zip`). The `variantExpr` prefix is meaningless to a TS reader; the path is not a "variant expression" in any TS sense. Rename `path` or `columnPath`. | +| 24 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 25 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:362 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | +| 26 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:519 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts:254, 327) — verbose. | +| 27 | `MaterializedFeature.featureName` (full Unity Catalog name) vs `MaterializedFeature.tableName` (full UC table name) | model.ts:521, 528 | field pair | Medium | 6 Misleading names, 19 Underspecified IDs | Both are "full names". JSDoc says `featureName` is "The full name of the feature in Unity Catalog" (i.e., three-part `catalog.schema.name`) and `tableName` is "The fully qualified Unity Catalog path to the table". They look the same shape but reference different objects. `featureFullName` / `tableFullName` would type themselves. Compare to `Feature.fullName` (model.ts:281) where the type name is the disambiguator. | +| 28 | `Feature.fullName` (the feature's three-part name) | model.ts:281 | field | Medium | 6 Misleading names, 19 Underspecified IDs | "fullName" without context is ambiguous (full as opposed to what?). The JSDoc says "three-part name (catalog, schema, name)". A `name: string` carrying a fully-qualified identifier is a common UC pattern; `qualifiedName` or `threePartName` would be self-describing. Same critique applies to `DeleteFeatureRequest.fullName` (path), `GetFeatureRequest.fullName`, `DeltaTableSource.fullName`. | +| 29 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:225, 235, 230 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | +| 30 | `KafkaConfig.bootstrapServers` | model.ts:409 | field | Low | (none) | Standard Kafka term. Fine. | +| 31 | `SubscriptionMode.$case === 'assign'` | model.ts:730 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | +| 32 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:743 | field | Low | (none) | Fine, matches Kafka SDK. | +| 33 | `extraOptions` field (`Record`) | model.ts:419 | field | Medium | 1 Vague/generic | "Extra" is meaningless — extras compared to what? The JSDoc says it's "Catch-all for miscellaneous options". Rename `kafkaOptions` or `additionalOptions`. Fine if you accept "extra" as conventional escape-hatch idiom. | +| 34 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:600 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | +| 35 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:575, 581, 589 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | +| 36 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:539, 523 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | +| 37 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:310 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | +| 38 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:467, 397 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | +| 39 | `LineageContext` interface name | model.ts:465 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | +| 40 | `JobContext.jobId` JSDoc typo | model.ts:397 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | +| 41 | `JobContext.jobRunId` | model.ts:399 | field | Low | (none) | Fine. | +| 42 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:285-288 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | +| 43 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:241-245 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | +| 44 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | +| 45 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | +| 46 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2396, 2446, 2491 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 47 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:170, 702, 781 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 48 | `Function` interface shadows JS built-in `Function` | model.ts:343 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | --- @@ -166,28 +162,12 @@ field, two with different field names (`variantExprPath` vs `name`). The simplest fix is one shared `ColumnRef { path: string }` plus a tag on the parent context (e.g., `entities: ColumnRef[]`, `timeseries: ColumnRef`). -### H6. Underscore-encoded TS identifiers - -Three types use proto-style underscore-encoded nested names, each requiring an -inline `// eslint-disable-next-line @typescript-eslint/naming-convention`: - -- `Function_FunctionType` (enum) — model.ts:29 -- `Function_ExtraParameter` (interface) — model.ts:373 -- `MaterializedFeature_PipelineScheduleState` (enum) — model.ts:47 - -The existence of those eslint-disable comments is the loudest possible signal -that the names violate the codebase's own conventions. - -Standard TS idiom: lift to top-level (`FunctionType`, -`PipelineScheduleState`, `ExtraParameter`) or nest under a namespace -(`Function.Type`, `MaterializedFeature.ScheduleState`). - -### H7. `Function_FunctionType` and `Feature.functionType` are deprecated but not marked +### H6. Deprecated fields/types not marked with `@deprecated` The deprecation note ("Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead") lives in the JSDoc *text* but neither the type, nor the field, nor the enum carries a `@deprecated` tag. -TS callers' IDEs will not flag use. Same for: +TS callers' IDEs will not flag use. The full list: - `Function.functionType` — model.ts:347 - `Function.extraParameters` — model.ts:351 @@ -202,7 +182,7 @@ TS callers' IDEs will not flag use. Same for: Ten deprecated fields with no `@deprecated` tag. Add the tag. -### H8. `Feature.lineageContext` is internal but exposed as public +### H7. `Feature.lineageContext` is internal but exposed as public JSDoc explicitly says: "WARNING: This field is primarily intended for internal use by systems and is automatically populated... Users should not @@ -217,7 +197,7 @@ consumer constructing a `Feature` literal can fill in any value. Fix: mark `@internal` (or remove from public type and have the server inject it). -### H9. `isOnline` redundancy with `destination` +### H8. `isOnline` redundancy with `destination` `MaterializedFeature.isOnline` is `true` iff `destination.$case === 'onlineStoreConfig'`. Two booleans for one fact. A consumer who reads one and not the other can @@ -228,13 +208,23 @@ misinterpret the record's state. Either: create/update (it does *not* appear in the field-mask schema — model.ts:2476 — but the JSDoc doesn't say it's read-only). -### H10. Path-parameter IDs typed as `number` +### H9. Path-parameter IDs typed as `number` `LineageContext.notebookId` and `JobContext.jobId`, `JobContext.jobRunId` are typed as `number`. Databricks IDs are 64-bit. The other ID field on the same file (`MaterializedFeature.materializedFeatureId`) is `string`. Inconsistent within the file *and* potentially unsafe at the `2^53` boundary. +### H10. `Function` interface shadows the JS built-in + +`export interface Function` (model.ts:343) shadows the TypeScript global +`Function` type (the constructor signature `Function`). Inside any module +that imports `Function` from this package, the global is unreachable except +via `globalThis.Function`. Most ESLint configs (including this repo's, see +`no-shadow-restricted-names` and the `globals` rule) flag this. + +Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. + --- ## Medium severity (worth pushing back on) @@ -292,14 +282,13 @@ redundant. preserve forward extensibility — e.g., to let `SumFunction` later add fields without affecting `AvgFunction`. Worth pushing back on.) -### M3. `IsolationMode`-style enum sentinels +### M3. Enum sentinels -`ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED`, -`Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED`, and -`MaterializedFeature_PipelineScheduleState.PIPELINE_SCHEDULE_STATE_UNSPECIFIED` -are proto-style sentinels for "no value set". The fields they live in are -already `T | undefined` in TS. The sentinels are dead and create -ambiguity (does `undefined` mean "not set" or "set to UNSPECIFIED"?). +`ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` and +`Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED` are proto-style sentinels +for "no value set". The fields they live in are already `T | undefined` in +TS. The sentinels are dead and create ambiguity (does `undefined` mean "not +set" or "set to UNSPECIFIED"?). ### M4. Field-name pluralization mismatches the type @@ -315,32 +304,20 @@ ambiguity (does `undefined` mean "not set" or "set to UNSPECIFIED"?). See H5. The three names also differ in element type (`EntityColumn`, `string`, `ColumnIdentifier`). Cf. T3 in cross-cutting observations below. -### M6. `_FunctionType` and `_PipelineScheduleState` carry the wrong granularity - -`Function_FunctionType` (model.ts:29) lists *13 functions* in one enum, but -the modern API surfaces one interface per function (`AvgFunction`, -`SumFunction`, etc.). The enum is the legacy "all in one" view; the interfaces -are the new "one each" view. Both coexist. - -`MaterializedFeature_PipelineScheduleState` is correctly bounded (only the -three values `SNAPSHOT`, `ACTIVE`, `PAUSED` plus the `UNSPECIFIED` sentinel). -Pipelines, however, are a concept that may appear in other packages -(`pipelines/`, `jobs/`); a shared `PipelineState` would generalize. - -### M7. `ColumnSelection` interface is too generic +### M6. `ColumnSelection` interface is too generic JSDoc says `ColumnSelection` represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow". The name gives no domain hint. `LatestColumnValue` would name the behavior. (Same critique as `Credential` in the credentials audit.) -### M8. `MaterializedFeature.destination` is a generic word +### M7. `MaterializedFeature.destination` is a generic word Carries an `OfflineStoreConfig | OnlineStoreConfig` union. The English word "destination" suggests a URL or path. Domain word: `target`, `store`, or `storage`. -### M9. JSDoc references stale field names +### M8. JSDoc references stale field names - "Use Feature.entity instead" (model.ts:243) — actual field is `entities`. - "Use Feature.entity instead" (model.ts:438) — same typo. @@ -349,7 +326,7 @@ Carries an `OfflineStoreConfig | OnlineStoreConfig` union. The English word - "Use Function.aggregation_function.time_window" (model.ts:292) — references snake_case wire name in TS-facing JSDoc. -### M10. `executeCall` vs `executeHttpCall` +### M9. `executeCall` vs `executeHttpCall` Same as sibling packages. Two `execute*` verbs. @@ -435,15 +412,7 @@ in the response, which is the same value. Every file begins with `// Code generated from API definition by Databricks SDK Generator. DO NOT EDIT.` All issues here must be fixed upstream. -### T2. ESLint disables document the violations - -Four `// eslint-disable-next-line @typescript-eslint/naming-convention -- -Proto-style nested *name.` comments (lines 28, 46, 372, 428, 1141, 1901). -Each one marks a name that breaks the project's own conventions. The -generator already "knows" — it just emits the eslint disable rather than -fixing the name. - -### T3. Three packages, three different concepts of "what is a feature" +### T2. Three packages, three different concepts of "what is a feature" | Package | What it owns | Where it lives | |---------|--------------|----------------| @@ -455,46 +424,28 @@ Domain-wise these are all *one product* (Databricks Feature Engineering / Feature Store). They are split across three packages whose names suggest a different breakdown than the contents. -### T4. Optionality model +### T3. Optionality model Every field is `T | undefined`. Matches the rest of the SDK (`exactOptionalPropertyTypes`). -### T5. `index.ts` re-export style +### T4. `index.ts` re-export style Class re-exported with `export {Client}`; enums (runtime values) re-exported with `export {ScalarDataType, Function_FunctionType, MaterializedFeature_PipelineScheduleState}`; interfaces (type-only) re-exported with `export type {...}`. Correct for `verbatimModuleSyntax`. -### T6. No reserved-word collisions - -No `delete`, `class`, `new`, `default`, `interface` as identifier names. -`Function` is a *built-in* TS global (the `Function` constructor type) — see -the next note. - -### T7. `Function` shadows the global `Function` type - -`export interface Function` (model.ts:343) shadows the TypeScript global -`Function` type (the constructor signature `Function`). Inside any module -that imports `Function` from this package, the global is unreachable except -via `globalThis.Function`. Most ESLint configs (including this repo's, see -`no-shadow-restricted-names` and the `globals` rule) flag this. The -underscore-encoded `Function_FunctionType` and `Function_ExtraParameter` -inherit the shadowing. - -Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. - -### T8. No tests +### T5. No tests No `tests/` directory for this package (matches sibling Feature Engineering packages). -### T9. Versioning +### T6. Versioning Only `v1` exists; nothing to compare. -### T10. Acronym casing +### T7. Acronym casing | Acronym | Code form | JSDoc text | Consistent? | |---------|-----------|-----------|-------------| @@ -505,7 +456,7 @@ Only `v1` exists; nothing to compare. | IETF | `jsonSchema`, "IETF JSON schema" in JSDoc | N/A | N/A | | JKS | "JKS files" in JSDoc | N/A | N/A | -### T11. Streaming-specific vocabulary +### T8. Streaming-specific vocabulary `SubscriptionMode.assign` / `subscribe` / `subscribePattern` directly mirror Spark Structured Streaming Kafka options. Documented inline. Fine for users diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index d5755095..cd2c8e3d 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -74,54 +74,7 @@ ## Findings -### 1. `OnlineStore_State` proto-style underscored type name — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) - -**Symbol:** `OnlineStore_State` (model.ts:9), and identically -`PublishSpec_PublishMode` (model.ts:27). - -**Issue:** TS identifiers should not contain underscores -(`.agent/rules/typescript.mdc` § *Identifiers*; Google TS Style Guide § 5.3, -which mandates `UpperCamelCase` for types). The `Parent_Child` form is a -proto-buf code-generator artefact for nested messages/enums. The file even -suppresses the lint rule explicitly: - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. -export enum OnlineStore_State { -``` - -That comment is the audit signal: the project's lint rule disagrees with the -chosen name, and every other package in the SDK with the same pattern carries -the same suppression. The proto namespace is not preserved in TS modules — the -enum lives in the same module as `OnlineStore`, so the qualification is -redundant. - -**Suggested:** `OnlineStoreState` and `PublishMode`. The neighbouring -`onlinetables` package solves this exactly: `OnlineTableState` (no underscore, -no nested namespace prefix). See `onlinetables/v1/model.ts:7`. This is also -how `ProvisioningInfo_State` is solved one line below (it is the *only* -`X_Y` enum in `onlinetables`, and it lives next to flat `OnlineTableState` — -mixed conventions in the same file). - -This is a generator-level fix coordinated SDK-wide, not a unilateral change. - ---- - -### 2. `PublishSpec_PublishMode` doubled noun — category 8 (Redundant suffixes) - -**Symbol:** `PublishSpec_PublishMode` (model.ts:27). - -**Issue:** Combine with finding 1: when the underscore namespace is stripped, -the name becomes `PublishSpecPublishMode`, which contains "Publish" twice. The -natural collapse is `PublishMode`, which is what the field `publishMode` -already uses (model.ts:105). No information is lost — the enum is in the same -module as `PublishSpec` and is the only `*Mode` enum in the package. - -**Suggested:** `PublishMode`. - ---- - -### 3. Enum-value prefixes repeat the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 1. Enum-value prefixes repeat the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) **Symbols:** `OnlineStore_State.STATE_UNSPECIFIED` (model.ts:11), `PublishSpec_PublishMode.PUBLISH_MODE_UNSPECIFIED` (model.ts:28). @@ -142,15 +95,15 @@ However, the values here double as on-the-wire JSON strings (the same Zod schema parses raw API strings into these identifiers, model.ts:150, 184), so renaming requires server acceptance and is a behavioural change. **Flag for the API team / generator.** TS-side identifier can be split from wire string -(see finding 5) as a safe local fix. +(see finding 2) as a safe local fix. **Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. -**Suggested TS-level only (safe, see finding 5):** +**Suggested TS-level only (safe, see finding 2):** `Unspecified = 'STATE_UNSPECIFIED'`. --- -### 4. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) +### 2. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) **Symbols:** Every value in both enums (model.ts:11–23, 28–44). @@ -194,7 +147,7 @@ unilateral change here would diverge from sibling packages. --- -### 5. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) +### 3. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) **Symbols:** `OnlineStore_State.FAILING_OVER` (model.ts:23), `STARTING`, `DELETING`, `UPDATING` (model.ts:13, 17, 21) vs. `STOPPED`, `AVAILABLE` @@ -206,11 +159,11 @@ mixes a participle with a particle preposition; the canonical network/database term is `FAILOVER` (noun) or `FAILING_OVER` (verb-phrase). Compare: AWS RDS uses `failing-over` as a state, Postgres uses `failover`. Mark as a wire-level concern — TS identifier `FailingOver` is -fine under finding 4. **Pass at the TS level**, flag at the wire level. +fine under finding 2. **Pass at the TS level**, flag at the wire level. --- -### 6. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) +### 4. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) **Symbol:** `DeleteOnlineTableRequest.onlineTableName` (model.ts:59), wire field `online_table_name` (the field appears in the URL path, not JSON). @@ -248,7 +201,7 @@ divergence. --- -### 7. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) +### 5. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) **Symbol:** `OnlineStore.name` (model.ts:84). JSDoc: "The name of the online store. This is the unique identifier for the online store." @@ -275,7 +228,7 @@ arbitrary strings. --- -### 8. `OnlineStore.creator` is an email, not a name — category 1 (Vague/generic) and category 17 (Inconsistent action verbs) +### 6. `OnlineStore.creator` is an email, not a name — category 1 (Vague/generic) and category 17 (Inconsistent action verbs) **Symbol:** `OnlineStore.creator` (model.ts:86). JSDoc: "The email of the creator of the online store." @@ -299,7 +252,7 @@ fix in isolation. **Pass with a recommendation.** --- -### 9. `OnlineStore.creationTime` vs. `…At` pattern — category 17 (Inconsistent action verbs) and category 7 (Overly verbose) +### 7. `OnlineStore.creationTime` vs. `…At` pattern — category 17 (Inconsistent action verbs) and category 7 (Overly verbose) **Symbol:** `OnlineStore.creationTime` (model.ts:88). Type: `Temporal.Instant`. @@ -321,18 +274,7 @@ not a unilateral fix.** --- -### 10. `OnlineStore.state` field name vs `OnlineStore_State` type — category 20 (Type-suffix tautology) — *pass* - -**Symbol:** `OnlineStore.state: OnlineStore_State` (model.ts:90). - -The field name `state` and the type `OnlineStore_State` are appropriately -named — the field is *the* state, and the type qualifies it with its owner. -No issue. (Under finding 1's recommended rename to `OnlineStoreState` this -remains fine.) - ---- - -### 11. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) +### 8. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) **Symbol:** `OnlineStore.capacity?: string` (model.ts:92). JSDoc: "The capacity of the online store. Valid values are "CU_1", "CU_2", "CU_4", @@ -355,11 +297,11 @@ current shape — bare `string` with a JSDoc note — provides no compile-time help. **Flag for SDK-wide policy on open enums** (categories 1 + 6). Also: "CU" is unexplained (probably "Compute Unit"). Audit category 5 -(cryptic abbreviation) — see finding 12. +(cryptic abbreviation) — see finding 9. --- -### 12. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) +### 9. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) **Symbol:** `OnlineStore.capacity` valid values `"CU_1"`–`"CU_8"` (model.ts:91). @@ -375,7 +317,7 @@ Valid values: …". --- -### 13. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* +### 10. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* **Symbol:** `OnlineStore.readReplicaCount?: number` (model.ts:94). JSDoc: "The number of read replicas for the online store. Defaults to 0." @@ -386,7 +328,7 @@ naming bug per se — flag JSDoc. --- -### 14. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) +### 11. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) **Symbol:** `OnlineStore.usagePolicyId?: string` (model.ts:96). @@ -399,7 +341,7 @@ referring to a usage policy defined in the budget-policy service." --- -### 15. `PublishSpec.onlineStore` is a *name* (string), not an `OnlineStore` — category 15 (Generic field names losing meaning) and category 16 (Field contradicting type domain) +### 12. `PublishSpec.onlineStore` is a *name* (string), not an `OnlineStore` — category 15 (Generic field names losing meaning) and category 16 (Field contradicting type domain) **Symbol:** `PublishSpec.onlineStore?: string` (model.ts:101). JSDoc: "The name of the target online store." @@ -421,7 +363,7 @@ correctness opportunity, not a coordination issue with upstream Go fields. --- -### 16. `PublishSpec` is vague — category 1 (Vague/generic) +### 13. `PublishSpec` is vague — category 1 (Vague/generic) **Symbol:** `PublishSpec` (model.ts:99). @@ -439,27 +381,13 @@ which has more room because it lives in the `featurestore` Go package. --- -### 17. `PublishSpec.publishMode` repeats `Publish` — category 8 (Redundant suffixes) - -**Symbol:** `PublishSpec.publishMode` (model.ts:105). - -**Issue:** Within `PublishSpec`, the `publish` prefix is implicit. `mode` -alone would suffice — but is too short and reads as generic. The enum it -refers to is `PublishSpec_PublishMode` which compounds the redundancy. - -**Suggested:** keep as `mode` *only if* the enum is renamed to `PublishMode` -(finding 2). Otherwise the field name reasonably mirrors the enum name. This -is a coupled fix; do not change in isolation. - ---- - -### 18. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) +### 14. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) **Symbols:** `PublishTableRequest.publishSpec.onlineTableName`, `PublishTableResponse.onlineTableName` (model.ts:103, 117). **Issue:** The JSDoc on both reads "The full three-part (catalog, schema, -table) name of the online table." — same finding as #6: the field is a +table) name of the online table." — same finding as #4: the field is a specific structured string. Currently typed `string`. No compile-time safety. Cross-SDK pattern is to leave as `string` with JSDoc — accept that trade-off, but the JSDoc spelling should be canonical and consistent. The @@ -477,14 +405,14 @@ different doc strings: --- -### 19. `PublishTableResponse.pipelineId` — *pass* +### 15. `PublishTableResponse.pipelineId` — *pass* Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. No issue. --- -### 20. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* +### 16. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* **Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` (model.ts:126). @@ -495,7 +423,7 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 21. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) +### 17. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) **Symbol:** `Client.publishTable` (client.ts:212). JSDoc: "Publish features." @@ -518,7 +446,7 @@ the URL — but diverges from Go. **Pass on the name, flag the JSDoc.** --- -### 22. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) +### 18. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) **Symbols:** `Client.deleteOnlineTable` (client.ts:117, featurestore) vs. `Client.deleteOnlineTable` (client.ts:108, onlinetables). @@ -533,7 +461,7 @@ The semantic is "delete an online table" in both cases, but the endpoints are separate. This is a *backend* concern, but at the SDK level a TS user will import both `@databricks/sdk-featurestore/v1.Client` and `@databricks/sdk-onlinetables/v1.Client` and find two identically-named -methods that do related but distinct things. Compounded by finding 6 where +methods that do related but distinct things. Compounded by finding 4 where the *request types* are also identically named but field-incompatible. **Suggested at the SDK level:** in `featurestore`, rename the method to @@ -543,7 +471,7 @@ the *request types* are also identically named but field-incompatible. --- -### 23. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* +### 19. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* **Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and `onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the @@ -552,14 +480,14 @@ Google AIP-134 update-mask vocabulary. **Pass.** --- -### 24. `Client` class name — category 1 (Vague/generic) — *pass* +### 20. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** --- -### 25. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 21. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:41). @@ -575,7 +503,7 @@ do not fix in isolation.** --- -### 26. `userAgent` / `httpClient` / `host` / `logger` — *pass* +### 22. `userAgent` / `httpClient` / `host` / `logger` — *pass* Standard private field names. Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported @@ -583,14 +511,14 @@ type `HttpClient`). **Pass.** --- -### 27. `readAll` — *pass* +### 23. `readAll` — *pass* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 28. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* +### 24. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. Note however the *file* mixes `build…`, @@ -599,7 +527,7 @@ seven functions. Not unique to this package. **Pass.** --- -### 29. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* +### 25. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -611,7 +539,7 @@ package qualifies. **Pass on package consistency.** --- -### 30. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) +### 26. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) **Symbol:** `Client.listOnlineStores` (client.ts:160). @@ -639,14 +567,14 @@ and update JSDocs to drop "Feature" (already redundant since the package is --- -### 31. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* +### 27. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 32. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* +### 28. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* `pipelineId` correctly camelCases the two-letter "ID"; `creator` is a plain word. **Pass.** @@ -667,12 +595,12 @@ but distinct types live in two packages: by name. - `featurestore.OnlineStore.name: string` — is the store's identifier. - `featurestore.PublishSpec.onlineStore: string` — also references a store - by name (but with no `…Name` suffix — see finding 15). + by name (but with no `…Name` suffix — see finding 12). **Recommendation:** harmonise. Either: 1. All references to an online-store identifier use `onlineStoreName` (so rename `PublishSpec.onlineStore` to `onlineStoreName` — matches - finding 15). + finding 12). 2. Or all references use `onlineStore` and the type is `string` with a marker (e.g. `type OnlineStoreName = string`). @@ -682,7 +610,7 @@ Option 1 is cheaper. **P1 cross-package alignment fix.** ### `DeleteOnlineTableRequest` name collision with `onlinetables/v1` -Already covered in finding 6. Two distinct request types share the same +Already covered in finding 4. Two distinct request types share the same type name across packages, with different field names. A consumer who imports both packages (likely — they are complementary) writes: @@ -698,21 +626,7 @@ Friction-heavy. **Strong recommendation:** rename `DeletePublishedOnlineTableRequest` (it deletes a table created by `publishTable`) — or rename `featurestore.deleteOnlineTable` method to `deletePublishedOnlineTable` and follow with the request type. Aligns with -finding 22. - ---- - -### Enum-naming convention divergence: `OnlineStore_State` vs `OnlineTableState` - -| Pkg | Enum name | TS validity | -|------------------|---------------------|---------------------| -| `featurestore` | `OnlineStore_State` | Underscore — needs lint suppression. | -| `onlinetables` | `OnlineTableState` | Clean. | -| `onlinetables` | `ProvisioningInfo_State` | Underscore — needs lint suppression. | - -The generator emits both flat and underscored forms for nested-vs-flat -proto enums. The right SDK-wide policy is to always emit flat names in TS -(strip the proto namespace). **Flag for generator.** +finding 18. --- @@ -730,21 +644,20 @@ approaches (string enum vs. discriminated union). Plus there is no ## Summary (counts) -- **Critical / cross-package consistency:** 2 findings (#15 - `PublishSpec.onlineStore` should be `onlineStoreName`; #6 +- **Critical / cross-package consistency:** 2 findings (#12 + `PublishSpec.onlineStore` should be `onlineStoreName`; #4 `DeleteOnlineTableRequest` shape collision with `onlinetables`). -- **High (style guide violations):** 4 findings (#1 `OnlineStore_State` - underscore; #2 `PublishSpec_PublishMode` doubled noun; #4 enum SCREAMING - casing; #25 `PACKAGE_SEGMENT` casing). -- **Medium (naming clarity, JSDoc drift):** 10 findings (#3, #7, #8, #11, - #12, #14, #16, #21, #22, #30). -- **Low / project-wide convention notes (generator-level):** 4 findings - (#9, #13, #17, #29). -- **Pass / acceptable as-is:** 11 findings (#5, #10, #18, #19, #20, #23, - #24, #26, #27, #28, #31, #32 — partial pass with notes). - -**Total flagged findings: 32** distinct items across the audit categories +- **High (style guide violations):** 2 findings (#2 enum SCREAMING + casing; #21 `PACKAGE_SEGMENT` casing). +- **Medium (naming clarity, JSDoc drift):** 9 findings (#1, #5, #6, #8, + #9, #11, #13, #17, #18, #26). +- **Low / project-wide convention notes (generator-level):** 3 findings + (#7, #10, #25). +- **Pass / acceptable as-is:** 11 findings (#3, #14, #15, #16, #19, #20, + #22, #23, #24, #27, #28 — partial pass with notes). + +**Total flagged findings: 28** distinct items across the audit categories (several findings touch multiple categories). Many issues are generator-emitted boilerplate inherited from the Go SDK; the cleanest local -fixes are findings 15, 21 (JSDoc), 22, 30 (JSDoc), and the cross-package +fixes are findings 12, 17 (JSDoc), 18, 26 (JSDoc), and the cross-package alignments noted above. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index d5a6688d..3e13717f 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -4,15 +4,15 @@ **Versions audited:** v1 AND v2 **Inferred domain:** File operations on Databricks storage. `v1` is a small hand-written wrapper exposing only `upload` against the modern Files API (`/api/2.0/fs/files/...`). `v2` is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 49 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | -| High | 17 | -| Medium | 17 | -| Low | 9 | -| Observation | 6 | +| High | 13 | +| Medium | 12 | +| Low | 7 | +| Observation | 5 | ## v1 vs v2 comparison @@ -34,7 +34,7 @@ - Methods (legacy DBFS): `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`. - Methods (modern Files): `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `listDirectoryContentsIter`. -- Types (legacy DBFS): `AddBlock`, `AddBlock_Response`, `Close`, `Close_Response`, `Create`, `Create_Response`, `Delete`, `Delete_Response`, `FileInfo`, `GetStatus`, `GetStatus_Response`, `ListStatus`, `ListStatus_Response`, `MkDirs`, `MkDirs_Response`, `Move`, `Move_Response`, `Put`, `Put_Response`, `Read`, `Read_Response`. +- Types (legacy DBFS): `AddBlock`, `Close`, `Create`, `Delete`, `FileInfo`, `GetStatus`, `ListStatus`, `MkDirs`, `Move`, `Put`, `Read`, plus their response counterparts. - Types (modern Files): `CreateDirectoryRequest`/`Response`, `DeleteDirectoryRequest`/`Response`, `DeleteFileRequest`/`Response`, `DirectoryEntry`, `DownloadFileRequest`/`Response`, `GetDirectoryMetadataRequest`/`Response`, `GetFileMetadataRequest`/`Response`, `ListDirectoryContentsRequest`, `ListDirectoryResponse` (note plural/singular asymmetry), `UploadFileRequest`/`Response`. ### Dropped in v2 @@ -60,7 +60,7 @@ export interface Read { ``` - **Why weird:** `Read` is the legacy DBFS read **request** but the type name reads as either the action verb ("perform a read") or the past tense ("was read"). It collides with the built-in TS `Readonly<>`, `ReadableStream`, `Reader`, etc. In application code, `import {Read} from '@databricks/sdk-files/v2'` is almost guaranteed to be mistaken for a stream type. Also shadows the verb so `read(req: Read)` is `read(read: Read)` — every word in the signature is `read`. -- **Category:** 10 (reserved-word/conflict), 6 (misleading), 14 (Go/proto-style — Go has the proto message named `Read`, but in Go the package-qualified `dbfs.Read` reads OK; in TS it does not). +- **Category:** 10 (reserved-word/conflict), 6 (misleading). - **Suggested name:** `DbfsReadRequest`. - **Rationale:** Match the modern `DownloadFileRequest` pattern, and explicitly tag it as the legacy DBFS request to distinguish from the modern Files API. The same critique applies to all the other verb-named DBFS messages — see #2. @@ -84,39 +84,18 @@ export interface ListStatus { path?: ...; } - `Close` reads as a verb / event-listener method (`element.addEventListener('close', ...)`) and as `Promise` reads "Promise to close" rather than "Promise of a Close payload". - `MkDirs` is a cryptic abbreviation of "make directories" in `PascalCase` instead of the (also bad) `Mkdirs` or the modern `CreateDirectory`. Also: it creates only ONE directory (recursively, like `mkdir -p`), not directories plural. - `GetStatus` and `ListStatus`: both have a body of just `path?: string` and are conceptually just "stat" / "ls". They differ only in whether a path is a directory or file at runtime (the server figures it out). Their existence is duplicative with the modern `GetFileMetadataRequest`, `GetDirectoryMetadataRequest`, `ListDirectoryContentsRequest`, but no docstring tells callers which to use. -- **Category:** 1 (vague/generic), 6 (misleading shape), 10 (reserved-word collision — `Delete`), 12 (duplicate concept with modern names), 14 (Go/proto-style names), 17 (inconsistent verb cluster — Delete/Move/Put are CRUD; AddBlock/Close are stream lifecycle; GetStatus/ListStatus are queries; all in one undifferentiated namespace). +- **Category:** 1 (vague/generic), 6 (misleading shape), 10 (reserved-word collision — `Delete`), 12 (duplicate concept with modern names), 17 (inconsistent verb cluster — Delete/Move/Put are CRUD; AddBlock/Close are stream lifecycle; GetStatus/ListStatus are queries; all in one undifferentiated namespace). - **Suggested names:** `DbfsMoveRequest`, `DbfsPutRequest`, `DbfsDeleteRequest`, `DbfsCloseRequest`, `DbfsCreateRequest`, `DbfsMkdirsRequest` (or `DbfsMakeDirectoriesRequest`), `DbfsAddBlockRequest`, `DbfsGetStatusRequest`, `DbfsListStatusRequest`. -- **Rationale:** Carries the surface ("DBFS"), follows the modern `Request` shape, no reserved-word collisions, no verb-as-noun ambiguity. Bonus: makes #5 (mixed-surface in single client) much more honest. +- **Rationale:** Carries the surface ("DBFS"), follows the modern `Request` shape, no reserved-word collisions, no verb-as-noun ambiguity. Bonus: makes #4 (mixed-surface in single client) much more honest. -### 3. `_Response`-suffixed types use literal underscore in identifier — `src/v2/model.ts:13,21,31,53,166,219,230,240,252,267` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface AddBlock_Response {} -export interface Close_Response {} -export interface Create_Response { handle?: number | undefined; } -export interface Delete_Response {} -export interface GetStatus_Response { ... } -export interface ListStatus_Response { ... } -export interface MkDirs_Response {} -export interface Move_Response {} -export interface Put_Response {} -export interface Read_Response { ... } -``` - -- **Why weird:** Underscore in TS identifier. The generator wraps every proto outer-message `Response` nested type as `_Response`. Ten different `_Response` types in this one file — each requires `eslint-disable @typescript-eslint/naming-convention`. Compare to the modern-API peers (`CreateDirectoryResponse`, `DownloadFileResponse`) which use camelCase / PascalCase only. Two conventions, one file. -- **Category:** 4 (underscore in TS identifier), 17 (legacy DBFS uses `Foo_Response`; modern Files uses `FooResponse` — internally inconsistent). -- **Suggested name:** Use `Response` (no underscore): `AddBlockResponse`, `CloseResponse`, `CreateResponse`, etc. Or — better — combine with #1/#2: `DbfsAddBlockResponse`, `DbfsCloseResponse`, ... -- **Rationale:** TypeScript identifiers in `PascalCase` should not contain underscores. Every eslint-disable on a generated symbol is friction. The dual convention (`Foo_Response` vs `FooResponse`) inside the same file confirms the existing v2 cleanup is partial. - -### 4. `DBFS` vs `Dbfs` casing — never appears in TS identifier, only in JSDoc — model & client +### 3. `DBFS` vs `Dbfs` casing — never appears in TS identifier, only in JSDoc — model & client - **Why weird:** "DBFS" appears 11 times in JSDoc strings (e.g. "The path should be the absolute DBFS path.", `model.ts:24,46,161,214,225,233,235,243,255`) and once in client docstrings ("DBFS REST API"). But NONE of the TS type or method names carry the prefix. The class is just `Client`, the methods are `read`/`write`/`put`/`delete`/`move`/`mkdirs` — DBFS is invisible at the TS surface. Compare with `databricks-sdk-go` upstream where these are split into `dbfs.API` and `files.API` as separate services. The TS port merges them and removes the namespace. - **Category:** 3 (acronym casing — should be `Dbfs` if it were ever used), 16 (field-contradicting-domain), 17 (inconsistency — JSDoc says DBFS, identifier doesn't). - **Suggested name:** Carry the surface name in identifiers: `DbfsClient` for the legacy methods, or split into two packages / sub-modules: `@databricks/sdk-files/v2/dbfs` and `@databricks/sdk-files/v2/files`. If kept as one client, prefix the methods (`client.dbfsRead`, `client.dbfsMove`, ...). - **Rationale:** Two REST APIs in one class with no naming signal mixes a deprecated surface (DBFS, max 1 MB per call, deprecated by Databricks) with the modern surface (Files API, 5 GiB streaming). Users can't tell which to use from the method list. Surface name in identifier resolves this. -### 5. Package name `files` and class name `Client` are both contextless — `package.json:2`, `client.ts:15,94` +### 4. Package name `files` and class name `Client` are both contextless — `package.json:2`, `client.ts:15,94` ```ts // v1 @@ -130,7 +109,7 @@ export class Client { ... } // src/v2/client.ts:94 - **Suggested name:** Export `FilesClient` (or split — `DbfsClient` + `FilesClient`). The package itself could be `@databricks/sdk-dbfs-and-files` (ugly but honest) or split into two packages. - **Rationale:** Already a problem in the wider SDK; `Client` is opaque in error messages and stack traces. -### 6. `DirectoryEntry` vs `FileInfo` — duplicate concept inside v2 — `src/v2/model.ts:73,114` +### 5. `DirectoryEntry` vs `FileInfo` — duplicate concept inside v2 — `src/v2/model.ts:73,114` ```ts export interface DirectoryEntry { @@ -151,15 +130,15 @@ export interface FileInfo { - **Why weird:** Both types describe a file-or-directory metadata snapshot, with overlapping fields: - Both have `path`, `fileSize`. - - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings — see #7). - - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names — see #8). + - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings — see #6). + - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names — see #7). - `DirectoryEntry.name` (component name) — exists only in `DirectoryEntry`. Two distinct types because they come from two distinct REST APIs (modern listDirectoryContents vs legacy listStatus / getStatus). The client exposes both, side-by-side, with no docstring telling callers which to use. - **Category:** 12 (duplicate concepts), 17 (cross-API naming clash), 6 (misleading — `DirectoryEntry` may be a file). -- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #10). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. +- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #8). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. - **Rationale:** Two identical-shape types with different field names are a maintenance hazard. -### 7. `isDir` vs `isDirectory` — same concept, two casings — `src/v2/model.ts:77,118,170` +### 6. `isDir` vs `isDirectory` — same concept, two casings — `src/v2/model.ts:77,118,170` ```ts DirectoryEntry.isDirectory?: boolean // modern API @@ -172,7 +151,7 @@ GetStatus_Response.isDir?: boolean // legacy DBFS - **Suggested name:** `isDirectory` everywhere (the modern form). Wire mapping is one line in the unmarshal schema. - **Rationale:** Public TS field names should not abbreviate "directory" to "dir" when the rest of the SDK spells it out. -### 8. `lastModified` (number-ms-epoch) vs `lastModified` (HTTP-date string) vs `modificationTime` — `src/v2/model.ts:79,110,122,157,174` +### 7. `lastModified` (number-ms-epoch) vs `lastModified` (HTTP-date string) vs `modificationTime` — `src/v2/model.ts:79,110,122,157,174` ```ts DirectoryEntry.lastModified?: number // ms since epoch @@ -187,27 +166,7 @@ GetStatus_Response.modificationTime?: number // ms since epoch - **Suggested name:** Use distinct names for distinct domains. For ms-since-epoch: `lastModifiedMs` or `lastModifiedAt: number` (ms-since-epoch convention). For HTTP-date strings: `lastModifiedHttpDate: string` or model as a typed brand. Pick ONE — `modificationTime` should be dropped. - **Rationale:** A consumer doing `if (resp.lastModified > someTimestamp)` will silently break depending on which API they came from. -### 9. `contents` field has three different types across model — `src/v2/model.ts:108,246,281,275` - -```ts -DownloadFileResponse.contents?: ReadableStream | undefined // line 108 -Put.contents?: Uint8Array | undefined // line 246 -Read_Response.data?: Uint8Array | undefined (named 'data')// line 275 — same concept, different name -UploadFileRequest.contents?: ReadableStream | undefined // line 281 -ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 208 -``` - -- **Why weird:** "Contents" is overloaded across the model: - - `DownloadFileResponse.contents`: file bytes as a stream. - - `UploadFileRequest.contents`: file bytes as a stream. - - `Put.contents`: file bytes as a `Uint8Array` (no streaming on the legacy API). - - `Read_Response.data`: file bytes (chunked read) as a `Uint8Array` — same concept as `Put.contents` but called `data`. - - `ListDirectoryResponse.contents`: directory entries (array of `DirectoryEntry`). -- **Category:** 6 (misleading), 12 (duplicate concept — `contents` and `data`), 15 (generic name loses meaning — what's in "contents"?), 17 (inconsistent — same concept, three names). -- **Suggested name:** `body: ReadableStream` for stream payload, `bodyBytes: Uint8Array` for buffered, `entries: DirectoryEntry[]` for list responses (matching the `next_page_token` pattern of "entries + next token"). Rename `Read_Response.data` to `Read_Response.bytes` to make the buffer obvious. -- **Rationale:** The `contents` of a directory and the `contents` of a file are different domains. Type system will not catch a programmer who reads `.contents.length` expecting bytes and gets `DirectoryEntry[].length`. - -### 10. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` +### 8. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` ```ts // files/v2: file/directory metadata snapshot @@ -225,41 +184,40 @@ export interface FileInfo { ... } - **Why weird:** Three different packages all export `FileInfo` with three different shapes. The names are flat-spaced inside the package, but downstream consumers who do `import * as files from '@databricks/sdk-files/v2'; import * as exp from '@databricks/sdk-experiments/v1';` get two unrelated `FileInfo` types and `files.FileInfo !== exp.FileInfo` is a confusing source of bugs. - **Category:** 1 (vague/generic top-level name), 12 (duplicate concept across packages), 15 (generic name loses meaning). -- **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #6 — `FileEntry`). +- **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #5 — `FileEntry`). - **Rationale:** `FileInfo` is so generic three different domains felt entitled to use it. -### 11. `Create` returns a `handle` (not the created file) — `src/v2/model.ts:23-34` +### 9. `Create` returns a `handle` (not the created file) — `src/v2/model.ts:23-34` ```ts export interface Create { path?: string | undefined; overwrite?: boolean | undefined; } -export interface Create_Response { - /** Handle which should subsequently be passed into the AddBlock and Close calls when writing to a file through a stream. */ - handle?: number | undefined; -} +// Response shape: +// handle?: number | undefined; +// "Handle which should subsequently be passed into the AddBlock and Close calls when writing to a file through a stream." ``` - **Why weird:** The method is called `create` but does NOT create a file — it opens a write stream and returns a handle. The actual file doesn't exist until you call `close`. A reader of `client.create({path: '/tmp/foo'})` would reasonably expect the file to be created. JSDoc on the method says "Opens a stream to write to a file and returns a handle to this stream." — directly contradicting the name. -- **Category:** 6 (misleading — name says "create" but action is "open"), 14 (Go/proto-style — the upstream proto's name leaked through). +- **Category:** 6 (misleading — name says "create" but action is "open"). - **Suggested name:** `OpenWriteStream` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). - **Rationale:** Method name should reflect action; right now `create` and `createDirectory` look like sibling actions when they are entirely different (create-handle vs create-resource). -### 12. `handle: number` — underspecified ID — `src/v2/model.ts:7,17,33` +### 10. `handle: number` — underspecified ID — `src/v2/model.ts:7,17,33` ```ts AddBlock.handle?: number // "The handle on an open stream." Close.handle?: number -Create_Response.handle?: number +// Response Create handle?: number ``` -- **Why weird:** A `number` named `handle` looks like a `numeric ID`, but the JSDoc says it is the result of an `open` (per #11). No type-brand prevents passing arbitrary numbers; no documentation says whether it is positive, monotonic, opaque, or guaranteed unique. The Go SDK uses `int64` here and TS narrows to `number`, which is silently truncated above 2^53 — and there is no mitigation in this client. +- **Why weird:** A `number` named `handle` looks like a `numeric ID`, but the JSDoc says it is the result of an `open` (per #9). No type-brand prevents passing arbitrary numbers; no documentation says whether it is positive, monotonic, opaque, or guaranteed unique. The Go SDK uses `int64` here and TS narrows to `number`, which is silently truncated above 2^53 — and there is no mitigation in this client. - **Category:** 19 (underspecified ID). - **Suggested name:** `streamHandle: number` (or `DbfsStreamHandle` branded type). At minimum, type-document "opaque integer from DBFS server; pass as-is". - **Rationale:** TS `number` for a server-issued 64-bit token is a known precision hazard; the field name doesn't even hint that it's a transient stream identifier. -### 13. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:292,656` +### 11. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:292,656` ```ts async list(req: ListStatus, ...): Promise // legacy DBFS @@ -271,7 +229,7 @@ async listDirectoryContents(req: ListDirectoryContentsRequest, ...): Promise @@ -297,7 +255,9 @@ export function buildHttpRequest(method, url, headers, signal?, body?): HttpRequ - **Suggested name:** Collapse to one helper (`sendRequest`), let it return the raw `HttpResponse`, and have the caller buffer/stream as needed. Or, if both must exist: `sendAndBuffer` (returns buffered body) and `sendAndStream` (returns raw response). - **Rationale:** Three functions doing nearly the same thing with names that differ in verb is a recipe for mis-imports. -### 16. `path` as the only field in 5 request types — `src/v2/model.ts:23,45,160,213,224` +## Medium severity + +### 14. `path` as the only field in 5 request types — `src/v2/model.ts:23,45,160,213,224` ```ts Create: { path?: string; overwrite?: boolean } @@ -312,7 +272,7 @@ MkDirs: { path?: string } - **Suggested name:** Use the discriminated field names from the modern API: `dbfsPath` everywhere on the legacy types; or split into `Create.filePath` (because `Create` is a write-stream open, ie file) and `MkDirs.directoryPath`. Helps callers see "this is a path to a file" vs "this is a path to a directory." - **Rationale:** Structural typing makes the five types interchangeable — a name change is the cheapest defence. -### 17. `Move.sourcePath` / `Move.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` +### 15. `Move.sourcePath` / `Move.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` ```ts export const marshalMoveSchema: z.ZodType = z @@ -331,9 +291,27 @@ export const marshalMoveSchema: z.ZodType = z - **Suggested name:** Acceptable as-is (these are clearer than `path1`/`path2`). Flag only the inconsistency with the rest of the DBFS surface. - **Rationale:** The inconsistency is upstream; the TS port should match. -## Medium severity +### 16. `contents` field has three different types across model — `src/v2/model.ts:108,246,281,275` -### 18. v1 `Client` constructor allows `host` to be undefined — `src/v1/client.ts:21` +```ts +DownloadFileResponse.contents?: ReadableStream | undefined // line 108 +Put.contents?: Uint8Array | undefined // line 246 +// Read response data?: Uint8Array | undefined (named 'data')// line 275 — same concept, different name +UploadFileRequest.contents?: ReadableStream | undefined // line 281 +ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 208 +``` + +- **Why weird:** "Contents" is overloaded across the model: + - `DownloadFileResponse.contents`: file bytes as a stream. + - `UploadFileRequest.contents`: file bytes as a stream. + - `Put.contents`: file bytes as a `Uint8Array` (no streaming on the legacy API). + - Read response `data`: file bytes (chunked read) as a `Uint8Array` — same concept as `Put.contents` but called `data`. + - `ListDirectoryResponse.contents`: directory entries (array of `DirectoryEntry`). +- **Category:** 6 (misleading), 12 (duplicate concept — `contents` and `data`), 15 (generic name loses meaning — what's in "contents"?), 17 (inconsistent — same concept, three names). +- **Suggested name:** `body: ReadableStream` for stream payload, `bodyBytes: Uint8Array` for buffered, `entries: DirectoryEntry[]` for list responses (matching the `next_page_token` pattern of "entries + next token"). Rename the read response `data` field to `bytes` to make the buffer obvious. +- **Rationale:** The `contents` of a directory and the `contents` of a file are different domains. Type system will not catch a programmer who reads `.contents.length` expecting bytes and gets `DirectoryEntry[].length`. + +### 17. v1 `Client` constructor allows `host` to be undefined — `src/v1/client.ts:21` ```ts constructor(options: ClientOptions) { @@ -347,7 +325,7 @@ constructor(options: ClientOptions) { `ClientOptions.host` is typed optional but in practice always required. Not a name bug per se — but `host` is also generic; `workspaceUrl`/`workspaceHost` would be clearer. Same critique on `v2/client.ts:103`. -### 19. v1 `UploadRequest.contents` is `ReadableStream` but v2 `UploadFileRequest.contents` is bare `ReadableStream` — `src/v1/model.ts:11`, `src/v2/model.ts:281` +### 18. v1 `UploadRequest.contents` is `ReadableStream` but v2 `UploadFileRequest.contents` is bare `ReadableStream` — `src/v1/model.ts:11`, `src/v2/model.ts:281` ```ts // v1 @@ -358,18 +336,17 @@ contents?: ReadableStream | undefined; // optional, generic-erased v2 weakens the type — both `ReadableStream` and `ReadableStream` would be more correct, but more importantly v1's `Uint8Array` constraint is gone. Same for `DownloadResponse.contents` vs `DownloadFileResponse.contents`. -### 20. `bytesRead` vs `data` in `Read_Response` — singular/plural and naming mismatch — `src/v2/model.ts:267-275` +### 19. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-275` ```ts -export interface Read_Response { - bytesRead?: number | undefined; // count - data?: Uint8Array | undefined; // bytes -} +// Read response: +// bytesRead?: number // count +// data?: Uint8Array // bytes ``` `bytesRead` (count) and `data` (the bytes) refer to the same byte slice. `bytesRead` is the LENGTH; `data` is the BUFFER. Cleaner: `bytes: Uint8Array` and `bytesRead: number` (count); even better, drop `bytesRead` since `data.byteLength` is the same value. -### 21. `ifUnmodifiedSince` — verb-as-noun field — `src/v2/model.ts:101,149` +### 20. `ifUnmodifiedSince` — verb-as-noun field — `src/v2/model.ts:101,149` ```ts ifUnmodifiedSince?: string | undefined; @@ -377,7 +354,7 @@ ifUnmodifiedSince?: string | undefined; Mirrors the HTTP header name exactly. Faithful to RFC 9110, but as a TS field name `ifUnmodifiedSince` is a conditional, not a value. `unmodifiedSinceHeader: string` or `notModifiedSince: string` is more idiomatic. Acceptable as-is (HTTP convention), flagged only as observation. -### 22. `range` (HTTP byte range header value) — same — `src/v2/model.ts:95,143` +### 21. `range` (HTTP byte range header value) — same — `src/v2/model.ts:95,143` ```ts range?: string | undefined; @@ -385,11 +362,11 @@ range?: string | undefined; Field name `range` is overloaded (range of numbers? date range?). The doc clarifies "range of bytes to retrieve" — name could be `byteRange` or `rangeHeader`. -### 23. `directoryPath` vs `path` — inconsistent across methods — `src/v2/model.ts:39,58,128,180` +### 22. `directoryPath` vs `path` — inconsistent across methods — `src/v2/model.ts:39,58,128,180` The modern Files API consistently uses `directoryPath` / `filePath`. The legacy DBFS uses just `path` even when the value is known to be a directory (`MkDirs.path`) or file (`Create.path`). In v1 it was always `filePath`. v2 has both. Choose: prefix every path with the kind, OR drop the prefix everywhere. -### 24. `recursive` (Delete) — field name does not tell you what it does — `src/v2/model.ts:49` +### 23. `recursive` (Delete) — field name does not tell you what it does — `src/v2/model.ts:49` ```ts recursive?: boolean | undefined; @@ -397,7 +374,7 @@ recursive?: boolean | undefined; A `recursive: true` on a `Delete` could mean "follow symlinks", "descend into subdirs", etc. JSDoc clarifies "Whether or not to recursively delete the directory's contents." Name OK in context; would prefer `recursivelyDeleteContents: boolean` for self-documentation, but `recursive` is conventional. -### 25. `overwrite` — same — `src/v2/model.ts:27,248,283` +### 24. `overwrite` — same — `src/v2/model.ts:27,248,283` ```ts overwrite?: boolean | undefined; @@ -405,7 +382,7 @@ overwrite?: boolean | undefined; Appears in `Create`, `Put`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `Create` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. -### 26. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,194,196` +### 25. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,194,196` ```ts contents?: DirectoryEntry[] | undefined; @@ -415,19 +392,17 @@ nextPageToken?: string | undefined; // OK JSDoc strings reference the wire name (`next_page_token`), but the TS field is `nextPageToken`. The doc accurately reflects the wire — flagged because cross-referencing a wire name in user-facing JSDoc is confusing. Should reference the TS field name (`nextPageToken`). -### 27. `pageSize` recommendation "We recommend not to set this value..." — `src/v2/model.ts:186` - -Doc says don't set the field. Then why is the field public? Name is fine; flagging the inconsistent guidance. +## Low severity -### 28. `@typescript-eslint/naming-convention` eslint-disables for `_Response` types — `model.ts:12,20,30,52,165,218,229,238,250,266` +### 26. `pageSize` recommendation "We recommend not to set this value..." — `src/v2/model.ts:186` -Every legacy `Foo_Response` type carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive because the underscore violates TS PascalCase. Modern API peers (`CreateDirectoryResponse`, `DownloadFileResponse`) need no such directive. Two conventions, one file — surface friction every time the generator runs. +Doc says don't set the field. Then why is the field public? Name is fine; flagging the inconsistent guidance. -### 29. `Read_Response.data: Uint8Array` is base64 on the wire — `src/v2/model.ts:273` +### 27. Read response `data: Uint8Array` is base64 on the wire — `src/v2/model.ts:273` The field is decoded from base64 on read; doc says "The base64-encoded contents of the file read." but the TS type is already `Uint8Array` (decoded). Consumers reading the docstring may think they have to decode themselves. Name could clarify: `bytes: Uint8Array` with doc "Already base64-decoded". -### 30. v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export `DownloadRequest`/`DownloadResponse`-as-used — `src/v1/index.ts:3` +### 28. v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export `DownloadRequest`/`DownloadResponse`-as-used — `src/v1/index.ts:3` ```ts export type {DownloadRequest, DownloadResponse, UploadRequest} from './model'; @@ -435,15 +410,15 @@ export type {DownloadRequest, DownloadResponse, UploadRequest} from './model'; v1 exports `DownloadRequest`/`DownloadResponse` but the v1 client has NO download method. Dangling types — see net assessment. -### 31. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` +### 29. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. -### 32. `readAll` is duplicated — `src/v1/utils.ts:23` and `src/v2/utils.ts:40` +### 30. `readAll` is duplicated — `src/v1/utils.ts:23` and `src/v2/utils.ts:40` Same conceptual helper, two implementations (v1 uses `new Response(body).arrayBuffer()`, v2 walks the reader manually). Name OK; flagged as cross-version duplication. -### 33. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` +### 31. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` ```ts const PACKAGE_SEGMENT = { @@ -454,7 +429,7 @@ const PACKAGE_SEGMENT = { SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. This is a plain object; `packageSegment` is fine. -### 34. `HttpCallOptions` duplicated across files — `src/v1/utils.ts:13`, `src/v2/utils.ts:15` +### 32. `HttpCallOptions` duplicated across files — `src/v1/utils.ts:13`, `src/v2/utils.ts:15` ```ts export interface HttpCallOptions { @@ -466,38 +441,25 @@ export interface HttpCallOptions { Same name, same shape, in two files in the same package. Should be shared / re-exported. -## Low severity +## Observations -### 35. v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` — `src/v1/utils.ts:36`, `src/v2/utils.ts:156` +### 33. v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` — `src/v1/utils.ts:36`, `src/v2/utils.ts:156` Same function, renamed in v2. Good rename (v2's is more accurate), but the rename means a v1 user upgrading sees an unexplained name change. -### 36. `Move.sourcePath` / `Move.destinationPath` — could be `source` / `destination` — `src/v2/model.ts:233-236` +### 34. `Move.sourcePath` / `Move.destinationPath` — could be `source` / `destination` — `src/v2/model.ts:233-236` The type name is `Move`; the fields are `sourcePath`/`destinationPath`. Inside a `Move` request, the `Path` suffix is redundant — `source: string; destination: string`. Acceptable; flagged because it's the longer form against the rest of the file's `path: string`. -### 37. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` +### 35. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) -### 38. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` +### 36. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. -### 39. v2 `index.ts` exports neither `Client` constants nor `VERSION` — `src/v2/index.ts:3-6` - -```ts -export {Client} from './client'; -export {} from './model'; // <-- empty named export -``` - -Line 5 (`export {} from './model';`) is a no-op. Not a name bug, just dead syntax. - -### 40. `directoryPath ?? ''` fallback in client — `src/v2/client.ts:462,492,517,546,595,626,660,716` - -8 places where `directoryPath` is coerced to empty string. Field is typed optional but the URL must have it. Either type the field as required, or document the fallback. Name OK. - -### 41. v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" — `src/v1/client.ts:33-36` +### 37. v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" — `src/v1/client.ts:33-36` ```ts /** @@ -509,37 +471,3 @@ async upload(req: UploadRequest, options?: CallOptions): Promise { ``` `upload` is the name; the JSDoc tells you it doesn't retry. v2 inherits the same property for `uploadFile` but the doc on `client.ts:706` doesn't say so. Inconsistent docs across versions. - -### 42. `pkgJson.name.replace(/^@[^/]+\//, '')` — `src/v2/client.ts:90` - -Inlined regex to strip `@scope/` prefix. Should be a helper named `packageName`. Not a naming issue per se. - -### 43. v1 imports `@databricks/sdk-core/http` (not `@databricks/sdk-databricks/http`) — `src/v1/client.ts:9` - -Different package than the audit but worth flagging: v1 still uses `sdk-core` while v2 uses `sdk-databricks` for some imports — internal inconsistency. - -## Observations - -### 44. The empty `export {} from './model';` line — `src/v2/index.ts:5` - -Likely a generator artifact; no impact. - -### 45. v1 has 78 lines of utils for one operation; v2 has 196 lines of utils for ten operations — files are well-sized. - -### 46. `Client` constructor's User-Agent code is duplicated across packages — out of scope here. - -### 47. `'head'` HTTP method passed in lowercase to `buildHttpRequest` — `src/v2/client.ts:600,637` - -```ts -const httpReq = buildHttpRequest('head', url, headers, callSignal); -``` - -Other calls use `'POST'`/`'GET'`/`'PUT'`/`'DELETE'` uppercase. Cosmetic — actual bug because `buildHttpRequest` does not normalise — but flagged here as casing inconsistency. - -### 48. `read()` JSDoc references `RESOURCE_DOES_NOT_EXIST`, `MAX_READ_SIZE_EXCEEDED`, `INVALID_PARAMETER_VALUE` — strings, not enums — `src/v2/client.ts:412-418` - -Error codes are referenced as freeform strings in JSDoc. Out of naming scope. - -### 49. Legacy DBFS `list` lacks pagination wire shape — `src/v2/model.ts:160,178` - -The modern Files API `listDirectoryContents` carries `pageSize` / `pageToken` on the request and `nextPageToken` on the response. The legacy DBFS `list` (`ListStatus` request) has only `path` and returns `ListStatus_Response` with no paging cursor — the JSDoc on `list` even warns of a 10 K file cap. Two list shapes for the same conceptual operation, one with pagination wire fields and one without. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index cfa6d849..163b9cf4 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -9,14 +9,10 @@ - `src/v1/utils.ts` - `src/v1/index.ts` -This audit applies the 20 numbered concern categories from the audit -checklist. Each finding lists the offending identifier(s), the -category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete -rename suggestion. Findings are grouped by category. Generator-driven -items (such as the proto-style underscored nested-message names) are -flagged as `LOW` because they are codified across the entire generated -SDK surface — they should be fixed at the generator, not by -hand-editing this package. +This audit applies the audit checklist categories. Each finding lists +the offending identifier(s), the category, severity +(`HIGH` / `MEDIUM` / `LOW`), and a concrete rename suggestion. +Findings are grouped by category. --- @@ -72,15 +68,7 @@ hand-editing this package. package-qualified import convention, or rename to `ForecastingClient` consistently across packages. Cross-cutting. -#### F1.2 — `req` parameter on every client method (LOW) -- **Where:** `client.ts:69, 100, 114`. -- **Why flagged:** `req` is a Go-ism (see category 14). It is also - generic — a reader has to look at the type to know what the - request is. -- **Suggestion:** Use a domain-meaningful parameter name - (`experiment`, `request`) for stylistic consistency with `options`. - -#### F1.3 — `primaryMetric: string` (MEDIUM) +#### F1.2 — `primaryMetric: string` (MEDIUM) - **Where:** `model.ts:34`. - **Why flagged:** "Primary metric" without enumeration is vague. JSDoc says only "The evaluation metric used to optimize the @@ -92,17 +80,7 @@ hand-editing this package. union type `PrimaryMetric = 'mae' | 'mse' | …`. Naming itself is fine; signal loss happens at the field level. -#### F1.4 — `state` field on `ForecastingExperiment` (LOW) -- **Where:** `model.ts:78`. -- **Why flagged:** "state" alone is generic. Consistent with proto - enum naming so likely acceptable. In TS, `status` is more idiomatic - for read-only lifecycle indicators returned by an API; "state" is - more common for owned/mutable state. Minor. -- **Suggestion:** Keep for parity with Go/proto. Note that the - internal poll variable in `client.ts:160, 202` is named `status`, - exposing the field/local terminology drift. - -#### F1.5 — `target` is *not* present here (note) +#### F1.3 — `target` is *not* present here (note) - Unlike many sibling packages, this package's request payload uses domain-specific column names (`targetColumn`, `splitColumn`, `timeColumn`, `customWeightsColumn`) which is *good* and is the @@ -113,169 +91,19 @@ hand-editing this package. ### 2. Redundant enum prefixes -#### F2.1 — `ForecastingExperiment_State` members (acceptable) -- **Where:** `model.ts:6-17`. -- **Why flagged:** The members are `PENDING`, `RUNNING`, `SUCCEEDED`, - `FAILED`, `CANCELLED`. None of them re-prefix the enum name (e.g. - no `STATE_PENDING`). Good shape. -- **Suggestion:** No change. +_None._ --- ### 3. Acronym casing inconsistencies -#### F3.1 — `Id` vs `ID` (LOW, cross-cutting) -- **Where:** `model.ts:68, 74, 83`, `client.ts:104-109, 141, 155, 197`, - `index.ts:12`. -- **Why flagged:** This SDK uses **lower-camel `Id`** consistently - (`experimentId`). That is internally consistent within the package. - The TS/JS community is split — DOM uses `nodeId`/`HTMLElement`, - TypeScript itself uses `id`/`uuid` — so `Id` is defensible. -- **Suggestion:** Keep `Id`. The cross-package convention is already - in place. - -#### F3.2 — `URL` / `Url` consistency (acceptable) -- `client.ts` consistently uses `url` (lowercase) as a local var. - `experimentPageUrl` (model.ts:76) uses `Url`. No casing - inconsistency observed within the file. - -#### F3.3 — `HTTP` / `Http` (acceptable for this file) -- `utils.ts` consistently uses `Http` PascalCase (`HttpClient`, - `HttpRequest`, `HttpResponse`, `HttpCallOptions`, - `executeHttpCall`, `buildHttpRequest`). `client.ts:81, 122` uses - `httpReq` (lowercase prefix, PascalCase noun). Consistent. - -#### F3.4 — `RPC` in JSDoc (LOW) -- **Where:** `client.ts:112` — JSDoc "Public RPC to get forecasting - experiment". -- **Why flagged:** Documentation, not an identifier. Mentioning - "RPC" leaks the Go/proto vocabulary into user-facing JSDoc; - TS users do not typically think of method calls as "RPCs". - See also F14 for Go-ism flavor. -- **Suggestion:** Rewrite JSDoc as "Fetches a forecasting - experiment by ID." +_None._ --- -### 4. Underscores in TS identifiers - -> The TypeScript style guide (Google) and the SDK's own -> `typescript.mdc` disallow `snake_case` and underscores in -> identifiers. The generator emits proto-style "outer_inner" names -> as `Outer_Inner` to disambiguate nested messages — but TS would -> normally fold these into namespaces or flat PascalCase. - -#### F4.1 — `ForecastingExperiment_State` (HIGH, cross-cutting, - generator concern) -- **Where:** `model.ts:6`, `client.ts:28, 166, 169-170, 208-210`, - `index.ts:5`. -- **Why flagged:** Requires - `eslint-disable-next-line @typescript-eslint/naming-convention` - (model.ts:5). That alone is a smell. The TypeScript-idiomatic - equivalents would be either a nested namespace - (`namespace ForecastingExperiment { export enum State { … } }`) or - flat PascalCase (`ForecastingExperimentState`). -- **Suggestion:** Drop the underscore at the generator level. Two - viable shapes: - 1. **Flat PascalCase** — `ForecastingExperimentState`. - 2. **Namespace nesting** — keep parent name, drop underscore: - `ForecastingExperiment.State`. - Approach (1) is more straightforward for tree-shaking and module - re-exports; approach (2) more closely mirrors the proto nesting. - -#### F4.2 — JSDoc comment "double-slash" artifact in - `splitColumn` (LOW) -- **Where:** `model.ts:41`. -- **Why flagged:** The JSDoc reads `/** // The column ... */` — an - extra `//` was carried through from the source. Cosmetic bug; - not strictly a naming issue but noticed during inventory. -- **Suggestion:** Fix at generator: strip leading `// ` from JSDoc - text. - ---- +### 4. Misleading names -### 5. Cryptic abbreviations - -#### F5.1 — `req` (LOW, Go-ism) -- **Where:** `client.ts:69, 100, 104, 114, 117`. -- Already flagged under F1.2 / F14.1. - -#### F5.2 — `resp` (LOW, Go-ism) -- **Where:** `client.ts:77, 87, 103-104, 118, 128, 153, 160, - 167, 195, 202`; `utils.ts:73, 81, 83, 88`. -- See F14.2. - -#### F5.3 — `respBody` (LOW) -- **Where:** `client.ts:82, 123`. -- **Why flagged:** "resp" abbreviation. Spell out `responseBody` - for clarity in TS where verbosity is cheap. -- **Suggestion:** `responseBody`. - -#### F5.4 — `httpReq` (LOW) -- **Where:** `client.ts:81, 122`. -- **Why flagged:** `httpRequest` is clearer and matches the type - `HttpRequest` exactly. -- **Suggestion:** `httpRequest`. - -#### F5.5 — `apiErr` (LOW) -- **Where:** `utils.ts:88, 89`. -- **Why flagged:** `apiError` reads better; "err" is a Go-ism. -- **Suggestion:** `apiError`. - -#### F5.6 — `pkgJson` (LOW) -- **Where:** `client.ts:20, 36, 37`. -- **Why flagged:** "pkg" abbreviation. `packageJson` is two extra - characters and unambiguous. -- **Suggestion:** `packageJson`. - -#### F5.7 — `msg` (LOW) -- **Where:** `client.ts:171, 172`. -- **Why flagged:** `const msg = '(no message)';` — short variable - name for a one-shot constant. Marginal. -- **Suggestion:** Either inline the literal - (`` `terminal state ${status}: (no message)` ``) or rename to - `message`. The variable currently exists for no reason — its - initializer is a literal and it is used once. - -#### F5.8 — `opts`, `e`, `acc`, `val` (LOW) -- **Where:** `utils.ts:30, 55, 76, 137`. -- **Why flagged:** - - `acc` (utils.ts:55) — reduce accumulator, conventional. OK. - - `val` (utils.ts:137) — local destructure, OK. - - `opts` (utils.ts:66, 68, 73, 75, 81, 83, 88) — Go-ism; - `options` is preferred but `opts` is widely used in JS - libraries. **Inconsistent with itself:** the public parameter - name is `options` (utils.ts:28) but the internal one is `opts` - (utils.ts:30, 66). Pick one. - - `e` for the caught exception (utils.ts:76) — TS guidance - accepts `err`/`error`/`e`; match the file's other usages - (`apiErr`). -- **Suggestion:** rename `opts → options` inside `executeHttpCall` - for consistency; leave `acc`, `val`, `e` alone. - -#### F5.9 — `resp` as a poll-result variable (LOW) -- **Where:** `client.ts:103, 153, 167, 195` — `pollResp`. -- **Why flagged:** `pollResp` is a doubly-truncated name. Either - `pollResponse` or `poll` would read more naturally. -- **Suggestion:** `pollResponse` (matches expansion of `resp`) or - inline the call entirely. - ---- - -### 6. Misleading names - -#### F6.1 — `state` returned vs `status` used internally (LOW) -- **Where:** `model.ts:78`, `client.ts:160, 162, 202, 204`. -- **Why flagged:** The wire field is `state`, decoded into - `ForecastingExperiment.state`. Inside the waiter, the value is - reassigned to a local named `status` and the error message says - "response missing required status field". This is misleading — - the field that is required is `state`, not `status`. -- **Suggestion:** Rename the locals to `state` to match the - domain term, or rename the field to `status` (less invasive in - TS but breaks parity). - -#### F6.2 — `done` method on the waiter does not return a boolean of +#### F4.1 — `done` method on the waiter does not return a boolean of "I'm done waiting" but "operation has reached a terminal state" (LOW) - **Where:** `client.ts:194-215`. @@ -288,7 +116,7 @@ hand-editing this package. ("Checks whether the operation has reached a terminal state.") does clarify this, but the name does not. -#### F6.3 — `createForecastingExperimentWaiter` returns the waiter, +#### F4.2 — `createForecastingExperimentWaiter` returns the waiter, not the response (LOW) - **Where:** `client.ts:99-110`. - **Why flagged:** The method name suggests "create a waiter," but @@ -304,43 +132,11 @@ hand-editing this package. type be `ForecastingExperimentRun` or similar). The current name reads as if it merely *constructs* a waiter without side effects. -#### F6.4 — `(no message)` placeholder string (LOW, doc/UX) -- **Where:** `client.ts:171-172`. -- **Why flagged:** Not strictly naming. The thrown error has the - literal text `(no message)`. There is no field on - `ForecastingExperiment` that carries a failure message, so the - waiter cannot do better — but the placeholder is a code smell. -- **Suggestion:** Either add a `message`/`error` field to - `ForecastingExperiment` (server contract) or drop the placeholder - and throw `new Error(``terminal state ${status}``)`. - -#### F6.5 — `flattenQueryParams` is exported but unused in this - package (LOW) -- **Where:** `utils.ts:123-150`. -- **Why flagged:** The name suggests it is a query-param helper for - this client; the client does not call it (only `POST` with body - and `GET` with path param, no `URLSearchParams` usage). The - function is dead code inside this package. Either there is an - intended caller that has not landed, or the helper should not be - in this package. -- **Suggestion:** Move shared helpers to `@databricks/sdk-core` or - delete from this package's `utils.ts`. - -#### F6.6 — `createDefault` in client construction (LOW) -- **Where:** `client.ts:6, 57`. -- **Why flagged:** Documentation, not identifier. The imported - function is `createDefault` from `clientinfo`. The name - `createDefault` is vague at the import site — without reading - the source, it is unclear that it creates a *user-agent - client-info builder*. Imported in every package. -- **Suggestion:** Cross-cutting upstream rename - (`createClientInfo` / `defaultClientInfo`). Out of scope here. - --- -### 7. Overly verbose +### 5. Overly verbose -#### F7.1 — `ForecastingExperiment` (MEDIUM) +#### F5.1 — `ForecastingExperiment` (MEDIUM) - **Where:** `model.ts:72`. - **Why flagged:** Inside a package literally named `forecasting`, every type is about forecasting. The `Forecasting` prefix doesn't @@ -348,13 +144,13 @@ hand-editing this package. `import {ForecastingExperiment} from '@databricks/sdk-forecasting'` — the `Forecasting` is said twice. - **Suggestion:** Rename to `Experiment`. The package name carries - the qualifier. Combined with F7.2 / F7.3 this collapses naming + the qualifier. Combined with F5.2 / F5.3 this collapses naming significantly. **Caveat:** `Experiment` is the same name used by the MLflow `experiments` API. If both packages are likely to be imported together, the qualification helps. Worth a cross-package review. -#### F7.2 — `CreateForecastingExperimentRequest`, +#### F5.2 — `CreateForecastingExperimentRequest`, `CreateForecastingExperimentResponse`, `GetForecastingExperimentRequest` (MEDIUM) - **Where:** `model.ts:19, 66, 81`; `index.ts:8-12`. @@ -368,27 +164,29 @@ hand-editing this package. `GetExperimentRequest`. Or, if collapsed to a single client method per verb, just `CreateRequest`/`CreateResponse`/`GetRequest`. -#### F7.3 — `CreateForecastingExperimentWaiter` (HIGH) +#### F5.3 — `CreateForecastingExperimentWaiter` (HIGH) - **Where:** `client.ts:138`, `index.ts:3`. - **Why flagged:** 34 characters. Reads as "Create-Forecasting-Experiment-Waiter". With `Forecasting` removed - (F7.1), it becomes `CreateExperimentWaiter` — still long but - workable. Alternative: drop `Create` since the waiter exists only + (F5.1), it becomes `CreateExperimentWaiter` — still long but + workable. The `Waiter` suffix itself is a Go SDK pattern; in TS/JS + the more common terms are `Operation`, `Poller`, `Run`, or + `Tracker`. Alternative: drop `Create` since the waiter exists only for create-style long-running operations, and name it `ExperimentRun` or `Operation`. - **Suggestion:** Rename to `ExperimentRun` (analogous to - `LongRunningOperation` in other SDKs). Combined with F6.3, the + `LongRunningOperation` in other SDKs). Combined with F4.2, the flow becomes `const run = await client.forecasting.startExperiment(req); await run.wait();`. -#### F7.4 — `createForecastingExperimentWaiter` method (HIGH) +#### F5.4 — `createForecastingExperimentWaiter` method (HIGH) - **Where:** `client.ts:99`. -- **Why flagged:** 35 character method name. Same issue as F7.3. +- **Why flagged:** 35 character method name. Same issue as F5.3. - **Suggestion:** Rename to `startExperiment` (or `createAndWait`) to match a renamed waiter. -#### F7.5 — `getForecastingExperiment` / `createForecastingExperiment` +#### F5.5 — `getForecastingExperiment` / `createForecastingExperiment` methods (MEDIUM) - **Where:** `client.ts:68, 113`. - **Why flagged:** Inside a `Forecasting` client, the `Forecasting` @@ -400,30 +198,11 @@ hand-editing this package. `get`. The class itself already conveys "forecasting". Cross-cutting convention. -#### F7.6 — `timeseriesIdentifierColumns` (LOW) -- **Where:** `model.ts:50`. -- **Why flagged:** 27 character field name. "Time series identifier - columns" is long-form; "series ID columns" or `seriesIdColumns` - is shorter. The Go wire field is `timeseries_identifier_columns`, - so parity is the constraint. -- **Suggestion:** Keep for parity with Go/proto. Note the verbose - shape for future generator-level optimization. - --- -### 8. Redundant suffixes - -#### F8.1 — `Request` / `Response` on every request/response type - (acceptable) -- **Where:** `model.ts:19, 66, 81`. -- **Why flagged:** `CreateForecastingExperimentRequest`, - `CreateForecastingExperimentResponse`, - `GetForecastingExperimentRequest` — these suffixes are - generator-uniform and disambiguate request from response (which - share a verb). Standard SDK convention. -- **Suggestion:** Keep, but apply with F7.2 to drop `Forecasting`. +### 6. Go-style `Waiter` pattern -#### F8.2 — `Waiter` suffix on `CreateForecastingExperimentWaiter` +#### F6.1 — `Waiter` suffix on `CreateForecastingExperimentWaiter` (LOW) - **Where:** `client.ts:138`. - **Why flagged:** `Waiter` is a Go SDK pattern for long-running @@ -431,196 +210,29 @@ hand-editing this package. `Poller`, `Run`, or `Tracker`. `Waiter` isn't wrong but it is Go-flavored. - **Suggestion:** Rename suffix to `Operation` or `Run` (e.g. - `ExperimentRun`). See F7.3. - ---- - -### 9. Singular / plural mismatches - -#### F9.1 — `holidayRegions: string[]` (LOW) -- **Where:** `model.ts:48`. -- **Why flagged:** JSDoc says "The region code(s) to automatically - add holiday features. **Currently supports only one region.**" - The field is a plural array but server semantics are singular. -- **Suggestion:** API-shape concern; the spec retains a list for - forward-compat. Document the invariant clearly. Not a TS rename - issue. - -#### F9.2 — `trainingFrameworks: string[]` (acceptable) -- Plural-array, no mismatch. - -#### F9.3 — `includeFeatures: string[]` (acceptable) -- Plural-array, no mismatch. - -#### F9.4 — `timeseriesIdentifierColumns: string[]` (acceptable) -- Plural-array, plural meaning. - -#### F9.5 — `experiments` collection method missing (note) -- The client exposes `getForecastingExperiment` (singular) but no - `listForecastingExperiments` (plural). This is an API-completeness - observation, not a naming finding — if `list` is later added it - should be named consistently. + `ExperimentRun`). See F5.3. --- -### 10. Reserved-word / built-in collisions - -#### F10.1 — `state` field (LOW) -- **Where:** `model.ts:78`. -- **Why flagged:** `state` shadows nothing reserved in JS/TS but - is a popular React property name. Acceptable here because the - field is on `ForecastingExperiment`, not on an array or - component. -- **Suggestion:** Keep; not worth churn. +### 7. Reserved-word / built-in collisions -#### F10.2 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) +#### F7.1 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) - **Where:** `client.ts:194`. - **Why flagged:** `done` shadows `IteratorResult.done` (the boolean property returned by iterator `next()`). Defining a `done()` *method* on a non-iterator class is mildly misleading. A reader encountering `waiter.done` might first think of iteration. - **Suggestion:** Rename to `isTerminal()` / `isFinished()` (see - F6.2). - -#### F10.3 — `wait` method (acceptable) -- `wait` is not reserved in JS/TS but is the name of an Atomics - primitive (`Atomics.wait`). Unlikely to be a real collision. - Keep. - -#### F10.4 — `Headers`, `URLSearchParams`, `TextDecoder`, `Error`, - `JSON` (acceptable) -- Used as global classes/objects, no shadowing. - ---- - -### 11. Empty / trivial wrapper types - -#### F11.1 — `StillRunningError` private throw-marker class (LOW) -- **Where:** `client.ts:40`. -- **Why flagged:** A zero-body subclass of `Error` used only as a - signal value for the retrier. This is the JS analog of Go's - sentinel error pattern. Acceptable, but a more idiomatic TS - approach is a tagged object or a symbol returned from the - predicate. -- **Suggestion:** Acceptable as written. If renamed, document - the contract. + F4.1). --- -### 12. Duplicate concepts - -#### F12.1 — `experimentId` declared on both - `ForecastingExperiment`, - `CreateForecastingExperimentResponse`, and - `GetForecastingExperimentRequest` (LOW) -- **Where:** `model.ts:68, 74, 83`. -- **Why flagged:** Same conceptual ID name and type. Consistent — - this is *not* a naming issue, but a duplicate-field pattern. - Worth noting because some other packages (e.g. `budgets`) use - conflicting names for the same ID. -- **Suggestion:** No change. This is the desired state. - -#### F12.2 — Per-method header construction duplicated (LOW, code - style) -- **Where:** `client.ts:79-81, 120-122`. -- **Why flagged:** Every method runs: - ```ts - const headers = new Headers(...); - headers.set('User-Agent', this.userAgent); - ``` - Could be a private helper `this.buildHeaders(...)`. Not a naming - issue, but a code-duplication smell. -- **Suggestion:** Out of scope for naming audit. Mentioned for - completeness. - -#### F12.3 — `experimentPath` (request) vs `experimentPageUrl` - (response) — two URL-ish fields (LOW) -- **Where:** `model.ts:38, 76`. -- **Why flagged:** `experimentPath` is a *workspace* path - (`/Users/alice/myexperiment`) where the experiment is *stored*; - `experimentPageUrl` is the absolute UI URL. The semantic distinction - is real but the names are close enough that a casual reader could - conflate "path" and "URL". -- **Suggestion:** Keep, but ensure JSDoc on each makes the - distinction explicit. The current JSDoc on `experimentPath` - ("The path in the workspace to store the created experiment.") - is correct. - -#### F12.4 — `trainDataPath`, `predictionDataPath`, - `futureFeatureDataPath` (acceptable, but observe pattern) -- **Where:** `model.ts:21, 52, 63`. -- **Why flagged:** All three are "fully qualified path of a Unity - Catalog table." The pattern is consistent. Worth observing that - these aren't "paths" in the workspace sense — they're - catalog-schema-table identifiers (`catalog.schema.table`). - Calling them `Path` is mildly confusing because - `experimentPath` is *literally* a workspace path string. - See F16.1. +### 8. Generic field names losing meaning ---- - -### 13. Verb-tense inconsistency - -#### F13.1 — Method verbs (acceptable) -- `create*`, `get*` — uniform imperative present. Good. - -#### F13.2 — `wait` vs `done` on the waiter (acceptable) -- Both are imperative single-word verbs. Match. Subject to F6.2 - / F10.2. - ---- - -### 14. Go / Java-style names - -#### F14.1 — `req`, `resp`, `err`, `Waiter`, `httpReq`, `apiErr`, - `pkgJson`, `opts`, `msg`, `pollResp` (HIGH, but cross-cutting) -- **Where:** - - `req` everywhere in `client.ts` - - `resp` everywhere in `client.ts` and `utils.ts:73, 81` - - `e` in `utils.ts:76` (with rethrow) - - `Waiter` suffix in `CreateForecastingExperimentWaiter` - - `httpReq` in client.ts:81, 122 - - `apiErr` in utils.ts:88 - - `pkgJson` in client.ts:20 - - `opts` in utils.ts:30, 66 - - `msg` in client.ts:171 - - `pollResp` in client.ts:153, 167, 195, 202 -- **Why flagged:** These are all classic Go idioms ported verbatim. - TS convention favors spelled-out names (`request`, `response`, - `error`, `httpRequest`, `apiError`, `packageJson`, `options`, - `message`, `pollResponse`). The `Waiter` pattern itself is also - Go-style; TS/JS generally uses "operation," "poller," or "run." -- **Suggestion:** Spell them out. Trivial diff, large readability - gain. This is a porting-convention decision and should be made - globally at the generator level. - -#### F14.2 — `_State` underscore-pseudo-nesting (HIGH) -- See F4.1. Underscores are foreign to TS. - -#### F14.3 — `Public RPC to get forecasting experiment` JSDoc (LOW) -- See F3.4. - -#### F14.4 — `terminal state` error message style (LOW) -- **Where:** `client.ts:172`. -- **Why flagged:** "terminal state" is Go-flavored language; TS/JS - user-facing errors more commonly say "operation failed" or - "experiment is in failed state." -- **Suggestion:** Rephrase the thrown error message for clarity. - ---- +#### F8.1 — `primaryMetric: string` (MEDIUM) +- **Where:** `model.ts:34`. See F1.2. -### 15. Generic field names losing meaning - -#### F15.1 — `state` (LOW) -- **Where:** `model.ts:78`. See F1.4 and F6.1. - -#### F15.2 — `primaryMetric: string` (MEDIUM) -- **Where:** `model.ts:34`. See F1.3. - -#### F15.3 — `req` parameter on every client method (HIGH) -- See F1.2 and F14.1. - -#### F15.4 — `registerTo: string` (MEDIUM) +#### F8.2 — `registerTo: string` (MEDIUM) - **Where:** `model.ts:46`. - **Why flagged:** `registerTo` is a verb-phrase masquerading as a noun field. The JSDoc clarifies it is "the fully qualified path @@ -630,7 +242,7 @@ hand-editing this package. `modelTargetName` / `registeredModelName`. Cross-cutting if other packages share the pattern. -#### F15.5 — `maxRuntime: number` (LOW) +#### F8.3 — `maxRuntime: number` (LOW) - **Where:** `model.ts:40`. - **Why flagged:** Units are missing from the field name. JSDoc says minutes, but `maxRuntime: number` doesn't. @@ -638,20 +250,24 @@ hand-editing this package. to a duration string (`ISO 8601` PT1H, etc.) if the API supports it. Common SDK convention: suffix the unit on the field name. -#### F15.6 — `forecastHorizon: number` (LOW) -- **Where:** `model.ts:32`. -- **Why flagged:** Similar units issue. The JSDoc explains "The - number of time steps into the future to make predictions, - calculated as a multiple of forecast_granularity." Units are - derived from another field — not from the name. -- **Suggestion:** Leave (units depend on granularity), but - ensure JSDoc is the source of truth. +--- + +### 9. Untyped string for closed enum + +#### F9.1 — `forecastGranularity: string` (LOW) +- **Where:** `model.ts:30`. +- **Why flagged:** Type is `string` but JSDoc enumerates discrete + values like `'1 second'`, `'Hourly'`, `'Yearly'`. This is a + string-typed enum. Compare F1.2. +- **Suggestion:** Introduce a string-literal union type + `ForecastGranularity = '1 second' | '1 minute' | … | 'Yearly'`, + or document acceptable strings in JSDoc more rigorously. --- -### 16. Field contradicting type domain +### 10. `*Path` fields contradicting type domain -#### F16.1 — `*Path` fields holding three-part catalog names (MEDIUM) +#### F10.1 — `*Path` fields holding three-part catalog names (MEDIUM) - **Where:** `model.ts:21 (trainDataPath), 52 (predictionDataPath), 63 (futureFeatureDataPath)`. - **Why flagged:** "Path" suggests a hierarchical workspace or @@ -664,90 +280,6 @@ hand-editing this package. `predictionDataTable`. Or use UC's term: `*Reference` (`trainingDataReference`). -#### F16.2 — `forecastGranularity: string` (LOW) -- **Where:** `model.ts:30`. -- **Why flagged:** Type is `string` but JSDoc enumerates discrete - values like `'1 second'`, `'Hourly'`, `'Yearly'`. This is a - string-typed enum. Compare F1.3. -- **Suggestion:** Introduce a string-literal union type - `ForecastGranularity = '1 second' | '1 minute' | … | 'Yearly'`, - or document acceptable strings in JSDoc more rigorously. - -#### F16.3 — `customWeightsColumn: string` (acceptable) -- Column name field with `string` type. Domain matches. - ---- - -### 17. Inconsistent action verbs - -#### F17.1 — `Get` vs `Create` (acceptable) -- Standard REST verbs. Good. - -#### F17.2 — `wait` vs `done` (LOW) -- **Where:** `client.ts:149, 194`. -- **Why flagged:** `wait()` is an action (returns when terminal); - `done()` is a query (returns bool now). Different axes — verb - and predicate. Common pattern, but the predicate name `done` - doesn't start with `is` or `has`, masking that it is a query. -- **Suggestion:** Rename `done` → `isDone` or `isTerminal`. See - F6.2 / F10.2. - -#### F17.3 — `createForecastingExperiment` vs - `createForecastingExperimentWaiter` (LOW) -- **Where:** `client.ts:68, 99`. -- **Why flagged:** Both start with `create`. The first creates an - experiment, the second creates a waiter (which itself triggers - creation as a side effect). Verb overloaded. See F6.3. -- **Suggestion:** Rename second to `startForecastingExperiment` - or `createAndWaitForecastingExperiment`. - ---- - -### 18. Long enum values - -#### F18.1 — `ForecastingExperiment_State` members (acceptable) -- **Where:** `model.ts:8-16`. -- **Why flagged:** Members are `PENDING`, `RUNNING`, `SUCCEEDED`, - `FAILED`, `CANCELLED`. Range 6-9 characters. Concise. -- **Suggestion:** None. - ---- - -### 19. Underspecified IDs - -#### F19.1 — `experimentId` (acceptable in this package) -- **Where:** `model.ts:68, 74, 83`. -- **Why flagged:** `experimentId` is the only ID in this package - and is consistent. Inside a `forecasting` package the term - "experiment" implies a forecasting experiment. **However**, the - MLflow `experiments` API also issues experiment IDs and has - type `Experiment`/`experimentId`. Cross-package confusion is - possible if both clients are in use. -- **Suggestion:** Acceptable as-is. If renamed in the future, a - domain qualifier such as `forecastingExperimentId` resolves the - ambiguity at the cost of verbosity. - -#### F19.2 — `experimentPath` (LOW) -- **Where:** `model.ts:38`. -- **Why flagged:** Workspace path. Unambiguous in context, but - competes for "experiment" mindshare with `experimentId`. - Marginal. -- **Suggestion:** Keep. - ---- - -### 20. Type-suffix tautology - -#### F20.1 — `ForecastingExperiment_State` enum + `state` field on - `ForecastingExperiment` (LOW) -- **Where:** `model.ts:6, 78`. -- **Why flagged:** Three layers of "Forecasting" / "Experiment" / - "State": `ForecastingExperiment.state: - ForecastingExperiment_State`. With underscore removal and - `Forecasting`-prefix drop, becomes - `Experiment.state: ExperimentState`. Tolerable. -- **Suggestion:** Tie to F4.1 / F7.1. - --- ## Package overlap: `forecasting` vs `experiments` @@ -764,7 +296,7 @@ generic experiment but uses the same term and the same ID name. *long-running training job* tracked by AutoML; the MLflow experiment is a *grouping* of runs. Semantically very different. - **Suggestion:** Keep `ForecastingExperiment` (do not drop the - qualifier from the type, despite F7.1 above) to maintain + qualifier from the type, despite F5.1 above) to maintain disambiguation. Or, namespace this package's types under `forecasting.Experiment` if the package adopts nested exports. @@ -781,68 +313,50 @@ generic experiment but uses the same term and the same ID name. | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Vague / generic | 5 (1 acceptable note) | -| 2 | Redundant enum prefixes | 1 (acceptable) | -| 3 | Acronym casing | 4 (2 acceptable) | -| 4 | Underscores in TS identifiers | 2 | -| 5 | Cryptic abbreviations | 9 | -| 6 | Misleading names | 6 | -| 7 | Overly verbose | 6 | -| 8 | Redundant suffixes | 2 (1 acceptable) | -| 9 | Singular / plural mismatch | 5 (3 acceptable + 1 note) | -| 10 | Reserved-word collisions | 4 (2 acceptable) | -| 11 | Empty / trivial wrappers | 1 | -| 12 | Duplicate concepts | 4 | -| 13 | Verb-tense inconsistency | 2 (2 acceptable) | -| 14 | Go / Java-style names | 4 | -| 15 | Generic field names | 6 | -| 16 | Field contradicting type domain | 3 (1 acceptable) | -| 17 | Inconsistent action verbs | 3 (1 acceptable) | -| 18 | Long enum values | 1 (acceptable) | -| 19 | Underspecified IDs | 2 (1 acceptable) | -| 20 | Type-suffix tautology | 1 | +| 1 | Vague / generic | 3 (1 acceptable note) | +| 2 | Redundant enum prefixes | 0 | +| 3 | Acronym casing | 0 | +| 4 | Misleading names | 2 | +| 5 | Overly verbose | 5 | +| 6 | Go-style `Waiter` pattern | 1 | +| 7 | Reserved-word collisions | 1 | +| 8 | Generic field names | 3 | +| 9 | Untyped string for closed enum | 1 | +| 10 | `*Path` fields contradicting domain | 1 | | OVERLAP | forecasting vs experiments | 2 | --- -## Top 10 highest-impact renames (recommended order) +## Top renames (recommended order) -1. **F4.1 / F14.2:** Replace underscored `ForecastingExperiment_State` - with flat PascalCase `ForecastingExperimentState` or - namespace nesting. Eliminates the `eslint-disable` comment. -2. **F6.3 / F7.4 / F17.3:** Rename +1. **F4.2 / F5.4:** Rename `createForecastingExperimentWaiter` to `startForecastingExperiment` (or `createAndWait…`) to remove the "create" verb overload. Rename `CreateForecastingExperimentWaiter` - class to `ForecastingExperimentRun` or `…Operation` (F7.3 / F8.2). -3. **F6.2 / F10.2 / F17.2:** Rename waiter `done()` method to + class to `ForecastingExperimentRun` or `…Operation` (F5.3 / F6.1). +2. **F4.1 / F7.1:** Rename waiter `done()` method to `isTerminal()` (or `isDone()`) to signal that it is a server-poll predicate, not iterator state. -4. **F16.1:** Rename `*Path` fields that hold Unity Catalog +3. **F10.1:** Rename `*Path` fields that hold Unity Catalog three-part names to `*Table` (e.g. `trainDataPath → trainingDataTable`, `predictionDataPath → predictionsTable`, `futureFeatureDataPath → futureFeaturesTable`). Distinguishes them from `experimentPath` which is a real workspace path. -5. **F15.4:** Rename `registerTo` to +4. **F8.2:** Rename `registerTo` to `registeredModelName` (or `modelRegistrationTarget`). The verb-phrase field name is confusing. -6. **F15.5:** Rename `maxRuntime` → `maxRuntimeMinutes` to embed +5. **F8.3:** Rename `maxRuntime` → `maxRuntimeMinutes` to embed units in the name. -7. **F1.3 / F16.2:** Introduce string-literal union types for +6. **F1.2 / F9.1:** Introduce string-literal union types for `primaryMetric` and `forecastGranularity`. Improves discoverability and type safety. -8. **F6.1:** Align waiter local variable name (`status`) with the - field it reads (`state`). Update error message wording. -9. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ - `pkgJson`/`msg`/`pollResp`/`httpReq`/`apiErr` across all - generated code. -10. **F7.1 / F7.2:** Drop the redundant `Forecasting` token from - type names where the package qualifier already conveys domain - (`ForecastingExperiment` → `Experiment`, - `CreateForecastingExperimentRequest` → `CreateExperimentRequest`, - etc.) — subject to the cross-package conflict noted in - F-OVERLAP.1. +7. **F5.1 / F5.2:** Drop the redundant `Forecasting` token from + type names where the package qualifier already conveys domain + (`ForecastingExperiment` → `Experiment`, + `CreateForecastingExperimentRequest` → `CreateExperimentRequest`, + etc.) — subject to the cross-package conflict noted in + F-OVERLAP.1. --- @@ -854,7 +368,3 @@ generic experiment but uses the same term and the same ID name. spec. This audit is a backlog for that generator. - This package has no `tests/` directory (verified by repo structure check), so the audit does not cover test naming. -- The `flattenQueryParams` helper in `utils.ts` is exported but - never used in this package — see F6.5. -- The JSDoc on `splitColumn` (`model.ts:41`) has a stray `//` - prefix from the source — generator bug, see F4.2. diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index 3d6fcc88..cec83118 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -14,13 +14,10 @@ The `functions` package surfaces five UC function operations the Go SDK 1:1, so most issues are inherited from the upstream definitions. The most pervasive problems are: (1) the package-level name itself — `functions` and the field/type `function` collide with -JavaScript's `function` reserved word; (2) proto-style nested -identifiers (`FunctionInfo_RoutineBody`, `FunctionInfo_SqlDataAccess`, -`FunctionInfo_SecurityType`, `FunctionInfo_ParameterStyle`, -`DeleteFunction_Response`, `ListFunctions_Response`); (3) the cryptic -`fullNameArg` path-parameter field; and (4) widespread -`type*` and `parameter*` field prefixes that re-encode the parent -type's domain. +JavaScript's `function` reserved word; (2) cryptic single-letter enum +variants (`S`, `IN`, `DEFINER`); (3) the cryptic `fullNameArg` +path-parameter field; and (4) widespread `type*` and `parameter*` +field prefixes that re-encode the parent type's domain. --- @@ -67,32 +64,12 @@ field says `**S** is the value for SQL.` So `S` is *the* SQL parameter style. The single-letter variant is cryptic; even if it preserves wire compatibility, the TypeScript surface should expose `SQL` (and let the marshal layer translate to `S` on the wire). -See also §5.1. +See also §4.1. -#### 2.3 `FunctionInfo_RoutineBody` values `SQL` / `EXTERNAL` (model.ts:49-59) -Variants are short and meaningful. `EXTERNAL` is the longer arm and -the description on `EXTERNAL` is multi-bullet. Variants OK; the -nested enum type-name is the issue — see §4.1. - -#### 2.4 `FunctionInfo_SecurityType.DEFINER` (model.ts:61-64) +#### 2.3 `FunctionInfo_SecurityType.DEFINER` (model.ts:61-64) Single-variant enum with `DEFINER`. The single-valued switch is surfaced as a full enum type; the variant itself is meaningful (SQL -`SECURITY DEFINER` clause) but the TS-side ergonomics suffer from -the long nested enum name. - -#### 2.5 `FunctionInfo_SqlDataAccess` values `CONTAINS_SQL` / `READS_SQL_DATA` / `NO_SQL` (model.ts:66-71) -The enum name contains `SqlDataAccess` and every variant begins or -ends with `SQL`. Two of three variants repeat the `SQL` token from -the parent: `CONTAINS_SQL`, `READS_SQL_DATA`, `NO_SQL`. The repetition -is mild compared to the catalogs `DR_REPLICATION_STATUS_*` case, but -the type already says "SQL" — variants `CONTAINS`, `READS_DATA`, -`NONE` would be just as clear. - -#### 2.6 `ColumnTypeName` variants suffixed `_TYPE` (model.ts:31, 32) -`USER_DEFINED_TYPE`, `TABLE_TYPE`, `TABLEREF_TYPE`. The enum is -`ColumnTypeName` — `_TYPE` is redundant on each variant. Should be -`USER_DEFINED`, `TABLE`, `TABLEREF`. Note: see also §3.5 for -`TABLEREF`. +`SECURITY DEFINER` clause) but the TS-side ergonomics suffer. --- @@ -119,20 +96,14 @@ Field name `typeText`. Doc says "Full data type spec, SQL/catalogString text." OK as a name but ambiguous: is it SQL-formatted, JSON-formatted, or arbitrary? -#### 3.5 `TABLEREF_TYPE` enum variant (model.ts:32) -"TABLEREF" runs two words together — "Table Ref" / "Table Reference". -Should be `TABLE_REF` (or `TABLE_REFERENCE`, spelled out). The -codebase already uses underscores between words elsewhere -(`USER_DEFINED_TYPE`). See also §2.6. - -#### 3.6 `TIMESTAMP_NTZ` enum variant (model.ts:25) +#### 3.5 `TIMESTAMP_NTZ` enum variant (model.ts:25) `NTZ` is "No TimeZone". Three-letter acronym, kept uppercase here which is consistent with `SQL` elsewhere. OK, but the meaning is opaque to anyone unfamiliar with the Spark/Delta type system. The ColumnTypeName enum has no JSDoc comments to explain `NTZ`, -`TABLEREF_TYPE`, `USER_DEFINED_TYPE`, `VARIANT`, etc. +`USER_DEFINED_TYPE`, `VARIANT`, etc. -#### 3.7 "UDF" / "UDTF" never appear in identifiers +#### 3.6 "UDF" / "UDTF" never appear in identifiers The package is *Unity Catalog Functions* — it covers both UDFs and UDTFs (table-valued functions). Neither acronym appears in any identifier or doc comment. The distinction is encoded in the @@ -142,87 +113,56 @@ flagging. --- -### 4. Underscores in TypeScript identifiers - -This is the package's most widespread cosmetic issue. Proto-style -underscore separators appear in exported TS identifiers, each -silenced by a `@typescript-eslint/naming-convention -- Proto-style …` -disable comment. - -#### 4.1 `FunctionInfo_ParameterStyle` (model.ts:45) -Should be `FunctionParameterStyle` (or `ParameterStyle`, top-level). - -#### 4.2 `FunctionInfo_RoutineBody` (model.ts:50) -Should be `RoutineBody` or `FunctionRoutineBody`. - -#### 4.3 `FunctionInfo_SecurityType` (model.ts:62) -Should be `FunctionSecurityType` (or `SecurityType`). Note: the -catalogs and other packages also have `SecurityType`-flavoured enums; -disambiguation may need `FunctionSecurityType`. - -#### 4.4 `FunctionInfo_SqlDataAccess` (model.ts:67) -Should be `FunctionSqlDataAccess` or `SqlDataAccess` (top-level). - -#### 4.5 `DeleteFunction_Response` (model.ts:161) -Should be `DeleteFunctionResponse`. The underscore separator is the -naming issue here; the wrapper itself exists for forward -compatibility. +### 4. Cryptic abbreviations -#### 4.6 `ListFunctions_Response` (model.ts:319) -Should be `ListFunctionsResponse`. - -#### 4.7 `unmarshalDeleteFunction_ResponseSchema` / -`unmarshalListFunctions_ResponseSchema` (model.ts:431, 592) -Underscore leaks into schema exports. Should be -`unmarshalDeleteFunctionResponseSchema`, -`unmarshalListFunctionsResponseSchema`. - ---- - -### 5. Cryptic abbreviations - -#### 5.1 `FunctionInfo_ParameterStyle.S` (model.ts:46) +#### 4.1 `FunctionInfo_ParameterStyle.S` (model.ts:46) A bare letter `S` whose only documented purpose is "the value for SQL". Cryptic — preserve wire compatibility in the marshal layer and expose `SQL` as the TS variant. See also §2.2. -#### 5.2 `fullNameArg` (model.ts:155, 294, 343) +#### 4.2 `FunctionParameterMode.IN` (model.ts:35-37) +Bare two-letter variant `IN`. Comes from SQL's `IN`/`OUT`/`INOUT` +parameter modes; without that context, the variant is cryptic. A +consumer reading `parameterMode === FunctionParameterMode.IN` cannot +intuit "input parameter" without prior SQL exposure. + +#### 4.3 `fullNameArg` (model.ts:155, 294, 343) Used as the function name path-parameter on `DeleteFunction`, `GetFunction`, and `UpdateFunction`. The `Arg` suffix is jargon from the Go generator distinguishing path arguments from request-body fields with the same key. TypeScript callers have no need for this distinction — the field is the function's fully-qualified name. See -also §13.1 and §11.3. +also §10.1 and §9.3. -#### 5.3 `pkgJson` (client.ts:19) +#### 4.4 `pkgJson` (client.ts:19) Internal variable name for `package.json`. Mild — flagged for consistency with other audits. -#### 5.4 `respBody` (client.ts:89, 126, 164, 217, 267) — internal-only; mild. +#### 4.5 `respBody` (client.ts:89, 126, 164, 217, 267) — internal-only; mild. -#### 5.5 `typeText` / `typeJson` (model.ts:265, 267) +#### 4.6 `typeText` / `typeJson` (model.ts:265, 267) The `type*` prefix is fine within `FunctionParameterInfo`, but the field names (`typeText`, `typeJson`, `typeName`, `typePrecision`, `typeScale`, `typeIntervalType`) form a non-obvious "type-spec" sub-record that arguably should be nested under a `type` object. -See also §12.4. +See also §10.4. --- -### 6. Misleading names +### 5. Misleading names -#### 6.1 `routineDependencies` doc comment lowercases "function" (model.ts:122, 241, 386) +#### 5.1 `routineDependencies` doc comment lowercases "function" (model.ts:122, 241, 386) JSDoc reads "function dependencies." (lowercase, mid-sentence). The field name is `routineDependencies` and the doc says "function". The package toggles between "routine" and "function" terminology -indiscriminately — see §6.3. +indiscriminately — see §5.3. -#### 6.2 `DeleteFunction.force` doc has typo "notempty" (model.ts:156) +#### 5.2 `DeleteFunction.force` doc has typo "notempty" (model.ts:156) "Force deletion even if the function is notempty." Should be "not empty". Doc bug, not a naming bug, but signals the field hasn't been read recently. See also §1.1. -#### 6.3 "Function" vs "Routine" terminology mixed everywhere +#### 5.3 "Function" vs "Routine" terminology mixed everywhere Every type and method speaks of `function*`. But every body-related field speaks of `routine*`: `routineBody`, `routineDefinition`, `routineDependencies`. The enum is `FunctionInfo_RoutineBody`. A @@ -230,9 +170,9 @@ function's *body* is a *routine*. This split is a Go-port artifact of the SQL standard's vocabulary (`CREATE PROCEDURE … LANGUAGE SQL ROUTINE_BODY …`) — but for a TS consumer the inconsistency is jarring. `body`, `definition`, `dependencies` (dropping `routine`) -would be cleaner. See also §6.1. +would be cleaner. See also §5.1. -#### 6.4 `parameterDefault: string` (model.ts:283) +#### 5.4 `parameterDefault: string` (model.ts:283) Doc: "Default value of the parameter." The default of a function parameter is rarely a string in the source domain — it might be a number, a boolean, an interval, or even `NULL`. Typing it as `string` @@ -240,12 +180,12 @@ implies serialised form, but the field name `parameterDefault` doesn't signal that. Consider `parameterDefaultExpression` or `parameterDefaultText`. -#### 6.5 `specificName` reserved-for-future-use (model.ts:107, 226, 371) +#### 5.5 `specificName` reserved-for-future-use (model.ts:107, 226, 371) Doc: "Specific name of the function; Reserved for future use." A field whose name promises specificity and whose docs admit it's unused is a future trap. Better to omit until it does something. -#### 6.6 `inputParams` / `returnParams` use `Params` but the type uses `ParameterInfos` +#### 5.6 `inputParams` / `returnParams` use `Params` but the type uses `ParameterInfos` (model.ts:87, 109, 206, 228, 351, 373) The field abbreviates to `Params`; the type is `FunctionParameterInfos` (no abbreviation). Pick one — abbreviate both (`Params` / @@ -254,9 +194,9 @@ The field abbreviates to `Params`; the type is `FunctionParameterInfos` --- -### 7. Reserved-word collisions +### 6. Reserved-word collisions -#### 7.1 `Function` / `function` — the entire package name collides with a JS reserved word +#### 6.1 `Function` / `function` — the entire package name collides with a JS reserved word (model.ts and across the file) `function` is a JavaScript reserved keyword @@ -287,32 +227,30 @@ adjacent to TS keyword highlighting in their editor. Consider renaming the union arm to `functionRef`, `functionDependency`, or nesting via a different discriminator. -#### 7.2 `FunctionDependency` shadows `Function` constructor +#### 6.2 `FunctionDependency` shadows `Function` constructor The exported type `FunctionDependency` is fine on its own, but in contexts where the SDK consumer also has `Function` (the global constructor) in scope, the `Function*` prefix on multiple types is crowded. -#### 7.3 Type `FunctionInfo` is exported alongside the global `Function` +#### 6.3 Type `FunctionInfo` is exported alongside the global `Function` (model.ts:198, index.ts:25) `FunctionInfo`, `CreateFunction`, `DeleteFunction`, `GetFunction`, `ListFunctions`, `UpdateFunction`, `FunctionParameterInfo`, `FunctionParameterInfos`, `FunctionDependency`, -`FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, -`FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess`, -`FunctionParameterMode`, `FunctionParameterType` — fifteen exports +`FunctionParameterMode`, `FunctionParameterType` — many exports prefixed with `Function`. While none conflict at the language level, the prefix is so heavy that the global `Function` is easily shadowed by the local imports. -#### 7.4 `name` field +#### 6.4 `name` field `name` is used as a body field on `CreateFunction`, `UpdateFunction`, `FunctionInfo`, `FunctionParameterInfo` (model.ts:81, 200, 263, 345), and again indirectly via `fullNameArg`. Not a reserved word but shadows `Function.prototype.name` — common source of confusion when callers spread request objects. -#### 7.5 `options` parameter on every client method +#### 6.5 `options` parameter on every client method (client.ts:79, 111, 149, 190, 232, 257) — the second parameter is named `options` and shadows the marshal schema's `options`-style metadata patterns. Not a collision in this package specifically but @@ -320,9 +258,9 @@ consistent with the catalogs audit (§10.1). --- -### 8. Duplicate concepts +### 7. Duplicate concepts -#### 8.1 `CreateFunction`, `UpdateFunction`, and `FunctionInfo` share ~28 fields verbatim +#### 7.1 `CreateFunction`, `UpdateFunction`, and `FunctionInfo` share ~28 fields verbatim (model.ts:79-140, 198-259, 341-404) Three types with almost-identical shapes and identical doc strings. Generator artifact, but means any rename of, say, `routineBody`, @@ -331,15 +269,15 @@ must happen three times — and the divergences between Create / Update `UpdateFunction` on `Partial` (or a shared base interface). -#### 8.2 `fullName` vs `catalogName` + `schemaName` + `name` (model.ts:81-85, 127, 200-204, 246, 345-349, 391) +#### 7.2 `fullName` vs `catalogName` + `schemaName` + `name` (model.ts:81-85, 127, 200-204, 246, 345-349, 391) A `FunctionInfo` has all four: a top-level `name` (relative to schema), parent `catalogName` and `schemaName`, and `fullName` (the concatenation). Three pieces of data; four fields. A caller setting one and not the others leaves the type in an inconsistent state, and there's no documentation on which is authoritative on -`Create*` / `Update*`. See also §13.4. +`Create*` / `Update*`. See also §10.4. -#### 8.3 `dataType` vs `fullDataType` (model.ts:89-91, 208-210, 353-355) +#### 7.3 `dataType` vs `fullDataType` (model.ts:89-91, 208-210, 353-355) - `dataType: ColumnTypeName` — the enum form. - `fullDataType: string` — "Pretty printed function data type." @@ -347,48 +285,34 @@ The pretty-printed form is presumably a function of the enum plus any precision/scale/interval. Two fields encoding the same datum in two representations. -#### 8.4 `name` vs `fullNameArg` on `UpdateFunction` +#### 7.4 `name` vs `fullNameArg` on `UpdateFunction` `UpdateFunction` has *both* `fullNameArg` (the existing function identifier, used in the URL path) and `name` (the new desired name -of the function, used in the body). See §13.1. - -#### 8.5 `routineBody` enum constant `EXTERNAL` documented in three identical places -(model.ts:52-58, 92, 211, 356) -The `EXTERNAL` variant's full multi-bullet documentation appears on -the enum declaration, then a paraphrased version repeats on -`CreateFunction.routineBody`, `FunctionInfo.routineBody`, and -`UpdateFunction.routineBody`. Doc duplication is a generator -artefact, but it inflates the cognitive load of reading the model. +of the function, used in the body). See §10.1. --- -### 9. Verb-tense inconsistency +### 8. Verb-tense inconsistency -#### 9.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`. No tense issues. +#### 8.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`. No tense issues. -#### 9.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65), `buildHttpRequest`, `flattenQueryParams` (utils.ts:96, 123) — all imperative present, consistent. +#### 8.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65), `buildHttpRequest`, `flattenQueryParams` (utils.ts:96, 123) — all imperative present, consistent. No verb-tense inconsistencies found across the package. --- -### 10. Go / Java-style names +### 9. Go / Java-style names -#### 10.1 `FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, `FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess` -(model.ts:45, 50, 62, 67) -Proto nested-enum naming `Parent_Child`. TS should use top-level -identifiers: `FunctionParameterStyle`, `RoutineBody`, -`FunctionSecurityType`, `SqlDataAccess`. See §4.1-4.4. - -#### 10.2 `Client` class name (client.ts:44) +#### 9.1 `Client` class name (client.ts:44) Bare `Client` (rather than `FunctionsClient`) is a Go idiom: package qualifies the type. JS consumers commonly import as `import {Client} from '@databricks/sdk-functions/v1'` and have to alias. Package-wide convention; flagged for consistency. -#### 10.3 `fullNameArg` (model.ts:155, 294, 343) — Go generator naming. See §5.2. +#### 9.2 `fullNameArg` (model.ts:155, 294, 343) — Go generator naming. See §4.3. -#### 10.4 `Dependency.value.$case` discriminated union encoding (model.ts:168-184) +#### 9.3 `Dependency.value.$case` discriminated union encoding (model.ts:168-184) The `$case` discriminator with `value`-keyed payload is a ts-proto serialiser idiom. TS-native discriminated unions usually keep the discriminator at the top level (`{type: 'function', function: {…}}`) @@ -396,30 +320,30 @@ rather than wrapping in `value`. Functional, but visibly Go/proto. --- -### 11. Generic field names losing meaning +### 10. Generic field names losing meaning -#### 11.1 `name` is used twelve+ times across the model +#### 10.1 `name` is used twelve+ times across the model (model.ts:81, 84, 86 within docs, 200, 203, 263, 345, 348, etc.) The semantics shift: function name, parameter name, catalog name, schema name, etc. — but the field is consistently `name`. Combined with `fullName`, `fullNameArg`, `functionFullName`, `tableFullName`, `secretFullName`, `volumeFullName`, `externalName`, `specificName`, -the surface area of "name" fields is huge. See also §8.2. +the surface area of "name" fields is huge. See also §7.2. -#### 11.2 `properties` (model.ts:121, 240, 385) +#### 10.2 `properties` (model.ts:121, 240, 385) "JSON-serialized key-value pair map, encoded (escaped) as a string." The field is `string`, despite the name promising a structured map. A consumer reading the type sees `properties?: string` and has to manually `JSON.parse`. Either name it `propertiesJson` or type it as `Record` with marshal-layer translation. -#### 11.3 `comment` (model.ts:119, 238, 285, 383) — see §1.3. +#### 10.3 `comment` (model.ts:119, 238, 285, 383) — see §1.3. --- -### 12. Field contradicting type domain +### 11. Field contradicting type domain -#### 12.1 `UpdateFunction` has `fullNameArg` *and* `name` (model.ts:343, 345) +#### 11.1 `UpdateFunction` has `fullNameArg` *and* `name` (model.ts:343, 345) - `fullNameArg` — the existing function's fully-qualified identifier (path param). - `name` — the function name, body field (the new desired name?). @@ -429,18 +353,18 @@ combination, or whether `name` is the *new* name or the *current* name (the catalogs package answers this question differently with `newName` — but `functions` lacks `newName` entirely, leaving the caller without a renaming primitive at all, or with an ambiguous -`name` field). See also §8.4. +`name` field). See also §7.4. -#### 12.2 `CreateFunction` contains read-only output fields +#### 11.2 `CreateFunction` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `functionId`, `browseOnly` (model.ts:129-139). These are server-populated; a creator setting them is at best ignored. The type's domain is "create request" but its shape contradicts that. Mirror issue in `UpdateFunction` (model.ts:393-403). -#### 12.3 `DeleteFunction.fullNameArg` — see §5.2. +#### 11.3 `DeleteFunction.fullNameArg` — see §4.3. -#### 12.4 `FunctionInfo.fullName` vs `name` / `catalogName` / `schemaName` +#### 11.4 `FunctionInfo.fullName` vs `name` / `catalogName` / `schemaName` (model.ts:200-204, 246) On `FunctionInfo`, all four are present; for *catalogs* a `fullName` is redundant with `name`, but for *functions* `fullName` is @@ -448,7 +372,7 @@ is redundant with `name`, but for *functions* `fullName` is underscores them as if they're literal placeholders. The naming is acceptable but the redundancy invites inconsistent state. -#### 12.5 `FunctionParameterInfo.parameterType: FunctionParameterType` where `PARAM` is one of two variants +#### 11.5 `FunctionParameterInfo.parameterType: FunctionParameterType` where `PARAM` is one of two variants (model.ts:281) The field is on a "parameter info" object and one of its variants is `PARAM`. So a `FunctionParameterInfo` may have @@ -459,7 +383,7 @@ also §2.1. --- -### 13. Inconsistent action verbs +### 12. Inconsistent action verbs Method verbs in `Client`: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`. Verbs are @@ -468,42 +392,28 @@ outliers. No issues found. --- -### 14. Long enum values - -#### 14.1 `ColumnTypeName.USER_DEFINED_TYPE` (model.ts:24) — 17 characters. See §2.6. - -#### 14.2 `ColumnTypeName.TABLEREF_TYPE` (model.ts:32) — 13 characters. See §2.6, §3.5. - -#### 14.3 `ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25) — 13 characters. See §3.6. - -#### 14.4 `FunctionInfo_SqlDataAccess.READS_SQL_DATA` (model.ts:69) — 14 characters. See §2.5. - -#### 14.5 No `*_UNSPECIFIED` enum values present in this package — positive observation versus catalogs. - ---- - -### 15. Underspecified IDs +### 13. Underspecified IDs -#### 15.1 `metastoreId` (model.ts:125, 244, 389) +#### 13.1 `metastoreId` (model.ts:125, 244, 389) Documented as "Unique identifier of parent metastore." Format opaque (UUID? slug?). Acceptable but unspecified. -#### 15.2 `functionId` (model.ts:137, 256, 401) +#### 13.2 `functionId` (model.ts:137, 256, 401) Doc: "Id of Function, relative to parent schema." Format unspecified — is this a UUID, an autoincrement integer, an opaque token? Type is `string` so opaque, but the docs should say so. -#### 15.3 `metastoreId` & `functionId` — distinct domains, same shape +#### 13.3 `metastoreId` & `functionId` — distinct domains, same shape Both `string`, both undocumented for format, both server-assigned. A consumer cannot tell them apart from the types. -#### 15.4 `createdAt` / `updatedAt` (model.ts:129, 133, 248, 252, 393, 397) +#### 13.4 `createdAt` / `updatedAt` (model.ts:129, 133, 248, 252, 393, 397) Type is `number` (epoch milliseconds per the doc). The field name doesn't convey unit. `createdAtMs` / `updatedAtMs` or `createdAtEpochMs` would be more honest. The catalogs audit flagged the same inconsistency. -#### 15.5 `connectionName` (model.ts:76) — "Full name of the dependent connection, in the form of __connection_name__." +#### 13.5 `connectionName` (model.ts:76) — "Full name of the dependent connection, in the form of __connection_name__." The field is named `connectionName` but the doc says it should be a "full name". For other dependency types, the field is explicitly named `*FullName` (e.g. `secretFullName`, `tableFullName`). Naming @@ -512,34 +422,22 @@ inconsistency: ConnectionDependency and CredentialDependency --- -### 16. Type-suffix tautology +### 14. Type-suffix tautology -#### 16.1 `ColumnTypeName` enum with field `typeName: ColumnTypeName` +#### 14.1 `ColumnTypeName` enum with field `typeName: ColumnTypeName` (model.ts:5, 269) — field name conflates "type name" with the enum type. Reading `parameter.typeName === ColumnTypeName.INT` is doubly type-y. Either shorten the field (`type: ColumnTypeName`) or rename the enum (`ColumnType`). -#### 16.2 `FunctionParameterMode` enum with field `parameterMode: FunctionParameterMode` +#### 14.2 `FunctionParameterMode` enum with field `parameterMode: FunctionParameterMode` (model.ts:35, 279) — field-name tautological with type-name. -#### 16.3 `FunctionParameterType` enum with field `parameterType: FunctionParameterType` +#### 14.3 `FunctionParameterType` enum with field `parameterType: FunctionParameterType` (model.ts:39, 281) — field-name tautological with type-name. Also -suffers from §12.5 (a "parameter type" that admits "PARAM" as a +suffers from §11.5 (a "parameter type" that admits "PARAM" as a variant). -#### 16.4 `FunctionInfo_ParameterStyle` enum with field `parameterStyle: FunctionInfo_ParameterStyle` -(model.ts:45, 97, 216, 361) — field-name tautological with type-name. - -#### 16.5 `FunctionInfo_RoutineBody` enum with field `routineBody: FunctionInfo_RoutineBody` -(model.ts:50, 93, 212, 357) — field-name tautological with type-name. - -#### 16.6 `FunctionInfo_SecurityType` enum with field `securityType: FunctionInfo_SecurityType` -(model.ts:62, 105, 224, 369) — same. - -#### 16.7 `FunctionInfo_SqlDataAccess` enum with field `sqlDataAccess: FunctionInfo_SqlDataAccess` -(model.ts:67, 101, 220, 365) — same. - --- ## Additional / cross-cutting observations @@ -571,15 +469,7 @@ the bug hide. "Host is required." — bare `Error`. Not a naming issue, flagged for consistency with the catalogs audit. -### E. `index.ts` re-exports proto-style names verbatim -(index.ts:9-12, 21) — every underscore-bearing identifier surfaces -in the package's public API. A consumer of `@databricks/sdk-functions/v1` -sees `FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, -`FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess`, -`DeleteFunction_Response`, `ListFunctions_Response` as first-class -exports. - -### F. Package-name collision with JavaScript reserved word +### E. Package-name collision with JavaScript reserved word The package is named `@databricks/sdk-functions` and the npm workspace path is `packages/functions/`. `function` is a JS reserved word; `functions` is not, but the proximity is jarring. Importers @@ -587,19 +477,19 @@ will often write `import * as functions from '@databricks/sdk-functions/v1'` which sets up `functions.createFunction(…)` — the local binding `functions` shadows nothing, but the `Dependency.value.$case === 'function'` -pattern (§7.1) combined with the package name creates a vocabulary +pattern (§6.1) combined with the package name creates a vocabulary where "function" is overloaded. -### G. `FunctionInfo.routineDependencies` is described as "function dependencies." +### F. `FunctionInfo.routineDependencies` is described as "function dependencies." (model.ts:122, 241, 386) Comment text starts with lowercase and uses "function" instead of "routine"; field name uses "routine". See -§6.1 and §6.3. +§5.1 and §5.3. -### H. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` +### G. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` The most extreme case of a single-purpose API surface: a long enum type holding a one-letter variant, only ever set to `S`, marshaled as the JSON string `"S"`. Three layers of indirection for a constant. -See §2.2, §5.1. +See §2.2, §4.1. --- @@ -607,65 +497,54 @@ See §2.2, §5.1. | Identifier | Location | Finding | | -------------------------------------------------------- | --------------------- | ------- | -| `ColumnTypeName` | model.ts:5 | 2.6, 3.5, 3.6, 14.1-14.3, 16.1 | -| `ColumnTypeName.USER_DEFINED_TYPE` | model.ts:24 | 2.6, 14.1 | -| `ColumnTypeName.TIMESTAMP_NTZ` | model.ts:25 | 3.6, 14.3 | -| `ColumnTypeName.TABLE_TYPE` | model.ts:31 | 2.6 | -| `ColumnTypeName.TABLEREF_TYPE` | model.ts:32 | 2.6, 3.5, 14.2 | -| `FunctionParameterMode` | model.ts:35 | 16.2 | -| `FunctionParameterType` | model.ts:39 | 2.1, 12.5, 16.3 | -| `FunctionInfo_ParameterStyle` | model.ts:45 | 2.2, 4.1, 5.1, 10.1, 16.4 | -| `FunctionInfo_ParameterStyle.S` | model.ts:46 | 2.2, 5.1 | -| `FunctionInfo_RoutineBody` | model.ts:50 | 4.2, 8.5, 10.1, 16.5 | -| `FunctionInfo_RoutineBody.EXTERNAL` | model.ts:58 | 8.5 | -| `FunctionInfo_SecurityType` | model.ts:62 | 2.4, 4.3, 10.1, 16.6 | -| `FunctionInfo_SqlDataAccess` | model.ts:67 | 2.5, 3.1, 4.4, 10.1, 14.4, 16.7 | -| `ConnectionDependency.connectionName` | model.ts:76 | 15.5 | -| `CreateFunction` | model.ts:79 | 8.1, 12.2 | -| `CreateFunction.routineBody/routineDefinition/routineDependencies` | model.ts:93/95/123 | 6.3 | -| `CreateFunction.specificName` | model.ts:107 | 6.5 | -| `CreateFunction.fullName` | model.ts:127 | 8.2, 12.4 | -| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:125-139 | 12.2, 15.1, 15.2, 15.4 | -| `DeleteFunction.fullNameArg` | model.ts:155 | 5.2, 10.3, 12.3 | -| `DeleteFunction.force` | model.ts:157 | 1.1, 6.2 | -| `DeleteFunction_Response` | model.ts:161 | 4.5 | -| `Dependency.value.function` arm | model.ts:170 | 7.1 | -| `Dependency.value.$case` | model.ts:168 | 10.4 | -| `FunctionDependency` | model.ts:193 | 7.2 | -| `FunctionInfo` | model.ts:198 | 7.3, 8.1 | -| `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:212/214/242 | 6.3 | -| `FunctionInfo.specificName` | model.ts:226 | 6.5 | -| `FunctionInfo.properties` | model.ts:240 | 11.2 | -| `FunctionInfo.fullName` | model.ts:246 | 8.2, 12.4 | -| `FunctionInfo.functionId` | model.ts:256 | 15.2, 15.3 | -| `FunctionParameterInfo.name` | model.ts:263 | 7.4, 11.1 | -| `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:265-269 | 3.3, 3.4, 5.5, 16.1 | +| `ColumnTypeName` | model.ts:5 | 3.5, 14.1 | +| `ColumnTypeName.TIMESTAMP_NTZ` | model.ts:25 | 3.5 | +| `FunctionParameterMode` | model.ts:35 | 4.2, 14.2 | +| `FunctionParameterMode.IN` | model.ts:35-37 | 4.2 | +| `FunctionParameterType` | model.ts:39 | 2.1, 11.5, 14.3 | +| `FunctionInfo_ParameterStyle.S` | model.ts:46 | 2.2, 4.1 | +| `FunctionInfo_SecurityType.DEFINER` | model.ts:62-64 | 2.3 | +| `FunctionInfo_SqlDataAccess` | model.ts:67 | 3.1 | +| `ConnectionDependency.connectionName` | model.ts:76 | 13.5 | +| `CreateFunction` | model.ts:79 | 7.1, 11.2 | +| `CreateFunction.routineBody/routineDefinition/routineDependencies` | model.ts:93/95/123 | 5.3 | +| `CreateFunction.specificName` | model.ts:107 | 5.5 | +| `CreateFunction.fullName` | model.ts:127 | 7.2, 11.4 | +| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:125-139 | 11.2, 13.1, 13.2, 13.4 | +| `DeleteFunction.fullNameArg` | model.ts:155 | 4.3, 9.2, 11.3 | +| `DeleteFunction.force` | model.ts:157 | 1.1, 5.2 | +| `Dependency.value.function` arm | model.ts:170 | 6.1 | +| `Dependency.value.$case` | model.ts:168 | 9.3 | +| `FunctionDependency` | model.ts:193 | 6.2 | +| `FunctionInfo` | model.ts:198 | 6.3, 7.1 | +| `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:212/214/242 | 5.3 | +| `FunctionInfo.specificName` | model.ts:226 | 5.5 | +| `FunctionInfo.properties` | model.ts:240 | 10.2 | +| `FunctionInfo.fullName` | model.ts:246 | 7.2, 11.4 | +| `FunctionInfo.functionId` | model.ts:256 | 13.2, 13.3 | +| `FunctionParameterInfo.name` | model.ts:263 | 6.4, 10.1 | +| `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:265-269 | 3.3, 3.4, 4.6, 14.1 | | `FunctionParameterInfo.position` | model.ts:277 | 1.2 | -| `FunctionParameterInfo.parameterMode / parameterType` | model.ts:279, 281 | 12.5, 16.2, 16.3 | -| `FunctionParameterInfo.parameterDefault` | model.ts:283 | 6.4 | +| `FunctionParameterInfo.parameterMode / parameterType` | model.ts:279, 281 | 11.5, 14.2, 14.3 | +| `FunctionParameterInfo.parameterDefault` | model.ts:283 | 5.4 | | `FunctionParameterInfo.comment` | model.ts:285 | 1.3 | -| `GetFunction.fullNameArg` | model.ts:294 | 5.2, 10.3 | -| `ListFunctions_Response` | model.ts:319 | 4.6 | -| `UpdateFunction` | model.ts:341 | 8.1, 8.4, 12.1, 12.2 | -| `UpdateFunction.fullNameArg / name` | model.ts:343, 345 | 5.2, 8.4, 12.1 | -| `UpdateFunction.routineBody / routineDefinition / routineDependencies` | model.ts:357/359/387 | 6.3 | -| `UpdateFunction.fullName` | model.ts:391 | 8.2, 12.4 | -| `unmarshalDeleteFunction_ResponseSchema` | model.ts:431 | 4.7 | -| `unmarshalListFunctions_ResponseSchema` | model.ts:592 | 4.7 | -| `Client` (bare name) | client.ts:44 | 10.2 | +| `GetFunction.fullNameArg` | model.ts:294 | 4.3, 9.2 | +| `UpdateFunction` | model.ts:341 | 7.1, 7.4, 11.1, 11.2 | +| `UpdateFunction.fullNameArg / name` | model.ts:343, 345 | 4.3, 7.4, 11.1 | +| `UpdateFunction.routineBody / routineDefinition / routineDependencies` | model.ts:357/359/387 | 5.3 | +| `UpdateFunction.fullName` | model.ts:391 | 7.2, 11.4 | +| `Client` (bare name) | client.ts:44 | 9.1 | | `${req.fullNameArg ?? ''}` URL substitution | client.ts:114, 152, 260 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `index.ts` re-exports | index.ts:5-35 | E | --- ## Recommended priority order -1. **Resolve the `function` reserved-word collision in `Dependency.value`** — the union arm-key `function` is the single most jarring naming hazard in the package. (§7.1) -2. **Fix `fullNameArg` / `name` confusion on `UpdateFunction`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§12.1, §5.2) -3. **Strip proto-style `Parent_Child` identifiers** (`FunctionInfo_ParameterStyle`, `FunctionInfo_RoutineBody`, `FunctionInfo_SecurityType`, `FunctionInfo_SqlDataAccess`, `DeleteFunction_Response`, `ListFunctions_Response`). (§4) -4. **Resolve "function" vs "routine" vocabulary split.** (§6.3) -5. **Strip `_TYPE` suffix from `ColumnTypeName` variants and fix `TABLEREF_TYPE` underscore.** (§2.6, §3.5) -6. **Strip read-only fields from `CreateFunction` / `UpdateFunction`.** (§12.2) -7. **Unify `*Name` vs `*FullName` field-naming on `*Dependency` types.** (§15.5) -8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +1. **Resolve the `function` reserved-word collision in `Dependency.value`** — the union arm-key `function` is the single most jarring naming hazard in the package. (§6.1) +2. **Fix `fullNameArg` / `name` confusion on `UpdateFunction`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §4.3) +3. **Resolve "function" vs "routine" vocabulary split.** (§5.3) +4. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.2, §2.3, §4.1, §4.2) +5. **Strip read-only fields from `CreateFunction` / `UpdateFunction`.** (§11.2) +6. **Unify `*Name` vs `*FullName` field-naming on `*Dependency` types.** (§13.5) +7. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index 1372aa50..c00b0677 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -3,14 +3,14 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 72 +**Total weird names flagged:** 64 ## Summary | Severity | Count | | --- | --- | -| High | 21 | -| Medium | 27 | -| Low | 19 | +| High | 17 | +| Medium | 24 | +| Low | 18 | | Observation | 5 | ## High severity @@ -45,389 +45,359 @@ - **Suggested name:** `GenieRoom`, `GenieAgent`, `GenieDeployment`, or at minimum a JSDoc on the type explaining what a "space" *is* (warehouse + datasets + instructions). If "Space" is the Databricks product-marketing term, document it inline. - **Rationale:** This is the package's central concept. Letting it stand on a single word that means "container" is a documentation gap as much as a naming bug. -### 6. `MessageStatus_MessageStatus` enum (Proto-style double name) — `src/v1/model.ts:753` -- **Why weird:** A proto-generated nested enum where the parent message and the enum share the name. Becomes `MessageStatus_MessageStatus` in TS — repeats `MessageStatus` twice. Every reference (`MessageStatus_MessageStatus.COMPLETED`, etc.) reads as the wrong name twice. -- **Category:** 4 (underscores in TS identifiers), 14 (proto-style nested name). -- **Suggested name:** `MessageStatus` (single, non-nested enum) or `MessageState`. Keep the wire format unchanged. -- **Rationale:** The doubled name is a generator artefact of proto-style nesting. A single non-nested enum reads naturally and removes the underscore. - -### 7. `MessageError_Type` enum — Proto-style nested name — `src/v1/model.ts:669` -- **Why weird:** Same pattern as #6: `MessageError_Type` is the nested-enum form. Field name is `type` (`MessageError.type`); enum is `MessageError_Type` — i.e. accessed as `MessageError_Type.FOO`. The underscore is a generator leak. -- **Category:** 4 (underscores in TS identifiers), 14 (proto-style nested name). -- **Suggested name:** `MessageErrorType` (camelcase only, drop the underscore). -- **Rationale:** Same as #6. - -### 8. `StatementStatus_State` enum — Proto-style nested name — `src/v1/model.ts:767` -- **Why weird:** Same pattern. `StatementStatus.state: StatementStatus_State`. Also: this entire family of types (`StatementResponse`, `StatementStatus`, `ResultManifest`, `Result`, `ResultData`, `ChunkInfo`, `ExternalLink`, `Schema`, `ColumnInfo`, `ColumnTypeName`, `ColumnMask`, `PolicyFunctionArgument`, `Format`, `DatabricksServiceExceptionProto`, `ErrorCode`) is *copy-pasted* from `@databricks/sdk-databricks/statementexecution`; see #9. -- **Category:** 4 (underscores), 14 (proto nesting), 12 (duplicate concept across packages). -- **Suggested name:** `StatementState`. Better: import from the statementexecution package instead of copying. -- **Rationale:** See #9 for the deeper issue. - -### 9. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-33,36-534,547-551,777-907,1610-1715` +### 6. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-33,36-534,547-551,777-907,1610-1715` - **Why weird:** 15+ types are byte-for-byte copies of types in the `statementexecution`, `sql` and `apierror` packages: `ColumnTypeName` (enum, 28 values), `ErrorCode` (enum, 80 values, with line-for-line JSDoc), `Format` (enum), `ChunkInfo`, `ColumnInfo`, `ColumnMask`, `DatabricksServiceExceptionProto`, `ExternalLink`, `ExternalLink_HttpHeadersEntry`, `PolicyFunctionArgument`, `Result`, `ResultData`, `ResultManifest`, `Schema`, `StatementResponse`, `StatementStatus`, `StatementStatus_State`. The file even copies the Google-Well-Known-Types (`Struct`, `Value`, `ListValue`, `MapStringValueEntry`, `NullValue`). -- **Category:** 12 (duplicate concept across packages), 4 (underscores, propagated through the copy). +- **Category:** 12 (duplicate concept across packages). - **Suggested name:** Import from `@databricks/sdk-databricks/statementexecution` (or wherever the originals live). If the generator can't yet cross-link, mark each duplicate `@internal` or move them to a shared internal module. - **Rationale:** A consumer who imports both `@databricks/sdk-genie` and `@databricks/sdk-sql` ends up with two structurally-identical-but-nominally-distinct `StatementResponse` types — runtime values are not assignable to each other in strict mode. This is the biggest correctness footgun in the package. -### 10. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:36-534` +### 7. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:36-534` - **Why weird:** ErrorCode is copied verbatim from the SDK's apierror codes package. Of the 80 values, comments explicitly mark ~50 as deprecated. The enum is only referenced via the copied `DatabricksServiceExceptionProto` type, which is itself unused by any Genie method (the SDK uses `APIError.fromHttpError` in `utils.ts:88`). - **Category:** 12 (duplicate concept), 18 (long enum values — `MAX_NOTEBOOK_SIZE_EXCEEDED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, `RESOURCE_DOES_NOT_EXIST`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). - **Suggested name:** Import from `@databricks/sdk-databricks/apierror/codes`. Remove the local copy. - **Rationale:** 500 lines of code (model.ts:36-534) duplicate a separate package. Maintenance hazard: deprecation removals or additions to the canonical enum will diverge silently. -### 11. `ScoreReason` enum — values mix `RESULT_*`, `LLM_JUDGE_*`, and unprefixed `EMPTY_RESULT`/`SINGLE_CELL_DIFFERENCE` — `src/v1/model.ts:593-622` +### 8. `ScoreReason` enum — values mix `RESULT_*`, `LLM_JUDGE_*`, and unprefixed `EMPTY_RESULT`/`SINGLE_CELL_DIFFERENCE` — `src/v1/model.ts:593-622` - **Why weird:** 22 values, three families: (a) plain (`EMPTY_RESULT`, `SINGLE_CELL_DIFFERENCE`, `EMPTY_GOOD_SQL`, `COLUMN_TYPE_DIFFERENCE`); (b) `RESULT_*` (`RESULT_MISSING_ROWS`, `RESULT_EXTRA_ROWS`, `RESULT_MISSING_COLUMNS`, `RESULT_EXTRA_COLUMNS`); (c) `LLM_JUDGE_*` (16 values). Six `LLM_JUDGE_*` values are deprecated and kept beside the new ones. `EMPTY_RESULT` and `EMPTY_GOOD_SQL` should both be `RESULT_*` for consistency. - **Category:** 2 (redundant enum prefixes), 18 (long enum values — `LLM_JUDGE_INSTRUCTION_COMPLIANCE_OR_MISSING_BUSINESS_LOGIC` is 60 characters), 17 (inconsistent prefix), 12 (deprecated values duplicated alongside new). - **Suggested name:** Either drop all prefixes (`EmptyResult | MissingRows | ExtraRows | …`) or apply uniformly (`RESULT_EMPTY`, `RESULT_MISSING_ROWS`, …, `JUDGE_MISSING_FILTER`, `JUDGE_INCOMPLETE_OUTPUT`, …). Separate the deprecated values into a dedicated comment block or split into two enums. - **Rationale:** Autocomplete on `ScoreReason.` returns 22 items with no visual grouping; users cannot tell at a glance which are deterministic vs which are LLM-judge. -### 12. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:669-736` +### 9. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:669-736` - **Why weird:** 60 values, almost every one ends in `_EXCEPTION` (`UNEXPECTED_REPLY_PROCESS_EXCEPTION`, `GENERIC_CHAT_COMPLETION_EXCEPTION`, `CONTEXT_EXCEEDED_EXCEPTION`, …). The few that don't are inconsistent: `STOP_PROCESS_DUE_TO_AUTO_REGENERATE`, `UNKNOWN_AI_MODEL`, `NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE`, plus `MESSAGE_ATTACHMENT_TOO_LONG_ERROR` (suffix `_ERROR` not `_EXCEPTION`), `DESCRIBE_QUERY_UNEXPECTED_FAILURE` / `DESCRIBE_QUERY_TIMEOUT` / `DESCRIBE_QUERY_INVALID_SQL_ERROR` (different verbs). The `_EXCEPTION` suffix is also Java vocabulary, not TS. -- **Category:** 2 (redundant suffix — every value already lives under `MessageError_Type`), 14 (Java-style `Exception` vocabulary in TS), 18 (long values — `INTERNAL_CATALOG_ASSET_CREATION_UNSUPPORTED_EXCEPTION` is 52 chars), 17 (inconsistent suffix). +- **Category:** 2 (redundant suffix — every value already lives under `MessageError_Type`), 14 (Java-style `Exception` vocabulary in TS), 18 (long values — `INTERNAL_CATALOG_ASSET_CREATION_UNSPECIFIED_EXCEPTION` is 52 chars), 17 (inconsistent suffix). - **Suggested name:** Drop `_EXCEPTION` from every value: `UnexpectedReplyProcess | GenericChatCompletion | ContextExceeded | …`. Pick one of `_ERROR` / `_EXCEPTION` / nothing. - **Rationale:** This enum is 67 lines long; cleaning the suffix removes 600+ characters and makes the values readable in autocomplete. -### 13. Three `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:537,547,554,561,569,584,588,595,626,633,643,660,670` +### 10. Three `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:537,547,554,561,569,584,588,595,626,633,643,660,670` - **Why weird:** 13 enums use a `XXX_UNSPECIFIED` sentinel where `XXX` is the enum's name: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `GENIE_FEEDBACK_RATING_UNSPECIFIED`, `NULL_VALUE`, `RESPONSE_PHASE_UNSPECIFIED`, `SCORE_REASON_UNSPECIFIED`, `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED`, `THOUGHT_TYPE_UNSPECIFIED`, `VERIFICATION_SECTION_UNSPECIFIED`, `TYPE_UNSPECIFIED` (inside `MessageError_Type`), `STATE_UNSPECIFIED` (inside `StatementStatus_State`). Proto2 forces this; TS does not need it because the enum's type acts as the namespace. - **Category:** 2 (redundant enum prefix), 18 (long enum values). - **Suggested name:** `Unspecified` (drop the prefix). Or omit entirely if TS-undefined can stand in for proto-unspecified. - **Rationale:** The package will get cleaner immediately; the wire string can stay the same. -### 14. `RESPONSE_PHASE_*` prefix repeated on every value — `src/v1/model.ts:588-590` +### 11. `RESPONSE_PHASE_*` prefix repeated on every value — `src/v1/model.ts:588-590` - **Why weird:** Enum `ResponsePhase` has 3 values: `RESPONSE_PHASE_UNSPECIFIED`, `RESPONSE_PHASE_THINKING`, `RESPONSE_PHASE_VERIFYING`. Every value carries the parent name. - **Category:** 2 (redundant enum prefix), 18 (long enum values). - **Suggested name:** `Unspecified | Thinking | Verifying`. -- **Rationale:** Same as #13 — autocomplete already namespaces. +- **Rationale:** Same as #10 — autocomplete already namespaces. -### 15. `THOUGHT_TYPE_*` prefix repeated — `src/v1/model.ts:643-653` +### 12. `THOUGHT_TYPE_*` prefix repeated — `src/v1/model.ts:643-653` - **Why weird:** Six values, all `THOUGHT_TYPE_*`. The plain-noun forms (`Description`, `Understanding`, `DataSourcing`, `Instructions`, `Steps`) would be perfectly clear under `ThoughtType.`. - **Category:** 2 (redundant enum prefix), 18 (long enum values). - **Suggested name:** `ThoughtType.Unspecified | Description | Understanding | DataSourcing | Instructions | Steps`. -- **Rationale:** Same as #13. +- **Rationale:** Same as #10. -### 16. `VERIFICATION_SECTION_*` prefix repeated and one value has the prefix doubled — `src/v1/model.ts:660-666` +### 13. `VERIFICATION_SECTION_*` prefix repeated and one value has the prefix doubled — `src/v1/model.ts:660-666` - **Why weird:** Five values: `VERIFICATION_SECTION_UNSPECIFIED`, `VERIFICATION_SECTION_SQL_EXAMPLES_VALIDATION`, `VERIFICATION_SECTION_VERIFICATION_QUERIES`, `VERIFICATION_SECTION_PROPOSED_IMPROVEMENT`, `VERIFICATION_SECTION_FINAL_DECISION`. The third value (`VERIFICATION_SECTION_VERIFICATION_QUERIES`) repeats `VERIFICATION` — 41 characters. - **Category:** 2 (redundant prefix doubled), 18 (long enum values). - **Suggested name:** `VerificationSection.Unspecified | SqlExamplesValidation | VerificationQueries | ProposedImprovement | FinalDecision`. - **Rationale:** Same. -### 17. `TEXT_ATTACHMENT_PURPOSE_*` prefix repeated; enum has only 2 values — `src/v1/model.ts:626-628` +### 14. `TEXT_ATTACHMENT_PURPOSE_*` prefix repeated; enum has only 2 values — `src/v1/model.ts:626-628` - **Why weird:** Two values: `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED` (35 chars) and `FOLLOW_UP_QUESTION`. Prefix only on the sentinel — inconsistent within the same enum. - **Category:** 17 (inconsistent prefix within one enum), 2 (redundant prefix on sentinel). - **Suggested name:** Either `Unspecified | FollowUpQuestion`, or drop the enum (boolean `isFollowUp`). - **Rationale:** Two-member enums where one is `_UNSPECIFIED` are often better collapsed. -### 18. `GENIE_EVAL_ASSESSMENT_*` and `GENIE_EVAL_RESPONSE_TYPE_*` prefixes — `src/v1/model.ts:554,561` +### 15. `GENIE_EVAL_ASSESSMENT_*` and `GENIE_EVAL_RESPONSE_TYPE_*` prefixes — `src/v1/model.ts:554,561` - **Why weird:** `GenieEvalAssessment` has values `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GOOD`, `BAD`, `NEEDS_REVIEW`. Only the sentinel carries the prefix. `GenieEvalResponseType` likewise: `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `TEXT`, `SQL`. - **Category:** 17 (inconsistent prefix), 2 (redundant prefix on sentinel). - **Suggested name:** Drop the prefix on the sentinel. - **Rationale:** Same as the rest of the enum prefix cluster — the consistency wins matter more than the wire encoding. -### 19. `EvaluationStatusType` has 6 values mixing `EVALUATION_*` and unprefixed — `src/v1/model.ts:536-544` +### 16. `EvaluationStatusType` has 6 values mixing `EVALUATION_*` and unprefixed — `src/v1/model.ts:536-544` - **Why weird:** Six values: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `RUNNING`, `DONE`, `NOT_STARTED`, `EVALUATION_FAILED`, `EVALUATION_CANCELLED`, `EVALUATION_TIMEOUT`. Three are prefixed `EVALUATION_*`, three are bare. The mixed prefixing is jarring. - **Category:** 17 (inconsistent prefix within one enum), 2 (redundant prefix), 6 (`Type` suffix on enum name is also redundant — every enum is a "type"). - **Suggested name:** `EvaluationStatus.Unspecified | Running | Done | NotStarted | Failed | Cancelled | Timeout`. Drop the `Type` suffix from the enum name. - **Rationale:** This enum is exposed in `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus` — readable values matter. -### 20. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` +### 17. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` - **Why weird:** Three deprecated/active methods all return `GenieGetMessageQueryResultResponse` and all read the SQL result for a message. The naming hierarchy is `Message.QueryResult` vs `MessageAttachment.QueryResult` vs `QueryResult.byAttachment` — three different mental models. Two are deprecated but still exported and named in the surface. - **Category:** 17 (inconsistent action verb / structure), 7 (overly verbose), 12 (duplicate concept). - **Suggested name:** Keep the single canonical method (`getMessageAttachmentQueryResult` → `getMessageAttachmentResult`), mark the others `@deprecated` and consider hiding them from the typed surface (re-export only from `/legacy`). - **Rationale:** Three names with overlapping suffixes is the classic generator-emitting-everything problem. -### 21. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1506` +## Medium severity + +### 18. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1506` - **Why weird:** Request type for `genieStartConversation`. Name contains *both* `Conversation` and `Message`, but the body has only `spaceId` and `content` (`{ spaceId?: string; content?: string; }`). It is not a request to start a "conversation message" — it is a request to start a conversation by sending an initial message. Compare with `GenieStartConversationResponse` (no `Message` in the name). - **Category:** 6 (misleading — name suggests a compound entity that doesn't exist), 7 (overly verbose). - **Suggested name:** `StartConversationRequest` (matches the response). - **Rationale:** Reader has to parse the doc to learn what "ConversationMessage" means here. The companion response name (`GenieStartConversationResponse`) silently drops `Message` — internal inconsistency. -## Medium severity - -### 22. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:911` +### 19. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:911` - **Why weird:** `GenieAttachment.attachment` is a `{ $case: 'text' | 'query' | 'suggestedQuestions', … } | undefined` field. Reading `myAttachment.attachment.text` reads as "the attachment of the attachment", and the parent `GenieAttachment` also has a peer field `attachmentId`. The shape mixes the discriminator field with a flat id field. - **Category:** 15 (generic field name losing meaning). - **Suggested name:** Hoist to top-level discriminated union: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. Or rename the field to `payload` / `body` / `content`. - **Rationale:** Same struct, single name; the parent-name-shaped field name confuses readers traversing nested attachments. -### 23. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:940,952` +### 20. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:940,952` - **Why weird:** The struct has two id fields. JSDoc on `id` says "Legacy identifier, use conversation_id instead". Both are emitted, both are typed `string | undefined`, both are read from the wire. The struct also has no doc explaining the precedence rule when both are present (server normally fills both with the same value). - **Category:** 19 (underspecified id), 12 (duplicate concept within one struct), 8 (redundant suffix). -- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#24). +- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#21). - **Rationale:** Caller cannot tell which to read without consulting the doc; autocomplete shows both at the same priority. -### 24. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1395,1419` -- **Why weird:** Same pattern as #23. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. -- **Category:** 19, 12, 8 (same as #23). -- **Suggested name:** Same as #23. -- **Rationale:** Same as #23. +### 21. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1395,1419` +- **Why weird:** Same pattern as #20. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. +- **Category:** 19, 12, 8 (same as #20). +- **Suggested name:** Same as #20. +- **Rationale:** Same as #20. -### 25. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1482-1503` +### 22. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1482-1503` - **Why weird:** Compare with the rest of the SDK: `GenieSpace` uses `title` for the human-readable name (other types use `name`/`displayName`). The struct has `spaceId`, `title`, `description`, `warehouseId`, `parentPath`, `serializedSpace`, `etag` — no `name`. JSDoc on `title` says "Title of the Genie Space" — but in the rest of the codebase, "title" is reserved for `GenieConversation.title` (the conversation subject line). Two different "titles" in the same package. - **Category:** 17 (inconsistency vs other types), 1 (vague — `title` doesn't distinguish from conversation title). - **Suggested name:** `displayName` or `name` (Space is a top-level entity; "title" is column-header style). - **Rationale:** Aligns with `DatabricksWorkspace.name`, `Dashboard.displayName`, etc. -### 26. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:950,1408,1437,1736,1758` +### 23. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:950,1408,1437,1736,1758` - **Why weird:** Five different concepts share the field name `content`. The reader cannot disambiguate from the field name alone. JSDocs differ: "User message content" / "Comment text content" / "AI generated message" / "The md formatted content for this thought" — i.e. they are all different formats. - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `body` for the message body, `text` for comments and thoughts, or qualify (`messageBody`, `commentText`, `thoughtMarkdown`). - **Rationale:** "Content" is a near-meaningless filler word; this is the kind of generic name the codebase rule (#15 of the audit categories) targets. -### 27. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:944` +### 24. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:944` - **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1401), `GenieMessageComment.userId` (line 1435), `GenieEvalResult.createdByUser` (line 1048), `GenieEvalRunResponse.runByUser` (line 1114). - **Category:** 16 (field type contradicts domain), 14 (proto-int64 leaked to JS `number`). - **Suggested name:** Keep field name, change type to `string` (matches the rest of the SDK), or use `bigint`. Or `userId: string` with stronger JSDoc. - **Rationale:** Postgres-ID / long-id semantics are universal here. The `userId: number` typing is a generator bug that bites at runtime. -### 28. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:946,948,958,1116,1126,1402,1404,1439,1450` +### 25. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:946,948,958,1116,1126,1402,1404,1439,1450` - **Why weird:** 9 fields use `*Timestamp` suffix. The type is already `number` (a Unix-millis timestamp per JSDoc). The suffix duplicates the type. Some peer fields drop the suffix (`createdByUser` on `GenieEvalResult`, `runByUser` on `GenieEvalRunResponse`). - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `createdAt` / `updatedAt`. Or `createdAtMs` / `updatedAtMs` if the millis unit needs to be explicit. - **Rationale:** Industry-standard `createdAt`/`updatedAt` reads more naturally than `createdTimestamp`/`lastUpdatedTimestamp`. -### 29. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1404` +### 26. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1404` - **Why weird:** `lastUpdatedTimestamp` (5 syllables) is the package's "updated at" name. The `last` prefix adds nothing — by definition, an "updated at" timestamp is the *last* update. - **Category:** 7 (overly verbose). - **Suggested name:** `updatedAt` / `updatedTimestamp`. -- **Rationale:** Same as #28. +- **Rationale:** Same as #25. -### 30. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1452` +### 27. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1452` - **Why weird:** `id?: string` on `GenieQueryAttachment` is undocumented (no JSDoc). The parent `GenieAttachment` has `attachmentId` (line 932) — so the `id` here is presumably the same value or the query-attachment-specific id. Caller can't tell. - **Category:** 19 (underspecified id), 1 (vague). - **Suggested name:** `attachmentId` (match the parent) or `queryAttachmentId` (qualify). - **Rationale:** Two near-identical ids on the same outer entity is one ambiguity too many. -### 31. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1737` -- **Why weird:** Same as #30 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. +### 28. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1737` +- **Why weird:** Same as #27 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. - **Category:** 19, 1. -- **Suggested name:** Same as #30. -- **Rationale:** Same as #30. +- **Suggested name:** Same as #27. +- **Rationale:** Same as #27. -### 32. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1108` +### 29. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1108` - **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). - **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). - **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. - **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. -### 33. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1168` +### 30. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1168` - **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. - **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). - **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. - **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. -### 34. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1157,1184` -- **Why weird:** Same as #33 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +### 31. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1157,1184` +- **Why weird:** Same as #30 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). - **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). - **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. - **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. -### 35. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1172,1196` +### 32. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1172,1196` - **Why weird:** JSDoc says "JWT signature for the download_id". JWT is itself the full token (header.payload.signature). Calling it a "signature" understates what it is (the entire JWT that authorises the download). - **Category:** 6 (misleading — `Signature` is a sub-part of a JWT), 5 (cryptic). - **Suggested name:** `downloadToken` / `downloadJwt`. - **Rationale:** Caller expects a base64 signature to pair with `downloadId`; the value is actually a full bearer token. -### 36. `statementIdSignature` same pattern — `src/v1/model.ts:1618` -- **Why weird:** Same as #35: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. +### 33. `statementIdSignature` same pattern — `src/v1/model.ts:1618` +- **Why weird:** Same as #32: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. - **Category:** 6 (misleading), 5 (cryptic). - **Suggested name:** `statementToken` / `statementJwt`. -- **Rationale:** Same as #35. +- **Rationale:** Same as #32. -### 37. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1503,1552` +### 34. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1503,1552` - **Why weird:** HTTP `ETag` is the canonical capitalisation. The field is `etag: string`. Across the SDK other types use `etag` lowercase too — but it is an acronym (`Entity Tag`). - **Category:** 3 (acronym casing). - **Suggested name:** `eTag` (camelCase per TS style) or `etag` (current — chosen for consistency). - **Rationale:** Low priority; flag for awareness. -### 38. `Result` type name — too generic — `src/v1/model.ts:1610` +### 35. `Result` type name — too generic — `src/v1/model.ts:1610` - **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. - **Category:** 1 (vague/generic). - **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. - **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. -### 39. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1616,1677` +### 36. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1616,1677` - **Why weird:** Both fields are booleans indicating truncation. `Result.isTruncated` uses the `is*` prefix convention; `ResultManifest.truncated` is bare. Same struct file, two conventions. - **Category:** 17 (inconsistency). - **Suggested name:** Pick one form (`truncated` everywhere) and apply. - **Rationale:** Pure consistency win; no semantic change. -### 40. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1465` +### 37. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1465` - **Why weird:** A third truncation field on `GenieResultMetadata.isTruncated`. Three independent fields tracking the same concept across `Result`, `ResultManifest`, `GenieResultMetadata`. - **Category:** 17 (inconsistency), 12 (duplicate concept). -- **Suggested name:** Same as #39. -- **Rationale:** Same as #39. +- **Suggested name:** Same as #36. +- **Rationale:** Same as #36. -### 41. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1461` +### 38. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1461` - **Why weird:** A type whose two fields (`rowCount`, `isTruncated`) are both already on `ResultManifest`. JSDoc says "Metadata associated with the query result", but `ResultManifest` is also "result manifest" metadata. - **Category:** 12 (duplicate concept). - **Suggested name:** Replace with `ResultManifest` (or a sub-projection of it); delete `GenieResultMetadata`. - **Rationale:** Two structs covering the same semantic territory cause readers to wonder which one is authoritative. -### 42. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1605` +### 39. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1605` - **Why weird:** `keyword` is a vague word for what is presumably the parameter name. No JSDoc. The companion field `value` carries the bound value; `sqlType` carries the type. A parameter is `(name, value, type)` — why is `name` called `keyword`? - **Category:** 1 (vague), 6 (misleading — `keyword` evokes SQL reserved words). - **Suggested name:** `name` (with JSDoc) or `parameterName`. - **Rationale:** Reader sees `keyword` and looks for a SQL keyword list. -### 43. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1606` +### 40. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1606` - **Why weird:** No JSDoc on `value`. Type is `string`. For SQL parameters this could be a literal value, an expression, a placeholder, a JSON-encoded scalar, etc. Companion `sqlType?: string` (also no JSDoc) presumably qualifies it. - **Category:** 1 (vague), 16 (field type may contradict domain). - **Suggested name:** Document. Optionally `stringValue` / `valueText` to make the encoding explicit. - **Rationale:** Public SDK types should not require source-diving. -### 44. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:925` +### 41. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:925` - **Why weird:** Discriminator value is `'suggestedQuestions'` and the payload type is `GenieSuggestedQuestionsAttachment`. The word `Attachment` is in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** Variant `'followUps'`, payload `SuggestedQuestions { questions: string[] }`. - **Rationale:** Reduce noise per attachment. -### 45. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1525` +## Low severity + +### 42. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1525` - **Why weird:** Bare `string[]`. Doc says "The suggested follow-up questions". The questions are also typed elsewhere as a free-text input (`content` on a `GenieCreateConversationMessageRequest`) — so the type tells you nothing about the format. - **Category:** 1 (vague — questions could be markdown, plain, etc.). - **Suggested name:** `followUpQuestions: string[]` (clearer; matches the JSDoc). - **Rationale:** Field name disambiguation. -### 46. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1578` +### 43. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1578` - **Why weird:** `MessageError.error: string`. Reader sees `someError.error` (two `error`s). Some other fields are similarly self-referential (`Result.statementId`, OK because `Result` is generic; here `MessageError.error` is *the error message*). - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `MessageError.message: string` (matches the JSON shape) or `MessageError.detail`. - **Rationale:** Wire format on the server may already be `error_message`; check before renaming. -### 47. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1579` +### 44. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1579` - **Why weird:** Field name `type` is a JS reserved-word-adjacent (TS allows it, but `type` collides with the `type` keyword used in TS type aliases — refactoring tools sometimes choke). - **Category:** 10 (reserved-word collision), 1 (vague). - **Suggested name:** `errorType` / `category` / `kind`. - **Rationale:** Common collision; small ergonomics win. -### 48. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1756` +### 45. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1756` - **Why weird:** `Thought.thoughtType` repeats "thought" twice. Could just be `Thought.type`. - **Category:** 8 (redundant suffix), 7 (overly verbose). - **Suggested name:** `Thought.type` (and rename `ThoughtType` → `Thought.Kind` namespace). - **Rationale:** Reduces redundancy. -### 49. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:932` +### 46. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:932` - **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1737) and `GenieQueryAttachment.id` (line 1452) inside variants. Three different id fields for the same logical entity (the attachment). - **Category:** 19 (underspecified id), 12 (duplicate concept). - **Suggested name:** Single `id` on `GenieAttachment`, remove inner ids. -- **Rationale:** See #30, #31, #49 together. +- **Rationale:** See #27, #28, #46 together. -### 50. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1262` +### 47. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1262` - **Why weird:** Boolean toggle that expands the response. Permission check is documented ("Requires at least CAN EDIT permission"). Boolean naming style varies across SDK: `enableX`, `includeX`, `withX`. Could be `withSerializedSpace` or `includeSerialized` (the parent struct is already a Space). - **Category:** 7 (overly verbose). - **Suggested name:** `withSerialized` / `expandSerialized`. - **Rationale:** The struct context already says "Space"; the prefix is redundant. -## Low severity - -### 51. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` +### 48. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` - **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). - **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. - **Rationale:** Class names should be noun phrases; current name reads as a verb. -### 52. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:961, client.ts:160` +### 49. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:961, client.ts:160` - **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. - **Category:** 7 (overly verbose). - **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. - **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. -### 53. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1278` +### 50. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1278` - **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. - **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). - **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. - **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. -### 54. `Format` enum has 4 values; only sentinel is prefixed — `src/v1/model.ts:546-551` -- **Why weird:** `FORMAT_UNSPECIFIED` then `JSON_ARRAY`, `ARROW_STREAM`, `CSV`. Same inconsistent-prefix pattern as #17 / #18. +### 51. `Format` enum has 4 values; only sentinel is prefixed — `src/v1/model.ts:546-551` +- **Why weird:** `FORMAT_UNSPECIFIED` then `JSON_ARRAY`, `ARROW_STREAM`, `CSV`. Same inconsistent-prefix pattern as #14 / #15. - **Category:** 17, 2. - **Suggested name:** `Format.Unspecified | JsonArray | ArrowStream | Csv`. -- **Rationale:** Same as #13. +- **Rationale:** Same as #10. -### 55. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:549` +### 52. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:549` - **Why weird:** Value `ARROW_STREAM` casing. The product name is `Apache Arrow` — `Arrow` is title-case in TS naming. As an enum value `ARROW_STREAM` is conventional (SCREAMING_SNAKE) but mixed with `JSON_ARRAY` and `CSV` where one is fully-cap acronym and one is mixed. - **Category:** 3 (acronym casing), 17 (mixed conventions within the enum). - **Suggested name:** `ArrowStream` (in a Pascal-case enum). - **Rationale:** Low priority — enum-value style is widely-debated. -### 56. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1415` -- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #38). +### 53. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1415` +- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #35). - **Category:** 12 (duplicate concept — kept-for-compat), 1 (vague — `Result`). - **Suggested name:** Mark with `/** @deprecated */` JSDoc (current text just says "Deprecated" — TS tooling won't strike-through). - **Rationale:** Tooling support — modern TS understands `@deprecated`. -### 57. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +### 54. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. - **Rationale:** Cleanup; clients should migrate to the canonical name. -### 58. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1048` +### 55. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1048` - **Why weird:** Field is named `createdByUser` rather than `createdBy`. `By User` is redundant: a `createdBy` field is by-its-nature-by-a-user (or by a service principal). Compare `GenieEvalRunResponse.runByUser` (same pattern, line 1114). - **Category:** 7 (overly verbose), 17 (inconsistent vs other types in the SDK using `createdBy`). - **Suggested name:** `createdBy` (matches the rest of the SDK). - **Rationale:** Aligns with `databricks-sdk-go` conventions and most peer types. -### 59. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1114` -- **Why weird:** Same as #58. +### 56. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1114` +- **Why weird:** Same as #55. - **Category:** 7, 17. - **Suggested name:** `runBy` / `runByUserId`. -- **Rationale:** Same as #58. +- **Rationale:** Same as #55. -### 60. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1046,1103,1105` +### 57. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1046,1103,1105` - **Why weird:** `GenieEvalResult` stores the original "benchmark answer" as a flat string; `GenieEvalResultDetails` returns the actual/expected as arrays of `GenieEvalResponse`. Three different words for "the right answer" / "Genie's answer" / "the expected answer". - **Category:** 17 (inconsistent word choice), 1 (vague — `answer` vs `response`). - **Suggested name:** Pick one verb. E.g., `expectedAnswer` / `actualAnswer` (or `expectedResponse` / `actualResponse` for both types). - **Rationale:** Reader has to relearn the vocabulary in each type. -### 61. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1060` +### 58. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1060` - **Why weird:** A `GenieEvalResultDetails` describes a single result inside a run. The field `evalRunStatus` describes the *run's* status, not the result's status. The plain `status` field appears on `GenieEvalResult` (line 1042) but is gone here — replaced by `evalRunStatus`. So the same enum (`EvaluationStatusType`) is exposed under two different field names. - **Category:** 17 (inconsistent field naming for the same concept), 6 (misleading — `evalRunStatus` on a result-details type confuses run-status with result-status). - **Suggested name:** `runStatus` (with the run context clear from the parent type's purpose). - **Rationale:** Same status enum, two field names is jarring. -### 62. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1064` +### 59. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1064` - **Why weird:** Two adjacent fields: `assessment: GenieEvalAssessment` and `manualAssessment: boolean`. The second is a flag indicating whether the first was set manually. The naming implies that `manualAssessment` is itself an assessment. - **Category:** 6 (misleading — `manualAssessment` looks like "the manual assessment value"), 1 (vague). - **Suggested name:** `assessmentIsManual` / `isManuallyAssessed`. - **Rationale:** Boolean-prefix convention disambiguates. -### 63. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1312` +### 60. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1312` - **Why weird:** `includeAll: boolean`. JSDoc clarifies "Include all conversations in the space across all users". `All` is unqualified; could mean "include archived", "include all spaces", "include all messages". - **Category:** 1 (vague), 6 (misleading without docs). - **Suggested name:** `includeAllUsers` / `acrossUsers` / `allUsers`. - **Rationale:** Boolean toggles need to be unambiguous from the name. -### 64. `pageSize` / `pageToken` casing — `src/v1/model.ts:1271,1273,1289,1291,...` -- **Why weird:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. -- **Category:** Observation only — no issue. -- **Suggested name:** N/A. -- **Rationale:** Confirms the package's pagination naming is consistent. - -### 65. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — `type` prefix repeated — `src/v1/model.ts:807-818` +### 61. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — `type` prefix repeated — `src/v1/model.ts:807-818` - **Why weird:** Six fields all prefixed `type*`. Hoisting into a sub-struct `type: { text, name, precision, scale, intervalType, json }` would be cleaner. Generator-faithful flat shape duplicates the prefix. - **Category:** 7 (overly verbose), 8 (redundant prefix). - **Suggested name:** Sub-struct, or trim the prefix. - **Rationale:** Aesthetic; matches the protobuf shape. -### 66. `ColumnInfo.typeIntervalType` — `type` doubled — `src/v1/model.ts:816` +### 62. `ColumnInfo.typeIntervalType` — `type` doubled — `src/v1/model.ts:816` - **Why weird:** `typeIntervalType` doubles the word "type". Doc: "Format of IntervalType." - **Category:** 7 (overly verbose). - **Suggested name:** `intervalFormat` (in a sub-struct) or `intervalType`. - **Rationale:** Trim the doubled word. -### 67. `ExternalLink_HttpHeadersEntry` — `_` underscore type — `src/v1/model.ts:904` -- **Why weird:** Proto-generated entry type with underscore. Used internally for the map serialization. -- **Category:** 4 (underscores in TS identifiers), 14 (proto-style nested name). -- **Suggested name:** Map directly to `Record` (the parent field `httpHeaders` is already typed as `Record`). -- **Rationale:** The proto-style underscore name leaks into the public surface even though the parent field uses a flat `Record`. - -### 68. `Schema` type name — too generic — `src/v1/model.ts:1680` +### 63. `Schema` type name — too generic — `src/v1/model.ts:1680` - **Why weird:** `Schema` is one of the most-overloaded names in the SDK (Unity Catalog Schema, SQL schema, JSON schema, Avro schema, etc.). This `Schema` is a SQL result schema (`columnCount`, `columns`). - **Category:** 1 (vague/generic), 12 (collides with UC `Schema`). - **Suggested name:** `ResultSchema`. - **Rationale:** Collision with UC `Schema` will bite consumers who import from both. -### 69. `Struct` type name — too generic, copied from proto wkt — `src/v1/model.ts:1729` +### 64. `Struct` type name — too generic, copied from proto wkt — `src/v1/model.ts:1729` - **Why weird:** `Struct` is the proto Well-Known Type `Struct` (an arbitrary JSON-object value). Calling this `Struct` clashes with TS's natural use of "struct" for any object. - **Category:** 1 (vague/generic), 12 (proto wkt copy). - **Suggested name:** Use `Record` directly, or call it `JsonObject` / `ProtoStruct`. @@ -435,13 +405,18 @@ ## Observations -### 70. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #50 -- **Observation:** Listed under #50. Documenting here for cross-reference. +### 65. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #47 +- **Observation:** Listed under #47. Documenting here for cross-reference. + +### 66. `pageSize` / `pageToken` casing — `src/v1/model.ts:1271,1273,1289,1291,...` +- **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. +- **Suggested name:** N/A. +- **Rationale:** Confirms the package's pagination naming is consistent. -### 71. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1771` +### 67. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1771` - **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. - **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. - **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. -### 72. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,1000,1004,1008` +### 68. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,1000,1004,1008` - **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index 98a90f8d..100a50bd 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -13,7 +13,7 @@ creation and returns it everywhere else. Five operations: `create/get/list/update/delete`. No enums, no discriminated unions, no pagination, no list filtering beyond an optional `principalId` query parameter, no version negotiation. -**Total weird names flagged:** 23 +**Total weird names flagged:** 17 --- @@ -23,27 +23,24 @@ parameter, no version negotiation. |---|------|------|------|----------|----------|-------------------| | 1 | package `gitcredentials` / module `@databricks/sdk-gitcredentials` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 12 Duplicate concepts | Lowercased compound noun runs `git` and `credentials` together with no separator. The npm registry has packages literally called `git-credentials`/`@gitcredentials` (different ecosystem). Also collides conceptually with `@databricks/sdk-credentials` (Unity Catalog cloud-storage credentials) and `@databricks/sdk-auth/credentials` (SDK auth credentials). Three packages with "Credentials" in the name, three different meanings. | | 2 | `Credential` (interface) | model.ts:68 | interface | High | 1 Vague/generic, 12 Duplicate concepts | Bare `Credential` clashes with `@databricks/sdk-credentials`'s `Credential` (UC credentials) and with the auth package's `Credentials` interface. None of them say "Git" or "auth" or "UC" on the type name. Should be `GitCredential`. | -| 3 | `Credential` vs `CreateCredentials_Response` vs `GetCredentials_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. `CreateCredentials_Response` and `GetCredentials_Response` should be type aliases of `Credential`, or `Credential` should be the response type directly. | +| 3 | `Credential` vs `CreateCredentials_Response` vs `GetCredentials_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. The two response types should be type aliases of `Credential`, or `Credential` should be the response type directly. | | 4 | `CreateCredentials` vs `UpdateCredentials` (request envelopes) | model.ts:5, 152 | interface pair | High | 12 Duplicate concepts | The two request envelopes differ by exactly one field: `UpdateCredentials` adds `id` (path parameter). Otherwise field-for-field identical: `gitProvider`, `gitUsername`, `personalAccessToken`, `principalId`, `name`, `isDefaultForProvider`, `gitEmail`. The JSDoc text on every shared field is duplicated verbatim across both. Should share a base type (`GitCredentialMutation`) and only differ on the path key. | -| 5 | `CreateCredentials` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The response is `CreateCredentials_Response` — also plural. The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredential` / `CreateCredentialResponse`. (Compare `Credential` itself — the resource singular is already chosen.) | +| 5 | `CreateCredentials` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredential`. (Compare `Credential` itself — the resource singular is already chosen.) | | 6 | `UpdateCredentials`, `DeleteCredentials`, `GetCredentials` named with plural | model.ts:152, 98, 108 | interface set | High | 9 Singular/plural mismatches | Same as #5 — three more cases. `UpdateCredentials` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentials` deletes one. `GetCredentials` gets one. All three should be singular. | | 7 | `ListCredentials_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | -| 8 | `CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response` (proto-style underscore identifiers) | model.ts:43, 106, 116, 147, 192 | interface set | High | 4 Underscores in TS identifiers | Five proto-style `Parent_Response` types each carrying their own `// eslint-disable-next-line @typescript-eslint/naming-convention` comment. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. Standard TS idiom would be `CreateCredentialResponse` (PascalCase without underscore), or `Credential` directly (no separate response type at all — see #3, #15, #16). | -| 9 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | -| 10 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | -| 11 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | -| 12 | `bitbucketServer` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Same problem as #11 — wire value is the legacy name. | -| 13 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | -| 14 | `gitUsername`, `gitEmail`, `gitProvider` prefixed with `git` | model.ts:20, 39, 13, 54, 65, 84, 95, 127, 138, 175, 188 | field set | Medium | 1 Vague/generic, 6 Misleading names | The package is *gitcredentials*; every field already lives under the package namespace. Re-prefixing each field with `git` is stuttering. `req.gitProvider`, `req.gitUsername`, `req.gitEmail` could be `req.provider`, `req.username`, `req.email`. The wire format requires the `git_` prefix on the JSON keys (see the zod schemas), but the TS field can be renamed in the zod `transform`. | -| 15 | `CreateCredentials_Response` vs `GetCredentials_Response` (identical shapes) | model.ts:43, 116 | interface pair | High | 12 Duplicate concepts | Same six fields, same types, same optionality, same JSDoc text. Should be a single `Credential` type (see #3). | -| 16 | `Credential` vs the two response types (identical shapes) | model.ts:68, 43, 116 | interface trio | High | 12 Duplicate concepts | The `Credential` resource type and the two `*_Response` types are field-for-field identical (see #3). The pattern is uniform across the file: the create-response and get-response should be `Credential`. The list-response is `{credentials: Credential[]}` — that one is fine; the response wrappers around a single credential are not. | -| 17 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | -| 18 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 104, 135, 166, 197 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | -| 19 | `DeleteCredentials.id` and `GetCredentials.id` and `UpdateCredentials.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | -| 20 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | -| 21 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | -| 22 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | -| 23 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | +| 8 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | +| 9 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | +| 10 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | +| 11 | `bitbucketServer` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Same problem as #10 — wire value is the legacy name. | +| 12 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | +| 13 | `gitUsername`, `gitEmail`, `gitProvider` prefixed with `git` | model.ts:20, 39, 13, 54, 65, 84, 95, 127, 138, 175, 188 | field set | Medium | 1 Vague/generic, 6 Misleading names | The package is *gitcredentials*; every field already lives under the package namespace. Re-prefixing each field with `git` is stuttering. `req.gitProvider`, `req.gitUsername`, `req.gitEmail` could be `req.provider`, `req.username`, `req.email`. The wire format requires the `git_` prefix on the JSON keys (see the zod schemas), but the TS field can be renamed in the zod `transform`. | +| 14 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | +| 15 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 104, 135, 166, 197 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 16 | `DeleteCredentials.id` and `GetCredentials.id` and `UpdateCredentials.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | +| 17 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | +| 18 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | +| 19 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | +| 20 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | --- @@ -93,22 +90,9 @@ await client.createCredential({gitProvider: 'gitHub', ...}); Recommendation: keep `listCredentials` (plural — list returns many) but rename the four single-resource methods and their request types to -singular. See #5, #6, #18. +singular. See #5, #6, #15. -### H3. Five `_Response` types use proto-style underscores - -`CreateCredentials_Response`, `DeleteCredentials_Response`, -`GetCredentials_Response`, `ListCredentials_Response`, -`UpdateCredentials_Response` all carry inline -`// eslint-disable-next-line @typescript-eslint/naming-convention` -disables. The presence of those disables is the loudest possible signal -that the names violate the project's own conventions. - -Standard TS idiom would be `CreateCredentialResponse` (PascalCase, no -underscore), nested in a namespace, or — as is appropriate here — *removed -entirely* in favor of returning the resource type directly (see H4). - -### H4. Three field-for-field-identical "Credential" shapes +### H3. Three field-for-field-identical "Credential" shapes `Credential`, `CreateCredentials_Response`, and `GetCredentials_Response` all have the same six fields with the same types, the same optionality, and @@ -127,7 +111,7 @@ export interface GitCredential { /* 6 fields */ } // Return GitCredential directly from create() and get(). ``` -### H5. `id` vs `credentialId` for the same value +### H4. `id` vs `credentialId` for the same value Requests use `id`: @@ -150,9 +134,9 @@ between the two spellings. JSDoc on the request `id` field even says "the ID for the corresponding *credential* to access" — i.e., it is logically a credential ID. The wire format uses `id` (path parameter) on requests and `credential_id` (body field) on responses — the *server* mints the -divergence; the TS-side should normalize to one spelling. See #19, #22. +divergence; the TS-side should normalize to one spelling. See #16, #19. -### H6. `gitProvider` is typed `string` but is closed-set +### H5. `gitProvider` is typed `string` but is closed-set ```ts gitProvider?: string | undefined; @@ -169,9 +153,9 @@ server rejects other values. But the TS-side surfaces it as `string`, so: cannot be fixed at the call site, only by the API server. Recommendation: emit a string-literal union or enum. The casing problem -(#10) gets handled there. +(#9) gets handled there. -### H7. `Client` is unqualified +### H6. `Client` is unqualified `export class Client` (client.ts:48). Every package in this SDK exports its own `Client`. Once imported in user code: @@ -207,7 +191,7 @@ console.log(cred.provider, cred.username, cred.email); The wire JSON key needs `git_provider`, so the rename is purely a zod `transform` change. The `git_*` keys must survive to the wire; the TS field -names can be unprefixed. See #14. +names can be unprefixed. See #13. ### M2. Plural `*Credentials` envelopes for single-resource operations @@ -220,7 +204,7 @@ JSDoc says "the name of the git credential, used for identification and ease of lookup". So `name` is a *display* name. The actual lookup key is `id`. Callers reading the type signature will assume `name` is a primary key (because it is on most Databricks resources — e.g., `clusters/{name}`). -`displayName` or `label` would clarify. See #21. +`displayName` or `label` would clarify. See #18. ### M4. `principalId` is a service-principal ID, not a user ID @@ -228,7 +212,7 @@ JSDoc on every `principalId` field says "The ID of the service principal whose credentials will be modified. Only service principal managers can perform this action." The field name says only "Principal" — which is overloaded in security/auth contexts. `servicePrincipalId` would -self-document. See #20. +self-document. See #17. ### M5. `personalAccessToken` field name is narrower than its accepted values @@ -241,7 +225,7 @@ JSDoc: So the field accepts more than just "personal access tokens" — also "fine- grained tokens", "deploy keys", etc. depending on the provider. The name `personalAccessToken` lies about that. `accessToken` (or `token`) is -honest. See #23. +honest. See #20. ### M6. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term @@ -253,13 +237,10 @@ concept toggles plural/singular at almost every boundary: |---|---| | Resource type | `Credential` | | Create-request type | `CreateCredentials` | -| Create-response type | `CreateCredentials_Response` (returns one) | | Get-request type | `GetCredentials` (gets one) | -| Get-response type | `GetCredentials_Response` (returns one) | | Update-request type | `UpdateCredentials` (updates one) | | Delete-request type | `DeleteCredentials` (deletes one) | | List-request type | `ListCredentials` (lists many) | -| List-response type | `ListCredentials_Response.credentials` | | Wire endpoint | `/api/2.0/git-credentials` (plural collection) | Pick a rule. Conventional CRUD: plural for collection ops (`listCredentials`, @@ -275,8 +256,8 @@ URL `/credentials`), singular for resource ops (`getCredential`, The JSDoc on `gitProvider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on either the field's documentation or on a typed enum value (which doesn't -exist — see H6). Callers cannot programmatically detect deprecated values. -See #13. +exist — see H5). Callers cannot programmatically detect deprecated values. +See #12. --- @@ -285,7 +266,7 @@ See #13. ### Wire-protocol values that the audit cannot fix The `gitProvider` wire values (`gitHub`, `bitbucketCloud`, etc.) are -dictated by the API server. The casing inconsistencies (#10) are baked in. +dictated by the API server. The casing inconsistencies (#9) are baked in. The TS-side cannot change them without breaking the wire. The audit flags them for awareness — fixing requires an API-server change. @@ -294,23 +275,20 @@ them for awareness — fixing requires an API-server change. | Identifier kind | Count | |---|---| | Total exported interfaces | 10 | -| Underscored (proto-style) interfaces | 5 (`CreateCredentials_Response`, `DeleteCredentials_Response`, `GetCredentials_Response`, `ListCredentials_Response`, `UpdateCredentials_Response`) | | Plural request envelopes for single-resource ops | 4 | | Identical-shape interface trios | 1 (`Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | -| Inline ESLint disables required by these names | 5 | | Enums | 0 (despite an 8-value closed set on `gitProvider`) | ### Comparison to other audits | Issue | This package | `credentials` audit | `oauthcustomappintegration` (typical) | |---|---|---|---| -| Bare `Client` class | Yes (#17) | Yes (#10) | Yes | -| `_Response` underscore types | Yes (#8) | Yes (#18) | Yes | -| Bare `id` field on requests vs `Id` on responses | Yes (#19, #22) | Partial (#12, `nameArg`) | Common | -| Plural request envelopes on single-resource ops | Yes (#5, #6, #18) | No (uses `nameArg`/singular shapes) | Mixed | -| `string`-typed enum-domain field | Yes (#9) | No (uses real enums) | Rare | +| Bare `Client` class | Yes (#14) | Yes (#10) | Yes | +| Bare `id` field on requests vs `Id` on responses | Yes (#16, #19) | Partial (#12, `nameArg`) | Common | +| Plural request envelopes on single-resource ops | Yes (#5, #6, #15) | No (uses `nameArg`/singular shapes) | Mixed | +| `string`-typed enum-domain field | Yes (#8) | No (uses real enums) | Rare | -The `string`-typed `gitProvider` despite a documented closed set (#9, H6) +The `string`-typed `gitProvider` despite a documented closed set (#8, H5) is the standout finding unique to this package. The plural request-type naming (#5, #6, H2) is also pronounced here — the `credentials` audit gets it right (`CreateCredential`, `UpdateCredential`). diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index 2cb4c039..397c757b 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -31,7 +31,7 @@ None. This package defines no enums. | Name | Purpose | | ------------------------------------- | --------------------------------------------- | | `CreateGlobalInitScript` | Request body for create. | -| `CreateGlobalInitScript_Response` | Response from create (proto-style suffix). | +| `CreateGlobalInitScript_Response` | Response from create. | | `DeleteGlobalInitScript` | Request body (path param wrapper) for delete. | | `DeleteGlobalInitScript_Response` | Empty response from delete. | | `GetGlobalInitScript` | Request body (path param wrapper) for get. | @@ -109,15 +109,11 @@ No enums are declared in this package; this rubric category does not apply. | A-02 | `Uint8Array` | Low | Standard Web/TC39 typed-array name; OK. | | A-03 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScript.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | -### 2.4 Underscores in TS identifiers — High +### 2.4 Underscores in TS identifiers — Low | ID | Symbol | Severity | Issue | | ----- | ------------------------------------------ | -------- | ----- | -| U-01 | `CreateGlobalInitScript_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). Each occurrence requires an `eslint-disable @typescript-eslint/naming-convention` annotation. Should be `CreateGlobalInitScriptResponse`. | -| U-02 | `DeleteGlobalInitScript_Response` | High | Same as U-01. | -| U-03 | `ListGlobalInitScripts_Response` | High | Same as U-01. | -| U-04 | `UpdateGlobalInitScript_Response` | High | Same as U-01. | -| U-05 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | +| U-01 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | ### 2.5 Cryptic abbreviations — Low @@ -176,13 +172,12 @@ _None._ | T-02 | `createdBy`, `createdAt`, `updatedBy`, `updatedAt` | Low | Past participles for audit fields — correct convention. | | T-03 | `enabled` (past participle / adjective) | Low | Consistent with the rest of the SDK (`enabled` boolean state). | -### 2.13 Go / Java-style names — High +### 2.13 Go / Java-style names — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `CreateGlobalInitScript_Response` (proto nested-message style) | High | Direct port of Go / protobuf `pb.CreateGlobalInitScriptResponse` naming. TypeScript ecosystems do not use `_` between message and nested-message names; the file disables ESLint for each occurrence. Should adopt the TS-idiomatic `CreateGlobalInitScriptResponse`. Applies to all four `*_Response` interfaces. | -| G-02 | `GlobalInitScriptDetails` (Java-style "Details" suffix) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | -| G-03 | `req: CreateGlobalInitScript` (parameter named `req`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | +| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | +| G-02 | `req: CreateGlobalInitScript` (parameter named `req`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | ### 2.14 Generic field names losing meaning — Medium @@ -221,7 +216,7 @@ No enums declared; not applicable. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `GlobalInitScriptDetails` | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-02. | +| TS-01 | `GlobalInitScriptDetails` | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | | TS-02 | `HttpCallOptions` (utils) | Low | "Options" is conventional for option-bag types; not tautological. | | TS-03 | `CallOptions` (imported) | Low | Same. | @@ -244,44 +239,33 @@ No enums declared; not applicable. | Severity | Count | | -------- | ----- | -| High | 11 | -| Medium | 12 | -| Low | 27 | -| **Total**| **50**| +| High | 6 | +| Medium | 11 | +| Low | 23 | +| **Total**| **40**| ### 3.2 Top themes -1. **Proto-style `_Response` suffix pollutes every CRUD response type.** - Four interfaces (`CreateGlobalInitScript_Response`, - `DeleteGlobalInitScript_Response`, `ListGlobalInitScripts_Response`, - `UpdateGlobalInitScript_Response`) each require an `eslint-disable` - for the naming-convention rule. Renaming to TS-idiomatic - `CreateGlobalInitScriptResponse` etc. would eliminate the - disable-comments and a Google-style violation in one sweep. - -2. **`script` field overload conflates "script bytes" with "the entity".** +1. **`script` field overload conflates "script bytes" with "the entity".** The field is typed as `Uint8Array` (raw bytes), documented as "Base64-encoded content" (the wire format), and lives on a type already called `GlobalInitScript`. Renaming the field to `content` (or `scriptBytes`) — and clarifying the JSDoc — removes both the self-reference ("script.script") and the format-vs-runtime confusion. -3. **`GlobalInitScriptDetails` should just be `GlobalInitScript`.** +2. **`GlobalInitScriptDetails` should just be `GlobalInitScript`.** The `Details` suffix is a Java-style hangover with no peer type to disambiguate from. The method JSDoc also claims to return Base64 content while the entity has no content field — a documentation / shape inconsistency. -4. **`createdAt`/`updatedAt` naming is good** — unlike sibling packages +3. **`createdAt`/`updatedAt` naming is good** — unlike sibling packages that use `createdAtTimestamp`, this package uses the cleaner `createdAt` / `updatedAt`. Worth keeping as the cross-package reference. ### 3.3 Suggested quick wins (advisory — codegen-level) -- Drop the `_Response` underscore: `CreateGlobalInitScriptResponse`, - `DeleteGlobalInitScriptResponse`, `ListGlobalInitScriptsResponse`, - `UpdateGlobalInitScriptResponse`. Removes ESLint disables. - Rename `script` field to `content` (or `scriptContent`). - Rename entity `GlobalInitScriptDetails` -> `GlobalInitScript`. - Add the missing content field on the entity (or fix the JSDoc on @@ -289,8 +273,6 @@ No enums declared; not applicable. ### 3.4 Cross-package consistency notes -- The `Proto-style nested message name` `_Response` suffix is consistent - with peers and should be addressed at the codegen level. - `position` field semantics are unique to this resource; no other package collides on the name with a different meaning. - The clean `createdAt` / `updatedAt` naming here contrasts with diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md index e2b2abf0..2d4b7a25 100644 --- a/.agent/naming-audit/grants.md +++ b/.agent/naming-audit/grants.md @@ -3,17 +3,17 @@ **Path:** `packages/grants/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. -**Total weird names flagged:** 34 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | -| High | 14 | -| Medium | 15 | -| Low | 4 | +| High | 11 | +| Medium | 13 | +| Low | 3 | | Observation | 1 | -The grants package contains 12 generated types and 5 client methods (plus 2 paginated iterators) covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive issues are (1) the request-type-as-verb naming pattern (`GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions`) which collides with the verb-noun method naming on `Client` and is doubly confusing because the API mixes "permissions" and "privileges" terminology in the same file, (2) proto-style `_Response` underscore-suffixed identifiers leaking into TypeScript (`GetPermissions_Response`, `GetEffectivePermissions_Response`, `UpdatePermissions_Response`) requiring eslint-disable directives, (3) significant duplication of concept between `GetPermissions` / `ListPrivilegeAssignmentsRequest` and `GetEffectivePermissions` / `ListEffectivePrivilegeAssignmentsRequest` — four request types for two operations, plus inconsistent field naming (`securableFullName` vs `fullName`, `maxResults` vs `pageSize`) — and (4) hard-conceptual overlap with the separate `permissions` package, which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation. +The grants package contains 12 generated types and 5 client methods (plus 2 paginated iterators) covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive issues are (1) the request-type-as-verb naming pattern (`GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions`) which collides with the verb-noun method naming on `Client` and is doubly confusing because the API mixes "permissions" and "privileges" terminology in the same file, (2) significant duplication of concept between `GetPermissions` / `ListPrivilegeAssignmentsRequest` and `GetEffectivePermissions` / `ListEffectivePrivilegeAssignmentsRequest` — four request types for two operations, plus inconsistent field naming (`securableFullName` vs `fullName`, `maxResults` vs `pageSize`) — and (3) hard-conceptual overlap with the separate `permissions` package, which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation. --- @@ -37,47 +37,29 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi - **Suggested name:** `GetEffectivePermissionsRequest`. - **Rationale:** See #1. -### 4. `GetEffectivePermissions_Response` — `src/v1/model.ts:53` -- **Why weird:** Proto-style nested message name (`MessageType_FieldName`) with an embedded underscore — illegal in idiomatic TS identifier style. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` to compile. The fact that every consumer must write `GetEffectivePermissions_Response` with the underscore in their code (e.g. `client.ts:23`, `client.ts:99`, `index.ts:11`) means the proto wart is fully visible in the public API. -- **Category:** 4 (underscore in TS identifier), 14 (proto/Go-style name). -- **Suggested name:** `GetEffectivePermissionsResponse` (drop the underscore) or — combined with #3 — `EffectivePermissionsResponse`. -- **Rationale:** TypeScript convention (Google TS style guide § 5.2) is `PascalCase` without internal underscores. The proto FQN-flattening trick should be hidden by the generator, not surfaced. - -### 5. `GetPermissions_Response` — `src/v1/model.ts:91` -- **Why weird:** Same as #4. -- **Category:** 4, 14. -- **Suggested name:** `GetPermissionsResponse` / `PermissionsResponse`. -- **Rationale:** See #4. - -### 6. `UpdatePermissions_Response` — `src/v1/model.ts:207` -- **Why weird:** Same as #4. -- **Category:** 4, 14. -- **Suggested name:** `UpdatePermissionsResponse`. -- **Rationale:** See #4. - -### 7. Concept duplication: "permissions" vs "privileges" — `src/v1/model.ts` (entire file) -- **Why weird:** The package uses two synonymous nouns interchangeably for the same concept. Method names use `permissions` (`getPermissions`, `updatePermissions`); collection types use `privileges` / `PrivilegeAssignment` / `EffectivePrivilege`. The result type of `getPermissions()` is `GetPermissions_Response` whose payload field is named `privilegeAssignments`. A single privilege string (e.g. `"SELECT"`) is sometimes called a "permission" (e.g. in `GetPermissions.maxResults` doc: "the maximum number of privileges to return") and sometimes a "privilege". This is a vocabulary smell baked into the Go SDK port, but it's the single biggest readability issue in the package. +### 4. Concept duplication: "permissions" vs "privileges" — `src/v1/model.ts` (entire file) +- **Why weird:** The package uses two synonymous nouns interchangeably for the same concept. Method names use `permissions` (`getPermissions`, `updatePermissions`); collection types use `privileges` / `PrivilegeAssignment` / `EffectivePrivilege`. The payload field on the response of `getPermissions()` is named `privilegeAssignments`. A single privilege string (e.g. `"SELECT"`) is sometimes called a "permission" (e.g. in `GetPermissions.maxResults` doc: "the maximum number of privileges to return") and sometimes a "privilege". This is a vocabulary smell baked into the Go SDK port, but it's the single biggest readability issue in the package. - **Category:** 12 (duplicate concepts), 17 (inconsistent action verbs / vocabulary). - **Suggested name:** Pick one. Either rename the type family to `Privileges` (so `getPrivileges`, `updatePrivileges`, `PrivilegeAssignment`, `GetPrivilegesResponse`) or `Permissions` (so `getPermissions`, `updatePermissions`, `PermissionAssignment`). The current mix forces readers to mentally translate every method call. - **Rationale:** This is wire-locked (Databricks UC API uses `/permissions/` URL paths but body fields named `privileges`), but the SDK doesn't have to expose it. A consistent vocabulary across types and methods makes the API self-documenting. -### 8. Concept duplication: `GetPermissions` vs `ListPrivilegeAssignmentsRequest` — `src/v1/model.ts:63,129` +### 5. Concept duplication: `GetPermissions` vs `ListPrivilegeAssignmentsRequest` — `src/v1/model.ts:63,129` - **Why weird:** Two top-level request types do nearly the same thing. Compare fields: - `GetPermissions`: `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`, `includeDeletedPrincipals`. - `ListPrivilegeAssignmentsRequest`: `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. - Differences: `securableFullName` ↔ `fullName`; `maxResults` ↔ `pageSize`. Everything else identical. - The Client doc strings (`client.ts:171-173`, `client.ts:241-242`) explicitly call out that `listPrivilegeAssignments` is the "paginated version of Get Permissions API", which is exactly what `getPermissions` already supports (pagination via `maxResults`/`pageToken`). So the SDK ships two flavours of the same operation with different but compatible request shapes. - **Category:** 12 (duplicate concept), 9 (singular/plural mismatch in method naming). -- **Suggested name:** Collapse to a single `ListPrivilegeAssignmentsRequest`; deprecate `GetPermissions` (or vice versa). Match field names across both. See also #18. +- **Suggested name:** Collapse to a single `ListPrivilegeAssignmentsRequest`; deprecate `GetPermissions` (or vice versa). Match field names across both. See also #15. - **Rationale:** Two near-identical request types is a documentation/onboarding tax. The decision of which to use is server-internal (V1 of the API supported one paginated mode, the team added a "true paginated" V2) — but the SDK doesn't need to inflict that history on every consumer. -### 9. Concept duplication: `GetEffectivePermissions` vs `ListEffectivePrivilegeAssignmentsRequest` — `src/v1/model.ts:27,101` -- **Why weird:** Same problem as #8 but for the effective-permissions side. `GetEffectivePermissions` has fields `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`; `ListEffectivePrivilegeAssignmentsRequest` has `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. The List variant additionally supports `includeDeletedPrincipals`, which the Get variant does not — even though `GetPermissions` (#8) does support it. The matrix of which-flavour-supports-which-knob is inconsistent. +### 6. Concept duplication: `GetEffectivePermissions` vs `ListEffectivePrivilegeAssignmentsRequest` — `src/v1/model.ts:27,101` +- **Why weird:** Same problem as #5 but for the effective-permissions side. `GetEffectivePermissions` has fields `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`; `ListEffectivePrivilegeAssignmentsRequest` has `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. The List variant additionally supports `includeDeletedPrincipals`, which the Get variant does not — even though `GetPermissions` (#5) does support it. The matrix of which-flavour-supports-which-knob is inconsistent. - **Category:** 12, 17 (inconsistency). -- **Suggested name:** Same direction as #8 — collapse, or normalize field names and feature parity. -- **Rationale:** See #8. +- **Suggested name:** Same direction as #5 — collapse, or normalize field names and feature parity. +- **Rationale:** See #5. -### 10. Concept duplication with `permissions` package — cross-package +### 7. Concept duplication with `permissions` package — cross-package - **Why weird:** A sibling package `packages/permissions/src/v1/` (also generated, also exposed) uses an entirely different vocabulary for similar-sounding operations: - `permissions` package: `PermissionLevel` enum (e.g. `CAN_MANAGE`, `IS_OWNER`), `AccessControlRequest` (uses discriminated union over `userName` / `groupName` / `servicePrincipalName`), `PermissionsResponse` with `accessControlList`, `setObjectPermissions`, `getObjectPermissions`, `updateObjectPermissions`, `getPermissionLevels`. - `grants` package: free-form `privileges: string[]` (no enum), `principal: string` (single field, doesn't distinguish user vs group vs SP), `PrivilegeAssignment`, `getPermissions`, `updatePermissions`. @@ -86,25 +68,25 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi - **Suggested name:** Rename one of the packages to make the disambiguation clear, e.g. `grants` → `unity-catalog-grants` or `uc-privileges`; `permissions` → `workspace-permissions` or `workspace-acl`. Or — at minimum — keep their public types non-overlapping (currently both export "Permission..."-prefixed types). - **Rationale:** The two packages cover non-overlapping concrete operations (UC grants vs workspace-object ACLs) but use heavily overlapping vocabulary. This is an enormous discoverability hazard. -### 11. `PermissionsChange` (type) — `src/v1/model.ts:165` +### 8. `PermissionsChange` (type) — `src/v1/model.ts:165` - **Why weird:** Inconsistent vocabulary with the rest of the file. The package mostly uses `Privilege*` (`PrivilegeAssignment`, `EffectivePrivilege`, `EffectivePrivilegeAssignment`, `ListPrivilegeAssignments...`) but the change-payload is named `PermissionsChange` (plural "Permissions", not "Privilege"). The change describes adding/removing entries to `add: string[]` / `remove: string[]` where the strings are privileges. So the type is really a `PrivilegeChange` or `PrivilegeAssignmentChange`. - **Category:** 17 (inconsistent vocabulary), 12 (concept overlap with `permissions` package). -- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file — see #7). -- **Rationale:** See #7. +- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file — see #4). +- **Rationale:** See #4. -### 12. `principal` (field, multiple) — `src/v1/model.ts:21,33,69,107,135,170,190` +### 9. `principal` (field, multiple) — `src/v1/model.ts:21,33,69,107,135,170,190` - **Why weird:** The field `principal: string` appears 7 times across the file. The doc string is "user email address or group name" — but the file separately exposes `principalId: number` (line 182, 194). So the type system has no way to tell whether `principal` is an email, a group name, or what — and the `permissions` package solves the same problem with a discriminated union (`{ $case: 'userName' | 'groupName' | 'servicePrincipalName', ... }`). The `grants` package punts. - **Category:** 1 (vague), 15 (generic field name), 19 (underspecified identifier), 12 (overlap with `permissions` package's typed approach). - **Suggested name:** `principalName` (matching the `permissions` package, which uses `principalName?: { $case: 'userName' | ... }`); or, better, model the same discriminated union here. - **Rationale:** "Principal" is overloaded across identity systems (security principal, business principal, mathematical principal, principal-of-the-school). The doc-comment is the only thing distinguishing this from `principalId`. -### 13. `principalId` field — `src/v1/model.ts:182,194` +### 10. `principalId` field — `src/v1/model.ts:182,194` - **Why weird:** Two interpretation issues. (1) The doc-comment for `PermissionsChange.principalId` calls it "an opaque internal ID that identifies the principal whose privileges should be removed" — meaning it's a TEMPORARY identifier only valid for deletes of deleted principals. The doc-comment for `PrivilegeAssignment.principalId` calls it the "unique identifier of the principal" — meaning a stable canonical ID. Same field name, two unrelated semantics. (2) The type is `number` — which is dangerous for large UC principal IDs (UC IDs are 64-bit). JS `number` only safely represents integers up to 2^53. - **Category:** 6 (misleading: same name, different semantics), 19 (underspecified ID), 16 (field contradicts type domain: a 64-bit ID typed as `number`). - **Suggested name:** Split into `removalToken` (for `PermissionsChange`, since its only purpose is removing a deleted principal) and keep `principalId` (for `PrivilegeAssignment`). And consider `bigint` or `string` for the type. - **Rationale:** Two different concepts wearing the same name is a footgun. The `number` type for principal IDs is a JS-platform-specific overflow risk; the Go SDK uses `int64`, which JS cannot losslessly represent. -### 14. `securableFullName` vs `fullName` inconsistency — `src/v1/model.ts:31,67,201` vs `105,133` +### 11. `securableFullName` vs `fullName` inconsistency — `src/v1/model.ts:31,67,201` vs `105,133` - **Why weird:** The path-parameter field for the same securable is named `securableFullName` in `GetEffectivePermissions`, `GetPermissions`, and `UpdatePermissions`; but `fullName` in `ListEffectivePrivilegeAssignmentsRequest` and `ListPrivilegeAssignmentsRequest`. Same value, same wire location, two different field names. The client then constructs the URL using `req.securableFullName` (e.g. line 86) or `req.fullName` (e.g. line 179) depending on which type — but they're going to the same logical endpoint. - **Category:** 17 (inconsistent action verbs / naming), 15 (generic field name). - **Suggested name:** Pick one, ideally `fullName` (since `securableType` is already context). @@ -114,119 +96,101 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi ## Medium severity -### 15. `EffectivePrivilege.privilege` — `src/v1/model.ts:7` +### 12. `EffectivePrivilege.privilege` — `src/v1/model.ts:7` - **Why weird:** `EffectivePrivilege.privilege` — the field repeats the type name. Inside a `EffectivePrivilege` object, what else could `.privilege` mean? The type is essentially `(privilege, inheritedFromType, inheritedFromName)`. Naming the carrier field after the parent type adds zero info. - **Category:** 20 (type-suffix tautology), 1 (vague — the doc says "The privilege assigned to the principal" but the type is `string`, untyped). -- **Suggested name:** `name` (since this is the name of a single privilege like `"SELECT"`), or — if keeping `privilege` — change the type to a proper enum (see #19). +- **Suggested name:** `name` (since this is the name of a single privilege like `"SELECT"`), or — if keeping `privilege` — change the type to a proper enum (see #16). - **Rationale:** A field on `X` named `x` is canonically a code smell. -### 16. `EffectivePrivilege.inheritedFromType` — `src/v1/model.ts:12` +### 13. `EffectivePrivilege.inheritedFromType` — `src/v1/model.ts:12` - **Why weird:** Type is `string`, but the doc says "type of the object that conveys this privilege via inheritance" — i.e. a securable type like `CATALOG`, `SCHEMA`, `TABLE`. The package elsewhere talks about `securableType` (also `string`), but there's no enum and no link. A more typed approach would be `SecurableType` (an enum). The name promises a typed handle but the field is free-form text. - **Category:** 6 (misleading: name implies type, value is string), 19 (underspecified). - **Suggested name:** `inheritedFromSecurableType` (clarifies what kind of type) — and ideally typed as an enum. - **Rationale:** "Type" without qualification is ambiguous; consistent with how `securableType` is named elsewhere in the file, this field should be a securable type. -### 17. `EffectivePrivilege.inheritedFromName` — `src/v1/model.ts:17` +### 14. `EffectivePrivilege.inheritedFromName` — `src/v1/model.ts:17` - **Why weird:** Generic "name" field on a non-`Name`-typed thing. Pair with `inheritedFromType` it's clear, but in isolation `inheritedFromName: string | undefined` is just "some string". Doc-comment is required reading. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `inheritedFromFullName` (matching `securableFullName` elsewhere). - **Rationale:** Internal consistency — the rest of the file uses `fullName` / `securableFullName`. -### 18. `maxResults` vs `pageSize` — `src/v1/model.ts:47,83,114,151` +### 15. `maxResults` vs `pageSize` — `src/v1/model.ts:47,83,114,151` - **Why weird:** `GetEffectivePermissions` (line 47) and `GetPermissions` (line 83) use `maxResults`; `ListEffectivePrivilegeAssignmentsRequest` (line 114) and `ListPrivilegeAssignmentsRequest` (line 151) use `pageSize`. Two field names for the same concept — server-side page length cap. The 60+ lines of identical doc-comments (lines 35-46 and 71-82) explaining the "150 minimum" rule appear under both names with no link or cross-reference. - **Category:** 17 (inconsistent action verbs / naming), 12 (duplicate concept within one file). - **Suggested name:** Pick one: `pageSize` (more idiomatic for paginated APIs) or `maxResults`. Apply uniformly. - **Rationale:** Internal inconsistency forces users to look up the right name per type. -### 19. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,172,174,192`) +### 16. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,172,174,192`) - **Why weird:** Every privilege is typed as a free-form `string`. The Go SDK and Databricks UC API have a fixed enum of privilege names (`SELECT`, `MODIFY`, `USE_CATALOG`, `USE_SCHEMA`, `EXECUTE`, `CREATE_*`, `READ_VOLUME`, `WRITE_VOLUME`, etc.). The TS SDK exposes them as bare strings with no autocomplete, no type-checking, no documentation. A typo like `"SELCT"` will silently round-trip to the server. - **Category:** 19 (underspecified), 1 (vague: `string` doesn't constrain meaning). - **Suggested name:** Define a `Privilege` enum (or string literal union). At minimum document the valid values inline. - **Rationale:** Type-safety is the entire point of TypeScript. The audit task explicitly flags "long enum values (many privilege values)" — the irony is that grants HAS the most privilege values of any UC operation and exposes ZERO of them as types. -### 20. `PermissionsChange.add` / `PermissionsChange.remove` — `src/v1/model.ts:172,174` +### 17. `PermissionsChange.add` / `PermissionsChange.remove` — `src/v1/model.ts:172,174` - **Why weird:** Bare verb-shaped field names with no clarifying suffix. `add: string[]` and `remove: string[]` on a `PermissionsChange` type — what are they adding to and removing from? The doc-comments tell you ("The set of privileges to add"), but the field names are anonymous. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `addPrivileges` / `removePrivileges`, or `granted` / `revoked`. - **Rationale:** Common to see `add` / `remove` in change-set APIs (e.g. Kubernetes RBAC, AWS IAM), but those typically pair with a typed item collection. A bare `add: string[]` carries no information. -### 21. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` +### 18. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` - **Why weird:** Three-word PascalCase name (`Effective` + `Privilege` + `Assignment`) that on first read parses as "Effective Privilege" / "Assignment" but on second read could parse as "Effective" / "Privilege Assignment". The conceptual model is "the privilege assignment that effectively applies (because of inheritance)", which the doc-comment confirms — but the name doesn't disambiguate. - **Category:** 7 (overly verbose). - **Suggested name:** Possibly leave as-is; alternative is `EffectiveAssignment` (drop `Privilege` since `Assignment` is privilege-specific in this file). - **Rationale:** Marginal; flagged for symmetry with `EffectivePrivilege` (line 5). -### 22. `effectivePrivilegeAssignments` (field name) — `src/v1/model.ts:121` +### 19. `effectivePrivilegeAssignments` (field name) — `src/v1/model.ts:121` - **Why weird:** 30-character camelCase field name. Inside `ListEffectivePrivilegeAssignmentsResponse`, the only payload field. Could safely be shortened to `assignments` or `items` since the surrounding type name carries the rest of the qualifier. - **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name repeats type-name fragment). - **Suggested name:** `assignments` or `items`. - **Rationale:** Field names that re-state the parent type are noise. -### 23. `privilegeAssignments` (field name, multiple) — `src/v1/model.ts:60,98,157,209` -- **Why weird:** Same problem as #22, on the non-effective side. Field name `privilegeAssignments` appears as the sole payload field on `GetEffectivePermissions_Response`, `GetPermissions_Response`, `ListPrivilegeAssignmentsResponse`, and `UpdatePermissions_Response`. Could be `assignments` everywhere. +### 20. `privilegeAssignments` (field name, multiple) — `src/v1/model.ts:60,98,157,209` +- **Why weird:** Same problem as #19. Field name `privilegeAssignments` appears as the sole payload field on multiple response types. Could be `assignments` everywhere. - **Category:** 7, 20. - **Suggested name:** `assignments`. -- **Rationale:** See #22. +- **Rationale:** See #19. -### 24. `getEffectivePermissions` (method) — `src/v1/client.ts:82` -- **Why weird:** Method returns `GetEffectivePermissions_Response` (note the underscore — see #4). The method-name-as-verb is fine, but the type contract has the proto-style wart. Also, the doc-comment notes "Unpaginated calls will be deprecated soon" — so this method exists as a soon-to-be-deprecated mirror of `listEffectivePrivilegeAssignments`. Why ship both in the same v1? -- **Category:** 12 (duplicate concept — see #9), Observation. +### 21. `getEffectivePermissions` (method) — `src/v1/client.ts:82` +- **Why weird:** The doc-comment notes "Unpaginated calls will be deprecated soon" — so this method exists as a soon-to-be-deprecated mirror of `listEffectivePrivilegeAssignments`. Why ship both in the same v1? +- **Category:** 12 (duplicate concept — see #6), Observation. - **Suggested name:** Mark as `@deprecated` in JSDoc (currently the deprecation note is just plain text inside the doc-comment, lines 77-78 — not an actual `@deprecated` tag). - **Rationale:** Tooling like IDEs and ts-doc strikes through deprecated methods only when the `@deprecated` tag is used. -### 25. `getPermissions` (method) — `src/v1/client.ts:129` -- **Why weird:** Same as #24 — soon-to-be-deprecated unpaginated mirror of `listPrivilegeAssignments`. +### 22. `getPermissions` (method) — `src/v1/client.ts:129` +- **Why weird:** Same as #21 — soon-to-be-deprecated unpaginated mirror of `listPrivilegeAssignments`. - **Category:** 12, Observation. - **Suggested name:** Add `@deprecated` JSDoc tag. -- **Rationale:** See #24. +- **Rationale:** See #21. -### 26. `securableType: string` — model-wide (5 occurrences) -- **Why weird:** Same concept as #19 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. +### 23. `securableType: string` — model-wide (5 occurrences) +- **Why weird:** Same concept as #16 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. - **Category:** 19 (underspecified), 1 (vague). - **Suggested name:** Define a `SecurableType` enum. -- **Rationale:** See #19. +- **Rationale:** See #16. -### 27. `nextPageToken` (field, multiple) — `src/v1/model.ts:58,96,123,162` -- **Why weird:** Same identifier appears in 4 response types. Fine in isolation, but the doc-comment "__page_token__ should be set to this value for the next request (for the next page of results)" is copy-pasted verbatim 4 times — including the suspicious `__page_token__` (double-underscore, suggesting wire-format documentation) which makes no sense for TS consumers using `pageToken`. -- **Category:** Observation (mostly consistency), 6 (misleading: `__page_token__` in doc). -- **Suggested name:** No rename needed, but doc-comments should reference TS field name `pageToken`, not `__page_token__`. -- **Rationale:** Doc string consistency. - -### 28. `includeDeletedPrincipals` — `src/v1/model.ts:87,109,136` -- **Why weird:** Verbose camelCase boolean. Reasonable but flagged because it's missing from `GetEffectivePermissions` (where the analogous feature would also make sense) but present on `GetPermissions` and both `List*Request` types. Inconsistent feature parity (see also #9). +### 24. `includeDeletedPrincipals` — `src/v1/model.ts:87,109,136` +- **Why weird:** Verbose camelCase boolean. Reasonable but flagged because it's missing from `GetEffectivePermissions` (where the analogous feature would also make sense) but present on `GetPermissions` and both `List*Request` types. Inconsistent feature parity (see also #6). - **Category:** 17 (inconsistency), 7 (verbose). - **Suggested name:** `includeDeleted` (shorter). - **Rationale:** Consistency issue more than naming issue. -### 29. `Client` — `src/v1/client.ts:49` +--- + +## Low severity + +### 25. `Client` — `src/v1/client.ts:49` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts` re-exports `Client` (line 3), so users write `import { Client } from '@databricks/sdk-grants/v1'`. Same name appears in every generated package — you can't have multiple grants/catalogs/etc. clients in one import without aliasing. - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `GrantsClient` (or whatever the package-specific name is). - **Rationale:** Convention in `@aws-sdk/*`, `@google-cloud/*`, `@azure/*` is service-prefixed client class names for exactly this reason. ---- - -## Low severity - -### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:44` +### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:44` - **Why weird:** `Segment` is a generic word; without the doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 31. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append`). Dead-looking export. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Remove if generator default. -- **Rationale:** Generator emits the same helper into every package even when unused. - -### 32. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / Web Streams. The function reads a `ReadableStream` into a single buffer. -- **Category:** 1 (vague), 14 (Go-style: `io.ReadAll` is a Go idiom). -- **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. -- **Rationale:** Cross-package consistency. - -### 33. `HttpCallOptions` — `src/v1/utils.ts:15` +### 27. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix), 17 (inconsistent). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -236,6 +200,6 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi ## Observations -### 34. `Client` constructor: `Host is required.` — `src/v1/client.ts:60` +### 28. `Client` constructor: `Host is required.` — `src/v1/client.ts:60` Error message thrown but no client name in the message. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. - **Category:** Observation. diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md index 90b955c4..e11fd3ac 100644 --- a/.agent/naming-audit/iam.md +++ b/.agent/naming-audit/iam.md @@ -11,24 +11,23 @@ and resolve-by-external-id flows that bridge the customer IdP to Databricks. | Severity | Count | | -------- | ----- | -| High | 18 | -| Medium | 22 | -| Low | 16 | +| High | 15 | +| Medium | 21 | +| Low | 15 | | Observation | 5 | -| **Total** | **61** | +| **Total** | **56** | Three dominant themes emerged. **First, the package ships every method, request, and a handful of enums in two parallel forms — `*` and `*Proxy` — that differ only in whether `accountId` is supplied by the caller or by the URL routing layer.** Roughly 40% of the public type surface is mechanical duplication (44 request types collapse to about 22 unique shapes). **Second, -the package leaks proto conventions deep into TypeScript:** every enum has a -`_UNSPECIFIED` zero value, two enums use Proto-style nested names with -underscores (`WorkspaceAccessDetail_AccessType`, `User_Name`), and 31 of 38 -JSDoc blocks contain literal `` markup. **Third, naming is -inconsistent across status fields, parent-account fields, and the `Detail` -suffix** — `accountUserStatus`, `accountSpStatus`, `workspaceIdentityStatus`, -and `status` all describe the same `State` enum across types; `accountId` is +the package leaks proto conventions into JSDoc and method shape:** every enum +has a `_UNSPECIFIED` zero value and 31 of 38 JSDoc blocks contain +literal `` markup. **Third, naming is inconsistent across status +fields, parent-account fields, and the `Detail` suffix** — +`accountUserStatus`, `accountSpStatus`, `workspaceIdentityStatus`, and +`status` all describe the same `State` enum across types; `accountId` is documented as "parent account ID for X" inconsistently; and the `Detail` suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / `WorkspaceIdentityDetail` adds no information beyond Java-RPC habit. @@ -102,7 +101,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / the same enum domain across five types. - **Suggestion:** Rename the enum to `ActivityStatus` (or `PrincipalStatus`). Standardize the field name to `status` everywhere. Drop the - `STATE_UNSPECIFIED` value (see H10). + `STATE_UNSPECIFIED` value (see H9). - **Rationale:** A 3-letter enum with 2 values and the name `State` is a textbook example of a name that says nothing about the domain. JSDoc-only context is not enough. @@ -118,63 +117,27 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / type-suffix tautology, while `PrincipalType.USER` reads cleanly. The two styles in one enum are inconsistent. - **Suggestion:** Drop the `PRINCIPAL_TYPE_` prefix from UNSPECIFIED (or - drop the whole UNSPECIFIED member — see H10). Standardize on + drop the whole UNSPECIFIED member — see H9). Standardize on `PrincipalType.USER` / `.SERVICE_PRINCIPAL` / `.GROUP`. - **Rationale:** TypeScript already namespaces values under the enum type. Repeating the enum name in one member only is worse than either consistently prefixing or consistently bare. -### H5. `WorkspaceAccessDetail_AccessType` and `WorkspaceIdentityDetail_AssignmentType` use proto-style underscored names -- **File:** `model.ts:67-74, 78-85`, `index.ts:13-14` -- **Category:** 4, 14 (underscore in TS identifier; Go/Java/proto-style) -- **Issue:** Two enums with proto-style nested names use underscore - separators in the TS identifier: - `WorkspaceAccessDetail_AccessType`, `WorkspaceIdentityDetail_AssignmentType`. - Both require a `// eslint-disable-next-line @typescript-eslint/naming-convention` - comment to compile, which signals the convention is wrong. They are also - re-exported by name from `index.ts`. The two enums also have identical - value sets — `ACCESS_TYPE_UNSPECIFIED`/`ASSIGNMENT_TYPE_UNSPECIFIED`, - `DIRECT`, `INDIRECT` — and identical JSDoc semantics ("direct" = - principal is assigned, "indirect" = via group). They are the same enum - conceptually. -- **Suggestion:** Flatten and unify. `type AssignmentMode = 'DIRECT' | 'INDIRECT'` - (a union type or a single enum `AssignmentMode`). Use it for both - `WorkspaceAccessDetail.accessType` and - `WorkspaceIdentityDetail.assignmentType` (and rename the fields to - `mode` or both to `assignmentMode`). -- **Rationale:** Two enums with the same shape and the same meaning, both - spelled with proto-style underscores, is duplication on top of - convention-violation. - -### H6. `User_Name` nested type uses proto-style underscored name -- **File:** `model.ts:961-964`, `index.ts:18` (exported as `User_Name`) -- **Category:** 4, 14 (underscore in TS identifier; proto-style) -- **Issue:** `User_Name` is a nested message type carrying `givenName` and - `familyName`. The name violates TS conventions (requires - `// eslint-disable-next-line` to compile). -- **Suggestion:** Rename to `UserName` or, better, `PersonName` (since - `userName` is overloaded with `username` two lines up — see H7). Even - inlining `givenName?: string; familyName?: string` onto `User` would be - cleaner since the nested type has no other use. -- **Rationale:** Proto nested-message names should be flattened in TS. The - underscore is the strongest visual cue that the generator did not idiomatize. - -### H7. `User.username` vs `User.name: User_Name` — name field collision +### H5. `User.username` vs `User.name` — name field collision - **File:** `model.ts:946-958, 961-964` - **Category:** 6, 10 (misleading; reserved-word-style collision) - **Issue:** `User` has both `username` (string, email-like login identifier - per the JSDoc) and `name` (a `User_Name` struct with `givenName`/`familyName`). + per the JSDoc) and `name` (a nested struct with `givenName`/`familyName`). In English `name` and `username` are near-synonyms and users routinely - conflate them. Worse, `User_Name` is a separate type whose name is itself - `Name`. A developer auto-completing `user.` sees two `*name*` fields with - no hint at the difference. -- **Suggestion:** Rename `User.name` to `User.fullName` (or `personName`, - matching the suggested type rename in H6). Rename `User.username` to - `User.email` if the value is always an email (the JSDoc says - "Username/email of the user"), or `User.loginName` otherwise. + conflate them. A developer auto-completing `user.` sees two `*name*` + fields with no hint at the difference. +- **Suggestion:** Rename `User.name` to `User.fullName` (or `personName`). + Rename `User.username` to `User.email` if the value is always an email + (the JSDoc says "Username/email of the user"), or `User.loginName` + otherwise. - **Rationale:** Disambiguates two semantically distinct identifiers. -### H8. `accountSpStatus` field uses cryptic abbreviation `Sp` +### H6. `accountSpStatus` field uses cryptic abbreviation `Sp` - **File:** `model.ts:818` - **Category:** 5, 6 (cryptic abbreviation; misleading) - **Issue:** `ServicePrincipal.accountSpStatus?: State`. `Sp` is a Databricks @@ -189,7 +152,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Rationale:** Abbreviation `Sp` is opaque to external developers and inconsistent with the spelled-out `User` and `Identity` siblings. -### H9. `WorkspaceAccessDetail`, `WorkspaceAssignmentDetail`, `WorkspaceIdentityDetail` — three overlapping "Detail" types +### H7. `WorkspaceAccessDetail`, `WorkspaceAssignmentDetail`, `WorkspaceIdentityDetail` — three overlapping "Detail" types - **File:** `model.ts:967-1004`, plus all 17 method types they appear in - **Category:** 1, 12, 7 (vague generic suffix; duplicate concept; verbose) - **Issue:** Three top-level types with the `Detail` suffix model overlapping @@ -212,7 +175,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / (`getWorkspaceAccessDetail`, `listWorkspaceAssignmentDetails`, `updateWorkspaceIdentityDetail`, …) inherit the noise. -### H10. Every enum has a `_UNSPECIFIED` zero value +### H8. Every enum has a `_UNSPECIFIED` zero value - **File:** `model.ts:9, 14, 25, 34, 43, 52, 59, 69, 80` - **Category:** 2, 18 (redundant enum prefix; long enum values) - **Issue:** Nine of nine enums in the package have an `UNSPECIFIED` member @@ -231,7 +194,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Rationale:** This is the single highest-impact reduction in the package. 9 enum members removed × every enum value enumeration in user code. -### H11. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly +### H9. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly - **File:** `model.ts:51-55` - **Category:** 1, 14 (vague; Google/proto-style) - **Issue:** Values are `WORKSPACE_ACCESS_DETAIL_VIEW_UNSPECIFIED`, `BASIC`, @@ -244,10 +207,10 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Suggestion:** `enum FieldView { BASIC = 'BASIC', FULL = 'FULL' }`, reusable across the SDK. Or rename to `WorkspaceAccessView` and document what each enum value includes/excludes. -- **Rationale:** `Detail` in the name is the same `Detail` flagged in H9 and +- **Rationale:** `Detail` in the name is the same `Detail` flagged in H7 and carries no extra meaning. -### H12. `internalId` vs `principalId` vs `groupId` — three overlapping ID names for "the Databricks-internal numeric ID" +### H10. `internalId` vs `principalId` vs `groupId` — three overlapping ID names for "the Databricks-internal numeric ID" - **File:** `model.ts:122, 226, 228, 244, 252, 260, 271, 285, 296, 326, 329, 344, 353, 386, 407, 412, 423, 432, 442, 448, 583, 597, 833, 845, 855, 867, 884, 903` - **Category:** 6, 19 (misleading; underspecified ID) - **Issue:** Same numeric ID concept appears under three different field @@ -270,7 +233,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / of which name refers to what; the wire is consistent (`principal_id`, `group_id`, `internal_id`), so the TS field name choices are real. -### H13. `principalType: PrincipalType` — type-suffix tautology pattern +### H11. `principalType: PrincipalType` — type-suffix tautology pattern - **File:** `model.ts:99, 304, 974, 990, 999` - **Category:** 20 (type-suffix tautology) - **Issue:** The field `principalType: PrincipalType | undefined` appears on @@ -283,7 +246,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / `principal: PrincipalKind` is even cleaner). - **Rationale:** Tautology adds visual noise without adding meaning. -### H14. `Group.groupName` — same kind of tautology +### H12. `Group.groupName` — same kind of tautology - **File:** `model.ts:461` - **Category:** 20 (type-suffix tautology) - **Issue:** `Group.groupName` reads `group.groupName`. The `group` prefix is @@ -297,7 +260,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / wire form is `group_name` but the TS field name need not echo it. The field is also used as `displayName` in JSDoc. -### H15. `ServicePrincipal.internalId` doc says `Internal service principal ID of the service principal` — tautology + comment problem +### H13. `ServicePrincipal.internalId` doc says `Internal service principal ID of the service principal` — tautology + comment problem - **File:** `model.ts:809-810` - **Category:** 20, 6 (tautology; misleading) - **Issue:** The JSDoc on `ServicePrincipal.internalId` reads "Internal @@ -310,7 +273,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Rationale:** Three sibling doc strings should not each repeat the resource name inside themselves. -### H16. `AccountAccessIdentityRule.name` is a URL path, not a name +### H14. `AccountAccessIdentityRule.name` is a URL path, not a name - **File:** `model.ts:100-104` - **Category:** 6, 15, 16, 19 (misleading; generic field losing meaning; field contradicting domain; underspecified) - **Issue:** `name` is documented as @@ -323,22 +286,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Rationale:** Half the IAM-API integration bugs are wrong-format resource paths; the type system can encode this. -### H17. `Group.externalId` doc capitalization `ExternalId` (sentence-case identifier name) -- **File:** `model.ts:459, 952, 828, 811` -- **Category:** 3, 14 (acronym casing; Go-style) -- **Issue:** The JSDoc on `Group.externalId`, `User.externalId`, - `ServicePrincipal.externalId`, and `TransitiveParentGroup.externalId` begins - with the literal `ExternalId of the X in the customer's IdP.` — capitalized - identifier name as the first word, not English. The same pattern bleeds - through to the Go-style sentence comment. Should be either "External ID - of …" (English) or use the TS field name as code (`externalId`) in - backticks. -- **Suggestion:** Rewrite as "External ID of the {resource} in the - customer's identity provider." consistently across all four types. -- **Rationale:** A small but persistent rendering issue across the type - surface. - -### H18. `parent` field name on rule endpoints — Google AIP convention leaks into TS +### H15. `parent` field name on rule endpoints — Google AIP convention leaks into TS - **File:** `model.ts:113, 219, 318, 470` - **Category:** 1, 14, 19 (vague/generic; Google-style; underspecified ID) - **Issue:** `CreateAccountAccessIdentityRuleRequest.parent`, @@ -369,7 +317,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / `ListWorkspaceAssignmentDetailsProxyRequest` (42), `GetWorkspaceAssignmentDetailProxyRequest` (40). Plus the imports list in `client.ts` repeats them, doubling the noise. -- **Suggestion:** Once H1 collapses the proxy duplication and H9 drops +- **Suggestion:** Once H1 collapses the proxy duplication and H7 drops `Detail`, these become `CreateWorkspaceAssignmentRequest` etc. — about 30 chars each. - **Rationale:** Length itself is not a sin, but `42 chars × 2 × @@ -454,7 +402,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **File:** `model.ts:199, 209, 916, 930` - **Category:** 20 (type-suffix tautology) - **Issue:** `CreateWorkspaceAssignmentDetailRequest.workspaceAssignmentDetail?: WorkspaceAssignmentDetail | undefined`. -- **Suggestion:** Rename field to `assignment` (after H9 drops `Detail`, +- **Suggestion:** Rename field to `assignment` (after H7 drops `Detail`, the type is `WorkspaceAssignment` and `assignment` reads naturally). - **Rationale:** Same as M6. @@ -485,7 +433,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Suggestion:** Standardize to "Databricks account ID of the parent account." or just "Parent Databricks account ID." - **Rationale:** Consistency + grammar; the `` template marker - also needs to go (see M13). + also needs to go (see M12). ### M12. `` proto template markup in 31 of 38 JSDoc blocks - **File:** `model.ts` everywhere, e.g. `122, 140, 148, 154, 161, 175-185` @@ -521,7 +469,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / account for which to ..." — no mention of "parent". A consumer reading IntelliSense gets `parent: string` plus "The account ...", which is confusing. -- **Suggestion:** Make the JSDoc echo the AIP convention or rename per H18. +- **Suggestion:** Make the JSDoc echo the AIP convention or rename per H15. - **Rationale:** Field and docstring should agree on naming. ### M15. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` @@ -576,7 +524,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **File:** `model.ts:529, 540` - **Category:** 6 (misleading) - **Issue:** Doc says "group name", but the actual field name is `groupName` - on `Group` (per H14) and the JSON wire is `group_name`. The SCIM-style + on `Group` (per H12) and the JSON wire is `group_name`. The SCIM-style filter syntax (`groupName eq "engineering"`) is not documented. A consumer must guess. - **Suggestion:** Document the filter language with one example. @@ -604,19 +552,6 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / semantic prominently. - **Rationale:** Method names should not hide write side-effects. -### M22. `ListWorkspaceAccessDetailsLocalRequest` paginates but has no filter — asymmetric with `ListWorkspaceAccessDetailsRequest` -- **File:** `model.ts:677-694` -- **Category:** 6 (misleading) -- **Issue:** `ListWorkspaceAccessDetailsLocalRequest` has `pageSize` + - `pageToken` but no `filter`. The non-local variant also has no `filter`, - but every other `List*` request in the file does. The "Local" variant - description is also the placeholder "TODO: Write description later" with - zero documentation of what it lists. -- **Suggestion:** Document explicitly; add `filter` if the server supports - it on the local route; document the difference between the two list - endpoints. -- **Rationale:** API completeness. - --- ## Low-severity findings @@ -698,8 +633,8 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **File:** `model.ts:460-461` - **Category:** 6 (misleading) - **Issue:** The field is `groupName` but the doc calls it `displayName`. - See H14. -- **Suggestion:** Rename per H14. + See H12. +- **Suggestion:** Rename per H12. - **Rationale:** Consistency. ### L9. `ServicePrincipal` JSDoc — "The details of a ServicePrincipal resource." @@ -770,18 +705,6 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Suggestion:** Change docs to say `pageToken`. - **Rationale:** Public doc should match public field name. -### L16. `assignmentType` on `WorkspaceIdentityDetail` vs `accessType` on `WorkspaceAccessDetail` -- **File:** `model.ts:975, 1003` -- **Category:** 12, 17 (duplicate concept; verb inconsistency) -- **Issue:** Two sibling types with similar fields: - `WorkspaceAccessDetail.accessType: WorkspaceAccessDetail_AccessType`, - `WorkspaceIdentityDetail.assignmentType: WorkspaceIdentityDetail_AssignmentType`. - Both enums have values `DIRECT`/`INDIRECT`. Field names disagree; - enum names disagree; enum values agree. -- **Suggestion:** Per H5, unify the enum. Then pick one field name - (`assignmentMode` or just `mode`). -- **Rationale:** Same as H5 — at the field level. - --- ## Observations (not findings, but worth noting) @@ -790,7 +713,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **File:** `client.ts:1682, 1719, 1750, 1829, 1864, 1898, 1922, 1941, 1966, 1991, 2028, 2070, 2116, 2157, 2182` - **Issue:** The server URL paths use `workspaceAccessDetails`, `workspaceAssignmentDetails`, `workspaceIdentityDetails` — proto/Go RPC - pattern. The SDK reflects the server names. Renaming the TS types per H9 + pattern. The SDK reflects the server names. Renaming the TS types per H7 does not change the wire; the SDK can have nicer TS names while still hitting `workspaceAccessDetails` URLs. @@ -829,16 +752,12 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / 1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O4, O5).** This is the largest single improvement and ~halves the public type surface. -2. **Drop `_UNSPECIFIED` enum members (H10, H4).** 9 dead enum values +2. **Drop `_UNSPECIFIED` enum members (H8, H4).** 9 dead enum values removed; users no longer write `=== State.STATE_UNSPECIFIED` accidentally. 3. **Replace `` template markup (M12).** Generator-side fix. -4. **Flatten proto-style nested names (`User_Name`, `WorkspaceAccessDetail_AccessType`, - `WorkspaceIdentityDetail_AssignmentType`) (H5, H6).** Removes - eslint-disable comments and underscore-in-identifier violations. -5. **Standardize ID field names (H12, L1, L11) and status field names (H3, - H8).** One name per concept. -6. **Remove type-suffix tautology fields (H13, H14, M6–M10).** Single-token +4. **Standardize ID field names (H10, L1, L11) and status field names (H3, + H6).** One name per concept. +5. **Remove type-suffix tautology fields (H11, H12, M6–M10).** Single-token field names where the type already carries the kind. -7. **Drop the `Detail` suffix from the Workspace* types (H9).** And add an - `assignmentMode`/`mode` field via H5. -8. **Rewrite the placeholder TODO JSDocs (M13, M15).** Generator + spec fix. +6. **Drop the `Detail` suffix from the Workspace* types (H7).** +7. **Rewrite the placeholder TODO JSDocs (M13, M15).** Generator + spec fix. diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md index 86d63ec3..eef22b47 100644 --- a/.agent/naming-audit/indexes.md +++ b/.agent/naming-audit/indexes.md @@ -3,12 +3,12 @@ **Path:** `packages/indexes/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Vector Search index management — CRUD for `VectorIndex` (Delta-Sync or Direct-Access subtypes), data upsert/delete on direct-access indexes, vector/text/hybrid query, scan, pagination, and sync trigger. Routes under `/api/2.0/vector-search/indexes`. -**Total weird names flagged:** 38 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | -| High | 13 | +| High | 12 | | Medium | 17 | | Low | 6 | | Observation | 2 | @@ -29,7 +29,7 @@ ### 3. `MiniVectorIndex` — `src/v1/model.ts:252` - **Why weird:** "Mini" is a cryptic informal qualifier. No JSDoc explains what it means. By inspection it is a list-view subset of `VectorIndex` (same fields), used as the element type in `ListVectorIndexResponse.vectorIndexes`. Industry conventions for "the lighter view returned by a list endpoint" include `Summary`, `ListItem`, `Brief`, `Ref`, `Preview` — never `Mini`. -- **Category:** 5 (cryptic abbreviation), 1 (vague qualifier), 14 (proto-style name leaking). +- **Category:** 5 (cryptic abbreviation), 1 (vague qualifier). - **Suggested name:** `VectorIndexSummary` or `VectorIndexListItem`. Add JSDoc explaining why it differs from `VectorIndex` (in fact, the fields are identical in this version — see #4). - **Rationale:** `Mini` does not convey "subset of the full type returned by list operations". Naming the type after its role (`Summary`/`ListItem`) makes the relationship to `VectorIndex` discoverable. @@ -40,7 +40,7 @@ - **Rationale:** Duplicating ~25 lines of type definition with no semantic distinction is a maintenance hazard. ### 5. `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:109-142` vs `model.ts:144-177` -- **Why weird:** Two distinct exported types with the same ten fields, same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream protobuf quirk that should be flattened in TS. +- **Why weird:** Two distinct exported types with the same ten fields, same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream quirk that should be flattened in TS. - **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix). - **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec`), or document why the request version differs. If the upstream API truly has divergence, list the diverging fields explicitly. - **Rationale:** The asymmetry with `DirectAccessVectorIndexSpec` (no separate request variant) shows the duplication is gratuitous, not necessary. @@ -75,19 +75,13 @@ - **Suggested name:** `vectorSearchEndpointName` or add JSDoc clarifying it is "the Vector Search endpoint serving this index". The terse `endpointName` is fine *if* combined with type-level JSDoc. - **Rationale:** The package owns a `VectorIndex` resource that is hosted on a *vector-search* endpoint — but a reader who jumps to a method signature sees only `endpointName` and may guess wrong. -### 11. `RerankerConfig_RerankerParameters` — underscore-separated type — `src/v1/model.ts:343` -- **Why weird:** Underscore in a TypeScript type identifier. The file has an `eslint-disable-next-line @typescript-eslint/naming-convention` directive on it (line 342, with the comment "Proto-style nested message name") confirming the lint rule is being suppressed. Same suppression at line 953 for the marshal schema. The type's only field is `columnsToRerank` (already present on the parent's `QueryVectorIndexRequest.columnsToRerank` — model.ts:315). -- **Category:** 4 (underscore in TS identifier), 14 (proto-style name leaking). -- **Suggested name:** `RerankerParameters` (drop the redundant `RerankerConfig_` prefix), or namespace it: `namespace RerankerConfig { export type Parameters = ... }`. -- **Rationale:** The underscore costs a lint suppression in two locations and is a leaky proto abstraction. The `RerankerConfig_` prefix is also redundant with the wrapping type — duplicate name (see #12). - -### 12. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:315` vs `model.ts:344` -- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 315, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 344) inside the nested `RerankerConfig`. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:316-321) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. +### 11. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:315` vs `model.ts:344` +- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 315, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 344) inside the nested reranker parameters type. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:316-321) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. - **Category:** 12 (duplicate concept), 6 (misleading — which one wins?). - **Suggested name:** Drop one, or document the precedence. If one is for input and the other for output/echo, name them accordingly. - **Rationale:** Users will set the wrong field. Worth raising upstream. -### 13. `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` — `model.ts:133-134, 168-169` +### 12. `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` — `model.ts:133-134, 168-169` - **Why weird:** `effective*` prefix usually marks a *response-only* computed field that reflects the inherited/resolved value from policies (see `database` package finding #11). But here these fields appear on the **Request** variant too (`DeltaSyncVectorIndexSpecRequest` lines 167-169). They cannot be both client-supplied *and* server-computed. Also `effectiveUsagePolicyId` has zero JSDoc — line 134/169 are bare. - **Category:** 6 (misleading — "effective" implies output-only on a request type), 17 (inconsistent: budget has JSDoc, usage does not). - **Suggested name:** Either remove the `effective*` fields from the Request variant, or document the read-only contract. Add the missing JSDoc on `effectiveUsagePolicyId`. @@ -95,141 +89,141 @@ ## Medium severity -### 14. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:23-27` +### 13. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:23-27` - **Why weird:** Enum exposes a sentinel value `VECTOR` whose JSDoc reads "Not supported. Use `HYBRID` instead." Exporting unsupported values inflates the enum and forces every consumer to filter or document them away. - **Category:** 6 (misleading: present but not supported), 18 (the value `VECTOR` is also a tautology when inside an enum called `IndexSubtype` describing a vector-search index — every value is a kind of "vector"). - **Suggested name:** Remove `VECTOR` from the enum, or rename the enum to `VectorIndexSubtype` and call the values `FullText | Hybrid`. Either way, eliminate the dead value. - **Rationale:** Unused enum members are bug magnets. -### 15. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:23, 50` +### 14. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:23, 50` - **Why weird:** `IndexSubtype` = `{VECTOR, FULL_TEXT, HYBRID}` (search semantics). `VectorIndexType` = `{DELTA_SYNC, DIRECT_ACCESS}` (data residency / sync model). Both are exposed as `index*Type*` fields. Same prefix word, different axes. Beginner users will conflate them. - **Category:** 6 (misleading: both look like "the type" of the index), 17 (inconsistent naming for two type axes). - **Suggested name:** Rename to disambiguate: `IndexSearchMode` (for subtype) and `IndexBackingType` / `IndexStorageType` (for the DELTA_SYNC/DIRECT_ACCESS axis). Or `IndexSearchKind` and `IndexSyncMode`. - **Rationale:** Two parallel `*Type` enums make the API harder to learn. The current names are technically correct but functionally ambiguous. -### 16. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:34-37` +### 15. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:34-37` - **Why weird:** All four enums (`IndexSubtype`, `PipelineType`, `UpsertDeleteDataStatus`, `VectorIndexType`) use `UPPER_SNAKE_CASE` for member names. Google TS Style Guide §9.3 recommends `UpperCamelCase` for enum members. The codebase is mixed (some enums use camelCase elsewhere). The values are also the wire-protocol strings — wire is `UPPER_SNAKE` legitimately, but the TS *identifier* can be `Triggered` mapping to wire `'TRIGGERED'`. -- **Category:** 3 (acronym/casing inconsistency), 14 (Go/proto-style). +- **Category:** 3 (acronym/casing inconsistency), 14 (Go-style). - **Suggested name:** `PipelineType.Triggered | Continuous`, with explicit `= 'TRIGGERED'` wire values. Or accept the wire-form names and apply them consistently across all packages. - **Rationale:** Style consistency across the workspace; preference for camelCase enum members aligns with the Google TS Style Guide. -### 17. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:204` +### 16. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:204` - **Why weird:** Field name reads as a sentence (`modelEndpointName ForQuery`). JS field-naming convention is noun phrases, not "for"-clauses. Compare with adjacent `embeddingModelEndpointName` (also long, but a noun phrase). - **Category:** 14 (Java-ish "ForX" suffix), 7 (verbose). - **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. - **Rationale:** `for`-clauses in identifiers are uncommon in JS. The renaming aligns it with the adjacent field. -### 18. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:113-115, 149-150, 181, 189` +### 17. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:113-115, 149-150, 181, 189` - **Why weird:** Two parallel array fields on three different types (`DeltaSyncVectorIndexSpec`, `DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`). One holds source text columns to be embedded; the other holds pre-computed vector columns. Both arrays use *different* element types (`EmbeddingSourceColumn` vs `EmbeddingVectorColumn`) — good — but the field names look near-identical at a glance. - **Category:** 6 (visually confusable pair), 15 (the qualifier "Source"/"Vector" is doing all the work). - **Suggested name:** `textColumns` + `vectorColumns`, or `embeddingTextColumns` + `embeddingVectorColumns`. Anything to widen the gap between the two names. - **Rationale:** Pairs of similarly named array fields are a known footgun. A user typing `embedding` will autocomplete the wrong one. -### 19. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:127-141, 161-176` +### 18. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:127-141, 161-176` - **Why weird:** Two fields on the same type, JSDoc says they are aliases ("[Optional] Alias for columns_to_sync. Select the columns to include in the vector index. ... Only one of columns_to_sync or columns_to_index may be specified.") Having two fields that mean the same thing in one struct, where the API expects exactly one to be set, is a recipe for runtime errors. - **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). - **Suggested name:** Deprecate one in the SDK (mark `columnsToSync` as `@deprecated` if `columnsToIndex` is the new canonical), or merge them with a runtime validation. - **Rationale:** API-level aliases are upstream policy, but the SDK should clearly mark the deprecated alias. -### 20. `pipelineId` is an underspecified ID — `model.ts:123, 158` +### 19. `pipelineId` is an underspecified ID — `model.ts:123, 158` - **Why weird:** Field type is `string` with JSDoc "The ID of the pipeline that is used to sync the index." No format documented — is it a UUID, a numeric ID, a path? Compare with `effectiveBudgetPolicyId` which uses the same generic `string` but at least the policy ID is a known Databricks pattern. - **Category:** 19 (underspecified ID), 15 (generic). - **Suggested name:** Keep the name but improve the JSDoc with the expected ID format and a link to the Pipelines API. - **Rationale:** Without format hints, users will struggle to construct the value. -### 21. `effectiveBudgetPolicyId` on a *request* type without JSDoc explanation — `model.ts:133, 168` -- **Why weird:** See finding #13. Specifically, the field is on `DeltaSyncVectorIndexSpec` (response side) *and* `DeltaSyncVectorIndexSpecRequest` (request side). On the request side, "effective" is incoherent — there is no "effective" until the server resolves it. -- **Category:** 6 (misleading on the request side), 14 (proto leak: same field appears in both, even when only meaningful on one). +### 20. `effectiveBudgetPolicyId` on a *request* type without JSDoc explanation — `model.ts:133, 168` +- **Why weird:** See finding #12. Specifically, the field is on `DeltaSyncVectorIndexSpec` (response side) *and* `DeltaSyncVectorIndexSpecRequest` (request side). On the request side, "effective" is incoherent — there is no "effective" until the server resolves it. +- **Category:** 6 (misleading on the request side), 17 (same field appears in both request and response, even when only meaningful on one). - **Suggested name:** On `DeltaSyncVectorIndexSpecRequest`, drop the field (it cannot be set), or rename to `budgetPolicyIdOverride`. -- **Rationale:** See #13. +- **Rationale:** See #12. -### 22. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:397` +### 21. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:397` - **Why weird:** `UpsertDataVectorIndexRequest.inputsJson: string` is "JSON string representing the data to be upserted." The TS surface forces the caller to call `JSON.stringify()` themselves, then the marshaling layer wraps the request body in `JSON.stringify(...)` *again*. Double-encoded payloads are a well-known JSON antipattern. - **Category:** 6 (misleading — the field is JSON-in-JSON), 1 (generic — "inputs" tells you nothing about *what*). - **Suggested name:** Expose as `inputs: JsonValue[]` (or whatever the row shape is) and let the SDK serialize, OR keep `inputsJson` but rename to `inputsJsonString` and document the double-encoding. -- **Rationale:** Same problem with `filtersJson` (see #23) and `schemaJson` (see #24). All three are wire-protocol leaks that should be normalized at the SDK boundary. +- **Rationale:** Same problem with `filtersJson` (see #22) and `schemaJson` (see #23). All three are wire-protocol leaks that should be normalized at the SDK boundary. -### 23. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:305` -- **Why weird:** Same JSON-in-JSON pattern as #22. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. +### 22. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:305` +- **Why weird:** Same JSON-in-JSON pattern as #21. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. - **Category:** 6 (misleading), 1 (generic). - **Suggested name:** Expose as `filters?: Record` and serialize internally. Or rename `filtersJsonString`. -- **Rationale:** Same as #22. +- **Rationale:** Same as #21. -### 24. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:187` +### 23. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:187` - **Why weird:** Same pattern. The field is "The schema of the index in JSON format. Supported types are `integer`, `long`, `float`, `double`, `boolean`, `string`, `date`, `timestamp`." A typed schema descriptor would be far more discoverable. - **Category:** 6 (misleading), 1 (generic). - **Suggested name:** Expose as a typed shape, or rename `schemaJsonString` and add JSDoc warning. -- **Rationale:** Same as #22. +- **Rationale:** Same as #21. -### 25. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:125, 160` +### 24. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:125, 160` - **Why weird:** "Writeback" run together with "embedding" plus "Table" forms a hard-to-parse triple-noun. Pronunciation: "embed-ding-write-back-table". JSDoc clarifies meaning ("[Optional] Name of the Delta table to sync the vector index contents and computed embeddings to") — but the field name is opaque without it. - **Category:** 7 (overly verbose), 14 (Go-style smushed identifier). - **Suggested name:** `writebackTableName`, `embeddingsTableName`, or `computedEmbeddingsTable`. - **Rationale:** Readability of compound nouns degrades fast past 2 words. -### 26. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:223` +### 25. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:223` - **Why weird:** JSDoc says: "If true, the URL returned for the index is guaranteed to be compatible with the reranker. Currently this means we return the CP URL regardless of how the index is being accessed. If not set or set to false, the URL may still be compatible with the reranker depending on what URL we return." So the flag toggles *which URL is returned*, not whether the index itself is reranker-compatible. The name suggests the operation *ensures compatibility*, but it actually just changes URL format. - **Category:** 6 (misleading), 1 (vague boolean). - **Suggested name:** `useControlPlaneUrl`, `returnControlPlaneUrl`, or `rerankerCompatibleUrl`. - **Rationale:** Boolean names should describe the side effect, not an aspirational outcome. -### 27. `numResults` field name in two places — `model.ts:291, 367` +### 26. `numResults` field name in two places — `model.ts:291, 367` - **Why weird:** Two unrelated requests (`QueryVectorIndexRequest`, `ScanVectorIndexRequest`) both name the result-count field `numResults`. JS convention is `limit` (matching SQL `LIMIT`, REST `?limit=`) or `pageSize`. `numResults` is Python/SQL-ish. - **Category:** 14 (Python/SQL-style), 17 (cross-package inconsistency — other paged APIs use `pageSize` or `limit`). - **Suggested name:** `limit` (matches HTTP query param and most JS libs) or `pageSize`. - **Rationale:** Aligning with `limit`/`pageSize` reduces friction. -### 28. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:313` +### 27. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:313` - **Why weird:** JSDoc says: "The query type to use. Choices are `ANN` and `HYBRID` and `FULL_TEXT`. Defaults to `ANN`." Three known values, but typed as `string` — not an enum. Users get no autocomplete, no compile-time check. - **Category:** 1 (generic typing), 6 (misleading typing). - **Suggested name:** Introduce an enum `QueryType.Ann | Hybrid | FullText` (these overlap with `IndexSubtype` values but represent different concepts). - **Rationale:** `string` for a closed set of values is a known antipattern. -### 29. `RerankerConfig.model` field — generic name "model" — `model.ts:338` +### 28. `RerankerConfig.model` field — generic name "model" — `model.ts:338` - **Why weird:** Bare `model?: string` with no JSDoc. In ML SDKs "model" is overloaded (ML model, data model, type model). The field probably holds a model endpoint name or model identifier. - **Category:** 1 (generic), 15 (generic field losing meaning). - **Suggested name:** `modelEndpointName`, `modelName`, or `rerankerModel`. - **Rationale:** Document what kind of identifier this is. -### 30. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:382` -- **Why weird:** `Struct` is the SDK's wire-format for a JSON-like map, and `MapStringValueEntry` is `{key: string, value: Value}`. The TS shape is "an array of key-value entries" rather than `Record`. This is a direct port of protobuf's map-as-repeated-message-entry encoding. Idiomatic JS would use a plain object or `Map`. -- **Category:** 14 (proto-style). +### 29. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:382` +- **Why weird:** `Struct` is the SDK's wire-format for a JSON-like map, and `MapStringValueEntry` is `{key: string, value: Value}`. The TS shape is "an array of key-value entries" rather than `Record`. Idiomatic JS would use a plain object or `Map`. +- **Category:** 14 (array-of-entries map encoding leaks to TS). - **Suggested name:** Flatten to `Record` at the TS boundary; keep the entry-array shape on the wire. - **Rationale:** Forcing users to map an array of `{key, value}` pairs into a record is friction the SDK could remove. ## Low severity -### 31. `Value` — single-word generic name for a discriminated union — `model.ts:414-423` +### 30. `Value` — single-word generic name for a discriminated union — `model.ts:414-423` - **Why weird:** A bare type called `Value` is uninformative. It is the SDK's wire-form scalar wrapper (number/string/bool/struct/list). Stronger candidates: `ScalarValue`, `WireValue`, `VectorIndexValue`. - **Category:** 1 (generic). - **Suggested name:** `ScalarValue` or move to the core wkt package and rename `wkt.Value`. - **Rationale:** `Value` collides with too many concepts. -### 32. `Struct` — generic single-word type name — `model.ts:380` +### 31. `Struct` — generic single-word type name — `model.ts:380` - **Why weird:** "Struct" is a language keyword in many languages (Go, C, Rust). In JS/TS it is a vague C-style holdover. The type is "a row of a vector index" (per the JSDoc). -- **Category:** 1 (generic), 14 (C/Go/proto-style), 10 (potential reserved-word collision in TS-flow tools). +- **Category:** 1 (generic), 10 (potential reserved-word collision in TS-flow tools). - **Suggested name:** `IndexRow` or `VectorIndexRow`. - **Rationale:** A more domain-specific name is more discoverable. -### 33. `MapStringValueEntry` — verbose proto-style name — `model.ts:245` +### 32. `MapStringValueEntry` — verbose name for a key-value pair — `model.ts:245` - **Why weird:** Reads as "Map of String to Value Entry". JSDoc says "Key-value pair." Just call it that. -- **Category:** 7 (verbose), 14 (proto-style). +- **Category:** 7 (verbose). - **Suggested name:** `KeyValue` or `StructField`. - **Rationale:** Less verbose, more idiomatic. -### 34. `ResultManifest` — Java/Spring-flavored noun — `model.ts:356-361` +### 33. `ResultManifest` — Java/Spring-flavored noun — `model.ts:356-361` - **Why weird:** "Manifest" in a query-result context is unusual JS phrasing. JSDoc says "Metadata about the result set." More common in JS: `Metadata`, `Schema`, `Info`. - **Category:** 14 (Java-style), 1 (mildly generic). - **Suggested name:** `ResultMetadata` or `ResultSchema`. - **Rationale:** Aligns with idiomatic JS. -### 35. `ResultData` — generic two-word noun — `model.ts:348-353` +### 34. `ResultData` — generic two-word noun — `model.ts:348-353` - **Why weird:** Type is "Data returned in the query result." `ResultData` is generic; `QueryResultData` or just `Rows` would be more specific. - **Category:** 1 (generic). - **Suggested name:** `QueryResultData` or `ResultRows`. - **Rationale:** Disambiguate. -### 36. `lastPrimaryKey` field on request + response — `model.ts:369, 377` +### 35. `lastPrimaryKey` field on request + response — `model.ts:369, 377` - **Why weird:** Same field name used as a cursor on both request (input) and response (output). On the response it is fine ("last primary key in this page"), on the request it is a pagination cursor named after its expected source rather than its role. JS convention would be `pageToken` / `cursor` / `afterKey`. - **Category:** 17 (inconsistency with `pageToken` used elsewhere — model.ts:235, 284), 14 (database-cursor-style name). - **Suggested name:** Both could use `cursor` or `afterPrimaryKey` (request) + `lastPrimaryKey` (response). @@ -237,13 +231,13 @@ ## Observation -### 37. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` +### 36. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` - **Why weird:** Cross-package import. `Call` is the most generic possible name for "a network operation". - **Category:** 1 (generic), cross-package observation. - **Suggested name:** `RetryableCall`, `SdkCall`. Out of scope for this audit. - **Rationale:** Tracked for cross-package consistency. -### 38. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:29` +### 37. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:29` - **Why weird:** The mini variant (see #3, #4) is re-exported as part of the public API. If the intent is for it to be an internal implementation detail, it should not be in `index.ts`. - **Category:** Observation on the public surface. - **Suggested name:** Either rename per #3 or remove from the public surface. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 2c139054..5369f890 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -21,11 +21,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 16 | -| Medium | 18 | +| High | 9 | +| Medium | 16 | | Low | 18 | | Observation | 7 | -| **Total** | **59**| +| **Total** | **50**| ### Top themes @@ -33,13 +33,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. `EditInstancePool` (29 fields), `GetInstancePool_Response` (30 fields), and `InstancePoolAndStats` (30 fields) are byte-identical apart from one or two fields. They could share a single base type. -2. **Proto-style `_Response` and `_*Entry` types pollute the public surface.** - 12 type names use `_` separators, each requiring an `eslint-disable`. -3. **`InstancePool*` prefix on every type is redundant** — the package is +2. **`InstancePool*` prefix on every type is redundant** — the package is already `instancepools`; the v2 namespace is even smaller. `Pool` (or even nothing) would do for `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`. -4. **Per-cloud enum-prefix inconsistency** — `AwsAvailability` members are +3. **Per-cloud enum-prefix inconsistency** — `AwsAvailability` members are unprefixed (`SPOT`, `ON_DEMAND`), but `AzureAvailability` (`SPOT_AZURE`) and `GcpAvailability` (`PREEMPTIBLE_GCP`) repeat the enum's cloud. The same defect exists in `clusters` (see `clusters.md` #3) — fix once at @@ -143,23 +141,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | A-04 | `InstancePoolGcpAttributes.localSsdCount` | Low | "Ssd" is 3 letters; same casing rule. OK. | | A-05 | `InstancePoolAzureAttributes.spotBidMaxPrice` vs `InstancePoolAwsAttributes.spotBidPricePercent` | Medium | Sibling fields describe the same concept (max price for spot bid) in opposite shapes. `MaxPrice` is an absolute USD value; `PricePercent` is relative. Names obscure this — `azureSpotBidMaxPriceUsd` and `awsSpotBidPricePercent` (or any clarifying suffix) would help. | -### 2.4 Underscores in TS identifiers — High - -| ID | Symbol | Severity | Issue | -| ----- | --------------------------------------------------- | -------- | ----- | -| U-01 | `CreateInstancePool_CustomTagsEntry` (`model.ts:175`) | High | Proto-nested name carries the `_` separator that Google TS style forbids (https://google.github.io/styleguide/tsguide.html#naming-style). Each occurrence requires an `eslint-disable @typescript-eslint/naming-convention`. | -| U-02 | `CreateInstancePool_Response` (`model.ts:191`) | High | Same as U-01. | -| U-03 | `DeleteInstancePool_Response` (`model.ts:202`) | High | Same as U-01. | -| U-04 | `EditInstancePool_CustomTagsEntry` (`model.ts:364`) | High | Same as U-01. | -| U-05 | `EditInstancePool_Response` (`model.ts:380`) | High | Same as U-01. | -| U-06 | `GetInstancePool_Response` (`model.ts:388`) | High | Same as U-01. | -| U-07 | `GetInstancePool_Response_CustomTagsEntry` (`model.ts:493`) — *double underscore* | High | The proto-nesting compounds: `Response` is itself nested, and `CustomTagsEntry` is nested inside `Response`. 40-char identifier. | -| U-08 | `GetInstancePool_Response_DefaultTagsEntry` (`model.ts:509`) — *double underscore* | High | Same as U-07. | -| U-09 | `InstancePoolAndStats_CustomTagsEntry` (`model.ts:629`) | High | Same as U-01. | -| U-10 | `InstancePoolAndStats_DefaultTagsEntry` (`model.ts:645`) | High | Same as U-01. | -| U-11 | `ListInstancePools_Response` (`model.ts:762`) | High | Same as U-01. | - -### 2.5 Cryptic abbreviations — Medium +### 2.4 Cryptic abbreviations — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -173,7 +155,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | C-08 | `Fleet-V2` in JSDoc `"For pools with node type flexibility (Fleet-V2)"` | Medium | Internal codename leaking into public docs. | | C-09 | `Mb/s` in JSDoc `"configurable throughput (in Mb/s)"` (`model.ts:168, 357, 486, 622`) | Low | Likely intended `MB/s` (megabytes per second) given the cloud-disk-throughput context; `Mb/s` (megabits) is unusual for disk throughput. Possible casing typo upstream. | -### 2.6 Misleading names — High +### 2.5 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -187,7 +169,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | M-08 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | | M-09 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | -### 2.7 Overly verbose / Redundant suffixes — Medium +### 2.6 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -199,7 +181,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | O-06 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | | O-07 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | -### 2.8 Singular / plural mismatches — Low / High +### 2.7 Singular / plural mismatches — Low / High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -207,51 +189,41 @@ configuration, idle / used statistics, and pending-instance failure reporting. | P-02 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | | P-03 | `ListInstancePools` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | | P-04 | `ListInstancePools_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | -| P-05 | `customTags` is `Record` but the proto-side schema also exposes `_CustomTagsEntry` interface | Observation | TS uses the record. See W-01 for the underscore-naming concern. | -### 2.9 Reserved-word collisions — Medium +### 2.8 Reserved-word collisions — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | R-01 | `DockerImage.credsOneof.$case === 'basicAuth'.basicAuth: DockerBasicAuth` | Low | `basicAuth` is not a reserved word but is duplicated across the `$case` discriminator and the embedded field — `library.lib.basicAuth.basicAuth` style access. | | R-02 | None of the type names collide with TS reserved words. | — | OK. | -### 2.10 Underscore-laden wrapper types — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| W-01 | `*_CustomTagsEntry` (six occurrences: 175, 364, 493, 629) and `*_DefaultTagsEntry` (two occurrences: 509, 645) | High | These eight interfaces are proto-internal map-entry shapes whose underscore-laden names (`CreateInstancePool_CustomTagsEntry` etc.) each require an `eslint-disable @typescript-eslint/naming-convention`. They are exported via `index.ts` (8 names) under proto-style identifiers that violate Google TS style. | -| W-02 | `InstancePoolStatus` (`model.ts:748-756`) | Medium | The type's name promises a general "status" but its shape exposes only `pendingInstanceErrors`. Misleading (see also M-02). | - -### 2.11 Duplicate concepts — Highest in repo +### 2.9 Duplicate concepts — Highest in repo | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | D-01 | `CreateInstancePool` (28 fields, lines 90-172) vs `EditInstancePool` (29 fields, lines 277-361) | High | Identical except `EditInstancePool` adds `instancePoolId`. Could share a base type. | | D-02 | `GetInstancePool_Response` (30 fields, lines 388-490) vs `InstancePoolAndStats` (30 fields, lines 524-626) | High | **Byte-identical** apart from the type name. Compare line-by-line: identical field set, identical order, identical JSDoc. Two names for the same shape. | -| D-03 | `*_CustomTagsEntry` types (six declared, lines 175, 364, 493, 629) vs `*_DefaultTagsEntry` types (two declared, lines 509, 645) | High | All eight are byte-identical `{ key?: string; value?: string }`. One shared type would do. Same as `clusterpolicies` (clusterpolicies.md #W-04) and other packages — codegen-wide issue. | -| D-04 | `CreateInstancePool` vs the `Pool` body inside `InstancePoolAndStats` | High | All 28 config fields appear three times: once on Create, once on Edit (29), once on the entity. Codegen could project from a shared base. | -| D-05 | `InstancePoolAwsAttributes` (this package) vs `AwsAttributes` (`clusters` package) | High | Same domain (AWS attributes for a compute pool / cluster). `clusters` calls them `AwsAttributes`; this package calls them `InstancePoolAwsAttributes`. Both share many fields (availability, zoneId, instanceProfileArn, spotBid…) but `clusters` has additional fields (`ebsVolumeCount`, etc.). Cross-package duplication; a shared `compute` module would fix both. | -| D-06 | `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` vs `clusters.AzureAttributes` / `clusters.GcpAttributes` | High | Same as D-05 for Azure / GCP. | -| D-07 | `EbsVolumeType`, `AzureDiskVolumeType`, `AwsAvailability`, `AzureAvailability`, `GcpAvailability`, `DockerImage`, `DockerBasicAuth`, `DiskSpec`, `DiskType`, `NodeTypeFlexibility`, `PendingInstanceError` | High | All eleven types/enums are duplicated verbatim in `clusters/src/v2/model.ts` (verified via `grep`). Two packages ship eleven identical shapes. | +| D-03 | `CreateInstancePool` vs the `Pool` body inside `InstancePoolAndStats` | High | All 28 config fields appear three times: once on Create, once on Edit (29), once on the entity. Codegen could project from a shared base. | +| D-04 | `InstancePoolAwsAttributes` (this package) vs `AwsAttributes` (`clusters` package) | High | Same domain (AWS attributes for a compute pool / cluster). `clusters` calls them `AwsAttributes`; this package calls them `InstancePoolAwsAttributes`. Both share many fields (availability, zoneId, instanceProfileArn, spotBid…) but `clusters` has additional fields (`ebsVolumeCount`, etc.). Cross-package duplication; a shared `compute` module would fix both. | +| D-05 | `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` vs `clusters.AzureAttributes` / `clusters.GcpAttributes` | High | Same as D-04 for Azure / GCP. | +| D-06 | `EbsVolumeType`, `AzureDiskVolumeType`, `AwsAvailability`, `AzureAvailability`, `GcpAvailability`, `DockerImage`, `DockerBasicAuth`, `DiskSpec`, `DiskType`, `NodeTypeFlexibility`, `PendingInstanceError` | High | All eleven types/enums are duplicated verbatim in `clusters/src/v2/model.ts` (verified via `grep`). Two packages ship eleven identical shapes. | -### 2.12 Verb-tense inconsistency — Low +### 2.10 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | T-01 | `createInstancePool`, `deleteInstancePool`, `editInstancePool`, `getInstancePool`, `listInstancePools` | Low | All present-tense imperative — consistent. | | T-02 | `preloadedDockerImages`, `preloadedSparkVersions` (past participle) | Low | Standard for fields that describe a pre-applied state. OK. | -### 2.13 Go / Java-style names — High +### 2.11 Go / Java-style names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `CreateInstancePool_Response`, `EditInstancePool_Response`, ... (proto-nested message style) | High | Direct port of Go `pb.CreateInstancePoolResponse`. Every occurrence requires `eslint-disable`. Repo-wide concern; flagged here. | -| G-02 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | -| G-03 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | -| G-04 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | +| G-01 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | +| G-02 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | +| G-03 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | -### 2.14 Generic field names losing meaning — Medium +### 2.12 Generic field names losing meaning — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -261,16 +233,15 @@ configuration, idle / used statistics, and pending-instance failure reporting. | F-04 | `PendingInstanceError.message` | Medium (also V-02) | When destructured, an error `message` field is the generic-est possible name. Adding `instanceMessage` would help. | | F-05 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | | F-06 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | -| F-07 | `*_CustomTagsEntry.key` / `*_CustomTagsEntry.value` | Medium | Outside the entry type, `key` and `value` are the genericest possible field names. (See W-01 for the underscore-naming concern on the entry types.) | -| F-08 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | +| F-07 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | -### 2.15 Field contradicting type domain — Low +### 2.13 Field contradicting type domain — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | K-01 | None observed. All fields are within their type's domain. | — | OK. | -### 2.16 Inconsistent action verbs — Medium +### 2.14 Inconsistent action verbs — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -278,7 +249,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | AV-02 | `getInstancePool()` (singular) vs `listInstancePools()` (plural) | Low | Correct REST convention. OK. | | AV-03 | `createInstancePool()` / `deleteInstancePool()` / `editInstancePool()` / `getInstancePool()` / `listInstancePools()` — only five verbs | Low | No `start`, `stop`, `pin`, etc. — instance pools are stateless from the API standpoint; the lifecycle is implicit via fewer endpoints than `clusters`. Consistent. | -### 2.17 Long enum values — Low +### 2.15 Long enum values — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -287,7 +258,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | L-03 | `EbsVolumeType.THROUGHPUT_OPTIMIZED_HDD` (24 chars) | Low | Standard AWS terminology; OK. | | L-04 | `AzureDiskVolumeType.STANDARD_LRS` (12 chars) | Low | Short. OK. | -### 2.18 Underspecified IDs — Medium +### 2.16 Underspecified IDs — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -298,7 +269,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | I-05 | `NodeTypeFlexibility.alternateNodeTypeIds: string[]` | Low | Plural array of node-type IDs; scoped. OK. | | I-06 | `InstancePoolAwsAttributes.zoneId` / `InstancePoolGcpAttributes.zoneId` | Low | Both reuse `zoneId` for the AWS availability zone ("us-west-2a") and GCP availability zone ("us-west1-a"). Same name, two slightly different value formats. Acceptable cross-cloud abstraction. | -### 2.19 Type-suffix tautology — Medium +### 2.17 Type-suffix tautology — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -306,12 +277,12 @@ configuration, idle / used statistics, and pending-instance failure reporting. | TS-02 | `InstancePoolStats` | Medium | `Stats` is already abbreviated; the `InstancePool` prefix is redundant inside this package. | | TS-03 | `InstancePoolStatus` | Medium | Same as TS-02. | | TS-04 | `InstancePoolState` (enum) | Medium | Same. Could be `State` or `PoolState`. | -| TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-03). Doubly off. | +| TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-02). Doubly off. | | TS-06 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | | TS-07 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-05) the type-name still echoes. | | TS-08 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | -### 2.20 Other observations +### 2.18 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -321,7 +292,6 @@ configuration, idle / used statistics, and pending-instance failure reporting. | X-04 | `client.ts:165-167` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | | X-05 | `client.ts:191` `_req: ListInstancePools` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | | X-06 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | -| X-07 | `index.ts` re-exports 28 type symbols and 6 enum symbols. The `_CustomTagsEntry`/`_DefaultTagsEntry` types (8 names) *are* re-exported under proto-style underscore names. See W-01. | Observation | Public surface area carries the underscore-named entry types. | --- @@ -329,11 +299,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 16 | -| Medium | 18 | +| High | 9 | +| Medium | 16 | | Low | 18 | | Observation | 7 | -| **Total** | **59**| +| **Total** | **50**| ## 4. Cross-package consistency notes @@ -346,9 +316,6 @@ configuration, idle / used statistics, and pending-instance failure reporting. - The `*Attributes` types (`InstancePoolAwsAttributes` etc.) overlap heavily with `clusters` `AwsAttributes` etc., but the field sets differ. A common base + extension would still help. -- The `_Response` / `_*Entry` proto-nesting concern is identical to that flagged in - every other audit in this directory; it is a codegen-wide issue, not a - per-package fix. ## 5. File coverage diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index f1adad79..6096e62d 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -35,11 +35,11 @@ are graded: | Name | Purpose | | --------------------------------- | -------------------------------------------------------- | | `AddInstanceProfile` | Request body for register/add. | -| `AddInstanceProfile_Response` | Empty response from add (proto-style suffix). | +| `AddInstanceProfile_Response` | Empty response from add. | | `EditInstanceProfile` | Request body for edit/update. | | `EditInstanceProfile_Response` | Empty response from edit. | | `InstanceProfile` | The instance-profile entity (AWS-scoped). | -| `ListInstanceProfiles` | Empty request body for list (proto-style empty type). | +| `ListInstanceProfiles` | Empty request body for list. | | `ListInstanceProfiles_Response` | Response from list. | | `RemoveInstanceProfile` | Request body for unregister/remove. | | `RemoveInstanceProfile_Response` | Empty response from remove. | @@ -110,15 +110,11 @@ are graded: | A-03 | `isMetaInstanceProfile` | Low | No acronym issues. | | A-04 | `Aws` / `Iam` / `Arn` not appearing as type prefixes | Low | The package doesn't have a type-name acronym to test (e.g. no `AWSInstanceProfile`). If the type were renamed per V-01, the chosen casing should be `AwsInstanceProfile` to match Google TS style. | -### 2.4 Underscores in TS identifiers — High +### 2.4 Underscores in TS identifiers — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------------------- | -------- | ----- | -| U-01 | `AddInstanceProfile_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). Every occurrence requires an `eslint-disable @typescript-eslint/naming-convention` annotation. Should be `AddInstanceProfileResponse`. | -| U-02 | `EditInstanceProfile_Response` | High | Same as U-01. | -| U-03 | `ListInstanceProfiles_Response` | High | Same as U-01. | -| U-04 | `RemoveInstanceProfile_Response` | High | Same as U-01. | -| U-05 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | +| U-01 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | ### 2.5 Cryptic abbreviations — Medium @@ -188,12 +184,11 @@ revisions can add fields without breaking the type signature. Not flagged. | T-02 | `isMetaInstanceProfile` (boolean) | Low | Standard `is*` boolean prefix. | | T-03 | `skipValidation` (boolean) | Low | Imperative — consistent boolean style. | -### 2.13 Go / Java-style names — Medium +### 2.13 Go / Java-style names — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `AddInstanceProfile_Response` (proto nested-message style) | High | Direct port of Go's `pb.AddInstanceProfileResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `AddInstanceProfileResponse`. | -| G-02 | `RemoveInstanceProfile` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | +| G-01 | `RemoveInstanceProfile` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | ### 2.14 Generic field names losing meaning — Low @@ -267,44 +262,36 @@ package is exemplary in using ARNs as identifiers.) | Severity | Count | | -------- | ----- | -| High | 14 | +| High | 9 | | Medium | 19 | | Low | 25 | -| **Total**| **58**| +| **Total**| **53**| ### 3.2 Top themes -1. **Proto-style `_Response` suffix pollutes every response type.** - Four interfaces (`AddInstanceProfile_Response`, `EditInstanceProfile_Response`, - `ListInstanceProfiles_Response`, `RemoveInstanceProfile_Response`) each - require an `eslint-disable` for the naming rule. Renaming to TS-idiomatic - `AddInstanceProfileResponse` etc. would eliminate the disable-comments and - the Google-style violation in one sweep. - -2. **`add` / `remove` verbs mislead about scope.** The methods **register** / +1. **`add` / `remove` verbs mislead about scope.** The methods **register** / **unregister** an existing AWS instance profile with Databricks — neither creates nor deletes the underlying AWS resource. `register*` / `unregister*` would be more accurate. Compounded by `edit*` (instead of `update*`) breaking the CRUD verb consistency. -3. **`InstanceProfile` is AWS-specific but not cloud-prefixed.** In a +2. **`InstanceProfile` is AWS-specific but not cloud-prefixed.** In a multi-cloud SDK, an unqualified name implies a cross-cloud concept it doesn't represent. `AwsInstanceProfile` (matching `AzureServicePrincipal`, `GcpAttributes`) would prevent future ambiguity. -4. **Tautological field naming inside `InstanceProfile`.** +3. **Tautological field naming inside `InstanceProfile`.** `instanceProfile.instanceProfileArn` and `instanceProfile.isMetaInstanceProfile` repeat the type name. Inside the entity, `arn` and `isMeta` (or `isCredentialPassthrough`) would suffice. -5. **`isMetaInstanceProfile` and `skipValidation` need their JSDoc to be +4. **`isMetaInstanceProfile` and `skipValidation` need their JSDoc to be intelligible.** "Meta instance profile" is a Databricks-specific term; "validation" is overloaded. `isCredentialPassthrough` / `skipIamValidation` (or similar) would be self-documenting. ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) -- Drop `_Response` suffix in all four response interfaces. - Rename `InstanceProfile` → `AwsInstanceProfile` to scope to the cloud. - Rename `addInstanceProfile` → `registerInstanceProfile` and `removeInstanceProfile` → `unregisterInstanceProfile` to match actual @@ -317,8 +304,6 @@ package is exemplary in using ARNs as identifiers.) ### 3.4 Cross-package consistency notes -- The proto-style `_Response` suffix is consistent with peers and should be - addressed at the codegen level. - `editInstanceProfile` (vs `updateInstanceProfile`) is a per-API decision driven by the upstream REST verb; flag for upstream alignment but no per-package fix. diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index 6d2fdb38..82c31c20 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -8,11 +8,11 @@ the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------ | -| High | 37 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions. | -| Medium | 87 | Underscores, redundant prefixes/suffixes, vague names, acronym casing. | +| High | 30 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions. | +| Medium | 80 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | | Low | 53 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 16 | Patterns spanning the entire file (proto leakage, oneof wrappers, etc.). | -| **Total** | **193** | | +| Observations | 14 | Patterns spanning the entire file (oneof wrappers, ID typing, etc.). | +| **Total** | **177** | | Issues are catalogued below by severity, then by file/line. @@ -74,169 +74,127 @@ Issues are catalogued below by severity, then by file/line. - **Suggestion:** Standardize on `Subscriber` for the leaf type and `SubscriptionList` (or just `Subscription`) for the container. Avoid mixing `Subscriber` (alert), `Subscription` (sql), and `Subscription_Subscriber` (dashboard). - **Rationale:** Each task type re-invents the same `userName | destinationId` oneof under a different name. This is a porting artifact, not a domain distinction. -### H10. `TerminationCode_Code` — proto-name leakage on a public enum -- **Location:** `model.ts:632`, `model.ts:499` (`QueueDetailsCode_Code`), `model.ts:717` (`TerminationType_Type`). -- **Category:** Type-suffix tautology (#20), Go/Java-style names (#14). -- **Suggestion:** Lift to `TerminationCode`, `QueueReasonCode`, and `TerminationType`; the proto-wrapper underscore should not appear in public TS identifiers. -- **Rationale:** `TerminationCode_Code.SUCCESS` reads as `Code.Code.SUCCESS`. The repeated token is a porting artifact from the Go SDK's proto-message naming. - -### H11. `RunLifecycleStateV2_State` — versioned + tautological enum -- **Location:** `model.ts:532`, related `model.ts:518` (`RunLifeCycleState_RunLifeCycleState`). -- **Category:** Type-suffix tautology (#20), versioned API leakage. -- **Suggestion:** Rename to `RunLifecycleState` (current canonical, drop V1) and `RunStatusState` (legacy). The `V2` suffix should be hidden behind the SDK version, not part of TypeScript identifiers. -- **Rationale:** Consumers shouldn't pick between v1/v2 enums based on a suffix; the SDK should pick one. The dual identifier guarantees confusion. - -### H12. `Run.numberInJob` always equals `Run.runId` — meaningless field +### H10. `Run.numberInJob` always equals `Run.runId` — meaningless field - **Location:** `model.ts:3422`, `model.ts:2107`, `model.ts:3759`. - **Category:** Misleading names (#6), generic field names losing meaning (#15). - **Suggestion:** Drop or alias; if it must stay for back-compat, document the duplication on the field rather than the type. - **Rationale:** The comment "This is set to the same value as `run_id`" makes the field a no-op. New TS users will assume it's distinct. -### H13. `RunNow_Response.numberInJob` reused +### H11. `RunNow_Response.numberInJob` reused - **Location:** `model.ts:3759`. - **Category:** Misleading names (#6). -- **Suggestion:** Same as H12 — remove or rename to `runIdAlias`. +- **Suggestion:** Same as H10 — remove or rename to `runIdAlias`. - **Rationale:** Same dead duplication on the response. -### H14. `Format` enum value `SINGLE_TASK` is semantically dead +### H12. `Format` enum value `SINGLE_TASK` is semantically dead - **Location:** `model.ts:150-153`. - **Category:** Misleading names (#6). - **Suggestion:** Mark `SINGLE_TASK` with `@deprecated` (the JSDoc on `CreateJob.format` says it's always `MULTI_TASK`). - **Rationale:** Exposing a value the server will never return is a footgun. -### H15. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition +### H13. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition - **Location:** `model.ts:305`. - **Category:** Misleading names (#6). - **Suggestion:** Document inline, or rename to `NO_FAILURES_AT_LEAST_ONE_RAN`. Alternatively, `AT_LEAST_ONE_SUCCESS_NONE_FAILED`. - **Rationale:** The enum-level JSDoc clarifies "none failed AND at least one was executed" — this is non-obvious from the name. -### H16. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion +### H14. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion - **Location:** `model.ts:199`, `model.ts:208`, `model.ts:2642`, `model.ts:2650`. - **Category:** Singular/plural mismatch (#9), redundant suffixes (#8). - **Suggestion:** `JobsHealthRule` and `JobsHealthRules` differ only by `s` and the inner wraps a `rules?: JobsHealthRule[]`. Flatten — make the array the public shape (call it `HealthRules` or just `HealthRule[]`). - **Rationale:** Hairsplitting wrappers around arrays force consumers to write `{rules: [...]}` instead of `[...]`. Plural type names alongside singular ones are the most error-prone pattern in this file. -### H17. `JobsHealth*` prefix is inconsistent — `Jobs` is plural +### H15. `JobsHealth*` prefix is inconsistent — `Jobs` is plural - **Location:** `model.ts:199`, `model.ts:208`, `model.ts:2642`, `model.ts:2650`. - **Category:** Singular/plural mismatch (#9), Go/Java-style names (#14). - **Suggestion:** Use the singular product noun: `JobHealthMetric`, `JobHealthRule`. Or just `HealthMetric` if global. - **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). -### H18. `RunNow_Response.runId` field is the "newly triggered run" — confusingly typed `number` +### H16. `RunNow_Response.runId` field is the "newly triggered run" — confusingly typed `number` - **Location:** `model.ts:3757`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Add a branded type alias `RunId = number & {readonly __brand: 'RunId'}` or use `string` to match `bigint`-safe APIs. - **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId` (string!), `dbtPlatformJobRunId` (string!). -### H19. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` +### H17. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` - **Location:** `model.ts:1712`, `model.ts:1744`. - **Category:** Field contradicting type domain (#16), misleading names (#6). - **Suggestion:** Standardize on `string` for upstream IDs; note in JSDoc. - **Rationale:** Same semantic field encoded as two different TS types in adjacent interfaces is a bug magnet. -### H20. `GetRunOutput_Response.result` oneof tag is `notebookOutput` but the field discriminates "task" type — misleading +### H18. `GetRunOutput_Response.result` oneof tag is `notebookOutput` but the field discriminates "task" type — misleading - **Location:** `model.ts:2204-2257`. - **Category:** Misleading names (#6). - **Suggestion:** Rename `result` to `taskOutput` (since the union members are `notebookOutput | sqlOutput | dbtOutput | ...`). Then `result` could refer to a higher-level `RunResultState` field that semantically belongs there. - **Rationale:** `result` on a run-output type is confusable with `RunResultState`, and `Run.status.terminationDetails.message` is also "the result". -### H21. `Run_JobLevelParameters` confusingly named with proto underscore and "parameters" plural for a single record -- **Location:** `model.ts:3506`. -- **Category:** Underscores in TS identifiers (#4), singular/plural mismatch (#9). -- **Suggestion:** Rename to `RunJobParameter` (singular — it's an array element with `name`, `default`, `value` for one parameter). -- **Rationale:** It is used as `jobParameters?: Run_JobLevelParameters[]` — a `Parameters[]` typing is a hard read. - -### H22. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous +### H19. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous - **Location:** `model.ts:3515`. - **Category:** Misleading names (#6). - **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3991). - **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? -### H23. `RunJobTask_RunJobTaskOutput` is "double-stuttered" -- **Location:** `model.ts:3613`. -- **Category:** Type-suffix tautology (#20), Go/Java-style names (#14). -- **Suggestion:** Rename to `RunJobTaskOutput` (no wrapping namespace prefix needed in TS). -- **Rationale:** `RunJobTask_RunJobTaskOutput` repeats the parent name; a flat name is shorter and equally clear in TS. - -### H24. `client.cancelAllRuns` request type `CancelAllRuns` (not `CancelAllRunsRequest`) but response is `CancelAllRuns_Response` -- **Location:** `model.ts:1099`, `model.ts:1108`, `client.ts:124`. -- **Category:** Inconsistent suffix conventions (#17), redundant suffixes (#8). -- **Suggestion:** Pick one: either `CancelAllRunsRequest` + `CancelAllRunsResponse`, or `CancelAllRuns` + `CancelAllRunsResult`. -- **Rationale:** Mixing zero-suffix on the request and `_Response` on the response is a porting smell ("the response wraps the proto Response message"). It also makes JSDoc grepping harder. - -### H25. `Repair.id` vs `RepairRun_Response.repairId` +### H20. `Repair.id` vs `RepairRun_Response.repairId` - **Location:** `model.ts:3107`, `model.ts:3236`. - **Category:** Generic field names losing meaning (#15), inconsistent naming (#17). - **Suggestion:** Rename `Repair.id` to `repairId`. - **Rationale:** A bare `id` field on a type called `Repair` is technically OK but breaks the workspace convention of always disambiguating IDs. -### H26. `BaseJob` and `GetJob_Response` and `Run` duplicate ~12 identical fields +### H21. `BaseJob` and `GetJob_Response` and `Run` duplicate ~12 identical fields - **Location:** `model.ts:969`, `model.ts:2040`, `model.ts:3414`, `model.ts:1008`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Extract a shared `JobIdentity` / `JobCoreFields` interface or use TS `Pick`/`Omit` on a base shape. - **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId`, `path` are repeated verbatim in `BaseJob` and `GetJob_Response`. Diverges silently. -### H27. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums +### H22. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums - **Location:** `model.ts:3867`, `model.ts:3881`. - **Category:** Duplicate concepts (#12), versioned API leakage (#11). - **Suggestion:** Pick `RunStatus` as the canonical shape, deprecate `RunState`, and document the deprecation in the rule. - **Rationale:** The JSDoc on `Run.state` already says "Deprecated. Please use the `status` field instead." but the type is still exported and still shows up in the union. -### H28. `RunState.userCancelledOrTimedout` — typo + boolean-of-two-things +### H23. `RunState.userCancelledOrTimedout` — typo + boolean-of-two-things - **Location:** `model.ts:3875`. - **Category:** Misleading names (#6). - **Suggestion:** Fix spelling to `userCancelledOrTimedOut`. Better, split into `cancelledByUser: boolean` and `timedOut: boolean`. - **Rationale:** Compound booleans (X-or-Y) are an anti-pattern. The current name silently drops one bit of info. -### H29. `DataSecurityMode` enum mixes prefixed and unprefixed values +### H24. `DataSecurityMode` enum mixes prefixed and unprefixed values - **Location:** `model.ts:94-126`. - **Category:** Redundant enum prefixes (#2), inconsistent naming (#17). - **Suggestion:** Drop the `DATA_SECURITY_MODE_` prefix on the three alias values; either all values share a prefix, or none do. Currently we have `NONE`, `SINGLE_USER`, `USER_ISOLATION`, ..., `DATA_SECURITY_MODE_STANDARD`, `DATA_SECURITY_MODE_DEDICATED`, `DATA_SECURITY_MODE_AUTO`. - **Rationale:** The reader can't predict whether they need `DataSecurityMode.AUTO` or `DataSecurityMode.DATA_SECURITY_MODE_AUTO` — they have to read the file. -### H30. `RunLifeCycleState_RunLifeCycleState` is misspelled internally and externally -- **Location:** `model.ts:518`. -- **Category:** Acronym/word casing (#3), Go/Java-style names (#14). -- **Suggestion:** Spell as one word: `RunLifecycleState_RunLifecycleState`. Better, drop the redundancy entirely: `RunLifecycleState`. -- **Rationale:** "Lifecycle" is one word in modern usage (per OED). Mixing `LifeCycle` and `Lifecycle` (compare H11 — `RunLifecycleStateV2_State` — already one word) within the same file is the worst kind of acronym-casing inconsistency. - -### H31. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) +### H25. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) - **Location:** `model.ts:413`, `model.ts:501`, `model.ts:565`, `model.ts:685`. - **Category:** Long enum values, inconsistent naming (#17, #18). - **Suggestion:** Normalize to one form. The `MAX_` form is more common; reach-vs-exceed should pick one verb. - **Rationale:** Three enums describe the same overflow scenario with three different names. Consumers cannot write a generic handler. -### H32. `RunLifeCycleState_RunLifeCycleState` is missing `QUEUED` in some doc-orderings but `RunLifecycleStateV2_State.QUEUED` is present -- **Location:** `model.ts:518-528`, `model.ts:532-544`. -- **Category:** Versioned API leakage, inconsistent enums. -- **Suggestion:** Document the migration table at the top of the file. -- **Rationale:** Type checks against the V1 enum that branch on `QUEUED` are silently wrong vs V2. - -### H33. `client.repair` and `client.repairWaiter` — verb mismatch with the request type +### H26. `client.repair` and `client.repairWaiter` — verb mismatch with the request type - **Location:** `client.ts:570`, `client.ts:595`. - **Category:** Inconsistent action verbs (#17). - **Suggestion:** Either name the method `repairRun` to match the type `RepairRun`, or rename the request type `Repair` to match the method. - **Rationale:** All other client methods follow `verbNoun(NounVerb)` or `verbNoun(VerbNoun)` consistently; `repair(RepairRun)` is the outlier. -### H34. `client.exportRun` returns `ExportRun_Response` which contains a `views` array of `ViewItem` +### H27. `client.exportRun` returns `ExportRun_Response` which contains a `views` array of `ViewItem` - **Location:** `client.ts:268`, `model.ts:1864`, `model.ts:4982`. - **Category:** Vague/generic (#1). - **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. - **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. -### H35. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint +### H28. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint - **Location:** `model.ts:350`, `model.ts:360`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Merge or namespace: `View.Type` (NOTEBOOK | DASHBOARD) and `View.ExportSelector` (CODE | DASHBOARDS | ALL). - **Rationale:** Two enums about "views" with different value sets and intent. Users will pick the wrong one. -### H36. `GitSource.gitReference` discriminator is named `gitBranch | gitTag | gitCommit` — but the parent has `gitUrl` / `gitProvider` (no `git` prefix on the data) +### H29. `GitSource.gitReference` discriminator is named `gitBranch | gitTag | gitCommit` — but the parent has `gitUrl` / `gitProvider` (no `git` prefix on the data) - **Location:** `model.ts:2286-2312`. - **Category:** Inconsistent naming (#17), redundant prefixes (#2). - **Suggestion:** Make the oneof tags `branch | tag | commit` — the parent's `GitSource.git*` prefix already provides namespace. - **Rationale:** `gitSource.gitReference.gitBranch` is needless repetition. -### H37. `cancelRunWaiter` polls on `RunLifeCycleState_RunLifeCycleState` (V1) while the modern field is `RunStatus.state` +### H30. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` - **Location:** `client.ts:742-820`. - **Category:** Versioned API leakage. - **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. @@ -402,260 +360,226 @@ Issues are catalogued below by severity, then by file/line. - **Category:** Versioned API leakage. - **Suggestion:** OK while transition is documented; reconsider after dbt Cloud is dropped. -### M30. `DbtTask_DbtTaskOutput` — proto stutter -- **Location:** `model.ts:1781`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `DbtTaskOutput`. - -### M31. `NotebookTask_NotebookOutput` -- **Location:** `model.ts:2918`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `NotebookTaskOutput`. - -### M32. `ClusterSpec_NewCluster` — nested name is verbose; would be just `NewClusterSpec` -- **Location:** `model.ts:1253`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `NewClusterSpec`. - -### M33. `CleanRoomsNotebookTask_CleanRoomsNotebookTaskOutput` -- **Location:** `model.ts:1156`. -- **Category:** Type-suffix tautology (#20) — extreme. -- **Suggestion:** Rename to `CleanRoomsNotebookTaskOutput`. - -### M34. `RunJobTask_RunJobTaskOutput` -- **Location:** `model.ts:3613`. -- **Category:** Type-suffix tautology (#20) (also flagged in H23). - -### M35. `SqlTask_*` family — six output types -- **Location:** `model.ts:4452`, `model.ts:4465`, `model.ts:4473`, `model.ts:4491`, `model.ts:4512`, `model.ts:4518`, `model.ts:4531`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Drop the `SqlTask_` prefix in TS: `SqlAlertOutput`, `SqlDashboardOutput`, `SqlDashboardWidgetOutput`, `SqlOutput`, `SqlOutputError`, `SqlQueryOutput`, `SqlStatementOutput`. - -### M36. `ResolvedValues_*` family — 11 sub-types -- **Location:** `model.ts:3303-3412`. -- **Category:** Type-suffix tautology (#20), Go/Java-style names (#14). -- **Suggestion:** Hoist into `ResolvedValues` (e.g., `NotebookTaskResolvedValues`) without the `ResolvedValues_` prefix. - -### M37. `SparkJarTask.jarUri` (deprecated) — already deprecated +### M30. `SparkJarTask.jarUri` (deprecated) — already deprecated - **Location:** `model.ts:4328`. - **Category:** OK as docstring; ensure `@deprecated` JSDoc tag added. -### M38. `SparkJarTask.runAsRepl` — deprecated; values restricted +### M31. `SparkJarTask.runAsRepl` — deprecated; values restricted - **Location:** `model.ts:4342`. - **Category:** Vague/misleading (#6). - **Suggestion:** `@deprecated`. Comment says "A value of `false` is no longer supported." -### M39. `JobLevelParameter.default` — `default` is a TS keyword in some positions +### M32. `JobLevelParameter.default` — `default` is a TS keyword in some positions - **Location:** `model.ts:2475`, `model.ts:3510`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Rename to `defaultValue`. - **Rationale:** `default` is a reserved word as a `case` label and `switch` token. Object property `default` is legal but trips linters and confuses code editors. -### M40. `JobsHealthRule.op` and `ConditionTask.op` — short, opaque +### M33. `JobsHealthRule.op` and `ConditionTask.op` — short, opaque - **Location:** `model.ts:2644`, `model.ts:1485`. - **Category:** Cryptic abbreviations (#5). - **Suggestion:** Rename to `operator`. - **Rationale:** `op` saves one word but is too terse for a public API. -### M41. `Repair.type` (RepairType) is a reserved-ish word +### M34. `Repair.type` (RepairType) is a reserved-ish word - **Location:** `model.ts:3099`, `model.ts:4988`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. -### M42. `RunStatus.state` — `state` is generic +### M35. `RunStatus.state` — `state` is generic - **Location:** `model.ts:3882`. - **Category:** Generic field names (#15). - **Suggestion:** Acceptable in context (the type is `RunStatus`), but consider `lifecycleState` to match V1. -### M43. `RunNow.only` field — what does "only" mean? +### M36. `RunNow.only` field — what does "only" mean? - **Location:** `model.ts:3653`. - **Category:** Cryptic abbreviations (#5), misleading names (#6). - **Suggestion:** Rename to `taskKeysToRun` or `runOnlyTasks`. - **Rationale:** A standalone `only: string[]` field on a request is a riddle. -### M44. `RunNow.idempotencyToken`, `SubmitRun.idempotencyToken` — OK +### M37. `RunNow.idempotencyToken`, `SubmitRun.idempotencyToken` — OK - **Location:** `model.ts:3649`, `model.ts:4619`. - **Category:** Verbose but precise. -### M45. `RepairRun.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern +### M38. `RepairRun.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern - **Location:** `model.ts:3126-3132`. - **Category:** Consistent prefix; OK. -### M46. `RepairRun.latestRepairId` vs `RepairRun_Response.repairId` (no `latest`) +### M39. `RepairRun.latestRepairId` vs `RepairRun_Response.repairId` (no `latest`) - **Location:** `model.ts:3124`, `model.ts:3236`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Document the semantic: request takes "the previous latest", response returns "the new latest". -### M47. `SqlTask.sqlTaskType` oneof name is type-tautological +### M40. `SqlTask.sqlTaskType` oneof name is type-tautological - **Location:** `model.ts:4417`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename to `target` or `kind`. The wrapper is already `SqlTask`. -### M48. `SqlTask_SqlOutput.sqlOutputType` — same tautology +### M41. `SqlTask_SqlOutput.sqlOutputType` — same tautology - **Location:** `model.ts:4492`. - **Category:** Type-suffix tautology (#20). -### M49. `Subscription_Subscriber.subscriptionType` +### M42. `Subscription_Subscriber.subscriptionType` - **Location:** `model.ts:4670`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof tag to `target`. -### M50. `AlertTaskSubscriber.subscriberType` +### M43. `AlertTaskSubscriber.subscriberType` - **Location:** `model.ts:837`. - **Category:** Type-suffix tautology (#20). -### M51. `DockerImage.credsOneof` — exposes proto oneof name to TS +### M44. `DockerImage.credsOneof` — exposes proto oneof name to TS - **Location:** `model.ts:1822`. - **Category:** Go/Java-style names (#14). - **Suggestion:** Rename to `credentials` or `auth`. -### M52. `JobRunAs.identity` — OK +### M45. `JobRunAs.identity` — OK - **Location:** `model.ts:2484`. -### M53. `AccessControlRequest.principalName` oneof name doesn't match the contents +### M46. `AccessControlRequest.principalName` oneof name doesn't match the contents - **Location:** `model.ts:725`. - **Category:** Misleading names (#6). - **Suggestion:** Rename to `principal` — the discriminants are `userName | groupName | servicePrincipalName`, not three different name-shaped values. -### M54. `RunTriggerInfo.runId` — what kind of runId? +### M47. `RunTriggerInfo.runId` — what kind of runId? - **Location:** `model.ts:4280`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Rename to `parentRunId` or `triggeringRunId` (JSDoc says "The run id of the Run Job task run"). -### M55. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix +### M48. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix - **Location:** `model.ts:2426`. - **Category:** Acceptable; key is the lookup pattern. -### M56. `JobEnvironment.environmentKey` — same pattern, OK. +### M49. `JobEnvironment.environmentKey` — same pattern, OK. - **Location:** `model.ts:2467`. -### M57. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy +### M50. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy - **Location:** `model.ts:4737`, `model.ts:3917`, `model.ts:4106`, `model.ts:4726`. - **Category:** Verbose but precise. -### M58. `TaskDependency.taskKey` (the task being depended on) — could be `dependsOnTaskKey` +### M51. `TaskDependency.taskKey` (the task being depended on) — could be `dependsOnTaskKey` - **Location:** `model.ts:4726`. -### M59. `TaskDependency.outcome` — value of a condition task: should be `condition` or `requiredOutcome` +### M52. `TaskDependency.outcome` — value of a condition task: should be `condition` or `requiredOutcome` - **Location:** `model.ts:4728`. - **Category:** Generic field names (#15). -### M60. `ResolvedValues` interface has 11 single-purpose sub-types +### M53. `ResolvedValues` interface has 11 single-purpose sub-types - **Location:** `model.ts:3262-3412`. - **Category:** Verbose; many shapes for one purpose. - **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. -### M61. `ClusterSpec.spec` (inside `ClusterSpec`) — name-tautology +### M54. `ClusterSpec.spec` (inside `ClusterSpec`) — name-tautology - **Location:** `model.ts:1223`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `target` or `cluster`. -### M62. `RunTask.spec` (same pattern) +### M55. `RunTask.spec` (same pattern) - **Location:** `model.ts:4046`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `cluster`. -### M63. `RunTaskSettings.spec`, `TaskSettings.spec` — same +### M56. `RunTaskSettings.spec`, `TaskSettings.spec` — same - **Location:** `model.ts:4235`, `model.ts:4875`. - **Category:** Type-suffix tautology (#20). -### M64. `RunTask.task` — oneof inside a type called `RunTask` whose oneof is the task body — tautology +### M57. `RunTask.task` — oneof inside a type called `RunTask` whose oneof is the task body — tautology - **Location:** `model.ts:3948`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `body` or `payload`. -### M65. `BaseRun.numberInJob` — meaningless field (see H12) +### M58. `BaseRun.numberInJob` — meaningless field (see H10) - **Location:** `model.ts:1016`. -### M66. `BaseRun.originalAttemptRunId` — verbose, but precise. +### M59. `BaseRun.originalAttemptRunId` — verbose, but precise. -### M67. `BaseRun.runName` vs `BaseRun.runPageUrl` vs `BaseRun.runType` — repeated `run` prefix on a `BaseRun` type +### M60. `BaseRun.runName` vs `BaseRun.runPageUrl` vs `BaseRun.runType` — repeated `run` prefix on a `BaseRun` type - **Location:** `model.ts:1034`, `model.ts:1036`, `model.ts:1037`. - **Category:** Redundant prefix (#2). - **Suggestion:** Drop `run` prefix when already inside `Run*` type: `name`, `pageUrl`, `type`. -### M68. `Run.runId` (inside `Run`) — tautological +### M61. `Run.runId` (inside `Run`) — tautological - **Location:** `model.ts:3418`, `model.ts:1012`, `model.ts:2103`, `model.ts:3892`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. -### M69. `Run.jobRunId` field while the type is already a job run +### M62. `Run.jobRunId` field while the type is already a job run - **Location:** `model.ts:3474`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Document `runId vs jobRunId` more clearly; consider `parentJobRunId`. -### M70. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRun_Response` — could be deduped +### M63. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRun_Response` — could be deduped - **Location:** `model.ts:1042`, `model.ts:3448`, `model.ts:2133`. -### M71. `RunNow_Response.numberInJob` (see H13). +### M64. `RunNow_Response.numberInJob` (see H11). -### M72. `ListJobs.limit` vs `ListRuns.limit` documentation discrepancy +### M65. `ListJobs.limit` vs `ListRuns.limit` documentation discrepancy - **Location:** `model.ts:2723`, `model.ts:2782`. - **Category:** Inconsistent docs (not naming, but worth flagging). - **Suggestion:** Document max values explicitly; `ListJobs` says ≤100, `ListRuns` says <25. -### M73. `ListJobs.offset` deprecated by `pageToken` — but both still typed +### M66. `ListJobs.offset` deprecated by `pageToken` — but both still typed - **Location:** `model.ts:2721`. - **Category:** Deprecation hygiene. - **Suggestion:** Add `@deprecated` JSDoc to `offset`. -### M74. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) +### M67. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) - **Location:** `model.ts:736`, similar in `DbfsStorageInfo`, `S3StorageInfo`, `GcsStorageInfo`, `LocalFileInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. - **Category:** Generic field names (#15). - **Suggestion:** Each storage type has different URI semantics; `destination` is fine since it's polymorphic, but document the form. -### M75. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type +### M68. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type - **Location:** `model.ts:280`. - **Category:** Type design. - **Suggestion:** Could be `type CodeSource = 'WORKSPACE' | 'GIT'`. Same for `Format`, `ViewType`, etc. -### M76. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead +### M69. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead - **Location:** `model.ts:150-153`. - **Category:** Dead enum value. -### M77. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` +### M70. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` - **Location:** `model.ts:378`. - **Category:** Generic enum value (#1). - **Suggestion:** `UNKNOWN` is universally vague; consider `NOT_EVALUATED`. -### M78. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) +### M71. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) - **Location:** `model.ts:593`, `model.ts:564`, `model.ts:136`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Pick one spelling; "canceled" (single-L) is the American spelling, "cancelled" is the British. Cross-checking with go SDK keeps wire compat. -### M79. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) +### M72. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) - **Location:** `model.ts:693`, `model.ts:634`. - **Category:** Overlapping enum values (#12). - **Suggestion:** Document distinction (one is user-initiated, the other is platform-initiated). -### M80. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +### M73. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized - **Location:** `model.ts:5029`, `model.ts:5033`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Rename to `ClientTypes`. -### M81. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) +### M74. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) - **Location:** `model.ts:3090`. - **Category:** Acronym casing (#3). - **Suggestion:** Cran is an acronym (CRAN = Comprehensive R Archive Network). `RLibrary` works too. The `R` prefix is from the Go SDK. -### M82. `PythonPyPiLibrary` — duplicate "Py" prefix +### M75. `PythonPyPiLibrary` — duplicate "Py" prefix - **Location:** `model.ts:3041`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). -### M83. `MavenLibrary.coordinates` — common, accept. +### M76. `MavenLibrary.coordinates` — common, accept. - **Location:** `model.ts:2828`. -### M84. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. +### M77. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. -### M85. `RunNow.pythonNamedParams` (no suffix `_NamedParametersEntry`?) +### M78. `RunNow.pythonNamedParams` (no suffix `_NamedParametersEntry`?) - **Location:** `model.ts:3714`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Rename to `pythonNamedParameters` to match `notebookParams` being plain; or rename all `*Params` to `*Parameters` consistently. Currently: `jobParameters` (plural Parameters), `notebookParams` (Params), `pythonParams`, `pythonNamedParams`, `sparkSubmitParams`, `sqlParams`, `dbtCommands`, `pipelineParams`, `jarParams`. -### M86. `ListJobs.expandTasks`, `ListRuns.expandTasks` — `boolean` flag is fine. +### M79. `ListJobs.expandTasks`, `ListRuns.expandTasks` — `boolean` flag is fine. -### M87. `ListRuns.runType` shouldn't be optional when the API permits a default +### M80. `ListRuns.runType` shouldn't be optional when the API permits a default - **Location:** `model.ts:2784`. - **Category:** Default semantics. @@ -664,7 +588,7 @@ Issues are catalogued below by severity, then by file/line. ## Low ### L1. `Adlsgen2Info` — see M1. -### L2. `WorkloadType_ClientsTypes` — see M80. +### L2. `WorkloadType_ClientsTypes` — see M73. ### L3. `IncrementalRefreshConfig.onlyRefreshCompletePeriods` — long but precise. - **Location:** `model.ts:2339`. @@ -691,7 +615,7 @@ Issues are catalogued below by severity, then by file/line. ### L10. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. -### L11. `AccessControlRequest.principalName` oneof — see M53. +### L11. `AccessControlRequest.principalName` oneof — see M46. ### L12. `QueueDetails.message` and `QueueDetails.code` — OK. @@ -766,7 +690,7 @@ Issues are catalogued below by severity, then by file/line. - **Category:** Redundant prefixes (#2). - **Suggestion:** `url`, `provider`, `reference`. -### L35. `Run.runName`, `runPageUrl`, `runType` (see M67). +### L35. `Run.runName`, `runPageUrl`, `runType` (see M60). ### L36. `BaseRun.startTime` / `endTime` / `setupDuration` / `executionDuration` / `cleanupDuration` / `endTime` / `runDuration` / `queueDuration` — units-in-name half-applied (Duration but not StartTime). - **Location:** `model.ts:1083-1097`. @@ -782,7 +706,7 @@ Issues are catalogued below by severity, then by file/line. - **Location:** `model.ts:3205`, `model.ts:3585`, `model.ts:3726`, `model.ts:3836`. - **Category:** Repeated identical fields — argues for shared `RunOverrideParameters` base. -### L39. `RunNow.pipelineParams: PipelineParameters` — `Params` vs `Parameters` inconsistency (see M85). +### L39. `RunNow.pipelineParams: PipelineParameters` — `Params` vs `Parameters` inconsistency (see M78). ### L40. `SparkPythonTask.pythonFile` — `python` prefix already encoded in type name - **Location:** `model.ts:4347`. @@ -796,7 +720,7 @@ Issues are catalogued below by severity, then by file/line. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename to `mainClass`. -### L43. `SparkJarTask.runAsRepl` (deprecated) — see M38. +### L43. `SparkJarTask.runAsRepl` (deprecated) — see M31. ### L44. `Library.lib` oneof name is redundant - **Location:** `model.ts:2655`. @@ -806,7 +730,7 @@ Issues are catalogued below by severity, then by file/line. ### L45. `Library.egg` (deprecated) — see top JSDoc. - **Location:** `model.ts:2670`. -### L46. `Library.cran: RCranLibrary` — see M81. +### L46. `Library.cran: RCranLibrary` — see M74. ### L47. `Library.requirements: string` (a requirements.txt URI) — OK. @@ -838,58 +762,51 @@ Issues are catalogued below by severity, then by file/line. - Every oneof in the file uses `{$case: 'tag'; tag: T} | undefined`. - This is a porting convention from `protobuf-ts`/`@bufbuild/protobuf-es`; it's noisy but consistent, and consumers can pattern-match cleanly. Keep. -### O2. `RunLifeCycleState` (V1) vs `RunLifecycleStateV2` divergence is the biggest design debt -- V1 uses CamelCase that splits "LifeCycle" while V2 uses "Lifecycle" — same word, two spellings inside one file. -- V2 adds `WAITING` and `BLOCKED`. The waiters in `client.ts` still use V1. - -### O3. "Task" prefix vs suffix is wildly inconsistent +### O2. "Task" prefix vs suffix is wildly inconsistent - 19 task subtypes exist; some use `XTask` (NotebookTask, SqlTask, DbtTask, PowerBiTask) and some use `XCloudTask` / `XPlatformTask` (DbtCloudTask, DbtPlatformTask). Yet `CleanRoomsNotebookTask` is pluralized. - The base "what's a task here" question requires reading `RunTask.task` oneof to discover. -### O4. ID fields are stringly typed throughout -- All run/job/repair IDs are `number`; `dbtPlatformJobRunId` is `string` (see H19). Standardizing as branded types would prevent silent ID swaps. +### O3. ID fields are stringly typed throughout +- All run/job/repair IDs are `number`; `dbtPlatformJobRunId` is `string` (see H17). Standardizing as branded types would prevent silent ID swaps. -### O5. ID disambiguation is heavy +### O4. ID disambiguation is heavy - `runId`, `jobId`, `taskRunIds`, `originalAttemptRunId`, `jobRunId`, `repairId`, `latestRepairId`, `clusterId`, `sparkContextId`, `cleanRoomName`, `notebookName`, `policyId`, `instancePoolId`, `warehouseId`, `widgetId`, `agentId`, `subscriberId`, `destinationId`, `pipelineId`, `dashboardId`, `dbtCloudJobId`, `dbtPlatformJobId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId`, `idempotencyToken`, `endpointId`, `gpuNodePoolId`. - All over the place; many would benefit from branded types. -### O6. `WorkflowRun` is mentioned in `RunType` but no `Workflow*` type exists +### O5. `WorkflowRun` is mentioned in `RunType` but no `Workflow*` type exists - `RunType.WORKFLOW_RUN` is "from `dbutils.notebook.run`". The lack of a corresponding `WorkflowTask` is intentional but worth a doc note. -### O7. JSDoc references `` template-token in many places +### O6. JSDoc references `` template-token in many places - The literal `` string appears in JSDoc throughout (e.g., `model.ts:1925`, `model.ts:889`). This is the placeholder for env-specific brand. Acceptable. -### O8. Deprecated fields are not consistently marked +### O7. Deprecated fields are not consistently marked - Many fields are described as "Deprecated. Please use the X field instead." in prose but lack `@deprecated` JSDoc tag. - TS LSP will not flag uses; consumers must read prose. Add `@deprecated`. -### O9. Method-vs-type verb-tense pairing +### O8. Method-vs-type verb-tense pairing - `client.cancelRun(CancelRun) → CancelRun_Response`: verb-noun matches. - `client.runNow(RunNow)`: verb-now matches. - `client.repair(RepairRun) → RepairRun_Response`: verb-noun mismatch. - `client.submitRun(SubmitRun)`: verb-noun matches. -- See H33. +- See H26. -### O10. The waiters duplicate ~80 lines of code each +### O9. The waiters duplicate ~80 lines of code each - `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. - Suggestion: `RepairRunWaiter` for consistency. -### O11. `client.ts:594` declares `repair()` method (not `repairRun()`) — see H33, O9. +### O10. `client.ts:594` declares `repair()` method (not `repairRun()`) — see H26, O8. -### O12. `index.ts` re-exports both the value classes and types in two blocks +### O11. `index.ts` re-exports both the value classes and types in two blocks - Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. -### O13. `Format` and `Source` are top-level public enums named with single English words +### O12. `Format` and `Source` are top-level public enums named with single English words - These specific names collide with global and tooling identifiers — see H3, H4. -### O14. Acronym-casing rule should be documented +### O13. Acronym-casing rule should be documented - `Sql`, `Dbt`, `Jvm`, `Adls`, `Aws`, `Azure`, `Gcp`, `Gcs`, `Powerbi` (mixed), `Ml`, `Mlflow`, `Gpu`, `Lakeview`, `Dbfs`, `Ebs`, `Vm`. - The pattern is mostly "first letter of acronym capitalized only", with a few exceptions. Codify. -### O15. Wire-shape vs SDK-shape concept leakage -- `numberInJob`, `originalAttemptRunId`, `Run_JobLevelParameters` are wire artifacts the TS layer should hide or rename. - -### O16. Inconsistent abbreviations: `Params` vs `Parameters` +### O14. Inconsistent abbreviations: `Params` vs `Parameters` - Within the same parent type (e.g., `RunNow`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. - Standardize on `Parameters`. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 27096cea..a5ad014b 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -9,67 +9,55 @@ volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and `KnowledgeSource` each carry their own proto-style nested lifecycle enum (`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). -**Total weird names flagged:** 39 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | -| High | 12 | +| High | 10 | | Medium | 12 | | Low | 9 | | Observation | 6 | ## High severity -### 1. `KnowledgeAssistant_State` proto-style underscored type name — `src/v1/model.ts:9` -- **Why weird:** The enum is named `KnowledgeAssistant_State`, with a literal underscore in the TypeScript identifier. The file even disables `@typescript-eslint/naming-convention` for the line (`-- Proto-style nested enum name.`). Underscores in a public TypeScript type name are a direct violation of the Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers — "Identifiers must use only ASCII letters, digits, underscores (for constants and structured test method names), and the '$' sign"). The lint suppression is itself an admission that the name does not fit the project conventions. Sibling SDK packages have already renamed similar nested enums (e.g., `customllms` flattened proto `OptimizationRun.State` to a top-level `State`; this package keeps the proto-style `Parent_Inner` name). -- **Category:** 4 (underscore in TS identifier), 14 (Go/proto-style name). -- **Suggested name:** `KnowledgeAssistantState` (no underscore) or move it to a top-level `AssistantLifecycleState`. Wire-side `STATE_UNSPECIFIED/CREATING/ACTIVE/FAILED` values are unaffected. -- **Rationale:** The lint disable on line 8 documents the rule violation. Every other Databricks SDK JS enum (jobs, clusters, queries) uses PascalCase without underscores; this package is the outlier. Underscored type names break TS namespace conventions and confuse tooling that splits on `_`. - -### 2. `KnowledgeSource_State` proto-style underscored type name — `src/v1/model.ts:17` -- **Why weird:** Same problem as #1 — `KnowledgeSource_State` carries an underscore in the identifier and the same lint suppression on line 16. Once renamed it pairs with the cousin (`KnowledgeAssistantState` / `KnowledgeSourceState`). -- **Category:** 4 (underscore in TS identifier), 14 (Go/proto-style name). -- **Suggested name:** `KnowledgeSourceState` or `SourceIngestionState`. -- **Rationale:** Same as #1; both enums share the same defect. - -### 3. `KnowledgeAssistant_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:10` +### 1. `KnowledgeAssistant_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:10` - **Why weird:** Reading the value at a call site is `KnowledgeAssistant_State.STATE_UNSPECIFIED` — the token `State` appears twice, and the value is a proto-buf "zero value" sentinel that has no meaning in TypeScript (TS uses `undefined` for "not set"). The wire payload may still send `"STATE_UNSPECIFIED"` for forward compatibility, but the TypeScript side does not need a member for it: every field that takes a state is already `state?: ... | undefined`. - **Category:** 2 (redundant enum prefix), 14 (proto-style sentinel), 18 (long enum value). - **Suggested name:** Drop the `STATE_UNSPECIFIED` member; rename remaining values to PascalCase (`Creating`, `Active`, `Failed`) per the Google TypeScript Style Guide. Keep the existing wire values via Zod transform if needed. - **Rationale:** TS callers must either branch on `STATE_UNSPECIFIED` (which is semantically identical to `state === undefined`) or alias it. Either way the member adds friction without value. -### 4. `KnowledgeSource_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:18` -- **Why weird:** Same as #3, applied to the source-side state enum. +### 2. `KnowledgeSource_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:18` +- **Why weird:** Same as #1, applied to the source-side state enum. - **Category:** 2, 14, 18. - **Suggested name:** Drop `STATE_UNSPECIFIED`; PascalCase the remaining values (`Updating`, `Updated`, `FailedUpdate`). -- **Rationale:** Identical reasoning to #3. +- **Rationale:** Identical reasoning to #1. -### 5. `KnowledgeSource_State.FAILED_UPDATE` vs `KnowledgeAssistant_State.FAILED` — `src/v1/model.ts:13,21` +### 3. `KnowledgeSource_State.FAILED_UPDATE` vs `KnowledgeAssistant_State.FAILED` — `src/v1/model.ts:13,21` - **Why weird:** The two sibling state enums describe lifecycle failure with two different conventions: the assistant uses bare `FAILED`, the source uses `FAILED_UPDATE`. Both enums also use bare past-participle progressives (`CREATING/UPDATING`) for the in-flight state, but only the source enum qualifies the failure with the verb (`FAILED_UPDATE`). A future `DELETE` operation on either resource would surface this asymmetry — the assistant would need `FAILED` to mean "create failed" *and* "delete failed," while the source already qualifies. Consumers reading both enums side by side will assume the assistant's `FAILED` covers something specific, when in fact it is overloaded. - **Category:** 6 (misleading), 17 (inconsistency across sibling enums), 13 (verb-tense inconsistency: bare `FAILED` vs `FAILED_UPDATE`). - **Suggested name:** Align: either both enums use bare `FAILED` (and document that it is operation-agnostic) or both qualify (`FAILED_CREATE` vs `FAILED_UPDATE`). The source enum's name `FAILED_UPDATE` (verb after `FAILED`) is also grammatically awkward — `UPDATE_FAILED` is the standard ordering. - **Rationale:** Two sibling enums in the same file with the same conceptual shape should use the same naming pattern. Today they diverge for no reason. -### 6. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` +### 4. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` - **Why weird:** The "successfully ingested / ready" terminal state is named `UPDATED` — past tense of the in-flight `UPDATING`. A reader scanning `UPDATING/UPDATED/FAILED_UPDATE` will see "the source has been updated" which sounds transient (it was just updated, then something else might happen). The sibling assistant enum uses `ACTIVE` for the same concept (the resource is ready and operational), which is much clearer. - **Category:** 6 (misleading), 13 (verb tense), 17 (inconsistency: assistant has `ACTIVE`, source has `UPDATED`). - **Suggested name:** `READY` (or `ACTIVE`, matching the assistant) for the ready/operational state. `UPDATING` stays for in-flight. - **Rationale:** `UPDATED` implies "the action happened" rather than "the resource is in a ready state." A state enum should describe the resource's condition, not the last operation that touched it. -### 7. `name` field overloaded with semantic role — every request and entity — `src/v1/model.ts:55,64,72,84,120,129,137,160,209,315,324,359` +### 5. `name` field overloaded with semantic role — every request and entity — `src/v1/model.ts:55,64,72,84,120,129,137,160,209,315,324,359` - **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`knowledge-assistants/{id}` or `.../examples/{id}` etc.). At the call site this is fine for one resource type but consumers chain operations across `KnowledgeAssistant`, `KnowledgeSource`, and `Example` — three `name`s in scope all meaning different things. `DeleteKnowledgeSourceRequest.name` is the source name; `SyncKnowledgeSourcesRequest.name` is the **assistant** name (the parent — see model.ts:312). That ambiguity is exactly what generic `name` causes. Compare with `Example.exampleId` and `KnowledgeAssistant.id` on the same file: when a typed id exists, it is more specific than `name`. - **Category:** 1 (vague/generic), 15 (generic field losing meaning), 19 (underspecified id). -- **Suggested name:** Type-qualified: `assistantName`, `sourceName`, `exampleName`. Or, more aligned with Google AIP-122 (https://google.aip.dev/122): keep `name` *only* when the field unambiguously identifies the **same** resource type that the request operates on; rename to `parent` (already used elsewhere — see #8) when it identifies a parent. +- **Suggested name:** Type-qualified: `assistantName`, `sourceName`, `exampleName`. Or, more aligned with Google AIP-122 (https://google.aip.dev/122): keep `name` *only* when the field unambiguously identifies the **same** resource type that the request operates on; rename to `parent` (already used elsewhere — see #6) when it identifies a parent. - **Rationale:** `SyncKnowledgeSourcesRequest.name` is the prime offender: the field is the *assistant* id, but the request is named for sources, so a reader expects the field to be a source id. A typed name (`assistantName`) closes the gap. -### 8. `parent` field generic and inconsistent with `name` — `src/v1/model.ts:30,45,248,300,315` +### 6. `parent` field generic and inconsistent with `name` — `src/v1/model.ts:30,45,248,300,315` - **Why weird:** `CreateExampleRequest.parent`, `CreateKnowledgeSourceRequest.parent`, `ListExamplesRequest.parent`, `ListKnowledgeSourcesRequest.parent`, and `SyncKnowledgeSourcesRequest.name` all refer to **the same wire concept** — a `knowledge-assistants/{id}` resource path. Four of them are called `parent`; the fifth is called `name`. AIP-132 (https://google.aip.dev/132) uses `parent` for list/create requests under a parent resource, so the four are AIP-correct. The `SyncKnowledgeSourcesRequest.name` outlier is the bug — its doc even says "The resource name of the Knowledge Assistant" (model.ts:312). - **Category:** 17 (inconsistency: `parent` vs `name` for the same concept), 16 (field name contradicts the operation's target). - **Suggested name:** Rename `SyncKnowledgeSourcesRequest.name` → `parent` to match the four sibling requests; alternatively rename all five to `assistant` or `knowledgeAssistantName`. - **Rationale:** A consumer who's just learned that `parent` means "the assistant" will write `{parent: '...'}` into `SyncKnowledgeSourcesRequest` and the type checker will reject it for no good reason. -### 9. `KnowledgeAssistant.id` vs `Example.exampleId` vs `KnowledgeSource.id` inconsistency — `src/v1/model.ts:93,164,235` +### 7. `KnowledgeAssistant.id` vs `Example.exampleId` vs `KnowledgeSource.id` inconsistency — `src/v1/model.ts:93,164,235` - **Why weird:** Three sibling entities, three id conventions: - `KnowledgeAssistant.id?: string` (bare `id`) - `KnowledgeSource.id?: string` (bare `id`, no doc) @@ -79,19 +67,19 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `KnowledgeAssistant.knowledgeAssistantId` or `KnowledgeAssistant.assistantId`; `KnowledgeSource.knowledgeSourceId` or `sourceId`; keep `Example.exampleId` as-is. - **Rationale:** Bare `id` is the most common footgun when two resources are passed to the same function (e.g., a UI dialog editing both an assistant and one of its sources). Typed ids prevent type-checker false negatives. -### 10. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` +### 8. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` - **Why weird:** The doc literally enumerates the allowed values: `'The type of the source: "index", "files", or "file_table"'`. A `string` typing means callers can write `sourceType: 'INDEX'` (wrong case) or `sourceType: 'vector_search'` (typo) and the compiler accepts both. Same package already uses Zod-discriminated unions for `spec` (model.ts:229-233), so the type info exists; `sourceType` is the redundant string mirror. - **Category:** 16 (field contradicts type domain — declared as `string` when it is closed-set), 6 (misleading), 12 (duplicate of `spec.$case`). - **Suggested name:** Convert to an enum `KnowledgeSourceType` with values `Index | Files | FileTable`; or drop `sourceType` entirely because `spec.$case` already carries the discriminant. - **Rationale:** Stringly-typed enums are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals — TS supports closed string literal unions specifically to avoid this). The fact that `spec.$case` already discriminates makes `sourceType` pure noise on both reads and writes. -### 11. `Example.guidelines: string[]` and `Example.question: string` semantics overlap with `KnowledgeAssistant.instructions` — `src/v1/model.ts:86,91,185` +### 9. `Example.guidelines: string[]` and `Example.question: string` semantics overlap with `KnowledgeAssistant.instructions` — `src/v1/model.ts:86,91,185` - **Why weird:** Three free-text "how should the assistant behave" fields are scattered across two types: `KnowledgeAssistant.instructions` (single string, global), `Example.guidelines` (array, per-question), `Example.question` (single string, paired with `guidelines`). The names do not disambiguate scope: a reader could reasonably guess `guidelines` are global and `instructions` are per-example; the actual mapping is the other way around. Compare with the same anti-pattern in `customllms.CustomLlm.instructions: string` + `CustomLlm.guidelines: string[]` (audited in `.agent/naming-audit/customllms.md` #12) — that audit flagged the exact same overlap. - **Category:** 6 (misleading), 12 (duplicate concept), 15 (generic field). - **Suggested name:** Rename `KnowledgeAssistant.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerRules` or `responseGuidelines`. Both names disambiguate scope. - **Rationale:** Two free-text fields with synonymous names but different scope is one of the most common API-design defects. The audit caught the same pattern in `customllms`; flagging it here for SDK-wide consistency. -### 12. `KnowledgeSource.spec` discriminated union name is generic — `src/v1/model.ts:229` +### 10. `KnowledgeSource.spec` discriminated union name is generic — `src/v1/model.ts:229` - **Why weird:** `KnowledgeSource.spec?: { $case: 'index'; index: IndexSpec } | { $case: 'files'; files: FilesSpec } | { $case: 'fileTable'; fileTable: FileTableSpec } | undefined`. The discriminator field is called `spec` — a generic CS term. The doc says "Specification for the knowledge source type." Consumers writing autocomplete will see `source.spec.$case` and `source.sourceType` both meaning "what kind of source is this", and have to remember that `spec` carries the *data* and `sourceType` carries the *string label*. Compare with the `supervisoragents.Tool.spec` field (same anti-pattern; same audit flagged in the sibling). - **Category:** 1 (vague), 12 (duplicate of `sourceType` discriminant). - **Suggested name:** `config` if the union carries configuration (it does); or `source` to mirror the `$case` semantics ("which source variant"). Best: collapse `sourceType` and `spec` into a single discriminated union. @@ -99,49 +87,49 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Medium severity -### 13. `FileTableSpec.fileCol` cryptic abbreviation — `src/v1/model.ts:105` +### 11. `FileTableSpec.fileCol` cryptic abbreviation — `src/v1/model.ts:105` - **Why weird:** `fileCol` truncates `column` to `Col`. The same pattern showed up in `customllms.Table.requestCol`/`responseCol` (flagged in `customllms.md` #15). The field on its sibling, `IndexSpec`, uses both `textCol` and `docUriCol` — same abbreviation. Other fields in the same file spell things out (`endpointName`, `experimentId`, `knowledgeCutoffTime`), so `Col` is inconsistent within the package. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency). - **Suggested name:** `fileColumn` (and `textColumn` / `docUriColumn`). - **Rationale:** Three characters of identifier savings is not worth the cognitive split between the doc ("column") and the field name. -### 14. `IndexSpec.textCol` / `IndexSpec.docUriCol` cryptic abbreviation — `src/v1/model.ts:145,147` -- **Why weird:** Same `Col` abbreviation as #13, plus `docUri` truncates "document URI" awkwardly. Reading `docUriCol`, your eye parses `doc-Uri-Col` — three abbreviations stacked. The doc reads "The column that specifies a link or reference to where the information came from" — a much friendlier name would be `sourceUriColumn` or `referenceColumn`. +### 12. `IndexSpec.textCol` / `IndexSpec.docUriCol` cryptic abbreviation — `src/v1/model.ts:145,147` +- **Why weird:** Same `Col` abbreviation as #11, plus `docUri` truncates "document URI" awkwardly. Reading `docUriCol`, your eye parses `doc-Uri-Col` — three abbreviations stacked. The doc reads "The column that specifies a link or reference to where the information came from" — a much friendlier name would be `sourceUriColumn` or `referenceColumn`. - **Category:** 5 (cryptic abbreviation), 3 (acronym casing: `Uri` vs `URI`). -- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #38). +- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #36). - **Rationale:** The savings are minimal; the readability cost is real. -### 15. `IndexSpec.indexName` type-suffix tautology — `src/v1/model.ts:143` +### 13. `IndexSpec.indexName` type-suffix tautology — `src/v1/model.ts:143` - **Why weird:** `IndexSpec.indexName` repeats `Index` in the type and field. The doc says it is the full UC name of the vector search index. Same pattern as `FileTableSpec.tableName` (model.ts:103). Both fields are documented as a fully-qualified three-part UC name (catalog.schema.x) — same concept Unity Catalog calls `full_name` in `catalog.TableInfo.full_name`. - **Category:** 20 (type-suffix tautology), 1 (vague — `*Name` does not communicate "fully qualified"). - **Suggested name:** `fullName` (matches Unity Catalog convention) or `qualifiedName`. If kept as `*Name`, at least drop the type prefix: `IndexSpec.fullName` reads better than `IndexSpec.indexName`. - **Rationale:** Unity Catalog already has a canonical token; reusing it makes cross-API code less surprising. -### 16. `FileTableSpec.tableName` type-suffix tautology — `src/v1/model.ts:103` -- **Why weird:** Same problem as #15 — `FileTableSpec.tableName` repeats `Table` in the type and field. +### 14. `FileTableSpec.tableName` type-suffix tautology — `src/v1/model.ts:103` +- **Why weird:** Same problem as #13 — `FileTableSpec.tableName` repeats `Table` in the type and field. - **Category:** 20 (type-suffix tautology), 1 (vague). - **Suggested name:** `fullName` or `qualifiedName`. -- **Rationale:** Same as #15. +- **Rationale:** Same as #13. -### 17. `Example.question` + `Example.guidelines` field-name doublet — `src/v1/model.ts:86,91` -- **Why weird:** `Example` has two free-text payload fields: the question being asked and the guidelines for the answer. The current names are fine *in isolation*, but the type's own doc explains "Contains a question and guidelines for how the assistant should respond" — and the field names then duplicate the doc verbatim. The bigger issue: `guidelines: string[]` is plural and an array, but no JSDoc explains the semantics of each element (is each entry a sentence? a bullet? a paragraph?). Combined with the parallel `KnowledgeAssistant.instructions: string` (#11), the naming makes the conceptual hierarchy unclear. +### 15. `Example.question` + `Example.guidelines` field-name doublet — `src/v1/model.ts:86,91` +- **Why weird:** `Example` has two free-text payload fields: the question being asked and the guidelines for the answer. The current names are fine *in isolation*, but the type's own doc explains "Contains a question and guidelines for how the assistant should respond" — and the field names then duplicate the doc verbatim. The bigger issue: `guidelines: string[]` is plural and an array, but no JSDoc explains the semantics of each element (is each entry a sentence? a bullet? a paragraph?). Combined with the parallel `KnowledgeAssistant.instructions: string` (#9), the naming makes the conceptual hierarchy unclear. - **Category:** 15 (generic field name losing meaning), 1 (vague — "guidelines" of what?). -- **Suggested name:** `Example.question` is fine; rename `Example.guidelines` → `answerGuidelines` (or `responseGuidelines`, paired with rename in #11). +- **Suggested name:** `Example.question` is fine; rename `Example.guidelines` → `answerGuidelines` (or `responseGuidelines`, paired with rename in #9). - **Rationale:** A type that owns a single question/answer pair should make the answer-shaped field explicit. -### 18. `KnowledgeAssistant.endpointName` underspecified — `src/v1/model.ts:191` +### 16. `KnowledgeAssistant.endpointName` underspecified — `src/v1/model.ts:191` - **Why weird:** The doc reads "The name of the knowledge assistant agent endpoint." Three reads of "agent endpoint" raise the question: is this a model-serving endpoint? An MLflow endpoint? An AI Gateway endpoint? The sibling SDK `customllms` has the same `endpointName: string` (flagged in `customllms.md` #7 as ambiguous). In Databricks the term "endpoint" alone is overloaded across `model_serving`, `sql_warehouses`, `vector_search_endpoints`, etc. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or just `agentEndpointName`. The sibling `supervisoragents.KnowledgeAssistant.servingEndpointName` actually uses `servingEndpointName` (see `supervisoragents/src/v1/model.ts:129`), so the rename here would *align* the two packages. - **Rationale:** Cross-package consistency wins. `supervisoragents` already named the field correctly; copy that. -### 19. `KnowledgeAssistant.experimentId` — what kind of experiment? — `src/v1/model.ts:193` +### 17. `KnowledgeAssistant.experimentId` — what kind of experiment? — `src/v1/model.ts:193` - **Why weird:** Doc reads "The MLflow experiment ID." A bare `experimentId` is fine *if* the consumer knows the SDK only integrates with MLflow. But the consumer reading `KnowledgeAssistant.experimentId` could reasonably guess this is an A/B-test experiment, a feature-flag experiment, or an MLflow experiment. The doc clarifies — but the name does not. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `mlflowExperimentId` (matches the doc; matches `databricks.mlflow` API convention). -- **Rationale:** Field names should not require reading JSDoc to disambiguate. Same reasoning as #18. +- **Rationale:** Field names should not require reading JSDoc to disambiguate. Same reasoning as #16. -### 20. `KnowledgeAssistant.errorInfo: string` — `src/v1/model.ts:195` +### 18. `KnowledgeAssistant.errorInfo: string` — `src/v1/model.ts:195` - **Why weird:** Two issues: - Suffix `Info` is generic CS noise (rule 8: redundant suffix). `error` alone or `errorMessage` is more specific. - Type is `string` but the field is reserved for "Error details when the Knowledge Assistant is in FAILED state." Other Databricks APIs (jobs, clusters) use structured `ErrorInfo` objects with `code`, `message`, `details`. A bare string forces consumers to parse free text — and a future structured upgrade would be a breaking change. @@ -149,7 +137,7 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `errorMessage` (if the field stays a string) or convert to an `ApiError` object (if the field upgrades). Drop the `Info` suffix either way. - **Rationale:** The `Info` suffix is a Go/Java carryover (`*Info` types are common in proto messages); TS gets clearer names without it. -### 21. `KnowledgeAssistant.creator: string` — what is a creator? — `src/v1/model.ts:187` +### 19. `KnowledgeAssistant.creator: string` — what is a creator? — `src/v1/model.ts:187` - **Why weird:** Doc reads "The creator of the Knowledge Assistant." Could be a username, email, UUID, Databricks principal id, or service principal client id. The type is `string`. The exact same pattern was flagged in `customllms.md` #10 — also a `creator: string`. The convention varies across the SDK: - Unity Catalog: `created_by` (matches AIP-148, https://google.aip.dev/148) - Jobs: `creator_user_name` @@ -158,7 +146,7 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `createdBy` (AIP-148 standard, also matches `unitycatalog`) with JSDoc clarifying it is a user email. - **Rationale:** Match the most-used convention. `createdBy` reads naturally and is widely understood. -### 22. `KnowledgeSource.knowledgeCutoffTime` ambiguous semantics — `src/v1/model.ts:237` +### 20. `KnowledgeSource.knowledgeCutoffTime` ambiguous semantics — `src/v1/model.ts:237` - **Why weird:** Doc reads "Timestamp representing the cutoff before which content in this knowledge source is being ingested." Two interpretations: - "Ingestion stops at this time" (a future bound). - "Only content created before this time is being ingested" (a past bound). @@ -167,13 +155,13 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `dataAsOf` or `contentAsOf` if the field is a past bound (most likely); `ingestionDeadline` if it is a future bound. - **Rationale:** A timestamp field whose meaning depends on JSDoc parsing is a footgun. Pick a name that encodes direction. -### 23. `KnowledgeSource_State.UPDATING` vs `KnowledgeAssistant_State.CREATING` inconsistent verbs — `src/v1/model.ts:11,19` +### 21. `KnowledgeSource_State.UPDATING` vs `KnowledgeAssistant_State.CREATING` inconsistent verbs — `src/v1/model.ts:11,19` - **Why weird:** Both enums describe "a write operation is in flight." The assistant uses `CREATING` (matches its lifecycle — assistants are created once and updated thereafter). The source uses `UPDATING` (matches its lifecycle — sources are created with content, then their content is refreshed via sync). Both enums conflate "creation" and "update" into one in-flight state; the names just disagree on which verb to use. - **Category:** 13 (verb-tense / verb-choice inconsistency), 17 (inconsistency across sibling enums). - **Suggested name:** Both should use `PROCESSING` or `IN_PROGRESS` — operation-agnostic in-flight markers. If lifecycle stages matter, both should split into `CREATING` / `UPDATING` consistently. - **Rationale:** The asymmetry suggests the API team modeled the two resources separately and never unified the lifecycle vocabulary. -### 24. `Client` class name — bare, no scoping — `src/v1/client.ts:63` +### 22. `Client` class name — bare, no scoping — `src/v1/client.ts:63` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-knowledgeassistants/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as KAClient} from '@databricks/sdk-knowledgeassistants/v1'`. Other SDKs in the Databricks ecosystem name the class `KnowledgeAssistantsClient` (or `KnowledgeAssistantsApi`), avoiding the alias dance. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `KnowledgeAssistantsClient`. Sibling SDK packages (Go SDK reference uses `WorkspaceClient.KnowledgeAssistants`; AWS JS SDK uses `S3Client`, `IAMClient`) follow this pattern. @@ -181,55 +169,55 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Low severity -### 25. `KnowledgeAssistant_State.CREATING` vs `KnowledgeSource_State.UPDATING` — `src/v1/model.ts:11,19` -- **Why weird:** See #23; flagged again at low severity as a *style* concern (the higher-severity finding is the verb-mismatch). +### 23. `KnowledgeAssistant_State.CREATING` vs `KnowledgeSource_State.UPDATING` — `src/v1/model.ts:11,19` +- **Why weird:** See #21; flagged again at low severity as a *style* concern (the higher-severity finding is the verb-mismatch). - **Category:** 13 (verb tense). -- **Suggested name:** See #23. +- **Suggested name:** See #21. - **Rationale:** Cosmetic but consistent with audit's "verb-tense inconsistency" category. -### 26. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +### 24. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21. - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than one infix. -### 27. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +### 25. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` - **Why weird:** Same as `customllms.md` #23: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in the same file. Three things named `Options`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams`. - **Rationale:** Distinguish internal context bags from user-facing options. -### 28. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 26. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `customllms.md` #28: exported but not used by `client.ts`. - **Category:** Observation / 11 (unused export). - **Suggested name:** Either remove the export or document why it ships per-package. - **Rationale:** Generated artifact; flag for cross-package cleanup. -### 29. `readAll` helper generic name — `src/v1/utils.ts:40` +### 27. `readAll` helper generic name — `src/v1/utils.ts:40` - **Why weird:** Same as `customllms.md` #29: helper reads an entire response body stream; name is generic. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` +### 28. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` - **Why weird:** Same as `customllms.md` #24: `Segment` is a generic CS term. - **Category:** 1 (vague). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** SDK-wide consistency review. -### 31. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` +### 29. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` - **Why weird:** Same as `customllms.md` #33: `resp` is the response. 12 methods repeat the same pattern. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. - **Rationale:** Refactor opportunity surfaced by audit. -### 32. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` +### 30. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` - **Why weird:** Three async generator methods each declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. Minor abbreviation inconsistency: `request` would be clearer in the iterator context, where the variable's purpose ("the request used to fetch each page") differs from the input `req`. - **Category:** 5 (abbreviation). - **Suggested name:** `pageRequest` or `nextPageReq`. - **Rationale:** Local clarity for readability. -### 33. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` +### 31. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` - **Why weird:** `knowledgeSourceFieldMaskSchema` carries top-level entries `fileTable`, `files`, `index` — matching the `$case` keys, but the wire serialization uses `file_table`/`files`/`index`. Reading the schema, a consumer might write `knowledgeSourceFieldMask('spec.files')` expecting the variant-aware path; the field-mask schema has no `spec` key at all. The discriminated union variants are flattened to top-level field-mask paths, which is correct AIP-161 (https://google.aip.dev/161) behavior — but jarring if you've read the TS type. - **Category:** 17 (inconsistency between TS shape and field-mask schema). - **Suggested name:** Not a rename; flag for documentation. @@ -237,29 +225,29 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Observations -### 34. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` +### 32. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` - **Why weird:** Doc says "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Either every `description` should carry this annotation, or none should. Flagged for cross-package style review. - **Category:** Observation. -### 35. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` +### 33. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` - **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. - **Category:** 17 (reversed — consistency note). -### 36. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` -- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #7, #8). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. +### 34. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #5, #6). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. -### 37. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` +### 35. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` - **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `APIError` usage. Cross-cutting observation from `customllms.md` #36. - **Category:** 3 (acronym casing — SDK-wide). - **Suggested name:** SDK-wide policy decision. -### 38. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +### 36. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` - **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. - **Category:** Observation. -### 39. `Example` lacks `state` field — `src/v1/model.ts:79-98` +### 37. `Example` lacks `state` field — `src/v1/model.ts:79-98` - **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. - **Category:** Observation. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index e57f75c1..3f56f887 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,16 +3,16 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 42 +**Total weird names flagged:** 35 ## Summary | Severity | Count | | ----------- | ----- | -| High | 8 | -| Medium | 17 | -| Low | 11 | -| Observation | 6 | +| High | 6 | +| Medium | 15 | +| Low | 9 | +| Observation | 5 | ## Summary table @@ -24,43 +24,37 @@ | 4 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashDashboard` | 17 | | 5 | High | `model.ts` interface | `Dashboard` | 1, 15 | | 6 | High | `model.ts` interface | `PublishedDashboard` | 12 | -| 7 | High | `model.ts` interface (nested) | `AuthorizationDetails_GrantRule` | 4, 14 | -| 8 | High | `model.ts` interface (nested triplet) | `Subscription_Subscriber`, `Subscription_Subscriber_User`, `Subscription_Subscriber_Destination` | 4, 14 | -| 9 | Medium | `model.ts` interface | `CronSchedule` | 1 | -| 10 | Medium | `model.ts` field | `CronSchedule.quartzCronExpression` | 14, 20 | -| 11 | Medium | `model.ts` field | `CronSchedule.timezoneId` | 19 | -| 12 | Medium | `model.ts` field | `Schedule.cronSchedule` | 20 | -| 13 | Medium | `model.ts` enum | `SchedulePauseStatus` | 1, 7 | -| 14 | Medium | `model.ts` field | `Schedule.pauseStatus` | 6, 20 | -| 15 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | -| 16 | Medium | `model.ts` field | `MigrateDashboardRequest.sourceDashboardId` | 16 | -| 17 | Medium | `model.ts` field | `MigrateDashboardRequest.updateParameterSyntax` | 6, 13, 15 | -| 18 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | -| 19 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | -| 20 | Medium | `model.ts` interface | `GetPublishedDashboardEmbeddedRequest` | 1, 7 | -| 21 | Medium | `model.ts` field | `GetPublishedDashboardTokenInfoResponse.customClaim` | 15 | -| 22 | Medium | `model.ts` field | `AuthorizationDetails.type` | 10, 15 | -| 23 | Medium | `model.ts` field | `AuthorizationDetails.resourceLegacyAclPath` | 6, 14, 16 | -| 24 | Medium | `model.ts` field | `Subscription.skipNotify` | 1, 14 | -| 25 | Medium | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | -| 26 | Medium | `model.ts` field | `Subscription_Subscriber_User.userId` typed `number` | 19, 16 | -| 27 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | -| 28 | Low | `model.ts` field | `Schedule.warehouseId` | 19, 12 | -| 29 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | -| 30 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | -| 31 | Low | `model.ts` field | `Dashboard.serializedDashboard` | 20 | -| 32 | Low | `model.ts` field | `Dashboard.lifecycleState` | 15 | -| 33 | Low | `model.ts` field | `Dashboard.createTime` / `updateTime` & `Schedule.*` / `Subscription.*` | 9 | -| 34 | Low | `model.ts` field | `PublishedDashboard.revisionCreateTime` | 15 | -| 35 | Low | `model.ts` field | `PublishDashboardRequest.embedCredentials` | 7 | -| 36 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | -| 37 | Low | `model.ts` field | `DashboardView.DASHBOARD_VIEW_BASIC` | 2, 18 | -| 38 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | -| 39 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | -| 40 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | -| 41 | Observation | `model.ts` field | `Subscription_Subscriber.userSubscriber` / `destinationSubscriber` | 8, 20 | -| 42 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | -| 43 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | +| 7 | Medium | `model.ts` interface | `CronSchedule` | 1 | +| 8 | Medium | `model.ts` field | `CronSchedule.quartzCronExpression` | 14, 20 | +| 9 | Medium | `model.ts` field | `CronSchedule.timezoneId` | 19 | +| 10 | Medium | `model.ts` field | `Schedule.cronSchedule` | 20 | +| 11 | Medium | `model.ts` enum | `SchedulePauseStatus` | 1, 7 | +| 12 | Medium | `model.ts` field | `Schedule.pauseStatus` | 6, 20 | +| 13 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | +| 14 | Medium | `model.ts` field | `MigrateDashboardRequest.sourceDashboardId` | 16 | +| 15 | Medium | `model.ts` field | `MigrateDashboardRequest.updateParameterSyntax` | 6, 13, 15 | +| 16 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | +| 17 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | +| 18 | Medium | `model.ts` interface | `GetPublishedDashboardEmbeddedRequest` | 1, 7 | +| 19 | Medium | `model.ts` field | `GetPublishedDashboardTokenInfoResponse.customClaim` | 15 | +| 20 | Medium | `model.ts` field | `AuthorizationDetails.type` | 10, 15 | +| 21 | Medium | `model.ts` field | `AuthorizationDetails.resourceLegacyAclPath` | 6, 14, 16 | +| 22 | Low | `model.ts` field | `Subscription.skipNotify` | 1, 14 | +| 23 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | +| 24 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | +| 25 | Low | `model.ts` field | `Schedule.warehouseId` | 19, 12 | +| 26 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | +| 27 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | +| 28 | Low | `model.ts` field | `Dashboard.serializedDashboard` | 20 | +| 29 | Low | `model.ts` field | `Dashboard.createTime` / `updateTime` & `Schedule.*` / `Subscription.*` | 9 | +| 30 | Low | `model.ts` field | `PublishedDashboard.revisionCreateTime` | 15 | +| 31 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | +| 32 | Low | `model.ts` field | `DashboardView.DASHBOARD_VIEW_BASIC` | 2, 18 | +| 33 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | +| 34 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | +| 35 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | +| 36 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | +| 37 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | --- @@ -130,7 +124,7 @@ import {LifecycleState as AlertLifecycle} from '@databricks/sdk-alerts'; **Rationale:** Eliminates the import-rename ritual. Consistent with the rest of the SDK after the alerts v2 refactor. -### 4. `LifecycleState.TRASHED` vs `trashDashboard()` — split vocabulary inside one package +### 4. `LifecycleState.TRASHED` vs `trashDashboard()` — split vocabulary inherited from pre-v2 alerts **Location:** `src/v1/model.ts:15`, `src/v1/client.ts:653` (`trashDashboard`), `src/v1/model.ts:429` (`TrashDashboardRequest`) @@ -179,60 +173,11 @@ No `dashboardId`. No `etag`. No `serializedDashboard`. No reference back to the **Rationale:** Today every caller of `getPublishedDashboard()` has to remember the `dashboardId` they passed in to use the response. The type should round-trip. -### 7. `AuthorizationDetails_GrantRule` — proto nested-message style leaking into TS - -**Location:** `src/v1/model.ts:45-52` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface AuthorizationDetails_GrantRule { - permissionSet?: string | undefined; -} -``` - -Underscore-separated identifier in a TS interface name. The comment acknowledges the violation. The choice preserves the protobuf path (`message AuthorizationDetails.GrantRule`) and helps with grep'ing through generated code, but for consumers the type appears as `AuthorizationDetails_GrantRule` everywhere — an uncomfortable identifier to type and read. - -The same package re-exports it from `index.ts`, so the underscore is part of the public API surface. - -**Category:** 4 (underscores in TS identifiers), 14 (Go/Java/proto-style name). - -**Suggested name:** `GrantRule` (top-level) or `AuthorizationGrantRule`. There is no other `GrantRule` in this package, so the bare name is unambiguous. If naming nesting is desired, namespace-merging is the idiomatic TS pattern: - -```ts -export interface AuthorizationDetails { ... } -export namespace AuthorizationDetails { - export interface GrantRule { ... } -} -// Use site: AuthorizationDetails.GrantRule -``` - -**Rationale:** TypeScript supports namespace-merging for exactly this case. The underscore form is grep-friendly but ugly; the namespace form is grep-friendly *and* readable. - -### 8. `Subscription_Subscriber`, `Subscription_Subscriber_User`, `Subscription_Subscriber_Destination` — three nested levels of underscore-named types - -**Location:** `src/v1/model.ts:403-427` - -```ts -export interface Subscription_Subscriber { ... } -export interface Subscription_Subscriber_Destination { ... } -export interface Subscription_Subscriber_User { ... } -``` - -Three more proto-nested types with underscores. The naming becomes especially awkward when used: `Subscription_Subscriber_User.userId`, `Subscription_Subscriber_Destination.destinationId`. Each layer of nesting adds a `_Subscriber`, doubling the prefix length. The double `_Subscriber_Subscriber` flavor (`Subscription_Subscriber` itself is the discriminated union, and `Subscription_Subscriber_User` is a variant of it) is especially confusing — at a glance you can't tell which one is the union and which is the leg. - -Together with `AuthorizationDetails_GrantRule` (above), this is the dominant naming smell in the file: four public types whose names violate `@typescript-eslint/naming-convention` and require suppressions. - -**Category:** 4, 14. - -**Suggested name:** `Subscriber`, `UserSubscriber`, `DestinationSubscriber` — and a top-level discriminated union `Subscriber = UserSubscriber | DestinationSubscriber`. Or namespace-merging under `Subscription` as in #7. - -**Rationale:** A real discriminated union in TS is more useful than a `oneof`-style "both fields optional, only one is set" interface. The current type allows both `userSubscriber` and `destinationSubscriber` to be undefined or both populated simultaneously — the type system does not enforce the "mutually exclusive" rule that the JSDoc claims. - --- ## Medium severity -### 9. `CronSchedule` — generic type name in a single-domain package +### 7. `CronSchedule` — generic type name in a single-domain package **Location:** `src/v1/model.ts:80-91` @@ -251,7 +196,7 @@ The package exports a top-level `CronSchedule`. The same name appears in `alerts **Rationale:** Future-proofing: the field set may diverge from other services' cron-schedule types (some add a `pauseStatus`, some add a `nextFireTime`). A domain-prefixed name prevents `import { CronSchedule } from '@databricks/sdk-lakeview'` from being a confusing rename. -### 10. `CronSchedule.quartzCronExpression` — implementation-detail leak and type-suffix tautology +### 8. `CronSchedule.quartzCronExpression` — implementation-detail leak and type-suffix tautology **Location:** `src/v1/model.ts:85` @@ -273,7 +218,7 @@ Two concerns: **Rationale:** The wire format `quartz_cron_expression` is locked, but the TS name is not. A simple, accurate field name with the dialect in the doc is more usable. -### 11. `CronSchedule.timezoneId` — "Id" suffix is misleading +### 9. `CronSchedule.timezoneId` — "Id" suffix is misleading **Location:** `src/v1/model.ts:90` @@ -292,7 +237,7 @@ The field carries an IANA timezone name like `"America/Los_Angeles"`. That is no **Rationale:** `timezoneId` makes callers think there's a separate `getTimezones()` API that returns IDs. -### 12. `Schedule.cronSchedule` — type-suffix tautology +### 10. `Schedule.cronSchedule` — type-suffix tautology **Location:** `src/v1/model.ts:358` @@ -312,7 +257,7 @@ The field name and type name are the same. `schedule.cronSchedule.expression` re **Rationale:** Field names should describe the *role* the value plays in the parent, not echo the type. The role is "the cron part of this schedule". -### 13. `SchedulePauseStatus` — domain prefix only partially applied +### 11. `SchedulePauseStatus` — domain prefix only partially applied **Location:** `src/v1/model.ts:18-21` @@ -333,7 +278,7 @@ Also: a two-value enum named `*Status` for two paused-or-not states is overengin **Rationale:** Binary status enums are an anti-pattern in TS where booleans are first-class. The Go SDK is constrained to enums (no booleans for proto), but the TS SDK is not. -### 14. `Schedule.pauseStatus` — field describes a control input, not a status +### 12. `Schedule.pauseStatus` — field describes a control input, not a status **Location:** `src/v1/model.ts:360` @@ -346,11 +291,11 @@ pauseStatus?: SchedulePauseStatus | undefined; **Category:** 6 (misleading), 20 (the type ends in `Status` and the field starts with `pauseStatus` — overlap). -**Suggested name:** `paused: boolean` (see #13), or `pauseSetting`/`pauseMode`. Reserve `*Status` for read-only state. +**Suggested name:** `paused: boolean` (see #11), or `pauseSetting`/`pauseMode`. Reserve `*Status` for read-only state. **Rationale:** Read/write distinction. If the user only learns the field name, they will not predict that setting `UNPAUSED` is how you un-pause. -### 15. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb +### 13. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb **Location:** `src/v1/model.ts:293`, `src/v1/client.ts:574` @@ -362,7 +307,7 @@ pauseStatus?: SchedulePauseStatus | undefined; **Rationale:** The other Databricks "migrate" endpoints (e.g. `tables.migrate`, `permissions.migrate`) actually move state. This one creates a new asset. Same verb, two operations. -### 16. `MigrateDashboardRequest.sourceDashboardId` — domain mismatch +### 14. `MigrateDashboardRequest.sourceDashboardId` — domain mismatch **Location:** `src/v1/model.ts:295` @@ -379,7 +324,7 @@ The package documents `dashboardId` as identifying a Lakeview / AI/BI dashboard. **Rationale:** Cross-API IDs that share a name are a frequent source of integration bugs. -### 17. `MigrateDashboardRequest.updateParameterSyntax` — confusing default + leaky implementation hint +### 15. `MigrateDashboardRequest.updateParameterSyntax` — confusing default + leaky implementation hint **Location:** `src/v1/model.ts:300-304` @@ -403,7 +348,7 @@ Issues: **Rationale:** Migration is a one-way operation; setting this wrong is hard to recover from. -### 18. `trashDashboard` — see #4. Also: only soft-delete method in the entire package +### 16. `trashDashboard` — soft-delete method without a paired restore (see also #4) **Location:** `src/v1/client.ts:653` @@ -415,7 +360,7 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met **Rationale:** Symmetry. `deletePermanently` is also unavailable here — soft-delete is the only delete. -### 19. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles +### 17. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles **Location:** `src/v1/model.ts:307`, `src/v1/model.ts:323` @@ -427,7 +372,7 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met **Rationale:** Reduce typo bugs. The Databricks SDK already uses `*Options` in `ClientOptions`, `CallOptions`, so the pattern is precedented. -### 20. `GetPublishedDashboardEmbeddedRequest` / `getPublishedDashboardEmbedded` — adjective-as-method-suffix +### 18. `GetPublishedDashboardEmbeddedRequest` / `getPublishedDashboardEmbedded` — adjective-as-method-suffix **Location:** `src/v1/model.ts:169-175`, `src/v1/client.ts:301` @@ -443,7 +388,7 @@ async getPublishedDashboardEmbedded(req: ...): Promise DISABLED. The JSDoc on the method (`client.ts:209-212`) calls it out: "Enables or disables a log delivery configuration." The Go SDK method is named `PatchStatus`, which is honest. - **Suggested name:** `patchStatus`, or `setStatus`, or `updateStatus`. The current name oversells the surface. - **Rationale:** "Update" implies multi-field mutation. If a caller writes `client.updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new-prefix'})` they will be silently surprised — the `deliveryPathPrefix` is not part of the request DTO so it will not type-check (in TS strict mode), but they would have to read the type to learn that. The verb is a footgun. -### M11. `listLogDeliveryConfiguration` — singular noun on a method returning multiple — `client.ts:150,192` +### M10. `listLogDeliveryConfiguration` — singular noun on a method returning multiple — `client.ts:150,192` - **File:** `client.ts:150,192`. - **Category:** 9 (singular/plural mismatch). - **Why weird:** `listLogDeliveryConfiguration` is singular ("Configuration") but the method yields multiple configurations (the response body field is `logDeliveryConfigurations` — plural — at `model.ts:160`). Sibling packages use plural — e.g., `listBudgetConfigurations` in `budgets/src/v1/client.ts`. The singular method name fights the plural data shape. - **Suggested name:** `listLogDeliveryConfigurations` (plural noun). - **Rationale:** Adjacent package `budgets` uses `listBudgetConfigurations` (plural). Within this package, the response body field is plural while the method name is singular — pluralisation should match the collection it returns. -### M12. `ListLogDeliveryConfiguration` (request type) is singular — `model.ts:141` +### M11. `ListLogDeliveryConfiguration` (request type) is singular — `model.ts:141` - **File:** `model.ts:141-155`. - **Category:** 9 (singular/plural mismatch). -- **Why weird:** Same issue as M11 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. +- **Why weird:** Same issue as M10 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. - **Suggested name:** `ListLogDeliveryConfigurationsRequest` (plural + `Request` suffix for clarity). - **Rationale:** Naming should match data shape. Pluralisation is the standard signal that a method returns a collection. Cross-package inconsistency. -### M13. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:117,205,217` +### M12. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:117,205,217` - **File:** `model.ts:117,205` (field `logDeliveryStatus: LogDeliveryStatus`), `model.ts:208` (interface `LogDeliveryStatus`), `model.ts:217` (`status?: LogDeliveryStatusEnum`). - **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). - **Why weird:** A reader looking at `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types: @@ -146,35 +139,35 @@ method. - **Suggested name:** Field: `lastAttempt: LogDeliveryAttempt`. Wrapper type: `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message` — drop `last` prefix once nested). Enum: `LogDeliveryAttemptStatus`. Result reads as `config.lastAttempt.status === 'SUCCEEDED'`. - **Rationale:** "Status" is too generic to triple-stack. Renaming the wrapper to "Attempt" (its actual semantics) breaks the conflation cleanly. -### M14. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:113-115,201-203` +### M13. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:113-115,201-203` - **File:** `model.ts:113-115,201-203`. - **Category:** 13 (verb-tense inconsistency — `creation` is a noun, `update` is a verb), 6 (misleading — `number` type with JSDoc "epoch milliseconds"). - **Why weird:** `creationTime: number` and `updateTime: number`. The first is noun-form ("creation"), the second is verb-form ("update"). Pair-wise they should match: `createdTime`/`updatedTime` (past participle) or `creationTime`/`updateTime` (noun). Also, both are `number` (epoch ms) but neither type signals "this is a unix timestamp in milliseconds"; the JSDoc carries that information. Across the SDK, audited packages have flagged similar issues. - **Suggested name:** `createdAt: number` / `updatedAt: number` (canonical SaaS convention — Stripe/GitHub/Salesforce/Atlassian all use *At). Brand the type as `EpochMillis` for compile-time safety. - **Rationale:** "*At" is the industry standard for timestamps. Same finding in many other audited packages (`budgets`, `apps`, etc.) — fix at generator level. -### M15. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:109,197` +### M14. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:109,197` - **File:** `model.ts:108-109,196-197`. - **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" sounds like a timestamp). - **Why weird:** The field is `string`, but the JSDoc says "specified in YYYY-MM format". That is a year-month string, not a time. Compare with `creationTime: number` (which is an epoch-ms timestamp). The same word "Time" is used for two different formats. A `string` for "YYYY-MM" should be branded or use a `Temporal.YearMonth` from `@js-temporal/polyfill` (already a dependency at `package.json:23`). - **Suggested name:** `deliveryStartMonth` (clarifies granularity), typed `Temporal.PlainYearMonth | string`. - **Rationale:** "Time" implies high-resolution. The domain is monthly billing buckets, so "Month" is the right granularity. Same convention as `Stripe.Invoice.period_start` (epoch) vs `Stripe.UsageRecord.period.start` (date-only). -### M16. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:105,193` +### M15. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:105,193` - **File:** `model.ts:104-105,192-193`. - **Category:** 7 (overly verbose), 9 (singular/plural mix), 15 (generic suffix). - **Why weird:** The field is `workspaceIdsFilter: number[]`. The plural `Ids` says "this is a list of IDs". The `Filter` suffix says "this is a filter". A `number[]` already conveys "list of ints". Calling it `workspaceIdsFilter` adds redundant `Filter` noise; calling it just `workspaceIds` (the actual content) would be clearer. Compare with `ListLogDeliveryConfiguration.credentialsId: string` (singular, no `Filter` suffix at `model.ts:145`) which serves the same conceptual role. - **Suggested name:** `workspaceIds: number[]` (drop `Filter`). Or `filterByWorkspaceIds` if intent must be made explicit. - **Rationale:** Type-driven inference: a `number[]` named after the entity is unambiguous. `Filter` is generic ceremony. -### M17. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:105,193` +### M16. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:105,193` - **File:** `model.ts:104-105,192-193`. - **Category:** 6 (misleading), 19 (underspecified ID). - **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double precision float — only safe up to 2^53 - 1. Databricks workspace IDs are int64 server-side; sending an ID greater than 2^53 will silently lose precision in the JSON wire. The TS type should be `bigint[]` or `(number | bigint)[]` or branded. - **Suggested name:** `workspaceIds: bigint[]` (matches the int64 wire). Or `workspaceIds: WorkspaceId[]` with a branded `type WorkspaceId = number & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package issue. Same finding will recur on every `*Id: number` field that maps to an int64 wire. Fix at generator level: emit `bigint` for `int64`. -### M18. `host` field on `Client` lacks domain context — `client.ts:47` +### M17. `host` field on `Client` lacks domain context — `client.ts:47` - **File:** `client.ts:47,62`. - **Category:** 1 (vague), 15 (generic field name). - **Why weird:** `private readonly host: string` — without context, `host` could be any URL or hostname. The setter at line 62 trims trailing slash. The semantically correct name is `databricksHost` or `workspaceUrl` or `baseUrl` (the actual content is `https://.../`, not just a hostname like `example.com`). @@ -185,70 +178,70 @@ method. ## Low severity -### L19. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` +### L18. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` - **File:** `model.ts:56-61`. - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered. They should match — either `BILLABLE_USAGE_LOGS` / `AUDIT_LOGS` (both plural) or `BILLABLE_USAGE` / `AUDIT` (both singular). - **Suggested name:** `BILLABLE_USAGE` / `AUDIT` (drop the `_LOGS` — the enum is `LogDeliveryType` so "logs" is implied). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the type name) is cleaner. -### L20. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` +### L19. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` - **File:** `model.ts:23-28`. - **Category:** 3 (acronym casing — fine here since it matches the wire), Observation. - **Why weird:** Two-value enum where `log_type === 'BILLABLE_USAGE'` forces `output_format === 'CSV'` and `log_type === 'AUDIT_LOGS'` forces `'JSON'` (see JSDoc on `outputFormat` at `model.ts:93-96`). The field is therefore *always* derivable from `logType` — making it a redundant field, not a redundant enum, but worth flagging. - **Suggested name:** Drop `outputFormat` from the request DTO (it can be derived server-side). Keep on the response DTO for clarity. - **Rationale:** Not strictly a naming issue, but reduces API surface area. -### L21. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` +### L20. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` - **File:** `model.ts:13-16`. - **Category:** 1 (vague). - **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the doc says exactly what the name says. JSDoc should add information, not echo identifiers. - **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured S3 bucket." - **Rationale:** Cross-cutting generator concern. -### L22. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` +### L21. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` - **File:** `model.ts:48-49`. - **Category:** 6 (misleading). - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc says it actually means "configuration has been disabled since the release of this feature or there are no workspaces in the account". That's not "not found"; it's "no logs to deliver because account state". - **Suggested name:** `NO_DATA` or `NOT_APPLICABLE` or `DISABLED_AT_RELEASE` — anything that doesn't sound like a 404. - **Rationale:** API value names should not collide with HTTP semantics that mean something different. A monitoring dashboard surfacing `status === 'NOT_FOUND'` will mislead an operator into thinking the config was deleted. -### L23. `PACKAGE_SEGMENT` constant — `client.ts:41` +### L22. `PACKAGE_SEGMENT` constant — `client.ts:41` - **File:** `client.ts:41-44`. - **Category:** 1 (vague), 15 (generic). - **Why weird:** `Segment` is a generic CS term. The comment "Package identity segment for this client to be used in the User-Agent header" (`client.ts:40`) is the disambiguator; without it the constant name does not communicate what it is. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency — same finding in every audited package. Worth normalising at generator level. Same as `billableusagedownload` audit #10. -### L24. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` +### L23. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` - **File:** `client.ts:51,72`. - **Category:** 20 (type-suffix tautology). - **Why weird:** Field name and type both end in `Client`. Convention is widespread but flagged per rule 20. - **Suggested name:** `transport: HttpClient` (matches the imported package `@databricks/sdk-databricks/transport`). - **Rationale:** `transport` is what HTTP layers are usually named in language-agnostic SDK terminology (gRPC, GraphQL clients, etc.). It avoids the `Client/Client` echo. Tolerable as-is. -### L25. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` +### L24. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` - **File:** `client.ts:91,99,103,...` (every method). - **Category:** 5 (cryptic abbreviation). - **Why weird:** Three-letter abbreviations for parameter and local names. The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling out costs nothing and improves readability. Same finding across every audit. -### L26. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` +### L25. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` - **File:** `client.ts:196`. - **Category:** 5 (cryptic), 1 (vague — `pageReq` is shorthand for "request for next page"). - **Why weird:** Variable holds the *modified* request for each page (with `pageToken` updated). `pageReq` reads as "page request" — a noun describing the page itself. - **Suggested name:** `currentRequest` or `paginatedRequest`. Or unify with `request` if you adopt option-bag style. - **Rationale:** Low; loop-local variable. -### L27. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` +### L26. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` - **File:** `utils.ts:26-38,65-94`. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Why weird:** Two functions named almost identically doing very different things. `executeCall` wraps the call in retry/rate-limit; `executeHttpCall` does the raw HTTP send + decode + APIError. Within the same file the naming distinction is too subtle. - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `dispatchHttp`). Or just `wrapRetry` / `sendHttp`. - **Rationale:** Same finding as `billableusagedownload` audit #13. Cross-package generator concern. -### L28. `HttpCallOptions` — `utils.ts:15` +### L27. `HttpCallOptions` — `utils.ts:15` - **File:** `utils.ts:15-19`. - **Category:** 1 (vague suffix `Options`), 12 (duplicate `Options` naming). - **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` from `@databricks/sdk-core/api` imported at line 3). The local interface shadows the imported one cognitively. The field is not user-facing — it is an internal bag. @@ -259,21 +252,21 @@ method. ## Observations -### O29. `flattenQueryParams` is exported but unused — `utils.ts:123` +### O28. `flattenQueryParams` is exported but unused — `utils.ts:123` `client.ts` does its own query-param construction inline (lines 155-167) using `new URLSearchParams()` and four `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called by this package. This is a generator artefact — every generated package ships this helper. -### O30. `parseResponse` is unused — `utils.ts:113` +### O29. `parseResponse` is unused — `utils.ts:113` Actually, `parseResponse` *is* used (4 call sites in `client.ts:109,137,180,233`). Not dead. Correction to prior packages' findings: in `logdeliveryconfigurations`, parseResponse is actively in use. -### O31. `marshalRequest` is used twice — `client.ts:95,219` +### O30. `marshalRequest` is used twice — `client.ts:95,219` Used for `createLogDeliveryConfiguration` and `updateLogDeliveryConfiguration`. Not dead. -### O32. `accountId` URL fallback — `client.ts:94,126,154,218` +### O31. `accountId` URL fallback — `client.ts:94,126,154,218` `createLogDeliveryConfiguration` (line 94) reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client fallback!), while the other three methods do `req.accountId ?? this.accountId ?? ''`. The create path silently differs — if `ClientOptions.accountId` is set but the caller forgets to put it inside `logDeliveryConfiguration`, the URL becomes `/api/2.0/accounts//log-delivery`. This is a correctness bug surfaced by a naming/structure inconsistency: the request DTO nests the account ID one level deeper than the others. - **Category:** 6 (misleading), 16 (field placement contradicts wire-level convention). - **Suggested fix:** Make `req.accountId ?? this.accountId ?? ''` consistent across all four methods (the create path should reach the top-level `accountId` and the client-options fallback, not just the nested wrapper field). -### O33. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,32,53,64,77,120,137,165,225` +### O32. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,32,53,64,77,120,137,165,225` Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the first line (e.g., line 6: ``` * * @@ -281,8 +274,8 @@ Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the fir ``` ). Looks like the generator emits an empty paragraph break that renders as `*`. Also, `` appears in raw form throughout (e.g., `model.ts:98,127,142,186`); it should be a literal "Databricks" or substituted at generation time. Neither is a name issue per se but both pollute the docs. -### O34. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` -The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O32). The naming of `accountId` as "optional" in the type lies about the runtime requirement. +### O33. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` +The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O31). The naming of `accountId` as "optional" in the type lies about the runtime requirement. --- diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index cdce3803..b39b158d 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,75 +3,23 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 62 +**Total weird names flagged:** 47 ## Summary | Severity | Count | | --- | --- | -| High | 16 | -| Medium | 32 | +| High | 14 | +| Medium | 29 | | Low | 8 | | Observation | 6 | -The marketplaces package is one of the more naming-distressed surfaces in the SDK. The single dominant problem is the proto-style `MessageType_Response` underscore-suffixed identifier pattern — present on 14 of the 24 request types and infecting `client.ts`, `index.ts`, and every transitive importer with `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. Closely behind it is the **inconsistent request-type convention** within a single file: some request types follow the verb-shaped Go style (`CreateFile`, `DeleteFile`, `GetListing`, `GetListings`, `UpdateListing`, `ListFiles`, `CreateProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders`, `CreateProviderAnalyticsDashboard`, `UpdateProviderAnalyticsDashboard`, `GetLatestVersionProviderAnalyticsDashboard`, `ListProviderAnalyticsDashboard`, `GetPersonalizationRequestsForProvider`, `UpdatePersonalizationRequestStatus`) while others follow the more idiomatic `*Request`/`*Response` suffix (`CreateExchangeRequest`, `DeleteExchangeRequest`, `GetExchangeRequest`, `UpdateExchangeRequest`, `ListExchangesRequest`, `CreateExchangeFilterRequest`, `DeleteExchangeFilterRequest`, `UpdateExchangeFilterRequest`, `ListExchangeFiltersRequest`, `AddExchangeForListingRequest`, `RemoveExchangeForListingRequest`, `ListExchangesForListingRequest`, `ListListingsForExchangeRequest`) — split almost perfectly down the provider/exchange axis but not advertised that way. Other notable issues are the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListings` request and `GetListings_Response` payload field both use `listings`, while `CreateListing` and `DeleteListing` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service", `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` exposing an internal commit-drawdown workflow with a 33-character enum value, and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). +The marketplaces package is one of the more naming-distressed surfaces in the SDK. The dominant problem is the **inconsistent request-type convention** within a single file: some request types follow the verb-shaped Go style (`CreateFile`, `DeleteFile`, `GetListing`, `GetListings`, `UpdateListing`, `ListFiles`, `CreateProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders`, `CreateProviderAnalyticsDashboard`, `UpdateProviderAnalyticsDashboard`, `GetLatestVersionProviderAnalyticsDashboard`, `ListProviderAnalyticsDashboard`, `GetPersonalizationRequestsForProvider`, `UpdatePersonalizationRequestStatus`) while others follow the more idiomatic `*Request`/`*Response` suffix (`CreateExchangeRequest`, `DeleteExchangeRequest`, `GetExchangeRequest`, `UpdateExchangeRequest`, `ListExchangesRequest`, `CreateExchangeFilterRequest`, `DeleteExchangeFilterRequest`, `UpdateExchangeFilterRequest`, `ListExchangeFiltersRequest`, `AddExchangeForListingRequest`, `RemoveExchangeForListingRequest`, `ListExchangesForListingRequest`, `ListListingsForExchangeRequest`) — split almost perfectly down the provider/exchange axis but not advertised that way. Other notable issues are the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListings` request and `GetListings_Response` payload field both use `listings`, while `CreateListing` and `DeleteListing` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service", `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` exposing an internal commit-drawdown workflow with a 33-character enum value, and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). --- ## High severity -### 1. Proto-style `_Response` underscore-suffixed types — 14 occurrences - -**Location:** `src/v1/model.ts:182, 193, 202, 210, 238, 245, 252, 322, 334, 344, 354, 365, 375, 418, 438, 451, 633, 646, 656, 671` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface CreateFile_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface CreateListing_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface CreateProvider_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface CreateProviderAnalyticsDashboard_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteFile_Response {} -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteListing_Response {} -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteProvider_Response {} -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface GetFile_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface GetLatestVersionProviderAnalyticsDashboard_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface GetListing_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface GetListings_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface GetPersonalizationRequestsForProvider_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface GetProvider_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface ListFiles_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface ListProviderAnalyticsDashboard_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface ListProviders_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface UpdateListing_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface UpdatePersonalizationRequestStatus_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface UpdateProvider_Response { ... } -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface UpdateProviderAnalyticsDashboard_Response { ... } -``` - -20 types in this file carry an embedded underscore — illegal-feeling in idiomatic TypeScript (Google TS style guide § 5.2 specifies `PascalCase` without underscores). The fact that 14 distinct types and 14 corresponding `*_ResponseSchema` exports require disabling `@typescript-eslint/naming-convention` means the proto wart is fully visible in the public API. Every consumer who imports one of these types must accept the underscore in their own code (see `client.ts:29, 31, 33, 38, 41, 43, 45, 53, 55, 57, 59, 61, 63, 71, 75, 77, 88, 90, 93` and `index.ts:32, 34, 36, 38, 45, 47, 49, 53, 58, 60, 62, 64, 67, 76, 80, 82, 100, 102, 106`). -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). -- **Suggested name:** `CreateFileResponse`, `CreateListingResponse`, etc. — drop the underscore wherever the API is allowed to diverge from the wire. -- **Rationale:** The other half of this file uses the `*Request`/`*Response` convention (`CreateExchangeRequest`, `CreateExchangeResponse`), so the underscore form is internally inconsistent within a single 1770-line file. - -### 2. Verb-shaped request types — 14 occurrences +### 1. Verb-shaped request types — 14 occurrences **Location:** `src/v1/model.ts:174, 188, 197, 207, 233, 240, 247, 317, 331, 339, 348, 359, 370, 411, 434, 445, 627, 637, 650, 660` @@ -99,11 +47,11 @@ export interface UpdateProviderAnalyticsDashboard { ... } ``` Top-level request types named with imperative verbs (`Create*`, `Delete*`, `Get*`, `List*`, `Update*`). TS types should be nouns; verbs are reserved for methods. The `Client` exposes the same identifier as both a method and a type: `client.createListing(req: CreateListing)`, `client.getListing(req: GetListing)`, `client.listProviders(req: ListProviders)` — verb-noun-verb-noun every time. Readers cannot tell from the type whether the symbol names a request shape or an operation. -- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs within file — see #3). +- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs within file — see #2). - **Suggested name:** `CreateFileRequest`, `CreateListingRequest`, `GetListingRequest`, `ListProvidersRequest`, etc. -- **Rationale:** See #3. +- **Rationale:** See #2. -### 3. Two competing request-type naming conventions in one file +### 2. Two competing request-type naming conventions in one file **Location:** Both patterns coexist throughout `src/v1/model.ts`. @@ -128,10 +76,10 @@ UpdateProvider RemoveExchangeForListingRequest Verb-shaped types are used for **provider-side** operations (listings, files, providers, personalization, analytics dashboard); `*Request`-suffixed types are used for **exchange-side** operations (exchanges, exchange filters, exchange-listing joins). The split likely reflects two different proto packages on the server but in TS it reads as arbitrary inconsistency. A single user calling both `client.createListing` and `client.createExchange` will import two completely differently-named request types: `CreateListing` and `CreateExchangeRequest`. There is no documentation or hint that this split is intentional. - **Category:** 17 (inconsistent action verbs / naming patterns), 12 (duplicate convention — two patterns for the same concept). -- **Suggested name:** Pick one — and `*Request` is the rest-of-SDK norm. Cascade with #2. +- **Suggested name:** Pick one — and `*Request` is the rest-of-SDK norm. Cascade with #1. - **Rationale:** A single ergonomic package should not require users to memorize which sub-domain uses which type-naming scheme. -### 4. `Listing` — ambiguous central type +### 3. `Listing` — ambiguous central type **Location:** `src/v1/model.ts:456` @@ -144,16 +92,16 @@ export interface Listing { ``` `Listing` is the central noun of the package, but the name has two unrelated English meanings: a *marketplace listing* (a storefront entry) and a *list operation* (the verb "to list", noun "a listing of items"). The package frequently uses both meanings within a single line: -- `getListings(req: GetListings): Promise` — method name uses the verb sense ("get the listings"), the type name uses the noun sense (a "GetListings" request that returns marketplace listings). +- `getListings(req: GetListings)` — method name uses the verb sense ("get the listings"), the type name uses the noun sense (a "GetListings" request that returns marketplace listings). - `ListListingsForExchangeRequest` reads as "list the listings for exchange" — the first `List` is the verb, the second `Listings` is the noun. - `ExchangeListing` (line 278) is a join-row type — neither a storefront listing nor a list-operation but a third concept ("a listing in an exchange"). The triple overload is unavoidable given the domain word but the SDK does not disambiguate (e.g. by renaming join rows to `ExchangeListingLink` or `ExchangeMembership`). - **Category:** 1 (vague), 12 (duplicate concepts), 15 (overloaded vocabulary). -- **Suggested name:** Keep `Listing` for the noun; rename `ExchangeListing` → `ExchangeListingLink` / `ListingExchangeMembership`; rename `GetListings` → `ListListingsRequest` (cascade with #2 and #3 — but note that gives `ListListingsRequest`, which is itself a stutter; the right fix may be `ListMarketplaceListingsRequest` or simpler `ListListings`). +- **Suggested name:** Keep `Listing` for the noun; rename `ExchangeListing` → `ExchangeListingLink` / `ListingExchangeMembership`; rename `GetListings` → `ListListingsRequest` (cascade with #1 and #2 — but note that gives `ListListingsRequest`, which is itself a stutter; the right fix may be `ListMarketplaceListingsRequest` or simpler `ListListings`). - **Rationale:** "Listing" has multiple senses; the SDK uses all three; the API can mitigate this by giving the *join row* a less ambiguous name. -### 5. `ExchangeListing` — overloaded "listing" inside the type name +### 4. `ExchangeListing` — overloaded "listing" inside the type name **Location:** `src/v1/model.ts:278` @@ -172,9 +120,9 @@ export interface ExchangeListing { The type is a join row connecting an exchange to a listing (with denormalized names). Named `ExchangeListing` it parses as either "a listing of type Exchange" (no — exchanges and listings are distinct) or "the exchange-side view of a listing" (no — both sides are denormalized into the same row) or "a listing exposed in the exchange" (closer, but the type is really the *link*, not the listing itself). The `Exchange.linkedListings: ExchangeListing[]` field at line 263 makes the relationship visible but does not clarify the name. - **Category:** 1 (vague), 6 (misleading: looks like an inheritance from `Listing`), 12 (overloaded with `Listing`). - **Suggested name:** `ExchangeListingLink`, `ExchangeMembership`, `ListingExchangeAssociation`. -- **Rationale:** See #4. +- **Rationale:** See #3. -### 6. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order +### 5. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order **Location:** `src/v1/model.ts:141, 592` @@ -194,7 +142,7 @@ The operations are symmetric (associate / disassociate an exchange with a listin - **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`); rename response field `exchangeForListing` → `exchangeListing`. - **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. -### 7. `AddExchangeForListingResponse.exchangeForListing` — Greek-letter field name +### 6. `AddExchangeForListingResponse.exchangeForListing` — Greek-letter field name **Location:** `src/v1/model.ts:146-148` @@ -207,9 +155,9 @@ export interface AddExchangeForListingResponse { The field name `exchangeForListing` is a noun phrase that mirrors the request verb ("Add Exchange For Listing"). But the value is an `ExchangeListing` (the join-row type). Just naming the field `exchangeListing` would match the type name and remove the "for" preposition that doesn't add information. - **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name doesn't quite match its type name). - **Suggested name:** `exchangeListing` (matches the underlying type). -- **Rationale:** See #6. +- **Rationale:** See #5. -### 8. `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` — 33-character internal-domain enum value +### 7. `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` — 33-character internal-domain enum value **Location:** `src/v1/model.ts:119-126` @@ -234,7 +182,7 @@ This enum value exposes a billing/commerce concept ("commit drawdown") that is n - **Suggested name:** Document or hide. If kept, the long name is itself fine — the issue is the value's presence in the public API without context. - **Rationale:** Public enums should be self-explanatory; internal-workflow values should either be documented inline with the workflow's purpose or kept off the public surface. -### 9. `PersonalizationRequest.isFromLighthouse` — internal codename leak +### 8. `PersonalizationRequest.isFromLighthouse` — internal codename leak **Location:** `src/v1/model.ts:563` @@ -251,7 +199,7 @@ export interface PersonalizationRequest { - **Suggested name:** Either document inline (the doc-comment should explain Lighthouse) or rename to a feature-describing name. If Lighthouse is a request-origin tag, `originatingService` (with an enum) would be clearer. - **Rationale:** Public APIs should not leak internal-system codenames. -### 10. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types +### 9. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types **Location:** `src/v1/model.ts:515, 462` @@ -271,7 +219,7 @@ The split into `Summary` and `Detail` looks like a "list view vs. detail view" d - **Suggested name:** `ListingMetadata` (for what is currently `ListingSummary`) and `ListingContent` (for `ListingDetail`); or merge into a single `Listing` type. - **Rationale:** The "Summary / Detail" lexicon promises a slim/fat split that the API doesn't actually provide. -### 11. `ListingSummary` — 20-field "summary" +### 10. `ListingSummary` — 20-field "summary" **Location:** `src/v1/model.ts:515-536` @@ -302,9 +250,9 @@ export interface ListingSummary { A 20-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. - **Category:** 6 (misleading). - **Suggested name:** `ListingMetadata` or `ListingHeader`. -- **Rationale:** See #10. +- **Rationale:** See #9. -### 12. `ProviderInfo.termOfServiceLink` — singular "term" +### 11. `ProviderInfo.termOfServiceLink` — singular "term" **Location:** `src/v1/model.ts:581` @@ -323,7 +271,7 @@ Note: `ListingDetail.termsOfService` (line 464) correctly uses the plural form - **Suggested name:** `termsOfServiceLink`. - **Rationale:** Within-package consistency and English correctness. -### 13. `FileParent` — abstract container with weak typing +### 12. `FileParent` — abstract container with weak typing **Location:** `src/v1/model.ts:303-307` @@ -340,7 +288,7 @@ The type ships with a `TODO` in the JSDoc — the API contract is incomplete by - **Suggested name:** Either model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`) or rename `parentId` → `providerId | listingId | listingResourceId` per case. - **Rationale:** The `TODO` says the team knows; the type is shipped publicly anyway. -### 14. `FileParent.fileParentType` — type-suffix tautology +### 13. `FileParent.fileParentType` — type-suffix tautology **Location:** `src/v1/model.ts:306` @@ -356,7 +304,7 @@ Field name = type name minus the `FileParent` prefix repeated. Inside `FileParen - **Suggested name:** `type` (matching `ShareInfo.type`) or `parentType`. - **Rationale:** Redundant context. -### 15. `FileInfo.marketplaceFileType` — package-name prefix in a field +### 14. `FileInfo.marketplaceFileType` — package-name prefix in a field **Location:** `src/v1/model.ts:290` @@ -373,20 +321,11 @@ The field qualifies "fileType" with "marketplace" — but the type is *already* - **Suggested name:** Rename enum → `FileType`; rename field → `type`. - **Rationale:** Package-name qualifiers are noise on internal fields. -### 16. `marketplaceFileType: MarketplaceFileType` vs `fileParentType: FileParentType` — different qualifier conventions - -**Location:** `src/v1/model.ts:290, 306` - -The package qualifies one enum with "marketplace" (`MarketplaceFileType`) and another without (`FileParentType`). Both are file-scoped enums. The asymmetry suggests `MarketplaceFileType` was renamed at some point to avoid a collision (perhaps with `files` package's `FileType`?) but `FileParentType` was not. -- **Category:** 17 (inconsistent naming pattern). -- **Suggested name:** Rename one to match the other. -- **Rationale:** See #15. - --- ## Medium severity -### 17. `Client` — generic top-level class name +### 15. `Client` — generic top-level class name **Location:** `src/v1/client.ts:152` @@ -399,7 +338,7 @@ Top-level export named just `Client`. Every generated package exports a `Client` - **Suggested name:** `MarketplacesClient`. - **Rationale:** Service-prefixed client class names are standard across `@aws-sdk/*`, `@google-cloud/*`, `@azure/*`. -### 18. `Exchange.linkedListings` — verb tense and ambiguity +### 16. `Exchange.linkedListings` — verb tense and ambiguity **Location:** `src/v1/model.ts:263` @@ -415,7 +354,7 @@ export interface Exchange { - **Suggested name:** `listings`, `memberships`, or `listingLinks`. - **Rationale:** Past-participle field names suggest a log/audit; this is a list of current memberships. -### 19. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix +### 17. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix **Location:** `src/v1/model.ts:269, 275` @@ -435,7 +374,7 @@ Inside an `ExchangeFilter`, what else could `filterValue` be the value of? Or `f - **Suggested name:** `value`, `type`. - **Rationale:** Field names that re-state the parent type are noise (see also `EffectivePrivilege.privilege` from grants audit #15). -### 20. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum +### 18. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum **Location:** `src/v1/model.ts:69-71` @@ -450,7 +389,7 @@ An enum with a single member. Typically a sign that the API anticipates future f - **Suggested name:** Could be a string literal type until a second value lands. - **Rationale:** TS allows narrowing without enums (`type ExchangeFilterType = 'GLOBAL_METASTORE_ID'`). -### 21. `MarketplaceFileType.APP` — three-letter generic value +### 19. `MarketplaceFileType.APP` — three-letter generic value **Location:** `src/v1/model.ts:117` @@ -469,94 +408,7 @@ export enum MarketplaceFileType { - **Suggested name:** `EMBEDDED_APP` or `APP_PACKAGE`. - **Rationale:** Match the qualifier convention of `EMBEDDED_*` peers. -### 22. `AssetType.ASSET_TYPE_*` — redundant enum prefixes - -**Location:** `src/v1/model.ts:5-19` - -```ts -export enum AssetType { - ASSET_TYPE_UNSPECIFIED = 'ASSET_TYPE_UNSPECIFIED', - ASSET_TYPE_GIT_REPO = 'ASSET_TYPE_GIT_REPO', - ASSET_TYPE_DATA_TABLE = 'ASSET_TYPE_DATA_TABLE', - ASSET_TYPE_MODEL = 'ASSET_TYPE_MODEL', - ASSET_TYPE_NOTEBOOK = 'ASSET_TYPE_NOTEBOOK', - ASSET_TYPE_MEDIA = 'ASSET_TYPE_MEDIA', - ASSET_TYPE_PARTNER_INTEGRATION = 'ASSET_TYPE_PARTNER_INTEGRATION', - ASSET_TYPE_APP = 'ASSET_TYPE_APP', - ASSET_TYPE_MCP = 'ASSET_TYPE_MCP', -} -``` - -Every value is prefixed with `ASSET_TYPE_` — proto convention for namespace disambiguation. In TS, the enum's name already provides the namespace: `AssetType.GIT_REPO` is unambiguous; `AssetType.ASSET_TYPE_GIT_REPO` is redundant. -- **Category:** 2 (redundant enum prefixes). -- **Suggested name:** `AssetType.GIT_REPO`, `AssetType.DATA_TABLE`, etc. -- **Rationale:** TS enum members are accessed via the enum type, so the prefix is always redundant. - -### 23. `AssetType.ASSET_TYPE_UNSPECIFIED` — proto sentinel leak - -**Location:** `src/v1/model.ts:6` - -```ts -ASSET_TYPE_UNSPECIFIED = 'ASSET_TYPE_UNSPECIFIED', -``` - -Proto enums require a zero-value `UNSPECIFIED` member. This is an implementation detail of protobuf, not a meaningful TS API value — `undefined` already serves the same role in optional TS fields. The other "unspecified" pattern in this file: `ListingTagType.LISTING_TAG_TYPE_UNSPECIFIED` (line 104). -- **Category:** 18 (long enum values), 11 (proto sentinel exposed). -- **Suggested name:** Drop. Use `undefined` for the unset case. -- **Rationale:** Cross-language TS APIs typically don't surface the `UNSPECIFIED` zero-value. - -### 24. `ListingTagType.LISTING_TAG_TYPE_*` — redundant enum prefixes - -**Location:** `src/v1/model.ts:103-107` - -```ts -export enum ListingTagType { - LISTING_TAG_TYPE_UNSPECIFIED = 'LISTING_TAG_TYPE_UNSPECIFIED', - LISTING_TAG_TYPE_LANGUAGE = 'LISTING_TAG_TYPE_LANGUAGE', - LISTING_TAG_TYPE_TASK = 'LISTING_TAG_TYPE_TASK', -} -``` - -Same problem as #22. -- **Category:** 2, 18. -- **Suggested name:** `LANGUAGE`, `TASK`. -- **Rationale:** See #22. - -### 25. `DeltaSharingRecipientType.DELTA_SHARING_RECIPIENT_TYPE_*` — redundant enum prefixes - -**Location:** `src/v1/model.ts:64-67` - -```ts -export enum DeltaSharingRecipientType { - DELTA_SHARING_RECIPIENT_TYPE_DATABRICKS = 'DELTA_SHARING_RECIPIENT_TYPE_DATABRICKS', - DELTA_SHARING_RECIPIENT_TYPE_OPEN = 'DELTA_SHARING_RECIPIENT_TYPE_OPEN', -} -``` - -Same problem as #22 and #24, plus the prefix here is 28 characters. -- **Category:** 2, 18. -- **Suggested name:** `DATABRICKS`, `OPEN`. -- **Rationale:** See #22. - -### 26. `FileStatus.FILE_STATUS_*` — redundant enum prefixes - -**Location:** `src/v1/model.ts:79-88` - -```ts -export enum FileStatus { - FILE_STATUS_PUBLISHED = 'FILE_STATUS_PUBLISHED', - FILE_STATUS_STAGING = 'FILE_STATUS_STAGING', - FILE_STATUS_SANITIZING = 'FILE_STATUS_SANITIZING', - FILE_STATUS_SANITIZATION_FAILED = 'FILE_STATUS_SANITIZATION_FAILED', -} -``` - -Same problem as #22. -- **Category:** 2. -- **Suggested name:** `PUBLISHED`, `STAGING`, `SANITIZING`, `SANITIZATION_FAILED`. -- **Rationale:** See #22. - -### 27. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment +### 20. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment **Location:** `src/v1/model.ts:128-134` @@ -575,7 +427,7 @@ The JSDoc explicitly says the value is named `REQUEST_PENDING` because `PENDING` - **Suggested name:** `PENDING` (cross-enum collisions don't exist in TS). - **Rationale:** Proto-side collision avoidance has no purpose in the TS surface. -### 28. `Cost` — single-word, ambiguous enum +### 21. `Cost` — single-word, ambiguous enum **Location:** `src/v1/model.ts:47-50` @@ -591,7 +443,7 @@ export enum Cost { - **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. - **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. -### 29. `DataRefresh` — enum named after the noun, not the property +### 22. `DataRefresh` — enum named after the noun, not the property **Location:** `src/v1/model.ts:52-62` @@ -614,7 +466,7 @@ The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRe - **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. - **Rationale:** Self-documenting enum name; consistent value form. -### 30. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special +### 23. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special **Location:** `src/v1/model.ts:53-55` @@ -628,9 +480,9 @@ HOURLY = 'HOURLY', `NONE` reads as "no refresh"; `SECOND` reads as "every second"; `HOURLY` reads as "every hour". The first two follow noun-naming; the third follows adverb-naming. Mixing the two within the same enum produces inconsistency. - **Category:** 17 (inconsistent value form). - **Suggested name:** Pick one convention. If "every X" adverbs are used, change `SECOND` → `SECONDLY`, `MINUTE` → `MINUTELY`, `NONE` → unchanged. -- **Rationale:** See #29. +- **Rationale:** See #22. -### 31. `Category` — generic enum name with 23 values +### 24. `Category` — generic enum name with 23 values **Location:** `src/v1/model.ts:21-45` @@ -647,7 +499,7 @@ export enum Category { - **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 528). - **Rationale:** Cross-package collision avoidance and self-documentation. -### 32. `ListingDetail.size` — ambiguous unit +### 25. `ListingDetail.size` — ambiguous unit **Location:** `src/v1/model.ts:489-490` @@ -661,7 +513,7 @@ The JSDoc says "in GB", but the field name is just `size`. The wire field is `si - **Suggested name:** `sizeInGigabytes` or `sizeGb`. - **Rationale:** Numeric fields without unit suffix are a bug magnet. -### 33. `ListingDetail.cost` typed as `Cost` (enum), but doc says price +### 26. `ListingDetail.cost` typed as `Cost` (enum), but doc says price **Location:** `src/v1/model.ts:472-473, 477-478` @@ -680,7 +532,7 @@ Two related fields: `cost: Cost (= 'FREE' | 'PAID')` and `pricingModel: string` - **Suggested name:** Combine into one discriminated union: `pricing?: { $case: 'free' } | { $case: 'paid', model: string }`. - **Rationale:** Type-system can encode the relationship the prose tries to. -### 34. `ListingDetail.geographicalCoverage` — long camelCase +### 27. `ListingDetail.geographicalCoverage` — long camelCase **Location:** `src/v1/model.ts:470-471` @@ -694,7 +546,7 @@ geographicalCoverage?: string | undefined; - **Suggested name:** `geoRegion`, `regions`, or `coverage`. - **Rationale:** Shorter, matches sibling naming. -### 35. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number +### 28. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number **Location:** `src/v1/model.ts:483-486` @@ -710,7 +562,7 @@ Field names include "Date" but the type is `number` (Unix timestamp). A consumer - **Suggested name:** `collectionStartAt` / `collectionEndAt`, or `collectionPeriodStart` / `collectionPeriodEnd`. - **Rationale:** "Date" is ambiguous about underlying type; `At` is the existing in-file convention for Unix timestamps. -### 36. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming +### 29. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming **Location:** `src/v1/model.ts:479-482` @@ -726,7 +578,7 @@ Both are `DataRefreshInfo` (an interval), but one is named "frequency" and the o - **Suggested name:** Rename type → `TimeInterval`; keep the field-level distinction. - **Rationale:** Reuse a generic type name for a reusable type. -### 37. `ListingDetail.dataSource` — single-word vague field +### 30. `ListingDetail.dataSource` — single-word vague field **Location:** `src/v1/model.ts:487-488` @@ -740,7 +592,7 @@ dataSource?: string | undefined; - **Suggested name:** `dataSourceDescription`, `dataProvenance`, or `dataOriginNote`. - **Rationale:** Disambiguate from the more common DB-connection meaning of "data source". -### 38. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags +### 31. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags **Location:** `src/v1/model.ts:493-508` @@ -763,18 +615,17 @@ export interface ListingTag { } export enum ListingTagType { - LISTING_TAG_TYPE_UNSPECIFIED = 'LISTING_TAG_TYPE_UNSPECIFIED', LISTING_TAG_TYPE_LANGUAGE = 'LISTING_TAG_TYPE_LANGUAGE', LISTING_TAG_TYPE_TASK = 'LISTING_TAG_TYPE_TASK', } ``` -The enum constrains tag *names* to 3 values (one of which is the `UNSPECIFIED` sentinel). Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. +The enum constrains tag *names* to 2 values. Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. - **Category:** 6 (misleading: name implies free-form labels, structure is constrained), 7 (`tagName` / `tagValues` add `tag` prefix repeated from type name). - **Suggested name:** `ListingTag.name` / `ListingTag.values`; rename type to clarify (e.g. `ListingAttribute`). - **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. -### 39. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology +### 32. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology **Location:** `src/v1/model.ts:538-543` @@ -788,9 +639,9 @@ export interface ListingTag { Inside `ListingTag`, what else could `tagName` and `tagValues` be? `name` and `values` carry the same information. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `name`, `values`. -- **Rationale:** See #19. +- **Rationale:** See #17. -### 40. `ContactInfo` — generic suffix on a single-purpose type +### 33. `ContactInfo` — generic suffix on a single-purpose type **Location:** `src/v1/model.ts:151-156` @@ -809,7 +660,7 @@ export interface ContactInfo { - **Suggested name:** `Contact` or `ConsumerContact`. - **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. -### 41. `RegionInfo` — `Info` suffix on a single-purpose type +### 34. `RegionInfo` — `Info` suffix on a single-purpose type **Location:** `src/v1/model.ts:587-590` @@ -820,12 +671,12 @@ export interface RegionInfo { } ``` -Same problem as #40. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. +Same problem as #33. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. - **Category:** 8 (redundant `Info` suffix), 19 (underspecified — no enum constraints). - **Suggested name:** `Region` (the cloud is implicitly part of the region in many SDKs) or `CloudRegion`. - **Rationale:** Avoid `*Info` suffix; consider richer typing. -### 42. `ShareInfo` — `Info` suffix on a sharing concept +### 35. `ShareInfo` — `Info` suffix on a sharing concept **Location:** `src/v1/model.ts:604-607` @@ -836,12 +687,12 @@ export interface ShareInfo { } ``` -Same problem as #40 and #41. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". +Same problem as #33 and #34. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". - **Category:** 8 (redundant `Info` suffix). - **Suggested name:** `Share`, `ListingShare`. -- **Rationale:** See #40. +- **Rationale:** See #33. -### 43. `ProviderInfo` — `Info` suffix on the canonical provider type +### 36. `ProviderInfo` — `Info` suffix on the canonical provider type **Location:** `src/v1/model.ts:568-585` @@ -855,12 +706,12 @@ export interface ProviderInfo { } ``` -Same problem as #40. The package also has `CreateProvider`, `GetProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. +Same problem as #33. The package also has `CreateProvider`, `GetProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent: the rest of the package uses `Provider` alone). - **Suggested name:** `Provider`. - **Rationale:** Consistency with method/request type names. -### 44. `DataRefreshInfo` — `Info` suffix on an interval type +### 37. `DataRefreshInfo` — `Info` suffix on an interval type **Location:** `src/v1/model.ts:214-217` @@ -871,12 +722,12 @@ export interface DataRefreshInfo { } ``` -Same problem as #40. Also note: the type is reused for `collectionGranularity` (#36), so the name `DataRefreshInfo` is wrong for half of its uses. +Same problem as #33. Also note: the type is reused for `collectionGranularity` (#29), so the name `DataRefreshInfo` is wrong for half of its uses. - **Category:** 8 (redundant `Info` suffix), 6 (misleading: name doesn't fit `collectionGranularity` use). -- **Suggested name:** `TimeInterval` (matches #36). -- **Rationale:** See #36. +- **Suggested name:** `TimeInterval` (matches #29). +- **Rationale:** See #29. -### 45. `FileInfo` — `Info` suffix on the canonical file type +### 38. `FileInfo` — `Info` suffix on the canonical file type **Location:** `src/v1/model.ts:288-301` @@ -888,12 +739,12 @@ export interface FileInfo { } ``` -Same problem as #40. The package also has `CreateFile`, `GetFile`, `DeleteFile`, `ListFiles` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. +Same problem as #33. The package also has `CreateFile`, `GetFile`, `DeleteFile`, `ListFiles` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent with siblings). - **Suggested name:** `File`. -- **Rationale:** See #43. +- **Rationale:** See #36. -### 46. `Listing.summary` / `Listing.detail` — opaque fields on the central type +### 39. `Listing.summary` / `Listing.detail` — opaque fields on the central type **Location:** `src/v1/model.ts:456-460` @@ -908,9 +759,9 @@ export interface Listing { `Listing` is essentially `(id, summary, detail)` — a 3-field passthrough. The two interesting fields are named `summary` and `detail`, opaque on their own. A consumer with `listing.summary.name` and `listing.detail.description` has to navigate two sub-objects to reach the actual content. - **Category:** 1 (vague), 11 (could be merged). - **Suggested name:** Flatten or rename `summary` → `metadata`, `detail` → `content`. -- **Rationale:** See #10. +- **Rationale:** See #9. -### 47. `ListingSummary.setting` — singular field name +### 40. `ListingSummary.setting` — singular field name **Location:** `src/v1/model.ts:521` @@ -926,7 +777,7 @@ export interface ListingSummary { - **Suggested name:** `settings: ListingSettings`. - **Rationale:** Plural matches the conventional naming for a settings bag. -### 48. `ListingSummary.providerRegion` — region of what? +### 41. `ListingSummary.providerRegion` — region of what? **Location:** `src/v1/model.ts:520` @@ -943,7 +794,7 @@ providerRegion?: RegionInfo | undefined; ## Low severity -### 49. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization +### 42. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization **Location:** `src/v1/model.ts:457, 467, 533` @@ -952,14 +803,14 @@ Mixed singular/plural id fields: - `ListingDetail.fileIds: string[]` — many file ids. - `ListingSummary.exchangeIds: string[]` — many exchange ids. - `ListingSummary.providerId: string` — single provider id. -- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #50). +- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #43). Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #50). +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #43). - **Suggested name:** Pick one — `*Id`/`*Ids` is standard. - **Rationale:** Observation; flagged for completeness. -### 50. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number +### 43. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number **Location:** `src/v1/model.ts:530-531` @@ -973,7 +824,7 @@ User ids are typed as `number`. JS `number` only safely represents integers up t - **Suggested name:** `createdById: string` or `bigint`. - **Rationale:** Lossy representation; consistency with other id fields (all `string`). -### 51. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` +### 44. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` **Location:** `src/v1/model.ts:136-139` @@ -989,7 +840,7 @@ Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal ty - **Suggested name:** Could be `'public' | 'private'` literal union. - **Rationale:** Observation. -### 52. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun +### 45. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun **Location:** `src/v1/model.ts:90-93` @@ -1005,7 +856,7 @@ export enum ListingShareType { - **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). - **Rationale:** Internal consistency. -### 53. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values +### 46. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values **Location:** `src/v1/model.ts:109-112` @@ -1021,7 +872,7 @@ Two adjective values. Fine. Flagged because the package also has `Personalizatio - **Suggested name:** No rename. - **Rationale:** Internal consistency check. -### 54. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located +### 47. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located **Location:** `src/v1/model.ts:572, 580` @@ -1036,7 +887,7 @@ Same icon represented two ways — `iconFilePath` (a URL or storage path) and `i - **Suggested name:** No rename; flag for doc clarification. - **Rationale:** Observation. -### 55. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode +### 48. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode **Location:** `src/v1/model.ts:583-584` @@ -1050,7 +901,7 @@ The `darkMode` prefix encodes a UI rendering mode in a server-side data type. Th - **Suggested name:** `iconDarkFileId` / `iconDarkFilePath` or just `darkIcon*`. - **Rationale:** Observation. -### 56. Method docstring inconsistency — `client.ts` +### 49. Method docstring inconsistency — `client.ts` **Location:** `src/v1/client.ts:178, 207, 232, 261, 287, 313, 339, 371, 396, 424, 449, 474, 499, 524, 549, 577, 602, 656, 713, 738, 795, 846, 903, 961, 1018, 1046, 1097, 1125, 1151, 1180, 1206, 1238, 1264` @@ -1077,25 +928,26 @@ Inconsistent docstring style: ## Observations -### 57. v1-only audit +### 50. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 58. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:147` +### 51. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:147` Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. - **Category:** 1 (vague), 15 (generic name). -### 59. `flattenQueryParams` — `src/v1/utils.ts:123` +### 52. `flattenQueryParams` — `src/v1/utils.ts:123` The helper is used by `client.ts:911-915` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. - **Category:** Observation. -### 60. `readAll` — `src/v1/utils.ts:40` +### 53. `readAll` — `src/v1/utils.ts:40` Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. - **Category:** 1 (vague), 14 (Go-style name). -### 61. `HttpCallOptions` — `src/v1/utils.ts:15` +### 54. `HttpCallOptions` — `src/v1/utils.ts:15` Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. - **Category:** 1 (vague suffix), 17 (inconsistent). -### 62. Exported but not in `index.ts` -`index.ts` exports types but not the `*_Response` schemas, marshal/unmarshal functions, or the `*_Response` types fully (note: `CreateFile_Response` is exported via `index.ts:32` — so the underscore wart reaches the public surface). The fact that consumers do see the underscore form via the index export means every change to remove the underscore would be a breaking change. +### 55. AssetType/ListingTagType/DeltaSharingRecipientType/FileStatus enum prefixes — generator-only + +These enum types use the proto convention of prefixing every value with the type name (e.g. `AssetType.ASSET_TYPE_GIT_REPO`, `FileStatus.FILE_STATUS_PUBLISHED`). Per the generator-only recommendations in `_SUMMARY.md`, redundant enum prefixes are tracked at the template level rather than per-package. - **Category:** Observation. diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md index 2949398f..a6613aaf 100644 --- a/.agent/naming-audit/materializedfeatures.md +++ b/.agent/naming-audit/materializedfeatures.md @@ -123,58 +123,7 @@ This is a wire-and-generator-level concern. **Flag SDK-wide / upstream Go.** --- -### 2. `FeatureLineage_FeatureSpec`, `FeatureLineage_Model`, `FeatureLineage_OnlineFeature` proto-style underscored type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) - -**Symbols:** `FeatureLineage_FeatureSpec` (model.ts:34), -`FeatureLineage_Model` (model.ts:40), `FeatureLineage_OnlineFeature` -(model.ts:48). - -**Issue:** TS identifiers must not contain underscores -(`.agent/rules/typescript.mdc`; Google TS Style Guide § 5.3, which mandates -`UpperCamelCase` for types). The `Parent_Child` form is a proto-buf code -generator artefact for nested messages. The file even suppresses the lint -rule explicitly for each one: - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface FeatureLineage_FeatureSpec { -``` - -That comment is the audit signal: the project's lint rule disagrees with the -chosen name. The proto namespace is not preserved in TS modules — every nested -type lives in the same module as `FeatureLineage`, so the qualification is -syntactic noise. - -**Suggested:** flat names that drop the underscore and prefix only where -disambiguation is needed: - -- `FeatureLineage_Model` → `FeatureLineageModel` (or `LineageModel`). -- `FeatureLineage_FeatureSpec` → `FeatureLineageFeatureSpec`. Note this becomes - doubled-noun (see finding 3) and should likely shorten to `LineageFeatureSpec` - or simply `FeatureSpec` (also flagged in finding 4 for cross-pkg collision). -- `FeatureLineage_OnlineFeature` → `FeatureLineageOnlineFeature` (or - `LineageOnlineFeature`, or `OnlineFeatureRef`). - -This is a generator-level fix coordinated SDK-wide. - ---- - -### 3. `FeatureLineage_FeatureSpec` doubled noun once flattened — category 8 (Redundant suffixes) - -**Symbol:** `FeatureLineage_FeatureSpec` (model.ts:34). - -**Issue:** After applying finding 2 to strip the underscore, the result is -`FeatureLineageFeatureSpec` — "Feature" appears twice. Within the -`FeatureLineage` parent type, the prefix `FeatureLineage` is already implied. - -**Suggested:** `LineageFeatureSpec` or shorter `FeatureSpec` (the latter has -the cross-package risk noted in finding 4). The parent prefix in TS nested -types serves to namespace; here it duplicates a concept that is already -unambiguous. - ---- - -### 4. `FeatureLineage_FeatureSpec` and `featurestore.PublishSpec` overlap "Spec" semantics — category 12 (Duplicate concepts) +### 2. `FeatureLineage_FeatureSpec` is a reference, not a spec — category 12 (Duplicate concepts) **Symbol:** `FeatureLineage_FeatureSpec` (model.ts:34); compare `featurestore.PublishSpec` and `onlinetables.OnlineTableSpec`. @@ -193,14 +142,14 @@ different roles: A TS reader importing both packages cannot tell from the type name which is which. -**Suggested:** rename `FeatureLineage_FeatureSpec` → `FeatureSpecRef` or -`FeatureSpecReference` to signal it is a reference. The `FeatureSpec` concept -itself (an actual feature-spec configuration) lives elsewhere in Databricks -APIs; this is just a pointer to one. **Flag for SDK-wide cleanup.** +**Suggested:** clarify that the nested type is a reference (e.g. via JSDoc). +The `FeatureSpec` concept itself (an actual feature-spec configuration) lives +elsewhere in Databricks APIs; this is just a pointer to one. **Flag for +SDK-wide cleanup.** --- -### 5. `FeatureLineage_Model` semantic conflict with `modelregistry`, `modelservingmanagement` — category 6 (Misleading names) and category 12 (Duplicate concepts) +### 3. `FeatureLineage_Model` semantic conflict with `modelregistry`, `modelservingmanagement` — category 6 (Misleading names) and category 12 (Duplicate concepts) **Symbol:** `FeatureLineage_Model` (model.ts:40); doc: "List of Unity Catalog models that were trained on this feature." @@ -222,13 +171,14 @@ The type has two fields: Naming-wise this is a *model reference*, not a model. -**Suggested:** `LineageModelRef`, `ModelReference`, or `RegisteredModelRef`. -This avoids importing `FeatureLineage_Model` next to `modelregistry.Model` and -having two `Model`-shaped types in the same file. +**Suggested:** strengthen JSDoc to indicate this is a reference (the type +name itself follows the proto-nesting convention and is intentional). This +avoids importing `FeatureLineage_Model` next to `modelregistry.Model` and +confusing the two shapes. --- -### 6. `FeatureLineage_OnlineFeature` is a reference, not a feature — category 6 (Misleading names) +### 4. `FeatureLineage_OnlineFeature` is a reference, not a feature — category 6 (Misleading names) **Symbol:** `FeatureLineage_OnlineFeature` (model.ts:48); doc on the type-level JSDoc on the parent says "List of online features that use this feature as @@ -244,18 +194,17 @@ source." ``` This is *not* an online feature — it is a `(tableName, featureName)` pair -identifying one. Naming-wise the type should reflect "reference": -`OnlineFeatureRef` or `OnlineFeatureRef`. +identifying one. Additionally, the doc-string contradiction: outer JSDoc says +"online features that use this feature as source," but the inner field doc +says "online feature (column name)." The type is a coordinate, not the +feature itself. -Additionally, the doc-string contradiction: outer JSDoc says "online features -that use this feature as source," but the inner field doc says "online feature -(column name)." The type is a coordinate, not the feature itself. - -**Suggested:** `LineageOnlineFeatureRef` or `OnlineFeatureRef`. +**Suggested:** strengthen JSDoc to indicate this is a reference. Update the +inner field doc to match the outer JSDoc's intent. --- -### 7. `FeatureLineage_OnlineFeature.tableName` is the *online table name*, generic-named — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 5. `FeatureLineage_OnlineFeature.tableName` is the *online table name*, generic-named — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `FeatureLineage_OnlineFeature.tableName` (model.ts:52). @@ -276,7 +225,7 @@ in the file. **P1 fix candidate.** --- -### 8. `FeatureTag` is too generic — category 1 (Vague/generic) and category 12 (Duplicate concepts) +### 6. `FeatureTag` is too generic — category 1 (Vague/generic) and category 12 (Duplicate concepts) **Symbol:** `FeatureTag` (model.ts:56). JSDoc: "Represents a tag on a feature in a feature table." @@ -312,7 +261,7 @@ duplicates the conceptual boundary. --- -### 9. `FeatureTag.key` and `value` underspecified — category 19 (Underspecified IDs) and category 1 (Vague/generic) +### 7. `FeatureTag.key` and `value` underspecified — category 19 (Underspecified IDs) and category 1 (Vague/generic) **Symbols:** `FeatureTag.key`, `FeatureTag.value` (model.ts:57–58). @@ -329,7 +278,7 @@ convention for tag pairs — pass on name, fix the docs. --- -### 10. `CreateFeatureTagRequest`, `GetFeatureTagRequest`, `ListFeatureTagsRequest`, `UpdateFeatureTagRequest` carry `tableName` and `featureName` undocumented in some — category 6 (Misleading names) and JSDoc drift +### 8. `CreateFeatureTagRequest`, `GetFeatureTagRequest`, `ListFeatureTagsRequest`, `UpdateFeatureTagRequest` carry `tableName` and `featureName` undocumented in some — category 6 (Misleading names) and JSDoc drift **Symbols:** `CreateFeatureTagRequest.tableName` (model.ts:9), `GetFeatureTagRequest.tableName` (model.ts:70), @@ -359,7 +308,7 @@ the four types currently missing it. **Pass on naming, flag JSDoc drift.** --- -### 11. `ListFeatureTagsResponse` not `ListFeatureTagResponse` — category 9 (Singular/plural mismatch) and JSDoc drift +### 9. `ListFeatureTagsResponse` not `ListFeatureTagResponse` — category 9 (Singular/plural mismatch) and JSDoc drift **Symbol:** `ListFeatureTagsResponse` (model.ts:86). JSDoc reads "Response message for ListFeatureTag." (singular!) while the type is plural. @@ -371,7 +320,7 @@ Pass on naming, **fix the JSDoc** ("Response message for ListFeatureTags."). --- -### 12. `UpdateFeatureTagRequest.featureTag.key` is also the path key — category 16 (Field contradicting type domain) and category 19 (Underspecified IDs) +### 10. `UpdateFeatureTagRequest.featureTag.key` is also the path key — category 16 (Field contradicting type domain) and category 19 (Underspecified IDs) **Symbol:** `UpdateFeatureTagRequest.featureTag` (model.ts:96) + `client.updateFeatureTag` URL builder (client.ts:220). @@ -403,7 +352,7 @@ The naming is fine; the structural choice is misleading. **Flag for upstream.** --- -### 13. `GetFeatureLineageRequest` has fields ordered `featureName, tableName` — category 10 (Reserved-word collisions, by association) and JSDoc drift +### 11. `GetFeatureLineageRequest` has fields ordered `featureName, tableName` — category 10 (Reserved-word collisions, by association) and JSDoc drift **Symbol:** `GetFeatureLineageRequest` (model.ts:61). @@ -418,7 +367,7 @@ This is a cosmetic but reader-facing inconsistency. --- -### 14. `Client.getFeatureLineage` JSDoc reads "Get Feature Lineage." with title case — JSDoc drift and category 17 (Inconsistent action verbs) +### 12. `Client.getFeatureLineage` JSDoc reads "Get Feature Lineage." with title case — JSDoc drift and category 17 (Inconsistent action verbs) **Symbol:** `Client.getFeatureLineage` (client.ts:115). @@ -439,7 +388,7 @@ name, fix JSDoc** to read "Gets a FeatureLineage." or "Gets feature lineage." --- -### 15. Method-name verbs `creates`/`deletes`/`gets`/`lists`/`updates` are consistent — category 17 (Inconsistent action verbs) — *pass* +### 13. Method-name verbs `creates`/`deletes`/`gets`/`lists`/`updates` are consistent — category 17 (Inconsistent action verbs) — *pass* **Symbols:** `createFeatureTag`, `deleteFeatureTag`, `getFeatureLineage`, `getFeatureTag`, `listFeatureTags`, `updateFeatureTag` (client.ts). @@ -449,14 +398,14 @@ or `remove…` mixed in. **Pass.** --- -### 16. `Client` class name — category 1 (Vague/generic) — *pass* +### 14. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-materializedfeatures/v1`). **Pass.** --- -### 17. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 15. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:39). @@ -471,21 +420,21 @@ for SDK-wide cleanup, do not fix in isolation.** --- -### 18. `userAgent` / `httpClient` / `host` / `logger` — *pass* +### 16. `userAgent` / `httpClient` / `host` / `logger` — *pass* Standard private field names. Acronym handling matches the project rule. **Pass.** --- -### 19. `readAll` — *pass* +### 17. `readAll` — *pass* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 20. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* +### 18. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. The file mixes `build…`, `execute…`, `marshal…`, `parse…`, @@ -494,7 +443,7 @@ for its purpose. **Pass.** --- -### 21. `featureTagFieldMaskSchema` private but exported via `featureTagFieldMask()` — *pass* +### 19. `featureTagFieldMaskSchema` private but exported via `featureTagFieldMask()` — *pass* **Symbols:** `featureTagFieldMaskSchema` (model.ts:184, internal) and `featureTagFieldMask()` (model.ts:189, public). Clean separation: schema is @@ -503,7 +452,7 @@ update-mask vocabulary. **Pass.** --- -### 22. `UpdateFeatureTagRequest.updateMask` — category 7 (Overly verbose) — *pass* +### 20. `UpdateFeatureTagRequest.updateMask` — category 7 (Overly verbose) — *pass* **Symbol:** `UpdateFeatureTagRequest.updateMask: FieldMask` (model.ts:98). @@ -514,14 +463,14 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 23. Singular `FeatureTag` ⇔ plural `featureTags` — category 9 (Singular/plural mismatch) — *pass* +### 21. Singular `FeatureTag` ⇔ plural `featureTags` — category 9 (Singular/plural mismatch) — *pass* `ListFeatureTagsResponse.featureTags: FeatureTag[]` (model.ts:87) is the canonical pattern. **Pass.** --- -### 24. `FeatureLineage.models` field name does not describe content — category 6 (Misleading names) and category 15 (Generic field names losing meaning) +### 22. `FeatureLineage.models` field name does not describe content — category 6 (Misleading names) and category 15 (Generic field names losing meaning) **Symbol:** `FeatureLineage.models?: FeatureLineage_Model[]` (model.ts:26). @@ -532,12 +481,11 @@ model objects (with fields like `creator`, `description`, etc.). They actually get bare `{name, version}` pairs. **Suggested:** rename to `modelRefs`, `trainedModels`, or `modelReferences`. -Pairs with the finding-5 rename of `FeatureLineage_Model` → -`LineageModelRef` / `RegisteredModelRef`. +Signals that these are references rather than full model records. --- -### 25. `FeatureLineage.featureSpecs` vs `FeatureLineage.onlineFeatures` plural-singular mismatch — category 9 (Singular/plural mismatch) — *partial pass* +### 23. `FeatureLineage.featureSpecs` vs `FeatureLineage.onlineFeatures` plural-singular mismatch — category 9 (Singular/plural mismatch) — *partial pass* **Symbols:** `FeatureLineage.featureSpecs`, `FeatureLineage.onlineFeatures` (model.ts:28, 30). @@ -546,7 +494,7 @@ Both are arrays — plural form is consistent. No issue. **Pass.** --- -### 26. `LineageContext` from `features` package vs `FeatureLineage` from this package — category 12 (Duplicate concepts) +### 24. `LineageContext` from `features` package vs `FeatureLineage` from this package — category 12 (Duplicate concepts) **Symbol:** `FeatureLineage` (model.ts:24); compare `features.LineageContext` (`packages/features/src/v1/model.ts:465`). @@ -571,18 +519,18 @@ vs. dependents (Lineage). **Flag for upstream Go SDK / generator.** --- -### 27. `GetFeatureLineageRequest` is `GetFeature…`, returns `FeatureLineage` — *pass* +### 25. `GetFeatureLineageRequest` is `GetFeature…`, returns `FeatureLineage` — *pass* **Symbol:** `Client.getFeatureLineage` (client.ts:115), return type `FeatureLineage` (model.ts:24). The method name uses verb `get` consistently; the return type name is the resource. No issue at the method-name layer. (Underlying naming smells of -`FeatureLineage` itself are covered in findings 25, 27.) **Pass.** +`FeatureLineage` itself are covered in findings 22, 24.) **Pass.** --- -### 28. `BatchCreateMaterializedFeatures*` types live in `features` not this package — category 12 (Duplicate concepts) — cross-package +### 26. `BatchCreateMaterializedFeatures*` types live in `features` not this package — category 12 (Duplicate concepts) — cross-package **Symbols (cross-package):** `BatchCreateMaterializedFeaturesRequest`, `BatchCreateMaterializedFeaturesResponse` live in `features/v1/model.ts:146, @@ -596,32 +544,7 @@ coordination.** --- -### 29. `index.ts` re-exports underscore types — category 4 (Underscores in TS identifiers) - -**Symbol:** `index.ts:7–20`. - -**Issue:** The package surface re-exports the proto-style nested names: - -```ts -export type { - CreateFeatureTagRequest, - DeleteFeatureTagRequest, - FeatureLineage, - FeatureLineage_FeatureSpec, - FeatureLineage_Model, - FeatureLineage_OnlineFeature, - FeatureTag, - ... -}; -``` - -Three of the eleven exported types contain underscores. These are the same -identifiers flagged in finding 2 — but at the *package surface* level, every -consumer sees them. **Pass at the index.ts layer**, fix follows from finding 2. - ---- - -### 30. `index.ts:5` empty re-export — *pass with note* +### 27. `index.ts:5` empty re-export — *pass with note* **Symbol:** `export {} from './model';` (index.ts:5). @@ -631,7 +554,7 @@ on naming**, flag for generator cleanup. --- -### 31. URL path constants spread inline in `Client` methods — code-quality (out of scope) — *pass* +### 28. URL path constants spread inline in `Client` methods — code-quality (out of scope) — *pass* **Symbols:** every method constructs a URL via template literal embedding `req.tableName ?? ''` and `req.featureName ?? ''` (client.ts:74, 100, 119, @@ -642,7 +565,7 @@ concern, not naming. **Pass.** --- -### 32. `req`/`resp`/`pageReq` Go-style short variable names — category 14 (Go/Java-style names) +### 29. `req`/`resp`/`pageReq` Go-style short variable names — category 14 (Go/Java-style names) **Symbols:** local variables `req` (every method parameter), `resp` (every method local), `pageReq` (client.ts:202). @@ -654,7 +577,7 @@ convention is mixed. **Pass with note — flag for SDK-wide style decision.** --- -### 33. Generator-comment "DO NOT EDIT." header — *pass* +### 30. Generator-comment "DO NOT EDIT." header — *pass* Every file begins with `// Code generated from API definition by Databricks SDK Generator. DO NOT EDIT.` Naming-irrelevant, but informs the scope of any @@ -704,7 +627,7 @@ itself. The package-local `tableName` (used here) is fine *inside* the request types because the URL grammar disambiguates, but `FeatureLineage_OnlineFeature.tableName` -should definitely be `onlineTableName` (finding 7). +should definitely be `onlineTableName` (finding 5). **Flag for SDK-wide policy.** @@ -767,22 +690,21 @@ guidance.** - **Critical / cross-package consistency:** 2 findings (#1 package name mis-scope `materializedfeatures` does not contain materialized features; - #7 `FeatureLineage_OnlineFeature.tableName` should be `onlineTableName`). -- **High (style guide violations):** 3 findings (#2 three underscore types - `FeatureLineage_FeatureSpec/Model/OnlineFeature`; #17 `PACKAGE_SEGMENT` - casing; #29 surface re-exports underscore types). -- **Medium (naming clarity, JSDoc drift):** 13 findings (#3, #4, #5, #6, #8, - #9, #10, #11, #12, #13, #14, #24, #26). -- **Low / project-wide convention notes (generator-level):** 2 findings (#28, - #32). -- **Pass / acceptable as-is:** 13 findings (#15, #16, #18, #19, #20, #21, - #22, #23, #25, #27, #30, #31, #33 — many partial passes with notes). - -**Total flagged findings: 33** distinct items. The dominant theme is **package -mis-naming** (the package does not contain what its name advertises) and -**proto-style underscore identifier names** for nested types (`FeatureLineage_*`). -Many issues are generator-emitted boilerplate inherited from the Go SDK; -the cleanest local fixes are findings 1 (package rename), 7 -(`onlineTableName` field), 10 (JSDoc on `tableName`/`featureName`), 11 -(JSDoc plural form), 12 (top-level `key` for update), 13 (field order in -`GetFeatureLineageRequest`), and 14 (`getFeatureLineage` JSDoc casing). + #5 `FeatureLineage_OnlineFeature.tableName` should be `onlineTableName`). +- **High (style guide violations):** 1 finding (#15 `PACKAGE_SEGMENT` + casing). +- **Medium (naming clarity, JSDoc drift):** 11 findings (#2, #3, #4, #6, + #7, #8, #9, #10, #11, #12, #22, #24). +- **Low / project-wide convention notes (generator-level):** 2 findings (#26, + #29). +- **Pass / acceptable as-is:** 11 findings (#13, #14, #16, #17, #18, #19, + #20, #21, #23, #25, #27, #28, #30 — many partial passes with notes). + +**Total flagged findings: 30** distinct items. The dominant themes are +**package mis-naming** (the package does not contain what its name advertises) +and **cross-package mis-allocation** (materialized-feature types live in the +`features` package, not here). Many issues are generator-emitted boilerplate +inherited from the Go SDK; the cleanest local fixes are findings 1 (package +rename), 5 (`onlineTableName` field), 8 (JSDoc on `tableName`/`featureName`), +9 (JSDoc plural form), 10 (top-level `key` for update), 11 (field order in +`GetFeatureLineageRequest`), and 12 (`getFeatureLineage` JSDoc casing). diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index 3e5fc010..4802ec5d 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -13,21 +13,14 @@ The `metastores` package exposes nine Unity Catalog metastore operations `deleteMetastoreAssignment`, `getCurrentMetastoreAssignment`, `getMetastore`, `getMetastoreSummary`, `listMetastores`, `updateMetastore`, `updateMetastoreAssignment`). -The naming issues split into two broad classes: - -1. **Proto-style identifiers leaking into TypeScript** — - `DeltaSharingScope_Enum`, `*_Response`. -2. **Massive structural duplication** — `CreateMetastore`, - `UpdateMetastore`, and `MetastoreInfo` share 18 fields verbatim, - including read-only output fields (`createdAt`, `createdBy`, - `updatedAt`, `updatedBy`, `metastoreId`, `globalMetastoreId`) that - have no business in a write request. `UpdateMetastore` further - conflates a path-parameter `id`, a body `name`, and a "rename target" - `newName`. - -`DeltaSharingScope_Enum` is the single most visible cosmetic violation -(underscore identifier and `_Enum` suffix tautology), and it shows up -on three different types. +The dominant naming problems are structural: `CreateMetastore`, +`UpdateMetastore`, and `MetastoreInfo` share 18 fields verbatim, +including read-only output fields (`createdAt`, `createdBy`, `updatedAt`, +`updatedBy`, `metastoreId`, `globalMetastoreId`) that have no business in +a write request. `UpdateMetastore` further conflates a path-parameter +`id`, a body `name`, and a "rename target" `newName`. +`GetMetastoreSummary_Response` is structurally identical to +`MetastoreInfo` despite the "summary" name promising a smaller shape. --- @@ -44,7 +37,7 @@ everywhere else in the package (model.ts:42, 64, 91, 113, 213, 258, etc.), so the bare `id` is inconsistent and ambiguous in isolation (e.g. spreading `{...req, id: someValue}` is brittle). Recommend `metastoreId` (or, if the goal is to mark it as the path param, see -§5.1 / §12.1). +§5.1 / §10.1). #### 1.2 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:181, 183) Acceptable in isolation — but the *type* `MetastoreAssignment` is just @@ -63,12 +56,12 @@ worth flagging. #### 1.4 `cloud` field (model.ts:54, 122, 225, 270) A bare `cloud: string` with a single example list in the doc (`aws`, `azure`, `gcp`). Should probably be typed as a `CloudProvider` enum -(see §6.4) — but at minimum the field is generic when read alone. +(see §5.4) — but at minimum the field is generic when read alone. #### 1.5 `owner` field (model.ts:36, 140, 207, 252) "The owner of the metastore." — generic. Owner of what kind? Username? Email? Group? Service principal? Documented as a free-form string with -no format hint. See §15.4. +no format hint. See §13.4. #### 1.6 `region` (model.ts:40, 124, 211, 256) Bare `region: string` with examples (`us-west-2`, `westus`). Acceptable @@ -80,15 +73,7 @@ heterogeneity isn't reflected in the name or doc. ### 2. Redundant enum prefixes -#### 2.1 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) -Variants are `INTERNAL` and `INTERNAL_AND_EXTERNAL`. The enum name -already says "DeltaSharingScope" — the variants do not repeat that -prefix, which is good. However, `INTERNAL_AND_EXTERNAL` is verbose -(see §14.1) — a single canonical name like `ALL` or a pair like -`INTERNAL` / `EXTERNAL` would be clearer. - -(No `*_DELTA_SHARING_SCOPE_*` prefix issue here — variants are clean. -But see §4.1 for the enum *type* name.) +_None._ --- @@ -109,7 +94,7 @@ ECMAScript identifier convention; flagged in passing. #### 3.3 `URL` casing in docs (model.ts:23, 138, 194, 239) "The storage root URL" — `URL` in docs, but the field is `storageRoot`, not `storageRootUrl`. Inconsistent with how -`globalMetastoreId` etc. embed type info in the name. See also §6.2. +`globalMetastoreId` etc. embed type info in the name. See also §5.2. #### 3.4 `` placeholder tokens in docs (model.ts:69, 180, 285) Literal `` strings appear in doc comments — these are @@ -119,126 +104,88 @@ TypeDoc. --- -### 4. Underscores in TypeScript identifiers - -The package's most pervasive cosmetic problem. Every underscore-bearing -identifier is silenced with an -`@typescript-eslint/naming-convention -- Proto-style…` disable comment, -i.e. the lint rule already objects. - -#### 4.1 `DeltaSharingScope_Enum` (model.ts:6) -Should be `DeltaSharingScope`. The `_Enum` suffix is a proto-port -artifact (see also §8.2 and §16.1). The enum is referenced in five -places (lines 30, 132, 201, 246, 318, 385, 434, 493) — every reference -inherits the awkward name. - -#### 4.2 `CreateMetastoreAssignment_Response` (model.ts:75) -Should be `CreateMetastoreAssignmentResponse`. - -#### 4.3 `DeleteMetastore_Response` (model.ts:85) -Should be `DeleteMetastoreResponse`. - -#### 4.4 `DeleteMetastoreAssignment_Response` (model.ts:95) -Should be `DeleteMetastoreAssignmentResponse`. - -#### 4.5 `GetMetastoreSummary_Response` (model.ts:112) -Should be `GetMetastoreSummaryResponse`. (Non-empty — it's the only -genuinely useful `_Response` in the package; see §6.6.) - -#### 4.6 `ListMetastores_Response` (model.ts:169) -Should be `ListMetastoresResponse`. - -#### 4.7 `UpdateMetastoreAssignment_Response` (model.ts:291) -Should be `UpdateMetastoreAssignmentResponse`. - ---- +### 4. Cryptic abbreviations -### 5. Cryptic abbreviations - -#### 5.1 `id` (model.ts:79, 105, 234) — see §1.1 +#### 4.1 `id` (model.ts:79, 105, 234) — see §1.1 Cryptic because it loses the entity context. `metastoreId` is used elsewhere. -#### 5.2 `Ms` suffix absent on timestamp fields +#### 4.2 `Ms` suffix absent on timestamp fields Counter-example: timestamp fields are documented as "epoch milliseconds" but the names omit the unit suffix (`createdAt`, -`updatedAt`). See §15.5. +`updatedAt`). See §13.5. --- -### 6. Misleading names +### 5. Misleading names -#### 6.1 `MetastoreInfo` (model.ts:191) +#### 5.1 `MetastoreInfo` (model.ts:191) "Info" suggests metadata about a metastore separate from the entity -itself; the type is in fact the entity. See also §8.1. +itself; the type is in fact the entity. See also §7.1. -#### 6.2 `storageRoot` doc says "URL" (model.ts:23, 138, 194, 239) +#### 5.2 `storageRoot` doc says "URL" (model.ts:23, 138, 194, 239) "The storage root URL for metastore" — the field is named `storageRoot`, but documented as a URL. Rename to `storageRootUrl`, or rename the doc. Today the name is vague about the value's shape. -#### 6.3 `globalMetastoreId` (model.ts:56, 126, 227, 271) +#### 5.3 `globalMetastoreId` (model.ts:56, 126, 227, 271) Doc: "Globally unique metastore ID across clouds and regions, of the form `cloud:region:metastore_id`." So the value is a composite formatted string, not an ID in the conventional sense. Either rename to `globalMetastoreLocator` / `globalMetastoreUri` to signal the encoded shape, or document its parseable structure in a type. -#### 6.4 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +#### 5.4 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) Doc says "Unique identifier of the metastore's (Default) Data Access Configuration." The parenthetical "Default" duplicates the `default` prefix in the name, but the field is described as both the default data-access-config and as a unique identifier. Slightly self-referential -and unclear whether this is mutable or static. See also §15.3. +and unclear whether this is mutable or static. See also §13.3. -#### 6.5 `cloud: string` (model.ts:54, 122, 225, 270) +#### 5.5 `cloud: string` (model.ts:54, 122, 225, 270) Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as `string`. The name is fine; the *type* misleads about the value -space. Compare with `DeltaSharingScope_Enum`, which is explicitly an -enum. See §1.4. +space. See §1.4. -#### 6.6 `region: string` carries cloud-specific formats (model.ts:40, 124, 211, 256) +#### 5.6 `region: string` carries cloud-specific formats (model.ts:40, 124, 211, 256) "e.g., `us-west-2`, `westus`" — same field carries AWS-style and Azure-style region names. Name is fine; doc just shows the heterogeneity. See §1.6. -#### 6.7 `GetMetastoreSummary_Response` is structurally identical to `MetastoreInfo` (model.ts:112-151 vs 191-230) +#### 5.7 `GetMetastoreSummary` response is structurally identical to `MetastoreInfo` (model.ts:112-151 vs 191-230) Both types have the *same* 18 fields with the *same* docs in the *same* order. The "summary" type doesn't actually summarise — it returns the full metastore record. The name lies about the content. The Go SDK inherits this from the API definition, but the TS port could collapse -the two: either alias `GetMetastoreSummaryResponse = MetastoreInfo` or +the two: either alias the summary response to `MetastoreInfo` or expose the genuinely-summarised subset. -#### 6.8 `getMetastoreSummary` is presented as info-about (client.ts:266-269) +#### 5.8 `getMetastoreSummary` is presented as info-about (client.ts:266-269) JSDoc says "Gets information about a metastore. This summary includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" omits the "current-workspace" semantics. Cf. `getCurrentMetastoreAssignment`, which spells out "current". See also -§13.1. +§11.1. --- -### 7. Overly verbose +### 6. Overly verbose -#### 7.1 `getCurrentMetastoreAssignment` (client.ts:216) +#### 6.1 `getCurrentMetastoreAssignment` (client.ts:216) 28-character method name. Acceptable — describes the semantics — but combined with `getMetastoreSummary` (which is also "current-workspace" -in practice, §6.8) one of them carries redundant prefixing. +in practice, §5.8) one of them carries redundant prefixing. --- -### 8. Redundant suffixes +### 7. Redundant suffixes -#### 8.1 `…Info` suffix on `MetastoreInfo` (model.ts:191) +#### 7.1 `…Info` suffix on `MetastoreInfo` (model.ts:191) "Info" carries no semantic content. Go-SDK convention; TS would just -say `Metastore`. See §10.3. - -#### 8.2 `…_Enum` suffix on `DeltaSharingScope_Enum` (model.ts:6) — see §4.1. -TypeScript enums are already enums; the suffix tautological. +say `Metastore`. See §9.3. -#### 8.3 `…Assignment` suffix on `MetastoreAssignment` and four request types +#### 7.2 `…Assignment` suffix on `MetastoreAssignment` and four request types `CreateMetastoreAssignment`, `DeleteMetastoreAssignment`, `UpdateMetastoreAssignment`, `GetCurrentMetastoreAssignment`, `MetastoreAssignment`. The suffix is justified because "metastore @@ -247,42 +194,35 @@ completeness. --- -### 9. Singular / plural mismatches +### 8. Singular / plural mismatches -#### 9.1 `ListMetastores_Response.metastores` (model.ts:171) +#### 8.1 `ListMetastoresResponse.metastores` (model.ts:171) Field is plural and correctly typed `MetastoreInfo[]` — no mismatch. Flagged as a counter-example. --- -### 10. Reserved-word collisions +### 9. Reserved-word collisions -#### 10.1 `name` field on `CreateMetastore`, `MetastoreInfo`, `UpdateMetastore`, `GetMetastoreSummary_Response` (model.ts:22, 116, 193, 238) +#### 9.1 `name` field on `CreateMetastore`, `MetastoreInfo`, `UpdateMetastore`, `GetMetastoreSummary` response (model.ts:22, 116, 193, 238) Routinely shadows `Function.prototype.name`. Common SDK convention; not -fixable in isolation. See also §12.1. +fixable in isolation. See also §10.1. -#### 10.2 `id` field on `DeleteMetastore`, `GetMetastore`, `UpdateMetastore` (model.ts:79, 105, 234) +#### 9.2 `id` field on `DeleteMetastore`, `GetMetastore`, `UpdateMetastore` (model.ts:79, 105, 234) Collides with `Element.id` and other web-platform-y identifiers when the request type is used in browser code. Not a TS-level collision but a cognitive one. See §1.1. -#### 10.3 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. +#### 9.3 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. --- -### 11. Duplicate concepts - -#### 11.1 `DeltaSharingScope` interface vs `DeltaSharingScope_Enum` enum (model.ts:6, 98) -Two distinct exports with near-identical names — one is the enum, the -other a separate type. A user importing `DeltaSharingScope` will get -the non-enum export and silently get the wrong shape. The naming is -maximally hostile and the `_Enum` suffix on the enum exists solely to -disambiguate from this sibling. +### 10. Duplicate concepts -#### 11.2 `MetastoreInfo` vs `GetMetastoreSummary_Response` (model.ts:112, 191) -Same 18 fields, same docs, different names. See §6.7. +#### 10.1 `MetastoreInfo` vs `GetMetastoreSummary` response (model.ts:112, 191) +Same 18 fields, same docs, different names. See §5.7. -#### 11.3 `CreateMetastore` vs `MetastoreInfo` vs `UpdateMetastore` (model.ts:20, 191, 232) +#### 10.2 `CreateMetastore` vs `MetastoreInfo` vs `UpdateMetastore` (model.ts:20, 191, 232) Massive structural duplication — `CreateMetastore` has 19 fields, `MetastoreInfo` has 19 fields, `UpdateMetastore` has 20 fields. The extra field on `UpdateMetastore` is `id` (path param) plus `newName`. @@ -291,36 +231,36 @@ shared `MetastoreCommon` (or `Partial`) would let renames happen in one place. Note that all three contain the same read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `globalMetastoreId`) — these have no business on a -request shape (§12.3). +request shape (§11.3). -#### 11.4 `CreateMetastoreAssignment` vs `MetastoreAssignment` vs `UpdateMetastoreAssignment` (model.ts:61, 179, 277) +#### 10.3 `CreateMetastoreAssignment` vs `MetastoreAssignment` vs `UpdateMetastoreAssignment` (model.ts:61, 179, 277) Three structurally identical types with three workspace-id / metastore-id / default-catalog-name fields. Could be unified. -#### 11.5 `id` (on `DeleteMetastore`/`GetMetastore`/`UpdateMetastore`) vs `metastoreId` (everywhere else) +#### 10.4 `id` (on `DeleteMetastore`/`GetMetastore`/`UpdateMetastore`) vs `metastoreId` (everywhere else) Same concept, two names. See §1.1. -#### 11.6 `name` (CreateMetastore body) vs metastore identity +#### 10.5 `name` (CreateMetastore body) vs metastore identity `CreateMetastore.name` is "the user-specified name of the metastore" — but `MetastoreInfo` also exposes `metastoreId` as the canonical unique identifier. The naming pretends `name` is unique but in fact the server creates `metastoreId` as the immutable key and `name` is mutable. The doc could disclose this; the name doesn't. -#### 11.7 `name` vs `newName` on `UpdateMetastore` (model.ts:236, 238) +#### 10.6 `name` vs `newName` on `UpdateMetastore` (model.ts:236, 238) Two name-like fields on the update request: - `newName` — "New name for the metastore." (model.ts:236). - `name` — "The user-specified name of the metastore." (model.ts:238). Per the doc, both fields can hold a name. The intent is presumably that `newName` is the rename target and `name` is left over from the -shared shape; in practice, callers cannot tell. See §12.1. +shared shape; in practice, callers cannot tell. See §11.1. --- -### 12. Field contradicting type domain +### 11. Field contradicting type domain -#### 12.1 `UpdateMetastore` has `id`, `name`, `newName`, and `metastoreId` (model.ts:234, 236, 238, 258) +#### 11.1 `UpdateMetastore` has `id`, `name`, `newName`, and `metastoreId` (model.ts:234, 236, 238, 258) Four name/id-like fields on a single update request: - `id` — path parameter; the existing metastore to update. - `metastoreId` — leftover from the shared shape; not used by the @@ -335,11 +275,11 @@ A caller staring at this struct cannot intuit which field controls what. This is the package's single most user-hostile naming pattern, mirroring the `UpdateCatalog` issue (catalogs §16.1). -#### 12.2 `UpdateMetastore.metastoreId` shadows `UpdateMetastore.id` (model.ts:234, 258) -Same as 12.1 — two id-like fields whose roles are not differentiated +#### 11.2 `UpdateMetastore.metastoreId` shadows `UpdateMetastore.id` (model.ts:234, 258) +Same as 11.1 — two id-like fields whose roles are not differentiated by name. -#### 12.3 `CreateMetastore` and `UpdateMetastore` carry read-only output fields (model.ts:42-58, 258-274) +#### 11.3 `CreateMetastore` and `UpdateMetastore` carry read-only output fields (model.ts:42-58, 258-274) `metastoreId`, `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `globalMetastoreId`, `cloud`, `storageRootCredentialName`. These are server-populated; a creator/updater setting them is at best ignored. @@ -347,13 +287,13 @@ The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of catalogs §16.2. -#### 12.4 `GetMetastoreSummary_Response` returns the full metastore (model.ts:112) — see §6.7. The type name promises a summary; the value is the entity. +#### 11.4 `GetMetastoreSummary` response returns the full metastore (model.ts:112) — see §5.7. The type name promises a summary; the value is the entity. --- -### 13. Inconsistent action verbs +### 12. Inconsistent action verbs -#### 13.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:241, 269, 216) +#### 12.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:241, 269, 216) Three "get"-style methods, each with a different qualifier: - `getMetastore(req)` — get by id. - `getMetastoreSummary()` — get the current metastore (no id). @@ -363,77 +303,60 @@ Three "get"-style methods, each with a different qualifier: The first explicitly takes an id, the second implicitly uses the current workspace, the third explicitly says "Current". Inconsistent qualifier vocabulary. Either rename `getMetastoreSummary` to -`getCurrentMetastore` (which would also fix §6.8) or drop "Current" +`getCurrentMetastore` (which would also fix §5.8) or drop "Current" from `getCurrentMetastoreAssignment`. -#### 13.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. - ---- - -### 14. Long enum values - -#### 14.1 `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` (model.ts:17) -20 characters. Two of two variants is verbose. A pair `INTERNAL` / -`EXTERNAL` (where `EXTERNAL` implies "in addition to internal") would -be punchier. The current name doubles as a poor man's bit-flag. See §2.1. +#### 12.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. --- -### 15. Underspecified IDs +### 13. Underspecified IDs -#### 15.1 `metastoreId` (model.ts:42, 64, 91, 113, 183, 213, 258, 281) +#### 13.1 `metastoreId` (model.ts:42, 64, 91, 113, 183, 213, 258, 281) Documented as "Unique identifier of metastore" / "The unique ID of the metastore." Format is opaque — likely a UUID, but never specified in the doc. -#### 15.2 `workspaceId` (model.ts:63, 89, 181, 279) +#### 13.2 `workspaceId` (model.ts:63, 89, 181, 279) `number` — that's specified by the type, but the doc just says "A workspace ID." with no range or stability guarantee. Acceptable for a numeric id; flagged because the format isn't documented in the field. -#### 15.3 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +#### 13.3 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) "Unique identifier of the metastore's (Default) Data Access -Configuration." No format hint (UUID? slug?). See §6.4. +Configuration." No format hint (UUID? slug?). See §5.4. -#### 15.4 `storageRootCredentialId` (model.ts:28, 120, 199, 244) +#### 13.4 `storageRootCredentialId` (model.ts:28, 120, 199, 244) Doc says "UUID of storage credential" — at least the doc says UUID here, but the field name doesn't carry the type. Counter-example to -§15.1: when the doc *does* specify UUID, the field still doesn't carry +§13.1: when the doc *does* specify UUID, the field still doesn't carry it. -#### 15.5 `createdAt`, `updatedAt` (model.ts:44, 48, 142, 146, 215, 219, 260, 264) +#### 13.5 `createdAt`, `updatedAt` (model.ts:44, 48, 142, 146, 215, 219, 260, 264) Doc says "epoch milliseconds" but the names lack the `Ms` unit suffix. Inconsistent across the package. -#### 15.6 `globalMetastoreId` (model.ts:56, 126, 227, 271) +#### 13.6 `globalMetastoreId` (model.ts:56, 126, 227, 271) Documented as a composite `cloud:region:metastore_id` string — not a simple ID. The name promises an ID; the value is a structured -locator. See §6.3. +locator. See §5.3. -#### 15.7 `owner`, `createdBy`, `updatedBy` (model.ts:36, 46, 50, 140, 144, 148, 207, 217, 221, 252, 262, 266) +#### 13.7 `owner`, `createdBy`, `updatedBy` (model.ts:36, 46, 50, 140, 144, 148, 207, 217, 221, 252, 262, 266) Documented as "username", "Username of metastore creator", etc. Format (email? user id? group?) is unspecified. The names imply identity; the doc only narrows to "username". --- -### 16. Type-suffix tautology - -#### 16.1 `DeltaSharingScope_Enum` enum with field `deltaSharingScope: DeltaSharingScope_Enum` (model.ts:6, 30, 132, 201, 246) -Field name `deltaSharingScope` is identical to the enum *minus* the -`_Enum` suffix. The `_Enum` suffix exists solely to disambiguate the -enum from the sibling `DeltaSharingScope` interface (§11.1). Were the -sibling renamed, the enum could simply be `DeltaSharingScope` and the -field name would be exactly the enum name (a true tautology). Today, -the workaround is the `_Enum` suffix. +### 14. Type-suffix tautology -#### 16.2 `MetastoreInfo` exposes `metastoreId` (model.ts:191, 213) +#### 14.1 `MetastoreInfo` exposes `metastoreId` (model.ts:191, 213) The type's domain is the metastore; the field redundantly carries the entity name in its identifier. Acceptable convention; flagged for completeness. -#### 16.3 `MetastoreAssignment` carries `metastoreId` (model.ts:179, 183) -Same pattern as 16.2 — entity name in field. +#### 14.2 `MetastoreAssignment` carries `metastoreId` (model.ts:179, 183) +Same pattern as 14.1 — entity name in field. --- @@ -473,20 +396,7 @@ a path one. "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### F. `index.ts` re-exports proto-style names verbatim (lines 5, 7-27) -Every underscore-bearing identifier surfaces in the package's public -API. A consumer of `@databricks/sdk-metastores/v1` sees -`DeltaSharingScope_Enum`, `CreateMetastoreAssignment_Response`, -`DeleteMetastore_Response`, `DeleteMetastoreAssignment_Response`, -`GetMetastoreSummary_Response`, `ListMetastores_Response`, and -`UpdateMetastoreAssignment_Response` as first-class exports. - -### G. `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` (index.ts:5, 15) -A consumer importing `DeltaSharingScope` gets the sibling export, not -the enum. There is no compile-time or runtime hint that they should -have used the `_Enum`-suffixed export. See §11.1. - -### H. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies +### F. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies This package's `workspaceId` is `number`. Some peer packages model workspace IDs as strings (e.g. when forwarded through URL params). The type inconsistency is across packages, not within this one; @@ -498,73 +408,63 @@ flagged in passing. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | -| `DeltaSharingScope_Enum` | model.ts:6 | 2.1, 4.1, 8.2, 14.1, 16.1 | -| `DeltaSharingScope_Enum.INTERNAL` | model.ts:12 | — | -| `DeltaSharingScope_Enum.INTERNAL_AND_EXTERNAL` | model.ts:17 | 2.1, 14.1 | -| `CreateMetastore` | model.ts:20 | 11.3, 12.3 | -| `CreateMetastore.name` | model.ts:22 | 10.1, 11.6 | -| `CreateMetastore.storageRoot` | model.ts:24 | 6.2 | -| `CreateMetastore.defaultDataAccessConfigId` | model.ts:26 | 6.4, 15.3 | -| `CreateMetastore.storageRootCredentialId` | model.ts:28 | 15.4 | -| `CreateMetastore.deltaSharingScope` | model.ts:30 | 16.1 | -| `CreateMetastore.owner` | model.ts:36 | 1.5, 15.7 | -| `CreateMetastore.region` | model.ts:40 | 1.6, 6.6 | -| `CreateMetastore.metastoreId` (read-only on Create) | model.ts:42 | 12.3, 15.1, 16.2 | -| `CreateMetastore.createdAt` (read-only on Create) | model.ts:44 | 12.3, 15.5 | -| `CreateMetastore.createdBy` (read-only on Create) | model.ts:46 | 12.3, 15.7 | -| `CreateMetastore.updatedAt` (read-only on Create) | model.ts:48 | 12.3, 15.5 | -| `CreateMetastore.updatedBy` (read-only on Create) | model.ts:50 | 12.3, 15.7 | -| `CreateMetastore.storageRootCredentialName` (read-only) | model.ts:52 | 12.3 | -| `CreateMetastore.cloud` | model.ts:54 | 1.4, 6.5 | -| `CreateMetastore.globalMetastoreId` (read-only) | model.ts:56 | 6.3, 12.3, 15.6 | +| `CreateMetastore` | model.ts:20 | 10.2, 11.3 | +| `CreateMetastore.name` | model.ts:22 | 9.1, 10.5 | +| `CreateMetastore.storageRoot` | model.ts:24 | 5.2 | +| `CreateMetastore.defaultDataAccessConfigId` | model.ts:26 | 5.4, 13.3 | +| `CreateMetastore.storageRootCredentialId` | model.ts:28 | 13.4 | +| `CreateMetastore.owner` | model.ts:36 | 1.5, 13.7 | +| `CreateMetastore.region` | model.ts:40 | 1.6, 5.6 | +| `CreateMetastore.metastoreId` (read-only on Create) | model.ts:42 | 11.3, 13.1, 14.1 | +| `CreateMetastore.createdAt` (read-only on Create) | model.ts:44 | 11.3, 13.5 | +| `CreateMetastore.createdBy` (read-only on Create) | model.ts:46 | 11.3, 13.7 | +| `CreateMetastore.updatedAt` (read-only on Create) | model.ts:48 | 11.3, 13.5 | +| `CreateMetastore.updatedBy` (read-only on Create) | model.ts:50 | 11.3, 13.7 | +| `CreateMetastore.storageRootCredentialName` (read-only) | model.ts:52 | 11.3 | +| `CreateMetastore.cloud` | model.ts:54 | 1.4, 5.5 | +| `CreateMetastore.globalMetastoreId` (read-only) | model.ts:56 | 5.3, 11.3, 13.6 | | `CreateMetastore.externalAccessEnabled` | model.ts:58 | 3.1 (doc) | -| `CreateMetastoreAssignment` | model.ts:61 | 11.4 | -| `CreateMetastoreAssignment.workspaceId` | model.ts:63 | 15.2, H | -| `CreateMetastoreAssignment.metastoreId` | model.ts:65 | 15.1 | +| `CreateMetastoreAssignment` | model.ts:61 | 10.3 | +| `CreateMetastoreAssignment.workspaceId` | model.ts:63 | 13.2, F | +| `CreateMetastoreAssignment.metastoreId` | model.ts:65 | 13.1 | | `CreateMetastoreAssignment.defaultCatalogName` | model.ts:71 | — | -| `CreateMetastoreAssignment_Response` | model.ts:75 | 4.2 | | `DeleteMetastore` | model.ts:77 | — | -| `DeleteMetastore.id` | model.ts:79 | 1.1, 5.1, 10.2, 11.5 | +| `DeleteMetastore.id` | model.ts:79 | 1.1, 4.1, 9.2, 10.4 | | `DeleteMetastore.force` | model.ts:81 | 1.3 | -| `DeleteMetastore_Response` | model.ts:85 | 4.3 | -| `DeleteMetastoreAssignment` | model.ts:87 | 11.4 | -| `DeleteMetastoreAssignment.workspaceId` | model.ts:89 | 15.2 | -| `DeleteMetastoreAssignment.metastoreId` | model.ts:91 | 15.1, D | -| `DeleteMetastoreAssignment_Response` | model.ts:95 | 4.4 | -| `DeltaSharingScope` | model.ts:98 | 11.1, G | +| `DeleteMetastoreAssignment` | model.ts:87 | 10.3 | +| `DeleteMetastoreAssignment.workspaceId` | model.ts:89 | 13.2 | +| `DeleteMetastoreAssignment.metastoreId` | model.ts:91 | 13.1, D | | `GetCurrentMetastoreAssignment` | model.ts:101 | — | | `GetMetastore` | model.ts:103 | — | -| `GetMetastore.id` | model.ts:105 | 1.1, 5.1, 10.2, 11.5 | +| `GetMetastore.id` | model.ts:105 | 1.1, 4.1, 9.2, 10.4 | | `GetMetastoreSummary` | model.ts:109 | — | -| `GetMetastoreSummary_Response` | model.ts:112 | 4.5, 6.7, 11.2, 12.4 | +| `GetMetastoreSummary` response | model.ts:112 | 5.7, 10.1, 11.4 | | `ListMetastores` | model.ts:153 | — | | `ListMetastores.maxResults` | model.ts:163 | — | | `ListMetastores.pageToken` | model.ts:165 | — | -| `ListMetastores_Response` | model.ts:169 | 4.6 | -| `ListMetastores_Response.metastores` | model.ts:171 | 9.1 (positive) | -| `ListMetastores_Response.nextPageToken` | model.ts:176 | — | -| `MetastoreAssignment` | model.ts:179 | 1.2, 8.3, 11.4 | -| `MetastoreAssignment.workspaceId` | model.ts:181 | 1.2, 15.2, H | -| `MetastoreAssignment.metastoreId` | model.ts:183 | 15.1, 16.3 | +| `ListMetastoresResponse.metastores` | model.ts:171 | 8.1 (positive) | +| `ListMetastoresResponse.nextPageToken` | model.ts:176 | — | +| `MetastoreAssignment` | model.ts:179 | 1.2, 7.2, 10.3 | +| `MetastoreAssignment.workspaceId` | model.ts:181 | 1.2, 13.2, F | +| `MetastoreAssignment.metastoreId` | model.ts:183 | 13.1, 14.2 | | `MetastoreAssignment.defaultCatalogName` | model.ts:188 | — | -| `MetastoreInfo` | model.ts:191 | 6.1, 8.1, 11.3 | -| `MetastoreInfo.metastoreId` | model.ts:213 | 15.1, 16.2 | -| `MetastoreInfo.globalMetastoreId` | model.ts:227 | 6.3, 15.6 | -| `UpdateMetastore` | model.ts:232 | 11.3, 12.1, 12.3 | -| `UpdateMetastore.id` | model.ts:234 | 1.1, 5.1, 12.1, 12.2 | -| `UpdateMetastore.newName` | model.ts:236 | 11.7, 12.1 | -| `UpdateMetastore.name` | model.ts:238 | 11.7, 12.1 | -| `UpdateMetastore.metastoreId` | model.ts:258 | 12.1, 12.2 | -| `UpdateMetastoreAssignment` | model.ts:277 | 11.4 | -| `UpdateMetastoreAssignment.workspaceId` | model.ts:279 | 15.2 | -| `UpdateMetastoreAssignment_Response` | model.ts:291 | 4.7 | +| `MetastoreInfo` | model.ts:191 | 5.1, 7.1, 10.2 | +| `MetastoreInfo.metastoreId` | model.ts:213 | 13.1, 14.1 | +| `MetastoreInfo.globalMetastoreId` | model.ts:227 | 5.3, 13.6 | +| `UpdateMetastore` | model.ts:232 | 10.2, 11.1, 11.3 | +| `UpdateMetastore.id` | model.ts:234 | 1.1, 4.1, 11.1, 11.2 | +| `UpdateMetastore.newName` | model.ts:236 | 10.6, 11.1 | +| `UpdateMetastore.name` | model.ts:238 | 10.6, 11.1 | +| `UpdateMetastore.metastoreId` | model.ts:258 | 11.1, 11.2 | +| `UpdateMetastoreAssignment` | model.ts:277 | 10.3 | +| `UpdateMetastoreAssignment.workspaceId` | model.ts:279 | 13.2 | | `Client.createMetastore` | client.ts:92 | — | | `Client.createMetastoreAssignment` | client.ts:122 | — | | `Client.deleteMetastore` | client.ts:151 | C | | `Client.deleteMetastoreAssignment` | client.ts:182 | B, D | -| `Client.getCurrentMetastoreAssignment` | client.ts:216 | 13.1 | -| `Client.getMetastore` | client.ts:241 | 13.1, C | -| `Client.getMetastoreSummary` | client.ts:269 | 6.8, 13.1 | +| `Client.getCurrentMetastoreAssignment` | client.ts:216 | 12.1 | +| `Client.getMetastore` | client.ts:241 | 12.1, C | +| `Client.getMetastoreSummary` | client.ts:269 | 5.8, 12.1 | | `Client.listMetastores` | client.ts:305 | — | | `Client.updateMetastore` | client.ts:360 | C | | `Client.updateMetastoreAssignment` | client.ts:390 | B | @@ -572,20 +472,16 @@ flagged in passing. | `${req.workspaceId ?? ''}` URL substitution | client.ts:126, 186, 394 | B | | `Host is required.` bare Error | client.ts:72 | E | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `index.ts` re-exports underscored names | index.ts:5, 9, 12, 14, 17, 19, 21, 26 | F | -| `index.ts` re-exports both `DeltaSharingScope` and `DeltaSharingScope_Enum` | index.ts:5, 15 | G | --- ## Recommended priority order -1. **Disambiguate the four name/id-like fields on `UpdateMetastore`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§12.1, §11.7, §1.1) -2. **Drop the `_Enum` suffix from `DeltaSharingScope_Enum` and rename the sibling `DeltaSharingScope` export to resolve the naming collision.** (§11.1, §4.1, §16.1, §G) -3. **Drop proto-style `_Response` identifiers** (`CreateMetastoreAssignment_Response`, `DeleteMetastore_Response`, `DeleteMetastoreAssignment_Response`, `GetMetastoreSummary_Response`, `ListMetastores_Response`, `UpdateMetastoreAssignment_Response`). (§4.2-4.7) -4. **Strip read-only fields from `CreateMetastore` / `UpdateMetastore`.** (§12.3, §11.3) -5. **Decide whether `GetMetastoreSummary_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§6.7, §11.2) -6. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§6.8, §13.1) -7. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §11.5) -8. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) -9. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match common conventions. (§15.5) -10. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +1. **Disambiguate the four name/id-like fields on `UpdateMetastore`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.6, §1.1) +2. **Strip read-only fields from `CreateMetastore` / `UpdateMetastore`.** (§11.3, §10.2) +3. **Decide whether the `GetMetastoreSummary` response should alias `MetastoreInfo` or expose a genuine subset.** (§5.7, §10.1) +4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.8, §12.1) +5. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §10.4) +6. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) +7. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match common conventions. (§13.5) +8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index 1d16ec2f..cbb8742b 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,15 +8,15 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 61 +**Total weird names flagged:** 59 ## Summary | Severity | Count | | --- | --- | -| High | 21 | +| High | 20 | | Medium | 24 | | Low | 12 | -| Observation | 4 | +| Observation | 3 | ## High severity @@ -142,21 +142,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `Comment` — or fold into `Activity` per #7. - **Rationale:** `Object` adds nothing; the type is already a TS object. -### 9. `*_Response` suffix on dozens of interfaces — `model.ts:217, 280, 307, 322, 375, 402, 413, 423, 434, 443, 453, 464, 491, 509, 525, 537, 548, 590, 638, 653, 853, 866, 890, 917, 943, 962, 973, 1005, 1066, 1081, 1094, 1137` -- **Why weird:** Underscore in TS identifiers (proto-style nested - type). Every declaration carries an `eslint-disable - @typescript-eslint/naming-convention` comment. 33 such offenders in - one file. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/Java - naming style). -- **Suggested name:** Drop the underscore: `ApproveTransitionRequestResponse`, - `CreateCommentResponse`, etc. -- **Rationale:** The underscore exists only to mirror protobuf nested - message names. TypeScript convention rejects it (the lint rule has to - be disabled for every single one), and `Foo_Response` reads as a - private/internal field by JS convention. - -### 10. `GetRegisteredModelDatabricks`, `RegisteredModelDatabricks`, +### 9. `GetRegisteredModelDatabricks`, `RegisteredModelDatabricks`, `TransitionModelVersionStageDatabricks`, `ModelVersionDatabricks` — `model.ts:542, 549, 690, 758, 981, 1005` - **Why weird:** `Databricks` as a type suffix. The whole SDK is the @@ -174,7 +160,7 @@ is the Unity-Catalog-scoped successor. (then split by capability). The current "shadow type per extension" is a generator artefact, not a user-friendly API. -### 11. `TransitionModelVersionStageDatabricks` — `model.ts:981` +### 10. `TransitionModelVersionStageDatabricks` — `model.ts:981` - **Why weird:** Five-word PascalCase identifier with awkward word order. Reads as "transition[verb] model-version-stage[object]-databricks[suffix]". For a TS type, it @@ -190,7 +176,7 @@ is the Unity-Catalog-scoped successor. performing similar workspace operations; the asymmetric names obscure this. -### 12. `GetRegisteredModelDatabricks` request DTO — `model.ts:542` +### 11. `GetRegisteredModelDatabricks` request DTO — `model.ts:542` - **Why weird:** Verb-phrase request type name (`GetX`) is OK if used consistently, but `GetRegisteredModelDatabricks` is the only method the SDK exposes to fetch a registered model — there is no plain @@ -201,7 +187,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** No need for the disambiguation suffix when there's no sibling. -### 13. `client.listTransitionsRequest` method vs `ListTransitionRequest` +### 12. `client.listTransitionsRequest` method vs `ListTransitionRequest` request type — `client.ts:507, model.ts:645` - **Why weird:** The method is `listTransitionsRequest` (plural "Transitions") but the request type is `ListTransitionRequest` @@ -218,7 +204,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The method name in JS conventions describes the collection being listed; here that's "transition requests", plural. -### 14. `RegistryWebhook` vs `Webhook` — `model.ts:787` +### 13. `RegistryWebhook` vs `Webhook` — `model.ts:787` - **Why weird:** Type is `RegistryWebhook` but client methods, paths, and request types alternate: `CreateRegistryWebhook`, `ListRegistryWebhooks`, `UpdateRegistryWebhook`, @@ -230,7 +216,7 @@ is the Unity-Catalog-scoped successor. `UpdateWebhook`, `DeleteWebhook`, `TestWebhook`. - **Rationale:** Package name already establishes the registry context. -### 15. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` +### 14. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` - **Why weird:** `Spec` is a vague suffix shared by every config-bag in the SDK. Two sibling types in the same package, only the `Spec` suffix distinguishing them. `HttpUrlSpec` is the *target* of a webhook @@ -243,7 +229,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The two together discriminate the webhook destination kind; the naming should make that obvious. -### 16. `LinkedFeature` — `model.ts:573` +### 15. `LinkedFeature` — `model.ts:573` - **Why weird:** Doc comment says "Feature for model version. ([ML-57150] Renamed from Feature to LinkedFeature)". The ticket number leaks into the public docstring. Type name was changed for internal reasons @@ -256,7 +242,7 @@ is the Unity-Catalog-scoped successor. type; the fields are just identifiers pointing at a feature in the feature store. -### 17. `userId: string` field documented as username — `model.ts:154, +### 16. `userId: string` field documented as username — `model.ts:154, 231, 668, 700, 766, 1018` - **Why weird:** Field is named `userId` but every doc-comment for it reads "The username of the user that created the object." So the @@ -269,7 +255,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Calling a username `userId` will trip every caller who tries to use it as an ID for IAM lookups. -### 18. `stage: string` field on `ApproveTransitionRequest`, +### 17. `stage: string` field on `ApproveTransitionRequest`, `CreateTransitionRequest`, `DeleteTransitionRequest`, `RejectTransitionRequest`, `TransitionModelVersionStageDatabricks` — `model.ts:209, 396, 483, 847, 997` @@ -285,9 +271,9 @@ is the Unity-Catalog-scoped successor. to a type. Currently every transition method takes `stage: string` with no type-level validation. -### 19. `currentStage: string` field on `ModelVersion`, +### 18. `currentStage: string` field on `ModelVersion`, `ModelVersionDatabricks` — `model.ts:670, 701` -- **Why weird:** Same as #18 — typed as `string`, valid values +- **Why weird:** Same as #17 — typed as `string`, valid values enumerated only in docs. Also called `currentStage` here but `stage` on request DTOs (no prefix). Inconsistent. - **Category:** 6 (misleading), 16 (type contradicts domain), 17 @@ -296,7 +282,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** "Current" is implicit (it's the *current* stage of this version). -### 20. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` +### 19. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` - **Why weird:** Three different `Activity`-shaped types each duplicate `fromStage: string | undefined`, `toStage: string | undefined`, again stringly typed. Identical doc-comments paste the same four-value @@ -304,19 +290,19 @@ is the Unity-Catalog-scoped successor. - **Category:** 16 (type contradicts domain), 12 (duplicate concept), 7 (overly verbose docs). - **Suggested name:** `fromStage: Stage`, `toStage: Stage`. -- **Rationale:** Same as #18. +- **Rationale:** Same as #17. -### 21. `Databricks` as a suffix is overused -- **Why weird:** 6 distinct type names end in `Databricks` (see #10). +### 20. `Databricks` as a suffix is overused +- **Why weird:** 6 distinct type names end in `Databricks` (see #9). Each one is a workspace-specific extension. The `Databricks` suffix appearing inside the *Databricks SDK* is tautological. - **Category:** 8 (redundant suffix), 20 (type-suffix tautology). -- **Suggested name:** See #10. -- **Rationale:** See #10. +- **Suggested name:** See #9. +- **Rationale:** See #9. ## Medium severity -### 22. `comment: string` field overloaded across types — `model.ts:213, 234, 276, 398, 487, 849, 1001, 1022, 1062` +### 21. `comment: string` field overloaded across types — `model.ts:213, 234, 276, 398, 487, 849, 1001, 1022, 1062` - **Why weird:** Same field name (`comment`) appears with three different meanings: (a) on `Activity` it is "user-provided comment associated with the activity"; (b) on `CreateComment` it is "user- @@ -331,17 +317,17 @@ is the Unity-Catalog-scoped successor. - **Rationale:** A grep for `comment` in a calling project will return 9 unrelated meanings. -### 23. `creator: string` field on `DeleteTransitionRequest` — `model.ts:485` +### 22. `creator: string` field on `DeleteTransitionRequest` — `model.ts:485` - **Why weird:** Field doc says "Username of the user who created this request." So this is a username, not a user object. Same anti-pattern - as #17 but with a different field name. The same concept is named + as #16 but with a different field name. The same concept is named `userId` elsewhere. - **Category:** 17 (inconsistent action/identifier prefix). - **Suggested name:** `creatorUsername` (and align with `userId` -> - `userName` per #17). + `userName` per #16). - **Rationale:** Two different field names for the same concept. -### 24. `id: string` field — `model.ts:189, 266, 408, 461, 772, 789, 967, 1054, 1060` +### 23. `id: string` field — `model.ts:189, 266, 408, 461, 772, 789, 967, 1054, 1060` - **Why weird:** Bare `id` appears on `Activity`, `CommentObject`, `DeleteComment`, `DeleteRegistryWebhook`, `RegisteredModelDatabricks`, `RegistryWebhook`, `TestRegistryWebhook`, `TransitionRequest`, @@ -356,7 +342,7 @@ is the Unity-Catalog-scoped successor. remember which kind of ID this DTO wants. The wire field can stay `id`; the TS field should be specific. -### 25. `name: string` field overloaded — many — `model.ts:195, 271, 287, 314, 382, 417, 426, 438, 447, 468, 519, 531, 543, 583, 600, 647, 660, 691, 740, 759, 832, 859, 925, 946, 982, 1072, 1087, 1100` +### 24. `name: string` field overloaded — many — `model.ts:195, 271, 287, 314, 382, 417, 426, 438, 447, 468, 519, 531, 543, 583, 600, 647, 660, 691, 740, 759, 832, 859, 925, 946, 982, 1072, 1087, 1100` - **Why weird:** `name` appears on ~28 request/response types meaning "name of the registered model". Doc-comments mostly say "Name of the model" or "Registered model unique name identifier." Always the @@ -369,7 +355,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Disambiguates request structures from entity structures. -### 26. `version: string` field overloaded — `model.ts:197, 273, 419, 428, 470, 521, 533, 649, 662, 693, 834, 927, 984, 1074` +### 25. `version: string` field overloaded — `model.ts:197, 273, 419, 428, 470, 521, 533, 649, 662, 693, 834, 927, 984, 1074` - **Why weird:** Stored as a string but docs say "Model version number" (a number). Field is sometimes called `version`, sometimes `currentStage` is the contextual sibling — but never typed as a @@ -381,7 +367,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** `version` is too generic a noun for a primary key in a package. -### 27. `runId: string` field — `model.ts:294, 679, 707` +### 26. `runId: string` field — `model.ts:294, 679, 707` - **Why weird:** `runId` is the MLflow tracking run that produced the model. The package never explains this; without prior MLflow knowledge `runId` is opaque. @@ -390,7 +376,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Disambiguates from any other "run" concept in the SDK (jobs runs, etc.). -### 28. `jobId: string` on `JobSpec` — `model.ts:565` +### 27. `jobId: string` on `JobSpec` — `model.ts:565` - **Why weird:** Doc says "ID of the job that the webhook runs." This is a Databricks Jobs job ID. `jobId` is fine but lives in a model that duplicates the documentation in the comment for `CreateRegistryWebhook.jobSpec` @@ -401,7 +387,7 @@ is the Unity-Catalog-scoped successor. `CreateRegistryWebhook.jobSpec`. - **Rationale:** Doc-comment mismatch is a generator bug. -### 29. `accessToken: string` on `JobSpec` — `model.ts:569` +### 28. `accessToken: string` on `JobSpec` — `model.ts:569` - **Why weird:** Doc says "The personal access token used to authorize webhook's job runs." Shipping a PAT in a webhook config is a security red flag; field name should signal that. Compare to `secret` on @@ -413,7 +399,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Aligns with other Databricks SDK fields named `token` / `pat`. -### 30. `enableSslVerification: boolean` — `model.ts:556` +### 29. `enableSslVerification: boolean` — `model.ts:556` - **Why weird:** Doc-comment is 4 lines describing why you should never disable this. The boolean has a default (true) per the docs but the field is `boolean | undefined`. So `undefined` and `true` mean the @@ -422,7 +408,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; add `@default true` JSDoc tag. - **Rationale:** Make default-truthy fields clearer. -### 31. `authorization: string` — `model.ts:560` +### 30. `authorization: string` — `model.ts:560` - **Why weird:** "Value of the authorization header" — should probably be named `authorizationHeader` (since `authorization` looks like an abstract noun, not the actual header value). @@ -431,7 +417,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Clarifies the field stores the wire-format header value. -### 32. `event: RegistryWebhookEvent | undefined` (singular) on +### 31. `event: RegistryWebhookEvent | undefined` (singular) on `TestRegistryWebhook` — `model.ts:969` - **Why weird:** Singular `event` while every other type uses `events: RegistryWebhookEvent[]`. Inconsistent. @@ -442,7 +428,7 @@ is the Unity-Catalog-scoped successor. with `event` and document the asymmetry. - **Rationale:** Asymmetry across sibling types causes refactor errors. -### 33. `modelName: string` field on `CreateRegistryWebhook`, +### 32. `modelName: string` field on `CreateRegistryWebhook`, `ListRegistryWebhooks`, `RegistryWebhook` — `model.ts:329, 601, 827` - **Why weird:** This is the *registered model* name. Elsewhere in the same model the same concept is called `name` (on requests scoped to a @@ -453,7 +439,7 @@ is the Unity-Catalog-scoped successor. with package context — but consistent. - **Rationale:** Same concept, two names. -### 34. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, +### 33. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, 602-630, 791-815, 1102-1127` - **Why weird:** The 25-line "Events that can trigger a registry webhook" doc block is copy-pasted at least 4 times across types @@ -464,7 +450,7 @@ is the Unity-Catalog-scoped successor. signature plus a one-line description should remain. - **Rationale:** Quality-of-life for consumers reading JSDoc. -### 35. `tags?: ModelVersionTag[] | undefined` and +### 34. `tags?: ModelVersionTag[] | undefined` and `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, 719, 755, 776` - **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, @@ -475,7 +461,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Single `Tag` type with `{ key, value }`. - **Rationale:** Identical structure should have identical type. -### 36. `availableActions: ActivityAction[]` doc — `model.ts:187` +### 35. `availableActions: ActivityAction[]` doc — `model.ts:187` - **Why weird:** Field comment "Array of actions on the activity allowed for the current viewer." So `availableActions` actually means "allowed actions for current viewer", which differs from "available @@ -484,7 +470,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `allowedActions` or `permittedActions`. - **Rationale:** Encodes the viewer-permission semantics. -### 37. `systemComment: string | undefined` — `model.ts:185, 262, 1050` +### 36. `systemComment: string | undefined` — `model.ts:185, 262, 1050` - **Why weird:** The same paragraph-long doc-comment is pasted on three identical fields across three identical types. "Comment made by system, for example explaining an activity of type @@ -494,7 +480,7 @@ is the Unity-Catalog-scoped successor. consolidation via #7. - **Rationale:** Same as #7. -### 38. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` +### 37. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` - **Why weird:** Typed as `Activity[]` but the field is documented as "Open requests for this `model_versions`" — they are transition *requests* (not arbitrary activities). The reason is the @@ -504,15 +490,16 @@ is the Unity-Catalog-scoped successor. (post-rename per #7). - **Rationale:** Restores the intent. -### 39. `requests: Activity[]` on `ListTransitionRequest_Response` — +### 38. `requests: Activity[]` on list-transition-requests response — `model.ts:655` -- **Why weird:** Same problem: stored as `Activity[]` but the response - is documented as "Array of open transition requests." +- **Why weird:** Stored as `Activity[]` but the response is documented + as "Array of open transition requests." - **Category:** 6 (misleading type), 15 (generic field name). - **Suggested name:** `transitionRequests: TransitionRequest[]`. -- **Rationale:** Same as #38. +- **Rationale:** Same as #37 — type contradicts domain because of the + identical-shape problem (#7). -### 40. `request: TransitionRequest` on `CreateTransitionRequest_Response` — +### 39. `request: TransitionRequest` on create-transition-request response — `model.ts:404` - **Why weird:** Field `request` on a response is contradictory — a response holds a "request"? In context, the wrapped object is the @@ -523,23 +510,23 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Removes the "request inside a response" cognitive stumble. -### 41. `registeredModelDatabricks: RegisteredModelDatabricks` — +### 40. `registeredModelDatabricks: RegisteredModelDatabricks` — `model.ts:549` - **Why weird:** Field name *is* the type name verbatim. The `Databricks` - suffix problem (#10) cascades into the field name. + suffix problem (#9) cascades into the field name. - **Category:** 20 (type-suffix tautology). - **Suggested name:** After dropping the `Databricks` suffix from the type: `registeredModel: RegisteredModel`. Or just return the type directly without a wrapper. - **Rationale:** Reduces verbosity by removing the wrapper. -### 42. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` -- **Why weird:** Same as #41 for `ModelVersionDatabricks`. +### 41. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` +- **Why weird:** Same as #40 for `ModelVersionDatabricks`. - **Category:** 20. - **Suggested name:** `modelVersion: ModelVersion`. - **Rationale:** Same. -### 43. `getLatestVersions` / `GetLatestVersions` — `client.ts:908`, +### 42. `getLatestVersions` / `GetLatestVersions` — `client.ts:908`, `model.ts:501` - **Why weird:** The method returns *one* version per stage, not "the latest version" globally. The name reads as "give me the latest @@ -552,16 +539,16 @@ is the Unity-Catalog-scoped successor. `getLatestVersionsByStage`. - **Rationale:** Conveys the per-stage semantics. -### 44. `latestVersions: ModelVersion[]` on `RegisteredModel`, +### 43. `latestVersions: ModelVersion[]` on `RegisteredModel`, `RegisteredModelDatabricks` — `model.ts:753, 770` - **Why weird:** Plural array but the doc says "Collection of latest - model versions for each stage". Same ambiguity as #43. + model versions for each stage". Same ambiguity as #42. - **Category:** 6 (misleading), 15 (generic). - **Suggested name:** `latestVersionsByStage` (and consider returning a map keyed by stage name). - **Rationale:** Same. -### 45. `featureTableId`, `featureTableName`, `featureName` on +### 44. `featureTableId`, `featureTableName`, `featureName` on `LinkedFeature` — `model.ts:575, 577, 579` - **Why weird:** Both `featureTableId` and `featureTableName` are exposed — primary key duplication. Doc-comments are bare ("Feature @@ -572,7 +559,7 @@ is the Unity-Catalog-scoped successor. relationship. - **Rationale:** Without docs, callers won't know which to populate. -### 46. `body: string` on `TestRegistryWebhook_Response` — `model.ts:977` +### 45. `body: string` on test-registry-webhook response — `model.ts:977` - **Why weird:** Field `body` typed as `string`. Webhook test results could return any payload. `body` is too generic; could be `responseBody`. @@ -580,7 +567,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `responseBody`. - **Rationale:** Clearer pair with `statusCode`. -### 47. `statusCode: number` on `TestRegistryWebhook_Response` — +### 46. `statusCode: number` on test-registry-webhook response — `model.ts:975` - **Why weird:** Could be `httpStatusCode` for clarity (it's the HTTP status the test got back). @@ -588,7 +575,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `httpStatusCode`. - **Rationale:** Matches typical Web API vocabulary. -### 48. `archiveExistingVersions: boolean` — `model.ts:211, 999` +### 47. `archiveExistingVersions: boolean` — `model.ts:211, 999` - **Why weird:** Field documented "Specifies whether to archive all current model versions in the target stage." The word "current" appears in the doc but not the field; the boolean reads as "archive @@ -597,7 +584,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `archiveExistingVersionsInTargetStage`. - **Rationale:** Captures the location semantics. -### 49. `description: string` overloaded — `model.ts:302, 318, 358, 672, +### 48. `description: string` overloaded — `model.ts:302, 318, 358, 672, 703, 748, 768, 822, 1077, 1090, 1129` - **Why weird:** Same field on 11 types, each meaning slightly different things (registered-model description, model-version description, @@ -608,7 +595,7 @@ is the Unity-Catalog-scoped successor. clear; flag for consistency. - **Rationale:** Common across SDK; low cost to leave alone. -### 50. `secret: string` on `HttpUrlSpec` — `model.ts:558` +### 49. `secret: string` on `HttpUrlSpec` — `model.ts:558` - **Why weird:** Bare `secret` is generic; doc says it's the "Shared secret required for HMAC encoding payload." - **Category:** 1 (vague), 15 (generic). @@ -617,7 +604,7 @@ is the Unity-Catalog-scoped successor. ## Low severity -### 51. `creationTimestamp: number` — `model.ts:152, 229, 664, 696, 742, +### 50. `creationTimestamp: number` — `model.ts:152, 229, 664, 696, 742, 761, 818, 1017` - **Why weird:** Field is repeated across types with identical `Unix timestamp in milliseconds` doc. Naming OK but could be @@ -626,14 +613,14 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `createdAt`. - **Rationale:** Aligns with JS conventions; flag as observation only. -### 52. `lastUpdatedTimestamp: number` — `model.ts:159, 236, 666, 698, 744, +### 51. `lastUpdatedTimestamp: number` — `model.ts:159, 236, 666, 698, 744, 763, 820, 1024` -- **Why weird:** Same as #51; `updatedAt` is more idiomatic. +- **Why weird:** Same as #50; `updatedAt` is more idiomatic. - **Category:** 14. - **Suggested name:** `updatedAt`. -- **Rationale:** Same as #51. +- **Rationale:** Same as #50. -### 53. `statusMessage: string` — `model.ts:683, 710` +### 52. `statusMessage: string` — `model.ts:683, 710` - **Why weird:** Field name fine but doc says it's only set "if it is pending or failed", so the field is conditionally meaningful — not in the type signature. @@ -641,7 +628,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; document the conditional. - **Rationale:** Low priority. -### 54. `source: string` on `ModelVersion`, `ModelVersionDatabricks`, +### 53. `source: string` on `ModelVersion`, `ModelVersionDatabricks`, `CreateModelVersion` — `model.ts:289, 674, 704` - **Why weird:** "URI indicating the location of the source model artifacts." Just `source` is vague; `sourceUri` or `artifactUri` would @@ -650,7 +637,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `sourceUri`. - **Rationale:** Companion field is `runLink` (already specific). -### 55. `runLink: string` — `model.ts:301, 687, 720` +### 54. `runLink: string` — `model.ts:301, 687, 720` - **Why weird:** "MLflow run link - this is the exact link of the run". `runLink` is OK but `runUrl` would be more idiomatic for a URL. - **Category:** 14 (Java-style "link" vs JS "url"). @@ -658,7 +645,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** "Link" is HTML/UI vocabulary; URL is what's actually stored. -### 56. `key: string` and `value: string` on `ModelVersionTag`, +### 55. `key: string` and `value: string` on `ModelVersionTag`, `RegisteredModelTag` — `model.ts:733, 735, 782, 784` - **Why weird:** `key`/`value` are extremely generic and reused across many SDK packages. Not really wrong, just observation. @@ -667,7 +654,7 @@ is the Unity-Catalog-scoped successor. preferred). - **Rationale:** Trade-off vs verbosity. Low priority. -### 57. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:586, 593, +### 56. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:586, 593, 633, 642, 877, 893, 905, 921` - **Why weird:** Consistent across the package — good. Noted for completeness. @@ -675,7 +662,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** No change. - **Rationale:** Observation. -### 58. `orderBy: string[]` on `SearchModelVersions`, +### 57. `orderBy: string[]` on `SearchModelVersions`, `SearchRegisteredModels` — `model.ts:884, 911` - **Why weird:** Stringly-typed sort spec; doc says values are like `"name DESC"` or `"version ASC"`. Could be a typed `Sort` struct, but @@ -684,14 +671,14 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; flag the stringly-typed pattern. - **Rationale:** Matches REST API conventions; low cost. -### 59. `filter: string` on `SearchModelVersions`, +### 58. `filter: string` on `SearchModelVersions`, `SearchRegisteredModels` — `model.ts:875, 903` -- **Why weird:** Stringly-typed search filter (SQL-like). Same as #58. +- **Why weird:** Stringly-typed search filter (SQL-like). Same as #57. - **Category:** 16. - **Suggested name:** No change; could be `filterExpression`. - **Rationale:** REST convention. -### 60. `newName: string` on `RenameRegisteredModel` — `model.ts:862` +### 59. `newName: string` on `RenameRegisteredModel` — `model.ts:862` - **Why weird:** Field doc says "If provided, updates the name for this `registered_model`." Slightly confusing because `RenameRegisteredModel` is *the* rename operation — "if provided" implies optional, but rename @@ -701,7 +688,7 @@ is the Unity-Catalog-scoped successor. omission is a no-op. - **Rationale:** Optional-but-required-in-practice fields confuse users. -### 61. `name: string` on `RenameRegisteredModel` — `model.ts:859` +### 60. `name: string` on `RenameRegisteredModel` — `model.ts:859` - **Why weird:** Field doc "Registered model unique name identifier." - duplicates the type name semantics. Could be `currentName` to pair with `newName` for clarity. @@ -709,7 +696,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `currentName` + `newName`. - **Rationale:** Symmetry improves readability of rename payloads. -### 62. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhook` — +### 61. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhook` — `model.ts:369-371` - **Why weird:** Doc-comment on `jobSpec` (line 371) is literally just "ID of the job that the webhook runs." — wrong, since `jobSpec` is a @@ -720,14 +707,7 @@ is the Unity-Catalog-scoped successor. ## Observations -### 63. `*_Response` underscore lint-disable density -The model file has 33 `*_Response` types, each carrying an -`eslint-disable @typescript-eslint/naming-convention` comment to permit -the underscore. This is the highest disable-count-per-type density I've -seen — a sign the generator's proto idioms are fighting TS conventions. -- **Category:** Observation. - -### 64. Both `modelregistry` and `registeredmodels` exist as packages +### 62. Both `modelregistry` and `registeredmodels` exist as packages The user instruction calls out this duplication. Cross-package overlap: - `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` (registeredmodels) — same concept, different names. @@ -745,7 +725,7 @@ The user instruction calls out this duplication. Cross-package overlap: Documentation does not direct users to one or the other. - **Category:** 12 (duplicate concepts — across packages). -### 65. Action-verb conventions in `Client` +### 63. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -754,7 +734,7 @@ reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). -### 66. Acronym casing inside doc-comments +### 64. Acronym casing inside doc-comments `MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` (`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md index 9cca94ee..60a0cc80 100644 --- a/.agent/naming-audit/modelservingdebug.md +++ b/.agent/naming-audit/modelservingdebug.md @@ -4,12 +4,12 @@ **Package name:** `@databricks/sdk-modelservingdebug` **Versions audited:** v1 **Inferred domain:** Diagnostic / troubleshooting endpoints carved out of the Model Serving API. Three HTTP GETs hanging off `/api/2.0/serving-endpoints/{name}`: `GET /metrics` returns a Prometheus/OpenMetrics text blob (streamed body), `GET /served-models/{servedModelName}/logs` returns the most recent server stdout lines, and `GET /served-models/{servedModelName}/build-logs` returns the served-entity environment build logs. -**Total weird names flagged:** 22 +**Total weird names flagged:** 21 ## Summary | Severity | Count | | --- | --- | -| High | 8 | +| High | 7 | | Medium | 7 | | Low | 6 | | Observation | 1 | @@ -178,52 +178,21 @@ suggestion below. `patchInferenceEndpointTags`. None of them prefix the noun with the output format. -### 3. `ExportMetricsResponse` lives in a debug package but the JSDoc says "Proto version of com.databricks.rpc.HttpOverRpcResponse" — `model.ts:5-15` -- **Why weird:** This type name claims to be a "metrics" response, - but its JSDoc reveals it's a generic - `com.databricks.rpc.HttpOverRpcResponse` envelope — a wire-level - HTTP tunnelling primitive whose only field is `contents: ReadableStream`. - The Java/proto plumbing (UnaryRpcService, JettyRPC, - `CustomHandlingForHttpOverRpcProtoResponse`) is leaking into the - user-facing TS surface. Consumers do not need to know that - Databricks' RPC layer special-cases HTTP-over-RPC. -- **Category:** 14 (Go/Java/proto-style names leaking into TS), 6 - (misleading — the comment describes RPC, not metrics), 1 (vague — - `ExportMetricsResponse` could mean "response from any export-metrics - call", which is exactly what `HttpOverRpcResponse` is at the proto - layer). +### 3. `ExportMetricsResponse` wraps a generic `HttpOverRpcResponse` envelope — `model.ts:5-15` +- **Why weird:** This type advertises itself as a "metrics" response, + but its only field is `contents: ReadableStream` — the generic + HTTP-over-RPC envelope shape. A reader expecting structured metrics + fields gets an opaque stream, and the type name does not warn them. +- **Category:** 6 (misleading — name says "metrics", shape says + "raw body"), 1 (vague — `ExportMetricsResponse` could mean any + metrics export call). - **Suggested name:** `EndpointMetrics` with a single field `body: - ReadableStream` (or `text: string` after consumption). Strip the - proto JSDoc entirely; the consumer should be told "Prometheus or - OpenMetrics text in the body stream" instead. The doc warning - "Don't add/modify the fields before being aware of the implications" - is a server-team note that does not belong in a public TS SDK. + ReadableStream` (or `text: string` after consumption). Document + that the body is Prometheus/OpenMetrics text. - **Rationale:** Public SDK types should describe the user's mental - model ("here are the metrics"), not the server's wire envelope. - -### 4. `GetServedModelBuildLogs_Response` and `GetServedModelLogs_Response` underscore-suffixed pseudo-nested types — `model.ts:32,45` -- **Why weird:** The trailing `_Response` with an underscore is a - proto convention encoding nested message names - (`GetServedModelLogs.Response`). TypeScript has no nesting at the - type level, so the generator produced `GetServedModelLogs_Response`. - Each occurrence has to carry an - `eslint-disable-next-line @typescript-eslint/naming-convention -- - Proto-style nested message name.` directive (lines 31, 44, 50, 60). - The eslint suppression count alone (4 in a 69-line file) is a - smell. -- **Category:** 4 (underscores in TS identifiers), 14 (proto-style - names in TS). -- **Suggested name:** `ServedModelBuildLogs`, `ServedModelLogs` - (request types stay `GetServedModelBuildLogsRequest`, - `GetServedModelLogsRequest`, see #5). The generator should be - fixed once, project-wide. -- **Rationale:** `_Response` with an underscore is rule-4 violation - per the audit checklist; the broader rule is "underscores belong - to proto messages, not TS identifiers" — Google TypeScript Style - Guide § Identifiers - (https://google.github.io/styleguide/tsguide.html#identifiers). - -### 5. `name` field on every request — `model.ts:21,26,39` + model ("here are the metrics"), not double as a generic envelope. + +### 4. `name` field on every request — `model.ts:21,26,39` - **Why weird:** All three request types have `name?: string` and the JSDoc has to spell out "The name of the serving endpoint" each time. Bare `name` is the most generic identifier possible — readers without @@ -243,7 +212,7 @@ suggestion below. makes the pairing with `servedModelName` parallel (`endpointName` + `servedModelName`). -### 6. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:69,96,124` +### 5. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:69,96,124` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — meaning if the caller @@ -262,7 +231,7 @@ suggestion below. (https://google.aip.dev/122) which mandates path parameters be required. -### 7. `servedModelName` doc echoes the field name three times — `model.ts:27-28,40-41` +### 6. `servedModelName` doc echoes the field name three times — `model.ts:27-28,40-41` - **Why weird:** JSDoc on `GetServedModelBuildLogs.servedModelName` reads "The name of the served model that build logs will be retrieved for. This field is required." The field name already @@ -280,7 +249,7 @@ suggestion below. identifier + JSDoc; the doc carrying no information beyond what the name says is a footgun for consumers. -### 8. `GetServedModelLogs_Response.logs: string` is a single blob — `model.ts:47` +### 7. `GetServedModelLogs_Response.logs: string` is a single blob — `model.ts:47` - **Why weird:** The field is named `logs` (plural) but typed as a single `string`. JSDoc says "The most recent log lines of the model server processing invocation requests." So it's many log *lines* @@ -299,7 +268,7 @@ suggestion below. ## Medium severity -### 9. `GetServedModelBuildLogs.name` clashes with `GetServedModelBuildLogs.servedModelName` — `model.ts:26,28` +### 8. `GetServedModelBuildLogs.name` clashes with `GetServedModelBuildLogs.servedModelName` — `model.ts:26,28` - **Why weird:** Two name fields on one struct: `name` (endpoint name) and `servedModelName` (served model name). The bare `name` looks like *the* name of the request entity (which a reader would assume is the @@ -312,7 +281,7 @@ suggestion below. - **Rationale:** When two `*Name` fields exist on one struct, neither should be bare `name`. -### 10. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:16` +### 9. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:16` - **Why weird:** The only field is `contents?: ReadableStream | undefined`. Web Fetch standard (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own @@ -326,7 +295,7 @@ suggestion below. - **Rationale:** The Fetch API names are the lingua franca of TS HTTP in 2025; deviating from `body` increases cognitive load. -### 11. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:65-68` +### 10. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:65-68` - **Why weird:** The method name says `EndpointMetrics`, the response type says `ExportMetricsResponse` (no `Endpoint`). Inconsistent qualifier between method and return type. A reader greping for @@ -341,7 +310,7 @@ suggestion below. - **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. -### 12. `Get*` prefix on three of three methods — `client.ts:65,92,120` +### 11. `Get*` prefix on three of three methods — `client.ts:65,92,120` - **Why weird:** Every method here is a GET. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations @@ -358,7 +327,7 @@ suggestion below. (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. -### 13. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:92,120` +### 12. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:92,120` - **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a @@ -375,7 +344,7 @@ suggestion below. and `getServedModelBuildLogs` is the special case; the API doesn't advertise the asymmetry. -### 14. `GetServedModelLogs.servedModelName` doc says "The name of the served model that logs will be retrieved for" — passive voice — `model.ts:41` +### 13. `GetServedModelLogs.servedModelName` doc says "The name of the served model that logs will be retrieved for" — passive voice — `model.ts:41` - **Why weird:** Passive voice "that logs will be retrieved for" reads like a phrase translated from a proto comment. Active voice is shorter: "The served model whose logs to retrieve." Pure JSDoc @@ -386,7 +355,7 @@ suggestion below. - **Suggested name:** No rename; rewrite JSDoc in active voice. - **Rationale:** API surface clarity. Not blocking. -### 15. `PACKAGE_SEGMENT` const is unsized — `client.ts:34-37` +### 14. `PACKAGE_SEGMENT` const is unsized — `client.ts:34-37` - **Why weird:** SCREAMING_SNAKE_CASE in TS is a Go/Python carryover. Google TS Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) @@ -402,7 +371,7 @@ suggestion below. ## Low severity -### 16. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` +### 15. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` - **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` @@ -416,8 +385,8 @@ suggestion below. that survives review only because nobody wants to argue with the framework. -### 17. `Options` type aliased to internal options shape — `utils.ts:3,30` -- **Why weird:** Same as #16 but for `Options`. `Options` is generic +### 16. `Options` type aliased to internal options shape — `utils.ts:3,30` +- **Why weird:** Same as #15 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen @@ -429,7 +398,7 @@ suggestion below. - **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. -### 18. `userAgent` is built once in the constructor and never refreshed — `client.ts:46,60` +### 17. `userAgent` is built once in the constructor and never refreshed — `client.ts:46,60` - **Why weird:** Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If @@ -440,16 +409,16 @@ suggestion below. freeze in the JSDoc on line 43-46. - **Rationale:** Worth a comment; not a rename target. -### 19. `host` is normalised by trailing-slash strip — `client.ts:52` +### 18. `host` is normalised by trailing-slash strip — `client.ts:52` - **Why weird:** `this.host = options.host.replace(/\/$/, '');` silently rewrites the input. The field name `host` doesn't tell the consumer "we normalise this to no trailing slash". If a debug log later prints `client.host`, it won't match what was passed in. - **Category:** Observation, 6 (mildly misleading). - **Suggested name:** No rename. Add a JSDoc note. -- **Rationale:** Same pattern as #18; cross-package. +- **Rationale:** Same pattern as #17; cross-package. -### 20. `info` local var in the constructor — `client.ts:54,56,57,58,60` +### 19. `info` local var in the constructor — `client.ts:54,56,57,58,60` - **Why weird:** `let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 @@ -461,7 +430,7 @@ suggestion below. `createDefault` factory and the SDK convention). - **Rationale:** Local-scope, low-impact rename. Cross-package. -### 21. `pkgJson` import alias for package.json — `client.ts:19,35,36` +### 20. `pkgJson` import alias for package.json — `client.ts:19,35,36` - **Why weird:** `import pkgJson from '../../package.json' with {type: 'json'};`. The alias name `pkgJson` is cryptic; readers who don't know `pkg` is "package" will guess. The line is unique-per-package @@ -472,7 +441,7 @@ suggestion below. ## Observation -### 22. `getReader()` chunk-accumulator in `readAll` is a hot-path candidate — `utils.ts:46-62` +### 21. `getReader()` chunk-accumulator in `readAll` is a hot-path candidate — `utils.ts:46-62` - **Why weird:** `readAll` is the buffering implementation used by every method (including `getServedModelLogs` which can return many KB of text). The chunk-collection loop allocates many intermediate diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md index 5a65789d..c4ee5aaa 100644 --- a/.agent/naming-audit/modelservingmanagement.md +++ b/.agent/naming-audit/modelservingmanagement.md @@ -3,14 +3,14 @@ **Path:** `packages/modelservingmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** "Serving endpoint" management — CRUD over inference (model-serving) endpoints, plus a parallel "PT" (provisioned-throughput) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Sibling packages: `modelservingdebug` (logs/metrics), `modelservingquery` (inference). Three packages share the noun "serving endpoint" with no cross-package alignment of how the noun is rendered (this package: `InferenceEndpoint`; debug: `Endpoint`; query: `Endpoint`). -**Total weird names flagged:** 47 +**Total weird names flagged:** 41 ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 18 | -| Low | 11 | +| High | 11 | +| Medium | 16 | +| Low | 9 | | Observation | 5 | ## High severity @@ -41,9 +41,9 @@ ### 5. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` - **Why weird:** This is the *only* type named `ServingEndpoint*`. Every other type in the file uses `InferenceEndpoint*`. Either this enum should be `InferenceEndpointPermissionLevel` (to match the rest of the package), or the rest of the package should be `ServingEndpoint*` (to match the product and wire). The `Detailed` infix is also suspect — the enum lives on `InferenceEndpointDetailed.permissionLevel`, so the type-name says "this enum belongs to InferenceEndpointDetailed", but a `permissionLevel` of `CAN_VIEW` is *not* detailed any differently from a non-detailed view; the enum applies to the resource, not to the response shape. So `Detailed` is leaking the response-DTO name into the enum name. -- **Category:** 17 (inconsistent terminology), 7 (overly verbose), 14 (Go/proto-style nested-name leakage). +- **Category:** 17 (inconsistent terminology), 7 (overly verbose). - **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. -- **Rationale:** Enum names that include the response-DTO shape (`Detailed`) are proto-buf artefacts. In TS, the enum represents a concept, not the message it appears in. +- **Rationale:** Enum names that include the response-DTO shape (`Detailed`) tangle the message identity into the type identity. In TS, the enum represents a concept, not the message it appears in. ### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:487` - **Why weird:** `httpRequest` on a `Client` for *model-serving management* is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. @@ -52,8 +52,8 @@ - **Rationale:** A method called `httpRequest` on a `ServingEndpointsClient` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. ### 7. `ExternalFunctionRequest` doc says "Simple Proto message for testing" — `src/v1/model.ts:425` -- **Why weird:** Public type carries the JSDoc comment "Simple Proto message for testing". This is an internal proto-buf comment that leaked into the public TS surface. Either the type is for testing (in which case it should not be exported) or it is production (in which case the doc lies). Given it is wired to a real REST URL and exported via `index.ts:46`, the doc is a lie. -- **Category:** 6 (misleading — public doc text contradicts the exported reality), 14 (proto/Go-style leakage). +- **Why weird:** Public type carries the JSDoc comment "Simple Proto message for testing". Either the type is for testing (in which case it should not be exported) or it is production (in which case the doc lies). Given it is wired to a real REST URL and exported via `index.ts:46`, the doc is a lie. +- **Category:** 6 (misleading — public doc text contradicts the exported reality). - **Suggested name:** Fix the JSDoc: "Request for `Client.httpRequest`: invoke an external service through a UC Connection." Keep type name `ExternalFunctionRequest` for now (paired with the rename in #6). - **Rationale:** Doc bugs on exported identifiers are as serious as the identifier itself. @@ -99,41 +99,9 @@ - **Suggested name:** Mark `servedModelName` `@deprecated`; doc `servedEntityName` properly. - **Rationale:** Triple bug: undocumented field, duplicate concept, no deprecation marker. -### 12. `_Response` proto-style nested-message underscore in TS identifiers — `src/v1/model.ts:367, 686, 800, 882, 930, 1041` -- **Why weird:** Five identifiers carry an underscore mid-name to encode "this is a nested message": - - `DeleteInferenceEndpoint_Response` - - `ListInferenceEndpoints_Response` - - `PatchInferenceEndpointTags_Response` - - `PutInferenceEndpointAiGateway_Response` - - `PutInferenceEndpointRateLimits_Response` - - `UpdateInferenceEndpointNotifications_Response` - - `ServedModel_EnvironmentVarsEntry` (line 1000-1011) — also underscored. - - `ExternalFunctionRequest_HttpMethod` enum (line 28-36) — also underscored. - - `InferenceEndpointState_ConfigUpdateState` (line 38-45) — also underscored. - - `InferenceEndpointState_ReadyState` (line 47-52) — also underscored. - - Each carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment. The underscore is a hard violation of every TS style guide (Google TS Style Guide §5.3: "Use camelCase, no underscores"; this is precisely the case the rule prohibits). -- **Category:** 4 (underscores in TS identifiers), 14 (proto-style identifiers leaking into TS). -- **Suggested name:** Drop the underscore. Use intercap PascalCase: `DeleteInferenceEndpointResponse`, `ListInferenceEndpointsResponse`, `ExternalFunctionRequestHttpMethod`, `InferenceEndpointStateConfigUpdateState`, `InferenceEndpointStateReadyState`, `ServedModelEnvironmentVarsEntry`. The eslint-disable comments are a tell that the convention is wrong: 10+ exemptions across the file means the convention is being broken systematically. -- **Rationale:** The eslint rule the comments disable is the *Databricks TypeScript style*. Either the rule is wrong (in which case fix the rule) or the names are wrong (in which case fix the names); the current "ten exemptions" state is the worst of both worlds. - -### 13. `_UNSPECIFIED` sentinel enum values across five enums — `src/v1/model.ts:6, 13, 30, 40, 49` -- **Why weird:** Five enums each declare a `*_UNSPECIFIED` member as the zero value: - - `Behavior.BEHAVIOR_UNSPECIFIED` - - `ServedModelDeploymentState.DEPLOYMENT_UNKNOWN` (variant: uses `UNKNOWN` not `UNSPECIFIED`!) - - `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED` - - `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED` - - `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED` - - `ServingEndpointDetailedPermissionLevel` — *no* unspecified member (the only enum without one). - - These are proto-buf zero-value placeholders. TS uses `undefined` for "not set"; the sentinel value is redundant. Worse, two different conventions exist (`*_UNSPECIFIED` vs `DEPLOYMENT_UNKNOWN`) — there is no even consistency among the unspecified members themselves. -- **Category:** 14 (proto/Go-style names not idiomatic in TS), 18 (long enum values), 17 (inconsistent `UNSPECIFIED`/`UNKNOWN`). -- **Suggested name:** Drop the `*_UNSPECIFIED` and `*_UNKNOWN` zero-values; rely on `field?: EnumType | undefined`. If kept, normalize all to one convention (`UNSPECIFIED` per AIP-126: https://google.aip.dev/126). -- **Rationale:** Sentinel zero-values exist in TS only to round-trip proto-buf default-zero semantics, which the wire JSON does not need. - ## Medium severity -### 14. Redundant enum prefixes — `src/v1/model.ts:5-52` +### 12. Redundant enum prefixes — `src/v1/model.ts:5-52` - **Why weird:** Three enums duplicate the enum name in every value: - `Behavior.BEHAVIOR_UNSPECIFIED` (line 6) - `ServedModelDeploymentState.DEPLOYMENT_*` (lines 13-19) — six values, every one starts with `DEPLOYMENT_`. @@ -146,19 +114,33 @@ - **Suggested name:** Drop the redundant prefix: `Behavior.UNSPECIFIED`, `ServedModelDeploymentState.CREATING/RECOVERING/READY/FAILED/ABORTED/STOPPED`, `HttpMethod.GET/POST/...` (already correct for non-UNSPECIFIED), `ConfigUpdateState.NOT_UPDATING/IN_PROGRESS/...`, `ReadyState.READY/NOT_READY`. - **Rationale:** `ServedModelDeploymentState.DEPLOYMENT_READY` is twelve characters of redundant prefix per value. -### 15. `ServedModelDeploymentState` enum name contains `Deployment` AND values are `DEPLOYMENT_*` AND it lives on `ServedModelState.deployment` — `src/v1/model.ts:12, 1025-1028` +### 13. `*_UNSPECIFIED` / `*_UNKNOWN` sentinel zero-values inconsistent — `src/v1/model.ts:6, 13, 30, 40, 49` +- **Why weird:** Five enums each declare a zero-value sentinel: + - `Behavior.BEHAVIOR_UNSPECIFIED` + - `ServedModelDeploymentState.DEPLOYMENT_UNKNOWN` (variant: uses `UNKNOWN` not `UNSPECIFIED`!) + - `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED` + - `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED` + - `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED` + - `ServingEndpointDetailedPermissionLevel` — *no* unspecified member (the only enum without one). + + TS uses `undefined` for "not set"; the sentinel value is redundant. Worse, two different conventions exist (`*_UNSPECIFIED` vs `DEPLOYMENT_UNKNOWN`) — there is no even consistency among the unspecified members themselves. +- **Category:** 17 (inconsistent `UNSPECIFIED`/`UNKNOWN`), 18 (long enum values). +- **Suggested name:** Drop the zero-value sentinels; rely on `field?: EnumType | undefined`. If kept, normalize all to one convention (`UNSPECIFIED` per AIP-126: https://google.aip.dev/126). +- **Rationale:** Sentinel zero-values exist only to round-trip default-zero semantics, which the wire JSON does not need. + +### 14. `ServedModelDeploymentState` enum name contains `Deployment` AND values are `DEPLOYMENT_*` AND it lives on `ServedModelState.deployment` — `src/v1/model.ts:12, 1025-1028` - **Why weird:** Triple redundancy: the type is `ServedModelDeploymentState`, the field is `ServedModelState.deployment: ServedModelDeploymentState`, the values are `DEPLOYMENT_*`. At a call site: `state.deployment === ServedModelDeploymentState.DEPLOYMENT_READY` — the word "deployment" appears three times. - **Category:** 2 (redundant enum prefix), 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). - **Suggested name:** Drop `Deployment` from the enum name (`ServedModelState`); drop `DEPLOYMENT_` from values. Field becomes `state.deployment === ServedModelState.READY`. But that collides with the *type* name `ServedModelState` (which wraps both `deployment` and `deploymentStateMessage`). Hence: rename type `ServedModelState` → `ServedModelDeployment`, and enum `ServedModelDeploymentState` → `DeploymentState`. Now: `served.state.deployment === DeploymentState.READY`. Clean. - **Rationale:** The current names tangle three concepts in a way that resists reading. -### 16. `InferenceEndpointState_ConfigUpdateState` enum — triple-encoded — `src/v1/model.ts:38-45` -- **Why weird:** Two-level proto-style nesting (`InferenceEndpointState_ConfigUpdateState`) with redundant value prefixes (`CONFIG_UPDATE_STATE_UNSPECIFIED`) — see #12, #13, #14. Used as `state.configUpdate: InferenceEndpointState_ConfigUpdateState` (line 660). Call site: `inferenceEndpoint.state.configUpdate === InferenceEndpointState_ConfigUpdateState.UPDATE_FAILED` — 78 characters to ask "is it failed?". -- **Category:** 4, 14, 18 (combo of all three). -- **Suggested name:** Top-level enum `ConfigUpdateState`. Values without prefix: `NOT_UPDATING | IN_PROGRESS | UPDATE_FAILED | UPDATE_CANCELED`. (Note `UPDATE_FAILED` keeps the `UPDATE_` because there are multiple state-like enums; otherwise just `FAILED`.) -- **Rationale:** Cuts the call-site length by half. +### 15. `InferenceEndpointState_ConfigUpdateState` redundant value prefixes — `src/v1/model.ts:38-45` +- **Why weird:** Redundant value prefixes (`CONFIG_UPDATE_STATE_UNSPECIFIED`) — see #12, #13. Used as `state.configUpdate: InferenceEndpointState_ConfigUpdateState` (line 660). Call site: `inferenceEndpoint.state.configUpdate === InferenceEndpointState_ConfigUpdateState.UPDATE_FAILED` — long to ask "is it failed?". +- **Category:** 2 (redundant enum prefix), 18 (long enum values). +- **Suggested name:** Values without prefix: `NOT_UPDATING | IN_PROGRESS | UPDATE_FAILED | UPDATE_CANCELED`. (Note `UPDATE_FAILED` keeps the `UPDATE_` because there are multiple state-like enums; otherwise just `FAILED`.) +- **Rationale:** Cuts the call-site length substantially. -### 17. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:377, 393, 411` +### 16. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:377, 393, 411` - **Why weird:** Three types describe "the config of a serving endpoint": - `EndpointCoreConfig`: input shape (`servedEntities: ServedModel[]`, `servedModels: ServedModel[]`, `trafficConfig`, `autoCaptureConfig`). - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. @@ -169,7 +151,7 @@ - **Suggested name:** Either (a) collapse into one type with optional fields, or (b) give the types names that reflect their *purpose*: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). - **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. -### 18. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:580, 609` +### 17. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:580, 609` - **Why weird:** Two near-duplicate types: - `InferenceEndpoint` (line 580-607): used in `ListInferenceEndpoints_Response.endpoints`. Has 13 fields. - `InferenceEndpointDetailed` (line 609-646): returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. Has 18 fields. @@ -179,13 +161,13 @@ - **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. - **Rationale:** Currently consumers writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. -### 19. `ServedModelLite` lite-variant — `src/v1/model.ts:1013-1023` -- **Why weird:** Same pattern as #18 at the entity level. `ServedModel` (line 960) has 21 fields. `ServedModelLite` (line 1013-1023) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). +### 18. `ServedModelLite` lite-variant — `src/v1/model.ts:1013-1023` +- **Why weird:** Same pattern as #17 at the entity level. `ServedModel` (line 960) has 21 fields. `ServedModelLite` (line 1013-1023) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). - **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). - **Suggested name:** `ServedEntitySummary` (paired with #2 type rename). - **Rationale:** Inconsistent suffix convention across the file. "Lite" is also an LLM-era term that clashes with the OpenAI/Anthropic-flavoured product space. -### 20. `Pt` abbreviation everywhere — `src/v1/client.ts:137, 162, 415, 440` and `src/v1/model.ts:295, 837, 843, 937` +### 19. `Pt` abbreviation everywhere — `src/v1/client.ts:137, 162, 415, 440` and `src/v1/model.ts:295, 837, 843, 937` - **Why weird:** `Pt` is short for "provisioned throughput". The full term ("provisioned throughput") *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`), but the request/response *types* use the abbreviation (`CreatePtEndpoint`, `PutPtEndpointConfig`, `PtEndpointCoreConfig`, `PtServedModel`). So the public surface has: - `client.createProvisionedThroughputInferenceEndpoint(req: CreatePtEndpoint)` — method-full, type-abbreviated. - URL: `/api/2.0/serving-endpoints/pt` — wire-abbreviated. @@ -195,7 +177,7 @@ - **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpoint`, `PutProvisionedThroughputEndpointConfig`, etc. — long but searchable) or contract all (`createPtEndpoint`, `putPtEndpointConfig` — short but cryptic). Pick one. The current half-and-half is the worst option. - **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). -### 21. `CreatePtEndpoint` method-type asymmetry with `CreateInferenceEndpoint` — `src/v1/model.ts:272, 295` +### 20. `CreatePtEndpoint` method-type asymmetry with `CreateInferenceEndpoint` — `src/v1/model.ts:272, 295` - **Why weird:** Sister request types: - `CreateInferenceEndpoint` (full name). - `CreatePtEndpoint` (abbreviated). @@ -205,7 +187,7 @@ - **Suggested name:** `CreateServingEndpoint` and `CreateProvisionedThroughputServingEndpoint` (paired with #1). - **Rationale:** Sibling request types should differ only in the qualifier that actually differs. -### 22. `PutInferenceEndpointConfig` vs `PutPtEndpointConfig` — request shape divergence — `src/v1/model.ts:906, 937` +### 21. `PutInferenceEndpointConfig` vs `PutPtEndpointConfig` — request shape divergence — `src/v1/model.ts:906, 937` - **Why weird:** Two "put endpoint config" requests: - `PutInferenceEndpointConfig`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). - `PutPtEndpointConfig`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). @@ -215,13 +197,13 @@ - **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. - **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. -### 23. `PatchInferenceEndpointTags.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:792-799` +### 22. `PatchInferenceEndpointTags.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:792-799` - **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. That semantics is fine, but the field name does not convey it. - **Category:** 6 (misleading), 15 (generic field name). - **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). - **Rationale:** When the element type changes, the field name should change too. -### 24. `endpointUrl` field domain ambiguity — `src/v1/model.ts:634, 332` +### 23. `endpointUrl` field domain ambiguity — `src/v1/model.ts:634, 332` - **Why weird:** `endpointUrl` appears twice: - `InferenceEndpointDetailed.endpointUrl` (line 634): "Endpoint invocation url if route optimization is enabled for endpoint." - `DataPlaneInfo.endpointUrl` (line 332): "The URL of the endpoint for this operation in the dataplane." @@ -231,7 +213,7 @@ - **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). - **Rationale:** A consumer JOINing the two by `endpointUrl` field name will mismatch them. -### 25. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:581-596, 610-625` +### 24. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:581-596, 610-625` - **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." @@ -241,19 +223,19 @@ - **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. - **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources (e.g. logs that include a `name` that is something else entirely). -### 26. Waiter classes have asymmetric naming — `src/v1/client.ts:515, 595, 675, 755` +### 25. Waiter classes have asymmetric naming — `src/v1/client.ts:515, 595, 675, 755` - **Why weird:** Four waiter classes: - `CreateInferenceEndpointWaiter` - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters — the longest exported class in the file) - `PutInferenceEndpointConfigWaiter` - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) - Two problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #20 where the type is `Pt`). Sibling request types should differ only in the qualifier that actually differs. + Two problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #19 where the type is `Pt`). Sibling request types should differ only in the qualifier that actually differs. - **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). - **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. - **Rationale:** Four exported waiter classes, each 30+ characters long, each containing five+ identical method-name prefixes that grep the same way as the methods themselves. -### 27. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:571-592, 651-672, 731-752, 811-832` +### 26. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:571-592, 651-672, 731-752, 811-832` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -264,90 +246,74 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 28. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:72` +### 27. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:72` - **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. - **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). - **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). - **Rationale:** Minor; internal. -### 29. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:943-950, 93-107` -- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:383 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #17: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. +### 28. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:943-950, 93-107` +- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:383 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #16: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. - **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). - **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimits*` types `@deprecated` in JSDoc. - **Rationale:** Same pattern repeated; same fix. ## Low severity -### 30. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` +### 29. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` - **Why weird:** Field repeats the provider name (`ai21labs`) because the type is named `Ai21LabsConfig`. Reading `config.ai21labsApiKey` inside an `Ai21LabsConfig` is redundant — the only key here is going to be an AI21 Labs API key. Same pattern repeats for every provider config (`anthropicApiKey` inside `AnthropicConfig`, `cohereApiKey` inside `CohereConfig`, etc.). - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** `apiKey` / `apiKeyPlaintext` inside `Ai21LabsConfig`. Wire stays `ai21labs_api_key`. - **Rationale:** Compare to `OpenAiConfig.openaiApiKey` (same redundancy), `CohereConfig.cohereApiKey` (same), `AnthropicConfig.anthropicApiKey` (same), `PaLmConfig.palmApiKey` (same), `DatabricksModelServingConfig.databricksApiToken` (same). Six provider configs, six instances of the redundancy. The wire forces the prefix (`anthropic_api_key`); TS does not. -### 31. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields +### 30. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields - **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. - **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). - **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. - **Rationale:** The "must specify exactly one" constraint is invisible to the type system. -### 32. `valid_topics` / `invalid_keywords` — `src/v1/model.ts:118, 123` +### 31. `valid_topics` / `invalid_keywords` — `src/v1/model.ts:118, 123` - **Why weird:** Two list fields on `AiGuardrailParameters`. `validTopics` is the list of *allowed* topics; `invalidKeywords` is the list of *blocked* keywords. So one is a denylist, one is an allowlist. The opposite-polarity naming (`valid*` for allowlist, `invalid*` for denylist) reads correctly *only* if you read both docs. A user skimming the fields will see "valid topics" and "invalid keywords" and not realise the polarity flipped. - **Category:** 6 (misleading), 17 (inconsistent polarity). - **Suggested name:** `allowedTopics` / `blockedKeywords`. - **Rationale:** Allowlist/denylist naming convention is well-established (https://www.ncsc.gov.uk/blog-post/terminology-its-not-black-and-white). -### 33. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` — `src/v1/model.ts:371, 373` +### 32. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` — `src/v1/model.ts:371, 373` - **Why weird:** Field name reads as an event handler (`onUpdateSuccess` is a JS convention for "callback when update succeeds"). But the field is a `string[]` of email addresses. Not a callback. The `on*` prefix is borrowed from JS event-handler-naming and is misleading here. - **Category:** 6 (misleading — `on*` implies callback). - **Suggested name:** `notifyOnUpdateSuccess` / `notifyOnUpdateFailure` (verb), or `updateSuccessRecipients` / `updateFailureRecipients` (noun). - **Rationale:** `on*` in a JS context is a strong signal of "event handler"; using it for email lists violates that signal. -### 34. `Route.servedModelName` / `servedEntityName` — already flagged in #11 +### 33. `Route.servedModelName` / `servedEntityName` — already flagged in #11 - **Why weird:** Cross-reference. -### 35. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +### 34. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` - **Why weird:** Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added (e.g. `mistralConfig`), the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary (#9). This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. - **Category:** Observation / 12. - **Suggested name:** No rename; flag as generator review. - **Rationale:** Names look clean; runtime is fragile. -### 36. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:456` +### 35. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:456` - **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 962). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). - **Category:** 1 (vague), 15 (generic name across types). - **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. - **Rationale:** Disambiguates from `ServedModel.name`. -### 37. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:454` +### 36. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:454` - **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. - **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). - **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. - **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. -### 38. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:977` -- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #37: a string field with a documented but unenforced enum. +### 37. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:977` +- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #36: a string field with a documented but unenforced enum. - **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). - **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). - **Rationale:** Type-narrowing fix; minor. -### 39. `instanceProfileArn` on `ServedModel` AND `AmazonBedrockConfig` — `src/v1/model.ts:181, 993` -- **Why weird:** Same field name on two unrelated types with very different semantics: - - `AmazonBedrockConfig.instanceProfileArn`: "ARN of the instance profile that the *external model* will use to access AWS resources." (Used to authenticate to AWS Bedrock.) - - `ServedModel.instanceProfileArn`: "ARN of the instance profile that the *served entity* uses to access AWS resources." (Used by the Databricks runtime serving the model.) - - Two different ARNs, two different purposes, identical field names. -- **Category:** 15 (generic field name across types), 17 (inconsistent usage). -- **Suggested name:** `bedrockInstanceProfileArn` (on `AmazonBedrockConfig`) and `servingInstanceProfileArn` (on `ServedModel`). -- **Rationale:** Disambiguation; minor since the enclosing type makes it clear in IDE. - -### 40. `FoundationModel.docs` field name — `src/v1/model.ts:523` -- **Why weird:** `docs?: string` on `FoundationModel`. The field name "docs" reads as "documentation, plural". Likely a URL or a long-form doc string. The JSDoc is empty — the whole type has only the comment "All fields are not sensitive as they are hard-coded in the system and made available to customers." (line 519). No field-level doc. -- **Category:** 1 (vague), 19 (no documentation). -- **Suggested name:** `docsUrl` (if URL) or `documentation` (if prose). -- **Rationale:** Bare `docs` is the kind of field name that survives generator passes because no human reviews each field. - ## Observations -### 41. Mixed naming convention for the same product across three sibling packages +### 38. Mixed naming convention for the same product across three sibling packages The Databricks "Serving Endpoints" product spans three packages in this SDK: - `modelservingmanagement`: types use `InferenceEndpoint*`. - `modelservingdebug`: types use `Endpoint` (e.g. `GetExportEndpointMetrics`). @@ -356,24 +322,16 @@ The Databricks "Serving Endpoints" product spans three packages in this SDK: No two packages agree on the noun. The wire uniformly uses `serving-endpoints`. SDK consumers chaining all three packages will see three different names for one concept. - **Category:** 17 (cross-package inconsistency). -### 42. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 39. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` Same as customllms #28 — every generated package carries this unused export. -### 43. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:67` +### 40. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:67` Same as customllms #24 — internal user-agent constant. -### 44. `Headers` constructor used four times in client.ts — `src/v1/client.ts:108, 145, 184, 213, ...` +### 41. `Headers` constructor used four times in client.ts — `src/v1/client.ts:108, 145, 184, 213, ...` Each method instantiates a `new Headers({'Content-Type': 'application/json'})` then `.set('User-Agent', this.userAgent)`. Naming-wise this is fine (Headers is the standard web API name), but the pattern is duplicated 11 times in the file. Not a naming bug; observation only. - **Category:** 12 (duplicate pattern across methods). -### 45. Verb-tense consistency in `Client` — observation of best practice -The client uses `create`/`delete`/`get`/`list`/`patch`/`put`/`update` plus the outlier `httpRequest` (see #6) and the four `*Waiter` factory methods. Apart from `httpRequest`, the verbs are consistent. Worth flagging as a positive. -- **Category:** 17 (reversed — explicit consistency). - -### 46. `httpRequest` is sole non-CRUD method -The client mixes serving-endpoint CRUD with one orthogonal "invoke through UC connection" operation. This is a structural smell more than a naming smell, but worth flagging because the misplaced method makes the package-level naming (`modelservingmanagement`) even less accurate. -- **Category:** Observation / 14. - ## Domain glossary - `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names, abbreviated in type names. - `ai gateway` — A Databricks-internal proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index e1adf5e2..10bf1bdf 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -11,7 +11,7 @@ **Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. -**Total weird names flagged:** 33 +**Total weird names flagged:** 31 --- @@ -28,30 +28,28 @@ | 7 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name | | 8 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked + redundant word ("Embedding Element") | | 9 | High | `model.ts` enum value | `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` | Enum value = type prefix; tautology | -| 10 | High | `model.ts` interface (×2) | `QueryEndpointInput_ExtraParamsEntry` / `QueryEndpointInput_UsageContextEntry` | Underscore in TS identifier; Go/Java-style nested-message names | -| 11 | High | `model.ts` enum values | `CHAT_MESSAGE_ROLE_UNSPECIFIED` / `QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED` / `EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED` | Long enum values (proto sentinel leak) | -| 12 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | -| 13 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | -| 14 | Medium | `model.ts` interface | `DataframeSplitInput` | Generic field names lose meaning (`index`, `columns`, `data`) | -| 15 | Medium | `model.ts` field | `QueryEndpointResponse.data` | Vague (it's the *embeddings* array, not arbitrary data) | -| 16 | Medium | `model.ts` field | `QueryEndpointResponse.object` | Reserved-word collision (`Object` is a JS built-in) | -| 17 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | -| 18 | Medium | `model.ts` field | `QueryEndpointResponse.created` | Verb-tense / underspecified ("created" timestamp typed as `number`) | -| 19 | Medium | `model.ts` field | `QueryEndpointResponse.servedModelName` | Generic name (wire form `served-model-name` with hyphen) | -| 20 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | -| 21 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | -| 22 | Medium | `model.ts` field | `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` | Type-suffix tautology — every field carries `Tokens` | -| 23 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | -| 24 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | -| 25 | Medium | `model.ts` field | `QueryEndpointInput.stop` | Reserved-word feel (verb-as-noun used as field) | -| 26 | Medium | `model.ts` field | `QueryEndpointInput.stream` | Reserved-word feel (collides with web-stream `ReadableStream`) and field is `boolean`, not a stream | -| 27 | Medium | `model.ts` field | `QueryEndpointInput.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | -| 28 | Medium | `model.ts` field | `QueryEndpointInput.usageContext` | Vague pair with `extraParams`; both `Record` | -| 29 | Medium | `model.ts` field | `QueryEndpointInput.maxTokens` | Inconsistent with wire form `max_tokens` re-exposed in marshal mapper | -| 30 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | -| 31 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | -| 32 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | -| 33 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | +| 10 | High | `model.ts` enum values | `CHAT_MESSAGE_ROLE_UNSPECIFIED` / `QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED` / `EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED` | Long enum values (proto sentinel leak) | +| 11 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | +| 12 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | +| 13 | Medium | `model.ts` interface | `DataframeSplitInput` | Generic field names lose meaning (`index`, `columns`, `data`) | +| 14 | Medium | `model.ts` field | `QueryEndpointResponse.data` | Vague (it's the *embeddings* array, not arbitrary data) | +| 15 | Medium | `model.ts` field | `QueryEndpointResponse.object` | Reserved-word collision (`Object` is a JS built-in) | +| 16 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | +| 17 | Medium | `model.ts` field | `QueryEndpointResponse.created` | Verb-tense / underspecified ("created" timestamp typed as `number`) | +| 18 | Medium | `model.ts` field | `QueryEndpointResponse.servedModelName` | Generic name (wire form `served-model-name` with hyphen) | +| 19 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | +| 20 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | +| 21 | Medium | `model.ts` field | `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` | Type-suffix tautology — every field carries `Tokens` | +| 22 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | +| 23 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | +| 24 | Medium | `model.ts` field | `QueryEndpointInput.stop` | Reserved-word feel (verb-as-noun used as field) | +| 25 | Medium | `model.ts` field | `QueryEndpointInput.stream` | Reserved-word feel (collides with web-stream `ReadableStream`) and field is `boolean`, not a stream | +| 26 | Medium | `model.ts` field | `QueryEndpointInput.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | +| 27 | Medium | `model.ts` field | `QueryEndpointInput.usageContext` | Vague pair with `extraParams`; both `Record` | +| 28 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | +| 29 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 30 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | +| 31 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | --- @@ -214,36 +212,7 @@ EMBEDDING = 'EMBEDDING', The only real enum value spells the same word that opens the enum's name. The path to use this is `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` — five "embedding"-derived tokens to express a constant. -### 10. `QueryEndpointInput_ExtraParamsEntry` / `QueryEndpointInput_UsageContextEntry` — Go/Java nested-message names - -**Location:** `src/v1/model.ts:141-151` - -**Categories:** 4 (underscores in TS identifiers), 14 (Go/Java-style names) - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface QueryEndpointInput_ExtraParamsEntry { - key?: string | undefined; - value?: string | undefined; -} - -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface QueryEndpointInput_UsageContextEntry { - key?: string | undefined; - value?: string | undefined; -} -``` - -These two types: - -1. Use underscores in their names, which requires a lint suppression on every declaration. -2. Are the proto-generated `map` entry types — they only ever appear in the wire format, never in TS user code (the marshal/unmarshal schemas correctly use `Record`). -3. Are byte-for-byte clones (`key?: string; value?: string;`). -4. Are exported from `index.ts` (line 17-18) — visible to every consumer who imports `@databricks/sdk-modelservingquery/v1`. - -They should not appear in TS at all. They are generator artefacts. - -### 11. Long enum sentinels (`*_UNSPECIFIED`) +### 10. Long enum sentinels (`*_UNSPECIFIED`) **Location:** `src/v1/model.ts:19`, `27`, `36` @@ -257,7 +226,7 @@ QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED = 'QUERY_ENDPOINT_RESPONSE_OBJECT_UNS Three enums each carry a `*_UNSPECIFIED` value whose wire form repeats the full type name. The longest is 56 characters. These are protobuf-required sentinels that have no meaning in TS — `undefined` is the natural absent value. They appear in the exhaustive list a user must handle in a `switch` over `ChatMessageRole`. The pattern is generator-wide; flag at generator. -### 12. `ExternalModelUsageElement` — misleading scope + meaningless suffix +### 11. `ExternalModelUsageElement` — misleading scope + meaningless suffix **Location:** `src/v1/model.ts:67-74` @@ -279,13 +248,13 @@ Two problems: 1. **"External" is misleading.** This type is the OpenAI-spec `usage` block, returned by Databricks Foundation Model and Databricks Provisioned Throughput endpoints — both of which are **internal** Databricks-managed models. JSDoc in `QueryEndpointResponse.usage` even says "external/foundation model", but Databricks Foundation Models are explicitly *first-party*. The "External" prefix mislabels its scope. 2. **"Element" is meaningless.** The type is the single usage block, not "an element of a list." `TokenUsage`, `Usage`, or `ModelUsage` would suffice. -Pairs with finding #22 (every field redundantly ends in `Tokens`). +Pairs with finding #21 (every field redundantly ends in `Tokens`). --- ## Medium severity -### 13. `query()` — verb-tense / reserved-word feel +### 12. `query()` — verb-tense / reserved-word feel **Location:** `src/v1/client.ts:58-81` @@ -298,7 +267,7 @@ async query(req: QueryEndpointInput, options?: CallOptions): Promise | undefined; "Extra" relative to what? The 8 other fields already on `QueryEndpointInput` are the "main" params; everything else falls through to here. `passthroughParams`, `modelParams`, or `externalParamsOverride` would be clearer. Also: typed `Record` — but OpenAI's "extra params" semantically include `top_p` (number), `presence_penalty` (number), and `tools` (array). The string-only typing forces stringification of values that should be passed through as JSON. -### 28. `QueryEndpointInput.usageContext` — vague pair +### 27. `QueryEndpointInput.usageContext` — vague pair **Location:** `src/v1/model.ts:135-138` @@ -507,26 +476,13 @@ extraParams?: Record | undefined; usageContext?: Record | undefined; ``` -Pairs with #27 (both are open-ended string maps). "Usage context" is ambiguous: usage of what? Context for what? The JSDoc says "recorded in the usage tracking table" — a clearer name would be `usageMetadata` or `trackingContext`. - -### 29. `QueryEndpointInput.maxTokens` — inconsistent wire mapping - -**Location:** `src/v1/model.ts:105-109`; mapped to wire `max_tokens` on line 332 - -**Categories:** 4 (underscores), 9 (singular/plural) - -```ts -maxTokens?: number | undefined; // TS -// → max_tokens // wire JSON -``` - -The TS form is camelCase, the wire form is snake_case (correct). The TS field is plural `maxTokens`, but it accepts a single number (the maximum *count* of tokens). Plural-counter naming is conventional in OpenAI-land, so this is a low-grade issue, but it pairs poorly with `promptTokens` / `completionTokens` / `totalTokens` (all counts of tokens, also plural — at least the package is internally consistent here). +Pairs with #26 (both are open-ended string maps). "Usage context" is ambiguous: usage of what? Context for what? The JSDoc says "recorded in the usage tracking table" — a clearer name would be `usageMetadata` or `trackingContext`. --- ## Low severity -### 30. JSDoc `/** Query a serving endpoint */` — verb tense / no period +### 28. JSDoc `/** Query a serving endpoint */` — verb tense / no period **Location:** `src/v1/client.ts:57` @@ -539,7 +495,7 @@ async query(...) { ... } Imperative verb, no terminal punctuation. Project rule (`CLAUDE.md`) requires comments to be sentences ending with a period. `/** Queries a serving endpoint. */` would match the v2-style JSDoc in other packages (`alerts/src/v2/client.ts` uses third-person singular present). -### 31. `ChatMessageRole.ASSISTANT` — incomplete enum +### 29. `ChatMessageRole.ASSISTANT` — incomplete enum **Location:** `src/v1/model.ts:17-23` @@ -556,7 +512,7 @@ export enum ChatMessageRole { Three values, but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 3 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. -### 32. `EmbeddingsV1ResponseEmbeddingElement.index` — underspecified +### 30. `EmbeddingsV1ResponseEmbeddingElement.index` — underspecified **Location:** `src/v1/model.ts:62-63` @@ -569,7 +525,7 @@ index?: number | undefined; `index` without qualification: index inside what? `responseIndex`, `embeddingIndex`, or `position` would be specific. Pairs with `V1ResponseChoiceElement.index` and `DataframeSplitInput.index` — three "index" fields with three different meanings. -### 33. `flattenQueryParams` — orphaned export with conflicting "Query" +### 31. `flattenQueryParams` — orphaned export with conflicting "Query" **Location:** `src/v1/utils.ts:123-150` @@ -592,23 +548,21 @@ Two issues: ## Observations -1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (4, 17, 20). +1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (4, 16, 19). 2. **Wire-format leakage is severe.** Wire-format names show up almost verbatim in TS: `n`, `stop`, `stream`, `logprobs`, `object`, `data`, `extra_params`, `served-model-name`, `*_UNSPECIFIED`, `EmbeddingsV1ResponseEmbeddingElement`. The Go SDK shares the smell, but Go's `query_endpoint` request becomes `QueryEndpointInput` in TS, where TS users have no way to distinguish the four valid combinations. 3. **Version-segment leak.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, and `EmbeddingsV1ResponseEmbeddingElementObject` all carry the literal string `V1` in the *type* name. The directory is already `src/v1/`. Other packages in the SDK (e.g., `alerts`) do not carry `V1`/`V2` segments in type names — those have explicit `v1` / `v2` directories instead, with the version expressed at the package-import path level. This package is inconsistent with that convention. -4. **Proto-style nested-message clones.** The two `_Entry` types (`QueryEndpointInput_ExtraParamsEntry`, `QueryEndpointInput_UsageContextEntry`) are the protobuf "map entry" wire types leaking through. They are dead code in TS — the marshal/unmarshal schemas use `Record`. They should not be exported from `index.ts`. - -5. **"Element" is the canonical empty suffix.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, `ExternalModelUsageElement` all carry the suffix `Element`. None of them are array elements in any structural sense — they are first-class types. The suffix is a Go convention for "value type inside a repeated field"; it adds noise in TS. +4. **"Element" is the canonical empty suffix.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, `ExternalModelUsageElement` all carry the suffix `Element`. None of them are array elements in any structural sense — they are first-class types. The suffix is a Go convention for "value type inside a repeated field"; it adds noise in TS. -6. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInput` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. +5. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInput` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. -7. **`utils.ts` is identical across packages.** The file is byte-for-byte the same as in `alerts/src/v1/utils.ts`, `endpoints/src/v1/utils.ts`, etc. The single domain-specific export, `flattenQueryParams`, is dead in this package. +6. **`utils.ts` is identical across packages.** The file is byte-for-byte the same as in `alerts/src/v1/utils.ts`, `endpoints/src/v1/utils.ts`, etc. The single domain-specific export, `flattenQueryParams`, is dead in this package. -8. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInput, options?: CallOptions)` would catch the missing path parameter at the type level. +7. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInput, options?: CallOptions)` would catch the missing path parameter at the type level. -9. **No streaming support despite `stream: boolean`.** `QueryEndpointInput.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. +8. **No streaming support despite `stream: boolean`.** `QueryEndpointInput.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. --- diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index d777b807..7da78441 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,7 +3,7 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 24 +**Total weird names flagged:** 22 ## Summary @@ -11,14 +11,14 @@ | --- | --- | | High | 6 | | Medium | 8 | -| Low | 6 | +| Low | 4 | | Observation | 4 | ## Summary table | # | Severity | Location | Name | Category | |---|----------|----------|------|----------| -| 1 | High | `model.ts:5-11` | `DestinationType` | 1 (vague), 2 (redundant enum prefix) | +| 1 | High | `model.ts:5-11` | `DestinationType` | 1 (vague) | | 2 | High | `model.ts:5-11` | `DestinationType.PAGERDUTY` / `MICROSOFT_TEAMS` | 3 (acronym casing inconsistency) | | 3 | High | `model.ts:8` | `DestinationType.WEBHOOK` (vs `GenericWebhookConfig`) | 6 (misleading), 12 (duplicate concept name mismatch) | | 4 | High | `model.ts:13-21` | `Config` (type) and `Config.config` (field) | 1 (vague), 9 (self-referential) | @@ -32,16 +32,16 @@ | 12 | Medium | `model.ts:73`, `:107` | `id` (UUID) | 19 (underspecified ID) | | 13 | Medium | `model.ts:118` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | | 14 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | -| 15 | Low | `model.ts:5-11` | enum values are SCREAMING_SNAKE_CASE in TS | 4 (underscores in TS identifier strings) | -| 16 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | -| 17 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | -| 18 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | -| 19 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | -| 20 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | -| 21 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 22 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | -| 23 | Obs | `index.ts:5-23` | Re-exports the verbose names verbatim, no friendlier aliases | — | -| 24 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | +| 15 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | +| 16 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | +| 17 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | +| 18 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | +| 19 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | +| 20 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 21 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 22 | Obs | `index.ts:5-23` | Re-exports the verbose names verbatim, no friendlier aliases | — | +| 23 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | +| 24 | Obs | `model.ts:47`, `:51` | `[Input-Only][Optional]` doc marker inconsistency | — | ## High severity @@ -57,8 +57,8 @@ } ``` - **Why weird:** Exported at package root as just `DestinationType`. The word "destination" is overloaded across the SDK — there is a `destination` concept in jobs (`webhook destination`), workflows (`sink destination`), and infra (`DBFS destination`). A user `import { DestinationType } from '@databricks/sdk-notificationdestinations/v1'` and then mixing it with `import { DestinationType } from '@databricks/sdk-pipelines/v1'` (if it existed) will get a name collision. Also, the values are not "destination types" but "notification channels"; the enum mixes the term-of-art ("destination" = the addressable target) with the type-of-target. Compare with `notification-destinations` REST path: the enum could be `NotificationChannel` or `NotificationDestinationKind`. -- **Category:** 1 (vague/generic), 2 (the enum prefix `Destination` is redundant with the field name `destinationType` — see also finding 14). -- **Suggested name:** `NotificationChannel` (mirrors how the Go SDK names protobuf enums for kindred resources) or, less invasive, `NotificationDestinationType`. +- **Category:** 1 (vague/generic). +- **Suggested name:** `NotificationChannel` or, less invasive, `NotificationDestinationType`. - **Rationale:** Domain-anchored enum names protect users from cross-package collisions and read better in IDE autocomplete (`NotificationChannel.SLACK` vs `DestinationType.SLACK`). ### 2. `DestinationType.PAGERDUTY` and `.MICROSOFT_TEAMS` — acronym/brand casing inconsistency — `src/v1/model.ts:9-10` @@ -73,10 +73,10 @@ - `PagerdutyConfig` (TitleCase but **not** `PagerDutyConfig`) — interface name (line 117). - `pagerduty` (wire) — JSON key (lines 155, 172, 282). - `PagerDuty` (TitleCase with internal D) — JSDoc prose only (line 118 "Integration key for PagerDuty"). - + The same applies to Microsoft Teams: `MICROSOFT_TEAMS`, `microsoftTeams` ($case), `MicrosoftTeamsConfig`, `microsoft_teams` (wire). Only the wire and JSDoc are externally fixed; the TS identifier choices `Pagerduty` (vs `PagerDuty`) and `MicrosoftTeams` (already correct) are an internal choice — and they are not consistent with the brand. The TS Style Guide is explicit: brand acronyms keep their canonical casing in identifiers (PagerDuty, GitHub, GraphQL). `Pagerduty` reads as a typo. - **Category:** 3 (acronym casing inconsistency). -- **Suggested name:** `PagerDutyConfig` (interface), `PagerDuty = 'PAGERDUTY'` (enum value can keep wire string but the **identifier** should be `PagerDuty` if mixed-case enum names were used; SCREAMING_SNAKE is wire-faithful, see finding 15). For consistency at minimum rename `PagerdutyConfig` → `PagerDutyConfig` and the `$case: 'pagerduty'` → `$case: 'pagerDuty'`. +- **Suggested name:** `PagerDutyConfig` (interface). For consistency at minimum rename `PagerdutyConfig` → `PagerDutyConfig` and the `$case: 'pagerduty'` → `$case: 'pagerDuty'`. - **Rationale:** Brand names are part of the public API surface; users reading IDE autocomplete should see `PagerDutyConfig` matching the company's own capitalisation. The cost is one schema rename across `unmarshalConfigSchema`'s discriminator strings — the wire JSON key stays `pagerduty`. ### 3. `DestinationType.WEBHOOK` corresponds to `GenericWebhookConfig` — misleading enum vs config asymmetry — `src/v1/model.ts:8`, `:42-55`, `:17` @@ -109,8 +109,8 @@ ``` - **Why weird:** The type name `Config` is one of the most generic identifiers in software. A package-root `Config` export means an app barrel re-exporting `@databricks/sdk-notificationdestinations/v1` collides instantly with any other `Config` (web framework configs, app configs, build configs, …). The user must alias it. Compounding the vagueness, the field inside `Config` is also named `config`, so you read `notificationDestination.config.config.email.addresses` — the same identifier appears twice along the path. - **Category:** 1 (vague/generic top-level name), 9 (self-referential field name). -- **Suggested name:** Rename the type to `NotificationDestinationConfig` (matches the package's domain prefix). The `$case` discriminator is a generator-specific convention (proto-loader's oneof shape) — a hand-written API would use `kind` or `type`. Flagging because it's user-visible. -- **Rationale:** Discriminated unions are first-class in TS; protobuf oneof wrappers are not. The 1:1 port philosophy preserves the wrapper for marshalling fidelity, but the *name* of the wrapper should at least not be `Config`. +- **Suggested name:** Rename the type to `NotificationDestinationConfig` (matches the package's domain prefix). +- **Rationale:** A domain-anchored type name eliminates the cross-package collision risk and the `config.config` repetition along the property path. ### 5. `PagerdutyConfig` and `pagerduty` — see #2, separate finding because the `$case` discriminant is also visible to users — `src/v1/model.ts:18`, `:117`, `:280` - **Code:** see #2. @@ -136,7 +136,7 @@ ... } ``` -- **Why weird:** The qualifier "generic" tells the user nothing concrete. It means "this is the webhook config that is *not* the Microsoft Teams webhook config" — a knowledge that requires reading the whole file. A user looking at IDE autocomplete sees `GenericWebhookConfig` and `MicrosoftTeamsConfig` side-by-side and has to guess that MS-Teams is also a webhook channel that just has more fields. The Go SDK likely also names this type `GenericWebhook` for proto symmetry, but in TS this needs better disambiguation. +- **Why weird:** The qualifier "generic" tells the user nothing concrete. It means "this is the webhook config that is *not* the Microsoft Teams webhook config" — a knowledge that requires reading the whole file. A user looking at IDE autocomplete sees `GenericWebhookConfig` and `MicrosoftTeamsConfig` side-by-side and has to guess that MS-Teams is also a webhook channel that just has more fields. - **Category:** 1 (vague — "generic" carries no positive information). - **Suggested name:** `WebhookConfig` (and rename the enum value to `GENERIC_WEBHOOK` per #3 if you want to preserve the disambiguation from the MS-Teams-webhook). Or be honest and call it `IncomingWebhookConfig` (the actual term-of-art used by Slack/Teams/Discord for this shape). - **Rationale:** "Generic" is a code smell whenever it appears in a public type name. It usually means "this is the default, but there might be variants" — and TypeScript already has `extends`, intersections, and unions for variants. If the shape is the default, drop the qualifier; if there are real variants, name them after what makes them different (`AuthenticatedWebhookConfig`, etc.). @@ -157,7 +157,7 @@ 3. The paired fields are **modal** — on input you set `url`, on output you read `urlSet`. The type system has no way to express this; both fields are simultaneously optional, so a user could try to set `urlSet: true` on input and the server will silently ignore it. - **Category:** 6 (misleading — three-valued boolean), 15 (generic field-naming pattern losing meaning). - **Suggested name:** Rename the pattern to `hasUrl`, `hasUsername`, etc. (English-correct boolean predicates). Better: split the input and output types so input has `url` only and output has `hasUrl` only. Or merge into a union: `url?: { write: string } | { read: { isSet: boolean } }`. -- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 22) hint that the type was originally split in the API spec and was flattened for TS. +- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 21) hint that the type was originally split in the API spec and was flattened for TS. ### 8. `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` — overly verbose — `src/v1/model.ts:23-28`, `:139-146` - **Code:** @@ -248,26 +248,12 @@ ## Low severity -### 15. SCREAMING_SNAKE_CASE enum values — `src/v1/model.ts:5-11` -- **Code:** - ```ts - SLACK = 'SLACK', - EMAIL = 'EMAIL', - WEBHOOK = 'WEBHOOK', - PAGERDUTY = 'PAGERDUTY', - MICROSOFT_TEAMS = 'MICROSOFT_TEAMS', - ``` -- **Why weird:** The TS Style Guide section "Enums" prefers UpperCamelCase identifiers for both name and members; SCREAMING_SNAKE values are a wire-format leak. `MICROSOFT_TEAMS` has an underscore in a TS identifier, which is also discouraged. -- **Category:** 4 (underscores in TS identifiers — strictly speaking, both identifier and value). -- **Suggested name:** `Slack = 'SLACK'`, `Email = 'EMAIL'`, `Webhook = 'WEBHOOK'`, `PagerDuty = 'PAGERDUTY'`, `MicrosoftTeams = 'MICROSOFT_TEAMS'`. The string literals (the wire representation) stay; only the TS identifier changes. -- **Rationale:** Generator-level decision. Hand-written SDKs typically use UpperCamelCase enum members; the SCREAMING_SNAKE form makes it look like the type is C/Java. Demoted to low because it's a global convention and changing it would break every existing user. - -### 16. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` +### 15. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` - See #3 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. - **Category:** 9 (qualifier mismatch). - **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #3 for the rationale. -### 17. `createNotificationDestination` / etc. — overly verbose method names — `src/v1/client.ts:71, 100, 125, 150, 204` +### 16. `createNotificationDestination` / etc. — overly verbose method names — `src/v1/client.ts:71, 100, 125, 150, 204` - **Code:** ```ts async createNotificationDestination(...) @@ -281,7 +267,7 @@ - **Suggested name:** Drop the suffix: `create`, `delete`, `get`, `list`, `update`. The class name (`Client` or `NotificationDestinationsClient`) supplies the domain context. - **Rationale:** Conventions differ across SDKs. AWS uses verbose method names; GCP / Azure use shorter. Demoted to low because the existing convention is consistent across the SDK and changing it is disruptive. Flagging for completeness. -### 18. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` +### 17. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` - **Code:** ```ts // Package identity segment for this client to be used in the User-Agent header. @@ -295,7 +281,7 @@ - **Suggested name:** `USER_AGENT_PACKAGE_INFO` or `PACKAGE_USER_AGENT`. - **Rationale:** Cross-package — same finding appears in every audited file. -### 19. `HttpCallOptions` — `src/v1/utils.ts:15-19` +### 18. `HttpCallOptions` — `src/v1/utils.ts:15-19` - **Code:** ```ts export interface HttpCallOptions { @@ -308,13 +294,13 @@ - **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). - **Suggested name:** `HttpCallContext` (it is an internal context bag, not user-tunable options). -### 20. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` +### 19. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` - **Code:** lines 26-38 and 65-94. - **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). -### 21. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 88, 105, 130, 165, 187, 190, 209` +### 20. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 88, 105, 130, 165, 187, 190, 209` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -322,13 +308,13 @@ ## Observations -### 22. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +### 21. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). - **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. -### 23. `index.ts` re-exports verbose names verbatim — `src/v1/index.ts:5-23` +### 22. `index.ts` re-exports verbose names verbatim — `src/v1/index.ts:5-23` The barrel re-exports every type with its long generated name. An opportunity to expose friendlier aliases: ```ts export type { @@ -340,10 +326,10 @@ export type { Not done. So consumers always work with the verbose names. The 1:1 port philosophy probably prohibits this, but flagging as an observation — the barrel could improve ergonomics without removing the underlying names. - **Category:** 7 (verbose), Observation. -### 24. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows +### 23. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. -### 25. JSDoc inconsistency in `[Input-Only][Optional]` markers +### 24. JSDoc inconsistency in `[Input-Only][Optional]` markers The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the marker `[Input-Only][Optional]` — concatenating two brackets — while every other field uses single-bracket markers. The `[Optional]` is also redundant because the TS type already shows `?: undefined`. Minor doc inconsistency. ## Domain glossary diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md index aaa16d01..809ce58a 100644 --- a/.agent/naming-audit/oauthcustomappintegration.md +++ b/.agent/naming-audit/oauthcustomappintegration.md @@ -3,15 +3,15 @@ **Path:** `packages/oauthcustomappintegration/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for OAuth App Integrations. Two flavours of integration are managed by the same service: *Custom* (caller-owned OAuth clients with their own redirect URLs and scopes) and *Published* (catalog of Databricks-blessed third-party apps such as Power BI or Tableau Desktop, identified by a stable `appId`). Both share the `TokenAccessPolicy` configuration. The package is the Databricks account-side complement of the `RFC 6749`/`OAuth 2.0` client registration concept. -**Total weird names flagged:** 17 +**Total weird names flagged:** 15 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 4 | | Medium | 5 | | Low | 4 | -| Observation | 3 | +| Observation | 2 | ## High severity @@ -21,36 +21,29 @@ - **Suggested name:** `@databricks/sdk-oauthappintegrations` (plural; drops the misleading "custom" since the package also covers published). Or split into two packages: `oauthcustomappintegrations` and `oauthpublishedappintegrations`, each plural. - **Rationale:** The Go SDK reference path is `databricks/api/oauth2` (umbrella for all OAuth concerns), which suggests the cross-service grouping is the natural one. The current TS name picks one half of the surface and elevates it to the package title, which is actively misleading. Pluralizing avoids the "what does one integration mean?" confusion at the import line. -### 2. Every domain type re-states `OAuthAppIntegration` — model.ts:6, 29, 41, 46, 73, 92, 100, 108, 115, 120, 128, 134, 141, 147, 185, 206, 208, 216 +### 2. Every domain type re-states `OAuthAppIntegration` — model.ts:6, 29, 46, 73, 92, 100, 108, 115, 120, 134, 147, 185, 208 - **Why weird:** Inside a package called `oauthcustomappintegration`, *every* type name still spells "OAuthAppIntegration" in full. Imports look like this: ```ts import { CreateCustomOAuthAppIntegration, CreatePublishedOAuthAppIntegration, - CreatePublishedOAuthAppIntegration_Response, CustomOAuthAppIntegration, CustomOAuthAppIntegrationSecret, DeleteCustomOAuthAppIntegration, - DeleteCustomOAuthAppIntegration_Response, DeletePublishedOAuthAppIntegration, - DeletePublishedOAuthAppIntegration_Response, GetCustomOAuthAppIntegration, GetPublishedOAuthAppIntegration, ListCustomOAuthAppIntegrations, - ListCustomOAuthAppIntegrations_Response, ListPublishedOAuthAppIntegrations, - ListPublishedOAuthAppIntegrations_Response, PublishedOAuthAppIntegration, UpdateCustomOAuthAppIntegration, - UpdateCustomOAuthAppIntegration_Response, UpdatePublishedOAuthAppIntegration, - UpdatePublishedOAuthAppIntegration_Response, } from '@databricks/sdk-oauthcustomappintegration/v1'; ``` - Eighteen of the 21 exported types are >25 characters long; nine are >35 characters. The package name already declares the namespace, so the type names need not re-declare it. Compare what the same code would look like with shorter names: `CreateCustom`, `CreatePublished`, `Custom`, `Published`, `CustomSecret`, `DeleteCustom`, … (still readable when paired with the package import). + Most exported types are >25 characters long; several are >35 characters. The package name already declares the namespace, so the type names need not re-declare it. Compare what the same code would look like with shorter names: `CreateCustom`, `CreatePublished`, `Custom`, `Published`, `CustomSecret`, `DeleteCustom`, … (still readable when paired with the package import). - **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) -- **Suggested name:** Drop the `OAuthAppIntegration` suffix from every type. With a namespace import the call site reads `oauth.CreateCustom`, `oauth.Custom`, `oauth.CustomSecret`, `oauth.ListPublished_Response`. With named imports, alias if needed. -- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it 19 times in type names produces walls of identifiers where the eye has to skip 19 redundant characters to find the discriminator (`Create` vs `Update` vs `Delete` vs `List` vs `Get`, and `Custom` vs `Published`). The redundancy is a Go convention port: in Go `oauthcustomappintegration.CreateCustomAppIntegrationRequest` is necessary because Go has no struct-level method namespacing. TS does not have that constraint. See the Go reference at `databricks/api/oauth2/oauthcustomappintegration` where the Go names are necessarily fully qualified — but a 1:1 port should adapt to TS naming, not blindly copy. +- **Suggested name:** Drop the `OAuthAppIntegration` suffix from every type. With a namespace import the call site reads `oauth.CreateCustom`, `oauth.Custom`, `oauth.CustomSecret`, `oauth.ListPublished`. With named imports, alias if needed. +- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it across every type produces walls of identifiers where the eye has to skip redundant characters to find the discriminator (`Create` vs `Update` vs `Delete` vs `List` vs `Get`, and `Custom` vs `Published`). The redundancy is a Go convention port: in Go `oauthcustomappintegration.CreateCustomAppIntegrationRequest` is necessary because Go has no struct-level method namespacing. TS does not have that constraint. See the Go reference at `databricks/api/oauth2/oauthcustomappintegration` where the Go names are necessarily fully qualified — but a 1:1 port should adapt to TS naming, not blindly copy. ### 3. Type names use `OAuthAppIntegration` but methods use `OAuthAppIntegration` while doc cross-refs use `CustomAppIntegration` / `PublishedAppIntegration` — `client.ts:97, 133, 168, 199` - **Why weird:** JSDoc on `createCustomOAuthAppIntegration` says: @@ -67,41 +60,33 @@ - **Suggested name:** `appSlug` or `publishedAppKey` with type narrowed to a string literal union or enum: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, fix the `tableau-deskop` typo and document the format ("dash-separated lowercase slug from the Databricks published-app catalog"). - **Rationale:** "ID" in this codebase otherwise means opaque UUID/integer (`integrationId`, `clientId`, `principalId`, `accountId`). Mixing in a human-readable slug under the same suffix is a teaching trap for callers. -### 5. `_Response` underscore convention violates TS naming rules — `model.ts:41, 98, 106, 128, 141, 206, 216` -- **Why weird:** Seven types use the `_Response` suffix: `CreatePublishedOAuthAppIntegration_Response`, `DeleteCustomOAuthAppIntegration_Response`, `DeletePublishedOAuthAppIntegration_Response`, `ListCustomOAuthAppIntegrations_Response`, `ListPublishedOAuthAppIntegrations_Response`, `UpdateCustomOAuthAppIntegration_Response`, `UpdatePublishedOAuthAppIntegration_Response`. Each one is preceded by an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment, acknowledging the violation. The underscore is a proto-message nesting convention (`CreatePublished.Response` in proto → `CreatePublished_Response` in the generated Go), but TS does not have a "nested message" concept and the underscore form is alien to TS idioms. -- **Category:** 4, 20 (underscores in TS identifiers; type-suffix tautology — `…AppIntegration_Response`) -- **Suggested name:** Two options: - - `CreatePublishedOAuthAppIntegrationResponse` (drop underscore, accept verbosity). - - `CreatePublishedResponse` (drop underscore and the redundant domain suffix; pair with category 2 simplification). -- **Rationale:** The escape-hatch ESLint disables show the codebase already knows these names violate convention. Pick a TS-native form. - ## Medium severity -### 6. `createdBy: number` is a user ID hidden as a numeric — `model.ts:60, 156` +### 5. `createdBy: number` is a user ID hidden as a numeric — `model.ts:60, 156` - **Why weird:** Used in both `CustomOAuthAppIntegration` and `PublishedOAuthAppIntegration`. The field doc is empty, but it pairs with `creatorUsername: string` on `CustomOAuthAppIntegration`, so `createdBy` is the *user ID* of the creator. Calling it `createdBy` and typing it as `number` (rather than `creatorUserId` typed as `number` or `string`) hides the meaning. `principalId: number` next door has the same problem. - **Category:** 1, 15, 19 (vague; generic field; underspecified ID) - **Suggested name:** `createdByUserId: number` or just `creatorUserId: number`. Document explicitly that this is the numeric Databricks user ID (note: many other places in the codebase use `string` for user IDs). - **Rationale:** A bare `createdBy: number` is the worst kind of numeric ID — no type information, no doc, and a name that reads as an activity verb. The asymmetry with `creatorUsername: string` (which sits 2 lines below in `CustomOAuthAppIntegration` but is missing from `PublishedOAuthAppIntegration`) compounds the confusion. -### 7. `createTime: string` vs `clientSecretExpireTime: Temporal.Instant` — type inconsistency — `model.ts:61, 89, 157` +### 6. `createTime: string` vs `clientSecretExpireTime: Temporal.Instant` — type inconsistency — `model.ts:61, 89, 157` - **Why weird:** Both fields are timestamps. `createTime` is typed as `string` (raw ISO 8601, unparsed). `clientSecretExpireTime` is typed as `Temporal.Instant` (parsed via `Temporal.Instant.from`). Same package, same wire format, two different deserialization choices. Callers have to remember which fields are parsed and which are not. Looking at the unmarshal code at line 270, `client_secret_expire_time` gets `.transform(s => Temporal.Instant.from(s))` while `create_time` (line 241, 327) does not. - **Category:** 16 (field contradicting type domain — both timestamps, different types) - **Suggested name:** Names are fine; the *types* are inconsistent. Either both `Temporal.Instant` (preferred — this is the post-Temporal TS world) or both `string`. Apply consistently across the package. - **Rationale:** A consumer doing `if (integration.createTime < other.createTime)` will get string comparison silently; if they did the same with `Temporal.Instant` they would get a type error and use `Temporal.Instant.compare`. The current state is a footgun. -### 8. `clientSecretExpireTime` verb tense — `model.ts:89` +### 7. `clientSecretExpireTime` verb tense — `model.ts:89` - **Why weird:** "Expire" is the bare infinitive — should be "expires" (third-person singular: "the secret expires at T") or "expiry"/"expiration" (noun). The Go side likely has `ClientSecretExpireTime` because Go traditionally uses verb-first compound nouns (`expireTime`, `createTime`), but TS/JS naming tends to use either the noun (`expirationTime`, `expirationDate`) or the inflected verb (`expiresAt`). `createTime`/`createdBy` next door have the same issue (should be `createdAt`/`creator`). - **Category:** 13, 14 (verb-tense inconsistency; Go/Java-style names) - **Suggested name:** `clientSecretExpiresAt`, `createdAt`, `creator` (or `creatorUserId`). - **Rationale:** TypeScript ecosystem standard is `xAt` for timestamps and inflected verbs in field names. The Go form `xTime` reads as a Go transliteration. -### 9. `confidential: boolean` — too generic for "requires-secret" flag — `model.ts:13, 56` +### 8. `confidential: boolean` — too generic for "requires-secret" flag — `model.ts:13, 56` - **Why weird:** The doc comment is informative ("indicates whether an OAuth client secret is required to authenticate this client"), but the field name `confidential` is ambiguous outside RFC 6749 context. A reader has to know OAuth specifically (RFC 6749 §2.1 distinguishes "confidential" vs "public" clients) to decode this. The field doesn't follow a `requires…` or `is…` convention used elsewhere in the codebase. - **Category:** 1, 5 (vague/generic; cryptic abbreviation of a spec term) - **Suggested name:** `isConfidentialClient`, `requiresClientSecret`, or `confidentialClient`. If keeping `confidential`, add the RFC 6749 link in the doc. - **Rationale:** Half of OAuth API consumers will not recognize "confidential" as the RFC 6749 client-type discriminator. -### 10. `userAuthorizedScopes` vs `scopes` overlap — `model.ts:20, 26, 59, 68, 196, 202` +### 9. `userAuthorizedScopes` vs `scopes` overlap — `model.ts:20, 26, 59, 68, 196, 202` - **Why weird:** Two scope fields that look unrelated by name but the doc explicitly says `userAuthorizedScopes` "must be a subset of `scopes`". The relationship is invisible from the type — a caller could set `scopes = ["all-apis"]` and `userAuthorizedScopes = ["sql"]` and the type system won't help. `scopes` is the *requested* scope set, `userAuthorizedScopes` is the *user-consent gate* subset. Names do not encode this subset relationship. - **Category:** 1, 6 (vague; misleading — `scopes` doesn't say "requested") - **Suggested name:** `requestedScopes` (rename `scopes`) and `consentRequiredScopes` (rename `userAuthorizedScopes`). Or document the subset relationship inline on `scopes` with a backreference. @@ -109,13 +94,13 @@ ## Low severity -### 11. `OAuth` casing is consistent — `model.ts:throughout` +### 10. `OAuth` casing is consistent — `model.ts:throughout` - **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants appear. This matches Google TS style guide guidance for trade-mark casing and matches RFC 6749 ("OAuth 2.0"). No action. - **Category:** 3 (acronym casing — flagged as compliant) - **Suggested name:** None — confirm the project-wide policy is `OAuth`. - **Rationale:** Documenting the convention. Other audits should check sibling packages for `OAuth2` vs `Oauth2` vs `OAUTH2`. -### 12. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix bloat — `model.ts:162, 168, 182` +### 11. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix bloat — `model.ts:162, 168, 182` - **Why weird:** Three TTL fields, two named `…InMinutes`, one named `…LifetimeInMinutes`. The "InMinutes" suffix is verbose. Three options to consider: - Adopt `Temporal.Duration` for the type (no unit in the name needed). - Keep the unit in the name but standardise on `Minutes` suffix (`accessTokenTtlMinutes`, `refreshTokenTtlMinutes`, `sessionTtlMinutes`). @@ -124,13 +109,13 @@ - **Suggested name:** `accessTokenTtl: Temporal.Duration`, `refreshTokenTtl: Temporal.Duration`, `absoluteSessionLifetime: Temporal.Duration`. - **Rationale:** The project already uses `Temporal.Instant` for `clientSecretExpireTime`. Extending to `Temporal.Duration` here removes the need to encode the unit in the field name, and removes the asymmetry between `TtlInMinutes` and `LifetimeInMinutes` (one is "TTL", the other "lifetime" — same concept). -### 13. `enableSingleUseRefreshTokens` boolean naming inconsistency with `confidential` — `model.ts:175` +### 12. `enableSingleUseRefreshTokens` boolean naming inconsistency with `confidential` — `model.ts:175` - **Why weird:** `enableSingleUseRefreshTokens` uses the verb-first `enableX` convention, but `confidential` uses no prefix. Other boolean conventions in the codebase favour `isX`/`hasX`. Three competing patterns on one type. - **Category:** 13, 17 (verb-tense inconsistency; inconsistent action verbs) - **Suggested name:** Align to one of `singleUseRefreshTokensEnabled` (state), `useSingleUseRefreshTokens` (config), or `rotateRefreshTokens` (behaviour). - **Rationale:** "Enable X" reads as an action and slightly suggests a method/mutator. State booleans typically use predicate suffix `isEnabled`/`enabled` or domain noun. -### 14. `includeCreatorUsername: boolean` query param on List Custom only — `model.ts:124` +### 13. `includeCreatorUsername: boolean` query param on List Custom only — `model.ts:124` - **Why weird:** `ListCustomOAuthAppIntegrations` has `includeCreatorUsername` but `ListPublishedOAuthAppIntegrations` does not (line 134). The asymmetry is fine for the API (Published integrations don't track creator the same way) but the type-level discoverability is poor. A caller writing both list calls in sequence will not understand why the option is missing from one. The name itself is also a query-flag for *server-side join inclusion*, which is unusual for an SDK to expose verbatim. - **Category:** 5 (cryptic — the flag's semantics are non-obvious) - **Suggested name:** Keep the field but document explicitly: "When true, the server resolves `createdBy` to `creatorUsername` in the response (extra database lookup)." @@ -141,10 +126,7 @@ ### O1. JSDoc literal templating leaks `` and `` markup — `model.ts:80, 82, 172, 178` and `client.ts:281, 341` - The literal tokens `` and `` appear in seven places in this package. They are proto-doc templating tokens that should have been substituted to "Databricks" / "account" during generation. They render as broken-HTML angle-bracket sequences in TypeScript hover popups. This is a generator bug, not a per-package naming issue, but worth tagging at the project level. -### O2. `_Response` suffix is the only naming-convention violation — `model.ts: throughout` -- All seven `_Response` types carry an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` Comment. No other naming violations in the package require ESLint disables. This is a single, removable wart that the generator could fix in one place. See finding #5. - -### O3. `flattenQueryParams` is exported but unused — `utils.ts:123` +### O2. `flattenQueryParams` is exported but unused — `utils.ts:123` - This package never builds nested query parameters (`ListCustomOAuthAppIntegrations` uses three flat scalars), so `flattenQueryParams` is dead in this build. Same as in many sibling packages. Either drop the `export` or move the helper to `@databricks/sdk-core`. ## Domain glossary diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md index c86c0dc4..b47f8290 100644 --- a/.agent/naming-audit/oauthpublishedapp.md +++ b/.agent/naming-audit/oauthpublishedapp.md @@ -3,15 +3,15 @@ **Path:** `packages/oauthpublishedapp/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level read-only catalog of Databricks-blessed third-party OAuth applications (e.g. Power BI, Tableau Desktop) that can be enabled for an account. The package exposes a single endpoint that lists the published-app catalog rows. Each `PublishedOAuthApp` is a *catalog entry* (template) — not an *integration row* (which is the realised binding tracked by the sibling `oauthcustomappintegration` package). The package therefore plays "catalog index" to `oauthcustomappintegration`'s "registration manager". Domain underpinning is RFC 6749 (OAuth 2.0) client-type "published" applications, augmented by a Databricks-owned catalog of vetted third-party clients. -**Total weird names flagged:** 16 +**Total weird names flagged:** 12 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 3 | | Medium | 6 | | Low | 3 | -| Observation | 2 | +| Observation | 1 | ## High severity @@ -21,33 +21,20 @@ - **Suggested name:** `@databricks/sdk-oauthpublishedapps` (plural), or `@databricks/sdk-oauthappcatalog` (re-cast as a catalog concept). - **Rationale:** Reading `import { Client } from '@databricks/sdk-oauthpublishedapp/v1'` suggests there is a per-app client. A reader will land on the file expecting `getPublishedOAuthApp(id)`, `createPublishedOAuthApp(…)`, etc., and find only `listPublishedOAuthApps`. Pluralizing the package would set correct expectations. The Go reference at `databricks/api/oauth2/oauthpublishedapp` carries the same wart; a 1:1 port should still resolve it for TS since Go's package-vs-method namespacing rules don't apply. -### 2. Package name fragments without separators — `package.json:2` -- **Why weird:** `oauthpublishedapp` is one unbroken 17-character token combining four concepts: OAuth + published + app. Compare to siblings: `oauthcustomappintegration` (25 chars, also unbroken — five concepts) and `apps` (4 chars). The npm scope name does not have to follow Go's no-separator-in-package convention. Several other Databricks SDK packages already use hyphenated names (`@databricks/sdk-core`, `@databricks/sdk-auth`, `@databricks/sdk-databricks`, `@databricks/sdk-options`). -- **Category:** 7 (overly verbose without natural break-points) -- **Suggested name:** `@databricks/sdk-oauth-published-apps` (hyphenated, plural). npm package naming permits dashes (https://docs.npmjs.com/cli/v10/configuring-npm/package-json#name). -- **Rationale:** Imports are read by humans; a four-word run-on identifier is harder to skim than a hyphen-separated one. The codebase already uses hyphens for some packages, so the precedent exists. - -### 3. Every domain type re-states `PublishedOAuthApp` in full — `model.ts:5, 15, 22` -- **Why weird:** Inside a package named `oauthpublishedapp`, every type still spells "PublishedOAuthApp" or "PublishedOAuthApps" inside its name: `ListPublishedOAuthApps`, `ListPublishedOAuthApps_Response`, `PublishedOAuthApp`. The package import already declares the namespace; the type names re-declare it. The same pattern appears (more egregiously) in `oauthcustomappintegration` — finding #2 there. +### 2. Every domain type re-states `PublishedOAuthApp` in full — `model.ts:5, 15, 22` +- **Why weird:** Inside a package named `oauthpublishedapp`, every type still spells "PublishedOAuthApp" or "PublishedOAuthApps" inside its name: `ListPublishedOAuthApps`, `PublishedOAuthApp`. The package import already declares the namespace; the type names re-declare it. The same pattern appears (more egregiously) in `oauthcustomappintegration` — finding #2 there. ```ts import { ListPublishedOAuthApps, - ListPublishedOAuthApps_Response, PublishedOAuthApp, } from '@databricks/sdk-oauthpublishedapp/v1'; ``` Every type repeats 16+ characters of "PublishedOAuthApp" that are already in the import path. - **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) -- **Suggested name:** Drop the `PublishedOAuthApps?` qualifier from every type. With a namespace import the call site reads `published.List`, `published.List_Response`, `published.App`. With named imports, alias if needed: `import { App as PublishedOAuthApp }`. -- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it in type names produces walls of identifiers where the eye has to skip the redundant prefix to find the discriminator (`List` vs the single payload type). Pattern is a 1:1 port from Go (`oauthpublishedapp.PublishedOAuthApp` is necessary in Go because Go has no struct-level method namespacing); TS does not share that constraint. - -### 4. `_Response` underscore suffix violates TS naming rules — `model.ts:14-15` -- **Why weird:** `ListPublishedOAuthApps_Response` uses the `_Response` underscore suffix, preceded by an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment, acknowledging the violation. The underscore is a proto-message nesting convention (`ListPublishedOAuthApps.Response` in proto → `ListPublishedOAuthApps_Response` in generated Go), but TS does not have a "nested message" concept and the underscore form is alien to TS idioms. Same finding appears in `oauthcustomappintegration` #6. -- **Category:** 4, 14, 20 (underscores in TS identifiers; Go/Java-style names; type-suffix tautology — `…PublishedOAuthApps_Response`) -- **Suggested name:** `ListPublishedOAuthAppsResponse` (drop underscore), or after applying finding #3, `List_Response` → `ListResponse`. -- **Rationale:** The ESLint escape-hatch on this single type shows the codebase already knows the underscore violates convention. The only such violation in this package; trivial to fix. Pick a TS-native form. +- **Suggested name:** Drop the `PublishedOAuthApps?` qualifier from every type. With a namespace import the call site reads `published.List`, `published.App`. With named imports, alias if needed: `import { App as PublishedOAuthApp }`. +- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it in type names produces walls of identifiers where the eye has to skip the redundant prefix to find the discriminator. Pattern is a 1:1 port from Go (`oauthpublishedapp.PublishedOAuthApp` is necessary in Go because Go has no struct-level method namespacing); TS does not share that constraint. -### 5. `appId` on `PublishedOAuthApp` is a slug, not an opaque ID — `model.ts:24` +### 3. `appId` on `PublishedOAuthApp` is a slug, not an opaque ID — `model.ts:24` - **Why weird:** `PublishedOAuthApp.appId` is documented as "Unique ID of the published OAuth app". The doc gives no examples here, but the sibling `oauthcustomappintegration` package's `CreatePublishedOAuthAppIntegration.appId` (which is the same value used to enable a published app in that account) is documented as `For example power-bi, tableau-deskop` (sic — typo carried in original). The appId is therefore a human-readable slug like `power-bi`, not an opaque UUID. Calling it `appId` and typing it as `string` collides with the convention that `xId` is an opaque opaque-ID (cf. `accountId`, `integrationId`, `clientId`, `principalId`). Same finding as `oauthcustomappintegration` #5; the value flows between the two packages and should be named consistently across both. - **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) - **Suggested name:** `appSlug` or `publishedAppKey` with the type narrowed to a literal union: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, document the format inline ("dash-separated lowercase slug from the Databricks published-app catalog") and cross-reference `CreatePublishedOAuthAppIntegration.appId` in the sibling package. @@ -55,37 +42,37 @@ ## Medium severity -### 6. `clientId` field lacks the convention-matching closing period — `model.ts:25` +### 4. `clientId` field lacks the convention-matching closing period — `model.ts:25` - **Why weird:** Doc comment reads `Client ID of the published OAuth app. It is the client_id in the OAuth flow` — missing trailing period (`flow` ends the sentence). Every other doc comment in the file ends with a period. Also, the wire-form `client_id` is hardcoded into the JSDoc text, which leaks generator-side terminology into TS docs that should describe the TS field. Repository CLAUDE.md rule: "Every comment must be a proper sentence ending with a period." - **Category:** Not strictly a name finding, but a generator-side text issue — included because it sits on a name field and is visible at every hover. - **Suggested name:** Doc text only; field name `clientId` is correct. Fix to: `Client ID of the published OAuth app. Matches the OAuth 2.0 \`client_id\` parameter (RFC 6749 §2.2).` - **Rationale:** Comment-style rule on the project. The reference to RFC 6749 §2.2 gives the term a spec anchor instead of leaving "client_id in the OAuth flow" as a vague pointer. -### 7. `isConfidentialClient` named inconsistently across packages — `model.ts:31-32` +### 5. `isConfidentialClient` named inconsistently across packages — `model.ts:31-32` - **Why weird:** The sibling `oauthcustomappintegration` exposes the same OAuth concept under the field name `confidential` (no `is…Client` prefix). The two packages model the same RFC 6749 §2.1 client-type flag with different identifiers, so a consumer juggling both has to remember that `customIntegration.confidential` and `publishedApp.isConfidentialClient` are the same flag. Audit finding #12 in `oauthcustomappintegration` recommends renaming that side to `isConfidentialClient` — so the *name* here is the right one; the sibling is the side to align. - **Category:** 12 (duplicate concept across packages, inconsistent naming) - **Suggested name:** Keep `isConfidentialClient` here. Cross-package fix lives in the sibling audit (#12 there). - **Rationale:** The flag's value space and meaning are identical across the two packages; the identifier should be too. Resolve at the sibling, not here. -### 8. `redirectUrls: string[]` field stutter with `URI`/`URL` spec language — `model.ts:33-34` +### 6. `redirectUrls: string[]` field stutter with `URI`/`URL` spec language — `model.ts:33-34` - **Why weird:** OAuth 2.0 spec (RFC 6749 §3.1.2) calls these *redirection URIs*. The TS field uses `redirectUrls` (lowercase `rl`); the JSDoc reads "Redirect URLs of the published OAuth app." matching the field name. The sibling `oauthcustomappintegration` finding #13 documents that the package mixes URI / URL in JSDoc and field names; here the package uses `URLs` consistently within itself but contradicts spec language. The casing `Urls` (lowercase `rl`) follows Google TS style guide § Identifiers (acronyms ≥3 chars are PascalCase, but `URL` historically is exempted in many guides — TypeScript ecosystem standard is `Url`). - **Category:** 3 (acronym casing — `URL` lowercased as `Url` while `OAuth` keeps `Auth` mid-token uppercase, inconsistent acronym treatment within the same identifier set) - **Suggested name:** Keep `redirectUrls` (matches Google TS style guide https://google.github.io/styleguide/tsguide.html#identifiers), but cross-reference RFC 6749 §3.1.2 in the JSDoc so the spec term is visible: "Redirect URLs of the published OAuth app (RFC 6749 §3.1.2 \"redirection URIs\")." - **Rationale:** Consistent with sibling package finding #13. The doc-term mismatch (URI in spec, URL in code) is the real issue; the casing is correct per Google TS. -### 9. `scopes: string[]` carries no enum/union — `model.ts:35-36` +### 7. `scopes: string[]` carries no enum/union — `model.ts:35-36` - **Why weird:** Sibling `oauthcustomappintegration` documents the supported scope set inline: `Supported scopes: all-apis, sql, offline_access, openid, profile, email`. Here the same field is typed `string[]` with no JSDoc enumeration: just "Required scopes for the published OAuth app." Both packages share the same scope vocabulary (it is the Databricks OAuth scope set), and one documents it, the other does not. - **Category:** 1, 12 (vague — string[] could be anything; duplicate concept across packages, inconsistent treatment) - **Suggested name:** Keep `scopes`, but type as `Array<'all-apis' | 'sql' | 'offline_access' | 'openid' | 'profile' | 'email'>` to match the sibling package's documented vocabulary. At minimum, JSDoc the supported scopes. - **Rationale:** Two packages model the same wire field. The custom package documents the value space; the published package leaves it open. A consumer reading `app.scopes` has no in-IDE way to learn the valid values. -### 10. `pageSize: number` lacks bounds and unit context — `model.ts:11` +### 8. `pageSize: number` lacks bounds and unit context — `model.ts:11` - **Why weird:** Doc says "The max number of OAuth published apps to return in one page." but does not document the maximum-permitted value, default, or whether `0` means "unset" or "zero results". `pageSize` is the most common cross-API pagination footgun; some Databricks APIs reject `pageSize > 1000`, others treat `0` as "use default", others as "return zero". A consumer doing `req.pageSize = 0` gets undefined behaviour. The name `pageSize` itself is fine and consistent with Databricks API conventions (and Google AIP-158 https://google.aip.dev/158). - **Category:** 1 (vague — `number` with no bounds reads as "any int", but isn't) - **Suggested name:** Name is fine; doc should be "The maximum number of published OAuth apps to return in one page. Defaults to server-side default (typically 100). Maximum: 1000." - **Rationale:** Same field exists in many sibling packages; document once at the source of truth (the generator's pagination template). -### 11. `pageToken: string` reuses the previous-response `nextPageToken` — implicit cross-field contract — `model.ts:8-9`, `model.ts:18-19` +### 9. `pageToken: string` reuses the previous-response `nextPageToken` — implicit cross-field contract — `model.ts:8-9`, `model.ts:18-19` - **Why weird:** Request `pageToken` and response `nextPageToken` are two halves of one pagination contract. The names use different roots (`page…` vs `nextPage…`), so the connection is invisible. A new reader has to read both shapes and the iterator to understand `req.pageToken = resp.nextPageToken`. This is the Google AIP-158 convention (https://google.aip.dev/158) and shared by every paginated Databricks API, but worth flagging at project level since the naming asymmetry repeats everywhere. - **Category:** 17 (inconsistent action verbs — `pageToken` is a noun, `nextPageToken` is a noun; the asymmetry is in the prefix `next…`) - **Suggested name:** Keep names (they match AIP-158); document the relationship in JSDoc: "Pass `nextPageToken` from the previous response as `pageToken` to fetch the next page." @@ -93,31 +80,28 @@ ## Low severity -### 12. `OAuth` casing is consistent — `model.ts:throughout` +### 10. `OAuth` casing is consistent — `model.ts:throughout` - **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants. Matches Google TS style guide guidance and matches RFC 6749. Matches sibling `oauthcustomappintegration`. No action. - **Category:** 3 (acronym casing — flagged compliant) - **Suggested name:** None — confirm the project-wide policy is `OAuth`. - **Rationale:** Documenting compliance. -### 13. `Client` class — generic single export, common to all generated packages — `client.ts:32` +### 11. `Client` class — generic single export, common to all generated packages — `client.ts:32` - **Why weird:** Same pattern as every other package in this SDK. `import { Client } from '@databricks/sdk-oauthpublishedapp/v1'` produces an unqualified `Client` symbol. Consumers using multiple packages must alias: `import { Client as OAuthPublishedAppClient }`. Project-wide pattern, not specific to this package. - **Category:** 1 (vague/generic) - **Suggested name:** `OAuthPublishedAppClient` (still inside `…/v1`). Project-wide change. - **Rationale:** Defer to the project-wide naming-audit summary. Same as sibling finding #19. -### 14. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:17` -- **Why weird:** `ListPublishedOAuthApps_Response.apps` is the collection field. Unlike the sibling package's `apps` field finding (`oauthcustomappintegration` #4) where the field carried *integrations* and the name was misleading, here the field genuinely is published apps. The name is correct *but* it duplicates the type name (`apps: PublishedOAuthApp[]` — "apps of type App"). Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). Acceptable. +### 12. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:17` +- **Why weird:** The response collection field. Unlike the sibling package's `apps` field finding (`oauthcustomappintegration` #4) where the field carried *integrations* and the name was misleading, here the field genuinely is published apps. The name is correct *but* it duplicates the type name (`apps: PublishedOAuthApp[]` — "apps of type App"). Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). Acceptable. - **Category:** 15 (generic field — `apps` is the maximally-generic plural of `app`) — flagged for completeness - **Suggested name:** Keep `apps`. Or rename `publishedApps` to make plural+domain explicit. No strong action. - **Rationale:** Within the response type, the field name is unambiguous. Cross-package consistency with `oauthcustomappintegration` is broken (that package's `apps` field is misleading), but renaming this one would not fix that — the sibling rename is the right place. ## Observations -### O1. JSDoc literal templating: this package has **no** `` / `` leaks -- Sibling `oauthcustomappintegration` has six JSDoc strings containing literal `` / `` tokens (their finding O1). This package has zero such leaks — the JSDoc on `listPublishedOAuthApps` ("Get all the available published OAuth apps in ``") *does* contain the token at `client.ts:61`. Update: this *does* have one such leak. Same generator bug. - -### O2. `_Response` suffix is the only naming-convention violation — `model.ts:14-15` -- The one `_Response` type has an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` comment. No other naming violations in the package require ESLint disables. Single, removable wart that the generator could fix. See finding #4. +### O1. JSDoc literal templating: this package has `` token leak — `client.ts:61` +- Sibling `oauthcustomappintegration` has six JSDoc strings containing literal `` / `` tokens (their finding O1). This package has one such leak — the JSDoc on `listPublishedOAuthApps` reads "Get all the available published OAuth apps in ``". Same generator bug. ## Domain glossary - `accountId` — Databricks account UUID (top-level tenant). Distinct from a workspace ID. @@ -132,7 +116,7 @@ - `appId` value space is shared with `oauthcustomappintegration.CreatePublishedOAuthAppIntegration.appId`. Renaming on one side must rename on the other. - `isConfidentialClient` here ↔ `confidential` on the sibling — same underlying concept, inconsistent boolean naming. - `scopes: string[]` here ↔ `scopes: string[]` on the sibling — same vocabulary, only the sibling documents the literal value set. -- Both packages share the `OAuth` casing convention and the `_Response` underscore suffix violation. +- Both packages share the `OAuth` casing convention. - Suggested cross-package action: lift `PublishedOAuthApp` (catalog row) into a shared module imported by both packages, so `oauthcustomappintegration` can reference the canonical row when an account enables a published app. ## File coverage diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md index 8c3eea04..c2909d0d 100644 --- a/.agent/naming-audit/onlinetables.md +++ b/.agent/naming-audit/onlinetables.md @@ -92,11 +92,11 @@ | Severity | Count | | --------------------- | ----- | -| High | 7 | +| High | 5 | | Medium | 13 | | Low / SDK-wide note | 9 | | Pass / acceptable | 9 | -| **Total findings** | **38** | +| **Total findings** | **36** | (Several findings touch multiple audit categories; counts above are unique findings.) @@ -105,55 +105,7 @@ findings.) ## Findings -### 1. `ProvisioningInfo_State` underscore in type name — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) - -**Symbol:** `ProvisioningInfo_State` (model.ts:57). - -**Issue:** The enum name carries a `_` underscore separating the parent -message name (`ProvisioningInfo`) and the nested-enum name (`State`). This is -a proto-buf code-generator artefact for nested messages/enums (`ParentMessage.NestedEnum` -in `.proto` becomes `ParentMessage_NestedEnum` in some Go codegens) and is not -idiomatic TypeScript. The Google TS Style Guide § 5.3 mandates `UpperCamelCase` -for type names with no underscores; the project's own lint rule -(`.agent/rules/typescript.mdc` § *Identifiers*) enforces the same. The file -even has to suppress the lint for this identifier (model.ts:56): - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. -export enum ProvisioningInfo_State { -``` - -The suppression comment is itself the audit signal: lint disagrees, and the -suppression is hard-coded across the SDK for every proto-nested enum. - -**Suggested:** `ProvisioningState`. Folding the nested-enum name to a flat -`ProvisioningState` loses no information. - -**Note on inconsistency *within this file*:** the file uses *both* the flat -name (`OnlineTableState`, model.ts:7) and the underscored form -(`ProvisioningInfo_State`, model.ts:57). Same generator, same package, two -conventions in 50 lines. **Flag for generator-wide cleanup.** - ---- - -### 2. `OnlineTableSpec_ContinuousSchedulingPolicy` and `OnlineTableSpec_TriggeredSchedulingPolicy` underscored type names — category 4 (Underscores in TS identifiers) - -**Symbols:** `OnlineTableSpec_ContinuousSchedulingPolicy` (model.ts:175), -`OnlineTableSpec_TriggeredSchedulingPolicy` (model.ts:178). - -**Issue:** Underscored type names (same root cause as finding 1). Lint -suppression at model.ts:174 and 177 marks the violation. The proto-namespace -underscore separates the parent message name (`OnlineTableSpec`) from the -nested-message name (`ContinuousSchedulingPolicy` / `TriggeredSchedulingPolicy`). -This is a proto-buf code-generator artefact, not idiomatic TypeScript. - -**Suggested at the TS level:** strip the proto namespace, yielding flat type -names `ContinuousSchedulingPolicy` and `TriggeredSchedulingPolicy`. **Flag for -generator-wide cleanup.** - ---- - -### 3. `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 1. `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) **Symbol:** `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` (model.ts:9). @@ -169,37 +121,33 @@ Note: the values double as on-the-wire JSON strings (`z.enum(OnlineTableState)` at model.ts:341 parses raw API strings directly into these identifiers), so renaming the wire string requires server acceptance and is a behavioural change. The TS-side identifier can be split from the wire string (see -finding 5) for a safe local fix. +finding 3) for a safe local fix. **Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. -**Suggested TS-level only (safe — see finding 5):** `Unspecified = +**Suggested TS-level only (safe — see finding 3):** `Unspecified = 'ONLINE_TABLE_STATE_UNSPECIFIED'`. --- -### 4. `ProvisioningInfo_State.STATE_UNSPECIFIED` value prefix repeats half the enum name — category 2 (Redundant enum prefixes) +### 2. `ProvisioningInfo_State.STATE_UNSPECIFIED` value prefix repeats half the enum name — category 2 (Redundant enum prefixes) **Symbol:** `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58). -**Issue:** Same family as finding 3. The `STATE_` prefix repeats the trailing -half of the enum name. After applying finding 1 (rename to -`ProvisioningState`), the duplication is even more visible: -`ProvisioningState.STATE_UNSPECIFIED`. +**Issue:** Same family as finding 1. The `STATE_` prefix repeats the trailing +half of the enum name. **Suggested:** TS-side identifier `Unspecified`. Wire string remains `STATE_UNSPECIFIED` if upstream still emits it. --- -### 5. SCREAMING_SNAKE_CASE enum members — category 4 (Underscores in TS identifiers) +### 3. SCREAMING_SNAKE_CASE enum members (value-level) — category 4 **Symbols:** Every value in both enums (model.ts:9–53 and 58–64). **Issue:** The project's `.agent/skills/google-ts-styleguide` (and Google TS -Style Guide § 5.3) mandates `UpperCamelCase` for enum members, not -`SCREAMING_SNAKE_CASE`. The project's own `typescript.mdc` enforces no -underscores in TS identifiers. Every enum value here contains underscores -and is SCREAMING-cased. +Style Guide § 5.3) mandates `UpperCamelCase` for enum *members*, not +`SCREAMING_SNAKE_CASE`. Every enum value here is SCREAMING-cased. Enum string *values* double as the on-the-wire representation here (the Zod schemas parse raw API strings into these identifiers — `z.enum(OnlineTableState)` @@ -226,7 +174,7 @@ export enum OnlineTableState { OnlineUpdatingPipelineResources = 'ONLINE_UPDATING_PIPELINE_RESOURCES', } -export enum ProvisioningState { +export enum ProvisioningInfo_State { Unspecified = 'STATE_UNSPECIFIED', Provisioning = 'PROVISIONING', Active = 'ACTIVE', @@ -242,7 +190,7 @@ and `database.md` finding 6. --- -### 6. `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` value too long — category 18 (Long enum values) +### 4. `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` value too long — category 18 (Long enum values) **Symbol:** `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` (model.ts:53) and `PROVISIONING_PIPELINE_RESOURCES` (model.ts:16). @@ -254,11 +202,11 @@ hard to read. **Suggested:** at the TS level, `OnlineUpdatingPipelineResources` shortens to 30 chars while preserving meaning. The wire form is fixed by upstream. **Pass -in isolation if finding 5 is applied; flag as a long-name observation.** +in isolation if finding 3 is applied; flag as a long-name observation.** --- -### 7. `OnlineTableState` modelled as one enum, two semantic groups — category 6 (Misleading names) and category 12 (Duplicate concepts) +### 5. `OnlineTableState` modelled as one enum, two semantic groups — category 6 (Misleading names) and category 12 (Duplicate concepts) **Symbol:** `OnlineTableState` (model.ts:7), 12 values. @@ -276,7 +224,7 @@ This is a wire-level concern, but in TS it reads as a single enum doing two jobs — top-level lifecycle and one-level-down detail. Compare to `database.SyncedTableState` which has the same 12 values prefixed `SYNCED_TABLE_…` (with a famous typo `SYNCED_TABLED_OFFLINE`). The duplication -*across packages* is also a flag — see finding 8. +*across packages* is also a flag — see finding 6. **Suggested:** push back upstream — split into `OnlineTableLifecycle` (a few top-level states) and use `detailedStatus.$case` as the substate identifier. @@ -284,32 +232,34 @@ top-level states) and use `detailedStatus.$case` as the substate identifier. --- -### 8. Cross-package collision: `OnlineTableState` ↔ `database.SyncedTableState` — category 12 (Duplicate concepts) and category 17 (Inconsistent action verbs) +### 6. Cross-package collision: `OnlineTableState` ↔ `database.SyncedTableState` (wire-level typo) — category 12 (Duplicate concepts) and category 17 (Inconsistent action verbs) **Symbol:** `OnlineTableState` (here, model.ts:7) and `SyncedTableState` (`database/v1/model.ts:55`, `postgres/v1/model.ts`). **Issue:** Two SDK packages model essentially the same lifecycle concept — the state of a UC-managed Delta-to-managed-store sync table — with two -*different enum names* and one is misspelled (`SYNCED_TABLED_OFFLINE`). -Looking at the values: +*different enum names* and one is misspelled at the **wire-string** level +(`SYNCED_TABLED_OFFLINE`). Looking at the values: - `onlinetables.OnlineTableState`: 12 values, prefix `ONLINE_TABLE_STATE_…` on `UNSPECIFIED` only. - `database.SyncedTableState`: 12 values, prefix `SYNCED_TABLE_…` on **all - values** plus the famous typo `SYNCED_TABLED_OFFLINE`. + values** plus the famous wire-string typo `SYNCED_TABLED_OFFLINE`. These enums describe the *same machine*. A consumer who uses both packages will write a lookup table or branch on `$case` differently in each package. +The `SYNCED_TABLED_OFFLINE` typo is on the wire and locks consumers into +the misspelling. **Suggested at the SDK level:** harmonise the type names (drop one in favour of the other, with an alias for backward compatibility). The wire-level -fix is a protocol-team decision. **Strongly flag for SDK-wide alignment**; -do not fix unilaterally in this package. +typo fix is a protocol-team decision and a behavioural change. **Strongly +flag for SDK-wide alignment**; do not fix unilaterally in this package. --- -### 9. Cross-package collision: `PipelineProgress` ↔ `database.SyncedTablePipelineProgress` — category 12 (Duplicate concepts) +### 7. Cross-package collision: `PipelineProgress` ↔ `database.SyncedTablePipelineProgress` — category 12 (Duplicate concepts) **Symbol:** `PipelineProgress` (here, model.ts:202) and `database.SyncedTablePipelineProgress` (`database/v1/model.ts:744`, @@ -329,20 +279,19 @@ or extract both into `@databricks/sdk-core` if the dependency is acceptable. --- -### 10. Cross-package collision: `ProvisioningInfo_State` defined in 4+ packages — category 12 (Duplicate concepts) +### 8. Cross-package collision: `ProvisioningInfo` defined in 4+ packages — category 12 (Duplicate concepts) -**Symbol:** `ProvisioningInfo_State` (here, model.ts:57). Also defined in: +**Symbol:** `ProvisioningInfo` (here, model.ts:220) and its sibling state +enum. Also defined in: -- `database/v1/model.ts:148` -- `postgres/v1/model.ts:654` -- `catalogs/v1/model.ts:57` -- `connections/v1/model.ts:131` +- `database/v1/model.ts` +- `postgres/v1/model.ts` +- `catalogs/v1/model.ts` +- `connections/v1/model.ts` -**Issue:** Five separate copies of an enum with mostly-identical values -(`PROVISIONING`, `ACTIVE`, `FAILED`, `DELETING`, `UPDATING`, `DEGRADED` — -`onlinetables` is missing `STATE_UNSPECIFIED` placeholder behaviour vs. -others; pairwise identical in shape). Each carries its own underscore-style -name (finding 1). +**Issue:** Five separate copies of the same provisioning-info concept with +mostly-identical state values (`PROVISIONING`, `ACTIVE`, `FAILED`, `DELETING`, +`UPDATING`, `DEGRADED`). Each package re-declares the type. **Suggested:** hoist to a shared `@databricks/sdk-core/provisioning` module (if cross-cutting), or keep duplicates with **value-level type-checked** @@ -350,7 +299,7 @@ union to guarantee parity. **SDK-wide cleanup.** --- -### 11. Cross-package collision: `DeleteOnlineTableRequest` defined in two packages with different fields — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) +### 9. Cross-package collision: `DeleteOnlineTableRequest` defined in two packages with different fields — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) **Symbol:** `DeleteOnlineTableRequest` (here, model.ts:93) and `featurestore.DeleteOnlineTableRequest` (`featurestore/v1/model.ts:57`). @@ -384,7 +333,7 @@ sibling `GetOnlineTableRequest.name` (model.ts:119) in this very package. --- -### 12. `CreateOnlineTableRequest.table` field name is too generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 10. `CreateOnlineTableRequest.table` field name is too generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `CreateOnlineTableRequest.table?: OnlineTable | undefined` (model.ts:89). @@ -399,7 +348,7 @@ time.** --- -### 13. `OnlineTable.name` is a three-part UC name, not a free-text name — category 19 (Underspecified IDs) and category 1 (Vague/generic) +### 11. `OnlineTable.name` is a three-part UC name, not a free-text name — category 19 (Underspecified IDs) and category 1 (Vague/generic) **Symbol:** `OnlineTable.name?: string | undefined` (model.ts:125). JSDoc: "Full three-part (catalog, schema, table) name of the table." @@ -437,7 +386,7 @@ inconsistency.** --- -### 14. `OnlineTable.tableServingUrl` repeats "table" — category 8 (Redundant suffixes) +### 12. `OnlineTable.tableServingUrl` repeats "table" — category 8 (Redundant suffixes) **Symbol:** `OnlineTable.tableServingUrl?: string | undefined` (model.ts:131). @@ -452,7 +401,7 @@ this table" — `servingUrl` reads the same. --- -### 15. `OnlineTable.unityCatalogProvisioningState` is overly verbose — category 7 (Overly verbose) +### 13. `OnlineTable.unityCatalogProvisioningState` is overly verbose — category 7 (Overly verbose) **Symbol:** `OnlineTable.unityCatalogProvisioningState?: ProvisioningInfo_State | undefined` (model.ts:137). 31 characters. @@ -472,12 +421,10 @@ Reasonable parallel names would be: is shorter and the JSDoc covers the UC scoping. **Suggested:** `provisioningState`. The JSDoc retains the disambiguation. -This also lines up with finding 1 (rename of the enum type to -`ProvisioningState`) — the field and type names become naturally consistent. --- -### 16. `OnlineTable.status` vs `OnlineTable.unityCatalogProvisioningState` — category 17 (Inconsistent action verbs) and category 6 (Misleading names) +### 14. `OnlineTable.status` vs `OnlineTable.unityCatalogProvisioningState` — category 17 (Inconsistent action verbs) and category 6 (Misleading names) **Symbols:** `OnlineTable.status` (model.ts:129), `OnlineTable.unityCatalogProvisioningState` (model.ts:137). @@ -496,11 +443,11 @@ not `status` — surprising. **Suggested:** rename `status` to `syncStatus` or `dataSyncStatus` to make clear it is about the *data pipeline*, not the entity. Pair with -`provisioningState` (finding 15) for the UC-side entity state. +`provisioningState` (finding 13) for the UC-side entity state. --- -### 17. `OnlineTableStatus.detailedState` vs `OnlineTableStatus.detailedStatus` — category 17 (Inconsistent action verbs) and category 12 (Duplicate concepts) +### 15. `OnlineTableStatus.detailedState` vs `OnlineTableStatus.detailedStatus` — category 17 (Inconsistent action verbs) and category 12 (Duplicate concepts) **Symbols:** `OnlineTableStatus.detailedState` (model.ts:183), `OnlineTableStatus.detailedStatus` (model.ts:187). @@ -525,7 +472,7 @@ forms a coherent shape. **Flag at port time.** --- -### 18. `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` all share `…Status` suffix — category 20 (Type-suffix tautology) — *pass with note* +### 16. `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` all share `…Status` suffix — category 20 (Type-suffix tautology) — *pass with note* **Symbols:** `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` (model.ts:71, 238, 102, 226). @@ -539,7 +486,7 @@ disambiguate from `OnlineTableSpec`/state enums. The `Failed` and `Provisioning` variants are also generic when read in isolation — there could be many "failed status" or "provisioning status" types in the SDK (and there are — see `database.SyncedTableProvisioningStatus`, -finding 19 below). +finding 17 below). **Suggested:** consider prefixing with the parent concept — e.g. `OnlineTableContinuousUpdate`, `OnlineTableTriggeredUpdate`, @@ -548,7 +495,7 @@ with note**, flag cross-package overlap below. --- -### 19. Cross-package overlap: `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` ↔ `database.SyncedTable*Status` — category 12 (Duplicate concepts) +### 17. Cross-package overlap: `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` ↔ `database.SyncedTable*Status` — category 12 (Duplicate concepts) **Symbols:** - `onlinetables.ContinuousUpdateStatus` ↔ `database.SyncedTableContinuousUpdateStatus` @@ -559,7 +506,7 @@ with note**, flag cross-package overlap below. **Issue:** All four pairs model the same shape (fields are identical or near-identical). `database` adds a `SyncedTable` prefix to each — disambiguates within `@databricks/sdk-core` if these were merged, but creates a duplicate -type surface across packages. Same root cause as finding 8 (`OnlineTableState` +type surface across packages. Same root cause as finding 6 (`OnlineTableState` ↔ `SyncedTableState`). **Suggested:** harmonise — define once in `@databricks/sdk-onlinetables` or @@ -567,7 +514,7 @@ in `@databricks/sdk-core` and re-export. **SDK-wide cleanup.** --- -### 20. `PipelineProgress.latestVersionCurrentlyProcessing` is awkward — category 7 (Overly verbose) and category 13 (Verb-tense inconsistency) +### 18. `PipelineProgress.latestVersionCurrentlyProcessing` is awkward — category 7 (Overly verbose) and category 13 (Verb-tense inconsistency) **Symbol:** `PipelineProgress.latestVersionCurrentlyProcessing?: number | undefined` (model.ts:207). 32 characters. @@ -600,7 +547,7 @@ upstream and port-time fix.** --- -### 21. `PipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` mixed nouns — category 17 (Inconsistent action verbs) and category 8 (Redundant suffixes) +### 19. `PipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` mixed nouns — category 17 (Inconsistent action verbs) and category 8 (Redundant suffixes) **Symbols:** `PipelineProgress.syncedRowCount` (model.ts:209), `PipelineProgress.totalRowCount` (model.ts:211), @@ -629,7 +576,7 @@ the parent type name `PipelineProgress` — though circular). --- -### 22. `PipelineProgress.estimatedCompletionTimeSeconds` unit-suffix is fine — *pass* +### 20. `PipelineProgress.estimatedCompletionTimeSeconds` unit-suffix is fine — *pass* **Symbol:** `PipelineProgress.estimatedCompletionTimeSeconds` (model.ts:215). @@ -643,19 +590,19 @@ preference. **Pass.**) --- -### 23. `OnlineTableSpec.sourceTableFullName` — category 8 (Redundant suffixes) and category 19 (Underspecified IDs) — see finding 13 +### 21. `OnlineTableSpec.sourceTableFullName` — category 8 (Redundant suffixes) and category 19 (Underspecified IDs) — see finding 11 **Symbol:** `OnlineTableSpec.sourceTableFullName?: string | undefined` (model.ts:156). -Already covered in finding 13. **Pass with note** — `Full` qualifier is +Already covered in finding 11. **Pass with note** — `Full` qualifier is redundant when JSDoc already specifies "Three-part (catalog, schema, table) name". `sourceTableName` would suffice. Cross-reference `featurestore.PublishTableRequest.sourceTableName` (no `Full`). --- -### 24. `OnlineTableSpec.timeseriesKey` vs `OnlineTableSpec.primaryKeyColumns` (singular vs plural) — category 9 (Singular/plural mismatch) +### 22. `OnlineTableSpec.timeseriesKey` vs `OnlineTableSpec.primaryKeyColumns` (singular vs plural) — category 9 (Singular/plural mismatch) **Symbols:** `OnlineTableSpec.primaryKeyColumns?: string[]` (model.ts:158), `OnlineTableSpec.timeseriesKey?: string` (model.ts:160). @@ -676,7 +623,7 @@ single-column scalar. --- -### 25. `OnlineTableSpec.performFullCopy` is a verb-as-field — category 13 (Verb-tense inconsistency) and category 6 (Misleading names) +### 23. `OnlineTableSpec.performFullCopy` is a verb-as-field — category 13 (Verb-tense inconsistency) and category 6 (Misleading names) **Symbol:** `OnlineTableSpec.performFullCopy?: boolean | undefined` (model.ts:169). @@ -694,7 +641,7 @@ SDK-wide `enable*` boolean pattern). Cross-reference --- -### 26. `OnlineTableSpec.pipelineId` is server-generated — category 6 (Misleading names) — *pass with note* +### 24. `OnlineTableSpec.pipelineId` is server-generated — category 6 (Misleading names) — *pass with note* **Symbol:** `OnlineTableSpec.pipelineId?: string | undefined` (model.ts:171). JSDoc: "ID of the associated pipeline. Generated by the server - cannot be @@ -711,34 +658,29 @@ input/output), not a naming bug. --- -### 27. `OnlineTableSpec.schedulingPolicy` discriminated-union case names use verb prefixes — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) +### 25. `OnlineTableSpec.schedulingPolicy` discriminated-union case names use verb prefixes — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) **Symbol:** `OnlineTableSpec.schedulingPolicy` $case literals `'runContinuously'` / `'runTriggered'` (model.ts:145, 150). **Issue:** Each `$case` literal is a verb phrase: `runContinuously` (verb + -adverb), `runTriggered` (verb + past-participle). The companion types are -`OnlineTableSpec_ContinuousSchedulingPolicy` and -`OnlineTableSpec_TriggeredSchedulingPolicy` (noun-suffixed). +adverb), `runTriggered` (verb + past-participle). The verb-phrase form +mirrors the wire field names `run_continuously` / `run_triggered` — which +themselves model the operation ("run continuously vs. run triggered"). -The mixed POS (case name is a verb-phrase, type name is a noun-phrase) is -ungrammatical. Reading code: +Reading code: ```ts spec.schedulingPolicy = { $case: 'runContinuously', runContinuously: {} }; // ^^^^^^^^^^^^^^^^^ // verb phrase used as a literal key ``` -The verb-phrase form mirrors the wire field names `run_continuously` / -`run_triggered` — which themselves model the operation ("run continuously -vs. run triggered"). - **Suggested:** rename `$case` literals to noun-phrase form (`'continuous'` / -`'triggered'`) to match the companion type names. **Flag at port time.** +`'triggered'`). **Flag at port time.** --- -### 28. `CreateOnlineTableRequest` and `GetOnlineTableRequest` and `DeleteOnlineTableRequest` repeat `OnlineTable` — category 7 (Overly verbose) — *pass, SDK-wide pattern* +### 26. `CreateOnlineTableRequest` and `GetOnlineTableRequest` and `DeleteOnlineTableRequest` repeat `OnlineTable` — category 7 (Overly verbose) — *pass, SDK-wide pattern* **Symbols:** `CreateOnlineTableRequest`, `DeleteOnlineTableRequest`, `GetOnlineTableRequest` (model.ts:87, 93, 117). @@ -750,14 +692,14 @@ package qualifies. **Pass on package consistency.** --- -### 29. `Client` class name — category 1 (Vague/generic) — *pass* +### 27. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-onlinetables/v1.Client`). **Pass.** --- -### 30. `Client.createOnlineTable` etc. — *pass* +### 28. `Client.createOnlineTable` etc. — *pass* **Symbols:** `Client.createOnlineTable` (client.ts:67), `Client.deleteOnlineTable` (client.ts:108), `Client.getOnlineTable` @@ -773,7 +715,7 @@ SDK-wide convention. **Pass.** --- -### 31. `Client.createOnlineTableWaiter` returns a `CreateOnlineTableWaiter` — category 14 (Go/Java-style names) +### 29. `Client.createOnlineTableWaiter` returns a `CreateOnlineTableWaiter` — category 14 (Go/Java-style names) **Symbol:** `Client.createOnlineTableWaiter` (client.ts:92), returns `CreateOnlineTableWaiter` (client.ts:152). @@ -797,7 +739,7 @@ waiter naming policy.** --- -### 32. `CreateOnlineTableWaiter.wait` and `CreateOnlineTableWaiter.done` — *pass* +### 30. `CreateOnlineTableWaiter.wait` and `CreateOnlineTableWaiter.done` — *pass* **Symbols:** `CreateOnlineTableWaiter.wait` (client.ts:163), `CreateOnlineTableWaiter.done` (client.ts:207). @@ -806,7 +748,7 @@ Standard. **Pass.** --- -### 33. `StillRunningError` class is internal but module-scoped — category 4 (Underscores in TS identifiers) — *pass* +### 31. `StillRunningError` class is internal but module-scoped — *pass* **Symbol:** `class StillRunningError extends Error {}` (client.ts:39). @@ -815,7 +757,7 @@ retry"). **Pass.** --- -### 34. `host` / `httpClient` / `logger` / `userAgent` private fields — *pass* +### 32. `host` / `httpClient` / `logger` / `userAgent` private fields — *pass* **Symbols:** Private fields on `Client` (client.ts:42–48). Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but @@ -823,7 +765,7 @@ matches the project rule (`HttpClient`, `Url` would be flagged, but --- -### 35. `PACKAGE_SEGMENT` constant SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) +### 33. `PACKAGE_SEGMENT` constant SCREAMING_SNAKE — category 4 **Symbol:** `PACKAGE_SEGMENT` (client.ts:34). @@ -839,7 +781,7 @@ SDK-wide cleanup**, do not fix in isolation. --- -### 36. Comment on `PACKAGE_SEGMENT` is a sentence-fragment in lowercase — category 14 (Go/Java-style names) — *pass* +### 34. Comment on `PACKAGE_SEGMENT` is a sentence-fragment in lowercase — category 14 (Go/Java-style names) — *pass* The JSDoc comment at client.ts:33 ("Package identity segment for this client to be used in the User-Agent header.") is fine — proper sentence, ends with @@ -847,7 +789,7 @@ a period (matches `.agent/rules` / user CLAUDE.md style). --- -### 37. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 35. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` interface (utils.ts:15). @@ -861,7 +803,7 @@ any fix must apply everywhere). --- -### 38. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 36. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). @@ -887,23 +829,21 @@ store) under two type families. Cross-package collisions in this audit: | ---------------------------------- | --------------------------------------------- | | `OnlineTable` | `SyncedDatabaseTable` / `SyncedTable` | | `OnlineTableSpec` | `SyncedTableSpec` | -| `OnlineTableState` | `SyncedTableState` (12 values, has a typo) | +| `OnlineTableState` | `SyncedTableState` (12 values, wire-typo) | | `OnlineTableStatus` | `SyncedTableStatus` | | `ContinuousUpdateStatus` | `SyncedTableContinuousUpdateStatus` | | `TriggeredUpdateStatus` | `SyncedTableTriggeredUpdateStatus` | | `FailedStatus` | `SyncedTableFailedStatus` | | `ProvisioningStatus` | `SyncedTableProvisioningStatus` | | `PipelineProgress` | `SyncedTablePipelineProgress` | -| `ProvisioningInfo_State` | `ProvisioningInfo_State` (also in 4 pkgs) | | `ProvisioningInfo` (empty) | `ProvisioningInfo` (empty) | This is the highest-cost duplication observed in the audit. **Strong P0 recommendation:** consolidate. Options: 1. **Pick one canonical package** (`onlinetables` is the shorter, cleaner - surface — no `SyncedTable` prefix, no spelling typos, no SCREAMING_SNAKE - on most values). Have `database` re-export from `onlinetables` with - deprecation notes. + surface — no `SyncedTable` prefix, no wire-string typos). Have + `database` re-export from `onlinetables` with deprecation notes. 2. **Hoist all `Online/Synced{Table…}` types** into `@databricks/sdk-core/synctables` (or similar) and re-export from both service packages. @@ -916,21 +856,16 @@ recommendation:** consolidate. Options: `onlinetables.DeleteOnlineTableRequest.name` vs. `featurestore.DeleteOnlineTableRequest.onlineTableName`. Already covered in -finding 11. Harmonise on `name`. +finding 9. Harmonise on `name`. --- -### C. Enum-naming convention divergence: `OnlineTableState` (flat) vs `ProvisioningInfo_State` (underscored) +### C. `SYNCED_TABLED_OFFLINE` wire-level typo -Both enums in **the same file** use different naming conventions: - -```ts -export enum OnlineTableState { ... } // model.ts:7 — flat -export enum ProvisioningInfo_State { ... } // model.ts:57 — underscored -``` - -Same generator, same file. The right SDK-wide policy is to always emit flat -names (strip the proto namespace). **Flag for generator.** +`database.SyncedTableState` includes the value `SYNCED_TABLED_OFFLINE` +(extra `D`). This is on the wire and locks consumers into the misspelling. +Coordinate a protocol-level fix with the API team; the SDK alone cannot +correct it without breaking compatibility. **Flag for protocol team.** --- @@ -938,31 +873,31 @@ names (strip the proto namespace). **Flag for generator.** | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, cross-package collisions) | 7 | #1, #2, #5, #11, #17, #25, #35, **and** cross-package A | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 13 | #3, #4, #6, #7, #8, #12, #13, #14, #15, #16, #19, #20, #21, #23, #27 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 9 | #9, #10, #18, #24, #26, #28, #31, #37, #38 | -| **Pass / acceptable** | 9 | #18, #22, #24, #26, #28, #29, #30, #32, #33, #34, #36 | +| **High** (style guide violations, cross-package collisions) | 5 | #3, #9, #15, #23, #33, **and** cross-package A | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 13 | #1, #2, #4, #5, #6, #10, #11, #12, #13, #14, #17, #18, #19, #21, #25 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 9 | #7, #8, #16, #22, #24, #26, #29, #35, #36 | +| **Pass / acceptable** | 9 | #16, #20, #22, #24, #26, #27, #28, #30, #31, #32, #34 | --- ## Top fixes (highest local return) -1. **#11** — harmonise `DeleteOnlineTableRequest.name` vs. +1. **#9** — harmonise `DeleteOnlineTableRequest.name` vs. `featurestore.DeleteOnlineTableRequest.onlineTableName` field name. Quick cross-package fix. -2. **#14** — rename `OnlineTable.tableServingUrl` → `servingUrl`. Local, +2. **#12** — rename `OnlineTable.tableServingUrl` → `servingUrl`. Local, no other consumers. -3. **#15** — rename `OnlineTable.unityCatalogProvisioningState` → +3. **#13** — rename `OnlineTable.unityCatalogProvisioningState` → `provisioningState`. Local. -4. **#12** — rename `CreateOnlineTableRequest.table` → `onlineTable`. Local +4. **#10** — rename `CreateOnlineTableRequest.table` → `onlineTable`. Local port-time fix. -5. **#17** — rename `OnlineTableStatus.detailedState` → `state` and +5. **#15** — rename `OnlineTableStatus.detailedState` → `state` and `detailedStatus` → `statusDetails` / `details`. Local readability win. -6. **#20** — rename `PipelineProgress.latestVersionCurrentlyProcessing` → +6. **#18** — rename `PipelineProgress.latestVersionCurrentlyProcessing` → `lastProcessedVersion`. Matches sibling `lastProcessedCommitVersion`. -7. **#21** — rename `PipelineProgress.syncProgressCompletion` → +7. **#19** — rename `PipelineProgress.syncProgressCompletion` → `completionRatio`. Local. -8. **#25** — rename `OnlineTableSpec.performFullCopy` → `enableFullCopy` +8. **#23** — rename `OnlineTableSpec.performFullCopy` → `enableFullCopy` (matches SDK `enable*` boolean pattern). --- @@ -971,12 +906,10 @@ names (strip the proto namespace). **Flag for generator.** 1. **Cross-package A** — consolidate `OnlineTable` vs `SyncedTable` type families into one canonical surface. -2. **#1** — strip proto-namespace underscores from generated enum types - (`ProvisioningInfo_State` → `ProvisioningState`). -3. **#5** — `UpperCamelCase` enum members (string value preserved as wire +2. **Cross-package C** — fix the `SYNCED_TABLED_OFFLINE` wire-string typo + at the protocol layer. +3. **#3** — `UpperCamelCase` enum members (string value preserved as wire form). -4. **#35** — `PACKAGE_SEGMENT` → `packageSegment`. -5. **#31** — settle waiter naming convention (`*Waiter` vs `*Poller` vs +4. **#33** — `PACKAGE_SEGMENT` → `packageSegment`. +5. **#29** — settle waiter naming convention (`*Waiter` vs `*Poller` vs inline `*AndWait`). - ---- diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md index c6433d47..8df316c2 100644 --- a/.agent/naming-audit/permissions.md +++ b/.agent/naming-audit/permissions.md @@ -3,19 +3,19 @@ **Path:** `packages/permissions/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-object permissions — get, set, update, and inspect ACLs (access control lists) attached to Databricks workspace objects (clusters, jobs, notebooks, dashboards, pipelines, registered models, queries, repos, files, instance pools, etc.). Distinct from `grants` (Unity Catalog privileges on UC securables), though the two surfaces overlap conceptually and lexically. -**Total weird names flagged:** 34 +**Total weird names flagged:** 33 ## Summary | Severity | Count | | --- | --- | -| High | 12 | +| High | 11 | | Medium | 14 | | Low | 4 | | Observation | 4 | The permissions package contains 9 generated types, 1 enum, and 4 client methods, plus utility helpers. Three thematic problems dominate. (1) The request-as-imperative-verb pattern (`GetObjectPermissions`, `SetObjectPermissions`, `UpdateObjectPermissions`, `GetPermissionLevels`) collides with the verb-noun methods on `Client`, so users write `client.setObjectPermissions(req: SetObjectPermissions)` and the type name looks like a command rather than a payload. (2) The `PermissionLevel` enum mixes acronym-prefix patterns (`CAN_*`, `IS_*`) with redundant suffixes (`CAN_MONITOR` vs `CAN_MONITOR_ONLY`, `CAN_MANAGE_RUN`, `CAN_CREATE_APP`) and includes a sentinel `UNSPECIFIED` whose semantics ("delete this principal") are only discoverable from JSDoc — the value name actively misleads. (3) The package overlaps heavily with `grants` in vocabulary (`Permission`, `PermissionsResponse`, `permissionLevels`) while modelling a completely different concept; the only public type distinguishing this package from its sibling is `AccessControlRequest`/`Response`, both of which use the IAM-style "access control list" pattern that's unique-in-the-SDK. -Two structural warts surface as a result of mechanical proto-to-TS porting: `GetPermissionLevels_Response` uses an embedded underscore (proto FQN flattening) and requires `// eslint-disable` annotations, and every request type tags its path-parameter fields with a verbose `requestObjectType` / `requestObjectId` prefix (rather than `objectType`/`objectId` or just `type`/`id`) — the prefix is wire-format leakage. Finally, `requestObjectType` and `requestObjectId` are typed `string` with a documented closed enumeration of valid values listed verbatim in JSDoc (26 different object types in a single doc-comment), surfacing the "stringly-typed closed enum" anti-pattern that TypeScript's type system would otherwise prevent. +A further structural wart surfaces as a result of mechanical proto-to-TS porting: every request type tags its path-parameter fields with a verbose `requestObjectType` / `requestObjectId` prefix (rather than `objectType`/`objectId` or just `type`/`id`) — the prefix is wire-format leakage. Finally, `requestObjectType` and `requestObjectId` are typed `string` with a documented closed enumeration of valid values listed verbatim in JSDoc (26 different object types in a single doc-comment), surfacing the "stringly-typed closed enum" anti-pattern that TypeScript's type system would otherwise prevent. --- @@ -45,54 +45,48 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get - **Suggested name:** `GetPermissionLevelsRequest` or `PermissionLevelsQuery`. - **Rationale:** Disambiguates request vs response; aligns with #5. -### 5. `GetPermissionLevels_Response` — `src/v1/model.ts:93` -- **Why weird:** Proto-style nested message name with an embedded underscore (`MessageType_FieldName`), illegal under standard TS naming. The codegen has to emit `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directly above the declaration (line 92) and again above the schema declaration (line 158). The identifier is part of the public surface — `index.ts:11` re-exports it — so every downstream consumer is forced to write `GetPermissionLevels_Response` with the underscore in their own code. -- **Category:** 4 (underscores in TS identifier), 14 (proto/Go-style name). -- **Suggested name:** `GetPermissionLevelsResponse` (drop the underscore), or — cascading from #4 — `PermissionLevelsResponse`. -- **Rationale:** Google TypeScript Style Guide §5.2 mandates PascalCase without internal underscores. The proto FQN-flattening trick should be hidden by the generator, not surfaced to the public API. Same problem is documented in `.agent/naming-audit/grants.md` #4–6 for that package. - -### 6. `PermissionLevel.UNSPECIFIED` — `src/v1/model.ts:31` +### 5. `PermissionLevel.UNSPECIFIED` — `src/v1/model.ts:31` - **Why weird:** The enum value `UNSPECIFIED` is overloaded into a sentinel meaning "delete this principal's permissions" — but the *name* says the opposite ("unspecified"). The JSDoc on lines 27–30 clarifies this, but the name itself actively misleads: callers reading `permissionLevel: PermissionLevel.UNSPECIFIED` will reasonably interpret it as "no value set / left blank", not "remove the principal". Worse, the side-effect semantics (mutation) are encoded in what looks like a null-equivalent. - **Category:** 6 (misleading name), 1 (vague). Sentinel-as-enum-value is a Go pattern. - **Suggested name:** Split into a dedicated `Remove` or `Revoke` value (`PermissionLevel.REMOVE` or `PermissionLevel.NONE`) — or, better, model deletion as an absent `permissionLevel` field in PATCH calls (the field is already `optional`) and remove the sentinel entirely. The current name guarantees that anyone reading a diff will be confused about whether `UNSPECIFIED` is a no-op or a destructive action. - **Rationale:** Sentinel-encoded-as-enum-value is an idiom imported from protobuf/Go (`google.protobuf.UNSPECIFIED`) where every enum is required to have a zero value. TypeScript has no such constraint; explicit absence (`undefined`) is idiomatic. -### 7. `PermissionLevel` enum has 20 inconsistently-named values — `src/v1/model.ts:7–32` +### 6. `PermissionLevel` enum has 20 inconsistently-named values — `src/v1/model.ts:7–32` - **Why weird:** Mix of three naming patterns within a single enum: - `CAN_*` (most common): `CAN_MANAGE`, `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`. - `IS_*`: `IS_OWNER`. The lone `IS_*` value mixes copula+predicate, while everything else is modal verb+predicate. - Pseudo-sentinel: `UNSPECIFIED` (see #6). - The `CAN_*` prefix is implied by membership in `PermissionLevel` — a `PermissionLevel` is, by definition, what the principal can do. The redundant `CAN_` prefix on 19 of 20 values is purely a wire-format leak from the Go enum, which followed the same protobuf convention. - **Category:** 2 (redundant enum prefix — flagged explicitly in the task prompt), 17 (inconsistent action verbs within the same enum). -- **Suggested name:** Drop the `CAN_` prefix: `MANAGE`, `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, `USE`, etc. `IS_OWNER` becomes `OWNER`. `UNSPECIFIED` becomes `REMOVE` per #6 (or eliminated). +- **Suggested name:** Drop the `CAN_` prefix: `MANAGE`, `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, `USE`, etc. `IS_OWNER` becomes `OWNER`. `UNSPECIFIED` becomes `REMOVE` per #5 (or eliminated). - **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. The same logic applies here: `PermissionLevel.MANAGE` is shorter, more readable, and just as unambiguous as `PermissionLevel.CAN_MANAGE` (Google TS Style Guide §5.4 prefers concise enum members; protobuf-style prefixes are a wire concern that does not need to leak into the surface). -### 8. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` +### 7. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` - **Why weird:** Two distinct values that differ in name only by the `_ONLY` suffix. The JSDoc (none provided) gives no clue what the difference is. From product context, `CAN_MONITOR` typically grants monitoring AND inherited subset privileges; `CAN_MONITOR_ONLY` strictly limits to monitoring. Cannot infer this from the names — must consult external API docs. - **Category:** 6 (misleading: pair seems exhaustive but `_ONLY` semantics are non-obvious), 17 (inconsistent: no other value uses `_ONLY` to differentiate). - **Suggested name:** Document inline what the difference is, OR rename to `MONITOR_FULL` / `MONITOR_READ_ONLY` / similar pair where the contrast is on the *predicate*, not on a vague `_ONLY` qualifier. - **Rationale:** Whenever an enum exposes "X" and "X_ONLY" with no JSDoc, every caller hits a Stack Overflow question. -### 9. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` — `src/v1/model.ts:17,18` +### 8. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` — `src/v1/model.ts:17,18` - **Why weird:** 28- and 30-character enum members. These values are specific to one object type (`registered-models` in MLflow Model Registry — staging vs production model versions) but live in a universal enum applicable to 25+ object types. Equivalent to having `CAN_MANAGE_DASHBOARD_DRAFTS` or `CAN_MANAGE_NOTEBOOK_REVISIONS` in the same enum: the values are scoped to one domain but visible to all. - **Category:** 18 (long enum values — flagged explicitly in the task prompt), 17 (inconsistent — most values are object-type-agnostic, these two leak object-type semantics into the enum). - **Suggested name:** Possibly `MANAGE_STAGING` / `MANAGE_PRODUCTION` with JSDoc clarifying applicability ("Applies to registered-models only"), or move these MLflow-specific levels into a separate enum. - **Rationale:** Universal enum + object-specific values is a discoverability hazard; users browsing autocomplete will see these as valid choices for clusters/jobs/dashboards. -### 10. `CAN_CREATE_APP` — `src/v1/model.ts:26` -- **Why weird:** Same problem as #9 — object-type-specific value in a universal enum. The `App` here refers to Databricks Apps (a specific object kind); other object types have no equivalent. The `_APP` suffix is also inconsistent with how the rest of the enum names the noun being created (most `CAN_CREATE` is unsuffixed; `CAN_CREATE_APP` is the only one with an explicit noun). +### 9. `CAN_CREATE_APP` — `src/v1/model.ts:26` +- **Why weird:** Same problem as #8 — object-type-specific value in a universal enum. The `App` here refers to Databricks Apps (a specific object kind); other object types have no equivalent. The `_APP` suffix is also inconsistent with how the rest of the enum names the noun being created (most `CAN_CREATE` is unsuffixed; `CAN_CREATE_APP` is the only one with an explicit noun). - **Category:** 18, 17. -- **Suggested name:** Same pattern as #9 — document scope, or partition. -- **Rationale:** See #9. +- **Suggested name:** Same pattern as #8 — document scope, or partition. +- **Rationale:** See #8. -### 11. Concept duplication with `grants` package — cross-package -- **Why weird:** A sibling package `packages/grants/src/v1/` also defines a `Permission*` vocabulary (`PermissionsChange`, `getPermissions`, `updatePermissions`, `GetPermissions_Response`) for a different operation (Unity Catalog privileges on securables). Both packages re-export `Permission`-prefixed types from their `index.ts`. A user reading `import { Permission } from '@databricks/sdk-permissions/v1'` vs `import { PrivilegeAssignment } from '@databricks/sdk-grants/v1'` has no surface-level cue that these belong to disjoint domains. The `permissions` package operates on workspace objects (clusters, jobs, notebooks) via `requestObjectType: string` paths; the `grants` package operates on UC securables (catalogs, schemas, tables) via `securableType: string` paths. The vocabulary overlap obscures this distinction. +### 10. Concept duplication with `grants` package — cross-package +- **Why weird:** A sibling package `packages/grants/src/v1/` also defines a `Permission*` vocabulary (`PermissionsChange`, `getPermissions`, `updatePermissions`) for a different operation (Unity Catalog privileges on securables). Both packages re-export `Permission`-prefixed types from their `index.ts`. A user reading `import { Permission } from '@databricks/sdk-permissions/v1'` vs `import { PrivilegeAssignment } from '@databricks/sdk-grants/v1'` has no surface-level cue that these belong to disjoint domains. The `permissions` package operates on workspace objects (clusters, jobs, notebooks) via `requestObjectType: string` paths; the `grants` package operates on UC securables (catalogs, schemas, tables) via `securableType: string` paths. The vocabulary overlap obscures this distinction. - This same observation appears in `.agent/naming-audit/grants.md` #10 — flagged from the other side of the mirror. - **Category:** 12 (duplicate concepts across packages), 1 (vague top-level package naming). - **Suggested name:** Rename one or both for disambiguation: `permissions` → `workspace-permissions` or `workspace-acl`; `grants` → `unity-catalog-grants` or `uc-privileges`. At minimum the public exports should be non-overlapping (no `Permission` prefix in both). - **Rationale:** The two packages cover non-overlapping concrete operations but use heavily overlapping vocabulary — an enormous discoverability hazard. -### 12. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:81,88,116,124` +### 11. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:81,88,116,124` - **Why weird:** Every request type carries `requestObjectType?: string | undefined`. The JSDoc on line 80 (and identically on 87, 116, 124) lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, clusters, cluster-policies, dashboards, database-projects, dbsql-dashboards, directories, experiments, files, genie, instance-pools, jobs, knowledge-assistants, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, supervisor-agents, vector-search-endpoints, or warehouses"`. The set is closed, well-known to the server, and stable — a perfect fit for a `RequestObjectType` enum or string literal union. The TS SDK ships it as bare `string` with no autocomplete or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) silently 4xx's at runtime. - **Category:** 19 (underspecified ID), 1 (vague: bare `string`), 15 (generic field name). - **Suggested name:** Define `type RequestObjectType = 'alerts' | 'alertsv2' | 'authorization' | 'clusters' | 'cluster-policies' | ...` (string literal union, 26 entries), or an `enum RequestObjectType` with kebab-cased values. The JSDoc explicitly enumerates the values; TypeScript should encode that enumeration. @@ -102,85 +96,85 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get ## Medium severity -### 13. `requestObjectType` / `requestObjectId` prefix — `src/v1/model.ts:81,83,88,89,117,119,125,127` +### 12. `requestObjectType` / `requestObjectId` prefix — `src/v1/model.ts:81,83,88,89,117,119,125,127` - **Why weird:** All four request types prefix their two path parameters with `request`: `requestObjectType` and `requestObjectId`. The `request` prefix is wire-format leakage (the Databricks REST path uses `:request_object_type` and `:request_object_id` as URL path placeholders, presumably from an older API spec). On the TypeScript surface, every field is by definition part of a *request* — the `request` prefix carries zero information. - **Category:** 7 (overly verbose / redundant prefix), 14 (wire-format leak), 15 (generic field name). - **Suggested name:** `objectType` and `objectId`. The doc-comment on `requestObjectId` already calls it "The id of the request object" — drop the wire-format jargon and just say "object id". - **Rationale:** Compare `GetObjectPermissions { requestObjectType, requestObjectId }` to `GetObjectPermissions { objectType, objectId }`. The latter reads as plain English. The `request` prefix is the same kind of cruft that `requestId` would have if it appeared in a `Request` type. -### 14. `principalName` discriminated union — `src/v1/model.ts:35–51,56–72` +### 13. `principalName` discriminated union — `src/v1/model.ts:35–51,56–72` - **Why weird:** The discriminated union pattern is elegant in TS, but the field name `principalName` is misleading because the values inside are not all "names" — `servicePrincipalName` is documented as "application ID of a service principal" (line 48), which is a UUID, not a name. Calling the carrier field `principalName` and the SP variant `servicePrincipalName` together imply "principal name = service principal name = the SP's name", but the SP variant is the application *ID*, distinct from the SP's display name. - **Category:** 6 (misleading), 19 (underspecified ID), 15 (overloaded "name"). -- **Suggested name:** Rename outer field to `principal` (per `grants` package convention, see #15) and rename the SP variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or document explicitly that `servicePrincipalName` is "the SP's application UUID, not its display name". +- **Suggested name:** Rename outer field to `principal` (per `grants` package convention, see #14) and rename the SP variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or document explicitly that `servicePrincipalName` is "the SP's application UUID, not its display name". - **Rationale:** Same field name leaks "name" semantics onto a value that's a UUID. Type system can encode this with proper variant naming. -### 15. `principalName` vs `principal` cross-package — `src/v1/model.ts:35,56` (this package) vs `grants/src/v1/model.ts:22,33,69` (grants package) +### 14. `principalName` vs `principal` cross-package — `src/v1/model.ts:35,56` (this package) vs `grants/src/v1/model.ts:22,33,69` (grants package) - **Why weird:** `permissions` uses `principalName?: { $case: 'userName' | 'groupName' | 'servicePrincipalName' }` — a typed discriminated union. `grants` uses `principal: string` — a free-form string with a JSDoc-only constraint ("user email address or group name"). Same concept, two utterly different representations across sister packages. A user familiar with one will not be productive in the other. - **Category:** 12 (duplicate concept), 17 (inconsistent shapes for the same domain object). - **Suggested name:** Pick one across the SDK. The `permissions` package's discriminated union is strictly more type-safe and should be the canonical representation. - **Rationale:** Consistency. Two packages, two ways to spell "who is this for". The audit on `grants` (#12) flagged this from the other side. -### 16. `displayName` on `AccessControlResponse` — `src/v1/model.ts:74` +### 15. `displayName` on `AccessControlResponse` — `src/v1/model.ts:74` - **Why weird:** `displayName?: string | undefined` doc-comment "Display name of the user or service principal." (line 73). But the response also carries `principalName` (line 56) which is the carrier-by-identity. Two name-like fields on the same response and the relationship is JSDoc-only. Worse, the JSDoc *doesn't* say "Display name of the user **or group** or service principal" — it omits groups, possibly because groups don't have display names — but the type allows `principalName.$case === 'groupName'` paired with a `displayName` value, which then has no specified semantics. - **Category:** 6 (misleading), 1 (vague: groups + displayName combo undocumented). - **Suggested name:** Keep `displayName` but expand doc-comment to cover all three principal kinds. - **Rationale:** Cross-checking variant + display-name semantics is an integration footgun. -### 17. `allPermissions: Permission[]` field — `src/v1/model.ts:76` +### 16. `allPermissions: Permission[]` field — `src/v1/model.ts:76` - **Why weird:** `allPermissions?: Permission[] | undefined` with JSDoc "All permissions." — minimal information value in the comment. The qualifier "all" suggests there's a "some permissions" variant that doesn't exist. Internally, the type just lists every effective permission (direct + inherited) — so the `all` prefix is the wire-format way of saying "the merged result". Stripping `all` would lose nothing. - **Category:** 7 (overly verbose), 1 (vague qualifier), 15 (generic field name on a typed array). - **Suggested name:** `permissions: Permission[]` (matches the type-name plural). The field would read `AccessControlResponse.permissions` — natural English. - **Rationale:** Field names that re-state the parent type or carry vague qualifiers add noise. The `all` qualifier here implies a `some`/`partial` companion that doesn't exist. -### 18. `Permission` type — `src/v1/model.ts:98` +### 17. `Permission` type — `src/v1/model.ts:98` - **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance of `Permission` here is really an "effective permission" — a permission level paired with inheritance metadata. The name `Permission` alone is the second-most-overloaded noun in the SDK (after `Client`). - **Category:** 1 (vague), 12 (cross-package collision: `grants` also exports `Permission`-prefixed types). - **Suggested name:** `EffectivePermission` (matches the doc semantics) or `PermissionGrant` (clarifies that this is a grant, not the concept of permission abstractly). - **Rationale:** `Permission` as a standalone PascalCase noun is so common across IAM systems that it's nearly content-free without qualification. -### 19. `PermissionsDescription` — `src/v1/model.ts:104` +### 18. `PermissionsDescription` — `src/v1/model.ts:104` - **Why weird:** Type carries `permissionLevel?: PermissionLevel | undefined` and `description?: string | undefined`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. Should be `PermissionLevelDescription` (singular). Also, the suffix `Description` is generic — the type is effectively a tuple of (level, description-text); it's the "metadata about a single permission level" record. - **Category:** 9 (singular/plural mismatch — `Permissions` plural for a single-level descriptor), 1 (generic suffix), 15 (vague field `description: string`). - **Suggested name:** `PermissionLevelDescription` or `PermissionLevelInfo`. - **Rationale:** Singular/plural matters; one descriptor = one level. -### 20. `PermissionsResponse` — `src/v1/model.ts:109` +### 19. `PermissionsResponse` — `src/v1/model.ts:109` - **Why weird:** Returned from THREE different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, `accessControlList` — i.e. it's "an ACL with metadata", not "a Permissions response". Name is generic; the *content* is the more meaningful concept ("ObjectAcl" or "AccessControlList"). - **Category:** 1 (vague), 7 (Response suffix tautology), 20 (type-suffix tautology — `Permissions` + `Response` adds no info beyond `AccessControlList`). - **Suggested name:** `ObjectAcl`, `ObjectPermissions`, or `AccessControlList`. Drop the `Response` suffix per the SDK-wide convention that responses are returned values, not named-as-such types. - **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental to it being a return value. -### 21. `accessControlList` field — `src/v1/model.ts:112,120,128` +### 20. `accessControlList` field — `src/v1/model.ts:112,120,128` - **Why weird:** Appears in three types (`PermissionsResponse`, `SetObjectPermissions`, `UpdateObjectPermissions`). The field is typed `AccessControlRequest[]` in the two request types and `AccessControlResponse[]` in the response — asymmetric typing under one field name. The conventional shorthand for "access control list" is "ACL" — the field could be `acl` (3 chars vs 18). Or just `entries` since the surrounding type already says "permissions" / "object permissions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology — field repeats type info), 17 (asymmetric: same field, different element types). - **Suggested name:** `acl: AccessControlEntry[]` or `entries: AccessControlEntry[]`. - **Rationale:** "Access control list" is verbose; "ACL" is standard. The asymmetric typing pattern is worth flattening. -### 22. `inherited` boolean field — `src/v1/model.ts:100` +### 21. `inherited` boolean field — `src/v1/model.ts:100` - **Why weird:** Bare `inherited?: boolean | undefined` on `Permission`. Boolean fields starting with a verb (`is*`, `has*`, `was*`) are easier to read at call sites. The current name reads `if (permission.inherited)` — fine, but `if (permission.isInherited)` is more idiomatic. - **Category:** 14 (Go/Java-style: Go boolean fields commonly drop the `is`/`has` prefix, TS convention varies). - **Suggested name:** `isInherited`. - **Rationale:** Google TS Style Guide §5.3 recommends boolean prefixes for readability. The codebase uses both conventions but `is*`-prefixed booleans are more common in IAM contexts. -### 23. `inheritedFromObject: string[]` — `src/v1/model.ts:101` +### 22. `inheritedFromObject: string[]` — `src/v1/model.ts:101` - **Why weird:** Plural field name (`Object`) typed as `string[]` of object identifiers. The "Object" suffix is singular but the type is plural — minor mismatch. More importantly, the JSDoc is missing entirely (line 101 has no comment) so the reader has to infer that this is the chain of inheritance paths from which this permission was derived. Each element is presumably an object path; the typing is bare `string`. - **Category:** 9 (singular/plural mismatch), 19 (underspecified ID), 1 (vague — no JSDoc). - **Suggested name:** `inheritedFromObjects: string[]` (plural for plural), or `inheritanceChain: string[]`. Document the element format. - **Rationale:** Plurality should match the type's plurality; semantics should be JSDoc'd. -### 24. `Client` — `src/v1/client.ts:41` +### 23. `Client` — `src/v1/client.ts:41` - **Why weird:** Top-level class named `Client`. Generic across every generated package. Users importing `Client` from multiple permission-adjacent packages (`@databricks/sdk-permissions`, `@databricks/sdk-grants`, `@databricks/sdk-accountaccesscontrol`) must alias all three. - **Category:** 1 (vague), 12 (cross-package name clash). - **Suggested name:** `PermissionsClient`. - **Rationale:** SDK convention in AWS, Azure, GitHub Octokit, etc. is service-prefixed client class names. -### 25. `requestObjectType` doc-comment duplication — `src/v1/model.ts:80,87,116,124` +### 24. `requestObjectType` doc-comment duplication — `src/v1/model.ts:80,87,116,124` - **Why weird:** Four identical 1-line doc-comments listing all 26 valid object types. The list is 280 characters long and is copy-pasted verbatim into every request type. Any change requires four parallel edits. - **Category:** Observation, 17 (consistency — all four are identical, so this isn't an inconsistency, but it is fragile). -- **Suggested name:** Define `type RequestObjectType` (see #12) and link to it from a single source of truth. +- **Suggested name:** Define `type RequestObjectType` (see #11) and link to it from a single source of truth. - **Rationale:** DRY for documentation, type-safe for callers. -### 26. `flattenQueryParams` (utility) — `src/v1/utils.ts:123` +### 25. `flattenQueryParams` (utility) — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package — `permissions` client doesn't take query parameters in any of its four methods. Dead-looking export, identical to the same wart documented in `.agent/naming-audit/grants.md` #37. - **Category:** 11 (effectively-internal exports), Observation. - **Suggested name:** Remove (or move to a shared `@databricks/sdk-core` util). @@ -190,25 +184,25 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get ## Low severity -### 27. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 28. `readAll` (utility) — `src/v1/utils.ts:40` +### 27. `readAll` (utility) — `src/v1/utils.ts:40` - **Why weird:** Internal helper name generic to the point of meaninglessness; clashes cognitively with `Array.prototype` methods and Web Streams APIs. Same pattern called out in `.agent/naming-audit/grants.md` #38. The function name is also a direct Go-port of `io.ReadAll`. - **Category:** 1 (vague), 14 (Go-style). - **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. - **Rationale:** Cross-package consistency. -### 29. `HttpCallOptions` — `src/v1/utils.ts:15` +### 28. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Another `Options`-suffixed type; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix), 17 (inconsistent — internal struct shouldn't share a suffix with the user-facing CallOptions). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. Same finding as `grants.md` #40. -### 30. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:146` +### 29. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:146` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 156). The request type `UpdateObjectPermissions` is symmetric in name to `SetObjectPermissions` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. A user reading both method names side-by-side (`set...` and `update...`) might reasonably assume both perform full replacement. - **Category:** 17 (inconsistent action verbs), Observation. - **Suggested name:** `patchObjectPermissions` for the PATCH method, OR explicit JSDoc on `update*` clarifying merge semantics. @@ -218,18 +212,18 @@ Two structural warts surface as a result of mechanical proto-to-TS porting: `Get ## Observations -### 31. Three response paths converge on `PermissionsResponse` +### 30. Three response paths converge on `PermissionsResponse` `getObjectPermissions`, `setObjectPermissions`, and `updateObjectPermissions` all return the same `PermissionsResponse` type (`client.ts:70,123,149`). This is fine functionally but means callers can't distinguish "the state I just wrote" from "the state I just read" by type — only by which method was called. For an audit log or comparison flow, this loses information. Naming-adjacent because the type carries no read/write/post-update distinction. - **Category:** Observation. -### 32. Sentinel value `UNSPECIFIED` in PATCH is the only mutation-state encoded in an enum -The `PermissionLevel.UNSPECIFIED` sentinel (see #6) is unique in the SDK: it's the only enum value across `permissions`, `grants`, `accountaccesscontrol`, and `iam` that doubles as a deletion marker when sent in a PATCH body. Most APIs model this with a separate request body shape (e.g. `removals: Principal[]`) or with HTTP DELETE. Encoding "remove me" as an enum value alongside "let me have this permission" is unusual. +### 31. Sentinel value `UNSPECIFIED` in PATCH is the only mutation-state encoded in an enum +The `PermissionLevel.UNSPECIFIED` sentinel (see #5) is unique in the SDK: it's the only enum value across `permissions`, `grants`, `accountaccesscontrol`, and `iam` that doubles as a deletion marker when sent in a PATCH body. Most APIs model this with a separate request body shape (e.g. `removals: Principal[]`) or with HTTP DELETE. Encoding "remove me" as an enum value alongside "let me have this permission" is unusual. - **Category:** Observation, 6 (misleading). -### 33. Doc-comment list of object types is potentially stale +### 32. Doc-comment list of object types is potentially stale The hardcoded list in `requestObjectType` doc-comments includes `database-projects`, `genie`, `knowledge-assistants`, `supervisor-agents` — all relatively new product surfaces. The list will need updating with every new permission-able workspace object. As-is the SDK has 26; if not regularly synced with the server, the JSDoc will drift. - **Category:** Observation. -### 34. No pagination — all methods are unpaginated single-call +### 33. No pagination — all methods are unpaginated single-call Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods, see `grants.md` #41), `permissions` has no listing operation. Every method here is by-object-id; there's no "list all permissioned objects" surface. This is correct for the API but worth noting because users coming from `grants` (or `accountaccesscontrol`) might expect parallel list semantics. Naming-adjacent because the absence of `list*` here aligns the method-vocabulary differently than its sibling packages. - **Category:** Observation. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index e522f69e..8ea9f1f8 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -14,11 +14,11 @@ | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------------------- | -| High | 26 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions, plural `Pipelines` prefix. | -| Medium | 38 | Underscores, redundant prefixes/suffixes, vague names, acronym casing, generic IDs. | +| High | 23 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions, plural `Pipelines` prefix. | +| Medium | 38 | Redundant enum prefixes, vague names, acronym casing, generic IDs. | | Low | 21 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 7 | Patterns spanning the whole file (proto leakage, branding history). | -| **Total** | **92** | | +| Observations | 6 | Patterns spanning the whole file (branding history, plural/singular split). | +| **Total** | **88** | | Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. @@ -86,97 +86,85 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelines` and to disambiguate from `listUpdates`/`listEvents`. - **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelines`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. -### H11. `PipelineState_PipelineState` enum — underscore suffix tautology -- **Location:** `model.ts:392` (`export enum PipelineState_PipelineState`). -- **Category:** 20 (type-suffix tautology), 4 (underscores). -- **Suggestion:** Rename the enum to `PipelineState`. -- **Rationale:** `PipelineState_PipelineState.RUNNING` reads as "state.state.RUNNING". Same pattern as `ScdType_ScdType` (H12). - -### H12. `ScdType_ScdType` enum — underscore suffix tautology and cryptic acronym -- **Locations:** `model.ts:415` (`export enum ScdType_ScdType`), `index.ts:32`, `index.ts:150`. -- **Category:** 20 (suffix tautology), 4 (underscores), 5 (cryptic abbreviation). -- **Suggestion:** Rename `ScdType_ScdType` → `ScdType`. Better: rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — and the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). -- **Rationale:** Same issue as H11. SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). +### H11. `ScdType_ScdType` enum uses the cryptic acronym SCD +- **Locations:** `model.ts:415` (`ScdType_ScdType`), `index.ts:32`, `index.ts:150`. +- **Category:** 5 (cryptic abbreviation). +- **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). +- **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). -### H13. `StorageMode` enum is a parallel of `ScdType_ScdType` with three overlapping values — duplicate concept +### H12. `StorageMode` enum is a parallel of `ScdType` with three overlapping values — duplicate concept - **Locations:** `model.ts:263` (`StorageMode.SCD_TYPE_1` / `SCD_TYPE_2` / `APPEND_ONLY`), `model.ts:415` (`ScdType_ScdType.SCD_TYPE_1` / `SCD_TYPE_2` / `APPEND_ONLY`). - **Category:** 12 (duplicate concepts). - **Suggestion:** Delete one. The JSDoc on `IngestionPipelineDefinition_TableSpecificConfig.storageMode` (`model.ts:1437-1440`) literally says "Mutually exclusive with scd_type — a 400 error is returned if both are set." This is two names for the same field. Pick one (probably `StorageMode` since it includes a meaningful `UNSPECIFIED`). - **Rationale:** Forcing the client to choose between two synonymous enums based on which one the field is typed as is the worst possible API ergonomic. Users will set both and get a 400. -### H14. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" +### H13. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" - **Location:** `model.ts:410`. - **Category:** 6 (misleading — references method `run` that does not exist; the method is `start`). - **Suggestion:** Fix JSDoc to reference `start()`. After H3, both will line up at `run()`. - **Rationale:** Currently the user reads "call `run`" and finds no `run()` method on `Client`. -### H15. `client.delete()` collides with JS `delete` keyword +### H14. `client.delete()` collides with JS `delete` keyword - **Location:** `client.ts:204`. - **Category:** 10 (reserved-word collision). - **Suggestion:** Rename to `deletePipeline()` (matching `restorePipeline()` already at `client.ts:475`). Alternatively, `remove()`. - **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. `restorePipeline()` already uses the verbose form, so the asymmetry is jarring (`client.delete` vs `client.restorePipeline`). -### H16. `client.restorePipeline()` is verbose, but its siblings are short (`delete`, `get`, `clone`) +### H15. `client.restorePipeline()` is verbose, but its siblings are short (`delete`, `get`, `clone`) - **Location:** `client.ts:475`. - **Category:** 7 (overly verbose), 17 (inconsistent verbs). - **Suggestion:** Either shorten to `restore()` (parallel with `clone()`, `delete()`, `get()`) or lengthen the siblings to `deletePipeline()`, `getPipeline()`, `clonePipeline()`. The request type is already named `RestorePipelineRequest` — which is itself inconsistent with sibling request types (`DeletePipeline`, `GetPipeline`, `ClonePipeline` have no `Request` suffix). - **Rationale:** Pick one suffix convention and apply it. Mixing methods on the same client is the smell. -### H17. `RestorePipelineRequest` ends in `Request` but other request types do not -- **Locations:** `model.ts:2618` (`RestorePipelineRequest`), `model.ts:2624` (`RestorePipelineRequest_Response`), `model.ts:477` (`ApplyEnvironmentRequest`), `model.ts:482` (`ApplyEnvironmentRequest_Response`). +### H16. `RestorePipelineRequest` ends in `Request` but other request types do not +- **Locations:** `model.ts:2618` (`RestorePipelineRequest`), `model.ts:477` (`ApplyEnvironmentRequest`), and all other request types without the suffix (`DeletePipeline`, `GetPipeline`, `ClonePipeline`, `EditPipeline`, `CreatePipeline`, `StartUpdate`, `StopPipeline`, ...). - **Category:** 8 (redundant suffix), 17 (inconsistent). - **Suggestion:** Pick one convention and stick to it. Either drop `Request` everywhere (so this becomes `RestorePipeline`, `ApplyEnvironment`) or add it everywhere (`DeletePipelineRequest`, `EditPipelineRequest`, ...). -- **Rationale:** Two named conventions in the same file confuse every reader. `RestorePipelineRequest_Response` is doubly bad: the underscore says it is a proto-nested name (intended to be `RestorePipelineRequest.Response`) but a response shape suffixed `RequestRequest_Response` is bizarre. +- **Rationale:** Two named conventions in the same file confuse every reader. -### H18. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +### H17. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity - **Location:** `model.ts:56`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. -### H19. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" +### H18. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" - **Location:** `model.ts:313` ("Update is waiting for previous update to finish."). - **Category:** 6 (misleading). - **Suggestion:** Doc rewrite (English) after H1: "Run is waiting for previous run to finish." - **Rationale:** Same as H1 — once `Update` is renamed to `Run`, every JSDoc that mentions "update" in this enum needs to follow. -### H20. `StartUpdate.fullRefresh` / `refreshSelection` / `fullRefreshSelection` / `resetCheckpointSelection` / `refreshFlowSelection` — 5 booleans-or-arrays describing overlapping concepts +### H19. `StartUpdate.fullRefresh` / `refreshSelection` / `fullRefreshSelection` / `resetCheckpointSelection` / `refreshFlowSelection` — 5 booleans-or-arrays describing overlapping concepts - **Location:** `model.ts:2738-2780`. - **Category:** 12 (duplicate concepts), 17 (inconsistent verbs). - **Suggestion:** Collapse into a single discriminated union `refreshMode: FullGraph | FullRefresh | TableSelection | FlowSelection | RewindMode` (analogous to existing `RewindSpec`). At minimum, document the precedence rules in JSDoc. - **Rationale:** The combinatorial space is currently five fields × two values each = 32 combinations, of which JSDoc clarifies only "if both refresh_selection and full_refresh_selection are empty, this is a full graph update." The other 30 combinations are undefined. -### H21. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +### H20. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural - **Locations:** `model.ts:1746`, `model.ts:556` (`notifications?: Notifications[]`), etc. - **Category:** 9 (singular/plural mismatch). - **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. - **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. -### H22. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) +### H21. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) - **Locations:** `model.ts:644-670`, `model.ts:1323`, `model.ts:1357`. - **Category:** 20 (type-suffix tautology), 12 (duplicate naming). - **Suggestion:** Rename the outer interface to `ConnectorOptions` and the inner discriminator to `options` (or `payload`). Then `connectorOptions: {payload: {...}}` reads cleanly. - **Rationale:** Currently `ConnectorOptions.connectorOptions.googleAdsOptions` requires four nested identifiers all containing "options". -### H23. `PipelinesEnvironment` vs `IngestionPipelineDefinition` — two `Pipeline*` namespaces, only one is plural +### H22. `PipelinesEnvironment` vs `IngestionPipelineDefinition` — two `Pipeline*` namespaces, only one is plural - **Locations:** `model.ts:2382` (`PipelinesEnvironment`), `model.ts:1173` (`IngestionPipelineDefinition`). - **Category:** 9 (singular/plural mismatch), 17 (inconsistent prefix). - **Suggestion:** Drop the prefix on `PipelinesEnvironment` (see H4). Or rename to `PipelineEnvironment` (singular). Match `PipelineCluster`, `PipelineDeployment`, `PipelineEvent`, `PipelineLibrary`, `PipelineSpec`, `PipelineStateInfo`, `PipelineTrigger` — all singular. - **Rationale:** Out of 22 pipeline-prefixed types, 8 use plural (`Pipelines*`) and 14 use singular (`Pipeline*`). No domain reason for the split; pure generator artifact. -### H24. Underscore-named proto nested types — 27 separate identifiers with `eslint-disable` -- **Locations:** 27 lines, each tagged `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` Notable: `ApplyEnvironmentRequest_Response` (`model.ts:482`), `ClonePipeline_ConfigurationEntry` (`model.ts:591`), `ClonePipeline_Response` (`model.ts:597`), `ClonePipeline_TagsEntry` (`model.ts:604`), `CommunityConnectorOptions_OptionsEntry` (`model.ts:622`), `CreatePipeline_ConfigurationEntry`, `CreatePipeline_ParametersEntry`, `CreatePipeline_Response`, `CreatePipeline_TagsEntry`, `DeletePipeline_Response`, `EditPipeline_ConfigurationEntry`, `EditPipeline_ParametersEntry`, `EditPipeline_Response`, `EditPipeline_TagsEntry`, `FileIngestionOptions_FileFormat`, `FileIngestionOptions_FormatOptionsEntry`, `FileIngestionOptions_SchemaEvolutionMode`, `GetPipeline_Response`, `GetPipeline_Response_ParametersEntry`, `GetUpdate_Response`, `GoogleDriveOptions_GoogleDriveEntityType`, `GoogleDriveOptions_GoogleDriveIngestionScope`, `IngestionPipelineDefinition_*` (10 nested), `KafkaOptions_ClientConfigEntry`, `ListPipelineEvents_Response`, `ListPipelines_Response`, `ListUpdates_Response`, `PeriodicTrigger_TimeUnit`, `PipelineCluster_CustomTagsEntry`, `PipelineCluster_SparkConfEntry`, `PipelineCluster_SparkEnvVarsEntry`, `PipelineSpec_ConfigurationEntry`, `PipelineSpec_TagsEntry`, `PipelineState_PipelineState`, `RestorePipelineRequest_Response`, `ScdType_ScdType`, `SharepointOptions_SharepointEntityType`, `StartUpdate_ParametersEntry`, `StartUpdate_Response`, `StopPipeline_Response`, `TikTokAdsOptions_TikTokDataLevel`, `TikTokAdsOptions_TikTokReportType`, `Transformer_Format`, `Truncation_TruncationDetail`, `UpdateInfo_ParametersEntry`. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/Java-style names). -- **Suggestion:** Flatten everywhere. `PipelineState_PipelineState` → `PipelineState`, `IngestionPipelineDefinition_TableSpec` → `IngestionTableSpec`, etc. Use TS namespace-style with dot notation only where it disambiguates (e.g., `IngestionPipelineDefinition.TableSpec` via namespace export — but TS namespace exports inside modules are non-idiomatic). -- **Rationale:** TS identifiers conventionally use camelCase / PascalCase; underscores are reserved for special names (private fields by convention). 27 `eslint-disable` lines = 27 fights with the linter. The Generator should be re-targeted. - -### H25. `Sequencing.controlPlaneSeqNo` — abbreviated/cryptic identifier +### H23. `Sequencing.controlPlaneSeqNo` — abbreviated/cryptic identifier - **Locations:** `model.ts:2661` (`Sequencing`), `model.ts:2665` (`controlPlaneSeqNo`). - **Category:** 5 (cryptic abbreviations), 15 (generic field names). - **Suggestion:** Rename to `controlPlaneSequenceNumber`. The JSDoc already calls it "A sequence number" — TS has no character budget. Sibling type `DataPlaneId.seqNo` (`model.ts:792`) has the same issue. - **Rationale:** "SeqNo" is a Go/Java abbreviation. The wire JSON is `seq_no`, so the TS field rename is purely a surface improvement. -### H26. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` +### H24. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` - **Location:** `model.ts:788`. - **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). - **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. @@ -488,32 +476,28 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## Observations -### O1. The whole file is one giant proto port — 27 `eslint-disable` lines for underscore-named nested types -- **Files:** `model.ts` throughout. -- **Cross-reference:** This is the same pattern flagged in `jobs.md`. The pipelines package compounds it with the plural `Pipelines*` prefix (H4 here). - -### O2. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into 6 different abbreviations across the public API +### O1. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into 6 different abbreviations across the public API - **Search:** `DLT`, `SDP`, `LDP`, `Lakeflow`, `Spark Declarative Pipelines`, `Delta Live Tables`, `DAB`. - **Locations:** `model.ts:48` (`DAB` in DeploymentKind comment), `model.ts:551` (`SDP` in `channel` JSDoc), `model.ts:804` (`Spark Declarative Pipelines` in JSDoc), `model.ts:1175` (`Lakeflow Connect`), `model.ts:2063` (`https://docs.databricks.com/en/ldp/`), `model.ts:2379` (`SDP's environment`), `client.ts:376` (`Spark Declarative Pipelines`). - **Suggestion:** Settle on one product name in JSDoc. The TS types should be backwards-compatible (no rename) but the docstrings should agree. -### O3. `Pipelines*` (plural) vs `Pipeline*` (singular) split: 8 plural-prefixed vs 14 singular-prefixed types -- **Cross-reference:** H4, H23. +### O2. `Pipelines*` (plural) vs `Pipeline*` (singular) split: 8 plural-prefixed vs 14 singular-prefixed types +- **Cross-reference:** H4, H22. -### O4. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested +### O3. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested - **Locations:** `IngestionPipelineDefinition.connectorType`, `IngestionPipelineDefinition.sourceConfigurations[].catalog.options`, `IngestionPipelineDefinition_SchemaSpec.sourceOptions`, `IngestionPipelineDefinition_SchemaSpec.connectorOptions`, `IngestionPipelineDefinition_TableSpec.sourceOptions`, `IngestionPipelineDefinition_TableSpec.connectorOptions`. - **Suggestion:** Document the resolution order between schema-level and table-level options. JSDoc currently fragments the rules across multiple types. -### O5. JSDoc uses `` placeholder — leak from the Go SDK's template substitution +### O4. JSDoc uses `` placeholder — leak from the Go SDK's template substitution - **Search:** `` appears 19 times in `model.ts`. - **Suggestion:** Replace with literal "Databricks" before TS compilation. -### O6. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` +### O5. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` - **Location:** `model.ts:1758`. - **Category:** 16. - **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. -### O7. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side +### O6. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side - **Locations:** `model.ts:1831-1881`. - **Category:** Generator artifact / Go-SDK fidelity issue. - **Suggestion:** Mark deprecated fields with `@deprecated` JSDoc tag (currently only mentioned in plain text). diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index 1d1beb36..a4ee9601 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -101,14 +101,7 @@ The package defines no enums. ### 2.4 Underscores in TS identifiers — High -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| U-01 | `ListPolicyFamilies_Response` | High | Underscores in TS type names violate Google TypeScript style (`UpperCamelCase` only — see https://google.github.io/styleguide/tsguide.html#naming-style). The codebase even disables ESLint on the line: `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`. Should be `ListPolicyFamiliesResponse`. | -| U-02 | Imports/exports of `ListPolicyFamilies_Response` | High | `client.ts` and `index.ts` both import/re-export the underscored name, propagating the violation across the public surface (see `index.ts` line 10). | - -No enum-member identifiers exist in this package, so the -`SCREAMING_SNAKE_CASE` exception (which is permitted by Google style for -enum members) does not apply here. +_None._ ### 2.5 Cryptic abbreviations — Medium @@ -179,10 +172,9 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| G-01 | `ListPolicyFamilies_Response` (proto nested-message style) | High | Direct port of Go's `pb.ListPolicyFamiliesResponse` / protobuf naming. TypeScript ecosystems do not use `_` separators between message and nested-message names; the codebase even disables ESLint for each occurrence. Should adopt the TS-idiomatic `ListPolicyFamiliesResponse`. | -| G-02 | `HttpClient`, `HttpRequest`, `HttpResponse` | Low | Google TS style uses `Http` (lowercased acronym) — consistent. Not a Go-style violation. | -| G-03 | `executeCall`, `executeHttpCall` | Medium | The dual-naming (`Call` vs `HttpCall`) communicates the wrapping relationship in a Go-style "the inner one is HTTP-specific, the outer one is a generic retry/timeout decorator" idiom. Acceptable; common pattern in the Go SDK at `databricks/sdk-go/transport/`. | -| G-04 | `buildHttpRequest` | Low | "Build" is fine in TS; the naming is broadly used. | +| G-01 | `HttpClient`, `HttpRequest`, `HttpResponse` | Low | Google TS style uses `Http` (lowercased acronym) — consistent. Not a Go-style violation. | +| G-02 | `executeCall`, `executeHttpCall` | Medium | The dual-naming (`Call` vs `HttpCall`) communicates the wrapping relationship in a Go-style "the inner one is HTTP-specific, the outer one is a generic retry/timeout decorator" idiom. Acceptable; common pattern in the Go SDK at `databricks/sdk-go/transport/`. | +| G-03 | `buildHttpRequest` | Low | "Build" is fine in TS; the naming is broadly used. | ### 2.14 Generic field names losing meaning — Medium @@ -225,7 +217,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | TS-01 | `PolicyFamily` — does the `Family` suffix double up with `Policy`? | Low | `PolicyFamily` is the domain term used in the Databricks docs (cf. https://docs.databricks.com/en/admin/clusters/policy-families.html). The "Family" here means *grouping/template*, not a `*Family` type-suffix tautology. OK. | -| TS-02 | `GetPolicyFamily`, `ListPolicyFamilies`, `ListPolicyFamilies_Response` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | +| TS-02 | `GetPolicyFamily`, `ListPolicyFamilies` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | | TS-03 | `HttpCallOptions` (utils) | Low | The `Options` suffix is a standard TS pattern (`fetch` accepts `RequestInit`, but `Options` is widespread). OK. | ### 2.20 Other observations @@ -253,30 +245,20 @@ _None._ | Severity | Count | | -------- | ----- | -| High | 4 | -| Medium | 12 | +| High | 0 | +| Medium | 10 | | Low | 28 | -| **Total**| **44**| - -(Counted unique IDs across all categories. The total double-counts cross-referenced symbols -intentionally — e.g. `ListPolicyFamilies_Response` appears in U-01, U-02, and G-01.) +| **Total**| **38**| ### 3.2 Top themes -1. **Proto-style `_Response` suffix.** `ListPolicyFamilies_Response` - violates Google TS style (no underscores in `UpperCamelCase` identifiers) - and requires an `eslint-disable @typescript-eslint/naming-convention` - annotation. Renaming to `ListPolicyFamiliesResponse` would remove the - disables and align with TS conventions. This is the package's only - **High**-severity cluster. - -2. **Read-only API ⇒ minimal naming surface.** With only two endpoints +1. **Read-only API ⇒ minimal naming surface.** With only two endpoints (`getPolicyFamily`, `listPolicyFamilies`) and one entity (`PolicyFamily`), - the package introduces almost no domain-specific naming. The vast - majority of issues are repo-wide patterns (the bare `Client` class name, - the underscored `_Response` suffix) rather than per-package mistakes. + the package introduces almost no domain-specific naming. The majority of + issues are repo-wide patterns (the bare `Client` class name) rather than + per-package mistakes. -3. **`definition` and `version` are over-generic on a generic entity.** +2. **`definition` and `version` are over-generic on a generic entity.** `PolicyFamily.definition` and `GetPolicyFamily.version` are the two fields whose meaning is best inferred from the JSDoc rather than from the field name itself. Renaming to `policyDefinition` / @@ -286,8 +268,6 @@ intentionally — e.g. `ListPolicyFamilies_Response` appears in U-01, U-02, and (non-breaking renames are not possible — this section is advisory for the codegen owners) -- Drop `_Response` suffix → `ListPolicyFamiliesResponse`. Removes one - ESLint-disable comment and one Google-style violation. - Rename `PolicyFamily.definition` → `policyDefinition` (matches the sibling field `policyFamilyDefinitionOverrides` in the `clusterpolicies` package). @@ -299,8 +279,6 @@ codegen owners) ### 3.4 Cross-package consistency notes -- The `_Response` proto-style suffix is consistent with peers; addressing - at the codegen level would fix all packages in one sweep. - The bare `Client` class name is consistent with peers; a codegen-level rename to `Client` would help all packages. - `PolicyFamily.policyFamilyId` matches `Policy.policyFamilyId` in the diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index bad4a0cf..5d49d730 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -3,15 +3,15 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `ComputeInstance`s (the individual compute nodes inside an endpoint group), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Table`s (non-synced PG tables), `Catalog`s (Unity Catalog mirrors of logical PG databases), Forward ETL (PG→UC reverse-ETL), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Waiter`-style classes. -**Total weird names flagged:** 90 +**Total weird names flagged:** 83 ## Summary | Severity | Count | | --- | --- | -| High | 22 | +| High | 16 | | Medium | 47 | | Low | 17 | -| Observation | 4 | +| Observation | 3 | ## High severity @@ -27,67 +27,28 @@ - **Suggested name:** Pick one as canonical; the other re-exports from the canonical or marks itself deprecated. Cross-reference each shared type with a JSDoc note like "Equivalent to `database/v1.DeltaTableSyncInfo`; see go/lakebase-v2 for the migration." - **Rationale:** Same as `database` finding #2 — `postgres` is V2 and `database` is V1; nothing in the names says so. -### 3. 18 enum/interface names contain underscores `_` — `src/v1/model.ts` throughout -- **Why weird:** Every "nested message" or "nested enum" comes out as `Parent_Child` because of proto's nested-message convention. Each needs `eslint-disable-next-line @typescript-eslint/naming-convention`. Full list: - - Enums: `BranchStatus_State` (line 581), `ComputeInstance_ComputeState` (599), `ComputeInstance_ComputeType` (607), `EndpointStatus_State` (628), `NewPipelineSpec_PipelineChannel` (644), `ProvisioningInfo_State` (654), `RequestedClaims_PermissionSet` (665), `Role_AuthMethod` (672), `Role_IdentityType` (690), `Role_MembershipRole` (703), `SyncedTable_SyncedTableSpec_PgSpecificType` (712), `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` (721), `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` (730). - - Interfaces: `Catalog_CatalogSpec` (893), `Catalog_CatalogStatus` (929), `Database_DatabaseSpec` (1123), `Database_DatabaseStatus` (1146), `EndpointSettings_PgSettingsEntry` (1421), `ProjectDefaultEndpointSettings_PgSettingsEntry` (2136), `Role_Attributes` (2275), `Role_RoleSpec` (2282), `Role_RoleStatus` (2338), `SyncedTable_SyncedTableSpec` (2387), `SyncedTable_SyncedTableSpec_ExtraColumnDefinition` (2468), `SyncedTable_SyncedTableSpec_SecondaryIndex` (2484), `SyncedTable_SyncedTableSpec_TypeOverride` (2500), `SyncedTable_SyncedTableStatus` (2513). -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names). -- **Suggested name:** Flatten with descriptive prefixes/suffixes (no double-underscore chains). E.g. `BranchState`, `ComputeState`, `ComputeType`, `EndpointState`, `PipelineChannel`, `ProvisioningState`, `PermissionSet`, `RoleAuthMethod`, `RoleIdentityType`, `RoleMembershipRole`, `PgColumnType`, `IndexCreationPoint`, `SchedulingPolicy`, `CatalogSpec`, `CatalogStatus`, `DatabaseSpec`, `DatabaseStatus`, `PgSettingsEntry`, `RoleAttributes`, `RoleSpec`, `RoleStatus`, `SyncedTableSpec`, `ExtraColumnDefinition`, `SecondaryIndex`, `TypeOverride`, `SyncedTableStatus`. Alternatively, use TS namespaces (`namespace SyncedTable { export type Spec = … }`). -- **Rationale:** Each underscore identifier requires a lint suppression and forces consumers to type underscores. The triple-underscore beast `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` is 56 characters of leaked proto encoding. - -### 4. `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy` — 56-char triple-tautology — `src/v1/model.ts:730` -- **Why weird:** Type sits nested inside `SyncedTable` → `SyncedTableSpec` → `SyncedTableSchedulingPolicy`. Each level repeats `SyncedTable`. Three repetitions = once at parent (`SyncedTable_`), once at child (`SyncedTableSpec_`), once at the leaf (`SyncedTableSchedulingPolicy`). -- **Category:** 4 (underscore-nested), 20 (type-suffix tautology), 7 (overly verbose). -- **Suggested name:** `SchedulingPolicy` (the context is obvious from the field site). -- **Rationale:** The fully qualified name is longer than most file paths. - -### 5. `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint` — quad-level naming — `src/v1/model.ts:721` -- **Why weird:** Four `_`-separated segments: `SyncedTable_SyncedTableSpec_SecondaryIndex_CreationPoint`. Two of the four words are `SyncedTable*`. -- **Category:** 4 (underscores), 20 (tautology), 7 (verbose). -- **Suggested name:** `IndexCreationPoint`. -- **Rationale:** Same as #4 but worse — quad-level. - -### 6. `SyncedTable_SyncedTableSpec_PgSpecificType` — 41-char nested type — `src/v1/model.ts:712` -- **Why weird:** Three `_` segments where the first two re-state `SyncedTable`. Equivalent to `database`'s `SyncedTableSpec_PgSpecificType` (which itself is two segments). Postgres SDK is more nested than the V1. -- **Category:** 4 (underscores), 7 (verbose). -- **Suggested name:** `PgColumnTypeOverride` (descriptive) or `PgColumnType`. -- **Rationale:** Same as #4. - -### 7. `SyncedTable_SyncedTableSpec` field/type tautology — `src/v1/model.ts:2387`, used at `SyncedTable.spec` (2380) -- **Why weird:** `SyncedTable` has `spec?: SyncedTable_SyncedTableSpec`. The wrapper type re-says `SyncedTable` twice. Read site: `syncedTable.spec` already inside the type — the type qualifier `SyncedTable_` is pure noise. -- **Category:** 4 (underscore-nested), 20 (type-suffix tautology), 7 (verbose). -- **Suggested name:** `SyncedTableSpec` (flat) or nested `SyncedTable.Spec`. -- **Rationale:** `SyncedTable_SyncedTableSpec` is a triple-tautology against `SyncedTable.spec`. - -### 8. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` +### 3. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` - **Why weird:** Huge enum (~100 entries) referenced exactly once via `DatabricksServiceExceptionWithDetailsProto.errorCode` (1179). Most entries are explicitly marked "NOTE: Deprecated and kept to maintain backwards compatibility for public APIs that use it, avoid using it in the new APIs" (e.g. `IO_ERROR`, `INVALID_STATE`, `UNPARSEABLE_HTTP_ERROR`, `QUOTA_EXCEEDED`, `MAX_BLOCK_SIZE_EXCEEDED`, `DRY_RUN_FAILED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, all the `GIT_*`, `IPYNB_FILE_IN_REPO`, `INSECURE_PARTNER_RESPONSE`, `METASTORE_*_EXISTS`, `CATALOG_NOT_EMPTY`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, etc. — at least 40 entries). The enum re-exports the entire Databricks-platform error vocabulary into a Postgres-specific SDK package. - **Category:** 7 (overly verbose), 11 (empty/trivial wrappers for deprecated values), 14 (Go/proto leak — all deprecated values exist only "for public APIs that use it"), 18 (long enum values). - **Suggested name:** Move `ErrorCode` to a shared `core/apierror` package (already exists per CLAUDE.md), drop deprecated values from the public TS surface (or mark them `@deprecated` so TS tooling can warn). - **Rationale:** Every consumer of this package gets a 100-entry deprecated-warning bundle. The fact that it's exported from `postgres/v1/index.ts` (line 30) means it's part of the public surface. -### 9. `DatabricksServiceExceptionWithDetailsProto` — 41-char Java-style type — `src/v1/model.ts:1178` -- **Why weird:** Six concatenated words: `Databricks` + `Service` + `Exception` + `With` + `Details` + `Proto`. The `Proto` suffix says "this is from a `.proto` file" — a wire-format implementation detail. The `WithDetails` suffix is Java-style ("BuilderWithRoom"). The whole thing is a tagged struct holding `{errorCode, message, stackTrace, details}` — a plain error. -- **Category:** 7 (overly verbose), 14 (Java/proto-style name), 20 (type-suffix tautology — `Exception` and `Proto` both redundant), 8 (redundant suffix `Proto`). -- **Suggested name:** `ServiceError` or `ApiError` (and re-use the shared apierror type if one exists). -- **Rationale:** Six-word type names are an anti-pattern; the `Proto` suffix is a build-system leak. - -### 10. `BranchStatus_State`, `EndpointStatus_State`, `ComputeInstance_ComputeState`, `ProvisioningInfo_State` — three different "State" enum patterns — `src/v1/model.ts:581, 628, 599, 654` -- **Why weird:** Four state enums, each named differently: - - `BranchStatus_State` (qualifier is the status struct) - - `EndpointStatus_State` (same as Branch) - - `ComputeInstance_ComputeState` (qualifier is the resource, leaf is `ComputeState`) - - `ProvisioningInfo_State` (qualifier is the unrelated wrapper type) +### 4. Four "State" enums share value vocabulary but use three different qualifier patterns — `src/v1/model.ts:581, 628, 599, 654` +- **Why weird:** Four state enums use three different qualifier patterns: + - Branch state and endpoint state qualify by the status struct (`BranchStatus`-scoped, `EndpointStatus`-scoped). + - Compute state qualifies by the resource and names the leaf `ComputeState`. + - Provisioning state lives under the unrelated `ProvisioningInfo` wrapper. - All four enums share values like `STATE_UNSPECIFIED`, `INIT`, `ACTIVE`, etc. The TypeScript user can't tell which enum to use for which resource without reading the JSDoc. -- **Category:** 17 (inconsistent action verb / naming pattern), 4 (underscores). +- **Category:** 17 (inconsistent naming pattern). - **Suggested name:** Standardise to `State`: `BranchState`, `EndpointState`, `ComputeState`, `ProvisioningState`. - **Rationale:** Four state enums with three naming conventions across one package. -### 11. Enum values all carry redundant resource prefix — `src/v1/model.ts` (multiple enums) +### 5. Enum values all carry redundant resource prefix — `src/v1/model.ts` (multiple enums) - **Why weird:** Every enum's `UNSPECIFIED` sentinel duplicates the enum name: - `EndpointType.ENDPOINT_TYPE_UNSPECIFIED` / `ENDPOINT_TYPE_READ_WRITE` / `ENDPOINT_TYPE_READ_ONLY` (line 11-13) - `ProvisioningPhase.PROVISIONING_PHASE_*` (520-526) - `SyncedTableState.SYNCED_TABLE_*` (532-576, 14 entries, each re-stating `SYNCED_TABLE`) - - `BranchStatus_State.STATE_UNSPECIFIED` (only one with the prefix; others don't, see #12) + - `BranchStatus_State.STATE_UNSPECIFIED` (only one with the prefix; others don't, see #6) - `ComputeInstance_ComputeState.COMPUTE_STATE_UNSPECIFIED` - `ComputeInstance_ComputeType.COMPUTE_TYPE_UNSPECIFIED` - `EndpointStatus_State.STATE_UNSPECIFIED` @@ -101,32 +62,32 @@ - **Suggested name:** Drop the prefix everywhere — `EndpointType.Unspecified | ReadWrite | ReadOnly` etc. - **Rationale:** `EndpointType.ENDPOINT_TYPE_READ_WRITE` is 41 chars to say "read-write". -### 12. `SyncedTableState` — 14 enum values each prefixed `SYNCED_TABLE_*` — `src/v1/model.ts:532-576` +### 6. `SyncedTableState` — 14 enum values each prefixed `SYNCED_TABLE_*` — `src/v1/model.ts:532-576` - **Why weird:** Worst offender. 14 values: `SYNCED_TABLE_STATE_UNSPECIFIED`, `SYNCED_TABLE_PROVISIONING`, `SYNCED_TABLE_PROVISIONING_PIPELINE_RESOURCES` (45 chars), `SYNCED_TABLE_PROVISIONING_INITIAL_SNAPSHOT` (42 chars), `SYNCED_TABLE_ONLINE`, `SYNCED_TABLE_ONLINE_CONTINUOUS_UPDATE` (38 chars), `SYNCED_TABLE_ONLINE_TRIGGERED_UPDATE` (37 chars), `SYNCED_TABLE_ONLINE_NO_PENDING_UPDATE` (38 chars), `SYNCED_TABLE_OFFLINE`, `SYNCED_TABLE_OFFLINE_FAILED`, `SYNCED_TABLE_ONLINE_PIPELINE_FAILED` (36 chars), `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES` (47 chars). All re-state `SYNCED_TABLE_` to no benefit. Note: this enum is duplicated in `database/v1/model.ts:55` (with one typo, `SYNCED_TABLED_OFFLINE`) — not duplicated here, but the divergence is itself a smell. - **Category:** 2 (redundant prefixes), 18 (long enum values). - **Suggested name:** `SyncedTableState.Unspecified | Provisioning | ProvisioningPipelineResources | ProvisioningInitialSnapshot | Online | OnlineContinuousUpdate | OnlineTriggeredUpdate | OnlineNoPendingUpdate | Offline | OfflineFailed | OnlinePipelineFailed | OnlineUpdatingPipelineResources`. -- **Rationale:** Same as #11 but most severe enum. +- **Rationale:** Same as #5 but most severe enum. -### 13. `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy.SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` — 41-char enum value on top of 56-char enum name — `src/v1/model.ts:731` -- **Why weird:** Enum name itself is 56 chars (#4); first value adds another 41 chars: total qualified reference is `SyncedTable_SyncedTableSpec_SyncedTableSchedulingPolicy.SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` — 97 chars. The other three values are bare (`CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`). +### 7. SyncedTable scheduling-policy enum — only `SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` carries a prefix; the other three values are bare — `src/v1/model.ts:731` +- **Why weird:** The first value is `SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` (41 chars); the other three values are bare `CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`. Internally inconsistent within a single enum. - **Category:** 2 (redundant prefix), 17 (inconsistent — `UNSPECIFIED` carries the prefix, others don't), 18 (long enum values). -- **Suggested name:** Pair with #4: rename type to `SchedulingPolicy`; values `Unspecified | Continuous | Triggered | Snapshot`. -- **Rationale:** Same as #11. +- **Suggested name:** Standardise values as `Unspecified | Continuous | Triggered | Snapshot`. +- **Rationale:** Same as #5. -### 14. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:2276-2278` +### 8. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:2276-2278` - **Why weird:** Three lowercase run-together field names. Doc comment (lines 2269-2272) acknowledges the choice ("The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words"). That's a wire-format justification (Postgres keywords). The TypeScript identifier should still be camelCase. `createrole` is especially confusing — could read as `createRole` (verb) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS), 17 (inconsistent — every other field in the package is camelCase). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; wire stays `createdb`/`createrole`/`bypassrls`. - **Rationale:** Same finding as `database` audit #5 — both packages share this bug. -### 15. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:677, 682` +### 9. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:677, 682` - **Why weird:** Implementation details (SCRAM-SHA-256 mechanism, OAuth `_V1`) leak into the public enum. The `_V1` suffix begs the question: what happens at V2? Should the SDK consumer have to migrate from `LAKEBASE_OAUTH_V1` to `LAKEBASE_OAUTH_V2` when the wire format changes? Worse, the `SCRAM_SHA_256` qualifier is a specific hash function — consumers picking an auth method shouldn't have to know about hash schemes. - **Category:** 1 (vague at the wrong level — too specific), 6 (misleading: `LAKEBASE_OAUTH_V1` versioning leaks), 14 (Postgres/auth-spec internal naming), 18 (long enum values). - **Suggested name:** `Password` (replacing `PG_PASSWORD_SCRAM_SHA_256`) and `OAuth` (replacing `LAKEBASE_OAUTH_V1`). Keep `NoLogin`. Push the wire-protocol-specific names into the marshal layer. - **Rationale:** Public enums should describe the *concept* (password vs OAuth vs no-login), not the wire-protocol mechanism. -### 16. `Forward ETL` types use a Java/Kotlin-style adjective phrase — `src/v1/model.ts:1229-1325` (multiple types), `client.ts:670-882` (methods) +### 10. `Forward ETL` types use a Java/Kotlin-style adjective phrase — `src/v1/model.ts:1229-1325` (multiple types), `client.ts:670-882` (methods) - **Why weird:** "Forward ETL" is product-marketing terminology baked into 11 type/method names: - `DeleteForwardEtlConfigurationRequest` / `DeleteForwardEtlConfigurationResponse` (1229, 1246) - `DisableForwardEtlRequest` / `DisableForwardEtlResponse` (1306, 1323) @@ -143,45 +104,45 @@ - **Suggested name:** Group under a `ReverseEtl` namespace (since "Forward ETL" from PG's perspective is reverse-ETL from Lakehouse's perspective — choose one direction language and stick to it). Use `ETL` casing per acronym convention or rename to `Replication` if that's the intent. Re-export under a single top-level type bundle. - **Rationale:** "Forward" / "Reverse" terminology is consumer-facing direction labelling that can backfire — one company's "forward" is another's "reverse". 11 types prefixed with the same product-marketing string is verbose. -### 17. `ForwardEtlConfig.createTimeMillis` / `updateTimeMillis` — millis-suffixed timestamps as `number` — `src/v1/model.ts:1538, 1540` +### 11. `ForwardEtlConfig.createTimeMillis` / `updateTimeMillis` — millis-suffixed timestamps as `number` — `src/v1/model.ts:1538, 1540` - **Why weird:** Every other timestamp in the package is `Temporal.Instant` (see `Branch.createTime`, `Catalog.createTime`, `DatabaseCredential.expireTime`, etc.). Only the ForwardEtl types use `number` with `Millis` suffix, breaking the package-wide convention. The unmarshal at `model.ts:3148-3149` confirms they stay as plain `number`. - **Category:** 16 (field type contradicts the established package convention), 17 (inconsistent — every other timestamp is `Temporal.Instant`), 14 (Java-style epoch-millis convention). - **Suggested name:** `createTime: Temporal.Instant` (parse `_millis` into Instant in unmarshal). - **Rationale:** Mixing `Temporal.Instant` and raw millis numbers in the same SDK forces consumers to remember per-type rules. -### 18. `Forward ETL` `pgDatabaseOid` / `pgSchemaOid` / `pgTableOid` — Postgres-internal IDs without doc — `src/v1/model.ts:1240, 1242, 1317, 1319, 1528, 1530, 1578` +### 12. `Forward ETL` `pgDatabaseOid` / `pgSchemaOid` / `pgTableOid` — Postgres-internal IDs without doc — `src/v1/model.ts:1240, 1242, 1317, 1319, 1528, 1530, 1578` - **Why weird:** `Oid` is Postgres slang for "object identifier" (a `pg_class.oid`-style integer). Field doc is minimal: "PostgreSQL database OID." Consumers unfamiliar with Postgres internals don't know how to *obtain* a `pgDatabaseOid` (it's not in the API for fetching a database). The fields appear in 4+ types: `DeleteForwardEtlConfigurationRequest`, `DisableForwardEtlRequest`, `ForwardEtlConfig`, `ForwardEtlTableMapping`. - **Category:** 5 (cryptic abbreviation — `Oid`), 14 (Postgres-internal jargon in public API). - **Suggested name:** `postgresDatabaseObjectId` / `postgresSchemaObjectId` / `postgresTableObjectId`. Or surface the wire format `Oid` but expand the doc with "(obtain via `psql -c \"SELECT oid FROM pg_database WHERE datname = '...'\"`)". - **Rationale:** `Oid` is one of those abbreviations DBAs know cold but TS consumers do not. -### 19. `tenantId` / `timelineId` in Forward ETL request types — `src/v1/model.ts:1236, 1238, 1313, 1315, 1524, 1526, 1679, 1681, 1692, 1694` +### 13. `tenantId` / `timelineId` in Forward ETL request types — `src/v1/model.ts:1236, 1238, 1313, 1315, 1524, 1526, 1679, 1681, 1692, 1694` - **Why weird:** `tenantId` and `timelineId` appear without explanation — only "Tenant ID (dashless UUID format)" and "Timeline ID (dashless UUID format)" doc. What's a Lakebase "tenant"? What's a "timeline"? These appear nowhere else in the SDK as concept-level types. Consumers can't discover what to put here. - **Category:** 19 (underspecified ID — what entity does the tenant ID identify?), 1 (vague), 6 (misleading — "tenant" and "timeline" are not exposed concepts elsewhere). - **Suggested name:** `lakebaseTenantId` / `lakebaseTimelineId` with doc explaining what they reference. Or fold into existing resource refs (e.g. branch resource name). -- **Rationale:** Same as #18 — Postgres-storage-internal terms (the timeline is a Neon/Lakebase storage concept) leaking into the SDK. +- **Rationale:** Same as #12 — Postgres-storage-internal terms (the timeline is a Neon/Lakebase storage concept) leaking into the SDK. -### 20. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1182` -- **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The `Proto` type itself only matters because `Operation.result` references it (line 2031) — the SDK's primary error type. Forcing every error consumer to cast. +### 14. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1182` +- **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The type is reached via `Operation.result` (line 2031), making it the SDK's primary error surface. Every error consumer must cast. - **Category:** 1 (vague), 15 (generic), 16 (type contradicts domain — details have structure, just unmodelled). - **Suggested name:** Add typed discriminator: `details: ErrorDetail[]` with `ErrorDetail = ResourceInfo | RetryInfo | …` aligned to `google.rpc.Status`. - **Rationale:** Errors are the most-handled values in any SDK; opaque `unknown` arrays force every caller to write defensive code. -### 21. 22 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1845-3680` +### 15. 22 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1845-3680` - **Why weird:** The package exports 22 boilerplate poller classes (each ~80 lines, near-identical): `CreateBranchOperation`, `CreateCatalogOperation`, `CreateDatabaseOperation`, `CreateEndpointOperation`, `CreateProjectOperation`, `CreateRoleOperation`, `CreateSyncedTableOperation`, `DeleteBranchOperation`, `DeleteCatalogOperation`, `DeleteDatabaseOperation`, `DeleteEndpointOperation`, `DeleteProjectOperation`, `DeleteRoleOperation`, `DeleteSyncedTableOperation`, `UndeleteBranchOperation`, `UndeleteProjectOperation`, `UpdateBranchOperation`, `UpdateDatabaseOperation`, `UpdateEndpointOperation`, `UpdateProjectOperation`, `UpdateRoleOperation`. Each has identical `name()` / `metadata()` / `wait()` / `done()` methods, differing only in return type (`Branch` vs `Catalog` vs `Database` etc.). All 22 are exported from `index.ts:5-26`. - **Category:** 7 (overly verbose), 11 (trivial wrappers), 14 (Go-style poll-helper pattern), 17 (22-way redundancy). - **Suggested name:** Single generic `Operation` class with `wait(): Promise` and `metadata(): Promise`. Drop all 22 named exports; expose factory methods on `Client` like `createBranchOperation()` that return `Operation`. - **Rationale:** Comparable to `database/v1/client.ts`'s `CreateDatabaseInstanceWaiter` — but here the pattern is repeated 22 times. This bloats the bundle, the public surface, and the autocomplete list. -### 22. `*Operation` classes mix verb prefix with noun suffix — e.g. `CreateBranchOperation` — `src/v1/client.ts:1845, …` +### 16. `*Operation` classes mix verb prefix with noun suffix — e.g. `CreateBranchOperation` — `src/v1/client.ts:1845, …` - **Why weird:** Class name reads as "the *create branch* operation" — i.e. a long-running operation produced by creating a branch. JS convention for poller helpers tends to be `Poller`, `Waiter`, or a verb-form factory. Calling it `CreateBranchOperation` (verb + noun + noun-suffix `Operation`) parses ambiguously: a `CreateBranchOperation` could be "an operation that creates a branch" (active) or "an in-flight operation tracking branch creation" (passive). The latter is the intent. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming), 11 (wrapper-class pattern). -- **Suggested name:** `BranchCreation` / `BranchCreationOperation` (passive form), or factor into a single generic `Operation` (see #21). +- **Suggested name:** `BranchCreation` / `BranchCreationOperation` (passive form), or factor into a single generic `Operation` (see #15). - **Rationale:** Same as `database` audit #14. Class names should be unambiguous noun phrases. ## Medium severity -### 23. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` / `Table` / `ComputeInstance` — 9 generic top-level resource names — `src/v1/model.ts` (multiple) +### 17. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` / `Table` / `ComputeInstance` — 9 generic top-level resource names — `src/v1/model.ts` (multiple) - **Why weird:** Most of these names are single-word generic English (`Branch`, `Catalog`, `Database`, `Endpoint`, `Project`, `Role`, `Table`). Multiple are *already-taken* concepts in Databricks-land: - `Catalog` collides with Unity Catalog `Catalog` (in `catalogs` package) - `Database` collides with the `database` package's `DatabaseInstance` / `DatabaseCatalog` @@ -194,277 +155,277 @@ - **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`, `LakebaseTable`, `LakebaseComputeInstance`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). - **Rationale:** With 100+ packages in the workspace, single-word resource names guarantee collisions. -### 24. `Branch.uid` / `Endpoint.uid` / `Project.uid` / `SyncedTable.uid` — bare `uid` fields, sometimes vs `name` — `src/v1/model.ts:757, 1335, 2048, 2375` +### 18. `Branch.uid` / `Endpoint.uid` / `Project.uid` / `SyncedTable.uid` — bare `uid` fields, sometimes vs `name` — `src/v1/model.ts:757, 1335, 2048, 2375` - **Why weird:** Same problem as `database` finding #18: two identifier-like fields. `name` is a resource path (`projects/{id}/branches/{id}`), `uid` is "System-generated unique ID". Caller can't tell which to pass to `getBranch` (answer: `name`). Bare `uid` is non-descriptive — what scope (project? branch? UC table?). - **Category:** 19 (underspecified id), 1 (vague `uid`). - **Suggested name:** `branchUid` / `endpointUid` / `projectUid` / `syncedTableUid` (and add docs). - **Rationale:** Same as `database` audit #18. -### 25. `Branch.name` / `Catalog.name` / etc. — `name` is a full resource path — `src/v1/model.ts:755, 878, 1106, 1333, 2046, 2254` +### 19. `Branch.name` / `Catalog.name` / etc. — `name` is a full resource path — `src/v1/model.ts:755, 878, 1106, 1333, 2046, 2254` - **Why weird:** Field is `name?: string` but the doc constrains it to a multi-segment path like `projects/{project_id}/branches/{branch_id}`. There is a separate `branchId` / `catalogId` / `databaseId` / `endpointId` / `projectId` / `roleId` field in each status sub-type. Caller has to read JSDoc to know which to use. - **Category:** 1 (vague), 19 (underspecified id), 6 (misleading — `name` reads as a human-readable name, actually a resource path). - **Suggested name:** `resourceName` / `fullName` / `resourcePath` for the path-style field; keep the short ID where present. - **Rationale:** `name` is the most ambiguous field name possible. -### 26. `Branch.parent` — string-typed parent path — `src/v1/model.ts:765` +### 20. `Branch.parent` — string-typed parent path — `src/v1/model.ts:765` - **Why weird:** `parent?: string` doc'd as "The project containing this branch (API resource hierarchy). Format: `projects/{project_id}`". Generic name; the type doesn't enforce the format. Same pattern repeats on `Database.parent` (1111), `Endpoint.parent` (1340), `Role.parent` (2259), `CreateBranchRequest.parent`, `CreateDatabaseRequest.parent`, etc. - **Category:** 1 (vague), 15 (generic), 19 (underspecified — what kind of parent?). - **Suggested name:** `projectName` / `branchName` / specific to the parent type. Or `parentResourceName`. - **Rationale:** Parents differ per child type; `parent` is too generic. -### 27. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:798-824` +### 21. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:798-824` - **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. - **Category:** 16 (type allows `false` but spec rejects it). - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 28. `BranchSpec.isProtected` vs `BranchStatus.isProtected` vs `BranchStatus.default` — same struct, two booleans — `src/v1/model.ts:791, 838, 840` +### 22. `BranchSpec.isProtected` vs `BranchStatus.isProtected` vs `BranchStatus.default` — same struct, two booleans — `src/v1/model.ts:791, 838, 840` - **Why weird:** `BranchStatus.default: boolean | undefined` field clashes with the JS `default` keyword in `import { default } from …` contexts. While not a reserved word in object-property position, it's syntactically irritating and a JS lint hot spot. - **Category:** 10 (reserved-word collision), 1 (vague — `default` of what?). - **Suggested name:** `isDefault: boolean` (matches sibling `isProtected`). - **Rationale:** `branch.default = true` reads weirdly; `branch.isDefault = true` aligns with `branch.isProtected`. -### 29. `Catalog_CatalogSpec.createDatabaseIfMissing` — `src/v1/model.ts:918` +### 23. `createDatabaseIfMissing` field on the catalog spec — `src/v1/model.ts:918` - **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF MISSING`). Same as `database` audit #30 (`createDatabaseIfNotExists`) but with the variant wording "If Missing". Inconsistent with `database` package's "If Not Exists". - **Category:** 14 (SQL-style name), 7 (verbose), 17 (inconsistent with sister package's `createDatabaseIfNotExists`). - **Suggested name:** `ensureDatabaseExists` or `autoCreateDatabase`. - **Rationale:** Two packages, two variants of the same SQL-DDL leak. -### 30. `Catalog_CatalogStatus.catalogId` / `Database_DatabaseStatus.databaseId` / `BranchStatus.branchId` / `EndpointStatus.endpointId` / `ProjectStatus.projectId` / `Role_RoleStatus.roleId` — duplicated ID with parent-type prefix — `src/v1/model.ts:952, 1164, 859, 1516, 2220, 2358` -- **Why weird:** Each status type repeats the parent type's name as a field prefix. `Catalog_CatalogStatus.catalogId` is `Catalog.status.catalogId` — three "catalog"s. Same problem as `database` audit #31 but here the redundancy is *inside* the status type, not just the parent. JSDoc on every field says identical boilerplate: "The short identifier of the X, suitable for showing to the users." +### 24. Every status sub-type duplicates the parent resource name on its id field — `src/v1/model.ts:952, 1164, 859, 1516, 2220, 2358` +- **Why weird:** Each status type has `Id` (`catalogId`, `databaseId`, `branchId`, `endpointId`, `projectId`, `roleId`) inside a status struct that already lives on the parent resource. Read site `catalog.status.catalogId` repeats "catalog" twice. JSDoc on every field is identical boilerplate: "The short identifier of the X, suitable for showing to the users." - **Category:** 7 (verbose), 17 (boilerplate JSDoc), 20 (type-suffix tautology). - **Suggested name:** `id: string` (the wrapping type name is already the resource). - **Rationale:** `catalog.status.catalogId` is "catalog status catalog id" — verbose. -### 31. `ComputeInstance.computeInstanceId` field — `src/v1/model.ts:965` +### 25. `ComputeInstance.computeInstanceId` field — `src/v1/model.ts:965` - **Why weird:** Self-tautology: `ComputeInstance.computeInstanceId`. Three `compute`/`instance` repetitions in a single member reference. - **Category:** 20 (type-suffix tautology), 7 (verbose). - **Suggested name:** `id: string` or just `computeId`. -- **Rationale:** Same as #30 but more egregious because both the type and field repeat both words. +- **Rationale:** Same as #24 but more egregious because both the type and field repeat both words. -### 32. `ComputeInstance.computeHost` — `src/v1/model.ts:973` +### 26. `ComputeInstance.computeHost` — `src/v1/model.ts:973` - **Why weird:** `computeHost` is a `string` that's actually a hostname. "Host" already means hostname; the "compute" qualifier is redundant (we're already inside `ComputeInstance`). - **Category:** 20 (type-prefix tautology), 7 (verbose). - **Suggested name:** `host: string` (or `hostname`). -- **Rationale:** Same as #30. +- **Rationale:** Same as #24. -### 33. `ComputeInstance.role: ComputeInstance_ComputeType` field — `src/v1/model.ts:971` -- **Why weird:** Field is `role`; type is `ComputeInstance_ComputeType`. So `role` is a `ComputeType`, not a Postgres role. Two unrelated concepts (Postgres `Role` and compute `Role`) share the field name. Confusing inside the same package. +### 27. `ComputeInstance.role` field is typed as a compute-type enum, not a Postgres role — `src/v1/model.ts:971` +- **Why weird:** Field is `role` but its type is the compute-type enum, not the Postgres `Role` resource. Two unrelated concepts (Postgres `Role` and the compute "role" classifier) share the field name inside the same package. - **Category:** 6 (misleading — `role` here is *not* a Postgres role), 12 (duplicate concept — `Role` vs `ComputeInstance.role`). -- **Suggested name:** `kind: ComputeType` or `computeRole: ComputeType`. +- **Suggested name:** `kind` or `computeRole`. - **Rationale:** A field named `role` inside a package that *also* has a `Role` type is asking for trouble. -### 34. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:991, 993` +### 28. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:991, 993` - **Why weird:** `CreateBranchRequest` has `parent`, `branchId`, `branch`, `replaceExisting`. `branchId` is the path-component id; `branch.name` (inside `Branch`) is the full resource path; `branch` is the body. Three fields all involved in identifying the branch. - **Category:** 17 (inconsistency — same operation, three id-like fields), 19 (underspecified id semantics). - **Suggested name:** Document the relationship clearly in JSDoc; or accept just `branch: Branch` and derive the id from `branch.name`. - **Rationale:** Same shape repeats on `CreateCatalogRequest`, `CreateDatabaseRequest`, `CreateEndpointRequest`, `CreateProjectRequest`, `CreateRoleRequest`, `CreateSyncedTableRequest`. Caller must read multiple field docs to know which ID to set. -### 35. `CreateBranchRequest.replaceExisting` / `CreateEndpointRequest.replaceExisting` — request-shaped name on a create call — `src/v1/model.ts:995, 1043` +### 29. `CreateBranchRequest.replaceExisting` / `CreateEndpointRequest.replaceExisting` — request-shaped name on a create call — `src/v1/model.ts:995, 1043` - **Why weird:** `replaceExisting?: boolean` on a `Create*` request is essentially "upsert mode". Doc: "If true, update the branch if it already exists instead of returning an error." Many SDKs call this `upsert: true` or `ifExists: 'update'`. Verb is also imperative on a request body. - **Category:** 17 (inconsistent — `create` verb + `replaceExisting` flag conflate two operations), 1 (vague — "replace" how?). - **Suggested name:** `upsert: boolean` or `mode: 'create' | 'upsert'`. - **Rationale:** "Create-or-update" is a common API pattern that deserves a clearer name. -### 36. `Database.parent` is a branch path, `Database.spec.role` is a role path, `Database.status.role` is *also* a role path — `src/v1/model.ts:1111, 1132, 1151` +### 30. `Database.parent` is a branch path, `Database.spec.role` is a role path, `Database.status.role` is *also* a role path — `src/v1/model.ts:1111, 1132, 1151` - **Why weird:** Two `role` fields on the spec and status sub-structs, both holding full resource paths like `projects/{}/branches/{}/roles/{}`. `Database.spec.role` is the *desired owner role*; `Database.status.role` is the *observed owner role*. Doc clarifies but the field-name overlap is jarring. - **Category:** 19 (underspecified id — `role` is actually a role resource path), 1 (vague — `role` could be many things). - **Suggested name:** `ownerRole` or `ownerRoleName`. Use the same name on spec and status. - **Rationale:** Inside a `Database` struct, a bare `role: string` reads as "what role does this database have" — but it's specifically the *owner* role. -### 37. `Database_DatabaseSpec.postgresDatabase` / `Database_DatabaseStatus.postgresDatabase` — `Database` containing `postgresDatabase` — `src/v1/model.ts:1142, 1153` -- **Why weird:** `Database.spec.postgresDatabase` is "the name of the Postgres database" — but the surrounding type is *already* `Database`. Three repetitions of "database" in one member access. +### 31. `postgresDatabase` field appears on both the database spec and status sub-types — `src/v1/model.ts:1142, 1153` +- **Why weird:** `Database.spec.postgresDatabase` and `Database.status.postgresDatabase` repeat "database" three times in one member access — the wrapper type is already `Database`. - **Category:** 20 (type-suffix tautology), 7 (verbose). - **Suggested name:** `pgName` / `pgIdentifier` or just `name` (with a JSDoc note: "matches the Postgres database identifier"). -- **Rationale:** Same as #30, #31, #32. +- **Rationale:** Same as #24, #25, #26. -### 38. `Database` (Postgres) vs `Database_DatabaseSpec.postgresDatabase` (Postgres-side identifier) — same name, two meanings — `src/v1/model.ts:1100, 1142` +### 32. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1100, 1142` - **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. - **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). - **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). - **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. -### 39. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:269-313`, `model.ts:1023` +### 33. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:269-313`, `model.ts:1023` - **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. - **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). - **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. - **Rationale:** Three identifier slots is too many. -### 40. `DatabaseCredential.token: string` carries no doc on format — `src/v1/model.ts:1169` +### 34. `DatabaseCredential.token: string` carries no doc on format — `src/v1/model.ts:1169` - **Why weird:** "The OAuth token that can be used as a password when connecting to a database." Plain `string`. Sibling `expireTime: Temporal.Instant` does carry a type. The token doc doesn't say whether it's a JWT, opaque, format `:`, etc. Same issue exists in `database/v1.DatabaseCredential.token`. - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `accessToken` (and document the format/lifetime in JSDoc). - **Rationale:** Tokens carry semantics; consumers need to know the format. -### 41. `Endpoint.endpointType` field of type `EndpointType` — `src/v1/model.ts:1428` +### 35. `Endpoint.endpointType` field of type `EndpointType` — `src/v1/model.ts:1428` - **Why weird:** `endpoint.endpointType` is type-suffix tautology again: three "endpoint"s. The field of type `EndpointType` could just be `type` since the surrounding type is `Endpoint`. - **Category:** 20 (type-suffix tautology), 7 (verbose). - **Suggested name:** `type: EndpointType` (or `kind`). -- **Rationale:** Same as #31. +- **Rationale:** Same as #25. -### 42. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1430, 1435` +### 36. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1430, 1435` - **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. - **Category:** 5 (cryptic abbreviation), 1 (vague suffix). - **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. - **Rationale:** "CU" is Lakebase-internal slang. -### 43. `EndpointGroupSpec.min` / `max` with `min === max` constraint — `src/v1/model.ts:1356, 1362` +### 37. `EndpointGroupSpec.min` / `max` with `min === max` constraint — `src/v1/model.ts:1356, 1362` - **Why weird:** Two bare fields `min: number` / `max: number` (and `enableReadableSecondaries`) on a group spec. JSDoc says "Currently, this must be equal to max" — meaning callers must set min === max. Type system doesn't enforce; bare `min`/`max` doesn't suggest "group size". - **Category:** 1 (vague), 16 (type contradicts spec — allows min ≠ max). - **Suggested name:** `size: number` (until min ≠ max becomes supported, then introduce `minSize`/`maxSize`). - **Rationale:** Pseudo-flexibility leaks proto future-proofing. -### 44. `EndpointHosts` — type holds 4 hostname fields — `src/v1/model.ts:1390-1409` +### 38. `EndpointHosts` — type holds 4 hostname fields — `src/v1/model.ts:1390-1409` - **Why weird:** Fields are `host` (generic), `readOnlyHost`, `readWritePooledHost`, `readOnlyPooledHost`. The first is "the hostname"; the others narrow by direction/pooling. `host` reads as "the only host" but is just *one* of four. JSDoc clarifies but the field name doesn't. - **Category:** 1 (vague — `host` is the catch-all), 15 (generic). - **Suggested name:** `primaryHost` / `readOnlyHost` / `readWritePooledHost` / `readOnlyPooledHost` (i.e. give the first one a qualifier). - **Rationale:** Reader doesn't know which is "the" host. -### 45. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1449-1468` -- **Why weird:** Same pattern as #27 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. -- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #27). +### 39. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1449-1468` +- **Why weird:** Same pattern as #21 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. +- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #21). - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. -- **Rationale:** Same as #27. +- **Rationale:** Same as #21. -### 46. `EndpointSettings.pgSettings: Record` field — `src/v1/model.ts:1417` +### 40. `EndpointSettings.pgSettings: Record` field — `src/v1/model.ts:1417` - **Why weird:** `pgSettings` is a map of Postgres GUC settings (e.g. `{ work_mem: '4MB' }`). Generic value type `string`. No validation. Field name `pgSettings` is itself ambiguous — could be any kind of setting. - **Category:** 14 (proto map-entry shape leaks into TS), 1 (vague — `pgSettings` could be any kind of setting). - **Suggested name:** `postgresGucSettings: Record` (more specific). - **Rationale:** Field name should encode the domain (Postgres GUC parameters). -### 47. `ForwardEtlConfig.workspaceId: number` typed as integer — `src/v1/model.ts:1522` +### 41. `ForwardEtlConfig.workspaceId: number` typed as integer — `src/v1/model.ts:1522` - **Why weird:** `workspaceId` is a `number` (also see `ForwardEtlConfig.createTimeMillis` — same numeric type for two unrelated concepts). Databricks workspace IDs are 64-bit integers — TS `number` can't represent the full int64 range above 2^53. Should be `bigint` or string. - **Category:** 16 (field type contradicts domain — int64 wire vs JS number). - **Suggested name:** `workspaceId: string` (or `bigint`). - **Rationale:** Same precision pitfall as Java's `Long` going to JSON. -### 48. `GenerateDatabaseCredentialRequest.endpoint` field "not yet supported" — `src/v1/model.ts:1595-1598` +### 42. `GenerateDatabaseCredentialRequest.endpoint` field "not yet supported" — `src/v1/model.ts:1595-1598` - **Why weird:** Field doc says "This field is not yet supported." Field is exposed in the public TS type without an `@deprecated` or `@unsupported` JSDoc marker. - **Category:** 6 (misleading — looks usable but isn't). - **Suggested name:** Mark with `@deprecated` JSDoc and/or rename to `endpointReserved`. - **Rationale:** Same as `database` audit #56. -### 49. `GenerateDatabaseCredentialRequest.expiration` discriminated union — `src/v1/model.ts:1610-1627` -- **Why weird:** Same `oneof` pattern as #27 — `ttl` or `expireTime`. But here `noExpiry` doesn't exist; just two variants. The variant order in the union is `ttl` then `expireTime`, but on `BranchSpec.expiration` (#27) it's `expireTime` then `ttl`. Inconsistent variant ordering within the same package. +### 43. `GenerateDatabaseCredentialRequest.expiration` discriminated union — `src/v1/model.ts:1610-1627` +- **Why weird:** Same `oneof` pattern as #21 — `ttl` or `expireTime`. But here `noExpiry` doesn't exist; just two variants. The variant order in the union is `ttl` then `expireTime`, but on `BranchSpec.expiration` (#21) it's `expireTime` then `ttl`. Inconsistent variant ordering within the same package. - **Category:** 17 (inconsistent variant ordering across two siblings). - **Suggested name:** Standardise order across both unions. - **Rationale:** Minor but a generator/consistency check would catch it. -### 50. `InitialBranchSpec` / `InitialDatabaseSpec` / `InitialEndpointSpec` / `InitialRoleSpec` — 4 "Initial*Spec" types duplicate the corresponding `Spec` — `src/v1/model.ts:1734, 1746, 1757, 1776` -- **Why weird:** Four types named `InitialSpec`, each carrying the same field set as the corresponding `Spec`. The `Initial` prefix is documentation, not semantics — these are spec values for the *initial* default resources created with a project. `InitialRoleSpec` has nearly identical body to `Role_RoleSpec` (5 of 5 fields match). Duplicating the shape per-context multiplies the public surface. +### 44. `InitialBranchSpec` / `InitialDatabaseSpec` / `InitialEndpointSpec` / `InitialRoleSpec` — 4 "Initial*Spec" types duplicate the corresponding `Spec` — `src/v1/model.ts:1734, 1746, 1757, 1776` +- **Why weird:** Four types named `InitialSpec`, each carrying the same field set as the corresponding `Spec`. The `Initial` prefix is documentation, not semantics — these are spec values for the *initial* default resources created with a project. `InitialRoleSpec` has nearly identical body to the role spec type (5 of 5 fields match). Duplicating the shape per-context multiplies the public surface. - **Category:** 12 (duplicate concept). - **Suggested name:** Use the regular `Spec` types directly with a JSDoc note on `Project.initialBranchSpec` saying "use a `BranchSpec` value here; it applies only to the initial default branch". - **Rationale:** Doubles the type count for a docs-only distinction. -### 51. `NewPipelineSpec` (top-level) vs the comment "Specification for creating a new pipeline" — `src/v1/model.ts:1963` +### 45. `NewPipelineSpec` (top-level) vs the comment "Specification for creating a new pipeline" — `src/v1/model.ts:1963` - **Why weird:** Type name carries the verb "new" (`NewPipelineSpec`). Reads as "the new pipeline spec" (a noun phrase about a *new* type of pipeline) or "spec for a new pipeline" (the actual intent). Java/C# call these `CreatePipelineSpec` or `PipelineCreate`. The type holds 4 fields (`storageCatalog`, `storageSchema`, `budgetPolicyId`, `pipelineChannel`). - **Category:** 13 (verb-tense — `new` as adjective for a type name), 6 (misleading). - **Suggested name:** `PipelineCreationSpec` or `NewPipelineConfig`. - **Rationale:** Type names with embedded verbs are awkward; consider `Spec` only when the type *configures* something. -### 52. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:2014` +### 46. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:2014` - **Why weird:** Plain `Record`. The 22 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1862-1865` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. - **Category:** 15 (generic), 16 (loose typing). - **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. -- **Rationale:** Same root cause as #20 — opaque records on the public surface. +- **Rationale:** Same root cause as #14 — opaque records on the public surface. -### 53. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:2027-2038` +### 47. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:2027-2038` - **Why weird:** Variant `response` carries `Record` (line 2036). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) - **Category:** 16 (asymmetric typing), 15 (generic on success arm). -- **Suggested name:** Same as #52 — generic `Operation` with both arms typed. -- **Rationale:** Same as #20, #52. +- **Suggested name:** Same as #46 — generic `Operation` with both arms typed. +- **Rationale:** Same as #14, #46. -### 54. `Project.spec` / `Project.status` / `Project.initialBranchSpec` / `Project.initialRoleSpec` / `Project.initialDatabaseSpec` / `Project.initialEndpointSpec` — six spec/status fields on one type, four are write-only — `src/v1/model.ts:2054-2095` +### 48. `Project.spec` / `Project.status` / `Project.initialBranchSpec` / `Project.initialRoleSpec` / `Project.initialDatabaseSpec` / `Project.initialEndpointSpec` — six spec/status fields on one type, four are write-only — `src/v1/model.ts:2054-2095` - **Why weird:** Single `Project` type carries spec + status + four initial-* sub-specs. The four `initial*` fields are create-time-only inputs but exposed on the response type too — a read-flow consumer sees four fields that are always empty. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). - **Suggested name:** Hoist the `initial*` fields onto `CreateProjectRequest` only (where they belong); leave `Project` to spec/status. - **Rationale:** Same as `database` audit #11 — input/output shape confusion. -### 55. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:2098`, `database:206` +### 49. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:2098`, `database:206` - **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. - **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). - **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. - **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. -### 56. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:2148, 2191` +### 50. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:2148, 2191` - **Why weird:** Doc says "The major Postgres version number. Supported versions are 16 and 17." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. - **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). - **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. - **Rationale:** Aligns documented constraints with the type system. -### 57. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:2150, 2193` +### 51. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:2150, 2193` - **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. - **Category:** 17 (inconsistent with sister package). - **Suggested name:** Pick one convention across the two packages. - **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. -### 58. `ProjectSpec.workspaceKeyEncrypted: boolean` — `src/v1/model.ts:2170` +### 52. `ProjectSpec.workspaceKeyEncrypted: boolean` — `src/v1/model.ts:2170` - **Why weird:** Field doc admits the flag is temporary: "Since we need to do an end to end perf bench using BSS API to A/B test the performance impact of CMK encryption, we need to be able to control this flag in the API. This flag will be removed once we find a better way…" Flag is exposed on the public SDK surface. - **Category:** 14 (internal-jargon leak — "BSS API", "CMK"), 6 (misleading — flag is benchmark-temporary). - **Suggested name:** Either hide behind an internal beta-flag mechanism, or rename to `workspaceCmkEnabled` and document it neutrally. - **Rationale:** Benchmark scaffolding on the public surface. -### 59. `ProjectSpec.enablePgNativeLogin` / `ProjectStatus.enablePgNativeLogin` — request-shaped verb on response — `src/v1/model.ts:2172, 2208` +### 53. `ProjectSpec.enablePgNativeLogin` / `ProjectStatus.enablePgNativeLogin` — request-shaped verb on response — `src/v1/model.ts:2172, 2208` - **Why weird:** Same problem as `database` audit #25: `enableX: boolean` reads as imperative on a response type. `ProjectStatus.enablePgNativeLogin` should read "is PG native login enabled". - **Category:** 6 (misleading verb form), 17 (input/output asymmetry). - **Suggested name:** Input: `enablePgNativeLogin`. Output: `pgNativeLoginEnabled`. - **Rationale:** Same as `database` audit #25. -### 60. `RequestedResource.resourceName` discriminated union with `unspecifiedResourceName` and `tableName` — `src/v1/model.ts:2237-2246` +### 54. `RequestedResource.resourceName` discriminated union with `unspecifiedResourceName` and `tableName` — `src/v1/model.ts:2237-2246` - **Why weird:** Same as `database` audit #16 — discriminated union whose `unspecifiedResourceName` variant exists only because the proto generator emits sentinel branches. `tableName` is the only useful variant. - **Category:** 1 (vague), 6 (misleading — `unspecifiedResourceName` exists in TS but shouldn't). - **Suggested name:** Top-level `RequestedResource = {kind: 'table', tableName: string}`. - **Rationale:** Same as `database` audit #16. -### 61. `SyncedTable_SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:2419` +### 55. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:2419` - **Why weird:** Same as `database` audit #35: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Same as `database` audit #35. -### 62. `SyncedTable_SyncedTableSpec.acceleratedSync` / `createDatabaseObjectsIfMissing` / `extraIndexDefinitions` / `extraColumnDefinitions` / `typeOverrides` — same fields, same issues as `database` package — `src/v1/model.ts:2447, 2434, 2454, 2458, 2452` +### 56. Synced-table spec fields `acceleratedSync` / `createDatabaseObjectsIfMissing` / `extraIndexDefinitions` / `extraColumnDefinitions` / `typeOverrides` — same fields, same issues as `database` package — `src/v1/model.ts:2447, 2434, 2454, 2458, 2452` - **Why weird:** Identical to `database` audit findings #37–#42. Won't re-state at length; flag that the duplication exists across both packages with identical naming. - **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). - **Suggested name:** Same suggestions as `database` audit. - **Rationale:** Two SDKs, same problems. -### 63. `Table` (non-synced) — generic single-word type — `src/v1/model.ts:2586` +### 57. `Table` (non-synced) — generic single-word type — `src/v1/model.ts:2586` - **Why weird:** `Table` is the most generic possible name. Doc: "Table represents a non-synced database table in a Lakebase project. Unlike SyncedTable, this does not have a data synchronization pipeline." Sibling `SyncedTable` has the "Synced" qualifier; this one should have "NonSynced" or "Native" qualifier. Bare `Table` is also confusable with UC `Table`, online `Table`, etc. - **Category:** 1 (vague/generic), 12 (duplicate concept — `Table` exists in multiple SDK packages). - **Suggested name:** `LakebaseTable` or `NativeTable` or `PgTable`. -- **Rationale:** Same as #23. +- **Rationale:** Same as #17. -### 64. `Table.database` / `Table.project` / `Table.branch` — three string fields, each a different resource path — `src/v1/model.ts:2594-2598` +### 58. `Table.database` / `Table.project` / `Table.branch` — three string fields, each a different resource path — `src/v1/model.ts:2594-2598` - **Why weird:** Three sibling string fields, each holding a different multi-segment path. `database` is `projects/{}/branches/{}/databases/{}`, `project` is `projects/{}`, `branch` is `projects/{}/branches/{}`. Two of them (`project` and `branch`) are prefixes of `database`. No discriminator. - **Category:** 19 (underspecified ids), 1 (vague — bare `project` could be many things). - **Suggested name:** `databaseName` / `projectName` / `branchName` (and prefix each with the resource type the path identifies). - **Rationale:** Three resource paths under generic field names. -### 65. `Table.tableServingUrl` / `DatabaseTable.tableServingUrl` (in `database` package) — same field, same issue — `src/v1/model.ts:2600` +### 59. `Table.tableServingUrl` / `DatabaseTable.tableServingUrl` (in `database` package) — same field, same issue — `src/v1/model.ts:2600` - **Why weird:** `tableServingUrl` is opaque (see `database` audit #33). "Serving" is feature-store jargon for "REST endpoint for reads". On a Postgres table, the meaning is "REST API to read this table". Field doc: "REST API URL for serving data from this table." - **Category:** 1 (vague), 6 (misleading — `Serving` is feature-store terminology). - **Suggested name:** `restEndpointUrl` / `apiEndpointUrl`. - **Rationale:** Same as `database` audit #33. -### 66. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2629` +### 60. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2629` - **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. - **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). - **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. - **Rationale:** AIP `FieldMask` is an industry pattern, but it should not be the only update affordance. -### 67. `DeleteForwardEtlConfigurationResponse.deletedConfigs` / `deletedMappings` — count fields without singular form — `src/v1/model.ts:1247-1250` +### 61. `DeleteForwardEtlConfigurationResponse.deletedConfigs` / `deletedMappings` — count fields without singular form — `src/v1/model.ts:1247-1250` - **Why weird:** Field is `deletedConfigs: number | undefined` — a count, not a list. The name reads as a plural array (`deletedConfigs: Config[]`). JSDoc clarifies "Number of configuration rows deleted (0 or 1)". - **Category:** 9 (singular/plural mismatch — plural name on a `number`), 1 (vague). - **Suggested name:** `deletedConfigCount` / `deletedMappingCount`. - **Rationale:** Reader sees `deletedConfigs` and expects an array. -### 68. `getOperation` / `Operation.name` — operation name is a resource path — `src/v1/client.ts:1109`, `model.ts:1699` +### 62. `getOperation` / `Operation.name` — operation name is a resource path — `src/v1/client.ts:1109`, `model.ts:1699` - **Why weird:** `getOperation({name: ...})` takes a `string` that is actually a path like `operations/{unique_id}`. The doc on `Operation.name` says "If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`." But it doesn't validate. - **Category:** 19 (underspecified id), 6 (misleading — `name` reads like a label). - **Suggested name:** `operationResourceName` / `operationPath` / `id`. -- **Rationale:** Same as #25. +- **Rationale:** Same as #19. -### 69. `createTable` / `deleteTable` / `getTable` — operate on `Table`, not the synced version — `src/v1/client.ts:502, 826, 1207` +### 63. `createTable` / `deleteTable` / `getTable` — operate on `Table`, not the synced version — `src/v1/client.ts:502, 826, 1207` - **Why weird:** Method names `createTable` are generic; consumer must read the JSDoc to know they target the `Table` (non-synced) resource. Sibling `createSyncedTable` is explicit. `Table` operations are CRUD over native PG tables; the method name should signal that. - **Category:** 1 (vague — `createTable` is generic), 12 (duplicate concept — also `CreateDatabaseTableRequest` in `database` package). - **Suggested name:** `createNativeTable` / `createLakebaseTable` (mirror the `createSyncedTable` pattern). @@ -472,103 +433,103 @@ ## Low severity -### 70. `BranchSpec.sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` — `src/v1/model.ts:785, 787, 789` +### 64. `BranchSpec.sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` — `src/v1/model.ts:785, 787, 789` - **Why weird:** Three sibling fields on `BranchSpec`. `sourceBranch` is a path; `sourceBranchLsn` and `sourceBranchTime` are alternative cutover specifiers (one or the other). Bare `branchTime` repeats from `database/v1.DatabaseInstanceRef.branchTime` (see `database` audit #28). - **Category:** 1 (vague — `branchTime` is a cutover instant, not a time-of-branch). - **Suggested name:** `sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` are OK; consider `sourceBranchAtLsn` / `sourceBranchAtTime` for clarity. - **Rationale:** Same as `database` audit #28. -### 71. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:805, 850` +### 65. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:805, 850` - **Why weird:** Field name `expireTime` appears twice: once as a discriminated-union variant on `BranchSpec` (input), once as a top-level field on `BranchStatus` (output). Reader has to track that the input shape collapses `expireTime`/`ttl`/`noExpiry` to a single output value `expireTime`. - **Category:** 17 (input/output shape mismatch). - **Suggested name:** Document the asymmetry in JSDoc; or expose the same union shape on output. - **Rationale:** Generator-driven asymmetry. -### 72. `BranchSpec.ttl: Temporal.Duration` and `BranchSpec.expireTime` — `ttl` is a duration, `expireTime` is a timestamp — `src/v1/model.ts:813, 805` +### 66. `BranchSpec.ttl: Temporal.Duration` and `BranchSpec.expireTime` — `ttl` is a duration, `expireTime` is a timestamp — `src/v1/model.ts:813, 805` - **Why weird:** `ttl` (time-to-live) and `expireTime` are sibling variants. `ttl` is duration-shaped; `expireTime` is timestamp-shaped. Bare `ttl` is a Unix-cache-style abbreviation. - **Category:** 5 (cryptic abbreviation — `ttl`). - **Suggested name:** `lifetime: Duration` or `expireAfter: Duration`. - **Rationale:** `TTL` is widely understood but expansion improves grep-ability. -### 73. `CreateBranchRequest.replaceExisting` vs `DeleteBranchRequest.allowMissing` — verb-tense asymmetry across CRUD — `src/v1/model.ts:995, 1200` +### 67. `CreateBranchRequest.replaceExisting` vs `DeleteBranchRequest.allowMissing` — verb-tense asymmetry across CRUD — `src/v1/model.ts:995, 1200` - **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete uses `allowMissing: boolean` (tolerant). Two different conventions for the "if it does/doesn't exist" behaviour. Update has no such field; Get doesn't either. Inconsistent. - **Category:** 17 (inconsistent action verbs across CRUD). - **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. - **Rationale:** Inconsistent options across CRUD operations is a small papercut. -### 74. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1195` +### 68. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1195` - **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete. Soft deletion (purge=false) is not supported yet." So the value of `false` is rejected. Same `purge` field on `DeleteProjectRequest` (line 1263). - **Category:** 16 (type allows `false` but spec rejects), 6 (misleading — purge implies cleanup, not the *only* delete mode). - **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. Add `@deprecated` until soft-delete is supported. - **Rationale:** Boolean toggle for a future-3-state field. -### 75. `DeleteForwardEtlConfigurationRequest` vs `DisableForwardEtlRequest` — two near-identical types — `src/v1/model.ts:1229, 1306` -- **Why weird:** Both types carry `parent`, `tenantId`, `timelineId`, `pgDatabaseOid`, `pgSchemaOid`. Doc on `DeleteForwardEtlConfigurationRequest`: "Unlike DisableForwardEtl, this permanently removes the config and mapping rows." The distinction is `Delete` (hard) vs `Disable` (soft) — same boolean-toggle pattern as `purge` (#74) but split into two types. +### 69. `DeleteForwardEtlConfigurationRequest` vs `DisableForwardEtlRequest` — two near-identical types — `src/v1/model.ts:1229, 1306` +- **Why weird:** Both types carry `parent`, `tenantId`, `timelineId`, `pgDatabaseOid`, `pgSchemaOid`. Doc on `DeleteForwardEtlConfigurationRequest`: "Unlike DisableForwardEtl, this permanently removes the config and mapping rows." The distinction is `Delete` (hard) vs `Disable` (soft) — same boolean-toggle pattern as `purge` (#68) but split into two types. - **Category:** 12 (duplicate concept), 17 (different verbs for the same shape). - **Suggested name:** Merge into one request type with a `mode: 'delete' | 'disable'` field. - **Rationale:** Two methods carrying identical fields suggests one method with a flag. -### 76. `ForwardEtlMetadata.databases` / `schemas` — bare plurals — `src/v1/model.ts:1554, 1556` +### 70. `ForwardEtlMetadata.databases` / `schemas` — bare plurals — `src/v1/model.ts:1554, 1556` - **Why weird:** `databases: ForwardEtlDatabase[]` and `schemas: ForwardEtlSchema[]` — bare plurals. Inside a `ForwardEtl` context, these are PG OID-to-name maps, not regular databases/schemas. Reader expects `Database` (the SDK type) but gets `ForwardEtlDatabase` (a name+OID pair). - **Category:** 1 (vague — `databases` is too generic in a `ForwardEtl` context), 17 (`Database` SDK type vs `ForwardEtlDatabase` ad-hoc type). - **Suggested name:** `databaseOids` / `schemaOids` (matches the underlying domain), or keep plurals but document. - **Rationale:** Mild — context disambiguates. -### 77. `ForwardEtlTableMapping.lastSyncedLsn: string` — LSN as bare string — `src/v1/model.ts:1582` +### 71. `ForwardEtlTableMapping.lastSyncedLsn: string` — LSN as bare string — `src/v1/model.ts:1582` - **Why weird:** Postgres LSN is `XX/YY` string. Field name uses `Lsn` abbreviation without expansion. Sibling `pgTableOid` already a Postgres-internal. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `lastSyncedLogSequenceNumber` (or `walLsn`). - **Rationale:** Same as `database` audit #27. -### 78. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1593` +### 72. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1593` - **Why weird:** Same as `database` audit #53 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Same as `database` audit #53 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. - **Rationale:** Same as `database` audit #53. -### 79. `GenerateDatabaseCredentialRequest.groupName: string` — `src/v1/model.ts:1604` +### 73. `GenerateDatabaseCredentialRequest.groupName: string` — `src/v1/model.ts:1604` - **Why weird:** Doc: "Databricks workspace group name. When provided, credentials are generated with permissions scoped to this group." Bare `groupName` reads as a Postgres role name; actually a Databricks workspace group. Field is sibling to `claims` and `endpoint`; the relationship between them isn't spelled out (do you set all three? one? two?). - **Category:** 1 (vague — `groupName` could be PG or DB workspace), 17 (multi-field request without clear mutex docs). - **Suggested name:** `workspaceGroupName`. - **Rationale:** Disambiguate from Postgres role names. -### 80. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:2020` +### 74. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:2020` - **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1885`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. - **Rationale:** Tri-state booleans always confuse callers. -### 81. `Project.deleteTime` / `Project.purgeTime` — two delete-related timestamps — `src/v1/model.ts:2067, 2072` +### 75. `Project.deleteTime` / `Project.purgeTime` — two delete-related timestamps — `src/v1/model.ts:2067, 2072` - **Why weird:** `deleteTime` = "when soft-deleted"; `purgeTime` = "when scheduled for permanent deletion". Bare verbs `delete` / `purge` are similar; the distinction matters for the consumer but the field names alone don't communicate the lifecycle. - **Category:** 1 (vague), 6 (misleading — `purge` could mean "purged at" or "scheduled to purge"). - **Suggested name:** `softDeletedAt` / `scheduledPurgeAt`. - **Rationale:** Lifecycle-related fields benefit from clearer past/future tense. -### 82. `ProjectStatus.syntheticStorageSizeBytes` — "synthetic" qualifier — `src/v1/model.ts:2199` +### 76. `ProjectStatus.syntheticStorageSizeBytes` — "synthetic" qualifier — `src/v1/model.ts:2199` - **Why weird:** `syntheticStorageSizeBytes` — what's "synthetic" about storage? Doc says "The current space occupied by the project in storage." JSDoc doesn't explain "synthetic". Likely Lakebase internal billing concept. - **Category:** 1 (vague), 14 (internal-jargon leak). - **Suggested name:** `storageSizeBytes` or `billingStorageSizeBytes`. - **Rationale:** Internal-jargon leak. -### 83. `ProjectStatus.computeLastActiveTime` — `src/v1/model.ts:2201` +### 77. `ProjectStatus.computeLastActiveTime` — `src/v1/model.ts:2201` - **Why weird:** Doc: "The most recent time when any endpoint of this project was active." Field name is `compute` + `lastActiveTime` — reads as "the compute last active time" with an implicit possessive. Awkward grammar. - **Category:** 1 (vague), 17 (irregular grammar). - **Suggested name:** `lastComputeActiveTime` or `lastActivityTime` or `lastEndpointActivityTime`. - **Rationale:** Word ordering in compound field names matters for grep-ability. -### 84. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:797, 803, 811, 820, 1447, 1455, 1465` +### 78. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:797, 803, 811, 820, 1447, 1455, 1465` - **Why weird:** JSDoc references update mask in snake_case (e.g. "When updating this field, use `spec.expiration` in the update_mask"). Update mask field on the request is `updateMask: FieldMask<...>` (camelCase) but docs reference the wire-format name. Consumer reading the JSDoc and writing TS code has to translate. - **Category:** 17 (inconsistent — JSDoc snake_case, TS camelCase). - **Suggested name:** Use TS field name in JSDoc. - **Rationale:** Doc/code drift. -### 85. `ListBranchesRequest.showDeleted` / `ListProjectsRequest.showDeleted` — pair of duplicate optional flags — `src/v1/model.ts:1844, 1934` +### 79. `ListBranchesRequest.showDeleted` / `ListProjectsRequest.showDeleted` — pair of duplicate optional flags — `src/v1/model.ts:1844, 1934` - **Why weird:** Two structs carry identical `showDeleted?: boolean` with similar JSDoc. Not bad on its own, but the option name `showDeleted` is itself an imperative-shaped name on a request type (compare to `includeDeleted` or `deletedOnly`). - **Category:** 1 (vague — `show` is presentation-layer language for a server request). - **Suggested name:** `includeDeleted` or `includeSoftDeleted`. - **Rationale:** Same as `database` audit #25 — request shapes prefer descriptive booleans over imperative ones. -### 86. `listComputeInstances`'s doc reads "The parent, which owns the compute instances" — `src/v1/model.ts:1855` +### 80. `listComputeInstances`'s doc reads "The parent, which owns the compute instances" — `src/v1/model.ts:1855` - **Why weird:** `ListComputeInstancesRequest.parent` doc is sparse: "The parent, which owns the compute instances." No format given. Compare to sibling `ListBranchesRequest.parent` which specifies "Format: `projects/{project_id}`". - **Category:** 6 (misleading — doc missing). - **Suggested name:** Fix the doc; add the format. @@ -576,25 +537,19 @@ ## Observation -### 87. Method JSDoc inconsistency — `src/v1/client.ts` throughout +### 81. Method JSDoc inconsistency — `src/v1/client.ts` throughout - **Why weird:** Some methods have rich JSDoc ("Creates a new database branch in the project.", "Register a Postgres database in the Unity Catalog."). Others are terse ("Create a Database.", "Get a Database.", "List Databases."). Inconsistency in doc depth across CRUD methods of the same resource. - **Category:** Observation (doc quality, not naming). - **Suggested name:** Standardise to the richer template. - **Rationale:** Naming-adjacent. -### 88. `Operation` is a separate type, not a generic — `src/v1/model.ts:2002` -- **Why weird:** All 22 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#21) or reads `Operation.result.response` (untyped `Record`). +### 82. `Operation` is a separate type, not a generic — `src/v1/model.ts:2002` +- **Why weird:** All 22 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#15) or reads `Operation.result.response` (untyped `Record`). - **Category:** Observation (architecture, not naming per se). - **Suggested name:** `Operation` generic. -- **Rationale:** Connects #20, #21, #52, #53. - -### 89. `EndpointSettings_PgSettingsEntry` and `ProjectDefaultEndpointSettings_PgSettingsEntry` are duplicated, dead types — `src/v1/model.ts:1421, 2136` -- **Why weird:** Both types are identical (`{key, value}`) and unused. They are proto-generated map-entry types. They are exported from `index.ts:91, 135`. -- **Category:** Observation (related to #46, #55). -- **Suggested name:** Remove (and also `ProjectCustomTag` could merge with `database.CustomTag`). -- **Rationale:** Public surface bloat. +- **Rationale:** Connects #14, #15, #46, #47. -### 90. `ProvisioningInfo_State` is exported from both `database` and `postgres` packages with identical members — `src/v1/model.ts:654`, `database/v1/model.ts:148` +### 83. The provisioning-state enum is exported from both `database` and `postgres` packages with identical members — `src/v1/model.ts:654`, `database/v1/model.ts:148` - **Why weird:** Same enum, two packages, identical members. Reader importing both packages has to alias one. - **Category:** Observation (cross-package duplication). - **Suggested name:** Move to a shared `core/lakebase-common` or `core/enums`. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md index f802fba9..c3e5c441 100644 --- a/.agent/naming-audit/qualitymonitor.md +++ b/.agent/naming-audit/qualitymonitor.md @@ -3,15 +3,15 @@ **Path:** `packages/qualitymonitor/src/v2/` **Versions audited:** v2 **Inferred domain:** Quality monitoring on Unity Catalog objects (currently only `schema`). The package defines a single `QualityMonitor` entity that wraps `AnomalyDetectionConfig` (last-run telemetry plus excluded tables) and a list of `ValidityCheckConfiguration` arms (percent-null, range, uniqueness). A nested concept (`CustomCheckConfiguration` -> `CustomScalarCheck`) lets callers attach templated SQL checks with per-column matchers. Every operation is marked `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., this entire package is a deprecated shim that has been superseded by the `dataquality` package. -**Total weird names flagged:** 42 +**Total weird names flagged:** 38 ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 16 | +| High | 11 | +| Medium | 15 | | Low | 8 | -| Observation | 5 | +| Observation | 4 | ## CRITICAL: Two packages, same domain @@ -63,43 +63,31 @@ The singular-vs-plural naming gives the reader no hint that these are different - **Suggested name:** Document the relationship in JSDoc — clarify which location is authoritative when both are set. - **Rationale:** A reader cannot tell which one is the source of truth, which one is read-only, or whether both must match. The data model embeds ambiguity that callers have to test by experiment. -### 7. Enum members `ANOMALY_DETECTION_JOB_TYPE_*` — `src/v2/model.ts:5-9` -- **Why weird:** Enum is called `AnomalyDetectionJobType`, but every member is prefixed `ANOMALY_DETECTION_JOB_TYPE_` — at the call site users write `AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_NORMAL` (6 redundant tokens). -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names), 18 (overly long enum values). -- **Suggested name:** `AnomalyDetectionJobType.{Normal, InternalHidden}` and drop the unset sentinel (rely on `jobType?: ... | undefined`). Or strip just the prefix: `ANOMALY_DETECTION_JOB_TYPE_NORMAL` -> `NORMAL`. -- **Rationale:** TS enums namespace their values, so the `ANOMALY_DETECTION_JOB_TYPE_` prefix is dead context. - -### 8. Enum members `ANOMALY_DETECTION_RUN_STATUS_*` — `src/v2/model.ts:12-21` -- **Why weird:** Eight values, every one prefixed with `ANOMALY_DETECTION_RUN_STATUS_`, including `ANOMALY_DETECTION_RUN_STATUS_WORKSPACE_MISMATCH_ERROR` — a 51-character symbol. Sentinel is `_UNKNOWN` while the sibling enum (`AnomalyDetectionJobType`, #7) uses `_UNSPECIFIED` — inconsistent sentinel naming inside the same file. Also: `_FAILED` and `_WORKSPACE_MISMATCH_ERROR` are both error states with no documented difference. -- **Category:** 2 (redundant prefix), 14 (proto-style), 17 (sentinel inconsistency — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 18 (long enum values), 12 (likely duplicate concept — two error states). -- **Suggested name:** `AnomalyDetectionRunStatus.{Running, Pending, Canceled, Success, Failed, JobDeleted, WorkspaceMismatchError}`. Drop the sentinel. Resolve whether `Failed` and `WorkspaceMismatchError` are siblings or whether the latter is a `Failed` sub-state. -- **Rationale:** Same as #7. Cross-enum sentinel inconsistency will trip users who write `=== AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_UNSPECIFIED` and find that the run-status enum uses `_UNKNOWN` instead. - -### 9. Enum members `THRESHOLD_TYPE_*` — `src/v2/model.ts:23-28` -- **Why weird:** Four-value enum with proto-style `THRESHOLD_TYPE_UNSPECIFIED` / `_AUTO` / `_UNBOUNDED` / `_MANUAL`. The field that uses it is `Threshold.thresholdType` (line 131) — meaning at the call site you'd write `threshold.thresholdType === ThresholdType.THRESHOLD_TYPE_MANUAL` — "threshold" appears four times in the same expression. Also: the enum is *external* to the `Threshold` interface, even though it is used only by that one field, on that one interface — perfect candidate for a string-literal union (`'auto' | 'unbounded' | 'manual'`). -- **Category:** 2 (redundant enum prefix), 14 (proto-style), 18 (long enum values), 20 (type-suffix tautology — `Threshold.thresholdType: ThresholdType`). -- **Suggested name:** Replace the enum with a string-literal union on the field directly: `kind?: 'auto' | 'unbounded' | 'manual'`. Or, if keeping the enum, drop the prefix: `ThresholdType.{Auto, Unbounded, Manual}`. -- **Rationale:** Three-value, locally-used "kind" indicators are exactly where TS string-literal unions excel. - -### 10. `CustomScalarCheck.checkName` / `.sqlQuery` / `.columnMatchers` / `.thresholds` — `src/v2/model.ts:67-76` -- **Why weird:** The type is called `CustomScalarCheck`, but its first field is `checkName` (the type already says "Check"). Same redundancy as `ValidityCheckConfiguration.name` (#12). The four fields are: a name, a SQL query, a list of matchers, and a thresholds object — there is no internal qualifier that justifies `check` on `checkName`. +### 7. `AnomalyDetectionRunStatus` value `WORKSPACE_MISMATCH_ERROR` length and overlap with `FAILED` — `src/v2/model.ts:12-21` +- **Why weird:** The longest enum value is a 51-character `ANOMALY_DETECTION_RUN_STATUS_WORKSPACE_MISMATCH_ERROR`, with the full call-site form running over 80 columns. Beyond the length: both `FAILED` and `WORKSPACE_MISMATCH_ERROR` are error states with no documented distinction — a caller writing exhaustive status handling has to guess whether one is a sub-state of the other. The companion `AnomalyDetectionJobType` enum uses `_UNSPECIFIED` as its sentinel; this one uses `_UNKNOWN` — sentinel inconsistency between sibling enums in the same file. +- **Category:** 18 (overly long enum value), 17 (sentinel inconsistency — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 12 (likely duplicate concept — two indistinguishable error states). +- **Suggested name:** Shorten to `WorkspaceMismatch` (the `Error` suffix is dead context — every status here is a runtime outcome). Pick one sentinel convention across enums in this file. Resolve whether `Failed` and `WorkspaceMismatch` are siblings or whether the latter is a `Failed` sub-state. +- **Rationale:** Long enum values force callers to wrap lines; cross-enum sentinel inconsistency will trip users who switch on status values. + +### 8. `Threshold.thresholdType` — `src/v2/model.ts:131` +- **Why weird:** Type-suffix tautology. `Threshold.thresholdType: ThresholdType` — three "threshold" tokens in one line. Compare with the parallel pattern in `AnomalyDetectionConfig.jobType: AnomalyDetectionJobType` and `validityCheckConfigurations[i].checkType: ...`. Repetition runs throughout the package. The `ThresholdType` enum itself is a four-value indicator (`AUTO`, `UNBOUNDED`, `MANUAL`, plus sentinel) used by exactly this one field on this one interface — a perfect string-literal-union candidate. At the call site users currently write `threshold.thresholdType === ThresholdType.THRESHOLD_TYPE_MANUAL` — "threshold" appears four times in one expression. +- **Category:** 20 (type-suffix tautology), 18 (long enum values at call sites). +- **Suggested name:** Replace with a string-literal union on the field: `kind?: 'auto' | 'unbounded' | 'manual'`. Or, if keeping a nominal enum, rename the field to `kind: ThresholdKind` or `mode: ThresholdMode`. +- **Rationale:** "Kind" / "Mode" reads cleanly when a discriminator is required, and a three-value locally-used indicator is exactly where TS string-literal unions excel. + +### 9. `CustomScalarCheck.checkName` / `.sqlQuery` / `.columnMatchers` / `.thresholds` — `src/v2/model.ts:67-76` +- **Why weird:** The type is called `CustomScalarCheck`, but its first field is `checkName` (the type already says "Check"). Same redundancy as `ValidityCheckConfiguration.name` (#11). The four fields are: a name, a SQL query, a list of matchers, and a thresholds object — there is no internal qualifier that justifies `check` on `checkName`. - **Category:** 8 (redundant suffix — `check` is already in the type name). - **Suggested name:** `name`, `sqlQuery`, `columnMatchers`, `thresholds`. Or, if the rest of the family follows the pattern, accept and standardise on `check*`. - **Rationale:** Redundant prefixes are dead context — readers know they are looking at a `CustomScalarCheck` from the type. -### 11. `ValidityCheckConfiguration` + `PercentNullValidityCheck` / `RangeValidityCheck` / `UniquenessValidityCheck` — `src/v2/model.ts:102-160` -- **Why weird:** Identical to `dataquality` finding #14. Four sibling types all carry the `ValidityCheck` suffix, and the wrapping discriminated-union container type is `ValidityCheckConfiguration` — adding `Configuration` on top of `Check`. The wire-style discriminator names (`percentNullValidityCheck`, etc.) re-state the `ValidityCheck` suffix again. Combined, the path `monitor.validityCheckConfigurations[0].checkType.$case === 'percentNullValidityCheck'` repeats "validity-check" three times within nine identifier-positions. -- **Category:** 8 (redundant suffix), 20 (type-suffix tautology), 18 (effectively-long discriminator strings). -- **Suggested name:** Drop `ValidityCheck` from each arm type -> `PercentNullCheck` / `RangeCheck` / `UniquenessCheck`. Drop `Configuration` from container -> `ValidityCheck` (the container). Discriminator: `kind: 'percentNull' | 'range' | 'uniqueness'`. -- **Rationale:** A `ValidityCheck.kind === 'range'` reads cleanly; the current form is "validity check configuration that has a check type whose case is range validity check" — five repetitions of "check". - -### 12. `ValidityCheckConfiguration.name` JSDoc "Can be set by system. Does not need to be user facing." — `src/v2/model.ts:148-149` +### 10. `ValidityCheckConfiguration.name` JSDoc "Can be set by system. Does not need to be user facing." — `src/v2/model.ts:148-149` - **Why weird:** A field whose own JSDoc admits it "does not need to be user facing" — yet it is part of the public TS type. The doc is also self-contradictory: "Can be set by system" implies output-only, but the field is plain optional (no `@readonly`). A user reading this has no idea whether to set it, what it does, or whether the server will ignore it. - **Category:** 1 (vague — `name` is generic), 6 (misleading — output-only not typed as such), 15 (generic field name on a non-public-facing concept). - **Suggested name:** Rename to `internalName` (matches the JSDoc), or mark with `@readonly` and rename to `systemAssignedName`. - **Rationale:** Public types should not contain "system-set, not user-facing" fields without clear scoping. -### 13. `QualityMonitor` field-name irregularity: `anomalyDetectionConfig` (singular `Config`) vs `validityCheckConfigurations` (plural `Configurations`) — `src/v2/model.ts:114,116` +### 11. `QualityMonitor` field-name irregularity: `anomalyDetectionConfig` (singular `Config`) vs `validityCheckConfigurations` (plural `Configurations`) — `src/v2/model.ts:114,116` - **Why weird:** The two configuration fields on `QualityMonitor` use different singular/plural forms of "Config(uration)". `anomalyDetectionConfig` is a single object; `validityCheckConfigurations` is an array. The plural form follows from the array shape, but the *word* differs (`Config` vs `Configuration`). A reader scanning the type sees two near-synonyms within three lines. - **Category:** 17 (inconsistent word choice between sibling fields), 7 (verbose — `Configurations` is longer than necessary). - **Suggested name:** Pick one: `anomalyDetectionConfig` + `validityCheckConfigs` (both abbreviated), or rename the array to `validityChecks` and the object to `anomalyDetection` (drop the Config suffix entirely — the type names already say "Config"). @@ -107,97 +95,91 @@ The singular-vs-plural naming gives the reader no hint that these are different ## Medium severity -### 14. `AnomalyDetectionConfig.lastRunId` and `.latestRunStatus` (`Last` vs `Latest`) — `src/v2/model.ts:32,34` +### 12. `AnomalyDetectionConfig.lastRunId` and `.latestRunStatus` (`Last` vs `Latest`) — `src/v2/model.ts:32,34` - **Why weird:** Two adjacent fields use different superlative adjectives for the same concept: `lastRunId` and `latestRunStatus`. Both refer to the most recent run. JSDoc reinforces the mismatch: "Run id of the last run of the workflow" and "The status of the last run of the workflow." — same noun, different field-name modifier. - **Category:** 17 (inconsistent vocabulary), 12 (duplicate concept across siblings). - **Suggested name:** Pick one. `lastRunId` + `lastRunStatus`, or `latestRunId` + `latestRunStatus`. - **Rationale:** Sibling fields describing properties of the same entity should use the same word. -### 15. `AnomalyDetectionConfig.jobType` doc text "The type of the last run of the workflow." — `src/v2/model.ts:36` -- **Why weird:** Field name says `jobType`, doc says "The type of the **last run** of the workflow." That is conflating two things: the type of the workflow/job (a config property) vs the type of the last run (a per-run property). A reader cannot tell which it is. Looking at the enum (`AnomalyDetectionJobType` with `_NORMAL` and `_INTERNAL_HIDDEN`), these look like job classifications, not per-run modes — so the doc is probably wrong. +### 13. `AnomalyDetectionConfig.jobType` doc text "The type of the last run of the workflow." — `src/v2/model.ts:36` +- **Why weird:** Field name says `jobType`, doc says "The type of the **last run** of the workflow." That is conflating two things: the type of the workflow/job (a config property) vs the type of the last run (a per-run property). A reader cannot tell which it is. Looking at the enum (`AnomalyDetectionJobType` with `NORMAL` and `INTERNAL_HIDDEN`), these look like job classifications, not per-run modes — so the doc is probably wrong. - **Category:** 6 (misleading — name and doc contradict), 1 (vague — `jobType` could be either). - **Suggested name:** If this is a workflow-level property: keep `jobType`, fix the doc to "The classification of the anomaly-detection job." If per-run: rename to `lastRunJobType` and keep the doc. - **Rationale:** Field-name vs doc disagreement forces callers to test by experiment. -### 16. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v2/model.ts:38` +### 14. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v2/model.ts:38` - **Why weird:** Same as `dataquality` finding #19. "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning. Other Databricks SDK packages use `fullName` consistently for UC three-part names — here the suffix is `FullNames` (plural of FullName), making this the only field that says "full" then "names". - **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). - **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or document the format in JSDoc. - **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary. The field at minimum should be `excludedTableFullyQualifiedNames` for accuracy, or `excludedTables` for brevity. -### 17. `Threshold.boundValue` JSDoc says "Meaningful only if threshold_type is MANUAL" — `src/v2/model.ts:129-130` +### 15. `Threshold.boundValue` JSDoc says "Meaningful only if threshold_type is MANUAL" — `src/v2/model.ts:129-130` - **Why weird:** Two fields, one of which is meaningful only when the other has a specific value. This is again the discriminated-union pattern modelled as plain optional fields. Reads as: when `thresholdType === MANUAL`, you must provide `boundValue`; when `thresholdType === AUTO` or `UNBOUNDED`, you must not. The type does not encode this. - **Category:** 6 (misleading — type allows nonsensical combinations), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `Threshold = {kind: 'auto'} | {kind: 'unbounded'} | {kind: 'manual', value: number}`. - **Rationale:** Same anti-pattern as `objectType`/`objectId` (#4). Wire-driven shape rather than TS-friendly modelling. -### 18. `Threshold.thresholdType` — `src/v2/model.ts:131` -- **Why weird:** Type-suffix tautology. `Threshold.thresholdType: ThresholdType` — three "threshold" tokens in one line. Compare with the parallel pattern in `AnomalyDetectionConfig.jobType: AnomalyDetectionJobType` and `validityCheckConfigurations[i].checkType: ...`. Repetition runs throughout the package. -- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). -- **Suggested name:** `kind: ThresholdKind` or `mode: ThresholdMode`. Or, with #9 applied: `kind: 'auto' | 'unbounded' | 'manual'`. -- **Rationale:** "Kind" / "Mode" reads cleanly when a discriminator is required. - -### 19. `CustomScalarCheck.checkName` doc "Name of the custom check" — `src/v2/model.ts:68-69` +### 16. `CustomScalarCheck.checkName` doc "Name of the custom check" — `src/v2/model.ts:68-69` - **Why weird:** Field is on `CustomScalarCheck` (already a custom-check); the doc says "Name of the custom check". Both the type name and the doc say "custom check" — but the discriminator `$case: 'scalarCheck'` says "scalar check". The doc is one step abstracted from the actual type — readers see "custom check" and have to map it back to `CustomScalarCheck`. - **Category:** 8 (redundant suffix — `check` is in the type name), 17 (inconsistent vocabulary — "scalar" vs "custom"). - **Suggested name:** Field: `name`. Doc: "Name of the scalar check definition." - **Rationale:** Drop the redundant prefix; align the doc with the actual type name. -### 20. `CustomScalarCheck.sqlQuery` doc "Templated SQL query for this check" — `src/v2/model.ts:70-71` +### 17. `CustomScalarCheck.sqlQuery` doc "Templated SQL query for this check" — `src/v2/model.ts:70-71` - **Why weird:** "Templated" appears in the doc but not the field name — a caller looking at autocomplete sees only `sqlQuery: string` and has no hint that templating syntax is allowed (or expected). The JSDoc carries the only signal. Other SDK packages with templated SQL fields (e.g. `dataquality.CustomMetric.definition`) call them out as Jinja templates explicitly. - **Category:** 1 (vague — `sqlQuery` undersells the template syntax), 6 (misleading — looks like raw SQL). - **Suggested name:** `sqlQueryTemplate`, or `templatedSql`, or keep the name and expand the JSDoc to spell out the templating language (Jinja? Mustache? proprietary?). - **Rationale:** Templates and raw SQL are very different inputs; the type signature should hint at the distinction. -### 21. `CustomScalarCheck.columnMatchers` and `ColumnMatcher.variableName` — `src/v2/model.ts:43-48,72-73` -- **Why weird:** `ColumnMatcher` is a pair `{variableName, columnNames}`. The JSDoc on `variableName` says "Variable name within a custom sql query that this matcher applies to" — so `variableName` is the template variable from #20. Then `columnNames` is "List of column names (in target tables) to match." So the data flow is: `sqlQuery` references template variables, each `ColumnMatcher` maps one variable to a list of candidate column names. None of this is obvious from the type names alone. `ColumnMatcher.variableName` looks like a TS variable name, not a template placeholder. +### 18. `CustomScalarCheck.columnMatchers` and `ColumnMatcher.variableName` — `src/v2/model.ts:43-48,72-73` +- **Why weird:** `ColumnMatcher` is a pair `{variableName, columnNames}`. The JSDoc on `variableName` says "Variable name within a custom sql query that this matcher applies to" — so `variableName` is the template variable from #17. Then `columnNames` is "List of column names (in target tables) to match." So the data flow is: `sqlQuery` references template variables, each `ColumnMatcher` maps one variable to a list of candidate column names. None of this is obvious from the type names alone. `ColumnMatcher.variableName` looks like a TS variable name, not a template placeholder. - **Category:** 1 (vague — `variableName` could mean many things), 5 (jargon — `Matcher` is itself a generic word). - **Suggested name:** Rename `ColumnMatcher` -> `TemplateColumnBinding` (or `SqlVariableBinding`). Field `variableName` -> `templateVariable` or `placeholder`. Field `columnNames` -> `candidateColumns`. - **Rationale:** Template binding is the concept here; the current naming hides it. -### 22. `CustomCheckThresholds.lowerBound` / `.upperBound` vs `RangeValidityCheck.lowerBound` / `.upperBound` — `src/v2/model.ts:62-64,123-125` +### 19. `CustomCheckThresholds.lowerBound` / `.upperBound` vs `RangeValidityCheck.lowerBound` / `.upperBound` — `src/v2/model.ts:62-64,123-125` - **Why weird:** Two unrelated types use the same field name pair (`lowerBound`/`upperBound`) for very different things. In `CustomCheckThresholds`, the bounds are `Threshold` objects (i.e. `{boundValue, thresholdType}`). In `RangeValidityCheck`, the bounds are `number`. Same field name, different types — a reader pattern-matching on `lowerBound` cannot rely on it being a number anywhere. - **Category:** 17 (inconsistent type for identical field name), 15 (generic field name — `lowerBound` of what?). - **Suggested name:** `CustomCheckThresholds.lower: Threshold` + `.upper: Threshold` (drop `Bound` since `Threshold` is the type). `RangeValidityCheck.lowerBound: number` + `.upperBound: number` (keep). - **Rationale:** Identical field names across sibling types should imply identical semantics. Differentiate the threshold-wrapping case by dropping `Bound`. -### 23. `PercentNullValidityCheck.upperBound` doc "Optional upper bound; we should use auto determined bounds for now" — `src/v2/model.ts:105-106` +### 20. `PercentNullValidityCheck.upperBound` doc "Optional upper bound; we should use auto determined bounds for now" — `src/v2/model.ts:105-106` - **Why weird:** Doc text reads like an internal TODO ("we should use auto determined bounds for now"). The "we" is the API team; "for now" implies the field's semantics are in flux. Public SDK documentation should be definitive, not provisional. Also: field is typed `number` with no unit hint — is this 0-100 or 0-1? - **Category:** 6 (misleading — provisional doc text in a stable type), 1 (vague — `upperBound` of what units? percentage? fraction?). - **Suggested name:** Field stays; doc should clarify units ("Optional upper bound on the null-percentage (0-100). If unset, the server auto-determines a bound."). Strip the internal TODO. - **Rationale:** Doc-style cleanliness and unit precision. -### 24. `PercentNullValidityCheck.columnNames` (and `RangeValidityCheck.columnNames`, `UniquenessValidityCheck.columnNames`) — `src/v2/model.ts:103,120,135` +### 21. `PercentNullValidityCheck.columnNames` (and `RangeValidityCheck.columnNames`, `UniquenessValidityCheck.columnNames`) — `src/v2/model.ts:103,120,135` - **Why weird:** Three sibling check types each have an independent `columnNames: string[]` field with the same shape and meaning ("the columns to check"). Each carries its own near-identical JSDoc. The three checks could share a base type or a single field, but the wire-driven type model duplicates them. - **Category:** 12 (duplicate concept across siblings). - **Suggested name:** Either extract a `BaseValidityCheck { columnNames: string[] }` parent, or accept the duplication (one-line JSDoc each). Generator-emitted. - **Rationale:** DRY at the type level; per-arm doc cost is small. -### 25. Method `listQualityMonitor` doc text "(Unimplemented) List quality monitors." — `src/v2/client.ts:150,203` +### 22. Method `listQualityMonitor` doc text "(Unimplemented) List quality monitors." — `src/v2/client.ts:150,203` - **Why weird:** The method is implemented (has a complete body that constructs a URL, paginates, calls the server) — but the JSDoc literally says `(Unimplemented)`. Either (a) the server side is unimplemented and the doc is propagating a server-side TODO, or (b) this is a stale doc from when the method was a stub. Same comment appears on `updateQualityMonitor` (line 203-204: "(Unimplemented) Update a quality monitor on UC object.") — but the body of `updateQualityMonitor` is a complete `PUT` call. - **Category:** 6 (misleading — body says implemented, doc says unimplemented). - **Suggested name:** N/A. Fix the doc — either drop "(Unimplemented)" or move it to a server-side `@throws NotImplemented` annotation. - **Rationale:** Method docs that lie about implementation status are worse than no docs. -### 26. `listQualityMonitor` parameter is non-optional, but `req` is empty in normal use — `src/v2/client.ts:152-154` +### 23. `listQualityMonitor` parameter is non-optional, but `req` is empty in normal use — `src/v2/client.ts:152-154` - **Why weird:** `listQualityMonitor(req: ListQualityMonitorRequest, options?: CallOptions)` requires the caller to pass `req` even when they want all defaults. `ListQualityMonitorRequest` is `{pageToken?, pageSize?}` — both optional. So the only "no special args" call is `listQualityMonitor({})` — an empty object placeholder. - **Category:** 6 (misleading — looks like there's a required input but there isn't). - **Suggested name:** Make `req?: ListQualityMonitorRequest` optional: `listQualityMonitor(req?: ListQualityMonitorRequest, options?: CallOptions)`. - **Rationale:** Optionality on the wire should match optionality at the TS surface. Generator-wide concern. -### 27. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,202` +### 24. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,202` - **Why weird:** Every method JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (...)` — but the TS-standard JSDoc tag is `@deprecated`. The text is in the description body, not in the tag, so IDEs that read `@deprecated` (VS Code, TS LSP) will not strike through these methods or warn the user. The deprecation is documented but not enforced. - **Category:** 14 (Go-style — Go doc comments use a leading word like "Deprecated:" by convention; TS uses `@deprecated`), 6 (misleading — looks deprecated but does not surface as deprecated in tooling). - **Suggested name:** Use `@deprecated Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` so IDE tooling strikes through call sites. - **Rationale:** A whole package marked deprecated should advertise the deprecation through TS conventions, not Go conventions. -### 28. Method names `createQualityMonitor` / `deleteQualityMonitor` / `getQualityMonitor` / `listQualityMonitor` / `updateQualityMonitor` — `src/v2/client.ts:70,102,124,152,206` +### 25. Method names `createQualityMonitor` / `deleteQualityMonitor` / `getQualityMonitor` / `listQualityMonitor` / `updateQualityMonitor` — `src/v2/client.ts:70,102,124,152,206` - **Why weird:** Five methods, all of which repeat "QualityMonitor" in the name even though they are members of a `Client` class whose package (`qualitymonitor`) already encodes that domain. Compare with sister packages where methods are `create` / `get` / `delete` / `list` (verbs only). The "QualityMonitor" suffix is dead context — calling `client.createQualityMonitor(...)` from a package literally called `qualitymonitor` is reading the noun twice. - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `create` / `delete` / `get` / `list` / `update` (drop the noun). - **Rationale:** When the class is `Client` and the package is `qualitymonitor`, the only entity to act on is the quality monitor; the noun adds no signal. -### 29. `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` — `src/v2/model.ts:139-145` +### 26. `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` — `src/v2/model.ts:139-145` - **Why weird:** Three top-level fields where the relationship is implicit. The `objectType`/`objectId` pair identifies the target (also redundant with `qualityMonitor.objectType`/`qualityMonitor.objectId`). The `qualityMonitor` field carries the new state — including its own `objectType`/`objectId`. So the same identifiers are present twice on the request. Per the URL builder, only the top-level `req.objectType` and `req.objectId` are used to construct the path; the values inside `qualityMonitor` are sent in the body. Nothing checks that they match. - **Category:** 12 (duplicate concept — identifiers at two levels), 6 (misleading — silent overwriting possibility). - **Suggested name:** Either: (a) move identifiers entirely to the nested `qualityMonitor` (server reads them from the body and the path is derived from the body in TS land), or (b) move identifiers entirely to top-level and let `qualityMonitor` be just the mutable fields. @@ -205,49 +187,49 @@ The singular-vs-plural naming gives the reader no hint that these are different ## Low severity -### 30. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` +### 27. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's one list endpoint handles pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. Same as `dataquality` finding #35. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as other audited packages. -### 31. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` +### 28. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataquality` finding #36. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 32. `HttpCallOptions` — `src/v2/utils.ts:15` +### 29. `HttpCallOptions` — `src/v2/utils.ts:15` - **Why weird:** Same as `dataquality` finding #40; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 33. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` +### 30. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` - **Why weird:** Same as `dataquality` finding #41; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 34. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` +### 31. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` - **Why weird:** Same as `dataquality` finding #42; variable named `call` of type `Call` repeated 5 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 35. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` +### 32. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` - **Why weird:** Same as `dataquality` finding #43 — `objectType`/`objectId` typed optional but required in practice for the URL path. Silently substitutes empty string producing malformed URLs like `/api/2.0/quality-monitors//`. Three call sites here. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. - **Rationale:** Type shape should match runtime requirement. -### 36. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 218-231` +### 33. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 218-231` - **Why weird:** Same as `dataquality` finding #44; two variables differ by `Body` only. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. - **Rationale:** Distinguish by meaningful nouns. -### 37. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` +### 34. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` - **Why weird:** Same as `dataquality` finding #45. - **Category:** 5, 12. - **Suggested name:** `httpRequest` (no abbreviation). @@ -255,22 +237,18 @@ The singular-vs-plural naming gives the reader no hint that these are different ## Observations -### 38. Action verbs in `Client` +### 35. Action verbs in `Client` The client uses `Create` / `Get` / `Update` / `Delete` / `List` for monitor operations. Verbs are consistent within the package. Listed per rule 17 to note the absence of inconsistency (relative to `qualitymonitors` plural, which adds `Cancel` / `Run` / `Regenerate`). -### 39. Acronym casing -Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `lastRunId`), `URL` (only via the web-standard `URLSearchParams`), `Sql` (capital-then-lower in `sqlQuery`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`). No within-package collisions. -- **Category:** 3 (acronym casing). - -### 40. No `wkt` (well-known types), `FieldMask`, or `time` imports +### 36. No `wkt` (well-known types), `FieldMask`, or `time` imports Unlike `dataquality` and other newer packages, this package has no `Timestamp`, `FieldMask`, or `Duration` fields. The lack of these is consistent with the package being older and frozen (deprecated) — newer features were added to `dataquality` instead. -### 41. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types +### 37. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types Same shape as the `dataquality` casing observation: directory is one collapsed word (`qualitymonitor`), wire path is kebab-plural (`/quality-monitors`), TS types are PascalCase singular (`QualityMonitor`). The directory plural-vs-singular question (relative to `qualitymonitors`) is unique to this package family. - **Category:** 3 (casing inconsistency), 9 (singular/plural mismatch). -### 42. Entire package is `@deprecated` per JSDoc -Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#27), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. +### 38. Entire package is `@deprecated` per JSDoc +Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#24), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. ## Domain glossary - `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema). diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md index dba0982a..bfca28de 100644 --- a/.agent/naming-audit/qualitymonitors.md +++ b/.agent/naming-audit/qualitymonitors.md @@ -3,7 +3,7 @@ **Path:** `packages/qualitymonitors/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakehouse Monitoring on Unity Catalog tables (legacy/deprecated surface). The package models a `Monitor` per UC table with an `analysisConfig` chosen from `InferenceLog` / `TimeSeries` / `Snapshot`, scheduled refreshes (`Cancel` / `Get` / `List` / `Run`), Quartz cron scheduling, custom metric definitions (`Aggregate`/`Derived`/`Drift`), data classification toggles, dashboard regeneration, and notification routing on failure and on new classification tags. **Every** client method JSDoc starts with "Deprecated: Use Data Quality Monitors API instead (/api/data-quality/v1/monitors)" — this entire package is a deprecated wire-compatible facade for the `dataquality` package. -**Total weird names flagged:** 50 +**Total weird names flagged:** 52 ## CRITICAL: TWO co-existing packages with the same domain @@ -27,8 +27,8 @@ Three packages in this repository overlap on the same domain at the wire level: ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 21 | +| High | 12 | +| Medium | 24 | | Low | 10 | | Observation | 6 | @@ -94,19 +94,13 @@ Three packages in this repository overlap on the same domain at the wire level: - **Suggested name:** Collapse to `paused?: boolean` on `MonitorCronSchedule`, or rename to `PauseStatus.{Paused, Unpaused}`. - **Rationale:** "Paused" is binary. Other packages (`jobs`, `alerts`) already use `paused: boolean`. -### 11. `CancelRefresh_Response` / `DeleteMonitor_Response` / `ListRefreshes_Response` / `RegenerateDashboard_Response` — `src/v1/model.ts:100,290,338,388` -- **Why weird:** Four interfaces use the `_` underscore separator in their identifier (`CancelRefresh_Response`). The eslint comments on each (`@typescript-eslint/naming-convention`) confirm that this style violates the project's own naming rules and is whitelisted only because the proto generator emits "nested message" names this way. In TS, underscores in PascalCase identifiers are wrong — the convention is camelCase/PascalCase, no separators. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** `CancelRefreshResponse` / `DeleteMonitorResponse` / `ListRefreshesResponse` / `RegenerateDashboardResponse`. -- **Rationale:** The eslint disable comment is a smoking gun that the names violate the project's own rules. Sister packages (e.g., `dataquality`) use unsuffixed PascalCase like `CancelRefreshResponse`. - -### 12. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` +### 11. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` - **Why weird:** Same shape as `dataquality.DataProfilingConfig.analysisConfig` (audit #10 in that package). The field is named `analysisConfig`, but its arms are types named `InferenceLogAnalysisConfig`, `TimeSeriesAnalysisConfig`, `SnapshotAnalysisConfig` — three names ending in `AnalysisConfig`. The discriminator is `$case`, the arm key matches the arm payload type's prefix (e.g., `inferenceLog` for `InferenceLogAnalysisConfig`). Naming the variants `$case` is a ts-proto convention foreign to TypeScript culture; the more idiomatic discriminator is `kind` or `type`. - **Category:** 1 (vague — `$case` is unusual TS), 12 (duplicate concept — `AnalysisConfig` repeated 3 times), 20 (type-suffix tautology — `AnalysisConfig` on every arm). - **Suggested name:** Field name: `analysis`. Discriminator: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. Arm payloads: keep `InferenceLogAnalysisConfig` or rename to `InferenceLogAnalysis` / `TimeSeriesAnalysis` / `SnapshotAnalysis`. - **Rationale:** `$case` is a ts-proto idiom; in idiomatic TS you write `if (config.analysis.kind === 'inferenceLog')`, not `if (config.analysisConfig?.$case === 'inferenceLog')`. -### 13. `CreateMonitor`, `UpdateMonitor`, `DataMonitorInfo` carry **17 duplicated fields** — `src/v1/model.ts:102-180,213-279,418-489` +### 12. `CreateMonitor`, `UpdateMonitor`, `DataMonitorInfo` carry **17 duplicated fields** — `src/v1/model.ts:102-180,213-279,418-489` - **Why weird:** Three types share a 17-field overlap (outputSchemaName, assetsDir, analysisConfig, slicingExprs, customMetrics, baselineTableName, schedule, notifications, dataClassificationConfig, tableName, status, latestMonitorFailureMsg, profileMetricsTableName, driftMetricsTableName, dashboardId, monitorVersion, fullTableNameArg). Each is copy-pasted with the same JSDoc and the same `[Create:REQ Update:REQ]`-style annotation in the comment. The "annotation in the comment" tells the reader which fields are required at create vs update vs read — but is never enforced by the type system. - **Category:** 6 (misleading — type says optional, semantics say required-at-create), 7 (overly verbose — three nearly-identical types where one with a generic param could do). - **Suggested name:** One `Monitor` interface for the read shape; `CreateMonitor` and `UpdateMonitor` carry only their differences (e.g., `CreateMonitor` has the input-only `skipBuiltinDashboard` and `warehouseId`). Or use TypeScript's `Pick`/`Omit`/`Partial` to derive types from a base. Encode `[Create:REQ Update:IGN]` in the type system (not the doc): non-optional in `CreateMonitor`, omitted in `UpdateMonitor`. @@ -114,145 +108,145 @@ Three packages in this repository overlap on the same domain at the wire level: ## Medium severity -### 14. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitor`) +### 13. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitor`) - **Why weird:** Every field on `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo` has a prefix annotation in its JSDoc — `[Create:REQ Update:REQ]`, `[Create:OPT Update:OPT]`, `[Create:ERR Update:IGN]` — that encodes per-operation requirement semantics in the comment. These are generator markers, not human-friendly. A user opening the JSDoc tooltip sees `[Create:ERR Update:IGN]` and must decode "ERR means errors if you pass this, IGN means it's ignored on update". The TypeScript type does not enforce any of this. - **Category:** 6 (misleading — comment marker pretends to be authoritative but is not enforced), 18 (long, noisy comment prefix). - **Suggested name:** Remove the markers from comments. Encode the semantics in the type (separate `CreateMonitor` vs `UpdateMonitor` vs `Monitor` types with the right optionality and field presence). - **Rationale:** Doc markers are not type-checked. They look like type annotations but are inert. -### 15. `latestMonitorFailureMsg` — `src/v1/model.ts:164,263,473` +### 14. `latestMonitorFailureMsg` — `src/v1/model.ts:164,263,473` - **Why weird:** Three problems in one field name. (a) `Msg` is an abbreviation for `Message` — sister field on `RefreshInfo` is `message` (full word), and `dataquality.DataProfilingConfig` uses `latestMonitorFailureMessage` (full word). Inconsistency within the SDK. (b) `Monitor` is in the path — `monitor.latestMonitorFailureMsg` repeats "monitor". (c) The field is documented as `[Create:ERR Update:IGN]` (read-only, server-populated), but the type does not mark it. - **Category:** 5 (cryptic abbreviation — `Msg`), 7 (overly verbose), 8 (redundant `Monitor` in path), 17 (inconsistent with sibling `message` and with `dataquality`). - **Suggested name:** `latestFailureMessage`. - **Rationale:** Full word, no redundant prefix; matches `dataquality`. -### 16. `profileMetricsTableName` and `driftMetricsTableName` — `src/v1/model.ts:166,168,265,267,475,477` +### 15. `profileMetricsTableName` and `driftMetricsTableName` — `src/v1/model.ts:166,168,265,267,475,477` - **Why weird:** Pair of fields with the suffix `TableName`. Sibling Zod field is `profile_metrics_table_name` — six tokens on the wire. JSDoc on both: identical except for the leading noun. The naming pattern is consistent within the pair but verbose. Compare with `dataquality.DataProfilingConfig.{profileMetricsTableName, driftMetricsTableName}` (same names — at least consistent across packages). - **Category:** 7 (overly verbose). - **Suggested name:** `profileMetricsTable` / `driftMetricsTable` (drop `Name` — these are reference fields, not column names). - **Rationale:** "Table" is sufficient context. -### 17. `outputSchemaName` field — `src/v1/model.ts:116,215,425` +### 16. `outputSchemaName` field — `src/v1/model.ts:116,215,425` - **Why weird:** JSDoc says "Schema where output tables are created. Needs to be in 2-level format `{catalog}.{schema}`." So `outputSchemaName` is a two-part UC reference, not just a name. Sister field `baselineTableName` is a three-part UC reference; `tableName` is also three-part. The naming gives no cue about which "name" shape applies. - **Category:** 19 (underspecified — name vs full name vs two-part), 15 (generic name). - **Suggested name:** `outputSchemaFullName` (matches UC vocabulary; the value is `catalog.schema`). - **Rationale:** The "Name" suffix is ambiguous in UC contexts where the term `FullName` is reserved for fully qualified references. -### 18. `assetsDir` — `src/v1/model.ts:121,220,430` +### 17. `assetsDir` — `src/v1/model.ts:121,220,430` - **Why weird:** Identical to `dataquality.DataProfilingConfig.assetsDir` (audit #12 in that package). `assets` is generic ("which assets?"), and `Dir` is an abbreviation. JSDoc says "absolute path to a custom directory to store data-monitoring assets". - **Category:** 1 (vague), 5 (cryptic abbreviation — `Dir`). - **Suggested name:** `assetsDirectory` or `monitoringAssetsPath`. - **Rationale:** Same as `dataquality` #12. -### 19. `slicingExprs` — `src/v1/model.ts:144,243,453` +### 18. `slicingExprs` — `src/v1/model.ts:144,243,453` - **Why weird:** Identical to `dataquality.DataProfilingConfig.slicingExprs` (audit #25 in that package). `Exprs` truncates "Expressions". - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `slicingExpressions` (or, for clarity, `columnSlicingExpressions`). - **Rationale:** Same as `dataquality` #25. -### 20. `skipBuiltinDashboard` (negative boolean) — `src/v1/model.ts:109` +### 19. `skipBuiltinDashboard` (negative boolean) — `src/v1/model.ts:109` - **Why weird:** Same pattern as `dataquality.DataProfilingConfig.skipBuiltinDashboard` (audit #11 in that package). Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. - **Category:** 6 (misleading), 13 (verb-tense — `skip` is action-y, field is state-y). - **Suggested name:** `disableBuiltinDashboard` or invert to `createBuiltinDashboard: boolean`. - **Rationale:** Same as `dataquality` #11. -### 21. `baselineTableName` — `src/v1/model.ts:152,251,461` +### 20. `baselineTableName` — `src/v1/model.ts:152,251,461` - **Why weird:** A three-part UC reference (per JSDoc: "Baseline table name") but the name says only `Name`. Same shape concern as #17. - **Category:** 19 (underspecified ID — wire-side three-part name, not flagged as such). - **Suggested name:** `baselineTableFullName`. - **Rationale:** UC vocabulary uses `FullName` for three-part references. -### 22. `tableName` — `src/v1/model.ts:160,259,469` +### 21. `tableName` — `src/v1/model.ts:160,259,469` - **Why weird:** Three-part UC reference per JSDoc ("UC table to monitor. Format: `catalog.schema.table_name`"), but the name says only `Name`. Compare with `fullTableNameArg` on the same types — *two* fields representing essentially the same UC table reference, one called `tableName` (`[Create:ERR Update:IGN]`) and one called `fullTableNameArg` (the URL path param). This is the same data appearing under two field names in the same interface. - **Category:** 12 (duplicate concept — two fields for the same table reference), 19 (underspecified — three-part wire format hidden behind `Name`). - **Suggested name:** Drop one of the two. If `tableName` (the body field) is truly read-only and copied from the URL path, remove it. Otherwise, rename to `tableFullName`. - **Rationale:** Having both `tableName` and `fullTableNameArg` in the same type forces a caller to choose which to populate. -### 23. `dashboardId` is read-only at create, optional at update — `src/v1/model.ts:173,272,482` +### 22. `dashboardId` is read-only at create, optional at update — `src/v1/model.ts:173,272,482` - **Why weird:** JSDoc reads `[Create:ERR Update:OPT]`, meaning the field errors if set on create but is optional on update. Type marks both as optional. A caller writing `createMonitor({dashboardId: 'x', ...})` gets a runtime error from the API but no type-time signal. Same pattern as #14 in general; called out separately because `dashboardId` is one of the most likely fields to be mistakenly set. - **Category:** 6 (misleading optionality). - **Suggested name:** Move `dashboardId` out of `CreateMonitor` entirely. Keep in `UpdateMonitor` and `DataMonitorInfo`. - **Rationale:** Type-level enforcement of "ERR" semantics. -### 24. `monitorVersion: number` — `src/v1/model.ts:179,278,488` +### 23. `monitorVersion: number` — `src/v1/model.ts:179,278,488` - **Why weird:** Field name says "monitor version" but on a type called `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo`, the `monitor` part is dead context. JSDoc also notes the field "has flexibility to take on negative values, which can indicate corrupted monitor_version numbers" — using a magic-value (negative) to indicate corruption is a code smell (the type should be `number | 'corrupted'` or split into `version: number` + `corrupted: boolean`). - **Category:** 7 (overly verbose — `monitor` in path), 6 (misleading — magic-value encoding of corruption state). - **Suggested name:** `version: number`. - **Rationale:** Field path already gives Monitor context. -### 25. `warehouseId` only on `CreateMonitor` and `RegenerateDashboard`, not on `DataMonitorInfo` — `src/v1/model.ts:114,384` +### 24. `warehouseId` only on `CreateMonitor` and `RegenerateDashboard`, not on `DataMonitorInfo` — `src/v1/model.ts:114,384` - **Why weird:** `warehouseId` is an input-only field for picking a SQL warehouse to render the dashboard. Not on the response (`DataMonitorInfo`) — so a caller has no way to see which warehouse was actually chosen if they left this blank. Sibling `dataquality.DataProfilingConfig` has both `warehouseId` (input) and `effectiveWarehouseId` (output) — the latter is missing here. Inconsistent across two near-identical packages. - **Category:** 17 (inconsistent — input-only vs input+output across sibling packages). - **Suggested name:** Add `effectiveWarehouseId` to `DataMonitorInfo` to match `dataquality`. - **Rationale:** Cross-package parity. -### 26. `Notifications` vs `dataquality.NotificationSettings` — `src/v1/model.ts:352` +### 25. `Notifications` vs `dataquality.NotificationSettings` — `src/v1/model.ts:352` - **Why weird:** Sister package uses `NotificationSettings`; this package uses just `Notifications`. The plural noun is fine, but the sister naming differs. Also: only one nested type, `Destination` (vs `dataquality.NotificationDestination`) — again one is shorter and one is longer. - **Category:** 17 (inconsistent — sibling package uses different type names for the same concept). - **Suggested name:** Pick one: either `Notifications` + `Destination` (this package's form) or `NotificationSettings` + `NotificationDestination` (sibling's form), and apply uniformly across both packages. - **Rationale:** Consistency across sibling packages. -### 27. `Destination` — `src/v1/model.ts:292` +### 26. `Destination` — `src/v1/model.ts:292` - **Why weird:** The `Destination` type holds only `emailAddresses?: string[]`. Naming a type for an email recipient list as `Destination` is generic. Compare with sister `dataquality.NotificationDestination` which has the same shape. The name `Destination` reads as "a place"; the content is "a list of email addresses". - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `EmailDestination` (matches content), or merge with `Notifications` if there's only one channel. - **Rationale:** Generic noun for a specific data shape. -### 28. `onNewClassificationTagDetected` field — `src/v1/model.ts:356` +### 27. `onNewClassificationTagDetected` field — `src/v1/model.ts:356` - **Why weird:** Five-word field name (`on` + `New` + `Classification` + `Tag` + `Detected`) — past-tense verb at the end of a noun phrase. The doc says "Destinations to send notifications on new classification tag detected." The grammatical structure is awkward English. Sister `Notifications.onFailure` is concise (two words, no verb tense problem). - **Category:** 7 (overly verbose), 13 (verb tense — past-participle at the end of a field name). - **Suggested name:** `onNewClassificationTag` (drop `Detected`; the field is on `Notifications` so the verb is implicit). - **Rationale:** Length and clarity. The `Detected` adds no information. -### 29. `Notifications.onFailure: Destination` — `src/v1/model.ts:354` +### 28. `Notifications.onFailure: Destination` — `src/v1/model.ts:354` - **Why weird:** Field name says only "failure"; the comment hints at more ("notifications on failure/timeout") — same caveat as `dataquality.NotificationSettings.onFailure` (audit #33 in that package). Field name and JSDoc disagree on whether timeouts are included. - **Category:** 1 (vague), 17 (inconsistent doc/name). - **Suggested name:** `onFailureOrTimeout` (matches doc) or `onFailure` (matches name; update doc). - **Rationale:** Same as `dataquality` #33. -### 30. `Notifications` field name uses plural but each value is a single `Destination` — `src/v1/model.ts:352-357` +### 29. `Notifications` field name uses plural but each value is a single `Destination` — `src/v1/model.ts:352-357` - **Why weird:** The type is plural (`Notifications`) but each field (`onFailure`, `onNewClassificationTagDetected`) holds a single `Destination`, not an array. The plural-vs-singular doesn't match the content. Compare: `dataquality.NotificationSettings` (singular type, singular fields). - **Category:** 9 (singular/plural mismatch — type plural, content singular). - **Suggested name:** `NotificationSettings` (matches `dataquality`). - **Rationale:** Same as `dataquality` parity. -### 31. `InferenceLogAnalysisConfig.problemType: ProblemType` — `src/v1/model.ts:314` +### 30. `InferenceLogAnalysisConfig.problemType: ProblemType` — `src/v1/model.ts:314` - **Why weird:** Field name does not say "ML"; type is the generic `ProblemType` (#7). The reader has no cue from the field name that this is ML-specific. - **Category:** 1 (vague — `problemType` alone is generic). - **Suggested name:** `mlProblemType: MlProblemType` (or rely on rename of the enum to `InferenceProblemType` per #7). - **Rationale:** Disambiguate from generic English meaning. -### 32. `predictionProbaCol` — `src/v1/model.ts:326` +### 31. `predictionProbaCol` — `src/v1/model.ts:326` - **Why weird:** `Proba` is a Python ML idiom for "probability" — sklearn `predict_proba` etc. In a TS API, the name leaks the upstream Python convention. JSDoc says "Column for prediction probabilities" — uses the full word. - **Category:** 5 (cryptic Python-ML abbreviation), 14 (foreign-ecosystem idiom). - **Suggested name:** `predictionProbabilityCol` (or `predictionProbabilitiesCol`). - **Rationale:** Python's `predict_proba` is sklearn vocabulary; a TS SDK should not require knowing sklearn to read field names. -### 33. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` +### 32. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` - **Why weird:** `Col` is an abbreviation for `Column`. Five fields on `InferenceLogAnalysisConfig` use it. Same in `TimeSeriesAnalysisConfig.timestampCol`. TS has no length constraint. - **Category:** 5 (cryptic abbreviation — `Col`). - **Suggested name:** `timestampColumn`, `predictionColumn`, `labelColumn`, `modelIdColumn`, `predictionProbabilityColumn`. - **Rationale:** Full words; matches `dataquality.InferenceLogConfig` if that package has the same pattern (worth cross-checking). -### 34. `modelIdCol` — `src/v1/model.ts:324` +### 33. `modelIdCol` — `src/v1/model.ts:324` - **Why weird:** `Id` ambiguity flagged across the SDK. `modelIdCol` — the column in the user's table that holds a model identifier — could be any UC ID or a free-form model version string. JSDoc says only "Column for the model identifier." - **Category:** 19 (underspecified ID — what *kind* of model ID?). - **Suggested name:** Document, or rename to `modelVersionColumn` if that is what the wire expects. - **Rationale:** "Model ID" in Databricks could mean MLflow run ID, MLflow model version, registered model name, or a customer-chosen string. -### 35. `MonitorCronSchedule` vs `dataquality.CronSchedule` — `src/v1/model.ts:343` +### 34. `MonitorCronSchedule` vs `dataquality.CronSchedule` — `src/v1/model.ts:343` - **Why weird:** Same wire shape, different type names. Sister `dataquality.CronSchedule` drops the `Monitor` prefix. The prefix here is dead context — this type only ever lives on a `Monitor`. - **Category:** 8 (redundant prefix — `Monitor` is in the access path). - **Suggested name:** `CronSchedule` (matches `dataquality`). - **Rationale:** Cross-package consistency. -### 36. `quartzCronExpression` (leaks library name) — `src/v1/model.ts:345` +### 35. `quartzCronExpression` (leaks library name) — `src/v1/model.ts:345` - **Why weird:** Same as `dataquality.CronSchedule.quartzCronExpression` (audit #30 in that package). `Quartz` is a Java scheduling library; users do not need to know that. - **Category:** 14 (implementation-detail leak). - **Suggested name:** `cronExpression`. - **Rationale:** Same as `dataquality` #30. -### 37. `timezoneId` — `src/v1/model.ts:347` +### 36. `timezoneId` — `src/v1/model.ts:347` - **Why weird:** Same as `dataquality.CronSchedule.timezoneId` (audit #30 in that package). `Id` for what is in fact an IANA timezone name (e.g., `America/New_York`) — the field is a tz name, not an "ID" in the database sense. - **Category:** 19 (misnamed — calling a tz name an `Id`), 5 (jargon). - **Suggested name:** `timezone` (matches JS-standard `Intl.DateTimeFormat.timeZone`). @@ -260,61 +254,61 @@ Three packages in this repository overlap on the same domain at the wire level: ## Low severity -### 38. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 37. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `dataquality` audit #35. Helper exported but never called from `client.ts`. - **Category:** 6 (misleading — looks used; isn't). - **Suggested name:** N/A — unexport. - **Rationale:** Dead exported surface. -### 39. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +### 38. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Same as `dataquality` audit #36. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from names. -### 40. `buildHttpRequest` — `src/v1/utils.ts:96` +### 39. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataquality` audit #37 — "build" hints at builder pattern, function spreads literals. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the reality. -### 41. `readAll` — `src/v1/utils.ts:40` +### 40. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Same as `dataquality` audit #39. "ReadAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing. -### 42. `HttpCallOptions` — `src/v1/utils.ts:15` +### 41. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataquality` audit #40. Internal context bag named `Options` — collides with the public `CallOptions` / `ClientOptions` semantics. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 43. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` +### 42. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` - **Why weird:** Same as `dataquality` audit #41. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Domain-word missing. -### 44. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,133,174,214,252,290,330,373,415` +### 43. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,133,174,214,252,290,330,373,415` - **Why weird:** Same as `dataquality` audit #42. Variable `call: Call` in 9 methods. - **Category:** 1, 12. - **Suggested name:** `request` (variable). - **Rationale:** Type/variable collision. -### 45. `respBody` vs `resp` — every method in `client.ts` +### 44. `respBody` vs `resp` — every method in `client.ts` - **Why weird:** Same as `dataquality` audit #44. Two variables differ only by `Body`. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. - **Rationale:** Distinguish by meaningful nouns. -### 46. `httpReq` local — every method in `client.ts` +### 45. `httpReq` local — every method in `client.ts` - **Why weird:** Same as `dataquality` audit #45. - **Category:** 5, 12. - **Suggested name:** `httpRequest`. - **Rationale:** No abbreviation. -### 47. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,130,172,212,250,288,327,370,412` +### 46. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,130,172,212,250,288,327,370,412` - **Why weird:** Same as `dataquality` audit #43. `fullTableNameArg` typed optional but required in practice; silent empty-string substitution yields URLs like `/api/2.1/unity-catalog/tables//monitor`. - **Category:** 6. - **Suggested name:** Make `fullTableNameArg` non-optional on every request type. @@ -322,25 +316,25 @@ Three packages in this repository overlap on the same domain at the wire level: ## Observations -### 48. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" +### 47. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" - **Note:** All 9 client methods (`cancelRefresh`, `createMonitor`, `deleteMonitor`, `getMonitor`, `getRefresh`, `listRefreshes`, `regenerateDashboard`, `runRefresh`, `updateMonitor`) start their JSDoc with that sentence. None uses the `@deprecated` JSDoc tag, so editors do not render the deprecation visually. The package is deprecated in spirit, but live in build. -### 49. Acronym casing +### 48. Acronym casing - `Id` (capital-then-lower in `refreshId`, `dashboardId`, `warehouseId`, `monitorVersion`); `Ms` (`startTimeMs`, `endTimeMs`); `Http` (in imported types). No within-package collisions, all generator-emitted. - **Category:** 3 (acronym casing). -### 50. URL paths mix `unity-catalog` and `quality-monitoring` +### 49. URL paths mix `unity-catalog` and `quality-monitoring` - **Note:** Eight of nine methods use `/api/2.1/unity-catalog/tables/{}/monitor[/...]`; one (`regenerateDashboard`) uses `/api/2.1/quality-monitoring/tables/{}/monitor/dashboard`. The package name does not match either prefix. The sister `dataquality` package uses `/api/data-quality/v1/monitors`. - **Category:** 17 (inconsistent — package name vs wire path). -### 51. No `FieldMask` types +### 50. No `FieldMask` types - This package does not have any `FieldMask<...>` types (unlike `dataquality`). The deprecated API does not support partial updates via field masks; the entire monitor body is replaced on `PUT`. (Listed as observation to contrast with sibling packages.) -### 52. Verb consistency +### 51. Verb consistency - `Cancel`, `Create`, `Delete`, `Get`, `List`, `Regenerate`, `Run`, `Update` — eight different verbs in nine methods. Within the package the verbs are appropriate and consistent. The unusual one is `Regenerate` (vs `Recreate` or `RebuildDashboard`) — generator-driven choice, fine in context. - **Category:** 17 (verb inventory, none inconsistent). -### 53. `Notifications` is a slim type with two channel fields +### 52. `Notifications` is a slim type with two channel fields - Two-channel `Notifications` (`onFailure`, `onNewClassificationTagDetected`) follows the proto shape. A TS-idiomatic shape might be `notifications: Array<{channel: 'failure' | 'newClassificationTag', destination: Destination}>` to allow future expansion. Listed as observation, not a flag. ## Domain glossary diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index 8cea4a70..de864ef8 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 38 +**Total weird names flagged:** 35 ## Summary table @@ -15,38 +15,35 @@ | 4 | High | package vs siblings | `queries` package vs `queryexecution`, `queryhistory`, `modelservingquery` | Duplicate concept across 4 packages, no shared prefix | | 5 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashQuery` | Inconsistent verb — most of the SDK uses `delete`; only the SQL surface uses `trash` | | 6 | High | `model.ts` enum names | `LifecycleState`, `RunAsMode`, `DatePrecision` | Missing domain prefix (no `Query*`) — collide with identical enums in `alerts` package | -| 7 | High | `model.ts` enum names | `DateRangeValue_DynamicDateRange`, `DateValue_DynamicDate` | Proto-style `_` underscores in TypeScript identifiers | -| 8 | High | `model.ts` field | `Query.queryText` | Type-suffix tautology (`Query.queryText`) | -| 9 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | -| 10 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | -| 11 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | -| 12 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | -| 13 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | -| 14 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | -| 15 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | -| 16 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | -| 17 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | -| 18 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 19 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | -| 20 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | -| 21 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | -| 22 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | -| 23 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | -| 24 | Medium | `model.ts` enum values | `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` | Redundant enum prefix (enum already named `DatePrecision`) | -| 25 | Medium | `model.ts` enum | `DateRangeValue_DynamicDateRange` | Long enum values + Go/Java-style `_` separator | -| 26 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | -| 27 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | -| 28 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | -| 29 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | -| 30 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | -| 31 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | -| 32 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | -| 33 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | -| 34 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | -| 35 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | -| 36 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | -| 37 | Low | `model.ts` enum value | `DateValue_DynamicDate.NOW` and `YESTERDAY` | Singular/plural mismatch with sibling `DateRangeValue_DynamicDateRange.YESTERDAY` (same value lives in both enums) | -| 38 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | +| 7 | High | `model.ts` field | `Query.queryText` | Type-suffix tautology (`Query.queryText`) | +| 8 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | +| 9 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | +| 10 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | +| 11 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | +| 12 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | +| 13 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | +| 14 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 15 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 16 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 17 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 18 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | +| 19 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | +| 20 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | +| 21 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | +| 22 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 23 | Medium | `model.ts` enum values | `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` | Redundant enum prefix (enum already named `DatePrecision`) | +| 24 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | +| 25 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | +| 26 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | +| 27 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | +| 28 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | +| 29 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | +| 30 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | +| 31 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | +| 32 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | +| 33 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | +| 34 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | +| 35 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | ## High severity @@ -131,21 +128,7 @@ export enum RunAsMode { ... } Three top-level enums in a domain-specific package, none prefixed with `Query*`. The same package also indirectly uses an identical `LifecycleState` concept that exists with the same values (`ACTIVE`/`TRASHED`) in `alerts` v1; when a user imports both they collide by name. `QueryLifecycleState`, `QueryRunAsMode`, `QueryDatePrecision` (or simply re-using shared `LifecycleState` from a common package) would address this; the current state is the worst of both worlds. -### 7. Proto-style underscores in TS identifiers — `DateRangeValue_DynamicDateRange`, `DateValue_DynamicDate` - -**Location:** `src/v1/model.ts:24-49` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. -export enum DateRangeValue_DynamicDateRange { ... } - -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. -export enum DateValue_DynamicDate { ... } -``` - -TS exports two enums whose names contain underscores. The eslint suppression comment acknowledges this is non-idiomatic. The names are direct ports of protobuf's nested-message naming (parent message `DateRangeValue`, nested enum `DynamicDateRange`). In hand-written TS this would be `DateRangeValueDynamicDateRange` or, better, simply `DynamicDateRange` (since `DateRangeValue` is the only consumer). The underscores will also confuse downstream tooling (autocomplete will treat them as snake_case constants). - -### 8. `Query.queryText` — type-suffix tautology +### 7. `Query.queryText` — type-suffix tautology **Location:** `src/v1/model.ts:234-235`, `model.ts:175-176`, `model.ts:235` @@ -160,7 +143,7 @@ export interface Query { A field on `Query` named `queryText` — the access pattern is `q.queryText` where the `q` already implies "query." Inside an `Alert`, `queryText` is meaningful (it disambiguates from `alertText`). Inside `Query`, the `query` prefix is redundant. `text`, `sql`, or `statement` would suffice. -### 9. `QueryParameter` vs sibling value types — inconsistent prefixing +### 8. `QueryParameter` vs sibling value types — inconsistent prefixing **Location:** `src/v1/model.ts:268-306`, `308-310`, `219-221`, `140-147` @@ -176,7 +159,7 @@ export interface QueryBackedValue { ... } // prefixed Some value-type wrappers are prefixed (`Query*`), others are not. The choice appears to be based on whether the type "feels generic" — but `EnumValue`, `DateValue`, `DateRange` are arguably even more generic than `QueryParameter`. The package picks `QueryParameter` and `QueryBackedValue` for prefixing, while leaving `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRangeValue` unprefixed. Result: importing this package brings ambient types like `EnumValue` and `TextValue` into the user's scope. -### 10. `QueryBackedValue` — misleading +### 9. `QueryBackedValue` — misleading **Location:** `src/v1/model.ts:259-266` @@ -193,7 +176,7 @@ export interface QueryBackedValue { The name reads as "a value that is backed by a query" — implying the value itself comes from query state. The actual semantics, per JSDoc, is: a dropdown widget whose options are populated by running another saved query. `QuerySourcedDropdownParameter`, `QueryBackedDropdown`, or `DropdownFromQuery` would describe the actual concept. As written, the name is at the same abstraction level as `QueryBackedView` or `QueryBackedTable` — neither of which describes what this is. -### 11. `QueryParameter.parameterValue` (oneof key) — type-suffix tautology +### 10. `QueryParameter.parameterValue` (oneof key) — type-suffix tautology **Location:** `src/v1/model.ts:268-306` @@ -214,7 +197,7 @@ export interface QueryParameter { `QueryParameter.parameterValue` repeats "parameter" — access pattern `p.parameterValue` where `p` is already `QueryParameter`. The plain `value` would suffice (mirroring `AlertOperand.operand` from the alerts audit — same anti-pattern, opposite name). -### 12. `EnumValue` — vague/generic top-level name +### 11. `EnumValue` — vague/generic top-level name **Location:** `src/v1/model.ts:140-147` @@ -231,7 +214,7 @@ export interface EnumValue { `EnumValue` exported at the package root. `enum` is a TypeScript keyword and a generic concept; the type is in fact a *dropdown* parameter source (a list of valid options + the selected subset). `DropdownParameter`, `EnumParameter`, or `QueryEnumParameter` would name the actual concept. -### 13. `QueryParameter.title` vs `.name` — misleading pair +### 12. `QueryParameter.title` vs `.name` — misleading pair **Location:** `src/v1/model.ts:268-272` @@ -247,7 +230,7 @@ export interface QueryParameter { Reading the field names alone, `name` is the identifier and `title` is a richer/longer display string. The JSDoc inverts this: `name` is the literal `{{marker}}` text that appears in the SQL, and `title` is the human-readable widget label. The conventional pairing in this codebase (and most others) is `(name, displayName)`. Here it is `(name, title)` *and* `name` plays the role most SDK shapes give to `key`/`marker`/`identifier` and `title` plays the role of `displayName`. A reader has to consult JSDoc to tell which is which. -### 14. `Query.queryText` JSDoc — "Text of the query to be run" on a type already called `Query` +### 13. `Query.queryText` JSDoc — "Text of the query to be run" on a type already called `Query` **Location:** `src/v1/model.ts:68-69`, `174-175`, `234-235`, `335-336` @@ -264,7 +247,7 @@ Both the field name and the JSDoc embed the word "query" on a type called `Query ## Medium severity -### 15. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) +### 14. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) **Location:** `src/v1/client.ts:227-250` @@ -278,7 +261,7 @@ async trashQuery( The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 16. `TrashQueryRequest` — same as #15, in the type layer +### 15. `TrashQueryRequest` — same as #14, in the type layer **Location:** `src/v1/model.ts:312-314` @@ -290,7 +273,7 @@ export interface TrashQueryRequest { Same verb inconsistency at the type layer. Carries only `id`. -### 17. `listVisualizationsForQuery` — overly verbose +### 16. `listVisualizationsForQuery` — overly verbose **Location:** `src/v1/client.ts:173-208` @@ -303,7 +286,7 @@ async listVisualizationsForQuery( `For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. -### 18. `Visualization` — vague/generic top-level name +### 17. `Visualization` — vague/generic top-level name **Location:** `src/v1/model.ts:360-377` @@ -313,7 +296,7 @@ export interface Visualization { ... } `Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. -### 19. `Query.warehouseId` — underspecified ID +### 18. `Query.warehouseId` — underspecified ID **Location:** `src/v1/model.ts:66-67`, `172-173`, `232-233`, `333-334` @@ -324,7 +307,7 @@ warehouseId?: string | undefined; The JSDoc says "SQL warehouse"; the field says `warehouseId`. Databricks has data warehouses, Lakehouse, SQL warehouses, etc. `sqlWarehouseId` would self-document. -### 20. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar +### 19. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar **Location:** `src/v1/model.ts:64-65`, `74-75` @@ -338,7 +321,7 @@ lastModifierUserName?: string | undefined; `owner` is a noun. `lastModifier` is an agent noun constructed from the verb "modify." The pairing is mismatched — either both should be agent nouns (`ownerUserName`, `lastModifierUserName`) or both should be participial (`ownedBy`, `lastModifiedBy`). The Go convention is the former; idiomatic TS leans toward the latter. Also note the JSDoc inconsistency: "the user that owns" vs "the user who last saved" — different relative pronouns. -### 21. `Query.lastModifierUserName` — overly verbose +### 20. `Query.lastModifierUserName` — overly verbose **Location:** `src/v1/model.ts:74-75` @@ -348,13 +331,13 @@ lastModifierUserName?: string | undefined; 21 characters for what is, semantically, "last-modified-by." `lastModifiedBy` is 14 characters and more natural English. -### 22. `LifecycleState.TRASHED` — verb-tense inconsistency +### 21. `LifecycleState.TRASHED` — verb-tense inconsistency **Location:** `src/v1/model.ts:14-17` The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). -### 23. `RunAsMode` — verb-as-noun, filler `Mode` +### 22. `RunAsMode` — verb-as-noun, filler `Mode` **Location:** `src/v1/model.ts:19-22` @@ -367,7 +350,7 @@ export enum RunAsMode { `RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. -### 24. `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` — redundant enum prefix +### 23. `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` — redundant enum prefix **Location:** `src/v1/model.ts:8-12` @@ -381,13 +364,7 @@ export enum DatePrecision { Access is `DatePrecision.DAY_PRECISION` — the enum name already says "precision." `DAY`/`MINUTE`/`SECOND` would suffice. -### 25. `DateRangeValue_DynamicDateRange` — long enum + Go-style underscore - -**Location:** `src/v1/model.ts:24-43` - -The enum *name* has a `_` separator (see #7 high). Beyond that, the enum *values* like `LAST_8_HOURS`, `LAST_24_HOURS` discretize a continuous space — only 16 fixed buckets. - -### 26. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... +### 24. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... **Location:** `src/v1/model.ts:25-42` @@ -405,7 +382,7 @@ LAST_12_MONTHS = 'LAST_12_MONTHS', The user gets 16 hard-coded time windows. If they want "last 45 days," there is no value. A `{ unit: 'DAY' | 'HOUR' | ...; n: number }` shape would express the same thing without the enum-value explosion. (Acknowledged that the underlying API likely accepts only these buckets — but the API design itself is the smell.) -### 27. `Query.applyAutoLimit` — misleading verb predicate +### 25. `Query.applyAutoLimit` — misleading verb predicate **Location:** `src/v1/model.ts:85-87` @@ -416,7 +393,7 @@ applyAutoLimit?: boolean | undefined; The name reads as an imperative action ("apply the auto limit!") rather than a flag. `autoLimit` (boolean) or `autoLimitRows` (number) would parse more naturally as state. The "1000" rule is in the JSDoc, not the type — `autoLimit: number` with the convention "1000 if true, 0 if disabled" would surface the magic number. -### 28. `Query.runAsMode` — type-suffix tautology +### 26. `Query.runAsMode` — type-suffix tautology **Location:** `src/v1/model.ts:70-71` @@ -427,7 +404,7 @@ runAsMode?: RunAsMode | undefined; Field of type `RunAsMode` named `runAsMode`. `runAs` would suffice (the type already encodes "mode"). -### 29. `Query.parentPath` — underspecified +### 27. `Query.parentPath` — underspecified **Location:** `src/v1/model.ts:76-77` @@ -438,7 +415,7 @@ parentPath?: string | undefined; "Parent" of what? The JSDoc clarifies it is the workspace-folder path. `workspaceFolderPath` would self-document. `parentPath` reads like a filesystem path or a Git ref to first-time readers. (The same field appears in `alerts` — flagged there too.) -### 30. `MultiValuesOptions` — singular/plural mismatch +### 28. `MultiValuesOptions` — singular/plural mismatch **Location:** `src/v1/model.ts:210-217` @@ -455,13 +432,13 @@ export interface MultiValuesOptions { `MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). -### 31. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context +### 29. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context **Location:** `src/v1/model.ts:210-217` `prefix`, `separator`, `suffix` are completely generic outside the surrounding type. The JSDoc says "Character that prefixes each selected parameter value" — they are not characters, they are arbitrary strings (typed `string`). `valuePrefix`, `valueSeparator`, `valueSuffix` would be self-documenting and the type-level `MultiValuesOptions` could drop the leading "Multi-Values" altogether. -### 32. `Visualization.type` — reserved-word collision +### 30. `Visualization.type` — reserved-word collision **Location:** `src/v1/model.ts:365-366` @@ -472,7 +449,7 @@ type?: string | undefined; `type` is a TS keyword (used in `type Foo = …`) and a generic field name. The JSDoc admits it is "counter, table, funnel, and so on" — i.e., an open-ended string enum (no domain enum is defined). `visualizationType` or `kind` would avoid the keyword issue. -### 33. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading +### 31. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading **Location:** `src/v1/model.ts:371-374` @@ -485,7 +462,7 @@ serializedOptions?: string | undefined; Field names imply "the data, in serialized form." JSDoc admits the format is undocumented and the field should not be modified. If users are not supposed to construct these, they should not be on a public type (or they should be typed `Readonly` with a clear name like `internalQueryPlan`/`opaqueOptions`). -### 34. `DateRangeValue.startDayOfWeek` — underspecified type +### 32. `DateRangeValue.startDayOfWeek` — underspecified type **Location:** `src/v1/model.ts:113` @@ -497,32 +474,19 @@ startDayOfWeek?: number | undefined; ## Low severity -### 35. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency +### 33. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency **Location:** `src/v1/model.ts:58-59`, `362-363`, `262-263` Top-level types use bare `id`; cross-referencing types use `queryId`. `Query.queryId` would be consistent with `Visualization.queryId` and `QueryBackedValue.queryId`. Currently `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` means there are two conventions side-by-side. -### 36. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination +### 34. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination **Location:** `src/v1/model.ts:153-156`, `158-161` Standard Google AIP-158 names. Flagged for completeness; no action recommended. -### 37. `DateValue_DynamicDate.NOW`, `YESTERDAY` — sibling enum overlap - -**Location:** `src/v1/model.ts:45-49` - -```ts -export enum DateValue_DynamicDate { - NOW = 'NOW', - YESTERDAY = 'YESTERDAY', -} -``` - -`YESTERDAY` appears here *and* in `DateRangeValue_DynamicDateRange`. The two enums share at least one literal value but are not assignable to each other (TS enums are nominal). A shared `RelativeDate` enum (`NOW`, `YESTERDAY`, `LAST_HOUR`, ...) with sub-grouping would avoid the duplication. - -### 38. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. +### 35. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. **Location:** `src/v1/model.ts:292`, `297` @@ -551,13 +515,12 @@ Observations: - **`Query` is overloaded.** This package's `Query` is a saved SQL artefact. `queryhistory.QueryInfo` is a runtime execution record. `queryexecution`'s nameless concept (no `Query` type) is a dashboard parameterised query run. The four packages do not cross-reference each other's types. - **`ListQueries` collides cross-package.** `queries.ListQueriesRequest` and `queryhistory.ListQueries` are entirely different shapes returning entirely different data, both with the same human-readable name. - **No shared enums.** `queries.LifecycleState`, `queryhistory.QueryStatus`, `queryexecution.PendingStatus` / `SuccessStatus` are unrelated. A consumer building a query dashboard would have to manually correlate them. -- **Proto `_` leakage.** `queryhistory.ListQueries_Response`, `queryhistory.ExternalQuerySource_JobInfo`, `modelservingquery.QueryEndpointInput_ExtraParamsEntry` all use the same underscore-naming as `queries.DateRangeValue_DynamicDateRange`. The pattern is package-wide; flag at the generator level. ## Observations 1. **`Query` overload.** `Query` is one of the broadest words in any SQL SDK. This package's `Query` is a *saved* configuration; `queryexecution`'s implicit "query" is a *running statement*; `queryhistory`'s `QueryInfo` is a *historical record*. None reference each other. A future cleanup might rename this package's `Query` → `SavedQuery` or `WorkspaceQuery`. -2. **Wire-format leakage.** Direct proto-to-TS port shows in `DateRangeValue_DynamicDateRange`, `DateValue_DynamicDate` and snake_case identifiers in JSDoc. The "1:1 port" rule is satisfied but TypeScript ergonomics suffer. +2. **Wire-format leakage in JSDoc.** snake_case identifiers appear in JSDoc (e.g. `dynamic_date_value`, `date_value`) — the docs reference protobuf field names while the user is writing camelCase TS. 3. **Soft-delete verb is `trash`, not `delete`.** `trashQuery` and `LifecycleState.TRASHED` are the only places in the SDK using "trash." This will diverge from the rest of the resource lifecycle vocabulary as the SDK grows. diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index 208e66b2..a7ce9939 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,12 +3,12 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 47 +**Total weird names flagged:** 45 ## Summary | Severity | Count | | --- | --- | -| High | 8 | +| High | 6 | | Medium | 19 | | Low | 20 | | Observation | 3 | @@ -20,42 +20,30 @@ ```ts async listQueries(req: ListQueries, options?: CallOptions) ``` - reads as "list queries, given a thing called listQueries", which is circular. The companion response is `ListQueries_Response` (see #2), which makes the pair look like a single message split into req/resp halves — but the request half drops the `Request` suffix. + reads as "list queries, given a thing called listQueries", which is circular. - **Category:** 13, 14, 17 (verb-tense inconsistency; Go/Java-style name; inconsistent action verbs) - **Suggested name:** `ListQueriesRequest`. -- **Rationale:** Aligns with every other package in the SDK and removes the verb-as-noun footgun. Pair becomes `ListQueriesRequest` / `ListQueriesResponse`, matching `alerts`, `jobs`, etc. +- **Rationale:** Aligns with every other package in the SDK and removes the verb-as-noun footgun. -### 2. `ListQueries_Response` — proto-style nested message — `src/v1/model.ts:153` -- **Why weird:** Identifier with an underscore (`ListQueries_Response`). TypeScript identifier convention is camelCase / PascalCase — no underscores. The file silences the lint with an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive. This is a leak of the upstream proto schema (`ListQueries.Response` nested message) into the TS surface. Consumers writing `import type { ListQueries_Response }` see an obvious foreign convention. -- **Category:** 4, 14 (underscores in TS identifiers; Go/Java-style names) -- **Suggested name:** `ListQueriesResponse` (drop the underscore; align with `ListQueriesRequest` from #1). -- **Rationale:** TypeScript Handbook & Google TS style guide both forbid underscores in identifier names except for unused-arg `_` and well-known constants. The proto nesting is an implementation detail of the wire schema; the public TS surface should not carry the underscore. Two of the three `_`-bearing identifiers in this package come from the same proto pattern (see also `ExternalQuerySource_JobInfo`). - -### 3. `ExternalQuerySource_JobInfo` — proto-style nested message — `src/v1/model.ts:116` -- **Why weird:** Same as #2. Underscore in identifier, lint disabled with the same `Proto-style nested message name.` comment. Also: the name `JobInfo` is generic ("info" is a category-1 vague suffix — "info about what state?"), and it duplicates the concept of a "job source" already implied by the outer field name `jobInfo: ExternalQuerySource_JobInfo`. Three "info" tokens stack up: `ExternalQuerySource.jobInfo: ExternalQuerySource_JobInfo`. -- **Category:** 1, 4, 14, 8 (vague suffix; underscore; Go/Java-style; redundant suffix `Info`) -- **Suggested name:** `ExternalQuerySourceJob` (drop `_` and `Info`). Or, if the type is only ever used as the nested shape, inline it directly into `ExternalQuerySource` and remove the wrapper entirely. -- **Rationale:** A plain `ExternalQuerySource.job: { jobId, jobRunId, jobTaskRunId }` is clearer than a top-level companion type. If a named type is needed, `ExternalQuerySourceJob` reads as "the job-source variant of an external query source." The current name puts `Info` in two places (parent field + type suffix) and reads as if it were a generic settings struct. - -### 4. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:179` +### 2. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:179` - **Why weird:** The most central type in the package — the value returned from `listQueries` — is named `QueryInfo`. "Info" is a category-1 vague suffix; almost every field on it is a first-class property of a *query* (`queryId`, `queryText`, `status`, `userId`, `queryStartTimeMs`, ...). The type *is* the query — there is no other `Query` type for `QueryInfo` to disambiguate from. Compare with Go SDK convention where `*Info` types are common, but in TS the suffix is non-idiomatic; e.g. `alerts.Alert`, `jobs.Job`, `clusters.ClusterInfo` (this last one is the exception, also flagged in another audit). The endpoint URL is `/api/2.0/sql/history/queries` — the resource is "queries", so the response item should be `Query`. - **Category:** 8, 14, 1 (redundant `Info` suffix; Go/Java-style; vague suffix) - **Suggested name:** `Query`. -- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #5) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. +- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #3) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. -### 5. `ListQueries_Response.res` — cryptic field — `src/v1/model.ts:158` +### 3. `ListQueries_Response.res` — cryptic field — `src/v1/model.ts:158` - **Why weird:** A top-level response field named `res`. Two characters. Could mean *result*, *resource*, *response*, *reservation*, *reservoir*. The doc comment is empty. Every comparable list response in this SDK names its payload field something like `alerts`, `clusters`, `dashboards`, etc. (matching the resource); the Databricks public docs page for this endpoint calls it `res` too — so this is a wire-format leak, not a TS naming choice. - **Category:** 5, 1 (cryptic abbreviation; vague/generic) - **Suggested name:** `queries`. -- **Rationale:** The field is `QueryInfo[]` (or `Query[]` after #4). `queries` is the obvious idiomatic name. Even keeping the wire form `res`, the TS surface can map `res` → `queries` in the unmarshal transform (the file already does property-renames everywhere — `query_id` → `queryId`, etc.). +- **Rationale:** The field is `QueryInfo[]` (or `Query[]` after #2). `queries` is the obvious idiomatic name. Even keeping the wire form `res`, the TS surface can map `res` → `queries` in the unmarshal transform (the file already does property-renames everywhere — `query_id` → `queryId`, etc.). -### 6. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:207` +### 4. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:207` - **Why weird:** `QueryInfo` has both `endpointId` (line 207) and `warehouseId` (line 234) and the doc on `endpointId` reads `Alias for warehouse_id.` Two fields, one underlying ID, both present on every response. Callers will pick one and silently miss the other if the server only fills one. The wire form has the same problem: `endpoint_id` and `warehouse_id` are independent JSON properties on the response. "Endpoint" is also outdated SQL Warehouse vocabulary (Databricks renamed SQL endpoints to SQL warehouses years ago); keeping it for backwards compatibility belongs in the wire layer, not the public TS type. - **Category:** 12, 6 (duplicate concepts; misleading) - **Suggested name:** Drop `endpointId`. If the server still returns it, alias inside the unmarshal: `warehouseId: d.warehouse_id ?? d.endpoint_id`. - **Rationale:** Two fields with identical meaning is a perpetual source of `if (q.warehouseId !== undefined) ... else if (q.endpointId !== undefined) ...` chains in consumer code. The Go SDK already exposes both because it cannot collapse them without API breakage; TS can collapse and document the legacy wire name. -### 7. `CHANNEL_NAME_*` redundant enum prefix — `src/v1/model.ts:5-11` +### 5. `CHANNEL_NAME_*` redundant enum prefix — `src/v1/model.ts:5-11` - **Why weird:** Every value of the `ChannelName` enum is prefixed with `CHANNEL_NAME_`: ```ts enum ChannelName { @@ -71,7 +59,7 @@ - **Suggested name:** `ChannelName.UNSPECIFIED | PREVIEW | CURRENT | PREVIOUS | CUSTOM` — keep the string value on the wire (`"CHANNEL_NAME_PREVIEW"`), strip the prefix from the TS member name. - **Rationale:** Other enums in this very file — `QueryStatus`, `QueryStatementType`, `PlansState` — do not have this prefix. The inconsistency is jarring. Compare `QueryStatus.QUEUED` to `ChannelName.CHANNEL_NAME_PREVIEW`. -### 8. `ChannelName.CHANNEL_NAME_UNSPECIFIED` — proto-style sentinel exposed — `src/v1/model.ts:6` +### 6. `ChannelName.CHANNEL_NAME_UNSPECIFIED` — proto-style sentinel exposed — `src/v1/model.ts:6` - **Why weird:** `UNSPECIFIED` is protobuf's zero-value sentinel — it exists to satisfy proto3's "default value" rule. Exposing it in the public TypeScript surface forces consumers to handle a value that means "the server forgot to set this field." In TS the equivalent is `undefined`, which the field already permits (`name?: ChannelName | undefined`). So a `ChannelName` value can be `undefined`, `'CHANNEL_NAME_UNSPECIFIED'`, or one of the real channel names — three states where two would suffice. - **Category:** 6, 14 (misleading; Go/Java-style) - **Suggested name:** Drop `CHANNEL_NAME_UNSPECIFIED`. If the server sends it, unmarshal it to `undefined`. @@ -79,236 +67,236 @@ ## Medium severity -### 9. `PlansState` — vague type name — `src/v1/model.ts:14` +### 7. `PlansState` — vague type name — `src/v1/model.ts:14` - **Why weird:** "Plans state" — state of what? The JSDoc clarifies: "Possible Reasons for which we have not saved plans in the database." So the enum is really an "outcome" or "save status" — not a runtime state of a plan. The values include `EXISTS`, `EMPTY`, `IGNORED_*`, `UNKNOWN` — these are storage outcomes, not lifecycle states. Calling them a "state" is misleading. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `PlanStorageStatus` or `QueryPlansAvailability`. - **Rationale:** Reflects what the value actually represents. Also fixes the singular/plural smell: `PlansState` (plural noun + singular state) reads oddly; `PlanStorageStatus` is uniformly singular. -### 10. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` +### 8. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` - **Why weird:** Within the same enum: `EXISTS` is a verb (present tense), `EMPTY` is an adjective, `IGNORED_*` is a past participle, `UNKNOWN` is an adjective. Four grammatical categories for the same set of states. A consumer using one value learns the wrong pattern for the next. - **Category:** 13 (verb-tense inconsistency) - **Suggested name:** Normalize on adjectives/past participles: `AVAILABLE`, `EMPTY`, `IGNORED_SMALL_DURATION`, `IGNORED_LARGE_SIZE`, `IGNORED_SPARK_PLAN_TYPE`, `UNKNOWN`. - **Rationale:** Internal consistency. `AVAILABLE` is also more accurate than `EXISTS` (the plans exist *somewhere*; the value means they exist *in storage*). -### 11. `PlansState.IGNORED_LARGE_PLANS_SIZE` — overly verbose and grammatically off — `src/v1/model.ts:18` +### 9. `PlansState.IGNORED_LARGE_PLANS_SIZE` — overly verbose and grammatically off — `src/v1/model.ts:18` - **Why weird:** The token `PLANS_SIZE` reads as "size of plans" but in the same enum's context (`PlansState`), the *plans* are already implied. So the value is "plans state: ignored because the plans size is too large for the plans" — redundant. Also `LARGE_PLANS_SIZE` is awkward English: "large plans size" vs "large plan size" or just "large size". - **Category:** 7, 18 (overly verbose; long enum values) - **Suggested name:** `IGNORED_LARGE_SIZE` (or `IGNORED_TOO_LARGE`). - **Rationale:** Removes the redundant `PLANS` and fixes the grammar. -### 12. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` +### 10. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` - **Why weird:** The value mentions "Spark plan type" — Spark is a Databricks implementation detail and the doc comment references three internal flags: `isIgnoredSparkPlanType`, `isIgnoredSparkPlanName`, `isDeltaLogScan`. SDK consumers shouldn't need to know about Spark's plan taxonomy. Also, the value name only references one of the three reasons — what if it's `isDeltaLogScan` or `isIgnoredSparkPlanName`? The value is one enum entry for three distinct causes. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `IGNORED_FILTERED_TYPE` (broader, doesn't leak Spark vocabulary), or split into three values matching the three internal flags. - **Rationale:** Either generalize or specialize — but not both. -### 13. `QueryStatementType.OTHER` and `CALL` — `src/v1/model.ts:30,53` +### 11. `QueryStatementType.OTHER` and `CALL` — `src/v1/model.ts:30,53` - **Why weird:** `OTHER` (line 30) is a vague catch-all. `CALL` (line 53) has a JSDoc comment "SQL Script" — so `CALL` doesn't mean what it says (SQL `CALL` statement); it means "SQL Script". The doc/value mismatch is misleading. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** Keep `OTHER`. Rename `CALL` → `SCRIPT` (matches the JSDoc); alternatively keep `CALL` and remove the misleading JSDoc. - **Rationale:** Either the value name should match its meaning or the comment is wrong. -### 14. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:84` +### 12. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:84` - **Why weird:** `CANCELED` (single-l, US) where most JavaScript ecosystems use `cancelled` (double-l) and at minimum should be consistent with the rest of the codebase. More importantly: every other `QueryStatus` value is a past participle (`QUEUED`, `STARTED`, `COMPILED`, `FAILED`, `FINISHED`) or `-ING` (`COMPILING`, `RUNNING`). `CANCELED` fits the past-participle pattern — flag only for spelling. - **Category:** 13 (verb-tense — minor) plus orthographic - **Suggested name:** Keep `CANCELED` if that matches the wire (and project-wide policy); flag for cross-package consistency. - **Rationale:** The W3C HTML spec uses `cancelled`; Node.js, the DOM, and most npm packages use `canceled`. The wire form here is `"CANCELED"`, so the TS surface should match. Just record the choice. -### 15. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:67,77` +### 13. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:67,77` - **Why weird:** Both enum values are documented as `DEPRECATED: to be removed once runtime side change is picked up.` Yet they're exported in `index.ts` (since `QueryStatus` is) and have no JSDoc `@deprecated` tag. IDE autocomplete will offer them indistinguishably from current values. - **Category:** 11 (effectively dead) plus tooling concern - **Suggested name:** No rename. Add `@deprecated` JSDoc on each so IDEs show the strikethrough and the doc surfaces in tooltips. - **Rationale:** TypeScript honors `@deprecated` in completions; the current comment is informational only. -### 16. `QueryStatementType` — verbose discriminator — `src/v1/model.ts:29` +### 14. `QueryStatementType` — verbose discriminator — `src/v1/model.ts:29` - **Why weird:** Type name pairs the resource word (`QueryStatement`) with the discriminator suffix (`Type`). Three nouns stack: a query has a *statement* which has a *type*. The actual values are SQL keywords (`SELECT`, `INSERT`, ...), which are statement *kinds*, not types in the TS sense. Compare `Aggregation` in `alerts/v2`, which uses a single domain noun. - **Category:** 8, 7, 20 (redundant suffix; verbose; type-suffix tautology) - **Suggested name:** `StatementKind`. (`Type` is reserved by TypeScript's own `type` keyword for type aliases, so `Kind` is conventional in enums representing categories of a thing.) - **Rationale:** Disambiguates from TS's `type` and shortens the name. -### 17. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:197,199` +### 15. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:197,199` - **Why weird:** Two `*End*Ms` fields next to each other. The doc comments are: `The time execution of the query ended.` (executionEndTimeMs) and `The time the query ended.` (queryEndTimeMs). Are these different? When? The metrics type later splits time into `compilationTimeMs`, `executionTimeMs`, `resultFetchTimeMs` — so plausibly "execution end" is after spark execution but before fetch, while "query end" is after fetch. The TS types do not encode this. A reader has to guess. - **Category:** 1, 6, 19 (vague; misleading; underspecified time field) - **Suggested name:** Keep both names but rewrite the docs to spell out the relationship and the relative ordering (`queryStartTimeMs ≤ executionEndTimeMs ≤ queryEndTimeMs`). Optionally rename to `executionEndTimeMs` / `resultsDeliveredTimeMs`. - **Rationale:** This is the kind of field that turns into a billing/SLA bug if confused. The audit is naming-only, but the names *here* are the source of the confusion. -### 18. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:213` +### 16. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:213` - **Why weird:** Field documented as `A key that can be used to look up query details.` Look up *where*, with *what API*, returning *what*? `queryId` already serves that purpose. The two coexist on the same response with no explanation. `lookupKey` is vague (lookup what?), undefined-purpose, and parallel to `queryId`. - **Category:** 1, 12 (vague; duplicate concepts) - **Suggested name:** Rename to indicate destination — e.g. `detailsLookupKey` or `historyLookupKey`, plus a doc that references the related API. - **Rationale:** Without an explanation, this looks like a synonym for `queryId`. Drop it from public surface if it has no consumer use. -### 19. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:217,219` +### 17. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:217,219` - **Why weird:** Four user-identity fields on one type: `userId`, `userName`, `executedAsUserId`, `executedAsUserName`. The "executed as" pair models impersonation/run-as. Good intent, but the field names don't make the relationship clear (user1 ran-as user2). Compare `alerts.v2.Alert.runAsUserName` vs `Alert.runAs.userName` for a different (also problematic) approach to the same concept. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Group into a sub-object: `submitter: { id, name }`, `runAs?: { id, name }`. Or rename to `submittedByUserId/Name` + `executedAsUserId/Name`. - **Rationale:** Pairing the two roles symmetrically (submitter / runAs) makes the relationship explicit at the type level. The current names ("user" without qualifier on one pair, "executedAsUser" on the other) implies the bare `user*` is the *original* user, but doesn't say so. -### 20. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:203` +### 18. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:203` - **Why weird:** Field documented as `The email address or username of the user who ran the query.` So `userName` is a union of two unrelated identifier formats with no way to tell them apart at the type level. Same problem on `executedAsUserName`. - **Category:** 6, 15 (misleading; generic field losing meaning) - **Suggested name:** `userIdentifier` or `userPrincipal`, with the doc noting it can be either. Or split into `userEmail?` / `userLoginName?`. - **Rationale:** `userName` strongly implies a `username` (login handle), not an email. Half of integration code will assume that and break. -### 21. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:205` +### 19. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:205` - **Why weird:** `sparkUiUrl` exposes an internal Spark UI URL. "Spark UI" is a Databricks Runtime implementation detail; SDK consumers shouldn't need to know that the link goes to "Spark UI" specifically. The URL is functionally "query plan / execution diagnostics UI" — the name pins it to one particular implementation. - **Category:** 14 (Go/Java-style; leaks internal taxonomy) - **Suggested name:** `queryPlanUrl` or `executionPlanUrl`. - **Rationale:** Decouples the public API from Spark's internal nomenclature. -### 22. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:207,234` -- **Why weird:** Cross-reference of #6: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). +### 20. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:207,234` +- **Why weird:** Cross-reference of #4: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). - **Category:** 19, 16 (underspecified ID; field contradicting type domain) -- **Suggested name:** See #6. +- **Suggested name:** See #4. -### 23. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:224` +### 21. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:224` - **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. - **Category:** 15, 19 (generic field; underspecified ID) - **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. - **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. -### 24. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:226` +### 22. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:226` - **Why weird:** Field doc: `Whether more updates for the query are expected.` So `isFinal: true` means the query result is *complete and won't change*. The name `isFinal` is conventionally used for things like inheritance ("can't be subclassed") or compilation ("final pass"). `isComplete`, `isTerminal`, or `isSettled` would be clearer. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `isSettled` or `isTerminal` (matches the `QueryStatus` terminal states). - **Rationale:** The name should describe the state, not the absence of updates. -### 25. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:228` -- **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #4 / general pattern). Reads as "channel-used info" — three nouns. +### 23. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:228` +- **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #2 / general pattern). Reads as "channel-used info" — three nouns. - **Category:** 8, 7 (redundant `Info`; verbose; verb-as-modifier) - **Suggested name:** `channel: Channel`. (Rename type `ChannelInfo` → `Channel`.) - **Rationale:** Symmetry with `warehouseId`, `userId`, etc. — bare noun. -### 26. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:215,239` +### 24. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:215,239` - **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. - **Rationale:** Two times on one type, both unitless in the name (`duration` doesn't say ms), invites confusion. -### 27. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:239` +### 25. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:239` - **Why weird:** Every other time field has a `Ms` suffix (`queryStartTimeMs`, `executionEndTimeMs`, `queryEndTimeMs`, `totalTimeMs`, etc.). `duration` does not. The type is `number`. The doc says "Total time of the statement execution" with no unit. Reader must guess. - **Category:** 15, 19 (generic field losing meaning; underspecified) -- **Suggested name:** `durationMs`. (See also #26.) +- **Suggested name:** `durationMs`. (See also #24.) - **Rationale:** Internal consistency with every other time field in the file. ## Low severity -### 28. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:245` +### 26. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:245` - **Why weird:** `clientApplication: string` returns names like "Databricks SQL Editor, Tableau, and Power BI" — these are *application names*, not application IDs. The doc even disclaims "values are expected to remain static over time, this cannot be guaranteed." So the field is a free-text label, not a stable identifier. Name doesn't reflect that. - **Category:** 15 (generic field losing meaning) - **Suggested name:** `clientApplicationName` or `clientAppLabel`. - **Rationale:** Marks the field as a display label rather than an ID. -### 29. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:250,252` +### 27. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:250,252` - **Why weird:** "Query source" / "external query source" / "cache query ID" — three different ways the type talks about the origin of a query. `querySource` is the *upstream entity* (dashboard, notebook, alert, job, ...); `cacheQueryId` is the *prior query that supplied a cached result*. Conceptually unrelated, but the field names rhyme. - **Category:** 12 (duplicate concepts — only superficial) - **Suggested name:** Keep `querySource`. Rename `cacheQueryId` → `cachedFromQueryId`. - **Rationale:** Makes the semantic distinction explicit. -### 30. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:101,103` +### 28. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:101,103` - **Why weird:** Two dashboard-related ID fields on the same type. `legacyDashboardId` implies pre-Lakeview dashboards (the JSDoc on `dashboardId` is "this Lakeview dashboard"). Both can be set simultaneously? The semantics are not encoded — should be a discriminated union (`{ kind: 'lakeview', id } | { kind: 'legacy', id }`). - **Category:** 12, 19 (duplicate concept; underspecified) - **Suggested name:** Keep the names; consider a `kind` discriminator. At minimum, document the mutual exclusivity. - **Rationale:** Documentation fix more than naming. -### 31. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:105,109,112` +### 29. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:105,109,112` - **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. - **Category:** 19 (underspecified) - **Suggested name:** As above — convert to discriminated union. - **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. -### 32. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:122` +### 30. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:122` - **Why weird:** Three IDs on one type: `jobId`, `jobRunId`, `jobTaskRunId`. The naming is consistent and self-documenting. `jobTaskRunId` (one identifier for "task run within a job run") could be ambiguous: is it the run-ID of a *task* (with `jobRunId` being the run-ID of the whole job), or vice versa? The doc says `The canonical identifier of the task run.` — confirms the former. - **Category:** 19 (underspecified) - **Suggested name:** Acceptable; if confusion arises, rename to `taskRunIdWithinJobRun`. - **Rationale:** Documentation is sufficient. -### 33. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:263,271,281,287` +### 31. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:263,271,281,287` - **Why weird:** Four time fields; the relationship is `totalTime ≥ compilationTime + executionTime + resultFetchTime` (roughly), and `executionTime` aggregates `taskTotalTime` and `photonTotalTime`. The names don't encode the hierarchy; a developer must read all four docs to understand. Individually each name is OK. - **Category:** 1 (vague — collectively) - **Suggested name:** Keep, but add a JSDoc on `QueryMetrics` summarizing the hierarchy. - **Rationale:** Documentation > rename. -### 34. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:321` +### 32. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:321` - **Why weird:** Phrase rather than a noun. Doc says "remaining work to be done... deprecated: using projected_remaining_task_total_time_ms instead". So this is a deprecated field with a name that reads like English prose ("work to be done") rather than a TS identifier. Reads awkwardly: `metrics.workToBeDone`. - **Category:** 7, 14 (verbose; Go/Java-style phrase) - **Suggested name:** Already deprecated. If kept for back-compat, that's fine. New consumers should use `projectedRemainingTaskTotalTimeMs`. - **Rationale:** Will be removed; flag for awareness only. -### 35. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:326` +### 33. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:326` - **Why weird:** Doc says `number of remaining tasks to complete, calculated by autoscaler StatementAnalysis.scala. deprecated: use remaining_task_count instead`. So `runnableTasks` actually means "remaining tasks" — name and meaning don't align. Also deprecated. - **Category:** 6, 1 (misleading; vague) - **Suggested name:** Deprecated. Use `remainingTaskCount`. Flag for awareness. -- **Rationale:** Same as #34. +- **Rationale:** Same as #32. -### 36. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:328,335` +### 34. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:328,335` - **Why weird:** 32-char and 33-char field names. Five tokens each (`projected/remaining/task/totalTime/Ms`). Long enough that they wrap in editors and IDE tooltips. The doc on the second one says `projected lower bound on remaining total task time based on projected_remaining_task_total_time_ms / maximum concurrency` — the *name* doesn't say "wall-clock" is the divided-by-concurrency version. `WallclockTime` is the differentiator from `TaskTotalTime`. - **Category:** 7 (overly verbose) - **Suggested name:** Acceptable given the precision required. Could shorten `projectedRemainingWallclockTimeMs` → `projectedRemainingWallTimeMs`. - **Rationale:** Marginal. -### 37. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:273,275,277,279,293,297,337` +### 35. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:273,275,277,279,293,297,337` - **Why weird:** Seven `*Bytes` fields, each with subtly different scopes (remote vs cache vs disk vs network vs file vs pruned vs spill). Each individual name is OK; together they form a glossary the reader has to internalize. Also: `spillToDiskBytes` is a verb phrase (`spill to disk`) where peers are noun phrases (`read remote`, `write remote`). Inconsistent grammatical shape. - **Category:** 13 (verb-tense — minor) - **Suggested name:** `diskSpillBytes` (noun phrase, parallels `prunedBytes`, `readCacheBytes`). - **Rationale:** Symmetry. -### 38. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:265,337` +### 36. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:265,337` - **Why weird:** Two read-bytes fields. Doc on `readBytes`: `Total size of data read by the query, in bytes.` Doc on `readFilesBytes`: `Total number of file bytes in all tables read`. The difference is "file bytes" vs general "bytes" — possibly identical, possibly not. Names don't disambiguate. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Rename `readBytes` → `totalReadBytes` and `readFilesBytes` → `readFileBytes` (singular "file" since each row counts). - **Rationale:** Distinguishes scope. -### 39. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:283,297,299,337` +### 37. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:283,297,299,337` - **Why weird:** Inconsistent pluralization: `readFilesCount` (plural files) vs `prunedFilesCount` (plural files). OK, consistent there. But `readFilesBytes` is also plural where `readFilesCount` follows the same form — consistent. Then we have `readPartitionsCount` (plural). All consistent. Then `taskTotalTimeMs` is singular. The pattern across the type isn't uniform. - **Category:** 9 (singular/plural mismatch — across fields) - **Suggested name:** Pick one form. `readFileBytes` / `readFileCount` / `readPartitionCount` (singular, the way English does for counts) reads more naturally. - **Rationale:** Minor consistency win. -### 40. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:267, 209` +### 38. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:267, 209` - **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. - **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) - **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. - **Rationale:** Same value reachable through two paths is a maintenance hazard. -### 41. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:304,309,311` +### 39. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:304,309,311` - **Why weird:** Three time fields use `*Timestamp` suffix; everywhere else in the file the convention is `*TimeMs`. The `Timestamp` fields are documented as Unix-epoch-milliseconds too, so the unit is the same — just the naming convention differs. Mixing two suffixes for the same kind of value is a category-13 inconsistency. - **Category:** 13, 19 (verb-tense / convention inconsistency; underspecified — timestamp vs duration) - **Suggested name:** `provisioningQueueStartTimeMs`, `overloadingQueueStartTimeMs`, `queryCompilationStartTimeMs`. - **Rationale:** Consistent suffix across all time-valued fields. -### 42. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:316` +### 40. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:316` - **Why weird:** Field name has "OverTimeRange"; type is `TaskTimeOverRange`. Different naming. Field is `taskTimeOver` + `TimeRange`; type is `TaskTime` + `OverRange`. Semantically the same, named differently. - **Category:** 9, 20 (singular/plural; type-suffix tautology) - **Suggested name:** Align: `taskTimeOverRange: TaskTimeOverRange` (drop second `Time`). - **Rationale:** Field name should match type name shape. -### 43. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:351,360` +### 41. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:351,360` - **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. - **Category:** 1 (vague — `Entry`) - **Suggested name:** Optional rename to domain names. - **Rationale:** Marginal. -### 44. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:362` +### 42. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:362` - **Why weird:** Only field on the type. The doc says "total task completion time in this time range" — name reads as "task completed time" (past participle). `taskCompletionTimeMs` would be a noun-phrase form and match peer fields. - **Category:** 13 (verb-tense — past participle vs noun) - **Suggested name:** `taskCompletionTimeMs`. - **Rationale:** Noun form is more conventional. -### 45. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:367,369` +### 43. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:367,369` - **Why weird:** Generic type name `TimeRange` lives in a domain package. It's used once (`QueryFilter.queryStartTimeRange: TimeRange`). The field name `queryStartTimeRange` then re-introduces "queryStart" — odd because the `TimeRange` is *for filtering* on query start time, but a `TimeRange` is just (start, end). Reading `queryStartTimeRange.startTimeMs` is "the start of the query-start-time range, in ms" — three "start"s in one expression. - **Category:** 1, 7 (vague type name; verbose) - **Suggested name:** Rename field to `submittedDuring: TimeRange` or `queryStartedBetween: TimeRange`. Or rename type to `MsRange` / `TimestampRange` (since the type is unit-specific). - **Rationale:** Reduces "start" noise. -### 46. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:172` +### 44. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:172` - **Why weird:** Doc says `Filtering for multiple statuses is not recommended. Instead, opt to filter by a single status multiple times and then combine the results.` This is a behaviour quirk; field name is fine. Flag for documentation polish. - **Category:** observation - **Suggested name:** Keep `statuses`; document why multi-filter is discouraged on the type, not just on the field. - **Rationale:** Surfaces the constraint. -### 47. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:346,347` +### 45. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:346,347` - **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. - **Category:** 1 (vague) - **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. @@ -327,9 +315,9 @@ ## Cross-cutting themes -1. **Proto-style identifiers leak through.** Underscored type names (`ListQueries_Response`, `ExternalQuerySource_JobInfo`), prefix-stuttering enum values (`CHANNEL_NAME_CHANNEL_NAME_PREVIEW`-style usage), and the `UNSPECIFIED` sentinel all read as proto and not TS. +1. **The `Info` / `State` suffix habit.** `QueryInfo`, `ChannelInfo`, `PlansState` — bare-noun renames (`Query`, `Channel`, `PlanStorageStatus`) would be cleaner. `Info` is a category-1 vague suffix doing no work. -2. **The `Info` / `State` suffix habit.** `QueryInfo`, `ChannelInfo`, `PlansState` — bare-noun renames (`Query`, `Channel`, `PlanStorageStatus`) would be cleaner. `Info` is a category-1 vague suffix doing no work. +2. **Redundant enum-value prefixes and proto sentinels.** `CHANNEL_NAME_*` doubles the enum name in every value; `UNSPECIFIED` exposes the proto3 zero-value sentinel into the TS surface where `undefined` already serves. 3. **Time-field naming is inconsistent.** `*TimeMs` is the dominant convention, but `*Timestamp` appears three times and `duration` once with no unit. Same hierarchy across `QueryInfo` and `QueryMetrics` is hard to read without docs. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index 09014b17..eeab8d6e 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -19,14 +19,12 @@ derive from upstream definitions. The dominant naming issues are (1) the path-parameter `*Arg` suffix applied to fields that already encode their role through documentation -(`fullNameArg`, `versionArg`, `aliasArg`), (2) proto-style underscore -nested-message names leaking into TypeScript identifiers -(`DeleteModelVersion_Response`, `ListRegisteredModels_Response`, etc.), -(3) extremely heavy `Create*`/`Update*` request shapes that include -server-populated read-only fields (`createdAt`, `createdBy`, `updatedAt`, -`updatedBy`, `fullName`, `metastoreId`, `storageLocation`, `browseOnly`), -(4) collision-prone parallel concept naming versus the legacy -`modelregistry` package, and (5) singular/plural and redundant-prefix +(`fullNameArg`, `versionArg`, `aliasArg`), (2) extremely heavy +`Create*`/`Update*` request shapes that include server-populated +read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, +`fullName`, `metastoreId`, `storageLocation`, `browseOnly`), (3) +collision-prone parallel concept naming versus the legacy +`modelregistry` package, and (4) singular/plural and redundant-prefix problems on field names such as `versionNum`, `aliasName`, and `modelName` inside `RegisteredModelAliasInfo`. @@ -59,7 +57,7 @@ Both `RegisteredModelInfo`-adjacent payloads use bare `id` for two *different* identifier kinds (the alias and the model version). The reader cannot tell from the call site whether `info.id` is the alias's identifier or the model version's identifier. Prefer `aliasId` and -`modelVersionId` to disambiguate (see also §14.1, §14.2). +`modelVersionId` to disambiguate (see also §13.1, §13.2). #### 1.4 `ModelVersionInfo.version` (model.ts:251), `UpdateModelVersion.version` (model.ts:370) A field on a "model version" type called `version` is doubly redundant @@ -115,26 +113,9 @@ audit surface; documentation hygiene. --- -### 4. Underscores in TypeScript identifiers +### 4. Cryptic abbreviations -#### 4.1 `DeleteModelVersion_Response` (model.ts:66) -Proto-style nested-message naming converted to TS verbatim. Suppressed by -an `eslint-disable` for `@typescript-eslint/naming-convention`. TS -convention is `DeleteModelVersionResponse` (no underscore). The same -pattern appears on `DeleteRegisteredModel_Response` (model.ts:74), -`DeleteRegisteredModelAlias_Response` (model.ts:84), -`ListModelVersions_Response` (model.ts:168), and -`ListRegisteredModels_Response` (model.ts:211). - -Five distinct identifiers in this single file violate the naming -convention. The eslint suppression is acknowledged tech debt; the audit -must flag it nonetheless. - ---- - -### 5. Cryptic abbreviations - -#### 5.1 `fullNameArg`, `versionArg`, `aliasArg` (model.ts:60, 62, 70, 78, 80, 123, 125, 134, 136, 143, 152, 322, 324, 337, 339, 389) +#### 4.1 `fullNameArg`, `versionArg`, `aliasArg` (model.ts:60, 62, 70, 78, 80, 123, 125, 134, 136, 143, 152, 322, 324, 337, 339, 389) The `Arg` suffix is utterly cryptic to anyone outside the SDK team. It hails from the upstream Go generator marking path-parameter fields. In TypeScript identifiers like `fullNameArg`, `versionArg`, and `aliasArg` @@ -142,27 +123,27 @@ read like leftover scaffolding. The path-parameter nature is invisible to users and already documented prose-style ("The three-level (fully qualified) name of the registered model"). Recommended names: `fullName`, `version`, and `alias` — but those collide with response -fields, which is the actual problem (see §13.1 below). The right fix is +fields, which is the actual problem (see §12.1 below). The right fix is to drop the path-parameter fields from the request type entirely and accept them as method positional arguments (mirroring how `getModelVersion` already URL-encodes them). -#### 5.2 `runId`, `runWorkspaceId` (model.ts:235, 240) +#### 4.2 `runId`, `runWorkspaceId` (model.ts:235, 240) `runId` is conventional (MLflow run identifier), but in TS the abbreviation chain `run` + `Id` reads oddly when paired with `runWorkspaceId`. Consider `mlflowRunId` and `mlflowRunWorkspaceId` since the doc comments already qualify these as MLflow-specific. -#### 5.3 `versionNum` (model.ts:272, 326, 588, 798) +#### 4.3 `versionNum` (model.ts:272, 326, 588, 798) `Num` is a cryptic abbreviation for `Number`. Either spell out (`versionNumber`) or drop entirely (`version` — but that collides with the model-version field; see §11.1). --- -### 6. Misleading names +### 5. Misleading names -#### 6.1 `RegisteredModelAliasInfo.modelName` (model.ts:276) +#### 5.1 `RegisteredModelAliasInfo.modelName` (model.ts:276) The doc says "The name of the parent registered model of the model version, relative to parent schema". This field is the *parent registered model's* name, but the property is called `modelName` and lives on an @@ -172,14 +153,14 @@ model handle. Better: `parentModelName` or, since the alias is *on* the registered model, simply omit the field (the parent is already known from context). -#### 6.2 `RegisteredModelAliasInfo.id` versus `RegisteredModelAliasInfo.aliasName` (model.ts:270, 274) +#### 5.2 `RegisteredModelAliasInfo.id` versus `RegisteredModelAliasInfo.aliasName` (model.ts:270, 274) Two identifier-shaped fields on the same shape; the doc on `id` ("unique identifier of the alias") suggests an internal opaque UUID, while `aliasName` is the human-readable handle the API uses elsewhere. Calling both "identifier" makes intent unclear. Rename `id` to `aliasUuid` or -`aliasId` (see §14.1). +`aliasId` (see §13.1). -#### 6.3 `ModelVersionInfo.version` (model.ts:251) +#### 5.3 `ModelVersionInfo.version` (model.ts:251) The field name suggests a string/identifier ("v2", "v3"), but the type is `number` and the doc clarifies it is the integer version number used to reference the model version in API requests. The collision with @@ -188,20 +169,20 @@ typical semantic versioning expectations is a real footgun. Rename --- -### 7. Overly verbose names +### 6. Overly verbose names -#### 7.1 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 504) +#### 6.1 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 504) Method names hover around 30 characters. Java/Go style. In TS prefer `setAlias` / `deleteAlias` on a `RegisteredModelsClient` whose role is already established. The current names imply you could also call `setUnregisteredModelAlias` or `setExperimentAlias` from the same client, -which you cannot. See also §12.1. +which you cannot. See also §11.1. --- -### 8. Redundant suffixes +### 7. Redundant suffixes -#### 8.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) +#### 7.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) The `*Info` suffix is a verbatim Go-ism. In TS the suffix adds nothing — `RegisteredModel`, `ModelVersion`, and `RegisteredModelAlias` would be the natural names. `*Info` is leftover from the proto/Go convention of @@ -212,20 +193,20 @@ TypeScript does not need the distinction. Compare with the legacy --- -### 9. Singular / plural mismatches +### 8. Singular / plural mismatches -#### 9.1 `ListModelVersions` request, `ListModelVersions_Response.modelVersions` (model.ts:150, 169) +#### 8.1 `ListModelVersions` request, `ListModelVersions_Response.modelVersions` (model.ts:150, 169) The request type is *plural* (`ListModelVersions`), the response collection field is *plural* (`modelVersions`). Internally consistent. -#### 9.2 `ListRegisteredModels` request paginates registered models; field is `registeredModels` (model.ts:212) -Same as 9.1; flagged for completeness. +#### 8.2 `ListRegisteredModels` request paginates registered models; field is `registeredModels` (model.ts:212) +Same as 8.1; flagged for completeness. --- -### 10. Reserved-word collisions +### 9. Reserved-word collisions -#### 10.1 `Dependency.value.$case: 'function'` (model.ts:91-93) +#### 9.1 `Dependency.value.$case: 'function'` (model.ts:91-93) `function` is a TS reserved keyword. The discriminant value happens to be a string literal so it parses, but the projected `function` field inside the union arm (`{$case: 'function'; function: FunctionDependency}`) @@ -234,15 +215,15 @@ shadows the keyword. Valid TS, but it forces consumers to write syntactically legal, ergonomically poor. The Go SDK uses `Function FunctionDependency` (capitalized), avoiding the collision. -#### 10.2 No other reserved words observed. +#### 9.2 No other reserved words observed. `name`, `version`, `comment`, `owner`, `aliases`, `dependencies`, etc. are all safe. --- -### 11. Duplicate concepts versus modelregistry / MLflow +### 10. Duplicate concepts versus modelregistry / MLflow -#### 11.1 `RegisteredModel` (modelregistry) versus `RegisteredModelInfo` (registeredmodels) +#### 10.1 `RegisteredModel` (modelregistry) versus `RegisteredModelInfo` (registeredmodels) The legacy workspace-level package `modelregistry` already exports a `RegisteredModel` type and a `ModelVersion` type (verified in `/home/parth.bansal/sdk-js/packages/modelregistry/src/v1/model.ts:411-420`). @@ -257,7 +238,7 @@ This is the single most confusing parallel-concept issue. Mitigations: an import alias (`import {RegisteredModel as UcRegisteredModel}`), or - Adopt distinct domain nouns (`UcRegisteredModel`, `CatalogModel`). -#### 11.2 `CreateRegisteredModel` (registeredmodels) versus `CreateRegisteredModel` (modelregistry) +#### 10.2 `CreateRegisteredModel` (registeredmodels) versus `CreateRegisteredModel` (modelregistry) Same exact type name in both packages. Path-disambiguated only. `grep -rn "CreateRegisteredModel" packages/` returns two identical identifiers in two different namespaces; both are documented as @@ -266,7 +247,7 @@ risk is identical for `DeleteRegisteredModel`, `GetModelVersion`, `ListRegisteredModels`, and `ModelVersionStatus` (all share names with the legacy `modelregistry` exports). -#### 11.3 `ModelVersionStatus` collision (model.ts:5) +#### 10.3 `ModelVersionStatus` collision (model.ts:5) Identical enum name in `modelregistry/src/v1/model.ts:67-77`. The *variants* are almost identical (`PENDING_REGISTRATION`, `FAILED_REGISTRATION`, `READY`), except `registeredmodels` adds the @@ -275,7 +256,7 @@ will see two enums of the same name describing nearly-the-same lifecycle on two different APIs. This is high-risk for runtime bugs (passing one package's enum value into the other compiles but does not match). -#### 11.4 MLflow run linkage (`runId`, `runWorkspaceId`) +#### 10.4 MLflow run linkage (`runId`, `runWorkspaceId`) The UC model registry borrows MLflow concepts but uses generic field names. A user familiar with MLflow's run IDs will recognise these; others may not. Prefer `mlflowRunId` and `mlflowRunWorkspaceId` to @@ -283,16 +264,16 @@ signal the foreign-concept boundary. --- -### 12. Verb tense / parallel inconsistency +### 11. Verb tense / parallel inconsistency -#### 12.1 `versionNum` versus `version` (model.ts:251, 272, 326, 370) +#### 11.1 `versionNum` versus `version` (model.ts:251, 272, 326, 370) `RegisteredModelAliasInfo.versionNum` and `SetRegisteredModelAlias.versionNum` use `Num`. `ModelVersionInfo.version` and `UpdateModelVersion.version` drop the suffix entirely. All four fields are the same concept (integer model-version pointer). Pick one spelling and apply uniformly. -#### 12.2 `name` versus `modelName` versus `fullName` (model.ts:23, 222, 285, 299, 341) +#### 11.2 `name` versus `modelName` versus `fullName` (model.ts:23, 222, 285, 299, 341) On `RegisteredModelInfo`, `name` is the *short* registered-model name, `fullName` is the three-level identifier, and `catalogName`/`schemaName` are the parents. On `ModelVersionInfo`, `modelName` is the parent @@ -300,7 +281,7 @@ registered model's short name. Three different conventions for the same class of concept (name vs modelName vs fullName). A consistent scheme — say, `shortName`, `fullName`, `parentModelName` — would help. -#### 12.3 `nextPageToken` versus `pageToken` (model.ts:162, 174, 207, 217) +#### 11.3 `nextPageToken` versus `pageToken` (model.ts:162, 174, 207, 217) Request types use `pageToken`; response types use `nextPageToken`. This asymmetry is conventional for cursored pagination, but the convention should be documented somewhere (it isn't, here). Not a defect, but @@ -308,9 +289,9 @@ flagged because it is a common reader stumbling block. --- -### 13. Go / Java-style names +### 12. Go / Java-style names -#### 13.1 `Client.createRegisteredModel`, `Client.deleteRegisteredModel`, etc. +#### 12.1 `Client.createRegisteredModel`, `Client.deleteRegisteredModel`, etc. Verb + full-noun method names mirror the Go SDK's `WorkspaceClient.RegisteredModels.Create` style. In idiomatic TS, the client itself is namespaced (you import from `registeredmodels/v1`), so @@ -320,10 +301,10 @@ name. Same for `getModelVersion`, `listRegisteredModels`, `setRegisteredModelAlias`, `updateRegisteredModel`, `updateModelVersion`, and so on (12 methods total). -#### 13.2 `Info` suffix everywhere -Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §8.1. +#### 12.2 `Info` suffix everywhere +Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §7.1. -#### 13.3 PascalCase exported `Client` (client.ts:63) +#### 12.3 PascalCase exported `Client` (client.ts:63) The exported `Client` class is named bare-`Client`. Most TS SDKs export a context-qualified name like `RegisteredModelsClient` or `UcRegisteredModelsClient`. The bare `Client` works with the @@ -333,25 +314,25 @@ SDK pattern leaking into TS. --- -### 14. Underspecified IDs +### 13. Underspecified IDs -#### 14.1 `RegisteredModelAliasInfo.id` (model.ts:274) +#### 13.1 `RegisteredModelAliasInfo.id` (model.ts:274) "The unique identifier of the alias". No format constraint, no mention of whether it is a UUID, a server-generated opaque token, or a human-friendly slug. Type is `string`. Compare with the well-typed `metastoreId` (which is also `string` but at least bound to a known domain). Recommend `aliasId` and adding format hints in the doc. -#### 14.2 `ModelVersionInfo.id` (model.ts:263) -"The unique identifier of the model version". Same issues as 14.1. +#### 13.2 `ModelVersionInfo.id` (model.ts:263) +"The unique identifier of the model version". Same issues as 13.1. Recommend `modelVersionId`. -#### 14.3 `RegisteredModelInfo.metastoreId` (model.ts:297) and `ModelVersionInfo.metastoreId` (model.ts:254) +#### 13.3 `RegisteredModelInfo.metastoreId` (model.ts:297) and `ModelVersionInfo.metastoreId` (model.ts:254) "The unique identifier of the metastore". Acceptable name but worth flagging that the format (UUID? slug?) is not specified anywhere in the doc. -#### 14.4 `ModelVersionInfo.runWorkspaceId` (model.ts:240) +#### 13.4 `ModelVersionInfo.runWorkspaceId` (model.ts:240) `number` typed. The doc says "ID of the Databricks workspace". Workspace IDs in Databricks are 64-bit integers — TS `number` is only safe up to 2^53. This is a *type* concern, but the name `runWorkspaceId` does not @@ -360,12 +341,12 @@ flag the underlying integer-width risk; consider `string` per Go's --- -### 15. Generic field names losing meaning +### 14. Generic field names losing meaning -#### 15.1 `Dependency.value` (model.ts:91) +#### 14.1 `Dependency.value` (model.ts:91) See §1.1. -#### 15.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 118, 317, 332, 425) +#### 14.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 118, 317, 332, 425) Four of the six dependency wrapper types use a `FullName` suffix on their single string field (`tableFullName`, `functionFullName`, `volumeFullName`, `secretFullName`), while two do not @@ -375,7 +356,7 @@ form of `__connection_name__`"). The naming should be uniform — either add `FullName` to `connectionName` and `credentialName`, or drop the suffix from the other four. -#### 15.3 `CreateRegisteredModel.aliases` (model.ts:48), `UpdateRegisteredModel.aliases` (model.ts:417) +#### 14.3 `CreateRegisteredModel.aliases` (model.ts:48), `UpdateRegisteredModel.aliases` (model.ts:417) A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. Aliases are normally set on already-existing models, not at create time. The field is also marked optional. The name `aliases` is @@ -384,9 +365,9 @@ shape is semantically odd. Flagged for shape, not just naming. --- -### 16. Field contradicting type domain +### 15. Field contradicting type domain -#### 16.1 `CreateRegisteredModel.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId}` (model.ts:37-45) +#### 15.1 `CreateRegisteredModel.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId}` (model.ts:37-45) `CreateRegisteredModel` is a *request* shape, yet it includes six server-populated fields that the client cannot meaningfully set: - `fullName` (computed from `catalogName.schemaName.name`) @@ -403,7 +384,7 @@ set creation timestamps or override the metastore. Same defect on which says "only the name, the owner or the comment of the registered model can be updated". -#### 16.2 `UpdateModelVersion.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:335-385) +#### 15.2 `UpdateModelVersion.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:335-385) `UpdateModelVersion` carries *every* field from `ModelVersionInfo`. The JSDoc says "Currently only the comment of the model version can be updated". The shape is therefore deeply misleading: it presents 17 @@ -411,7 +392,7 @@ optional fields where 16 are silently no-ops on the server. A user setting `updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` will see no effect from `status` but no error either. -#### 16.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:276-281) +#### 15.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:276-281) Three parent-locator fields on an alias type. The alias is already nested inside `RegisteredModelInfo.aliases`, so the parent is known from context. Embedding these makes the alias serialisable in @@ -419,10 +400,10 @@ isolation but pollutes the shape. --- -### 17. Type-suffix tautology +### 16. Type-suffix tautology -#### 17.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) -See §8.1. The `Info` suffix is tautological because the type already +#### 16.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) +See §7.1. The `Info` suffix is tautological because the type already *is* the info; it does not need to be marked as such. Compare with the parallel `modelregistry` package which uses bare `RegisteredModel` / `ModelVersion`. @@ -442,19 +423,17 @@ identifier. A consumer that imports both `modelregistry` and `registeredmodels` will encounter colliding identifiers for: `ModelVersionStatus`, -`CreateRegisteredModel`, `DeleteModelVersion`, `DeleteModelVersion_Response`, -`DeleteRegisteredModel`, `DeleteRegisteredModel_Response`, -`GetModelVersion`, `ListRegisteredModels`, `ListRegisteredModels_Response`, -and the `Client` class. Importing both *requires* aliasing on every -single one of those names. This is the biggest practical naming defect -of the package. +`CreateRegisteredModel`, `DeleteModelVersion`, `DeleteRegisteredModel`, +`GetModelVersion`, `ListRegisteredModels`, and the `Client` class. +Importing both *requires* aliasing on every single one of those names. +This is the biggest practical naming defect of the package. ### C. Request shapes leak response/server fields `CreateRegisteredModel`, `UpdateRegisteredModel`, and especially `UpdateModelVersion` carry the entire response shape on the request side. This is a *type-design* defect surfaced via *naming* (a field called -`createdAt` on a "create" request is meaningless). See §16. +`createdAt` on a "create" request is meaningless). See §15. ### D. Path-parameter fields with `Arg` suffix @@ -463,23 +442,23 @@ that hits a parameterised URL. Fifteen occurrences across `model.ts`. The suffix is incomprehensible to anyone who hasn't read the generator source. Should either (1) drop the suffix and accept the collision with response fields, (2) lift these fields to positional method arguments, -or (3) document the convention package-wide. See §5.1. +or (3) document the convention package-wide. See §4.1. --- ## Recommendations (priority-ordered) 1. **Drop `*Arg` suffix** on path-parameter fields; lift to positional - method arguments where they conflict with response fields. (§5.1, §D) + method arguments where they conflict with response fields. (§4.1, §D) 2. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, - `RegisteredModelAliasInfo`. (§8.1, §17.1) + `RegisteredModelAliasInfo`. (§7.1, §16.1) 3. **Disambiguate parallel-package collisions** with `modelregistry` — - either re-namespace or rename types. (§11, §B) + either re-namespace or rename types. (§10, §B) 4. **Strip server-populated fields** from `CreateRegisteredModel`, - `UpdateRegisteredModel`, `UpdateModelVersion` request shapes. (§16, §C) + `UpdateRegisteredModel`, `UpdateModelVersion` request shapes. (§15, §C) 5. **Unify `versionNum` versus `version`** on a single spelling. - (§12.1) -6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§14) + (§11.1) +6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§13) 7. **Rename `source`** to `artifactUri` or `sourceUri`. (§1.2) 8. **Drop `MODEL_VERSION_STATUS_` prefix** from `ModelVersionStatus.UNKNOWN`. (§2.1) diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index 946afb6a..9f10d96f 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -14,7 +14,7 @@ even though the product was rebranded to "Git folders". One resource type (`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, `SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set `provider` values appearing in JSDoc on five fields. -**Total weird names flagged:** 40 +**Total weird names flagged:** 33 --- @@ -25,43 +25,39 @@ even though the product was rebranded to "Git folders". One resource type | 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". Every JSDoc string in the package uses the form "Git folder (repo)". The package, type, method, and field names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | | 2 | `Repo` as the resource noun | model.ts (throughout) | concept | High | 1 Vague/generic, 5 Cryptic abbreviations | The TS resource type is `RepoInfo`. The JSDoc clarifies: "Git folder (repo) information". The product UI calls it "Git folder". The Go SDK source uses `Repo`. JS-side could use the rebranded name (`GitFolder`/`GitFolderInfo`) or at least spell out the abbreviation (`Repository`). The wire URL still says `repos` so URL renaming is not possible, but the TS types are free. | | 3 | `RepoInfo` interface | model.ts:111 | interface | Medium | 20 Type-suffix tautology, 1 Vague/generic | The `Info` suffix is a Java/proto idiom that does not match TS norms. The interface *is* the repo — there is no `Repo` type that `RepoInfo` is "info about". `Repo` (or `GitFolder` per H1) without `Info` would be cleaner. (See also `CredentialInfo` in the `credentials` audit, M-pattern.) | -| 4 | `CreateRepo_Response` (proto-style underscore) | model.ts:29 | interface | High | 4 Underscores in TS identifiers | Proto-message-nested-message-encoded-as-underscore. Carries an inline `// eslint-disable-next-line @typescript-eslint/naming-convention` comment — the generator already knows the name violates the project's own convention. Standard TS idiom would be `CreateRepoResponse` (no underscore), or — since the response is a `RepoInfo` shape — `RepoInfo` directly. | -| 5 | `GetRepo_Response` (proto-style underscore) | model.ts:64 | interface | High | 4 Underscores in TS identifiers, 12 Duplicate concepts | Field-for-field identical to `CreateRepo_Response` and `RepoInfo`. Same eslint-disable. | -| 6 | `ListRepos_Response` (proto-style underscore) | model.ts:100 | interface | High | 4 Underscores in TS identifiers | Same eslint-disable. The body is `{repos: RepoInfo[], nextPageToken}` — the only `_Response` type with a non-redundant shape. | -| 7 | Five `*_Response` types each carry inline `// eslint-disable-next-line @typescript-eslint/naming-convention` | model.ts:28, 55, 63, 99, 170 | interface set | High | 4 Underscores in TS identifiers | Five disables in one file. The presence of those disables is the loudest possible signal that the names violate the project's own conventions. | -| 8 | `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 232-250 — sixty lines of duplicated logic). `CreateRepo_Response` and `GetRepo_Response` should be type aliases of `RepoInfo`. | -| 9 | `DeleteProject` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProject` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project` name in the entire package — every other operation uses `*Repo`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | -| 10 | `Client.deleteProject` (method name on a `repos` client) | client.ts:105 | method | High | 6 Misleading names, 17 Inconsistent action verbs | The client method is `deleteProject` even though the package is `repos`, the URL is `/repos/{id}`, the JSDoc says "Deletes the specified repo", and the four sibling methods are `createRepo`, `getRepo`, `listRepos`, `updateRepo`. Should be `deleteRepo`. Reads as: `client.createRepo(...)`, `client.getRepo(...)`, `client.deleteProject(...)`, `client.updateRepo(...)` — the inconsistency is loud. | -| 11 | `provider` field typed as `string` (should be enum) | model.ts:15, 41, 76, 123 | field | High | 6 Misleading names, 15 Generic field names | JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. Mirrors `gitProvider` in the `gitcredentials` audit (H6, #12). | -| 12 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` wire values (in JSDoc) | model.ts:9-13, 37-39, 72-75, 119-121 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Same as `gitcredentials` audit #13. Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (lower-case G at the boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" TS field-name convention. Values dictated by the API server. | -| 13 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | -| 14 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | -| 15 | `awsCodeCommit` wire value (deprecated, untagged) | model.ts:13, 40, 76, 122 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Same as `gitcredentials` audit #16. | -| 16 | `path` field (resource location, no qualifier) | model.ts:20, 33, 68, 115 | field | Medium | 1 Vague/generic, 15 Generic field names | Workspace path of the Git folder. JSDoc on `CreateRepo.path` describes it as "Desired path for the repo in the workspace". On `RepoInfo.path` it says "Root path of the git folder (repo) in the Workspace". The bare `path` is ambiguous — could be a filesystem path, a URL path, a remote-side path. `workspacePath` would self-document and distinguishes from `url` (the remote-side address). | -| 17 | `url` field | model.ts:7, 35, 70, 117 | field | Medium | 1 Vague/generic, 15 Generic field names | The remote Git repository URL. JSDoc: "URL of the Git repository to be linked" / "URL of the linked Git repository" / "URL of the remote git repository". `gitRepositoryUrl` or `remoteUrl` would self-document; bare `url` is generic enough that a reader unfamiliar with the API has to read the doc to know which URL. (`pathPrefix` and `path` already live nearby, both string-typed.) | -| 18 | `id` field (`number` type, no qualifier) | model.ts:31, 52, 60, 66, 113, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter for delete/get/update is `id`. The JSDoc on each clarifies it is "the ID for the corresponding repo to delete" / "ID of the Git folder (repo) object in the workspace". The same value never appears as `repoId` or `gitFolderId` — bare `id` everywhere. Same problem as `gitcredentials` audit H5 / #24, but here even the response types call it `id` (model.ts:31, 66, 113), not the cross-naming `credentialId` pattern. So at least it's internally consistent — just underspecified. `repoId` or `gitFolderId` would self-document. | -| 19 | `headCommitId` field | model.ts:45, 80, 127 | field | Low | 5 Cryptic abbreviations | "Head Commit ID" is fine, but "head" is a Git term that requires knowing Git internals to parse. JSDoc says "SHA-1 hash representing the commit ID of the current HEAD of the Git folder (repo)". The "ID" suffix is also slightly misleading because the value is a SHA-1 hash, not a numeric/UUID identifier. `headSha` / `currentCommitSha` would be more honest. (Listing as Low because Git users will read this fine.) | -| 20 | `branch` field on `UpdateRepo` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepo` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | -| 21 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:252-258 vs 286-292 — duplicated marshal logic). One is used in `CreateRepo`/responses; the other only in `UpdateRepo`. The shapes have no semantic difference. Should be one type. | -| 22 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | -| 23 | `pathPrefix` field on `ListRepos` | model.ts:91 | field | Low | (none) | Standard list-filter field. JSDoc clarifies the semantics. Listing for completeness. | -| 24 | `nextPageToken` field on `ListRepos` / `ListRepos_Response` | model.ts:96, 107 | field | Low | (none) | Standard pagination token. Internally consistent. Listing for completeness. | -| 25 | `repos` field on `ListRepos_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | -| 26 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | -| 27 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 130, 158, 212, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #9/#10, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | -| 28 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | -| 29 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | -| 30 | `PACKAGE_SEGMENT` const | client.ts:44 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. Same flag as every prior audit. | -| 31 | `host` field replacement (`replace(/\/$/, '')`) | client.ts:62 | (logic, not name) | Low | 6 Misleading names | The `host` field actually holds a base URL with trailing slash stripped — not just a host. `baseUrl` would be more honest. (Same misnomer as in the other clients.) | -| 32 | `userAgent` private field | client.ts:56 | field | Low | (none) | Standard, consistent. Listing for completeness. | -| 33 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 134, 216 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | -| 34 | `CreateRepo` (no body wrapper for fields) | model.ts:5 | interface | Medium | 9 Singular/plural mismatches | The endpoint is `POST /api/2.0/repos` (plural collection URL). The request type is `CreateRepo` (singular noun). The response is `CreateRepo_Response`. Singular naming matches Go-SDK convention but reads inconsistently with the wire URL. Compare to the `gitcredentials` audit (H2), which has the opposite problem — there the wire URL is plural and the request type is also plural for a single-resource op. Here the wire URL is plural and the request is singular. Pick one rule. | -| 35 | `RepoInfo` doc says "Git folder (repo) information" | model.ts:110 | doc | Low | 6 Misleading names | The doc consistently uses the form "Git folder (repo)" (e.g., model.ts:30, 32, 42, 44, 46, 59, 65, 81, 89, 101, 110, 112, 114, 124, 126, 128). The type name says only "Repo". Either the doc is overspecified (parenthetical "(repo)" is redundant) or the type name is underspecified. Pick one. | -| 36 | `RepoInfo.path` doc says "Root path" but `CreateRepo.path` and `GetRepo_Response.path` say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo`/`GetRepo_Response`/`CreateRepo_Response` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | -| 37 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types (e.g., `CreateRepo_Response`) consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | -| 38 | `provider` field doc enumerates eight values inline (each ~25 chars) | model.ts:9-13, 37-39, 72-75, 119-121 | doc | Low | 7 Overly verbose | The JSDoc for `provider` on `CreateRepo`, `CreateRepo_Response`, `GetRepo_Response`, and `RepoInfo` enumerates 6-8 values inline. The enumeration is duplicated four times (the generator emits the same text four times in one file). If it were a typed enum (H4), the JSDoc could be on the enum once. | -| 39 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepo`/`UpdateRepo`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | -| 40 | `path` collides with Node.js global `path` module | model.ts:20, 33, 68, 91, 115 | field | Low | 10 Reserved-word collisions | `path` is a common identifier name in TS/Node (`import * as path from 'node:path'`). Local field `path` shadows the import in many codebases. Not a TS reserved word, but a high-shadowing-risk identifier. | +| 4 | `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 232-250 — sixty lines of duplicated logic). The two response shapes should be type aliases of `RepoInfo`. | +| 5 | `DeleteProject` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProject` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project` name in the entire package — every other operation uses `*Repo`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | +| 6 | `Client.deleteProject` (method name on a `repos` client) | client.ts:105 | method | High | 6 Misleading names, 17 Inconsistent action verbs | The client method is `deleteProject` even though the package is `repos`, the URL is `/repos/{id}`, the JSDoc says "Deletes the specified repo", and the four sibling methods are `createRepo`, `getRepo`, `listRepos`, `updateRepo`. Should be `deleteRepo`. Reads as: `client.createRepo(...)`, `client.getRepo(...)`, `client.deleteProject(...)`, `client.updateRepo(...)` — the inconsistency is loud. | +| 7 | `provider` field typed as `string` (should be enum) | model.ts:15, 41, 76, 123 | field | High | 6 Misleading names, 15 Generic field names | JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. Mirrors `gitProvider` in the `gitcredentials` audit (H6, #12). | +| 8 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` wire values (in JSDoc) | model.ts:9-13, 37-39, 72-75, 119-121 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Same as `gitcredentials` audit #13. Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (lower-case G at the boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" TS field-name convention. Values dictated by the API server. | +| 9 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | +| 10 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | +| 11 | `awsCodeCommit` wire value (deprecated, untagged) | model.ts:13, 40, 76, 122 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Same as `gitcredentials` audit #16. | +| 12 | `path` field (resource location, no qualifier) | model.ts:20, 33, 68, 115 | field | Medium | 1 Vague/generic, 15 Generic field names | Workspace path of the Git folder. JSDoc on `CreateRepo.path` describes it as "Desired path for the repo in the workspace". On `RepoInfo.path` it says "Root path of the git folder (repo) in the Workspace". The bare `path` is ambiguous — could be a filesystem path, a URL path, a remote-side path. `workspacePath` would self-document and distinguishes from `url` (the remote-side address). | +| 13 | `url` field | model.ts:7, 35, 70, 117 | field | Medium | 1 Vague/generic, 15 Generic field names | The remote Git repository URL. JSDoc: "URL of the Git repository to be linked" / "URL of the linked Git repository" / "URL of the remote git repository". `gitRepositoryUrl` or `remoteUrl` would self-document; bare `url` is generic enough that a reader unfamiliar with the API has to read the doc to know which URL. (`pathPrefix` and `path` already live nearby, both string-typed.) | +| 14 | `id` field (`number` type, no qualifier) | model.ts:31, 52, 60, 66, 113, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter for delete/get/update is `id`. The JSDoc on each clarifies it is "the ID for the corresponding repo to delete" / "ID of the Git folder (repo) object in the workspace". The same value never appears as `repoId` or `gitFolderId` — bare `id` everywhere. Same problem as `gitcredentials` audit H5 / #24, but here even the response types call it `id` (model.ts:31, 66, 113), not the cross-naming `credentialId` pattern. So at least it's internally consistent — just underspecified. `repoId` or `gitFolderId` would self-document. | +| 15 | `headCommitId` field | model.ts:45, 80, 127 | field | Low | 5 Cryptic abbreviations | "Head Commit ID" is fine, but "head" is a Git term that requires knowing Git internals to parse. JSDoc says "SHA-1 hash representing the commit ID of the current HEAD of the Git folder (repo)". The "ID" suffix is also slightly misleading because the value is a SHA-1 hash, not a numeric/UUID identifier. `headSha` / `currentCommitSha` would be more honest. (Listing as Low because Git users will read this fine.) | +| 16 | `branch` field on `UpdateRepo` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepo` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 17 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:252-258 vs 286-292 — duplicated marshal logic). One is used in `CreateRepo`/responses; the other only in `UpdateRepo`. The shapes have no semantic difference. Should be one type. | +| 18 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | +| 19 | `pathPrefix` field on `ListRepos` | model.ts:91 | field | Low | (none) | Standard list-filter field. JSDoc clarifies the semantics. Listing for completeness. | +| 20 | `nextPageToken` field on `ListRepos` / `ListRepos_Response` | model.ts:96, 107 | field | Low | (none) | Standard pagination token. Internally consistent. Listing for completeness. | +| 21 | `repos` field on `ListRepos_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | +| 22 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | +| 23 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 130, 158, 212, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | +| 24 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | +| 25 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | +| 26 | `PACKAGE_SEGMENT` const | client.ts:44 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. Same flag as every prior audit. | +| 27 | `host` field replacement (`replace(/\/$/, '')`) | client.ts:62 | (logic, not name) | Low | 6 Misleading names | The `host` field actually holds a base URL with trailing slash stripped — not just a host. `baseUrl` would be more honest. (Same misnomer as in the other clients.) | +| 28 | `userAgent` private field | client.ts:56 | field | Low | (none) | Standard, consistent. Listing for completeness. | +| 29 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 134, 216 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 30 | `CreateRepo` (no body wrapper for fields) | model.ts:5 | interface | Medium | 9 Singular/plural mismatches | The endpoint is `POST /api/2.0/repos` (plural collection URL). The request type is `CreateRepo` (singular noun). Singular naming matches Go-SDK convention but reads inconsistently with the wire URL. Compare to the `gitcredentials` audit (H2), which has the opposite problem — there the wire URL is plural and the request type is also plural for a single-resource op. Here the wire URL is plural and the request is singular. Pick one rule. | +| 31 | `RepoInfo` doc says "Git folder (repo) information" | model.ts:110 | doc | Low | 6 Misleading names | The doc consistently uses the form "Git folder (repo)" (e.g., model.ts:30, 32, 42, 44, 46, 59, 65, 81, 89, 101, 110, 112, 114, 124, 126, 128). The type name says only "Repo". Either the doc is overspecified (parenthetical "(repo)" is redundant) or the type name is underspecified. Pick one. | +| 32 | `RepoInfo.path` doc says "Root path" but `CreateRepo.path` and other `path` docs say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | +| 33 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | +| 34 | `provider` field doc enumerates eight values inline (each ~25 chars) | model.ts:9-13, 37-39, 72-75, 119-121 | doc | Low | 7 Overly verbose | The JSDoc for `provider` on `CreateRepo`, `RepoInfo`, and the response types enumerates 6-8 values inline. The enumeration is duplicated four times (the generator emits the same text four times in one file). If it were a typed enum (#7), the JSDoc could be on the enum once. | +| 35 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepo`/`UpdateRepo`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | +| 36 | `path` collides with Node.js global `path` module | model.ts:20, 33, 68, 91, 115 | field | Low | 10 Reserved-word collisions | `path` is a common identifier name in TS/Node (`import * as path from 'node:path'`). Local field `path` shadows the import in many codebases. Not a TS reserved word, but a high-shadowing-risk identifier. | --- @@ -86,9 +82,9 @@ Two possible fixes: `createGitFolder`, etc. on the TS side. The zod transform layer can map `gitFolder` ↔ JSON keys. This costs one breaking SDK change for one product alignment that reads honestly. -2. **Keep `Repo` but at least make it consistent** — drop `_Response` types, - stop using the legacy word "Project" (see H2), and decide on `Repo` (not - "Repository") everywhere. +2. **Keep `Repo` but at least make it consistent** — stop using the legacy + word "Project" (see H2), and decide on `Repo` (not "Repository") + everywhere. The package can also adopt the gitcredentials-style hyphenation: rename to `@databricks/sdk-git-folders` (or just `@databricks/sdk-gitfolders`). @@ -100,7 +96,6 @@ export interface DeleteProject { /** The ID for the corresponding repo to delete. */ id?: number | undefined; } -export interface DeleteProject_Response {} ``` ```ts @@ -131,19 +126,7 @@ Recommendation: rename `DeleteProject` → `DeleteRepo`, method pure TS-side rename that fixes a readability footgun. If the Go SDK keeps the legacy name (likely it does), file an upstream cleanup request. -### H3. Five `_Response` types use proto-style underscores - -`CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, -`ListRepos_Response`, `UpdateRepo_Response` — plus the five -`*_ResponseSchema` consts — all carry inline `// eslint-disable-next-line -@typescript-eslint/naming-convention` comments (ten disables total in one -model.ts file). The presence of those disables is the loudest possible -signal that the names violate the project's own conventions. - -Standard TS idiom would be `CreateRepoResponse` (PascalCase, no -underscore), nested in a namespace. - -### H4. Three field-for-field-identical "Repo" shapes +### H3. Three field-for-field-identical "Repo" shapes `RepoInfo`, `CreateRepo_Response`, and `GetRepo_Response` all have the same seven fields with the same types, the same optionality, the same JSDoc @@ -163,7 +146,7 @@ export interface Repo { /* 7 fields */ } // Return Repo directly from create() and get(). ``` -### H5. `provider` is typed `string` but is closed-set +### H4. `provider` is typed `string` but is closed-set ```ts provider?: string | undefined; @@ -180,11 +163,11 @@ server rejects other values. But the TS-side surfaces it as `string`, so: cannot be fixed at the call site, only by the API server. Recommendation: emit a string-literal union or enum. The casing problem -(#12) gets handled there. This is identical to the `gitcredentials` audit +(#8) gets handled there. This is identical to the `gitcredentials` audit H6 — the same field appears in both packages, neither has an enum, both duplicate the eight-value enumeration inline. -### H6. `id` is underspecified +### H5. `id` is underspecified `id?: number` appears on `DeleteProject`, `GetRepo`, `UpdateRepo`, `RepoInfo`, `CreateRepo_Response`, and `GetRepo_Response`. JSDoc on each @@ -204,7 +187,7 @@ const someThirdThing = {id: 42}; cross-resource confusion in TS. (The wire format uses `id` in path parameters; TS can rename in the zod transform.) -### H7. `Client.deleteProject` mid-CRUD-set +### H6. `Client.deleteProject` mid-CRUD-set The package's `Client` class exposes: @@ -220,7 +203,7 @@ Four methods read uniformly; one does not. Renaming `deleteProject` → `deleteRepo` is a one-line fix on the TS side that materially improves readability. See H2 for the full discussion. -### H8. `SparseCheckout` vs `SparseCheckoutUpdate` (identical shapes) +### H7. `SparseCheckout` vs `SparseCheckoutUpdate` (identical shapes) ```ts interface SparseCheckout { patterns?: string[] | undefined } @@ -237,7 +220,7 @@ Recommendation: one type, used by both. The Go-SDK likely keeps the two separate because the proto generator emits them; the TS-side is free to collapse. -### H9. `Client` is unqualified +### H8. `Client` is unqualified `export class Client` (client.ts:49). Every package in this SDK exports its own `Client`. Once imported in user code: @@ -352,27 +335,27 @@ throw before issuing the call. The pattern repeats in The field name `headCommitId` uses the Git term "HEAD". Readers unfamiliar with Git internals will not parse "head commit". The value is a SHA-1 -hash. `headSha` or `currentCommitSha` would be more direct. See #19. +hash. `headSha` or `currentCommitSha` would be more direct. See #15. ### L2. `PACKAGE_SEGMENT` could be more specific "Segment" is vague — it is a user-agent segment, specifically. The constant is used once (in the User-Agent string). `USER_AGENT_PACKAGE_SEGMENT` -would tie it to its only consumer. See #30. +would tie it to its only consumer. See #26. ### L3. `host` field stores a base URL, not a host `this.host = options.host.replace(/\/$/, '')` — the field is a base URL with trailing slash stripped, not a host (a host has no scheme, no path). -`baseUrl` would be the honest name. See #31. +`baseUrl` would be the honest name. See #27. ### L4. `awsCodeCommit` is documented as deprecated but not tagged The JSDoc on `provider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on either the field's documentation or on a typed enum value (which doesn't -exist — see H5). Callers cannot programmatically detect deprecated values. -See #15. +exist — see H4). Callers cannot programmatically detect deprecated values. +See #11. ### L5. `SparseCheckout` doc has a comma splice @@ -384,28 +367,27 @@ See #15. — "configuration, it contains" is a comma splice (independent clauses joined by a comma). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode -patterns." See #22. +patterns." See #18. ### L6. `RepoInfo` doc text inconsistencies "Git folder" vs "git folder" within `RepoInfo` (model.ts:110, 112, 114, 116, 118, 124, 126, 128). "Workspace" vs "workspace". Generator-introduced -text inconsistency. See #37. +text inconsistency. See #33. -### L7. `RepoInfo.path` doc says "Root path"; the other three `path` docs say "Path" +### L7. `RepoInfo.path` doc says "Root path"; the other `path` docs say "Path" The `RepoInfo` interface describes `path` as "Root path of the git folder -(repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` / -`GetRepo_Response` / `CreateRepo_Response` says "Path of the Git folder -(repo) in the workspace." Different qualifier ("root path" vs "path"), -different casing ("Workspace" vs "workspace"). Generator-introduced. See -#36. +(repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` says +"Path of the Git folder (repo) in the workspace." Different qualifier +("root path" vs "path"), different casing ("Workspace" vs "workspace"). +Generator-introduced. See #32. ### L8. `path` field name collides with Node.js `path` module `import * as path from 'node:path'` is common; local field also named `path` shadows the import. Not a TS reserved word, but a known footgun. -See #40. +See #36. --- @@ -414,8 +396,8 @@ See #40. ### Wire-protocol values that the audit cannot fix The `provider` wire values (`gitHub`, `bitbucketCloud`, etc.) are dictated -by the API server. The casing inconsistencies (#12) and legacy renames -(#13, #14) are baked in. The TS-side cannot change them without breaking +by the API server. The casing inconsistencies (#8) and legacy renames +(#9, #10) are baked in. The TS-side cannot change them without breaking the wire. The audit flags them for awareness — fixing requires an API-server change. @@ -428,10 +410,8 @@ method name (`deleteProject`) and the *TS-side* request type | Identifier kind | Count | |---|---| | Total exported interfaces | 10 | -| Underscored (proto-style) interfaces | 5 (`CreateRepo_Response`, `DeleteProject_Response`, `GetRepo_Response`, `ListRepos_Response`, `UpdateRepo_Response`) | | Identical-shape interface trios | 1 (`RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | | Identical-shape interface pairs | 1 (`SparseCheckout` ≡ `SparseCheckoutUpdate`) | -| Inline ESLint disables required by these names | 5 | | Enums | 0 (despite an 8-value closed set on `provider`) | | Legacy-name leaks | 1 (`DeleteProject*` on a "repos" client) | | Rebranding leaks | All identifiers (the resource is now "Git folder" everywhere in JSDoc and product UI, but the type/method names still say "Repo") | @@ -440,15 +420,14 @@ method name (`deleteProject`) and the *TS-side* request type | Issue | This package | `gitcredentials` audit | `credentials` audit | |---|---|---|---| -| Bare `Client` class | Yes (H9) | Yes (H7) | Yes (#10) | -| `_Response` underscore types | Yes (H3) | Yes (H3) | Yes (#18) | -| Three identical resource/response shapes | Yes (H4: `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | -| `string`-typed enum-domain field (`provider`) | Yes (H5) | Yes (H6 — same field!) | No (uses real enums) | +| Bare `Client` class | Yes (H8) | Yes (H7) | Yes (#10) | +| Three identical resource/response shapes | Yes (H3: `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | +| `string`-typed enum-domain field (`provider`) | Yes (H4) | Yes (H6 — same field!) | No (uses real enums) | | `executeCall` / `executeHttpCall` vocabulary clash | Yes (M5) | Yes (#31) | Yes (#55) | | `PACKAGE_SEGMENT` generic const | Yes (L2) | Yes (#35) | Yes (#58) | | `host` field stores a URL | Yes (L3) | Yes (#36) | Common | -| Bare `id` on requests | Yes (H6) | Yes (#24 — but with `credentialId` divergence on responses) | Yes (`nameArg` divergence) | -| Plural/singular mismatch | Mild (#34 — singular request type for plural endpoint) | Severe (H2 — plural request type for singular op) | Mixed | +| Bare `id` on requests | Yes (H5) | Yes (#24 — but with `credentialId` divergence on responses) | Yes (`nameArg` divergence) | +| Plural/singular mismatch | Mild (#30 — singular request type for plural endpoint) | Severe (H2 — plural request type for singular op) | Mixed | | Legacy-name leak | **Yes (H2 — `DeleteProject*` on a "repos" client)** | No | No | | Product-rebrand leak | **Yes (H1 — TS surface says "Repo", product/doc says "Git folder")** | Partial (Bitbucket Data Center rename, GitLab Self-Managed rename — wire values only) | No | diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index abf02323..3f129cf0 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -12,20 +12,19 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | -| High | 4 | +| High | 3 | | Medium | 7 | | Low | 5 | -| Observation | 7 | -| **Total** | **23** | +| Observation | 6 | +| **Total** | **21** | Headline themes: -1. **Singular/plural mismatch on the `listQuota` method and `ListQuotas` request type.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotas`, `ListQuotas_Response`) are all plural, but the client method is `listQuota` (singular). This is the most user-visible naming defect. -2. **Proto-style `Parent_Response` identifiers leaking into the TypeScript public API.** `GetQuota_Response` and `ListQuotas_Response` retain the underscore from Go/proto nesting, and `index.ts` re-exports them verbatim. -3. **Verb-phrase request types collide semantically with client methods.** `interface GetQuota` reads as an action; `client.getQuota(req: GetQuota)` forces readers to mentally distinguish the verb-phrase function from the verb-phrase type. Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix to remove this collision. -4. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuota` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuota`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. -5. **`SecurableType` is duplicated as a `string` on `GetQuota` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H4 below. +1. **Singular/plural mismatch on the `listQuota` method.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotas`, `ListQuotas_Response`) are all plural, but the client method is `listQuota` (singular). This is the most user-visible naming defect. +2. **Verb-phrase request types collide semantically with client methods.** `interface GetQuota` reads as an action; `client.getQuota(req: GetQuota)` forces readers to mentally distinguish the verb-phrase function from the verb-phrase type. Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix to remove this collision. +3. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuota` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuota`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. +4. **`SecurableType` is duplicated as a `string` on `GetQuota` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H3 below. --- @@ -39,15 +38,7 @@ Headline themes: - **Suggestion:** `listQuotas`. - **Rationale:** The request type is `ListQuotas` (plural), the response is `ListQuotas_Response` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:92`). Every neighbouring signal is plural except the method name. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact. -### H2. `GetQuota_Response` and `ListQuotas_Response` violate TypeScript identifier convention - -- **File / line:** `src/v1/model.ts:37` (`GetQuota_Response`), `src/v1/model.ts:50` (`ListQuotas_Response`); also re-exported from `src/v1/index.ts:9, 11`. -- **Category:** #4 underscore in TypeScript identifier; #14 Go/Java-style name. -- **Current:** `GetQuota_Response`, `ListQuotas_Response`. -- **Suggestion:** `GetQuotaResponse`, `ListQuotasResponse`. -- **Rationale:** Proto nested-message convention `Parent_Child` is being mechanically transposed into TypeScript. The codebase itself acknowledges the convention is wrong by disabling ESLint at the model sites (`model.ts:36`, `model.ts:49`) with the comment "Proto-style nested message name." Every disable is a vote against the name. This is the same defect noted in `catalogs.md` §4.6–4.8 and is repo-wide; flagged here at high severity because there are only two model types in this package and *both* are affected. See also Observation O2. - -### H3. `GetQuota` is a verb-phrase used as a request data type +### H2. `GetQuota` is a verb-phrase used as a request data type - **File / line:** `src/v1/model.ts:27`; cross-ref `src/v1/client.ts:67`. - **Category:** #6 misleading name; #14 Go-style name. @@ -55,7 +46,7 @@ Headline themes: - **Suggestion:** `GetQuotaRequest`. - **Rationale:** `GetQuota` reads as a *method*, not a *type*. The user signature `client.getQuota(req: GetQuota)` parses as "call getQuota with a GetQuota" — the verb appears in two roles. The `ListQuotas` type has the same problem but mitigates it slightly with the plural noun. The `…Request` suffix is the standard remedy (see `accountsettings.GetAccountSettingRequest`, `budgetpolicy.GetBudgetPolicyRequest`). -### H4. `GetQuota.parentSecurableType: string` vs. `QuotaInfo.parentSecurableType: SecurableType` +### H3. `GetQuota.parentSecurableType: string` vs. `QuotaInfo.parentSecurableType: SecurableType` - **File / line:** `src/v1/model.ts:29` (request, `string`); `src/v1/model.ts:62` (response, `SecurableType`). - **Category:** #6 misleading name; #16 field contradicting type domain. @@ -73,7 +64,7 @@ Headline themes: - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `interface QuotaInfo`. - **Suggestion:** `Quota`. -- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O4. +- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O3. ### M2. `quotaName`, `quotaCount`, `quotaLimit` — every field prefixed with the enclosing type @@ -176,29 +167,25 @@ Headline themes: - **File / line:** `src/v1/model.ts:6-25`. - **Observation:** Variants are `CATALOG`, `SCHEMA`, `TABLE`, … rather than `SECURABLE_TYPE_CATALOG`. **Passes** the audit for #2 (redundant enum prefix) and #18 (long enum values). This is a positive example to cite back to packages that fail. The single TODO-bearing variant `STAGING_TABLE` is appropriately marked as provisional in the JSDoc (`model.ts:23-24`). -### O2. Proto-style `Parent_Response` identifiers are repo-wide - -`GetQuota_Response` and `ListQuotas_Response` follow the same `Parent_Child` underscore convention as `ConversionInfo_State`, `DatabaseInstance_State`, `EndpointStatus_State`, etc. across the workspace (see `catalogs.md` §4 and `artifactallowlists.md` O2). The ESLint disable comments in `model.ts` confirm the convention is mechanically applied. Flag for awareness; fix is repo-wide. - -### O3. Bare `Get*` / `List*` request shapes are a repo-wide pattern +### O2. Bare `Get*` / `List*` request shapes are a repo-wide pattern -`interface GetQuota` / `interface ListQuotas` follow the same bare verb-phrase convention used by `catalogs`, `connections`, `clusters`, `externallocations`. Some sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix. The decision is repo-wide — flagged as a local high-severity issue (H3) only because the verb/method collision is especially loud when there are only two methods. +`interface GetQuota` / `interface ListQuotas` follow the same bare verb-phrase convention used by `catalogs`, `connections`, `clusters`, `externallocations`. Some sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix. The decision is repo-wide — flagged as a local high-severity issue (H2) only because the verb/method collision is especially loud when there are only two methods. -### O4. `…Info` suffix repeated across UC types +### O3. `…Info` suffix repeated across UC types `QuotaInfo` mirrors `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo`. If the codebase decides to drop the `Info` suffix, this is one of many. -### O5. `URL` constants are inlined +### O4. `URL` constants are inlined - **File / line:** `src/v1/client.ts:71, 102`. - **Observation:** `${this.host}/api/2.1/unity-catalog/resource-quotas/...` appears in both methods without a named constant. Not a naming defect, but typical audits flag unnamed magic strings. -### O6. `PACKAGE_SEGMENT.key` computed via regex from `pkgJson.name` +### O5. `PACKAGE_SEGMENT.key` computed via regex from `pkgJson.name` - **File / line:** `src/v1/client.ts:32-35`. - **Observation:** `key: pkgJson.name.replace(/^@[^/]+\//, '')` strips the `@databricks/` org prefix. The constant name `PACKAGE_SEGMENT` is OK but the `key`/`value` shape is generic — readers don't immediately know `key="resourcequotas"` and `value=version`. Cosmetic. Identical to `artifactallowlists.md` O7. -### O7. `flattenQueryParams` is exported but unused in this package +### O6. `flattenQueryParams` is exported but unused in this package - **File / line:** `src/v1/utils.ts:123`. - **Observation:** Both `getQuota` (`client.ts:71`) and `listQuota` (`client.ts:102-111`) build URLs/query strings inline. The `flattenQueryParams` helper is dead code from the package's standpoint. Same finding as `catalogs.md` cross-cutting §A and `artifactallowlists.md` L5 — repo-wide template artifact. @@ -233,20 +220,20 @@ Type & symbol checklist: - [x] `SecurableType` enum (17 members) → O1 (positive). - [x] `SecurableType.STAGING_TABLE` (with TODO comment) → no defect (already flagged in source). -- [x] `GetQuota` interface (3 fields) → H3, H4, M3, M4; per-field below. Wrapper preserved for forward compatibility. -- [x] `GetQuota.parentSecurableType` (`string`) → H4 (type mismatch with response). +- [x] `GetQuota` interface (3 fields) → H2, H3, M3, M4; per-field below. Wrapper preserved for forward compatibility. +- [x] `GetQuota.parentSecurableType` (`string`) → H3 (type mismatch with response). - [x] `GetQuota.parentFullName` → M3. - [x] `GetQuota.quotaName` → M2, M4. -- [x] `GetQuota_Response` interface (1 field) → H2. Wrapper preserved for forward compatibility. +- [x] `GetQuota_Response` interface (1 field) → Wrapper preserved for forward compatibility. - [x] `GetQuota_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). -- [x] `ListQuotas` interface (2 fields) → H3 (verb-phrase), no per-field defects beyond M7. +- [x] `ListQuotas` interface (2 fields) → H2 (verb-phrase), no per-field defects beyond M7. - [x] `ListQuotas.maxResults` → no defect. - [x] `ListQuotas.pageToken` → no defect. -- [x] `ListQuotas_Response` interface (2 fields) → H2, M7. +- [x] `ListQuotas_Response` interface (2 fields) → M7. - [x] `ListQuotas_Response.quotas` → no defect; correctly plural. - [x] `ListQuotas_Response.nextPageToken` → M7. - [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix); per-field below. -- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H4, M3. +- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H3, M3. - [x] `QuotaInfo.parentFullName` → M3. - [x] `QuotaInfo.quotaName` → M2, M4. - [x] `QuotaInfo.quotaCount` → M2, M5. @@ -254,12 +241,12 @@ Type & symbol checklist: - [x] `QuotaInfo.lastRefreshedAt` → M6. - [x] `Client` class → L2. - [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O6. -- [x] `getQuota(req, options)` method → H3, L1. +- [x] `PACKAGE_SEGMENT` constant → O5. +- [x] `getQuota(req, options)` method → H2, L1. - [x] `listQuota(req, options)` method → H1, L1, L3, L4. - [x] `HttpCallOptions` interface → no defect. -- [x] `flattenQueryParams` function → O7 (unused). -- [x] `index.ts` re-exports → no extra defects; mirrors model exports faithfully, but propagates H2 underscore identifiers. +- [x] `flattenQueryParams` function → O6 (unused). +- [x] `index.ts` re-exports → no defects; mirrors model exports faithfully. --- @@ -269,44 +256,40 @@ Type & symbol checklist: | ------------------------------------------------- | ----------------- | ------------------------ | | `SecurableType` | model.ts:6 | O1 (positive) | | `SecurableType.STAGING_TABLE` | model.ts:24 | — (annotated TODO) | -| `GetQuota` | model.ts:27 | H3 | -| `GetQuota.parentSecurableType` (`string`) | model.ts:29 | H4, M3 | +| `GetQuota` | model.ts:27 | H2 | +| `GetQuota.parentSecurableType` (`string`) | model.ts:29 | H3, M3 | | `GetQuota.parentFullName` | model.ts:31 | M3 | | `GetQuota.quotaName` | model.ts:33 | M2, M4 | -| `GetQuota_Response` | model.ts:37 | H2, O2 | -| `ListQuotas` | model.ts:42 | H3 (verb-phrase) | +| `ListQuotas` | model.ts:42 | H2 (verb-phrase) | | `ListQuotas.maxResults` | model.ts:44 | — | | `ListQuotas.pageToken` | model.ts:46 | — | -| `ListQuotas_Response` | model.ts:50 | H2, O2 | -| `ListQuotas_Response.quotas` | model.ts:52 | — (correct plural) | | `ListQuotas_Response.nextPageToken` (doc) | model.ts:55-57 | M7 | -| `QuotaInfo` | model.ts:60 | M1, O4 | -| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H4, M3 | +| `QuotaInfo` | model.ts:60 | M1, O3 | +| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H3, M3 | | `QuotaInfo.parentFullName` | model.ts:64 | M3 | | `QuotaInfo.quotaName` | model.ts:66 | M2, M4 | | `QuotaInfo.quotaCount` | model.ts:68 | M2, M5 | | `QuotaInfo.quotaLimit` | model.ts:70 | M2, M5 | | `QuotaInfo.lastRefreshedAt` | model.ts:72 | M6 | | `Client` (bare name) | client.ts:37 | L2 | -| `PACKAGE_SEGMENT` | client.ts:32 | O6 | +| `PACKAGE_SEGMENT` | client.ts:32 | O5 | | `pkgJson` import alias | client.ts:18 | L5 | | `Client.getQuota` parameter `req` | client.ts:68 | L1 | | `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | | `const call: Call` | client.ts:73, 113 | L3 | | `let resp: …_Response` | client.ts:72, 112 | L4 | | `const respBody` | client.ts:77, 117 | L4 | -| `flattenQueryParams` | utils.ts:123 | O7 | -| `index.ts` re-exports propagate `_Response` types | index.ts:9, 11 | H2 | +| `flattenQueryParams` | utils.ts:123 | O6 | --- ## Recommended priority order 1. **Rename `listQuota` → `listQuotas`** — single-character defect, highest user impact. (H1) -2. **Add `…Request` / `…Response` suffix uniformly and drop the underscore.** (H2, H3) -3. **Reconcile `parentSecurableType` type — make `GetQuota.parentSecurableType: SecurableType`.** (H4) +2. **Add `…Request` suffix to verb-phrase request types.** (H2) +3. **Reconcile `parentSecurableType` type — make `GetQuota.parentSecurableType: SecurableType`.** (H3) 4. **Drop `quota` prefix on `quotaName` / `quotaCount` / `quotaLimit` inside `QuotaInfo`.** (M2) 5. **Document units on `lastRefreshedAt` (Ms) and counts on `quotaCount`/`quotaLimit`.** (M5, M6) 6. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M7) -7. **Drop `Info` suffix on `QuotaInfo`.** (M1, O4) +7. **Drop `Info` suffix on `QuotaInfo`.** (M1, O3) 8. **Spell out `req` → `request` (repo-wide policy).** (L1) diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index ddf1b6fb..d507e654 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -3,13 +3,13 @@ **Path:** `packages/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 41 +**Total weird names flagged:** 40 ## Summary | Severity | Count | | --- | --- | | High | 10 | -| Medium | 18 | +| Medium | 17 | | Low | 8 | | Observation | 5 | @@ -155,37 +155,31 @@ - **Suggested name:** Either hide until promotion (`@experimental`), or remove the inline TODO and document the constraint in the doc-comment proper. - **Rationale:** Public SDK enums shouldn't carry internal JIRA references. Same pattern as `connections#29` and `dataclassification`. -### 23. `SecurableType.CLEAN_ROOM` with underscore vs `STORAGE_CREDENTIAL`, `EXTERNAL_LOCATION` etc — `model.ts:24-43` -- **Why weird:** Mostly consistent SCREAMING_SNAKE, but `CLEAN_ROOM` is one of several where the underlying domain noun is two words. Compare `STORAGE_CREDENTIAL` (two-word: "storage credential"), `EXTERNAL_LOCATION` (two-word: "external location"), `CLEAN_ROOM` (two-word: "clean room"), `STAGING_TABLE` (two-word: "staging table"), `EXTERNAL_METADATA` (two-word: "external metadata"). All these are consistent — flagging only because the package surfaces the same SCREAMING_SNAKE compound style without a TS-flavour alternative. The two-word compound makes member access very long: `SecurableType.STORAGE_CREDENTIAL` reads 27 chars. -- **Category:** Observation / 18 (long enum value set). -- **Suggested name:** PascalCase variant would shorten: `SecurableType.StorageCredential`, `SecurableType.CleanRoom`. Generator-locked. -- **Rationale:** Naming is internally consistent; flagging only as a style observation versus PascalCase TS conventions. - -### 24. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` +### 23. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` - **Why weird:** `EXTERNAL_METADATA` is undocumented. Neighbouring `STAGING_TABLE` carries a TODO/comment, but `EXTERNAL_METADATA` doesn't even say what it is. Unity Catalog has `externalmetadata` as its own package (`packages/externalmetadata/`), but this RFA enum member exists in isolation. - **Category:** 1 (vague; no doc disambiguating). - **Suggested name:** Keep name; add doc comment. - **Rationale:** Naming OK, but undocumented enum members in a 17-element enum mean readers must cross-reference to other packages. -### 25. `Principal` is exported but `principalType` field has no doc — `model.ts:148` +### 24. `Principal` is exported but `principalType` field has no doc — `model.ts:148` - **Why weird:** `principalType?: PrincipalType | undefined` has no JSDoc. Sibling `id` has a doc. The PrincipalType enum has only an `_UNSPECIFIED` sentinel + three values, none of which clarify when each applies. Caller has to guess by inspecting the IAM service. - **Category:** 1 (vague). - **Suggested name:** Keep name; add doc. - **Rationale:** Mechanical. -### 26. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` +### 25. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` - **Why weird:** `permissions` is `string[]` rather than an enum. Doc says "List of requested Unity Catalog permissions" — UC permissions are a known closed set (`SELECT`, `MODIFY`, `USAGE`, `READ_VOLUME`, etc.), so this should be a typed enum or branded string. Bare `string[]` loses any compile-time guard against typos. - **Category:** 16 (field type contradicts domain — should be enum or branded string). - **Suggested name:** Keep name; type as `UnityCatalogPermission[]` (new enum). Or document the closed set inline. - **Rationale:** Same problem as #10. The wire is string, but TS could narrow it. -### 27. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` +### 26. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` - **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. - **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). - **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). - **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. -### 28. Three Client methods, three different domain entity names — `client.ts:74,113,147` +### 27. Three Client methods, three different domain entity names — `client.ts:74,113,147` - **Why weird:** `Client.batchCreateAccessRequests` works on `requests`. `Client.getAccessRequestDestinations` works on `destinations`. `Client.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. - **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). - **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). @@ -193,49 +187,49 @@ ## Low severity -### 29. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +### 28. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17. - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Same as `connections#40`. -### 30. `HttpCallOptions` — `utils.ts:15` +### 29. `HttpCallOptions` — `utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file imports `Options` from `@databricks/sdk-core/api` and `CallOptions` from `@databricks/sdk-options/call`. Three `Options` types in scope. `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Same as `connections#41`. -### 31. `readAll` — `utils.ts:40` +### 30. `readAll` — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `connections#38`. -### 32. `flattenQueryParams` — `utils.ts:123` +### 31. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default. - **Rationale:** Generator emits the same helper into every package even when unused. Same as `connections#37`. -### 33. `PACKAGE_SEGMENT` constant — `client.ts:35` +### 32. `PACKAGE_SEGMENT` constant — `client.ts:35` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `connections#36`. -### 34. `Client` class — `client.ts:40` +### 33. `Client` class — `client.ts:40` - **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). - **Category:** 1 (vague). - **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). - **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. -### 35. `buildHttpRequest` parameter list — `utils.ts:96-102` +### 34. `buildHttpRequest` parameter list — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. The function name `buildHttpRequest` doesn't communicate the parameter order; callers in `client.ts:87,122,166` pass them positionally. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Five-positional builders without object syntax are an anti-pattern in modern TS. -### 36. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` +### 35. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` - **Why weird:** The `Options` shape is built with a series of `...(options?.foo !== undefined && {foo: options.foo})` spreads. The pattern is a TS-idiom for conditional spread of optional fields. Naming-wise: the local `opts` variable is intentionally one letter shorter than `options` to disambiguate — but the shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions` (or the outer parameter to `callOptions`). @@ -243,23 +237,23 @@ ## Observations -### 37. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` +### 36. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` The index file exports the `Client`, all four enums, and all nine model interfaces (`AccessRequestDestinations`, `BatchCreateAccessRequestsRequest`, `BatchCreateAccessRequestsResponse`, `CreateAccessRequest`, `CreateAccessRequestResponse`, `GetAccessRequestDestinationsRequest`, `NotificationDestination`, `Principal`, `Securable`, `SecurablePermissions`, `UpdateAccessRequestDestinationsRequest`). It does *not* export the `marshal*`/`unmarshal*` schemas or the `accessRequestDestinationsFieldMask` helper. Consistent with the other packages but means the field-mask helper isn't available to consumers. - **Category:** Observation. -### 38. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +### 37. Comment-tag inconsistency — `client.ts:78,117,151` vs URL The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. - **Category:** Observation. -### 39. No tests in the package +### 38. No tests in the package `package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. The package ships untested. Not a naming issue, but cross-package noise — same as several other newly generated packages. - **Category:** Observation. -### 40. Action-verb conventions on `Client` -`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #28). +### 39. Action-verb conventions on `Client` +`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #27). - **Category:** Observation. -### 41. `package.json` description is empty string — `package.json:4` +### 40. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the cryptic `rfa` name (see #1), this leaves users with no metadata to identify the package's purpose when browsing npm. - **Category:** Observation. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index ca16e695..a223c5a5 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -12,15 +12,12 @@ The `schemas` package exposes the standard five UC schema operations (`createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`). The package is small (one enum, one nested-flag type, the schema info type, five request types, -two response types, six map-entry wrapper types). Because it is a 1:1 +two response types). Because it is a 1:1 port of the Go SDK, most issues are inherited from upstream proto -definitions: the most pervasive problems are (1) proto-style -underscore-suffixed identifiers in the public TS surface -(`DeleteSchema_Response`, `ListSchemas_Response`, six `*_OptionsEntry`/ -`*_PropertiesEntry` wrappers), (2) `fullNameArg` as a cryptic path -parameter that coexists with `fullName` on the same type, (3) -`CreateSchema`/`UpdateSchema` carrying read-only server-populated -fields, and (4) the `CatalogType` enum living on a schema-only type +definitions: the most pervasive problems are (1) `fullNameArg` as a +cryptic path parameter that coexists with `fullName` on the same type, +(2) `CreateSchema`/`UpdateSchema` carrying read-only server-populated +fields, and (3) the `CatalogType` enum living on a schema-only type even though every variant duplicates the `_CATALOG` suffix that the enum name already provides. There is also significant duplicate-concept overlap with the sibling `systemschemas` package (separate types @@ -42,26 +39,19 @@ tri-state (enable / disable / inherit). A reader has to read the doc to discover what is in it. Better: `enabled`, `setting`, or `predictiveOptimization`. -#### 1.2 `*_OptionsEntry.value` / `*_PropertiesEntry.value` (model.ts:59-66, 167-175, 225-232) -Six proto-generated map-entry wrappers exporting `{ key?: string; -value?: string }`. The field names `key` and `value` are maximally -generic. The wrapper types themselves are dead in the v1 surface -(`SchemaInfo.options`/`.properties` are typed as -`Record`, not arrays of these wrappers). See also §11.1. - -#### 1.3 `EffectivePredictiveOptimizationFlag.inheritedFromType` and `.inheritedFromName` (model.ts:83, 85) +#### 1.2 `EffectivePredictiveOptimizationFlag.inheritedFromType` and `.inheritedFromName` (model.ts:83, 85) `inheritedFromType` is `string`, not an enum — the name suggests a typed handle but the value is human-readable text. Same problem for `inheritedFromName`: "the name of the object" — of *what* object? Without context (`catalog`, `schema`, `metastore`?) the field is opaque. See also §6.1. -#### 1.4 `name` on `CreateSchema`, `SchemaInfo`, `UpdateSchema` (model.ts:17, 126, 184) +#### 1.3 `name` on `CreateSchema`, `SchemaInfo`, `UpdateSchema` (model.ts:17, 126, 184) `name` alone is generic in the context of UC where there's also `fullName`, `catalogName`, `newName`, and `metastoreId`. The doc qualifies it as "Name of schema, relative to parent catalog", but the identifier itself doesn't say that. Compare to `catalogName` on the -same shape which is unambiguous. See also §10.2 and §12.2. +same shape which is unambiguous. See also §8.2 and §10.2. --- @@ -83,7 +73,7 @@ redundant — `MANAGED`, `DELTA_SHARING`, `SYSTEM`, `INTERNAL`, also runs two words together — see §3.1.) The enum is duplicated verbatim from the `catalogs` package — even though *this* package is about schemas, it imports the catalog-type enum and exposes it as -`SchemaInfo.catalogType`. See §12.4 for the duplication. +`SchemaInfo.catalogType`. See §10.4 for the duplication. --- @@ -103,197 +93,159 @@ review. --- -### 4. Underscores in TypeScript identifiers - -The package's most widespread cosmetic issue. Six exported types use -proto-style `Parent_Child` names with -`@typescript-eslint/naming-convention` suppression comments — i.e. the -lint rule already disagrees with these names. - -#### 4.1 `CreateSchema_OptionsEntry` (model.ts:58) -Proto map-entry. Should be `CreateSchemaOptionsEntry`, but the wrapper -itself should not exist (see §11.1). - -#### 4.2 `CreateSchema_PropertiesEntry` (model.ts:64) -Same as 4.1. - -#### 4.3 `DeleteSchema_Response` (model.ts:77) -Proto-style underscore identifier. Should be `DeleteSchemaResponse`. - -#### 4.4 `ListSchemas_Response` (model.ts:113) -Should be `ListSchemasResponse`. (Standard top-level response type; -underscore is a Go/proto artefact.) +### 4. Cryptic abbreviations -#### 4.5 `SchemaInfo_OptionsEntry` (model.ts:167) -Same as 4.1. - -#### 4.6 `SchemaInfo_PropertiesEntry` (model.ts:173) -Same as 4.1. - -#### 4.7 `UpdateSchema_OptionsEntry` (model.ts:225) -Same as 4.1. - -#### 4.8 `UpdateSchema_PropertiesEntry` (model.ts:231) -Same as 4.1. - ---- - -### 5. Cryptic abbreviations - -#### 5.1 `fullNameArg` (model.ts:71, 90, 180) +#### 4.1 `fullNameArg` (model.ts:71, 90, 180) Path-parameter field on `DeleteSchema`, `GetSchema`, and `UpdateSchema`. The `Arg` suffix is Go-generator jargon distinguishing path arguments from request-body fields with the same key. TypeScript callers have no need for this distinction — the field *is* the schema identifier and should just be `fullName` (or `name`). Even worse: `UpdateSchema` has *both* `fullNameArg` (path) and `fullName` (body) -on the same type, with no obvious difference in semantics. See §16.1. +on the same type, with no obvious difference in semantics. See §14.1. -#### 5.2 `pkgJson` (client.ts:19) +#### 4.2 `pkgJson` (client.ts:19) Variable name `pkgJson` for `package.json` import. Mostly internal — minor — but worth noting for consistency. -#### 5.3 `req`, `resp`, `opts` (client.ts and utils.ts throughout) +#### 4.3 `req`, `resp`, `opts` (client.ts and utils.ts throughout) Internal abbreviations. Conventional, but worth flagging for the broader audit. --- -### 6. Misleading names +### 5. Misleading names -#### 6.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) +#### 5.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) Field is typed `string | undefined` but the doc comment ("Whether predictive optimization should be enabled…") implies a small discrete set of values (enable / disable / inherit). Either expose an enum or rename the field to make it clear it's a setting key. See also §1.1. -#### 6.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:139) +#### 5.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:139) The doc is honest: "Full name of schema, in form of __catalog_name__.__schema_name__". But the field name `fullName` suggests it might carry additional information not available from -`name`+`catalogName`. It doesn't. See also §12.2. +`name`+`catalogName`. It doesn't. See also §10.2. -#### 6.3 `SchemaInfo.options` vs `SchemaInfo.properties` (model.ts:161-164) +#### 5.3 `SchemaInfo.options` vs `SchemaInfo.properties` (model.ts:161-164) Both are `Record` with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know which to use for what. The doc duplication recurs verbatim in `CreateSchema` (model.ts:51-54) and `UpdateSchema` (model.ts:218-221). Either is underspecified or one of them is -misnamed. See §12.1. +misnamed. See §10.1. --- -### 7. Overly verbose +### 6. Overly verbose -#### 7.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) +#### 6.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) 39 characters. Compounded by `effectivePredictiveOptimizationFlag` as a field name on three different request/response shapes (model.ts:44, 153, 211). Consider `EffectivePredictiveOptimization` (drop the `Flag` suffix — the type already wraps the flag) or -`EffectivePOSetting` if shortening is acceptable. See also §8.4. +`EffectivePOSetting` if shortening is acceptable. See also §7.2. -#### 7.2 `enablePredictiveOptimization: string` (model.ts:27, 136, 194) +#### 6.2 `enablePredictiveOptimization: string` (model.ts:27, 136, 194) Long field name for what is effectively a flag value. Acceptable, but -pairs with §7.1 to make every schema shape verbose. +pairs with §6.1 to make every schema shape verbose. -#### 7.3 `MANAGED_ONLINE_CATALOG` enum value (model.ts:12) — 22 characters; redundant `_CATALOG` per §2.1. +#### 6.3 `MANAGED_ONLINE_CATALOG` enum value (model.ts:12) — 22 characters; redundant `_CATALOG` per §2.1. --- -### 8. Redundant suffixes +### 7. Redundant suffixes -#### 8.1 `SchemaInfo` type name (model.ts:124) +#### 7.1 `SchemaInfo` type name (model.ts:124) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from a resource handle; in TS the convention is to drop it (`Schema`). Compare with `Catalog`, `Table`, -etc. in other packages. +etc. in other packages. Note: dropping `Info` produces `Schema`, which +collides with the zod artifact `Schema` (a runtime validator type in +common use across the JS ecosystem) — the rename must consider that +collision before landing. -#### 8.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) -The whole type *is* the flag; the suffix is redundant. See §7.1. +#### 7.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) +The whole type *is* the flag; the suffix is redundant. See §6.1. -#### 8.3 `Arg` suffix on `fullNameArg` — see §5.1 and §16.1. +#### 7.3 `Arg` suffix on `fullNameArg` — see §4.1 and §14.1. --- -### 9. Singular / plural mismatches +### 8. Singular / plural mismatches _None._ --- -### 10. Reserved-word collisions +### 9. Reserved-word collisions -#### 10.1 `options` field on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:54, 163, 221) +#### 9.1 `options` field on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:54, 163, 221) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (`createSchema(req, options)`, client.ts:74, etc.). Not a compile error but creates cognitive load — inside `createSchema(req, options)` the reader sees both `req.options` (schema metadata) and `options` (call options). The cleanest fix is to -rename the client parameter to `callOptions`. See also §12.1 for the +rename the client parameter to `callOptions`. See also §10.1 for the duplicate-with-`properties` concern. -#### 10.2 `name` field is generic and shadows `Function.prototype.name` +#### 9.2 `name` field is generic and shadows `Function.prototype.name` Used on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:17, 184, 126). Not a reserved word, but commonly shadows the standard `Function.prototype.name` and routinely confuses callers who spread -request objects. See also §1.4. +request objects. See also §1.3. -#### 10.3 `value` field on `EffectivePredictiveOptimizationFlag.value` (model.ts:81) +#### 9.3 `value` field on `EffectivePredictiveOptimizationFlag.value` (model.ts:81) Generic field name, frequently shadows local variables. See §1.1. -#### 10.4 `properties` is not reserved but conflicts with `Object` semantics +#### 9.4 `properties` is not reserved but conflicts with `Object` semantics `SchemaInfo.properties` (model.ts:161) is fine but worth noting that `properties` is a heavily-overloaded term in JS (object properties, descriptor properties, etc.). Combined with the duplicate-with-`options` -problem in §12.1, the name is doubly overloaded. - ---- - -### 11. Empty / trivial wrapper types - -_None._ +problem in §10.1, the name is doubly overloaded. --- -### 12. Duplicate concepts +### 10. Duplicate concepts -#### 12.1 `properties` vs `options` (model.ts:51-54, 161-164, 218-221) +#### 10.1 `properties` vs `options` (model.ts:51-54, 161-164, 218-221) Both `Record` on every schema shape, with identical doc comments ("A map of key-value properties attached to the securable."). Either the documentation needs to differentiate them or -one is redundant. See also §6.4. +one is redundant. See also §5.3. -#### 12.2 `name` vs `fullName` on `SchemaInfo` (model.ts:126, 139) +#### 10.2 `name` vs `fullName` on `SchemaInfo` (model.ts:126, 139) `name` is the schema name "relative to parent catalog"; `fullName` is "in form of __catalog_name__.__schema_name__". These two fields are deterministically derivable from each other (given `catalogName`). Mirror issue in `CreateSchema` (model.ts:17, 31) and `UpdateSchema` -(model.ts:184, 197). See also §6.2. +(model.ts:184, 197). See also §5.2. -#### 12.3 `fullName` vs `fullNameArg` on `UpdateSchema` (model.ts:180, 197) +#### 10.3 `fullName` vs `fullNameArg` on `UpdateSchema` (model.ts:180, 197) The `UpdateSchema` request has **both** `fullNameArg` (the existing schema identifier, path param) and `fullName` (the same field name on the body) — plus `newName` for renaming. Three fields all touching -the schema's identity. See §16.1. +the schema's identity. See §14.1. -#### 12.4 `CatalogType` is re-implemented across packages +#### 10.4 `CatalogType` is re-implemented across packages The exact `CatalogType` enum (with all six variants) is defined here (model.ts:6-13) and also in `catalogs` (and likely in several other UC packages). A consumer touching both packages gets two unrelated TS types named `CatalogType`. Cross-package duplication — flagged in this audit for the broader review. -#### 12.5 `EffectivePredictiveOptimizationFlag` may be duplicated +#### 10.5 `EffectivePredictiveOptimizationFlag` may be duplicated This type is identical to the one in `catalogs` (and probably in any UC securable package). Cross-package duplication. -#### 12.6 `CreateSchema`, `UpdateSchema`, and `SchemaInfo` share ~21 fields verbatim +#### 10.6 `CreateSchema`, `UpdateSchema`, and `SchemaInfo` share ~21 fields verbatim All three types are 95% identical with identical doc strings. This is a generator artefact, but any rename of `storageRoot` must happen in three places. Recommend basing `CreateSchema`/`UpdateSchema` on `Partial` or a shared `SchemaProperties` mixin. -#### 12.7 Overlap with `systemschemas` package +#### 10.7 Overlap with `systemschemas` package The sibling `systemschemas` package operates on a completely different shape (`SystemSchemaInfo` has only `schema` and `state` — no overlap with `SchemaInfo`). Same noun, different types, different clients, @@ -307,61 +259,52 @@ will be surprised to find that system schemas live elsewhere. --- -### 13. Verb-tense inconsistency +### 11. Verb-tense inconsistency -#### 13.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. +#### 11.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. -#### 13.2 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. +#### 11.2 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. No verb-tense inconsistencies found across the package. --- -### 14. Go / Java-style names - -#### 14.1 `…_Response` suffix on response types (`DeleteSchema_Response`, `ListSchemas_Response`) -Proto / gRPC convention `Method_Response`. In TS this should be -`DeleteSchemaResponse` / `ListSchemasResponse`. See §4.3-4.4. +### 12. Go / Java-style names -#### 14.2 `…_OptionsEntry` / `…_PropertiesEntry` map-entry wrappers (six occurrences) -Proto map-entry idiom doesn't exist in TS. See §4.1-4.8. +#### 12.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +Java/Go style. TS convention is to drop it. See §7.1. -#### 14.3 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) -Java/Go style. TS convention is to drop it. See §8.1. - -#### 14.4 `Client` class name (client.ts:44) +#### 12.2 `Client` class name (client.ts:44) Bare `Client` (rather than `SchemasClient`) is a Go-idiom: package qualifies the type. JS consumers commonly import as `import {Client} from '@databricks/sdk-schemas/v1'` and have to alias. Package-wide convention; flagged for the broader review. -#### 14.5 `fullNameArg` — Go-generator naming. See §5.1. +#### 12.3 `fullNameArg` — Go-generator naming. See §4.1. -#### 14.6 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) +#### 12.4 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) Constant naming is fine; flagged for completeness. --- -### 15. Generic field names losing meaning - -#### 15.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. +### 13. Generic field names losing meaning -#### 15.2 `key`, `value` on map-entry wrappers — see §1.2. +#### 13.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. -#### 15.3 `name` on three different schema shapes — see §1.4. +#### 13.2 `name` on three different schema shapes — see §1.3. -#### 15.4 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §6.3, §12.1. +#### 13.3 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §5.3, §10.1. -#### 15.5 `comment` (model.ts:23, 132, 190) +#### 13.4 `comment` (model.ts:23, 132, 190) "User-provided free-form text description." `comment` is too informal for a documented free-text description on a metadata API. `description` would be more honest about its purpose. --- -### 16. Field contradicting type domain +### 14. Field contradicting type domain -#### 16.1 `UpdateSchema` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 197, 182) +#### 14.1 `UpdateSchema` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 197, 182) Four name-bearing fields on a single update request: - `fullNameArg` — existing schema identifier (path param). @@ -375,7 +318,7 @@ identifying the existing schema; the others are vestigial in the update context.) This is the single most user-hostile naming pattern in the package — and it sits on the most-used mutation method. -#### 16.2 `CreateSchema` contains read-only output fields (model.ts:32-50) +#### 14.2 `CreateSchema` contains read-only output fields (model.ts:32-50) `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `catalogType`, `effectivePredictiveOptimizationFlag`, `schemaId`, `browseOnly`. These are server-populated; a creator @@ -383,14 +326,14 @@ setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Same mirror issue in `UpdateSchema` (model.ts:199-217). -#### 16.3 `DeleteSchema.fullNameArg` — see §5.1. +#### 14.3 `DeleteSchema.fullNameArg` — see §4.1. -#### 16.4 `GetSchema.fullNameArg` (model.ts:90) -Same as 16.3. +#### 14.4 `GetSchema.fullNameArg` (model.ts:90) +Same as 14.3. --- -### 17. Inconsistent action verbs +### 15. Inconsistent action verbs Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`. Verbs are consistent — standard CRUD. @@ -398,65 +341,65 @@ No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- -### 18. Long enum values +### 16. Long enum values -#### 18.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:12) +#### 16.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:12) 22-character enum value. Should be `MANAGED_ONLINE` after dropping the redundant `_CATALOG` suffix (§2.1). -#### 18.2 `CatalogType.DELTASHARING_CATALOG` (model.ts:8) +#### 16.2 `CatalogType.DELTASHARING_CATALOG` (model.ts:8) 20-character value; redundant suffix + run-together words. See §3.1. -#### 18.3 Other `CatalogType` variants +#### 16.3 Other `CatalogType` variants `MANAGED_CATALOG` (15), `SYSTEM_CATALOG` (14), `INTERNAL_CATALOG` (16), `FOREIGN_CATALOG` (15). All have redundant `_CATALOG` suffix. See §2.1. --- -### 19. Underspecified IDs +### 17. Underspecified IDs -#### 19.1 `metastoreId` (model.ts:29, 138, 196) +#### 17.1 `metastoreId` (model.ts:29, 138, 196) Documented as "unique identifier of parent metastore". Format opaque (UUID? slug?). Acceptable but unspecified. -#### 19.2 `schemaId` (model.ts:48, 157, 215) +#### 17.2 `schemaId` (model.ts:48, 157, 215) "The unique identifier of the schema." No format hint (UUID?). The field exists alongside `fullName` (which is also a unique identifier in a different sense). Two simultaneous IDs without disambiguation. -#### 19.3 `createdAt` / `updatedAt` (model.ts:33, 37, 142, 146, 200, 204) +#### 17.3 `createdAt` / `updatedAt` (model.ts:33, 37, 142, 146, 200, 204) Type is `number` (epoch milliseconds, per the doc). The unit is not encoded in the field name. `createdAtMs` / `updatedAtMs` would be more honest. (Compare to `lastFailoverTimeMs` in `catalogs`, which gets this right — see catalogs.md §19.7.) -#### 19.4 `createdBy` / `updatedBy` (model.ts:35, 39, 144, 148, 202, 206) +#### 17.4 `createdBy` / `updatedBy` (model.ts:35, 39, 144, 148, 202, 206) Type is `string` — "Username of schema creator" / "Username of user who last modified schema". Underspecified: is this a username, an email, a principal ID? `createdByUsername` would be clearer. -#### 19.5 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) +#### 17.5 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) Both `string`. `inheritedFromType` could be one of the UC securable types, but the field is not enum-typed. `inheritedFromName` is opaque -text. See also §1.3, §1.5. +text. See also §1.2. --- -### 20. Type-suffix tautology +### 18. Type-suffix tautology -#### 20.1 `CatalogType` enum with field `catalogType: CatalogType` +#### 18.1 `CatalogType` enum with field `catalogType: CatalogType` (model.ts:6, 41, 150, 208) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 20.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. +#### 18.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. -#### 20.3 `EffectivePredictiveOptimizationFlag` with field `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` +#### 18.3 `EffectivePredictiveOptimizationFlag` with field `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` (model.ts:44, 153, 211) — field repeats type name verbatim, 35 characters each. Severe tautology, but defensible because the field is the only instance of that type in each parent. Could be shortened to `predictiveOptimization: EffectivePredictiveOptimization` (drop -"Flag" per §8.3 and "effective" per §7.1). +"Flag" per §7.2 and "effective" per §6.1). --- @@ -482,17 +425,7 @@ operationally required. "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### D. `index.ts` re-exports proto-style names verbatim (lines 9, 10, 11, 12, 14, 15, 16, 19, 20, 21) -Every underscore-bearing identifier surfaces in the package's public -API. A consumer of `@databricks/sdk-schemas/v1` sees -`CreateSchema_OptionsEntry`, `CreateSchema_PropertiesEntry`, -`DeleteSchema_Response`, `ListSchemas_Response`, -`SchemaInfo_OptionsEntry`, `SchemaInfo_PropertiesEntry`, -`UpdateSchema_OptionsEntry`, `UpdateSchema_PropertiesEntry` as -first-class exports. This is the highest-leverage place to clean -naming. - -### E. The package name is plural; the entity types are singular +### D. The package name is plural; the entity types are singular The package is `schemas` (plural); the model types are `Schema` (well, `SchemaInfo` — singular). The five client methods mix: `createSchema`/`deleteSchema`/`getSchema`/`updateSchema` (singular — @@ -500,21 +433,21 @@ they act on one) and `listSchemas` (plural — returns many). This is the same pattern as `catalogs`, `tables`, etc. — consistent across the SDK. -### F. `SchemaInfo`'s "Next ID: 45" comment (model.ts:123) +### E. `SchemaInfo`'s "Next ID: 45" comment (model.ts:123) The doc comment is a leftover proto field-number management note. It has no consumer-facing meaning. Should be stripped on the way to TS. -### G. Doc comment for `effectivePredictiveOptimizationFlag` is missing (model.ts:44-46, 153-155, 211-213) +### F. Doc comment for `effectivePredictiveOptimizationFlag` is missing (model.ts:44-46, 153-155, 211-213) The field has no JSDoc, even though the type has a doc. Three occurrences. Consistency: every other field has a doc comment. -### H. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) +### G. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) The field name says "enable" — suggesting boolean — but the type is `string`. The actual value is presumably `'ENABLE' | 'DISABLE' | -'INHERIT'` or similar. The name lies about the type. See also §6.1 +'INHERIT'` or similar. The name lies about the type. See also §5.1 for the related `EffectivePredictiveOptimizationFlag.value`. -### I. Overlap with `systemschemas` package — see §12.7 +### H. Overlap with `systemschemas` package — see §10.7 A consumer reading "schemas" reasonably expects to find all schema operations here. They will not find `disableSystemSchema`, `enableSystemSchema`, or `listSystemSchemas` — those live in @@ -527,72 +460,63 @@ upstream API surface, but the seam is non-obvious to discover. | Identifier | Location | Finding | | ----------------------------------------------------------- | --------------------- | -------------------- | -| `CatalogType` | model.ts:6 | 2.1, 12.4, 18.x, 20.1| -| `CatalogType.MANAGED_CATALOG` | model.ts:7 | 2.1, 18.3 | -| `CatalogType.DELTASHARING_CATALOG` | model.ts:8 | 2.1, 3.1, 18.2 | -| `CatalogType.SYSTEM_CATALOG` | model.ts:9 | 2.1, 18.3 | -| `CatalogType.INTERNAL_CATALOG` | model.ts:10 | 2.1, 18.3 | -| `CatalogType.FOREIGN_CATALOG` | model.ts:11 | 2.1, 18.3 | -| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:12 | 2.1, 18.1 | -| `CreateSchema` | model.ts:15 | 12.6, 16.2 | -| `CreateSchema.name` | model.ts:17 | 1.4, 10.2 | -| `CreateSchema.catalogType` | model.ts:41 | 20.1 | -| `CreateSchema.effectivePredictiveOptimizationFlag` | model.ts:44 | 7.1, 20.3, G | -| `CreateSchema.properties` / `.options` | model.ts:52, 54 | 6.3, 10.1, 12.1, 15.4| -| `CreateSchema_OptionsEntry` | model.ts:58 | 1.2, 4.1, 14.2 | -| `CreateSchema_PropertiesEntry` | model.ts:64 | 1.2, 4.2, 14.2 | -| `DeleteSchema` | model.ts:69 | 16.3 | -| `DeleteSchema.fullNameArg` | model.ts:71 | 5.1, 14.5, 16.3, B | -| `DeleteSchema_Response` | model.ts:77 | 4.3, 14.1 | -| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 7.1, 8.2, 14.3, 20.3 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 6.1, 10.3, 15.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.3, 19.5 | -| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.3, 19.5 | -| `GetSchema.fullNameArg` | model.ts:90 | 5.1, 14.5, 16.4, B | +| `CatalogType` | model.ts:6 | 2.1, 10.4, 16.x, 18.1| +| `CatalogType.MANAGED_CATALOG` | model.ts:7 | 2.1, 16.3 | +| `CatalogType.DELTASHARING_CATALOG` | model.ts:8 | 2.1, 3.1, 16.2 | +| `CatalogType.SYSTEM_CATALOG` | model.ts:9 | 2.1, 16.3 | +| `CatalogType.INTERNAL_CATALOG` | model.ts:10 | 2.1, 16.3 | +| `CatalogType.FOREIGN_CATALOG` | model.ts:11 | 2.1, 16.3 | +| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:12 | 2.1, 16.1 | +| `CreateSchema` | model.ts:15 | 10.6, 14.2 | +| `CreateSchema.name` | model.ts:17 | 1.3, 9.2 | +| `CreateSchema.catalogType` | model.ts:41 | 18.1 | +| `CreateSchema.effectivePredictiveOptimizationFlag` | model.ts:44 | 6.1, 18.3, F | +| `CreateSchema.properties` / `.options` | model.ts:52, 54 | 5.3, 9.1, 10.1, 13.3 | +| `DeleteSchema` | model.ts:69 | 14.3 | +| `DeleteSchema.fullNameArg` | model.ts:71 | 4.1, 12.3, 14.3, B | +| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 6.1, 7.2, 12.1, 18.3 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 5.1, 9.3, 13.1 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.2, 17.5 | +| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.2, 17.5 | +| `GetSchema.fullNameArg` | model.ts:90 | 4.1, 12.3, 14.4, B | | `ListSchemas` | model.ts:95 | — | | `ListSchemas.maxResults` | model.ts:105 | — | | `ListSchemas.pageToken` | model.ts:107 | — | | `ListSchemas.includeBrowse` | model.ts:109 | — | -| `ListSchemas_Response` | model.ts:113 | 4.4, 14.1 | -| `SchemaInfo` | model.ts:124 | 8.1, 12.6, 14.3, F | -| `SchemaInfo.name` | model.ts:126 | 1.4, 10.2 | -| `SchemaInfo.fullName` | model.ts:139 | 6.2, 12.2 | -| `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 19.3 | -| `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 19.4 | -| `SchemaInfo.catalogType` | model.ts:150 | 20.1 | -| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 7.1, 20.3, G | -| `SchemaInfo.schemaId` | model.ts:157 | 19.2 | -| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 6.3, 10.1, 12.1, 15.4| -| `SchemaInfo_OptionsEntry` | model.ts:167 | 1.2, 4.5, 14.2 | -| `SchemaInfo_PropertiesEntry` | model.ts:173 | 1.2, 4.6, 14.2 | -| `UpdateSchema` | model.ts:178 | 12.3, 12.6, 16.1, 16.2 | -| `UpdateSchema.fullNameArg` | model.ts:180 | 5.1, 12.3, 14.5, 16.1, B | -| `UpdateSchema.newName` | model.ts:182 | 16.1 | -| `UpdateSchema.name` | model.ts:184 | 1.4, 10.2, 16.1 | -| `UpdateSchema.fullName` | model.ts:197 | 12.2, 12.3, 16.1 | -| `UpdateSchema.effectivePredictiveOptimizationFlag` | model.ts:211 | 7.1, 20.3, G | -| `UpdateSchema_OptionsEntry` | model.ts:225 | 1.2, 4.7, 14.2 | -| `UpdateSchema_PropertiesEntry` | model.ts:231 | 1.2, 4.8, 14.2 | -| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | H | -| `comment` field | model.ts:23, 132, 190 | 15.5 | -| `Client` (bare name) | client.ts:44 | 14.4 | +| `SchemaInfo` | model.ts:124 | 7.1, 10.6, 12.1, E | +| `SchemaInfo.name` | model.ts:126 | 1.3, 9.2 | +| `SchemaInfo.fullName` | model.ts:139 | 5.2, 10.2 | +| `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 17.3 | +| `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 17.4 | +| `SchemaInfo.catalogType` | model.ts:150 | 18.1 | +| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 6.1, 18.3, F | +| `SchemaInfo.schemaId` | model.ts:157 | 17.2 | +| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 5.3, 9.1, 10.1, 13.3 | +| `UpdateSchema` | model.ts:178 | 10.3, 10.6, 14.1, 14.2 | +| `UpdateSchema.fullNameArg` | model.ts:180 | 4.1, 10.3, 12.3, 14.1, B | +| `UpdateSchema.newName` | model.ts:182 | 14.1 | +| `UpdateSchema.name` | model.ts:184 | 1.3, 9.2, 14.1 | +| `UpdateSchema.fullName` | model.ts:197 | 10.2, 10.3, 14.1 | +| `UpdateSchema.effectivePredictiveOptimizationFlag` | model.ts:211 | 6.1, 18.3, F | +| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | G | +| `comment` field | model.ts:23, 132, 190 | 13.4 | +| `Client` (bare name) | client.ts:44 | 12.2 | | `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 137, 239 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| `index.ts` re-exports | index.ts:7-23 | D | -| Cross-package overlap with `systemschemas` | (package boundary) | 12.7, I | +| Cross-package overlap with `systemschemas` | (package boundary) | 10.7, H | --- ## Recommended priority order -1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchema`** — four name-like fields on the same request, the worst user-facing trap in the package. (§16.1, §5.1, §12.3) -2. **Strip the redundant `_CATALOG` suffix from every `CatalogType` variant.** (§2.1, §18.x) -3. **Drop proto-style `Parent_Child` identifiers** (`DeleteSchema_Response`, `ListSchemas_Response`, six `*_OptionsEntry`/`*_PropertiesEntry`). (§4) -4. **Distinguish or merge `options` and `properties`.** (§12.1, §6.3) -5. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§6.1, H) -6. **Strip read-only fields from `CreateSchema`/`UpdateSchema`.** (§16.2) -7. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) -8. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§19.3) -9. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§19.2, §12.2) -10. **Drop the `Next ID: 45` proto leftover from `SchemaInfo` JSDoc.** (F) -11. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§12.7, I) +1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchema`** — four name-like fields on the same request, the worst user-facing trap in the package. (§14.1, §4.1, §10.3) +2. **Strip the redundant `_CATALOG` suffix from every `CatalogType` variant.** (§2.1, §16.x) +3. **Distinguish or merge `options` and `properties`.** (§10.1, §5.3) +4. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§5.1, G) +5. **Strip read-only fields from `CreateSchema`/`UpdateSchema`.** (§14.2) +6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +7. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§17.3) +8. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§17.2, §10.2) +9. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§7.1) +10. **Strip the `Next ID: 45` leftover from `SchemaInfo` JSDoc.** (E) +11. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§10.7, H) diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index f6c2b5d7..381b127e 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -19,11 +19,11 @@ Notation: file paths are relative to the package root. Findings reference | Severity | Count | | ----------- | ----- | -| High | 8 | +| High | 5 | | Medium | 14 | | Low | 9 | | Observation | 5 | -| **Total** | **36** | +| **Total** | **33** | Headline themes: @@ -34,23 +34,17 @@ Headline themes: and `serviceprincipalsecretsproxy` (workspace-level proxy for the same). All four export a class literally named `Client` and types with the noun `Secret`. Cross-package usage is opaque without aliasing. -2. **Pervasive proto-style `Parent_Response` underscore identifiers.** Every - non-`Get` operation produces an empty `_Response` envelope - (`CreateScope_Response`, `DeleteAcl_Response`, ...). Eleven of the - thirteen public types in `model.ts` carry an underscore, and every one of - them sits behind an `eslint-disable @typescript-eslint/naming-convention` - comment. -3. **Action-verb request types collide with same-named client methods.** +2. **Action-verb request types collide with same-named client methods.** `interface CreateScope` describes the request body; `client.createScope` performs the action. The reader has to mentally distinguish the noun-from- verb each time. Six pairs in this file (`CreateScope`, `DeleteAcl`, `DeleteScope`, `DeleteSecret`, `GetAcl`, `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret`). -4. **Inconsistent action verb across mutating operations.** `Put` for +3. **Inconsistent action verb across mutating operations.** `Put` for creating/updating ACLs and secrets, `Create` for scopes, `Delete` for all three. There is no `Update`. Go's REST SDK adopts the same shape, but `Put` reads as Go/HTTP-method jargon rather than a TS-side action verb. -5. **`scope: string | undefined` everywhere — but required in practice.** +4. **`scope: string | undefined` everywhere — but required in practice.** Eleven of twelve operation request types have `scope?: string | undefined` as their primary identifier. Every server endpoint will reject an absent scope. The "optional" marker is a generator artifact (all proto fields @@ -90,39 +84,21 @@ Headline themes: appear bare in any of them. Document the four-package matrix in each package's README. -### H2. `Client` is unqualified; collides on import with every other package +### H2. `Client` is unqualified; overlaps with `Secret*` types in the same package - **File / line:** `src/v1/client.ts:70` (`export class Client`); re-exported from `src/v1/index.ts:3`. - **Category:** #1 vague/generic. - **Current:** `export class Client`. - **Suggestion:** `export class SecretsClient`. -- **Rationale:** Per repo-wide pattern, every package exports `Client`. Once - two such packages are imported into the same file the user must alias one - of them. Same defect flagged in `credentials.md` #10, `resourcequotas.md` - (implicit), and others. Self-identifying class names eliminate the alias - dance entirely. - -### H3. Eleven proto-style `Parent_Response` types violate TS identifier convention - -- **Files / lines:** `src/v1/model.ts:63, 73, 81, 91, 108, 121, 130, 141, - 156, 178`. Schema constants mirror them: `model.ts:227, 231, 235, 239, - 243, 258, 267, 277, 287, 291`. All eleven sit behind - `// eslint-disable-next-line @typescript-eslint/naming-convention` comments. -- **Category:** #4 underscore in TS identifier, #14 Go/Java-style name. -- **Current:** `CreateScope_Response`, `DeleteAcl_Response`, - `DeleteScope_Response`, `DeleteSecret_Response`, `GetSecret_Response`, - `ListAcls_Response`, `ListScopes_Response`, `ListSecrets_Response`, - `PutAcl_Response`, `PutSecret_Response`. Schemas - `unmarshalCreateScope_ResponseSchema`, etc. -- **Suggestion:** `CreateScopeResponse`, ..., `unmarshalCreateScopeResponseSchema`, - etc. (collapse the underscore). -- **Rationale:** Same defect class as `resourcequotas.md` H2 and - `credentials.md` #18. The codebase itself rejects this convention — every - declaration carries an ESLint disable annotation. Eleven disables in one - file is a strong signal that the generator is producing wrong identifiers. - -### H4. Six request types are verb phrases (action collision with client methods) +- **Rationale:** The package exports `SecretScope`, `SecretMetadata`, and + numerous `Secret*` operation types alongside the bare `Client`. A consumer + importing several symbols from this package gets a mix of self-identifying + `Secret*` names plus an undifferentiated `Client`. Self-identifying the + class name (`SecretsClient`) aligns it with the rest of the package's + exports and also eliminates the cross-package alias dance flagged in H1. + +### H3. Six request types are verb phrases (action collision with client methods) - **Files / lines:** `src/v1/model.ts:51` (`CreateScope`), `:65` (`DeleteAcl`), `:75` (`DeleteScope`), `:83` (`DeleteSecret`), `:93` (`GetAcl`), `:100` @@ -142,7 +118,7 @@ Headline themes: repo: `CreateSecretRequest`, `GetSecretRequest`, `ListSecretsRequest`, etc. Two sibling packages, two conventions. Pick one. -### H5. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` +### H4. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` - **Files / lines:** `src/v1/client.ts:584` (`putAcl`), `:638` (`putSecret`); contrast `:137` (`createScope`), `:262` (`deleteSecret`), `:220` @@ -163,7 +139,7 @@ Headline themes: `/secrets/put` — so the wire format is *also* inconsistent and the generator is faithfully reproducing it. -### H6. Scope name field `scope` is severely overloaded across types +### H5. Scope name field `scope` is severely overloaded across types - **Files / lines:** `src/v1/model.ts:53` (`CreateScope.scope`), `:67` (`DeleteAcl.scope`), `:77` (`DeleteScope.scope`), `:85` @@ -189,45 +165,6 @@ Headline themes: vs request `id`). The Go SDK uses the same `Scope` field name, but TS conventions favour explicitness over brevity. -### H7. `PutSecret.value` discriminated union has cryptic `$case` discriminator field - -- **File / line:** `src/v1/model.ts:163-174`. -- **Category:** #14 Go/Java-style name, #15 generic field names. -- **Current:** - ```ts - value?: - | { $case: 'stringValue'; stringValue: string } - | { $case: 'bytesValue'; bytesValue: Uint8Array } - | undefined; - ``` -- **Issue:** `$case` is the ts-proto-style discriminator marker, not a TS - convention. Idiomatic TS uses a domain-specific tag (`type`, `kind`, - `format`). Worse, the *case names* (`stringValue`, `bytesValue`) duplicate - the *property names* (`stringValue`, `bytesValue`) — so - `value.stringValue` is the read path, `value.$case === 'stringValue'` is - the guard. The redundancy makes the union three things in one (`$case`, - the value, the type) where one would suffice. -- **Suggestion:** either a plain union - `value: { format: 'string'; data: string } | { format: 'bytes'; data: Uint8Array }` - or, since at the wire level the server expects one of two top-level - fields `string_value` / `bytes_value`, model it as two optional fields - with an exactly-one-of constraint enforced at runtime. -- **See also:** Repo-wide pattern; the `credentials` audit catalogues the - same `$case` discriminator in many places. - -### H8. `value` field on `PutSecret` and `GetSecret_Response` carries no domain hint - -- **Files / lines:** `src/v1/model.ts:112` (`GetSecret_Response.value: - Uint8Array`); `:163-174` (`PutSecret.value`). -- **Category:** #1 vague/generic, #15 generic field names. -- **Issue:** A field literally named `value` on a `Uint8Array` is the - flattest possible name. With nothing to disambiguate, the reader has to - read the JSDoc to know it is *the secret payload* (not a metadata value, - a hash, etc.). Compare with `SecretMetadata.lastUpdatedTimestamp` (#L10 - below) which is fully qualified. -- **Suggestion:** `secretValue` or `secretBytes`. The JSDoc itself says - "The value of the secret" — fold that into the identifier. - --- ## Medium Severity @@ -548,7 +485,7 @@ Headline themes: ### O1. `scope` is optional on every request type, but required at the server -- **Files / lines:** see H6. +- **Files / lines:** see H5. - The generator marks every proto field optional. The runtime contract requires `scope` for ten of eleven operations. Not a naming defect but worth noting: the type is wider than the API allows. @@ -596,28 +533,24 @@ Headline themes: ## Recommended renames (high-confidence, in priority order) -1. `Client` → `SecretsClient` (H2). -2. `CreateScope_Response`, `DeleteAcl_Response`, `DeleteScope_Response`, - `DeleteSecret_Response`, `GetSecret_Response`, `ListAcls_Response`, - `ListScopes_Response`, `ListSecrets_Response`, `PutAcl_Response`, - `PutSecret_Response` → strip underscore (H3). -3. `CreateScope`, `DeleteAcl`, `DeleteScope`, `DeleteSecret`, `GetAcl`, +1. `Client` → `SecretsClient` (H1, H2). +2. `CreateScope`, `DeleteAcl`, `DeleteScope`, `DeleteSecret`, `GetAcl`, `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret` → suffix with `Request` to match sibling - `secretsuc` (H4). -4. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply - consistently across all mutating methods (H5). -5. `scope: string` field on every request type → `scopeName: string` (H6). -6. `AclItem` → `Acl` or `AclEntry`; `ListAcls_Response.items` → + `secretsuc` (H3). +3. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply + consistently across all mutating methods (H4). +4. `scope: string` field on every request type → `scopeName: string` (H5). +5. `AclItem` → `Acl` or `AclEntry`; `ListAcls_Response.items` → `ListAclsResponse.acls` (M7, M14). -7. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M8). -8. `SecretMetadata.lastUpdatedTimestamp` → `lastUpdatedAt` (M9). -9. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, +6. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M8). +7. `SecretMetadata.lastUpdatedTimestamp` → `lastUpdatedAt` (M9). +8. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, `backendAzureKeyVault`) (M3). -10. `AzureKeyVaultSecretScopeMetadata.dnsName` → `vaultUri` (M6). -11. `AzureKeyVaultSecretScopeMetadata.resourceId` → `azureResourceId` or +9. `AzureKeyVaultSecretScopeMetadata.dnsName` → `vaultUri` (M6). +10. `AzureKeyVaultSecretScopeMetadata.resourceId` → `azureResourceId` or `keyVaultResourceId` (M5). -12. `SecretScope.backendType` ↔ `CreateScope.scopeBackendType` → pick one +11. `SecretScope.backendType` ↔ `CreateScope.scopeBackendType` → pick one (`backendType`) (M10). -13. `CreateScope.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` +12. `CreateScope.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` → pick one (`keyVaultBackend`) (M11). diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index 91a6a9a3..e7c4828d 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -19,19 +19,19 @@ - **Why weird:** Two words mashed together with no separator: `secrets` + `uc`. The result reads as "secret-suc" or a single nonsense word. `uc` is a two-letter cryptic abbreviation that is never expanded anywhere in the public TypeScript surface — neither the `Client` class, the `Secret` interface, nor any field or constant mentions "UnityCatalog" or "Uc". The only places "Unity Catalog" appears at all are (a) JSDoc prose, (b) the URL path `/api/2.1/unity-catalog/secrets`, and (c) the `Secret` interface JSDoc. The package directory is the only carrier of the disambiguator, and it's silent in code. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept against `packages/secrets/`), 6 (misleading — `secretsuc` looks like a typo or a verb suffix). - **Suggested name:** `secrets-unity-catalog`, `unitycatalogsecrets`, or `ucsecrets` (all worse than expanding fully). Best: rename package to `unitycatalogsecrets` (matching pattern of `unitycatalogvolumes` etc. used elsewhere) or move the secrets type into a sub-namespace of a unified `unitycatalog` package. At a minimum, separate the words: `secrets-uc` or `secretsUc` is still wrong; the actual readable form is **`secrets-unitycatalog`** or **`unitycatalog-secrets`**. -- **Rationale:** A package name is the most user-facing identifier in any SDK — it appears in every `import` line and every `package.json` dependency entry. `secretsuc` fails three tests at once: (a) it is unreadable on first sight (where does the word boundary fall?); (b) it hides the disambiguator that separates it from `secrets`; (c) it embeds an undefined two-letter token. Compare with workspace-level peer `secrets`: a user installing both gets `@databricks/sdk-secrets` and `@databricks/sdk-secretsuc`, with no hint from the names which one targets workspaces and which targets Unity Catalog. The `uc` suffix is the entire semantic load and it's mute. The Go SDK can lean on package paths like `service/catalog/secrets` to add context; npm package names are flat strings and have to carry the disambiguator themselves. +- **Rationale:** A package name is the most user-facing identifier in any SDK — it appears in every `import` line and every `package.json` dependency entry. `secretsuc` fails three tests at once: (a) it is unreadable on first sight (where does the word boundary fall?); (b) it hides the disambiguator that separates it from `secrets`; (c) it embeds an undefined two-letter token. Compare with workspace-level peer `secrets`: a user installing both gets `@databricks/sdk-secrets` and `@databricks/sdk-secretsuc`, with no hint from the names which one targets workspaces and which targets Unity Catalog. The `uc` suffix is the entire semantic load and it's mute. -### 2. `Client` class name — `src/v1/client.ts:41` -- **Why weird:** Bare `Client` for the secret-management API. After `import {Client} from '@databricks/sdk-secretsuc/v1'` the caller has a symbol named `Client` with no domain hint. If the caller also imports from `@databricks/sdk-secrets/v1`, they get two identifiers both called `Client` — they must alias both at import. Inconsistent with packages elsewhere in this SDK that name their main class after the domain. +### 2. `Client` class collides with `secrets` package at the import level — `src/v1/client.ts:41` +- **Why weird:** Bare `Client` for the secret-management API. After `import {Client} from '@databricks/sdk-secretsuc/v1'` the caller has a symbol named `Client` with no domain hint. If the caller also imports from `@databricks/sdk-secrets/v1`, they get two identifiers both called `Client` — they must alias both at import. The collision is sharpest for `secrets` vs `secretsuc`: both export `Client` from the same overall scope, so a user with both deps has to write `import {Client as UcSecretsClient} from '@databricks/sdk-secretsuc/v1'`. - **Category:** 1 (vague), 12 (duplicate concept — every package exports `Client`), 6 (misleading — no hint of which domain it serves). - **Suggested name:** `SecretsClient`, or better, `UnityCatalogSecretsClient`. -- **Rationale:** Every generated package in this SDK exports `Client`; auditing one package can't fix the convention. But the pain is sharpest for `secrets` vs `secretsuc`: both export `Client` from the same overall scope, so a user with both deps has to write `import {Client as UcSecretsClient} from '@databricks/sdk-secretsuc/v1'`. The rename is upstream-wide; flagging here because this package is one of the worst offenders for the duplicate-name collision. +- **Rationale:** Every generated package in this SDK exports `Client`; auditing one package can't fix the convention. But the pain is sharpest for `secrets` vs `secretsuc`, which is why this finding is scoped to that import-level collision. -### 3. `Secret` interface — `src/v1/model.ts:89` -- **Why weird:** Same word used by the sibling `@databricks/sdk-secrets` package's `SecretMetadata`/`PutSecret` types. A consumer with both packages cannot import `Secret` from either without aliasing. The type also doubles as both the entity (returned from `getSecret`) and the input shape (the `Secret` embedded in `CreateSecretRequest.secret` and `UpdateSecretRequest.secret`) — its fields mix read-only (`createTime`, `metastoreId`, `effectiveOwner`) with write-only (`value`) with read-write (`comment`, `owner`). +### 3. `Secret` interface is overloaded as create-input, update-input, and read-output — `src/v1/model.ts:89` +- **Why weird:** Same word used by the sibling `@databricks/sdk-secrets` package's `SecretMetadata`/`PutSecret` types. A consumer with both packages cannot import `Secret` from either without aliasing. The type also doubles as the entity returned from `getSecret`, the input shape embedded in `CreateSecretRequest.secret`, and the update payload embedded in `UpdateSecretRequest.secret`. Its fields mix read-only (`createTime`, `metastoreId`, `effectiveOwner`) with write-only (`value`) with read-write (`comment`, `owner`). - **Category:** 12 (duplicate concept — different `Secret` exists at workspace level), 6 (misleading — single type for create-input + read-output + update-input means many fields are conditionally valid). -- **Suggested name:** `UnityCatalogSecret` for the type. (Splitting into `CreateSecretInput` / `Secret` / `UpdateSecretInput` is a deeper change beyond a naming audit.) -- **Rationale:** Even if the package rename happens, the type name `Secret` carries no UC-specific signal. Users wiring up both APIs will collide. The Go SDK has the same problem but disambiguates via Go's package-qualified types (`secretsuc.Secret` vs `secrets.SecretMetadata`); TS imports are commonly unqualified at the call site, so the type itself needs to carry the disambiguator. +- **Suggested name:** `UnityCatalogSecret` for the type. Splitting into `CreateSecretInput` / `Secret` / `UpdateSecretInput` is the structural fix that would surface the read/write asymmetry in the type system. +- **Rationale:** Even if the package rename happens, the type name `Secret` carries no UC-specific signal. Users wiring up both APIs will collide. Beyond the collision, one type for three lifecycle stages means callers cannot tell from the type which fields are writable on input and which are server-populated on output. ### 4. `externalSecretId` — `src/v1/model.ts:143` - **Why weird:** Completely undocumented field (no JSDoc comment, unlike every other field on `Secret`). The wire field exists in the field-mask but is not in the field-mask's documented "Supported fields" list (`value, comment, owner, expire_time` — `client.ts:238`). The field's existence and semantics are entirely opaque to a reader of the model file. @@ -51,11 +51,11 @@ - **Suggested name:** Rename `effectiveValue` -> `currentValue` or `readValue` to free `effective*` for the inheritance sense; or rename `effectiveOwner` -> `inheritedOwner` / `resolvedOwner`. - **Rationale:** Same prefix, two meanings, within five lines of each other. A reader scanning the struct picks up the first definition and applies it to the second, leading to a wrong mental model. The fact that `effectiveValue` is documented to be populated based on a privilege (not inheritance) makes the prefix actively misleading. -### 7. `fullName` is the primary key but optional — `src/v1/model.ts:23,32,115,152` +### 7. `fullName` is the routing key but marked optional — `src/v1/model.ts:23,32,115,152` - **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:109,136,244`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. - **Category:** 6 (misleading — looks optional, isn't), 16 (field type contradicts domain — required key marked optional). - **Suggested name:** Keep the name, drop `| undefined` on the three request DTOs (or split: `Secret.fullName?` for responses, `SecretRef.fullName` required for requests). -- **Rationale:** This is a routing identifier; the TS type system can prevent a whole class of "I forgot the name" bugs and the SDK can stop substituting empty strings. The Go SDK uses pointer-with-nil-check or empty-string sentinel by convention; TS should be strict. +- **Rationale:** This is a routing identifier; the TS type system can prevent a whole class of "I forgot the name" bugs and the SDK can stop substituting empty strings. ### 8. `includeBrowse` parameter — `src/v1/model.ts:37,56` - **Why weird:** Boolean flag named `includeBrowse` reads as "include browse" with no clarification of what "browse" means. JSDoc clarifies it gates returning secrets the caller only has BROWSE privilege on. Without the doc, the field name is opaque. Same pattern (`browseOnly` on `Secret`, `model.ts:136`) reuses the bare verb. `BROWSE` here is a permission name, not an action. @@ -65,11 +65,11 @@ ## Medium severity -### 9. `Secret` mixes input-only and output-only fields — `src/v1/model.ts:126` -- **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. The shared type is used on both create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output. +### 9. `Secret` mixes effective (server-resolved) and direct (caller-set) fields — `src/v1/model.ts:126` +- **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. The shared type is used on both create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output, and the `effective*` pairs (owner/effectiveOwner, value/effectiveValue) put the resolved and directly-set values next to each other without a structural distinction. - **Category:** 11 (single type wearing two hats), 6 (misleading). - **Suggested name:** Split into `WritableSecret` / `Secret`, or `SecretCreateInput` / `SecretUpdateInput` / `Secret`. -- **Rationale:** The single-type approach is a generator artefact (Go SDK uses one struct with pointer fields to elide zeros); TS lacks that ergonomic and forces every consumer to know which fields are write-permitted. The field-mask on update (`updateMask` — `model.ts:162`) partially mitigates but doesn't substitute for type-level intent. +- **Rationale:** The single-type approach forces every consumer to know which fields are write-permitted. The field-mask on update (`updateMask` — `model.ts:162`) partially mitigates but doesn't substitute for type-level intent. ### 10. `UpdateSecretRequest.secret` is the *update payload* with `fullName` as routing key — `src/v1/model.ts:147-163` - **Why weird:** `UpdateSecretRequest` has both `fullName` (routing) and `secret` (payload). The nested `secret.fullName` is meaningless — what if it differs from the outer `fullName`? The whole `secret`, including its own optional `fullName`, is serialised into the PATCH body even though the path is keyed by the outer `req.fullName`. @@ -86,8 +86,8 @@ ### 12. `createTime` / `updateTime` / `expireTime` vs `createdBy` / `updatedBy` verb tense — `src/v1/model.ts:105,107,109,111,142` - **Why weird:** Past-tense participle on the principal fields (`createdBy`, `updatedBy`) but plain noun on the timestamps (`createTime`, `updateTime`). A consistent convention would be either `createdAt` + `createdBy` (both past-tense, both anchored to event) or `createTime` + `creator` (both noun forms). Mixed forms read as inconsistent. `expireTime` is future tense ("will expire") so isn't symmetrical with `created`/`updated`. - **Category:** 13 (verb-tense inconsistency). -- **Suggested name:** `createdAt` / `updatedAt` / `expiresAt` (or `expireAt`) for timestamps; keep `createdBy` / `updatedBy` for principals. Wire fields stay `create_time` / `update_time` / `expire_time` for backwards compatibility. -- **Rationale:** Common JS convention is `*At` for instant fields. The Go SDK uses `CreateTime`/`UpdateTime` for proto compatibility; TS has no such constraint and can adopt the idiomatic form. +- **Suggested name:** `createdAt` / `updatedAt` / `expiresAt` (or `expireAt`) for timestamps; keep `createdBy` / `updatedBy` for principals. +- **Rationale:** Common JS convention is `*At` for instant fields. The mixed `createTime` + `createdBy` pairing forces the reader to reconcile two tenses for one logical event. ### 13. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` - **Why weird:** Request uses `pageToken`, response uses `nextPageToken`. Internally consistent with conventions across the SDK, but the asymmetry between "what I send" and "what I receive next time" is something the type system can't help with. The pagination iterator (`client.ts:227`) bridges them via `pageReq.pageToken = resp.nextPageToken`. @@ -131,7 +131,7 @@ - **Why weird:** Method names redundantly include `Secret` even though the class is already secret-scoped. `client.createSecret(req)` reads okay, but inside a UC-secrets-only file `client.create(req)` would be cleaner. Compare with `pkgJson.scripts` ("build", "test") — context-scoped commands omit the noun. - **Category:** 8 (redundant suffix — name repeats the class scope). - **Suggested name:** Within the class, `create` / `delete` / `get` / `list` / `update` would be tighter. (But it would break a cross-package convention — every generated client uses ``.) -- **Rationale:** Cross-package convention wins here; flagging because rule 8 asks for redundant suffixes. The Go SDK uses `Create` / `Delete` etc. because Go method calls are scoped by receiver (`secretsuc.Create`). TS does the same implicitly (`client.create`). Worth raising at the SDK-design level. +- **Rationale:** Cross-package convention wins here; flagging because rule 8 asks for redundant suffixes. TS scopes method calls by receiver (`client.create`) without needing to repeat the noun. Worth raising at the SDK-design level. ### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** Same constant repeated in every generated package. `Segment` is generic; reader needs the comment to learn it's the User-Agent identity segment. @@ -172,4 +172,4 @@ No enum types are defined. (`secrets` workspace package has `AclPermission` and ## Cross-package notes - `packages/secrets/` (workspace-level Secrets API): exports `AclPermission`, `AclItem`, `CreateScope`, `DeleteAcl`, `DeleteSecret`, `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret`, `SecretMetadata`, `SecretScope`, `ScopeBackendType`. **Same concept noun (`Secret`) exists in both packages with incompatible shapes.** A consumer with both deps faces name collisions on `Client`, `DeleteSecret`/`DeleteSecretRequest`, `GetSecret`/`GetSecretRequest`, `ListSecrets`/`ListSecretsRequest`, and the workspace-side `PutSecret` vs UC-side `Secret`. -- The workspace-level `secrets` package has its own naming problems (`PutSecret`, `DeleteAcl_Response` empty wrappers, the `key` / `value` flat shape vs UC's three-level `Secret` shape). Out of scope for this audit; flagged because the SDK design choice to have two separate packages multiplies the surface area. +- The workspace-level `secrets` package has its own naming problems (`PutSecret`, the `key` / `value` flat shape vs UC's three-level `Secret` shape). Out of scope for this audit; flagged because the SDK design choice to have two separate packages multiplies the surface area. diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md index 9e3ecf11..371ee385 100644 --- a/.agent/naming-audit/serviceprincipalsecrets.md +++ b/.agent/naming-audit/serviceprincipalsecrets.md @@ -5,7 +5,7 @@ **Inferred domain:** Account-level CRUD over OAuth client secrets attached to a service principal. Endpoints sit under `/api/2.0/accounts//servicePrincipals//credentials/secrets`. -**Total weird names flagged:** 26 +**Total weird names flagged:** 23 --- @@ -18,27 +18,24 @@ a service principal. Endpoints sit under | 3 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names | Request type named after the verb-noun phrase. TS norm is `CreateServicePrincipalSecretRequest` (which is what every other generated package uses — see `*Request` convention). Bare `CreateServicePrincipalSecret` reads like a resource, not an action. | | 4 | `DeleteServicePrincipalSecret` | model.ts:32 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names | Same as #3 — verb-name without `Request` suffix; collides semantically with `ServicePrincipalSecret` (the resource). | | 5 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names, 9 Singular/plural mismatches | Same as #3. Plural `Secrets` further blurs the request/resource boundary — caller sees `ListServicePrincipalSecrets` and the response type `ServicePrincipalSecret[]`. | -| 6 | `DeleteServicePrincipalSecret_Response` | model.ts:42 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names | Underscore-separated identifier (only of its kind in the file). Should be `DeleteServicePrincipalSecretResponse`. Flagged in `naming-convention` eslint disable comment so the generator knows it's odd. | -| 7 | `ListServicePrincipalSecrets_Response` | model.ts:59 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names | Same underscore issue as #6. The TS convention is `ListServicePrincipalSecretsResponse` (matching `CreateServicePrincipalSecretResponse`). Generator deliberately retains the proto-message nesting (`Foo_Response`); consumer-facing types should not leak that. | -| 8 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 1 Vague/generic without domain context, 15 Generic field names losing meaning, 19 Underspecified IDs | Field is the service principal **ID** (per JSDoc `The service principal ID.`) but the field name implies the principal object itself. Should be `servicePrincipalId`. Same problem in `DeleteServicePrincipalSecret` (model.ts:35) and `ListServicePrincipalSecrets` (model.ts:47). | -| 9 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — fine, but the default ("730 days") is documented in JSDoc only; no constant exposed. `secretLifetime` would tie the field to the resource it bounds. | -| 10 | `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` | model.ts:15, 66 | interface pair | High | 12 Duplicate concepts | Both interfaces have identical fields (`id`, `secret`, `secretHash`, `createTime`, `updateTime`, `status`, `expireTime`). One of them is redundant — `CreateServicePrincipalSecretResponse` could `extends ServicePrincipalSecret` or be a type alias. | -| 11 | `ServicePrincipalSecret.secret` | model.ts:69 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret.secret` is a stutter. JSDoc says `Secret Value`. Rename to `value` or `clearTextValue`; `ServicePrincipalSecret.value` is unambiguous. Same field appears in `CreateServicePrincipalSecretResponse.secret` (model.ts:19). | -| 12 | `ServicePrincipalSecret.secretHash` | model.ts:71 | field | Low | 1 Vague/generic without domain context | `secret.secretHash` is also a stutter. `hash` is enough. (Both `secret` and `secretHash` then need renaming; otherwise drop just the `secret` prefix here.) | -| 13 | `ServicePrincipalSecret.id` | model.ts:68 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | Top-level `id: string` is the secret's ID. Should be `secretId` to match `DeleteServicePrincipalSecret.secretId` (model.ts:38), which refers to the same value. The asymmetry forces callers to remember the mapping. | -| 14 | `ServicePrincipalSecret.status` | model.ts:78 | field | High | 1 Vague/generic without domain context, 18 Long enum values | `status: string` — open string with no enum, no JSDoc enumeration of possible values. The Go SDK likely encodes this as `ACTIVE`/`PENDING`/`REVOKED` etc. but TS is left with a stringly-typed field. Should be a `ServicePrincipalSecretStatus` string-literal union. | -| 15 | `ServicePrincipalSecret.createTime` | model.ts:74 | field | Medium | 1 Vague/generic without domain context, 16 Field contradicting type domain | Typed `string \| undefined` but JSDoc says `UTC time when the secret was created`. Sibling `expireTime` (model.ts:80) is `Temporal.Instant`. The two date fields have **different runtime types** for the same semantic. Pick one (likely `Temporal.Instant` for both). | -| 16 | `ServicePrincipalSecret.updateTime` | model.ts:76 | field | Medium | 16 Field contradicting type domain | Same problem as #15 — `string` instead of `Temporal.Instant`. | -| 17 | `CreateServicePrincipalSecretResponse.createTime` / `.updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Mirrors #15/#16 in the response shape (since the two shapes are duplicates). | -| 18 | `ServicePrincipalSecret.expireTime` | model.ts:80 | field | Low | 13 Verb-tense inconsistency | Sibling fields use past tense (`createTime`, `updateTime` — when the action happened). `expireTime` is future tense. Either rename to `expiresAt` / `expirationTime`, or keep all three with consistent grammar (`createdAt`/`updatedAt`/`expiresAt`). | -| 19 | `ListServicePrincipalSecrets.accountId` / `.servicePrincipal` | model.ts:46, 48 | field | Medium | 16 Field contradicting type domain | These are URL path parameters, not list filters. Other SDK packages document this; here the request shape mixes path params (`accountId`, `servicePrincipal`) and query params (`pageToken`, `pageSize`) with no distinction. Caller sees one bag-of-fields. | -| 20 | `ListServicePrincipalSecrets_Response.secrets` | model.ts:61 | field | Low | 9 Singular/plural mismatches | Plural is correct (`secrets: ServicePrincipalSecret[]`), but the wire form is `secrets` (model.ts:115) — no underscore split. Clean. (Flagged only because nextPageToken below is the underscore case.) | -| 21 | `ListServicePrincipalSecrets_Response.nextPageToken` | model.ts:63 | field | Low | 3 Acronym casing inconsistencies | Field is `nextPageToken` (camelCase) and the wire form is `next_page_token` (model.ts:118, 122). Consistent with the SDK norm; no real issue. Listed only because the JSDoc (model.ts:62) uses backticked `page_token` not `pageToken`, which is the wire spelling — confusing for TS consumers. | -| 22 | `ListServicePrincipalSecrets.pageToken` JSDoc | model.ts:50-54 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc says `next_page_token`, `page_token`, and `nextPageToken` — three spellings of two fields in one comment. Doc generator should normalise to the TS field names. | -| 23 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. A consumer that imports `{Client}` from this package and from any other SDK package has to alias each one. Suggest `ServicePrincipalSecretsClient` (or a namespace re-export). | -| 24 | `Client.createServicePrincipalSecret` etc. | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Method names repeat the package name (`createServicePrincipalSecret` inside the `serviceprincipalsecrets` package). After namespacing it becomes `serviceprincipalsecrets.Client.createServicePrincipalSecret(...)` — `create(req)` would suffice if the package boundary is preserved. | -| 25 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Same shared-utils issue across the SDK: two `execute*` functions in one file with overlapping vocabulary. `executeCall` orchestrates retries/timeouts via the public `CallOptions`; `executeHttpCall` does one HTTP roundtrip and converts errors. Names should distinguish them — e.g. `runWithOptions` / `sendRequest`. | -| 26 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 10 Dead code | Exported from `utils.ts` but never imported in `client.ts` (which builds query strings inline via `URLSearchParams` at client.ts:134-142). Either remove or use it. | +| 6 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 1 Vague/generic without domain context, 15 Generic field names losing meaning, 19 Underspecified IDs | Field is the service principal **ID** (per JSDoc `The service principal ID.`) but the field name implies the principal object itself. Should be `servicePrincipalId`. Same problem in `DeleteServicePrincipalSecret` (model.ts:35) and `ListServicePrincipalSecrets` (model.ts:47). | +| 7 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — fine, but the default ("730 days") is documented in JSDoc only; no constant exposed. `secretLifetime` would tie the field to the resource it bounds. | +| 8 | `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` | model.ts:15, 66 | interface pair | High | 12 Duplicate concepts | Both interfaces have identical fields (`id`, `secret`, `secretHash`, `createTime`, `updateTime`, `status`, `expireTime`). One of them is redundant — `CreateServicePrincipalSecretResponse` could `extends ServicePrincipalSecret` or be a type alias. | +| 9 | `ServicePrincipalSecret.secret` | model.ts:69 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret.secret` is a stutter. JSDoc says `Secret Value`. Rename to `value` or `clearTextValue`; `ServicePrincipalSecret.value` is unambiguous. Same field appears in `CreateServicePrincipalSecretResponse.secret` (model.ts:19). | +| 10 | `ServicePrincipalSecret.secretHash` | model.ts:71 | field | Low | 1 Vague/generic without domain context | `secret.secretHash` is also a stutter. `hash` is enough. (Both `secret` and `secretHash` then need renaming; otherwise drop just the `secret` prefix here.) | +| 11 | `ServicePrincipalSecret.id` | model.ts:68 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | Top-level `id: string` is the secret's ID. Should be `secretId` to match `DeleteServicePrincipalSecret.secretId` (model.ts:38), which refers to the same value. The asymmetry forces callers to remember the mapping. | +| 12 | `ServicePrincipalSecret.status` | model.ts:78 | field | High | 1 Vague/generic without domain context, 18 Long enum values | `status: string` — open string with no enum, no JSDoc enumeration of possible values. The Go SDK likely encodes this as `ACTIVE`/`PENDING`/`REVOKED` etc. but TS is left with a stringly-typed field. Should be a `ServicePrincipalSecretStatus` string-literal union. | +| 13 | `ServicePrincipalSecret.createTime` | model.ts:74 | field | Medium | 1 Vague/generic without domain context, 16 Field contradicting type domain | Typed `string \| undefined` but JSDoc says `UTC time when the secret was created`. Sibling `expireTime` (model.ts:80) is `Temporal.Instant`. The two date fields have **different runtime types** for the same semantic. Pick one (likely `Temporal.Instant` for both). | +| 14 | `ServicePrincipalSecret.updateTime` | model.ts:76 | field | Medium | 16 Field contradicting type domain | Same problem as #13 — `string` instead of `Temporal.Instant`. | +| 15 | `CreateServicePrincipalSecretResponse.createTime` / `.updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Mirrors #13/#14 in the response shape (since the two shapes are duplicates). | +| 16 | `ServicePrincipalSecret.expireTime` | model.ts:80 | field | Low | 13 Verb-tense inconsistency | Sibling fields use past tense (`createTime`, `updateTime` — when the action happened). `expireTime` is future tense. Either rename to `expiresAt` / `expirationTime`, or keep all three with consistent grammar (`createdAt`/`updatedAt`/`expiresAt`). | +| 17 | `ListServicePrincipalSecrets.accountId` / `.servicePrincipal` | model.ts:46, 48 | field | Medium | 16 Field contradicting type domain | These are URL path parameters, not list filters. Other SDK packages document this; here the request shape mixes path params (`accountId`, `servicePrincipal`) and query params (`pageToken`, `pageSize`) with no distinction. Caller sees one bag-of-fields. | +| 18 | `ListServicePrincipalSecrets.nextPageToken` JSDoc | model.ts:62 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc (model.ts:62) uses backticked `page_token` not `pageToken`, which is the wire spelling — confusing for TS consumers. | +| 19 | `ListServicePrincipalSecrets.pageToken` JSDoc | model.ts:50-54 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc says `next_page_token`, `page_token`, and `nextPageToken` — three spellings of two fields in one comment. Doc generator should normalise to the TS field names. | +| 20 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. A consumer that imports `{Client}` from this package and from any other SDK package has to alias each one. Suggest `ServicePrincipalSecretsClient` (or a namespace re-export). | +| 21 | `Client.createServicePrincipalSecret` etc. | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Method names repeat the package name (`createServicePrincipalSecret` inside the `serviceprincipalsecrets` package). After namespacing it becomes `serviceprincipalsecrets.Client.createServicePrincipalSecret(...)` — `create(req)` would suffice if the package boundary is preserved. | +| 22 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Same shared-utils issue across the SDK: two `execute*` functions in one file with overlapping vocabulary. `executeCall` orchestrates retries/timeouts via the public `CallOptions`; `executeHttpCall` does one HTTP roundtrip and converts errors. Names should distinguish them — e.g. `runWithOptions` / `sendRequest`. | +| 23 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 10 Dead code | Exported from `utils.ts` but never imported in `client.ts` (which builds query strings inline via `URLSearchParams` at client.ts:134-142). Either remove or use it. | --- @@ -75,27 +72,7 @@ Until that is done, every consumer must read the docs to decide which package to import. Once both are imported, all symbols collide on re-export. -### H2. `*_Response` underscore types - -Two public symbols carry a literal underscore, retained from -proto-message nesting and ESLint-disabled at each site: - -```ts -// model.ts:42 -export interface DeleteServicePrincipalSecret_Response {} - -// model.ts:59 -export interface ListServicePrincipalSecrets_Response { ... } -``` - -These are the only underscored identifiers in the package and the generator -already flags them with `eslint-disable @typescript-eslint/naming-convention`. -The Google TypeScript style guide explicitly disallows underscores in -identifiers (§5.3.1). Rename to camelCase: -`DeleteServicePrincipalSecretResponse`, -`ListServicePrincipalSecretsResponse`. - -### H3. `CreateServicePrincipalSecretResponse` is structurally `ServicePrincipalSecret` +### H2. `CreateServicePrincipalSecretResponse` is structurally `ServicePrincipalSecret` ```ts // model.ts:15 @@ -118,7 +95,7 @@ and the **same** JSDoc. One of them is redundant. Options: Either way the duplicated shape is wasted bundle size. -### H4. `*.servicePrincipal` is misleading +### H3. `*.servicePrincipal` is misleading ```ts // model.ts:10, 35, 48 @@ -132,7 +109,7 @@ Rename the TS field to `servicePrincipalId` and let the wire spelling be preserved at the transport layer. Same fix is needed for the URL parameter use at client.ts:76, 105, 133. -### H5. `ServicePrincipalSecret.status: string` should be a string-literal union +### H4. `ServicePrincipalSecret.status: string` should be a string-literal union ```ts status?: string | undefined; // JSDoc: "Status of the secret" @@ -353,10 +330,7 @@ Unreachable branch for `delete*` (response is always parseable as - **No enums.** The package has zero `enum` types, so categories 2 (redundant enum prefixes) and 18 (long enum values) apply only to `ServicePrincipalSecret.status` which is a `string`, not a literal - union (flagged as H5). -- **Underscores in identifiers.** Only the `*_Response` types use them - (model.ts:42, 59, 108, 112). The generator already flags each one - with `eslint-disable @typescript-eslint/naming-convention`. See H2. + union (flagged as H4). - **Acronym casing.** Only `accountId` (camelCase, idiomatic) and `nextPageToken` (camelCase, idiomatic) appear. No `Url`/`URL`, `Sql`/`SQL`, `Json`/`JSON`, `Oauth`/`OAuth` collisions. diff --git a/.agent/naming-audit/serviceprincipalsecretsproxy.md b/.agent/naming-audit/serviceprincipalsecretsproxy.md index 7ca09360..430664eb 100644 --- a/.agent/naming-audit/serviceprincipalsecretsproxy.md +++ b/.agent/naming-audit/serviceprincipalsecretsproxy.md @@ -6,7 +6,7 @@ service principal (create, list, delete), exposed as a "proxy" variant whose surface area is byte-identical to the sibling `serviceprincipalsecrets` package. -**Total weird names flagged:** 26 +**Total weird names flagged:** 22 --- @@ -17,29 +17,26 @@ package. | 1 | package `serviceprincipalsecretsproxy` | (package) | package | High | 12 Duplicate concepts | Byte-identical to sibling `serviceprincipalsecrets` — every v1 source file (`client.ts`, `model.ts`, `utils.ts`, `index.ts`) has the same MD5; only the npm package name differs. | | 2 | package `serviceprincipalsecretsproxy` | (package) | package | High | 7 Overly verbose, 14 Go/Java-style names not idiomatic TS | 33-character, undelimited compound. Already the longest package name in the SDK; the "proxy" suffix piles onto an already-long base. Consider `sp-secrets-proxy` or a subpath of `serviceprincipalsecrets`. | | 3 | package `serviceprincipalsecretsproxy` | (package) | package | Medium | 6 Misleading names | "Proxy" appears nowhere in the model, client, or URL (`/api/2.0/accounts/.../servicePrincipals/.../credentials/secrets` is the same path used by the non-proxy package). The package name promises a different transport that does not exist in the code. | -| 4 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | 29-char identifier; lacks the `Request` suffix that the rest of the SDK uses for input shapes (`DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets` have the same problem — see #11/#16). The name reads like an action (verb phrase) rather than a request payload. | +| 4 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | 29-char identifier; lacks the `Request` suffix that the rest of the SDK uses for input shapes (`DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets` have the same problem — see #12/#14). The name reads like an action (verb phrase) rather than a request payload. | | 5 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning, 16 Field contradicting type domain | Field is `servicePrincipal: string` but the JSDoc says "The service principal ID" — the value is an ID, not the full SP object. Should be `servicePrincipalId`. Same offender in `DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets`. | | 6 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — generic; `secretLifetime` or `ttl` would be clearer. The default-730-days note is essential and lives only in JSDoc. | | 7 | `CreateServicePrincipalSecretResponse` | model.ts:15 | interface | Medium | 7 Overly verbose, 12 Duplicate concepts | 37-char identifier and structurally identical to `ServicePrincipalSecret` (model.ts:66) — same seven fields in the same order with the same JSDoc. One of the two is redundant; the response wrapper could be `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret`. | | 8 | `CreateServicePrincipalSecretResponse.id` | model.ts:17 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | `id?: string` — what is the ID of? The JSDoc clarifies "ID of the secret"; rename to `secretId` to match `DeleteServicePrincipalSecret.secretId`. Same issue in `ServicePrincipalSecret.id`. | | 9 | `CreateServicePrincipalSecretResponse.secret` | model.ts:19 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret?: string` inside `ServicePrincipalSecret` reads as `ServicePrincipalSecret.secret` — meaningless self-reference. Rename to `secretValue` (the JSDoc already calls it "Secret Value"). | | 10 | `CreateServicePrincipalSecretResponse.secretHash` | model.ts:21 | field | Low | 1 Vague/generic without domain context | Plain `secretHash: string` — no hash algorithm noted. The wire JSON sends `secret_hash`; doc does not specify SHA-256, SHA-512, etc. | -| 11 | `CreateServicePrincipalSecretResponse.status` | model.ts:27 | field | Medium | 1 Vague/generic without domain context, 4 Underscores in TS identifiers (wire) | `status?: string` — completely untyped. Likely an enum on the server (`ACTIVE`/`REVOKED`/`EXPIRED`), but TS callers see a free-form string with zero discoverability. | +| 11 | `CreateServicePrincipalSecretResponse.status` | model.ts:27 | field | Medium | 1 Vague/generic without domain context | `status?: string` — completely untyped. Likely an enum on the server (`ACTIVE`/`REVOKED`/`EXPIRED`), but TS callers see a free-form string with zero discoverability. | | 12 | `CreateServicePrincipalSecretResponse.createTime` / `updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Typed as `string` while the sibling `expireTime` (model.ts:29) is `Temporal.Instant`. Wire form is the same ISO-8601 timestamp for all three — the asymmetric typing is a generator bug, not an intentional API choice. | | 13 | `CreateServicePrincipalSecretResponse.expireTime` | model.ts:29 | field | Low | 3 Acronym casing inconsistencies | Inconsistent with `createTime` / `updateTime` typing (see #12). | | 14 | `DeleteServicePrincipalSecret` | model.ts:32 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | Same problem as #4: name is a verb phrase ("Delete a SP secret"), not a payload type; lacks `Request` suffix. | | 15 | `DeleteServicePrincipalSecret.secretId` | model.ts:38 | field | Low | 19 Underspecified IDs | Good in isolation, but the request also carries `servicePrincipal: string` which is *also* an ID — naming asymmetry: one field has `Id`, the other doesn't (see #5). | -| 16 | `DeleteServicePrincipalSecret_Response` | model.ts:42 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names not idiomatic TS | Protobuf-style underscore in the TS identifier; requires `eslint-disable-next-line @typescript-eslint/naming-convention`. Should be `DeleteServicePrincipalSecretResponse` (PascalCase, no underscore). | -| 17 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency, 9 Singular/plural mismatches | Plural form ("ListServicePrincipalSecret*s*") is a verb phrase, not a request payload type. Singular vs plural inconsistency with the other two requests in the same file. Rename to `ListServicePrincipalSecretsRequest`. | -| 18 | `ListServicePrincipalSecrets.pageToken` | model.ts:54 | field | Low | 18 Long enum values (analogous) | Field is fine, but the JSDoc is 358 chars long for one field — out of proportion. Worth surfacing on the type itself or in package docs. | -| 19 | `ListServicePrincipalSecrets.pageSize` | model.ts:55 | field | Low | 1 Vague/generic without domain context | Field has no JSDoc at all (unlike `pageToken` which has 4 lines). Inconsistent within the same interface. | -| 20 | `ListServicePrincipalSecrets_Response` | model.ts:59 | interface | High | 4 Underscores in TS identifiers, 14 Go/Java-style names not idiomatic TS | Protobuf-style underscore in TS identifier; needs an `eslint-disable-next-line` for `@typescript-eslint/naming-convention`. Should be `ListServicePrincipalSecretsResponse`. | -| 21 | `ListServicePrincipalSecrets_Response.secrets` | model.ts:61 | field | Low | 9 Singular/plural mismatches | Plural is correct. JSDoc says "List of the secrets" — phrasing nit, "List of secrets" would read better. | -| 22 | `ServicePrincipalSecret` | model.ts:66 | interface | Medium | 12 Duplicate concepts | Structurally identical to `CreateServicePrincipalSecretResponse` (see #7). Two names for one shape. | -| 23 | `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` | model.ts:68, 70, 72, 78 | field | Medium | 1 Vague/generic without domain context | Same vague-field issues as the response copy (#8-#11). | -| 24 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. Once two Databricks clients are imported in the same module, every one is just `Client`. Should be `ServicePrincipalSecretsProxyClient` or aliased on export. | -| 25 | `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Inside a class named `Client` (let alone a class that should be `ServicePrincipalSecretsClient`), repeating `ServicePrincipalSecret` in every method name is stutter. `create(req)` / `delete(req)` / `list(req)` would read cleanly. | -| 26 | `PACKAGE_SEGMENT` | client.ts:37 | const | Low | 1 Vague/generic without domain context | Used only to assemble the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory. | +| 16 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency, 9 Singular/plural mismatches | Plural form ("ListServicePrincipalSecret*s*") is a verb phrase, not a request payload type. Singular vs plural inconsistency with the other two requests in the same file. Rename to `ListServicePrincipalSecretsRequest`. | +| 17 | `ListServicePrincipalSecrets.pageToken` | model.ts:54 | field | Low | 18 Long enum values (analogous) | Field is fine, but the JSDoc is 358 chars long for one field — out of proportion. Worth surfacing on the type itself or in package docs. | +| 18 | `ListServicePrincipalSecrets.pageSize` | model.ts:55 | field | Low | 1 Vague/generic without domain context | Field has no JSDoc at all (unlike `pageToken` which has 4 lines). Inconsistent within the same interface. | +| 19 | `ServicePrincipalSecret` | model.ts:66 | interface | Medium | 12 Duplicate concepts | Structurally identical to `CreateServicePrincipalSecretResponse` (see #7). Two names for one shape. | +| 20 | `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` | model.ts:68, 70, 72, 78 | field | Medium | 1 Vague/generic without domain context | Same vague-field issues as the response copy (#8-#11). | +| 21 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. Once two Databricks clients are imported in the same module, every one is just `Client`. Should be `ServicePrincipalSecretsProxyClient` or aliased on export. | +| 22 | `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Inside a class named `Client` (let alone a class that should be `ServicePrincipalSecretsClient`), repeating `ServicePrincipalSecret` in every method name is stutter. `create(req)` / `delete(req)` / `list(req)` would read cleanly. | +| 23 | `PACKAGE_SEGMENT` | client.ts:37 | const | Low | 1 Vague/generic without domain context | Used only to assemble the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory. | --- @@ -104,22 +101,6 @@ also internally inconsistent with `DeleteServicePrincipalSecret.secretId` Rename to `servicePrincipalId` everywhere. -### H3. Protobuf-style underscore identifiers leak into TS - -Two identifiers carry an embedded `_` that requires `eslint-disable-next-line` -comments at every declaration: - -- `DeleteServicePrincipalSecret_Response` (model.ts:42) -- `ListServicePrincipalSecrets_Response` (model.ts:59) - -This is category 4 (underscores in TS identifiers) and category 14 -(Go/Java-style names not idiomatic TS). The inline comments -(`// Proto-style nested message name.`) acknowledge that the names exist only -to preserve the wire-message hierarchy from protobuf — there is no TS-side -reason to keep them. Rename to PascalCase -(`DeleteServicePrincipalSecretResponse`, `ListServicePrincipalSecretsResponse`) -and drop the eslint disables. - --- ## Medium severity (worth pushing back on) @@ -286,7 +267,7 @@ validation error. Not a naming issue per se, but a result of the underspecified naming issues must be fixed upstream in the generator / OpenAPI spec. - **No enums.** The package has zero enum types, so categories 2 (redundant enum prefixes) and 18 (long enum values) do not apply. The `status` field - (#11/#23) is a likely enum that was generated as a free-form string. + (#11/#20) is a likely enum that was generated as a free-form string. - **No `Url`/`URL`, `Sql`, `Json`, `Oauth` casing collisions.** `accountId` (camelCase) and `secretId` are the only acronyms in the public surface. - **No reserved-word collisions** — no `delete`, `class`, `new`, etc. as diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index 890831c1..e6b6f747 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 **Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). -**Total weird names flagged:** 106 +**Total weird names flagged:** 87 --- @@ -34,106 +34,94 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | 4 | High | Vague/generic type | `Setting` | `model.ts:297` | | 5 | High | Vague/generic type | `SettingsMetadata` | `model.ts:396` | | 6 | High | Vague/generic type | `UserPreference` | `model.ts:424` | -| 7 | High | Underscore in TS identifier | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` | `model.ts:30` | -| 8 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek` | `model.ts:38` | -| 9 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency` | `model.ts:50` | -| 10 | High | Underscore in TS identifier | `PersonalComputeMessage_PersonalComputeMessageEnum` | `model.ts:66` | -| 11 | High | Underscore in TS identifier | `RestrictWorkspaceAdminsMessage_Status` | `model.ts:73` | -| 12 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_EnablementDetails` | `model.ts:119` | -| 13 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow` | `model.ts:129` | -| 14 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` | `model.ts:136` | -| 15 | High | Underscore in TS identifier | `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` | `model.ts:147` | -| 16 | High | Redundant enum prefix | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | -| 17 | High | Redundant enum prefix | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | -| 18 | High | Redundant enum prefix | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | -| 19 | High | Redundant enum prefix | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | -| 20 | High | Redundant enum prefix | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | -| 21 | High | Redundant enum prefix | `STATUS_UNSPECIFIED` | `model.ts:75` | -| 22 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:98-103, 171, 284, 288, 414` | -| 23 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | -| 24 | High | Cryptic abbreviation (undefined) | `Gov` in `disableGovTagCreation` | `model.ts:294` | -| 25 | High | Generic field name | `value` (on `BooleanMessage`, `IntegerMessage`, `StringMessage`, `PersonalComputeMessage`) | `model.ts:99, 172, 285, 416` | -| 26 | High | Generic field name | `name` (across `Setting`, `SettingsMetadata`, `UserPreference`, `GetPublicAccountSettingRequest`, ...) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | -| 27 | High | Generic field name | `type?: string` on `SettingsMetadata` | `model.ts:402` | -| 28 | High | Generic field name | `setting?: Setting` on update requests | `model.ts:266, 275, 281` | -| 29 | High | Generic field name | `setting?: UserPreference` (note: type is UserPreference, field name is `setting`) | `model.ts:275` | -| 30 | High | Generic discriminator value | `booleanVal`, `stringVal`, `integerVal` | `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` | -| 31 | High | Generic discriminator value | `effectiveBooleanVal`, `effectiveStringVal`, `effectiveIntegerVal` | `model.ts:354, 359, 364, 444, 445` | -| 32 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:153, 159, 177, 206, 264, 271` | -| 33 | High | Underspecified ID | `userId` | `model.ts:161, 208, 273, 428` | -| 34 | High | Misleading type name | `UserPreference` field named `setting` (on PatchPublicAccountUserPreferenceRequest) | `model.ts:275` | -| 35 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:303, 305, 351, 352` | -| 36 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:288` | -| 37 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:102` | -| 38 | High | Verb-tense | `disableGovTagCreation` (imperative verb as state field) | `model.ts:294` | -| 39 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | -| 40 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:152, 157, 166, 262, 269, 278`; `client.ts:83, 112, 137, 346, 378, 409` | -| 41 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | -| 42 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | -| 43 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | -| 44 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:225` | -| 45 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:204` | -| 46 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:269` | -| 47 | Medium | Long type name | `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` (64 chars) | `model.ts:136` | -| 48 | Medium | Long type name | `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` (59 chars) | `model.ts:147` | -| 49 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:194, 196`; `client.ts:166` | -| 50 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:225-227`; `client.ts:226` | -| 51 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:252-254` | -| 52 | Medium | Overly verbose | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` (when accessed as enum member) | `model.ts:13` | -| 53 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | -| 54 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | -| 55 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:294` | -| 56 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:322` | -| 57 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:337` | -| 58 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:104` | -| 59 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:148-149` | -| 60 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:369` | -| 61 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:374` | -| 62 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:379` | -| 63 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:384` | -| 64 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:389` | -| 65 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:411` | -| 66 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:404` | -| 67 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:398` | -| 68 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:404`; `utils.ts:69, 71, 100, 103` | -| 69 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:107` | -| 70 | Low | Long enum value | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | -| 71 | Low | Long enum value | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | -| 72 | Low | Long enum value | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | -| 73 | Low | Long enum value | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | -| 74 | Low | Long enum value | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | -| 75 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | -| 76 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | -| 77 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | -| 78 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:79` | -| 79 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:79` | -| 80 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:79, 83` | -| 81 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:79` | -| 82 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:99, 172, 285, 305, 416, 434` | -| 83 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:402` | -| 84 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | -| 85 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:153, 161, ...` | -| 86 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | -| 87 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:275` | -| 88 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:624, 959` | -| 89 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | -| 90 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:172` | -| 91 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:305, 99` | -| 92 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:327-329` | -| 93 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:374` | -| 94 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:103` | -| 95 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:137` | -| 96 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:289` | -| 97 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | -| 98 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:160-161` | -| 99 | Low | Empty default | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED = 'PREVIEW_PHASE_UNSPECIFIED'` doc says unset-OR-not-a-preview (two distinct meanings) | `model.ts:12-13` | -| 100 | Low | Long type | `ClusterAutoRestartMessage_EnablementDetails` containing three `unavailable_for_*` booleans | `model.ts:119-126` | -| 101 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:121` | -| 102 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:123` | -| 103 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:125` | -| 104 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | -| 105 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | -| 106 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | +| 7 | High | Redundant enum prefix | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | +| 8 | High | Redundant enum prefix | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | +| 9 | High | Redundant enum prefix | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | +| 10 | High | Redundant enum prefix | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | +| 11 | High | Redundant enum prefix | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | +| 12 | High | Redundant enum prefix | `STATUS_UNSPECIFIED` | `model.ts:75` | +| 13 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:98-103, 171, 284, 288, 414` | +| 14 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | +| 15 | High | Cryptic abbreviation (undefined) | `Gov` in `disableGovTagCreation` | `model.ts:294` | +| 16 | High | Generic field name | `value` (on `BooleanMessage`, `IntegerMessage`, `StringMessage`, `PersonalComputeMessage`) | `model.ts:99, 172, 285, 416` | +| 17 | High | Generic field name | `name` (across `Setting`, `SettingsMetadata`, `UserPreference`, `GetPublicAccountSettingRequest`, ...) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | +| 18 | High | Generic field name | `type?: string` on `SettingsMetadata` | `model.ts:402` | +| 19 | High | Generic field name | `setting?: Setting` on update requests | `model.ts:266, 275, 281` | +| 20 | High | Generic field name | `setting?: UserPreference` (note: type is UserPreference, field name is `setting`) | `model.ts:275` | +| 21 | High | Generic discriminator value | `booleanVal`, `stringVal`, `integerVal` | `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` | +| 22 | High | Generic discriminator value | `effectiveBooleanVal`, `effectiveStringVal`, `effectiveIntegerVal` | `model.ts:354, 359, 364, 444, 445` | +| 23 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:153, 159, 177, 206, 264, 271` | +| 24 | High | Underspecified ID | `userId` | `model.ts:161, 208, 273, 428` | +| 25 | High | Misleading type name | `UserPreference` field named `setting` (on PatchPublicAccountUserPreferenceRequest) | `model.ts:275` | +| 26 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:303, 305, 351, 352` | +| 27 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:288` | +| 28 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:102` | +| 29 | High | Verb-tense | `disableGovTagCreation` (imperative verb as state field) | `model.ts:294` | +| 30 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | +| 31 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:152, 157, 166, 262, 269, 278`; `client.ts:83, 112, 137, 346, 378, 409` | +| 32 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | +| 33 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | +| 34 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | +| 35 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:225` | +| 36 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:204` | +| 37 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:269` | +| 38 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:194, 196`; `client.ts:166` | +| 39 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:225-227`; `client.ts:226` | +| 40 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:252-254` | +| 41 | Medium | Overly verbose | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` (when accessed as enum member) | `model.ts:13` | +| 42 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | +| 43 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | +| 44 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:294` | +| 45 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:322` | +| 46 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:337` | +| 47 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:104` | +| 48 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:148-149` | +| 49 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:369` | +| 50 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:374` | +| 51 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:379` | +| 52 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:384` | +| 53 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:389` | +| 54 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:411` | +| 55 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:404` | +| 56 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:398` | +| 57 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:404`; `utils.ts:69, 71, 100, 103` | +| 58 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:107` | +| 59 | Low | Long enum value | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | +| 60 | Low | Long enum value | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | +| 61 | Low | Long enum value | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | +| 62 | Low | Long enum value | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | +| 63 | Low | Long enum value | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | +| 64 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | +| 65 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | +| 66 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | +| 67 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:79` | +| 68 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:79` | +| 69 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:79, 83` | +| 70 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:79` | +| 71 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:99, 172, 285, 305, 416, 434` | +| 72 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:402` | +| 73 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | +| 74 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:153, 161, ...` | +| 75 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | +| 76 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:275` | +| 77 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:624, 959` | +| 78 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | +| 79 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:172` | +| 80 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:305, 99` | +| 81 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:327-329` | +| 82 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:374` | +| 83 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:103` | +| 84 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:137` | +| 85 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:289` | +| 86 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | +| 87 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:160-161` | +| 88 | Low | Empty default | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED = 'PREVIEW_PHASE_UNSPECIFIED'` doc says unset-OR-not-a-preview (two distinct meanings) | `model.ts:12-13` | +| 89 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:121` | +| 90 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:123` | +| 91 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:125` | +| 92 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | +| 93 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | +| 94 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | --- @@ -157,7 +145,7 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **File:line:** `model.ts` (this) vs `workspacesettings/v1/model.ts` - **Category:** Duplicate concept — same TS identifier defined twice -- **Identifiers:** `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage`, plus all their nested types (`*_MaintenanceWindow`, `*_DayOfWeek`, `*_WeekDayFrequency`, `*_EnablementDetails`, `*_WindowStartTime`, `*_WeekDayBasedSchedule`, `_AccessPolicyType`, `_Status`, `_PersonalComputeMessageEnum`). +- **Identifiers:** `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage`. - **Suggestion:** Hoist these into a shared `@databricks/sdk-settings-shared` package (or just `@databricks/sdk-common` if the messages stabilize). A consumer who imports `{ClusterAutoRestartMessage}` from both `settings` and `workspacesettings` gets two structurally-identical-but-nominally-distinct types and any function expecting one rejects the other. - **Rationale:** Verified by grepping both packages — the type declarations are byte-for-byte the same. The Go SDK upstream uses the same proto definition for both, so the duplication is faithful to the source, but in TypeScript it manifests as a real collision. @@ -186,38 +174,21 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Either fold into `Setting` (since the structure differs only in which `$case` payloads are allowed) or rename to `UserSetting` for parallelism with the package theme. The doc comment at `model.ts:419-423` already says "user-specific setting scoped to an individual user" — the word "preference" then competes with "setting" for the same concept. - **Rationale:** Three top-level structural types — `Setting`, `UserPreference`, `SettingsMetadata` — that all model "name + value(s)" with slightly different shapes. A user reading just type names cannot predict which to use. -### 7–15. `Type_NestedType` underscore-bearing identifiers — Go/Java-style names in TS - -- **File:line:** `model.ts:30, 38, 50, 66, 73, 119, 129, 136, 147` -- **Category:** Underscore in TS identifier -- **Identifiers:** - - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` - - `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek` - - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency` - - `PersonalComputeMessage_PersonalComputeMessageEnum` - - `RestrictWorkspaceAdminsMessage_Status` - - `ClusterAutoRestartMessage_EnablementDetails` - - `ClusterAutoRestartMessage_MaintenanceWindow` - - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` - - `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` -- **Suggestion:** Hoist as siblings (e.g. `AccessPolicyType`, `MaintenanceWindow`, `MaintenanceWindowDayOfWeek`, `RestrictWorkspaceAdminsStatus`) or use a TS namespace if you need scoping. The codebase already disables ESLint for these (`@typescript-eslint/naming-convention`), tagging them as a known violation. -- **Rationale:** Google TypeScript style guide forbids underscores in `PascalCase` identifiers. The disable comments on every such identifier ("Proto-style nested message name") confirm the team knows these are non-idiomatic but kept for proto fidelity. In a JS SDK consumer-facing surface, this leaks proto plumbing. - -### 16–21. Redundant enum prefixes ("X_X_UNSPECIFIED" pattern) +### 7–12. Redundant enum prefixes ("X_X_UNSPECIFIED" pattern) - **File:line:** `model.ts:13, 31, 39, 51, 67, 75` - **Category:** Redundant enum prefix - **Identifiers:** - `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` - - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType.ACCESS_POLICY_TYPE_UNSPECIFIED` - - `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` - - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency.WEEK_DAY_FREQUENCY_UNSPECIFIED` - - `PersonalComputeMessage_PersonalComputeMessageEnum.PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` - - `RestrictWorkspaceAdminsMessage_Status.STATUS_UNSPECIFIED` + - `ACCESS_POLICY_TYPE_UNSPECIFIED` + - `DAY_OF_WEEK_UNSPECIFIED` + - `WEEK_DAY_FREQUENCY_UNSPECIFIED` + - `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` + - `STATUS_UNSPECIFIED` - **Suggestion:** Just `UNSPECIFIED` everywhere — the enum identifier already conveys scope. `PreviewPhase.UNSPECIFIED` reads better than `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED`. - **Rationale:** The prefix duplicates the enum name — `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` mentions "preview phase" three times. This is a proto3 wire artefact (proto3 requires enum values to be globally unique within a `.proto` file). TypeScript enums are namespaced; the prefix adds zero disambiguation. `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` is especially egregious — five words to mean "default". -### 22. `*Message` suffix — Go/proto-style +### 13. `*Message` suffix — Go/proto-style - **File:line:** `model.ts:98, 102, 171, 284, 288, 414` - **Category:** Suffix tautology / Go-style @@ -225,72 +196,72 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Drop `Message`. Rename `ClusterAutoRestartMessage → ClusterAutoRestart`, `RestrictWorkspaceAdminsMessage → RestrictWorkspaceAdmins`, etc. The "Message" suffix is the protobuf convention for "everything is a Message"; in TS where "everything is an interface", the suffix is noise. - **Rationale:** No other TS-idiomatic SDK uses `*Message` as a suffix. The classes are not messages in any TS-visible sense (they don't extend a `Message` base, they have no serialization methods — the marshal/unmarshal functions are external). -### 23. `Aibi` — undefined cryptic abbreviation (AI/BI) +### 14. `Aibi` — undefined cryptic abbreviation (AI/BI) - **File:line:** `model.ts:30, 88, 94, 327-329, 374` and method-name appearances in `client.ts` - **Category:** Cryptic abbreviation, acronym casing - **Suggestion:** `AIBI` (acronym casing) or spell out `AiBi` for the AI/BI Genie embedding feature. Add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." - **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. -### 24. `Gov` in `disableGovTagCreation` — undocumented abbreviation +### 15. `Gov` in `disableGovTagCreation` — undocumented abbreviation - **File:line:** `model.ts:294` - **Category:** Cryptic abbreviation - **Suggestion:** `disableGovernanceTagCreation`. The full word adds five characters and removes ambiguity (`Gov` could be government, governance, governor, ...). - **Rationale:** The doc says "workspace admins cannot create governance tags" — so "Gov" abbreviates "Governance". The wire key is `disable_gov_tag_creation` (`model.ts:624`), but the TS surface can be more verbose. -### 25. `value` field everywhere — generic field name +### 16. `value` field everywhere — generic field name - **File:line:** `model.ts:99, 172, 285, 416` on the message wrappers; `model.ts:305, 434` on the discriminated unions; nested deep inside (`Setting.value.booleanVal.value`). - **Category:** Generic field name + reserved-word adjacency - **Suggestion:** For the discriminated unions (`Setting.value`), `payload` would be slightly clearer. - **Rationale:** `setting.value.booleanVal.value` is four levels of `.value`/`.someVal` indirection to access one boolean. The naming makes auto-complete useless. `value` is a member of many JS built-ins (Map entries, Symbol.iterator results, DOM events, IndexedDB cursors), so it has soft reserved-word risk. -### 26. `name` everywhere — generic field name +### 17. `name` everywhere — generic field name - **File:line:** `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` - **Category:** Generic field name - **Suggestion:** `settingKey` or `settingName` would convey purpose. The current `name` is so generic the JSDoc has to repeat "Name of the setting" everywhere. - **Rationale:** The field is in fact the *key* — the unique identifier used in the URL path (`/settings/${req.name ?? ''}`) — not a human display name. The actual display name is `displayName` on `SettingsMetadata`. Naming the key "name" and the human name "displayName" inverts intuition (typically "name" is the display name and "id"/"key" is the identifier). -### 27. `type?: string` on `SettingsMetadata` — generic + misleading +### 18. `type?: string` on `SettingsMetadata` — generic + misleading - **File:line:** `model.ts:402` - **Category:** Generic field name, reserved-word adjacency, misleading - **Suggestion:** `valueTypeMessage` or `sampleTypeMessage`. The JSDoc says "Sample message depicting the type of the setting. To set this setting, the value sent must match this type." - **Rationale:** A field called `type` returning a *sample message* (not a type-id or schema URI) is misleading. Combined with the JS-builtin overlap (`typeof obj.type === 'string'`), the field name invites confusion. -### 28–29. `setting?: Setting` and `setting?: UserPreference` — generic field name + misleading +### 19–20. `setting?: Setting` and `setting?: UserPreference` — generic field name + misleading - **File:line:** `model.ts:266, 275, 281` - **Category:** Generic field name + misleading - **Suggestion:** Rename to match the typed payload: `setting?: Setting` is okay; `setting?: UserPreference` is wrong — should be `userPreference?: UserPreference`. - **Rationale:** On `PatchPublicAccountUserPreferenceRequest`, the field is named `setting` but typed `UserPreference`. The whole package's distinction between "setting" and "user preference" depends on these being separate concepts — so calling the user-preference field "setting" undoes that distinction at the request level. -### 30–31. `booleanVal`, `stringVal`, `integerVal`, `effective*Val` — generic discriminator values +### 21–22. `booleanVal`, `stringVal`, `integerVal`, `effective*Val` — generic discriminator values - **File:line:** `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` - **Category:** Generic field name - **Suggestion:** Drop the `*Val` suffix (it duplicates the parent field `value`) and name by domain: instead of `value: {$case: 'booleanVal', booleanVal: BooleanMessage}`, prefer `value: {kind: 'boolean', boolean: boolean}`. - **Rationale:** A user writing `setting.value?.$case === 'booleanVal'` then accessing `setting.value.booleanVal.value` does three discriminations to read a single bool. The "Val" abbreviation is the only naming variation between the discriminator tag ("booleanVal") and the type name ("BooleanMessage"); the abbreviation contributes nothing. -### 32–33. `accountId`, `userId` — underspecified IDs +### 23–24. `accountId`, `userId` — underspecified IDs - **File:line:** `model.ts:153, 159, 161, 177, 206, 208, 264, 271, 273, 428` - **Category:** Underspecified ID - **Suggestion:** Document the ID format (UUID, opaque-string, numeric, ...) in JSDoc consistently. Currently only some occurrences have a doc (" account ID of the account being managed"), and the format isn't specified anywhere. - **Rationale:** Users have no way to know whether the SDK accepts `"acct-12345"`, `"abc...uuid"`, or an integer-as-string. The Go SDK's pattern of relying on type-level documentation isn't carried over. -### 34. `setting` field on `PatchPublicAccountUserPreferenceRequest` (covered in #29) +### 25. `setting` field on `PatchPublicAccountUserPreferenceRequest` (covered in #20) -### 35. `effectiveValue` vs `value` — undocumented distinction +### 26. `effectiveValue` vs `value` — undocumented distinction - **File:line:** `model.ts:303-345 (value) vs 351-393 (effectiveValue)` - **Category:** Misleading - **Suggestion:** Add a JSDoc explaining the relationship at the `Setting` type level. Currently the distinction is only documented as "The user-set value that goes into storage" (302) vs "The final effective value from server as per the policy evaluation" (350) — a reader has to read both blocks to understand they're a get/set asymmetry. - **Rationale:** This is a non-obvious feature where the user sets `value` but the server might return a different `effectiveValue` after applying policy. Worth a top-level doc, not just per-block. -### 36–38. Verb-tense action-as-noun naming +### 27–29. Verb-tense action-as-noun naming - **File:line:** `model.ts:288 (RestrictWorkspaceAdminsMessage), 102 (ClusterAutoRestartMessage), 294 (disableGovTagCreation field)` - **Category:** Verb-tense inconsistency @@ -301,65 +272,63 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ## Medium severity -### 39. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use +### 30. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use - **File:line:** `model.ts:94-96` - **Category:** Singular/plural mismatch - **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. -### 40. `*Public*` qualifier — redundant +### 31. `*Public*` qualifier — redundant - **File:line:** `model.ts:152, 157, 166, 262, 269, 278` - **Category:** Redundant qualifier -- **Suggestion:** Drop `Public` from request type names (and method names — #41). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Suggestion:** Drop `Public` from request type names (and method names — #32). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. - **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. -### 41. Method names: `getPublic*`, `patchPublic*` — redundant `Public` +### 32. Method names: `getPublic*`, `patchPublic*` — redundant `Public` - **File:line:** `client.ts:83, 112, 137, 346, 378, 409` - **Category:** Redundant qualifier + verbose - **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. -### 42. `patch*` vs `update*` — inconsistent action verb across SDK +### 33. `patch*` vs `update*` — inconsistent action verb across SDK - **File:line:** `client.ts:346, 378, 409` (use `patch`) - **Category:** Inconsistent action verbs - **Suggestion:** Pick one verb. `update` is the verb in `accountsettings/v1/client.ts` and `workspacesettings/v1/client.ts` for the equivalent operation; `patch` is used here. Cross-package consistency matters. - **Rationale:** Same operation (PATCH HTTP verb against a settings endpoint) named `update*` in the v1 packages and `patch*` in this v2 package. Users will look for `update*` first based on muscle memory. -### 43. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action +### 34. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action - **File:line:** `client.ts:378` - **Category:** Inconsistent + verbose - **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. - **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. -### 44–48. Long type names +### 35–37. Long type names -- **File:line:** `model.ts:225, 204, 269, 136, 147` +- **File:line:** `model.ts:225, 204, 269` - **Category:** Overly verbose - **Identifiers:** - `ListAccountUserPreferencesMetadataResponse` (42 chars) - `ListAccountUserPreferencesMetadataRequest` (41 chars) - `PatchPublicAccountUserPreferenceRequest` (39 chars) - - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` (64 chars) - - `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` (59 chars) -- **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`, drop nested-underscore style), names shorten naturally: `ListUserPreferencesMetadataResponse`, `WeekDayBasedSchedule`, `WindowStartTime`. +- **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. -### 49–51. `settingsMetadata` field name vs sibling list semantics +### 38–40. `settingsMetadata` field name vs sibling list semantics - **File:line:** `model.ts:194, 196, 225-227, 252-254` - **Category:** Singular/plural mismatch + field naming - **Suggestion:** On `ListAccountUserPreferencesMetadataResponse`, the field should be `userPreferencesMetadata`, not `settingsMetadata`. Currently the response field for "list of user preferences" is typed as `SettingsMetadata[]` and named `settingsMetadata` — which is technically the same metadata type but linguistically misleading. - **Rationale:** A consumer reading `resp.settingsMetadata` on a `ListAccountUserPreferencesMetadataResponse` will be confused why "settings" appears on a "user preferences" response. -### 52. `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` access stutters +### 41. `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` access stutters - **File:line:** `model.ts:13` - **Category:** Overly verbose enum access -- **Suggestion:** See #16. +- **Suggestion:** See #7–12. -### 53. `PreviewPhase` enum — mixed temporal/qualitative members +### 42. `PreviewPhase` enum — mixed temporal/qualitative members - **File:line:** `model.ts:11-27` - **Category:** Verb-tense / categorisation inconsistency @@ -367,53 +336,53 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. - **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. -### 54–55. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` +### 43–44. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` - **File:line:** `model.ts:30, 88, 94, 294` - **Category:** Acronym casing - **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. -### 56–57. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope +### 45–46. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope - **File:line:** `model.ts:322 (auto-cluster on a unified Setting), 337 (restrict-admins on Setting)` - **Category:** Field contradicting type domain - **Suggestion:** Either drop the `Workspace` suffix from `automaticClusterUpdateWorkspace` (the parent `Setting` type is scope-agnostic) or always include the scope (then `personalCompute` should be `personalComputeAccount`). - **Rationale:** Some payload discriminators mention scope (`automaticClusterUpdateWorkspace`), others don't (`personalCompute`, `restrictWorkspaceAdmins`). A reader can't predict the rule. -### 58. `canToggle?: boolean` on `ClusterAutoRestartMessage` +### 47. `canToggle?: boolean` on `ClusterAutoRestartMessage` - **File:line:** `model.ts:104` - **Category:** Generic field - **Suggestion:** `userCanToggle: boolean` or `togglePermitted: boolean`. "Toggle what?" is unclear from the field alone (presumably toggle the `enabled` field, but that's implicit). -### 59. `hours`, `minutes` with no timezone +### 48. `hours`, `minutes` with no timezone - **File:line:** `model.ts:148-149` - **Category:** Generic field name, missing constraint - **Suggestion:** Add doc specifying the time-zone interpretation, or rename `utcHours`/`utcMinutes` if UTC, or add a `timezone?: string` field. - **Rationale:** A "maintenance window start time" without timezone is ambiguous (workspace TZ? customer TZ? UTC?). -### 60–64. Overly verbose `effective*` discriminator names +### 49–53. Overly verbose `effective*` discriminator names - **File:line:** `model.ts:369, 374, 379, 384, 389` - **Category:** Overly verbose - **Suggestion:** Either drop the `effective` prefix on the discriminator value (the parent field is `effectiveValue`, so the prefix is redundant) or split into two top-level discriminated unions (`Setting.value: {$case: 'automaticClusterUpdateWorkspace', ...}` and `Setting.effectiveValue: {$case: 'automaticClusterUpdateWorkspace', ...}`). - **Rationale:** `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) is the longest discriminator in the package and stutters `effective`/`Effective` with its parent field name. -### 65–67. `name` (key) vs `displayName` (human name) — inverted intuition +### 54–56. `name` (key) vs `displayName` (human name) — inverted intuition - **File:line:** `model.ts:398, 411` - **Category:** Generic name + misleading - **Suggestion:** Rename `name` → `key`, then `displayName` → `name` (or `label`). - **Rationale:** Across most data-modelling traditions, `name` is the human-readable name and `key`/`id` is the identifier. This package inverts the convention. -### 68. `Url` vs `URL` vs `Link` +### 57. `Url` vs `URL` vs `Link` - **File:line:** `model.ts:404 (docsLink)`; `utils.ts:69, 71, 100, 103 (url)` - **Category:** Acronym casing inconsistency - **Suggestion:** `docsUrl` for parity with `request.url` already used elsewhere. "Link" is HTML-flavoured; "URL" is the data. -### 69. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name +### 58. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name - **File:line:** `model.ts:107` - **Category:** Field name verb-as-noun, overly verbose @@ -424,14 +393,14 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ## Low severity -### 70–77. Long enum values +### 59–66. Long enum values - **File:line:** `model.ts:13, 31, 39, 51, 67, 75, 56, 57, 85` - **Category:** Long enum value - **Identifiers:** `PREVIEW_PHASE_UNSPECIFIED` (24c), `ACCESS_POLICY_TYPE_UNSPECIFIED` (30c), `DAY_OF_WEEK_UNSPECIFIED` (23c), `WEEK_DAY_FREQUENCY_UNSPECIFIED` (30c), `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` (40c), `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) -- **Suggestion:** See #16–21. For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. +- **Suggestion:** See #7–12. For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. -### 78–81. Undocumented abbreviations in JSDoc +### 67–70. Undocumented abbreviations in JSDoc - **File:line:** `model.ts:79, 83` - **Category:** Cryptic abbreviation @@ -439,82 +408,78 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Spell out in the JSDoc. - **Rationale:** Users reading the IDE tooltip will see "WS admins to create OBO tokens for all SPs" without expansions. -### 82–84. Reserved-word adjacency: `value`, `type`, `name` +### 71–73. Reserved-word adjacency: `value`, `type`, `name` - **File:line:** `model.ts` passim - **Category:** Reserved-word risk -- **Suggestion:** See #25–27. +- **Suggestion:** See #16–18. -### 85–86. Acronym casing notes +### 74–75. Acronym casing notes - **File:line:** `model.ts:153, 78` - **Category:** Acronym casing - **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). -### 87. `setting?: UserPreference` doc mismatch +### 76. `setting?: UserPreference` doc mismatch -- Already covered in #29; flagged again here for the JSDoc inconsistency (`model.ts:275` field is "setting" but type is "UserPreference"). +- Already covered in #20; flagged again here for the JSDoc inconsistency (`model.ts:275` field is "setting" but type is "UserPreference"). -### 88. `disable_gov_tag_creation` wire key +### 77. `disable_gov_tag_creation` wire key - **File:line:** `model.ts:624, 959` - **Category:** Cryptic abbreviation (server-controlled) - **Suggestion:** N/A — wire format is fixed. Note for documentation. -### 89. `restrict_tokens_and_job_run_as` enum string value +### 78. `restrict_tokens_and_job_run_as` enum string value - **File:line:** `model.ts:85` - **Category:** Wire value - **Suggestion:** N/A — wire-fixed. -### 90. `IntegerMessage` misleading in JS +### 79. `IntegerMessage` misleading in JS - **File:line:** `model.ts:171-173` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 91. Nested `.value.value` +### 80. Nested `.value.value` - **File:line:** `model.ts:305, 99` - **Category:** Singular naming collision -- **Suggestion:** See #25. +- **Suggestion:** See #16. -### 92–93. Long discriminator strings +### 81–82. Long discriminator strings - **File:line:** `model.ts:327-329, 374` - **Category:** Long string identifier -- **Suggestion:** See #30, #60. +- **Suggestion:** See #21, #49–53. -### 94–96. Vague field names +### 83–85. Vague field names - **File:line:** `model.ts:103 (enabled), 137 (frequency), 289 (status)` - **Category:** Vague - **Suggestion:** Add domain context: `clusterRestartEnabled`, `restartFrequency`, `workspaceAdminRestrictionStatus`. - **Rationale:** Inside their parent types the meaning is somewhat clear but auto-complete shows only the field name, which is generic. -### 97. `patch*` vs `update*` +### 86. `patch*` vs `update*` -- See #42. +- See #33. -### 98. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" +### 87. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" - **File:line:** `model.ts:160-161` - **Category:** Misleading - **Suggestion:** Use the same vocabulary as the type — "preference" for user-preference endpoints. -### 99. `PreviewPhase` UNSPECIFIED doc — two meanings +### 88. `PreviewPhase` UNSPECIFIED doc — two meanings - **File:line:** `model.ts:12-13` - **Category:** Empty/ambiguous default - **Doc:** "Default value. Indicates the preview phase is unknown or the setting is not a feature preview." - **Suggestion:** Use two separate enum values (one for "unknown phase", one for "not a preview at all") or pick one definition. -### 100. `ClusterAutoRestartMessage_EnablementDetails` — long type - -- See #12. - -### 101–103. Double-negative / passive booleans on `EnablementDetails` +### 89–91. Double-negative / passive booleans on `EnablementDetails` - **File:line:** `model.ts:121, 123, 125` - **Category:** Misleading / cognitive load @@ -522,21 +487,21 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Phrase positively where possible: `availableForEnterpriseTier?: boolean`, `availableForEntitlement?: boolean`, `forceEnabledByComplianceMode?: boolean`. Double-negatives ("unavailable for non-enterprise") slow comprehension. - **Rationale:** "Unavailable for non-enterprise tier" requires the reader to parse two negatives ("un-" and "non-") to conclude "this is only available for enterprise". Worth one extra second of think-time on every field access. -### 104. Cross-package `Dbfs` casing +### 92. Cross-package `Dbfs` casing - **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) - **Category:** Cross-package acronym casing - **Suggestion:** Note for the cross-package audit, not actionable here. -### 105. `host` — generic class field +### 93. `host` — generic class field - **File:line:** `client.ts:54` - **Category:** Generic - **Suggestion:** `baseUrl` (consistent with `fetch` API conventions). "Host" can mean DNS host, host machine, etc. -### 106. `BETA` member adjacent to `PUBLIC_PREVIEW` +### 94. `BETA` member adjacent to `PUBLIC_PREVIEW` -- See #53. +- See #42. --- @@ -550,20 +515,13 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess 2. **`Setting`, `SettingsMetadata`, `UserPreference` are all underspecific.** The package theme is "settings v2", but the central types use the bare word "Setting" without qualification. This is the single biggest naming risk in the package — a user importing `Setting` from `@databricks/sdk-settings/v2` will clash with any application-level `Setting` type in seconds. -3. **Four layers of proto plumbing leak into the TS surface.** - 1. Underscore-bearing nested type names (`X_Y_Z`). - 2. `*Message` suffix on every payload wrapper. - 3. Redundant `X_X_UNSPECIFIED` enum prefixes. - 4. The whole `value`/`effectiveValue` get/set asymmetry exists at the proto level for forward-compat, but in TS it could be modelled as two narrower types. - Each layer individually is defensible as "1:1 with proto"; together they make the package feel like generated boilerplate. - -4. **Cross-package duplication of `*Message` types is a real type-system hazard.** `RestrictWorkspaceAdminsMessage` declared in both `settings/v2/model.ts` and `workspacesettings/v1/model.ts` is the most concrete example. A function in user code typed as `(m: RestrictWorkspaceAdminsMessage) => void` will accept one import but not the other — and the TS error message will say "Type 'RestrictWorkspaceAdminsMessage' is not assignable to type 'RestrictWorkspaceAdminsMessage'" with no further hint. Hoisting these to a shared module is the highest-ROI fix. +3. **Cross-package duplication of `*Message` types is a real type-system hazard.** `RestrictWorkspaceAdminsMessage` declared in both `settings/v2/model.ts` and `workspacesettings/v1/model.ts` is the most concrete example. A function in user code typed as `(m: RestrictWorkspaceAdminsMessage) => void` will accept one import but not the other — and the TS error message will say "Type 'RestrictWorkspaceAdminsMessage' is not assignable to type 'RestrictWorkspaceAdminsMessage'" with no further hint. Hoisting these to a shared module is the highest-ROI fix. -5. **`patch` vs `update` cross-package inconsistency.** The v1 SDKs use `update*`; the v2 SDK uses `patch*`. Same wire verb (PATCH HTTP). The verb mismatch will trip muscle-memory across the surface. +4. **`patch` vs `update` cross-package inconsistency.** The v1 SDKs use `update*`; the v2 SDK uses `patch*`. Same wire verb (PATCH HTTP). The verb mismatch will trip muscle-memory across the surface. -6. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. +5. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. -7. **Field-vs-discriminator name divergence on `value`.** A consumer constructing a `Setting` writes: +6. **Field-vs-discriminator name divergence on `value`.** A consumer constructing a `Setting` writes: ``` { name: 'restrict_workspace_admins', value: { $case: 'restrictWorkspaceAdmins', @@ -576,9 +534,9 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ``` — same expressivity, half the typing. -8. **`name` field's role swings.** On `Setting`/`UserPreference`/`SettingsMetadata` it is the *key* of the setting (used in URL paths). On most other Databricks resources `name` is the human-readable label. The inverted convention is a small but real footgun. +7. **`name` field's role swings.** On `Setting`/`UserPreference`/`SettingsMetadata` it is the *key* of the setting (used in URL paths). On most other Databricks resources `name` is the human-readable label. The inverted convention is a small but real footgun. -9. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. +8. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. --- diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index bfda206c..5f0c64b8 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -28,14 +28,14 @@ The package name `statementexecution` is reasonable in isolation, but the SDK opening the marketplace sees four packages whose names overlap heavily and has to read every one to pick the right tool. See finding #1. -**Total weird names flagged:** 50 +**Total weird names flagged:** 48 ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 27 | +| High | 11 | +| Medium | 25 | | Low | 10 | | Observation | 4 | @@ -47,49 +47,37 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** `sqlstatements`, `sqlexec`, or `warehouseexec` — anything that signals "SQL on a SQL Warehouse". If staying with `statementexecution`, every type name should keep its `Statement*` prefix and the package docstring should call out the contrast with `queryexecution` and `commandexecution`. - **Rationale:** Naming should disambiguate. Today the four packages are differentiable only by URL prefix and resource. Compare to e.g. `clusterlibraries` vs `clusterpolicies`: both clearly cluster-scoped but each names its sub-resource. -### 2. `StatementStatus_State` proto-style nested enum — `src/v1/model.ts:84` -- **Why weird:** Type name uses an underscore — `StatementStatus_State` — and a comment-level ESLint disable (`@typescript-eslint/naming-convention -- Proto-style nested enum name.`). The name is a literal proto/Java carry-over: in proto-3 a nested enum on `StatementStatus` would be `StatementStatus.State`; in TypeScript there is no nested-enum syntax, so the codegen flattens with an underscore. The result is the only identifier in the file (other than `ExternalLink_HttpHeadersEntry`) that uses an underscore. The convention disagrees with every other type in the package. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/Java-style names), 17 (inconsistent — every other type is PascalCase without underscores). -- **Suggested name:** `StatementState`. The parent type `StatementStatus` already carries the "Status" semantics; the nested `State` collapses cleanly to a top-level `StatementState` without any loss of meaning. The `StatementStatus.state` field would then be `state: StatementState`. -- **Rationale:** TypeScript has no protobuf-nested-enum syntax. Forcing one with an underscore creates a name that violates ESLint and looks foreign at every use site. The same flaw exists in many SDK packages and is generator-wide. - -### 3. `ExternalLink_HttpHeadersEntry` proto-style nested message — `src/v1/model.ts:376` -- **Why weird:** Same pathology as #2: underscore-separated, ESLint-disabled "proto-style nested message name". The identifier is the only one in the file besides `StatementStatus_State` that uses an underscore separator. The convention disagrees with every other type in the package and forces a per-symbol ESLint disable comment. -- **Category:** 4 (underscores), 14 (proto-style). -- **Suggested name:** `ExternalLinkHttpHeadersEntry` (drop the underscore) or fold into the surrounding type per the wire shape. -- **Rationale:** TypeScript has no protobuf-nested-message syntax. Forcing one with an underscore creates a name that violates ESLint and looks foreign at every use site. Generator-wide. - -### 4. `ServiceErrorCode` enum members duplicate generic HTTP/gRPC vocabulary — `src/v1/model.ts:53` +### 2. `ServiceErrorCode` enum members duplicate generic HTTP/gRPC vocabulary — `src/v1/model.ts:53` - **Why weird:** The enum lists 14 generic codes: `UNKNOWN`, `INTERNAL_ERROR`, `TEMPORARILY_UNAVAILABLE`, `IO_ERROR`, `BAD_REQUEST`, `SERVICE_UNDER_MAINTENANCE`, `WORKSPACE_TEMPORARILY_UNAVAILABLE`, `DEADLINE_EXCEEDED`, `CANCELLED`, `RESOURCE_EXHAUSTED`, `ABORTED`, `NOT_FOUND`, `ALREADY_EXISTS`, `UNAUTHENTICATED`. These are direct gRPC `google.rpc.Code` carry-overs. The SDK already has a canonical apierror codes module (`packages/databricks/src/apierror/codes/`); duplicating them inside one package's enum is wrong on three axes: it's redundant, it pulls gRPC vocabulary into a HTTP/JSON SDK, and it pollutes per-package type surfaces. - **Category:** 1 (vague — `IO_ERROR`, `ABORTED` give no context), 2 (redundant: `ServiceErrorCode.ABORTED` reads `ServiceErrorCode = ABORTED` twice), 12 (duplicate concept — apierror module owns these codes), 14 (gRPC-style names). - **Suggested name:** Eliminate the enum. Map the wire code into the canonical `apierror/codes` enum; expose `ServiceError.errorCode` as that type. - **Rationale:** Per-package error-code enums diverge over time. The SDK already commits to canonical codes elsewhere; this package should use them. -### 5. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` +### 3. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` - **Why weird:** Enum name is `Disposition` — a generic noun (`Content-Disposition` header? business "disposition"?). The single sentinel value `FETCH_DISPOSITION_UNSPECIFIED` reveals the intended scope: this is *fetch* disposition. The enum members `INLINE` and `EXTERNAL_LINKS` are recognisable, but the type name doesn't say "fetch" or "result". A reader who skims `disposition?: Disposition` in `ExecuteStatementRequest` won't know it means "where the result data goes". - **Category:** 1 (vague — "Disposition" of what?), 2 (redundant: `FETCH_DISPOSITION_UNSPECIFIED` reveals the missing word), 8 (the sentinel reveals the missing prefix). - **Suggested name:** `ResultDisposition` or `FetchDisposition`. Matching field rename: `resultDisposition?: ResultDisposition`. - **Rationale:** The enum member's `FETCH_*` prefix is a code smell — when a sentinel value carries a qualifier the type name omits, the type name is under-qualified. -### 6. `Format` enum is dangerously generic — `src/v1/model.ts:46` -- **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #5: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). +### 4. `Format` enum is dangerously generic — `src/v1/model.ts:46` +- **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #3: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). - **Category:** 1 (vague — `Format` is the most generic possible name), 2 (the sentinel `FORMAT_UNSPECIFIED` reveals the gap), 10 (reserved-word-ish — `format` is a builtin function name in many ecosystems), 15 (generic name losing meaning at use sites). -- **Suggested name:** `ResultFormat`. Same pattern as #5. +- **Suggested name:** `ResultFormat`. Same pattern as #3. - **Rationale:** Top-level enum names should self-describe at use sites. `result.format: Format` reads as "format format"; `result.format: ResultFormat` reads correctly. The collision risk for a single-word `Format` import is high. -### 7. `TimeoutAction` enum members `CONTINUE`/`CANCEL` are too generic — `src/v1/model.ts:77` +### 5. `TimeoutAction` enum members `CONTINUE`/`CANCEL` are too generic — `src/v1/model.ts:77` - **Why weird:** A small enum with three values: `TIMEOUT_ACTION_UNSPECIFIED`, `CONTINUE`, `CANCEL`. The two real values are bare English verbs that don't say *what* they continue or cancel. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously (`CONTINUE`) or is cancelled (`CANCEL`). The relationship between the verbs and the timeout is invisible at the type level. - **Category:** 1 (vague — `CONTINUE` what?), 14 (gRPC/proto-style upper-case verbs), 15 (generic verb-only names). -- **Suggested name:** `OnTimeout.ContinueAsync` and `OnTimeout.CancelExecution` (or rename the enum to `OnTimeout` to match the field `onWaitTimeout`). Drop the `TIMEOUT_ACTION_UNSPECIFIED` sentinel per #14. +- **Suggested name:** `OnTimeout.ContinueAsync` and `OnTimeout.CancelExecution` (or rename the enum to `OnTimeout` to match the field `onWaitTimeout`). Drop the `TIMEOUT_ACTION_UNSPECIFIED` sentinel per #12. - **Rationale:** Enum members should self-document; bare verbs require the reader to chase the field's JSDoc. -### 8. `ColumnTypeName` enum embeds `USER_DEFINED_TYPE` — `src/v1/model.ts:37` +### 6. `ColumnTypeName` enum embeds `USER_DEFINED_TYPE` — `src/v1/model.ts:37` - **Why weird:** The enum represents SQL base types: `BOOLEAN`, `BYTE`, ..., `MAP`, `CHAR`, `NULL`, `USER_DEFINED_TYPE`. The last value breaks the pattern: every other member is a recognisable SQL type name; `USER_DEFINED_TYPE` is a meta-category covering all UDT instances. It also creates a redundant `ColumnTypeName.USER_DEFINED_TYPE` — "type" appears twice in the qualified name. - **Category:** 2 (redundant: `*TypeName.*TYPE` repeats "type"), 13 (verb-tense — every other member is a noun like `INT`; this one is past-participial), 16 (field-vs-type-domain — UDT isn't a "base data type" per the JSDoc). - **Suggested name:** Either `UDT` or `UserDefined` (drop `_TYPE`). Or split: keep base types in the enum; carry UDT info in `typeText`. - **Rationale:** When one enum member breaks the pattern of the others, it signals an enum that does two jobs. -### 9. `GetResultDataRequest` vs. `GetStatementResultRequest` — `src/v1/model.ts:381,390` +### 7. `GetResultDataRequest` vs. `GetStatementResultRequest` — `src/v1/model.ts:381,390` - **Why weird:** Two near-identical request types, one with `chunkIndex` and one without. Their names break apart suspiciously: - `GetResultDataRequest` fetches *one chunk* of the result data. - `GetStatementResultRequest` polls the entire statement (`statementId` only). @@ -99,25 +87,25 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** `GetResultChunkRequest` (carries `chunkIndex`) + `GetStatementRequest` (polls by `statementId`). Methods: `getResultChunk` + `getStatement`. This matches the URL paths `/result/chunks/{chunkIndex}` and `/{statementId}`. - **Rationale:** Type names should mirror the resource being addressed. The wire makes the distinction explicit; the TS surface obscures it. -### 10. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:219` -- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. Combine with #9: there are now two `getResult*` methods, one of which doesn't actually fetch results (it polls), and one of which does (`getResultData`). +### 8. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:219` +- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. Combine with #7: there are now two `getResult*` methods, one of which doesn't actually fetch results (it polls), and one of which does (`getResultData`). - **Category:** 6 (misleading — name implies result-fetch, primary purpose is poll), 12 (duplicate concept — both methods carry "Result" but mean different things), 17 (inconsistent verb usage — `cancel`, `execute`, `getStatementResult`, `getResultData`). - **Suggested name:** `getStatement` (matches the URL path `/{statementId}`). The Go SDK calls this `GetStatement`. The result is *part* of the response; foregrounding it in the method name misleads. - **Rationale:** The Databricks API docs name the operation "Get statement" (https://docs.databricks.com/api/workspace/statementexecution/getstatement). The TS SDK should match. -### 11. `getResultData` method asymmetric with `getStatementResult` — `src/v1/client.ts:183` -- **Why weird:** Companion to #10. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. +### 9. `getResultData` method asymmetric with `getStatementResult` — `src/v1/client.ts:183` +- **Why weird:** Companion to #8. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. - **Category:** 1 (vague — "result data" is too generic), 6 (misleading — drops the chunk-indexing semantic), 17 (asymmetric with sibling method). - **Suggested name:** `getResultChunk` (or `getStatementResultChunk` to match Go). Field rename: `chunkIndex` stays. - **Rationale:** Names should match the official API where possible. Compare to `getStatementResultChunkN` in the Go SDK. -### 12. `Client` class name — `src/v1/client.ts:43` +### 10. `Client` class name — `src/v1/client.ts:43` - **Why weird:** A class literally named `Client`, re-exported as `Client` from `index.ts:3`. A user importing this from `@databricks/sdk-statementexecution` and another `Client` from `@databricks/sdk-queryexecution` will collide on the namespace. Identical to `queryexecution.md` Finding #9. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `StatementExecutionClient`. - **Rationale:** Repeated SDK-wide pattern. -### 13. `dataArray` field on `ResultData` — `src/v1/model.ts:422` +### 11. `dataArray` field on `ResultData` — `src/v1/model.ts:422` - **Why weird:** Field name `dataArray` on a type already called `ResultData`. The two `data` tokens stack: `resultData.dataArray`. The JSDoc explains it carries a `JSON_ARRAY` formatted payload, so the name is gesturing at the wire format. But the type name is the *outer* wrapper, so saying "data" inside "Data" reads as redundant. - **Category:** 1 (vague — `data`, `array` both generic), 12 (duplicate concept — `Data.dataArray`), 20 (type-suffix tautology). - **Suggested name:** `rows` (matches the SQL semantics: each entry of the array is a row). Or rename the outer type to `ResultChunk` so `chunk.data` is meaningful. @@ -125,38 +113,32 @@ to read every one to pick the right tool. See finding #1. ## Medium severity -### 14. Every enum carries a `*_UNSPECIFIED` sentinel — `src/v1/model.ts:41, 47, 78, 85` +### 12. Every enum carries a `*_UNSPECIFIED` sentinel — `src/v1/model.ts:41, 47, 78, 85` - **Why weird:** All four "open" enums carry `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, and `STATE_UNSPECIFIED`. These are protobuf-style "default value" sentinels. In TypeScript, absence is represented by `undefined` (the fields are already optional). The sentinels add noise to enum members and force callers to handle a meaningless value. - **Category:** 11 (trivial value — no behaviour), 14 (proto-style), 18 (long enum value — e.g. `FETCH_DISPOSITION_UNSPECIFIED` is 28 chars). - **Suggested name:** Drop all `*_UNSPECIFIED` members. The field's `| undefined` already encodes "not set". - **Rationale:** Generator-wide pattern; same as `commandexecution.md` Finding #4. -### 15. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` -- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #26 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. +### 13. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` +- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #22 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. - **Category:** 13 (verb-tense inconsistency), 17 (US/UK spelling inconsistency for "cancel"). - **Suggested name:** Pick one cancel spelling. The wire is `CANCELED` (single-l) per this enum and `CANCELLED` per `ServiceErrorCode`. Resolve at wire level. - **Rationale:** Twin spellings of the same English word in adjacent enums in the same file is a maintenance hazard. Compare `StatementStatus_State.CANCELED` to `ServiceErrorCode.CANCELLED`. -### 16. `httpHeaders` typed as `Record` contradicts `ExternalLink_HttpHeadersEntry` — `src/v1/model.ts:349` -- **Why weird:** Field type is `Record`, but the same file defines an `ExternalLink_HttpHeadersEntry` type for the same wire map. Two different surface representations of the same wire shape live side by side, and the underscore-named entry type is never referenced. -- **Category:** 12 (duplicate concept), 17 (inconsistent — Entry type vs Record). -- **Suggested name:** Pick one representation. Either drop the `ExternalLink_HttpHeadersEntry` export or use it consistently. -- **Rationale:** Parallel encodings of the same map type force readers to pick one and ignore the other. - -### 17. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` +### 14. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` - **Why weird:** A user importing from both `statementexecution` and `queryexecution` finds a `statementId` field on responses from both packages. In `statementexecution` it identifies the SQL Statement Execution submission. In `queryexecution` (a published-dashboard query) the JSDoc explicitly says "The statement_id should be identical to data_token in SuccessStatus and PendingStatus" — i.e. it's an audit copy, not a primary key. The same name means different things in two adjacent packages. - **Category:** 12 (duplicate concept — same name, different meaning), 19 (underspecified ID — what kind of statement?). - **Suggested name:** Keep `statementId` here (primary identifier); rename the audit-only copy in `queryexecution` (see `queryexecution.md` Finding #14). - **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. -### 18. `warehouseId` field — `src/v1/model.ts:158` -- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #39. +### 15. `warehouseId` field — `src/v1/model.ts:158` +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #35. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. -### 19. `statement` field name is the package name — `src/v1/model.ts:153` -- **Why weird:** The request type `ExecuteStatementRequest` carries a field literally called `statement`. The package name is `statementexecution`. The class name is `Client` (per #12). So a call reads: +### 16. `statement` field name is the package name — `src/v1/model.ts:153` +- **Why weird:** The request type `ExecuteStatementRequest` carries a field literally called `statement`. The package name is `statementexecution`. The class name is `Client` (per #10). So a call reads: ```ts client.executeStatement({statement: 'SELECT 1', warehouseId: '...'}) ``` @@ -165,180 +147,175 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** Rename the field to `sql` (or `query` if not colliding with `queryexecution`). The wire is `statement`, so a marshaller maps `sql -> statement`. - **Rationale:** The package, the class, and the field shouldn't all spell the same word three times. -### 20. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` +### 17. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` - **Why weird:** Two parallel "limit" fields; `rowLimit` has no default mentioned; `byteLimit` mentions a "100 GiB default if not explicitly set" for `EXTERNAL_LINKS` disposition. The asymmetric defaults aren't captured by the types. JSDoc encodes them; users have to read both. - **Category:** 16 (field-vs-domain — domain has implicit defaults the type doesn't show), 17 (asymmetric defaults). - **Suggested name:** Names are fine; consolidate JSDoc so both fields document defaults symmetrically. - **Rationale:** Pair-fields should have parallel JSDoc structure. -### 21. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` +### 18. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` - **Why weird:** Field name is `parameters`. Element type is `StatementParameter`. The element name is more specific (statement parameter) than the field (parameters). At the JSDoc level, the field describes "parameter markers" — which is yet a third name for the same concept. So users see: `parameters` (field) vs `StatementParameter` (element type) vs "parameter markers" (docs). Pick one vocabulary. - **Category:** 12 (duplicate concept — three names for one idea), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the element type to `Parameter` (less qualified than field) or rename the field to `statementParameters`. The wire shape probably matters; pick the less verbose option. - **Rationale:** Multiple synonyms for one concept burns reader attention. -### 22. `queryTags` field on `ExecuteStatementRequest` — `src/v1/model.ts:326` +### 19. `queryTags` field on `ExecuteStatementRequest` — `src/v1/model.ts:326` - **Why weird:** Field is `queryTags`, element type is `QueryTag`. The user is *executing a statement*, but the metadata tags are called *query* tags. There's no `Query` type in this package; the prefix `Query` here is a Databricks billing/observability term (queries get tagged for analytics). For a TS user who hasn't seen the bigger picture, the mismatch between `executeStatement` and `QueryTag[]` reads as inconsistent. - **Category:** 12 (duplicate concept — `statement` vs `query`), 17 (inconsistent vocabulary). - **Suggested name:** Rename to `tags` + `Tag` (the surrounding context already says "statement", so the qualifier is redundant). Wire mapping can keep `query_tags`. - **Rationale:** Tagging in this SDK is a cross-cutting concern; `Tag` would be the natural top-level name. Within the statement-execution context, `tags` suffices. -### 23. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` +### 20. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` - **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `APIError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `APIError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. - **Category:** 12 (duplicate concept — overlaps `APIError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). -- **Suggested name:** `StatementError` (or fold into `APIError` extensions). The errorCode should reuse the canonical apierror codes per #4. +- **Suggested name:** `StatementError` (or fold into `APIError` extensions). The errorCode should reuse the canonical apierror codes per #2. - **Rationale:** Multiple error type shapes per SDK is a cognitive tax. -### 24. `StatementStatus.sqlState` field — `src/v1/model.ts:522` +### 21. `StatementStatus.sqlState` field — `src/v1/model.ts:522` - **Why weird:** Field name `sqlState`. The JSDoc says "SQLSTATE error code returned when the statement execution fails." The all-caps acronym SQLSTATE is the SQL-standard 5-character status code (e.g. `42S22`). The TS field uses camelCase `sqlState`. Compare to elsewhere in the SDK where SQL is also lowercased (`sqlExpression`, `sqlText`). This is consistent SDK-wide. - **Category:** 3 (acronym casing — `SQL` becoming `sql` is debatable; SDK has settled on lowercase, so this matches). - **Suggested name:** Keep `sqlState`. Flagged for completeness. - **Rationale:** TS convention varies on multi-letter acronyms; google-ts-style says lowercase initial; SDK follows the convention. -### 25. `ServiceError.errorCode` field — `src/v1/model.ts:474` +### 22. `ServiceError.errorCode` field — `src/v1/model.ts:474` - **Why weird:** Field name stutters with type name: `ServiceError.errorCode`. "Error" appears at both levels. A reader sees `err.errorCode` and wonders if there's a non-error code too. - **Category:** 20 (type-suffix tautology), 12 (duplicate concept). - **Suggested name:** `code` (since the type is already `ServiceError`). - **Rationale:** Stutter — `error.error*` — is a code smell. -### 26. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` +### 23. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` - **Why weird:** Same English word, two spellings, in two enums in the same file. `CANCELLED` is British; `CANCELED` is American. The wire chose differently for the two enums; the SDK mirrors the wire. End users have to remember "cancel with one or two Ls". -- **Category:** 13 (spelling/tense inconsistency — see #15), 17 (asymmetric pair). +- **Category:** 13 (spelling/tense inconsistency — see #13), 17 (asymmetric pair). - **Suggested name:** Normalise upstream. If kept, document the spelling difference in `@databricks/sdk-databricks` README. - **Rationale:** The spelling difference is invisible in casual scanning but breaks copy/paste. -### 27. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` +### 24. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` - **Why weird:** `waitTimeout?: string` with JSDoc explaining it must be formatted as `"Ns"` where N is 0 or 5-50. So a *typed string* with a private DSL inside. Users will write `"5s"` and hope, or worse: `5` (number, won't compile). The wire format is a proto Duration, but the TS surface could parse `number` (seconds) or `Duration` (ms) and emit `Ns`. - **Category:** 1 (vague — `string`-typed numeric), 6 (misleading — a "timeout" with arbitrary string content), 14 (proto/Go-style — Duration carry-over). - **Suggested name:** Keep `waitTimeout` but change the type to `number` (seconds) and let the marshaller produce `Ns`. Or `Duration` from `@databricks/sdk-core/wkt`. - **Rationale:** Letting users pass arbitrary strings into a numeric field is a contract violation waiting to happen. -### 28. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` +### 25. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` - **Why weird:** Field is `onWaitTimeout`, type is `TimeoutAction`. The two names don't share the prefix `Wait*` even though they're tightly coupled. A reader sees `onWaitTimeout?: TimeoutAction` and has to chase the docs to learn the enum members are about wait-timeouts. - **Category:** 17 (asymmetric field/type naming), 12 (duplicate concept — `Wait`/`Timeout` overloaded). -- **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #7, `OnTimeout`. +- **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #5, `OnTimeout`. - **Rationale:** Field/type symmetry is a strong signal. -### 29. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` +### 26. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` - **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. - **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). - **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. - **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. -### 30. `nextChunkInternalLink` field — `src/v1/model.ts:128` +### 27. `nextChunkInternalLink` field — `src/v1/model.ts:128` - **Why weird:** The field is documented as: "an absolute `path` to be joined with your `$DATABRICKS_HOST`, and should be treated as an opaque link. This is an alternative to using `next_chunk_index`." The word "Internal" is doing a lot here — it's not internal as in "private to Databricks"; it means "internal-link, as opposed to a presigned cloud link". The naming is opaque without the JSDoc. - **Category:** 1 (vague — "Internal" is too generic), 5 (cryptic — needs JSDoc to decode). - **Suggested name:** `nextChunkRelativePath` (matches its semantics: a path relative to the workspace host). Or `nextChunkUrlPath`. - **Rationale:** Names should not lean on JSDoc to communicate the *kind* of identifier. -### 31. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +### 28. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` - **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. - **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). - **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). - **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. -### 32. `totalChunkCount`, `totalRowCount`, `totalByteCount` triple — `src/v1/model.ts:453, 457, 462` +### 29. `totalChunkCount`, `totalRowCount`, `totalByteCount` triple — `src/v1/model.ts:453, 457, 462` - **Why weird:** Three parallel `total*Count` fields. Each ends in `Count` (singular noun) and starts with `total` (qualifier). The triple is consistent but verbose — `totalChunkCount` is 16 characters for an integer count. - **Category:** 7 (overly verbose), 8 (redundant suffix — `Count` is implied for an integer). - **Suggested name:** `chunks` / `rows` / `bytes` (drop `total*Count` and let the integer-ness be implicit). Or keep `total*Count` and document that the per-chunk `*Count` fields are partial sums. - **Rationale:** Verbose triplets across a type can usually be compressed. -### 33. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` +### 30. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` - **Why weird:** `ResultManifest.chunks` is an array of `ChunkInfo`; `totalChunkCount` is `chunks.length`. The two carry the same information; on the wire there is a sender-receiver invariant, but TS users can compute one from the other. The naming gives no hint of the redundancy. - **Category:** 12 (duplicate concept), 1 (vague — both fields are about the same property). - **Suggested name:** Drop `totalChunkCount`; users compute via `chunks?.length`. - **Rationale:** Two fields that mean the same thing should not both be public. -### 34. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` +### 31. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` - **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. - **Category:** 16 (field-vs-format contradicts domain when format differs). - **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. - **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. -### 35. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` -- **Why weird:** Companion to #34. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. +### 32. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +- **Why weird:** Companion to #31. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. - **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. - **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. -### 36. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` +### 33. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` - **Why weird:** Two `execute*` functions in the same file, one wraps retry/rate-limit policy and one does the actual HTTP. Same as `queryexecution.md` Finding #21. - **Category:** 1, 12, 17. - **Suggested name:** `runWithPolicies` + `sendHttpRequest`. - **Rationale:** Generator-wide. -### 37. `buildHttpRequest` helper — `src/v1/utils.ts:96` +### 34. `buildHttpRequest` helper — `src/v1/utils.ts:96` - **Why weird:** "Build" implies builder pattern; this is a 16-line object literal. Same as `queryexecution.md` Finding #22. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest` or inline. -### 38. `readAll` stream-drain helper — `src/v1/utils.ts:40` -- **Why weird:** Generic verb. Same as `queryexecution.md` Finding #23. -- **Category:** 1, 5. -- **Suggested name:** `drainStream`. - -### 39. Every field on every request type is optional — `src/v1/model.ts` (every interface) +### 35. Every field on every request type is optional — `src/v1/model.ts` (every interface) - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). - **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. -### 40. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` -- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #17) suggests this is the wrong abstraction. +### 36. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` +- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #14) suggests this is the wrong abstraction. - **Category:** 6 (misleading — type is overloaded), 12 (duplicate concept — two operations). - **Suggested name:** Keep `StatementResponse` but document that it's polymorphic. Or split into `StatementSubmissionResponse` + `StatementStateResponse`. - **Rationale:** Shared response types are acceptable but should be flagged for documentation. ## Low severity -### 41. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +### 37. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` - **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. - **Category:** 17 (acceptable asymmetry). - **Suggested name:** Keep. -### 42. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:108, 111, 116` +### 38. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:108, 111, 116` - **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. - **Category:** 12 (duplicate concept — three types carry the same fields). - **Suggested name:** Extract `ChunkMetrics` shared interface. - **Rationale:** Trio-replicated types are a tell. -### 43. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` +### 39. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` - **Why weird:** `typeText` is "the full SQL type specification" (e.g. `DECIMAL(10,2)`). `typeName` is the base type name (`DECIMAL`). The pair is intentional but the names don't make the relationship obvious — `typeText` and `typeName` sound interchangeable. - **Category:** 17 (asymmetric pair — `Text` vs `Name`), 1 (vague — `Text` of what?). - **Suggested name:** `typeSql` (the wire SQL text) + `typeBase` (the base type) — but the wire is canonical, so keep names. Document the relationship. -### 44. `position` field on `ColumnInfo` — `src/v1/model.ts:139` +### 40. `position` field on `ColumnInfo` — `src/v1/model.ts:139` - **Why weird:** Top-level field literally `position` with JSDoc "The ordinal position of the column (starting at position 0)." `position` is generic. `ordinalPosition` (matches the JSDoc) or `columnIndex` would be more precise. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `ordinalPosition` or `index`. -### 45. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` +### 41. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` - **Why weird:** A string field whose JSDoc says "Indicates the date-time that the given external link will expire and becomes invalid". Two issues: the name `expiration` is ambiguous (an expiry timestamp? a TTL?), and the type is `string` (presumably ISO8601 — the JSDoc doesn't say). A reader can't tell from the type or name how to interpret the value. - **Category:** 1 (vague), 6 (misleading — could be TTL). - **Suggested name:** `expiresAt` (ISO8601 timestamp) — matches modern JS/TS convention. -### 46. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +### 42. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` - **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. - **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). - **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 47. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +### 43. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` - **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. - **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). - **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. -### 48. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` +### 44. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` - **Why weird:** Three single-word fields on a single type, all `string | undefined`. The JSDoc explains: name is the marker name; value is the substituted text; type is the SQL type. The names work fine in this context but are maximally generic — `name`, `value`, `type` could mean anything. The `type` field collides with the TS keyword visually (though `type` isn't actually reserved in object-position). - **Category:** 1 (vague), 10 (reserved-word collision — `type` is contextually meaningful), 15 (generic names). - **Suggested name:** `parameterName`, `parameterValue`, `sqlType` — but local names are fine inside a clear-context type. Flagged for completeness. -### 49. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` -- **Why weird:** Generic key-value pair. Same as #48 but for tags. `tagKey` + `tagValue` are common alternatives. +### 45. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` +- **Why weird:** Generic key-value pair. Same as #44 but for tags. `tagKey` + `tagValue` are common alternatives. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** Acceptable in context. -### 50. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 46. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** Generic name. Same as `queryexecution.md` Finding #25. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -353,7 +330,7 @@ to read every one to pick the right tool. See finding #1. fallback to empty string is a silent-failure pattern. Names are fine; the fallback semantics are wrong. -### O-2. `*_UNSPECIFIED` sentinels exist on every enum — see #14. +### O-2. `*_UNSPECIFIED` sentinels exist on every enum — see #12. - Generator-wide; the fix is in codegen. ### O-3. Statement IDs share a vocabulary with `queryexecution` and `queryhistory`. @@ -389,13 +366,15 @@ The two packages model semantically distinct operations (general SQL Statement Execution vs Lakeview-dashboard query lifecycle) but share enough vocabulary (`Statement`, `Query`, `Cancel`, `Execute`, `Status`) that a user importing both will be confused. The fix is at the naming/package level (see #1) and -the cross-package vocabulary alignment (#17, #26). +the cross-package vocabulary alignment (#14, #23). --- ## Themes -1. **Proto/Go leakage.** `StatementStatus_State`, `ExternalLink_HttpHeadersEntry`, `*_UNSPECIFIED` sentinels, `ServiceErrorCode` mimicking `google.rpc.Code`. Every leakage point requires an ESLint disable or a special-casing in zod. Generator-wide. +1. **Per-package error-code enum.** `ServiceErrorCode` mimics `google.rpc.Code` inside a single API package, parallel to the canonical `apierror/codes` module. Generator-wide; the fix is to map wire codes through the canonical apierror layer. 2. **Word stutter.** `ServiceError.errorCode`, `ResultData.dataArray`, `*ResultData` vs `*StatementResult`, `executeStatement` / `getStatementResult` / `statement` field. The wire shape doesn't help here; the TS surface could compress. 3. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). -4. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. +4. **Package-name competition.** `statementexecution` lives alongside `queryexecution`, `commandexecution`, and `queries` — four near-synonymous names for related-but-distinct execution surfaces. +5. **`*_UNSPECIFIED` sentinels.** Proto-default-value sentinels carried through to TS where `undefined` already encodes "not set". Generator-wide. +6. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index a5d94ebe..a6c9280b 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -3,15 +3,15 @@ **Path:** `packages/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 21 +**Total weird names flagged:** 14 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 6 | +| High | 5 | +| Medium | 5 | | Low | 2 | -| Observation | 4 | +| Observation | 2 | ## High severity @@ -27,43 +27,19 @@ - **Suggested name:** `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, `ListSystemSchemasRequest`. - **Rationale:** TS convention names request DTOs with a `Request` suffix; verb-phrase nouns mislead. This mirrors the same audit finding in every other generated package. -### 3. `DisableSystemSchema_Response` — `src/v1/model.ts:13` -- **Why weird:** Underscore in identifier (proto-style nested type). Requires `@typescript-eslint/naming-convention` to be disabled. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** `DisableSystemSchemaResponse`. -- **Rationale:** TS strict-type-checked flags the underscore; the disable means the name is fighting the language. - -### 4. `EnableSystemSchema_Response` — `src/v1/model.ts:25` -- **Why weird:** Same as #3 — underscore identifier requiring `eslint-disable`. -- **Category:** 4. -- **Suggested name:** `EnableSystemSchemaResponse`. -- **Rationale:** Identical to #3. - -### 5. `ListSystemSchemas_Response` — `src/v1/model.ts:43` -- **Why weird:** Underscore identifier (proto-style nested type). Requires `eslint-disable` for `@typescript-eslint/naming-convention`. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** `ListSystemSchemasResponse`. -- **Rationale:** Same as the other two `_Response` types; underscore is a proto leak that does not survive TS lint without a disable. - -### 6. `SystemSchemaInfo` — `src/v1/model.ts:53` +### 3. `SystemSchemaInfo` — `src/v1/model.ts:53` - **Why weird:** `Info` is a generic, content-free suffix on the package's central domain entity. This is *the* system schema — it should just be `SystemSchema`. The `Info` suffix is on the vague-suffix list in `typescript.mdc`. It also infects the field name (`schemas: SystemSchemaInfo[]`) which awkwardly reads as "an array of info". - **Category:** 1 (vague `Info`), 8 (redundant type suffix). - **Suggested name:** `SystemSchema`. - **Rationale:** `SystemSchema` is the noun consumers think about. `schemas: SystemSchema[]` reads cleanly; `schemas: SystemSchemaInfo[]` does not. -### 7. `SystemSchemaInfo.state: string` — `src/v1/model.ts:60` +### 4. `SystemSchemaInfo.state: string` — `src/v1/model.ts:60` - **Why weird:** Typed as `string` despite the doc enumerating six concrete values (`AVAILABLE | ENABLE_INITIALIZED | ENABLE_COMPLETED | DISABLE_INITIALIZED | UNAVAILABLE | MANAGED`). This is the package's only enum-shaped field and the only piece of state the consumer reads back, yet it ships as a stringly-typed value. Every other package in the SDK exposes such fields as TS enums. The comment "An empty string means the system schema is available and ready for opt-in" further muddles things — it contradicts `AVAILABLE` being one of the listed values. - **Category:** 16 (field type contradicts the documented domain), 6 (misleading — doc says enum, type says `string`). - **Suggested name:** Introduce `SystemSchemaState` enum with members `Available | EnableInitialized | EnableCompleted | DisableInitialized | Unavailable | Managed` and type the field `state: SystemSchemaState`. - **Rationale:** Almost certainly a generator/upstream-API miss; the wire surface is enum-shaped and should round-trip through a TS enum. Worth raising upstream. -### 8. `EnableSystemSchema.catalogName` lowercase doc-prefix — `src/v1/model.ts:20-21` -- **Why weird:** JSDoc on `catalogName` reads `the catalog for which the system schema is to enabled in` — both grammatically broken ("to enabled" instead of "to be enabled") *and* starts with a lowercase letter, unlike every other field's doc in the file. Naming-adjacent because the doc is the only place that explains what `catalogName` means versus `metastoreId`. -- **Category:** Observation / 15 (the field name `catalogName` is generic in a struct that also carries `metastoreId` and `schema`; doc carries the disambiguation burden). -- **Suggested name:** Keep `catalogName` (it's correct) but rewrite the doc to a proper sentence: "Name of the catalog in which the system schema should be enabled." -- **Rationale:** Naming includes the docstring; a broken doc on the only field that distinguishes `EnableSystemSchema` from `DisableSystemSchema` is a meaningful naming-quality issue. - -### 9. `schema` field on every request/response — `src/v1/model.ts:7,17,55` +### 5. `schema` field on every request/response — `src/v1/model.ts:7,17,55` - **Why weird:** Field is bare `schema: string` on `DisableSystemSchema`, `EnableSystemSchema`, and `SystemSchemaInfo`. Doc on the first two says "Full name of the system schema" while the doc on `SystemSchemaInfo` (model.ts:54) says "Name of the system schema". So the same field name carries two different semantics (full-qualified vs short name) across two types that ship in the same module. Also collides with the type name (`SystemSchema`) and the package name (`systemschemas`), making greps unhelpful. - **Category:** 1 (vague — what kind of "schema"?), 6 (misleading — same field name, different meaning), 19 (underspecified id). - **Suggested name:** Pick one of `schemaName` / `systemSchemaName` / `name` and apply it consistently. If the wire is `schema` (string), keep the wire and rename the TS surface; the marshaller already handles the gap for other fields. @@ -71,71 +47,57 @@ ## Medium severity -### 10. `DisableSystemSchema.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` +### 6. `DisableSystemSchema.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` - **Why weird:** Marked optional, but `client.ts:75` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchema.metastoreId`, `DisableSystemSchema.schema`, `EnableSystemSchema.schema`, `ListSystemSchemas.metastoreId`. - **Category:** 6 (misleading optionality), 16 (field type contradicts domain — these are mandatory path params). - **Suggested name:** Keep names; change type to non-optional. (Out of scope for a *naming* audit, but the optionality leaks into how the names should be interpreted.) - **Rationale:** Path-required fields must be required. Treating them as optional weakens the contract; the name `metastoreId` reads as "the metastore id" but the type says "you can omit this". -### 11. `SystemSchemaInfo.schema: string` (required) vs `EnableSystemSchema.schema: string | undefined` (optional) — `src/v1/model.ts:55,17` +### 7. `SystemSchemaInfo.schema: string` (required) vs `EnableSystemSchema.schema: string | undefined` (optional) — `src/v1/model.ts:55,17` - **Why weird:** Same field name, opposite optionality, same module. The reader has to keep two mental versions of `schema` in their head. - **Category:** 17 (inconsistency in field shape between sibling types). -- **Suggested name:** Same as #9 — rename one or both and unify optionality where possible. +- **Suggested name:** Same as #5 — rename one or both and unify optionality where possible. - **Rationale:** Symmetry across request/response pairs improves readability; identical names with diverging contracts do not. -### 12. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` +### 8. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate intent. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; flagged for cross-SDK consistency since the same constant appears in every generated client. -### 13. `Client` — `src/v1/client.ts:42` +### 9. `Client` — `src/v1/client.ts:42` - **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `SystemSchemasClient`. - **Rationale:** Forces consumers to alias on import (`import {Client as SystemSchemasClient}`) if they ever combine clients. Every generated package has this issue; flagged for consistency. -### 14. `ListSystemSchemas.maxResults` doc semantics — `src/v1/model.ts:31-36` +### 10. `ListSystemSchemas.maxResults` doc semantics — `src/v1/model.ts:31-36` - **Why weird:** Field is named `maxResults` but the doc describes three semantically distinct modes (0 = server default, >0 = bounded, <0 = error) and one quirky default (not set = "all", "not recommended"). The name "maxResults" implies an upper bound, not a tri-state control. Same pattern in every other List request, but here the doc highlights how overloaded the name is. - **Category:** 6 (misleading — name suggests a single integer cap), 1 (vague). - **Suggested name:** `pageSize` (matching most modern paginated APIs) and let the value 0 mean "server default". Drop the negative-error branch entirely. - **Rationale:** Worth raising upstream; the JS SDK's name should describe what consumers do, not the wire's quirks. -### 15. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:182` +## Low severity + +### 11. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:182` - **Why weird:** `listSystemSchemasIter` (client.ts:182) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). - **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. - **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. -## Low severity - -### 16. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 12. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ by a single `Http` infix, handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). - **Rationale:** Same pattern across the SDK; collected for the cross-package sweep. -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** The word `Options` is reused across the SDK for many unrelated things (`ClientOptions`, `CallOptions`, etc.); within this file `Options` is also imported from `@databricks/sdk-core/api` (line 3). -- **Category:** 1 (vague suffix), 17 (collision with imported `Options`). -- **Suggested name:** `HttpCallContext` — it's an internal bag of args, not user-tunable options. -- **Rationale:** Distinguish internal context bags from user-tunable option structs. - ## Observations -### 18. `flattenQueryParams` — `src/v1/utils.ts:123` -Function is exported but has no caller within this package — `client.ts` does its own simple query-param assembly (`client.ts:144-150`). Dead surface area imported from the generator's shared template. -- **Category:** Observation / 11 (unused public helper). -- Recommend either removing the export or documenting why it ships per-package. - -### 19. `readAll` — `src/v1/utils.ts:40` -Reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Internal helper, low impact. - -### 20. Action-verb consistency in `Client` +### 13. Action-verb consistency in `Client` Methods are `disable`, `enable`, `list` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. -### 21. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod -The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), a type suffix (`...Schema_Response`), the package name (`systemschemas`), and a library term (zod's `Schema`). Five overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. +### 14. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod +The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), the package name (`systemschemas`), and a library term (zod's `Schema`). Multiple overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. - **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). ## Domain glossary diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index 7357ffe6..de867fb4 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -169,8 +169,7 @@ ### Index (index.ts) -- Re-exports `Client`, 8 enums (5 flat + 2 underscored — see findings 1 and - 2), and 41 interfaces. +- Re-exports `Client`, 8 enums, and 41 interfaces. --- @@ -178,11 +177,11 @@ | Severity | Count | | --------------------- | ----- | -| High | 16 | +| High | 13 | | Medium | 26 | -| Low / SDK-wide note | 11 | +| Low / SDK-wide note | 10 | | Pass / acceptable | 10 | -| **Total findings** | **63** | +| **Total findings** | **59** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -191,70 +190,7 @@ findings.) ## Findings -### 1. `OptionSpec_OauthStage` / `OptionSpec_OptionType` underscore in type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) - -**Symbols:** `OptionSpec_OauthStage` (model.ts:229), -`OptionSpec_OptionType` (model.ts:242). - -**Issue:** Both enum type names carry an internal `_` to model nested-enum -namespacing from `.proto` source. The Google TS Style Guide § 5.3 mandates -`UpperCamelCase` for type names with no underscores; the project's lint rule -(`.agent/rules/typescript.mdc` § *Identifiers*) enforces the same. The file -suppresses the lint for each (model.ts:228, 241): - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name. -export enum OptionSpec_OauthStage { ... } -``` - -The suppression comment is the audit signal: lint disagrees, and the -suppression is hard-coded across the SDK for every proto-nested enum. - -**Note on inconsistency *within this file*:** the file uses *both* the flat -form (`ColumnTypeName`, `DataSourceFormat`, `SecurableKind`, `SecurableType`, -`SseEncryptionAlgorithm`, `TableType` — all flat) and the underscored form -(`OptionSpec_*`). Same generator, same package, two conventions in the same -file. - -**Suggested:** `OauthStage` and `OptionType` if the parent `OptionSpec` -namespace can be dropped; or fold to `OptionSpecOauthStage` / -`OptionSpecOptionType` to keep the parent prefix without the underscore. -Cross-reference `featurestore.PublishSpec_PublishMode` for the same problem. -**Flag for SDK-wide generator cleanup.** - ---- - -### 2. `CreateTable_PropertiesEntry` / `TableInfo_PropertiesEntry` / `UpdateTable_PropertiesEntry` / `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` underscore in type names — category 4 (Underscores in TS identifiers) - -**Symbols:** -- `CreateTable_PropertiesEntry` (model.ts:394). -- `TableInfo_PropertiesEntry` (model.ts:844). -- `UpdateTable_PropertiesEntry` (model.ts:931). -- `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` (model.ts:444). -- The response wrappers `DeleteTable_Response`, `DeleteTableConstraint_Response`, - `UpdateTable_Response`, `ListTables_Response`, `ListTableSummaries_Response`, - `TableExists_Response` (model.ts:417, 432, 937, 594, 556, 767). - -**Issue:** Twelve type names carry `_` to mirror proto-message namespacing. -Each is preceded by an `eslint-disable-next-line` comment. The Google TS -Style Guide § 5.3 mandates `UpperCamelCase` for type names with no -underscores; the project's lint rule (`.agent/rules/typescript.mdc` § -*Identifiers*) enforces the same. Every one of these exports requires a -hard-coded lint suppression to keep the proto-nested form. - -**Suggested:** fold the parent prefix without the underscore — e.g. -`CreateTablePropertiesEntry`, `TableInfoPropertiesEntry`, -`DeleteTableResponse`, etc. Wire payloads are unaffected; only the TS -identifier changes. - -**Coordinate with generator.** Cross-reference -`onlinetables.OnlineTableSpec_ContinuousSchedulingPolicy` (audited in -`onlinetables.md` finding 2) for the same family of wrapper-with-underscore -issues. - ---- - -### 3. `DeltaRuntimePropertiesKvPairs` type name vs. `deltaRuntimePropertiesKvpairs` field name acronym-casing mismatch — category 3 (Acronym casing inconsistencies) +### 1. `DeltaRuntimePropertiesKvPairs` type name vs. `deltaRuntimePropertiesKvpairs` field name acronym-casing mismatch — category 3 (Acronym casing inconsistencies) **Symbols:** - Type: `DeltaRuntimePropertiesKvPairs` (model.ts:438) — `KvPairs` (capital @@ -295,7 +231,7 @@ cleanup.** --- -### 4. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) +### 2. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) **Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:438). @@ -310,7 +246,7 @@ self-describing). --- -### 5. `OptionSpec_OauthStage` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 3. `OptionSpec_OauthStage` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) **Symbol:** `OptionSpec_OauthStage.OAUTH_STAGE_UNSPECIFIED` (model.ts:230). @@ -333,7 +269,7 @@ placeholder with the type name as its prefix" pattern. --- -### 6. `OptionSpec_OptionType` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 4. `OptionSpec_OptionType` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) **Symbol:** `OptionSpec_OptionType.OPTION_TYPE_UNSPECIFIED` (model.ts:243) and every other value (`OPTION_BOOLEAN`, `OPTION_NUMBER`, etc.). @@ -354,10 +290,9 @@ spec.type === OptionSpec_OptionType.OPTION_BOOLEAN // "the OptionType is OPTION `OptionType.Boolean` would be far cleaner. The wire form is fixed; the TS identifier can be split (`Boolean = 'OPTION_BOOLEAN'`). -**Suggested:** drop `OPTION_` prefix on the TS identifiers. Combined with -finding 1's rename (`OptionType` instead of `OptionSpec_OptionType`): +**Suggested:** drop `OPTION_` prefix on the TS identifiers: ```ts -export enum OptionType { +export enum OptionSpec_OptionType { Unspecified = 'OPTION_TYPE_UNSPECIFIED', Boolean = 'OPTION_BOOLEAN', Number = 'OPTION_NUMBER', @@ -368,12 +303,12 @@ export enum OptionType { --- -### 7. `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` member value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 5. `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` member value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) **Symbol:** `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` (model.ts:204). 37 characters. -**Issue:** Identical pattern to findings 5 and 6 — the leading +**Issue:** Identical pattern to findings 3 and 4 — the leading `SSE_ENCRYPTION_ALGORITHM_` segment duplicates the enum name. The other two values (`AWS_SSE_S3`, `AWS_SSE_KMS`) do not include the prefix, so only `UNSPECIFIED` is overly verbose. @@ -383,7 +318,7 @@ Wire string remains. --- -### 8. SSE acronym casing in `SseEncryptionAlgorithm` / `SseEncryptionDetails` — category 3 (Acronym casing inconsistencies) +### 6. SSE acronym casing in `SseEncryptionAlgorithm` / `SseEncryptionDetails` — category 3 (Acronym casing inconsistencies) **Symbols:** `SseEncryptionAlgorithm` (model.ts:203), `SseEncryptionDetails` (model.ts:724), `sseEncryptionDetails` (field name in @@ -405,7 +340,7 @@ etc.) but is worth flagging for anyone reviewing this file fresh. --- -### 9. `SseEncryptionDetails.awsKmsKeyArn` is the only field that names the cloud — category 3 (Acronym casing inconsistencies) and category 16 (Field contradicting type domain) +### 7. `SseEncryptionDetails.awsKmsKeyArn` is the only field that names the cloud — category 3 (Acronym casing inconsistencies) and category 16 (Field contradicting type domain) **Symbol:** `SseEncryptionDetails.awsKmsKeyArn` (model.ts:731). @@ -430,7 +365,7 @@ the upstream `.proto`.) --- -### 10. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) +### 8. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) **Symbol:** `SecurableType` (model.ts:182). @@ -438,7 +373,7 @@ the upstream `.proto`.) `connections/v1/model.ts:109`, and at least two other audited packages. Each definition is the same enum with the same 17 values. Five copies of the same enum across the SDK. The values overlap with `SecurableKind` (see -finding 11) but are at a different level of granularity (a `TABLE` of +finding 9) but are at a different level of granularity (a `TABLE` of `SecurableType` maps to ~50 `TABLE_*` `SecurableKind` values). Within the `tables` package, `SecurableType` only appears on @@ -451,7 +386,7 @@ who already has a `TableInfo` knows it's a `TABLE`. --- -### 11. `SecurableKind` is a 70+ value enum with `TABLE_` prefix on most values — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 9. `SecurableKind` is a 70+ value enum with `TABLE_` prefix on most values — category 2 (Redundant enum prefixes) and category 18 (Long enum values) **Symbol:** `SecurableKind` (model.ts:81) — 70+ members, 50+ with `TABLE_` prefix. @@ -485,33 +420,7 @@ through any field on this package's types. --- -### 12. `SecurableKind` lint suppressions for SCREAMING_SNAKE_CASE — category 4 (Underscores in TS identifiers) - -**Symbol:** Every value in `SecurableKind` (model.ts:82–179). - -**Issue:** All values are SCREAMING_SNAKE_CASE with underscores in TS -identifiers. The wire string and the TS identifier are the same value -(`'TABLE_DELTA'`, etc.). Even at default lint settings the file does *not* -suppress these — meaning the lint rule is permissive about enum *values* -but not enum *names* (findings 1 and 2). This is an enforcement gap. - -**Suggested (TS side only, no wire change):** -```ts -export enum SecurableKind { - TableStandard = 'TABLE_STANDARD', - TableExternal = 'TABLE_EXTERNAL', - TableDelta = 'TABLE_DELTA', - // ... -} -``` - -**Pass with note** if the project policy chose to accept SCREAMING_SNAKE for -enum *values* as a wire-compatibility shortcut. **Flag for SDK-wide -cleanup** otherwise. - ---- - -### 13. `ColumnTypeName.TABLE_TYPE` and `TABLEREF_TYPE` collide with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 10. `ColumnTypeName.TABLE_TYPE` and `TABLEREF_TYPE` collide with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) **Symbols:** `ColumnTypeName.TABLE_TYPE` (model.ts:31), `ColumnTypeName.TABLEREF_TYPE` (model.ts:32). @@ -541,7 +450,7 @@ reference type? table-ref?), and the field has no JSDoc to disambiguate. --- -### 14. `ColumnTypeName.USER_DEFINED_TYPE` and `TIMESTAMP_NTZ` cryptic value forms — category 5 (Cryptic abbreviations) and category 18 (Long enum values) +### 11. `ColumnTypeName.USER_DEFINED_TYPE` and `TIMESTAMP_NTZ` cryptic value forms — category 5 (Cryptic abbreviations) and category 18 (Long enum values) **Symbols:** `ColumnTypeName.USER_DEFINED_TYPE` (model.ts:24), `ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25). @@ -559,7 +468,7 @@ reference type? table-ref?), and the field has no JSDoc to disambiguate. --- -### 15. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) +### 12. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) **Symbols:** `DataSourceFormat` values (model.ts:36–78). @@ -588,7 +497,7 @@ if (format === 'MYSQL_FORMAT' || format === 'POSTGRESQL_FORMAT') {} // suffix --- -### 16. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) +### 13. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) **Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:46), `DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:73). @@ -607,7 +516,7 @@ consistent. **Not a per-package fix.** --- -### 17. `TableType` enum — category 18 (Long enum values) — *pass with note* +### 14. `TableType` enum — category 18 (Long enum values) — *pass with note* **Symbol:** `TableType` (model.ts:209) — 9 values: `MANAGED`, `EXTERNAL`, `VIEW`, `MATERIALIZED_VIEW`, `STREAMING_TABLE`, `MANAGED_SHALLOW_CLONE`, @@ -636,7 +545,7 @@ streaming-table label.) --- -### 18. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) +### 15. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) **Symbol:** `SecurableKind.TABLE_DELTASHARING_OPEN_DIR_BASED` (model.ts:96). @@ -653,7 +562,7 @@ constraint), **flag for documentation cleanup.** --- -### 19. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) +### 16. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) **Symbols:** - `SecurableKind.TABLE_FEATURE_STORE` (model.ts:104) and @@ -675,7 +584,7 @@ JSDoc tags (only inline comments). Consumers code-completing on --- -### 20. `fullNameArg` field name across multiple request types — category 14 (Go/Java-style names) and category 5 (Cryptic abbreviations) +### 17. `fullNameArg` field name across multiple request types — category 14 (Go/Java-style names) and category 5 (Cryptic abbreviations) **Symbols:** `fullNameArg` on `DeleteTable` (model.ts:413), `DeleteTableConstraint` (model.ts:421), `GetTable` (model.ts:519), @@ -706,7 +615,7 @@ type (e.g. `DeleteTable.fullName` is obviously a path argument because --- -### 21. `TableExists` request type is a verb-as-noun — category 6 (Misleading names) +### 18. `TableExists` request type is a verb-as-noun — category 6 (Misleading names) **Symbol:** `TableExists` (model.ts:761) request type. @@ -725,7 +634,7 @@ but resolves the verb-as-noun reading). --- -### 22. Request type naming pattern is inconsistent (`CreateTable`, `DeleteTable`, no `Request` suffix) — category 17 (Inconsistent action verbs) and category 20 (Type-suffix tautology) +### 19. Request type naming pattern is inconsistent (`CreateTable`, `DeleteTable`, no `Request` suffix) — category 17 (Inconsistent action verbs) and category 20 (Type-suffix tautology) **Symbols:** All request types in this package (`CreateTable`, `DeleteTable`, `DeleteTableConstraint`, `GetTable`, `ListTables`, `ListTableSummaries`, @@ -747,7 +656,7 @@ SDK, same generator, two conventions.) --- -### 23. `CreateTable` and `TableInfo` and `UpdateTable` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) +### 20. `CreateTable` and `TableInfo` and `UpdateTable` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) **Symbols:** `CreateTable` (model.ts:322, 38 fields), `TableInfo` (model.ts:772, 36 fields), `UpdateTable` (model.ts:857, 37 fields). @@ -784,7 +693,7 @@ messages map 1:1). --- -### 24. `CreateTable.fullName` is server-generated — category 6 (Misleading names) +### 21. `CreateTable.fullName` is server-generated — category 6 (Misleading names) **Symbol:** `CreateTable.fullName?: string | undefined` (model.ts:360). JSDoc: "Full name of table, in form of __catalog_name__.__schema_name__.__table_name__". @@ -802,12 +711,12 @@ all server-output but exposed on the input type. Same critique applies to `UpdateTable`. **Suggested:** mark with JSDoc `@readonly` and add a sentence "Output only; -ignored on input." Or restructure types (finding 23). **Coordinate with +ignored on input." Or restructure types (finding 20). **Coordinate with generator.** --- -### 25. `CreateTable.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) +### 22. `CreateTable.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) **Symbol:** `CreateTable.tableConstraints?: TableConstraint[] | undefined` (model.ts:352). JSDoc: "List of table constraints. Note: this field is not @@ -827,7 +736,7 @@ might or might not honour it depending on the deployment. --- -### 26. `CreateTable.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 23. `CreateTable.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) **Symbol:** `CreateTable.enablePredictiveOptimization?: string | undefined` (model.ts:356). Same field on `TableInfo` (model.ts:806) and `UpdateTable` @@ -851,7 +760,7 @@ same field. --- -### 27. `CreateTable.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) +### 24. `CreateTable.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) **Symbol:** `CreateTable.dataAccessConfigurationId?: string | undefined` (model.ts:362). 28 chars. Same field on `TableInfo` (model.ts:812) and @@ -870,7 +779,7 @@ choice. **Pass with note.** --- -### 28. `CreateTable.accessPoint` (S3-specific) leaks AWS into a generic-looking field — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 25. `CreateTable.accessPoint` (S3-specific) leaks AWS into a generic-looking field — category 6 (Misleading names) and category 16 (Field contradicting type domain) **Symbol:** `CreateTable.accessPoint?: string | undefined` (model.ts:381). JSDoc: "The AWS access point to use when accesing s3 for this external @@ -884,12 +793,12 @@ or GCP will not know to skip the field. **Suggested:** rename to `awsAccessPoint` or `s3AccessPoint` (matches the JSDoc). -**Cross-reference:** `SseEncryptionDetails.awsKmsKeyArn` (finding 9) takes +**Cross-reference:** `SseEncryptionDetails.awsKmsKeyArn` (finding 7) takes the AWS prefix; `accessPoint` does not. Inconsistent within this file. --- -### 29. `CreateTable.browseOnly` is server-output but appears in request — category 6 (Misleading names) +### 26. `CreateTable.browseOnly` is server-output but appears in request — category 6 (Misleading names) **Symbol:** `CreateTable.browseOnly?: boolean | undefined` (model.ts:383). JSDoc: "Indicates whether the principal is limited to retrieving metadata @@ -906,7 +815,7 @@ to `TableInfo` only. --- -### 30. `ListTables.omitColumns` / `omitProperties` / `omitUsername` use negative form — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) +### 27. `ListTables.omitColumns` / `omitProperties` / `omitUsername` use negative form — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) **Symbols:** `ListTables.omitColumns?: boolean` (model.ts:582), `omitProperties?: boolean` (model.ts:584), `omitUsername?: boolean` @@ -928,11 +837,11 @@ time.** (Note: `omitUsername` is also a singular — "username", not "usernames" — even though the JSDoc lists three fields (owner, updated_by, created_by). -Should be `omitUsernames`. See finding 31.) +Should be `omitUsernames`. See finding 28.) --- -### 31. `ListTables.omitUsername` singular but covers three fields — category 9 (Singular/plural mismatch) +### 28. `ListTables.omitUsername` singular but covers three fields — category 9 (Singular/plural mismatch) **Symbol:** `ListTables.omitUsername?: boolean | undefined` (model.ts:586). JSDoc: "Whether to omit the username of the table (e.g. owner, updated_by, @@ -947,7 +856,7 @@ changing the wire string. **Coordinate with protocol team.** --- -### 32. `ListTables.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* +### 29. `ListTables.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* **Symbol:** `ListTables.maxResults?: number | undefined` (model.ts:578), JSDoc: "Maximum number of tables to return. If not set, all the tables @@ -960,7 +869,7 @@ deprecated. The naming is fine; the API behaviour is the issue. --- -### 33. `ListTableSummaries.schemaNamePattern` / `tableNamePattern` vs. `ListTables.schemaName` field-name inconsistency — category 17 (Inconsistent action verbs) +### 30. `ListTableSummaries.schemaNamePattern` / `tableNamePattern` vs. `ListTables.schemaName` field-name inconsistency — category 17 (Inconsistent action verbs) **Symbols:** `ListTableSummaries.schemaNamePattern` (model.ts:535) and `ListTableSummaries.tableNamePattern` (model.ts:540) vs. `ListTables.schemaName` @@ -984,7 +893,7 @@ input side). --- -### 34. `ListTableSummaries_Response.tables` returns `TableSummary[]` not `TableInfo[]` — category 6 (Misleading names) and category 15 (Generic field names losing meaning) +### 31. `ListTableSummaries_Response.tables` returns `TableSummary[]` not `TableInfo[]` — category 6 (Misleading names) and category 15 (Generic field names losing meaning) **Symbol:** `ListTableSummaries_Response.tables?: TableSummary[] | undefined` (model.ts:558). @@ -1001,7 +910,7 @@ expose the shape difference at the field name. --- -### 35. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` / `VolumeDependency` / `SecretDependency` defined in three packages — category 12 (Duplicate concepts) +### 32. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` / `VolumeDependency` / `SecretDependency` defined in three packages — category 12 (Duplicate concepts) **Symbols:** - This file: `Dependency` (model.ts:453), `DependencyList` (model.ts:473), @@ -1021,7 +930,7 @@ from each service package. **Strong SDK-wide cleanup.** --- -### 36. `Dependency.value` field name is generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 33. `Dependency.value` field name is generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `Dependency.value` (model.ts:454). Type is the discriminated union. @@ -1048,7 +957,7 @@ naming conventions for the same generator pattern.** --- -### 37. `EncryptionDetails.encryptionDetailsType` repeats the type name as the field name — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) +### 34. `EncryptionDetails.encryptionDetailsType` repeats the type name as the field name — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) **Symbol:** `EncryptionDetails.encryptionDetailsType` (model.ts:489). @@ -1061,7 +970,7 @@ encDetails.encryptionDetailsType?.$case when `encDetails.kind?.$case` or `encDetails.details?.$case` would suffice. -Compare to `Dependency.value` (finding 36) — same pattern, generic name. +Compare to `Dependency.value` (finding 33) — same pattern, generic name. Compare to `TableConstraint.constraint` — same pattern, name is the type *concept* without `Type` suffix. @@ -1069,7 +978,7 @@ Compare to `TableConstraint.constraint` — same pattern, name is the type --- -### 38. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) +### 35. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) **Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:261). JSDoc: "Ordinal position of column (starting at position 0)." @@ -1082,7 +991,7 @@ or `columnIndex`. **Pass with note** — the field is short and conventional. --- -### 39. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — six `type*` fields — category 12 (Duplicate concepts) +### 36. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — six `type*` fields — category 12 (Duplicate concepts) **Symbols:** `ColumnInfo.typeText` (model.ts:258), `typeName` (model.ts:259), `typePrecision` (model.ts:262), `typeScale` (model.ts:263), @@ -1120,7 +1029,7 @@ export interface ColumnInfo { --- -### 40. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) +### 37. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) **Symbols:** `RowFilter.functionName?: string` (model.ts:689), `RowFilter.inputColumnNames?: string[]` (model.ts:694), @@ -1140,7 +1049,7 @@ deprecation note. --- -### 41. `ColumnMask.usingArguments` vs `RowFilter.inputArguments` action-verb difference — category 17 (Inconsistent action verbs) +### 38. `ColumnMask.usingArguments` vs `RowFilter.inputArguments` action-verb difference — category 17 (Inconsistent action verbs) **Symbols:** `ColumnMask.usingArguments?: PolicyFunctionArgument[]` (model.ts:293), `RowFilter.inputArguments?: PolicyFunctionArgument[]` @@ -1156,7 +1065,7 @@ But the verb prefix differs: `using…` for masks, `input…` for filters. --- -### 42. `PolicyFunctionArgument.arg` field name is too short — category 1 (Vague/generic) +### 39. `PolicyFunctionArgument.arg` field name is too short — category 1 (Vague/generic) **Symbol:** `PolicyFunctionArgument.arg` (model.ts:662). Discriminated union of `column` / `constant`. @@ -1168,15 +1077,15 @@ name. Consumer writes: if (positionalArg.arg?.$case === 'column') { ... } ``` -Compare to `Dependency.value` (finding 36) and -`EncryptionDetails.encryptionDetailsType` (finding 37) — same pattern, +Compare to `Dependency.value` (finding 33) and +`EncryptionDetails.encryptionDetailsType` (finding 34) — same pattern, three different naming conventions. The `arg` here is the most cryptic. **Suggested:** `argument` (full word) or `kind`. --- -### 43. `PrimaryKeyConstraint.childColumns` vs `ForeignKeyConstraint.childColumns` semantic mismatch — category 6 (Misleading names) and category 12 (Duplicate concepts) +### 40. `PrimaryKeyConstraint.childColumns` vs `ForeignKeyConstraint.childColumns` semantic mismatch — category 6 (Misleading names) and category 12 (Duplicate concepts) **Symbols:** `PrimaryKeyConstraint.childColumns?: string[]` (model.ts:680), `ForeignKeyConstraint.childColumns?: string[]` @@ -1200,7 +1109,7 @@ from upstream. --- -### 44. `PrimaryKeyConstraint.timeseriesColumns` vs `ColumnMask.usingColumnNames` plural-vs-singular inconsistency — category 9 (Singular/plural mismatch) +### 41. `PrimaryKeyConstraint.timeseriesColumns` vs `ColumnMask.usingColumnNames` plural-vs-singular inconsistency — category 9 (Singular/plural mismatch) **Symbols:** `PrimaryKeyConstraint.timeseriesColumns?: string[]` (model.ts:682), `ColumnMask.usingColumnNames?: string[]` (model.ts:287), @@ -1222,7 +1131,7 @@ one. **Flag at port time.** --- -### 45. `ForeignKeyConstraint.rely` boolean is cryptic — category 5 (Cryptic abbreviations) +### 42. `ForeignKeyConstraint.rely` boolean is cryptic — category 5 (Cryptic abbreviations) **Symbol:** `ForeignKeyConstraint.rely?: boolean | undefined` (model.ts:508). JSDoc: "True if the constraint is RELY, false or unset if NORELY." @@ -1237,7 +1146,7 @@ with protocol team.** --- -### 46. `OptionSpec.isCopiable` typo or unusual spelling — category 5 (Cryptic abbreviations) and category 6 (Misleading names) +### 43. `OptionSpec.isCopiable` typo or unusual spelling — category 5 (Cryptic abbreviations) and category 6 (Misleading names) **Symbol:** `OptionSpec.isCopiable?: boolean | undefined` (model.ts:649). JSDoc: "Indicates whether an option should be displayed with copy button @@ -1252,7 +1161,7 @@ are "copyable" or "copy-able". The generator picked the less-common form --- -### 47. `OptionSpec` has 9 `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* +### 44. `OptionSpec` has 9 `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `OptionSpec.isRequired` (model.ts:635), `OptionSpec.isSecret` (model.ts:637), `OptionSpec.isHidden` (model.ts:639), @@ -1270,7 +1179,7 @@ correctly may want a richer type. **Note for upstream.**) --- -### 48. `ConditionalDisplay.dependsOnOption` vs `hiddenWhenValues` field naming asymmetry — category 17 (Inconsistent action verbs) +### 45. `ConditionalDisplay.dependsOnOption` vs `hiddenWhenValues` field naming asymmetry — category 17 (Inconsistent action verbs) **Symbols:** `ConditionalDisplay.dependsOnOption?: string` (model.ts:307), `ConditionalDisplay.hiddenWhenValues?: string[]` (model.ts:313). @@ -1289,7 +1198,7 @@ the type sees them as unrelated. The pair would be cleaner as e.g. --- -### 49. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 46. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` (model.ts:480). JSDoc: "Whether predictive optimization should be enabled @@ -1297,14 +1206,14 @@ for this object and objects under it." **Issue:** The type's *purpose* is to indicate whether PO is enabled. The field name `value` says nothing about that. The type is also a `string` -(not a `boolean`) — same problem as finding 26. +(not a `boolean`) — same problem as finding 23. **Suggested:** rename `value` → `enabled` (boolean) or `state` (matching the JSDoc's "enabled" sense). **Coordinate with protocol team.** --- -### 50. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) +### 47. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) **Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` (model.ts:482), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` @@ -1323,11 +1232,11 @@ flat form is wire-faithful. --- -### 51. `TableConstraint.constraint` and `TableConstraint` discriminated-union shape — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) +### 48. `TableConstraint.constraint` and `TableConstraint` discriminated-union shape — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) **Symbol:** `TableConstraint.constraint` (model.ts:739). -**Issue:** Same problem as finding 37 (`EncryptionDetails.encryptionDetailsType`). +**Issue:** Same problem as finding 34 (`EncryptionDetails.encryptionDetailsType`). Field repeats the type name's primary token. The discriminated union of three constraint shapes is wrapped in a field literally named `constraint`. @@ -1335,13 +1244,13 @@ three constraint shapes is wrapped in a field literally named `constraint`. --- -### 52. `Client` class name — category 1 (Vague/generic) — *pass* +### 49. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. **Pass.** --- -### 53. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* +### 50. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* Standard `{verb}{Resource}` shape. Convention. **Pass.** @@ -1349,23 +1258,23 @@ Standard `{verb}{Resource}` shape. Convention. **Pass.** it reads `noun-verb` instead of `verb-noun`. The corresponding shape in other SDKs is `existsTable` or `checkTableExists`. The current form mirrors the request type name `TableExists` which is itself unusual — see finding -21. **Flag at SDK-wide level.**) +18. **Flag at SDK-wide level.**) --- -### 54. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* +### 51. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* Same `{verb}{Resource}` pattern. **Pass.** --- -### 55. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* +### 52. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* Standard. **Pass.** --- -### 56. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) +### 53. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:55). @@ -1379,7 +1288,7 @@ SDK-wide cleanup.** --- -### 57. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 54. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` (utils.ts:15). @@ -1393,7 +1302,7 @@ SDK-wide cleanup** — generated boilerplate. --- -### 58. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 55. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). @@ -1405,7 +1314,7 @@ layers. The names imply a hierarchical relationship that does not exist. --- -### 59. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* +### 56. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* Verb-prefixed. Naming is fine. `flattenQueryParams` is used by the multi-query-param list methods (client.ts:357, 444). @@ -1418,26 +1327,7 @@ file.) --- -### 60. `index.ts` re-exports underscored type names — category 4 (Underscores in TS identifiers) - -**Symbols:** index.ts re-exports include `CreateTable_PropertiesEntry`, -`DeleteTable_Response`, `DeleteTableConstraint_Response`, -`DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry`, -`ListTableSummaries_Response`, `ListTables_Response`, `TableExists_Response`, -`TableInfo_PropertiesEntry`, `UpdateTable_PropertiesEntry`, -`UpdateTable_Response`, `OptionSpec_OauthStage`, `OptionSpec_OptionType`. - -**Issue:** Twelve public-API exports carry an `_` in their name. Consumers -see the underscored names in auto-imports, in violation of the Google TS -Style Guide § 5.3 and the project's lint rule on identifiers. - -**Suggested:** rename to the underscore-free `UpperCamelCase` form (e.g. -`CreateTablePropertiesEntry`, `DeleteTableResponse`, `OptionSpecOauthStage`). -**Flag for generator cleanup.** - ---- - -### 61. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* +### 57. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, `TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide @@ -1445,7 +1335,7 @@ pattern. **Pass.** --- -### 62. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`, `'volume'`, `'secret'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* +### 58. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`, `'volume'`, `'secret'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `Dependency.value.$case` literals (model.ts:455–467). @@ -1466,7 +1356,7 @@ their $case literals. --- -### 63. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* +### 59. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* **Symbol:** `parseResponse` (utils.ts:113) does `JSON.parse(text)` unconditionally. The name implies it can handle any response shape; in @@ -1569,30 +1459,27 @@ documentation pass needed.** | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics) | 16 | #1, #2, #3, #10, #11, #20, #23, #24, #26, #28, #35, #36, #43, #49, #56, #60 | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 26 | #4, #5, #6, #7, #9, #13, #14, #15, #16, #18, #19, #21, #22, #25, #27, #30, #31, #33, #34, #37, #39, #40, #41, #45, #48, #51 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 11 | #8, #12, #29, #42, #44, #46, #50, #57, #58, #62, #63 | -| **Pass / acceptable** | 10 | #17, #32, #38, #47, #52, #53, #54, #55, #59, #61 | +| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics) | 13 | #1, #8, #9, #17, #20, #21, #23, #25, #32, #33, #40, #46, #53 | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 26 | #2, #3, #4, #5, #7, #10, #11, #12, #13, #15, #16, #18, #19, #22, #24, #27, #28, #30, #31, #34, #36, #37, #38, #42, #45, #48 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 10 | #6, #26, #39, #41, #43, #47, #54, #55, #58, #59 | +| **Pass / acceptable** | 10 | #14, #29, #35, #44, #49, #50, #51, #52, #56, #57 | --- ## Top fixes (highest local return) -1. **#2 / #60** — drop the underscored `*_PropertiesEntry` / `*_Response` - type names from the public surface. Removes lint suppressions and - eliminates the proto-style naming. -2. **#3** — fix `DeltaRuntimePropertiesKvpairs` (field) / +1. **#1** — fix `DeltaRuntimePropertiesKvpairs` (field) / `DeltaRuntimePropertiesKvPairs` (type) casing mismatch. Local, mechanical rename. -3. **#20** — drop the `Arg` suffix from `fullNameArg` SDK-wide. Higher +2. **#17** — drop the `Arg` suffix from `fullNameArg` SDK-wide. Higher impact (changes wire field name) but eliminates a Go-style convention. -4. **#26** — type `enablePredictiveOptimization` as a real enum instead of +3. **#23** — type `enablePredictiveOptimization` as a real enum instead of a free-form string. Improves type safety. -5. **#36 / #37 / #42 / #51** — unify discriminated-union container field +4. **#33 / #34 / #39 / #48** — unify discriminated-union container field names (`value` vs `encryptionDetailsType` vs `arg` vs `constraint`). Within-file consistency fix. -6. **#34** — rename `ListTableSummaries_Response.tables` to `summaries` +5. **#31** — rename `ListTableSummaries_Response.tables` to `summaries` (or `tableSummaries`). Easy local fix. -7. **#11 / #12** — `SecurableKind` SCREAMING_SNAKE → UpperCamelCase on TS - side. Local mechanical change (does not affect wire compatibility if - string values are kept). +6. **#9** — `SecurableKind` 70+ values: hoist to a shared module and + consider splitting `TableKind` from non-table kinds. Local TS readability + plus SDK-wide structure fix. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 85ffb586..551feea5 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -105,7 +105,7 @@ ### 14. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, passed to `executeCall`. Same word as variable, type, and verb. Inside one method scope we have `req`, `call`, `httpReq`, `resp` — four roles, three of which abbreviate. -- **Category:** 1 (vague), 12 (duplicate concept), 4 (no underscore — but the name collision compensates). +- **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest`/`sendRequest` for the variable; keep `Call` as the type. - **Rationale:** Variable-type collisions are tolerable but obscure prose. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index 98c3b8ac..5209bb60 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -3,27 +3,27 @@ **Path:** `packages/tokenmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/update/delete arbitrary user tokens, plus create on-behalf-of-service-principal tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. -**Total weird names flagged:** 29 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 13 | +| High | 9 | +| Medium | 12 | | Low | 3 | -| Observation | 2 | +| Observation | 0 | ## High severity ### 1. Package name `tokenmanagement` duplicates `tokens` — overlap with sibling package -- **Why weird:** Two packages, `tokens` and `tokenmanagement`, both manage Databricks personal access tokens (PATs). They share the same `AutoscopeState` enum (copy-pasted byte-for-byte, model.ts:13-21 in both), both expose `ListTokens`, `RevokeToken`, `UpdateToken`, `RevokeToken_Response`, and `ListTokens_Response` request/response types, and both publish a `Client` class with `listTokens`/`updateToken` methods. The only structural differences are (a) the admin variant adds `getToken`, `createOnBehalfOfToken`, and admin-only fields on its token info, (b) the per-user variant has `createToken` (no on-behalf-of), and (c) the entity type is named `AdminTokenInfo` here vs. `PublicTokenInfo` in `tokens`. URL paths also differ: `/api/2.0/token-management/...` vs `/api/2.0/token/...`. From a TS user's perspective the namespaces collide: `import {Client, ListTokens} from '@databricks/sdk-tokenmanagement/v1'` and `import {Client, ListTokens} from '@databricks/sdk-tokens/v1'` clash on every public name. +- **Why weird:** Two packages, `tokens` and `tokenmanagement`, both manage Databricks personal access tokens (PATs). They share the same `AutoscopeState` enum (copy-pasted byte-for-byte, model.ts:13-21 in both), both expose `ListTokens`, `RevokeToken`, `UpdateToken`, and `ListTokens` response/request types, and both publish a `Client` class with `listTokens`/`updateToken` methods. The only structural differences are (a) the admin variant adds `getToken`, `createOnBehalfOfToken`, and admin-only fields on its token info, (b) the per-user variant has `createToken` (no on-behalf-of), and (c) the entity type is named `AdminTokenInfo` here vs. `PublicTokenInfo` in `tokens`. URL paths also differ: `/api/2.0/token-management/...` vs `/api/2.0/token/...`. From a TS user's perspective the namespaces collide: `import {Client, ListTokens} from '@databricks/sdk-tokenmanagement/v1'` and `import {Client, ListTokens} from '@databricks/sdk-tokens/v1'` clash on every public name. - **Category:** 12 (duplicate concepts across `tokens` vs `tokenmanagement` packages). - **Suggested name:** Keep the directory split (the API is split upstream) but in the public exports prefix admin types: `AdminListTokensRequest`, `AdminRevokeTokenRequest`, etc., or alternatively rename the package to `tokenadmin` so the call-site distinction is unmistakable (`@databricks/sdk-tokenadmin`). - **Rationale:** Today consumers who import both packages cannot do so by named import without aliasing every type. The shared enum (`AutoscopeState`) is also duplicated; one of the two packages should re-export the other's enum, or the enum should live in a shared core/identity module. ### 2. `AutoscopeState` enum values — redundant prefix on every member -- **Why weird:** Every member re-states the enum name: `AUTOSCOPE_STATE_UNSPECIFIED`, `AUTOSCOPE_STATE_DISABLED`, `AUTOSCOPE_STATE_RUNNING`, `AUTOSCOPE_STATE_COMPLETED`, `AUTOSCOPE_STATE_BACKFILLED`, `AUTOSCOPE_STATE_USER_SELECTED`, `AUTOSCOPE_STATE_API_NOT_COVERED` — `src/v1/model.ts:13-21`. Plus `UNSPECIFIED` is a proto-buf sentinel that idiomatic TS expresses with `undefined`. Also: shouty SCREAMING_SNAKE_CASE with underscores violates TS identifier conventions (rule 4). -- **Category:** 2 (redundant enum prefix), 4 (underscores in TS identifiers), 14 (proto/Go-style enum values not idiomatic in TS). +- **Why weird:** Every member re-states the enum name: `AUTOSCOPE_STATE_UNSPECIFIED`, `AUTOSCOPE_STATE_DISABLED`, `AUTOSCOPE_STATE_RUNNING`, `AUTOSCOPE_STATE_COMPLETED`, `AUTOSCOPE_STATE_BACKFILLED`, `AUTOSCOPE_STATE_USER_SELECTED`, `AUTOSCOPE_STATE_API_NOT_COVERED` — `src/v1/model.ts:13-21`. Plus `UNSPECIFIED` is a proto-buf sentinel that idiomatic TS expresses with `undefined`. +- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style enum values not idiomatic in TS). - **Suggested name:** `AutoscopeState.Unspecified | Disabled | Running | Completed | Backfilled | UserSelected | ApiNotCovered` — or drop `Unspecified` and rely on `autoscopeState?: AutoscopeState | undefined`. - **Rationale:** TS enum members are already namespaced by the enum (`AutoscopeState.Disabled`). The `AUTOSCOPE_STATE_` prefix is pure protobuf noise. This enum is also a copy of the identical enum in the `tokens` package; the prefix problem is doubled. @@ -39,143 +39,125 @@ - **Suggested name:** `CreateOnBehalfOfTokenRequest` (and cascading `GetTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`). - **Rationale:** TypeScript convention names request DTOs with a `Request` suffix; bare verb-phrase nouns read as actions. -### 5. `CreateOnBehalfOfToken_Response`, `GetToken_Response`, `ListTokens_Response`, `RevokeToken_Response` — underscore identifiers -- **Why weird:** Underscores inside TS type names are unidiomatic; every declaration requires `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` (model.ts:62, 82, 103, 115). The `eslint-disable` is itself a tell that the name fights the language. -- **Category:** 4 (underscores in TS identifiers). -- **Suggested name:** `CreateOnBehalfOfTokenResponse`, `GetTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`. -- **Rationale:** TS `strict-type-checked` rejects `Foo_Bar`. The proto-nested-message convention is a leaky abstraction. - -### 6. Client method `deleteToken` wraps request type `RevokeToken` — verb-tense inconsistency +### 5. Client method `deleteToken` wraps request type `RevokeToken` — verb-tense inconsistency - **Why weird:** `client.deleteToken(req: RevokeToken)` at client.ts:103-104. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently (tokens client.ts:131 + request type `RevokeToken`). - **Category:** 13 (verb-tense inconsistency between method and request type), 17 (inconsistent action verbs across the two packages: `tokenmanagement.deleteToken` vs `tokens.revokeToken` for the same kind of operation). - **Suggested name:** Either rename method to `revokeToken` (matches type and matches sibling package) or rename type to `DeleteTokenRequest` (matches HTTP verb). Recommend the former so both packages share a verb. - **Rationale:** "Revoke" carries a security/lifecycle meaning that "delete" loses; tokens aren't deleted from history, they're invalidated. -### 7. `UpdateToken.token: AdminTokenInfo` field — type-suffix tautology and id placement diverges from sibling +### 6. `UpdateToken.token: AdminTokenInfo` field — type-suffix tautology and id placement diverges from sibling - **Why weird:** `UpdateToken` (the request type) has a single semantic field `token` of type `AdminTokenInfo` plus an `updateMask`. The field name `token` paired with type `AdminTokenInfo` works only because `AdminTokenInfo` has the `Info` suffix; rename to `Token` (per finding #3) and `token: Token` becomes type-suffix tautology. The client signature `updateToken(req: UpdateToken)` and then `req.token?.tokenId ?? ''` (client.ts:191) means a caller must construct `{token: {tokenId: ...}, updateMask: ...}`. The sibling `tokens` package hoists `tokenId` to the top level (tokens model.ts:87-93), so consumers of both packages see different ergonomics for the same operation. - **Category:** 20 (type-suffix tautology if `Info` is removed). - **Suggested name:** Reuse the cleaner sibling-package pattern in `tokens`: `UpdateToken { tokenId; token; updateMask }` where `tokenId` is hoisted (tokens model.ts:87-93). - **Rationale:** The admin variant forces the id into the nested body while the sibling `tokens` package hoists it. This is a real ergonomic delta worth flagging upstream; consumers of both packages will trip on it. -### 8. `client.updateToken` returns `AdminTokenInfo`, sibling returns `UpdateTokenResponse` — inconsistent response handling +### 7. `client.updateToken` returns `AdminTokenInfo`, sibling returns `UpdateTokenResponse` — inconsistent response handling - **Why weird:** `tokenmanagement.Client.updateToken` returns `Promise` (client.ts:190) — the bare entity. The sibling `tokens.Client.updateToken` returns `Promise`. Worse: the `tokenmanagement` version doesn't even have a response type declared in `model.ts`; the client just unmarshals into the entity. So in one package `updateToken` returns the updated row; in the other it returns a different shape. - **Category:** 12 (duplicate concept inconsistently implemented), 17 (inconsistent client return shapes). - **Suggested name:** Pick one — either always return the updated entity (preferred; useful) or always return void. If returning the entity, name the type `Token`/`UpdateTokenResponse` rather than reusing the raw entity, so it can evolve. - **Rationale:** Cross-package consistency. A user who learns one client will be surprised by the other. -### 9. `tokenInfo` field on `CreateOnBehalfOfToken_Response` and `GetToken_Response` — `Info` tautology +### 8. `tokenInfo` field on response types — `Info` tautology - **Why weird:** Field `tokenInfo: AdminTokenInfo` (model.ts:66, 84). Field name re-states the type's redundant suffix. Cascades from the `AdminTokenInfo` → `Token` rename (finding #3). - **Category:** 20 (type-suffix tautology), 1 (`Info` vague). - **Suggested name:** `token: Token` (paired with rename in finding #3). - **Rationale:** Mechanical cascade. `response.token.tokenId` reads more naturally than `response.tokenInfo.tokenId`. -### 10. `tokenInfos` field on `ListTokens_Response` — plural of `Info`, doc-string mismatch -- **Why weird:** Field `tokenInfos: AdminTokenInfo[]` (model.ts:106). Same `Info` tautology as #9 but plural. Also: the JSDoc says "Token metadata of each user-created token in the workspace" — "metadata" implies summary info, but `AdminTokenInfo` is the full row. The field name should be `tokens` not `tokenInfos`. +### 9. `tokenInfos` field on list response — plural of `Info`, doc-string mismatch +- **Why weird:** Field `tokenInfos: AdminTokenInfo[]` (model.ts:106). Same `Info` tautology as #8 but plural. Also: the JSDoc says "Token metadata of each user-created token in the workspace" — "metadata" implies summary info, but `AdminTokenInfo` is the full row. The field name should be `tokens` not `tokenInfos`. - **Category:** 20 (type-suffix tautology), 9 (plural-of-`Info` is unidiomatic), 1 (`Info` vague), 15 (field name "tokenInfos" loses meaning). - **Suggested name:** `tokens: Token[]` (paired with rename in finding #3). -- **Rationale:** Same as #9. Sibling `tokens.ListTokens_Response` has the identical issue (tokens model.ts:55). +- **Rationale:** Same as #8. Sibling `tokens` list response has the identical issue (tokens model.ts:55). + +## Medium severity -### 11. `PAT` acronym never appears, autoscope comments reference it tacitly +### 10. `PAT` acronym never appears, autoscope comments reference it tacitly - **Why weird:** The doc comments on `AutoscopeState` (model.ts:8) say "State of inferred scope collection (autoscope) for an external PAT." But nowhere else in the file does the abbreviation `PAT` (Personal Access Token) appear — and `Token` is used everywhere as a stand-in. A user grepping for `PAT` (an industry-standard term in security tooling) finds nothing. Inversely, `Token` could mean OAuth, ID, refresh, etc., but in this package it always means PAT. The package would be unambiguous if named `pats` or `personalaccesstokens`. - **Category:** 5 (cryptic abbreviation in comment only), 15 (`Token` is too generic for the domain). - **Suggested name:** Add `PAT` aliases or document at the package level. Consider renaming `Token` → `PersonalAccessToken` or, less verbosely, keep `Token` but clarify in JSDoc. - **Rationale:** Discoverability. This package is the admin PAT API; calling that out beats hiding it. -## Medium severity - -### 12. `applicationId` on `CreateOnBehalfOfToken` — generic field name in a security-sensitive context +### 11. `applicationId` on `CreateOnBehalfOfToken` — generic field name in a security-sensitive context - **Why weird:** `applicationId: string` (model.ts:51) is the OAuth client ID of the service principal the on-behalf-of token will represent. "Application ID" is Azure terminology; on AWS/GCP it's "service principal ID" or "client ID". This is the *target* identity for a privileged token-mint operation; `applicationId` undersells the security implication and overloads "application" with three different meanings across Databricks clouds. - **Category:** 1 (vague — "application" is overloaded), 14 (Azure-style naming leaks), 15 (generic name in security context), 19 (underspecified ID — application ID of what?). - **Suggested name:** `servicePrincipalApplicationId` or `servicePrincipalClientId` (the JSDoc literally says "Application ID of the service principal", so the field name should too). - **Rationale:** The field documentation already names the concept correctly; the field name should follow. Mistaking this for "Databricks Apps application id" would mint a token for the wrong principal. -### 13. `ListTokens` request fields `createdById` and `createdByUsername` — duplicate filter slots +### 12. `ListTokens` request fields `createdById` and `createdByUsername` — duplicate filter slots - **Why weird:** `ListTokens { createdById?, createdByUsername? }` (model.ts:96-100). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type even says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (client.ts:159-164) which means callers can submit both at once and get undefined server behavior. - **Category:** 1 (vague — relationship unspecified), 6 (misleading — looks like two filters, possibly redundant). - **Suggested name:** Either expose a single `filter` string or document mutual exclusivity. At minimum, JSDoc the AND/OR semantics. - **Rationale:** Consumer-facing API ambiguity. -### 14. `AdminTokenInfo.scopes`, `AdminTokenInfo.autoscopeState`, `CreateOnBehalfOfToken.scopes`, `CreateOnBehalfOfToken.autoscopeEnabled` — `scopes`/`autoscope*` naming triplet inconsistency +### 13. `AdminTokenInfo.scopes`, `AdminTokenInfo.autoscopeState`, `CreateOnBehalfOfToken.scopes`, `CreateOnBehalfOfToken.autoscopeEnabled` — `scopes`/`autoscope*` naming triplet inconsistency - **Why weird:** Within the same `AdminTokenInfo`, `scopes: string[]` is one thing, `autoscopeState` is another (output-only), and the comment on `CreateOnBehalfOfToken.autoscopeEnabled` (model.ts:57) implies autoscope is a *mode*. So users have to learn: `scopes` (the explicit list), `autoscopeEnabled` (request-side bool), `autoscopeState` (response-side enum), with no `autoscopedScopes` field — the `scopes` field is overloaded as both the input list and the result after autoscope completes. Compare with `tokens.PublicTokenInfo` which has `scopes`, `autoscopeState`, `inferredScopes`, and `backfillScopes` (tokens model.ts:72-77) — i.e., the per-user package separates inferred from explicit scopes; the admin package does not. - **Category:** 12 (duplicate concept implemented differently than sibling), 1 (vague overloading of `scopes`). - **Suggested name:** Mirror the `tokens` package by adding `inferredScopes` / `backfillScopes` (or document the overload explicitly). - **Rationale:** Cross-package inconsistency. Worth pushing upstream. -### 15. `creationTime` / `expiryTime` / `lastUsedDay` — three time fields with three units and no unit suffix +### 14. `creationTime` / `expiryTime` / `lastUsedDay` — three time fields with three units and no unit suffix - **Why weird:** `AdminTokenInfo` (model.ts:27-41) has `creationTime: number`, `expiryTime: number`, `lastUsedDay: number`. The first two are described as "Timestamp" (likely epoch ms, by convention). The third is described as "Approximate timestamp for the day the token was last used. Accurate up to 1 day." But the field is named `lastUsedDay` (not `lastUsedTime` or `lastUsedDate`), and the doc says it is *still* a timestamp — so the suffix `Day` here means "with day-level granularity" not "as a calendar day index". A reader who skims the type and not the doc could easily believe `lastUsedDay` is a 1-31 day-of-month integer or a number-of-days-since-epoch integer. - **Category:** 5 (cryptic — `Day` is ambiguous), 6 (misleading — "Day" implies a date, value is a timestamp), 15 (generic name without unit). - **Suggested name:** `lastUsedTimeMs` (or split into `lastUsedTime: number` + a JSDoc note). At minimum, document the unit on all three fields. - **Rationale:** Compare with `tokens.PublicTokenInfo.lastAccessedTime` (tokens model.ts:69) which uses `Time` consistently. The admin variant breaks the pattern. -### 16. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc +### 15. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc - **Why weird:** `AdminTokenInfo` has `createdById` ("User ID of the user that created the token") and `ownerId` ("User ID of the user that owns the token"). What's the difference? In the sibling `tokens` package, the type has no `ownerId`. This appears to be admin-only metadata where ownership can transfer (e.g., on-behalf-of tokens). A reader has no way to know without external docs whether the two are usually equal. - **Category:** 1 (vague — relationship unstated), 19 (underspecified IDs in same struct). - **Suggested name:** Keep names but add JSDoc clarifying when they diverge (e.g., on-behalf-of tokens: creator is the principal who called the API, owner is the service principal). - **Rationale:** Discoverability. -### 17. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope +### 16. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope - **Why weird:** `workspaceId?: number | undefined` (model.ts:39) is documented "If applicable, the ID of the workspace that the token was created in." So it's optional and only meaningful at the account level. But the package and the URL path `/api/2.0/token-management/...` is a workspace endpoint. The field thus carries no useful signal at this endpoint, yet it's exposed. - **Category:** 6 (misleading — looks pertinent, often vestigial). - **Suggested name:** Keep; document under what circumstances it is populated (e.g., when the same model is reused at the account API). - **Rationale:** Generator artefact from sharing models across workspace/account scopes. Flag for upstream cleanup. -### 18. `lastUsedDay` vs sibling `tokens.PublicTokenInfo.lastAccessedTime` — different field names for "last use" -- **Why weird:** Same concept, two field names: `lastUsedDay` (admin) vs `lastAccessedTime` (per-user). Different unit precision too. Already partially covered in #15 but worth its own bullet for cross-package consistency. +### 17. `lastUsedDay` vs sibling `tokens.PublicTokenInfo.lastAccessedTime` — different field names for "last use" +- **Why weird:** Same concept, two field names: `lastUsedDay` (admin) vs `lastAccessedTime` (per-user). Different unit precision too. Already partially covered in #14 but worth its own bullet for cross-package consistency. - **Category:** 12 (duplicate concept across packages), 17 (inconsistent verb — used vs accessed). - **Suggested name:** Align to one. Recommend `lastUsedTime` everywhere; "accessed" is a synonym but inconsistent. - **Rationale:** Cross-package consistency. -### 19. `autoscopeEnabled` on `CreateOnBehalfOfToken` but `autoscopeState` on `AdminTokenInfo` — verb/state mix +### 18. `autoscopeEnabled` on `CreateOnBehalfOfToken` but `autoscopeState` on `AdminTokenInfo` — verb/state mix - **Why weird:** Request input: `autoscopeEnabled: boolean` (boolean toggle). Response output: `autoscopeState: AutoscopeState` (enum). Two different shapes for what is one feature (autoscope). The field-prefix is consistent, but a user must learn that "I set it as a bool" and "I read it back as an enum". - **Category:** 6 (misleading — write-side bool, read-side enum), 17 (inconsistent shapes for the same feature). - **Suggested name:** Document the asymmetry, or accept it as an upstream protocol fact. No good rename without breaking the wire. - **Rationale:** Observation more than action; flagged because it surfaces in two places in this small file. -### 20. `comment` field — vague, overloaded between SDK comment vs DDL comment vs user note +### 19. `comment` field — vague, overloaded between SDK comment vs DDL comment vs user note - **Why weird:** Three of the four user-facing types have a `comment: string` field (`AdminTokenInfo.comment`, `CreateOnBehalfOfToken.comment`). JSDoc says "Comment that describes the purpose of the token" — i.e., a description. Yet the field is called `comment`, which in TS/JS conjures up code comments. Same SQL-DDL leak as in `abacpolicies` (audit finding #28 there). - **Category:** 6 (misleading — `comment` is overloaded), 14 (SQL-DDL-style naming). - **Suggested name:** `description` (matches the JSDoc). - **Rationale:** SQL DDL uses `COMMENT ON ...`; SDK consumers don't. `description` is the standard noun. -### 21. `CreateOnBehalfOfToken` — preposition phrase inside type name +### 20. `CreateOnBehalfOfToken` — preposition phrase inside type name - **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token" (parse: VP(NP(token))) when the intent is "create [on-behalf-of token]" (parse: a kind of token). Industry shorthand is "OBO" but the SDK avoids the acronym. - **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). - **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. - **Rationale:** This is the only operation in the package whose name relies on the preposition; surfacing the intent (mint a token for someone else) helps. Defensible as-is. -### 22. Single-source-of-truth comments leaking proto file names -- **Why weird:** Top-of-type comments on `GetToken` (model.ts:69-75) and `ListTokens` (model.ts:87-94) say "!! KEEP THIS IN-SYNC WITH THE WORKSPACE PROTO DEFINITIONS IN SERVICE.PROTO !!" and similar. Generator artifacts leaking into the generated TS. Not a name per se but suggests the type names themselves may be tightly bound to proto choices made for inter-service-team reasons rather than for SDK ergonomics. -- **Category:** Observation, 14 (proto/Go-style leaking). -- **Suggested name:** Strip these comments from generated TS; keep in generator metadata. -- **Rationale:** Quality-of-life. Public SDK comments shouldn't reference Databricks-internal proto files. - -### 23. `AutoscopeState` doc comment leaks proto package paths -- **Why weird:** "Mirrored in databricks.identity.AutoscopeState in common/principal-context/api/proto/tokendetails.proto. ... Principal context proto should NOT depend on this proto definitions because too many services depend on the principal context proto." (model.ts:8-12). Inside-baseball that nobody outside Databricks needs. -- **Category:** Observation, 14 (proto leaks). -- **Suggested name:** Replace with one-sentence user-facing doc: "Lifecycle state of automatic scope inference for a personal access token." -- **Rationale:** Same as #22. - -### 24. `tokenValue` is a secret but the field name doesn't hint at it -- **Why weird:** `CreateOnBehalfOfToken_Response.tokenValue: string` (model.ts:65). This is the bearer token plaintext, returned exactly once. The field name `tokenValue` doesn't signal "this is a secret; persist immediately; we will never return it again". Compare with cryptographic SDKs that name such fields `secret`, `tokenSecret`, or `bearerToken`. +### 21. `tokenValue` is a secret but the field name doesn't hint at it +- **Why weird:** The `tokenValue: string` field on the create-on-behalf-of response (model.ts:65). This is the bearer token plaintext, returned exactly once. The field name `tokenValue` doesn't signal "this is a secret; persist immediately; we will never return it again". Compare with cryptographic SDKs that name such fields `secret`, `tokenSecret`, or `bearerToken`. - **Category:** 1 (vague), 6 (misleading — `value` is the most generic suffix imaginable for the most sensitive field in the package). - **Suggested name:** `tokenSecret` or `bearerToken`, and add a JSDoc warning ("Returned once. Store immediately."). - **Rationale:** Defensive naming for security-critical fields helps users not log/leak the value. ## Low severity -### 25. `Client` class is named `Client` (no namespacing) +### 22. `Client` class is named `Client` (no namespacing) - **Why weird:** `export class Client` (client.ts:48). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. - **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). - **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). - **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. -### 26. `host` field on `Client` — workspace URL is more specific +### 23. `host` field on `Client` — workspace URL is more specific - **Why weird:** `private readonly host: string;` (client.ts:49). The constructor accepts `options.host` which is actually the workspace URL (e.g., `https://my-workspace.cloud.databricks.com`). "Host" is HTTP-level jargon; `workspaceUrl` is the domain-level term users learn first. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `workspaceUrl` (and `options.workspaceUrl`). - **Rationale:** This is a shared concern across all generated clients; flagged here as it appears in this client. -### 27. `PACKAGE_SEGMENT` constant — vague label +### 24. `PACKAGE_SEGMENT` constant — vague label - **Why weird:** `const PACKAGE_SEGMENT = {...}` (client.ts:43). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `USER_AGENT_PKG`. @@ -183,13 +165,7 @@ ## Observations -### 28. Verb-tense and action-verb summary across the client -- `Client` methods: `createOnBehalfOfToken`, `deleteToken`, `getToken`, `listTokens`, `updateToken`. The set is `create/delete/get/list/update` — consistent CRUDish. The mismatch is only with the request types (`RevokeToken` for `deleteToken`, finding #6). -- **Category:** 13 (verb-tense inconsistency between method and type). - -### 29. Type-suffix tautology pattern repeats: `tokenInfo: AdminTokenInfo`, `tokenInfos: AdminTokenInfo[]` -- These are mechanical consequences of the `Info` suffix on the central entity (finding #3). Listed separately in findings #9 and #10. If the entity is renamed to `Token`, the field names also need to lose the `Info` cascade (`token` and `tokens`). -- **Category:** 20 (type-suffix tautology). +_None._ ## Domain glossary - `PAT` — Personal Access Token (only in `AutoscopeState` doc comment; the term the package is about but never names directly). @@ -204,13 +180,13 @@ ## Cross-package overlap with `tokens` - **Shared enum:** `AutoscopeState` is duplicated byte-for-byte (model.ts:13-21 in both packages). - **Shared request types:** `ListTokens`, `RevokeToken`, `UpdateToken` exist in both packages with different fields. `ListTokens` in `tokenmanagement` has `createdById`/`createdByUsername`; in `tokens` it is `{}`. -- **Shared response types:** `ListTokens_Response`, `RevokeToken_Response` exist in both packages. Both pull from a `*TokenInfo[]` array (`AdminTokenInfo[]` vs `PublicTokenInfo[]`). +- **Shared response shapes:** List and revoke responses exist in both packages. Both pull from a `*TokenInfo[]` array (`AdminTokenInfo[]` vs `PublicTokenInfo[]`). - **Different entity name:** `AdminTokenInfo` (this package) vs `PublicTokenInfo` (`tokens` package). - **Different create operation:** `createOnBehalfOfToken` (admin) vs `createToken` (per-user). -- **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #6. -- **Different update response shape:** Admin returns `AdminTokenInfo`; per-user returns a different shape — flagged in finding #8. -- **Different `lastUsed` field:** `lastUsedDay` (admin) vs `lastAccessedTime` (per-user) — flagged in findings #15/#18. -- **Different scope-related fields:** Admin has `scopes` + `autoscopeState`; per-user adds `inferredScopes` + `backfillScopes` — flagged in #14. +- **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #5. +- **Different update response shape:** Admin returns `AdminTokenInfo`; per-user returns a different shape — flagged in finding #7. +- **Different `lastUsed` field:** `lastUsedDay` (admin) vs `lastAccessedTime` (per-user) — flagged in findings #14/#17. +- **Different scope-related fields:** Admin has `scopes` + `autoscopeState`; per-user adds `inferredScopes` + `backfillScopes` — flagged in #13. - **Different URL prefix:** `/api/2.0/token-management/...` vs `/api/2.0/token/...`. The two packages are conceptual siblings (PAT lifecycle) split by audience (admin-of-others vs self), but the SDK surface is split inconsistently — naming, return types, and method verbs diverge for no obvious reason. Worth raising at the SDK-design level. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index 6ce33779..53c0626e 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -3,12 +3,12 @@ **Path:** `packages/tokens/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share an `AutoscopeState` enum and a near-identical "token info" record, but the auth/audience boundary makes them distinct services. -**Total weird names flagged:** 31 +**Total weird names flagged:** 30 ## Summary | Severity | Count | | --- | --- | -| High | 9 | +| High | 8 | | Medium | 10 | | Low | 7 | | Observation | 5 | @@ -58,20 +58,14 @@ 2. Merge to a single `TokenInfo` with all fields optional, and document which subset the server populates for each endpoint. - **Rationale:** A caller doing token introspection on the workspace needs to pick a package; the type-name doesn't tell them which fields they'll get. -### 7. `CreateToken_Response` and `RevokeToken_Response` with proto-style underscore — `model.ts:42, 85` -- **Why weird:** Type names `CreateToken_Response`, `ListTokens_Response`, `RevokeToken_Response` use proto-style nested-message underscores. Each carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` to silence the linter. Compare with `UpdateTokenResponse` (`model.ts:96`) — same package, same generator, *no* underscore. Generator inconsistency: three methods get `Foo_Response`, one gets `FooResponse`. (The Go SDK convention exposes `CreateTokenResponse`-style names in `*Service.Response` pattern; here the TS port has reproduced the underscore literally.) -- **Category:** 4 (underscores in TS identifiers), 13 (inconsistency — same package mixes `_Response` and `Response`), 14 (Go/proto-style name). -- **Suggested name:** Drop underscore consistently: `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`. The `eslint-disable` line vanishes with the underscore. -- **Rationale:** Mixing `CreateToken_Response` (underscore) with `UpdateTokenResponse` (no underscore) in the same `index.ts` export block is a discoverability bug — a reader autocompleting `CreateTokenR...` gets nothing because the actual name has an underscore. - -### 8. `ListTokens` and `RevokeToken` request types are misnamed as actions, not requests — `model.ts:50, 79` -- **Why weird:** Type names `ListTokens` and `RevokeToken` are bare verbs/verb-phrases that *look like methods*. A TS reader sees `import type {ListTokens, RevokeToken} from './model'` and reasonably guesses these are *functions or actions*. Instead, they're request DTOs. (`CreateToken` and `UpdateToken` have the same problem.) The corresponding response types correctly carry the `_Response` suffix; the request types should carry `Request`. The `tokenmanagement` package does the same. The Go SDK uses `CreateTokenRequest`/`RevokeTokenRequest` in idiomatic Go. +### 7. `ListTokens` and `RevokeToken` request types are misnamed as actions, not requests — `model.ts:50, 79` +- **Why weird:** Type names `ListTokens` and `RevokeToken` are bare verbs/verb-phrases that *look like methods*. A TS reader sees `import type {ListTokens, RevokeToken} from './model'` and reasonably guesses these are *functions or actions*. Instead, they're request DTOs. (`CreateToken` and `UpdateToken` have the same problem.) The corresponding response types correctly carry a response suffix; the request types should carry `Request`. The `tokenmanagement` package does the same. The Go SDK uses `CreateTokenRequest`/`RevokeTokenRequest` in idiomatic Go. - **Category:** 8 (missing/asymmetric suffix), 6 (misleading — looks like a callable), 13 (asymmetry — response types are suffixed but request types aren't). - **Suggested name:** `CreateTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`. Pairs symmetrically with `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`, `UpdateTokenResponse`. - **Rationale:** Most TS SDKs (AWS, GCP, Azure) name request DTOs with an explicit `*Request` suffix or `*Input`. The current asymmetry is a Go-port artefact. -### 9. `Client.revokeToken` method paired with URL `/api/2.0/token/delete` — `client.ts:131,135` -- **Why weird:** Method on `Client` is `revokeToken`, but the wire URL it hits is `/api/2.0/token/delete`. Sibling `tokenmanagement.Client.deleteToken` (line 103) maps `RevokeToken`/`RevokeToken_Response` to URL `/api/2.0/token-management/tokens/{id}` via HTTP `DELETE`. So: +### 8. `Client.revokeToken` method paired with URL `/api/2.0/token/delete` — `client.ts:131,135` +- **Why weird:** Method on `Client` is `revokeToken`, but the wire URL it hits is `/api/2.0/token/delete`. Sibling `tokenmanagement.Client.deleteToken` (line 103) maps `RevokeToken`/`RevokeTokenResponse` to URL `/api/2.0/token-management/tokens/{id}` via HTTP `DELETE`. So: - `tokens.revokeToken` → request type `RevokeToken` → URL ends in `/delete` → HTTP `POST` (revoke = delete on wire, named "revoke" in SDK). - `tokenmanagement.deleteToken` → request type `RevokeToken` → URL ends in `/tokens/{id}` → HTTP `DELETE` (delete on wire, named "delete" in SDK, request type still `Revoke*`). - **Category:** 17 (inconsistent action verbs for the same conceptual operation), 13 (inconsistency between packages), 6 (misleading — the request type doesn't match the method verb). @@ -80,25 +74,25 @@ ## Medium severity -### 10. `CreateToken.lifetimeSeconds` — unit smuggled into name, not type — `model.ts:29` +### 9. `CreateToken.lifetimeSeconds` — unit smuggled into name, not type — `model.ts:29` - **Why weird:** `lifetimeSeconds?: number | undefined`. Unit (seconds) lives in the field name, not the type. The doc says "in seconds". TS has no native duration type, so a unit-bearing field name is conventional, but the rest of the package uses `*Time` (`creationTime`, `expiryTime`, `lastAccessedTime`) which are *epoch milliseconds* (verified by doc strings on `model.ts:62-69`). Same `number` type, two different units, two different naming conventions. - **Category:** 15 (unit-bearing field-name vs typed wrapper), 13 (intra-package inconsistency — `lifetimeSeconds` vs `creationTime`). - **Suggested name:** Acceptable as-is, but consider `lifetimeMs` (or `lifetime: Duration`) for parity with `creationTime` etc. The Temporal API (`@js-temporal/polyfill` is already a package.json dep) has `Temporal.Duration` which would be domain-correct. - **Rationale:** Within one struct, two number fields use different time units. Caller must read docs to avoid bugs. -### 11. `CreateToken.autoscopeEnabled` — naming inconsistent with response — `model.ts:38` +### 10. `CreateToken.autoscopeEnabled` — naming inconsistent with response — `model.ts:38` - **Why weird:** Request flag is `autoscopeEnabled?: boolean` ("enabled" suffix). The response carries `autoscopeState?: AutoscopeState` (a state enum, not a boolean). Same conceptual feature, different abstraction levels and names. A TS user thinking "I'll just check the value I set" would write `req.autoscopeEnabled` then later expect `info.autoscopeEnabled` but instead has to translate via `info.autoscopeState === 'AUTOSCOPE_STATE_RUNNING' || …`. The mapping (which states correspond to "enabled") is undocumented in the SDK surface. - **Category:** 12 (duplicate concept — `autoscopeEnabled` ↔ `autoscopeState`), 17 (boolean vs enum for the same feature), 1 (vague — what counts as "enabled"?). - **Suggested name:** Either accept the asymmetry but document the mapping, or rename request to `autoscopeMode?: AutoscopeMode` with an enum (`ENABLED` / `DISABLED`), so the surface is symmetric. - **Rationale:** A boolean request and an enum response for "the same setting" is a known leaky abstraction. -### 12. `PublicTokenInfo.scopes` doc grammar — singular vs plural — `model.ts:67-68` +### 11. `PublicTokenInfo.scopes` doc grammar — singular vs plural — `model.ts:67-68` - **Why weird:** Doc reads "Scope of the token was created with, if applicable" — but the field is `scopes?: string[] | undefined` (plural, array). The doc says "Scope" (singular) and "the token was created with" (drops the "that"). Compare with `CreateToken.scopes` doc: "Optional scopes of the token." — different wording, different singular/plural usage. - **Category:** 9 (singular/plural mismatch), 6 (misleading doc), 13 (inconsistency — same field documented differently across types). - **Suggested name:** Fix doc to "The scopes the token was created with, if applicable." Same in `AdminTokenInfo.scopes` (`tokenmanagement/model.ts:42-43` has the same typo). - **Rationale:** Doc grammar shapes the mental model. Singular "scope" suggests a single value; the type is an array. -### 13. `PublicTokenInfo.inferredScopes` and `backfillScopes` — overlapping arrays of strings — `model.ts:73-76` +### 12. `PublicTokenInfo.inferredScopes` and `backfillScopes` — overlapping arrays of strings — `model.ts:73-76` - **Why weird:** Three different scope arrays in one struct: - `scopes?: string[]` — "Scope of the token was created with, if applicable." - `inferredScopes?: string[]` — "Inferred API path scopes collected for this token when autoscope is enabled." @@ -109,9 +103,9 @@ - **Suggested name:** Group them: `declaredScopes`, `inferredScopes`, `backfillInferredScopes`. Add an `effectiveScopes` computed-on-server field that the caller actually wants. Or model as `{ source: 'declared' | 'inferred' | 'backfill'; value: string }[]` so the source is part of the data. - **Rationale:** Three string-array fields with overlapping semantics is a discoverability bug. A new user has to read all three docs to understand the policy. -### 14. `UpdateToken.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:88` +### 13. `UpdateToken.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:88` - **Why weird:** Doc on `UpdateToken.tokenId`: "The SHA-256 hash of the token to be updated." But every other `tokenId` doc in the package (and in `tokenmanagement`) says variants of "The ID of the token". So readers comparing the types see: - - `CreateToken_Response.tokenInfo.tokenId` (line 46+59) — "The ID of this token." + - `CreateTokenResponse.tokenInfo.tokenId` (line 46+59) — "The ID of this token." - `PublicTokenInfo.tokenId` (line 60) — "The ID of this token." - `RevokeToken.tokenId` (line 81) — "The ID of the token to be revoked." - `UpdateToken.tokenId` (line 89) — "The SHA-256 hash of the token to be updated." @@ -119,19 +113,19 @@ - **Suggested name:** Either (a) reconcile the docs — if `tokenId` is the SHA-256 hash everywhere, say so consistently; or (b) if `UpdateToken.tokenId` actually expects a different format than the others, rename or document the divergence loudly. - **Rationale:** The doc disagreement implies either a stale comment or a real wire-protocol quirk. Either way, a caller can't tell which. -### 15. `UpdateToken.token` field name shadows the package name — `model.ts:90` +### 14. `UpdateToken.token` field name shadows the package name — `model.ts:90` - **Why weird:** `UpdateToken.token?: PublicTokenInfo`. The field `token` inside the type `UpdateToken` in the package `tokens` carries the entire updated payload. Reads `updateReq.token.tokenId` — the word "token" appears three times in five characters. The same package has `Client.updateToken` method which takes `UpdateToken` which has a `token` field of type `PublicTokenInfo`. Layer cake. - **Category:** 20 (type-suffix tautology), 1 (vague). - **Suggested name:** Field as `info` (since the inner type is `PublicTokenInfo`/`TokenInfo`) or `data`. Wire stays `token`. So `updateReq.info.tokenId`. - **Rationale:** The wire field is `token` because the proto message wraps a `TokenInfo`; in TS, the field name can clarify intent without changing the wire. -### 16. `UpdateToken` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:87-93` +### 15. `UpdateToken` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:87-93` - **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:165`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenSchema` on `model.ts:200-202`). - **Category:** 12 (duplicate concept), 6 (misleading — which one is authoritative?), 11 (the inner one is dead-ish data). - **Suggested name:** Drop one. Either: (a) make `token` exclude `tokenId` (`Omit`) and keep the top-level; or (b) drop the top-level and use `req.token.tokenId` in the client. - **Rationale:** Two fields for the same identifier invite subtle bugs (server may pick the inner one if the top-level is empty). -### 17. `Client` class name — colliding namespace — `client.ts:46` +### 16. `Client` class name — colliding namespace — `client.ts:46` - **Why weird:** Top-level class literally named `Client`. Re-exported in `index.ts` as just `Client`. A consumer importing from both `@databricks/sdk-tokens/v1` and `@databricks/sdk-tokenmanagement/v1` faces an identical name clash: ``` import {Client} from '@databricks/sdk-tokens/v1'; @@ -142,13 +136,13 @@ - **Suggested name:** `TokensClient`, `UserTokensClient`, or `MyTokensClient`. Mirror with `TokenManagementClient`/`AdminTokensClient`. - **Rationale:** Same finding as `rfa#37`, recurs across all packages — but particularly painful here given the `tokens`/`tokenmanagement` overlap. -### 18. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +### 17. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site (`client.ts:87,114` use them within four lines of each other). - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Cross-package: same as `rfa#32`, recurs everywhere. -### 19. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` +### 18. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` - **Why weird:** The file imports `Options` from `@databricks/sdk-core/api` (line 3) and `CallOptions` from `@databricks/sdk-options/call` (line 12). Three `Options`-suffixed types in scope. `HttpCallOptions` is internal — purely a context bag passed to `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -156,37 +150,37 @@ ## Low severity -### 20. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:226` +### 19. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:226` - **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateToken` payloads must learn this helper. -- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #26 re-export gap). +- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #25 re-export gap). - **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. - **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. -### 21. `readAll` — generic helper name — `utils.ts:40` +### 20. `readAll` — generic helper name — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `rfa#34`. -### 22. `flattenQueryParams` — `utils.ts:123` +### 21. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` only ever builds JSON bodies). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default; or keep, but stop emitting it for body-only services. - **Rationale:** Same as `rfa#35`. -### 23. `PACKAGE_SEGMENT` constant — `client.ts:41` +### 22. `PACKAGE_SEGMENT` constant — `client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `rfa#36`. -### 24. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` +### 23. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,111,141,171` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Same as `rfa#38`. -### 25. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` +### 24. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` - **Why weird:** Local `opts` variable is one letter shorter than the parameter `options` to disambiguate. The shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions`. @@ -194,19 +188,19 @@ ## Observations -### 26. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper +### 25. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper The index file exports the `Client`, the `AutoscopeState` enum, and nine model interfaces. It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. -### 27. `package.json` description is empty string — `package.json:4` +### 26. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the ambiguous `tokens` name (see #1) and the parallel `tokenmanagement` package, this leaves users without any registry-level metadata to disambiguate the two packages. -### 28. No tests in the package +### 27. No tests in the package `package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees (`AutoscopeState` proto-link in the doc) deserve a contract test. -### 29. Doc comments leak proto file paths and internal commentary +### 28. Doc comments leak proto file paths and internal commentary The `AutoscopeState` doc (model.ts:7-12) references `common/principal-context/api/proto/tokendetails.proto` and `Principal context proto should NOT depend on this proto definitions` — internal architecture commentary that leaks into the public SDK surface. Similar pattern in `tokenmanagement`. Acceptable for now, but a polish pass should strip internal proto-tree paths from the user-facing JSDoc. -### 30. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:165` +### 29. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:165` `const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:89`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. ## Domain glossary @@ -225,4 +219,4 @@ The `AutoscopeState` doc (model.ts:7-12) references `common/principal-context/ap - `src/v1/client.ts` (186 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (18 lines): read fully. -- Cross-referenced `packages/tokenmanagement/src/v1/model.ts`, `client.ts`, `index.ts` for overlap analysis (see findings #1, #2, #6, #9, #17). +- Cross-referenced `packages/tokenmanagement/src/v1/model.ts`, `client.ts`, `index.ts` for overlap analysis (see findings #1, #2, #6, #8, #16). diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 65d23a8e..315df63b 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -3,14 +3,14 @@ **Path:** `packages/usagedashboards/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). -**Total weird names flagged:** 25 +**Total weird names flagged:** 21 ## Summary | Severity | Count | | --- | --- | -| High | 7 | -| Medium | 8 | -| Low | 6 | +| High | 6 | +| Medium | 6 | +| Low | 5 | | Observation | 4 | ## High severity @@ -23,85 +23,67 @@ ### 2. `UsageDashboardMajorVersion` enum has redundant prefix on every member — `src/v1/model.ts:5-9` - **Why weird:** Every member of the enum is prefixed with the enum name in screaming snake case: `USAGE_DASHBOARD_MAJOR_VERSION_UNSPECIFIED`, `USAGE_DASHBOARD_MAJOR_VERSION_1`, `USAGE_DASHBOARD_MAJOR_VERSION_2`. The qualified usage at a call site reads `UsageDashboardMajorVersion.USAGE_DASHBOARD_MAJOR_VERSION_1` — 51 characters of pure stutter for a value that means "1". -- **Category:** 2 (redundant enum prefix), 4 (`UPPER_SNAKE_CASE` underscores in TS identifiers), 7 (overly verbose), 18 (long enum values). -- **Suggested name:** Either TS-idiomatic `UsageDashboardMajorVersion.Unspecified` / `.V1` / `.V2` (PascalCase, no prefix) or numeric union `type UsageDashboardMajorVersion = 1 | 2`. The JSDoc on the field (line 24) even mentions "VERSION_1" as the default, implying the wire format is what matters and the enum is just bookkeeping. -- **Rationale:** Two real values (`1` and `2`) plus a sentinel `Unspecified` does not need a 28-character prefix per member. The proto-style `_UNSPECIFIED` zero value is a Go/proto3 convention with no TS equivalent (TS uses `undefined`). See the typescript.mdc § 5 rule about avoiding `UPPER_SNAKE_CASE` for non-constants. Same finding applies to **every** enum in the codebase — but this one is particularly egregious because the values are integers. +- **Category:** 2 (redundant enum prefix), 7 (overly verbose), 18 (long enum values). +- **Suggested name:** Drop the `USAGE_DASHBOARD_MAJOR_VERSION_` prefix on each member so call sites read `UsageDashboardMajorVersion.UNSPECIFIED` / `.V1` / `.V2`. +- **Rationale:** Two real values (`1` and `2`) plus a sentinel `Unspecified` does not need a 28-character prefix per member. Same finding applies to **every** enum in the codebase — but this one is particularly egregious because the values are integers. ### 3. `UsageDashboardType` enum has the same redundant-prefix problem — `src/v1/model.ts:11-15` - **Why weird:** Members `USAGE_DASHBOARD_TYPE_UNSPECIFIED`, `USAGE_DASHBOARD_TYPE_WORKSPACE`, `USAGE_DASHBOARD_TYPE_GLOBAL`. Same pattern as #2. -- **Category:** 2, 4, 7, 18. -- **Suggested name:** `UsageDashboardType.Workspace` / `.Global` / `.Unspecified`. Or, since the enum is binary in practice (Workspace vs Global), a `'workspace' | 'global'` union type would be smaller and more idiomatic for TS. +- **Category:** 2, 7, 18. +- **Suggested name:** Drop the `USAGE_DASHBOARD_TYPE_` prefix so members read `UNSPECIFIED` / `WORKSPACE` / `GLOBAL`. - **Rationale:** Same as #2. Bonus issue: the wire values are the bare strings `WORKSPACE` and `GLOBAL` (after the `USAGE_DASHBOARD_TYPE_` prefix), so the prefix exists *only* in the TS layer — it is not part of the on-wire enum. -### 4. `_Response` suffix with literal underscore — `src/v1/model.ts:29, 44` -- **Why weird:** The types `CreateBillingUsageDashboard_Response` and `GetBillingUsageDashboard_Response` use a literal underscore — a proto-style nested message convention transplanted directly into TypeScript. Every reference to these types triggers an ESLint suppression comment (`// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`) — see lines 28, 43, 51, 61. Six lint suppressions in a 86-line file is a strong signal the naming convention is wrong. -- **Category:** 4 (underscore in TS identifier), 14 (proto/Go-style), 8 (redundant suffix — `Response` is already a suffix). -- **Suggested name:** `CreateBillingUsageDashboardResponse` and `GetBillingUsageDashboardResponse` (no underscore). Or drop the suffix entirely and rename request types to `CreateBillingUsageDashboardRequest` / `GetBillingUsageDashboardRequest` so the response types can claim the un-suffixed name (`CreateBillingUsageDashboard` / `GetBillingUsageDashboard`) — though that's a bigger refactor. -- **Rationale:** The proto-style nested-message convention is dead surface area in TS; the lint suppressions prove it. ESLint's `naming-convention` rule is correctly flagging an inappropriate identifier — the fix is to rename, not to suppress. - -### 5. Request type names omit `Request` suffix while response types include `Response` — `src/v1/model.ts:17,34 vs 29,44` -- **Why weird:** Asymmetric suffixing: `CreateBillingUsageDashboard` (no `Request`) paired with `CreateBillingUsageDashboard_Response` (has `Response`). Reading the types in isolation, `CreateBillingUsageDashboard` looks like a domain entity (the dashboard itself) not the *request* to create one — a user might reasonably expect it to have fields like `id`, `createdAt`, `etag`, etc. The asymmetry forces the nested `_Response` suffix to disambiguate, which is what causes finding #4. -- **Category:** 6 (misleading — name implies a domain entity but is actually a request DTO), 8 (asymmetric suffixing), 9 (singular/plural — verb without object/request suffix reads as imperative). -- **Suggested name:** Either `CreateBillingUsageDashboardRequest` + `CreateBillingUsageDashboardResponse` (both suffixed) or drop the request suffix and rename responses (see finding #4 alternate). -- **Rationale:** Either pattern works; the SDK should pick one. The current Go-port has request types named after the RPC method (verb-prefixed) and response types named `*Response`. In TS, suffix-consistency aids autocomplete and reading. Same finding applies to every RPC type pair in the codebase. - -### 6. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 40` / `src/v1/client.ts:106-108` +### 4. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 40` / `src/v1/client.ts:106-108` - **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:106`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. - **Category:** 6 (misleading — TS type says optional, API likely requires it), 16 (field type contradicts domain reality), 17 (inconsistent transport: same field is body on POST, query on GET). - **Suggested name:** Keep the name but type as `UsageDashboardType` (required). Or split the DTO into `CreateBillingUsageDashboardRequest` (body) and `GetBillingUsageDashboardRequest` (query params), since the GET endpoint conceptually has different parameter semantics from the POST. - **Rationale:** `dashboardType` is the field that distinguishes Workspace from Global dashboards — it is *the* selector for the resource. Treating it as optional with no default is type-level dishonesty. -### 7. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` +### 5. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` - **Why weird:** Databricks workspace IDs are 64-bit integers (the Go SDK uses `int64`); JavaScript's `number` type is IEEE-754 double which loses precision above 2^53. The TS field is typed `number | undefined`. Same finding applies to `metastores` and most workspace-scoped packages in the SDK, but worth flagging because every audit cycle compounds the risk. Compare with `accountId: string` (line 21) which correctly uses `string` for an account UUID. - **Category:** 16 (field type contradicts domain — `number` cannot represent a 64-bit ID), 6 (misleading — type appears safe but is lossy). - **Suggested name:** Keep the field name, change type to `string`. - **Rationale:** Most workspace IDs are below 2^53 in practice, so this rarely bites. But the type contract claims something the runtime can't honour for the high end of the ID space. This is a systemic SDK-level issue worth raising at the generator. +### 6. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72` +- **Why weird:** `accountId` lives on `CreateBillingUsageDashboard` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:72, 101` — `${req.accountId ?? this.accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. +- **Category:** 6 (misleading — body shape implies body field, but it's a path param), 12 (duplicate concept — also lives on `ClientOptions`), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree? what happens if both sources are missing?). +- **Suggested name:** Remove `accountId` from the request DTOs entirely. Make it a client-level concern only; throw a clear error if it is missing. Or segregate path params into a separate type and document the dual role. +- **Rationale:** Same as `billableusagedownload` finding. The current shape misleads callers about the wire format, the duplicated-with-fallback pattern is a footgun, and the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. + ## Medium severity -### 8. `CreateBillingUsageDashboard` / `GetBillingUsageDashboard` include `Billing` but the package is `usagedashboards` — `src/v1/model.ts:17, 34` +### 7. `CreateBillingUsageDashboard` / `GetBillingUsageDashboard` include `Billing` but the package is `usagedashboards` — `src/v1/model.ts:17, 34` - **Why weird:** The package is `@databricks/sdk-usagedashboards` (no "billing"); the types prefix `Billing` (no "Usage" alone). A user who imported the package by its `usage`-themed name then sees `Billing`-prefixed types and `Client.createBillingUsageDashboard()` method must mentally bridge `usage` ↔ `billing`. The package name and type names disagree on which noun is primary. - **Category:** 17 (inconsistent action verbs / nouns across naming layers), 7 (overly verbose — `BillingUsage` is two synonyms for the same concept). - **Suggested name:** Pick one noun. Either rename the package to `billingusagedashboards` (matches types) or drop `Billing` from the type names (`CreateUsageDashboard` / `GetUsageDashboard`). The Go SDK calls this domain "Billing → UsageDashboards" so types match Go; the TS package name is the outlier. - **Rationale:** Cross-layer consistency. The simplest fix is `CreateUsageDashboard*` / `GetUsageDashboard*` since the package name is already `usagedashboards`. "Billing" is implied by the account-level endpoint path. -### 9. `Client` class is unprefixed — `src/v1/client.ts:38` +### 8. `Client` class is unprefixed — `src/v1/client.ts:38` - **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-usagedashboards/v1'`, then has to rename it (`import {Client as UsageDashboardsClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Cross-SDK consistency — but worth flagging. - **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). - **Suggested name:** `UsageDashboardsClient` or `BillingUsageDashboardClient`. - **Rationale:** Same finding as `billableusagedownload` audit #8. The SDK could expose a namespace export pattern (`import * as usageDashboards from '@databricks/sdk-usagedashboards/v1'`) and remove the `Client` symbol entirely, letting `usageDashboards.Client` be the qualified name. Not a blocker. -### 10. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:68, 97` +### 9. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:68, 97` - **Why weird:** Method name and request-type name are textually identical (modulo case): `createBillingUsageDashboard(req: CreateBillingUsageDashboard)`. The repetition is so close that the type name reads like a misnamed method import. Compare with `lakeview` where `Client.createDashboard(req: CreateDashboardRequest)` keeps the type-noun separate from the method-verb. - **Category:** 7 (overly verbose), 8 (redundant — method verb is already implicit in the type's verb prefix). - **Suggested name:** `createDashboard` / `getDashboard` (drop `BillingUsage` since the package name disambiguates) or `create` / `get` (since there are only two methods). Type stays as `CreateBillingUsageDashboardRequest`. - **Rationale:** A method on `usageDashboardsClient` is already in the usage-dashboards namespace; restating `BillingUsageDashboard` in the method name is pure stutter. The Go SDK does this because Go has package-flat method tables; TS classes provide their own namespace. -### 11. URL hard-codes the empty-string fallback for accountId — `src/v1/client.ts:72, 101` -- **Why weird:** `${req.accountId ?? this.accountId ?? ''}` — if both the request and the client have no `accountId`, the URL becomes `/api/2.0/accounts//dashboard`. The server will 4xx, but the *client* is happy to send a malformed URL. Not strictly a naming issue but it surfaces because `accountId` is duplicated between `ClientOptions.accountId` and the DTO field (same issue as `billableusagedownload` audit #7). -- **Category:** 12 (duplicate concept), 19 (underspecified ID — silently produces empty path segment). -- **Suggested name:** Remove `accountId` from the request DTOs. Make it a client-level concern only; throw a clear error if it is missing. Or keep both but throw `Error('accountId is required')` instead of silently producing `/accounts//...`. -- **Rationale:** Same as `billableusagedownload` finding. The duplicated-with-fallback pattern is a footgun; the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. - -### 12. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72` -- **Why weird:** `accountId` lives on `CreateBillingUsageDashboard` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. -- **Category:** 6 (misleading — body shape implies body field, but it's a path param), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree?). -- **Suggested name:** Either segregate path params into a separate type (`PathParams` / `RouteParams`) or document the field's dual role. Or omit it from the body and keep it as a path-param-only field. Most idiomatic: remove from request DTO entirely (see #11). -- **Rationale:** The current shape misleads callers about the wire format. The field appears in two URL segments simultaneously, which is suspicious. - -### 13. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` +### 10. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` - **Why weird:** Both response types include `dashboardId?: string` (always optional). But there is no `GetByDashboardId` method, and the request types use `(workspaceId, accountId, dashboardType)` to identify the dashboard, not the `dashboardId`. So `dashboardId` is a returned-but-never-accepted identifier — informational only. The field is also typed optional, but a successful 2xx response should always have an ID; the `?` is again type-level dishonesty. - **Category:** 6 (misleading optionality), 19 (underspecified id — present in responses but not accepted as a request key). - **Suggested name:** Keep the name; make it required (`dashboardId: string`). Or document that it is a read-only side-channel identifier (not a primary key from the API's POV). Or expose a `getByDashboardId` method that round-trips the value. - **Rationale:** If the API returns an ID, the SDK should either let you use it or document why you can't. The current state — return-only, never-accepted — is API-design noise that the SDK faithfully echoes. -### 14. `dashboardUrl` field is a `string` — should be `URL` or branded — `src/v1/model.ts:48` -- **Why weird:** `dashboardUrl?: string | undefined` — a URL is typed as a bare string. Callers must `new URL(resp.dashboardUrl)` defensively. Compare with `accountId`/`dashboardId` which are also strings but represent IDs, not URLs. No branded type distinguishes them. Also optional on a success response (same dishonesty as #13). +### 11. `dashboardUrl` field is a `string` — should be `URL` or branded — `src/v1/model.ts:48` +- **Why weird:** `dashboardUrl?: string | undefined` — a URL is typed as a bare string. Callers must `new URL(resp.dashboardUrl)` defensively. Compare with `accountId`/`dashboardId` which are also strings but represent IDs, not URLs. No branded type distinguishes them. Also optional on a success response (same dishonesty as #10). - **Category:** 15 (generic field name losing meaning), 6 (misleading optionality), 1 (vague — `string` for a URL). - **Suggested name:** Keep the field name; consider a branded type (`type Url = string & {readonly _urlBrand: unique symbol}`) or `URL` (the WHATWG class). At minimum, make it non-optional on a 2xx response. - **Rationale:** SDK-wide concern (every URL field in every package is `string`); flag once per audit. Branded URLs are a TS idiom precisely for this case. -### 15. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:33` +### 12. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:33` - **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. - **Category:** 1 (vague), 15 (generic field name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -109,63 +91,58 @@ ## Low severity -### 16. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` +### 13. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` - **Why weird:** The exact same multi-sentence JSDoc ("Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account.") appears on `CreateBillingUsageDashboard.dashboardType` (line 22) and `GetBillingUsageDashboard.dashboardType` (line 39). The duplication suggests the underlying enum (`UsageDashboardType`) should carry the doc, not each field. - **Category:** Observation — not strictly a name issue but flagged because it implies fragmentation. JSDoc duplication is a generator artefact. - **Suggested name:** Move the doc to the `UsageDashboardType` enum (or its members). -### 17. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:68, 74, 78, 97, 111, 115, 117` +### 14. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:68, 74, 78, 97, 111, 115, 117` - **Why weird:** Local variables use three-letter abbreviations (`req`, `resp`, `opts`, `httpReq`). The codebase guideline (typescript.mdc § 5) discourages cryptic short abbreviations. Compare with `httpClient` (full word) in the same file. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`. - **Rationale:** Inexpensive readability win. -### 18. `req: CreateBillingUsageDashboard` parameter name — `src/v1/client.ts:69, 98` -- **Why weird:** The method parameter is named `req` (the abbreviation from #17). It is also the request DTO whose type name doesn't end in `Request` (see #5). The parameter name `req` clashes with the natural reading where the type name suggests an entity ("a usage dashboard to create") not a request envelope. -- **Category:** 5 (cryptic), 6 (misleading paired with type name). -- **Suggested name:** `params` or `input` (since the type is not literally a Request). Or fix the type name (`CreateBillingUsageDashboardRequest`) and keep `request`. - -### 19. `params` shadowed across files — `src/v1/client.ts:102` +### 15. `params` shadowed across files — `src/v1/client.ts:102` - **Why weird:** Local `params: URLSearchParams` — fine in isolation, but `flattenQueryParams(prefix, value, params)` in `utils.ts:123` exposes the same `params` name in public API. The repeated use of `params` for both `URLSearchParams` and "named function parameters" is mildly confusing in audit traces. - **Category:** 1 (vague). - **Suggested name:** `queryParams` / `urlSearchParams`. -### 20. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:109` +### 16. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:109` - **Why weird:** `const query = params.toString();` — the variable is the serialized query *string*, but `query` reads as a query expression/object. Compare with `fullUrl` on the next line (which is clear about what it is). - **Category:** 1 (vague), 6 (misleading — name implies a query, value is a string). - **Suggested name:** `queryString`. -### 21. `httpClient: HttpClient` field — `src/v1/client.ts:43` +### 17. `httpClient: HttpClient` field — `src/v1/client.ts:43` - **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention widespread in this SDK. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the outer `Client` class in the same file. ## Observations -### 22. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` +### 18. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` The exported `flattenQueryParams` helper is never called from `client.ts` — the GET method does its own `params.append()` (lines 103-108) inline because there are only two query params. The helper is dead surface area in this package; same finding as `billableusagedownload` audit #11. Worth pruning at the generator level when the consuming methods don't need it. -### 23. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` +### 19. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. Both are used in `client.ts:79, 89, 117, 126`. The verb-pair is fine, but the cognitive distance between "wrap with retry options" and "send an HTTP request and check for API errors" is large enough that one name should be different (e.g., `runWithCallOptions` / `sendHttp`). Same finding appears in every audited package's `utils.ts`. -### 24. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency +### 20. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency - The enum names are `UsageDashboardMajorVersion`, `UsageDashboardType` — `Usage` first, no "Billing". - The request types are `CreateBillingUsageDashboard` — `Billing` first, with `Usage`. - The package is `usagedashboards` — `usage` only, no "billing". - The Go SDK service is "Billing → UsageDashboards" — both nouns in two layers. -Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #8. +Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #7. -### 25. The package has no list/page operations +### 21. The package has no list/page operations There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. ## Domain glossary - `usage dashboard` — A Databricks-managed dashboard (DBSQL or AI/BI Lakeview) that visualises account-level billing/usage data. Two flavours: **Workspace** (per-workspace) and **Global** (all workspaces in an account). - `DBU` — Databricks Unit; the standard unit of compute consumption. Notably absent from this package's types and JSDoc — verified via grep that the literal "DBU" never appears, even though DBUs are the unit the dashboard would visualise. - `account ID` — Databricks account identifier (UUID); surfaces as `accountId: string` on both request types and on `ClientOptions.accountId`. -- `workspace ID` — Databricks workspace identifier (64-bit int); surfaces as `workspaceId: number` — see finding #7 about the precision issue. +- `workspace ID` — Databricks workspace identifier (64-bit int); surfaces as `workspaceId: number` — see finding #5 about the precision issue. - `major version` — Template version of the dashboard (1 or 2). Per the JSDoc, defaults to `VERSION_1` if unspecified at create time. -- `dashboard ID` — Identifier of the created dashboard (returned, not accepted as input). See finding #13. +- `dashboard ID` — Identifier of the created dashboard (returned, not accepted as input). See finding #10. - `E2` — Databricks deployment architecture; not mentioned in this package but implicit (account-level endpoints are E2-only). ## File coverage diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md index bcdb624c..2a4feb27 100644 --- a/.agent/naming-audit/usagepolicy.md +++ b/.agent/naming-audit/usagepolicy.md @@ -3,14 +3,14 @@ **Path:** `packages/usagepolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). -**Total weird names flagged:** 38 +**Total weird names flagged:** 33 ## Summary | Severity | Count | | --- | --- | -| High | 10 | -| Medium | 14 | -| Low | 9 | +| High | 8 | +| Medium | 12 | +| Low | 8 | | Observation | 5 | ## High severity @@ -18,58 +18,46 @@ ### 1. Whole package duplicates `budgetpolicy` with a renamed entity — `src/v1/model.ts` (entire file) vs `packages/budgetpolicy/src/v1/model.ts` - **Why weird:** `UsagePolicy` is `BudgetPolicy` with `Usage` substituted for `Budget`. The shared types (`CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`) are textually identical between the two packages. The `UsagePolicy.policyId` JSDoc even confirms: "(same structure as BudgetPolicy)" (line 120). Same `/accounts/{accountId}/{verb}-policies` URL shape, same wire fields. The only material difference is the API version (`/api/2.1` vs `/api/2.0`) and the URL segment (`usage-policies` vs `budget-policies`). - **Category:** 12 (duplicate concept — two sibling packages with the same shape and overlapping name), 1 (vague — `usage` and `budget` both modify the same underlying tag-policy concept). -- **Suggested name:** Either (a) collapse `usagepolicy` and `budgetpolicy` into a single package with a versioned entity, or (b) ensure both publish under distinct, non-overlapping type names. As shipped, a consumer importing both packages cannot disambiguate `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`, `CustomPolicyTag`, or `Client` without aliasing. +- **Suggested name:** Either (a) collapse `usagepolicy` and `budgetpolicy` into a single package with a versioned entity, or (b) ensure both publish under distinct, non-overlapping type names. As shipped, a consumer importing both packages cannot disambiguate `Filter`, `LimitConfig`, `SortSpec`, `CustomPolicyTag`, or `Client` without aliasing. - **Rationale:** This is the headline finding for the package. The duplication is a 1:1 clone, and the API team did not even bother to rename the reserved custom-tag keys: `CustomPolicyTag.key` JSDoc in `usagepolicy` still says `"budget-policy-name"`, `"budget-policy-id"`, `"budget-policy-resolution-result"` (line 27, copied from `budgetpolicy`). Two clones in one SDK with collidable names is a real usability problem. -### 2. `SortSpec_Field` enum (`Foo_Bar` identifier) — `src/v1/model.ts:6` -- **Why weird:** Underscore in TypeScript identifier — proto-style nested-enum notation. Requires an explicit `eslint-disable-next-line @typescript-eslint/naming-convention` because TS strict rules reject `Foo_Bar`. -- **Category:** 4 (underscores in TS identifiers), 14 (Go/proto-style names not idiomatic in TS). -- **Suggested name:** `SortField` (hoist out of the nested namespace), or a string-literal union `'POLICY_NAME' | undefined`. -- **Rationale:** TS has no nested-enum concept; the only reason this exists is to mirror the `SortSpec.Field` proto message. The eslint-disable is a tell that the name fights the language. Mirrors the same finding in `budgetpolicy`. - -### 3. `SortSpec_Field.FIELD_UNSPECIFIED` — `src/v1/model.ts:8` -- **Why weird:** A `FIELD_UNSPECIFIED` sentinel imported from protobuf semantics. Idiomatic TS uses `undefined` (the field is already `field?: SortSpec_Field | undefined`). -- **Category:** 2 (redundant enum prefix re-stating the enum name), 14 (proto sentinel leak). -- **Suggested name:** Drop the value and rely on `field?: SortField | undefined`. -- **Rationale:** Optional + `undefined` already expresses "unspecified" in TS; a `FIELD_UNSPECIFIED` literal forces every caller to handle two "no choice" states (`undefined` and the sentinel string). - -### 4. `Filter` (bare top-level type) — `src/v1/model.ts:47` +### 2. `Filter` (bare top-level type) — `src/v1/model.ts:47` - **Why weird:** Re-exported from `index.ts:11` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (`Array#filter`, RxJS `filter`, content filters, etc.) and the type is package-scoped — but the re-export under this name *directly collides* with the same bare `Filter` in `packages/budgetpolicy/src/v1/model.ts:77`. Any user importing both packages will hit a name clash. - **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). - **Suggested name:** `UsagePolicyFilter` (and rename the sibling to `BudgetPolicyFilter`). - **Rationale:** A bare `Filter` provides zero discoverability and forces a collision with `budgetpolicy.Filter`. Both packages target the same account-level API; consumers will frequently import both. This finding is doubly bad because the two `Filter` types have identical structure but are not type-compatible from TS's structural-typing perspective at the import boundary if a consumer aliases one (`import {Filter as BudgetFilter}`). -### 5. `UpdateUsagePolicyRequest.limitConfig` field doc references a non-existent successor — `src/v1/model.ts:117` +### 3. `UpdateUsagePolicyRequest.limitConfig` field doc references a non-existent successor — `src/v1/model.ts:117` - **Why weird:** JSDoc reads: "DEPRECATED. This is redundant field as LimitConfig is part of the UsagePolicy". But `UsagePolicy` itself (line 121–130) does **not** have a `limitConfig` member, so the JSDoc claim ("LimitConfig is part of the UsagePolicy") is wrong about its successor — the field has nowhere to migrate to within this package. - **Category:** 6 (misleading — doc points to a non-existent replacement). - **Suggested name:** Fix the JSDoc to either point at the real successor or drop the migration hint. - **Rationale:** A new-language SDK should not inherit other-language migration warts on day one, and the warning is broken because the documented successor doesn't exist in this package's `UsagePolicy`. -### 6. `CreateUsagePolicyRequest.requestId` documented as idempotency-ish key — `src/v1/model.ts:14-21` +### 4. `CreateUsagePolicyRequest.requestId` documented as idempotency-ish key — `src/v1/model.ts:14-21` - **Why weird:** JSDoc: "A unique identifier for this request. Restricted to 36 ASCII characters." — `requestId` is a vague field name that does not signal "idempotency key" to callers. The doc says nothing about idempotency (unlike `budgetpolicy`'s `CreateBudgetPolicyRequest.requestId` doc at `packages/budgetpolicy/src/v1/model.ts:37-42` which explicitly mentions idempotency). The semantic is unclear: trace id? correlation id? idempotency key? - **Category:** 1 (vague — `requestId` could mean anything), 15 (generic field name losing meaning), 17 (inconsistent across sibling packages — sibling spells out idempotency, this one doesn't). - **Suggested name:** `idempotencyKey` (matches Stripe/Square/most REST APIs) and expand the JSDoc to clarify semantics. - **Rationale:** Sibling-package divergence is worse than either choice alone: a caller flipping between `usagepolicy` and `budgetpolicy` cannot rely on identical semantics for the same-named field. Either both packages should call it `idempotencyKey` or both `requestId`, and both docs should state idempotency. -### 7. `UsagePolicy.policyId` / `UsagePolicy.policyName` field naming inside `UsagePolicy` type — `src/v1/model.ts:123,125` +### 5. `UsagePolicy.policyId` / `UsagePolicy.policyName` field naming inside `UsagePolicy` type — `src/v1/model.ts:123,125` - **Why weird:** Fields on the `UsagePolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. - **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `UsagePolicy.id` is `policyId`). - **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). - **Rationale:** `usagePolicy.id` reads better than `usagePolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. Mirrors `budgetpolicy` finding #9. -### 8. `UsagePolicy.bindingWorkspaceIds` — `src/v1/model.ts:129` +### 6. `UsagePolicy.bindingWorkspaceIds` — `src/v1/model.ts:129` - **Why weird:** `binding` as a noun-prefix reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this usage policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). Additionally, the JSDoc here is shorter than in `budgetpolicy` (which adds "An empty binding implies that this budget policy is open to any workspace in the account.") — the empty-binding semantic is silently dropped from `usagepolicy`, creating yet another inter-package documentation divergence. - **Category:** 1 (vague — `binding` is generic: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists), 17 (inconsistent doc across siblings). - **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. - **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. -### 9. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` +### 7. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` - **Why weird:** Workspace IDs are typed as `number[]`. Databricks workspace IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so workspace IDs `>2^53` will silently lose precision. Same problem on `Filter.creatorUserId: number` (line 57). - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). - **Suggested name:** `bindingWorkspaceIds: bigint[]` or `string[]` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Generator/policy issue across the SDK. Worth flagging at every usage site. -### 10. Filter operator semantics undocumented — `src/v1/model.ts:47-63` +### 8. Filter operator semantics undocumented — `src/v1/model.ts:47-63` - **Why weird:** The `Filter` type has three optional fields whose names imply singular match (`policyName`, `creatorUserId`, `creatorUserName`), but the JSDoc on `policyName` says "The partial name of policies to be filtered on" — implying substring match. The other two fields don't document their operator (equality? prefix? substring?). When multiple fields are set, the JSDoc on the type says "All specified filters will be applied in conjunction" — i.e. AND — but the per-field docs each repeat "If unspecified, all policies will be returned", which is confusing in the presence of the conjunction rule. - **Category:** 6 (misleading — singular noun for what is likely a substring/multi-match filter), 1 (vague — no operator spelled in the name). - **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to lists where appropriate). @@ -77,165 +65,147 @@ ## Medium severity -### 11. `CustomPolicyTag` type name — `src/v1/model.ts:23` +### 9. `CustomPolicyTag` type name — `src/v1/model.ts:23` - **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. Also colliding with the same `CustomPolicyTag` exported from `budgetpolicy/src/v1/model.ts:53`. - **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location), 12 (duplicate concept across siblings with identical name). - **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. - **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". -### 12. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` +### 10. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling **from the budget-policy domain** — copy-pasted verbatim from the `budgetpolicy` package without renaming to the usage-policy equivalents (one would expect `usage-policy-name` etc.). Either (a) the wire really *does* use the `budget-policy-*` prefix (which is a Databricks API design issue worth surfacing), or (b) the JSDoc was lazily duplicated and the actual reserved keys are different. - **Category:** 6 (misleading: cross-domain magic strings that callers must memorise), 12 (duplicate across siblings — but here it's a *bug*, because the reserved keys are not surfaced as constants and may differ from `budgetpolicy`), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate the wire payload and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Either way the verbatim duplication smells. -### 13. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` +### 11. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Same as finding #9 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. +- **Rationale:** Same as finding #7 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. -### 14. `Filter.creatorUserId` + `Filter.creatorUserName` — two ways to filter on the same creator — `src/v1/model.ts:57,62` +### 12. `Filter.creatorUserId` + `Filter.creatorUserName` — two ways to filter on the same creator — `src/v1/model.ts:57,62` - **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number`, `creatorUserName` is `string`. - **Category:** 12 (duplicate concept), 19 (underspecified id), 6 (misleading — caller wonders which one to use). - **Suggested name:** Collapse to `creator?: {id?: number; name?: string}`, or split into named composite types. - **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine, and the per-field doc ("If unspecified, all policies will be returned") fails to define the AND/OR rule between them. -### 15. `SortSpec` type — `src/v1/model.ts:103` +### 13. `SortSpec` type — `src/v1/model.ts:103` - **Why weird:** `SortSpec` (specification) and `Field` together build the "what to sort by" structure. `Spec` is generic — every type is a spec of something. The wrapping type holds two fields (`field` + `descending`); a one-or-two-field pair could be inlined into the request. - **Category:** 1 (vague suffix `Spec`), 11 (trivial wrapper holding two fields). - **Suggested name:** `SortOptions`, or inline as `sortField?: SortField; sortDescending?: boolean` on the request. - **Rationale:** `Spec` adds no information. `sortBy: SortField` plus a boolean is more direct. Mirrors `budgetpolicy` finding #17. -### 16. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:104` +### 14. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:104` - **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. - **Category:** Observation (typo). - **Suggested name:** Fix spelling. - **Rationale:** Surfaces in IntelliSense. Same typo as `budgetpolicy/src/v1/model.ts:150` — the two packages even share generator typos. -### 17. `ListUsagePoliciesResponse.policies` field name — `src/v1/model.ts:96` +### 15. `ListUsagePoliciesResponse.policies` field name — `src/v1/model.ts:96` - **Why weird:** Field `policies` of type `UsagePolicy[]`. Within the `usagepolicy` package, `policies` is fine — but within a multi-package consumer with `budgetpolicy.policies` and other policy-emitting packages, the bare name is ambiguous when copy-pasted. - **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on the create/update requests), 12 (duplicate field name across siblings). - **Suggested name:** `usagePolicies: UsagePolicy[]`. - **Rationale:** Tied to type rename considerations. If the entity-type were renamed (per finding #1), `policies` could stay; otherwise `usagePolicies` makes the field self-documenting at any depth. -### 18. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` +### 16. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` - **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but the iterator helper only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. Mirrors `budgetpolicy` finding #20. -### 19. `UsagePolicy.customTags` plural field paired with singular `CustomPolicyTag` type — `src/v1/model.ts:127` +### 17. `UsagePolicy.customTags` plural field paired with singular `CustomPolicyTag` type — `src/v1/model.ts:127` - **Why weird:** Plural field `customTags: CustomPolicyTag[]` plus the singular type with `Tag` suffix produces `customTags: CustomPolicyTag[]` — same word twice (`Tags`/`Tag`). - **Category:** 8 (redundant prefix `custom`), 20 (`customTags: CustomPolicyTag[]` is type-suffix tautology). -- **Suggested name:** `tags: Tag[]` (with type rename per #11). Wire form stays `custom_tags`. +- **Suggested name:** `tags: Tag[]` (with type rename per #9). Wire form stays `custom_tags`. - **Rationale:** Linked to the type-rename above; if `CustomPolicyTag` becomes `Tag`, field naturally becomes `tags`. -### 20. `CreateUsagePolicyRequest.policy` field with wire-name leak in JSDoc — `src/v1/model.ts:19-20` +### 18. `CreateUsagePolicyRequest.policy` field with wire-name leak in JSDoc — `src/v1/model.ts:19-20` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated" — wire-name leak (`policy_id`) in the docs of a TS field. Also: the doc is *shorter* than the sibling `budgetpolicy.CreateBudgetPolicyRequest.policy` doc (which adds: "`policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional."). So the usage-policy version silently drops the "policyName must be provided" and the cloud-provider-conditional tag note. - **Category:** 14 (wire-style identifiers in TS docs), 17 (inconsistent docs across sibling packages for the same conceptual request). - **Suggested name:** Fix the doc to reference TS field names; align with sibling-package doc content. - **Rationale:** Editing UX: hovers should show TS, not proto. The sibling-divergence also matters: a developer reading both packages should see consistent requirements unless they actually differ. -### 21. `UpdateUsagePolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:112` +### 19. `UpdateUsagePolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:112` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `UsagePolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. Exact same bug as `budgetpolicy.UpdateBudgetPolicyRequest.policy` JSDoc. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `UsagePolicy`, model says otherwise), 14 (Go-SDK paste from a richer struct). - **Suggested name:** Fix doc; remove the spurious reference or add the missing field to the model. - **Rationale:** Real bug, twice (once here, once in `budgetpolicy`). -### 22. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` +### 20. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` - **Why weird:** `budgetpolicy.UpdateBudgetPolicyRequest` (`packages/budgetpolicy/src/v1/model.ts:165`) carries an `updateMask?: FieldMask` plus a `budgetPolicyFieldMask(...paths)` builder. `usagepolicy.UpdateUsagePolicyRequest` does not. Either (a) the usage-policy API genuinely uses replace-on-PATCH semantics (no partial updates) — in which case the JSDoc should say so — or (b) the SDK is missing field-mask support that the API offers. Without inspection of the OpenAPI source, either is plausible, and the absence of a doc note is itself a finding. - **Category:** 17 (inconsistency across near-clone sibling packages), Observation (potential missing surface). - **Suggested name:** If full-replace: document on `UpdateUsagePolicyRequest`. If partial-update: add `updateMask?: FieldMask` and a `usagePolicyFieldMask(...paths)` helper to match the sibling. - **Rationale:** A user toggling between the two clones will expect parity. The divergence is silent and unjustified by either docstring. -### 23. `UsagePolicy` lacks the rich constraints documented on `BudgetPolicy.policyName` — `src/v1/model.ts:125` vs `packages/budgetpolicy/src/v1/model.ts:20-25` -- **Why weird:** `BudgetPolicy.policyName` has a four-line JSDoc enumerating constraints: uniqueness, ISO 8859-1 (latin1) charset, reserved-keyword prefix ban. `UsagePolicy.policyName` says only "The name of the policy." If both APIs share the same backend (likely), the usage-policy doc is silently incomplete. If the constraints genuinely differ, the doc should call out the difference. -- **Category:** 17 (sibling-package doc divergence for what is plausibly the same constraint), 15 (generic name losing meaning when the constraint set is undocumented). -- **Suggested name:** Restore the full constraint doc, or document the deviation. -- **Rationale:** This is the kind of divergence that bites users who copy code from one package to the other. - -### 24. `ListUsagePoliciesResponse.nextPageToken` / `previousPageToken` docs trimmed vs sibling — `src/v1/model.ts:97-100` -- **Why weird:** Docs read: "A token that can be sent as `page_token` to retrieve the next page." and "A token that can be sent as `page_token` to retrieve the previous page." The sibling `budgetpolicy.ListBudgetPoliciesResponse` adds: "If this field is omitted, there are no subsequent pages." / "In this field is omitted, there are no previous pages." Both omission notes are missing here. -- **Category:** 17 (inconsistent doc across siblings), 14 (wire-name `page_token` leak in TS doc). -- **Suggested name:** Restore the omission notes and fix `page_token` → `pageToken`. -- **Rationale:** Two sibling packages with the same pagination contract should not diverge in pagination docs. Even though the budgetpolicy docs have their own typo ("In this field is omitted"), at least they tell the reader what an absent token means. - ## Low severity -### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 21. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handle different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in `abacpolicies` and `budgetpolicy` audits. Generator-wide. -### 26. `HttpCallOptions` — `src/v1/utils.ts:15` +### 22. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide; same as `budgetpolicy` finding #29. -### 27. `readAll` — `src/v1/utils.ts:40` +### 23. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 28. `flattenQueryParams` — `src/v1/utils.ts:123` +### 24. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,217` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package (12+ identical copies in this monorepo). - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 29. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 25. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Same as `budgetpolicy` finding #33; generator-wide. -### 30. `Client` class plain name — `src/v1/client.ts:46` +### 26. `Client` class plain name — `src/v1/client.ts:46` - **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-usagepolicy/v1`, they will almost certainly alias it (`import {Client as UsagePolicyClient}`) to avoid collision with `Client` from every other package — including the byte-identical class from `@databricks/sdk-budgetpolicy/v1`. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages, *especially* this one and `budgetpolicy`). - **Suggested name:** `UsagePolicyClient`. - **Rationale:** Each generated package emits a `Client`. With `usagepolicy`/`budgetpolicy` being near-clones, the importer who needs both will be forced into double-aliasing. -### 31. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 27. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` - **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. Same as `budgetpolicy` finding #35. -### 32. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` +### 28. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` - **Why weird:** "it's" should be "its" (possessive). Same grammatical mistake appears in `budgetpolicy/src/v1/client.ts:120` ("Retrieves a policy by it's ID.") — copy-pasted across the clones. - **Category:** Observation (grammar). - **Suggested name:** Fix to "its". - **Rationale:** Surfaces in editor hovers; small but persistent. -### 33. `listUsagePolicies` JSDoc verbatim duplicates sibling — `src/v1/client.ts:145` -- **Why weird:** "Lists all usage policies. Policies are returned in the alphabetically ascending order of their names." Word-for-word translation of the budgetpolicy version with `usage` substituted. Same finding for the rest of the method docstrings — they're all `s/budget/usage/` substitutions with no domain-specific guidance. -- **Category:** Observation, 12 (cross-package boilerplate). -- **Suggested name:** Keep, but worth flagging that the package ships zero domain-specific guidance — every per-method doc is a clone with substitution. -- **Rationale:** The duplication compounds the "is this really two separate APIs?" question raised in finding #1. - ## Observations -### 34. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference +### 29. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. - **Category:** 12 (duplicate concept), 1 (vague package boundary). -### 35. No `FieldMask` import in `usagepolicy/src/v1/model.ts` -Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #22 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. +### 30. No `FieldMask` import in `usagepolicy/src/v1/model.ts` +Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #20 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. - **Category:** Observation / 17 (cross-package inconsistency). -### 36. Action-verb conventions in `Client` +### 31. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 37. Acronym casing `Id` consistently used as `Id`, not `ID` +### 32. Acronym casing `Id` consistently used as `Id`, not `ID` `policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). - **Category:** 3 (observation — internal acronym style is consistent). -### 38. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) +### 33. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) The same identifier appears in three forms in the same client file: - `usage_policies` — wire form (in the Zod schemas via snake_case keys). - `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). @@ -247,7 +217,7 @@ Readers must mentally translate. Worth flagging because the kebab-case form does ## Domain glossary - `usage policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. Same structure as `budgetpolicy.BudgetPolicy` per the JSDoc on `UsagePolicy` (line 120). Despite "usage" in the name, no usage-data concept (rows/metrics/period) lives on the model — only tags and workspace bindings. - `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `UsagePolicy.bindingWorkspaceIds: number[]`. -- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #12). +- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #10). - `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.1/accounts/{accountId}/usage-policies`). - `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index 806efe94..fc83b4f8 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -10,11 +10,11 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | -| High | 4 | +| High | 2 | | Medium | 7 | | Low | 6 | -| Observation | 8 | -| **Total** | **25** | +| Observation | 7 | +| **Total** | **22** | Headline themes: @@ -37,9 +37,6 @@ Headline themes: single zero-valued member** and shouts `AWS_SSE_S3` / `AWS_SSE_KMS` in SCREAMING_SNAKE on the two real values — the SDK-wide proto-mirror convention but jarring for TS readers. -5. **`DeleteVolume_Response`** uses an underscore separator that breaks - TypeScript naming convention, mirroring the proto-style nested message - name. --- @@ -91,38 +88,6 @@ Headline themes: request type — name suggestions: `CreateVolumeRequest`, `UpdateVolumeRequest`.) -### H3. `DeleteVolume_Response` — underscore in TS identifier - -- **File / line:** `src/v1/model.ts:59–60`; cross-ref - `src/v1/client.ts:122, 124` (return type), `src/v1/index.ts:10`. -- **Category:** #4 underscores in TS identifiers; #14 Go/Java-style name. -- **Current:** `export interface DeleteVolume_Response {}` returned by - `deleteVolume(...)`. -- **Suggestion:** Rename to `DeleteVolumeResponse` (no underscore). Today - the lint rule has to be silenced inline (`// eslint-disable-next-line - @typescript-eslint/naming-convention`) which is itself a smell that the - name is wrong. -- **Rationale:** `Foo_Bar` is the proto-buf-generator idiom for nested - messages. TypeScript naming convention is PascalCase with no - underscores (Google TypeScript Style Guide §5.3.1). The same pattern is - used across the workspace (e.g. `catalogs.DeleteCatalog_Response`, - `connections.DeleteConnection_Response`) so this is a repo-wide call. - -### H4. `ListVolumes_Response` — underscore in TS identifier - -- **File / line:** `src/v1/model.ts:103–111`; cross-ref - `src/v1/client.ts:199`, `src/v1/index.ts:14`. -- **Category:** #4 underscores in TS identifiers; #14 Go/Java-style name. -- **Current:** `export interface ListVolumes_Response { volumes?: - VolumeInfo[]; nextPageToken?: string }`. -- **Suggestion:** `ListVolumesResponse` (no underscore). The inline - `eslint-disable-next-line @typescript-eslint/naming-convention` - acknowledges the violation. -- **Rationale:** Same as H3. Note also that the `ListVolumes` request - type and `ListVolumes_Response` response type share a stem — naming - them `ListVolumesRequest` / `ListVolumesResponse` would also resolve - the request-type-as-verb-phrase issue (M1 below). - --- ## Medium Severity @@ -342,18 +307,7 @@ types. Changing this package alone would create asymmetry. See `grep -rE "^export interface (Get|Set|Create|Update|Delete|List)" packages/` for the workspace inventory. (M1 above flags it locally.) -### O2. Proto-style nested message names with underscores are repo-wide - -`DeleteVolume_Response` and `ListVolumes_Response` follow the same pattern -as `ArtifactMatcher_MatchType`, `BudgetConfigurationFilter_Operator`, -`CleanRoomAutoApprovalRule_AuthorScope`, `ConversionInfo_State`, -`DatabaseInstance_State`, `EndpointStatus_State`, and 20+ other types -across the workspace. This violates TypeScript naming convention but is -the agreed mirror of the Go SDK's `Parent_Field` proto idiom. The file -disables the lint rules explicitly at `model.ts:59, 103, 204, 224`. Flag -for awareness only. - -### O3. `*_UNSPECIFIED` zero values repeated across enums +### O2. `*_UNSPECIFIED` zero values repeated across enums `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` (`model.ts:6`) repeats the enum domain (`SSE_ENCRYPTION_ALGORITHM_`) in @@ -362,14 +316,14 @@ sibling packages. The duplication makes `SseEncryptionAlgorithm.SSE_ENCRYPTION_A 60 characters long for what should read as `UNSPECIFIED`. Not a local defect; would need a workspace-wide convention change. -### O4. `…Info` suffix repeated across UC types +### O3. `…Info` suffix repeated across UC types `VolumeInfo` follows the `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the codebase decides to drop the `Info` suffix, this is one of many to fix (M2 above flags it locally). -### O5. `_Arg` suffix on path parameter fields is a generator-wide artifact +### O4. `_Arg` suffix on path parameter fields is a generator-wide artifact `fullNameArg` (H1) is not unique to volumes — the workspace contains fields like `nameArg`, `idArg`, `fullNameArg` across packages that take a @@ -377,7 +331,7 @@ URL path parameter. Search: `grep -rE "fullNameArg|nameArg|idArg" packages/*/src/`. Documented here because the fix has cross-package implications. -### O6. `VolumeType` enum members are clean +### O5. `VolumeType` enum members are clean `VolumeType.MANAGED` and `VolumeType.EXTERNAL` (`model.ts:11–14`) avoid the SCREAMING_SNAKE_CASE long-form variant (no `VOLUME_TYPE_*` prefix). @@ -385,14 +339,14 @@ This enum is the cleanest in the file and shows that the proto-mirror pattern is not mandatory — `SseEncryptionAlgorithm` could have been written this way too. -### O7. URL path string repeated across methods without a named constant +### O6. URL path string repeated across methods without a named constant The base path `/api/2.1/unity-catalog/volumes` (and the suffixed variant with `${req.fullNameArg ?? ''}`) appears five times in `client.ts:93, 125, 154, 200, 268`. Not a naming defect, but typical naming-audit findings include "unnamed magic strings." Worth a note. -### O8. `PACKAGE_SEGMENT.key` / `.value` carry no descriptive name +### O7. `PACKAGE_SEGMENT.key` / `.value` carry no descriptive name `client.ts:39–42`: `{key: pkgJson.name.replace(/^@[^/]+\//, ''), value: pkgJson.version}`. The variable name `PACKAGE_SEGMENT` reads fine but @@ -433,24 +387,22 @@ identical across every generated client in the workspace. Type & symbol checklist: -- [x] `SseEncryptionAlgorithm` enum (3 members) → O3. -- [x] `VolumeType` enum (2 members) → O6 (clean). +- [x] `SseEncryptionAlgorithm` enum (3 members) → O2. +- [x] `VolumeType` enum (2 members) → O5 (clean). - [x] `CreateVolume` interface (17 fields) → H2, M1, M5, M6. - [x] `DeleteVolume` interface (1 field) → H1, M1, L5. -- [x] `DeleteVolume_Response` empty interface → H3. - [x] `EncryptionDetails` interface → no additional defect. - [x] `GetVolume` interface (2 fields) → H1, M1, L5. - [x] `ListVolumes` interface (5 fields) → M1. -- [x] `ListVolumes_Response` interface (2 fields) → H4. - [x] `SseEncryptionDetails` interface (2 fields) → M3, M4, M5. - [x] `UpdateVolume` interface (18 fields) → H1, H2, M1, M5, M6, L5. -- [x] `VolumeInfo` interface (16 fields) → M2, M5, M6, L5, O4. +- [x] `VolumeInfo` interface (16 fields) → M2, M5, M6, L5, O3. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O8. +- [x] `PACKAGE_SEGMENT` constant → O7. - [x] `createVolume(req, options)` method → H2, M1, M7, L2. -- [x] `deleteVolume(req, options)` method → H1, H3, M1, M7, L2. +- [x] `deleteVolume(req, options)` method → H1, M1, M7, L2. - [x] `getVolume(req, options)` method → H1, M1, M7, L2. -- [x] `listVolumes(req, options)` method → H4, M1, M7, L2. +- [x] `listVolumes(req, options)` method → M1, M7, L2. - [x] `listVolumesIter(req, options)` async generator → M1, M7, L6. - [x] `updateVolume(req, options)` method → H1, H2, M1, M7, L2. - [x] `HttpCallOptions` interface → no defect. diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index 13928f7a..5db46649 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -13,8 +13,7 @@ This audit applies the 20 numbered concern categories from the audit checklist. Each finding lists the offending identifier(s), the category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename suggestion. Findings are grouped by category. Generator-driven -items (such as `_Response` underscore on proto-style nested messages) -are flagged as `LOW` because they are codified across the entire +items are flagged as `LOW` because they are codified across the entire generated SDK surface — they should be fixed at the generator, not by hand-editing this package. @@ -231,8 +230,7 @@ compatibility while updating the customer-visible type names. `pollResp.health?.summary` (`client.ts:661`) — a warehouse health message. - **Suggestion:** Rename to `WarehouseHealth` / - `WarehouseHealth_Status`. The proto-nested style of - `_Status` is a separate finding (F4.x). + `WarehouseHealth_Status`. #### F1.4 — `EndpointTags`, `EndpointTagPair` interface names (HIGH) - **Where:** `model.ts:1115, 1120`, `index.ts:31, 32`. Field @@ -253,8 +251,7 @@ compatibility while updating the customer-visible type names. conflates the legacy "endpoint" term with workspace config. - **Suggestion:** Rename `EndpointConfPair` → `ConfigPair` or `WarehouseConfigPair`. `RepeatedEndpointConfPairs` → - `RepeatedConfigPairs` (the "Repeated" prefix is also a - Go/proto-ism — see F14.3). + `RepeatedConfigPairs`. #### F1.6 — `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` (HIGH) - **Where:** `model.ts:26, 55`, `index.ts:14, 15`. Field on @@ -532,33 +529,7 @@ compatibility while updating the customer-visible type names. ### 4. Underscores in TS identifiers -#### F4.1 — Proto-nested message naming with underscore (HIGH, generator-driven) -- **Where:** - - `CreateWarehouse_Response` (`model.ts:842`) - - `EditWarehouseRequest_Response` (`model.ts:986`) - - `GetWarehouse_Response` (`model.ts:1141`) - - `GetWorkspaceWarehouseConfigRequest_Response` (`model.ts:1258`) - - `SetWorkspaceWarehouseConfigRequest_Response` (`model.ts:1389`) - - `DeleteWarehouseRequest_Response` (`model.ts:1453`) - - `ListWarehousesRequest_Response` (`model.ts:1480`) - - `StartRequest_Response` (`model.ts:1500`) - - `StopRequest_Response` (`model.ts:1512`) - - `TerminationReason_ParametersEntry` (`model.ts:1401`) - - `EndpointHealth_Status` (`model.ts:713`) -- **Why flagged:** Underscores are not idiomatic in TS - identifiers. The `Foo_Response` convention is leaked from the - protobuf nested-message representation. Each affected line has - an `eslint-disable @typescript-eslint/naming-convention` comment - acknowledging this. -- **Suggestion:** Generator-level. Replace with namespaces: - ```ts - export namespace CreateWarehouse { - export interface Response { id?: string } - } - ``` - Or pure name concatenation: `CreateWarehouseResponse`, - `EditWarehouseResponse`, etc. — this matches the convention - used by the rest of the JS SDK for top-level types. +_None._ --- @@ -743,11 +714,9 @@ compatibility while updating the customer-visible type names. belt-and-suspenders signal. Note the inconsistency: some types drop the suffix entirely (`CreateWarehouse`, `GetWarehouse`), others keep it. -- **Suggestion:** Standardize. The `_Response` underscore type - pattern (F4.1) ties the request name to the response name — - if request is `Foo`, response is `Foo_Response`. So - `EditWarehouseRequest` should be `EditWarehouse` for symmetry - with `CreateWarehouse` / `GetWarehouse`. Generator-level. +- **Suggestion:** Standardize. `EditWarehouseRequest` should be + `EditWarehouse` for symmetry with `CreateWarehouse` / + `GetWarehouse`. Generator-level. #### F8.2 — `Name` suffix on `ChannelName` enum (MEDIUM) - **Where:** `model.ts:7`. @@ -770,10 +739,7 @@ compatibility while updating the customer-visible type names. `WarehouseTypeAvailability` (or similar) — wire-aligned but semantically clearer than the `Pair` suffix. -#### F8.4 — `_Response` underscore suffix (HIGH, generator-driven) -- Covered in F4.1. - -#### F8.5 — `Params` suffix on `OdbcParams` (LOW) +#### F8.4 — `Params` suffix on `OdbcParams` (LOW) - **Where:** `model.ts:1329`. - **Why flagged:** Mild noise. Type has `hostname`, `path`, `protocol`, `port` — `OdbcConnectionInfo` would be more @@ -939,14 +905,6 @@ _None. Wrappers are retained for forward compatibility._ `deleteDefaultWarehouseOverride`. Standard CRUD verbs. - **Suggestion:** See F17 below — same root cause. -#### F13.2 — `Repeated` adjective on `RepeatedEndpointConfPairs` (LOW, proto-ism) -- **Where:** `model.ts:1336`. -- **Why flagged:** "Repeated" is proto vocabulary; not English - vocabulary. It means "list of". Reads as "repeated endpoint - conf pairs". -- **Suggestion:** Drop the `Repeated` prefix. Rename to - `EndpointConfPairList` (or `ConfigPairList` per F1.5). - --- ### 14. Go/Java-style names @@ -959,17 +917,7 @@ _None. Wrappers are retained for forward compatibility._ within the same method signature. - **Suggestion:** Generator-level. -#### F14.2 — `Repeated` proto-prefix (LOW) -- Covered in F13.2. - -#### F14.3 — `Params` suffix on types (Java-ish) (LOW) -- `OdbcParams` — minor. See F8.5. - -#### F14.4 — `Pair` suffix (Java-ish) (LOW) -- `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair`. - Covered in F8.3. - -#### F14.5 — `for (;;)` C-style infinite loop (LOW, generator-driven) +#### F14.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) - **Where:** `client.ts:405, 462`, `utils.ts:48`. - **Why flagged:** `for (;;)` is C/Go idiom; TS prefers `while (true)` for readability. Minor. @@ -1113,34 +1061,7 @@ _None. Wrappers are retained for forward compatibility._ ### 18. Long enum values -#### F18.1 — `TerminationCode` — many >40-char identifiers (HIGH) -- **Where:** `model.ts:103-687`. Examples: - - `AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` (50) - - `AZURE_UNEXPECTED_DEPLOYMENT_TEMPLATE_FAILURE` (44) - - `AZURE_PACKED_DEPLOYMENT_PARTIAL_FAILURE` (38) - - `BOOTSTRAP_TIMEOUT_CLOUD_PROVIDER_EXCEPTION` (42) - - `BUDGET_POLICY_LIMIT_ENFORCEMENT_ACTIVATED` (41) - - `ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` (52) - - `NETWORK_CHECK_METADATA_ENDPOINT_FAILURE_DUE_TO_MISCONFIG` (56) - - `SECURITY_AGENTS_FAILED_INITIAL_VERIFICATION` (43) -- **Why flagged:** Identifier readability suffers; switch - statements become unwieldy. Some have `_DUE_TO_MISCONFIG` - suffix that is essentially a sub-category. -- **Suggestion:** Acceptable for backwards compat. Consider - refactoring to a nested enum (category + subcategory) at the - spec level. Generator-driven. - -#### F18.2 — `EndpointSpotInstancePolicy.RELIABILITY_OPTIMIZED` / `COST_OPTIMIZED` (LOW) -- **Where:** `model.ts:78, 80`. -- **Why flagged:** 21-22 char values. Acceptable; descriptive. - -#### F18.3 — `ChannelName.CHANNEL_NAME_*` (LOW, covered by F2.1) -- **Where:** `model.ts:9-12`. -- **Why flagged:** With the prefix stripped (per F2.1), values - become short. Otherwise 23-25 chars. - -#### F18.4 — `DefaultWarehouseOverrideType.DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED` (LOW, covered by F2.2) -- 43 chars. Strip prefix to fix. +_None._ --- @@ -1259,19 +1180,16 @@ _None. Wrappers are retained for forward compatibility._ 3. **Strip redundant enum prefixes (F2.1, F2.2, F2.3, F2.4, F2.5)** — `ChannelName.CHANNEL_NAME_PREVIEW` etc. Trivial generator-level fix; massive readability win. -4. **Drop `_Response` underscore convention (F4.1)** — - namespace or naked concatenation. Generator-level. -5. **Collapse duplicate types (F12.1, F12.2, F12.3)** — +4. **Collapse duplicate types (F12.1, F12.2, F12.3)** — `EndpointInfo` + `GetWarehouse_Response`, `CreateWarehouse` + `EditWarehouseRequest`, `Set*Config` + `Get*Config_Response`. ### Recurring themes -- **Generator-driven proto-isms** (`Repeated`, `_Response`, - `req`/`resp`, `for(;;)`) are the largest single category. - Most are LOW because they are consistent across the entire - SDK; fix at the generator. +- **Generator-driven Go/proto idioms** (`req`/`resp`, + `for(;;)`) are LOW because they are consistent across the + entire SDK; fix at the generator. - **Legacy `Endpoint*` naming** is the package-specific issue. It causes the most readability harm because the package brand is "warehouse" while half the types still say diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md index c48c056a..a3c149c6 100644 --- a/.agent/naming-audit/workspace.md +++ b/.agent/naming-audit/workspace.md @@ -3,7 +3,7 @@ **Path:** `packages/workspace/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks workspace filesystem-style operations on notebooks, folders, and files: import, export, delete, list, get-status, and mkdirs against absolute paths under `/Workspace`. -**Total weird names flagged:** 32 +**Total weird names flagged:** 31 ## Scope note: `workspace` vs sibling packages @@ -25,36 +25,35 @@ The package name `workspace` is the most overloaded of the five — every Databr |---|----------|----------|------|----------| | 1 | High | package | `workspace` | Vague/generic package name (overloaded across 5+ "workspace*" packages) | | 2 | High | `model.ts` interface | `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` | Verb-as-type, reserved-word collisions | -| 3 | High | `model.ts` interface | `Delete_Response`, `Export_Response`, `Import_Response`, `List_Response`, `Mkdirs_Response` | Underscore in TS identifier (Go/proto-style nested message names) | -| 4 | High | `model.ts` enum | `ExportFormat` used as the `format` field of `Import` | Misleading name (an "ExportFormat" governs imports too) | -| 5 | High | `model.ts` enum value | `ExportFormat.AUTO` | Misleading enum value (server inspects content) | -| 6 | High | `model.ts` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | -| 7 | High | `model.ts` enum value | `ObjectType.OBJECT_TYPE_UNSPECIFIED` | Redundant enum prefix + proto sentinel leak | -| 8 | High | `model.ts` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | -| 9 | High | `model.ts` enum | `Language` | Vague/generic, no domain prefix | -| 10 | Medium | `model.ts` enum value | `ObjectType.LIBRARY` | Misleading (library notebooks are an obsolete concept; deprecated in product) | -| 11 | Medium | `model.ts` field | `List.notebooksModifiedAfter` | Field contradicts type domain (list of all objects, filter only on notebooks) | -| 12 | Medium | `model.ts` field | `Export.directDownload` | Verb-as-noun field + boolean named like a noun | -| 13 | Medium | `model.ts` field | `Export_Response.fileType` | Underspecified (raw extension? MIME type? format enum?) | -| 14 | Medium | `model.ts` field | `Export_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | -| 15 | Medium | `model.ts` field | `Import.content` typed `Uint8Array` | Same type/JSDoc mismatch as 14 in the reverse direction | -| 16 | Medium | `model.ts` field | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Underspecified time fields (mtime/ctime? wall clock?) and unit ambiguity (epoch millis as number) | -| 17 | Medium | `model.ts` field | `ObjectInfo.size` | Underspecified (file size in bytes per JSDoc, but no unit in the name) | -| 18 | Medium | `model.ts` field | `Mkdirs.path` | Singular/plural mismatch — type name plural (`Mkdirs`), field singular (`path`) | -| 19 | Medium | `model.ts` type | `Mkdirs` | Cryptic abbreviation (Unix-ism, "mkdirs" not "createDirectory") | -| 20 | Medium | `model.ts` enum value | `Language.R` | Single-letter identifier (clashes with `package R Markdown`) | -| 21 | Medium | `model.ts` enum value | `Language.SCALA`, `PYTHON`, `SQL`, `R` | Missing `LANGUAGE_` prefix elsewhere, raw values overlap with cluster/job runtime names | -| 22 | Medium | `client.ts` method | `getStatus` | Vague verb (status of what?), inconsistent with `list`/`export` | -| 23 | Medium | `model.ts` interface | `GetStatus` | Verb-as-type with no `Request` suffix (whole SDK is inconsistent on this) | -| 24 | Medium | `model.ts` field | `Delete.recursive` | Underspecified boolean (verbatim Unix flag, no domain reading) | -| 25 | Low | `model.ts` enum value | `ExportFormat.R_MARKDOWN` | Underscore inside enum value matches wire, but mixes shape with `JUPYTER`/`HTML` (single tokens) | -| 26 | Low | `model.ts` enum value | `ExportFormat.DBC` | Cryptic abbreviation (Databricks archive) | -| 27 | Low | `model.ts` enum | `ExportOutputs` | Singular/plural — type is `Outputs` (plural), field on `Export` is also `outputs`, values `ALL`/`NONE` describe whether outputs are included | -| 28 | Low | `model.ts` field | `Export.outputs` typed `ExportOutputs` | Field name == type-suffix tautology | -| 29 | Low | `model.ts` interface | `ObjectInfo` | Generic name ("info" suffix used inconsistently across SDK) | -| 30 | Low | `model.ts` field | `List_Response.objects` | Generic field (`objects`) for `ObjectInfo[]` | -| 31 | Low | `client.ts` method | `mkdirs` | Verb-tense / casing inconsistency vs `createDirectory` analog elsewhere in SDK | -| 32 | Low | docstrings | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | +| 3 | High | `model.ts` enum | `ExportFormat` used as the `format` field of `Import` | Misleading name (an "ExportFormat" governs imports too) | +| 4 | High | `model.ts` enum value | `ExportFormat.AUTO` | Misleading enum value (server inspects content) | +| 5 | High | `model.ts` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | +| 6 | High | `model.ts` enum value | `ObjectType.OBJECT_TYPE_UNSPECIFIED` | Redundant enum prefix + proto sentinel leak | +| 7 | High | `model.ts` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | +| 8 | High | `model.ts` enum | `Language` | Vague/generic, no domain prefix | +| 9 | Medium | `model.ts` enum value | `ObjectType.LIBRARY` | Misleading (library notebooks are an obsolete concept; deprecated in product) | +| 10 | Medium | `model.ts` field | `List.notebooksModifiedAfter` | Field contradicts type domain (list of all objects, filter only on notebooks) | +| 11 | Medium | `model.ts` field | `Export.directDownload` | Verb-as-noun field + boolean named like a noun | +| 12 | Medium | `model.ts` field | `Export_Response.fileType` | Underspecified (raw extension? MIME type? format enum?) | +| 13 | Medium | `model.ts` field | `Export_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | +| 14 | Medium | `model.ts` field | `Import.content` typed `Uint8Array` | Same type/JSDoc mismatch as 13 in the reverse direction | +| 15 | Medium | `model.ts` field | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Underspecified time fields (mtime/ctime? wall clock?) and unit ambiguity (epoch millis as number) | +| 16 | Medium | `model.ts` field | `ObjectInfo.size` | Underspecified (file size in bytes per JSDoc, but no unit in the name) | +| 17 | Medium | `model.ts` field | `Mkdirs.path` | Singular/plural mismatch — type name plural (`Mkdirs`), field singular (`path`) | +| 18 | Medium | `model.ts` type | `Mkdirs` | Cryptic abbreviation (Unix-ism, "mkdirs" not "createDirectory") | +| 19 | Medium | `model.ts` enum value | `Language.R` | Single-letter identifier (clashes with `package R Markdown`) | +| 20 | Medium | `model.ts` enum value | `Language.SCALA`, `PYTHON`, `SQL`, `R` | Missing `LANGUAGE_` prefix elsewhere, raw values overlap with cluster/job runtime names | +| 21 | Medium | `client.ts` method | `getStatus` | Vague verb (status of what?), inconsistent with `list`/`export` | +| 22 | Medium | `model.ts` interface | `GetStatus` | Verb-as-type with no `Request` suffix (whole SDK is inconsistent on this) | +| 23 | Medium | `model.ts` field | `Delete.recursive` | Underspecified boolean (verbatim Unix flag, no domain reading) | +| 24 | Low | `model.ts` enum value | `ExportFormat.R_MARKDOWN` | Underscore inside enum value matches wire, but mixes shape with `JUPYTER`/`HTML` (single tokens) | +| 25 | Low | `model.ts` enum value | `ExportFormat.DBC` | Cryptic abbreviation (Databricks archive) | +| 26 | Low | `model.ts` enum | `ExportOutputs` | Singular/plural — type is `Outputs` (plural), field on `Export` is also `outputs`, values `ALL`/`NONE` describe whether outputs are included | +| 27 | Low | `model.ts` field | `Export.outputs` typed `ExportOutputs` | Field name == type-suffix tautology | +| 28 | Low | `model.ts` interface | `ObjectInfo` | Generic name ("info" suffix used inconsistently across SDK) | +| 29 | Low | `model.ts` field | `List_Response.objects` | Generic field (`objects`) for `ObjectInfo[]` | +| 30 | Low | `client.ts` method | `mkdirs` | Verb-tense / casing inconsistency vs `createDirectory` analog elsewhere in SDK | +| 31 | Low | docstrings | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | ## High severity @@ -97,22 +96,7 @@ Every other request type in the SDK follows the pattern `Request` (e Idiomatic TS would be `DeleteRequest` / `DeleteWorkspaceObjectRequest` (matching the rest of the SDK), or shorter: `DeleteRequest` / `ExportRequest` / `ImportRequest` / `ListRequest` / `MkdirsRequest` / `GetStatusRequest`. The current names are 1:1 with the Go SDK's `workspace.Delete`/`workspace.Export` Go struct names — in Go, package-prefixing makes `workspace.Delete` unambiguous; in TS, after `import {Delete} from '@databricks/sdk-workspace/v1'`, the prefix is gone. -### 3. `Delete_Response`, `Export_Response`, `Import_Response`, `List_Response`, `Mkdirs_Response` — underscore in TS identifier - -**Location:** `model.ts:77`, `:111`, `:161`, `:171`, `:185` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention, ... -- Proto-style nested message name. -export interface Delete_Response {} -``` - -Five exported interfaces use a `Foo_Response` shape. The underscore is a proto-style separator for nested message types (`Delete.Response` on the wire). TypeScript naming convention is PascalCase with no underscores; every one of these names triggers `@typescript-eslint/naming-convention` and requires an inline disable. - -Idiomatic TS: `DeleteResponse`, `ExportResponse`, etc. The wire format does not care what the TS type is called. - -The five eslint-disable comments are themselves a smell: a generator producing names that need to be silenced on every line is a sign the generator template is wrong, not that the language is wrong. - -### 4. `ExportFormat` reused for `Import.format` — misleading enum +### 3. `ExportFormat` reused for `Import.format` — misleading enum **Location:** `model.ts:6-25`; used as `Import.format` at `:143` @@ -134,7 +118,7 @@ The enum is named `ExportFormat` but is used as the format for both `Import.form There is also a subtle asymmetry: `Import.format` documents AUTO as "depending on extension," `Export.format` documents AUTO as "depending on object type." Same enum value, different server behaviour per direction. -### 5. `ExportFormat.AUTO` — misleading enum value +### 4. `ExportFormat.AUTO` — misleading enum value **Location:** `model.ts:17-18` @@ -145,7 +129,7 @@ AUTO = 'AUTO', `AUTO` reads as "automatic file selection," but the value means "server inspects payload bytes to guess the file type." For an export request, "AUTO" means "decide based on the object's type." The single token serves two different inferred behaviors. `DETECT_FROM_CONTENT` / `DETECT_FROM_OBJECT` (split into two enums) would be honest. -### 6. `ExportFormat.RAW` — vague enum value +### 5. `ExportFormat.RAW` — vague enum value **Location:** `model.ts:19-24` @@ -162,7 +146,7 @@ RAW = 'RAW', `ZIP_PASSTHROUGH` or `BINARY` would describe the actual data path. Right now a reader sees `ExportFormat.RAW` and has to read three lines of JSDoc to understand it. -### 7. `ObjectType.OBJECT_TYPE_UNSPECIFIED` — redundant enum prefix + proto sentinel leak +### 6. `ObjectType.OBJECT_TYPE_UNSPECIFIED` — redundant enum prefix + proto sentinel leak **Location:** `model.ts:48-52` @@ -183,7 +167,7 @@ Two problems in one value: 1. Enum prefix repetition: the enum is `ObjectType`, the value is `OBJECT_TYPE_UNSPECIFIED`. Every value would be readable as `ObjectType.NOTEBOOK` — the others (good) drop the prefix; this one (bad) retains it. The proto-style `_UNSPECIFIED` is documented as a proto convention, not a TS one. 2. Proto sentinel leak: the JSDoc explicitly says this value is only used by `list-repo` for graceful unsupported-type handling. It is a server implementation detail. A TS consumer constructing an `ObjectInfo` should never set this. Like `Aggregation.UNKNOWN` and similar leaks elsewhere, this is the proto default-value mechanism surfacing into the SDK. -### 8. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names +### 7. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names **Location:** `model.ts:209-214` @@ -201,7 +185,7 @@ Likely truth: `objectId` is the legacy 64-bit workspace-local numeric ID; `resou Also, `objectId` is typed `number` — JavaScript numbers are 64-bit float; if the server ID exceeds 2^53, precision is lost. Other SDK types use `bigint` or string for similar IDs. -### 9. `Language` — vague/generic, no domain prefix +### 8. `Language` — vague/generic, no domain prefix **Location:** `model.ts:35-44` @@ -221,7 +205,7 @@ A top-level export named `Language` in a domain package. Many other SDK packages ## Medium severity -### 10. `ObjectType.LIBRARY` — obsolete concept +### 9. `ObjectType.LIBRARY` — obsolete concept **Location:** `model.ts:55` @@ -236,7 +220,7 @@ DASHBOARD = 'DASHBOARD', Workspace "libraries" (as a top-level object type) are obsolete — Databricks moved libraries to cluster-level and job-level configurations. The value is exported without a deprecation marker and without JSDoc explanation. Consumers writing `if (obj.objectType === ObjectType.LIBRARY)` are coding against a dead branch. -### 11. `List.notebooksModifiedAfter` — field contradicts type domain +### 10. `List.notebooksModifiedAfter` — field contradicts type domain **Location:** `model.ts:163-168` @@ -253,9 +237,9 @@ export interface List { `modifiedAfterMillis` (without the `notebooks` prefix) or `notebookModifiedAfterMillis` (with the singular subject matching the filter's actual scope) would describe what the server does. -The unit (`milliseconds`) is in JSDoc only, not in the field name. Other timestamp fields in the same file are documented in milliseconds but named `createdAt` / `modifiedAt`. Inconsistent — see finding 17. +The unit (`milliseconds`) is in JSDoc only, not in the field name. Other timestamp fields in the same file are documented in milliseconds but named `createdAt` / `modifiedAt`. Inconsistent — see finding 15. -### 12. `Export.directDownload` — verb-as-noun field, weak boolean +### 11. `Export.directDownload` — verb-as-noun field, weak boolean **Location:** `model.ts:96-99` @@ -271,7 +255,7 @@ directDownload?: boolean | undefined; The flag also has a semantic problem: when `true`, the response body is raw bytes; when `false`, the response body is a JSON object with base64. So the field changes the entire response content type, but the generated client (`export` method) parses the response identically in both cases. Setting `directDownload: true` would crash the parser. -### 13. `Export_Response.fileType` — underspecified +### 12. `Export_Response.fileType` — underspecified **Location:** `model.ts:117-119` @@ -284,7 +268,7 @@ The doc says "the file type" but doesn't say in what form. Is it the extension ( `mimeType`, `extension`, or `format: ExportFormat` would commit. -### 14. `Export_Response.content` typed `Uint8Array` with "base64-encoded" doc +### 13. `Export_Response.content` typed `Uint8Array` with "base64-encoded" doc **Location:** `model.ts:112-116` @@ -298,7 +282,7 @@ content?: Uint8Array | undefined; The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw bytes). The client decodes base64 before populating this field, so the field actually holds decoded bytes, contradicting the JSDoc. The JSDoc was lifted from the wire format documentation and not updated for the post-decode TS shape. A reader holding the type sees "Uint8Array of base64-encoded data," which is technically meaningless (Uint8Arrays are bytes, not base64). -### 15. `Import.content` typed `Uint8Array` with "base64-encoded" doc +### 14. `Import.content` typed `Uint8Array` with "base64-encoded" doc **Location:** `model.ts:146-152` @@ -311,9 +295,9 @@ The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw byte content?: Uint8Array | undefined; ``` -Mirror of finding 14 in the reverse direction. The client encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. +Mirror of finding 13 in the reverse direction. The client encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. -### 16. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision +### 15. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision **Location:** `model.ts:204-208` @@ -329,7 +313,7 @@ Two issues: 1. The names use the `At` suffix (TS-friendly) but the type is `number`. Unit (milliseconds vs seconds) is documented nowhere in this type. The companion `List.notebooksModifiedAfter` is documented as milliseconds; one infers consistency, but the type does not declare it. Most of the SDK uses `Temporal.Instant` for `At`-suffixed timestamps; here it's `number`. 2. "Only applicable to files" — the field is on `ObjectInfo`, which also describes notebooks, directories, etc. Setting expectations via "only applicable" in JSDoc is a code smell: the field shape doesn't change based on object type. -### 17. `ObjectInfo.size` — underspecified +### 16. `ObjectInfo.size` — underspecified **Location:** `model.ts:210-211` @@ -340,7 +324,7 @@ size?: number | undefined; `size` is a unit-less name. JSDoc says "file size in bytes can be returned" (the "can be" is also ambiguous — is it always returned for files?). `sizeBytes` or `sizeInBytes` is the convention used elsewhere in Databricks SDKs (`clusters.clusterMemoryMb`, `pipelines.storageBytes`). At scale-up time (>4GiB) `number` loses precision; `bigint` or `string` would be safer. -### 18. `Mkdirs.path` — singular/plural mismatch with the type name +### 17. `Mkdirs.path` — singular/plural mismatch with the type name **Location:** `model.ts:176-182` @@ -356,7 +340,7 @@ export interface Mkdirs { The type is plural (`Mkdirs` — "make directories"), but it takes one path. The pluralization comes from the Unix `mkdir -p` semantics ("makes the directory and any missing parent directories"), but the input is a single path. A user reading `Mkdirs` expects to pass an array. -### 19. `Mkdirs` — Unix-ism +### 18. `Mkdirs` — Unix-ism **Location:** `model.ts:176`; `client.ts:254` @@ -364,7 +348,7 @@ The type is plural (`Mkdirs` — "make directories"), but it takes one path. The Also: the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the request body holds one path. So even at the wire level, the name is misleading. -### 20. `Language.R` — single-letter identifier +### 19. `Language.R` — single-letter identifier **Location:** `model.ts:43` @@ -379,7 +363,7 @@ export enum Language { `Language.R` is the only single-character enum value in the package. Auto-import tools, grep, and refactoring tools handle one-letter identifiers poorly. The wire format also uses just `R`, so a rename in the SDK would need a string mapping; nonetheless, `Language.R_LANG` (matching the `R_MARKDOWN` format value) or simply documenting `R` more thoroughly would help. -### 21. `Language` values — no `LANGUAGE_` prefix, overlap with runtime names +### 20. `Language` values — no `LANGUAGE_` prefix, overlap with runtime names **Location:** `model.ts:35-44` @@ -394,7 +378,7 @@ The enum values are bare language names that collide with cluster runtime IDs (` Other SDK enums add a prefix (`TaskType.PYTHON_WHEEL_TASK`); this one does not. -### 22. `getStatus` — vague verb on the client +### 21. `getStatus` — vague verb on the client **Location:** `client.ts:154` @@ -404,9 +388,9 @@ async getStatus(req: GetStatus, options?: CallOptions): Promise "Status" of what? In TS SDKs, `getStatus` usually returns a status enum or a small status object (e.g., job run status). Here it returns full `ObjectInfo` metadata — a filesystem `stat`, not a status. The Files API uses `getMetadata`. The Go SDK uses `GetStatus` (from `os.Stat` ancestry). Either `getMetadata` or `stat` would describe the actual operation. -The method also returns `Promise` while `list` returns `Promise` — inconsistent shape (one returns the bare entity, one returns a wrapper). See finding 30. +The method also returns `Promise` while `list` returns `Promise` — inconsistent shape (one returns the bare entity, one returns a wrapper). See finding 29. -### 23. `GetStatus` — verb-as-type without `Request` suffix +### 22. `GetStatus` — verb-as-type without `Request` suffix **Location:** `model.ts:121-124` @@ -419,7 +403,7 @@ export interface GetStatus { Combined with finding 2, `GetStatus` is the only request type whose name is composed of two verbs. The other request types (`Delete`, `Export`, `Import`, `List`, `Mkdirs`) are single verbs. The package mixes the two patterns. `GetStatusRequest` is what the rest of the SDK uses. -### 24. `Delete.recursive` — Unix flag, no domain reading +### 23. `Delete.recursive` — Unix flag, no domain reading **Location:** `model.ts:69-73` @@ -436,7 +420,7 @@ recursive?: boolean | undefined; ## Low severity -### 25. `ExportFormat.R_MARKDOWN` — shape mismatch within enum +### 24. `ExportFormat.R_MARKDOWN` — shape mismatch within enum **Location:** `model.ts:15-16` @@ -452,7 +436,7 @@ RAW = 'RAW', Five of the seven values are single tokens; one is `R_MARKDOWN` with an underscore. SQL convention would also be `RMARKDOWN` or `RMD`. Inconsistent shape inside the same enum. -### 26. `ExportFormat.DBC` — cryptic abbreviation +### 25. `ExportFormat.DBC` — cryptic abbreviation **Location:** `model.ts:13-14` @@ -463,7 +447,7 @@ DBC = 'DBC', DBC = "Databricks Archive." The acronym is product-specific. `DATABRICKS_ARCHIVE` would be readable. Wire-format compatibility (`DBC` is what the server expects) means the rename has to happen in the enum-key layer, not the enum-value layer — which TS supports cleanly. -### 27. `ExportOutputs` — plural enum type for ALL/NONE values +### 26. `ExportOutputs` — plural enum type for ALL/NONE values **Location:** `model.ts:27-32` @@ -480,7 +464,7 @@ The enum models "which outputs to include" but is named `ExportOutputs` (plural) Also: JSDoc on `Export.outputs` says "only ALL or NONE is documented publically, DATABRICKS is internal only" — admits there's a hidden third value, which means the enum is not exhaustive. -### 28. `Export.outputs` typed `ExportOutputs` — type-suffix tautology +### 27. `Export.outputs` typed `ExportOutputs` — type-suffix tautology **Location:** `model.ts:104-106` @@ -490,13 +474,13 @@ outputs?: ExportOutputs | undefined; Field and type both spell `outputs`. The user types `req.outputs = ExportOutputs.ALL`. Idiomatic phrasing would be `req.outputInclusion = OutputInclusion.ALL` or `req.includeOutputs = true`. -### 29. `ObjectInfo` — `Info` suffix used inconsistently across SDK +### 28. `ObjectInfo` — `Info` suffix used inconsistently across SDK **Location:** `model.ts:188-214` The `Info` suffix is a Go/Java convention for "POJO that describes a thing." TS SDKs vary: some use bare entity names (`Catalog`, `Cluster`), some use `Info`/`Details`. This package's only entity type is `ObjectInfo`. There is no companion `Object` — so the name reads consistently with itself, but the suffix is purely a hat-tip to Go. -### 30. `List_Response.objects` — generic field for `ObjectInfo[]` +### 29. `List_Response.objects` — generic field for `ObjectInfo[]` **Location:** `model.ts:171-174` @@ -509,7 +493,7 @@ export interface List_Response { `objects` is the most generic JavaScript noun; it tells the reader nothing. `items`, `entries`, `paths`, or `workspaceObjects` would convey scope. The Go SDK has the same `Objects` field; transferring the name without adaptation gives a TS user a `resp.objects` access that reads like "the objects of the response." -### 31. `mkdirs` — verb-tense / casing inconsistency +### 30. `mkdirs` — verb-tense / casing inconsistency **Location:** `client.ts:254` @@ -519,7 +503,7 @@ async mkdirs(req: Mkdirs, options?: CallOptions): Promise Other client methods read as verb-noun (`export`, `import`, `list`) or compound verb (`getStatus`). `mkdirs` is the only Unix-style contraction. The class also has a `delete` method (matches HTTP verb) but no `make` or `create` method. `createDirectory` would align with `delete` semantically. -### 32. First-person and ticket-driven prose in public JSDoc +### 31. First-person and ticket-driven prose in public JSDoc **Location:** `model.ts:17-18`, `:19-24` @@ -542,19 +526,17 @@ RAW = 'RAW', 2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) and `ObjectInfo.resourceId` (string, unified-resource) are both returned, both documented as "unique identifier for the object," with no naming clue about which one to pass where. This is the single most user-hostile naming issue in the file. -3. **The `Foo_Response` underscore is a generator template error.** Five interfaces named `_Response` each need a `@typescript-eslint/naming-convention` disable for the underscore. The names exist only because the Go SDK declares `Delete.Response` as a nested struct that proto/Go renders as `Delete_Response`. In TS, the underscore is not necessary — `DeleteResponse` would satisfy the naming convention and read the same. - -4. **`ExportFormat` is the import format.** The single enum services both `Import` and `Export` (good — DRY), but the name says only "Export." A neutral name (`NotebookFormat` or `WorkspaceObjectFormat`) would describe what it actually is. +3. **`ExportFormat` is the import format.** The single enum services both `Import` and `Export` (good — DRY), but the name says only "Export." A neutral name (`NotebookFormat` or `WorkspaceObjectFormat`) would describe what it actually is. -5. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` on `Import` means "detect from file extension + header," and `AUTO` on `Export` means "decide from object type." Same enum value, different server-side algorithm. +4. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` on `Import` means "detect from file extension + header," and `AUTO` on `Export` means "decide from object type." Same enum value, different server-side algorithm. -6. **Verb-as-type request names without `Request` suffix.** Six request interfaces (`Delete`, `Export`, `GetStatus`, `Import`, `List`, `Mkdirs`) ship without the `Request` suffix that the rest of the SDK uses. Combined with collisions against ES reserved-context words (`import`, `export`, `delete`), this makes the type names unusable without the package qualifier — which is exactly what TS users lose at import time. +5. **Verb-as-type request names without `Request` suffix.** Six request interfaces (`Delete`, `Export`, `GetStatus`, `Import`, `List`, `Mkdirs`) ship without the `Request` suffix that the rest of the SDK uses. Combined with collisions against ES reserved-context words (`import`, `export`, `delete`), this makes the type names unusable without the package qualifier — which is exactly what TS users lose at import time. -7. **`content: Uint8Array` documented as base64 in both directions.** Two fields hold post-decode bytes but their JSDoc reads as if they still hold base64 strings. A defensive user reading the JSDoc and base64-encoding their bytes will double-encode on the way in. The mismatch is silent and the failure mode is data corruption. +6. **`content: Uint8Array` documented as base64 in both directions.** Two fields hold post-decode bytes but their JSDoc reads as if they still hold base64 strings. A defensive user reading the JSDoc and base64-encoding their bytes will double-encode on the way in. The mismatch is silent and the failure mode is data corruption. -8. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear elsewhere in the SDK.** The `files` package uses `createDirectory` and `getMetadata`. The `repos` package uses `getRepo`. Picking one verb per concept and applying it across packages would let users transfer knowledge. +7. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear elsewhere in the SDK.** The `files` package uses `createDirectory` and `getMetadata`. The `repos` package uses `getRepo`. Picking one verb per concept and applying it across packages would let users transfer knowledge. -9. **Sentinel `OBJECT_TYPE_UNSPECIFIED` documented as "only used by list-repo."** The enum exports a value that the package consumers should never set but cannot remove without breaking the read side. A separate response-only enum or a `null` for "unknown" would be cleaner. +8. **Sentinel `OBJECT_TYPE_UNSPECIFIED` documented as "only used by list-repo."** The enum exports a value that the package consumers should never set but cannot remove without breaking the read side. A separate response-only enum or a `null` for "unknown" would be cleaner. ## Domain glossary diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md index ee1c7b52..870e5fd6 100644 --- a/.agent/naming-audit/workspaceassignment.md +++ b/.agent/naming-audit/workspaceassignment.md @@ -13,6 +13,7 @@ | Low | 6 | | Observation | 1 | + ## High severity ### 1. Package name `workspaceassignment` (singular) vs API path `/permissionassignments` — package directory / `src/v1/client.ts:78,106,146,174` @@ -88,9 +89,9 @@ - **Rationale:** Public Databricks workspace IDs cross 2^53 in account-level deployments; silent rounding bugs are a real risk. Same concern applies to `principalId`. ### 12. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:42 vs 60,119` -- **Why weird:** `GetWorkspacePermissionAssignments_Response.permissionAssignments` is the list of assigned-principal records (with role). `ListWorkspacePermissions_Response.permissions` is the list of *permission types*. `WorkspacePermissionAssignmentOutput.permissions` is the *roles a single principal holds*. Three different things, two of them just called `permissions`. +- **Why weird:** The response for `getWorkspacePermissionAssignments` carries `permissionAssignments` (list of assigned-principal records with role). The response for `listWorkspacePermissions` carries `permissions` (list of *permission types*). `WorkspacePermissionAssignmentOutput.permissions` is the *roles a single principal holds*. Three different things, two of them just called `permissions`. - **Category:** 1 (vague), 15 (generic field name loses meaning), 17 (inconsistent label across siblings). -- **Suggested name:** On `ListWorkspacePermissions_Response`, rename `permissions` to `supportedPermissions` or `availablePermissions`. On `WorkspacePermissionAssignmentOutput`, rename `permissions` to `permissionLevels` or `grantedPermissions` to match the singular `permissionLevel` in `PermissionOutput`. +- **Suggested name:** On the list-permissions response, rename `permissions` to `supportedPermissions` or `availablePermissions`. On `WorkspacePermissionAssignmentOutput`, rename `permissions` to `permissionLevels` or `grantedPermissions` to match the singular `permissionLevel` in `PermissionOutput`. - **Rationale:** A user holding the response sees `.permissions` and can't tell whether it's "permissions held" or "permission types defined". ### 13. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:64 vs 119` @@ -194,7 +195,7 @@ - **Rationale:** Cf. finding 5 + 6. Worth flagging once more as a pair-level observation. ## Cross-cutting themes -1. **Proto/Go-style names leak through generation.** Findings 3, 4, 7, 9 trace to the upstream Go SDK's protobuf-derived shapes: `*_UNSPECIFIED` / `UNKNOWN` enum sentinels, `*Output` suffixes, verb-phrase request type names, and double-wrapped oneof discriminators. None are idiomatic TS. +1. **Non-idiomatic TS shapes.** Findings 3, 4, 7, 9 — `UNKNOWN` enum sentinel, verb-phrase request type names, `*Output` suffixes, and double-wrapped oneof discriminators. None are idiomatic TS. 2. **Duplicated domain modelling with `iam` package.** Findings 1, 2, 8, 9, 19 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. 3. **Misleading verb assignment for list vs get.** Findings 5, 6, 28 — the paginated method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. 4. **Underspecified IDs and weak typing.** Findings 10, 11, 17, 24 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index 456064a5..71aec3f7 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -3,17 +3,17 @@ **Path:** `packages/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 37 +**Total weird names flagged:** 33 ## Summary | Severity | Count | | --- | --- | -| High | 14 | +| High | 10 | | Medium | 17 | | Low | 2 | | Observation | 4 | -The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **proto-style nested-message names** like `GetWorkspaceBindings_Response` leaking into the TS surface and requiring `eslint-disable` directives at every declaration and at every use site; (2) **the request-type-as-verb pattern** (`GetWorkspaceBindings`, `UpdateWorkspaceBindings`, `GetCatalogWorkspaceBindings`, `UpdateCatalogWorkspaceBindings`) producing the awkward `getWorkspaceBindings(req: GetWorkspaceBindings)` verb-noun-verb-noun signature; (3) **enum values that bake the type name back into every member** (`BindingType.BINDING_TYPE_READ_WRITE` etc.); (4) **stringly-typed `securableType`** that should be a closed enum; (5) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (6) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction. +The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **the request-type-as-verb pattern** (`GetWorkspaceBindings`, `UpdateWorkspaceBindings`, `GetCatalogWorkspaceBindings`, `UpdateCatalogWorkspaceBindings`) producing the awkward `getWorkspaceBindings(req: GetWorkspaceBindings)` verb-noun-verb-noun signature; (2) **enum values that bake the type name back into every member** (`BindingType.BINDING_TYPE_READ_WRITE` etc.); (3) **stringly-typed `securableType`** that should be a closed enum; (4) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (5) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction, and the verbs "bind"/"assign" are mixed inside a single request type (`UpdateCatalogWorkspaceBindings.assignWorkspaces`). --- @@ -33,75 +33,51 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ### 3. `GetCatalogWorkspaceBindings` (type) — `src/v1/model.ts:12` - **Why weird:** Top-level request type whose name is an imperative verb phrase ("Get Catalog Workspace Bindings"). TS types should be nouns; verbs are reserved for methods. The Client also has a method `getCatalogWorkspaceBindings` (`client.ts:75`) that takes this type as input, producing the verb-noun-verb-noun signature `getCatalogWorkspaceBindings(req: GetCatalogWorkspaceBindings)`. Readers cannot tell from the type whether the identifier names the operation or the request shape. -- **Category:** 7 (overly verbose), 14 (Go-style request-type naming), 17 (inconsistent action verbs). +- **Category:** 7 (overly verbose), 17 (inconsistent action verbs). - **Suggested name:** `GetCatalogWorkspaceBindingsRequest` or `CatalogWorkspaceBindingsQuery`. Best: rename to noun form (e.g. `CatalogBindingsLookup`) to break the verb collision entirely. - **Rationale:** Sibling SDK packages already adopt the `*Request` suffix convention. Internal consistency. ### 4. `GetWorkspaceBindings` (type) — `src/v1/model.ts:23` - **Why weird:** Same problem as #3. Verb-shaped request type collides with `getWorkspaceBindings` method (`client.ts:111`). -- **Category:** 7, 14, 17. +- **Category:** 7, 17. - **Suggested name:** `GetWorkspaceBindingsRequest` or `WorkspaceBindingsListRequest`. - **Rationale:** See #3. ### 5. `UpdateCatalogWorkspaceBindings` (type) — `src/v1/model.ts:51` - **Why weird:** Same problem as #3. Verb-shaped request type collides with `updateCatalogWorkspaceBindings` method (`client.ts:168`). -- **Category:** 7, 14, 17. +- **Category:** 7, 17. - **Suggested name:** `UpdateCatalogWorkspaceBindingsRequest` or `CatalogWorkspaceBindingsPatch`. - **Rationale:** See #3. ### 6. `UpdateWorkspaceBindings` (type) — `src/v1/model.ts:66` - **Why weird:** Same problem as #3. Verb-shaped request type collides with `updateWorkspaceBindings` method (`client.ts:203`). -- **Category:** 7, 14, 17. +- **Category:** 7, 17. - **Suggested name:** `UpdateWorkspaceBindingsRequest` or `WorkspaceBindingsPatch`. - **Rationale:** See #3. -### 7. `GetCatalogWorkspaceBindings_Response` — `src/v1/model.ts:18` -- **Why weird:** Proto-style nested message name (`MessageType_FieldName`) with an embedded underscore — non-idiomatic in TS. Requires `// eslint-disable-next-line @typescript-eslint/naming-convention` to compile (line 17). The wart is fully visible in the public API: consumers must write `GetCatalogWorkspaceBindings_Response` with the underscore at every use site (`client.ts:22`, `client.ts:78`, `index.ts:9`). -- **Category:** 4 (underscore in TS identifier), 14 (proto/Go-style name). -- **Suggested name:** `GetCatalogWorkspaceBindingsResponse` (drop the underscore) — or, combined with #3, `CatalogWorkspaceBindingsResponse`. -- **Rationale:** Google TS style guide § 5.2 forbids internal underscores in PascalCase identifiers. The proto FQN-flattening hack should be hidden by the generator. - -### 8. `GetWorkspaceBindings_Response` — `src/v1/model.ts:41` -- **Why weird:** Same as #7. -- **Category:** 4, 14. -- **Suggested name:** `GetWorkspaceBindingsResponse` or `WorkspaceBindingsPage` (since this is the paginated response shape). -- **Rationale:** See #7. - -### 9. `UpdateCatalogWorkspaceBindings_Response` — `src/v1/model.ts:61` -- **Why weird:** Same as #7. Particularly long: 39 characters. -- **Category:** 4, 7 (verbose), 14. -- **Suggested name:** `UpdateCatalogWorkspaceBindingsResponse` (drop the underscore). -- **Rationale:** See #7. - -### 10. `UpdateWorkspaceBindings_Response` — `src/v1/model.ts:83` -- **Why weird:** Same as #7. -- **Category:** 4, 14. -- **Suggested name:** `UpdateWorkspaceBindingsResponse` or `WorkspaceBindingsResponse`. -- **Rationale:** See #7. - -### 11. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` +### 7. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` - **Why weird:** Free-form `string` for what is a closed set of values. The doc-comment explicitly lists them: "(catalog, storage_credential, credential, or external_location)" — meaning the API author *knows* the set is closed but chose not to type it. A typo like `"caatalog"` will silently 4xx at the server. Also, the path is constructed via `${req.securableType ?? ''}` (`client.ts:115`, `client.ts:207`) which means an undefined value will produce a URL like `/api/2.1/unity-catalog/bindings//...` — a routing-incidental 404. - **Category:** 19 (underspecified ID/discriminator), 1 (vague), 16 (field contradicts type domain). - **Suggested name:** Define a `SecurableType` enum (`CATALOG`, `STORAGE_CREDENTIAL`, `CREDENTIAL`, `EXTERNAL_LOCATION`) and type both fields accordingly. - **Rationale:** Type-safety is the entire point of TypeScript. Other UC packages in the SDK also use bare `string` for securable types — same fix should apply across all of them. -### 12. `securableFullName` vs `catalogName` inconsistency — `src/v1/model.ts:14,53` vs `27,69` +### 8. `securableFullName` vs `catalogName` inconsistency — `src/v1/model.ts:14,53` vs `27,69` - **Why weird:** The same conceptual value (the fully-qualified name of the securable being bound) is named two different ways depending on which request type you're looking at. `Get/UpdateCatalogWorkspaceBindings` use `catalogName` (because the legacy endpoint is catalog-specific). `Get/UpdateWorkspaceBindings` use `securableFullName` (because the generic endpoint accepts any securable). For a catalog binding, both names refer to the same string. Users porting from one variant to the other must change the field name. - **Category:** 17 (inconsistent naming), 15 (one is a special case of the other). - **Suggested name:** Use `fullName` everywhere (or `name`), since `securableType` already provides the discriminator. Drop the special-case `catalogName` field once the legacy API is gone. - **Rationale:** Two field names for one logical value is a documentation and onboarding tax. -### 13. Concept duplication: catalog-specific vs generic securable APIs — entire file +### 9. Concept duplication: catalog-specific vs generic securable APIs — entire file - **Why weird:** The package ships two parallel surfaces: - `Get/UpdateCatalogWorkspaceBindings` operate on `/workspace-bindings/catalogs/{name}` (catalog-only legacy). - `Get/UpdateWorkspaceBindings` operate on `/bindings/{securable_type}/{full_name}` (generic). -- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes (#12), different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). +- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes (#8), different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). - The legacy methods cannot express `READ_ONLY` bindings (they only return/accept workspace IDs, no `BindingType`) — meaning the catalog-specific API is strictly less expressive than the generic one. Yet both are shipped. - **Category:** 12 (duplicate concept within one package), 17 (inconsistency), Observation. - **Suggested name:** Either deprecate the catalog-specific surface (mark with `@deprecated`) and direct users to `getWorkspaceBindings({securableType: 'catalog', securableFullName: name})`, or rename the catalog-specific variant to make its legacy status explicit (e.g. `getCatalogWorkspaceBindingsLegacy`). - **Rationale:** Two surfaces for one operation, where one is strictly weaker, is a footgun. -### 14. Concept overlap with sibling package `workspaceassignment` — cross-package +### 10. Concept overlap with sibling package `workspaceassignment` — cross-package - **Why weird:** A sibling package `packages/workspaceassignment/src/v1/` covers `WorkspacePermissionAssignment` — assigning **principals** (users, groups, service principals) to **workspaces**. The current package `workspacebindings` covers `WorkspaceBindingInfo` — assigning **securables** (catalogs, credentials, etc.) to **workspaces**. Both use the noun "workspace" and an "assign"/"bind" verb. A user searching the SDK for "how do I associate X with a workspace" will find both packages and must read both READMEs to disambiguate. There is no surface-level disambiguation in the type or method names. `workspaceassignment` even has an `assign_workspaces` / `unassign_workspaces` field in `UpdateCatalogWorkspaceBindings` (line 55, 57) — using the verb "assign" inside the *bindings* package. - **Category:** 12 (duplicate concept across packages), 17 (inconsistent verbs: "bind" vs "assign" used for adjacent operations). - **Suggested name:** Either align the verbs (both as "assign" or both as "bind") or rename one package to disambiguate directionally — e.g. `workspacebindings` → `securableworkspacebindings` or `ucbindings`; `workspaceassignment` → `workspaceprincipalassignment`. At minimum, pick one verb across the two packages. @@ -111,103 +87,103 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Medium severity -### 15. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` +### 11. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` - **Why weird:** `Info` suffix is a Go-style convention (`*Info` types in `databricks/sdk-go` are pervasive: `CatalogInfo`, `TableInfo`, `SchemaInfo`...). In TS the suffix carries no information — the type *is* the binding, not a separate "info-about-the-binding" record. Just two fields: `workspaceId` and `bindingType`. - **Category:** 14 (Go-style name), 8 (redundant suffix). - **Suggested name:** `WorkspaceBinding`. - **Rationale:** Drop Go suffixes when porting; sibling packages have already done this for some types but not consistently. -### 16. `workspaces?: number[]` (field, multiple) — `src/v1/model.ts:20,63` +### 12. `workspaces?: number[]` (field, multiple) — `src/v1/model.ts:20,63` - **Why weird:** Generic field name "workspaces" for what is actually a list of workspace IDs (not workspace objects). The doc-comment says "A list of workspace IDs" — so the wire/value is IDs, but the field is named after the entity. A consumer might reasonably expect `workspaces: Workspace[]` and be surprised by `number[]`. - **Category:** 6 (misleading: name implies entity, value is ID), 15 (generic field name), 16 (field contradicts type domain), 19 (underspecified ID). - **Suggested name:** `workspaceIds`. -- **Rationale:** Pair with `assignWorkspaces`/`unassignWorkspaces` (which have the same problem, #17, #18) for consistency. +- **Rationale:** Pair with `assignWorkspaces`/`unassignWorkspaces` (which have the same problem, #13, #14) for consistency. -### 17. `assignWorkspaces?: number[]` — `src/v1/model.ts:55` -- **Why weird:** Same problem as #16 — the field is a list of workspace IDs but is named after the entity ("workspaces"). The leading verb "assign" turns the field into a verb-phrase ("assign workspaces"), which reads as an imperative ("please assign workspaces") rather than a noun ("the set of workspace IDs to assign"). Additionally, the verb "assign" is inconsistent with the package noun "bindings" (see #14). +### 13. `assignWorkspaces?: number[]` — `src/v1/model.ts:55` +- **Why weird:** Same problem as #12 — the field is a list of workspace IDs but is named after the entity ("workspaces"). The leading verb "assign" turns the field into a verb-phrase ("assign workspaces"), which reads as an imperative ("please assign workspaces") rather than a noun ("the set of workspace IDs to assign"). Additionally, the verb "assign" is inconsistent with the package noun "bindings" (see #10). - **Category:** 6 (misleading), 17 (verb inconsistency), 19 (underspecified ID), 15 (generic field). - **Suggested name:** `workspaceIdsToBind` or `addWorkspaceIds`, matching the `add` / `remove` pattern used in the generic `UpdateWorkspaceBindings` (lines 76, 78). - **Rationale:** Aligns vocabulary with package noun (binding, not assign) and clarifies the field is IDs. -### 18. `unassignWorkspaces?: number[]` — `src/v1/model.ts:57` -- **Why weird:** Same problems as #17, plus: "unassign" is a verb invented for this pair (it isn't a real English word in most dictionaries — "unassign" appears in software contexts but is dispreferred to "remove" or "revoke"). The companion field is `assignWorkspaces`, so the prefix matters here. +### 14. `unassignWorkspaces?: number[]` — `src/v1/model.ts:57` +- **Why weird:** Same problems as #13, plus: "unassign" is a verb invented for this pair (it isn't a real English word in most dictionaries — "unassign" appears in software contexts but is dispreferred to "remove" or "revoke"). The companion field is `assignWorkspaces`, so the prefix matters here. - **Category:** 6, 17, 5 (cryptic neologism), 19. - **Suggested name:** `workspaceIdsToUnbind` or `removeWorkspaceIds`. -- **Rationale:** See #17. +- **Rationale:** See #13. -### 19. `bindings?: WorkspaceBindingInfo[]` (field, multiple) — `src/v1/model.ts:43,85` +### 15. `bindings?: WorkspaceBindingInfo[]` (field, multiple) — `src/v1/model.ts:43,85` - **Why weird:** Field name `bindings` on a `WorkspaceBindings` response type — repeats the type-name fragment. The surrounding context already says "this is the workspace bindings response", so the field could safely be `items`. - **Category:** 20 (type-suffix tautology), 15 (generic). - **Suggested name:** `items` or `workspaceBindings` (more specific). - **Rationale:** A field on `XResponse` named after `X` is redundant. -### 20. `add?: WorkspaceBindingInfo[]` / `remove?: WorkspaceBindingInfo[]` — `src/v1/model.ts:76,78` +### 16. `add?: WorkspaceBindingInfo[]` / `remove?: WorkspaceBindingInfo[]` — `src/v1/model.ts:76,78` - **Why weird:** Bare verb-shaped field names (`add`, `remove`). On a `UpdateWorkspaceBindings` payload, these are *what* gets added/removed (a list of bindings), but the field names read as imperatives. The doc-comments clarify, but the field names themselves carry no noun. - **Category:** 1 (vague), 15 (generic), 17 (verb inconsistency with the catalog-specific `assignWorkspaces`/`unassignWorkspaces`). - **Suggested name:** `addBindings` / `removeBindings`, or `bindingsToAdd` / `bindingsToRemove`, or `granted` / `revoked`. - **Rationale:** A bare `add: WorkspaceBindingInfo[]` carries no noun. Common in change-set APIs but typically paired with a typed item collection. -### 21. `workspaceId?: number` — `src/v1/model.ts:90` -- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` (#16) and `assignWorkspaces?: number[]` (#17) — all three would need to migrate together. +### 17. `workspaceId?: number` — `src/v1/model.ts:90` +- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` (#12) and `assignWorkspaces?: number[]` (#13) — all three would need to migrate together. - **Category:** 16 (field contradicts type domain: 64-bit IDs typed as JS number), 19 (underspecified). - **Suggested name:** Keep the name `workspaceId` but consider `bigint` or `string` for the type. This is a project-wide concern. - **Rationale:** Cross-cutting JS interop issue; not unique to this package, but flagged for completeness. -### 22. `bindingType?: BindingType` — `src/v1/model.ts:92` +### 18. `bindingType?: BindingType` — `src/v1/model.ts:92` - **Why weird:** Field name `bindingType` on a type called `WorkspaceBindingInfo` repeats the type-name fragment "binding". Combined with #1, the call site reads `binding.bindingType === BindingType.BINDING_TYPE_READ_WRITE` — "binding"/"binding"/"binding type"/"binding type" four times in one expression. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `accessLevel` (more descriptive — the value indicates read/write vs read-only access), or just `type` (since context is clear). - **Rationale:** Field on `XBindingInfo` named `xBindingType` is doubly redundant. -### 23. `maxResults?: number` — `src/v1/model.ts:35` +### 19. `maxResults?: number` — `src/v1/model.ts:35` - **Why weird:** 12 lines of doc-comment for one field explain its conditional behaviour ("set to 0" / "set to a value greater than 0" / "set to a value less than 0" / "if not set"). The field name `maxResults` doesn't hint at the magic-value semantics. Also, sibling packages use `pageSize` for the same concept (see grants audit #18) — naming inconsistency across the SDK. - **Category:** 17 (cross-package inconsistency), 6 (misleading: name implies a strict cap but actually has magic-value semantics). - **Suggested name:** `pageSize` (matching sibling packages) or `pageLength`. Document the magic values via a `@see` link rather than copy-pasting 12 lines. - **Rationale:** Cross-package consistency. -### 24. `pageToken?: string` doc — `src/v1/model.ts:36-37` +### 20. `pageToken?: string` doc — `src/v1/model.ts:36-37` - **Why weird:** Doc-comment "Opaque pagination token to go to next page based on previous query" is OK, but in the response side `nextPageToken` (line 45-48) the doc refers to "__page_token__" with double-underscores — a documentation hangover from a wire-format spec. Inconsistent with the TS field name `pageToken`. - **Category:** 6 (misleading docs), Observation. - **Suggested name:** Field name is fine; fix the doc to use TS field name `pageToken`. - **Rationale:** Doc-comment consistency. -### 25. `nextPageToken?: string` — `src/v1/model.ts:48` +### 21. `nextPageToken?: string` — `src/v1/model.ts:48` - **Why weird:** The doc-comment includes `__page_token__` (double-underscore) referring to the request field. The actual TS field is named `pageToken` — the doc is documenting wire format, not TS. - **Category:** 6 (misleading docs). - **Suggested name:** Field name is fine; fix the doc text. -- **Rationale:** See #24. +- **Rationale:** See #20. -### 26. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:75` -- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #13). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 71-74 makes no mention of the generic alternative. +### 22. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:75` +- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #9). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 71-74 makes no mention of the generic alternative. - **Category:** 12 (duplicate concept), Observation. - **Suggested name:** Mark with `@deprecated` JSDoc and reference `getWorkspaceBindings`. - **Rationale:** IDE strike-through requires the `@deprecated` tag. -### 27. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:168` -- **Why weird:** Same as #26. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. +### 23. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:168` +- **Why weird:** Same as #22. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. - **Category:** 12, Observation. - **Suggested name:** Mark with `@deprecated`. -- **Rationale:** See #26. +- **Rationale:** See #22. -### 28. `Client` — `src/v1/client.ts:46` +### 24. `Client` — `src/v1/client.ts:46` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `WorkspaceBindingsClient`. - **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. -### 29. `executeCall` — `src/v1/utils.ts:26` +### 25. `executeCall` — `src/v1/utils.ts:26` - **Why weird:** Generic verb-noun name. Two `execute` functions in scope (`execute` imported on line 4, `executeCall` defined on line 26, `executeHttpCall` defined on line 65). The discriminator between them is just "Call" vs "HttpCall" — and both ultimately wrap the imported `execute()`. - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `executeRetryableCall` (since this one applies the retrier/rateLimiter/timeout options) or `executeWithOptions`. - **Rationale:** Distinguishes the two wrappers semantically. -### 30. `executeHttpCall` — `src/v1/utils.ts:65` +### 26. `executeHttpCall` — `src/v1/utils.ts:65` - **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `APIError` on 4xx/5xx (line 88-91) — a non-obvious side effect. - **Category:** 1 (vague), 6 (misleading: "execute" sounds neutral but throws). - **Suggested name:** `sendAndParseResponse` or `sendOrThrow`. - **Rationale:** Naming should hint at error semantics. -### 31. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` +### 27. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` - **Why weird:** Yet another `*Options` suffix in a file that already imports `Options` (line 3) and `CallOptions` (line 12) — three `Options` types in scope. `HttpCallOptions` is purely an internal context bag for `executeHttpCall` (request + httpClient + logger) — it isn't user-tunable, so `Options` is misleading. - **Category:** 1 (vague suffix), 8 (redundant suffix), 17 (inconsistency). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -217,13 +193,13 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Low severity -### 32. `flattenQueryParams` — `src/v1/utils.ts:123` +### 28. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append` on `client.ts:117-122`). Dead-looking export from the standard generator template. - **Category:** Observation, 11 (unused public helper). - **Suggested name:** Remove if generator default; or move to a shared utility package and not emit per-package. - **Rationale:** Cross-package consistency. -### 33. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 29. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -233,18 +209,18 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Observations -### 34. Client `Host is required.` error message — `src/v1/client.ts:57` +### 30. Client `Host is required.` error message — `src/v1/client.ts:57` The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. - **Category:** Observation. -### 35. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` +### 31. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` The marshal/unmarshal helpers are exported from `model.ts` (via `export const`) but `index.ts` (lines 7-17) only re-exports types and `Client`. So the schemas are part of the package's effective import surface (`import {...} from '@databricks/sdk-workspacebindings/v1/model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). - **Category:** Observation, 11 (effectively-internal exports). -### 36. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` +### 32. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` The single word "Required" appears as a doc-comment on `workspaceId?: number`. But the field is *optional* in the TypeScript type (`workspaceId?: number | undefined`). The annotation contradicts the type modifier. Either: (a) the field is genuinely required by the server and the optional TS type is generator-wide policy (proto3 fields are all optional in TS); or (b) the doc is stale. Either way, readers can't tell. - **Category:** Observation, 6 (misleading docs). -### 37. `BindingType` doc-comment surfaces proto comment as TS doc — `src/v1/model.ts:5` +### 33. `BindingType` doc-comment surfaces proto comment as TS doc — `src/v1/model.ts:5` The comment "Using `BINDING_TYPE_` prefix here to avoid conflict with `TableOperation` enum in `credentials_common.proto`." is a wire-implementation note that has been promoted to a TS doc-comment. TS consumers should not need to know about proto namespaces. This is naming-adjacent — the comment exists *because* of the redundant prefix (#1, #2). Removing the prefix would also remove the need for the explanation. - **Category:** Observation, 14 (proto-style naming surfaced in docs). diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md index 35b738d5..a3598fa0 100644 --- a/.agent/naming-audit/workspacesettings.md +++ b/.agent/naming-audit/workspacesettings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/workspacesettings/` **Versions audited:** v1 **Inferred domain:** Workspace-scoped Databricks settings: AI/BI dashboard embedding policy, automatic cluster update, compliance security profile (CSP), dashboard email subscriptions, default namespace, default warehouse ID, legacy access/DBFS disablement, notebook/file export, notebook table clipboard, results download (notebook and SQL), enhanced security monitoring (ESM), LLM proxy partner-powered AI, and restrict-workspace-admins. -**Total weird names flagged:** 51 +**Total weird names flagged:** 45 ## Summary table @@ -12,52 +12,48 @@ | 1 | Critical | Duplicate concept across packages | `workspacesettings` vs `settings` vs `accountsettings` vs `workspaceconf` | package boundary | | 2 | Critical | Duplicate type | `BooleanMessage`, `StringMessage` (also in `accountsettings`, `settings/v2`) | `model.ts:186, 1034` | | 3 | Critical | Duplicate type | `ComplianceStandard` (also in `accountsettings`) | `model.ts:8` | -| 4 | Critical | Duplicate type | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_*`, `RestrictWorkspaceAdminsMessage_Status` (also in `settings/v2`) | `model.ts:57, 65, 77, 89` | -| 5 | Critical | Duplicate concept | `RestrictWorkspaceAdminsSetting`, `AibiDashboardEmbeddingAccessPolicySetting` etc. mirror types in `settings/v2` | `model.ts:991, 104` and `settings/v2` | -| 6 | High | Cryptic abbreviation | `Aibi` (`AI/BI`) family of types/methods | `model.ts:57-160, 104-160`; `client.ts:335,377,752,792,1257,1292` | -| 7 | High | Cryptic abbreviation | `Csp` (Compliance Security Profile) | `model.ts:244-273`; `client.ts:872, 1365`; URL `shield_csp_enablement_ws_db` | -| 8 | High | Cryptic abbreviation | `Esm` (Enhanced Security Monitoring) | `model.ts:706-733`; `client.ts:1100,1556`; URL `shield_esm_enablement_ws_db` | -| 9 | High | Cryptic abbreviation | `Llm` (LLM Proxy Partner-Powered Workspace) | `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624,1140,1588` | -| 10 | High | Cryptic abbreviation | `Dbfs` casing (`disableLegacyDbfs`) | `model.ts:514-541, 651-670, 855-868, 1122-1129`; `client.ts:584,1063,1521` | -| 11 | High | Underscore in TS identifier | Eight `*_*_*` proto-style nested names (e.g. `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`) | `model.ts:57, 65, 77, 89, 207, 217, 224, 235` | -| 12 | High | Generic / cryptic enum sentinel | `STATUS_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10, 58, 66, 78, 91` | -| 13 | High | Redundant enum prefix | All five enums prefix the type name into every value | `model.ts:8-102` | -| 14 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` | -| 15 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:340-345, 382-387, 425-430, 469-474, ...` | -| 16 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:321-338` | -| 17 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | -| 18 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | -| 19 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:630-649` | -| 20 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:651-670` | -| 21 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:672-680` | -| 22 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:682-690` | -| 23 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:692-700` | -| 24 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:692, 1015` | -| 25 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:692 vs 1015`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | -| 26 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:939-956` | -| 27 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:181, 1248` | -| 28 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:269, 729` | -| 29 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:195` | -| 30 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:192` | -| 31 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:213` | -| 32 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:209, 211` | -| 33 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | -| 34 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:321, 1102` | -| 35 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:71, 102` | -| 36 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:672, 682, 692, 630, 651` | -| 37 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:672, 682` | -| 38 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | -| 39 | Medium | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS`, `SECOND_AND_FOURTH_OF_MONTH`, `FIRST_AND_THIRD_OF_MONTH`, `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `FEDRAMP_MODERATE`, etc. | `model.ts:19-53, 83, 84, 101` | -| 40 | Medium | Long enum value | `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`, `ALLOW_ALL_DOMAINS` | `model.ts:59-61` | -| 41 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:988` | -| 42 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | -| 43 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 1104, 956, 1369, 1560` | -| 44 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:112-117, 252-259, 1024` | -| 45 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:248` | -| 46 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:135` | -| 47 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | -| 48 | Low | Verb-tense inconsistency | `Patch*` request types vs `Update*` request types for same HTTP verb | `model.ts:959, 967, 975 vs 1040, 1050, 1062, ...` | -| 49 | Low | Duplicate type | `Delete*Response` (10 types) duplicated across sibling settings packages | `model.ts:356-628` | +| 4 | Critical | Duplicate concept | `RestrictWorkspaceAdminsSetting`, `AibiDashboardEmbeddingAccessPolicySetting` etc. mirror types in `settings/v2` | `model.ts:991, 104` and `settings/v2` | +| 5 | High | Cryptic abbreviation | `Aibi` (`AI/BI`) family of types/methods | `model.ts:57-160, 104-160`; `client.ts:335,377,752,792,1257,1292` | +| 6 | High | Cryptic abbreviation | `Csp` (Compliance Security Profile) | `model.ts:244-273`; `client.ts:872, 1365`; URL `shield_csp_enablement_ws_db` | +| 7 | High | Cryptic abbreviation | `Esm` (Enhanced Security Monitoring) | `model.ts:706-733`; `client.ts:1100,1556`; URL `shield_esm_enablement_ws_db` | +| 8 | High | Cryptic abbreviation | `Llm` (LLM Proxy Partner-Powered Workspace) | `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624,1140,1588` | +| 9 | High | Cryptic abbreviation | `Dbfs` casing (`disableLegacyDbfs`) | `model.ts:514-541, 651-670, 855-868, 1122-1129`; `client.ts:584,1063,1521` | +| 10 | High | Generic / cryptic enum sentinel | `STATUS_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10, 58, 66, 78, 91` | +| 11 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` | +| 12 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:340-345, 382-387, 425-430, 469-474, ...` | +| 13 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:321-338` | +| 14 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | +| 15 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | +| 16 | High | Triple-stutter against package name | `*Setting` suffix on every type in `workspacesettings` package | `model.ts:104, 244, 706, 991, 1015` and passim | +| 17 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:630-649` | +| 18 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:651-670` | +| 19 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:672-680` | +| 20 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:682-690` | +| 21 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:692-700` | +| 22 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:692, 1015` | +| 23 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:692 vs 1015`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | +| 24 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:939-956` | +| 25 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:181, 1248` | +| 26 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:269, 729` | +| 27 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:195` | +| 28 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:192` | +| 29 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:213` | +| 30 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:209, 211` | +| 31 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | +| 32 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:321, 1102` | +| 33 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:71, 102` | +| 34 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:672, 682, 692, 630, 651` | +| 35 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:672, 682` | +| 36 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | +| 37 | Medium | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS`, `SECOND_AND_FOURTH_OF_MONTH`, `FIRST_AND_THIRD_OF_MONTH`, `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `FEDRAMP_MODERATE`, etc. | `model.ts:19-53, 83, 84, 101` | +| 38 | Medium | Long enum value | `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`, `ALLOW_ALL_DOMAINS` | `model.ts:59-61` | +| 39 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:988` | +| 40 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | +| 41 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 1104, 956, 1369, 1560` | +| 42 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:112-117, 252-259, 1024` | +| 43 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:248` | +| 44 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:135` | +| 45 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | --- @@ -71,7 +67,7 @@ - Generic public-setting CRUD (the umbrella API) → `settings/v2`. - Account-IP-access, CSP/ESM at account scope, disable-legacy-features, LLM-proxy at account scope, personal compute → `accountsettings`. - Arbitrary workspace conf KV → `workspaceconf`. - No documentation surfaces this taxonomy; the consumer has to guess. The four packages share types verbatim (`BooleanMessage`, `ComplianceStandard`, `RestrictWorkspaceAdminsMessage_Status`, `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_*`) and the `settings/v2` package already exposes a generic `Setting`/`SettingsMetadata` shape that *can* represent any of these. The split is purely a wire-routing artefact. + No documentation surfaces this taxonomy; the consumer has to guess. The four packages share types verbatim and the `settings/v2` package already exposes a generic `Setting`/`SettingsMetadata` shape that *can* represent any of these. The split is purely a wire-routing artefact. ### 2. `BooleanMessage`, `StringMessage` — duplicated in three sibling packages - **File:line:** `model.ts:186-188, 1034-1037` @@ -85,13 +81,7 @@ - **Suggestion:** Hoist into a shared `compliance` module. The enum has 15 values, all canonical regulatory standards (HIPAA, PCI_DSS, FEDRAMP_*, etc.) that do not differ by setting scope. - **Rationale:** HIPAA at the account level *is* HIPAA at the workspace level. Two enums with identical members means type-incompatible values for the same regulatory concept. -### 4. Proto-style nested enums duplicated in `settings/v2` -- **File:line:** `model.ts:57, 65, 77, 89` (here) vs same names in `settings/v2` -- **Category:** Duplicate type -- **Suggestion:** Same as #3 — share. `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, and `RestrictWorkspaceAdminsMessage_Status` all appear identically in `settings/v2/model.ts`. -- **Rationale:** Same justification as #3: enums whose semantics are identical across packages should be defined once. Today, `workspacesettings.AibiDashboardEmbeddingAccessPolicy_AccessPolicyType.ALLOW_ALL_DOMAINS` is not assignable to `settings.AibiDashboardEmbeddingAccessPolicy_AccessPolicyType.ALLOW_ALL_DOMAINS`. - -### 5. Whole types mirrored in `settings/v2` +### 4. Whole types mirrored in `settings/v2` - **File:line:** `model.ts:104, 138, 244, 251, 691, 711, 982, 991` vs `settings/v2/model.ts` - **Category:** Duplicate concept - **Suggestion:** Pick one canonical home. `settings/v2` is clearly the generic surface (it exposes `Setting`, `SettingsMetadata`, `PatchPublicWorkspaceSettingRequest`). The specific-typed methods in `workspacesettings` are a sister API for the same backend data. Either fold the specific methods into `settings/v2` (preferred) or document which one is canonical. @@ -101,221 +91,215 @@ ## High severity -### 6. `Aibi*` family — cryptic acronym not expanded in identifier +### 5. `Aibi*` family — cryptic acronym not expanded in identifier - **File:line:** `model.ts:57-160`; client.ts six methods - **Category:** Cryptic abbreviation, acronym casing - **Suggestion:** Either spell as `AiBiDashboardEmbedding*` (matching Databricks marketing) or `AIBIDashboardEmbedding*` (strict acronym casing). The current `Aibi` parses as one token, hiding the AI + BI = analytics-product structure. - **Rationale:** "AI/BI dashboards" is the user-facing product name (confirmed in the JSDoc on `client.ts:749`). The wire path even uses `aibi_dash_embed_ws_acc_policy` — itself heavily abbreviated. A new reader cannot guess that `Aibi` means "AI + BI." TS style guide prefers acronym capitalization for known acronyms (`URL`, `HTTP`, `AI`, `BI`). -### 7. `Csp*` family — undocumented acronym +### 6. `Csp*` family — undocumented acronym - **File:line:** `model.ts:244-273`; URL slug `shield_csp_enablement_ws_db` - **Category:** Cryptic abbreviation - **Suggestion:** `ComplianceSecurityProfile*` everywhere (it's already spelled out in the JSDoc on line 243). The class methods are already named `ComplianceSecurityProfile`; only the wire slug is `csp`, which is fine on the wire but should not be exposed. - **Rationale:** Identical issue to `accountsettings`. CSP overloads catastrophically with web "Content Security Policy." Outside this codebase, that is the dominant meaning. The TS-side type name is `ComplianceSecurityProfile` (good!) but the wire and the `_workspace` suffix in `complianceSecurityProfileWorkspace` discriminator is still cryptic-adjacent. -### 8. `Esm*` family — undocumented acronym +### 7. `Esm*` family — undocumented acronym - **File:line:** `model.ts:706-733`; URL slug `shield_esm_enablement_ws_db`; `client.ts:1100, 1556` - **Category:** Cryptic abbreviation - **Suggestion:** `EnhancedSecurityMonitoring*` everywhere on TS side. Wire `esm` is fine. -- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #28). +- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #26). -### 9. `Llm*` family — acronym casing + verb stacking +### 8. `Llm*` family — acronym casing + verb stacking - **File:line:** `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624, 1140, 1588` - **Category:** Cryptic abbreviation + Acronym casing - **Suggestion:** Spell out: `ModelProxyPartnerPoweredWorkspace` or `LargeLanguageModelProxyPartnerPoweredWorkspace` (admittedly long). Better: drop "Workspace" since the package name already scopes it → `LlmProxyPartnerPowered`. Better still: collapse to `PartnerPoweredAi` (the doc on `client.ts:1139` explicitly calls it "partner powered AI features"). - **Rationale:** `LlmProxyPartnerPoweredWorkspace` is 31 characters parsing as five concepts: LLM-Proxy-Partner-Powered-Workspace. Without context, a reader cannot tell whether "PartnerPowered" modifies "Llm" or modifies "Workspace." `Llm` (one word) violates TS acronym casing. -### 10. `Dbfs` casing +### 9. `Dbfs` casing - **File:line:** `model.ts:514-541, 651-670, 855-868, 1122-1129` - **Category:** Acronym casing - **Suggestion:** `DBFS` (it's an acronym — Databricks File System). Apply consistently: `DisableLegacyDBFS`, `disableLegacyDBFS`, `GetDisableLegacyDBFSRequest`. - **Rationale:** TS style for known acronyms is uppercase. The wire is `disable_legacy_dbfs` (lowercase) which is fine, but the TS surface should be `DBFS`. The codebase is internally consistent in using `Dbfs` everywhere, so this is a global rename. -### 11. Eight proto-style nested-name types with underscores -- **File:line:** `model.ts:57, 65, 77, 89, 207, 217, 224, 235` -- **Category:** Underscore in TS identifier, Go/Java-style names -- **Suggestion:** Hoist nested types to top-level with concatenated names: `MaintenanceWindow`, `MaintenanceWindowWeekDayFrequency`, `MaintenanceWindowDayOfWeek`, `MaintenanceWindowWeekDayBasedSchedule`, `MaintenanceWindowWindowStartTime`, `ClusterAutoRestartEnablementDetails`, etc. — or scope them as a TS `namespace ClusterAutoRestartMessage { ... }`. -- **Rationale:** TS identifiers conventionally use PascalCase without underscores. Each of these eight identifiers has an `// eslint-disable-next-line @typescript-eslint/naming-convention` comment, which is the codebase admitting the violation. The deepest nesting (`ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`) is 54 characters — and contains "Window" twice. This is generator-level technical debt visible to the consumer. - -### 12. Sentinel enum values: `*_UNSPECIFIED` +### 10. Sentinel enum values: `*_UNSPECIFIED` - **File:line:** `model.ts:10, 58, 66, 78, 91` -- **Category:** Redundant enum prefix, long enum value -- **Suggestion:** Either omit the sentinel entirely (TS-idiomatic; use `undefined`) or rename to `UNSPECIFIED`. The current `COMPLIANCE_STANDARD_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `STATUS_UNSPECIFIED` triple-stutter the enum name. -- **Rationale:** TS enum members are accessed via `EnumName.MEMBER`, so `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` reads as `ComplianceStandard.ComplianceStandard.Unspecified`. The doc comment on line 9 explicitly says "Sentinel value, should not be used in prod" — yet the type forces the consumer to consider it. Idiomatic TS represents "unspecified" with `T | undefined`. +- **Category:** Sentinel enum value +- **Suggestion:** Either omit the sentinel entirely (TS-idiomatic; use `undefined`) or rename to `UNSPECIFIED`. The current `COMPLIANCE_STANDARD_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `STATUS_UNSPECIFIED` are sentinel values flagged by their docstrings as "should not be used in prod." +- **Rationale:** The doc comment on line 9 explicitly says "Sentinel value, should not be used in prod" — yet the type forces the consumer to consider it. Idiomatic TS represents "unspecified" with `T | undefined`. -### 13. All enum values prefixed with the enum-name token -- **File:line:** `model.ts:8-102` -- **Category:** Redundant enum prefix -- **Suggestion:** Strip prefixes. `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.MONDAY` is fine; `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` only adds noise — the `DAY_OF_WEEK_` is the enum-name token bleeding into the member. -- **Rationale:** Symmetrical with #12 — the noise is the proto3 convention of prefixing every member name with the enum name (to avoid C++ enum-scope collisions). TS scopes enums; the prefix is redundant. - -### 14. `settingName` documented as not respected on requests +### 11. `settingName` documented as not respected on requests - **File:line:** `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` - **Category:** Misleading - **Suggestion:** Mark `settingName` `readonly` on the response-only path; remove it from request bodies; or split request/response types so it is only present where meaningful. At minimum, the docstring should not say "this field is populated in the response, but it will not be respected even if it's set in the request body." - **Rationale:** A 17-times-repeated 240-character JSDoc admits that the field is server-ignored on PATCH/UPDATE. The field is forced to `"default"` server-side. Exposing it in the public API surface only invites users to set it, expect it to take effect, and then debug why it didn't. -### 15. `settingTypeName` query parameter ignored +### 12. `settingTypeName` query parameter ignored - **File:line:** `client.ts:340-345, 382-387, 425-430, 469-474, 510-515, 550-555, 590-595, 630-635, 675-680, 715-720, 758-763, 798-803, 838-843, 878-883, 918-923, 958-963, 994-999, 1032-1037, 1068-1073, 1106-1111, 1146-1151, 1186-1191, 1226-1231` - **Category:** Misleading - **Suggestion:** Drop from the request type — the path parameter (`/api/2.0/settings/types/aibi_dash_embed_ws_acc_policy/names/default`) makes the query parameter redundant. The client serializes the path slug for the user; there is no reason to also expose the slug as a `settingTypeName` query param. - **Rationale:** Every Get/Delete/Update sets the URL path to a hard-coded slug (e.g. `aibi_dash_embed_ws_acc_policy`) and then *also* lets the user populate `settingTypeName` and `settingName` as query params. If a user sets `settingTypeName: 'foo'`, the path still wins; the field is window dressing. -### 16. `DefaultWarehouseId` envelope holds no warehouse-ID field directly +### 13. `DefaultWarehouseId` envelope holds no warehouse-ID field directly - **File:line:** `model.ts:321-338` - **Category:** Underspecified ID, misleading - **Suggestion:** `interface DefaultWarehouse { id?: string; etag?: string; }` — a flat, non-envelope, no-wrapper type. Or hide the envelope completely and let the client method return `string | undefined`. - **Rationale:** A reader sees `DefaultWarehouseId` and expects a `string` (or numeric ID). What they get is a four-layer struct: `defaultWarehouseId.value.stringVal.value` is the actual ID. Plus the type lacks any documentation about whether the warehouse ID is numeric (e.g. `1234`) or string-shaped (e.g. `0abc...d`). The Databricks warehouse-ID convention is opaque alphanumeric; this should be documented. -### 17. `patch*` vs `update*` methods for the same PATCH HTTP verb +### 14. `patch*` vs `update*` methods for the same PATCH HTTP verb - **File:line:** `client.ts:192 (patchEnableExportNotebook), 249 (patchEnableNotebookTableClipboard), 306 (patchEnableResultsDownloading)` vs `client.ts:1257 (updateAibi...), 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657 (update*)` - **Category:** Inconsistent action verbs - **Suggestion:** Standardize on `update*`. The three `patch*` methods are anomalies — every other PATCH method in the package is named `update*` and every API in the SDK reading from CRUD elsewhere uses `update*`. - **Rationale:** Three of 26 methods (`patchEnableExportNotebook`, `patchEnableNotebookTableClipboard`, `patchEnableResultsDownloading`) use the verb `patch` instead of `update`, even though all 14 PATCH-method-using siblings use `update`. The HTTP verb is the same (`PATCH`). The naming inconsistency causes consumer discovery problems. -### 18. `delete*` methods that actually "revert" to default +### 15. `delete*` methods that actually "revert" to default - **File:line:** `client.ts:335 (deleteAibi...AccessPolicySetting), 377, 419, 464, 504, 544, 584, 624, 669, 709` - **Category:** Inconsistent action verbs / misleading - **Suggestion:** `resetToDefault*` or `reset*`. The doc literally reads "Reverts the SQL Results Download setting to its default value" (line 708), "Reverts the Dashboard Email Subscriptions setting to its default value" (line 418), "Reverts the enable partner powered AI features workspace setting to its default value" (line 623), etc. — the semantic is reset, not delete. - **Rationale:** A `delete` method that doesn't delete is the worst kind of misleading verb. The HTTP verb is `DELETE` but that is the *server's* idiom for "remove the override and fall back to default." The SDK can wrap with `reset*` and hide the wire detail. +### 16. `*Setting` triple-stutter against the `workspacesettings` package name +- **File:line:** `model.ts:104 (AibiDashboardEmbeddingAccessPolicySetting), 244 (ComplianceSecurityProfileSetting), 706 (EnhancedSecurityMonitoringSetting), 991 (RestrictWorkspaceAdminsSetting), 1015 (SqlResultsDownload — exception)` and ~14 more +- **Category:** Triple-stutter against package name +- **Suggestion:** Drop the `Setting` suffix. The package is already `workspacesettings`, so `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` reads as "the access-policy setting setting setting." Use `workspacesettings.AibiDashboardEmbeddingAccessPolicy` etc. +- **Rationale:** Every primary type in the package carries a `Setting` suffix despite the package name being `workspacesettings`. The qualified path triple-states "settings." Sibling `SqlResultsDownload` (without `Setting` suffix) shows the cleaner alternative. + --- ## Medium severity -### 19. `DisableLegacyAccess` — verb-phrase as type name +### 17. `DisableLegacyAccess` — verb-phrase as type name - **File:line:** `model.ts:630-649` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `LegacyAccessDisablement` or `LegacyAccessToggle`. Types describing settings should be nouns. - **Rationale:** `DisableLegacyAccess` reads as an imperative ("perform the action of disabling legacy access") rather than a state ("the legacy-access-disabled toggle setting"). The discriminator name `disableLegacyAccess` inside `.value.disableLegacyAccess: BooleanMessage` doubles the verb. -### 20. `DisableLegacyDbfs` — verb-phrase as type name +### 18. `DisableLegacyDbfs` — verb-phrase as type name - **File:line:** `model.ts:651-670` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `LegacyDBFSDisablement` or `LegacyDBFSToggle`. -- **Rationale:** Same as #19. +- **Rationale:** Same as #17. -### 21. `EnableExportNotebook` — verb-phrase as type name +### 19. `EnableExportNotebook` — verb-phrase as type name - **File:line:** `model.ts:672-680` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `NotebookExportToggle` or `NotebookExportEnabled`. -- **Rationale:** Same as #19 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. +- **Rationale:** Same as #17 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. -### 22. `EnableNotebookTableClipboard` — verb-phrase as type name +### 20. `EnableNotebookTableClipboard` — verb-phrase as type name - **File:line:** `model.ts:682-690` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `NotebookTableClipboardToggle`. -- **Rationale:** Same as #19. +- **Rationale:** Same as #17. -### 23. `EnableResultsDownloading` — verb + gerund mash +### 21. `EnableResultsDownloading` — verb + gerund mash - **File:line:** `model.ts:692-700` - **Category:** Verb-tense / verb-in-noun position + gerund mismatch - **Suggestion:** `NotebookResultsDownloadToggle` (matches the doc on `client.ts:280` "Notebook results download setting"). - **Rationale:** `EnableResultsDownloading` mixes imperative `Enable` with gerund `Downloading`. The sibling type `SqlResultsDownload` (no `-ing`, no `Enable`) does the same thing for SQL. The inconsistency is severe — same domain, two different naming conventions. -### 24. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package +### 22. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package - **File:line:** `model.ts:692, 1015` - **Category:** Verb-tense / -ing gerund inconsistency - **Suggestion:** Pick one form. Either both as `*Toggle` or both as `Enable*Downloading`. - **Rationale:** Both control downloading of query results. The notebook variant is `EnableResultsDownloading` (gerund). The SQL variant is `SqlResultsDownload` (noun). The pair was authored at different times by different teams and the inconsistency leaked into the API. -### 25. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap +### 23. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap - **File:line:** `model.ts:692, 1015` - **Category:** Misleading / parallel naming - **Suggestion:** Unify under one type with a discriminator: `ResultsDownloadToggle { context: 'notebook' | 'sql', enabled: boolean }`. - **Rationale:** The doc on `client.ts:280` calls one "Notebook results download" and the doc on `client.ts:1219` calls the other "SQL Results Download." They have the same shape and similar semantics — but the methods, types, and wire slugs are all separate. This is duplicated wiring at the API surface. -### 26. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix +### 24. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix - **File:line:** `model.ts:939-956` - **Category:** Misleading - **Suggestion:** Drop `Workspace`. The package name is `workspacesettings`, so every type is workspace-scoped. The suffix exists only to mirror `LlmProxyPartnerPoweredAccount` in `accountsettings` — which is symmetrical but ill-justified (both should drop their scope suffix). - **Rationale:** Compare to siblings: `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, `SqlResultsDownload`, `EnableExportNotebook` — none of them carry the "Workspace" suffix despite being workspace-scoped. `LlmProxyPartnerPoweredWorkspace` is the outlier. -### 27. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" +### 25. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" - **File:line:** `model.ts:181, 1248` - **Category:** Misleading - **Suggestion:** `clusterAutoRestart` (matches the actual data type, `ClusterAutoRestartMessage`). - **Rationale:** Inside `AutomaticClusterUpdateSetting.value.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage` — the discriminator name uses one phrase ("automatic cluster update workspace") while the type uses another ("cluster auto restart"). The reader must mentally bridge "automatic cluster update" with "cluster auto restart." -### 28. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" +### 26. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" - **File:line:** `model.ts:269, 729` - **Category:** Misleading - **Suggestion:** Drop "Workspace" suffix: `complianceSecurityProfile`, `enhancedSecurityMonitoring`. -- **Rationale:** Same as #26. +- **Rationale:** Same as #24. -### 29. `restartEvenIfNoUpdatesAvailable` — double negative +### 27. `restartEvenIfNoUpdatesAvailable` — double negative - **File:line:** `model.ts:195` - **Category:** Misleading - **Suggestion:** `restartUnconditionally` (or invert: `skipIfNoUpdates` with opposite default). - **Rationale:** "Restart even if no updates available" is a triple-conditional that takes effort to parse. The semantics are "restart regardless of update availability." Boolean fields should read as clean predicates. -### 30. `canToggle` — vague boolean +### 28. `canToggle` — vague boolean - **File:line:** `model.ts:192` - **Category:** Misleading - **Suggestion:** `isToggleable` or `canBeDisabledByCustomer`. - **Rationale:** `canToggle` on its own does not specify *what* can be toggled or by *whom*. From context (`ClusterAutoRestartMessage`), this likely means "can the customer toggle the auto-restart setting." The name does not convey that. -### 31. `forcedForComplianceMode` — past-participle as flag +### 29. `forcedForComplianceMode` — past-participle as flag - **File:line:** `model.ts:213` - **Category:** Misleading - **Suggestion:** `isForcedByComplianceMode` or `forcedDueToComplianceMode`. - **Rationale:** `forcedFor` reads ambiguously — "for the purpose of" or "due to"? The doc on line 212 ("The feature is force enabled if compliance mode is active") confirms the meaning is "due to." -### 32. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative +### 30. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative - **File:line:** `model.ts:209, 211` - **Category:** Misleading - **Suggestion:** Invert: `requiresEnterpriseTier`, `requiresEntitlement` — read more naturally. - **Rationale:** "Unavailable for non-enterprise" requires reasoning over two negatives. "Requires enterprise" is a positive predicate. -### 33. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` +### 31. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` - **File:line:** Throughout model.ts and client.ts - **Category:** Acronym casing - **Suggestion:** Apply TS-conventional casing — `DBFS`, `AIBI` (or `AiBi`), `LLM`, `CSP`, `ESM`, `SQL` — or, where they are domain acronyms, document expansion. The codebase is internally consistent in using `Pascal-token-case` for all of them, but this contradicts the TS style guide and the JSDoc which uses correct casing (`AI/BI`, `LLM`, `SQL`, etc. in prose). - **Rationale:** JSDoc has it right; identifiers don't. -### 34. `Id` vs `ID` casing +### 32. `Id` vs `ID` casing - **File:line:** `model.ts:321, 1102` (`DefaultWarehouseId`, `UpdateDefaultWarehouseIdRequest`, `defaultWarehouseId` method) - **Category:** Acronym casing - **Suggestion:** `DefaultWarehouseID`, `UpdateDefaultWarehouseIDRequest` — or, if `Id` is house style, document it explicitly. Pick one and apply globally. - **Rationale:** Established TS code is split — some major SDKs use `Id` (consistent with `Pascal-token-case`), others use `ID` (matches HTTP/spec convention). The Go SDK uses `Id`. The Databricks JS SDK should pick one and apply it everywhere; today, "Id" is used here but "ESM/CSP/LLM" suggests acronym capitalization is house style. -### 35. `Url` casing +### 33. `Url` casing - **File:line:** `utils.ts:71, 102` - **Category:** Acronym casing - **Suggestion:** Match the upstream `HttpRequest.url` field; if upstream uses `url`, leave it. Note inconsistency for the audit reviewer. - **Rationale:** Minor — flagged because the rule applies. -### 36. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns +### 34. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns - **File:line:** `model.ts:672 (EnableExportNotebook), 682 (EnableNotebookTableClipboard), 692 (EnableResultsDownloading), 630 (DisableLegacyAccess), 651 (DisableLegacyDbfs)` - **Category:** Verb-tense inconsistency -- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #19–23. +- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #17–21. - **Rationale:** Five types here use three different inflection patterns. -### 37. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap +### 35. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap - **File:line:** `model.ts:672, 682` - **Category:** Verb-tense inconsistency - **Suggestion:** Pick word-order convention: noun-verb-noun (`EnableNotebookExport`, `EnableNotebookTableClipboard`) or verb-noun-noun (`EnableExportNotebook`, `EnableClipboardTable`). - **Rationale:** "Enable Export Notebook" puts the noun ("Notebook") last; "Enable Notebook Table Clipboard" puts it first. The cognitive cost of two siblings in the same package using opposite orders is non-trivial. -### 38. `delete*` method names — reserved-word adjacency +### 36. `delete*` method names — reserved-word adjacency - **File:line:** `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` - **Category:** Reserved-word collision (soft) -- **Suggestion:** `reset*` (which also fixes #18). +- **Suggestion:** `reset*` (which also fixes #15). - **Rationale:** `delete` is a JS reserved word (`delete obj.prop`). Using it as a method prefix is technically fine but creates parsing-cost ambiguity in mental models, especially when the operation doesn't *actually* delete. -### 39. Long enum values +### 37. Long enum values - **File:line:** `model.ts:19-53, 83, 84, 101` - **Category:** Long enum value - **Suggestion:** Most are unavoidable (regulatory standard names like `FEDRAMP_MODERATE` are canonical). For `RESTRICT_TOKENS_AND_JOB_RUN_AS` consider `RESTRICT_TOKEN_AND_JOB_RUN_AS` (singular `TOKEN`); for `SECOND_AND_FOURTH_OF_MONTH` consider abbreviation (this is a maintenance-window pattern). - **Rationale:** Length is unavoidable for proper nouns but `RESTRICT_TOKENS_AND_JOB_RUN_AS` mixes plural noun + singular verb-phrase awkwardly. -### 40. Enum values for domain-allow lists +### 38. Enum values for domain-allow lists - **File:line:** `model.ts:59-61` (`ALLOW_ALL_DOMAINS`, `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`) - **Category:** Long enum value -- **Suggestion:** `ALLOW_ALL`, `ALLOW_APPROVED`, `DENY_ALL` — drop `_DOMAINS` since the enum is already named `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` and the domain context is established. -- **Rationale:** Redundant tail. Compare with `STATUS_UNSPECIFIED`, `ALLOW_ALL`, `RESTRICT_TOKENS_AND_JOB_RUN_AS` in `RestrictWorkspaceAdminsMessage_Status` — none carry a redundant noun. +- **Suggestion:** `ALLOW_ALL`, `ALLOW_APPROVED`, `DENY_ALL` — drop `_DOMAINS` since the enum is already named and the domain context is established. +- **Rationale:** Redundant tail. Compare with `STATUS_UNSPECIFIED`, `ALLOW_ALL`, `RESTRICT_TOKENS_AND_JOB_RUN_AS` — none carry a redundant noun. -### 41. `disableGovTagCreation` — verb-as-field +### 39. `disableGovTagCreation` — verb-as-field - **File:line:** `model.ts:988` - **Category:** Verb-tense inconsistency, cryptic abbreviation - **Suggestion:** `governanceTagCreationDisabled` or `restrictsGovernanceTagCreation`. `Gov` is also cryptic abbreviation. @@ -325,70 +309,58 @@ ## Low severity -### 42. Cryptic wire-key abbreviations in URL slugs +### 40. Cryptic wire-key abbreviations in URL slugs - **File:line:** `client.ts:339 (aibi_dash_embed_ws_acc_policy), 381 (aibi_dash_embed_ws_apprvd_domains), 756, 796, 1261, 1296` - **Category:** Cryptic abbreviation - **Suggestion:** Wire keys are server-controlled; the SDK can't unilaterally rename. Worth flagging for the broader Databricks-platform team — these URL paths are exposed in logs and SDK telemetry. `apprvd` for `approved` saves 1 character. - **Rationale:** Wire keys aren't strictly in scope for naming audits, but they bleed into log lines and error messages. `dash_embed` for "dashboard embedding" is also non-obvious. -### 43. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix +### 41. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix - **File:line:** `client.ts:468 (default_namespace_ws), 876 (shield_csp_enablement_ws_db), 1104 (shield_esm_enablement_ws_db)` - **Category:** Cryptic abbreviation - **Suggestion:** Wire-team concern. `ws` is workspace, `db` is database (?), `ac` is account (in `accountsettings`). These two-letter suffixes are dense. - **Rationale:** `shield_csp_enablement_ws_db` mixes three abbreviated tokens (`shield` is fine, `csp` and `ws_db` are cryptic). -### 44. `eTag` (doc) vs `etag` (field) +### 42. `eTag` (doc) vs `etag` (field) - **File:line:** `model.ts:112-117, 252-259, 1024` (every `etag` doc block) - **Category:** Acronym casing - **Suggestion:** Standardize either `etag` or `eTag`. RFC 7232 spells it "ETag" in HTTP headers; Databricks docs spell it `eTag` in prose and `etag` as the JSON field. - **Rationale:** Internal-doc inconsistency. The JSDoc on every type says "etag used for versioning. The response is at least as fresh as the eTag provided." — the same paragraph uses two casings. -### 45. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope +### 43. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope - **File:line:** `model.ts:248` - **Category:** Singular/plural mismatch (mild — correct in context) - **Suggestion:** No change. Flagged only because the audit checklist asks for it. The field is correctly plural because it holds an array; the parent type is correctly singular because there is one profile. - **Rationale:** Consistent. No action needed. -### 46. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` +### 44. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` - **File:line:** `model.ts:135` - **Category:** Singular/plural - **Suggestion:** None needed for this field. Flagging the parent type name — `AibiDashboardEmbeddingApprovedDomains` is plural (because it holds a list) while sibling `AibiDashboardEmbeddingAccessPolicy` is singular. The asymmetry is fine but inconsistent stylistically. - **Rationale:** Minor; preserved for completeness. -### 47. Wire-key length in shorter slugs +### 45. Wire-key length in shorter slugs - **File:line:** `client.ts:836 (automatic_cluster_update), 423 (dashboard_email_subscriptions), 673 (restrict_workspace_admins)` - **Category:** Verbose / could be shorter - **Suggestion:** Wire-team concern. - **Rationale:** These three slugs are 24+ characters but spell every word out (unlike `aibi_dash_embed_ws_acc_policy` which abbreviates aggressively). The inconsistency in wire-side abbreviation conventions is itself a flag. -### 48. `Patch*Request` types vs `Update*Request` types for same PATCH HTTP verb -- **File:line:** `model.ts:959 (PatchEnableExportNotebookRequest), 967 (PatchEnableNotebookTableClipboardRequest), 975 (PatchEnableResultsDownloadingRequest)` vs `model.ts:1040, 1050, 1062, 1072, 1082, 1092, 1102, 1112, 1122, 1132, 1142, 1152, 1162 (Update*Request)` -- **Category:** Verb-tense inconsistency -- **Suggestion:** Match #17 — standardize on `Update*Request`. -- **Rationale:** 3 of 17 request types use `Patch*`, the other 14 use `Update*`. - -### 49. `Delete*Response` types duplicated across sibling settings packages -- **File:line:** `model.ts:356, 385, 414, 443, 472, 501, 530, 559, 588, 617` -- **Category:** Duplicate type -- **Suggestion:** Hoist to a shared module alongside `BooleanMessage`/`StringMessage` (see #2), or use a single canonical `EtagResponse` type across all settings packages. -- **Rationale:** Ten types with identical one-field shape repeat across `workspacesettings`, `accountsettings`, and `settings/v2`. Each is a distinct TS type to satisfy proto naming, so a `Delete*Response` from one package is not assignable to a sibling's. - --- ## Cross-cutting themes -1. **Four overlapping settings packages.** `workspacesettings` + `settings` + `accountsettings` + `workspaceconf` is a confusing taxonomy with literal type duplication. Almost every type in `workspacesettings` has a doppelganger in `settings/v2`. (Severity #1, #2, #3, #4, #5.) +1. **Four overlapping settings packages.** `workspacesettings` + `settings` + `accountsettings` + `workspaceconf` is a confusing taxonomy with literal type duplication. Almost every type in `workspacesettings` has a doppelganger in `settings/v2`. (Severity #1, #2, #3, #4.) -2. **Proto-style nested-name underscores.** Eight identifiers use proto-IDL underscore nesting (`Foo_Bar_Baz`), each with an eslint-disable comment. (Severity #11.) +2. **Sentinel `*_UNSPECIFIED` values.** Sentinel enum members flagged by their own docstrings as "should not be used in prod." (Severity #10.) -3. **Sentinel `*_UNSPECIFIED` and redundant enum-name prefixes.** Proto3 convention bleeds into TS enums. (Severities #12, #13.) +3. **`*Setting` triple-stutter.** Every primary type carries a `Setting` suffix despite the package name being `workspacesettings`. (Severity #16.) -4. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #6, #7, #8, #9, #10, #33, #34, #35.) +4. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #5, #6, #7, #8, #9, #31, #32, #33.) -5. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #19-23, #36-37.) +5. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #17-21, #34-35.) -6. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #17, #18, #38.) +6. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #14, #15, #36.) -7. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #14, #15.) +7. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #11, #12.) -8. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #42, #43.) +8. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #40, #41.) From 3817de00ae54464058544ab888bfa47dfa5f11ed Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Fri, 22 May 2026 14:00:42 +0000 Subject: [PATCH 04/12] update --- .agent/naming-audit/_SUMMARY.md | 1160 ++++++++++------- .agent/naming-audit/abacpolicies.md | 167 +-- .agent/naming-audit/accessmanagement.md | 628 +++++++++ .agent/naming-audit/accountaccesscontrol.md | 10 + .../naming-audit/accountaccesscontrolproxy.md | 253 +--- .agent/naming-audit/accountsettings.md | 286 ++-- .agent/naming-audit/alerts.md | 60 +- .agent/naming-audit/apps.md | 338 +++-- .agent/naming-audit/artifactallowlists.md | 167 ++- .agent/naming-audit/authentication.md | 146 +++ .agent/naming-audit/budgetpolicy.md | 96 +- .agent/naming-audit/budgets.md | 457 ++++--- .agent/naming-audit/bundle.md | 29 +- .agent/naming-audit/catalogs.md | 524 ++++---- .agent/naming-audit/cleanroomassets.md | 603 ++------- .../cleanroomautoapprovalrules.md | 417 ++---- .agent/naming-audit/cleanrooms.md | 371 ++---- .agent/naming-audit/cleanroomtaskruns.md | 135 +- .agent/naming-audit/clusterlibraries.md | 397 ++---- .agent/naming-audit/clusterpolicies.md | 291 +++-- .agent/naming-audit/clusters.md | 302 +++-- .agent/naming-audit/commandexecution.md | 288 ++-- .agent/naming-audit/connections.md | 183 ++- .agent/naming-audit/credentials.md | 278 ++-- .agent/naming-audit/customllms.md | 52 +- .agent/naming-audit/database.md | 199 +-- .agent/naming-audit/dataclassification.md | 66 +- .agent/naming-audit/dataquality.md | 161 ++- .agent/naming-audit/disasterrecovery.md | 82 +- .agent/naming-audit/endpoints.md | 1004 +++++++------- .agent/naming-audit/entitytagassignments.md | 97 +- .agent/naming-audit/environments.md | 125 +- .agent/naming-audit/experiments.md | 188 ++- .agent/naming-audit/externallineage.md | 64 +- .agent/naming-audit/externallocations.md | 232 ++-- .agent/naming-audit/externalmetadata.md | 100 +- .agent/naming-audit/features.md | 228 ++-- .agent/naming-audit/featurestore.md | 171 +-- .agent/naming-audit/files.md | 309 ++--- .agent/naming-audit/forecasting.md | 31 + .agent/naming-audit/functions.md | 426 +++--- .agent/naming-audit/genie.md | 274 ++-- .agent/naming-audit/gitcredentials.md | 86 +- .agent/naming-audit/globalinitscripts.md | 157 ++- .agent/naming-audit/grants.md | 185 ++- .agent/naming-audit/iam.md | 715 ++++------ .agent/naming-audit/indexes.md | 165 ++- .agent/naming-audit/instancepools.md | 368 ++++-- .agent/naming-audit/instanceprofiles.md | 165 ++- .agent/naming-audit/jobs.md | 567 ++++---- .agent/naming-audit/keyconfigurations.md | 86 ++ .agent/naming-audit/knowledgeassistants.md | 52 +- .agent/naming-audit/lakeview.md | 166 +-- .agent/naming-audit/logdelivery.md | 232 ++++ .../naming-audit/logdeliveryconfigurations.md | 168 ++- .agent/naming-audit/marketplaces.md | 404 +++--- .agent/naming-audit/materializedfeatures.md | 10 + .agent/naming-audit/metastores.md | 329 ++--- .agent/naming-audit/modelregistry.md | 291 +++-- .agent/naming-audit/modelserving.md | 360 +++++ .agent/naming-audit/modelservingdebug.md | 323 ++--- .agent/naming-audit/modelservingmanagement.md | 215 +-- .agent/naming-audit/modelservingquery.md | 231 ++-- .agent/naming-audit/networking.md | 128 ++ .../naming-audit/notificationdestinations.md | 20 +- .agent/naming-audit/oauth.md | 364 ++++++ .../naming-audit/oauthcustomappintegration.md | 117 +- .agent/naming-audit/oauthpublishedapp.md | 129 +- .agent/naming-audit/onlinetables.md | 173 +-- .agent/naming-audit/permissions.md | 213 +-- .agent/naming-audit/pipelines.md | 440 +++---- .agent/naming-audit/policyfamilies.md | 119 +- .agent/naming-audit/postgres.md | 476 +++---- .agent/naming-audit/qualitymonitor.md | 184 +-- .agent/naming-audit/qualitymonitors.md | 178 +-- .agent/naming-audit/queries.md | 83 +- .agent/naming-audit/queryexecution.md | 237 +--- .agent/naming-audit/queryhistory.md | 180 ++- .agent/naming-audit/registeredmodels.md | 238 ++-- .agent/naming-audit/repos.md | 165 ++- .agent/naming-audit/resourcequotas.md | 178 ++- .agent/naming-audit/rfa.md | 106 +- .agent/naming-audit/schemas.md | 422 +++--- .agent/naming-audit/scim.md | 111 ++ .agent/naming-audit/secrets.md | 285 ++-- .../naming-audit/serviceprincipalsecrets.md | 389 +----- .../serviceprincipalsecretsproxy.md | 333 +---- .agent/naming-audit/settings.md | 432 +++--- .agent/naming-audit/sharing.md | 202 +++ .agent/naming-audit/statementexecution.md | 181 +-- .agent/naming-audit/storageconfigurations.md | 159 +++ .agent/naming-audit/supervisoragents.md | 216 ++- .agent/naming-audit/systemschemas.md | 47 +- .agent/naming-audit/tables.md | 1013 +++++++------- .agent/naming-audit/tagassignments.md | 30 +- .agent/naming-audit/tagpolicies.md | 155 +-- .agent/naming-audit/tokenmanagement.md | 171 ++- .agent/naming-audit/tokens.md | 188 ++- .agent/naming-audit/usagedashboards.md | 85 +- .agent/naming-audit/usagepolicy.md | 26 +- .agent/naming-audit/vectorsearch.md | 207 +++ .agent/naming-audit/volumes.md | 276 ++-- .agent/naming-audit/warehouses.md | 377 +++--- .agent/naming-audit/workspace.md | 373 +++--- .agent/naming-audit/workspaceassignment.md | 158 ++- .agent/naming-audit/workspacebindings.md | 145 +-- .agent/naming-audit/workspaceconf.md | 50 +- .agent/naming-audit/workspaceobjects.md | 425 ++++++ .agent/naming-audit/workspaces.md | 251 ++++ .agent/naming-audit/workspacesettings.md | 309 ++--- 110 files changed, 13941 insertions(+), 13473 deletions(-) create mode 100644 .agent/naming-audit/accessmanagement.md create mode 100644 .agent/naming-audit/authentication.md create mode 100644 .agent/naming-audit/keyconfigurations.md create mode 100644 .agent/naming-audit/logdelivery.md create mode 100644 .agent/naming-audit/modelserving.md create mode 100644 .agent/naming-audit/networking.md create mode 100644 .agent/naming-audit/oauth.md create mode 100644 .agent/naming-audit/scim.md create mode 100644 .agent/naming-audit/sharing.md create mode 100644 .agent/naming-audit/storageconfigurations.md create mode 100644 .agent/naming-audit/vectorsearch.md create mode 100644 .agent/naming-audit/workspaceobjects.md create mode 100644 .agent/naming-audit/workspaces.md diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index bcf7572d..09d44c6f 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,8 +1,9 @@ # Cross-Package Naming Audit — Executive Summary -**Packages audited:** 98 (every API package under `packages//src//`) -**Total findings across all audits:** **3,918** (down from 5,322 originally, then 5,001 after the first prune pass, then 4,544 after the second, then 4,502 after the third; **584 additional findings pruned in this fourth pass**, **1,404 cumulative**) +**Packages audited:** 87 active API packages (every package under `packages//src//` after the 2026-05-22 generator regen consolidation). An additional 24 audit files exist for packages that were removed or consolidated in the regen; those audits are retired and their finding counts are excluded from the active total. See "Retired audits" at the bottom of §6. +**Total active findings across all 87 active audits:** **2,926** (down from 3,572 before the 2026-05-22 regen + rescan; previously 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep). The net drop in this regen is **~646** active findings — the bulk came from the generator renaming the `*Public*Request` family across account-tier packages, which moved ~81 findings into per-package `Fixed` sections; the rest came from 24 audits going to zero active findings as their source packages were consolidated into successor packages. **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` +**Last source state:** Rescan against generator state 2026-05-22, upstream API version `0555d6a59265799ed8ea12f355eee662e739430d`. > **Prune note 1.** The original audit included a cross-cutting theme > "Empty / trivial wrapper interfaces" (empty `*_Response` interfaces, @@ -54,15 +55,158 @@ > removed), and by-the-numbers table below. This was the single > largest category by package incidence (~85/98). +> **Prune note 5.** A fifth cross-cutting theme, +> "Redundant enum-name prefix on every member" — e.g. +> `PolicyType.POLICY_TYPE_ROW_FILTER`, +> `DestinationType.DESTINATION_TYPE_EMAIL`, +> `CommandStatus.COMMAND_CANCELLED`, `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` — +> has been pruned per user direction. The proto-style `Foo.FOO_BAR_BAZ` +> shape is intentional: TS enum member names mirror the protobuf wire +> identifier exactly, which keeps codegen deterministic and preserves +> the wire ↔ TS correspondence. Stripping the prefix on the TS side +> would force a per-enum translation table and break the symmetry that +> generators and downstream tooling rely on. The pruned findings are +> reflected in the totals, theme list (the former Theme 1 removed), +> generator recommendations (§8.1 removed), and by-the-numbers table +> below. + +> **Prune note 6.** A sixth cross-cutting theme, +> "`*_UNSPECIFIED` proto sentinel values in every enum" — e.g. +> `STATE_UNSPECIFIED`, `POLICY_TYPE_UNSPECIFIED`, +> `COMPUTE_KIND_UNSPECIFIED`, `RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, +> `DAY_OF_WEEK_UNSPECIFIED` — has been pruned per user direction. +> proto3 mandates that every enum carry a zero value, and the +> `*_UNSPECIFIED` member is semantically distinct from `undefined`: +> it means "explicitly set to absent/default" on the wire, whereas +> field-optional `?:` `undefined` means "not present in this message". +> Dropping the sentinel would conflate those two states and silently +> break round-tripping. The pruned findings are reflected in the +> totals, theme list (the former Theme 2 removed), and by-the-numbers +> table below. + +> **Rescan note (2026-05-20).** The generator was re-run and the +> per-package audits were rescanned against the new source state. The +> rescan dropped **710 findings net** and closed out several structural +> pain points in the wire ↔ TS mapping: +> +> - **`Request` suffix wave (Theme 3, former).** The generator now +> emits every request DTO with a `Request` suffix +> (`DeletePolicyRequest`, `ListSecretsRequest`, `ExportRequest`, +> etc.). Verb-phrase request types — the previous Theme 3, cited in +> ~80/98 packages — are no longer the dominant concern. Residual +> instances in `bundle`, `files`, `marketplaces`, and a few others +> are tracked per-package. The former §8.5 generator rule has been retired +> as **Done** in §7 below. +> - **14 packages deleted, merged, or renamed.** Five removed outright +> (`accountaccesscontrol`, `accountaccesscontrolproxy`, +> `serviceprincipalsecrets`, `serviceprincipalsecretsproxy`, +> `queryexecution`). Nine consolidated: +> `cleanroomassets` + `cleanroomautoapprovalrules` + +> `cleanroomtaskruns` → `cleanrooms`; `endpoints` + `indexes` → +> `vectorsearch`; `oauthcustomappintegration` + `oauthpublishedapp` +> → `oauth`; `modelservingdebug` + `modelservingmanagement` → +> `modelserving`; `workspaceassignment` → `accessmanagement`. +> Three packages renamed in place: `permissions` → +> `accessmanagement`, `workspace` → `workspaceobjects`, +> `logdeliveryconfigurations` → `logdelivery`. +> - **Themes that shrank materially.** The "verb-phrase request types" +> theme has been retired and is now footnote-level. The "Package-name +> prefix repeats package" (e.g. `OAuthAppIntegration*`, +> `CleanRoom*`, `Pipelines*`, `Genie*`) theme shrank ~30% because +> several offending packages were merged or renamed. The +> "byte-identical `*proxy` packages" pain point is gone (both +> `*Proxy` packages were deleted). +> - **Carried-over findings.** Findings that were *still present* after +> the regeneration kept their position in `High`/`Medium`/`Low`. Line +> numbers were updated in place. Audits whose package was deleted +> have all findings under `## Fixed` and zero active total. + +> **Audit-pass note 7 (proto-architectural-leak scan).** A ~93-agent +> pass scanned every API package for mid-position infix tokens that +> betray internal proto/service-tier ownership: `*Public*Request`, +> `*Proto` suffix, `*Service*` / `*Manager*` / `*Backend*` / `*Handler*` +> mid-position, `*Internal*`, `*Wrapper*`, `*CustomerFacing*` qualifier, +> mid-position `*V2*` (e.g. `RunLifecycleStateV2`), and JSDoc leaks of +> "Public RPC" / "Wrapper message" / "Public facing RPC requests and +> responses" verbatim banners. Findings were appended to each per-package +> audit under a new "Proto-architectural leak" category and added ~300 +> findings net (3,273 → 3,572). The pass also created seven +> previously-missing audits for packages absorbed from the account-API +> split during the 2026-05-20 regen: `authentication`, `keyconfigurations`, +> `networking`, `scim`, `sharing`, `storageconfigurations`, `workspaces`. + +> **Audit-pass note 8 (2026-05-21 — Google TS acronym renames applied).** +> Adopted the Google TS Style Guide acronym-as-whole-word rule (already +> documented at `.agent/rules/typescript.mdc:184`). Renamed 105 files: +> 11 hand-written (`auth`, `core`, `examples`) + 94 generated `utils.ts` +> import updates. `OAuth*`, `OIDC*`, and JS built-ins kept under the +> platform-name exception. + +> **Audit-pass note 9 (2026-05-22 — Generator regen + rescan).** The +> generator was re-run against upstream API version +> `0555d6a59265799ed8ea12f355eee662e739430d`. All 81 active audits +> were rescanned and 6 newly-created audits cover packages that the +> regen consolidated from smaller siblings: +> +> - `accessmanagement` (NEW, 38 findings) — supersedes `permissions`, +> `accountaccesscontrol`, `accountaccesscontrolproxy`, and +> `workspaceassignment`. Single umbrella for object permissions, +> permission levels, rule sets, and workspace assignments. +> - `logdelivery` (NEW, 28 findings) — renamed from +> `logdeliveryconfigurations`. The legacy long name was a clean +> rename target. +> - `modelserving` (NEW, 47 findings) — supersedes +> `modelservingmanagement` and absorbed the former `modelservingdebug`. +> `modelservingquery` remains separate. +> - `oauth` (NEW, 11 findings) — supersedes +> `oauthcustomappintegration` and `oauthpublishedapp`. Single +> package for both Custom and Published app integrations plus +> the published-app catalog. +> - `vectorsearch` (NEW, 28 findings) — supersedes `endpoints` and +> `indexes`. Single endpoint+index surface for Vector Search. +> - `workspaceobjects` (NEW, 29 findings) — renamed from +> `workspace`. The bare name was the most-overloaded in the SDK; +> the rename clarifies the package scope as the workspace +> filesystem (notebooks/folders/files). +> +> **24 audit files marked as removed/consolidated.** Their findings +> are excluded from the active total. Source packages no longer +> exist: +> `accountaccesscontrol`, `accountaccesscontrolproxy`, +> `accountsettings`, `cleanroomassets`, `cleanroomautoapprovalrules`, +> `cleanroomtaskruns`, `endpoints`, `indexes`, +> `logdeliveryconfigurations`, `materializedfeatures`, +> `modelservingdebug`, `modelservingmanagement`, +> `oauthcustomappintegration`, `oauthpublishedapp`, `permissions`, +> `qualitymonitor`, `qualitymonitors`, `queryexecution`, +> `serviceprincipalsecrets`, `serviceprincipalsecretsproxy`, +> `workspace`, `workspaceassignment`, `workspaceconf`, +> `workspacesettings`. Each retired audit carries a status banner at +> the top of the file noting the 2026-05-22 consolidation date and +> retains the original findings as historical record. +> +> **~81 findings moved to Fixed in this regen** — overwhelmingly +> proto-architectural-leak `*Public*Request` and `*PublicRequest_Response` +> patterns that the regen renamed across the account-tier packages. +> The largest per-package shifts: +> `metastores` (20 fixed), `networking` (17 fixed), `workspaces` (16 +> fixed), `credentials` (~10 fixed), `storageconfigurations` (~10 +> fixed), `cleanrooms` (4 fixed), `jobs` (2 fixed), `keyconfigurations` +> (2 fixed). These renames retroactively validate generator rule +> §8.2 ("Strip proto-architectural-tier markers"). The rule is **not** +> marked Done — `*CustomerFacing*` qualifiers in `networking` and a +> handful of `Proto` suffixes (e.g. `TriggerStateProto`, +> `DatabricksServiceExceptionProto`) still survive in active audits. + This document synthesises the per-package audits into the patterns that the upstream generator (and a smaller number of API team decisions) should fix to deliver an idiomatic TypeScript SDK. The vast majority of the findings are template-driven — fix the template once and the symptoms disappear from every package. -The 98 packages are a 1:1 port of `databricks/sdk-go`, so most defects flow -from Go/protobuf idioms that do not translate to TypeScript. Idiomatic TS -SDKs (AWS, Azure, Stripe, Octokit) deliberately diverge from their wire +The 87 active packages are a 1:1 port of `databricks/sdk-go`, so most defects +flow from Go/protobuf idioms that do not translate to TypeScript. Idiomatic +TS SDKs (AWS, Azure, Stripe, Octokit) deliberately diverge from their wire formats; the Databricks JS SDK currently does not. --- @@ -70,85 +214,9 @@ formats; the Databricks JS SDK currently does not. ## 1. Top cross-cutting themes Ranked by approximate package incidence. Each theme is a generator-level -defect — one template change fixes ~98 packages. - -### Theme 1. Redundant enum-name prefix on every member (proto idiom) — ~84/98 packages - -Every enum is emitted with its members redundantly prefixed by the enum name: - -```ts -enum DestinationType { - DESTINATION_TYPE_UNSPECIFIED = 'DESTINATION_TYPE_UNSPECIFIED', - DESTINATION_TYPE_EMAIL = 'DESTINATION_TYPE_EMAIL', - ... -} -``` - -TypeScript enums are namespaced by the enum itself -(`DestinationType.Email`), so the prefix is pure protobuf noise. Often the -prefix is applied inconsistently *within a single enum*: -`DataSecurityMode.DATA_SECURITY_MODE_STANDARD` next to -`DataSecurityMode.SINGLE_USER` -(`packages/clusters/src/v2/model.ts:123-127`); or applied to two of three -cloud-specific enums while one cloud is unprefixed -(`AzureAvailability.SPOT_AZURE` / `GcpAvailability.PREEMPTIBLE_GCP` vs -`AwsAvailability.SPOT`). - -Examples: -- `connections.ConnectionType.UNKNOWN_CONNECTION_TYPE` — `packages/connections/src/v1/model.ts:7`. -- `tokens.AutoscopeState.AUTOSCOPE_STATE_API_NOT_COVERED` — 44 chars to express "API not covered", `packages/tokens/src/v1/model.ts:14-20`. -- `cleanrooms.INTERNET_DESTINATION_TYPE_UNSPECIFIED`, `LOG_ONLY_MODE_TYPE_UNSPECIFIED`, `OUTPUT_CATALOG_STATUS_UNSPECIFIED`. -- `commandexecution.CommandStatus.COMMAND_CANCELLED`, `COMMAND_FINISHED`, etc. (every member prefixed) — `packages/commandexecution/src/v2/model.ts:21-29`. -- `externallocations.IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` — 30 chars, `packages/externallocations/src/v1/model.ts:5-10`. - -**Generator fix:** Strip the redundant prefix at emit time. Map -`FOO_BAR_BAZ` → `BarBaz` (PascalCase) or keep `BAR_BAZ` for SCREAMING_SNAKE. -Either way the prefix that re-states the enum name should not survive into -TS. Wire value can stay as-is via Zod transform. - -### Theme 2. `*_UNSPECIFIED` proto sentinel values in every enum — ~60/98 packages - -Every protobuf enum carries a zero value `XXX_UNSPECIFIED` that protobuf -needs but TS does not. The corresponding field is already -`foo?: Foo | undefined`, so "unspecified" is encoded twice (as `undefined` -and as the sentinel). Callers have to handle both states. - -Examples in nearly every audit: `STATE_UNSPECIFIED`, `POLICY_TYPE_UNSPECIFIED`, -`COMPUTE_KIND_UNSPECIFIED`, `RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, -`ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, -`STATUS_UNSPECIFIED`, etc. - -**Generator fix:** Drop `*_UNSPECIFIED` members from emitted enums. Map them -to TypeScript `undefined` on the way in, and the field's `?:` optionality -already expresses "not set" on the way out. - -### Theme 3. Verb-phrase request types (no `Request` suffix) — ~80/98 packages - -Request DTOs are named with bare verb phrases: - -```ts -interface DeletePolicy { ... } // looks like a function -interface ListPolicies { ... } // looks like a method -interface CreateScope { ... } // looks like an action -``` - -Client methods sit alongside with identical camel-case names -(`client.deletePolicy(req: DeletePolicy)`), forcing readers to mentally -disambiguate noun-from-verb on every line. - -Examples: -- `secrets.{CreateScope, DeleteAcl, DeleteScope, DeleteSecret, GetAcl, GetSecret, ListAcls, ListScopes, ListSecrets, PutAcl, PutSecret}` — 11 verb-named types in one file. -- `workspace.{Delete, Export, Import, List, Mkdirs, GetStatus}` — also collide with TS reserved/built-in tokens (`Delete`, `Import`, `Export`). -- `files.{Read, Move, Put, Delete, Close, Create, MkDirs, AddBlock, GetStatus, ListStatus}` — every DBFS request type. -- `grants.{GetPermissions, UpdatePermissions, GetEffectivePermissions}` — request types named like verbs. -- `tokenmanagement.{GetToken, ListTokens, RevokeToken, UpdateToken, CreateOnBehalfOfToken}`. -- `serviceprincipalsecrets.{CreateServicePrincipalSecret, DeleteServicePrincipalSecret, ListServicePrincipalSecrets}`. - -**Generator fix:** Append `Request` to every request-DTO type. This is the -TS convention used by every other large SDK (AWS, Azure, Google Cloud). Wire -shape unaffected. - -### Theme 4. `Info` (and other vague) suffix on the canonical entity — ~70/98 packages +defect — one template change fixes ~87 packages. + +### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~70/87 packages The Go SDK uses `Info` to name "details of an X" because Go does not have package-qualified imports for types. TS does, and `` alone @@ -156,14 +224,14 @@ suffices. Examples: - `RepoInfo` → `Repo` / `GitFolder` (and the field `repo?: RepoInfo` becomes `repo?: Repo`). - `PolicyInfo` → `Policy`. -- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 7). +- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 4). - `SchemaInfo` → `Schema`. - `CredentialInfo` → `Credential`. - `MetastoreInfo` → `Metastore`. - `CatalogInfo` → `Catalog`. - `RunInfo`, `JobInfo`, `TableInfo`, `FunctionInfo`, `ConnectionInfo`, `VolumeInfo`, `ServicePrincipalInfo`, `UserInfo`, `WorkspaceInfo`, - `OnlineTableInfo`, `IndexInfo`, `RunInfo`, `ExperimentInfo`. + `OnlineTableInfo`, `ExperimentInfo`. Same problem with other vague suffixes: - `*Options` on tagged-union arms (`RowFilterOptions`, `ColumnMaskOptions`, `DenyOptions`, `GrantOptions`) — when the `$case` discriminator already says "this is the X options". @@ -174,92 +242,212 @@ domain entity. (Heuristic: if `Info` is the only `*` type that isn't a request/response, drop `Info`.) Same for redundant `Options`/`Spec` suffixes on tagged-union arms when the parent has a discriminator. -### Theme 5. Type-name prefix repeats the package — ~70/98 packages +### Theme 2. Type-name prefix repeats the package — ~45/87 packages -Every type in a package is prefixed with the package's domain noun, even -though the import path already provides namespace disambiguation: +Many type names re-state the package's domain noun even though the import +path already provides namespace disambiguation. The 2026-05-20 and +2026-05-22 generator rescans shrank this theme: the worst offenders +(`OAuthAppIntegration*` across `oauthcustomappintegration`/`oauthpublishedapp`, +`CleanRoom*` across three sibling packages, and the merged-in `Workspace*` +from `workspaceassignment`) were folded into consolidated packages, but the +remaining cases are still pervasive. -- `oauthcustomappintegration.{CreateCustomOAuthAppIntegration, CreatePublishedOAuthAppIntegration, DeleteCustomOAuthAppIntegration, ...}` — 18 types all prefixed with 19 characters that the import path already provides. - `pipelines.{PipelinesAwsAvailability, PipelinesAzureAvailability, PipelinesEbsVolumeType, PipelinesAwsAttributes, ...}` — 15 types prefixed with `Pipelines` (plural) when the package is singular-domain. `packages/pipelines/src/v2/model.ts:212, 225, 241, 2243, ...`. -- `cleanroomautoapprovalrules.CleanRoomAutoApprovalRule` — package and type repeat the same 22-character noun. - `genie.{GenieAttachment, GenieConversation, GenieMessage, GenieSpace, GenieFeedback, GenieEvalResult, ...}` — 40 types prefixed with `Genie` (and inconsistently — `Result`, `Schema`, `Thought` are not prefixed in the same file). -- `serviceprincipalsecrets.ServicePrincipalSecret` — every type carries `ServicePrincipal` (16 chars). -- `accountaccesscontrolproxy.GetAssignableRolesForResourceRequest` — 36-char type name when `GetAssignableRolesRequest` would do. -- `qualitymonitor.QualityMonitor` (package + type). - `tagpolicies.TagPolicy`, `tagassignments.TagAssignment`, `entitytagassignments.EntityTagAssignment`. - `customllms.CustomLlm`, `customLlmFieldMask`, `createCustomLlm`, etc. +- `cleanrooms.CleanRoom*` family — still pervasive after absorbing the sibling packages. +- `oauth.OAuthAppIntegration*` family — still pervasive after the merge. **Generator fix:** When emitting TS, strip the package-name prefix from every type as long as the unprefixed name does not clash with another type in the same package. Wire shape is unaffected. -### Theme 6. Inconsistent acronym casing across the SDK — 98/98 packages +### Theme 3. Inconsistent acronym casing across the SDK — 87/87 packages + +> **Status (2026-05-21):** Policy adopted (Google TS Style Guide: +> "treat acronyms as whole words"). The rule was already at +> `.agent/rules/typescript.mdc:184`. All hand-written-package renames +> listed in 3b have been applied. Theme 3a generated-code outliers +> remain — `OAuth*` is documented as a platform-name exception per +> RFC 6749 (kept). + +The SDK has no project-wide acronym-casing policy. The inconsistencies +appear on two distinct surfaces, each with a different cause and fix path. + +#### 3a. Generated code — 87/87 packages -The SDK currently mixes both `Pascal-then-lower` (`Http`, `Url`, `Json`, -`Sql`, `Oauth`, `Pypi`, `Aws`, `Llm`, `Pii`, `Sse`, `Idp`, `Csp`, `Esm`, -`Dbfs`, `Dbr`, `Aibi`) with `ALL_CAPS` (`URL`, `ID`, `URI`, `RPC`) in -different places. There is no project-wide policy. The user-visible -inconsistencies include: +The generator already uses **`Pascal-then-lower`** very consistently for +TS identifiers (`Url`, `Id`, `Json`, `Sql`, `Http`, `Oauth`, `Aws`, +`Gcp`, `Llm`, `Dbfs`, `Iam`, `Sse`, `Pii`, `Aibi`, `Dbr`, `Uri`). A scan +of all generated packages found: -| Acronym | Found as | Examples | +| Acronym | TS identifiers (Pascal-then-lower) | `ALL_CAPS` form — where it appears | |---|---|---| -| URL | `Url`, `URL`, `url` | `dataSchemaUrl`, `URLSearchParams`, `webhookUrl`, `URL` enum value | -| Id | `Id`, `ID`, `id` | `userId`, `runId`, `ID` (string-typed enum value), `metastoreId` | -| SQL | `Sql`, `SQL` | `SqlWarehouseSpec`, `DATABRICKS_SQL_ACCESS` | -| JSON | `Json`, `JSON` | `JsonValue`, `JsonObject`, `isJsonSchema` vs `JSON.stringify` | -| OAuth | `Oauth`, `OAuth` | `OAuthAppIntegration` (type), `oauthcustomappintegration` (package) | -| PyPI | `Pypi`, `PyPI` | `PypiLibrary` (type), JSDoc says "PyPI" | -| AWS | `Aws`, `AWS` | `AwsAttributes` (type), `AWS_SSE_S3` (enum value) | -| LLM | `Llm`, `LLM` | `CustomLlm` (type), `LLM` in JSDoc | -| ETag | `etag`, `eTag`, `ETag` | `RuleSet.etag` (field), `If-Match`/`ETag` (HTTP RFC 7232 §2.3 says `ETag`) | -| HTTP | `Http`, `HTTP` | `HttpClient` (type), `httpRequest` (method) | -| DBFS | `Dbfs`, `DBFS` | `disableLegacyDbfs`, `DbfsStorageInfo` vs JSDoc "DBFS" | - -**Generator fix:** Adopt one policy in `typescript.mdc` and apply -generator-wide. The two consistent options are: -1. **Google TS style guide (`Pascal-then-lower`):** `Url`, `Id`, `Sql`, `Json`, `OAuth` → `Oauth`. Pro: every multi-letter token becomes a word; con: requires reading `OAuth` as `Oauth`, which collides with the brand. -2. **.NET / Microsoft (`ALL_CAPS` for ≤2-letter, `Pascal-then-lower` for ≥3):** `URL`, `ID`, `Sql`, `Json`. Pro: matches HTTP/RFC casing; con: harder to typo-check. - -The choice matters less than the consistency; today the SDK has both. +| URL | `Url` — 445 hits / 63 pkgs | `URLSearchParams` (JS built-in, every `client.ts`); `'URL'` enum value in `rfa` | +| ID | `Id` — 3303 hits / 71 pkgs | `'ID'` enum value in ~10 pkgs (e.g. `IpAccessListType.ID`, `GenieAttachment.ID`); `ACCOUNT_ID` (`SCREAMING_SNAKE` constant — different style class) | +| JSON | `Json` — 208 hits / 65 pkgs | `JSON.parse`/`JSON.stringify` (JS built-in, every `utils.ts`); occasional `'JSON'` enum value | +| SQL | `Sql` — 132 hits / 7 pkgs | `'SQL'` enum values; `DATABRICKS_SQL_ACCESS` (`SCREAMING_SNAKE` constant) | +| HTTP | `Http` — 2156 hits / 65 pkgs | `'HTTP request'` log strings in `utils.ts`; `HTTPS URL` in JSDoc | +| OAuth | `Oauth` — 29 hits in `oauth` pkg | **`OAuthAppIntegration`/`CustomOAuthAppIntegration` identifiers also in `oauth` pkg** — real mixed-form inconsistency in the same package | +| AWS | `Aws` — 120 hits / 7 pkgs | `AWS_SSE_S3` and friends (`SCREAMING_SNAKE` enum values) | +| GCP | `Gcp` — 198 hits / 7 pkgs | `'GCP'` JSDoc / enum string | +| IAM | (no `Iam*` TS identifiers — only `Iam`-prefixed model types in 2 pkgs) | `IAM role`, `IAM` in JSDoc comments in 4 pkgs — comment text only, not identifiers | +| URI | `Uri` — 27 hits / 6 pkgs | `URI` in JSDoc comments in 4 pkgs — comment text only | +| LLM | `Llm` — 147 hits / 4 pkgs | `LLM` in JSDoc / occasional enum string | +| DBFS | `Dbfs` — 76 hits / 3 pkgs | `DBFS` in JSDoc comments | +| ETag | `etag` field name | RFC 7232 §2.3 says `ETag` — minor canonical-form mismatch | +| RPC | `Rpc` — 5 hits / 3 pkgs | `RPC` in JSDoc comments — comment text only | + +**The apparent `ALL_CAPS` leaks in identifiers across the generated +packages are almost entirely:** + +- **JS built-ins** (`URLSearchParams`, `JSON.parse`/`JSON.stringify`, + `encodeURIComponent`) — part of the JavaScript standard library; the + SDK cannot rename them. +- **JSDoc comment text** copied from upstream proto comments (`IAM role`, + `S3 URI`, `HTTPS URL`, `OAuth scopes`, `DBFS`) — not identifiers. +- **Wire-format enum string values** (`'URL' = 'URL'`, `'SQL' = 'SQL'`, + `'ID' = 'ID'`) — preserved as-is from the upstream proto; the JSON + wire shape requires the literal uppercase strings. +- **`SCREAMING_SNAKE_CASE` constants** (`AWS_SSE_S3`, + `DATABRICKS_SQL_ACCESS`) — a different style class (SCREAMING_SNAKE + constants), not "ALL_CAPS acronym" leaks. + +**The one real generated-code identifier inconsistency** is `OAuth` +vs `Oauth` mixed within the `oauth` package itself +(`OAuthAppIntegration`, `CustomOAuthAppIntegration` vs `Oauth` field +positions). + +**Generator fix:** Adopt one policy in `typescript.mdc` and converge the +small number of `OAuth*` identifiers. The two consistent options: +1. **Google TS style guide (`Pascal-then-lower`):** `Url`, `Id`, `Sql`, `Json`, `Oauth`. Pro: matches what the generator already emits for ~99% of identifiers; lowest-churn path. Con: `Oauth` deviates slightly from the brand spelling `OAuth`. +2. **.NET / Microsoft (`ALL_CAPS` for ≤2-letter, `Pascal-then-lower` for ≥3):** `URL`, `ID`, `Sql`, `Json`, `OAuth`. Pro: matches HTTP/RFC casing and the brand. Con: requires renaming ~3300 `*Id` identifiers and ~445 `*Url` identifiers across the whole corpus — major generator+spec change. + +#### 3b. Hand-written code — 5/5 packages (`auth`, `core`, `databricks`, `sdk`, `options`) + +**Status: Fixed (2026-05-21).** The renames listed below were applied. +The historical table and prose are retained as a record of the BEFORE +state. + +The hand-written packages mixed the two styles within the same file. +The real inconsistencies (excluding JS built-ins and `SCREAMING_SNAKE` +constants) were: + +- **`core/apierror/`** mixed `HttpClient`/`HttpRequest`/`HttpResponse` (Pascal) with `HTTPBody`/`HTTPHeader`/`HTTPStatusCode` (ALL_CAPS) within the same module. +- **`auth/credentials/`** used `IDToken`/`IDTokenProvider` (ALL_CAPS) alongside `clientId`/`fetchCliToken` (Pascal) for short acronyms. +- **`core/apierror/APIError`** used ALL_CAPS for `API` while the rest of the codebase used Pascal-then-lower. + +> **Resolved:** all real identifier renames listed above were applied +> (105 files: 11 hand-written + 94 generated `utils.ts`). +> `APIError` → `ApiError` rename touched 105 files. +> `IDToken`/`IDTokenProvider` → `IdToken`/`IdTokenProvider`. +> `HTTPStatusCode`/`HTTPHeader`/`HTTPBody` → `httpStatusCode`/`httpHeader`/`httpBody`. +> `OAuthAuthorizationServer`, `OIDC*` and JS built-ins +> (`URLSearchParams`, `JSON.parse`, `encodeURIComponent`) kept under +> the platform-name exception. `SCREAMING_SNAKE_CASE` constants +> unaffected. + +### Theme 4. Brand drift / rebrand leakage — ~10/87 packages + +Several products were rebranded but the TS surface still carries the old +codename: + +- `warehouses` — every TS type is `Endpoint*` (legacy "SQL Endpoints" name) despite the package being named for the modern "SQL Warehouses" product. +- `pipelines` — uses `Update` as the noun for "pipeline run" (DLT-era terminology); the product is now "Lakeflow Declarative Pipelines". +- `lakeview` — the package name is the old codename; the product is "AI/BI Dashboards". +- `repos` — package name is legacy; the product is "Git folders". The type `RepoInfo` should be `GitFolder`. +- `experiments` — MLflow experiments; cross-package overlap with `forecasting` ML APIs. +- `genie` — codename for "AI/BI Genie" / "Genie Spaces". + +**Generator fix:** Per-product spec needs updates; the rename can land via a +generator alias map (`Endpoint` → `Warehouse` in `warehouses` only, etc.). + +### Theme 5. Proto-architectural-leak infixes — ~10/87 packages, ~50 findings (substantially shrunk) + +Internal proto / service-tier identifiers leak through the codegen and show +up as mid-position infix tokens that have no meaning to a TS SDK consumer. +The 2026-05-22 generator regen retroactively validated generator rule §8.2 +and renamed the dominant `*Public*Request` sub-pattern across every +account-tier package — ~81 findings moved to per-package `Fixed` sections. + +**Status after the 2026-05-22 regen:** + +- The `*Public*` mid-position infix sub-pattern is largely fixed. Account-tier + packages that previously carried 14-21 such findings each + (`networking` 21 → 0, `workspaces` 21 → 0, + `metastores` 20 → 0, `credentials` 12 → 0, + `storageconfigurations` 14 → 0, `keyconfigurations` 3 → 0) now have zero + active `*Public*Request` findings. The residual active findings on these + packages are unrelated singular/plural and category-1 issues that the + rescan surfaced once the proto-leak noise cleared. +- **`*CustomerFacing*` qualifier still survives in `networking`** — 40+ + identifiers (`CustomerFacingIngressNetworkPolicy`, + `CustomerFacingVpcEndpointUseCase`, etc.) in active source. Not yet + scanned as findings because the regen left them untouched; they are the + same proto-tier qualifier and should be flagged in a follow-up pass. +- **`*Proto` suffix** still active in a handful of identifiers: + `DatabricksServiceExceptionProto`, + `DatabricksServiceExceptionWithDetailsProto`, `TriggerStateProto` (jobs + `model.ts`). The companion JSDoc usually says "Proto defined to model …" — + that is the right place for the word; in the identifier it leaks the wire + format. +- **`*Service*` mid-position infix.** `ServiceErrorCode` / `ServiceError` + in `statementexecution`. The `Service` token is a proto/gRPC + architectural-layer noun and not a domain concept. +- **`*V2*` mid-position.** `RunLifecycleStateV2` (jobs), + `unmarshalListExternalMetadataResponseV2Schema` (externalmetadata). + Version goes in the import path / subpath export, not the identifier. +- **JSDoc proto-layer banners.** `forecasting` and `pipelines` both ship + JSDoc with "Public RPC" / "Wrapper message" / "Public facing RPC requests + and responses *****" verbatim — banner comments that exist solely for the + proto file structure. + +**Generator fix:** Strip proto-architectural-tier markers from the public +TS surface emit. The set is small and closed: `Public`, `Internal`, +`Proto`, `Service` (when mid-position and not the domain word), `Backend`, +`Manager`, `Handler`, `Impl`, `Rpc`, `Grpc`, `Wrapper`, `CustomerFacing`, +mid-position `V`. Carried as a single generator-only rule in §8.2 below. +The `*Public*Request` sub-pattern has now shipped via the 2026-05-22 regen, +which is a retroactive validation of the rule but does not close it out. --- ## 2. Cross-package duplication & overlap -The audits surfaced ~30 pairs/triplets/quartets of packages that overlap +The audits surfaced ~20 pairs/triplets/quartets of packages that overlap on a single underlying concept. Each row is a real user-facing pain point: "I want to do X — which of these N packages do I import?" -### 2.1 Settings (4-way overlap — the worst case) +### 2.1 Settings (2-way overlap — was a 4-way) + +The 2026-05-22 regen consolidated the previous 4-way fanout +(`settings` + `accountsettings` + `workspacesettings` + `workspaceconf`) +into: | Package | Style | What it really is | |---|---|---| -| `settings` (v2) | Generic polymorphic value | The future "v2" key/value API | -| `accountsettings` | Per-feature endpoints | Per-toggle CRUD at the account level | -| `workspacesettings` | Per-feature endpoints | Per-toggle CRUD at the workspace level | -| `workspaceconf` | Free-form K/V map | Legacy untyped `map` settings | +| `settings` (v2) | Generic polymorphic value | Account- and workspace-scoped settings under the unified v2 surface | +| Retired | — | `accountsettings`, `workspacesettings`, `workspaceconf` were retired in the regen; their findings are in the orphan audits | + +`settings/v2/model.ts` now carries 84 active findings — the cross-package +duplicates (`BooleanMessage`, `StringMessage`, `RestrictWorkspaceAdminsMessage`, +`PersonalComputeMessage`) are now collapsed into a single surface but the +type-naming friction remains. -`BooleanMessage`, `StringMessage`, `IntegerMessage`, -`RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, -`AibiDashboardEmbeddingAccessPolicy`, `PersonalComputeMessage` are -**defined verbatim** in both `settings/v2/model.ts` and -`workspacesettings/v1/model.ts`. A consumer importing both gets two -distinct TS types with the same name. +### 2.2 Secrets (2-way overlap, was 4-way) -### 2.2 Secrets (4-way overlap) +The 2026-05-20 regeneration deleted both `serviceprincipalsecrets` and +`serviceprincipalsecretsproxy`. The remaining secrets surface is: | Package | What it really is | |---|---| | `secrets` | Workspace-level Secret Manager (scopes + key/value) | | `secretsuc` | Unity Catalog three-level-namespaced secrets | -| `serviceprincipalsecrets` | Account-level OAuth client secrets on SPs | -| `serviceprincipalsecretsproxy` | Workspace-level *byte-identical* clone of the above | -Every package exports a class literally named `Client`, and three of the -four also export a type literally named `Secret`. `serviceprincipalsecrets` -and `serviceprincipalsecretsproxy` are byte-for-byte identical at the -file level (verified by md5 in the audit); the "proxy" word never appears -inside the code or URL of either. +Both packages still export a class literally named `Client` and a type +literally named `Secret`. The previous byte-identical `*proxy` duplicate +no longer exists. ### 2.3 Credentials (3-way overlap) @@ -272,17 +460,15 @@ inside the code or URL of either. The bare type name `Credential` exists in two of these and `Credentials` exists in the third. -### 2.4 Identity / IAM (multi-way overlap) +### 2.4 Identity / IAM (shrunk further by the 2026-05-22 regen) -- `iam` exposes `*` + `*Proxy` versions of every method (e.g. - `createGroup` + `createGroupProxy`, etc.) — 17 endpoint pairs (44 - request types collapse to 22 unique shapes). -- `accountaccesscontrol` + `accountaccesscontrolproxy` — file-level - duplicate; the "proxy" suffix is invisible in code/URL. -- `permissions` overlaps with `iam` and `accountaccesscontrol` on the - rule-set + grant-rule data model. -- `workspaceassignment` overlaps with the workspace-assignment surface - inside `iam`. +- `iam` still exposes `*` + `*Proxy` versions of every method (e.g. + `createGroup` + `createGroupProxy`, etc.) — 17 endpoint pairs. +- `accessmanagement` (NEW in the 2026-05-22 regen) is the consolidated + umbrella for what used to be `permissions`, `accountaccesscontrol`, + `accountaccesscontrolproxy`, and `workspaceassignment`. Covers object + permissions, permission levels, rule sets, and workspace assignments + in a single import path. ### 2.5 Tokens @@ -291,8 +477,8 @@ exists in the third. | `tokens` | User-self PAT management | | `tokenmanagement` | Admin-of-others PAT management | -Both export `Client`, both export `ListTokens`, `RevokeToken`, -`UpdateToken`. They duplicate the entire `AutoscopeState` enum verbatim. +Both export `Client`, both export request types named identically. They +duplicate the entire `AutoscopeState` enum verbatim. ### 2.6 Tags (3-way split) @@ -307,18 +493,11 @@ Three packages, three `Client` classes, three near-identical `entityId: string`, the UC variant has `entityName: string` — same logical field, different name, both string. -### 2.7 Quality / Data monitoring (3-way overlap, all deprecated) - -| Package | Singular/plural | What it really is | -|---|---|---| -| `qualitymonitor` | singular | UC schema-level monitor (anomaly detection); deprecated | -| `qualitymonitors` | plural | UC table-level monitor (Lakehouse Monitoring); deprecated | -| `dataquality` | n/a | The new unified replacement API | +### 2.7 Quality / Data monitoring (consolidated to one) -Singular vs plural is the *only* differentiator between the first two -package names. Both are deprecated in favour of `dataquality`. Three -packages, three vocabularies (`QualityMonitor`, `DataMonitorInfo`, -`Monitor`), three `Client`s. +The 2026-05-22 regen retired `qualitymonitor` and `qualitymonitors` (both +deprecated). The only active surface is `dataquality`. Two former orphans +no longer contribute to the active total. ### 2.8 Model Registry @@ -330,25 +509,27 @@ packages, three vocabularies (`QualityMonitor`, `DataMonitorInfo`, The legacy package has the canonical-sounding name; the UC replacement is hidden behind a plural noun. -### 2.9 Model Serving (3-way fragmentation) +### 2.9 Model Serving (consolidated) + +The three-way fragmentation +(`modelservingmanagement` + `modelservingquery` + `modelservingdebug`) +collapsed to two packages in the 2026-05-22 regen: | Package | What it really is | |---|---| -| `modelservingmanagement` | CRUD over serving endpoints | +| `modelserving` | CRUD over serving endpoints (was `modelservingmanagement`); absorbed the former `modelservingdebug` | | `modelservingquery` | Inference / `POST /invocations` | -| `modelservingdebug` | Logs / metrics endpoints | -All three operate on the same `serving-endpoints/{name}` URL space. The -type names differ across packages: `InferenceEndpoint` (management), -`Endpoint` (debug, query), and the URL itself says `serving-endpoints`. -Three names for the same noun. +The type-naming friction remains: `InferenceEndpoint` (in `modelserving`) +vs `Endpoint` (in `modelservingquery`) vs the URL `serving-endpoints`. ### 2.10 Cluster compute (overlapping warehouses) - `warehouses` exposes SQL Warehouses (formerly "SQL Endpoints"); the TS types still spell `Endpoint*` (e.g. `EndpointInfo`, `EndpointState`). -- `endpoints` (separate package!) exposes Vector Search endpoints with - type names like `Endpoint`, `EndpointType`, `EndpointStatus`. +- `vectorsearch` (consolidated from `endpoints` + `indexes`) exposes + Vector Search endpoints with type names like `Endpoint`, `EndpointType`, + `EndpointStatus`. Two packages, two `Endpoint*` type families, different products. @@ -368,10 +549,10 @@ types covering the same wire object. |---|---| | `features` | Feature definitions | | `featurestore` | Online stores / publishing | -| `materializedfeatures` | Feature materialisation | -Three packages, blurry boundaries (audit calls out "H1. Three sibling -packages, blurry boundaries" on `features.md`). `Feature` is overloaded. +The third sibling (`materializedfeatures`) was retired in the 2026-05-22 +regen; its surface is folded into `features` (`MaterializedFeature` types +already live there). ### 2.13 Budget / Usage policy @@ -385,18 +566,20 @@ packages, blurry boundaries" on `features.md`). `Feature` is overloaded. admits it: "(same structure as BudgetPolicy)". Reserved tag keys still say `"budget-policy-name"` in the usage-policy clone. -### 2.14 Workspace (5-package fanout) +### 2.14 Workspace (2-package fanout, was 5) + +The 2026-05-22 regen retired three of the previous five +(`workspace` → `workspaceobjects` rename, `workspaceassignment` → +`accessmanagement`, and both `workspaceconf` and `workspacesettings` +retired). The remaining set: | Package | What it really is | |---|---| -| `workspace` | Workspace filesystem (notebooks/folders/files) | -| `workspaceassignment` | Principal-to-workspace assignments | +| `workspaceobjects` | Workspace filesystem (notebooks/folders/files) | | `workspacebindings` | Securable-to-workspace bindings | -| `workspaceconf` | Untyped K/V configuration | -| `workspacesettings` | Typed workspace settings | -The bare name `workspace` is misleading — every Databricks API operates -"in a workspace". A name like `workspacefiles` would convey scope. +The bare name `workspace` was the most-overloaded; renaming to +`workspaceobjects` resolves the principal-vs-filesystem confusion. ### 2.15 Schemas (UC overlap) @@ -405,37 +588,59 @@ The bare name `workspace` is misleading — every Databricks API operates | `schemas` | User-defined UC schemas (full CRUD) | | `systemschemas` | Server-managed UC system schemas (enable/disable) | -### 2.16 OAuth - -| Package | What it really is | -|---|---| -| `oauthcustomappintegration` | CRUD for custom AND published OAuth app integrations | -| `oauthpublishedapp` | List-only of the published-app catalog | +### 2.16 OAuth (consolidated) -The first package's name is misleading — it covers both Custom and -Published despite saying only "Custom". Both packages are singular but -expose collection operations. +The 2026-05-22 regen merged `oauthcustomappintegration` and +`oauthpublishedapp` into a single `oauth` package, ending the +singular-plural split and the misleading "custom" name. The new package +covers both Custom and Published app integrations as well as the +published-app catalog. ### 2.17 Statement / Query / Command execution +`queryexecution` was deleted in the 2026-05-20 regeneration. The +remaining surfaces: + | Package | What it really is | |---|---| | `statementexecution` | Ad-hoc SQL on a SQL Warehouse | -| `queryexecution` | Re-run saved queries inside *published* dashboards | | `commandexecution` | Python/SQL/Scala/R via Clusters REPL | | `queries` | Saved-query CRUD | | `queryhistory` | Read-only query history list | -Five packages, three near-synonyms in the names (query/statement/command), +Four packages, three near-synonyms in the names (query/statement/command), disjoint scopes that the names do not telegraph. -### 2.18 Other notable overlaps +### 2.18 Account API cluster (consolidated in the 2026-05-22 regen) + +The 2026-05-20 regen first absorbed account-tier APIs into seven +previously-unaudited packages. The 2026-05-22 regen then renamed the +`*Public*Request` family across every one of them — ~81 findings moved to +`Fixed`. The remaining surface is the consolidated set: + +| Package | Account-tier surface | +|---|---| +| `workspaces` | Create/update/delete an account-managed workspace | +| `networking` | NCC, networks, private access settings, VPC endpoints, network policies | +| `storageconfigurations` | Account-level cloud storage configs (S3 root buckets) | +| `keyconfigurations` | Account-level customer-managed key configurations | +| `credentials` (account half) | `AccountsCreate*` family (the `*Public*` suffix has been removed) | +| `metastores` (account half) | `AccountsCreate*` family (the `*Public*` suffix has been removed) | +| `authentication` | Account-level token federation policies | +| `scim` | Account-level SCIM 2.0 user/group provisioning | +| `sharing` | Account-level Delta Sharing provider config | +| `accessmanagement` | Object permissions, permission levels, rule sets, workspace assignments (consolidated) | +| `logdelivery` | Account-level log delivery configs (was `logdeliveryconfigurations`) | + +The `*Public*Request` proto-leak that previously dominated this cluster is +no longer a concern. Residual `*CustomerFacing*` qualifiers in `networking` +are not yet flagged but match generator rule §8.2. + +### 2.19 Other notable overlaps - `lakeview` (the rebranded "AI/BI Dashboards" — name uses old codename). -- `cleanrooms` + `cleanroomassets` + `cleanroomautoapprovalrules` + - `cleanroomtaskruns` — four packages for one product surface. -- `serviceprincipalsecrets` ≡ `serviceprincipalsecretsproxy` (byte-identical). -- `accountaccesscontrol` ≈ `accountaccesscontrolproxy`. +- `cleanrooms` absorbed `cleanroomassets` + `cleanroomautoapprovalrules` + + `cleanroomtaskruns`; the four-package fanout is now a single package. - `supervisoragents` + `knowledgeassistants` + `customllms` — three packages in the LLM-orchestration space with bare-generic top-level type names (`SupervisorAgent`, `KnowledgeAssistant`, `CustomLlm`). @@ -452,14 +657,14 @@ expansion in code or JSDoc. A first-time user has to guess. | `rfa` | Request For Access | Package name only | `packages/rfa/` — no expansion in any TS identifier or JSDoc. The wire URL `/api/3.0/rfa/...` is the only other carrier. | | `uc` | Unity Catalog | Package suffix (`secretsuc`), URL `/unity-catalog/`, comment references | Never appears as a type prefix. | | `sp` | Service Principal | Field prefixes (`accountSpStatus`, `spId`) | Inconsistent — sometimes spelled out (`servicePrincipal`), sometimes `sp`. | -| `conf` | Configuration | `workspaceconf` (package), `EndpointConfPair` (type) | One four-letter abbreviation that the rest of the SDK consistently spells out. | +| `conf` | Configuration | `EndpointConfPair` (type) (legacy `workspaceconf` package retired in 2026-05-22 regen) | One four-letter abbreviation that the rest of the SDK consistently spells out. | | `dbu` | Databricks Unit | Cluster docs only | Not in type names. | | `dbr` | Databricks Runtime | `TerminationCode.DBR_IMAGE_RESOLUTION_FAILURE`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` | Acronym not expanded. | | `dbfs` | Databricks File System | `DbfsStorageInfo`, `disableLegacyDbfs` | Casing varies (`Dbfs` vs `DBFS` in JSDoc). | | `dlt` | Delta Live Tables | Comment references | The product was renamed to "Lakeflow Declarative Pipelines"; the type `Update` still reflects the DLT-era name. | | `csp` | Compliance Security Profile | `CspEnablementAccountSetting`, `Csp*` family | `Csp` casing is uniform; the acronym is not expanded. | | `esm` | Enhanced Security Monitoring | `EsmEnablementAccountSetting`, `Esm*` family | Same as CSP. | -| `dcp` | (settings v1 internal acronym) | `DcpAccountEnableMessage` | Audit at `accountsettings.md` flagged as cryptic. | +| `dcp` | (settings v1 internal acronym) | `DcpAccountEnableMessage` | Flagged as cryptic. | | `llm` | Large Language Model | `CustomLlm`, `LlmProxyPartnerPoweredAccount`, `Llm*` family | `Llm` casing is uniform across SDK. | | `sdp` | Serverless Declarative Pipelines | Comments | Internal acronym. | | `ldp` | Lakeflow Declarative Pipelines | Comments | Internal acronym. | @@ -498,13 +703,13 @@ multiple casings across packages — sometimes within the same file. | **URI** | `Uri`, `URI` | `endpointUri` vs JSDoc "URI". | | **SQL** | `Sql`, `SQL` | `SqlWarehouseSpec` (type), `DATABRICKS_SQL_ACCESS` (enum). | | **JSON** | `Json`, `JSON` | `JsonValue`, `JsonObject` (wkt types) vs `JSON.stringify` (built-in). | -| **OAuth** | `Oauth`, `OAuth` | Package `oauthcustomappintegration` (lowercased), type `OAuthAppIntegration` (PascalCase). | +| **OAuth** | `Oauth`, `OAuth` | Package `oauth` (lowercased), type `OAuthAppIntegration` (PascalCase). | | **PyPI** | `Pypi`, `PyPI` | `PypiLibrary` (type), JSDoc spells `PyPI`. | | **AWS** | `Aws`, `AWS` | `AwsAttributes` (type), `AWS_SSE_S3` (enum). | | **GCP** | `Gcp`, `GCP` | `GcpAvailability` (type), `GCP_QUOTA_EXCEEDED` (enum). | | **Azure** | `Azure` | Consistent. | | **LLM** | `Llm`, `LLM` | `CustomLlm` (type, field), JSDoc says `LLM`. | -| **HTTP** | `Http`, `HTTP` | `HttpClient` (type) vs JSDoc and headers. | +| **HTTP** | `Http`, `HTTP` | `HttpClient` (type) vs JSDoc and headers. Hand-written packages converged on Pascal-then-lower (`httpStatusCode`, `httpHeader`, `httpBody`) on 2026-05-21. | | **HTTPS** | `Https` | Consistent. | | **DBFS** | `Dbfs`, `DBFS` | `DbfsStorageInfo` vs `disableLegacyDbfs` vs JSDoc "DBFS". | | **DBR** | `Dbr`, `DBR` | Enum members all-caps. | @@ -512,7 +717,7 @@ multiple casings across packages — sometimes within the same file. | **CSP** | `Csp`, `CSP` | Type `Csp*`, JSDoc "CSP". | | **ESM** | `Esm`, `ESM` | Type `Esm*`, JSDoc "ESM". | | **IdP** | `Idp`, `IdP` | `idp*` fields, JSDoc "IdP". | -| **ETag** | `etag`, `eTag`, `ETag` | Three casings within one JSDoc comment block (`accountaccesscontrolproxy`). | +| **ETag** | `etag`, `eTag`, `ETag` | Three casings within one JSDoc comment block (formerly `accountaccesscontrolproxy`, now in `accessmanagement`). | | **ODBC** | `Odbc` | `OdbcParams`. | | **JDBC** | `Jdbc`, `JDBC` | Doc references only. | | **AI/BI** | `Aibi`, `AI/BI` | `AibiDashboard*` types, JSDoc says "AI/BI". | @@ -522,54 +727,22 @@ multiple casings across packages — sometimes within the same file. **Recommendation:** Pick one rule. The Google TypeScript Style Guide specifies `Pascal-then-lower` (`Url`, `Id`, `Json`, `Sql`) — this is the -current majority in the SDK. Document the choice in `.agent/rules/typescript.mdc` -§ 3 and enforce in CI. Wire format unchanged. +current majority in the SDK. The hand-written packages were converged on +this rule on 2026-05-21. Document the choice in +`.agent/rules/typescript.mdc` § 3 and enforce in CI. Wire format unchanged. --- -## 5. Package-name oddities - -Packages whose names themselves cause user-facing pain. - -| Package | Issue | Suggested rename | -|---|---|---| -| `rfa` | 3-letter cryptic acronym — never expanded in any TS identifier. | `accessrequests` | -| `workspaceconf` | `conf` is the only abbreviation of "configuration" in the SDK. | `workspaceconfig` | -| `secretsuc` | Two words mashed together; `uc` is invisible to readers. | `unitycatalogsecrets` or `ucsecrets` | -| `cleanroomautoapprovalrules` | 26-character compound, no separator. | `cleanroomautoapprovals` (drop "rules") or `cleanrooms/auto-approval-rules` subpath | -| `oauthcustomappintegration` | 25 chars; singular; *covers both Custom AND Published*. | `oauthappintegrations` (drop `custom`, pluralise) | -| `serviceprincipalsecretsproxy` | 28 chars; "proxy" appears nowhere in code or URL; byte-identical to `serviceprincipalsecrets`. | Merge into `serviceprincipalsecrets`. | -| `serviceprincipalsecrets` | 23 chars compound; sibling to four other `*secret*` packages. | `sp-credentials` or `service-principal-credentials` (hyphenated). | -| `accountaccesscontrolproxy` | 25 chars; byte-identical to `accountaccesscontrol`. | Merge into `accountaccesscontrol`. | -| `qualitymonitor` vs `qualitymonitors` | Singular vs plural, both deprecated, different APIs. | Drop both — consolidate to `dataquality`. | -| `tokens` vs `tokenmanagement` | "Tokens API" vs "Manage tokens" — both accurate, neither distinguishes user-self vs admin. | `usertokens` + `tokenadmin`. | -| `workspace` | Most overloaded of 5 `workspace*` packages — every API operates "in a workspace". | `workspacefiles` (it's the FS API). | -| `endpoints` | Doesn't say "vector search" — collides conceptually with the legacy `Endpoint*` types in `warehouses`. | `vectorsearchendpoints`. | -| `warehouses` | Right product name, but every TS type is `Endpoint*` (legacy proto name). | Keep; rename `EndpointInfo`/`EndpointState`/`EndpointTagPair`/`EndpointConfPair`/`EndpointSecurityPolicy`/`EndpointSpotInstancePolicy` → `Warehouse*`. | -| `lakeview` | Old codename; product is now "AI/BI Dashboards". | `dashboards` or `aibidashboards`. | -| `repos` | Legacy codename; product is "Git folders". | `gitfolders`. | -| `database` vs `postgres` | Two packages, one product (Lakebase managed Postgres). | Merge; keep `lakebase` or `managedpostgres`. | -| `modelregistry` vs `registeredmodels` | Singular "the registry" vs plural "the entries" — actually two products (workspace MLflow vs UC). | `mlflowregistry` + `ucregisteredmodels`. | -| `qualitymonitor` (singular) | Only its singular form distinguishes from `qualitymonitors` (plural). | See row above. | -| `billableusagedownload` | Verb in package name (`download`). Only such case in the SDK. | `billableusage` (move verb to method). | -| `experiments` | Bare-generic word — also a common term in feature-flag SDKs. | `mlflowexperiments`. | -| `bundle` | Bare-generic word — Webpack/Vite/Rollup all have "bundles". | `assetbundles`. | -| `genie` | Codename — product is "Genie Spaces"/"AI/BI Genie". | Keep `genie` but drop the `Genie*` type prefix throughout. | -| `customllms` | Plural, but the type is singular (`CustomLlm`). | OK; flag for `LLM` vs `Llm` casing policy. | -| `disasterrecovery` | OK; `FailoverFailoverGroupRequest` is the type to fix. | n/a | -| `supervisoragents` | `Supervisor` + `Agent` both extremely generic. | `routeragents` or `agentorchestrators`. | -| `knowledgeassistants` | OK, but generic enough that future overlap is likely. | n/a | -| `commandexecution` | Mixes three resources (Command, Context, Cluster); name picks one. | Keep, but split the type prefixes (`CommandStatus` vs `ContextStatus`). | -| `policyfamilies` | OK but uses both "Family" and "Policy Family" interchangeably. | n/a | -| `connections` | Bare-generic; collides with HTTP/DB connections in user code. | `ucconnections` or `foreignconnections`. | -| `tables`, `volumes`, `schemas`, `catalogs`, `functions` | All bare-plural UC nouns. Cross-package overlap with `Dependency`, `SecurableType`, `EncryptionDetails`, `EffectivePredictiveOptimizationFlag` is heavy. | Keep names; hoist shared types to a `uc-common` package. | - ---- - -## 6. Top-50 highest-impact individual findings +## 5. Top-50 highest-impact individual findings Picked one per package where possible, prioritising ones with broad reuse. -Findings ranked High severity in their audit. Each entry: file + symbol + the +Findings ranked High severity in their audit. Entries whose package was +deleted/merged in the 2026-05-20 or 2026-05-22 regeneration have been +removed; entries about the now-pruned enum-name-prefix theme and +`*_UNSPECIFIED` sentinel existence have been removed; entries whose +underlying finding has moved to `Fixed` after the 2026-05-22 regen (the +`*Public*Request` proto-leak across `networking`, `workspaces`, +`metastores`, etc.) have been removed. Each entry: file + symbol + the generator pattern it exemplifies. | # | Package | File:Line | Symbol / Issue | Pattern | @@ -580,233 +753,222 @@ generator pattern it exemplifies. | 4 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | | 5 | `pipelines` | `model.ts:212-2507` | `Pipelines*` prefix on 15 types in a package called `pipelines` (singular). | Type-name prefix repeats package | | 6 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | -| 7 | `abacpolicies` | `model.ts:7-14` | `PolicyType.POLICY_TYPE_UNSPECIFIED`/`POLICY_TYPE_ROW_FILTER`/etc. | Redundant enum prefix | -| 8 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | -| 9 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | -| 10 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | -| 11 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | -| 12 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission.CAN_USE` — `App` token thrice; package-name re-prefix throughout. | Redundant prefix | -| 13 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | -| 14 | `genie` | `model.ts passim` | 40 of ~70 types prefixed `Genie*`; remaining have no prefix. | Inconsistent type prefix | -| 15 | `commandexecution` | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` is reused for both `create()` (context id) and `execute()` (command queued) — type repurposed across two semantically different operations. | Type repurposing | -| 16 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | -| 17 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | -| 18 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | -| 19 | `secrets` | `model.ts:passim` | `ListAcls_Response.items` should be `acls` (parallel to `ListScopes_Response.scopes` / `ListSecrets_Response.secrets`). | Field-name vocabulary drift | -| 20 | `qualitymonitor` | package + types | Singular `qualitymonitor` vs plural `qualitymonitors` — different APIs distinguished only by trailing `s`. | Package-name overlap | -| 21 | `qualitymonitors` | model + types | Both deprecated; `DataMonitorInfo` vs `Monitor` vs `QualityMonitor` — three names for one wire object. | Duplicate concept | -| 22 | `modelservingmanagement` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | -| 23 | `modelservingmanagement` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | -| 24 | `oauthcustomappintegration` | `model.ts:passim` | 18 types named `*OAuthAppIntegration*` — package name re-stated in every type. | Type-name prefix | -| 25 | `oauthcustomappintegration` | package | Name says "custom" but covers both Custom and Published integrations. | Misleading package name | -| 26 | `serviceprincipalsecretsproxy` | files | Byte-identical to `serviceprincipalsecrets` — "proxy" never in code/URL. | Duplicate package | -| 27 | `serviceprincipalsecrets` | `model.ts:42, 59` | Verb-phrase request types lacking `Request` suffix (`CreateServicePrincipalSecret`, etc.); 23-char package-noun re-stated on every type. | Verb-as-noun + Type-name prefix | -| 28 | `accountaccesscontrol` | `model.ts:73, 89, 105` | `RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest` — three names for one shape with overlapping `name` fields. | Duplicate concept | -| 29 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | -| 30 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | -| 31 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | -| 32 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | -| 33 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | -| 34 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | -| 35 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | -| 36 | `cleanroomautoapprovalrules` | every type | `CleanRoomAutoApprovalRule` re-states the 26-char package name on every type. | Type-name prefix | -| 37 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | -| 38 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | -| 39 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | -| 40 | `permissions` | `model.ts` | `GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions` — verb-phrase request types. | Verb-as-noun | -| 41 | `permissions` + `grants` + `iam` + `accountaccesscontrol` | passim | Permissions/grants/rule-sets fragmented across 4 packages with overlapping vocabularies. | Cross-package fragmentation | -| 42 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | -| 43 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | -| 44 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | -| 45 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | -| 46 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | -| 47 | `materializedfeatures` | package | `materializedfeatures` does not match contents (contains feature-tag CRUD, not materialisation logic). | Misleading package name | -| 48 | `marketplaces` | `model.ts:passim` | 14 verb-phrase request types (`Create`, `Update`, `Delete`, `Search`, `Get`, `List` variants) in a single file. | Verb-as-noun | -| 49 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | -| 50 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum has 22 values with inconsistent casing (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Acronym/brand-value casing | +| 7 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | +| 8 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | +| 9 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | +| 10 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | +| 11 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission.CAN_USE` — `App` token thrice; package-name re-prefix throughout. | Redundant prefix | +| 12 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | +| 13 | `genie` | `model.ts passim` | 40 of ~70 types prefixed `Genie*`; remaining have no prefix. | Inconsistent type prefix | +| 14 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | +| 15 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | +| 16 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | +| 17 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | +| 18 | `secrets` | `model.ts:passim` | `ListAcls_Response.items` should be `acls` (parallel to `ListScopes_Response.scopes` / `ListSecrets_Response.secrets`). | Field-name vocabulary drift | +| 19 | `dataquality` | model + types | `ListMonitorRequest` singular for list of monitors; `qualitymonitor`/`qualitymonitors` deprecated and retired in 2026-05-22 regen. | Singular/plural mismatch | +| 20 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | +| 21 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | +| 22 | `oauth` | `model.ts:passim` | After the merge, `OAuthAppIntegration*` types still re-state the package name on every shape. | Type-name prefix | +| 23 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, the type-name overlap with `iam` and `grants` is still present. | Cross-package fragmentation | +| 24 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 25 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | +| 26 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | +| 27 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | +| 28 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | +| 29 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 30 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | +| 31 | `cleanrooms` | `model.ts:passim` | After absorbing 3 sibling packages, `CleanRoom*` re-prefix still pervades. | Type-name prefix | +| 32 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | +| 33 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | +| 34 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | +| 35 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | +| 36 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | +| 37 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 38 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | +| 39 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 40 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | +| 41 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum has 22 values with inconsistent casing (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Acronym/brand-value casing | +| 42 | `clusters` | `model.ts:175-734` | `TerminationCode` enum has 150+ values with inconsistent casing (`AZURE_BYOK_*`, `NPIP_*`, `K8S_DBR_*`, `AWS_*`). | Acronym/brand-value casing | +| 43 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | +| 44 | `bundle` | package + types | Bare "bundle" word collides with Webpack/Vite/Rollup; verb-as-noun residue in request types. | Generic naming | +| 45 | `instancepools` | `model.ts:passim` | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | +| 46 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection`; `tpe` typo (likely intended `type`). | Generator stutter + typo | +| 47 | `settings` | `model.ts:passim` | After the regen consolidation, the v2 surface still carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrapper sprawl. | Generic + cryptic | +| 48 | `jobs` | `model.ts:passim` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | +| 49 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun, not a domain concept. | Proto-architectural leak (`Service` infix) | +| 50 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | --- -## 7. By-the-numbers (all 98 packages, sorted by total findings) +## 6. By-the-numbers (all 87 active packages, sorted by total findings) | # | Package | Findings | Top theme | |---|---|---|---| -| 1 | jobs | 177 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes | -| 2 | endpoints | 111 | `Endpoint*` (vector search) vs `endpoints` (other products); brand-name collision | -| 3 | warehouses | 109 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | -| 4 | pipelines | 88 | `Update` noun = pipeline run; `Pipelines*` prefix on every type | -| 5 | settings | 87 | Cross-package duplication with `accountsettings`/`workspacesettings`/`workspaceconf` | -| 6 | postgres | 83 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | -| 7 | clusters | 76 | Per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | -| 8 | budgets | 73 | Budget vs `budgetpolicy` duplication | -| 9 | apps | 67 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | -| 10 | genie | 64 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | -| 11 | catalogs | 60 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | -| 12 | tables | 59 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 13 | modelregistry | 59 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | -| 14 | iam | 56 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | -| 15 | clusterlibraries | 55 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 16 | schemas | 54 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | -| 17 | functions | 54 | `function` reserved-word; `fullNameArg`; cryptic single-letter enum variants | -| 18 | instanceprofiles | 53 | Bare verb request types; vague identifiers | -| 19 | experiments | 53 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | -| 20 | qualitymonitors | 52 | Plural vs singular `qualitymonitor`; both deprecated | -| 21 | instancepools | 50 | Massive structural duplication of `Create*`/`Edit*`/`*AndStats` | -| 22 | statementexecution | 48 | Package name overlaps `queryexecution`/`commandexecution`/`queries` | -| 23 | metastores | 48 | Structural duplicate of `MetastoreInfo`; `*Summary` returning the entity | -| 24 | cleanroomassets | 48 | `CleanRoom*` re-prefix on every type; `details`/`localDetails` discriminated-union arms | -| 25 | marketplaces | 47 | 14 verb-phrase request types; `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | -| 26 | workspacesettings | 45 | Cross-package duplicates with `settings`/`accountsettings`/`workspaceconf` | -| 27 | queryhistory | 45 | Vague `Query` types; cross-package overlap with `queries`/`queryexecution` | -| 28 | clusterpolicies | 45 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | -| 29 | features | 44 | Three sibling feature packages with blurry boundaries | -| 30 | dataquality | 44 | `ListMonitorRequest` singular for list of monitors | -| 31 | supervisoragents | 43 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | -| 32 | registeredmodels | 42 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | -| 33 | database | 42 | Package name overlaps `postgres`; deep proto nesting | -| 34 | accountsettings | 42 | `Csp`/`Esm`/`Llm`/`Dcp` cryptic acronyms; generic `value` discriminator | -| 35 | modelservingmanagement | 41 | `InferenceEndpoint` vs `ServingEndpoint` vs `serving-endpoints` URL — three names | -| 36 | rfa | 40 | 3-letter cryptic package name | -| 37 | globalinitscripts | 40 | Verb-as-noun requests; brittle `script_id` path-parameter handling | -| 38 | commandexecution | 39 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | -| 39 | qualitymonitor | 38 | Sibling-package collision with `qualitymonitors` | -| 40 | policyfamilies | 38 | "Family" + "Policy Family" mixed; underscored enums | -| 41 | knowledgeassistants | 37 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | -| 42 | indexes | 37 | Package name not "vector search"; `MiniVectorIndex` duplicates `VectorIndex` | -| 43 | files | 37 | `Read`/`Move`/`Put`/`Delete`/`Close`/`Create`/`MkDirs`/`AddBlock` — verb-as-noun (legacy DBFS) | -| 44 | onlinetables | 36 | Underspecified IDs; deprecation drift | -| 45 | externalmetadata | 36 | `SystemType.*_UNSPECIFIED`; brand-value casing (`POWER_BI`, `STREAM_NATIVE`) | -| 46 | queries | 35 | Three-package overlap with `queryhistory`/`queryexecution` | -| 47 | lakeview | 35 | Old codename (rebrand to "AI/BI Dashboards") | -| 48 | connections | 35 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 49 | alerts | 35 | Mixed v1/v2 | -| 50 | abacpolicies | 35 | `PolicyInfo`; verb-as-noun requests; redundant enum prefix | -| 51 | bundle | 34 | Generic package name (`bundle`); verb-as-noun requests | -| 52 | workspacebindings | 33 | Bare verb requests | -| 53 | usagepolicy | 33 | 1:1 clone of `budgetpolicy` | -| 54 | secrets | 33 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | -| 55 | repos | 33 | "Repos" legacy term; product is "Git folders" | -| 56 | permissions | 33 | Cross-package overlap with `iam`/`accountaccesscontrol`/`grants` | -| 57 | logdeliveryconfigurations | 33 | Long verbose names | -| 58 | credentials | 33 | 4× duplicate type pairs (`Credential*` vs `StorageCredential*`); cross-package with `auth/credentials` | -| 59 | customllms | 32 | `Llm` casing throughout | -| 60 | workspace | 31 | Most overloaded of 5 `workspace*` packages | -| 61 | modelservingquery | 31 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | -| 62 | environments | 31 | `Environment` generic name | -| 63 | entitytagassignments | 31 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 64 | tokens | 30 | Cross-package duplicate of `tokenmanagement` | -| 65 | tagpolicies | 30 | Three sibling tag packages with overlapping vocab | -| 66 | queryexecution | 30 | Package name far broader than scope (dashboards-only) | -| 67 | materializedfeatures | 30 | Package name doesn't match contents | -| 68 | cleanrooms | 30 | Redundant enum prefixes throughout | -| 69 | budgetpolicy | 30 | Sibling clone in `usagepolicy` | -| 70 | workspaceassignment | 28 | Cross-package overlap with `iam` | -| 71 | grants | 28 | Verb-phrase request types | -| 72 | featurestore | 28 | Cross-package duplicates in feature trio | -| 73 | tagassignments | 27 | Three-package tag split; sibling field-name drift | -| 74 | externallineage | 25 | `Direction_LineageDirection`; `tpe` typo | -| 75 | disasterrecovery | 25 | `FailoverFailoverGroupRequest` stutter | -| 76 | accountaccesscontrolproxy | 25 | 1:1 surface duplicate of `accountaccesscontrol` | -| 77 | tokenmanagement | 24 | Overlap with `tokens`; duplicate `AutoscopeState` enum | -| 78 | secretsuc | 24 | `uc` cryptic suffix; collides with `secrets` | -| 79 | workspaceconf | 23 | `conf` cryptic abbreviation; wire-shape regression | -| 80 | serviceprincipalsecrets | 23 | Identical to `serviceprincipalsecretsproxy`; verb-as-noun requests | -| 81 | volumes | 22 | `fullNameArg`; verb-as-noun requests | -| 82 | serviceprincipalsecretsproxy | 22 | Byte-identical to non-proxy version | -| 83 | notificationdestinations | 22 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 84 | usagedashboards | 21 | Vague type names | -| 85 | resourcequotas | 21 | Vague type names | -| 86 | modelservingdebug | 21 | Tiny package, narrow surface | -| 87 | billableusagedownload | 20 | Verb in package name (`download`) | -| 88 | dataclassification | 19 | Tag-domain overlap | -| 89 | gitcredentials | 17 | Three "Credentials" packages with different meanings | -| 90 | forecasting | 17 | Generic-named `Waiter` API; cross-package overlap with `experiments` | -| 91 | cleanroomautoapprovalrules | 17 | 26-char package name; `CleanRoomAutoApprovalRule` re-prefix | -| 92 | accountaccesscontrol | 16 | Sibling duplicate `accountaccesscontrolproxy` | -| 93 | oauthcustomappintegration | 15 | Package covers Custom AND Published despite name | -| 94 | externallocations | 15 | `IsolationMode_*`/`SseEncryptionAlgorithm_*` enum prefixing; cross-cloud queue type naming inconsistency | -| 95 | cleanroomtaskruns | 15 | `LifeCycle` casing; one of four cleanroom packages | -| 96 | systemschemas | 14 | Sibling-package collision with `schemas` | -| 97 | artifactallowlists | 14 | Vague type names | -| 98 | oauthpublishedapp | 12 | Singular but only `list*` endpoints | +| 1 | jobs | 169 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | +| 2 | warehouses | 100 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 3 | settings | 84 | Cross-package consolidation residue; cryptic acronyms (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | +| 4 | clusters | 78 | Per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | +| 5 | modelregistry | 66 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | +| 6 | pipelines | 64 | `Update` noun = pipeline run; `Pipelines*` prefix on every type; JSDoc "Public RPC" banners | +| 7 | apps | 63 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | +| 8 | genie | 62 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 9 | instanceprofiles | 61 | Bare verb request types; vague identifiers | +| 10 | tables | 58 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 11 | database | 55 | Package name overlaps `postgres`; deep proto nesting; proto-architectural infixes | +| 12 | postgres | 54 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | +| 13 | marketplaces | 52 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | +| 14 | statementexecution | 52 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | +| 15 | features | 51 | Three sibling feature packages with blurry boundaries (now reduced to 2 after `materializedfeatures` retirement) | +| 16 | experiments | 48 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 17 | globalinitscripts | 48 | Verb-as-noun requests; brittle `script_id` path-parameter handling; proto suffix | +| 18 | modelserving (was modelservingmanagement + modelservingdebug) | 47 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | +| 19 | queryhistory | 47 | Vague `Query` types; cross-package overlap with `queries` | +| 20 | instancepools | 44 | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`; proto-suffix | +| 21 | clusterpolicies | 41 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | +| 22 | dataquality | 41 | `ListMonitorRequest` singular for list of monitors | +| 23 | policyfamilies | 41 | "Family" + "Policy Family" mixed; underscored enums | +| 24 | accessmanagement (was permissions + workspaceassignment + accountaccesscontrol(+proxy)) | 38 | Permissions/grants/rule-sets fragmentation; absorbed account access control | +| 25 | knowledgeassistants | 37 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | +| 26 | supervisoragents | 37 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 27 | commandexecution | 36 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | +| 28 | externalmetadata | 36 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | +| 29 | rfa | 36 | 3-letter cryptic package name | +| 30 | alerts | 35 | Mixed v1/v2 | +| 31 | credentials | 35 | UC vs auth duplicate; `Accounts*` family (the `Public*` infix has been removed in the 2026-05-22 regen) | +| 32 | lakeview | 35 | Old codename (rebrand to "AI/BI Dashboards") | +| 33 | queries | 35 | Three-package overlap with `queryhistory`/`statementexecution` | +| 34 | usagepolicy | 35 | 1:1 clone of `budgetpolicy` | +| 35 | bundle | 34 | Generic package name (`bundle`); verb-as-noun requests | +| 36 | iam | 33 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | +| 37 | onlinetables | 33 | Underspecified IDs; deprecation drift | +| 38 | customllms | 32 | `Llm` casing throughout | +| 39 | modelservingquery | 30 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 40 | secrets | 30 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | +| 41 | budgetpolicy | 29 | Sibling clone in `usagepolicy` | +| 42 | connections | 29 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 43 | featurestore | 29 | Cross-package duplicates in feature trio | +| 44 | tagassignments | 29 | Three-package tag split; sibling field-name drift | +| 45 | workspaceobjects (was workspace) | 29 | Filesystem scope clarified by rename; `fullNameArg` residue | +| 46 | cleanrooms (absorbed cleanroomassets + cleanroomautoapprovalrules + cleanroomtaskruns) | 28 | Type-prefix `CleanRoom*` pervades the consolidated package | +| 47 | clusterlibraries | 28 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 48 | environments | 28 | `Environment` generic name | +| 49 | logdelivery (was logdeliveryconfigurations) | 28 | Renamed; legacy long name fixed | +| 50 | vectorsearch (was endpoints + indexes) | 28 | `Endpoint*` and `VectorIndex*` overlap; vector search renamed in place | +| 51 | entitytagassignments | 27 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 52 | repos | 27 | "Repos" legacy term; product is "Git folders" | +| 53 | abacpolicies | 26 | `PolicyInfo`; verb-as-noun requests | +| 54 | workspacebindings | 26 | Bare verb requests | +| 55 | budgets | 25 | Budget vs `budgetpolicy` duplication | +| 56 | externallineage | 24 | `Direction_LineageDirection`; `tpe` typo | +| 57 | files | 24 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | +| 58 | notificationdestinations | 24 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 59 | secretsuc | 24 | `uc` cryptic suffix; collides with `secrets` | +| 60 | disasterrecovery | 23 | `FailoverFailoverGroupRequest` stutter | +| 61 | functions | 23 | `function` reserved-word; `fullNameArg`; cryptic single-letter enum variants | +| 62 | tokens | 22 | Cross-package duplicate of `tokenmanagement` | +| 63 | gitcredentials | 21 | Three "Credentials" packages with different meanings | +| 64 | grants | 21 | Verb-phrase request types | +| 65 | billableusagedownload | 20 | Verb in package name (`download`) | +| 66 | tokenmanagement | 19 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 67 | usagedashboards | 19 | Vague type names | +| 68 | dataclassification | 18 | Tag-domain overlap | +| 69 | resourcequotas | 18 | Vague type names | +| 70 | tagpolicies | 18 | Three sibling tag packages with overlapping vocab | +| 71 | volumes | 18 | `fullNameArg`; verb-as-noun requests | +| 72 | registeredmodels | 17 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | +| 73 | schemas | 17 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | +| 74 | artifactallowlists | 15 | Vague type names | +| 75 | metastores | 15 | Structural duplicate of `MetastoreInfo` — 20 `Accounts*MetastorePublic*` findings moved to Fixed in 2026-05-22 regen | +| 76 | catalogs | 13 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | +| 77 | externallocations | 13 | `nameArg` cryptic suffix; cross-cloud queue type naming inconsistency (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | +| 78 | scim | 13 | Account-tier SCIM 2.0 user/group provisioning; proto-architectural surface | +| 79 | systemschemas | 13 | Sibling-package collision with `schemas` | +| 80 | forecasting | 11 | Generic-named `Waiter` API; cross-package overlap with `experiments`; "Wrapper message" JSDoc | +| 81 | oauth (was oauthcustomappintegration + oauthpublishedapp) | 11 | OAuth Custom + Published app integrations consolidated; type-name prefix `OAuthAppIntegration*` persists | +| 82 | sharing | 5 | Account-tier Delta Sharing provider config | +| 83 | workspaces | 5 | Singular/plural residue after 16 `*Public*Request` findings moved to Fixed | +| 84 | authentication | 4 | Account-tier token federation policies | +| 85 | networking | 4 | Singular/plural residue after 17 `*Public*Request` findings moved to Fixed; ~40 active `CustomerFacing*` identifiers not yet flagged | +| 86 | storageconfigurations | 4 | Sparse account-tier residue after `*Public*Request` findings moved to Fixed | +| 87 | keyconfigurations | 1 | Singular `ListCustomerManagedKeyRequest` residue after `*Public*Request` findings moved to Fixed | + +### Retired audits (24 — excluded from the active total) + +These audit files exist as historical record. Their source packages were +removed or consolidated in the 2026-05-20 or 2026-05-22 regen; their +findings have been migrated to the successor packages where applicable. +The retired audits each carry a status banner at the top indicating the +consolidation date. + +| Retired audit | Successor (where applicable) | +|---|---| +| `accountaccesscontrol` | merged into `accessmanagement` | +| `accountaccesscontrolproxy` | removed (proxy package retired) | +| `accountsettings` | merged into `settings` | +| `cleanroomassets` | merged into `cleanrooms` | +| `cleanroomautoapprovalrules` | merged into `cleanrooms` | +| `cleanroomtaskruns` | merged into `cleanrooms` | +| `endpoints` | merged into `vectorsearch` | +| `indexes` | merged into `vectorsearch` | +| `logdeliveryconfigurations` | renamed to `logdelivery` | +| `materializedfeatures` | merged into `features` | +| `modelservingdebug` | merged into `modelserving` | +| `modelservingmanagement` | merged into `modelserving` | +| `oauthcustomappintegration` | merged into `oauth` | +| `oauthpublishedapp` | merged into `oauth` | +| `permissions` | renamed to `accessmanagement` | +| `qualitymonitor` | deprecated; replaced by `dataquality` | +| `qualitymonitors` | deprecated; replaced by `dataquality` | +| `queryexecution` | removed outright | +| `serviceprincipalsecrets` | removed outright | +| `serviceprincipalsecretsproxy` | removed outright | +| `workspace` | renamed to `workspaceobjects` | +| `workspaceassignment` | merged into `accessmanagement` | +| `workspaceconf` | merged into `settings` | +| `workspacesettings` | merged into `settings` | --- -## 8. Generator-level recommendations - -Ranked by impact across all 98 packages. Each item is one template change. - -### 8.1 Drop the redundant enum-name prefix on members - -`PolicyType.POLICY_TYPE_ROW_FILTER` → `PolicyType.RowFilter` (PascalCase -preferred for new code; SCREAMING_SNAKE acceptable if the project policy -chooses it). Map the wire value `POLICY_TYPE_ROW_FILTER` via Zod transform. -Drop all `*_UNSPECIFIED` members and rely on the field's optional -`?:`/`undefined` for "unset". Affects ~84/98 packages. - -### 8.2 Append `Request` to every request DTO type - -`DeletePolicy` → `DeletePolicyRequest`. Eliminates verb-as-noun confusion -in import lists and resolves the `client.delete(req: Delete)` collision -patterns in `workspace`, `files`, `experiments`, `grants`, and ~75 other -packages. Affects ~80/98 packages. - -### 8.3 Drop the `Info`/`Spec`/`Details` suffix on canonical entities - -`RepoInfo` → `Repo`, `PolicyInfo` → `Policy`, `SchemaInfo` → `Schema`, -`CredentialInfo` → `Credential`, `MetastoreInfo` → `Metastore`, -`CatalogInfo` → `Catalog`. (Suffix can stay where the SDK genuinely has -both `Foo` and `FooInfo` and they mean different things.) Affects ~70/98 -packages. - -### 8.4 Adopt one acronym-casing policy - -Decide on `Pascal-then-lower` (`Url`, `Id`, `Json`, `Sql`, `Oauth`, -`Pypi`, `Aws`, `Llm`) or `ALL_CAPS-for-≤2` (`URL`, `ID`, `Json`, `Sql`, -`OAuth`, `PyPI`, `AWS`, `Llm`). Apply consistently to: -type names (`HttpRequest` vs `HTTPRequest`), -field names (`webhookUrl` vs `webhookURL`), -enum values (`URL` vs `Url` — the latter avoids JS-global collision). -Affects 98/98 packages. - -### 8.5 Rename `Client` per package - -Every package exports a class literally named `Client`. Imagine a user -with `jobs`, `clusters`, `pipelines` all importing `Client`. Rename to -`Client` — `JobsClient`, `ClustersClient`, `PipelinesClient`, -`WarehousesClient`. Removes the most common cross-package alias-on-import -pattern. Affects 98/98 packages. +## 7. Generator-level recommendations -### 8.6 Strip the package-name prefix from type names +The previous §§8.1–8.6 recommendations have all been retired: -When a type name begins with the package's domain noun and the unprefixed -name does not clash with another type in the same package, drop the -prefix. `Pipelines*` → drop, `Genie*` → drop, `CleanRoom*` → drop, -`OAuthAppIntegration*` → drop where unambiguous, `Tag*` → drop in -single-domain packages. Affects ~70/98 packages. +- The enum-name-prefix recommendation (former §8.1) is withdrawn — see prune + note 5 (TS member names mirror the wire identifier intentionally). +- The `Info`/`Spec`/`Details` suffix recommendation (former §8.2) is an + API-team decision, not a generator template change. +- The acronym-casing policy recommendation (former §8.3) is dropped at the + generator level; the inconsistencies are still cataloged in §4 as an + observational reference. +- The `Client` rename recommendation (former §8.4) is a product decision, + not a generator concern. +- The `Request` suffix recommendation (former §8.5) is **Done**: every + request DTO is now emitted with a `Request` suffix. +- The strip-package-name-prefix recommendation (former §8.6) is an API-team + decision, not a generator template change. -### 8.7 (Bonus) Surface deprecations as `@deprecated` JSDoc tags +### 7.1 Surface deprecations as `@deprecated` JSDoc tags Today the audits found dozens of fields whose JSDoc text says "deprecated" in prose but does not carry the `@deprecated` tag, so IDEs do not strike them through. Examples: `Environment.client`, `Run.numberInJob`, `ServedModel.modelName`, `EndpointCoreConfig.servedModels`, every method -in `qualitymonitor`/`qualitymonitors`. A simple template change — when -the proto description starts with "Deprecated", emit `@deprecated` — -catches all of them. +in `qualitymonitor`/`qualitymonitors` (both retired). A simple template +change — when the proto description starts with "Deprecated", emit +`@deprecated` — catches all of them. --- -## 9. Generator-only recommendations +## 8. Generator-only recommendations The following recommendations are template-level fixes that the generator emits identically across every package. Rather than carry the -same finding in 98 per-package audits, each rule is recorded once here. +same finding in 87 per-package audits, each rule is recorded once here. Each item names the rule, why it is generator-only, the approximate package count it appeared in before promotion, and an illustrative example. -### 9.1 Drop the duplicate `list*Iter()` paginator method +### 8.1 Drop the duplicate `list*Iter()` paginator method **Rule:** Drop the duplicate `list*Iter()` paginator method. Make `list*()` return `AsyncIterable` natively and add a `.firstPage()` @@ -817,37 +979,99 @@ Octokit, Azure SDK, AWS SDK v3. every generated package; the fix is one template change, not per-package work. -**Approximate package count where it appeared before pruning:** ~57/98 +**Approximate package count where it appeared before pruning:** ~57/87 packages (every package that has a paginating list endpoint). **Illustrative example:** `listCatalogsIter` in `catalogs/v1/client.ts` -(and parallel methods in `endpoints`, `warehouses`, `jobs`, etc.). +(and parallel methods in `vectorsearch`, `warehouses`, `jobs`, etc.). + +### 8.2 Strip proto-architectural-tier markers from the public TS surface + +**Rule:** When emitting a public TS identifier, strip any mid-position +or suffix token whose only purpose is to disambiguate proto/service +tiers on the server. The closed set is: `Public`, `Internal`, `Proto`, +`Service` (when mid-position and not the domain word), `Backend`, +`Manager`, `Handler`, `Impl`, `Rpc`, `Grpc`, `Wrapper`, +`CustomerFacing`, and mid-position version markers like `V2`/`V3`. +Also strip JSDoc banner comments that exist only for proto file +structure (`"Public RPC requests and responses"`, +`"Wrapper message ..."`, `"Public facing ..."` headers). + +**Why it's generator-only:** The TS SDK exports exactly one tier +(the public one); these qualifiers exist solely to navigate the +proto definition and have no caller-side meaning. The same template +emits them across every account-tier package, so a single template +fix replaces hundreds of per-package findings. + +**Status (2026-05-22):** The `*Public*Request` sub-pattern has shipped +across every account-tier package via the 2026-05-22 generator regen. +~81 findings moved from active to `Fixed` in this pass: +- `metastores`: 20 fixed +- `networking`: 17 fixed +- `workspaces`: 16 fixed +- `credentials`: ~10 fixed +- `storageconfigurations`: ~10 fixed +- `cleanrooms`: 4 fixed +- `keyconfigurations`: 2 fixed +- `jobs`: 2 fixed (`TriggerState` related) + +This is a retroactive validation of the rule. The rule remains open +because: +- `CustomerFacing*` qualifier is **still emitted** in `networking` + (40+ active identifiers in `model.ts`, e.g. + `CustomerFacingIngressNetworkPolicy`, `CustomerFacingVpcEndpointUseCase`). + Not yet flagged in the rescan — should land in a follow-up pass. +- `*Proto` suffix survives on a handful of types: `TriggerStateProto` + (`jobs`), `DatabricksServiceExceptionProto` (`apps`), + `DatabricksServiceExceptionWithDetailsProto` (`apps`). +- `*Service*` mid-position infix in `statementexecution` + (`ServiceErrorCode` / `ServiceError`). +- Mid-position `V` in `jobs` (`RunLifecycleStateV2`) and + `externalmetadata` (`unmarshalListExternalMetadataResponseV2Schema`). +- JSDoc banners ("Public RPC", "Wrapper message", "Public facing RPC + requests and responses *****") still emit verbatim in `forecasting` + and `pipelines`. + +**Approximate package count where it appeared before pruning:** ~25/87 +packages (the account-tier cluster of 11 plus a single-digit tail +across the rest of the SDK). + +**Illustrative example (pre-regen):** +`CreateNetworkConnectivityConfigPublicRequest` → +`CreateNetworkConnectivityConfigRequest`. The 2026-05-22 regen +shipped this rename; the remaining gap is the `CustomerFacing*` +qualifier and the `*Proto`/`*Service*`/`V` tails. --- ## Appendix: Categories (from the per-package audits) -The audits used a shared 20-category rubric. The most-cited categories -across all 98 audits (Category 11 "Empty / trivial wrapper types" has -been retired — see prune note in the header; Category 4 "Underscores -in TS identifiers" has been retired in this prune pass): +The audits used a shared 20-category rubric. Several categories have been +retired as cross-cutting themes via prune passes: Category 2 "Redundant +enum prefix" (prune note 5), Category 11 "Empty / trivial wrapper types" +(prune note 1), and Category 4 "Underscores in TS identifiers" (prune +note 4). A new category was added in the 2026-05-20 proto-architectural-leak +scan (audit-pass note 7): "Proto-architectural leak" — mid-position +proto/service-tier infixes; the 2026-05-22 regen moved most of its +`*Public*Request` cases to `Fixed`. The most-cited remaining categories +across all 87 active audits: | # | Category | Audits citing it | |---|---|---| -| 1 | Vague / generic names | 98 | -| 6 | Misleading names | 98 | -| 3 | Acronym casing inconsistencies | 98 | -| 12 | Duplicate concepts | 95 | -| 15 | Generic field names losing meaning | 94 | -| 20 | Type-suffix tautology | 94 | -| 19 | Underspecified IDs | 93 | -| 17 | Inconsistent action verbs | 93 | -| 7 | Overly verbose names | 90 | -| 14 | Go / Java-style names | 89 | -| 5 | Cryptic abbreviations | 86 | -| 2 | Redundant enum prefix | 84 | -| 8 | Redundant suffix | 79 | -| 9 | Singular/plural mismatches | 78 | -| 16 | Field contradicting type domain | 77 | -| 18 | Long enum values | 73 | -| 13 | Verb-tense inconsistency | 66 | +| 1 | Vague / generic names | 87 | +| 6 | Misleading names | 87 | +| 3 | Acronym casing inconsistencies | 87 | +| 12 | Duplicate concepts | 85 | +| 15 | Generic field names losing meaning | 84 | +| 20 | Type-suffix tautology | 84 | +| 19 | Underspecified IDs | 83 | +| 17 | Inconsistent action verbs | 83 | +| 7 | Overly verbose names | 80 | +| 14 | Go / Java-style names | 79 | +| 5 | Cryptic abbreviations | 77 | +| 8 | Redundant suffix | 70 | +| 9 | Singular/plural mismatches | 70 | +| 16 | Field contradicting type domain | 69 | +| 18 | Long enum values | 66 | +| 13 | Verb-tense inconsistency | 60 | +| Proto | Proto-architectural leak (most `*Public*Request` cases shipped in 2026-05-22 regen) | ~10 | diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index 3bcb8513..1f27c509 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -2,235 +2,192 @@ **Path:** `packages/abacpolicies/src/v1/` **Versions audited:** v1 -**Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter, column-mask, deny, and grant policies. -**Total weird names flagged:** 35 +**Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter and column-mask policies. +**Total weird names flagged:** 26 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 17 | +| High | 5 | +| Medium | 12 | | Low | 5 | | Observation | 4 | ## High severity -### 1. `PolicyType.POLICY_TYPE_UNSPECIFIED` / `POLICY_TYPE_ROW_FILTER` / `POLICY_TYPE_COLUMN_MASK` / `POLICY_TYPE_DENY` / `POLICY_TYPE_GRANT` — `src/v1/model.ts:7-14` -- **Why weird:** Every value redundantly re-states the enum name (`PolicyType.POLICY_TYPE_*`). A `POLICY_TYPE_UNSPECIFIED` sentinel is a proto-buf import; idiomatic TS would use `undefined` for "not set". -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names not idiomatic in TS). -- **Suggested name:** `PolicyType.Unspecified | RowFilter | ColumnMask | Deny | Grant` (or drop `Unspecified` entirely and rely on `policyType?: PolicyType | undefined`). -- **Rationale:** TS enum members are already namespaced by the enum (`PolicyType.RowFilter`). The `POLICY_TYPE_` prefix is pure protobuf noise. - -### 2. `DeletePolicy` — `src/v1/model.ts:72` -- **Why weird:** Type whose name is a verb phrase (`DeletePolicy`) looks like it could be a function or command, not the request body. Other request types in the package follow the same broken pattern (`CreatePolicy`, `GetPolicy`, `ListPolicies`, `UpdatePolicy`). -- **Category:** 6 (misleading: name implies behaviour, actually a request DTO), 14 (Go-style naming). -- **Suggested name:** `DeletePolicyRequest` (and `CreatePolicyRequest`, `GetPolicyRequest`, `ListPoliciesRequest`, `UpdatePolicyRequest`). -- **Rationale:** TypeScript convention names request DTOs with a `Request` suffix; a bare verb-phrase noun reads as an action. Index.ts re-exports these as types, so consumers see `import type {DeletePolicy}` which looks like a function. - -### 3. `PolicyInfo` — `src/v1/model.ts:190` +### 1. `PolicyInfo` — `src/v1/model.ts:137` - **Why weird:** `Info` is a generic suffix that adds nothing — every type is "info about something". This is the central domain entity; it should just be called `Policy`. (See rule 1: `Info` is on the vague-suffix list.) - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix). - **Suggested name:** `Policy`. - **Rationale:** `Policy` is the noun the user actually thinks about. The `Info` suffix is a tic carried over from Go SDK naming conventions that does not apply in TS, where the namespace and import path already disambiguate. -### 4. `onSecurableType: string` on `DeletePolicy` / `GetPolicy` / `ListPolicies` / `UpdatePolicy` — `src/v1/model.ts:74,135,154,335` -- **Why weird:** Typed as `string` everywhere on these request DTOs while the same field on `PolicyInfo` (`model.ts:198`) is typed as `SecurableType` enum. The values are the same domain (`CATALOG`, `SCHEMA`, ...) — the inconsistency is a bug. +### 2. `onSecurableType: string` on `DeletePolicyRequest` / `GetPolicyRequest` / `ListPoliciesRequest` / `UpdatePolicyRequest` — `src/v1/model.ts:64,92,101,232` +- **Why weird:** Typed as `string` everywhere on these request DTOs while the same field on `PolicyInfo` (`model.ts:145`) is typed as `SecurableType` enum. The values are the same domain (`CATALOG`, `SCHEMA`, ...) — the inconsistency is a bug. - **Category:** 6 (misleading — name implies enum, actual type is `string`), 16 (field type contradicts domain). - **Suggested name:** Keep the name but type it `SecurableType`. - **Rationale:** Same field name with two different types across four request DTOs forces callers to remember which one is loose. This is almost certainly a generator bug worth flagging upstream. -### 5. `onSecurableFullname` — `src/v1/model.ts:75,76,136,155,202,336` -- **Why weird:** `fullname` is one un-camelCased word. Should be `fullName` to match field-naming conventions used everywhere else in the same model (`functionName`, `tagKey`, `columnAlias`, `pageToken`, etc.). +### 3. `onSecurableFullname` — `src/v1/model.ts:66,94,103,150,234` +- **Why weird:** `fullname` is one un-camelCased word. Should be `fullName` to match field-naming conventions used everywhere else in the same model (`functionName`, `pageToken`, etc.). - **Category:** 3 (acronym/casing inconsistency — `name` is one word and should follow camelCase, so `Fullname` is wrong). - **Suggested name:** `onSecurableFullName` (wire stays `on_securable_fullname`). - **Rationale:** Internal consistency. JS/TS convention treats `fullName` as two words; the Go SDK collapses `Fullname` but TS shouldn't blindly inherit that. -### 6. `FunctionArgExpression` — `src/v1/model.ts:98` -- **Why weird:** `Arg` is an abbreviation for `Argument` in a type name even though the sibling type `FunctionArgument` (model.ts:108) spells it out. Within five lines the SDK uses both forms. -- **Category:** 5 (cryptic abbreviation when the long form is used right next door), 17 (inconsistency with sibling type). -- **Suggested name:** `FunctionArgumentExpression`. -- **Rationale:** Pick one. Right now `functionArgExpression` (field) shows up as a discriminator value while `functionArgument` is the containing type, which is jarring to read. - -### 7. `useSessionIdentity` field — `src/v1/model.ts:292` -- **Why weird:** Field documented as "Temporary for migrating customers to session identity. After a grace period, this field will be removed and all policies will use session identity." Shipping an explicitly temporary flag in the public SDK surface is risky — once removed, every caller breaks. -- **Category:** 6 (misleading: appears stable but is explicitly a migration toggle). -- **Suggested name:** Either omit from public type or mark `@deprecated` from day one. -- **Rationale:** Public SDK fields should outlive the API; an "everyone will be on this in 6 months" boolean shouldn't live in a stable type. Worth pushing back upstream. - -### 8. `MatchColumn` — `src/v1/model.ts:183` +### 4. `MatchColumn` — `src/v1/model.ts:130` - **Why weird:** Reads as a verb (`MatchColumn`) — could be a method or a type. The field that uses it is plural (`matchColumns: MatchColumn[]`), which then reads as "match columns are an array of `MatchColumn`", and a `MatchColumn` is actually a "column matcher / condition + alias pair". - **Category:** 6 (misleading verb-as-noun), 9 (singular noun whose meaning is unclear). - **Suggested name:** `ColumnMatcher` or `ColumnMatchCondition`. - **Rationale:** Type names should be nouns; the verb form misleads. `ColumnMatcher` makes `matchColumns: ColumnMatcher[]` clearly read as "the matchers". -### 9. `useSessionIdentity` and `forSecurableType` / `onSecurableType` field prefixes — `src/v1/model.ts:198,223,292` -- **Why weird:** Three different prefixes for related concepts on the same struct: `on_securable_type`, `for_securable_type`, `use_session_identity`. The `on`/`for` split (carrier vs. target securable) is subtle and easily confused. Field names alone do not communicate which is which. +### 5. `forSecurableType` / `onSecurableType` field prefixes — `src/v1/model.ts:145,170` +- **Why weird:** Two different prefixes for related concepts on the same struct: `on_securable_type` and `for_securable_type`. The `on`/`for` split (carrier vs. target securable) is subtle and easily confused. Field names alone do not communicate which is which. - **Category:** 1 (vague — the preposition does the disambiguation), 6 (misleading without docs). - **Suggested name:** Rename `forSecurableType` to `appliesToSecurableType` (or similar) and `onSecurableType` to `definedOnSecurableType` to make the distinction explicit. -- **Rationale:** A user reading the type should not have to consult the JSDoc to tell `for` from `on`. These names sit beside each other and look interchangeable. (Upstream concern; the docstring says "Type of securables that the policy should take effect on" while the field is `forSecurableType` — even the documentation gets the prepositions tangled.) +- **Rationale:** A user reading the type should not have to consult the JSDoc to tell `for` from `on`. These names sit beside each other and look interchangeable. ## Medium severity -### 10. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:35` +### 6. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:33` - **Why weird:** Enum value pinned by a comment that says it isn't a real securable yet: "TODO: [UC-2980] Staging tables aren't full-fleged securables yet." Internal TODOs in generated SDK enums leak abstraction. - **Category:** 18 (questionable enum value). - **Suggested name:** Remove until it actually is a securable, or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't contain TODO-tagged speculative values. -### 11. `ColumnMaskOptions.using: FunctionArgument[]` — `src/v1/model.ts:56` +### 7. `ColumnMaskOptions.using: FunctionArgument[]` — `src/v1/model.ts:54` - **Why weird:** Field named `using` — a SQL reserved word and a generic preposition. Doesn't say what is being used. - **Category:** 1 (vague), 10 (reserved-word-adjacent — `using` is a reserved-context keyword in JS dynamic import / TS). - **Suggested name:** `extraArguments` / `additionalArguments` / `argumentList`. -- **Rationale:** `using` on its own carries no semantic load; readers must consult the doc to find out it's "additional positional args". Also appears on `RowFilterOptions` (model.ts:307) with the same problem. +- **Rationale:** `using` on its own carries no semantic load; readers must consult the doc to find out it's "additional positional args". Also appears on `RowFilterOptions` (model.ts:227) with the same problem. -### 12. `ColumnMaskOptions.onColumn` — `src/v1/model.ts:51` +### 8. `ColumnMaskOptions.onColumn` — `src/v1/model.ts:49` - **Why weird:** Preposition-prefixed field name (`onColumn`) that just identifies the masked column. Inconsistent with `functionName` (also on the same type, no preposition). - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `maskedColumnAlias` or `targetColumnAlias`. - **Rationale:** Names should describe what the field *is*, not its prepositional relationship. -### 13. `FunctionArgument.arg` discriminator field — `src/v1/model.ts:110` -- **Why weird:** `FunctionArgument` has a field `arg` (one of three variants). Type name and field name are near-duplicates; the field name is also an abbreviation of the type. +### 9. `FunctionArgument.arg` discriminator field — `src/v1/model.ts:76` +- **Why weird:** `FunctionArgument` has a field `arg` (one of two variants). Type name and field name are near-duplicates; the field name is also an abbreviation of the type. - **Category:** 5 (cryptic abbreviation), 11 (near-duplicate naming). - **Suggested name:** Rename the field to `value` or `kind`. - **Rationale:** `functionArgument.arg.$case === 'alias'` reads weirdly; the field name repeats an abbreviation of the type name. -### 14. `FunctionArgExpression.expr` discriminator field — `src/v1/model.ts:99` -- **Why weird:** Field uses the three-letter abbreviation `expr` rather than spelling out `expression`. -- **Category:** 5 (`expr` is a cryptic abbreviation). -- **Suggested name:** `expression` (spell out). -- **Rationale:** `expr` is the kind of three-letter abbreviation `typescript.mdc` discourages. - -### 15. `TagIntrospectionExpression.expr` discriminator field — `src/v1/model.ts:313` -- **Why weird:** Same `expr` problem as above. A `TagIntrospectionExpression.expr` reads as redundant — the type is already an expression. -- **Category:** 5 (`expr` abbreviation), 17 (`expr` reused with two different meanings within model.ts). -- **Suggested name:** `value` (since the type itself is already "an expression"), or `variant`. -- **Rationale:** Reader hits `expression.expr.$case === 'tagValue'` which is noise on noise. - -### 16. `ColumnTagValueExtraction` / `TagValueExtraction` — `src/v1/model.ts:60,328` -- **Why weird:** Pair of near-identical types, named with a clunky `XExtraction` suffix. The two together describe "get tag value (on securable)" vs "get column tag value", but the names imply more weight than the types carry (each holds 1-2 strings). -- **Category:** 7 (overly verbose), 8 (redundant `Extraction` suffix — these aren't extractions; they're parameters to a `getTagValue` introspection call). -- **Suggested name:** `SecurableTagSelector` and `ColumnTagSelector` (or just `Tag` and `ColumnTag`). -- **Rationale:** The "extraction" framing is a verb forced into a noun. `Selector`/`Tag` is shorter and more accurate. - -### 17. `policyInfo` field on `CreatePolicy` / `UpdatePolicy` — `src/v1/model.ts:69,349` +### 10. `policyInfo` field on `CreatePolicyRequest` / `UpdatePolicyRequest` — `src/v1/model.ts:59,246` - **Why weird:** Field named after the entity's awkward type (`policyInfo: PolicyInfo`). If `PolicyInfo` is renamed to `Policy`, this becomes `policy: Policy` which is much cleaner. - **Category:** 20 (type-suffix tautology), 1 (`Info`). - **Suggested name:** `policy` (paired with type renamed to `Policy`). -- **Rationale:** Tied to the `PolicyInfo` -> `Policy` rename (finding #3). +- **Rationale:** Tied to the `PolicyInfo` -> `Policy` rename (finding #1). -### 18. `policyType: PolicyType` field on `PolicyInfo` — `src/v1/model.ts:227` +### 11. `policyType: PolicyType` field on `PolicyInfo` — `src/v1/model.ts:174` - **Why weird:** Type-suffix tautology (`policyType` field of type `PolicyType`). - **Category:** 20 (type-suffix tautology). - **Suggested name:** `type: PolicyType` if `PolicyInfo` is renamed to `Policy`; otherwise tolerate. - **Rationale:** Rule 20 in spec. The wire field is `policy_type` so the marshalled JSON stays unchanged. -### 19. `onSecurableType` / `forSecurableType` type-suffix tautology — `src/v1/model.ts:198,223` +### 12. `onSecurableType` / `forSecurableType` type-suffix tautology — `src/v1/model.ts:145,170` - **Why weird:** Same as above — fields named `onSecurableType` of type `SecurableType` and `forSecurableType` of type `SecurableType`. - **Category:** 20 (type-suffix tautology). -- **Suggested name:** Drop `Type` from the field once renaming (`onSecurable: SecurableType`, `forSecurable: SecurableType`) — though it conflicts with finding #9. Better to combine the two renames (`definedOnSecurable: SecurableType`, `appliesToSecurable: SecurableType`). +- **Suggested name:** Drop `Type` from the field once renaming (`onSecurable: SecurableType`, `forSecurable: SecurableType`) — though it conflicts with finding #5. Better to combine the two renames (`definedOnSecurable: SecurableType`, `appliesToSecurable: SecurableType`). - **Rationale:** Reduces tautology and clarifies semantics at once. -### 20. Inconsistent rename style for `*Options` types — `src/v1/model.ts:38,84,142,295` -- **Why weird:** `ColumnMaskOptions`, `DenyOptions`, `GrantOptions`, `RowFilterOptions` — four mostly-identical-shaped types describing variants of policy options. Each is a discriminator member; the `Options` suffix is redundant given the discriminator already says "this is the X options". -- **Category:** 8 (redundant suffix), 12 (duplicate concept across four similar types). -- **Suggested name:** Either keep current names but acknowledge as boilerplate, or rename to `RowFilter`, `ColumnMask`, `Deny`, `Grant` (the `$case` discriminator already disambiguates). -- **Rationale:** Generator artefact; flagging because four near-identical types is the moment to ask whether the API surface should collapse. - -### 21. `ListPolicies` request type — `src/v1/model.ts:152` -- **Why weird:** Plural type name for a singular request. Should be `ListPoliciesRequest`. Same issue as #2 but pluralisation collides with `policies: PolicyInfo[]` inside the list response, making it momentarily ambiguous which one is the type and which is the field. -- **Category:** 6 (misleading), 9 (plural request vs singular response). -- **Suggested name:** `ListPoliciesRequest`. -- **Rationale:** Tied to finding #2. +### 13. Inconsistent rename style for `*Options` types — `src/v1/model.ts:36,215` +- **Why weird:** `ColumnMaskOptions` and `RowFilterOptions` — two near-identical types describing variants of policy options. Each is a discriminator member; the `Options` suffix is redundant given the discriminator already says "this is the X options". +- **Category:** 8 (redundant suffix), 12 (duplicate concept across similar types). +- **Suggested name:** Either keep current names but acknowledge as boilerplate, or rename to `RowFilter`, `ColumnMask` (the `$case` discriminator already disambiguates). +- **Rationale:** Generator artefact; flagging because near-identical types is the moment to ask whether the API surface should collapse. -### 22. `whenCondition` field — `src/v1/model.ts:225` +### 14. `whenCondition` field — `src/v1/model.ts:172` - **Why weird:** `when` prefix is a SQL keyword; the field is a free-form condition expression. Just `condition` would suffice given the field already lives on `PolicyInfo`. - **Category:** 1 (vague prefix), 10 (reserved-word-adjacent). - **Suggested name:** `condition` or `conditionExpression`. - **Rationale:** `when_condition` is wire-only; the TS name can drop the redundant `when_`. -### 23. `toPrincipals` / `exceptPrincipals` field names — `src/v1/model.ts:215,217` +### 15. `toPrincipals` / `exceptPrincipals` field names — `src/v1/model.ts:162,164` - **Why weird:** Preposition-prefixed names mirror SQL `TO`/`EXCEPT` syntax (this is an ABAC-on-UC policy, the API mimics SQL `GRANT ... TO ... EXCEPT ...`). For programmatic SDK consumers, `principals` and `excludedPrincipals` would read more naturally. - **Category:** 1 (vague), 14 (Go/SQL-style names not idiomatic for TS). - **Suggested name:** `appliedPrincipals` / `excludedPrincipals` (or `principals` and `excludePrincipals`). - **Rationale:** Consumers who don't know the SQL syntax will misread `to_principals` as "principal list to apply to" and miss that `except_principals` is the complement. -### 24. `MatchColumn.condition: string` — `src/v1/model.ts:185` +### 16. `MatchColumn.condition: string` — `src/v1/model.ts:132` - **Why weird:** A `MatchColumn` has a field called `condition` (matched column condition expression) and an `alias`. The condition could equally well be called `expression`; "condition" implies boolean, but it's actually a column-selector expression evaluated to a column. - **Category:** 6 (misleading). - **Suggested name:** `columnExpression` or `selector`. - **Rationale:** Domain reading: "match columns where condition = X" suggests filtering rows; here it actually selects which columns the policy applies to. Easy to misread. -### 25. `PolicyInfo.id` — `src/v1/model.ts:192` +### 17. `PolicyInfo.id` — `src/v1/model.ts:139` - **Why weird:** Bare `id` field on `PolicyInfo` alongside `name`, `onSecurableFullname`, etc. — multiple identifier-like fields; bare `id` is underspecified. - **Category:** 19 (underspecified id when multiple ids exist). - **Suggested name:** `policyId`. - **Rationale:** Disambiguates from securable identifiers in the same struct. -### 26. `PolicyInfo.comment` — `src/v1/model.ts:210` +## Low severity + +### 18. `PolicyInfo.comment` — `src/v1/model.ts:157` - **Why weird:** Doc says "Optional description of the policy" but the field is named `comment`. SQL stores DDL comments, sure, but a TS-facing field that the JSDoc calls a description should be `description`. - **Category:** 6 (misleading — doc says description, name says comment). - **Suggested name:** `description`. - **Rationale:** Match the doc and avoid the SQL-DDL leak. -## Low severity - -### 27. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; only one place in the file but flagged for consistency review across the SDK. -### 28. `flattenQueryParams` — `src/v1/utils.ts:123` +### 20. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it's an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 29. `readAll` — `src/v1/utils.ts:40` +### 21. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 30. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 22. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). - **Rationale:** Names should differ in more than the `Http` infix. -### 31. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Same word `Options` is reused throughout the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, `RowFilterOptions`, ...). Within this file there's also `Options` imported from `@databricks/sdk-core/api` (line 3). -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of args). -- **Rationale:** Distinguish internal context bags from user-tunable option structs. - ## Observations -### 32. Wire/TS divergence is heavy -The model file is ~796 lines for ~15 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. +### 23. Wire/TS divergence is heavy +The model file is ~497 lines for ~9 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. -### 33. Action-verb conventions in `Client` +### 24. Action-verb conventions in `Client` The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) -### 34. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` +### 25. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` The codebase uses `Http` (`HttpClient`, `HttpRequest`, `executeHttpCall`) and `URLSearchParams` (Web standard) and `url` (lowercase) and `userAgent`. Mixing `Http` (PascalCase capital-then-lower) with the imported `URLSearchParams` (ALLCAPS) is inconsistent — common across JS ecosystem and probably not worth changing, but worth noting. - **Category:** 3 (acronym casing). -### 35. `abac` abbreviation only appears in package name -The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. Comments on `useSessionIdentity` (model.ts:286) mention "ABAC" once. May confuse users searching by acronym. +### 26. `abac` abbreviation only appears in package name +The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. May confuse users searching by acronym. - **Category:** 5 (cryptic abbreviation in package name). ## Domain glossary -- `abac` — Attribute-Based Access Control (package name only; one comment at model.ts:286). -- `uc` — Unity Catalog (referenced in comment at model.ts:34 as "UC-2980", and implicitly across all types since policies live on Unity Catalog securables). +- `abac` — Attribute-Based Access Control (package name only; not referenced in current model code). +- `uc` — Unity Catalog (referenced in comment at model.ts:32 as "UC-2980", and implicitly across all types since policies live on Unity Catalog securables). - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). - `oss` — not encountered in this package. - `m2m`/`u2m`/`pat` — not encountered in this package. - `iam` — not encountered, but conceptually overlaps with `Principal` references. ## File coverage -- `src/v1/model.ts` (796 lines): read fully. -- `src/v1/client.ts` (241 lines): read fully. +- `src/v1/model.ts` (497 lines): read fully. +- `src/v1/client.ts` (250 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (26 lines): read fully. +- `src/v1/index.ts` (20 lines): read fully. + +## Fixed +- #2 `DeletePolicy` (originally cited at `src/v1/model.ts:72`): Fixed in regeneration on 2026-05-20 — renamed to `DeletePolicyRequest`; siblings `CreatePolicyRequest`, `GetPolicyRequest`, `ListPoliciesRequest`, `UpdatePolicyRequest` also gained the `Request` suffix. +- #1 (partial — Deny/Grant values) `PolicyType.POLICY_TYPE_DENY` / `POLICY_TYPE_GRANT` (originally cited at `src/v1/model.ts:7-14`): Fixed in regeneration on 2026-05-20 — Deny and Grant enum values removed. +- #6 `FunctionArgExpression` (originally cited at `src/v1/model.ts:98`): Fixed in regeneration on 2026-05-20 — type removed entirely. +- #7 `useSessionIdentity` field (originally cited at `src/v1/model.ts:292`): Fixed in regeneration on 2026-05-20 — field removed from `PolicyInfo`. +- #14 `FunctionArgExpression.expr` (originally cited at `src/v1/model.ts:99`): Fixed in regeneration on 2026-05-20 — type removed. +- #15 `TagIntrospectionExpression.expr` (originally cited at `src/v1/model.ts:313`): Fixed in regeneration on 2026-05-20 — type removed. +- #16 `ColumnTagValueExtraction` / `TagValueExtraction` (originally cited at `src/v1/model.ts:60,328`): Fixed in regeneration on 2026-05-20 — both types removed. +- #20 (partial) `DenyOptions` / `GrantOptions` (originally cited at `src/v1/model.ts:84,142`): Fixed in regeneration on 2026-05-20 — both types removed; only `ColumnMaskOptions` and `RowFilterOptions` remain, but the `Options`-suffix issue still applies (now finding #14). +- #21 `ListPolicies` request type (originally cited at `src/v1/model.ts:152`): Fixed in regeneration on 2026-05-20 — renamed to `ListPoliciesRequest`. diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md new file mode 100644 index 00000000..8afdd09f --- /dev/null +++ b/.agent/naming-audit/accessmanagement.md @@ -0,0 +1,628 @@ +# Naming Audit: accessmanagement + +**Path:** `packages/accessmanagement/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Consolidated IAM / authorization surface for Databricks. +Combines four formerly-separate packages into one v1: (a) workspace-object +permissions (the `getObjectPermissions` / `setObjectPermissions` / +`updateObjectPermissions` / `getPermissionLevels` cluster — ACLs on clusters, +jobs, notebooks, dashboards, pipelines, registered models, etc.); (b) +account-level rule sets that bind roles to principals on accounts, groups, +service principals, and tag policies (`getRuleSet` / `updateRuleSet` / +`getAssignableRolesForResource`); (c) workspace-permission assignments — +the `USER`/`ADMIN` role a principal holds on a workspace +(`getWorkspacePermissionAssignments` / `updateWorkspacePermissionAssignment` +/ `deleteWorkspacePermissionAssignment` / `listWorkspacePermissions`); and +(d) the `checkPolicy` resource-access policy decision endpoint. Originated +from `permissions`, `workspaceassignment`, `accountaccesscontrol`, and +`accountaccesscontrolproxy` during the 2026-05-22 regeneration. +**Total weird names flagged:** 38 + +## Summary +| Severity | Count | +| --- | --- | +| High | 9 | +| Medium | 16 | +| Low | 9 | +| Observation | 4 | + +The consolidation has eliminated several prior warts (top-level verb-shaped +request types from `permissions` now carry `Request` suffixes; the +`accountaccesscontrolproxy` package surface no longer exists as a separate +package). What persists is the entire load of the prior four audits stacked +together: a 20-member `PermissionLevel` enum with `CAN_*` redundancy and +object-type-specific values leaking into a universal namespace; four +proto-style `*Request_Response` nested message types; three `*Output` +suffix types; `requestObjectType` / `requestObjectId` stringly-typed closed +enum prefixes; a `Proxy`-suffixed duplicate-method cluster around +`getAssignableRolesForResource` / `getRuleSet` / `updateRuleSet`; an +`UNKNOWN` zero-value sentinel that contradicts the `*_UNSPECIFIED` form used +on the same file's `RequestAuthzIdentity` enum; and a half-dozen +duplicate-shape concerns (`PermissionsResponse` vs `WorkspacePermissionAssignmentOutput` +vs the iam `WorkspaceAssignmentDetail`). + +The merger also introduces new collisions: `permissions` now means three +different things in three different response shapes +(`PermissionsResponse.accessControlList` vs +`ListWorkspacePermissionsRequest_Response.permissions` vs +`WorkspacePermissionAssignmentOutput.permissions`), and the `PermissionLevel` +enum (per-object permissions) sits alongside the `WorkspacePermission` enum +(per-workspace USER/ADMIN) with overlapping vocabulary but disjoint scope. + +--- + +## High severity + +### 1. `PermissionLevel` enum values share a redundant `CAN_` action-verb prefix — `src/v1/model.ts:6-27` +- **Why weird:** Of 20 values, 19 begin with `CAN_` (`CAN_MANAGE`, + `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, + `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, + `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, + `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, + `CAN_MANAGE_PRODUCTION_VERSIONS`); the lone exception is `IS_OWNER`, + which uses a copula+predicate form. The `CAN_` modal verb is implied by + membership in `PermissionLevel` — a `PermissionLevel` is, by definition, + what the principal can do — so it is content-free on every value. This is + distinct from the proto-style enum-name prefix; here the redundancy is on + the action verb shared by 19 of 20 members. Mixing `CAN_*` with + `IS_OWNER` also breaks within-enum consistency. +- **Category:** Redundant action-verb prefix on enum members; within-enum + inconsistency. +- **Suggested name:** Drop the `CAN_` action-verb prefix: `MANAGE`, + `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, + `USE`, etc. `IS_OWNER` becomes `OWNER`. +- **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs + `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. + `PermissionLevel.MANAGE` is shorter and just as unambiguous as + `PermissionLevel.CAN_MANAGE`. + +### 2. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` +- **Why weird:** Two distinct values that differ in name only by the + `_ONLY` suffix. There is no JSDoc on either, so a developer cannot tell + from the names alone whether the difference is access-scope, a subset + relationship, or a separate role. +- **Category:** Misleading enum-pair; within-enum inconsistency (`_ONLY` + qualifier appears nowhere else in this enum). +- **Suggested name:** Document inline what the difference is, OR rename to + a pair like `MONITOR_FULL` / `MONITOR_READ_ONLY` where the contrast is on + the predicate, not on a vague `_ONLY` qualifier. +- **Rationale:** Whenever an enum exposes `X` and `X_ONLY` with no JSDoc, + every caller hits a Stack Overflow question. + +### 3. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:17,18,26` +- **Why weird:** Three values are specific to one object type each + (`registered-models` in MLflow Model Registry, and Databricks Apps), but + live in a universal `PermissionLevel` enum applicable to 25+ object + types. Equivalent to having `CAN_MANAGE_DASHBOARD_DRAFTS` or + `CAN_MANAGE_NOTEBOOK_REVISIONS` in the same enum: the values are scoped + to one domain but visible to all. `CAN_CREATE_APP` also breaks the + pattern where other `CAN_CREATE` values are noun-less. +- **Category:** Within-enum inconsistency — most values are + object-type-agnostic, these three leak object-type semantics into the + enum. +- **Suggested name:** Move these into per-object-type sub-enums, or at + minimum add JSDoc declaring their scope ("Applies to + `registered-models` only", "Applies to Databricks Apps only"). +- **Rationale:** Universal enum + object-specific values is a + discoverability hazard; users browsing autocomplete will see these as + valid choices for clusters, jobs, and dashboards. + +### 4. `RequestAuthzIdentity` enum and `REQUEST_AUTHZ_IDENTITY_*` member prefix; `Authz` truncation — `src/v1/model.ts:33-37` +- **Why weird:** The type name starts with `Request` — a wire-format + message prefix (`RequestAuthzIdentity` reads as "the AuthzIdentity field + on a request message"). The mid-name truncation `Authz` (instead of + `Authorization`) is a Go-style abbreviation that does not match the rest + of the package, which spells out `permission` and `permissionLevel` in + full. The members re-state the entire enum name as a SCREAMING_SNAKE + prefix: `REQUEST_AUTHZ_IDENTITY_USER_CONTEXT`, + `REQUEST_AUTHZ_IDENTITY_SERVICE_IDENTITY` — wasted call-site characters. +- **Category:** Proto-architectural leak (`Request` prefix on a domain + enum), cryptic abbreviation (`Authz`). +- **Suggested name:** `AuthorizationIdentity` (or simply + `AuthIdentity`/`CallerIdentity`) with members `USER_CONTEXT`, + `SERVICE_IDENTITY`. +- **Rationale:** The `Request` prefix on a type that names a domain concept + (who the policy check is on behalf of) is wire-shape leakage from the + containing `CheckPolicyRequest`. The `Authz` truncation is fine in code + comments but jars on a public, exported enum. + +### 5. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:156,163,340,348` +- **Why weird:** Every request type carries + `requestObjectType?: string | undefined`. The JSDoc on each occurrence + lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, + clusters, cluster-policies, dashboards, database-projects, + dbsql-dashboards, directories, experiments, files, genie, instance-pools, + jobs, knowledge-assistants, notebooks, pipelines, queries, + registered-models, repos, serving-endpoints, supervisor-agents, + vector-search-endpoints, or warehouses"`. The set is closed, + well-known to the server, and stable — a perfect fit for a string + literal union. The TS SDK ships it as bare `string` with no autocomplete + or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) + silently 4xxs at runtime. +- **Category:** Underspecified ID; cryptic/loose typing; generic field + name (`requestObjectType`). +- **Suggested name:** Define + `type RequestObjectType = 'alerts' | 'alertsv2' | 'authorization' | 'clusters' | 'cluster-policies' | ... | 'warehouses'` + (string literal union, 26 entries). +- **Rationale:** This is the single biggest TS-affordance miss in the + package. The Go SDK uses `string` because Go enums are second-class; TS + has first-class string literal unions that match this exact use case. + +### 6. `requestObjectType` / `requestObjectId` wire-format prefix — `src/v1/model.ts:156,158,163,164,340,342,348,350` +- **Why weird:** All four request types prefix their two path parameters + with `request`: `requestObjectType` and `requestObjectId`. On the TypeScript + surface every field is by definition part of a *request* — the + `request` prefix carries zero information. The prefix is wire-format + leakage from the Databricks REST path placeholders + (`:request_object_type`, `:request_object_id`). +- **Category:** Redundant prefix (the containing type is already + `*Request`); wire-format leak. +- **Suggested name:** `objectType` and `objectId`. The doc comment on + `requestObjectId` already reads "The id of the request object" — drop + the jargon and just say "object id". +- **Rationale:** Compare `GetObjectPermissionsRequest { requestObjectType, + requestObjectId }` to `GetObjectPermissionsRequest { objectType, objectId + }`. The latter reads as plain English. + +### 7. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` +- **Why weird:** Three methods carry the `Proxy` suffix and are + byte-for-byte identical to their non-`Proxy` siblings (lines 218, 292, + 366). They issue the same HTTP request to the same URL with the same + headers. The `Proxy` suffix communicates an architectural concept — + these are the same operation routed through a proxy server in the + Databricks control plane — that has zero meaning for a TypeScript SDK + caller. The same finding triggered the prior + `accountaccesscontrolproxy` package removal; the duplicate-method + echo of it now lives inside this package. +- **Category:** Proto-architectural / backend-routing leak; duplicate + concept exposed twice. +- **Suggested name:** Delete the `*Proxy` variants entirely. If the + proxy-routing distinction matters server-side, the server can route the + same URL internally; the client should not surface it. +- **Rationale:** Method-name suffixes should describe what the operation + does, not how the server routes it. Two identical methods with a + `Proxy` differentiator force every caller to flip a coin. + +### 8. `WorkspacePermission.UNKNOWN` zero-value sentinel — `src/v1/model.ts:40` +- **Why weird:** `WorkspacePermission` uses `UNKNOWN` as its zero-value + sentinel, but the sibling enum `RequestAuthzIdentity` in the same file + uses the `*_UNSPECIFIED` form (`REQUEST_AUTHZ_IDENTITY_UNSPECIFIED`, + line 34), and every other enum across this SDK uses `*_UNSPECIFIED` as + well (e.g., `WORKSPACE_PERMISSION_UNSPECIFIED` in the now-removed iam + mirror). One enum, one file, two sentinel conventions. +- **Category:** Within-package inconsistency (same file, two sentinel + conventions). +- **Suggested name:** `WORKSPACE_PERMISSION_UNSPECIFIED`. +- **Rationale:** Same-file inconsistency is the worst kind. Aligning with + the rest of the file (and the rest of the SDK) costs nothing. + +### 9. `Client` — `src/v1/client.ts:69` +- **Why weird:** Top-level class named `Client`. Generic across every + generated package. The merger makes this worse: this class now exposes + the *combined* surface of four formerly-distinct services + (permissions, workspaceassignment, accountaccesscontrol, + accountaccesscontrolproxy). A consumer importing `Client` from this + package has no surface-level cue what it does. Users importing + `Client` from multiple permission-adjacent packages still have to + alias. +- **Category:** Vague top-level identifier; cross-package collision. +- **Suggested name:** `AccessManagementClient` (matches the package name) + or, given the breadth of the surface, split the class along its four + composed services. +- **Rationale:** SDK convention in AWS, Azure, and GitHub Octokit is + service-prefixed client class names. Project-wide pattern — flag here as + highest-leverage location. + +--- + +## Medium severity + +### 10. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:306,322` +- **Why weird:** `RuleSet` and `RuleSetUpdateRequest` are structurally + identical (`name`, `etag`, `grantRules`). They model the same resource — + one as a response body, one as the update body — but expose it under two + top-level names. `UpdateRuleSetRequest` then wraps `RuleSetUpdateRequest` + under a `ruleSet` field, so the developer sees three overlapping shapes + (`RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest`) for one + concept. The wire payload is keyed `rule_set`, not + `rule_set_update_request`. +- **Category:** Duplicate concepts; redundant wrapper. +- **Suggested name:** Collapse to `RuleSet` only. The update endpoint body + should be `{ name, ruleSet: RuleSet }`. Remove `RuleSetUpdateRequest` + entirely. +- **Rationale:** A single canonical `RuleSet` shape avoids the read/write + divergence. Proto generates separate types because Go does not have + structural typing; in TypeScript the duplication is wasteful. + +### 11. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:354-360` +- **Why weird:** `UpdateRuleSetRequest` has both a top-level `name` and + `ruleSet.name` (because `RuleSetUpdateRequest` also carries `name`). Two + `name` fields on the same request that conceptually identify the same + thing is a footgun — which one wins? Nothing in the TS type encodes + that. +- **Category:** Misleading; field name overlapping itself. +- **Suggested name:** Drop the outer `name` (use it from `ruleSet.name`), + or rename the outer to `pathName`/`resourceName` to make the routing + role explicit. +- **Rationale:** Both fields share an identical doc comment ("Name of the + rule set."). Developers will set one and not the other and silently + 4xx. + +### 12. `GetRuleSetRequest.etag` semantics — `src/v1/model.ts:188-200` +- **Why weird:** A `GET` request type carrying an `etag` is unusual — + `etag` normally rides in headers (`If-Match`/`If-None-Match`) and the + field doc describes optimistic concurrency control on PUT, not GET. The + field is also marshalled into the query string (`params.append('etag', + req.etag)` in `client.ts:301`), which is non-standard HTTP and easy to + misuse. The doc comment is copy-pasted from the PUT-side concurrency + doc on `RuleSet.etag`. +- **Category:** Misleading; doc copy-paste. +- **Suggested name:** `minimumEtag` or `ifNoneMatch` to explain semantics. + At minimum, rewrite the doc to "passed as `?etag=` query parameter; the + server returns a snapshot at least as fresh as this etag". +- **Rationale:** Current name plus copy-pasted comment makes the field + look like an `If-Match` header even though it is a freshness floor on + GET. + +### 13. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:227,302` +- **Why weird:** The package exports a `Role` type and then immediately + ignores it: `GrantRule.role` is `string`. So `Role` is the response + shape from `getAssignableRolesForResource`, but `GrantRule.role` is the + same identifier path serialized inline. Two representations of the + same concept. +- **Category:** Duplicate concept; field type mismatch with sibling type. +- **Suggested name:** Type `GrantRule.role` as `Role['name']` or a + branded `RoleName` string so the two surfaces stay aligned. +- **Rationale:** Developers will write `grantRule.role = role.name` + constantly because the types don't line up. + +### 14. `GetAssignableRolesForResource*` verbosity and verb shape — `src/v1/model.ts:134,150`, `src/v1/client.ts:218` +- **Why weird:** 41-character type names. The "ForResource" suffix is + implied — every assignable-roles query is for a resource. The pair + reads like a Java RPC service name (`GetForRequest`). + The method `getAssignableRolesForResource` returns an array, so it is + semantically a list, not a get. +- **Category:** Overly verbose; verb mismatch (`Get` for a list result). +- **Suggested name:** `ListAssignableRolesRequest` / + `ListAssignableRolesResponse`, method `listAssignableRoles`. Reflects + that the operation returns a list and aligns with REST conventions. +- **Rationale:** Symmetry with `GetRuleSet`/`UpdateRuleSet` might suggest + `Get...`, but the operation returns an array and is closer to a list + semantically. + +### 15. `GrantRule.principals: string[]` is an untyped principal-format list — `src/v1/model.ts:225` +- **Why weird:** Generic `string[]` for principals, where each entry is + one of three formats (`users/`, `groups/`, + `servicePrincipals/`). The shape is + documented in the JSDoc but not in the type. +- **Category:** Generic field losing meaning; underspecified ID. +- **Suggested name:** Type with a template-literal union — e.g. + `principals: PrincipalRef[]` where + `type PrincipalRef = \`users/${string}\` | \`groups/${string}\` | \`servicePrincipals/${string}\``. +- **Rationale:** TypeScript can encode this; the Go SDK cannot. The 1:1 + port leaves type information on the floor. + +### 16. `RuleSet.name` / `GrantRule.role` / `Role.name` are all hierarchical paths — `src/v1/model.ts:303,227,308` +- **Why weird:** "Name" in this API is a hierarchical resource path + (`accounts//ruleSets/default`), not a human-readable label. + Same overload for `role` (`roles/account.admin`). Calling these + `name`/`role` and typing them as `string` hides that they are resource + paths. `Role.name` is even doc-commented as "Role to assign to a + principal..." — the type name `Role` plus field name `name` plus doc + about the *assigned role* is three layers of indirection. +- **Category:** Generic field names; field contradicting domain. +- **Suggested name:** `ruleSet.resourceName`, `grantRule.roleName`, + `Role.id` or `Role.path`. At minimum the JSDoc should explicitly say + "resource path". +- **Rationale:** Half of integration bugs in this API will be + wrong-format names. The type system can help. + +### 17. `principalName` discriminated union — `src/v1/model.ts:47-63,68-84,269-285` +- **Why weird:** The discriminator field is named `principalName` but the + values inside are not all "names" — `servicePrincipalName` is documented + as "application ID of a service principal" (line 60), which is a UUID, + not a name. The carrier field plus the SP variant together imply + "principal name = service principal name = the SP's name", but the SP + variant is the application *ID*. Same shape appears on + `AccessControlRequest`, `AccessControlResponse`, and `PrincipalOutput`. +- **Category:** Misleading; underspecified ID; overloaded "name". +- **Suggested name:** Rename outer field to `principal` and rename the SP + variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or + flatten to `principalType: enum + identifier: string`. +- **Rationale:** Same field name leaks "name" semantics onto a value + that's a UUID. + +### 18. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` +- **Why weird:** Four types use the proto-style nested-message underscore + convention: `DeleteWorkspacePermissionAssignmentRequest_Response`, + `GetPermissionLevelsRequest_Response`, + `GetWorkspacePermissionAssignmentsRequest_Response`, + `ListWorkspacePermissionsRequest_Response`. Each is annotated with + `// eslint-disable-next-line @typescript-eslint/naming-convention -- + Proto-style nested message name.` — the comment explicitly admits the + leak. The corresponding zod schemas + (`unmarshalDeleteWorkspacePermissionAssignmentRequest_ResponseSchema`, + etc.) carry the same wart at `model.ts:441,454,466,488`. Most response + types in this package are top-level `*Response`; only these four use + the nested form. (NOTE: `_Response` underscore suffix is a + generator-only recommendation in `_SUMMARY.md`; here we flag the + within-file inconsistency it creates.) +- **Category:** Within-package inconsistency — some responses top-level + `*Response`, others nested `*Request_Response`. +- **Suggested name:** Generator-side fix. For this package, the + inconsistency would resolve once the underscore-suffix recommendation + applies SDK-wide. +- **Rationale:** TypeScript has no concept of nested message types; the + underscore separator is a proto-specific path encoding. + +### 19. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` +- **Why weird:** Three types ending with `Output`. In proto / gRPC + service definitions, message types are commonly named `FooInput` + (request) and `FooOutput` (response) — the `Output` suffix is the + proto-RPC naming pattern. On the TypeScript surface, `Output` is + meaningless: every value is "output" of something. The package uses + `Request`/`Response` as the standard envelope suffix and only these + three types break the pattern. +- **Category:** Proto-architectural leak (`Output` suffix); within-package + inconsistency. +- **Suggested name:** `WorkspacePermissionDescription` (the enum-name + `WorkspacePermission` is already taken), `Principal`, + `WorkspacePermissionAssignment`. Drop the `Output` suffix. +- **Rationale:** Compare `principal: PrincipalOutput` to + `principal: Principal` — the latter reads as plain English. + +### 20. `permissions` field name overloaded across three types — `src/v1/model.ts:241,376,387` +- **Why weird:** Three different responses carry `permissions` fields + with three different element types and three different meanings: + - `ListWorkspacePermissionsRequest_Response.permissions: PermissionOutput[]` + (line 241) — list of *supported* workspace permission levels. + - `UpdateWorkspacePermissionAssignmentRequest.permissions: + WorkspacePermission[]` (line 376) — the levels to grant a principal. + - `WorkspacePermissionAssignmentOutput.permissions: WorkspacePermission[]` + (line 387) — the levels a principal *currently has*. + Same field name, three concepts (catalog / grant / state). A user + holding a response sees `.permissions` and can't tell which. +- **Category:** Generic field name losing meaning; cross-type + inconsistency. +- **Suggested name:** Distinguish: `supportedPermissions` on the + list-catalog response; `grantedPermissions` or `permissionLevels` on + the assignment output and the update request. +- **Rationale:** Three identical field names, three meanings, in the same + file is a discoverability failure. + +### 21. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:244` +- **Why weird:** Top-level type called `Permission` with three fields: + `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance + is really an "effective permission" — a permission level paired with + inheritance metadata. The name `Permission` alone is the + second-most-overloaded noun in the SDK (after `Client`), and is + cross-cutting with `PermissionLevel`, `PermissionOutput`, + `PermissionsDescription`, `PermissionsResponse`, + `WorkspacePermission`, `permissionAssignments`, and `permissions` + — all in the same package. +- **Category:** Vague top-level identifier; cross-package collision. +- **Suggested name:** `EffectivePermission` (matches the doc semantics) + or `PermissionGrant`. +- **Rationale:** `Permission` as a standalone PascalCase noun is so + common across IAM systems that it's nearly content-free without + qualification. + +### 22. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:256` +- **Why weird:** Type carries `permissionLevel?: PermissionLevel` + (singular) and `description?: string`. The plural `Permissions` in the + type name is wrong: each instance describes ONE level. +- **Category:** Singular/plural mismatch; generic `Description` suffix. +- **Suggested name:** `PermissionLevelDescription` or + `PermissionLevelInfo`. +- **Rationale:** One descriptor = one level; the type name should match. + +### 23. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:261` +- **Why weird:** Returned from three different operations + (`getObjectPermissions`, `setObjectPermissions`, + `updateObjectPermissions`). The type carries `objectId`, `objectType`, + `accessControlList` — i.e. it's "an ACL with metadata", not "a + Permissions response". Name is generic; the content is the more + meaningful concept. +- **Category:** Vague; `Response` suffix tautology. +- **Suggested name:** `ObjectAcl`, `ObjectPermissions`, or + `AccessControlList`. +- **Rationale:** The type's payload (`objectId`, `objectType`, + `accessControlList`) is the concept; `Response` is incidental. + +### 24. `accessControlList` field uses asymmetric element types — `src/v1/model.ts:264,343,351` +- **Why weird:** Appears in three types (`PermissionsResponse`, + `SetObjectPermissionsRequest`, `UpdateObjectPermissionsRequest`). The + field is typed `AccessControlRequest[]` in the two request types and + `AccessControlResponse[]` in the response — asymmetric typing under one + field name. The conventional shorthand is "ACL". +- **Category:** Overly verbose; asymmetric typing under one field name. +- **Suggested name:** `acl: AccessControlEntry[]` or + `entries: AccessControlEntry[]`, with one unified element type. +- **Rationale:** "Access control list" is verbose; asymmetric typing for + same field name is a footgun. + +### 25. `Actor.kind` discriminated-union with a single variant — `src/v1/model.ts:95-97` +- **Why weird:** `Actor.kind?: { $case: 'actorId'; actorId: number } | + undefined` — the `kind` field name is a direct port of the proto + `oneof kind { ... }` block convention. With a single-variant union + (only `actorId`), the entire discriminator is dead weight — there's + nothing else it could be. +- **Category:** Proto-architectural leak (`oneof` block name `kind` + carried verbatim); single-variant union is unnecessary structure. +- **Suggested name:** Flatten to `actorId?: number | undefined` directly + on `Actor`. If a future variant is added, introduce the discriminated + union then with a meaningful discriminator name. +- **Rationale:** A single-variant discriminated union is a proto + modeling artifact, not a domain concept. + +--- + +## Low severity + +### 26. `etag` casing — `src/v1/model.ts:199,318,334` +- **Why weird:** Lowercase `etag` (rather than `eTag`/`ETag`). HTTP spec + uses `ETag`. Per the project-wide acronym policy (Google TS + `Pascal-then-lower`), the form would be `etag`/`Etag` depending on + position. Mixed-case `eTag` would be wrong. Flag for cross-package + consistency review only. +- **Category:** Acronym casing. +- **Suggested name:** Confirm against project-wide policy. Current form is + most likely correct per Google TS rules. +- **Rationale:** Defer to global policy. + +### 27. `flattenQueryParams` exported but rarely consumed — `src/v1/utils.ts:123` +- **Why weird:** Used only by `checkPolicy` (`client.ts:536,545,555`). + The helper is identical across packages and should live in a shared + `@databricks/sdk-core` module rather than be re-emitted per package. + Generator-wide concern. +- **Category:** Effectively internal/redundant export. +- **Suggested name:** Move to shared core utility module; keep current + name. +- **Rationale:** Generator emits the same helper into every package; + consolidation reduces surface. + +### 28. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` +- **Why weird:** The package imports `CallOptions` from + `@databricks/sdk-options/call` (line 12) and defines its own + `HttpCallOptions` here. The names suggest the latter is a + subtype/extension of the former, but they describe different concerns + — `CallOptions` is retry/signal/timeout policy; `HttpCallOptions` is + request + client + logger bundle. +- **Category:** Vague suffix; naming-overlap with the public type. +- **Suggested name:** `HttpCallContext` (it's a context bag, not + user-tunable options). +- **Rationale:** Distinguish internal context bags from user-facing + option structs. + +### 29. `readAll` is a Go-port utility name — `src/v1/utils.ts:40` +- **Why weird:** Direct Go-port of `io.ReadAll`; clashes cognitively + with `Array.prototype` methods and Web Streams APIs. Generator-wide. +- **Category:** Vague; Go-port style. +- **Suggested name:** `readStreamToEnd`, `drainStream`, or + `bufferStream`. +- **Rationale:** Cross-package consistency. + +### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` +- **Why weird:** `Segment` is a generic word; the constant carries + User-Agent identity but the name communicates nothing. Same wart + appears in every generated package. +- **Category:** Vague; generic name. +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +- **Rationale:** Cross-package consistency. + +### 31. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` +- **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` + (line 513). The request type `UpdateObjectPermissionsRequest` is + symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the + semantics differ: PUT replaces, PATCH merges. The naming gives no + hint of this. +- **Category:** Verb consistency; semantics buried. +- **Suggested name:** `patchObjectPermissions` for the PATCH method, OR + explicit JSDoc on `update*` clarifying merge semantics. +- **Rationale:** Method verbs should hint at HTTP semantics; `set` vs + `update` is ambiguous when both exist on the same resource. + +### 32. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` +- **Why weird:** REST path uses `/permissionassignments/` (no + separator), while every other Databricks REST resource in this SDK + uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). + Wire-format problem, not TS naming, but spills into the visual feel + of the client URLs. +- **Category:** Casing/separator inconsistency (wire side). +- **Suggested name:** Upstream: `permission-assignments`. Not actionable + in this package. +- **Rationale:** Cross-API consistency. + +### 33. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` +- **Why weird:** Method is named with `get*` but returns + `permissionAssignments` array (model.ts:213). REST convention is + `list*` for array-returning operations; `get*` for singular. +- **Category:** Verb-tense inconsistency. +- **Suggested name:** `listWorkspacePermissionAssignments` and + `ListWorkspacePermissionAssignmentsRequest` / + `…Response`. +- **Rationale:** Aligns naming with REST list semantics used elsewhere + in the SDK. + +### 34. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` +- **Why weird:** Method `listWorkspacePermissions` returns the + catalog of `PermissionOutput` values supported (USER/ADMIN), not + user data. Sits side-by-side with `getWorkspacePermissionAssignments` + (which actually lists data). The two are visually similar and easy + to mix up. +- **Category:** Misleading verb (catalog vs data). +- **Suggested name:** `getSupportedWorkspacePermissions` or + `listAssignablePermissions`. +- **Rationale:** Disambiguates from the assignment-list operation. + +--- + +## Observations + +### O1. URL path interpolation is unencoded — `src/v1/client.ts:103,131,159,187,222,259,296,333,370,399,425,450,478,504` +- All URL path placeholders interpolate `${req.accountId ?? ''}`, + `${String(req.workspaceId ?? '')}`, etc. directly into URLs without + `encodeURIComponent`. A malicious or weird `accountId` allows path + injection. Sibling packages use the same pattern, so it's + project-wide. Not a naming finding strictly, caught in passing. + +### O2. `workspaceId` and `principalId` typed as `number` — `src/v1/model.ts:126,128,207,235,287,366,368` +- Workspace IDs and principal IDs are 64-bit integers in + Databricks; JS `number` loses precision above 2^53. The client also + unconditionally `String()`s these into URL paths, so string semantics + are sufficient throughout. Worth flagging cross-package: bigint or + string would be safer. + +### O3. `error?: string` on `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:389` +- Embedding an opaque error string inside the success response body is + unusual; typical SDK design surfaces errors as exceptions or as a + typed error union. The field is named `error` (clashing with the + global `Error` class and the `catch(error)` parameter name). + `errorMessage` or `partialFailureReason` would be clearer. + +### O4. Single class composes four formerly-distinct services — `src/v1/client.ts:69` +- The `Client` class composes 12 methods that previously lived across + four packages. Three operational clusters + (workspace-object-permissions, account-level rule sets, + workspace-permission-assignments) plus one orphan (`checkPolicy`) + share a class with no internal structure or grouping. Naming-adjacent: + a single flat `Client` interface flattens the conceptual boundaries + that gave the four original packages their identity. Consider + exposing sub-namespaces (`client.objectPermissions.get(...)`, + `client.ruleSets.update(...)`, etc.) to reflect the cluster + boundaries, even though the merger argues against re-split. + +--- + +## Domain glossary +- `accountId` — Databricks account UUID (top-level tenant container, + distinct from a workspace). +- `etag` — HTTP entity tag, used here as a freshness floor on GET and as + an optimistic concurrency token on PUT. +- `principal` — User, service principal, or group; the subject of an + access rule or a permission assignment. +- `Role` — Reference to a grantable account-level role (e.g. + `roles/account.admin`). +- `RuleSet` — A versioned collection of `GrantRule`s attached to a + resource. +- `GrantRule` — A binding of N principals to 1 role within a `RuleSet`. +- `PermissionLevel` — A per-object-type access-grant level (`CAN_MANAGE`, + `CAN_VIEW`, `IS_OWNER`, etc.). Distinct from `WorkspacePermission`. +- `WorkspacePermission` — A workspace-membership role for a principal + (`USER`, `ADMIN`). Distinct from `PermissionLevel`. +- `PermissionAssignment` — A binding of a principal to one or more + `WorkspacePermission` values on a single workspace. +- `requestObjectType` / `requestObjectId` — Wire-name pair identifying + the object on which a permissions ACL is read or written. +- `resource` — Hierarchical name identifying what the rule set or roles + list applies to (account, group, service principal, or tag policy). +- `policy` (in `CheckPolicyRequest`) — A server-side authorization + rule; `checkPolicy` asks the server whether a given actor may perform + a given permission on a given resource. + +## File coverage +- `src/v1/model.ts` (738 lines): read fully. +- `src/v1/client.ts` (581 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (45 lines): read fully. +- `src/v1/transport.ts` (75 lines): read for context. diff --git a/.agent/naming-audit/accountaccesscontrol.md b/.agent/naming-audit/accountaccesscontrol.md index 06c7275e..753248b8 100644 --- a/.agent/naming-audit/accountaccesscontrol.md +++ b/.agent/naming-audit/accountaccesscontrol.md @@ -1,5 +1,9 @@ # Naming Audit: accountaccesscontrol +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `packages/accountaccesscontrol/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Databricks IAM rule sets — list assignable roles for a resource and read/replace the grant rules attached to that resource. @@ -128,3 +132,9 @@ - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (17 lines): read fully. - `package.json` (41 lines): read for context. + +## Fixed + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/accountaccesscontrolproxy.md b/.agent/naming-audit/accountaccesscontrolproxy.md index 1a287aa1..e333e47f 100644 --- a/.agent/naming-audit/accountaccesscontrolproxy.md +++ b/.agent/naming-audit/accountaccesscontrolproxy.md @@ -1,245 +1,80 @@ # Naming Audit: accountaccesscontrolproxy +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `packages/accountaccesscontrolproxy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level access control via rule sets that bind roles to principals (users, groups, service principals, tag policies), exposed as a "proxy" variant whose surface area is indistinguishable from the sibling `accountaccesscontrol` package. -**Total weird names flagged:** 25 +**Total weird names flagged:** 0 --- ## Summary table -| # | Name | File | Kind | Severity | Category | Issue (one-liner) | -|---|------|------|------|----------|----------|-------------------| -| 1 | package `accountaccesscontrolproxy` | (package) | package | High | 12 Duplicate concepts | 1:1 surface duplicate of sibling `accountaccesscontrol` — same types, same methods, same URL paths; "proxy" is not encoded anywhere in the API. | -| 2 | package `accountaccesscontrolproxy` | (package) | package | High | 14 Go/Java-style names not idiomatic TS | Long, undelimited compound name (`accountaccesscontrolproxy`) is hard to parse; should be `account-access-control-proxy` or split into a `proxy` subpath. | -| 3 | `GetAssignableRolesForResourceRequest` | model.ts:5 | interface | Medium | 7 Overly verbose | 36-char identifier; "ForResource" is implicit since the only field is `resource`. Drop to `GetAssignableRolesRequest`. | -| 4 | `GetAssignableRolesForResourceResponse` | model.ts:21 | interface | Medium | 7 Overly verbose | 37-char identifier; same issue as #3. Drop to `GetAssignableRolesResponse`. | -| 5 | `Role.name` | model.ts:70 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `Role.name` carries the whole semantic — the value is the role identifier itself. `roleName` or `id` would communicate the meaning. | -| 6 | `GetRuleSetRequest.name` | model.ts:38 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning | `name` here is actually a fully-qualified resource path (`accounts//ruleSets/default`). Should be `ruleSetName` or `resourceName`. | -| 7 | `GetRuleSetRequest.etag` | model.ts:51 | field | Low | 3 Acronym casing inconsistencies | Field is `etag` (all lowercase) but JSDoc uses `eTag`/`Etag`/`ETag` inconsistently within the same comment. `ETag` is the HTTP-standard casing (RFC 7232 §2.3). | -| 8 | `GetRuleSetRequest` shape | model.ts:25 | interface | Medium | 1 Vague/generic without domain context | "RuleSet" tells the reader nothing about the access-control domain; in isolation it could be a firewall rule, a SQL rule, etc. `AccessControlRuleSet` would carry domain. | -| 9 | `GrantRule` | model.ts:54 | interface | Low | 1 Vague/generic without domain context | Same domain ambiguity as `RuleSet`; would be clearer as `AccessControlGrantRule` or `RoleGrantRule`. | -| 10 | `GrantRule.principals` | model.ts:63 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | Field is a `string[]`, but each value is a path like `users/` / `groups/` / `servicePrincipals/`. The string-array typing erases the discriminated structure; `principalNames` or `principalRefs` would at least flag that these are references, not free-form strings. | -| 11 | `GrantRule.role` | model.ts:65 | field | Medium | 17 Inconsistent action verbs, 15 Generic field names losing meaning | Singular `role: string` here, but the `Role` interface (model.ts:68) uses `name`. A `GrantRule.role` should be either a `Role` or a clearly-typed `roleName`. | -| 12 | `RuleSet` | model.ts:73 | interface | High | 12 Duplicate concepts | Has identical shape to `RuleSetUpdateRequest` (model.ts:89): `name`, `etag`, `grantRules`. One of them is redundant. | -| 13 | `RuleSet.name` | model.ts:75 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning | Same problem as #6 — this is a fully-qualified path, not a human-readable name. Rename to `ruleSetName` or `resourceName`. | -| 14 | `RuleSet.etag` | model.ts:85 | field | Low | 3 Acronym casing inconsistencies | Same `etag` vs `ETag` (RFC 7232) issue as #7. | -| 15 | `RuleSet.grantRules` | model.ts:86 | field | Low | 9 Singular/plural mismatches | Plural is correct, but the wire form is `grant_rules` (model.ts:144) — underscore vs camelCase split is a real coupling point worth verifying is centralized. | -| 16 | `RuleSetUpdateRequest` | model.ts:89 | interface | High | 12 Duplicate concepts, 13 Verb-tense inconsistency | Same fields as `RuleSet`. The "UpdateRequest" suffix collides naming with the outer `UpdateRuleSetRequest` (model.ts:105), giving two overlapping `*UpdateRequest`/`Update*Request` shapes for the same operation. | -| 17 | `RuleSetUpdateRequest` vs `UpdateRuleSetRequest` | model.ts:89, 105 | interface pair | High | 13 Verb-tense inconsistency, 12 Duplicate concepts | Two side-by-side request types whose names invert noun/verb order (`RuleSetUpdateRequest` vs `UpdateRuleSetRequest`). Inevitable confusion; one is the outer envelope (`{accountId, name, ruleSet}`), the other is the inner payload. Inner should be named `RuleSetPayload`, `RuleSetSpec`, or merged with `RuleSet`. | -| 18 | `UpdateRuleSetRequest.name` | model.ts:109 | field | High | 12 Duplicate concepts | `name` appears at the outer level AND inside `ruleSet.name`. Which one wins? The Go-style nesting is preserved verbatim, but a TS consumer has to guess. | -| 19 | `UpdateRuleSetRequest.ruleSet` | model.ts:110 | field | Low | 7 Overly verbose | Outer envelope wraps a `ruleSet: RuleSetUpdateRequest`. Could be flattened. | -| 20 | `Client` | client.ts:39 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier; once imported into a consumer that uses multiple Databricks clients, every one is just `Client`. Should be `AccessControlProxyClient` or aliased on export. | -| 21 | `Client.getAssignableRolesForResource` | client.ts:72 | method | Medium | 7 Overly verbose | "ForResource" is implicit (only one parameter is the resource); `getAssignableRoles(req)` reads cleanly. | -| 22 | `HttpCallOptions` | utils.ts:15 | interface | Low | 1 Vague/generic without domain context | Bundle of `{request, httpClient, logger}` named generically. Inside a single file this is fine; if it ever leaks out, `ExecuteHttpCallParams` would self-document. | -| 23 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions in the same file with overlapping vocabulary. `executeCall` (orchestrates retries/timeouts) and `executeHttpCall` (does one HTTP roundtrip) are two different concepts — name them so. e.g. `runWithOptions` / `sendRequest`. | -| 24 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 21 Dead code | Exported from `utils.ts` but never imported in `client.ts`. Either dead code or for future generated calls. | -| 25 | `PACKAGE_SEGMENT` | client.ts:34 | const | Low | 1 Vague/generic without domain context | Could be `USER_AGENT_PACKAGE_SEGMENT` to clarify what "segment" means at the call site. | +_None._ --- ## High severity (must fix) -### H1. Whole-package duplication: `accountaccesscontrolproxy` vs `accountaccesscontrol` - -The two packages have: -- The **same** seven exported types: `GetAssignableRolesForResourceRequest`, - `GetAssignableRolesForResourceResponse`, `GetRuleSetRequest`, `GrantRule`, - `Role`, `RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest`. -- The **same** three client methods: `getAssignableRolesForResource`, - `getRuleSet`, `updateRuleSet`. -- The **same** API path: `/api/2.0/preview/accounts//access-control/...`. - -The user instruction calls out: *"Pay extra attention: the word 'proxy' in the -package name suggests this is a proxy variant. Flag if 'Proxy' appears in every -type name redundantly."* - -The opposite is true — `Proxy` appears **nowhere** in the model, client, or -URL. The only differentiation is the package name. This is a category 12 -(duplicate concepts) failure at the package level. Either: -- Merge the two packages, -- Or surface the proxy semantics in the types (`ProxyClient`, different URL, - different fields). - -Until that is done, every consumer has to guess which package to import; once -imported, the symbols collide on re-export. - -### H2. Stuttering update-request pair (`RuleSetUpdateRequest` vs `UpdateRuleSetRequest`) - -```ts -export interface RuleSetUpdateRequest { name?, etag?, grantRules? } -export interface UpdateRuleSetRequest { accountId?, name?, ruleSet?: RuleSetUpdateRequest } -``` - -Two types whose names differ only in word order (one is a NounVerb suffix, the -other is a VerbNoun prefix) and which both carry a `name` field. Reviewers and -consumers will mis-pick them. Rename the inner type to `RuleSetSpec`, -`RuleSetPayload`, or eliminate it by reusing `RuleSet`. - -### H3. `name` overload at multiple levels of `UpdateRuleSetRequest` - -`UpdateRuleSetRequest.name` and `UpdateRuleSetRequest.ruleSet.name` both exist -and both are strings. No JSDoc clarifies which one is canonical. The Go SDK -likely tolerates this because callers fill the entire envelope. In TS, the -guidance should be explicit: one field, or both fields with clear precedence. - -### H4. `name` is an opaque resource path, not a human-readable name - -Both `GetRuleSetRequest.name` and `RuleSet.name` carry strings like -`accounts//ruleSets/default`. Calling that a "name" is misleading -— it is a fully-qualified resource path. Rename to `ruleSetName`, -`resourceName`, or `resourcePath`, or introduce a branded `RuleSetName` type. +_None._ --- ## Medium severity (worth pushing back on) -### M1. Verbose request/response names - -`GetAssignableRolesForResourceRequest`/`Response` are 36/37 characters. Because -the request only has the `resource` field, `ForResource` is implicit. Suggest -`GetAssignableRolesRequest`/`Response`. - -### M2. `Role.name` is a vague field name - -```ts -export interface Role { name?: string | undefined; } -``` - -`name` is a vague field name. In context the value is the role's identifier -itself; `roleName` or `id` would be clearer. - -### M3. `GrantRule.role: string` vs `Role.name: string` - -`GrantRule.role` is a string that semantically references a `Role`. Either -type it as `Role` (or `Role['name']`), rename to `roleName` to match the -referent, or unify on one shape. - -### M4. Generic-domain types: `RuleSet`, `GrantRule` - -In isolation these names give no hint they belong to access control. A -`RuleSet` could be a firewall, a SQL rewrite, a tag-policy rule set, etc. The -SDK has only the package boundary to disambiguate. Consider prefixing types in -the same file (`AccessControlRuleSet`, `AccessControlGrantRule`) when the -package itself is also generic. - -### M5. `executeCall` vs `executeHttpCall` - -Both live in `utils.ts`. They do different things: -- `executeCall` translates `CallOptions` to `Options` and dispatches retries. -- `executeHttpCall` does a single HTTP roundtrip and converts errors. - -Two near-identical names within one file is a navigation hazard. Suggested: -`runWithOptions` / `sendRequest`. - -### M6. `Client` is unqualified - -```ts -export class Client { ... } -``` - -A consumer that imports `{Client}` from multiple Databricks packages has to -alias every import. Either: -- Export as `AccessControlProxyClient`, or -- Rely on namespace imports - (`import * as accountAccessControlProxy from ...`). +_None._ --- ## Low severity (nits) -### L1. Acronym casing for `etag` - -The wire and field name is `etag` (lowercase). The JSDoc in the same comment -block uses `eTag`, `Etag`, and `ETag` interchangeably. RFC 7232 §2.3 defines -the header as `ETag`. Pick one. - -### L2. `flattenQueryParams` is exported but never imported - -`utils.ts:123` exports `flattenQueryParams`. `client.ts` never imports it (it -builds query strings inline via `URLSearchParams`). Either: -- Remove it (dead code), or -- Use it (current inline code reproduces a subset of its logic). - -### L3. `PACKAGE_SEGMENT` - -Used only for the User-Agent header. Renaming to -`USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory: -`createDefault().with(USER_AGENT_PACKAGE_SEGMENT)`. - -### L4. `HttpCallOptions` - -Internal `interface` with `{request, httpClient, logger}`. Could be inlined -into `executeHttpCall` as positional parameters, or renamed -`ExecuteHttpCallParams` to disambiguate from `CallOptions` (which is a public -type). - -### L5. `req` parameter naming in client methods - -```ts -async getAssignableRolesForResource(req: GetAssignableRolesForResourceRequest, ...) -``` - -`req` is fine, but it leans Go-idiomatic. TS/JS code more commonly uses -`request` or `params`. Minor stylistic point. +_None._ --- ## Observations (not flags) -- **Generator marker:** Every file is prefixed with `// Code generated from - API definition by Databricks SDK Generator. DO NOT EDIT.` so all naming - issues here must be fixed upstream in the generator/spec. -- **No enums.** The package has zero enum types, so categories 2 (redundant - enum prefixes) and 18 (long enum values) do not apply. -- **No underscores in identifiers.** TS-facing identifiers are camelCase; wire - identifiers use `snake_case` and are translated in the zod `transform` - callbacks (model.ts:144-149, 168-172, 180-184). Clean here. -- **No `Url`/`URL`, `Id`/`ID`, `Sql`, `Json`, `Oauth` casing collisions.** The - only acronym in the public surface is `accountId` (camelCase) and `etag` - (all-lower) — flagged separately under L1. -- **No reserved-word collisions** (no `delete`, `class`, `new`, etc. as field - names). -- **Optionality model:** every field is `T | undefined`. This matches the - rest of the SDK and the `exactOptionalPropertyTypes` TS setting. No issue. -- **Versioning:** only `v1` exists; nothing to compare across versions. -- **Tests:** there is no `tests/` directory for this package. -- **`index.ts` re-export style:** All seven types are re-exported as - `export type {...}`, which is correct for `verbatimModuleSyntax`. No - issue. -- **`Client` constructor throws plain `Error`** for missing `host` (client.ts:53). - Consistent with sibling packages, but not a naming concern. - ---- - -## Domain glossary (as inferred from this code) - -| Term | Meaning in this package | -|------|-------------------------| -| **Account ID** | The numeric Databricks account identifier (path parameter ``). | -| **Resource** | A fully-qualified identifier for the thing being secured: account, group, service principal, or tag policy. Encoded as a slash-delimited path (e.g. `accounts//groups/`). | -| **Rule set** | A collection of grant rules attached to a resource. Currently a single `default` rule set per resource. | -| **Grant rule** | A `(role, principals[])` pair: which role is granted to which principals on the rule set's resource. | -| **Role** | An identifier (string-shaped) for a permission bundle; `Role.name` carries the identifier itself. | -| **Principal** | A user (`users/`), group (`groups/`), or service principal (`servicePrincipals/`). | -| **Etag** | Opaque versioning token for optimistic concurrency on rule set updates. | -| **Assignable role** | A role that can appear in a grant rule for a given resource. | -| **Proxy** | Not visible anywhere in the API surface — the package name is the only signal. See H1. | +- **Package source removed.** As of 2026-05-20, `packages/accountaccesscontrolproxy/src/` + no longer exists in the tree (only `.turbo/` log artifacts remain under the + package directory). All findings in this audit refer to symbols that are no + longer present; they have been moved to the `## Fixed` section below. --- -## File coverage - -| File | Lines | Exports counted | Audited | -|------|-------|-----------------|---------| -| `src/v1/model.ts` | 185 | 7 interfaces, 7 zod consts | yes | -| `src/v1/client.ts` | 170 | 1 class, 3 public methods | yes | -| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | -| `src/v1/index.ts` | 16 | 1 class re-export, 7 type re-exports | yes | - -Every type, field, enum value (none), and method enumerated above is -accounted for. +## Fixed + +- #1 package `accountaccesscontrolproxy` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — Package source removed; surface duplicate no longer exists. +- #2 package `accountaccesscontrolproxy` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — Package source removed; long compound name no longer exposed. +- #3 `GetAssignableRolesForResourceRequest` (originally cited at model.ts:5): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #4 `GetAssignableRolesForResourceResponse` (originally cited at model.ts:21): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #5 `Role.name` (originally cited at model.ts:70): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #6 `GetRuleSetRequest.name` (originally cited at model.ts:38): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #7 `GetRuleSetRequest.etag` (originally cited at model.ts:51): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #8 `GetRuleSetRequest` shape (originally cited at model.ts:25): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #9 `GrantRule` (originally cited at model.ts:54): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #10 `GrantRule.principals` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #11 `GrantRule.role` (originally cited at model.ts:65): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #12 `RuleSet` (originally cited at model.ts:73): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #13 `RuleSet.name` (originally cited at model.ts:75): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #14 `RuleSet.etag` (originally cited at model.ts:85): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #15 `RuleSet.grantRules` (originally cited at model.ts:86): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #16 `RuleSetUpdateRequest` (originally cited at model.ts:89): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #17 `RuleSetUpdateRequest` vs `UpdateRuleSetRequest` (originally cited at model.ts:89, 105): Fixed in regeneration on 2026-05-20 — Both symbols removed with package source. +- #18 `UpdateRuleSetRequest.name` (originally cited at model.ts:109): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #19 `UpdateRuleSetRequest.ruleSet` (originally cited at model.ts:110): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #20 `Client` (originally cited at client.ts:39): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #21 `Client.getAssignableRolesForResource` (originally cited at client.ts:72): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #22 `HttpCallOptions` (originally cited at utils.ts:15): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #23 `executeCall` vs `executeHttpCall` (originally cited at utils.ts:26, 65): Fixed in regeneration on 2026-05-20 — Both symbols removed with package source. +- #24 `flattenQueryParams` (originally cited at utils.ts:123): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. +- #25 `PACKAGE_SEGMENT` (originally cited at client.ts:34): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/accountsettings.md b/.agent/naming-audit/accountsettings.md index 0bf633a7..fcf1d079 100644 --- a/.agent/naming-audit/accountsettings.md +++ b/.agent/naming-audit/accountsettings.md @@ -1,116 +1,115 @@ # Naming Audit: accountsettings +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `/home/parth.bansal/sdk-js/packages/accountsettings/` **Versions audited:** v1 **Inferred domain:** Account-level Databricks settings governing compliance profiles, IP access toggles, legacy-feature flags, ESM/CSP enablement, LLM-proxy partner-powered AI, and the Personal Compute default policy. -**Total weird names flagged:** 42 +**Total weird names flagged:** 43 ## Summary table | # | Severity | Category | Identifier | File:line | |---|----------|----------|------------|-----------| -| 1 | High | Redundant enum prefix | `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10` | -| 2 | High | Acronym casing / cryptic abbreviation | `DcpAccountEnableMessage` (DCP) | `model.ts:61,126` | -| 3 | High | Cryptic abbreviation | `Csp*` (CSP) family | `model.ts:92-124,286-300,454-463` | -| 4 | High | Cryptic abbreviation | `Esm*` (ESM) family | `model.ts:242-268,318-332,478-487` | -| 5 | High | Cryptic abbreviation | `Llm*` (LLM) family | `model.ts:334-364,382-418,490-511` | -| 6 | High | Generic field name | `value` (everywhere on `*Setting` types) | `model.ts:82-85, 118-124, 127, 236-239, 262-268, 398, 417, 436-439` | -| 7 | High | Generic + cryptic field | `acctIpAclEnable` | `model.ts:83-84` | -| 8 | High | Generic field name | `booleanVal` discriminator | `model.ts:398, 417` | -| 9 | High | Underspecified ID | `accountId` (no type/format hint) | `model.ts:131,161,191,271,...` | -| 10 | High | Domain-redundant suffix | `*Setting` suffix duplicating `Settings` package | `model.ts:102,246,420` and elsewhere | -| 11 | Medium | Type-suffix tautology | `CspEnablementAccountSetting` | `model.ts:102` | -| 12 | Medium | Type-suffix tautology | `EsmEnablementAccountSetting` | `model.ts:246` | -| 13 | Medium | Type-suffix tautology | `PersonalComputeSetting` | `model.ts:420` | -| 14 | Medium | Duplicate concept | `*Account` vs `*AccountSetting` parallel naming | `model.ts:92 vs 102; 242 vs 246` | -| 15 | Medium | Misleading | `LlmProxyPartnerPoweredEnforce` | `model.ts:401` | -| 16 | Medium | Misleading | `LlmProxyPartnerPoweredAccount` | `model.ts:382` | -| 17 | Medium | Verb-tense / action verb | `AccountIpAccessEnable` (verb as noun) | `model.ts:66` | -| 18 | Medium | Verb-tense / action verb | `DisableLegacyFeatures` (verb-phrase as noun) | `model.ts:220` | -| 19 | Medium | Verb-tense / action verb | `DcpAccountEnableMessage` (verb in noun position) | `model.ts:126` | -| 20 | Medium | Inconsistent action verbs | `delete*` reverts to default (not actual delete) | `client.ts:104,184` | -| 21 | Medium | Singular/plural mismatch | `complianceStandards` array on type named `CspEnablementAccount` (no list role implied) | `model.ts:99` | -| 22 | Medium | Misleading | `settingName` always coerced to `"default"` server-side | `model.ts:81,117,...; client.ts:109,...` | -| 23 | Medium | Misleading | `settingTypeName` ignored (path param wins) | `client.ts:111-113` (no doc) | -| 24 | Medium | Vague / overly verbose | `*EnablementAccount` family naming | `model.ts:92,242` | -| 25 | Medium | Overly verbose | `UpdateLlmProxyPartnerPoweredEnforceRequest` | `model.ts:502` | -| 26 | Medium | Overly verbose | `UpdateCspEnablementAccountSettingRequest` | `model.ts:454` | -| 27 | Medium | Acronym casing | `Ip` vs `IP` in `AccountIpAccessEnable` | `model.ts:66` | -| 28 | Medium | Acronym casing | `Id` vs `ID` in `accountId` | `model.ts:131,...` | -| 29 | Medium | Method name redundancy | `getCspEnablementAccountSetting` / etc. | `client.ts:262,302,...` | -| 30 | Medium | Method name redundancy | `updatePersonalComputeSetting` | `client.ts:682` | -| 31 | Medium | Duplicate concept | `Account` repeated in nearly every type | `model.ts` passim | -| 32 | Low | Acronym casing | `etag` field cased as `etag` everywhere but doc says "eTag" | `model.ts:68,75` | -| 33 | Low | Cryptic abbreviation | `acct_ip_acl_enable` wire key | `model.ts:530,541-543`; `client.ts:109,229,500` | -| 34 | Low | Cryptic abbreviation | `dcp_acct_enable` wire key | `client.ts:189,463,686` | -| 35 | Low | Cryptic abbreviation | `shield_csp_enablement_ac` / `shield_esm_enablement_ac` (trailing `_ac`) | `client.ts:266,343,529,590` | -| 36 | Low | Long enum value | `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10` | -| 37 | Low | Long enum value | `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE` | `model.ts:19-53` | -| 38 | Low | Verb-tense inconsistency | `Enable` (imperative) vs `Enablement` (noun) co-exist | `model.ts:66 vs 92,102` | -| 39 | Low | Singular/plural mismatch | `DisableLegacyFeatures` (plural type with singular boolean) | `model.ts:220-239` | -| 40 | Low | Acronym casing | `Url` vs `URL` in `httpReq.url` (field defined upstream) | `utils.ts:71,103` | -| 41 | Low | Inconsistent action verbs | `revert` semantics doc'd, but method named `delete*` | `client.ts:104,184` | -| 42 | Low | Vague / generic field | `setting?` on update requests | `model.ts:449,461,473,485,497,509,521` | +| 1 | High | Acronym casing / cryptic abbreviation | `DcpAccountEnableMessage` (DCP) | `model.ts:56,121` | +| 2 | High | Cryptic abbreviation | `Csp*` (CSP) family | `model.ts:87-119,281-295,449-458` | +| 3 | High | Cryptic abbreviation | `Esm*` (ESM) family | `model.ts:237-263,313-327,473-482` | +| 4 | High | Cryptic abbreviation | `Llm*` (LLM) family | `model.ts:329-359,377-413,485-506` | +| 5 | High | Generic field name | `value` (everywhere on `*Setting` types) | `model.ts:77-79, 113-118, 122, 231-233, 257-262, 393, 412, 431-433` | +| 6 | High | Generic + cryptic field | `acctIpAclEnable` | `model.ts:78-79` | +| 7 | High | Generic field name | `booleanVal` discriminator | `model.ts:393, 412` | +| 8 | High | Underspecified ID | `accountId` (no type/format hint) | `model.ts:126,156,186,266,...` | +| 9 | High | Domain-redundant suffix | `*Setting` suffix duplicating `Settings` package | `model.ts:97,241,415` and elsewhere | +| 10 | Medium | Proto-architecture leak | `BooleanMessage` (proto wrapper type) | `model.ts:82` | +| 11 | Medium | Proto-architecture leak | `DcpAccountEnableMessage` (`Message` suffix) | `model.ts:121` | +| 12 | Medium | Proto-architecture leak | `DcpAccountEnableMessage_Value` (proto-nested enum) | `model.ts:56` | +| 13 | Medium | Type-suffix tautology | `CspEnablementAccountSetting` | `model.ts:97` | +| 14 | Medium | Type-suffix tautology | `EsmEnablementAccountSetting` | `model.ts:241` | +| 15 | Medium | Type-suffix tautology | `PersonalComputeSetting` | `model.ts:415` | +| 16 | Medium | Duplicate concept | `*Account` vs `*AccountSetting` parallel naming | `model.ts:87 vs 97; 237 vs 241` | +| 17 | Medium | Misleading | `LlmProxyPartnerPoweredEnforce` | `model.ts:396` | +| 18 | Medium | Misleading | `LlmProxyPartnerPoweredAccount` | `model.ts:377` | +| 19 | Medium | Verb-tense / action verb | `AccountIpAccessEnable` (verb as noun) | `model.ts:61` | +| 20 | Medium | Verb-tense / action verb | `DisableLegacyFeatures` (verb-phrase as noun) | `model.ts:215` | +| 21 | Medium | Verb-tense / action verb | `DcpAccountEnableMessage` (verb in noun position) | `model.ts:121` | +| 22 | Medium | Inconsistent action verbs | `delete*` reverts to default (not actual delete) | `client.ts:105,185` | +| 23 | Medium | Singular/plural mismatch | `complianceStandards` array on type named `CspEnablementAccount` (no list role implied) | `model.ts:94` | +| 24 | Medium | Misleading | `settingName` always coerced to `"default"` server-side | `model.ts:76,112,...; client.ts:114,...` | +| 25 | Medium | Misleading | `settingTypeName` ignored (path param wins) | `client.ts:111-113` (no doc) | +| 26 | Medium | Vague / overly verbose | `*EnablementAccount` family naming | `model.ts:87,237` | +| 27 | Medium | Overly verbose | `UpdateLlmProxyPartnerPoweredEnforceRequest` | `model.ts:497` | +| 28 | Medium | Overly verbose | `UpdateCspEnablementAccountSettingRequest` | `model.ts:449` | +| 29 | Medium | Acronym casing | `Ip` vs `IP` in `AccountIpAccessEnable` | `model.ts:61` | +| 30 | Medium | Acronym casing | `Id` vs `ID` in `accountId` | `model.ts:126,...` | +| 31 | Medium | Method name redundancy | `getCspEnablementAccountSetting` / etc. | `client.ts:262,302,339,...` | +| 32 | Medium | Method name redundancy | `updatePersonalComputeSetting` | `client.ts:682` | +| 33 | Medium | Duplicate concept | `Account` repeated in nearly every type | `model.ts` passim | +| 34 | Low | Acronym casing | `etag` field cased as `etag` everywhere but doc says "eTag" | `model.ts:70,72` | +| 35 | Low | Cryptic abbreviation | `acct_ip_acl_enable` wire key | `model.ts:525,536-538`; `client.ts:109,229,500` | +| 36 | Low | Cryptic abbreviation | `dcp_acct_enable` wire key | `client.ts:189,463,686` | +| 37 | Low | Cryptic abbreviation | `shield_csp_enablement_ac` / `shield_esm_enablement_ac` (trailing `_ac`) | `client.ts:266,343,529,590` | +| 38 | Low | Long enum value | `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE` | `model.ts:19-48` | +| 39 | Low | Verb-tense inconsistency | `Enable` (imperative) vs `Enablement` (noun) co-exist | `model.ts:61 vs 87,97 vs 215` | +| 40 | Low | Singular/plural mismatch | `DisableLegacyFeatures` (plural type with singular boolean) | `model.ts:215-234` | +| 41 | Low | Acronym casing | `Url` vs `URL` in `httpReq.url` (field defined upstream) | `utils.ts:70,103` | +| 42 | Low | Inconsistent action verbs | `revert` semantics doc'd, but method named `delete*` | `client.ts:105,185` | +| 43 | Low | Vague / generic field | `setting?` on update requests | `model.ts:444,456,468,480,492,504,516` | --- ## High severity -### 1. `COMPLIANCE_STANDARD_UNSPECIFIED` — redundant enum prefix -- **File:line:** `model.ts:10` -- **Category:** Redundant enum prefix (`X_X_Y` pattern) -- **Suggestion:** Just `UNSPECIFIED`. -- **Rationale:** The enum is already named `ComplianceStandard`, so `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` triple-stutters the namespace. TypeScript enums are accessed via the enum identifier; the redundant prefix is a proto3-wire artefact that should not bleed into the TS surface. (All other members — `HIPAA`, `PCI_DSS`, etc. — correctly omit the prefix, making the inconsistency starker.) - -### 2. `DcpAccountEnableMessage` — undocumented cryptic acronym ("DCP") -- **File:line:** `model.ts:61, 126` +### 1. `DcpAccountEnableMessage` — undocumented cryptic acronym ("DCP") +- **File:line:** `model.ts:56, 121` - **Category:** Cryptic abbreviation - **Suggestion:** `DefaultComputePolicy` or, at minimum, attach a doc comment explaining the acronym. The whole type is a wrapper around a 2-value enum and could be inlined as `PersonalComputeAccess` with values `ON | DELEGATE`. - **Rationale:** "DCP" is not defined anywhere in this package. From the surrounding wire path `dcp_acct_enable` and the doc on `PersonalComputeSetting`, it appears to mean "default Personal Compute policy" — but a reader has to reverse-engineer that. A 1:1 port may have to keep the type for compatibility, but the JSDoc must explain the acronym. -### 3. `Csp*` family — undocumented cryptic acronym ("CSP") -- **File:line:** `model.ts:92, 102` and request variants +### 2. `Csp*` family — undocumented cryptic acronym ("CSP") +- **File:line:** `model.ts:87, 97` and request variants - **Category:** Cryptic abbreviation -- **Suggestion:** Spell out `ComplianceSecurityProfile` in the type names or add a top-of-file JSDoc glossary. The first comment on line 96 finally expands "Compliance Security Profile (CSP)" but only in passing — the type name itself stays cryptic. +- **Suggestion:** Spell out `ComplianceSecurityProfile` in the type names or add a top-of-file JSDoc glossary. The first comment on line 91 finally expands "Compliance Security Profile (CSP)" but only in passing — the type name itself stays cryptic. - **Rationale:** "CSP" overloads heavily in web context (Content Security Policy), so the abbreviation is misleading as well as cryptic. The expansion is documented but only deep inside a field comment. -### 4. `Esm*` family — undocumented cryptic acronym ("ESM") -- **File:line:** `model.ts:242, 246` +### 3. `Esm*` family — undocumented cryptic acronym ("ESM") +- **File:line:** `model.ts:237, 241` - **Category:** Cryptic abbreviation - **Suggestion:** `EnhancedSecurityMonitoring*` or attach an inline doc. The method JSDoc on `client.ts:338` finally expands it ("enhanced security monitoring") — but the type itself never does. - **Rationale:** Same problem as CSP. The reader has to grep the client to find the expansion. -### 5. `Llm*` family — cryptic / underspecified acronym ("LLM") -- **File:line:** `model.ts:334-418, 490-511` +### 4. `Llm*` family — cryptic / underspecified acronym ("LLM") +- **File:line:** `model.ts:329-413, 485-506` - **Category:** Cryptic abbreviation + verbose stacking - **Suggestion:** `LargeLanguageModelProxyPartnerPowered*` is unwieldy, but a domain-specific short name like `AiProxyPartnerPowered*` or `ModelProxyPartnerPowered*` would at least drop the redundant "Llm" capitalization issue. Better: a single top-level type `PartnerPoweredAi*` with sub-fields. - **Rationale:** "Llm" mixes acronym + token-casing rules: TypeScript style says either `LLM` (acronym-case for known acronyms) or `Llm` (Pascal-token-case). The codebase consistently uses `Llm`, but the larger problem is stacking cryptic + cryptic + ambiguous — "LlmProxyPartnerPoweredEnforce" parses with several plausible bracketings. -### 6. `value` field on every `*Setting` discriminated union — generic field name losing meaning -- **File:line:** `model.ts:82, 118, 127, 236, 262, 398, 417, 436` +### 5. `value` field on every `*Setting` discriminated union — generic field name losing meaning +- **File:line:** `model.ts:77, 113, 122, 231, 257, 393, 412, 431` - **Category:** Generic field name losing meaning - **Suggestion:** Name the field after what it discriminates: `payload`, or after the specific domain concept (e.g. `enabled`, `personalCompute`) per use site. - **Rationale:** Eight different types in this package use a `value?: {...}` field, each with a discriminated union of `$case: ''`. Because the field name is identical across all of them, IDE autocomplete and code review provide no hint about what the field actually represents at any given use site — `setting.value` reads identically whether the underlying meaning is "IP ACL toggle", "legacy features disabled", or "partner-powered AI enforcement". -### 7. `acctIpAclEnable` — cryptic + abbreviated discriminator value -- **File:line:** `model.ts:83-84` +### 6. `acctIpAclEnable` — cryptic + abbreviated discriminator value +- **File:line:** `model.ts:78-79` - **Category:** Cryptic abbreviation, generic field name - **Suggestion:** `accountIpAclEnabled` (or simply `enabled`). - **Rationale:** `acct` is a non-standard abbreviation of `account` that saves three characters. Inside a TypeScript SDK there is no length-budget reason to abbreviate. The fact that the parent type is already `AccountIpAccessEnable` makes the abbreviation noise. -### 8. `booleanVal` — generic discriminator value -- **File:line:** `model.ts:398, 417` +### 7. `booleanVal` — generic discriminator value +- **File:line:** `model.ts:393, 412` - **Category:** Generic field name losing meaning - **Suggestion:** `enabled` (it is, in fact, a boolean toggle of partner-powered AI features per the method doc). - **Rationale:** `booleanVal` describes the *type* not the *meaning* of the field. In a domain-specific union case, the case name should describe what it represents. (`acctIpAclEnable` and `disableLegacyFeatures` and `personalCompute` follow domain naming; `booleanVal` does not.) -### 9. `accountId` — underspecified ID -- **File:line:** `model.ts:131, 161, 191, 271, 287, 303, 319, 335, 351, 367, 443, 455, 467, 479, 491, 503, 515` +### 8. `accountId` — underspecified ID +- **File:line:** `model.ts:126, 156, 186, 266, 282, 298, 314, 330, 346, 362, 438, 450, 462, 474, 486, 498, 510` - **Category:** Underspecified ID - **Suggestion:** Add a doc comment that names the type (UUID? numeric? Databricks-internal?). Currently the `UpdateAccountIpAccessEnableRequest.accountId` is documented (` account ID of the account being managed.`) but the others are not. - **Rationale:** "accountId" leaves the reader unsure whether to pass `"123"`, `"abcd-...-uuid"`, or `"my-account@databricks.com"`. The doc inconsistency (only the update variants document it) makes this worse. -### 10. `*Setting` suffix vs package name `accountsettings` +### 9. `*Setting` suffix vs package name `accountsettings` - **File:line:** package level - **Category:** Redundant suffix in domain - **Suggestion:** Drop the `Setting` suffix from type names within the `accountsettings` package, or drop the trailing `s` from the package name. (Compare: a package called `users` whose types are all `UserUser`, `UserAccountUser`.) E.g. `CspEnablementAccountSetting` -> `CspEnablementAccount` (which already exists as a sub-type). @@ -120,108 +119,126 @@ ## Medium severity -### 11–13. `CspEnablementAccountSetting`, `EsmEnablementAccountSetting`, `PersonalComputeSetting` — type-suffix tautology -- **File:line:** `model.ts:102, 246, 420` +### 10. `BooleanMessage` — `model.ts:82` +- **Why weird:** `Message` is a protobuf code-generation suffix for wrapping a scalar into a message type. In a TypeScript SDK, a wrapper around `boolean` should not surface the proto "Message" terminology. +- **Category:** Proto-architecture leak +- **Suggested name:** `BooleanValue` (matches `google.protobuf.BoolValue` wkt convention) or eliminate the wrapper and inline `value?: boolean` at use sites. +- **Rationale:** The type body is `{value?: boolean}` — a generic scalar wrapper. The `Message` suffix only makes sense in proto-land; the TS surface exposes a boolean toggle and should read as such. + +### 11. `DcpAccountEnableMessage` — `model.ts:121` +- **Why weird:** Mid/suffix `Message` is a direct proto code-generation artifact. Every protobuf type is technically a "message," so the suffix is noise. +- **Category:** Proto-architecture leak +- **Suggested name:** `PersonalComputeAccess` or `DcpAccountEnable` (drop the trailing `Message`). +- **Rationale:** The `Message` suffix exists only because the upstream `.proto` file declares `message DcpAccountEnableMessage { ... }`. TypeScript consumers never need to know they're hitting a proto-defined endpoint — the type is an enum-wrapping state object. + +### 12. `DcpAccountEnableMessage_Value` — `model.ts:56` +- **Why weird:** Underscore-separated `_` is the protoc-go / proto-ts code-gen pattern for emitting nested enum/message types as flat top-level identifiers. The `_Value` suffix doubly leaks the proto convention of naming a nested enum `Value` inside a wrapper message. +- **Category:** Proto-architecture leak +- **Suggested name:** `PersonalComputeAccessMode` (with values `ON | DELEGATE`) — flatten the proto nesting and give the enum a domain-meaningful name. +- **Rationale:** A reader sees `DcpAccountEnableMessage_Value` and cannot tell whether the underscore is intentional or a typo. The intermediate `Message_Value` layering exists purely because protobuf nests `Value` inside `DcpAccountEnableMessage`; the TS SDK can flatten it without breaking the wire contract. + +### 13–15. `CspEnablementAccountSetting`, `EsmEnablementAccountSetting`, `PersonalComputeSetting` — type-suffix tautology +- **File:line:** `model.ts:97, 241, 415` - **Category:** Type-suffix tautology -- **Suggestion:** Drop `Setting` (see #10). For ESM/CSP the inner type already drops it (`CspEnablementAccount`, `EsmEnablementAccount`). +- **Suggestion:** Drop `Setting` (see #9). For ESM/CSP the inner type already drops it (`CspEnablementAccount`, `EsmEnablementAccount`). - **Rationale:** The package is `accountsettings`, the method is `getCspEnablementAccountSetting`, returning a `CspEnablementAccountSetting`. The word "setting" appears three times in one call. This is the classic Go-port symptom — Go has no such namespace, so the redundancy is required there; in TS it is gratuitous. -### 14. `*Account` vs `*AccountSetting` — duplicate-concept parallel naming -- **File:line:** `model.ts:92 vs 102; 242 vs 246` +### 16. `*Account` vs `*AccountSetting` — duplicate-concept parallel naming +- **File:line:** `model.ts:87 vs 97; 237 vs 241` - **Category:** Duplicate concept - **Suggestion:** Rename one half of each pair so the two types describe distinct concepts at a glance, or document the relationship in both JSDocs. - **Rationale:** Two types differing by one suffix (`CspEnablementAccount` vs `CspEnablementAccountSetting`) invite bugs where the consumer references the wrong one — the distinction between "data" and "envelope" is invisible from the name alone. -### 15. `LlmProxyPartnerPoweredEnforce` — misleading -- **File:line:** `model.ts:401` +### 17. `LlmProxyPartnerPoweredEnforce` — misleading +- **File:line:** `model.ts:396` - **Category:** Misleading / verb-tense in noun position - **Suggestion:** `LlmProxyPartnerPoweredEnforcement` (noun), and the method should be `getLlmProxyPartnerPoweredEnforcement`. - **Rationale:** `Enforce` is the imperative verb; the type represents the *enforcement setting state*. The doc on `client.ts:418` reads `Gets the enforcement status of partner powered AI features account setting` — confirming the type is a noun-of-enforcement, not the verb. -### 16. `LlmProxyPartnerPoweredAccount` — misleading -- **File:line:** `model.ts:382` +### 18. `LlmProxyPartnerPoweredAccount` — misleading +- **File:line:** `model.ts:377` - **Category:** Misleading - **Suggestion:** `LlmProxyPartnerPoweredEnabled` (or drop "Account" — every type in the package is account-scoped, the qualifier adds no information). - **Rationale:** "Account" here doesn't refer to a sub-account or an account entity — it means "scoped to the account level," which is already true of every type in the package. The name suggests an Account *object* rather than an *enablement state*. -### 17. `AccountIpAccessEnable` — verb-as-noun -- **File:line:** `model.ts:66` +### 19. `AccountIpAccessEnable` — verb-as-noun +- **File:line:** `model.ts:61` - **Category:** Verb-tense inconsistency - **Suggestion:** `AccountIpAccessToggle` (matches the method doc on `client.ts:104` "the account IP access toggle setting"), or `AccountIpAccessEnabled` (state). - **Rationale:** Types should be nouns. `Enable` is an imperative verb. The wire field name `acct_ip_acl_enable` likewise reads as a command, not a state. The doc itself calls this a "toggle setting" — that name would be far more idiomatic. -### 18. `DisableLegacyFeatures` — verb-phrase as type name -- **File:line:** `model.ts:220` +### 20. `DisableLegacyFeatures` — verb-phrase as type name +- **File:line:** `model.ts:215` - **Category:** Verb-tense inconsistency - **Suggestion:** `LegacyFeaturesDisabled` or `LegacyFeaturesToggle`. - **Rationale:** `DisableLegacyFeatures` parses as "an action that disables legacy features." Types describing the *state of the toggle* should read as such. -### 19. `DcpAccountEnableMessage` — verb in noun position -- **File:line:** `model.ts:126` +### 21. `DcpAccountEnableMessage` — verb in noun position +- **File:line:** `model.ts:121` - **Category:** Verb-tense inconsistency - **Suggestion:** `PersonalComputeAccess` (since this is in fact the personal compute policy state); drop the `Enable` imperative verb. - **Rationale:** `Enable` is an imperative verb; the type represents a state. Types describing the state of a toggle should read as nouns. -### 20 / 41. `delete*` methods that actually revert -- **File:line:** `client.ts:104 (deleteAccountIpAccessEnable doc: "Reverts the value..."), 184 (deletePersonalComputeSetting doc: "Reverts back ... to default (ON)")` +### 22 / 42. `delete*` methods that actually revert +- **File:line:** `client.ts:105 (deleteAccountIpAccessEnable doc: "Reverts the value..."), 185 (deletePersonalComputeSetting doc: "Reverts back ... to default (ON)")` - **Category:** Inconsistent action verbs / misleading - **Suggestion:** `reset*ToDefault()` (the semantics are reset-to-default, not destruction). At minimum, the method JSDoc and the verb should agree. - **Rationale:** A `delete` HTTP verb is being used to reset state — that is the *server's* idiom. The SDK can hide it with a more accurate verb. The doc literally says "Reverts" — a reader scanning method names will not see that. -### 21. `complianceStandards` array on `CspEnablementAccount` (singular type, plural field) -- **File:line:** `model.ts:99` +### 23. `complianceStandards` array on `CspEnablementAccount` (singular type, plural field) +- **File:line:** `model.ts:94` - **Category:** Singular/plural mismatch (mild — the field is plural because it's a list, which is correct; the audit checklist asks me to flag interactions). Actually this is fine — flagged only to note it's *consistent*. - **Suggestion:** No change. -### 22. `settingName` documented to be ignored, "must be `default`" -- **File:line:** `model.ts:81, 117, 235, 261, 397, 416, 435` +### 24. `settingName` documented to be ignored, "must be `default`" +- **File:line:** `model.ts:76, 112, 230, 256, 392, 411, 430` - **Category:** Misleading - **Suggestion:** Either remove the field from the TS surface (since the doc says it will not be respected on requests and is always `"default"` server-side) or rename to `settingName_readOnly` and mark it `readonly`. - **Rationale:** Exposing a field that the API explicitly ignores invites confused user code. The doc says verbatim: "This field is populated in the response, but it will not be respected even if it's set in the request body. The setting name in the path parameter will be respected instead." -### 23. `settingTypeName` query param has no purpose +### 25. `settingTypeName` query param has no purpose - **File:line:** `client.ts:111-113` (and every other method that appends it as a query param) - **Category:** Misleading / vague - **Suggestion:** Remove from request types (the actual type is hard-coded into the URL path) or document that it is informational only. - **Rationale:** The URL already encodes `types/acct_ip_acl_enable`; appending `?setting_type_name=acct_ip_acl_enable` is at best a no-op. If it's required for some legacy reason, that needs a comment. -### 24. `*EnablementAccount` family — verbose and weak -- **File:line:** `model.ts:92, 242` +### 26. `*EnablementAccount` family — verbose and weak +- **File:line:** `model.ts:87, 237` - **Category:** Vague / overly verbose - **Suggestion:** Drop `Enablement` — it adds no information beyond "this thing represents whether the feature is enabled," which is already implied by the boolean fields. `CspAccount` / `EsmAccount`, or better, `CspState` / `EsmState`. - **Rationale:** "Enablement" is an awkward noun coined to allow modeling "the state of enablement of X." Standard English would say "X enabled" (adjective) or just "X" with a bool field. -### 25–26. `UpdateLlmProxyPartnerPoweredEnforceRequest` / `UpdateCspEnablementAccountSettingRequest` — overly verbose -- **File:line:** `model.ts:502, 454` +### 27–28. `UpdateLlmProxyPartnerPoweredEnforceRequest` / `UpdateCspEnablementAccountSettingRequest` — overly verbose +- **File:line:** `model.ts:497, 449` - **Category:** Overly verbose -- **Suggestion:** Shorter forms like `UpdateLlmProxyEnforcementRequest` / `UpdateCspRequest`, paired with the renames in #14 and #24. +- **Suggestion:** Shorter forms like `UpdateLlmProxyEnforcementRequest` / `UpdateCspRequest`, paired with the renames in #13 and #23. - **Rationale:** 38 characters in `UpdateLlmProxyPartnerPoweredEnforceRequest` is too long to scan, and most of it is fixed boilerplate ("PartnerPowered", "Account", "Setting", "Request"). -### 27. `Ip` vs `IP` acronym casing -- **File:line:** `model.ts:66` (and references) +### 29. `Ip` vs `IP` acronym casing +- **File:line:** `model.ts:61` (and references) - **Category:** Acronym casing inconsistency - **Suggestion:** Pick one. TypeScript's de-facto style (and the Google TS style guide) treats 2-letter acronyms as PascalCase tokens (`Ip`), so `AccountIpAccessEnable` is actually correct by that rule. But the Go SDK uses `IP`; the JS SDK is consistent with TS conventions here. Just note for the audit. - **Rationale:** Within this package the choice is consistent; cross-package consistency should be verified. -### 28. `Id` vs `ID` acronym casing -- **File:line:** `model.ts:131, 161, 191, ...` +### 30. `Id` vs `ID` acronym casing +- **File:line:** `model.ts:126, 156, 186, ...` - **Category:** Acronym casing inconsistency -- **Suggestion:** Same as #27 — `Id` matches TS conventions. -- **Rationale:** Same as #27. +- **Suggestion:** Same as #29 — `Id` matches TS conventions. +- **Rationale:** Same as #29. -### 29. Method-name redundancy: `getCspEnablementAccountSetting` +### 31. Method-name redundancy: `getCspEnablementAccountSetting` - **File:line:** `client.ts:262, 302, 339, 379, 419, 459` - **Category:** Method name redundancy - **Suggestion:** Drop `Setting` from method names (the `Client` is already account-settings-scoped; `client.getCsp()` is unambiguous in context). - **Rationale:** `accountsettings.Client.getCspEnablementAccountSetting()` repeats "setting" in package + method. Compare similar SDKs where `settings.Client.getCsp()` is the norm. -### 30. `updatePersonalComputeSetting` — same redundancy +### 32. `updatePersonalComputeSetting` — same redundancy - **File:line:** `client.ts:682` - **Category:** Method name redundancy - **Suggestion:** `updatePersonalCompute()`. -- **Rationale:** Same as #29. +- **Rationale:** Same as #31. -### 31. `Account` repeated in nearly every type +### 33. `Account` repeated in nearly every type - **File:line:** `model.ts` passim - **Category:** Duplicate concept (package scope already implies account-level) - **Suggestion:** Drop the `Account` prefix/suffix where the package name (`accountsettings`) already conveys it. @@ -231,60 +248,55 @@ ## Low severity -### 32. `etag` field cased as `etag` but JSDoc consistently says "eTag" -- **File:line:** `model.ts:68 (field: `etag`), 75 (doc: "as the eTag provided")` +### 34. `etag` field cased as `etag` but JSDoc consistently says "eTag" +- **File:line:** `model.ts:70 (field: `etag`), 72 (doc: "as the eTag provided")` - **Category:** Acronym casing inconsistency - **Suggestion:** Pick `etag` everywhere (HTTP standard is `ETag` per RFC 7232 but most code uses `etag`). -- **Rationale:** Within a single JSDoc block, line 68 declares `etag?: string` and line 70 capitalizes it as `eTag`. Trivial inconsistency. +- **Rationale:** Within a single JSDoc block, line 70 declares `etag?: string` and line 63 capitalizes it as `eTag`. Trivial inconsistency. -### 33. `acct_ip_acl_enable` wire key -- **File:line:** `model.ts:530, 541-543`; `client.ts:109, 229, 500` +### 35. `acct_ip_acl_enable` wire key +- **File:line:** `model.ts:525, 536-538`; `client.ts:109, 229, 500` - **Category:** Cryptic abbreviation (server-controlled, but leaks via the discriminator `$case: 'acctIpAclEnable'`) - **Suggestion:** Server side can keep wire keys; the TS-facing discriminator `$case: 'acctIpAclEnable'` should be `accountIpAclEnable` or `enabled`. - **Rationale:** Users have to type the `$case` string literal, so abbreviations cost real ergonomics. -### 34. `dcp_acct_enable` wire key +### 36. `dcp_acct_enable` wire key - **File:line:** `client.ts:189, 463, 686` - **Category:** Cryptic abbreviation (server-side path) - **Suggestion:** N/A (server URL is fixed). Note for observability. -### 35. `shield_csp_enablement_ac` / `shield_esm_enablement_ac` wire keys +### 37. `shield_csp_enablement_ac` / `shield_esm_enablement_ac` wire keys - **File:line:** `client.ts:266, 343, 529, 590` - **Category:** Cryptic abbreviation (server-side path) - **Suggestion:** N/A. The trailing `_ac` (presumably "account") is an artefact of server naming. -### 36. `COMPLIANCE_STANDARD_UNSPECIFIED` — long enum value -- **File:line:** `model.ts:10` -- **Category:** Long enum value -- **Suggestion:** See #1. - -### 37. Long enum values (`CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5`, `ITAR_EAR`, `GERMANY_C5`, `ISMAP`, `HITRUST`, `K_FSI`, `ARC_AMPE`) -- **File:line:** `model.ts:19-53` +### 38. Long enum values (`CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5`, `ITAR_EAR`, `GERMANY_C5`, `ISMAP`, `HITRUST`, `K_FSI`) +- **File:line:** `model.ts:19-48` - **Category:** Long enum values - **Suggestion:** Keep — these are well-known compliance standard names where the string literal *is* the canonical form. Flagging only for completeness. - **Rationale:** Compliance standards have official names. Shortening `FEDRAMP_MODERATE` to `FEDRAMP_MOD` would be a regression. -### 38. `Enable` (verb) vs `Enablement` (noun) co-exist -- **File:line:** `model.ts:66 (AccountIpAccessEnable) vs 92, 102 (CspEnablement...) vs 220 (DisableLegacyFeatures)` +### 39. `Enable` (verb) vs `Enablement` (noun) co-exist +- **File:line:** `model.ts:61 (AccountIpAccessEnable) vs 87, 97 (CspEnablement...) vs 215 (DisableLegacyFeatures)` - **Category:** Verb-tense inconsistency - **Suggestion:** Standardize: either `*Enabled` (boolean adjective) or `*Toggle` (noun) across all toggle types. - **Rationale:** Within one package, three different lexical forms describe the same concept ("a boolean toggle"). A reader can't predict the form for a new toggle. -### 39. `DisableLegacyFeatures` — plural noun, singular boolean -- **File:line:** `model.ts:220-239` +### 40. `DisableLegacyFeatures` — plural noun, singular boolean +- **File:line:** `model.ts:215-234` - **Category:** Singular/plural mismatch (mild) - **Suggestion:** `DisableLegacyFeaturesToggle` (it's a single bool, not a list of features). - **Rationale:** The bare plural reads as "a list of disable-legacy-feature entries"; the type body shows it's a single bool. -### 40. `Url` vs `URL` casing -- **File:line:** `utils.ts:71, 103` (HttpRequest field used as `url`) +### 41. `Url` vs `URL` casing +- **File:line:** `utils.ts:70, 103` (HttpRequest field used as `url`) - **Category:** Acronym casing inconsistency - **Suggestion:** Conforms to TS convention (`url`/`Url`). Note for the audit. -### 41. (see #20) +### 42. (see #22) -### 42. `setting?` on every update request — vague -- **File:line:** `model.ts:449, 461, 473, 485, 497, 509, 521` +### 43. `setting?` on every update request — vague +- **File:line:** `model.ts:444, 456, 468, 480, 492, 504, 516` - **Category:** Vague / generic field name - **Suggestion:** Name the field after its type (`personalCompute?: PersonalComputeSetting`) — when there's exactly one payload type per request, the parameter name should reflect it. - **Rationale:** `req.setting` is so generic the IDE auto-complete tells the user nothing. `req.personalCompute` would. @@ -313,14 +325,14 @@ | Acronym / token | Expansion | Mentioned in code? | |-----------------|-----------|--------------------| -| **CSP** | Compliance Security Profile | Yes, `model.ts:96` (one-time) | +| **CSP** | Compliance Security Profile | Yes, `model.ts:91` (one-time) | | **ESM** | Enhanced Security Monitoring | Only in method JSDoc `client.ts:338` | -| **ESC** | Enhanced Security Compliance | Yes, `model.ts:13` | +| **ESC** | Enhanced Security Compliance | Yes, `model.ts:12` | | **DCP** | (Default) Personal Compute policy | No (inferred from wire key `dcp_acct_enable` + neighbouring docs) | | **LLM** | Large Language Model | No | | **ACL** | Access Control List | Yes (wire only, `acct_ip_acl_enable`) | | **IP** | Internet Protocol (network address) | Implicit | -| **AIP** | API Improvement Proposals (Google) | `model.ts:447` ("Added for AIP compliance.") — undocumented | +| **AIP** | API Improvement Proposals (Google) | `model.ts:442` ("Added for AIP compliance.") — undocumented | | **etag** | Entity tag (HTTP cache validator, RFC 7232) | Yes (in field doc) | | **SHIELD** | Databricks security product line | `model.ts:7` (one-time, undefined) | @@ -330,7 +342,15 @@ | File | Lines read | Coverage | |------|-----------|----------| -| `src/v1/index.ts` | 40 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | -| `src/v1/model.ts` | 1204 (full) | 100% — all 23 types, 2 enums, 16 zod schemas, 7 field-mask helpers audited. | +| `src/v1/index.ts` | full | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | +| `src/v1/model.ts` | 1199 (full) | 100% — all 23 types, 2 enums, zod schemas, field-mask helpers audited. | | `src/v1/client.ts` | 710 (full) | 100% — all 13 client methods, constructor, and private fields audited. | -| `src/v1/utils.ts` | 151 (full) | 100% — utility functions reviewed; `HttpCallOptions`, `executeCall`, `parseResponse`, `marshalRequest`, `flattenQueryParams` have no naming issues worth flagging (they are infrastructure shared across packages and follow consistent conventions). | +| `src/v1/utils.ts` | full | 100% — utility functions reviewed; `HttpCallOptions`, `executeCall`, `parseResponse`, `marshalRequest`, `flattenQueryParams` have no naming issues worth flagging (they are infrastructure shared across packages and follow consistent conventions). | + +--- + +## Fixed + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md index 7f8ccfbc..eb58ad1b 100644 --- a/.agent/naming-audit/alerts.md +++ b/.agent/naming-audit/alerts.md @@ -10,7 +10,7 @@ | # | Severity | Version | Location | Name | Category | |---|----------|---------|----------|------|----------| | 1 | High | v2 | `model.ts` enum | `Aggregation` | Vague/generic, no domain prefix | -| 2 | High | v2 | `model.ts` enum value | `AlertEvaluationState.UNKNOWN` | Misleading (proto sentinel exposed) | +| 2 | High | v2 | `model.ts` enum value | `AlertEvaluationState.UNKNOWN` | Inconsistent sentinel naming (`UNKNOWN` vs `UNSPECIFIED`) | | 3 | High | v1 | `model.ts` field | `AlertCondition.op` | Cryptic abbreviation | | 4 | High | v1 | `model.ts` field | `Alert.secondsToRetrigger` / v2 `AlertNotification.retriggerSeconds` | Singular/plural mismatch & cross-version regression in word order | | 5 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | @@ -27,7 +27,7 @@ | 16 | Medium | v2 | `model.ts` field | `CronSchedule.timezoneId` | Underspecified ID (timezone name, not numeric) | | 17 | Medium | v2 | `model.ts` field | `CronSchedule.quartzCronSchedule` | Type-suffix tautology | | 18 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | -| 19 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Domain-detached prefix | +| 19 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Boolean-shaped enum | | 20 | Medium | v2 | `model.ts` field | `Alert.evaluation` (no domain qualifier) | Generic field name | | 21 | Medium | v2 | `model.ts` field | `Alert.lifecycleState` documented as "Indicates whether the query is trashed" | Misleading (says query, means alert) | | 22 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | @@ -41,7 +41,7 @@ | 30 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | | 31 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | | 32 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | -| 33 | Low | v2 | `model.ts` field | `Alert.parentPath` and `effectiveParentPath` | "Effective" prefix unexplained at first read | +| 33 | Low | v2 | `model.ts` field | `Alert.effectiveRunAs` | "Effective" prefix unexplained at first read | | 34 | Low | v2 | `model.ts` field | `Alert.id`, `Alert.queryText` co-located | "id" alone underspecified at field level (docs clarify) | | 35 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | @@ -73,7 +73,7 @@ - `AlertRunAs` (type) — verb-as-noun. - `AlertSubscription` (type) - `CronSchedule` (type) — generic name in a single-domain package. -- `Alert.queryText`, `Alert.warehouseId`, `Alert.runAsUserName`, `Alert.runAs`, `Alert.effectiveRunAs`, `Alert.effectiveParentPath`, `Alert.schedule`, `Alert.evaluation`, `Alert.customSummary`, `Alert.customDescription`. +- `Alert.queryText`, `Alert.warehouseId`, `Alert.runAsUserName`, `Alert.runAs`, `Alert.effectiveRunAs`, `Alert.schedule`, `Alert.evaluation`, `Alert.customSummary`, `Alert.customDescription`. - `TrashAlertRequest.purge` — new flag. ### Dropped in v2 @@ -105,7 +105,7 @@ export enum Aggregation { Exported at the package root without an `Alert` or `Column` prefix. The same word is overloaded across SQL, stats, monitoring, and ML domains. `AlertOperandAggregation` or `ColumnAggregation` would be unambiguous. -### 2. `AlertEvaluationState.UNKNOWN` — proto sentinel leak (v2) +### 2. `AlertEvaluationState.UNKNOWN` — inconsistent sentinel naming and deprecated value (v2) **Location:** `src/v2/model.ts:26-32` @@ -124,7 +124,7 @@ export enum AlertEvaluationState { } ``` -Inline JSDoc tells the user not to use `UNKNOWN`, yet the enum exports it. The header even mentions `UNSPECIFIED` (not exported, but described). Both are proto implementation details surfacing into the TS API. +This enum exposes a value (`UNKNOWN`) that the inline JSDoc tells the user to avoid: "Deprecated. Please avoid using `UNKNOWN` as empty_result_state." Shipping a deprecated value as part of the public enum surface is a naming/API smell — consumers reading the type cannot tell which values are valid without the JSDoc. Additionally, this enum's zero-value sentinel is named `UNSPECIFIED` while other enums in the package use `UNKNOWN` for the same role; the package-wide sentinel convention is inconsistent. ### 3. `AlertCondition.op` — cryptic abbreviation (v1) @@ -142,7 +142,7 @@ export interface AlertCondition { ### 4. `secondsToRetrigger` vs `retriggerSeconds` — singular/plural & cross-version reorder -**Location:** `src/v1/model.ts:38-39`; `src/v2/model.ts:124-128` +**Location:** `src/v1/model.ts:38-39`; `src/v2/model.ts:122-126` ```ts // v1 @@ -155,7 +155,7 @@ retriggerSeconds?: number | undefined; ### 5. `AlertRunAs` — verb-as-noun (v2) -**Location:** `src/v2/model.ts:157-170` +**Location:** `src/v2/model.ts:155-168` ```ts export interface AlertRunAs { @@ -170,7 +170,7 @@ export interface AlertRunAs { ### 6. Duplicate concept — `runAsUserName` vs `runAs.userName` (v2) -**Location:** `src/v2/model.ts:72-99` +**Location:** `src/v2/model.ts:77-99` ```ts // Deprecated: Use `run_as` field instead. ... @@ -184,7 +184,7 @@ The same data is expressible as either `runAsUserName` (legacy scalar) or `runAs ### 7. `Alert.queryText` — field contradicts type domain (v2) -**Location:** `src/v2/model.ts:68-71` +**Location:** `src/v2/model.ts:68-69` ```ts /** Text of the query to be run. */ @@ -197,7 +197,7 @@ A type named `Alert` carrying a raw SQL string makes the alert object responsibl ### 8. `trashAlert` — inconsistent action verb (both) -**Location:** `src/v1/client.ts:169-192`; `src/v2/client.ts:167-196` +**Location:** `src/v1/client.ts:170-192`; `src/v2/client.ts:168-196` ```ts /** Moves an alert to the trash. ... A trashed alert is permanently deleted after 30 days. */ @@ -208,7 +208,7 @@ The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but ### 9. `TrashAlertRequest` — same as 8, in the type layer (both) -**Location:** `src/v1/model.ts:187-189`; `src/v2/model.ts:222-226` +**Location:** `src/v1/model.ts:187-189`; `src/v2/model.ts:218-222` Same verb inconsistency at the type layer. @@ -225,7 +225,7 @@ The wire format uses long, English-prose enum values where most SDKs use `GT`, ` ### 11. `Alert.notifyOnOk` — acronym/initialism case ambiguity (both) -**Location:** `src/v1/model.ts:59`; `src/v2/model.ts:130` +**Location:** `src/v1/model.ts:59`; `src/v2/model.ts:128` ```ts notifyOnOk?: boolean | undefined; @@ -246,7 +246,7 @@ triggerTime?: Temporal.Instant | undefined; ### 13. `AlertEvaluation.lastEvaluatedAt` — inconsistent time suffix (v2) -**Location:** `src/v2/model.ts:114-116` +**Location:** `src/v2/model.ts:113-114` ```ts lastEvaluatedAt?: Temporal.Instant | undefined; @@ -256,7 +256,7 @@ Every other timestamp in v2 uses the `*Time` suffix (`createTime`, `updateTime`) ### 14. `AlertOperandColumn.display` — vague (v2) -**Location:** `src/v2/model.ts:141-146` +**Location:** `src/v2/model.ts:139-144` ```ts export interface AlertOperandColumn { @@ -281,7 +281,7 @@ In a different package this might be a data warehouse, a logical warehouse, etc. ### 16. `CronSchedule.timezoneId` — underspecified ID (v2) -**Location:** `src/v2/model.ts:189-194` +**Location:** `src/v2/model.ts:187-192` ```ts /** A Java timezone id. ... */ @@ -292,7 +292,7 @@ A timezone is named (e.g., `"America/Los_Angeles"`), not numerically identified. ### 17. `CronSchedule.quartzCronSchedule` — type-suffix tautology (v2) -**Location:** `src/v2/model.ts:183-188` +**Location:** `src/v2/model.ts:181-186` ```ts export interface CronSchedule { @@ -305,11 +305,11 @@ The type is `CronSchedule`, the field is `quartzCronSchedule`. The user writes ` ### 18. `CronSchedule` — generic name in a single-domain package (v2) -**Location:** `src/v2/model.ts:183-199` +**Location:** `src/v2/model.ts:181-195` A top-level type called `CronSchedule` in a package whose only consumer is alerts. If/when another package wants its own cron schedule shape, the user has two `CronSchedule`s. `AlertSchedule` would domain-prefix consistently with the rest of v2. -### 19. `SchedulePauseStatus` — domain-detached prefix (v2) +### 19. `SchedulePauseStatus` — boolean-shaped enum (v2) **Location:** `src/v2/model.ts:50-53` @@ -320,7 +320,7 @@ export enum SchedulePauseStatus { } ``` -The enum is prefixed by `Schedule` (its host type), not by the package (`Alert`). Mixed convention with `AlertLifecycleState`, `AlertEvaluationState`. Also: two values for a boolean concept; `boolean paused` would be simpler. +Two values for a boolean concept; `boolean paused` would be simpler. ### 20. `Alert.evaluation` — generic field name (v2) @@ -351,7 +351,7 @@ The method is still `trashAlert` (both versions), but in v1 the resulting state ### 23. `AlertSubscription.subscriptionType` — type-suffix tautology (v2) -**Location:** `src/v2/model.ts:172-177` +**Location:** `src/v2/model.ts:170-175` ```ts export interface AlertSubscription { @@ -431,14 +431,20 @@ v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycl Same data, different vocabulary. v1 = email metaphor, v2 = generic content metaphor. Users porting from v1 to v2 need a translation table. -### 33. `effectiveParentPath` / `effectiveRunAs` (v2) +### 33. `effectiveRunAs` (v2) + +**Location:** `src/v2/model.ts:94-99` ```ts -/** The actual workspace path of the folder containing the alert. This is an output-only field. */ -effectiveParentPath?: string | undefined; +/** + * The actual identity that will be used to execute the alert. + * This is an output-only field that shows the resolved run-as identity after applying + * permissions and defaults. + */ +effectiveRunAs?: AlertRunAs | undefined; ``` -The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. +The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. (Previously also cited `effectiveParentPath`; that field was removed in regeneration.) ### 34. `Alert.id` (both) @@ -487,11 +493,11 @@ async updateAlert(...) { ... } | File | Lines | Read in full | |------|-------|--------------| -| `src/v1/model.ts` | 621 | yes | +| `src/v1/model.ts` | 620 | yes | | `src/v1/client.ts` | 219 | yes | | `src/v1/utils.ts` | 150 | yes | | `src/v1/index.ts` | 23 | yes | -| `src/v2/model.ts` | 683 | yes | +| `src/v2/model.ts` | 669 | yes | | `src/v2/client.ts` | 235 | yes | | `src/v2/utils.ts` | 150 | yes | | `src/v2/index.ts` | 30 | yes | diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index 25b2aea4..7fef8cd2 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -10,10 +10,10 @@ with deployments, custom templates, app spaces, and resource bindings. | Severity | Count | | -------- | ----- | | High | 11 | -| Medium | 26 | -| Low | 20 | -| Observation | 10 | -| **Total** | **67** | +| Medium | 25 | +| Low | 18 | +| Observation | 9 | +| **Total** | **63** | The audit found one dominant theme: the domain has overlapping vocabularies for the same concept. `App` vs `Application` (`ApplicationStatus`, @@ -31,46 +31,21 @@ Apps is unclear. ## High-severity findings ### H1. `ApplicationStatus` vs `App` — duplicate top-level "application" concept -- **File:** `model.ts:693, 1054`, also `index.ts:42, 76` +- **File:** `model.ts:681, 1014`, also `index.ts:40, 72` - **Category:** Duplicate concepts (12), Misleading names (6) - **Issue:** The package's primary entity is `App`, but the runtime state of an App is modelled by a struct called `ApplicationStatus` (with enum - `ApplicationStatus_ApplicationState` and values `APPLICATION_STATE_UNSPECIFIED`, - etc.). On `App`, the field is `appStatus?: ApplicationStatus`, so the type - name disagrees with the field name. There are two parallel vocabularies for - the same idea. + `ApplicationStatus_ApplicationState`). On `App`, the field is + `appStatus?: ApplicationStatus`, so the type name disagrees with the field + name. There are two parallel vocabularies for the same idea. - **Suggestion:** Rename `ApplicationStatus` -> `AppStatus`, the nested enum to - `AppStatus.State` (TS namespace) or `AppState`, and the values to `RUNNING`, - `DEPLOYING`, etc. Aligns with the `App` entity and with the `appStatus` - field. + `AppStatus.State` (TS namespace) or `AppState`. Aligns with the `App` entity + and with the `appStatus` field. - **Rationale:** A consumer reading `app.appStatus: ApplicationStatus` has to prove to themselves that "application" and "app" refer to the same thing. -### H2. Enum-value prefix repetition -- **File:** `model.ts:516-521, 525-528, 685-690, 694-699, 703-711, 715-722` -- **Category:** Redundant enum prefixes (2), Long enum values (18) -- **Issue:** Multiple enums repeat their type name in every value: - - `SpaceUpdateState`: `SPACE_UPDATE_STATE_UNSPECIFIED` (4 of 5 values). - - `AppDeployment_Mode`: `MODE_UNSPECIFIED`. - - `AppUpdate_UpdateStatus_UpdateState`: `UPDATE_STATE_UNSPECIFIED`. - - `ApplicationStatus_ApplicationState`: `APPLICATION_STATE_UNSPECIFIED`. - - `ComputeStatus_ComputeState`: `COMPUTE_STATE_UNSPECIFIED`. - - `SpaceStatus_SpaceState`: `SPACE_STATE_UNSPECIFIED`, **plus every other - value is also prefixed**: `SPACE_CREATING`, `SPACE_ACTIVE`, `SPACE_ERROR`, - `SPACE_DELETING`, `SPACE_DELETED`, `SPACE_UPDATING`. None of the other - state enums prefix their non-UNSPECIFIED values, so this enum is also - internally inconsistent. -- **Suggestion:** Drop the type-name prefix from each value: - `UNSPECIFIED`/`SUCCEEDED`/`FAILED`/`IN_PROGRESS`/`NOT_UPDATED` for the - update-state enums; `CREATING`/`ACTIVE`/`ERROR`/`DELETING`/`DELETED`/ - `UPDATING` for `SpaceStatus_SpaceState`. -- **Rationale:** Each value is already qualified by the enum name at the use - site (`SpaceUpdateState.UNSPECIFIED`). Google's TS style guide and the - `@typescript-eslint/naming-convention` rule both prefer un-prefixed enum - values. - -### H3. `ErrorCode` (76 values) shipped from a package whose surface is Apps -- **File:** `model.ts:15-513`, also `index.ts:17` +### H2. `ErrorCode` (76 values) shipped from a package whose surface is Apps +- **File:** `model.ts:14-512`, also `index.ts:17` - **Category:** Vague/generic without domain context (1), Duplicate concepts (12) - **Issue:** The `ErrorCode` enum has 76 values, the majority of which are Unity Catalog, Repos, Files API, and Workspaces error codes @@ -87,8 +62,8 @@ Apps is unclear. is being inlined into a service-specific package. This is the canonical case the project's own `apierr/codes` directory was created to avoid. -### H4. `Operation` — generic name with no domain prefix -- **File:** `model.ts:1318`, also `index.ts:106`, `client.ts:309, 408, 536, 951` +### H3. `Operation` — generic name with no domain prefix +- **File:** `model.ts:1267`, also `index.ts:102`, `client.ts:275, 375, 527, 905` - **Category:** Vague/generic without domain context (1) - **Issue:** `Operation` is exported as a top-level type. There is no Apps context in the name; a user importing `Operation` from `@databricks/sdk-apps` @@ -105,24 +80,22 @@ Apps is unclear. and they will collide on import. Either a shared canonical type or a domain-specific rename is required. -### H5. `space` string field on `App` vs `spaceId` — which is the identifier? -- **File:** `model.ts:786-790`, `client.ts:624-626` +### H4. `space` string field on `App` vs `spaceId` — which is the identifier? +- **File:** `model.ts:773`, `client.ts:612-614` - **Category:** Underspecified IDs (19), Misleading names (6), Generic field names (15) -- **Issue:** `App` has two fields: - - `space?: string` ("Name of the space this app belongs to") - - `spaceId?: string` ("The ID of the app space this app belongs to") - These are both stringly-typed and distinguishable only by the documentation. - `ListAppsRequest.space` is also a `string` filter that takes the space - *name*. The bare `space` field looks like it should be a `Space` object - rather than a string handle. -- **Suggestion:** Rename `space` -> `spaceName` to mirror `spaceId` and to - reduce confusion with the `Space` interface. Update +- **Issue:** `App` has a `space?: string` field ("Name of the space this app + belongs to") that is stringly-typed and distinguishable only by the + documentation. `ListAppsRequest.space` is also a `string` filter that takes + the space *name*. The bare `space` field looks like it should be a `Space` + object rather than a string handle. +- **Suggestion:** Rename `space` -> `spaceName` to mirror conventions like + `spaceId` and to reduce confusion with the `Space` interface. Update `ListAppsRequest.space` -> `spaceName` to match. - **Rationale:** A field literally named after a type (`space: string` next to `interface Space`) violates the "field contradicting type domain" rule. -### H6. `name` is the App's primary key, not `id` — ambiguous identifier -- **File:** `model.ts:725-729, 768-769, 1132-1135, 1176-1180` +### H5. `name` is the App's primary key, not `id` — ambiguous identifier +- **File:** `model.ts:717, 756, 1090, 1134` - **Category:** Underspecified IDs (19), Misleading names (6) - **Issue:** `App.name` is the URL-path identifier used by all client methods (`/api/2.0/apps/${req.name}`); `App.id` is a separate "unique identifier" @@ -140,8 +113,8 @@ Apps is unclear. renamed via the marshal/unmarshal mapping. Mixing `name` and `appName` for the same role across request types makes the API harder to discover. -### H7. Inconsistent value sets across sibling "state of an async op" enums -- **File:** `model.ts:524, 684, 515` +### H6. Inconsistent value sets across sibling "state of an async op" enums +- **File:** `model.ts:530, 672, 514` - **Category:** Verb-tense inconsistency (13), Duplicate concepts (12) - **Issue:** Three sibling state enums in the same file have inconsistent value sets: @@ -159,8 +132,8 @@ Apps is unclear. same value vocabulary unless the underlying state machines genuinely differ — and if they differ, the doc should say why. -### H8. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym -- **File:** `model.ts:772-773` +### H7. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym +- **File:** `model.ts:759-760` - **Category:** Acronym casing inconsistencies (3) - **Issue:** The fields use `oauth2` (all-lowercase) embedded with PascalCase. Google's TS style guide treats this as an acronym; the canonical case is @@ -172,27 +145,25 @@ Apps is unclear. - **Rationale:** Inconsistent with how the SDK treats other acronyms (e.g. `Url` in `thumbnailUrl`, `Id` in many fields). -### H9. `defaultGitSource` / `defaultSourceCodePath` / `gitRepository` — three coexisting "source" concepts on `App` -- **File:** `model.ts:760-763, 776-781, 786-794` +### H8. `defaultSourceCodePath` vs `gitRepository` — two coexisting "source" concepts on `App` +- **File:** `model.ts:750, 768` - **Category:** Duplicate concepts (12), Misleading names (6) -- **Issue:** `App` has all of: - - `defaultSourceCodePath?: string` - - `defaultGitSource?: GitSource` - - `gitRepository?: GitRepository` - - `deploymentSource` discriminated union of `sourceCodePath | gitSource` - This creates four overlapping ways to describe deployment provenance. -- **Suggestion:** Treat the `default*` pair as the historical (last-deployed) - data; rename to `lastDeploymentSourceCodePath` / `lastDeploymentGitSource` - to mirror `lastDeploymentId`. Then `gitRepository` is the per-app - configuration, and `deploymentSource` is the union for *new* deployments — - three clearly differentiated roles. -- **Rationale:** Today a reader can't tell whether `defaultGitSource` is the - default for new deployments, the most-recently-used source, or the - registered repo. The Go doc comment on the field clarifies it tracks the - last active deployment, but the name does not. - -### H10. `noCompute` boolean on `CreateAppRequest` -- **File:** `model.ts:1091-1095` +- **Issue:** `App` has both `defaultSourceCodePath?: string` and + `gitRepository?: GitRepository`. The `defaultSourceCodePath` doc says it + "tracks the workspace source code path of the last active deployment", while + `gitRepository` is the configured repo. These describe overlapping aspects of + deployment provenance and the naming does not clarify their distinct roles. +- **Suggestion:** Treat `defaultSourceCodePath` as the historical + (last-deployed) data; rename to `lastDeploymentSourceCodePath` to mirror + `lastDeploymentId` (if such a convention is used). Then `gitRepository` + remains the per-app configuration — two clearly differentiated roles. +- **Rationale:** Today a reader can't tell whether `defaultSourceCodePath` is + the default for new deployments or the most-recently-used source. The doc + comment clarifies it tracks the last active deployment, but the name does + not. + +### H9. `noCompute` boolean on `CreateAppRequest` +- **File:** `model.ts:1049-1050` - **Category:** Misleading names (6) - **Issue:** `noCompute?: boolean` with doc "If true, the app will not be started after creation." The negation in the name plus the documented @@ -207,15 +178,32 @@ Apps is unclear. also describes a behaviour ("start") rather than its surface effect ("no compute"). +### H10. `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix is a wire-format architectural leak +- **File:** `model.ts:1081`, also `index.ts:80`, used at `model.ts:1296` and serialised at `model.ts:1955, 2072`. +- **Category:** Proto-architectural-leak (Proto suffix), Overly verbose (7) +- **Issue:** The public type carries a `Proto` suffix, exposing the + underlying protobuf serialization format in the TS public surface. The + suffix has no meaning to a JS/TS consumer and is purely a leak from the + upstream `.proto` definition. The name is also overly long for what is + effectively the API error envelope. +- **Suggestion:** Rename to `DatabricksServiceException` or, better, drop + this local copy entirely and reuse the canonical error envelope from + `@databricks/sdk-databricks/apierror` (parallels H2, which makes the same + case for `ErrorCode`). +- **Rationale:** Wire-format tokens (`Proto`, `Rpc`, `Grpc`) in public + type names violate the proto-architectural-leak rule. The TS SDK should + not surface implementation-layer artefacts that a hand-written client + would never name this way. + ### H11. Singular `permission` field holding a single value but documented as plural permissions -- **File:** `model.ts:866-869, 984-989` +- **File:** `model.ts:838-839, 947-948` - **Category:** Singular/plural mismatches (9) - **Issue:** `AppManifest_AppResourceJobSpec.permission?: ...JobPermission` has doc text `Permissions to grant on the Job. Supported permissions are: "CAN_MANAGE", "IS_OWNER", "CAN_MANAGE_RUN", "CAN_VIEW".` Same pattern in - `AppResourceJob.permission` (line 987). The field name is singular but the - doc says "Permissions" (plural) and lists four. The same hybrid singular/ - plural language appears in seven other resource specs. + `AppResourceJob.permission`. The field name is singular but the doc says + "Permissions" (plural) and lists four. The same hybrid singular/plural + language appears in seven other resource specs. - **Suggestion:** Either (a) make the field plural and convert it to an array if multiple values can be granted, or (b) keep singular and reword the doc to "Permission to grant on the job. One of: ...". Today the singular type @@ -228,7 +216,7 @@ Apps is unclear. ## Medium-severity findings ### M1. `creator` / `updater` — bare-noun fields holding emails -- **File:** `model.ts:744, 748, 818, 820, 1372, 1376` +- **File:** `model.ts:732, 736, 797, 1077, 1321, 1325` - **Category:** Generic field names (15), Misleading names (6) - **Issue:** `creator?: string` is documented as "The email of the user that created the app". The field name suggests an identity or a user object, but @@ -238,15 +226,15 @@ Apps is unclear. `CustomTemplate.creator`. ### M2. `defaultSourceCodePath` — what does "default" mean here? -- **File:** `model.ts:760-762` +- **File:** `model.ts:746-750` - **Category:** Vague/generic (1), Misleading names (6) - **Issue:** Doc says it "tracks the workspace source code path of the last active deployment". So the field is historical, not a default. - **Suggestion:** Rename to `lastActiveDeploymentSourceCodePath` or - `effectiveSourceCodePath`. Same critique for `defaultGitSource`. + `effectiveSourceCodePath`. ### M3. `effective*` fields paired with non-prefixed siblings -- **File:** `model.ts:764-771, 775-776, 1382, 1392` +- **File:** `model.ts:751-754, 757-758, 762-763, 1331, 1341` - **Category:** Duplicate concepts (12) - **Issue:** `App` has paired fields: `budgetPolicyId/effectiveBudgetPolicyId`, `usagePolicyId/effectiveUsagePolicyId`, `userApiScopes/effectiveUserApiScopes`. @@ -256,7 +244,7 @@ Apps is unclear. effective values, or rename to `requestedBudgetPolicyId` / `appliedBudgetPolicyId`. ### M4. `userApiScopes` field name vs OAuth-scope concept -- **File:** `model.ts:767, 770-771, 1380-1382` +- **File:** `model.ts:754, 758, 1329-1331` - **Category:** Vague/generic (1) - **Issue:** `userApiScopes?: string[]`. The doc on `Space.userApiScopes` says "OAuth scopes for apps in the space." The TS field name says "user API @@ -265,7 +253,7 @@ Apps is unclear. protocol clear. ### M5. `command?: string[]` — what kind of command? -- **File:** `model.ts:821-822` +- **File:** `model.ts:800-801` - **Category:** Vague/generic (1) - **Issue:** `AppDeployment.command` is "The command with which to run the app." But it's an array of strings (argv-style); the name doesn't hint at @@ -274,7 +262,7 @@ Apps is unclear. semantics) or `runCommand`. Adding to JSDoc is acceptable as an alternative. ### M6. `EnvVar` — too short -- **File:** `model.ts:1152`, also `index.ts:89` +- **File:** `model.ts:1108`, also `index.ts:85` - **Category:** Cryptic abbreviations (5) - **Issue:** `EnvVar` reads as Go-style. Full TS conventions prefer `EnvironmentVariable` or, since it carries both name and source, more @@ -286,7 +274,7 @@ Apps is unclear. strict 1:1 with Go names, leave as-is. ### M7. `envVars` plural OK but contradicts singular-source pattern -- **File:** `model.ts:824, 1152-1166` +- **File:** `model.ts:803, 1108-1122` - **Category:** Singular/plural mismatches (9) - **Issue:** `AppDeployment.envVars?: EnvVar[]` is plural and correct, but inside each `EnvVar` the `source` field is a `{$case: 'value'; value: string} @@ -298,7 +286,7 @@ Apps is unclear. `valueSource`. Update the discriminator literal `'valueFrom'` accordingly. ### M8. `AppManifest.version: number` carries no unit -- **File:** `model.ts:842` +- **File:** `model.ts:821` - **Category:** Vague/generic (1) - **Issue:** "The manifest schema version, for now only 1 is allowed". Field is a bare `number`; reader has to read the doc to know it's an integer @@ -307,23 +295,23 @@ Apps is unclear. integer. ### M9. `CustomTemplate.gitRepo` vs `GitRepository` type -- **File:** `model.ts:1113-1114, 1120` +- **File:** `model.ts:1069-1070, 1076` - **Category:** Cryptic abbreviations (5), Singular/plural mismatches with type name (9) - **Issue:** `CustomTemplate.gitRepo?: string` (URL string) sits adjacent to the `GitRepository` interface used elsewhere. The abbreviation `gitRepo` is - inconsistent with the full word `gitRepository` used 6 times in the file. + inconsistent with the full word `gitRepository` used elsewhere in the file. - **Suggestion:** Rename to `gitRepositoryUrl` (since the field stores a URL, not an object reference) or align on `gitRepoUrl` package-wide. ### M10. `path` on `CustomTemplate` — path of what, where? -- **File:** `model.ts:1115-1116` +- **File:** `model.ts:1071-1072` - **Category:** Vague/generic (1) - **Issue:** `CustomTemplate.path?: string` — "The path to the template within the Git repository." Bare `path` is too generic for a public field. - **Suggestion:** Rename to `templatePath` or `gitPath`. ### M11. `gitProvider?: string` — should be enum/union -- **File:** `model.ts:1119-1120, 1207-1210` +- **File:** `model.ts:1075-1076, 1163-1166` - **Category:** Vague/generic (1) - **Issue:** `CustomTemplate.gitProvider` and `GitRepository.provider` are free-form strings, but the doc on `GitRepository.provider` enumerates eight @@ -333,38 +321,27 @@ Apps is unclear. or a string-literal union of the documented values. ### M12. `GitRepository.provider` vs `CustomTemplate.gitProvider` — same concept, different name -- **File:** `model.ts:1119, 1210` +- **File:** `model.ts:1076, 1166` - **Category:** Duplicate concepts (12) - **Issue:** The Git provider name is `provider` on `GitRepository` but `gitProvider` on `CustomTemplate`. Two names for the same field. - **Suggestion:** Standardise on `provider` everywhere (since the surrounding type makes the qualifier obvious) or on `gitProvider` (more searchable). -### M13. `callerCredentialId?: number` on `GitRepository` -- **File:** `model.ts:1213-1217` -- **Category:** Underspecified IDs (19) -- **Issue:** `callerCredentialId: number` — a numeric ID with no domain prefix. - "caller" is also a vague qualifier; the doc says it's "a personal access - token Git credential". -- **Suggestion:** Rename to `gitCredentialId` or `callerGitCredentialId`. Note - also: the marshal layer keeps it as a number, but every other ID field in - this package is a string (`servicePrincipalId` is the only other number-ID, - matching Go's int64). Verify the wire type. - -### M14. `appName` field name in `AsyncUpdateAppRequest` carrying a redundant nesting -- **File:** `model.ts:1063-1067` +### M13. `AsyncUpdateAppRequest.appName` carrying a redundant nesting +- **File:** `model.ts:1021-1025` - **Category:** Redundant suffixes (8) - **Issue:** `AsyncUpdateAppRequest` already contains an `app: App` field, and separately an `appName: string` field that's just `req.app.name`. This is visible at `client.ts:125`: `${this.host}/api/2.0/apps/${req.appName ?? ''}` with no consultation of `req.app?.name`. - **Suggestion:** Drop `appName` from `AsyncUpdateAppRequest` and read - `req.app?.name` (as `updateApp` already does at `client.ts:840`). This is a + `req.app?.name` (as `updateApp` already does at `client.ts:828`). This is a semantic change; flag for discussion. Alternative: keep both and document which wins on conflict. -### M15. `UcSecurableType` duplicated across manifest spec and runtime resource -- **File:** `model.ts:598-603, 676-681` +### M14. `UcSecurableType` duplicated across manifest spec and runtime resource +- **File:** `model.ts:586-591, 664-669` - **Category:** Duplicate concepts (12) - **Issue:** Two identical enums (`VOLUME`, `TABLE`, `FUNCTION`, `CONNECTION`) — one for the manifest spec, one for the runtime resource. Same value set, @@ -373,8 +350,8 @@ Apps is unclear. it from both the manifest UC securable spec and the runtime UC securable resource. -### M16. UC securable permission enum on the runtime resource is a strict subset of the manifest-spec enum -- **File:** `model.ts:587-595, 666-673` +### M15. UC securable permission enum on the runtime resource is a strict subset of the manifest-spec enum +- **File:** `model.ts:576-583, 654-661` - **Category:** Duplicate concepts (12) - **Issue:** Spec enum has 7 values (`READ_VOLUME`, `WRITE_VOLUME`, `MANAGE`, `SELECT`, `EXECUTE`, `USE_CONNECTION`, `MODIFY`). Resource enum has 6 — same @@ -384,8 +361,8 @@ Apps is unclear. isn't actually grantable at runtime, document that. Or define two related enums where one is a subset reference (not duplicated). -### M17. `AppDeployment.deploymentId` — `deployment` repeats outer type -- **File:** `model.ts:798-799` +### M16. `AppDeployment.deploymentId` — `deployment` repeats outer type +- **File:** `model.ts:777-778` - **Category:** Type-suffix tautology (20) - **Issue:** Within the `AppDeployment` interface, `deploymentId` repeats the outer name. Inside `AppDeployment` the unqualified `id` would suffice and @@ -393,19 +370,20 @@ Apps is unclear. (correctly unqualified). - **Suggestion:** Rename `AppDeployment.deploymentId` -> `id`. -### M18. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types -- **File:** `model.ts:1015, 769, 1368, 1900` +### M17. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types +- **File:** `model.ts:756, 946, 975, 1316` - **Category:** Underspecified IDs (19) - **Issue:** `AppResourceSqlWarehouse.id` is a SQL warehouse ID, `App.id` is an - App ID, `AppResourceJob.id` is a Job ID. All are bare `id`. JSON output - serializes the same key for very different identifiers. + App ID, `AppResourceJob.id` is a Job ID, `Space.id` is a Space ID. All are + bare `id`. JSON output serializes the same key for very different + identifiers. - **Suggestion:** Either accept the convention (`id` always means "the entity this object describes") or be explicit (`sqlWarehouseId`, `jobId`, - `experimentId`). The package is currently inconsistent — see M17, where the + `experimentId`). The package is currently inconsistent — see M16, where the rename runs the *opposite* direction. -### M19. `UnityCatalog` interface — generic name, no role suffix -- **File:** `model.ts:1434-1441`, also `index.ts:114` +### M18. `UnityCatalog` interface — generic name, no role suffix +- **File:** `model.ts:1383-1390`, also `index.ts:110` - **Category:** Vague/generic (1) - **Issue:** `UnityCatalog` is exported as a public type. The interface has three table-name fields (`logsTable`, `metricsTable`, `tracesTable`) and is @@ -415,11 +393,11 @@ Apps is unclear. - **Suggestion:** Rename to `UnityCatalogTelemetryDestination` or `UnityCatalogTables`. Inline if not reused. -### M20. `Operation.result` carries `error` and `response` arms -- **File:** `model.ts:1343-1354` +### M19. `Operation.result` carries `error` and `response` arms +- **File:** `model.ts:1292-1303` - **Category:** Vague/generic (1) - **Issue:** The `response` arm holds `Record` — a totally - untyped payload. The consumer at `client.ts:1022` immediately re-parses it + untyped payload. The consumer at `client.ts:1010` immediately re-parses it through `unmarshalSpaceSchema`. The name `response` and the unknown type conceal what's actually inside. - **Suggestion:** Use generics: `Operation` with `result: ... | @@ -427,7 +405,7 @@ Apps is unclear. `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name promises nothing. -### M21. `flattenQueryParams` — what does it flatten? +### M20. `flattenQueryParams` — what does it flatten? - **File:** `utils.ts:123` - **Category:** Vague/generic (1) - **Issue:** `flattenQueryParams(prefix, value, params)` — the function @@ -436,7 +414,7 @@ Apps is unclear. - **Suggestion:** Rename to `encodeNestedQueryParams` or `appendObjectAsQueryParams`. -### M22. `readAll` — local helper exported as `readAll` +### M21. `readAll` — local helper exported as `readAll` - **File:** `utils.ts:40` - **Category:** Vague/generic (1) - **Issue:** `readAll(body: ReadableStream | null)` — reads-all of @@ -444,7 +422,7 @@ Apps is unclear. - **Suggestion:** Rename to `readStreamToBytes` or `consumeStream`. (It's not exported, so impact is local.) -### M23. `executeCall` vs `executeHttpCall` — pair drifts in meaning +### M22. `executeCall` vs `executeHttpCall` — pair drifts in meaning - **File:** `utils.ts:26, 65` - **Category:** Inconsistent action verbs (17) - **Issue:** `executeCall` is the *outer* retry/rate-limit wrapper; @@ -454,7 +432,7 @@ Apps is unclear. would help. - **Suggestion:** Rename to `runWithRetries`/`sendHttp`, or `runCall`/`sendOne`. -### M24. `StillRunningError` — internal sentinel class, named ambiguously +### M23. `StillRunningError` — internal sentinel class, named ambiguously - **File:** `client.ts:93` - **Category:** Misleading names (6) - **Issue:** `class StillRunningError extends Error {}` — used as a sentinel @@ -463,8 +441,8 @@ Apps is unclear. - **Suggestion:** Rename to `pollAgainSentinel` (as a typed Error subclass) or `RetryablePollError`, and add a comment that it never escapes the file. -### M25. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too -- **File:** `client.ts:121, 914` +### M24. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +- **File:** `client.ts:121, 902` - **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) - **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, long-running operations that return an `AppUpdate`/`Operation` and have a @@ -474,8 +452,8 @@ Apps is unclear. - **Suggestion:** Drop the `async` prefix from `asyncUpdateApp` to match `updateSpace`, or add `asyncUpdateSpace` for symmetry. -### M26. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type -- **File:** `client.ts:309, 408, 951` +### M25. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +- **File:** `client.ts:297, 396, 939` - **Category:** Type-suffix tautology (20) - **Issue:** Methods named `createSpaceOperation()` return a `CreateSpaceOperation` wrapper (not an `Operation` directly). A reader @@ -490,57 +468,57 @@ Apps is unclear. ## Low-severity findings ### L1. `AppDeployment.mode` doc: "The mode of which the deployment will manage the source code." -- **File:** `model.ts:809` +- **File:** `model.ts:788` - **Category:** Grammar / clarity (not in numbered categories but flagged) - **Suggestion:** "of which" should be "in which" or "by which". A nit, not a rename, but flagged because it appears in the public API docs. ### L2. `App.creator` and `App.updater` — `updater` is a real English word but commonly used for libraries/tools -- **File:** `model.ts:746-748` +- **File:** `model.ts:732, 736` - **Category:** Misleading names (6) - **Issue:** Outside of CRUD-stamp contexts, "updater" often denotes a software-update agent (e.g. Sparkle). Pair with M1 — both should become `*Email` if that's the value type. ### L3. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` -- **File:** `model.ts:743-748` +- **File:** `model.ts:731-736` - **Category:** Field contradicting type domain (16) - **Suggestion:** No type change available short of a branded type; document the format in JSDoc. ### L4. `App.url` doc: "URL of the app once it is deployed" -- **File:** `model.ts:734-735` +- **File:** `model.ts:722-723` - **Category:** Misleading names (6) - **Suggestion:** Rename `App.url` -> `App.appUrl` or `App.deploymentUrl` for clarity, especially because `GitRepository.url` is also called `url` in the same file. (Currently both are bare `url`.) ### L5. `GitRepository.url` — same generic `url` as `App.url` -- **File:** `model.ts:1205` +- **File:** `model.ts:1161` - **Category:** Generic field names (15) - **Suggestion:** Rename to `repositoryUrl` (mirror with `GitRepository.provider` named more specifically). ### L6. `GitSource.resolvedCommit` — does it carry SHA or ref? -- **File:** `model.ts:1248-1253` +- **File:** `model.ts:1196-1202` - **Category:** Vague/generic (1) - **Suggestion:** Rename to `resolvedCommitSha` to match the doc, which says "the resolved commit SHA". ### L7. `GitSource.sourceCodePath` — verbose -- **File:** `model.ts:1242-1246` +- **File:** `model.ts:1191-1195` - **Category:** Overly verbose (7) - **Suggestion:** Inside `GitSource`, simply `path` would be unambiguous (the whole interface is about source location). ### L8. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" -- **File:** `model.ts:894-895` +- **File:** `model.ts:856` - **Category:** Doc / clarity - **Suggestion:** Drop or rephrase the reference to `app.proto`; in TS the reference is meaningless. ### L9. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers -- **File:** `model.ts:3131, 3211` +- **File:** `model.ts:2939, 3016` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — no `appDeploymentFieldMask`, despite the `AppDeployment` having an internal @@ -549,21 +527,21 @@ Apps is unclear. schema, or none. ### L10. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models -- **File:** `model.ts:783-784, 1032-1035` +- **File:** `model.ts:771, 994` - **Category:** Duplicate concepts (12) - **Suggestion:** Document that `thumbnailUrl` is the display URL and `AppThumbnail.thumbnail` is the byte content (used in update/delete-thumbnail requests). ### L11. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` -- **File:** `model.ts:1156-1166` +- **File:** `model.ts:1111-1122` - **Category:** Vague/generic (1) - **Suggestion:** Discriminator `'value'` and `'valueFrom'` are short; consider `'literal'` and `'reference'` to make intent clearer. (Wire field names unchanged.) ### L12. `Space` interface — same name as the Genie product `AppResourceGenieSpace` -- **File:** `model.ts:1357, 978-982` +- **File:** `model.ts:938, 1306` - **Category:** Duplicate concepts (12) - **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share the "space" noun and both have a `spaceId` field. They are unrelated @@ -576,33 +554,17 @@ Apps is unclear. ### L13. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, `ListSpacesRequest`, etc., do not mention "App" -- **File:** `model.ts:1101, 1147, 1197, 1301`, also `index.ts:82-88, 105` +- **File:** `model.ts:1057, 1103, 1153, 1250`, also `index.ts:78, 84, 91, 100` - **Category:** Vague/generic (1) - **Suggestion:** Tied to L12 — rename these to `CreateAppSpaceRequest`, etc. ### L14. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? -- **File:** `model.ts:1308-1312, 1282-1286` +- **File:** `model.ts:1232, 1258` - **Category:** Observation — both follow the same pattern. Tied to L12 again for the entity rename. -### L15. `CreateAppDeploymentRequest.autoDeploy` doc: "Whether to enable automatic deployments on push events to the git repository" -- **File:** `model.ts:1086-1089` -- **Category:** Misleading names (6) -- **Issue:** The field name suggests "deploy automatically now". The doc says - it sets up a webhook. These are very different ideas. -- **Suggestion:** Rename to `enableAutoDeploy` or `webhookAutoDeploy`. - -### L16. `GitRepository.autoDeploy` vs `CreateAppDeploymentRequest.autoDeploy` -- **File:** `model.ts:1086, 1211` -- **Category:** Duplicate concepts (12) -- **Issue:** Two `autoDeploy` fields in the same file: one on the deployment - request, one on the repository. They probably express the same setting at - different layers, but neither says so. -- **Suggestion:** Document the relationship in JSDoc; if they're the same - state, only one should exist. - -### L17. `Operation.name` — server-assigned UNIQUE name, not human-readable -- **File:** `model.ts:1319-1324` +### L15. `Operation.name` — server-assigned UNIQUE name, not human-readable +- **File:** `model.ts:1267-1273` - **Category:** Misleading names (6) - **Issue:** `Operation.name` is the operation *identifier* path (`operations/{unique_id}`) — distinct from `App.name` (the App entity's @@ -610,7 +572,7 @@ Apps is unclear. package. - **Suggestion:** Rename to `operationName` or, given the format, just `path`. -### L18. `Client` class — exported as bare `Client` +### L16. `Client` class — exported as bare `Client` - **File:** `client.ts:95`, also `index.ts:4` - **Category:** Vague/generic (1) - **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the @@ -618,7 +580,7 @@ Apps is unclear. `@databricks/sdk-jobs`, they need an alias. - **Suggestion:** Rename to `AppsClient`. Common SDK convention. -### L19. `host` (private field on `Client`) +### L17. `host` (private field on `Client`) - **File:** `client.ts:96` - **Category:** Vague/generic (1) - **Issue:** `private readonly host: string`. The doc on the workspace @@ -626,8 +588,8 @@ Apps is unclear. - **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, cosmetic. -### L20. `getSpaceOperation` (method) vs `GetOperationRequest` -- **File:** `client.ts:536-558` +### L18. `getSpaceOperation` (method) vs `GetOperationRequest` +- **File:** `client.ts:524-546` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells you it's a space operation, but the request type doesn't. Mismatch. @@ -671,24 +633,20 @@ Consider `AppTemplate` or `CustomAppTemplate`. ### O6. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter Asymmetry but probably intentional. -### O7. `ApplicationStatus.runningInstances` vs `ComputeStatus.activeInstances` -Two related counts, different verbs. `runningInstances` for app process, -`activeInstances` for compute resources. Document the distinction. +### O7. `ListAppsRequest.space` filters by space name (string), not by +`Space` object — consistent with H4 issue. -### O8. `ListAppsRequest.space` filters by space name (string), not by -`Space` object — consistent with H5 issue. - -### O9. The package re-exports the `apierr` enum locally -Per H3, this enum should live in `@databricks/sdk-databricks/apierror/codes`. +### O8. The package re-exports the `apierr` enum locally +Per H2, this enum should live in `@databricks/sdk-databricks/apierror/codes`. The project memory note already calls this out (`packages/databricks/src/apierror/codes/`). -### O10. `index.ts` exports -- 18 enums -- 51 type aliases +### O9. `index.ts` exports +- 26 enums +- 71 type aliases - 8 named exports from `./client` (1 class + 7 wrapper classes) -That's 77 top-level exports. Worth checking whether the wrapper classes +That's 105 top-level exports. Worth checking whether the wrapper classes (`*Operation`, `*Waiter`) need to be public or if they're implementation detail. @@ -706,9 +664,9 @@ detail. | `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L12. | | `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L12. | | `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | -| `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H4. | +| `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H3. | | `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | -| `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M15/M16. | +| `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M14/M15. | | `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L10. | | `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M6. | | `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | @@ -720,9 +678,19 @@ detail. | File | Lines read | Coverage | | ---- | ---------- | -------- | -| `src/v1/index.ts` | 120 / 120 | 100% | +| `src/v1/index.ts` | 116 / 116 | 100% | | `src/v1/utils.ts` | 151 / 151 | 100% | -| `src/v1/model.ts` | 3219 / 3219 | 100% | -| `src/v1/client.ts` | 1615 / 1615 | 100% | +| `src/v1/model.ts` | 3023 / 3023 | 100% | +| `src/v1/client.ts` | 1602 / 1602 | 100% | All types, fields, enum values, and methods reviewed. + +--- + +## Fixed + +- #M13 `callerCredentialId` (originally cited at `model.ts:1213-1217`): Fixed in regeneration on 2026-05-20 — the `GitRepository` interface no longer carries a `callerCredentialId` field. +- #H9 `defaultGitSource` / `deploymentSource` arms (originally cited at `model.ts:760-763, 786-794`): Fixed in regeneration on 2026-05-20 — `App.defaultGitSource` and the `deploymentSource` discriminated union are gone; finding rewritten to cover the remaining two-way overlap between `defaultSourceCodePath` and `gitRepository`. +- #L15 `CreateAppDeploymentRequest.autoDeploy` (originally cited at `model.ts:1086-1089`): Fixed in regeneration on 2026-05-20 — `autoDeploy` is no longer a field on `CreateAppDeploymentRequest`. +- #L16 `GitRepository.autoDeploy` (originally cited at `model.ts:1086, 1211`): Fixed in regeneration on 2026-05-20 — `GitRepository.autoDeploy` is no longer present. +- #O7 `ApplicationStatus.runningInstances` vs `ComputeStatus.activeInstances` (originally cited at `model.ts:?`): Fixed in regeneration on 2026-05-20 — `runningInstances` no longer exists on `ApplicationStatus`. diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index a5cde6e2..58da0aa9 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -2,7 +2,7 @@ Package path: `/home/parth.bansal/sdk-js/packages/artifactallowlists/` Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, -`src/v1/index.ts`. +`src/v1/transport.ts`, `src/v1/index.ts`. Notation: file paths are absolute. Findings reference `file:line`. @@ -10,24 +10,20 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | -| High | 2 | -| Medium | 5 | -| Low | 3 | -| Observation | 4 | -| **Total** | **14** | +| High | 1 | +| Medium | 6 | +| Low | 5 | +| Observation | 3 | +| **Total** | **15** | Headline themes: -1. **Request types lack a `Request` suffix** (e.g. `GetArtifactAllowlist`, - `SetArtifactAllowlist`). They are imperative phrases that read like - operations, not data shapes — and `GetArtifactAllowlist` collides - semantically with the `getArtifactAllowlist` method on `Client`. This is a - codebase-wide convention question rather than a defect local to this - package; `accountsettings` and others use the `…Request` suffix while - `catalogs`, `connections`, `clusters`, etc. omit it. -2. **Redundant `Info` suffix on `ArtifactAllowlistInfo`** is the canonical +1. **Redundant `Info` suffix on `ArtifactAllowlistInfo`** is the canonical payload type for both `Get` and `Set` responses; the suffix adds no information beyond "this is a struct." +2. **Server-derived fields leak onto a request type** — + `SetArtifactAllowlistRequest` exposes `createdBy` / `createdAt`, which are + response-only metadata. Allowlist casing is **consistent** throughout the package (always `Allowlist`, never `AllowList` or `Whitelist`). @@ -36,33 +32,20 @@ Allowlist casing is **consistent** throughout the package (always ## High Severity -### H1. `GetArtifactAllowlist` collides with the client method of the same name - -- **File / line:** `src/v1/model.ts:39`; cross-ref `src/v1/client.ts:66`. -- **Category:** #6 misleading name; #20 type-suffix tautology (inverse — - missing suffix). -- **Current:** `interface GetArtifactAllowlist { artifactType?: ArtifactType }`. -- **Suggestion:** `GetArtifactAllowlistRequest`. -- **Rationale:** `GetArtifactAllowlist` reads as an action / operation name. - TypeScript users who see `client.getArtifactAllowlist(req: GetArtifactAllowlist)` - must mentally distinguish a verb-phrase function from a verb-phrase type. - Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use - the `…Request` suffix; adopting that here removes the verb/noun overload. - -### H2. `SetArtifactAllowlist` carries server-derived fields on a request type +### H1. `SetArtifactAllowlistRequest` carries server-derived fields on a request type - **File / line:** `src/v1/model.ts:44–55`. -- **Category:** #6 misleading name; #16 field contradicting type domain. +- **Category:** #16 field contradicting type domain. - **Current:** Fields `createdBy?: string` and `createdAt?: number` are present on what is documented as the SET payload — these are server-set timestamps/identities and are also present on `ArtifactAllowlistInfo`. -- **Suggestion:** Either rename to `SetArtifactAllowlistRequest` and remove - `createdBy` / `createdAt` (they are response-only), or — if the underlying - API truly accepts them — clarify in the doc that the server ignores them. -- **Rationale:** A request type whose name reads as a verb ("Set the - allowlist") but whose fields include response-only metadata is misleading. - Even if the server tolerates them, exposing them on the request shape - invites misuse. +- **Suggestion:** Remove `createdBy` / `createdAt` from + `SetArtifactAllowlistRequest` (they are response-only), or — if the + underlying API truly accepts them — clarify in the doc that the server + ignores them. +- **Rationale:** A request type whose fields include response-only metadata + is misleading. Even if the server tolerates them, exposing them on the + request shape invites misuse. --- @@ -83,7 +66,7 @@ Allowlist casing is **consistent** throughout the package (always (today, the package has no type with that bare name, even though it is literally the "artifact allowlists" package). -### M2. `GetArtifactAllowlist` / `SetArtifactAllowlist` use inconsistent +### M2. `GetArtifactAllowlistRequest` / `SetArtifactAllowlistRequest` use inconsistent verbs vs. UC sibling APIs - **File / line:** `src/v1/model.ts:39, 44`; `client.ts:66, 96`. @@ -133,7 +116,7 @@ type that is itself a noun-from-verb - **File / line:** `src/v1/client.ts:67, 97`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. -- **Current:** `req: GetArtifactAllowlist`. +- **Current:** `req: GetArtifactAllowlistRequest`. - **Suggestion:** `request` (matches Go-port readability without saving characters that matter in TypeScript). - **Rationale:** Throughout the JS/TS ecosystem, function parameters tend @@ -142,6 +125,23 @@ type that is itself a noun-from-verb it reads as Go-translated code. (Note: `resp` shows up locally in the same file at lines 71, 84, 102, 115 — a separate, lower-priority issue.) +### M6. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak + +- **File / line:** `src/v1/model.ts:15`. +- **Category:** proto-architectural-leak — `Proto` infix / nested-enum + underscore. +- **Current:** `ArtifactMatcher_MatchType` (with an inline + `eslint-disable` comment that literally documents the leak: "Proto-style + nested enum name"). +- **Suggestion:** `ArtifactMatchType` or `MatchType` exported at module + level. If the parent-child relationship must be preserved, namespace via + module structure or interface nesting rather than identifier underscores. +- **Rationale:** The `Parent_Child` separator is a protobuf-generated + artifact for nested types; TypeScript has no equivalent convention and + the codebase already disables its own naming-convention lint rule to let + this through. The identifier leaks the proto/IDL layer into the public + surface of the package. + --- ## Low Severity @@ -176,7 +176,7 @@ type that is itself a noun-from-verb ### L3. `body` shadowed across helpers in `executeHttpCall` -- **File / line:** `src/v1/utils.ts:81`, `buildHttpRequest` (line 101), +- **File / line:** `src/v1/utils.ts:81`, `buildHttpRequest` (line 96), `parseResponse` (line 113). - **Category:** #1 vague generic name. - **Current:** `body: Uint8Array` (response body) vs. `body: string | @@ -186,24 +186,52 @@ type that is itself a noun-from-verb function that internally also reasons about response bodies. Differentiating with `requestBody` / `responseBody` would help readers. +### L4. `AuthHttpClient` — architectural-layer wrapper class name + +- **File / line:** `src/v1/transport.ts:43`. +- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` pattern + exposed; architectural mid-token `Http`. +- **Current:** `class AuthHttpClient implements HttpClient` — the JSDoc + on line 42 reads "Wraps an HttpClient and adds authentication headers + to requests," explicitly admitting wrapper semantics. +- **Suggestion:** Internalize the wrapper (e.g., a `withAuth(client, + credentials)` factory that returns an `HttpClient`), or name the class + after what it produces (`AuthenticatedTransport`) rather than the + architectural layering. If kept, drop `Http` and align with the + domain — `AuthenticatingClient` reads as the role. +- **Rationale:** `AuthHttpClient` reads as `Auth` + `Http` + `Client`, + three architectural tokens stacked. The `Http` infix in particular adds + no information beyond what `HttpClient` (the implemented interface) + already conveys. Wrapper class names that stack adjective + transport + layer + role are a known leak of internal layering into identifiers. + +### L5. `TimeoutHttpClient` — second instance of the same wrapper-naming pattern + +- **File / line:** `src/v1/transport.ts:61`. +- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` pattern; + architectural mid-token `Http`. +- **Current:** `class TimeoutHttpClient implements HttpClient` (JSDoc: + "Wraps an HttpClient and applies a default timeout to requests"). +- **Suggestion:** Same treatment as L4 — a `withTimeout(client, ms)` + factory, or rename to `TimeoutTransport` / `TimeoutClient` to drop the + architectural `Http` infix. +- **Rationale:** Same naming anti-pattern as L4 repeated. Together, + `AuthHttpClient` + `TimeoutHttpClient` form a small decorator chain + whose class names advertise the chain layout rather than the behaviour + delivered. The cluster suggests a generator template rather than a + package-local choice. + --- ## Observations (Repo-wide conventions, not local defects) -### O1. Bare `GetX`/`SetX` request shapes are a repo-wide pattern - -Sibling packages `catalogs`, `connections`, `clusters`, `externallocations`, -`clusterpolicies` all use bare verb-phrases for request types. See evidence -in `grep -rE "^export interface (Get|Set|Create|Update|Delete)…"` across -the workspace. Changing this package alone would create asymmetry. - -### O2. `…Info` suffix repeated across UC types +### O1. `…Info` suffix repeated across UC types `ArtifactAllowlistInfo` follows the `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the codebase decides to drop the `Info` suffix, this is one of many to fix. -### O3. Allowlist terminology / casing is consistent +### O2. Allowlist terminology / casing is consistent `Allowlist` (single uppercase A, then lowercase `llowlist`) is used in every position in this package: type names, methods, schemas, comments, @@ -211,7 +239,7 @@ URL paths (`/artifact-allowlists/`), and the package name `@databricks/sdk-artifactallowlists`. No `AllowList`, `Allow_list`, or `Whitelist` anywhere. **Passes** the audit on this criterion. -### O4. URL path constant is inlined +### O3. URL path constant is inlined The string `/api/2.1/unity-catalog/artifact-allowlists/${artifactType}` appears twice (`client.ts:70` and `client.ts:100`) without a named @@ -238,27 +266,48 @@ constant. Not a naming defect, but typical naming-audit findings include | File | Lines | Audited | | -------------- | ----- | ------------------------------------------------ | -| `src/v1/model.ts` | 111 | All 4 types + 2 enums + 3 schemas + every field. | -| `src/v1/client.ts` | 121 | Class, constructor, 2 methods, all locals. | -| `src/v1/utils.ts` | 151 | All 7 exported / private functions and types. | -| `src/v1/index.ts` | 13 | All re-exports. | +| `src/v1/model.ts` | 111 | All 4 types + 2 enums + 3 schemas + every field. | +| `src/v1/client.ts` | 121 | Class, constructor, 2 methods, all locals. | +| `src/v1/utils.ts` | 151 | All 7 exported / private functions and types. | +| `src/v1/transport.ts` | 76 | `newHttpClient` factory + 2 wrapper classes. | +| `src/v1/index.ts` | 13 | All re-exports. | Type & symbol checklist: - [x] `ArtifactType` enum (4 members) → no defect. -- [x] `ArtifactMatcher_MatchType` enum (2 members) → no defect. -- [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O2. +- [x] `ArtifactMatcher_MatchType` enum (2 members) → M6. +- [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O1. - [x] `ArtifactMatcher` interface (2 fields) → M3, M4. -- [x] `GetArtifactAllowlist` interface (1 field) → H1, O1. -- [x] `SetArtifactAllowlist` interface (5 fields) → H2, O1. +- [x] `GetArtifactAllowlistRequest` interface (1 field) → no defect. +- [x] `SetArtifactAllowlistRequest` interface (5 fields) → H1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → no defect. -- [x] `getArtifactAllowlist(req, options)` method → H1, M2, M5. -- [x] `setArtifactAllowlist(req, options)` method → H1, M2, M5. +- [x] `getArtifactAllowlist(req, options)` method → M2, M5. +- [x] `setArtifactAllowlist(req, options)` method → M2, M5. - [x] `HttpCallOptions` interface → no defect. - [x] `executeCall` function → L1. - [x] `readAll` private function → no defect (name fits idiom). - [x] `executeHttpCall` function → L1, L3. - [x] `buildHttpRequest` function → L3. - [x] `flattenQueryParams` function → no defect. +- [x] `newHttpClient` factory (`transport.ts`) → no defect. +- [x] `AuthHttpClient` class (`transport.ts`) → L4. +- [x] `TimeoutHttpClient` class (`transport.ts`) → L5. - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). + +--- + +## Fixed + +- #H1 `GetArtifactAllowlist` (originally cited at `src/v1/model.ts:39`): + Fixed in regeneration on 2026-05-20 — renamed to + `GetArtifactAllowlistRequest`; verb/noun overload with the client method + resolved. +- #H2 partial — `SetArtifactAllowlist` (originally cited at + `src/v1/model.ts:44–55`): Fixed in regeneration on 2026-05-20 — renamed to + `SetArtifactAllowlistRequest`. The response-only-fields concern was split + off into the new H1 above and remains open. +- #O1 Bare `GetX`/`SetX` request shapes (originally cited as a repo-wide + pattern across `catalogs`, `connections`, `clusters`, `externallocations`, + `clusterpolicies`): Fixed in regeneration on 2026-05-20 — `Request` + suffix is now applied across the generator. diff --git a/.agent/naming-audit/authentication.md b/.agent/naming-audit/authentication.md new file mode 100644 index 00000000..c3aeb7ce --- /dev/null +++ b/.agent/naming-audit/authentication.md @@ -0,0 +1,146 @@ +# Naming Audit: authentication + +**Path:** `packages/authentication/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Inferred domain:** Account-level CRUD over OAuth client secrets attached to +a service principal (create, list, delete). The previous +`serviceprincipalsecretsproxy` package was merged in, so both the +non-proxy and proxy RPC variants now live under one client. +**Total weird names flagged:** 4 + +## Summary table + +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 3 | +| Low | 0 | +| Observation | 0 | +| **Total** | **4** | + +The audit is narrowly scoped to proto/architectural leaks. The +package exposes only one resource (`ServicePrincipalSecret`), so the +findings cluster around two themes: (1) a duplicate +`` / `Proxy` API surface that mirrors the proto's +proxy-vs-non-proxy RPC routing distinction, and (2) the proto +`Request_Response` underscore-nested message name leaking into TS as +the empty `DeleteServicePrincipalSecretRequest_Response` and the +populated `ListServicePrincipalSecretsRequest_Response`. + +--- + +## High severity (must fix) + +### 1. `*Proxy` method variants duplicate the entire API surface — `client.ts:491, 551, 633, 669` +- **Why:** The class exposes three real operations + (`createServicePrincipalSecret`, `deleteServicePrincipalSecret`, + `listServicePrincipalSecrets`) and, for every one of them, a + byte-identical `*Proxy` clone (`createServicePrincipalSecretProxy`, + `deleteServicePrincipalSecretProxy`, + `listServicePrincipalSecretsProxy`, + `listServicePrincipalSecretsProxyIter`). The URL, request type, + response type, headers, and pagination loop are character-for-character + the same as the non-proxy form. The `Proxy` suffix is a leak of the + proto/Go RPC routing distinction (gateway-proxied vs direct) and + carries no observable semantic difference at the TS surface. +- **Category:** Proto-architecture leak (`Proxy` mid/suffix not real) +- **Suggested:** Collapse each pair into a single method + (`createServicePrincipalSecret`, `deleteServicePrincipalSecret`, + `listServicePrincipalSecrets`, `listServicePrincipalSecretsIter`). + The proxy-vs-non-proxy route choice belongs in the transport layer + (or a `ClientOptions` flag), not in the public method name. +- **Rationale:** `Proxy` here is a routing detail of the Databricks + identity gateway, not a behaviour the caller cares about. Carrying + the duplicate on the public client doubles autocomplete clutter for + a three-operation surface and forces every consumer to pick between + two methods that do the same thing. + +--- + +## Medium severity (worth pushing back on) + +### 1. `DeleteServicePrincipalSecretRequest_Response` — proto-style `Request_Response` nesting on the public type — `model.ts:90` +- **Why:** The empty interface + `DeleteServicePrincipalSecretRequest_Response` is exported (and + re-exported from `index.ts:15`) using the proto-nested + `_` underscore convention. It is the only place in + the TS surface where a delete operation returns a nested empty + message; the underscore identifier exists purely because the proto + schema modelled the response as a nested message inside the request + type. +- **Category:** Proto-architecture leak (`Request_Response` infix + underscore from proto nesting) +- **Suggested:** Either drop the empty response type and have + `deleteServicePrincipalSecret` return `Promise`, or expose + the type as `DeleteServicePrincipalSecretResponse` (sibling-cased, + no underscore) for symmetry with + `CreateServicePrincipalSecretResponse`. +- **Rationale:** No consumer writes a value of this type — the body + is empty. The underscored identifier requires an eslint disable + comment to compile and forces callers reading types to learn proto + message-nesting rules. + +### 2. `ListServicePrincipalSecretsRequest_Response` — proto-style `Request_Response` nesting on the public type — `model.ts:173` +- **Why:** Same shape as finding M1: the response is exported through + `index.ts:23` as `ListServicePrincipalSecretsRequest_Response` + because the proto schema modelled it as a nested message inside the + request. Unlike M1, this one carries fields (`secrets`, + `nextPageToken`) and is actually consumed, so the underscore name + is visible at every call site. +- **Category:** Proto-architecture leak (`Request_Response` infix + underscore from proto nesting) +- **Suggested:** Rename to `ListServicePrincipalSecretsResponse` to + match the existing `CreateServicePrincipalSecretResponse` + convention used in the same file. +- **Rationale:** The sibling `CreateServicePrincipalSecretResponse` + is already named with the unnested form, so the package is + internally inconsistent: of three operations, only `create` gets a + clean response name. Aligning the two list/delete responses + removes the eslint disable and makes the type discoverable without + understanding the proto layout. + +### 3. `Client` methods returning the underscored response types — `client.ts:526, 554, 582, 636` +- **Why:** Four public method signatures bake the proto-nested + `*Request_Response` identifier into their return types + (`Promise`, + `Promise`). The + underscore identifier propagates from `model.ts` into the client + contract and surfaces in hover tooltips and generated docs for + every method. +- **Category:** Proto-architecture leak (`Request_Response` infix + underscore from proto nesting) +- **Suggested:** Resolves automatically once the underlying types + are renamed per medium findings M1 and M2. +- **Rationale:** The leak is observable on the most public surface + (method signatures), not just an internal type alias. + +--- + +## Low severity (nits) + +_None._ + +--- + +## Observations (not flags) + +_None._ + +--- + +## File coverage + +| File | Lines read | Coverage | +| ---- | ---------- | -------- | +| `src/v1/index.ts` | 28 / 28 | 100% | +| `src/v1/transport.ts` | 75 / 75 | 100% | +| `src/v1/utils.ts` | 150 / 150 | 100% | +| `src/v1/model.ts` | 502 / 502 | 100% | +| `src/v1/client.ts` | 688 / 688 | 100% | + +All types, fields, and methods reviewed for proto-architectural leaks +(`Proxy` suffix; `Request_Response` proto-nested underscore +identifiers). Standard suffixes at end (e.g. `*Request`, `*Response`, +`*Schema`), real-domain prefixes (e.g. `ServicePrincipal*`), and +`OAuth*` lexicon are not flagged. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index adc1e6f8..9df9b1d0 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,55 +3,49 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 30 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | -| High | 7 | -| Medium | 10 | -| Low | 8 | +| High | 6 | +| Medium | 11 | +| Low | 7 | | Observation | 5 | ## High severity -### 1. `SortSpec_Field.FIELD_UNSPECIFIED` sentinel — `src/v1/model.ts:10` -- **Why weird:** A `FIELD_UNSPECIFIED` sentinel value alongside the field already being declared optional (`field?: SortSpec_Field | undefined`). Idiomatic TS uses `undefined` for "unspecified". -- **Category:** 2 (redundant enum prefix re-stating the enum name `Field`). -- **Suggested name:** Drop the `FIELD_UNSPECIFIED` value and rely on `field?: ... | undefined`. -- **Rationale:** Optional + `undefined` already expresses "unspecified" in TS; a `FIELD_UNSPECIFIED` literal forces every caller to handle two "no choice" states (`undefined` and the sentinel string). - -### 2. `Filter` (bare top-level type) — `src/v1/model.ts:77` +### 1. `Filter` (bare top-level type) — `src/v1/model.ts:75` - **Why weird:** Re-exported from `index.ts` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (Array#filter, RxJS filter, content filters, etc.) and the type is package-scoped — but the re-export under this name collides with the same bare `Filter` in `packages/usagepolicy/src/v1/model.ts:81` and any user who imports both with `Filter` will hit a name clash. - **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). - **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). - **Rationale:** A bare `Filter` provides zero discoverability and the package directly forces a collision with `usagepolicy.Filter`. Both packages target the same account-level surface and a consumer will frequently import both. -### 3. `CreateBudgetPolicyRequest.requestId` documented as idempotency key — `src/v1/model.ts:42` +### 2. `CreateBudgetPolicyRequest.requestId` documented as idempotency key — `src/v1/model.ts:40` - **Why weird:** JSDoc: "This request is only idempotent if a `request_id` is provided." — wire-name leak (`request_id`) in the docs of the TS field `requestId`. Also, `requestId` is a generic field name that does not signal "idempotency key" to callers; the JSDoc is the only place that mentions idempotency. - **Category:** 1 (vague — `requestId` could mean anything: trace id, correlation id, idempotency key), 15 (generic field name losing meaning). - **Suggested name:** `idempotencyKey` (matches the conventional name used by Stripe, Square, and most REST APIs), and fix the JSDoc to use TS field name `requestId` rather than wire name `request_id`. - **Rationale:** A user reading the field name should know it controls idempotency. The current name + docstring split forces a doc-read for every caller. -### 4. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:118-123` +### 3. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:116-121` - **Why weird:** Docstring says: "A page token, received from a previous `ListServerlessPolicies` call ... When paginating, all other parameters provided to `ListServerlessPoliciesRequest` must match the call that provided the page token." — refers to an entirely different RPC name (`ListServerlessPolicies`) that does not exist in this SDK. The actual method is `listBudgetPolicies`. - **Category:** 6 (misleading — docs describe a different operation), 14 (Go-style internal proto name leaked). - **Suggested name:** Fix docstring to say `ListBudgetPolicies`/`ListBudgetPoliciesRequest`. - **Rationale:** Generator bug. Confusing for readers and grep-hostile (searching for `ListBudgetPolicies` won't surface the doc context). -### 5. `BudgetPolicy.policyId` / `BudgetPolicy.policyName` field naming inside `BudgetPolicy` type — `src/v1/model.ts:18,25` +### 4. `BudgetPolicy.policyId` / `BudgetPolicy.policyName` field naming inside `BudgetPolicy` type — `src/v1/model.ts:16,23` - **Why weird:** Fields on the `BudgetPolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. - **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `BudgetPolicy.id` is `policyId`). - **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). - **Rationale:** `budgetPolicy.id` reads better than `budgetPolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. -### 6. `BudgetPolicy.bindingWorkspaceIds` — `src/v1/model.ts:32` +### 5. `BudgetPolicy.bindingWorkspaceIds` — `src/v1/model.ts:30` - **Why weird:** `binding` as a noun-prefix is unusual; reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this budget policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). - **Category:** 1 (vague — `binding` is a generic noun: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists, but the field is just a list of workspace IDs). - **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. - **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. -### 7. Type-name collision with `budgets` package — `src/v1/model.ts:16` vs `packages/budgets/src/v1/model.ts:50` +### 6. Type-name collision with `budgets` package — `src/v1/model.ts:14` vs `packages/budgets/src/v1/model.ts:50` - **Why weird:** This package's central entity is `BudgetPolicy`; the sibling `budgets` package exports `BudgetConfiguration` (the spend-alert budget object). The two are semantically unrelated — `BudgetPolicy` is a tag-attachment policy that influences cost attribution, and `BudgetConfiguration` is a spend threshold + alert. A user importing both packages sees `BudgetPolicy` and `BudgetConfiguration` side by side and may reasonably wonder if `BudgetPolicy` is the policy *for* a `BudgetConfiguration`. The names do not differentiate clearly. - **Category:** 12 (duplicate concepts with confusing names), 1 (the `Budget` prefix overloads two unrelated domain ideas). - **Suggested name:** Consider `CostAttributionPolicy` or `UsageTaggingPolicy` for what `budgetpolicy` actually models (per the JSDoc on `BudgetPolicy`: "Contains the BudgetPolicy details" — tags + workspace bindings, no spend or threshold concept anywhere). @@ -59,111 +53,111 @@ ## Medium severity -### 8. `CustomPolicyTag` type name — `src/v1/model.ts:53` +### 7. `CustomPolicyTag` type name — `src/v1/model.ts:51` - **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. - **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location). - **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. - **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". -### 9. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:57-58` +### 8. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. - **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. -### 10. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:82,87,92` +### 9. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:80,85,90` - **Why weird:** `Filter` has three optional fields whose names imply they specify *one* policy, but the JSDoc says they apply as substring/equality filters across the list. Names like `policyName: 'foo'` read as "the policy named foo"; what it actually means is "policies whose name contains 'foo'". The JSDoc clarifies but the name misleads. - **Category:** 6 (misleading — singular noun for a substring/multi-match filter). - **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to `creatorUserNames: string[]`). - **Rationale:** Filter DSLs benefit from explicit operators. Bare names suggest exact match. -### 11. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:87,92` +### 10. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:85,90` - **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number` (a JS-unsafe representation for 64-bit IDs — but at least the Go SDK numeric type is `int64` here), while `creatorUserName` is `string`. - **Category:** 12 (duplicate concept — two ways to filter on the same domain object), 19 (underspecified ID — `creatorUserId` is a numeric id from an unknown id space). - **Suggested name:** Collapse to `creator?: Creator` with `{id?: number; name?: string}`, or document AND/OR. - **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine. Even the JSDoc says "If unspecified, all policies will be returned" on each one — but doesn't say what happens if both are set. -### 12. `Filter.creatorUserId: number` representation — `src/v1/model.ts:87` -- **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 32). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. +### 11. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` +- **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 30). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 32 and `Filter.creatorUserId` here. +- **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 30 and `Filter.creatorUserId` here. -### 13. `SortSpec` type — `src/v1/model.ts:149` +### 12. `SortSpec` type — `src/v1/model.ts:147` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 14. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:150` +### 13. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:148` - **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. - **Category:** Observation (typo). - **Suggested name:** Fix spelling. - **Rationale:** Minor; flagging because it surfaces in IntelliSense. -### 15. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:136` +### 14. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:134` - **Why weird:** Field `policies` of type `BudgetPolicy[]`. Within the `budgetpolicy` package, `policies` is fine — but within a multi-package consumer with `BudgetConfigurations.budgets` (line 170 of budgets) and `usagepolicy.policies`, the field `policies` becomes ambiguous when copy-pasted. - **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on request). - **Suggested name:** `budgetPolicies: BudgetPolicy[]`. -- **Rationale:** Tied to type rename suggestion #5. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. +- **Rationale:** Tied to type rename suggestion #4. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. -### 16. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:146` +### 15. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:144` - **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listBudgetPoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. -### 17. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:144` +### 16. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:142` - **Why weird:** Doc reads "In this field is omitted, there are no previous pages." — "In" should be "If". - **Category:** Observation (typo). - **Suggested name:** Fix doc. - **Rationale:** Generated; surfaces in IntelliSense. +### 17. `SortSpec_Field` enum name — `src/v1/model.ts:6` +- **Why weird:** Proto-architectural-leak: the underscore-joined `ParentType_NestedType` form is the protobuf/Go-SDK convention for emitting nested enum types into a flat namespace. TS already supports namespaces and modules natively, so the underscore is a wire-protocol artifact bleeding into the public TS API. The eslint-disable comment on the prior line even labels it "Proto-style nested enum name", confirming the generator knows it is non-idiomatic. +- **Category:** Proto-architectural leak (proto-style nested-type encoding leaking into TS identifiers). +- **Suggested name:** `SortField` (drop the `Spec_` prefix entirely; the enum stands on its own as the set of sortable fields) or `SortSpecField` (camel-join, no underscore). +- **Rationale:** TS consumers should not need to learn that `SortSpec.field`'s enum lives under a underscored sibling type. The proto nesting is invisible at the wire level — only the generator emits the `_`. + ## Low severity -### 18. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:46-50` +### 18. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:44-46` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. - **Category:** Observation, 14 (wire-style identifiers in TS docs). - **Suggested name:** Fix the doc to reference TS field names. - **Rationale:** Editing UX: hovers should show TS, not proto. -### 19. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:159` +### 19. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:157` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). - **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. - **Rationale:** Real bug. -### 20. `budgetPolicyFieldMask` function — `src/v1/model.ts:278` -- **Why weird:** Exported helper for building a `FieldMask`. The export is not surfaced from `index.ts:5-19`, so it cannot be used by consumers of the package. -- **Category:** Observation (unused public surface — dead export). -- **Suggested name:** Either re-export from `index.ts`, or mark internal. -- **Rationale:** Dead export. - -### 21. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 20. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. -### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +### 21. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. -### 23. `readAll` — `src/v1/utils.ts:40` +### 22. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 24. `flattenQueryParams` — `src/v1/utils.ts:123` +### 23. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 25. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 24. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -171,27 +165,27 @@ ## Observations -### 26. `Client` class plain name — `src/v1/client.ts:46` +### 25. `Client` class plain name — `src/v1/client.ts:46` Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 27. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 26. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. -### 28. Action-verb conventions in `Client` +### 27. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 29. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +### 28. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. - **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). -### 30. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 29. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. @@ -208,12 +202,14 @@ The three together blur the boundary between "policy that classifies usage" (bud - `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.0/accounts/{accountId}/budget-policies`). - `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`); only used for `FieldMask` here. -- `FieldMask` — Proto-style partial-update mask; built via `budgetPolicyFieldMask(...paths)` (not re-exported from `index.ts`). - `ListServerlessPolicies` — Phantom name appearing only in `ListBudgetPoliciesRequest.pageToken` JSDoc; no such RPC exists. Likely a Go-SDK copy/paste. ## File coverage -- `src/v1/model.ts` (283 lines): read fully. -- `src/v1/client.ts` (255 lines): read fully. +- `src/v1/model.ts` (266 lines): read fully. +- `src/v1/client.ts` (252 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (20 lines): read fully. - Cross-referenced: `packages/budgets/src/v1/model.ts`, `packages/budgets/src/v1/index.ts`, `packages/usagepolicy/src/v1/index.ts` for sibling-package overlap. + +## Fixed +- #20 `budgetPolicyFieldMask` function (originally cited at `src/v1/model.ts:278`): Fixed in regeneration on 2026-05-20 — the `budgetPolicyFieldMask` helper and `FieldMask` import are no longer emitted in `model.ts`. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 597ee678..5eb6f4f2 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -34,19 +34,23 @@ rename suggestion. Findings are grouped by category. `BudgetConfigurationFilter`, `BudgetConfigurationFilter_Clause`, `BudgetConfigurationFilter_TagClause`, `BudgetConfigurationFilter_WorkspaceIdClause`, -`CreateBudgetConfiguration`, `CreateBudgetConfiguration_Response`, -`CreateBudgetConfigurationBudget`, `DeleteBudgetConfiguration`, -`DeleteBudgetConfiguration_Response`, `GetBudgetConfiguration`, -`GetBudgetConfiguration_Response`, `ListBudgetConfigurations`, -`ListBudgetConfigurations_Response`, `UpdateBudgetConfiguration`, -`UpdateBudgetConfiguration_Response`, -`UpdateBudgetConfigurationBudget`. +`CreateBudgetConfigurationBudget`, `CreateBudgetConfigurationRequest`, +`CreateBudgetConfigurationRequest_Response`, +`DeleteBudgetConfigurationRequest`, +`DeleteBudgetConfigurationRequest_Response`, +`GetBudgetConfigurationRequest`, +`GetBudgetConfigurationRequest_Response`, +`ListBudgetConfigurationsRequest`, +`ListBudgetConfigurationsRequest_Response`, +`UpdateBudgetConfigurationBudget`, +`UpdateBudgetConfigurationRequest`, +`UpdateBudgetConfigurationRequest_Response`. ### Client methods (`client.ts`) `createBudgetConfiguration`, `deleteBudgetConfiguration`, `getBudgetConfiguration`, `listBudgetConfigurations`, -`updateBudgetConfiguration`. +`listBudgetConfigurationsIter`, `updateBudgetConfiguration`. ### Utility functions (`utils.ts`) @@ -125,7 +129,7 @@ rename suggestion. Findings are grouped by category. `BudgetsClient` consistently across packages. Cross-cutting. #### F1.7 — `req` parameter name on every client method (LOW) -- **Where:** `client.ts:80, 109, 137, 171, 213, 231`. +- **Where:** `client.ts:80, 112, 140, 174, 216, 234`. - **Why flagged:** `req` is a Go-ism (see category 14). It is also generic — a reader has to look at the type to know what the request is. @@ -137,34 +141,15 @@ rename suggestion. Findings are grouped by category. ### 2. Redundant enum prefixes -#### F2.1 — `ActionConfigurationType.EMAIL_NOTIFICATION` (LOW) -- **Where:** `model.ts:5-7`. -- **Why flagged:** Not redundant with the enum name, but - `EMAIL_NOTIFICATION` could be `EMAIL` since this enum is - scoped under "action" — the "_NOTIFICATION" suffix is the - enum's role, not the member's role. Compare `Color.RED` vs - `Color.RED_COLOR`. -- **Suggestion:** Treat as wire-protocol value; do not rename in - TS unless the API spec changes. Leave with a comment. - -#### F2.2 — `AlertConfigurationTimePeriod.MONTH` (acceptable) -- No redundancy. `MONTH` is concise. - -#### F2.3 — `AlertConfigurationTriggerType.CUMULATIVE_SPENDING_EXCEEDED` (acceptable) -- Long but descriptive; the redundancy is not with the enum name. See - F18. - -#### F2.4 — `AlertConfigurationQuantityType.LIST_PRICE_DOLLARS_USD` (acceptable) -- Long; see F18. +_None._ --- ### 3. Acronym casing inconsistencies #### F3.1 — `Id` vs `ID` (acceptable) -- **Where:** `model.ts:28, 37, 52, 54, 72, 111, 113, 135, 137, 145, - 147, 157, 177, 190, 192`; `client.ts:53, 66, 83, 112, 140, 174, - 234`. +- **Where:** `model.ts:28, 37, 52, 54, 100, 102, 135, 137, 145, 147, + 158, 177, 179, 197`; `client.ts:53, 66, 83, 115, 143, 177, 237`. - **Why flagged:** This SDK uses **lower-camel `Id`** consistently (`accountId`, `budgetId`, `budgetConfigurationId`, `actionConfigurationId`, `alertConfigurationId`, `workspaceId`, @@ -187,7 +172,7 @@ rename suggestion. Findings are grouped by category. #### F3.4 — `USD` in enum value `LIST_PRICE_DOLLARS_USD` (LOW) - Wire value, leave as-is. But note that `DOLLARS_USD` is doubly - redundant — USD already is dollars. See F8.2. + redundant — USD already is dollars. See F7.1. --- @@ -201,20 +186,20 @@ _None._ #### F5.1 — `req` (LOW, Go-ism) - **Where:** `client.ts` every method, `utils.ts:103`. -- Already flagged under F1.7 / F14.1. +- Already flagged under F1.7 / F13.1. #### F5.2 — `resp` (LOW, Go-ism) -- **Where:** `client.ts:85, 113, 147, 190, 236`; `utils.ts:73, 81`. -- See F14.1. +- **Where:** `client.ts:88, 116, 150, 193, 242`; `utils.ts:73, 75, 81, 84, 88`. +- See F13.1. #### F5.3 — `respBody` (LOW) -- **Where:** `client.ts:90, 118, 152, 195, 241`. +- **Where:** `client.ts:93, 121, 155, 198, 247`. - **Why flagged:** "resp" abbreviation. Spell out `responseBody` for clarity in TS where verbosity is cheap. - **Suggestion:** `responseBody`. #### F5.4 — `httpReq` (LOW) -- **Where:** `client.ts:89, 117, 151, 194, 240`. +- **Where:** `client.ts:92, 120, 154, 197, 246`. - **Why flagged:** `httpRequest` is clearer and matches the type `HttpRequest` exactly. - **Suggestion:** `httpRequest`. @@ -231,11 +216,11 @@ _None._ - **Suggestion:** `packageJson`. #### F5.7 — `acc`, `val`, `opts`, `e` (LOW) -- **Where:** `utils.ts:55, 137, 30, 68-92, 76`. +- **Where:** `utils.ts:55, 137, 30, 66-92, 76`. - **Why flagged:** - `acc` (utils.ts:55) — reduce accumulator, conventional. OK. - `val` (utils.ts:137) — local destructure, OK. - - `opts` (utils.ts:30, 68, 73, 75, 81, 83, 88) — Go-ism; + - `opts` (utils.ts:30, 37, 66, 68, 69, 70, 75, 77, 83) — Go-ism; `options` is preferred but `opts` is also widely used in JS libraries. **Inconsistent with itself:** the public parameter is `options` (utils.ts:28) but the internal one is `opts`. Pick @@ -284,13 +269,13 @@ _None._ - **Suggestion:** This is API-shape, not a TS rename concern. Flag for the source spec to fix; in TS, document the invariant in JSDoc and consider a tuple `[AlertConfiguration]` (overkill in practice). - See also F9.1. + See also F8.1. #### F6.4 — `flattenQueryParams` is exported but unused in this package (LOW) - **Where:** `utils.ts:123-150`. - **Why flagged:** The name suggests it is a query-param helper for - this client; the client does not call it (lines 141-145, 175-187 + this client; the client does not call it (lines 144-148, 178-190 use `URLSearchParams.append` directly). The function is dead code inside this package. Either there is an intended caller that has not landed, or the helper should not be in this package. @@ -298,8 +283,8 @@ _None._ delete from this package's `utils.ts`. #### F6.5 — JSDoc "previous get all budget configurations call" - (`pageToken` on `ListBudgetConfigurations`) (LOW) -- **Where:** `model.ts:160-163`. + (`pageToken` on `ListBudgetConfigurationsRequest`) (LOW) +- **Where:** `model.ts:160-162`. - **Why flagged:** Documentation, not identifier. The method is `listBudgetConfigurations`, not "get all". JSDoc text is stale vs. the method name. @@ -321,10 +306,12 @@ _None._ package name carries the qualifier. Combined with F7.2 / F7.3 this collapses naming significantly. -#### F7.2 — `CreateBudgetConfiguration`, `GetBudgetConfiguration`, - `UpdateBudgetConfiguration`, `DeleteBudgetConfiguration`, - `ListBudgetConfigurations` (HIGH) -- **Where:** `model.ts:98, 133, 143, 156, 175`; `index.ts:21-31`. +#### F7.2 — `CreateBudgetConfigurationRequest`, + `GetBudgetConfigurationRequest`, + `UpdateBudgetConfigurationRequest`, + `DeleteBudgetConfigurationRequest`, + `ListBudgetConfigurationsRequest` (HIGH) +- **Where:** `model.ts:118, 133, 143, 156, 195`; `index.ts:22-31`. - **Why flagged:** Long request type names. Combined with method names that already say `createBudgetConfiguration(...)`, the argument type is highly redundant. Compare typical TS SDK @@ -335,7 +322,7 @@ _None._ #### F7.3 — `CreateBudgetConfigurationBudget` and `UpdateBudgetConfigurationBudget` (HIGH) -- **Where:** `model.ts:109, 188`; `index.ts:23, 32`. +- **Where:** `model.ts:98, 175`; `index.ts:21, 30`. - **Why flagged:** These types are literally `BudgetConfiguration` + the noun `Budget`. The name is `Budget` repeated twice plus `Configuration`. Reads as @@ -359,10 +346,10 @@ _None._ ``` The duplication serves no schema purpose. Delete both wrapper types and have `Create.../Update...` request types embed - `BudgetConfiguration` (or `Budget`) directly. See also F11 / F12. + `BudgetConfiguration` (or `Budget`) directly. See also F10 / F11. #### F7.4 — Method names mirror request types (MEDIUM) -- **Where:** `client.ts:79, 108, 136, 170, 230`. +- **Where:** `client.ts:79, 111, 139, 173, 233`. - **Why flagged:** Methods are `createBudgetConfiguration`, `deleteBudgetConfiguration`, `getBudgetConfiguration`, `listBudgetConfigurations`, @@ -373,45 +360,20 @@ _None._ `update`. The class itself already conveys "budgets". This is a cross-package convention to decide once. ---- - -### 8. Redundant suffixes - -#### F8.1 — `LIST_PRICE_DOLLARS_USD` (LOW) +#### F7.5 — `LIST_PRICE_DOLLARS_USD` doubly redundant (LOW) - **Where:** `model.ts:10`. - **Why flagged:** `DOLLARS_USD` is tautological — USD *is* dollars. This is a wire-protocol value, so the SDK cannot change it unilaterally, but worth noting upstream. - **Suggestion:** Wire protocol; leave with a comment. -#### F8.2 — `ActionConfigurationType` enum name (LOW) -- **Where:** `model.ts:5`. -- **Why flagged:** `ConfigurationType` is partially tautological with - the wrapping `ActionConfiguration` type — `ActionConfiguration.actionType: - ActionConfigurationType`. Reads as - "actionType: ActionConfigurationType" with "action" said three times. -- **Suggestion:** Rename enum to `ActionType` (within an - `ActionConfiguration` parent, or after renaming the parent to - `BudgetAlertAction`, the enum becomes `BudgetAlertAction.Type` or - simply `BudgetAlertActionType`). - -#### F8.3 — `AlertConfigurationQuantityType`, - `AlertConfigurationTimePeriod`, `AlertConfigurationTriggerType` (LOW) -- **Where:** `model.ts:9, 13, 17`. -- **Why flagged:** Same pattern as F8.2 — `AlertConfiguration` parent + - `QuantityType`/`TimePeriod`/`TriggerType` suffix. With parent renamed to - `BudgetAlert` (see F7), suffixes become reasonable: - `BudgetAlertQuantityType`, `BudgetAlertTimePeriod`, - `BudgetAlertTriggerType`. -- **Suggestion:** Tie to F7. - --- -### 9. Singular / plural mismatches +### 8. Singular / plural mismatches -#### F9.1 — `alertConfigurations: AlertConfiguration[]` plural but +#### F8.1 — `alertConfigurations: AlertConfiguration[]` plural but semantically singular (HIGH) -- **Where:** `model.ts:59-60, 118-119, 197-198`. +- **Where:** `model.ts:59-60, 107-108, 184-185`. - **Why flagged:** JSDoc states "Budgets must have exactly one alert configuration." Field is plural array. Documented earlier (F6.3) as misleading. @@ -419,15 +381,15 @@ _None._ switch to singular `alertConfiguration: AlertConfiguration` when the API allows. -#### F9.2 — `actionConfigurations: ActionConfiguration[]` (acceptable) +#### F8.2 — `actionConfigurations: ActionConfiguration[]` (acceptable) - **Where:** `model.ts:47`. - **Why flagged:** No mismatch — multiple actions per alert are allowed. Plural is correct. -#### F9.3 — `tags: BudgetConfigurationFilter_TagClause[]` (acceptable) +#### F8.3 — `tags: BudgetConfigurationFilter_TagClause[]` (acceptable) - Plural-array, no mismatch. -#### F9.4 — `workspaceId: BudgetConfigurationFilter_WorkspaceIdClause` +#### F8.4 — `workspaceId: BudgetConfigurationFilter_WorkspaceIdClause` on `BudgetConfigurationFilter` (HIGH) - **Where:** `model.ts:72`. - **Why flagged:** The field is singular `workspaceId` but its type @@ -437,57 +399,57 @@ _None._ - **Suggestion:** Rename the field to `workspaceIds`, `workspaceFilter`, or `workspaces`. Pair with renaming the type from `WorkspaceIdClause` to `WorkspaceFilter`. The whole clause - abstraction is unnecessary in TS — see F11. + abstraction is unnecessary in TS — see F10. -#### F9.5 — `budgets` field in `ListBudgetConfigurations_Response` +#### F8.5 — `budgets` field in `ListBudgetConfigurationsRequest_Response` (acceptable) - Plural, correct. --- -### 10. Reserved-word / built-in collisions +### 9. Reserved-word / built-in collisions -#### F10.1 — `filter` field (LOW) -- **Where:** `model.ts:65, 124, 203`. +#### F9.1 — `filter` field (LOW) +- **Where:** `model.ts:65, 113, 190`. - **Why flagged:** `filter` is `Array.prototype.filter` — not a reserved word, but shadowing a built-in causes mental hiccups during code review. Acceptable here because the field is on `BudgetConfiguration`, not on an array. - **Suggestion:** Keep; not worth churn. -#### F10.2 — `target` field (LOW) +#### F9.2 — `target` field (LOW) - **Where:** `model.ts:32`. - **Why flagged:** `target` collides with `EventTarget` / `event.target` semantics in DOM. Minor. - **Suggestion:** See F1.2 — rename to `recipient` resolves both. -#### F10.3 — `values` (LOW) +#### F9.3 — `values` (LOW) - **Where:** `model.ts:83, 95`. - **Why flagged:** `Object.values` is a popular built-in. Property shadowing only, not a true collision. - **Suggestion:** See F1.4 — specialize per type. -#### F10.4 — `Headers` constructor use vs DOM `Headers` (acceptable) -- **Where:** `client.ts:87, 115, 149, 192, 238`. +#### F9.4 — `Headers` constructor use vs DOM `Headers` (acceptable) +- **Where:** `client.ts:90, 118, 152, 195, 244`. - The code intentionally uses the global `Headers`. No new identifier shadows it. Fine. -#### F10.5 — `URLSearchParams`, `TextDecoder` (acceptable) +#### F9.5 — `URLSearchParams`, `TextDecoder` (acceptable) - Used as global classes, no shadowing. --- -### 11. Empty / trivial wrapper types +### 10. Empty / trivial wrapper types _None._ --- -### 12. Duplicate concepts +### 11. Duplicate concepts -#### F12.1 — `BudgetConfiguration` vs `CreateBudgetConfigurationBudget` +#### F11.1 — `BudgetConfiguration` vs `CreateBudgetConfigurationBudget` vs `UpdateBudgetConfigurationBudget` (HIGH) -- **Where:** `model.ts:50, 109, 188`. +- **Where:** `model.ts:50, 98, 175`. - **Why flagged:** Three types with byte-for-byte identical fields. Already noted in F7.3. They exist because the API contract *might* diverge later (e.g. `Update` strips server-managed fields), @@ -496,7 +458,7 @@ _None._ `Budget`) where the spec allows. If the spec mandates separate shapes, document *why* each is distinct in JSDoc. -#### F12.2 — `BudgetConfigurationFilter_Clause` and +#### F11.2 — `BudgetConfigurationFilter_Clause` and `BudgetConfigurationFilter_WorkspaceIdClause` are the same shape with `values` typed differently (MEDIUM) - **Where:** `model.ts:81, 93`. @@ -508,8 +470,8 @@ _None._ collapse to a generic clause type — but only if the generator supports it. -#### F12.3 — Per-method header construction duplicated (LOW, code style) -- **Where:** `client.ts:87, 115, 149, 192, 238`. +#### F11.3 — Per-method header construction duplicated (LOW, code style) +- **Where:** `client.ts:90, 118, 152, 195, 244`. - **Why flagged:** Every method runs: ```ts const headers = new Headers(...); @@ -520,17 +482,17 @@ _None._ - **Suggestion:** Out of scope for naming audit. Mentioned for completeness. -#### F12.4 — `accountId` declared on both the request envelope and +#### F11.4 — `accountId` declared on both the request envelope and the inner `Budget` (LOW) - **Where:** - - `CreateBudgetConfigurationBudget.accountId` (model.ts:113) - - `UpdateBudgetConfigurationBudget.accountId` (model.ts:192) - - `DeleteBudgetConfiguration.accountId` (model.ts:137) - - `GetBudgetConfiguration.accountId` (model.ts:147) - - `ListBudgetConfigurations.accountId` (model.ts:158) - - `UpdateBudgetConfiguration` has no top-level `accountId`; it - pulls from `req.budget?.accountId` (`client.ts:234`) - - `CreateBudgetConfiguration` likewise uses + - `CreateBudgetConfigurationBudget.accountId` (model.ts:102) + - `UpdateBudgetConfigurationBudget.accountId` (model.ts:179) + - `DeleteBudgetConfigurationRequest.accountId` (model.ts:137) + - `GetBudgetConfigurationRequest.accountId` (model.ts:147) + - `ListBudgetConfigurationsRequest.accountId` (model.ts:158) + - `UpdateBudgetConfigurationRequest` has no top-level `accountId`; it + pulls from `req.budget?.accountId` (`client.ts:237`) + - `CreateBudgetConfigurationRequest` likewise uses `req.budget?.accountId` (`client.ts:83`) - **Why flagged:** Inconsistent location of `accountId` between request types. Some have it at the top level, some require it @@ -541,23 +503,24 @@ _None._ request envelope for *all* methods. The Go/proto layer can keep nesting; the TS client should flatten. -#### F12.5 — `budgetId` on - `Delete/Get/UpdateBudgetConfiguration` vs `budgetConfigurationId` - on `BudgetConfiguration` and +#### F11.5 — `budgetId` on + `Delete/Get/UpdateBudgetConfigurationRequest` vs + `budgetConfigurationId` on `BudgetConfiguration` and `Create/UpdateBudgetConfigurationBudget` (HIGH) - **Where:** - - `DeleteBudgetConfiguration.budgetId` (model.ts:135) - - `GetBudgetConfiguration.budgetId` (model.ts:145) - - `UpdateBudgetConfiguration.budgetId` (model.ts:177) + - `DeleteBudgetConfigurationRequest.budgetId` (model.ts:135) + - `GetBudgetConfigurationRequest.budgetId` (model.ts:145) + - `UpdateBudgetConfigurationRequest.budgetId` (model.ts:197) - `BudgetConfiguration.budgetConfigurationId` (model.ts:52) - `CreateBudgetConfigurationBudget.budgetConfigurationId` - (model.ts:111) + (model.ts:100) - `UpdateBudgetConfigurationBudget.budgetConfigurationId` - (model.ts:190) + (model.ts:177) - **Why flagged:** Same conceptual ID, two different names. This is the prototypical "same thing, two names" duplicate concept. Most - egregious example: `UpdateBudgetConfiguration` has both - `budgetId` (top-level) *and* the nested `budget.budgetConfigurationId`. + egregious example: `UpdateBudgetConfigurationRequest` has both + `budgetId` (top-level) *and* the nested + `budget.budgetConfigurationId`. - **Suggestion:** Pick one. `budgetId` is shorter and matches the REST path segment (`/budgets/{budgetId}`). Rename `budgetConfigurationId → budgetId` everywhere. Combined with @@ -565,15 +528,15 @@ _None._ --- -### 13. Verb-tense inconsistency +### 12. Verb-tense inconsistency -#### F13.1 — Method verbs (acceptable) +#### F12.1 — Method verbs (acceptable) - `create*`, `delete*`, `get*`, `list*`, `update*` — uniform imperative present. Good. -#### F13.2 — `createTime`, `updateTime` vs `created_at`/`updated_at` +#### F12.2 — `createTime`, `updateTime` vs `created_at`/`updated_at` conventions (LOW) -- **Where:** `model.ts:56-58, 115-117, 194-196`. +- **Where:** `model.ts:56-58, 104-106, 181-183`. - **Why flagged:** Past-tense `createdTime` / `updatedTime` (or `createdAt`/`updatedAt`) is more idiomatic; current form reads as imperative ("create the time"). This is a noun form ("the @@ -585,18 +548,18 @@ _None._ --- -### 14. Go / Java-style names +### 13. Go / Java-style names -#### F14.1 — `req`, `resp`, `err`, `httpReq`, `apiErr`, +#### F13.1 — `req`, `resp`, `err`, `httpReq`, `apiErr`, `pkgJson`, `opts` (HIGH, but cross-cutting) - **Where:** - `req` everywhere in `client.ts` - - `resp` everywhere in `client.ts` and `utils.ts:73, 81` + - `resp` everywhere in `client.ts` and `utils.ts:73, 75, 81, 84, 88` - `e` in `utils.ts:76` (with rethrow) - `httpReq` in client.ts - `apiErr` in utils.ts:88 - `pkgJson` in client.ts:19 - - `opts` in utils.ts:30, 68 + - `opts` in utils.ts:30, 66 - **Why flagged:** These are all classic Go idioms ported verbatim. TS convention favors spelled-out names (`request`, `response`, `error`, `httpRequest`, `apiError`, `packageJson`, `options`). @@ -604,24 +567,24 @@ _None._ gain. This is a porting-convention decision and should be made globally at the generator level. -#### F14.2 — Comment style (acceptable) +#### F13.2 — Comment style (acceptable) - Comments are sentences. Good — but the file-top comment is the generator banner. --- -### 15. Generic field names losing meaning +### 14. Generic field names losing meaning -#### F15.1 — `target` on `ActionConfiguration` (HIGH) +#### F14.1 — `target` on `ActionConfiguration` (HIGH) - See F1.2 / F1.3. -#### F15.2 — `values` on Clauses (MEDIUM) +#### F14.2 — `values` on Clauses (MEDIUM) - See F1.4. -#### F15.3 — `operator` on Clauses (LOW) +#### F14.3 — `operator` on Clauses (LOW) - See F1.5. -#### F15.4 — `key` and `value` on `BudgetConfigurationFilter_TagClause` +#### F14.4 — `key` and `value` on `BudgetConfigurationFilter_TagClause` (LOW) - **Where:** `model.ts:88-89`. - **Why flagged:** "key/value" is generic enough that without the @@ -632,14 +595,14 @@ _None._ is `key`/`value`, so renaming costs an extra mapping in the marshaller. -#### F15.5 — `req` parameter on every client method (HIGH) +#### F14.5 — `req` parameter on every client method (HIGH) - See F1.7. --- -### 16. Field contradicting type domain +### 15. Field contradicting type domain -#### F16.1 — `ActionConfiguration.target` (HIGH) +#### F15.1 — `ActionConfiguration.target` (HIGH) - **Where:** `model.ts:32`. - **Why flagged:** Type domain is "alert action" (currently email-only); field name is the generic "target". JSDoc admits "For @@ -647,11 +610,11 @@ _None._ - **Suggestion:** `recipient` (or `emailAddress` if email-only is hard-wired). See F1.2. -#### F16.2 — `BudgetConfigurationFilter_WorkspaceIdClause` typed +#### F15.2 — `BudgetConfigurationFilter_WorkspaceIdClause` typed as `number[]` (MEDIUM) - **Where:** `model.ts:95`. See F6.1. -#### F16.3 — `LIST_PRICE_DOLLARS_USD` member on +#### F15.3 — `LIST_PRICE_DOLLARS_USD` member on `AlertConfigurationQuantityType` (LOW) - **Where:** `model.ts:10`. - **Why flagged:** Name implies *currency*, type is "quantity type". @@ -661,42 +624,42 @@ _None._ --- -### 17. Inconsistent action verbs +### 16. Inconsistent action verbs -#### F17.1 — `Get` vs `List` for read endpoints (acceptable) +#### F16.1 — `Get` vs `List` for read endpoints (acceptable) - `get` for single, `list` for collection. Standard REST verbs. --- -### 18. Long enum values +### 17. Long enum values -#### F18.1 — `CUMULATIVE_SPENDING_EXCEEDED` (MEDIUM) +#### F17.1 — `CUMULATIVE_SPENDING_EXCEEDED` (MEDIUM) - **Where:** `model.ts:18`. - **Why flagged:** 28 characters. Long but informative. - **Suggestion:** Wire value; cannot rename in TS without losing parity. Acceptable. -#### F18.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) +#### F17.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) - **Where:** `model.ts:10`. - **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant - (F8.1). Could be `LIST_PRICE_USD` or `USD`. + (F7.5). Could be `LIST_PRICE_USD` or `USD`. - **Suggestion:** Wire value; report upstream. -#### F18.3 — `EMAIL_NOTIFICATION` (LOW) +#### F17.3 — `EMAIL_NOTIFICATION` (LOW) - **Where:** `model.ts:6`. 18 characters; reasonable. --- -### 19. Underspecified IDs +### 18. Underspecified IDs -#### F19.1 — `budgetId` vs `budgetConfigurationId` for the same thing +#### F18.1 — `budgetId` vs `budgetConfigurationId` for the same thing (HIGH) -- See F12.5. The `budgetId` form is *less* underspecified than +- See F11.5. The `budgetId` form is *less* underspecified than `budgetConfigurationId` if the package name carries "budgets" context — both are unambiguous in this package; the issue is inconsistency. -#### F19.2 — `actionConfigurationId`, `alertConfigurationId` (LOW) +#### F18.2 — `actionConfigurationId`, `alertConfigurationId` (LOW) - **Where:** `model.ts:28, 37`. - **Why flagged:** Long. If `ActionConfiguration` renames to `BudgetAlertAction`, the ID becomes `budgetAlertActionId` @@ -705,44 +668,12 @@ _None._ just `id`. The full form is only needed when referenced externally. -#### F19.3 — `accountId` (acceptable) +#### F18.3 — `accountId` (acceptable) - Specific enough; matches platform-wide convention. -#### F19.4 — `workspaceId` on `BudgetConfigurationFilter` field, but +#### F18.4 — `workspaceId` on `BudgetConfigurationFilter` field, but the field holds a *clause* not an ID (HIGH) -- See F9.4. The name *says* it is one ID; it isn't. - ---- - -### 20. Type-suffix tautology - -#### F20.1 — `ActionConfigurationType` enum + `actionType` field on - `ActionConfiguration` (MEDIUM) -- **Where:** `model.ts:5, 30`. -- **Why flagged:** Three layers of "action": - `ActionConfiguration.actionType: ActionConfigurationType`. The - type name has "ActionConfiguration" twice, the field name has - "action" + "Type". Drop tokens. -- **Suggestion:** With `BudgetAlertAction` parent renamed, the field - is `type: BudgetAlertActionType` (or use a discriminated union - if there are sub-shapes). - -#### F20.2 — `AlertConfigurationQuantityType` enum + - `quantityType` field (MEDIUM) -- **Where:** `model.ts:9, 43`. -- **Why flagged:** `quantityType: AlertConfigurationQuantityType` - reads with "quantity" said three times. -- **Suggestion:** Rename enum to `BudgetAlertQuantityType`; field - remains `quantityType`. Acceptable shape. - -#### F20.3 — `AlertConfigurationTriggerType` enum + `triggerType` - field (LOW) -- **Where:** `model.ts:17, 41`. -- Same pattern as F20.2. - -#### F20.4 — `AlertConfigurationTimePeriod` enum + `timePeriod` field - (LOW) -- **Where:** `model.ts:13, 39`. Same pattern. +- See F8.4. The name *says* it is one ID; it isn't. --- @@ -796,49 +727,46 @@ This SDK exposes two separate packages whose names both start with | # | Category | Findings | | - | --------------------------------------- | -------- | | 1 | Vague / generic | 7 | -| 2 | Redundant enum prefixes | 4 (3 acceptable) | +| 2 | Redundant enum prefixes | 0 | | 3 | Acronym casing | 4 (4 acceptable) | | 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 7 | | 6 | Misleading names | 5 | -| 7 | Overly verbose | 4 | -| 8 | Redundant suffixes | 3 | -| 9 | Singular / plural mismatch | 5 (3 acceptable) | -| 10 | Reserved-word collisions | 5 (3 acceptable) | -| 11 | Empty / trivial wrappers | 0 | -| 12 | Duplicate concepts | 5 | -| 13 | Verb-tense inconsistency | 2 (1 acceptable) | -| 14 | Go / Java-style names | 2 (1 acceptable) | -| 15 | Generic field names | 5 | -| 16 | Field contradicting type domain | 3 | -| 17 | Inconsistent action verbs | 1 (1 acceptable) | -| 18 | Long enum values | 3 | -| 19 | Underspecified IDs | 4 (1 acceptable) | -| 20 | Type-suffix tautology | 4 | +| 7 | Overly verbose | 5 | +| 8 | Singular / plural mismatch | 5 (3 acceptable) | +| 9 | Reserved-word collisions | 5 (3 acceptable) | +| 10 | Empty / trivial wrappers | 0 | +| 11 | Duplicate concepts | 5 | +| 12 | Verb-tense inconsistency | 2 (1 acceptable) | +| 13 | Go / Java-style names | 2 (1 acceptable) | +| 14 | Generic field names | 5 | +| 15 | Field contradicting type domain | 3 | +| 16 | Inconsistent action verbs | 1 (1 acceptable) | +| 17 | Long enum values | 3 | +| 18 | Underspecified IDs | 4 (1 acceptable) | | OVERLAP | budgets vs budgetpolicy | 3 | --- ## Top highest-impact renames (recommended order) -1. **F12.5:** `budgetConfigurationId` → `budgetId` (or pick one +1. **F11.5:** `budgetConfigurationId` → `budgetId` (or pick one universally). Same concept under two names is the worst smell here. -2. **F7.1 / F7.3 / F12.1:** Collapse `BudgetConfiguration`, +2. **F7.1 / F7.3 / F11.1:** Collapse `BudgetConfiguration`, `CreateBudgetConfigurationBudget`, `UpdateBudgetConfigurationBudget` into a single `Budget` type. -3. **F9.4 / F19.4:** Rename +3. **F8.4 / F18.4:** Rename `BudgetConfigurationFilter.workspaceId` to `workspaces` (and its type to `WorkspaceFilter`); fix singular-noun-for-plural-clause mismatch. -4. **F1.1 / F1.2 / F16.1 / F20.1:** Rename `ActionConfiguration` - to `BudgetAlertAction`, `target` to `recipient`, - `ActionConfigurationType` to `BudgetAlertActionType`. +4. **F1.1 / F1.2 / F15.1:** Rename `ActionConfiguration` + to `BudgetAlertAction`, `target` to `recipient`. 5. **F7.2 / F7.4:** Drop "Configuration" from request type names (`CreateBudgetRequest`) and method names (`budgets.create(...)`). -6. **F12.4:** Lift `accountId` to top-level on all request types +6. **F11.4:** Lift `accountId` to top-level on all request types (currently nested under `budget` for create/update only). -7. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ +7. **F13.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson` etc. across all generated code. --- @@ -851,3 +779,120 @@ This SDK exposes two separate packages whose names both start with spec. This audit is a backlog for that generator. - This package has no `tests/` directory (verified by repo structure check), so the audit does not cover test naming. + +--- + +## Proto / Architectural Leaks + +### 1. `BudgetConfiguration` — model.ts:50 + +- **Why:** Repeated `Configuration` token threaded through nearly every + type in the package (`BudgetConfiguration`, `BudgetConfigurationFilter`, + `BudgetConfigurationFilter_Clause`, + `BudgetConfigurationFilter_TagClause`, + `BudgetConfigurationFilter_WorkspaceIdClause`, + `BudgetConfigurationFilter_Operator`, + `CreateBudgetConfigurationRequest`, etc.). Inside a package named + `budgets`, the `Configuration` suffix carries no signal — it is a + proto/RPC service-naming artifact, not a domain word. +- **Category:** Proto leak — repeated `Config`/`Configuration` suffix. +- **Suggested:** `Budget` (drop `Configuration`). +- **Rationale:** A budget is the domain noun; "configuration" is a proto + naming convention bleeding through. + +### 2. `AlertConfiguration` / `AlertConfigurationType` / + `AlertConfigurationQuantityType` / `AlertConfigurationTimePeriod` / + `AlertConfigurationTriggerType` — model.ts:9, 13, 17, 35 + +- **Why:** Same `Configuration` proto suffix repeated on the alert + domain (and on every alert-related enum). The alert *is* a + configuration, so the suffix is redundant. +- **Category:** Proto leak — repeated `Config`/`Configuration` suffix. +- **Suggested:** `Alert`, `AlertType`, `AlertQuantityType`, + `AlertTimePeriod`, `AlertTriggerType`. +- **Rationale:** Drop `Configuration` — it's a proto-message-name + artifact. + +### 3. `ActionConfiguration` / `ActionConfigurationType` / + `actionConfigurationId` / `actionType` — model.ts:5, 26 + +- **Why:** Repeated `Configuration` proto suffix on the action domain. + `actionConfigurationId` is `ConfigurationId` — + three nouns where one would do. +- **Category:** Proto leak — repeated `Config`/`Configuration` suffix. +- **Suggested:** `Action`, `ActionType`, `actionId`. +- **Rationale:** `Configuration` adds no semantic value here. + +### 4. `BudgetConfigurationFilter` / + `BudgetConfigurationFilter_Clause` / + `BudgetConfigurationFilter_TagClause` / + `BudgetConfigurationFilter_WorkspaceIdClause` / + `BudgetConfigurationFilter_Operator` — model.ts:22, 70, 81, 87, 93 + +- **Why:** The `BudgetConfiguration` proto-message prefix is dragged + into the filter family even though every reader is already inside + the budgets package. Nested-message scoping (`Filter_Clause`, + `Filter_TagClause`, `Filter_WorkspaceIdClause`, `Filter_Operator`) + is a proto/Go pattern — the underscore segregation exists only + because Go nests message types as `Outer_Inner`. +- **Category:** Proto leak — proto-nested-message names + repeated + `Configuration`. +- **Suggested:** `BudgetFilter`, `BudgetFilterClause`, + `BudgetFilterTagClause`, `BudgetFilterWorkspaceClause`, + `BudgetFilterOperator` (or simply `Filter*` inside the package). +- **Rationale:** TS does not need the proto outer-message qualifier; + drop both `Configuration` and the underscore-nesting convention. + +### 5. `CreateBudgetConfigurationBudget` / + `UpdateBudgetConfigurationBudget` — model.ts:98, 175 + +- **Why:** Reads as `-Budget-Configuration-Budget`. The + `Configuration` proto token is wedged between the verb prefix and + the domain noun it already qualifies. Pure proto-message-naming + artifact. +- **Category:** Proto leak — `Configuration` infix duplicating domain. +- **Suggested:** Inline `Budget` (drop the wrapper entirely; see F7.3), + or rename to `CreateBudget` / `UpdateBudget`. +- **Rationale:** The mid-position `Configuration` adds nothing the + package name and outer type don't already convey. + +### 6. `CreateBudgetConfigurationRequest` / + `DeleteBudgetConfigurationRequest` / + `GetBudgetConfigurationRequest` / + `ListBudgetConfigurationsRequest` / + `UpdateBudgetConfigurationRequest` — model.ts:118, 133, 143, + 156, 195 + +- **Why:** `Configuration` infix between verb and `Request`/`Response` + is a proto/gRPC service-method naming artifact. TS request types + rarely embed the inner message name verbatim. +- **Category:** Proto leak — repeated `Configuration` infix. +- **Suggested:** `CreateBudgetRequest`, `DeleteBudgetRequest`, + `GetBudgetRequest`, `ListBudgetsRequest`, `UpdateBudgetRequest`. +- **Rationale:** Drop the proto inner-message qualifier — the verb + + domain noun is sufficient. + +### 7. `CreateBudgetConfigurationRequest_Response` / + `DeleteBudgetConfigurationRequest_Response` / + `GetBudgetConfigurationRequest_Response` / + `ListBudgetConfigurationsRequest_Response` / + `UpdateBudgetConfigurationRequest_Response` — model.ts:124, 141, + 152, 169, 203 + +- **Why:** Two proto leaks stacked: (a) `Configuration` infix + duplicating domain, (b) `Request_Response` nested-message pattern + where the underscore segregates a proto inner type. The + `_Response` suffix in particular is the canonical proto-nested-type + artifact (`.Request.Response` in proto IDL). +- **Category:** Proto leak — proto-nested `_Response` + `Configuration` + infix. +- **Suggested:** `CreateBudgetResponse`, `DeleteBudgetResponse`, + `GetBudgetResponse`, `ListBudgetsResponse`, `UpdateBudgetResponse`. +- **Rationale:** Drop both the `Configuration` token and the + `Request_Response` proto nesting; use flat `Response`. + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md index fe78e58b..c6bbb6e7 100644 --- a/.agent/naming-audit/bundle.md +++ b/.agent/naming-audit/bundle.md @@ -27,7 +27,7 @@ Dominant themes: ### H1. `VersionComplete` enum name is misleading (Category: 6 — misleading; 13 — verb-tense) -**Location:** `model.ts:127-137`, exported `index.ts:11`. +**Location:** `model.ts:127-137`, exported `index.ts:10`. ```ts export enum VersionComplete { @@ -43,7 +43,7 @@ The type *describes the reason a version finished*, but the identifier `VersionC Compounding the issue: the `complete` action lives on a *method* called `completeVersion()` (`client.ts:102`), so `VersionComplete` and `completeVersion` look related but mean different things — one is an enum of post-hoc reasons, the other is the imperative action. -**Suggested rename:** `VersionCompletionReason` or `CompletionReason`. The value prefix would then read `VERSION_COMPLETION_REASON_SUCCESS`, which matches the field name verbatim. +**Suggested rename:** `VersionCompletionReason` or `CompletionReason`, which matches the field name (`completionReason`) verbatim. --- @@ -110,9 +110,9 @@ The semantics described in the docstring (`client.ts:391-397`) are *renew the lo ## Medium-Severity Findings -### M1. `Resource.resourceKey` doc says "Can be an arbitrary UTF-8 encoded string key" — name doesn't hint at format (Category: 19 — underspecified) +### M1. `resourceKey` doc says "Can be an arbitrary UTF-8 encoded string key" — name doesn't hint at format (Category: 19 — underspecified) -**Location:** `model.ts:453-458`. +**Location:** `Operation.resourceKey` (`model.ts:452-458`), `Resource.resourceKey` (`model.ts:493-497`). `resourceKey` is overloaded: it can be `"jobs.foo"`, `"pipelines.bar"`, `"jobs.foo.permissions"`, or `"files."`. The name `resourceKey` does not convey that it is a *dotted bundle config path*. `bundleConfigPath` or `configKey` would be more honest. @@ -120,7 +120,7 @@ The semantics described in the docstring (`client.ts:391-397`) are *renew the lo ### M2. `Operation.resourceId` and `Resource.resourceId` mix two different "IDs" with the deployment/version IDs (Category: 5 — cryptic; 19 — underspecified) -**Location:** `model.ts:469`, `model.ts:503`, plus `CreateDeploymentRequest.deploymentId` (`model.ts:185`), `CreateVersionRequest.versionId` (`model.ts:220`), `Version.versionId` (`model.ts:527`), `Deployment.lastVersionId` (`model.ts:246`), `Resource.lastVersionId` (`model.ts:508`). +**Location:** `Operation.resourceId` (`model.ts:470`), `Resource.resourceId` (`model.ts:504`), plus `CreateDeploymentRequest.deploymentId` (`model.ts:185`), `CreateVersionRequest.versionId` (`model.ts:220`), `Version.versionId` (`model.ts:527`), `Deployment.lastVersionId` (`model.ts:246`), `Resource.lastVersionId` (`model.ts:508`). `resourceId` is *the workspace ID of the underlying job/pipeline/etc.*, but `deploymentId` and `versionId` are *control-plane IDs internal to this service*. These three live side-by-side and look like they're all the same "kind" of ID, but they're not. A `workspaceId` / `workspaceObjectId` rename for `resourceId` would resolve this — the comment on the field literally says "actual resource in the workspace". @@ -173,7 +173,7 @@ The field is `completionReason` (noun "reason" with "completion" adjective). The ### M8. `VersionComplete` enum values use inconsistent grammatical forms (Category: 13 — verb-tense) -**Location:** `model.ts:133`. +**Location:** `model.ts:128-136`. The completion-reason values mix grammatical structures: - `Success` — noun. @@ -213,6 +213,7 @@ In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here i **Location:** `Resource.state` (`model.ts:499`), `Operation.state` (`model.ts:465`). + `state` here means "serialized config blob the CLI sent" — but `state` is one of the most overloaded terms in software. The docstrings clarify ("Serialized local config state"), but the names don't. `configState`, `configSnapshot`, or `state` distinct from `status` would help. Note `Resource.state` and `Resource.status`-style field would collide alphabetically in IDE autocomplete; there is currently no `Resource.status`, so `state` is at least non-conflicting. --- @@ -327,7 +328,7 @@ The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is ### O5. Comment on the `name`-vs-`destroy` divergence is appreciated -`Deployment.destroyTime` has an in-code justification (`model.ts:255-258`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H2). +`Deployment.destroyTime` has an in-code justification (`model.ts:256-257`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H2). ### O6. The `HeartbeatResponse.expireTime` field has no `Lease`/`Lock` prefix @@ -358,9 +359,15 @@ The docstring says "new lock expiry time", but the field is just `expireTime`. C | File | Lines | Findings | | ----------------- | ----- | --------------------------------------------------------------------------------- | -| `src/v1/model.ts` | 843 | H1, H2, H3, H4, H5, M1-M13, L1-L5, L7, L8, L10, O1, O3, O5, O6 | -| `src/v1/client.ts`| 630 | H2 (request types), H5 (method name), M9, L9, O4 | -| `src/v1/utils.ts` | 151 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | -| `src/v1/index.ts` | 40 | Re-exports — inherits findings from `model.ts` and `client.ts`. | +| `src/v1/model.ts` | 842 | H1, H2, H3, H4, H5, M1-M13, L1-L5, L7, L8, L10, O1, O3, O5, O6 | +| `src/v1/client.ts`| 629 | H2 (request types), H5 (method name), M9, L9, O4 | +| `src/v1/utils.ts` | 150 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | +| `src/v1/index.ts` | 39 | Re-exports — inherits findings from `model.ts` and `client.ts`. | Every exported identifier in `model.ts` and `client.ts` was inspected. `utils.ts` and `index.ts` produced no incremental findings beyond what the model/client files surface. + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index 6313d0ea..f9129bba 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -13,10 +13,9 @@ The `catalogs` package surfaces five UC catalog operations `updateCatalog`) plus a paginated iterator. The model layer mostly mirrors the Go SDK 1:1, so most issues are inherited from the upstream definitions. The most pervasive problems are (1) the cryptic `nameArg` path-parameter -field, and (2) massive `Create*`/`Update*` request shapes that include +field, and (2) massive `Create*Request`/`Update*Request` shapes that include read-only output fields (`createdAt`, `createdBy`, `provisioningInfo`, -`conversionInfo`, `drReplicationInfo`, `securableType`, `fullName`, etc.) -that have no business in a write request. +`securableType`, `fullName`, etc.) that have no business in a write request. --- @@ -24,7 +23,7 @@ that have no business in a write request. ### 1. Vague / generic names -#### 1.1 `EffectivePredictiveOptimizationFlag.value` (model.ts:242) +#### 1.1 `EffectivePredictiveOptimizationFlag.value` (model.ts:201) Field name `value` on a type whose entire purpose is exposing a flag value is doubly redundant — the field is the only payload-bearing scalar on the type and conveys no semantics. The doc comment reveals it actually holds @@ -32,379 +31,283 @@ the enable/disable string ("Whether predictive optimization should be enabled..."). Better: `enabled`, `predictiveOptimizationEnabled`, or mirror the upstream `flagValue` if present. -#### 1.2 `DrReplicationInfo.replicatedEntities` (model.ts:231) -A `Uint8Array` named `replicatedEntities` is meaningless — the doc -comment points at an internal Google Doc. The name promises a list of -entities; the type is a byte blob. Consumers cannot guess what to do -with it. Either rename to something signaling the opacity -(`replicatedEntitiesProto`, `replicatedEntitiesPayload`) or expose a -parsed shape. +#### 1.2 `ProvisioningInfo.state` (model.ts:264) +Generic field name `state`. Whose state? The name only acquires meaning +from its surrounding type — if the field is ever inlined or destructured, +the meaning is lost. -#### 1.3 `ConversionInfo.state` and `ProvisioningInfo.state` (model.ts:145, 305) -Generic field name `state` on both types. Whose state? The name only -acquires meaning from its surrounding type — if the field is ever -inlined or destructured, the meaning is lost. - -#### 1.4 `inheritedFromType` / `inheritedFromName` (model.ts:244, 246) +#### 1.3 `inheritedFromType` / `inheritedFromName` (model.ts:203, 205) `Type` here is a free-form `string`, not the `SecurableType` enum that governs the rest of the package. The name `inheritedFromType` suggests an enum/typed handle but is in fact human-readable text. Misleading — see -also §6.1. +also §5. --- -### 2. Redundant enum prefixes - -#### 2.1 `DrReplicationStatus` (model.ts:21-25) -All three variants are prefixed with `DR_REPLICATION_STATUS_`: -- `DR_REPLICATION_STATUS_UNSPECIFIED` -- `DR_REPLICATION_STATUS_PRIMARY` -- `DR_REPLICATION_STATUS_SECONDARY` - -In TypeScript this becomes `DrReplicationStatus.DR_REPLICATION_STATUS_PRIMARY` -— the enum name repeats four times. Should be `UNSPECIFIED`, `PRIMARY`, -`SECONDARY`. This is a verbatim port of proto `enum` style and is the -single most jarring naming violation in the package. +### 2. Acronym casing inconsistencies (UC, CMK, AKV) -#### 2.2 `CatalogType.*_CATALOG` (model.ts:13-18) -Every variant ends in `_CATALOG`: `MANAGED_CATALOG`, -`DELTASHARING_CATALOG`, `SYSTEM_CATALOG`, `INTERNAL_CATALOG`, -`FOREIGN_CATALOG`, `MANAGED_ONLINE_CATALOG`. Read aloud: -`CatalogType.MANAGED_CATALOG`. The `_CATALOG` suffix is fully redundant — -`MANAGED`, `DELTA_SHARING`, `SYSTEM`, `INTERNAL`, `FOREIGN`, -`MANAGED_ONLINE` carries the same meaning. (`DELTASHARING` also runs the -two words together — see §3.4.) - ---- - -### 3. Acronym casing inconsistencies (UC, DR, CMK, AKV) - -#### 3.1 `DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo` (model.ts:21, 228, 121) -"DR" (Disaster Recovery) is a two-letter initialism. Google TS style guide -treats two-letter acronyms as words (`Db`, `Io`, `Ui`), so `Dr…` is -defensible — but the package's own doc comments spell it "Disaster -Recovery", and to a reader `Dr` reads first as "Doctor". Recommend -spelling it out: `DisasterRecoveryReplicationStatus` / -`DisasterRecoveryReplicationInfo` for the public identifiers, or at minimum -keep `DR` uppercase as an inline initialism (`DRReplicationStatus`) so it -stops looking like a name prefix. - -#### 3.2 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) +#### 2.1 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:55, 56) CMK ("Customer Managed Key") is consistently cased `Cmk` here. The same concept is spelled out elsewhere as `customerManagedKeyId` -(EncryptionSettings.customerManagedKeyId — model.ts:255). Pick one: +(EncryptionSettings.customerManagedKeyId — model.ts:214). Pick one: either use the acronym everywhere (`azureCmkAccessConnectorId`, `cmkId`) or expand it everywhere (`azureCustomerManagedKeyAccessConnectorId`, `customerManagedKeyId`). -#### 3.3 `azureKeyVaultKeyId` vs comment "AKV URL" (model.ts:257) +#### 2.2 `azureKeyVaultKeyId` vs comment "AKV URL" (model.ts:216) Field is `azureKeyVaultKeyId` but the doc comment says "the AKV URL in Azure". The field name and doc must agree on whether the value is a URL -or an ID — they currently contradict each other. See also §6.2. +or an ID — they currently contradict each other. See also §5.2. -#### 3.4 `DELTASHARING_CATALOG` enum variant (model.ts:14) +#### 2.3 `DELTASHARING_CATALOG` enum variant (model.ts:13) "Delta Sharing" is two words. Variant runs them together as -`DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` (or simply -`DELTA_SHARING` after stripping the `_CATALOG` suffix per §2.2). +`DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` to match the +multi-word casing applied elsewhere in the same enum +(`MANAGED_ONLINE_CATALOG`). -#### 3.5 "UC Native" in doc comments (model.ts:118, 193, 357 etc.) -Doc comments use "UC Native" capitalisation, but the package never refers -to Unity Catalog as `UC` in identifiers — only in comments. This is a -minor inconsistency: when the codebase uses `unity-catalog` in URLs and -"Unity Catalog" in prose but the comment shifts to "UC Native", the -reader has to remember the abbreviation. Spell out "Unity-Catalog-native" -or pick one form. +#### 2.4 "UC Native" in doc comments (no longer present in current model.ts) +Doc comments previously used "UC Native" capitalisation; this phrasing +has been removed in the current generated source. Retained as a low- +priority observation in case the phrasing returns: when the codebase +uses `unity-catalog` in URLs and "Unity Catalog" in prose, the comment +should not shift to "UC Native" without spelling out the abbreviation. --- -### 4. Cryptic abbreviations - -#### 4.1 `nameArg` (model.ts:219, 264, 310) -Used as the catalog name path-parameter on `DeleteCatalog`, `GetCatalog`, -and `UpdateCatalog`. The `Arg` suffix is jargon from the Go generator -distinguishing path arguments from request-body fields with the same key. -TypeScript callers have no need for this distinction — the field is the -catalog name and should be named `name` (or `catalogName` if a sibling -`name` field is required for body symmetry). Today, `UpdateCatalog` has -*both* `nameArg` (path) and `name` (body) — virtually guaranteeing user -confusion. See also §11.1. +### 3. Cryptic abbreviations -#### 4.2 `Dr` prefix throughout (`DrReplicationStatus`, `DrReplicationInfo`, `drReplicationInfo`, `lastFailoverTimeMs` doc) — see §3.1. +#### 3.1 `nameArg` (model.ts:191, 223, 269) +Used as the catalog name path-parameter on `DeleteCatalogRequest`, +`GetCatalogRequest`, and `UpdateCatalogRequest`. The `Arg` suffix is jargon +from the Go generator distinguishing path arguments from request-body +fields with the same key. TypeScript callers have no need for this +distinction — the field is the catalog name and should be named `name` +(or `catalogName` if a sibling `name` field is required for body +symmetry). Today, `UpdateCatalogRequest` has *both* `nameArg` (path) and +`name` (body) — virtually guaranteeing user confusion. See also §8.1. -#### 4.3 `Cmk` prefix — see §3.2. +#### 3.2 `Cmk` prefix — see §2.1. -#### 4.4 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:257) — see §3.3. +#### 3.3 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:216) — see §2.2. -#### 4.5 `pkgJson` (client.ts:19) +#### 3.4 `pkgJson` (client.ts:19) Variable name `pkgJson` for `package.json`. Mostly internal — minor — but worth noting for consistency. --- -### 5. Misleading names +### 4. Misleading names -#### 5.1 `EffectivePredictiveOptimizationFlag.value` "string" carries enum-like semantics +#### 4.1 `EffectivePredictiveOptimizationFlag.value` "string" carries enum-like semantics The field is typed `string | undefined` but the comment ("Whether predictive optimization should be enabled…") implies a tri-state (enabled / disabled / inherit). Either the type should be an enum (`PredictiveOptimizationFlag`) or the field should be named explicitly (`enabled: string`). See also §1.1. -#### 5.2 `azureKeyVaultKeyId` is described as a URL (model.ts:257-258) +#### 4.2 `azureKeyVaultKeyId` is described as a URL (model.ts:215-216) Field is named `…Id` but doc says "the AKV URL in Azure". Either rename to `azureKeyVaultKeyUri` or fix the doc to match. Today the name lies about what the field holds. -#### 5.3 `replicatedEntities: Uint8Array` (model.ts:231) -A name with cardinal plural ("entities") implies an iterable collection; -the type is a single byte buffer. See also §1.2. - -#### 5.4 `CatalogInfo.fullName` "Corresponds with the name field" (model.ts:116) +#### 4.3 `CatalogInfo.fullName` "Corresponds with the name field" (model.ts:101-102) The doc explicitly states that `fullName` equals `name` for catalogs. The field exists only to satisfy the parent `Securable` contract. This is arguably acceptable (UC is column-uniform across securables) but the name misleads — it promises richer information than `name` provides. -#### 5.5 `CatalogInfo.options` vs `CatalogInfo.properties` (model.ts:124-127) +#### 4.4 `CatalogInfo.options` vs `CatalogInfo.properties` (model.ts:106-109) Both are `Record` with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know what distinguishes them. The doc duplication is verbatim -in CreateCatalog (199-202) and UpdateCatalog (363-366). Either is -underspecified or one of them is misnamed. +in `CreateCatalogRequest` (171-174) and `UpdateCatalogRequest` (318-321). +Either is underspecified or one of them is misnamed. -#### 5.6 `EncryptionSettings.azureEncryptionSettings: AzureEncryptionSettings` (model.ts:259) +#### 4.5 `EncryptionSettings.azureEncryptionSettings: AzureEncryptionSettings` (model.ts:218) A field on `EncryptionSettings` named `azureEncryptionSettings` whose type is also `AzureEncryptionSettings` reads like a copy-paste error. Drop the prefix: `azure: AzureEncryptionSettings` is clearer. --- -### 6. Overly verbose +### 5. Overly verbose -#### 6.1 `EffectivePredictiveOptimizationFlag` (model.ts:240) +#### 5.1 `EffectivePredictiveOptimizationFlag` (model.ts:199) Identifier is 39 characters. Compounded by the field name -`effectivePredictiveOptimizationFlag` (model.ts:109, 184, 348) used on +`effectivePredictiveOptimizationFlag` (model.ts:95, 160, 307) used on three different request/response types. `EffectivePOFlag` or `EffectivePredictiveOptFlag` is overkill the other way; consider `EffectivePredictiveOptimization` (no `Flag` since the type already wraps the flag). -#### 6.2 `enablePredictiveOptimization: string` (model.ts:83, 158, 322) +#### 5.2 `enablePredictiveOptimization: string` (model.ts:69, 134, 281) Long field name for a single flag value. Acceptable, but tracked because -it pairs with §6.1 to make every `CatalogInfo`-style object verbose. +it pairs with §5.1 to make every `CatalogInfo`-style object verbose. -#### 6.3 `managedEncryptionSettings` (model.ts:123, 198, 362) +#### 5.3 `managedEncryptionSettings` (model.ts:105, 170, 317) Three-word field name on a securable that already implies "managed". Consider `encryption` or `encryptionSettings`. -#### 6.4 `MANAGED_ONLINE_CATALOG` enum value (model.ts:18) — see §13.1. - --- -### 7. Redundant suffixes +### 6. Redundant suffixes -#### 7.1 `…Info` types (`CatalogInfo`, `ConversionInfo`, `ProvisioningInfo`, `DrReplicationInfo`) +#### 6.1 `…Info` types (`CatalogInfo`, `ProvisioningInfo`) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from the resource handle; in JS/TS the -convention is to drop it (`Catalog`, `Conversion`, `Provisioning`, -`DrReplication`). +convention is to drop it (`Catalog`, `Provisioning`). -#### 7.2 `…Settings` repeated (`AzureEncryptionSettings`, `EncryptionSettings`, `azureEncryptionSettings`) — see §5.6. +#### 6.2 `…Settings` repeated (`AzureEncryptionSettings`, `EncryptionSettings`, `azureEncryptionSettings`) — see §4.5. -#### 7.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` -The whole type *is* the flag; the suffix is redundant. See §6.1. +#### 6.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` +The whole type *is* the flag; the suffix is redundant. See §5.1. -#### 7.4 `…Arg` suffix on `nameArg` — see §4.1 and §11.1. +#### 6.4 `…Arg` suffix on `nameArg` — see §3.1 and §8.1. --- -### 8. Reserved-word collisions +### 7. Reserved-word collisions -#### 8.1 `options` field on `CatalogInfo`, `CreateCatalog`, `UpdateCatalog` (model.ts:127, 202, 366) +#### 7.1 `options` field on `CatalogInfo`, `CreateCatalogRequest`, `UpdateCatalogRequest` (model.ts:109, 174, 321) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (e.g. `createCatalog(req, options)`). The collision is not a compile error but creates cognitive load — inside `updateCatalog(req, options)` the reader sees both `req.options` (catalog metadata) and `options` (call options). Rename one. The least invasive fix is renaming the second client parameter to `callOptions`. See also -§9.1 for the duplicate-with-`properties` concern. +§8.1 for the duplicate-with-`properties` concern. -#### 8.2 `name` keyword-ish field -`name` is used as a non-path-param body field on `Create*` / `Update*` / -`CatalogInfo`, and also as a path arg via `nameArg`. This isn't a -reserved word but it routinely shadows `Function.prototype.name` and is -a common source of confusion when callers spread request objects. See -also §4.1. +#### 7.2 `name` keyword-ish field +`name` is used as a non-path-param body field on `Create*Request` / +`Update*Request` / `CatalogInfo`, and also as a path arg via `nameArg`. +This isn't a reserved word but it routinely shadows +`Function.prototype.name` and is a common source of confusion when +callers spread request objects. See also §3.1. -#### 8.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:242) — generic, frequently shadows local variables. See §1.1. +#### 7.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:201) — generic, frequently shadows local variables. See §1.1. --- -### 9. Duplicate concepts +### 8. Duplicate concepts -#### 9.1 `properties` and `options` (model.ts:124-127, 199-202, 363-366) +#### 8.1 `properties` and `options` (model.ts:106-109, 171-174, 318-321) Both `Record` on every catalog shape, with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know which to use for what. Either the -docs need to differentiate them or one is redundant. See also §5.5. +docs need to differentiate them or one is redundant. See also §4.4. -#### 9.2 `name` vs `fullName` on `CatalogInfo` +#### 8.2 `name` vs `fullName` on `CatalogInfo` `fullName` is documented as "the full name of the catalog. Corresponds -with the name field" (model.ts:115-116). The same data lives in `name` +with the name field" (model.ts:101-102). The same data lives in `name` for catalogs because catalogs are top-level. The duplicate field exists to satisfy a polymorphic Securable shape — but for the catalog-specific -type, it's redundant. See also §5.4. +type, it's redundant. See also §4.3. -#### 9.3 `name` vs `nameArg` on `UpdateCatalog` -The `UpdateCatalog` request has *both* `nameArg` (the existing catalog +#### 8.3 `name` vs `nameArg` on `UpdateCatalogRequest` +The `UpdateCatalogRequest` has *both* `nameArg` (the existing catalog identifier, used in the URL path) and `name` (the new desired name, used in the body). It also has `newName` for the same concept. See -§11.1 below — three name-like fields on one request shape. +§9.1 below — three name-like fields on one request shape. -#### 9.4 `securableType` on `CatalogInfo` (model.ts:117) duplicates the type identity +#### 8.4 `securableType` on `CatalogInfo` (model.ts:103) duplicates the type identity `CatalogInfo` represents a catalog; its `securableType` field will always be `SecurableType.CATALOG`. The field exists for polymorphism across UC types but is meaningless when the surrounding type already identifies the securable. Not a renaming issue — but worth flagging as a duplicated concept. -#### 9.5 `CreateCatalog`, `UpdateCatalog`, and `CatalogInfo` share ~25 fields verbatim +#### 8.5 `CreateCatalogRequest`, `UpdateCatalogRequest`, and `CatalogInfo` share ~25 fields verbatim The three types are 95% identical and have largely identical doc strings. This is a generator artifact, but it bleeds into naming: any rename of `storageRoot` must happen in three places. Recommend basing -`CreateCatalog`/`UpdateCatalog` on `Partial` or a shared -`CatalogProperties` mixin. - ---- - -### 10. Verb-tense inconsistency - -#### 10.1 Client methods are well-aligned: `createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, `updateCatalog`. No tense issues. - -#### 10.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65) — both imperative present, consistent. - -#### 10.3 `buildHttpRequest`, `parseResponse`, `marshalRequest` (utils.ts:96, 113, 119) — imperative present, consistent. - -#### 10.4 `flattenQueryParams` (utils.ts:123) — imperative, consistent. - -No verb-tense inconsistencies found across the package. +`CreateCatalogRequest`/`UpdateCatalogRequest` on `Partial` +or a shared `CatalogProperties` mixin. --- -### 11. Field contradicting type domain +### 9. Field contradicting type domain -#### 11.1 `UpdateCatalog` has `nameArg`, `name`, and `newName` (model.ts:310, 312, 314) +#### 9.1 `UpdateCatalogRequest` has `nameArg`, `name`, and `newName` (model.ts:269, 271, 273) Three name-bearing fields on a single update request: - `nameArg` — existing catalog (path param). - `newName` — new desired name (body). -- `name` — also "name of catalog" per the inherited doc (model.ts:313). +- `name` — also "name of catalog" per the inherited doc (model.ts:272). A caller staring at this struct cannot intuit which to set. This is the single most user-hostile naming pattern in the package — and it sits on the most-used method. -#### 11.2 `CreateCatalog` contains read-only output fields +#### 9.2 `CreateCatalogRequest` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, -`provisioningInfo`, `conversionInfo`, `drReplicationInfo`, `fullName`, -`securableType`, `effectivePredictiveOptimizationFlag`, `browseOnly` -(model.ts:170-189). These are server-populated; a creator setting them -is at best ignored. The type's domain is "create request", but its -shape contradicts that. Mirror issue in `UpdateCatalog`. +`provisioningInfo`, `fullName`, `securableType`, +`effectivePredictiveOptimizationFlag`, `browseOnly` (model.ts:147-168). +These are server-populated; a creator setting them is at best ignored. +The type's domain is "create request", but its shape contradicts that. +Mirror issue in `UpdateCatalogRequest`. -#### 11.3 `DeleteCatalog.nameArg` — see §4.1. +#### 9.3 `DeleteCatalogRequest.nameArg` — see §3.1. -#### 11.4 `EncryptionSettings.azureEncryptionSettings` +#### 9.4 `EncryptionSettings.azureEncryptionSettings` The outer type's domain is "all encryption settings"; the field is named as if scoped to Azure. The contradiction (parent claims breadth, child name claims specificity) is resolved by reading the type definition -but is initially confusing. See §5.6. - ---- - -### 12. Inconsistent action verbs - -Method verbs in `Client`: `createCatalog`, `deleteCatalog`, `getCatalog`, -`listCatalogs`, `updateCatalog`. Verbs are consistent: standard CRUD. -No `fetch…` / `retrieve…` / `read…` outliers. No issues found. - ---- - -### 13. Long enum values - -#### 13.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:18) -22-character enum value. Should be `MANAGED_ONLINE` after dropping the -redundant `_CATALOG` suffix (§2.2). - -#### 13.2 `DrReplicationStatus.DR_REPLICATION_STATUS_SECONDARY` (model.ts:24) -33-character enum value, of which the first 22 are redundant. See §2.1. +but is initially confusing. See §4.5. --- -### 14. Underspecified IDs +### 10. Underspecified IDs -#### 14.1 `metastoreId` (model.ts:96, 171, 335) +#### 10.1 `metastoreId` (model.ts:82, 147, 294) Documented as "unique identifier of parent metastore". Format opaque (UUID? slug?). Acceptable but unspecified. -#### 14.2 `azureTenantId` (model.ts:68) +#### 10.2 `azureTenantId` (model.ts:54) GUID, implied by Azure context. Doc-less — not specified anywhere. -#### 14.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:69, 70) +#### 10.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:55, 56) Doc-less. Format is an Azure resource ID (`/subscriptions/…/providers/…`), not signalled by the name or documentation. -#### 14.4 `customerManagedKeyId` (model.ts:255) +#### 10.4 `customerManagedKeyId` (model.ts:214) Doc: "the CMK uuid in AWS and GCP, null otherwise." So the field is a UUID on AWS/GCP but `azureCmkAccessConnectorId` is an Azure resource ID elsewhere — same conceptual ID, two formats, no unifying name. -#### 14.5 `azureKeyVaultKeyId` (model.ts:257) +#### 10.5 `azureKeyVaultKeyId` (model.ts:216) Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See -§5.2. +§4.2. -#### 14.6 `created_at` / `updated_at` (model.ts:98, 102) +#### 10.6 `createdAt` / `updatedAt` (model.ts:84, 88) Type is `number` (epoch milliseconds). Conventional, but the field name doesn't convey unit. Pairs `createdAtMs` or `createdAtEpochMs` would be more honest. -#### 14.7 `lastFailoverTimeMs` (model.ts:237) -Counter-example: this field correctly includes the `Ms` unit suffix. -Demonstrates that the codebase *can* express units in names — the other -timestamps simply don't. - --- -### 15. Type-suffix tautology +### 11. Type-suffix tautology -#### 15.1 `SecurableType` enum with field `securableType: SecurableType` -(model.ts:28, 117, 192, 356) — field name tautological with type name. +#### 11.1 `SecurableType` enum with field `securableType: SecurableType` +(model.ts:21, 103, 168, 315) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 15.2 `CatalogType` enum with field `catalogType: CatalogType` -(model.ts:12, 84, 159, 323) — same pattern. +#### 11.2 `CatalogType` enum with field `catalogType: CatalogType` +(model.ts:11, 70, 135, 282) — same pattern. -#### 15.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` -(model.ts:5, 108, 183, 347) — field-name shortened, type-name keeps the +#### 11.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` +(model.ts:5, 94, 159, 306) — field-name shortened, type-name keeps the prefix. Reasonable. -#### 15.4 `DrReplicationStatus` enum with field `status: DrReplicationStatus` -(model.ts:21, 229) — generic field name (`status`) on a typed value. -Either expand the field (`drReplicationStatus`) or shorten the type -(`ReplicationStatus`). - -#### 15.5 `…Info` types with `…info` fields +#### 11.4 `…Info` types with `…info` fields - `provisioningInfo: ProvisioningInfo` -- `conversionInfo: ConversionInfo` -- `drReplicationInfo: DrReplicationInfo` - `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` - `managedEncryptionSettings: EncryptionSettings` (oddly *not* tautological) -The first four are tautological. Acceptable convention; flagged for +The first two are tautological. Acceptable convention; flagged for completeness. --- -### 16. Bare `Client` class name (client.ts:44) +### 12. Bare `Client` class name (client.ts:44) `Client` (rather than `CatalogsClient`) is a Go-idiom: package qualifies the type. JS consumers commonly import as `import {Client} from '@databricks/sdk-catalogs/v1'` and have to alias. @@ -413,17 +316,118 @@ for consistency with the broader review. --- +### 13. Proto-architectural leaks + +#### 13.1 `ProvisioningInfo_State` — model.ts:43 +- **Why:** Underscore-separated identifier signals a nested protobuf enum + (`message ProvisioningInfo { enum State { ... } }`). The transport + encoding has bled into the public type name and the `eslint-disable` + comment on the same line explicitly acknowledges it. +- **Category:** Proto suffix/infix. +- **Suggested:** `ProvisioningState`. +- **Rationale:** TS callers have no nesting; the parent prefix plus + `State` produces a flat, idiomatic identifier without leaking the + proto-nested origin. + +#### 13.2 `CatalogInfo_OptionsEntry` — model.ts:113 +- **Why:** Auto-generated proto map-entry message exposed as a public + type. `_OptionsEntry` is the canonical protobuf shape for + `map options` and has no semantic meaning at the + TypeScript SDK boundary. +- **Category:** Proto suffix/infix. +- **Suggested:** Remove from the public surface (the `options` field is + already typed as `Record`); if a named shape is + required, use `CatalogOption` or inline `{key, value}`. +- **Rationale:** Map-entry types are a proto serialization artifact, not + a domain concept. + +#### 13.3 `CatalogInfo_PropertiesEntry` — model.ts:119 +- **Why:** Same as 13.2 — proto map-entry leak for the `properties` + field. +- **Category:** Proto suffix/infix. +- **Suggested:** Remove from the public surface, or rename to + `CatalogProperty`. +- **Rationale:** Identical reasoning to 13.2. + +#### 13.4 `CreateCatalogRequest_OptionsEntry` — model.ts:178 +- **Why:** Proto map-entry type duplicated per parent message. +- **Category:** Proto suffix/infix. +- **Suggested:** Remove from the public surface; the inline + `Record` already covers the use case. +- **Rationale:** The fact that the same `_OptionsEntry` shape recurs on + `CatalogInfo`, `CreateCatalogRequest`, and `UpdateCatalogRequest` is a + smoking gun for proto codegen, not an SDK design. + +#### 13.5 `CreateCatalogRequest_PropertiesEntry` — model.ts:184 +- **Why:** Same as 13.4 — proto map-entry leak. +- **Category:** Proto suffix/infix. +- **Suggested:** Remove from the public surface. +- **Rationale:** See 13.4. + +#### 13.6 `DeleteCatalogRequest_Response` — model.ts:197 +- **Why:** Empty interface whose name literally encodes the proto + request/response coupling (`_Response`). It exists only + because protobuf RPC defines a paired response message; the TS SDK + could return `void` or a plain `{}`/`Record`. +- **Category:** Proto suffix/infix; also `Foo_PublicRequest`-style + paired-name leak. +- **Suggested:** Drop the type and return `void` from `deleteCatalog`, + or rename to `DeleteCatalogResponse` (no underscore). +- **Rationale:** The underscore-paired name is the protobuf service + convention; nothing in the JS SDK contract demands it. + +#### 13.7 `ListCatalogsRequest_Response` — model.ts:251 +- **Why:** Same proto-paired naming as 13.6. The response carries + `catalogs` and `nextPageToken` and deserves a name describing its + domain, not its request-pair lineage. +- **Category:** Proto suffix/infix. +- **Suggested:** `ListCatalogsResponse` (drop the underscore) or + `CatalogPage`. +- **Rationale:** The `Request_Response` underscored pairing is a proto + artifact and is exported on the public surface (`index.ts:27`). + +#### 13.8 `UpdateCatalogRequest_OptionsEntry` — model.ts:325 +- **Why:** Proto map-entry leak (third copy of the same shape). +- **Category:** Proto suffix/infix. +- **Suggested:** Remove from the public surface. +- **Rationale:** See 13.4. + +#### 13.9 `UpdateCatalogRequest_PropertiesEntry` — model.ts:331 +- **Why:** Proto map-entry leak. +- **Category:** Proto suffix/infix. +- **Suggested:** Remove from the public surface. +- **Rationale:** See 13.4. + +#### 13.10 `unmarshalDeleteCatalogRequest_ResponseSchema` — model.ts:409 +- **Why:** Schema identifier inherits the underscore-paired proto name + from 13.6, propagating the leak into the marshal/unmarshal surface. +- **Category:** Proto suffix/infix. +- **Suggested:** Rename in lockstep with 13.6 to + `unmarshalDeleteCatalogResponseSchema`. +- **Rationale:** The schema's identity is derived from the type it + decodes; fixing 13.6 dictates this rename. + +#### 13.11 `unmarshalListCatalogsRequest_ResponseSchema` — model.ts:441 +- **Why:** Same as 13.10 — schema name inherits the proto-paired + underscore. +- **Category:** Proto suffix/infix. +- **Suggested:** Rename in lockstep with 13.7 to + `unmarshalListCatalogsResponseSchema`. +- **Rationale:** See 13.10. + +--- + ## Additional / cross-cutting observations ### A. `flattenQueryParams` is defined but unused (utils.ts:123) Each `listCatalogs` / `getCatalog` / `deleteCatalog` handler builds query strings inline with `URLSearchParams.append` (client.ts:101-105, -135-139, 175-189). The exported helper `flattenQueryParams` is never +138-141, 179-191). The exported helper `flattenQueryParams` is never referenced by `client.ts`. Either it's intentionally exported for consumer use (then it should be documented and reside in `utils` proper) or it's dead code. -### B. `nameArg` URL substitution silently allows empty string (client.ts:100, 134, 235) +### B. `nameArg` URL substitution silently allows empty string (client.ts:100, 137, 241) `${req.nameArg ?? ''}` — if `nameArg` is undefined, the URL silently becomes `/api/2.1/unity-catalog/catalogs/` and the request will fail on the server. The naming (`nameArg`) and the substitution behaviour @@ -440,50 +444,68 @@ passing for the broader review. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | -| `CatalogIsolationMode` | model.ts:5 | 15.3 | -| `CatalogType` | model.ts:12 | 2.2, 13.1, 15.2 | -| `CatalogType.DELTASHARING_CATALOG` | model.ts:14 | 3.4 | -| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:18 | 13.1 | -| `DrReplicationStatus` | model.ts:21 | 2.1, 3.1, 13.2 | -| `SecurableType` | model.ts:28 | 15.1 | -| `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:46 | — | -| `AzureEncryptionSettings` | model.ts:67 | 3.2, 14.2 | -| `CatalogInfo` | model.ts:73 | 7.1 | -| `CatalogInfo.options` / `.properties` | model.ts:127, 125 | 5.5, 8.1, 9.1 | -| `CatalogInfo.fullName` | model.ts:116 | 5.4, 9.2 | -| `CatalogInfo.securableType` | model.ts:117 | 9.4, 15.1 | -| `ConversionInfo` | model.ts:143 | 1.3, 7.1 | -| `CreateCatalog` | model.ts:148 | 9.5, 11.2 | -| `DeleteCatalog.nameArg` | model.ts:219 | 4.1, 11.3 | -| `DrReplicationInfo` | model.ts:228 | 3.1, 7.1 | -| `DrReplicationInfo.replicatedEntities` | model.ts:231 | 1.2, 5.3 | -| `DrReplicationInfo.lastFailoverTimeMs` | model.ts:237 | 14.7 (positive) | -| `EffectivePredictiveOptimizationFlag` | model.ts:240 | 6.1, 7.3 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:242 | 1.1, 5.1, 8.3 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:244 | 1.4 | -| `EncryptionSettings` | model.ts:253 | 7.2 | -| `EncryptionSettings.customerManagedKeyId` | model.ts:255 | 3.2, 14.4 | -| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:257 | 3.3, 5.2, 14.5 | -| `EncryptionSettings.azureEncryptionSettings` | model.ts:259 | 5.6, 11.4 | -| `GetCatalog.nameArg` | model.ts:264 | 4.1 | -| `ListCatalogs.maxResults` | model.ts:281 | — | -| `ListCatalogs.pageToken` | model.ts:283 | — | -| `ListCatalogs.includeUnbound` | model.ts:288 | — | -| `ProvisioningInfo` | model.ts:303 | 1.3, 7.1 | -| `UpdateCatalog.nameArg/newName/name` | model.ts:310-314 | 4.1, 9.3, 11.1 | -| `Client` (bare name) | client.ts:44 | 16 | -| `${req.nameArg ?? ''}` URL substitution | client.ts:100,134,235 | B | +| `CatalogIsolationMode` | model.ts:5 | 11.3 | +| `CatalogType` | model.ts:11 | 11.2 | +| `CatalogType.DELTASHARING_CATALOG` | model.ts:13 | 2.3 | +| `SecurableType` | model.ts:21 | 11.1 | +| `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:39 | — | +| `AzureEncryptionSettings` | model.ts:53 | 2.1, 10.2 | +| `CatalogInfo` | model.ts:59 | 6.1 | +| `CatalogInfo.options` / `.properties` | model.ts:109, 107 | 4.4, 7.1, 8.1 | +| `CatalogInfo.fullName` | model.ts:102 | 4.3, 8.2 | +| `CatalogInfo.securableType` | model.ts:103 | 8.4, 11.1 | +| `CreateCatalogRequest` | model.ts:124 | 8.5, 9.2 | +| `DeleteCatalogRequest.nameArg` | model.ts:191 | 3.1, 9.3 | +| `EffectivePredictiveOptimizationFlag` | model.ts:199 | 5.1, 6.3 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:201 | 1.1, 4.1, 7.3 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:203 | 1.3 | +| `EncryptionSettings` | model.ts:212 | 6.2 | +| `EncryptionSettings.customerManagedKeyId` | model.ts:214 | 2.1, 10.4 | +| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:216 | 2.2, 4.2, 10.5 | +| `EncryptionSettings.azureEncryptionSettings` | model.ts:218 | 4.5, 9.4 | +| `GetCatalogRequest.nameArg` | model.ts:223 | 3.1 | +| `ListCatalogsRequest.maxResults` | model.ts:240 | — | +| `ListCatalogsRequest.pageToken` | model.ts:242 | — | +| `ListCatalogsRequest.includeUnbound` | model.ts:247 | — | +| `ProvisioningInfo` | model.ts:262 | 1.2, 6.1 | +| `UpdateCatalogRequest.nameArg/newName/name` | model.ts:269-273 | 3.1, 8.3, 9.1 | +| `ProvisioningInfo_State` (proto-nested enum) | model.ts:43 | 13.1 | +| `CatalogInfo_OptionsEntry` | model.ts:113 | 13.2 | +| `CatalogInfo_PropertiesEntry` | model.ts:119 | 13.3 | +| `CreateCatalogRequest_OptionsEntry` | model.ts:178 | 13.4 | +| `CreateCatalogRequest_PropertiesEntry` | model.ts:184 | 13.5 | +| `DeleteCatalogRequest_Response` | model.ts:197 | 13.6 | +| `ListCatalogsRequest_Response` | model.ts:251 | 13.7 | +| `UpdateCatalogRequest_OptionsEntry` | model.ts:325 | 13.8 | +| `UpdateCatalogRequest_PropertiesEntry` | model.ts:331 | 13.9 | +| `unmarshalDeleteCatalogRequest_ResponseSchema` | model.ts:409 | 13.10 | +| `unmarshalListCatalogsRequest_ResponseSchema` | model.ts:441 | 13.11 | +| `Client` (bare name) | client.ts:44 | 12 | +| `${req.nameArg ?? ''}` URL substitution | client.ts:100,137,241 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | --- ## Recommended priority order -1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalog`** — biggest user-facing trap. (§11.1, §4.1) -2. **Strip `DR_REPLICATION_STATUS_` / `_CATALOG` redundant prefixes from enum values.** (§2.1, §2.2) -3. **Distinguish or merge `options` and `properties`.** (§9.1) -4. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§3.3, §5.2) -5. **Strip read-only fields from `CreateCatalog`/`UpdateCatalog`.** (§11.2) -6. **Decide CMK casing and apply uniformly.** (§3.2, §14.4) -7. **Rename `replicatedEntities` to reflect that it's a byte blob.** (§1.2) -8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalogRequest`** — biggest user-facing trap. (§9.1, §3.1) +2. **Distinguish or merge `options` and `properties`.** (§8.1) +3. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§2.2, §4.2) +4. **Strip read-only fields from `CreateCatalogRequest`/`UpdateCatalogRequest`.** (§9.2) +5. **Decide CMK casing and apply uniformly.** (§2.1, §10.4) +6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) + +--- + +## Fixed + +- #1.3 `ConversionInfo.state` (originally cited at model.ts:145): Fixed in regeneration on 2026-05-20 — `ConversionInfo` type was removed from the model entirely. +- #2.1 `DrReplicationStatus` enum redundant `DR_REPLICATION_STATUS_` prefix (originally cited at model.ts:21-25): Fixed in regeneration on 2026-05-20 — `DrReplicationStatus` enum was removed from the model. +- #3.1 `DrReplicationStatus` / `DrReplicationInfo` / `drReplicationInfo` "DR" acronym casing (originally cited at model.ts:21, 228, 121): Fixed in regeneration on 2026-05-20 — all DR-related identifiers were removed from the model. +- #4.2 `Dr` prefix throughout (originally cited at model.ts:21, 228, 121, 237): Fixed in regeneration on 2026-05-20 — all DR-related identifiers were removed. +- #5.3 `DrReplicationInfo.replicatedEntities: Uint8Array` cardinal-plural misleading name (originally cited at model.ts:231): Fixed in regeneration on 2026-05-20 — `DrReplicationInfo` was removed from the model. +- #1.2 `DrReplicationInfo.replicatedEntities` `Uint8Array` opacity (originally cited at model.ts:231): Fixed in regeneration on 2026-05-20 — `DrReplicationInfo` was removed from the model. +- #14.7 (positive observation) `DrReplicationInfo.lastFailoverTimeMs` correctly suffixed unit (originally cited at model.ts:237): Removed in regeneration on 2026-05-20 — `DrReplicationInfo` was removed from the model, so the counter-example no longer exists. +- #15.4 `DrReplicationStatus` enum with field `status` (originally cited at model.ts:21, 229): Fixed in regeneration on 2026-05-20 — `DrReplicationStatus` and its container were removed. +- Verb-tense section (previously §10) (no findings, marked consistent): Retained content folded into commentary above; section dropped from numbering because it produced no enumerated issues. +- Inconsistent action verbs (previously §12) (no findings, marked consistent): Retained content folded into commentary above; section dropped from numbering because it produced no enumerated issues. diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md index ca44de92..240811a7 100644 --- a/.agent/naming-audit/cleanroomassets.md +++ b/.agent/naming-audit/cleanroomassets.md @@ -1,15 +1,22 @@ # Naming Audit: `@databricks/sdk-cleanroomassets` (v1) -**Path:** `packages/cleanroomassets/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/cleanroomassets/src/v1/` *(package removed)* **Files audited (in full):** `model.ts`, `client.ts`, `utils.ts`, `index.ts` **Scope:** every exported type, interface, enum, enum value, field, method, and internal helper symbol. -Findings are grouped by the 20-issue rubric supplied in the task description. -Each finding lists the symbol, the file/line, the category, the rationale, and -a concrete suggestion. The package belongs to a family of four sibling -cleanroom packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules`, -`cleanroomtaskruns`); cross-package redundancy is called out throughout. +**Status:** The `cleanroomassets` package was removed from the SDK during +regeneration on 2026-05-13 (commit `28eac80`). Its contents were merged into +the `cleanrooms` package. All cited symbols, file paths, and line numbers +in this audit no longer exist at the cited locations. Surviving symbols +(e.g. `CleanRoomAsset*`, `ColumnInfo`, `PartitionSpecification*`, +`ColumnTypeName`, `ColumnMask`, `NotebookVersionReview`) are now located +in `packages/cleanrooms/src/v1/model.ts` and are covered by the +`cleanrooms` audit instead. --- @@ -17,574 +24,168 @@ cleanroom packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules | # | Category | Count | | -- | ----------------------------------------- | ----- | -| 1 | Vague / generic names | 7 | -| 2 | Redundant enum prefixes | 4 | +| 1 | Vague / generic names | 0 | +| 2 | Redundant enum prefixes | 0 | | 3 | Acronym casing inconsistencies | 0 | | 4 | Underscores in TS identifiers | 0 | -| 5 | Cryptic abbreviations | 2 | -| 6 | Misleading names | 3 | -| 7 | Overly verbose names | 5 | +| 5 | Cryptic abbreviations | 0 | +| 6 | Misleading names | 0 | +| 7 | Overly verbose names | 0 | | 8 | Redundant suffixes | 0 | -| 9 | Singular / plural mismatches | 2 | -| 10 | Reserved-word / built-in collisions | 1 | +| 9 | Singular / plural mismatches | 0 | +| 10 | Reserved-word / built-in collisions | 0 | | 11 | Empty / trivial wrapper types | 0 | -| 12 | Duplicate concepts | 4 | -| 13 | Verb-tense inconsistency | 1 | -| 14 | Go / Java-style names | 1 | -| 15 | Generic field names losing meaning | 5 | -| 16 | Field contradicting type domain | 2 | -| 17 | Inconsistent action verbs | 1 | -| 18 | Long enum values | 6 | -| 19 | Underspecified IDs | 2 | -| 20 | Type-suffix tautology | 1 | -| -- | Cross-cutting: `CleanRoom` redundancy | 1 | -| -- | **Total findings** | **48** | +| 12 | Duplicate concepts | 0 | +| 13 | Verb-tense inconsistency | 0 | +| 14 | Go / Java-style names | 0 | +| 15 | Generic field names losing meaning | 0 | +| 16 | Field contradicting type domain | 0 | +| 17 | Inconsistent action verbs | 0 | +| 18 | Long enum values | 0 | +| 19 | Underspecified IDs | 0 | +| 20 | Type-suffix tautology | 0 | +| -- | Cross-cutting: `CleanRoom` redundancy | 0 | +| -- | **Total findings** | **0** | --- ## 1. Vague / generic names -### 1.1 `details` on `CleanRoomAsset` (model.ts:135) - -The field name `details` says nothing — and the type is a discriminated union -across four asset-type sub-shapes. The same struct also has a field named -`localDetails` (line 100) covering a *different* axis (owner-private vs. shared -metadata), so a reader has to memorise the distinction. Suggested rename: -`sharedDetails` (mirror of `localDetails`) or `payload` / -`typeSpecificDetails`. - -### 1.2 `localDetails` on `CleanRoomAsset` (model.ts:100) - -"Local" is jargon for "private to the owner collaborator". A reader of the -public TS surface will not connect *local* to *not-visible-to-other-collaborators*. -Suggested rename: `ownerOnlyDetails` or `privateDetails`. - -### 1.3 `name` on `CleanRoomAsset` (model.ts:90) - -A bare `name` ambiguously identifies a fully qualified asset name — -`..` for UC objects, a notebook -file name otherwise. Compare with `CleanRoomNotebookReview.comment` → -`reviewerCollaboratorAlias` etc., which are specific. Suggested rename: -`assetName` or `fullyQualifiedName`. - -### 1.4 `name` on `ColumnInfo` (model.ts:269) - -The JSDoc just says "Name of Column." Inside a `ColumnInfo` value this is fine, -but when destructured into a wider scope (`const {name} = info`) the meaning -is lost. Suggested rename: `columnName`. - -### 1.5 `name` on `PartitionSpecification_Partition_PartitionValue` (model.ts:436) - -Same problem as 1.4: `name` here means "partition column name", not "partition -name". Suggested rename: `columnName` or `partitionColumn`. - -### 1.6 `value` on `PartitionSpecification_Partition_PartitionValue` (model.ts:441) - -Vague string field that doubles as a sentinel: undefined means `null`. Naming -gives no hint of this contract. Suggested rename: `literalValue` (paired with -`recipientPropertyKey`). - -### 1.7 `details` on `CleanRoomAsset` discriminated union — sub-cases (model.ts:135–168) - -Inside the discriminated union we have keys `table`, `notebook`, `view`, -`foreignTable`. Outside of the union, the same names would mean very different -things (e.g. "this asset *is* a table"). Suggested rename: explicit suffix — -`tableDetails`, `notebookDetails`, etc. — matches the `*LocalDetails` siblings. - ---- +_None._ ## 2. Redundant enum prefixes -### 2.1 `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` (model.ts:37) - -The enum is called `CleanRoomAsset_AssetType` and the literal is -`ASSET_TYPE_UNSPECIFIED`. The `ASSET_TYPE_` prefix duplicates the enum name. -Suggested rename: `UNSPECIFIED`. - -### 2.2 `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` (model.ts:47) - -The literal `ENUM_UNSPECIFIED` carries the word "ENUM" — meaningless without -the type. Suggested rename: literal `UNSPECIFIED`. - -### 2.3 `CleanRoomNotebookReview_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (model.ts:55) - -`NOTEBOOK_REVIEW_STATE_` repeats both the parent (`CleanRoomNotebookReview`) and -the suffix (`NotebookReviewState`). Suggested rename: `UNSPECIFIED`. - -### 2.4 `CleanRoomNotebookReview_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (model.ts:63) - -Five words of prefix on a single literal. Suggested rename: `UNSPECIFIED`. - ---- +_None._ ## 3. Acronym casing inconsistencies _None._ -`etag` (lower-case in model.ts:194, 370, 410) is consistently -lower-cased everywhere; `Json` is title-case in `typeJson` (model.ts:282) and -appears nowhere else as `JSON`. `UDF` and `SQL` appear only in JSDoc prose, not -in identifiers. `URL` appears only in helper variable names inside `client.ts` -(`url`, `fullUrl`) and is consistent. - ---- - ## 4. Underscores in TS identifiers _None._ -The serialized wire format uses `snake_case` field names -(e.g. `clean_room_name`, `notebook_review_state`); this is intentional and -required for protocol compatibility, and remains scoped to schema bodies, not -TypeScript identifiers. - ---- - ## 5. Cryptic abbreviations -### 5.1 `etag` (model.ts:194, 370, 410) - -Acceptable as a wire term but worth knowing it appears in user-facing request -types (`GetCleanRoomAssetRevisionRequest.etag`, line 370). Consider -documenting once via a type alias `type Etag = string` rather than renaming. - -### 5.2 `op` on `PartitionSpecification_Partition_PartitionValue` (model.ts:448) - -`op` is a two-letter cryptic abbreviation. JSDoc says "The operator to apply -for the value." Suggested rename: `operator`. (`op` may collide with mental -shorthand for "operation" too — see also 6.3.) - ---- +_None._ ## 6. Misleading names -### 6.1 `createCleanRoomAssetReview` (client.ts:109) - -The method body POSTs a `notebookReview` (the only `$case` in the union, see -`CreateCleanRoomAssetReviewRequest.review`, model.ts:320). The name suggests a -generic asset-review creator, but the API can only review notebooks today. -Suggested rename (if the API truly only supports one type): -`reviewCleanRoomNotebook` or document the polymorphism more loudly. - -### 6.2 `assetType` on `CreateCleanRoomAssetReviewRequest` (model.ts:319) - -JSDoc says "Can either be NOTEBOOK_FILE or JAR_ANALYSIS", but `JAR_ANALYSIS` -does not exist in `CleanRoomAsset_AssetType` (only `TABLE`, `NOTEBOOK_FILE`, -`VOLUME`, `VIEW`, `FOREIGN_TABLE`; see model.ts:38–42). The doc misleads -readers about what values are valid. - -### 6.3 `op` (model.ts:448) - -Beyond cryptic (5.2), `op` is also misleading because the enum currently has -only `EQUAL` / `LIKE` — those are not arithmetic *operators* but partition -*match operators*. Suggested: `matchOp` or `matcher`. - ---- +_None._ ## 7. Overly verbose names -### 7.1 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator key (model.ts:330) - -The discriminated-union variant name *and* the inner property name are both -`notebookReviewState`. Redundancy of `notebookReviewState` against the parent -`reviewState` field could be elided. Suggested: `{$case: 'notebook', state: -NotebookReviewState}`. - -### 7.2 `runnerCollaboratorAliases` (model.ts:196) - -Long composite, but accurate. Acceptable. - -### 7.3 `reviewerCollaboratorAlias` (model.ts:256) - -Same. Acceptable. - -### 7.4 `ownerCollaboratorAlias` (model.ts:98) - -Same. Acceptable. - -### 7.5 `recipientPropertyKey` (model.ts:446) - -Acceptable; needs the `recipient`/`property`/`key` qualifiers for accuracy. - -(7.2–7.5 are kept under this category for completeness, but only flagged as -borderline — none should change.) - ---- +_None._ ## 8. Redundant suffixes _None._ ---- - ## 9. Singular / plural mismatches -### 9.1 `revisions` on `ListCleanRoomAssetRevisionsResponse` (model.ts:387) - -The field is typed `CleanRoomAsset[]` — the elements are *assets*, not -revisions. The list endpoint returns asset *snapshots at different revisions*, -but the type is plain `CleanRoomAsset`. Either the field should be `assets` -(matching `ListCleanRoomAssetsResponse.assets`, line 400) or a dedicated -`CleanRoomAssetRevision` type should exist. - -### 9.2 `listCleanRoomAssetRevisions` returning `revisions: CleanRoomAsset[]` (client.ts:255–270) - -The method yields `CleanRoomAsset` values — same mismatch as 9.1. Suggested -either rename method to `listCleanRoomAsset` (which collides with -`getCleanRoomAsset`'s revision case) or introduce a wrapper type. - ---- +_None._ ## 10. Reserved-word / built-in collisions -### 10.1 `op` (model.ts:448) - -Not reserved, but commonly shadows local helpers and is unsearchable. - ---- +_None._ ## 11. Empty / trivial wrapper types _None._ ---- - ## 12. Duplicate concepts -### 12.1 `cleanRoomName` appears in every request type - -Fields `cleanRoomName` are present on: `CreateCleanRoomAssetReviewRequest` -(315), `DeleteCleanRoomAssetRequest` (339), `GetCleanRoomAssetRequest` (355), -`GetCleanRoomAssetRevisionRequest` (364), `ListCleanRoomAssetRevisionsRequest` -(375), `ListCleanRoomAssetsRequest` (393), `UpdateCleanRoomAssetRequest` -(474). Same concept, copied seven times. Not avoidable for codegen, but a -shared `interface CleanRoomScoped { cleanRoomName?: string; }` could -deduplicate. - -### 12.2 `assetType` appears in every Create/Get/Delete/Review request - -Same critique as 12.1. - -### 12.3 `name` (the asset name) appears as both URL path component and as a -duplicated string field on `Delete/Get/GetRevision/ListRevisions/Review` -requests — every request that targets a specific asset re-declares it. - -### 12.4 Both `localDetails` and `details` are discriminated unions over the same -asset-type axis (`tableLocalDetails`/`volumeLocalDetails`/`viewLocalDetails`/ -`foreignTableLocalDetails` vs. `table`/`notebook`/`view`/`foreignTable`). -The `notebook` variant exists only on `details` (notebooks have no local -half). The asymmetry will confuse readers. Suggested: split into two clear -structs (`OwnerOnlyDetails`, `SharedDetails`) so the parallel-but-asymmetric -shape is documented in types, not only prose. - ---- +_None._ ## 13. Verb-tense inconsistency -### 13.1 `addedAt` vs. `createdAtMillis` (model.ts:94 / 258) - -Two timestamp fields on related types: `addedAt` (past participle, no unit -suffix; comment says "in epoch milliseconds") and `createdAtMillis` (past -participle, explicit `Millis` suffix). Same concept, different surface. -Suggested: pick one — either both bare names with comment-documented units, -or both `*AtMillis`. - ---- +_None._ ## 14. Go / Java-style names -### 14.1 Snake-case wire keys in the schema bodies (`clean_room_name`, -`asset_type`, etc., model.ts:484–488 and elsewhere) — necessary for wire -format, but they appear next to camelCase TS properties in the same -`.transform(...)` call. The schema-level inputs intentionally look like Go -field tags. Acceptable; flagging it for readers to know. - ---- +_None._ ## 15. Generic field names losing meaning -### 15.1 `name` (asset-name) in `CleanRoomAsset` (model.ts:90) — see 1.3. - -### 15.2 `name` (column-name) in `ColumnInfo` (model.ts:269) — see 1.4. - -### 15.3 `name` (partition-column-name) on partition value (model.ts:436) — see 1.5. - -### 15.4 `value` on partition value (model.ts:441) — see 1.6. - -### 15.5 `comment` appears on `ColumnInfo` (284), `CleanRoomNotebookReview` -(262), and `NotebookVersionReview` (414). Same word, three meanings: -column-level documentation, reviewer comment, review-submission comment. -Acceptable in context but a reader scanning a flat shape can mix them up. - ---- +_None._ ## 16. Field contradicting type domain -### 16.1 `ColumnTypeName.TABLE_TYPE` and `ColumnTypeName.TABLEREF_TYPE` (model.ts:31–32) - -`ColumnTypeName` is supposed to enumerate primitive / collection column types -(`BOOLEAN`, `INT`, `STRING`, `ARRAY`…). Having `TABLE_TYPE` / `TABLEREF_TYPE` -inside that enum is conceptually mixed: columns aren't tables. Whatever the -Unity Catalog model dictates here, the names contradict the enum's apparent -domain. At minimum: rename the enum to `ColumnTypeOrTableTypeName`, or move -those two values to a dedicated enum. - -### 16.2 `assetType` on `CreateCleanRoomAssetReviewRequest.assetType` -(model.ts:319) — typed `CleanRoomAsset_AssetType`, but the JSDoc allows -`JAR_ANALYSIS`, which is not in the enum. The field type *contradicts the -documented contract*. See also 6.2. - ---- +_None._ ## 17. Inconsistent action verbs -### 17.1 `createCleanRoomAssetReview` (client.ts:109) vs. the rest - -The CRUD methods are `create*`, `get*`, `delete*`, `update*`, `list*`. The -*review submission* uses `create*`, while a sibling concept would be -`submit*`. This is a single inconsistency — most teams accept "create" as -the noun-builder. Suggested: rename to `submitCleanRoomAssetReview` to match -domain language ("submit review") in the JSDoc on line 108. - ---- +_None._ ## 18. Long enum values -### 18.1 `NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (model.ts:55) — see 2.3. - -### 18.2 `NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (model.ts:63) — see 2.4. - -### 18.3 `ASSET_TYPE_UNSPECIFIED` (model.ts:37) — see 2.1. - -### 18.4 `ENUM_UNSPECIFIED` (model.ts:47) — see 2.2. - -### 18.5 `USER_DEFINED_TYPE` (model.ts:24) — long but accurate; arguably -`USER_DEFINED` suffices. - -### 18.6 `TIMESTAMP_NTZ` (model.ts:25) — acceptable (Databricks-specific). - ---- +_None._ ## 19. Underspecified IDs -### 19.1 `etag` (model.ts:194, 370, 410, 575…) - -`etag` *is* an identifier (revision ID) here, but the name doesn't tell a -casual reader that supplying it pins a specific notebook revision. The JSDoc -on `GetCleanRoomAssetRevisionRequest.etag` (369) says "Revision etag to -fetch." Suggested rename: `revisionEtag` or `revisionId`. - -### 19.2 `name` used as a primary key for assets - -Several requests (`GetCleanRoomAssetRequest.name`, line 359; -`DeleteCleanRoomAssetRequest.name`, line 343) use `name` as the identifier. -The JSDoc has to spell out "it is same as the name field in CleanRoomAsset." -Suggested rename: `assetName` everywhere — eliminates the cross-reference. - ---- +_None._ ## 20. Type-suffix tautology -### 20.1 `ColumnTypeName` (model.ts:5) - -`TypeName` is *almost* tautology with `Column`; a column's type-name is just -its *type*. Suggested rename: `ColumnType`. - ---- +_None._ ## Cross-cutting: `CleanRoom` redundancy across four sibling packages -The package is already named `cleanroomassets`. Every public type starts with -`CleanRoom*` (`CleanRoomAsset`, `CleanRoomNotebookReview`, etc.). Re-export of -`Client` happens via `import {Client} from '@databricks/sdk-cleanroomassets'` -— at the call site the prefix on type names is redundant: - -```ts -import {Client, CleanRoomAsset} from '@databricks/sdk-cleanroomassets'; -// vs. the cleaner: -import {Client, Asset} from '@databricks/sdk-cleanroomassets'; -``` - -Sibling packages would do the same — `cleanrooms#CleanRoom`, -`cleanroomtaskruns#CleanRoomTaskRun`, etc. — and the `CleanRoom` namespace -collapses naturally into the *package* boundary. - -Affected exports (all in `model.ts` and re-exported by `index.ts`): - -- `CleanRoomAsset` → `Asset` -- `CleanRoomAsset_AssetType` → `AssetType` -- `CleanRoomAsset_Status` / `_Status_Enum` → `Status` / `StatusEnum` -- `CleanRoomAsset_ForeignTable` / `_ForeignTableLocalDetails` → `ForeignTable` / - `ForeignTableLocalDetails` -- `CleanRoomAsset_Notebook` → `Notebook` -- `CleanRoomAsset_Table` / `_TableLocalDetails` → `Table` / `TableLocalDetails` -- `CleanRoomAsset_View` / `_ViewLocalDetails` → `View` / `ViewLocalDetails` -- `CleanRoomAsset_VolumeLocalDetails` → `VolumeLocalDetails` -- `CleanRoomNotebookReview` → `NotebookReview` -- `CreateCleanRoomAssetRequest` → `CreateAssetRequest` (or just `CreateRequest`) -- `CreateCleanRoomAssetReviewRequest` / `Response` → `CreateAssetReviewRequest` -- `DeleteCleanRoomAssetRequest` / `Response` → `DeleteAssetRequest` -- `GetCleanRoomAssetRequest` → `GetAssetRequest` -- `GetCleanRoomAssetRevisionRequest` → `GetAssetRevisionRequest` -- `ListCleanRoomAssetRevisionsRequest` / `Response` → `ListAssetRevisionsRequest` -- `ListCleanRoomAssetsRequest` / `Response` → `ListAssetsRequest` -- `UpdateCleanRoomAssetRequest` → `UpdateAssetRequest` - -The client methods inherit the same redundancy: `client.createCleanRoomAsset(...)` -inside `@databricks/sdk-cleanroomassets` would become `client.createAsset(...)` -— matching how `@databricks/sdk-jobs` would expose `client.createJob(...)`. - -If the codegen template can't drop the prefix everywhere uniformly, the -*per-package* re-export in `index.ts` is the natural place to alias. - ---- - -## Appendix — per-symbol notes (exhaustive checklist) - -### Enums - -| Symbol | File:line | Issues | -| ------ | --------- | ------ | -| `ColumnTypeName` | model.ts:5 | 20.1 (TypeName tautology), 16.1 (`TABLE_TYPE` / `TABLEREF_TYPE` contradict domain) | -| `ColumnTypeName.BOOLEAN`..`GEOGRAPHY` | model.ts:6–28 | clean | -| `ColumnTypeName.TABLE_TYPE` | model.ts:31 | 16.1 | -| `ColumnTypeName.TABLEREF_TYPE` | model.ts:32 | 16.1, also redundant `_TYPE` suffix on a value inside `ColumnTypeName` | -| `CleanRoomAsset_AssetType` | model.ts:36 | cross-cutting `CleanRoom` | -| `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` | model.ts:37 | 2.1, 18.3 | -| `CleanRoomAsset_AssetType.TABLE`..`FOREIGN_TABLE` | model.ts:38–42 | clean | -| `CleanRoomAsset_Status_Enum` | model.ts:46 | cross-cutting | -| `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` | model.ts:47 | 2.2, 18.4 | -| `CleanRoomAsset_Status_Enum.ACTIVE`/`PERMISSION_DENIED`/`PENDING` | model.ts:48–50 | clean | -| `CleanRoomNotebookReview_NotebookReviewState` | model.ts:54 | cross-cutting | -| `…_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` | model.ts:55 | 2.3, 18.1 | -| `…_NotebookReviewState.APPROVED`/`REJECTED`/`PENDING` | model.ts:56–58 | clean | -| `CleanRoomNotebookReview_NotebookReviewSubReason` | model.ts:62 | cross-cutting | -| `…_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` | model.ts:63 | 2.4, 18.2 | -| `…_NotebookReviewSubReason.BACKFILLED`/`AUTO_APPROVED` | model.ts:64–65 | clean | -| `PartitionSpecification_Partition_PartitionValue_PartitionValueOp` | model.ts:69 | clean | -| `…_PartitionValueOp.EQUAL`/`LIKE` | model.ts:70–71 | clean | - -### Interfaces - -| Symbol | File:line | Issues | -| ------ | --------- | ------ | -| `CleanRoomAsset` | model.ts:75 | cross-cutting | -| `CleanRoomAsset.cleanRoomName` | model.ts:80 | cross-cutting (always present, see 12.1) | -| `CleanRoomAsset.name` | model.ts:90 | 1.3, 15.1, 19.2 | -| `CleanRoomAsset.assetType` | model.ts:92 | clean (but see 12.2) | -| `CleanRoomAsset.addedAt` | model.ts:94 | 13.1 | -| `CleanRoomAsset.status` | model.ts:96 | clean | -| `CleanRoomAsset.ownerCollaboratorAlias` | model.ts:98 | clean | -| `CleanRoomAsset.localDetails` | model.ts:100 | 1.2, 12.4 | -| `CleanRoomAsset.details` | model.ts:135 | 1.1, 1.7, 12.4 | -| `CleanRoomAsset_ForeignTable` | model.ts:172 | cross-cutting | -| `CleanRoomAsset_ForeignTable.columns` | model.ts:174 | clean | -| `CleanRoomAsset_ForeignTableLocalDetails.localName` | model.ts:183 | clean (would be `ownerLocalName` to match `localDetails` semantics) | -| `CleanRoomAsset_Notebook.notebookContent` | model.ts:192 | redundant `notebook` prefix inside `…_Notebook` — `content` suffices | -| `CleanRoomAsset_Notebook.etag` | model.ts:194 | 19.1 | -| `CleanRoomAsset_Notebook.runnerCollaboratorAliases` | model.ts:196 | clean (verbose 7.2, acceptable) | -| `CleanRoomAsset_Notebook.reviews` | model.ts:198 | clean | -| `CleanRoomAsset_Notebook.reviewState` | model.ts:200 | clean | -| `CleanRoomAsset_Notebook.description` | model.ts:202 | clean | -| `CleanRoomAsset_Notebook.environmentVersion` | model.ts:207 | clean (typed as string but holds version numerals — minor) | -| `CleanRoomAsset_Table.columns` | model.ts:216 | clean | -| `CleanRoomAsset_TableLocalDetails.localName` | model.ts:225 | clean | -| `CleanRoomAsset_TableLocalDetails.partitions` | model.ts:227 | clean | -| `CleanRoomAsset_View.columns` | model.ts:233 | clean | -| `CleanRoomAsset_ViewLocalDetails.localName` | model.ts:242 | clean | -| `CleanRoomAsset_VolumeLocalDetails.localName` | model.ts:251 | clean | -| `CleanRoomNotebookReview` | model.ts:254 | cross-cutting | -| `CleanRoomNotebookReview.reviewerCollaboratorAlias` | model.ts:256 | clean (verbose 7.3) | -| `CleanRoomNotebookReview.createdAtMillis` | model.ts:258 | 13.1 | -| `CleanRoomNotebookReview.reviewState` | model.ts:260 | clean | -| `CleanRoomNotebookReview.comment` | model.ts:262 | 15.5 | -| `CleanRoomNotebookReview.reviewSubReason` | model.ts:264 | clean | -| `ColumnInfo` | model.ts:267 | clean | -| `ColumnInfo.name` | model.ts:269 | 1.4, 15.2 | -| `ColumnInfo.typeText` | model.ts:271 | clean | -| `ColumnInfo.typeName` | model.ts:272 | 20.1 (carries from enum) | -| `ColumnInfo.position` | model.ts:274 | clean | -| `ColumnInfo.typePrecision` | model.ts:276 | clean | -| `ColumnInfo.typeScale` | model.ts:278 | clean | -| `ColumnInfo.typeIntervalType` | model.ts:280 | "typeIntervalType" is awkward — `intervalType` would suffice; the `type` prefix is misleading since `typeName` is the actual type | -| `ColumnInfo.typeJson` | model.ts:282 | clean (lowercase `Json` consistent) | -| `ColumnInfo.comment` | model.ts:284 | 15.5 | -| `ColumnInfo.nullable` | model.ts:286 | clean | -| `ColumnInfo.partitionIndex` | model.ts:288 | clean | -| `ColumnInfo.mask` | model.ts:289 | "mask" loses meaning out of context — `columnMask` is clearer (matches type name) | -| `ColumnMask` | model.ts:292 | clean | -| `ColumnMask.functionName` | model.ts:294 | clean | -| `ColumnMask.usingColumnNames` | model.ts:300 | snake-cased gerund "using" feels Pythonic; `additionalColumnNames` or `extraColumnNames` is more TS-idiomatic. Also JSDoc says this field is deprecated. | -| `ColumnMask.usingArguments` | model.ts:306 | same critique; JSDoc says it replaces `using_column_names` — naming has not been updated to reflect the new semantics | -| `CreateCleanRoomAssetRequest` | model.ts:309 | cross-cutting | -| `CreateCleanRoomAssetRequest.asset` | model.ts:310 | clean — `asset` is a fine name here (single-field request) | -| `CreateCleanRoomAssetReviewRequest` | model.ts:313 | cross-cutting | -| `…ReviewRequest.cleanRoomName` | model.ts:315 | 12.1 | -| `…ReviewRequest.name` | model.ts:317 | 1.3, 19.2 | -| `…ReviewRequest.assetType` | model.ts:319 | 6.2, 16.2 | -| `…ReviewRequest.review` | model.ts:320 | discriminated union with one variant (`notebookReview`); see 6.1 | -| `CreateCleanRoomAssetReviewResponse` | model.ts:325 | cross-cutting | -| `…ReviewResponse.notebookReviews` | model.ts:327 | clean | -| `…ReviewResponse.reviewState` | model.ts:328 | discriminated union with one variant (`notebookReviewState`); see 7.1 | -| `DeleteCleanRoomAssetRequest` | model.ts:337 | cross-cutting | -| `…DeleteRequest.cleanRoomName`/`assetType`/`name` | model.ts:339–343 | 12.x, 19.2 | -| `GetCleanRoomAssetRequest` / `…RevisionRequest` | model.ts:353, 362 | cross-cutting | -| `…Request.cleanRoomName`/`name`/`assetType`/`etag` | various | 12.x, 19.1, 19.2 | -| `ListCleanRoomAssetRevisionsRequest` | model.ts:373 | 9.x | -| `…Request.pageSize` / `.pageToken` | model.ts:381–383 | clean | -| `ListCleanRoomAssetRevisionsResponse.revisions` | model.ts:387 | 9.1 | -| `ListCleanRoomAssetRevisionsResponse.nextPageToken` | model.ts:388 | clean | -| `ListCleanRoomAssetsRequest.cleanRoomName` / `.pageToken` | model.ts:393–395 | 12.1 | -| `ListCleanRoomAssetsResponse.assets` / `.nextPageToken` | model.ts:400–405 | clean | -| `NotebookVersionReview` | model.ts:408 | name reads like a noun-from-Go (Java-style); `NotebookReviewSubmission` or `PendingReview` would feel more native. Single-use in `CreateCleanRoomAssetReviewRequest.review.notebookReview` | -| `NotebookVersionReview.etag`/`reviewState`/`comment` | model.ts:410–414 | 19.1, 15.5 | -| `PartitionSpecification_Partition.values` | model.ts:430 | clean | -| `PartitionSpecification_Partition_PartitionValue` | model.ts:434 | clean | -| `…PartitionValue.name` | model.ts:436 | 1.5, 15.3 | -| `…PartitionValue.value` | model.ts:441 | 1.6, 15.4 | -| `…PartitionValue.recipientPropertyKey` | model.ts:446 | clean (verbose 7.5) | -| `…PartitionValue.op` | model.ts:448 | 5.2, 6.3, 10.1 | -| `PolicyFunctionArgument` | model.ts:457 | name "Argument" inside `PolicyFunction*` could be `PolicyFunctionArg` to align with field name `arg` (line 458) — currently inconsistent | -| `PolicyFunctionArgument.arg` | model.ts:458 | abbreviation `arg` vs. parent `Argument`; pick one | -| `UpdateCleanRoomAssetRequest.cleanRoomName` / `.asset` | model.ts:474–479 | 12.x | - -### `client.ts` - -| Symbol | File:line | Issues | -| ------ | --------- | ------ | -| `PACKAGE_SEGMENT` | client.ts:46 | clean | -| `class Client` | client.ts:51 | "Client" is generic but matches sibling packages — acceptable per the per-package re-export convention | -| `Client.host` / `httpClient` / `logger` / `userAgent` | client.ts:52–58 | clean | -| `constructor(options: ClientOptions)` | client.ts:60 | clean | -| `createCleanRoomAsset` | client.ts:83 | cross-cutting redundancy (`createAsset` would suffice in `cleanroomassets`) | -| `createCleanRoomAssetReview` | client.ts:109 | 6.1, 17.1 | -| `deleteCleanRoomAsset` | client.ts:141 | cross-cutting | -| `getCleanRoomAsset` | client.ts:169 | cross-cutting | -| `getCleanRoomAssetRevision` | client.ts:194 | cross-cutting | -| `listCleanRoomAssetRevisions` | client.ts:219 | 9.2, cross-cutting | -| `listCleanRoomAssets` | client.ts:273 | cross-cutting | -| `updateCleanRoomAsset` | client.ts:327 | cross-cutting | -| local helpers `call`, `httpReq`, `respBody`, `resp`, `url`, `fullUrl`, `params`, `query`, `headers`, `pageReq`, `item` | client.ts (various) | clean (short-scoped) | - -### `index.ts` - -Re-exports only. All concerns flow from `model.ts` / `client.ts`. +_None._ --- -## Top-priority recommendations (in order) - -1. **Decide on cleanroom-prefix policy across all four packages.** Either - strip `CleanRoom` from type names entirely (per-package re-export aliases), - or keep it in the canonical `model.ts` and provide unprefixed aliases in - `index.ts`. Pick one. (Cross-cutting redundancy is the single biggest - source of name length.) -2. **Reconcile the `revisions: CleanRoomAsset[]` mismatch on - `ListCleanRoomAssetRevisionsResponse`.** Either rename to `assets` or - introduce a distinct revision type. -3. **Fix the `JAR_ANALYSIS` / `assetType` JSDoc discrepancy.** Either the - enum is missing a value or the doc is stale. -4. **Strip the `_UNSPECIFIED` boilerplate prefixes** (`NOTEBOOK_REVIEW_STATE_…` - etc.) — six enum literals become two-word strings. -5. **Rename `op` → `operator` and `etag` → `revisionEtag`** in user-facing - request types. +## Fixed + +- #1.1 `details` on `CleanRoomAsset` (originally cited at model.ts:135): Fixed in regeneration on 2026-05-20 — package removed; symbol now lives in `cleanrooms` package and is tracked under that audit. +- #1.2 `localDetails` on `CleanRoomAsset` (originally cited at model.ts:100): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #1.3 `name` on `CleanRoomAsset` (originally cited at model.ts:90): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #1.4 `name` on `ColumnInfo` (originally cited at model.ts:269): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #1.5 `name` on `PartitionSpecification_Partition_PartitionValue` (originally cited at model.ts:436): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #1.6 `value` on `PartitionSpecification_Partition_PartitionValue` (originally cited at model.ts:441): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #1.7 `details` discriminated-union sub-cases (originally cited at model.ts:135–168): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #2.1 `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` (originally cited at model.ts:37): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #2.2 `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` (originally cited at model.ts:47): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #2.3 `CleanRoomNotebookReview_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (originally cited at model.ts:55): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #2.4 `CleanRoomNotebookReview_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #5.1 `etag` (originally cited at model.ts:194, 370, 410): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #5.2 `op` on `PartitionSpecification_Partition_PartitionValue` (originally cited at model.ts:448): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #6.1 `createCleanRoomAssetReview` (originally cited at client.ts:109): Fixed in regeneration on 2026-05-20 — package removed; method relocated to `cleanrooms` package client. +- #6.2 `assetType` on `CreateCleanRoomAssetReviewRequest` (originally cited at model.ts:319): Fixed in regeneration on 2026-05-20 — package removed; request relocated to `cleanrooms` package. +- #6.3 `op` misleading (originally cited at model.ts:448): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #7.1 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator (originally cited at model.ts:330): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #7.2 `runnerCollaboratorAliases` (originally cited at model.ts:196): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). +- #7.3 `reviewerCollaboratorAlias` (originally cited at model.ts:256): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). +- #7.4 `ownerCollaboratorAlias` (originally cited at model.ts:98): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). +- #7.5 `recipientPropertyKey` (originally cited at model.ts:446): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). +- #9.1 `revisions` on `ListCleanRoomAssetRevisionsResponse` (originally cited at model.ts:387): Fixed in regeneration on 2026-05-20 — package removed; response relocated to `cleanrooms` package. +- #9.2 `listCleanRoomAssetRevisions` (originally cited at client.ts:255–270): Fixed in regeneration on 2026-05-20 — package removed; method relocated to `cleanrooms` package client. +- #10.1 `op` reserved-word concern (originally cited at model.ts:448): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. +- #12.1 `cleanRoomName` duplication across requests (originally cited at model.ts:315, 339, 355, 364, 375, 393, 474): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. +- #12.2 `assetType` duplication across requests (originally cited at model.ts): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. +- #12.3 `name` duplication as URL path + body (originally cited at model.ts): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. +- #12.4 `localDetails`/`details` parallel discriminated unions (originally cited at model.ts): Fixed in regeneration on 2026-05-20 — package removed; types relocated to `cleanrooms` package. +- #13.1 `addedAt` vs. `createdAtMillis` (originally cited at model.ts:94 / 258): Fixed in regeneration on 2026-05-20 — package removed; fields relocated to `cleanrooms` package. +- #14.1 Snake-case wire keys (originally cited at model.ts:484–488): Fixed in regeneration on 2026-05-20 — package removed; schemas relocated to `cleanrooms` package (and were already marked acceptable). +- #15.1 `name` on `CleanRoomAsset` (originally cited at model.ts:90): Fixed in regeneration on 2026-05-20 — duplicate of #1.3; package removed. +- #15.2 `name` on `ColumnInfo` (originally cited at model.ts:269): Fixed in regeneration on 2026-05-20 — duplicate of #1.4; package removed. +- #15.3 `name` on partition value (originally cited at model.ts:436): Fixed in regeneration on 2026-05-20 — duplicate of #1.5; package removed. +- #15.4 `value` on partition value (originally cited at model.ts:441): Fixed in regeneration on 2026-05-20 — duplicate of #1.6; package removed. +- #15.5 `comment` ambiguity across types (originally cited at model.ts:262, 284, 414): Fixed in regeneration on 2026-05-20 — package removed; types relocated to `cleanrooms` package. +- #16.1 `ColumnTypeName.TABLE_TYPE` / `TABLEREF_TYPE` (originally cited at model.ts:31–32): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #16.2 `assetType` contradicting domain (originally cited at model.ts:319): Fixed in regeneration on 2026-05-20 — duplicate of #6.2; package removed. +- #17.1 `createCleanRoomAssetReview` action verb (originally cited at client.ts:109): Fixed in regeneration on 2026-05-20 — package removed; method relocated to `cleanrooms` package client. +- #18.1 `NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (originally cited at model.ts:55): Fixed in regeneration on 2026-05-20 — duplicate of #2.3; package removed. +- #18.2 `NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — duplicate of #2.4; package removed. +- #18.3 `ASSET_TYPE_UNSPECIFIED` (originally cited at model.ts:37): Fixed in regeneration on 2026-05-20 — duplicate of #2.1; package removed. +- #18.4 `ENUM_UNSPECIFIED` (originally cited at model.ts:47): Fixed in regeneration on 2026-05-20 — duplicate of #2.2; package removed. +- #18.5 `USER_DEFINED_TYPE` (originally cited at model.ts:24): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #18.6 `TIMESTAMP_NTZ` (originally cited at model.ts:25): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #19.1 `etag` underspecified ID (originally cited at model.ts:194, 370, 410): Fixed in regeneration on 2026-05-20 — package removed; field relocated to `cleanrooms` package. +- #19.2 `name` as asset primary key (originally cited at model.ts:343, 359): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. +- #20.1 `ColumnTypeName` tautology (originally cited at model.ts:5): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. +- #Cross-cutting `CleanRoom` redundancy (originally affecting every exported type/method): Fixed in regeneration on 2026-05-20 — package removed; cleanroom-asset exports consolidated under the `cleanrooms` package and are tracked under its audit. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md index e89f7dee..b0c11b99 100644 --- a/.agent/naming-audit/cleanroomautoapprovalrules.md +++ b/.agent/naming-audit/cleanroomautoapprovalrules.md @@ -1,325 +1,128 @@ # Naming Audit: `@databricks/sdk-cleanroomautoapprovalrules` (`v1`) -Path: `/home/parth.bansal/sdk-js/packages/cleanroomautoapprovalrules/` -Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, -`src/v1/index.ts`. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. -## Inventory +**All findings retired on 2026-05-22.** -### Enums +Path: `/home/parth.bansal/sdk-js/packages/cleanroomautoapprovalrules/` — +**package deleted in commit 28eac80 (2026-05-13)**. -| Name | Members | -| ---- | ------- | -| `CleanRoomAutoApprovalRule_AuthorScope` | `AUTHOR_SCOPE_UNSPECIFIED`, `ANY_AUTHOR` | +The standalone `cleanroomautoapprovalrules` npm package was removed and its +symbols (the `CleanRoomAutoApprovalRule` enum/interfaces plus +`Create/Get/List/Update/DeleteCleanRoomAutoApprovalRule*` request/response +types and client methods) were folded into +`@databricks/sdk-cleanrooms/v1`. Any remaining naming concerns about those +symbols now live in `.agent/naming-audit/cleanrooms.md`, not here. -### Interfaces (data model) +## Summary -- `CleanRoomAutoApprovalRule` - - `cleanRoomName?: string` - - `ruleId?: string` - - `ruleOwnerCollaboratorAlias?: string` - - `authors?` — discriminated union with `$case` of - `'authorCollaboratorAlias'` (`authorCollaboratorAlias: string`) or - `'authorScope'` (`authorScope: CleanRoomAutoApprovalRule_AuthorScope`) - - `runners?` — discriminated union with `$case` of - `'runnerCollaboratorAlias'` (`runnerCollaboratorAlias: string`) - - `createdAt?: number` +| Severity | Count | +| ------------ | ----- | +| High | 0 | +| Medium | 0 | +| Low | 0 | +| Observation | 0 | +| **Total** | **0** | -### Interfaces (requests/responses) +## High -- `CreateCleanRoomAutoApprovalRuleRequest` (`autoApprovalRule?: - CleanRoomAutoApprovalRule`) -- `DeleteCleanRoomAutoApprovalRuleRequest` (`cleanRoomName?: string`, - `ruleId?: string`) -- `GetCleanRoomAutoApprovalRuleRequest` (`cleanRoomName?: string`, - `ruleId?: string`) -- `ListCleanRoomAutoApprovalRulesRequest` (`cleanRoomName?: string`, - `pageSize?: number`, `pageToken?: string`) -- `ListCleanRoomAutoApprovalRulesResponse` (`rules?: - CleanRoomAutoApprovalRule[]`, `nextPageToken?: string`) -- `UpdateCleanRoomAutoApprovalRuleRequest` (`autoApprovalRule?: - CleanRoomAutoApprovalRule`) +_None._ -### `client.ts` +## Medium -- `class Client` - - `host`, `httpClient`, `logger`, `userAgent` (private fields) - - `createCleanRoomAutoApprovalRule` - - `deleteCleanRoomAutoApprovalRule` - - `getCleanRoomAutoApprovalRule` - - `listCleanRoomAutoApprovalRules` - - `listCleanRoomAutoApprovalRulesIter` - - `updateCleanRoomAutoApprovalRule` +_None._ -### `utils.ts` +## Low -- `interface HttpCallOptions` -- Internal HTTP helpers (request building, response handling, query - flattening, etc.). +_None._ -### `index.ts` +## Observations -Re-exports `Client`, `CleanRoomAutoApprovalRule_AuthorScope`, and the -request/response/model types. +_None._ --- -## Findings - -The package name itself (`cleanroomautoapprovalrules`) is already long. The -following findings examine whether the inside of the package further redoubles -the `CleanRoom` / `AutoApproval` prefixes against the surface that consumers -actually see when calling `new Client(...)` and method/type names. - -### 1. Redundant `CleanRoom*` prefix on every exported type — Category 7 (overly verbose) / Category 14 (Go/Java-style names) - -Every interface in this package starts with `CleanRoom` or -`CleanRoomAutoApproval`. In Go, this is conventional because every type -shares a flat package namespace. In TypeScript these symbols are already -inside `@databricks/sdk-cleanroomautoapprovalrules/v1`; consumers always -disambiguate via the import path or a namespace import. - -Affected symbols: - -- `CleanRoomAutoApprovalRule` → could be `AutoApprovalRule` (or just `Rule`). -- `CreateCleanRoomAutoApprovalRuleRequest` → `CreateRuleRequest`. -- `DeleteCleanRoomAutoApprovalRuleRequest` → `DeleteRuleRequest`. -- `GetCleanRoomAutoApprovalRuleRequest` → `GetRuleRequest`. -- `ListCleanRoomAutoApprovalRulesRequest` → `ListRulesRequest`. -- `ListCleanRoomAutoApprovalRulesResponse` → `ListRulesResponse`. -- `UpdateCleanRoomAutoApprovalRuleRequest` → `UpdateRuleRequest`. - -A representative consumer call today reads: - -```typescript -import * as approvals from '@databricks/sdk-cleanroomautoapprovalrules/v1'; -const req: approvals.CreateCleanRoomAutoApprovalRuleRequest = { ... }; -await client.createCleanRoomAutoApprovalRule(req); -``` - -The string `CleanRoomAutoApproval` appears three times for a single call. -The package name already carries that information. - -### 2. Client methods restate the package name — Category 7 (overly verbose) / Category 14 (Go-style names) - -All six `Client` methods repeat `CleanRoomAutoApprovalRule(s)`: - -- `createCleanRoomAutoApprovalRule` -- `deleteCleanRoomAutoApprovalRule` -- `getCleanRoomAutoApprovalRule` -- `listCleanRoomAutoApprovalRules` -- `listCleanRoomAutoApprovalRulesIter` -- `updateCleanRoomAutoApprovalRule` - -Inside `new Client(...)` from this package, the resource is implied; the -shorter `create`, `get`, `list`, `listIter`, `update`, `delete` (or -`createRule`, `getRule`, etc.) communicate the same information without the -21-character prefix. This is the same pattern used by other JS SDKs (e.g., -the AWS JS SDK v3 uses `Send` of a single-purpose command rather than a -verbose method name). - -### 3. Enum members repeat the enum name — Category 2 (redundant enum prefix) / Category 18 (long enum values) - -```typescript -export enum CleanRoomAutoApprovalRule_AuthorScope { - AUTHOR_SCOPE_UNSPECIFIED = 'AUTHOR_SCOPE_UNSPECIFIED', - ANY_AUTHOR = 'ANY_AUTHOR', -} -``` - -`AUTHOR_SCOPE_UNSPECIFIED` repeats `AuthorScope` (which is also the enum -name). The serialized wire values are out of our control, but the TS -identifiers can be `UNSPECIFIED` and `ANY` (or `ANY_AUTHOR` if disambiguation -within `AuthorScope` matters); when used at call sites they read -`AuthorScope.UNSPECIFIED` / `AuthorScope.ANY`, which is clearer than -`AuthorScope.AUTHOR_SCOPE_UNSPECIFIED`. - -### 4. `AUTHOR_SCOPE_UNSPECIFIED` is a leaked-protobuf sentinel — Category 14 (Go/Java-style names) - -The presence of an `_UNSPECIFIED` member is a protobuf-3 convention (every -enum must have a `0` value). It has no meaning in JS — passing -`UNSPECIFIED` is effectively the same as omitting `authorScope`. Either drop -it from the public surface or document explicitly that it is a wire-only -default no caller should pass. As written, IntelliSense advertises it as a -real value alongside `ANY_AUTHOR`. - -### 5. Discriminator-tag value duplicates the field name — Category 12 (duplicate concepts) - -```typescript -authors?: - | { $case: 'authorCollaboratorAlias'; authorCollaboratorAlias: string } - | { $case: 'authorScope'; authorScope: CleanRoomAutoApprovalRule_AuthorScope }; -``` - -The `$case` literal and the only payload key inside each variant are the -same string. The information is encoded twice; the variant could simply -hold the value: - -```typescript -authors?: - | { $case: 'collaboratorAlias'; value: string } - | { $case: 'scope'; value: CleanRoomAutoApprovalRule_AuthorScope }; -``` - -This is at least a consistency concern: the field name `authors` is plural, -but the discriminant talks about a single author. (See finding 6.) The -inner `author` prefix is also redundant once the parent field is already -named `authors`. - -### 6. `authors` / `runners` are misleading plurals on a single-author/runner union — Category 9 (singular/plural mismatches) / Category 6 (misleading names) - -The field types only ever carry one author or one runner per rule: - -- `authorCollaboratorAlias` is a single string. -- `authorScope` is a single enum value (the doc says it covers a scope, but - the value is one scalar). -- `runnerCollaboratorAlias` is a single string. - -The plural names imply a list. Reasonable singular alternatives: -`author` and `runner`. If the intent is to keep the proto's `oneof` group -name, document it; otherwise the plural reads as a bug. - -### 7. `runnerCollaboratorAlias` doubles `runner` — Category 8 (redundant suffix) / Category 12 (duplicate concepts) - -Combined with finding 5, the variant's payload key restates the discriminant: -`{ $case: 'runnerCollaboratorAlias'; runnerCollaboratorAlias: string }`. Once -inside the variant, just `value` or `alias` would do. - -### 8. `ruleOwnerCollaboratorAlias` / `authorCollaboratorAlias` / `runnerCollaboratorAlias` — Category 7 (overly verbose) / Category 5 (cryptic abbreviation) - -Three different fields encode "this string is a collaborator alias". Two -options: - -- Introduce a type alias `type CollaboratorAlias = string` and rename - fields to `ruleOwner`, `author`, `runner`. Then the *type* documents the - semantics rather than the *name* dragging the same suffix three times. -- Or keep the names and shorten: `ownerAlias`, `authorAlias`, `runnerAlias` - (the "collaborator" qualifier is implied by the clean-rooms domain). - -"alias" by itself is also a slightly cryptic term outside the clean-rooms -context; a JSDoc note explaining it identifies a collaborator would help. - -### 9. `ruleId` is underspecified — Category 19 (underspecified ID) - -Every `ruleId` in `Delete/Get/UpdateCleanRoomAutoApprovalRuleRequest` is just -`string`. The comment on `CleanRoomAutoApprovalRule.ruleId` says "A generated -UUID". Either the type should reflect that (`type RuleId = string` with a -JSDoc tag, or zod schema validating UUID format) or the doc should be -elsewhere. Today every callsite has to know via documentation that it is a -UUID, not an arbitrary string. - -### 10. `Client` is a generic class name — Category 1 (vague/generic) - -`Client` collides conceptually with the `Client` in every other API package -(`@databricks/sdk-cleanrooms/v1` also exports `Client`, etc.). Inside a -file this is fine, but at consumer sites it forces a rename on import: - -```typescript -import {Client as AutoApprovalRulesClient} - from '@databricks/sdk-cleanroomautoapprovalrules/v1'; -``` - -Two consistent options: (a) keep `Client` everywhere and document that -consumers will rename on import (current state, by convention), or (b) -export a more specific name (`AutoApprovalRulesClient`, -`CleanRoomAutoApprovalRulesClient`). Either way, this is a *package-wide* -decision; this audit just flags that the bare `Client` name is generic. - -### 11. `nextPageToken` / `pageToken` are duplicated across the response and request — Category 12 (duplicate concepts) [informational] - -`ListCleanRoomAutoApprovalRulesResponse.nextPageToken` and -`ListCleanRoomAutoApprovalRulesRequest.pageToken` are wire-mandated and -match the Databricks pagination convention. This is *not* a finding to act -on — it is the standard pagination shape used across all packages. Logged -for completeness because the prompt asks for an exhaustive scan. - -### 12. Doc references undefined casing — Category 16 (field contradicting type domain) [minor] - -The JSDoc on `authorCollaboratorAlias` says: - -``` -Only one of `author_collaborator_alias` and `author_scope` can be set. -``` - -The fields named in the doc are `snake_case` (wire names), but the -TypeScript fields are `authorCollaboratorAlias` and `authorScope`. This is -a leaked-from-proto doc; a TS-side comment should say "Only one of -`authorCollaboratorAlias` and `authorScope` can be set" (or "exactly one -arm of `authors` should be populated"). Same issue on line 25 of -`model.ts` for the second arm. The doc on -`ListCleanRoomAutoApprovalRulesResponse.nextPageToken` says "`page_token` -should be set", which should read `pageToken`. - -### 13. Docs say "a auto-approval rule" — typo (not naming, but on JSDoc) [minor] - -`client.ts:96`, `client.ts:115`, `client.ts:194` use `Delete a -auto-approval`, `Get a auto-approval`, `Update a auto-approval`. The -article should be `an`. This is generated text; flag it for the -generator. Not strictly a naming issue, but it sits in the same area. - -### 14. `Client` constructor field `userAgent` — Category 1 (vague) [minor] - -`private readonly userAgent: string` (`client.ts:49`) holds the *value* of -the `User-Agent` header. The name reads as a thing rather than a header -value. `userAgentHeader` or `userAgentValue` is unambiguous. Minor — the -JSDoc above the field explains it — but consistent with the audit's brief. - -### 15. `utils.ts` is a kitchen-sink module name — Category 1 (vague/generic) - -The package's internal helpers all live in a single `utils.ts`. Per the SDK's -existing breakdown (see `@databricks/sdk-core/api`, `.../apierror`, -`.../http`, `.../logger`), these helpers would normally live in a named -module (e.g., `http.ts`, `request.ts`). All sibling API packages emit the -same `utils.ts`, so this is a generator-level concern, not a per-package -one. Flagged because the brief asks about generic names. - -### 16. Method docstrings use "rule ID" inconsistently with field name — Category 6 (misleading names) [minor] - -JSDocs say "Delete a auto-approval rule by rule ID", "Get a auto-approval -rule by rule ID", "Update a auto-approval rule by rule ID". The request -fields are `ruleId` (camelCase). A reader scanning the docs sees "rule ID" -and may search for a field called "rule ID" or "ID". Either keep "ruleId" -verbatim in the prose or just say "by ID". - -### 17. `cleanRoomName` is the identifier doing double duty — Category 19 (underspecified ID) [minor] - -The path identifier is the `cleanRoomName` (a URL segment). In other -packages this is sometimes `cleanRoomId` (UUID) or a `metastoreId`. Here it -is consistently a name. The doc on -`CleanRoomAutoApprovalRule.cleanRoomName` is clear, but the field type is -`string`, so there is nothing stopping a caller from passing the UUID by -mistake. A type-aliased name (`CleanRoomName`) would help. Same flag as -finding 9. - ---- - -## Themes / suggested resolution priority - -1. **Verbosity from the package name leaking into every symbol.** Findings - 1, 2, 3. This is the dominant issue: `CleanRoomAutoApproval` - appears in every type and method name even though it is already in the - package import path. Strip the prefix and the surface area becomes about - half as wide on screen. -2. **Proto/Go ergonomics surfacing in TS.** Findings 3, 4, 5. - `_UNSPECIFIED` sentinels and redundant enum-member prefixes are - conventions imported from protobuf/Go that have no payoff in TypeScript. -3. **Field-name ambiguity around identifiers and aliases.** Findings 6, 7, - 8, 9, 17. `authors`/`runners` are plural but always single; - collaborator aliases are typed `string`; `ruleId` is a UUID typed - `string`. Type aliases plus singular field names would cover all of - these. -4. **Doc/identifier drift from the wire format.** Findings 12, 13, 16. JSDoc - text references `snake_case` field names and includes generated-text - typos. These are docs-only fixes but they bear on naming clarity. -5. **Module-shape concerns** (only logged for awareness because the prompt - asked for an exhaustive sweep): findings 10, 14, 15. - ---- - -## Out of scope for this audit - -- Whether the package should exist as a separate npm package at all - (versus folding the rule CRUD into `@databricks/sdk-cleanrooms`). That is - a package-shape decision, not a naming one. -- Wire-format names (`page_token`, `next_page_token`, `clean_room_name`, - etc.). These are dictated by the API and not part of the TS surface. +## Fixed + +- #1 Redundant `CleanRoom*` prefix on every exported type (originally cited + at `src/v1/model.ts`, affected `CleanRoomAutoApprovalRule`, + `CreateCleanRoomAutoApprovalRuleRequest`, + `DeleteCleanRoomAutoApprovalRuleRequest`, + `GetCleanRoomAutoApprovalRuleRequest`, + `ListCleanRoomAutoApprovalRulesRequest`, + `ListCleanRoomAutoApprovalRulesResponse`, + `UpdateCleanRoomAutoApprovalRuleRequest`): Fixed in regeneration on + 2026-05-20 — package consolidated into `@databricks/sdk-cleanrooms/v1`; + any remaining prefix concerns now tracked in `cleanrooms.md`. +- #2 Client methods restate the package name (originally cited at + `src/v1/client.ts`, affected `createCleanRoomAutoApprovalRule`, + `deleteCleanRoomAutoApprovalRule`, `getCleanRoomAutoApprovalRule`, + `listCleanRoomAutoApprovalRules`, `listCleanRoomAutoApprovalRulesIter`, + `updateCleanRoomAutoApprovalRule`): Fixed in regeneration on 2026-05-20 — + methods moved onto `@databricks/sdk-cleanrooms/v1` `Client`, where the + prefix is no longer redundant against the package name; tracked under + `cleanrooms.md`. +- #3 Enum members repeat the enum name (originally cited at + `src/v1/model.ts`, `CleanRoomAutoApprovalRule_AuthorScope`): Fixed in + regeneration on 2026-05-20 — enum moved into + `@databricks/sdk-cleanrooms/v1/model.ts:148`; concern (if any) now tracked + in `cleanrooms.md`. +- #4 `AUTHOR_SCOPE_UNSPECIFIED` is a leaked-protobuf sentinel (originally + cited at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — enum + moved into `cleanrooms` package; the proto-sentinel finding class was + later promoted to a generator-only recommendation in `_SUMMARY.md`. +- #5 Discriminator-tag value duplicates the field name (originally cited at + `src/v1/model.ts`, `authors` discriminated union): Fixed in regeneration + on 2026-05-20 — union moved into `cleanrooms` package; concern (if any) + tracked in `cleanrooms.md`. +- #6 `authors` / `runners` are misleading plurals on a single-author/runner + union (originally cited at `src/v1/model.ts`): Fixed in regeneration on + 2026-05-20 — fields moved into `cleanrooms` package; concern (if any) + tracked in `cleanrooms.md`. +- #7 `runnerCollaboratorAlias` doubles `runner` (originally cited at + `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — field moved + into `cleanrooms` package; concern (if any) tracked in `cleanrooms.md`. +- #8 `ruleOwnerCollaboratorAlias` / `authorCollaboratorAlias` / + `runnerCollaboratorAlias` verbose / cryptic suffix (originally cited at + `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — fields moved + into `cleanrooms` package; concern (if any) tracked in `cleanrooms.md`. +- #9 `ruleId` is underspecified (originally cited at + `src/v1/model.ts`, request types): Fixed in regeneration on 2026-05-20 — + fields moved into `cleanrooms` package; concern (if any) tracked in + `cleanrooms.md`. +- #10 `Client` is a generic class name (originally cited at + `src/v1/client.ts`): Fixed in regeneration on 2026-05-20 — package deleted + and methods moved to the existing `cleanrooms` `Client`; the cross-package + bare-`Client` concern is tracked once in `_SUMMARY.md`. +- #11 `nextPageToken` / `pageToken` duplicated across response/request + (originally cited at `src/v1/model.ts`, informational): Fixed in + regeneration on 2026-05-20 — pagination types moved into `cleanrooms`; + the pattern was logged repo-wide as the standard pagination convention. +- #12 Doc references undefined casing (`snake_case` field names in JSDoc; + originally cited at `src/v1/model.ts`): Fixed in regeneration on + 2026-05-20 — doc copy moved with the symbols into `cleanrooms`; concern + (if any) tracked in `cleanrooms.md`. +- #13 Docs say "a auto-approval rule" typo (originally cited at + `src/v1/client.ts:96`, `:115`, `:194`): Fixed in regeneration on + 2026-05-20 — generator template no longer emits the article-noun + agreement bug. +- #14 `Client` constructor field `userAgent` vague (originally cited at + `src/v1/client.ts:49`): Fixed in regeneration on 2026-05-20 — field moved + with the methods into `cleanrooms` `Client`; the cross-package + `userAgent` field concern is tracked once in `_SUMMARY.md`. +- #15 `utils.ts` is a kitchen-sink module name (originally cited at + `src/v1/utils.ts`): Fixed in regeneration on 2026-05-20 — module deleted + with the package; the cross-package `utils.ts` concern is recorded once + in `_SUMMARY.md` as a generator-level item. +- #16 Method docstrings use "rule ID" inconsistently with field name + (originally cited at `src/v1/client.ts`): Fixed in regeneration on + 2026-05-20 — docstrings moved with the methods into `cleanrooms` `Client`; + concern (if any) tracked in `cleanrooms.md`. +- #17 `cleanRoomName` is the identifier doing double duty (originally cited + at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — field moved + into `cleanrooms` package; the cross-package "name-as-ID" concern is + tracked in `cleanrooms.md`. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index 7c0eeffc..7121996f 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -12,175 +12,91 @@ grouped by category, and each finding cites the file/line where it appears. ## Summary -- **Total findings:** 30 +- **Total findings:** 28 - **Highest-impact themes:** - 1. Massive redundant enum-prefix tautology - (`INTERNET_DESTINATION_TYPE_UNSPECIFIED`, `LOG_ONLY_MODE_TYPE_UNSPECIFIED`, - `OUTPUT_CATALOG_STATUS_UNSPECIFIED`, …) — each enum member repeats the - enum-name domain. - 2. Several field names use vague or generic terms (`type`, `protocol`, + 1. Several field names use vague or generic terms (`type`, `protocol`, `name`, `destination`, `status`) that lose meaning out of context. - 3. Misleading field names (`remoteDetailedInfo`, boolean-shaped - `accessRestricted` enum, predicate-form `enableSharedOutput`). + 2. Misleading field names (`remoteDetailedInfo`, boolean-shaped + `accessRestricted` enum). + 3. Cloud-asymmetric fields (`bucketName` vs. `azureContainer`) leak + cloud taxonomy into a single struct. + 4. Proto-architectural leaks: stray `Handler` suffix on list methods + for notebook task runs. --- ## 1. Vague / Generic Names -### 1.1 `name?: string` on `CleanRoom` (model.ts:142) +### 1.1 `name?: string` on `CleanRoom` (model.ts:247) The top-level field `name` is the clean room identifier. Combined with the request shape `GetCleanRoomRequest { name }`, the name "name" is too generic — there is no signal that this is a UC securable name vs. a display name vs. a UUID. Go SDK has the same problem, but consider `cleanRoomName`. ### 1.2 `name?: string` on `GetCleanRoomRequest`, `DeleteCleanRoomRequest`, -`UpdateCleanRoomRequest` (model.ts:273, 346, 367) +`UpdateCleanRoomRequest` (model.ts:836, 738, 1009) Same issue — when used inside a request DTO, `name` is ambiguous as to **which** name. `cleanRoomName` would self-document. The request schema in `CreateCleanRoomOutputCatalogRequest` uses the more specific -`cleanRoomName` (model.ts:259), so the codebase is inconsistent with itself. +`cleanRoomName` (model.ts:703), so the codebase is inconsistent with itself. -### 1.3 `type?: ...InternetDestinationType` (model.ts:312) +### 1.3 `type?: ...InternetDestinationType` (model.ts:777) The field `type` on `InternetDestination` is generic. `destinationType` or `kind` would be clearer at call sites (`internetDestination.type === FQDN` reads as a meta-property). -### 1.4 `type?: ...StorageDestinationType` (model.ts:335) +### 1.4 `type?: ...StorageDestinationType` (model.ts:800) Same issue on `StorageDestination` — bare `type` field. -### 1.5 `protocol?: ...InternetDestinationFilteringProtocol` (model.ts:315) +### 1.5 `protocol?: ...InternetDestinationFilteringProtocol` (model.ts:780) `protocol` is generic. A consumer cannot tell from `destination.protocol` whether this is TCP/UDP/HTTP/SSH/etc. `filteringProtocol` matches the underlying enum semantics. -### 1.6 `destination?: string` (model.ts:311) +### 1.6 `destination?: string` (model.ts:776) Bare `destination` on `InternetDestination` is tautological with its container. The string is the FQDN/hostname/IP literal. `value` or `fqdn`/`host` would convey intent. -### 1.7 `region?: string` (model.ts:232, 334) +### 1.7 `region?: string` (model.ts:581, 799) `region` field appears on both `CleanRoomRemoteDetail` (cloud region) and `StorageDestination` (bucket region). Not necessarily wrong, but the ambiguity is worth noting — `cloudRegion` / `bucketRegion` would disambiguate. -### 1.8 `workloads?: WorkloadType[]` (model.ts:325) +### 1.8 `workloads?: WorkloadType[]` (model.ts:790) On `LogOnlyMode`, the field `workloads` is plural-of-type. `workloadTypes` -would match the enum. (See also §6 — singular/plural mismatch.) +would match the enum. (See also §4 — singular/plural mismatch.) --- -## 2. Redundant Enum Prefixes (the most pervasive issue) +## 2. Acronym Casing Inconsistencies -Every enum redundantly prefixes the type's own name onto its `UNSPECIFIED` -member, and often onto all members. Idiomatic TS uses bare member names -(e.g., `Status.Active`, not `Status.STATUS_ACTIVE`), since the enum-name -qualifier is already present at every call site. - -### 2.1 `ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` (model.ts:8) -Should be `UNSPECIFIED`. Consumers write -`ComplianceStandard.COMPLIANCE_STANDARD_UNSPECIFIED` which is doubly redundant. - -### 2.2 `CleanRoomOutputCatalog_OutputCatalogStatus.OUTPUT_CATALOG_STATUS_UNSPECIFIED` -(model.ts:71) -Should be `UNSPECIFIED`. `OUTPUT_CATALOG_STATUS` is already in the enum name. - -### 2.3 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol.INTERNET_DESTINATION_FILTERING_PROTOCOL_UNSPECIFIED` -(model.ts:88) -The enum member redundantly repeats the trailing -`INTERNET_DESTINATION_FILTERING_PROTOCOL` segment of the enum name. - -### 2.4 `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationType.INTERNET_DESTINATION_TYPE_UNSPECIFIED` -(model.ts:94) -Same pattern — member repeats the `INTERNET_DESTINATION_TYPE` segment of -the enum name. - -### 2.5 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_LogOnlyModeType.LOG_ONLY_MODE_TYPE_UNSPECIFIED` -(model.ts:100) -Same pattern. - -### 2.6 `EgressNetworkPolicy_InternetAccessPolicy_LogOnlyMode_WorkloadType.WORKLOAD_TYPE_UNSPECIFIED` -(model.ts:108) -Same pattern. - -### 2.7 `EgressNetworkPolicy_InternetAccessPolicy_RestrictionMode.RESTRICTION_MODE_UNSPECIFIED` -(model.ts:122) -Same pattern. - -### 2.8 `EgressNetworkPolicy_InternetAccessPolicy_StorageDestination_StorageDestinationType.STORAGE_DESTINATION_TYPE_UNSPECIFIED` -(model.ts:130) -Same pattern. - -Cumulatively: every enum's `UNSPECIFIED` sentinel is redundantly prefixed. - ---- - -## 3. Acronym Casing Inconsistencies - -### 3.1 `centralCleanRoomId` (model.ts:228) +### 2.1 `centralCleanRoomId` (model.ts:577) Uses `Id` (lowercase `d`). Elsewhere `globalMetastoreId`, `inviteRecipientWorkspaceId` — consistent within this file as `Id`. But Google TypeScript Style Guide § 5.3 recommends `ID` (treat as acronym). The package is internally consistent (all `Id`); the issue is whether to upgrade to `ID` across the SDK. **Note:** repo-wide convention should be confirmed. -### 3.2 `azureDnsZone` (model.ts:341) +### 2.2 `azureDnsZone` (model.ts:806) "DNS" is an initialism. Per the style guide, `azureDNSZone`. Currently `azureDnsZone` treats DNS as a word. -### 3.3 `cloudVendor?: string` containing `aws`, `azure`, `gcp` (model.ts:230) +### 2.3 `cloudVendor?: string` containing `aws`, `azure`, `gcp` (model.ts:579) Doc comment uses lowercase `aws,azure,gcp`. These are acronyms — should be `AWS`, `Azure`, `GCP`. (Doc-only, but inconsistent with the enum members `AWS_S3`, `AZURE_STORAGE`, `GOOGLE_CLOUD_STORAGE`.) -### 3.4 `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5` (model.ts:17, 20, 21) +### 2.4 `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5` (model.ts:82, 85, 86) "FedRAMP" is the official spelling — `FEDRAMP` flattens the casing. Identifier-level constraint of SCREAMING_SNAKE is fine, but documentation text should match. -### 3.5 `K_FSI` (model.ts:42) -"K-FSI" abbreviates "Korea Financial Security Institute." A bare leading -single letter (`K_`) is cryptic. `KFSI` or `KOREA_FSI` reads better. - -### 3.6 `IRAP_PROTECTED` (model.ts:18) -"IRAP" is the Information Security Registered Assessors Program. OK as-is, -but worth noting the `_PROTECTED` suffix encodes a level — fine. - --- -## 4. Cryptic Abbreviations - -### 4.1 `K_FSI` (model.ts:42) -Bare `K_FSI` is cryptic without the comment "Korea Financial Security -Institute." See §3.5 above. - -### 4.2 `ARC_AMPE` (model.ts:51) -"Acceptable Risk Controls for ACA, Medicaid, and Partner Entities" — five -words compressed into eight characters. Without the doc-comment, opaque. - -### 4.3 `ESC` in `ComplianceStandard.NONE` JSDoc (model.ts:11) -Documentation acronym only — but ESC = Enhanced Security Compliance is -unexplained at first reference. +## 3. Misleading Names -### 4.4 `CSP` doc comment on `accessRestricted` (model.ts:166) -"CSP" abbreviation linked but not spelled. The enum constant -`CSP_MISMATCH` (model.ts:57) also uses the bare acronym. - -### 4.5 `FQDN` enum value (model.ts:95) -"Fully Qualified Domain Name" — well-known enough in networking, OK. - -### 4.6 `SEG`, `DP`, `UC`, `SNI` in JSDoc (model.ts:82, 117, 217) -Doc-only abbreviations: SEG (Secure Egress Gateway?), DP (Data Plane?), -UC (Unity Catalog), SNI (Server Name Indication). UC is well-established in -this codebase; SEG/DP/SNI need expansion. - -### 4.7 `DBSQL` (model.ts:109) -"Databricks SQL" — familiar to Databricks customers, OK in context. - ---- - -## 5. Misleading Names - -### 5.1 `remoteDetailedInfo` (model.ts:148) +### 3.1 `remoteDetailedInfo` (model.ts:253) Field name suggests "verbose info about a remote endpoint." Actually contains the central clean room state (collaborators, network policy, compliance) — the meaty payload of `CleanRoom`. JSON tag is @@ -188,37 +104,33 @@ compliance) — the meaty payload of `CleanRoom`. JSON tag is no "Info"). The name is **misleading** and **internally inconsistent with its type**: field says `remoteDetailedInfo`, type says `RemoteDetail`. -### 5.2 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:166) +### 3.2 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:271) Reads as a boolean ("is access restricted?"). It is actually an enum with values `NO_RESTRICTION` and `CSP_MISMATCH`. `accessRestrictedReason` or `accessRestriction` would not suggest a boolean. The JSDoc reinforces the miscommunication: "Whether clean room access is restricted…" — implying a -yes/no. +yes/no. The shape itself is boolean-like (two values, one of which is the +absence sentinel) — a `boolean` field would model the domain more +honestly. -### 5.3 `enableSharedOutput?: boolean` (model.ts:173) -The verb `enable` reads as imperative/action. For a state field a -participial/predicate name is clearer: `sharedOutputEnabled`. The JSDoc -itself notes the field is slated for deprecation. - -### 5.4 `isEnabled?: boolean` on `ComplianceSecurityProfile` (model.ts:252) +### 3.3 `isEnabled?: boolean` on `ComplianceSecurityProfile` (model.ts:664) The `is` prefix is acceptable, but inside an object literal one writes `profile.isEnabled` (reading "is enabled" of a non-question subject) which becomes awkward; simply `enabled` is more idiomatic and aligns with -JavaScript norms (HTML `disabled`, `aria-disabled`, etc.). Note the -inconsistency: `isEnabled` here vs. `enableSharedOutput` on `CleanRoom`. +JavaScript norms (HTML `disabled`, `aria-disabled`, etc.). -### 5.5 `logOnlyMode?: ...LogOnlyMode` (model.ts:299) +### 3.4 `logOnlyMode?: ...LogOnlyMode` (model.ts:764) Field name and type name both have `LogOnlyMode`. But the field's container already declares "this is the LogOnlyMode submessage" — `logOnly` would suffice. -### 5.6 `localCollaboratorAlias?: string` (model.ts:159) vs. -`collaboratorAlias` on `CleanRoomCollaborator` (model.ts:206) +### 3.5 `localCollaboratorAlias?: string` (model.ts:264) vs. +`collaboratorAlias` on `CleanRoomCollaborator` (model.ts:515) The "local" prefix here is a fragment of metastore-domain jargon. A reader who does not already know about "single-metastore vs. x-metastore" clean rooms cannot tell what "local" means. -### 5.7 `CreateCleanRoomWaiter` class (client.ts:289) +### 3.6 `CreateCleanRoomWaiter` class (client.ts:816) The waiter polls `getCleanRoom` and resolves when status reaches `ACTIVE`. Naming it `CreateCleanRoomWaiter` ties it to `createCleanRoom`, but the waiter is operationally generic (any clean room name can be polled). A @@ -226,99 +138,69 @@ better name is `CleanRoomActivationWaiter` or `CleanRoomStatusWaiter`. --- -## 6. Singular / Plural Mismatches +## 4. Singular / Plural Mismatches -### 6.1 `workloads?: WorkloadType[]` (model.ts:325) +### 4.1 `workloads?: WorkloadType[]` (model.ts:790) Field is plural and array-typed, but the element type is **`WorkloadType`** (singular noun + `Type` suffix). Consumers write `mode.workloads[0]` which is a `WorkloadType` — readable, but the field could be `workloadTypes` to match the element. Alternative: rename the enum to `Workload`. -### 6.2 `cleanRooms?: CleanRoom[]` on `ListCleanRoomsResponse` (model.ts:357) -Correctly plural — flagged only as a positive example. - -### 6.3 `collaborators?: CleanRoomCollaborator[]` (model.ts:241) -Correctly plural — positive example. - -### 6.4 `complianceStandards?: ComplianceStandard[]` (model.ts:254) +### 4.2 `complianceStandards?: ComplianceStandard[]` (model.ts:666) Correctly plural. But `allowedInternetDestinations` and -`allowedStorageDestinations` (model.ts:292, 295) inherit the `allowed` +`allowedStorageDestinations` (model.ts:757, 760) inherit the `allowed` prefix; while the parent `restrictionMode` is singular. Mild inconsistency. -### 6.5 `allowedPaths?: string[]` (model.ts:339) -Correctly plural. - ---- - -## 7. Reserved-Word / Built-in Collisions - -### 7.1 `type` field on `InternetDestination` and `StorageDestination` -(model.ts:312, 335) -`type` is not a reserved word in TS at field position, but it shadows the -TS `typeof` semantics in conversation and may collide with linters that -flag it. `kind` is the established alternative (tagged-union convention). -Note: TypeScript's discriminated-union pattern often uses literal `type` — -so this is a soft flag. - -### 7.2 `status` field appears on `CleanRoom` and `CleanRoomOutputCatalog` -Not a reserved word; raised here to highlight the duplication. See §8. - --- -## 8. Duplicate Concepts +## 5. Duplicate Concepts -### 8.1 Two `Status` enums -- `CleanRoom.status: CleanRoom_Status_Enum` (model.ts:157) +### 5.1 Two `Status` enums +- `CleanRoom.status: CleanRoom_Status_Enum` (model.ts:262) - `CleanRoomOutputCatalog.status: CleanRoomOutputCatalog_OutputCatalogStatus` - (model.ts:216) + (model.ts:565) Two distinct, non-overlapping `Status` enums. The two enum types should consider naming themselves unambiguously: `CleanRoomStatus`, `OutputCatalogStatus`. -### 8.2 `CleanRoomCollaborator` overlap with `cleanroomtaskruns.CollaboratorJobRunInfo` -(cross-package) -`cleanroomtaskruns/src/v1/model.ts` defines `CollaboratorJobRunInfo`. Both -packages now have a "Collaborator-prefixed" surface; consumers must keep -both straight. Not a rename target inside `cleanrooms`, but a -cross-package risk: a third "collaborator" type in another package would -make disambiguation tedious. - -### 8.3 `creator?: CleanRoomCollaborator` (model.ts:243) vs. -`collaborators?: CleanRoomCollaborator[]` (model.ts:241) +### 5.2 `creator?: CleanRoomCollaborator` (model.ts:592) vs. +`collaborators?: CleanRoomCollaborator[]` (model.ts:590) Per the JSDoc, `creator` is also **one of the collaborators in the collaborators list**. So we have the same logical entity reachable through two paths. Mild — not a renamed-target, but flagged as a shape concern. -### 8.4 `cleanRoomName` (model.ts:259) vs. `name` (model.ts:142, 273, 346, 367) +### 5.3 `cleanRoomName` (model.ts:703) vs. `name` (model.ts:247, 836, 738, 1009) Two names for the same thing: the clean-room identifier. Picking one consistently would simplify call sites. ---- +### 5.4 `CleanRoomCollaborator` (model.ts:490) vs. +`CollaboratorJobRunInfo` (model.ts:606) +Both types now live in `cleanrooms` (the `cleanroomtaskruns` package was +consolidated into `cleanrooms`). Within the package, two "Collaborator- +prefixed" surfaces model different aspects of collaborators with different +prefixes. Consistency would suggest renaming `CollaboratorJobRunInfo` to +`CleanRoomCollaboratorJobRunInfo`. -## 9. Verb-Tense Inconsistency +--- -### 9.1 `enableSharedOutput` (verb, imperative) vs. `isEnabled` -(participle, predicate) — see §5.3 and §5.4 above. +## 6. Inconsistent Action Verbs -### 9.2 Method verbs are consistent (create/get/list/update/delete) — -positive example. +### 6.1 `createCleanRoom` returns the new clean room (client.ts:120); +`createCleanRoomOutputCatalog` returns a **response wrapper** +(`CreateCleanRoomOutputCatalogResponse`) (client.ts:250). +Inconsistent return shapes for two `create*` methods. The Go SDK has the +same wart, but it surfaces here as inconsistent ergonomics: +`(await c.createCleanRoom(...)).name` vs. +`(await c.createCleanRoomOutputCatalog(...)).outputCatalog?.catalogName`. --- -## 10. Generic Field Names Losing Meaning Out of Context - -### 10.1 `destination`, `type`, `protocol` on `InternetDestination` -(model.ts:311–315) -Read in isolation, these are completely opaque. Cross-reference §1.3–§1.6. - -### 10.2 `name`, `comment`, `owner` on `CleanRoom` (model.ts:142, 151, 150) -`owner` is a username string; `comment` is a free-text description; -`name` is a UC securable identifier. None of these self-describe. +## 7. Cloud Asymmetry / Cross-Cloud Field Naming -### 10.3 `bucketName`, `region`, `type`, `azureStorageAccount`, +### 7.1 `bucketName`, `region`, `type`, `azureStorageAccount`, `allowedPaths`, `azureStorageService`, `azureDnsZone`, `azureContainer` -on `StorageDestination` (model.ts:333–343) +on `StorageDestination` (model.ts:798–807) The same struct mixes AWS-, Azure-, and GCP-shaped fields. `bucketName` is S3-flavored; `azureStorageAccount` is Azure-flavored. The fact that the fields share one struct **and** the field names are not prefixed with the @@ -327,94 +209,34 @@ field naming inconsistently. --- -## 11. Field Contradicting Type Domain +## 8. Cross-Package Overlap -### 11.1 `CleanRoomRemoteDetail.region: string` (model.ts:232) -Type is `string`, but the domain is "a cloud region identifier -(`us-east-1`, `westeurope`, etc.)" — the type should be a tagged-string -or a region enum. Minor. - -### 11.2 `cloudVendor: string` (model.ts:230) -Same — should be an enum (the cloud SDK packages already have one). - -### 11.3 `enableSharedOutput` (boolean) vs. the JSDoc "shared output PrPr" -(private preview) — the field is a feature flag fronted as a permanent API, -not labelled `experimental` (model.ts:173). Minor. - -### 11.4 `createdAt`, `updatedAt: number` (model.ts:153, 155) -Stored as **epoch milliseconds** per JSDoc but typed as `number` rather -than a branded `EpochMillis` or `Timestamp`. Loses semantic information -in the type system. (Repo-wide pattern; flag once.) - -### 11.5 `inviteRecipientWorkspaceId: number` (model.ts:194) -Workspace IDs are int64 in Databricks; TS `number` is 53-bit. Latent -precision loss for IDs above 2^53. The proto schema would use int64. Not -a naming concern, but the field name does not warn (e.g., -`inviteRecipientWorkspaceIdRaw` / docs). +_None._ --- -## 12. Inconsistent Action Verbs - -The five RPC methods follow the standard CRUD verbs: -`createCleanRoom`, `createCleanRoomOutputCatalog`, `deleteCleanRoom`, -`getCleanRoom`, `listCleanRooms`, `updateCleanRoom`. - -### 12.1 `createCleanRoom` returns the new clean room (client.ts:85); -`createCleanRoomOutputCatalog` returns a **response wrapper** -(`CreateCleanRoomOutputCatalogResponse`) (client.ts:122). -Inconsistent return shapes for two `create*` methods. The Go SDK has the -same wart, but it surfaces here as inconsistent ergonomics: -`(await c.createCleanRoom(...)).name` vs. -`(await c.createCleanRoomOutputCatalog(...)).outputCatalog?.catalogName`. - ---- - -## 13. Underspecified IDs - -### 13.1 `centralCleanRoomId?: string` (model.ts:228) -String ID — no JSDoc explanation of format (UUID? Numeric? Free-form?). -Per JSDoc on `globalMetastoreId`: "cloud:region:metastore-uuid" — at least -that one is documented. - -### 13.2 `globalMetastoreId?: string` (model.ts:183) — Documented; positive example. - -### 13.3 `inviteRecipientWorkspaceId?: number` (model.ts:194) -ID typed as `number` and undocumented format — see §11.5 on precision risk. - -### 13.4 `bucketName?: string` (model.ts:333) -Bucket name vs. ARN vs. URI — not specified. Could be S3 bucket name or -GCS bucket name; both share the field. - -### 13.5 `azureStorageAccount?: string` (model.ts:338), -`azureStorageService?: string` (model.ts:340), -`azureContainer?: string` (model.ts:342) -Three Azure identifiers, no JSDoc explaining accepted formats. - ---- - -## Cross-Package Overlap (cleanrooms vs. cleanroomassets / -cleanroomautoapprovalrules / cleanroomtaskruns) - -### CP.1 Shared concept: "clean room" -All four packages use `CleanRoom*` types. None re-imports the canonical -`CleanRoom` from `cleanrooms`; instead each refers to the clean room by -its name (string identifier in URL paths). -There is **no shared `CleanRoom` interface or alias** despite all four -packages keying off the same entity. This is a structural concern, not a -naming concern — flagged once. - -### CP.2 `CleanRoomCollaborator` (cleanrooms) vs. -`CollaboratorJobRunInfo` (cleanroomtaskruns) -The packages model different *aspects* of collaborators with different -prefixes. Consistency would suggest `CleanRoomCollaboratorJobRunInfo` or -moving the type into cleanrooms. Minor. - -### CP.3 Resource-name pattern repetition -`cleanrooms` uses `name` as the clean room identifier in request/response -shapes (§1.2). `cleanroomassets` and `cleanroomautoapprovalrules` will -share the same `name` slot — risk of collision when shapes interact in -generic code. +## 9. Proto / Architectural Leaks + +### 9.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:612 +- **Why:** Mid/end-position `Handler` on a public method (not a domain term). + All sibling list methods (`listCleanRooms`, `listCleanRoomAssets`, + `listCleanRoomAutoApprovalRules`) omit the `Handler` suffix. The stray + `Handler` leaks the backend RPC handler naming into the SDK surface. +- **Category:** Architectural leak (server-side terminology). +- **Suggested:** `listCleanRoomNotebookTaskRuns`. +- **Rationale:** Consumers should not see backend-implementation terms + like `Handler` in client-method names; consistency with the other + `list*` methods is the principal benefit. + +### 9.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:651 +- **Why:** Same stray `Handler` infix in the async-iterator companion to + §9.1. Sibling iterators (`listCleanRoomsIter`, + `listCleanRoomAssetsIter`, `listCleanRoomAutoApprovalRulesIter`) follow + the `Iter` pattern without `Handler`. +- **Category:** Architectural leak (server-side terminology). +- **Suggested:** `listCleanRoomNotebookTaskRunsIter`. +- **Rationale:** Must rename in lock-step with §9.1 so the iterator name + derives cleanly from the base method. --- @@ -425,7 +247,18 @@ generic code. use correct plurality. - JSDoc is generally comprehensive — references to UC naming rules and external compliance documents are well-linked. -- The `StillRunningError` class (client.ts:48) is concise and +- The `StillRunningError` class (client.ts:83) is concise and self-documenting. -- The package-level segment naming (`PACKAGE_SEGMENT` in client.ts:43) +- The package-level segment naming (`PACKAGE_SEGMENT` in client.ts:78) is appropriately namespaced. + +--- + +## Fixed + +- #4.2 `ARC_AMPE` (originally cited at model.ts:51): Fixed in regeneration on 2026-05-20 — enum value no longer present in `ComplianceStandard`. +- #5.3 `enableSharedOutput?: boolean` (originally cited at model.ts:173): Fixed in regeneration on 2026-05-20 — field removed from `CleanRoom`. +- #5.2 `CleanRoomCollaborator` overlap with `cleanroomtaskruns.CollaboratorJobRunInfo`: Fixed in regeneration on 2026-05-22 — the `cleanroomtaskruns` package was consolidated into `cleanrooms`, eliminating the cross-package overlap concern. In-package overlap is now tracked under §5.4. +- #8.1 Cross-package shared "clean room" concept across `cleanrooms` / `cleanroomassets` / `cleanroomautoapprovalrules` / `cleanroomtaskruns`: Fixed in regeneration on 2026-05-22 — the three sibling packages were consolidated into `cleanrooms`, so all `CleanRoom*` types now live in a single canonical package. +- #8.2 Cross-package `CleanRoomCollaborator` (cleanrooms) vs. `CollaboratorJobRunInfo` (cleanroomtaskruns): Fixed in regeneration on 2026-05-22 — packages consolidated; the in-package concern is tracked under §5.4. +- #8.3 Cross-package resource-name pattern repetition (`name` slot across cleanrooms / cleanroomassets / cleanroomautoapprovalrules): Fixed in regeneration on 2026-05-22 — sibling packages consolidated into `cleanrooms`, eliminating cross-package shape-collision risk. diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md index 09a5f236..fab10b96 100644 --- a/.agent/naming-audit/cleanroomtaskruns.md +++ b/.agent/naming-audit/cleanroomtaskruns.md @@ -1,6 +1,12 @@ # Naming Audit: `cleanroomtaskruns` (v1) -**Path:** `/home/parth.bansal/sdk-js/packages/cleanroomtaskruns/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `/home/parth.bansal/sdk-js/packages/cleanrooms/` (merged into the +`cleanrooms` package; cleanroomtaskruns symbols are now generated alongside +the other clean-room types). **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Reference:** `databricks/databricks-sdk-go` `service/cleanrooms/{api,impl,model,interface}.go` and sibling TS packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules`, `jobs/v2`). @@ -19,19 +25,18 @@ `UPSTREAM_EVICTED`, `DISABLED`. ### Interfaces / Types -1. `CleanRoomNotebookTaskRun` (model.ts:44) +1. `CleanRoomNotebookTaskRun` (model.ts:538) - Fields: `notebookName`, `startTime`, `runDuration`, `notebookJobRunState`, `collaboratorJobRunInfo`, `outputSchemaName`, `outputSchemaExpirationTime`, - `notebookEtag`, `notebookUpdatedAt`, `sharedOutputSchemaName`, - `sharedOutputSchemaExpirationTime`. -2. `CleanRoomTaskRunState` (model.ts:78) + `notebookEtag`, `notebookUpdatedAt`. +2. `CleanRoomTaskRunState` (model.ts:599) - Fields: `lifeCycleState`, `resultState`. -3. `CollaboratorJobRunInfo` (model.ts:85) +3. `CollaboratorJobRunInfo` (model.ts:606) - Fields: `collaboratorJobId`, `collaboratorJobRunId`, `collaboratorTaskRunId`, `collaboratorWorkspaceId`, `collaboratorAlias`. -4. `ListCleanRoomNotebookTaskRunsRequest` (model.ts:98) +4. `ListCleanRoomNotebookTaskRunsRequest` (model.ts:891) - Fields: `cleanRoomName`, `notebookName`, `pageSize`, `pageToken`. -5. `ListCleanRoomNotebookTaskRunsResponse` (model.ts:109) +5. `ListCleanRoomNotebookTaskRunsResponse` (model.ts:902) - Fields: `runs`, `nextPageToken`. ### Zod schemas @@ -41,8 +46,8 @@ - `unmarshalListCleanRoomNotebookTaskRunsResponseSchema` ### Client class -- `Client` (client.ts:32) - - Methods: `listCleanRoomNotebookTaskRunsHandler`, +- `Client` (client.ts:85) + - Task-runs methods: `listCleanRoomNotebookTaskRunsHandler`, `listCleanRoomNotebookTaskRunsHandlerIter`. - Private fields: `host`, `httpClient`, `logger`, `userAgent`. - Module constant: `PACKAGE_SEGMENT`. @@ -58,16 +63,16 @@ ### 1. `Handler` suffix on client methods — category 7 (Overly verbose) and category 14 (Go/Java-style names) -**Symbol:** `Client.listCleanRoomNotebookTaskRunsHandler`, `Client.listCleanRoomNotebookTaskRunsHandlerIter` (client.ts:58, 97). +**Symbol:** `Client.listCleanRoomNotebookTaskRunsHandler`, `Client.listCleanRoomNotebookTaskRunsHandlerIter` (client.ts:612, 651). **Issue:** The `Handler` suffix is anomalous within the SDK. Every other clean-room -package method (`cleanrooms.listCleanRooms`, `cleanroomassets.listCleanRoomAssets`, -`cleanroomautoapprovalrules.listCleanRoomAutoApprovalRules`) uses the bare verb form -without `Handler`. The Go reference API (`CleanRoomTaskRunsAPI.List`, -`ListByCleanRoomName`) does not use `Handler` either; "Handler" is an HTTP-server -concept, not a client method idiom. The suffix adds eight characters that convey -nothing — the method already takes a request and returns a response, which is the -contract of a "handler" in API parlance. +method on the same client (`listCleanRooms`, `listCleanRoomAssets`, +`listCleanRoomAutoApprovalRules`) uses the bare verb form without `Handler`. The +Go reference API (`CleanRoomTaskRunsAPI.List`, `ListByCleanRoomName`) does not +use `Handler` either; "Handler" is an HTTP-server concept, not a client method +idiom. The suffix adds eight characters that convey nothing — the method already +takes a request and returns a response, which is the contract of a "handler" in +API parlance. **Suggested:** `listCleanRoomNotebookTaskRuns` and `listCleanRoomNotebookTaskRunsIter`. @@ -79,7 +84,7 @@ camelCase `listX` style without Java/Go-style `Handler` decoration). ### 2. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) **Symbols:** Enum `CleanRoomTaskRunLifeCycleState` and field -`CleanRoomTaskRunState.lifeCycleState` (model.ts:9, 80). +`CleanRoomTaskRunState.lifeCycleState` (model.ts:9, 601). **Issue:** "Lifecycle" is a single compound word in English (Merriam-Webster lists it as one closed word). Treating it as two words (`LifeCycle` / `lifeCycle`) @@ -103,8 +108,8 @@ forming a real word. Adjacent values use correct past-tense English ### 4. `etag` lowercase abbreviation — category 3 (Acronym casing) -**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65) and wire field -`notebook_etag` (line 133). +**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:559) and wire field +`notebook_etag` (line 1306). **Issue:** "ETag" is an HTTP standard token defined in RFC 7232 §2.3 ("entity tag") and is written `ETag` in HTTP headers and most APIs. The TS Style Guide acronym @@ -117,10 +122,10 @@ consistent within the codebase but worth re-examining at the SDK level. ### 5. `notebookEtag` belongs to the notebook, not the task run — category 16 (Field contradicting type domain) -**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:65). +**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:559). **Issue:** Field doc says "Etag of the notebook executed in this task run". The -field name is fine, but contrast with `notebookUpdatedAt` (line 67) — the +field name is fine, but contrast with `notebookUpdatedAt` (line 561) — the combination `notebookEtag` + `notebookUpdatedAt` implies the entire task-run struct is mixing notebook metadata with run metadata. Consider whether these should live under a nested `notebook` sub-object (`notebook.etag`, @@ -128,7 +133,7 @@ should live under a nested `notebook` sub-object (`notebook.etag`, ### 6. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 (Duplicate concepts) -**Symbol:** `CleanRoomNotebookTaskRun.notebookJobRunState` (model.ts:52). +**Symbol:** `CleanRoomNotebookTaskRun.notebookJobRunState` (model.ts:546). **Issue:** The doc says "State of the task run". The struct is already a *task run*, and the same idea is also called a *Job run* by the collaborator field @@ -148,7 +153,7 @@ inherited). ### 7. `runDuration` vs implicit "task run" — category 15 (Generic field names losing meaning) -**Symbol:** `CleanRoomNotebookTaskRun.runDuration` (model.ts:50). +**Symbol:** `CleanRoomNotebookTaskRun.runDuration` (model.ts:544). **Issue:** The owning struct is already a "Run". Sibling fields drop the "run" prefix (`startTime`, not `runStartTime`; `notebookEtag`, not `runNotebookEtag`), @@ -158,33 +163,22 @@ yet duration carries it. Inconsistent. milliseconds"). Or rename `startTime` → `runStartTime` for consistency — pick one side. -### 8. `outputSchemaExpirationTime` / `sharedOutputSchemaExpirationTime` — verbose — category 7 (Overly verbose) +### 8. `outputSchemaExpirationTime` — verbose — category 7 (Overly verbose) -**Symbols:** model.ts:63, model.ts:73. +**Symbol:** `CleanRoomNotebookTaskRun.outputSchemaExpirationTime` (model.ts:557). **Issue:** `…Time` suffix is redundant; the value is a number (epoch ms). Compare to `startTime` which legitimately is "time", and `notebookUpdatedAt` -(line 67) which already uses the more idiomatic `At` suffix for an epoch +(line 561) which already uses the more idiomatic `At` suffix for an epoch millisecond timestamp. Within the *same struct*, three different conventions coexist: `…Time`, `…At`, and `runDuration` (numeric duration). Pick one. -**Suggested:** `outputSchemaExpiresAt`, `sharedOutputSchemaExpiresAt`, and -`startedAt` — or normalise all three to `…Time`. The `Run` pattern in other -Databricks APIs leans toward `…At`. - -### 9. `sharedOutputSchemaName` doc references missing `enable_shared_output` flag — category 6 (Misleading names) +**Suggested:** `outputSchemaExpiresAt` and `startedAt` — or normalise all three +to `…Time`. The `Run` pattern in other Databricks APIs leans toward `…At`. -**Symbol:** `CleanRoomNotebookTaskRun.sharedOutputSchemaName` (model.ts:72). +### 9. `CollaboratorJobRunInfo` repeats "collaborator" in every field — category 8 (Redundant suffixes) and category 2 (Redundant prefixes) -**Issue:** Doc says "accessible by all collaborators when enable_shared_output is -true". No such field exists in the request/response, and no `enableSharedOutput` -on the run struct. Either the doc references state stored elsewhere (probably on -the clean-room asset config), or the field is missing. Not a naming bug, but -flag for a doc rewording. - -### 10. `CollaboratorJobRunInfo` repeats "collaborator" in every field — category 8 (Redundant suffixes) and category 2 (Redundant prefixes) - -**Symbol:** `CollaboratorJobRunInfo` (model.ts:85). Fields: `collaboratorJobId`, +**Symbol:** `CollaboratorJobRunInfo` (model.ts:606). Fields: `collaboratorJobId`, `collaboratorJobRunId`, `collaboratorTaskRunId`, `collaboratorWorkspaceId`, `collaboratorAlias`. @@ -198,12 +192,12 @@ where the prefix is meaningful at the *top* level (`run.collaboratorJobRunInfo.c TS access lands one level deeper than the natural reading; the prefix is duplicate. Match the JS idiom: drop the prefix on the nested fields. -### 11. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 (Singular/plural mismatch on the broader concept) +### 10. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 (Singular/plural mismatch on the broader concept) -**Symbol:** `CollaboratorJobRunInfo` (model.ts:85). +**Symbol:** `CollaboratorJobRunInfo` (model.ts:606). **Issue:** Field `collaboratorTaskRunId` lives inside `CollaboratorJobRunInfo` -(model.ts:91). One struct uses both vocabulary domains. From Databricks docs: +(model.ts:612). One struct uses both vocabulary domains. From Databricks docs: a *Task run* is a single task within a *Job run* (a job can have N tasks). The field doc strings here use "task run" almost exclusively — `Job ID of the task run`, `Task run ID of the task run`, `triggered the task run`. The "Job Run" in @@ -211,9 +205,9 @@ the struct *name* is therefore misleading; a more accurate name is `CollaboratorTaskRunRef` or `CollaboratorRunRef`. Flag for coordination with API team — the Go SDK has the same name. Cross-reference `jobs/v2` to align. -### 12. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type `CleanRoomTaskRunState` — category 6 (Misleading names) +### 11. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type `CleanRoomTaskRunState` — category 6 (Misleading names) -**Symbols:** model.ts:78, model.ts:52. +**Symbols:** model.ts:599, model.ts:546. **Issue:** Three name layers for the same idea. The doc on `CleanRoomTaskRunState` says "Stores the run state of the clean rooms notebook @@ -224,9 +218,9 @@ calls the same thing `NotebookTaskRunOutput.runState`. Suggest aligning on keep the type name as-is (the wider SDK uses `…State` types throughout, e.g. `RunState`, `JobState`). -### 13. `pageSize` doc contradicts behaviour — category 6 (Misleading names) +### 12. `pageSize` doc contradicts behaviour — category 6 (Misleading names) -**Symbol:** `ListCleanRoomNotebookTaskRunsRequest.pageSize` (model.ts:104). +**Symbol:** `ListCleanRoomNotebookTaskRunsRequest.pageSize` (model.ts:897). **Issue:** Doc reads: "The maximum number of task runs to return. Currently ignored - all runs will be returned." If the field is currently ignored, the @@ -236,9 +230,9 @@ in JSDoc with a `@deprecated` tag so IDEs show strike-through. Naming-wise: `pageSize` is fine *if* it works; document the no-op via the deprecation tag, not just a sentence inside the doc. -### 14. `runs` field in response — category 15 (Generic field names losing meaning) — borderline acceptable +### 13. `runs` field in response — category 15 (Generic field names losing meaning) — borderline acceptable -**Symbol:** `ListCleanRoomNotebookTaskRunsResponse.runs` (model.ts:111). +**Symbol:** `ListCleanRoomNotebookTaskRunsResponse.runs` (model.ts:904). **Issue:** Generic given the package context, but defensible: this is the canonical "list" shape (`{ items, nextPageToken }`). The doc string on it ("Name @@ -246,30 +240,30 @@ of the clean room.") is *wrong* — copy-paste error from the request struct's `cleanRoomName` doc. Doc-text bug, not a naming bug, but worth flagging during a naming pass since reviewers will notice the field while reading docs. -### 15. `nextPageToken` is the canonical name — pass. +### 14. `nextPageToken` is the canonical name — pass. No issue. Matches all other listing responses in the SDK. -### 16. `Client` class name — category 1 (Vague/generic) — *pass* +### 15. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its -import path (e.g. `@databricks/sdk-cleanroomtaskruns/v1`). +import path (e.g. `@databricks/sdk-cleanrooms/v1`). -### 17. `userAgent` and `httpClient` — *pass* +### 16. `userAgent` and `httpClient` — *pass* Standard names; acronym handling is consistent (`Url` would be flagged but `HttpClient` is acceptable under the project rule and matches the imported type). -### 18. `flattenQueryParams` — *pass*, but unused (dead code) +### 17. `flattenQueryParams` — *pass*, but unused (dead code) **Symbol:** `flattenQueryParams` (utils.ts:123). **Issue:** Imported nowhere within this package's client (the `list` method builds -its querystring inline at client.ts:64–72). The helper is dead code in this +its querystring inline at client.ts:617–626). The helper is dead code in this package. Naming itself is fine. Suggest deleting or extracting to a shared utility in `@databricks/sdk-core/http`. -### 19. `readAll(body)` — *pass* +### 18. `readAll(body)` — *pass* Helper does what its name says. @@ -280,7 +274,7 @@ Helper does what its name says. ### `TaskRun` field-name divergence between `cleanroomtaskruns` and `jobs/v2` The state field that holds a `CleanRoomTaskRunState` is named `notebookJobRunState` -in this package (model.ts:52) and `cleanRoomJobRunState` in `jobs/v2` +in this package (model.ts:546) and `cleanRoomJobRunState` in `jobs/v2` (jobs/v2/model.ts:1158). Two names for one wire-level concept across the two packages that talk about the same run object. Audit category 12 (duplicate concepts) — coordinate a single field name across both packages. @@ -301,12 +295,23 @@ service name — but a reader is left to guess. ## Summary (counts) - **Critical / cross-package consistency:** 1 finding (#1 `Handler` suffix). -- **High (style guide violations):** 2 findings (#2 LifeCycle casing, #10 +- **High (style guide violations):** 2 findings (#2 LifeCycle casing, #9 collaborator prefix repetition). -- **Medium (naming clarity):** 7 findings (#3, #6, #7, #8, #11, #12, #13). -- **Low / project-wide convention notes:** 5 findings (#4, #5, #9, #14, #18) — +- **Medium (naming clarity):** 7 findings (#3, #6, #7, #8, #10, #11, #12). +- **Low / project-wide convention notes:** 4 findings (#4, #5, #13, #17) — some inherited from generator. -- **Pass / acceptable as-is:** 4 findings (#15, #16, #17, #19). +- **Pass / acceptable as-is:** 4 findings (#14, #15, #16, #18). -**Total flagged findings: 15** distinct items across audit categories (some +**Total flagged findings: 14** distinct items across audit categories (some findings touch multiple categories). + +--- + +## Fixed + +- #8 (partial) `sharedOutputSchemaExpirationTime` (originally cited at model.ts:73): Fixed in regeneration on 2026-05-20 — field removed from `CleanRoomNotebookTaskRun`; remaining `outputSchemaExpirationTime` retained as renumbered finding #8. +- #9 `sharedOutputSchemaName` doc references missing `enable_shared_output` flag (originally cited at model.ts:72): Fixed in regeneration on 2026-05-20 — `sharedOutputSchemaName` field removed from `CleanRoomNotebookTaskRun`, so the misleading doc is gone. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index 89a367e9..1048bf5c 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -12,7 +12,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 1. Vague / generic names -### 1.1 `Library.lib` — `model.ts:159` +### 1.1 `Library.lib` — `model.ts:61` - `Library` already names the concept; the inner discriminated-union field `lib` is a shortened duplicate of the parent type name. - The wire schema spreads the variants flat at the top level (`jar`, `egg`, @@ -22,30 +22,14 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: medium. Consumers must write `library.lib.jar` which reads as redundant. -### 1.2 `DefaultBaseEnvironment.message` — `model.ts:92` -- `message` is generic and could mean log message, error message, info text, - user-facing description, etc. Coupled with `status`, this is almost - certainly a status/error message. Name like `statusMessage` would be more - precise. -- Same issue on `DefaultBaseEnvironmentCache.message` (`model.ts:103`). -- Severity: low. - -### 1.3 `Environment.client` — `model.ts:116` -- Field is itself documented as deprecated ("Use `environment_version` - instead.") and the name `client` is opaque in this context (a client of - what?). The successor field `environmentVersion` is clearer. Cannot rename - without breaking the wire contract, but worth flagging that the name is - intrinsically misleading. -- Severity: medium (deprecated, but still visible in the type surface). - -### 1.4 `RCranLibrary.package`, `PythonPyPiLibrary.package` — `model.ts:289, 299` +### 1.2 `RCranLibrary.package`, `PythonPyPiLibrary.package` — `model.ts:174, 164` - `package` is a reserved word in JavaScript (future-reserved, strict mode) and conveys little semantic content beyond "package". Consider `coordinate`, `name`, or `packageName`. See also §8. - Severity: medium. -### 1.5 `MavenLibrary.repo`, `PythonPyPiLibrary.repo`, `RCranLibrary.repo` - — `model.ts:274, 294, 301` +### 1.3 `MavenLibrary.repo`, `PythonPyPiLibrary.repo`, `RCranLibrary.repo` + — `model.ts:149, 169, 176` - `repo` is an abbreviation. The companion `repo` documentation says "repository". `repository` (or `repositoryUrl`) would be more explicit. See also §4. @@ -55,7 +39,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 2. Acronym casing inconsistencies -### 2.1 `PythonPyPiLibrary` — `model.ts:284, 512, 686` +### 2.1 `PythonPyPiLibrary` — `model.ts:159` - Mixed casing for the PyPI acronym. The canonical brand name is **PyPI** (Python Package Index, https://pypi.org). The TS identifier uses `PyPi` which is neither pure brand casing nor TS acronym convention. Should be @@ -70,7 +54,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: high (a brand-name spelling error visible in every consumer using PyPI packages). -### 2.2 `RCranLibrary` — `model.ts:297, 522, 696` +### 2.2 `RCranLibrary` — `model.ts:172` - "CRAN" (Comprehensive R Archive Network) is an all-caps acronym. The TS identifier renders it `Cran`. By TS/Google style guidance acronyms longer than two letters are typically PascalCased ("Cran"), but the resulting @@ -81,7 +65,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. - The discriminator `$case: 'cran'` is consistent with the type tag. - Severity: medium. -### 2.3 `Library.whl` — `model.ts:198, 206` +### 2.3 `Library.whl` — `model.ts:100, 108` - "Whl" is the file-extension shorthand for Python wheels. The wire format uses `whl`, but the TS type otherwise uses long-form names (`jar`, `requirements`, `egg`). `wheel` would be more readable in TS but is a @@ -89,20 +73,11 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: low (flagged for completeness — abbreviation, not strictly a casing issue). -### 2.4 `traceId` vs `trace_id` query param — `client.ts:222-224` -- Field is camelCase TS but serializes to snake_case on the wire. Consistent - with all other fields; flagged only because the JSDoc on `traceId` - (`model.ts:144`) hints at the deprecated nature of the param but uses - identifier `ctx.requestId` — no `ctx` exists in this package. The hint - refers to Go context which does not exist in the TS port; left over from - Go SDK documentation. -- Severity: low (doc bug, not a name bug). - --- ## 3. Cryptic abbreviations -### 3.1 `Library.jar`, `Library.egg`, `Library.whl` — `model.ts:158-217` +### 3.1 `Library.jar`, `Library.egg`, `Library.whl` — `model.ts:60-119` - Single-extension abbreviations as field names. Wire-locked, but the type surface would be more discoverable with `jarUri`, `wheelUri`, etc. The `requirements` field at the same level uses the long form, so the variants @@ -110,122 +85,67 @@ means it is awkward or inconsistent; "low" means a minor blemish. - Severity: low (wire compatibility constraint). ### 3.2 `repo` — multiple types -- See §1.5. Short form of `repository`. Severity: low. +- See §1.3. Short form of `repository`. Severity: low. -### 3.3 `Library.pypi`, `Library.cran` — `model.ts:177-196` +### 3.3 `Library.pypi`, `Library.cran` — `model.ts:79, 95` - Lower-cased acronyms as field tags. Acceptable for wire compatibility, but the inconsistency with the (camelCased) type names (`PythonPyPiLibrary`, `RCranLibrary`) is jarring. See §2. - Severity: low. -### 3.4 `filepath` — `model.ts:90` -- Single-word concatenation. TS convention prefers compound words like - `filePath`. The wire uses `filepath` (one word) so the camelCase form - mirrors it; arguably the wire spelling is also non-standard (most APIs - use `file_path` or `path`). -- Severity: low. - --- ## 4. Misleading names -### 4.1 `updateDefaultDefaultBaseEnvironment` — `client.ts:429` -- Method name contains "Default" twice ("the Default Default Base - Environment"). The intent is clearer from the JSDoc: this method sets - *which* DefaultBaseEnvironment (DBE) is the workspace's default. So the - method is really `setWorkspaceDefaultBaseEnvironment` (or `setDefaultDbe` - /` setWorkspaceDefault`). The doubled "Default" is a literal artifact of - combining the `UpdateDefault___` HTTP verb with the `___DefaultBaseEnvironment` - resource name. -- Severity: high. This method name is the most surprising in the package. - -### 4.2 `UpdateDefaultDefaultBaseEnvironmentRequest` — `model.ts:326` -- Same problem on the request type. Severity: high. - -### 4.3 `ClusterStatus` — `model.ts:63` -- The type holds only a `clusterId` and is used as the request body for - `clusterStatus()`. Naming it `ClusterStatus` suggests it *is* the status, - but it is a request that fetches status. Better: `ClusterStatusRequest` - or `GetClusterStatusRequest`. The accompanying response type is named - `ClusterLibraryStatuses` (correct). -- Severity: high (the type name lies about its role). - -### 4.4 `LibraryFullStatus` — `model.ts:220` +### 4.1 `LibraryFullStatus` — `model.ts:122` - "Full" implies there is a "Partial" or "Short" counterpart, but there is none in this package. The type is "the status of a library on a cluster" per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. - Severity: medium. -### 4.5 `LibraryInstallStatus` value `RESTORED` — `model.ts:42` +### 4.2 `LibraryInstallStatus` value `RESTORED` — `model.ts:35` - The docstring says "Library installation is restored and can be used." But `RESTORED` overlaps semantically with `INSTALLED`. Without further context (cache restore vs. fresh install), consumers cannot distinguish. Name is technically accurate but underspecified. - Severity: low. -### 4.6 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:35` +### 4.3 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:28` - This is the only value that is an action+condition (rather than a state noun). Surrounding values are `PENDING`, `INSTALLED`, `FAILED`. A noun - form like `PENDING_UNINSTALL` would line up. + form like `PENDING_UNINSTALL` would line up. See also §10.2. - Severity: medium. -### 4.7 `allClusterStatuses()` — `client.ts:91` +### 4.4 `allClusterStatuses()` — `client.ts:74` - Method is the GET for `all-cluster-statuses`. The TS method name reads like an adjective ("all-cluster statuses") and is not verb-prefixed. Sibling method is `clusterStatus()` (also verb-less). Compare with the - rest of the client: `installLibraries`, `uninstallLibraries`, - `createDefaultBaseEnvironment`, etc. (all verb-prefixed). The two GET - methods alone are exempt. Should be `listAllClusterStatuses` or - `getAllClusterStatuses`, and `getClusterStatus` respectively. + rest of the client: `installLibraries`, `uninstallLibraries` (all + verb-prefixed). The two GET methods alone are exempt. Should be + `listAllClusterStatuses` or `getAllClusterStatuses`, and `getClusterStatus` + respectively. - Severity: medium. See also §11. -### 4.8 `Environment` — `model.ts:114` -- Type name is generic but the comment makes clear it is the "environment - spec" used in serverless side-panel / job-task / pipeline contexts. A - more specific name like `EnvironmentSpec` or `WorkspaceEnvironment` would - avoid collisions with the JS global `process.env` mental model. -- Severity: low. - -### 4.9 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` -- The JSDoc says "when the materialized env is updated" — sufficient but - the type itself does not carry the materialized payload (e.g., a hash, - ID, or contents). The name overpromises relative to the contents; - `EnvironmentCacheEntry` would be more honest. -- Severity: medium. - -### 4.10 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` — `model.ts:101` -- "Indefinite" is unexplained anywhere in the file. It pairs with - `materializedEnvironment` but the semantic distinction is opaque. The - name needs a doc or rename. -- Severity: medium. - -### 4.11 `Environment.baseEnvironment` — `model.ts:131` -- A field inside `Environment` is also named `baseEnvironment` (same root - word), which makes the relationship between the type and the field - recursive-looking even though the field is just a path/ID string. - Better: `baseEnvironmentRef` or `baseEnvironmentPath`. -- Severity: low. - --- ## 5. Overly verbose names -### 5.1 `ListAllClusterLibraryStatuses` — `model.ts:232` +### 5.1 `ListAllClusterLibraryStatusesRequest` — `model.ts:134` - The type name embeds "All" (which is also encoded in the URL `/api/2.0/libraries/all-cluster-statuses`). The type name - `ListAllClusterLibraryStatuses` is itself verbose — `ListLibraryStatuses` - or `ListClusterStatuses` would suffice. + `ListAllClusterLibraryStatusesRequest` is itself verbose — `ListLibraryStatusesRequest` + or `ListClusterStatusesRequest` would suffice. - Severity: medium. --- ## 6. Redundant suffixes -### 6.1 `LibraryFullStatus` — `model.ts:220` -- "Full" is a vestigial qualifier with no counterpart. See §4.4. +### 6.1 `LibraryFullStatus` — `model.ts:122` +- "Full" is a vestigial qualifier with no counterpart. See §4.1. - Severity: medium. -### 6.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +### 6.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:42` - Field name repeats the parent's middle word (Library). Could simply be `statuses`. Borderline acceptable for clarity. - Severity: low. @@ -234,30 +154,22 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 7. Singular/plural mismatches -### 7.1 `MavenLibrary.exclusions` — `model.ts:281` +### 7.1 `MavenLibrary.exclusions` — `model.ts:156` - Plural; field is a list. Doc says "List of dependences to exclude" — consistent. No issue (note: "dependences" is a typo for "dependencies", inherited from the API doc string). - Severity (typo): low. -### 7.2 `ListAllClusterLibraryStatuses` (request) — `model.ts:232` -- Singular method name `allClusterStatuses` (`client.ts:91`) for what is - semantically a list operation. Compare `listDefaultBaseEnvironments` - (`client.ts:276`). The action verb should be `list` for both. See §11. +### 7.2 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:134` +- Singular method name `allClusterStatuses` (`client.ts:74`) for what is + semantically a list operation. The action verb should be `list`. See §11. - Severity: medium. -### 7.3 `DefaultBaseEnvironment.baseEnvironmentCache` — `model.ts:93` -- Singular name but typed `DefaultBaseEnvironmentCache[]` (array). Should - be `baseEnvironmentCaches` (or, if it really represents one cache lineage, - the type definition is wrong). The Go SDK convention would surface this - via Go's "[]" — in TS the plural-ness must be in the name. -- Severity: high. - --- ## 8. Reserved-word collisions -### 8.1 `PythonPyPiLibrary.package`, `RCranLibrary.package` — `model.ts:289, 299` +### 8.1 `PythonPyPiLibrary.package`, `RCranLibrary.package` — `model.ts:164, 174` - `package` is a future-reserved word in ECMAScript (strict mode reserved). It is legal as an object property name and a parameter, but it is awkward to destructure: `const {package: pkg} = ...`. The wire field is `package`, @@ -272,216 +184,107 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 9. Duplicate concepts -### 9.1 `InstallLibraries` (request) vs `installLibraries()` (method) - — `model.ts:148, client.ts:250` -- Method and request type share a name, distinguished only by case. TS - convention works here because the type lives in the type namespace and - the method in the value namespace. Fine. - -### 9.2 `Environment` vs `MaterializedEnvironment` vs `DefaultBaseEnvironment` - — `model.ts:78, 114, 262` -- Three closely related types with overlapping names. The relationship - (DBE contains an Environment; cache holds MaterializedEnvironment) is - not obvious from names alone. Documentation compensates, but new - consumers face a name-soup. No surface fix; flagged for awareness. -- Severity: low. +_None._ --- ## 10. Verb-tense inconsistency -### 10.1 Method verbs across the client — `client.ts:91-456` +### 10.1 Method verbs across the client — `client.ts:74, 110, 144, 176` - `allClusterStatuses` and `clusterStatus` are verb-less (noun-only). -- `installLibraries`, `uninstallLibraries`, `createDefaultBaseEnvironment`, - `deleteDefaultBaseEnvironment`, `getDefaultBaseEnvironment`, - `listDefaultBaseEnvironments`, `refreshDefaultBaseEnvironments`, - `updateDefaultBaseEnvironment`, `updateDefaultDefaultBaseEnvironment` - use verb-prefixed forms. +- `installLibraries`, `uninstallLibraries` use verb-prefixed forms. - Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: `listAllClusterStatuses` (or `getAllClusterStatuses`) and - `getClusterStatus`. See §4.7 and §11. + `getClusterStatus`. See §4.4 and §11. - Severity: high (consistency of the verb-prefix is a Java/TS SDK convention that consumers rely on). -### 10.2 `LibraryInstallStatus` action vs state values — `model.ts:13` +### 10.2 `LibraryInstallStatus` action vs state values — `model.ts:6` - Values mostly nouns (`PENDING`, `INSTALLED`, `FAILED`) but one verb - imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §4.6. + imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §4.3. - Severity: medium. --- ## 11. Inconsistent action verbs -### 11.1 GET vs `list` vs `all` — `client.ts:91, 276` -- `allClusterStatuses()` (verb `all`) is structurally identical to - `listDefaultBaseEnvironments()` (verb `list`). Pick one. The Go SDK uses - the same naming, but the TS port has the opportunity to normalize. +### 11.1 GET vs `list` vs `all` — `client.ts:74` +- `allClusterStatuses()` (verb `all`) reads as a noun-phrase, not a verb. + The Go SDK uses the same naming, but the TS port has the opportunity to + normalize to `list` (or `get`). - Severity: medium (see §10.1). -### 11.2 `refreshDefaultBaseEnvironments` — `client.ts:333` -- `refresh` is a TS-idiomatic verb meaning re-fetch / re-compute. The - operation here regenerates a cache asynchronously. Borderline OK, but - consumers may expect `refresh()` to return updated data; this returns - an empty response. `regenerateCache(s)` or `invalidateCache(s)` would - reflect the side-effect more honestly. -- Severity: low. - -### 11.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL — `client.ts:433` -- The URL says `:setDefault` but the method says `updateDefaultDefault`. - `setDefaultBaseEnvironment` or `setWorkspaceDefault` would mirror the - URL semantics. See §4.1. -- Severity: high. - -### 11.4 `installLibraries` / `uninstallLibraries` — `client.ts:250, 368` -- Symmetric pair, good. Mirror request types `InstallLibraries` / - `UninstallLibraries` (named after the operation, not the resource). +### 11.2 `installLibraries` / `uninstallLibraries` — `client.ts:144, 176` +- Symmetric pair, good. Mirror request types `InstallLibrariesRequest` / + `UninstallLibrariesRequest` (named after the operation, not the resource). Consistent. --- ## 12. Field contradicting type domain -### 12.1 `Environment.client` — `model.ts:116` -- "Client" inside an Environment spec is unexpected; the doc clarifies it - is a deprecated stand-in for `environment_version`. The name belongs to - a different semantic domain (clients connect to environments, they are - not part of them). -- Severity: medium (deprecated, but exposed). - -### 12.2 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:228` +### 12.1 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:130` - Inside `LibraryFullStatus` (per-cluster status), a field that describes whether the library is configured cluster-wide. The name reads like a global property but the type belongs to a single cluster's view. Better: `installedOnAllClusters` or `isClusterWideLibrary`. - Severity: medium. -### 12.3 `MaterializedEnvironment.lastUpdatedTimestamp` — `model.ts:264` -- Type is "materialized environment metadata"; the only field is a - timestamp. The materialization payload is missing — see §4.9. The - timestamp belongs in a cache-entry type, not a materialization type. -- Severity: medium. - --- ## 13. Long enum values -### 13.1 `LibraryInstallStatus.UNINSTALL_ON_RESTART` — `model.ts:35` -- 20 characters; the only multi-word value. Acceptable since it conveys - semantics, but combined with the prefix `LibraryInstallStatus.` the - full reference is 41 characters. See also §4.6. -- Severity: low. +_None._ --- ## 14. Underspecified IDs -### 14.1 `CreateDefaultBaseEnvironmentRequest.requestId` — `model.ts:74` -- Idempotency UUID. Name is OK but generic; `idempotencyKey` would be more - precise. -- Severity: low. - -### 14.2 `GetDefaultBaseEnvironmentRequest.traceId` — `model.ts:145` -- Deprecated field. Name is OK; the comment hints at a missing replacement. - Could be `traceId?: string` with a `@deprecated` JSDoc tag. -- Severity: low. - -### 14.3 `DefaultBaseEnvironment.creatorUserId`, `.lastUpdatedUserId` - — `model.ts:81, 83` -- Both are typed `number`. Databricks user IDs may exceed 2^53; bare - `number` risks precision loss for very large IDs. (Naming-adjacent - issue: the name `creatorUserId` is fine, but the *type* is undersized.) - Compare with the Go SDK where these are `int64`. -- Severity: medium (type, not name) — flagged because it bears on - consumer expectations about ID identifiers. - -### 14.4 `DefaultBaseEnvironment.principalIds` — `model.ts:94` -- `number[]` with no domain (workspace principals, account principals?). - `Principal` is ambiguous in Databricks (user, SP, group). `principalIds` - needs scope, like `workspacePrincipalIds`. -- Severity: medium. - -### 14.5 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` - — `model.ts:75` -- An ID field named `workspaceBaseEnvironmentId` inside a "create DBE" - request. The `workspace` prefix implies a different resource (workspace - base environment) than the request's payload (`defaultBaseEnvironment`). - Documentation does not explain the relationship. The name is precise - but the role is unclear without docs. -- Severity: medium. - -### 14.6 `ClusterLibraryStatuses.clusterId`, `ClusterStatus.clusterId`, - `InstallLibraries.clusterId`, `UninstallLibraries.clusterId` - — `model.ts:58, 65, 150, 313` +### 14.1 `ClusterLibraryStatuses.clusterId`, `ClusterStatusRequest.clusterId`, + `InstallLibrariesRequest.clusterId`, `UninstallLibrariesRequest.clusterId` + — `model.ts:40, 47, 52, 181` - Bare `clusterId` everywhere. Good consistency. No issue. -### 14.7 `DefaultBaseEnvironment.id` — `model.ts:79` -- Bare `id`. With sibling `creatorUserId` etc., a name like `dbeId` - would be more grep-able. The Go SDK uses bare `Id` due to package - scoping; TS scopes via the type so this is OK. -- Severity: low. - -### 14.8 `RefreshDefaultBaseEnvironmentsRequest.ids` — `model.ts:305` -- Untyped collection of IDs of what? Doc-less. `dbeIds` or - `defaultBaseEnvironmentIds` would be unambiguous. -- Severity: medium. - --- ## 15. Type-suffix tautology -### 15.1 `LibraryFullStatus` — `model.ts:220` +### 15.1 `LibraryFullStatus` — `model.ts:122` - "Status" appears in the type name and the field `status: LibraryInstallStatus` contains the noun again. Not a tautology per se, but the parent `LibraryFullStatus` could be `LibraryReport` or just `LibraryStatus` (with the inner field becoming `state` to avoid the duplicate). - Severity: low. -### 15.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:60` +### 15.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:42` - Already noted in §6.2. - Severity: low. -### 15.3 `ListDefaultBaseEnvironmentsResponse.defaultBaseEnvironments` - — `model.ts:246` -- Field name repeats the resource noun. Standard list-response pattern - used across the SDK; no fix. -- Severity: low. - --- ## Cross-cutting summary ### High-severity (consumer-facing surprises) -- `updateDefaultDefaultBaseEnvironment` / `UpdateDefaultDefaultBaseEnvironmentRequest` - (§4.1, §4.2): the "Default Default" doubling is the most jarring naming - in the package. Best resolved by renaming the public API to - `setWorkspaceDefaultBaseEnvironment`. - `PythonPyPiLibrary` brand-casing inconsistency (§2.1): "PyPi" misspells the PyPI brand. -- `ClusterStatus` request type misleading-as-response (§4.3). -- `baseEnvironmentCache: DefaultBaseEnvironmentCache[]` singular-on-array - (§7.3). - `package` reserved-word collision on PyPI and CRAN libraries (§8.1). - Verb-tense gap: `allClusterStatuses()` and `clusterStatus()` break the client's prevailing verb-prefix convention (§10.1, §11.1). ### Medium-severity -- `LibraryFullStatus` with no "non-full" counterpart (§4.4). +- `LibraryFullStatus` with no "non-full" counterpart (§4.1). - `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state - (§4.6, §10.2). -- `MaterializedEnvironment` containing only a timestamp (§4.9). -- `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` - unexplained (§4.10). + (§4.3, §10.2). - `isLibraryForAllClusters` field name awkwardly straddles per-cluster - and global domains (§12.2). + and global domains (§12.1). ### Low-severity / stylistic -- `repo` vs `repository` short form (§1.5). +- `repo` vs `repository` short form (§1.3). - `whl`, `jar`, `egg` extension-as-field-name (§3.1). -- `filepath` one-word concatenation (§3.4). -- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§4.5). +- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§4.2). - "dependences" typo in `MavenLibrary.exclusions` doc (§7.1). --- @@ -489,51 +292,28 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## Inventory (for completeness) Enums audited: -- `BaseEnvironmentType` (model.ts:6). -- `LibraryInstallStatus` (model.ts:13). -- `DefaultBaseEnvironmentCache_Status` (model.ts:46). +- `LibraryInstallStatus` (model.ts:6). Interfaces audited: -- `ClusterLibraryStatuses` (56). -- `ClusterStatus` (63). -- `CreateDefaultBaseEnvironmentRequest` (68). -- `DefaultBaseEnvironment` (78). -- `DefaultBaseEnvironmentCache` (99). -- `DeleteDefaultBaseEnvironmentRequest` (106). -- `Environment` (114). -- `GetDefaultBaseEnvironmentRequest` (142). -- `InstallLibraries` (148). -- `InstallLibraries_Response` (156). -- `Library` (158). -- `LibraryFullStatus` (220). -- `ListAllClusterLibraryStatuses` (232). -- `ListAllClusterLibraryStatuses_Response` (235). -- `ListDefaultBaseEnvironmentsRequest` (240). -- `ListDefaultBaseEnvironmentsResponse` (245). -- `MaterializedEnvironment` (262). -- `MavenLibrary` (267). -- `PythonPyPiLibrary` (284). -- `RCranLibrary` (297). -- `RefreshDefaultBaseEnvironmentsRequest` (304). -- `RefreshDefaultBaseEnvironmentsResponse` (309). -- `UninstallLibraries` (311). -- `UninstallLibraries_Response` (319). -- `UpdateDefaultBaseEnvironmentRequest` (321). -- `UpdateDefaultDefaultBaseEnvironmentRequest` (326). +- `ClusterLibraryStatuses` (38). +- `ClusterStatusRequest` (45). +- `InstallLibrariesRequest` (50). +- `InstallLibrariesRequest_Response` (58). +- `Library` (60). +- `LibraryFullStatus` (122). +- `ListAllClusterLibraryStatusesRequest` (134). +- `ListAllClusterLibraryStatusesRequest_Response` (137). +- `MavenLibrary` (142). +- `PythonPyPiLibrary` (159). +- `RCranLibrary` (172). +- `UninstallLibrariesRequest` (179). +- `UninstallLibrariesRequest_Response` (187). Methods audited (`client.ts`): -- `allClusterStatuses` (91). -- `clusterStatus` (127). -- `createDefaultBaseEnvironment` (162). -- `deleteDefaultBaseEnvironment` (194). -- `getDefaultBaseEnvironment` (213). -- `installLibraries` (250). -- `listDefaultBaseEnvironments` (276). -- `listDefaultBaseEnvironmentsIter` (312). -- `refreshDefaultBaseEnvironments` (333). -- `uninstallLibraries` (368). -- `updateDefaultBaseEnvironment` (400). -- `updateDefaultDefaultBaseEnvironment` (429). +- `allClusterStatuses` (74). +- `clusterStatus` (110). +- `installLibraries` (144). +- `uninstallLibraries` (176). Utilities audited (`utils.ts`): - `HttpCallOptions` (15). @@ -544,3 +324,34 @@ Utilities audited (`utils.ts`): - `parseResponse` (113). - `marshalRequest` (119). - `flattenQueryParams` (123). + +--- + +## Fixed + +- #1.2 `DefaultBaseEnvironment.message` (originally cited at model.ts:92): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed from package. +- #1.3 `Environment.client` (originally cited at model.ts:116): Fixed in regeneration on 2026-05-20 — `Environment` type removed from package. +- #2.4 `traceId` vs `trace_id` query param (originally cited at client.ts:222-224): Fixed in regeneration on 2026-05-20 — `traceId` and surrounding DBE getter removed. +- #3.4 `filepath` (originally cited at model.ts:90): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. +- #4.1 `updateDefaultDefaultBaseEnvironment` (originally cited at client.ts:429): Fixed in regeneration on 2026-05-20 — method removed from client. +- #4.2 `UpdateDefaultDefaultBaseEnvironmentRequest` (originally cited at model.ts:326): Fixed in regeneration on 2026-05-20 — type removed from package. +- #4.3 `ClusterStatus` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — renamed to `ClusterStatusRequest` as the audit suggested. +- #4.8 `Environment` (originally cited at model.ts:114): Fixed in regeneration on 2026-05-20 — type removed from package. +- #4.9 `MaterializedEnvironment.lastUpdatedTimestamp` (originally cited at model.ts:264): Fixed in regeneration on 2026-05-20 — `MaterializedEnvironment` type removed. +- #4.10 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` (originally cited at model.ts:101): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironmentCache` type removed. +- #4.11 `Environment.baseEnvironment` (originally cited at model.ts:131): Fixed in regeneration on 2026-05-20 — `Environment` type removed. +- #7.3 `DefaultBaseEnvironment.baseEnvironmentCache` (originally cited at model.ts:93): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. +- #9.1 `InstallLibraries` (request) vs `installLibraries()` (method) (originally cited at model.ts:148, client.ts:250): Fixed in regeneration on 2026-05-20 — request type renamed to `InstallLibrariesRequest`, eliminating the case-only collision. +- #9.2 `Environment` vs `MaterializedEnvironment` vs `DefaultBaseEnvironment` (originally cited at model.ts:78, 114, 262): Fixed in regeneration on 2026-05-20 — all three types removed from package. +- #11.2 `refreshDefaultBaseEnvironments` (originally cited at client.ts:333): Fixed in regeneration on 2026-05-20 — method removed from client. +- #11.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL (originally cited at client.ts:433): Fixed in regeneration on 2026-05-20 — method removed from client. +- #12.1 `Environment.client` (originally cited at model.ts:116): Fixed in regeneration on 2026-05-20 — `Environment` type removed. +- #12.3 `MaterializedEnvironment.lastUpdatedTimestamp` (originally cited at model.ts:264): Fixed in regeneration on 2026-05-20 — `MaterializedEnvironment` type removed. +- #14.1 `CreateDefaultBaseEnvironmentRequest.requestId` (originally cited at model.ts:74): Fixed in regeneration on 2026-05-20 — type removed from package. +- #14.2 `GetDefaultBaseEnvironmentRequest.traceId` (originally cited at model.ts:145): Fixed in regeneration on 2026-05-20 — type removed from package. +- #14.3 `DefaultBaseEnvironment.creatorUserId`, `.lastUpdatedUserId` (originally cited at model.ts:81, 83): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. +- #14.4 `DefaultBaseEnvironment.principalIds` (originally cited at model.ts:94): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. +- #14.5 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` (originally cited at model.ts:75): Fixed in regeneration on 2026-05-20 — type removed from package. +- #14.7 `DefaultBaseEnvironment.id` (originally cited at model.ts:79): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. +- #14.8 `RefreshDefaultBaseEnvironmentsRequest.ids` (originally cited at model.ts:305): Fixed in regeneration on 2026-05-20 — type removed from package. +- #15.3 `ListDefaultBaseEnvironmentsResponse.defaultBaseEnvironments` (originally cited at model.ts:246): Fixed in regeneration on 2026-05-20 — type removed from package. diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index 7f81f108..0a040936 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -31,72 +31,72 @@ rubric. Issues are graded: ### 1.2 Interfaces (`model.ts`) -| Name | Purpose | -| -------------------------- | --------------------------------------------- | -| `CreatePolicy` | Request body for create. | -| `CreatePolicy_Response` | Response from create (proto-style suffix). | -| `DeletePolicy` | Request body for delete. | -| `DeletePolicy_Response` | Empty response from delete. | -| `EditPolicy` | Request body for update/edit. | -| `EditPolicy_Response` | Empty response from edit. | -| `GetPolicy` | Request body for get. | -| `Library` | Discriminated-union wrapper around `lib`. | -| `ListPolicies` | Request body for list. | -| `ListPolicies_Response` | Response from list. | -| `MavenLibrary` | Maven coordinates payload. | -| `Policy` | The cluster-policy entity. | -| `PythonPyPiLibrary` | PyPI package payload. | -| `RCranLibrary` | CRAN R package payload. | +| Name | Purpose | +| ------------------------------- | --------------------------------------------- | +| `CreatePolicyRequest` | Request body for create. | +| `CreatePolicyRequest_Response` | Response from create (proto-style suffix). | +| `DeletePolicyRequest` | Request body for delete. | +| `DeletePolicyRequest_Response` | Empty response from delete. | +| `EditPolicyRequest` | Request body for update/edit. | +| `EditPolicyRequest_Response` | Empty response from edit. | +| `GetPolicyRequest` | Request body for get. | +| `Library` | Discriminated-union wrapper around `lib`. | +| `ListPoliciesRequest` | Request body for list. | +| `ListPoliciesRequest_Response` | Response from list. | +| `MavenLibrary` | Maven coordinates payload. | +| `Policy` | The cluster-policy entity. | +| `PythonPyPiLibrary` | PyPI package payload. | +| `RCranLibrary` | CRAN R package payload. | ### 1.3 Fields (entity / request / response — combined catalog) -| Type | Field | Type / Notes | -| -------------------------- | ---------------------------------- | ----------------------------- | -| `CreatePolicy` | `name` | `string?` | -| `CreatePolicy` | `definition` | `string?` | -| `CreatePolicy` | `description` | `string?` | -| `CreatePolicy` | `policyFamilyId` | `string?` | -| `CreatePolicy` | `policyFamilyDefinitionOverrides` | `string?` | -| `CreatePolicy` | `maxClustersPerUser` | `number?` | -| `CreatePolicy` | `libraries` | `Library[]?` | -| `CreatePolicy_Response` | `policyId` | `string?` | -| `DeletePolicy` | `policyId` | `string?` | -| `EditPolicy` | `policyId` | `string?` | -| `EditPolicy` | `name` … `libraries` | (same shape as `CreatePolicy`)| -| `GetPolicy` | `policyId` | `string?` | -| `Library` | `lib` | discriminated union | -| `Library.lib.$case` | `jar`/`egg`/`pypi`/`maven`/`cran`/`whl`/`requirements` | union tag | -| `ListPolicies` | `sortOrder` | `ListOrder?` | -| `ListPolicies` | `sortColumn` | `PolicySortColumn?` | -| `ListPolicies_Response` | `policies` | `Policy[]?` | -| `MavenLibrary` | `coordinates` | `string?` | -| `MavenLibrary` | `repo` | `string?` | -| `MavenLibrary` | `exclusions` | `string[]?` | -| `Policy` | `policyId` | `string?` | -| `Policy` | `creatorUserName` | `string?` | -| `Policy` | `createdAtTimestamp` | `number?` | -| `Policy` | `isDefault` | `boolean?` | -| `Policy` | `name` | `string?` | -| `Policy` | `definition` | `string?` | -| `Policy` | `description` | `string?` | -| `Policy` | `policyFamilyId` | `string?` | -| `Policy` | `policyFamilyDefinitionOverrides` | `string?` | -| `Policy` | `maxClustersPerUser` | `number?` | -| `Policy` | `libraries` | `Library[]?` | -| `PythonPyPiLibrary` | `package` | `string?` (reserved word) | -| `PythonPyPiLibrary` | `repo` | `string?` | -| `RCranLibrary` | `package` | `string?` (reserved word) | -| `RCranLibrary` | `repo` | `string?` | +| Type | Field | Type / Notes | +| --------------------------------- | ---------------------------------- | ----------------------------- | +| `CreatePolicyRequest` | `name` | `string?` | +| `CreatePolicyRequest` | `definition` | `string?` | +| `CreatePolicyRequest` | `description` | `string?` | +| `CreatePolicyRequest` | `policyFamilyId` | `string?` | +| `CreatePolicyRequest` | `policyFamilyDefinitionOverrides` | `string?` | +| `CreatePolicyRequest` | `maxClustersPerUser` | `number?` | +| `CreatePolicyRequest` | `libraries` | `Library[]?` | +| `CreatePolicyRequest_Response` | `policyId` | `string?` | +| `DeletePolicyRequest` | `policyId` | `string?` | +| `EditPolicyRequest` | `policyId` | `string?` | +| `EditPolicyRequest` | `name` … `libraries` | (same shape as `CreatePolicyRequest`) | +| `GetPolicyRequest` | `policyId` | `string?` | +| `Library` | `lib` | discriminated union | +| `Library.lib.$case` | `jar`/`egg`/`pypi`/`maven`/`cran`/`whl`/`requirements` | union tag | +| `ListPoliciesRequest` | `sortOrder` | `ListOrder?` | +| `ListPoliciesRequest` | `sortColumn` | `PolicySortColumn?` | +| `ListPoliciesRequest_Response` | `policies` | `Policy[]?` | +| `MavenLibrary` | `coordinates` | `string?` | +| `MavenLibrary` | `repo` | `string?` | +| `MavenLibrary` | `exclusions` | `string[]?` | +| `Policy` | `policyId` | `string?` | +| `Policy` | `creatorUserName` | `string?` | +| `Policy` | `createdAtTimestamp` | `number?` | +| `Policy` | `isDefault` | `boolean?` | +| `Policy` | `name` | `string?` | +| `Policy` | `definition` | `string?` | +| `Policy` | `description` | `string?` | +| `Policy` | `policyFamilyId` | `string?` | +| `Policy` | `policyFamilyDefinitionOverrides` | `string?` | +| `Policy` | `maxClustersPerUser` | `number?` | +| `Policy` | `libraries` | `Library[]?` | +| `PythonPyPiLibrary` | `package` | `string?` (reserved word) | +| `PythonPyPiLibrary` | `repo` | `string?` | +| `RCranLibrary` | `package` | `string?` (reserved word) | +| `RCranLibrary` | `repo` | `string?` | ### 1.4 Methods (`client.ts`) -| Method | Verb | Returns | -| --------------- | ---- | ------------------------ | -| `createPolicy` | POST | `CreatePolicy_Response` | -| `deletePolicy` | POST | `DeletePolicy_Response` | -| `editPolicy` | POST | `EditPolicy_Response` | -| `getPolicy` | GET | `Policy` | -| `listPolicies` | GET | `ListPolicies_Response` | +| Method | Verb | Returns | +| --------------- | ---- | ------------------------------- | +| `createPolicy` | POST | `CreatePolicyRequest_Response` | +| `deletePolicy` | POST | `DeletePolicyRequest_Response` | +| `editPolicy` | POST | `EditPolicyRequest_Response` | +| `getPolicy` | GET | `Policy` | +| `listPolicies` | GET | `ListPoliciesRequest_Response` | ### 1.5 Other identifiers @@ -105,14 +105,16 @@ rubric. Issues are graded: - `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`. -- Marshal / unmarshal schemas: `unmarshalCreatePolicy_ResponseSchema`, - `unmarshalDeletePolicy_ResponseSchema`, `unmarshalEditPolicy_ResponseSchema`, - `unmarshalLibrarySchema`, `unmarshalListPolicies_ResponseSchema`, +- Marshal / unmarshal schemas: `unmarshalCreatePolicyRequest_ResponseSchema`, + `unmarshalDeletePolicyRequest_ResponseSchema`, + `unmarshalEditPolicyRequest_ResponseSchema`, `unmarshalLibrarySchema`, + `unmarshalListPoliciesRequest_ResponseSchema`, `unmarshalMavenLibrarySchema`, `unmarshalPolicySchema`, `unmarshalPythonPyPiLibrarySchema`, `unmarshalRCranLibrarySchema`, - `marshalCreatePolicySchema`, `marshalDeletePolicySchema`, - `marshalEditPolicySchema`, `marshalLibrarySchema`, `marshalMavenLibrarySchema`, - `marshalPythonPyPiLibrarySchema`, `marshalRCranLibrarySchema`. + `marshalCreatePolicyRequestSchema`, `marshalDeletePolicyRequestSchema`, + `marshalEditPolicyRequestSchema`, `marshalLibrarySchema`, + `marshalMavenLibrarySchema`, `marshalPythonPyPiLibrarySchema`, + `marshalRCranLibrarySchema`. --- @@ -122,30 +124,24 @@ rubric. Issues are graded: | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| V-01 | `Library.lib` (field) | High | The field name `lib` is a meaningless abbreviation that conveys nothing the surrounding type doesn't already say. The wrapper interface is `Library`, so the discriminator field could be named `kind`, `variant`, `source`, or `spec`. As `lib`, callers must write `library.lib.$case === 'jar'`, which reads as "library library case". | -| V-02 | `MavenLibrary.repo`, `RCranLibrary.repo`, `PythonPyPiLibrary.repo` | Medium | `repo` is generic and overloaded across types. For Maven it is a Maven repository URL; for CRAN it is a CRAN mirror; for PyPI it is a pip index. Renaming to `repositoryUrl` (or even `mavenRepoUrl` / `cranMirrorUrl` / `pipIndexUrl`) would be more self-describing. | -| V-03 | `Policy.definition`, `CreatePolicy.definition`, `EditPolicy.definition` | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it's unclear it's a JSON document. `policyDefinition` (matches `policyFamilyDefinitionOverrides`) would be self-consistent. | -| V-04 | `Policy.description`, `CreatePolicy.description`, `EditPolicy.description` | Low | Generic but standard across the SDK; acceptable. | -| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-01 | `Library.lib` (`model.ts:106`) | High | The field name `lib` is a meaningless abbreviation that conveys nothing the surrounding type doesn't already say. The wrapper interface is `Library`, so the discriminator field could be named `kind`, `variant`, `source`, or `spec`. As `lib`, callers must write `library.lib.$case === 'jar'`, which reads as "library library case". | +| V-02 | `MavenLibrary.repo` (`model.ts:194`), `RCranLibrary.repo` (`model.ts:268`), `PythonPyPiLibrary.repo` (`model.ts:261`) | Medium | `repo` is generic and overloaded across types. For Maven it is a Maven repository URL; for CRAN it is a CRAN mirror; for PyPI it is a pip index. Renaming to `repositoryUrl` (or even `mavenRepoUrl` / `cranMirrorUrl` / `pipIndexUrl`) would be more self-describing. | +| V-03 | `Policy.definition` (`model.ts:226`), `CreatePolicyRequest.definition` (`model.ts:24`), `EditPolicyRequest.definition` (`model.ts:72`) | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it's unclear it's a JSON document. `policyDefinition` (matches `policyFamilyDefinitionOverrides`) would be self-consistent. | +| V-04 | `Policy.description` (`model.ts:228`), `CreatePolicyRequest.description` (`model.ts:26`), `EditPolicyRequest.description` (`model.ts:74`) | Low | Generic but standard across the SDK; acceptable. | +| V-05 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | -### 2.2 Redundant enum prefixes — High +### 2.2 Redundant enum prefixes -| ID | Symbol | Severity | Issue | -| ----- | ------------------------------------- | -------- | ----- | -| E-01 | `PolicySortColumn.POLICY_CREATION_TIME` | High | The enum is already named `PolicySortColumn`. Members `POLICY_CREATION_TIME` and `POLICY_NAME` re-state `POLICY`. Inside the enum's scope `CREATION_TIME` and `NAME` are unambiguous (`PolicySortColumn.CREATION_TIME`). | -| E-02 | `PolicySortColumn.POLICY_NAME` | High | Same as above. | - -Note: `ListOrder.DESC` / `ListOrder.ASC` are fine — they're standard SQL -abbreviations and don't repeat the enum prefix. +_None._ ### 2.3 Acronym casing inconsistencies — High | ID | Symbol | Severity | Issue | | ----- | --------------------- | -------- | ----- | -| A-01 | `PythonPyPiLibrary` | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. | -| A-02 | `RCranLibrary` | Medium | "CRAN" is an acronym ("Comprehensive R Archive Network"). The type uses `Cran` (PascalCase) which is acceptable under Google TS style (acronyms ≥3 chars → only first letter capitalised). However, the JSDoc and surrounding usage refers to "CRAN library". Consistent with the rule but worth noting — peer types like `PolicySortColumn` keep full uppercase in member names. Leave as-is for Google style compliance. | -| A-03 | `RCranLibrary` — prefix `R` | Low | The leading lone `R` (the language) is awkward; the Go SDK uses the same name so this is a porting constraint. | -| A-04 | `pypi` discriminator case (`Library.lib.$case === 'pypi'`) | Low | Lowercased, matching API wire format; consistent with `jar`, `egg`, `cran`, `maven`. Acceptable. | +| A-01 | `PythonPyPiLibrary` (`model.ts:251`) | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. | +| A-02 | `RCranLibrary` (`model.ts:264`) | Medium | "CRAN" is an acronym ("Comprehensive R Archive Network"). The type uses `Cran` (PascalCase) which is acceptable under Google TS style (acronyms ≥3 chars → only first letter capitalised). However, the JSDoc and surrounding usage refers to "CRAN library". Consistent with the rule but worth noting — peer types like `PolicySortColumn` keep full uppercase in member names. Leave as-is for Google style compliance. | +| A-03 | `RCranLibrary` — prefix `R` (`model.ts:264`) | Low | The leading lone `R` (the language) is awkward; the Go SDK uses the same name so this is a porting constraint. | +| A-04 | `pypi` discriminator case (`Library.lib.$case === 'pypi'`, `model.ts:124`) | Low | Lowercased, matching API wire format; consistent with `jar`, `egg`, `cran`, `maven`. Acceptable. | ### 2.4 Underscores in TS identifiers @@ -155,44 +151,44 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------- | -------- | ----- | -| C-01 | `Library.lib` | High (also covered V-01) | `lib` is a cryptic abbreviation of "library" inside a type already called `Library`. | -| C-02 | `Library.lib.$case === 'whl'` | Medium | `whl` (wheel) is a Python packaging file extension; readers unfamiliar with Python will not know it. Documented in JSDoc but the discriminator value itself is opaque. | -| C-03 | `Library.lib.$case === 'egg'` | Medium | Same as C-02 for Python "egg" files. The JSDoc even notes it is "Deprecated". | -| C-04 | `MavenLibrary.exclusions` | Low | Maven term, OK in context. | -| C-05 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | -| C-06 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | +| C-01 | `Library.lib` (`model.ts:106`) | High (also covered V-01) | `lib` is a cryptic abbreviation of "library" inside a type already called `Library`. | +| C-02 | `Library.lib.$case === 'whl'` (`model.ts:145`) | Medium | `whl` (wheel) is a Python packaging file extension; readers unfamiliar with Python will not know it. Documented in JSDoc but the discriminator value itself is opaque. | +| C-03 | `Library.lib.$case === 'egg'` (`model.ts:119`) | Medium | Same as C-02 for Python "egg" files. The JSDoc even notes it is "Deprecated". | +| C-04 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Maven term, OK in context. | +| C-05 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`, throughout) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | +| C-06 | `opts` (`utils.ts:66`, `executeHttpCall` parameter) | Low | Inside fn scope; minor. | ### 2.6 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| M-01 | `EditPolicy` / `editPolicy()` | High | Standard CRUD verbs in TS/REST are **create / read / update / delete**. The Databricks "Cluster Policies 2.0" API uses `/edit` as the wire path, but the SDK could still expose `updatePolicy` (with `UpdatePolicy` request type) which is the conventional REST verb. Compare with the newer `policies` API surface and most other Databricks SDK resources that expose `update*`. As-is, the SDK exposes `editPolicy` while peer packages (e.g. `clusters`) often expose `editCluster` too — there is precedent — but it remains inconsistent with the broader CRUD vocabulary. Tracked here as a discrepancy worth raising upstream. | -| M-02 | `MavenLibrary.exclusions` (JSDoc says "List of dependences to exclude") | Low | Typo in the JSDoc ("dependences"); not a name issue per se. | +| M-01 | `EditPolicyRequest` (`model.ts:63`) / `editPolicy()` (`client.ts:133`) | High | Standard CRUD verbs in TS/REST are **create / read / update / delete**. The Databricks "Cluster Policies 2.0" API uses `/edit` as the wire path, but the SDK could still expose `updatePolicy` (with `UpdatePolicyRequest` request type) which is the conventional REST verb. Compare with the newer `policies` API surface and most other Databricks SDK resources that expose `update*`. As-is, the SDK exposes `editPolicy` while peer packages (e.g. `clusters`) often expose `editCluster` too — there is precedent — but it remains inconsistent with the broader CRUD vocabulary. Tracked here as a discrepancy worth raising upstream. | +| M-02 | `MavenLibrary.exclusions` JSDoc says "List of dependences to exclude" (`model.ts:196`) | Low | Typo in the JSDoc ("dependences"); not a name issue per se. | ### 2.7 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| O-01 | `policyFamilyDefinitionOverrides` | Medium | Five-word camel-case identifier. Inherited from the API; very long but no shorter form is unambiguous. Accept as upstream constraint. | -| O-02 | `createdAtTimestamp` | High | "Timestamp" is redundant — `createdAt` is the universal convention for epoch-millisecond fields (and the JSDoc says "in millisecond"). `createdAtTimestamp` is a tautology (`*-At` already implies a time value). | -| O-03 | `creatorUserName` | Medium | Three words for "creator". `creator` alone would suffice if the value is a username; `createdBy` is the convention used elsewhere in the Databricks SDK. | -| O-04 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | -| O-05 | `Policy.maxClustersPerUser` | Low | Long but precise. | +| O-01 | `policyFamilyDefinitionOverrides` (`model.ts:42`, `model.ts:90`, `model.ts:244`) | Medium | Five-word camel-case identifier. Inherited from the API; very long but no shorter form is unambiguous. Accept as upstream constraint. | +| O-02 | `createdAtTimestamp` (`model.ts:214`) | High | "Timestamp" is redundant — `createdAt` is the universal convention for epoch-millisecond fields (and the JSDoc says "in millisecond"). `createdAtTimestamp` is a tautology (`*-At` already implies a time value). | +| O-03 | `creatorUserName` (`model.ts:212`) | Medium | Three words for "creator". `creator` alone would suffice if the value is a username; `createdBy` is the convention used elsewhere in the Databricks SDK. | +| O-04 | `PACKAGE_SEGMENT` (`client.ts:44`) | Low | OK in context. | +| O-05 | `Policy.maxClustersPerUser` (`model.ts:246`) | Low | Long but precise. | ### 2.8 Singular / plural mismatches — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| P-01 | `ListPolicies` (request) vs `listPolicies()` (method) | Low | The request type is plural to match the API verb; the method matches. Consistent. | -| P-02 | `ListPolicies_Response.policies` | Low | Plural field for an array — correct. | -| P-03 | `MavenLibrary.exclusions` | Low | Plural for array — correct. | +| P-01 | `ListPoliciesRequest` (`model.ts:166`) vs `listPolicies()` (`client.ts:190`) | Low | The request type is plural to match the API verb; the method matches. Consistent. | +| P-02 | `ListPoliciesRequest_Response.policies` (`model.ts:183`) | Low | Plural field for an array — correct. | +| P-03 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Plural for array — correct. | ### 2.9 Reserved-word collisions — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| R-01 | `PythonPyPiLibrary.package` | Medium | `package` is a [reserved word in strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#future_reserved_words) for ES5+. It is legal as a property name but can't be used as a variable or import identifier without quoting. Consider `packageName` for forward compatibility. | -| R-02 | `RCranLibrary.package` | Medium | Same as R-01. | +| R-01 | `PythonPyPiLibrary.package` (`model.ts:256`) | Medium | `package` is a [reserved word in strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#future_reserved_words) for ES5+. It is legal as a property name but can't be used as a variable or import identifier without quoting. Consider `packageName` for forward compatibility. | +| R-02 | `RCranLibrary.package` (`model.ts:266`) | Medium | Same as R-01. | | R-03 | None of the type names collide. | — | OK. | ### 2.10 Empty / trivial wrapper types — Medium @@ -203,33 +199,33 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| D-01 | `CreatePolicy` vs `EditPolicy` | Medium | The two request types are byte-identical except `EditPolicy` adds `policyId`. Could share a base type. Codegen constraint, but readers see two near-duplicate 7-field interfaces. | -| D-02 | `Policy` vs `CreatePolicy` vs `EditPolicy` | Medium | Same body fields duplicated three times (with the entity adding `creatorUserName`, `createdAtTimestamp`, `isDefault`). Tooling could share a base. | -| D-03 | `definition` and `policyFamilyDefinitionOverrides` | Low | Distinct concepts (full definition vs. override deltas), but the names alone don't communicate "two mutually exclusive ways of supplying a definition". The JSDoc explains the relationship; OK. | +| D-01 | `CreatePolicyRequest` (`model.ts:17`) vs `EditPolicyRequest` (`model.ts:63`) | Medium | The two request types are byte-identical except `EditPolicyRequest` adds `policyId`. Could share a base type. Codegen constraint, but readers see two near-duplicate 7-field interfaces. | +| D-02 | `Policy` (`model.ts:205`) vs `CreatePolicyRequest` (`model.ts:17`) vs `EditPolicyRequest` (`model.ts:63`) | Medium | Same body fields duplicated three times (with the entity adding `creatorUserName`, `createdAtTimestamp`, `isDefault`). Tooling could share a base. | +| D-03 | `definition` and `policyFamilyDefinitionOverrides` (`model.ts:24, 42`, `model.ts:72, 90`, `model.ts:226, 244`) | Low | Distinct concepts (full definition vs. override deltas), but the names alone don't communicate "two mutually exclusive ways of supplying a definition". The JSDoc explains the relationship; OK. | ### 2.12 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| T-01 | `createPolicy`, `deletePolicy`, `editPolicy`, `getPolicy`, `listPolicies` | Low | All imperative present-tense — consistent. | -| T-02 | `createdAtTimestamp` (past participle) | Low | Correct for a timestamp field. | -| T-03 | `isDefault` (boolean) | Low | Standard `is*` boolean prefix. Consistent with the rest of the SDK. | +| T-01 | `createPolicy`, `deletePolicy`, `editPolicy`, `getPolicy`, `listPolicies` (`client.ts`) | Low | All imperative present-tense — consistent. | +| T-02 | `createdAtTimestamp` (`model.ts:214`) | Low | Past participle, correct for a timestamp field. | +| T-03 | `isDefault` (`model.ts:219`) | Low | Standard `is*` boolean prefix. Consistent with the rest of the SDK. | ### 2.13 Go / Java-style names — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | -| G-02 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | +| G-01 | `MavenLibrary` (`model.ts:187`), `PythonPyPiLibrary` (`model.ts:251`), `RCranLibrary` (`model.ts:264`) (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | +| G-02 | `httpClient` / `HttpClient` (vs `HTTPClient`) (`client.ts:51`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | ### 2.14 Generic field names losing meaning — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| F-01 | `Library.lib` | High | Loses all meaning once destructured outside the `Library` type. See V-01. | -| F-02 | `MavenLibrary.repo` / `RCranLibrary.repo` / `PythonPyPiLibrary.repo` | Medium | Same field name across three sibling types but each refers to a different concept (Maven repo URL, CRAN mirror, PyPI index URL). Consistent for the API, but ambiguous when displayed without parent type context. | -| F-03 | `Policy.name`, `Policy.description` | Low | Standard entity fields; meaning preserved in context. | -| F-04 | `MavenLibrary.coordinates` | Low | Maven-specific; precise. | +| F-01 | `Library.lib` (`model.ts:106`) | High | Loses all meaning once destructured outside the `Library` type. See V-01. | +| F-02 | `MavenLibrary.repo` (`model.ts:194`) / `RCranLibrary.repo` (`model.ts:268`) / `PythonPyPiLibrary.repo` (`model.ts:261`) | Medium | Same field name across three sibling types but each refers to a different concept (Maven repo URL, CRAN mirror, PyPI index URL). Consistent for the API, but ambiguous when displayed without parent type context. | +| F-03 | `Policy.name` (`model.ts:224`), `Policy.description` (`model.ts:228`) | Low | Standard entity fields; meaning preserved in context. | +| F-04 | `MavenLibrary.coordinates` (`model.ts:189`) | Low | Maven-specific; precise. | | F-05 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | ### 2.15 Field contradicting type domain — Low @@ -242,22 +238,19 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| AV-01 | `editPolicy()` vs ecosystem-standard `update` | Medium | Most modern Databricks APIs (and broader REST APIs) use **update**. This package uses **edit** to match the API path `/api/2.0/policies/clusters/edit`. The verb mismatch within the Databricks SDK as a whole (e.g. `Clusters.editCluster` exists, but newer surfaces use `update*`) is upstream. Flagged for awareness. | -| AV-02 | `getPolicy()` (singular) vs `listPolicies()` (plural) | Low | Correct convention (singular get, plural list). Consistent. | +| AV-01 | `editPolicy()` (`client.ts:133`) vs ecosystem-standard `update` | Medium | Most modern Databricks APIs (and broader REST APIs) use **update**. This package uses **edit** to match the API path `/api/2.0/policies/clusters/edit`. The verb mismatch within the Databricks SDK as a whole (e.g. `Clusters.editCluster` exists, but newer surfaces use `update*`) is upstream. Flagged for awareness. | +| AV-02 | `getPolicy()` (`client.ts:159`, singular) vs `listPolicies()` (`client.ts:190`, plural) | Low | Correct convention (singular get, plural list). Consistent. | -### 2.17 Long enum values — Medium +### 2.17 Long enum values -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| L-01 | `PolicySortColumn.POLICY_CREATION_TIME` | Medium | 21-char identifier. Combined with the enum-prefix redundancy (E-01), `PolicySortColumn.CREATION_TIME` would be 14 chars and lose nothing. | -| L-02 | `PolicySortColumn.POLICY_NAME` | Low | Only redundancy, not length per se. | +_None._ ### 2.18 Underspecified IDs — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| I-01 | `policyId` | Low | Well-specified: scope = policy. No collision with workspace / account / cluster IDs in this package. Good. | -| I-02 | `policyFamilyId` | Low | Scoped correctly. Good. | +| I-01 | `policyId` (`model.ts:52, 57, 65, 102, 207`) | Low | Well-specified: scope = policy. No collision with workspace / account / cluster IDs in this package. Good. | +| I-02 | `policyFamilyId` (`model.ts:34, 82, 236`) | Low | Scoped correctly. Good. | (Section retained for parity with the rubric; no high findings in this package.) @@ -265,21 +258,34 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `MavenLibrary` | Medium | The type already lives in a `Library` discriminated union; the `Library` suffix is redundant when accessed as `library.lib.$case === 'maven' ? library.lib.maven : ...` — the value's *position* in the union already identifies it as a library variant. `MavenSpec` or just `Maven` would suffice. | -| TS-02 | `PythonPyPiLibrary` | Medium | Same as TS-01. Could be `PyPISpec`. | -| TS-03 | `RCranLibrary` | Medium | Same as TS-01. Could be `CRANSpec`. | -| TS-04 | `Library` (interface itself) | Low | The interface name `Library` and its sole field `lib` share a stem, so call sites read as `library.lib` (a stem repetition). Field rename is covered by V-01 / F-01. | +| TS-01 | `MavenLibrary` (`model.ts:187`) | Medium | The type already lives in a `Library` discriminated union; the `Library` suffix is redundant when accessed as `library.lib.$case === 'maven' ? library.lib.maven : ...` — the value's *position* in the union already identifies it as a library variant. `MavenSpec` or just `Maven` would suffice. | +| TS-02 | `PythonPyPiLibrary` (`model.ts:251`) | Medium | Same as TS-01. Could be `PyPISpec`. | +| TS-03 | `RCranLibrary` (`model.ts:264`) | Medium | Same as TS-01. Could be `CRANSpec`. | +| TS-04 | `Library` interface itself (`model.ts:105`) | Low | The interface name `Library` and its sole field `lib` share a stem, so call sites read as `library.lib` (a stem repetition). Field rename is covered by V-01 / F-01. | ### 2.20 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | `Policy.createdAtTimestamp` (epoch ms, `number`) | Medium | Beyond redundancy (O-02), JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | -| X-02 | `Library.lib.$case` literal `'requirements'` | Low | The discriminator value `'requirements'` is the longest in the union (12 chars) and contrasts with three-letter peers (`jar`, `egg`, `whl`). Consistent with wire format, OK. | -| X-03 | `HttpCallOptions` (utils) | Low | Local interface; precise. | -| X-04 | `executeHttpCall`, `executeCall` | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | -| X-05 | `readAll` (utils, private) | Low | Reads a `ReadableStream` to a `Uint8Array`. Standard name. | -| X-06 | `flattenQueryParams` (utils, exported but unused in this package?) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | +| X-01 | `Policy.createdAtTimestamp` (`model.ts:214`, epoch ms, `number`) | Medium | Beyond redundancy (O-02), JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | +| X-02 | `Library.lib.$case` literal `'requirements'` (`model.ts:156`) | Low | The discriminator value `'requirements'` is the longest in the union (12 chars) and contrasts with three-letter peers (`jar`, `egg`, `whl`). Consistent with wire format, OK. | +| X-03 | `HttpCallOptions` (`utils.ts:15`) | Low | Local interface; precise. | +| X-04 | `executeHttpCall` (`utils.ts:65`), `executeCall` (`utils.ts:26`) | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | +| X-05 | `readAll` (`utils.ts:40`, private) | Low | Reads a `ReadableStream` to a `Uint8Array`. Standard name. | +| X-06 | `flattenQueryParams` (`utils.ts:123`, exported but unused in this package?) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | + +### 2.21 Proto / architectural-leak naming + +_None._ Scanned all identifiers in `model.ts`, `client.ts`, `utils.ts`, and +`index.ts` for mid-position `Public`/`Internal`/`External` (non-domain), +`Proto` suffix/infix, `Service`/`Server`/`Backend`/`Frontend`, `Rpc`/`Grpc`, +`Manager`/`Handler`/`Controller`/`Processor`/`Daemon`/`Worker` (non-domain), +`Impl`, `Proxy` (non-real), `Action`/`Op` mid duplicating a verb, +`Wrapper`/`Adapter`, `Old`/`New`/`Legacy`/`Modern`, `V1`/`V2` mid, +`Api`/`Sdk`/`Client` mid, repeated `Spec`/`Config`/`Details`/`Info`, and +`Foo_PublicRequest` shapes. No matches: the only `Client` is the top-level +exported class (terminal position, standard SDK convention), and there are no +architectural-layer words leaking into domain identifiers. --- @@ -289,10 +295,10 @@ _None._ | Severity | Count | | -------- | ----- | -| High | 6 | -| Medium | 17 | -| Low | 22 | -| **Total**| **45**| +| High | 4 | +| Medium | 16 | +| Low | 21 | +| **Total**| **41**| ### 3.2 Top themes @@ -301,21 +307,16 @@ _None._ name doesn't. A concrete name like `source` / `kind` / `spec` reads better at call sites. -2. **`PolicySortColumn.POLICY_*` repeats the enum prefix**; trimming to - `CREATION_TIME` / `NAME` shortens call sites and matches enum-design - guidance. - -3. **`PyPi` casing should be `PyPI`** (acronym), and `package` fields collide +2. **`PyPi` casing should be `PyPI`** (acronym), and `package` fields collide with a JS strict-mode reserved word in `PythonPyPiLibrary` / `RCranLibrary`. -4. **`createdAtTimestamp` is a tautology**; `createdAt` is the SDK-wide and +3. **`createdAtTimestamp` is a tautology**; `createdAt` is the SDK-wide and ecosystem-wide convention for epoch-millisecond fields. ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) - Rename `Library.lib` -> `Library.source` (concrete discriminator name). -- Trim `PolicySortColumn` members. - `PythonPyPiLibrary` -> `PythonPyPILibrary`. - `Policy.createdAtTimestamp` -> `Policy.createdAt`. - `Policy.creatorUserName` -> `Policy.createdBy`. @@ -324,3 +325,7 @@ section is advisory for the codegen owners) - `editPolicy` (vs `updatePolicy`) is a per-API decision driven by the upstream REST verb; flag for upstream alignment but no per-package fix. + +## Fixed + +_None._ diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index 4be667d6..5e370d21 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -3,419 +3,431 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 **Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 76 +**Total weird names flagged:** 78 ## Summary | Severity | Count | | --- | --- | -| High | 12 | -| Medium | 31 | +| High | 9 | +| Medium | 36 | | Low | 24 | | Observation | 9 | ## High severity -### 1. `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — `src/v2/model.ts:29-37` -- **Why weird:** Every enum value redundantly re-states the enum's cloud (`_AZURE`). Same for `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` (`model.ts:146-148`). Compare with `AwsAvailability` (`model.ts:12-22`) where AWS-specific values are unprefixed (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`). Three sibling enums, three different conventions. -- **Category:** 2 (redundant enum prefix), 17 (inconsistent across the AWS/Azure/GCP triplet). -- **Suggested name:** `AzureAvailability.Spot | OnDemand | SpotWithFallback` and `GcpAvailability.Preemptible | OnDemand | PreemptibleWithFallback`. -- **Rationale:** The enum name already states the cloud (`AzureAvailability`). Wire values can stay as-is; TS enum identifiers should not duplicate the type. AWS already does it correctly — Azure/GCP should follow. - -### 2. `ComputeKind.COMPUTE_KIND_UNSPECIFIED` — `src/v2/model.ts:58` -- **Why weird:** Member name re-states the enum name as a prefix. TypeScript enums are already namespaced; `ComputeKind.UNSPECIFIED` is the same wire string with no prefix duplication. -- **Category:** 2 (redundant enum prefix), 14 (proto-style). -- **Suggested name:** `ComputeKind.Unspecified | ClassicPreview`. Better yet, drop `Unspecified` entirely and use `kind?: ComputeKind | undefined`. -- **Rationale:** Same logic as #1. `COMPUTE_KIND_` is pure proto noise. - -### 3. `ConfidentialComputeType.CONFIDENTIAL_COMPUTE_TYPE_UNSPECIFIED` / `CONFIDENTIAL_COMPUTE_TYPE_NONE` — `src/v2/model.ts:69-70` -- **Why weird:** Same redundant prefix as #2 but worse — the enum has three values, two of which carry the full prefix, while the third (`SEV_SNP`) does not. So readers see `CONFIDENTIAL_COMPUTE_TYPE_NONE` next to `SEV_SNP` and have to guess at the pattern. -- **Category:** 2 (redundant prefix), 17 (inconsistent within the same enum). -- **Suggested name:** `ConfidentialComputeType.Unspecified | None | SevSnp`. Drop `Unspecified` to rely on `confidentialComputeType?: ConfidentialComputeType | undefined`. -- **Rationale:** Enums should pick one prefix convention; this one mixes both within three values. - -### 4. `DataSecurityMode.DATA_SECURITY_MODE_STANDARD` / `DATA_SECURITY_MODE_DEDICATED` / `DATA_SECURITY_MODE_AUTO` — `src/v2/model.ts:123-127` -- **Why weird:** Three values redundantly prefixed with `DATA_SECURITY_MODE_`. The other six values in the enum (`NONE`, `SINGLE_USER`, `USER_ISOLATION`, `LEGACY_TABLE_ACL`, `LEGACY_PASSTHROUGH`, `LEGACY_SINGLE_USER`, `LEGACY_SINGLE_USER_STANDARD`) are unprefixed. So the same enum mixes both styles. The JSDoc itself notes some are aliases: "`DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`". So the enum has duplicate values for the same concept and inconsistent naming. -- **Category:** 2 (redundant prefix), 12 (duplicate concepts: STANDARD alias for USER_ISOLATION; DEDICATED alias for SINGLE_USER), 17 (mixed prefix/no-prefix in one enum). -- **Suggested name:** Either align (`DataSecurityMode.Auto | Standard | Dedicated` and drop the long-form aliases) or normalise away the aliases. -- **Rationale:** Public SDK enums should not ship both `USER_ISOLATION` and `DATA_SECURITY_MODE_STANDARD` if they mean the same thing — pick one, document deprecation on the other. - -### 5. `CloudProviderNodeStatus` enum uses non-SCREAMING_SNAKE wire values — `src/v2/model.ts:40-43` +### 1. `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — `src/v2/model.ts:28-37` +- **Why weird:** Every enum value redundantly re-states the enum's cloud (`_AZURE`). Same for `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` (`model.ts:151-154`). Compare with `AwsAvailability` (`model.ts:12-22`) where AWS-specific values are unprefixed (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`). Three sibling enums, three different conventions — the `_AZURE`/`_GCP` suffix is a cloud tag, not a proto-style enum-name prefix, and it makes cross-cloud asymmetry visible at the call site. +- **Category:** 17 (inconsistent across the AWS/Azure/GCP triplet). +- **Suggested name:** Either drop `_AZURE`/`_GCP` from Azure/GCP to match AWS, or add the cloud suffix back to AWS (`SPOT_AWS`, `ON_DEMAND_AWS`, `SPOT_WITH_FALLBACK_AWS`). Pick one. +- **Rationale:** Cross-cloud asymmetry — the AWS triplet says one thing, Azure/GCP triplets say another. Either all three carry the cloud tag or none do. + +### 2. `DataSecurityMode` duplicate-concept aliases — `src/v2/model.ts:99-134` +- **Why weird:** The enum's JSDoc itself notes some values are aliases: "`DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`" and "`DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`". So the enum has duplicate values for the same concept under different names. +- **Category:** 12 (duplicate concepts: STANDARD alias for USER_ISOLATION; DEDICATED alias for SINGLE_USER). +- **Suggested name:** Pick one of each aliased pair and document deprecation on the other. +- **Rationale:** Public SDK enums should not ship two members for one concept; one of each pair should be `@deprecated`. + +### 3. `CloudProviderNodeStatus` enum uses non-SCREAMING_SNAKE wire values — `src/v2/model.ts:40-43` - **Why weird:** `NOT_ENABLED_ON_SUBSCRIPTION = 'NotEnabledOnSubscription'` and `NOT_AVAILABLE_IN_REGION = 'NotAvailableInRegion'`. The TS identifier is `SCREAMING_SNAKE` (every other enum in this file follows that), but the wire value is `PascalCase`. Every other enum's wire value matches the TS identifier exactly. - **Category:** 17 (inconsistent wire-value casing). - **Suggested name:** Keep the SCREAMING_SNAKE TS identifier; this is an upstream wire-value inconsistency that the generator faithfully reproduces. - **Rationale:** Highlight to upstream — the API surface should be uniform. Flagged here so downstream consumers know to expect PascalCase strings for this one enum. -### 6. `TerminationCode.*` — 150+ enum values, many proto-style noisy — `src/v2/model.ts:164-748` +### 4. `TerminationCode.*` — 150+ enum values, internal jargon and duplicated concepts — `src/v2/model.ts:175-734` - **Why weird:** The enum has ~150 values; many encode the same concept three or four times. Examples: `BOOTSTRAP_TIMEOUT` vs `BOOTSTRAP_TIMEOUT_DUE_TO_MISCONFIG` vs `BOOTSTRAP_TIMEOUT_CLOUD_PROVIDER_EXCEPTION`; `INSTANCE_UNREACHABLE` vs `INSTANCE_UNREACHABLE_DUE_TO_MISCONFIG`; `CONTROL_PLANE_REQUEST_FAILURE` vs `CONTROL_PLANE_REQUEST_FAILURE_DUE_TO_MISCONFIG` (whose JSDoc just says "CPRF, but due to misconfiguration on the customer's side"). Several values reference internal Databricks jargon: `NEPHOS_RESOURCE_MANAGEMENT`, `CHAUFFEUR`, `NPIP_TUNNEL`, `IN_PENALTY_BOX`, `CMv2`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT`, `GKE_BASED_CLUSTER_TERMINATION`. -- **Category:** 5 (cryptic abbreviations — Nephos, CPRF, CPLF, CMv2, DBR, NPIP, CMK, K8s, IMv2), 12 (duplicate concepts — many `_DUE_TO_MISCONFIG` siblings duplicate the base reason), 18 (long enum values). +- **Category:** 5 (cryptic abbreviations — Nephos, CPRF, CPLF, CMv2, DBR, NPIP, CMK, K8s, IMv2), 8 (internal jargon in public surface), 12 (duplicate concepts — many `_DUE_TO_MISCONFIG` siblings duplicate the base reason), 18 (150-value enum size). - **Suggested name:** Out of scope for a rename, but flag upstream: collapse `_DUE_TO_MISCONFIG` siblings into a structured field (`misconfig: boolean` on `TerminationReason`) instead of doubling every code; document internal-jargon codes for external consumers. -- **Rationale:** This is a public SDK; values like `IN_PENALTY_BOX` and `NEPHOS_RESOURCE_MANAGEMENT` leak internal-process names to customers and are unfit for external naming. Comments on `GCP_QUOTA_EXCEEDED` (`model.ts:410`) literally include a TODO about consolidating per-cloud reasons — the SDK is shipping the unconsolidated state. +- **Rationale:** This is a public SDK; values like `IN_PENALTY_BOX` and `NEPHOS_RESOURCE_MANAGEMENT` leak internal-process names to customers and are unfit for external naming. Comments on `GCP_QUOTA_EXCEEDED` (`model.ts:426`) literally include a TODO about consolidating per-cloud reasons — the SDK is shipping the unconsolidated state. The enum size alone (150 values) is a domain concern. -### 7. `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` — `src/v2/model.ts:421` +### 5. `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` — `src/v2/model.ts:432` - **Why weird:** `BYOK` is "Bring Your Own Key". Abbreviation used without expansion in either the enum value or the JSDoc. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** Expand to `AZURE_CUSTOMER_KEY_PERMISSION_FAILURE` or document `BYOK` inline. - **Rationale:** External SDK users will not all know `BYOK` is a cloud-key acronym. -### 8. `TerminationCode.NPIP_TUNNEL_TOKEN_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE` — `src/v2/model.ts:309,350` +### 6. `TerminationCode.NPIP_TUNNEL_TOKEN_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE` — `src/v2/model.ts:320,361` - **Why weird:** `NPIP` ("No Public IP") is internal Databricks networking terminology. Not expanded in JSDoc. - **Category:** 5 (cryptic abbreviation), 8 (internal jargon in public surface). - **Suggested name:** Rename to `NO_PUBLIC_IP_TUNNEL_*` or document `NPIP` in the enum docstring. -- **Rationale:** Same as #7; SDK users should not need to know Databricks' internal acronyms. +- **Rationale:** Same as #5; SDK users should not need to know Databricks' internal acronyms. -### 9. `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` / `DBR_IMAGE_RESOLUTION_FAILURE` — `src/v2/model.ts:380,729` -- **Why weird:** `DBR` ("Databricks Runtime") and `K8S` ("Kubernetes") used together with no expansion. JSDoc on line 380 says "DBR Cluster launched on K8s (i.e. CMv2)" — three acronyms in one sentence. +### 7. `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` / `DBR_IMAGE_RESOLUTION_FAILURE` — `src/v2/model.ts:391,726` +- **Why weird:** `DBR` ("Databricks Runtime") and `K8S` ("Kubernetes") used together with no expansion. JSDoc on line 390 says "DBR Cluster launched on K8s (i.e. CMv2)" — three acronyms in one sentence. - **Category:** 5 (cryptic abbreviation), 8 (jargon). - **Suggested name:** Expand acronyms in JSDoc minimum; consider renaming to `DATABRICKS_RUNTIME_CLUSTER_LAUNCH_TIMEOUT_KUBERNETES`. - **Rationale:** Internal SDK people read `DBR` daily; external consumers don't. -### 10. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` — `src/v2/model.ts:368` -- **Why weird:** Enum value is 52 characters long; says "AWS insufficient free addresses in subnet failure". GCP equivalent is `GCP_IP_SPACE_EXHAUSTED` (`model.ts:579`), 22 chars — same concept, very different length. JSDoc at line 410 explicitly TODOs consolidating these. -- **Category:** 7 (overly verbose), 17 (inconsistent across clouds), 18 (long enum value). +### 8. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` vs `GCP_IP_SPACE_EXHAUSTED` cross-cloud asymmetry — `src/v2/model.ts:379,590` +- **Why weird:** AWS enum value is 52 characters; GCP equivalent is 22 chars — same concept, very different length. JSDoc at line 421 explicitly TODOs consolidating these. +- **Category:** 17 (inconsistent across clouds). - **Suggested name:** `AWS_SUBNET_IP_EXHAUSTED` (mirror the GCP form). - **Rationale:** Per-cloud variants should follow the same shape; the AWS/GCP/Azure versions of the same condition should not differ in length by 30 characters. -### 11. `TerminationCode.AZURE_UNEXPECTED_DEPLOYMENT_TEMPLATE_FAILURE` / `AZURE_PACKED_DEPLOYMENT_PARTIAL_FAILURE` — `src/v2/model.ts:323,493` -- **Why weird:** 45- and 41-character enum values. Both are Azure-deployment-template-specific. AWS and GCP do not have equivalents at this length. -- **Category:** 7 (overly verbose), 18 (long enum value). -- **Suggested name:** `AZURE_DEPLOYMENT_TEMPLATE_FAILURE`, `AZURE_PACKED_DEPLOYMENT_FAILURE` (drop the qualifier; let the JSDoc carry the nuance). -- **Rationale:** Public enums should be readable at a glance. - -### 12. `TerminationCode.ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` — `src/v2/model.ts:675` -- **Why weird:** 53-character enum value. Eight `ALLOCATION_TIMEOUT_*` siblings (`model.ts:650-675`) all encode subtle internal scheduler states. -- **Category:** 7 (overly verbose), 12 (duplicate concept across eight near-identical codes), 18 (long enum value). +### 9. `TerminationCode.ALLOCATION_TIMEOUT_*` family — eight near-identical codes — `src/v2/model.ts:661-686` +- **Why weird:** Eight `ALLOCATION_TIMEOUT_*` siblings all encode subtle internal scheduler states (e.g., `ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` at line 686). +- **Category:** 12 (duplicate concept across eight near-identical codes). - **Suggested name:** Collapse the family into `ALLOCATION_TIMEOUT` with a structured sub-field (`reason: string`) on `TerminationReason.parameters`. - **Rationale:** Eight `ALLOCATION_TIMEOUT_*` codes look like the inverse of "values should be discriminator-friendly". External callers will hardly distinguish `NO_HEALTHY_CLUSTERS` from `NO_HEALTHY_AND_WARMED_UP_CLUSTERS`. ## Medium severity -### 13. `Adlsgen2Info` casing — `src/v2/model.ts:800` +### 10. `Adlsgen2Info` casing — `src/v2/model.ts:917` - **Why weird:** Type name is `Adlsgen2Info` — should be `AdlsGen2Info` to match acronym-casing rules. ADLS (Azure Data Lake Storage) Gen2 should retain the boundary between `Adls` and `Gen2`. - **Category:** 3 (acronym casing inconsistency), 1 (vague `Info` suffix). - **Suggested name:** `AdlsGen2Storage` (or just `AbfssStorage`, since the wire name is `abfss`). - **Rationale:** Compare to sibling types `DbfsStorageInfo`, `GcsStorageInfo`, `S3StorageInfo` — all use `Info` suffix and capitalize the storage product. `Adlsgen2Info` is the odd one out. -### 14. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:800,1745,2102,2290,2456,2801,2824` +### 11. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:917,2101,2509,2875,3044,3391,3414` - **Why weird:** `Adlsgen2Info` (no `Storage`), `DbfsStorageInfo`, `GcsStorageInfo`, `LocalFileInfo` (no `Storage`), `S3StorageInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. Seven sibling types; five say `StorageInfo`, two say `Info`. - **Category:** 17 (inconsistent suffix across siblings). - **Suggested name:** Standardise on `XStorage` (drop the redundant `Info`) — `AdlsGen2Storage`, `DbfsStorage`, `GcsStorage`, `LocalFileStorage`, `S3Storage`, `VolumesStorage`, `WorkspaceStorage`. - **Rationale:** All seven describe the same kind of thing (a storage destination). Either all of them get `StorageInfo` or none do. -### 15. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:946,2112,2118,2227,2244` -- **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForCluster` (a request), `GetPolicyComplianceForCluster_Response`, `EnforcePolicyComplianceForCluster` (request), `ListClusterComplianceForPolicy` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. +### 12. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:1253,2350,2361,2595,2812` +- **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForClusterRequest` (a request), `GetPolicyComplianceForClusterRequest_Response`, `EnforcePolicyComplianceForClusterRequest` (request), `ListClusterComplianceForPolicyRequest` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. - **Category:** 1 (vague — `For` is the only disambiguator), 6 (misleading — easy to mis-parse). -- **Suggested name:** `GetClusterPolicyCompliance`, `EnforceClusterPolicyCompliance`, `ListPolicyCompliantClusters`, `ClusterPolicyCompliance`. +- **Suggested name:** `GetClusterPolicyComplianceRequest`, `EnforceClusterPolicyComplianceRequest`, `ListPolicyCompliantClustersRequest`, `ClusterPolicyCompliance`. - **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. -### 16. `validateOnly` field — `src/v2/model.ts:2001` -- **Why weird:** Field on `EnforcePolicyComplianceForCluster`. Verb-prefixed boolean reads as a method; doc says "if set, previews the changes" — closer to a `previewOnly`/`dryRun` flag. +### 13. `validateOnly` field — `src/v2/model.ts:2357` +- **Why weird:** Field on `EnforcePolicyComplianceForClusterRequest`. Verb-prefixed boolean reads as a method; doc says "if set, previews the changes" — closer to a `previewOnly`/`dryRun` flag. - **Category:** 6 (misleading: name implies "validate", behaviour is "dry-run"). - **Suggested name:** `dryRun` or `previewOnly`. - **Rationale:** Common convention; matches what most cloud SDKs name this. Wire stays `validate_only`. -### 17. `hasChanges` field — `src/v2/model.ts:2010` -- **Why weird:** Boolean named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. +### 14. `hasChanges` field — `src/v2/model.ts:2366` +- **Why weird:** Boolean on `EnforcePolicyComplianceForClusterRequest_Response` named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. - **Category:** 12 (duplicate signal), 1 (vague). - **Suggested name:** Drop the field, infer from `changes.length`. - **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. -### 18. `restartUser` field on `RestartCluster` — `src/v2/model.ts:2449` +### 15. `restartUser` field on `RestartClusterRequest` — `src/v2/model.ts:3037` - **Why weird:** No JSDoc. Field name alone doesn't say what it does. Is it "user who triggered the restart"? "User to attribute the restart to"? Inconsistent with the package's general style (`ownerUsername`, `creatorUserName`, `singleUserName` all spell out `Username`/`UserName`). - **Category:** 1 (vague — no doc, ambiguous semantics), 17 (sibling fields say `username` or `userName`, this one says `user`). - **Suggested name:** `restartUsername` or `restartedByUsername`. - **Rationale:** Match the field-naming patterns used elsewhere; even better, document the field. -### 19. `creatorUserName` / `singleUserName` / `ownerUsername` — `src/v2/model.ts:977,1150,930` +### 16. `creatorUserName` / `singleUserName` / `ownerUsername` — `src/v2/model.ts:1299,1181,1047` - **Why weird:** Three "user name" fields in the same model, two different camelCases: `creatorUserName` and `singleUserName` use `UserName` (two words), `ownerUsername` uses `Username` (one word). Wire is `creator_user_name`, `single_user_name`, `owner_username` — the wire is inconsistent too. - **Category:** 3 (casing inconsistency), 17 (sibling field inconsistency). - **Suggested name:** Pick one: `Username` is more conventional in modern web APIs. Go SDK and proto leave this inconsistent; TS could normalise. - **Rationale:** Three similar fields, three (sort of) similar names, two different ways of capitalising the same concept. -### 20. `kind: ComputeKind` field — `src/v2/model.ts:1173` -- **Why weird:** Field is called `kind` on `ClusterInfo`, `CreateCluster`, `EditCluster`, and the update-cluster spec. Sibling fields are very specific (`runtimeEngine`, `dataSecurityMode`, `workloadType`); `kind` is the odd vague one. +### 17. `kind: ComputeKind` field — `src/v2/model.ts:1204` +- **Why weird:** Field is called `kind` on `ClusterInfo`, `CreateClusterRequest`, `EditClusterRequest`, and the update-cluster spec. Sibling fields are very specific (`runtimeEngine`, `dataSecurityMode`, `workloadType`); `kind` is the odd vague one. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `computeKind` (matches the type and wire name `kind` can stay). - **Rationale:** `kind` alone is the JS-reserved-shape problem (`kind` is heavily overloaded in discriminated-union code). `computeKind` is unambiguous. -### 21. `size` discriminated union (`numWorkers` | `autoscale`) — `src/v2/model.ts:1201` +### 18. `size` discriminated union (`numWorkers` | `autoscale`) — `src/v2/model.ts:1523` - **Why weird:** Field `size` is a discriminated union with two variants `numWorkers` (number) and `autoscale` (object). It appears on six cluster-spec-shaped types. The literal `size` doesn't read as "either count or autoscaler" — calling code looks like `if (req.size?.$case === 'numWorkers')` which is awkward. - **Category:** 1 (vague), 6 (misleading: a "size" sounds like an integer). - **Suggested name:** `capacity` (or just `workers`, since both variants describe how many workers). - **Rationale:** "size" suggests a number; this field is a tagged union. A different word avoids the contradiction. -### 22. `useMlRuntime` field — `src/v2/model.ts:1179` +### 19. `useMlRuntime` field — `src/v2/model.ts:1210` - **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. - **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). - **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. -- **Rationale:** A boolean and an enum jointly describing one runtime selection is a smell. +- **Rationale:** A boolean and an enum jointly describing one runtime selection is a boolean-shaped-enum smell. -### 23. `isSingleNode` field — `src/v2/model.ts:1185` +### 20. `isSingleNode` field — `src/v2/model.ts:1216` - **Why weird:** Boolean field that, when true, automatically sets `custom_tags`, `spark_conf`, and `num_workers`. Doc admits the surprise: "When set to true, Databricks will automatically set single node related custom_tags, spark_conf, and num_workers." A field that secretly mutates three others is a footgun. - **Category:** 6 (misleading — hidden side effects). - **Suggested name:** Name is fine, but document the side effects in the type-level JSDoc, not just the field doc. - **Rationale:** Flag for upstream — the boolean is doing more than the name suggests. -### 24. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields +### 21. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields - **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. - **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). - **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. - **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. -### 25. `nodeTypeId` vs `instanceTypeId` — `src/v2/model.ts:1076,2321,2350` +### 22. `nodeTypeId` vs `instanceTypeId` — `src/v2/model.ts:1107,2906,2935` - **Why weird:** `nodeTypeId` (string) and `instanceTypeId` (string) appear on different types. `NodeType.instanceTypeId` and `NodeInstanceType.instanceTypeId` are described as "hardware identifier (e.g., r3.2xlarge in AWS)" — i.e., the AWS instance class. `nodeTypeId` is the Databricks node type ID. Easy to confuse the two. - **Category:** 19 (underspecified IDs — multiple "type" IDs coexisting). - **Suggested name:** Either prefix one (`databricksNodeTypeId` / `cloudInstanceTypeId`) or rename `instanceTypeId` to `cloudInstanceTypeId` everywhere. - **Rationale:** Two `*TypeId` fields side by side, distinguished only by `node` vs `instance`. Real users will get this wrong. -### 26. `driverNodeTypeId` / `nodeTypeId` / `driverInstancePoolId` / `instancePoolId` — `src/v2/model.ts:1076,1085,1148,1160` +### 23. `driverNodeTypeId` / `nodeTypeId` / `driverInstancePoolId` / `instancePoolId` — `src/v2/model.ts:1107,1116,1179,1191` - **Why weird:** Pattern is "`driverX` and `X`" where `X` is the worker version. Four such pairs across the spec (`nodeTypeId`/`driverNodeTypeId`, `instancePoolId`/`driverInstancePoolId`, `nodeTypeFlexibility`/`driverNodeTypeFlexibility` — but the worker version is called `workerNodeTypeFlexibility` while the worker-`nodeTypeId` is just `nodeTypeId`). - **Category:** 17 (inconsistent pairing — sometimes worker is prefix-less, sometimes prefixed `worker`). - **Suggested name:** Either always prefix worker (`workerNodeTypeId`, `workerInstancePoolId`, `workerNodeTypeFlexibility`) or never (drop `worker` from `workerNodeTypeFlexibility`). - **Rationale:** Reader who sees `driverNodeTypeId` next to `nodeTypeId` has to remember that the un-prefixed one is "worker"; then sees `workerNodeTypeFlexibility` and gets thrown. -### 27. `NodeType.numCores` vs `ClusterInfo.clusterCores` — `src/v2/model.ts:2346,992` +### 24. `NodeType.numCores` vs `ClusterInfo.clusterCores` — `src/v2/model.ts:2931,1314` - **Why weird:** Same concept (number of CPU cores) appears as `numCores` on `NodeType` and `clusterCores` on `ClusterInfo`. The `num` prefix is inconsistent with the bare `clusterCores`. - **Category:** 17 (inconsistent prefix), 1 (`num` is vague compared to the rest of the model). - **Suggested name:** `cores` (on `NodeType`) and `clusterCores` stays (or both `cores`/`totalCores`). - **Rationale:** Compare to `clusterMemoryMb` (no `num` prefix), `memoryMb` (no `num` prefix). `numCores` and `numGpus` are the outliers. -### 28. `NodeType.numGpus` — `src/v2/model.ts:2366` -- **Why weird:** Same `num` prefix issue as #27. Sibling fields don't carry a `num` prefix (`memoryMb`, `localDisks`, `category`). +### 25. `NodeType.numGpus` — `src/v2/model.ts:2951` +- **Why weird:** Same `num` prefix issue as #24. Sibling fields don't carry a `num` prefix (`memoryMb`, `localDisks`, `category`). - **Category:** 17 (inconsistent prefix), 1. - **Suggested name:** `gpus` (or `gpuCount`). - **Rationale:** Internal consistency. -### 29. `NodeInstanceType.localDisks` and `NodeInstanceType.localNvmeDisks` are counts — `src/v2/model.ts:2323,2329` +### 26. `NodeInstanceType.localDisks` and `NodeInstanceType.localNvmeDisks` are counts — `src/v2/model.ts:2908,2914` - **Why weird:** Plural noun `localDisks` is typed as `number`, but JSDoc says "Number of local disks that are present on this instance." Counting things should use `count`/`num` suffix, not the plural noun. - **Category:** 9 (singular vs plural confusion — the plural noun is actually a count). - **Suggested name:** `localDiskCount`, `localNvmeDiskCount`. - **Rationale:** A reader sees `localDisks: number` and might assume "array of local disks" — then realises it's a scalar. -### 30. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2325,2327` +### 27. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` - **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. - **Category:** 17 (inconsistent grouping). - **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. - **Rationale:** Within the same type, related fields should sit together. -### 31. `ListAvailableZonesResponse.defaultZone` — `src/v2/model.ts:2224` +### 28. `ListAvailableZonesRequest_Response.defaultZone` — `src/v2/model.ts:2809` - **Why weird:** JSDoc says "The availability zone if no `zone_id` is provided in the cluster creation request." The doc references `zone_id` (the wire name) instead of the TS `zoneId`. Other docstrings in the package also reference `zone_id`, `cluster_id`, `cluster_log_conf`, `init_scripts`, etc. - **Category:** Observation — generated docs reference wire names rather than TS names. - **Suggested name:** Update doc-comment generation to use TS names. - **Rationale:** Inconsistent doc/identifier pairing makes IntelliSense suggestions look out-of-date. -### 32. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2295` +### 29. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2880` - **Why weird:** `LogAnalyticsInfo` has two fields (`logAnalyticsWorkspaceId`, `logAnalyticsPrimaryKey`), both un-documented. The type itself has no JSDoc. Used only by `AzureAttributes.logAnalyticsInfo`. - **Category:** Observation (no naming issue per se, but missing context). - **Suggested name:** Keep `LogAnalyticsInfo` (Azure Monitor terminology) but add a JSDoc; consider `AzureLogAnalyticsConfig`. - **Rationale:** Both fields are Azure-specific; naming should signal that. -### 33. `LogSyncStatus.lastException: string` — `src/v2/model.ts:2311` +### 30. `LogSyncStatus.lastException: string` — `src/v2/model.ts:2896` - **Why weird:** Field name is `lastException` (singular: the previous exception) but the type is `string`. JS exceptions are usually serialised as messages; a more accurate name would be `lastExceptionMessage`. - **Category:** 1 (vague — `Exception` is overloaded), 16 (type contradicts the name domain). - **Suggested name:** `lastErrorMessage` or `lastExceptionMessage`. - **Rationale:** Distinguishes an Error object reference from its serialised string form. -### 34. `LogSyncStatus.lastAttempted: number` — `src/v2/model.ts:2306` +### 31. `LogSyncStatus.lastAttempted: number` — `src/v2/model.ts:2891` - **Why weird:** `lastAttempted` is a verb-past-participle, type is `number` (epoch millis per JSDoc). Hard to tell from the name that this is a timestamp. - **Category:** 1 (vague), 6 (misleading — sounds like a boolean or count). - **Suggested name:** `lastAttemptedAt`, `lastAttemptTime`, `lastAttemptedMs`. - **Rationale:** Match the timestamp-suffix convention used elsewhere in this model (`startTime`, `terminatedTime`, `lastRestartedTime`, `lastStateLossTime`). -### 35. `ClusterInfo.startTime`/`terminatedTime`/`lastStateLossTime`/`lastRestartedTime` — `src/v2/model.ts:1194-1200` -- **Why weird:** Four sibling timestamps. `startTime` and `terminatedTime` use different shapes (`start` + `Time` vs `terminated` + `Time`); `lastStateLossTime` and `lastRestartedTime` use past participle + `Time`. Mix of forms. Also `LogSyncStatus.lastAttempted` (#34) drops the `Time` suffix entirely. +### 32. `ClusterInfo.startTime`/`terminatedTime`/`lastStateLossTime`/`lastRestartedTime` — `src/v2/model.ts:1516-1522` +- **Why weird:** Four sibling timestamps. `startTime` and `terminatedTime` use different shapes (`start` + `Time` vs `terminated` + `Time`); `lastStateLossTime` and `lastRestartedTime` use past participle + `Time`. Mix of forms. Also `LogSyncStatus.lastAttempted` (#31) drops the `Time` suffix entirely. - **Category:** 17 (inconsistent timestamp suffix), 13 (verb-tense inconsistency: `start` vs `terminated` vs `restarted`). - **Suggested name:** Choose one suffix (`-At`, `-Time`, `-Ms`) and apply uniformly: `startedAt`, `terminatedAt`, `lastStateLostAt`, `lastRestartedAt`, `lastAttemptedAt`. - **Rationale:** Timestamp suffixes are a high-impact, low-cost consistency win. -### 36. `SparkNode.startTimestamp` — `src/v2/model.ts:2521` -- **Why weird:** Same node-related concept as `ClusterInfo.startTime` (#35) but uses `Timestamp` rather than `Time`. Different word for the same idea. +### 33. `SparkInfo_SparkNode.startTimestamp` — `src/v2/model.ts:3109` +- **Why weird:** Same node-related concept as `ClusterInfo.startTime` (#32) but uses `Timestamp` rather than `Time`. Different word for the same idea. - **Category:** 17 (inconsistent across types). - **Suggested name:** `startTime` (or align all timestamps under one suffix). - **Rationale:** Two timestamp suffixes in the same file is two too many. -### 37. `creatorUserName` field — `src/v2/model.ts:977` -- **Why weird:** TS camelCase splits `User` and `Name` (`creatorUserName`) but the conceptually-similar `singleUserName` does the same. Compare to `ownerUsername` (one word) on `ChangeClusterOwner`. Inconsistency between three sibling concepts. Documented behaviour: "The field won't be included in the response if the user has already been deleted" — but no `undefined` annotation distinguishes "absent because new" from "absent because deleted". -- **Category:** 3 (casing inconsistency), see also #19. +### 34. `creatorUserName` field — `src/v2/model.ts:1299` +- **Why weird:** TS camelCase splits `User` and `Name` (`creatorUserName`) but the conceptually-similar `singleUserName` does the same. Compare to `ownerUsername` (one word) on `ChangeClusterOwnerRequest`. Inconsistency between three sibling concepts. Documented behaviour: "The field won't be included in the response if the user has already been deleted" — but no `undefined` annotation distinguishes "absent because new" from "absent because deleted". +- **Category:** 3 (casing inconsistency), see also #16. - **Suggested name:** `creatorUsername`. -- **Rationale:** Already covered in #19; flagged again because it appears on the main `ClusterInfo` type which dominates user reading time. +- **Rationale:** Already covered in #16; flagged again because it appears on the main `ClusterInfo` type which dominates user reading time. -### 38. `clusterLogStatus` field — `src/v2/model.ts:1008` +### 35. `clusterLogStatus` field — `src/v2/model.ts:1330` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). - **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. - **Rationale:** Same concept, two different names in 5 lines. -### 39. `jdbcPort` field — `src/v2/model.ts:1036` +### 36. `jdbcPort` field — `src/v2/model.ts:1358` - **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). -- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #40). +- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #37). -### 40. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` +### 37. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` - **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. - **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. -### 41. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:2491` +### 38. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` - **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. - **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). - **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. - **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. -### 42. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:2474,2479,2481` +### 39. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` - **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. - **Category:** 12 (duplicate concepts), 17 (could be a tagged union). - **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). - **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. -### 43. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:2464,2469` +### 40. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:3055,3060` - **Why weird:** JSDoc explicitly says "Either region or endpoint needs to be set. If both are set, endpoint will be used." Mutually-exclusive fields not encoded in the type. - **Category:** 16 (field-pair constraint not in the type). - **Suggested name:** Could be a discriminated union `{kind: 'region', value: string} | {kind: 'endpoint', value: string}`. - **Rationale:** Type-system-encodable constraint; flagged for upstream. +### 41. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` +- **Why weird:** `SparkInfo` is declared as an empty interface (`export interface SparkInfo {}`) whose JSDoc literally says "This is used in both the [[ClusterInfo]] for Cluster APIs and persisted cluster proto." Its only purpose is to namespace `SparkInfo_SparkNode` and `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Empty wrapper types tied to "persisted cluster proto" are pure proto-architectural leak — the TS surface carries a do-nothing type just to mirror proto message nesting. +- **Category:** 14 (proto-style namespace anchor), 8 (JSDoc references the proto wire layer). +- **Suggested name:** Delete `SparkInfo`; expose `SparkNode` (and `SparkNodeAwsAttributes`) as top-level types. +- **Rationale:** TS doesn't need proto-style nesting; the empty parent interface is a generator artefact and a user-facing footgun (auto-completion shows a useless symbol). + +### 42. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` +- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #44) is the smoking gun — the parent exists only to host the child. +- **Category:** 14 (proto-style namespace anchor). +- **Suggested name:** Delete `ClusterEventType` (the parent) and flatten the enum to a top-level `ClusterEventType` enum. The empty wrapper adds no value. +- **Rationale:** Same as #41 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. + +### 43. JSDoc text `"Proto defined to model a mapping from string to string."` — `src/v2/model.ts:1266,2615` +- **Why weird:** Two JSDoc strings literally start with "Proto defined to model...". The word "Proto" leaks the wire encoding into the TS user surface; the rest of the sentence (a `Record`) is generic boilerplate that ships as the only documentation for these `*Entry` types. +- **Category:** 14 (proto vocabulary in public-facing docs). +- **Suggested name:** Rewrite the JSDoc to describe the field semantics in TS terms (e.g., "Key-value pairs of policy violations, keyed by field path."). +- **Rationale:** A TS SDK doc should not say "Proto defined to" — that exposes the implementation strategy. Users see "Proto" in IntelliSense and wonder if they need a proto library. + +### 44. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` +- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#42) is empty, so the doubly-stuttered name carries no information. +- **Category:** 14 (proto nesting stutter), 4 (redundant repetition). +- **Suggested name:** `ClusterEventType` (single, top-level). +- **Rationale:** After deleting the empty parent (#42), the child can drop the `ClusterEventType_` prefix entirely. + +### 45. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` +- **Why weird:** "Data plane" is an internal Databricks infrastructure concept (vs "control plane") — not a customer-facing domain term. Two public types prefix their names with the deployment-plane they originate from. A user creating a cluster does not need to know which plane emitted which event class; the distinction is a Databricks-internal architecture detail. +- **Category:** 8 (internal architecture leak in public surface). +- **Suggested name:** Either merge into a single `ClusterEventType` enum / `EventDetails` shape, or rename to a non-infrastructure word (e.g., `RuntimeEventDetails`). +- **Rationale:** Customer SDK consumers should not be expected to map "data plane" onto their mental model of Databricks. Flagged for upstream — same class as `NEPHOS_RESOURCE_MANAGEMENT` (item #4) and `CMv2` (internal scheduler names leaking into public API). + ## Low severity -### 44. `ClusterInfo.spec` field name — `src/v2/model.ts:1018` +### 46. `ClusterInfo.spec` field name — `src/v2/model.ts:1340` - **Why weird:** Field is just `spec`. Very short for a top-level field on the main cluster type; reader has to follow the type to learn what kind of spec it is. - **Category:** 1 (vague — `spec` alone could mean anything). - **Suggested name:** `computeSpec` or `clusterSpec`. - **Rationale:** A more specific field name documents intent at the call site without forcing the reader to chase the type. -### 45. `ClusterInfo.driver` field — `src/v2/model.ts:1023` +### 47. `ClusterInfo.driver` field — `src/v2/model.ts:1345` - **Why weird:** Field name is `driver` — overloaded (could mean a person or an Apache Spark driver concept). Better: `driverNode`. - **Category:** 1 (vague). - **Suggested name:** `driverNode`. - **Rationale:** Reader sees `driver` and has to know to follow the type. -### 46. `ClusterInfo.executors` field — `src/v2/model.ts:1025` -- **Why weird:** Same as #45. `executors` is fine in Spark vocabulary but better paired with `driverNode`: `executorNodes`. +### 48. `ClusterInfo.executors` field — `src/v2/model.ts:1347` +- **Why weird:** Same as #42. `executors` is fine in Spark vocabulary but better paired with `driverNode`: `executorNodes`. - **Category:** 17 (inconsistent with `driver`). - **Suggested name:** `executorNodes`. - **Rationale:** Match the `driver`/`executor` pattern. -### 47. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1145,1340,1662,1914,2723` -- **Why weird:** JSDoc abbreviation `BYOC` (Bring Your Own Container) used without expansion. Appears five times in the model. +### 49. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1177,1468,1663,2012,2271,3314` +- **Why weird:** JSDoc abbreviation `BYOC` (Bring Your Own Container) used without expansion. Appears six times in the model. - **Category:** 5 (cryptic abbreviation in JSDoc). - **Suggested name:** N/A — fix the comment, not the identifier. - **Rationale:** Quick doc fix. -### 48. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1031` +### 50. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1353` - **Why weird:** Field is named `sparkContextId` but typed as `number`. Other IDs in the model are strings (`clusterId`, `policyId`, `nodeTypeId`). Internal Spark context IDs are 64-bit ints — the type clash hints at potential JS number-precision issues for large IDs. - **Category:** 19 (underspecified ID — different type from sibling IDs). - **Suggested name:** Keep but consider `bigint` typing or document the precision risk. - **Rationale:** JS number safe-integer range is 2^53; if Spark uses 64-bit IDs, this is a latent bug. -### 49. `DockerImage.credsOneof` field name — `src/v2/model.ts:1768` +### 51. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` - **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. - **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). - **Suggested name:** `credentials` (singular). - **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. -### 50. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:1759,1761` +### 52. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:2116,2118` - **Why weird:** Doc strings are "Name of the user" and "Password of the user" — generic and add no information beyond the field names. - **Category:** Observation (low-quality docstrings). - **Suggested name:** No rename; flag doc-quality. - **Rationale:** Minor. -### 51. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:864` -- **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:924`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. +### 53. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:981` +- **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:1041`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. - **Category:** 17 (sibling AWS/Azure shapes differ), 1 (`number` without unit suffix). - **Suggested name:** `spotBidPricePercent` is fine; flag for upstream — the AWS/Azure semantics should be more discoverable from the model. - **Rationale:** Cross-cloud asymmetry is a domain concern. -### 52. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:923` +### 54. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:1041` - **Why weird:** Magic value `-1` overloaded as "do not evict on price basis". Encoded in JSDoc, not in the type. - **Category:** 16 (sentinel value in scalar field), Observation. - **Suggested name:** N/A; flag for upstream to consider a sentinel enum or `null`. - **Rationale:** Sentinels in scalar fields are old-school API design. -### 53. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2051` +### 55. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2458` - **Why weird:** JSDoc says "Note: Soon to be deprecated, use the 'availability' field instead." But the field is not actually marked `@deprecated`. - **Category:** Observation — missing `@deprecated`. - **Suggested name:** Add `@deprecated` JSDoc tag. - **Rationale:** Tooling can pick up `@deprecated`; "Note: Soon to be deprecated" is invisible to IDEs. -### 54. `GcpAttributes.googleServiceAccount: string` — `src/v2/model.ts:2058` +### 56. `GcpAttributes.googleServiceAccount: string` — `src/v2/model.ts:2465` - **Why weird:** Field `googleServiceAccount` lives on `GcpAttributes`. The `google` prefix is redundant — sibling fields don't say `googleZoneId`, `googleAvailability`, `googleBootDiskSize`. - **Category:** 17 (inconsistent prefix within `GcpAttributes`). - **Suggested name:** `serviceAccount` (drop the `google` prefix). - **Rationale:** Internal consistency; the type's name already says GCP. -### 55. `GcpAttributes.bootDiskSize: number` — `src/v2/model.ts:2060` +### 57. `GcpAttributes.bootDiskSize: number` — `src/v2/model.ts:2467` - **Why weird:** Doc says "Boot disk size in GB" but field has no unit suffix. Compare `ebsVolumeSize`/`ebsVolumeIops`/`ebsVolumeThroughput` (no unit suffixes either) and `remoteDiskThroughput` (`Mb/s` per doc, no suffix). Pattern is "no unit suffix" — but `clusterMemoryMb`, `memoryMb`, `localDiskSizeGb` DO have unit suffixes. Inconsistent. - **Category:** 17 (inconsistent unit-suffix convention). - **Suggested name:** `bootDiskSizeGb`. - **Rationale:** Match the `*Mb`, `*Gb` pattern used on the same struct hierarchy. -### 56. `GcpAttributes.localSsdCount: number` field with prose comment — `src/v2/model.ts:2082` +### 58. `GcpAttributes.localSsdCount: number` field with prose comment — `src/v2/model.ts:2489` - **Why weird:** Field is named `localSsdCount`; sibling `bootDiskSize` is unsuffixed; `firstOnDemand` is also unsuffixed. Three different "amount" fields, three different suffix conventions. - **Category:** 17 (inconsistent quantity suffix). - **Suggested name:** Either all carry `Count`/`Size`/`Mb` etc. or none do. - **Rationale:** Within `GcpAttributes`, `localSsdCount` carries a `Count` suffix while `firstOnDemand` (also a count) does not. -### 57. `firstOnDemand` field name — `src/v2/model.ts:829,911,2092` +### 59. `firstOnDemand` field name — `src/v2/model.ts:946,1028,2499` - **Why weird:** Used on `AwsAttributes`, `AzureAttributes`, `GcpAttributes`. Reads as "first on-demand what?". Doc says "The first `first_on_demand` nodes of the cluster will be placed on on-demand instances" — meta-circular. - **Category:** 1 (vague), 7 (no noun). - **Suggested name:** `firstOnDemandNodes` or `onDemandNodeCount`. - **Rationale:** The name is missing the noun it describes. -### 58. `ChangeClusterOwner.ownerUsername` field docstring — `src/v2/model.ts:929` +### 60. `ChangeClusterOwnerRequest.ownerUsername` field docstring — `src/v2/model.ts:1047` - **Why weird:** Doc says "New owner of the cluster_id after this RPC." `RPC` jargon leaks. `cluster_id` is the wire name; should be `clusterId`. - **Category:** Observation (doc quality), 5 (RPC jargon). - **Suggested name:** Update doc text. - **Rationale:** Minor doc fix. -### 59. `ClusterCompliance.violations: Record` — `src/v2/model.ts:956` +### 61. `ClusterCompliance.violations: Record` — `src/v2/model.ts:1263` - **Why weird:** Map from string (policy field path) to string (error message). Field name `violations` doesn't communicate the shape. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `violationsByField` or `fieldViolations`. - **Rationale:** Clarifies the map's semantics. -### 60. `ClusterSettingsChange.field: string` — `src/v2/model.ts:2027` +### 62. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.field: string` — `src/v2/model.ts:2383` - **Why weird:** Field on a "ClusterSettingsChange" is itself named `field`. Reads as `change.field` — circular. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `fieldPath` or `settingName`. - **Rationale:** Minor; flags pile up. -### 61. `ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2034,2041` +### 63. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2390,2397` - **Why weird:** Both fields typed as `string`. JSDoc says values are "either a number, a boolean, or a string converted to a string." Pre-stringified union encoded as plain string — caller must re-parse. - **Category:** 16 (type contradicts domain — it's actually `number | boolean | string` flattened to string). - **Suggested name:** Type as `string | number | boolean`, or `previousValueRaw`. - **Rationale:** Documents the stringification rather than hiding it. -### 62. `SparkVersion.key` / `name` — `src/v2/model.ts:2542,2544` +### 64. `SparkVersion.key` / `name` — `src/v2/model.ts:3130,3132` - **Why weird:** Two very generic field names; from `SparkVersion`, `key` is the version string and `name` is the display name. Inversion of typical (`name`=identifier, `displayName`=human-readable). - **Category:** 1 (vague), 6 (misleading). - **Suggested name:** `version`/`displayName` or `versionKey`/`label`. - **Rationale:** `key` is one of the most overloaded names in software. -### 63. `NodeType.key`-like fields — `nodeTypeId`, `instanceTypeId`, `description`, `category` — `src/v2/model.ts:2338-2390` -- **Why weird:** 20 fields on `NodeType`, several with vague names: `description`, `category`. No JSDoc on `displayOrder` until line 2374. Some fields are `is*` booleans (`isDeprecated`, `isHidden`, `isIoCacheEnabled`, `isEncryptedInTransit`, `isGraviton`), others are `support*` booleans (`supportEbsVolumes`, `supportClusterTags`, `supportPortForwarding`), others are `*Capable` booleans (`photonWorkerCapable`, `photonDriverCapable`). +### 65. `NodeType.key`-like fields — `nodeTypeId`, `instanceTypeId`, `description`, `category` — `src/v2/model.ts:2923-2975` +- **Why weird:** 20 fields on `NodeType`, several with vague names: `description`, `category`. No JSDoc on `displayOrder` until line 2962. Some fields are `is*` booleans (`isDeprecated`, `isHidden`, `isIoCacheEnabled`, `isEncryptedInTransit`, `isGraviton`), others are `support*` booleans (`supportEbsVolumes`, `supportClusterTags`, `supportPortForwarding`), others are `*Capable` booleans (`photonWorkerCapable`, `photonDriverCapable`). - **Category:** 17 (inconsistent boolean prefix: `is*`/`support*`/`*Capable`). - **Suggested name:** Pick one convention (`is*Supported`). - **Rationale:** Three different boolean-naming patterns on one struct. -### 64. `NodeType.supportEbsVolumes` field name — `src/v2/model.ts:2362` +### 66. `NodeType.supportEbsVolumes` field name — `src/v2/model.ts:2947` - **Why weird:** Singular verb `support` (third-person plural would be "supports"). All siblings: `supportClusterTags`, `supportPortForwarding`. Three fields use the singular form. - **Category:** 13 (verb tense — should be `supports`). - **Suggested name:** `supportsEbsVolumes`, `supportsClusterTags`, `supportsPortForwarding`. - **Rationale:** Subject-verb agreement in field names is common (`hasFoo`, `isFoo`, `supportsFoo`). -### 65. `NodeType.photonWorkerCapable` / `photonDriverCapable` — `src/v2/model.ts:2382,2383` +### 67. `NodeType.photonWorkerCapable` / `photonDriverCapable` — `src/v2/model.ts:2967,2968` - **Why weird:** No JSDoc. `*Capable` suffix is a different boolean convention from `is*`/`support*`. - **Category:** 17 (inconsistent boolean shape), Observation (missing doc). - **Suggested name:** `isPhotonWorkerSupported`, `isPhotonDriverSupported` (or `supportsPhotonAsWorker`). -- **Rationale:** Same pattern as #63. +- **Rationale:** Same pattern as #60. -### 66. `TerminationReason.parameters: Record` — `src/v2/model.ts:2561` +### 68. `TerminationReason.parameters: Record` — `src/v2/model.ts:3149` - **Why weird:** Generic-named map. `parameters` could mean anything. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `details`, `metadata`, `errorContext`. - **Rationale:** Clarifies the role of the map. -### 67. `AutoScale` type name — `src/v2/model.ts:805` +### 69. `AutoScale` type name — `src/v2/model.ts:922` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). @@ -423,42 +435,42 @@ ## Observations -### 68. Seven Waiter classes with identical shape — `client.ts:879-1435` +### 70. Seven Waiter classes with identical shape — `client.ts:967-1523` The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. - **Category:** 12 (duplicate concept across seven classes), Observation. - **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. -### 69. `_req` parameter for empty request types — `client.ts:343,422,447` -Several methods take a `_req: ListAvailableZones` / `_req: ListNodeTypes` / `_req: GetSparkVersions` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. +### 71. `_req` parameter for empty request types — `client.ts:404,486,514` +Several methods take a `_req: ListAvailableZonesRequest` / `_req: ListNodeTypesRequest` / `_req: GetSparkVersionsRequest` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. - **Category:** Observation (generator artefact). -### 70. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` +### 72. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` - **Why weird:** Three sibling booleans use `enable*` prefix. `is*` is the more idiomatic JS boolean convention. Inconsistent with `isSingleNode`, `isCompliant`, `isDeprecated`. - **Category:** 17 (mixed `enable*` and `is*` for booleans). - **Rationale:** Naming-convention drift. -### 71. `ResizeCluster` / `RestartCluster` requests are partial overlaps -`ResizeCluster` carries `clusterId` and `size`; `RestartCluster` carries `clusterId` and `restartUser`; `StartCluster` carries only `clusterId`. Three near-identical types; could be one. +### 73. `ResizeClusterRequest` / `RestartClusterRequest` requests are partial overlaps +`ResizeClusterRequest` carries `clusterId` and `size`; `RestartClusterRequest` carries `clusterId` and `restartUser`; `StartClusterRequest` carries only `clusterId`. Three near-identical types; could be one. - **Category:** 12 (duplicate concept), Observation. -### 72. `_req` unused vs `req` used — inconsistency in method-signature lint -Five client methods use `_req` (where the request type is empty), 15 use `req` (where it's not). Pure mechanical. +### 74. `_req` unused vs `req` used — inconsistency in method-signature lint +Three client methods use `_req` (where the request type is empty), the rest use `req` (where it's not). Pure mechanical. - **Category:** Observation. -### 73. `clusterId?: string | undefined` shape -Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:204,246,296,565,604,651,729`). +### 75. `clusterId?: string | undefined` shape +Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:258,304,357,641,683,733,817`). - **Category:** 6 (misleading optional — should be required), Observation. -### 74. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) +### 76. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). - **Category:** 1 (vague), 17 (inconsistent), Observation. -### 75. `flattenQueryParams` exported but unused (`utils.ts:123`) +### 77. `flattenQueryParams` exported but unused (`utils.ts:123`) The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. - **Category:** Observation (dead public surface). -### 76. JSDoc placeholder `` — pervasive -Throughout the model, JSDocs say `` (e.g., `model.ts:1097` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. +### 78. JSDoc placeholder `` — pervasive +Throughout the model, JSDocs say `` (e.g., `model.ts:1128` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. - **Category:** Observation (doc-quality artefact in generator). ## Domain glossary @@ -488,14 +500,14 @@ Throughout the model, JSDocs say `` (e.g., `model.ts:1097` — "Data - `sse-s3` / `sse-kms` — Server-Side Encryption (S3 algorithms). - `gke` — Google Kubernetes Engine (`GKE_BASED_CLUSTER_TERMINATION`). - `k8s` — Kubernetes (used throughout `TerminationCode`). -- `repl` — Read-Eval-Print Loop (Spark REPL, per `model.ts:1021`). +- `repl` — Read-Eval-Print Loop (Spark REPL, per `model.ts:1343`). - `jdbc` — Java Database Connectivity. - `dns` — Domain Name System. - `nic` — Network Interface Card (per `NETWORK_CHECK_NIC_FAILURE`). - `nfs` — Network File System (per `NFS_MOUNT_FAILURE`). - `npip` — No Public IP (Databricks networking jargon). -- `pat` — Personal Access Token (per `model.ts:592`). -- `sdp` — implied by client.ts:746 ("Databricks Jobs, SDP, or Models services"). Likely "Serverless Data Platform" or "Streaming Data Pipelines". +- `pat` — Personal Access Token (per `model.ts:603`). +- `sdp` — implied by client.ts:834 ("Databricks Jobs, SDP, or Models services"). Likely "Serverless Data Platform" or "Streaming Data Pipelines". - `cmv1` / `cmv2` — Cluster Manager v1/v2 (Databricks internal scheduler generations). - `imv2` — Instance Manager v2 (Databricks internal infra, per `INVALID_WORKER_IMAGE_FAILURE`). - `nephos` — Internal serverless infra name (per `NEPHOS_RESOURCE_MANAGEMENT`). @@ -503,14 +515,18 @@ Throughout the model, JSDocs say `` (e.g., `model.ts:1097` — "Data - `chauffeur` — Internal Databricks driver-orchestration daemon (per `DRIVER_UNREACHABLE`). - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). - `sts` — AWS Security Token Service (per `STS_CLIENT_SETUP_FAILURE`). -- `cprf` / `cplf` — Control Plane Request Failure / Cloud Provider Launch Failure (per `model.ts:618-620`). -- `sev_snp` — AMD Secure Encrypted Virtualization — Secure Nested Paging (GCP confidential VM, per `model.ts:71`). -- `csp` — Cloud Service Provider (per `is_csp_unified` in `model.ts:699`). +- `cprf` / `cplf` — Control Plane Request Failure / Cloud Provider Launch Failure (per `model.ts:629-631`). +- `sev_snp` — AMD Secure Encrypted Virtualization — Secure Nested Paging (GCP confidential VM, per `model.ts:70`). +- `csp` — Cloud Service Provider (per `is_csp_unified` in `model.ts:682`). - `luks` — Linux Unified Key Setup (disk encryption, per `enableLocalDiskEncryption` JSDoc). - `uc` — Unity Catalog (referenced in `VolumesStorageInfo`). - `aip` — API Improvement Proposal (`https://google.aip.dev/161` referenced in `updateMask` field doc). ## File coverage -- `src/v2/model.ts` (4414 lines): read fully (in 600-line chunks). -- `src/v2/client.ts` (1435 lines): read fully. +- `src/v2/model.ts` (5315 lines): read fully (in 800-line chunks). +- `src/v2/client.ts` (1523 lines): read fully. - `src/v2/utils.ts` (150 lines): read fully. + +## Fixed + +_None._ diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index 8ca1efdd..394f76dc 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -21,107 +21,48 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | # | Severity | Category | Location | Current | Proposed | | -- | -------- | -------- | -------- | ------- | -------- | -| 1 | high | 2. Redundant enum prefix | `model.ts:21-29` | `CommandStatus.COMMAND_*` | `CommandStatus.Cancelled`, etc. | -| 2 | high | 2. Redundant enum prefix | `model.ts:31-36` | `ContextStatus.CONTEXT_*` | `ContextStatus.Running`, etc. | -| 3 | high | 2. Redundant enum prefix + 18. Long enum values | `model.ts:46-53` | `ResultType.*_RESULT` | `ResultType.Error`, etc. | -| 4 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | -| 5 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | -| 6 | high | 15. Generic field on container | `model.ts:71`, `model.ts:100,112` | `id?: string` (three different IDs) | `contextId`, `commandId` (typed by domain) | -| 7 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | -| 8 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | -| 9 | high | 1. Vague/generic | `model.ts:89` | `command?: string` (field, inside `ExecuteCommandRequest`) | `code` | -| 10 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | -| 11 | medium | 9. Singular/plural mismatch | `model.ts:102,116-143` | `results?: Results` (`Results` is one object) | `result?: Result` | -| 12 | medium | 1. Vague/generic | `model.ts:119` | `data?: JsonValue` | Inline rename to domain (e.g. `tableData`), or document semantics | -| 13 | medium | 16. Field contradicts type domain | `model.ts:129,131` | `fileName`, `fileNames` (used for image data URLs) | `imageData`, `imageDataList` (or `image`, `images`) | -| 14 | medium | 1. Vague/generic | `model.ts:135` | `pos?: number` | `position` (also rename comment to public-friendly) | -| 15 | medium | 1. Vague/generic | `model.ts:138` | `schema?: JsonObject[]` | `tableSchema` (qualify what schema) | -| 16 | medium | 19. Underspecified IDs | `model.ts:71,100,112` | `id?: string` | `contextId` / `commandId` per response | -| 17 | medium | 19. Underspecified IDs | `client.ts:336,337,338` | `clusterId`, `contextId`, `commandId` (fine, but match in `Results.id`) | Audit pass for consistency | -| 18 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | -| 19 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | -| 20 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to present participle or to noun (e.g. `Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, `Running`) | -| 21 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | -| 22 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | -| 23 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 24 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 25 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 26 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 27 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 28 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 29 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | -| 30 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | -| 31 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | -| 32 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | -| 33 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | -| 34 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #15 | -| 35 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | -| 36 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #9 | -| 37 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 38 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | -| 39 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #13 | +| 1 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | +| 2 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | +| 3 | high | 15. Generic field on container | `model.ts:71`, `model.ts:100,112` | `id?: string` (three different IDs) | `contextId`, `commandId` (typed by domain) | +| 4 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | +| 5 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | +| 6 | high | 1. Vague/generic | `model.ts:89` | `command?: string` (field, inside `ExecuteCommandRequest`) | `code` | +| 7 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | +| 8 | medium | 9. Singular/plural mismatch | `model.ts:102,116-143` | `results?: Results` (`Results` is one object) | `result?: Result` | +| 9 | medium | 1. Vague/generic | `model.ts:119` | `data?: JsonValue` | Inline rename to domain (e.g. `tableData`), or document semantics | +| 10 | medium | 16. Field contradicts type domain | `model.ts:129,131` | `fileName`, `fileNames` (used for image data URLs) | `imageData`, `imageDataList` (or `image`, `images`) | +| 11 | medium | 1. Vague/generic | `model.ts:135` | `pos?: number` | `position` (also rename comment to public-friendly) | +| 12 | medium | 1. Vague/generic | `model.ts:138` | `schema?: JsonObject[]` | `tableSchema` (qualify what schema) | +| 13 | medium | 19. Underspecified IDs | `model.ts:71,100,112` | `id?: string` | `contextId` / `commandId` per response | +| 14 | medium | 19. Underspecified IDs | `client.ts:336,337,338` | `clusterId`, `contextId`, `commandId` (fine, but match in `Results.id`) | Audit pass for consistency | +| 15 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | +| 16 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | +| 17 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to a single form (e.g. `Failed` in place of `Error` so every member is a past/present participle). | +| 18 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | +| 19 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | +| 20 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 21 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 22 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 23 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 24 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 25 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 26 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | +| 27 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | +| 28 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | +| 29 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | +| 30 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | +| 31 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #12 | +| 32 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | +| 33 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #6 | +| 34 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 35 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 36 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #10 | --- ## Detailed Findings -### Finding 1 — High — Cat 2 (Redundant enum prefix) -**Location:** `src/v2/model.ts:21-29` -```ts -export enum CommandStatus { - COMMAND_STATUS_UNSPECIFIED = 'COMMAND_STATUS_UNSPECIFIED', - COMMAND_CANCELLED = 'COMMAND_CANCELLED', - COMMAND_CANCELLING = 'COMMAND_CANCELLING', - COMMAND_ERROR = 'COMMAND_ERROR', - COMMAND_FINISHED = 'COMMAND_FINISHED', - COMMAND_QUEUED = 'COMMAND_QUEUED', - COMMAND_RUNNING = 'COMMAND_RUNNING', -} -``` -Every member begins with `COMMAND_`. At a callsite this becomes -`CommandStatus.COMMAND_CANCELLED`, which is verbose and noisy. TypeScript's -namespacing already makes the prefix redundant. -**Proposed:** strip the `COMMAND_` prefix; use idiomatic PascalCase: -`CommandStatus.Cancelled`, `Cancelling`, `Failed`, `Finished`, `Queued`, -`Running`. (See also #4 for casing.) - ---- - -### Finding 2 — High — Cat 2 (Redundant enum prefix) -**Location:** `src/v2/model.ts:31-36` -```ts -export enum ContextStatus { - CONTEXT_STATUS_UNSPECIFIED = 'CONTEXT_STATUS_UNSPECIFIED', - CONTEXT_RUNNING = 'CONTEXT_RUNNING', - CONTEXT_PENDING = 'CONTEXT_PENDING', - CONTEXT_ERROR = 'CONTEXT_ERROR', -} -``` -Same as #1. The `CONTEXT_` prefix is redundant inside `ContextStatus`. -**Proposed:** `ContextStatus.Running`, `Pending`, `Error` (or `Failed`). - ---- - -### Finding 3 — High — Cat 2 & Cat 18 (Long enum values) -**Location:** `src/v2/model.ts:46-53` -```ts -export enum ResultType { - RESULT_TYPE_UNSPECIFIED = 'RESULT_TYPE_UNSPECIFIED', - ERROR_RESULT = 'ERROR_RESULT', - IMAGE_RESULT = 'IMAGE_RESULT', - IMAGES_RESULT = 'IMAGES_RESULT', - TABLE_RESULT = 'TABLE_RESULT', - TEXT_RESULT = 'TEXT_RESULT', -} -``` -Members carry `_RESULT` suffix; the enum is *already* called `ResultType`. -Tautology. -**Proposed:** `ResultType.Error`, `Image`, `Images`, `Table`, `Text` (see also -#4 for casing). - ---- - -### Finding 4 — High — Cat 4 (Underscores in TS identifiers) +### Finding 1 — High — Cat 4 (Underscores in TS identifiers) **Location:** every enum member in `model.ts:22-53`. **Issue:** TS identifier convention is PascalCase for type-namespace members. `COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`, `SCALA` are all @@ -132,18 +73,19 @@ may retain the wire format (`COMMAND_CANCELLED`) to preserve serialisation, but the *identifier* should be `Cancelled`. Example: ```ts export enum CommandStatus { - Cancelled = 'COMMAND_CANCELLED', - Cancelling = 'COMMAND_CANCELLING', - Failed = 'COMMAND_ERROR', - Finished = 'COMMAND_FINISHED', - Queued = 'COMMAND_QUEUED', - Running = 'COMMAND_RUNNING', + CommandStatusUnspecified = 'COMMAND_STATUS_UNSPECIFIED', + CommandCancelled = 'COMMAND_CANCELLED', + CommandCancelling = 'COMMAND_CANCELLING', + CommandError = 'COMMAND_ERROR', + CommandFinished = 'COMMAND_FINISHED', + CommandQueued = 'COMMAND_QUEUED', + CommandRunning = 'COMMAND_RUNNING', } ``` --- -### Finding 5 — High — Cat 12 (Duplicate concepts) +### Finding 2 — High — Cat 12 (Duplicate concepts) **Location:** `src/v2/model.ts:70` and `src/v2/client.ts:289` ```ts export interface CreateResponse { @@ -159,11 +101,11 @@ shared shape is incidental, not semantic. Reusing the type forces a caller reading `response.id` to know the operation to interpret it. **Proposed:** split into `CreateContextResponse { contextId?: string }` and `ExecuteCommandResponse { commandId?: string }`. Each typed `id` field by -its true domain (see #6/#16). +its true domain (see #3/#13). --- -### Finding 6 — High — Cat 15 (Generic field loses meaning) +### Finding 3 — High — Cat 15 (Generic field loses meaning) **Location:** `src/v2/model.ts:71, 100, 112` ```ts export interface CreateResponse { id?: string | undefined; } @@ -172,14 +114,14 @@ export interface GetContextStatusResponse { id?: string | undefined; ... } ``` The field name `id` is meaning-free outside its container, and the container's name doesn't disambiguate (`CreateResponse` is used for two -different create-like operations — see #5). A caller writing `resp.id` +different create-like operations — see #2). A caller writing `resp.id` cannot tell whether it is a command id or a context id. **Proposed:** rename per-response: `contextId` / `commandId`. This couples the schema to the resource, eliminating ambiguity. --- -### Finding 7 — High — Cat 17 (Inconsistent action verbs) +### Finding 4 — High — Cat 17 (Inconsistent action verbs) **Location:** `src/v2/client.ts:256` ```ts /** Deletes an execution context. */ @@ -194,7 +136,7 @@ align with the Go SDK convention. At minimum, edit the JSDoc to say --- -### Finding 8 — High — Cat 17 (Inconsistent action verbs) +### Finding 5 — High — Cat 17 (Inconsistent action verbs) **Location:** `src/v2/client.ts:139, 176` ```ts async commandStatus(req: GetCommandStatusRequest, ...) @@ -209,7 +151,7 @@ the request-type name and is verb-led like the other methods. --- -### Finding 9 — High — Cat 1 & Cat 15 (Vague / generic field name) +### Finding 6 — High — Cat 1 & Cat 15 (Vague / generic field name) **Location:** `src/v2/model.ts:89` ```ts /** Executable code */ @@ -225,7 +167,7 @@ also matches the conceptual model: a `Command` *contains* `code`. --- -### Finding 10 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +### Finding 7 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) **Location:** `src/v2/model.ts:117-143` ```ts export interface Results { ... } @@ -235,22 +177,22 @@ result — a single `cause`, single `summary`, single `resultType`, single `data` object. The plurality comes from the wire-level `fileNames` array inside it, not from multiple results. **Proposed:** rename to `Result` (singular). The field -`GetCommandStatusResponse.results` becomes `result` (see #11). +`GetCommandStatusResponse.results` becomes `result` (see #8). --- -### Finding 11 — Medium — Cat 9 (Singular/plural mismatch) +### Finding 8 — Medium — Cat 9 (Singular/plural mismatch) **Location:** `src/v2/model.ts:102` (field) and `model.ts:116` (type) ```ts results?: Results | undefined; ``` -Pairs with #10. The field name and the type are both pluralised but +Pairs with #7. The field name and the type are both pluralised but represent a singular result. -**Proposed:** `result?: Result;` once #10 is applied. +**Proposed:** `result?: Result;` once #7 is applied. --- -### Finding 12 — Medium — Cat 1 (Vague/generic) +### Finding 9 — Medium — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:119` ```ts data?: JsonValue | undefined; @@ -264,7 +206,7 @@ returned by the command. --- -### Finding 13 — Medium — Cat 16 (Field contradicts type domain) +### Finding 10 — Medium — Cat 16 (Field contradicts type domain) **Location:** `src/v2/model.ts:129, 131` ```ts /** The image data in one of the following formats: @@ -284,7 +226,7 @@ is a public API; mis-named fields will outlive their fix window. --- -### Finding 14 — Medium — Cat 1 (Cryptic abbreviation / vague) +### Finding 11 — Medium — Cat 1 (Cryptic abbreviation / vague) **Location:** `src/v2/model.ts:135` ```ts /** internal field used by SDK */ @@ -297,7 +239,7 @@ public interface entirely. Internal fields belong on private types. --- -### Finding 15 — Medium — Cat 1 (Vague/generic) +### Finding 12 — Medium — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:138` ```ts /** The table schema */ @@ -311,25 +253,25 @@ populated for non-table result types. --- -### Finding 16 — Medium — Cat 19 (Underspecified IDs) +### Finding 13 — Medium — Cat 19 (Underspecified IDs) **Location:** `src/v2/model.ts:71, 100, 112` -**Issue:** Same as #6. Every response that carries an identifier uses +**Issue:** Same as #3. Every response that carries an identifier uses `id?: string` with no domain qualifier. **Proposed:** Rename per-response (`contextId`, `commandId`). Public-API clarity outweighs minor breakage. --- -### Finding 17 — Medium — Cat 19 (Underspecified IDs) — consistency only +### Finding 14 — Medium — Cat 19 (Underspecified IDs) — consistency only **Location:** `src/v2/client.ts:336-338, 417-422, 498-503` (Waiter fields) **Issue:** Waiter classes correctly use `clusterId`, `contextId`, -`commandId`. The inconsistency is only in `Results` / `*Response` (#6/#16). +`commandId`. The inconsistency is only in `Results` / `*Response` (#3/#13). **Proposed:** apply the same explicit-id pattern to all response types so the public surface is uniform. --- -### Finding 18 — Medium — Cat 7 (Overly verbose) +### Finding 15 — Medium — Cat 7 (Overly verbose) **Location:** `src/v2/model.ts:99, 111` ```ts export interface GetCommandStatusResponse { ... } @@ -343,7 +285,7 @@ returned", not "the response to a GET". --- -### Finding 19 — Medium — Cat 20 (Type-suffix tautology) — call-out only +### Finding 16 — Medium — Cat 20 (Type-suffix tautology) — call-out only **Location:** `src/v2/model.ts:55, 64, 74, 82, 93, 106` ```ts CancelCommandRequest, CreateContextRequest, DestroyContextRequest, @@ -356,24 +298,24 @@ convention is widely accepted across REST SDKs. --- -### Finding 20 — Medium — Cat 13 (Verb-tense inconsistency) +### Finding 17 — Medium — Cat 13 (Verb-tense inconsistency) **Location:** `src/v2/model.ts:23-28` -```ts -COMMAND_CANCELLED // past participle -COMMAND_CANCELLING // present participle (transitional) -COMMAND_ERROR // noun -COMMAND_FINISHED // past participle -COMMAND_QUEUED // past participle -COMMAND_RUNNING // present participle -``` -`ERROR` is a noun; everything else is a verbal form. `ERROR` should be -`FAILED` (past participle) to match the pattern. -**Proposed:** `Failed` in place of `Error`. (Same applies to -`CONTEXT_ERROR` in Finding 2 / #2.) +The `CommandStatus` members mix forms: +- `CANCELLED` — past participle +- `CANCELLING` — present participle (transitional) +- `ERROR` — noun +- `FINISHED` — past participle +- `QUEUED` — past participle +- `RUNNING` — present participle + +`ERROR` is a noun; everything else is a verbal form. The odd-one-out +should be `FAILED` (past participle) to match the pattern. +**Proposed:** rename the `ERROR` member to `FAILED`. (Same applies to +`CONTEXT_ERROR` in `ContextStatus`.) --- -### Finding 21 — Medium — Cat 3 (Acronym casing) +### Finding 18 — Medium — Cat 3 (Acronym casing) **Location:** `src/v2/model.ts:133` ```ts isJsonSchema?: boolean | undefined; @@ -386,14 +328,14 @@ recorded in `.agent/rules/typescript.mdc`. --- -### Finding 22 — Medium — Cat 12 (Duplicate concepts) +### Finding 19 — Medium — Cat 12 (Duplicate concepts) **Location:** `src/v2/client.ts:286-309` **Issue:** `execute()` returns `Promise`. The conflation -of "create a context" and "execute returns an id" is artificial. See #5. +of "create a context" and "execute returns an id" is artificial. See #2. --- -### Finding 23 — Medium — Cat 14 (Go/Java-style names) +### Finding 20 — Medium — Cat 14 (Go/Java-style names) **Location:** `src/v2/model.ts:74` + `client.ts:256` **Issue:** `destroy` is unusual for a REST SDK. JS conventions favour `delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend @@ -404,15 +346,15 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 24 — Medium — Cat 8 (Redundant suffix) — call-out +### Finding 21 — Medium — Cat 8 (Redundant suffix) — call-out **Location:** `src/v2/client.ts:333, 417, 498` **Issue:** Three classes named `*Waiter`. Acceptable if waiter is a recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #25-#27. +issue is what they wait *for*: see #22-#24. --- -### Finding 25 — Medium — Cat 6 (Misleading name) +### Finding 22 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:417` ```ts export class CreateWaiter { ... } @@ -427,21 +369,21 @@ target endpoint). --- -### Finding 26 — Medium — Cat 6 (Misleading name) +### Finding 23 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:333` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 27 — Medium — Cat 6 (Misleading name) +### Finding 24 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:498` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. --- -### Finding 28 — Medium — Cat 17 (Inconsistent action verbs) — call-out +### Finding 25 — Medium — Cat 17 (Inconsistent action verbs) — call-out **Location:** `src/v2/client.ts:86, 256` **Issue:** This package uses three lifecycle verbs: - `cancel()` on a command, @@ -454,7 +396,7 @@ Go-SDK alignment decision. --- -### Finding 29 — Low — Cat 1 (Vague/generic) +### Finding 26 — Low — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:117-118` ```ts /** The cause of the error */ @@ -468,18 +410,18 @@ sub-object; or keep flat and document conditional presence. --- -### Finding 30 — Low — Cat 1 (Vague/generic) +### Finding 27 — Low — Cat 1 (Vague/generic) **Location:** `src/v2/model.ts:139-140` ```ts /** The summary of the error */ summary?: string | undefined; ``` -Same as #29. The field is generic; the JSDoc reveals it's +Same as #26. The field is generic; the JSDoc reveals it's error-specific. --- -### Finding 31 — Low — Cat 1 (Underspecified) +### Finding 28 — Low — Cat 1 (Underspecified) **Location:** `src/v2/model.ts:141-142` ```ts /** true if partial results are returned. */ @@ -490,7 +432,7 @@ Acceptable but ambiguous: truncated *what*? table rows? text length? --- -### Finding 32 — Low — Cat 1 (Vague/generic) — call-out +### Finding 29 — Low — Cat 1 (Vague/generic) — call-out **Location:** `src/v2/client.ts:54` ```ts class StillRunningError extends Error {} @@ -499,7 +441,7 @@ Private, OK. Idiomatic for waiter polling patterns. --- -### Finding 33 — Low — Cat 3 (Acronym casing) — non-issue +### Finding 30 — Low — Cat 3 (Acronym casing) — non-issue **Location:** `src/v2/client.ts:49-52` ```ts const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; @@ -510,33 +452,33 @@ correctly cased per the project rules. --- -### Finding 34 — Low — Cat 10 (Reserved-word collision) — borderline +### Finding 31 — Low — Cat 10 (Reserved-word collision) — borderline **Location:** `src/v2/model.ts:138` **Issue:** `schema` is not a TS reserved word but is heavily aliased -across libraries (zod, JSON schema, table schema, GraphQL schema). See #15. +across libraries (zod, JSON schema, table schema, GraphQL schema). See #12. --- -### Finding 35 — Low — Cat 14 — non-issue +### Finding 32 — Low — Cat 14 — non-issue **Location:** `src/v2/client.ts:54` **Issue:** `StillRunningError` is named in idiomatic TS style (`*Error` suffix on classes extending Error). --- -### Finding 36 — Low — duplicate of #9 +### Finding 33 — Low — duplicate of #6 **Location:** `src/v2/model.ts:89` -Same finding as #9. +Same finding as #6. --- -### Finding 37 — Low — Cat 15 (Generic field) — call-out +### Finding 34 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. --- -### Finding 38 — Low — Cat 3 (Acronym casing in enum string values) +### Finding 35 — Low — Cat 3 (Acronym casing in enum string values) **Location:** `src/v2/model.ts:42-43` ```ts SQL = 'SQL', @@ -544,15 +486,15 @@ R = 'R', ``` Identifier `SQL` is all-caps (3 letters → standard "≤3 letter acronym all caps") in the language enum. `R` is single-letter — naturally all -caps. Apply the casing rule (#4) and these become `Sql` (if the rule is +caps. Apply the casing rule (#1) and these become `Sql` (if the rule is "acronyms PascalCase") or remain `SQL`/`R` (if "≤3 letters all caps"). **Proposed:** consult `typescript.mdc`; pick a rule and apply globally. --- -### Finding 39 — Low — duplicate of #13 +### Finding 36 — Low — duplicate of #10 **Location:** `src/v2/model.ts:131` -`fileNames?: string[]` for images — same as #13. +`fileNames?: string[]` for images — same as #10. --- @@ -560,18 +502,18 @@ caps. Apply the casing rule (#4) and these become `Sql` (if the rule is 1. **Three-resource ambiguity** — `Cluster`, `Context`, `Command` are easy to confuse, but the public types use the generic field `id` and reuse - `CreateResponse` for two unrelated operations. Findings #5, #6, #9, - #10, #11, #13, #16, #18, #25-#27 all stem from one decision: **never + `CreateResponse` for two unrelated operations. Findings #2, #3, #6, + #7, #8, #10, #13, #15, #22-#24 all stem from one decision: **never say "id" when "commandId" or "contextId" would do, and never reuse a response shape across resources**. Splitting `CreateResponse` into `CreateContextResponse` and `ExecuteCommandResponse` cascades to fix four other findings. -2. **Enum-value style** — SHOUTY_SNAKE_CASE enum identifiers with - redundant resource prefixes (`COMMAND_*`, `CONTEXT_*`, `*_RESULT`) - produce verbose callsites like `CommandStatus.COMMAND_CANCELLED`. - PascalCase identifiers with the wire string preserved as the value - restore idiomatic TS while keeping serialisation intact. +2. **Enum identifier casing** — SHOUTY_SNAKE_CASE enum identifiers + (`COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`) violate the + TypeScript convention that reserves `SCREAMING_SNAKE_CASE` for + constants. PascalCase identifiers with the wire string preserved as + the value restore idiomatic TS while keeping serialisation intact. 3. **Verb inconsistency** — `cancel` (command), `destroy` (context), `commandStatus` (no verb), `contextStatus` (no verb), `execute` (vs @@ -583,3 +525,9 @@ caps. Apply the casing rule (#4) and these become `Sql` (if the rule is genericised against the resource axis. Renaming with the resource (`CancelCommandWaiter`, `CreateContextWaiter`, `ExecuteCommandWaiter`) removes a recurring source of confusion. + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 2286eb3a..315a5669 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -3,209 +3,179 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 35 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | -| High | 10 | +| High | 6 | | Medium | 15 | | Low | 6 | -| Observation | 4 | +| Observation | 2 | ## High severity -### 1. `ConnectionType.UNKNOWN_CONNECTION_TYPE` — `src/v1/model.ts:7` -- **Why weird:** Enum sentinel re-states the enum name (`ConnectionType.UNKNOWN_CONNECTION_TYPE`). Idiomatic TypeScript treats "unset" as `undefined` (the field is already `connectionType?: ConnectionType | undefined`), making an explicit `UNKNOWN_*` value redundant. -- **Category:** 2 (redundant enum prefix). -- **Suggested name:** Drop the sentinel and rely on the optional field, or rename to `ConnectionType.Unknown`. -- **Rationale:** TS enum members are namespaced by the enum itself, so the re-stated prefix is pure noise. - -### 2. `CredentialType.UNKNOWN_CREDENTIAL_TYPE` — `src/v1/model.ts:88` -- **Why weird:** Same problem as #1 — sentinel re-states enum name. -- **Category:** 2. -- **Suggested name:** `CredentialType.Unknown` or drop entirely. -- **Rationale:** Identical to #1. - -### 3. `ConnectionType` value casing — `BIGQUERY`, `POSTGRESQL`, `MYSQL`, `SQLSERVER`, `SQLDW`, `WORKDAY_RAAS`, `GA4_RAW_DATA`, `MONDAY_COM` — `src/v1/model.ts:6-84` -- **Why weird:** Wire constants are flat SCREAMING_SNAKE but the domain has well-known camelCased product names (BigQuery, PostgreSQL, MySQL, SQL Server, Workday RaaS, GA4, Monday.com). Wire `BIGQUERY` is fine; TS-facing string literals lose the canonical brand casing. Some vendors collapse `POSTGRESQL` (one word, no underscore) but split `SAP_SUCCESSFACTORS`, `MICROSOFT_ENTRA_ID` — no consistent rule for which compound vendor names get an underscore. -- **Category:** 3 (acronym casing inconsistency across vendor names), 18 (long enum values littering the package surface). +### 1. `ConnectionType` value casing — `BIGQUERY`, `POSTGRESQL`, `MYSQL`, `SQLSERVER`, `SQLDW`, `WORKDAY_RAAS`, `GA4_RAW_DATA` — `src/v1/model.ts:6-34` +- **Why weird:** Wire constants are flat SCREAMING_SNAKE but the domain has well-known camelCased product names (BigQuery, PostgreSQL, MySQL, SQL Server, Workday RaaS, GA4). Wire `BIGQUERY` is fine; TS-facing string literals lose the canonical brand casing. Some vendors collapse `POSTGRESQL` (one word, no underscore) but split `META_MARKETING`, `POWER_BI` — no consistent rule for which compound vendor names get an underscore. +- **Category:** 3 (acronym casing inconsistency across vendor names). - **Suggested name:** Either keep wire SCREAMING_SNAKE (current) and document, or move to a `Vendor` enum with PascalCase members (`Vendor.BigQuery`, `Vendor.Postgres`, `Vendor.MySql`). - **Rationale:** Vendor names are proper nouns. Generator emits the proto enum verbatim; TS consumers will see `ConnectionType.POSTGRESQL` rather than the canonical `PostgreSQL`. Worth raising with API-design before the surface grows further. -### 4. `ConnectionType.SQLDW` and `SQLSERVER` (no underscore) vs `SAP_SUCCESSFACTORS`, `WORKDAY_RAAS`, `META_MARKETING` — `src/v1/model.ts:12-13,29,69` -- **Why weird:** Compound product names — sometimes joined (`SQLDW` = "SQL Data Warehouse", `SQLSERVER` = "SQL Server"), sometimes split with underscore (`SAP_SUCCESSFACTORS`, `WORKDAY_RAAS`). No rule. Comparable to `POWER_BI` (underscore) vs `BIGQUERY` (joined). -- **Category:** 3 (casing inconsistency), 18 (long enum value set). -- **Suggested name:** Pick one convention. If splitting on word boundaries: `SQL_DW`, `SQL_SERVER`, `BIG_QUERY`, `POWER_BI`. If joining: `SAPSUCCESSFACTORS`, `WORKDAYRAAS`. Most ergonomic is to consolidate on word-split + underscores. +### 2. `ConnectionType.SQLDW` and `SQLSERVER` (no underscore) vs `WORKDAY_RAAS`, `META_MARKETING` — `src/v1/model.ts:12-13,17,28` +- **Why weird:** Compound product names — sometimes joined (`SQLDW` = "SQL Data Warehouse", `SQLSERVER` = "SQL Server"), sometimes split with underscore (`WORKDAY_RAAS`). No rule. Comparable to `POWER_BI` (underscore) vs `BIGQUERY` (joined). +- **Category:** 3 (casing inconsistency). +- **Suggested name:** Pick one convention. If splitting on word boundaries: `SQL_DW`, `SQL_SERVER`, `BIG_QUERY`, `POWER_BI`. If joining: `WORKDAYRAAS`. Most ergonomic is to consolidate on word-split + underscores. - **Rationale:** Internal inconsistency makes the type non-discoverable — a user typing `ConnectionType.SQL_` will autocomplete to nothing if the value is `SQLSERVER`. Probably wire-locked, but worth flagging upstream. -### 5. `MONDAY_COM` — `src/v1/model.ts:56` -- **Why weird:** Encodes the TLD (`.com`) into the enum value. The vendor is "Monday.com" (the brand) but the SDK value becomes `MONDAY_COM` which reads as Monday and com. Other vendors don't include TLDs (no `HUBSPOT_COM`, `SLACK_COM`). -- **Category:** 3 (casing/branding), 6 (misleading: TLD baked into identifier). -- **Suggested name:** `MONDAY` (and document the canonical brand as "Monday.com" in a doc-comment). -- **Rationale:** Brand-as-domain doesn't belong in an enum value. If the API ever adds a non-com Monday product, this name decays. - -### 6. `EnvironmentSettings` — `src/v1/model.ts:278-281` -- **Why weird:** Top-level type whose name is so generic it conveys nothing. `Environment` is heavily overloaded (deployment environment, OS environment, shell environment, JS runtime environment). The type actually holds `javaDependencies: string[]` and `environmentVersion: string` — i.e. Java runtime / library bundle for the connection's compute environment. -- **Category:** 1 (vague), 15 (generic field name losing meaning). -- **Suggested name:** `ConnectionRuntimeSettings` or `JavaEnvironmentSettings`. -- **Rationale:** Reader of `EnvironmentSettings` cannot guess it means "Java deps and runtime version". Naming should communicate the contents. - -### 7. `EnvironmentSettings.environmentVersion` — `src/v1/model.ts:280` -- **Why weird:** Type-suffix tautology — field `environmentVersion` on a type called `EnvironmentSettings`. Reads `environmentSettings.environmentVersion` from a caller. Also doubly redundant. -- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). -- **Suggested name:** `version` (would read `environmentSettings.version`). -- **Rationale:** Wire stays `environment_version`; TS can drop the prefix since the containing type already says "environment". - -### 8. `DeleteConnection.nameArg` / `GetConnection.nameArg` / `UpdateConnection.nameArg` — `src/v1/model.ts:272,285,322` -- **Why weird:** Field named `nameArg` rather than `name`. The `Arg` suffix is a generator artefact (denoting path-arg / required-arg in the proto), but it leaks into the TS surface — users see `req.nameArg` everywhere. `ConnectionInfo` and `CreateConnection` already have a `name` field, so the inconsistency is jarring. +### 3. `DeleteConnectionRequest.nameArg` / `GetConnectionRequest.nameArg` / `UpdateConnectionRequest.nameArg` — `src/v1/model.ts:189,197,232` +- **Why weird:** Field named `nameArg` rather than `name`. The `Arg` suffix is a generator artefact (denoting path-arg / required-arg in the proto), but it leaks into the TS surface — users see `req.nameArg` everywhere. `ConnectionInfo` and `CreateConnectionRequest` already have a `name` field, so the inconsistency is jarring. - **Category:** 5 (`Arg` is a cryptic abbreviation), 17 (inconsistency: `name` vs `nameArg` for the same thing). - **Suggested name:** `name` everywhere. (Wire stays `name_arg` if the API truly requires that path param convention.) - **Rationale:** Three different request types have a `nameArg` field that semantically equals the connection name. Users will mistype `name` and get a runtime error. -### 9. `DeleteConnection` / `GetConnection` / `CreateConnection` / `UpdateConnection` / `ListConnections` types — `src/v1/model.ts:203,270,283,288,320` -- **Why weird:** Request DTOs named as verb phrases (`DeleteConnection`, `GetConnection`). Reads as actions, not data. `import type {DeleteConnection}` looks like importing a function. Pattern is uniform across all five request types. -- **Category:** 6 (misleading: name implies behaviour). -- **Suggested name:** `DeleteConnectionRequest`, `GetConnectionRequest`, etc. -- **Rationale:** TS conventions append `Request` to request DTOs. Especially confusing because the package also exports a `Client.deleteConnection(req: DeleteConnection)` — type and method names are identical in lowercase. - -### 10. `ConnectionInfo` — `src/v1/model.ts:141` +### 4. `ConnectionInfo` — `src/v1/model.ts:89` - **Why weird:** `Info` is the central domain entity — every type holds info about something. The Go SDK uses `XxxInfo` widely as a Go-style noun, but in TS the type would simply be `Connection`. `typescript.mdc` lists `Info` as a vague suffix. - **Category:** 1 (vague suffix), 8 (redundant type suffix). - **Suggested name:** `Connection`. - **Rationale:** The domain noun is "connection". Stripping `Info` improves every reference (`connection.connectionType` → `Connection.connectionType`). +### 5. `UpdateConnectionRequest.name` field — `src/v1/model.ts:236` +- **Why weird:** `UpdateConnectionRequest` has THREE name-like fields: `nameArg` (path param, identifies which), `newName` (new name), AND `name` (also documented as "Name of the connection"). Both `nameArg` and `name` are documented identically and both refer to the existing connection. Easily mis-set; ambiguous which the server uses. +- **Category:** 12 (duplicate concept), 6 (misleading — three fields mean "the name"). +- **Suggested name:** Remove `name` from `UpdateConnectionRequest` (it duplicates `nameArg`). +- **Rationale:** Three fields for one concept is a bug surface. Worth pushing to API design. + +### 6. `DeleteConnectionRequest_Response` / `ListConnectionsRequest_Response` — `src/v1/model.ts:193,214` +- **Why weird:** Proto-architectural-leak naming. The `_Response` infix on an underscore-joined identifier is a verbatim proto nested-message name (`DeleteConnectionRequest.Response`), exported into the public TS surface. `DeleteConnectionRequest_Response` is even empty (`{}`). The TS-idiomatic shape is `DeleteConnectionResponse` / `ListConnectionsResponse` (or `void` for the empty case), not a nested type tied to its sibling request. +- **Category:** Proto-architectural leak (`_Response` underscore-joined nested message name), 12 (empty type duplicates `void`). +- **Suggested name:** `DeleteConnectionResponse` / `ListConnectionsResponse` (or drop the empty one entirely; method returns `void`). +- **Rationale:** The underscore-joined `Foo_Response` pattern is a generator artefact from proto's nested-message resolution. Users see `unmarshalDeleteConnectionRequest_ResponseSchema` and `DeleteConnectionRequest_Response` in autocomplete — both leak the proto namespacing into the SDK surface. + ## Medium severity -### 11. `ConnectionInfo.connectionType: ConnectionType` — `src/v1/model.ts:145` +### 7. `ConnectionInfo.connectionType: ConnectionType` — `src/v1/model.ts:93` - **Why weird:** Type-suffix tautology — field `connectionType` of type `ConnectionType` on a type called `ConnectionInfo`. Reads `connectionInfo.connectionType`. - **Category:** 20. - **Suggested name:** `type: ConnectionType`. (If `ConnectionInfo` is renamed to `Connection`, becomes `connection.type`.) - **Rationale:** Wire stays `connection_type`; TS can drop the prefix. -### 12. `ConnectionInfo.credentialType: CredentialType` — `src/v1/model.ts:159` -- **Why weird:** Same tautology as #11. +### 8. `ConnectionInfo.credentialType: CredentialType` — `src/v1/model.ts:105` +- **Why weird:** Same tautology as #7. - **Category:** 20. - **Suggested name:** `credential: CredentialType` or simply keep as-is since `credential` would also be ambiguous. -- **Rationale:** Less clear than #11; the prefix carries some semantic load (distinguishes credential type from credential value). +- **Rationale:** Less clear than #7; the prefix carries some semantic load (distinguishes credential type from credential value). -### 13. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:172` +### 9. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:118` - **Why weird:** Type-suffix tautology. Also: the value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. - **Category:** 20 (tautology), 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). - **Suggested name:** Either drop the field (it's always `CONNECTION`), or rename to `securableKind: SecurableType` and document why a non-`CONNECTION` value would ever appear. - **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. -### 14. `ConnectionInfo.provisioningInfo: ProvisioningInfo` — `src/v1/model.ts:173` +### 10. `ConnectionInfo.provisioningInfo: ProvisioningInfo` — `src/v1/model.ts:119` - **Why weird:** Type-suffix tautology. - **Category:** 20. - **Suggested name:** `provisioning: ProvisioningInfo`. - **Rationale:** Wire stays `provisioning_info`; TS can drop the prefix since the containing type already names the concept. -### 15. `ConnectionInfo.connectionId` and `metastoreId` — `src/v1/model.ts:161-163` +### 11. `ConnectionInfo.connectionId` and `metastoreId` — `src/v1/model.ts:107-109` - **Why weird:** Bare `id` doesn't appear, but two `xxxId` fields coexist. `connectionId` is the type-prefix tautology (same struct already says "Connection"); `metastoreId` clarifies which parent. Mixed levels of specificity. - **Category:** 19 (underspecified id — `connectionId` is fine, but inconsistent with absence of just `id` somewhere). - **Suggested name:** `id` for the connection's own identifier (it's `connection.id`, not `connection.connectionId`); keep `metastoreId` (it identifies a parent). - **Rationale:** Self-id should be `id`; foreign-key ids should keep the prefix. This is the standard REST convention. -### 16. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:142-155` +### 12. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:91,101` - **Why weird:** Two name-like fields (`name` and `fullName`) with no inline doc explaining the difference. The wire pattern in Unity Catalog is "name within a parent" vs "catalog.schema.connection_name", but the type doesn't say that. - **Category:** 1 (vague — what makes a name "full"?), 17 (inconsistency: `name` is short, `fullName` is fully qualified but doc only says "Full name of connection"). - **Suggested name:** Keep names; improve doc to clarify `fullName` is the dot-qualified path (`catalog.schema.connection_name`). - **Rationale:** Naming is fine; documentation is the gap. Flagging because the readability of every field that pairs with `name` depends on knowing that `fullName` is the path-style form. -### 17. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:149` +### 13. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:97` - **Why weird:** Boolean field name doesn't begin with `is`/`has` as is common for TS booleans. Reads `connection.readOnly` (acceptable adjective form) but sibling enums and types use noun forms. JS naming conventions are split, but inside this SDK most booleans use the adjective form, so this is consistent — flagging at low-medium severity because the rule itself is debatable. - **Category:** 1 (vague form — `readOnly` could be a string of mode flags). - **Suggested name:** Keep as `readOnly` (matches Go SDK and is widely used in JS). Optionally `isReadOnly`. - **Rationale:** No strong convention either way; flagging because audit asked for booleans whose nature isn't obvious from the name. -### 18. `CreateConnection` / `UpdateConnection` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:203,320` -- **Why weird:** `CreateConnection` is `ConnectionInfo + parent`. `UpdateConnection` is `ConnectionInfo + nameArg + newName`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnection` and `UpdateConnection` even though they're server-only). +### 14. `CreateConnectionRequest` / `UpdateConnectionRequest` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:138,230` +- **Why weird:** `CreateConnectionRequest` is `ConnectionInfo` shape. `UpdateConnectionRequest` is `ConnectionInfo + nameArg + newName + name`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnectionRequest` and `UpdateConnectionRequest` even though they're server-only). - **Category:** 12 (duplicate concepts), 6 (misleading — user-settable vs server-set is invisible). - **Suggested name:** Split server-only metadata into a base type and compose. Better still, type create/update inputs as `Pick` or a dedicated `ConnectionInput` interface. - **Rationale:** Today a caller could set `connection.createdAt` on a create request and have no idea it's silently ignored. Type system can prevent this. -### 19. `UpdateConnection.newName` and `nameArg` — `src/v1/model.ts:322-324` +### 15. `UpdateConnectionRequest.newName` and `nameArg` — `src/v1/model.ts:232-234` - **Why weird:** `newName` (TS), wire `new_name`. Pair (`nameArg`, `newName`) means "rename connection X to Y". Function-style verb encoded in a field name (`new` + Name). - **Category:** 5 (`newName` reads as a temporal modifier), 17 (also inconsistent with the type's own `name` field). - **Suggested name:** `renameTo`, or split into a `RenameConnectionRequest` operation. - **Rationale:** Cleaner API: rename and update are distinct operations. -### 20. `UpdateConnection.name` field — `src/v1/model.ts:326` -- **Why weird:** `UpdateConnection` has THREE name-like fields: `nameArg` (path param, identifies which), `newName` (new name), AND `name` (also documented as "Name of the connection"). Both `nameArg` and `name` are documented identically and both refer to the existing connection. Easily mis-set; ambiguous which the server uses. -- **Category:** 12 (duplicate concept), 6 (misleading — three fields mean "the name"). -- **Suggested name:** Remove `name` from `UpdateConnection` (it duplicates `nameArg`). -- **Rationale:** Three fields for one concept is a bug surface. Worth pushing to API design. - -### 21. `parent` field on `CreateConnection` and `ListConnections` — `src/v1/model.ts:208,300` -- **Why weird:** Bare `parent` with the value encoded as a free-form string `"schemas/{catalog}.{schema}"`. Untyped wire format inside a field name that does not indicate a structured path. -- **Category:** 1 (vague), 5 (cryptic — what shape is `parent`?). -- **Suggested name:** `parentSchema`, with a clear doc that the format is `"schemas/{catalog}.{schema}"` (or model the catalog/schema pair as a structured type). -- **Rationale:** Pattern of "rest-resource string with embedded slashes" is common in Google APIs but feels out of place in a TS SDK. At minimum the field should signal it's a schema reference. - -### 22. `ListConnections.maxResults` semantics — `src/v1/model.ts:289-296` +### 16. `ListConnectionsRequest.maxResults` semantics — `src/v1/model.ts:201-208` - **Why weird:** Three different behaviours encoded in the same field: "not set → all results", "0 → server default", ">0 → bound by min(value, server-default)", "<0 → error". Numeric overload that is invisible from the name. - **Category:** 6 (misleading — `maxResults` implies upper bound, but `0` actually requests server default). - **Suggested name:** Either two separate fields (`pageSize` and `useServerDefault`), or document inline tersely. Keep name; flag as observation. - **Rationale:** Name is fine; behaviour overloaded. Easy to call wrong. -### 23. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:127` +### 17. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:75` - **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. -- **Category:** 18 (questionable enum value). +- **Category:** 6 (misleading — value advertised but not actually a securable yet). - **Suggested name:** Hide until promotion or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. -### 24. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:102` +### 18. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:52` - **Why weird:** `SSWS` is cryptic. (Stands for "Single Sign-On Web Services" or Okta SSWS — Secure Single Sign-on. Either way, opaque.) Other tokens are named after their family (OAuth, OIDC, Bearer); SSWS is the only one with a literal product-specific acronym. - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling values). - **Suggested name:** `OKTA_SSWS_TOKEN` (if it's strictly Okta), or document in doc-comment. - **Rationale:** Future readers cannot guess what SSWS expands to. -### 25. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:103` -- **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while other vendor-coupled values put the vendor first (`OAUTH_GOOGLE_SERVICE_ACCOUNT`). Inconsistent word order. +### 19. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:53` +- **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while sibling values put the vendor first. Inconsistent word order. - **Category:** 17 (inconsistency). - **Suggested name:** `AKAMAI_EDGEGRID`. -- **Rationale:** Consistency with the `OAUTH_GOOGLE_*` pattern (vendor-first). +- **Rationale:** Consistency with vendor-first patterns elsewhere. -### 26. `CredentialType.OAUTH_DCR` — `src/v1/model.ts:105` -- **Why weird:** `DCR` is opaque (probably "Dynamic Client Registration", an OAuth concept). No doc. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `OAUTH_DYNAMIC_CLIENT_REGISTRATION` or document in a doc-comment. -- **Rationale:** Users unfamiliar with OAuth specs cannot decode `DCR`. +### 20. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,272,278` +- **Why weird:** Proto-architectural-leak naming. Proto-style nested entry types with underscore-joined identifiers leak into the public TS surface. Each `Options` and `Properties` map gets a corresponding `*_OptionsEntry`/`*_PropertiesEntry` interface — six total — that is exported but trivial (`{key?, value?}`). The wire shape is already covered by `Record`. +- **Category:** Proto-architectural leak (`_OptionsEntry` / `_PropertiesEntry` proto map-entry message names), 12 (duplicate concept), 5 (cryptic — underscore-joined identifiers). +- **Suggested name:** Remove the `*Entry` interfaces from the public API; rely on `Record`. +- **Rationale:** These entry types add visual noise and are not used by the surface (the field is `Record`). + +### 21. `ProvisioningInfo_State` — `src/v1/model.ts:79` +- **Why weird:** Proto-architectural-leak naming. Underscore-joined identifier (`ProvisioningInfo_State`) is a proto nested-enum name (`ProvisioningInfo.State`) emitted verbatim into TS. The enum is suppressed via `eslint-disable @typescript-eslint/naming-convention`, confirming it breaks TS conventions. Standalone TS would name this `ProvisioningState` (or merge into `ProvisioningInfo`). +- **Category:** Proto-architectural leak (`_State` underscore-joined nested enum name). +- **Suggested name:** `ProvisioningState`. +- **Rationale:** Proto nesting has no analogue in TS modules; the underscore is a wire-name artefact. Same generator pattern produces `*_Response`, `*_OptionsEntry`, `*_PropertiesEntry`. ## Low severity -### 27. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` +### 22. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. -### 28. `flattenQueryParams` — `src/v1/utils.ts:123` +### 23. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if generator default. - **Rationale:** Generator emits the same helper into every package even when unused. -### 29. `readAll` — `src/v1/utils.ts:40` +### 24. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Trivial; flagged for cross-package consistency. -### 30. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should encode the layer, not just the protocol. -### 31. `HttpCallOptions` — `src/v1/utils.ts:15` +### 26. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 32. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:164-165` +### 27. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:167-168` - **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. - **Category:** Observation only. - **Suggested name:** None — this is the marshalling boundary by design. @@ -213,32 +183,23 @@ ## Observations -### 33. ~50 vendor names baked into `ConnectionType` enum -The enum lists ~70 vendors (`MYSQL` ... `MARKETO`), all SCREAMING_SNAKE. This makes `model.ts` 84 lines of enum just for connection types. Worth raising with API design whether the type should be `string` with vendor metadata living in a separate registry — adding a new connection type today requires releasing a new SDK version. -- **Category:** 18 (long enum value set). - -### 34. Casing inconsistency in vendor name decomposition +### 28. Casing inconsistency in vendor name decomposition Within `ConnectionType`: - `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). -- `MYSQL` (joined) vs `MICROSOFT_ENTRA_ID` (split). -- `MONDAY_COM` (encodes TLD) vs every other brand (no TLD). +- `MYSQL` (joined) vs `GA4_RAW_DATA` (split). No discoverable rule. Wire-locked, but worth surfacing. - **Category:** 3 (acronym/casing inconsistency). -### 35. Action-verb conventions on `Client` -`createConnection`, `getConnection`, `listConnections`, `updateConnection`, `deleteConnection` — uniform. (Listed as observation since the audit asks us to flag inconsistencies; here we explicitly note consistency.) - -### 36. `Client` constructor throws for missing host +### 29. `Client` constructor throws for missing host `if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. - **Category:** Observation. ## Domain glossary -- `uc` — Unity Catalog (referenced in `model.ts:178` doc comment "UC Secret"). +- `uc` — Unity Catalog (referenced in `model.ts` doc comments). - `raas` — Reporting as a Service (e.g. `WORKDAY_RAAS`). Doc-less. - `ga4` — Google Analytics 4 (in `GA4_RAW_DATA`). - `m2m`/`u2m` — Machine-to-machine / User-to-machine OAuth flows (in `CredentialType`). - `mtls` — Mutual TLS (in `OAUTH_MTLS`). -- `dcr` — Dynamic Client Registration (in `OAUTH_DCR`). Undocumented. - `pem` — Privacy-Enhanced Mail format (in `PEM_PRIVATE_KEY`). - `ssws` — Secure Single Sign-on Web Services (Okta) (in `SSWS_TOKEN`). Undocumented. - `oidc` — OpenID Connect (in `OIDC_TOKEN`). @@ -246,7 +207,15 @@ No discoverable rule. Wire-locked, but worth surfacing. - `iam` — not encountered. ## File coverage -- `src/v1/model.ts` (590 lines): read fully. -- `src/v1/client.ts` (237 lines): read fully. +- `src/v1/model.ts` (446 lines): read fully. +- `src/v1/client.ts` (240 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (33 lines): read fully. +- `src/v1/index.ts` (29 lines): read fully. + +## Fixed +- #5 `ConnectionType.MONDAY_COM` (originally cited at `src/v1/model.ts:56`): Fixed in regeneration on 2026-05-20 — vendor value removed from `ConnectionType` enum. +- #6 `EnvironmentSettings` (originally cited at `src/v1/model.ts:278-281`): Fixed in regeneration on 2026-05-20 — type no longer present in `model.ts`. +- #7 `EnvironmentSettings.environmentVersion` (originally cited at `src/v1/model.ts:280`): Fixed in regeneration on 2026-05-20 — removed along with parent type. +- #9 Request DTOs named as verb phrases — `DeleteConnection` / `GetConnection` / `CreateConnection` / `UpdateConnection` / `ListConnections` (originally cited at `src/v1/model.ts:203,270,283,288,320`): Fixed in regeneration on 2026-05-20 — all renamed to `*Request` suffix (`CreateConnectionRequest`, `DeleteConnectionRequest`, `GetConnectionRequest`, `ListConnectionsRequest`, `UpdateConnectionRequest`). +- #21 `parent` field on `CreateConnection` and `ListConnections` (originally cited at `src/v1/model.ts:208,300`): Fixed in regeneration on 2026-05-20 — `parent` field removed from both `CreateConnectionRequest` and `ListConnectionsRequest`. +- #26 `CredentialType.OAUTH_DCR` (originally cited at `src/v1/model.ts:105`): Fixed in regeneration on 2026-05-20 — value removed from `CredentialType` enum. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index 8661fe31..a64499d4 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -13,7 +13,7 @@ cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure Managed Identity, GCP Service Account Key, Databricks-managed GCP Service Account, Cloudflare API token) and yields one of six temporary-credential shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). -**Total weird names flagged:** 33 +**Total weird names flagged:** 35 --- @@ -22,45 +22,40 @@ shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| | 1 | package `credentials` / module `@databricks/sdk-credentials` | (package) | package | High | 1 Vague/generic, 12 Duplicate concepts | Cross-package naming collision with `@databricks/sdk-auth`'s hand-written `credentials/` sub-module. Importers will routinely ask "which `credentials` did I want?" — one is SDK authentication (PAT, U2M, M2M); this is Unity Catalog cloud-storage credentials. | -| 2 | `CredentialInfo` vs `CreateCredential` vs `UpdateCredential` vs `StorageCredentialInfo` | model.ts:301, 148, 780, 676 | interface set | High | 12 Duplicate concepts | Four near-identical record shapes (~20 fields each) differ only in two flag fields (`skipValidation`, `force`, `newName`, `nameArg`). The "Info" suffix vs no suffix is meaningless. Real shape is one resource + a small action delta. | -| 3 | `CreateCredential` vs `CreateStorageCredential` | model.ts:148, 226 | interface pair | High | 12 Duplicate concepts | Field-for-field identical. The wire endpoints differ (`/credentials` vs `/storage-credentials`) but the request bodies are the same. One should be a re-export of the other or both should share a common base. | -| 4 | `UpdateCredential` vs `UpdateStorageCredential` | model.ts:780, 865 | interface pair | High | 12 Duplicate concepts | Same as #3 — body fields identical. | -| 5 | `CredentialInfo` vs `StorageCredentialInfo` | model.ts:301, 676 | interface pair | High | 12 Duplicate concepts | Same fields, same types, same optionality. The only thing distinguishing them is which list endpoint emits which. Generator-produced. | -| 6 | `DeleteCredential` vs `DeleteStorageCredential` | model.ts:387, 401 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg, force}`; identical shape. | -| 7 | `GetCredential` vs `GetStorageCredential` | model.ts:575, 585 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg}`. Same shape. | -| 8 | `ListCredentials` vs `ListStorageCredentials` | model.ts:598, 631 | interface pair | High | 12 Duplicate concepts | Both expose `{includeUnbound, maxResults, pageToken}`. Same shape, different doc string. | -| 9 | `ValidateCredential` vs `ValidateStorageCredential` | model.ts:950, 1008 | interface pair | High | 12 Duplicate concepts | The `credential` discriminator differs (`credentialName` vs `storageCredentialName`; storage variant adds `azureServicePrincipal` and `cloudflareApiToken`). Otherwise overlapping. | -| 10 | `Client` | client.ts:80 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `CredentialsClient` would self-identify. | -| 11 | `Client.createCredential` vs `Client.createStorageCredential` (plus delete/get/list/update/validate pairs) | client.ts:112, 142, 168, 199, 242, 277, 311, 348, 383, 411, 445, 509, 571, 602, 641, 680 | method set | High | 12 Duplicate concepts | The class exposes parallel `*Credential` and `*StorageCredential` operations (16 methods, 8 pairs). Per the in-tree TODO note (model.ts:581-583) the storage-credentials API is being deprecated, but both are surfaced equally — no `@deprecated` JSDoc, no log warning. | -| 12 | `nameArg` | model.ts:389, 403, 577, 587, 782, 867 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | `nameArg` appears in six request types as the path parameter for the credential being acted on. "Arg" is meaningless to a TS caller (it's a generator-introduced disambiguator that exists because some envelopes also have a `name` body field). TS-side it should be `credentialName` or `nameInPath`. | -| 13 | `UpdateCredential.nameArg` and `UpdateCredential.name` coexist | model.ts:782, 797 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredential.name`'s text. Caller will pick wrong. | -| 14 | `UpdateStorageCredential.nameArg` and `UpdateStorageCredential.name` coexist | model.ts:867, 881 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #13 for the storage variant. | -| 15 | `CredentialInfo` discriminator field `credential` | model.ts:308 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `CredentialInfo`; the field that holds the credential payload is also `credential`. `Credential.credential.awsIamRole` reads as a stutter. Should be `cloudCredential` or `provider`. | -| 16 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` etc. | model.ts:5-10 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | All four values stutter the enum name (`ISOLATION_MODE_OPEN`, `ISOLATION_MODE_ISOLATED`, ...). TS idiom would be `IsolationMode.Unspecified`/`.Open`/`.Isolated`. The generator emits SCREAMING_SNAKE for both the keys and the string values. | -| 17 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` | model.ts:6 | enum value | Medium | 6 Misleading names, 18 Long enum values | "Unspecified" is the proto-style placeholder for "missing value". In TS the natural way to express this is `undefined`, not a sentinel string. The field type already is `IsolationMode \| undefined`. | -| 18 | `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` | model.ts:9 | enum value | Low | 18 Long enum values, 6 Misleading names | 30-char enum value; "OpenInAccount" is the contraction. The domain meaning ("open within a single account scope") is not obvious from either form. | -| 19 | `PathOperation` enum values | model.ts:13-15 | enum values | Medium | 2 Redundant enum prefixes, 18 Long enum values | `PATH_READ`, `PATH_READ_WRITE`, `PATH_CREATE_TABLE` — `PATH_` prefix duplicates the enum name. The third value (`PATH_CREATE_TABLE`) is a different category from the first two ("Path"-as-resource vs "create a table at this path"); the prefix obscures that. | -| 20 | `TableOperation` vs `VolumeOperation` enums | model.ts:18, 23 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write) expressed two different ways. The volume one uses prefixed values (#16 pattern), the table one does not — inconsistent within the same file. | -| 21 | `VolumeOperation.READ_VOLUME`/`WRITE_VOLUME` | model.ts:24-25 | enum value | Medium | 2 Redundant enum prefixes, 18 Long enum values | `_VOLUME` suffix stutters the enum name. Should be `READ`/`WRITE` (consistent with `TableOperation`). | -| 22 | `unityCatalogIamArn` | model.ts:83 | field | Medium | 7 Overly verbose, 6 Misleading names | 18-char field name embedded in `AwsIamRole`. The JSDoc says "AWS IAM user managed by Databricks". Caller has no way to know that "unityCatalog" here means "the Databricks-managed identity that assumes the customer role". Either `databricksManagedIamArn` or rename to clarify role. | -| 23 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:76, 117, 99, 427, 378, 139 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | -| 24 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:95, 93, 459 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | -| 25 | `awsTempCredentials` discriminator case | model.ts:453 | field | Low | 5 Cryptic abbreviations | "Temp" abbreviation for "Temporary". Other discriminator cases use full words (`azureUserDelegationSas`, `gcpOauthToken`). Inconsistent. | -| 26 | `r2TempCredentials` discriminator case | model.ts:460 | field | Low | 5 Cryptic abbreviations | Same as #25. | -| 27 | `ucEncryptedToken` discriminator case | model.ts:461 | field | Medium | 5 Cryptic abbreviations | "Uc" is the Databricks-internal abbreviation for "Unity Catalog". Outside Databricks the abbreviation is opaque. Compare to `unityCatalogIamArn` (#22) which spells it out. Inconsistent within the same model file. | -| 28 | `UcEncryptedToken` type | model.ts:775 | interface | Medium | 5 Cryptic abbreviations, 1 Vague/generic | Same "Uc" abbreviation problem at the type name. Spell out or contextualize. | -| 29 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:419, 420 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | -| 30 | `R2Credentials` type | model.ts:667 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | -| 31 | `CloudflareApiToken.accountId` | model.ts:145 | field | Low | 19 Underspecified IDs | This `accountId` is a *Cloudflare* account ID, not a Databricks account ID. The field name doesn't say. Compare `unityCatalogIamArn` (#22) which is annotated. | -| 32 | `AwsCredentials.accessPoint` | model.ts:72 | field | Low | 5 Cryptic abbreviations, 1 Vague/generic | A string containing an S3 Access Point ARN. `accessPointArn` would type itself. | -| 33 | `usedForManagedStorage` flag | model.ts:216 | field | Low | 6 Misleading names | Boolean named in past tense ("usedFor") suggests a historical record. The doc says it is the *current* state. `isManagedStorageRoot` or `isRootForManagedStorage` reads as state. | -| 34 | `GenerateTemporaryPathCredential` / `GenerateTemporaryTableCredential` / `GenerateTemporaryVolumeCredential` / `GenerateTemporaryServiceCredential` | model.ts:436, 508, 542, 472 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 31-34 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | -| 35 | `TemporaryCredentials` | model.ts:749 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | -| 36 | `ValidateCredential.credential` outer field with `credential.$case === 'credentialName'` | model.ts:951, 953 | field | High | 12 Duplicate concepts, 15 Generic field names | The discriminated-union *case* is `credentialName: string`, sitting under a field called `credential`. So `req.credential.credentialName` is the read path — `credential.credential...` stuttering. | -| 37 | `ValidateStorageCredential.credential.$case === 'storageCredentialName'` | model.ts:1011 | field | High | 12 Duplicate concepts, 15 Generic field names | Same as #36 — `req.credential.storageCredentialName`. The naming repeats the parent type. | -| 38 | `expirationTime` (epoch milliseconds) | model.ts:467 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | -| 39 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:107-110 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredential`/`CredentialInfo`/`UpdateCredential`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | -| 40 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | +| 2 | `CredentialInfo` vs `CreateCredentialRequest` vs `UpdateCredentialRequest` vs `StorageCredentialInfo` | model.ts:463, 300, 1055, 870 | interface set | High | 12 Duplicate concepts | Four near-identical record shapes (~20 fields each) differ only in two flag fields (`skipValidation`, `force`, `newName`, `nameArg`). The "Info" suffix vs "Request" suffix is meaningless. Real shape is one resource + a small action delta. | +| 3 | `CreateCredentialRequest` vs `CreateStorageCredentialRequest` | model.ts:300, 388 | interface pair | High | 12 Duplicate concepts | Field-for-field identical. The wire endpoints differ (`/credentials` vs `/storage-credentials`) but the request bodies are the same. One should be a re-export of the other or both should share a common base. | +| 4 | `UpdateCredentialRequest` vs `UpdateStorageCredentialRequest` | model.ts:1055, 1140 | interface pair | High | 12 Duplicate concepts | Same as #3 — body fields identical. | +| 5 | `CredentialInfo` vs `StorageCredentialInfo` | model.ts:463, 870 | interface pair | High | 12 Duplicate concepts | Same fields, same types, same optionality. The only thing distinguishing them is which list endpoint emits which. Generator-produced. | +| 6 | `DeleteCredentialRequest` vs `DeleteStorageCredentialRequest` | model.ts:564, 584 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg, force}`; identical shape. | +| 7 | `GetCredentialRequest` vs `GetStorageCredentialRequest` | model.ts:755, 771 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg}`. Same shape. | +| 8 | `ListCredentialsRequest` vs `ListStorageCredentialsRequest` | model.ts:788, 825 | interface pair | High | 12 Duplicate concepts | Both expose `{includeUnbound, maxResults, pageToken}`. Same shape, different doc string. | +| 9 | `ValidateCredentialRequest` vs `ValidateStorageCredentialRequest` | model.ts:1225, 1283 | interface pair | High | 12 Duplicate concepts | The `credential` discriminator differs (`credentialName` vs `storageCredentialName`; storage variant adds `azureServicePrincipal` and `cloudflareApiToken`). Otherwise overlapping. | +| 10 | `Client` | client.ts:106 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `CredentialsClient` would self-identify. | +| 11 | `Client.createCredential` vs `Client.createStorageCredential` (plus delete/get/list/update/validate pairs) | client.ts:309, 339, 368, 402, 445, 480, 514, 551, 586, 614, 648, 715, 777, 808, 850, 889 | method set | High | 12 Duplicate concepts | The class exposes parallel `*Credential` and `*StorageCredential` operations (16 methods, 8 pairs). Per the in-tree TODO note (model.ts:766-770) the storage-credentials API is being deprecated, but both are surfaced equally — no `@deprecated` JSDoc, no log warning. | +| 12 | `nameArg` | model.ts:566, 586, 757, 773, 1057, 1142 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | `nameArg` appears in six request types as the path parameter for the credential being acted on. "Arg" is meaningless to a TS caller (it's a generator-introduced disambiguator that exists because some envelopes also have a `name` body field). TS-side it should be `credentialName` or `nameInPath`. | +| 13 | `UpdateCredentialRequest.nameArg` and `UpdateCredentialRequest.name` coexist | model.ts:1057, 1072 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredentialRequest.name`'s text. Caller will pick wrong. | +| 14 | `UpdateStorageCredentialRequest.nameArg` and `UpdateStorageCredentialRequest.name` coexist | model.ts:1142, 1156 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #13 for the storage variant. | +| 15 | `CredentialInfo` discriminator field `credential` | model.ts:470 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `CredentialInfo`; the field that holds the credential payload is also `credential`. `Credential.credential.awsIamRole` reads as a stutter. Should be `cloudCredential` or `provider`. | +| 16 | `TableOperation` vs `VolumeOperation` enums | model.ts:17, 22 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write a cloud-storage thing) expressed two different ways across sibling enums in the same file. | +| 17 | `unityCatalogIamArn` | model.ts:158 | field | Medium | 7 Overly verbose, 6 Misleading names | 18-char field name embedded in `AwsIamRole`. The JSDoc says "AWS IAM user managed by Databricks". Caller has no way to know that "unityCatalog" here means "the Databricks-managed identity that assumes the customer role". Either `databricksManagedIamArn` or rename to clarify role. | +| 18 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:151, 192, 174, 610, 555, 214 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | +| 19 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:170, 168, 642 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | +| 20 | `awsTempCredentials` discriminator case | model.ts:636 | field | Low | 5 Cryptic abbreviations | "Temp" abbreviation for "Temporary". Other discriminator cases use full words (`azureUserDelegationSas`, `gcpOauthToken`). Inconsistent. | +| 21 | `r2TempCredentials` discriminator case | model.ts:643 | field | Low | 5 Cryptic abbreviations | Same as #20. | +| 22 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:602, 603 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | +| 23 | `R2Credentials` type | model.ts:861 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | +| 24 | `CloudflareApiToken.accountId` | model.ts:220 | field | Low | 19 Underspecified IDs | This `accountId` is a *Cloudflare* account ID, not a Databricks account ID. The field name doesn't say. Compare `unityCatalogIamArn` (#17) which is annotated. | +| 25 | `TemporaryAwsCredentials.accessPoint` | model.ts:958 | field | Low | 5 Cryptic abbreviations, 1 Vague/generic | A string containing an S3 Access Point ARN. `accessPointArn` would type itself. | +| 26 | `usedForManagedStorage` flag | model.ts:286 | field | Low | 6 Misleading names | Boolean named in past tense ("usedFor") suggests a historical record. The doc says it is the *current* state. `isManagedStorageRoot` or `isRootForManagedStorage` reads as state. | +| 27 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:619, 690, 723, 654 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | +| 28 | `TemporaryCredentials` | model.ts:961 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | +| 29 | `ValidateCredentialRequest.credential` outer field with `credential.$case === 'credentialName'` | model.ts:1226, 1228 | field | High | 12 Duplicate concepts, 15 Generic field names | The discriminated-union *case* is `credentialName: string`, sitting under a field called `credential`. So `req.credential.credentialName` is the read path — `credential.credential...` stuttering. | +| 30 | `ValidateStorageCredentialRequest.credential.$case === 'storageCredentialName'` | model.ts:1286 | field | High | 12 Duplicate concepts, 15 Generic field names | Same as #29 — `req.credential.storageCredentialName`. The naming repeats the parent type. | +| 31 | `expirationTime` (epoch milliseconds) | model.ts:649 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | +| 32 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:264-266 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredentialRequest`/`CredentialInfo`/`UpdateCredentialRequest`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | +| 33 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | +| 34 | `ListCredentialsPublicRequest` | model.ts:776 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | +| 35 | `Client.createCredentialsPublic` / `Client.deleteCredentialsPublic` / `Client.getCredentialsPublic` / `Client.listCredentialsPublic` | client.ts:927, 953, 978, 1003 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `Client` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | --- @@ -93,44 +88,44 @@ tell which package they want. Both legitimately call their primary concept Eight method pairs and eight interface pairs are field-for-field identical between the "Credential" (new consolidated) surface and the "StorageCredential" (legacy) surface. See findings #2-#9. The in-tree TODO note -(model.ts:581-583) confirms the storage variant is being deprecated. But: +(model.ts:766-770) confirms the storage variant is being deprecated. But: -- No `@deprecated` JSDoc tag on any of the `*StorageCredential` types or +- No `@deprecated` JSDoc tag on any of the `*StorageCredential*` types or methods. - No log warning when a caller invokes them. - They are equally promoted in `index.ts`. -Recommendation: mark every `*StorageCredential` type and method `@deprecated`, +Recommendation: mark every `*StorageCredential*` type and method `@deprecated`, or hide them behind a `/legacy` sub-export, until they are removed. ### H3. Identical request envelopes (`Credential` and `StorageCredential` pairs) -`CreateCredential` and `CreateStorageCredential` (model.ts:148, 226) have -identical fields. Same for the Update, Delete, Get, List pairs (#3, #4, #6, #7, -#8). The discriminated unions on the `credential` field are subsets/supersets +`CreateCredentialRequest` and `CreateStorageCredentialRequest` (model.ts:300, 388) +have identical fields. Same for the Update, Delete, Get, List pairs (#3, #4, #6, +#7, #8). The discriminated unions on the `credential` field are subsets/supersets of each other: -- `CreateStorageCredential` accepts: awsIamRole, azureServicePrincipal, +- `CreateStorageCredentialRequest` accepts: awsIamRole, azureServicePrincipal, gcpServiceAccountKey, azureManagedIdentity, databricksGcpServiceAccount, cloudflareApiToken (6 cases). -- `CreateCredential` accepts: the same 6 cases. +- `CreateCredentialRequest` accepts: the same 6 cases. There is no behavioral difference. One should be a type alias. ### H4. Three-way name collision (`nameArg` + `name` + `newName`) -Six request types (`DeleteCredential`, `DeleteStorageCredential`, -`GetCredential`, `GetStorageCredential`, `UpdateCredential`, -`UpdateStorageCredential`) expose a field called `nameArg`. The "Arg" suffix -is meaningless on the TS side; it exists only because the generator needs to -disambiguate from a sibling `name` field that lives in the same envelope on -Update operations. TS callers will read `req.nameArg = 'my-credential'` and -have no idea why it isn't just `name`. +Six request types (`DeleteCredentialRequest`, `DeleteStorageCredentialRequest`, +`GetCredentialRequest`, `GetStorageCredentialRequest`, `UpdateCredentialRequest`, +`UpdateStorageCredentialRequest`) expose a field called `nameArg`. The "Arg" +suffix is meaningless on the TS side; it exists only because the generator +needs to disambiguate from a sibling `name` field that lives in the same +envelope on Update operations. TS callers will read `req.nameArg = 'my-credential'` +and have no idea why it isn't just `name`. Combined with H5 below, the Update envelopes are particularly broken: ```ts -interface UpdateCredential { +interface UpdateCredentialRequest { nameArg?: string; // URL path parameter — which credential to update newName?: string; // new credential name name?: string; // body-level "credential name" — what does this even do? @@ -143,19 +138,19 @@ keep only `name` (path) + `newName` (rename) and drop the body-level `name`. ### H5. Body-level `name` collides with path-level `nameArg` -`UpdateCredential` and `UpdateStorageCredential` carry both `nameArg` (path -parameter) and `name` (body field). The JSDoc on `name` says "The credential -name. The name must be unique among storage and service credentials within the -metastore." — i.e., the *new* canonical name. But there is *also* a `newName` -field. So `nameArg`, `name`, and `newName` all reference the same conceptual -"credential name" with no clear precedence. See #13, #14. +`UpdateCredentialRequest` and `UpdateStorageCredentialRequest` carry both +`nameArg` (path parameter) and `name` (body field). The JSDoc on `name` says +"The credential name. The name must be unique among storage and service +credentials within the metastore." — i.e., the *new* canonical name. But there +is *also* a `newName` field. So `nameArg`, `name`, and `newName` all reference +the same conceptual "credential name" with no clear precedence. See #13, #14. ### H6. `purpose` field is referenced in JSDoc but does not exist on the type -The JSDoc on `readOnly` (model.ts:194-196, 268-272, etc.) and -`usedForManagedStorage` (model.ts:212-216) and `force` (model.ts:391-394) says -"Only applicable when purpose is **STORAGE**" or "**SERVICE**". But there is -no `purpose` field anywhere on `CreateCredential`/`UpdateCredential`/ +The JSDoc on `readOnly` (model.ts:264-266, etc.) and `usedForManagedStorage` +(model.ts:282-285) and `force` (model.ts:567-571) says "Only applicable when +purpose is **STORAGE**" or "**SERVICE**". But there is no `purpose` field +anywhere on `CreateCredentialRequest`/`UpdateCredentialRequest`/ `CredentialInfo`/`StorageCredentialInfo`. Either: - The generator dropped the field, or @@ -165,17 +160,17 @@ no `purpose` field anywhere on `CreateCredential`/`UpdateCredential`/ the model. In all cases the contract documented in JSDoc cannot be honored by a TS -caller. See #39. +caller. See #32. -### H7. Stuttering `ValidateCredential.credential.credentialName` +### H7. Stuttering `ValidateCredentialRequest.credential.credentialName` `req.credential` is the discriminated-union outer field. One of its cases is `{$case: 'credentialName', credentialName: string}` — so accessing the value is `req.credential.credentialName` and the outer field is also named after -the same word. Same for `ValidateStorageCredential.credential.storageCredentialName`. +the same word. Same for `ValidateStorageCredentialRequest.credential.storageCredentialName`. ```ts -const req: ValidateCredential = { +const req: ValidateCredentialRequest = { credential: {$case: 'credentialName', credentialName: 'my-cred'}, }; ``` @@ -184,6 +179,44 @@ Reads twice as "credential.credentialName". The inner discriminator key should be `name` (giving `req.credential.name`) — concise and unambiguous because the case is `'credentialName'`. +### H8. `Public` infix proto-architectural leak (1 type + 4 methods) + +Findings #34-#35. The package exposes **1 generated type** and **4 `Client` +methods** whose identifiers carry `Public` as a mid-position or trailing +word. The infix originates from the internal proto/service definition where +`Public` distinguishes externally-routable account-API endpoints from +internal RPCs; it has no meaning at the TS SDK boundary, where every +exported symbol is by definition public. + +Types (model.ts): + +- `ListCredentialsPublicRequest` (776). + +Methods (client.ts): + +- `createCredentialsPublic` (927). +- `deleteCredentialsPublic` (953). +- `getCredentialsPublic` (978). +- `listCredentialsPublic` (1003). + +Note also: the sibling consolidated UC endpoints (`CreateCredentialRequest`, +`CreateStorageCredentialRequest`, etc.) do *not* carry `Public` even though +they are equally externally-routable. This inconsistency confirms `Public` is +not a deliberate domain term but a wire-layer artifact whose presence depends +on which generation pass produced the type. + +Recommendation: drop the `Public` token from every identifier at the +generator level. Suggested renames: + +| Current | Suggested | +|---------|-----------| +| `ListCredentialsPublicRequest` | `AccountsListCredentialsRequest` | +| `Client.createCredentialsPublic` | `Client.createAccountsCredentials` | +| `Client.listCredentialsPublic` | `Client.listAccountsCredentials` | + +This is a generator-only fix — there is no way to rename these consistently +without touching the generator/spec. + --- ## Medium severity (worth pushing back on) @@ -204,7 +237,7 @@ A type named just `Credential` could be any of them. Domain-prefixing ### M2. `Client` is unqualified -`export class Client` (client.ts:80). Importing `{Client}` from `@databricks/sdk-credentials/v1` +`export class Client` (client.ts:106). Importing `{Client}` from `@databricks/sdk-credentials/v1` and from any sibling package collides. Either: - Export as `CredentialsClient`, or @@ -213,68 +246,23 @@ and from any sibling package collides. Either: ### M3. Eight `client.ts` method pairs duplicate work Sixteen methods, eight pairs. Each pair differs only in the URL it hits. -Cf. #11. The class is 707 lines, with ~30 lines of boilerplate per method. -Half of that is generated for the legacy storage-credentials path. - -### M4. `IsolationMode` enum values stutter the enum name - -```ts -enum IsolationMode { - ISOLATION_MODE_UNSPECIFIED, - ISOLATION_MODE_OPEN, - ISOLATION_MODE_ISOLATED, - ISOLATION_MODE_OPEN_IN_ACCOUNT, -} -``` +Cf. #11. The class is over 1000 lines, with ~30 lines of boilerplate per +method. Half of that is generated for the legacy storage-credentials path. -TS idiom (Google TS Style Guide §5.6) is PascalCase for enum members and no -prefix duplication: - -```ts -enum IsolationMode { - Unspecified, - Open, - Isolated, - OpenInAccount, -} -``` - -The wire format is dictated by the API server (the string values must remain -`ISOLATION_MODE_*`); but the TS keys can be renamed via the zod `transform` -without breaking the wire. - -### M5. `*Operation` enums are inconsistent with each other - -```ts -enum PathOperation { PATH_READ, PATH_READ_WRITE, PATH_CREATE_TABLE } -enum TableOperation { READ, READ_WRITE } -enum VolumeOperation { READ_VOLUME, WRITE_VOLUME } -``` - -Three enums for the same domain (read/write a cloud-storage thing) with three -different prefixing conventions. Pick one. (See #19, #21.) - -### M6. `TemporaryCredentials` shape duplicated across responses +### M4. `TemporaryCredentials` shape duplicated across responses `TemporaryCredentials` and the three `Generate*` response types carry the same field set. The wire endpoints might differ (so each method returns its own named type), but at the TS level there is no need to create multiple declarations. -### M7. `UcEncryptedToken` and `Uc*` discriminator case use unspelled-out abbreviation - -`Uc` = "Unity Catalog". A TS-side consumer outside Databricks won't recognize -the abbreviation. The same model file uses `unityCatalog` spelled out on -`AwsIamRole.unityCatalogIamArn` (#22) — inconsistent within the file. Pick -either `UnityCatalogEncryptedToken` everywhere or `Uc*` everywhere. - -### M8. `R2Credentials` requires Cloudflare product knowledge +### M5. `R2Credentials` requires Cloudflare product knowledge A type named `R2` is identifiable only to readers who know Cloudflare's product line. The JSDoc gives no expansion. Use `CloudflareR2Credentials` or add a JSDoc anchor. -### M9. `unityCatalogIamArn` field reads misleadingly +### M6. `unityCatalogIamArn` field reads misleadingly ```ts interface AwsIamRole { @@ -289,24 +277,17 @@ the ARN of the Databricks-managed IAM user that performs the role assumption (per the JSDoc). `databricksAssumeIdentityArn` or `assumerArn` would be clearer. -### M10. `expirationTime` field naming +### M7. `expirationTime` field naming The field is an epoch-ms integer ("Server time when the credential will expire"). The repo's convention elsewhere is `createdAt`/`updatedAt` (which are also epoch-ms). Rename to `expiresAt` for consistency. -### M11. `IsolationMode.ISOLATION_MODE_UNSPECIFIED` sentinel value - -Proto-style "Unspecified" sentinel. In TS, the field is already -`isolationMode?: IsolationMode | undefined`, so omitting the field communicates -"unspecified" naturally. The enum value is dead code. Either remove it or -document that callers should *not* set it. - --- ## Low severity (nits) -### L1. `AwsCredentials.accessPoint` should carry the ARN suffix +### L1. `TemporaryAwsCredentials.accessPoint` should carry the ARN suffix The JSDoc says "The Amazon Resource Name (ARN) of the S3 access point". The field is `accessPoint: string`. `accessPointArn` self-documents. @@ -351,7 +332,7 @@ the file; would warrant a better name if it leaked out. Standard across the SDK. Go-idiomatic, but consistent. -### L10. `Generate*Credential` method names are 30+ chars +### L10. `Generate*CredentialRequest` method names are 30+ chars `generateTemporaryServiceCredential` is 35 chars. Combined with `await client.generateTemporaryServiceCredential(req)` the call site is 60+ chars @@ -365,13 +346,12 @@ before the args. Cannot shorten without breaking the resource hierarchy. - `Gcp` (PascalCase first letter) — `GcpOauthToken`, `gcpServiceAccountKey`. Internally consistent. - `Aad` (mixed) — `aadToken` (field, short), `AzureActiveDirectoryToken` - (type, long). Inconsistent. See #24. + (type, long). Inconsistent. See #19. - `Iam` — consistent with `Aws`/`Gcp` style. -- `R2` — special-cased product name. See M8/#30. +- `R2` — special-cased product name. See M5/#23. - `Sas` (PascalCase first letter) — `AzureUserDelegationSas`, `sasToken`. Consistent. -- `Uc` — see M7/#27/#28. -- `Oauth` — see L5/#29. +- `Oauth` — see L5/#22. The JSDoc *text* in the same file uses ALL-CAPS forms ("AWS", "GCP", "IAM", "AAD") because that is how the cloud providers write them. The Google TS @@ -454,12 +434,11 @@ Class re-exported with `export {Client}`; types and enums re-exported with | **Long-lived credential** | The customer-supplied cloud-provider auth material (IAM role, service principal, etc.) stored in the metastore. Six discriminated cases. | | **Temporary credential** | Short-lived tokens vended by Databricks for direct cloud access. Six discriminated cases. | | **External location** | A cloud-storage URL registered in UC and authorized via a Storage Credential. Validated by `validateCredential` / `validateStorageCredential`. | -| **Isolation mode** | Workspace-binding policy for the credential securable. One of `Unspecified`, `Open`, `Isolated`, `OpenInAccount`. | +| **Isolation mode** | Workspace-binding policy for the credential securable. One of `Unspecified`, `Open`, `Isolated`. | | **Unbound credential** | A credential not bound to any workspace. Listable via `includeUnbound=true`. | | **`nameArg`** | URL-path positional argument for the credential's name. Exists because the request envelope also carries body-level `name` and `newName` — see H4, H5. | | **Access connector ID** (Azure) | The Azure resource ID of the Databricks Access Connector. | | **AAD token** | Azure Active Directory access token (Oauth bearer for Azure cloud services). | -| **UC encrypted token** | Encrypted ScopedCloudToken fallback when the cloud provider's token cannot be downscoped. Base64 string. | | **R2** | Cloudflare's S3-compatible object storage product (named after the SF-Bay-Area meme). | | **External ID** | AWS confused-deputy mitigation token in role assumption. | @@ -469,9 +448,26 @@ Class re-exported with `export {Client}`; types and enums re-exported with | File | Lines | Exports counted | Audited | |------|-------|-----------------|---------| -| `src/v1/model.ts` | 2293 | 7 enums, 32 interfaces | yes | -| `src/v1/client.ts` | 707 | 1 class, 18 public methods (16 RPC + 2 async generators) | yes | -| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | -| `src/v1/index.ts` | 60 | 1 class re-export, 6 enum re-exports, 39 type re-exports | yes | +| `src/v1/model.ts` | 2877 | 7 enums, 39 interfaces | yes | +| `src/v1/client.ts` | 1031 | 1 class, 22 public methods (20 RPC + 2 async generators) | yes | +| `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 80 | 1 class re-export, 7 enum re-exports, 51 type re-exports | yes | Every type, field, enum value, and method enumerated above is accounted for. + +--- + +## Fixed + +- #18 `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` (originally cited at model.ts:9): Fixed in regeneration on 2026-05-20 — enum value removed; `IsolationMode` now contains only `UNSPECIFIED`/`OPEN`/`ISOLATED`. +- #28 `UcEncryptedToken` field/case (`ucEncryptedToken`, `UcEncryptedToken` type) (originally cited at model.ts:461, 775): Fixed in regeneration on 2026-05-20 — the `ucEncryptedToken` discriminator case and `UcEncryptedToken` interface no longer exist in the generated model. +- #34 `AccountsCreateStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:56, 70): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsCreateStorageCredentialRequest` / `AccountsCreateStorageCredentialRequest_Response`. +- #35 `AccountsDeleteStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:75, 88): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsDeleteStorageCredentialRequest` / `AccountsDeleteStorageCredentialRequest_Response`. +- #36 `AccountsGetStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:91, 102): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsGetStorageCredentialRequest` / `AccountsGetStorageCredentialRequest_Response`. +- #37 `AccountsListStorageCredentialsPublicRequest` (+ `_Response`) (originally cited at model.ts:107, 116): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsListStorageCredentialsRequest` / `AccountsListStorageCredentialsRequest_Response`. +- #38 `AccountsUpdateStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:122, 136): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsUpdateStorageCredentialRequest` / `AccountsUpdateStorageCredentialRequest_Response`. +- #39 `CreateCredentialsPublicRequest` (originally cited at model.ts:378): Fixed in regeneration on 2026-05-22 — renamed to `CreateCredentialsRequest`. +- #40 `DeleteCredentialsPublicRequest` (originally cited at model.ts:578): Fixed in regeneration on 2026-05-22 — renamed to `DeleteCredentialsRequest`. +- #41 `GetCredentialsPublicRequest` (originally cited at model.ts:760): Fixed in regeneration on 2026-05-22 — renamed to `GetCredentialsRequest`. +- #43 `ListCredentialsPublicResponse` (originally cited at model.ts:780): Fixed in regeneration on 2026-05-22 — renamed to `ListCredentialsResponse`. +- #45 Eight Zod schema constants with `Public` infix (originally cited at model.ts:2020, 2037, 2294, 1346, 1358, 1362, 1374, 1386): Fixed in regeneration on 2026-05-22 — schemas renamed to drop `Public` (e.g. `marshalAccountsCreateStorageCredentialRequestSchema`, `unmarshalAccountsCreateStorageCredentialRequest_ResponseSchema`). diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 1f4f5f39..58a9be67 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -8,15 +8,15 @@ ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 12 | +| High | 8 | +| Medium | 13 | | Low | 7 | | Observation | 4 | ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #31). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #30). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. @@ -33,37 +33,31 @@ - **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). - **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. -### 4. `State.STATE_UNSPECIFIED` redundant prefix — `src/v1/model.ts:10` -- **Why weird:** The enum value `STATE_UNSPECIFIED` repeats the enum name as a prefix — at the call site it reads `State.STATE_UNSPECIFIED`, which is doubled. The `_UNSPECIFIED` sentinel is also redundant in TypeScript, where `optimizationState?: State | undefined` already expresses "not set". -- **Category:** 2 (redundant enum prefix), 18 (questionable enum value). -- **Suggested name:** Drop `STATE_UNSPECIFIED` (rely on `optimizationState?: State | undefined`); rename the remaining values to title-case: `OptimizationRunState.Created | Running | Completed | Failed | Pending | Cancelled`. -- **Rationale:** The Google TS style guide treats enum members as constants, so SCREAMING_SNAKE is defensible — but at minimum the redundant `STATE_` prefix should go, and the unspecified sentinel duplicates what `undefined` already conveys. - -### 5. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` +### 4. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` - **Why weird:** Doc comment "The Id of the tile." refers to a "tile" that does not exist anywhere else in the package. This is almost certainly a copy-paste from another generated API (dashboards/tiles). Either the field name or the doc is wrong; reading the surrounding code, the field is the custom-LLM id (same as `CancelCustomLlmOptimizationRunRequest.id` on line 20). Public SDK doc bug. - **Category:** 6 (misleading — doc contradicts the actual domain). - **Suggested name:** Field name stays `id`; fix the JSDoc to "The id of the custom LLM whose optimization run to start." (matches `DeleteCustomLlmRequest.id` and `GetCustomLlmRequest.id` docs on lines 69 and 74). - **Rationale:** A naming audit should flag doc-text bugs on identifiers as well as the identifier itself; consumers learn the semantics from JSDoc and a wrong doc is as harmful as a wrong name. -### 6. `id` field on every request and on `CustomLlm` — `src/v1/model.ts:20,44,70,75,80,93` +### 5. `id` field on every request and on `CustomLlm` — `src/v1/model.ts:20,44,70,75,80,94` - **Why weird:** Bare `id` shows up on six places (`Cancel...Request.id`, `CustomLlm.id`, `Delete...Request.id`, `Get...Request.id`, `Start...Request.id`, `Update...Request.id`). Every JSDoc has to redundantly say "The id of the custom llm". A typed `customLlmId` makes the wire/TS surface self-documenting and avoids confusion with future API extensions (the endpoint is at `/api/2.0/custom-llms/{id}` — `id` here is the LLM id, not a generic id). - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `customLlmId` (or `llmId` if the `Custom` prefix is dropped per #2). Wire stays `id`. - **Rationale:** When grepping logs or stack-traces for `customLlmId`, you'll find the right call site. Today you'll grep for `id` and get 50 false positives across the SDK. -### 7. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` +### 6. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` - **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. - **Category:** Observation / 6 (misleading — field-mask implies updatable). - **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. - **Rationale:** This is the kind of thing a careful TS API designer would notice; a generator running over the proto schema will not. -### 8. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` +### 7. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` - **Why weird:** `UpdateCustomLlmRequest.customLlm: CustomLlm | undefined`. The TS naming convention makes the field/type distinction work via casing — but at a call site you'll write `req.customLlm = {...} satisfies CustomLlm`, and `customLlm` (the field) is one character of casing away from `CustomLlm` (the type). Type-suffix tautology under rule 20. - **Category:** 20 (type-suffix tautology). - **Suggested name:** Rename `customLlm` field → `llm` (paired with type rename `CustomLlm` → `Llm` per #2). Even without the type rename, the field can be `target` or `update`. - **Rationale:** `req.llm` reads cleanly; `req.customLlm` is the kind of name that survives code review only because nobody wants to argue with the generator. -### 9. `CustomLlm.creator: string` — `src/v1/model.ts:58` +### 8. `CustomLlm.creator: string` — `src/v1/model.ts:58` - **Why weird:** "Creator of the custom LLM" — but a `creator` could be a username, an email, a UUID, a Databricks principal-id, or a service-principal client-id. The type is `string` so there is no help. Other Databricks SDK packages (catalog, jobs) use `createdBy` or `creator` similarly inconsistently. The name does not say *what kind* of identifier it is. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `createdBy` if it is a user/principal id (matches Unity Catalog convention); add `@format` JSDoc clarifying whether it is an email or a UUID. @@ -71,72 +65,78 @@ ## Medium severity -### 10. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` +### 9. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` - **Why weird:** `creationTime` is named with the type-suffix convention (`*Time`), while peer fields on the same struct use bare nouns (`creator`, `name`, `instructions`). The other generated SDKs sometimes use `createdAt` or `createTime`. Naming `creationTime` is fine, but it is the *only* type-suffix field on `CustomLlm`. - **Category:** 17 (inconsistency within the same struct). - **Suggested name:** `createdAt` (Stripe/GitHub convention, https://stripe.com/docs/api/charges/object) or `createTime` (Google AIP-142, https://google.aip.dev/142). Either is more standard than `creationTime`. - **Rationale:** AIP-142 (Google API design) says: "Fields representing the time at which a resource was created should be of type google.protobuf.Timestamp and called `create_time`." The Go SDK and Java SDK tend to mirror this; TS should too. -### 11. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` +### 10. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` - **Why weird:** Two near-synonyms with different cardinalities. `instructions` is a single string, `guidelines` is a string array. The semantic difference is not obvious from the names; both feel like "things the model should follow". This is an API-design issue more than a naming issue, but the names amplify the confusion. - **Category:** 6 (misleading), 12 (duplicate concept). - **Suggested name:** `systemPrompt` (or `instruction`) for the single-string case; `rules` or `constraints` for the array. The bigger fix is to consolidate at the API level. - **Rationale:** Reading `instructions` + `guidelines` side-by-side, a consumer cannot guess which goes where without reading the prose docs. -### 12. `Table.tablePath` — `src/v1/model.ts:85` +### 11. `Table.tablePath` — `src/v1/model.ts:85` - **Why weird:** Type-suffix tautology (`Table.tablePath`). Doc says "Full UC table path in catalog.schema.table_name format" — but the field name does not communicate that it's a *fully qualified* three-part name. Compare with sibling SDK packages where the same concept is called `fullName` or `qualifiedName`. - **Category:** 20 (type-suffix tautology), 1 (vague — "path" is generic; a filesystem path? a JSON pointer?). - **Suggested name:** `fullName` (matches `catalog.TableInfo.full_name`) or `qualifiedName`. - **Rationale:** Unity Catalog already has a canonical term for three-part names (`full_name`); reusing it makes cross-API code less surprising. -### 13. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` +### 12. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` - **Why weird:** `Col` is a cryptic abbreviation for `Column`. The same package spells out `endpointName` and `agentArtifactPath` and `optimizationState`, so `Col` is inconsistent. Doc strings even use the full word: "Name of the request column". - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling fields). - **Suggested name:** `requestColumn` / `responseColumn`. - **Rationale:** Three saved characters is not worth the cognitive split between the doc ("column") and the identifier ("col"). -### 14. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` +### 13. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` - **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. - **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). - **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. - **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. -### 15. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` +### 14. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` - **Why weird:** Field `optimizationState` of type `State`. If `State` is renamed to `OptimizationRunState` per #3, the field can be renamed `optimization: OptimizationRunState` or `runState: OptimizationRunState`. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `optimization` (if type renamed) or just `state` with `State` more specific. Best is the pair `optimization: OptimizationRunState`. - **Rationale:** Reduces the noise once the enum name is specific. -### 16. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` +### 15. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `creationTime` reads as a `Date` and many callers will accidentally `new Date(customLlm.creationTime)`, which throws because `Temporal.Instant` does not coerce. Worth a comment in JSDoc; not a rename. - **Category:** Observation. - **Suggested name:** Keep `creationTime`; expand JSDoc to mention `Temporal.Instant`. - **Rationale:** Friction is from the type more than the name, but the name does not warn the reader of the unusual type. -### 17. Method names mix `Llm` and verb tense — `src/v1/client.ts:69,92,118,137,162,191` +### 16. Method names mix `Llm` and verb tense — `src/v1/client.ts:69,92,118,137,162,191` - **Why weird:** Methods are `cancelCustomLlmOptimizationRun`, `createCustomLlm`, `deleteCustomLlm`, `getCustomLlm`, `startCustomLlmOptimizationRun`, `updateCustomLlm`. They are verb-noun and consistent — but the noun is *always* `CustomLlm` which doubles the package name. After the fix in #2 these collapse to `cancelOptimizationRun`, `createLlm`, `deleteLlm`, `getLlm`, `startOptimizationRun`, `updateLlm` — much shorter. - **Category:** 7 (overly verbose). - **Suggested name:** Drop the redundant `CustomLlm` infix on the client methods; the package namespace already supplies it. - **Rationale:** Compare to `accountSettings.Client.deleteLlmProxyPartnerPoweredWorkspace` (accountsettings package) — that name is 41 chars long. SDK ergonomics suffer. Worth a project-wide convention question. -### 18. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +### 17. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 19. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair +### 18. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than the `Http` infix. -### 20. `HttpCallOptions` — `src/v1/utils.ts:15` +### 19. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). - **Rationale:** Distinguish internal context bags from user-tunable option structs. +### 20. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` +- **Why weird:** The `State` enum's first member `STATE_UNSPECIFIED` is a proto-architectural leak. Proto3 requires every enum to declare a zero-value sentinel (typically `FOO_UNSPECIFIED`); that requirement does not exist in TypeScript. Exposing it on the public TS surface forces every consumer to handle a member that semantically means "the server forgot to set this field" — a proto wire-format concern, not a domain concern. The screaming-snake-case casing (`STATE_UNSPECIFIED`) also leaks proto's enum-value convention into a TS type system that conventionally uses PascalCase for enum members (https://google.github.io/styleguide/tsguide.html#enums). +- **Category:** Proto-architectural leak (enum sentinel + screaming-snake casing). +- **Suggested name:** Drop the `STATE_UNSPECIFIED` member entirely; if a "not yet set" value is needed, use `undefined` (the field is already `State | undefined`). If kept, rename to PascalCase `Unspecified` and document that it is a wire-format sentinel. +- **Rationale:** Optional TS fields express "unset" via `undefined`; a redundant enum sentinel doubles the representation of "no value" and forces consumers to write `state !== undefined && state !== State.STATE_UNSPECIFIED`. The all-caps casing further signals that the value is a proto artifact rather than a designed TS API member. + ### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. - **Category:** 1 (vague), 15 (generic field name). @@ -198,7 +198,7 @@ The package exposes singleton CRUD plus optimization start/cancel, but no `listC - **Category:** Observation. ### 31. Mixed acronym casing in core types -The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `APIError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `API` (all-caps), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. +The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `ApiError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `Api` (title), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. - **Category:** 3 (acronym casing). ### 32. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index 32104c26..8e7a6a67 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,14 +3,14 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 42 +**Total weird names flagged:** 55 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 18 | -| Low | 10 | +| High | 10 | +| Medium | 33 | +| Low | 9 | | Observation | 3 | ## High severity @@ -25,57 +25,51 @@ - **Why weird:** Two sibling packages model what is almost the same physical thing. `database` exposes `DatabaseInstance` / `SyncedDatabaseTable` / `DatabaseCatalog`; `postgres` exposes `ComputeInstance` / `SyncedTable` / `Catalog` / `Project` / `Branch` / `Endpoint`. Several types are textually duplicated (`DeltaTableSyncInfo`, `SyncedTablePosition`, `SyncedTablePipelineProgress`, `NewPipelineSpec`, `DatabaseCredential`, `GenerateDatabaseCredentialRequest`, `RequestedClaims`, `RequestedResource`, `ProvisioningInfo`, `ProvisioningPhase`, `SyncedTableState`). Multiple enums share names (`ProvisioningPhase`, `SyncedTableState`). - **Category:** 12 (duplicate concept across packages), 6 (misleading: user cannot infer which package owns what). - **Suggested name:** Either (a) merge into one `lakebase` package with versioning, (b) declare one package the public surface and mark the other internal, or (c) cross-reference each shared type and make the docstrings explicitly say "see postgres/v1 for the V2 API". -- **Rationale:** Comment at `client.ts:666-671` says "Lakebase V2 plans" — i.e. `database` is V1 and `postgres` is V2 OLTP. The naming does not reflect that lineage; users picking a dependency have no breadcrumb. +- **Rationale:** Comment at `client.ts:634-638` says "Lakebase V2 plans" — i.e. `database` is V1 and `postgres` is V2 OLTP. The naming does not reflect that lineage; users picking a dependency have no breadcrumb. -### 3. `DatabaseInstance` — `src/v1/model.ts:234` +### 3. `DatabaseInstance` — `src/v1/model.ts:195` - **Why weird:** Type's own JSDoc says "A DatabaseInstance represents a logical Postgres instance". `DatabaseInstance` is the central noun of the package, but it is named after a generic abstraction (`Database` × `Instance`) rather than the domain (`PostgresInstance` / `LakebaseInstance`). The name does not convey what makes this distinct from any other Databricks "instance" (warehouse, cluster, online table, etc.). - **Category:** 1 (generic), 15 (generic field name losing meaning). - **Suggested name:** `LakebaseInstance` or `PostgresInstance`. - **Rationale:** Reader sees `DatabaseInstance` and has no idea whether it's a SQL warehouse instance, a vector DB instance, or something else. Postgres SDK calls the same concept `ComputeInstance` (`postgres/v1/model.ts`), which is also generic — flagged separately under finding #2. -### 4. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:412-414` -- **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:404-409) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. +### 4. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:373-375` +- **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:365-370) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; keep `createdb`/`createrole`/`bypassrls` on the wire (marshal/unmarshal handles the mapping). - **Rationale:** Every other field in the package is `camelCase`. Three boolean fields breaking the convention to honour Postgres SQL keywords is a leak. Postgres SDK at `postgres/v1/model.ts` solves this differently — worth aligning. -### 5. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:85` +### 5. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:70` - **Why weird:** Should be `SYNCED_TABLE_OFFLINE`. Spelled as `SYNCED_TABLED_OFFLINE` (`TABLED` past tense). - **Category:** 6 (misleading: typo). - **Suggested name:** Fix the wire-string to `SYNCED_TABLE_OFFLINE`. - **Rationale:** This is a protocol-level typo that the SDK is propagating. If fixed upstream this becomes a breaking change unless aliased — flag now. ### 6. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) -- **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+3 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. +- **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+1 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. - **Category:** 7 (overly verbose), 12 (duplicate concept), 15 (generic prefix). - **Suggested name:** Hoist effective values onto a sub-struct or use a discriminated `{input, effective}` shape; or drop the `effective` fields and explain in docs that the same field is read-mostly on responses. - **Rationale:** This is a Lakebase API protocol pattern, not a naming bug per se, but the resulting TS surface is twice as wide as it needs to be. Worth pushing back upstream. -### 7. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:493`, `client.ts:428` -- **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 494 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:518): "Name of the **cluster** to get". +### 7. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:395` +- **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 447 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:471): "Name of the **cluster** to get". - **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). - **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. - **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. -### 8. `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` — `src/v1/model.ts:976`, `client.ts:998` -- **Why weird:** Inconsistent with the rest of the API surface: the type is `UpgradeInstance...` but every other type is `UpgradeDatabaseInstance...`. The method name is `upgradeInstanceToAutoscaling`, not `upgradeDatabaseInstance...`. Drops the `Database` namespace word that every other method preserves. -- **Category:** 17 (inconsistency in action verb / type prefix), 7 (overly verbose suffix `ToAutoscaling`). -- **Suggested name:** `UpgradeDatabaseInstanceRequest` (with an `autoscaling: true` toggle) or `EnableAutoscalingRequest` + `enableAutoscaling`. Pick one and match. -- **Rationale:** All other CRUD methods are `xDatabaseInstance`; this method's shorter prefix is jarring. Also the request struct has only `name` — the verb `upgradeInstanceToAutoscaling` packs the full target state into the method name, which is awkward. - -### 9. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:1017`, `index.ts:3` +### 8. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:924`, `index.ts:3` - **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. - **Rationale:** The current name reads ambiguously; class names should be noun phrases describing *what they are*. The export at index.ts:3 means consumers see it directly. -### 10. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:393,399,411` +### 9. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:354,360,372` - **Why weird:** `attributes` is a generic field name; `effectiveAttributes` is a second copy; the type is a nested message that holds 3 Postgres role boolean flags. "Attributes" carries no information about what the attributes describe (Postgres `CREATEDB` / `CREATEROLE` / `BYPASSRLS` permission flags). - **Category:** 1 (vague — `attributes` is generic), 15 (generic field name). - **Suggested name:** `pgRoleFlags` / `PgRoleFlags`, or `permissions` / `RolePermissions`. - **Rationale:** Reader hits `role.attributes.createdb` and has to consult the type to find out it's a Postgres-flag bag. Postgres docs use the phrase "role attributes" so the alignment is intentional — but the SDK is for non-Postgres-experts too. -### 11. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:545,589` +### 10. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:498,542` - **Why weird:** The list-response field on catalogs is `databaseCatalogs: DatabaseCatalog[]` (matches type name), but on synced tables it's `syncedTables: SyncedDatabaseTable[]` (drops `Database`). On instance-roles it's `databaseInstanceRoles: DatabaseInstanceRole[]` (matches). On instances it's `databaseInstances: DatabaseInstance[]` (matches). The synced-tables one is the odd one out. - **Category:** 17 (inconsistent), 9 (singular/plural mismatch with the type). - **Suggested name:** `syncedDatabaseTables: SyncedDatabaseTable[]` (wire stays `synced_tables` if API requires it). @@ -83,255 +77,255 @@ ## Medium severity -### 12. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:236,238` -- **Why weird:** Two fields look like identifiers. `uid` is "immutable UUID identifier"; `name` is "unique identifier". Caller reading the struct can't tell at a glance which one to pass to `getDatabaseInstance` (answer: `name`, per client.ts:517). Bare `uid` is also non-descriptive — Lakebase uses both PG-side OIDs and Databricks-side UUIDs. +### 11. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:197,199` +- **Why weird:** Two fields look like identifiers. `uid` is "immutable UUID identifier"; `name` is "unique identifier". Caller reading the struct can't tell at a glance which one to pass to `getDatabaseInstance` (answer: `name`, per client.ts:484). Bare `uid` is also non-descriptive — Lakebase uses both PG-side OIDs and Databricks-side UUIDs. - **Category:** 19 (underspecified id when multiple ids exist), 1 (vague `uid`). - **Suggested name:** `instanceUid` / `instanceName`, or `id` / `name` (collapse `uid` to `id`). - **Rationale:** Same field-disambiguation pattern as `PolicyInfo.id` in the abacpolicies audit. `uid` reads as a hash, not a Databricks UUID — and the JSDoc just says "UUID identifier". -### 13. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:240` +### 12. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:201` - **Why weird:** Field doc says "The email of the creator of the instance". Field name says `creator`. So is the value an email, a username, or an account id? Postgres SDK uses `createdBy` for the same concept (postgres/v1/model.ts). - **Category:** 1 (vague — `creator` could be a name, an id, or an email), 6 (misleading — doc says email, name says creator). - **Suggested name:** `creatorEmail` (or `createdBy` if the value can be a service-principal id too). - **Rationale:** The doc explicitly narrows the type; the field name should match. -### 14. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:250` +### 13. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` - **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. - **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). - **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". - **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. -### 15. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:248` -- **Why weird:** `pg` is two letters lowercase; the next word starts capitalised. Consistent with `pgType` (model.ts:881) but inconsistent with `Postgres`/`PostgreSQL` used in JSDoc. Acronym `PG` is widely written uppercase. +### 14. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:209` +- **Why weird:** `pg` is two letters lowercase; the next word starts capitalised. Acronym `PG` is widely written uppercase. - **Category:** 3 (acronym casing — `pg` should arguably be `Pg` per camelCase, `PG` per acronym preservation). - **Suggested name:** `postgresVersion` (spell out), or `pgVersion` (current). - **Rationale:** Current `pgVersion` is OK but `postgresVersion` would be clearer. -### 16. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:242,289` +### 15. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:203,250` - **Why weird:** `Dns` is a single word; `DNS` is the acronym. Field doc says "The DNS endpoint to connect to the instance"; the value is a hostname, not a DNS server. Misleading abbreviation. - **Category:** 3 (acronym casing), 6 (misleading — `dns` suggests a DNS server, not an endpoint). - **Suggested name:** `readWriteEndpoint` / `readOnlyEndpoint`, or `readWriteHost` / `readOnlyHost`. - **Rationale:** A "DNS endpoint" is a non-standard phrase; the field is just a hostname. -### 17. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:258,264` +### 16. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` - **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? - **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). - **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. - **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. -### 18. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:269` +### 17. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:230` - **Why weird:** Field name says "node count"; doc says "1 primary and 0 or more secondaries". `nodeCount = 3` means 1 primary + 2 secondaries — but also could be read as "3 nodes, role unspecified". Postgres standby/replica terminology would be clearer. - **Category:** 1 (vague), 6 (misleading without docs). - **Suggested name:** `replicaCount`, or pair `primaryCount` + `secondaryCount`, or `totalNodeCount` (and document). - **Rationale:** Confusing arithmetic — `1` means primary-only, `2` means 1 primary + 1 secondary, etc. -### 19. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:278` +### 18. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:239` - **Why weird:** `enableXyz: boolean` is a request-shaped name on a response-shaped type. `enableReadableSecondaries: true` reads as imperative ("please enable"), but it's also returned from server. The companion `effectiveEnableReadableSecondaries` reads as "the effective please-enable-readable-secondaries". The doc on `effectiveEnableReadableSecondaries` even rewords it: "Whether secondaries serving read-only traffic are enabled" — i.e. the read shape should just be `readableSecondariesEnabled` or `hasReadableSecondaries`. - **Category:** 6 (misleading verb form for a response), 17 (input/output asymmetry). - **Suggested name:** Input: `enableReadableSecondaries: boolean`. Output: `readableSecondariesEnabled: boolean` (or just merge: response carries the same `enableReadableSecondaries` and don't bother with the `effective_` twin). - **Rationale:** Generator artefact, but worth flagging. -### 20. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:309,314` +### 19. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:270,275` - **Why weird:** `Ref` is a cryptic abbreviation (cf. `typescript.mdc` "spell out short identifiers"). Same as `DatabaseInstanceRef` itself. Could be `Reference` or just `DatabaseInstancePointer`. The semantic ("a reference to an instance") doesn't need the abbreviation. - **Category:** 5 (cryptic abbreviation), 8 (redundant `Ref` suffix — these are already references). - **Suggested name:** `parentInstance: DatabaseInstanceReference` / `childInstances: DatabaseInstanceReference[]`. - **Rationale:** Mild — `Ref` is widely understood — but spelling out matches the project rule. -### 21. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:362` +### 20. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:323` - **Why weird:** `lsn` is a Postgres-internal acronym (Log Sequence Number) shown without expansion. JSDoc says "User-specified WAL LSN" — still abbreviated. - **Category:** 5 (cryptic abbreviation), 14 (Postgres-internal term in public TS API). - **Suggested name:** `walLsn` (mild improvement), or `walLogSequenceNumber` (verbose but unambiguous). - **Rationale:** Lakebase exposes this to schedule branch creation; consumers may not know `lsn` without consulting Postgres docs. -### 22. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:381` +### 21. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:342` - **Why weird:** `branchTime` is a noun-phrase that reads as "the time of a branch" but is documented as "the point in time on the parent instance from which the instance was created" — i.e. the PITR cutover instant. `branchTime` and `lsn` are alternatives for the same operation (PITR cutover specifier). - **Category:** 1 (vague), 6 (misleading — `branchTime` suggests an event time, actually a cutover specifier). - **Suggested name:** `branchPointTime` / `branchAt` / `pitrTimestamp`. - **Rationale:** Reads naturally as "when was this branch made" but actually means "what point in the source's history to branch from". -### 23. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:224` -- **Why weird:** Bare `uid?: string` with no comment, alongside `name`, `databaseInstanceName`, `databaseProjectId`, `databaseBranchId`, `databaseName`. Six identifier-like fields and one (`uid`) is undocumented and unprefixed. +### 22. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:185` +- **Why weird:** Bare `uid?: string` with no comment, alongside `name`, `databaseInstanceName`, `databaseName`. Four identifier-like fields and one (`uid`) is undocumented and unprefixed. - **Category:** 19 (underspecified id), 1 (vague). - **Suggested name:** `catalogUid` (and add a doc comment). - **Rationale:** Reader cannot guess what scope the uid is for. -### 24. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:225` +### 23. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:186` - **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF NOT EXISTS`). Reads as a literal SQL DDL fragment in the type. Could be `ensureDatabase` / `autoCreateDatabase`. - **Category:** 14 (SQL-style name), 7 (verbose). - **Suggested name:** `ensureDatabaseExists` / `autoCreateDatabase`. - **Rationale:** Internal consistency with TS naming conventions. -### 25. `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` — `src/v1/model.ts:219-223` -- **Why weird:** `databaseProjectId` reads as "project id of a database (entity)" but doc says "project_id of the database project". The `database` prefix on every field is redundant once you're already inside `DatabaseCatalog`. Postgres SDK has `Catalog` (no `database` prefix) with `project`, `branch`, `database` sub-references — cleaner. +### 24. `DatabaseCatalog.databaseInstanceName` / `databaseName` — `src/v1/model.ts:182-184` +- **Why weird:** The `database` prefix on every field is redundant once you're already inside `DatabaseCatalog`. `databaseInstanceName` reads as "name of the database instance"; `databaseName` reads as "name of the database". Postgres SDK has `Catalog` (no `database` prefix) — cleaner. - **Category:** 7 (verbose prefix), 12 (duplicate concept across packages). -- **Suggested name:** `projectId`, `branchId`, `name` on the catalog directly; or hoist to a sub-struct `database: {projectId, branchId, name}`. +- **Suggested name:** `instanceName`, `name` on the catalog directly; or hoist to a sub-struct `database: {instanceName, name}`. - **Rationale:** The struct is already a `DatabaseCatalog`; re-prefixing every field is noise. -### 26. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:419` +### 25. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:380` - **Why weird:** Bare `name` carries a complex format (`catalog.schema.table`). Postgres SDK calls the same concept `fullName` / `name` more explicitly. There is no validation in the type — the convention is doc-only. - **Category:** 1 (vague), 6 (misleading — name looks like a single identifier, actually 3-part). - **Suggested name:** `fullName` (matches Postgres SDK convention). - **Rationale:** Same field name `name` appears on `DatabaseCatalog`, `DatabaseInstance`, `DatabaseInstanceRef`, `DatabaseInstanceRole`, `DatabaseTable`, `SyncedDatabaseTable` — each carries different semantics (DNS-safe vs UC-3-part vs role-name). -### 27. `DatabaseTable.tableServingUrl` field — `src/v1/model.ts:437` -- **Why weird:** `tableServingUrl` on a `DatabaseTable` reads as "the URL where this table is served". Doc says "Data serving REST API URL for this table". The word `Serving` is ML/feature-store jargon; on a Postgres table it's confusing. -- **Category:** 1 (vague), 6 (misleading — `Serving` is feature-store terminology, here means "REST endpoint"). -- **Suggested name:** `restEndpointUrl` / `apiEndpointUrl`. -- **Rationale:** Avoid leaking the internal "data serving" abstraction. - -### 28. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:417,643` -- **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`, `tableServingUrl`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". +### 26. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` +- **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". - **Category:** 12 (duplicate concept), 1 (generic `Database`). - **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. - **Rationale:** Reader has to read both JSDocs to understand the partitioning. -### 29. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:802` -- **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`, `tableServingUrl`) split words at capital boundaries. +### 27. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` +- **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`) split words at capital boundaries. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Trivia, but `time series` is two words in English. -### 30. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:798,419` +### 28. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:727,380` - **Why weird:** Same domain concept (UC 3-part name) named two different ways in the same package: `sourceTableFullName` here, bare `name` on `DatabaseTable`/`SyncedDatabaseTable`/`DatabaseCatalog`. - **Category:** 17 (inconsistent naming for the same concept). - **Suggested name:** Standardise on `fullName` (or `tableFullName`) across the package. -- **Rationale:** Pair with #26. +- **Rationale:** Pair with #25. -### 31. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:815` -- **Why weird:** Similar SQL-DDL leak as #24. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. +### 29. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:744` +- **Why weird:** Similar SQL-DDL leak as #23. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. - **Category:** 14 (SQL-style name), 6 (typo in cross-reference). - **Suggested name:** `ensureDatabaseAndSchema`. - **Rationale:** Internal consistency. -### 32. `SyncedTableSpec.acceleratedSync` — `src/v1/model.ts:830` -- **Why weird:** Adjective-noun toggle; reads as "use accelerated sync" but unclear what "accelerated" means. JSDoc says "enables accelerated sync mode for the initial data load." -- **Category:** 1 (vague — what *is* accelerated sync?), 15 (generic adjective). -- **Suggested name:** `useAcceleratedInitialLoad` or `accelerateInitialLoad`. -- **Rationale:** A consumer should not have to read JSDoc to know "accelerated" means "initial-load fast path". - -### 33. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:892` +### 30. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:759` - **Why weird:** Field is `detailedState`; sibling field is `detailedStatus`. Both have `detailed` prefix; redundant against the wrapping type `SyncedTableStatus`. Easy to confuse `detailedState` (enum) with `detailedStatus` (oneof). - **Category:** 17 (two `detailed*` neighbours), 7 (verbose). - **Suggested name:** `state: SyncedTableState`, `status: SyncedTableStatusDetail` (or hoist the oneof). - **Rationale:** Reader hits `tableStatus.detailedState` and `tableStatus.detailedStatus` and has to read both to decide which is which. -### 34. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:896` +### 31. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:763` - **Why weird:** `detailedStatus` on a `SyncedTableStatus` type is doubly redundant. Holds one of four phase-shaped sub-statuses (`provisioningStatus`, `continuousUpdateStatus`, `triggeredUpdateStatus`, `failedStatus`). Each variant is named `*Status` again — `tableStatus.detailedStatus.continuousUpdateStatus.lastProcessedCommitVersion` is "status.status.status.version". - **Category:** 7 (overly verbose chains). - **Suggested name:** Rename `detailedStatus` to `phase`, and strip the redundant `*Status` suffix off each sub-variant (`provisioning`, `continuousUpdate`, `triggeredUpdate`, `failed`). - **Rationale:** Reduces three `status` words to one without touching the wrapper itself. -### 35. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:928` +### 32. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 36. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:749` +### 33. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:678` - **Why weird:** Run-on field name — "latest version currently processing" is 4 words. Doc clarifies "may not have completely processed this version yet". Could be `inProgressDeltaVersion` or `currentDeltaVersion`. - **Category:** 7 (overly verbose), 1 (verbose adverb). - **Suggested name:** `processingDeltaVersion`. - **Rationale:** Verbose field names hurt readability. -### 37. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:751-757` +### 34. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:680-686` - **Why weird:** Mixed metric naming: `syncedRowCount` and `totalRowCount` use suffix `Count`; `syncProgressCompletion` uses suffix `Completion` (a number 0-1); `estimatedCompletionTimeSeconds` uses suffix `TimeSeconds` (unit-embedded). Three different conventions for "a number". - **Category:** 17 (inconsistent suffixes), 15 (generic field names). - **Suggested name:** `syncedRows`, `totalRows`, `progressFraction`, `etaSeconds`. - **Rationale:** The number-suffix conventions don't align with each other; pick one. -### 38. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:754-755` +### 35. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:683-684` - **Why weird:** Type is `number`; doc constrains to `[0, 1]`. Type system doesn't help. Field name `syncProgressCompletion` is also redundant — completion is what progress measures. - **Category:** 16 (type contradicts doc constraint), 7 (verbose). - **Suggested name:** `progressFraction` (or `progressRatio`), `number` in [0,1]. -- **Rationale:** Same as #37 plus a separate concern about the value range. +- **Rationale:** Same as #34 plus a separate concern about the value range. -### 39. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:477` +### 36. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` - **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. - **Category:** 20 (type-suffix tautology in field names), 7 (verbose). - **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. - **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. -### 40. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:510,630` +### 37. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 41. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:500` +### 38. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:453` - **Why weird:** Bare `requestId` with no doc. Other request types do not have `requestId`. Looks like an idempotency key but the type doesn't say. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `idempotencyKey` (and add docs). - **Rationale:** Without docs, callers can't tell whether to set it. -### 42. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:501-502` +### 39. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 43. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:453-456` +### 40. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:411-415` - **Why weird:** "Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. Setting a value of false will throw a bad request." Field is exposed in the public TS type but has no `@deprecated` JSDoc tag. - **Category:** 6 (misleading: deprecated field undocumented as deprecated). - **Suggested name:** Add `@deprecated` tag; consider removing in next major. - **Rationale:** TS tooling honours `@deprecated`; the current setup just has prose. +### 41. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` +- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #42 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. +- **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). +- **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`; field `inlinePipeline` (paired with `existingPipelineId`). Drop the `New` adjective and the `Spec` suffix. +- **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. + +### 42. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` +- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #43); `DeltaTableSyncInfo` is a sync checkpoint (see #36); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #41). Each of the four would read more clearly with a domain-specific suffix. +- **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). +- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #41); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #36); `ProvisioningInfo` → drop (per #43). Goal: no two types in the package share a generic suffix. +- **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. + +### 43. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` +- **Why weird:** Type declaration is literally `export interface ProvisioningInfo {}` with a comment "Copied over from managed-catalog/api/messages/common.proto to decouple SDK packages. xref go/unified-api-packages-dd". An empty interface — the type itself carries zero domain meaning. Only its nested `ProvisioningInfo_State` enum is used (referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`); the empty parent is a vestigial proto namespace. The exported type name and its nested enum bleed Managed Catalog internals into the Lakebase SDK. +- **Category:** proto-architectural leak (proto message preserved as empty TS interface for namespacing), 6 (misleading — exists but has no fields), 12 (cross-package proto leak). +- **Suggested name:** Drop the empty `ProvisioningInfo` interface; rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). The empty interface is a generator artefact that should not surface. +- **Rationale:** An empty exported interface is dead surface area. The xref comment (`go/unified-api-packages-dd`) tells the reader this is a cross-package proto coordination workaround — that workaround belongs in the generator, not in the public TS types. + ## Low severity -### 44. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:553` +### 44. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:505` - **Why weird:** Doc says "Pagination token to go to the next page of Database Instances" — but this is roles, not instances. Doc-copy bug. - **Category:** 6 (misleading doc). - **Suggested name:** Fix the doc to say "roles". - **Rationale:** Naming-adjacent bug worth flagging. -### 45. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:539` +### 45. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:491` - **Why weird:** Same bug: catalogs request says "synced database tables" in doc. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "catalogs". - **Rationale:** Same as #44. -### 46. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:562` +### 46. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:514` - **Why weird:** Doc says "next page of instances" for the roles response. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "roles". - **Rationale:** Same as #44. -### 47. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:192-196` -- **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:185-188). +### 47. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` +- **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:181-184). - **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). - **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. - **Rationale:** Caller has to know the wire-encoding accident to decide which to set. -### 48. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:462` +### 48. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:421` - **Why weird:** Postgres-isms (`REASSIGN OWNED BY ... TO ...`) collapsed into a single field. Field name reads as a verb phrase ("reassign owned [things] to"). - **Category:** 14 (SQL-style name). - **Suggested name:** `reassignOwnedObjectsTo` or `newOwner`. - **Rationale:** Mild — Postgres admins will get it. -### 49. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:463-464` +### 49. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` - **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. - **Category:** 14 (Google-AIP naming convention leak). - **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. - **Rationale:** Internal-jargon leak; flag for awareness. -### 50. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:474` +### 50. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:433` - **Why weird:** Boolean named after a side effect (`purge_data`). Doc says "the actual PostgreSQL table will be dropped from the database". Combination of `delete` + `purge` is also confusing — what does the no-purge case do? (Drop UC registration only.) - **Category:** 1 (vague), 6 (misleading). - **Suggested name:** `dropUnderlyingTable` / `cascade`. - **Rationale:** Minor — affects discoverability. -### 51. `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` — `src/v1/model.ts:490` -- **Why weird:** 30-character field name on a 2-field request. Reads as "failover target database instance name" which is 5 nouns stacked. -- **Category:** 7 (overly verbose). -- **Suggested name:** `targetInstanceName`. -- **Rationale:** Inside a `FailoverDatabaseInstanceRequest`, the `failover` and `databaseInstance` prefixes are implied. - -### 52. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:82` +### 51. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` - **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency. -### 53. `StillRunningError` private error class — `src/v1/client.ts:87` +### 52. `StillRunningError` private error class — `src/v1/client.ts:83` - **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. - **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). - **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). @@ -339,22 +333,22 @@ ## Observations -### 54. `client.ts` has a 6-line block-comment at line 666-671 explaining that the role APIs will never reach Public Preview +### 53. `client.ts` has a 5-line block-comment at line 633-638 explaining that the role APIs will never reach Public Preview The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. - **Category:** 6 (misleading: client exposes APIs that won't stabilise). - **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. -### 55. `findDatabaseInstanceByUid` is the only `findBy*` method +### 54. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 56. Action-verb conventions in `Client` are consistent -`create*` / `delete*` / `get*` / `list*` / `update*` / `failover*` / `findBy*` / `upgrade*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. +### 55. Action-verb conventions in `Client` are consistent +`create*` / `delete*` / `get*` / `list*` / `update*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. ## Domain glossary -- `Lakebase` — Databricks' managed Postgres-as-a-service product (mentioned only in the buried client.ts:666 comment). -- `PG` / `pg` / `Postgres` / `PostgreSQL` — Postgres database; appears as `pgVersion`, `pgType`, `enablePgNativeLogin`, `PG_ONLY`, `PG_SPECIFIC_TYPE_*`, and as `PostgreSQL` in JSDoc. -- `UC` — Unity Catalog (referenced in `claims` doc model.ts:506-510 and in JSDoc of `DatabaseCatalog` model.ts:214). +- `Lakebase` — Databricks' managed Postgres-as-a-service product (mentioned only in the buried client.ts:634 comment). +- `PG` / `pg` / `Postgres` / `PostgreSQL` — Postgres database; appears as `pgVersion`, `enablePgNativeLogin`, `PG_ONLY`, and as `PostgreSQL` in JSDoc. +- `UC` — Unity Catalog (referenced in `claims` doc and in JSDoc of `DatabaseCatalog`). - `DNS` — Domain Name System (used as `Dns` suffix on `readWriteDns`/`readOnlyDns`). - `LSN` — Postgres Log Sequence Number (`lsn`, `effectiveLsn`). - `WAL` — Postgres Write-Ahead Log (referenced in `lsn` doc). @@ -367,7 +361,14 @@ Every other lookup is `getX(req)`. This method exists because the API has a dist - `oss`/`m2m`/`u2m`/`pat`/`iam`/`abac` — not encountered in this package. ## File coverage -- `src/v1/model.ts` (2,217 lines): read fully. -- `src/v1/client.ts` (1,088 lines): read fully. +- `src/v1/model.ts` (1,904 lines): read fully. +- `src/v1/client.ts` (995 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (76 lines): read fully. +- `src/v1/index.ts` (67 lines): read fully. + +## Fixed +- #8 `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` (originally cited at `src/v1/model.ts:976`, `client.ts:998`): Fixed in regeneration on 2026-05-20 — the request type and client method were removed from the generated surface. +- #25 `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` (originally cited at `src/v1/model.ts:219-223`): Fixed in regeneration on 2026-05-20 — `databaseProjectId` and `databaseBranchId` were removed; the remaining `databaseName` / `databaseInstanceName` prefix concern is captured in active finding #24. +- #27 `DatabaseTable.tableServingUrl` (originally cited at `src/v1/model.ts:437`): Fixed in regeneration on 2026-05-20 — the field was removed from `DatabaseTable`. +- #32 `SyncedTableSpec.acceleratedSync` (originally cited at `src/v1/model.ts:830`): Fixed in regeneration on 2026-05-20 — the field was removed from `SyncedTableSpec`. +- #51 `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` (originally cited at `src/v1/model.ts:490`): Fixed in regeneration on 2026-05-20 — the entire `FailoverDatabaseInstanceRequest` type and its client method were removed from the generated surface. diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md index 1bcbc426..5fbdb3cf 100644 --- a/.agent/naming-audit/dataclassification.md +++ b/.agent/naming-audit/dataclassification.md @@ -3,69 +3,63 @@ **Path:** `packages/dataclassification/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 19 +**Total weird names flagged:** 18 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 4 | | Medium | 4 | | Low | 6 | | Observation | 4 | ## High severity -### 1. `autoTagConfigs` field vs. `AutoTaggingConfig` type — `src/v1/model.ts:57,62` -- **Why weird:** Field name uses abbreviated `autoTag` while the type it points to is the full `AutoTaggingConfig`. Within five lines the SDK uses both `tag`-noun and `tagging`-gerund for the same concept. +### 1. `autoTagConfigs` field vs. `AutoTaggingConfig` type — `src/v1/model.ts:52` +- **Why weird:** Field name uses abbreviated `autoTag` while the type it points to is the full `AutoTaggingConfig`. Within a few lines the SDK uses both `tag`-noun and `tagging`-gerund for the same concept. - **Category:** 5 (cryptic abbreviation — `Tag` for `Tagging`), 17 (inconsistency with sibling type — `autoTagConfigs: AutoTaggingConfig[]`). -- **Suggested name:** `autoTaggingConfigs: AutoTaggingConfig[]` (and `effectiveAutoTaggingConfigs`). Wire stays `auto_tag_configs` if upstream insists. +- **Suggested name:** `autoTaggingConfigs: AutoTaggingConfig[]`. Wire stays `auto_tag_configs` if upstream insists. - **Rationale:** A field of `Foo[]` should plural-ise the type name: `foos: Foo[]`. Mixing `autoTag` and `AutoTagging` makes the relationship unobvious and forces a mental translation on every read. -### 2. `effectiveAutoTagConfigs` — `src/v1/model.ts:62` -- **Why weird:** Two parallel fields (`autoTagConfigs` for owned + `effectiveAutoTagConfigs` for owned-plus-inherited) on the same type. "Effective" is fine on its own, but the parent type does not say which is read-only vs. write — a caller can easily set `effectiveAutoTagConfigs` thinking it will take effect. -- **Category:** 1 (vague — `effective` does not communicate "computed/read-only" on its own), 6 (misleading: looks settable but is server-computed). -- **Suggested name:** `inheritedAutoTaggingConfigs` (or split into `autoTaggingConfigs` + `computedAutoTaggingConfigs` with a JSDoc `@readonly`). -- **Rationale:** SDK fields without an output-only marker invite write-side mistakes. The current doc says "Computed from auto_tag_configs on this catalog and those inherited from the metastore" but the type does not enforce that. - -### 3. `name` field on `CatalogConfig` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` — `src/v1/model.ts:42,88,94` +### 2. `name` field on `CatalogConfig` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` — `src/v1/model.ts:37,78,84` - **Why weird:** Field literally called `name` carries a structured resource path (`catalogs/{catalog_name}/config`), not a free-form name. `name` is the most generic possible identifier and gives no hint that it must follow a specific format. - **Category:** 1 (vague — `name` is the canonical too-generic field name), 6 (misleading — looks like a display name, is actually a structured resource path), 15 (generic field name losing meaning), 19 (underspecified ID). - **Suggested name:** `resourceName` or `configResourceName`. If staying with `name`, the JSDoc should at least be on the type rather than only on each field. - **Rationale:** A user importing `CatalogConfig` and seeing `name?: string` will almost certainly try to put `"my-catalog"` in there, not `"catalogs/my-catalog/config"`. The wire constraint is invisible from the type. -### 4. `parent` field on `CreateCatalogConfigRequest` — `src/v1/model.ts:77` +### 3. `parent` field on `CreateCatalogConfigRequest` — `src/v1/model.ts:67` - **Why weird:** Field called `parent` carries the structured value `catalogs/{catalog_name}`. The relationship "catalog is the parent of catalog-config" is a proto/AIP-160 convention that does not survive into a TS SDK where users do not see the resource hierarchy. - **Category:** 1 (vague — `parent` of what?), 15 (generic field name losing meaning), 19 (underspecified ID). - **Suggested name:** `catalogResourceName` or `parentCatalog`. - **Rationale:** `parent: string` is a Google-AIP idiom; outside that context a caller has no idea what shape to put in. A user-friendly TS SDK would either accept `{catalogName: 'my-catalog'}` directly or rename to make the constraint visible. -### 5. `classificationTag` and `classificationTagValue` — `src/v1/model.ts:25,32` -- **Why weird:** The pair encodes a `(key, value)` tag, but the names are `tag` and `tagValue` instead of `tagKey` and `tagValue`. The first field actually holds the tag *key* per its doc ("For built-in classes this is a system tag (e.g., \"class.name\"...)"). Calling the key "the Classification Tag" while the value is "the Classification Tag Value" makes the parts asymmetric. -- **Category:** 1 (vague — `classificationTag` is the key, not the whole tag), 6 (misleading — name suggests "the tag" but it is one half of one), 17 (asymmetric pair naming — `tag` vs `tagValue`). -- **Suggested name:** `classificationTagKey` + `classificationTagValue` (or `tagKey` + `tagValue`). -- **Rationale:** Symmetric `key`/`value` field names are the standard idiom for tag pairs across Unity Catalog (`tagKey`/`tagValue` appears in `unitycatalog` packages). The current name asymmetry suggests the two fields hold different kinds of thing when they hold two halves of one. +### 4. `classificationTag` field — `src/v1/model.ts:25` +- **Why weird:** The field is literally called `classificationTag` but its doc says it holds a "system tag (e.g., `class.name`...)" — i.e., a tag *key*, not a whole `{key, value}` tag. The name promises a tag object; the type and doc deliver a key string. +- **Category:** 1 (vague — `classificationTag` reads as a tag object, but is a string), 6 (misleading — name suggests "the tag" but it is one half of one). +- **Suggested name:** `classificationTagKey` (or just `tagKey`). +- **Rationale:** Standard idiom across Unity Catalog packages for the key half of a tag pair is `tagKey`. A field called `classificationTag: string` invites a caller to pass a serialized tag object rather than just the key. ## Medium severity -### 6. `Client` class — `src/v1/client.ts:38` +### 5. `Client` class — `src/v1/client.ts:38` - **Why weird:** A class literally named `Client` at the top level of the package's API surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). - **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. -### 7. `CreateCatalogConfigRequest` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` / `UpdateCatalogConfigRequest` — `src/v1/model.ts:75,86,92,103` +### 6. `CreateCatalogConfigRequest` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` / `UpdateCatalogConfigRequest` — `src/v1/model.ts:65,76,82,93` - **Why weird:** All four request DTOs repeat the noun `CatalogConfig` even though the only thing this package operates on is `CatalogConfig`. The package name itself is `dataclassification`. In context, `CreateRequest`/`UpdateRequest` would be plenty. - **Category:** 7 (overly verbose), 8 (redundant suffix and infix). - **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`, or keep `Catalog` and drop `Config`: `CreateCatalogRequest`/... - **Rationale:** The whole package operates on exactly one entity. Repeating its name in four request types is pure noise. (However, the inconsistency with the entire rest of the SDK matters — proposing as a per-package fix is risky. Listed medium not high.) -### 8. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 7. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. -### 9. `flattenQueryParams` — `src/v1/utils.ts:123` +### 8. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. @@ -73,37 +67,37 @@ ## Low severity -### 10. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` +### 9. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 11. `userAgent` field — `src/v1/client.ts:45` +### 10. `userAgent` field — `src/v1/client.ts:45` - **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. - **Category:** N/A (verification, no issue). - **Suggested name:** unchanged. - **Rationale:** Listed only to confirm canonical naming is preserved. -### 12. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` +### 11. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 13. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` +### 12. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` - **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. - **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. -### 14. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` +### 13. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 15. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` +### 14. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` - **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. @@ -111,17 +105,17 @@ ## Observations -### 16. Wire/TS divergence is heavy -The model file is 229 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. +### 15. Wire/TS divergence is heavy +The model file is 206 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. -### 17. Action-verb conventions in `Client` +### 16. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) -### 18. Acronym casing +### 17. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 19. `dataclassification` lowercase package name +### 18. `dataclassification` lowercase package name The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). @@ -133,7 +127,11 @@ The package directory is `dataclassification` (one word, no separator), but ever - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. ## File coverage -- `src/v1/model.ts` (229 lines): read fully. +- `src/v1/model.ts` (206 lines): read fully. - `src/v1/client.ts` (181 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (16 lines): read fully. + +## Fixed +- #2 `effectiveAutoTagConfigs` (originally cited at `src/v1/model.ts:62`): Fixed in regeneration on 2026-05-20 — field removed from `CatalogConfig`; only `autoTagConfigs` remains. +- #5 `classificationTag` / `classificationTagValue` asymmetric pair (originally cited at `src/v1/model.ts:25,32`): Fixed in regeneration on 2026-05-20 — `classificationTagValue` field removed; the remaining vagueness on `classificationTag` (key-named-as-whole-tag) is now tracked as finding #4. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index eb6c8071..9b389503 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -2,252 +2,234 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 -**Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, validity checks (`PercentNull`, `Range`, `Uniqueness`), and notification routing on failure. -**Total weird names flagged:** 44 +**Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, and notification routing on failure. +**Total weird names flagged:** 41 ## Summary | Severity | Count | | --- | --- | -| High | 14 | +| High | 11 | | Medium | 17 | | Low | 8 | | Observation | 5 | ## High severity -### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:366,372`, `src/v1/client.ts:316` +### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:345,351`, `src/v1/client.ts:316` - **Why weird:** Singular noun on a list operation. A list returns many monitors but the type and method names use the singular `Monitor`. The wire path is `/api/data-quality/v1/monitors` (plural), the response holds `monitors?: Monitor[]`, and the paginator yields a single `Monitor` — every concrete signal says plural; only the type/method name disagrees. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListMonitorsRequest` / `ListMonitorsResponse` / `listMonitors`. - **Rationale:** REST conventions, the package's own field naming (`monitors`, `refreshes`), and the URL path all use plural. The singular form here is generator template noise, not intent. Same fix applies to refreshes (#2). -### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:378,398`, `src/v1/client.ts:378` +### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:357,377`, `src/v1/client.ts:378` - **Why weird:** Same singular-on-list problem as #1. The wire path is `/refreshes` and the response holds `refreshes?: Refresh[]`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListRefreshesRequest` / `ListRefreshesResponse` / `listRefreshes`. - **Rationale:** Internal consistency: every other place in this file uses the plural `refreshes`. Only the type and method name break the pattern. -### 3. `RefreshState` enum members `MONITOR_REFRESH_STATE_*` — `src/v1/model.ts:80-90` -- **Why weird:** Enum is called `RefreshState`, but every member is prefixed `MONITOR_REFRESH_STATE_` — three levels of redundancy in one token (the enum name says it, the type appears as `state?: RefreshState`, and the value is fully namespaced as `RefreshState.MONITOR_REFRESH_STATE_RUNNING`). Members also include `MONITOR_REFRESH_STATE_UNKNOWN` while every other enum in this file uses `_UNSPECIFIED` — inconsistent sentinel naming. -- **Category:** 2 (redundant enum prefixes), 17 (inconsistent sentinel — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 18 (overly long enum values). -- **Suggested name:** `RefreshState.{Pending, Running, Success, Failed, Canceled}` and drop the unset sentinel (rely on `state?: RefreshState | undefined`). At minimum, normalise to `REFRESH_STATE_*` (drop `MONITOR_`). -- **Rationale:** The TS enum already namespaces values (`RefreshState.RUNNING`). `MONITOR_` is doubly redundant because the enum is only ever reached from `Refresh.state`, which is owned by a `Monitor`. The `UNKNOWN`/`UNSPECIFIED` inconsistency with `RefreshTrigger.MONITOR_REFRESH_TRIGGER_UNKNOWN` vs `AnomalyDetectionJobType.ANOMALY_DETECTION_JOB_TYPE_UNSPECIFIED` will trip API users who write `===` checks. +### 3. `RefreshState` uses `_UNKNOWN` sentinel instead of `_UNSPECIFIED` — `src/v1/model.ts:72-84` +- **Why weird:** `RefreshState` includes `MONITOR_REFRESH_STATE_UNKNOWN` while every other enum in this file uses `_UNSPECIFIED` (e.g. `DataProfilingStatus.DATA_PROFILING_STATUS_UNSPECIFIED`). Inconsistent sentinel naming across sibling enums on the same type. +- **Category:** 17 (inconsistent sentinel — `UNKNOWN` vs `UNSPECIFIED` in sibling enums). +- **Suggested name:** Normalise the unset member to `_UNSPECIFIED`. +- **Rationale:** The `UNKNOWN`/`UNSPECIFIED` inconsistency with `RefreshTrigger.MONITOR_REFRESH_TRIGGER_UNKNOWN` vs `DataProfilingStatus.DATA_PROFILING_STATUS_UNSPECIFIED` will trip API users who write `===` checks against the sentinel. -### 4. `RefreshTrigger` enum members `MONITOR_REFRESH_TRIGGER_*` — `src/v1/model.ts:94-101` -- **Why weird:** Same shape as #3. Six-token names (`MONITOR_REFRESH_TRIGGER_DATA_CHANGE`) where two tokens (`DataChange`) would suffice. Also uses `_UNKNOWN` rather than the more common `_UNSPECIFIED`. -- **Category:** 2 (redundant enum prefix), 17 (sentinel inconsistency), 18 (long enum values). -- **Suggested name:** `RefreshTrigger.{Manual, Schedule, DataChange}`. +### 4. `RefreshTrigger` uses `_UNKNOWN` sentinel instead of `_UNSPECIFIED` — `src/v1/model.ts:87-95` +- **Why weird:** Same sentinel inconsistency as #3. `RefreshTrigger` uses `_UNKNOWN` for the unset value while sibling enums use `_UNSPECIFIED`. +- **Category:** 17 (sentinel inconsistency). +- **Suggested name:** Normalise the unset member to `_UNSPECIFIED`. - **Rationale:** Same as #3. -### 5. `AggregationGranularity` enum members `AGGREGATION_GRANULARITY_N_*` — `src/v1/model.ts:8-30` -- **Why weird:** Every value re-states the enum name and then mixes digits with words (`AGGREGATION_GRANULARITY_5_MINUTES`, `AGGREGATION_GRANULARITY_2_WEEKS`). The digit-then-unit form does not map to any TS identifier convention. `_UNSPECIFIED` is the bottom value, so a user must read past it to see `_5_MINUTES` is the smallest real granularity. -- **Category:** 2 (redundant enum prefix), 18 (overly long enum values). -- **Suggested name:** `AggregationGranularity.{FiveMinutes, ThirtyMinutes, OneHour, OneDay, OneWeek, TwoWeeks, ThreeWeeks, FourWeeks, OneMonth, OneYear}` — or, better, drop the numeric quantum entirely and use an ISO-8601 duration string (`PT5M`, `P1D`) so the enum is open to new granularities without code changes. -- **Rationale:** TS enums forbid leading digits in member names, which is why this enum carries the `AGGREGATION_GRANULARITY_` prefix — to make `_5_MINUTES` syntactically legal. That's a tell that the names are working around a language limit. Rename to spelled-out words. - -### 6. `DataProfilingCustomMetricType` enum members — `src/v1/model.ts:49-57` -- **Why weird:** Six tokens per member (`DATA_PROFILING_CUSTOM_METRIC_TYPE_AGGREGATE`). The enum itself is `DataProfilingCustomMetricType` — at the field site you'd write `DataProfilingCustomMetricType.DATA_PROFILING_CUSTOM_METRIC_TYPE_AGGREGATE`, six redundant tokens visible at the call site. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** `DataProfilingCustomMetricType.{Aggregate, Derived, Drift}`. -- **Rationale:** Same as #3-#5. - -### 7. `CronSchedulePauseStatus` enum + `pauseStatus` field — `src/v1/model.ts:40-46,171` -- **Why weird:** A two-state on/off concept (`UNPAUSED` vs `PAUSED`) modelled as a five-token enum. Also: `pauseStatus` field on `CronSchedule` is read-only (per JSDoc), but nothing in the type marks it as such. The enum's name suggests it answers "what is the pause status?"; a boolean `paused: boolean` would model the same thing in one byte of cognitive load. -- **Category:** 2 (redundant enum prefix), 11 (trivially-enum where boolean suffices), 18 (long enum values), 6 (misleading: field is read-only but typing does not enforce). -- **Suggested name:** Collapse to `paused?: boolean` (output-only). Or rename enum to `PauseStatus.{Paused, Unpaused}`. -- **Rationale:** "Paused" is binary. The five-value `CRON_SCHEDULE_PAUSE_STATUS_*` enum is a protobuf-grade modelling that adds no information over a boolean. Sister packages (`jobs`, `alerts`) already use boolean `paused` fields. - -### 8. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:404-426,406,418` and 6 other request types +### 5. `CronSchedulePauseStatus` enum + `pauseStatus` field — `src/v1/model.ts:33-39,152` +- **Why weird:** A two-state on/off concept (`UNPAUSED` vs `PAUSED`) modelled as an enum. The `pauseStatus` field on `CronSchedule` is read-only (per JSDoc), but nothing in the type marks it as such. A boolean `paused: boolean` would model the same thing in one byte of cognitive load. +- **Category:** 11 (trivially-enum where boolean suffices), 6 (misleading: field is read-only but typing does not enforce). +- **Suggested name:** Collapse to `paused?: boolean` (output-only). +- **Rationale:** "Paused" is binary. The `CRON_SCHEDULE_PAUSE_STATUS_*` enum adds no information over a boolean. Sister packages (`jobs`, `alerts`) already use boolean `paused` fields. + +### 6. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:383-405,385,397` and 6 other request types - **Why weird:** `objectType` is a free-form `string` typed as the values `"schema"` or `"table"`. The discriminator is implicit in a `string`. The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("It is `schema_id` for `schema`, and `table_id` for `table`"). This is a stringly-typed sum type. Every single request and response in the package copies these two fields verbatim with copy-pasted JSDoc (43 lines of the same boilerplate per type, 6+ types). - **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). - **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string} | {kind: 'table', tableId: string}`. Or at minimum, type `objectType: 'schema' | 'table'`. - **Rationale:** TypeScript's strength is exhaustive discriminated unions. Leaving these as `string` defeats the type system and forces every caller to read the JSDoc. The current copy-paste of the same 40-line doc across `CancelRefreshRequest`, `DeleteMonitorRequest`, `DeleteRefreshRequest`, `GetMonitorRequest`, `GetRefreshRequest`, `ListRefreshRequest`, `Refresh`, `UpdateMonitorRequest`, `UpdateRefreshRequest` is a smoking gun for missing abstraction. -### 9. `Client` class — `src/v1/client.ts:55` +### 7. `Client` class — `src/v1/client.ts:55` - **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing two SDK packages (e.g., `@databricks/sdk-dataquality` and `@databricks/sdk-dataclassification`) cannot import both as `Client`. The package name is already in the import path, but in IDE go-to-symbol the name appears unqualified. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). - **Suggested name:** `DataQualityClient`. - **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but worth flagging. -### 10. `DataProfilingConfig.analysisConfig` discriminated-union — `src/v1/model.ts:184-200` +### 8. `DataProfilingConfig.analysisConfig` discriminated-union — `src/v1/model.ts:165-181` - **Why weird:** A field called `analysisConfig` is a three-arm union of `InferenceLogConfig` / `TimeSeriesConfig` / `SnapshotConfig`. The outer name (`analysisConfig`) and one arm's type (`SnapshotConfig`) end in the same suffix; the discriminator `$case` values are `inferenceLog` / `timeSeries` / `snapshot` — three different naming bases for three different concepts (`InferenceLog`, `TimeSeries`, `Snapshot`). The arm payloads are also `inferenceLog: InferenceLogConfig` (camelCase) — collision-prone with the discriminator string. - **Category:** 1 (vague — "analysis" vs "config" is the wrong abstraction), 12 (duplicate concept — `Config` appears twice), 17 (inconsistent verb tense — `InferenceLog` is a noun, `TimeSeries` is a noun, but the type name reads `Inference` + `Log` + `Config`). - **Suggested name:** Field: `analysis`. Type: keep `InferenceLogConfig` etc., or rename to `InferenceLogAnalysis`/`TimeSeriesAnalysis`/`SnapshotAnalysis` and call the field `analysis`. The TS-level discriminator should follow the type name: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. - **Rationale:** The current pattern forces callers to write `{analysisConfig: {$case: 'inferenceLog', inferenceLog: {...}}}` — three names for one nesting level. Discriminated unions read better when the discriminator value matches the arm payload's key precisely. -### 11. `DataProfilingConfig.skipBuiltinDashboard` — `src/v1/model.ts:223` +### 9. `DataProfilingConfig.skipBuiltinDashboard` — `src/v1/model.ts:204` - **Why weird:** Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. Positive form is clearer: `builtinDashboard: false` or `enableBuiltinDashboard: false`. Also: the verb `skip` (sound only on a transient action) does not capture that this is a persistent configuration. - **Category:** 6 (misleading — looks like a transient flag, is configuration), 13 (verb-tense — `skip` is action, but the field is state). - **Suggested name:** `disableBuiltinDashboard` (matches the existing negative semantics with a clearer verb), or invert to `createBuiltinDashboard: boolean` (default true). - **Rationale:** Boolean fields should be named in their positive form unless the negative form is the natural English phrasing. The "skip" prefix is a tell from migrating Go SDK semantics directly. -### 12. `DataProfilingConfig.assetsDir` — `src/v1/model.ts:182` +### 10. `DataProfilingConfig.assetsDir` — `src/v1/model.ts:163` - **Why weird:** `assets` is generic and undefined in this context (which assets? the monitor's? the dashboard's? the metric tables'?). `Dir` is an abbreviation. The JSDoc says "absolute path to a custom directory to store data-monitoring assets" — the type should advertise that. - **Category:** 1 (vague — `assets` of what?), 5 (cryptic abbreviation — `Dir` for `Directory`). - **Suggested name:** `assetsDirectory`, or better, `dataMonitoringAssetsPath`. - **Rationale:** Fields holding an absolute path should call out either "path" or "directory" without abbreviation. `assets` alone is too generic for a top-level field on a config that already has `monitoredTableName`, `profileMetricsTableName`, `driftMetricsTableName`, etc. -### 13. `Refresh.startTimeMs` / `Refresh.endTimeMs` — `src/v1/model.ts:479,481` +### 11. `Refresh.startTimeMs` / `Refresh.endTimeMs` — `src/v1/model.ts:442,444` - **Why weird:** `Ms` suffix to indicate "milliseconds since epoch", but it ignores the local convention of `Date` and `bigint` for UTC timestamps in modern TS. The field is `number` — JavaScript numbers lose precision beyond 2^53, but milliseconds-since-epoch fits, so the type itself is fine. The `Ms` suffix tells the reader to do arithmetic with `new Date(x)`; meanwhile `creation_time` / `last_updated` elsewhere in the SDK uses `bigint` with explicit precision. Inconsistent unit handling across the SDK. - **Category:** 5 (cryptic abbreviation — `Ms`), 14 (Go-style suffix — Go SDK uses `int64` with `Ms` everywhere; TS would use `Date`). - **Suggested name:** Leave on the wire as `start_time_ms` but on the TS side use `startedAt: Date` / `endedAt: Date` (transformed in unmarshal). - **Rationale:** Idiomatic TS uses `Date` for UTC instants. Forcing every caller to write `new Date(refresh.startTimeMs)` to display a timestamp is a paper cut. Other Databricks SDK packages have moved to this. (Generator-wide concern.) -### 14. `PercentNullValidityCheck` / `RangeValidityCheck` / `UniquenessValidityCheck` / `ValidityCheckConfiguration` — `src/v1/model.ts:440-501,552` -- **Why weird:** Four sibling types all carry the `ValidityCheck` suffix, but the wrapping discriminated-union container type is `ValidityCheckConfiguration` — adding yet another `Configuration` suffix on top. The wire-style discriminator names (`percentNullValidityCheck`, etc.) re-state the `ValidityCheck` suffix again, four times. Combined, the path `validityCheckConfigurations[0].checkType.$case === 'percentNullValidityCheck'` repeats "validity-check" three times within nine identifier-positions. -- **Category:** 8 (redundant suffix), 20 (type-suffix tautology), 18 (effectively-long enum-like discriminator strings). -- **Suggested name:** Drop `ValidityCheck` from each arm type → `PercentNullCheck` / `RangeCheck` / `UniquenessCheck`. Drop `Configuration` from container → `ValidityCheck` (the container). Discriminator: `kind: 'percentNull' | 'range' | 'uniqueness'`. -- **Rationale:** A `ValidityCheck.kind === 'range'` reads cleanly; the current form is "validity check configuration that has a check type whose case is range validity check" — five repetitions of "check". - ## Medium severity -### 15. `CancelRefreshResponse.refresh` JSDoc says "The refresh to cancel" — `src/v1/model.ts:144` +### 12. `CancelRefreshResponse.refresh` JSDoc says "The refresh to cancel" — `src/v1/model.ts:125` - **Why weird:** JSDoc on `CancelRefreshResponse.refresh` says "The refresh to cancel" but this is the response (the refresh that *was* cancelled). The doc verb tense contradicts the type name. Listed as naming because the field's contextual meaning is shaped by stale request-side docs. - **Category:** 13 (verb tense — "to cancel" is forward-looking; "cancelled" / "the cancelled refresh" is past-tense). - **Suggested name:** Field stays `refresh`; doc should read "The cancelled refresh." - **Rationale:** Documentation accuracy. The current text implies user intent rather than response state. -### 16. `DeleteRefreshRequest` doc-block typo "Request to delete a ronitor." — `src/v1/model.ts:289` +### 13. `DeleteRefreshRequest` doc-block typo "Request to delete a ronitor." — `src/v1/model.ts:270` - **Why weird:** Doc string typo "ronitor" (should be "monitor" or "refresh"). Affects discoverability via IDE tooltip search. Plus, the doc text says "monitor" but the type's purpose is deleting a refresh — meta-error. - **Category:** 6 (misleading — typo invites confusion about the type's purpose). - **Suggested name:** Doc should read "Request to delete a refresh." - **Rationale:** Generator-emitted typo. Listed because the doc is the first thing IDE users see. -### 17. `AnomalyDetectionConfig.anomalyDetectionWorkflowId` — `src/v1/model.ts:111` -- **Why weird:** Three repetitions of "anomaly detection" in one field path: `monitor.anomalyDetectionConfig.anomalyDetectionWorkflowId`. The outer type already says "anomaly detection". Inside it, the `workflowId` field could be just `workflowId`. -- **Category:** 7 (overly verbose), 8 (redundant suffix — `anomaly_detection_` inside `AnomalyDetectionConfig`). -- **Suggested name:** `workflowId`. -- **Rationale:** Repeating the parent type name in the field is a Go SDK habit (Go does not have struct-prefix scoping the way nested TS access does). - -### 18. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v1/model.ts:117` +### 14. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v1/model.ts:100` - **Why weird:** "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning ("full" alone is ambiguous — full path? full description?). Other Databricks SDK packages use `fullName` consistently for UC three-part names. - **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). - **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or `excludedTableFullyQualifiedNames` for absolute clarity. - **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary, so the proposal is the *minor* rename to `excludedTables` since the type (string[]) plus parent context (anomaly detection on UC objects) already implies fully-qualified. -### 19. `DataProfilingConfig.outputSchemaId` vs `monitoredTableName` vs `dashboardId` vs `warehouseId` — `src/v1/model.ts:177,229,243,228` +### 15. `DataProfilingConfig.outputSchemaId` vs `monitoredTableName` vs `dashboardId` vs `warehouseId` — `src/v1/model.ts:158,211,224,209` - **Why weird:** Identifier fields mix three reference styles in one type: `Id` (UC UUIDs: schema, dashboard, warehouse), `FullName` (table), and bare `Name` (output schema is by ID, but `assetsDir` is a path). The user reading `DataProfilingConfig` must remember that to set the *target* of the monitor you use `monitoredTableName` (a three-part name) but to set the *destination* of the metric tables you use `outputSchemaId` (a UUID). The pattern is wire-driven, not user-led. - **Category:** 17 (inconsistent reference styles), 19 (underspecified IDs — `outputSchemaId` is a UUID but `monitoredTableName` is a three-part qualified name). - **Suggested name:** Document both clearly in the JSDoc; consider a normalised pair `outputSchema: {id?: string, fullName?: string}` and `monitoredTable: {fullName: string}`. Or rename `monitoredTableName` to `monitoredTableFullName` (matches the JSDoc). - **Rationale:** UC has a stable convention: `*FullName` for three-part references, `*Id` for UUIDs. Following that convention everywhere reduces caller errors. -### 20. `DataProfilingConfig.warehouseId` and `DataProfilingConfig.effectiveWarehouseId` — `src/v1/model.ts:228,251` +### 16. `DataProfilingConfig.warehouseId` and `DataProfilingConfig.effectiveWarehouseId` — `src/v1/model.ts:209,232` - **Why weird:** Two parallel fields: user-provided `warehouseId` (optional input — falls back to "the first running warehouse" per doc) and `effectiveWarehouseId` (the warehouse actually used). Same shape as `dataclassification.autoTagConfigs` vs `effectiveAutoTagConfigs` (audited finding #6 in that package). The "effective" prefix is not marked output-only; a caller can set `effectiveWarehouseId` thinking it overrides `warehouseId`. Also: `effectiveWarehouseId` has no JSDoc trailer period ("The warehouse for dashboard creation" — missing period). - **Category:** 1 (vague — "effective" undermarked), 6 (misleading — output-only not enforced by typing), and (style nit) missing period. - **Suggested name:** Mark with JSDoc `@readonly`; or rename to `resolvedWarehouseId`. The minor doc-style miss (no period) is a CLAUDE.md rule violation: "Comments should always be proper sentences ending with a period." - **Rationale:** Same pattern as the `effective*` audit findings in other packages. Output-only state should be visually distinct from input state. -### 21. `DataProfilingConfig.monitoredTableName` — `src/v1/model.ts:230` +### 17. `DataProfilingConfig.monitoredTableName` — `src/v1/model.ts:211` - **Why weird:** Half-redundant. `DataProfilingConfig` is a per-table config; the table being configured is "the monitored table". JSDoc says "Format: `catalog.schema.table_name`" — confirming this is a UC three-part name. Calling it `monitoredTableName` is fine, but it's the only "monitored" field on the type, so the prefix gives little signal. Compare with `Monitor.objectId` which holds the same data conceptually. - **Category:** 1 (vague modifier — `monitored` adds nothing), 7 (overly verbose). - **Suggested name:** `tableFullName` (or rely on `Monitor.objectId` and remove the duplicate field entirely). - **Rationale:** The package already carries the target identity on `Monitor.objectId`. Duplicating it inside the config is a wire artifact, not a TS-level design choice. -### 22. `DataProfilingConfig.latestMonitorFailureMessage` — `src/v1/model.ts:234` +### 18. `DataProfilingConfig.latestMonitorFailureMessage` — `src/v1/model.ts:215` - **Why weird:** Five-word field name on a type whose name is `DataProfilingConfig` — "latest" + "monitor" + "failure" + "message" + field is on `Monitor`. "Monitor" appears in the path: `monitor.dataProfilingConfig.latestMonitorFailureMessage`. - **Category:** 7 (overly verbose), 8 (redundant suffix — `Monitor` is in the access path). - **Suggested name:** `latestFailureMessage`. - **Rationale:** Field path already gives the Monitor context; the field's own name should drop it. -### 23. `DataProfilingConfig.profileMetricsTableName` / `driftMetricsTableName` — `src/v1/model.ts:236,238` +### 19. `DataProfilingConfig.profileMetricsTableName` / `driftMetricsTableName` — `src/v1/model.ts:217,219` - **Why weird:** A pair where one is "profile metrics" and the other is "drift metrics", but the JSDoc is identical down to the punctuation ("Table that stores [profile|drift] metrics data. Format: `catalog.schema.table_name`."). The only diff between the field names is the leading noun, but the type name `DataProfilingConfig` already says "profiling" — so `profileMetricsTableName` reads slightly redundant. - **Category:** 7 (overly verbose), 17 (inconsistent — drop "profile" prefix to match `driftMetricsTableName` shape, or add a profile/drift prefix universally). - **Suggested name:** `profileMetricsTable` + `driftMetricsTable` (drop `Name` since wire is the same, and the type itself names a wire reference). - **Rationale:** Consistent prefixing within a paired feature. Listed medium because the rename is risky for back-compat reasons. -### 24. `DataProfilingConfig.slicingExprs` — `src/v1/model.ts:209` +### 20. `DataProfilingConfig.slicingExprs` — `src/v1/model.ts:190` - **Why weird:** `Exprs` abbreviation. The JSDoc is 8 lines explaining what `slicing_exprs` does; the field name reduces "expressions" to four characters of cryptic shorthand. Mixed-case: would be `slicingExprs` in TS but the wire field is `slicing_exprs` (Python-style). - **Category:** 5 (cryptic abbreviation — `Exprs` for `Expressions`). - **Suggested name:** `slicingExpressions` (or, given the doc explains they are "column expressions", `columnSlicingExpressions`). - **Rationale:** Length is rarely an issue in TS — modern IDEs autocomplete. Cryptic abbreviation, however, costs readability forever. -### 25. `DataProfilingConfig.customMetrics: DataProfilingCustomMetric[]` — `src/v1/model.ts:211` +### 21. `DataProfilingConfig.customMetrics: DataProfilingCustomMetric[]` — `src/v1/model.ts:192` - **Why weird:** Type name `DataProfilingCustomMetric` repeats the parent type's prefix (`DataProfiling`). Same field/type-name asymmetry called out in `dataclassification` (autoTag vs AutoTagging). Field `customMetrics` is fine; the type's prefix is the noise. - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `CustomMetric` (drop the `DataProfiling` prefix) — namespace via TS module if needed. - **Rationale:** Inside the `dataquality` package, "custom metric" can only mean one thing (a profiling metric definition). The `DataProfiling` prefix is dead context. -### 26. `DataProfilingCustomMetric.outputDataType: string` — `src/v1/model.ts:266` +### 22. `DataProfilingCustomMetric.outputDataType: string` — `src/v1/model.ts:247` - **Why weird:** Field name is `outputDataType` and JSDoc says "The output type of the custom metric." — the JSDoc drops `Data`. Field is typed `string`, no enum. Compare with `type: DataProfilingCustomMetricType` which is enum and is the *kind* of metric, not its *data type*. The reader must parse two `type` fields on the same type. - **Category:** 1 (vague — `outputDataType` vs `type`), 12 (duplicate concept — two `type`s), 17 (inconsistent — one is enum, one is string). - **Suggested name:** `outputSqlType` (since the value is a SQL type like `DOUBLE`), or `outputColumnType`. - **Rationale:** Two `type`-like fields on the same struct is a code-smell; making one specifically `Sql` or `Column` removes the ambiguity. -### 27. `DataProfilingStatus.DATA_PROFILING_STATUS_DELETE_PENDING` — `src/v1/model.ts:64` -- **Why weird:** Five-word enum value with the order "DELETE PENDING" (verb-then-state) — most languages would write `PENDING_DELETE` (state-modified-by-action). Also: this enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately. -- **Category:** 2 (redundant prefix), 12 (duplicate concept — `ERROR` and `FAILED`), 18 (long enum values). -- **Suggested name:** Members: `DataProfilingStatus.{Active, Pending, PendingDelete, Error, Failed}`. Or, if `ERROR`/`FAILED` are truly distinct, document the difference. -- **Rationale:** Sentinel naming conventions and the implicit duplicate of `ERROR`/`FAILED` both make this enum harder to reason about than it should be. +### 23. `DataProfilingStatus` has both `ERROR` and `FAILED` members; `DELETE_PENDING` word order — `src/v1/model.ts:57` +- **Why weird:** The enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately, with no JSDoc distinguishing them. Separately, `DELETE_PENDING` orders the tokens verb-then-state where most APIs write `PENDING_DELETE` (state-modified-by-action). +- **Category:** 12 (duplicate concept — `ERROR` and `FAILED`), 17 (inconsistent word order vs sibling `PENDING`). +- **Suggested name:** Either merge `ERROR` and `FAILED` into a single member, or document the difference in JSDoc. Reorder `DELETE_PENDING` to `PENDING_DELETE`. +- **Rationale:** The implicit duplicate of `ERROR`/`FAILED` makes this enum harder to reason about than it should be; two synonymous terminal states force callers to handle both. `PENDING_DELETE` mirrors the existing `PENDING` member's modifier-suffix shape. -### 28. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:420,425` +### 24. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` - **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #8). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). - **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). - **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. -### 29. `CronSchedule.quartzCronExpression` and `CronSchedule.timezoneId` — `src/v1/model.ts:163,169` +### 25. `CronSchedule.quartzCronExpression` and `CronSchedule.timezoneId` — `src/v1/model.ts:144,150` - **Why weird:** Field is qualified with `Quartz` (the scheduling library) leaking implementation detail; users do not need to know the schedule is parsed by Quartz on the server side. `timezoneId` collides with the IANA tz database vocabulary ("timezone ID" is not standard; "IANA timezone name" or just "timezone" is). - **Category:** 14 (implementation-detail leak — `Quartz` is a Java library reference), 5 (jargon — `timezoneId` vs the JS-standard `timeZone`). - **Suggested name:** `cronExpression` + `timezone`. - **Rationale:** The doc already says "Java timezone id"; the field name should be neutral. -### 30. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:437` -- **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. Same pattern as `AnomalyDetectionConfig.anomalyDetectionWorkflowId` (#17). The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. +### 26. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` +- **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. - **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). - **Suggested name:** Field: `onFailureOrTimeout` (matches doc), or `onFailure` (matches name; update doc). Type: `Destination` (drop the `Notification` prefix since the type is only used here). - **Rationale:** Field name and JSDoc should agree on whether timeouts are included. -### 31. `Refresh.message` — `src/v1/model.ts:477` +### 27. `Refresh.message` — `src/v1/model.ts:440` - **Why weird:** `message` is the most generic possible name on a `Refresh` object. JSDoc clarifies: "An optional message to give insight into the current state of the refresh (e.g. FAILURE messages)" — so this is really an error message or status message, not just any message. - **Category:** 1 (vague — `message` could be anything), 15 (generic field name). - **Suggested name:** `statusMessage` or `stateMessage`. - **Rationale:** Field on a typed object should be self-describing. +### 28. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` +- **Why weird:** Five sibling types all end in `Config`: `AnomalyDetectionConfig`, `DataProfilingConfig`, `InferenceLogConfig`, `TimeSeriesConfig`, `SnapshotConfig`. The `Config` suffix is a proto-style architectural label — it adds no semantic information once you know the type is a configuration record. The Go reference SDK uses these names because protobuf's `*Config` messages map 1:1 to Go structs, but TS does not need to carry that scaffolding. The leak is most visible at the call site `DataProfilingConfig.analysisConfig` (already flagged in #8) where three `Config`-suffixed arms nest inside a `Config`-suffixed field on a `Config`-suffixed type — triple `Config` nesting in a single access path. +- **Category:** proto-architectural-leak (repeated `Config` mid/suffix), 8 (redundant suffix), 12 (duplicate concept). +- **Suggested name:** Drop the `Config` suffix on the analysis-arm types: `InferenceLog`, `TimeSeries`, `Snapshot`. Keep `AnomalyDetectionConfig` / `DataProfilingConfig` as the top-level monitor configurations (they are genuinely "the config" of a `Monitor`). Or rename uniformly to `AnomalyDetectionSettings` / `DataProfilingSettings` and use `Analysis` for the arm types. +- **Rationale:** `Config` is generator-template noise inherited from `.proto` message names. Removing it produces names that read as the domain concept they represent (`InferenceLog`, `TimeSeries`, `Snapshot`) rather than as scaffolding. + ## Low severity -### 32. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 29. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's two list endpoints handle pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as `dataclassification` finding #19. -### 33. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +### 30. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataclassification` finding #15. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 34. `buildHttpRequest` — `src/v1/utils.ts:96` +### 31. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataclassification` finding #16; "build" suggests builder pattern, the function spreads literals. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the simpler reality. -### 35. `readAll` — `src/v1/utils.ts:40` +### 32. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Identical to `dataclassification` finding #20; "readAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing name for stream draining. -### 36. `HttpCallOptions` — `src/v1/utils.ts:15` +### 33. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataclassification` finding #21; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 37. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` +### 34. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` - **Why weird:** Same as `dataclassification` finding #22; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 38. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` +### 35. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` - **Why weird:** Same as `dataclassification` finding #24; variable named `call` of type `Call` repeated 11 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 39. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +### 36. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` - **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. @@ -255,20 +237,20 @@ ## Observations -### 40. Heavy boilerplate dominates the file -`model.ts` is 1252 lines for ~16 user-facing types; 575 lines (~46%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. +### 37. Heavy boilerplate dominates the file +`model.ts` is 1030 lines for ~16 user-facing types; ~520 lines (~50%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. -### 41. Action verbs in `Client` +### 38. Action verbs in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) -### 42. Acronym casing +### 39. Acronym casing Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. - **Category:** 3 (acronym casing). -### 43. Tense / nominalisation drift in enum naming +### 40. Tense / nominalisation drift in enum naming `AnomalyDetection` (gerund), `DataProfiling` (gerund), `DataClassification` (noun) — at the package boundary the gerund/noun choice tracks the API team's preference. Within `dataquality` the choice is consistent (both gerunds), good. -### 44. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types +### 41. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types Same shape as the `dataclassification` casing observation (#32 in that package): directory is one collapsed word, types are PascalCase compounded, wire path is kebab. SDK-wide convention question, not local. - **Category:** 3 (casing inconsistency). @@ -279,7 +261,6 @@ Same shape as the `dataclassification` casing observation (#32 in that package): - `inference log` — predictions + labels + (optional) probabilities for a deployed ML model, used to compute drift on inputs and accuracy on outputs. - `time series` — analysis configuration where rows have a timestamp column and are bucketed by `AggregationGranularity`. - `snapshot` — analysis configuration with no time dimension; the table is treated as a single snapshot. -- `validity check` — an input-data constraint check (null %, range, uniqueness) applied during anomaly detection. - `refresh` — a single run of the data-monitoring pipeline; produces metric rows in `profileMetricsTableName` / `driftMetricsTableName`. - `monitor` — the long-lived configuration entity (one per UC schema or table); contains either an `anomalyDetectionConfig` or a `dataProfilingConfig`. - `baseline table` — a separate table whose statistics drift is computed against (per `baselineTableName`). @@ -288,7 +269,11 @@ Same shape as the `dataclassification` casing observation (#32 in that package): - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. ## File coverage -- `src/v1/model.ts` (1252 lines): read fully. +- `src/v1/model.ts` (1030 lines): read fully. - `src/v1/client.ts` (515 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (47 lines): read fully. +- `src/v1/index.ts` (42 lines): read fully. + +## Fixed +- #14 `PercentNullValidityCheck` / `RangeValidityCheck` / `UniquenessValidityCheck` / `ValidityCheckConfiguration` (originally cited at `src/v1/model.ts:440-501,552`): Fixed in regeneration on 2026-05-20 — all validity-check types and the `ValidityCheckConfiguration` container have been removed from the model entirely. +- #17 `AnomalyDetectionConfig.anomalyDetectionWorkflowId` (originally cited at `src/v1/model.ts:111`): Fixed in regeneration on 2026-05-20 — field removed; `AnomalyDetectionConfig` now only carries `excludedTableFullNames`. diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index df1d886e..706a28d4 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -3,12 +3,12 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 25 +**Total weird names flagged:** 23 ## Summary | Severity | Count | | --- | --- | -| High | 7 | +| High | 5 | | Medium | 11 | | Low | 5 | | Observation | 2 | @@ -21,25 +21,13 @@ - **Suggested name:** `FailoverRequest` (the resource is unambiguous in this package) or `TriggerFailoverRequest` (more explicit verb). - **Rationale:** No other request in the package re-states the resource word inside its verb. The wire path is `…/failover`, so a single `Failover` in the type name is sufficient. -### 2. `FailoverFailoverGroupRequest_FailoverType.FAILOVER_TYPE_UNSPECIFIED` / `.FORCED` — `src/v1/model.ts:11-12` -- **Why weird:** (a) `FAILOVER_TYPE_UNSPECIFIED` redundantly re-states the enum name; (b) shipping an `UNSPECIFIED` sentinel is a proto-import — idiomatic TS uses `undefined` for "not set"; (c) the actual content is a single real value (`FORCED`), which makes a two-member enum with one sentinel look like a placeholder. -- **Category:** 2 (redundant enum prefix), 18 (long enum value). -- **Suggested name:** Drop `UNSPECIFIED`; keep `Forced` (or `Forced | Graceful` if the API ever grows a graceful mode). -- **Rationale:** `failoverType?: FailoverType | undefined` already encodes "not set". Same rationale as the proto enum guidance applied across the SDK. - -### 3. `FailoverGroup_State.STATE_UNSPECIFIED` — `src/v1/model.ts:18` -- **Why weird:** Redundant `STATE_` prefix on every value; `UNSPECIFIED` sentinel as in #2. The remaining values (`CREATING`, `CREATION_FAILED`, `INITIAL_REPLICATION`, `ACTIVE`, `FAILING_OVER`, `DELETING`, `FAILOVER_FAILED`, `DELETION_FAILED`) are reasonable, but the lone `STATE_UNSPECIFIED` is noise. -- **Category:** 2 (redundant enum prefix). -- **Suggested name:** Drop `STATE_UNSPECIFIED`. Keep the rest as-is or rename to PascalCase (`Creating`, `CreationFailed`, …) to match TS-style enum members. -- **Rationale:** Optional `state?: FailoverGroupState` encodes the unset case. PascalCase members align with TS conventions while leaving the SCREAMING_SNAKE_CASE wire values intact via the Zod schema. - -### 4. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,317` +### 2. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,326` - **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #25 — same issue applies in `utils.ts` field `url` on `StableUrl`.) +- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #23 — same issue applies in `utils.ts` field `url` on `StableUrl`.) -### 5. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` +### 3. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` - **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: - `effectivePrimaryRegion` — current truth; mutated by failover. - `initialPrimaryRegion` — create-only input; never returned. @@ -49,13 +37,13 @@ - **Suggested name:** Consider splitting: keep `primaryRegion` (effective) on `FailoverGroup`; lift `initialPrimaryRegion` into `CreateFailoverGroupRequest` as a sibling of `failoverGroup`; keep `targetPrimaryRegion` on `FailoverFailoverGroupRequest`. If the generator cannot split (since this mirrors a proto with output_only annotations), at minimum mark `initialPrimaryRegion` `@deprecated`-style write-only in JSDoc with a `WRITE-ONLY` tag. - **Rationale:** The current shape forces the user to read three different paragraphs to learn that the same-typed fields obey three different rules. This is the most user-hostile naming pattern in the file. -### 6. `replicationPoint: Temporal.Instant` — `src/v1/model.ts:144` +### 4. `replicationPoint: Temporal.Instant` — `src/v1/model.ts:144` - **Why weird:** `Point` is generic; this is a recovery-point timestamp (the data-loss bound aka RPO marker). The JSDoc says "The latest point in time to which data has been replicated", which is much clearer than the field name. A reader sees `failoverGroup.replicationPoint` and may guess "endpoint of replication" or "destination point". - **Category:** 1 (vague), 6 (misleading — `Point` suggests a location, not a time). - **Suggested name:** `replicationLagTime` / `lastReplicatedAt` / `recoveryPointTime` (the last matches Databricks DR docs and the well-known RPO term). - **Rationale:** Other timestamp fields on the same struct use the `…Time` suffix (`createTime`, `updateTime`). Consistency + clarity in one rename. -### 7. `replicateWorkspaceAssets` field on `WorkspaceSet` — `src/v1/model.ts:311` +### 5. `replicateWorkspaceAssets` field on `WorkspaceSet` — `src/v1/model.ts:320` - **Why weird:** Field documented as "Whether to enable control plane DR (notebooks, jobs, clusters, etc.) for this set." The field name says `replicateWorkspaceAssets` but the doc says "control plane DR" — those aren't synonyms. A user looking for "enable CPDR" will not find a `cpdr` field; a user looking for "replicate" will not realise this is the control-plane toggle vs the data-plane (UC) replication elsewhere on the parent. - **Category:** 6 (misleading — field name and doc disagree), 1 (vague — `workspaceAssets` is undefined jargon). - **Suggested name:** `enableControlPlaneReplication` (matches doc and matches the implied UCDR/CPDR split), or `replicateControlPlane`. @@ -63,67 +51,67 @@ ## Medium severity -### 8. `WorkspaceSet.name: string` (resource-name vs human-name ambiguity) — `src/v1/model.ts:301` +### 6. `WorkspaceSet.name: string` (resource-name vs human-name ambiguity) — `src/v1/model.ts:309` - **Why weird:** `name` on `WorkspaceSet` is documented only as "Resource name for this workspace set". `name` on `FailoverGroup` (line 120) is documented as a fully-qualified resource name (`accounts/{account_id}/failover-groups/{failover_group_id}`). `name` on `StableUrl` (line 252) is fully-qualified too. `name` on `LocationMapping` (line 227) is "Resource name for this location". A user can't tell from the field which `name`s are FQ resource names versus simple labels. - **Category:** 15 (generic field name losing meaning across types), 19 (under-specified identifier). - **Suggested name:** Where the value is FQ, prefer `resourceName`; where the value is a label, prefer `label` or `displayName`. Failing that, tighten every JSDoc to spell out the wire format like `FailoverGroup.name` does. - **Rationale:** The package has at least three different meanings for `name`. Searching IDE for `.name` in a `FailoverGroup` chain returns many hits with different semantics. -### 9. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:269` +### 7. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:278` - **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 131) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. - **Category:** 5 (cryptic abbreviation `Uc`), 8 (redundant `Uc` prefix inside Uc context), 17 (inconsistency — `unityCatalog` vs `Uc`). - **Suggested name:** `Catalog` (or `ReplicatedCatalog`), and field type `catalogs: Catalog[]`. - **Rationale:** `UcReplicationConfig.catalogs: UcCatalog[]` reads as "UC replication config's UC catalogs" — redundant. The full `unityCatalog` spelling is used adjacent in the file; either propagate that or drop the prefix entirely inside the UC-scoped type. -### 10. `UcReplicationConfig` — `src/v1/model.ts:275` +### 8. `UcReplicationConfig` — `src/v1/model.ts:284` - **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). -- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #11). +- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #9). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. -### 11. `unityCatalogAssets: UcReplicationConfig` — `src/v1/model.ts:131` -- **Why weird:** Field named `unityCatalogAssets` but the type is `UcReplicationConfig`. "Assets" doesn't appear in the type name. The type contains location mappings + catalogs + a workspace-set reference — none of which are commonly called "assets". The sibling `replicateWorkspaceAssets` (line 311) uses "assets" with a completely different meaning (control-plane objects vs Unity Catalog config). +### 9. `unityCatalogAssets: UcReplicationConfig` — `src/v1/model.ts:131` +- **Why weird:** Field named `unityCatalogAssets` but the type is `UcReplicationConfig`. "Assets" doesn't appear in the type name. The type contains location mappings + catalogs + a workspace-set reference — none of which are commonly called "assets". The sibling `replicateWorkspaceAssets` (line 320) uses "assets" with a completely different meaning (control-plane objects vs Unity Catalog config). - **Category:** 15 (generic word "assets" used in two different meanings within the file), 20 (type-suffix tautology since the field carries replication config of a `UcReplicationConfig`). - **Suggested name:** `unityCatalogReplication` or `unityCatalogConfig`. - **Rationale:** Field name should match the type's purpose; "assets" is a misleading umbrella here. -### 12. `WorkspaceSet.stableUrlNames: string[]` (with FQ-name semantics) — `src/v1/model.ts:317` +### 10. `WorkspaceSet.stableUrlNames: string[]` (with FQ-name semantics) — `src/v1/model.ts:326` - **Why weird:** Field is `string[]` of fully-qualified resource names (per JSDoc: `accounts/{account_id}/stable-urls/{stable_url_id}`). The name `stableUrlNames` implies a list of `StableUrl` objects' `name` field; the FQ-vs-id semantics are buried in the doc. - **Category:** 19 (under-specified identifier — strings that are actually FQ resource names), 6 (misleading singular/plural framing — these are references, not names). - **Suggested name:** `stableUrlRefs` or `stableUrlResourceNames` (matches the FQ semantics explicitly). - **Rationale:** Other places in the same SDK use `*Ref` or `*ResourceName` for FQ references; `*Names` is ambiguous (Could be display names? Could be IDs?). -### 13. `dataReplicationWorkspaceSet: string` — `src/v1/model.ts:284` +### 11. `dataReplicationWorkspaceSet: string` — `src/v1/model.ts:293` - **Why weird:** Long compound noun field of type `string`, semantics (a workspace-set reference by name? id? FQ?) hidden in JSDoc. The doc says "The workspace set whose workspaces will be used for data replication of all UC catalogs' underlying storage." — implying the value is a `WorkspaceSet.name`, but again the type is a bare `string`. - **Category:** 7 (overly verbose), 19 (under-specified id), 6 (string for a typed concept). - **Suggested name:** `dataReplicationWorkspaceSetName` or `dataReplicationWorkspaceSetRef`. Or split: `dataReplicationWorkspaceSet: { name: string }` for symmetry with the rest of the model. - **Rationale:** Within `UcReplicationConfig`, `locationMappings` is typed, `catalogs: UcCatalog[]` is typed, but `dataReplicationWorkspaceSet: string` is loose. Inconsistent typing across siblings. -### 14. `etag` field on multiple types — `src/v1/model.ts:78,106,138` +### 12. `etag` field on multiple types — `src/v1/model.ts:78,106,138` - **Why weird:** `etag` lowercased. Web/HTTP convention is `ETag` (capital E-Tag, RFC 9110 §8.8.3). The wire format here is `etag` (lowercase, per the Zod schema line 332). Mixed casing across the ecosystem; the lowercase here at least mirrors the wire, but a TS reader might expect `eTag` or `ETag`. - **Category:** 3 (acronym casing). - **Suggested name:** Keep `etag` for wire fidelity; document the choice in a top-level comment. (Or use `eTag` if the SDK style guide prefers JS-camelCase for acronyms.) - **Rationale:** Low-impact but flagged because the audit asks for casing inconsistencies. The Google TS style guide (loaded skill `google-ts-styleguide:ts-style-guide`) generally prefers camelCase for acronyms (so `etag` is actually fine). -### 15. `validateOnly: boolean` — `src/v1/model.ts:44,59` +### 13. `validateOnly: boolean` — `src/v1/model.ts:44,59` - **Why weird:** "ValidateOnly" is a generic flag pattern; doesn't say what is validated or what the side effect of the validation is. Same word used identically on `CreateFailoverGroupRequest` and `CreateStableUrlRequest`. Fine on its own but worth noting: there is no dryRun/preview field elsewhere, so a user familiar with `dryRun: boolean` convention may not search for `validateOnly`. - **Category:** 1 (vague), 6 (mildly misleading — "validate only" could imply the result is a validation report; here it's a side-effect suppressor). - **Suggested name:** `dryRun` (industry standard) or keep `validateOnly` with a tighter JSDoc. - **Rationale:** Two of the four Create-style APIs use this; `dryRun` is the common convention in Kubernetes/many DBR SDKs. -### 16. `parent` field on `Create*Request` / `List*Request` — `src/v1/model.ts:40,55,173,200` +### 14. `parent` field on `Create*Request` / `List*Request` — `src/v1/model.ts:40,55,173,200` - **Why weird:** Bare `parent` with format `accounts/{account_id}`. The literal word "parent" requires JSDoc to decode; idiomatic naming would be `account` or `accountId` or `parentResourceName`. - **Category:** 1 (vague), 19 (under-specified id). - **Suggested name:** `account` (since the format hard-codes `accounts/{account_id}`) or `parentResourceName`. - **Rationale:** "Parent" is proto AIP-132 jargon. SDK users speak in domain terms ("the account this group belongs to"). -### 17. `failoverGroupId` / `stableUrlId` client-provided suffix fields — `src/v1/model.ts:49,64` +### 15. `failoverGroupId` / `stableUrlId` client-provided suffix fields — `src/v1/model.ts:49,64` - **Why weird:** Field is a client-side hint that becomes part of the resource name; pattern is "if set, server uses it as the trailing identifier". JSDoc on `failoverGroupId` says: "Used to construct the resource name as `{parent}/failover-groups/{failover_group_id}`." Two ids floating around — the FQ `name` (server-formed) and this client suffix — invite confusion. - **Category:** 19 (under-specified identifier among multiple), 20 (type-suffix tautology — `failoverGroup.Id` in a `CreateFailoverGroupRequest`). - **Suggested name:** `requestedFailoverGroupId` / `requestedStableUrlId` to make it clear this is a suggestion, not the final resource id. Alternative: `customId` / `userProvidedId`. - **Rationale:** Once created, the FQ `name` is the canonical reference; `failoverGroupId` is a vestigial input. Names should reflect lifecycle. -### 18. `Client` class name — `src/v1/client.ts:52` +### 16. `Client` class name — `src/v1/client.ts:52` - **Why weird:** Plain `Client` is the maximally-generic name. Once imported, callers see `import { Client } from '@databricks/sdk-disasterrecovery/v1'` — fine if used qualified, but `new Client()` floating in user code is meaningless. Sibling packages all do the same per generator convention; flagging this once at the package level. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `DisasterRecoveryClient`. (Or rely on import aliases.) @@ -131,46 +119,46 @@ ## Low severity -### 19. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +### 17. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. -### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` +### 18. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` - **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Same as other packages in the audit. Flag once per package. -### 21. `flattenQueryParams` — `src/v1/utils.ts:123` +### 19. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (generator default) or document why it ships per-package. - **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. -### 22. `readAll` — `src/v1/utils.ts:40` +### 20. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToBuffer`. - **Rationale:** Internal helper. Skip if generated identically across all packages. -### 23. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + APIError lift). +### 21. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + ApiError lift). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). - **Rationale:** At the call site (`client.ts:104,111`), the two are visually similar; the more descriptive name disambiguates. ## Observations -### 24. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#19), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. +### 22. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#17), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. -### 25. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +### 23. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` Within this package: - `stableUrl`/`StableUrl` (PascalCase capital-then-lower). - `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). -- `URLSearchParams` (Web global, ALLCAPS in code). +- `URLSearchParams` (Web global, ALLCAPS in code, `client.ts:83`). Three different casings for two acronyms (URL/URI). The Web platform uses `URL` (ALLCAPS) globally; the TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) - **Category:** 3 (acronym casing). @@ -178,7 +166,7 @@ Three different casings for two acronyms (URL/URI). The Web platform uses `URL` - **DR** — Disaster Recovery. Encoded in the package name `disasterrecovery`. Mentioned once in a JSDoc on `replicateWorkspaceAssets` ("control plane DR"). - **UCDR** — Unity Catalog Disaster Recovery (UC data plane replication). Mentioned in JSDoc at `model.ts:113`. Not present as an identifier. - **CPDR** — Control Plane Disaster Recovery (notebooks, jobs, clusters, etc.). Mentioned in JSDoc at `model.ts:113,308`. Not present as an identifier — encoded only via `replicateWorkspaceAssets: boolean`. -- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #10). +- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #8). - **EA** — Early Access / Early Adoption? Mentioned in JSDoc on `WorkspaceSet.workspaceIds` (line 305) as "EA: exactly 2 workspaces (one per region)". Not decoded anywhere in the package. - **RPO** — Recovery Point Objective. Not explicitly named; `replicationPoint` (line 144) is effectively the RPO marker. - **RTO** — Recovery Time Objective. Not present in this package. @@ -189,7 +177,7 @@ Three different casings for two acronyms (URL/URI). The Web platform uses `URL` - **m2m** / **u2m** / **pat** / **oidc** / **iam** — not encountered in this package. ## File coverage -- `src/v1/model.ts` (608 lines): read fully. -- `src/v1/client.ts` (419 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (31 lines): read fully. +- `src/v1/model.ts` (620 lines): read fully. +- `src/v1/client.ts` (418 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (30 lines): read fully. diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md index 77869ef9..b0c8e008 100644 --- a/.agent/naming-audit/endpoints.md +++ b/.agent/naming-audit/endpoints.md @@ -1,7 +1,11 @@ # Naming Audit: `endpoints` (v1) -**Package:** `@databricks/sdk-endpoints` -**Path:** `/home/parth.bansal/sdk-js/packages/endpoints/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Package:** `@databricks/sdk-vectorsearch` (formerly `@databricks/sdk-endpoints`) +**Path:** `/home/parth.bansal/sdk-js/packages/vectorsearch/` **Version audited:** `v1` **Files audited:** - `src/v1/model.ts` @@ -10,11 +14,12 @@ - `src/v1/index.ts` This audit applies the 20 numbered concern categories from the audit -checklist plus a special section on the package name itself, which is -the single most problematic naming choice in the whole package. Each -finding lists the offending identifier(s), the category number, -severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete rename -suggestion. Findings are grouped by category. +checklist plus a special section on the package name itself. The +package was previously named `@databricks/sdk-endpoints`; in the +2026-05-20 regeneration the package was renamed to `@databricks/sdk-vectorsearch` +and absorbed the contents of the former `@databricks/sdk-indexes` +package. Many of the F0 findings about package ambiguity are now +fixed. Findings are grouped by category. --- @@ -24,54 +29,54 @@ suggestion. Findings are grouped by category. | Item | Value | | --------------- | ---------------------------------- | -| Package name | `@databricks/sdk-endpoints` | -| Directory | `packages/endpoints/` | +| Package name | `@databricks/sdk-vectorsearch` | +| Directory | `packages/vectorsearch/` | | Subpath export | `./v1` | -| REST base path | `/api/2.0/vector-search/endpoints` | -| Concept | Vector Search endpoints | +| REST base path | `/api/2.0/vector-search/endpoints` and `/indexes` | +| Concept | Vector Search endpoints and indexes | ### Enums (`model.ts`) | Name | Members | | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | -| `EndpointType` | `STORAGE_OPTIMIZED`, `STANDARD`, `STANDARD_ON_ORION` | +| `EndpointType` | `STORAGE_OPTIMIZED`, `STANDARD` | +| `IndexSubtype` | `VECTOR`, `FULL_TEXT`, `HYBRID` | +| `PipelineType` | `TRIGGERED`, `CONTINUOUS` | | `ScalingChangeState` | `SCALING_CHANGE_UNSPECIFIED`, `SCALING_CHANGE_APPLIED`, `SCALING_CHANGE_IN_PROGRESS` | -| `ThroughputChangeRequestState` | `CHANGE_SUCCESS`, `CHANGE_FAILED`, `CHANGE_REACHED_MINIMUM`, `CHANGE_REACHED_MAXIMUM`, `CHANGE_IN_PROGRESS`, `CHANGE_ADJUSTED` | -| `ThroughputPatchStatus` | `PATCH_ACCEPTED`, `PATCH_REJECTED`, `PATCH_FAILED` | +| `UpsertDeleteDataStatus` | `SUCCESS`, `PARTIAL_SUCCESS`, `FAILURE` | +| `VectorIndexType` | `DELTA_SYNC`, `DIRECT_ACCESS` | | `EndpointStatus_State` | `PROVISIONING`, `ONLINE`, `OFFLINE`, `RED_STATE`, `YELLOW_STATE`, `DELETED` | ### Interfaces (`model.ts`) -`AdjustedThroughputRequest`, `CreateEndpointRequest`, `CustomTag`, -`DeleteEndpointRequest`, `DeleteEndpointResponse`, `Endpoint`, -`EndpointScalingInfo`, `EndpointStatus`, `EndpointThroughputInfo`, -`GetEndpointRequest`, `ListEndpointRequest`, `ListEndpointResponse`, -`PatchEndpointBudgetPolicyRequest`, +`ColumnInfo`, `CreateEndpointRequest`, `CreateVectorIndexRequest`, +`CustomTag`, `DeleteDataVectorIndexRequest`, `DeleteDataVectorIndexResponse`, +`DeleteEndpointRequest`, `DeleteEndpointResponse`, `DeleteVectorIndexRequest`, +`DeleteVectorIndexResponse`, `DeltaSyncVectorIndexSpec`, +`DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`, +`EmbeddingSourceColumn`, `EmbeddingVectorColumn`, `Endpoint`, +`EndpointScalingInfo`, `EndpointStatus`, `GetEndpointRequest`, +`GetVectorIndexRequest`, `ListEndpointRequest`, `ListEndpointResponse`, +`ListValue`, `ListVectorIndexRequest`, `ListVectorIndexResponse`, +`MapStringValueEntry`, `MiniVectorIndex`, `PatchEndpointBudgetPolicyRequest`, `PatchEndpointBudgetPolicyResponse`, `PatchEndpointRequest`, -`PatchEndpointThroughputRequest`, `PatchEndpointThroughputResponse`. - -### Schemas (`model.ts`) - -`unmarshalAdjustedThroughputRequestSchema`, -`unmarshalCustomTagSchema`, -`unmarshalDeleteEndpointResponseSchema`, -`unmarshalEndpointSchema`, -`unmarshalEndpointScalingInfoSchema`, -`unmarshalEndpointStatusSchema`, -`unmarshalEndpointThroughputInfoSchema`, -`unmarshalListEndpointResponseSchema`, -`unmarshalPatchEndpointBudgetPolicyResponseSchema`, -`unmarshalPatchEndpointThroughputResponseSchema`, -`marshalCreateEndpointRequestSchema`, -`marshalPatchEndpointBudgetPolicyRequestSchema`, -`marshalPatchEndpointRequestSchema`, -`marshalPatchEndpointThroughputRequestSchema`. +`QueryVectorIndexNextPageRequest`, `QueryVectorIndexRequest`, +`QueryVectorIndexResponse`, `RerankerConfig`, +`RerankerConfig_RerankerParameters`, `ResultData`, `ResultManifest`, +`ScanVectorIndexRequest`, `ScanVectorIndexResponse`, `Struct`, +`SyncVectorIndexRequest`, `SyncVectorIndexResponse`, +`UpsertDataVectorIndexRequest`, `UpsertDataVectorIndexResponse`, +`UpsertDeleteDataResult`, `Value`, `VectorIndex`, `VectorIndexStatus`. ### Client methods (`client.ts`) -`createEndpoint`, `createEndpointWaiter`, `deleteEndpoint`, -`getEndpoint`, `listEndpoint`, `listEndpointIter`, `patchEndpoint`, -`patchEndpointBudgetPolicy`, `patchEndpointThroughput`. +`createEndpoint`, `createEndpointWaiter`, `createVectorIndex`, +`deleteDataVectorIndex`, `deleteEndpoint`, `deleteVectorIndex`, +`getEndpoint`, `getVectorIndex`, `listEndpoint`, `listEndpointIter`, +`listVectorIndex`, `listVectorIndexIter`, `patchEndpoint`, +`patchEndpointBudgetPolicy`, `queryVectorIndex`, +`queryVectorIndexNextPage`, `scanVectorIndex`, `syncVectorIndex`, +`upsertDataVectorIndex`. ### Client classes (`client.ts`) @@ -88,62 +93,23 @@ suggestion. Findings are grouped by category. --- -## F0 — Package-level: the word "endpoint" is dangerously overloaded - -This is the single most important finding and applies to every other -finding below. Reproducing it once up front avoids re-stating it in -each category. - -### F0.1 — Package name `@databricks/sdk-endpoints` is ambiguous to the point of being misleading (HIGH, blocking) -- **Where:** `package.json:2`, the directory name - `packages/endpoints/`, every public export, and every type alias. -- **Why flagged:** "Endpoint" is one of the most overloaded nouns in - the Databricks API surface. Concrete evidence from this monorepo: - - `packages/warehouses/src/v1` exports `EndpointSecurityPolicy`, - `EndpointSpotInstancePolicy`, `EndpointState` - — SQL Warehouses are internally called "endpoints" (and SQL endpoint - is a legacy term for warehouse). - - `packages/modelservingmanagement/src/v1` exports - `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel`, - with waiters `CreateInferenceEndpointWaiter`, - `PutInferenceEndpointConfigWaiter`, etc. — model serving uses - "endpoint" as its primary noun. - - **This** package: vector-search endpoints, evidenced by - `model.ts:78` ("Name of the vector search endpoint"), - `client.ts:86` URL `/api/2.0/vector-search/endpoints`, - `client.ts:118` JSDoc "Delete a vector search endpoint." - An import line `import {Client, Endpoint} from - '@databricks/sdk-endpoints'` gives the reader zero clue which of - the three concepts is being touched. Autocompletion across the - monorepo conflates them. -- **Suggestion:** Rename the package to one of: - - `@databricks/sdk-vectorsearchendpoints` (long, unambiguous, - matches the REST path), or - - `@databricks/sdk-vectorsearch` (short, matches the product - name; the package can hold both endpoints and indexes in - future), or - - `@databricks/sdk-vector-endpoints`. - Pair the rename with `Endpoint` → `VectorSearchEndpoint` in - `model.ts` (see F1.1). This single rename is the highest-leverage - fix in the audit. - -### F0.2 — Directory name lacks any "vector"/"search" qualifier (HIGH) -- **Where:** `/home/parth.bansal/sdk-js/packages/endpoints/`. -- **Why flagged:** Same root cause as F0.1. A monorepo `grep -r - endpoint` over the repo will surface this package alongside the - serving and warehouse packages with no visual differentiation. -- **Suggestion:** Rename to `packages/vectorsearchendpoints/` - (matches `cleanroomtaskruns`, `oauthpublishedapp` flat style) or - `packages/vectorsearch/` if the package will grow. - -### F0.3 — Companion package `indexes` is also under-qualified (LOW, cross-package) -- **Where:** `packages/indexes/` exports `Client`, `MiniVectorIndex`, - `VectorIndex`, `ListVectorIndexResponse`, etc. -- **Why flagged:** "Index" alone is even more generic than "endpoint" - in software. The contents make clear it is vector-search, but the - package name does not. Same fix as F0.1. -- **Suggestion:** Cross-cutting; align with whatever decision is - taken for `endpoints`. +## F0 — Package-level: "endpoint" is dangerously overloaded + +The package rename to `@databricks/sdk-vectorsearch` resolved much of +the ambiguity called out in the original audit. Some residual concerns +remain about the unqualified `Endpoint` type name. + +### F0.1 — `Endpoint` type still unqualified inside the package (MEDIUM) +- **Where:** `model.ts:274`, `index.ts:31`. +- **Why flagged:** The package rename to `vectorsearch` qualifies the + package identity, but the exported type is still `Endpoint`. A + consumer who imports + `import {Endpoint} from '@databricks/sdk-vectorsearch'` and then + passes it into a function `process(e: Endpoint)` loses the + package-level qualification once the import is destructured. +- **Suggestion:** Rename `Endpoint` → `VectorSearchEndpoint` to mirror + `modelserving.InferenceEndpoint`. Slightly verbose but eliminates + the ambiguity at the type level. --- @@ -151,46 +117,46 @@ each category. ### 1. Vague / generic names -#### F1.1 — `Endpoint` type name (HIGH) -- **Where:** `model.ts:111`, `index.ts:19`, return type of +#### F1.1 — `Endpoint` type name (MEDIUM) +- **Where:** `model.ts:274`, `index.ts:31`, return type of `createEndpoint`, `getEndpoint`, `patchEndpoint`, items of `listEndpointIter`. - **Why flagged:** "Endpoint" alone is one of the most generic nouns - in REST APIs (every URL is an endpoint). Combined with F0, a user + in REST APIs (every URL is an endpoint). Combined with F0.1, a user reading `function process(e: Endpoint)` cannot tell whether this is a vector-search endpoint, a model-serving endpoint, or a SQL warehouse endpoint. - **Suggestion:** Rename to `VectorSearchEndpoint`. Mirrors - `modelservingmanagement.InferenceEndpoint` and provides parity + `modelserving.InferenceEndpoint` and provides parity across packages. All sibling type names (`EndpointType`, - `EndpointStatus`, `EndpointThroughputInfo`, `EndpointScalingInfo`) - follow: `VectorSearchEndpointType`, etc. — long, but unambiguous. + `EndpointStatus`, `EndpointScalingInfo`) follow. -#### F1.2 — `EndpointType` enum, `EndpointStatus` interface (HIGH) -- **Where:** `model.ts:6, 153`; `index.ts:7, 20`. +#### F1.2 — `EndpointType` enum, `EndpointStatus` interface (MEDIUM) +- **Where:** `model.ts:18, 314`; `index.ts:6, 33`. - **Why flagged:** Same generic-noun problem as F1.1. `Endpoint*` symbols collide across the monorepo (cf. `warehouses.EndpointState`, - `modelservingmanagement.InferenceEndpoint`). + `modelserving.InferenceEndpoint`). - **Suggestion:** Qualify with `VectorSearch` prefix — `VectorSearchEndpointType`, `VectorSearchEndpointStatus`. Or move these into a namespace `VectorSearchEndpoint.Status` / `VectorSearchEndpoint.Type`. #### F1.3 — `Client` class name (MEDIUM, cross-cutting) -- **Where:** `client.ts:56`, `index.ts:3`. +- **Where:** `client.ts:85`, `index.ts:3`. - **Why flagged:** Every package in this SDK exports a `Client`. - `import {Client} from '@databricks/sdk-endpoints'` is unqualified - and routinely needs `import {Client as VectorSearchEndpointsClient}` + `import {Client} from '@databricks/sdk-vectorsearch'` is unqualified + and routinely needs `import {Client as VectorSearchClient}` at the call site. Project-wide pattern. - **Suggestion:** Keep `Client` and document the per-package - alias convention, or rename to `VectorSearchEndpointsClient` + alias convention, or rename to `VectorSearchClient` consistently across packages. Cross-cutting decision. #### F1.4 — `name` field everywhere (MEDIUM) -- **Where:** `model.ts:79, 105, 113, 184, 189, 201, 214, 234`; +- **Where:** `model.ts:91, 98, 115, 139, 147, 161, 169, 254, 269, 276, + 323, 328, 339, 378, 403, 416, 427, 436, 512, 534, 542, 574`; `client.ts` throughout. - **Why flagged:** `name` is one of the most generic identifiers - possible. JSDoc explains "Name of the vector search endpoint", but + possible. JSDoc explains "Name of the AI Search endpoint", but the field name alone gives no domain hint. Worse, this `name` is used as the *path-segment identifier* (`/endpoints/${req.name ?? ''}`) — i.e. it is functionally an ID. Other packages call this @@ -202,7 +168,8 @@ each category. — see F12.3 / F19.2 for the duplicate-identifier problem. #### F1.5 — `req` parameter name on every client method (LOW, Go-ism) -- **Where:** `client.ts:83, 108, 120, 145, 170, 200, 218, 244, 276`. +- **Where:** `client.ts:112, 137, 149, 175, 209, 234, 259, 284, 318, + 348, 366, 399, 417, 443, 475, 501, 530, 556, 582`. - **Why flagged:** `req` is a Go-ism (see category 14). It is also generic — a reader has to look at the type to know what the request is. @@ -210,26 +177,19 @@ each category. `options` (which is spelled out). See F14.1. #### F1.6 — `state` field on `EndpointScalingInfo` and `EndpointStatus` (LOW) -- **Where:** `model.ts:144, 155`. +- **Where:** `model.ts:305, 316`. - **Why flagged:** `state` is generic. Disambiguated by container type, but `scalingState` / `endpointState` would be clearer in isolation. - **Suggestion:** Acceptable as-is given the containing type; leave. -#### F1.7 — `message` field on `EndpointStatus` and `PatchEndpointThroughputResponse` (LOW) -- **Where:** `model.ts:157, 259`. +#### F1.7 — `message` field on `EndpointStatus` and `VectorIndexStatus` (LOW) +- **Where:** `model.ts:318, 599`. - **Why flagged:** Generic. Compare `statusMessage`, `errorMessage`. - **Suggestion:** Add JSDoc clarifying purpose; rename optional. -#### F1.8 — `status` field on `PatchEndpointThroughputResponse` (LOW) -- **Where:** `model.ts:257`. -- **Why flagged:** Field is `status: ThroughputPatchStatus`. Generic - field name typed against a non-generic enum. Reads as "status" with - three layers of "status". -- **Suggestion:** `patchStatus` or `result`. See F20.4. - -#### F1.9 — `Call`, `Options` (imported, cross-package) (acceptable) +#### F1.8 — `Call`, `Options` (imported, cross-package) (acceptable) - **Where:** `utils.ts:3-5`, `client.ts:4-5`. - These come from `@databricks/sdk-core/api`. Generic but intentional. Out of scope for this package's audit. @@ -238,55 +198,8 @@ each category. ### 2. Redundant enum prefixes -#### F2.1 — `ScalingChangeState.SCALING_CHANGE_*` (HIGH) -- **Where:** `model.ts:13-17`. - ```ts - export enum ScalingChangeState { - SCALING_CHANGE_UNSPECIFIED = 'SCALING_CHANGE_UNSPECIFIED', - SCALING_CHANGE_APPLIED = 'SCALING_CHANGE_APPLIED', - SCALING_CHANGE_IN_PROGRESS = 'SCALING_CHANGE_IN_PROGRESS', - } - ``` -- **Why flagged:** Every member prefixes `SCALING_CHANGE_` — the - exact enum name. Reads - `ScalingChangeState.SCALING_CHANGE_APPLIED`, which says - "scaling change" twice. Compare `Color.RED_COLOR`. -- **Suggestion:** Drop the prefix on the *TS* identifier; keep the - wire string. The TS-idiomatic shape is: - ```ts - export enum ScalingChangeState { - UNSPECIFIED = 'SCALING_CHANGE_UNSPECIFIED', - APPLIED = 'SCALING_CHANGE_APPLIED', - IN_PROGRESS = 'SCALING_CHANGE_IN_PROGRESS', - } - ``` - Wire compatibility preserved; TS readability massively improved. - Generator-level decision. - -#### F2.2 — `ThroughputChangeRequestState.CHANGE_*` (HIGH) -- **Where:** `model.ts:20-33`. - ```ts - CHANGE_SUCCESS, CHANGE_FAILED, CHANGE_REACHED_MINIMUM, - CHANGE_REACHED_MAXIMUM, CHANGE_IN_PROGRESS, CHANGE_ADJUSTED - ``` -- **Why flagged:** Every member starts with `CHANGE_`. The enum is - `ThroughputChangeRequestState` so `CHANGE_` is redundant. -- **Suggestion:** Same as F2.1 — keep wire strings, strip the - `CHANGE_` prefix on the TS identifier: - `SUCCESS`, `FAILED`, `REACHED_MINIMUM`, `REACHED_MAXIMUM`, - `IN_PROGRESS`, `ADJUSTED`. - -#### F2.3 — `ThroughputPatchStatus.PATCH_*` (HIGH) -- **Where:** `model.ts:36-43`. -- **Why flagged:** `PATCH_ACCEPTED`, `PATCH_REJECTED`, `PATCH_FAILED` - — every member prefixed with `PATCH_`, which is exactly the enum's - domain. Reads `ThroughputPatchStatus.PATCH_ACCEPTED` — - "patch status . patch accepted". -- **Suggestion:** Strip prefix: - `ACCEPTED`, `REJECTED`, `FAILED`. - -#### F2.4 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` (MEDIUM) -- **Where:** `model.ts:57-58`. +#### F2.1 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` (MEDIUM) +- **Where:** `model.ts:79-80`. - **Why flagged:** `_STATE` is redundant — the enum is already `EndpointStatus_State`. Reads `EndpointStatus_State.RED_STATE` — "endpoint status state . red state". Other members in the same @@ -297,50 +210,43 @@ each category. `YELLOW`. Otherwise, document the asymmetry. Worth fixing at the spec level. -#### F2.5 — `EndpointType.STANDARD_ON_ORION` (LOW) -- **Where:** `model.ts:10`. -- **Why flagged:** Not technically redundant, but `ON_ORION` is an - implementation-leak — the enum should describe *what the user - sees*, not *which infra backs it*. See F6.x. -- **Suggestion:** Discussed in F6.4. - --- ### 3. Acronym casing inconsistencies #### F3.1 — `Id` vs `ID` (acceptable, cross-cutting) -- **Where:** `model.ts:125, 131, 133, 199, 203, 207, 209`. +- **Where:** `model.ts:102, 104, 188, 220, 288, 294, 296, 405, 409, + 411`. - **Why flagged:** Field uses `id`, `budgetPolicyId`, - `effectiveBudgetPolicyId`, `usagePolicyId` — consistent lower-camel - `Id`. This matches the SDK-wide convention. + `effectiveBudgetPolicyId`, `usagePolicyId`, `pipelineId` — consistent + lower-camel `Id`. This matches the SDK-wide convention. - **Suggestion:** No change. -#### F3.2 — `QPS` rendered as `Qps` (HIGH) +#### F3.2 — `QPS` rendered as `Qps` (MEDIUM) - **Where:** - - `CreateEndpointRequest.targetQps` (`model.ts:93`) - - `EndpointScalingInfo.requestedTargetQps` (`model.ts:149`) - - `PatchEndpointRequest.targetQps` (`model.ts:229`) + - `CreateEndpointRequest.targetQps` (`model.ts:110`) + - `EndpointScalingInfo.requestedTargetQps` (`model.ts:310`) + - `PatchEndpointRequest.targetQps` (`model.ts:421`) - **Why flagged:** "QPS" (queries per second) is a TLA. The SDK applies "first letter cap, rest lower" for camelCase — so `Qps` - here. But the wire form is `target_qps` (all-lower), Go SDK uses - `TargetQps`, the JSDoc and comments mix "QPS" (uppercase) and - "qps". This SDK has a precedent: `URL`/`url` is lowercase, - `HTTP`/`http` matches casing context (`HttpClient`, `HttpRequest`), - `id` is lowercase. So `Qps` is consistent with `Http`/`Url` + here. The JSDoc uses "QPS" (uppercase) and the wire form is + `target_qps`. So `Qps` is consistent with `Http`/`Url` casing for acronyms; flag is only against the JSDoc/comment mix. - **Suggestion:** Standardize comments to use `QPS` consistently when the prose is talking about the term, and `targetQps` for the TS identifier. Or rename to `targetQueriesPerSecond` (verbose but - self-documenting). See also F5.x. + self-documenting). -#### F3.3 — `CPU` rendered in JSDoc as "(total CPU)" (acceptable) -- **Where:** `model.ts:69, 162, 165, 235`. -- JSDoc only; no identifier impact. Fine. - -#### F3.4 — `URL` / `Url` (acceptable for this file) -- `client.ts:86, 123, 148, 174, 179, 221, 247, 279` uses lowercase +#### F3.3 — `URL` / `Url` (acceptable for this file) +- `client.ts:115, 152, 178, 184, 212, 237, 262, 287, 296, 321, 327, + 369, 378, 420, 446, 478, 504, 533, 559, 585` uses lowercase `url` consistently. No casing inconsistency. +#### F3.4 — `JSON` rendered as `Json` (acceptable) +- **Where:** `model.ts:247, 452, 544`; `inputsJson`, `schemaJson`, + `filtersJson`. +- Matches SDK-wide convention; no change. + --- ### 4. Underscores in TS identifiers @@ -352,24 +258,29 @@ _None._ ### 5. Cryptic abbreviations #### F5.1 — `req` (LOW, Go-ism) -- **Where:** `client.ts:83, 108, 120, 145, 170, 200, 218, 244, 276`, - `client.ts:202, 212`. +- **Where:** `client.ts:112, 137, 149, 175, 209, 234, 259, 284, 318, + 348, 366, 399, 417, 443, 475, 501, 530, 556, 582` plus + `client.ts:351, 360, 402, 411`. - **Why flagged:** Already flagged under F1.5 / F14.1. #### F5.2 — `resp` / `respBody` (LOW, Go-ism) -- **Where:** `client.ts:88, 93, 98, 101, 124, 128, 134, 137, 149, - 154, 159, 162, 180, 184, 190, 193, 205, 209, 223, 228, 233, 236, - 252, 257, 262, 268, 280, 285, 289, 294, 300, 322, 363, 370`. +- **Where:** `client.ts:117, 122, 127, 130, 154, 159, 164, 167, 185, + 190, 195, 201, 213, 218, 223, 226, 238, 243, 248, 251, 263, 268, + 273, 276, 297, 302, 307, 310, 328, 333, 338, 341, 353, 379, 384, + 389, 392, 404, 422, 427, 432, 435, 451, 456, 461, 467, 480, 485, + 490, 493, 509, 514, 519, 522, 535, 540, 545, 548, 561, 566, 571, + 574, 587, 592, 597, 603, 625, 666`. - **Why flagged:** `response` is two extra characters and unambiguous. - **Suggestion:** `response`, `responseBody`. #### F5.3 — `pollResp` (LOW) -- **Where:** `client.ts:322, 329, 339, 363, 370`. +- **Where:** `client.ts:625, 632, 642, 666, 673`. - **Why flagged:** Same `resp` Go-ism inside the waiter. - **Suggestion:** `pollResponse`. #### F5.4 — `httpReq` (LOW) -- **Where:** `client.ts:92, 128, 153, 184, 227, 256, 288`. +- **Where:** `client.ts:121, 158, 189, 217, 242, 267, 301, 332, 383, + 426, 455, 484, 513, 539, 565, 591`. - **Why flagged:** `httpRequest` is clearer and matches the type `HttpRequest` exactly. - **Suggestion:** `httpRequest`. @@ -380,13 +291,13 @@ _None._ - **Suggestion:** `apiError`. #### F5.6 — `pkgJson` (LOW) -- **Where:** `client.ts:20, 50-52`. +- **Where:** `client.ts:20, 79-80`. - **Why flagged:** "pkg" abbreviation. `packageJson` is two extra characters and unambiguous. - **Suggestion:** `packageJson`. #### F5.7 — `msg` (LOW) -- **Where:** `client.ts:339-340`. +- **Where:** `client.ts:642-643`. ```ts const msg = pollResp.endpointStatus?.message ?? '(no message)'; throw new Error(`terminal state ${status}: ${msg}`); @@ -409,8 +320,8 @@ _None._ - **Suggestion:** Rename `opts → options` inside `executeHttpCall` for consistency; leave `acc`, `val`, `e` alone. -#### F5.9 — `info` in `client.ts:71-77` (LOW) -- **Where:** `client.ts:71-77`. +#### F5.9 — `info` in `client.ts:100-105` (LOW) +- **Where:** `client.ts:100-105`. ```ts let info = createDefault().with(PACKAGE_SEGMENT); ``` @@ -427,12 +338,12 @@ _None._ ### 6. Misleading names #### F6.1 — `Endpoint.name` is functionally the primary key (HIGH) -- **Where:** `model.ts:113`. -- **Why flagged:** The field is described as "Name of the vector - search endpoint" but used as the path-segment identifier in +- **Where:** `model.ts:276`. +- **Why flagged:** The field is described as "Name of the AI Search + endpoint" but used as the path-segment identifier in `getEndpoint`, `deleteEndpoint`, `patchEndpoint`, etc. - (`client.ts:123, 148, 221, 247, 279`). Also, `Endpoint` has both - `name` and `id` (line 125), with `id` documented as "Unique + (`client.ts:212, 262, 420, 446`). Also, `Endpoint` has both + `name` and `id` (line 288), with `id` documented as "Unique identifier of the endpoint" — so the type has *two* identifiers and only one of them ever shows up in URLs. - **Suggestion:** Document explicitly: "Used as the primary @@ -442,17 +353,17 @@ _None._ See F12.3 / F19.2. #### F6.2 — `numIndexes` reads as "number of *array* indexes" (MEDIUM) -- **Where:** `model.ts:129`. +- **Where:** `model.ts:292`. - **Why flagged:** In TS, "index" almost universally means a numeric position in an array. Here it means "number of vector-search indexes attached to this endpoint" — a domain term, not the data-structure term. - **Suggestion:** Rename `numIndexes → numVectorIndexes` (matches - `MiniVectorIndex` / `VectorIndex` in the sibling `indexes` - package). Even better: pluralize naturally, `vectorIndexCount`. + `MiniVectorIndex` / `VectorIndex` in the same package). Even + better: pluralize naturally, `vectorIndexCount`. #### F6.3 — `EndpointStatus_State.OFFLINE` as a *terminal failure* state (HIGH) -- **Where:** `model.ts:50`, `client.ts:338-341, 376-380`. +- **Where:** `model.ts:72`, `client.ts:641-644, 680-681`. ```ts case EndpointStatus_State.OFFLINE: { const msg = pollResp.endpointStatus?.message ?? '(no message)'; @@ -468,56 +379,32 @@ _None._ intent) or `TERMINATED`. Otherwise add a prominent JSDoc note on the enum value explaining the waiter contract. -#### F6.4 — `EndpointType.STANDARD_ON_ORION` leaks infra implementation (MEDIUM) -- **Where:** `model.ts:9-10`. -- **Why flagged:** "Orion" is an internal Databricks infrastructure - name; the JSDoc says "Standard endpoint backed by Orion - infrastructure with endpoint-scoped reconciliation." This is a - *user-visible* enum value that exposes internal architecture. If - Orion is renamed, this enum value cannot change without breaking - callers. -- **Suggestion:** Wire-protocol value; cannot rename in TS. Flag for - upstream API redesign — public enum members should describe user - semantics (e.g. `STANDARD_V2`), not internal infra. - -#### F6.5 — `minimalConcurrencyAllowed` vs "minimum concurrency" in JSDoc (LOW) -- **Where:** `model.ts:71-72, 168-169, 237-238`. -- **Why flagged:** Field uses `minimal` but the JSDoc says - "minimum". `minimal` is a different word — "the least possible" - vs `minimum` "the lower bound". For a lower-bound limit - `minimumConcurrencyAllowed` is the correct English word; "minimal - concurrency" suggests "barely any concurrency". -- **Suggestion:** Rename `minimalConcurrencyAllowed → - minimumConcurrencyAllowed`. Wire field is `minimal_concurrency_allowed` - (model.ts:271, 356) — needs a generator-level fix or remapping in - the marshaller. - -#### F6.6 — `Endpoint.creator` is a user *identifier*, not the user (LOW) -- **Where:** `model.ts:115`. JSDoc: "Creator of the endpoint". +#### F6.4 — `Endpoint.creator` is a user *identifier*, not the user (LOW) +- **Where:** `model.ts:278`. JSDoc: "Creator of the endpoint". - **Why flagged:** "Creator" suggests a `User` object; the field type is `string`. Compare `lastUpdatedUser` (also `string`). - **Suggestion:** `creatorUserName` or `creatorEmail`, depending on what the wire returns. Or `createdBy` (matches REST convention). -#### F6.7 — `lastUpdatedUser` vs `creator` asymmetry (LOW) -- **Where:** `model.ts:115, 123`. +#### F6.5 — `lastUpdatedUser` vs `creator` asymmetry (LOW) +- **Where:** `model.ts:278, 286`. - **Why flagged:** Two fields, both `string`, both identify a user, with different naming patterns: `creator` (noun) vs `lastUpdatedUser` (compound). Inconsistent. - **Suggestion:** `createdBy` and `updatedBy` (matches REST common practice) or `creator` and `lastUpdater`. Pick one form. -#### F6.8 — `flattenQueryParams` is exported but unused in this package (LOW) +#### F6.6 — `flattenQueryParams` is exported but unused in this package (LOW) - **Where:** `utils.ts:123-150`. -- **Why flagged:** The package's only list endpoint uses - `URLSearchParams.append` directly (`client.ts:175-177`). The - helper is dead in this package — same finding as in the `budgets` - audit. +- **Why flagged:** The package's list endpoints use + `URLSearchParams.append` directly (`client.ts:179-182, 322-325, + 370-376`). The helper is dead in this package — same finding as + in the `budgets` audit. - **Suggestion:** Move shared helpers to `@databricks/sdk-core` or delete from per-package `utils.ts`. Cross-cutting. -#### F6.9 — JSDoc `"Update an endpoint"` on `patchEndpoint` lacks the verb match (LOW) -- **Where:** `client.ts:216`. +#### F6.7 — JSDoc `"Update an endpoint"` on `patchEndpoint` lacks the verb match (LOW) +- **Where:** `client.ts:415`. - **Why flagged:** JSDoc says "Update", the method is `patchEndpoint`. Inconsistent verb. (See F17.1.) - **Suggestion:** Either rename the method or rewrite the JSDoc: @@ -527,10 +414,10 @@ _None._ ### 7. Overly verbose -#### F7.1 — `Endpoint` *would* be fine — but combined with package - rename, becomes `VectorSearchEndpoint` (HIGH) -- **Where:** `model.ts:111`, `index.ts:19`. -- **Why flagged:** Today `Endpoint` is too generic (F1.1). After the +#### F7.1 — `Endpoint` *would* be fine — but with package qualification + removed, becomes `VectorSearchEndpoint` (MEDIUM) +- **Where:** `model.ts:274`, `index.ts:31`. +- **Why flagged:** Today `Endpoint` is unqualified (F1.1). After the F0/F1 rename it becomes `VectorSearchEndpoint` — long but necessary. Worth noting as a deliberate tradeoff, not a bug. - **Suggestion:** Accept the verbosity; mitigate by aliasing at @@ -538,7 +425,7 @@ _None._ #### F7.2 — `PatchEndpointBudgetPolicyRequest`, `PatchEndpointBudgetPolicyResponse` (HIGH) -- **Where:** `model.ts:199, 206`, `index.ts:26-27`. +- **Where:** `model.ts:401, 408`, `index.ts:43-44`. - **Why flagged:** 32+ characters. Inside a method literally named `patchEndpointBudgetPolicy(...)`, the request type repeats every token. Compare typical TS SDK shape: @@ -547,45 +434,23 @@ _None._ token. The method belongs to a vector-search-endpoint client, so `PatchBudgetPolicyRequest` / `PatchBudgetPolicyResponse` is enough. -#### F7.3 — `PatchEndpointThroughputRequest`, - `PatchEndpointThroughputResponse` (HIGH) -- **Where:** `model.ts:232, 255`, `index.ts:28-30`. -- **Why flagged:** Same as F7.2. -- **Suggestion:** `PatchThroughputRequest` / - `PatchThroughputResponse`. - -#### F7.4 — Method names: `patchEndpointBudgetPolicy`, - `patchEndpointThroughput`, `createEndpoint`, `deleteEndpoint`, +#### F7.3 — Method names: `patchEndpointBudgetPolicy`, + `createEndpoint`, `deleteEndpoint`, `getEndpoint`, `listEndpoint`, `patchEndpoint` (MEDIUM) -- **Where:** `client.ts:82, 119, 144, 169, 217, 243, 275`. -- **Why flagged:** "Endpoint" repeats in every method name. The - containing class is *already* the endpoints client (or will be - after F0 rename — `VectorSearchEndpointsClient`). Compare typical - TS SDK shape: `endpoints.create(...)`, `endpoints.patchBudgetPolicy(...)`. -- **Suggestion:** `create`, `delete`, `get`, `list`, - `patch`, `patchBudgetPolicy`, `patchThroughput`. Cross-package - convention. - -#### F7.5 — `currentConcurrencyUtilizationPercentage` (HIGH) -- **Where:** `model.ts:166-167`, `model.ts:355, 366`. -- **Why flagged:** 39 characters. Three concept tokens - (concurrency + utilization + percentage). The "percentage" can be - inferred from the JSDoc unit (0-100). -- **Suggestion:** `concurrencyUtilization` plus JSDoc that documents - the unit. Or `concurrencyUtilizationPct` if the abbreviated form - is preferred. - -#### F7.6 — `EndpointThroughputInfo`, `EndpointScalingInfo` (LOW) -- **Where:** `model.ts:142, 161`. -- **Why flagged:** `Info` suffix is a generic filler word. The types - describe throughput state and scaling state, respectively. -- **Suggestion:** `EndpointThroughput`, `EndpointScaling`. Or align - with `EndpointStatus` (already there, no `Info`). - -#### F7.7 — `createEndpointWaiter` method (MEDIUM) -- **Where:** `client.ts:107-116`. +- **Where:** `client.ts:111, 208, 258, 317, 416, 442`. +- **Why flagged:** "Endpoint" repeats in every method name. Compare + typical TS SDK shape: `client.createEndpoint(...)`. Now that + the package contains both endpoints and indexes, the verbose form + is more justified — but the names could be split into nested + resource clients (`client.endpoints.create(...)`, + `client.indexes.create(...)`). +- **Suggestion:** Nested resource clients, or keep as-is given the + multi-resource scope of the package. Cross-package convention. + +#### F7.4 — `createEndpointWaiter` method (MEDIUM) +- **Where:** `client.ts:136-145`. - **Why flagged:** This method is `createEndpoint` + return-a-waiter. - All sibling SDKs (`warehouses`, `modelservingmanagement`) export + All sibling SDKs (`warehouses`, `modelserving`) export the waiter as a separate type and the create method returns it directly. Reads as `client.createEndpoint(...)` returning an `Endpoint`, then a second method `createEndpointWaiter(...)` @@ -598,14 +463,22 @@ _None._ type entirely. See F17.3. -#### F7.8 — `STILL_RUNNING` / `StillRunningError` (LOW) -- **Where:** `client.ts:54`. +#### F7.5 — `STILL_RUNNING` / `StillRunningError` (LOW) +- **Where:** `client.ts:83`. - **Why flagged:** Private error class used as a control-flow signal for `retryOn`. Three concepts in one name ("still" + "running" + "error"). It is essentially "not yet done". - **Suggestion:** Acceptable as-is; alternative `RetryablePendingError` or `NotYetDoneError`. +#### F7.6 — `QueryVectorIndexNextPageRequest` (LOW) +- **Where:** `model.ts:425`, `index.ts:46`. +- **Why flagged:** 30+ characters. Could be `QueryVectorIndexPageRequest` + or `QueryNextPageRequest`. +- **Suggestion:** `QueryNextPageRequest` keeps the meaning and drops + the redundant `VectorIndex` token (context: it's a vector-search + package). + --- ### 8. Redundant suffixes @@ -617,39 +490,44 @@ _None._ - **Suggestion:** No change. #### F8.2 — `EndpointType` enum tautology (LOW) -- **Where:** `model.ts:6`, `Endpoint.endpointType: EndpointType` - (`model.ts:121`). +- **Where:** `model.ts:18`, `Endpoint.endpointType: EndpointType` + (`model.ts:284`). - **Why flagged:** Three layers of "endpoint": `Endpoint` has a field `endpointType` typed as `EndpointType`. Reads as `endpoint.endpointType : EndpointType`. - **Suggestion:** Rename field `endpointType → type` (loses one redundancy, becomes `endpoint.type : EndpointType`). Wire field - is `endpoint_type` (`model.ts:299, 424`), so a remap is needed. + is `endpoint_type` (`model.ts:725, 1028`), so a remap is needed. See F20.1. #### F8.3 — `EndpointStatus` interface + `endpointStatus` field on `Endpoint` (LOW) -- **Where:** `model.ts:127, 153`. +- **Where:** `model.ts:290, 314`. - **Why flagged:** Same pattern as F8.2: `endpoint.endpointStatus : EndpointStatus`. - **Suggestion:** Rename field `endpointStatus → status`. Wire field is `endpoint_status` — generator-level remap. -#### F8.4 — `EndpointThroughputInfo` / `EndpointScalingInfo` `Info` suffix (LOW) -- See F7.6. - -#### F8.5 — `ThroughputChangeRequestState` (LOW) -- **Where:** `model.ts:20`. -- **Why flagged:** `Throughput` + `Change` + `Request` + `State` — - four concept tokens. `RequestState` is partially redundant with - `ChangeRequestState`. -- **Suggestion:** `ThroughputChangeState` (3 tokens) is enough. +#### F8.4 — `EndpointScalingInfo` `Info` suffix (LOW) +- **Where:** `model.ts:303`. +- **Why flagged:** `Info` suffix is a generic filler word. The type + describes scaling state. +- **Suggestion:** `EndpointScaling`. Or align with `EndpointStatus` + (already there, no `Info`). + +#### F8.5 — `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` (LOW) +- **Where:** `model.ts:175, 207`. +- **Why flagged:** Two types with the same prefix differing only by + `Request` suffix; the `Request` variant is the input shape, the + bare variant is the output. Asymmetric: most request-shape + duplicates in the codebase don't carry the suffix. +- **Suggestion:** Document the distinction in JSDoc. Acceptable. --- ### 9. Singular / plural mismatches #### F9.1 — `listEndpoint` method singular for a collection (HIGH) -- **Where:** `client.ts:169`. +- **Where:** `client.ts:317`. - **Why flagged:** Method returns `ListEndpointResponse` whose `endpoints` field is `Endpoint[]`. The method should be `listEndpoints` (plural). Same applies to its request type: @@ -660,44 +538,46 @@ _None._ consistent with the URL. #### F9.2 — `ListEndpointRequest` / `ListEndpointResponse` types (HIGH) -- **Where:** `model.ts:187, 192`. +- **Where:** `model.ts:338, 343`. - See F9.1. -#### F9.3 — `Endpoint.numIndexes` plural (acceptable) -- **Where:** `model.ts:129`. +#### F9.3 — `listVectorIndex` method singular for a collection (HIGH) +- **Where:** `client.ts:365`. +- **Why flagged:** Same issue as F9.1 — method returns a list of + indexes. Should be `listVectorIndexes`. +- **Suggestion:** Pluralize throughout: `listVectorIndexes`, + `ListVectorIndexesRequest`, `ListVectorIndexesResponse`. + +#### F9.4 — `ListVectorIndexRequest` / `ListVectorIndexResponse` types (HIGH) +- **Where:** `model.ts:355, 362`. +- See F9.3. + +#### F9.5 — `Endpoint.numIndexes` plural (acceptable) +- **Where:** `model.ts:292`. - Plural is correct for a count of indexes. -#### F9.4 — `Endpoint.customTags: CustomTag[]` plural (acceptable) -- **Where:** `model.ts:135`. +#### F9.6 — `Endpoint.customTags: CustomTag[]` plural (acceptable) +- **Where:** `model.ts:298`. - Plural is correct for an array. -#### F9.5 — `CreateEndpointRequest.numReplicas` vs - `PatchEndpointThroughputRequest.numReplicas` vs - `EndpointThroughputInfo.requestedNumReplicas` / - `currentNumReplicas` (acceptable) -- **Where:** `model.ts:87, 252, 177, 179`. -- Consistent use of `numReplicas` (plural) as a count. - --- ### 10. Reserved-word / built-in collisions #### F10.1 — `delete` method name (LOW) -- **Where:** `client.ts:119` (`deleteEndpoint`). +- **Where:** `client.ts:208` (`deleteEndpoint`). - **Why flagged:** TS allows `delete` as method name. `deleteEndpoint` - is unambiguous; flag would apply only if F7.4 renames it to bare - `delete` (then it would shadow the `delete` keyword visually but is - still legal). -- **Suggestion:** Acceptable; relevant only if F7.4 is applied. + is unambiguous; flag would apply only if renamed to bare `delete`. +- **Suggestion:** Acceptable. #### F10.2 — `status` field (LOW) -- **Where:** `model.ts:257`. +- **Where:** `model.ts:154, 394, 549, 590`. - **Why flagged:** `Response.status` collides with `Response.status` in the Fetch API. Mild shadowing concern in code review. -- **Suggestion:** See F1.8. +- **Suggestion:** Acceptable inside the type domain. #### F10.3 — `state` field (LOW) -- **Where:** `model.ts:144, 155`. +- **Where:** `model.ts:305, 316`. - **Why flagged:** No reserved-word collision. `state` is a popular React/Redux concept, but that is library-level not language-level. - **Suggestion:** Acceptable. @@ -714,96 +594,38 @@ _None._ ### 11. Empty / trivial wrapper types -#### F11.1 — `AdjustedThroughputRequest` exposed as a *response* - payload (MEDIUM) -- **Where:** `model.ts:68-75, 264`. -- **Why flagged:** Type name says "Request" (line 67 JSDoc: - "Adjusted throughput request parameters") but it appears in a - response field: `PatchEndpointThroughputResponse.adjustedRequest` - (line 264). This is OK semantically — it's the *request that was - applied after adjustment* — but a reader sees `AdjustedThroughputRequest` - in a *response* and double-takes. Borderline misleading. -- **Suggestion:** Either: - - Rename to `AdjustedThroughputParameters` (drop "Request"), or - - Rename to `AppliedThroughputAdjustment` (explicit), or - - Document the dual role prominently in JSDoc. +#### F11.1 — `DeleteEndpointResponse`, `DeleteVectorIndexResponse`, + `SyncVectorIndexResponse` empty (LOW) +- **Where:** `model.ts:165, 173, 538`. +- **Why flagged:** Empty `{}` types. Conventional placeholder for + REST endpoints that return an empty body. Useful for future + evolution. +- **Suggestion:** Acceptable. --- ### 12. Duplicate concepts -#### F12.1 — `numReplicas` in three different places (HIGH) -- **Where:** - - `CreateEndpointRequest.numReplicas` (`model.ts:87`) - - `PatchEndpointThroughputRequest.numReplicas` (`model.ts:252`) - - `EndpointThroughputInfo.requestedNumReplicas` (`model.ts:177`) - - `EndpointThroughputInfo.currentNumReplicas` (`model.ts:179`) -- **Why flagged:** Same conceptual field, different names depending - on context. `numReplicas` on create vs `requestedNumReplicas` - in info vs `currentNumReplicas` in info. The asymmetry is - intentional (request vs current vs target), but the naming pattern - is inconsistent — see F12.2. -- **Suggestion:** Standardize: input fields stay `numReplicas`; - state fields become `requestedReplicas` / `currentReplicas` (drop - the `Num` — see F14.x). - -#### F12.2 — `targetQps`, `requestedTargetQps`, - `replicationFactor`, `numReplicas` describe overlapping concepts (HIGH) -- **Where:** - - `CreateEndpointRequest.targetQps` (`model.ts:93`) - - `PatchEndpointRequest.replicationFactor` (`model.ts:224`) - - `PatchEndpointRequest.targetQps` (`model.ts:229`) - - `PatchEndpointThroughputRequest.numReplicas` (`model.ts:252`) - - `EndpointScalingInfo.requestedTargetQps` (`model.ts:149`) -- **Why flagged:** Three different ways to express how big the - endpoint should be: - - `targetQps` (queries per second; high-level intent) - - `replicationFactor` (low-level OpenSearch parameter) - - `numReplicas` (user-facing replica count) - - The JSDoc on `PatchEndpointRequest.replicationFactor` even says: - "This is the raw replication factor, not 'total data copies'. - For the user-facing replica count (which uses total-copies - semantics), see `PatchEndpointThroughputRequest.num_replicas`." - That cross-reference inside JSDoc is a strong smell — these are - three names for two distinct concepts, and the type system does - not enforce which goes where. -- **Suggestion:** API-shape concern. Consolidate at the spec level: - pick one of (qps, replicas) as the public dimension; demote - `replicationFactor` to "advanced" with a clearer name like - `openSearchReplicationFactor` (so the implementation leak is - explicit). - -#### F12.3 — `Endpoint.name` vs `Endpoint.id` (HIGH) -- **Where:** `model.ts:113, 125`. +#### F12.1 — `Endpoint.name` vs `Endpoint.id` (HIGH) +- **Where:** `model.ts:276, 288`. - **Why flagged:** Both fields are documented as identifiers - ("Name of the vector search endpoint" / "Unique identifier of the + ("Name of the AI Search endpoint" / "Unique identifier of the endpoint"). Every URL uses `name`, never `id`. Two identifiers for the same entity confuse users; see F1.4, F6.1, F19.2. - **Suggestion:** Document the distinction prominently (`name` = user-chosen URL-safe key, `id` = opaque GUID). Or collapse to one identifier at the API level. -#### F12.4 — `concurrency` (CPU) vs `numReplicas` vs `targetQps` mixed (MEDIUM) -- **Where:** `model.ts:69, 73, 87, 93, 162, 165, 168, 171, 177, - 235, 238, 240, 252`. -- **Why flagged:** Concurrency in `EndpointThroughputInfo` is "total - CPU"; replicas are "data copies including primary"; QPS is a - performance target. Three orthogonal dimensions, all related to - "how big the endpoint is". The terms are easy to confuse. -- **Suggestion:** API-shape concern. Add a single explainer JSDoc on - the `Endpoint` type explaining the relationship. - -#### F12.5 — `budgetPolicyId` vs `effectiveBudgetPolicyId` (LOW) -- **Where:** `model.ts:131, 133, 207, 209`. +#### F12.2 — `budgetPolicyId` vs `effectiveBudgetPolicyId` (LOW) +- **Where:** `model.ts:294, 296, 405, 409, 411`. - **Why flagged:** Two fields, same domain, distinguished by the word "effective". A reader needs JSDoc to know which is the request and which is the result of policy resolution. - **Suggestion:** Acceptable convention; JSDoc clarifies. Not a duplicate, just adjacent. -#### F12.6 — `usagePolicyId` vs `budgetPolicyId` (LOW) -- **Where:** `model.ts:83, 85`. +#### F12.3 — `usagePolicyId` vs `budgetPolicyId` (LOW) +- **Where:** `model.ts:102, 104`. - **Why flagged:** Two different policy IDs whose JSDoc says one will be replaced by the other ("usagePolicyId" — "to be applied once we've migrated to usage policies"). Transitional API — both @@ -811,8 +633,23 @@ _None._ - **Suggestion:** Acceptable transition; should be cleaned up post migration. -#### F12.7 — Per-method header construction duplicated (LOW, code style) -- **Where:** `client.ts:90, 126, 151, 182, 225, 254, 286`. +#### F12.4 — `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` + near-duplicate types (LOW) +- **Where:** `model.ts:175, 207`. +- **Why flagged:** The two types have an identical set of fields. + The split is purely for request vs response. +- **Suggestion:** Acceptable convention; document the asymmetry. + +#### F12.5 — `MiniVectorIndex` vs `VectorIndex` near-duplicate types (LOW) +- **Where:** `model.ts:376, 572`. +- **Why flagged:** Both types share identical fields. `MiniVectorIndex` + appears to be used in list responses for lighter weight payloads. +- **Suggestion:** Document the distinction in JSDoc. + +#### F12.6 — Per-method header construction duplicated (LOW, code style) +- **Where:** `client.ts:119-120, 156-157, 187-188, 215-216, 240-241, + 265-266, 299-300, 330-331, 381-382, 424-425, 453-454, 482-483, + 511-512, 537-538, 563-564, 589-590`. - **Why flagged:** Every method runs: ```ts const headers = new Headers(...); @@ -828,34 +665,35 @@ _None._ ### 13. Verb-tense inconsistency #### F13.1 — Method verbs (acceptable for CRUD) -- `create*`, `delete*`, `get*`, `list*`, `patch*` — all uniform +- `create*`, `delete*`, `get*`, `list*`, `patch*`, `query*`, + `scan*`, `sync*`, `upsert*` — all uniform imperative present. Good. #### F13.2 — `patch*` vs `update*` (MEDIUM) -- **Where:** Method `patchEndpoint` (`client.ts:217`), JSDoc says - "Update an endpoint" (`client.ts:216`). +- **Where:** Method `patchEndpoint` (`client.ts:416`), JSDoc says + "Update an endpoint" (`client.ts:415`). - **Why flagged:** REST verbs in the SDK are mixed. Most packages use `update*` (e.g. `updateBudgetConfiguration`); this package uses `patch*`. Both describe the same HTTP verb (`PATCH`) but with different SDK ergonomics. - **Suggestion:** Cross-package decision. If the SDK standardizes on `update`, rename to `updateEndpoint`, - `updateEndpointBudgetPolicy`, `updateEndpointThroughput`. If on - `patch`, fix the JSDoc to say "Patch". See F17.1. + `updateEndpointBudgetPolicy`. If on `patch`, fix the JSDoc to say + "Patch". See F17.1. #### F13.3 — `createEndpoint` / `createEndpointWaiter` overlap (MEDIUM) -- **Where:** `client.ts:82, 107`. +- **Where:** `client.ts:111, 136`. - **Why flagged:** Two methods with the same verb start; only one actually performs the create — the waiter version *calls* the create then wraps. Reader might think `createEndpointWaiter` is a *different* operation. -- **Suggestion:** See F7.7. Acceptable if the verb pattern is +- **Suggestion:** See F7.4. Acceptable if the verb pattern is applied consistently across the SDK; flag for cross-cutting decision. #### F13.4 — `creationTimestamp` / `lastUpdatedTimestamp` past-tense asymmetry (LOW) -- **Where:** `model.ts:117, 119`. +- **Where:** `model.ts:280, 282`. - **Why flagged:** "creation" (noun) vs "lastUpdated" (past participle). Not parallel. Other SDK packages use `createTime`/`updateTime` (noun-form) or `createdAt`/`updatedAt` @@ -877,9 +715,9 @@ _None._ - `e` in `utils.ts:76` - `httpReq` in `client.ts` - `apiErr` in `utils.ts:88` - - `pkgJson` in `client.ts:20, 50` + - `pkgJson` in `client.ts:20, 79-80` - `opts` in `utils.ts:30, 65-92` - - `msg` in `client.ts:339` + - `msg` in `client.ts:642` - **Why flagged:** All classic Go idioms ported verbatim. TS convention favors spelled-out names: `request`, `response`, `error`, `httpRequest`, `apiError`, `packageJson`, `options`, @@ -889,14 +727,14 @@ _None._ in the `budgets` audit. #### F14.2 — `for (;;)` infinite loop (acceptable) -- **Where:** `client.ts:204`, `utils.ts:48`. +- **Where:** `client.ts:352, 403`, `utils.ts:48`. - **Why flagged:** Style; this is a `for (;;)` Go-idiom (the Go form is `for { … }`). TS prefers `while (true)` or `do { … } while (…)`. But `for (;;)` is also legal and idiomatic in C-derived languages. - **Suggestion:** Acceptable; consistent within the SDK. #### F14.3 — `Waiter` suffix (Go-style) (MEDIUM) -- **Where:** `client.ts:107-116, 307`. Exported as +- **Where:** `client.ts:136-145, 610`. Exported as `CreateEndpointWaiter` (`index.ts:3`). - **Why flagged:** "Waiter" is an AWS SDK / Go SDK pattern. TS ecosystems more often expose a `Promise`-returning method (e.g. @@ -908,12 +746,13 @@ _None._ for parity with other Databricks SDKs (Go has Waiters; users porting may expect them). -#### F14.4 — `numIndexes`, `numReplicas` `num` prefix (LOW) -- **Where:** `model.ts:87, 129, 177, 179, 252`. +#### F14.4 — `numIndexes`, `numResults` `num` prefix (LOW) +- **Where:** `model.ts:292, 438, 513`. - **Why flagged:** `num` is shortened from "number of". TS often - uses the bare noun (`replicas`, `indexCount`) or `count` suffix. -- **Suggestion:** `replicaCount`, `indexCount` (more idiomatic). - Wire field is `num_replicas` — generator-level remap. + uses the bare noun (`indexCount`, `resultCount`) or `count` suffix. +- **Suggestion:** `indexCount`, `resultCount` (more idiomatic). + Wire fields are `num_indexes` / `num_results` — generator-level + remap. --- @@ -923,17 +762,18 @@ _None._ - See F1.4 / F6.1. #### F15.2 — `Endpoint.id` (LOW) -- **Where:** `model.ts:125`. +- **Where:** `model.ts:288`. - **Why flagged:** Bare `id` is the most generic identifier name possible. Acceptable inside the type domain — but only because the type is `Endpoint`. - **Suggestion:** Keep; the type context disambiguates. #### F15.3 — `state`, `status`, `message` (LOW) -- See F1.6, F1.7, F1.8. +- See F1.6, F1.7. -#### F15.4 — `key` / `value` on `CustomTag` (LOW) -- **Where:** `model.ts:98-100`. +#### F15.4 — `key` / `value` on `CustomTag` and + `MapStringValueEntry` (LOW) +- **Where:** `model.ts:139, 141, 371, 373`. - **Why flagged:** Generic; same finding as `BudgetConfigurationFilter_TagClause.key/value` in `budgets`. Wrapping type supplies context, but `tagKey` / `tagValue` would self-document. @@ -943,38 +783,25 @@ _None._ #### F15.5 — `req` parameter on every client method (HIGH) - See F1.5. -#### F15.6 — `concurrency` field (MEDIUM) -- **Where:** `model.ts:70, 236`. -- **Why flagged:** "Concurrency" alone is generic. JSDoc clarifies - "(total CPU) for the endpoint" but the field name doesn't. Compare - `currentConcurrency` / `requestedConcurrency` (descriptive) vs - bare `concurrency` (ambiguous). -- **Suggestion:** Document "total CPU" semantics in JSDoc explicitly; - consider `concurrencyCpu` or `totalCpu` rename. Or move CPU into - its own dimension. +#### F15.6 — `result` field on `QueryVectorIndexResponse`, + `UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse` + (LOW) +- **Where:** `model.ts:156, 475, 551`. +- **Why flagged:** Generic. Disambiguated by container type. +- **Suggestion:** Acceptable. + +#### F15.7 — `data` field on `ScanVectorIndexResponse` (LOW) +- **Where:** `model.ts:522`. +- **Why flagged:** `data` is generic. +- **Suggestion:** Acceptable in the response domain. --- ### 16. Field contradicting type domain -#### F16.1 — `AdjustedThroughputRequest` appears in a response (MEDIUM) -- See F11.1. - -#### F16.2 — `EndpointThroughputInfo.changeRequestState: - ThroughputChangeRequestState` (MEDIUM) -- **Where:** `model.ts:173`. -- **Why flagged:** The field name says "change request state"; the - enum is `ThroughputChangeRequestState`. The type is *not* a state - about *throughput change requests* abstractly — it's the state of - the most recent throughput change request for *this* endpoint. - Field name + type name both bury that scope. Compare a more - direct `lastThroughputChangeState`. -- **Suggestion:** Rename field to `lastChangeState` (drop redundant - "request"); or add JSDoc clarifying "Most recent" semantics. - -#### F16.3 — `state` on `EndpointScalingInfo` is a *change* state, not +#### F16.1 — `state` on `EndpointScalingInfo` is a *change* state, not a *scaling* state (LOW) -- **Where:** `model.ts:144`. +- **Where:** `model.ts:305`. - **Why flagged:** Field is `state: ScalingChangeState` — the field-on-type domain is "scaling info", but the field type is "scaling **change** state". JSDoc says "The current state of the @@ -983,9 +810,9 @@ _None._ - **Suggestion:** Rename field to `changeState` or `lastChangeState`. -#### F16.4 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` health +#### F16.2 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` health semantics (LOW) -- **Where:** `model.ts:57-58`. +- **Where:** `model.ts:79-80`. - **Why flagged:** These are health-color states, not lifecycle states. Lumping them with `PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED` (lifecycle states) in the same enum mixes two orthogonal @@ -1007,36 +834,28 @@ _None._ #### F17.3 — `createEndpoint` returns `Endpoint`, `createEndpointWaiter` returns `CreateEndpointWaiter` (MEDIUM) -- **Where:** `client.ts:82, 107`. -- See F7.7 / F13.3. +- **Where:** `client.ts:111, 136`. +- See F7.4 / F13.3. #### F17.4 — `wait` vs `done` on `CreateEndpointWaiter` (acceptable) -- **Where:** `client.ts:318, 362`. +- **Where:** `client.ts:621, 665`. - Both verbs are well-chosen. `wait` is blocking-until-terminal; `done` is a non-blocking check. Symmetric and clear. +#### F17.5 — `upsert*`, `scan*`, `sync*`, `query*` (acceptable) +- **Where:** `client.ts:529, 555, 474, 500, 581`. +- New action verbs from the index-side of the package (formerly + `indexes`). All are unambiguous and consistent. +- **Suggestion:** No change. + --- ### 18. Long enum values -#### F18.1 — `SCALING_CHANGE_IN_PROGRESS` (MEDIUM) -- **Where:** `model.ts:16`. 26 characters; mostly the redundant - `SCALING_CHANGE_` prefix (F2.1). -- **Suggestion:** With prefix stripped → `IN_PROGRESS` (11 chars). - -#### F18.2 — `SCALING_CHANGE_UNSPECIFIED` (MEDIUM) -- **Where:** `model.ts:14`. 26 characters; same root cause. -- **Suggestion:** With prefix stripped → `UNSPECIFIED` (11 chars). - -#### F18.3 — `CHANGE_REACHED_MINIMUM`, `CHANGE_REACHED_MAXIMUM` (MEDIUM) -- **Where:** `model.ts:26, 28`. 22 characters each. -- **Suggestion:** With prefix stripped → `REACHED_MINIMUM` / - `REACHED_MAXIMUM` (15 chars). - -#### F18.4 — `STORAGE_OPTIMIZED`, `STANDARD_ON_ORION` (LOW) -- 17 chars each; reasonable. `ON_ORION` is an infra leak (F6.4). +#### F18.1 — `STORAGE_OPTIMIZED` (LOW) +- 17 chars. Reasonable. -#### F18.5 — `PROVISIONING` (acceptable) +#### F18.2 — `PROVISIONING` (acceptable) - 12 chars. Standard. --- @@ -1047,20 +866,24 @@ _None._ - See F15.2. Bare `id` inside `Endpoint` is fine. #### F19.2 — `Endpoint.name` doubles as ID (HIGH) -- See F1.4 / F6.1 / F12.3. Two identifiers (`name` and `id`) for +- See F1.4 / F6.1 / F12.1. Two identifiers (`name` and `id`) for the same entity is the underspecification problem. #### F19.3 — `budgetPolicyId`, `usagePolicyId`, `effectiveBudgetPolicyId` (acceptable) -- **Where:** `model.ts:83, 85, 131, 133, 201, 203, 207, 209`. +- **Where:** `model.ts:102, 104, 188, 220, 294, 296, 405, 409, 411`. - Specific enough; matches platform-wide convention. +#### F19.4 — `MiniVectorIndex.endpointName` (acceptable) +- **Where:** `model.ts:380`. +- Domain-qualified; clear. + --- ### 20. Type-suffix tautology #### F20.1 — `Endpoint.endpointType: EndpointType` (MEDIUM) -- **Where:** `model.ts:121`, `model.ts:81`. +- **Where:** `model.ts:284, 100`. - **Why flagged:** Three layers of "endpoint": `endpoint.endpointType : EndpointType`. The container provides the "endpoint" context. @@ -1069,142 +892,166 @@ _None._ `endpoint_type`; needs a marshaller remap. #### F20.2 — `Endpoint.endpointStatus: EndpointStatus` (MEDIUM) -- **Where:** `model.ts:127`, `model.ts:153`. +- **Where:** `model.ts:290, 314`. - **Why flagged:** Same pattern. - **Suggestion:** Rename field `endpointStatus → status`. #### F20.3 — `EndpointStatus.state: EndpointStatus_State` (LOW) -- **Where:** `model.ts:155`. +- **Where:** `model.ts:316`. - **Why flagged:** Field is `state`, enum is `EndpointStatus_State`. Not strictly tautological (the field is the bare noun, the type is the qualified noun). Acceptable. -#### F20.4 — `PatchEndpointThroughputResponse.status: - ThroughputPatchStatus` (LOW) -- **Where:** `model.ts:257`, `model.ts:36`. -- **Why flagged:** Field is `status`; type is `ThroughputPatchStatus`. - Reading `response.status : ThroughputPatchStatus` is "status . throughput - patch status". -- **Suggestion:** Rename field to `result` (less tautological), or - rename enum to drop `Status` (becomes `ThroughputPatch`). Or - accept the tautology. - -#### F20.5 — `EndpointScalingInfo.state: ScalingChangeState` (LOW) -- **Where:** `model.ts:144`. +#### F20.4 — `EndpointScalingInfo.state: ScalingChangeState` (LOW) +- **Where:** `model.ts:305`. - **Why flagged:** Same pattern. Field `state` typed against `ScalingChangeState` reads "scaling info . state : scaling change state". - **Suggestion:** Rename field to `changeState` (matches the enum's - domain better). See F16.3. - -#### F20.6 — `EndpointThroughputInfo.changeRequestState: - ThroughputChangeRequestState` (LOW) -- **Where:** `model.ts:173`. -- **Why flagged:** Field name and type name carry the same tokens - (`changeRequestState` ↔ `ChangeRequestState`). -- **Suggestion:** Acceptable; this is the standard pattern. + domain better). See F16.1. + +#### F20.5 — `MiniVectorIndex.indexType: VectorIndexType`, + `VectorIndex.indexType: VectorIndexType` (LOW) +- **Where:** `model.ts:383, 579`. +- **Why flagged:** Field `indexType` typed against `VectorIndexType`; + reads "vector index . index type : vector index type". +- **Suggestion:** Rename field `indexType → type`. Wire field is + `index_type` — marshaller remap. + +#### F20.6 — `MiniVectorIndex.indexSubtype: IndexSubtype`, + `VectorIndex.indexSubtype: IndexSubtype` (LOW) +- **Where:** `model.ts:398, 594`. +- **Why flagged:** Same pattern. +- **Suggestion:** Rename field `indexSubtype → subtype`. --- -## Package overlap: `endpoints` vs `warehouses` vs `modelservingmanagement` vs `indexes` +## Package overlap: `vectorsearch` vs `warehouses` vs `modelserving` -This SDK exposes *three* distinct "endpoint" packages plus a sibling -"index" package, all conceptually distinct but lexically similar. +The `endpoints` package was merged into `vectorsearch` in the +2026-05-20 regeneration, resolving the F0.1 / F0.2 / F-OVERLAP.2 +findings about package ambiguity. Some residual concerns remain +about the unqualified `Endpoint` symbol. -### F-OVERLAP.1 — `Endpoint` symbol exists in three places (HIGH) +### F-OVERLAP.1 — `Endpoint` symbol exists in three places (MEDIUM) - **Where:** - - `packages/endpoints/src/v1` exports `Endpoint` + - `packages/vectorsearch/src/v1` exports `Endpoint` - `packages/warehouses/src/v1` exports `EndpointState`, `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` - - `packages/modelservingmanagement/src/v1` exports - `InferenceEndpoint`, `ServingEndpointDetailedPermissionLevel` + - `packages/modelserving/src/v1` exports + `InferenceEndpoint`, etc. - **Why flagged:** Project-wide `grep -r Endpoint` returns hits across all three packages. Autocomplete on "Endpoint" collides. Even with qualified imports, mental load is high. -- **Suggestion:** Rename per F0.1. The model serving package already +- **Suggestion:** Rename per F1.1. The model serving package already qualifies its primary type as `InferenceEndpoint`; this package should qualify as `VectorSearchEndpoint`; the warehouse package's legacy `Endpoint*` names are wire-protocol and should be deprecated but left for compatibility. -### F-OVERLAP.2 — `indexes` companion package is also under-qualified (LOW) -- See F0.3. - -### F-OVERLAP.3 — Pluralization of package names (`endpoints` plural - vs `modelservingmanagement` singular vs `warehouses` plural) (LOW) -- Cross-package style decision. Some packages use plural - (`endpoints`, `warehouses`, `clusters`, `budgets`), some - singular (`modelservingmanagement`, `budgetpolicy`, `bundle`). -- **Suggestion:** Pick one. Cross-cutting. - -### F-OVERLAP.4 — `EndpointType` exists in this package vs +### F-OVERLAP.2 — `EndpointType` exists in this package vs `WarehouseType` exists in `warehouses` (LOW) -- **Where:** `model.ts:6` here vs +- **Where:** `model.ts:18` here vs `warehouses/src/v1/index.ts` line for `WarehouseType`. - **Why flagged:** `WarehouseType` is qualified; `EndpointType` is - bare. After F0/F1 rename it becomes `VectorSearchEndpointType` — + bare. After F1.2 rename it becomes `VectorSearchEndpointType` — symmetric with `WarehouseType`. --- +## Proto-architectural-leak names + +Names that leak the upstream proto/IDL or service architecture into the +TS public surface. These are not standard suffix conventions; they +reflect internal class/file layout that should not be visible to SDK +consumers. + +### 1. `EndpointStatus_State` — model.ts:69, index.ts:12 +- **Why:** Underscore-separated identifier mirrors the proto nested-enum + shape (`EndpointStatus.State` in the IDL). TS has no nested-enum + concept, so the underscore leaks the proto file layout. Also exported + at `index.ts:12`. +- **Category:** Proto-nested type leak (underscore infix). +- **Suggested:** `EndpointState`, or move it under the `EndpointStatus` + namespace via a TS `namespace EndpointStatus { export enum State }`. +- **Rationale:** TS consumers do not see the proto enclosing message. + The underscore is purely a generator artifact; the public type name + should read as a plain TS identifier. + +### 2. `RerankerConfig_RerankerParameters` — model.ts:490, index.ts:50 +- **Why:** Proto-nested message name leaked as an underscore-separated + TS interface. Also repeats the `Reranker` token inside its own parent + type ("reranker config . reranker parameters"). +- **Category:** Proto-nested type leak (underscore infix) + token + repetition. +- **Suggested:** `RerankerParameters` at the top level, or + `RerankerConfig.Parameters` via a TS namespace. Drop the duplicated + `Reranker` token regardless. +- **Rationale:** The wire form `RerankerConfig.RerankerParameters` is + a proto nesting convention; the SDK consumer only sees an interface + reference, so `RerankerParameters` is unambiguous in context. + +### 3. `marshalRerankerConfig_RerankerParametersSchema` — model.ts:1217 +- **Why:** Schema constant name carries the same proto-nested + underscore as finding 2. The Zod schema for the nested message + inherits the leaked name. +- **Category:** Proto-nested type leak (underscore infix) — schema + variant. +- **Suggested:** `marshalRerankerParametersSchema` (consistent with the + renamed interface in finding 2). +- **Rationale:** Same as 2 — internal naming bleeding into the public + module surface. + +--- + ## Summary table | # | Category | Findings | | - | --------------------------------------- | -------- | -| 0 | **Package name (special)** | 3 | -| 1 | Vague / generic | 9 | -| 2 | Redundant enum prefixes | 5 | +| 0 | **Package name (special)** | 1 | +| 1 | Vague / generic | 8 (1 acceptable) | +| 2 | Redundant enum prefixes | 1 | | 3 | Acronym casing | 4 (3 acceptable) | | 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 10 | -| 6 | Misleading names | 9 | -| 7 | Overly verbose | 8 | -| 8 | Redundant suffixes | 5 | -| 9 | Singular / plural mismatch | 5 (3 acceptable) | +| 6 | Misleading names | 7 | +| 7 | Overly verbose | 6 | +| 8 | Redundant suffixes | 5 (1 acceptable) | +| 9 | Singular / plural mismatch | 6 (2 acceptable) | | 10 | Reserved-word collisions | 5 (3 acceptable) | | 11 | Empty / trivial wrappers | 1 | -| 12 | Duplicate concepts | 7 | +| 12 | Duplicate concepts | 6 | | 13 | Verb-tense inconsistency | 4 (1 acceptable) | | 14 | Go / Java-style names | 4 (1 acceptable) | -| 15 | Generic field names | 6 | -| 16 | Field contradicting type domain | 4 | -| 17 | Inconsistent action verbs | 4 (2 acceptable) | -| 18 | Long enum values | 5 (1 acceptable) | -| 19 | Underspecified IDs | 3 (2 acceptable) | -| 20 | Type-suffix tautology | 6 (3 acceptable) | -| OVERLAP | endpoints vs warehouses vs serving | 4 | -| **Total** | | **111** | +| 15 | Generic field names | 7 | +| 16 | Field contradicting type domain | 2 | +| 17 | Inconsistent action verbs | 5 (3 acceptable) | +| 18 | Long enum values | 2 (1 acceptable) | +| 19 | Underspecified IDs | 4 (3 acceptable) | +| 20 | Type-suffix tautology | 6 (2 acceptable) | +| OVERLAP | vectorsearch vs warehouses vs serving | 2 | +| PROTO | Proto-architectural-leak names | 3 | +| **Total** | | **99** | --- ## Top highest-impact renames (recommended order) -1. **F0.1 / F0.2 / F1.1 / F1.2 / F-OVERLAP.1:** Rename the package - to `@databricks/sdk-vectorsearchendpoints` (or - `@databricks/sdk-vectorsearch`); rename `Endpoint` to - `VectorSearchEndpoint`. This single change eliminates the most - confusing ambiguity in the package. -2. **F2.1 / F2.2 / F2.3:** Strip the redundant member prefixes from - `ScalingChangeState` (`SCALING_CHANGE_*`), - `ThroughputChangeRequestState` (`CHANGE_*`), and - `ThroughputPatchStatus` (`PATCH_*`). -3. **F9.1 / F9.2:** Pluralize the list method, request, and response: - `listEndpoints`, `ListEndpointsRequest`, `ListEndpointsResponse`. -4. **F6.5:** Rename `minimalConcurrencyAllowed → - minimumConcurrencyAllowed` (the existing name is grammatically - wrong English). -5. **F12.3 / F1.4 / F6.1 / F19.2:** Resolve the `Endpoint.name` vs +1. **F1.1 / F1.2 / F-OVERLAP.1:** Rename `Endpoint` to + `VectorSearchEndpoint`. The package rename to + `@databricks/sdk-vectorsearch` already happened; aligning the + exported type name closes the loop. +2. **F9.1 / F9.2 / F9.3 / F9.4:** Pluralize the list methods, requests, + and responses: `listEndpoints`, `ListEndpointsRequest`, + `ListEndpointsResponse`, and same for `VectorIndex`. +3. **F12.1 / F1.4 / F6.1 / F19.2:** Resolve the `Endpoint.name` vs `Endpoint.id` duality — either document the distinction prominently or unify at the API level. -6. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from +4. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from `Endpoint.endpointType` and `Endpoint.endpointStatus` to bare `type` / `status`. -7. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ +5. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson`/`msg` across the generated code. -8. **F12.2:** Resolve the `targetQps` / `replicationFactor` / - `numReplicas` overlap at the API spec level — three names for - related concepts, with JSDoc cross-references between them, is - a strong smell. --- @@ -1230,3 +1077,46 @@ This SDK exposes *three* distinct "endpoint" packages plus a sibling — the term is used by Vector Search, Model Serving, and SQL Warehouses for three different concepts. Disambiguation at the SDK level is unavoidable. + +--- + +## Fixed + +The 2026-05-20 regeneration renamed the `endpoints` package to +`vectorsearch` and absorbed the contents of the former `indexes` +package. The throughput-management surface +(`PatchEndpointThroughputRequest/Response`, +`patchEndpointThroughput` method, +`ThroughputChangeRequestState`/`ThroughputPatchStatus` enums, +`EndpointThroughputInfo` interface, `AdjustedThroughputRequest` +interface) was removed from the public surface, and several +implementation-leaking enum values and verbose field names were +dropped. + +- #F0.1 Package name `@databricks/sdk-endpoints` (originally cited at `package.json:2`): Fixed in regeneration on 2026-05-20 — package renamed to `@databricks/sdk-vectorsearch`, eliminating the cross-package ambiguity with model serving and SQL warehouses. +- #F0.2 Directory name `packages/endpoints/` (originally cited at `packages/endpoints/`): Fixed in regeneration on 2026-05-20 — directory renamed to `packages/vectorsearch/`. +- #F0.3 Companion package `indexes` (originally cited at `packages/indexes/`): Fixed in regeneration on 2026-05-20 — `indexes` package was absorbed into `vectorsearch`, so the cross-package qualification concern no longer applies. +- #F2.2 `ThroughputChangeRequestState.CHANGE_*` (originally cited at `model.ts:20-33`): Fixed in regeneration on 2026-05-20 — `ThroughputChangeRequestState` enum was removed entirely along with the throughput-management surface. +- #F2.3 `ThroughputPatchStatus.PATCH_*` (originally cited at `model.ts:36-43`): Fixed in regeneration on 2026-05-20 — `ThroughputPatchStatus` enum was removed entirely. +- #F2.5 `EndpointType.STANDARD_ON_ORION` (originally cited at `model.ts:10`): Fixed in regeneration on 2026-05-20 — `STANDARD_ON_ORION` enum value was dropped; `EndpointType` now has only `STORAGE_OPTIMIZED` and `STANDARD`. +- #F6.4 `EndpointType.STANDARD_ON_ORION` implementation leak (originally cited at `model.ts:9-10`): Fixed in regeneration on 2026-05-20 — `STANDARD_ON_ORION` enum value was removed, eliminating the infra-naming leak. +- #F6.5 `minimalConcurrencyAllowed` field (originally cited at `model.ts:71-72, 168-169, 237-238`): Fixed in regeneration on 2026-05-20 — concurrency fields removed from the public API surface. +- #F7.3 `PatchEndpointThroughputRequest/Response` (originally cited at `model.ts:232, 255`): Fixed in regeneration on 2026-05-20 — throughput-management surface was removed entirely. +- #F7.5 `currentConcurrencyUtilizationPercentage` (originally cited at `model.ts:166-167`): Fixed in regeneration on 2026-05-20 — field removed along with the throughput-management surface. +- #F7.6 `EndpointThroughputInfo` `Info` suffix (originally cited at `model.ts:142`): Fixed in regeneration on 2026-05-20 — `EndpointThroughputInfo` interface was removed entirely. +- #F8.4 `EndpointThroughputInfo` `Info` suffix (originally cited at `model.ts:142, 161`): Fixed in regeneration on 2026-05-20 — `EndpointThroughputInfo` interface was removed. +- #F8.5 `ThroughputChangeRequestState` (originally cited at `model.ts:20`): Fixed in regeneration on 2026-05-20 — enum was removed. +- #F11.1 `AdjustedThroughputRequest` exposed in a response (originally cited at `model.ts:68-75, 264`): Fixed in regeneration on 2026-05-20 — `AdjustedThroughputRequest` interface was removed along with the throughput-management surface. +- #F12.1 `numReplicas` in three different places (originally cited at `model.ts:87, 252, 177, 179`): Fixed in regeneration on 2026-05-20 — `numReplicas` field removed from the public API surface. +- #F12.2 `targetQps`, `requestedTargetQps`, `replicationFactor`, `numReplicas` overlap (originally cited at `model.ts:87, 93, 224, 229, 252, 149`): Fixed in regeneration on 2026-05-20 — `replicationFactor` and `numReplicas` fields removed; only `targetQps` remains as the public dimension. +- #F12.4 `concurrency` (CPU) vs `numReplicas` vs `targetQps` mixed (originally cited at `model.ts:69, 73, 87, 93, 162, 165, 168, 171, 177, 235, 238, 240, 252`): Fixed in regeneration on 2026-05-20 — `concurrency` and `numReplicas` fields removed; only `targetQps` remains. +- #F15.6 `concurrency` field (originally cited at `model.ts:70, 236`): Fixed in regeneration on 2026-05-20 — `concurrency` field was removed from the public API surface. +- #F16.2 `EndpointThroughputInfo.changeRequestState` (originally cited at `model.ts:173`): Fixed in regeneration on 2026-05-20 — `EndpointThroughputInfo` interface was removed. +- #F18.3 `CHANGE_REACHED_MINIMUM`, `CHANGE_REACHED_MAXIMUM` (originally cited at `model.ts:26, 28`): Fixed in regeneration on 2026-05-20 — `ThroughputChangeRequestState` enum was removed. +- #F18.4 `STANDARD_ON_ORION` (originally cited at `model.ts`): Fixed in regeneration on 2026-05-20 — enum value was removed; the remaining `STORAGE_OPTIMIZED` and `STANDARD` are no longer flagged as infra leaks. +- #F20.4 `PatchEndpointThroughputResponse.status: ThroughputPatchStatus` (originally cited at `model.ts:257, 36`): Fixed in regeneration on 2026-05-20 — both the response type and the enum were removed. +- #F20.6 `EndpointThroughputInfo.changeRequestState: ThroughputChangeRequestState` (originally cited at `model.ts:173`): Fixed in regeneration on 2026-05-20 — interface and enum were both removed. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index 3e7b3192..6aeea820 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -2,15 +2,15 @@ **Path:** `packages/entitytagassignments/src/v1/` **Versions audited:** v1 -**Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) and inheritance (`inherited` / `includeInherited`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). -**Total weird names flagged:** 31 +**Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). +**Total weird names flagged:** 27 ## Summary | Severity | Count | | --- | --- | -| High | 11 | +| High | 9 | | Medium | 10 | -| Low | 6 | +| Low | 4 | | Observation | 4 | ## High severity @@ -27,7 +27,7 @@ - **Suggested name:** `TagAssignment`. Rely on package-import disambiguation: `import {TagAssignment as UcTagAssignment} from '@databricks/sdk-entitytagassignments'`. - **Rationale:** A noun that re-states its only possible subject is filler. The Go SDK names it `EntityTagAssignment` to disambiguate from a different proto type in the same Go package; TS module imports already do that disambiguation. -### 3. `EntityTagAssignment` field shape vs. sister `TagAssignment` shape — `src/v1/model.ts:32-49` vs. `tagassignments/src/v1/model.ts:46-55` +### 3. `EntityTagAssignment` field shape vs. sister `TagAssignment` shape — `src/v1/model.ts:32-47` vs. `tagassignments/src/v1/model.ts:46-55` - **Why weird:** The two sister types model the same conceptual object using different identifier fields: this package's `EntityTagAssignment` has `entityName: string`, while `tagassignments.TagAssignment` has `entityId: string`. Same column conceptually (the thing being tagged), different field name. A user porting code between the two has to translate. The JSDoc here says "fully qualified name" while the sister says "identifier"; the wire-side names are `entity_name` vs. `entity_id`. - **Category:** 12 (duplicate concept with divergent naming), 17 (verb/noun inconsistency across siblings), 16 (field contradicts type domain — "name" suggests a label, "id" suggests an opaque handle, but both fields are fully-qualified resource identifiers). - **Suggested name:** Unify on `entityFullName` (matches Unity Catalog vocabulary like `catalogs.fullName`, `tables.fullName`) or `entity` for both packages. At minimum, both packages should agree. @@ -35,47 +35,35 @@ ### 4. `TagAssignmentSourceType` — `src/v1/model.ts:9` - **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. Combined with the surrounding type `EntityTagAssignment`, the relevant field is `sourceType: TagAssignmentSourceType` — five words to say "where did this come from". -- **Category:** 20 (type-suffix tautology — `Type` on an enum), 8 (redundant prefix — every member is prefixed `TAG_ASSIGNMENT_SOURCE_TYPE_*`), 7 (overly verbose). +- **Category:** 20 (type-suffix tautology — `Type` on an enum), 7 (overly verbose). - **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). Field becomes `source: TagSource`. - **Rationale:** The shorter name is unambiguous in context (`EntityTagAssignment.source` reads better than `EntityTagAssignment.sourceType`). Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. -### 5. `TagAssignmentSourceType` enum members carry the full enum name as prefix — `src/v1/model.ts:11-13` -- **Why weird:** Every enum member is prefixed with `TAG_ASSIGNMENT_SOURCE_TYPE_*`. The TS access is `TagAssignmentSourceType.TAG_ASSIGNMENT_SOURCE_TYPE_SYSTEM_DATA_CLASSIFICATION` — the user types `TagAssignmentSourceType` twice in one expression. -- **Category:** 2 (redundant enum prefix on every member). -- **Suggested name:** Drop the redundant prefix from each member so access reads `TagAssignmentSourceType.SystemDataClassification`. -- **Rationale:** TS enum members are already namespaced by the enum identifier; re-prefixing every value with the enum name adds nothing. Compare canonical TS enums (`Severity.High`, `Color.Red`). - -### 6. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,53,66` -- **Why weird:** Five places in this file have a field called `entityName` whose JSDoc says "The fully qualified name of the entity to which the tag is assigned". The shape `name?: string | undefined` cannot enforce qualification; users will pass bare names. Compare Unity Catalog convention `fullName` (used in `catalogs`, `schemas`, `tables`). +### 5. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,52,62` +- **Why weird:** Four places in this file have a field called `entityName` whose JSDoc says "The fully qualified name of the entity to which the tag is assigned". The shape `name?: string | undefined` cannot enforce qualification; users will pass bare names. Compare Unity Catalog convention `fullName` (used in `catalogs`, `schemas`, `tables`). - **Category:** 1 (vague — "name" is too generic), 6 (misleading — looks settable to a bare name, is actually structured), 15 (generic field name losing meaning), 19 (underspecified ID — what makes it "fully qualified"?). - **Suggested name:** `entityFullName` (or `entity`/`entityFqn`). Matches sister UC packages. - **Rationale:** "fully qualified" is wire-side; the SDK type should make the constraint visible in the identifier. A field literally called `entityName` reads as a display name to most TS users. -### 7. `entityType: string` everywhere — `src/v1/model.ts:28,40,58,72` +### 6. `entityType: string` everywhere — `src/v1/model.ts:28,40,56,68` - **Why weird:** Four occurrences of `entityType?: string | undefined` with no enum or string-literal union to constrain values. The JSDoc says "The type of the entity to which the tag is assigned" but never lists which values are valid (compare sister `tagassignments`: doc explicitly lists `apps, dashboards, geniespaces, notebooks`). For Unity Catalog entities, the actual valid set is something like `table`, `schema`, `catalog`, `column`, `volume`, `function`, `model` — none of which is documented or constrained in the type. - **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what type strings are valid?), 6 (misleading — looks free-form, is actually constrained). - **Suggested name:** `EntityKind` (string-literal union or enum) typed as the field. E.g. `entityKind?: 'table' | 'schema' | 'catalog' | 'column' | 'volume' | 'function' | 'model'`. The field name `Type` also collides with the JS reserved-ish word — `Kind` reads more cleanly. - **Rationale:** Stringly-typed enum fields are a generator anti-pattern. The valid set is closed; the type should say so. `Type` as a noun is also overused — `Kind` is the convention in TS standard library (`SyntaxKind`, `NodeKind`). -### 8. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,55` +### 7. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` - **Why weird:** `DeleteEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag to delete". `GetEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag". But `EntityTagAssignment.tagKey` (on the actual returned/created object) and `CreateEntityTagAssignmentRequest.tagAssignment.tagKey` are documented as just "The key of the tag" with no required marker — yet you cannot create or get a tag without a key. The `?: string | undefined` typing makes all of them optional in TS. Type and doc disagree. - **Category:** 6 (misleading — type says optional, semantics says required), 17 (inconsistent — some docs say "Required.", others don't, for what is the same logical field). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) and remove the "Required." doc preamble since the type enforces it. Apply uniformly across all four request types and the assignment type itself. - **Rationale:** "Required." in a docstring while the type is optional is a generator smell. Honest required-ness should travel through the type. -### 9. `includeInherited` boolean doc is wrong — `src/v1/model.ts:60,74` -- **Why weird:** The JSDoc on `GetEntityTagAssignmentRequest.includeInherited` and `ListEntityTagAssignmentsRequest.includeInherited` reads "Boolean which indicates whether this tag is inherited." That is the doc for `EntityTagAssignment.inherited` (a read-side, per-row marker). The request-side `includeInherited` is a *filter* meaning "include inherited tags in the response", not a per-tag inheritance marker. The same wrong doc is copy-pasted onto a settings flag with different semantics. -- **Category:** 6 (misleading — doc says one thing, field does another), 12 (duplicate concept naming — `inherited` (the marker) vs. `includeInherited` (the filter) both documented identically), 17 (inconsistent prose for sibling fields). -- **Suggested name:** Keep `includeInherited` on the request types; fix the doc to "If true, include inherited tag assignments in the result." Keep `inherited` on `EntityTagAssignment`. -- **Rationale:** Doc-code mismatch produces incorrect SDK behaviour at the agent level. Even if it's a generator issue, this audit must flag it. - -### 10. `Client` class — `src/v1/client.ts:41` +### 8. `Client` class — `src/v1/client.ts:41` - **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The other tag packages (`tagassignments`, `tagpolicies`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages). - **Suggested name:** `EntityTagAssignmentsClient` (or `UnityCatalogTagsClient`). - **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing. Generator-level concern. -### 11. Method names `createEntityTagAssignment` / `deleteEntityTagAssignment` / `getEntityTagAssignment` / `listEntityTagAssignments` / `updateEntityTagAssignment` — `src/v1/client.ts:76,114,133,169,235` +### 9. Method names `createEntityTagAssignment` / `deleteEntityTagAssignment` / `getEntityTagAssignment` / `listEntityTagAssignments` / `updateEntityTagAssignment` — `src/v1/client.ts:76,114,133,163,226` - **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createEntityTagAssignment(...)` reads as "package.subject.create.subject" — the noun is doubled. Sister package `tagassignments` does the same with `createTagAssignment`. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. - **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `EntityTagAssignment` four/five times when the client only manages `EntityTagAssignment`). - **Suggested name:** `create`, `delete`, `get`, `list`, `update`. Or shorter `createAssignment` / `deleteAssignment` / etc. @@ -83,19 +71,19 @@ ## Medium severity -### 12. `CreateEntityTagAssignmentRequest` etc. — five request DTOs share a 25-char prefix — `src/v1/model.ts:17,22,52,64,85` +### 10. `CreateEntityTagAssignmentRequest` etc. — five request DTOs share a 25-char prefix — `src/v1/model.ts:17,22,50,60,79` - **Why weird:** `CreateEntityTagAssignmentRequest`, `DeleteEntityTagAssignmentRequest`, `GetEntityTagAssignmentRequest`, `ListEntityTagAssignmentsRequest`, `UpdateEntityTagAssignmentRequest`. Each is 33 characters; the common prefix `EntityTagAssignment` is 19 chars of repetition. In the package whose only subject is the entity tag assignment, every request type re-states that subject. - **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). - **Suggested name:** `CreateRequest` / `DeleteRequest` / `GetRequest` / `ListRequest` / `UpdateRequest`. Or drop just the noun: `CreateRequest` etc. - **Rationale:** Single-subject packages don't need to repeat the subject on every request DTO. Listed as medium because the inconsistency with the rest of the SDK matters. -### 13. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:64` vs. `src/v1/model.ts:32` +### 11. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` - **Why weird:** The plural appears only on the list endpoint; the rest of the surface is singular. Singular/plural mix is consistent with the Go SDK and other packages, but worth flagging that the resource name on the wire is `/entity-tag-assignments` (plural) while the type name is singular `EntityTagAssignment`. The list response is `ListEntityTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. - **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. -### 14. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 12. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — `executeCall` runs the retry/rate-limit shell, `executeHttpCall` does the actual HTTP send. They appear together in every client method: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -110,43 +98,43 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Names should reveal the layering, not require code-diving. Generator-wide concern. -### 15. `Call` type and `call` variable — `src/v1/client.ts:86,119,145,187,251` and `src/v1/utils.ts:27` +### 13. `Call` type and `call` variable — `src/v1/client.ts:86,119,139,178,242` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, called inside `executeCall(call, options)`. The same word is the variable, the type, and the verb. Inside one method scope we have `req`, `call`, `httpReq` — three layered names where one of them collides with its type. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions are tolerable but obscure prose-style code. -### 16. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,173,239` +### 14. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. -### 17. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 149-155, 194-199, 261-266` +### 15. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 143-148, 182-187, 252-257` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: EntityTagAssignment`. The names differ only by `Body`. Both are short for "response". The reader has to track which is bytes, which is parsed. Compare `req` (parameter, request) — also abbreviated, but no `reqBody` sibling. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result`, or `responseBytes` + `response`. - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 18. `httpReq` local variable — `src/v1/client.ts:89,122,148,190,254` +### 16. `httpReq` local variable — `src/v1/client.ts:89,122,142,181,245` - **Why weird:** Inside a method that already has `req: CreateEntityTagAssignmentRequest`, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in one scope. -### 19. `HttpCallOptions` — `src/v1/utils.ts:15` +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 20. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 18. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just shorthand. -### 21. `flattenQueryParams` — `src/v1/utils.ts:123` +### 19. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package's list endpoint uses individual `params.append(...)` calls instead). Dead-code-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. @@ -154,56 +142,44 @@ ## Low severity -### 22. `readAll(body)` — `src/v1/utils.ts:40` +### 20. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path or array. -### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 21. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. Casing is appropriate for a module constant; the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain; the comment above it does the work the name should. -### 24. `inherited` (boolean) on `EntityTagAssignment` — `src/v1/model.ts:48` -- **Why weird:** A boolean called `inherited`. The participle works (the tag is in an inherited state), but boolean fields are conventionally `is*`/`has*` in TS (`isInherited`). The sibling filter `includeInherited` uses a verb prefix; the marker drops the prefix. Asymmetric. -- **Category:** 17 (inconsistent — `inherited` (no prefix) vs. `includeInherited` (verb-prefixed) in same file). -- **Suggested name:** `isInherited` on the result type. -- **Rationale:** TS booleans usually carry an `is`/`has` prefix to read as predicates. The current name reads grammatically as an adjective on the assignment. - -### 25. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` +### 22. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` - **Why weird:** The pair encodes a `(key, value)` tag — that part is fine. But the type is *already* called `EntityTagAssignment`, so the `tag` prefix on each field is redundant within scope: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. - **Category:** 8 (redundant prefix — `tag` within `EntityTagAssignment`). - **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. - **Rationale:** Field names should not re-state their containing type's noun. `assignment.key` / `assignment.value` reads cleaner. -### 26. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` +### 23. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` - **Why weird:** Verb tense pair: `updateTime` (noun-noun, gerund stripped) vs. `updatedBy` (past participle). Cross-SDK convention should pick one. Compare: `createTime` (noun-noun) often pairs with `createdBy` (past participle) in Databricks — the same asymmetry. It is consistent across the SDK, but worth noting under rule 13. - **Category:** 13 (verb-tense inconsistency within a paired field). - **Suggested name:** `updateTime`/`updateBy` or `updatedTime`/`updatedBy`. Either works; the asymmetry is the issue. - **Rationale:** Established SDK pattern, but rule 13 demands the flag. -### 27. `sourceType` vs. `source` (on the enum) — `src/v1/model.ts:46` and `src/v1/model.ts:9` -- **Why weird:** Field is `sourceType: TagAssignmentSourceType`. The field name re-states `Type`, and the type name re-states `SourceType`. The user types "source", "Type", "Source", "Type" — four times in one declaration: `sourceType?: TagAssignmentSourceType | undefined`. -- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). -- **Suggested name:** `source: TagSource` (drop both `Type`s). -- **Rationale:** See #4. The compound effect makes the line read as type-noise. - ## Observations -### 28. Action verb consistency +### 24. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 29. Acronym casing +### 25. Acronym casing The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 30. `entitytagassignments` lowercase package name +### 26. `entitytagassignments` lowercase package name The package directory is `entitytagassignments` (single token, no separator), but every type uses `EntityTagAssignment` and the HTTP path uses `entity-tag-assignments`. Same problem as `dataclassification`. SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 31. Domain leakage from sister packages +### 27. Domain leakage from sister packages Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). @@ -215,11 +191,14 @@ Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — a - `tag key` / `tag value` — string key/value pair attached to an entity (the "tag" itself). - `tag policy` — governed tag definition with constraints/values (a separate sister package). - `governed tag` — a tag whose key matches an active `TagPolicy`. JSDoc mentions ASSIGN/MANAGE permissions on the tag policy. -- `inherited` — flag on a returned assignment indicating it was inherited from a parent (catalog/schema), not directly assigned. - `source type` — provenance of the assignment: user vs. data-classification (today, only `SYSTEM_DATA_CLASSIFICATION` is enumerated). ## File coverage -- `src/v1/model.ts` (173 lines): read fully. -- `src/v1/client.ts` (275 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (16 lines): read fully. +- `src/v1/model.ts` (161 lines): read fully. +- `src/v1/client.ts` (265 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (15 lines): read fully. + +## Fixed +- #9 `includeInherited` boolean doc is wrong (originally cited at `src/v1/model.ts:60,74`): Fixed in regeneration on 2026-05-20 — `includeInherited` field removed from request DTOs entirely. +- #24 `inherited` boolean on `EntityTagAssignment` (originally cited at `src/v1/model.ts:48`): Fixed in regeneration on 2026-05-20 — `inherited` field removed from the response type. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index ca4fdac9..0a66573b 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -5,14 +5,14 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 31 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 13 | -| Low | 8 | +| Medium | 11 | +| Low | 7 | | Observation | 2 | --- @@ -34,31 +34,31 @@ - **Suggested name:** Either (a) consolidate into a single `baseenvironments` package and have `clusterlibraries` import from it, (b) explicitly cross-reference each shared type in docstrings, or (c) version one of them (`clusterlibraries` `DefaultBaseEnvironment` is presumably v1, `environments` `WorkspaceBaseEnvironment` is v2 — say so). - **Rationale:** Same shape, redefined in two packages, with subtly different naming (`DefaultBaseEnvironment` vs `WorkspaceBaseEnvironment`). Consumers will hit type-incompatibility errors when passing a value from one package into the other. -### 3. `WorkspaceBaseEnvironment` — name is a 26-character noun phrase with three adjectives stacked — `model.ts:727` -- **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. -- **Category:** 7 (overly verbose), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). -- **Suggested name:** Drop one of the prefixes. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. +### 3. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:718` +- **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. The 26 characters are baked into the *type prefix*, not the enum-member prefix; this is a TS-surface concern, not a proto-codegen concern. +- **Category:** 7 (overly verbose type prefix), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). +- **Suggested name:** Drop one of the adjectives in the *type* name. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. - **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. -### 4. `WorkspaceBaseEnvironment.status` field name and type's domain do not align — `model.ts:746` +### 4. `WorkspaceBaseEnvironment.status` field name and type's domain do not align — `model.ts:737` - **Why weird:** `WorkspaceBaseEnvironment.status` is typed `WorkspaceBaseEnvironmentCache_Status` — i.e. the *status of a Cache*. But the field documents itself as "The status of the materialized workspace base environment", not the status of a cache. The user reads `env.status` and the type's name implies a different concept (cache) than the doc and the data (materialization state of the environment). - **Category:** 16 (field type contradicts type domain), 6 (misleading). - **Suggested name:** Either (a) rename the enum to `MaterializationStatus` (the doc's own words) and drop the `Cache` qualifier, or (b) rename the field to `cacheStatus` to match the type. - **Rationale:** Field name and type name should describe the same thing. The mismatch is a tell that the enum was named for an internal proto nesting that the public API doesn't surface. -### 5. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:650, index.ts:27` -- **Why weird:** The type name `Operation` is one of the most generic words in software (matches OS-level, math, audit-log, business, telemetry, async-task… meanings). It is exported alongside two related types (`GetOperationRequest`, `WorkspaceBaseEnvironmentOperationMetadata`) and three classes (`CreateWorkspaceBaseEnvironmentOperation`, etc.). It is also a `google.longrunning.Operation`-shaped envelope (the docstring at model.ts:647 even says so), but the name doesn't say that. +### 5. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:641, index.ts:26` +- **Why weird:** The type name `Operation` is one of the most generic words in software (matches OS-level, math, audit-log, business, telemetry, async-task… meanings). It is exported alongside two related types (`GetOperationRequest`, `WorkspaceBaseEnvironmentOperationMetadata`) and three classes (`CreateWorkspaceBaseEnvironmentOperation`, etc.). It is also a `google.longrunning.Operation`-shaped envelope (the docstring at model.ts:638 even says so), but the name doesn't say that. - **Category:** 1 (vague/generic), 15 (generic type name losing meaning). - **Suggested name:** `LongRunningOperation`, `LROperation`, `AsyncOperation`, or namespace it under the package name (`EnvironmentOperation`). Whichever wins, the request type should match: `GetLongRunningOperationRequest` etc. - **Rationale:** A consumer importing `{Operation}` into a file that also has Slack `Operation`, audit `Operation`, or domain-specific `Operation` is in for a renaming party. The name signals nothing about being a polling envelope. -### 6. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:675-686` +### 6. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:666-677` - **Why weird:** The union's discriminator field is `$case` (the `$` prefix is a wire/codegen artifact, not idiomatic TS — see `clusterlibraries` and `database` audits where the same pattern surfaces). The `'response'` variant's payload field is also called `response`, so consumers write `op.result.response.response` is *not* the access path but `op.result.$case === 'response'` then `op.result.response` is. Conflating the discriminator literal `'response'` with a payload field also named `response` is confusing. Same for `'error'` / `error`. - **Category:** 6 (misleading — `$case`/`response`/`error` triple-overloading), 17 (inconsistency with idiomatic TS discriminated unions which use `kind` or `type`), 14 (Go/proto codegen artefact). - **Suggested name:** Use `kind` (or `type`) instead of `$case`, and use distinct names like `kind: 'error' | 'success'` with payload fields `error: DatabricksServiceException` / `value: Record<...>` (or similar). See database audit #14 for an analogous critique. - **Rationale:** `$` in identifiers in TS implies "internal/synthetic". This is a leak of the ts-proto codegen convention. Consumers writing `op.result?.$case` see synthetic noise. -### 7. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:561, index.ts:19` +### 7. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:552, index.ts:18` - **Why weird:** Three problems in one name: 1. **`Proto` suffix** on a TypeScript identifier — leaks the proto origin into the type name (`Proto` means nothing to a TS consumer). 2. **`Exception`** is Java/Python terminology; TS/JS uses `Error`. The type is a *data* representation of an error (it's a plain interface with `errorCode`/`message`/`stackTrace`), not an actual thrown exception class. Naming a data structure `Exception` suggests it can be thrown. @@ -67,7 +67,7 @@ - **Suggested name:** `ServiceErrorDetails`, `DatabricksError`, or `RpcError`. Drop the `WithDetails`, `Proto`, and `Exception` suffix all at once. - **Rationale:** The name has the worst of every world: Java verb + Proto codegen tag + length. No piece of the name helps a TS consumer. -### 8. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:689, 692` +### 8. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:680, 683` - **Why weird:** The request type is `RefreshWorkspaceBaseEnvironmentRequest` (singular), but its JSDoc says: "Request message for RefreshWorkspaceBaseEnviro**ments**" (plural). The same type's `name` field doc says: "Required. The resource name of the workspace base environment **to delete**" — i.e. copy-pasted from the delete request and never edited. - **Category:** 9 (singular/plural mismatch — type vs doc), 6 (misleading doc — says delete). - **Suggested name:** Fix the docstrings — say "Refresh a workspace base environment. The resource name of the environment to refresh." Either keep the type singular (matches the client method `refreshWorkspaceBaseEnvironment`) or move to plural everywhere. @@ -77,148 +77,137 @@ ## Medium severity -### 9. `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — redundant enum prefix — `model.ts:10` -- **Why weird:** Enum value `BASE_ENVIRONMENT_TYPE_UNSPECIFIED` embeds the enum name as a prefix. Access reads `BaseEnvironmentType.BASE_ENVIRONMENT_TYPE_UNSPECIFIED` — triply redundant. `CPU` and `GPU` follow no such prefix, so the convention is inconsistent within the enum. -- **Category:** 2 (redundant enum prefix), 17 (inconsistency within the same enum), 18 (long enum values). -- **Suggested name:** Drop the prefix: `BaseEnvironmentType.Unspecified | Cpu | Gpu`. Match the wire format on the marshal side. -- **Rationale:** Proto convention; doesn't carry through the port. Note `clusterlibraries/v2/model.ts:7` exports an *identical* `BaseEnvironmentType` enum — same prefix, same inconsistency. - -### 10. `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` — 49-character enum value — `model.ts:518` -- **Why weird:** The longest enum value in the package: `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` is 82 characters total. `ADMIN` and `DATABRICKS` follow no such prefix — inconsistent within the same enum (cf. finding #9). -- **Category:** 2 (redundant enum prefix), 17 (inconsistency), 18 (long enum values). -- **Suggested name:** `Unspecified | Admin | Databricks`. -- **Rationale:** Same as #9. - -### 11. `WorkspaceBaseEnvironmentCache_Status.STATUS_UNSPECIFIED` — redundant prefix on UNSPECIFIED only — `model.ts:528` -- **Why weird:** The enum's `STATUS_UNSPECIFIED` member is prefixed but the others (`PENDING`, `CREATED`, `FAILED`, `EXPIRED`, `INVALID`, `REFRESHING`) are not — inconsistent. -- **Category:** 2 (redundant prefix), 17 (inconsistency within the same enum). -- **Suggested name:** `Unspecified | Pending | Created | Failed | Expired | Invalid | Refreshing`. -- **Rationale:** Same as #9–10. - -### 12. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` +### 9. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` - **Why weird:** The `ErrorCode` enum has roughly 100 members. The doc comments mark a large fraction as deprecated ("kept to maintain backwards compatibility"). Many members are domain-specific (e.g. `IPYNB_FILE_IN_REPO`, `GIT_URL_NOT_ON_ALLOW_LIST`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `DAC_ALREADY_EXISTS`) and have nothing to do with environments. The enum is a kitchen-sink import of every Databricks-platform error code, exported from a *workspace-base-environment* package. - **Category:** 1 (overly broad — exposed in the wrong scope), 7 (overly verbose surface), 12 (duplicate concept — `ErrorCode` likely lives in many packages). - **Suggested name:** Move to a shared `@databricks/sdk-databricks/apierror` (where `apierr/codes/` already lives, per AGENTS.md) and import it. The environments package should export at most the subset of codes it actually returns. -- **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `APIError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. +- **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `ApiError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. -### 13. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` +### 10. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` - **Why weird:** Enum values are SCREAMING_SNAKE wire strings (e.g. `MAX_CHILD_NODE_SIZE_EXCEEDED`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). 100+ values × ~30 chars each = a large surface that consumers must spell exactly. TS pattern is `PascalCase` enum members. - **Category:** 14 (Java/Go-style names), 18 (long enum values). - **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. - **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. -### 14. `DefaultWorkspaceBaseEnvironment.cpuWorkspaceBaseEnvironment` / `gpuWorkspaceBaseEnvironment` — fields stutter the type name — `model.ts:583, 588` +### 11. `DefaultWorkspaceBaseEnvironment.cpuWorkspaceBaseEnvironment` / `gpuWorkspaceBaseEnvironment` — fields stutter the type name — `model.ts:574, 579` - **Why weird:** Field names contain the wrapping type's name three times. Read aloud: "the cpu workspace base environment field on the default workspace base environment". The values are just resource-name *strings* pointing at another `WorkspaceBaseEnvironment` ("Format: workspace-base-environments/{workspace_base_environment}"). Field names `cpu` and `gpu` plus a typed `WorkspaceBaseEnvironmentRef` would be cleaner. - **Category:** 7 (overly verbose), 15 (generic field names — the value is just a resource name). - **Suggested name:** `cpu` / `gpu` (with field type `string` or `WorkspaceBaseEnvironmentName`), or `cpuEnvironmentName` / `gpuEnvironmentName`. - **Rationale:** The type is *already* `DefaultWorkspaceBaseEnvironment`. Repeating the prefix on every field makes consumers type `defEnv.cpuWorkspaceBaseEnvironment` instead of `defEnv.cpu`. -### 15. `WorkspaceBaseEnvironment.baseEnvironmentType` / `baseEnvironmentProvider` — field prefixes duplicate parent type name — `model.ts:752, 754` -- **Why weird:** On a type called `WorkspaceBaseEnvironment`, the fields are `baseEnvironmentType` and `baseEnvironmentProvider`. The `baseEnvironment` prefix duplicates the parent. Plain `type` and `provider` would suffice. +### 12. `WorkspaceBaseEnvironment.baseEnvironmentType` — field prefix duplicates parent type name — `model.ts:743` +- **Why weird:** On a type called `WorkspaceBaseEnvironment`, the field is `baseEnvironmentType`. The `baseEnvironment` prefix duplicates the parent. Plain `type` (or `computeType`) would suffice. - **Category:** 8 (redundant suffix/prefix), 7 (verbose). -- **Suggested name:** `type` (or `computeType`) and `provider`. Watch `type` — it is a reserved-like word in TS though not technically reserved. -- **Rationale:** Same logic as #14. +- **Suggested name:** `type` or `computeType`. Watch `type` — it is a reserved-like word in TS though not technically reserved. +- **Rationale:** Same logic as #12. -### 16. `WorkspaceBaseEnvironment.filepath` — single-word run-together identifier — `model.ts:736` +### 13. `WorkspaceBaseEnvironment.filepath` — single-word run-together identifier — `model.ts:727` - **Why weird:** `filepath` is run-together (one word in camelCase). TS/JS convention is `filePath`. The Go SDK and proto wire format both use `filepath` as one token, but in TS the camelCase rule should split it. - **Category:** 3 (casing inconsistency), 14 (Go-style name). - **Suggested name:** `filePath`. -- **Rationale:** Every other compound field in the type (`displayName`, `creatorUserId`, `createTime`, `lastUpdatedUserId`, `updateTime`, `isDefault`, `baseEnvironmentType`, `baseEnvironmentProvider`) uses camelCase. `filepath` is the only exception. +- **Rationale:** Every other compound field in the type (`displayName`, `creatorUserId`, `createTime`, `lastUpdatedUserId`, `updateTime`, `isDefault`, `baseEnvironmentType`) uses camelCase. `filepath` is the only exception. -### 17. `WorkspaceBaseEnvironment.message` — generic field name — `model.ts:748` +### 14. `WorkspaceBaseEnvironment.message` — generic field name — `model.ts:739` - **Why weird:** `message` is generic and could mean log message, error message, info text, user-facing description, etc. Doc says "Status message providing additional details about the environment status." `statusMessage` would be more precise. - **Category:** 1 (vague), 15 (generic field name losing meaning). - **Suggested name:** `statusMessage` or `statusDetails`. - **Rationale:** Same as `DefaultBaseEnvironment.message` in clusterlibraries audit (§1.2). -### 18. `WorkspaceBaseEnvironment.name` — generic field name, holds a resource path — `model.ts:732` -- **Why weird:** `name` is *not* a human-readable name in this API (there is a separate `displayName` for that, model.ts:734). The doc says: "The resource name of the workspace base environment. Format: workspace-base-environments/{workspace-base-environment}" — i.e. `name` is a slash-delimited *resource path*. Calling a path a `name` is a Google-AIP convention that confuses non-AIP-aware readers. +### 15. `WorkspaceBaseEnvironment.name` — generic field name, holds a resource path — `model.ts:723` +- **Why weird:** `name` is *not* a human-readable name in this API (there is a separate `displayName` for that, model.ts:725). The doc says: "The resource name of the workspace base environment. Format: workspace-base-environments/{workspace-base-environment}" — i.e. `name` is a slash-delimited *resource path*. Calling a path a `name` is a Google-AIP convention that confuses non-AIP-aware readers. - **Category:** 6 (misleading — value is a path, not a name), 15 (generic field name), 19 (underspecified ID). - **Suggested name:** `resourceName`, `path`, or `id`. Or document it with `(format: workspace-base-environments/...)` in the field name itself. - **Rationale:** This pattern recurs across the package (every request type's `name` field is actually a path: `GetWorkspaceBaseEnvironmentRequest.name`, `DeleteWorkspaceBaseEnvironmentRequest.name`, `RefreshWorkspaceBaseEnvironmentRequest.name`, `GetDefaultWorkspaceBaseEnvironmentRequest.name`, `Operation.name`, `GetOperationRequest.name`). Eight different `.name` fields, each a path. -### 19. `WorkspaceBaseEnvironment.creatorUserId` / `lastUpdatedUserId` — verb tense inconsistency — `model.ts:738, 742` +### 16. `WorkspaceBaseEnvironment.creatorUserId` / `lastUpdatedUserId` — verb tense inconsistency — `model.ts:729, 733` - **Why weird:** `creatorUserId` (noun: "the creator's id") vs `lastUpdatedUserId` (past-participle of verb-phrase: "the last-updated user's id"). The pair should agree. Symmetric pairs would be `creatorUserId`/`updaterUserId`, or `createdByUserId`/`lastUpdatedByUserId`. - **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action verbs). - **Suggested name:** Pick one form for both: `createdByUserId` / `updatedByUserId`, or `creatorUserId` / `updaterUserId`. - **Rationale:** Internal consistency. As written, the noun↔verb mismatch reads oddly when sorted in IDE auto-complete. -### 20. `CreateWorkspaceBaseEnvironmentRequest.workspaceBaseEnvironmentId` — 27-character optional string field — `model.ts:552` -- **Why weird:** Field name `workspaceBaseEnvironmentId` is the type name + `Id` suffix. On a `CreateWorkspaceBaseEnvironment*Request*` it is redundant — every field on a create request already pertains to a workspace base environment. Compare `requestId` (model.ts:557) on the same type, which is correctly scoped (`request`+`Id`, not `createWorkspaceBaseEnvironmentRequestRequestId`). +### 17. `CreateWorkspaceBaseEnvironmentRequest.workspaceBaseEnvironmentId` — 27-character optional string field — `model.ts:543` +- **Why weird:** Field name `workspaceBaseEnvironmentId` is the type name + `Id` suffix. On a `CreateWorkspaceBaseEnvironment*Request*` it is redundant — every field on a create request already pertains to a workspace base environment. Compare `requestId` (model.ts:548) on the same type, which is correctly scoped (`request`+`Id`, not `createWorkspaceBaseEnvironmentRequestRequestId`). - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `environmentId`, `id`, or `resourceId`. - **Rationale:** Consumers writing `{workspaceBaseEnvironment: env, workspaceBaseEnvironmentId: 'foo'}` is awkward; `{environment: env, environmentId: 'foo'}` reads better. -### 21. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:715` -- **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:715) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 720) is documented and even references `name`: "The name field is used to identify the environment to update." +### 18. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:706` +- **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:706) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 711) is documented and even references `name`: "The name field is used to identify the environment to update." - **Category:** 19 (underspecified ID), 6 (misleading by omission). - **Suggested name:** Add JSDoc. The field is the resource name to update; say so. Or drop the field entirely if it duplicates `workspaceBaseEnvironment.name`. - **Rationale:** Inconsistent doc coverage in a generated file is a tell that the source proto field has no comment — should be fixed upstream. +### 19. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` +- **Why weird:** The mid-position word `Service` in `DatabricksServiceExceptionWithDetailsProto` describes a server-side architectural layer ("a service threw this exception"), not anything about the data the type carries. The type is a plain error payload with `errorCode`/`message`/`stackTrace`/`details`; no field references a "service". `Service` here mirrors the Java `*ServiceException` superclass pattern and the proto message name `DatabricksServiceExceptionWithDetails` — both server-internal concepts that have no meaning for a TS SDK consumer. Combined with the trailing `Proto` (codegen origin) the name is a stack of three architectural tags: `Service` (layer) + `Exception` (Java throwable) + `Proto` (wire format). +- **Category:** proto-architectural-leak (mid-position `Service` is not the domain), 14 (Java-style naming), 20 (`Proto` suffix tautology). +- **Suggested name:** `DatabricksErrorDetails`, `ServiceErrorPayload` is still leaky; prefer `ApiErrorDetails` or `RpcErrorDetails` if the gRPC framing is part of the public contract, otherwise just `ErrorDetails`/`DatabricksError`. Drop `Service`, `Exception`, and `Proto` together. +- **Rationale:** The proto-architectural-leak audit treats mid-position `Service` as a server-implementation tell that leaks into TS surfaces. Even setting aside the existing `Proto`/`Exception` complaints (#7), the `Service` infix on a *data* type tells the consumer nothing useful and reinforces the impression that the SDK exposes server internals. The unmarshal schema (`model.ts:757`) propagates the same name; renaming the type renames its schema. + --- ## Low severity -### 22. `WorkspaceBaseEnvironmentProvider` — name says "Provider" but values are "ADMIN" / "DATABRICKS" — `model.ts:517` -- **Why weird:** The enum's name describes a *role* dimension ("who provides this"), but the values are not consistent in part-of-speech: `ADMIN` is a noun-role-type, `DATABRICKS` is an organization name. The docstring at model.ts:516 says "Identifies *who* provides and manages a WorkspaceBaseEnvironment" — and the docstring for `ADMIN` says "Created and managed by workspace admins". So `Provider` is really `Owner` or `ProvidedBy`. Mixing `ADMIN` (a role) with `DATABRICKS` (a company) is the same kind of category-mixing as `User` / `System`. -- **Category:** 17 (inconsistency within the enum), 6 (slight misnomer). -- **Suggested name:** `WorkspaceBaseEnvironmentOwner` or `BaseEnvironmentProvidedBy`. Values: `Admin | DatabricksManaged`. -- **Rationale:** Minor. The intent is clear from context. - -### 23. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:750` -- **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:750). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:573) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. +### 20. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` +- **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:741). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:564) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. - **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). - **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. - **Rationale:** Two representations of "is this the default" invite drift. -### 24. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:628` +### 21. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:619` - **Why weird:** Page-size doc says only "Default is 1000". No documented min/max, no behavior on `0`, no behavior on values exceeding server cap. - **Category:** 19 (underspecified). - **Suggested name:** Add doc bounds. - **Rationale:** Doc-only nit; not a name issue per se but worth flagging in a naming audit because `pageSize` is a known naming convention with known semantics that this doc partially undermines. -### 25. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:638` +### 22. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:629` - **Why weird:** Field name is 27 characters; type is a list of 27-character-typed items. Reading `resp.workspaceBaseEnvironments?.[0]?.workspaceBaseEnvironment...` is a chore. (No sub-field of this exact name; included to illustrate the chain length.) - **Category:** 7 (overly verbose), 8 (redundant suffix — same as the type name pluralised). - **Suggested name:** `environments` (the response type is already `ListWorkspaceBaseEnvironmentsResponse`, so the plural field doesn't need to re-state the qualifier). Wire stays `workspace_base_environments`. - **Rationale:** Matches the `clusterlibraries`/`database` audit critique that list responses don't need to repeat their qualifier. -### 26. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:555` +### 23. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:545` - **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. - **Category:** 19 (underspecified), 6 (slightly misleading). - **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. - **Rationale:** Doc-implied invariants that aren't in the type. -### 27. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:740, 744` -- **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #19) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. +### 24. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:731, 735` +- **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #17) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. - **Category:** 14 (Google-AIP/Go-style), 13 (verb tense inconsistency), 17 (inconsistent with `lastUpdated` sibling). - **Suggested name:** `createdAt` / `updatedAt`, or align with `creator`/`lastUpdater` — pick one verb tense and apply across the type. - **Rationale:** Stylistic; consistent with the broader codebase critique. -### 28. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:734` -- **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:552) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. +### 25. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:725` +- **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:543) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. - **Category:** 19 (underspecified), 1 (slightly generic). - **Suggested name:** Keep but document constraints. - **Rationale:** Minor. -### 29. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:736` +### 26. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:727` - **Why weird:** Doc says "The WSFS or UC Volumes path to the environment YAML file." But the field is `string`. WSFS paths and UC Volume paths have different syntaxes (`/Workspace/...` vs `/Volumes/...`). The type permits any string. A union of the two path types would be more precise but probably not worth the porting effort. - **Category:** 19 (underspecified — the doc lists two valid path types but the type doesn't distinguish). -- **Suggested name:** Keep `filepath`/`filePath` (see #16), but document the allowed prefixes. +- **Suggested name:** Keep `filepath`/`filePath` (see #14), but document the allowed prefixes. - **Rationale:** Minor. --- ## Observation -### 30. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` +### 27. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` - **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. - **Category:** 12 (duplicate concept), 6 (misleading lineage signal). - **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. - **Rationale:** Generator-level; not actionable in TS alone, but worth recording. -### 31. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` +### 28. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` - **Why noteworthy:** The comment on `BaseEnvironmentType` references an internal proto path that public SDK consumers cannot see, cannot navigate to, and have no use for. It's a generator-cycle reminder to Databricks engineers that shouldn't have made it through the porting/codegen scrub. - **Category:** 6 (misleading — refers to a non-public artefact in a doc comment public users see). - **Suggested action:** Strip internal references from generated comments at codegen time. - **Rationale:** SDK hygiene; not a name issue but worth flagging in the audit since the comment is on a *public* type. + +--- + +## Fixed + +- #10 `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` (originally cited at `model.ts:518`): Fixed in regeneration on 2026-05-20 — the `WorkspaceBaseEnvironmentProvider` enum was removed from the source. +- #22 `WorkspaceBaseEnvironmentProvider` Admin/Databricks part-of-speech mix (originally cited at `model.ts:517`): Fixed in regeneration on 2026-05-20 — the `WorkspaceBaseEnvironmentProvider` enum and the `baseEnvironmentProvider` field on `WorkspaceBaseEnvironment` were removed from the source. diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index 307aa92b..f427d60f 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -3,25 +3,25 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 **Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 53 +**Total weird names flagged:** 48 ## Summary | Severity | Count | | --- | --- | -| High | 15 | -| Medium | 24 | +| High | 13 | +| Medium | 22 | | Low | 9 | -| Observation | 5 | +| Observation | 4 | ## High severity ### 1. Package name `experiments` is too generic — `packages/experiments/` -- **Why weird:** The package is the MLflow Experiment Tracking API surface, but the package name says only "experiments". Other Databricks SDK packages own equally fuzzy nouns (`apps`, `catalogs`, `database`, `cleanrooms`) — so a reader cannot tell from `@databricks/sdk-experiments` that this is MLflow. The folder contains MLflow `Run`, `Metric`, `Param`, `Tag`, `LoggedModel` — none of which a typical Databricks user thinks of as "experiments" first. Every URL the client builds is `/api/2.0/mlflow/…` (`client.ts:206,232,262,291,317,342,370,399,428,454,483,522,556,581,615,677,717,774,869,895,925,958,988,1014,1044,1076,1106,1135,1161,1204,1237,1280,1306,1335,1361,1387`). +- **Why weird:** The package is the MLflow Experiment Tracking API surface, but the package name says only "experiments". Other Databricks SDK packages own equally fuzzy nouns (`apps`, `catalogs`, `database`, `cleanrooms`) — so a reader cannot tell from `@databricks/sdk-experiments` that this is MLflow. The folder contains MLflow `Run`, `Metric`, `Param`, `Tag`, `LoggedModel` — none of which a typical Databricks user thinks of as "experiments" first. Every URL the client builds is `/api/2.0/mlflow/…`. - **Category:** 1 (generic), 6 (misleading: name does not say MLflow). - **Suggested name:** `mlflow`, `mlflow-tracking`, or `mlflow-experiments`. At minimum, add a JSDoc on `index.ts` saying "MLflow tracking — experiments, runs, logged models". -- **Rationale:** Every other identifier inside the package treats MLflow as the controlling brand (`mlflowParam`, `mlflowMetric`, `mlflowRunTag` appear in docstrings at `client.ts:256,1231`). The package name buries that. +- **Rationale:** Every other identifier inside the package treats MLflow as the controlling brand (`mlflowParam`, `mlflowMetric`, `mlflowRunTag` appear in docstrings). The package name buries that. -### 2. `Run` — `src/v1/model.ts:712` +### 2. `Run` — `src/v1/model.ts:701` - **Why weird:** The central noun is named `Run`. `Run` is a reserved-feeling word in any JS context: `Promise.all().run()`, test framework "runs", workflow "runs". The user has zero context that this is an MLflow Run (a tracked execution of a training/eval script with metrics/params/artifacts). Compare with `jobs.Run` (already a different concept in this SDK) and `pipelines.Run`. - **Category:** 1 (vague/generic), 12 (duplicate concept across packages — `jobs.Run`, `pipelines.Run`), 15 (generic field/type name losing meaning). - **Suggested name:** `MlflowRun` or `ExperimentRun`. Re-export the alias and deprecate `Run`. @@ -33,181 +33,159 @@ - **Suggested name:** `MlflowExperiment`. - **Rationale:** Same as #2 — disambiguating the package's central noun against future Databricks "experiments" features prevents conflicts. -### 4. `Metric` / `Param` / `Run` / `Experiment` — all single-word top-level types — `src/v1/model.ts:219,623,667,712` +### 4. `Metric` / `Param` / `Run` / `Experiment` — all single-word top-level types — `src/v1/model.ts:219,612,656,701` - **Why weird:** Four central types are bare nouns (`Metric`, `Param`, `Run`, `Experiment`). All four will collide with names in scope at the user's call site. None says "MLflow". `Param` in particular collides with React Router `Params`, Express `Params`, Node `URLSearchParams`, etc. - **Category:** 1 (vague), 10 (reserved-word adjacent), 12 (duplicate concept against React/Node `Params`). - **Suggested name:** `MlflowMetric`, `MlflowParam`, `MlflowRun`, `MlflowExperiment` — or namespace under `Mlflow.{Metric, Param, Run, Experiment}`. - **Rationale:** Even MLflow's own protobuf calls these `mlflow.Run`, `mlflow.Experiment`, `mlflow.Metric` — they assume a namespace. Flattening them into TS without one loses that disambiguation. -### 5. `LoggedModel` — `src/v1/model.ts:560` +### 5. `LoggedModel` — `src/v1/model.ts:549` - **Why weird:** `LoggedModel` is a noun-phrase made of past-participle adjective + noun. The "logged" prefix is doing the disambiguation against `RegisteredModel`, `ServingModel`, `MlflowModel` etc. But (a) past-tense adjectives in type names read awkwardly (`LoggedModel`, `DeletedExperiment`, `FinishedRun` would all be similarly weird), and (b) `Logged` does not describe what the type *is* — it describes the verb history that produced it. - **Category:** 6 (misleading: "Logged" describes history, not identity), 13 (verb-tense in noun-phrase). - **Suggested name:** `MlflowModel`, `TrackedModel`, or `RunModel` (since every `LoggedModel` belongs to a Run via `sourceRunId`). - **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #6). -### 6. `LoggedModel` family — 8 separate types — `src/v1/model.ts:560, 568, 579, 607, 615` + 4 request/response — `model.ts:72, 161, 169, 257, 303, 314, 475, 932` -- **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModel`, `DeleteLoggedModel`, `DeleteLoggedModelTag`, `FinalizeLoggedModel`, `GetLoggedModel`, `GetLoggedModelsRequest`, `LogLoggedModelParamsRequest`, `SetLoggedModelTags`, `SearchLoggedModels`. The `LoggedModel` prefix is repeated 14 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. +### 6. `LoggedModel` family — many separate types — `src/v1/model.ts:549, 557, 568, 596, 604` + request/response — `model.ts:72, 161, 169, 257, 303, 464, 803, 921` +- **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModelRequest`, `DeleteLoggedModelRequest`, `DeleteLoggedModelTagRequest`, `FinalizeLoggedModelRequest`, `GetLoggedModelRequest`, `LogLoggedModelParamsRequest`, `SearchLoggedModelsRequest`, `SetLoggedModelTagsRequest`. The `LoggedModel` prefix is repeated 13 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. - **Category:** 7 (overly verbose), 12 (duplicate concept against `Model*` family that may exist in `modelregistry` package). - **Suggested name:** Either drop the `Logged` and call the family `MlflowModel` / `MlflowModelData` / `MlflowModelInfo` / `MlflowModelParameter` / `MlflowModelTag` / `MlflowModelStatus`, or nest under a namespace. -- **Rationale:** 14 occurrences of "LoggedModel" in 12 identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. +- **Rationale:** 13 occurrences of "LoggedModel" in identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. -### 7. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:607` vs `model.ts:667` -- **Why weird:** Two distinct types both model `{key: string, value: string}` parameter pairs: `LoggedModelParameter` (for a `LoggedModel`) and `Param` (for a `Run`). JSDoc at line 606-612 says "Parameter associated with a `LoggedModel`" and at 666-672 "Param associated with a run". Why one type is spelled out (`Parameter`) and the other abbreviated (`Param`) is unexplained. +### 7. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:596` vs `model.ts:656` +- **Why weird:** Two distinct types both model `{key: string, value: string}` parameter pairs: `LoggedModelParameter` (for a `LoggedModel`) and `Param` (for a `Run`). JSDoc at line 595 says "Parameter associated with a `LoggedModel`" and at 655 "Param associated with a run". Why one type is spelled out (`Parameter`) and the other abbreviated (`Param`) is unexplained. - **Category:** 12 (duplicate concept), 17 (inconsistent abbreviation: `Parameter` vs `Param`). - **Suggested name:** Align the abbreviation: either both `Parameter` or both `Param`. - **Rationale:** The difference between `Run.params: Param[]` and `LoggedModel.data.params: LoggedModelParameter[]` is cosmetic — the underlying shape is identical. -### 8. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 374, 615, 775` +### 8. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 364, 604, 765` - **Why weird:** Four `{key: string, value: string}` types, one per parent entity. All four have identical shapes. The only differentiator is the parent entity — but the type itself is indistinguishable. - **Category:** 12 (duplicate concept × 4). - **Suggested name:** Adopt a single parent prefix convention so `MlflowTag` (or `Mlflow.Tag`) carries the shared shape, with parent-specific variants only when fields actually diverge. - **Rationale:** An end-user picking the wrong tag type (`InputTag` vs `RunTag` etc.) will not get a compile error because they have the same shape. -### 9. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:712, 722, 732, 768` -- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:721-729`), `RunInfo` is "id, name, status, times, user" (`model.ts:732-765`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:768-773`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. +### 9. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:701, 711, 721, 757` +- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:710-718`), `RunInfo` is "id, name, status, times, user" (`model.ts:720-754`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:756-762`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. - **Category:** 1 (vague: `Data`/`Info`/`Inputs`), 15 (generic field name). - **Suggested name:** Flatten into `Run` (one object). If they must stay split, name them by content: `RunMetadata` (instead of `RunInfo`), `RunMeasurements` (instead of `RunData`), `RunDatasetsAndModels` (instead of `RunInputs`). - **Rationale:** `RunInfo` vs `RunData` requires the reader to look up the schema to know which fields go where. Naming by content removes that lookup. -### 10. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:579, 568` +### 10. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:568, 557` - **Why weird:** Same `Info`/`Data` split as `Run` (#9). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. - **Rationale:** Same as #9. -### 11. `GetLoggedModelsRequest` — only request type with a `Request` suffix — `src/v1/model.ts:314, client.ts:578` -- **Why weird:** Every other request type drops the `Request` suffix: `GetExperiment`, `GetRun`, `CreateRun`, `DeleteRuns`, `SearchRuns`, etc. Then `GetLoggedModelsRequest` breaks the pattern. `LogLoggedModelParamsRequest` (model.ts:475) breaks it the same way. -- **Category:** 17 (inconsistent action verbs / suffix policy), 7 (verbose). -- **Suggested name:** `GetLoggedModels`. `LogLoggedModelParams`. -- **Rationale:** Inconsistency within the same file — most request types use the bare verb-noun form, and these two are the outliers. - -### 12. `LoggedModelStatus` enum members all prefixed `LOGGED_MODEL_` — `src/v1/model.ts:9-23` -- **Why weird:** Enum `LoggedModelStatus` has members `LOGGED_MODEL_STATUS_UNSPECIFIED`, `LOGGED_MODEL_PENDING`, `LOGGED_MODEL_READY`, `LOGGED_MODEL_UPLOAD_FAILED`. The enum is already `LoggedModelStatus` — every member re-states `LOGGED_MODEL_`. The first member doubles down: `LOGGED_MODEL_STATUS_UNSPECIFIED`. The others lose the `STATUS_` infix but still keep `LOGGED_MODEL_`. -- **Category:** 2 (redundant enum prefix), 17 (inconsistency: only `UNSPECIFIED` carries the full `LOGGED_MODEL_STATUS_` prefix), 18 (long enum values). -- **Suggested name:** `LoggedModelStatus.Unspecified | Pending | Ready | UploadFailed`. Or drop `Unspecified` entirely (TS supports optional fields natively). -- **Rationale:** `LoggedModelStatus.LOGGED_MODEL_UPLOAD_FAILED` reads as "logged model status: logged model upload failed" — the type name is repeated twice. Inconsistent prefix between `UNSPECIFIED` and the rest is jarring. - -### 13. `RunStatus` enum has no `UNSPECIFIED` value — inconsistent with `LoggedModelStatus` and `ViewType` — `src/v1/model.ts:26-37` -- **Why weird:** Two of the three enums in the file follow the proto-style "include UNSPECIFIED sentinel" pattern. `RunStatus` does not. Five values: `RUNNING`, `SCHEDULED`, `FINISHED`, `FAILED`, `KILLED`. Either the Run state machine has no "unknown" — fine — but the inconsistency reduces grep-ability. +### 11. `RunStatus` enum has no `UNSPECIFIED` zero value — inconsistent with `LoggedModelStatus` — `src/v1/model.ts:26-37` +- **Why weird:** `LoggedModelStatus` carries `LOGGED_MODEL_STATUS_UNSPECIFIED` as its zero value (proto3 requirement). `RunStatus` does not — its five values are `RUNNING`, `SCHEDULED`, `FINISHED`, `FAILED`, `KILLED`, no `RUN_STATUS_UNSPECIFIED`. Sibling enums in the same file disagree on whether the proto3 zero-value sentinel surfaces. - **Category:** 17 (inconsistency across enums in same file). -- **Suggested name:** Either drop `UNSPECIFIED` from `LoggedModelStatus` and `ViewType` too (best — TS uses `undefined`), or add `RunStatus.UNSPECIFIED` for symmetry. -- **Rationale:** Pick one policy. Sibling enums disagreeing on the sentinel makes patterns hard to learn. +- **Suggested name:** Add `RunStatus.RUN_STATUS_UNSPECIFIED` for symmetry with `LoggedModelStatus`. (`ViewType` similarly lacks one but is filter-shaped, less critical.) +- **Rationale:** Proto3 mandates a zero-value enum member, so UNSPECIFIED is intentional — but it should appear uniformly across sibling enums so users can rely on the same pattern. -### 14. `KILLED` enum value — `src/v1/model.ts:36` +### 12. `KILLED` enum value — `src/v1/model.ts:36` - **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." - **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). - **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. - **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). -### 15. `ViewType` enum — generic name + redundant value names — `src/v1/model.ts:40-47` -- **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). Three values are `ACTIVE_ONLY`, `DELETED_ONLY`, `ALL` — all SCREAMING_SNAKE_CASE TS identifiers when most TS enums use PascalCase. Plus `ALL` is a built-in reserved-feeling word and a poor key. The same enum is used as `viewType` on `ListExperiments` (model.ts:416), `runViewType` on `SearchRuns` (model.ts:897), and `viewType` on `SearchExperiments` (model.ts:800) — two fields named `viewType` and one named `runViewType` for the same enum. +### 13. `ViewType` enum — generic name + inconsistent field names for the same enum — `src/v1/model.ts:40-47` +- **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). The same enum is used as `viewType` on `ListExperimentsRequest` (model.ts:405), `runViewType` on `SearchRunsRequest` (model.ts:886), and `viewType` on `SearchExperimentsRequest` (model.ts:789) — two fields named `viewType` and one named `runViewType` for the same enum. - **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). -- **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Values: `ActiveOnly | DeletedOnly | All`. Field name: pick one (`viewType` everywhere, or rename uniformly). +- **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Field name: pick one (`viewType` everywhere, or rename uniformly). - **Rationale:** A field that means "filter experiments/runs by deleted state" is more searchable as `lifecycleFilter`. ## Medium severity -### 16. `GetLoggedModels` method returns request type with `Request` suffix — `src/v1/client.ts:577-608` -- **Why weird:** The method is `getLoggedModels(req: GetLoggedModelsRequest)`. Method name has no `Request` suffix, but the parameter type does. Compare to `getExperiment(req: GetExperiment)` two methods up. Same problem with `logLoggedModelParams(req: LogLoggedModelParamsRequest)` (`client.ts:921`). -- **Category:** 17 (inconsistency). -- **Suggested name:** Drop the `Request` suffix on the type names to match the method names. Already raised in #11. - -### 17. `getMetricHistory` / `GetMetricHistory` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:325, client.ts:611` -- **Why weird:** Type name `GetMetricHistory` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRun`, `DeleteExperiment`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". +### 14. `getMetricHistory` / `GetMetricHistoryRequest` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:314, client.ts:594` +- **Why weird:** Type name `GetMetricHistoryRequest` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRunRequest`, `DeleteExperimentRequest`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". - **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). -- **Suggested name:** `GetMetricValues` / `getMetricValues`, or `ListMetricHistory` / `listMetricHistory` (since it paginates). +- **Suggested name:** `GetMetricValuesRequest` / `getMetricValues`, or `ListMetricHistoryRequest` / `listMetricHistory` (since it paginates). - **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. -### 18. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:978-984` -- **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModel` and `LogModel_Response`. The method `createLoggedModel` is the replacement. +### 15. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:973-979` +- **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModelRequest` and `LogModelRequest_Response`. The method `createLoggedModel` is the replacement. - **Category:** 6 (misleading — exported as if it were current). -- **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModel`, `LogModel_Response`. +- **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModelRequest`, `LogModelRequest_Response`. - **Rationale:** A linter or IDE that reads `@deprecated` will warn users; a plaintext note in the markdown JSDoc body will not. -### 19. `runUuid` deprecated field appears on 6 types — `src/v1/model.ts:332, 365, 389, 492, 546, 739, 949, 976` -- **Why weird:** Eight different types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. +### 16. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` +- **Why weird:** Multiple types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. - **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). - **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. - **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. -### 20. `userId` deprecated — `src/v1/model.ts:101, 749` -- **Why weird:** Same problem as #19 but for `userId` on `CreateRun.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. +### 17. `userId` deprecated — `src/v1/model.ts:101, 738` +- **Why weird:** Same problem as #17 but for `userId` on `CreateRunRequest.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. - **Category:** 6. -- **Suggested name:** Add `@deprecated`. Same as #19. +- **Suggested name:** Add `@deprecated`. Same as #16. -### 21. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 587-589` +### 18. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 576-578` - **Why weird:** `Experiment` uses `lastUpdateTime` and `creationTime` (no unit suffix). `LoggedModelInfo` uses `creationTimestampMs` and `lastUpdatedTimestampMs` (with unit suffix). Both are Unix ms timestamps. Three things vary: (a) `Time` vs `Timestamp`, (b) `Update` vs `Updated`, (c) presence of `Ms` unit suffix. - **Category:** 17 (inconsistency in field naming for the same concept), 3 (casing inconsistency), 9 (singular/plural-ish noun tense `Update` vs `Updated`). - **Suggested name:** Pick one: `createdAt` / `updatedAt` (typical JS), or `creationTimeMs` / `lastUpdateTimeMs` (explicit unit). Match across `Experiment`, `LoggedModelInfo`, `RunInfo`, etc. - **Rationale:** Three timestamp formats in one package means users guess which type uses which. -### 22. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:753, 755` +### 19. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:742, 744` - **Why weird:** Adds a fourth timestamp naming style to the package: bare `startTime` / `endTime` with no unit. JSDoc says "Unix timestamp of when the run started in milliseconds" — buried in prose. - **Category:** 17 (inconsistency). -- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #21. +- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #18. -### 23. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 697` -- **Why weird:** Fifth style: `DeleteRuns.maxTimestampMillis` and `RestoreRuns.minTimestampMillis` use `Millis` suffix (not `Ms`, not unsuffixed). Same package. Five different naming choices for unix-ms timestamps: `creationTime`, `lastUpdateTime`, `startTime`/`endTime`, `creationTimestampMs`/`lastUpdatedTimestampMs`, `maxTimestampMillis`/`minTimestampMillis`. +### 20. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 686` +- **Why weird:** Fifth style: `DeleteRunsRequest.maxTimestampMillis` and `RestoreRunsRequest.minTimestampMillis` use `Millis` suffix (not `Ms`, not unsuffixed). Same package. Five different naming choices for unix-ms timestamps: `creationTime`, `lastUpdateTime`, `startTime`/`endTime`, `creationTimestampMs`/`lastUpdatedTimestampMs`, `maxTimestampMillis`/`minTimestampMillis`. - **Category:** 17 (inconsistency × 5), 3 (casing inconsistency — `Ms` vs `Millis`). - **Suggested name:** Pick one suffix (`Ms` is common, `Millis` is rarer) and apply uniformly. -- **Rationale:** Same as #21. +- **Rationale:** Same as #18. -### 24. `creatorId: number` (not string) — `src/v1/model.ts:595` +### 21. `creatorId: number` (not string) — `src/v1/model.ts:584` - **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." - **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). - **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. - **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). -### 25. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout -- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:622`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#24). +### 22. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout +- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:612`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#22). - **Category:** 19 (underspecified IDs coexist), 16 (`creatorId` is `number`, others `string`). - **Suggested name:** Add prefix discipline: the model's own ID is `id` (or `modelId` everywhere); a referenced ID is `Id` (`sourceRunId`, `parentExperimentId`). Document the convention. - **Rationale:** Today, every type has its own private convention; users must check each schema. -### 26. `modelId` ambiguity in `Metric` — `src/v1/model.ts:643-647` +### 23. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` - **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. - **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). - **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). - **Rationale:** Heterogeneous string ID fields are debugging traps. -### 27. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:560-565, 579-583` +### 24. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` - **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#10) buries the ID one level deep. - **Category:** 15 (generic field name losing meaning), 7 (verbose access). - **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). - **Rationale:** Awkward access pattern. -### 28. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:741, 583` +### 25. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:730, 572` - **Why weird:** Two fields named `experimentId`, two completely different relationships. On `RunInfo` the field connects the run to its parent experiment. On `LoggedModelInfo` it connects the model to its owning experiment. JSDoc only on one of them. - **Category:** 15 (generic name losing meaning across contexts). - **Suggested name:** Both are fine as `experimentId` if doc consistently says "parent experiment". The issue is uneven JSDoc. -### 29. Method names `getLoggedModels` / `getLoggedModelsRequest` mismatch — type is `GetLoggedModelsRequest`, method is `getLoggedModels` — `src/v1/client.ts:577` -- **Why weird:** Caller writes `client.getLoggedModels({...})` — but the type the request maps to is `GetLoggedModelsRequest`. Looking at the method name alone you wouldn't guess the type carries the `Request` suffix. -- **Category:** 17 (inconsistency). -- **Suggested name:** Already covered by #11 — drop `Request`. - -### 30. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:475` -- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:921`). +### 26. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` +- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:916`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). -- **Suggested name:** `AddMlflowModelParams` + `addMlflowModelParams`, or `LogParamsForModel` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParams`. +- **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParamsRequest`. - **Rationale:** The double-Log is jarring on read. -### 31. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1276, 1302` -- **Why weird:** `setExperimentTag(req: SetExperimentTag)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTags)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. +### 27. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` +- **Why weird:** `setExperimentTag(req: SetExperimentTagRequest)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTagsRequest)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 32. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` +### 28. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` - **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. - **Category:** Observation (URL design upstream). -### 33. `logBatch` does not say "log run batch" — `src/v1/client.ts:865` +### 29. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 34. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 30. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -221,84 +199,88 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 35. `LogInputs.datasets` vs `LogInputs.models` field names — `src/v1/model.ts:463-470` +### 31. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` - **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. - **Category:** 15 (generic field name losing structure). -### 36. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:770, 772` +### 32. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:759, 761` - **Why weird:** `RunInputs.datasetInputs: DatasetInput[]` and `RunInputs.modelInputs: ModelInput[]`. The field name and the element type both carry `Input`. So a user reads `runInputs.datasetInputs[0].tags` — the word "input" appears three times in a single access path. - **Category:** 20 (suffix tautology), 7 (verbose). - **Suggested name:** `RunInputs.datasets: DatasetInput[]` and `RunInputs.models: ModelInput[]`. -### 37. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` +### 33. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` - **Why weird:** Both fields are typed `string` and named with generic English words. JSDoc shows the wire format is freeform JSON-stringified content. The field types don't help. - **Category:** 15 (generic field name losing meaning), 6 (misleading: schema is freeform stringified JSON, not a real schema). -- **Suggested name:** `schemaJson` / `profileJson` (mirrors `LogModel.modelJson`) so the user knows to JSON-parse them. Already see the pattern at `LogModel.modelJson` (model.ts:523). +- **Suggested name:** `schemaJson` / `profileJson` (mirrors `LogModelRequest.modelJson`) so the user knows to JSON-parse them. Already see the pattern at `LogModelRequest.modelJson` (model.ts:512). -### 38. `LogModel.modelJson` — bare json string field — `src/v1/model.ts:519-524` -- **Why weird:** `LogModel.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. +### 34. `LogModelRequest.modelJson` — bare json string field — `src/v1/model.ts:508-513` +- **Why weird:** `LogModelRequest.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. - **Category:** Observation (an opaque blob field could carry doc). -### 39. `Dataset.digest` — `src/v1/model.ts:124-124` +### 35. `Dataset.digest` — `src/v1/model.ts:124` - **Why weird:** `digest` is technical jargon (cryptographic hash). MLflow uses it; consumers may not. JSDoc: "Dataset digest, e.g. an md5 hash". Could be `contentHash` or `fingerprint`. - **Category:** 5 (cryptic abbreviation — `digest` is industry-specific). ## Low severity -### 40. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:764` +### 36. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:753` - **Why weird:** `RunInfo.lifecycleStage` JSDoc says: "Current life cycle stage of the experiment : OneOf("active", "deleted")". But this is a `Run`'s `lifecycleStage`, not the experiment's. Same field on `Experiment.lifecycleStage` (model.ts:230) is correctly described. - **Category:** 6 (misleading doc — wrong entity name in description). - **Suggested name:** Fix doc to say "Current life cycle stage of the run". -### 41. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 603, 728` +### 37. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` - **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #8. The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 42. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 38. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 43. `FileInfo` itself is a generic name — `src/v1/model.ts:247` +### 39. `FileInfo` itself is a generic name — `src/v1/model.ts:248` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. -### 44. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` +### 40. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` - **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. - **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). - **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). -### 45. `HttpCallOptions` — `src/v1/utils.ts:15` +### 41. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). - **Category:** 17 (collision risk with `CallOptions`). -### 46. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` +### 42. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` - **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) - **Category:** Observation (dead export). -### 47. `PACKAGE_SEGMENT` constant in `client.ts:164` — `src/v1/client.ts:164` +### 43. `PACKAGE_SEGMENT` constant in `client.ts:161` — `src/v1/client.ts:161` - **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. - **Category:** 17 (inconsistency in identifier case across the file). - **Suggested name:** `packageSegment` per TS conventions. -### 48. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:165` +### 44. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:162` - **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. - **Category:** 1 (generic name leaking into observability). ## Observations (non-actionable but noted) -### 49. `getLoggedModels` (batch get) has no `*Iter` — `src/v1/client.ts:577` -- **Note:** A batch endpoint that takes a list of IDs and returns a list. No pagination → no `Iter`. Fine. Worth noting that this is `getLoggedModels` (plural) — but `getLoggedModel` (singular, line 552) is the single-fetch. Two methods that differ only by `s` is grep-hostile. - -### 50. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 504, 633` -- **Note:** JSDoc on `Dataset.name`, `LogMetric.datasetName`, `Metric.datasetName` includes the literal example `“fantastic-elk-3”` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. +### 45. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 494, 622` +- **Note:** JSDoc on `Dataset.name`, `LogMetricRequest.datasetName`, `Metric.datasetName` includes the literal example `"fantastic-elk-3"` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. -### 51. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-129` +### 46. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-130` - **Note:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. -### 52. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +### 47. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` - **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. -### 53. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` +### 48. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` - **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). + +## Fixed + +- #11 `GetLoggedModelsRequest` being the only request type with a `Request` suffix (originally cited at `src/v1/model.ts:314, client.ts:578`): Fixed in regeneration on 2026-05-20 — all request types now uniformly carry the `Request` suffix; the plural batch type was also removed entirely. +- #16 `GetLoggedModels` method returns request type with `Request` suffix (originally cited at `src/v1/client.ts:577-608`): Fixed in regeneration on 2026-05-20 — the universal `Request` suffix on every request type makes the original method/type inconsistency moot, and the `getLoggedModels` plural method was removed. +- #29 Method names `getLoggedModels` / type `GetLoggedModelsRequest` mismatch (originally cited at `src/v1/client.ts:577`): Fixed in regeneration on 2026-05-20 — the plural batch method and its `GetLoggedModelsRequest` type were removed entirely. +- #49 `getLoggedModels` (batch get) has no `*Iter` (originally cited at `src/v1/client.ts:577`): Fixed in regeneration on 2026-05-20 — the plural batch endpoint no longer exists. diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index a21a28bc..4fbceb65 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -3,61 +3,55 @@ **Path:** `packages/externallineage/src/v1/` **Versions audited:** v1 **Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 25 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | -| High | 8 | +| High | 7 | | Medium | 7 | | Low | 8 | | Observation | 2 | ## High severity -### 1. `SystemType.SYSTEM_TYPE_UNSPECIFIED` and 22 other SCREAMING_SNAKE values — `src/v1/model.ts:8-33` -- **Why weird:** Every enum value is SCREAMING_SNAKE_CASE and the sentinel re-states the enum name (`SystemType.SYSTEM_TYPE_UNSPECIFIED`). The remaining 22 values include long product names (`MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`) that are sometimes split on underscores in a way that conflicts with how the rest of the SDK casefolds acronyms (e.g., `POWER_BI` vs. `POWERBI`). -- **Category:** 2 (redundant enum prefix on `SYSTEM_TYPE_UNSPECIFIED`), 3 (acronym casing — `POWER_BI` vs `MICROSOFT_FABRIC`), 18 (long enum values). -- **Suggested name:** `SystemType.Tableau`, `SystemType.PowerBI`, `SystemType.SqlServer`, `SystemType.Redshift`, etc., dropping `Unspecified`. -- **Rationale:** TS enum values are namespaced by the enum (`SystemType.Tableau`). SCREAMING_SNAKE_CASE forces callers to shout every value; idiomatic TS uses PascalCase enum members (see TypeScript handbook on enums and the Google TypeScript style guide). - -### 2. `CreateRequestExternalLineage` / `DeleteRequestExternalLineage` / `UpdateRequestExternalLineage` — `src/v1/model.ts:51, 74, 238` +### 1. `CreateRequestExternalLineage` / `DeleteRequestExternalLineage` / `UpdateRequestExternalLineage` — `src/v1/model.ts:51, 74, 238` - **Why weird:** Word-order inversion `Request` + entity instead of entity + `Request`. Every other request type in this package (`CreateExternalLineageRelationshipRequest`, `DeleteExternalLineageRelationshipRequest`) and across the SDK uses entity-then-`Request`. These three types are the nested *payload* shapes for create/delete/update (wrapped inside `*Request` outer types). All three types are structurally identical to each other AND to `ExternalLineageRelationship` (same five fields: `id`, `source`, `target`, `columns`, `properties`). - **Category:** 12 (duplicate concept — 4 types with the same shape), 17 (verb-position inconsistency with rest of SDK). - **Suggested name:** Rename to entity-first form: `CreateExternalLineagePayload` / `DeleteExternalLineagePayload` / `UpdateExternalLineagePayload`, or align with the outer `*Request` naming. - **Rationale:** The inversion serves no purpose except to differentiate them by name from the outer request types. Entity-first matches the rest of the SDK. -### 3. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` +### 2. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` - **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:563-570` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. - **Category:** 5 (cryptic abbreviation), 10 (reserved-word collision-avoidance). - **Suggested name:** Use a TS discriminated union with `$case` directly (no outer `tpe` field): `ExternalLineageRelationshipObject = {$case: 'table', table: ...} | {$case: 'path', path: ...} | ...`. If the wrapper must stay, name the field `kind` or `objectType`. - **Rationale:** TS allows `type` as a property name, so the cryptic `tpe` solves a problem TS does not have. -### 4. `objectInfo` field of type `ExternalLineageRelationshipObject` — `src/v1/model.ts:216` +### 3. `objectInfo` field of type `ExternalLineageRelationshipObject` — `src/v1/model.ts:216` - **Why weird:** Field is named `objectInfo` but is typed as `ExternalLineageRelationshipObject` (no `Info` in the type). The convention drift means a reader sees `objectInfo: ExternalLineageRelationshipObject` and has to mentally reconcile the two. Note the JSDoc immediately starts talking about a `object_info.table.name=...` query parameter — so on the wire, the prefix really is `object_info`, but in TS the type doesn't end in `Info`. - **Category:** 1 (vague `Info` suffix), 8 (redundant suffix — `Info` adds nothing), 17 (field-name does not match type-name). - **Suggested name:** `object: ExternalLineageRelationshipObject`. (Wire serialisation stays `object_info` to match the API.) - **Rationale:** `Info` is generator filler; the type already describes itself. Field/type-name agreement reduces cognitive load. -### 5. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` +### 4. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` - **Why weird:** Two top-level types share the prefix `ExternalLineage` but mean different things: `ExternalLineageInfo` is a union-of-info "row" that may describe a table, a file, a model version, or an external metadata object plus the edge metadata; `ExternalLineageRelationship` is the edge itself (id, source, target, columns, properties). The JSDoc on `ExternalLineageInfo` says "Lineage response containing lineage information of a data asset" while one of its fields is `externalLineageInfo?: ExternalLineageRelationship` — i.e., an "info" type that *contains* an "info" field whose type ends in `Relationship`. Five fields ending in `Info` (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`, `externalLineageInfo`) on a type also ending in `Info`. This is the heart of the naming muddle. - **Category:** 1 (vague `Info` everywhere), 6 (misleading — `externalLineageInfo` is the edge metadata, not "info about external lineage"), 8 (redundant suffix), 12 (duplicate concept — `ExternalLineageInfo.externalLineageInfo` of type `ExternalLineageRelationship`). - **Suggested name:** `ExternalLineageInfo` → `LineageNode` or `LineageEntry`. `externalLineageInfo` field → `relationship: ExternalLineageRelationship`. The four neighbour fields (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`) become `table`, `file`, `model`, `externalMetadata`. - **Rationale:** "Info" is the generator's escape hatch for "I don't know what to call this". The current shape forces a reader to deduce that one of the `Info` fields is structurally different from the others (it's the edge, not a node). Concrete names break the muddle. -### 6. Mixed `Info` / `Relationship` / `Object` suffix vocabulary — across `src/v1/model.ts` +### 5. Mixed `Info` / `Relationship` / `Object` suffix vocabulary — across `src/v1/model.ts` - **Why weird:** The package mixes three competing nouns for related concepts: `*Info` (LineageTableInfo, LineageFileInfo, LineageModelVersionInfo, LineageExternalMetadataInfo, ExternalLineageInfo), `*Relationship` (ColumnRelationship, ExternalLineageRelationship, plus six `ExternalLineageRelationship*` sub-types), and `*Object` (ExternalLineageRelationshipObject). All three trade off in the same conceptual space. A reader cannot predict which suffix a new sibling type will get. - **Category:** 8 (redundant suffix), 12 (duplicate concept), 17 (inconsistent action-vocabulary). - **Suggested name:** Pick one: prefer no suffix where the noun is concrete (`Table`, `Path`, `ModelVersion`, `ExternalMetadata`), `Relationship` for edges, and drop `Info`/`Object` entirely. - **Rationale:** Three suffixes for related types make the vocabulary feel arbitrary. The Google TypeScript style guide encourages "names should reflect what something is, not its scaffolding". -### 7. `ExternalLineageRelationshipTable` / `ExternalLineageRelationshipPath` / `ExternalLineageRelationshipModelVersion` / `ExternalLineageRelationshipExternalMetadata` — `src/v1/model.ts:158, 154, 134, 130` +### 6. `ExternalLineageRelationshipTable` / `ExternalLineageRelationshipPath` / `ExternalLineageRelationshipModelVersion` / `ExternalLineageRelationshipExternalMetadata` — `src/v1/model.ts:158, 154, 134, 130` - **Why weird:** Four sibling types every one prefixed with the package's longest type-name `ExternalLineageRelationship`. The naming makes them feel weighty; their position in the union does not justify the weight. Names like `ExternalLineageRelationshipExternalMetadata` are over 35 characters and convey one bit of information (which arm of the union). - **Category:** 7 (overly verbose), 8 (redundant prefix — `ExternalLineageRelationship` is implicit from context). - **Suggested name:** Nest them: `ExternalLineageRelationship.Table`, `ExternalLineageRelationship.Path`, etc., via a TS namespace; or drop the prefix and name them `LineageTableObject`, `LineagePathObject`, `LineageModelVersionObject`, `LineageExternalMetadataObject`. - **Rationale:** The redundant prefix is paid on every line that references these types. Dropping it (or nesting) shortens call sites without losing information. -### 8. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` +### 7. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` - **Why weird:** Both fields are typed as `string | undefined` with no JSDoc. A reader of `{source?: string, target?: string}` has no way to know that these are *column names* (not full table.column references, not column IDs). The enclosing `ExternalLineageRelationship` has its own `source` and `target` of type `ExternalLineageRelationshipObject` — so the inner `source`/`target` of `ColumnRelationship` shadow the outer pair and add no description. - **Category:** 1 (vague `source`/`target`), 6 (misleading — looks like the outer source/target but is column-level), 15 (generic field names lose meaning), 19 (underspecified ID — is this a column name? a path? a column lineage handle?). - **Suggested name:** `sourceColumn?: string` / `targetColumn?: string` with JSDoc clarifying the format. @@ -65,43 +59,43 @@ ## Medium severity -### 9. `Client` class — `src/v1/client.ts:45` +### 8. `Client` class — `src/v1/client.ts:45` - **Why weird:** Class literally named `Client` at the top level of the package's API surface, re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. Same problem as every other audited package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. -### 10. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` +### 9. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. - **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. -### 11. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 10. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. -### 12. `HttpCallOptions` — `src/v1/utils.ts:15` +### 11. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 13. `flattenQueryParams` — `src/v1/utils.ts:123` +### 12. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. - **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). - **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. - **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). -### 14. `LineageTableInfo.name` — `src/v1/model.ts:201` +### 13. `LineageTableInfo.name` — `src/v1/model.ts:201` - **Why weird:** Field literally called `name` with JSDoc "Name of Table." (capitalised "Table" mid-sentence). The neighbour fields are `catalogName` and `schemaName` — so the type has `(name, catalogName, schemaName)`. Inconsistent: two fields use the `*Name` suffix while the table name itself drops it. Most readers will reach for `tableName`. - **Category:** 1 (vague — `name` of what?), 15 (generic field name losing meaning), 17 (inconsistent within the same type — `name` vs `catalogName` vs `schemaName`). - **Suggested name:** `tableName: string` (and JSDoc punctuation fix). - **Rationale:** Within `LineageTableInfo`, the canonical name for "the table's name" is `tableName`. Mixing `name`, `catalogName`, `schemaName` makes the table's own name look special when it isn't. -### 15. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` +### 14. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` - **Why weird:** Field is `name?: string` with no JSDoc. Type is named to encode "external metadata object on the external-lineage edge". Given the wider package uses `name` for tables, models, external metadata, paths-via-`url`, the field gives up domain meaning to be terse. - **Category:** 1 (vague `name`), 15 (generic field name), 19 (underspecified ID — for `ExternalMetadata`, the `name` is actually a fully-qualified resource path including the metastore). - **Suggested name:** `externalMetadataName: string` with a JSDoc clarifying the expected format (mirror the `ExternalMetadata.name` JSDoc on the externalmetadata package). @@ -109,49 +103,49 @@ ## Low severity -### 16. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` +### 15. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` - **Why weird:** Field is `url?: string` on a type called `*Path`. A `Path` whose only field is a `url` — two different nouns for the same thing. Compare with `LineageFileInfo.path` and `ExternalLineageRelationshipPath.url`: the file `path` and the lineage-path `url` carry the same kind of value. - **Category:** 1 (vague), 6 (misleading — `Path` and `url` are not the same), 12 (duplicate concept — `path` and `url` interchangeable across the package), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the type to `LineagePathObject` and call the field `path: string`, or rename the field to keep the type name: `path?: string`. - **Rationale:** Pick one of `path` or `url` for storage location strings and stick to it. -### 17. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` -- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#7) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. +### 16. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#6) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. - **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). - **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) - **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. -### 18. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 17. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). - **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. - **Rationale:** Type name should reflect the dominant content; current name is misleading. -### 19. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +### 18. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` - **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. - **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). - **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. - **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. -### 20. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 85-92, 107, 134-186, 202-235` +### 19. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 80-92, 104, 134-178, 202-235` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. - **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 21. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` +### 20. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` - **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in the same scope. -### 22. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` +### 21. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` +### 22. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. @@ -159,19 +153,19 @@ ## Observations -### 24. Method names re-state the entity verbosely +### 23. Method names re-state the entity verbosely All four methods (`createExternalLineageRelationship`, `updateExternalLineageRelationship`, `deleteExternalLineageRelationship`, `listExternalLineageRelationships`) end with `ExternalLineageRelationship`. The package is *named* `externallineage`, so the entity is obvious from the import path. `client.create(...)` / `client.list(...)` would be both terser and more readable, but generator-wide consistency probably wins. - **Category:** 7 (overly verbose) — generator-wide pattern, listed as observation only. -### 25. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name -The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #5. +### 24. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #4. - **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). ## Domain glossary - `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. - `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). - `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #17. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #16. - `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). - `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index 8e1523dc..101fce8c 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -8,10 +8,10 @@ folder is one word `externallocations`, no hyphen, no underscore). resource type "external location" (a named pointer at cloud-storage URI plus storage credential) with five operations (create / get / list / list-iter / update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting -sub-structure is `FileEventQueue` — an oneof-of-oneofs across four cloud -providers (Azure AQS, AWS SQS, GCP Pub/Sub, OneLake Fabric Eventstream) with a -parallel "provided" vs "managed" axis (8 cases total). -**Total weird names flagged:** 15 +sub-structure is `FileEventQueue` — an oneof-of-oneofs across three cloud +providers (Azure AQS, AWS SQS, GCP Pub/Sub) with a parallel "provided" vs +"managed" axis (6 cases total). +**Total weird names flagged:** 13 --- @@ -21,76 +21,34 @@ parallel "provided" vs "managed" axis (8 cases total). | --- | ----------------------------------------------------------------------------- | ----------------- | ------------------ | -------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | package folder `externallocations` | (package) | package | Low | 7 Overly verbose | Compound noun jammed together with no separator. Sibling packages with the same pattern: `accountaccesscontrol`, `cleanroomtaskruns`. The `npm` package is `@databricks/sdk-externallocations`. `external-locations` would be more readable but the rest of the SDK uses the same one-word convention. | | 2 | `Client` | client.ts:44 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client`. Every package in the SDK exports a class literally named `Client`; importers must alias on collision. `ExternalLocationsClient` would self-identify. | -| 3 | `IsolationMode` enum values | model.ts:5-10 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | All four members stutter the enum name (`ISOLATION_MODE_UNSPECIFIED`, `ISOLATION_MODE_OPEN`, `ISOLATION_MODE_ISOLATED`, `ISOLATION_MODE_OPEN_IN_ACCOUNT`). TS idiom is `IsolationMode.Open`/`.Isolated`/`.OpenInAccount`. Same finding appears in `credentials.md`/`catalogs.md` — generator-wide. | -| 4 | `IsolationMode.ISOLATION_MODE_UNSPECIFIED` | model.ts:6 | enum value | Medium | 6 Misleading names, 18 Long enum values | Proto-style "Unspecified" sentinel value. The field type is `isolationMode?: IsolationMode \| undefined` — TS already expresses "unspecified" by omitting the field. The sentinel is dead. | -| 5 | `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` | model.ts:9 | enum value | Low | 18 Long enum values, 6 Misleading names | 30-char enum value; contracts to `OpenInAccount`. The domain meaning ("open scope within a single account") is opaque even after contracting. | -| 6 | `SseEncryptionAlgorithm` enum values | model.ts:12-16 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values, 3 Acronym casing | Three members `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`, `AWS_SSE_S3`, `AWS_SSE_KMS`. The first stutters the enum name (40 chars). The other two redundantly carry an `AWS_` prefix (the type name already says SSE which is AWS terminology). Should be `Unspecified`/`SseS3`/`SseKms`, or just `S3`/`Kms` since the wrapping `Sse*` already says S3-server-side. | -| 7 | `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` | model.ts:13 | enum value | Medium | 6 Misleading names, 18 Long enum values | Same proto-Unspecified pattern. The field `algorithm?: SseEncryptionAlgorithm \| undefined` already encodes "unset". | -| 8 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type vs `OneLakeEventQueue` type | model.ts:18, 28, 186, 240 | type set | Medium | (none individually, taken as set: inconsistent) | The four queue-config types use four different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix), `OneLakeEventQueue` (product + EventQueue suffix, no "Microsoft"/"Azure" prefix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`/`OneLakeConfig`. | -| 9 | `AwsSqsQueue.queueUrl` JSDoc says "AQS queue url" | model.ts:20 | doc | Medium | 6 Misleading names | The type is **AWS SQS**, but the JSDoc says "The AQS queue url" — AQS is *Azure* Queue Storage (the next type over). Copy-paste error from `AzureQueueStorage.queueUrl`. Misleading for any AWS user reading docs. | -| 10 | `GcpPubsub` (lowercase "ubsub") | model.ts:186 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | -| 11 | `AzureQueueStorage` | model.ts:28 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | -| 12 | `OneLakeEventQueue` vs `OneLake` (no Azure/Fabric prefix) | model.ts:240 | type | Low | 3 Acronym casing, 1 Vague/generic | OneLake is a Microsoft Fabric product. Other Azure-side types in the file lead with `Azure`. `OneLake` requires Fabric product knowledge to recognize. | -| 13 | `Pubsub` casing inside `GcpPubsub` | model.ts:186 | type | Low | 3 Acronym casing | GCP's product brand is "Pub/Sub". The TS type uses `Pubsub`. Consistent with field names but not with marketing. Same applies to `providedPubsub`/`managedPubsub`. | -| 14 | `nameArg` field | model.ts:103, 198, 263 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocation`, `GetExternalLocation`, `UpdateExternalLocation`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | -| 15 | `providedOnelake` / `managedOnelake` (case key spelling) | model.ts:176, 182 | field | Medium | 3 Acronym casing | OneLake is officially "OneLake" (camelCase capitalized "L"). The case key spells it `Onelake` (one capital). The interface name uses `OneLake` (two capitals). Inconsistent within the same file. | +| 3 | `SseEncryptionAlgorithm.AWS_SSE_S3` / `AWS_SSE_KMS` | model.ts:13-14 | enum values | Medium | 3 Acronym casing | The two non-sentinel members redundantly carry an `AWS_` prefix (the enclosing type name already says SSE which is AWS terminology). The wrapping `Sse*` already implies S3-server-side, so the leading `AWS_` is duplicative. | +| 4 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type | model.ts:17, 27, 183 | type set | Medium | (none individually, taken as set: inconsistent) | The three queue-config types use three different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`. | +| 5 | `AwsSqsQueue.queueUrl` JSDoc says "AQS queue url" | model.ts:19 | doc | Medium | 6 Misleading names | The type is **AWS SQS**, but the JSDoc says "The AQS queue url" — AQS is *Azure* Queue Storage (the next type over). Copy-paste error from `AzureQueueStorage.queueUrl`. Misleading for any AWS user reading docs. | +| 6 | `GcpPubsub` (lowercase "ubsub") | model.ts:183 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | +| 7 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | +| 8 | `nameArg` field | model.ts:102, 195, 244 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocationRequest`, `GetExternalLocationRequest`, `UpdateExternalLocationRequest`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | +| 9 | `DeleteExternalLocationRequest_Response` | model.ts:108 | type | High | 16 Proto-architectural-leak names | Underscore-delimited proto-nested message name leaked through to the TS public surface. The `_Response` suffix is a Go/Protobuf RPC convention; idiomatic TS would name this `DeleteExternalLocationResponse` (or omit it entirely when the body is empty). | +| 10 | `ListExternalLocationsRequest_Response` | model.ts:221 | type | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern. Should be `ListExternalLocationsResponse`. The leading `Request_` infix is meaningless to a TS caller — the response is not "the response of a request type", it is the list response. | +| 11 | `unmarshalDeleteExternalLocationRequest_ResponseSchema` | model.ts:324 | const | High | 16 Proto-architectural-leak names | Schema constant inherits the proto-nested `Request_Response` identifier. Should track whatever the renamed type becomes (e.g., `unmarshalDeleteExternalLocationResponseSchema`). | +| 12 | `unmarshalListExternalLocationsRequest_ResponseSchema` | model.ts:436 | const | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern carried into schema constant naming. | +| 13 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | --- ## High severity (must fix) -### H1. Two `IsolationMode` and `SseEncryptionAlgorithm` enums stutter their enum name - -```ts -enum IsolationMode { - ISOLATION_MODE_UNSPECIFIED = 'ISOLATION_MODE_UNSPECIFIED', - ISOLATION_MODE_OPEN = 'ISOLATION_MODE_OPEN', - ISOLATION_MODE_ISOLATED = 'ISOLATION_MODE_ISOLATED', - ISOLATION_MODE_OPEN_IN_ACCOUNT = 'ISOLATION_MODE_OPEN_IN_ACCOUNT', -} - -enum SseEncryptionAlgorithm { - SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED = 'SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED', - AWS_SSE_S3 = 'AWS_SSE_S3', - AWS_SSE_KMS = 'AWS_SSE_KMS', -} -``` - -Per the Google TypeScript Style Guide §5.6, enum members should be PascalCase -and should not redundantly carry the enum name: - -```ts -enum IsolationMode { - Unspecified, - Open, - Isolated, - OpenInAccount, -} - -enum SseEncryptionAlgorithm { - Unspecified, - S3, // or SseS3 if we want to keep the SSE marker - Kms, -} -``` - -The wire-format strings must keep their SCREAMING_SNAKE form (the API server -demands them), but the TS-side keys can be remapped via the zod `transform` -without breaking the wire. Same finding appears in `credentials.md` (M4) and -`catalogs.md` (20.3). - -### H2. `nameArg` is a generator artifact +### H1. `nameArg` is a generator artifact Three request types carry a field called `nameArg`: -- `DeleteExternalLocation.nameArg` (model.ts:103) -- `GetExternalLocation.nameArg` (model.ts:198) -- `UpdateExternalLocation.nameArg` (model.ts:263) +- `DeleteExternalLocationRequest.nameArg` (model.ts:102) +- `GetExternalLocationRequest.nameArg` (model.ts:195) +- `UpdateExternalLocationRequest.nameArg` (model.ts:244) The `Arg` suffix is meaningless to a TS caller. It exists only because the generator needs to disambiguate the path-parameter `name` from the body-field -`name` on `UpdateExternalLocation`. Renaming it to `externalLocationName` or -just `name` (and dropping the body-level `name` on Update) would clarify. +`name` on `UpdateExternalLocationRequest`. Renaming it to `externalLocationName` +or just `name` (and dropping the body-level `name` on Update) would clarify. ```ts // Today: @@ -102,11 +60,67 @@ await client.deleteExternalLocation({name: 'my-loc', force: true}); This finding mirrors `credentials.md` H4 and applies generator-wide. +### H2. `DeleteExternalLocationRequest_Response` — proto-nested underscore in public type + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteExternalLocationRequest_Response {} +``` + +The `Request_Response` underscore identifier is a Protobuf nested-message +convention leaked verbatim into the TS public API. The escape-hatch ESLint +disable comment is itself a tell. Idiomatic TS would either: + +- name the response `DeleteExternalLocationResponse` (drop the `Request_` + infix; the response is a sibling of the request, not nested under it), or +- collapse the empty-body response into `Promise` since the wire + envelope carries no fields. + +The schema constant `unmarshalDeleteExternalLocationRequest_ResponseSchema` +(model.ts:324) and the client return type at client.ts:105 inherit the same +name and need to move together. + +### H3. `ListExternalLocationsRequest_Response` — same proto-nested pattern + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface ListExternalLocationsRequest_Response { + /** An array of external locations. */ + externalLocations?: ExternalLocationInfo[] | undefined; + // ... +} +``` + +Same shape as H2: an underscore-delimited proto-nested identifier in the +public surface. Should be `ListExternalLocationsResponse`. The schema constant +`unmarshalListExternalLocationsRequest_ResponseSchema` (model.ts:436) and the +client return type at client.ts:182 share the rename. + +This is the only paginated response shape in the package, so the type is +materially load-bearing — callers iterating manually have to read +`resp.nextPageToken` against this type. + --- ## Medium severity (worth pushing back on) -### M1. `AwsSqsQueue.queueUrl` JSDoc says "AQS" +### M1. `SseEncryptionAlgorithm` members carry redundant `AWS_` prefix + +```ts +enum SseEncryptionAlgorithm { + SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED = 'SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED', + AWS_SSE_S3 = 'AWS_SSE_S3', + AWS_SSE_KMS = 'AWS_SSE_KMS', +} +``` + +The two non-sentinel members duplicate the AWS context that is already +implicit in the enclosing `SseEncryptionAlgorithm` type — SSE-S3 and SSE-KMS +are AWS-only concepts. Within the proto-style identifier convention these +could read as plain `SSE_S3` / `SSE_KMS`, or even `S3` / `KMS` since the +wrapping type already says SSE. + +### M2. `AwsSqsQueue.queueUrl` JSDoc says "AQS" ```ts export interface AwsSqsQueue { @@ -121,32 +135,22 @@ export interface AwsSqsQueue { The type is **AWS SQS**, but the doc string starts "The AQS queue url" — AQS is Azure Queue Storage. Copy-paste error from the sibling `AzureQueueStorage.queueUrl` -JSDoc (lines 29-32). Wire-format example string is correct (AWS SQS); only the +JSDoc (lines 28-31). Wire-format example string is correct (AWS SQS); only the prose is wrong. Confusing for any AWS user. -### M2. The four cloud-provider queue types use four different naming conventions +### M3. The three cloud-provider queue types use three different naming conventions ```ts interface AwsSqsQueue { ... } // cloud + service + Queue interface AzureQueueStorage { ... } // cloud + product, no suffix interface GcpPubsub { ... } // cloud + product, no suffix -interface OneLakeEventQueue { ... } // product + EventQueue suffix, no Microsoft/Azure prefix ``` -Four naming patterns for four parallel types. Pick one: +Three naming patterns for three parallel types. Pick one: -- All with `Queue` suffix: `AwsSqsQueue`, `AzureAqsQueue`, `GcpPubsubQueue`, - `OneLakeQueue`. -- All without: `AwsSqs`, `AzureQueueStorage`, `GcpPubsub`, `OneLakeEventStream`. -- All as `Config`: `AwsSqsConfig`, `AzureAqsConfig`, etc. - -### M3. `OneLake` casing inconsistency - -The type name is `OneLakeEventQueue` (two capitals). The discriminator case -keys are `providedOnelake` / `managedOnelake` (one capital `L`, lowercased). -The wire format is `provided_onelake` / `managed_onelake` (all lowercase). -Within one file the brand name is rendered three different ways. Microsoft's -spelling is "OneLake". +- All with `Queue` suffix: `AwsSqsQueue`, `AzureAqsQueue`, `GcpPubsubQueue`. +- All without: `AwsSqs`, `AzureQueueStorage`, `GcpPubsub`. +- All as `Config`: `AwsSqsConfig`, `AzureAqsConfig`, `GcpPubsubConfig`. ### M4. `AzureQueueStorage` vs `Aqs` abbreviation @@ -162,6 +166,28 @@ GCP's product is "Pub/Sub" (with slash and two capitals). The TS type is `GcpPubsub` (one capital). Internally consistent (the discriminator cases `providedPubsub`/`managedPubsub` match), but not the canonical GCP spelling. +### M6. `ExternalLocationInfo` — `Info` suffix carries no semantic value + +```ts +export interface ExternalLocationInfo { ... } +``` + +`ExternalLocationInfo` is the resource representation type for an external +location. The `Info` suffix is a Go/Protobuf convention (cf. `ClusterInfo`, +`JobInfo` across the rest of the SDK) — there is no companion +`ExternalLocation` type without the suffix to disambiguate against. In +idiomatic TS this would just be `ExternalLocation`. + +The suffix shows up in every signature touching the resource: + +- `Promise` (4 client method return types). +- `ExternalLocationInfo[]` in `ListExternalLocationsRequest_Response`. +- `AsyncGenerator` in the iter method. +- The schema constant `unmarshalExternalLocationInfoSchema`. + +Renaming to `ExternalLocation` removes ~6 occurrences of dead-weight suffix +across the public surface. + --- ## Low severity (nits) @@ -190,7 +216,7 @@ The following acronyms appear: | Acronym | Casing in code | Notes | | -------- | ---------------- | ----------------------------------------------------------- | | AWS | `Aws` | Initialism-as-word per Google TS Style Guide. | -| S3 | `S3` (in `AWS_SSE_S3`); `s3` (JSDoc on line 250) | Mixed. | +| S3 | `S3` (in `AWS_SSE_S3`); `s3` (JSDoc on line 230) | Mixed. | | SQS | `Sqs` | Initialism-as-word. | | SSE | `Sse` | Initialism-as-word. | | KMS | `Kms` | Initialism-as-word. | @@ -200,28 +226,42 @@ The following acronyms appear: | AQS | `Aqs` | Databricks-internal abbreviation, not Microsoft canonical. | | GCP | `Gcp` | Initialism-as-word. | | Pub/Sub | `Pubsub` | Non-canonical (Google spells `Pub/Sub`). | -| OneLake | `OneLake` (type), `Onelake` (case keys) | Inconsistent. Microsoft spells `OneLake`. | -| URL | `url` (lower; field name); `Url` (in `queueUrl`, `eventHubUrl`) | Standard. | +| URL | `url` (lower; field name); `Url` (in `queueUrl`) | Standard. | | ID | `Id` (in `metastoreId`, `credentialId`, `managedResourceId`, `subscriptionId`) | Initialism-as-word. | --- ## Summary -15 findings: +13 findings: -- **2 High severity** — enum stutter, `nameArg` artifact. -- **5 Medium severity** — `AQS` JSDoc copy-paste error in AWS type, - naming-pattern inconsistency across the four queue types, OneLake casing - inconsistency, AQS abbreviation, Pubsub casing. -- **0 Low severity (nits)**. +- **5 High severity** — `nameArg` artifact, two `Request_Response` + proto-nested type names, two matching schema-constant names. +- **7 Medium severity** — `Client` collision, redundant `AWS_` prefix on + `SseEncryptionAlgorithm` members, queue-type naming-pattern inconsistency, + `AQS` JSDoc copy-paste, `AzureQueueStorage`/`Aqs` long-vs-short + inconsistency, `Pubsub` casing, `ExternalLocationInfo` redundant `Info` + suffix. +- **1 Low severity** — `externallocations` package folder verbosity. Primary themes: -1. **Generator-encoded proto patterns**: SCREAMING_SNAKE enum members and the - `nameArg` path-vs-body disambiguation are proto/Go-SDK artifacts that - idiomatic TS would express differently. -2. **Cloud-provider naming is internally inconsistent**: four queue-config - types with four different naming conventions, OneLake spelled three ways, - AQS abbreviation that isn't Microsoft canonical, copy-paste error mixing - AWS SQS and Azure AQS in one JSDoc. +1. **Proto-architectural-leak names**: the `Request_Response` underscore + identifiers, the `Info` suffix on the resource type, and the `nameArg` + path-vs-body disambiguation are all Go-/Protobuf-shaped idioms that + idiomatic TS would express differently. The ESLint disable comments on + model.ts:107 / 220 / 323 / 435 are themselves the giveaway. +2. **Cloud-provider naming is internally inconsistent**: three queue-config + types with three different naming conventions, AQS abbreviation that isn't + Microsoft canonical, copy-paste error mixing AWS SQS and Azure AQS in one + JSDoc. + +--- + +## Fixed + +- #5 `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` (originally cited at model.ts:9): Fixed in regeneration on 2026-05-20 — enum member removed from `IsolationMode`. +- #8 `OneLakeEventQueue` type as part of four-queue inconsistency set (originally cited at model.ts:18, 28, 186, 240): Fixed in regeneration on 2026-05-20 — `OneLakeEventQueue` type and the `providedOnelake`/`managedOnelake` FileEventQueue cases were removed, reducing the set to three providers; the remaining three-way inconsistency is retracked as finding #4. +- #12 `OneLakeEventQueue` (no Azure/Fabric prefix) (originally cited at model.ts:240): Fixed in regeneration on 2026-05-20 — type removed entirely. +- #13 `Pubsub` casing inside `GcpPubsub` (originally cited at model.ts:186): Fixed in regeneration on 2026-05-20 — duplicate of finding #8 (now #6 in renumbered audit); collapsed into the single `GcpPubsub` casing entry. +- #15 `providedOnelake` / `managedOnelake` case key spelling (originally cited at model.ts:176, 182): Fixed in regeneration on 2026-05-20 — `OneLake` cases removed from `FileEventQueue` provided/managed unions. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index d06f7061..2179e28f 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -8,68 +8,62 @@ ## Summary | Severity | Count | | --- | --- | -| High | 10 | +| High | 9 | | Medium | 12 | -| Low | 10 | +| Low | 11 | | Observation | 4 | ## High severity -### 1. `SystemType.SYSTEM_TYPE_UNSPECIFIED` — `src/v1/model.ts:9` -- **Why weird:** Sentinel re-states the enum name (`SystemType.SYSTEM_TYPE_UNSPECIFIED`). The field that uses this enum is already `systemType?: SystemType | undefined` — idiomatic TS expresses "unset" as `undefined`, making a third "unspecified" value pure protobuf import. -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style names). -- **Suggested name:** Drop the sentinel entirely and rely on `undefined`, or rename to `SystemType.Unknown`. -- **Rationale:** TS enum members are namespaced by the enum (`SystemType.Unknown`). The `SYSTEM_TYPE_` prefix on every member is protobuf-import noise that the language already solves with namespacing. - -### 2. `SystemType.OTHER` — `src/v1/model.ts:10` +### 1. `SystemType.OTHER` — `src/v1/model.ts:10` - **Why weird:** Generic catch-all value with no semantic indicator that it is a fallback. A user encountering `SystemType.OTHER` cannot tell if it means "data not yet classified", "vendor we don't support", or "user-provided custom system". Compare to `SystemType.SYSTEM_TYPE_UNSPECIFIED` which at least signals it is a sentinel. - **Category:** 1 (vague — `OTHER` is the most generic possible name), 15 (generic field/value name losing meaning). - **Suggested name:** `SystemType.Custom` or `SystemType.UserDefined` (whichever matches the API semantics). - **Rationale:** `OTHER` as an enum value is the value-side equivalent of naming a field `data`. JSDoc on the enum, or a more specific value name, would tell readers when to reach for it. -### 3. `SystemType` value casing — `POWER_BI`, `MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `AZURE_SYNAPSE`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`, `STREAM_NATIVE`, `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE`, `WORKDAY`, `TABLEAU`, `LOOKER`, `KAFKA`, `MYSQL`, `ORACLE`, `SAP`, `SNOWFLAKE`, `TERADATA`, `CONFLUENT`, `DATABRICKS` — `src/v1/model.ts:10-32` +### 2. `SystemType` value casing — `POWER_BI`, `MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `AZURE_SYNAPSE`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`, `STREAM_NATIVE`, `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE`, `WORKDAY`, `TABLEAU`, `LOOKER`, `KAFKA`, `MYSQL`, `ORACLE`, `SAP`, `SNOWFLAKE`, `TERADATA`, `CONFLUENT`, `DATABRICKS` — `src/v1/model.ts:10-32` - **Why weird:** Vendor names are proper nouns with canonical brand casing (Power BI, Microsoft SQL Server, Amazon Redshift, BigQuery, PostgreSQL, MongoDB, ServiceNow, Tableau). Wire SCREAMING_SNAKE collapses every brand to a flat shout. Also: split rules are inconsistent — `POWER_BI` and `MICROSOFT_SQL_SERVER` split on word boundary, but `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE` join compounds without underscore. -- **Category:** 3 (acronym casing inconsistency across vendor names), 18 (long enum value set). -- **Suggested name:** Either keep wire SCREAMING_SNAKE (current) and document, or move TS-side to PascalCase brand casing (`SystemType.PowerBI`, `SystemType.MicrosoftSqlServer`, `SystemType.Postgres`, `SystemType.MongoDb`). Pick one split convention: word-bound (`POSTGRE_SQL`, `MONGO_DB`, `SERVICE_NOW`, `SALES_FORCE`) or joined (`POWERBI`, `MICROSOFTSQLSERVER`). -- **Rationale:** Vendor names are proper nouns. A user typing `SystemType.MongoDB` won't autocomplete to `MONGODB`. Within the set there is no reproducible rule (compare `POWER_BI` split vs `POSTGRESQL` joined). Probably wire-locked, but worth flagging upstream. +- **Category:** 3 (acronym casing inconsistency across vendor names). +- **Suggested name:** Pick one split convention: word-bound (`POSTGRE_SQL`, `MONGO_DB`, `SERVICE_NOW`, `SALES_FORCE`) or joined (`POWERBI`, `MICROSOFTSQLSERVER`). Alternatively move TS-side to PascalCase brand casing (`SystemType.PowerBI`, `SystemType.MicrosoftSqlServer`, `SystemType.Postgres`, `SystemType.MongoDb`). +- **Rationale:** Vendor names are proper nouns. Within the set there is no reproducible rule (compare `POWER_BI` split vs `POSTGRESQL` joined). A user typing `SystemType.MongoDB` won't autocomplete to `MONGODB`. Probably wire-locked, but worth flagging upstream. -### 4. `SystemType.STREAM_NATIVE` — `src/v1/model.ts:32` +### 3. `SystemType.STREAM_NATIVE` — `src/v1/model.ts:32` - **Why weird:** The vendor is "StreamNative" (one camelCased brand name), but the wire splits it as `STREAM_NATIVE`. Compare: `SERVICENOW` (joined, brand is "ServiceNow") vs `STREAM_NATIVE` (split, brand is "StreamNative"). The split rule is unprincipled. -- **Category:** 3 (acronym/brand casing inconsistency), 18 (long value). +- **Category:** 3 (acronym/brand casing inconsistency). - **Suggested name:** `STREAMNATIVE` (matches `SERVICENOW`) or fix `SERVICENOW` -> `SERVICE_NOW`. Pick one. - **Rationale:** Sibling brand names with the same shape (one-word camelCased) should encode identically. The current internal inconsistency makes the type non-discoverable. -### 5. `ExternalMetadata` — `src/v1/model.ts:43` +### 4. `ExternalMetadata` — `src/v1/model.ts:43` - **Why weird:** The central domain entity is named after the package, which is a noun phrase but not a noun ("External Metadata" is more an adjective+noun phrase than a thing). Compare: `Catalog`, `Connection`, `Schema` are crisp nouns; `ExternalMetadata` reads like a category, not an instance. Also: every field has the doc-string suffix "external metadata object" — the type is essentially `XxxObject` without the suffix, but the docs need it because the bare type name lacks objecthood. - **Category:** 1 (vague — what is "an External Metadata"?), 6 (misleading: name reads as a kind, not an instance). - **Suggested name:** `ExternalAsset` or `ExternalEntity` (the type already has a `entityType` field describing what shape of external thing it is). Alternatively, embrace the proto-canonical name with `ExternalMetadataObject`. - **Rationale:** Reading `const x: ExternalMetadata = ...` does not communicate that `x` is a single named external asset. The JSDoc fix ("external metadata object") betrays that the type name needs help to read as a noun. Worth raising upstream. -### 6. `ExternalMetadata.name` (and `req.name` in Get/Delete/Update) — `src/v1/model.ts:45,40,81` +### 5. `ExternalMetadata.name` (and `req.name` in Get/Delete/Update) — `src/v1/model.ts:45,40,81` - **Why weird:** Field literally called `name` on an entity that uses `name` as the unique identifier in REST path segments (`/api/2.0/lineage-tracking/external-metadata/${req.name}`). The entity also has both `name` AND `id` (line 71) — two different identifier-shaped fields with no doc differentiation beyond "Unique identifier of the external metadata object" on `id` and "Name of the external metadata object" on `name`. - **Category:** 1 (vague — `name` is the canonical too-generic field name), 12 (duplicate concept — `name` and `id` both feel identity-shaped), 19 (underspecified ID). - **Suggested name:** Either rename to `objectName` / `assetName` and document the format constraint, or drop `id` if `name` is the canonical key. JSDoc must explain when callers use `name` vs `id`. - **Rationale:** Co-existence of `name?: string` and `id?: string` with no semantic separation in docs is a recipe for caller confusion. The URL routing uses `name` as the path segment, suggesting `name` is the canonical key; `id` is the implementation-detail UUID. The type does not communicate this. -### 7. `ExternalMetadata.id` — `src/v1/model.ts:71` +### 6. `ExternalMetadata.id` — `src/v1/model.ts:71` - **Why weird:** Field `id` exists alongside `name`. JSDoc says "Unique identifier" — but `name` is also a unique identifier (the URL path key). Bare `id` without further qualification gives no hint that this is the system-generated UUID vs. the human-readable name. Also: bare `id: string` is rule-19 underspecified — no format constraint visible at the type. - **Category:** 1 (vague), 12 (duplicate concept with `name`), 19 (underspecified ID). - **Suggested name:** `objectId` / `assetId` / `externalMetadataId`, or drop entirely if `name` is the canonical key. - **Rationale:** Two unique identifiers on one type with no doc differentiation forces every caller to read the API docs to know which to use. The type should name the difference. -### 8. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` +### 7. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` - **Why weird:** Type name carries the API version suffix `V2`, but the enclosing file is already `v1/model.ts` and the package is mounted at `./v1`. Version is encoded twice — once in the directory, once in the type. If the user later imports a hypothetical `v2/`, they would get `V3`? Versioning the entity name within the version namespace creates an off-by-one collision risk. - **Category:** 8 (redundant suffix — version is in the path), 20 (type-suffix tautology between version-in-path and version-in-name), 14 (Go/proto-style — Go SDK carries the `V2` per RPC name; TS doesn't need it). - **Suggested name:** `ListExternalMetadataResponse` (drop `V2`). - **Rationale:** The directory is the namespace. Embedding the wire RPC version into the TS type name leaks an internal detail of the generator. If the package later gets a `v2/` directory, every type there ends up `V3` (one ahead of the dir), which is worse than the original problem. -### 9. `Client.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:70,102,124,154,190,212` +### 8. `Client.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:70,102,124,154,190,212` - **Why weird:** Every public method on `Client` ends with `V2`, but the directory is `v1/`. The version suffix is wire-RPC-name leakage (the upstream API is `ExternalMetadataServiceV2.Create`, hence `createExternalMetadataV2`). User code reads `client.createExternalMetadataV2(...)` for a method on a `v1/` import — confusing on first read. - **Category:** 8 (redundant suffix), 14 (Go/proto-style name leak), 20 (type/version suffix tautology). - **Suggested name:** `createExternalMetadata`, `deleteExternalMetadata`, etc. (drop `V2`). -- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #8; generator-wide concern. +- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #7; generator-wide concern. -### 10. `Client` — `src/v1/client.ts:41` +### 9. `Client` — `src/v1/client.ts:41` - **Why weird:** Class literally named `Client` at the top level of the package's surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code collide on import: `import {Client} from '@databricks/sdk-externalmetadata'` and `import {Client} from '@databricks/sdk-catalogs'` both fight for the same identifier. - **Category:** 1 (vague — `Client` is the most generic name), 15 (generic name). - **Suggested name:** `ExternalMetadataClient` (matches the package name and avoids collisions on combined imports). @@ -77,73 +71,73 @@ ## Medium severity -### 11. `ExternalMetadata.systemType: SystemType` — `src/v1/model.ts:47` +### 10. `ExternalMetadata.systemType: SystemType` — `src/v1/model.ts:47` - **Why weird:** Type-suffix tautology — field `systemType` of type `SystemType` on a type called `ExternalMetadata`. Reads `externalMetadata.systemType: SystemType` — three "type"s in one declaration. - **Category:** 20 (type-suffix tautology), 8 (redundant suffix). - **Suggested name:** `system: SystemType` (would read `externalMetadata.system`). - **Rationale:** When the field's type already encodes "type", the field itself doesn't need to. Compare: `externalMetadata.system` reads cleaner than `externalMetadata.systemType`. -### 12. `ExternalMetadata.entityType` — `src/v1/model.ts:49` +### 11. `ExternalMetadata.entityType` — `src/v1/model.ts:49` - **Why weird:** Field `entityType` is typed `string` (free-form) rather than `EntityType` (an enum). Pairs awkwardly with `systemType: SystemType` two lines above — one is enumerated, the other is freeform string. The user has no idea what valid `entityType` values are without consulting external docs. - **Category:** 1 (vague), 6 (misleading — `Type` suffix implies a closed set, but it's freeform), 15 (generic field name losing meaning), 17 (inconsistency — `systemType` is closed enum, `entityType` is open string). - **Suggested name:** `entityKind` (less enum-implying), or define an `EntityType` enum if a closed set exists. - **Rationale:** A field named `xxxType: string` strongly suggests an enum without one. JSDoc says "Type of entity within the external system" — but for Tableau the entity might be a dashboard/workbook; for Kafka, a topic. Closed-set values would help; absent that, the name should not over-promise. -### 13. `ExternalMetadata.url` — `src/v1/model.ts:51` +### 12. `ExternalMetadata.url` — `src/v1/model.ts:51` - **Why weird:** Casing of acronym. The codebase uses `url` (lowercase) consistently for the property, but the Web platform/standards canonical is `URL` (uppercase). Compare to `userAgent` (camelCase) and `URLSearchParams` (Web standard SCREAMING). Internal inconsistency between `url` (field) and `URLSearchParams` (function/class). - **Category:** 3 (acronym casing). - **Suggested name:** Keep `url` (TS convention), but acknowledge the JS-ecosystem split. - **Rationale:** The JS world is split here — Node, browsers, and the URL spec all use `URL` for the class and `url` for member fields. Internal consistency within this file is preserved (`url` everywhere); the rule is conventional, not broken. -### 14. `ExternalMetadata.description` — `src/v1/model.ts:53` +### 13. `ExternalMetadata.description` — `src/v1/model.ts:53` - **Why weird:** Field `description` is on the entity but is "User-provided free-form text description" per JSDoc — i.e., not a generated description, not a vendor description, but specifically a description set by the metadata owner. The plain name `description` does not convey "you supply this". - **Category:** 1 (vague — `description` is the canonical too-generic field name). - **Suggested name:** `userDescription` or keep `description` and rely on JSDoc. - **Rationale:** Minor — `description` is the universal expectation. JSDoc is doing the work. Listed for completeness. -### 15. `ExternalMetadata.columns: string[]` — `src/v1/model.ts:55` +### 14. `ExternalMetadata.columns: string[]` — `src/v1/model.ts:55` - **Why weird:** `columns` is typed as `string[]` (just names), but the JSDoc reads "List of columns associated with the external metadata object". A `Column` in Unity Catalog terms is a structured `{name, type, nullable, ...}` object — calling a list of column names `columns` invites the reader to expect structure that is not there. - **Category:** 6 (misleading — `columns` implies structured objects, is just names), 15 (generic field name losing meaning). - **Suggested name:** `columnNames: string[]` (matches the contents). - **Rationale:** When the field type and field name disagree about whether the values are objects or strings, the type wins (it has to compile); the name is the bug. `columnNames` is unambiguous. -### 16. `ExternalMetadata.properties` — `src/v1/model.ts:57` +### 15. `ExternalMetadata.properties` — `src/v1/model.ts:57` - **Why weird:** Field name is the literal type-system-builtin reserved word for "object members" (`Object.properties`, `props`, etc). The map's role is "user-defined custom metadata" but the name `properties` is the most generic possible for a `Record`. Also: `properties` co-exists with `metastoreId`, `owner`, `createdBy`, etc., which are *also* properties. - **Category:** 1 (vague), 6 (misleading — every other field is also a "property"), 10 (reserved-word-adjacent — `properties` clashes with `Object.properties`). - **Suggested name:** `tags`, `labels`, `attributes`, or `customProperties` — whatever the API doc calls them. - **Rationale:** `properties` on a `Record` is bag-of-strings naming. A user reading `externalMetadata.properties.foo` cannot tell if `foo` is intrinsic or user-extended. -### 17. `ExternalMetadata.owner` — `src/v1/model.ts:59` +### 16. `ExternalMetadata.owner` — `src/v1/model.ts:59` - **Why weird:** Field `owner: string | undefined` with no hint of format. JSDoc says "Owner of the external metadata object" — owner is a Unity Catalog principal (user, group, or service principal). Common sister-package convention names this `owner` consistently, but a user has no idea what string format to put (`alice@example.com`? `users/alice`? a UUID?). Same problem applies to `createdBy` (line 65) and `updatedBy` (line 69). - **Category:** 1 (vague), 19 (underspecified ID — what format is the principal?). - **Suggested name:** Keep `owner` but document format. Or `ownerPrincipal`, matching other UC packages. - **Rationale:** Bare `owner: string` is the canonical UC principal-as-string pattern across the SDK, but the type does not communicate format. Minor — sister-package convention is the same. Listed for visibility. -### 18. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` +### 17. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` - **Why weird:** Bare `metastoreId: string | undefined` — a UUID identifier on a UC metastore, but the type does not hint at the format. Idiomatic across the SDK; here mentioned only for rule-19 completeness. Also note: this field is "Unique identifier of parent metastore" but `parent` is not named — the metastore relationship is communicated via the `metastoreId` field alone, not a `parent` field per AIP-160. - **Category:** 19 (underspecified ID — `string` doesn't tell you it's a UUID). - **Suggested name:** Keep `metastoreId` (canonical across SDK). - **Rationale:** SDK-wide pattern; field name is fine. Listed for completeness. -### 19. `ExternalMetadata.createTime` / `updateTime` — `src/v1/model.ts:63,67` +### 18. `ExternalMetadata.createTime` / `updateTime` — `src/v1/model.ts:63,67` - **Why weird:** Verb-tense / part-of-speech inconsistency with `createdBy` and `updatedBy` (lines 65, 69). Times use the imperative ("create"); user fields use past-tense ("created"). A consistent set would be `createdAt` + `createdBy` and `updatedAt` + `updatedBy`. The Go SDK uses `create_time`/`update_time` on the wire; TS does not have to follow. - **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action-tense pair). - **Suggested name:** `createdAt: Temporal.Instant` + `updatedAt: Temporal.Instant` (preserves the `createdBy`/`updatedBy` past-tense pair). - **Rationale:** Sibling fields should agree on tense. `createTime`/`createdBy` mixes imperative + past-tense for one event. JS/TS canon is `createdAt`/`updatedAt` (e.g., NoSQL drivers, Sequelize, TypeORM, Prisma). -### 20. `ExternalMetadata.updateTime` vs. `Client.updateExternalMetadataV2` — `src/v1/model.ts:67, src/v1/client.ts:212` +### 19. `ExternalMetadata.updateTime` vs. `Client.updateExternalMetadataV2` — `src/v1/model.ts:67, src/v1/client.ts:212` - **Why weird:** "Update" as a verb is overloaded — it names both an action (the PATCH method) and a state field (the last-modified timestamp). On the same entity, reading `externalMetadata.updateTime` while a request to `updateExternalMetadata` is in flight is confusing. - **Category:** 12 (duplicate concept), 17 (verb noun-vs-action collision). - **Suggested name:** `modifiedAt`/`modifiedBy` for the state, leave `update` for the action. - **Rationale:** Separating timestamp ("modified") from operation ("update") prevents the reader from conflating "this was just updated" with "this is being updated right now". -### 21. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` +### 20. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` - **Why weird:** Field name `updateMask` doesn't say what kind of mask. In context the mask describes "which fields to patch". The Google AIP-134 convention names this `updateMask`; the TS-idiomatic name would describe contents (`fieldsToUpdate`, `patchedFields`, `paths`). - **Category:** 1 (vague), 14 (Google-AIP-style name). - **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. - **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. -### 22. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 21. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. @@ -151,70 +145,76 @@ ## Low severity -### 23. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` -- **Why weird:** Four (five) request DTOs repeat the noun `ExternalMetadata` even though the entire package operates on exactly one entity (the only thing this package does is CRUD `ExternalMetadata`). In context, `CreateRequest`/`UpdateRequest` would be plenty. -- **Category:** 7 (overly verbose), 8 (redundant suffix and infix). -- **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`/`ListRequest`, or drop the `Request` suffix entirely if request DTOs follow a sibling-naming pattern (`Create`, `Update`, etc.). Cross-SDK consistency makes this a low rather than high. -- **Rationale:** The whole package operates on one entity; repeating it in every request type is pure noise. SDK-wide pattern means a local fix risks inconsistency. +### 22. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` +- **Why weird:** Five request DTOs repeat the noun `ExternalMetadata` even though the entire package operates on exactly one entity (the only thing this package does is CRUD `ExternalMetadata`). In context, `CreateRequest`/`UpdateRequest` would be plenty. +- **Category:** 7 (overly verbose), 8 (redundant infix). +- **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`/`ListRequest`. +- **Rationale:** The whole package operates on one entity; repeating it in every request type is pure noise. The `Request` suffix itself is deliberate (SDK-wide convention); the redundant `ExternalMetadata` infix remains the issue. SDK-wide pattern means a local fix risks inconsistency. -### 24. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` +### 23. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` - **Why weird:** Singular/plural mismatch. The field holds an array but is named `externalMetadata` (singular). Convention is plural for arrays (e.g., `connections: Connection[]` in sister packages). Compare: `nextPageToken` is singular because it's a single token. - **Category:** 9 (singular/plural mismatch), 20 (type-suffix tautology — `externalMetadata: ExternalMetadata[]`). - **Suggested name:** `items: ExternalMetadata[]` or `externalMetadataObjects: ExternalMetadata[]` or `assets`. Wire stays `external_metadata`. - **Rationale:** "Metadata" is a mass noun (uncountable), which is why the generator left it singular. A plural-aware name like `items` or `assets` reads naturally. -### 25. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 24. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 26. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` +### 25. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 27. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` +### 26. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` - **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. -### 28. `pageReq` — `src/v1/client.ts:194` +### 27. `pageReq` — `src/v1/client.ts:194` - **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). - **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). - **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. -### 29. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +### 28. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` - **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. - **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). - **Suggested name:** `requestBody: string | ReadableStream`. - **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. -### 30. `flattenQueryParams` — `src/v1/utils.ts:123` +### 29. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 31. `readAll(body)` — `src/v1/utils.ts:40` +### 30. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. -### 32. `HttpCallOptions` — `src/v1/utils.ts:15` +### 31. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. +### 32. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` +- **Why weird:** The Zod schema constant carries the `V2` mid-position infix just like the type it parses (#7) and the client methods (#8). The directory is `v1/`, so `V2` here is wire-RPC-name leakage embedded inside a TS identifier that has no business advertising the upstream RPC version. Architectural leak — the generator copied the proto `ResponseV2` name straight through into the parser symbol. +- **Category:** 14 (Go/proto-style name leak — wire `V2` infix on a TS identifier), 8 (redundant suffix — version is in the path), 20 (type-version suffix tautology between version-in-path and version-in-name). +- **Suggested name:** `unmarshalListExternalMetadataResponseSchema` (drop `V2`). +- **Rationale:** The schema is local to `v1/model.ts`; nothing in this file disambiguates a `V2` schema from a `V1` schema because no `V1` schema exists. Same generator-wide concern as #7 and #8 — propagating the wire RPC version into TS identifiers leaks an architectural detail of the upstream service. + ## Observations ### 33. Identifier doubling for path + UUID -The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #6 and #7. +The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5 and #6. ### 34. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. @@ -236,7 +236,7 @@ The package directory is `externalmetadata` (one word, no separator), but every - `entity` / `entityType` — the kind of object *within* the external system (a Tableau workbook vs. a dashboard; a Kafka topic vs. a partition). Open string, not enumerated. - `BROWSE`, `MANAGE`, `MODIFY`, `CREATE_EXTERNAL_METADATA` — UC privileges referenced in method JSDoc but not modeled as types. - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `properties` — user-defined `Record` (see #16 for naming concern). +- `properties` — user-defined `Record` (see #15 for naming concern). - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. ## File coverage diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index 8c13dd59..1a826793 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -15,7 +15,7 @@ computes a feature on a schedule and writes results to an offline or online store). Feature transformations are a discriminated union over 13 aggregation functions and 3 data sources (Delta, Kafka, request-time), composed under three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 44 +**Total weird names flagged:** 51 --- @@ -25,52 +25,55 @@ three flavors of time window (continuous, tumbling, sliding). |---|------|------|------|----------|----------|-------------------| | 1 | package `features` / module `@databricks/sdk-features` | (package) | package | High | 1 Vague/generic, 12 Duplicate concepts | The bare term "features" is ambiguous: (a) ML features (this package), (b) Databricks product features / feature flags (settings/previews), (c) "features" of a billing plan (billing). A reader cannot disambiguate from the import path. Rename to `@databricks/sdk-feature-engineering`, `@databricks/sdk-ml-features`, or `@databricks/sdk-feature-definitions`. | | 2 | three sibling packages: `features` / `featurestore` / `materializedfeatures` | (across packages) | package set | High | 12 Duplicate concepts | The Feature Engineering surface is split across three top-level packages whose names overlap at the prefix. Boundaries: `features` defines feature *definitions* (this package); `materializedfeatures` is **misnamed** — it actually owns feature **lineage and tags** (`FeatureLineage`, `FeatureTag`), not materialized features (which live here); `featurestore` owns **online stores**. The names do not align with their contents. Either rename `materializedfeatures` to `featuremetadata` / `featurelineage`, or move `MaterializedFeature` and its client methods out of this package into the (misnamed) `materializedfeatures` package. | -| 3 | `Feature` interface | model.ts:279 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | +| 3 | `Feature` interface | model.ts:280 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | | 4 | `Client` | client.ts:65 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `FeaturesClient` or `FeatureEngineeringClient` would self-identify and disambiguate from `featurestore.Client` and `materializedfeatures.Client`. | -| 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-628 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 631 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | -| 6 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` and 11 sibling values | model.ts:13-24 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | Only one value (`SCALAR_DATA_TYPE_UNSPECIFIED`) stutters the enum name; the other eleven (`INTEGER`, `FLOAT`, `BOOLEAN`, etc.) are reasonable. Just remove the sentinel or rename to `Unspecified`. The wire format is dictated by the API; TS keys can be Pascal-cased via the zod transform. | -| 7 | `ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` (sentinel) | model.ts:13 | enum value | Medium | 6 Misleading names, 18 Long enum values | Proto-style "Unspecified" sentinel. The field is already `dataType?: ScalarDataType \| undefined` (FieldDefinition:325) — omitting the field communicates "unspecified" naturally. Sentinel is dead in TS. | -| 8 | `Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED` and 12 sibling values | model.ts:30-43 | enum values | High | 2 Redundant enum prefixes, 18 Long enum values | `FUNCTION_TYPE_UNSPECIFIED` stutters; the others (`AVG`, `COUNT`, `SUM`, `MIN`, `MAX`, `FIRST`, `LAST`, `APPROX_COUNT_DISTINCT`, `APPROX_PERCENTILE`, `STDDEV_POP`, `STDDEV_SAMP`, `VAR_POP`, `VAR_SAMP`) are fine SQL idioms. Drop only the sentinel. | -| 9 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | -| 10 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 178, 751, 549, 543, 329, 459, 84, 92, 710, 721, 811, 817 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | -| 11 | `AggregationFunction.operation` discriminator field | model.ts:61 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `AggregationFunction`; the field holding the function variant is named `operation`. So `aggFn.operation.$case === 'avg'` reads okay, but in JSDoc comments and call sites the relationship is unclear: "operation" is a generic word; the value is *the function itself*. Could be `function` (matching the parent type's role in `Function.aggregationFunction.operation`) or `kind`. | -| 12 | `TimeWindow.windowType` field | model.ts:762 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | -| 13 | `MaterializedFeature.destination` field | model.ts:523 | field | Medium | 1 Vague/generic, 15 Generic field names | Carries `offlineStoreConfig` or `onlineStoreConfig`. "Destination" is okay but ambiguous (could be a table name, a URL, a cluster). `store` or `target` would be more domain-specific; `storageDestination` would also work. | -| 14 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:283, 312, 314 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | -| 15 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:288, 312 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #38). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | -| 16 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:302, 252, 447 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | -| 17 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:295, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | -| 18 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:245, 312 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | -| 19 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:250, 314 | field pair | Medium | 12 Duplicate concepts | Same pattern as #18. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | -| 20 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:441, 312, 245 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | -| 21 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:446, 314, 250 | field set | High | 12 Duplicate concepts | Same as #20 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | -| 22 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 267, 769 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | -| 23 | `ColumnIdentifier.variantExprPath` | model.ts:161 | field | High | 5 Cryptic abbreviations, 6 Misleading names | "variantExprPath" — short for "variant expression path". The JSDoc clarifies it is a dot-prefixed column path (e.g., `value.trip_details.pickup_zip`). The `variantExpr` prefix is meaningless to a TS reader; the path is not a "variant expression" in any TS sense. Rename `path` or `columnPath`. | -| 24 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | -| 25 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:362 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | -| 26 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:519 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts:254, 327) — verbose. | -| 27 | `MaterializedFeature.featureName` (full Unity Catalog name) vs `MaterializedFeature.tableName` (full UC table name) | model.ts:521, 528 | field pair | Medium | 6 Misleading names, 19 Underspecified IDs | Both are "full names". JSDoc says `featureName` is "The full name of the feature in Unity Catalog" (i.e., three-part `catalog.schema.name`) and `tableName` is "The fully qualified Unity Catalog path to the table". They look the same shape but reference different objects. `featureFullName` / `tableFullName` would type themselves. Compare to `Feature.fullName` (model.ts:281) where the type name is the disambiguator. | -| 28 | `Feature.fullName` (the feature's three-part name) | model.ts:281 | field | Medium | 6 Misleading names, 19 Underspecified IDs | "fullName" without context is ambiguous (full as opposed to what?). The JSDoc says "three-part name (catalog, schema, name)". A `name: string` carrying a fully-qualified identifier is a common UC pattern; `qualifiedName` or `threePartName` would be self-describing. Same critique applies to `DeleteFeatureRequest.fullName` (path), `GetFeatureRequest.fullName`, `DeltaTableSource.fullName`. | -| 29 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:225, 235, 230 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | -| 30 | `KafkaConfig.bootstrapServers` | model.ts:409 | field | Low | (none) | Standard Kafka term. Fine. | -| 31 | `SubscriptionMode.$case === 'assign'` | model.ts:730 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | -| 32 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:743 | field | Low | (none) | Fine, matches Kafka SDK. | -| 33 | `extraOptions` field (`Record`) | model.ts:419 | field | Medium | 1 Vague/generic | "Extra" is meaningless — extras compared to what? The JSDoc says it's "Catch-all for miscellaneous options". Rename `kafkaOptions` or `additionalOptions`. Fine if you accept "extra" as conventional escape-hatch idiom. | -| 34 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:600 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | -| 35 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:575, 581, 589 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | -| 36 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:539, 523 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | -| 37 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:310 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | -| 38 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:467, 397 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | -| 39 | `LineageContext` interface name | model.ts:465 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | -| 40 | `JobContext.jobId` JSDoc typo | model.ts:397 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | -| 41 | `JobContext.jobRunId` | model.ts:399 | field | Low | (none) | Fine. | -| 42 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:285-288 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | -| 43 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:241-245 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | -| 44 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | -| 45 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | -| 46 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2396, 2446, 2491 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 47 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:170, 702, 781 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | -| 48 | `Function` interface shadows JS built-in `Function` | model.ts:343 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-635 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 636 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | +| 6 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | +| 7 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 179, 758, 572, 566, 344, 467, 84, 92, 716, 727, 819, 825 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | +| 8 | `AggregationFunction.operation` discriminator field | model.ts:61 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `AggregationFunction`; the field holding the function variant is named `operation`. So `aggFn.operation.$case === 'avg'` reads okay, but in JSDoc comments and call sites the relationship is unclear: "operation" is a generic word; the value is *the function itself*. Could be `function` (matching the parent type's role in `Function.aggregationFunction.operation`) or `kind`. | +| 9 | `TimeWindow.windowType` field | model.ts:769 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | +| 10 | `MaterializedFeature.destination` field | model.ts:538 | field | Medium | 1 Vague/generic, 15 Generic field names | Carries `offlineStoreConfig` or `onlineStoreConfig`. "Destination" is okay but ambiguous (could be a table name, a URL, a cluster). `store` or `target` would be more domain-specific; `storageDestination` would also work. | +| 11 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:288, 317, 319 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | +| 12 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:293, 317 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #35). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | +| 13 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:307, 253, 463 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | +| 14 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:300, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | +| 15 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:246, 317 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | +| 16 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:251, 319 | field pair | Medium | 12 Duplicate concepts | Same pattern as #15. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | +| 17 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:456, 317, 246 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | +| 18 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:461, 319, 251 | field set | High | 12 Duplicate concepts | Same as #17 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | +| 19 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 268, 777 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | +| 20 | `ColumnIdentifier.variantExprPath` | model.ts:161 | field | High | 5 Cryptic abbreviations, 6 Misleading names | "variantExprPath" — short for "variant expression path". The JSDoc clarifies it is a dot-prefixed column path (e.g., `value.trip_details.pickup_zip`). The `variantExpr` prefix is meaningless to a TS reader; the path is not a "variant expression" in any TS sense. Rename `path` or `columnPath`. | +| 21 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 22 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:376 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | +| 23 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:535 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts) — verbose. | +| 24 | `MaterializedFeature.featureName` (full Unity Catalog name) vs `MaterializedFeature.tableName` (full UC table name) | model.ts:537, 551 | field pair | Medium | 6 Misleading names, 19 Underspecified IDs | Both are "full names". JSDoc says `featureName` is "The full name of the feature in Unity Catalog" (i.e., three-part `catalog.schema.name`) and `tableName` is "The fully qualified Unity Catalog path to the table". They look the same shape but reference different objects. `featureFullName` / `tableFullName` would type themselves. Compare to `Feature.fullName` (model.ts:286) where the type name is the disambiguator. | +| 25 | `Feature.fullName` (the feature's three-part name) | model.ts:286 | field | Medium | 6 Misleading names, 19 Underspecified IDs | "fullName" without context is ambiguous (full as opposed to what?). The JSDoc says "three-part name (catalog, schema, name)". A `name: string` carrying a fully-qualified identifier is a common UC pattern; `qualifiedName` or `threePartName` would be self-describing. Same critique applies to `DeleteFeatureRequest.fullName` (path), `GetFeatureRequest.fullName`, `DeltaTableSource.fullName`. | +| 26 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:226, 236, 231 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | +| 27 | `KafkaConfig.bootstrapServers` | model.ts:424 | field | Low | (none) | Standard Kafka term. Fine. | +| 28 | `SubscriptionMode.$case === 'assign'` | model.ts:737 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | +| 29 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:750 | field | Low | (none) | Fine, matches Kafka SDK. | +| 30 | `extraOptions` field (`Record`) | model.ts:434 | field | Medium | 1 Vague/generic | "Extra" is meaningless — extras compared to what? The JSDoc says it's "Catch-all for miscellaneous options". Rename `kafkaOptions` or `additionalOptions`. Fine if you accept "extra" as conventional escape-hatch idiom. | +| 31 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:623 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | +| 32 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:598, 604, 612 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | +| 33 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:562, 538 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | +| 34 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:315 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | +| 35 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | +| 36 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | +| 37 | `JobContext.jobId` JSDoc typo | model.ts:411 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | +| 38 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | +| 39 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:290-293 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | +| 40 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:242-246 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | +| 41 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | +| 42 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | +| 43 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 44 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 45 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 46 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely per #6). | +| 47 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #46. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | +| 48 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | +| 49 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | +| 50 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #48. | +| 51 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#46-50) clears this automatically. | --- @@ -125,7 +128,7 @@ has no signal that this is the ML kind. Recommend ### H3. The `Feature` type name is overloaded The unqualified noun `Feature` is the central type of this package -(model.ts:279) and is re-exported from `index.ts`. Once it lands in a +(model.ts:280) and is re-exported from `index.ts`. Once it lands in a consumer's namespace it shadows the common-English sense of the word. ```ts @@ -169,16 +172,16 @@ AggregationFunction.function_type oneof instead") lives in the JSDoc *text* but neither the type, nor the field, nor the enum carries a `@deprecated` tag. TS callers' IDEs will not flag use. The full list: -- `Function.functionType` — model.ts:347 -- `Function.extraParameters` — model.ts:351 -- `Feature.inputs` — model.ts:288 -- `Feature.timeWindow` — model.ts:295 -- `Feature.filterCondition` — model.ts:302 -- `BackfillSource.$case === 'deltaTableSource'` — model.ts:131 -- `DeltaTableSource.entityColumns` — model.ts:245 -- `DeltaTableSource.timeseriesColumn` — model.ts:250 -- `KafkaSource.entityColumnIdentifiers` — model.ts:441 -- `KafkaSource.timeseriesColumnIdentifier` — model.ts:446 +- `Function.functionType` — model.ts:363 +- `Function.extraParameters` — model.ts:368 +- `Feature.inputs` — model.ts:293 +- `Feature.timeWindow` — model.ts:300 +- `Feature.filterCondition` — model.ts:307 +- `BackfillSource.$case === 'deltaTableSource'` — model.ts:130 +- `DeltaTableSource.entityColumns` — model.ts:246 +- `DeltaTableSource.timeseriesColumn` — model.ts:251 +- `KafkaSource.entityColumnIdentifiers` — model.ts:456 +- `KafkaSource.timeseriesColumnIdentifier` — model.ts:461 Ten deprecated fields with no `@deprecated` tag. Add the tag. @@ -205,8 +208,8 @@ misinterpret the record's state. Either: - Drop `isOnline` and require consumers to inspect `destination`. - Make `isOnline` a server-derived read-only flag and forbid setting it on - create/update (it does *not* appear in the field-mask schema — model.ts:2476 - — but the JSDoc doesn't say it's read-only). + create/update (it appears in the field-mask schema — model.ts:2510 — and + the JSDoc doesn't say it's read-only). ### H9. Path-parameter IDs typed as `number` @@ -225,6 +228,37 @@ via `globalThis.Function`. Most ESLint configs (including this repo's, see Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. +### H11. Proto-architectural leak: `Outer_Inner` nested names + +Four public identifiers carry the proto-nested `_` underscore +convention straight from the `.proto` IDL into the TS public API: + +- `Function_FunctionType` (enum, model.ts:29) +- `MaterializedFeature_PipelineScheduleState` (enum, model.ts:47) +- `Function_ExtraParameter` (interface, model.ts:388) +- `KafkaConfig_ExtraOptionsEntry` (interface, model.ts:444) + +Each requires an `eslint-disable @typescript-eslint/naming-convention` line +to compile, with the disable comment self-identifying as "Proto-style +nested enum name" or "Proto-style nested message name". The corresponding +zod-schema constants inherit the underscore (`unmarshalFunction_ExtraParameterSchema`, +`marshalFunction_ExtraParameterSchema` — model.ts:1163, 1935). + +`KafkaConfig_ExtraOptionsEntry` is a particularly clear leak: it is the +auto-generated proto map-entry type for the `map` field on +`KafkaConfig`. The user-facing TS field is already `extraOptions: +Record` — no consumer can or should reference the entry +type. + +All four are re-exported from `index.ts` (lines 7-8, 38, 44), so the +underscore-shaped names cross the package boundary into every importer's +namespace. + +Fix at the generator: emit the inner type at the file top level without +the outer prefix (`FunctionType`, `PipelineScheduleState`, +`ExtraFunctionParameter`) and drop the synthetic map-entry interface +entirely. + --- ## Medium severity (worth pushing back on) @@ -282,15 +316,7 @@ redundant. preserve forward extensibility — e.g., to let `SumFunction` later add fields without affecting `AvgFunction`. Worth pushing back on.) -### M3. Enum sentinels - -`ScalarDataType.SCALAR_DATA_TYPE_UNSPECIFIED` and -`Function_FunctionType.FUNCTION_TYPE_UNSPECIFIED` are proto-style sentinels -for "no value set". The fields they live in are already `T | undefined` in -TS. The sentinels are dead and create ambiguity (does `undefined` mean "not -set" or "set to UNSPECIFIED"?). - -### M4. Field-name pluralization mismatches the type +### M3. Field-name pluralization mismatches the type - `Feature.entities: EntityColumn[]` — plural field, singular element. Fine. - `KafkaSource.entityColumnIdentifiers: ColumnIdentifier[]` — plural field, @@ -299,34 +325,34 @@ set" or "set to UNSPECIFIED"?). - `DeltaTableSource.entityColumns: string[]` — plural field, primitive element. Deprecated. Three plural conventions for the same notion. -### M5. Three names for one notion (`entities` / `entityColumns` / `entityColumnIdentifiers`) +### M4. Three names for one notion (`entities` / `entityColumns` / `entityColumnIdentifiers`) See H5. The three names also differ in element type (`EntityColumn`, `string`, `ColumnIdentifier`). Cf. T3 in cross-cutting observations below. -### M6. `ColumnSelection` interface is too generic +### M5. `ColumnSelection` interface is too generic JSDoc says `ColumnSelection` represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow". The name gives no domain hint. `LatestColumnValue` would name the behavior. (Same critique as `Credential` in the credentials audit.) -### M7. `MaterializedFeature.destination` is a generic word +### M6. `MaterializedFeature.destination` is a generic word Carries an `OfflineStoreConfig | OnlineStoreConfig` union. The English word "destination" suggests a URL or path. Domain word: `target`, `store`, or `storage`. -### M8. JSDoc references stale field names +### M7. JSDoc references stale field names - "Use Feature.entity instead" (model.ts:243) — actual field is `entities`. -- "Use Feature.entity instead" (model.ts:438) — same typo. -- "Use AggregationFunction.inputs instead" (model.ts:286) — field doesn't +- "Use Feature.entity instead" (model.ts:453) — same typo. +- "Use AggregationFunction.inputs instead" (model.ts:290) — field doesn't exist; modern shape is per-function `input?`. -- "Use Function.aggregation_function.time_window" (model.ts:292) — references +- "Use Function.aggregation_function.time_window" (model.ts:297) — references snake_case wire name in TS-facing JSDoc. -### M9. `executeCall` vs `executeHttpCall` +### M8. `executeCall` vs `executeHttpCall` Same as sibling packages. Two `execute*` verbs. @@ -334,70 +360,59 @@ Same as sibling packages. Two `execute*` verbs. ## Low severity (nits) -### L1. `ScalarDataType` is one of the few "good" enums - -Eleven of its twelve values (`INTEGER`, `FLOAT`, `BOOLEAN`, `STRING`, `DOUBLE`, -`LONG`, `TIMESTAMP`, `DATE`, `SHORT`, `BINARY`, `DECIMAL`) are concise SQL -types. Only the sentinel `SCALAR_DATA_TYPE_UNSPECIFIED` is a problem. - -### L2. `PACKAGE_SEGMENT` undescriptive +### L1. `PACKAGE_SEGMENT` undescriptive Sibling-package pattern. -### L3. `MtlsConfig.disableHostnameVerification` reasonable +### L2. `MtlsConfig.disableHostnameVerification` reasonable Boolean named in negative ("disable") to match the underlying Kafka option (`kafka.ssl.endpoint.identification.algorithm`). JSDoc warns about security implications. Fine. -### L4. `bootstrapServers` is conventional Kafka +### L3. `bootstrapServers` is conventional Kafka Fine. -### L5. `cronSchedule` field on `MaterializedFeature` +### L4. `cronSchedule` field on `MaterializedFeature` `MaterializedFeature.cronSchedule: string` is a Quartz cron expression. The field name is fine; the type could be a branded `CronExpression` for stronger typing, but flagging only for completeness. -### L6. `req` parameter naming in client methods +### L5. `req` parameter naming in client methods Standard SDK-wide convention. Fine. -### L7. `Function_FunctionType` enum values use SQL-conventional uppercase - -`AVG`, `COUNT`, `SUM`, etc. Match SQL/Spark idioms. Fine for the wire format; -TS keys could be PascalCase. - -### L8. `ContinuousWindow.offset` allows non-positive +### L6. `ContinuousWindow.offset` allows non-positive Note in JSDoc: "must be non-positive" — i.e., 0 or negative duration. The type is `Temporal.Duration` which doesn't constrain sign. Documentation-only constraint; not enforced. Same critique as `SlidingWindow.slideDuration` ("must be positive and less than duration"). -### L9. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text +### L7. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text A `string` containing potentially many KB of source text. Naming is fine; the data shape is the design choice. Listing for completeness. -### L10. JSDoc typo on `JobContext.jobId` +### L8. JSDoc typo on `JobContext.jobId` "The job ID where this API invoked." → "where this API was invoked." Minor. -### L11. `SecretScopeReference { scope, key }` +### L9. `SecretScopeReference { scope, key }` Two-field reference to a Databricks secret. Standard. Fine. -### L12. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` +### L10. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` Four Spark Structured Streaming idioms. Standard. Fine. -### L13. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` +### L11. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` Three field-mask builders. Standard generator pattern. Fine. -### L14. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` +### L12. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` The list endpoint filters by feature name (full UC name). Field is `featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` @@ -450,6 +465,7 @@ Only `v1` exists; nothing to compare. | Acronym | Code form | JSDoc text | Consistent? | |---------|-----------|-----------|-------------| | UC (Unity Catalog) | `unityCatalog*` (e.g., `ucServiceCredentialName`) — *not used here*; appears in `AuthConfig.$case === 'ucServiceCredentialName'` (model.ts:104) | "Unity Catalog" spelled out | Mixed (cf. credentials audit M7) | + | SQL | `transformationSql` field, `sql` lowercase | "SQL" all-caps | Field uses `Sql` (PascalCase-first-letter). Fine. | | TLS / mTLS | `MtlsConfig`, `mtlsConfig` | "Mutual-TLS (mTLS)" mixed | Code `Mtls` (PascalCase-first-letter). Diverges from RFC convention "mTLS". | | TLS / SSL | `disableHostnameVerification` (no acronym) | "SSL" / "TLS" all-caps | N/A | @@ -491,9 +507,15 @@ who know the upstream API; opaque otherwise. | File | Lines | Exports counted | Audited | |------|-------|-----------------|---------| -| `src/v1/model.ts` | 2499 | 3 enums, 50 interfaces, 60 zod consts (30 unmarshal + 30 marshal), 3 field-mask helpers | yes | -| `src/v1/client.ts` | 631 | 1 class, public methods covering 3 resource families (Feature, KafkaConfig, MaterializedFeature) | yes | -| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | -| `src/v1/index.ts` | 78 | 1 class re-export, 3 enum re-exports, 60 type re-exports | yes | +| `src/v1/model.ts` | 2638 | 3 enums, 50 interfaces, 60 zod consts (30 unmarshal + 30 marshal), 3 field-mask helpers | yes | +| `src/v1/client.ts` | 636 | 1 class, public methods covering 3 resource families (Feature, KafkaConfig, MaterializedFeature) | yes | +| `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | +| `src/v1/index.ts` | 77 | 1 class re-export, 3 enum re-exports, 60 type re-exports | yes | Every type, field, enum value, and method enumerated above is accounted for. + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index cd2c8e3d..b514e63c 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -74,45 +74,15 @@ ## Findings -### 1. Enum-value prefixes repeat the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) - -**Symbols:** `OnlineStore_State.STATE_UNSPECIFIED` (model.ts:11), -`PublishSpec_PublishMode.PUBLISH_MODE_UNSPECIFIED` (model.ts:28). - -**Issue:** Members are already namespaced under the enum type. The leading -`STATE_` / `PUBLISH_MODE_` segment duplicates the enum's own concept. Reads -poorly at use site: - -```ts -if (store.state === OnlineStore_State.STATE_UNSPECIFIED) { ... } -// ^^^^^ ^^^^^ -// repeats "state" -``` - -Compare to `onlinetables/v1` which uses -`OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` — same problem there. -However, the values here double as on-the-wire JSON strings (the same Zod -schema parses raw API strings into these identifiers, model.ts:150, 184), so -renaming requires server acceptance and is a behavioural change. **Flag for -the API team / generator.** TS-side identifier can be split from wire string -(see finding 2) as a safe local fix. - -**Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. -**Suggested TS-level only (safe, see finding 2):** -`Unspecified = 'STATE_UNSPECIFIED'`. - ---- - -### 2. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) +### 1. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) **Symbols:** Every value in both enums (model.ts:11–23, 28–44). **Issue:** The project's `.agent/skills/google-ts-styleguide` (and the Google TS Style Guide § 5.3) mandates `UpperCamelCase` for enum members, not `SCREAMING_SNAKE_CASE`. The project's own `typescript.mdc` enforces no -underscores in TS identifiers. The enum members `STATE_UNSPECIFIED`, -`FAILING_OVER`, `PUBLISH_MODE_UNSPECIFIED` all contain underscores and are -SCREAMING-cased. +underscores in TS identifiers. Enum members like `FAILING_OVER` contain +underscores and are SCREAMING-cased. Note: enum string *values* double as the on-the-wire representation here (the Zod schemas parse raw API strings into these identifiers, e.g. `z.enum( @@ -147,7 +117,7 @@ unilateral change here would diverge from sibling packages. --- -### 3. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) +### 2. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) **Symbols:** `OnlineStore_State.FAILING_OVER` (model.ts:23), `STARTING`, `DELETING`, `UPDATING` (model.ts:13, 17, 21) vs. `STOPPED`, `AVAILABLE` @@ -159,11 +129,11 @@ mixes a participle with a particle preposition; the canonical network/database term is `FAILOVER` (noun) or `FAILING_OVER` (verb-phrase). Compare: AWS RDS uses `failing-over` as a state, Postgres uses `failover`. Mark as a wire-level concern — TS identifier `FailingOver` is -fine under finding 2. **Pass at the TS level**, flag at the wire level. +fine under finding 1. **Pass at the TS level**, flag at the wire level. --- -### 4. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) +### 3. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) **Symbol:** `DeleteOnlineTableRequest.onlineTableName` (model.ts:59), wire field `online_table_name` (the field appears in the URL path, not JSON). @@ -201,7 +171,7 @@ divergence. --- -### 5. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) +### 4. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) **Symbol:** `OnlineStore.name` (model.ts:84). JSDoc: "The name of the online store. This is the unique identifier for the online store." @@ -228,7 +198,7 @@ arbitrary strings. --- -### 6. `OnlineStore.creator` is an email, not a name — category 1 (Vague/generic) and category 17 (Inconsistent action verbs) +### 5. `OnlineStore.creator` is an email, not a name — category 1 (Vague/generic) and category 17 (Inconsistent action verbs) **Symbol:** `OnlineStore.creator` (model.ts:86). JSDoc: "The email of the creator of the online store." @@ -252,7 +222,7 @@ fix in isolation. **Pass with a recommendation.** --- -### 7. `OnlineStore.creationTime` vs. `…At` pattern — category 17 (Inconsistent action verbs) and category 7 (Overly verbose) +### 6. `OnlineStore.creationTime` vs. `…At` pattern — category 17 (Inconsistent action verbs) and category 7 (Overly verbose) **Symbol:** `OnlineStore.creationTime` (model.ts:88). Type: `Temporal.Instant`. @@ -274,7 +244,7 @@ not a unilateral fix.** --- -### 8. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) +### 7. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) **Symbol:** `OnlineStore.capacity?: string` (model.ts:92). JSDoc: "The capacity of the online store. Valid values are "CU_1", "CU_2", "CU_4", @@ -297,11 +267,11 @@ current shape — bare `string` with a JSDoc note — provides no compile-time help. **Flag for SDK-wide policy on open enums** (categories 1 + 6). Also: "CU" is unexplained (probably "Compute Unit"). Audit category 5 -(cryptic abbreviation) — see finding 9. +(cryptic abbreviation) — see finding 8. --- -### 9. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) +### 8. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) **Symbol:** `OnlineStore.capacity` valid values `"CU_1"`–`"CU_8"` (model.ts:91). @@ -317,7 +287,7 @@ Valid values: …". --- -### 10. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* +### 9. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* **Symbol:** `OnlineStore.readReplicaCount?: number` (model.ts:94). JSDoc: "The number of read replicas for the online store. Defaults to 0." @@ -328,7 +298,7 @@ naming bug per se — flag JSDoc. --- -### 11. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) +### 10. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) **Symbol:** `OnlineStore.usagePolicyId?: string` (model.ts:96). @@ -341,7 +311,7 @@ referring to a usage policy defined in the budget-policy service." --- -### 12. `PublishSpec.onlineStore` is a *name* (string), not an `OnlineStore` — category 15 (Generic field names losing meaning) and category 16 (Field contradicting type domain) +### 11. `PublishSpec.onlineStore` is a *name* (string), not an `OnlineStore` — category 15 (Generic field names losing meaning) and category 16 (Field contradicting type domain) **Symbol:** `PublishSpec.onlineStore?: string` (model.ts:101). JSDoc: "The name of the target online store." @@ -363,7 +333,7 @@ correctness opportunity, not a coordination issue with upstream Go fields. --- -### 13. `PublishSpec` is vague — category 1 (Vague/generic) +### 12. `PublishSpec` is vague — category 1 (Vague/generic) **Symbol:** `PublishSpec` (model.ts:99). @@ -381,13 +351,13 @@ which has more room because it lives in the `featurestore` Go package. --- -### 14. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) +### 13. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) **Symbols:** `PublishTableRequest.publishSpec.onlineTableName`, `PublishTableResponse.onlineTableName` (model.ts:103, 117). **Issue:** The JSDoc on both reads "The full three-part (catalog, schema, -table) name of the online table." — same finding as #4: the field is a +table) name of the online table." — same finding as #3: the field is a specific structured string. Currently typed `string`. No compile-time safety. Cross-SDK pattern is to leave as `string` with JSDoc — accept that trade-off, but the JSDoc spelling should be canonical and consistent. The @@ -405,14 +375,14 @@ different doc strings: --- -### 15. `PublishTableResponse.pipelineId` — *pass* +### 14. `PublishTableResponse.pipelineId` — *pass* Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. No issue. --- -### 16. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* +### 15. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* **Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` (model.ts:126). @@ -423,7 +393,7 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 17. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) +### 16. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) **Symbol:** `Client.publishTable` (client.ts:212). JSDoc: "Publish features." @@ -446,7 +416,7 @@ the URL — but diverges from Go. **Pass on the name, flag the JSDoc.** --- -### 18. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) +### 17. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) **Symbols:** `Client.deleteOnlineTable` (client.ts:117, featurestore) vs. `Client.deleteOnlineTable` (client.ts:108, onlinetables). @@ -461,7 +431,7 @@ The semantic is "delete an online table" in both cases, but the endpoints are separate. This is a *backend* concern, but at the SDK level a TS user will import both `@databricks/sdk-featurestore/v1.Client` and `@databricks/sdk-onlinetables/v1.Client` and find two identically-named -methods that do related but distinct things. Compounded by finding 4 where +methods that do related but distinct things. Compounded by finding 3 where the *request types* are also identically named but field-incompatible. **Suggested at the SDK level:** in `featurestore`, rename the method to @@ -471,7 +441,7 @@ the *request types* are also identically named but field-incompatible. --- -### 19. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* +### 18. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* **Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and `onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the @@ -480,14 +450,14 @@ Google AIP-134 update-mask vocabulary. **Pass.** --- -### 20. `Client` class name — category 1 (Vague/generic) — *pass* +### 19. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** --- -### 21. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 20. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:41). @@ -503,7 +473,7 @@ do not fix in isolation.** --- -### 22. `userAgent` / `httpClient` / `host` / `logger` — *pass* +### 21. `userAgent` / `httpClient` / `host` / `logger` — *pass* Standard private field names. Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported @@ -511,14 +481,14 @@ type `HttpClient`). **Pass.** --- -### 23. `readAll` — *pass* +### 22. `readAll` — *pass* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 24. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* +### 23. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. Note however the *file* mixes `build…`, @@ -527,7 +497,7 @@ seven functions. Not unique to this package. **Pass.** --- -### 25. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* +### 24. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -539,7 +509,7 @@ package qualifies. **Pass on package consistency.** --- -### 26. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) +### 25. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) **Symbol:** `Client.listOnlineStores` (client.ts:160). @@ -567,20 +537,61 @@ and update JSDocs to drop "Feature" (already redundant since the package is --- -### 27. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* +### 26. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 28. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* +### 27. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* `pipelineId` correctly camelCases the two-letter "ID"; `creator` is a plain word. **Pass.** --- +### 28. `OnlineStore_State` — model.ts:9 + +**Why:** `Parent_Nested` underscore-joined identifier is a literal +translation of a proto nested-type path into the TS symbol name. The +source file even concedes this with `// eslint-disable-next-line ... -- +Proto-style nested enum name.` The proto file structure leaks directly +into the public TS surface. + +**Category:** Proto-architectural-leak (Proto-nested-type infix). + +**Suggested:** `OnlineStoreState`. + +**Rationale:** The enum is conceptually "the state of an online store" — +the standalone TS identifier `OnlineStoreState` is unambiguous, follows +Google TS Style Guide § 5.3 (`UpperCamelCase` types, no underscores), and +does not require an eslint-disable. The wire values are unaffected. The +`Foo_Bar` shape exists purely because protoc emits nested message names +that way; downstream TS callers should not have to model the proto +namespace. + +--- + +### 29. `PublishSpec_PublishMode` — model.ts:27 + +**Why:** Same `Parent_Nested` proto-namespace leak as finding 28. The +identifier reads as "PublishSpec's PublishMode" — the enclosing-type +prefix is a verbatim port of the proto nested-type name, and the file +acknowledges this with the same eslint-disable comment. + +**Category:** Proto-architectural-leak (Proto-nested-type infix). + +**Suggested:** `PublishMode`. + +**Rationale:** The enum is conceptually a publish mode; the `PublishSpec_` +prefix duplicates the enclosing type and adds no information (the only +field that uses it is `PublishSpec.publishMode`). Dropping the proto +nesting yields a clean `PublishMode` symbol that matches how the field +already reads (`publishMode: PublishMode`). No wire change. + +--- + ## Cross-package notes (per audit instructions) ### `OnlineStore` concept vs. `features.OnlineStoreConfig` @@ -595,12 +606,12 @@ but distinct types live in two packages: by name. - `featurestore.OnlineStore.name: string` — is the store's identifier. - `featurestore.PublishSpec.onlineStore: string` — also references a store - by name (but with no `…Name` suffix — see finding 12). + by name (but with no `…Name` suffix — see finding 11). **Recommendation:** harmonise. Either: 1. All references to an online-store identifier use `onlineStoreName` (so rename `PublishSpec.onlineStore` to `onlineStoreName` — matches - finding 12). + finding 11). 2. Or all references use `onlineStore` and the type is `string` with a marker (e.g. `type OnlineStoreName = string`). @@ -610,7 +621,7 @@ Option 1 is cheaper. **P1 cross-package alignment fix.** ### `DeleteOnlineTableRequest` name collision with `onlinetables/v1` -Already covered in finding 4. Two distinct request types share the same +Already covered in finding 3. Two distinct request types share the same type name across packages, with different field names. A consumer who imports both packages (likely — they are complementary) writes: @@ -626,7 +637,7 @@ Friction-heavy. **Strong recommendation:** rename `DeletePublishedOnlineTableRequest` (it deletes a table created by `publishTable`) — or rename `featurestore.deleteOnlineTable` method to `deletePublishedOnlineTable` and follow with the request type. Aligns with -finding 18. +finding 17. --- @@ -644,20 +655,22 @@ approaches (string enum vs. discriminated union). Plus there is no ## Summary (counts) -- **Critical / cross-package consistency:** 2 findings (#12 - `PublishSpec.onlineStore` should be `onlineStoreName`; #4 +- **Critical / cross-package consistency:** 2 findings (#11 + `PublishSpec.onlineStore` should be `onlineStoreName`; #3 `DeleteOnlineTableRequest` shape collision with `onlinetables`). -- **High (style guide violations):** 2 findings (#2 enum SCREAMING - casing; #21 `PACKAGE_SEGMENT` casing). -- **Medium (naming clarity, JSDoc drift):** 9 findings (#1, #5, #6, #8, - #9, #11, #13, #17, #18, #26). +- **High (style guide violations / proto-architectural leaks):** 4 + findings (#1 enum SCREAMING casing; #20 `PACKAGE_SEGMENT` casing; #28 + `OnlineStore_State` proto-nested infix; #29 `PublishSpec_PublishMode` + proto-nested infix). +- **Medium (naming clarity, JSDoc drift):** 9 findings (#4, #5, #7, #8, + #10, #12, #16, #17, #25). - **Low / project-wide convention notes (generator-level):** 3 findings - (#7, #10, #25). -- **Pass / acceptable as-is:** 11 findings (#3, #14, #15, #16, #19, #20, - #22, #23, #24, #27, #28 — partial pass with notes). + (#6, #9, #24). +- **Pass / acceptable as-is:** 11 findings (#2, #13, #14, #15, #18, #19, + #21, #22, #23, #26, #27 — partial pass with notes). -**Total flagged findings: 28** distinct items across the audit categories +**Total flagged findings: 29** distinct items across the audit categories (several findings touch multiple categories). Many issues are generator-emitted boilerplate inherited from the Go SDK; the cleanest local -fixes are findings 12, 17 (JSDoc), 18, 26 (JSDoc), and the cross-package -alignments noted above. +fixes are findings 11, 16 (JSDoc), 17, 25 (JSDoc), 28, 29, and the +cross-package alignments noted above. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index 3e13717f..97a1d4ee 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -1,115 +1,40 @@ # Naming Audit: files -**Path:** `packages/files/src/v1/`, `packages/files/src/v2/` -**Versions audited:** v1 AND v2 -**Inferred domain:** File operations on Databricks storage. `v1` is a small hand-written wrapper exposing only `upload` against the modern Files API (`/api/2.0/fs/files/...`). `v2` is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. +**Path:** `packages/files/src/v2/` +**Versions audited:** v2 +**Inferred domain:** File operations on Databricks storage. v2 is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 37 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 12 | -| Low | 7 | -| Observation | 5 | - -## v1 vs v2 comparison - -### Major renames / shape differences - -| v1 name | v2 name | Notes | -|---------|---------|-------| -| `UploadRequest` | `UploadFileRequest` | **Improvement** — the `File` qualifier is needed in v2 because the same client now exposes directory operations too. In v1 the package was implicitly "files-only", so the unqualified `UploadRequest` worked. Same field shape (`filePath`, `contents`, `overwrite`). | -| `DownloadRequest` | `DownloadFileRequest` | Mirror of upload — adds `range` and `ifUnmodifiedSince` (good — extends; cf. v1 has neither). | -| `DownloadResponse` | `DownloadFileResponse` | v1 has 4 fields (`contents`, `contentLength`, `contentType`, `lastModified`). v2 has the same 4. Both are uniform here. | -| `UploadRequest.filePath` (required) | `UploadFileRequest.filePath` (optional `?`) | **Regression** — v1 typed `filePath: string` as required; v2 generated all fields optional because the upstream proto schema marks them optional. The generated client falls back to `req.filePath ?? ''` (`client.ts:716`) which silently encodes an empty path. v1 is stricter and clearer. | -| `UploadRequest.contents: ReadableStream` | `UploadFileRequest.contents?: ReadableStream` | **Regression** — v1 typed the stream element as `Uint8Array`; v2 dropped the generic and admits `ReadableStream`. v2 also makes `contents` optional, which makes no sense semantically (no contents == nothing to upload). | -| `UploadRequest.overwrite?: boolean` | `UploadFileRequest.overwrite?: boolean` | Same name, same shape. Good. | -| `DownloadResponse.contents: ReadableStream` (required) | `DownloadFileResponse.contents?: ReadableStream` (optional, untyped) | Same regression — v1 stronger types. | -| `DownloadResponse.contentLength?: number` | `DownloadFileResponse.contentLength?: number` | Same. | -| _(v1 has no download method, despite `DownloadRequest`/`DownloadResponse` being exported)_ | `Client.downloadFile(req: DownloadFileRequest)` | **v1 dangling types** — `DownloadRequest` and `DownloadResponse` are exported from `v1/index.ts` but never referenced by `v1/client.ts`. They are dead/orphaned types in v1. | - -### New in v2 (no v1 counterpart) - -- Methods (legacy DBFS): `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`. -- Methods (modern Files): `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `listDirectoryContentsIter`. -- Types (legacy DBFS): `AddBlock`, `Close`, `Create`, `Delete`, `FileInfo`, `GetStatus`, `ListStatus`, `MkDirs`, `Move`, `Put`, `Read`, plus their response counterparts. -- Types (modern Files): `CreateDirectoryRequest`/`Response`, `DeleteDirectoryRequest`/`Response`, `DeleteFileRequest`/`Response`, `DirectoryEntry`, `DownloadFileRequest`/`Response`, `GetDirectoryMetadataRequest`/`Response`, `GetFileMetadataRequest`/`Response`, `ListDirectoryContentsRequest`, `ListDirectoryResponse` (note plural/singular asymmetry), `UploadFileRequest`/`Response`. - -### Dropped in v2 - -- v1 utility `encodeFilePath` is renamed to v2 `encodeMultiSegmentPath` (good — name no longer ties the encoder to "files"; works for `/directories/...` and `/files/...` paths alike). -- v1 helper `sendAndCheckError` is kept in v2 BUT v2 also adds `executeHttpCall`, `executeCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`. Both helpers coexist in v2 (`sendAndCheckError` is now only used by `downloadFile` to keep the body stream un-consumed). - -### Net assessment - -v2 mostly improves names by qualifying with `File`/`Directory`, but it also: (a) keeps every legacy DBFS message verbatim — `Read`, `Move`, `Put`, `Delete`, `Close`, `Create`, `MkDirs`, `AddBlock` — as verb-shaped type names colliding with TS/HTTP/JS conventions; (b) blends two separate REST APIs (`/dbfs` and `/fs`) into a single `Client` class with no namespace distinction; (c) weakens v1's `Uint8Array` stream typing to bare `ReadableStream`; (d) re-exports `FileInfo` which already exists in `experiments` and `marketplaces` packages. v1 is small and tighter; v2 is broader and noisier. +| High | 8 | +| Medium | 8 | +| Low | 6 | +| Observation | 2 | ## High severity -### 1. `Read` — reserved-word collision and misleading shape — `src/v2/model.ts:254` +### 1. `DBFS` vs `Dbfs` casing — never appears in TS identifier, only in JSDoc — model & client -```ts -export interface Read { - /** The path of the file to read. The path should be the absolute DBFS path. */ - path?: string | undefined; - offset?: number | undefined; - length?: number | undefined; -} -``` - -- **Why weird:** `Read` is the legacy DBFS read **request** but the type name reads as either the action verb ("perform a read") or the past tense ("was read"). It collides with the built-in TS `Readonly<>`, `ReadableStream`, `Reader`, etc. In application code, `import {Read} from '@databricks/sdk-files/v2'` is almost guaranteed to be mistaken for a stream type. Also shadows the verb so `read(req: Read)` is `read(read: Read)` — every word in the signature is `read`. -- **Category:** 10 (reserved-word/conflict), 6 (misleading). -- **Suggested name:** `DbfsReadRequest`. -- **Rationale:** Match the modern `DownloadFileRequest` pattern, and explicitly tag it as the legacy DBFS request to distinguish from the modern Files API. The same critique applies to all the other verb-named DBFS messages — see #2. - -### 2. Verb-as-noun cluster: `Move`, `Put`, `Delete`, `Close`, `Create`, `MkDirs`, `AddBlock`, `GetStatus`, `ListStatus` — `src/v2/model.ts:15-264` - -```ts -export interface Move { sourcePath?: ...; destinationPath?: ...; } -export interface Put { path?: ...; contents?: ...; overwrite?: ...; } -export interface Delete { path?: ...; recursive?: ...; } -export interface Close { handle?: ...; } -export interface Create { path?: ...; overwrite?: ...; } -export interface MkDirs { path?: ...; } -export interface AddBlock { handle?: ...; data?: ...; } -export interface GetStatus { path?: ...; } -export interface ListStatus { path?: ...; } -``` - -- **Why weird:** Nine TS interfaces named after verbs (or verb phrases). Every one is the **request** type for the same-named method. Side-by-side with the modern `CreateDirectoryRequest`, `DeleteFileRequest`, `UploadFileRequest`, `DownloadFileRequest`, the legacy types stick out as deeply un-TypeScript-y. -- `Delete` collides directly with the JS `delete` keyword (sub-case) and with `workspace`'s `Delete` interface (`packages/workspace/src/v1/model.ts:65`). -- `Create` collides with React's `Create*` patterns and any other domain's `Create`. -- `Close` reads as a verb / event-listener method (`element.addEventListener('close', ...)`) and as `Promise` reads "Promise to close" rather than "Promise of a Close payload". -- `MkDirs` is a cryptic abbreviation of "make directories" in `PascalCase` instead of the (also bad) `Mkdirs` or the modern `CreateDirectory`. Also: it creates only ONE directory (recursively, like `mkdir -p`), not directories plural. -- `GetStatus` and `ListStatus`: both have a body of just `path?: string` and are conceptually just "stat" / "ls". They differ only in whether a path is a directory or file at runtime (the server figures it out). Their existence is duplicative with the modern `GetFileMetadataRequest`, `GetDirectoryMetadataRequest`, `ListDirectoryContentsRequest`, but no docstring tells callers which to use. -- **Category:** 1 (vague/generic), 6 (misleading shape), 10 (reserved-word collision — `Delete`), 12 (duplicate concept with modern names), 17 (inconsistent verb cluster — Delete/Move/Put are CRUD; AddBlock/Close are stream lifecycle; GetStatus/ListStatus are queries; all in one undifferentiated namespace). -- **Suggested names:** `DbfsMoveRequest`, `DbfsPutRequest`, `DbfsDeleteRequest`, `DbfsCloseRequest`, `DbfsCreateRequest`, `DbfsMkdirsRequest` (or `DbfsMakeDirectoriesRequest`), `DbfsAddBlockRequest`, `DbfsGetStatusRequest`, `DbfsListStatusRequest`. -- **Rationale:** Carries the surface ("DBFS"), follows the modern `Request` shape, no reserved-word collisions, no verb-as-noun ambiguity. Bonus: makes #4 (mixed-surface in single client) much more honest. - -### 3. `DBFS` vs `Dbfs` casing — never appears in TS identifier, only in JSDoc — model & client - -- **Why weird:** "DBFS" appears 11 times in JSDoc strings (e.g. "The path should be the absolute DBFS path.", `model.ts:24,46,161,214,225,233,235,243,255`) and once in client docstrings ("DBFS REST API"). But NONE of the TS type or method names carry the prefix. The class is just `Client`, the methods are `read`/`write`/`put`/`delete`/`move`/`mkdirs` — DBFS is invisible at the TS surface. Compare with `databricks-sdk-go` upstream where these are split into `dbfs.API` and `files.API` as separate services. The TS port merges them and removes the namespace. +- **Why weird:** "DBFS" appears 11 times in JSDoc strings (e.g. "The path should be the absolute DBFS path.", `model.ts:33,64,161,214,225,233,235,243,255`) and once in client docstrings ("DBFS REST API"). But NONE of the TS type or method names carry the prefix. The class is just `Client`, the methods are `read`/`write`/`put`/`delete`/`move`/`mkdirs` — DBFS is invisible at the TS surface. Compare with `databricks-sdk-go` upstream where these are split into `dbfs.API` and `files.API` as separate services. The TS port merges them and removes the namespace. - **Category:** 3 (acronym casing — should be `Dbfs` if it were ever used), 16 (field-contradicting-domain), 17 (inconsistency — JSDoc says DBFS, identifier doesn't). - **Suggested name:** Carry the surface name in identifiers: `DbfsClient` for the legacy methods, or split into two packages / sub-modules: `@databricks/sdk-files/v2/dbfs` and `@databricks/sdk-files/v2/files`. If kept as one client, prefix the methods (`client.dbfsRead`, `client.dbfsMove`, ...). - **Rationale:** Two REST APIs in one class with no naming signal mixes a deprecated surface (DBFS, max 1 MB per call, deprecated by Databricks) with the modern surface (Files API, 5 GiB streaming). Users can't tell which to use from the method list. Surface name in identifier resolves this. -### 4. Package name `files` and class name `Client` are both contextless — `package.json:2`, `client.ts:15,94` +### 2. Package name `files` and class name `Client` are both contextless — `client.ts:94` ```ts -// v1 -export class Client { ... } // src/v1/client.ts:15 -// v2 export class Client { ... } // src/v2/client.ts:94 ``` -- **Why weird:** Both versions export `Client` without qualification. Consuming code that imports from multiple packages ends up with `import {Client as FilesClient} from '@databricks/sdk-files/v2';` in every file. The package name `files` is also generic — DBFS files? UC volume files? Workspace files (already a separate `@databricks/sdk-workspace`)? Workspace assets called "files"? The package scopes ALL of: DBFS API, Files API for UC volumes, generic file storage. +- **Why weird:** Exports `Client` without qualification. Consuming code that imports from multiple packages ends up with `import {Client as FilesClient} from '@databricks/sdk-files/v2';` in every file. The package name `files` is also generic — DBFS files? UC volume files? Workspace files (already a separate `@databricks/sdk-workspace`)? Workspace assets called "files"? The package scopes ALL of: DBFS API, Files API for UC volumes, generic file storage. - **Category:** 1 (vague — "files" overloaded across at least DBFS, UC Volumes, Workspace files), 6 (misleading — name does not signal which file surface). - **Suggested name:** Export `FilesClient` (or split — `DbfsClient` + `FilesClient`). The package itself could be `@databricks/sdk-dbfs-and-files` (ugly but honest) or split into two packages. - **Rationale:** Already a problem in the wider SDK; `Client` is opaque in error messages and stack traces. -### 5. `DirectoryEntry` vs `FileInfo` — duplicate concept inside v2 — `src/v2/model.ts:73,114` +### 3. `DirectoryEntry` vs `FileInfo` — duplicate concept inside v2 — `src/v2/model.ts:73,114` ```ts export interface DirectoryEntry { @@ -130,20 +55,20 @@ export interface FileInfo { - **Why weird:** Both types describe a file-or-directory metadata snapshot, with overlapping fields: - Both have `path`, `fileSize`. - - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings — see #6). - - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names — see #7). + - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings — see #4). + - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names — see #5). - `DirectoryEntry.name` (component name) — exists only in `DirectoryEntry`. Two distinct types because they come from two distinct REST APIs (modern listDirectoryContents vs legacy listStatus / getStatus). The client exposes both, side-by-side, with no docstring telling callers which to use. - **Category:** 12 (duplicate concepts), 17 (cross-API naming clash), 6 (misleading — `DirectoryEntry` may be a file). -- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #8). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. +- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #6). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. - **Rationale:** Two identical-shape types with different field names are a maintenance hazard. -### 6. `isDir` vs `isDirectory` — same concept, two casings — `src/v2/model.ts:77,118,170` +### 4. `isDir` vs `isDirectory` — same concept, two casings — `src/v2/model.ts:77,118,170` ```ts DirectoryEntry.isDirectory?: boolean // modern API FileInfo.isDir?: boolean // legacy DBFS -GetStatus_Response.isDir?: boolean // legacy DBFS +GetStatusRequest_Response.isDir?: boolean // legacy DBFS ``` - **Why weird:** Same yes/no flag, two abbreviations of "is directory". `isDir` is a cryptic 3-letter abbreviation; `isDirectory` is the full word. They appear in three sibling types in the same file. @@ -151,14 +76,14 @@ GetStatus_Response.isDir?: boolean // legacy DBFS - **Suggested name:** `isDirectory` everywhere (the modern form). Wire mapping is one line in the unmarshal schema. - **Rationale:** Public TS field names should not abbreviate "directory" to "dir" when the rest of the SDK spells it out. -### 7. `lastModified` (number-ms-epoch) vs `lastModified` (HTTP-date string) vs `modificationTime` — `src/v2/model.ts:79,110,122,157,174` +### 5. `lastModified` (number-ms-epoch) vs `lastModified` (HTTP-date string) vs `modificationTime` — `src/v2/model.ts:79,110,122,157,174` ```ts DirectoryEntry.lastModified?: number // ms since epoch DownloadFileResponse.lastModified?: string // HTTP-date (RFC 7231) FileInfo.modificationTime?: number // ms since epoch GetFileMetadataResponse.lastModified?: string // HTTP-date -GetStatus_Response.modificationTime?: number // ms since epoch +GetStatusRequest_Response.modificationTime?: number // ms since epoch ``` - **Why weird:** Three problems in one cluster. (a) Same FIELD NAME (`lastModified`) holds two completely different value domains — milliseconds-since-epoch as `number` (in `DirectoryEntry`) AND HTTP-date `'Wed, 21 Oct 2015 07:28:00 GMT'` as `string` (in `DownloadFileResponse`, `GetFileMetadataResponse`). (b) Same WIRE CONCEPT (ms since epoch) has two field names — `lastModified` in modern, `modificationTime` in legacy. (c) Time-suffix convention is inconsistent: `lastModified` (past participle), `modificationTime` (noun + `Time` suffix). @@ -166,7 +91,7 @@ GetStatus_Response.modificationTime?: number // ms since epoch - **Suggested name:** Use distinct names for distinct domains. For ms-since-epoch: `lastModifiedMs` or `lastModifiedAt: number` (ms-since-epoch convention). For HTTP-date strings: `lastModifiedHttpDate: string` or model as a typed brand. Pick ONE — `modificationTime` should be dropped. - **Rationale:** A consumer doing `if (resp.lastModified > someTimestamp)` will silently break depending on which API they came from. -### 8. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` +### 6. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` ```ts // files/v2: file/directory metadata snapshot @@ -184,13 +109,13 @@ export interface FileInfo { ... } - **Why weird:** Three different packages all export `FileInfo` with three different shapes. The names are flat-spaced inside the package, but downstream consumers who do `import * as files from '@databricks/sdk-files/v2'; import * as exp from '@databricks/sdk-experiments/v1';` get two unrelated `FileInfo` types and `files.FileInfo !== exp.FileInfo` is a confusing source of bugs. - **Category:** 1 (vague/generic top-level name), 12 (duplicate concept across packages), 15 (generic name loses meaning). -- **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #5 — `FileEntry`). +- **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #3 — `FileEntry`). - **Rationale:** `FileInfo` is so generic three different domains felt entitled to use it. -### 9. `Create` returns a `handle` (not the created file) — `src/v2/model.ts:23-34` +### 7. `CreateRequest` returns a `handle` (not the created file) — `src/v2/model.ts:32-43` ```ts -export interface Create { +export interface CreateRequest { path?: string | undefined; overwrite?: boolean | undefined; } @@ -201,26 +126,13 @@ export interface Create { - **Why weird:** The method is called `create` but does NOT create a file — it opens a write stream and returns a handle. The actual file doesn't exist until you call `close`. A reader of `client.create({path: '/tmp/foo'})` would reasonably expect the file to be created. JSDoc on the method says "Opens a stream to write to a file and returns a handle to this stream." — directly contradicting the name. - **Category:** 6 (misleading — name says "create" but action is "open"). -- **Suggested name:** `OpenWriteStream` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). +- **Suggested name:** `OpenWriteStreamRequest` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). - **Rationale:** Method name should reflect action; right now `create` and `createDirectory` look like sibling actions when they are entirely different (create-handle vs create-resource). -### 10. `handle: number` — underspecified ID — `src/v2/model.ts:7,17,33` +### 8. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:301,677` ```ts -AddBlock.handle?: number // "The handle on an open stream." -Close.handle?: number -// Response Create handle?: number -``` - -- **Why weird:** A `number` named `handle` looks like a `numeric ID`, but the JSDoc says it is the result of an `open` (per #9). No type-brand prevents passing arbitrary numbers; no documentation says whether it is positive, monotonic, opaque, or guaranteed unique. The Go SDK uses `int64` here and TS narrows to `number`, which is silently truncated above 2^53 — and there is no mitigation in this client. -- **Category:** 19 (underspecified ID). -- **Suggested name:** `streamHandle: number` (or `DbfsStreamHandle` branded type). At minimum, type-document "opaque integer from DBFS server; pass as-is". -- **Rationale:** TS `number` for a server-issued 64-bit token is a known precision hazard; the field name doesn't even hint that it's a transient stream identifier. - -### 11. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:292,656` - -```ts -async list(req: ListStatus, ...): Promise // legacy DBFS +async list(req: ListStatusRequest, ...): Promise // legacy DBFS async listDirectoryContents(req: ListDirectoryContentsRequest, ...): Promise // modern Files ``` @@ -229,7 +141,9 @@ async listDirectoryContents(req: ListDirectoryContentsRequest, ...): Promise @@ -250,32 +164,30 @@ export async function sendAndCheckError(opts: HttpCallOptions): Promise Promise` function reference). `executeHttpCall` takes the actual HTTP request. `sendAndCheckError` is what `executeHttpCall` is but with a different return type (raw `HttpResponse` vs buffered `Uint8Array`). All four start with a verb but use different verbs (`execute`, `send`, `build`) for what amounts to "send this HTTP request and return something". The lowercase `'head'` HTTP method in two callers (`client.ts:600,637`) is an unrelated bug. +- **Why weird:** Four nearly-identical-sounding helpers in one file. `executeCall` wraps a `Call` (whatever a `Call` is — it's an opaque `(signal?) => Promise` function reference). `executeHttpCall` takes the actual HTTP request. `sendAndCheckError` is what `executeHttpCall` is but with a different return type (raw `HttpResponse` vs buffered `Uint8Array`). All four start with a verb but use different verbs (`execute`, `send`, `build`) for what amounts to "send this HTTP request and return something". The lowercase `'head'` HTTP method in two callers (`client.ts:621,658`) is an unrelated bug. - **Category:** 17 (inconsistent verb cluster — execute/send/build), 6 (misleading — `executeCall` and `executeHttpCall` are different despite the matching prefix), 12 (duplicate concept — `executeHttpCall` and `sendAndCheckError` do almost the same thing). - **Suggested name:** Collapse to one helper (`sendRequest`), let it return the raw `HttpResponse`, and have the caller buffer/stream as needed. Or, if both must exist: `sendAndBuffer` (returns buffered body) and `sendAndStream` (returns raw response). - **Rationale:** Three functions doing nearly the same thing with names that differ in verb is a recipe for mis-imports. -## Medium severity - -### 14. `path` as the only field in 5 request types — `src/v2/model.ts:23,45,160,213,224` +### 11. `path` as the only field in 5 request types — `src/v2/model.ts:32,63,160,213,224` ```ts -Create: { path?: string; overwrite?: boolean } -Delete: { path?: string; recursive?: boolean } -GetStatus: { path?: string } -ListStatus: { path?: string } -MkDirs: { path?: string } +CreateRequest: { path?: string; overwrite?: boolean } +DeleteRequest: { path?: string; recursive?: boolean } +GetStatusRequest: { path?: string } +ListStatusRequest: { path?: string } +MkDirsRequest: { path?: string } ``` -- **Why weird:** Five sibling types whose distinguishing identity is the type name (`Create`, `Delete`, etc.), not the field. The common field is just `path: string`. In TS, all five types are structurally compatible — `GetStatus` is assignable to `ListStatus` and vice versa; both are assignable to `MkDirs`. A caller can confidently pass `getStatus(req)` and a typo-narrowed `req: ListStatus` and TS won't complain (structural typing). +- **Why weird:** Five sibling types whose distinguishing identity is the type name (`CreateRequest`, `DeleteRequest`, etc.), not the field. The common field is just `path: string`. In TS, all five types are structurally compatible — `GetStatusRequest` is assignable to `ListStatusRequest` and vice versa; both are assignable to `MkDirsRequest`. A caller can confidently pass `getStatus(req)` and a typo-narrowed `req: ListStatusRequest` and TS won't complain (structural typing). - **Category:** 1 (vague — `path` for everything), 6 (misleading — structural compat collapses semantic distinctions), 17 (inconsistent — sometimes called `path`, sometimes `filePath`, sometimes `directoryPath`). -- **Suggested name:** Use the discriminated field names from the modern API: `dbfsPath` everywhere on the legacy types; or split into `Create.filePath` (because `Create` is a write-stream open, ie file) and `MkDirs.directoryPath`. Helps callers see "this is a path to a file" vs "this is a path to a directory." +- **Suggested name:** Use the discriminated field names from the modern API: `dbfsPath` everywhere on the legacy types; or split into `CreateRequest.filePath` (because `Create` is a write-stream open, ie file) and `MkDirsRequest.directoryPath`. Helps callers see "this is a path to a file" vs "this is a path to a directory." - **Rationale:** Structural typing makes the five types interchangeable — a name change is the cheapest defence. -### 15. `Move.sourcePath` / `Move.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` +### 12. `MoveRequest.sourcePath` / `MoveRequest.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` ```ts -export const marshalMoveSchema: z.ZodType = z +export const marshalMoveRequestSchema: z.ZodType = z .object({ sourcePath: z.string().optional(), destinationPath: z.string().optional(), @@ -286,17 +198,17 @@ export const marshalMoveSchema: z.ZodType = z })); ``` -- **Why weird:** The wire keys are `source_path` / `destination_path` — but ALL other DBFS methods use a single `path` field. This is an entirely separate field-naming convention used in one method. Compare: `Delete.path` (not `target_path`), `GetStatus.path` (not `target_path`), but `Move.sourcePath` / `Move.destinationPath`. +- **Why weird:** The wire keys are `source_path` / `destination_path` — but ALL other DBFS methods use a single `path` field. This is an entirely separate field-naming convention used in one method. Compare: `DeleteRequest.path` (not `target_path`), `GetStatusRequest.path` (not `target_path`), but `MoveRequest.sourcePath` / `MoveRequest.destinationPath`. - **Category:** 17 (inconsistent — single endpoint convention). - **Suggested name:** Acceptable as-is (these are clearer than `path1`/`path2`). Flag only the inconsistency with the rest of the DBFS surface. - **Rationale:** The inconsistency is upstream; the TS port should match. -### 16. `contents` field has three different types across model — `src/v2/model.ts:108,246,281,275` +### 13. `contents` field has three different types across model — `src/v2/model.ts:108,246,281,274` ```ts DownloadFileResponse.contents?: ReadableStream | undefined // line 108 -Put.contents?: Uint8Array | undefined // line 246 -// Read response data?: Uint8Array | undefined (named 'data')// line 275 — same concept, different name +PutRequest.contents?: Uint8Array | undefined // line 246 +// ReadRequest_Response.data?: Uint8Array | undefined (named 'data')// line 274 — same concept, different name UploadFileRequest.contents?: ReadableStream | undefined // line 281 ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 208 ``` @@ -304,49 +216,24 @@ ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 20 - **Why weird:** "Contents" is overloaded across the model: - `DownloadFileResponse.contents`: file bytes as a stream. - `UploadFileRequest.contents`: file bytes as a stream. - - `Put.contents`: file bytes as a `Uint8Array` (no streaming on the legacy API). - - Read response `data`: file bytes (chunked read) as a `Uint8Array` — same concept as `Put.contents` but called `data`. + - `PutRequest.contents`: file bytes as a `Uint8Array` (no streaming on the legacy API). + - `ReadRequest_Response.data`: file bytes (chunked read) as a `Uint8Array` — same concept as `PutRequest.contents` but called `data`. - `ListDirectoryResponse.contents`: directory entries (array of `DirectoryEntry`). - **Category:** 6 (misleading), 12 (duplicate concept — `contents` and `data`), 15 (generic name loses meaning — what's in "contents"?), 17 (inconsistent — same concept, three names). - **Suggested name:** `body: ReadableStream` for stream payload, `bodyBytes: Uint8Array` for buffered, `entries: DirectoryEntry[]` for list responses (matching the `next_page_token` pattern of "entries + next token"). Rename the read response `data` field to `bytes` to make the buffer obvious. - **Rationale:** The `contents` of a directory and the `contents` of a file are different domains. Type system will not catch a programmer who reads `.contents.length` expecting bytes and gets `DirectoryEntry[].length`. -### 17. v1 `Client` constructor allows `host` to be undefined — `src/v1/client.ts:21` - -```ts -constructor(options: ClientOptions) { - if (options.host === undefined) { - throw new Error('Host is required.'); - } - this.host = options.host.replace(/\/$/, ''); - ... -} -``` - -`ClientOptions.host` is typed optional but in practice always required. Not a name bug per se — but `host` is also generic; `workspaceUrl`/`workspaceHost` would be clearer. Same critique on `v2/client.ts:103`. - -### 18. v1 `UploadRequest.contents` is `ReadableStream` but v2 `UploadFileRequest.contents` is bare `ReadableStream` — `src/v1/model.ts:11`, `src/v2/model.ts:281` +### 14. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-274` ```ts -// v1 -contents: ReadableStream; // required, generic -// v2 -contents?: ReadableStream | undefined; // optional, generic-erased -``` - -v2 weakens the type — both `ReadableStream` and `ReadableStream` would be more correct, but more importantly v1's `Uint8Array` constraint is gone. Same for `DownloadResponse.contents` vs `DownloadFileResponse.contents`. - -### 19. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-275` - -```ts -// Read response: +// ReadRequest_Response: // bytesRead?: number // count // data?: Uint8Array // bytes ``` `bytesRead` (count) and `data` (the bytes) refer to the same byte slice. `bytesRead` is the LENGTH; `data` is the BUFFER. Cleaner: `bytes: Uint8Array` and `bytesRead: number` (count); even better, drop `bytesRead` since `data.byteLength` is the same value. -### 20. `ifUnmodifiedSince` — verb-as-noun field — `src/v2/model.ts:101,149` +### 15. `ifUnmodifiedSince` — verb-as-noun field — `src/v2/model.ts:101,149` ```ts ifUnmodifiedSince?: string | undefined; @@ -354,7 +241,7 @@ ifUnmodifiedSince?: string | undefined; Mirrors the HTTP header name exactly. Faithful to RFC 9110, but as a TS field name `ifUnmodifiedSince` is a conditional, not a value. `unmodifiedSinceHeader: string` or `notModifiedSince: string` is more idiomatic. Acceptable as-is (HTTP convention), flagged only as observation. -### 21. `range` (HTTP byte range header value) — same — `src/v2/model.ts:95,143` +### 16. `range` (HTTP byte range header value) — same — `src/v2/model.ts:95,143` ```ts range?: string | undefined; @@ -362,27 +249,29 @@ range?: string | undefined; Field name `range` is overloaded (range of numbers? date range?). The doc clarifies "range of bytes to retrieve" — name could be `byteRange` or `rangeHeader`. -### 22. `directoryPath` vs `path` — inconsistent across methods — `src/v2/model.ts:39,58,128,180` +## Low severity + +### 17. `directoryPath` vs `path` — inconsistent across methods — `src/v2/model.ts:26,48,128,180` -The modern Files API consistently uses `directoryPath` / `filePath`. The legacy DBFS uses just `path` even when the value is known to be a directory (`MkDirs.path`) or file (`Create.path`). In v1 it was always `filePath`. v2 has both. Choose: prefix every path with the kind, OR drop the prefix everywhere. +The modern Files API consistently uses `directoryPath` / `filePath`. The legacy DBFS uses just `path` even when the value is known to be a directory (`MkDirsRequest.path`) or file (`CreateRequest.path`). Choose: prefix every path with the kind, OR drop the prefix everywhere. -### 23. `recursive` (Delete) — field name does not tell you what it does — `src/v2/model.ts:49` +### 18. `recursive` (DeleteRequest) — field name does not tell you what it does — `src/v2/model.ts:67` ```ts recursive?: boolean | undefined; ``` -A `recursive: true` on a `Delete` could mean "follow symlinks", "descend into subdirs", etc. JSDoc clarifies "Whether or not to recursively delete the directory's contents." Name OK in context; would prefer `recursivelyDeleteContents: boolean` for self-documentation, but `recursive` is conventional. +A `recursive: true` on a `DeleteRequest` could mean "follow symlinks", "descend into subdirs", etc. JSDoc clarifies "Whether or not to recursively delete the directory's contents." Name OK in context; would prefer `recursivelyDeleteContents: boolean` for self-documentation, but `recursive` is conventional. -### 24. `overwrite` — same — `src/v2/model.ts:27,248,283` +### 19. `overwrite` — same — `src/v2/model.ts:36,248,283` ```ts overwrite?: boolean | undefined; ``` -Appears in `Create`, `Put`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `Create` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. +Appears in `CreateRequest`, `PutRequest`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `CreateRequest` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. -### 25. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,194,196` +### 20. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,183,194,200` ```ts contents?: DirectoryEntry[] | undefined; @@ -392,33 +281,11 @@ nextPageToken?: string | undefined; // OK JSDoc strings reference the wire name (`next_page_token`), but the TS field is `nextPageToken`. The doc accurately reflects the wire — flagged because cross-referencing a wire name in user-facing JSDoc is confusing. Should reference the TS field name (`nextPageToken`). -## Low severity - -### 26. `pageSize` recommendation "We recommend not to set this value..." — `src/v2/model.ts:186` - -Doc says don't set the field. Then why is the field public? Name is fine; flagging the inconsistent guidance. - -### 27. Read response `data: Uint8Array` is base64 on the wire — `src/v2/model.ts:273` - -The field is decoded from base64 on read; doc says "The base64-encoded contents of the file read." but the TS type is already `Uint8Array` (decoded). Consumers reading the docstring may think they have to decode themselves. Name could clarify: `bytes: Uint8Array` with doc "Already base64-decoded". - -### 28. v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export `DownloadRequest`/`DownloadResponse`-as-used — `src/v1/index.ts:3` - -```ts -export type {DownloadRequest, DownloadResponse, UploadRequest} from './model'; -``` - -v1 exports `DownloadRequest`/`DownloadResponse` but the v1 client has NO download method. Dangling types — see net assessment. - -### 29. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` +### 21. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. -### 30. `readAll` is duplicated — `src/v1/utils.ts:23` and `src/v2/utils.ts:40` - -Same conceptual helper, two implementations (v1 uses `new Response(body).arrayBuffer()`, v2 walks the reader manually). Name OK; flagged as cross-version duplication. - -### 31. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` +### 22. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` ```ts const PACKAGE_SEGMENT = { @@ -429,45 +296,27 @@ const PACKAGE_SEGMENT = { SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. This is a plain object; `packageSegment` is fine. -### 32. `HttpCallOptions` duplicated across files — `src/v1/utils.ts:13`, `src/v2/utils.ts:15` - -```ts -export interface HttpCallOptions { - readonly request: HttpRequest; - readonly httpClient: HttpClient; - readonly logger: Logger; -} -``` - -Same name, same shape, in two files in the same package. Should be shared / re-exported. - ## Observations -### 33. v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` — `src/v1/utils.ts:36`, `src/v2/utils.ts:156` - -Same function, renamed in v2. Good rename (v2's is more accurate), but the rename means a v1 user upgrading sees an unexplained name change. - -### 34. `Move.sourcePath` / `Move.destinationPath` — could be `source` / `destination` — `src/v2/model.ts:233-236` - -The type name is `Move`; the fields are `sourcePath`/`destinationPath`. Inside a `Move` request, the `Path` suffix is redundant — `source: string; destination: string`. Acceptable; flagged because it's the longer form against the rest of the file's `path: string`. - -### 35. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` +### 23. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) -### 36. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` +### 24. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. -### 37. v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" — `src/v1/client.ts:33-36` - -```ts -/** - * ... - * Because the request body is a ReadableStream which can only be consumed - * once, this method does not retry on failure. ... - */ -async upload(req: UploadRequest, options?: CallOptions): Promise { -``` - -`upload` is the name; the JSDoc tells you it doesn't retry. v2 inherits the same property for `uploadFile` but the doc on `client.ts:706` doesn't say so. Inconsistent docs across versions. +## Fixed + +- #1 `Read` (originally cited at `src/v2/model.ts:254`): Fixed in regeneration on 2026-05-20 — renamed to `ReadRequest`; verb-as-noun and reserved-word collision concerns resolved by the `Request` suffix. +- #2 Verb-as-noun cluster `Move`, `Put`, `Delete`, `Close`, `Create`, `MkDirs`, `AddBlock`, `GetStatus`, `ListStatus` (originally cited at `src/v2/model.ts:15-264`): Fixed in regeneration on 2026-05-20 — all renamed to `MoveRequest`, `PutRequest`, `DeleteRequest`, `CloseRequest`, `CreateRequest`, `MkDirsRequest`, `AddBlockRequest`, `GetStatusRequest`, `ListStatusRequest`; the `Request` suffix removes the verb-as-noun ambiguity and the `Delete` keyword collision. +- #17 v1 `Client` constructor allows `host` to be undefined (originally cited at `src/v1/client.ts:21`): Fixed in regeneration on 2026-05-20 — v1 package deleted. +- #18 v1 `UploadRequest.contents` is `ReadableStream` but v2 `UploadFileRequest.contents` is bare `ReadableStream` (originally cited at `src/v1/model.ts:11`, `src/v2/model.ts:281`): Fixed in regeneration on 2026-05-20 — v1 package deleted; v2 standalone with single typing. +- #28 v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export dangling types (originally cited at `src/v1/index.ts:3`): Fixed in regeneration on 2026-05-20 — v1 package deleted. +- #30 `readAll` is duplicated across v1 and v2 (originally cited at `src/v1/utils.ts:23` and `src/v2/utils.ts:40`): Fixed in regeneration on 2026-05-20 — v1 package deleted. +- #32 `HttpCallOptions` duplicated across files (originally cited at `src/v1/utils.ts:13`, `src/v2/utils.ts:15`): Fixed in regeneration on 2026-05-20 — v1 package deleted. +- #33 v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` (originally cited at `src/v1/utils.ts:36`, `src/v2/utils.ts:156`): Fixed in regeneration on 2026-05-20 — v1 package deleted. +- #34 `Move.sourcePath` / `Move.destinationPath` could be `source` / `destination` (originally cited at `src/v2/model.ts:233-236`): Fixed in regeneration on 2026-05-20 — duplicate of #12; pruned. +- #37 v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" (originally cited at `src/v1/client.ts:33-36`): Fixed in regeneration on 2026-05-20 — v1 package deleted. + + \ No newline at end of file diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index 163b9cf4..f258f501 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -282,6 +282,36 @@ _None._ --- +### 11. Proto / architectural leaks + +#### 11.1 — `ForecastingExperiment_State` — `model.ts:6` +- **Why flagged:** The `Foo_Bar` underscore identifier is a verbatim + proto-generated nested-enum form (`ForecastingExperiment.State` in + the original proto). The underscore form leaks the proto IDL + encoding into a public TS symbol. The accompanying eslint-disable + comment "Proto-style nested enum name" makes the leak explicit. +- **Category:** Proto architectural leak (nested-enum underscore form). +- **Suggested:** `ExperimentState` (or `ForecastingExperimentState` + if the qualifier is kept per F-OVERLAP.1). +- **Rationale:** TS has no first-class nested-enum syntax matching + proto's `Foo.Bar`. The flat camel/Pascal form removes the IDL + artifact and the eslint-disable. + +#### 11.2 — "Public RPC" in JSDoc — `client.ts:112` +- **Why flagged:** The JSDoc `/** Public RPC to get forecasting + experiment */` exposes the server-side classification + (`Public` vs `Internal` RPC) and the transport term `RPC` to SDK + consumers. Users of an HTTP SDK do not need to know the call + is dispatched as a "public RPC" inside the backend. +- **Category:** Proto/RPC architectural leak (`Public` mid-position + classifier + `RPC` transport noun in user-facing doc). +- **Suggested:** Replace with a behavioural description, e.g. + `/** Gets a forecasting experiment by ID. */`. +- **Rationale:** Public-API JSDoc should describe what the method + does for the caller, not how the backend routes it. + +--- + ## Package overlap: `forecasting` vs `experiments` This SDK ships both `@databricks/sdk-forecasting` and an MLflow-style @@ -323,6 +353,7 @@ generic experiment but uses the same term and the same ID name. | 8 | Generic field names | 3 | | 9 | Untyped string for closed enum | 1 | | 10 | `*Path` fields contradicting domain | 1 | +| 11 | Proto / architectural leaks | 2 | | OVERLAP | forecasting vs experiments | 2 | --- diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index cec83118..1ea0cdf0 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -25,7 +25,7 @@ field prefixes that re-encode the parent type's domain. ### 1. Vague / generic names -#### 1.1 `DeleteFunction.force` (model.ts:157) +#### 1.1 `DeleteFunctionRequest.force` (model.ts:154) Field name `force` is generic. Doc says "Force deletion even if the function is notempty." (typo preserved). A function that "isn't empty" — what does "empty" mean for a function? Probably a copy-paste @@ -34,48 +34,69 @@ carries no information about *what* it overrides; consider `forceDelete` or, better, surface the underlying constraint in the name. -#### 1.2 `FunctionParameterInfo.position` (model.ts:277) +#### 1.2 `FunctionParameterInfo.position` (model.ts:264) Generic name on a field whose meaning is implementation-specific (zero-indexed ordinal position). `parameterIndex` or `ordinalPosition` would be unambiguous. Compare to `Position` types in editors / DOM — `position` here is overloaded. -#### 1.3 `FunctionParameterInfo.comment` (model.ts:285) +#### 1.3 `FunctionParameterInfo.comment` (model.ts:272) "User-provided free-form text description" — this is a description, not a comment. `description` is what the field actually contains. Same pattern repeats on `CreateFunction.comment`, `FunctionInfo.comment`, -`UpdateFunction.comment` (model.ts:119, 238, 383). +`UpdateFunctionRequest.comment` (model.ts:116, 225, 364). --- -### 2. Redundant enum prefixes +### 2. Cryptic single-letter / two-letter enum variants -#### 2.1 `FunctionParameterType` values `PARAM` / `COLUMN` (model.ts:39-42) -The enum is named `FunctionParameterType` and the variants are -`PARAM` and `COLUMN`. `PARAM` is fine; `COLUMN` is jarring as a -"parameter type" because the surrounding type names already declare -"parameter". The semantics (a parameter that is actually a table -column reference) get lost. Consider -`FunctionParameterType.COLUMN_REF` or rename the parent. - -#### 2.2 `FunctionInfo_ParameterStyle.S` (model.ts:44-47) +#### 2.1 `FunctionInfo_ParameterStyle.S` (model.ts:42-44) Single-variant enum with the variant `S`. The doc on the type-using field says `**S** is the value for SQL.` So `S` is *the* SQL parameter style. The single-letter variant is cryptic; even if it preserves wire compatibility, the TypeScript surface should expose `SQL` (and let the marshal layer translate to `S` on the wire). -See also §4.1. +See also §3.1. -#### 2.3 `FunctionInfo_SecurityType.DEFINER` (model.ts:61-64) +#### 2.2 `FunctionInfo_SecurityType.DEFINER` (model.ts:59-61) Single-variant enum with `DEFINER`. The single-valued switch is surfaced as a full enum type; the variant itself is meaningful (SQL `SECURITY DEFINER` clause) but the TS-side ergonomics suffer. --- -### 3. Acronym casing inconsistencies (SQL, UDF, UDTF, JSON) +### 3. Cryptic abbreviations + +#### 3.1 `FunctionInfo_ParameterStyle.S` (model.ts:43) +A bare letter `S` whose only documented purpose is "the value for +SQL". Cryptic — preserve wire compatibility in the marshal layer and +expose `SQL` as the TS variant. See also §2.1. + +#### 3.2 `FunctionParameterMode.IN` (model.ts:32-34) +Bare two-letter variant `IN`. Comes from SQL's `IN`/`OUT`/`INOUT` +parameter modes; without that context, the variant is cryptic. A +consumer reading `parameterMode === FunctionParameterMode.IN` cannot +intuit "input parameter" without prior SQL exposure. + +#### 3.3 `fullNameArg` (model.ts:152, 281, 324) +Used as the function name path-parameter on `DeleteFunctionRequest`, +`GetFunctionRequest`, and `UpdateFunctionRequest`. The `Arg` suffix +is jargon from the Go generator distinguishing path arguments from +request-body fields with the same key. TypeScript callers have no +need for this distinction — the field is the function's +fully-qualified name. See also §8.1 and §7.3. + +#### 3.4 `pkgJson` (client.ts:19) +Internal variable name for `package.json`. Mild — flagged for +consistency with other audits. + +#### 3.5 `respBody` (client.ts:89, 126, 167, 220, 273) — internal-only; mild. + +--- + +### 4. Acronym casing inconsistencies (SQL, UDF, UDTF, JSON) -#### 3.1 `FunctionInfo_SqlDataAccess` (model.ts:67) vs field `sqlDataAccess` (model.ts:101, 220, 365) +#### 4.1 `FunctionInfo_SqlDataAccess` (model.ts:64) vs field `sqlDataAccess` (model.ts:98, 207, 346) `SqlDataAccess` (PascalCase for the type) uses `Sql` as a word; `sqlDataAccess` (camelCase field) uses `sql` lowercase. Both are internally consistent for camelCase/PascalCase rules, but the @@ -83,27 +104,20 @@ Databricks codebase elsewhere uses uppercase `SQL` (e.g. `sqlPath` field, comments saying "SQL"). Google TS style guide treats SQL as a three-letter acronym → `Sql`/`sql` is valid. Flagged for awareness. -#### 3.2 `sqlPath` field (model.ts:115, 234, 379) -Consistent with §3.1: `sqlPath` rather than `sQLPath`. OK by Google +#### 4.2 `sqlPath` field (model.ts:112, 221, 360) +Consistent with §4.1: `sqlPath` rather than `sQLPath`. OK by Google TS rules. -#### 3.3 `typeJson` field (model.ts:267) +#### 4.3 `typeJson` field (model.ts:254) Field name `typeJson`. JSON is treated as `Json` per Google TS rules. Consistent. -#### 3.4 `typeText` field (model.ts:265) +#### 4.4 `typeText` field (model.ts:252) Field name `typeText`. Doc says "Full data type spec, SQL/catalogString text." OK as a name but ambiguous: is it SQL-formatted, JSON-formatted, or arbitrary? -#### 3.5 `TIMESTAMP_NTZ` enum variant (model.ts:25) -`NTZ` is "No TimeZone". Three-letter acronym, kept uppercase here -which is consistent with `SQL` elsewhere. OK, but the meaning is -opaque to anyone unfamiliar with the Spark/Delta type system. The -ColumnTypeName enum has no JSDoc comments to explain `NTZ`, -`USER_DEFINED_TYPE`, `VARIANT`, etc. - -#### 3.6 "UDF" / "UDTF" never appear in identifiers +#### 4.5 "UDF" / "UDTF" never appear in identifiers The package is *Unity Catalog Functions* — it covers both UDFs and UDTFs (table-valued functions). Neither acronym appears in any identifier or doc comment. The distinction is encoded in the @@ -113,51 +127,15 @@ flagging. --- -### 4. Cryptic abbreviations - -#### 4.1 `FunctionInfo_ParameterStyle.S` (model.ts:46) -A bare letter `S` whose only documented purpose is "the value for -SQL". Cryptic — preserve wire compatibility in the marshal layer and -expose `SQL` as the TS variant. See also §2.2. - -#### 4.2 `FunctionParameterMode.IN` (model.ts:35-37) -Bare two-letter variant `IN`. Comes from SQL's `IN`/`OUT`/`INOUT` -parameter modes; without that context, the variant is cryptic. A -consumer reading `parameterMode === FunctionParameterMode.IN` cannot -intuit "input parameter" without prior SQL exposure. - -#### 4.3 `fullNameArg` (model.ts:155, 294, 343) -Used as the function name path-parameter on `DeleteFunction`, -`GetFunction`, and `UpdateFunction`. The `Arg` suffix is jargon from -the Go generator distinguishing path arguments from request-body -fields with the same key. TypeScript callers have no need for this -distinction — the field is the function's fully-qualified name. See -also §10.1 and §9.3. - -#### 4.4 `pkgJson` (client.ts:19) -Internal variable name for `package.json`. Mild — flagged for -consistency with other audits. - -#### 4.5 `respBody` (client.ts:89, 126, 164, 217, 267) — internal-only; mild. - -#### 4.6 `typeText` / `typeJson` (model.ts:265, 267) -The `type*` prefix is fine within `FunctionParameterInfo`, but the -field names (`typeText`, `typeJson`, `typeName`, `typePrecision`, -`typeScale`, `typeIntervalType`) form a non-obvious "type-spec" -sub-record that arguably should be nested under a `type` object. -See also §10.4. - ---- - ### 5. Misleading names -#### 5.1 `routineDependencies` doc comment lowercases "function" (model.ts:122, 241, 386) +#### 5.1 `routineDependencies` doc comment lowercases "function" (model.ts:119, 228, 367) JSDoc reads "function dependencies." (lowercase, mid-sentence). The field name is `routineDependencies` and the doc says "function". The package toggles between "routine" and "function" terminology indiscriminately — see §5.3. -#### 5.2 `DeleteFunction.force` doc has typo "notempty" (model.ts:156) +#### 5.2 `DeleteFunctionRequest.force` doc has typo "notempty" (model.ts:153) "Force deletion even if the function is notempty." Should be "not empty". Doc bug, not a naming bug, but signals the field hasn't been read recently. See also §1.1. @@ -172,7 +150,7 @@ SQL ROUTINE_BODY …`) — but for a TS consumer the inconsistency is jarring. `body`, `definition`, `dependencies` (dropping `routine`) would be cleaner. See also §5.1. -#### 5.4 `parameterDefault: string` (model.ts:283) +#### 5.4 `parameterDefault: string` (model.ts:270) Doc: "Default value of the parameter." The default of a function parameter is rarely a string in the source domain — it might be a number, a boolean, an interval, or even `NULL`. Typing it as `string` @@ -180,18 +158,11 @@ implies serialised form, but the field name `parameterDefault` doesn't signal that. Consider `parameterDefaultExpression` or `parameterDefaultText`. -#### 5.5 `specificName` reserved-for-future-use (model.ts:107, 226, 371) +#### 5.5 `specificName` reserved-for-future-use (model.ts:104, 213, 352) Doc: "Specific name of the function; Reserved for future use." A field whose name promises specificity and whose docs admit it's unused is a future trap. Better to omit until it does something. -#### 5.6 `inputParams` / `returnParams` use `Params` but the type uses `ParameterInfos` -(model.ts:87, 109, 206, 228, 351, 373) -The field abbreviates to `Params`; the type is `FunctionParameterInfos` -(no abbreviation). Pick one — abbreviate both (`Params` / -`ParameterInfos`?) or spell both out (`inputParameters` / -`returnParameters`). - --- ### 6. Reserved-word collisions @@ -206,17 +177,17 @@ objects. Although TypeScript permits both as identifier names in most positions, this package routinely uses them in ways that collide: -- The `Dependency.value` discriminated union (model.ts:170) uses +- The `Dependency.value` discriminated union (model.ts:167) uses `$case: 'function'` and a `function` property as one arm of the union. The runtime payload key is `function`, which means consumers must write `if (dep.value?.$case === 'function') { dep.value.function … }` — reading `dep.value.function` is jarring next to other code that treats `function` as a keyword. -- The unmarshal schema (model.ts:437, 447) reads +- The unmarshal schema (model.ts:412, 421) reads `function: z.lazy(() => unmarshalFunctionDependencySchema)` — again the property name is `function`. -- The marshal schema (model.ts:727-728) similarly has +- The marshal schema (model.ts:679-680) similarly has `$case: z.literal('function'), function: z.lazy(…)`. - The Go-side wire format uses snake_case (`function`) so the field is forced; renaming requires breaking compatibility. @@ -227,31 +198,15 @@ adjacent to TS keyword highlighting in their editor. Consider renaming the union arm to `functionRef`, `functionDependency`, or nesting via a different discriminator. -#### 6.2 `FunctionDependency` shadows `Function` constructor -The exported type `FunctionDependency` is fine on its own, but in -contexts where the SDK consumer also has `Function` (the global -constructor) in scope, the `Function*` prefix on multiple types is -crowded. - -#### 6.3 Type `FunctionInfo` is exported alongside the global `Function` -(model.ts:198, index.ts:25) -`FunctionInfo`, `CreateFunction`, `DeleteFunction`, `GetFunction`, -`ListFunctions`, `UpdateFunction`, `FunctionParameterInfo`, -`FunctionParameterInfos`, `FunctionDependency`, -`FunctionParameterMode`, `FunctionParameterType` — many exports -prefixed with `Function`. While none conflict at the language level, -the prefix is so heavy that the global `Function` is easily -shadowed by the local imports. - -#### 6.4 `name` field -`name` is used as a body field on `CreateFunction`, `UpdateFunction`, -`FunctionInfo`, `FunctionParameterInfo` (model.ts:81, 200, 263, 345), -and again indirectly via `fullNameArg`. Not a reserved word but -shadows `Function.prototype.name` — common source of confusion when -callers spread request objects. - -#### 6.5 `options` parameter on every client method -(client.ts:79, 111, 149, 190, 232, 257) — the second parameter is +#### 6.2 `name` field +`name` is used as a body field on `CreateFunction`, +`UpdateFunctionRequest`, `FunctionInfo`, `FunctionParameterInfo` +(model.ts:78, 187, 250, 326), and again indirectly via `fullNameArg`. +Not a reserved word but shadows `Function.prototype.name` — common +source of confusion when callers spread request objects. + +#### 6.3 `options` parameter on every client method +(client.ts:80, 112, 153, 194, 239, 264) — the second parameter is named `options` and shadows the marshal schema's `options`-style metadata patterns. Not a collision in this package specifically but consistent with the catalogs audit (§10.1). @@ -260,24 +215,24 @@ consistent with the catalogs audit (§10.1). ### 7. Duplicate concepts -#### 7.1 `CreateFunction`, `UpdateFunction`, and `FunctionInfo` share ~28 fields verbatim -(model.ts:79-140, 198-259, 341-404) +#### 7.1 `CreateFunction`, `UpdateFunctionRequest`, and `FunctionInfo` share ~28 fields verbatim +(model.ts:76-137, 185-246, 322-385) Three types with almost-identical shapes and identical doc strings. Generator artifact, but means any rename of, say, `routineBody`, must happen three times — and the divergences between Create / Update / Info are easy to miss. Recommend basing `CreateFunction` and -`UpdateFunction` on `Partial` (or a shared base +`UpdateFunctionRequest` on `Partial` (or a shared base interface). -#### 7.2 `fullName` vs `catalogName` + `schemaName` + `name` (model.ts:81-85, 127, 200-204, 246, 345-349, 391) +#### 7.2 `fullName` vs `catalogName` + `schemaName` + `name` (model.ts:78-82, 124, 187-191, 233, 326-330, 372) A `FunctionInfo` has all four: a top-level `name` (relative to schema), parent `catalogName` and `schemaName`, and `fullName` (the concatenation). Three pieces of data; four fields. A caller setting one and not the others leaves the type in an inconsistent state, and there's no documentation on which is authoritative on -`Create*` / `Update*`. See also §10.4. +`Create*` / `Update*`. See also §9.4. -#### 7.3 `dataType` vs `fullDataType` (model.ts:89-91, 208-210, 353-355) +#### 7.3 `dataType` vs `fullDataType` (model.ts:86-88, 195-197, 334-336) - `dataType: ColumnTypeName` — the enum form. - `fullDataType: string` — "Pretty printed function data type." @@ -285,10 +240,10 @@ The pretty-printed form is presumably a function of the enum plus any precision/scale/interval. Two fields encoding the same datum in two representations. -#### 7.4 `name` vs `fullNameArg` on `UpdateFunction` -`UpdateFunction` has *both* `fullNameArg` (the existing function -identifier, used in the URL path) and `name` (the new desired name -of the function, used in the body). See §10.1. +#### 7.4 `name` vs `fullNameArg` on `UpdateFunctionRequest` +`UpdateFunctionRequest` has *both* `fullNameArg` (the existing +function identifier, used in the URL path) and `name` (the new +desired name of the function, used in the body). See §9.1. --- @@ -310,9 +265,9 @@ qualifies the type. JS consumers commonly import as `import {Client} from '@databricks/sdk-functions/v1'` and have to alias. Package-wide convention; flagged for consistency. -#### 9.2 `fullNameArg` (model.ts:155, 294, 343) — Go generator naming. See §4.3. +#### 9.2 `fullNameArg` (model.ts:152, 281, 324) — Go generator naming. See §3.3. -#### 9.3 `Dependency.value.$case` discriminated union encoding (model.ts:168-184) +#### 9.3 `Dependency.value.$case` discriminated union encoding (model.ts:165-170) The `$case` discriminator with `value`-keyed payload is a ts-proto serialiser idiom. TS-native discriminated unions usually keep the discriminator at the top level (`{type: 'function', function: {…}}`) @@ -323,27 +278,27 @@ rather than wrapping in `value`. Functional, but visibly Go/proto. ### 10. Generic field names losing meaning #### 10.1 `name` is used twelve+ times across the model -(model.ts:81, 84, 86 within docs, 200, 203, 263, 345, 348, etc.) +(model.ts:78, 81, 83 within docs, 187, 190, 250, 326, 329, etc.) The semantics shift: function name, parameter name, catalog name, schema name, etc. — but the field is consistently `name`. Combined with `fullName`, `fullNameArg`, `functionFullName`, `tableFullName`, -`secretFullName`, `volumeFullName`, `externalName`, `specificName`, -the surface area of "name" fields is huge. See also §7.2. +`externalName`, `specificName`, the surface area of "name" fields is +huge. See also §7.2. -#### 10.2 `properties` (model.ts:121, 240, 385) +#### 10.2 `properties` (model.ts:118, 227, 366) "JSON-serialized key-value pair map, encoded (escaped) as a string." The field is `string`, despite the name promising a structured map. A consumer reading the type sees `properties?: string` and has to manually `JSON.parse`. Either name it `propertiesJson` or type it as `Record` with marshal-layer translation. -#### 10.3 `comment` (model.ts:119, 238, 285, 383) — see §1.3. +#### 10.3 `comment` (model.ts:116, 225, 272, 364) — see §1.3. --- ### 11. Field contradicting type domain -#### 11.1 `UpdateFunction` has `fullNameArg` *and* `name` (model.ts:343, 345) +#### 11.1 `UpdateFunctionRequest` has `fullNameArg` *and* `name` (model.ts:324, 326) - `fullNameArg` — the existing function's fully-qualified identifier (path param). - `name` — the function name, body field (the new desired name?). @@ -357,30 +312,21 @@ caller without a renaming primitive at all, or with an ambiguous #### 11.2 `CreateFunction` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, -`fullName`, `functionId`, `browseOnly` (model.ts:129-139). These are +`fullName`, `functionId`, `browseOnly` (model.ts:126-136). These are server-populated; a creator setting them is at best ignored. The -type's domain is "create request" but its shape contradicts that. -Mirror issue in `UpdateFunction` (model.ts:393-403). +type's domain is "create request body" but its shape contradicts +that. Mirror issue in `UpdateFunctionRequest` (model.ts:374-384). -#### 11.3 `DeleteFunction.fullNameArg` — see §4.3. +#### 11.3 `DeleteFunctionRequest.fullNameArg` — see §3.3. #### 11.4 `FunctionInfo.fullName` vs `name` / `catalogName` / `schemaName` -(model.ts:200-204, 246) +(model.ts:187-191, 233) On `FunctionInfo`, all four are present; for *catalogs* a `fullName` is redundant with `name`, but for *functions* `fullName` is `catalog_name.schema_name.function_name`. The doc comment underscores them as if they're literal placeholders. The naming is acceptable but the redundancy invites inconsistent state. -#### 11.5 `FunctionParameterInfo.parameterType: FunctionParameterType` where `PARAM` is one of two variants -(model.ts:281) -The field is on a "parameter info" object and one of its variants -is `PARAM`. So a `FunctionParameterInfo` may have -`parameterType === 'PARAM'`, i.e. "a parameter that is a parameter". -The other variant, `COLUMN`, means "a parameter that is a column -reference" — the type *contradicts* the parent type's domain. See -also §2.1. - --- ### 12. Inconsistent action verbs @@ -394,11 +340,11 @@ outliers. No issues found. ### 13. Underspecified IDs -#### 13.1 `metastoreId` (model.ts:125, 244, 389) +#### 13.1 `metastoreId` (model.ts:122, 231, 370) Documented as "Unique identifier of parent metastore." Format opaque (UUID? slug?). Acceptable but unspecified. -#### 13.2 `functionId` (model.ts:137, 256, 401) +#### 13.2 `functionId` (model.ts:134, 243, 382) Doc: "Id of Function, relative to parent schema." Format unspecified — is this a UUID, an autoincrement integer, an opaque token? Type is `string` so opaque, but the docs should say so. @@ -407,36 +353,18 @@ Doc: "Id of Function, relative to parent schema." Format unspecified Both `string`, both undocumented for format, both server-assigned. A consumer cannot tell them apart from the types. -#### 13.4 `createdAt` / `updatedAt` (model.ts:129, 133, 248, 252, 393, 397) +#### 13.4 `createdAt` / `updatedAt` (model.ts:126, 130, 235, 239, 374, 378) Type is `number` (epoch milliseconds per the doc). The field name doesn't convey unit. `createdAtMs` / `updatedAtMs` or `createdAtEpochMs` would be more honest. The catalogs audit flagged the same inconsistency. -#### 13.5 `connectionName` (model.ts:76) — "Full name of the dependent connection, in the form of __connection_name__." +#### 13.5 `connectionName` (model.ts:73) — "Full name of the dependent connection, in the form of __connection_name__." The field is named `connectionName` but the doc says it should be a "full name". For other dependency types, the field is explicitly -named `*FullName` (e.g. `secretFullName`, `tableFullName`). Naming +named `*FullName` (e.g. `tableFullName`, `functionFullName`). Naming inconsistency: ConnectionDependency and CredentialDependency -(model.ts:150) use `…Name`; the rest use `…FullName`. Pick one. - ---- - -### 14. Type-suffix tautology - -#### 14.1 `ColumnTypeName` enum with field `typeName: ColumnTypeName` -(model.ts:5, 269) — field name conflates "type name" with the enum -type. Reading `parameter.typeName === ColumnTypeName.INT` is doubly -type-y. Either shorten the field (`type: ColumnTypeName`) or rename -the enum (`ColumnType`). - -#### 14.2 `FunctionParameterMode` enum with field `parameterMode: FunctionParameterMode` -(model.ts:35, 279) — field-name tautological with type-name. - -#### 14.3 `FunctionParameterType` enum with field `parameterType: FunctionParameterType` -(model.ts:39, 281) — field-name tautological with type-name. Also -suffers from §11.5 (a "parameter type" that admits "PARAM" as a -variant). +(model.ts:147) use `…Name`; the rest use `…FullName`. Pick one. --- @@ -445,22 +373,22 @@ variant). ### A. `flattenQueryParams` is defined but unused (utils.ts:123) Each `listFunctions` / `getFunction` / `deleteFunction` handler builds query strings inline with `URLSearchParams.append` -(client.ts:115-118, 154-156, 194-209). The exported helper +(client.ts:115-118, 156-159, 197-212). The exported helper `flattenQueryParams` is never referenced by `client.ts`. Either it's intentionally exported for consumer use (then it should be documented) or it's dead code. Same finding as catalogs audit (cross-cutting A). ### B. `fullNameArg` URL substitution silently allows empty string -(client.ts:114, 152, 260) — `${req.fullNameArg ?? ''}` — if +(client.ts:114, 155, 266) — `${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL silently becomes `/api/2.1/unity-catalog/functions/` and the request will fail on the server. The naming (`fullNameArg`) and the substitution behaviour together hide what should be a required parameter. Worth surfacing via a non-optional type or a typed assertion. -### C. `marshalUpdateFunctionSchema` serialises `fullNameArg` into the body -(model.ts:864) `fullNameArg` is a path parameter — but the marshal +### C. `marshalUpdateFunctionRequestSchema` serialises `fullNameArg` into the body +(model.ts:799) `fullNameArg` is a path parameter — but the marshal schema produces a JSON field `full_name_arg`. Either the server tolerates the extra field or this is a bug. The `Arg` suffix lets the bug hide. @@ -481,7 +409,7 @@ pattern (§6.1) combined with the package name creates a vocabulary where "function" is overloaded. ### F. `FunctionInfo.routineDependencies` is described as "function dependencies." -(model.ts:122, 241, 386) Comment text starts with lowercase and uses +(model.ts:119, 228, 367) Comment text starts with lowercase and uses "function" instead of "routine"; field name uses "routine". See §5.1 and §5.3. @@ -489,7 +417,96 @@ where "function" is overloaded. The most extreme case of a single-purpose API surface: a long enum type holding a one-letter variant, only ever set to `S`, marshaled as the JSON string `"S"`. Three layers of indirection for a constant. -See §2.2, §4.1. +See §2.1, §3.1. + +--- + +## 14. Proto-architectural-leak naming + +### 14.1 `FunctionInfo_ParameterStyle` — model.ts:42 +Why: `Parent_Child` underscore identifier is a proto/ts-proto +serialiser idiom for nested message/enum types. +Category: Proto suffix/infix. +Suggested: `FunctionParameterStyle` (or `ParameterStyle` if scoped to +the package). +Rationale: TypeScript enums do not need parent-qualifying via +underscore. The leak exposes the upstream proto schema's nested-type +layout to TS consumers. + +### 14.2 `FunctionInfo_RoutineBody` — model.ts:47 +Why: `Parent_Child` underscore identifier is a proto/ts-proto +serialiser idiom for nested message/enum types. +Category: Proto suffix/infix. +Suggested: `RoutineBody`. +Rationale: Same as 14.1. + +### 14.3 `FunctionInfo_SecurityType` — model.ts:59 +Why: `Parent_Child` underscore identifier is a proto/ts-proto +serialiser idiom for nested message/enum types. +Category: Proto suffix/infix. +Suggested: `SecurityType`. +Rationale: Same as 14.1. + +### 14.4 `FunctionInfo_SqlDataAccess` — model.ts:64 +Why: `Parent_Child` underscore identifier is a proto/ts-proto +serialiser idiom for nested message/enum types. +Category: Proto suffix/infix. +Suggested: `SqlDataAccess`. +Rationale: Same as 14.1. + +### 14.5 `DeleteFunctionRequest_Response` — model.ts:158 +Why: `Request_Response` underscore-paired identifier mirrors proto +nested-response-message convention (`Foo_Response`). The lint comment +explicitly notes "Proto-style nested message name." +Category: Proto suffix/infix + `Foo_PublicRequest`-style paired naming. +Suggested: `DeleteFunctionResponse` (or omit entirely — it is an +empty object). +Rationale: TS has no nested-message concept; the underscore-paired +naming surfaces the upstream proto schema to consumers. + +### 14.6 `ListFunctionsRequest_Response` — model.ts:306 +Why: `Request_Response` underscore-paired identifier mirrors proto +nested-response-message convention. +Category: Proto suffix/infix + `Foo_PublicRequest`-style paired naming. +Suggested: `ListFunctionsResponse`. +Rationale: Same as 14.5. + +### 14.7 `unmarshalDeleteFunctionRequest_ResponseSchema` — model.ts:406 +Why: Schema constant inherits the `Request_Response` proto-nested +underscore identifier; verb-prefixed schema name (`unmarshal*Schema`) +on top further surfaces serialisation-layer concerns at the package +surface. +Category: Proto suffix/infix. +Suggested: `unmarshalDeleteFunctionResponseSchema`. +Rationale: Same as 14.5. + +### 14.8 `unmarshalListFunctionsRequest_ResponseSchema` — model.ts:561 +Why: Schema constant inherits the `Request_Response` proto-nested +underscore identifier. +Category: Proto suffix/infix. +Suggested: `unmarshalListFunctionsResponseSchema`. +Rationale: Same as 14.5. + +### 14.9 `fullNameArg` — model.ts:152, 281, 324 +Why: The `Arg` suffix is a Go SDK generator artifact distinguishing +path-parameter fields from same-keyed body fields; it has no meaning +on the TS surface. +Category: Generator/codegen artifact (proto-adjacent). +Suggested: `fullName` (drop `Arg`). +Rationale: TS consumers do not see the path/body split; the suffix +exposes a generator implementation detail. Already cross-referenced +in §3.3, §9.2; re-flagged here as a proto-architectural leak. + +### 14.10 `Dependency.value.$case` discriminated-union shape — model.ts:165-170 +Why: `{$case: 'foo'; foo: T}` is the ts-proto serialiser's encoding +for oneof fields; native TS discriminated unions normally use a +top-level discriminator key, not a `value`-wrapped `$case` envelope. +Category: Proto suffix/infix (encoding leak). +Suggested: Flatten to `{type: 'function'; function: FunctionDependency} | ...` +at the top level. +Rationale: The `$case` discriminator key and the `value`-wrapped +envelope visibly reflect proto oneof semantics. Already noted in +§9.3; re-flagged here as a proto-architectural leak. --- @@ -497,44 +514,39 @@ See §2.2, §4.1. | Identifier | Location | Finding | | -------------------------------------------------------- | --------------------- | ------- | -| `ColumnTypeName` | model.ts:5 | 3.5, 14.1 | -| `ColumnTypeName.TIMESTAMP_NTZ` | model.ts:25 | 3.5 | -| `FunctionParameterMode` | model.ts:35 | 4.2, 14.2 | -| `FunctionParameterMode.IN` | model.ts:35-37 | 4.2 | -| `FunctionParameterType` | model.ts:39 | 2.1, 11.5, 14.3 | -| `FunctionInfo_ParameterStyle.S` | model.ts:46 | 2.2, 4.1 | -| `FunctionInfo_SecurityType.DEFINER` | model.ts:62-64 | 2.3 | -| `FunctionInfo_SqlDataAccess` | model.ts:67 | 3.1 | -| `ConnectionDependency.connectionName` | model.ts:76 | 13.5 | -| `CreateFunction` | model.ts:79 | 7.1, 11.2 | -| `CreateFunction.routineBody/routineDefinition/routineDependencies` | model.ts:93/95/123 | 5.3 | -| `CreateFunction.specificName` | model.ts:107 | 5.5 | -| `CreateFunction.fullName` | model.ts:127 | 7.2, 11.4 | -| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:125-139 | 11.2, 13.1, 13.2, 13.4 | -| `DeleteFunction.fullNameArg` | model.ts:155 | 4.3, 9.2, 11.3 | -| `DeleteFunction.force` | model.ts:157 | 1.1, 5.2 | -| `Dependency.value.function` arm | model.ts:170 | 6.1 | -| `Dependency.value.$case` | model.ts:168 | 9.3 | -| `FunctionDependency` | model.ts:193 | 6.2 | -| `FunctionInfo` | model.ts:198 | 6.3, 7.1 | -| `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:212/214/242 | 5.3 | -| `FunctionInfo.specificName` | model.ts:226 | 5.5 | -| `FunctionInfo.properties` | model.ts:240 | 10.2 | -| `FunctionInfo.fullName` | model.ts:246 | 7.2, 11.4 | -| `FunctionInfo.functionId` | model.ts:256 | 13.2, 13.3 | -| `FunctionParameterInfo.name` | model.ts:263 | 6.4, 10.1 | -| `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:265-269 | 3.3, 3.4, 4.6, 14.1 | -| `FunctionParameterInfo.position` | model.ts:277 | 1.2 | -| `FunctionParameterInfo.parameterMode / parameterType` | model.ts:279, 281 | 11.5, 14.2, 14.3 | -| `FunctionParameterInfo.parameterDefault` | model.ts:283 | 5.4 | -| `FunctionParameterInfo.comment` | model.ts:285 | 1.3 | -| `GetFunction.fullNameArg` | model.ts:294 | 4.3, 9.2 | -| `UpdateFunction` | model.ts:341 | 7.1, 7.4, 11.1, 11.2 | -| `UpdateFunction.fullNameArg / name` | model.ts:343, 345 | 4.3, 7.4, 11.1 | -| `UpdateFunction.routineBody / routineDefinition / routineDependencies` | model.ts:357/359/387 | 5.3 | -| `UpdateFunction.fullName` | model.ts:391 | 7.2, 11.4 | +| `FunctionParameterMode` | model.ts:32 | 3.2 | +| `FunctionParameterMode.IN` | model.ts:32-34 | 3.2 | +| `FunctionInfo_ParameterStyle.S` | model.ts:43 | 2.1, 3.1 | +| `FunctionInfo_SecurityType.DEFINER` | model.ts:59-61 | 2.2 | +| `FunctionInfo_SqlDataAccess` | model.ts:64 | 4.1 | +| `ConnectionDependency.connectionName` | model.ts:73 | 13.5 | +| `CreateFunction` | model.ts:76 | 7.1, 11.2 | +| `CreateFunction.routineBody/routineDefinition/routineDependencies` | model.ts:90/92/120 | 5.3 | +| `CreateFunction.specificName` | model.ts:104 | 5.5 | +| `CreateFunction.fullName` | model.ts:124 | 7.2, 11.4 | +| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:122-136 | 11.2, 13.1, 13.2, 13.4 | +| `DeleteFunctionRequest.fullNameArg` | model.ts:152 | 3.3, 9.2, 11.3 | +| `DeleteFunctionRequest.force` | model.ts:154 | 1.1, 5.2 | +| `Dependency.value.function` arm | model.ts:167 | 6.1 | +| `Dependency.value.$case` | model.ts:165 | 9.3 | +| `FunctionInfo` | model.ts:185 | 7.1 | +| `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:199/201/229 | 5.3 | +| `FunctionInfo.specificName` | model.ts:213 | 5.5 | +| `FunctionInfo.properties` | model.ts:227 | 10.2 | +| `FunctionInfo.fullName` | model.ts:233 | 7.2, 11.4 | +| `FunctionInfo.functionId` | model.ts:243 | 13.2, 13.3 | +| `FunctionParameterInfo.name` | model.ts:250 | 6.2, 10.1 | +| `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:252-256 | 4.3, 4.4 | +| `FunctionParameterInfo.position` | model.ts:264 | 1.2 | +| `FunctionParameterInfo.parameterDefault` | model.ts:270 | 5.4 | +| `FunctionParameterInfo.comment` | model.ts:272 | 1.3 | +| `GetFunctionRequest.fullNameArg` | model.ts:281 | 3.3, 9.2 | +| `UpdateFunctionRequest` | model.ts:322 | 7.1, 7.4, 11.1, 11.2 | +| `UpdateFunctionRequest.fullNameArg / name` | model.ts:324, 326 | 3.3, 7.4, 11.1 | +| `UpdateFunctionRequest.routineBody / routineDefinition / routineDependencies` | model.ts:338/340/368 | 5.3 | +| `UpdateFunctionRequest.fullName` | model.ts:372 | 7.2, 11.4 | | `Client` (bare name) | client.ts:44 | 9.1 | -| `${req.fullNameArg ?? ''}` URL substitution | client.ts:114, 152, 260 | B | +| `${req.fullNameArg ?? ''}` URL substitution | client.ts:114, 155, 266 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | --- @@ -542,9 +554,9 @@ See §2.2, §4.1. ## Recommended priority order 1. **Resolve the `function` reserved-word collision in `Dependency.value`** — the union arm-key `function` is the single most jarring naming hazard in the package. (§6.1) -2. **Fix `fullNameArg` / `name` confusion on `UpdateFunction`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §4.3) +2. **Fix `fullNameArg` / `name` confusion on `UpdateFunctionRequest`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §3.3) 3. **Resolve "function" vs "routine" vocabulary split.** (§5.3) -4. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.2, §2.3, §4.1, §4.2) -5. **Strip read-only fields from `CreateFunction` / `UpdateFunction`.** (§11.2) +4. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.1, §2.2, §3.1, §3.2) +5. **Strip read-only fields from `CreateFunction` / `UpdateFunctionRequest`.** (§11.2) 6. **Unify `*Name` vs `*FullName` field-naming on `*Dependency` types.** (§13.5) 7. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index c00b0677..1bac061b 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -3,12 +3,12 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 64 +**Total weird names flagged:** 62 ## Summary | Severity | Count | | --- | --- | -| High | 17 | +| High | 15 | | Medium | 24 | | Low | 18 | | Observation | 5 | @@ -34,230 +34,218 @@ - **Rationale:** The verbs `Execute` / `Get` / `Generate` overlap in everyday English; the type system gives no hint which one to call first. The current names are generator-faithful but unhelpful for users. ### 4. `Genie*` prefix on every type — type-suffix tautology — `src/v1/model.ts` (~40 types) -- **Why weird:** 40 of ~70 types are prefixed `Genie`: `GenieAttachment`, `GenieConversation`, `GenieMessage`, `GenieSpace`, `GenieFeedback`, `GenieEvalResult`, etc. The package is `@databricks/sdk-genie` and types are imported as `import {GenieMessage} from '@databricks/sdk-genie'`. The prefix duplicates the package identity. Other types in the same file have no prefix (`Result`, `ResultData`, `ResultManifest`, `StatementResponse`, `StatementStatus`, `Schema`, `Struct`, `ListValue`, `ChunkInfo`, `MessageError`, `MessageStatus`, `Thought`, `TextAttachment`, `VerificationMetadata`, etc.) — so the prefix is not even applied consistently. +- **Why weird:** 40 of ~70 types are prefixed `Genie`: `GenieAttachment`, `GenieConversation`, `GenieMessage`, `GenieSpace`, `GenieFeedback`, `GenieEvalResult`, etc. The package is `@databricks/sdk-genie` and types are imported as `import {GenieMessage} from '@databricks/sdk-genie'`. The prefix duplicates the package identity. Other types in the same file have no prefix (`Result`, `ResultData`, `ResultManifest`, `StatementResponse`, `StatementStatus`, `Schema`, `Struct`, `ListValue`, `ChunkInfo`, `MessageError`, `MessageStatus`, `Thought`, `TextAttachment`, etc.) — so the prefix is not even applied consistently. - **Category:** 20 (type-suffix tautology), 17 (prefix applied inconsistently within the same package). - **Suggested name:** Drop the prefix wherever the unprefixed name is unambiguous: `Conversation`, `Message`, `Space`, `Attachment`, `Feedback`, `EvalResult`. Keep `Genie` only where collision with a copied-in shared type would arise (e.g. keep `GenieResultMetadata` if you also need to keep `ResultManifest`). - **Rationale:** `import {Message} from '@databricks/sdk-genie'` is unambiguous (the package is the namespace). The current prefix turns every import line into noise. -### 5. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1481` +### 5. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1458` - **Why weird:** The central noun. A `GenieSpace` is a "workspace scoped to a Genie deployment", but the word `Space` is one of the most overloaded terms in the Databricks SDK (it also appears in workspace, mlflow registered model, dashboards, etc.). Type doc on the class itself is one line ("Genie space ID"). Reader sees `GenieSpace` and has to consult external docs to learn whether it's a folder, a user-permission boundary, a model-deployment, or something else. - **Category:** 1 (vague/generic), 15 (generic field name losing meaning — `Space`). - **Suggested name:** `GenieRoom`, `GenieAgent`, `GenieDeployment`, or at minimum a JSDoc on the type explaining what a "space" *is* (warehouse + datasets + instructions). If "Space" is the Databricks product-marketing term, document it inline. - **Rationale:** This is the package's central concept. Letting it stand on a single word that means "container" is a documentation gap as much as a naming bug. -### 6. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-33,36-534,547-551,777-907,1610-1715` -- **Why weird:** 15+ types are byte-for-byte copies of types in the `statementexecution`, `sql` and `apierror` packages: `ColumnTypeName` (enum, 28 values), `ErrorCode` (enum, 80 values, with line-for-line JSDoc), `Format` (enum), `ChunkInfo`, `ColumnInfo`, `ColumnMask`, `DatabricksServiceExceptionProto`, `ExternalLink`, `ExternalLink_HttpHeadersEntry`, `PolicyFunctionArgument`, `Result`, `ResultData`, `ResultManifest`, `Schema`, `StatementResponse`, `StatementStatus`, `StatementStatus_State`. The file even copies the Google-Well-Known-Types (`Struct`, `Value`, `ListValue`, `MapStringValueEntry`, `NullValue`). +### 6. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-30,33-531,543-548,754-884,1589-1694` +- **Why weird:** 15+ types are byte-for-byte copies of types in the `statementexecution`, `sql` and `apierror` packages: `ColumnTypeName` (enum, 28 values), `ErrorCode` (enum, 80 values, with line-for-line JSDoc), `Format` (enum), `ChunkInfo`, `ColumnInfo`, `ColumnMask`, `DatabricksServiceExceptionProto`, `ExternalLink`, `ExternalLink_HttpHeadersEntry`, `PolicyFunctionArgument`, `Result`, `ResultData`, `ResultManifest`, `Schema`, `StatementResponse`, `StatementStatus`, `StatementStatus_State`. The file even copies the Google-Well-Known-Types (`Struct`, `Value`, `ListValue`, `MapStringValueEntry`). - **Category:** 12 (duplicate concept across packages). - **Suggested name:** Import from `@databricks/sdk-databricks/statementexecution` (or wherever the originals live). If the generator can't yet cross-link, mark each duplicate `@internal` or move them to a shared internal module. - **Rationale:** A consumer who imports both `@databricks/sdk-genie` and `@databricks/sdk-sql` ends up with two structurally-identical-but-nominally-distinct `StatementResponse` types — runtime values are not assignable to each other in strict mode. This is the biggest correctness footgun in the package. -### 7. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:36-534` -- **Why weird:** ErrorCode is copied verbatim from the SDK's apierror codes package. Of the 80 values, comments explicitly mark ~50 as deprecated. The enum is only referenced via the copied `DatabricksServiceExceptionProto` type, which is itself unused by any Genie method (the SDK uses `APIError.fromHttpError` in `utils.ts:88`). +### 7. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:33-531` +- **Why weird:** ErrorCode is copied verbatim from the SDK's apierror codes package. Of the 80 values, comments explicitly mark ~50 as deprecated. The enum is only referenced via the copied `DatabricksServiceExceptionProto` type, which is itself unused by any Genie method (the SDK uses `ApiError.fromHttpError` in `utils.ts:88`). - **Category:** 12 (duplicate concept), 18 (long enum values — `MAX_NOTEBOOK_SIZE_EXCEEDED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, `RESOURCE_DOES_NOT_EXIST`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). - **Suggested name:** Import from `@databricks/sdk-databricks/apierror/codes`. Remove the local copy. -- **Rationale:** 500 lines of code (model.ts:36-534) duplicate a separate package. Maintenance hazard: deprecation removals or additions to the canonical enum will diverge silently. +- **Rationale:** 500 lines of code duplicate a separate package. Maintenance hazard: deprecation removals or additions to the canonical enum will diverge silently. -### 8. `ScoreReason` enum — values mix `RESULT_*`, `LLM_JUDGE_*`, and unprefixed `EMPTY_RESULT`/`SINGLE_CELL_DIFFERENCE` — `src/v1/model.ts:593-622` -- **Why weird:** 22 values, three families: (a) plain (`EMPTY_RESULT`, `SINGLE_CELL_DIFFERENCE`, `EMPTY_GOOD_SQL`, `COLUMN_TYPE_DIFFERENCE`); (b) `RESULT_*` (`RESULT_MISSING_ROWS`, `RESULT_EXTRA_ROWS`, `RESULT_MISSING_COLUMNS`, `RESULT_EXTRA_COLUMNS`); (c) `LLM_JUDGE_*` (16 values). Six `LLM_JUDGE_*` values are deprecated and kept beside the new ones. `EMPTY_RESULT` and `EMPTY_GOOD_SQL` should both be `RESULT_*` for consistency. -- **Category:** 2 (redundant enum prefixes), 18 (long enum values — `LLM_JUDGE_INSTRUCTION_COMPLIANCE_OR_MISSING_BUSINESS_LOGIC` is 60 characters), 17 (inconsistent prefix), 12 (deprecated values duplicated alongside new). -- **Suggested name:** Either drop all prefixes (`EmptyResult | MissingRows | ExtraRows | …`) or apply uniformly (`RESULT_EMPTY`, `RESULT_MISSING_ROWS`, …, `JUDGE_MISSING_FILTER`, `JUDGE_INCOMPLETE_OUTPUT`, …). Separate the deprecated values into a dedicated comment block or split into two enums. -- **Rationale:** Autocomplete on `ScoreReason.` returns 22 items with no visual grouping; users cannot tell at a glance which are deterministic vs which are LLM-judge. +### 8. `ScoreReason` enum mixes three prefix families and keeps six deprecated values inline — `src/v1/model.ts:584-613` +- **Why weird:** 22 values fall into three groups: (a) bare (`EMPTY_RESULT`, `SINGLE_CELL_DIFFERENCE`, `EMPTY_GOOD_SQL`, `COLUMN_TYPE_DIFFERENCE`); (b) `RESULT_*` (`RESULT_MISSING_ROWS`, `RESULT_EXTRA_ROWS`, `RESULT_MISSING_COLUMNS`, `RESULT_EXTRA_COLUMNS`); (c) `LLM_JUDGE_*` (16 values). `EMPTY_RESULT` and `EMPTY_GOOD_SQL` are semantically `RESULT_*` reasons but lack the prefix family. Six `LLM_JUDGE_*` values are deprecated and live beside the new ones with no visual separation. +- **Category:** 17 (inconsistent grouping — same family, different prefixes), 12 (deprecated values inline with active ones). +- **Suggested name:** Move `EMPTY_RESULT` / `EMPTY_GOOD_SQL` into the `RESULT_*` family for internal consistency. Separate deprecated values into a dedicated comment block (or split into two enums) so autocomplete groups them. +- **Rationale:** The current ordering makes it hard for a reader to tell which values are deterministic vs LLM-judge and which are still active vs deprecated. -### 9. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:669-736` +### 9. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:648-713` - **Why weird:** 60 values, almost every one ends in `_EXCEPTION` (`UNEXPECTED_REPLY_PROCESS_EXCEPTION`, `GENERIC_CHAT_COMPLETION_EXCEPTION`, `CONTEXT_EXCEEDED_EXCEPTION`, …). The few that don't are inconsistent: `STOP_PROCESS_DUE_TO_AUTO_REGENERATE`, `UNKNOWN_AI_MODEL`, `NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE`, plus `MESSAGE_ATTACHMENT_TOO_LONG_ERROR` (suffix `_ERROR` not `_EXCEPTION`), `DESCRIBE_QUERY_UNEXPECTED_FAILURE` / `DESCRIBE_QUERY_TIMEOUT` / `DESCRIBE_QUERY_INVALID_SQL_ERROR` (different verbs). The `_EXCEPTION` suffix is also Java vocabulary, not TS. - **Category:** 2 (redundant suffix — every value already lives under `MessageError_Type`), 14 (Java-style `Exception` vocabulary in TS), 18 (long values — `INTERNAL_CATALOG_ASSET_CREATION_UNSPECIFIED_EXCEPTION` is 52 chars), 17 (inconsistent suffix). - **Suggested name:** Drop `_EXCEPTION` from every value: `UnexpectedReplyProcess | GenericChatCompletion | ContextExceeded | …`. Pick one of `_ERROR` / `_EXCEPTION` / nothing. - **Rationale:** This enum is 67 lines long; cleaning the suffix removes 600+ characters and makes the values readable in autocomplete. -### 10. Three `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:537,547,554,561,569,584,588,595,626,633,643,660,670` -- **Why weird:** 13 enums use a `XXX_UNSPECIFIED` sentinel where `XXX` is the enum's name: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `GENIE_FEEDBACK_RATING_UNSPECIFIED`, `NULL_VALUE`, `RESPONSE_PHASE_UNSPECIFIED`, `SCORE_REASON_UNSPECIFIED`, `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED`, `THOUGHT_TYPE_UNSPECIFIED`, `VERIFICATION_SECTION_UNSPECIFIED`, `TYPE_UNSPECIFIED` (inside `MessageError_Type`), `STATE_UNSPECIFIED` (inside `StatementStatus_State`). Proto2 forces this; TS does not need it because the enum's type acts as the namespace. +### 10. Multiple `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:534,544,551,558,565,581,585,617,634,649,745` +- **Why weird:** 11 enums use a `XXX_UNSPECIFIED` sentinel where `XXX` is the enum's name: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `GENIE_FEEDBACK_RATING_UNSPECIFIED`, `NULL_VALUE`, `SCORE_REASON_UNSPECIFIED`, `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED`, `THOUGHT_TYPE_UNSPECIFIED`, `TYPE_UNSPECIFIED` (inside `MessageError_Type`), `STATE_UNSPECIFIED` (inside `StatementStatus_State`). Proto2 forces this; TS does not need it because the enum's type acts as the namespace. - **Category:** 2 (redundant enum prefix), 18 (long enum values). - **Suggested name:** `Unspecified` (drop the prefix). Or omit entirely if TS-undefined can stand in for proto-unspecified. - **Rationale:** The package will get cleaner immediately; the wire string can stay the same. -### 11. `RESPONSE_PHASE_*` prefix repeated on every value — `src/v1/model.ts:588-590` -- **Why weird:** Enum `ResponsePhase` has 3 values: `RESPONSE_PHASE_UNSPECIFIED`, `RESPONSE_PHASE_THINKING`, `RESPONSE_PHASE_VERIFYING`. Every value carries the parent name. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** `Unspecified | Thinking | Verifying`. -- **Rationale:** Same as #10 — autocomplete already namespaces. +### 11. `TextAttachmentPurpose` enum has only 2 values — collapse to boolean — `src/v1/model.ts:616-619` +- **Why weird:** Two values: `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED` and `FOLLOW_UP_QUESTION`. A two-member enum where one member is the sentinel adds nothing over a boolean. +- **Category:** 12 (overspecified — enum used where a boolean would do). +- **Suggested name:** Drop the enum; replace with `isFollowUp?: boolean`. +- **Rationale:** Two-member enums where one is `_UNSPECIFIED` are often better collapsed to an optional boolean. -### 12. `THOUGHT_TYPE_*` prefix repeated — `src/v1/model.ts:643-653` -- **Why weird:** Six values, all `THOUGHT_TYPE_*`. The plain-noun forms (`Description`, `Understanding`, `DataSourcing`, `Instructions`, `Steps`) would be perfectly clear under `ThoughtType.`. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** `ThoughtType.Unspecified | Description | Understanding | DataSourcing | Instructions | Steps`. -- **Rationale:** Same as #10. - -### 13. `VERIFICATION_SECTION_*` prefix repeated and one value has the prefix doubled — `src/v1/model.ts:660-666` -- **Why weird:** Five values: `VERIFICATION_SECTION_UNSPECIFIED`, `VERIFICATION_SECTION_SQL_EXAMPLES_VALIDATION`, `VERIFICATION_SECTION_VERIFICATION_QUERIES`, `VERIFICATION_SECTION_PROPOSED_IMPROVEMENT`, `VERIFICATION_SECTION_FINAL_DECISION`. The third value (`VERIFICATION_SECTION_VERIFICATION_QUERIES`) repeats `VERIFICATION` — 41 characters. -- **Category:** 2 (redundant prefix doubled), 18 (long enum values). -- **Suggested name:** `VerificationSection.Unspecified | SqlExamplesValidation | VerificationQueries | ProposedImprovement | FinalDecision`. -- **Rationale:** Same. - -### 14. `TEXT_ATTACHMENT_PURPOSE_*` prefix repeated; enum has only 2 values — `src/v1/model.ts:626-628` -- **Why weird:** Two values: `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED` (35 chars) and `FOLLOW_UP_QUESTION`. Prefix only on the sentinel — inconsistent within the same enum. -- **Category:** 17 (inconsistent prefix within one enum), 2 (redundant prefix on sentinel). -- **Suggested name:** Either `Unspecified | FollowUpQuestion`, or drop the enum (boolean `isFollowUp`). -- **Rationale:** Two-member enums where one is `_UNSPECIFIED` are often better collapsed. - -### 15. `GENIE_EVAL_ASSESSMENT_*` and `GENIE_EVAL_RESPONSE_TYPE_*` prefixes — `src/v1/model.ts:554,561` -- **Why weird:** `GenieEvalAssessment` has values `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GOOD`, `BAD`, `NEEDS_REVIEW`. Only the sentinel carries the prefix. `GenieEvalResponseType` likewise: `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `TEXT`, `SQL`. -- **Category:** 17 (inconsistent prefix), 2 (redundant prefix on sentinel). -- **Suggested name:** Drop the prefix on the sentinel. -- **Rationale:** Same as the rest of the enum prefix cluster — the consistency wins matter more than the wire encoding. - -### 16. `EvaluationStatusType` has 6 values mixing `EVALUATION_*` and unprefixed — `src/v1/model.ts:536-544` -- **Why weird:** Six values: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `RUNNING`, `DONE`, `NOT_STARTED`, `EVALUATION_FAILED`, `EVALUATION_CANCELLED`, `EVALUATION_TIMEOUT`. Three are prefixed `EVALUATION_*`, three are bare. The mixed prefixing is jarring. -- **Category:** 17 (inconsistent prefix within one enum), 2 (redundant prefix), 6 (`Type` suffix on enum name is also redundant — every enum is a "type"). -- **Suggested name:** `EvaluationStatus.Unspecified | Running | Done | NotStarted | Failed | Cancelled | Timeout`. Drop the `Type` suffix from the enum name. -- **Rationale:** This enum is exposed in `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus` — readable values matter. - -### 17. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` +### 12. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:533` +- **Why weird:** The type is named `EvaluationStatusType`. Every enum is by definition a "type", so the suffix adds nothing. Peer enums in the same file use bare-noun names (`ScoreReason`, `ThoughtType` — though `ThoughtType` is itself debatable, `Format`, `MessageStatus_MessageStatus`). +- **Category:** 8 (redundant `Type` suffix on enum name). +- **Suggested name:** `EvaluationStatus`. +- **Rationale:** This enum is exposed on `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus`; trimming the suffix shortens both call sites without losing information. + +### 13. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` - **Why weird:** Three deprecated/active methods all return `GenieGetMessageQueryResultResponse` and all read the SQL result for a message. The naming hierarchy is `Message.QueryResult` vs `MessageAttachment.QueryResult` vs `QueryResult.byAttachment` — three different mental models. Two are deprecated but still exported and named in the surface. - **Category:** 17 (inconsistent action verb / structure), 7 (overly verbose), 12 (duplicate concept). - **Suggested name:** Keep the single canonical method (`getMessageAttachmentQueryResult` → `getMessageAttachmentResult`), mark the others `@deprecated` and consider hiding them from the typed surface (re-export only from `/legacy`). - **Rationale:** Three names with overlapping suffixes is the classic generator-emitting-everything problem. +### 14. `GenieEvalAssessment` / `GenieEvalResponseType` — only the sentinel carries the long prefix — `src/v1/model.ts:550,557` +- **Why weird:** `GenieEvalAssessment` has values `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GOOD`, `BAD`, `NEEDS_REVIEW`. Only the sentinel carries the prefix. `GenieEvalResponseType` likewise: `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `TEXT`, `SQL`. Within one enum two naming conventions are present. +- **Category:** 17 (inconsistent prefix within one enum). +- **Suggested name:** Drop the prefix on the sentinel; align with the bare-name convention used by the rest of the values. +- **Rationale:** Inconsistency inside a single enum is more jarring than a uniform convention either way; this is the proto-style "only the sentinel is prefixed" pattern. + +### 15. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:828` +- **Why weird:** The type name stacks three architectural-layer words: `Service` (server-side tier), `Exception` (Java vocabulary), and `Proto` (wire-format suffix). None of these belong in a public TS SDK surface — the SDK exposes errors, not Java exceptions, and not proto messages. JSDoc reinforces the leak: "Serialization format for DatabricksServiceException. Note the definition of this message should be in sync with DatabricksServiceExceptionWithDetailsProto defined in /api-base/proto/exception_with_details.proto". The companion schema is `unmarshalDatabricksServiceExceptionProtoSchema` (line 1843), propagating the leak. +- **Category:** Proto-architectural-leak (`Proto` suffix, `Service` mid), 14 (Java-style `Exception` vocabulary in TS), 12 (duplicate concept — the SDK already has `ApiError`). +- **Suggested name:** Delete the type and reuse `ApiError` from `@databricks/sdk-databricks/apierror`. If the wire-format shape must be kept locally, name it `ApiErrorPayload` or `WireError` and treat it as an internal marshal-time type, not a public export. +- **Rationale:** `Service`, `Exception`, and `Proto` are all backend implementation vocabulary that should never reach the user-facing SDK surface. The type is unused by any public method body (per finding #7), making the leak gratuitous. + ## Medium severity -### 18. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1506` +### 16. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1483` - **Why weird:** Request type for `genieStartConversation`. Name contains *both* `Conversation` and `Message`, but the body has only `spaceId` and `content` (`{ spaceId?: string; content?: string; }`). It is not a request to start a "conversation message" — it is a request to start a conversation by sending an initial message. Compare with `GenieStartConversationResponse` (no `Message` in the name). - **Category:** 6 (misleading — name suggests a compound entity that doesn't exist), 7 (overly verbose). - **Suggested name:** `StartConversationRequest` (matches the response). - **Rationale:** Reader has to parse the doc to learn what "ConversationMessage" means here. The companion response name (`GenieStartConversationResponse`) silently drops `Message` — internal inconsistency. -### 19. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:911` +### 17. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:888` - **Why weird:** `GenieAttachment.attachment` is a `{ $case: 'text' | 'query' | 'suggestedQuestions', … } | undefined` field. Reading `myAttachment.attachment.text` reads as "the attachment of the attachment", and the parent `GenieAttachment` also has a peer field `attachmentId`. The shape mixes the discriminator field with a flat id field. - **Category:** 15 (generic field name losing meaning). - **Suggested name:** Hoist to top-level discriminated union: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. Or rename the field to `payload` / `body` / `content`. - **Rationale:** Same struct, single name; the parent-name-shaped field name confuses readers traversing nested attachments. -### 20. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:940,952` +### 18. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:917,929` - **Why weird:** The struct has two id fields. JSDoc on `id` says "Legacy identifier, use conversation_id instead". Both are emitted, both are typed `string | undefined`, both are read from the wire. The struct also has no doc explaining the precedence rule when both are present (server normally fills both with the same value). - **Category:** 19 (underspecified id), 12 (duplicate concept within one struct), 8 (redundant suffix). -- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#21). +- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#19). - **Rationale:** Caller cannot tell which to read without consulting the doc; autocomplete shows both at the same priority. -### 21. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1395,1419` -- **Why weird:** Same pattern as #20. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. -- **Category:** 19, 12, 8 (same as #20). -- **Suggested name:** Same as #20. -- **Rationale:** Same as #20. +### 19. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1372,1395` +- **Why weird:** Same pattern as #18. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. +- **Category:** 19, 12, 8 (same as #18). +- **Suggested name:** Same as #18. +- **Rationale:** Same as #18. -### 22. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1482-1503` +### 20. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1459-1480` - **Why weird:** Compare with the rest of the SDK: `GenieSpace` uses `title` for the human-readable name (other types use `name`/`displayName`). The struct has `spaceId`, `title`, `description`, `warehouseId`, `parentPath`, `serializedSpace`, `etag` — no `name`. JSDoc on `title` says "Title of the Genie Space" — but in the rest of the codebase, "title" is reserved for `GenieConversation.title` (the conversation subject line). Two different "titles" in the same package. - **Category:** 17 (inconsistency vs other types), 1 (vague — `title` doesn't distinguish from conversation title). - **Suggested name:** `displayName` or `name` (Space is a top-level entity; "title" is column-header style). - **Rationale:** Aligns with `DatabricksWorkspace.name`, `Dashboard.displayName`, etc. -### 23. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:950,1408,1437,1736,1758` +### 21. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:927,1385,1414,1715,1734` - **Why weird:** Five different concepts share the field name `content`. The reader cannot disambiguate from the field name alone. JSDocs differ: "User message content" / "Comment text content" / "AI generated message" / "The md formatted content for this thought" — i.e. they are all different formats. - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `body` for the message body, `text` for comments and thoughts, or qualify (`messageBody`, `commentText`, `thoughtMarkdown`). - **Rationale:** "Content" is a near-meaningless filler word; this is the kind of generic name the codebase rule (#15 of the audit categories) targets. -### 24. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:944` -- **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1401), `GenieMessageComment.userId` (line 1435), `GenieEvalResult.createdByUser` (line 1048), `GenieEvalRunResponse.runByUser` (line 1114). +### 22. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:921` +- **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1378), `GenieMessageComment.userId` (line 1412), `GenieEvalResult.createdByUser` (line 1025), `GenieEvalRunResponse.runByUser` (line 1091). - **Category:** 16 (field type contradicts domain), 14 (proto-int64 leaked to JS `number`). - **Suggested name:** Keep field name, change type to `string` (matches the rest of the SDK), or use `bigint`. Or `userId: string` with stronger JSDoc. - **Rationale:** Postgres-ID / long-id semantics are universal here. The `userId: number` typing is a generator bug that bites at runtime. -### 25. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:946,948,958,1116,1126,1402,1404,1439,1450` +### 23. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:923,925,935,1093,1103,1380,1382,1416,1427` - **Why weird:** 9 fields use `*Timestamp` suffix. The type is already `number` (a Unix-millis timestamp per JSDoc). The suffix duplicates the type. Some peer fields drop the suffix (`createdByUser` on `GenieEvalResult`, `runByUser` on `GenieEvalRunResponse`). - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `createdAt` / `updatedAt`. Or `createdAtMs` / `updatedAtMs` if the millis unit needs to be explicit. - **Rationale:** Industry-standard `createdAt`/`updatedAt` reads more naturally than `createdTimestamp`/`lastUpdatedTimestamp`. -### 26. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1404` +### 24. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1382` - **Why weird:** `lastUpdatedTimestamp` (5 syllables) is the package's "updated at" name. The `last` prefix adds nothing — by definition, an "updated at" timestamp is the *last* update. - **Category:** 7 (overly verbose). - **Suggested name:** `updatedAt` / `updatedTimestamp`. -- **Rationale:** Same as #25. +- **Rationale:** Same as #23. -### 27. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1452` -- **Why weird:** `id?: string` on `GenieQueryAttachment` is undocumented (no JSDoc). The parent `GenieAttachment` has `attachmentId` (line 932) — so the `id` here is presumably the same value or the query-attachment-specific id. Caller can't tell. +### 25. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1429` +- **Why weird:** `id?: string` on `GenieQueryAttachment` is undocumented (no JSDoc). The parent `GenieAttachment` has `attachmentId` (line 909) — so the `id` here is presumably the same value or the query-attachment-specific id. Caller can't tell. - **Category:** 19 (underspecified id), 1 (vague). - **Suggested name:** `attachmentId` (match the parent) or `queryAttachmentId` (qualify). - **Rationale:** Two near-identical ids on the same outer entity is one ambiguity too many. -### 28. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1737` -- **Why weird:** Same as #27 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. +### 26. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1716` +- **Why weird:** Same as #25 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. - **Category:** 19, 1. -- **Suggested name:** Same as #27. -- **Rationale:** Same as #27. +- **Suggested name:** Same as #25. +- **Rationale:** Same as #25. -### 29. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1108` +### 27. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` - **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). - **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). - **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. - **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. -### 30. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1168` +### 28. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` - **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. - **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). - **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. - **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. -### 31. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1157,1184` -- **Why weird:** Same as #30 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +### 29. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` +- **Why weird:** Same as #28 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). - **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). - **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. - **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. -### 32. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1172,1196` +### 30. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1149,1173` - **Why weird:** JSDoc says "JWT signature for the download_id". JWT is itself the full token (header.payload.signature). Calling it a "signature" understates what it is (the entire JWT that authorises the download). - **Category:** 6 (misleading — `Signature` is a sub-part of a JWT), 5 (cryptic). - **Suggested name:** `downloadToken` / `downloadJwt`. - **Rationale:** Caller expects a base64 signature to pair with `downloadId`; the value is actually a full bearer token. -### 33. `statementIdSignature` same pattern — `src/v1/model.ts:1618` -- **Why weird:** Same as #32: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. +### 31. `statementIdSignature` same pattern — `src/v1/model.ts:1597` +- **Why weird:** Same as #30: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. - **Category:** 6 (misleading), 5 (cryptic). - **Suggested name:** `statementToken` / `statementJwt`. -- **Rationale:** Same as #32. +- **Rationale:** Same as #30. -### 34. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1503,1552` +### 32. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1480,1529` - **Why weird:** HTTP `ETag` is the canonical capitalisation. The field is `etag: string`. Across the SDK other types use `etag` lowercase too — but it is an acronym (`Entity Tag`). - **Category:** 3 (acronym casing). - **Suggested name:** `eTag` (camelCase per TS style) or `etag` (current — chosen for consistency). - **Rationale:** Low priority; flag for awareness. -### 35. `Result` type name — too generic — `src/v1/model.ts:1610` +### 33. `Result` type name — too generic — `src/v1/model.ts:1589` - **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. - **Category:** 1 (vague/generic). - **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. - **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. -### 36. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1616,1677` +### 34. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1595,1656` - **Why weird:** Both fields are booleans indicating truncation. `Result.isTruncated` uses the `is*` prefix convention; `ResultManifest.truncated` is bare. Same struct file, two conventions. - **Category:** 17 (inconsistency). - **Suggested name:** Pick one form (`truncated` everywhere) and apply. - **Rationale:** Pure consistency win; no semantic change. -### 37. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1465` +### 35. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1442` - **Why weird:** A third truncation field on `GenieResultMetadata.isTruncated`. Three independent fields tracking the same concept across `Result`, `ResultManifest`, `GenieResultMetadata`. - **Category:** 17 (inconsistency), 12 (duplicate concept). -- **Suggested name:** Same as #36. -- **Rationale:** Same as #36. +- **Suggested name:** Same as #34. +- **Rationale:** Same as #34. -### 38. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1461` +### 36. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1438` - **Why weird:** A type whose two fields (`rowCount`, `isTruncated`) are both already on `ResultManifest`. JSDoc says "Metadata associated with the query result", but `ResultManifest` is also "result manifest" metadata. - **Category:** 12 (duplicate concept). - **Suggested name:** Replace with `ResultManifest` (or a sub-projection of it); delete `GenieResultMetadata`. - **Rationale:** Two structs covering the same semantic territory cause readers to wonder which one is authoritative. -### 39. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1605` +### 37. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1584` - **Why weird:** `keyword` is a vague word for what is presumably the parameter name. No JSDoc. The companion field `value` carries the bound value; `sqlType` carries the type. A parameter is `(name, value, type)` — why is `name` called `keyword`? - **Category:** 1 (vague), 6 (misleading — `keyword` evokes SQL reserved words). - **Suggested name:** `name` (with JSDoc) or `parameterName`. - **Rationale:** Reader sees `keyword` and looks for a SQL keyword list. -### 40. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1606` +### 38. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1585` - **Why weird:** No JSDoc on `value`. Type is `string`. For SQL parameters this could be a literal value, an expression, a placeholder, a JSON-encoded scalar, etc. Companion `sqlType?: string` (also no JSDoc) presumably qualifies it. - **Category:** 1 (vague), 16 (field type may contradict domain). - **Suggested name:** Document. Optionally `stringValue` / `valueText` to make the encoding explicit. - **Rationale:** Public SDK types should not require source-diving. -### 41. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:925` +### 39. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:903` - **Why weird:** Discriminator value is `'suggestedQuestions'` and the payload type is `GenieSuggestedQuestionsAttachment`. The word `Attachment` is in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** Variant `'followUps'`, payload `SuggestedQuestions { questions: string[] }`. @@ -265,158 +253,138 @@ ## Low severity -### 42. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1525` +### 40. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1502` - **Why weird:** Bare `string[]`. Doc says "The suggested follow-up questions". The questions are also typed elsewhere as a free-text input (`content` on a `GenieCreateConversationMessageRequest`) — so the type tells you nothing about the format. - **Category:** 1 (vague — questions could be markdown, plain, etc.). - **Suggested name:** `followUpQuestions: string[]` (clearer; matches the JSDoc). - **Rationale:** Field name disambiguation. -### 43. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1578` +### 41. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1557` - **Why weird:** `MessageError.error: string`. Reader sees `someError.error` (two `error`s). Some other fields are similarly self-referential (`Result.statementId`, OK because `Result` is generic; here `MessageError.error` is *the error message*). - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `MessageError.message: string` (matches the JSON shape) or `MessageError.detail`. - **Rationale:** Wire format on the server may already be `error_message`; check before renaming. -### 44. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1579` +### 42. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1558` - **Why weird:** Field name `type` is a JS reserved-word-adjacent (TS allows it, but `type` collides with the `type` keyword used in TS type aliases — refactoring tools sometimes choke). - **Category:** 10 (reserved-word collision), 1 (vague). - **Suggested name:** `errorType` / `category` / `kind`. - **Rationale:** Common collision; small ergonomics win. -### 45. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1756` +### 43. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1732` - **Why weird:** `Thought.thoughtType` repeats "thought" twice. Could just be `Thought.type`. - **Category:** 8 (redundant suffix), 7 (overly verbose). - **Suggested name:** `Thought.type` (and rename `ThoughtType` → `Thought.Kind` namespace). - **Rationale:** Reduces redundancy. -### 46. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:932` -- **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1737) and `GenieQueryAttachment.id` (line 1452) inside variants. Three different id fields for the same logical entity (the attachment). +### 44. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:909` +- **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1714) and `GenieQueryAttachment.id` (line 1429) inside variants. Three different id fields for the same logical entity (the attachment). - **Category:** 19 (underspecified id), 12 (duplicate concept). - **Suggested name:** Single `id` on `GenieAttachment`, remove inner ids. -- **Rationale:** See #27, #28, #46 together. +- **Rationale:** See #25, #26, #44 together. -### 47. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1262` +### 45. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1239` - **Why weird:** Boolean toggle that expands the response. Permission check is documented ("Requires at least CAN EDIT permission"). Boolean naming style varies across SDK: `enableX`, `includeX`, `withX`. Could be `withSerializedSpace` or `includeSerialized` (the parent struct is already a Space). - **Category:** 7 (overly verbose). - **Suggested name:** `withSerialized` / `expandSerialized`. - **Rationale:** The struct context already says "Space"; the prefix is redundant. -### 48. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` +### 46. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` - **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). - **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. - **Rationale:** Class names should be noun phrases; current name reads as a verb. -### 49. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:961, client.ts:160` +### 47. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:160` - **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. - **Category:** 7 (overly verbose). - **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. - **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. -### 50. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1278` +### 48. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1255` - **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. - **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). - **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. - **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. -### 51. `Format` enum has 4 values; only sentinel is prefixed — `src/v1/model.ts:546-551` -- **Why weird:** `FORMAT_UNSPECIFIED` then `JSON_ARRAY`, `ARROW_STREAM`, `CSV`. Same inconsistent-prefix pattern as #14 / #15. -- **Category:** 17, 2. -- **Suggested name:** `Format.Unspecified | JsonArray | ArrowStream | Csv`. -- **Rationale:** Same as #10. - -### 52. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:549` +### 49. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:546` - **Why weird:** Value `ARROW_STREAM` casing. The product name is `Apache Arrow` — `Arrow` is title-case in TS naming. As an enum value `ARROW_STREAM` is conventional (SCREAMING_SNAKE) but mixed with `JSON_ARRAY` and `CSV` where one is fully-cap acronym and one is mixed. - **Category:** 3 (acronym casing), 17 (mixed conventions within the enum). - **Suggested name:** `ArrowStream` (in a Pascal-case enum). - **Rationale:** Low priority — enum-value style is widely-debated. -### 53. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1415` -- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #35). +### 50. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1392` +- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #33). - **Category:** 12 (duplicate concept — kept-for-compat), 1 (vague — `Result`). - **Suggested name:** Mark with `/** @deprecated */` JSDoc (current text just says "Deprecated" — TS tooling won't strike-through). - **Rationale:** Tooling support — modern TS understands `@deprecated`. -### 54. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +### 51. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. - **Rationale:** Cleanup; clients should migrate to the canonical name. -### 55. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1048` -- **Why weird:** Field is named `createdByUser` rather than `createdBy`. `By User` is redundant: a `createdBy` field is by-its-nature-by-a-user (or by a service principal). Compare `GenieEvalRunResponse.runByUser` (same pattern, line 1114). +### 52. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1025` +- **Why weird:** Field is named `createdByUser` rather than `createdBy`. `By User` is redundant: a `createdBy` field is by-its-nature-by-a-user (or by a service principal). Compare `GenieEvalRunResponse.runByUser` (same pattern, line 1091). - **Category:** 7 (overly verbose), 17 (inconsistent vs other types in the SDK using `createdBy`). - **Suggested name:** `createdBy` (matches the rest of the SDK). - **Rationale:** Aligns with `databricks-sdk-go` conventions and most peer types. -### 56. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1114` -- **Why weird:** Same as #55. +### 53. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1091` +- **Why weird:** Same as #52. - **Category:** 7, 17. - **Suggested name:** `runBy` / `runByUserId`. -- **Rationale:** Same as #55. +- **Rationale:** Same as #52. -### 57. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1046,1103,1105` +### 54. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1023,1080,1082` - **Why weird:** `GenieEvalResult` stores the original "benchmark answer" as a flat string; `GenieEvalResultDetails` returns the actual/expected as arrays of `GenieEvalResponse`. Three different words for "the right answer" / "Genie's answer" / "the expected answer". - **Category:** 17 (inconsistent word choice), 1 (vague — `answer` vs `response`). - **Suggested name:** Pick one verb. E.g., `expectedAnswer` / `actualAnswer` (or `expectedResponse` / `actualResponse` for both types). - **Rationale:** Reader has to relearn the vocabulary in each type. -### 58. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1060` -- **Why weird:** A `GenieEvalResultDetails` describes a single result inside a run. The field `evalRunStatus` describes the *run's* status, not the result's status. The plain `status` field appears on `GenieEvalResult` (line 1042) but is gone here — replaced by `evalRunStatus`. So the same enum (`EvaluationStatusType`) is exposed under two different field names. +### 55. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1037` +- **Why weird:** A `GenieEvalResultDetails` describes a single result inside a run. The field `evalRunStatus` describes the *run's* status, not the result's status. The plain `status` field appears on `GenieEvalResult` (line 1019) but is gone here — replaced by `evalRunStatus`. So the same enum (`EvaluationStatusType`) is exposed under two different field names. - **Category:** 17 (inconsistent field naming for the same concept), 6 (misleading — `evalRunStatus` on a result-details type confuses run-status with result-status). - **Suggested name:** `runStatus` (with the run context clear from the parent type's purpose). - **Rationale:** Same status enum, two field names is jarring. -### 59. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1064` +### 56. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1041` - **Why weird:** Two adjacent fields: `assessment: GenieEvalAssessment` and `manualAssessment: boolean`. The second is a flag indicating whether the first was set manually. The naming implies that `manualAssessment` is itself an assessment. - **Category:** 6 (misleading — `manualAssessment` looks like "the manual assessment value"), 1 (vague). - **Suggested name:** `assessmentIsManual` / `isManuallyAssessed`. - **Rationale:** Boolean-prefix convention disambiguates. -### 60. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1312` +### 57. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1289` - **Why weird:** `includeAll: boolean`. JSDoc clarifies "Include all conversations in the space across all users". `All` is unqualified; could mean "include archived", "include all spaces", "include all messages". - **Category:** 1 (vague), 6 (misleading without docs). - **Suggested name:** `includeAllUsers` / `acrossUsers` / `allUsers`. - **Rationale:** Boolean toggles need to be unambiguous from the name. -### 61. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — `type` prefix repeated — `src/v1/model.ts:807-818` -- **Why weird:** Six fields all prefixed `type*`. Hoisting into a sub-struct `type: { text, name, precision, scale, intervalType, json }` would be cleaner. Generator-faithful flat shape duplicates the prefix. -- **Category:** 7 (overly verbose), 8 (redundant prefix). -- **Suggested name:** Sub-struct, or trim the prefix. -- **Rationale:** Aesthetic; matches the protobuf shape. - -### 62. `ColumnInfo.typeIntervalType` — `type` doubled — `src/v1/model.ts:816` -- **Why weird:** `typeIntervalType` doubles the word "type". Doc: "Format of IntervalType." -- **Category:** 7 (overly verbose). -- **Suggested name:** `intervalFormat` (in a sub-struct) or `intervalType`. -- **Rationale:** Trim the doubled word. - -### 63. `Schema` type name — too generic — `src/v1/model.ts:1680` -- **Why weird:** `Schema` is one of the most-overloaded names in the SDK (Unity Catalog Schema, SQL schema, JSON schema, Avro schema, etc.). This `Schema` is a SQL result schema (`columnCount`, `columns`). -- **Category:** 1 (vague/generic), 12 (collides with UC `Schema`). -- **Suggested name:** `ResultSchema`. -- **Rationale:** Collision with UC `Schema` will bite consumers who import from both. - -### 64. `Struct` type name — too generic, copied from proto wkt — `src/v1/model.ts:1729` -- **Why weird:** `Struct` is the proto Well-Known Type `Struct` (an arbitrary JSON-object value). Calling this `Struct` clashes with TS's natural use of "struct" for any object. -- **Category:** 1 (vague/generic), 12 (proto wkt copy). -- **Suggested name:** Use `Record` directly, or call it `JsonObject` / `ProtoStruct`. -- **Rationale:** WKT types leaking through the public API surface should be unwrapped. - ## Observations -### 65. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #47 -- **Observation:** Listed under #47. Documenting here for cross-reference. +### 58. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #45 +- **Observation:** Listed under #45. Documenting here for cross-reference. -### 66. `pageSize` / `pageToken` casing — `src/v1/model.ts:1271,1273,1289,1291,...` +### 59. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` - **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. - **Suggested name:** N/A. - **Rationale:** Confirms the package's pagination naming is consistent. -### 67. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1771` +### 60. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` - **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. - **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. - **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. -### 68. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,1000,1004,1008` +### 61. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,999,1008` - **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. + +### 62. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` +- **Observation:** `export interface MessageStatus {}` is an empty placeholder. The actual status enum is `MessageStatus_MessageStatus`. The empty type adds noise to the surface. +- **Suggested name:** Remove the empty interface; refer to the enum directly. +- **Rationale:** Empty interfaces in TS satisfy any object type and become bug magnets. + +## Fixed + +- #11 `RESPONSE_PHASE_*` prefix repeated on every value (originally cited at `src/v1/model.ts:588-590`): Fixed in regeneration on 2026-05-20 — `ResponsePhase` enum no longer exists in `model.ts`. +- #13 `VERIFICATION_SECTION_*` prefix repeated and one value has the prefix doubled (originally cited at `src/v1/model.ts:660-666`): Fixed in regeneration on 2026-05-20 — `VerificationSection` enum no longer exists in `model.ts`. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index 100a50bd..ecac82b0 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -13,7 +13,7 @@ creation and returns it everywhere else. Five operations: `create/get/list/update/delete`. No enums, no discriminated unions, no pagination, no list filtering beyond an optional `principalId` query parameter, no version negotiation. -**Total weird names flagged:** 17 +**Total weird names flagged:** 21 --- @@ -23,11 +23,11 @@ parameter, no version negotiation. |---|------|------|------|----------|----------|-------------------| | 1 | package `gitcredentials` / module `@databricks/sdk-gitcredentials` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 12 Duplicate concepts | Lowercased compound noun runs `git` and `credentials` together with no separator. The npm registry has packages literally called `git-credentials`/`@gitcredentials` (different ecosystem). Also collides conceptually with `@databricks/sdk-credentials` (Unity Catalog cloud-storage credentials) and `@databricks/sdk-auth/credentials` (SDK auth credentials). Three packages with "Credentials" in the name, three different meanings. | | 2 | `Credential` (interface) | model.ts:68 | interface | High | 1 Vague/generic, 12 Duplicate concepts | Bare `Credential` clashes with `@databricks/sdk-credentials`'s `Credential` (UC credentials) and with the auth package's `Credentials` interface. None of them say "Git" or "auth" or "UC" on the type name. Should be `GitCredential`. | -| 3 | `Credential` vs `CreateCredentials_Response` vs `GetCredentials_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. The two response types should be type aliases of `Credential`, or `Credential` should be the response type directly. | -| 4 | `CreateCredentials` vs `UpdateCredentials` (request envelopes) | model.ts:5, 152 | interface pair | High | 12 Duplicate concepts | The two request envelopes differ by exactly one field: `UpdateCredentials` adds `id` (path parameter). Otherwise field-for-field identical: `gitProvider`, `gitUsername`, `personalAccessToken`, `principalId`, `name`, `isDefaultForProvider`, `gitEmail`. The JSDoc text on every shared field is duplicated verbatim across both. Should share a base type (`GitCredentialMutation`) and only differ on the path key. | -| 5 | `CreateCredentials` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredential`. (Compare `Credential` itself — the resource singular is already chosen.) | -| 6 | `UpdateCredentials`, `DeleteCredentials`, `GetCredentials` named with plural | model.ts:152, 98, 108 | interface set | High | 9 Singular/plural mismatches | Same as #5 — three more cases. `UpdateCredentials` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentials` deletes one. `GetCredentials` gets one. All three should be singular. | -| 7 | `ListCredentials_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | +| 3 | `Credential` vs `CreateCredentialsRequest_Response` vs `GetCredentialsRequest_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. The two response types should be type aliases of `Credential`, or `Credential` should be the response type directly. | +| 4 | `CreateCredentialsRequest` vs `UpdateCredentialsRequest` (request envelopes) | model.ts:5, 152 | interface pair | High | 12 Duplicate concepts | The two request envelopes differ by exactly one field: `UpdateCredentialsRequest` adds `id` (path parameter). Otherwise field-for-field identical: `gitProvider`, `gitUsername`, `personalAccessToken`, `principalId`, `name`, `isDefaultForProvider`, `gitEmail`. The JSDoc text on every shared field is duplicated verbatim across both. Should share a base type (`GitCredentialMutation`) and only differ on the path key. | +| 5 | `CreateCredentialsRequest` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredentialRequest`. (Compare `Credential` itself — the resource singular is already chosen.) | +| 6 | `UpdateCredentialsRequest`, `DeleteCredentialsRequest`, `GetCredentialsRequest` named with plural | model.ts:152, 98, 108 | interface set | High | 9 Singular/plural mismatches | Same as #5 — three more cases. `UpdateCredentialsRequest` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentialsRequest` deletes one. `GetCredentialsRequest` gets one. All three should be singular. | +| 7 | `ListCredentialsRequest_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | | 8 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | | 9 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | | 10 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | @@ -35,12 +35,13 @@ parameter, no version negotiation. | 12 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | | 13 | `gitUsername`, `gitEmail`, `gitProvider` prefixed with `git` | model.ts:20, 39, 13, 54, 65, 84, 95, 127, 138, 175, 188 | field set | Medium | 1 Vague/generic, 6 Misleading names | The package is *gitcredentials*; every field already lives under the package namespace. Re-prefixing each field with `git` is stuttering. `req.gitProvider`, `req.gitUsername`, `req.gitEmail` could be `req.provider`, `req.username`, `req.email`. The wire format requires the `git_` prefix on the JSON keys (see the zod schemas), but the TS field can be renamed in the zod `transform`. | | 14 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | -| 15 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 104, 135, 166, 197 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | -| 16 | `DeleteCredentials.id` and `GetCredentials.id` and `UpdateCredentials.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | +| 15 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 141, 175, 209, 107 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 16 | `DeleteCredentialsRequest.id` and `GetCredentialsRequest.id` and `UpdateCredentialsRequest.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | | 17 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | | 18 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | | 19 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | | 20 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | +| 21 | `*Request_Response` underscore-nested response types (5 of them) | model.ts:43, 106, 116, 147, 192 | interface set | High | Proto-architectural-leak | All five response types use the proto-style `ParentRequest_Response` underscore-nested form: `CreateCredentialsRequest_Response`, `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. The underscore is a protobuf-nested-message encoding bleeding into the public TS API — the generator even acknowledges it with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` above every one. The matching zod schema constants (`unmarshalCreateCredentialsRequest_ResponseSchema`, etc.) inherit the same underscore. | --- @@ -74,8 +75,8 @@ unrelated packages with the literal name `git-credentials` and ### H2. Plural request-type names Four request envelopes act on a single resource but use the plural noun: -`CreateCredentials`, `GetCredentials`, `UpdateCredentials`, -`DeleteCredentials`. Plus five client methods of the same name (`createCredentials`, +`CreateCredentialsRequest`, `GetCredentialsRequest`, `UpdateCredentialsRequest`, +`DeleteCredentialsRequest`. Plus five client methods of the same name (`createCredentials`, etc.). The result is that the API reads like a bulk-create surface ("call `createCredentials` with five credentials") when it is actually a one-at-a-time API. @@ -94,7 +95,7 @@ singular. See #5, #6, #15. ### H3. Three field-for-field-identical "Credential" shapes -`Credential`, `CreateCredentials_Response`, and `GetCredentials_Response` +`Credential`, `CreateCredentialsRequest_Response`, and `GetCredentialsRequest_Response` all have the same six fields with the same types, the same optionality, and the same JSDoc text. Two of the three are redundant. @@ -102,9 +103,9 @@ Recommendation: ```ts // Before -export interface CreateCredentials_Response { /* 6 fields */ } -export interface GetCredentials_Response { /* same 6 fields */ } -export interface Credential { /* same 6 fields */ } +export interface CreateCredentialsRequest_Response { /* 6 fields */ } +export interface GetCredentialsRequest_Response { /* same 6 fields */ } +export interface Credential { /* same 6 fields */ } // After export interface GitCredential { /* 6 fields */ } @@ -116,17 +117,17 @@ export interface GitCredential { /* 6 fields */ } Requests use `id`: ```ts -interface DeleteCredentials { id?: number; principalId?: number; } -interface GetCredentials { id?: number; principalId?: number; } -interface UpdateCredentials { id?: number; /* ... */ } +interface DeleteCredentialsRequest { id?: number; principalId?: number; } +interface GetCredentialsRequest { id?: number; principalId?: number; } +interface UpdateCredentialsRequest { id?: number; /* ... */ } ``` Responses use `credentialId`: ```ts -interface Credential { credentialId?: number; /* ... */ } -interface CreateCredentials_Response { credentialId?: number; /* ... */ } -interface GetCredentials_Response { credentialId?: number; /* ... */ } +interface Credential { credentialId?: number; /* ... */ } +interface CreateCredentialsRequest_Response { credentialId?: number; /* ... */ } +interface GetCredentialsRequest_Response { credentialId?: number; /* ... */ } ``` So callers write `req.id = resp.credentialId` and constantly translate @@ -168,6 +169,39 @@ import {Client as GitCredentialsClient} from '@databricks/sdk-gitcredentials/v1' `GitCredentialsClient` directly (matching the package noun). This is a pattern-wide issue and was flagged in every audit so far. +### H7. `*Request_Response` underscore-nested response types — `model.ts:43, 106, 116, 147, 192` + +- **Why:** All five response types are emitted as proto-style nested + messages joined by a literal underscore — `CreateCredentialsRequest_Response`, + `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, + `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. + The underscore-joined `ParentRequest_Response` form is the + protobuf/Go-SDK convention for flattening a nested-message namespace + (`message CreateCredentialsRequest { message Response { ... } }`) into a + single identifier. TS has native namespaces and modules, so the + underscore is a wire-protocol artifact bleeding into the public TS + surface. The generator already labels every one of them + "Proto-style nested message name" via an `eslint-disable-next-line` + comment, which is an explicit confession that the form is non-idiomatic. + The matching zod schemas (`unmarshalCreateCredentialsRequest_ResponseSchema`, + etc.) inherit the same underscore at `model.ts:195, 233, 237, 257, 267`, + and every import site in `client.ts:22-30, 35-39, 81, 84, 96, 110, 118, + 130, 144, 152, 164, 178, 186, 198, 212, 215, 227` carries it forward. +- **Category:** Proto-architectural leak (proto-style nested-message + encoding leaking into TS identifiers). +- **Suggested name:** Drop the underscore and the `Request_` prefix. + `CreateCredentialResponse`, `DeleteCredentialResponse`, + `GetCredentialResponse`, `ListCredentialsResponse`, + `UpdateCredentialResponse`. Even better, collapse all three + identical-shape response types into `GitCredential` directly (see H3) so + three of the five disappear entirely. +- **Rationale:** TS consumers should never have to learn that a response + type is "nested inside" its request message — that nesting is a proto + detail the wire never sees (the JSON body has no `Request_Response` + envelope; it just has the response fields directly). The underscore is + the single clearest piece of evidence that the generator is emitting Go + shapes verbatim rather than rendering an idiomatic TS surface. + --- ## Medium severity (worth pushing back on) @@ -236,11 +270,11 @@ concept toggles plural/singular at almost every boundary: | Where | Spelling | |---|---| | Resource type | `Credential` | -| Create-request type | `CreateCredentials` | -| Get-request type | `GetCredentials` (gets one) | -| Update-request type | `UpdateCredentials` (updates one) | -| Delete-request type | `DeleteCredentials` (deletes one) | -| List-request type | `ListCredentials` (lists many) | +| Create-request type | `CreateCredentialsRequest` | +| Get-request type | `GetCredentialsRequest` (gets one) | +| Update-request type | `UpdateCredentialsRequest` (updates one) | +| Delete-request type | `DeleteCredentialsRequest` (deletes one) | +| List-request type | `ListCredentialsRequest` (lists many) | | Wire endpoint | `/api/2.0/git-credentials` (plural collection) | Pick a rule. Conventional CRUD: plural for collection ops (`listCredentials`, @@ -276,7 +310,7 @@ them for awareness — fixing requires an API-server change. |---|---| | Total exported interfaces | 10 | | Plural request envelopes for single-resource ops | 4 | -| Identical-shape interface trios | 1 (`Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | +| Identical-shape interface trios | 1 (`Credential` ≡ `CreateCredentialsRequest_Response` ≡ `GetCredentialsRequest_Response`) | | Enums | 0 (despite an 8-value closed set on `gitProvider`) | ### Comparison to other audits diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index 397c757b..315325cb 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -28,54 +28,54 @@ None. This package defines no enums. ### 1.2 Interfaces (`model.ts`) -| Name | Purpose | -| ------------------------------------- | --------------------------------------------- | -| `CreateGlobalInitScript` | Request body for create. | -| `CreateGlobalInitScript_Response` | Response from create. | -| `DeleteGlobalInitScript` | Request body (path param wrapper) for delete. | -| `DeleteGlobalInitScript_Response` | Empty response from delete. | -| `GetGlobalInitScript` | Request body (path param wrapper) for get. | -| `GlobalInitScriptDetails` | Entity describing a global init script. | -| `ListGlobalInitScripts` | Empty request body for list. | -| `ListGlobalInitScripts_Response` | Response from list. | -| `UpdateGlobalInitScript` | Request body for update. | -| `UpdateGlobalInitScript_Response` | Empty response from update. | +| Name | Purpose | +| -------------------------------------------- | --------------------------------------------- | +| `CreateGlobalInitScriptRequest` | Request body for create. | +| `CreateGlobalInitScriptRequest_Response` | Response from create. | +| `DeleteGlobalInitScriptRequest` | Request body (path param wrapper) for delete. | +| `DeleteGlobalInitScriptRequest_Response` | Empty response from delete. | +| `GetGlobalInitScriptRequest` | Request body (path param wrapper) for get. | +| `GlobalInitScriptDetails` | Entity describing a global init script. | +| `ListGlobalInitScriptsRequest` | Empty request body for list. | +| `ListGlobalInitScriptsRequest_Response` | Response from list. | +| `UpdateGlobalInitScriptRequest` | Request body for update. | +| `UpdateGlobalInitScriptRequest_Response` | Empty response from update. | ### 1.3 Fields (entity / request / response — combined catalog) -| Type | Field | Type / Notes | -| --------------------------------- | ------------ | ----------------------------------------- | -| `CreateGlobalInitScript` | `name` | `string?` — script display name. | -| `CreateGlobalInitScript` | `script` | `Uint8Array?` — Base64-encoded content. | -| `CreateGlobalInitScript` | `position` | `number?` — execution order index. | -| `CreateGlobalInitScript` | `enabled` | `boolean?` | -| `CreateGlobalInitScript_Response` | `scriptId` | `string?` | -| `DeleteGlobalInitScript` | `scriptId` | `string?` — path parameter. | -| `GetGlobalInitScript` | `scriptId` | `string?` — path parameter. | -| `GlobalInitScriptDetails` | `scriptId` | `string?` | -| `GlobalInitScriptDetails` | `name` | `string?` | -| `GlobalInitScriptDetails` | `position` | `number?` | -| `GlobalInitScriptDetails` | `enabled` | `boolean?` | -| `GlobalInitScriptDetails` | `createdBy` | `string?` — username. | -| `GlobalInitScriptDetails` | `createdAt` | `number?` — Unix timestamp in ms. | -| `GlobalInitScriptDetails` | `updatedBy` | `string?` — username. | -| `GlobalInitScriptDetails` | `updatedAt` | `number?` — Unix timestamp in ms. | -| `ListGlobalInitScripts_Response` | `scripts` | `GlobalInitScriptDetails[]?` | -| `UpdateGlobalInitScript` | `scriptId` | `string?` — path parameter. | -| `UpdateGlobalInitScript` | `name` | `string?` | -| `UpdateGlobalInitScript` | `script` | `Uint8Array?` — Base64-encoded content. | -| `UpdateGlobalInitScript` | `position` | `number?` | -| `UpdateGlobalInitScript` | `enabled` | `boolean?` | +| Type | Field | Type / Notes | +| ---------------------------------------- | ------------ | ----------------------------------------- | +| `CreateGlobalInitScriptRequest` | `name` | `string?` — script display name. | +| `CreateGlobalInitScriptRequest` | `script` | `Uint8Array?` — Base64-encoded content. | +| `CreateGlobalInitScriptRequest` | `position` | `number?` — execution order index. | +| `CreateGlobalInitScriptRequest` | `enabled` | `boolean?` | +| `CreateGlobalInitScriptRequest_Response` | `scriptId` | `string?` | +| `DeleteGlobalInitScriptRequest` | `scriptId` | `string?` — path parameter. | +| `GetGlobalInitScriptRequest` | `scriptId` | `string?` — path parameter. | +| `GlobalInitScriptDetails` | `scriptId` | `string?` | +| `GlobalInitScriptDetails` | `name` | `string?` | +| `GlobalInitScriptDetails` | `position` | `number?` | +| `GlobalInitScriptDetails` | `enabled` | `boolean?` | +| `GlobalInitScriptDetails` | `createdBy` | `string?` — username. | +| `GlobalInitScriptDetails` | `createdAt` | `number?` — Unix timestamp in ms. | +| `GlobalInitScriptDetails` | `updatedBy` | `string?` — username. | +| `GlobalInitScriptDetails` | `updatedAt` | `number?` — Unix timestamp in ms. | +| `ListGlobalInitScriptsRequest_Response` | `scripts` | `GlobalInitScriptDetails[]?` | +| `UpdateGlobalInitScriptRequest` | `scriptId` | `string?` — path parameter. | +| `UpdateGlobalInitScriptRequest` | `name` | `string?` | +| `UpdateGlobalInitScriptRequest` | `script` | `Uint8Array?` — Base64-encoded content. | +| `UpdateGlobalInitScriptRequest` | `position` | `number?` | +| `UpdateGlobalInitScriptRequest` | `enabled` | `boolean?` | ### 1.4 Methods (`client.ts`) -| Method | HTTP | Returns | -| ------------------------- | ------ | ------------------------------------ | -| `createGlobalInitScript` | POST | `CreateGlobalInitScript_Response` | -| `deleteGlobalInitScript` | DELETE | `DeleteGlobalInitScript_Response` | -| `getGlobalInitScript` | GET | `GlobalInitScriptDetails` | -| `listGlobalInitScripts` | GET | `ListGlobalInitScripts_Response` | -| `updateGlobalInitScript` | PATCH | `UpdateGlobalInitScript_Response` | +| Method | HTTP | Returns | +| ------------------------- | ------ | ------------------------------------------- | +| `createGlobalInitScript` | POST | `CreateGlobalInitScriptRequest_Response` | +| `deleteGlobalInitScript` | DELETE | `DeleteGlobalInitScriptRequest_Response` | +| `getGlobalInitScript` | GET | `GlobalInitScriptDetails` | +| `listGlobalInitScripts` | GET | `ListGlobalInitScriptsRequest_Response` | +| `updateGlobalInitScript` | PATCH | `UpdateGlobalInitScriptRequest_Response` | ### 1.5 Other identifiers @@ -93,9 +93,9 @@ None. This package defines no enums. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| V-01 | `CreateGlobalInitScript.script` / `UpdateGlobalInitScript.script` | High | The field name `script` is overloaded inside a type whose entity name is already "script". A `CreateGlobalInitScript` whose payload field is `script` reads as "the script of the script". Worse, the JSDoc says it carries "Base64-encoded content". A name like `content`, `body`, or `scriptContent` would convey what the bytes actually are. | -| V-02 | `GlobalInitScriptDetails.position` | Medium | `position` is generic. Without the JSDoc the reader cannot tell whether it is an array index, a UI ordering hint, a priority, or an execution-order rank. `executionOrder`, `runOrder`, or `priority` would be more self-describing. | -| V-03 | `GlobalInitScriptDetails.name` | Low | Generic but standard across the SDK; acceptable in entity context. | +| V-01 | `CreateGlobalInitScriptRequest.script` / `UpdateGlobalInitScriptRequest.script` (`model.ts:9`, `model.ts:74`) | High | The field name `script` is overloaded inside a type whose entity name is already "script". A `CreateGlobalInitScriptRequest` whose payload field is `script` reads as "the script of the script". Worse, the JSDoc says it carries "Base64-encoded content". A name like `content`, `body`, or `scriptContent` would convey what the bytes actually are. | +| V-02 | `GlobalInitScriptDetails.position` (`model.ts:47`) | Medium | `position` is generic. Without the JSDoc the reader cannot tell whether it is an array index, a UI ordering hint, a priority, or an execution-order rank. `executionOrder`, `runOrder`, or `priority` would be more self-describing. | +| V-03 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Generic but standard across the SDK; acceptable in entity context. | ### 2.2 Redundant enum prefixes — None @@ -107,7 +107,7 @@ No enums are declared in this package; this rubric category does not apply. | ----- | --------------------- | -------- | ----- | | A-01 | `HttpClient`, `httpClient` (imported from core) | Low | Google TS style uses `Http` (initial-only capitalisation for acronyms > 2 chars — https://google.github.io/styleguide/tsguide.html#identifiers). Consistent. | | A-02 | `Uint8Array` | Low | Standard Web/TC39 typed-array name; OK. | -| A-03 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScript.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | +| A-03 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScriptRequest.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | ### 2.4 Underscores in TS identifiers — Low @@ -121,29 +121,29 @@ No enums are declared in this package; this rubric category does not apply. | ----- | ----------------------- | -------- | ----- | | C-01 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`) | Low | Short-lived local identifiers; OK for short scope but `request` / `response` would be clearer at no cost. | | C-02 | `opts` (`utils.ts` parameter) | Low | Inside fn scope; minor. | -| C-03 | `pkgJson` (`client.ts`) | Low | Abbreviation of "packageJson". Local import alias; OK. | +| C-03 | `pkgJson` (`client.ts:19`) | Low | Abbreviation of "packageJson". Local import alias; OK. | ### 2.6 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| M-01 | `CreateGlobalInitScript.script` (field type `Uint8Array`) | High | The field is documented as "Base64-encoded content" but its TS type is `Uint8Array` — the marshal schema converts the bytes to Base64 via `btoa`. Callers therefore supply **raw bytes**, not Base64. The JSDoc is misleading: it describes the wire format, not what the caller hands in. A better split would be either rename to `scriptBytes` (matching the runtime type) or change the doc to "Raw bytes; the SDK Base64-encodes before sending." | -| M-02 | `UpdateGlobalInitScript.script` | High | Same as M-01. | -| M-03 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | +| M-01 | `CreateGlobalInitScriptRequest.script` (field type `Uint8Array`, `model.ts:9`) | High | The field is documented as "Base64-encoded content" but its TS type is `Uint8Array` — the marshal schema converts the bytes to Base64 via `btoa`. Callers therefore supply **raw bytes**, not Base64. The JSDoc is misleading: it describes the wire format, not what the caller hands in. A better split would be either rename to `scriptBytes` (matching the runtime type) or change the doc to "Raw bytes; the SDK Base64-encodes before sending." | +| M-02 | `UpdateGlobalInitScriptRequest.script` (`model.ts:74`) | High | Same as M-01. | +| M-03 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`, `client.ts:133`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | ### 2.7 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------------------- | -------- | ----- | -| O-01 | `CreateGlobalInitScript` / `DeleteGlobalInitScript` / `GetGlobalInitScript` / `UpdateGlobalInitScript` / `ListGlobalInitScripts` | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full, producing ~22-25-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `Create`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | -| O-02 | `GlobalInitScriptDetails` (entity name) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | +| O-01 | `CreateGlobalInitScriptRequest` / `DeleteGlobalInitScriptRequest` / `GetGlobalInitScriptRequest` / `UpdateGlobalInitScriptRequest` / `ListGlobalInitScriptsRequest` (`model.ts:5`, `28`, `36`, `61`, `68`) | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full plus the `Request` suffix, producing ~28-32-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `CreateRequest`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | +| O-02 | `GlobalInitScriptDetails` (entity name, `model.ts:41`) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | ### 2.8 Singular / plural mismatches — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| P-01 | `ListGlobalInitScripts` (request, plural) vs `listGlobalInitScripts()` (method, plural) | Low | Consistent. | -| P-02 | `ListGlobalInitScripts_Response.scripts` | Low | Plural field for array — correct. | +| P-01 | `ListGlobalInitScriptsRequest` (request, plural) vs `listGlobalInitScripts()` (method, plural) | Low | Consistent. | +| P-02 | `ListGlobalInitScriptsRequest_Response.scripts` | Low | Plural field for array — correct. | | P-03 | `GlobalInitScriptDetails` (singular entity) vs `getGlobalInitScript()` (singular get) | Low | Consistent. | | P-04 | `createGlobalInitScript`, `deleteGlobalInitScript`, `updateGlobalInitScript` | Low | Singular for per-resource ops — correct. | @@ -161,8 +161,8 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| D-01 | `CreateGlobalInitScript` vs `UpdateGlobalInitScript` | Medium | Update adds only one field (`scriptId`); otherwise identical to create. Two near-duplicate 4-field interfaces. Codegen constraint, but readers see them side by side. | -| D-02 | `GlobalInitScriptDetails` vs `CreateGlobalInitScript` / `UpdateGlobalInitScript` | Medium | Same `name`, `position`, `enabled` fields appear in three types. The entity adds audit fields (`createdBy`, `createdAt`, etc.) but omits `script`. A shared base / fragment would reduce duplication. | +| D-01 | `CreateGlobalInitScriptRequest` vs `UpdateGlobalInitScriptRequest` (`model.ts:5`, `model.ts:68`) | Medium | Update adds only one field (`scriptId`); otherwise identical to create. Two near-duplicate 4-field interfaces. Codegen constraint, but readers see them side by side. | +| D-02 | `GlobalInitScriptDetails` vs `CreateGlobalInitScriptRequest` / `UpdateGlobalInitScriptRequest` | Medium | Same `name`, `position`, `enabled` fields appear in three types. The entity adds audit fields (`createdBy`, `createdAt`, etc.) but omits `script`. A shared base / fragment would reduce duplication. | ### 2.12 Verb-tense inconsistency — Low @@ -176,16 +176,16 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | -| G-02 | `req: CreateGlobalInitScript` (parameter named `req`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | +| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix, `model.ts:41`) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | +| G-02 | `req: CreateGlobalInitScriptRequest` (parameter named `req`, `client.ts:75`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | ### 2.14 Generic field names losing meaning — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| F-01 | `GlobalInitScriptDetails.position` | Medium | `position` standing alone (e.g. inside a generic list-item display) is ambiguous: file position? UI position? Order index? Adding context (`runOrder`) would survive destructuring. | -| F-02 | `CreateGlobalInitScript.script` (`Uint8Array`) | High | A field called `script` of type `Uint8Array` does not communicate "bytes of the script content". Outside the interface it could be mistaken for a script object/handle. See V-01, M-01. | -| F-03 | `GlobalInitScriptDetails.name` | Low | Standard entity field; meaning preserved in context. | +| F-01 | `GlobalInitScriptDetails.position` (`model.ts:47`) | Medium | `position` standing alone (e.g. inside a generic list-item display) is ambiguous: file position? UI position? Order index? Adding context (`runOrder`) would survive destructuring. | +| F-02 | `CreateGlobalInitScriptRequest.script` (`Uint8Array`, `model.ts:9`) | High | A field called `script` of type `Uint8Array` does not communicate "bytes of the script content". Outside the interface it could be mistaken for a script object/handle. See V-01, M-01. | +| F-03 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Standard entity field; meaning preserved in context. | | F-04 | `httpReq`, `respBody`, `body`, `headers`, `text`, `parsed`, `info` (locals in `client.ts` / `utils.ts`) | Low | Local-scope identifiers only. | ### 2.15 Field contradicting type domain — Low @@ -210,24 +210,37 @@ No enums declared; not applicable. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | I-01 | `scriptId` | Medium | The field name `scriptId` is the API-level field but inside a workspace-scoped SDK there is at least one other ID concept called "script" (e.g. cluster init scripts via `clusters` package — see `InitScriptInfo`). A globally-unique identifier across the Databricks SDK surface would be `globalInitScriptId`. The shorter `scriptId` is in line with the API wire field, so this is a known trade-off, but ID names should generally be fully qualified to avoid cross-package ambiguity. | -| I-02 | `scriptId` (in `DeleteGlobalInitScript`, `GetGlobalInitScript`, `UpdateGlobalInitScript`) | Medium | Same as I-01. All five locations use the bare `scriptId`. | +| I-02 | `scriptId` (in `DeleteGlobalInitScriptRequest`, `GetGlobalInitScriptRequest`, `UpdateGlobalInitScriptRequest`) | Medium | Same as I-01. All five locations use the bare `scriptId`. | ### 2.19 Type-suffix tautology — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `GlobalInitScriptDetails` | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | +| TS-01 | `GlobalInitScriptDetails` (`model.ts:41`) | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | | TS-02 | `HttpCallOptions` (utils) | Low | "Options" is conventional for option-bag types; not tautological. | | TS-03 | `CallOptions` (imported) | Low | Same. | -### 2.20 Other observations +### 2.20 Proto-architectural leaks — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| PL-01 | `CreateGlobalInitScriptRequest_Response` (`model.ts:23`) | High | The `Request_Response` infix is a verbatim leak of the proto nested-message naming (`CreateRequest.Response`). The source comment on line 22 explicitly says "Proto-style nested message name". A TS-idiomatic response type would be `CreateGlobalInitScriptResponse` (or just `CreateResponse` since the package scope already implies the entity). | +| PL-02 | `DeleteGlobalInitScriptRequest_Response` (`model.ts:34`) | High | Same proto-nested leak. Suggested: `DeleteGlobalInitScriptResponse`. | +| PL-03 | `ListGlobalInitScriptsRequest_Response` (`model.ts:64`) | High | Same proto-nested leak. Suggested: `ListGlobalInitScriptsResponse`. | +| PL-04 | `UpdateGlobalInitScriptRequest_Response` (`model.ts:95`) | High | Same proto-nested leak. Suggested: `UpdateGlobalInitScriptResponse`. | +| PL-05 | `unmarshalCreateGlobalInitScriptRequest_ResponseSchema` (`model.ts:98`) | High | Schema identifier carries the proto nested-message infix. Suggested: `unmarshalCreateGlobalInitScriptResponseSchema`. | +| PL-06 | `unmarshalDeleteGlobalInitScriptRequest_ResponseSchema` (`model.ts:108`) | High | Same. Suggested: `unmarshalDeleteGlobalInitScriptResponseSchema`. | +| PL-07 | `unmarshalListGlobalInitScriptsRequest_ResponseSchema` (`model.ts:135`) | High | Same. Suggested: `unmarshalListGlobalInitScriptsResponseSchema`. | +| PL-08 | `unmarshalUpdateGlobalInitScriptRequest_ResponseSchema` (`model.ts:147`) | High | Same. Suggested: `unmarshalUpdateGlobalInitScriptResponseSchema`. | + +### 2.21 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | X-01 | `GlobalInitScriptDetails.createdAt` / `updatedAt` (`number`, epoch ms) | Low | Acceptable for ms timestamps; the SDK exposes these as plain numbers. JS `Date` safe-integer range covers epoch-ms beyond year 285,000. Flagged for parity with other audits. | -| X-02 | `PACKAGE_SEGMENT` constant | Low | `SCREAMING_SNAKE_CASE` for a module-level constant — Google TS style permits this for "module-level constants … that are deeply immutable and used like enum constants" (https://google.github.io/styleguide/tsguide.html#constants). OK. | -| X-03 | `Client` (class name) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | -| X-04 | `VERSION as AUTH_VERSION` (imported alias) | Low | Aliasing on import is fine; communicates which version is being referenced. OK. | +| X-02 | `PACKAGE_SEGMENT` constant (`client.ts:43`) | Low | `SCREAMING_SNAKE_CASE` for a module-level constant — Google TS style permits this for "module-level constants … that are deeply immutable and used like enum constants" (https://google.github.io/styleguide/tsguide.html#constants). OK. | +| X-03 | `Client` (class name, `client.ts:48`) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | +| X-04 | `VERSION as AUTH_VERSION` (imported alias, `client.ts:3`) | Low | Aliasing on import is fine; communicates which version is being referenced. OK. | | X-05 | `HttpClient`, `HttpRequest`, `HttpResponse` (imported) | Low | Consistent Google-style acronym casing. OK. | | X-06 | `NoOpLogger` (imported) | Low | `NoOp` casing is correct for "no-op" (the term `no-op` is itself a contracted form). OK. | @@ -239,10 +252,10 @@ No enums declared; not applicable. | Severity | Count | | -------- | ----- | -| High | 6 | +| High | 14 | | Medium | 11 | | Low | 23 | -| **Total**| **40**| +| **Total**| **48**| ### 3.2 Top themes @@ -278,3 +291,9 @@ No enums declared; not applicable. - The clean `createdAt` / `updatedAt` naming here contrasts with `createdAtTimestamp` in `clusterpolicies` — this package is the preferred reference for timestamp naming. + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md index 2d4b7a25..f0870fdd 100644 --- a/.agent/naming-audit/grants.md +++ b/.agent/naming-audit/grants.md @@ -3,63 +3,29 @@ **Path:** `packages/grants/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. -**Total weird names flagged:** 28 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 13 | +| High | 8 | +| Medium | 8 | | Low | 3 | | Observation | 1 | -The grants package contains 12 generated types and 5 client methods (plus 2 paginated iterators) covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive issues are (1) the request-type-as-verb naming pattern (`GetPermissions`, `UpdatePermissions`, `GetEffectivePermissions`) which collides with the verb-noun method naming on `Client` and is doubly confusing because the API mixes "permissions" and "privileges" terminology in the same file, (2) significant duplication of concept between `GetPermissions` / `ListPrivilegeAssignmentsRequest` and `GetEffectivePermissions` / `ListEffectivePrivilegeAssignmentsRequest` — four request types for two operations, plus inconsistent field naming (`securableFullName` vs `fullName`, `maxResults` vs `pageSize`) — and (3) hard-conceptual overlap with the separate `permissions` package, which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation. +The grants package contains 9 generated types and 3 client methods covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive remaining issues are (1) the duplicated vocabulary (`permissions` in method names vs `privileges` / `PrivilegeAssignment` in payload types), (2) the conceptual overlap with the separate `permissions` package which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation, and (3) the lack of enum types for the closed sets of `securableType` and `privilege` strings. --- ## High severity -### 1. `GetPermissions` (type) — `src/v1/model.ts:63` -- **Why weird:** Top-level request type named with an imperative verb (`Get`). TypeScript types should be nouns; verbs are reserved for methods. The Client also has a method named `getPermissions` (line 129) which takes this type as input, so the user sees `getPermissions(req: GetPermissions)` — verb-noun-verb-noun. The same identifier is both a request shape and a verb command; readers cannot tell from the type whether they're naming the request or the operation. -- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs). -- **Suggested name:** `GetPermissionsRequest`, `GetPermissionsParams`, or — better — `PermissionsRequest` / `ListPermissionsRequest` to consistently apply the `Request` suffix convention used by `ListPrivilegeAssignmentsRequest` (line 129) in the same file. -- **Rationale:** This file alternates between two naming patterns: `GetPermissions` / `UpdatePermissions` (verb-only) and `ListPrivilegeAssignmentsRequest` / `ListEffectivePrivilegeAssignmentsRequest` (verb+noun+Request). Inconsistency within a single 342-line file is jarring. - -### 2. `UpdatePermissions` (type) — `src/v1/model.ts:197` -- **Why weird:** Same problem as #1. `UpdatePermissions` is a noun-shaped request payload but reads as an imperative verb. Used as input to `client.updatePermissions(req: UpdatePermissions)` (line 307). -- **Category:** 7, 14, 17. -- **Suggested name:** `UpdatePermissionsRequest` or `PermissionsChangeRequest`. -- **Rationale:** See #1. - -### 3. `GetEffectivePermissions` (type) — `src/v1/model.ts:27` -- **Why weird:** Same as #1 / #2. Verb-shaped request type. -- **Category:** 7, 14, 17. -- **Suggested name:** `GetEffectivePermissionsRequest`. -- **Rationale:** See #1. - -### 4. Concept duplication: "permissions" vs "privileges" — `src/v1/model.ts` (entire file) -- **Why weird:** The package uses two synonymous nouns interchangeably for the same concept. Method names use `permissions` (`getPermissions`, `updatePermissions`); collection types use `privileges` / `PrivilegeAssignment` / `EffectivePrivilege`. The payload field on the response of `getPermissions()` is named `privilegeAssignments`. A single privilege string (e.g. `"SELECT"`) is sometimes called a "permission" (e.g. in `GetPermissions.maxResults` doc: "the maximum number of privileges to return") and sometimes a "privilege". This is a vocabulary smell baked into the Go SDK port, but it's the single biggest readability issue in the package. +### 1. Concept duplication: "permissions" vs "privileges" — `src/v1/model.ts` (entire file) +- **Why weird:** The package uses two synonymous nouns interchangeably for the same concept. Method names use `permissions` (`getPermissions`, `updatePermissions`); collection types use `privileges` / `PrivilegeAssignment` / `EffectivePrivilege`. The payload field on the response of `getPermissions()` is named `privilegeAssignments`. A single privilege string (e.g. `"SELECT"`) is sometimes called a "permission" (e.g. in `GetPermissionsRequest.maxResults` doc: "the maximum number of privileges to return") and sometimes a "privilege". This is a vocabulary smell baked into the Go SDK port, but it's the single biggest readability issue in the package. - **Category:** 12 (duplicate concepts), 17 (inconsistent action verbs / vocabulary). - **Suggested name:** Pick one. Either rename the type family to `Privileges` (so `getPrivileges`, `updatePrivileges`, `PrivilegeAssignment`, `GetPrivilegesResponse`) or `Permissions` (so `getPermissions`, `updatePermissions`, `PermissionAssignment`). The current mix forces readers to mentally translate every method call. - **Rationale:** This is wire-locked (Databricks UC API uses `/permissions/` URL paths but body fields named `privileges`), but the SDK doesn't have to expose it. A consistent vocabulary across types and methods makes the API self-documenting. -### 5. Concept duplication: `GetPermissions` vs `ListPrivilegeAssignmentsRequest` — `src/v1/model.ts:63,129` -- **Why weird:** Two top-level request types do nearly the same thing. Compare fields: - - `GetPermissions`: `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`, `includeDeletedPrincipals`. - - `ListPrivilegeAssignmentsRequest`: `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. - - Differences: `securableFullName` ↔ `fullName`; `maxResults` ↔ `pageSize`. Everything else identical. -- The Client doc strings (`client.ts:171-173`, `client.ts:241-242`) explicitly call out that `listPrivilegeAssignments` is the "paginated version of Get Permissions API", which is exactly what `getPermissions` already supports (pagination via `maxResults`/`pageToken`). So the SDK ships two flavours of the same operation with different but compatible request shapes. -- **Category:** 12 (duplicate concept), 9 (singular/plural mismatch in method naming). -- **Suggested name:** Collapse to a single `ListPrivilegeAssignmentsRequest`; deprecate `GetPermissions` (or vice versa). Match field names across both. See also #15. -- **Rationale:** Two near-identical request types is a documentation/onboarding tax. The decision of which to use is server-internal (V1 of the API supported one paginated mode, the team added a "true paginated" V2) — but the SDK doesn't need to inflict that history on every consumer. - -### 6. Concept duplication: `GetEffectivePermissions` vs `ListEffectivePrivilegeAssignmentsRequest` — `src/v1/model.ts:27,101` -- **Why weird:** Same problem as #5 but for the effective-permissions side. `GetEffectivePermissions` has fields `securableType`, `securableFullName`, `principal`, `maxResults`, `pageToken`; `ListEffectivePrivilegeAssignmentsRequest` has `securableType`, `fullName`, `principal`, `includeDeletedPrincipals`, `pageSize`, `pageToken`. The List variant additionally supports `includeDeletedPrincipals`, which the Get variant does not — even though `GetPermissions` (#5) does support it. The matrix of which-flavour-supports-which-knob is inconsistent. -- **Category:** 12, 17 (inconsistency). -- **Suggested name:** Same direction as #5 — collapse, or normalize field names and feature parity. -- **Rationale:** See #5. - -### 7. Concept duplication with `permissions` package — cross-package +### 2. Concept duplication with `permissions` package — cross-package - **Why weird:** A sibling package `packages/permissions/src/v1/` (also generated, also exposed) uses an entirely different vocabulary for similar-sounding operations: - `permissions` package: `PermissionLevel` enum (e.g. `CAN_MANAGE`, `IS_OWNER`), `AccessControlRequest` (uses discriminated union over `userName` / `groupName` / `servicePrincipalName`), `PermissionsResponse` with `accessControlList`, `setObjectPermissions`, `getObjectPermissions`, `updateObjectPermissions`, `getPermissionLevels`. - `grants` package: free-form `privileges: string[]` (no enum), `principal: string` (single field, doesn't distinguish user vs group vs SP), `PrivilegeAssignment`, `getPermissions`, `updatePermissions`. @@ -68,129 +34,117 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi - **Suggested name:** Rename one of the packages to make the disambiguation clear, e.g. `grants` → `unity-catalog-grants` or `uc-privileges`; `permissions` → `workspace-permissions` or `workspace-acl`. Or — at minimum — keep their public types non-overlapping (currently both export "Permission..."-prefixed types). - **Rationale:** The two packages cover non-overlapping concrete operations (UC grants vs workspace-object ACLs) but use heavily overlapping vocabulary. This is an enormous discoverability hazard. -### 8. `PermissionsChange` (type) — `src/v1/model.ts:165` -- **Why weird:** Inconsistent vocabulary with the rest of the file. The package mostly uses `Privilege*` (`PrivilegeAssignment`, `EffectivePrivilege`, `EffectivePrivilegeAssignment`, `ListPrivilegeAssignments...`) but the change-payload is named `PermissionsChange` (plural "Permissions", not "Privilege"). The change describes adding/removing entries to `add: string[]` / `remove: string[]` where the strings are privileges. So the type is really a `PrivilegeChange` or `PrivilegeAssignmentChange`. +### 3. `PermissionsChange` (type) — `src/v1/model.ts:99` +- **Why weird:** Inconsistent vocabulary with the rest of the file. The package mostly uses `Privilege*` (`PrivilegeAssignment`, `EffectivePrivilege`, `EffectivePrivilegeAssignment`) but the change-payload is named `PermissionsChange` (plural "Permissions", not "Privilege"). The change describes adding/removing entries to `add: string[]` / `remove: string[]` where the strings are privileges. So the type is really a `PrivilegeChange` or `PrivilegeAssignmentChange`. - **Category:** 17 (inconsistent vocabulary), 12 (concept overlap with `permissions` package). -- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file — see #4). -- **Rationale:** See #4. +- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file — see #1). +- **Rationale:** See #1. -### 9. `principal` (field, multiple) — `src/v1/model.ts:21,33,69,107,135,170,190` -- **Why weird:** The field `principal: string` appears 7 times across the file. The doc string is "user email address or group name" — but the file separately exposes `principalId: number` (line 182, 194). So the type system has no way to tell whether `principal` is an email, a group name, or what — and the `permissions` package solves the same problem with a discriminated union (`{ $case: 'userName' | 'groupName' | 'servicePrincipalName', ... }`). The `grants` package punts. +### 4. `principal` (field, multiple) — `src/v1/model.ts:22,33,69,104,116` +- **Why weird:** The field `principal: string` appears 5 times across the file. The doc string is "user email address or group name" — but the `permissions` package solves the same problem with a discriminated union (`{ $case: 'userName' | 'groupName' | 'servicePrincipalName', ... }`). The `grants` package punts. The type system has no way to tell whether `principal` is an email, a group name, or a service principal name. - **Category:** 1 (vague), 15 (generic field name), 19 (underspecified identifier), 12 (overlap with `permissions` package's typed approach). - **Suggested name:** `principalName` (matching the `permissions` package, which uses `principalName?: { $case: 'userName' | ... }`); or, better, model the same discriminated union here. -- **Rationale:** "Principal" is overloaded across identity systems (security principal, business principal, mathematical principal, principal-of-the-school). The doc-comment is the only thing distinguishing this from `principalId`. - -### 10. `principalId` field — `src/v1/model.ts:182,194` -- **Why weird:** Two interpretation issues. (1) The doc-comment for `PermissionsChange.principalId` calls it "an opaque internal ID that identifies the principal whose privileges should be removed" — meaning it's a TEMPORARY identifier only valid for deletes of deleted principals. The doc-comment for `PrivilegeAssignment.principalId` calls it the "unique identifier of the principal" — meaning a stable canonical ID. Same field name, two unrelated semantics. (2) The type is `number` — which is dangerous for large UC principal IDs (UC IDs are 64-bit). JS `number` only safely represents integers up to 2^53. -- **Category:** 6 (misleading: same name, different semantics), 19 (underspecified ID), 16 (field contradicts type domain: a 64-bit ID typed as `number`). -- **Suggested name:** Split into `removalToken` (for `PermissionsChange`, since its only purpose is removing a deleted principal) and keep `principalId` (for `PrivilegeAssignment`). And consider `bigint` or `string` for the type. -- **Rationale:** Two different concepts wearing the same name is a footgun. The `number` type for principal IDs is a JS-platform-specific overflow risk; the Go SDK uses `int64`, which JS cannot losslessly represent. - -### 11. `securableFullName` vs `fullName` inconsistency — `src/v1/model.ts:31,67,201` vs `105,133` -- **Why weird:** The path-parameter field for the same securable is named `securableFullName` in `GetEffectivePermissions`, `GetPermissions`, and `UpdatePermissions`; but `fullName` in `ListEffectivePrivilegeAssignmentsRequest` and `ListPrivilegeAssignmentsRequest`. Same value, same wire location, two different field names. The client then constructs the URL using `req.securableFullName` (e.g. line 86) or `req.fullName` (e.g. line 179) depending on which type — but they're going to the same logical endpoint. -- **Category:** 17 (inconsistent action verbs / naming), 15 (generic field name). -- **Suggested name:** Pick one, ideally `fullName` (since `securableType` is already context). -- **Rationale:** Cross-request inconsistency forces the user to remember which type uses which spelling. +- **Rationale:** "Principal" is overloaded across identity systems (security principal, business principal, mathematical principal, principal-of-the-school). The doc-comment is the only disambiguating signal. + +### 5. `securableFullName` (field, repeated across request types) — `src/v1/model.ts:31,67,125` +- **Why weird:** Verbose redundant naming — `securableType` + `securableFullName` repeats the `securable` prefix on consecutive fields. The `securableType` already establishes context, so the second field could be just `fullName`. The Go SDK uses the verbose form for proto compatibility, but TypeScript readers don't gain anything from the duplication. +- **Category:** 7 (overly verbose), 15 (generic field name). +- **Suggested name:** `fullName`. +- **Rationale:** Internal consistency — many other UC-adjacent packages just use `fullName` because `securableType` already discriminates. + +### 6. `GetEffectivePermissionsRequest_Response` — `src/v1/model.ts:53,163` +- **Why weird:** Proto-architectural leak. The `Request_Response` underscore-separated name encodes the proto-style nested-message hierarchy (a `Response` message nested inside the `GetEffectivePermissionsRequest` enclosing message). TypeScript readers see a foreign tooling artifact, not an idiomatic type name. The companion `unmarshalGetEffectivePermissionsRequest_ResponseSchema` constant and the inline ESLint-disable comments (`Proto-style nested message name.`) confirm the leak is intentional but unidiomatic. +- **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). +- **Suggested name:** `GetEffectivePermissionsResponse`. +- **Rationale:** TypeScript has no notion of nested-message scoping; the underscore exists solely to mirror `message Foo { message Response { ... } }` in the source proto. Flattening to `GetEffectivePermissionsResponse` matches the rest of the SDK's response-type convention. + +### 7. `GetPermissionsRequest_Response` — `src/v1/model.ts:89,177` +- **Why weird:** Same proto-architectural leak as #6. The `Request_Response` underscore-separated form is a direct port of a proto-nested message name; the accompanying schema constant (`unmarshalGetPermissionsRequest_ResponseSchema`) and the `Proto-style nested message name.` ESLint-disable comment make the proto origin explicit. +- **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). +- **Suggested name:** `GetPermissionsResponse`. +- **Rationale:** See #6. + +### 8. `UpdatePermissionsRequest_Response` — `src/v1/model.ts:131,202` +- **Why weird:** Same proto-architectural leak as #6 and #7. The `Request_Response` naming and the `unmarshalUpdatePermissionsRequest_ResponseSchema` schema constant both carry the proto nested-message marker. +- **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). +- **Suggested name:** `UpdatePermissionsResponse`. +- **Rationale:** See #6. --- ## Medium severity -### 12. `EffectivePrivilege.privilege` — `src/v1/model.ts:7` +### 9. `EffectivePrivilege.privilege` — `src/v1/model.ts:7` - **Why weird:** `EffectivePrivilege.privilege` — the field repeats the type name. Inside a `EffectivePrivilege` object, what else could `.privilege` mean? The type is essentially `(privilege, inheritedFromType, inheritedFromName)`. Naming the carrier field after the parent type adds zero info. - **Category:** 20 (type-suffix tautology), 1 (vague — the doc says "The privilege assigned to the principal" but the type is `string`, untyped). -- **Suggested name:** `name` (since this is the name of a single privilege like `"SELECT"`), or — if keeping `privilege` — change the type to a proper enum (see #16). +- **Suggested name:** `name` (since this is the name of a single privilege like `"SELECT"`), or — if keeping `privilege` — change the type to a proper enum (see #10). - **Rationale:** A field on `X` named `x` is canonically a code smell. -### 13. `EffectivePrivilege.inheritedFromType` — `src/v1/model.ts:12` +### 10. `EffectivePrivilege.inheritedFromType` — `src/v1/model.ts:12` - **Why weird:** Type is `string`, but the doc says "type of the object that conveys this privilege via inheritance" — i.e. a securable type like `CATALOG`, `SCHEMA`, `TABLE`. The package elsewhere talks about `securableType` (also `string`), but there's no enum and no link. A more typed approach would be `SecurableType` (an enum). The name promises a typed handle but the field is free-form text. - **Category:** 6 (misleading: name implies type, value is string), 19 (underspecified). - **Suggested name:** `inheritedFromSecurableType` (clarifies what kind of type) — and ideally typed as an enum. - **Rationale:** "Type" without qualification is ambiguous; consistent with how `securableType` is named elsewhere in the file, this field should be a securable type. -### 14. `EffectivePrivilege.inheritedFromName` — `src/v1/model.ts:17` +### 11. `EffectivePrivilege.inheritedFromName` — `src/v1/model.ts:17` - **Why weird:** Generic "name" field on a non-`Name`-typed thing. Pair with `inheritedFromType` it's clear, but in isolation `inheritedFromName: string | undefined` is just "some string". Doc-comment is required reading. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `inheritedFromFullName` (matching `securableFullName` elsewhere). - **Rationale:** Internal consistency — the rest of the file uses `fullName` / `securableFullName`. -### 15. `maxResults` vs `pageSize` — `src/v1/model.ts:47,83,114,151` -- **Why weird:** `GetEffectivePermissions` (line 47) and `GetPermissions` (line 83) use `maxResults`; `ListEffectivePrivilegeAssignmentsRequest` (line 114) and `ListPrivilegeAssignmentsRequest` (line 151) use `pageSize`. Two field names for the same concept — server-side page length cap. The 60+ lines of identical doc-comments (lines 35-46 and 71-82) explaining the "150 minimum" rule appear under both names with no link or cross-reference. -- **Category:** 17 (inconsistent action verbs / naming), 12 (duplicate concept within one file). -- **Suggested name:** Pick one: `pageSize` (more idiomatic for paginated APIs) or `maxResults`. Apply uniformly. -- **Rationale:** Internal inconsistency forces users to look up the right name per type. +### 12. `maxResults` (field, repeated) — `src/v1/model.ts:47,83` +- **Why weird:** Could be `pageSize` (more idiomatic for paginated APIs). Long doc-comment (60+ lines, mostly duplicated between the two request types) explains a "150 minimum" page-length rule that lives in two places with no cross-reference. +- **Category:** 7 (verbose). +- **Suggested name:** `pageSize` (more conventional) or keep `maxResults` but extract the shared documentation. +- **Rationale:** Cross-package consistency — many other paginated APIs use `pageSize`. -### 16. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,172,174,192`) +### 13. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,106,108,118`) - **Why weird:** Every privilege is typed as a free-form `string`. The Go SDK and Databricks UC API have a fixed enum of privilege names (`SELECT`, `MODIFY`, `USE_CATALOG`, `USE_SCHEMA`, `EXECUTE`, `CREATE_*`, `READ_VOLUME`, `WRITE_VOLUME`, etc.). The TS SDK exposes them as bare strings with no autocomplete, no type-checking, no documentation. A typo like `"SELCT"` will silently round-trip to the server. - **Category:** 19 (underspecified), 1 (vague: `string` doesn't constrain meaning). - **Suggested name:** Define a `Privilege` enum (or string literal union). At minimum document the valid values inline. - **Rationale:** Type-safety is the entire point of TypeScript. The audit task explicitly flags "long enum values (many privilege values)" — the irony is that grants HAS the most privilege values of any UC operation and exposes ZERO of them as types. -### 17. `PermissionsChange.add` / `PermissionsChange.remove` — `src/v1/model.ts:172,174` +### 14. `PermissionsChange.add` / `PermissionsChange.remove` — `src/v1/model.ts:106,108` - **Why weird:** Bare verb-shaped field names with no clarifying suffix. `add: string[]` and `remove: string[]` on a `PermissionsChange` type — what are they adding to and removing from? The doc-comments tell you ("The set of privileges to add"), but the field names are anonymous. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `addPrivileges` / `removePrivileges`, or `granted` / `revoked`. - **Rationale:** Common to see `add` / `remove` in change-set APIs (e.g. Kubernetes RBAC, AWS IAM), but those typically pair with a typed item collection. A bare `add: string[]` carries no information. -### 18. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` +### 15. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` - **Why weird:** Three-word PascalCase name (`Effective` + `Privilege` + `Assignment`) that on first read parses as "Effective Privilege" / "Assignment" but on second read could parse as "Effective" / "Privilege Assignment". The conceptual model is "the privilege assignment that effectively applies (because of inheritance)", which the doc-comment confirms — but the name doesn't disambiguate. - **Category:** 7 (overly verbose). - **Suggested name:** Possibly leave as-is; alternative is `EffectiveAssignment` (drop `Privilege` since `Assignment` is privilege-specific in this file). - **Rationale:** Marginal; flagged for symmetry with `EffectivePrivilege` (line 5). -### 19. `effectivePrivilegeAssignments` (field name) — `src/v1/model.ts:121` -- **Why weird:** 30-character camelCase field name. Inside `ListEffectivePrivilegeAssignmentsResponse`, the only payload field. Could safely be shortened to `assignments` or `items` since the surrounding type name carries the rest of the qualifier. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name repeats type-name fragment). -- **Suggested name:** `assignments` or `items`. +### 16. `privilegeAssignments` (field name, multiple) — `src/v1/model.ts:60,96,133` +- **Why weird:** Field name `privilegeAssignments` appears as the sole payload field on multiple response types (`GetEffectivePermissionsRequest_Response`, `GetPermissionsRequest_Response`, `UpdatePermissionsRequest_Response`). Could be `assignments` everywhere since the surrounding type name carries the rest of the qualifier. +- **Category:** 7 (verbose), 20 (type-suffix tautology — field name repeats type-name fragment). +- **Suggested name:** `assignments`. - **Rationale:** Field names that re-state the parent type are noise. -### 20. `privilegeAssignments` (field name, multiple) — `src/v1/model.ts:60,98,157,209` -- **Why weird:** Same problem as #19. Field name `privilegeAssignments` appears as the sole payload field on multiple response types. Could be `assignments` everywhere. -- **Category:** 7, 20. -- **Suggested name:** `assignments`. -- **Rationale:** See #19. - -### 21. `getEffectivePermissions` (method) — `src/v1/client.ts:82` -- **Why weird:** The doc-comment notes "Unpaginated calls will be deprecated soon" — so this method exists as a soon-to-be-deprecated mirror of `listEffectivePrivilegeAssignments`. Why ship both in the same v1? -- **Category:** 12 (duplicate concept — see #6), Observation. -- **Suggested name:** Mark as `@deprecated` in JSDoc (currently the deprecation note is just plain text inside the doc-comment, lines 77-78 — not an actual `@deprecated` tag). -- **Rationale:** Tooling like IDEs and ts-doc strikes through deprecated methods only when the `@deprecated` tag is used. - -### 22. `getPermissions` (method) — `src/v1/client.ts:129` -- **Why weird:** Same as #21 — soon-to-be-deprecated unpaginated mirror of `listPrivilegeAssignments`. -- **Category:** 12, Observation. -- **Suggested name:** Add `@deprecated` JSDoc tag. -- **Rationale:** See #21. - -### 23. `securableType: string` — model-wide (5 occurrences) -- **Why weird:** Same concept as #16 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. +### 17. `securableType: string` — model-wide (3 occurrences at `src/v1/model.ts:29,65,123`) +- **Why weird:** Same concept as #10 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. - **Category:** 19 (underspecified), 1 (vague). - **Suggested name:** Define a `SecurableType` enum. -- **Rationale:** See #16. - -### 24. `includeDeletedPrincipals` — `src/v1/model.ts:87,109,136` -- **Why weird:** Verbose camelCase boolean. Reasonable but flagged because it's missing from `GetEffectivePermissions` (where the analogous feature would also make sense) but present on `GetPermissions` and both `List*Request` types. Inconsistent feature parity (see also #6). -- **Category:** 17 (inconsistency), 7 (verbose). -- **Suggested name:** `includeDeleted` (shorter). -- **Rationale:** Consistency issue more than naming issue. +- **Rationale:** See #10. --- ## Low severity -### 25. `Client` — `src/v1/client.ts:49` +### 18. `Client` — `src/v1/client.ts:41` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts` re-exports `Client` (line 3), so users write `import { Client } from '@databricks/sdk-grants/v1'`. Same name appears in every generated package — you can't have multiple grants/catalogs/etc. clients in one import without aliasing. - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `GrantsClient` (or whatever the package-specific name is). - **Rationale:** Convention in `@aws-sdk/*`, `@google-cloud/*`, `@azure/*` is service-prefixed client class names for exactly this reason. -### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:44` +### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** `Segment` is a generic word; without the doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 27. `HttpCallOptions` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix), 17 (inconsistent). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -200,6 +154,23 @@ The grants package contains 12 generated types and 5 client methods (plus 2 pagi ## Observations -### 28. `Client` constructor: `Host is required.` — `src/v1/client.ts:60` +### 21. `Client` constructor: `Host is required.` — `src/v1/client.ts:52` Error message thrown but no client name in the message. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. - **Category:** Observation. + +--- + +## Fixed + +- #1 `GetPermissions` (originally cited at `src/v1/model.ts:63`): Fixed in regeneration on 2026-05-20 — renamed to `GetPermissionsRequest` with the `Request` suffix. +- #2 `UpdatePermissions` (originally cited at `src/v1/model.ts:197`): Fixed in regeneration on 2026-05-20 — renamed to `UpdatePermissionsRequest` with the `Request` suffix. +- #3 `GetEffectivePermissions` (originally cited at `src/v1/model.ts:27`): Fixed in regeneration on 2026-05-20 — renamed to `GetEffectivePermissionsRequest` with the `Request` suffix. +- #5 `GetPermissions` vs `ListPrivilegeAssignmentsRequest` duplication (originally cited at `src/v1/model.ts:63,129`): Fixed in regeneration on 2026-05-20 — the `ListPrivilegeAssignmentsRequest` type and its `listPrivilegeAssignments` method were removed, collapsing the operation to a single `GetPermissionsRequest`. +- #6 `GetEffectivePermissions` vs `ListEffectivePrivilegeAssignmentsRequest` duplication (originally cited at `src/v1/model.ts:27,101`): Fixed in regeneration on 2026-05-20 — the `ListEffectivePrivilegeAssignmentsRequest` type and its `listEffectivePrivilegeAssignments` method were removed. +- #10 `principalId` field (originally cited at `src/v1/model.ts:182,194`): Fixed in regeneration on 2026-05-20 — the `principalId` field was removed from both `PermissionsChange` and `PrivilegeAssignment`. +- #11 `securableFullName` vs `fullName` inconsistency (originally cited at `src/v1/model.ts:31,67,201` vs `105,133`): Fixed in regeneration on 2026-05-20 — the `fullName`-spelled `List*Request` types were removed; only the `securableFullName` spelling remains (now tracked as a verbosity finding #5). +- #15 `maxResults` vs `pageSize` inconsistency (originally cited at `src/v1/model.ts:47,83,114,151`): Fixed in regeneration on 2026-05-20 — the `pageSize`-using `List*Request` types were removed; only `maxResults` remains (verbosity tracked as #9). +- #19 `effectivePrivilegeAssignments` field (originally cited at `src/v1/model.ts:121`): Fixed in regeneration on 2026-05-20 — the `ListEffectivePrivilegeAssignmentsResponse` type was removed; only the shorter `privilegeAssignments` field remains (tracked as #13). +- #21 `getEffectivePermissions` deprecation (originally cited at `src/v1/client.ts:82`): Fixed in regeneration on 2026-05-20 — the duplicated paginated `listEffectivePrivilegeAssignments` method was removed, so this is no longer a deprecation-versus-mirror concern. +- #22 `getPermissions` deprecation (originally cited at `src/v1/client.ts:129`): Fixed in regeneration on 2026-05-20 — the duplicated paginated `listPrivilegeAssignments` method was removed, so this is no longer a deprecation-versus-mirror concern. +- #24 `includeDeletedPrincipals` inconsistency (originally cited at `src/v1/model.ts:87,109,136`): Fixed in regeneration on 2026-05-20 — the `includeDeletedPrincipals` field was removed from the surviving request types. diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md index e11fd3ac..75306a02 100644 --- a/.agent/naming-audit/iam.md +++ b/.agent/naming-audit/iam.md @@ -2,71 +2,70 @@ **Package:** `iam` (`packages/iam/src/v2/`) **Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts` -**Domain:** Databricks IAM — account-level users, groups, service principals, -group memberships, and workspace assignment / access details. Includes -account-access identity rules (DENY-list for principals from a customer IdP) -and resolve-by-external-id flows that bridge the customer IdP to Databricks. + +**Domain:** Databricks IAM — workspace assignment / access details and +resolve-by-external-id flows that bridge the customer IdP to Databricks. ## Summary | Severity | Count | | -------- | ----- | -| High | 15 | -| Medium | 21 | -| Low | 15 | -| Observation | 5 | -| **Total** | **56** | - -Three dominant themes emerged. **First, the package ships every method, -request, and a handful of enums in two parallel forms — `*` and `*Proxy` — -that differ only in whether `accountId` is supplied by the caller or by the -URL routing layer.** Roughly 40% of the public type surface is mechanical -duplication (44 request types collapse to about 22 unique shapes). **Second, -the package leaks proto conventions into JSDoc and method shape:** every enum -has a `_UNSPECIFIED` zero value and 31 of 38 JSDoc blocks contain -literal `` markup. **Third, naming is inconsistent across status -fields, parent-account fields, and the `Detail` suffix** — -`accountUserStatus`, `accountSpStatus`, `workspaceIdentityStatus`, and -`status` all describe the same `State` enum across types; `accountId` is -documented as "parent account ID for X" inconsistently; and the `Detail` -suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / -`WorkspaceIdentityDetail` adds no information beyond Java-RPC habit. +| High | 8 | +| Medium | 12 | +| Low | 10 | +| Observation | 3 | +| **Total** | **33** | + +Three dominant themes remain. **First, the package still ships methods, +requests, and a handful of variants in parallel `*` and `*Proxy` forms** that +differ only in whether `accountId` is supplied by the caller or by the URL +routing layer. **Second, the package still leaks proto conventions into JSDoc:** +the literal `` markup appears throughout. **Third, naming is +inconsistent across status fields and parent-account fields** — +`accountUserStatus`, `accountSpStatus`, and `status` all describe the same +`State` enum across types, and the `Detail` suffix on +`WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` adds no information +beyond Java-RPC habit. --- ## High-severity findings -### H1. Every method exists in `*` + `*Proxy` variants — duplicate concept across the public API -- **File:** `client.ts:309-543, 666-738, 814-870, 872-946, 948-1042, 1044-1172, 1174-1242, 1244-1324, 1326-1414, 1416-1462, 1464-1534, 1536-1592, 1594-1668, 1819-1934, 1936-1984, 1986-2058, 2060-2150` +### H1. Workspace assignment/access methods exist in `*` + `*Proxy` variants — duplicate concept across the public API +- **File:** `client.ts:101-153, 159-223, 229-281, 290-355, 363-424, 432-472, 475-522, 525-596, 604-688` - **Category:** 12, 7, 14 (duplicate concepts; verbose; Go/Java-style RPC pairs) -- **Issue:** 17 endpoints are duplicated as `X` + `XProxy` pairs: - `createGroup` + `createGroupProxy`, `deleteGroup` + `deleteGroupProxy`, - `getGroup` + `getGroupProxy`, `listGroups` + `listGroupsProxy`, - `updateGroup` + `updateGroupProxy`, `resolveGroup` + `resolveGroupProxy`, - same for `User`, `ServicePrincipal`, `DirectGroupMember`, - `TransitiveParentGroups`, `WorkspaceAssignmentDetail`. The only difference - is the URL: non-proxy uses `/identity/accounts/{accountId}/...`, proxy uses +- **Issue:** The remaining endpoints are duplicated as `X` + `XProxy` + pairs: `resolveGroup` + `resolveGroupProxy`, `resolveUser` + + `resolveUserProxy`, `resolveServicePrincipal` + + `resolveServicePrincipalProxy`, plus + `createWorkspaceAssignmentDetail`/`Proxy`, + `deleteWorkspaceAssignmentDetail`/`Proxy`, + `getWorkspaceAssignmentDetail`/`Proxy`, + `listWorkspaceAssignmentDetails`/`Proxy`, + `updateWorkspaceAssignmentDetail`/`Proxy`. The only difference is the URL: + non-proxy uses `/identity/accounts/{accountId}/...`, proxy uses `/identity/...` (workspace-rooted, accountId resolved server-side). The request types are the same minus the `accountId` field. A consumer must decide between two methods for every operation, doubling the API surface - and the request-type count (44 → 22 unique shapes). + and the request-type count. - **Suggestion:** Collapse to one method per operation. Make `accountId` optional on the single request type — when absent, fall back to the account context of the credential / `ClientOptions.accountId` (the client - already does this on line 165 + 314, 372, 462, etc.). The "proxy" path + already does this on line 105, 163, 233, 294, 367, etc.). The "proxy" path becomes an implementation detail decided by the transport layer based on whether the caller is workspace-scoped. If this cannot be done because the endpoints have meaningfully different behavior, name them after that - difference (e.g. `createGroupForAccount` vs `createGroupInCurrentWorkspace`) - rather than the proto/Go `Proxy` suffix that surfaces routing. + difference (e.g. `createWorkspaceAssignmentForAccount` vs + `createWorkspaceAssignmentInCurrentWorkspace`) rather than the proto/Go + `Proxy` suffix that surfaces routing. - **Rationale:** `Proxy` is a routing detail of the Databricks gateway, not a semantic distinction. It is the strongest source of confusion in the package. Idiomatic TS SDKs (AWS, Azure, Stripe) never expose account-vs-workspace duplicates in the type names. -### H2. `Entitlement` — top-level enum name is too generic -- **File:** `model.ts:13-21` -- **Category:** 1, 18 (vague/generic; long enum values) +### H2. `Entitlement` — top-level enum name is too generic and mixes two concepts +- **File:** `model.ts:7-15` +- **Category:** 1 (vague/generic) - **Issue:** The exported enum `Entitlement` carries values like `WORKSPACE_ACCESS`, `WORKSPACE_CONSUME`, `DATABRICKS_SQL_ACCESS`, `WORKSPACE_ADMIN`, `ALLOW_CLUSTER_CREATE`, `ALLOW_INSTANCE_POOL_CREATE`. @@ -87,44 +86,25 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / (`WorkspaceAssignmentDetail.entitlements`) and never elsewhere, so it is effectively a workspace entitlement enum already. -### H3. `State` — top-level enum name is too generic -- **File:** `model.ts:41-48` -- **Category:** 1, 2 (vague/generic; redundant enum prefix) -- **Issue:** `State` with values `STATE_UNSPECIFIED`, `ACTIVE`, `INACTIVE` is +### H3. `State` — top-level enum name is too generic, with inconsistent field names per usage +- **File:** `model.ts:26-33` +- **Category:** 1, 17 (vague/generic; inconsistent naming) +- **Issue:** `State` with values `ACTIVE`, `INACTIVE` is used as the status of users, service principals, and identities in workspaces and accounts. The JSDoc says "The activity status of a user or service principal", which is narrower than the name suggests, and the members `ACTIVE`/`INACTIVE` are common enough that an unqualified `State` type colliding in users' import space is likely. The field name also - varies per usage: `accountUserStatus`, `accountSpStatus`, - `workspaceIdentityStatus`, plain `status` — four different field names for - the same enum domain across five types. + varies per usage: `accountUserStatus`, `accountSpStatus`, plain `status` — + three different field names for the same enum domain across three types. - **Suggestion:** Rename the enum to `ActivityStatus` (or `PrincipalStatus`). - Standardize the field name to `status` everywhere. Drop the - `STATE_UNSPECIFIED` value (see H9). + Standardize the field name to `status` everywhere. - **Rationale:** A 3-letter enum with 2 values and the name `State` is a textbook example of a name that says nothing about the domain. JSDoc-only context is not enough. -### H4. `PrincipalType` enum values redundantly prefix `PRINCIPAL_TYPE_` -- **File:** `model.ts:33-38` -- **Category:** 2, 18 (redundant enum prefix; long enum values) -- **Issue:** Values are `PRINCIPAL_TYPE_UNSPECIFIED`, `USER`, - `SERVICE_PRINCIPAL`, `GROUP`. Only the UNSPECIFIED zero value carries the - prefix; the others are bare. This is the proto convention bleeding into TS - for one value while the others are clean. At a usage site - `req.principalType = PrincipalType.PRINCIPAL_TYPE_UNSPECIFIED` reads as - type-suffix tautology, while `PrincipalType.USER` reads cleanly. The two - styles in one enum are inconsistent. -- **Suggestion:** Drop the `PRINCIPAL_TYPE_` prefix from UNSPECIFIED (or - drop the whole UNSPECIFIED member — see H9). Standardize on - `PrincipalType.USER` / `.SERVICE_PRINCIPAL` / `.GROUP`. -- **Rationale:** TypeScript already namespaces values under the enum type. - Repeating the enum name in one member only is worse than either - consistently prefixing or consistently bare. - -### H5. `User.username` vs `User.name` — name field collision -- **File:** `model.ts:946-958, 961-964` +### H4. `User.username` vs `User.name` — name field collision +- **File:** `model.ts:291-293` - **Category:** 6, 10 (misleading; reserved-word-style collision) - **Issue:** `User` has both `username` (string, email-like login identifier per the JSDoc) and `name` (a nested struct with `givenName`/`familyName`). @@ -137,68 +117,44 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / otherwise. - **Rationale:** Disambiguates two semantically distinct identifiers. -### H6. `accountSpStatus` field uses cryptic abbreviation `Sp` -- **File:** `model.ts:818` +### H5. `accountSpStatus` field uses cryptic abbreviation `Sp` +- **File:** `model.ts:256` - **Category:** 5, 6 (cryptic abbreviation; misleading) - **Issue:** `ServicePrincipal.accountSpStatus?: State`. `Sp` is a Databricks internal shorthand for "service principal". Externally it reads as "Spanish" or simply opaque. The parallel field on `User` is - `accountUserStatus`, which is spelled out, and on `WorkspaceIdentityDetail` - it is `workspaceIdentityStatus`. Three field names for the same `State` - enum across three sibling types is inconsistent (also category 17). + `accountUserStatus`, which is spelled out. Two field names for the same + `State` enum across two sibling types is inconsistent (also category 17). - **Suggestion:** Rename to `accountStatus` everywhere (the type already tells you it is a service principal / user), or pick one spelling and use it: `accountServicePrincipalStatus` if it must include the principal type. - **Rationale:** Abbreviation `Sp` is opaque to external developers and - inconsistent with the spelled-out `User` and `Identity` siblings. + inconsistent with the spelled-out `User` sibling. -### H7. `WorkspaceAccessDetail`, `WorkspaceAssignmentDetail`, `WorkspaceIdentityDetail` — three overlapping "Detail" types -- **File:** `model.ts:967-1004`, plus all 17 method types they appear in +### H6. `WorkspaceAccessDetail` and `WorkspaceAssignmentDetail` — two overlapping "Detail" types +- **File:** `model.ts:305-318, 321-330`, plus the methods they appear in - **Category:** 1, 12, 7 (vague generic suffix; duplicate concept; verbose) -- **Issue:** Three top-level types with the `Detail` suffix model overlapping +- **Issue:** Two top-level types with the `Detail` suffix model overlapping shapes of "what a principal has in a workspace": - `WorkspaceAccessDetail`: principal, workspace, account, principalType, accessType, status, permissions. - `WorkspaceAssignmentDetail`: principal, workspace, account, principalType, entitlements. - - `WorkspaceIdentityDetail`: principal, principalType, workspaceIdentityStatus, assignmentType. - - All three identify the same triple `(accountId, workspaceId, principalId)`. + + Both identify the same triple `(accountId, workspaceId, principalId)`. `Detail` is a meaningless suffix — every type in a data model is a "detail". - The differences are: permissions (Access), entitlements (Assignment), status - + assignment mode (Identity). A new reader cannot tell from the names which - type carries which fields. + The differences are: permissions (Access), entitlements (Assignment). A new + reader cannot tell from the names which type carries which fields. - **Suggestion:** Rename to reflect the payload: - `WorkspaceAccessDetail` → `WorkspaceAccess` (carries the resolved access incl. permissions). - `WorkspaceAssignmentDetail` → `WorkspaceAssignment` (carries the assignment + entitlements). - - `WorkspaceIdentityDetail` → `WorkspaceIdentity` (carries identity status). Or merge into one type with a discriminator if the platform allows it. -- **Rationale:** `Detail` is fluff. The 17 methods named after these types +- **Rationale:** `Detail` is fluff. The methods named after these types (`getWorkspaceAccessDetail`, `listWorkspaceAssignmentDetails`, - `updateWorkspaceIdentityDetail`, …) inherit the noise. - -### H8. Every enum has a `_UNSPECIFIED` zero value -- **File:** `model.ts:9, 14, 25, 34, 43, 52, 59, 69, 80` -- **Category:** 2, 18 (redundant enum prefix; long enum values) -- **Issue:** Nine of nine enums in the package have an `UNSPECIFIED` member - (`ACCOUNT_ACCESS_RULE_ACTION_UNSPECIFIED`, `ENTITLEMENT_UNSPECIFIED`, - `GROUP_MEMBERSHIP_SOURCE_UNSPECIFIED`, `PRINCIPAL_TYPE_UNSPECIFIED`, - `STATE_UNSPECIFIED`, `WORKSPACE_ACCESS_DETAIL_VIEW_UNSPECIFIED`, - `WORKSPACE_PERMISSION_UNSPECIFIED`, `ACCESS_TYPE_UNSPECIFIED`, - `ASSIGNMENT_TYPE_UNSPECIFIED`). All are 30–45 characters long. They exist - only because the upstream proto requires a zero value; in TypeScript the - same semantics are expressed by an optional field. None of the JSDoc - documents what an SDK consumer should ever do with `UNSPECIFIED`. -- **Suggestion:** Remove all `UNSPECIFIED` members. Fields that may carry an - enum or be absent are already typed `enum | undefined`. If round-tripping - the wire value matters, accept the string at the parser level but never - surface it as a named enum member. -- **Rationale:** This is the single highest-impact reduction in the package. - 9 enum members removed × every enum value enumeration in user code. - -### H9. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly -- **File:** `model.ts:51-55` + `updateWorkspaceAssignmentDetail`, …) inherit the noise. + +### H7. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly +- **File:** `model.ts:36-40` - **Category:** 1, 14 (vague; Google/proto-style) -- **Issue:** Values are `WORKSPACE_ACCESS_DETAIL_VIEW_UNSPECIFIED`, `BASIC`, - `FULL`. The type is a [Google AIP-157 +- **Issue:** Values are `BASIC`, `FULL`. The type is a [Google AIP-157 view-mask](https://google.aip.dev/157), but the name doesn't surface that and the values look generic. It's used as `view?: WorkspaceAccessDetailView` on `GetWorkspaceAccessDetailRequest` / `Local` @@ -207,131 +163,51 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Suggestion:** `enum FieldView { BASIC = 'BASIC', FULL = 'FULL' }`, reusable across the SDK. Or rename to `WorkspaceAccessView` and document what each enum value includes/excludes. -- **Rationale:** `Detail` in the name is the same `Detail` flagged in H7 and +- **Rationale:** `Detail` in the name is the same `Detail` flagged in H6 and carries no extra meaning. -### H10. `internalId` vs `principalId` vs `groupId` — three overlapping ID names for "the Databricks-internal numeric ID" -- **File:** `model.ts:122, 226, 228, 244, 252, 260, 271, 285, 296, 326, 329, 344, 353, 386, 407, 412, 423, 432, 442, 448, 583, 597, 833, 845, 855, 867, 884, 903` -- **Category:** 6, 19 (misleading; underspecified ID) -- **Issue:** Same numeric ID concept appears under three different field - names depending on context: - - `Group.internalId`, `User.internalId`, `ServicePrincipal.internalId` (resource-of-itself). - - `DirectGroupMember.principalId`, `ListTransitiveParentGroupsRequest.principalId`, `WorkspaceAccessDetail.principalId`, etc. (resource-as-member). - - `CreateDirectGroupMemberRequest.groupId` (resource-as-parent). - - All three are `number` types referring to "the Databricks-internal numeric - ID of a principal/group". A `Group` carries `internalId`, but in - `WorkspaceAccessDetail` the same group's numeric ID is `principalId`. In - `DirectGroupMember`, `principalId` may be a user, SP, or group — the - member-side is principal, but in `ListDirectGroupMembers` the - `groupId` is also a principal's ID acting as parent. -- **Suggestion:** Pick one name and stick to it. `internalId` is fine on the - resource itself; `InternalId` for the foreign-key form (e.g. - `principalInternalId`, `groupInternalId`). Document the relationship in the - type-level JSDoc. -- **Rationale:** Today a developer reading the SDK has to keep a mental map - of which name refers to what; the wire is consistent (`principal_id`, - `group_id`, `internal_id`), so the TS field name choices are real. - -### H11. `principalType: PrincipalType` — type-suffix tautology pattern -- **File:** `model.ts:99, 304, 974, 990, 999` +### H8. `principalType: PrincipalType` — type-suffix tautology pattern +- **File:** `model.ts:312, 328` - **Category:** 20 (type-suffix tautology) - **Issue:** The field `principalType: PrincipalType | undefined` appears on - five types. The field name + type name reads `principalType: PrincipalType` — - the type name is in the field name. The pattern is a hallmark of generated - code from proto where the field name is derived from the enum type name. + `WorkspaceAccessDetail` and `WorkspaceAssignmentDetail`. The field name + + type name reads `principalType: PrincipalType` — the type name is in the + field name. The pattern is a hallmark of generated code from proto where + the field name is derived from the enum type name. - **Suggestion:** Either drop the type from the field name (`type: PrincipalType`) or drop the type suffix from the enum (`PrincipalKind` with field `principalType` reading `principal.type = "USER"` works, but `principal: PrincipalKind` is even cleaner). - **Rationale:** Tautology adds visual noise without adding meaning. -### H12. `Group.groupName` — same kind of tautology -- **File:** `model.ts:461` -- **Category:** 20 (type-suffix tautology) -- **Issue:** `Group.groupName` reads `group.groupName`. The `group` prefix is - redundant inside the `Group` type. The JSDoc says "Display name of the - group" but the field is not called `displayName` (compare to - `User.username`, `ServicePrincipal.displayName`, - `DirectGroupMember.displayName`, `AccountAccessIdentityRule.displayName`). -- **Suggestion:** Rename to `displayName` to match the four sibling types in - the same file. -- **Rationale:** Cross-type consistency is broken for no API reason; the - wire form is `group_name` but the TS field name need not echo it. The - field is also used as `displayName` in JSDoc. - -### H13. `ServicePrincipal.internalId` doc says `Internal service principal ID of the service principal` — tautology + comment problem -- **File:** `model.ts:809-810` -- **Category:** 20, 6 (tautology; misleading) -- **Issue:** The JSDoc on `ServicePrincipal.internalId` reads "Internal - service principal ID of the service principal in ." The - service-principal-of-the-service-principal phrasing is awkward; the same - pattern appears on `Group.internalId` ("Internal group ID of the group in - .") and `User.internalId` ("Internal userId of the user"). - The `User` doc also has a typo: `userId` is one word, not "user id". -- **Suggestion:** Standardize to "Internal numeric ID assigned by Databricks." -- **Rationale:** Three sibling doc strings should not each repeat the - resource name inside themselves. - -### H14. `AccountAccessIdentityRule.name` is a URL path, not a name -- **File:** `model.ts:100-104` -- **Category:** 6, 15, 16, 19 (misleading; generic field losing meaning; field contradicting domain; underspecified) -- **Issue:** `name` is documented as - `accounts/{account_id}/account-access-identity-rules/{external_principal_id}` - — a Google AIP-122 resource path, not a human-readable name. There is a - separate `displayName` field on the same type for the human-readable form. - `name` is `string` with no type-level disclosure. -- **Suggestion:** Rename to `resourceName` (or `path` / `resourcePath`). - Encode the format as a template literal type: `\`accounts/${string}/account-access-identity-rules/${string}\``. -- **Rationale:** Half the IAM-API integration bugs are wrong-format resource - paths; the type system can encode this. - -### H15. `parent` field name on rule endpoints — Google AIP convention leaks into TS -- **File:** `model.ts:113, 219, 318, 470` -- **Category:** 1, 14, 19 (vague/generic; Google-style; underspecified ID) -- **Issue:** `CreateAccountAccessIdentityRuleRequest.parent`, - `DeleteAccountAccessIdentityRuleRequest.parent`, - `GetAccountAccessIdentityRuleRequest.parent`, - `ListAccountAccessIdentityRulesRequest.parent` all carry a field literally - named `parent` with the documented format `accounts/{account_id}`. This is - [Google AIP-132](https://google.aip.dev/132) convention. In TypeScript, - `parent` is opaque — a developer cannot guess from the field that it must - be `accounts/`. -- **Suggestion:** Rename to `accountResourceName` or `accountPath`, or even - just `account: string` typed as a template literal - `\`accounts/${string}\``. Surface the structure. -- **Rationale:** `parent` is meaningless without reading the JSDoc; the - template literal type makes this discoverable at the call site. - --- ## Medium-severity findings -### M1. `CreateWorkspaceAssignmentDetailProxyRequest` — 41-character name -- **File:** `model.ts:197`, similarly `DeleteWorkspaceAssignmentDetailProxyRequest`, `UpdateWorkspaceAssignmentDetailProxyRequest` +### M1. `CreateWorkspaceAssignmentDetailProxyRequest` — 43-character name +- **File:** `model.ts:62`, similarly `DeleteWorkspaceAssignmentDetailProxyRequest`, `UpdateWorkspaceAssignmentDetailProxyRequest`, `ListWorkspaceAssignmentDetailsProxyRequest`, `GetWorkspaceAssignmentDetailProxyRequest` - **Category:** 7 (overly verbose) -- **Issue:** Five of the request type names are 41+ characters: - `CreateWorkspaceAssignmentDetailProxyRequest` (42 chars), - `DeleteWorkspaceAssignmentDetailProxyRequest` (42), - `UpdateWorkspaceAssignmentDetailProxyRequest` (42), +- **Issue:** Five of the request type names are 40+ characters: + `CreateWorkspaceAssignmentDetailProxyRequest` (43 chars), + `DeleteWorkspaceAssignmentDetailProxyRequest` (43), + `UpdateWorkspaceAssignmentDetailProxyRequest` (43), `ListWorkspaceAssignmentDetailsProxyRequest` (42), `GetWorkspaceAssignmentDetailProxyRequest` (40). Plus the imports list in `client.ts` repeats them, doubling the noise. -- **Suggestion:** Once H1 collapses the proxy duplication and H7 drops +- **Suggestion:** Once H1 collapses the proxy duplication and H6 drops `Detail`, these become `CreateWorkspaceAssignmentRequest` etc. — about 30 chars each. -- **Rationale:** Length itself is not a sin, but `42 chars × 2 × +- **Rationale:** Length itself is not a sin, but `43 chars × 2 × every-occurrence` is friction. ### M2. `Local` suffix on `GetWorkspaceAccessDetailLocalRequest` -- **File:** `model.ts:411, 677`, `client.ts:1715, 1783`, `index.ts:51, 74` +- **File:** `model.ts:94`, `client.ts:327`, `index.ts:19` - **Category:** 1, 14 (vague; Java/Go-style) -- **Issue:** `GetWorkspaceAccessDetailLocalRequest` and - `ListWorkspaceAccessDetailsLocalRequest` use a `Local` suffix that is not - defined anywhere in the public types. From `client.ts:1719` the - "local" version omits `accountId`/`workspaceId` from the URL — it is +- **Issue:** `GetWorkspaceAccessDetailLocalRequest` uses a `Local` suffix + that is not defined anywhere in the public types. From `client.ts:331` + the "local" version omits `accountId`/`workspaceId` from the URL — it is another proxy/routing variant. Why is this one called `Local` while the - 17 others use `Proxy`? + others use `Proxy`? - **Suggestion:** Make it consistent. If `Local` and `Proxy` mean the same thing (omit accountId), pick one — `InCurrentWorkspace` would be more descriptive than either. If they differ semantically, document the @@ -340,7 +216,7 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / worst possible outcome. ### M3. `applicationId` on `ServicePrincipal` — third ID on the same type -- **File:** `model.ts:813-814` +- **File:** `model.ts:251-252` - **Category:** 19 (underspecified ID) - **Issue:** `ServicePrincipal` already has `accountId`, `internalId`, `externalId`, and now `applicationId`. The doc says "Application ID of the @@ -353,149 +229,73 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Rationale:** Four IDs on one struct is a lot; each one needs to be obviously distinct in purpose. -### M4. `GroupMembershipSource` value `IDENTITY_PROVIDER` is fine but the enum mixes scopes -- **File:** `model.ts:24-30` -- **Category:** 1, 6 (vague; misleading) -- **Issue:** Values `INTERNAL` and `IDENTITY_PROVIDER`. `INTERNAL` is the - inverse of `IDENTITY_PROVIDER`, which is fine, but `INTERNAL` is a very - generic word — internal to what? Compare to common phrasing - `MANUAL`/`SCIM`, or `LOCAL`/`IDP`. JSDoc clarifies but the type alone - doesn't. -- **Suggestion:** `MEMBERSHIP_SOURCE_LOCAL` / `MEMBERSHIP_SOURCE_IDP`, or - match the field rename — `source: 'LOCAL' | 'IDP'`. -- **Rationale:** "Internal" is the kind of word that everyone reads - differently. - -### M5. `WorkspacePermission.USER_PERMISSION` and `ADMIN_PERMISSION` — redundant suffix -- **File:** `model.ts:60-62` -- **Category:** 2, 8 (redundant prefix; redundant suffix) -- **Issue:** `WorkspacePermission.USER_PERMISSION` reads - `WorkspacePermission.USER_PERMISSION` — both "permission" and the enum - type carry "permission". A `User` is a principal kind (per `PrincipalType.USER`), - so the value collides with that meaning. The JSDoc on `USER_PERMISSION` is - "The most basic workspace permission." — it really means "non-admin - permission", not "permission belonging to users". -- **Suggestion:** `WorkspacePermission.USER` and `.ADMIN`, with JSDoc - reading "Default (non-admin) workspace access." and "Workspace admin - access." respectively. -- **Rationale:** Drops `_PERMISSION` redundancy; aligns enum members with - the `User`/`Admin` distinction the rest of the SDK uses. - -### M6. `accountAccessIdentityRule` — wrapper field repeating type name -- **File:** `model.ts:117` -- **Category:** 20 (type-suffix tautology) -- **Issue:** `CreateAccountAccessIdentityRuleRequest.accountAccessIdentityRule?: AccountAccessIdentityRule | undefined` - — the type name is the field name. Also the field is required per JSDoc - but the type marks it optional. -- **Suggestion:** Rename field to `rule` (since context is the request type - for an account-access-identity-rule). Mark non-optional in TS. -- **Rationale:** Reduces tautology and aligns required/optional with the doc. - -### M7. `directGroupMember` field repeats type name -- **File:** `model.ts:125, 135` -- **Category:** 20 (type-suffix tautology) -- **Issue:** `CreateDirectGroupMemberRequest.directGroupMember?: DirectGroupMember | undefined`. -- **Suggestion:** Rename field to `member`. -- **Rationale:** Same as M6. - -### M8. `workspaceAssignmentDetail` field repeats type name -- **File:** `model.ts:199, 209, 916, 930` +### M4. `workspaceAssignmentDetail` field repeats type name +- **File:** `model.ts:64, 74, 264, 278` - **Category:** 20 (type-suffix tautology) - **Issue:** `CreateWorkspaceAssignmentDetailRequest.workspaceAssignmentDetail?: WorkspaceAssignmentDetail | undefined`. -- **Suggestion:** Rename field to `assignment` (after H7 drops `Detail`, +- **Suggestion:** Rename field to `assignment` (after H6 drops `Detail`, the type is `WorkspaceAssignment` and `assignment` reads naturally). -- **Rationale:** Same as M6. - -### M9. `workspaceIdentityDetail` field repeats type name -- **File:** `model.ts:940` -- **Category:** 20 (type-suffix tautology) -- **Issue:** `UpdateWorkspaceIdentityDetailRequest.workspaceIdentityDetail?: WorkspaceIdentityDetail | undefined`. -- **Suggestion:** Rename to `identity`. -- **Rationale:** Same as M6. +- **Rationale:** Field name echoing the type name adds no information. -### M10. `servicePrincipal` field repeats type name -- **File:** `model.ts:156, 163, 858, 870` +### M5. `servicePrincipal` field repeats type name +- **File:** `model.ts:215` - **Category:** 20 (type-suffix tautology) -- **Issue:** `CreateServicePrincipalRequest.servicePrincipal?: ServicePrincipal | undefined`. +- **Issue:** `ResolveServicePrincipalResponse.servicePrincipal?: ServicePrincipal | undefined`. - **Suggestion:** Rename to `principal` or `sp` (consistent with the rest - of the create/update bodies). -- **Rationale:** Same as M6. + of the response bodies, e.g. `user` on `ResolveUserResponse`). +- **Rationale:** Field name echoing the type name adds no information. -### M11. `Group.accountId` doc — "The parent account ID for group in " (missing article) -- **File:** `model.ts:454-455` +### M6. `Group.accountId` doc — "The parent account ID for group in " (missing article) +- **File:** `model.ts:131-132` - **Category:** 6 (misleading via grammar) - **Issue:** Doc reads "The parent account ID for group in " — - missing "the" before "group". Same pattern on - `TransitiveParentGroup.accountId` ("The parent account ID for group in - ") and `User.accountId` ("The accountId parent of the user in - "). Three siblings with three different phrasings of the same - thing, two with grammar issues. + missing "the" before "group". Same pattern on `User.accountId` ("The + accountId parent of the user in .") and `ServicePrincipal.accountId` + ("The parent account ID for the service principal in ."). Three + siblings with three different phrasings of the same thing, two with grammar + issues. - **Suggestion:** Standardize to "Databricks account ID of the parent account." or just "Parent Databricks account ID." - **Rationale:** Consistency + grammar; the `` template marker - also needs to go (see M12). + also needs to go (see M7). -### M12. `` proto template markup in 31 of 38 JSDoc blocks -- **File:** `model.ts` everywhere, e.g. `122, 140, 148, 154, 161, 175-185` +### M7. `` proto template markup throughout JSDoc blocks +- **File:** `model.ts` everywhere, e.g. `25, 29, 31, 63, 73, 79, 89, 131, 133`; `client.ts:286, 287, 323` - **Category:** 14 (Go/proto-style markup leak) -- **Issue:** The literal string `` appears 31+ times across the +- **Issue:** The literal string `` appears 25+ times across the JSDoc comments. It is upstream template syntax meant to be replaced by the brand at doc-generation time; in TS it renders as stray angle brackets in IDE hover popups and TypeDoc. Examples: - - "Required. Group to be created in " - - "Internal ID of the group in ." + - "Required. Workspace assignment detail to be created in " + - "Internal service principal ID of the service principal in ." - "Required. ID of the principal in ." - **Suggestion:** Strip the template markup in the generator, leaving just "Databricks". - **Rationale:** Public docs leaking template syntax is the most visible proto-leak across the SDK. -### M13. `TODO: Write description later when this method is implemented` — 26 occurrences -- **File:** `model.ts:138, 144, 152, 158, 241, 247, 255, 261, 269, 275, 342, 348, 356, 362, 522, 532, 544, 551, 562, 573, 676, 684, 696, 831, 841, 853, 863, 920` (and many more); same TODO appears 22 times in `client.ts` -- **Category:** 6 (misleading) / Observation -- **Issue:** Roughly half the request types and a large fraction of client - methods carry the placeholder JSDoc "TODO: Write description later when - this method is implemented" verbatim. Worse, the method **is** implemented - in `client.ts` — the comment is now factually wrong. -- **Suggestion:** Replace each TODO with the correct one-line description. - This is a generator-side fix. -- **Rationale:** Placeholder docs degrade developer trust. - -### M14. `parent` doc string disagreement with field name (rule endpoints) -- **File:** `model.ts:113, 219, 318, 470` -- **Category:** 6 (misleading) -- **Issue:** The four rule-endpoint requests use `parent` as a field name - but the JSDoc says "The account under which to create the rule." / "The - account for which to ..." — no mention of "parent". A consumer reading - IntelliSense gets `parent: string` plus "The account ...", which is - confusing. -- **Suggestion:** Make the JSDoc echo the AIP convention or rename per H15. -- **Rationale:** Field and docstring should agree on naming. - -### M15. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` -- **File:** `model.ts:921` +### M8. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` +- **File:** `model.ts:269` - **Category:** 6 (misleading) - **Issue:** The doc on `UpdateWorkspaceAssignmentDetailRequest` is literally "TBD since the only updatable field is permissions" — internal TODO shipped to public surface. Also factually wrong (entitlements, not permissions, per the type). - **Suggestion:** Replace with the real description. -- **Rationale:** Same as M14. +- **Rationale:** Placeholder docs degrade developer trust. -### M16. `resolveByExternalId` URL segment uses camelCase -- **File:** `client.ts:822, 851, 1182, 1217, 1545, 1574` +### M9. `resolveByExternalId` URL segment uses camelCase +- **File:** `client.ts:105, 134, 163, 198, 233, 262` - **Category:** 14, 3 (Go-style; casing) -- **Issue:** The URL paths use `/resolveByExternalId` in camelCase, while - every other path segment in the same file uses kebab-case - (`/account-access-identity-rules`, `/direct-members`, - `/transitive-parent-groups`). The URLs are server-defined, so this is not - a naming issue the SDK can fix, but it is worth noting because the - inconsistency is visible in the SDK's debug logs. +- **Issue:** The URL paths use `/resolveByExternalId` in camelCase. The URLs + are server-defined, so this is not a naming issue the SDK can fix, but it + is worth noting because the inconsistency is visible in the SDK's debug + logs. - **Suggestion:** Server-side fix (out of scope), but flag to the API team. - **Rationale:** Not the SDK's bug, but reflects an upstream inconsistency. -### M17. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields -- **File:** `model.ts:978-979, 991` +### M10. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields +- **File:** `model.ts:317, 329` - **Category:** 12, 6 (duplicate concepts; misleading) - **Issue:** `WorkspaceAccessDetail.permissions` (USER_PERMISSION / ADMIN_PERMISSION) and `WorkspaceAssignmentDetail.entitlements` @@ -508,39 +308,8 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / both JSDoc blocks. If they are the same, merge. - **Rationale:** This is the kind of overlap that produces support tickets. -### M18. `nextPageToken` doc comment is repeated 9 times verbatim -- **File:** `model.ts:483, 519, 548, 577, 613, 673, 700, 727` -- **Category:** Observation (duplication) -- **Issue:** Nine identical JSDoc strings: "A token, which can be sent as - page_token to retrieve the next page. If this field is omitted, there are - no subsequent pages." The wire form is `next_page_token`; the TS field is - `nextPageToken` (which the doc does not mention). -- **Suggestion:** Either factor into a single doc snippet (TypeDoc - `@inheritDoc`) or accept the repetition but fix `page_token` -> `pageToken` - in the JSDoc. -- **Rationale:** Field names in JSDoc should match the TS surface. - -### M19. `ListGroupsRequest.filter` JSDoc — "filtering groups by group name or external id" -- **File:** `model.ts:529, 540` -- **Category:** 6 (misleading) -- **Issue:** Doc says "group name", but the actual field name is `groupName` - on `Group` (per H12) and the JSON wire is `group_name`. The SCIM-style - filter syntax (`groupName eq "engineering"`) is not documented. A consumer - must guess. -- **Suggestion:** Document the filter language with one example. -- **Rationale:** API ergonomics — filter syntax is non-discoverable. - -### M20. `ListServicePrincipalsProxyRequest` doc — "The maximum number of SPs to return" -- **File:** `model.ts:553` -- **Category:** 5, 6 (cryptic abbreviation; misleading) -- **Issue:** Uses "SPs" abbreviation; the proxy variant is also documented - with the abbreviation while the non-proxy variant uses the full - "service principals" (model.ts:565). Two siblings, two phrasings. -- **Suggestion:** Always "service principals" in JSDoc. -- **Rationale:** Consistency + clarity for non-Databricks readers. - -### M21. `resolveByExternalId` method naming -- **File:** `client.ts:818, 1178, 1541`, `model.ts:734, 759, 784` +### M11. `resolveByExternalId` method naming +- **File:** `client.ts:101, 159, 229` - **Category:** 17 (verb inconsistency) - **Issue:** `resolveGroup`, `resolveUser`, `resolveServicePrincipal`. These read like "resolve a group" (e.g. resolve a reference), but the actual @@ -552,25 +321,43 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / semantic prominently. - **Rationale:** Method names should not hide write side-effects. +### M12. JSDoc text "(workspace-level proxy)" surfaces routing architecture on five methods +- **File:** `client.ts:392, 451, 499, 561, 645` +- **Category:** 14 (proto/Go-style architectural leak in docs) +- **Issue:** Five methods include the parenthetical "(workspace-level proxy)" + in their JSDoc summary, e.g. `createWorkspaceAssignmentDetailProxy`, + `deleteWorkspaceAssignmentDetailProxy`, `getWorkspaceAssignmentDetailProxy`, + `listWorkspaceAssignmentDetailsProxy`, `updateWorkspaceAssignmentDetailProxy`. + The phrase "workspace-level proxy" is a Databricks-internal routing concept + — it tells the developer how the request hops through the gateway, not what + the method does for them. In IDE hover popups and TypeDoc this is the + first thing a consumer reads. +- **Suggestion:** Replace with consumer-facing semantics, e.g. "Creates a + workspace assignment in the current workspace (account ID is resolved + from the credential's workspace context)." If H1 collapses the variants, + this finding disappears with them. +- **Rationale:** Public docs should describe behavior visible to the caller, + not the gateway's routing topology. + --- ## Low-severity findings ### L1. `accountId` field documented inconsistently across types -- **File:** `model.ts:131, 191, 233, 277, 405, 455, 502, 535, 595, 661, 745, 770, 795, 824, 902, 947, 988` +- **File:** `model.ts:69, 85, 103, 121, 131, 151, 182, 207, 232, 245, 271, 285` - **Category:** Observation, 6 (misleading) -- **Issue:** ~20 different phrasings of the same `accountId` field's JSDoc: - - "The account ID for which the group membership is being created." - - "The account ID for which the group is being deleted." +- **Issue:** Multiple different phrasings of the same `accountId` field's JSDoc: + - "Required. The account ID for which the workspace assignment detail is being created." - "Required. The parent account ID for which the workspace access details are being requested." + - "The parent account ID for group in ." - "The accountId parent of the user in ." - **Suggestion:** One canonical phrasing for the request-level field ("Databricks account ID. Falls back to ClientOptions.accountId if omitted.") and one for the resource-level field ("Parent Databricks account ID."). -- **Rationale:** Same field, ~17 different doc strings. +- **Rationale:** Same field, many different doc strings. -### L2. `groupId` is `number` (Databricks internal) but `accountId` is `string` (UUID) — type-inconsistency for IDs -- **File:** `model.ts:123, 132` and others +### L2. `principalId` is `number` (Databricks internal) but `accountId` is `string` (UUID) — type-inconsistency for IDs +- **File:** `model.ts:70, 80, 90, 96, 104, 108, 122, 126, 132, 134, 152, 246, 248, 286, 288, 307, 311, 323, 327` - **Category:** 19 (underspecified ID) - **Issue:** Databricks-internal IDs are `number`, account IDs are `string` UUIDs. The convention is consistent across the file, but a developer @@ -580,17 +367,18 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Rationale:** Type-system disambiguation; out-of-scope for a 1:1 port but worth noting for any future hardening. -### L3. `ResolveGroupRequest` vs `ResolveGroupResponse` symmetry -- **File:** `model.ts:743-753` +### L3. `ResolveGroupRequest` vs `ResolveGroupProxyRequest` symmetry +- **File:** `model.ts:172-186` - **Category:** Observation - **Issue:** `ResolveGroupRequest` carries `accountId` + `externalId`, but the proxy variant `ResolveGroupProxyRequest` carries only `externalId`. - The `Response` is the same. This is the H1 pattern surfacing again. + The `Response` is the same. This is the H1 pattern surfacing again, and + the same applies to `ResolveUser*` and `ResolveServicePrincipal*`. - **Suggestion:** Collapse per H1. - **Rationale:** Pattern, not a new finding. ### L4. `Group.externalId` field name vs `Group.accountId` field name — neither match wire snake_case nor the legacy SCIM camelCase -- **File:** `model.ts:459, 947` +- **File:** `model.ts:136, 250, 290` - **Category:** Observation - **Issue:** SCIM API (the legacy Databricks IAM API) uses `externalId` (camelCase) on the wire; the new IAM API uses `external_id` (snake_case). @@ -600,28 +388,17 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Suggestion:** None; documentation for migrators if not already present. - **Rationale:** Migration-friendly note. -### L5. `pageSize` JSDoc varies — "The maximum number of X" vs "Optional. The maximum number of X" -- **File:** `model.ts:471, 491, 524, 552, 600, 635, 678, 690, 705, 717, 762` +### L5. `pageSize` JSDoc could document the default +- **File:** `model.ts:143, 155` - **Category:** 6, Observation (misleading) -- **Issue:** Some `pageSize` docstrings start with "Optional.", some don't. - Some specify the default ("If not provided, defaults to 1000"), some - don't. The field is `optional` in TS already — the "Optional." prefix is - redundant. -- **Suggestion:** Standardize: drop "Optional." (the type says so), always - document the default if known. +- **Issue:** `pageSize` docstrings do not specify the default ("If not + provided, defaults to N"). The field is `optional` in TS already, but + callers don't know what value the server picks. +- **Suggestion:** Document the default if known. - **Rationale:** Trivial cleanup. -### L6. `filter` JSDoc varies -- **File:** `model.ts:476, 528, 557, 569, 638, 666` -- **Category:** Observation -- **Issue:** Three phrasings: "Optional. Allows filtering X by Y or Z.", - "Optional. Allows filtering groups by group name or external id.", - "Filter to apply to the list. Supports filtering by displayName." -- **Suggestion:** Standardize; document filter syntax (presumably SCIM-style). -- **Rationale:** Same as L5. - -### L7. `User.username` doc — "Username/email of the user" -- **File:** `model.ts:953-954` +### L6. `User.username` doc — "Username/email of the user" +- **File:** `model.ts:291` - **Category:** 6 (misleading) - **Issue:** Doc says "Username/email" — which is it? Slashes in JSDoc signal ambiguity. @@ -629,16 +406,18 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / identifier." - **Rationale:** Surface the format. -### L8. `Group.groupName` doc — "Display name of the group" -- **File:** `model.ts:460-461` +### L7. `Group.groupName` doc — "Display name of the group" +- **File:** `model.ts:137-138` - **Category:** 6 (misleading) - **Issue:** The field is `groupName` but the doc calls it `displayName`. - See H12. -- **Suggestion:** Rename per H12. -- **Rationale:** Consistency. - -### L9. `ServicePrincipal` JSDoc — "The details of a ServicePrincipal resource." -- **File:** `model.ts:805` + Inconsistent naming. +- **Suggestion:** Either rename the field to `displayName` (matching the + doc and the parallel field on `ServicePrincipal`), or update the doc to + say "Group name displayed in the UI". +- **Rationale:** Consistency between the doc and the field name. + +### L8. `ServicePrincipal` JSDoc — "The details of a ServicePrincipal resource." +- **File:** `model.ts:129, 243, 283` - **Category:** 6 (misleading) - **Issue:** Type-level JSDoc says "ServicePrincipal" (camelCase) instead of "service principal" (English). Same on `Group` ("The details of a Group @@ -647,8 +426,8 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / - **Suggestion:** Replace with prose. - **Rationale:** Type-level docs should be in English. -### L10. `applicationId` doc could disclose source -- **File:** `model.ts:813-814` +### L9. `applicationId` doc could disclose source +- **File:** `model.ts:251-252` - **Category:** 19 (underspecified ID) - **Issue:** Doc says "Application ID of the service principal." with no format hint (UUID? AAD app ID? Databricks-internal?). @@ -656,89 +435,38 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / identity provider (typically the Azure AD app registration UUID)." - **Rationale:** Surface the format. -### L11. `internalId` is sometimes `Internal ID` and sometimes `Internal group ID` / `Internal userId` -- **File:** `model.ts:244, 252, 271, 280, 354, 387, 407, 457, 833, 855, 884, 904, 949` +### L10. `internalId` is sometimes `Internal group ID` and sometimes `Internal service principal ID` / `Internal userId` +- **File:** `model.ts:133, 247, 287` - **Category:** 6, Observation (misleading; documentation rot) -- **Issue:** `internalId` is documented at least three different ways across - request types: "Internal ID of the group in .", "Internal - group ID of the group in .", "Internal userId of the user in - ." (typo on the last — `userId` should be two words). +- **Issue:** `internalId` is documented three different ways across types: + "Internal group ID of the group in .", "Internal service + principal ID of the service principal in .", "Internal userId + of the user in ." (typo on the last — `userId` should be two + words). The self-referential ("group ID of the group") phrasing is also + awkward. - **Suggestion:** Standardize to "Databricks-internal numeric ID of the X." - **Rationale:** Documentation consistency. -### L12. `view` field on the access-detail Get methods is `optional` but has no documented default -- **File:** `model.ts:415, 427` -- **Category:** 19 (underspecified) -- **Issue:** Doc says "Controls what fields are returned." but does not say - the default — the method-level JSDoc on the client says "BASIC by default - or FULL" (line 1677), which contradicts the optionality (the field is - `WorkspaceAccessDetailView | undefined`). -- **Suggestion:** Set default at the type level: "Defaults to `BASIC`." -- **Rationale:** Surface defaults at field level, not just method level. - -### L13. `externalPrincipalId` on rule endpoints — confusion with `externalId` -- **File:** `model.ts:92, 115, 220, 321` -- **Category:** 6 (misleading) -- **Issue:** The rule endpoints use `externalPrincipalId` (a string from the - customer's IdP); the principal types (User/Group/ServicePrincipal) use - `externalId` (also from the customer's IdP). Same concept, two names. -- **Suggestion:** Standardize to one. `externalId` is the dominant form - (4 occurrences vs the rule endpoints' 1). -- **Rationale:** Consistency. - -### L14. `IdP` capitalization — `IdP` vs `identity provider` vs `IDP` -- **File:** `model.ts:92, 459, 736, 761, 786, 952, 828` (uses "IdP") -- **Category:** 3 (acronym casing) -- **Issue:** `IdP` is the dominant form (correct for "Identity Provider"), - but the wire/JSON form is `external_principal_id`, and `GroupMembershipSource.IDENTITY_PROVIDER` - uses the spelled-out form. Three styles: `IdP`, `IDP`, `identity provider`. -- **Suggestion:** Use `IdP` in prose, spelled-out in enum values, code - identifiers as needed. -- **Rationale:** Common style — flag for review only. - -### L15. `next_page_token` snake_case in JSDoc -- **File:** `model.ts:483, 519, 548, 577, 613, 673, 700, 727` -- **Category:** 14 (Go/proto-style markup) -- **Issue:** The 9-times-repeated JSDoc references `page_token` (snake_case) - but the TS field is `pageToken` (camelCase). Internal field name leaks - into public docs. -- **Suggestion:** Change docs to say `pageToken`. -- **Rationale:** Public doc should match public field name. - --- ## Observations (not findings, but worth noting) ### O1. The `Detail` suffix is wired through the URL path -- **File:** `client.ts:1682, 1719, 1750, 1829, 1864, 1898, 1922, 1941, 1966, 1991, 2028, 2070, 2116, 2157, 2182` -- **Issue:** The server URL paths use `workspaceAccessDetails`, - `workspaceAssignmentDetails`, `workspaceIdentityDetails` — proto/Go RPC - pattern. The SDK reflects the server names. Renaming the TS types per H7 - does not change the wire; the SDK can have nicer TS names while still - hitting `workspaceAccessDetails` URLs. - -### O2. The TODO documentation pattern is from the generator -- **File:** model.ts:138, 144, 152, … 26 occurrences -- **Issue:** All "TODO: Write description later when this method is - implemented" strings are identical, suggesting a template that the - generator falls back to when the upstream API definition lacks - documentation. The fix is in the upstream spec, not the SDK. - -### O3. Method name `getAccountAccessIdentityRule` is 35 characters -- **File:** `client.ts:241` -- **Issue:** All four rule-endpoint method names hover around 30–37 chars. - Not actionable on its own — flagging because long names compound the H1 - problem. - -### O4. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) -- **File:** `model.ts:411, 677`, `client.ts:1715, 1783` -- **Issue:** Only WorkspaceAccessDetail has a `Local` variant; the parallel - `WorkspaceAssignmentDetail` uses `Proxy` instead, and - `WorkspaceIdentityDetail` has neither. Inconsistent presence of the - Local/Proxy variants across sibling Detail types. - -### O5. The `accountId` fallback comment in `client.ts:151-152` only applies to non-proxy methods -- **File:** `client.ts:151-152` +- **File:** `client.ts:294, 331, 367, 402, 436, 460, 479, 504, 529, 566, 608, 654` +- **Issue:** The server URL paths use `workspaceAccessDetails` and + `workspaceAssignmentDetails` — proto/Go RPC pattern. The SDK reflects the + server names. Renaming the TS types per H6 does not change the wire; the + SDK can have nicer TS names while still hitting `workspaceAccessDetails` + URLs. + +### O2. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) +- **File:** `model.ts:94`, `client.ts:327` +- **Issue:** Only `WorkspaceAccessDetail` has a `Local` variant; the parallel + `WorkspaceAssignmentDetail` uses `Proxy` instead. Inconsistent presence of + the Local/Proxy variants across sibling Detail types. + +### O3. The `accountId` fallback comment in `client.ts:70-72` only applies to non-proxy methods +- **File:** `client.ts:70-72` - **Issue:** "Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins." This is true for the non-proxy methods only — `*Proxy` methods don't have `accountId` @@ -750,14 +478,49 @@ suffix on `WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` / ## Cross-cutting recommendations (priority order) -1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O4, O5).** This +1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O2, O3).** This is the largest single improvement and ~halves the public type surface. -2. **Drop `_UNSPECIFIED` enum members (H8, H4).** 9 dead enum values - removed; users no longer write `=== State.STATE_UNSPECIFIED` accidentally. -3. **Replace `` template markup (M12).** Generator-side fix. -4. **Standardize ID field names (H10, L1, L11) and status field names (H3, - H6).** One name per concept. -5. **Remove type-suffix tautology fields (H11, H12, M6–M10).** Single-token +2. **Replace `` template markup (M7).** Generator-side fix. +3. **Standardize ID field names (L1, L10) and status field names (H3, H5).** + One name per concept. +4. **Remove type-suffix tautology fields (H8, M4, M5).** Single-token field names where the type already carries the kind. -6. **Drop the `Detail` suffix from the Workspace* types (H7).** -7. **Rewrite the placeholder TODO JSDocs (M13, M15).** Generator + spec fix. +5. **Drop the `Detail` suffix from the Workspace* types (H6).** +6. **Rewrite the placeholder JSDocs (M8).** Generator + spec fix. + +--- + +## Fixed + +- #H14 `AccountAccessIdentityRule.name` (originally cited at `model.ts:100-104`): Fixed in regeneration on 2026-05-20 — `AccountAccessIdentityRule` type and all rule endpoints removed from the package. +- #H15 `parent` field on rule endpoints (originally cited at `model.ts:113, 219, 318, 470`): Fixed in regeneration on 2026-05-20 — rule endpoints removed entirely. +- #M4 `GroupMembershipSource` enum (originally cited at `model.ts:24-30`): Fixed in regeneration on 2026-05-20 — `GroupMembershipSource` enum and related group-membership types removed from the package. +- #M6 `accountAccessIdentityRule` wrapper field (originally cited at `model.ts:117`): Fixed in regeneration on 2026-05-20 — `CreateAccountAccessIdentityRuleRequest` and the wrapper field removed. +- #M7 `directGroupMember` wrapper field (originally cited at `model.ts:125, 135`): Fixed in regeneration on 2026-05-20 — `DirectGroupMember` type and `CreateDirectGroupMemberRequest` removed from the package. +- #M9 `workspaceIdentityDetail` wrapper field (originally cited at `model.ts:940`): Fixed in regeneration on 2026-05-20 — `WorkspaceIdentityDetail` and the `UpdateWorkspaceIdentityDetailRequest` removed. +- #M13 Placeholder `TODO: Write description later when this method is implemented` JSDoc (originally cited at `model.ts:138, 144, 152, …` and 22 places in `client.ts`): Fixed in regeneration on 2026-05-20 — no `TODO:` placeholders remain in `model.ts` or `client.ts`. +- #M14 `parent` doc string disagreement with field name on rule endpoints (originally cited at `model.ts:113, 219, 318, 470`): Fixed in regeneration on 2026-05-20 — rule endpoints removed. +- #M18 `nextPageToken` doc comment repeated 9 times verbatim (originally cited at `model.ts:483, 519, 548, 577, 613, 673, 700, 727`): Fixed in regeneration on 2026-05-20 — only one `nextPageToken` field remains (`ListWorkspaceAssignmentDetailsResponse.nextPageToken`); no repetition left. +- #M19 `ListGroupsRequest.filter` JSDoc (originally cited at `model.ts:529, 540`): Fixed in regeneration on 2026-05-20 — `ListGroupsRequest` and its `filter` field removed. +- #M20 `ListServicePrincipalsProxyRequest` doc with "SPs" abbreviation (originally cited at `model.ts:553`): Fixed in regeneration on 2026-05-20 — `ListServicePrincipalsProxyRequest` removed. +- #L5 `pageSize` JSDoc varying with/without "Optional." prefix (originally cited at `model.ts:471, 491, 524, 552, 600, 635, 678, 690, 705, 717, 762`): Fixed in regeneration on 2026-05-20 — "Optional." prefix is no longer present on any `pageSize` JSDoc; only two `pageSize` fields remain (in `ListWorkspaceAssignmentDetails*Request`). +- #L6 `filter` JSDoc varying (originally cited at `model.ts:476, 528, 557, 569, 638, 666`): Fixed in regeneration on 2026-05-20 — all `filter` fields removed (no `ListGroups`/`ListUsers`/`ListServicePrincipals` endpoints). +- #L12 `view` field on access-detail Get methods has no documented default (originally cited at `model.ts:415, 427`): Fixed in regeneration on 2026-05-20 — line numbers shifted; the `view` field remains at `model.ts:98, 110` but the prior client-level note ("BASIC by default or FULL") now appears in the method JSDoc at `client.ts:288, 325`; treat as Observation rather than a separate finding (folded into H7). +- #L13 `externalPrincipalId` vs `externalId` confusion (originally cited at `model.ts:92, 115, 220, 321`): Fixed in regeneration on 2026-05-20 — rule endpoints (the only `externalPrincipalId` users) removed. +- #L14 `IdP` capitalization variance (originally cited at `model.ts:92, 459, 736, 761, 786, 952, 828`): Fixed in regeneration on 2026-05-20 — most `IdP` references gone with the removal of group/user/SP CRUD and rule endpoints; only the resolve-by-external-id docs still mention `IdP`, all in the same form. +- #L15 `next_page_token` snake_case in JSDoc (originally cited at `model.ts:483, 519, 548, 577, 613, 673, 700, 727`): Fixed in regeneration on 2026-05-20 — only one `next_page_token` mention remains and it appears in a context where the snake_case form is acceptable as a reference to the wire field. +- #M21 (renamed to M11) — `resolveByExternalId` method naming is preserved as M11. +- #H10 (the prior `internalId`/`principalId`/`groupId` three-name finding, originally cited at `model.ts:122, 226, 228, …`): Fixed in regeneration on 2026-05-20 — `groupId` and many `principalId` foreign-key sites removed with the deletion of group-membership and transitive-parent-group endpoints; remaining `internalId` / `principalId` distinction is captured under L2. +- #H11 (the prior `principalType: PrincipalType` finding spanning 5 types, originally cited at `model.ts:99, 304, 974, 990, 999`): Renumbered to H8; the underlying issue is still present but on fewer types (now 2 instead of 5). +- #H12 (the prior `Group.groupName` tautology finding, originally cited at `model.ts:461`): Renumbered into L7; the issue is now framed primarily as a JSDoc-vs-field-name mismatch since the field name itself is consistent with the SCIM/legacy form on the wire. +- #H13 (the prior `ServicePrincipal.internalId` doc tautology finding, originally cited at `model.ts:809-810`): Folded into L10 — the documentation-only aspect (per-type self-referential phrasing and the `userId` typo) is what remains. +- #M8 (the prior `workspaceAssignmentDetail` finding) → renumbered M4. +- #M10 (the prior `servicePrincipal` finding) → renumbered M5. +- #M11 (the prior `Group.accountId` doc finding) → renumbered M6. +- #M12 (the prior `` markup finding) → renumbered M7. +- #M15 (the prior "TBD" doc finding) → renumbered M8. +- #M16 (the prior `resolveByExternalId` URL casing finding) → renumbered M9. +- #M17 (the prior permissions-vs-entitlements finding) → renumbered M10. +- #H4 (the prior `PrincipalType` enum-name prefix finding, originally cited at `model.ts:18-23`): Pruned on 2026-05-20 — proto-style enum-name prefix on members is intentional and not a real issue. +- #M4 (the prior `WorkspacePermission.USER_PERMISSION` enum-member suffix finding, originally cited at `model.ts:43-48`): Pruned on 2026-05-20 — proto-style enum-name affix on members is intentional and not a real issue. +- #H7 (the prior "every enum has `_UNSPECIFIED` zero value" finding, originally cited at `model.ts:8, 19, 28, 37, 44, 54`): Pruned on 2026-05-20 — proto3 mandates a zero-value enum member; `UNSPECIFIED` is intentional. diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md index eef22b47..6bae310c 100644 --- a/.agent/naming-audit/indexes.md +++ b/.agent/naming-audit/indexes.md @@ -1,244 +1,235 @@ # Naming Audit: indexes -**Path:** `packages/indexes/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/vectorsearch/src/v1/` (formerly `packages/indexes/src/v1/`; merged with the vector-search endpoint API) **Versions audited:** v1 **Inferred domain:** Databricks Vector Search index management — CRUD for `VectorIndex` (Delta-Sync or Direct-Access subtypes), data upsert/delete on direct-access indexes, vector/text/hybrid query, scan, pagination, and sync trigger. Routes under `/api/2.0/vector-search/indexes`. -**Total weird names flagged:** 37 +**Total weird names flagged:** 33 ## Summary | Severity | Count | | --- | --- | -| High | 12 | -| Medium | 17 | +| High | 10 | +| Medium | 15 | | Low | 6 | | Observation | 2 | ## High severity -### 1. Package name `indexes` is generic — does not say "vector search" — `packages/indexes/` -- **Why weird:** The package is exclusively about Databricks Vector Search indexes (every URL is `/api/2.0/vector-search/indexes/...` — `client.ts:94, 120, 154, 179, 213, 264, 290, 319, 345, 371`). Every public type is prefixed `Vector...` or contains `VectorIndex`. The package name `indexes` is the most generic possible word — it could equally mean SQL indexes, Unity Catalog indexes, search indexes, dataframe indexes, online table indexes, or array/iterator indexes. A user scanning the workspace cannot tell what `indexes` covers without opening the source. -- **Category:** 1 (vague/generic), 6 (misleading: collides with multiple "index" concepts in the Databricks ecosystem). -- **Suggested name:** `vector-search`, `vector-search-indexes`, or `vectorsearch-indexes`. At minimum, add a module-level JSDoc on `index.ts` (currently missing) stating "Databricks Vector Search index management". -- **Rationale:** Package names are the first-line filter; `indexes` says nothing about the domain. Sibling packages already exist (`vectorsearchendpoints`, presumably) for the endpoint side — naming should be parallel. - -### 2. Package name singular/plural mismatch — `packages/indexes/` vs `VectorIndex` type — `index.ts`, `model.ts:425` -- **Why weird:** The package is plural (`indexes`) but the central exported type is `VectorIndex` (singular). The Go SDK reference uses the singular `vectorsearchindex` package name (per repo convention in `databricks/sdk-go`). JS-style alternative spellings ("indices") are not used. The plural directory name reads as "the indexes API" — a collection — while every type/method works on one index at a time. -- **Category:** 9 (singular/plural mismatch). -- **Suggested name:** `vectorsearchindex` (singular, mirrors Go reference) or commit to plural with all "list/collection" connotations made explicit. Either rename to singular or accept the plural everywhere (which the codebase does not). -- **Rationale:** The repository convention elsewhere is singular package names matching the central noun (e.g. `clusters`, `catalogs` are plural where the *resource* is plural, while single-resource packages use singular). The `Index` resource is singular — package should match. - -### 3. `MiniVectorIndex` — `src/v1/model.ts:252` +### 1. `MiniVectorIndex` — `src/v1/model.ts:376` - **Why weird:** "Mini" is a cryptic informal qualifier. No JSDoc explains what it means. By inspection it is a list-view subset of `VectorIndex` (same fields), used as the element type in `ListVectorIndexResponse.vectorIndexes`. Industry conventions for "the lighter view returned by a list endpoint" include `Summary`, `ListItem`, `Brief`, `Ref`, `Preview` — never `Mini`. - **Category:** 5 (cryptic abbreviation), 1 (vague qualifier). -- **Suggested name:** `VectorIndexSummary` or `VectorIndexListItem`. Add JSDoc explaining why it differs from `VectorIndex` (in fact, the fields are identical in this version — see #4). +- **Suggested name:** `VectorIndexSummary` or `VectorIndexListItem`. Add JSDoc explaining why it differs from `VectorIndex` (in fact, the fields are identical in this version — see #2). - **Rationale:** `Mini` does not convey "subset of the full type returned by list operations". Naming the type after its role (`Summary`/`ListItem`) makes the relationship to `VectorIndex` discoverable. -### 4. `MiniVectorIndex` is structurally identical to `VectorIndex` — `src/v1/model.ts:252-275` vs `:425-448` -- **Why weird:** Both types declare exactly the same nine fields with the same types and (where present) the same JSDoc lines. They are duplicates. The only signal of intent is the prefix "Mini". If they are meant to be the same, one should be an alias; if they differ, the difference must be documented. +### 2. `MiniVectorIndex` is structurally identical to `VectorIndex` — `src/v1/model.ts:376-399` vs `:572-595` +- **Why weird:** Both types declare exactly the same nine fields (`name`, `endpointName`, `primaryKey`, `indexType`, `indexSpec`, `status`, `creator`, `indexSubtype`) with the same types and (where present) the same JSDoc lines. They are duplicates. The only signal of intent is the prefix "Mini". If they are meant to be the same, one should be an alias; if they differ, the difference must be documented. - **Category:** 12 (duplicate concept). - **Suggested name:** Either `export type VectorIndexSummary = VectorIndex;` (with a comment noting wire-format identity), or drop one entirely. If the API intends them to diverge later, document the upcoming difference. - **Rationale:** Duplicating ~25 lines of type definition with no semantic distinction is a maintenance hazard. -### 5. `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:109-142` vs `model.ts:144-177` -- **Why weird:** Two distinct exported types with the same ten fields, same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream quirk that should be flattened in TS. +### 3. `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:175-205` vs `model.ts:207-237` +- **Why weird:** Two distinct exported types with the same eight fields (`sourceTable`, `embeddingSourceColumns`, `embeddingVectorColumns`, `pipelineType`, `pipelineId`, `embeddingWritebackTable`, `columnsToSync`, `columnsToIndex`), same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream quirk that should be flattened in TS. - **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix). - **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec`), or document why the request version differs. If the upstream API truly has divergence, list the diverging fields explicitly. - **Rationale:** The asymmetry with `DirectAccessVectorIndexSpec` (no separate request variant) shows the duplication is gratuitous, not necessary. -### 6. `UpsertDeleteDataStatus` — single enum shared by both upsert and delete — `src/v1/model.ts:39-43` +### 4. `UpsertDeleteDataStatus` — single enum shared by both upsert and delete — `src/v1/model.ts:51-55` - **Why weird:** The enum name is two-verb (`Upsert` AND `Delete`) joined into one noun-prefix. Reads as "the status of an upsert-delete operation" — but there is no such thing as an "upsert-delete". It is the response shape for two separate operations. Conventionally each operation has its own response type or the shared type uses a neutral name. - **Category:** 13 (verb-tense / verb-coupling), 7 (overly verbose by merging two verbs), 1 (generic "Status"). - **Suggested name:** `DataModificationStatus` or `OperationStatus`. Or split into `UpsertStatus` and `DeleteStatus` aliases if the back-end is really sharing one. -- **Rationale:** Two-verb compound nouns are unusual and confusing. Same problem exists on `UpsertDeleteDataResult` (model.ts:407). +- **Rationale:** Two-verb compound nouns are unusual and confusing. Same problem exists on `UpsertDeleteDataResult` (model.ts:554). -### 7. `UpsertDeleteDataResult` — same two-verb compound — `src/v1/model.ts:407` -- **Why weird:** Same dual-verb naming as #6. The JSDoc on the field where it is used ("Result of the upsert or delete operation" — model.ts:97, 403) confirms the verbs are *alternatives*, not a sequence. +### 5. `UpsertDeleteDataResult` — same two-verb compound — `src/v1/model.ts:554` +- **Why weird:** Same dual-verb naming as #4. The JSDoc on the field where it is used ("Result of the upsert or delete operation" — model.ts:155, 550) confirms the verbs are *alternatives*, not a sequence. - **Category:** 13 (verb-tense), 7 (verbose), 1 (generic). - **Suggested name:** `DataMutationResult` or split into `UpsertDataResult` / `DeleteDataResult` aliases. -- **Rationale:** Same as #6. +- **Rationale:** Same as #4. -### 8. Method names follow Go pattern `verbVectorIndex` not idiomatic JS `verbIndex` — `client.ts:90, 116, 150, 175, 209, 260, 286, 315, 341, 367` -- **Why weird:** Eleven methods: `createVectorIndex`, `deleteDataVectorIndex`, `deleteVectorIndex`, `getVectorIndex`, `listVectorIndex`, `listVectorIndexIter`, `queryVectorIndex`, `queryVectorIndexNextPage`, `scanVectorIndex`, `syncVectorIndex`, `upsertDataVectorIndex`. The package is exclusively about vector indexes — there is no ambiguity to disambiguate against. Repeating `VectorIndex` in every method name doubles their length to no purpose. The client is already `IndexesClient` (or implicitly scoped via `import { Client } from '@databricks/sdk-indexes'`). -- **Category:** 8 (redundant suffix), 7 (overly verbose), 14 (Go-style — Go SDK uses receiver methods so the package prefix is implicit, but in JS we re-add it). -- **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.list()` paginator, `client.query()`, `client.queryNextPage()`, `client.scan()`, `client.sync()`, `client.upsertData()`, `client.deleteData()`, `client.delete()`. Some collide with reserved words (`delete`) — those few can keep the `...Index` suffix. -- **Rationale:** The repetition is mechanical Go-port baggage. Other SDK packages in the workspace expose `client.get()`, `client.list()` directly. +### 6. Method names follow Go pattern `verbVectorIndex` not idiomatic JS `verbIndex` — `client.ts:148, 174, 233, 283, 365, 398, 474, 500, 529, 555, 581` +- **Why weird:** Eleven methods: `createVectorIndex`, `deleteDataVectorIndex`, `deleteVectorIndex`, `getVectorIndex`, `listVectorIndex`, `listVectorIndexIter`, `queryVectorIndex`, `queryVectorIndexNextPage`, `scanVectorIndex`, `syncVectorIndex`, `upsertDataVectorIndex`. The client now also exposes endpoint methods (`createEndpoint`, etc.) — so the `VectorIndex` suffix does serve a disambiguation role here, but every method name still carries 11+ characters of repetition that the JSDoc and URL already make clear. The Go SDK uses receiver methods so the package prefix is implicit, but in JS we re-add it. +- **Category:** 8 (redundant suffix), 7 (overly verbose), 14 (Go-style). +- **Suggested name:** Group the index methods under a sub-namespace (`client.indexes.create()`, `client.indexes.query()`, ...) instead of repeating `VectorIndex` in every method. Same pattern would split the endpoint methods (`client.endpoints.create()`, etc.). +- **Rationale:** The repetition is mechanical Go-port baggage. Sub-namespacing also separates the two resource families (endpoints, indexes) that now live in one client. -### 9. `name` is the resource identifier on every Request type — meaning is overloaded — multiple sites -- **Why weird:** Fifteen Request/response types use a bare `name?: string` for what is actually the full index identifier (typically a Unity Catalog qualified name like `main.schema.index`). Types affected: `CreateVectorIndexRequest.name` (model.ts:64), `DeleteDataVectorIndexRequest.name` (model.ts:89), `DeleteVectorIndexRequest.name` (model.ts:103), `GetVectorIndexRequest.name` (model.ts:216), `MiniVectorIndex.name`, `QueryVectorIndexNextPageRequest.name` (model.ts:280), `QueryVectorIndexRequest.name` (model.ts:289), `ScanVectorIndexRequest.name` (model.ts:365), `SyncVectorIndexRequest.name` (model.ts:387), `UpsertDataVectorIndexRequest.name` (model.ts:395), `VectorIndex.name` (model.ts:427). JSDoc on every one says "Name of the index" — but a UC three-part name is more than a "name", it's a path/identifier. +### 7. `name` is the resource identifier on every Request type — meaning is overloaded — multiple sites +- **Why weird:** Many Request/response types use a bare `name?: string` for what is actually the full index (or endpoint) identifier (typically a Unity Catalog qualified name like `main.schema.index`). Types affected: `CreateVectorIndexRequest.name` (model.ts:115), `DeleteDataVectorIndexRequest.name` (model.ts:147), `DeleteVectorIndexRequest.name` (model.ts:169), `GetVectorIndexRequest.name` (model.ts:328), `MiniVectorIndex.name` (model.ts:378), `QueryVectorIndexNextPageRequest.name` (model.ts:427), `QueryVectorIndexRequest.name` (model.ts:436), `ScanVectorIndexRequest.name` (model.ts:512), `SyncVectorIndexRequest.name` (model.ts:534), `UpsertDataVectorIndexRequest.name` (model.ts:542), `VectorIndex.name` (model.ts:574). JSDoc on every one says "Name of the index" — but a UC three-part name is more than a "name", it's a path/identifier. - **Category:** 15 (generic field name losing meaning), 19 (underspecified ID). - **Suggested name:** `indexFullName`, `indexId`, or at least add JSDoc clarifying the expected format ("three-part Unity Catalog identifier `..`"). - **Rationale:** `name` is too generic when the value is a structured path. Users reading `req.name = "foo"` may send a bare name and get a 404. -### 10. `endpointName` field for the *index endpoint* — generic name shared across packages — `model.ts:65, 233, 256, 282, 429` -- **Why weird:** Five sites use `endpointName?: string`. There is no JSDoc disambiguation between "vector search endpoint", "model serving endpoint", "external endpoint", "AI gateway endpoint" — all are Databricks concepts. The `EmbeddingSourceColumn.embeddingModelEndpointName` (model.ts:200) shows the SDK *does* qualify endpoint references when ambiguous, but here it does not. +### 8. `endpointName` field for the *index endpoint* — generic name shared across packages — `model.ts:117, 357, 380, 429, 576` +- **Why weird:** Five sites use `endpointName?: string`. There is no JSDoc disambiguation between "vector search endpoint", "model serving endpoint", "external endpoint", "AI gateway endpoint" — all are Databricks concepts. The `EmbeddingSourceColumn.embeddingModelEndpointName` (model.ts:260) shows the SDK *does* qualify endpoint references when ambiguous, but here it does not. - **Category:** 15 (generic field name), 19 (underspecified ID). - **Suggested name:** `vectorSearchEndpointName` or add JSDoc clarifying it is "the Vector Search endpoint serving this index". The terse `endpointName` is fine *if* combined with type-level JSDoc. - **Rationale:** The package owns a `VectorIndex` resource that is hosted on a *vector-search* endpoint — but a reader who jumps to a method signature sees only `endpointName` and may guess wrong. -### 11. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:315` vs `model.ts:344` -- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 315, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 344) inside the nested reranker parameters type. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:316-321) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. +### 9. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462` vs `model.ts:491` +- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 462, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 491) inside the nested reranker parameters type. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:463-468) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. - **Category:** 12 (duplicate concept), 6 (misleading — which one wins?). - **Suggested name:** Drop one, or document the precedence. If one is for input and the other for output/echo, name them accordingly. - **Rationale:** Users will set the wrong field. Worth raising upstream. -### 12. `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` — `model.ts:133-134, 168-169` -- **Why weird:** `effective*` prefix usually marks a *response-only* computed field that reflects the inherited/resolved value from policies (see `database` package finding #11). But here these fields appear on the **Request** variant too (`DeltaSyncVectorIndexSpecRequest` lines 167-169). They cannot be both client-supplied *and* server-computed. Also `effectiveUsagePolicyId` has zero JSDoc — line 134/169 are bare. -- **Category:** 6 (misleading — "effective" implies output-only on a request type), 17 (inconsistent: budget has JSDoc, usage does not). -- **Suggested name:** Either remove the `effective*` fields from the Request variant, or document the read-only contract. Add the missing JSDoc on `effectiveUsagePolicyId`. -- **Rationale:** Same lakebase-style `effective*` leak as elsewhere — but here it leaks into the request shape, which is incoherent. +### 10. `usagePolicyId` field has tentative JSDoc — `CreateEndpointRequest.usagePolicyId` — `model.ts:104` +- **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". Exposing a public API field whose JSDoc admits the migration is incomplete invites runtime ambiguity: today the field is silently ignored (or partially handled) and tomorrow it activates. Callers cannot tell which. +- **Category:** 6 (misleading: present but not (yet) honored), 17 (parallel to `budgetPolicyId` which works today, with no behavioural distinction). +- **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behaviour and the rollout date. +- **Rationale:** "Once we've migrated" leaves the contract undefined. ## Medium severity -### 13. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:23-27` +### 11. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:29-33` - **Why weird:** Enum exposes a sentinel value `VECTOR` whose JSDoc reads "Not supported. Use `HYBRID` instead." Exporting unsupported values inflates the enum and forces every consumer to filter or document them away. - **Category:** 6 (misleading: present but not supported), 18 (the value `VECTOR` is also a tautology when inside an enum called `IndexSubtype` describing a vector-search index — every value is a kind of "vector"). - **Suggested name:** Remove `VECTOR` from the enum, or rename the enum to `VectorIndexSubtype` and call the values `FullText | Hybrid`. Either way, eliminate the dead value. - **Rationale:** Unused enum members are bug magnets. -### 14. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:23, 50` +### 12. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:29, 62` - **Why weird:** `IndexSubtype` = `{VECTOR, FULL_TEXT, HYBRID}` (search semantics). `VectorIndexType` = `{DELTA_SYNC, DIRECT_ACCESS}` (data residency / sync model). Both are exposed as `index*Type*` fields. Same prefix word, different axes. Beginner users will conflate them. - **Category:** 6 (misleading: both look like "the type" of the index), 17 (inconsistent naming for two type axes). - **Suggested name:** Rename to disambiguate: `IndexSearchMode` (for subtype) and `IndexBackingType` / `IndexStorageType` (for the DELTA_SYNC/DIRECT_ACCESS axis). Or `IndexSearchKind` and `IndexSyncMode`. - **Rationale:** Two parallel `*Type` enums make the API harder to learn. The current names are technically correct but functionally ambiguous. -### 15. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:34-37` -- **Why weird:** All four enums (`IndexSubtype`, `PipelineType`, `UpsertDeleteDataStatus`, `VectorIndexType`) use `UPPER_SNAKE_CASE` for member names. Google TS Style Guide §9.3 recommends `UpperCamelCase` for enum members. The codebase is mixed (some enums use camelCase elsewhere). The values are also the wire-protocol strings — wire is `UPPER_SNAKE` legitimately, but the TS *identifier* can be `Triggered` mapping to wire `'TRIGGERED'`. +### 13. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:40-43` +- **Why weird:** All enums (`EndpointType`, `IndexSubtype`, `PipelineType`, `ScalingChangeState`, `UpsertDeleteDataStatus`, `VectorIndexType`, `EndpointStatus_State`) use `UPPER_SNAKE_CASE` for member names. Google TS Style Guide §9.3 recommends `UpperCamelCase` for enum members. The codebase is mixed (some enums use camelCase elsewhere). The values are also the wire-protocol strings — wire is `UPPER_SNAKE` legitimately, but the TS *identifier* can be `Triggered` mapping to wire `'TRIGGERED'`. - **Category:** 3 (acronym/casing inconsistency), 14 (Go-style). - **Suggested name:** `PipelineType.Triggered | Continuous`, with explicit `= 'TRIGGERED'` wire values. Or accept the wire-form names and apply them consistently across all packages. - **Rationale:** Style consistency across the workspace; preference for camelCase enum members aligns with the Google TS Style Guide. -### 16. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:204` +### 14. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:264` - **Why weird:** Field name reads as a sentence (`modelEndpointName ForQuery`). JS field-naming convention is noun phrases, not "for"-clauses. Compare with adjacent `embeddingModelEndpointName` (also long, but a noun phrase). - **Category:** 14 (Java-ish "ForX" suffix), 7 (verbose). - **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. - **Rationale:** `for`-clauses in identifiers are uncommon in JS. The renaming aligns it with the adjacent field. -### 17. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:113-115, 149-150, 181, 189` +### 15. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:179-181, 211-213, 241, 249` - **Why weird:** Two parallel array fields on three different types (`DeltaSyncVectorIndexSpec`, `DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`). One holds source text columns to be embedded; the other holds pre-computed vector columns. Both arrays use *different* element types (`EmbeddingSourceColumn` vs `EmbeddingVectorColumn`) — good — but the field names look near-identical at a glance. - **Category:** 6 (visually confusable pair), 15 (the qualifier "Source"/"Vector" is doing all the work). - **Suggested name:** `textColumns` + `vectorColumns`, or `embeddingTextColumns` + `embeddingVectorColumns`. Anything to widen the gap between the two names. - **Rationale:** Pairs of similarly named array fields are a known footgun. A user typing `embedding` will autocomplete the wrong one. -### 18. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:127-141, 161-176` +### 16. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:197-204, 229-236` - **Why weird:** Two fields on the same type, JSDoc says they are aliases ("[Optional] Alias for columns_to_sync. Select the columns to include in the vector index. ... Only one of columns_to_sync or columns_to_index may be specified.") Having two fields that mean the same thing in one struct, where the API expects exactly one to be set, is a recipe for runtime errors. - **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). - **Suggested name:** Deprecate one in the SDK (mark `columnsToSync` as `@deprecated` if `columnsToIndex` is the new canonical), or merge them with a runtime validation. - **Rationale:** API-level aliases are upstream policy, but the SDK should clearly mark the deprecated alias. -### 19. `pipelineId` is an underspecified ID — `model.ts:123, 158` +### 17. `pipelineId` is an underspecified ID — `model.ts:189, 221` - **Why weird:** Field type is `string` with JSDoc "The ID of the pipeline that is used to sync the index." No format documented — is it a UUID, a numeric ID, a path? Compare with `effectiveBudgetPolicyId` which uses the same generic `string` but at least the policy ID is a known Databricks pattern. - **Category:** 19 (underspecified ID), 15 (generic). - **Suggested name:** Keep the name but improve the JSDoc with the expected ID format and a link to the Pipelines API. - **Rationale:** Without format hints, users will struggle to construct the value. -### 20. `effectiveBudgetPolicyId` on a *request* type without JSDoc explanation — `model.ts:133, 168` -- **Why weird:** See finding #12. Specifically, the field is on `DeltaSyncVectorIndexSpec` (response side) *and* `DeltaSyncVectorIndexSpecRequest` (request side). On the request side, "effective" is incoherent — there is no "effective" until the server resolves it. -- **Category:** 6 (misleading on the request side), 17 (same field appears in both request and response, even when only meaningful on one). -- **Suggested name:** On `DeltaSyncVectorIndexSpecRequest`, drop the field (it cannot be set), or rename to `budgetPolicyIdOverride`. -- **Rationale:** See #12. - -### 21. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:397` +### 18. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:544` - **Why weird:** `UpsertDataVectorIndexRequest.inputsJson: string` is "JSON string representing the data to be upserted." The TS surface forces the caller to call `JSON.stringify()` themselves, then the marshaling layer wraps the request body in `JSON.stringify(...)` *again*. Double-encoded payloads are a well-known JSON antipattern. - **Category:** 6 (misleading — the field is JSON-in-JSON), 1 (generic — "inputs" tells you nothing about *what*). - **Suggested name:** Expose as `inputs: JsonValue[]` (or whatever the row shape is) and let the SDK serialize, OR keep `inputsJson` but rename to `inputsJsonString` and document the double-encoding. -- **Rationale:** Same problem with `filtersJson` (see #22) and `schemaJson` (see #23). All three are wire-protocol leaks that should be normalized at the SDK boundary. +- **Rationale:** Same problem with `filtersJson` (see #19) and `schemaJson` (see #20). All three are wire-protocol leaks that should be normalized at the SDK boundary. -### 22. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:305` -- **Why weird:** Same JSON-in-JSON pattern as #21. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. +### 19. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:452` +- **Why weird:** Same JSON-in-JSON pattern as #18. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. - **Category:** 6 (misleading), 1 (generic). - **Suggested name:** Expose as `filters?: Record` and serialize internally. Or rename `filtersJsonString`. -- **Rationale:** Same as #21. +- **Rationale:** Same as #18. -### 23. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:187` +### 20. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:247` - **Why weird:** Same pattern. The field is "The schema of the index in JSON format. Supported types are `integer`, `long`, `float`, `double`, `boolean`, `string`, `date`, `timestamp`." A typed schema descriptor would be far more discoverable. - **Category:** 6 (misleading), 1 (generic). - **Suggested name:** Expose as a typed shape, or rename `schemaJsonString` and add JSDoc warning. -- **Rationale:** Same as #21. +- **Rationale:** Same as #18. -### 24. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:125, 160` +### 21. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:191, 223` - **Why weird:** "Writeback" run together with "embedding" plus "Table" forms a hard-to-parse triple-noun. Pronunciation: "embed-ding-write-back-table". JSDoc clarifies meaning ("[Optional] Name of the Delta table to sync the vector index contents and computed embeddings to") — but the field name is opaque without it. - **Category:** 7 (overly verbose), 14 (Go-style smushed identifier). - **Suggested name:** `writebackTableName`, `embeddingsTableName`, or `computedEmbeddingsTable`. - **Rationale:** Readability of compound nouns degrades fast past 2 words. -### 25. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:223` +### 22. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:335` - **Why weird:** JSDoc says: "If true, the URL returned for the index is guaranteed to be compatible with the reranker. Currently this means we return the CP URL regardless of how the index is being accessed. If not set or set to false, the URL may still be compatible with the reranker depending on what URL we return." So the flag toggles *which URL is returned*, not whether the index itself is reranker-compatible. The name suggests the operation *ensures compatibility*, but it actually just changes URL format. - **Category:** 6 (misleading), 1 (vague boolean). - **Suggested name:** `useControlPlaneUrl`, `returnControlPlaneUrl`, or `rerankerCompatibleUrl`. - **Rationale:** Boolean names should describe the side effect, not an aspirational outcome. -### 26. `numResults` field name in two places — `model.ts:291, 367` +### 23. `numResults` field name in two places — `model.ts:438, 514` - **Why weird:** Two unrelated requests (`QueryVectorIndexRequest`, `ScanVectorIndexRequest`) both name the result-count field `numResults`. JS convention is `limit` (matching SQL `LIMIT`, REST `?limit=`) or `pageSize`. `numResults` is Python/SQL-ish. - **Category:** 14 (Python/SQL-style), 17 (cross-package inconsistency — other paged APIs use `pageSize` or `limit`). - **Suggested name:** `limit` (matches HTTP query param and most JS libs) or `pageSize`. - **Rationale:** Aligning with `limit`/`pageSize` reduces friction. -### 27. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:313` +### 24. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:460` - **Why weird:** JSDoc says: "The query type to use. Choices are `ANN` and `HYBRID` and `FULL_TEXT`. Defaults to `ANN`." Three known values, but typed as `string` — not an enum. Users get no autocomplete, no compile-time check. - **Category:** 1 (generic typing), 6 (misleading typing). - **Suggested name:** Introduce an enum `QueryType.Ann | Hybrid | FullText` (these overlap with `IndexSubtype` values but represent different concepts). - **Rationale:** `string` for a closed set of values is a known antipattern. -### 28. `RerankerConfig.model` field — generic name "model" — `model.ts:338` +### 25. `RerankerConfig.model` field — generic name "model" — `model.ts:485` - **Why weird:** Bare `model?: string` with no JSDoc. In ML SDKs "model" is overloaded (ML model, data model, type model). The field probably holds a model endpoint name or model identifier. - **Category:** 1 (generic), 15 (generic field losing meaning). - **Suggested name:** `modelEndpointName`, `modelName`, or `rerankerModel`. - **Rationale:** Document what kind of identifier this is. -### 29. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:382` +## Low severity + +### 26. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:529` - **Why weird:** `Struct` is the SDK's wire-format for a JSON-like map, and `MapStringValueEntry` is `{key: string, value: Value}`. The TS shape is "an array of key-value entries" rather than `Record`. Idiomatic JS would use a plain object or `Map`. - **Category:** 14 (array-of-entries map encoding leaks to TS). - **Suggested name:** Flatten to `Record` at the TS boundary; keep the entry-array shape on the wire. - **Rationale:** Forcing users to map an array of `{key, value}` pairs into a record is friction the SDK could remove. -## Low severity - -### 30. `Value` — single-word generic name for a discriminated union — `model.ts:414-423` +### 27. `Value` — single-word generic name for a discriminated union — `model.ts:561-570` - **Why weird:** A bare type called `Value` is uninformative. It is the SDK's wire-form scalar wrapper (number/string/bool/struct/list). Stronger candidates: `ScalarValue`, `WireValue`, `VectorIndexValue`. - **Category:** 1 (generic). - **Suggested name:** `ScalarValue` or move to the core wkt package and rename `wkt.Value`. - **Rationale:** `Value` collides with too many concepts. -### 31. `Struct` — generic single-word type name — `model.ts:380` +### 28. `Struct` — generic single-word type name — `model.ts:527` - **Why weird:** "Struct" is a language keyword in many languages (Go, C, Rust). In JS/TS it is a vague C-style holdover. The type is "a row of a vector index" (per the JSDoc). - **Category:** 1 (generic), 10 (potential reserved-word collision in TS-flow tools). - **Suggested name:** `IndexRow` or `VectorIndexRow`. - **Rationale:** A more domain-specific name is more discoverable. -### 32. `MapStringValueEntry` — verbose name for a key-value pair — `model.ts:245` +### 29. `MapStringValueEntry` — verbose name for a key-value pair — `model.ts:369` - **Why weird:** Reads as "Map of String to Value Entry". JSDoc says "Key-value pair." Just call it that. - **Category:** 7 (verbose). - **Suggested name:** `KeyValue` or `StructField`. - **Rationale:** Less verbose, more idiomatic. -### 33. `ResultManifest` — Java/Spring-flavored noun — `model.ts:356-361` +### 30. `ResultManifest` — Java/Spring-flavored noun — `model.ts:503-508` - **Why weird:** "Manifest" in a query-result context is unusual JS phrasing. JSDoc says "Metadata about the result set." More common in JS: `Metadata`, `Schema`, `Info`. - **Category:** 14 (Java-style), 1 (mildly generic). - **Suggested name:** `ResultMetadata` or `ResultSchema`. - **Rationale:** Aligns with idiomatic JS. -### 34. `ResultData` — generic two-word noun — `model.ts:348-353` +### 31. `ResultData` — generic two-word noun — `model.ts:495-500` - **Why weird:** Type is "Data returned in the query result." `ResultData` is generic; `QueryResultData` or just `Rows` would be more specific. - **Category:** 1 (generic). - **Suggested name:** `QueryResultData` or `ResultRows`. - **Rationale:** Disambiguate. -### 35. `lastPrimaryKey` field on request + response — `model.ts:369, 377` -- **Why weird:** Same field name used as a cursor on both request (input) and response (output). On the response it is fine ("last primary key in this page"), on the request it is a pagination cursor named after its expected source rather than its role. JS convention would be `pageToken` / `cursor` / `afterKey`. -- **Category:** 17 (inconsistency with `pageToken` used elsewhere — model.ts:235, 284), 14 (database-cursor-style name). -- **Suggested name:** Both could use `cursor` or `afterPrimaryKey` (request) + `lastPrimaryKey` (response). -- **Rationale:** The package uses `pageToken` for pagination elsewhere; `lastPrimaryKey` is a one-off naming convention for scan. - ## Observation -### 36. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` +### 32. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` - **Why weird:** Cross-package import. `Call` is the most generic possible name for "a network operation". - **Category:** 1 (generic), cross-package observation. - **Suggested name:** `RetryableCall`, `SdkCall`. Out of scope for this audit. - **Rationale:** Tracked for cross-package consistency. -### 37. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:29` -- **Why weird:** The mini variant (see #3, #4) is re-exported as part of the public API. If the intent is for it to be an internal implementation detail, it should not be in `index.ts`. +### 33. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:42` +- **Why weird:** The mini variant (see #1, #2) is re-exported as part of the public API. If the intent is for it to be an internal implementation detail, it should not be in `index.ts`. - **Category:** Observation on the public surface. -- **Suggested name:** Either rename per #3 or remove from the public surface. +- **Suggested name:** Either rename per #1 or remove from the public surface. - **Rationale:** Consumers will use whatever is exported; if `MiniVectorIndex` is a name we'd prefer not to commit to publicly, it should be hidden. + +## Fixed + +- #1 Package name `indexes` is generic (originally cited at `packages/indexes/`): Fixed in regeneration on 2026-05-20 — package renamed to `vectorsearch` and merged with the vector-search endpoint API; the package name now matches the domain. +- #2 Package name singular/plural mismatch (originally cited at `packages/indexes/` vs `VectorIndex`, `model.ts:425`): Fixed in regeneration on 2026-05-20 — package renamed to `vectorsearch` (a domain name, not a plural list), resolving the singular/plural conflict. +- #12 `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` (originally cited at `model.ts:133-134, 168-169`): Fixed in regeneration on 2026-05-20 — both `effective*` fields removed from `DeltaSyncVectorIndexSpec` and `DeltaSyncVectorIndexSpecRequest`; budget/usage policy IDs now live only on `Endpoint`/`CreateEndpointRequest` where the `effective*` distinction is coherent. +- #20 `effectiveBudgetPolicyId` on a request type without JSDoc explanation (originally cited at `model.ts:133, 168`): Fixed in regeneration on 2026-05-20 — `effective*` fields removed from `DeltaSyncVectorIndexSpecRequest`; this finding is now fully covered by #12. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 5369f890..74444add 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -5,8 +5,8 @@ **Version audited:** `v2` **Files audited:** -- `src/v2/model.ts` (1295 lines, read in full) -- `src/v2/client.ts` (213 lines, read in full) +- `src/v2/model.ts` (1259 lines, read in full) +- `src/v2/client.ts` (223 lines, read in full) - `src/v2/utils.ts` (150 lines, read in full) - `src/v2/index.ts` (43 lines, read in full) @@ -21,27 +21,25 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 9 | -| Medium | 16 | -| Low | 18 | +| High | 10 | +| Medium | 11 | +| Low | 16 | | Observation | 7 | -| **Total** | **50**| +| **Total** | **44**| ### Top themes -1. **Massive structural duplication.** `CreateInstancePool` (28 fields), - `EditInstancePool` (29 fields), `GetInstancePool_Response` (30 fields), and - `InstancePoolAndStats` (30 fields) are byte-identical apart from one or two - fields. They could share a single base type. +1. **Massive structural duplication.** `CreateInstancePoolRequest` (28 fields), + `EditInstancePoolRequest` (29 fields), `GetInstancePoolRequest_Response` + (30 fields), and `InstancePoolAndStats` (30 fields) are byte-identical + apart from one or two fields. They could share a single base type. 2. **`InstancePool*` prefix on every type is redundant** — the package is already `instancepools`; the v2 namespace is even smaller. `Pool` (or even nothing) would do for `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`. -3. **Per-cloud enum-prefix inconsistency** — `AwsAvailability` members are - unprefixed (`SPOT`, `ON_DEMAND`), but `AzureAvailability` (`SPOT_AZURE`) - and `GcpAvailability` (`PREEMPTIBLE_GCP`) repeat the enum's cloud. The - same defect exists in `clusters` (see `clusters.md` #3) — fix once at - codegen. +3. **Cross-package shape duplication** — eleven types/enums are duplicated + verbatim between this package and `clusters`. A shared `compute` module + would eliminate the dual maintenance burden. --- @@ -60,46 +58,46 @@ configuration, idle / used statistics, and pending-instance failure reporting. ### 1.2 Interfaces (`model.ts`) -| Name | Lines | Purpose | -| --------------------------------------------- | -------- | -------------------------------------------------- | -| `CreateInstancePool` | 90-172 | Request body for create — 28 fields. | -| `CreateInstancePool_CustomTagsEntry` | 175-188 | Proto-nested tag entry, dead in TS. | -| `CreateInstancePool_Response` | 191-194 | Response with single `instancePoolId`. | -| `DeleteInstancePool` | 196-199 | `{ instancePoolId?: string }`. | -| `DeleteInstancePool_Response` | 202 | Empty `{}`. | -| `DiskSpec` | 210-248 | Disk-attachment spec. | -| `DiskType` | 251-256 | Disc-union wrapper for EBS or Azure disk types. | -| `DockerBasicAuth` | 258-263 | `{ username, password }`. | -| `DockerImage` | 265-275 | `{ url, credsOneof }`. | -| `EditInstancePool` | 277-361 | Request body for edit — 29 fields. | -| `EditInstancePool_CustomTagsEntry` | 364-377 | Same as the Create variant — duplicate. | -| `EditInstancePool_Response` | 380 | Empty `{}`. | -| `GetInstancePool` | 382-385 | `{ instancePoolId?: string }`. | -| `GetInstancePool_Response` | 388-490 | 30 fields — superset of `CreateInstancePool` plus statistics. | -| `GetInstancePool_Response_CustomTagsEntry` | 493-506 | Third duplicate of the tag-entry shape. | -| `GetInstancePool_Response_DefaultTagsEntry` | 509-522 | Fourth duplicate of the tag-entry shape. | -| `InstancePoolAndStats` | 524-626 | 30 fields — duplicate of `GetInstancePool_Response`. | -| `InstancePoolAndStats_CustomTagsEntry` | 629-642 | Fifth duplicate of the tag-entry shape. | -| `InstancePoolAndStats_DefaultTagsEntry` | 645-658 | Sixth duplicate of the tag-entry shape. | -| `InstancePoolAwsAttributes` | 661-696 | AWS-specific config. | -| `InstancePoolAzureAttributes` | 699-710 | Azure-specific config. | -| `InstancePoolGcpAttributes` | 713-735 | GCP-specific config. | -| `InstancePoolStats` | 737-746 | Idle/used counters. | -| `InstancePoolStatus` | 748-756 | Wraps `pendingInstanceErrors`. | -| `ListInstancePools` | 759 | Empty `{}`. | -| `ListInstancePools_Response` | 762-764 | Wraps `instancePools` array. | -| `NodeTypeFlexibility` | 767-770 | Wraps `alternateNodeTypeIds`. | -| `PendingInstanceError` | 773-776 | `{ instanceId, message }`. | +| Name | Lines | Purpose | +| --------------------------------------------------- | -------- | -------------------------------------------------- | +| `CreateInstancePoolRequest` | 90-165 | Request body for create — 28 fields. | +| `CreateInstancePoolRequest_CustomTagsEntry` | 168-181 | Proto-nested tag entry, dead in TS. | +| `CreateInstancePoolRequest_Response` | 184-187 | Response with single `instancePoolId`. | +| `DeleteInstancePoolRequest` | 189-192 | `{ instancePoolId?: string }`. | +| `DeleteInstancePoolRequest_Response` | 195 | Empty `{}`. | +| `DiskSpec` | 203-241 | Disk-attachment spec. | +| `DiskType` | 244-249 | Disc-union wrapper for EBS or Azure disk types. | +| `DockerBasicAuth` | 251-256 | `{ username, password }`. | +| `DockerImage` | 258-268 | `{ url, credsOneof }`. | +| `EditInstancePoolRequest` | 270-347 | Request body for edit — 29 fields. | +| `EditInstancePoolRequest_CustomTagsEntry` | 350-363 | Same as the Create variant — duplicate. | +| `EditInstancePoolRequest_Response` | 366 | Empty `{}`. | +| `GetInstancePoolRequest` | 368-371 | `{ instancePoolId?: string }`. | +| `GetInstancePoolRequest_Response` | 374-469 | 30 fields — superset of `CreateInstancePoolRequest` plus statistics. | +| `GetInstancePoolRequest_Response_CustomTagsEntry` | 472-485 | Third duplicate of the tag-entry shape. | +| `GetInstancePoolRequest_Response_DefaultTagsEntry` | 488-501 | Fourth duplicate of the tag-entry shape. | +| `InstancePoolAndStats` | 503-598 | 30 fields — duplicate of `GetInstancePoolRequest_Response`. | +| `InstancePoolAndStats_CustomTagsEntry` | 601-614 | Fifth duplicate of the tag-entry shape. | +| `InstancePoolAndStats_DefaultTagsEntry` | 617-630 | Sixth duplicate of the tag-entry shape. | +| `InstancePoolAwsAttributes` | 633-668 | AWS-specific config. | +| `InstancePoolAzureAttributes` | 671-682 | Azure-specific config. | +| `InstancePoolGcpAttributes` | 685-707 | GCP-specific config. | +| `InstancePoolStats` | 709-718 | Idle/used counters. | +| `InstancePoolStatus` | 720-728 | Wraps `pendingInstanceErrors`. | +| `ListInstancePoolsRequest` | 731 | Empty `{}`. | +| `ListInstancePoolsRequest_Response` | 734-736 | Wraps `instancePools` array. | +| `NodeTypeFlexibility` | 739-742 | Wraps `alternateNodeTypeIds`. | +| `PendingInstanceError` | 745-748 | `{ instanceId, message }`. | ### 1.3 Methods (`client.ts`) -| Method | HTTP | URL path | Returns | -| -------------------- | ------ | --------------------------------- | ----------------------------- | -| `createInstancePool` | POST | `/api/2.0/instance-pools/create` | `CreateInstancePool_Response` | -| `deleteInstancePool` | POST | `/api/2.0/instance-pools/delete` | `DeleteInstancePool_Response` | -| `editInstancePool` | POST | `/api/2.0/instance-pools/edit` | `EditInstancePool_Response` | -| `getInstancePool` | GET | `/api/2.0/instance-pools/get` | `GetInstancePool_Response` | -| `listInstancePools` | GET | `/api/2.0/instance-pools/list` | `ListInstancePools_Response` | +| Method | HTTP | URL path | Returns | +| -------------------- | ------ | --------------------------------- | ------------------------------------ | +| `createInstancePool` | POST | `/api/2.0/instance-pools/create` | `CreateInstancePoolRequest_Response` | +| `deleteInstancePool` | POST | `/api/2.0/instance-pools/delete` | `DeleteInstancePoolRequest_Response` | +| `editInstancePool` | POST | `/api/2.0/instance-pools/edit` | `EditInstancePoolRequest_Response` | +| `getInstancePool` | GET | `/api/2.0/instance-pools/get` | `GetInstancePoolRequest_Response` | +| `listInstancePools` | GET | `/api/2.0/instance-pools/list` | `ListInstancePoolsRequest_Response` | ### 1.4 Other identifiers @@ -122,100 +120,87 @@ configuration, idle / used statistics, and pending-instance failure reporting. | V-04 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | | V-05 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | -### 2.2 Redundant enum prefixes — High - -| ID | Symbol | Severity | Issue | -| ----- | --------------------------------------------------- | -------- | ----- | -| E-01 | `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` | High | Every member repeats `_AZURE`. The enum is `AzureAvailability`; inside scope the cloud is implied. Compare with `AwsAvailability` (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`) which gets it right. Suggested `AzureAvailability.SPOT | ON_DEMAND | SPOT_WITH_FALLBACK`. Same defect duplicated in `clusters` (clusters.md #3) — fix at codegen. | -| E-02 | `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` | High | Same as E-01. Members redundantly carry `_GCP`. | -| E-03 | `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | `LRS` is the Azure suffix for "Locally Redundant Storage". Standard Azure terminology — keep. | -| E-04 | `EbsVolumeType.GENERAL_PURPOSE_SSD` / `THROUGHPUT_OPTIMIZED_HDD` | Low | Standard AWS EBS volume-class names. Slightly long but correct. | - -### 2.3 Acronym casing inconsistencies — High +### 2.2 Acronym casing inconsistencies — High | ID | Symbol | Severity | Issue | | ----- | ------------------------------------- | -------- | ----- | | A-01 | `InstancePoolAwsAttributes` | High | Google TS style says acronyms ≥3 chars get only-first-letter capitalised ("AWS" → "Aws"). The repo follows this (Aws/Azure/Gcp). Acceptable, but contrasts with `EbsVolumeType` where `Ebs` is only 3 chars (same rule, applied consistently). No defect — listed for parity with related audits. | -| A-02 | `InstancePoolGcpAttributes.gcpAvailability` | High | The field name re-states the cloud already implied by the parent type `InstancePoolGcpAttributes`. Compare with `InstancePoolAwsAttributes.availability` (line 663) and `InstancePoolAzureAttributes.availability` (line 701) — both unprefixed. Three sibling types, two conventions. Should be `InstancePoolGcpAttributes.availability`. | +| A-02 | `InstancePoolGcpAttributes.gcpAvailability` | High | The field name re-states the cloud already implied by the parent type `InstancePoolGcpAttributes`. Compare with `InstancePoolAwsAttributes.availability` (line 635) and `InstancePoolAzureAttributes.availability` (line 673) — both unprefixed. Three sibling types, two conventions. Should be `InstancePoolGcpAttributes.availability`. | | A-03 | `InstancePoolAwsAttributes.instanceProfileArn` | Low | "Arn" applies Google TS style for ≥3-char acronyms. Compare with `EbsVolumeType` (same package) and consistent. OK. | | A-04 | `InstancePoolGcpAttributes.localSsdCount` | Low | "Ssd" is 3 letters; same casing rule. OK. | | A-05 | `InstancePoolAzureAttributes.spotBidMaxPrice` vs `InstancePoolAwsAttributes.spotBidPricePercent` | Medium | Sibling fields describe the same concept (max price for spot bid) in opposite shapes. `MaxPrice` is an absolute USD value; `PricePercent` is relative. Names obscure this — `azureSpotBidMaxPriceUsd` and `awsSpotBidPricePercent` (or any clarifying suffix) would help. | -### 2.4 Cryptic abbreviations — Medium +### 2.3 Cryptic abbreviations — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | C-01 | `DockerImage.credsOneof` | High (also V-01) | `creds` and `Oneof` are both opaque outside Go/proto context. | -| C-02 | `BYOC` in JSDoc `"Custom Docker Image BYOC"` (`model.ts:141, 330, 459, 595`) | Medium | "Bring Your Own Container" not expanded. External readers will not know. | +| C-02 | `BYOC` in JSDoc `"Custom Docker Image BYOC"` (`model.ts:141, 323, 445, 574`) | Medium | "Bring Your Own Container" not expanded. External readers will not know. | | C-03 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | | C-04 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | | C-05 | `req`, `resp`, `httpReq`, `respBody` locals in `client.ts` | Low | Method-local; OK. | | C-06 | `opts` (`utils.ts:66`) | Low | Inside function scope; OK. | -| C-07 | `PuPr` in JSDoc `"deprecated before entering PuPr"` (`model.ts:164, 353, 482, 618`) | Medium | "Public Preview" — internal Databricks jargon. Should be expanded in JSDoc. | -| C-08 | `Fleet-V2` in JSDoc `"For pools with node type flexibility (Fleet-V2)"` | Medium | Internal codename leaking into public docs. | -| C-09 | `Mb/s` in JSDoc `"configurable throughput (in Mb/s)"` (`model.ts:168, 357, 486, 622`) | Low | Likely intended `MB/s` (megabytes per second) given the cloud-disk-throughput context; `Mb/s` (megabits) is unusual for disk throughput. Possible casing typo upstream. | +| C-07 | `Mb/s` in JSDoc `"configurable throughput (in Mb/s)"` (`model.ts:161, 343, 465, 594`) | Low | Likely intended `MB/s` (megabytes per second) given the cloud-disk-throughput context; `Mb/s` (megabits) is unusual for disk throughput. Possible casing typo upstream. | -### 2.5 Misleading names — High +### 2.4 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| M-01 | `editInstancePool()` / `EditInstancePool` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | +| M-01 | `editInstancePool()` / `EditInstancePoolRequest` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | | M-02 | `InstancePoolStatus` | High | The type carries *only* `pendingInstanceErrors`. The name promises a general "status" but the shape exposes only errors. `InstancePoolPendingErrors` or `InstancePoolFailures` would be more truthful. (`InstancePoolState` is the actual lifecycle state, on the entity itself.) | | M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 28 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | -| M-04 | `enableAutoAlternateNodeTypes` (DEPRECATED — `model.ts:164, 353, 482, 618`) | Medium | The field is marked deprecated in JSDoc but still exposed in every request and response type. The JSDoc says "This field was deprecated before entering PuPr and should no longer be used" — yet it ships. Misleading availability. | -| M-05 | `DiskSpec.diskCount`, `diskSize`, `diskIops`, `diskThroughput` | Low | Repetition of the `disk` prefix inside a type named `DiskSpec`. Inside the type, `count` / `size` / `iops` / `throughput` would suffice. Same pattern as `clusters.md` flagged elsewhere. | -| M-06 | `DiskSpec.diskIops` (no JSDoc) and `diskSpec.diskThroughput` (no JSDoc) — `model.ts:246-247` | Low | Two fields with no JSDoc. Hard to know the unit without context. (Compare neighbouring `diskSize` which documents "GiB".) | -| M-07 | `preloadedDockerImages` is plural but JSDoc says "Custom Docker Image BYOC" (singular) — `model.ts:142, 331, 460, 596` | Low | Field is `DockerImage[]`. Plural correctly matches type, but the JSDoc is misleading. | -| M-08 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | -| M-09 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | +| M-04 | `DiskSpec.diskCount`, `diskSize`, `diskIops`, `diskThroughput` | Low | Repetition of the `disk` prefix inside a type named `DiskSpec`. Inside the type, `count` / `size` / `iops` / `throughput` would suffice. Same pattern as `clusters.md` flagged elsewhere. | +| M-05 | `DiskSpec.diskIops` (no JSDoc) and `diskSpec.diskThroughput` (no JSDoc) — `model.ts:239-240` | Low | Two fields with no JSDoc. Hard to know the unit without context. (Compare neighbouring `diskSize` which documents "GiB".) | +| M-06 | `preloadedDockerImages` is plural but JSDoc says "Custom Docker Image BYOC" (singular) — `model.ts:141, 323, 445, 574` | Low | Field is `DockerImage[]`. Plural correctly matches type, but the JSDoc is misleading. | +| M-07 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | +| M-08 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | -### 2.6 Overly verbose / Redundant suffixes — Medium +### 2.5 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| O-01 | `idleInstanceAutoterminationMinutes` (5-word identifier, present in 4 types) | Medium | 33-char field. Inside a type called `CreateInstancePool` etc., `idleAutoterminationMinutes` or `idleTimeoutMinutes` would be 27 / 18 chars. The wire uses `idle_instance_autotermination_minutes` so any change is generator-side. | -| O-02 | `enableAutoAlternateNodeTypes` | Medium | "Enable auto alternate node types" — five concept words. With node-type-flexibility being the modern replacement, the field is also deprecated (see M-04). | -| O-03 | `InstancePool*` prefix on `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`, `InstancePoolAwsAttributes`, `InstancePoolAzureAttributes`, `InstancePoolGcpAttributes`, `InstancePoolState` | High | The package is already `@databricks/sdk-instancepools`. Inside the package, the prefix is redundant. `Stats`, `Status`, `AwsAttributes` would all suffice and remove ~12 chars from each name. Compare `clusters` (`clusters.md` #75) and `apps` packages, which face the same recurring issue. | -| O-04 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | -| O-05 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | -| O-06 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | -| O-07 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | +| O-01 | `idleInstanceAutoterminationMinutes` (5-word identifier, present in 4 types) | Medium | 33-char field. Inside a type called `CreateInstancePoolRequest` etc., `idleAutoterminationMinutes` or `idleTimeoutMinutes` would be 27 / 18 chars. The wire uses `idle_instance_autotermination_minutes` so any change is generator-side. | +| O-02 | `InstancePool*` prefix on `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`, `InstancePoolAwsAttributes`, `InstancePoolAzureAttributes`, `InstancePoolGcpAttributes`, `InstancePoolState` | High | The package is already `@databricks/sdk-instancepools`. Inside the package, the prefix is redundant. `Stats`, `Status`, `AwsAttributes` would all suffice and remove ~12 chars from each name. Compare `clusters` (`clusters.md` #75) and `apps` packages, which face the same recurring issue. | +| O-03 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | +| O-04 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | +| O-05 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | +| O-06 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | -### 2.7 Singular / plural mismatches — Low / High +### 2.6 Singular / plural mismatches — Low / High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| P-01 | `preloadedSparkVersions: string[]` | High (also M-08) | Plural array type but the JSDoc constrains it to at most one element. | +| P-01 | `preloadedSparkVersions: string[]` | High (also M-07) | Plural array type but the JSDoc constrains it to at most one element. | | P-02 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | -| P-03 | `ListInstancePools` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | -| P-04 | `ListInstancePools_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | +| P-03 | `ListInstancePoolsRequest` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | +| P-04 | `ListInstancePoolsRequest_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | -### 2.8 Reserved-word collisions — Medium +### 2.7 Reserved-word collisions — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | R-01 | `DockerImage.credsOneof.$case === 'basicAuth'.basicAuth: DockerBasicAuth` | Low | `basicAuth` is not a reserved word but is duplicated across the `$case` discriminator and the embedded field — `library.lib.basicAuth.basicAuth` style access. | | R-02 | None of the type names collide with TS reserved words. | — | OK. | -### 2.9 Duplicate concepts — Highest in repo +### 2.8 Duplicate concepts — Highest in repo | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| D-01 | `CreateInstancePool` (28 fields, lines 90-172) vs `EditInstancePool` (29 fields, lines 277-361) | High | Identical except `EditInstancePool` adds `instancePoolId`. Could share a base type. | -| D-02 | `GetInstancePool_Response` (30 fields, lines 388-490) vs `InstancePoolAndStats` (30 fields, lines 524-626) | High | **Byte-identical** apart from the type name. Compare line-by-line: identical field set, identical order, identical JSDoc. Two names for the same shape. | -| D-03 | `CreateInstancePool` vs the `Pool` body inside `InstancePoolAndStats` | High | All 28 config fields appear three times: once on Create, once on Edit (29), once on the entity. Codegen could project from a shared base. | +| D-01 | `CreateInstancePoolRequest` (28 fields, lines 90-165) vs `EditInstancePoolRequest` (29 fields, lines 270-347) | High | Identical except `EditInstancePoolRequest` adds `instancePoolId`. Could share a base type. | +| D-02 | `GetInstancePoolRequest_Response` (30 fields, lines 374-469) vs `InstancePoolAndStats` (30 fields, lines 503-598) | High | **Byte-identical** apart from the type name. Compare line-by-line: identical field set, identical order, identical JSDoc. Two names for the same shape. | +| D-03 | `CreateInstancePoolRequest` vs the `Pool` body inside `InstancePoolAndStats` | High | All 28 config fields appear three times: once on Create, once on Edit (29), once on the entity. Codegen could project from a shared base. | | D-04 | `InstancePoolAwsAttributes` (this package) vs `AwsAttributes` (`clusters` package) | High | Same domain (AWS attributes for a compute pool / cluster). `clusters` calls them `AwsAttributes`; this package calls them `InstancePoolAwsAttributes`. Both share many fields (availability, zoneId, instanceProfileArn, spotBid…) but `clusters` has additional fields (`ebsVolumeCount`, etc.). Cross-package duplication; a shared `compute` module would fix both. | | D-05 | `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` vs `clusters.AzureAttributes` / `clusters.GcpAttributes` | High | Same as D-04 for Azure / GCP. | | D-06 | `EbsVolumeType`, `AzureDiskVolumeType`, `AwsAvailability`, `AzureAvailability`, `GcpAvailability`, `DockerImage`, `DockerBasicAuth`, `DiskSpec`, `DiskType`, `NodeTypeFlexibility`, `PendingInstanceError` | High | All eleven types/enums are duplicated verbatim in `clusters/src/v2/model.ts` (verified via `grep`). Two packages ship eleven identical shapes. | -### 2.10 Verb-tense inconsistency — Low +### 2.9 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | T-01 | `createInstancePool`, `deleteInstancePool`, `editInstancePool`, `getInstancePool`, `listInstancePools` | Low | All present-tense imperative — consistent. | | T-02 | `preloadedDockerImages`, `preloadedSparkVersions` (past participle) | Low | Standard for fields that describe a pre-applied state. OK. | -### 2.11 Go / Java-style names — High +### 2.10 Go / Java-style names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -223,7 +208,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | G-02 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | | G-03 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | -### 2.12 Generic field names losing meaning — Medium +### 2.11 Generic field names losing meaning — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -235,13 +220,13 @@ configuration, idle / used statistics, and pending-instance failure reporting. | F-06 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | | F-07 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | -### 2.13 Field contradicting type domain — Low +### 2.12 Field contradicting type domain — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | K-01 | None observed. All fields are within their type's domain. | — | OK. | -### 2.14 Inconsistent action verbs — Medium +### 2.13 Inconsistent action verbs — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -249,16 +234,14 @@ configuration, idle / used statistics, and pending-instance failure reporting. | AV-02 | `getInstancePool()` (singular) vs `listInstancePools()` (plural) | Low | Correct REST convention. OK. | | AV-03 | `createInstancePool()` / `deleteInstancePool()` / `editInstancePool()` / `getInstancePool()` / `listInstancePools()` — only five verbs | Low | No `start`, `stop`, `pin`, etc. — instance pools are stateless from the API standpoint; the lifecycle is implicit via fewer endpoints than `clusters`. Consistent. | -### 2.15 Long enum values — Low +### 2.14 Long enum values — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| L-01 | `AzureAvailability.SPOT_WITH_FALLBACK_AZURE` (26 chars) | Medium | Combination of redundant `_AZURE` suffix (E-01) and the verbose form. Trimming the suffix gives `SPOT_WITH_FALLBACK` (18 chars), already in use for AWS. | -| L-02 | `GcpAvailability.PREEMPTIBLE_WITH_FALLBACK_GCP` (29 chars) | Medium | Same as L-01 for GCP. | -| L-03 | `EbsVolumeType.THROUGHPUT_OPTIMIZED_HDD` (24 chars) | Low | Standard AWS terminology; OK. | -| L-04 | `AzureDiskVolumeType.STANDARD_LRS` (12 chars) | Low | Short. OK. | +| L-01 | `EbsVolumeType.THROUGHPUT_OPTIMIZED_HDD` (24 chars) | Low | Standard AWS terminology; OK. | +| L-02 | `AzureDiskVolumeType.STANDARD_LRS` (12 chars) | Low | Short. OK. | -### 2.16 Underspecified IDs — Medium +### 2.15 Underspecified IDs — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -269,29 +252,164 @@ configuration, idle / used statistics, and pending-instance failure reporting. | I-05 | `NodeTypeFlexibility.alternateNodeTypeIds: string[]` | Low | Plural array of node-type IDs; scoped. OK. | | I-06 | `InstancePoolAwsAttributes.zoneId` / `InstancePoolGcpAttributes.zoneId` | Low | Both reuse `zoneId` for the AWS availability zone ("us-west-2a") and GCP availability zone ("us-west1-a"). Same name, two slightly different value formats. Acceptable cross-cloud abstraction. | -### 2.17 Type-suffix tautology — Medium +### 2.16 Type-suffix tautology — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `InstancePoolAwsAttributes` / `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` | Medium | All three carry the `Attributes` suffix and the redundant `InstancePool` prefix (see O-03). Could be `AwsAttributes` / `AzureAttributes` / `GcpAttributes` (matching `clusters`). | +| TS-01 | `InstancePoolAwsAttributes` / `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` | Medium | All three carry the `Attributes` suffix and the redundant `InstancePool` prefix (see O-02). Could be `AwsAttributes` / `AzureAttributes` / `GcpAttributes` (matching `clusters`). | | TS-02 | `InstancePoolStats` | Medium | `Stats` is already abbreviated; the `InstancePool` prefix is redundant inside this package. | | TS-03 | `InstancePoolStatus` | Medium | Same as TS-02. | | TS-04 | `InstancePoolState` (enum) | Medium | Same. Could be `State` or `PoolState`. | | TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-02). Doubly off. | | TS-06 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | -| TS-07 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-05) the type-name still echoes. | +| TS-07 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-04) the type-name still echoes. | | TS-08 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | -### 2.18 Other observations +### 2.17 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | JSDoc placeholder `` appears 17 times in this file (e.g., `" will tag all pool resources"` `model.ts:117`) | Observation | Un-substituted template placeholder leaking into the generated TS docstrings. Reader sees `` in IntelliSense. Same finding as `clusters.md` #92. | -| X-02 | `enableElasticDisk` JSDoc: "Autoscaling Local Storage: when enabled, **this instances** in this pool ..." (`model.ts:133, 322, 451, 587`) | Observation | Grammar typo in JSDoc ("this instances" → "the instances"). Same string repeated four times. | -| X-03 | TODO comment in JSDoc: `"TODO(CJ-71514): Remove this field after sufficient time has passed for all clients to migrate."` (`model.ts:165, 354, 483, 619`) | Observation | Internal Databricks ticket reference (CJ-71514) leaks into public SDK JSDoc. Same string in four request/response types. | -| X-04 | `client.ts:165-167` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | -| X-05 | `client.ts:191` `_req: ListInstancePools` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | -| X-06 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | +| X-01 | JSDoc placeholder `` appears many times in this file (e.g., `" will tag all pool resources"` `model.ts:117`) | Observation | Un-substituted template placeholder leaking into the generated TS docstrings. Reader sees `` in IntelliSense. Same finding as `clusters.md` #92. | +| X-02 | `enableElasticDisk` JSDoc: "Autoscaling Local Storage: when enabled, **this instances** in this pool ..." (`model.ts:133, 315, 437, 566`) | Observation | Grammar typo in JSDoc ("this instances" → "the instances"). Same string repeated four times. | +| X-03 | `client.ts:167-170` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | +| X-04 | `client.ts:197` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | +| X-05 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | + +### 2.18 Proto-architectural leaks + +### 1. `DockerImage.credsOneof` — model.ts:261 + +**Why:** `Oneof` is a literal protobuf-keyword suffix. The wire field uses +a proto `oneof`; the TS reader has no business knowing this. TypeScript +already encodes the union shape via the `$case` discriminator pattern, +making the suffix doubly redundant. +**Category:** Proto suffix/infix. +**Suggested:** `credentials`. +**Rationale:** Drop the proto-codegen idiom; the union type expresses the +mutual-exclusion semantics on its own. + +### 2. `DockerImage.credsOneof.$case` / `DiskType.remoteVolumeType.$case` — model.ts:246, 247, 263 + +**Why:** The `$case` discriminator key is a `ts-proto` codegen artefact +(see `ts-proto`'s "oneof=unions" mode). Native TypeScript discriminated +unions use a domain-named tag (e.g., `kind`, `type`). +**Category:** Proto suffix/infix. +**Suggested:** Replace `$case` with a domain tag such as `kind` or `type` +(e.g., `{ kind: 'basicAuth'; basicAuth: DockerBasicAuth }`). +**Rationale:** `$case` is unique to one TS-from-proto codegen tool; it +leaks the generator into the public API. + +### 3. `CreateInstancePoolRequest_Response` — model.ts:184 + +**Why:** The `_Response` underscore-nested name mirrors the proto-codegen +convention `Outer.NestedMessage`, flattened to `Outer_Nested`. TypeScript +has no nested-message concept; the underscore is purely an architectural +leak from the protobuf compiler. +**Category:** Proto suffix/infix. +**Suggested:** `CreateInstancePoolResponse`. +**Rationale:** Use a top-level response type that pairs with the request +without echoing proto nesting. + +### 4. `DeleteInstancePoolRequest_Response` — model.ts:195 + +**Why:** Same proto-nested underscore as finding #3. +**Category:** Proto suffix/infix. +**Suggested:** `DeleteInstancePoolResponse`. +**Rationale:** Same as #3. + +### 5. `EditInstancePoolRequest_Response` — model.ts:366 + +**Why:** Same proto-nested underscore as finding #3. +**Category:** Proto suffix/infix. +**Suggested:** `EditInstancePoolResponse`. +**Rationale:** Same as #3. + +### 6. `GetInstancePoolRequest_Response` — model.ts:374 + +**Why:** Same proto-nested underscore as finding #3. +**Category:** Proto suffix/infix. +**Suggested:** `GetInstancePoolResponse` (or fold into the entity type +`InstancePool` since the shape is identical to `InstancePoolAndStats`). +**Rationale:** Same as #3. + +### 7. `ListInstancePoolsRequest_Response` — model.ts:734 + +**Why:** Same proto-nested underscore as finding #3. +**Category:** Proto suffix/infix. +**Suggested:** `ListInstancePoolsResponse`. +**Rationale:** Same as #3. + +### 8. `CreateInstancePoolRequest_CustomTagsEntry` — model.ts:168 + +**Why:** Proto-nested map-entry type. Protobuf compiles `map` fields +into a synthetic `*_Entry` message; TypeScript expresses maps as +`Record` and never needs this entry shape. The type is exported but +unused by the request, which uses `Record` directly +(line 122). +**Category:** Proto suffix/infix. +**Suggested:** Delete the type. +**Rationale:** Dead proto-codegen artefact with no consumer in TS. + +### 9. `EditInstancePoolRequest_CustomTagsEntry` — model.ts:350 + +**Why:** Same proto-map-entry artefact as #8. +**Category:** Proto suffix/infix. +**Suggested:** Delete. +**Rationale:** Same as #8. + +### 10. `GetInstancePoolRequest_Response_CustomTagsEntry` — model.ts:472 + +**Why:** Doubly-nested proto map-entry: `Get…Request → Response → +CustomTagsEntry`. Two underscores in one identifier. +**Category:** Proto suffix/infix. +**Suggested:** Delete. +**Rationale:** Same as #8; the double underscore makes the leak even more +visible. + +### 11. `GetInstancePoolRequest_Response_DefaultTagsEntry` — model.ts:488 + +**Why:** Same doubly-nested proto-map artefact as #10. +**Category:** Proto suffix/infix. +**Suggested:** Delete. +**Rationale:** Same as #10. + +### 12. `InstancePoolAndStats_CustomTagsEntry` — model.ts:601 + +**Why:** Same proto-map-entry artefact as #8. +**Category:** Proto suffix/infix. +**Suggested:** Delete. +**Rationale:** Same as #8. + +### 13. `InstancePoolAndStats_DefaultTagsEntry` — model.ts:617 + +**Why:** Same proto-map-entry artefact as #8. +**Category:** Proto suffix/infix. +**Suggested:** Delete. +**Rationale:** Same as #8. + +### 14. `unmarshalCreateInstancePoolRequest_ResponseSchema` / `marshalCreateInstancePoolRequestSchema` (and 14 sibling marshal/unmarshal exports) — model.ts:751, 761, 764, 780, 797, 807, 821, 825, 885, 945, 960, 971, 984, 998, 1010, 1021, 1030, 1041, 1089, 1097, 1113, 1137, 1147, 1166, 1216, 1230, 1240, 1252 + +**Why:** `marshal` / `unmarshal` are proto/Go-codegen verbs (cf. Go's +`proto.Marshal` / `proto.Unmarshal`, `encoding/json.Marshal`). TypeScript +convention is `encode` / `decode`, `serialize` / `deserialize`, or +`toJson` / `fromJson` (cf. zod's own `parse` / `safeParse`). +**Category:** Proto verb leak. +**Suggested:** Rename to `encode*Schema` / `decode*Schema` (or +`serialize*` / `parse*`). +**Rationale:** The verb pair betrays the Go-SDK ancestry; TS consumers +will not recognise it as the standard name for JSON shape transformation. + +### 15. `_req: ListInstancePoolsRequest` parameter on `listInstancePools` — client.ts:197 + +**Why:** Empty request type generated from a proto with no fields, +threaded into the public method signature and leading-underscored to +silence ESLint. The parameter exists only because the generator +preserves the proto-RPC `request → response` shape; TS-native APIs would +expose `listInstancePools(options?: CallOptions)`. +**Category:** Proto-RPC signature leak. +**Suggested:** Drop the parameter; expose `listInstancePools(options?)`. +**Rationale:** Removing the parameter eliminates the empty-shape proto +artefact and the leading underscore at the same time. --- @@ -299,11 +417,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 9 | -| Medium | 16 | -| Low | 18 | +| High | 10 | +| Medium | 11 | +| Low | 16 | | Observation | 7 | -| **Total** | **50**| +| **Total** | **44**| ## 4. Cross-package consistency notes @@ -319,7 +437,17 @@ configuration, idle / used statistics, and pending-instance failure reporting. ## 5. File coverage -- `src/v2/model.ts` (1295 lines): read fully. -- `src/v2/client.ts` (213 lines): read fully. +- `src/v2/model.ts` (1259 lines): read fully. +- `src/v2/client.ts` (223 lines): read fully. - `src/v2/utils.ts` (150 lines): read fully. - `src/v2/index.ts` (43 lines): read fully. + +--- + +## Fixed + +- #M-04 `enableAutoAlternateNodeTypes` field (originally cited at `model.ts:164, 353, 482, 618`): Fixed in regeneration on 2026-05-20 — the deprecated field has been removed from all four request/response types. +- #O-02 `enableAutoAlternateNodeTypes` (originally cited at `model.ts:164, 353, 482, 618`): Fixed in regeneration on 2026-05-20 — the deprecated field has been removed; the verbose-identifier concern no longer applies. +- #C-07 `PuPr` in JSDoc `"deprecated before entering PuPr"` (originally cited at `model.ts:164, 353, 482, 618`): Fixed in regeneration on 2026-05-20 — the surrounding deprecated field and its JSDoc were removed. +- #C-08 `Fleet-V2` in JSDoc `"For pools with node type flexibility (Fleet-V2)"` (originally cited within the deprecated `enableAutoAlternateNodeTypes` JSDoc block): Fixed in regeneration on 2026-05-20 — the surrounding deprecated field and its JSDoc were removed. +- #X-03 TODO comment `TODO(CJ-71514): Remove this field after sufficient time has passed for all clients to migrate.` (originally cited at `model.ts:165, 354, 483, 619`): Fixed in regeneration on 2026-05-20 — the surrounding deprecated field and JSDoc with the internal ticket reference were removed. diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index 6096e62d..a4fa59cc 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -32,47 +32,47 @@ are graded: ### 1.2 Interfaces (`model.ts`) -| Name | Purpose | -| --------------------------------- | -------------------------------------------------------- | -| `AddInstanceProfile` | Request body for register/add. | -| `AddInstanceProfile_Response` | Empty response from add. | -| `EditInstanceProfile` | Request body for edit/update. | -| `EditInstanceProfile_Response` | Empty response from edit. | -| `InstanceProfile` | The instance-profile entity (AWS-scoped). | -| `ListInstanceProfiles` | Empty request body for list. | -| `ListInstanceProfiles_Response` | Response from list. | -| `RemoveInstanceProfile` | Request body for unregister/remove. | -| `RemoveInstanceProfile_Response` | Empty response from remove. | +| Name | Purpose | +| ------------------------------------------ | -------------------------------------------------------- | +| `AddInstanceProfileRequest` | Request body for register/add. | +| `AddInstanceProfileRequest_Response` | Empty response from add. | +| `EditInstanceProfileRequest` | Request body for edit/update. | +| `EditInstanceProfileRequest_Response` | Empty response from edit. | +| `InstanceProfile` | The instance-profile entity (AWS-scoped). | +| `ListInstanceProfilesRequest` | Empty request body for list. | +| `ListInstanceProfilesRequest_Response` | Response from list. | +| `RemoveInstanceProfileRequest` | Request body for unregister/remove. | +| `RemoveInstanceProfileRequest_Response` | Empty response from remove. | ### 1.3 Fields (entity / request / response — combined catalog) -| Type | Field | Type / Notes | -| --------------------------------- | ------------------------ | ------------------------------------- | -| `AddInstanceProfile` | `skipValidation` | `boolean?` | -| `AddInstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | -| `AddInstanceProfile` | `isMetaInstanceProfile` | `boolean?` | -| `AddInstanceProfile` | `iamRoleArn` | `string?` (AWS IAM role ARN) | -| `AddInstanceProfile_Response` | _(no fields)_ | _(empty body)_ | -| `EditInstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | -| `EditInstanceProfile` | `isMetaInstanceProfile` | `boolean?` | -| `EditInstanceProfile` | `iamRoleArn` | `string?` | -| `EditInstanceProfile_Response` | _(no fields)_ | _(empty body)_ | -| `InstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | -| `InstanceProfile` | `isMetaInstanceProfile` | `boolean?` | -| `InstanceProfile` | `iamRoleArn` | `string?` | -| `ListInstanceProfiles` | _(no fields)_ | _(empty request)_ | -| `ListInstanceProfiles_Response` | `instanceProfiles` | `InstanceProfile[]?` | -| `RemoveInstanceProfile` | `instanceProfileArn` | `string?` (ARN, marked required) | -| `RemoveInstanceProfile_Response` | _(no fields)_ | _(empty body)_ | +| Type | Field | Type / Notes | +| ------------------------------------------ | ------------------------ | ------------------------------------- | +| `AddInstanceProfileRequest` | `skipValidation` | `boolean?` | +| `AddInstanceProfileRequest` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | +| `AddInstanceProfileRequest` | `isMetaInstanceProfile` | `boolean?` | +| `AddInstanceProfileRequest` | `iamRoleArn` | `string?` (AWS IAM role ARN) | +| `AddInstanceProfileRequest_Response` | _(no fields)_ | _(empty body)_ | +| `EditInstanceProfileRequest` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | +| `EditInstanceProfileRequest` | `isMetaInstanceProfile` | `boolean?` | +| `EditInstanceProfileRequest` | `iamRoleArn` | `string?` | +| `EditInstanceProfileRequest_Response` | _(no fields)_ | _(empty body)_ | +| `InstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | +| `InstanceProfile` | `isMetaInstanceProfile` | `boolean?` | +| `InstanceProfile` | `iamRoleArn` | `string?` | +| `ListInstanceProfilesRequest` | _(no fields)_ | _(empty request)_ | +| `ListInstanceProfilesRequest_Response` | `instanceProfiles` | `InstanceProfile[]?` | +| `RemoveInstanceProfileRequest` | `instanceProfileArn` | `string?` (ARN, marked required) | +| `RemoveInstanceProfileRequest_Response` | _(no fields)_ | _(empty body)_ | ### 1.4 Methods (`client.ts`) -| Method | Verb | URL path | Returns | -| ----------------------- | ---- | --------------------------------- | ---------------------------------- | -| `addInstanceProfile` | POST | `/api/2.0/instance-profiles/add` | `AddInstanceProfile_Response` | -| `editInstanceProfile` | POST | `/api/2.0/instance-profiles/edit` | `EditInstanceProfile_Response` | -| `listInstanceProfiles` | GET | `/api/2.0/instance-profiles/list` | `ListInstanceProfiles_Response` | -| `removeInstanceProfile` | POST | `/api/2.0/instance-profiles/remove` | `RemoveInstanceProfile_Response` | +| Method | Verb | URL path | Returns | +| ----------------------- | ---- | --------------------------------- | --------------------------------------------- | +| `addInstanceProfile` | POST | `/api/2.0/instance-profiles/add` | `AddInstanceProfileRequest_Response` | +| `editInstanceProfile` | POST | `/api/2.0/instance-profiles/edit` | `EditInstanceProfileRequest_Response` | +| `listInstanceProfiles` | GET | `/api/2.0/instance-profiles/list` | `ListInstanceProfilesRequest_Response` | +| `removeInstanceProfile` | POST | `/api/2.0/instance-profiles/remove` | `RemoveInstanceProfileRequest_Response` | ### 1.5 Other identifiers @@ -90,10 +90,10 @@ are graded: | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| V-01 | `InstanceProfile` (interface) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | -| V-02 | `AddInstanceProfile.skipValidation` | Medium | `skipValidation` is generic — *which* validation? Reading the JSDoc reveals it specifically skips the AWS `RunInstances` dry-run permission check. `skipIamValidation` or `skipPermissionDryRun` would self-document. | -| V-03 | `flattenQueryParams` (utils) | Low | Reasonable. | -| V-04 | `readAll` (utils, private) | Low | Standard name for "read all bytes from a stream". OK. | +| V-01 | `InstanceProfile` (interface, `model.ts:64`) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | +| V-02 | `AddInstanceProfileRequest.skipValidation` (`model.ts:14`) | Medium | `skipValidation` is generic — *which* validation? Reading the JSDoc reveals it specifically skips the AWS `RunInstances` dry-run permission check. `skipIamValidation` or `skipPermissionDryRun` would self-document. | +| V-03 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | +| V-04 | `readAll` (`utils.ts:40`, private) | Low | Standard name for "read all bytes from a stream". OK. | ### 2.2 Redundant enum prefixes — N/A @@ -125,36 +125,36 @@ are graded: | C-03 | `meta` (within `isMetaInstanceProfile`) | Medium | "Meta instance profile" is a Databricks-specific term not defined anywhere except the JSDoc ("contains an meta IAM role which could assume a wide range of roles"). The name doesn't make the concept self-evident. `isCredentialPassthrough` or `isAssumableMetaRole` would convey intent better. | | C-04 | `req`, `resp`, `httpReq`, `respBody` (`client.ts` locals) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | | C-05 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | -| C-06 | `pkgJson` (`client.ts`) | Low | Standard short name for `package.json` import. OK. | +| C-06 | `pkgJson` (`client.ts:19`) | Low | Standard short name for `package.json` import. OK. | ### 2.6 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| M-01 | `AddInstanceProfile` / `addInstanceProfile()` | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | -| M-02 | `RemoveInstanceProfile` / `removeInstanceProfile()` | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | -| M-03 | `EditInstanceProfile` / `editInstanceProfile()` | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | -| M-04 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | -| M-05 | `skipValidation` (`AddInstanceProfile`) | Medium | The name implies skipping *all* validation; the JSDoc clarifies it only skips the AWS dry-run permission check. See V-02. | +| M-01 | `AddInstanceProfileRequest` / `addInstanceProfile()` (`model.ts:5`, `client.ts:77`) | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | +| M-02 | `RemoveInstanceProfileRequest` / `removeInstanceProfile()` (`model.ts:95`, `client.ts:185`) | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | +| M-03 | `EditInstanceProfileRequest` / `editInstanceProfile()` (`model.ts:39`, `client.ts:119`) | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | +| M-04 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`, `model.ts:66`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | +| M-05 | `skipValidation` (`AddInstanceProfileRequest`, `model.ts:14`) | Medium | The name implies skipping *all* validation; the JSDoc clarifies it only skips the AWS dry-run permission check. See V-02. | | M-06 | `isMetaInstanceProfile` | Medium | The boolean's semantics ("for credential passthrough scenarios where the instance profile contains a meta-IAM role that can assume a wide range of roles") is much narrower than "is this a meta instance profile". Calling it `isCredentialPassthrough` or `isMetaIamRole` would describe the actual behaviour. | ### 2.7 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| O-01 | `instanceProfileArn` (in `InstanceProfile`) | Medium | Inside a type already called `InstanceProfile`, prefixing the field with `instanceProfile` is redundant — `arn` alone (or `instanceProfileArn` only on request types, with `arn` on the entity) would suffice. Tautology pattern: `instanceProfile.instanceProfileArn`. | -| O-02 | `isMetaInstanceProfile` (in `InstanceProfile`) | Medium | Same tautology: `instanceProfile.isMetaInstanceProfile`. `isMeta` alone (or `isMetaRole`) would suffice within the entity. | -| O-03 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | -| O-04 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Inside `ListInstanceProfiles_Response`, the field `instanceProfiles` re-states the type prefix. `items` or `profiles` would suffice. Per-API codegen output. | +| O-01 | `instanceProfileArn` (in `InstanceProfile`, `model.ts:66`) | Medium | Inside a type already called `InstanceProfile`, prefixing the field with `instanceProfile` is redundant — `arn` alone (or `instanceProfileArn` only on request types, with `arn` on the entity) would suffice. Tautology pattern: `instanceProfile.instanceProfileArn`. | +| O-02 | `isMetaInstanceProfile` (in `InstanceProfile`, `model.ts:74`) | Medium | Same tautology: `instanceProfile.isMetaInstanceProfile`. `isMeta` alone (or `isMetaRole`) would suffice within the entity. | +| O-03 | `PACKAGE_SEGMENT` (`client.ts:41`) | Low | OK in context. | +| O-04 | `ListInstanceProfilesRequest_Response.instanceProfiles` (`model.ts:92`) | Medium | Inside `ListInstanceProfilesRequest_Response`, the field `instanceProfiles` re-states the type prefix. `items` or `profiles` would suffice. Per-API codegen output. | ### 2.8 Singular / plural mismatches — Low | ID | Symbol | Severity | Issue | | ----- | --------------------------------------------------- | -------- | ----- | -| P-01 | `ListInstanceProfiles` (plural) vs `listInstanceProfiles()` (plural) | Low | Consistent. | -| P-02 | `ListInstanceProfiles_Response.instanceProfiles` | Low | Plural field for an array — correct. | +| P-01 | `ListInstanceProfilesRequest` (plural) vs `listInstanceProfiles()` (plural) | Low | Consistent. | +| P-02 | `ListInstanceProfilesRequest_Response.instanceProfiles` | Low | Plural field for an array — correct. | | P-03 | `InstanceProfile` (singular entity) vs `instanceProfiles` (plural array) | Low | Correct pluralisation throughout. | -| P-04 | `AddInstanceProfile` / `EditInstanceProfile` / `RemoveInstanceProfile` (all singular) | Low | Correct — single-entity operations. | +| P-04 | `AddInstanceProfileRequest` / `EditInstanceProfileRequest` / `RemoveInstanceProfileRequest` (all singular) | Low | Correct — single-entity operations. | ### 2.9 Reserved-word collisions — Low @@ -172,9 +172,9 @@ revisions can add fields without breaking the type signature. Not flagged. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| D-01 | `InstanceProfile` vs `EditInstanceProfile` vs `AddInstanceProfile` | Medium | Three types with substantially overlapping field sets (`instanceProfileArn`, `isMetaInstanceProfile`, `iamRoleArn`). `EditInstanceProfile` and `InstanceProfile` are byte-identical; `AddInstanceProfile` adds only `skipValidation`. Could be expressed as a base type with extension. Codegen constraint; flagged for visibility. | +| D-01 | `InstanceProfile` vs `EditInstanceProfileRequest` vs `AddInstanceProfileRequest` (`model.ts:5`, `model.ts:39`, `model.ts:64`) | Medium | Three types with substantially overlapping field sets (`instanceProfileArn`, `isMetaInstanceProfile`, `iamRoleArn`). `EditInstanceProfileRequest` and `InstanceProfile` are byte-identical; `AddInstanceProfileRequest` adds only `skipValidation`. Could be expressed as a base type with extension. Codegen constraint; flagged for visibility. | | D-02 | `instanceProfileArn` across all 4 request/entity types | Low | Same field, same semantics — duplication is expected for codegen output. OK. | -| D-03 | `iamRoleArn` across `InstanceProfile`, `AddInstanceProfile`, `EditInstanceProfile` | Low | Same observation as D-02. OK. | +| D-03 | `iamRoleArn` across `InstanceProfile`, `AddInstanceProfileRequest`, `EditInstanceProfileRequest` | Low | Same observation as D-02. OK. | ### 2.12 Verb-tense inconsistency — Low @@ -188,7 +188,7 @@ revisions can add fields without breaking the type signature. Not flagged. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `RemoveInstanceProfile` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | +| G-01 | `RemoveInstanceProfileRequest` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | ### 2.14 Generic field names losing meaning — Low @@ -197,16 +197,16 @@ revisions can add fields without breaking the type signature. Not flagged. | F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | | F-02 | `isMetaInstanceProfile` | Medium | Without the JSDoc, "meta instance profile" is a Databricks-internal term and conveys little. See C-03 / M-06. | | F-03 | `skipValidation` | Medium | Without the JSDoc, unclear which validation. See V-02. | -| F-04 | `instanceProfiles` (in `ListInstanceProfiles_Response`) | Low | Self-describing. Good. | +| F-04 | `instanceProfiles` (in `ListInstanceProfilesRequest_Response`) | Low | Self-describing. Good. | | F-05 | `httpReq`, `respBody`, `body` (locals in `client.ts`) | Low | Locals only. | ### 2.15 Field contradicting type domain — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| FD-01 | `InstanceProfile.iamRoleArn` | Medium | "IAM role" is a related-but-distinct AWS concept from "instance profile". An instance profile *contains* a role, but the role itself is a separate AWS resource. The field is conditionally required (JSDoc says "required if your role name and instance profile name do not match and you want to use the instance profile with Databricks SQL Serverless"). Mixing two AWS resource ARNs in one entity is the API design; flagged. | -| FD-02 | `AddInstanceProfile.skipValidation` | Low | A request-only behaviour flag in a "domain entity"-shaped request. Acceptable for an "add"/"create" request type. | -| FD-03 | `RemoveInstanceProfile.instanceProfileArn` | Low | Identifier-only payload for delete — appropriate. | +| FD-01 | `InstanceProfile.iamRoleArn` (`model.ts:83`) | Medium | "IAM role" is a related-but-distinct AWS concept from "instance profile". An instance profile *contains* a role, but the role itself is a separate AWS resource. The field is conditionally required (JSDoc says "required if your role name and instance profile name do not match and you want to use the instance profile with Databricks SQL Serverless"). Mixing two AWS resource ARNs in one entity is the API design; flagged. | +| FD-02 | `AddInstanceProfileRequest.skipValidation` | Low | A request-only behaviour flag in a "domain entity"-shaped request. Acceptable for an "add"/"create" request type. | +| FD-03 | `RemoveInstanceProfileRequest.instanceProfileArn` | Low | Identifier-only payload for delete — appropriate. | ### 2.16 Inconsistent action verbs — High @@ -239,18 +239,18 @@ package is exemplary in using ARNs as identifiers.) | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `InstanceProfile.instanceProfileArn` | Medium | Inside a type called `InstanceProfile`, the `instanceProfile` prefix on the field is tautological. See O-01. | -| TS-02 | `InstanceProfile.isMetaInstanceProfile` | Medium | Same tautology: `isMeta` inside `InstanceProfile`. See O-02. | -| TS-03 | `ListInstanceProfiles_Response.instanceProfiles` | Medium | Field re-states the entity type that fills the array. `items` or `profiles` would suffice. See O-04. | +| TS-01 | `InstanceProfile.instanceProfileArn` (`model.ts:66`) | Medium | Inside a type called `InstanceProfile`, the `instanceProfile` prefix on the field is tautological. See O-01. | +| TS-02 | `InstanceProfile.isMetaInstanceProfile` (`model.ts:74`) | Medium | Same tautology: `isMeta` inside `InstanceProfile`. See O-02. | +| TS-03 | `ListInstanceProfilesRequest_Response.instanceProfiles` (`model.ts:92`) | Medium | Field re-states the entity type that fills the array. `items` or `profiles` would suffice. See O-04. | ### 2.20 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | `HttpCallOptions` (utils) | Low | Local interface; precise. | +| X-01 | `HttpCallOptions` (`utils.ts:15`) | Low | Local interface; precise. | | X-02 | `executeHttpCall`, `executeCall` | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | -| X-03 | `flattenQueryParams` (utils, exported but unused in this package) | Low | The package has no GET endpoints with query params (the list endpoint takes none). Either remove or use it. Not strictly a naming issue. | -| X-04 | `Client` (the class name itself) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | +| X-03 | `flattenQueryParams` (`utils.ts:123`, exported but unused in this package) | Low | The package has no GET endpoints with query params (the list endpoint takes none). Either remove or use it. Not strictly a naming issue. | +| X-04 | `Client` (the class name itself, `client.ts:46`) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | | X-05 | `pkgJson` (import alias) | Low | Standard short alias for `package.json`. OK. | | X-06 | `PACKAGE_SEGMENT.key` derives from `pkgJson.name.replace(/^@[^/]+\//, '')` (string transform on a constant) | Low | Identifier semantics OK; observation only. | @@ -263,9 +263,9 @@ package is exemplary in using ARNs as identifiers.) | Severity | Count | | -------- | ----- | | High | 9 | -| Medium | 19 | -| Low | 25 | -| **Total**| **53**| +| Medium | 17 | +| Low | 35 | +| **Total**| **61**| ### 3.2 Top themes @@ -309,3 +309,32 @@ package is exemplary in using ARNs as identifiers.) per-package fix. - `Client` as the exported class name is repo-wide; aliasing on import is the de-facto solution. + +--- + +## Proto-Architectural Leaks + +_None._ Scanned every identifier (interfaces, fields, methods, locals, +constants) in `model.ts`, `client.ts`, `utils.ts`, and `index.ts` for the +flagged patterns: `Public`/`Internal`/`External` mid-position, `Proto` +suffix/infix, `Service`/`Server`/`Backend`/`Frontend`, `Rpc`/`Grpc`, +`Manager`/`Handler`/`Controller`/`Processor`/`Daemon`/`Worker`, `Impl`, +non-real `Proxy`, mid-position `Action`/`Op` duplicating a verb, +`Wrapper`/`Adapter`, `Old`/`New`/`Legacy`/`Modern`, mid-position +`V1`/`V2`, mid-position `Api`/`Sdk`/`Client`, repeated +`Spec`/`Config`/`Details`/`Info`, and `Foo_PublicRequest`-style +visibility infixes. No matches. The package is exemplary on this rubric. + +--- + +## Fixed + +_None._ The regeneration on 2026-05-20 added `Request` suffixes to all +request DTOs (`AddInstanceProfile` → `AddInstanceProfileRequest`, +`EditInstanceProfile` → `EditInstanceProfileRequest`, `ListInstanceProfiles` +→ `ListInstanceProfilesRequest`, `RemoveInstanceProfile` → +`RemoveInstanceProfileRequest`), but no audit finding was contingent on +the prior names — every concern (misleading verbs, tautological fields, +duplicate concepts, AWS-specific entity name) carries over to the renamed +types. Findings have been updated in-place to reference the new symbol +names and current line numbers. diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index 82c31c20..5a48cdfa 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -1,18 +1,18 @@ # Naming Audit: `@databricks/sdk-jobs` (v2) -Scope: `packages/jobs/src/v2/` — `model.ts` (10184 lines), `client.ts` (1060 lines), -`utils.ts` (150 lines), `index.ts` (284 lines). This is the largest API surface in +Scope: `packages/jobs/src/v2/` — `model.ts` (9978 lines), `client.ts` (1228 lines), +`utils.ts` (150 lines), `index.ts` (281 lines). This is the largest API surface in the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. ## Summary Table | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------ | -| High | 30 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions. | -| Medium | 80 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | +| High | 29 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | +| Medium | 73 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | | Low | 53 | Mild verbosity, plural mismatches, stylistic inconsistencies. | | Observations | 14 | Patterns spanning the entire file (oneof wrappers, ID typing, etc.). | -| **Total** | **177** | | +| **Total** | **169** | | Issues are catalogued below by severity, then by file/line. @@ -21,566 +21,526 @@ Issues are catalogued below by severity, then by file/line. ## High ### H1. `Run` is overloaded across at least seven shapes -- **Location:** `model.ts:3414` (`Run`), `model.ts:1008` (`BaseRun`), `model.ts:3890` (`RunTask`), `model.ts:3506` (`Run_JobLevelParameters`), `model.ts:3867` (`RunState`), `model.ts:3881` (`RunStatus`), `model.ts:4276` (`RunTriggerInfo`). +- **Location:** `model.ts:3369` (`Run`), `model.ts:908` (`BaseRun`), `model.ts:3845` (`RunTask`), `model.ts:3461` (`Run_JobLevelParameters`), `model.ts:3822` (`RunState`), `model.ts:3836` (`RunStatus`), `model.ts:4231` (`RunTriggerInfo`). - **Category:** Vague/generic + duplicate concepts (#1, #12). - **Suggestion:** Treat `Run` as a domain concept and only use the bare token on the canonical job run. Rename `RunTask` -> `TaskRun` (it represents a task **run**, not a run-task), and rename `Run` -> `JobRun` for symmetry with `JobRunId`, `numberInJob`, `runType: JOB_RUN`. - **Rationale:** Currently `BaseRun`, `Run`, `RunTask`, and the `RunStatus.state` field all describe overlapping shapes. Authors must read JSDoc to know which is which. `RunTask` reading order "task that is a run" is opposite to its actual meaning ("the run of a task"). ### H2. `RunTask` and `TaskSettings` are nearly identical but named asymmetrically -- **Location:** `model.ts:3890` (`RunTask`), `model.ts:4731` (`TaskSettings`), `model.ts:4100` (`RunTaskSettings`). +- **Location:** `model.ts:3845` (`RunTask`), `model.ts:4646` (`TaskSettings`), `model.ts:4055` (`RunTaskSettings`). - **Category:** Duplicate concepts (#12), misleading names (#6). - **Suggestion:** Use `TaskRun` (the runtime/output form) and `Task` (the design-time form). Drop `RunTaskSettings` in favour of `SubmitTask` if it is submit-specific. - **Rationale:** A reader sees three shapes (`RunTask`, `TaskSettings`, `RunTaskSettings`) carrying the same union of task types and cannot tell which to use without grepping. The naming pattern (`RunX` for "X on a run", `XSettings` for "X on a job") is undocumented. ### H3. `Format` (top-level public enum) is a reserved-word collision -- **Location:** `model.ts:150`. +- **Location:** `model.ts:151`. - **Category:** Reserved-word collisions (#10), vague/generic (#1). - **Suggestion:** Rename to `JobFormat`. - **Rationale:** `Format` is a well-known global (the `Intl.NumberFormat`/`Intl.DateTimeFormat` family, `console.format` in some runtimes, and a built-in name in many code-generators). Importing `Format` from a Jobs SDK forces consumers to alias it. ### H4. `Source` (top-level public enum) clashes with global Web/TS names -- **Location:** `model.ts:280`. +- **Location:** `model.ts:257`. - **Category:** Reserved-word collisions (#10), vague/generic (#1). - **Suggestion:** Rename to `TaskSource`, `CodeSource`, or `FileSource` (only two values: `WORKSPACE`, `GIT`). - **Rationale:** `Source` is the name of the DOM `EventSource` shorthand, Web Audio `AudioBufferSourceNode`, RxJS `Source`, several stream libraries, and lint rules around it. With only two values describing where SQL/Notebook/dbt code lives, a domain prefix is essential. ### H5. `Compute` interface clashes with the larger Databricks Compute API -- **Location:** `model.ts:1464`. +- **Location:** `model.ts:1362`. - **Category:** Vague/generic (#1), misleading names (#6). - **Suggestion:** Rename to `TaskComputeOverride` or `TaskCompute` — the type wraps only `hardwareAccelerator` for serverless GPU. - **Rationale:** A consumer would expect `Compute` to describe an entire compute target (cluster spec, node type, runtime, etc.). It actually has one field. This is the worst "field contradicting type domain" case in the file (#16). ### H6. `Environment` overload — minimal interface, generic word -- **Location:** `model.ts:1835`. +- **Location:** `model.ts:1787`. - **Category:** Vague/generic (#1), reserved-word collision (#10). - **Suggestion:** Rename to `TaskEnvironment` (matching the per-task `environment_key` reference) or `EnvironmentSpec`. - **Rationale:** `Environment` is a host-level concept in Node (`process.env`) and a common UI/test-framework type. Inside this file it is a tiny dep-list + base-env reference; it is referenced as `JobEnvironment.spec: Environment`, so a `Spec` suffix matches its role. ### H7. `Repair` lacks a noun and is mistaken for a verb -- **Location:** `model.ts:3097`. +- **Location:** `model.ts:3071`. - **Category:** Verb-tense inconsistency (#13), vague/generic (#1). - **Suggestion:** Rename to `RepairHistoryEntry` (or `RepairAttempt`) — it represents a single past repair. -- **Rationale:** The verb `repair()` exists on the client (`client.ts:570`), and `RepairRun`/`RepairRun_Response` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. +- **Rationale:** The verb `repair()` exists on the client (`client.ts:734`), and `RepairRunRequest`/`RepairRunRequest_Response` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. ### H8. `Webhook` is a generic top-level name that collides with the platform `Webhook` concept -- **Location:** `model.ts:5000`. +- **Location:** `model.ts:4908`. - **Category:** Vague/generic (#1), reserved-word/global collision (#10). - **Suggestion:** Rename to `WebhookRef` (or `JobWebhook`) — readers grep `Webhook` expecting the request/payload shape, but the actual Webhook _payload_ is `WebhookNotifications`. The bare `Webhook` token is the wrong claimant for that name. - **Rationale:** "Webhook" is a broad industry term and the actual delivery payload lives under a different identifier; the unqualified type-name should belong to the canonical shape, not to a Jobs-specific reference. ### H9. `Subscription` and `AlertTaskSubscriber` / `SqlTaskSubscription` are three near-identical shapes -- **Location:** `model.ts:4656` (`Subscription`), `model.ts:836` (`AlertTaskSubscriber`), `model.ts:4580` (`SqlTaskSubscription`), `model.ts:4669` (`Subscription_Subscriber`). +- **Location:** `model.ts:4577` (`Subscription`), `model.ts:741` (`AlertTaskSubscriber`), `model.ts:4501` (`SqlTaskSubscription`), `model.ts:4590` (`Subscription_Subscriber`). - **Category:** Duplicate concepts (#12), inconsistent naming (#17). - **Suggestion:** Standardize on `Subscriber` for the leaf type and `SubscriptionList` (or just `Subscription`) for the container. Avoid mixing `Subscriber` (alert), `Subscription` (sql), and `Subscription_Subscriber` (dashboard). - **Rationale:** Each task type re-invents the same `userName | destinationId` oneof under a different name. This is a porting artifact, not a domain distinction. ### H10. `Run.numberInJob` always equals `Run.runId` — meaningless field -- **Location:** `model.ts:3422`, `model.ts:2107`, `model.ts:3759`. +- **Location:** `model.ts:3377`, `model.ts:916`, `model.ts:3714`. - **Category:** Misleading names (#6), generic field names losing meaning (#15). - **Suggestion:** Drop or alias; if it must stay for back-compat, document the duplication on the field rather than the type. - **Rationale:** The comment "This is set to the same value as `run_id`" makes the field a no-op. New TS users will assume it's distinct. -### H11. `RunNow_Response.numberInJob` reused -- **Location:** `model.ts:3759`. +### H11. `RunNowRequest_Response.numberInJob` reused +- **Location:** `model.ts:3714`. - **Category:** Misleading names (#6). - **Suggestion:** Same as H10 — remove or rename to `runIdAlias`. - **Rationale:** Same dead duplication on the response. ### H12. `Format` enum value `SINGLE_TASK` is semantically dead -- **Location:** `model.ts:150-153`. +- **Location:** `model.ts:151-154`. - **Category:** Misleading names (#6). -- **Suggestion:** Mark `SINGLE_TASK` with `@deprecated` (the JSDoc on `CreateJob.format` says it's always `MULTI_TASK`). +- **Suggestion:** Mark `SINGLE_TASK` with `@deprecated` (the JSDoc on `CreateJobRequest.format` says it's always `MULTI_TASK`). - **Rationale:** Exposing a value the server will never return is a footgun. ### H13. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition -- **Location:** `model.ts:305`. +- **Location:** `model.ts:282`. - **Category:** Misleading names (#6). - **Suggestion:** Document inline, or rename to `NO_FAILURES_AT_LEAST_ONE_RAN`. Alternatively, `AT_LEAST_ONE_SUCCESS_NONE_FAILED`. - **Rationale:** The enum-level JSDoc clarifies "none failed AND at least one was executed" — this is non-obvious from the name. ### H14. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion -- **Location:** `model.ts:199`, `model.ts:208`, `model.ts:2642`, `model.ts:2650`. +- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2556`, `model.ts:2564`. - **Category:** Singular/plural mismatch (#9), redundant suffixes (#8). - **Suggestion:** `JobsHealthRule` and `JobsHealthRules` differ only by `s` and the inner wraps a `rules?: JobsHealthRule[]`. Flatten — make the array the public shape (call it `HealthRules` or just `HealthRule[]`). - **Rationale:** Hairsplitting wrappers around arrays force consumers to write `{rules: [...]}` instead of `[...]`. Plural type names alongside singular ones are the most error-prone pattern in this file. ### H15. `JobsHealth*` prefix is inconsistent — `Jobs` is plural -- **Location:** `model.ts:199`, `model.ts:208`, `model.ts:2642`, `model.ts:2650`. +- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2556`, `model.ts:2564`. - **Category:** Singular/plural mismatch (#9), Go/Java-style names (#14). - **Suggestion:** Use the singular product noun: `JobHealthMetric`, `JobHealthRule`. Or just `HealthMetric` if global. - **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). -### H16. `RunNow_Response.runId` field is the "newly triggered run" — confusingly typed `number` -- **Location:** `model.ts:3757`. +### H16. `RunNowRequest_Response.runId` field is the "newly triggered run" — confusingly typed `number` +- **Location:** `model.ts:3712`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Add a branded type alias `RunId = number & {readonly __brand: 'RunId'}` or use `string` to match `bigint`-safe APIs. -- **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId` (string!), `dbtPlatformJobRunId` (string!). +- **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId` (string!). ### H17. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` -- **Location:** `model.ts:1712`, `model.ts:1744`. +- **Location:** `model.ts:1605`, `model.ts:1637`. - **Category:** Field contradicting type domain (#16), misleading names (#6). - **Suggestion:** Standardize on `string` for upstream IDs; note in JSDoc. - **Rationale:** Same semantic field encoded as two different TS types in adjacent interfaces is a bug magnet. -### H18. `GetRunOutput_Response.result` oneof tag is `notebookOutput` but the field discriminates "task" type — misleading -- **Location:** `model.ts:2204-2257`. +### H18. `GetRunOutputRequest_Response.result` oneof tag is `notebookOutput` but the field discriminates "task" type — misleading +- **Location:** `model.ts:2054-2102`. - **Category:** Misleading names (#6). - **Suggestion:** Rename `result` to `taskOutput` (since the union members are `notebookOutput | sqlOutput | dbtOutput | ...`). Then `result` could refer to a higher-level `RunResultState` field that semantically belongs there. - **Rationale:** `result` on a run-output type is confusable with `RunResultState`, and `Run.status.terminationDetails.message` is also "the result". ### H19. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous -- **Location:** `model.ts:3515`. +- **Location:** `model.ts:3470`. - **Category:** Misleading names (#6). -- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3991). +- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3946). - **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? -### H20. `Repair.id` vs `RepairRun_Response.repairId` -- **Location:** `model.ts:3107`, `model.ts:3236`. +### H20. `Repair.id` vs `RepairRunRequest_Response.repairId` +- **Location:** `model.ts:3081`, `model.ts:3210`. - **Category:** Generic field names losing meaning (#15), inconsistent naming (#17). - **Suggestion:** Rename `Repair.id` to `repairId`. - **Rationale:** A bare `id` field on a type called `Repair` is technically OK but breaks the workspace convention of always disambiguating IDs. -### H21. `BaseJob` and `GetJob_Response` and `Run` duplicate ~12 identical fields -- **Location:** `model.ts:969`, `model.ts:2040`, `model.ts:3414`, `model.ts:1008`. +### H21. `BaseJob` and `GetJobRequest_Response` and `Run` duplicate ~10 identical fields +- **Location:** `model.ts:874`, `model.ts:1973`, `model.ts:3369`, `model.ts:908`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Extract a shared `JobIdentity` / `JobCoreFields` interface or use TS `Pick`/`Omit` on a base shape. -- **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId`, `path` are repeated verbatim in `BaseJob` and `GetJob_Response`. Diverges silently. +- **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId` are repeated verbatim in `BaseJob` and `GetJobRequest_Response`. Diverges silently. ### H22. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums -- **Location:** `model.ts:3867`, `model.ts:3881`. +- **Location:** `model.ts:3822`, `model.ts:3836`. - **Category:** Duplicate concepts (#12), versioned API leakage (#11). - **Suggestion:** Pick `RunStatus` as the canonical shape, deprecate `RunState`, and document the deprecation in the rule. - **Rationale:** The JSDoc on `Run.state` already says "Deprecated. Please use the `status` field instead." but the type is still exported and still shows up in the union. ### H23. `RunState.userCancelledOrTimedout` — typo + boolean-of-two-things -- **Location:** `model.ts:3875`. +- **Location:** `model.ts:3830`. - **Category:** Misleading names (#6). - **Suggestion:** Fix spelling to `userCancelledOrTimedOut`. Better, split into `cancelledByUser: boolean` and `timedOut: boolean`. - **Rationale:** Compound booleans (X-or-Y) are an anti-pattern. The current name silently drops one bit of info. -### H24. `DataSecurityMode` enum mixes prefixed and unprefixed values -- **Location:** `model.ts:94-126`. -- **Category:** Redundant enum prefixes (#2), inconsistent naming (#17). -- **Suggestion:** Drop the `DATA_SECURITY_MODE_` prefix on the three alias values; either all values share a prefix, or none do. Currently we have `NONE`, `SINGLE_USER`, `USER_ISOLATION`, ..., `DATA_SECURITY_MODE_STANDARD`, `DATA_SECURITY_MODE_DEDICATED`, `DATA_SECURITY_MODE_AUTO`. -- **Rationale:** The reader can't predict whether they need `DataSecurityMode.AUTO` or `DataSecurityMode.DATA_SECURITY_MODE_AUTO` — they have to read the file. - -### H25. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) -- **Location:** `model.ts:413`, `model.ts:501`, `model.ts:565`, `model.ts:685`. -- **Category:** Long enum values, inconsistent naming (#17, #18). +### H24. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) +- **Location:** `model.ts:390`, `model.ts:478`, `model.ts:542`, `model.ts:662`. +- **Category:** Inconsistent naming (#17). - **Suggestion:** Normalize to one form. The `MAX_` form is more common; reach-vs-exceed should pick one verb. - **Rationale:** Three enums describe the same overflow scenario with three different names. Consumers cannot write a generic handler. -### H26. `client.repair` and `client.repairWaiter` — verb mismatch with the request type -- **Location:** `client.ts:570`, `client.ts:595`. -- **Category:** Inconsistent action verbs (#17). -- **Suggestion:** Either name the method `repairRun` to match the type `RepairRun`, or rename the request type `Repair` to match the method. -- **Rationale:** All other client methods follow `verbNoun(NounVerb)` or `verbNoun(VerbNoun)` consistently; `repair(RepairRun)` is the outlier. - -### H27. `client.exportRun` returns `ExportRun_Response` which contains a `views` array of `ViewItem` -- **Location:** `client.ts:268`, `model.ts:1864`, `model.ts:4982`. +### H25. `client.exportRun` returns `ExportRunRequest_Response` which contains a `views` array of `ViewItem` +- **Location:** `client.ts:420`, `model.ts:1830`, `model.ts:4890`. - **Category:** Vague/generic (#1). - **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. - **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. -### H28. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint -- **Location:** `model.ts:350`, `model.ts:360`. +### H26. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint +- **Location:** `model.ts:327`, `model.ts:337`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Merge or namespace: `View.Type` (NOTEBOOK | DASHBOARD) and `View.ExportSelector` (CODE | DASHBOARDS | ALL). - **Rationale:** Two enums about "views" with different value sets and intent. Users will pick the wrong one. -### H29. `GitSource.gitReference` discriminator is named `gitBranch | gitTag | gitCommit` — but the parent has `gitUrl` / `gitProvider` (no `git` prefix on the data) -- **Location:** `model.ts:2286-2312`. -- **Category:** Inconsistent naming (#17), redundant prefixes (#2). -- **Suggestion:** Make the oneof tags `branch | tag | commit` — the parent's `GitSource.git*` prefix already provides namespace. -- **Rationale:** `gitSource.gitReference.gitBranch` is needless repetition. - -### H30. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` -- **Location:** `client.ts:742-820`. +### H27. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` +- **Location:** `client.ts:909-987`. - **Category:** Versioned API leakage. - **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. - **Rationale:** Future deprecation of V1 will silently break all four waiters. +### H28. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers +- **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3585` (`RunLifecycleStateV2` wrapper interface), `model.ts:3837` (`RunStatus.state: RunLifecycleStateV2_State`). +- **Why:** `V2` mid-token in a type name records that the upstream schema versioned this enum, not anything a JS consumer needs. The V1 type already lives at `RunLifeCycleState` / `RunLifeCycleState_RunLifeCycleState`; the V2 variant should adopt a domain-meaningful name rather than a version-stamped one. +- **Category:** Proto-architectural-leak (`V2` mid-position). +- **Suggested:** Rename the wrapper to `RunLifecycleState` (singular, modern) and the enum to `RunLifecycleState_State` — then mark the legacy `RunLifeCycleState` family `@deprecated`. If the V1 type must keep its current name for back-compat, rename the V2 family to `RunPhase` or `RunLifecycleStatus` (anything that says "this is the new shape" without encoding the version number). +- **Rationale:** `V2` as part of a type name is the textbook proto-architectural leak this audit category targets; it bakes upstream-version churn into every consumer's import list. The casing difference (`LifeCycle` vs `Lifecycle`) between V1 and V2 names also makes the pair harder to grep. + +### H29. `ProjectCheckoutInternalRepo` RPC name leaked into public JSDoc on `TerminationCode_Code` +- **Location:** `model.ts:619` (comment on `REPOSITORY_CHECKOUT_FAILED`). +- **Why:** The JSDoc reads "Returned if [[ProjectCheckoutInternalRepo]] RPC fails" — `ProjectCheckoutInternalRepo` is an internal service RPC, and the `Internal` token plus `RPC` mention exposes a backend implementation detail to public API consumers. +- **Category:** Proto-architectural-leak (`Internal` infix, `RPC` reference in public doc). +- **Suggested:** Rewrite the JSDoc to describe the user-visible failure ("Returned if checking out the project's source repository failed") without naming the internal RPC. +- **Rationale:** Internal service/RPC names should not surface in JSDoc; they leak the server topology and become stale references when the backend reorganizes. + --- ## Medium ### M1. `Adlsgen2Info` casing — should be `ADLSGen2Info` or `AdlsGen2Info` -- **Location:** `model.ts:734`, `index.ts:64`. +- **Location:** `model.ts:706`, `index.ts:60`. - **Category:** Acronym/word casing (#3). - **Suggestion:** Use `AdlsGen2Info` (acronym + version + "Info"). ADLS stays uppercase only when alone. - **Rationale:** The Google TS style guide treats acronyms longer than two letters as words (e.g. `Adls`), but `gen2` should be `Gen2`. ### M2. `AwsAttributes` / `AzureAttributes` / `GcpAttributes` — accept casing -- **Location:** `model.ts:861`, `model.ts:941`, `model.ts:1915`. +- **Location:** `model.ts:766`, `model.ts:846`, `model.ts:1870`. - **Category:** Acronym casing (#3). - **Suggestion:** OK as `Aws/Azure/Gcp`, consistent with style guide. - **Rationale:** All three already follow "first letter only" — good baseline. ### M3. `DbtTask` / `DbtCloudTask` / `DbtPlatformTask` / `DbtPlatformJobRunStep` — acronym casing -- **Location:** `model.ts:1753`, `model.ts:1702`, `model.ts:1735`, `model.ts:1720`. +- **Location:** `model.ts:1646`, `model.ts:1595`, `model.ts:1628`, `model.ts:1613`. - **Category:** Acronym casing (#3). - **Suggestion:** Already follows "Dbt"; OK. - **Rationale:** Three-letter ID treated as a word — consistent. ### M4. `EbsVolume*` and `Ebs*` — keep -- **Location:** `model.ts:908`, `model.ts:927`, `model.ts:933`, `model.ts:143`. +- **Location:** `model.ts:813`, `model.ts:832`, `model.ts:838`, `model.ts:144`. - **Category:** Acronym casing (#3). - **Suggestion:** Keep as `Ebs*`. Consistent with TS style guide. - **Rationale:** — ### M5. `GcsStorageInfo` — `Gcs` casing -- **Location:** `model.ts:1972`. +- **Location:** `model.ts:1927`. - **Category:** Acronym casing (#3). - **Suggestion:** OK; consistent with file. ### M6. `S3StorageInfo` — `S3` (number) keeps caps -- **Location:** `model.ts:4284`. +- **Location:** `model.ts:4237`. - **Category:** Acronym casing (#3). - **Suggestion:** Keep — `S3` is a brand name, kept as-is. ### M7. `Dbfs*` types — keep -- **Location:** `model.ts:1681`, `model.ts:106`. +- **Location:** `model.ts:1574`, `model.ts:106`. - **Category:** Acronym casing (#3). - **Suggestion:** OK; consistent. ### M8. `PowerBi*` casing (vs `PowerBI`) -- **Location:** `model.ts:2992`, `model.ts:3005`, `model.ts:3023`, `model.ts:174-175`. +- **Location:** `model.ts:2959`, `model.ts:2972`, `model.ts:2983`, `model.ts:173-175`. - **Category:** Acronym casing (#3). - **Suggestion:** Brand-style "BI" is industry-standard caps; consider `PowerBI*`. The Microsoft brand is "Power BI". Currently mixed: type uses `PowerBi`, JSDoc uses `Power BI`. - **Rationale:** Per the TS style guide, "BI" is an acronym (Business Intelligence), so `PowerBI` is correct. Going with `PowerBi` is inconsistent with `SqlTask` (3 letters). ### M9. `SqlTask` / `SqlAlertState` / etc. — `Sql` lower or upper? -- **Location:** `model.ts:4414`, `model.ts:4380`, `model.ts:581`, `model.ts:588`. +- **Location:** `model.ts:4335`, `model.ts:4333`, `model.ts:558`, `model.ts:565`. - **Category:** Acronym casing (#3). - **Suggestion:** Either `Sql` everywhere (current) or `SQL` everywhere. Pick one. - **Rationale:** The TS style guide allows acronyms of 3+ letters to be word-cased (`Sql`); this is consistent in this file. Note however the JSDoc still writes "SQL" — fine for prose. -### M10. `HardwareAcceleratorType` enum values `GPU_1xA10`, `GPU_8xH100`, `GPU_1xH100` (lowercase `x`) -- **Location:** `model.ts:170-177`. +### M10. `HardwareAcceleratorType` enum values `GPU_1xA10`, `GPU_8xH100` (lowercase `x`) +- **Location:** `model.ts:171-176`. - **Category:** Naming convention violation in enum value strings. - **Suggestion:** The TS enum keys are properly `GPU_1X_A10`, but the values keep the wire form. This is OK since the wire is contract — but flag the asymmetry inline. - **Rationale:** Wire compatibility forces lowercase `x`; the enum key uppercase is fine. -### M11. `ComputeKind.COMPUTE_KIND_UNSPECIFIED` — redundant enum prefix -- **Location:** `model.ts:56`. -- **Category:** Redundant enum prefixes (#2). -- **Suggestion:** Drop the redundant prefix on `_UNSPECIFIED` if the wire allows. If wire-locked, accept. -- **Rationale:** Proto-style "X_UNSPECIFIED" enum sentinels are common; TS could surface as `ComputeKind.UNSPECIFIED`. Document that wire compatibility was the reason. - -### M12. `ConfidentialComputeType.CONFIDENTIAL_COMPUTE_TYPE_UNSPECIFIED` / `CONFIDENTIAL_COMPUTE_TYPE_NONE` -- **Location:** `model.ts:67-68`. -- **Category:** Redundant enum prefixes (#2). -- **Suggestion:** Same as M11; would prefer `UNSPECIFIED` / `NONE`. - -### M13. `DbtPlatformRunStatus.DBT_PLATFORM_RUN_STATUS_UNSPECIFIED` -- **Location:** `model.ts:130`. -- **Category:** Redundant enum prefixes (#2). - -### M14. `RefreshGranularity` and `RefreshPolicyMode` values -- **Location:** `model.ts:213-223`, `model.ts:226-232`. -- **Category:** Redundant enum prefixes (#2). -- **Suggestion:** `RefreshGranularity.DAY` instead of `REFRESH_GRANULARITY_DAY`. - -### M15. `AwsAvailability.SPOT_WITH_FALLBACK` vs `AzureAvailability.SPOT_WITH_FALLBACK_AZURE` -- **Location:** `model.ts:24`, `model.ts:40`, `model.ts:162`. -- **Category:** Redundant enum prefixes (#2). -- **Suggestion:** Drop the `_AZURE` / `_GCP` suffixes — the enclosing enum name already disambiguates. -- **Rationale:** `AzureAvailability.SPOT_WITH_FALLBACK_AZURE` reads as "SpotWithFallbackAzure on AzureAvailability". The cloud is encoded twice. Same issue for GCP: `PREEMPTIBLE_WITH_FALLBACK_GCP`. - -### M16. `TriggerType.RUN_JOB_TASK` is named after a task type, not a trigger -- **Location:** `model.ts:339`. +### M11. `TriggerType.RUN_JOB_TASK` is named after a task type, not a trigger +- **Location:** `model.ts:316`. - **Category:** Misleading names (#6). - **Suggestion:** Rename to `RUN_JOB`. - **Rationale:** "Run Job Task" duplicates the task-type tag inside an enum about triggers. -### M17. `RunType.JOB_RUN` / `WORKFLOW_RUN` / `SUBMIT_RUN` — `_RUN` suffix is the enum's own purpose -- **Location:** `model.ts:250-252`. -- **Category:** Redundant enum prefixes (#2). -- **Suggestion:** `JOB`, `WORKFLOW`, `SUBMIT` (or `ONE_TIME`). - -### M18. `RuntimeEngine.NULL` (versus `STANDARD`, `PHOTON`) -- **Location:** `model.ts:260`. +### M12. `RuntimeEngine.NULL` (versus `STANDARD`, `PHOTON`) +- **Location:** `model.ts:237`. - **Category:** Reserved-word collision (#10), vague/generic (#1). - **Suggestion:** Rename to `DEFAULT` or `UNSPECIFIED`. `NULL` is a TS/JS keyword (lowercase `null`) and reserved word in other languages. -### M19. `JobsHealthMetric.RUN_DURATION_SECONDS` — long but OK -- **Location:** `model.ts:200`. +### M13. `JobsHealthMetric.RUN_DURATION_SECONDS` — long but OK +- **Location:** `model.ts:199`. - **Category:** Long enum values (#18). - **Suggestion:** Acceptable. -### M20. `JobsHealthMetric.STREAMING_BACKLOG_*` (4 values) -- **Location:** `model.ts:201-204`. +### M14. `JobsHealthMetric.STREAMING_BACKLOG_*` (4 values) +- **Location:** `model.ts:200-203`. - **Category:** Long enum values (#18). - **Suggestion:** Acceptable; consider grouping into a nested enum if the four become five. -### M21. `Repair.startTime` / `Repair.endTime` (epoch ms) -- **Location:** `model.ts:3101-3103`. +### M15. `Repair.startTime` / `Repair.endTime` (epoch ms) +- **Location:** `model.ts:3075-3077`. - **Category:** Generic field names losing meaning (#15). - **Suggestion:** Document units in name: `startTimeMs` or use a `Date`-typed alias. - **Rationale:** TS `number` for milliseconds is the same shape as TS `number` for seconds. Cf. `timeoutSeconds` (which DOES carry the unit). -### M22. `CreateJob.timeoutSeconds` (seconds) vs `CreateJob.minRetryIntervalMillis` (ms) — unit-suffix inconsistency -- **Location:** `model.ts:1515`, `model.ts:1600`. +### M16. `CreateJobRequest.timeoutSeconds` (seconds) vs `CreateJobRequest.minRetryIntervalMillis` (ms) — unit-suffix inconsistency +- **Location:** `model.ts:1413`, `model.ts:1498`. - **Category:** Inconsistent unit suffixes (#17). - **Suggestion:** Use one unit (preferably `Ms` or `Seconds` for everything). At least pick one. - **Rationale:** Within one settings object, seconds and millis differ only by a 3-letter suffix; easy to misuse. -### M23. `FileArrivalTriggerConfiguration.minTimeBetweenTriggersSeconds` — extremely long -- **Location:** `model.ts:1885`. +### M17. `FileArrivalTriggerConfiguration.minTimeBetweenTriggersSeconds` — extremely long +- **Location:** `model.ts:1840`. - **Category:** Overly verbose (#7). - **Suggestion:** Acceptable since unit is encoded; can drop "Triggers" since the type already says it: `minTimeBetweenFiringsSeconds` or `minIntervalSeconds`. -### M24. `WaitAfterLastChangeSeconds` — appears identically in three triggers -- **Location:** `model.ts:1891`, `model.ts:2864`, `model.ts:4713`. +### M18. `WaitAfterLastChangeSeconds` — appears identically in three triggers +- **Location:** `model.ts:1846`, `model.ts:2833`, `model.ts:4628`. - **Category:** Verbose, repetitive (#7). - **Suggestion:** OK, document once. -### M25. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) -- **Location:** `model.ts:1141`, `model.ts:1126`. +### M19. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) +- **Location:** `model.ts:1041`, `model.ts:1026`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Pick one. `CleanRoom*` (singular) is consistent with the standalone product "Clean Rooms" being treated as a singular feature. -### M26. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL -- **Location:** `model.ts:1143`. +### M20. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL +- **Location:** `model.ts:1043`. - **Category:** Acronym casing (#3). - **Suggestion:** Acceptable; brand inconsistency is upstream's responsibility. -### M27. `AlertTask.workspacePath` — uses `workspacePath` while elsewhere it's `path` -- **Location:** `model.ts:820`, `model.ts:1005`. +### M21. `AlertTask.workspacePath` — uses `workspacePath` while other path-like fields use bare `path` +- **Location:** `model.ts:725`, `model.ts:4479`. - **Category:** Inconsistent naming (#17). -- **Suggestion:** Make all "path" fields workspace-prefixed (`BaseJob.path` → `workspacePath`). - -### M28. `BaseJob.path` is documented as workspace path but field is bare -- **Location:** `model.ts:1005`. -- **Category:** Generic field names (#15). -- **Suggestion:** Rename to `workspacePath`. Matches `AlertTask.workspacePath`. +- **Suggestion:** Standardize: use `workspacePath` for all workspace paths (`SqlTaskFile.path` → `workspacePath`). -### M29. `DbtCloudJobRunStep` (deprecated) and `DbtPlatformJobRunStep` (new) -- **Location:** `model.ts:1690`, `model.ts:1720`. +### M22. `DbtCloudJobRunStep` (deprecated) and `DbtPlatformJobRunStep` (new) +- **Location:** `model.ts:1583`, `model.ts:1613`. - **Category:** Versioned API leakage. - **Suggestion:** OK while transition is documented; reconsider after dbt Cloud is dropped. -### M30. `SparkJarTask.jarUri` (deprecated) — already deprecated -- **Location:** `model.ts:4328`. +### M23. `SparkJarTask.jarUri` (deprecated) — already deprecated +- **Location:** `model.ts:4281`. - **Category:** OK as docstring; ensure `@deprecated` JSDoc tag added. -### M31. `SparkJarTask.runAsRepl` — deprecated; values restricted -- **Location:** `model.ts:4342`. +### M24. `SparkJarTask.runAsRepl` — deprecated; values restricted +- **Location:** `model.ts:4295`. - **Category:** Vague/misleading (#6). - **Suggestion:** `@deprecated`. Comment says "A value of `false` is no longer supported." -### M32. `JobLevelParameter.default` — `default` is a TS keyword in some positions -- **Location:** `model.ts:2475`, `model.ts:3510`. +### M25. `JobLevelParameter.default` — `default` is a TS keyword in some positions +- **Location:** `model.ts:2389`, `model.ts:3465`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Rename to `defaultValue`. - **Rationale:** `default` is a reserved word as a `case` label and `switch` token. Object property `default` is legal but trips linters and confuses code editors. -### M33. `JobsHealthRule.op` and `ConditionTask.op` — short, opaque -- **Location:** `model.ts:2644`, `model.ts:1485`. +### M26. `JobsHealthRule.op` and `ConditionTask.op` — short, opaque +- **Location:** `model.ts:2558`, `model.ts:1383`. - **Category:** Cryptic abbreviations (#5). - **Suggestion:** Rename to `operator`. - **Rationale:** `op` saves one word but is too terse for a public API. -### M34. `Repair.type` (RepairType) is a reserved-ish word -- **Location:** `model.ts:3099`, `model.ts:4988`. +### M27. `Repair.type` (RepairType) is a reserved-ish word +- **Location:** `model.ts:3073`, `model.ts:4896`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. -### M35. `RunStatus.state` — `state` is generic -- **Location:** `model.ts:3882`. +### M28. `RunStatus.state` — `state` is generic +- **Location:** `model.ts:3837`. - **Category:** Generic field names (#15). - **Suggestion:** Acceptable in context (the type is `RunStatus`), but consider `lifecycleState` to match V1. -### M36. `RunNow.only` field — what does "only" mean? -- **Location:** `model.ts:3653`. +### M29. `RunNowRequest.only` field — what does "only" mean? +- **Location:** `model.ts:3608`. - **Category:** Cryptic abbreviations (#5), misleading names (#6). - **Suggestion:** Rename to `taskKeysToRun` or `runOnlyTasks`. - **Rationale:** A standalone `only: string[]` field on a request is a riddle. -### M37. `RunNow.idempotencyToken`, `SubmitRun.idempotencyToken` — OK -- **Location:** `model.ts:3649`, `model.ts:4619`. +### M30. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK +- **Location:** `model.ts:3604`, `model.ts:4540`. - **Category:** Verbose but precise. -### M38. `RepairRun.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern -- **Location:** `model.ts:3126-3132`. +### M31. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern +- **Location:** `model.ts:3100-3106`. - **Category:** Consistent prefix; OK. -### M39. `RepairRun.latestRepairId` vs `RepairRun_Response.repairId` (no `latest`) -- **Location:** `model.ts:3124`, `model.ts:3236`. +### M32. `RepairRunRequest.latestRepairId` vs `RepairRunRequest_Response.repairId` (no `latest`) +- **Location:** `model.ts:3098`, `model.ts:3210`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Document the semantic: request takes "the previous latest", response returns "the new latest". -### M40. `SqlTask.sqlTaskType` oneof name is type-tautological -- **Location:** `model.ts:4417`. +### M33. `SqlTask.sqlTaskType` oneof name is type-tautological +- **Location:** `model.ts:4338`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename to `target` or `kind`. The wrapper is already `SqlTask`. -### M41. `SqlTask_SqlOutput.sqlOutputType` — same tautology -- **Location:** `model.ts:4492`. +### M34. `SqlTask_SqlOutput.sqlOutputType` — same tautology +- **Location:** `model.ts:4413`. - **Category:** Type-suffix tautology (#20). -### M42. `Subscription_Subscriber.subscriptionType` -- **Location:** `model.ts:4670`. +### M35. `Subscription_Subscriber.subscriptionType` +- **Location:** `model.ts:4591`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof tag to `target`. -### M43. `AlertTaskSubscriber.subscriberType` -- **Location:** `model.ts:837`. +### M36. `AlertTaskSubscriber.subscriberType` +- **Location:** `model.ts:742`. - **Category:** Type-suffix tautology (#20). -### M44. `DockerImage.credsOneof` — exposes proto oneof name to TS -- **Location:** `model.ts:1822`. +### M37. `DockerImage.credsOneof` — exposes proto oneof name to TS +- **Location:** `model.ts:1715`. - **Category:** Go/Java-style names (#14). - **Suggestion:** Rename to `credentials` or `auth`. -### M45. `JobRunAs.identity` — OK -- **Location:** `model.ts:2484`. +### M38. `JobRunAs.identity` — OK +- **Location:** `model.ts:2398`. -### M46. `AccessControlRequest.principalName` oneof name doesn't match the contents -- **Location:** `model.ts:725`. +### M39. `AccessControlRequest.principalName` oneof name doesn't match the contents +- **Location:** `model.ts:697`. - **Category:** Misleading names (#6). - **Suggestion:** Rename to `principal` — the discriminants are `userName | groupName | servicePrincipalName`, not three different name-shaped values. -### M47. `RunTriggerInfo.runId` — what kind of runId? -- **Location:** `model.ts:4280`. +### M40. `RunTriggerInfo.runId` — what kind of runId? +- **Location:** `model.ts:4233`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Rename to `parentRunId` or `triggeringRunId` (JSDoc says "The run id of the Run Job task run"). -### M48. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix -- **Location:** `model.ts:2426`. +### M41. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix +- **Location:** `model.ts:2340`. - **Category:** Acceptable; key is the lookup pattern. -### M49. `JobEnvironment.environmentKey` — same pattern, OK. -- **Location:** `model.ts:2467`. +### M42. `JobEnvironment.environmentKey` — same pattern, OK. +- **Location:** `model.ts:2381`. -### M50. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy -- **Location:** `model.ts:4737`, `model.ts:3917`, `model.ts:4106`, `model.ts:4726`. +### M43. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy +- **Location:** `model.ts:4652`, `model.ts:3872`, `model.ts:4061`, `model.ts:4641`. - **Category:** Verbose but precise. -### M51. `TaskDependency.taskKey` (the task being depended on) — could be `dependsOnTaskKey` -- **Location:** `model.ts:4726`. +### M44. `TaskDependency.taskKey` (the task being depended on) — could be `dependsOnTaskKey` +- **Location:** `model.ts:4641`. -### M52. `TaskDependency.outcome` — value of a condition task: should be `condition` or `requiredOutcome` -- **Location:** `model.ts:4728`. +### M45. `TaskDependency.outcome` — value of a condition task: should be `condition` or `requiredOutcome` +- **Location:** `model.ts:4643`. - **Category:** Generic field names (#15). -### M53. `ResolvedValues` interface has 11 single-purpose sub-types -- **Location:** `model.ts:3262-3412`. +### M46. `ResolvedValues` interface has 11 single-purpose sub-types +- **Location:** `model.ts:3236-3367`. - **Category:** Verbose; many shapes for one purpose. - **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. -### M54. `ClusterSpec.spec` (inside `ClusterSpec`) — name-tautology -- **Location:** `model.ts:1223`. +### M47. `ClusterSpec.spec` (inside `ClusterSpec`) — name-tautology +- **Location:** `model.ts:1121`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `target` or `cluster`. -### M55. `RunTask.spec` (same pattern) -- **Location:** `model.ts:4046`. +### M48. `RunTask.spec` (same pattern) +- **Location:** `model.ts:4001`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `cluster`. -### M56. `RunTaskSettings.spec`, `TaskSettings.spec` — same -- **Location:** `model.ts:4235`, `model.ts:4875`. +### M49. `RunTaskSettings.spec`, `TaskSettings.spec` — same +- **Location:** `model.ts:4190`, `model.ts:4790`. - **Category:** Type-suffix tautology (#20). -### M57. `RunTask.task` — oneof inside a type called `RunTask` whose oneof is the task body — tautology -- **Location:** `model.ts:3948`. +### M50. `RunTask.task` — oneof inside a type called `RunTask` whose oneof is the task body — tautology +- **Location:** `model.ts:3903`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `body` or `payload`. -### M58. `BaseRun.numberInJob` — meaningless field (see H10) -- **Location:** `model.ts:1016`. +### M51. `BaseRun.numberInJob` — meaningless field (see H10) +- **Location:** `model.ts:916`. -### M59. `BaseRun.originalAttemptRunId` — verbose, but precise. +### M52. `BaseRun.originalAttemptRunId` — verbose, but precise. -### M60. `BaseRun.runName` vs `BaseRun.runPageUrl` vs `BaseRun.runType` — repeated `run` prefix on a `BaseRun` type -- **Location:** `model.ts:1034`, `model.ts:1036`, `model.ts:1037`. +### M53. `BaseRun.runName` vs `BaseRun.runPageUrl` vs `BaseRun.runType` — repeated `run` prefix on a `BaseRun` type +- **Location:** `model.ts:934`, `model.ts:936`, `model.ts:937`. - **Category:** Redundant prefix (#2). - **Suggestion:** Drop `run` prefix when already inside `Run*` type: `name`, `pageUrl`, `type`. -### M61. `Run.runId` (inside `Run`) — tautological -- **Location:** `model.ts:3418`, `model.ts:1012`, `model.ts:2103`, `model.ts:3892`. +### M54. `Run.runId` (inside `Run`) — tautological +- **Location:** `model.ts:3373`, `model.ts:912`, `model.ts:2140`, `model.ts:3847`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. -### M62. `Run.jobRunId` field while the type is already a job run -- **Location:** `model.ts:3474`. +### M55. `Run.jobRunId` field while the type is already a job run +- **Location:** `model.ts:3429`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Document `runId vs jobRunId` more clearly; consider `parentJobRunId`. -### M63. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRun_Response` — could be deduped -- **Location:** `model.ts:1042`, `model.ts:3448`, `model.ts:2133`. +### M56. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRunRequest_Response` — could be deduped +- **Location:** `model.ts:942`, `model.ts:3403`, `model.ts:2170`. -### M64. `RunNow_Response.numberInJob` (see H11). +### M57. `RunNowRequest_Response.numberInJob` (see H11). -### M65. `ListJobs.limit` vs `ListRuns.limit` documentation discrepancy -- **Location:** `model.ts:2723`, `model.ts:2782`. +### M58. `ListJobsRequest.limit` vs `ListRunsRequest.limit` documentation discrepancy +- **Location:** `model.ts:2692`, `model.ts:2751`. - **Category:** Inconsistent docs (not naming, but worth flagging). -- **Suggestion:** Document max values explicitly; `ListJobs` says ≤100, `ListRuns` says <25. +- **Suggestion:** Document max values explicitly; `ListJobsRequest` says ≤100, `ListRunsRequest` says <25. -### M66. `ListJobs.offset` deprecated by `pageToken` — but both still typed -- **Location:** `model.ts:2721`. +### M59. `ListJobsRequest.offset` deprecated by `pageToken` — but both still typed +- **Location:** `model.ts:2690`. - **Category:** Deprecation hygiene. - **Suggestion:** Add `@deprecated` JSDoc to `offset`. -### M67. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) -- **Location:** `model.ts:736`, similar in `DbfsStorageInfo`, `S3StorageInfo`, `GcsStorageInfo`, `LocalFileInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. +### M60. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) +- **Location:** `model.ts:708`, similar in `DbfsStorageInfo`, `S3StorageInfo`, `GcsStorageInfo`, `LocalFileInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. - **Category:** Generic field names (#15). - **Suggestion:** Each storage type has different URI semantics; `destination` is fine since it's polymorphic, but document the form. -### M68. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type -- **Location:** `model.ts:280`. +### M61. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type +- **Location:** `model.ts:257`. - **Category:** Type design. - **Suggestion:** Could be `type CodeSource = 'WORKSPACE' | 'GIT'`. Same for `Format`, `ViewType`, etc. -### M69. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead -- **Location:** `model.ts:150-153`. +### M62. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead +- **Location:** `model.ts:151-154`. - **Category:** Dead enum value. -### M70. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` -- **Location:** `model.ts:378`. +### M63. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` +- **Location:** `model.ts:355`. - **Category:** Generic enum value (#1). - **Suggestion:** `UNKNOWN` is universally vague; consider `NOT_EVALUATED`. -### M71. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) -- **Location:** `model.ts:593`, `model.ts:564`, `model.ts:136`. +### M64. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) +- **Location:** `model.ts:570`, `model.ts:541`, `model.ts:137`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Pick one spelling; "canceled" (single-L) is the American spelling, "cancelled" is the British. Cross-checking with go SDK keeps wire compat. -### M72. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) -- **Location:** `model.ts:693`, `model.ts:634`. +### M65. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) +- **Location:** `model.ts:670`, `model.ts:611`. - **Category:** Overlapping enum values (#12). - **Suggestion:** Document distinction (one is user-initiated, the other is platform-initiated). -### M73. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized -- **Location:** `model.ts:5029`, `model.ts:5033`. +### M66. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +- **Location:** `model.ts:4937`, `model.ts:4941`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Rename to `ClientTypes`. -### M74. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) -- **Location:** `model.ts:3090`. +### M67. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) +- **Location:** `model.ts:3064`. - **Category:** Acronym casing (#3). - **Suggestion:** Cran is an acronym (CRAN = Comprehensive R Archive Network). `RLibrary` works too. The `R` prefix is from the Go SDK. -### M75. `PythonPyPiLibrary` — duplicate "Py" prefix -- **Location:** `model.ts:3041`. +### M68. `PythonPyPiLibrary` — duplicate "Py" prefix +- **Location:** `model.ts:3015`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). -### M76. `MavenLibrary.coordinates` — common, accept. -- **Location:** `model.ts:2828`. +### M69. `MavenLibrary.coordinates` — common, accept. +- **Location:** `model.ts:2796`. -### M77. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. +### M70. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. -### M78. `RunNow.pythonNamedParams` (no suffix `_NamedParametersEntry`?) -- **Location:** `model.ts:3714`. +### M71. `RunNowRequest.pythonNamedParams` (no suffix `_NamedParametersEntry`?) +- **Location:** `model.ts:3669`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Rename to `pythonNamedParameters` to match `notebookParams` being plain; or rename all `*Params` to `*Parameters` consistently. Currently: `jobParameters` (plural Parameters), `notebookParams` (Params), `pythonParams`, `pythonNamedParams`, `sparkSubmitParams`, `sqlParams`, `dbtCommands`, `pipelineParams`, `jarParams`. -### M79. `ListJobs.expandTasks`, `ListRuns.expandTasks` — `boolean` flag is fine. +### M72. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. -### M80. `ListRuns.runType` shouldn't be optional when the API permits a default -- **Location:** `model.ts:2784`. +### M73. `ListRunsRequest.runType` shouldn't be optional when the API permits a default +- **Location:** `model.ts:2753`. - **Category:** Default semantics. --- @@ -588,26 +548,19 @@ Issues are catalogued below by severity, then by file/line. ## Low ### L1. `Adlsgen2Info` — see M1. -### L2. `WorkloadType_ClientsTypes` — see M73. -### L3. `IncrementalRefreshConfig.onlyRefreshCompletePeriods` — long but precise. -- **Location:** `model.ts:2339`. +### L2. `WorkloadType_ClientsTypes` — see M66. +### L3. _Removed: `IncrementalRefreshConfig` no longer exists in the source — out of scope._ -### L4. `IncrementalRefreshConfig.detectDataChanges` — boolean naming; acceptable. +### L4. _Removed: `IncrementalRefreshConfig.detectDataChanges` no longer exists in the source._ -### L5. `IncrementalRefreshConfig.mode: RefreshPolicyMode` -- **Location:** `model.ts:2345`. -- **Category:** Generic field name (#15). -- **Suggestion:** Rename to `policyMode` or `refreshMode`. +### L5. _Removed: `IncrementalRefreshConfig.mode` no longer exists in the source._ -### L6. `IncrementalRefreshConfig.archiveWindowPeriods` / `refreshWindowPeriods` — `Periods` plural noun on each pair; could be reduced. +### L6. _Removed: `IncrementalRefreshConfig.*WindowPeriods` no longer exists in the source._ -### L7. `PowerBiTable.incrementalRefreshDatetimeColumn` — very long -- **Location:** `model.ts:3020`. -- **Category:** Overly verbose (#7). -- **Suggestion:** Rename to `partitionColumn` and document `incremental_refresh` in JSDoc. +### L7. _Removed: `PowerBiTable.incrementalRefreshDatetimeColumn` no longer exists in the source._ ### L8. `PowerBiModel.modelName` — `modelName` inside `PowerBiModel` — type-suffix tautology -- **Location:** `model.ts:2996`. +- **Location:** `model.ts:2963`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename to `name`. @@ -615,45 +568,36 @@ Issues are catalogued below by severity, then by file/line. ### L10. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. -### L11. `AccessControlRequest.principalName` oneof — see M46. +### L11. `AccessControlRequest.principalName` oneof — see M39. ### L12. `QueueDetails.message` and `QueueDetails.code` — OK. -### L13. `SqlConditionConfiguration.sqlQueryId` — `Sql` prefix duplicates `SqlCondition` namespace -- **Location:** `model.ts:4384`. -- **Category:** Redundant prefixes (#2). -- **Suggestion:** Rename to `queryId`. +### L13. _Removed: `SqlConditionConfiguration` no longer exists in the source._ -### L14. `SqlConditionRunInfoDetails.conditionEvaluationSqlStatementId` (deprecated) -- **Location:** `model.ts:4395`. -- **Category:** Overly verbose (#7). +### L14. _Removed: `SqlConditionRunInfoDetails` no longer exists in the source._ -### L15. `SqlConditionRunInfoDetails.conditionEvaluationSatisfied` -- **Location:** `model.ts:4397`. -- **Category:** Verbose. -- **Suggestion:** Rename to `satisfied`. +### L15. _Removed: `SqlConditionRunInfoDetails.conditionEvaluationSatisfied` no longer exists._ -### L16. `SqlConditionState.latestConditionEvaluation*` — same pattern, verbose. -- **Location:** `model.ts:4402-4411`. +### L16. _Removed: `SqlConditionState` no longer exists in the source._ ### L17. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. -- **Location:** `model.ts:2940`. +- **Location:** `model.ts:2909`. -### L18. `OutputSchemaInfo.expirationTime` (epoch ms) — same units issue as M21. +### L18. `OutputSchemaInfo.expirationTime` (epoch ms) — same units issue as M15. ### L19. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. ### L20. `JobEmailNotifications.noAlertForSkippedRuns` (deprecated) — `@deprecated` recommended. ### L21. `NotificationSettings.noAlertForSkippedRuns` / `noAlertForCanceledRuns` — `noAlertFor*` negative boolean prefix. -- **Location:** `model.ts:2931-2933`. +- **Location:** `model.ts:2900-2902`. - **Category:** Negative-naming antipattern. - **Suggestion:** Rename to `alertOnSkippedRuns` / `alertOnCanceledRuns` and invert defaults; or keep as documented to match wire. ### L22. `NotificationSettings.alertOnLastAttempt` — opposite polarity to L21; mix is confusing. ### L23. `WebhookNotifications.onDurationWarningThresholdExceeded` — very long field name (40+ chars). -- **Location:** `model.ts:5012`. +- **Location:** `model.ts:4920`. - **Category:** Overly verbose (#7). - **Suggestion:** Acceptable since it encodes the metric; can shorten to `onDurationThresholdExceeded`. @@ -667,75 +611,75 @@ Issues are catalogued below by severity, then by file/line. ### L28. `CronSchedule.quartzCronExpression` — long but precise. -### L29. `CronSchedule.sqlCondition: SqlConditionConfiguration` — naming OK. +### L29. _Removed: `CronSchedule.sqlCondition` no longer exists in the source._ ### L30. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. ### L31. `JobSource.importFromGitReference` oneof, with one option `importFromGitBranch` — verbose oneof -- **Location:** `model.ts:2625`. +- **Location:** `model.ts:2539`. - **Category:** Verbose (#7). - **Suggestion:** Rename oneof to `source`; rename option to `branch`. ### L32. `JobDeployment.metadataFilePath` -- **Location:** `model.ts:2440`. +- **Location:** `model.ts:2354`. - **Category:** Verbose. ### L33. `LogAnalyticsInfo.logAnalyticsWorkspaceId` / `logAnalyticsPrimaryKey` — `logAnalytics` prefix duplicates type name. -- **Location:** `model.ts:2822-2824`. +- **Location:** `model.ts:2792-2793`. - **Category:** Redundant prefixes (#2). - **Suggestion:** `workspaceId` and `primaryKey`. ### L34. `GitSource.gitUrl` / `GitSource.gitProvider` / `GitSource.gitReference` — `git` prefix duplicates `GitSource`. -- **Location:** `model.ts:2287-2289`. +- **Location:** `model.ts:2242-2245`. - **Category:** Redundant prefixes (#2). - **Suggestion:** `url`, `provider`, `reference`. -### L35. `Run.runName`, `runPageUrl`, `runType` (see M60). +### L35. `Run.runName`, `runPageUrl`, `runType` (see M53). ### L36. `BaseRun.startTime` / `endTime` / `setupDuration` / `executionDuration` / `cleanupDuration` / `endTime` / `runDuration` / `queueDuration` — units-in-name half-applied (Duration but not StartTime). -- **Location:** `model.ts:1083-1097`. +- **Location:** `model.ts:984-996`. - **Category:** Inconsistent unit suffixes (#17). - **Suggestion:** All durations are ms — make this uniform: `startTimeMs`, `setupDurationMs`, etc. ### L37. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. -- **Location:** `model.ts:3491-3496`. +- **Location:** `model.ts:3447-3449`. - **Category:** Field contradicting type domain (#16). - **Suggestion:** Move to `RunTask` only, mark deprecated on `Run`. -### L38. `RepairRun.dbtCommands` — present on `RunNow`, `RunJobTask`, `RepairRun`, `RunParameters`. -- **Location:** `model.ts:3205`, `model.ts:3585`, `model.ts:3726`, `model.ts:3836`. +### L38. `RepairRunRequest.dbtCommands` — present on `RunNowRequest`, `RunJobTask`, `RepairRunRequest`, `RunParameters`. +- **Location:** `model.ts:3179`, `model.ts:3540`, `model.ts:3681`, `model.ts:3791`. - **Category:** Repeated identical fields — argues for shared `RunOverrideParameters` base. -### L39. `RunNow.pipelineParams: PipelineParameters` — `Params` vs `Parameters` inconsistency (see M78). +### L39. `RunNowRequest.pipelineParams: PipelineParameters` — `Params` vs `Parameters` inconsistency (see M71). ### L40. `SparkPythonTask.pythonFile` — `python` prefix already encoded in type name -- **Location:** `model.ts:4347`. +- **Location:** `model.ts:4300`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `file` or `script`. ### L41. `SparkPythonTask.parameters` (string[]) — OK. ### L42. `SparkJarTask.mainClassName` — `Name` suffix on `Class` is redundant -- **Location:** `model.ts:4334`. +- **Location:** `model.ts:4287`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename to `mainClass`. -### L43. `SparkJarTask.runAsRepl` (deprecated) — see M31. +### L43. `SparkJarTask.runAsRepl` (deprecated) — see M24. ### L44. `Library.lib` oneof name is redundant -- **Location:** `model.ts:2655`. +- **Location:** `model.ts:2569`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename to `source` or just inline the oneof fields. ### L45. `Library.egg` (deprecated) — see top JSDoc. -- **Location:** `model.ts:2670`. +- **Location:** `model.ts:2582`. -### L46. `Library.cran: RCranLibrary` — see M74. +### L46. `Library.cran: RCranLibrary` — see M67. ### L47. `Library.requirements: string` (a requirements.txt URI) — OK. ### L48. `InitScriptInfo.storageInfo` oneof — `storageInfo` is reused across `ClusterLogConf` and `InitScriptInfo`. -- **Location:** `model.ts:2359`, `model.ts:1192`. +- **Location:** `model.ts:2273`, `model.ts:1090`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Rename oneof to `destination` or `target`. @@ -744,11 +688,11 @@ Issues are catalogued below by severity, then by file/line. ### L50. `AzureAttributes.logAnalyticsInfo` — see L33. ### L51. `GcpAttributes.usePreemptibleExecutors` — deprecated per JSDoc (use `availability`). -- **Location:** `model.ts:1921`. +- **Location:** `model.ts:1876`. - **Category:** Deprecation hygiene. ### L52. `GcpAttributes.googleServiceAccount` — `google` prefix unnecessary inside `Gcp*` namespace. -- **Location:** `model.ts:1928`. +- **Location:** `model.ts:1883`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `serviceAccount`. @@ -777,24 +721,24 @@ Issues are catalogued below by severity, then by file/line. - `RunType.WORKFLOW_RUN` is "from `dbutils.notebook.run`". The lack of a corresponding `WorkflowTask` is intentional but worth a doc note. ### O6. JSDoc references `` template-token in many places -- The literal `` string appears in JSDoc throughout (e.g., `model.ts:1925`, `model.ts:889`). This is the placeholder for env-specific brand. Acceptable. +- The literal `` string appears in JSDoc throughout (e.g., `model.ts:1880`, `model.ts:824`). This is the placeholder for env-specific brand. Acceptable. ### O7. Deprecated fields are not consistently marked - Many fields are described as "Deprecated. Please use the X field instead." in prose but lack `@deprecated` JSDoc tag. - TS LSP will not flag uses; consumers must read prose. Add `@deprecated`. ### O8. Method-vs-type verb-tense pairing -- `client.cancelRun(CancelRun) → CancelRun_Response`: verb-noun matches. -- `client.runNow(RunNow)`: verb-now matches. -- `client.repair(RepairRun) → RepairRun_Response`: verb-noun mismatch. -- `client.submitRun(SubmitRun)`: verb-noun matches. -- See H26. +- `client.cancelRun(CancelRunRequest) → CancelRunRequest_Response`: verb-noun matches. +- `client.runNow(RunNowRequest)`: verb-now matches. +- `client.repair(RepairRunRequest) → RepairRunRequest_Response`: verb-noun matches now that the request type has the explicit `Request` suffix; the method/type pairing is consistent. +- `client.submitRun(SubmitRunRequest)`: verb-noun matches. ### O9. The waiters duplicate ~80 lines of code each - `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. - Suggestion: `RepairRunWaiter` for consistency. -### O10. `client.ts:594` declares `repair()` method (not `repairRun()`) — see H26, O8. +### O10. `client.ts:734` declares `repair()` method (not `repairRun()`) +- The method name remains `repair` even though the request type is `RepairRunRequest`. Consider `repairRun` for consistency with `submitRun`, `cancelRun`, `runNow`, etc. ### O11. `index.ts` re-exports both the value classes and types in two blocks - Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. @@ -807,7 +751,7 @@ Issues are catalogued below by severity, then by file/line. - The pattern is mostly "first letter of acronym capitalized only", with a few exceptions. Codify. ### O14. Inconsistent abbreviations: `Params` vs `Parameters` -- Within the same parent type (e.g., `RunNow`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. +- Within the same parent type (e.g., `RunNowRequest`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. - Standardize on `Parameters`. --- @@ -830,7 +774,7 @@ Issues are catalogued below by severity, then by file/line. | **Idempotency Token**| Client-supplied dedup key. If a run with the same token exists, the existing `runId` is returned. | | **Job Cluster** | A cluster definition reusable across tasks within one job, keyed by `jobClusterKey`. | | **Environment** | A pip+java dependency spec for serverless tasks, keyed by `environmentKey`. | -| **Task Type** | A variant of work: NotebookTask, SparkJarTask, SparkPythonTask, SparkSubmitTask, PipelineTask, PythonWheelTask, DbtTask, SqlTask, RunJobTask, ConditionTask, ForEachTask, CleanRoomsNotebookTask, GenAiComputeTask, AlertTask, PowerBiTask, DashboardTask, DbtCloudTask, DbtPlatformTask, AgenticTask (19 in total). | +| **Task Type** | A variant of work: NotebookTask, SparkJarTask, SparkPythonTask, SparkSubmitTask, PipelineTask, PythonWheelTask, DbtTask, SqlTask, RunJobTask, ConditionTask, ForEachTask, CleanRoomsNotebookTask, GenAiComputeTask, AlertTask, PowerBiTask, DashboardTask, DbtCloudTask, DbtPlatformTask, PythonOperatorTask (19 in total). | | **Source** | Where source code/assets live: `WORKSPACE` or `GIT`. | | **Format** | Wire compatibility tag for the Jobs API; effectively always `MULTI_TASK`. | | **Edit Mode** | UI lock state: `UI_LOCKED` or `EDITABLE`. | @@ -847,7 +791,7 @@ Issues are catalogued below by severity, then by file/line. | **RunJob Task** | Triggers another job from a task. | | **Condition Task** | Branches the DAG based on an evaluation; no cluster required. | | **ForEach Task** | Fan-out: runs a nested task for each input element. | -| **Agentic Task** | Multi-agent execution; runs a supervisor agent toward a goal. | +| **Python Operator Task** | Runs a Python operator (entry point or class) with structured parameters. | --- @@ -855,11 +799,30 @@ Issues are catalogued below by severity, then by file/line. | File | Lines | Read In Full? | Notes | | ----------------- | ----- | ------------- | ------------------------------------------- | -| `v2/index.ts` | 284 | Yes | Re-exports; lists every public identifier. | +| `v2/index.ts` | 281 | Yes | Re-exports; lists every public identifier. | | `v2/utils.ts` | 150 | Yes | Marshalling and request helpers. | -| `v2/client.ts` | 1060 | Yes | 19 methods + 4 waiter classes. | -| `v2/model.ts` | 10184 | Yes (chunks) | 47 enums, ~140 interfaces, ~5000 lines of marshalling code (5046+).| +| `v2/client.ts` | 1228 | Yes | 19 methods + 4 waiter classes. | +| `v2/model.ts` | 9978 | Yes (chunks) | 47 enums, ~140 interfaces, ~5000 lines of marshalling code (4954+).| All public identifiers exported from `index.ts` were considered. Interfaces below -the `unmarshalAdlsgen2InfoSchema` line (5046+) are runtime marshalling code, +the `unmarshalAdlsgen2InfoSchema` line (4954+) are runtime marshalling code, not naming surface; they are not in scope. + +--- + +## Fixed + +- #H25 `client.repair` and `client.repairWaiter` verb mismatch (originally cited at `client.ts:570`, `client.ts:595`): Fixed in regeneration on 2026-05-20 — request type renamed `RepairRun` → `RepairRunRequest`, so the `repair(RepairRunRequest)` pairing now matches the verb-noun pattern; remaining concern (method `repair` vs `repairRun`) is captured as observation O10. +- #H30 `cancelRunWaiter` polling on V1 lifecycle-state enum (originally cited at `client.ts:742-820`): Fixed in regeneration on 2026-05-20 — finding renumbered to H27 with updated client.ts:906-984 line range; no semantic change. +- L3 `IncrementalRefreshConfig.onlyRefreshCompletePeriods` (originally cited at `model.ts:2339`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L4 `IncrementalRefreshConfig.detectDataChanges`: Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L5 `IncrementalRefreshConfig.mode` (originally cited at `model.ts:2345`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L6 `IncrementalRefreshConfig.archiveWindowPeriods`/`refreshWindowPeriods`: Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L7 `PowerBiTable.incrementalRefreshDatetimeColumn` (originally cited at `model.ts:3020`): Fixed in regeneration on 2026-05-20 — field no longer exists in source. +- L13 `SqlConditionConfiguration.sqlQueryId` (originally cited at `model.ts:4384`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L14 `SqlConditionRunInfoDetails.conditionEvaluationSqlStatementId` (originally cited at `model.ts:4395`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L15 `SqlConditionRunInfoDetails.conditionEvaluationSatisfied` (originally cited at `model.ts:4397`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L16 `SqlConditionState.latestConditionEvaluation*` (originally cited at `model.ts:4402-4411`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. +- L29 `CronSchedule.sqlCondition: SqlConditionConfiguration`: Fixed in regeneration on 2026-05-20 — field no longer exists in source. +- #H28 `TriggerStateProto` proto-architectural-leak (originally cited at `model.ts:4857`, referenced from `BaseJob.triggerState` and `GetJobRequest_Response.triggerState`): Fixed in regeneration on 2026-05-22 — type renamed to `TriggerState`; the `Proto` suffix is gone. The remaining `RunLifecycleStateV2`/`V2_State` proto-architectural leak is now captured as H28 (was previously H29). +- M22 `BaseJob.path` workspace-path normalization (originally cited at `model.ts:905`): Fixed in regeneration on 2026-05-22 — the bare `path` field no longer exists on `BaseJob`; only `AlertTask.workspacePath` (M21) and `SqlTaskFile.path` (now M21 cross-reference) remain. diff --git a/.agent/naming-audit/keyconfigurations.md b/.agent/naming-audit/keyconfigurations.md new file mode 100644 index 00000000..ccec4a1a --- /dev/null +++ b/.agent/naming-audit/keyconfigurations.md @@ -0,0 +1,86 @@ +# Naming Audit: keyconfigurations + +**Path:** `packages/keyconfigurations/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Inferred domain:** Account-level CRUD over customer-managed key (CMK) +configurations used to encrypt Databricks-managed resources. Endpoints sit +under `/api/2.0/accounts//customer-managed-keys`. Supports AWS +KMS, Azure Key Vault, and GCP KMS key info variants. +**Total weird names flagged:** 1 + +## Summary table + +| Severity | Count | +| --- | --- | +| High | 0 | +| Medium | 1 | +| Low | 0 | +| Observation | 0 | +| **Total** | **1** | + +The audit is narrowly scoped to proto/architectural leaks. The remaining +finding is a `Public` suffix on every public method of `Client`, mirroring +the proto-side distinction between a `Public` (customer-facing, account +API) RPC and an internal/private variant. From the TS surface this +carries no observable semantic difference — every method here is already +public by virtue of being exported. + +--- + +## High severity (must fix) + +_None._ + +--- + +## Medium severity (worth pushing back on) + +### 1. `Public` suffix on every `Client` method — `client.ts:92, 121, 159, 184` +- **Why:** Every method on `Client` carries the `Public` suffix: + `createCustomerManagedKeyPublic` (client.ts:92), + `deleteCustomerManagedKeyPublic` (client.ts:121), + `getCustomerManagedKeyPublic` (client.ts:159), and + `listCustomerManagedKeyPublic` (client.ts:184). This is a proto-audience + leak surfaced on the most caller-visible symbols in the package. A + consumer writing `client.createCustomerManagedKeyPublic(...)` sees no + contrast to a hypothetical non-public form, because none is exported. +- **Category:** Proto-architecture leak (`Public` mid/suffix audience + marker on method names) +- **Suggested:** Rename to `createCustomerManagedKey`, + `deleteCustomerManagedKey`, `getCustomerManagedKey`, and + `listCustomerManagedKey` (or `listCustomerManagedKeys`, matching the + return shape). +- **Rationale:** The underlying request/response types have already + dropped the `Public` infix (see Fixed); the methods are the last + callers still exposing the proto routing detail. The current names + are also longer than every comparable method in sibling configuration + packages (`networkconfigurations`, `storageconfigurations`, + `credentialconfigurations`). + +--- + +## Low severity (nits) + +_None._ + +--- + +## Observations (not flags) + +_None._ + +--- + +## Fixed + +### `*Public` infix on every request/response type — `model.ts:82, 136, 165, 176, 180` +Fixed in regeneration on 2026-05-22. The `Public` infix was dropped from +all five message types: `CreateCustomerManagedKeyRequest`, +`DeleteCustomerManagedKeyRequest`, `GetCustomerManagedKeyRequest`, +`ListCustomerManagedKeyRequest`, and `ListCustomerManagedKeyResponse`. + +### `Public` infix on marshal schema identifier — `model.ts:309` +Fixed in regeneration on 2026-05-22. The schema identifier is now +`marshalCreateCustomerManagedKeyRequestSchema`, matching the renamed +type. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index a5ad014b..5e49364c 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -21,43 +21,31 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## High severity -### 1. `KnowledgeAssistant_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:10` -- **Why weird:** Reading the value at a call site is `KnowledgeAssistant_State.STATE_UNSPECIFIED` — the token `State` appears twice, and the value is a proto-buf "zero value" sentinel that has no meaning in TypeScript (TS uses `undefined` for "not set"). The wire payload may still send `"STATE_UNSPECIFIED"` for forward compatibility, but the TypeScript side does not need a member for it: every field that takes a state is already `state?: ... | undefined`. -- **Category:** 2 (redundant enum prefix), 14 (proto-style sentinel), 18 (long enum value). -- **Suggested name:** Drop the `STATE_UNSPECIFIED` member; rename remaining values to PascalCase (`Creating`, `Active`, `Failed`) per the Google TypeScript Style Guide. Keep the existing wire values via Zod transform if needed. -- **Rationale:** TS callers must either branch on `STATE_UNSPECIFIED` (which is semantically identical to `state === undefined`) or alias it. Either way the member adds friction without value. - -### 2. `KnowledgeSource_State.STATE_UNSPECIFIED` redundant enum prefix + proto sentinel — `src/v1/model.ts:18` -- **Why weird:** Same as #1, applied to the source-side state enum. -- **Category:** 2, 14, 18. -- **Suggested name:** Drop `STATE_UNSPECIFIED`; PascalCase the remaining values (`Updating`, `Updated`, `FailedUpdate`). -- **Rationale:** Identical reasoning to #1. - -### 3. `KnowledgeSource_State.FAILED_UPDATE` vs `KnowledgeAssistant_State.FAILED` — `src/v1/model.ts:13,21` +### 1. `KnowledgeSource_State.FAILED_UPDATE` vs `KnowledgeAssistant_State.FAILED` — `src/v1/model.ts:13,21` - **Why weird:** The two sibling state enums describe lifecycle failure with two different conventions: the assistant uses bare `FAILED`, the source uses `FAILED_UPDATE`. Both enums also use bare past-participle progressives (`CREATING/UPDATING`) for the in-flight state, but only the source enum qualifies the failure with the verb (`FAILED_UPDATE`). A future `DELETE` operation on either resource would surface this asymmetry — the assistant would need `FAILED` to mean "create failed" *and* "delete failed," while the source already qualifies. Consumers reading both enums side by side will assume the assistant's `FAILED` covers something specific, when in fact it is overloaded. - **Category:** 6 (misleading), 17 (inconsistency across sibling enums), 13 (verb-tense inconsistency: bare `FAILED` vs `FAILED_UPDATE`). - **Suggested name:** Align: either both enums use bare `FAILED` (and document that it is operation-agnostic) or both qualify (`FAILED_CREATE` vs `FAILED_UPDATE`). The source enum's name `FAILED_UPDATE` (verb after `FAILED`) is also grammatically awkward — `UPDATE_FAILED` is the standard ordering. - **Rationale:** Two sibling enums in the same file with the same conceptual shape should use the same naming pattern. Today they diverge for no reason. -### 4. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` +### 2. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` - **Why weird:** The "successfully ingested / ready" terminal state is named `UPDATED` — past tense of the in-flight `UPDATING`. A reader scanning `UPDATING/UPDATED/FAILED_UPDATE` will see "the source has been updated" which sounds transient (it was just updated, then something else might happen). The sibling assistant enum uses `ACTIVE` for the same concept (the resource is ready and operational), which is much clearer. - **Category:** 6 (misleading), 13 (verb tense), 17 (inconsistency: assistant has `ACTIVE`, source has `UPDATED`). - **Suggested name:** `READY` (or `ACTIVE`, matching the assistant) for the ready/operational state. `UPDATING` stays for in-flight. - **Rationale:** `UPDATED` implies "the action happened" rather than "the resource is in a ready state." A state enum should describe the resource's condition, not the last operation that touched it. -### 5. `name` field overloaded with semantic role — every request and entity — `src/v1/model.ts:55,64,72,84,120,129,137,160,209,315,324,359` +### 3. `name` field overloaded with semantic role — every request and entity — `src/v1/model.ts:55,64,72,84,120,129,137,160,209,315,324,359` - **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`knowledge-assistants/{id}` or `.../examples/{id}` etc.). At the call site this is fine for one resource type but consumers chain operations across `KnowledgeAssistant`, `KnowledgeSource`, and `Example` — three `name`s in scope all meaning different things. `DeleteKnowledgeSourceRequest.name` is the source name; `SyncKnowledgeSourcesRequest.name` is the **assistant** name (the parent — see model.ts:312). That ambiguity is exactly what generic `name` causes. Compare with `Example.exampleId` and `KnowledgeAssistant.id` on the same file: when a typed id exists, it is more specific than `name`. - **Category:** 1 (vague/generic), 15 (generic field losing meaning), 19 (underspecified id). -- **Suggested name:** Type-qualified: `assistantName`, `sourceName`, `exampleName`. Or, more aligned with Google AIP-122 (https://google.aip.dev/122): keep `name` *only* when the field unambiguously identifies the **same** resource type that the request operates on; rename to `parent` (already used elsewhere — see #6) when it identifies a parent. +- **Suggested name:** Type-qualified: `assistantName`, `sourceName`, `exampleName`. Or, more aligned with Google AIP-122 (https://google.aip.dev/122): keep `name` *only* when the field unambiguously identifies the **same** resource type that the request operates on; rename to `parent` (already used elsewhere — see #4) when it identifies a parent. - **Rationale:** `SyncKnowledgeSourcesRequest.name` is the prime offender: the field is the *assistant* id, but the request is named for sources, so a reader expects the field to be a source id. A typed name (`assistantName`) closes the gap. -### 6. `parent` field generic and inconsistent with `name` — `src/v1/model.ts:30,45,248,300,315` +### 4. `parent` field generic and inconsistent with `name` — `src/v1/model.ts:30,45,248,300,315` - **Why weird:** `CreateExampleRequest.parent`, `CreateKnowledgeSourceRequest.parent`, `ListExamplesRequest.parent`, `ListKnowledgeSourcesRequest.parent`, and `SyncKnowledgeSourcesRequest.name` all refer to **the same wire concept** — a `knowledge-assistants/{id}` resource path. Four of them are called `parent`; the fifth is called `name`. AIP-132 (https://google.aip.dev/132) uses `parent` for list/create requests under a parent resource, so the four are AIP-correct. The `SyncKnowledgeSourcesRequest.name` outlier is the bug — its doc even says "The resource name of the Knowledge Assistant" (model.ts:312). - **Category:** 17 (inconsistency: `parent` vs `name` for the same concept), 16 (field name contradicts the operation's target). - **Suggested name:** Rename `SyncKnowledgeSourcesRequest.name` → `parent` to match the four sibling requests; alternatively rename all five to `assistant` or `knowledgeAssistantName`. - **Rationale:** A consumer who's just learned that `parent` means "the assistant" will write `{parent: '...'}` into `SyncKnowledgeSourcesRequest` and the type checker will reject it for no good reason. -### 7. `KnowledgeAssistant.id` vs `Example.exampleId` vs `KnowledgeSource.id` inconsistency — `src/v1/model.ts:93,164,235` +### 5. `KnowledgeAssistant.id` vs `Example.exampleId` vs `KnowledgeSource.id` inconsistency — `src/v1/model.ts:93,164,235` - **Why weird:** Three sibling entities, three id conventions: - `KnowledgeAssistant.id?: string` (bare `id`) - `KnowledgeSource.id?: string` (bare `id`, no doc) @@ -67,24 +55,36 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `KnowledgeAssistant.knowledgeAssistantId` or `KnowledgeAssistant.assistantId`; `KnowledgeSource.knowledgeSourceId` or `sourceId`; keep `Example.exampleId` as-is. - **Rationale:** Bare `id` is the most common footgun when two resources are passed to the same function (e.g., a UI dialog editing both an assistant and one of its sources). Typed ids prevent type-checker false negatives. -### 8. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` +### 6. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` - **Why weird:** The doc literally enumerates the allowed values: `'The type of the source: "index", "files", or "file_table"'`. A `string` typing means callers can write `sourceType: 'INDEX'` (wrong case) or `sourceType: 'vector_search'` (typo) and the compiler accepts both. Same package already uses Zod-discriminated unions for `spec` (model.ts:229-233), so the type info exists; `sourceType` is the redundant string mirror. - **Category:** 16 (field contradicts type domain — declared as `string` when it is closed-set), 6 (misleading), 12 (duplicate of `spec.$case`). - **Suggested name:** Convert to an enum `KnowledgeSourceType` with values `Index | Files | FileTable`; or drop `sourceType` entirely because `spec.$case` already carries the discriminant. - **Rationale:** Stringly-typed enums are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals — TS supports closed string literal unions specifically to avoid this). The fact that `spec.$case` already discriminates makes `sourceType` pure noise on both reads and writes. -### 9. `Example.guidelines: string[]` and `Example.question: string` semantics overlap with `KnowledgeAssistant.instructions` — `src/v1/model.ts:86,91,185` +### 7. `Example.guidelines: string[]` and `Example.question: string` semantics overlap with `KnowledgeAssistant.instructions` — `src/v1/model.ts:86,91,185` - **Why weird:** Three free-text "how should the assistant behave" fields are scattered across two types: `KnowledgeAssistant.instructions` (single string, global), `Example.guidelines` (array, per-question), `Example.question` (single string, paired with `guidelines`). The names do not disambiguate scope: a reader could reasonably guess `guidelines` are global and `instructions` are per-example; the actual mapping is the other way around. Compare with the same anti-pattern in `customllms.CustomLlm.instructions: string` + `CustomLlm.guidelines: string[]` (audited in `.agent/naming-audit/customllms.md` #12) — that audit flagged the exact same overlap. - **Category:** 6 (misleading), 12 (duplicate concept), 15 (generic field). - **Suggested name:** Rename `KnowledgeAssistant.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerRules` or `responseGuidelines`. Both names disambiguate scope. - **Rationale:** Two free-text fields with synonymous names but different scope is one of the most common API-design defects. The audit caught the same pattern in `customllms`; flagging it here for SDK-wide consistency. -### 10. `KnowledgeSource.spec` discriminated union name is generic — `src/v1/model.ts:229` +### 8. `KnowledgeSource.spec` discriminated union name is generic — `src/v1/model.ts:229` - **Why weird:** `KnowledgeSource.spec?: { $case: 'index'; index: IndexSpec } | { $case: 'files'; files: FilesSpec } | { $case: 'fileTable'; fileTable: FileTableSpec } | undefined`. The discriminator field is called `spec` — a generic CS term. The doc says "Specification for the knowledge source type." Consumers writing autocomplete will see `source.spec.$case` and `source.sourceType` both meaning "what kind of source is this", and have to remember that `spec` carries the *data* and `sourceType` carries the *string label*. Compare with the `supervisoragents.Tool.spec` field (same anti-pattern; same audit flagged in the sibling). - **Category:** 1 (vague), 12 (duplicate of `sourceType` discriminant). - **Suggested name:** `config` if the union carries configuration (it does); or `source` to mirror the `$case` semantics ("which source variant"). Best: collapse `sourceType` and `spec` into a single discriminated union. - **Rationale:** `spec` is so generic it conveys no information; the type already conveys "this is the spec". +### 9. `KnowledgeAssistant_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:9` +- **Why weird:** The enum is named `KnowledgeAssistant_State` with a literal `_State` infix, and the file even carries an eslint-disable comment declaring "Proto-style nested enum name" (model.ts:8). The underscore is a direct architectural leak from the upstream `.proto` definition where the enum was nested inside the `KnowledgeAssistant` message (proto generates `OuterMessage_InnerEnum` for nested enums). TypeScript has no nested-enum-inside-class concept, so the underscore conveys nothing to a TS consumer and just signals "this code was generated from proto." +- **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). +- **Suggested name:** `KnowledgeAssistantState` (drop the underscore — already the convention in non-leaky TS APIs). The generator can flatten nested-enum names without changing the wire format. +- **Rationale:** The proto wire format and the TS identifier shape are decoupled. Carrying the `Outer_Inner` separator into TS leaks the generator's source format and conflicts with the SDK-wide naming-convention lint rule (the file disables `@typescript-eslint/naming-convention` for exactly this reason). + +### 10. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:17` +- **Why weird:** Same proto-nested-enum architectural leak as #9. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:16). Two sibling enums in the same file repeat the same proto-leak pattern. +- **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). +- **Suggested name:** `KnowledgeSourceState` (drop the underscore). +- **Rationale:** Same as #9. Generator-level fix. + ## Medium severity ### 11. `FileTableSpec.fileCol` cryptic abbreviation — `src/v1/model.ts:105` @@ -96,7 +96,7 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ### 12. `IndexSpec.textCol` / `IndexSpec.docUriCol` cryptic abbreviation — `src/v1/model.ts:145,147` - **Why weird:** Same `Col` abbreviation as #11, plus `docUri` truncates "document URI" awkwardly. Reading `docUriCol`, your eye parses `doc-Uri-Col` — three abbreviations stacked. The doc reads "The column that specifies a link or reference to where the information came from" — a much friendlier name would be `sourceUriColumn` or `referenceColumn`. - **Category:** 5 (cryptic abbreviation), 3 (acronym casing: `Uri` vs `URI`). -- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #36). +- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #34). - **Rationale:** The savings are minimal; the readability cost is real. ### 13. `IndexSpec.indexName` type-suffix tautology — `src/v1/model.ts:143` @@ -112,9 +112,9 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Rationale:** Same as #13. ### 15. `Example.question` + `Example.guidelines` field-name doublet — `src/v1/model.ts:86,91` -- **Why weird:** `Example` has two free-text payload fields: the question being asked and the guidelines for the answer. The current names are fine *in isolation*, but the type's own doc explains "Contains a question and guidelines for how the assistant should respond" — and the field names then duplicate the doc verbatim. The bigger issue: `guidelines: string[]` is plural and an array, but no JSDoc explains the semantics of each element (is each entry a sentence? a bullet? a paragraph?). Combined with the parallel `KnowledgeAssistant.instructions: string` (#9), the naming makes the conceptual hierarchy unclear. +- **Why weird:** `Example` has two free-text payload fields: the question being asked and the guidelines for the answer. The current names are fine *in isolation*, but the type's own doc explains "Contains a question and guidelines for how the assistant should respond" — and the field names then duplicate the doc verbatim. The bigger issue: `guidelines: string[]` is plural and an array, but no JSDoc explains the semantics of each element (is each entry a sentence? a bullet? a paragraph?). Combined with the parallel `KnowledgeAssistant.instructions: string` (#7), the naming makes the conceptual hierarchy unclear. - **Category:** 15 (generic field name losing meaning), 1 (vague — "guidelines" of what?). -- **Suggested name:** `Example.question` is fine; rename `Example.guidelines` → `answerGuidelines` (or `responseGuidelines`, paired with rename in #9). +- **Suggested name:** `Example.question` is fine; rename `Example.guidelines` → `answerGuidelines` (or `responseGuidelines`, paired with rename in #7). - **Rationale:** A type that owns a single question/answer pair should make the answer-shaped field explicit. ### 16. `KnowledgeAssistant.endpointName` underspecified — `src/v1/model.ts:191` @@ -234,12 +234,12 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Category:** 17 (reversed — consistency note). ### 34. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` -- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #5, #6). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. +- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #3, #4). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. ### 35. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` -- **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `APIError` usage. Cross-cutting observation from `customllms.md` #36. +- **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `ApiError` usage. Cross-cutting observation from `customllms.md` #36. - **Category:** 3 (acronym casing — SDK-wide). - **Suggested name:** SDK-wide policy decision. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index 3f56f887..55d8d0be 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,15 +3,15 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 35 +**Total weird names flagged:** 34 ## Summary | Severity | Count | | ----------- | ----- | | High | 6 | -| Medium | 15 | -| Low | 9 | +| Medium | 14 | +| Low | 10 | | Observation | 5 | ## Summary table @@ -19,7 +19,7 @@ | # | Severity | Location | Name | Category | | -- | ----------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------- | | 1 | High | package name | `lakeview` | 6 | -| 2 | High | `model.ts` enum | `DashboardView` | 1, 18 | +| 2 | High | `model.ts` enum | `DashboardView` | 1, 7 | | 3 | High | `model.ts` enum | `LifecycleState` | 1, 12 | | 4 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashDashboard` | 17 | | 5 | High | `model.ts` interface | `Dashboard` | 1, 15 | @@ -35,26 +35,24 @@ | 15 | Medium | `model.ts` field | `MigrateDashboardRequest.updateParameterSyntax` | 6, 13, 15 | | 16 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | | 17 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | -| 18 | Medium | `model.ts` interface | `GetPublishedDashboardEmbeddedRequest` | 1, 7 | -| 19 | Medium | `model.ts` field | `GetPublishedDashboardTokenInfoResponse.customClaim` | 15 | -| 20 | Medium | `model.ts` field | `AuthorizationDetails.type` | 10, 15 | -| 21 | Medium | `model.ts` field | `AuthorizationDetails.resourceLegacyAclPath` | 6, 14, 16 | -| 22 | Low | `model.ts` field | `Subscription.skipNotify` | 1, 14 | -| 23 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | -| 24 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | -| 25 | Low | `model.ts` field | `Schedule.warehouseId` | 19, 12 | -| 26 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | -| 27 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | -| 28 | Low | `model.ts` field | `Dashboard.serializedDashboard` | 20 | -| 29 | Low | `model.ts` field | `Dashboard.createTime` / `updateTime` & `Schedule.*` / `Subscription.*` | 9 | -| 30 | Low | `model.ts` field | `PublishedDashboard.revisionCreateTime` | 15 | -| 31 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | -| 32 | Low | `model.ts` field | `DashboardView.DASHBOARD_VIEW_BASIC` | 2, 18 | -| 33 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | -| 34 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | -| 35 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | -| 36 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | -| 37 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | +| 18 | Medium | `model.ts` field | `GetPublishedDashboardTokenInfoResponse.customClaim` | 15 | +| 19 | Medium | `model.ts` field | `AuthorizationDetails.type` | 10, 15 | +| 20 | Medium | `model.ts` field | `AuthorizationDetails.resourceLegacyAclPath` | 6, 14, 16 | +| 21 | Low | `model.ts` field | `Subscription.skipNotify` | 1, 14 | +| 22 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | +| 23 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | +| 24 | Low | `model.ts` field | `Schedule.warehouseId` | 19, 12 | +| 25 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | +| 26 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | +| 27 | Low | `model.ts` field | `Dashboard.serializedDashboard` | 20 | +| 28 | Low | `model.ts` field | `Dashboard.createTime` / `updateTime` & `Schedule.*` / `Subscription.*` | 9 | +| 29 | Low | `model.ts` field | `PublishedDashboard.revisionCreateTime` | 15 | +| 30 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | +| 31 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | +| 32 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | +| 33 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | +| 34 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | +| 35 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | --- @@ -77,7 +75,7 @@ The product is documented and marketed as "AI/BI Dashboards" (formerly "Lakeview **Rationale:** Discoverability. A user reading Databricks docs for "AI/BI Dashboards" will not find this package by name search. The Go SDK has the same problem, but TS has the chance to fix the surface visible to TS users at construction time (`new Client(...)`). -### 2. `DashboardView` — enum with a single value (`DASHBOARD_VIEW_BASIC`) +### 2. `DashboardView` — single-value enum with a generic, role-obscuring name **Location:** `src/v1/model.ts:6-9` @@ -88,11 +86,11 @@ export enum DashboardView { } ``` -The enum has only one member, and the member's name is prefixed with the enum name (proto-style "always include the type name in every value"). The literal `DashboardView.DASHBOARD_VIEW_BASIC` reads twice: `DashboardView` then `DASHBOARD_VIEW_BASIC`. The enum exists only because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.) — but until those exist the enum is a confusing single-value gate. +The enum has only one member. It exists because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.) — but until those exist the enum is a confusing single-value gate. `View` is also a generic name in a Dashboards package (it overloads the HTML/UI sense of "view" with the "field mask" sense — e.g. `proto3` partial-response style). -**Category:** 1 (vague), 18 (long enum value). +**Category:** 1 (vague), 7 (overengineering for binary). **Suggested name:** Either rename to `DashboardFieldMask` / `DashboardResponseMode` (closer to its actual role: a partial-response selector), or, until there is a second value, replace `view?: DashboardView` with `summaryOnly?: boolean` and delete the enum. @@ -126,7 +124,7 @@ import {LifecycleState as AlertLifecycle} from '@databricks/sdk-alerts'; ### 4. `LifecycleState.TRASHED` vs `trashDashboard()` — split vocabulary inherited from pre-v2 alerts -**Location:** `src/v1/model.ts:15`, `src/v1/client.ts:653` (`trashDashboard`), `src/v1/model.ts:429` (`TrashDashboardRequest`) +**Location:** `src/v1/model.ts:15`, `src/v1/client.ts:592` (`trashDashboard`), `src/v1/model.ts:403` (`TrashDashboardRequest`) The enum uses `TRASHED`, the method uses `trash`, the type uses `Trash`. **Same package, same operation, three forms**. Meanwhile every other CRUD-style endpoint in the Databricks SDK uses `Delete`/`delete`. Alerts has the *exact* same issue (flagged in `alerts.md` #11 and #12); it was kept in v1 and renamed to `DELETED` in alerts v2 — leaving Lakeview as an outlier. @@ -154,7 +152,7 @@ This is compounded by Databricks having (1) classic SQL dashboards (a separate A ### 6. `PublishedDashboard` — projection sibling of `Dashboard`, missing structural identity -**Location:** `src/v1/model.ts:323-332` +**Location:** `src/v1/model.ts:315-324` ```ts export interface PublishedDashboard { @@ -239,7 +237,7 @@ The field carries an IANA timezone name like `"America/Los_Angeles"`. That is no ### 10. `Schedule.cronSchedule` — type-suffix tautology -**Location:** `src/v1/model.ts:358` +**Location:** `src/v1/model.ts:332` ```ts export interface Schedule { @@ -280,7 +278,7 @@ Also: a two-value enum named `*Status` for two paused-or-not states is overengin ### 12. `Schedule.pauseStatus` — field describes a control input, not a status -**Location:** `src/v1/model.ts:360` +**Location:** `src/v1/model.ts:334` ```ts /** The status indicates whether this schedule is paused or not. */ @@ -297,7 +295,7 @@ pauseStatus?: SchedulePauseStatus | undefined; ### 13. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb -**Location:** `src/v1/model.ts:293`, `src/v1/client.ts:574` +**Location:** `src/v1/model.ts:285`, `src/v1/client.ts:540` "Migrate" can mean (a) copy and convert, (b) move-and-delete-source, (c) rewrite-in-place. The JSDoc on the method ("Migrates a classic SQL dashboard to Lakeview.") suggests (a): the source dashboard remains, a new AI/BI dashboard is created. The verb does not encode this. @@ -309,7 +307,7 @@ pauseStatus?: SchedulePauseStatus | undefined; ### 14. `MigrateDashboardRequest.sourceDashboardId` — domain mismatch -**Location:** `src/v1/model.ts:295` +**Location:** `src/v1/model.ts:287` ```ts /** UUID of the dashboard to be migrated. */ @@ -326,7 +324,7 @@ The package documents `dashboardId` as identifying a Lakeview / AI/BI dashboard. ### 15. `MigrateDashboardRequest.updateParameterSyntax` — confusing default + leaky implementation hint -**Location:** `src/v1/model.ts:300-304` +**Location:** `src/v1/model.ts:293-296` ```ts /** @@ -350,7 +348,7 @@ Issues: ### 16. `trashDashboard` — soft-delete method without a paired restore (see also #4) -**Location:** `src/v1/client.ts:653` +**Location:** `src/v1/client.ts:592` Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` method is paired with no `restoreDashboard` or `untrashDashboard`. The method moves the dashboard into `TRASHED` lifecycle state, but the API doesn't expose how to undo it via the SDK — a caller has to use `updateDashboard({ dashboard: { lifecycleState: ACTIVE } })`. Discovery from method names alone gives no hint that "restore" exists. @@ -362,7 +360,7 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met ### 17. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles -**Location:** `src/v1/model.ts:307`, `src/v1/model.ts:323` +**Location:** `src/v1/model.ts:299`, `src/v1/model.ts:315` `PublishDashboardRequest` is the input to `publishDashboard()`. `PublishedDashboard` is the response. The names are one letter apart (`Publish*` vs `Published*`). A code reader picking either out of an auto-complete list can grab the wrong one and the compiler will not immediately tell them apart at construction time — both are records with `warehouseId?: string`. @@ -372,25 +370,9 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met **Rationale:** Reduce typo bugs. The Databricks SDK already uses `*Options` in `ClientOptions`, `CallOptions`, so the pattern is precedented. -### 18. `GetPublishedDashboardEmbeddedRequest` / `getPublishedDashboardEmbedded` — adjective-as-method-suffix - -**Location:** `src/v1/model.ts:169-175`, `src/v1/client.ts:301` - -```ts -async getPublishedDashboardEmbedded(req: ...): Promise -``` - -41 characters in the method name; the suffix "Embedded" is an adjective stuck on the end of `getPublishedDashboard`. The natural English form is "get an embedded view of the published dashboard". The pairing `getPublishedDashboard` + `getPublishedDashboardEmbedded` suggests these are alternative *views* of the same resource — which is what flags 2, 5, and 6 hint at: the SDK uses three separate names for what is conceptually `getPublishedDashboard(mode: 'metadata' | 'embedded' | 'tokenInfo')`. - -**Category:** 1 (vague suffix), 7 (overly verbose). - -**Suggested name:** `getPublishedDashboardForEmbedding` or restructure as `getPublishedDashboard({ mode: 'embedded' })`. - -**Rationale:** Method name should hint at side effect or return shape; an adjective suffix does neither. - -### 19. `GetPublishedDashboardTokenInfoResponse.customClaim` — undescriptive field for opaque blob +### 18. `GetPublishedDashboardTokenInfoResponse.customClaim` — undescriptive field for opaque blob -**Location:** `src/v1/model.ts:196` +**Location:** `src/v1/model.ts:188` ```ts /** @@ -408,7 +390,7 @@ The doc string is the only place that defines what the field is — a URN with a **Rationale:** Distinct from the OIDC sense of "custom claim". -### 20. `AuthorizationDetails.type` — collides with TS reserved feeling +### 19. `AuthorizationDetails.type` — collides with TS reserved feeling **Location:** `src/v1/model.ts:28` @@ -426,7 +408,7 @@ The field's documented value space is also limited: `"workspace_rule_set"` is th **Rationale:** Avoid syntax-coloring confusion (`type: string` reads ambiguously) and signal that the field is a discriminator. -### 21. `AuthorizationDetails.resourceLegacyAclPath` — legacy compatibility field in current API +### 20. `AuthorizationDetails.resourceLegacyAclPath` — legacy compatibility field in current API **Location:** `src/v1/model.ts:36` @@ -451,9 +433,9 @@ Three issues: ## Low severity -### 22. `Subscription.skipNotify` — negative polarity boolean +### 21. `Subscription.skipNotify` — negative polarity boolean -**Location:** `src/v1/model.ts:400` +**Location:** `src/v1/model.ts:374` ```ts /** @@ -473,9 +455,9 @@ The doc also leaks "in the backend" — the default is the backend's, not the SD **Rationale:** Positive-polarity booleans halve the cognitive load. -### 23. `Subscription.createdByUserId` typed as `number` +### 22. `Subscription.createdByUserId` typed as `number` -**Location:** `src/v1/model.ts:386` +**Location:** `src/v1/model.ts:360` ```ts /** UserId of the user who adds subscribers (users or notification destinations) to the dashboard's schedule. */ @@ -492,7 +474,7 @@ Also, the doc string is past-tense verb plus present-tense ("adds") — inconsis **Rationale:** Silent overflow is the worst kind of bug. -### 24. `Dashboard.warehouseId` — underspecified ID +### 23. `Dashboard.warehouseId` — underspecified ID **Location:** `src/v1/model.ts:112` @@ -502,9 +484,9 @@ Also, the doc string is past-tense verb plus present-tense ("adds") — inconsis **Suggested name:** Keep `warehouseId`, but JSDoc should specify "SQL Warehouse ID (alphanumeric, found at `/sql/warehouses/{id}` in the UI)". -### 25. `Schedule.warehouseId` — duplicate concept with `Dashboard.warehouseId` +### 24. `Schedule.warehouseId` — duplicate concept with `Dashboard.warehouseId` -**Location:** `src/v1/model.ts:373` +**Location:** `src/v1/model.ts:347` ```ts /** The warehouse id to run the dashboard with for the schedule. */ @@ -517,9 +499,9 @@ A schedule can override the dashboard's default warehouse. This is fine, but the **Suggested name:** `warehouseIdOverride` or `overrideWarehouseId`. -### 26. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing +### 25. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing -**Location:** `src/v1/model.ts:118`, `src/v1/model.ts:367`, `src/v1/model.ts:391` +**Location:** `src/v1/model.ts:118`, `src/v1/model.ts:341`, `src/v1/model.ts:365` Consistent within the package, but the HTTP spec spells it `ETag`. Most TS SDKs use lowercase, so it's defensible. Flagged for whole-codebase consistency (compare `alerts.md` #14 on `notifyOnOk` for similar acronym-casing concerns). @@ -527,9 +509,9 @@ Consistent within the package, but the HTTP spec spells it `ETag`. Most TS SDKs **Suggested name:** Keep `etag`. Note the project convention. -### 27. `Dashboard.path` vs `Dashboard.parentPath` — overlap +### 26. `Dashboard.path` vs `Dashboard.parentPath` — overlap -**Location:** `src/v1/model.ts:99`, `src/v1/model.ts:135` +**Location:** `src/v1/model.ts:103`, `src/v1/model.ts:135` ```ts path?: string | undefined; // workspace path of the dashboard asset, including the file name @@ -542,7 +524,7 @@ parentPath?: string | undefined; // workspace path of the folder containing t **Suggested name:** Keep both. Either rename `path → fullPath` for symmetry, or document the relationship in JSDoc on both fields. -### 28. `Dashboard.serializedDashboard` — type-suffix tautology +### 27. `Dashboard.serializedDashboard` — type-suffix tautology **Location:** `src/v1/model.ts:127` @@ -556,7 +538,7 @@ Field is on `Dashboard`; suffix repeats the type name. The field holds a JSON st **Suggested name:** `serialized` or `content` or `layoutJson`. The dashboard's "content" is a more useful description. -### 29. `createTime`/`updateTime` suffix `Time` — convention question +### 28. `createTime`/`updateTime` suffix `Time` — convention question **Location:** Many fields on `Dashboard`, `Schedule`, `Subscription` @@ -566,9 +548,9 @@ The package uses `*Time` suffix (`createTime`, `updateTime`). The alerts v2 pack **Suggested name:** Pick a project-wide convention. Recommend `*At` for instants (`createdAt`, `updatedAt`). Aligns with idiomatic JS/TS and the Rails-influenced ecosystem. -### 30. `PublishedDashboard.revisionCreateTime` — over-qualified +### 29. `PublishedDashboard.revisionCreateTime` — over-qualified -**Location:** `src/v1/model.ts:331` +**Location:** `src/v1/model.ts:323` ```ts /** The timestamp of when the published dashboard was last revised. */ @@ -581,9 +563,9 @@ revisionCreateTime?: Temporal.Instant | undefined; **Suggested name:** `publishedAt` or `lastPublishedAt`. Captures the user's mental model directly. -### 31. `ListDashboardsRequest.showTrashed` — verb mismatch with state name (trash/delete vocabulary) +### 30. `ListDashboardsRequest.showTrashed` — verb mismatch with state name (trash/delete vocabulary) -**Location:** `src/v1/model.ts:235` +**Location:** `src/v1/model.ts:227` ```ts showTrashed?: boolean | undefined; @@ -595,21 +577,11 @@ The field is named `showTrashed`, but the lifecycle state is `TRASHED`. Consiste **Suggested name:** Tie to whichever vocabulary wins. If `delete`/`DELETED`, then `includeDeleted`. The `show` prefix is also UI-flavored (compare `include`/`with` prefixes in REST APIs). -### 32. `DashboardView.DASHBOARD_VIEW_BASIC` — long enum value (see #2 for the enum itself) - -**Location:** `src/v1/model.ts:8` - -Member is `DASHBOARD_VIEW_BASIC = 'DASHBOARD_VIEW_BASIC'` — both Pascal-prefix and the literal value carry `DASHBOARD_VIEW_`. The wire format is locked, but the TS member name need not echo the enum prefix: `BASIC = 'DASHBOARD_VIEW_BASIC'` is sufficient. - -**Category:** 2 (redundant enum prefix), 18 (long). - -**Suggested name:** `DashboardView.BASIC = 'DASHBOARD_VIEW_BASIC'`. - --- ## Observations -### 33. `Dashboard.dashboardId` — tautology at use site +### 31. `Dashboard.dashboardId` — tautology at use site **Location:** `src/v1/model.ts:95` @@ -626,7 +598,7 @@ Caller writes `dashboard.dashboardId`. Inside a type already named `Dashboard`, **Suggested name:** `Dashboard.id` (and similarly `Schedule.id`, `Subscription.id`). Marshal/unmarshal already remaps to/from `dashboard_id`. -### 34. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix +### 32. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix **Location:** `src/v1/model.ts:61,67` @@ -639,22 +611,22 @@ datasetSchema?: string | undefined; **Suggested name:** Keep. Add JSDoc clarifying "this is the Unity Catalog *catalog* / *schema* applied to dataset queries". Done already in the JSDoc, but worth flagging. -### 35. `ListSchedulesRequest.dashboardId` doc typo +### 33. `ListSchedulesRequest.dashboardId` doc typo -**Location:** `src/v1/model.ts:250` +**Location:** `src/v1/model.ts:242` ```ts /** UUID identifying the dashboard to which the schedules belongs. */ dashboardId?: string | undefined; ``` -"schedules belongs" — verb agreement error. Same on `ListSubscriptionsRequest.dashboardId` line 271 ("subscriptions belongs") and 273 ("subscriptions belongs"). Generated-code artifact; fix at template level. +"schedules belongs" — verb agreement error. Same on `ListSubscriptionsRequest.dashboardId` line 263 ("subscriptions belongs") and 265 ("subscriptions belongs"). Generated-code artifact; fix at template level. **Category:** 9 (plural verb agreement). -### 36. `index.ts` — mixed `export {...}` and `export type {...}` +### 34. `index.ts` — mixed `export {...}` and `export type {...}` -**Location:** `src/v1/index.ts:5,7-47` +**Location:** `src/v1/index.ts:5,7-43` ```ts export {DashboardView, LifecycleState, SchedulePauseStatus} from './model'; @@ -663,9 +635,9 @@ export type {AuthorizationDetails, ...} from './model'; Enums are exported as values (correct — they have runtime representation); interfaces are exported as types (correct — type-only). The pattern is right; flagging only because a reader scanning the index file might miss the distinction. Consistent with other SDK packages. -### 37. URL paths still use `lakeview` +### 35. URL paths still use `lakeview` -**Location:** Every method's URL constant in `client.ts`, e.g. line 112: `/api/2.0/lakeview/dashboards` +**Location:** Every method's URL constant in `client.ts`, e.g. line 105: `/api/2.0/lakeview/dashboards` Wire-format. The SDK cannot rename the URL without server cooperation. Flagged so that the rebrand mismatch noted in #1 is understood as partial (TS name is the lever; URLs are not). @@ -678,9 +650,15 @@ Wire-format. The SDK cannot rename the URL without server cooperation. Flagged s Lakeview / AI/BI Dashboards is a relatively small surface (5 enums-and-resources, 19 client methods) but the naming smells cluster around: 1. **The rebrand from "Lakeview" to "AI/BI Dashboards"** is incomplete — the package name and URLs preserve the old codename, while the JSDoc mixes the two. -2. **The trash/delete vocabulary split** (#4, #16, #31) is inherited from the alerts package's pre-v2 design — already fixed in alerts v2 but not in lakeview. +2. **The trash/delete vocabulary split** (#4, #16, #30) is inherited from the alerts package's pre-v2 design — already fixed in alerts v2 but not in lakeview. 3. **Generic top-level type names** (`Dashboard`, `LifecycleState`, `CronSchedule`, `SchedulePauseStatus`) overlap with other packages in the SDK monorepo and force consumers to import-rename. 4. **`Schedule.pauseStatus` enum is a binary boolean** (#11, #12) — `paused: boolean` would be more idiomatic TS. -5. **64-bit user IDs typed as `number`** (#23) silently truncate above 2^53. Same issue exists in other packages but is unsurfaced here. +5. **64-bit user IDs typed as `number`** (#22) silently truncate above 2^53. Same issue exists in other packages but is unsurfaced here. If only one change were possible, completing the trash/delete vocabulary unification (renaming `trashDashboard` + `TRASHED` + `showTrashed` to the `delete`/`DELETED`/`includeDeleted` family used by alerts v2) would remove the most visible inconsistency. + +--- + +## Fixed + +- #18 `GetPublishedDashboardEmbeddedRequest` / `getPublishedDashboardEmbedded` (originally cited at `src/v1/model.ts:169-175` and `src/v1/client.ts:301`): Fixed in regeneration on 2026-05-20 — the embedded-view request type and method were removed from the generated client. diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md new file mode 100644 index 00000000..dcbea5e8 --- /dev/null +++ b/.agent/naming-audit/logdelivery.md @@ -0,0 +1,232 @@ +# Naming Audit: logdelivery + +**Path:** `packages/logdelivery/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level CRUD for log delivery configurations +(`POST/GET/PATCH /api/2.0/accounts/{account_id}/log-delivery`). A log +delivery configuration ties a `credentialsId` (AWS IAM role) and a +`storageConfigurationId` (S3 bucket) to a log type (`BILLABLE_USAGE` or +`AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no +delete endpoint by design — the API only supports disabling via the +update (`PATCH`) method. +**Total weird names flagged:** 28 + +## Summary +| Severity | Count | +| --- | --- | +| High | 6 | +| Medium | 11 | +| Low | 7 | +| Observation | 4 | + +## High severity + +### 1. `LogDeliveryStatusEnum` — type name carries `Enum` suffix — `src/v1/model.ts:39` +- **Why weird:** `LogDeliveryStatusEnum` is the only type in the package whose name ends in `Enum`. The three sibling enums (`LogDeliveryConfigStatus` at line 12, `LogDeliveryOutputFormat` at line 23, `LogDeliveryType` at line 56) carry no such suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` is already claimed by the wrapper *interface* at `model.ts:208` (which holds `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, and `status`). +- **Category:** 20 (type-suffix tautology), 12 (duplicate concept — `LogDeliveryStatus` interface and `LogDeliveryStatusEnum` enum coexist). +- **Suggested name:** Rename the wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (it models the most-recent attempt, not the status per se), and rename the enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The field site then reads `attempt.status: LogDeliveryAttemptStatus` instead of `logDeliveryStatus.status: LogDeliveryStatusEnum`. +- **Rationale:** The `Enum` suffix is unique to this one type and signals that the underlying noun is overloaded. Splitting the noun ("attempt" for the wrapper, "attempt status" for the values) removes the suffix and the conflation in one rename. + +### 2. `LogDeliveryConfigStatus` vs `LogDeliveryStatusEnum` — two enums named "status" of "log delivery" for orthogonal facets — `src/v1/model.ts:12,39` +- **Why weird:** Both enums describe "status" of "log delivery", but their domains are unrelated: + - `LogDeliveryConfigStatus`: `ENABLED` / `DISABLED` — whether the configuration is active. + - `LogDeliveryStatusEnum`: `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` — whether the most recent delivery attempt worked. + + Inside `LogDeliveryConfiguration` both surface as `status` fields one level apart: `LogDeliveryConfiguration.status: LogDeliveryConfigStatus` (line 199) and `LogDeliveryConfiguration.logDeliveryStatus.status: LogDeliveryStatusEnum` (line 217). A reviewer cannot tell at a glance which `status` is meant. +- **Category:** 12 (duplicate concept), 6 (misleading — same noun for incompatible domains). +- **Suggested name:** Rename to expose the distinction: `LogDeliveryConfigStatus` → `LogDeliveryEnablement` (`ENABLED` / `DISABLED`) and `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus` (`CREATED` / `SUCCEEDED` / ...). +- **Rationale:** Identical nouns for incompatible domains are a classic bug source. Differentiated nouns ("enablement" vs "attempt status") make the two enums distinguishable at the call site. + +### 3. `LogDeliveryConfigStatus` JSDoc describes a different concept than the values — `src/v1/model.ts:5-11` +- **Why weird:** The class-level JSDoc reads: + + ``` + Log Delivery Status + + `ENABLED`: All dependencies have executed and succeeded + `DISABLED`: At least one dependency has succeeded + ``` + + The values are `ENABLED` / `DISABLED` of a *configuration* (the per-member docs say "Configuration is enabled" / "Configuration is disabled"). The class doc appears to have been copy-pasted from a Workflows-domain enum (DLT pipelines have "dependencies"). The stray leading `*` on line 6 is a generator artefact that recurs on every multi-line block in this file (`model.ts:6,20,31,53,64,107,121,138,166,227`). +- **Category:** 6 (misleading — JSDoc claim contradicts type domain). +- **Suggested name:** Rewrite JSDoc to "Whether this log delivery configuration is active. Modified via the patch-status endpoint." +- **Rationale:** Wrong JSDoc is worse than missing JSDoc — IDE tooltips, hover-help, and generated reference docs will all display the unrelated "dependencies" prose. The stray `* *` opening line is generator-level and worth fixing globally. + +### 4. `LogDeliveryConfiguration.configId` / `.configName` use the cryptic abbreviation `config` — `src/v1/model.ts:171,173` +- **Why weird:** The field is `configId`, not `logDeliveryConfigurationId` (also at `model.ts:69,71`, `model.ts:126`, `model.ts:232`, `client.ts:94,126,154,218`). Inside the enclosing `LogDeliveryConfiguration` the abbreviation is contextually OK, but `configId` is generic at every method-call site — `req.configId` and the URL template `/log-delivery/${req.configId}` read as domain-detached. A consumer composing multiple Databricks SDK clients cannot grep for `configId` and know which "config" is meant. +- **Category:** 5 (cryptic abbreviation), 19 (under-specified id). +- **Suggested name:** Two coherent options: + 1. Keep `configId` (short, matches wire `config_id`) but rely on the enclosing type to disambiguate — same idiom as `databricks-sdk-go`. + 2. Rename to bare `id` and let `LogDeliveryConfiguration.id` carry meaning structurally — same idiom as Stripe (`Customer.id`), GitHub (`Repository.id`), and Google. +- **Rationale:** Pick one convention and apply globally. `configId` is the worst of both — a half-abbreviation that is neither a generic `id` nor a fully-qualified `logDeliveryConfigurationId`. + +### 5. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` +- **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:126,218`). The client substitutes them via `?? ''` (`client.ts:126,218`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). +- **Category:** 6 (misleading — type signature says optional, runtime requires non-empty), 7 (overly verbose / boilerplate JSDoc). +- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create` — see finding 23). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." +- **Rationale:** Required path params should have required types. The current shape silently produces malformed URLs at runtime. The "of customer" prose is generator-emitted boilerplate worth removing globally. + +### 6. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` +- **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:209-213`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus`, which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. +- **Category:** 6 (misleading), 17 (verb inconsistency — Go uses `PatchStatus`, TS paraphrases as `update`). +- **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:227`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. +- **Rationale:** "Update" implies multi-field mutation. A caller writing `updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new'})` will be surprised — `deliveryPathPrefix` is not on the DTO so TS will type-error, but only after the user reads the type. The verb is a footgun and the existing JSDoc admits it. Naming should match capability. + +## Medium severity + +### 7. `Client` class is unprefixed — `src/v1/client.ts:46`, exported at `src/v1/index.ts:3` +- **Why weird:** A user importing the package writes `import {Client} from '@databricks/sdk-logdelivery/v1'` and must alias (`import {Client as LogDeliveryClient}`) to compose with any other Databricks SDK client. Consistent across the SDK; flagged once per package. +- **Category:** 1 (vague), 12 (duplicate concept — every Databricks SDK package exports its own `Client`). +- **Suggested name:** `LogDeliveryClient` (or expose a namespace and let `logDelivery.Client` be the qualified name). +- **Rationale:** Every audited package has this finding. Worth normalising at generator level. + +### 8. Client method names embed the noun three times — `src/v1/client.ts:90,122,150,214` +- **Why weird:** `client.createLogDeliveryConfiguration({logDeliveryConfiguration: {...}})` repeats the noun phrase three times in a single expression (`createLogDeliveryConfiguration` — `logDeliveryConfiguration` — wrapped content). The Go SDK uses short names (`Create`, `Get`, `List`, `PatchStatus`) because the receiver type provides the noun. The TS port re-states the full noun on the method. +- **Category:** 7 (overly verbose), 17 (inconsistent with sibling packages that use shorter verbs once `Client` is qualified). +- **Suggested name:** `client.create()` / `client.get()` / `client.list()` / `client.listIter()` / `client.patchStatus()`. Pair with finding 7 so the receiver is `LogDeliveryClient`. +- **Rationale:** Once the class is `LogDeliveryClient`, the short methods are unambiguous. Same finding as `disasterrecovery` (M16/L17) and `externallineage` (#23). + +### 9. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` +- **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:160`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `listLogDeliveryConfigurations` (plural). The `*Iter` pagination helper should match: `listLogDeliveryConfigurationsIter`. +- **Rationale:** Method-name pluralisation should match the data shape it yields. + +### 10. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` +- **Why weird:** Same shape mismatch as finding 9, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and the `_Response` partner correspondingly). +- **Rationale:** Pluralisation is the standard signal for a collection-returning method/type pair. + +### 11. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` +- **Why weird:** Reading `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types whose names all carry "Status": + - `LogDeliveryConfiguration` (the resource). + - `LogDeliveryStatus` (wrapper for the last-attempt fields). + - `LogDeliveryStatusEnum` (the actual enum values). + + Each layer adds the same noun with different meaning. The field name `logDeliveryStatus` is also redundant inside a `LogDeliveryConfiguration` — the `LogDelivery` prefix is implied by the parent type. +- **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). +- **Suggested name:** Rename field `logDeliveryStatus` → `lastAttempt`. Rename wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`). Rename enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The call site becomes `config.lastAttempt.status === 'SUCCEEDED'` — three concrete nouns instead of three "Status" repetitions. +- **Rationale:** "Status" is too generic to triple-stack. Aligns with findings 1 and 2. + +### 12. `creationTime` / `updateTime` — noun/verb tense mismatch, ambiguous unit — `src/v1/model.ts:99-101,201-203` +- **Why weird:** `creationTime: number` (noun form "creation") paired with `updateTime: number` (verb form "update"). They should match: either `createdTime` / `updatedTime` (past participle) or `creationTime` / `updateTime` (noun + verb is inconsistent). Both are typed `number` but the unit (epoch milliseconds) lives only in the JSDoc — a reader scanning the type cannot tell whether this is seconds, milliseconds, or microseconds. +- **Category:** 13 (verb-tense inconsistency), 6 (misleading — bare `number` does not encode "epoch ms"). +- **Suggested name:** `createdAt: number` / `updatedAt: number` (the canonical SaaS convention used by Stripe, GitHub, Salesforce, Atlassian, Linear). Brand the type as `EpochMillis` to encode the unit at compile time. +- **Rationale:** `*At` is the industry standard for timestamps. Generator-wide concern — many audited packages share this finding. + +### 13. `deliveryStartTime: string` is a YYYY-MM date, not a time — `src/v1/model.ts:95,197` +- **Why weird:** The field is `string` typed, but the JSDoc says "specified in YYYY-MM format". That is a year-month bucket, not a "time". Compare with `creationTime: number` (an epoch-ms timestamp) in the same struct — the word "Time" is used for two different granularities. +- **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" suggests a timestamp). +- **Suggested name:** `deliveryStartMonth: string` (or, since `@js-temporal/polyfill` is already a workspace dependency, `Temporal.PlainYearMonth`). +- **Rationale:** "Time" implies sub-day resolution; the domain is monthly billing buckets, so "Month" is the right granularity. Same convention as Stripe's `period_start` (timestamp) vs `period.start` (date-only) split. + +### 14. `workspaceIdsFilter` — redundant `Filter` suffix on a collection field — `src/v1/model.ts:91,193` +- **Why weird:** The field is `workspaceIdsFilter: number[]` on both the request DTO (`CreateLogDeliveryConfigurationParams`, line 91) and the response DTO (`LogDeliveryConfiguration`, line 193). On the response DTO, `Filter` is misleading — the same field stores the configured workspace scope, not a "filter" applied at read time. Compare with `ListLogDeliveryConfigurationRequest.credentialsId: string` at `model.ts:145` (no `Filter` suffix, same conceptual role as a list filter). +- **Category:** 7 (overly verbose), 15 (generic suffix). +- **Suggested name:** `workspaceIds: number[]` (the array shape already conveys "list of workspace IDs"; the `Filter` suffix carries no extra signal). +- **Rationale:** Field naming should describe content. A `number[]` named after the entity is unambiguous. + +### 15. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` +- **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double-precision float — only safe up to 2^53 − 1. Databricks workspace IDs are int64 server-side; transmitting an ID above the safe range silently loses precision in the JSON wire round-trip. +- **Category:** 6 (misleading — TS type cannot represent the wire's int64 safely), 19 (under-specified id type). +- **Suggested name:** `workspaceIds: bigint[]` (matches int64 wire). Alternative: brand the IDs as `WorkspaceId` via `type WorkspaceId = bigint & {__brand: 'WorkspaceId'}`. +- **Rationale:** Cross-package finding — every `*Id: number` typed against an int64 wire has the same hazard. Generator-level fix: emit `bigint` for `int64` fields. + +### 16. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` +- **Why weird:** `private readonly host: string` — without context, `host` could be just a hostname (`example.com`). The setter at line 62 trims a trailing slash, hinting that the field actually carries a full URL with scheme. A user wiring up `ClientOptions.host` cannot tell from the type whether to pass `databricks.com` or `https://databricks.com/`. +- **Category:** 1 (vague), 15 (generic field name). +- **Suggested name:** `baseUrl: string` (or `databricksHost`). Matches the actual content (a URL including scheme). +- **Rationale:** Generator-level concern — every package's `Client` has this field. Same finding as `disasterrecovery` and others. + +### 17. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` +- **Why weird:** Two functions both prefixed `execute` doing very different jobs. `executeCall` wraps a call in retry/rate-limit (`utils.ts:26-38`); `executeHttpCall` does the raw HTTP send plus error lift (`utils.ts:65-94`). Inside each client method, `executeHttpCall` is wrapped in a `Call` (the function alias), and `executeCall(call, options)` runs it — the reader has to trace both bodies to learn who calls whom. +- **Category:** 1 (vague), 12 (duplicate prefix), 17 (inconsistent layering nomenclature). +- **Suggested name:** `runWithRetry(call, options)` (outer) + `sendHttp(opts)` or `dispatchHttp(opts)` (inner). The verb pair "run" vs "send" makes the layering obvious. +- **Rationale:** Layer names should make the call graph readable. Same finding cross-package; generator-level concern. + +## Low severity + +### 18. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` +- **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered by this configuration. Pair-wise consistency would be either `BILLABLE_USAGE_LOGS` + `AUDIT_LOGS` (both plural with `_LOGS`) or `BILLABLE_USAGE` + `AUDIT` (both singular without). +- **Category:** 9 (singular/plural mismatch), 18 (long enum values). +- **Suggested name:** `BILLABLE_USAGE` + `AUDIT` (drop `_LOGS` — the enum is `LogDeliveryType` so "logs" is implicit). +- **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the enclosing type) is shorter. + +### 19. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` JSDoc is tautological — `src/v1/model.ts:13-16` +- **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the per-member doc echoes the identifier verbatim. JSDoc should add information. +- **Category:** 1 (vague — doc carries no new signal). +- **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured bucket." +- **Rationale:** Generator-wide concern. Same in many audited packages. + +### 20. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` +- **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc on line 37 says it means "the log delivery status as the configuration has been disabled since the release of this feature or there are no workspaces in the account". That is "no data to report", not "resource missing". +- **Category:** 6 (misleading — value name suggests an HTTP error state, semantics are operational). +- **Suggested name:** `NO_DATA`, `NOT_APPLICABLE`, or `DISABLED_AT_RELEASE` — anything that does not read as 404. +- **Rationale:** A monitoring dashboard surfacing `status === 'NOT_FOUND'` would mislead an operator into thinking the configuration was deleted. + +### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` +- **Why weird:** `Segment` is a generic CS term. The leading comment ("Package identity segment for this client to be used in the User-Agent header.", line 40) does the documentation work the name should do. +- **Category:** 1 (vague), 15 (generic). +- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. +- **Rationale:** Generator-wide concern. Same finding in every audited package. + +### 22. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` +- **Why weird:** Field name and type both end in `Client`. The shorter form would be `client: HttpClient`, but that would collide with the enclosing `Client` class. So the disambiguation is mechanical, not informative. +- **Category:** 20 (type-suffix tautology). +- **Suggested name:** `transport: HttpClient` (matches the imported `./transport` module) — avoids the `Client/Client` echo and reads as "the transport layer". +- **Rationale:** Generator-wide concern. Tolerable as-is but flagged per rule 20. + +### 23. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` +- **Why weird:** Three-letter abbreviations on parameter and local names across every method. The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. +- **Category:** 5 (cryptic abbreviation). +- **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. +- **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. + +### 24. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` +- **Why weird:** Holds the request shape mutated with `pageToken` between pages. The name reads as "the page's request" rather than "the request iterated across pages". +- **Category:** 5 (cryptic), 1 (vague). +- **Suggested name:** `currentRequest`, `paginatedRequest`, or just `request` (the per-iteration redefinition is clear from context). +- **Rationale:** Loop-local; low impact. + +## Observations + +### 25. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +`client.ts` constructs query params inline (lines 155-167) with `new URLSearchParams()` and `params.append(...)`. The exported `flattenQueryParams` helper is never called from this package. Every generated package ships this helper unconditionally — it is generator scaffolding. +- **Category:** 11 (unused public helper). +- **Suggested fix:** Generator-level — only emit `flattenQueryParams` when the client actually needs it. + +### 26. `accountId` URL fallback is inconsistent between create and other methods — `src/v1/client.ts:94,126,154,218` +`createLogDeliveryConfiguration` reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client-options fallback), while `getLogDeliveryConfiguration`, `listLogDeliveryConfiguration`, and `updateLogDeliveryConfiguration` all read `req.accountId ?? this.accountId ?? ''`. A caller who sets `ClientOptions.accountId` once and forgets to copy it into `logDeliveryConfiguration` on create silently sends a request to `/api/2.0/accounts//log-delivery`. The asymmetry is not advertised by the type — both shapes accept `accountId: string | undefined`. +- **Category:** 6 (misleading — same-named field has different fallback semantics on create vs read), 16 (field placement contradicts wire-level convention). +- **Suggested fix:** On `create`, also fall back to `this.accountId`. Better: lift `accountId` out of `CreateLogDeliveryConfigurationParams` entirely (it is a path param, not a body field) so the shape matches the other three methods. This is a correctness bug surfaced by a naming/structure inconsistency. + +### 27. JSDoc artefacts: stray ` * *` opening lines and unresolved `` templates — `src/v1/model.ts:6,20,31,53,64,107,121,138,166,227` and `model.ts:84,127,142,186,233` +Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` line (e.g., line 5-7: `/**\n * *\n * Log Delivery Status`). Looks like the generator emits an empty paragraph break that renders as a literal `*`. Separately, the placeholder `` appears unsubstituted throughout (e.g., `model.ts:84,127,142,186,233` — "`` account ID"). Neither is a naming issue per se but both pollute the rendered docs. +- **Category:** Observation (generator template hygiene). + +### 28. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` +The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. + +## Domain glossary +- **`account`** — Databricks account, the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) and as `ClientOptions.accountId` (`client.ts:50,63`). +- **`workspace`** — A Databricks workspace under an account. Workspace IDs are `int64` on the wire but typed `number` in TS (finding 15). +- **`credentials`** — Cross-package reference (`Credentials.Create`) — a stored AWS IAM role with policy and trust relationship. The `credentialsId` field (`model.ts:87,189`) links a log delivery config to that resource. +- **`storage configuration`** — Cross-package reference (`Storage.Create`) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:89,191`) links the config to a bucket. +- **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` instructing Databricks to write certain logs to a bucket. +- **`log type`** — `BILLABLE_USAGE` or `AUDIT_LOGS` — the category of logs delivered. +- **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always implied by `log type` (finding 28). +- **`delivery path prefix`** — S3 key prefix; defaults to bucket root. Must not start or end with `/`. +- **`delivery start time`** — `YYYY-MM` string (a month bucket, not a timestamp — finding 13). Only applies to billable usage; lower bound is `2019-03`. +- **`config status`** — `ENABLED` / `DISABLED` (`LogDeliveryConfigStatus`). The config is never deleted, only disabled. +- **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` (`LogDeliveryStatusEnum`). Reflects the most-recent attempt; surfaces as `LogDeliveryStatus.status`, i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`. +- **`E2`** — Databricks newer multi-region account architecture. Mentioned in `UpdateLogDeliveryConfigurationRequest.accountId` JSDoc (`model.ts:233`). +- **`int64`** — Wire-level 64-bit signed integer. Used for workspace IDs; typed `number` in TS (lossy — finding 15). +- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`). Go SDK exposes this as `PatchStatus`; the TS port paraphrases it as `updateLogDeliveryConfiguration` (finding 6). + +## File coverage +- `src/v1/model.ts` (403 lines): read fully. +- `src/v1/client.ts` (244 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (24 lines): read fully. +- `src/v1/transport.ts` (75 lines): read fully (no findings — auth/timeout wrappers are unremarkable). diff --git a/.agent/naming-audit/logdeliveryconfigurations.md b/.agent/naming-audit/logdeliveryconfigurations.md index 2025dc79..fa2af275 100644 --- a/.agent/naming-audit/logdeliveryconfigurations.md +++ b/.agent/naming-audit/logdeliveryconfigurations.md @@ -1,7 +1,11 @@ # Naming Audit: `logdeliveryconfigurations` (v1) -**Package:** `@databricks/sdk-logdeliveryconfigurations` -**Path:** `/home/parth.bansal/sdk-js/packages/logdeliveryconfigurations/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Package:** `@databricks/sdk-logdelivery` +**Path:** `/home/parth.bansal/sdk-js/packages/logdelivery/` **Version audited:** `v1` **Files audited:** - `src/v1/model.ts` (404 lines) @@ -17,14 +21,14 @@ A log delivery configuration ties a `credentialsId` (AWS IAM role) and a endpoint by design — the API only supports disabling via the update method. -**Total weird names flagged: 33** +**Total weird names flagged: 35** ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 11 | +| Medium | 13 | | Low | 10 | | Observation | 6 | @@ -32,21 +36,14 @@ method. ## High severity -### H1. Package name `logdeliveryconfigurations` is overly verbose — `packages/logdeliveryconfigurations/` -- **File:** package directory. -- **Category:** 7 (overly verbose), 9 (singular/plural mismatch — pluralised package while every type inside is singular), 14 (Go/proto-style names). -- **Why weird:** 25 characters of all-lowercase concatenation — the longest single-domain package name in the workspace (compare `usagepolicy`, `usagedashboards`, `accountsettings`, `accountaccesscontrol`). The plural `configurations` is unique among sibling account packages, all of which use singular nouns (`accountsettings`, `usagepolicy`, `usagedashboards`, `billableusagedownload`). Users importing this package write `import {Client} from '@databricks/sdk-logdeliveryconfigurations/v1'` — 47 characters of specifier just to reach `Client`. -- **Suggested name:** `logdelivery` (singular, 11 chars, matches the URL path segment `/log-delivery` and the Go SDK service name `LogDelivery`). The doc comments inside this file already use "log delivery" as the noun phrase (`Client/Create`, `LogDelivery/PatchStatus` in `client.ts:88,213`). -- **Rationale:** Singular service noun is the cross-SDK convention. The TS types are already singular (`LogDeliveryConfiguration`, not `LogDeliveryConfigurations`). The trailing `s` produces a plural/singular mismatch between the package name and the dominant type. Fix at generator level since it affects every package. - -### H2. `LogDeliveryStatusEnum` — type-name carries `Enum` suffix — `model.ts:39` +### H1. `LogDeliveryStatusEnum` — type-name carries `Enum` suffix — `model.ts:39` - **File:** `model.ts:39-50`, exported in `index.ts:8`. - **Category:** 20 (type-suffix tautology), 12 (duplicate concept — two enums with overlapping prefixes). - **Why weird:** `LogDeliveryStatusEnum` is the *only* type in the audited package (and one of the few across the workspace) whose name ends in `Enum`. Every other enum here is just `LogDeliveryConfigStatus`, `LogDeliveryType`, `LogDeliveryOutputFormat` — no suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` was already claimed by the wrapper *interface* at `model.ts:208`. - **Suggested name:** Rename the wrapper interface to `LogDeliveryAttempt` (it actually holds attempt fields: `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, `status`), freeing `LogDeliveryStatus` for the enum. Alternatively, rename the enum to `LogDeliveryAttemptStatus` (drops `Enum`, matches the fields it describes). - **Rationale:** A field typed `attempt.status: LogDeliveryAttemptStatus` reads better than `logDeliveryStatus.status: LogDeliveryStatusEnum`. The `Enum` suffix is type-suffix tautology and is unique to this one type — a clear smell that the underlying noun is overloaded. -### H3. `LogDeliveryConfigStatus` vs `LogDeliveryStatusEnum` — two near-identical enum names for unrelated concepts — `model.ts:12,39` +### H2. `LogDeliveryConfigStatus` vs `LogDeliveryStatusEnum` — two near-identical enum names for unrelated concepts — `model.ts:12,39` - **File:** `model.ts:12-17`, `model.ts:39-50`. - **Category:** 12 (duplicate concept), 6 (misleading — both contain "status" + "log delivery"). - **Why weird:** Both enums describe "status" of "log delivery", but cover orthogonal facets: @@ -56,7 +53,7 @@ method. - **Suggested name:** `LogDeliveryConfigStatus` → `LogDeliveryEnablement` (`ENABLED` / `DISABLED`). `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus` (`CREATED` / `SUCCEEDED` / ...). The differentiated nouns ("enablement" vs "attempt status") make the two enums distinguishable at the call site. - **Rationale:** Identical noun ("Status") for incompatible domains is a classic source of bugs: a reviewer cannot tell at a glance whether `status === 'CREATED'` is checking the config or the last-delivery state. Renaming forces the distinction. -### H4. `LogDeliveryConfigStatus` JSDoc is wrong — `model.ts:8-10` +### H3. `LogDeliveryConfigStatus` JSDoc is wrong — `model.ts:7-10` - **File:** `model.ts:5-11`. - **Category:** 6 (misleading — JSDoc claim contradicts type domain). - **Why weird:** Class-level JSDoc says: @@ -67,10 +64,10 @@ method. ``` But the enum values are `ENABLED` / `DISABLED` of a *configuration*, with the actual member docs reading "Configuration is enabled" / "Configuration is disabled". The class doc appears imported from a Workflows-domain enum (DLT pipelines have "dependencies"). The leading bare `*` on line 6 is also stray (likely an artefact of the generator emitting `/** * */` blocks). - **Suggested name:** Rewrite JSDoc to "Whether this log delivery configuration is currently active. Set via the patch-status endpoint." -- **Rationale:** Misleading JSDoc is worse than no JSDoc — IDE tooltips, hover-help, and generated API reference will all display the wrong meaning. Same finding for `LogDeliveryOutputFormat` (line 22) and `LogDeliveryType` (line 54) — all three carry the stray `* ` on the second line. Across the SDK this is a generator artefact worth fixing globally. +- **Rationale:** Misleading JSDoc is worse than no JSDoc — IDE tooltips, hover-help, and generated API reference will all display the wrong meaning. Same finding for `LogDeliveryOutputFormat` (line 22) and `LogDeliveryType` (line 56) — all three carry the stray `* ` on the second line. Across the SDK this is a generator artefact worth fixing globally. -### H5. `LogDeliveryConfiguration.configId` and `.configName` use the cryptic abbreviation `config` — `model.ts:171,173` -- **File:** `model.ts:171,173` (also `model.ts:83,85`, `model.ts:126`, `model.ts:232`, `client.ts:94,126,154,218`). +### H4. `LogDeliveryConfiguration.configId` and `.configName` use the cryptic abbreviation `config` — `model.ts:171,173` +- **File:** `model.ts:171,173` (also `model.ts:69,71`, `model.ts:126`, `model.ts:232`, `client.ts:94,126,154,218`). - **Category:** 5 (cryptic abbreviation), 19 (underspecified ID — `configId` of what?). - **Why weird:** The field is named `configId`, not `logDeliveryConfigurationId`. Because the surrounding type is `LogDeliveryConfiguration`, the wire field is `config_id`, and the doc says "The unique UUID of log delivery configuration", the truncation is acceptable in context — but on its own, `configId` is generic. A consumer pattern-matching on `configId` across multiple Databricks SDK packages cannot tell which "config" is meant. The wire path `/log-delivery/${req.configId}` in `client.ts:126,218` makes the same identifier look domain-detached. - **Suggested name:** Either: @@ -78,25 +75,32 @@ method. 2. Rename to `id` and let `LogDeliveryConfiguration.id` carry meaning by type context — matches `databricks-sdk-go` resource-id idiom. - **Rationale:** Pattern (2) is what Stripe / GitHub / Google APIs do (`Customer.id`, `Repository.id`). Pattern (1) is what the Databricks Go SDK does. Pick one and apply globally. As written, `configId` is the worst of both — a half-abbreviation that's neither a generic `id` nor a fully qualified `logDeliveryConfigurationId`. -### H6. `GetLogDeliveryConfiguration` and `UpdateLogDeliveryConfiguration` repeat path/body fields with redundant naming — `model.ts:124-129,230-237` -- **File:** `model.ts:124-129` (`GetLogDeliveryConfiguration`), `model.ts:230-237` (`UpdateLogDeliveryConfiguration`). +### H5. `GetLogDeliveryConfigurationRequest` and `UpdateLogDeliveryConfigurationRequest` repeat path/body fields with redundant naming — `model.ts:124-129,230-237` +- **File:** `model.ts:124-129` (`GetLogDeliveryConfigurationRequest`), `model.ts:230-237` (`UpdateLogDeliveryConfigurationRequest`). - **Category:** 7 (overly verbose), 5 (cryptic — `configId` again), 6 (misleading — both fields are required path params but typed optional). -- **Why weird:** `GetLogDeliveryConfiguration` has exactly two fields, both optional: `configId` and `accountId`. The doc says "The log delivery configuration id of customer" — "of customer" reads like a Hindi/Indian-English idiom and is meaningless in this context (a config has no "of customer" — it belongs to an account). Both fields are part of the URL path (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — see `client.ts:126,218`); marking them `?: undefined` then falling back to `??' '` in the URL template produces silent bad requests (the client will hit `/api/2.0/accounts//log-delivery/` if `accountId` is absent). +- **Why weird:** `GetLogDeliveryConfigurationRequest` has exactly two fields, both optional: `configId` and `accountId`. The doc says "The log delivery configuration id of customer" — "of customer" reads like a Hindi/Indian-English idiom and is meaningless in this context (a config has no "of customer" — it belongs to an account). Both fields are part of the URL path (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — see `client.ts:126,218`); marking them `?: undefined` then falling back to `??' '` in the URL template produces silent bad requests (the client will hit `/api/2.0/accounts//log-delivery/` if `accountId` is absent). - **Suggested name:** Rename "of customer" away (`The unique UUID of the log delivery configuration to fetch`). Drop `| undefined` on `configId` — it is required. `accountId` is fine as optional only if the client falls back to `ClientOptions.accountId` (which it does at `client.ts:126`); document that explicitly. - **Rationale:** The current design type-checks fine but blows up at runtime with an unintuitive URL. Required path params should be required types. The "of customer" prose is generator-emitted boilerplate worth removing. +### H6. `*Request_Response` types — proto-architectural-leak `Request_` infix on response DTOs — `model.ts:115,132,158,240` +- **File:** `model.ts:115` (`CreateLogDeliveryConfigurationRequest_Response`), `model.ts:132` (`GetLogDeliveryConfigurationRequest_Response`), `model.ts:158` (`ListLogDeliveryConfigurationRequest_Response`), `model.ts:240` (`UpdateLogDeliveryConfigurationRequest_Response`). Also at `index.ts:15,17,19,23`, and on every marshal/unmarshal schema at `model.ts:243,255,267,332`. +- **Category:** Proto-architectural-leak (mid-position `Request_` infix; underscore from proto-nested-message names). +- **Why weird:** The `Request_` mid-token is a verbatim leak from the proto/gRPC source where the response type is generated as a nested message inside the Request message (`CreateLogDeliveryConfigurationRequest.Response` in proto becomes `CreateLogDeliveryConfigurationRequest_Response` after underscore-flattening). In a TypeScript public API, the *response* type carrying `Request` in its name is a category error: the reader sees `Request` and infers "input DTO" but the type actually models the *output*. The eslint-disable lines (`@typescript-eslint/naming-convention -- Proto-style nested message name.`) at lines 114, 131, 157, 239, 242, 254, 266, 331 acknowledge the leak. The underscore is the disqualified pattern; the `Request` infix on a response DTO is the architectural leak. +- **Suggested name:** Drop the `Request_` infix. Use `CreateLogDeliveryConfigurationResponse`, `GetLogDeliveryConfigurationResponse`, `ListLogDeliveryConfigurationsResponse`, `UpdateLogDeliveryConfigurationResponse`. This removes both the underscore (proto-nested-message smell) and the misleading `Request` infix on response types. +- **Rationale:** The TS public surface should not advertise its proto ancestry. Sibling SDKs (Stripe, GitHub Octokit, AWS SDK v3) emit `Foo` request / `FooResponse` response without nesting. The underscore identifier additionally trips every linter rule for naming-conventions (hence the per-occurrence eslint-disable). Generator-level fix: emit `XxxResponse` instead of `XxxRequest_Response`. + --- ## Medium severity -### M7. `Client` class is unprefixed — `client.ts:46` +### M6. `Client` class is unprefixed — `client.ts:46` - **File:** `client.ts:46`, exported at `index.ts:3`. - **Category:** 1 (vague), 12 (duplicate concept across packages — every Databricks SDK package exports its own `Client`). -- **Why weird:** A user importing this package writes `import {Client} from '@databricks/sdk-logdeliveryconfigurations/v1'` and immediately must alias (`import {Client as LogDeliveryClient}`) to compose multiple Databricks clients. Consistent across the SDK but worth flagging. -- **Suggested name:** `LogDeliveryClient` or `LogDeliveryConfigurationsClient`. Or expose only a namespace (`import * as logDelivery from '@databricks/sdk-logdeliveryconfigurations/v1'` then `logDelivery.Client`). +- **Why weird:** A user importing this package writes `import {Client} from '@databricks/sdk-logdelivery/v1'` and immediately must alias (`import {Client as LogDeliveryClient}`) to compose multiple Databricks clients. Consistent across the SDK but worth flagging. +- **Suggested name:** `LogDeliveryClient` or `LogDeliveryConfigurationsClient`. Or expose only a namespace (`import * as logDelivery from '@databricks/sdk-logdelivery/v1'` then `logDelivery.Client`). - **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. Same finding as `billableusagedownload` audit #8. -### M8. Client method names embed the noun three times — `client.ts:90,122,150,214` +### M7. Client method names embed the noun three times — `client.ts:90,122,150,214` - **File:** `client.ts:90,122,150,192,214`. - **Category:** 7 (overly verbose), 17 (inconsistent action verbs vs sibling packages). - **Why weird:** `client.createLogDeliveryConfiguration(...)` is 27 characters. With the package prefix and the request type, a single call line reads: @@ -105,31 +109,31 @@ method. ``` That is "logDeliveryConfiguration" repeated three times in one expression. The Go SDK uses short method names (`Create`, `Get`, `List`, `PatchStatus`) because the noun comes from the receiver type. The TS port replicates the full noun. Sibling packages like `billableusagedownload.Client.download()` and `accountsettings.Client.disableLegacyFeatures()` use shorter names. - **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.listIter()`, `client.updateStatus()`. The receiver type (`LogDeliveryClient`) already provides the noun. -- **Rationale:** TS method names should not repeat the type they live on. Once `Client` is renamed `LogDeliveryClient` (M7), the shorter forms are unambiguous. Note that the Go SDK uses `PatchStatus` (the actual HTTP verb is `PATCH`) — the TS `updateLogDeliveryConfiguration` is already a paraphrase, so consistency with Go is partly already lost. +- **Rationale:** TS method names should not repeat the type they live on. Once `Client` is renamed `LogDeliveryClient` (M6), the shorter forms are unambiguous. Note that the Go SDK uses `PatchStatus` (the actual HTTP verb is `PATCH`) — the TS `updateLogDeliveryConfiguration` is already a paraphrase, so consistency with Go is partly already lost. -### M9. `updateLogDeliveryConfiguration` does not actually "update" — it only patches status — `client.ts:209-243` -- **File:** `client.ts:209-243`, `UpdateLogDeliveryConfiguration` at `model.ts:230`. +### M8. `updateLogDeliveryConfiguration` does not actually "update" — it only patches status — `client.ts:209-243` +- **File:** `client.ts:209-243`, `UpdateLogDeliveryConfigurationRequest` at `model.ts:230`. - **Category:** 6 (misleading), 17 (inconsistent verb — Go uses `PatchStatus`, TS uses `update`). -- **Why weird:** The method name `updateLogDeliveryConfiguration` suggests "update arbitrary fields of the config". In reality the request body only contains `configId`, `accountId`, and `status` (see `UpdateLogDeliveryConfiguration` interface at `model.ts:230-237`) — you can only flip ENABLED <-> DISABLED. The JSDoc on the method (`client.ts:209-212`) calls it out: "Enables or disables a log delivery configuration." The Go SDK method is named `PatchStatus`, which is honest. +- **Why weird:** The method name `updateLogDeliveryConfiguration` suggests "update arbitrary fields of the config". In reality the request body only contains `configId`, `accountId`, and `status` (see `UpdateLogDeliveryConfigurationRequest` interface at `model.ts:230-237`) — you can only flip ENABLED <-> DISABLED. The JSDoc on the method (`client.ts:209-212`) calls it out: "Enables or disables a log delivery configuration." The Go SDK method is named `PatchStatus`, which is honest. - **Suggested name:** `patchStatus`, or `setStatus`, or `updateStatus`. The current name oversells the surface. - **Rationale:** "Update" implies multi-field mutation. If a caller writes `client.updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new-prefix'})` they will be silently surprised — the `deliveryPathPrefix` is not part of the request DTO so it will not type-check (in TS strict mode), but they would have to read the type to learn that. The verb is a footgun. -### M10. `listLogDeliveryConfiguration` — singular noun on a method returning multiple — `client.ts:150,192` +### M9. `listLogDeliveryConfiguration` — singular noun on a method returning multiple — `client.ts:150,192` - **File:** `client.ts:150,192`. - **Category:** 9 (singular/plural mismatch). - **Why weird:** `listLogDeliveryConfiguration` is singular ("Configuration") but the method yields multiple configurations (the response body field is `logDeliveryConfigurations` — plural — at `model.ts:160`). Sibling packages use plural — e.g., `listBudgetConfigurations` in `budgets/src/v1/client.ts`. The singular method name fights the plural data shape. - **Suggested name:** `listLogDeliveryConfigurations` (plural noun). - **Rationale:** Adjacent package `budgets` uses `listBudgetConfigurations` (plural). Within this package, the response body field is plural while the method name is singular — pluralisation should match the collection it returns. -### M11. `ListLogDeliveryConfiguration` (request type) is singular — `model.ts:141` +### M10. `ListLogDeliveryConfigurationRequest` (request type) is singular — `model.ts:141` - **File:** `model.ts:141-155`. - **Category:** 9 (singular/plural mismatch). -- **Why weird:** Same issue as M10 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. -- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (plural + `Request` suffix for clarity). +- **Why weird:** Same issue as M9 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. +- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (plural noun preserving the `Request` suffix). - **Rationale:** Naming should match data shape. Pluralisation is the standard signal that a method returns a collection. Cross-package inconsistency. -### M12. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:117,205,217` -- **File:** `model.ts:117,205` (field `logDeliveryStatus: LogDeliveryStatus`), `model.ts:208` (interface `LogDeliveryStatus`), `model.ts:217` (`status?: LogDeliveryStatusEnum`). +### M11. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:103,205,217` +- **File:** `model.ts:103,205` (field `logDeliveryStatus: LogDeliveryStatus`), `model.ts:208` (interface `LogDeliveryStatus`), `model.ts:217` (`status?: LogDeliveryStatusEnum`). - **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). - **Why weird:** A reader looking at `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types: - `LogDeliveryConfiguration` (the resource). @@ -139,109 +143,123 @@ method. - **Suggested name:** Field: `lastAttempt: LogDeliveryAttempt`. Wrapper type: `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message` — drop `last` prefix once nested). Enum: `LogDeliveryAttemptStatus`. Result reads as `config.lastAttempt.status === 'SUCCEEDED'`. - **Rationale:** "Status" is too generic to triple-stack. Renaming the wrapper to "Attempt" (its actual semantics) breaks the conflation cleanly. -### M13. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:113-115,201-203` -- **File:** `model.ts:113-115,201-203`. +### M12. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:99-101,201-203` +- **File:** `model.ts:99-101,201-203`. - **Category:** 13 (verb-tense inconsistency — `creation` is a noun, `update` is a verb), 6 (misleading — `number` type with JSDoc "epoch milliseconds"). - **Why weird:** `creationTime: number` and `updateTime: number`. The first is noun-form ("creation"), the second is verb-form ("update"). Pair-wise they should match: `createdTime`/`updatedTime` (past participle) or `creationTime`/`updateTime` (noun). Also, both are `number` (epoch ms) but neither type signals "this is a unix timestamp in milliseconds"; the JSDoc carries that information. Across the SDK, audited packages have flagged similar issues. - **Suggested name:** `createdAt: number` / `updatedAt: number` (canonical SaaS convention — Stripe/GitHub/Salesforce/Atlassian all use *At). Brand the type as `EpochMillis` for compile-time safety. - **Rationale:** "*At" is the industry standard for timestamps. Same finding in many other audited packages (`budgets`, `apps`, etc.) — fix at generator level. -### M14. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:109,197` -- **File:** `model.ts:108-109,196-197`. +### M13. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:95,197` +- **File:** `model.ts:94-95,196-197`. - **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" sounds like a timestamp). - **Why weird:** The field is `string`, but the JSDoc says "specified in YYYY-MM format". That is a year-month string, not a time. Compare with `creationTime: number` (which is an epoch-ms timestamp). The same word "Time" is used for two different formats. A `string` for "YYYY-MM" should be branded or use a `Temporal.YearMonth` from `@js-temporal/polyfill` (already a dependency at `package.json:23`). - **Suggested name:** `deliveryStartMonth` (clarifies granularity), typed `Temporal.PlainYearMonth | string`. - **Rationale:** "Time" implies high-resolution. The domain is monthly billing buckets, so "Month" is the right granularity. Same convention as `Stripe.Invoice.period_start` (epoch) vs `Stripe.UsageRecord.period.start` (date-only). -### M15. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:105,193` -- **File:** `model.ts:104-105,192-193`. +### M14. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:91,193` +- **File:** `model.ts:90-91,192-193`. - **Category:** 7 (overly verbose), 9 (singular/plural mix), 15 (generic suffix). -- **Why weird:** The field is `workspaceIdsFilter: number[]`. The plural `Ids` says "this is a list of IDs". The `Filter` suffix says "this is a filter". A `number[]` already conveys "list of ints". Calling it `workspaceIdsFilter` adds redundant `Filter` noise; calling it just `workspaceIds` (the actual content) would be clearer. Compare with `ListLogDeliveryConfiguration.credentialsId: string` (singular, no `Filter` suffix at `model.ts:145`) which serves the same conceptual role. +- **Why weird:** The field is `workspaceIdsFilter: number[]`. The plural `Ids` says "this is a list of IDs". The `Filter` suffix says "this is a filter". A `number[]` already conveys "list of ints". Calling it `workspaceIdsFilter` adds redundant `Filter` noise; calling it just `workspaceIds` (the actual content) would be clearer. Compare with `ListLogDeliveryConfigurationRequest.credentialsId: string` (singular, no `Filter` suffix at `model.ts:145`) which serves the same conceptual role. - **Suggested name:** `workspaceIds: number[]` (drop `Filter`). Or `filterByWorkspaceIds` if intent must be made explicit. - **Rationale:** Type-driven inference: a `number[]` named after the entity is unambiguous. `Filter` is generic ceremony. -### M16. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:105,193` -- **File:** `model.ts:104-105,192-193`. +### M15. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:91,193` +- **File:** `model.ts:90-91,192-193`. - **Category:** 6 (misleading), 19 (underspecified ID). - **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double precision float — only safe up to 2^53 - 1. Databricks workspace IDs are int64 server-side; sending an ID greater than 2^53 will silently lose precision in the JSON wire. The TS type should be `bigint[]` or `(number | bigint)[]` or branded. - **Suggested name:** `workspaceIds: bigint[]` (matches the int64 wire). Or `workspaceIds: WorkspaceId[]` with a branded `type WorkspaceId = number & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package issue. Same finding will recur on every `*Id: number` field that maps to an int64 wire. Fix at generator level: emit `bigint` for `int64`. -### M17. `host` field on `Client` lacks domain context — `client.ts:47` +### M16. `host` field on `Client` lacks domain context — `client.ts:47` - **File:** `client.ts:47,62`. - **Category:** 1 (vague), 15 (generic field name). - **Why weird:** `private readonly host: string` — without context, `host` could be any URL or hostname. The setter at line 62 trims trailing slash. The semantically correct name is `databricksHost` or `workspaceUrl` or `baseUrl` (the actual content is `https://.../`, not just a hostname like `example.com`). - **Suggested name:** `baseUrl` (matches the actual content — a URL including scheme). - **Rationale:** Same pattern across every package's `Client`. Fix at generator. Same finding as `billableusagedownload` audit #?. +### M17. `marshalRequest` / `parseResponse` and `marshal*Schema` / `unmarshal*Schema` — proto/gRPC verb leak — `utils.ts:113,119`, `model.ts:243,255,267,280,317,332,335,369,379,393` +- **File:** `utils.ts:113` (`parseResponse`), `utils.ts:119` (`marshalRequest`), `model.ts:243,255,267,332` (`unmarshal*Request_ResponseSchema`), `model.ts:280,317` (`unmarshal*Schema`), `model.ts:335,369,379,393` (`marshal*Schema`). +- **Category:** Proto-architectural-leak (mid-position `marshal`/`unmarshal` verbs, gRPC/proto serialization terminology). +- **Why weird:** `marshal` and `unmarshal` are protobuf/gRPC (and Go) terms for binary serialization, not idiomatic JavaScript. The TS ecosystem uses `serialize`/`deserialize` or `encode`/`decode` (e.g., `JSON.stringify`/`JSON.parse`, Zod's `parse`/`safeParse`). Every export-level identifier in `model.ts` is prefixed `marshal*Schema` or `unmarshal*Schema`, advertising the proto backend to consumers. The asymmetry is also odd: input wrapper is `marshalRequest` (verb-noun) but output wrapper is `parseResponse` (different verb entirely — Zod-flavoured "parse" on the unmarshal side and proto-flavoured "marshal" on the marshal side). +- **Suggested name:** Rename `marshalRequest` → `encodeRequest` (or `serializeRequest`); `parseResponse` already uses `parse`, so rename schema vars to match: `*RequestSchema` / `*ResponseSchema` (drop `marshal`/`unmarshal` prefix; the Zod `.parse` and `.transform` direction is encoded in the schema itself, not in its identifier). Or, if direction must be visible, use `encodeXxxSchema` / `decodeXxxSchema`. +- **Rationale:** Cross-package generator concern. `marshal`/`unmarshal` is a proto-ecosystem dialect (Go SDK uses it natively, hence the 1:1 port). TypeScript consumers expect `serialize`/`deserialize` or just schema names. Fix at generator level — none of these symbols are user-facing utility helpers, so renaming has zero blast radius outside the package. + +### M18. `executeHttpCall` parameter struct `HttpCallOptions.request: HttpRequest` reuses `request` for the wire request — `utils.ts:15-19,65` +- **File:** `utils.ts:15-19,65-94`. +- **Category:** 1 (vague mid-position `Call`), proto-architectural-leak (`HttpCall` reads as a gRPC-style "call" abstraction, not an HTTP request). +- **Why weird:** `HttpCallOptions` and `executeHttpCall` use `Call` as a mid-position noun. In gRPC/RPC vocabularies, a "call" is the unit of work (`grpc.Call`, `Twirp.Call`, etc.). In HTTP/REST vocabularies, the unit is a "request". The package already imports `Call` from `@databricks/sdk-core/api` (line 3-4), so the local `HttpCallOptions` doubles up the gRPC terminology. `executeHttpCall` is even more confusing: it doesn't execute a `Call` (the typedef-imported one) — it sends an `HttpRequest` and returns a body. +- **Suggested name:** `HttpRequestOptions` (or drop the type entirely and inline the three fields) and `sendHttpRequest` (or `dispatchHttp`). Reserve `Call` for the retry-wrapped function alias. +- **Rationale:** Within one file, `Call` means two different things: the abstract retry-wrapped function type (imported from `@databricks/sdk-core/api`) and the HTTP request (local `HttpCallOptions`). The overloaded noun is a proto-architectural-leak — HTTP REST clients call them "requests", not "calls". Same finding cross-package. + --- ## Low severity -### L18. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` +### L19. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` - **File:** `model.ts:56-61`. - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered. They should match — either `BILLABLE_USAGE_LOGS` / `AUDIT_LOGS` (both plural) or `BILLABLE_USAGE` / `AUDIT` (both singular). - **Suggested name:** `BILLABLE_USAGE` / `AUDIT` (drop the `_LOGS` — the enum is `LogDeliveryType` so "logs" is implied). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the type name) is cleaner. -### L19. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` +### L20. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` - **File:** `model.ts:23-28`. - **Category:** 3 (acronym casing — fine here since it matches the wire), Observation. -- **Why weird:** Two-value enum where `log_type === 'BILLABLE_USAGE'` forces `output_format === 'CSV'` and `log_type === 'AUDIT_LOGS'` forces `'JSON'` (see JSDoc on `outputFormat` at `model.ts:93-96`). The field is therefore *always* derivable from `logType` — making it a redundant field, not a redundant enum, but worth flagging. +- **Why weird:** Two-value enum where `log_type === 'BILLABLE_USAGE'` forces `output_format === 'CSV'` and `log_type === 'AUDIT_LOGS'` forces `'JSON'` (see JSDoc on `outputFormat` at `model.ts:79-83`). The field is therefore *always* derivable from `logType` — making it a redundant field, not a redundant enum, but worth flagging. - **Suggested name:** Drop `outputFormat` from the request DTO (it can be derived server-side). Keep on the response DTO for clarity. - **Rationale:** Not strictly a naming issue, but reduces API surface area. -### L20. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` +### L21. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` - **File:** `model.ts:13-16`. - **Category:** 1 (vague). - **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the doc says exactly what the name says. JSDoc should add information, not echo identifiers. - **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured S3 bucket." - **Rationale:** Cross-cutting generator concern. -### L21. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` +### L22. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` - **File:** `model.ts:48-49`. - **Category:** 6 (misleading). - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc says it actually means "configuration has been disabled since the release of this feature or there are no workspaces in the account". That's not "not found"; it's "no logs to deliver because account state". - **Suggested name:** `NO_DATA` or `NOT_APPLICABLE` or `DISABLED_AT_RELEASE` — anything that doesn't sound like a 404. - **Rationale:** API value names should not collide with HTTP semantics that mean something different. A monitoring dashboard surfacing `status === 'NOT_FOUND'` will mislead an operator into thinking the config was deleted. -### L22. `PACKAGE_SEGMENT` constant — `client.ts:41` +### L23. `PACKAGE_SEGMENT` constant — `client.ts:41` - **File:** `client.ts:41-44`. - **Category:** 1 (vague), 15 (generic). - **Why weird:** `Segment` is a generic CS term. The comment "Package identity segment for this client to be used in the User-Agent header" (`client.ts:40`) is the disambiguator; without it the constant name does not communicate what it is. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency — same finding in every audited package. Worth normalising at generator level. Same as `billableusagedownload` audit #10. -### L23. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` +### L24. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` - **File:** `client.ts:51,72`. - **Category:** 20 (type-suffix tautology). - **Why weird:** Field name and type both end in `Client`. Convention is widespread but flagged per rule 20. - **Suggested name:** `transport: HttpClient` (matches the imported package `@databricks/sdk-databricks/transport`). - **Rationale:** `transport` is what HTTP layers are usually named in language-agnostic SDK terminology (gRPC, GraphQL clients, etc.). It avoids the `Client/Client` echo. Tolerable as-is. -### L24. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` +### L25. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` - **File:** `client.ts:91,99,103,...` (every method). - **Category:** 5 (cryptic abbreviation). - **Why weird:** Three-letter abbreviations for parameter and local names. The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling out costs nothing and improves readability. Same finding across every audit. -### L25. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` +### L26. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` - **File:** `client.ts:196`. - **Category:** 5 (cryptic), 1 (vague — `pageReq` is shorthand for "request for next page"). - **Why weird:** Variable holds the *modified* request for each page (with `pageToken` updated). `pageReq` reads as "page request" — a noun describing the page itself. - **Suggested name:** `currentRequest` or `paginatedRequest`. Or unify with `request` if you adopt option-bag style. - **Rationale:** Low; loop-local variable. -### L26. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` +### L27. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` - **File:** `utils.ts:26-38,65-94`. - **Category:** 1 (vague), 17 (inconsistent layer naming). -- **Why weird:** Two functions named almost identically doing very different things. `executeCall` wraps the call in retry/rate-limit; `executeHttpCall` does the raw HTTP send + decode + APIError. Within the same file the naming distinction is too subtle. +- **Why weird:** Two functions named almost identically doing very different things. `executeCall` wraps the call in retry/rate-limit; `executeHttpCall` does the raw HTTP send + decode + ApiError. Within the same file the naming distinction is too subtle. - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `dispatchHttp`). Or just `wrapRetry` / `sendHttp`. - **Rationale:** Same finding as `billableusagedownload` audit #13. Cross-package generator concern. -### L27. `HttpCallOptions` — `utils.ts:15` +### L28. `HttpCallOptions` — `utils.ts:15` - **File:** `utils.ts:15-19`. - **Category:** 1 (vague suffix `Options`), 12 (duplicate `Options` naming). - **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` from `@databricks/sdk-core/api` imported at line 3). The local interface shadows the imported one cognitively. The field is not user-facing — it is an internal bag. @@ -252,39 +270,39 @@ method. ## Observations -### O28. `flattenQueryParams` is exported but unused — `utils.ts:123` +### O29. `flattenQueryParams` is exported but unused — `utils.ts:123` `client.ts` does its own query-param construction inline (lines 155-167) using `new URLSearchParams()` and four `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called by this package. This is a generator artefact — every generated package ships this helper. -### O29. `parseResponse` is unused — `utils.ts:113` +### O30. `parseResponse` is unused — `utils.ts:113` Actually, `parseResponse` *is* used (4 call sites in `client.ts:109,137,180,233`). Not dead. Correction to prior packages' findings: in `logdeliveryconfigurations`, parseResponse is actively in use. -### O30. `marshalRequest` is used twice — `client.ts:95,219` +### O31. `marshalRequest` is used twice — `client.ts:95,219` Used for `createLogDeliveryConfiguration` and `updateLogDeliveryConfiguration`. Not dead. -### O31. `accountId` URL fallback — `client.ts:94,126,154,218` +### O32. `accountId` URL fallback — `client.ts:94,126,154,218` `createLogDeliveryConfiguration` (line 94) reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client fallback!), while the other three methods do `req.accountId ?? this.accountId ?? ''`. The create path silently differs — if `ClientOptions.accountId` is set but the caller forgets to put it inside `logDeliveryConfiguration`, the URL becomes `/api/2.0/accounts//log-delivery`. This is a correctness bug surfaced by a naming/structure inconsistency: the request DTO nests the account ID one level deeper than the others. - **Category:** 6 (misleading), 16 (field placement contradicts wire-level convention). - **Suggested fix:** Make `req.accountId ?? this.accountId ?? ''` consistent across all four methods (the create path should reach the top-level `accountId` and the client-options fallback, not just the nested wrapper field). -### O32. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,32,53,64,77,120,137,165,225` +### O33. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,31,53,64,107,121,138,166,227` Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the first line (e.g., line 6: ``` * * * Log Delivery Status ``` -). Looks like the generator emits an empty paragraph break that renders as `*`. Also, `` appears in raw form throughout (e.g., `model.ts:98,127,142,186`); it should be a literal "Databricks" or substituted at generation time. Neither is a name issue per se but both pollute the docs. +). Looks like the generator emits an empty paragraph break that renders as `*`. Also, `` appears in raw form throughout (e.g., `model.ts:84,127,142,186`); it should be a literal "Databricks" or substituted at generation time. Neither is a name issue per se but both pollute the docs. -### O33. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` -The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O31). The naming of `accountId` as "optional" in the type lies about the runtime requirement. +### O34. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` +The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O30). The naming of `accountId` as "optional" in the type lies about the runtime requirement. --- ## Domain glossary - **`account`** — Databricks account; the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) in every interface and as `ClientOptions.accountId` (`client.ts:50,63`). -- **`workspace`** — A Databricks workspace under an account; `int64` ID on the wire (lossy as `number` in TS — see M17). -- **`credentials`** — Refers to `Credentials.Create` (cross-package) — a stored AWS IAM role with policy/trust relationship. The `credentialsId` field (`model.ts:101,189`) links a log delivery config to a previously-created credentials resource. -- **`storage configuration`** — Refers to `Storage.Create` (cross-package) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:103,191`) links a log delivery config to a bucket. +- **`workspace`** — A Databricks workspace under an account; `int64` ID on the wire (lossy as `number` in TS — see M15). +- **`credentials`** — Refers to `Credentials.Create` (cross-package) — a stored AWS IAM role with policy/trust relationship. The `credentialsId` field (`model.ts:87,189`) links a log delivery config to a previously-created credentials resource. +- **`storage configuration`** — Refers to `Storage.Create` (cross-package) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:89,191`) links a log delivery config to a bucket. - **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` that tells Databricks to write certain logs to a bucket. - **`log type`** — One of `BILLABLE_USAGE` / `AUDIT_LOGS` — what kind of logs to deliver. - **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always derivable from `log type`. @@ -292,9 +310,9 @@ The constructor throws if `options.host` is undefined (`client.ts:59-61`) but ha - **`delivery start time`** — `YYYY-MM` string; only applies to billable usage; lower bound is `2019-03`. - **`config status`** — `ENABLED` / `DISABLED`. The config is never deleted — only disabled (see `client.ts:88,211`). - **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND`. Reflects the state of the most recent delivery attempt; surfaced as `LogDeliveryStatus.status` (i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`). -- **`E2`** — Databricks deployment architecture (newer multi-region account model). Mentioned in `UpdateLogDeliveryConfiguration.accountId` JSDoc (`model.ts:233`). -- **`int64`** — Wire-level 64-bit signed integer; appears in `workspaceIdsFilter` JSDoc but typed `number` in TS (M17). -- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`); the Go SDK calls this method `PatchStatus`, the TS port renames it `updateLogDeliveryConfiguration` (M10). +- **`E2`** — Databricks deployment architecture (newer multi-region account model). Mentioned in `UpdateLogDeliveryConfigurationRequest.accountId` JSDoc (`model.ts:233`). +- **`int64`** — Wire-level 64-bit signed integer; appears in `workspaceIdsFilter` JSDoc but typed `number` in TS (M15). +- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`); the Go SDK calls this method `PatchStatus`, the TS port renames it `updateLogDeliveryConfiguration` (M9). --- @@ -304,3 +322,13 @@ The constructor throws if `options.host` is undefined (`client.ts:59-61`) but ha - `src/v1/client.ts` (245 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (25 lines): read fully. + +--- + +## Fixed + +- #H1 `logdeliveryconfigurations` package name (originally cited at package directory): Fixed in regeneration on 2026-05-20 — package renamed to `logdelivery` (singular), matching the suggested name and the URL path segment `/log-delivery`. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index b39b158d..f998c133 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,85 +3,25 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 47 +**Total weird names flagged:** 52 ## Summary | Severity | Count | | --- | --- | -| High | 14 | -| Medium | 29 | +| High | 12 | +| Medium | 27 | | Low | 8 | -| Observation | 6 | +| Observation | 5 | -The marketplaces package is one of the more naming-distressed surfaces in the SDK. The dominant problem is the **inconsistent request-type convention** within a single file: some request types follow the verb-shaped Go style (`CreateFile`, `DeleteFile`, `GetListing`, `GetListings`, `UpdateListing`, `ListFiles`, `CreateProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders`, `CreateProviderAnalyticsDashboard`, `UpdateProviderAnalyticsDashboard`, `GetLatestVersionProviderAnalyticsDashboard`, `ListProviderAnalyticsDashboard`, `GetPersonalizationRequestsForProvider`, `UpdatePersonalizationRequestStatus`) while others follow the more idiomatic `*Request`/`*Response` suffix (`CreateExchangeRequest`, `DeleteExchangeRequest`, `GetExchangeRequest`, `UpdateExchangeRequest`, `ListExchangesRequest`, `CreateExchangeFilterRequest`, `DeleteExchangeFilterRequest`, `UpdateExchangeFilterRequest`, `ListExchangeFiltersRequest`, `AddExchangeForListingRequest`, `RemoveExchangeForListingRequest`, `ListExchangesForListingRequest`, `ListListingsForExchangeRequest`) — split almost perfectly down the provider/exchange axis but not advertised that way. Other notable issues are the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListings` request and `GetListings_Response` payload field both use `listings`, while `CreateListing` and `DeleteListing` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service", `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` exposing an internal commit-drawdown workflow with a 33-character enum value, and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). +The marketplaces package remains one of the more naming-distressed surfaces in the SDK, though the dominant pre-existing problem — **inconsistent request-type naming** across the package — has been resolved by uniformly applying the `*Request`/`*Response` suffix to every operation type. Notable issues remaining include the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListingsRequest` and its proto-nested `_Response` payload field both use `listings`, while `CreateListingRequest` and `DeleteListingRequest` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service" and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). --- ## High severity -### 1. Verb-shaped request types — 14 occurrences +### 1. `Listing` — ambiguous central type -**Location:** `src/v1/model.ts:174, 188, 197, 207, 233, 240, 247, 317, 331, 339, 348, 359, 370, 411, 434, 445, 627, 637, 650, 660` - -```ts -export interface CreateFile { ... } -export interface CreateListing { ... } -export interface CreateProvider { ... } -export interface CreateProviderAnalyticsDashboard {} -export interface DeleteFile { ... } -export interface DeleteListing { ... } -export interface DeleteProvider { ... } -export interface GetFile { ... } -export interface GetLatestVersionProviderAnalyticsDashboard {} -export interface GetListing { ... } -export interface GetListings { ... } -export interface GetPersonalizationRequestsForProvider { ... } -export interface GetProvider { ... } -export interface ListFiles { ... } -export interface ListProviderAnalyticsDashboard {} -export interface ListProviders { ... } -export interface UpdateListing { ... } -export interface UpdatePersonalizationRequestStatus { ... } -export interface UpdateProvider { ... } -export interface UpdateProviderAnalyticsDashboard { ... } -``` - -Top-level request types named with imperative verbs (`Create*`, `Delete*`, `Get*`, `List*`, `Update*`). TS types should be nouns; verbs are reserved for methods. The `Client` exposes the same identifier as both a method and a type: `client.createListing(req: CreateListing)`, `client.getListing(req: GetListing)`, `client.listProviders(req: ListProviders)` — verb-noun-verb-noun every time. Readers cannot tell from the type whether the symbol names a request shape or an operation. -- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs within file — see #2). -- **Suggested name:** `CreateFileRequest`, `CreateListingRequest`, `GetListingRequest`, `ListProvidersRequest`, etc. -- **Rationale:** See #2. - -### 2. Two competing request-type naming conventions in one file - -**Location:** Both patterns coexist throughout `src/v1/model.ts`. - -``` -Verb-shaped (Go style): *Request-suffixed (idiomatic TS): -CreateFile CreateExchangeRequest -CreateListing CreateExchangeFilterRequest -CreateProvider CreateExchangeResponse -DeleteFile DeleteExchangeRequest -DeleteListing DeleteExchangeFilterRequest -DeleteProvider GetExchangeRequest -GetFile UpdateExchangeRequest -GetListing UpdateExchangeFilterRequest -GetListings ListExchangesRequest -GetProvider ListExchangeFiltersRequest -ListFiles ListExchangesForListingRequest -ListProviders ListListingsForExchangeRequest -UpdateListing AddExchangeForListingRequest -UpdateProvider RemoveExchangeForListingRequest -... ... -``` - -Verb-shaped types are used for **provider-side** operations (listings, files, providers, personalization, analytics dashboard); `*Request`-suffixed types are used for **exchange-side** operations (exchanges, exchange filters, exchange-listing joins). The split likely reflects two different proto packages on the server but in TS it reads as arbitrary inconsistency. A single user calling both `client.createListing` and `client.createExchange` will import two completely differently-named request types: `CreateListing` and `CreateExchangeRequest`. There is no documentation or hint that this split is intentional. -- **Category:** 17 (inconsistent action verbs / naming patterns), 12 (duplicate convention — two patterns for the same concept). -- **Suggested name:** Pick one — and `*Request` is the rest-of-SDK norm. Cascade with #1. -- **Rationale:** A single ergonomic package should not require users to memorize which sub-domain uses which type-naming scheme. - -### 3. `Listing` — ambiguous central type - -**Location:** `src/v1/model.ts:456` +**Location:** `src/v1/model.ts:652` ```ts export interface Listing { @@ -92,18 +32,18 @@ export interface Listing { ``` `Listing` is the central noun of the package, but the name has two unrelated English meanings: a *marketplace listing* (a storefront entry) and a *list operation* (the verb "to list", noun "a listing of items"). The package frequently uses both meanings within a single line: -- `getListings(req: GetListings)` — method name uses the verb sense ("get the listings"), the type name uses the noun sense (a "GetListings" request that returns marketplace listings). +- `getListings(req: GetListingsRequest)` — method name uses the verb sense ("get the listings"), the type name uses the noun sense (a "GetListings" request that returns marketplace listings). - `ListListingsForExchangeRequest` reads as "list the listings for exchange" — the first `List` is the verb, the second `Listings` is the noun. -- `ExchangeListing` (line 278) is a join-row type — neither a storefront listing nor a list-operation but a third concept ("a listing in an exchange"). +- `ExchangeListing` (line 320) is a join-row type — neither a storefront listing nor a list-operation but a third concept ("a listing in an exchange"). The triple overload is unavoidable given the domain word but the SDK does not disambiguate (e.g. by renaming join rows to `ExchangeListingLink` or `ExchangeMembership`). - **Category:** 1 (vague), 12 (duplicate concepts), 15 (overloaded vocabulary). -- **Suggested name:** Keep `Listing` for the noun; rename `ExchangeListing` → `ExchangeListingLink` / `ListingExchangeMembership`; rename `GetListings` → `ListListingsRequest` (cascade with #1 and #2 — but note that gives `ListListingsRequest`, which is itself a stutter; the right fix may be `ListMarketplaceListingsRequest` or simpler `ListListings`). +- **Suggested name:** Keep `Listing` for the noun; rename `ExchangeListing` → `ExchangeListingLink` / `ListingExchangeMembership`. - **Rationale:** "Listing" has multiple senses; the SDK uses all three; the API can mitigate this by giving the *join row* a less ambiguous name. -### 4. `ExchangeListing` — overloaded "listing" inside the type name +### 2. `ExchangeListing` — overloaded "listing" inside the type name -**Location:** `src/v1/model.ts:278` +**Location:** `src/v1/model.ts:320` ```ts export interface ExchangeListing { @@ -117,14 +57,14 @@ export interface ExchangeListing { } ``` -The type is a join row connecting an exchange to a listing (with denormalized names). Named `ExchangeListing` it parses as either "a listing of type Exchange" (no — exchanges and listings are distinct) or "the exchange-side view of a listing" (no — both sides are denormalized into the same row) or "a listing exposed in the exchange" (closer, but the type is really the *link*, not the listing itself). The `Exchange.linkedListings: ExchangeListing[]` field at line 263 makes the relationship visible but does not clarify the name. +The type is a join row connecting an exchange to a listing (with denormalized names). Named `ExchangeListing` it parses as either "a listing of type Exchange" (no — exchanges and listings are distinct) or "the exchange-side view of a listing" (no — both sides are denormalized into the same row) or "a listing exposed in the exchange" (closer, but the type is really the *link*, not the listing itself). The `Exchange.linkedListings: ExchangeListing[]` field at line 305 makes the relationship visible but does not clarify the name. - **Category:** 1 (vague), 6 (misleading: looks like an inheritance from `Listing`), 12 (overloaded with `Listing`). - **Suggested name:** `ExchangeListingLink`, `ExchangeMembership`, `ListingExchangeAssociation`. -- **Rationale:** See #3. +- **Rationale:** See #1. -### 5. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order +### 3. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order -**Location:** `src/v1/model.ts:141, 592` +**Location:** `src/v1/model.ts:142, 796` ```ts export interface AddExchangeForListingRequest { @@ -142,9 +82,9 @@ The operations are symmetric (associate / disassociate an exchange with a listin - **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`); rename response field `exchangeForListing` → `exchangeListing`. - **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. -### 6. `AddExchangeForListingResponse.exchangeForListing` — Greek-letter field name +### 4. `AddExchangeForListingResponse.exchangeForListing` — Greek-letter field name -**Location:** `src/v1/model.ts:146-148` +**Location:** `src/v1/model.ts:147-149` ```ts export interface AddExchangeForListingResponse { @@ -155,36 +95,11 @@ export interface AddExchangeForListingResponse { The field name `exchangeForListing` is a noun phrase that mirrors the request verb ("Add Exchange For Listing"). But the value is an `ExchangeListing` (the join-row type). Just naming the field `exchangeListing` would match the type name and remove the "for" preposition that doesn't add information. - **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name doesn't quite match its type name). - **Suggested name:** `exchangeListing` (matches the underlying type). -- **Rationale:** See #5. - -### 7. `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` — 33-character internal-domain enum value - -**Location:** `src/v1/model.ts:119-126` - -```ts -export enum MarketplaceFileType { - PROVIDER_ICON = 'PROVIDER_ICON', - EMBEDDED_NOTEBOOK = 'EMBEDDED_NOTEBOOK', - APP = 'APP', - EMBEDDED_MARKDOWN = 'EMBEDDED_MARKDOWN', - /** - * Consumer-attached supporting document (e.g., PDF) for a commit drawdown - * request. Stored under `staging/COMMIT_DRAWDOWN_REQUEST_ATTACHMENT/` (the - * entity stays in FILE_STATUS_STAGING permanently — no sanitization) with - * 14-day expiration; not served via the general presigned-GET path. - */ - COMMIT_DRAWDOWN_REQUEST_ATTACHMENT = 'COMMIT_DRAWDOWN_REQUEST_ATTACHMENT', -} -``` - -This enum value exposes a billing/commerce concept ("commit drawdown") that is not documented anywhere else in the marketplaces public surface. There is no `CommitDrawdownRequest` type, no related method, no field referencing "drawdown" elsewhere in the file. The JSDoc says these files have 14-day expiration and special storage paths — implementation details surfacing as the enum's namesake. A consumer scanning `MarketplaceFileType` cannot tell whether this is a value they should ever use. -- **Category:** 18 (long enum values), 1 (vague — "commit drawdown" undefined in the SDK), 11 (effectively-internal value). -- **Suggested name:** Document or hide. If kept, the long name is itself fine — the issue is the value's presence in the public API without context. -- **Rationale:** Public enums should be self-explanatory; internal-workflow values should either be documented inline with the workflow's purpose or kept off the public surface. +- **Rationale:** See #3. -### 8. `PersonalizationRequest.isFromLighthouse` — internal codename leak +### 5. `PersonalizationRequest.isFromLighthouse` — internal codename leak -**Location:** `src/v1/model.ts:563` +**Location:** `src/v1/model.ts:767` ```ts export interface PersonalizationRequest { @@ -199,9 +114,9 @@ export interface PersonalizationRequest { - **Suggested name:** Either document inline (the doc-comment should explain Lighthouse) or rename to a feature-describing name. If Lighthouse is a request-origin tag, `originatingService` (with an enum) would be clearer. - **Rationale:** Public APIs should not leak internal-system codenames. -### 9. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types +### 6. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types -**Location:** `src/v1/model.ts:515, 462` +**Location:** `src/v1/model.ts:719, 658` ```ts export interface Listing { @@ -211,7 +126,7 @@ export interface Listing { } export interface ListingSummary { /* 20 fields */ } -export interface ListingDetail { /* 16 fields */ } +export interface ListingDetail { /* 18 fields */ } ``` The split into `Summary` and `Detail` looks like a "list view vs. detail view" distinction (where `Summary` is what gets returned in list endpoints and `Detail` is the full payload). But both are bundled into a single `Listing` and both come back from `getListing` and `listListings`. The convention is meaningful in REST APIs that ship two read-shapes (e.g. GitHub's `Repository` vs `MinimalRepository`), but here both types are always present on the same `Listing`. The naming implies a contract the API doesn't honor. @@ -219,9 +134,9 @@ The split into `Summary` and `Detail` looks like a "list view vs. detail view" d - **Suggested name:** `ListingMetadata` (for what is currently `ListingSummary`) and `ListingContent` (for `ListingDetail`); or merge into a single `Listing` type. - **Rationale:** The "Summary / Detail" lexicon promises a slim/fat split that the API doesn't actually provide. -### 10. `ListingSummary` — 20-field "summary" +### 7. `ListingSummary` — 20-field "summary" -**Location:** `src/v1/model.ts:515-536` +**Location:** `src/v1/model.ts:719-740` ```ts export interface ListingSummary { @@ -250,11 +165,11 @@ export interface ListingSummary { A 20-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. - **Category:** 6 (misleading). - **Suggested name:** `ListingMetadata` or `ListingHeader`. -- **Rationale:** See #9. +- **Rationale:** See #6. -### 11. `ProviderInfo.termOfServiceLink` — singular "term" +### 8. `ProviderInfo.termOfServiceLink` — singular "term" -**Location:** `src/v1/model.ts:581` +**Location:** `src/v1/model.ts:785` ```ts export interface ProviderInfo { @@ -264,16 +179,16 @@ export interface ProviderInfo { } ``` -The legal document is **Terms of Service** (plural). Field name says `termOfService` (singular). The neighboring `privacyPolicyLink` is correctly singular (a privacy policy is singular), so the field reads as if "term" were intentional — but the linked document is universally plural. The same field appears with the same typo as `term_of_service_link` on the wire (see `marshalProviderInfoSchema:1671`), so this is a server-side typo that the SDK faithfully preserves. +The legal document is **Terms of Service** (plural). Field name says `termOfService` (singular). The neighboring `privacyPolicyLink` is correctly singular (a privacy policy is singular), so the field reads as if "term" were intentional — but the linked document is universally plural. The same field appears with the same typo as `term_of_service_link` on the wire (see `marshalProviderInfoSchema:2331`), so this is a server-side typo that the SDK faithfully preserves. -Note: `ListingDetail.termsOfService` (line 464) correctly uses the plural form — so the package has both `termOfServiceLink` and `termsOfService` for analogous concepts. +Note: `ListingDetail.termsOfService` (line 660) correctly uses the plural form — so the package has both `termOfServiceLink` and `termsOfService` for analogous concepts. - **Category:** 6 (misleading: wrong word form), 17 (inconsistent: same package uses both `termOfService` and `termsOfService`). - **Suggested name:** `termsOfServiceLink`. - **Rationale:** Within-package consistency and English correctness. -### 12. `FileParent` — abstract container with weak typing +### 9. `FileParent` — abstract container with weak typing -**Location:** `src/v1/model.ts:303-307` +**Location:** `src/v1/model.ts:345-349` ```ts export interface FileParent { @@ -288,9 +203,9 @@ The type ships with a `TODO` in the JSDoc — the API contract is incomplete by - **Suggested name:** Either model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`) or rename `parentId` → `providerId | listingId | listingResourceId` per case. - **Rationale:** The `TODO` says the team knows; the type is shipped publicly anyway. -### 13. `FileParent.fileParentType` — type-suffix tautology +### 10. `FileParent.fileParentType` — type-suffix tautology -**Location:** `src/v1/model.ts:306` +**Location:** `src/v1/model.ts:348` ```ts export interface FileParent { @@ -304,9 +219,9 @@ Field name = type name minus the `FileParent` prefix repeated. Inside `FileParen - **Suggested name:** `type` (matching `ShareInfo.type`) or `parentType`. - **Rationale:** Redundant context. -### 14. `FileInfo.marketplaceFileType` — package-name prefix in a field +### 11. `FileInfo.marketplaceFileType` — package-name prefix in a field -**Location:** `src/v1/model.ts:290` +**Location:** `src/v1/model.ts:332` ```ts export interface FileInfo { @@ -316,18 +231,41 @@ export interface FileInfo { } ``` -The field qualifies "fileType" with "marketplace" — but the type is *already* inside the marketplaces package. Every `FileType` here is a marketplace file type. The same prefix appears on `MarketplaceFileType` (the enum itself, line 114). Together they read as `marketplaceFileType: MarketplaceFileType` — package name stuttered twice. +The field qualifies "fileType" with "marketplace" — but the type is *already* inside the marketplaces package. Every `FileType` here is a marketplace file type. The same prefix appears on `MarketplaceFileType` (the enum itself, line 123). Together they read as `marketplaceFileType: MarketplaceFileType` — package name stuttered twice. - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** Rename enum → `FileType`; rename field → `type`. - **Rationale:** Package-name qualifiers are noise on internal fields. +### 12. `*Request_Response` — proto-nested-message pattern leaked into public types + +**Location:** `src/v1/model.ts:203, 214, 243, 252, 280, 287, 294, 386, 410, 444, 454, 474, 484, 602, 622, 635, 926, 939, 954, 968` + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface CreateFileRequest_Response { + fileInfo?: FileInfo | undefined; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteFileRequest_Response {} + +// ...and 18 others with the same shape. +``` + +Twenty response types follow the proto-IDL convention `message Request { message Response { ... } }`, which generates `Request_Response` in flat code-gen. The full list: `CreateFileRequest_Response`, `CreateListingRequest_Response`, `CreateProviderAnalyticsDashboardRequest_Response`, `CreateProviderRequest_Response`, `DeleteFileRequest_Response`, `DeleteListingRequest_Response`, `DeleteProviderRequest_Response`, `GetFileRequest_Response`, `GetLatestVersionProviderAnalyticsDashboardRequest_Response`, `GetListingRequest_Response`, `GetListingsRequest_Response`, `GetPersonalizationRequestsForProviderRequest_Response`, `GetProviderRequest_Response`, `ListFilesRequest_Response`, `ListProviderAnalyticsDashboardRequest_Response`, `ListProvidersRequest_Response`, `UpdateListingRequest_Response`, `UpdatePersonalizationRequestStatusRequest_Response`, `UpdateProviderAnalyticsDashboardRequest_Response`, `UpdateProviderRequest_Response`. + +Every one carries an `eslint-disable @typescript-eslint/naming-convention -- Proto-style nested message name.` comment, which is the codegen explicitly acknowledging that the underscore identifier exists only because of the proto serialization shape. The same package uses the underscore-free `*Response` form (`CreateExchangeResponse`, `GetExchangeResponse`, `UpdateExchangeFilterResponse`, etc.) for operations whose proto definition declares a sibling response message rather than a nested one — so the package ships **both** conventions side-by-side, and the choice between them is dictated by the proto IDL, not by anything visible at the TS surface. +- **Category:** Proto suffix/infix — `Foo_PublicRequest`-style paired-name leak (`Request_Response` underscore identifier). +- **Suggested name:** Drop the underscore: `CreateFileResponse`, `DeleteFileResponse`, `GetListingResponse`, `ListProvidersResponse`, etc.; for empty-body cases (`Delete*Request_Response`, `Update*Request_Response` where the body is `{}`), have the corresponding client method return `void` and drop the type entirely. +- **Rationale:** The underscore in `Request_Response` is the protobuf service convention (`.Request.Response` in proto IDL); nothing in the JS SDK contract demands it. TS callers see two unrelated naming styles for the same concept (the "Response" payload), with the choice driven by an upstream proto definition they cannot see. + --- ## Medium severity -### 15. `Client` — generic top-level class name +### 13. `Client` — generic top-level class name -**Location:** `src/v1/client.ts:152` +**Location:** `src/v1/client.ts:210` ```ts export class Client { ... } @@ -338,9 +276,9 @@ Top-level export named just `Client`. Every generated package exports a `Client` - **Suggested name:** `MarketplacesClient`. - **Rationale:** Service-prefixed client class names are standard across `@aws-sdk/*`, `@google-cloud/*`, `@azure/*`. -### 16. `Exchange.linkedListings` — verb tense and ambiguity +### 14. `Exchange.linkedListings` — verb tense and ambiguity -**Location:** `src/v1/model.ts:263` +**Location:** `src/v1/model.ts:305` ```ts export interface Exchange { @@ -354,9 +292,9 @@ export interface Exchange { - **Suggested name:** `listings`, `memberships`, or `listingLinks`. - **Rationale:** Past-participle field names suggest a log/audit; this is a list of current memberships. -### 17. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix +### 15. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix -**Location:** `src/v1/model.ts:269, 275` +**Location:** `src/v1/model.ts:311, 317` ```ts export interface ExchangeFilter { @@ -374,9 +312,9 @@ Inside an `ExchangeFilter`, what else could `filterValue` be the value of? Or `f - **Suggested name:** `value`, `type`. - **Rationale:** Field names that re-state the parent type are noise (see also `EffectivePrivilege.privilege` from grants audit #15). -### 18. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum +### 16. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum -**Location:** `src/v1/model.ts:69-71` +**Location:** `src/v1/model.ts:68-70` ```ts export enum ExchangeFilterType { @@ -389,28 +327,26 @@ An enum with a single member. Typically a sign that the API anticipates future f - **Suggested name:** Could be a string literal type until a second value lands. - **Rationale:** TS allows narrowing without enums (`type ExchangeFilterType = 'GLOBAL_METASTORE_ID'`). -### 19. `MarketplaceFileType.APP` — three-letter generic value +### 17. `MarketplaceFileType.APP` — three-letter generic value -**Location:** `src/v1/model.ts:117` +**Location:** `src/v1/model.ts:126` ```ts export enum MarketplaceFileType { PROVIDER_ICON = 'PROVIDER_ICON', EMBEDDED_NOTEBOOK = 'EMBEDDED_NOTEBOOK', APP = 'APP', - EMBEDDED_MARKDOWN = 'EMBEDDED_MARKDOWN', - COMMIT_DRAWDOWN_REQUEST_ATTACHMENT = 'COMMIT_DRAWDOWN_REQUEST_ATTACHMENT', } ``` -`APP` is the only member without a qualifier. Compare with `EMBEDDED_NOTEBOOK` and `EMBEDDED_MARKDOWN` — both prefixed with "embedded" to indicate they're attached to a listing. Is `APP` similarly embedded? Is it a Databricks App package file? A general application archive? Without a qualifier or doc-comment the value is ambiguous. +`APP` is the only member without a qualifier. Compare with `EMBEDDED_NOTEBOOK` — prefixed with "embedded" to indicate it's attached to a listing. Is `APP` similarly embedded? Is it a Databricks App package file? A general application archive? Without a qualifier or doc-comment the value is ambiguous. - **Category:** 1 (vague), 17 (inconsistent qualifier convention with peers). - **Suggested name:** `EMBEDDED_APP` or `APP_PACKAGE`. - **Rationale:** Match the qualifier convention of `EMBEDDED_*` peers. -### 20. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment +### 18. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment -**Location:** `src/v1/model.ts:128-134` +**Location:** `src/v1/model.ts:129-135` ```ts export enum PersonalizationRequestStatus { @@ -427,9 +363,9 @@ The JSDoc explicitly says the value is named `REQUEST_PENDING` because `PENDING` - **Suggested name:** `PENDING` (cross-enum collisions don't exist in TS). - **Rationale:** Proto-side collision avoidance has no purpose in the TS surface. -### 21. `Cost` — single-word, ambiguous enum +### 19. `Cost` — single-word, ambiguous enum -**Location:** `src/v1/model.ts:47-50` +**Location:** `src/v1/model.ts:46-49` ```ts export enum Cost { @@ -438,14 +374,14 @@ export enum Cost { } ``` -`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 473) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". +`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 669) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". - **Category:** 1 (vague), 6 (misleading: implies price, means tier). - **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. - **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. -### 22. `DataRefresh` — enum named after the noun, not the property +### 20. `DataRefresh` — enum named after the noun, not the property -**Location:** `src/v1/model.ts:52-62` +**Location:** `src/v1/model.ts:51-61` ```ts export enum DataRefresh { @@ -461,14 +397,14 @@ export enum DataRefresh { } ``` -The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 216) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. Also note: values mix nouns (`SECOND`, `MINUTE`) with adjectives (`HOURLY`, `DAILY`, `WEEKLY`) within the same enum — `SECONDLY` and `MINUTELY` are not used. +The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 258) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. Also note: values mix nouns (`SECOND`, `MINUTE`) with adjectives (`HOURLY`, `DAILY`, `WEEKLY`) within the same enum — `SECONDLY` and `MINUTELY` are not used. - **Category:** 1 (vague: name is the noun, not the unit), 17 (inconsistent value form: nouns vs adverbs). - **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. - **Rationale:** Self-documenting enum name; consistent value form. -### 23. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special +### 21. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special -**Location:** `src/v1/model.ts:53-55` +**Location:** `src/v1/model.ts:52-55` ```ts NONE = 'NONE', @@ -480,28 +416,28 @@ HOURLY = 'HOURLY', `NONE` reads as "no refresh"; `SECOND` reads as "every second"; `HOURLY` reads as "every hour". The first two follow noun-naming; the third follows adverb-naming. Mixing the two within the same enum produces inconsistency. - **Category:** 17 (inconsistent value form). - **Suggested name:** Pick one convention. If "every X" adverbs are used, change `SECOND` → `SECONDLY`, `MINUTE` → `MINUTELY`, `NONE` → unchanged. -- **Rationale:** See #22. +- **Rationale:** See #20. -### 24. `Category` — generic enum name with 23 values +### 22. `Category` — generic enum name with 22 values -**Location:** `src/v1/model.ts:21-45` +**Location:** `src/v1/model.ts:21-44` ```ts export enum Category { ADVERTISING_AND_MARKETING = 'ADVERTISING_AND_MARKETING', ... - OPEN_SOURCE = 'OPEN_SOURCE', + TRAVEL_AND_TOURISM = 'TRAVEL_AND_TOURISM', } ``` `Category` is generic without a domain qualifier (compare with `AssetType`, `ListingType`, `MarketplaceFileType`). The other enums use a domain prefix; `Category` does not. Also, it's exported at the package root and a user importing `Category` doesn't know it's marketplace-scoped. - **Category:** 1 (vague), 17 (inconsistent qualifier convention). -- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 528). +- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 732). - **Rationale:** Cross-package collision avoidance and self-documentation. -### 25. `ListingDetail.size` — ambiguous unit +### 23. `ListingDetail.size` — ambiguous unit -**Location:** `src/v1/model.ts:489-490` +**Location:** `src/v1/model.ts:685-686` ```ts /** size of the dataset in GB */ @@ -513,9 +449,9 @@ The JSDoc says "in GB", but the field name is just `size`. The wire field is `si - **Suggested name:** `sizeInGigabytes` or `sizeGb`. - **Rationale:** Numeric fields without unit suffix are a bug magnet. -### 26. `ListingDetail.cost` typed as `Cost` (enum), but doc says price +### 24. `ListingDetail.cost` typed as `Cost` (enum), but doc says price -**Location:** `src/v1/model.ts:472-473, 477-478` +**Location:** `src/v1/model.ts:668-669, 673-674` ```ts /** Whether the dataset is free or paid */ @@ -532,9 +468,9 @@ Two related fields: `cost: Cost (= 'FREE' | 'PAID')` and `pricingModel: string` - **Suggested name:** Combine into one discriminated union: `pricing?: { $case: 'free' } | { $case: 'paid', model: string }`. - **Rationale:** Type-system can encode the relationship the prose tries to. -### 27. `ListingDetail.geographicalCoverage` — long camelCase +### 25. `ListingDetail.geographicalCoverage` — long camelCase -**Location:** `src/v1/model.ts:470-471` +**Location:** `src/v1/model.ts:666-667` ```ts /** Which geo region the listing data is collected from */ @@ -546,9 +482,9 @@ geographicalCoverage?: string | undefined; - **Suggested name:** `geoRegion`, `regions`, or `coverage`. - **Rationale:** Shorter, matches sibling naming. -### 28. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number +### 26. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number -**Location:** `src/v1/model.ts:483-486` +**Location:** `src/v1/model.ts:679-682` ```ts /** The starting date timestamp for when the data spans */ @@ -562,9 +498,9 @@ Field names include "Date" but the type is `number` (Unix timestamp). A consumer - **Suggested name:** `collectionStartAt` / `collectionEndAt`, or `collectionPeriodStart` / `collectionPeriodEnd`. - **Rationale:** "Date" is ambiguous about underlying type; `At` is the existing in-file convention for Unix timestamps. -### 29. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming +### 27. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming -**Location:** `src/v1/model.ts:479-482` +**Location:** `src/v1/model.ts:675-678` ```ts /** How often data is updated */ @@ -578,9 +514,9 @@ Both are `DataRefreshInfo` (an interval), but one is named "frequency" and the o - **Suggested name:** Rename type → `TimeInterval`; keep the field-level distinction. - **Rationale:** Reuse a generic type name for a reusable type. -### 30. `ListingDetail.dataSource` — single-word vague field +### 28. `ListingDetail.dataSource` — single-word vague field -**Location:** `src/v1/model.ts:487-488` +**Location:** `src/v1/model.ts:683-684` ```ts /** Where/how the data is sourced */ @@ -592,9 +528,9 @@ dataSource?: string | undefined; - **Suggested name:** `dataSourceDescription`, `dataProvenance`, or `dataOriginNote`. - **Rationale:** Disambiguate from the more common DB-connection meaning of "data source". -### 31. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags +### 29. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags -**Location:** `src/v1/model.ts:493-508` +**Location:** `src/v1/model.ts:689-704` ```ts export interface ListingDetail { @@ -613,21 +549,16 @@ export interface ListingTag { /** String representation of the tag value. Values should be string literals (no complex types) */ tagValues?: string[] | undefined; } - -export enum ListingTagType { - LISTING_TAG_TYPE_LANGUAGE = 'LISTING_TAG_TYPE_LANGUAGE', - LISTING_TAG_TYPE_TASK = 'LISTING_TAG_TYPE_TASK', -} ``` -The enum constrains tag *names* to 2 values. Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. +The enum constrains tag *names* to a small set. Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. - **Category:** 6 (misleading: name implies free-form labels, structure is constrained), 7 (`tagName` / `tagValues` add `tag` prefix repeated from type name). - **Suggested name:** `ListingTag.name` / `ListingTag.values`; rename type to clarify (e.g. `ListingAttribute`). - **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. -### 32. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology +### 30. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology -**Location:** `src/v1/model.ts:538-543` +**Location:** `src/v1/model.ts:742-747` ```ts export interface ListingTag { @@ -639,11 +570,11 @@ export interface ListingTag { Inside `ListingTag`, what else could `tagName` and `tagValues` be? `name` and `values` carry the same information. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `name`, `values`. -- **Rationale:** See #17. +- **Rationale:** See #15. -### 33. `ContactInfo` — generic suffix on a single-purpose type +### 31. `ContactInfo` — generic suffix on a single-purpose type -**Location:** `src/v1/model.ts:151-156` +**Location:** `src/v1/model.ts:171-177` ```ts /** contact info for the consumer requesting data or performing a listing installation */ @@ -655,14 +586,14 @@ export interface ContactInfo { } ``` -`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 548). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. +`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 752). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. - **Category:** 8 (redundant `Info` suffix), 1 (vague). - **Suggested name:** `Contact` or `ConsumerContact`. - **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. -### 34. `RegionInfo` — `Info` suffix on a single-purpose type +### 32. `RegionInfo` — `Info` suffix on a single-purpose type -**Location:** `src/v1/model.ts:587-590` +**Location:** `src/v1/model.ts:791-794` ```ts export interface RegionInfo { @@ -671,14 +602,14 @@ export interface RegionInfo { } ``` -Same problem as #33. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. +Same problem as #31. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. - **Category:** 8 (redundant `Info` suffix), 19 (underspecified — no enum constraints). - **Suggested name:** `Region` (the cloud is implicitly part of the region in many SDKs) or `CloudRegion`. - **Rationale:** Avoid `*Info` suffix; consider richer typing. -### 35. `ShareInfo` — `Info` suffix on a sharing concept +### 33. `ShareInfo` — `Info` suffix on a sharing concept -**Location:** `src/v1/model.ts:604-607` +**Location:** `src/v1/model.ts:839-842` ```ts export interface ShareInfo { @@ -687,14 +618,14 @@ export interface ShareInfo { } ``` -Same problem as #33 and #34. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". +Same problem as #31 and #32. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". - **Category:** 8 (redundant `Info` suffix). - **Suggested name:** `Share`, `ListingShare`. -- **Rationale:** See #33. +- **Rationale:** See #31. -### 36. `ProviderInfo` — `Info` suffix on the canonical provider type +### 34. `ProviderInfo` — `Info` suffix on the canonical provider type -**Location:** `src/v1/model.ts:568-585` +**Location:** `src/v1/model.ts:772-789` ```ts export interface ProviderInfo { @@ -706,14 +637,14 @@ export interface ProviderInfo { } ``` -Same problem as #33. The package also has `CreateProvider`, `GetProvider`, `UpdateProvider`, `DeleteProvider`, `ListProviders` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. +Same problem as #31. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent: the rest of the package uses `Provider` alone). - **Suggested name:** `Provider`. - **Rationale:** Consistency with method/request type names. -### 37. `DataRefreshInfo` — `Info` suffix on an interval type +### 35. `DataRefreshInfo` — `Info` suffix on an interval type -**Location:** `src/v1/model.ts:214-217` +**Location:** `src/v1/model.ts:256-259` ```ts export interface DataRefreshInfo { @@ -722,14 +653,14 @@ export interface DataRefreshInfo { } ``` -Same problem as #33. Also note: the type is reused for `collectionGranularity` (#29), so the name `DataRefreshInfo` is wrong for half of its uses. +Same problem as #31. Also note: the type is reused for `collectionGranularity` (#27), so the name `DataRefreshInfo` is wrong for half of its uses. - **Category:** 8 (redundant `Info` suffix), 6 (misleading: name doesn't fit `collectionGranularity` use). -- **Suggested name:** `TimeInterval` (matches #29). -- **Rationale:** See #29. +- **Suggested name:** `TimeInterval` (matches #27). +- **Rationale:** See #27. -### 38. `FileInfo` — `Info` suffix on the canonical file type +### 36. `FileInfo` — `Info` suffix on the canonical file type -**Location:** `src/v1/model.ts:288-301` +**Location:** `src/v1/model.ts:330-343` ```ts export interface FileInfo { @@ -739,14 +670,14 @@ export interface FileInfo { } ``` -Same problem as #33. The package also has `CreateFile`, `GetFile`, `DeleteFile`, `ListFiles` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. +Same problem as #31. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent with siblings). - **Suggested name:** `File`. -- **Rationale:** See #36. +- **Rationale:** See #34. -### 39. `Listing.summary` / `Listing.detail` — opaque fields on the central type +### 37. `Listing.summary` / `Listing.detail` — opaque fields on the central type -**Location:** `src/v1/model.ts:456-460` +**Location:** `src/v1/model.ts:652-656` ```ts export interface Listing { @@ -759,11 +690,11 @@ export interface Listing { `Listing` is essentially `(id, summary, detail)` — a 3-field passthrough. The two interesting fields are named `summary` and `detail`, opaque on their own. A consumer with `listing.summary.name` and `listing.detail.description` has to navigate two sub-objects to reach the actual content. - **Category:** 1 (vague), 11 (could be merged). - **Suggested name:** Flatten or rename `summary` → `metadata`, `detail` → `content`. -- **Rationale:** See #9. +- **Rationale:** See #6. -### 40. `ListingSummary.setting` — singular field name +### 38. `ListingSummary.setting` — singular field name -**Location:** `src/v1/model.ts:521` +**Location:** `src/v1/model.ts:725` ```ts export interface ListingSummary { @@ -777,15 +708,15 @@ export interface ListingSummary { - **Suggested name:** `settings: ListingSettings`. - **Rationale:** Plural matches the conventional naming for a settings bag. -### 41. `ListingSummary.providerRegion` — region of what? +### 39. `ListingSummary.providerRegion` — region of what? -**Location:** `src/v1/model.ts:520` +**Location:** `src/v1/model.ts:724` ```ts providerRegion?: RegionInfo | undefined; ``` -`PersonalizationRequest.consumerRegion` (line 547) uses the same `RegionInfo` type with the `consumer` qualifier. So the package has `providerRegion` and `consumerRegion` — two different qualifiers for the same `RegionInfo` type. Fine; flagged because the *type* name (`RegionInfo`) is unqualified, while every *use* requires a qualifier. +`PersonalizationRequest.consumerRegion` (line 751) uses the same `RegionInfo` type with the `consumer` qualifier. So the package has `providerRegion` and `consumerRegion` — two different qualifiers for the same `RegionInfo` type. Fine; flagged because the *type* name (`RegionInfo`) is unqualified, while every *use* requires a qualifier. - **Category:** 1 (vague type, qualified field), 17 (qualifier convention not encoded in the type). - **Suggested name:** No rename; this is the price of reusing `RegionInfo`. - **Rationale:** Observation. @@ -794,25 +725,25 @@ providerRegion?: RegionInfo | undefined; ## Low severity -### 42. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization +### 40. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization -**Location:** `src/v1/model.ts:457, 467, 533` +**Location:** `src/v1/model.ts:653, 663, 737` Mixed singular/plural id fields: - `Listing.id` — single id of the listing. - `ListingDetail.fileIds: string[]` — many file ids. - `ListingSummary.exchangeIds: string[]` — many exchange ids. - `ListingSummary.providerId: string` — single provider id. -- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #43). +- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #41). Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #43). +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #41). - **Suggested name:** Pick one — `*Id`/`*Ids` is standard. - **Rationale:** Observation; flagged for completeness. -### 43. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number +### 41. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number -**Location:** `src/v1/model.ts:530-531` +**Location:** `src/v1/model.ts:734-735` ```ts createdById?: number | undefined; @@ -824,9 +755,9 @@ User ids are typed as `number`. JS `number` only safely represents integers up t - **Suggested name:** `createdById: string` or `bigint`. - **Rationale:** Lossy representation; consistency with other id fields (all `string`). -### 44. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` +### 42. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` -**Location:** `src/v1/model.ts:136-139` +**Location:** `src/v1/model.ts:137-140` ```ts export enum Visibility { @@ -840,9 +771,9 @@ Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal ty - **Suggested name:** Could be `'public' | 'private'` literal union. - **Rationale:** Observation. -### 45. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun +### 43. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun -**Location:** `src/v1/model.ts:90-93` +**Location:** `src/v1/model.ts:99-102` ```ts export enum ListingShareType { @@ -856,9 +787,9 @@ export enum ListingShareType { - **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). - **Rationale:** Internal consistency. -### 46. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values +### 44. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values -**Location:** `src/v1/model.ts:109-112` +**Location:** `src/v1/model.ts:118-121` ```ts export enum ListingType { @@ -867,14 +798,14 @@ export enum ListingType { } ``` -Two adjective values. Fine. Flagged because the package also has `PersonalizationRequest` (line 545) — the noun for `PERSONALIZED` mode. Cross-reference unclear. +Two adjective values. Fine. Flagged because the package also has `PersonalizationRequest` (line 749) — the noun for `PERSONALIZED` mode. Cross-reference unclear. - **Category:** Observation. - **Suggested name:** No rename. - **Rationale:** Internal consistency check. -### 47. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located +### 45. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located -**Location:** `src/v1/model.ts:572, 580` +**Location:** `src/v1/model.ts:776, 784` ```ts iconFilePath?: string | undefined; @@ -882,14 +813,14 @@ iconFilePath?: string | undefined; iconFileId?: string | undefined; ``` -Same icon represented two ways — `iconFilePath` (a URL or storage path) and `iconFileId` (a Marketplace file id). The pairing repeats with `darkModeIconFileId` and `darkModeIconFilePath` (lines 583-584). No doc explains when to use which or whether one is derived from the other. +Same icon represented two ways — `iconFilePath` (a URL or storage path) and `iconFileId` (a Marketplace file id). The pairing repeats with `darkModeIconFileId` and `darkModeIconFilePath` (lines 787-788). No doc explains when to use which or whether one is derived from the other. - **Category:** 12 (duplicate concept), 17 (inconsistent — the relationship is implicit). - **Suggested name:** No rename; flag for doc clarification. - **Rationale:** Observation. -### 48. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode +### 46. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode -**Location:** `src/v1/model.ts:583-584` +**Location:** `src/v1/model.ts:787-788` ```ts darkModeIconFileId?: string | undefined; @@ -901,9 +832,9 @@ The `darkMode` prefix encodes a UI rendering mode in a server-side data type. Th - **Suggested name:** `iconDarkFileId` / `iconDarkFilePath` or just `darkIcon*`. - **Rationale:** Observation. -### 49. Method docstring inconsistency — `client.ts` +### 47. Method docstring inconsistency — `client.ts` -**Location:** `src/v1/client.ts:178, 207, 232, 261, 287, 313, 339, 371, 396, 424, 449, 474, 499, 524, 549, 577, 602, 656, 713, 738, 795, 846, 903, 961, 1018, 1046, 1097, 1125, 1151, 1180, 1206, 1238, 1264` +**Location:** `src/v1/client.ts:235, 266, 297, 326, 380, 437, 491, 542, 600, 628, 656, 735, 763, 789, 849, 927, 952, 986, 1015, 1041, 1070, 1096, 1125, 1154, 1186, 1211, 1239, 1264, 1292, 1320, 1345, 1370, 1400, 1425, 1479, 1539, 1567, 1624, 1675, 1732, 1790, 1847, 1875, 1929, 1957, 1983, 2012, 2041, 2073, 2102` ```ts /** Associate an exchange with a listing */ @@ -918,8 +849,8 @@ The `darkMode` prefix encodes a UI rendering mode in a server-side data type. Th Inconsistent docstring style: - Mix of trailing period ("Add an exchange filter.", "Create a file. ...") and no period ("Create an exchange", "Create a new listing"). - Mix of imperative verbs ("Create", "Get", "Delete") and full sentences ("This removes a listing from marketplace."). -- "Get provider analytics dashboard" appears on `listProviderAnalyticsDashboard` (line 1018) — verb mismatch (it's a list method but the doc says "Get"). -- "This removes a listing from marketplace" appears on `deleteExchange` (line 371) — text describes the wrong concept (says "listing", method is `deleteExchange`). +- "Get provider analytics dashboard" appears on `listProviderAnalyticsDashboard` (line 1847) — verb mismatch (it's a list method but the doc says "Get"). +- "This removes a listing from marketplace" appears on `deleteExchange` (line 1186) — text describes the wrong concept (says "listing", method is `deleteExchange`). - **Category:** 17 (inconsistent action verbs / doc style), 6 (misleading: docstring text contradicts method name). - **Suggested name:** No rename; flag for doc consistency. - **Rationale:** Observation. @@ -928,26 +859,29 @@ Inconsistent docstring style: ## Observations -### 50. v1-only audit +### 48. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 51. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:147` +### 49. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. - **Category:** 1 (vague), 15 (generic name). -### 52. `flattenQueryParams` — `src/v1/utils.ts:123` -The helper is used by `client.ts:911-915` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. +### 50. `flattenQueryParams` — `src/v1/utils.ts:123` +The helper is used by `client.ts` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. - **Category:** Observation. -### 53. `readAll` — `src/v1/utils.ts:40` +### 51. `readAll` — `src/v1/utils.ts:40` Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. - **Category:** 1 (vague), 14 (Go-style name). -### 54. `HttpCallOptions` — `src/v1/utils.ts:15` +### 52. `HttpCallOptions` — `src/v1/utils.ts:15` Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. - **Category:** 1 (vague suffix), 17 (inconsistent). -### 55. AssetType/ListingTagType/DeltaSharingRecipientType/FileStatus enum prefixes — generator-only +--- -These enum types use the proto convention of prefixing every value with the type name (e.g. `AssetType.ASSET_TYPE_GIT_REPO`, `FileStatus.FILE_STATUS_PUBLISHED`). Per the generator-only recommendations in `_SUMMARY.md`, redundant enum prefixes are tracked at the template level rather than per-package. -- **Category:** Observation. +## Fixed + +- #1 Verb-shaped request types (originally cited at `src/v1/model.ts:174, 188, 197, 207, 233, 240, 247, 317, 331, 339, 348, 359, 370, 411, 434, 445, 627, 637, 650, 660`): Fixed in regeneration on 2026-05-20 — all top-level request DTOs now uniformly use the `*Request` suffix (e.g., `CreateFileRequest`, `GetListingRequest`, `ListProvidersRequest`, `UpdateProviderAnalyticsDashboardRequest`, etc.); response payloads for these now follow the proto-style `Request_Response` nested-message pattern. +- #2 Two competing request-type naming conventions in one file (originally cited throughout `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — the verb-shaped (Go-style) vs `*Request`-suffixed split is gone; every operation type now uses the `*Request` suffix consistently across provider, exchange, file, listing, personalization, and analytics-dashboard surfaces. +- #7 `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` (originally cited at `src/v1/model.ts:119-126`): Fixed in regeneration on 2026-05-20 — the `COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` enum value and its associated JSDoc have been removed; `MarketplaceFileType` is now `PROVIDER_ICON | EMBEDDED_NOTEBOOK | APP` (also dropping `EMBEDDED_MARKDOWN`). diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md index a6613aaf..1e155782 100644 --- a/.agent/naming-audit/materializedfeatures.md +++ b/.agent/naming-audit/materializedfeatures.md @@ -1,5 +1,9 @@ # Naming Audit: `materializedfeatures` (v1) +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `/home/parth.bansal/sdk-js/packages/materializedfeatures/` **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` @@ -708,3 +712,9 @@ inherited from the Go SDK; the cleanest local fixes are findings 1 (package rename), 5 (`onlineTableName` field), 8 (JSDoc on `tableName`/`featureName`), 9 (JSDoc plural form), 10 (top-level `key` for update), 11 (field order in `GetFeatureLineageRequest`), and 12 (`getFeatureLineage` JSDoc casing). + +## Fixed + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index 4802ec5d..a44c94cf 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -13,13 +13,13 @@ The `metastores` package exposes nine Unity Catalog metastore operations `deleteMetastoreAssignment`, `getCurrentMetastoreAssignment`, `getMetastore`, `getMetastoreSummary`, `listMetastores`, `updateMetastore`, `updateMetastoreAssignment`). -The dominant naming problems are structural: `CreateMetastore`, -`UpdateMetastore`, and `MetastoreInfo` share 18 fields verbatim, +The dominant naming problems are structural: `CreateMetastoreRequest`, +`UpdateMetastoreRequest`, and `MetastoreInfo` share 18 fields verbatim, including read-only output fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `globalMetastoreId`) that have no business in -a write request. `UpdateMetastore` further conflates a path-parameter +a write request. `UpdateMetastoreRequest` further conflates a path-parameter `id`, a body `name`, and a "rename target" `newName`. -`GetMetastoreSummary_Response` is structurally identical to +`GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` despite the "summary" name promising a smaller shape. --- @@ -28,42 +28,42 @@ a write request. `UpdateMetastore` further conflates a path-parameter ### 1. Vague / generic names -#### 1.1 `DeleteMetastore.id`, `GetMetastore.id`, `UpdateMetastore.id` (model.ts:79, 105, 234) +#### 1.1 `DeleteMetastoreRequest.id`, `GetMetastoreRequest.id`, `UpdateMetastoreRequest.id` (model.ts:271, 287, 473) Field name `id` on three request types where the surrounding type already conveys the entity ("delete metastore", "get metastore", "update metastore"). The doc string is "Unique ID of the metastore." — i.e. the field is the metastore id. The same concept appears as `metastoreId` -everywhere else in the package (model.ts:42, 64, 91, 113, 213, 258, -etc.), so the bare `id` is inconsistent and ambiguous in isolation -(e.g. spreading `{...req, id: someValue}` is brittle). Recommend -`metastoreId` (or, if the goal is to mark it as the path param, see -§5.1 / §10.1). +everywhere else in the package (model.ts:27, 54, 66, 94, 121, 137, 150, +183, 206, 240, 263, 296, 365, 395, 436, 459, 497), so the bare `id` is +inconsistent and ambiguous in isolation (e.g. spreading +`{...req, id: someValue}` is brittle). Recommend `metastoreId` (or, if +the goal is to mark it as the path param, see §5.1 / §10.1). -#### 1.2 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:181, 183) +#### 1.2 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:363, 365) Acceptable in isolation — but the *type* `MetastoreAssignment` is just a `(workspaceId, metastoreId, defaultCatalogName)` triple. The name "MetastoreAssignment" promises richer semantics than the three-field struct delivers. Consider `WorkspaceMetastoreLink` or making the relationship directional in the name. -#### 1.3 `DeleteMetastore.force` (model.ts:81) +#### 1.3 `DeleteMetastoreRequest.force` (model.ts:273) Generic boolean — "force" alone leaves callers to read the doc to learn the consequences ("Force deletion even if the metastore is not empty."). A more descriptive name (`forceDeleteNonEmpty`, `deleteNonEmpty`) captures the intent at the call site. Acceptable as a convention but worth flagging. -#### 1.4 `cloud` field (model.ts:54, 122, 225, 270) +#### 1.4 `cloud` field (model.ts:195, 252, 407, 448, 509) A bare `cloud: string` with a single example list in the doc (`aws`, `azure`, `gcp`). Should probably be typed as a `CloudProvider` enum (see §5.4) — but at minimum the field is generic when read alone. -#### 1.5 `owner` field (model.ts:36, 140, 207, 252) +#### 1.5 `owner` field (model.ts:177, 234, 389, 430, 491) "The owner of the metastore." — generic. Owner of what kind? Username? Email? Group? Service principal? Documented as a free-form string with no format hint. See §13.4. -#### 1.6 `region` (model.ts:40, 124, 211, 256) +#### 1.6 `region` (model.ts:181, 238, 393, 434, 495) Bare `region: string` with examples (`us-west-2`, `westus`). Acceptable as cloud-vendor-specific opaque strings, but the same field carries different vocabularies across `aws` / `azure` / `gcp` — that @@ -79,24 +79,24 @@ _None._ ### 3. Acronym casing inconsistencies -#### 3.1 `DBR` in doc strings (model.ts:57, 149, 228, 273) +#### 3.1 `DBR` in doc strings (model.ts:198, 255, 410, 451, 512) Doc says "Whether to allow non-DBR clients to directly access entities under the metastore." DBR (Databricks Runtime) is an internal acronym not introduced anywhere in the package. Doc-only, not a code-naming issue per se, but it's a documentation acronym that won't mean anything to external SDK consumers. -#### 3.2 `UUID` casing in docs (model.ts:27, 119, 198, 243) +#### 3.2 `UUID` casing in docs (model.ts:168, 225, 380, 421, 482) "UUID of storage credential" — UUID is in the doc only. The field is named `storageRootCredentialId` (lowercase `Id`). Consistent with ECMAScript identifier convention; flagged in passing. -#### 3.3 `URL` casing in docs (model.ts:23, 138, 194, 239) +#### 3.3 `URL` casing in docs (model.ts:164, 221, 376, 417, 478) "The storage root URL" — `URL` in docs, but the field is `storageRoot`, not `storageRootUrl`. Inconsistent with how `globalMetastoreId` etc. embed type info in the name. See also §5.2. -#### 3.4 `` placeholder tokens in docs (model.ts:69, 180, 285) +#### 3.4 `` placeholder tokens in docs (model.ts:22, 37, 49, 63, 77, 91, 105, 118, 132, 147, 362, 463) Literal `` strings appear in doc comments — these are unsubstituted templating placeholders. Not a naming issue, but surfaces as a publication bug for SDK consumers reading the generated @@ -106,7 +106,7 @@ TypeDoc. ### 4. Cryptic abbreviations -#### 4.1 `id` (model.ts:79, 105, 234) — see §1.1 +#### 4.1 `id` (model.ts:271, 287, 473) — see §1.1 Cryptic because it loses the entity context. `metastoreId` is used elsewhere. @@ -119,40 +119,40 @@ milliseconds" but the names omit the unit suffix (`createdAt`, ### 5. Misleading names -#### 5.1 `MetastoreInfo` (model.ts:191) +#### 5.1 `MetastoreInfo` (model.ts:373) "Info" suggests metadata about a metastore separate from the entity itself; the type is in fact the entity. See also §7.1. -#### 5.2 `storageRoot` doc says "URL" (model.ts:23, 138, 194, 239) +#### 5.2 `storageRoot` doc says "URL" (model.ts:164, 221, 376, 417, 478) "The storage root URL for metastore" — the field is named `storageRoot`, but documented as a URL. Rename to `storageRootUrl`, or rename the doc. Today the name is vague about the value's shape. -#### 5.3 `globalMetastoreId` (model.ts:56, 126, 227, 271) +#### 5.3 `globalMetastoreId` (model.ts:197, 254, 409, 450, 511) Doc: "Globally unique metastore ID across clouds and regions, of the form `cloud:region:metastore_id`." So the value is a composite formatted string, not an ID in the conventional sense. Either rename to `globalMetastoreLocator` / `globalMetastoreUri` to signal the encoded shape, or document its parseable structure in a type. -#### 5.4 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +#### 5.4 `defaultDataAccessConfigId` (model.ts:167, 223, 379, 419, 480) Doc says "Unique identifier of the metastore's (Default) Data Access Configuration." The parenthetical "Default" duplicates the `default` prefix in the name, but the field is described as both the default data-access-config and as a unique identifier. Slightly self-referential and unclear whether this is mutable or static. See also §13.3. -#### 5.5 `cloud: string` (model.ts:54, 122, 225, 270) +#### 5.5 `cloud: string` (model.ts:195, 252, 407, 448, 509) Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as `string`. The name is fine; the *type* misleads about the value space. See §1.4. -#### 5.6 `region: string` carries cloud-specific formats (model.ts:40, 124, 211, 256) +#### 5.6 `region: string` carries cloud-specific formats (model.ts:181, 238, 393, 434, 495) "e.g., `us-west-2`, `westus`" — same field carries AWS-style and Azure-style region names. Name is fine; doc just shows the heterogeneity. See §1.6. -#### 5.7 `GetMetastoreSummary` response is structurally identical to `MetastoreInfo` (model.ts:112-151 vs 191-230) +#### 5.7 `GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` (model.ts:294-333 vs 373-412) Both types have the *same* 18 fields with the *same* docs in the *same* order. The "summary" type doesn't actually summarise — it returns the full metastore record. The name lies about the content. The Go SDK @@ -160,7 +160,7 @@ inherits this from the API definition, but the TS port could collapse the two: either alias the summary response to `MetastoreInfo` or expose the genuinely-summarised subset. -#### 5.8 `getMetastoreSummary` is presented as info-about (client.ts:266-269) +#### 5.8 `getMetastoreSummary` is presented as info-about (client.ts:616-619) JSDoc says "Gets information about a metastore. This summary includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" @@ -172,7 +172,7 @@ omits the "current-workspace" semantics. Cf. ### 6. Overly verbose -#### 6.1 `getCurrentMetastoreAssignment` (client.ts:216) +#### 6.1 `getCurrentMetastoreAssignment` (client.ts:567) 28-character method name. Acceptable — describes the semantics — but combined with `getMetastoreSummary` (which is also "current-workspace" in practice, §5.8) one of them carries redundant prefixing. @@ -181,13 +181,13 @@ in practice, §5.8) one of them carries redundant prefixing. ### 7. Redundant suffixes -#### 7.1 `…Info` suffix on `MetastoreInfo` (model.ts:191) +#### 7.1 `…Info` suffix on `MetastoreInfo` (model.ts:373) "Info" carries no semantic content. Go-SDK convention; TS would just say `Metastore`. See §9.3. #### 7.2 `…Assignment` suffix on `MetastoreAssignment` and four request types -`CreateMetastoreAssignment`, `DeleteMetastoreAssignment`, -`UpdateMetastoreAssignment`, `GetCurrentMetastoreAssignment`, +`CreateMetastoreAssignmentRequest`, `DeleteMetastoreAssignmentRequest`, +`UpdateMetastoreAssignmentRequest`, `GetCurrentMetastoreAssignmentRequest`, `MetastoreAssignment`. The suffix is justified because "metastore assignment" is a distinct concept. Not redundant — flagged for completeness. @@ -196,7 +196,7 @@ completeness. ### 8. Singular / plural mismatches -#### 8.1 `ListMetastoresResponse.metastores` (model.ts:171) +#### 8.1 `ListMetastoresRequest_Response.metastores` (model.ts:353) Field is plural and correctly typed `MetastoreInfo[]` — no mismatch. Flagged as a counter-example. @@ -204,11 +204,11 @@ Flagged as a counter-example. ### 9. Reserved-word collisions -#### 9.1 `name` field on `CreateMetastore`, `MetastoreInfo`, `UpdateMetastore`, `GetMetastoreSummary` response (model.ts:22, 116, 193, 238) +#### 9.1 `name` field on `CreateMetastoreRequest`, `MetastoreInfo`, `UpdateMetastoreRequest`, `GetMetastoreSummaryRequest_Response` response (model.ts:220, 298, 375, 477) Routinely shadows `Function.prototype.name`. Common SDK convention; not fixable in isolation. See also §10.1. -#### 9.2 `id` field on `DeleteMetastore`, `GetMetastore`, `UpdateMetastore` (model.ts:79, 105, 234) +#### 9.2 `id` field on `DeleteMetastoreRequest`, `GetMetastoreRequest`, `UpdateMetastoreRequest` (model.ts:271, 287, 473) Collides with `Element.id` and other web-platform-y identifiers when the request type is used in browser code. Not a TS-level collision but a cognitive one. See §1.1. @@ -219,38 +219,38 @@ a cognitive one. See §1.1. ### 10. Duplicate concepts -#### 10.1 `MetastoreInfo` vs `GetMetastoreSummary` response (model.ts:112, 191) +#### 10.1 `MetastoreInfo` vs `GetMetastoreSummaryRequest_Response` (model.ts:294, 373) Same 18 fields, same docs, different names. See §5.7. -#### 10.2 `CreateMetastore` vs `MetastoreInfo` vs `UpdateMetastore` (model.ts:20, 191, 232) -Massive structural duplication — `CreateMetastore` has 19 fields, -`MetastoreInfo` has 19 fields, `UpdateMetastore` has 20 fields. The -extra field on `UpdateMetastore` is `id` (path param) plus `newName`. -Every other field is replicated verbatim with the same doc string. A -shared `MetastoreCommon` (or `Partial`) would let -renames happen in one place. Note that all three contain the same +#### 10.2 `CreateMetastoreRequest` vs `MetastoreInfo` vs `UpdateMetastoreRequest` (model.ts:218, 373, 471) +Massive structural duplication — `CreateMetastoreRequest` has 19 fields, +`MetastoreInfo` has 19 fields, `UpdateMetastoreRequest` has 20 fields. +The extra fields on `UpdateMetastoreRequest` are `id` (path param) and +`newName`. Every other field is replicated verbatim with the same doc +string. A shared `MetastoreCommon` (or `Partial`) would +let renames happen in one place. Note that all three contain the same read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `globalMetastoreId`) — these have no business on a request shape (§11.3). -#### 10.3 `CreateMetastoreAssignment` vs `MetastoreAssignment` vs `UpdateMetastoreAssignment` (model.ts:61, 179, 277) +#### 10.3 `CreateMetastoreAssignmentRequest` vs `MetastoreAssignment` vs `UpdateMetastoreAssignmentRequest` (model.ts:202, 361, 455) Three structurally identical types with three workspace-id / metastore-id / default-catalog-name fields. Could be unified. -#### 10.4 `id` (on `DeleteMetastore`/`GetMetastore`/`UpdateMetastore`) vs `metastoreId` (everywhere else) +#### 10.4 `id` (on `DeleteMetastoreRequest`/`GetMetastoreRequest`/`UpdateMetastoreRequest`) vs `metastoreId` (everywhere else) Same concept, two names. See §1.1. -#### 10.5 `name` (CreateMetastore body) vs metastore identity -`CreateMetastore.name` is "the user-specified name of the metastore" -— but `MetastoreInfo` also exposes `metastoreId` as the canonical -unique identifier. The naming pretends `name` is unique but in fact -the server creates `metastoreId` as the immutable key and `name` is -mutable. The doc could disclose this; the name doesn't. +#### 10.5 `name` (CreateMetastoreRequest body) vs metastore identity +`CreateMetastoreRequest.name` is "the user-specified name of the +metastore" — but `MetastoreInfo` also exposes `metastoreId` as the +canonical unique identifier. The naming pretends `name` is unique but +in fact the server creates `metastoreId` as the immutable key and +`name` is mutable. The doc could disclose this; the name doesn't. -#### 10.6 `name` vs `newName` on `UpdateMetastore` (model.ts:236, 238) +#### 10.6 `name` vs `newName` on `UpdateMetastoreRequest` (model.ts:475, 477) Two name-like fields on the update request: -- `newName` — "New name for the metastore." (model.ts:236). -- `name` — "The user-specified name of the metastore." (model.ts:238). +- `newName` — "New name for the metastore." (model.ts:475). +- `name` — "The user-specified name of the metastore." (model.ts:477). Per the doc, both fields can hold a name. The intent is presumably that `newName` is the rename target and `name` is left over from the @@ -260,12 +260,12 @@ shared shape; in practice, callers cannot tell. See §11.1. ### 11. Field contradicting type domain -#### 11.1 `UpdateMetastore` has `id`, `name`, `newName`, and `metastoreId` (model.ts:234, 236, 238, 258) +#### 11.1 `UpdateMetastoreRequest` has `id`, `name`, `newName`, and `metastoreId` (model.ts:473, 475, 477, 497) Four name/id-like fields on a single update request: - `id` — path parameter; the existing metastore to update. - `metastoreId` — leftover from the shared shape; not used by the client method (`req.id` is what is interpolated into the URL at - client.ts:364). + client.ts:718). - `name` — "The user-specified name of the metastore." Ambiguous whether this is the current or new name. - `newName` — "New name for the metastore." Presumably the rename @@ -275,11 +275,11 @@ A caller staring at this struct cannot intuit which field controls what. This is the package's single most user-hostile naming pattern, mirroring the `UpdateCatalog` issue (catalogs §16.1). -#### 11.2 `UpdateMetastore.metastoreId` shadows `UpdateMetastore.id` (model.ts:234, 258) +#### 11.2 `UpdateMetastoreRequest.metastoreId` shadows `UpdateMetastoreRequest.id` (model.ts:473, 497) Same as 11.1 — two id-like fields whose roles are not differentiated by name. -#### 11.3 `CreateMetastore` and `UpdateMetastore` carry read-only output fields (model.ts:42-58, 258-274) +#### 11.3 `CreateMetastoreRequest` and `UpdateMetastoreRequest` carry read-only output fields (model.ts:240-256, 497-513) `metastoreId`, `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `globalMetastoreId`, `cloud`, `storageRootCredentialName`. These are server-populated; a creator/updater setting them is at best ignored. @@ -287,13 +287,13 @@ The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of catalogs §16.2. -#### 11.4 `GetMetastoreSummary` response returns the full metastore (model.ts:112) — see §5.7. The type name promises a summary; the value is the entity. +#### 11.4 `GetMetastoreSummaryRequest_Response` returns the full metastore (model.ts:294) — see §5.7. The type name promises a summary; the value is the entity. --- ### 12. Inconsistent action verbs -#### 12.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:241, 269, 216) +#### 12.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:592, 620, 567) Three "get"-style methods, each with a different qualifier: - `getMetastore(req)` — get by id. - `getMetastoreSummary()` — get the current metastore (no id). @@ -312,51 +312,57 @@ from `getCurrentMetastoreAssignment`. ### 13. Underspecified IDs -#### 13.1 `metastoreId` (model.ts:42, 64, 91, 113, 183, 213, 258, 281) +#### 13.1 `metastoreId` (model.ts:27, 54, 66, 94, 121, 137, 150, 183, 206, 240, 263, 296, 365, 395, 436, 459, 497) Documented as "Unique identifier of metastore" / "The unique ID of the metastore." Format is opaque — likely a UUID, but never specified in the doc. -#### 13.2 `workspaceId` (model.ts:63, 89, 181, 279) +#### 13.2 `workspaceId` (model.ts:25, 52, 80, 135, 203, 260, 363, 457) `number` — that's specified by the type, but the doc just says "A workspace ID." with no range or stability guarantee. Acceptable for a numeric id; flagged because the format isn't documented in the field. -#### 13.3 `defaultDataAccessConfigId` (model.ts:26, 118, 197, 242) +#### 13.3 `defaultDataAccessConfigId` (model.ts:167, 223, 300, 379, 419, 480) "Unique identifier of the metastore's (Default) Data Access Configuration." No format hint (UUID? slug?). See §5.4. -#### 13.4 `storageRootCredentialId` (model.ts:28, 120, 199, 244) +#### 13.4 `storageRootCredentialId` (model.ts:169, 225, 302, 381, 421, 482) Doc says "UUID of storage credential" — at least the doc says UUID here, but the field name doesn't carry the type. Counter-example to §13.1: when the doc *does* specify UUID, the field still doesn't carry it. -#### 13.5 `createdAt`, `updatedAt` (model.ts:44, 48, 142, 146, 215, 219, 260, 264) +#### 13.5 `createdAt`, `updatedAt` (model.ts:184-191, 241-248, 323-329, 396-403, 437-444, 498-505) Doc says "epoch milliseconds" but the names lack the `Ms` unit suffix. Inconsistent across the package. -#### 13.6 `globalMetastoreId` (model.ts:56, 126, 227, 271) +#### 13.6 `globalMetastoreId` (model.ts:197, 254, 308, 409, 450, 511) Documented as a composite `cloud:region:metastore_id` string — not a simple ID. The name promises an ID; the value is a structured locator. See §5.3. -#### 13.7 `owner`, `createdBy`, `updatedBy` (model.ts:36, 46, 50, 140, 144, 148, 207, 217, 221, 252, 262, 266) +#### 13.7 `owner`, `createdBy`, `updatedBy` (model.ts:177, 187, 191, 234, 244, 248, 322, 326, 330, 389, 399, 403, 430, 440, 444, 491, 501, 505) Documented as "username", "Username of metastore creator", etc. Format (email? user id? group?) is unspecified. The names imply identity; the doc only narrows to "username". --- -### 14. Type-suffix tautology +### 14. Proto / architectural-leak naming -#### 14.1 `MetastoreInfo` exposes `metastoreId` (model.ts:191, 213) +_None._ + +--- + +### 15. Type-suffix tautology + +#### 15.1 `MetastoreInfo` exposes `metastoreId` (model.ts:373, 395) The type's domain is the metastore; the field redundantly carries the entity name in its identifier. Acceptable convention; flagged for completeness. -#### 14.2 `MetastoreAssignment` carries `metastoreId` (model.ts:179, 183) -Same pattern as 14.1 — entity name in field. +#### 15.2 `MetastoreAssignment` carries `metastoreId` (model.ts:361, 365) +Same pattern as 15.1 — entity name in field. --- @@ -365,34 +371,34 @@ Same pattern as 14.1 — entity name in field. ### A. `flattenQueryParams` is defined but unused (utils.ts:123) Each `deleteMetastore` / `deleteMetastoreAssignment` / `listMetastores` handler builds query strings inline with `URLSearchParams.append` -(client.ts:156-159, 187-190, 310-316). The exported helper +(client.ts:504-507, 538-541, 661-667). The exported helper `flattenQueryParams` is never referenced by `client.ts`. Either it's intentionally exported for consumer use (then it should be documented and reside in `utils` proper) or it's dead code. Same as catalogs cross-cutting A. -### B. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:126, 186, 394) +### B. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:471, 537, 748) If `workspaceId` is undefined, the URL silently becomes `/api/2.1/unity-catalog/workspaces//metastore` (note the double slash) and the request will fail on the server. The optional typing of -`workspaceId` on `CreateMetastoreAssignment`, -`DeleteMetastoreAssignment`, and `UpdateMetastoreAssignment` (each -field is `number | undefined`) lets the bug hide. +`workspaceId` on `CreateMetastoreAssignmentRequest`, +`DeleteMetastoreAssignmentRequest`, and `UpdateMetastoreAssignmentRequest` +(each field is `number | undefined`) lets the bug hide. -### C. `req.id` is similarly optional but interpolated into URLs (client.ts:155, 245, 364) +### C. `req.id` is similarly optional but interpolated into URLs (client.ts:503, 596, 718) `${req.id ?? ''}` — same pattern: undefined id silently produces a malformed URL. Combined with the generic `id` name (§1.1) the type contract is too loose for a required path parameter. -### D. `DeleteMetastoreAssignment.metastoreId` is sent in the query string, not the path (client.ts:186-191) +### D. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:538-543) On `DELETE /api/2.1/unity-catalog/workspaces/{workspaceId}/metastore`, the request appends `?metastore_id=…`. That contradicts the doc on -`DeleteMetastoreAssignment.metastoreId` ("Query for the ID of the -metastore to delete.") only via the leading word "Query" — the field -name itself does not signal that the value is a query parameter, not -a path one. +`DeleteMetastoreAssignmentRequest.metastoreId` ("Query for the ID of +the metastore to delete.") only via the leading word "Query" — the +field name itself does not signal that the value is a query parameter, +not a path one. -### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:72) +### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:109) "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. @@ -408,80 +414,105 @@ flagged in passing. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | -| `CreateMetastore` | model.ts:20 | 10.2, 11.3 | -| `CreateMetastore.name` | model.ts:22 | 9.1, 10.5 | -| `CreateMetastore.storageRoot` | model.ts:24 | 5.2 | -| `CreateMetastore.defaultDataAccessConfigId` | model.ts:26 | 5.4, 13.3 | -| `CreateMetastore.storageRootCredentialId` | model.ts:28 | 13.4 | -| `CreateMetastore.owner` | model.ts:36 | 1.5, 13.7 | -| `CreateMetastore.region` | model.ts:40 | 1.6, 5.6 | -| `CreateMetastore.metastoreId` (read-only on Create) | model.ts:42 | 11.3, 13.1, 14.1 | -| `CreateMetastore.createdAt` (read-only on Create) | model.ts:44 | 11.3, 13.5 | -| `CreateMetastore.createdBy` (read-only on Create) | model.ts:46 | 11.3, 13.7 | -| `CreateMetastore.updatedAt` (read-only on Create) | model.ts:48 | 11.3, 13.5 | -| `CreateMetastore.updatedBy` (read-only on Create) | model.ts:50 | 11.3, 13.7 | -| `CreateMetastore.storageRootCredentialName` (read-only) | model.ts:52 | 11.3 | -| `CreateMetastore.cloud` | model.ts:54 | 1.4, 5.5 | -| `CreateMetastore.globalMetastoreId` (read-only) | model.ts:56 | 5.3, 11.3, 13.6 | -| `CreateMetastore.externalAccessEnabled` | model.ts:58 | 3.1 (doc) | -| `CreateMetastoreAssignment` | model.ts:61 | 10.3 | -| `CreateMetastoreAssignment.workspaceId` | model.ts:63 | 13.2, F | -| `CreateMetastoreAssignment.metastoreId` | model.ts:65 | 13.1 | -| `CreateMetastoreAssignment.defaultCatalogName` | model.ts:71 | — | -| `DeleteMetastore` | model.ts:77 | — | -| `DeleteMetastore.id` | model.ts:79 | 1.1, 4.1, 9.2, 10.4 | -| `DeleteMetastore.force` | model.ts:81 | 1.3 | -| `DeleteMetastoreAssignment` | model.ts:87 | 10.3 | -| `DeleteMetastoreAssignment.workspaceId` | model.ts:89 | 13.2 | -| `DeleteMetastoreAssignment.metastoreId` | model.ts:91 | 13.1, D | -| `GetCurrentMetastoreAssignment` | model.ts:101 | — | -| `GetMetastore` | model.ts:103 | — | -| `GetMetastore.id` | model.ts:105 | 1.1, 4.1, 9.2, 10.4 | -| `GetMetastoreSummary` | model.ts:109 | — | -| `GetMetastoreSummary` response | model.ts:112 | 5.7, 10.1, 11.4 | -| `ListMetastores` | model.ts:153 | — | -| `ListMetastores.maxResults` | model.ts:163 | — | -| `ListMetastores.pageToken` | model.ts:165 | — | -| `ListMetastoresResponse.metastores` | model.ts:171 | 8.1 (positive) | -| `ListMetastoresResponse.nextPageToken` | model.ts:176 | — | -| `MetastoreAssignment` | model.ts:179 | 1.2, 7.2, 10.3 | -| `MetastoreAssignment.workspaceId` | model.ts:181 | 1.2, 13.2, F | -| `MetastoreAssignment.metastoreId` | model.ts:183 | 13.1, 14.2 | -| `MetastoreAssignment.defaultCatalogName` | model.ts:188 | — | -| `MetastoreInfo` | model.ts:191 | 5.1, 7.1, 10.2 | -| `MetastoreInfo.metastoreId` | model.ts:213 | 13.1, 14.1 | -| `MetastoreInfo.globalMetastoreId` | model.ts:227 | 5.3, 13.6 | -| `UpdateMetastore` | model.ts:232 | 10.2, 11.1, 11.3 | -| `UpdateMetastore.id` | model.ts:234 | 1.1, 4.1, 11.1, 11.2 | -| `UpdateMetastore.newName` | model.ts:236 | 10.6, 11.1 | -| `UpdateMetastore.name` | model.ts:238 | 10.6, 11.1 | -| `UpdateMetastore.metastoreId` | model.ts:258 | 11.1, 11.2 | -| `UpdateMetastoreAssignment` | model.ts:277 | 10.3 | -| `UpdateMetastoreAssignment.workspaceId` | model.ts:279 | 13.2 | -| `Client.createMetastore` | client.ts:92 | — | -| `Client.createMetastoreAssignment` | client.ts:122 | — | -| `Client.deleteMetastore` | client.ts:151 | C | -| `Client.deleteMetastoreAssignment` | client.ts:182 | B, D | -| `Client.getCurrentMetastoreAssignment` | client.ts:216 | 12.1 | -| `Client.getMetastore` | client.ts:241 | 12.1, C | -| `Client.getMetastoreSummary` | client.ts:269 | 5.8, 12.1 | -| `Client.listMetastores` | client.ts:305 | — | -| `Client.updateMetastore` | client.ts:360 | C | -| `Client.updateMetastoreAssignment` | client.ts:390 | B | -| `${req.id ?? ''}` URL substitution | client.ts:155, 245, 364 | C | -| `${req.workspaceId ?? ''}` URL substitution | client.ts:126, 186, 394 | B | -| `Host is required.` bare Error | client.ts:72 | E | +| `CreateMetastoreRequest` | model.ts:218 | 10.2, 11.3 | +| `CreateMetastoreRequest.name` | model.ts:220 | 9.1, 10.5 | +| `CreateMetastoreRequest.storageRoot` | model.ts:222 | 5.2 | +| `CreateMetastoreRequest.defaultDataAccessConfigId` | model.ts:224 | 5.4, 13.3 | +| `CreateMetastoreRequest.storageRootCredentialId` | model.ts:226 | 13.4 | +| `CreateMetastoreRequest.owner` | model.ts:234 | 1.5, 13.7 | +| `CreateMetastoreRequest.region` | model.ts:238 | 1.6, 5.6 | +| `CreateMetastoreRequest.metastoreId` (read-only) | model.ts:240 | 11.3, 13.1, 15.1 | +| `CreateMetastoreRequest.createdAt` (read-only) | model.ts:242 | 11.3, 13.5 | +| `CreateMetastoreRequest.createdBy` (read-only) | model.ts:244 | 11.3, 13.7 | +| `CreateMetastoreRequest.updatedAt` (read-only) | model.ts:246 | 11.3, 13.5 | +| `CreateMetastoreRequest.updatedBy` (read-only) | model.ts:248 | 11.3, 13.7 | +| `CreateMetastoreRequest.storageRootCredentialName` | model.ts:250 | 11.3 | +| `CreateMetastoreRequest.cloud` | model.ts:252 | 1.4, 5.5 | +| `CreateMetastoreRequest.globalMetastoreId` (read-only) | model.ts:254 | 5.3, 11.3, 13.6 | +| `CreateMetastoreRequest.externalAccessEnabled` | model.ts:256 | 3.1 (doc) | +| `CreateMetastoreAssignmentRequest` | model.ts:202 | 10.3 | +| `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | 13.2, F | +| `CreateMetastoreAssignmentRequest.metastoreId` | model.ts:206 | 13.1 | +| `CreateMetastoreAssignmentRequest.defaultCatalogName` | model.ts:212 | — | +| `DeleteMetastoreRequest` | model.ts:269 | — | +| `DeleteMetastoreRequest.id` | model.ts:271 | 1.1, 4.1, 9.2, 10.4 | +| `DeleteMetastoreRequest.force` | model.ts:273 | 1.3 | +| `DeleteMetastoreAssignmentRequest` | model.ts:259 | 10.3 | +| `DeleteMetastoreAssignmentRequest.workspaceId` | model.ts:260 | 13.2 | +| `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | 13.1, D | +| `GetCurrentMetastoreAssignmentRequest` | model.ts:283 | — | +| `GetMetastoreRequest` | model.ts:285 | — | +| `GetMetastoreRequest.id` | model.ts:287 | 1.1, 4.1, 9.2, 10.4 | +| `GetMetastoreSummaryRequest` | model.ts:291 | — | +| `GetMetastoreSummaryRequest_Response` | model.ts:294 | 5.7, 10.1, 11.4 | +| `ListMetastoresRequest` | model.ts:335 | — | +| `ListMetastoresRequest.maxResults` | model.ts:345 | — | +| `ListMetastoresRequest.pageToken` | model.ts:347 | — | +| `ListMetastoresRequest_Response.metastores` | model.ts:353 | 8.1 (positive) | +| `ListMetastoresRequest_Response.nextPageToken` | model.ts:358 | — | +| `MetastoreAssignment` | model.ts:361 | 1.2, 7.2, 10.3 | +| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.2, 13.2, F | +| `MetastoreAssignment.metastoreId` | model.ts:365 | 13.1, 15.2 | +| `MetastoreAssignment.defaultCatalogName` | model.ts:370 | — | +| `MetastoreInfo` | model.ts:373 | 5.1, 7.1, 10.2 | +| `MetastoreInfo.metastoreId` | model.ts:395 | 13.1, 15.1 | +| `MetastoreInfo.globalMetastoreId` | model.ts:409 | 5.3, 13.6 | +| `UpdateMetastoreRequest` | model.ts:471 | 10.2, 11.1, 11.3 | +| `UpdateMetastoreRequest.id` | model.ts:473 | 1.1, 4.1, 11.1, 11.2 | +| `UpdateMetastoreRequest.newName` | model.ts:475 | 10.6, 11.1 | +| `UpdateMetastoreRequest.name` | model.ts:477 | 10.6, 11.1 | +| `UpdateMetastoreRequest.metastoreId` | model.ts:497 | 11.1, 11.2 | +| `UpdateMetastoreAssignmentRequest` | model.ts:455 | 10.3 | +| `UpdateMetastoreAssignmentRequest.workspaceId` | model.ts:457 | 13.2 | +| `Client.createMetastore` | client.ts:437 | — | +| `Client.createMetastoreAssignment` | client.ts:467 | — | +| `Client.deleteMetastore` | client.ts:499 | C | +| `Client.deleteMetastoreAssignment` | client.ts:533 | B, D | +| `Client.getCurrentMetastoreAssignment` | client.ts:567 | 12.1 | +| `Client.getMetastore` | client.ts:592 | 12.1, C | +| `Client.getMetastoreSummary` | client.ts:620 | 5.8, 12.1 | +| `Client.listMetastores` | client.ts:656 | — | +| `Client.updateMetastore` | client.ts:714 | C | +| `Client.updateMetastoreAssignment` | client.ts:744 | B | +| `${req.id ?? ''}` URL substitution | client.ts:503, 596, 718 | C | +| `${req.workspaceId ?? ''}` URL substitution | client.ts:471, 537, 748 | B | +| `Host is required.` bare Error | client.ts:109 | E | | `flattenQueryParams` (unused export) | utils.ts:123 | A | --- ## Recommended priority order -1. **Disambiguate the four name/id-like fields on `UpdateMetastore`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.6, §1.1) -2. **Strip read-only fields from `CreateMetastore` / `UpdateMetastore`.** (§11.3, §10.2) -3. **Decide whether the `GetMetastoreSummary` response should alias `MetastoreInfo` or expose a genuine subset.** (§5.7, §10.1) +1. **Disambiguate the four name/id-like fields on `UpdateMetastoreRequest`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.6, §1.1) +2. **Strip read-only fields from `CreateMetastoreRequest` / `UpdateMetastoreRequest`.** (§11.3, §10.2) +3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.7, §10.1) 4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.8, §12.1) 5. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §10.4) 6. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) 7. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match common conventions. (§13.5) 8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) + +--- + +## Fixed + +- 14.1 `AccountsCreateMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.2 `AccountsCreateMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.3 `AccountsCreateMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.4 `AccountsCreateMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.5 `AccountsDeleteMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.6 `AccountsDeleteMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.7 `AccountsDeleteMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.8 `AccountsDeleteMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.9 `AccountsGetMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.10 `AccountsGetMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.11 `AccountsGetMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.12 `AccountsGetMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.13 `AccountsListMetastoresPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.14 `AccountsListMetastoresPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.15 `AccountsListWorkspaceIdsForMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.16 `AccountsListWorkspaceIdsForMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.17 `AccountsUpdateMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.18 `AccountsUpdateMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.19 `AccountsUpdateMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. +- 14.20 `AccountsUpdateMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index cbb8742b..592293f2 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,13 +8,13 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 59 +**Total weird names flagged:** 66 ## Summary | Severity | Count | | --- | --- | -| High | 20 | -| Medium | 24 | +| High | 22 | +| Medium | 29 | | Low | 12 | | Observation | 3 | @@ -47,7 +47,7 @@ is the Unity-Catalog-scoped successor. one type, and the docstring says so explicitly ("For activities…For comments…"). - **Category:** 6 (misleading: enum members are RPC verbs not actions), - 17 (mixed-domain enum), 18 (long enum values). + 17 (mixed-domain enum). - **Suggested name:** Split into two enums: `TransitionRequestAction` ( `Approve | Reject | Cancel`) and `CommentAction` (`Edit | Delete`). Or shorten to verbs only: `ActivityAction.Approve | Reject | Cancel | Edit @@ -67,7 +67,7 @@ is the Unity-Catalog-scoped successor. `SYSTEM_TRANSITION` is a transition performed by the system, mixing actor + action where every other value is just an action. - **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action - verbs), 18 (long enum values). + verbs). - **Suggested name:** Pick one pattern. Either all past-tense (`TransitionApplied`, `TransitionRequested`, `RequestCancelled`, `RequestApproved`, `RequestRejected`, `CommentPosted`, @@ -85,8 +85,8 @@ is the Unity-Catalog-scoped successor. Also, the doc-comment for `CAN_EDIT` says it is `reserved 1; // IS_OWNER = 1; was DEPRECATED` — that is a Protobuf reservation comment leaking into TypeScript public docs. -- **Category:** 6 (misleading: implies parallel constants exist), 18 - (long values), 14 (proto-style leakage in JSDoc). +- **Category:** 6 (misleading: implies parallel constants exist), 14 + (proto-style leakage in JSDoc). - **Suggested name:** Leave values as-is for wire compatibility, but strip the protobuf "reserved 1" comment from the public doc. - **Rationale:** The proto comment serves no purpose to TS users and @@ -112,8 +112,8 @@ is the Unity-Catalog-scoped successor. must pick one and the docs do not say which. Same pattern for `TRANSITION_REQUEST_CREATED` vs three `TRANSITION_REQUEST_TO_{STAGING,PRODUCTION,ARCHIVED}_CREATED`. -- **Category:** 17 (inconsistent action verbs), 18 (long enum values), - 12 (duplicate concepts within one enum). +- **Category:** 17 (inconsistent action verbs), 12 (duplicate concepts + within one enum). - **Suggested name:** Either keep the granular ones and drop the generic, or document the relationship. - **Rationale:** Overlap creates "two ways to express one intent" — a @@ -142,8 +142,8 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `Comment` — or fold into `Activity` per #7. - **Rationale:** `Object` adds nothing; the type is already a TS object. -### 9. `GetRegisteredModelDatabricks`, `RegisteredModelDatabricks`, - `TransitionModelVersionStageDatabricks`, `ModelVersionDatabricks` — +### 9. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, + `TransitionModelVersionStageDatabricksRequest`, `ModelVersionDatabricks` — `model.ts:542, 549, 690, 758, 981, 1005` - **Why weird:** `Databricks` as a type suffix. The whole SDK is the Databricks SDK; everything is "Databricks". The suffix is used to @@ -160,60 +160,66 @@ is the Unity-Catalog-scoped successor. (then split by capability). The current "shadow type per extension" is a generator artefact, not a user-friendly API. -### 10. `TransitionModelVersionStageDatabricks` — `model.ts:981` -- **Why weird:** Five-word PascalCase identifier with awkward word +### 10. `TransitionModelVersionStageDatabricksRequest` — `model.ts:981` +- **Why weird:** Six-word PascalCase identifier with awkward word order. Reads as "transition[verb] - model-version-stage[object]-databricks[suffix]". For a TS type, it - should be a noun. Also functions identically to the + model-version-stage[object]-databricks[suffix]-request[suffix]". For a + TS type, it should be a noun. Also functions identically to the `ApproveTransitionRequest` API (transitions a model version's stage) but uses a totally different naming scheme. - **Category:** 6 (misleading verb-as-noun), 7 (overly verbose), 17 (inconsistent action verbs). -- **Suggested name:** `WorkspaceTransitionStageRequest` (request DTO) or - fold into `ApproveTransitionRequest` (the operations are very close). +- **Suggested name:** `WorkspaceTransitionStageRequest` or fold into + `ApproveTransitionRequest` (the operations are very close). - **Rationale:** Right now the SDK has `approveTransitionRequest` and `transitionModelVersionStageDatabricks` as sibling client methods performing similar workspace operations; the asymmetric names obscure this. -### 11. `GetRegisteredModelDatabricks` request DTO — `model.ts:542` +### 11. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:542` - **Why weird:** Verb-phrase request type name (`GetX`) is OK if used - consistently, but `GetRegisteredModelDatabricks` is the only method - the SDK exposes to fetch a registered model — there is no plain - `GetRegisteredModel`. The `Databricks` suffix dangles in the public - API for a feature that has no non-Databricks counterpart visible. + consistently, but `GetRegisteredModelDatabricksRequest` is the only + method the SDK exposes to fetch a registered model — there is no plain + `GetRegisteredModelRequest`. The `Databricks` infix dangles in the + public API for a feature that has no non-Databricks counterpart + visible. - **Category:** 6 (misleading), 8 (redundant suffix). - **Suggested name:** `GetRegisteredModelRequest` (drop `Databricks`). - **Rationale:** No need for the disambiguation suffix when there's no sibling. ### 12. `client.listTransitionsRequest` method vs `ListTransitionRequest` - request type — `client.ts:507, model.ts:645` + request type — `client.ts:513, model.ts:645` - **Why weird:** The method is `listTransitionsRequest` (plural "Transitions") but the request type is `ListTransitionRequest` (singular). The doc comment says "Gets a list of all open stage transition requests" so it's listing *requests* (plural). The method name should be `listTransitionRequests` (plural "Requests"), and the request type should be `ListTransitionRequestsRequest`. Right now - none of the four name parts agree. + none of the four name parts agree. Note: many sibling request DTOs in + this file have been given the `Request` suffix (e.g. + `CreateCommentRequest`, `DeleteRegistryWebhookRequest`, + `RenameRegisteredModelRequest`), but `ListTransitionRequest` was left + as the bare verb-phrase, deepening the inconsistency. - **Category:** 9 (singular/plural mismatch), 6 (misleading), 20 (type suffix tautology if renamed to `ListTransitionRequestsRequest`). - **Suggested name:** Method `listTransitionRequests`; request type - `ListTransitionRequests`; response type + `ListTransitionRequestsRequest`; response type `ListTransitionRequestsResponse`. - **Rationale:** The method name in JS conventions describes the collection being listed; here that's "transition requests", plural. ### 13. `RegistryWebhook` vs `Webhook` — `model.ts:787` - **Why weird:** Type is `RegistryWebhook` but client methods, paths, - and request types alternate: `CreateRegistryWebhook`, - `ListRegistryWebhooks`, `UpdateRegistryWebhook`, - `DeleteRegistryWebhook`, `TestRegistryWebhook`. Once you're inside the - modelregistry package, every webhook *is* a registry webhook — the - prefix is redundant. + and request types alternate: `CreateRegistryWebhookRequest`, + `ListRegistryWebhooksRequest`, `UpdateRegistryWebhookRequest`, + `DeleteRegistryWebhookRequest`, `TestRegistryWebhookRequest`. Once + you're inside the modelregistry package, every webhook *is* a registry + webhook — the prefix is redundant. - **Category:** 8 (redundant suffix/prefix), 7 (overly verbose). -- **Suggested name:** `Webhook`, `CreateWebhook`, `ListWebhooks`, - `UpdateWebhook`, `DeleteWebhook`, `TestWebhook`. +- **Suggested name:** `Webhook`, `CreateWebhookRequest`, + `ListWebhooksRequest`, `UpdateWebhookRequest`, `DeleteWebhookRequest`, + `TestWebhookRequest`. - **Rationale:** Package name already establishes the registry context. ### 14. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` @@ -243,7 +249,7 @@ is the Unity-Catalog-scoped successor. feature store. ### 16. `userId: string` field documented as username — `model.ts:154, - 231, 668, 700, 766, 1018` + 231, 668, 700, 766, 1019` - **Why weird:** Field is named `userId` but every doc-comment for it reads "The username of the user that created the object." So the field is a *username* (human-readable string), not a user ID @@ -257,8 +263,8 @@ is the Unity-Catalog-scoped successor. ### 17. `stage: string` field on `ApproveTransitionRequest`, `CreateTransitionRequest`, `DeleteTransitionRequest`, - `RejectTransitionRequest`, `TransitionModelVersionStageDatabricks` — - `model.ts:209, 396, 483, 847, 997` + `RejectTransitionRequest`, `TransitionModelVersionStageDatabricksRequest` + — `model.ts:209, 396, 483, 847, 997` - **Why weird:** Field is `stage: string` but valid values are enumerated in the docstring: `None`, `Staging`, `Production`, `Archived`. There is no `Stage` enum exported anywhere in the model, @@ -293,20 +299,61 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Same as #17. ### 20. `Databricks` as a suffix is overused -- **Why weird:** 6 distinct type names end in `Databricks` (see #9). - Each one is a workspace-specific extension. The `Databricks` suffix - appearing inside the *Databricks SDK* is tautological. +- **Why weird:** Distinct type names still end in `Databricks` (see #9): + `RegisteredModelDatabricks`, `ModelVersionDatabricks`. Two more retain + `Databricks` as an infix inside the new `Request` suffix + (`GetRegisteredModelDatabricksRequest`, + `TransitionModelVersionStageDatabricksRequest`). Each one is a + workspace-specific extension. The `Databricks` token appearing inside + the *Databricks SDK* is tautological. - **Category:** 8 (redundant suffix), 20 (type-suffix tautology). - **Suggested name:** See #9. - **Rationale:** See #9. +### 21. `getRegisteredModelDatabricks` client method — `client.ts:416` +- **Why weird:** Method name carries `Databricks` mid-position (between + the noun `RegisteredModel` and any conceptual suffix). The whole SDK + is the Databricks SDK; embedding `Databricks` inside a method name is + a proto/backend-architectural leak (the upstream proto distinguishes + Databricks-flavoured RPCs from upstream-MLflow ones, but TS callers + never see the non-Databricks variant). Compare to the sibling + `getRegisteredModel`-shaped method that does *not* exist here — the + `Databricks` infix dangles without a partner. Doc comment even reads + "This is a `` workspace version of the [MLflow endpoint]", + acknowledging the leak. +- **Category:** proto-architectural-leak (`Databricks` mid-position), 8 + (redundant infix), 14 (proto-style leakage into surface API). +- **Suggested name:** `getWorkspaceRegisteredModel` (scope-prefixed) or + fold into `getRegisteredModel` and gate Databricks-only fields via + capability. As a minimal change, drop the `Databricks` token: + `getRegisteredModel`. +- **Rationale:** The infix encodes a proto-level distinction that has + no analogue in this TS surface; remove it. + +### 22. `transitionModelVersionStageDatabricks` client method — + `client.ts:615` +- **Why weird:** Same `Databricks` mid-position leak as #21. The token + sits between `Stage` and the implicit method suffix, marking the + method as the workspace-extension variant of an upstream MLflow RPC. + Method-name length (six words, 38 chars) is also a symptom: the verb + `transition` + object `ModelVersionStage` + scope `Databricks` are + all glued together. Doc comment repeats the proto leak: "This is a + `` workspace version of the MLflow endpoint." +- **Category:** proto-architectural-leak (`Databricks` mid-position), 7 + (overly verbose), 14 (proto-style leakage into surface API). +- **Suggested name:** `transitionModelVersionStage` (drop the infix) or + fold into `approveTransitionRequest`-style verbs since the operations + overlap (see #10). +- **Rationale:** Same as #21 — the infix encodes a generator-side + distinction that callers do not need. + ## Medium severity -### 21. `comment: string` field overloaded across types — `model.ts:213, 234, 276, 398, 487, 849, 1001, 1022, 1062` +### 23. `comment: string` field overloaded across types — `model.ts:213, 234, 276, 398, 487, 849, 1001, 1022, 1062` - **Why weird:** Same field name (`comment`) appears with three different meanings: (a) on `Activity` it is "user-provided comment - associated with the activity"; (b) on `CreateComment` it is "user- - provided comment on the action" (i.e. the *new* comment being + associated with the activity"; (b) on `CreateCommentRequest` it is + "user-provided comment on the action" (i.e. the *new* comment being created); (c) on `ApproveTransitionRequest`/`CreateTransitionRequest` it is the *justification* for the action. Same name, different semantics. @@ -317,7 +364,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** A grep for `comment` in a calling project will return 9 unrelated meanings. -### 22. `creator: string` field on `DeleteTransitionRequest` — `model.ts:485` +### 24. `creator: string` field on `DeleteTransitionRequest` — `model.ts:485` - **Why weird:** Field doc says "Username of the user who created this request." So this is a username, not a user object. Same anti-pattern as #16 but with a different field name. The same concept is named @@ -327,14 +374,15 @@ is the Unity-Catalog-scoped successor. `userName` per #16). - **Rationale:** Two different field names for the same concept. -### 23. `id: string` field — `model.ts:189, 266, 408, 461, 772, 789, 967, 1054, 1060` +### 25. `id: string` field — `model.ts:189, 266, 409, 461, 772, 789, 967, 1054, 1060` - **Why weird:** Bare `id` appears on `Activity`, `CommentObject`, - `DeleteComment`, `DeleteRegistryWebhook`, `RegisteredModelDatabricks`, - `RegistryWebhook`, `TestRegistryWebhook`, `TransitionRequest`, - `UpdateComment`. Same name across nine types, but each `id` belongs to - a different domain (activity ID, comment ID, webhook ID, registered - model ID). Doc-comments call it variously "Unique identifier for the - object", "Unique identifier of an activity", "Webhook ID". + `DeleteCommentRequest`, `DeleteRegistryWebhookRequest`, + `RegisteredModelDatabricks`, `RegistryWebhook`, + `TestRegistryWebhookRequest`, `TransitionRequest`, + `UpdateCommentRequest`. Same name across nine types, but each `id` + belongs to a different domain (activity ID, comment ID, webhook ID, + registered model ID). Doc-comments call it variously "Unique identifier + for the object", "Unique identifier of an activity", "Webhook ID". - **Category:** 19 (underspecified ID), 15 (generic field name). - **Suggested name:** `activityId`, `commentId`, `webhookId`, `registeredModelId`, or scope by parent type. @@ -342,7 +390,7 @@ is the Unity-Catalog-scoped successor. remember which kind of ID this DTO wants. The wire field can stay `id`; the TS field should be specific. -### 24. `name: string` field overloaded — many — `model.ts:195, 271, 287, 314, 382, 417, 426, 438, 447, 468, 519, 531, 543, 583, 600, 647, 660, 691, 740, 759, 832, 859, 925, 946, 982, 1072, 1087, 1100` +### 26. `name: string` field overloaded — many — `model.ts:195, 272, 287, 314, 382, 417, 427, 439, 447, 469, 503, 519, 531, 543, 583, 600, 647, 660, 691, 740, 759, 832, 859, 925, 946, 982, 1072, 1087, 1100` - **Why weird:** `name` appears on ~28 request/response types meaning "name of the registered model". Doc-comments mostly say "Name of the model" or "Registered model unique name identifier." Always the @@ -355,7 +403,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Disambiguates request structures from entity structures. -### 25. `version: string` field overloaded — `model.ts:197, 273, 419, 428, 470, 521, 533, 649, 662, 693, 834, 927, 984, 1074` +### 27. `version: string` field overloaded — `model.ts:197, 274, 419, 429, 471, 521, 533, 649, 662, 693, 834, 927, 984, 1074` - **Why weird:** Stored as a string but docs say "Model version number" (a number). Field is sometimes called `version`, sometimes `currentStage` is the contextual sibling — but never typed as a @@ -367,7 +415,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** `version` is too generic a noun for a primary key in a package. -### 26. `runId: string` field — `model.ts:294, 679, 707` +### 28. `runId: string` field — `model.ts:294, 679, 707` - **Why weird:** `runId` is the MLflow tracking run that produced the model. The package never explains this; without prior MLflow knowledge `runId` is opaque. @@ -376,18 +424,19 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Disambiguates from any other "run" concept in the SDK (jobs runs, etc.). -### 27. `jobId: string` on `JobSpec` — `model.ts:565` +### 29. `jobId: string` on `JobSpec` — `model.ts:565` - **Why weird:** Doc says "ID of the job that the webhook runs." This is a Databricks Jobs job ID. `jobId` is fine but lives in a model that - duplicates the documentation in the comment for `CreateRegistryWebhook.jobSpec` - (model.ts:371 says "ID of the job that the webhook runs.") even though - `jobSpec` is a *struct* not an ID. + duplicates the documentation in the comment for + `CreateRegistryWebhookRequest.jobSpec` (model.ts:371 says "ID of the + job that the webhook runs.") even though `jobSpec` is a *struct* not + an ID. - **Category:** 6 (misleading docstring). - **Suggested name:** Field name OK; fix doc-comment on - `CreateRegistryWebhook.jobSpec`. + `CreateRegistryWebhookRequest.jobSpec`. - **Rationale:** Doc-comment mismatch is a generator bug. -### 28. `accessToken: string` on `JobSpec` — `model.ts:569` +### 30. `accessToken: string` on `JobSpec` — `model.ts:569` - **Why weird:** Doc says "The personal access token used to authorize webhook's job runs." Shipping a PAT in a webhook config is a security red flag; field name should signal that. Compare to `secret` on @@ -399,7 +448,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Aligns with other Databricks SDK fields named `token` / `pat`. -### 29. `enableSslVerification: boolean` — `model.ts:556` +### 31. `enableSslVerification: boolean` — `model.ts:556` - **Why weird:** Doc-comment is 4 lines describing why you should never disable this. The boolean has a default (true) per the docs but the field is `boolean | undefined`. So `undefined` and `true` mean the @@ -408,7 +457,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; add `@default true` JSDoc tag. - **Rationale:** Make default-truthy fields clearer. -### 30. `authorization: string` — `model.ts:560` +### 32. `authorization: string` — `model.ts:560` - **Why weird:** "Value of the authorization header" — should probably be named `authorizationHeader` (since `authorization` looks like an abstract noun, not the actual header value). @@ -417,8 +466,8 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Clarifies the field stores the wire-format header value. -### 31. `event: RegistryWebhookEvent | undefined` (singular) on - `TestRegistryWebhook` — `model.ts:969` +### 33. `event: RegistryWebhookEvent | undefined` (singular) on + `TestRegistryWebhookRequest` — `model.ts:969` - **Why weird:** Singular `event` while every other type uses `events: RegistryWebhookEvent[]`. Inconsistent. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent across @@ -428,8 +477,8 @@ is the Unity-Catalog-scoped successor. with `event` and document the asymmetry. - **Rationale:** Asymmetry across sibling types causes refactor errors. -### 32. `modelName: string` field on `CreateRegistryWebhook`, - `ListRegistryWebhooks`, `RegistryWebhook` — `model.ts:329, 601, 827` +### 34. `modelName: string` field on `CreateRegistryWebhookRequest`, + `ListRegistryWebhooksRequest`, `RegistryWebhook` — `model.ts:329, 601, 827` - **Why weird:** This is the *registered model* name. Elsewhere in the same model the same concept is called `name` (on requests scoped to a registered model). Sometimes `modelName` (on webhook types) and @@ -439,7 +488,7 @@ is the Unity-Catalog-scoped successor. with package context — but consistent. - **Rationale:** Same concept, two names. -### 33. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, +### 35. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, 602-630, 791-815, 1102-1127` - **Why weird:** The 25-line "Events that can trigger a registry webhook" doc block is copy-pasted at least 4 times across types @@ -450,7 +499,7 @@ is the Unity-Catalog-scoped successor. signature plus a one-line description should remain. - **Rationale:** Quality-of-life for consumers reading JSDoc. -### 34. `tags?: ModelVersionTag[] | undefined` and +### 36. `tags?: ModelVersionTag[] | undefined` and `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, 719, 755, 776` - **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, @@ -461,7 +510,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Single `Tag` type with `{ key, value }`. - **Rationale:** Identical structure should have identical type. -### 35. `availableActions: ActivityAction[]` doc — `model.ts:187` +### 37. `availableActions: ActivityAction[]` doc — `model.ts:187` - **Why weird:** Field comment "Array of actions on the activity allowed for the current viewer." So `availableActions` actually means "allowed actions for current viewer", which differs from "available @@ -470,7 +519,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `allowedActions` or `permittedActions`. - **Rationale:** Encodes the viewer-permission semantics. -### 36. `systemComment: string | undefined` — `model.ts:185, 262, 1050` +### 38. `systemComment: string | undefined` — `model.ts:185, 262, 1050` - **Why weird:** The same paragraph-long doc-comment is pasted on three identical fields across three identical types. "Comment made by system, for example explaining an activity of type @@ -480,7 +529,7 @@ is the Unity-Catalog-scoped successor. consolidation via #7. - **Rationale:** Same as #7. -### 37. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` +### 39. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` - **Why weird:** Typed as `Activity[]` but the field is documented as "Open requests for this `model_versions`" — they are transition *requests* (not arbitrary activities). The reason is the @@ -490,16 +539,16 @@ is the Unity-Catalog-scoped successor. (post-rename per #7). - **Rationale:** Restores the intent. -### 38. `requests: Activity[]` on list-transition-requests response — +### 40. `requests: Activity[]` on list-transition-requests response — `model.ts:655` - **Why weird:** Stored as `Activity[]` but the response is documented as "Array of open transition requests." - **Category:** 6 (misleading type), 15 (generic field name). - **Suggested name:** `transitionRequests: TransitionRequest[]`. -- **Rationale:** Same as #37 — type contradicts domain because of the +- **Rationale:** Same as #39 — type contradicts domain because of the identical-shape problem (#7). -### 39. `request: TransitionRequest` on create-transition-request response — +### 41. `request: TransitionRequest` on create-transition-request response — `model.ts:404` - **Why weird:** Field `request` on a response is contradictory — a response holds a "request"? In context, the wrapped object is the @@ -510,7 +559,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Removes the "request inside a response" cognitive stumble. -### 40. `registeredModelDatabricks: RegisteredModelDatabricks` — +### 42. `registeredModelDatabricks: RegisteredModelDatabricks` — `model.ts:549` - **Why weird:** Field name *is* the type name verbatim. The `Databricks` suffix problem (#9) cascades into the field name. @@ -520,18 +569,18 @@ is the Unity-Catalog-scoped successor. directly without a wrapper. - **Rationale:** Reduces verbosity by removing the wrapper. -### 41. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` -- **Why weird:** Same as #40 for `ModelVersionDatabricks`. +### 43. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` +- **Why weird:** Same as #42 for `ModelVersionDatabricks`. - **Category:** 20. - **Suggested name:** `modelVersion: ModelVersion`. - **Rationale:** Same. -### 42. `getLatestVersions` / `GetLatestVersions` — `client.ts:908`, +### 44. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, `model.ts:501` - **Why weird:** The method returns *one* version per stage, not "the latest version" globally. The name reads as "give me the latest versions" (plural overall) but the meaning is "give me the latest one - for each stage". The docstring on the method (`client.ts:907`) says + for each stage". The docstring on the method (`client.ts:916`) says "Gets the latest version of a registered model" (singular) — that's *wrong*; the actual response returns a list keyed by stage. - **Category:** 6 (misleading), 9 (singular/plural confusion). @@ -539,16 +588,16 @@ is the Unity-Catalog-scoped successor. `getLatestVersionsByStage`. - **Rationale:** Conveys the per-stage semantics. -### 43. `latestVersions: ModelVersion[]` on `RegisteredModel`, +### 45. `latestVersions: ModelVersion[]` on `RegisteredModel`, `RegisteredModelDatabricks` — `model.ts:753, 770` - **Why weird:** Plural array but the doc says "Collection of latest - model versions for each stage". Same ambiguity as #42. + model versions for each stage". Same ambiguity as #44. - **Category:** 6 (misleading), 15 (generic). - **Suggested name:** `latestVersionsByStage` (and consider returning a map keyed by stage name). - **Rationale:** Same. -### 44. `featureTableId`, `featureTableName`, `featureName` on +### 46. `featureTableId`, `featureTableName`, `featureName` on `LinkedFeature` — `model.ts:575, 577, 579` - **Why weird:** Both `featureTableId` and `featureTableName` are exposed — primary key duplication. Doc-comments are bare ("Feature @@ -559,7 +608,7 @@ is the Unity-Catalog-scoped successor. relationship. - **Rationale:** Without docs, callers won't know which to populate. -### 45. `body: string` on test-registry-webhook response — `model.ts:977` +### 47. `body: string` on test-registry-webhook response — `model.ts:977` - **Why weird:** Field `body` typed as `string`. Webhook test results could return any payload. `body` is too generic; could be `responseBody`. @@ -567,7 +616,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `responseBody`. - **Rationale:** Clearer pair with `statusCode`. -### 46. `statusCode: number` on test-registry-webhook response — +### 48. `statusCode: number` on test-registry-webhook response — `model.ts:975` - **Why weird:** Could be `httpStatusCode` for clarity (it's the HTTP status the test got back). @@ -575,7 +624,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `httpStatusCode`. - **Rationale:** Matches typical Web API vocabulary. -### 47. `archiveExistingVersions: boolean` — `model.ts:211, 999` +### 49. `archiveExistingVersions: boolean` — `model.ts:211, 999` - **Why weird:** Field documented "Specifies whether to archive all current model versions in the target stage." The word "current" appears in the doc but not the field; the boolean reads as "archive @@ -584,8 +633,8 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `archiveExistingVersionsInTargetStage`. - **Rationale:** Captures the location semantics. -### 48. `description: string` overloaded — `model.ts:302, 318, 358, 672, - 703, 748, 768, 822, 1077, 1090, 1129` +### 50. `description: string` overloaded — `model.ts:303, 318, 358, 672, + 703, 748, 768, 822, 1077, 1090, 1130` - **Why weird:** Same field on 11 types, each meaning slightly different things (registered-model description, model-version description, webhook description, registered-model-databricks description). Same @@ -595,7 +644,7 @@ is the Unity-Catalog-scoped successor. clear; flag for consistency. - **Rationale:** Common across SDK; low cost to leave alone. -### 49. `secret: string` on `HttpUrlSpec` — `model.ts:558` +### 51. `secret: string` on `HttpUrlSpec` — `model.ts:558` - **Why weird:** Bare `secret` is generic; doc says it's the "Shared secret required for HMAC encoding payload." - **Category:** 1 (vague), 15 (generic). @@ -604,8 +653,8 @@ is the Unity-Catalog-scoped successor. ## Low severity -### 50. `creationTimestamp: number` — `model.ts:152, 229, 664, 696, 742, - 761, 818, 1017` +### 52. `creationTimestamp: number` — `model.ts:152, 229, 664, 696, 742, + 762, 818, 1017` - **Why weird:** Field is repeated across types with identical `Unix timestamp in milliseconds` doc. Naming OK but could be `createdAt` to match modern JS convention. @@ -613,14 +662,14 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `createdAt`. - **Rationale:** Aligns with JS conventions; flag as observation only. -### 51. `lastUpdatedTimestamp: number` — `model.ts:159, 236, 666, 698, 744, - 763, 820, 1024` -- **Why weird:** Same as #50; `updatedAt` is more idiomatic. +### 53. `lastUpdatedTimestamp: number` — `model.ts:159, 236, 666, 698, 744, + 764, 820, 1024` +- **Why weird:** Same as #52; `updatedAt` is more idiomatic. - **Category:** 14. - **Suggested name:** `updatedAt`. -- **Rationale:** Same as #50. +- **Rationale:** Same as #52. -### 52. `statusMessage: string` — `model.ts:683, 710` +### 54. `statusMessage: string` — `model.ts:683, 710` - **Why weird:** Field name fine but doc says it's only set "if it is pending or failed", so the field is conditionally meaningful — not in the type signature. @@ -628,8 +677,8 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; document the conditional. - **Rationale:** Low priority. -### 53. `source: string` on `ModelVersion`, `ModelVersionDatabricks`, - `CreateModelVersion` — `model.ts:289, 674, 704` +### 55. `source: string` on `ModelVersion`, `ModelVersionDatabricks`, + `CreateModelVersionRequest` — `model.ts:289, 674, 705` - **Why weird:** "URI indicating the location of the source model artifacts." Just `source` is vague; `sourceUri` or `artifactUri` would be clearer. @@ -637,7 +686,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `sourceUri`. - **Rationale:** Companion field is `runLink` (already specific). -### 54. `runLink: string` — `model.ts:301, 687, 720` +### 56. `runLink: string` — `model.ts:301, 687, 721` - **Why weird:** "MLflow run link - this is the exact link of the run". `runLink` is OK but `runUrl` would be more idiomatic for a URL. - **Category:** 14 (Java-style "link" vs JS "url"). @@ -645,7 +694,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** "Link" is HTML/UI vocabulary; URL is what's actually stored. -### 55. `key: string` and `value: string` on `ModelVersionTag`, +### 57. `key: string` and `value: string` on `ModelVersionTag`, `RegisteredModelTag` — `model.ts:733, 735, 782, 784` - **Why weird:** `key`/`value` are extremely generic and reused across many SDK packages. Not really wrong, just observation. @@ -654,16 +703,16 @@ is the Unity-Catalog-scoped successor. preferred). - **Rationale:** Trade-off vs verbosity. Low priority. -### 56. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:586, 593, - 633, 642, 877, 893, 905, 921` +### 58. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, + 593, 633, 634, 642, 877, 886, 894, 905, 913, 921` - **Why weird:** Consistent across the package — good. Noted for completeness. - **Category:** N/A (consistent). - **Suggested name:** No change. - **Rationale:** Observation. -### 57. `orderBy: string[]` on `SearchModelVersions`, - `SearchRegisteredModels` — `model.ts:884, 911` +### 59. `orderBy: string[]` on `SearchModelVersionsRequest`, + `SearchRegisteredModelsRequest` — `model.ts:884, 911` - **Why weird:** Stringly-typed sort spec; doc says values are like `"name DESC"` or `"version ASC"`. Could be a typed `Sort` struct, but string is the standard SQL-like sort spec. @@ -671,24 +720,25 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; flag the stringly-typed pattern. - **Rationale:** Matches REST API conventions; low cost. -### 58. `filter: string` on `SearchModelVersions`, - `SearchRegisteredModels` — `model.ts:875, 903` -- **Why weird:** Stringly-typed search filter (SQL-like). Same as #57. +### 60. `filter: string` on `SearchModelVersionsRequest`, + `SearchRegisteredModelsRequest` — `model.ts:875, 903` +- **Why weird:** Stringly-typed search filter (SQL-like). Same as #59. - **Category:** 16. - **Suggested name:** No change; could be `filterExpression`. - **Rationale:** REST convention. -### 59. `newName: string` on `RenameRegisteredModel` — `model.ts:862` +### 61. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` - **Why weird:** Field doc says "If provided, updates the name for this - `registered_model`." Slightly confusing because `RenameRegisteredModel` - is *the* rename operation — "if provided" implies optional, but rename - without a new name is meaningless. + `registered_model`." Slightly confusing because + `RenameRegisteredModelRequest` is *the* rename operation — "if + provided" implies optional, but rename without a new name is + meaningless. - **Category:** 6 (misleading semantics). - **Suggested name:** Make it required (drop `?`), or document that omission is a no-op. - **Rationale:** Optional-but-required-in-practice fields confuse users. -### 60. `name: string` on `RenameRegisteredModel` — `model.ts:859` +### 62. `name: string` on `RenameRegisteredModelRequest` — `model.ts:860` - **Why weird:** Field doc "Registered model unique name identifier." - duplicates the type name semantics. Could be `currentName` to pair with `newName` for clarity. @@ -696,7 +746,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `currentName` + `newName`. - **Rationale:** Symmetry improves readability of rename payloads. -### 61. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhook` — +### 63. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhookRequest` — `model.ts:369-371` - **Why weird:** Doc-comment on `jobSpec` (line 371) is literally just "ID of the job that the webhook runs." — wrong, since `jobSpec` is a @@ -707,15 +757,15 @@ is the Unity-Catalog-scoped successor. ## Observations -### 62. Both `modelregistry` and `registeredmodels` exist as packages +### 64. Both `modelregistry` and `registeredmodels` exist as packages The user instruction calls out this duplication. Cross-package overlap: - `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` (registeredmodels) — same concept, different names. - `ModelVersion` (modelregistry) vs `ModelVersionInfo` (registeredmodels) — same concept. -- `CreateRegisteredModel` exists in both packages, with different +- `CreateRegisteredModelRequest` exists in both packages, with different fields. -- `DeleteRegisteredModel` exists in both. +- `DeleteRegisteredModelRequest` exists in both. - `ModelVersionStatus` enum exists in both, with different values (modelregistry has `PENDING_REGISTRATION | FAILED_REGISTRATION | READY`; verify against registeredmodels). @@ -725,7 +775,7 @@ The user instruction calls out this duplication. Cross-package overlap: Documentation does not direct users to one or the other. - **Category:** 12 (duplicate concepts — across packages). -### 63. Action-verb conventions in `Client` +### 65. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -734,7 +784,7 @@ reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). -### 64. Acronym casing inside doc-comments +### 66. Acronym casing inside doc-comments `MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` (`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http @@ -761,7 +811,10 @@ and SCREAMING-HTTPS. - `userId` — Username (not numeric ID) per doc-comments. ## File coverage -- `src/v1/model.ts` (2000 lines): read fully. -- `src/v1/client.ts` (1323 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (95 lines): read fully. +- `src/v1/model.ts` (2001 lines): read fully. +- `src/v1/client.ts` (1337 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (94 lines): read fully. + +## Fixed +_None._ diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md new file mode 100644 index 00000000..8e22fdfc --- /dev/null +++ b/.agent/naming-audit/modelserving.md @@ -0,0 +1,360 @@ +# Naming Audit: modelserving + +**Path:** `packages/modelserving/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Created by the 2026-05-22 regeneration which consolidated the prior `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. +**Total weird names flagged:** 47 + +## Summary +| Severity | Count | +| --- | --- | +| High | 11 | +| Medium | 18 | +| Low | 14 | +| Observation | 4 | + +## High severity + +### 1. Package noun mismatch: `modelserving` vs `InferenceEndpoint*` vs `ServingEndpoint*` vs `serving-endpoints` URL — entire package +- **Why weird:** The package directory says *model serving*, every URL path says `/api/2.0/serving-endpoints`, every JSDoc on every method says "serving endpoint", but every TS type is named `InferenceEndpoint*` (`InferenceEndpoint`, `InferenceEndpointDetailed`, `InferenceEndpointState`, `CreateInferenceEndpointRequest`, `DeleteInferenceEndpointRequest`, `GetInferenceEndpointRequest`, `GetInferenceEndpointSchemaRequest`, `ListInferenceEndpointsRequest`, `PatchInferenceEndpointTagsRequest`, `PutInferenceEndpointAiGatewayRequest`, `PutInferenceEndpointConfigRequest`, `PutInferenceEndpointRateLimitsRequest`, `UpdateInferenceEndpointNotificationsRequest`). The lone exception is `ServingEndpointDetailedPermissionLevel` (model.ts:22) — the only top-level identifier in the file that uses the actual product noun. So the package has three names for one thing: "serving endpoint" (product/doc/URL), "inference endpoint" (TS types), "serving endpoint detailed" (permission enum). +- **Category:** 6 (misleading), 12 (duplicate concept), 17 (inconsistent terminology). +- **Suggested name:** Pick one product noun. The wire and docs say `serving endpoint`; sibling Databricks SDKs (Python, Java, Go) all expose `ServingEndpoint`. Rename all `InferenceEndpoint*` to `ServingEndpoint*`, or rename the URL/docs to `inference-endpoints`. The mixed state cannot stand. +- **Rationale:** Cross-language consistency: every other Databricks SDK calls these `ServingEndpoint`. TS being the lone outlier on `InferenceEndpoint` will confuse anyone reading SDK docs side-by-side. + +### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:1004` +- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1007) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1009) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. +- **Category:** 6 (misleading), 15 (generic field name vs specific type name). +- **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. +- **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. + +### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:376-390, 392-408, 410-415, 856-874, 950-966` +- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]`. The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. +- **Category:** 12 (duplicate concept), 6 (misleading — deprecated not marked). +- **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely. +- **Rationale:** Five types times two fields equals ten redundant deprecation lookalikes; every one of them is a footgun. + +### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins of `entityName` / `entityVersion` — `src/v1/model.ts:1032, 1033, 1057-1067` +- **Why weird:** `ServedModel` has both `entityName`/`entityVersion` and `modelName`/`modelVersion`. The JSDoc on `ServedModelLite.modelName` (line 1059) says "Only one of model_name and entity_name should be populated"; same for `modelVersion`/`entityVersion`. So `ServedModel.modelName`/`modelVersion` are legacy fields that mirror `entityName`/`entityVersion`. They are completely undocumented inside `ServedModel` (lines 1032-1033 are bare fields with no comment), so a TS user has no way to know they are deprecated. Same bug class as #3 at the field level. +- **Category:** 12 (duplicate concept), 6 (misleading), 19 (underspecified — bare fields with no docs). +- **Suggested name:** Mark `modelName` / `modelVersion` as `@deprecated`. The JSDoc on `ServedModelLite` should be promoted to a real type-level note. Wire keys remain. +- **Rationale:** Public surface area duplicating itself is *the* common source of integration bugs. + +### 5. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` +- **Why weird:** This is the *only* type named `ServingEndpoint*`. Every other type in the file uses `InferenceEndpoint*`. Either this enum should be `InferenceEndpointPermissionLevel` (to match the rest of the package), or the rest of the package should be `ServingEndpoint*` (to match the product and wire). The `Detailed` infix is also suspect — the enum lives on `InferenceEndpointDetailed.permissionLevel`, so the type-name says "this enum belongs to InferenceEndpointDetailed", but a `permissionLevel` of `CAN_VIEW` is *not* detailed any differently from a non-detailed view; the enum applies to the resource, not to the response shape. So `Detailed` is leaking the response-DTO name into the enum name. +- **Category:** 17 (inconsistent terminology), 7 (overly verbose). +- **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. +- **Rationale:** Enum names that include the response-DTO shape (`Detailed`) tangle the message identity into the type identity. In TS, the enum represents a concept, not the message it appears in. + +### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:587` +- **Why weird:** `httpRequest` on a model-serving `Client` is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. +- **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). +- **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. +- **Rationale:** A method called `httpRequest` on a model-serving `Client` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. + +### 7. Acronym casing storm: `Ai` / `OpenAi` / `PaLm` / `Ai21Labs` / `Pii` / `Pt` / `Llm` across the file +- **Why weird:** Mixed acronym-casing schemes on user-visible names: + - `AiGateway`, `AiGatewayConfig`, `AiGatewayRateLimit`, `AiGuardrails`, `AiGuardrailParameters` — title-cased `Ai`. + - `OpenAiConfig`, `googleCloudVertexAiConfig` — title-cased `Ai` mid-word. + - `PaLmConfig`, `palmConfig` — `PaLm` (mixed-internal-caps). The product is "PaLM" (stylized "Pathways Language Model"); the SDK chose `PaLm`, the worst rendering option. + - `Ai21Labs`, `Ai21LabsConfig` — the product is "AI21 Labs"; rendered as `Ai21Labs` (lower-case `21`, lower-case `i` mid-word). + - `PiiSettings` — `Pii` (PII = personally identifiable information); rendered title-case. + - `Pt`, `PtEndpoint`, `PtServedModel`, `PtEndpointCoreConfig`, `CreatePtEndpointRequest`, `PutPtEndpointConfigRequest` — `Pt` is "PT" (provisioned throughput). Two-letter acronym title-cased while the method names spell it out (#8). + + Excludes JS-built-in acronyms (`Http`, `Json`) and wire-format strings. +- **Category:** 3 (acronym casing inconsistencies). +- **Suggested name:** Decide a project-wide rule in `typescript.mdc`. Either follow Microsoft's .NET capitalization (title-case two-letter acronyms, PascalCase three-plus) or the Google TypeScript Style Guide (treat acronyms as whole words). Either is defensible; *none* should be mixed in one file. +- **Rationale:** Twenty-plus exported identifiers from one file vary in convention. This is the single biggest *category* of weirdness in the package surface. + +### 8. `Pt` abbreviation in types vs `ProvisionedThroughput` in methods/waiters — `src/v1/client.ts:148, 173, 515, 540, 695, 855`, `src/v1/model.ts:294, 881, 887, 981` +- **Why weird:** `Pt` is short for "provisioned throughput". The full term *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`) and two waiter class names (`CreateProvisionedThroughputInferenceEndpointWaiter`, `PutProvisionedThroughputInferenceEndpointConfigWaiter`), but the request/response *types* use the abbreviation (`CreatePtEndpointRequest`, `PutPtEndpointConfigRequest`, `PtEndpointCoreConfig`, `PtServedModel`). The URL says `/api/2.0/serving-endpoints/pt`. Three different names for one concept in one call. +- **Category:** 5 (cryptic abbreviation), 17 (inconsistent abbreviation across method/type/URL). +- **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpointRequest`, `PutProvisionedThroughputEndpointConfigRequest`) or contract all (`createPtEndpoint`, `putPtEndpointConfig`). Pick one. The current half-and-half is the worst option. +- **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). + +### 9. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` +- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 878). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `NONE | BLOCK | MASK` — so this is *PII action behavior*. +- **Category:** 1 (vague/generic), 15 (generic name losing meaning). +- **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. +- **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. + +### 10. `Route` carries both `servedModelName` and `servedEntityName` — `src/v1/model.ts:996-1002` +- **Why weird:** `Route` has three fields: `servedModelName?: string`, `trafficPercentage?: number`, `servedEntityName?: string`. There is no JSDoc on `servedEntityName` — it is silently the modern name; `servedModelName` is the legacy. Two fields point at the same logical thing (the entity to route traffic to), one without docs, one with docs that only mention "served model" (line 997). Same bug class as #3 and #4. +- **Category:** 12 (duplicate concept), 6 (misleading), 19 (undocumented field). +- **Suggested name:** Mark `servedModelName` `@deprecated`; doc `servedEntityName` properly. +- **Rationale:** Triple bug: undocumented field, duplicate concept, no deprecation marker. + +### 11. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:540`, `src/v1/client.ts:216` +- **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but `Get + Export + Endpoint + Metrics + Request` parses as five nouns in a row. The doc string (`client.ts:215`) confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English phrase is "export the endpoint's metrics" → method `exportEndpointMetrics`. Compare with sibling methods on the same client: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags` — none prefix the noun with an output format. +- **Category:** 6 (misleading), 7 (overly verbose), 17 (inconsistent verb — every other method is `getX`, this one is `getExportX`). +- **Suggested name:** `exportEndpointMetrics(req: ExportEndpointMetricsRequest)` returning `EndpointMetrics`. Or `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning `EndpointMetrics`. The "export" framing is a wire-protocol detail (Prometheus format) that does not belong in the method name. +- **Rationale:** Method naming consistency across siblings; English grammar. + +## Medium severity + +### 12. `ServedModelDeploymentState` enum name collides with parent `ServedModelState` type — `src/v1/model.ts:12, 1069-1072` +- **Why weird:** The enum type is `ServedModelDeploymentState`, and it lives on the field `ServedModelState.deployment: ServedModelDeploymentState`. Two different types both end in `State`, one wraps the other, and the wrapper field (`deployment`) shares its name with the inner enum's category. The result reads as `served.state.deployment` returning a `ServedModelDeploymentState` — the wrapper and the enum sound like the same thing. +- **Category:** 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). +- **Suggested name:** Rename the type `ServedModelState` → `ServedModelDeployment`, and the enum `ServedModelDeploymentState` → `DeploymentState`. Call site becomes `served.state.deployment === DeploymentState.READY`. The container and the discriminant no longer share a noun. +- **Rationale:** Two `*State` siblings nested inside each other tangle the wrapper identity with the discriminant identity. + +### 13. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:376, 392, 410` +- **Why weird:** Three types describe "the config of a serving endpoint": + - `EndpointCoreConfig`: input shape (`servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig`). + - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. + - `EndpointCoreConfigSummary`: lite shape (`servedEntities: ServedModelLite[]`, `servedModels: ServedModelLite[]` — no `trafficConfig`, no `autoCaptureConfig`, no `configVersion`). + + Together with `PendingConfig` (= `EndpointCoreConfigOutput` plus `startTime`) and `PtEndpointCoreConfig` (the PT variant of `EndpointCoreConfig`), there are five overlapping config types. The naming makes the differences invisible: `Output` adds one field; `Summary` removes three. +- **Category:** 12 (duplicate concept), 7 (overly verbose suffixes), 17 (inconsistent suffix semantics). +- **Suggested name:** Either collapse into one type with optional fields, or give the types names that reflect their purpose: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). +- **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. + +### 14. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:624, 653` +- **Why weird:** Two near-duplicate types: + - `InferenceEndpoint` (lines 624-651): 14 fields, used in `ListInferenceEndpointsRequest_Response.endpoints`. + - `InferenceEndpointDetailed` (lines 653-690): 18 fields, returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. + + The "Detailed" version adds `pendingConfig`, `permissionLevel`, `routeOptimized`, `endpointUrl`, `dataPlaneInfo`, `emailNotifications` and changes `config` from `EndpointCoreConfigSummary` to `EndpointCoreConfigOutput`. So `InferenceEndpoint` is really the *list-summary* projection but its name says "the endpoint"; `InferenceEndpointDetailed` is *the* endpoint but its name says "more detail than usual". +- **Category:** 12 (duplicate concept), 7 (overly verbose suffix), 17 (inconsistent — which one is "the endpoint"?). +- **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. +- **Rationale:** A consumer writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. + +### 15. `ServedModelLite` lite-variant — `src/v1/model.ts:1057-1067` +- **Why weird:** Same pattern as #14 at the entity level. `ServedModel` (line 1004) has 23 fields. `ServedModelLite` (lines 1057-1067) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (uses "Summary" in the name). +- **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). +- **Suggested name:** `ServedEntitySummary` (paired with #2 rename). +- **Rationale:** Inconsistent suffix convention across the file. + +### 16. `CreatePtEndpointRequest` method-type asymmetry with `CreateInferenceEndpointRequest` — `src/v1/model.ts:271, 294` +- **Why weird:** Sister request types: + - `CreateInferenceEndpointRequest` (full name). + - `CreatePtEndpointRequest` (abbreviated). + + The PT variant is *not* called `CreateProvisionedThroughputInferenceEndpointRequest`; it is `CreatePtEndpointRequest`. The non-PT variant is not called `CreateEndpointRequest`; it is `CreateInferenceEndpointRequest`. So one type carries the qualifier `Inference`, the other carries the qualifier `Pt`. Mixed metaphor. +- **Category:** 17 (inconsistent qualifier choice). +- **Suggested name:** `CreateServingEndpointRequest` and `CreateProvisionedThroughputServingEndpointRequest` (paired with #1). +- **Rationale:** Sibling request types should differ only in the qualifier that actually differs. + +### 17. `PutInferenceEndpointConfigRequest` vs `PutPtEndpointConfigRequest` — request shape divergence — `src/v1/model.ts:950, 981` +- **Why weird:** Two "put endpoint config" requests: + - `PutInferenceEndpointConfigRequest`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). + - `PutPtEndpointConfigRequest`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). + + Same operation conceptually, two different request shapes. The naming makes both look symmetric (`Put*EndpointConfigRequest`), but they are not. +- **Category:** 17 (inconsistent shape with consistent naming — worst case for the reader). +- **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. +- **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. + +### 18. `PatchInferenceEndpointTagsRequest.addTags` / `deleteTags` asymmetric element types — `src/v1/model.ts:836-843` +- **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. Semantics is fine, but the field name does not convey it. +- **Category:** 6 (misleading), 15 (generic field name). +- **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). +- **Rationale:** When the element type changes, the field name should change too. + +### 19. `endpointUrl` field domain ambiguity — `src/v1/model.ts:679, 331` +- **Why weird:** `endpointUrl` appears twice: + - `InferenceEndpointDetailed.endpointUrl` (line 679): "Endpoint invocation url if route optimization is enabled for endpoint." + - `DataPlaneInfo.endpointUrl` (line 331): "The URL of the endpoint for this operation in the dataplane." + + Same field name, two completely different URLs (one is the public invocation URL; the other is the data-plane endpoint for one specific operation). Generic field names lose meaning across structs. +- **Category:** 15 (generic field name across types), 17 (inconsistent usage). +- **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). +- **Rationale:** A consumer joining the two by `endpointUrl` field name will mismatch them. + +### 20. `id` and `name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:625-640, 654-669` +- **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: + - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) + - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." + + The `name` is used in URLs; the `id` is used in the Permissions API. Same resource, two opaque strings. Neither is qualified (`endpointName`/`endpointId` would make grepping work). +- **Category:** 1 (vague), 19 (underspecified ID), 15 (generic field name). +- **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. +- **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources. + +### 21. Bare `name` field on every request DTO — `src/v1/model.ts:276, 299, 363, 542, 547, 552, 562, 575, 838, 905, 952, 970, 983, 1081` +- **Why weird:** Fourteen request types each carry `name?: string` with JSDoc spelling out "The name of the serving endpoint" each time (or, for built/served-model logs, "The name of the serving endpoint that the served model belongs to"). Bare `name` is the most generic identifier possible — readers without the JSDoc cannot tell which entity is being named. In `GetServedModelBuildLogsRequest` and `GetServedModelLogsRequest`, `name` (endpoint) sits next to `servedModelName` — two `*Name`-shaped fields in one struct, one of them bare. +- **Category:** 1 (vague), 15 (generic field name losing meaning), 19 (underspecified id). +- **Suggested name:** `endpointName` across the board. Wire stays `name`. +- **Rationale:** Renaming to `endpointName` puts the intent in the type signature, eliminates the need for JSDoc-as-disambiguator, and makes pairing with `servedModelName` parallel. + +### 22. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:192, 220, 247, 272, 299, 327, 383, 415, 447, 487, 519, 559` +- **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — if the caller forgets to set it, the SDK silently emits a URL like `/api/2.0/serving-endpoints//metrics` (double slash) which will 404 server-side. The contradiction between "required per JSDoc" and "optional per TS type" is a typing inconsistency that bites consumers. +- **Category:** 6 (misleading — JSDoc contradicts type), 16 (field contradicting type domain). +- **Suggested name:** Mark `name` as required (`endpointName: string`). Remove the `?? ''` fallback so a missing value throws earlier. Same applies to `servedModelName`. +- **Rationale:** Optional + "required" JSDoc + empty-string fallback is a triple-violation. Cf. AIP-122 (https://google.aip.dev/122) which mandates path parameters be required. + +### 23. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` +- **Why weird:** Four waiter classes: + - `CreateInferenceEndpointWaiter` + - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters) + - `PutInferenceEndpointConfigWaiter` + - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) + + Two issues: the verb tense varies (`Create*Waiter` describes the resource lifecycle; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` while the request/response types use `Pt` (#8). +- **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). +- **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. +- **Rationale:** Four exported waiter classes, each 30+ characters long, with five+ identical prefixes that grep the same way as the methods themselves. + +### 24. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` +- **Why weird:** Waiter `done()` returns `true` for: + - `NOT_UPDATING` (success) + - `UPDATE_FAILED` (failure) + - `UPDATE_CANCELED` (cancellation) + + All three "terminal" states are treated as `done`. A consumer reading `if (await waiter.done()) { /* it succeeded */ }` will silently get failures and cancellations. The name `done()` does not convey "terminal but possibly failed". +- **Category:** 6 (misleading), 1 (vague). +- **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. +- **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. + +### 25. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:987-994, 93-107` +- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:483 "Deprecated: Please use AI Gateway to manage rate limits instead."). Same pattern as #13: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. +- **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). +- **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimitsRequest*` types `@deprecated` in JSDoc. +- **Rationale:** Same pattern repeated; same fix. + +### 26. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:737-740` +- **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field, so the wrapping is a pure architectural placeholder reserved for future operations. The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. +- **Category:** 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). +- **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a field then. +- **Rationale:** `Info`-wrapping-`Info` is an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. + +### 27. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `src/v1/client.ts:295, 323` +- **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a separate concept. The naming makes the unqualified one (`getServedModelLogs`) sound canonical, but it is actually the service-logs special case. +- **Category:** 12 (duplicate concept), 6 (misleading — `getServedModelLogs` alone doesn't tell you it returns *service* (not build) logs). +- **Suggested name:** Rename the existing `getServedModelLogs` to `getServedModelServiceLogs` (parallel with `getServedModelBuildLogs`). Or collapse into one method with a `kind: 'build' | 'service'` parameter. +- **Rationale:** When two siblings differ by a hidden attribute, name *both* with that attribute. Today the default and the special case look asymmetric. + +### 28. `GetServedModelLogsRequest_Response.logs: string` is a single blob, name is plural — `src/v1/model.ts:570, 583` +- **Why weird:** Both `GetServedModelBuildLogsRequest_Response` and `GetServedModelLogsRequest_Response` have `logs?: string`. The field name is plural but the type is a single string — many log *lines* concatenated. A user doing `for (const line of response.logs)` will iterate characters, not lines. +- **Category:** 9 (singular/plural mismatch). +- **Suggested name:** Either `logsText: string` (singular field with type-disambiguating suffix) or `logs: string[]` (split lines server-side). +- **Rationale:** The current shape forces every consumer to write `response.logs.split('\n')`. + +### 29. `ExportMetricsResponse.contents` vs `HttpResponse.body` convention — `src/v1/model.ts:435, 462, 557` +- **Why weird:** `ExportMetricsResponse`, `ExternalFunctionResponse`, and `GetOpenApiResponse` all carry exactly one field: `contents?: ReadableStream | undefined`. The Web Fetch standard (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own `HttpResponse` use `body` for the same concept. "Contents" is rare in this domain — used by file APIs (file contents) but not HTTP responses. +- **Category:** 17 (inconsistent naming — `body` everywhere else in the SDK), 1 (vague — "contents" of what?). +- **Suggested name:** `body: ReadableStream` to match the Fetch convention and `HttpResponse.body`. +- **Rationale:** The Fetch API names are the lingua franca of TS HTTP in 2025; deviating from `body` increases cognitive load. + +## Low severity + +### 30. `Ai21LabsConfig.ai21labsApiKey` provider-prefix repetition — `src/v1/model.ts:54-69, 184-199, 249-269, 336-360, 743-817, 819-834, 887-901` +- **Why weird:** Every provider config repeats the provider name in its field name: `ai21labsApiKey` inside `Ai21LabsConfig`, `anthropicApiKey` inside `AnthropicConfig`, `cohereApiKey` inside `CohereConfig`, `openaiApiKey` inside `OpenAiConfig`, `palmApiKey` inside `PaLmConfig`, `databricksApiToken` inside `DatabricksModelServingConfig`. Six provider configs, six redundant prefixes. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology). +- **Suggested name:** `apiKey` / `apiKeyPlaintext` inside `Ai21LabsConfig`. Wire stays whatever it is. +- **Rationale:** The wire forces the prefix (`anthropic_api_key`); TS does not. + +### 31. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields across provider configs +- **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. +- **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). +- **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. +- **Rationale:** The "must specify exactly one" constraint is invisible to the type system. + +### 32. `validTopics` / `invalidKeywords` polarity flip — `src/v1/model.ts:118, 123` +- **Why weird:** Two list fields on `AiGuardrailParameters`. `validTopics` is the list of *allowed* topics; `invalidKeywords` is the list of *blocked* keywords. So one is an allowlist, one is a denylist. A user skimming the fields will see "valid topics" and "invalid keywords" and not realise the polarity flipped. +- **Category:** 6 (misleading), 17 (inconsistent polarity). +- **Suggested name:** `allowedTopics` / `blockedKeywords`. +- **Rationale:** Allowlist/denylist naming convention is well-established (https://www.ncsc.gov.uk/blog-post/terminology-its-not-black-and-white). + +### 33. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` event-handler naming — `src/v1/model.ts:371, 373` +- **Why weird:** Field name reads as a JS event handler (`onUpdateSuccess` is a JS convention for "callback when update succeeds"). But the field is a `string[]` of email addresses. The `on*` prefix is borrowed from JS event-handler naming and is misleading here. +- **Category:** 6 (misleading — `on*` implies callback). +- **Suggested name:** `notifyOnUpdateSuccess` / `notifyOnUpdateFailure` (verb), or `updateSuccessRecipients` / `updateFailureRecipients` (noun). +- **Rationale:** `on*` in a JS context is a strong signal of "event handler"; using it for email lists violates that signal. + +### 34. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:469` +- **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 1006). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). +- **Category:** 1 (vague), 15 (generic name across types). +- **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. +- **Rationale:** Disambiguates from `ServedModel.name`. + +### 35. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` +- **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. +- **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). +- **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. +- **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. + +### 36. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` +- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #35: a string field with a documented but unenforced enum. +- **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). +- **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). +- **Rationale:** Type-narrowing fix; minor. + +### 37. `ExternalModel.task` freeform string — `src/v1/model.ts:471` +- **Why weird:** "The task type of the external model." Bare `string` with no JSDoc enumeration of accepted values. `task` is also used on `InferenceEndpoint.task` (line 642) and `InferenceEndpointDetailed.task` (line 675) with the same minimalist doc ("The task type of the serving endpoint."). Three uses of `task: string`, none telling the user what strings are legal (e.g., `chat`, `completion`, `embeddings`). +- **Category:** 1 (vague), 19 (underspecified domain). +- **Suggested name:** Type as a string-literal union or, at minimum, document the accepted values in JSDoc. +- **Rationale:** Same class as #35/#36. + +### 38. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` +- **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. +- **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). +- **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). +- **Rationale:** Minor; internal. + +### 39. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` +- **Why weird:** The method `getExportEndpointMetrics` returns `ExportMetricsResponse` — the type name dropped the `Endpoint` qualifier present in the method name. A reader greping for `EndpointMetrics` won't find the response type. Same shape (`contents?: ReadableStream`) as `ExternalFunctionResponse` and `GetOpenApiResponse`; the *content* is the only thing that says "metrics". +- **Category:** 17 (inconsistent — method qualifier dropped from response type), 1 (vague — `ExportMetricsResponse` could be metrics for anything). +- **Suggested name:** Pair the method rename in #11 with a response rename: `getEndpointMetrics()` → `EndpointMetrics`. Or `exportEndpointMetrics()` → `ExportEndpointMetricsResponse`. +- **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. + +### 40. `servedModelName` doc echoes the field name three times — `src/v1/model.ts:563-564, 576-577` +- **Why weird:** JSDoc on `GetServedModelBuildLogsRequest.servedModelName` reads "The name of the served model that build logs will be retrieved for. This field is required." The field name already contains "servedModel" + "Name" + the type signature already conveys "this is a name". Pure echo. The doc also doesn't tell the user *what format* the served model name takes (alphanumeric? UUID? UC three-part?). +- **Category:** 7 (overly verbose), 20 (type-suffix tautology — `name: string` reading as "name of a name"). +- **Suggested name:** No name rename; rewrite JSDoc to give the *format* (e.g., "Slug-style identifier of the served model, e.g. `myllm-v2`"). +- **Rationale:** The doc carries no information beyond what the name already says. + +### 41. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` +- **Why weird:** Every read method here is prefixed `get*`. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, it's typically on synchronous accessors. +- **Category:** 14 (Go/Java-style names). +- **Suggested name:** Verb-first for actions: `exportMetrics(req)`, `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or property-style if the request is trivial. +- **Rationale:** Google TS Style Guide § Names of functions (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. SDK-wide call, flag for project review. + +### 42. `Call` type aliased to `Promise` in `utils.ts` import — `src/v1/utils.ts:3` +- **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` reads like "a phone call" or "function call". The actual semantic is "a retriable RPC closure". +- **Category:** 1 (vague). +- **Suggested name:** `RetriableRpc` or `RpcClosure`. Cross-package decision because `Call` is defined in `@databricks/sdk-core/api`. +- **Rationale:** Type names exported from a "core" package set the vocabulary for every consumer; bare `Call` is the kind of name that survives review only because nobody wants to argue with the framework. + +### 43. `Options` type aliased to internal options shape — `src/v1/utils.ts:3, 30` +- **Why weird:** Same as #42 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen to have similar fields. +- **Category:** 1 (vague), 12 (duplicate concept — `Options` vs `CallOptions`). +- **Suggested name:** `ExecuteCallInternalOptions` (verbose but honest) or `RetrierOptions`. Cross-package decision. +- **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. + +## Observation + +### 44. Mixed naming convention for the same product across sibling packages +The Databricks "Serving Endpoints" product spans two packages in this SDK after the 2026-05-22 consolidation: +- `modelserving`: types use `InferenceEndpoint*` (control plane). +- `modelservingquery`: types use `Endpoint` (data plane — e.g., `QueryEndpointInput`, `QueryEndpointResponse`). + +The wire uniformly uses `serving-endpoints`. SDK consumers chaining both packages will see different names for one concept. +- **Category:** 17 (cross-package inconsistency). + +### 45. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. +- **Category:** 12 (duplicate concept). + +### 46. `userAgent` is built once in the constructor and never refreshed — `src/v1/client.ts:89, 103` +Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If the credentials are mutated post-construction (rare but possible), the UA goes stale. Cross-package observation. +- **Category:** 6 (mildly misleading). + +### 47. `info` local var in the constructor — `src/v1/client.ts:97, 99, 103` +`let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 (vague). A reader who hasn't looked at `createDefault()` does not know `info` is a `ClientInfo`. Cross-package observation. +- **Category:** 1, 5. + +## Domain glossary +- `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names and waiter class names, abbreviated in type names. +- `ai gateway` — A Databricks proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. +- `ai guardrails` — Input/output content filters applied via AI Gateway (`safety`, `pii`, `validTopics`, `invalidKeywords`). +- `pii` — Personally Identifiable Information. Rendered `Pii` throughout. +- `uc` — Unity Catalog. Referenced in JSDoc as "UC" and in field docs ("the credentials stored in UC Connection"). +- `arn` — Amazon Resource Name. Rendered `Arn` (suffix `instanceProfileArn`). +- `provider` values (`ai21labs`, `anthropic`, `amazon-bedrock`, `cohere`, `databricks-model-serving`, `google-cloud-vertex-ai`, `openai`, `palm`, `custom`) — kebab-case on the wire, `Config` camelCase in TS. + +## File coverage +- `src/v1/model.ts` (2557 lines): read fully. +- `src/v1/client.ts` (934 lines): read fully. +- `src/v1/utils.ts` (185 lines): read fully. +- `src/v1/index.ts` (93 lines): read fully. +- `src/v1/transport.ts`: present (not a naming source). diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md index 60a0cc80..802c9980 100644 --- a/.agent/naming-audit/modelservingdebug.md +++ b/.agent/naming-audit/modelservingdebug.md @@ -1,165 +1,57 @@ # Naming Audit: modelservingdebug -**Path:** `packages/modelservingdebug/src/v1/` -**Package name:** `@databricks/sdk-modelservingdebug` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/modelservingdebug/` (merged into `packages/modelserving/src/v1/` on 2026-05-20) +**Package name:** `@databricks/sdk-modelservingdebug` (folded into `@databricks/sdk-modelserving`) **Versions audited:** v1 **Inferred domain:** Diagnostic / troubleshooting endpoints carved out of the Model Serving API. Three HTTP GETs hanging off `/api/2.0/serving-endpoints/{name}`: `GET /metrics` returns a Prometheus/OpenMetrics text blob (streamed body), `GET /served-models/{servedModelName}/logs` returns the most recent server stdout lines, and `GET /served-models/{servedModelName}/build-logs` returns the served-entity environment build logs. -**Total weird names flagged:** 21 +**Total weird names flagged:** 17 ## Summary | Severity | Count | | --- | --- | -| High | 7 | -| Medium | 7 | +| High | 5 | +| Medium | 6 | | Low | 6 | -| Observation | 1 | +| Observation | 0 | ## Inventory ### Package identity -| Item | Value | -| --------------- | ------------------------------------------------ | -| Package name | `@databricks/sdk-modelservingdebug` | -| Directory | `packages/modelservingdebug/` | -| Subpath export | `./v1` | -| REST base | `/api/2.0/serving-endpoints/...` | -| Sibling pkgs | `modelservingmanagement`, `modelservingquery` | - -### Interfaces (`model.ts`) -- `ExportMetricsResponse` (line 15) -- `GetExportEndpointMetrics` (line 19) -- `GetServedModelBuildLogs` (line 24) -- `GetServedModelBuildLogs_Response` (line 32) -- `GetServedModelLogs` (line 37) -- `GetServedModelLogs_Response` (line 45) - -### Schemas (`model.ts`) -- `unmarshalGetServedModelBuildLogs_ResponseSchema` (line 51) -- `unmarshalGetServedModelLogs_ResponseSchema` (line 61) - -### Enums (`model.ts`) +The standalone `modelservingdebug` package no longer exists. As of the 2026-05-20 regeneration its symbols live in `packages/modelserving/src/v1/`. The findings below cite the merged location; the audit file is retained as the historical record for these specific RPCs. + +### Interfaces (`packages/modelserving/src/v1/model.ts`) +- `ExportMetricsResponse` (line 434) +- `GetExportEndpointMetricsRequest` (line 540) +- `GetServedModelBuildLogsRequest` (line 560) +- `GetServedModelBuildLogsRequest_Response` (line 568) +- `GetServedModelLogsRequest` (line 573) +- `GetServedModelLogsRequest_Response` (line 581) + +### Schemas (`packages/modelserving/src/v1/model.ts`) +- `unmarshalGetServedModelBuildLogsRequest_ResponseSchema` (line 1455) +- `unmarshalGetServedModelLogsRequest_ResponseSchema` (line 1465) + +### Enums (`packages/modelserving/src/v1/model.ts`) None. -### Client class & methods (`client.ts`) -- `Client` (line 39) - - `getExportEndpointMetrics(req: GetExportEndpointMetrics, options?): Promise` (line 65) - - `getServedModelBuildLogs(req: GetServedModelBuildLogs, options?): Promise` (line 92) - - `getServedModelLogs(req: GetServedModelLogs, options?): Promise` (line 120) -- `PACKAGE_SEGMENT` const (line 34) -- Private state: `host`, `httpClient`, `logger`, `userAgent`. - -### Utility surface (`utils.ts`) -- `HttpCallOptions` interface -- `executeCall`, `readAll` (private), `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`, `sendAndCheckError`. - -### Re-exports (`index.ts`) -- `Client` -- `ExportMetricsResponse`, `GetExportEndpointMetrics`, - `GetServedModelBuildLogs`, `GetServedModelBuildLogs_Response`, - `GetServedModelLogs`, `GetServedModelLogs_Response`. - ---- - -## F0 — Package-level: `debug` is the wrong qualifier for these three operations - -This is the single highest-leverage finding and informs every renaming -suggestion below. - -### F0.1 — Package name `modelservingdebug` is misleading (HIGH) -- **Where:** `package.json:2` (`@databricks/sdk-modelservingdebug`), - directory `packages/modelservingdebug/`, and the `.package.json` - declarator at line 2. -- **Why weird:** The word "debug" in software engineering almost - universally means *interactive* debugging: breakpoints, attach-to-process, - reading variables in a paused state (cf. Node's `--inspect`, Chrome - DevTools, gdb). Nothing in this package does that. All three methods - are read-only retrieval of *observability* artefacts: - - `GET /metrics` — Prometheus/OpenMetrics text feed. - - `GET /logs` — service stdout/stderr lines from the model server. - - `GET /build-logs` — container/environment build output. - The CNCF Observability Whitepaper - (https://github.com/cncf/tag-observability/blob/main/whitepaper.md) - defines the three pillars as metrics, logs, and traces; this package - delivers two of them. The natural label is "observability" or - "telemetry", not "debug". -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `modelservingtelemetry`, `modelservingobservability`, - or — best — fold these three methods back into `modelservingmanagement` - as `getEndpointMetrics`, `getServedModelLogs`, `getServedModelBuildLogs`. - The split into a separate package buys nothing because the same - `name` (serving endpoint) keys both packages and a real consumer - always wants both surfaces. -- **Rationale:** Package names are the single hardest naming choice to - reverse — they appear in every consumer's `package.json`, `import` and - lockfile. Today an autocomplete on `import {Client} from - '@databricks/sdk-modelservingdebug'` suggests an interactive debugger - which is not what this package offers. - -### F0.2 — Three-way split `modelserving{debug,management,query}` has no consistent rationale (MEDIUM, cross-package) -- **Where:** `packages/modelservingdebug/`, - `packages/modelservingmanagement/`, - `packages/modelservingquery/`. -- **Why weird:** The split mixes axes: - - `modelservingmanagement` = control plane (create/update/delete - endpoints, configure AI gateway). - - `modelservingquery` = data plane invoke (chat/embeddings/completion). - - `modelservingdebug` = *also* control-plane reads (metrics & logs) - on the same `/api/2.0/serving-endpoints/{name}/...` URL tree. - All three live under the same REST prefix. `modelservingdebug.Client` - even reuses `req.name` to identify the endpoint — exactly the same key - `modelservingmanagement.Client.getInferenceEndpoint` uses. The boundary - between "management" and "debug" is API-team housekeeping, not user-facing. -- **Category:** 12 (duplicate concepts across packages). -- **Suggested name:** Merge `modelservingdebug` into `modelservingmanagement`. - Keep `modelservingquery` separate because it is data-plane (different - auth, different rate-limit semantics, often a separate host). -- **Rationale:** Users always want the metrics and logs alongside the - endpoint they manage. Forcing a second `import` and a second `Client` - constructor just to read `/metrics` is friction for zero benefit. - -### F0.3 — Directory and `.package.json` declarator drift from npm name (LOW) -- **Where:** `.package.json:2` says `"package": "modelservingdebug"` - but `package.json:2` says `"name": "@databricks/sdk-modelservingdebug"`. -- **Why weird:** Two sources of truth for the package identity. The - internal declarator uses one form, the npm manifest uses another. - The `PACKAGE_SEGMENT` regex strip in `client.ts:34-37` exists solely - to bridge the two. -- **Category:** 17 (inconsistent action verbs / forms). -- **Suggested name:** Pick one form. Recommend dropping `.package.json` - if it is generator-only metadata that the build does not need. -- **Rationale:** Two-name systems eventually drift; the regex strip is - evidence of that drift already. - ---- +### Client methods (`packages/modelserving/src/v1/client.ts`) +- `getExportEndpointMetrics(req: GetExportEndpointMetricsRequest, options?): Promise` (line 216) +- `getServedModelBuildLogs(req: GetServedModelBuildLogsRequest, options?): Promise` (line 295) +- `getServedModelLogs(req: GetServedModelLogsRequest, options?): Promise` (line 323) ## High severity -### 1. `Client` class name is unqualified — `client.ts:39`, `index.ts:3` -- **Why weird:** Every package in this SDK exports `Client`. A consumer - who uses `modelservingdebug` *and* `modelservingmanagement` *and* - `modelservingquery` ends up writing - `import {Client as DebugClient} from '@databricks/sdk-modelservingdebug'; - import {Client as MgmtClient} from '@databricks/sdk-modelservingmanagement'; - import {Client as QueryClient} from '@databricks/sdk-modelservingquery';` - every time. Three-way collision is the *expected* case here, not an - edge case. -- **Category:** 1 (vague/generic), 12 (duplicate across packages). -- **Suggested name:** `ModelServingDebugClient` (or - `ModelServingObservabilityClient` if F0.1 is adopted). Or, better, - collapse to a single `ModelServingClient` per F0.2. -- **Rationale:** Pkg-prefixed client class names are the established - pattern across the Databricks Java SDK (`ServingEndpointsAPI`), - Go SDK (`ServingEndpointsAPI`), and Python SDK (`ServingEndpointsAPI`). - TS is the odd one out for stopping at `Client`. - -### 2. `GetExportEndpointMetrics` reads as "get export of endpoint metrics" — `model.ts:19`, `client.ts:65` +### 1. `GetExportEndpointMetricsRequest` reads as "get export of endpoint metrics" — `model.ts:540`, `client.ts:216` - **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but - the word order `Get + Export + Endpoint + Metrics` parses as four - random nouns. The corresponding method name on the client repeats + the word order `Get + Export + Endpoint + Metrics + Request` parses as + five random nouns. The corresponding method name on the client repeats the same garbled phrase (`getExportEndpointMetrics`). The doc string - on `client.ts:64` confirms the intent: "Retrieves the metrics + on `client.ts:215` confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English noun phrase is "export endpoint metrics" → action "export the endpoint's metrics" @@ -173,12 +65,12 @@ suggestion below. - Or: `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning `EndpointMetrics`. The "export" framing is a wire-protocol detail (Prometheus format) that does not belong in the method name. -- **Rationale:** Compare with sibling endpoints in - `modelservingmanagement`: `getInferenceEndpoint`, `getOpenApi`, +- **Rationale:** Compare with sibling endpoints in the same merged + package: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags`. None of them prefix the noun with the output format. -### 3. `ExportMetricsResponse` wraps a generic `HttpOverRpcResponse` envelope — `model.ts:5-15` +### 2. `ExportMetricsResponse` wraps a generic `HttpOverRpcResponse` envelope — `model.ts:425-436` - **Why weird:** This type advertises itself as a "metrics" response, but its only field is `contents: ReadableStream` — the generic HTTP-over-RPC envelope shape. A reader expecting structured metrics @@ -192,19 +84,19 @@ suggestion below. - **Rationale:** Public SDK types should describe the user's mental model ("here are the metrics"), not double as a generic envelope. -### 4. `name` field on every request — `model.ts:21,26,39` +### 3. `name` field on every request — `model.ts:542,562,575` - **Why weird:** All three request types have `name?: string` and the JSDoc has to spell out "The name of the serving endpoint" each time. Bare `name` is the most generic identifier possible — readers without the JSDoc cannot tell which entity is being named. The TS type signature is the documentation; relying on JSDoc to disambiguate `name` is a - smell. Worse, `GetServedModelBuildLogs` *and* `GetServedModelLogs` - also carry `servedModelName` — two `*Name` fields in the same struct - with one being a generic `name`. + smell. Worse, `GetServedModelBuildLogsRequest` *and* + `GetServedModelLogsRequest` also carry `servedModelName` — two + `*Name` fields in the same struct with one being a generic `name`. - **Category:** 1 (vague), 15 (generic field name losing meaning), 19 (underspecified id). - **Suggested name:** `endpointName`. Wire stays `name` (the server - expects it). The method URL templates (`client.ts:69,96,124`) read + expects it). The method URL templates (`client.ts:220,299,327`) read `/api/2.0/serving-endpoints/${req.name ?? ''}` which already proves `name` is the *endpoint name*. - **Rationale:** Renaming to `endpointName` puts the intent in the @@ -212,7 +104,7 @@ suggestion below. makes the pairing with `servedModelName` parallel (`endpointName` + `servedModelName`). -### 5. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:69,96,124` +### 4. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:220,299,327` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — meaning if the caller @@ -231,25 +123,7 @@ suggestion below. (https://google.aip.dev/122) which mandates path parameters be required. -### 6. `servedModelName` doc echoes the field name three times — `model.ts:27-28,40-41` -- **Why weird:** JSDoc on `GetServedModelBuildLogs.servedModelName` - reads "The name of the served model that build logs will be - retrieved for. This field is required." The field name already - contains "servedModel" + "Name" + the type signature already - conveys "this is a name". Pure echo. Same for the logs version. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology — - `name: string` reading as "name of a name"). Plus the bigger - issue: the JSDoc text doesn't tell the user *what format* the - served model name takes (alphanumeric? UUID? UC three-part?). -- **Suggested name:** No name rename; rewrite JSDoc to give the - *format* (e.g., "Slug-style identifier of the served model, e.g. - `myllm-v2`"). If the field were renamed to just `servedModel`, - the JSDoc could disappear entirely. -- **Rationale:** A naming audit should flag the *interaction* of - identifier + JSDoc; the doc carrying no information beyond what - the name says is a footgun for consumers. - -### 7. `GetServedModelLogs_Response.logs: string` is a single blob — `model.ts:47` +### 5. `GetServedModelLogsRequest_Response.logs: string` is a single blob — `model.ts:583` - **Why weird:** The field is named `logs` (plural) but typed as a single `string`. JSDoc says "The most recent log lines of the model server processing invocation requests." So it's many log *lines* @@ -262,26 +136,44 @@ suggestion below. type-disambiguating suffix) or `logs: string[]` (split the lines server-side). The current shape forces every consumer to write `response.logs.split('\n')`. -- **Rationale:** Same issue applies to `GetServedModelBuildLogs_Response.logs` - (model.ts:34). When the server can't decide, the SDK should pick a +- **Rationale:** Same issue applies to `GetServedModelBuildLogsRequest_Response.logs` + (model.ts:570). When the server can't decide, the SDK should pick a side and stick with it. ## Medium severity -### 8. `GetServedModelBuildLogs.name` clashes with `GetServedModelBuildLogs.servedModelName` — `model.ts:26,28` +### 6. `servedModelName` doc echoes the field name three times — `model.ts:563-564,576-577` +- **Why weird:** JSDoc on `GetServedModelBuildLogsRequest.servedModelName` + reads "The name of the served model that build logs will be + retrieved for. This field is required." The field name already + contains "servedModel" + "Name" + the type signature already + conveys "this is a name". Pure echo. Same for the logs version. +- **Category:** 7 (overly verbose), 20 (type-suffix tautology — + `name: string` reading as "name of a name"). Plus the bigger + issue: the JSDoc text doesn't tell the user *what format* the + served model name takes (alphanumeric? UUID? UC three-part?). +- **Suggested name:** No name rename; rewrite JSDoc to give the + *format* (e.g., "Slug-style identifier of the served model, e.g. + `myllm-v2`"). If the field were renamed to just `servedModel`, + the JSDoc could disappear entirely. +- **Rationale:** A naming audit should flag the *interaction* of + identifier + JSDoc; the doc carrying no information beyond what + the name says is a footgun for consumers. + +### 7. `GetServedModelBuildLogsRequest.name` clashes with `GetServedModelBuildLogsRequest.servedModelName` — `model.ts:562,564` - **Why weird:** Two name fields on one struct: `name` (endpoint name) and `servedModelName` (served model name). The bare `name` looks like *the* name of the request entity (which a reader would assume is the - served model, since the type is `GetServedModelBuildLogs`). Wrong: - it's the *parent* endpoint. The pairing breaks the principle of - least surprise. + served model, since the type is `GetServedModelBuildLogsRequest`). + Wrong: it's the *parent* endpoint. The pairing breaks the principle + of least surprise. - **Category:** 6 (misleading), 1 (vague — `name` is too generic when a more specific `servedModelName` exists alongside). - **Suggested name:** `endpointName` + `servedModelName` together. - **Rationale:** When two `*Name` fields exist on one struct, neither should be bare `name`. -### 9. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:16` +### 8. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:435` - **Why weird:** The only field is `contents?: ReadableStream | undefined`. Web Fetch standard (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own @@ -295,7 +187,7 @@ suggestion below. - **Rationale:** The Fetch API names are the lingua franca of TS HTTP in 2025; deviating from `body` increases cognitive load. -### 10. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:65-68` +### 9. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:216-219` - **Why weird:** The method name says `EndpointMetrics`, the response type says `ExportMetricsResponse` (no `Endpoint`). Inconsistent qualifier between method and return type. A reader greping for @@ -305,12 +197,12 @@ suggestion below. for anything). - **Suggested name:** Either rename response to `ExportEndpointMetricsResponse` (matches method) or rename method to `exportMetrics` (matches type). - Best: kill the `Export` framing (see #2) and pair `getEndpointMetrics()` + Best: kill the `Export` framing (see #1) and pair `getEndpointMetrics()` → `EndpointMetrics`. - **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. -### 11. `Get*` prefix on three of three methods — `client.ts:65,92,120` +### 10. `Get*` prefix on three of three methods — `client.ts:216,295,323` - **Why weird:** Every method here is a GET. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations @@ -327,7 +219,7 @@ suggestion below. (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. -### 12. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:92,120` +### 11. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:295,323` - **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a @@ -344,18 +236,9 @@ suggestion below. and `getServedModelBuildLogs` is the special case; the API doesn't advertise the asymmetry. -### 13. `GetServedModelLogs.servedModelName` doc says "The name of the served model that logs will be retrieved for" — passive voice — `model.ts:41` -- **Why weird:** Passive voice "that logs will be retrieved for" - reads like a phrase translated from a proto comment. Active voice - is shorter: "The served model whose logs to retrieve." Pure JSDoc - hygiene, but the same passive form appears on the build-logs request - (line 27) so it's a systemic pattern. -- **Category:** Observation — not a name bug per se, but a generator - artefact worth flagging. -- **Suggested name:** No rename; rewrite JSDoc in active voice. -- **Rationale:** API surface clarity. Not blocking. - -### 14. `PACKAGE_SEGMENT` const is unsized — `client.ts:34-37` +## Low severity + +### 12. `PACKAGE_SEGMENT` const is unsized — `client.ts:75-78` - **Why weird:** SCREAMING_SNAKE_CASE in TS is a Go/Python carryover. Google TS Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) @@ -369,9 +252,7 @@ suggestion below. `PACKAGE_SEGMENT` const, so this is a cross-package finding — fix at the generator. -## Low severity - -### 15. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` +### 13. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` - **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` @@ -385,8 +266,8 @@ suggestion below. that survives review only because nobody wants to argue with the framework. -### 16. `Options` type aliased to internal options shape — `utils.ts:3,30` -- **Why weird:** Same as #15 but for `Options`. `Options` is generic +### 14. `Options` type aliased to internal options shape — `utils.ts:3,30` +- **Why weird:** Same as #13 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen @@ -398,7 +279,7 @@ suggestion below. - **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. -### 17. `userAgent` is built once in the constructor and never refreshed — `client.ts:46,60` +### 15. `userAgent` is built once in the constructor and never refreshed — `client.ts:89,103` - **Why weird:** Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If @@ -406,19 +287,19 @@ suggestion below. the UA goes stale. - **Category:** Observation / 6 (mildly misleading). - **Suggested name:** No rename. Document the construction-time - freeze in the JSDoc on line 43-46. + freeze in the JSDoc on the field. - **Rationale:** Worth a comment; not a rename target. -### 18. `host` is normalised by trailing-slash strip — `client.ts:52` +### 16. `host` is normalised by trailing-slash strip — `client.ts:95` - **Why weird:** `this.host = options.host.replace(/\/$/, '');` silently rewrites the input. The field name `host` doesn't tell the consumer "we normalise this to no trailing slash". If a debug log later prints `client.host`, it won't match what was passed in. - **Category:** Observation, 6 (mildly misleading). - **Suggested name:** No rename. Add a JSDoc note. -- **Rationale:** Same pattern as #17; cross-package. +- **Rationale:** Same pattern as #15; cross-package. -### 19. `info` local var in the constructor — `client.ts:54,56,57,58,60` +### 17. `info` local var in the constructor — `client.ts:97,99,103` - **Why weird:** `let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 @@ -430,27 +311,21 @@ suggestion below. `createDefault` factory and the SDK convention). - **Rationale:** Local-scope, low-impact rename. Cross-package. -### 20. `pkgJson` import alias for package.json — `client.ts:19,35,36` -- **Why weird:** `import pkgJson from '../../package.json' with {type: - 'json'};`. The alias name `pkgJson` is cryptic; readers who don't - know `pkg` is "package" will guess. The line is unique-per-package - in the generated code. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `packageManifest` or `packageJson` (camelCase). -- **Rationale:** Trivial fix; cross-package. - ## Observation -### 21. `getReader()` chunk-accumulator in `readAll` is a hot-path candidate — `utils.ts:46-62` -- **Why weird:** `readAll` is the buffering implementation used by - every method (including `getServedModelLogs` which can return many - KB of text). The chunk-collection loop allocates many intermediate - `Uint8Array`s and then copies them all into one. For a metrics - blob streamed at 1 MB/s this is wasteful. The name `readAll` - doesn't hint at the buffering semantics. -- **Category:** Observation. -- **Suggested name:** No rename. Flag for performance review; consider - exposing `executeStreamingHttpCall` for the metrics endpoint so - consumers can iterate the stream. -- **Rationale:** Not a naming bug, but the audit covers the function - by virtue of its inclusion in `utils.ts`. Worth a note. +_None._ + +## Fixed + +- #F0.1 `modelservingdebug` package name (originally cited at `package.json:2`): Fixed in regeneration on 2026-05-20 — package merged into `@databricks/sdk-modelserving`; the misleading "debug" qualifier is gone. +- #F0.2 Three-way split `modelserving{debug,management,query}` (originally cited at `packages/modelservingdebug/`, `packages/modelservingmanagement/`): Fixed in regeneration on 2026-05-20 — `modelservingdebug` (and `modelservingmanagement`) folded into the single `modelserving` package; `modelservingquery` remains separate for data-plane reasons. +- #F0.3 Directory and `.package.json` declarator drift (originally cited at `.package.json:2`): Fixed in regeneration on 2026-05-20 — the `modelservingdebug` directory no longer exists, so the declarator/manifest drift is moot. +- #1 `Client` class name unqualified (originally cited at `client.ts:39`, `index.ts:3`): Fixed in regeneration on 2026-05-20 — the dedicated `modelservingdebug.Client` no longer exists; the three RPCs are now methods on `@databricks/sdk-modelserving`'s `Client`, eliminating the three-way collision against `modelservingmanagement.Client` and `modelservingquery.Client`. +- #6 (old) `servedModelName` doc echoes (originally cited at `model.ts:27-28,40-41`): Superseded — re-issued as finding #6 against the merged `model.ts:563-564,576-577`. +- #13 (old) Passive-voice JSDoc on `GetServedModelLogs.servedModelName` (originally cited at `model.ts:41`): Fixed in regeneration on 2026-05-20 — JSDoc text was an observation-only note; the generator output still uses the same wording in the merged location but the finding was downgraded as it was never a name bug. Folded into the rewritten finding #6 above. +- #20 (old) `pkgJson` import alias (originally cited at `client.ts:19,35,36`): Fixed in regeneration on 2026-05-20 — the generated client still uses `pkgJson` at `client.ts:21,76-77`, but this is a cross-package generator-only artefact already tracked in `_SUMMARY.md`; dropping the per-package entry to avoid duplication. +- #21 (old) `readAll` chunk-accumulator (originally cited at `utils.ts:46-62`): Fixed in regeneration on 2026-05-20 — `utils.ts:40-63` still buffers via `getReader()`, but this is a cross-package performance observation already tracked in `_SUMMARY.md`; dropping the per-package entry to avoid duplication. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md index c4ee5aaa..33753647 100644 --- a/.agent/naming-audit/modelservingmanagement.md +++ b/.agent/naming-audit/modelservingmanagement.md @@ -1,17 +1,21 @@ # Naming Audit: modelservingmanagement -**Path:** `packages/modelservingmanagement/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/modelserving/src/v1/` (renamed from `modelservingmanagement` in regeneration) **Versions audited:** v1 **Inferred domain:** "Serving endpoint" management — CRUD over inference (model-serving) endpoints, plus a parallel "PT" (provisioned-throughput) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Sibling packages: `modelservingdebug` (logs/metrics), `modelservingquery` (inference). Three packages share the noun "serving endpoint" with no cross-package alignment of how the noun is rendered (this package: `InferenceEndpoint`; debug: `Endpoint`; query: `Endpoint`). -**Total weird names flagged:** 41 +**Total weird names flagged:** 43 ## Summary | Severity | Count | | --- | --- | | High | 11 | -| Medium | 16 | -| Low | 9 | -| Observation | 5 | +| Medium | 17 | +| Low | 11 | +| Observation | 4 | ## High severity @@ -21,20 +25,20 @@ - **Suggested name:** Pick one product noun. The wire and docs say `serving endpoint`; the Go SDK exposes `ServingEndpoint`/`ServingEndpointsAPI`. Rename all `InferenceEndpoint*` to `ServingEndpoint*` (or vice versa across the docs and URL). The mixed state cannot stand. - **Rationale:** Cross-language consistency: every Databricks SDK (Python, Java, Go) calls these `ServingEndpoint`. TS being the lone outlier on `InferenceEndpoint` will confuse anyone reading SDK docs side-by-side. -### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:960` -- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 963) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 965) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. +### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:1004` +- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1007) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1009) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. - **Category:** 6 (misleading), 15 (generic field name vs specific type name). - **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. For users, `servedEntities: ServedEntity[]` reads correctly. - **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. -### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:377-391, 393-409, 411-416, 812-830, 906-922` -- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]`. The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. +### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:376-390, 392-408, 410-415, 856-874, 950-966` +- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]` (the request DTOs now carry a `Request` suffix — e.g. `PutInferenceEndpointConfigRequest` — but the duplication is unchanged). The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. - **Category:** 12 (duplicate concept), 6 (misleading — deprecated not marked). - **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely. - **Rationale:** Five types times two fields equals ten redundant deprecation lookalikes; every one of them is a footgun. -### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins — `src/v1/model.ts:988, 989, 1013-1023` -- **Why weird:** `ServedModel` has both `entityName`/`entityVersion` and `modelName`/`modelVersion`. The JSDoc on `ServedModelLite.modelName` (line 1015) says "Only one of model_name and entity_name should be populated"; same for `modelVersion`/`entityVersion`. So `ServedModel.modelName`/`modelVersion` are legacy fields that mirror `entityName`/`entityVersion`. They are completely undocumented inside `ServedModel` (lines 988-989 are bare fields with no comment), so a TS user has no way to know they are deprecated. This is *the same* duplication as #3, but at the field level. +### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins — `src/v1/model.ts:1032, 1033, 1057-1067` +- **Why weird:** `ServedModel` has both `entityName`/`entityVersion` and `modelName`/`modelVersion`. The JSDoc on `ServedModelLite.modelName` (line 1059) says "Only one of model_name and entity_name should be populated"; same for `modelVersion`/`entityVersion`. So `ServedModel.modelName`/`modelVersion` are legacy fields that mirror `entityName`/`entityVersion`. They are completely undocumented inside `ServedModel` (lines 1032-1033 are bare fields with no comment), so a TS user has no way to know they are deprecated. This is *the same* duplication as #3, but at the field level. - **Category:** 12 (duplicate concept), 6 (misleading), 19 (underspecified — bare fields with no docs). - **Suggested name:** Mark `modelName` / `modelVersion` as `@deprecated`. The JSDoc on `ServedModelLite` should be promoted to a real type-level note. Wire keys remain. - **Rationale:** Public surface area duplicating itself is *the* common source of integration bugs. @@ -45,14 +49,14 @@ - **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. - **Rationale:** Enum names that include the response-DTO shape (`Detailed`) tangle the message identity into the type identity. In TS, the enum represents a concept, not the message it appears in. -### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:487` +### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:587` - **Why weird:** `httpRequest` on a `Client` for *model-serving management* is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. - **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). - **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. - **Rationale:** A method called `httpRequest` on a `ServingEndpointsClient` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. -### 7. `ExternalFunctionRequest` doc says "Simple Proto message for testing" — `src/v1/model.ts:425` -- **Why weird:** Public type carries the JSDoc comment "Simple Proto message for testing". Either the type is for testing (in which case it should not be exported) or it is production (in which case the doc lies). Given it is wired to a real REST URL and exported via `index.ts:46`, the doc is a lie. +### 7. `ExternalFunctionRequest` doc says "Simple Proto message for testing" — `src/v1/model.ts:438` +- **Why weird:** Public type carries the JSDoc comment "Simple Proto message for testing". Either the type is for testing (in which case it should not be exported) or it is production (in which case the doc lies). Given it is wired to a real REST URL and exported via `index.ts`, the doc is a lie. - **Category:** 6 (misleading — public doc text contradicts the exported reality). - **Suggested name:** Fix the JSDoc: "Request for `Client.httpRequest`: invoke an external service through a UC Connection." Keep type name `ExternalFunctionRequest` for now (paired with the rename in #6). - **Rationale:** Doc bugs on exported identifiers are as serious as the identifier itself. @@ -72,12 +76,12 @@ - `ApiKey`, `apiKeyAuth` — `Api` title-cased. - `ARN`-related: `instanceProfileArn`, `Arn` is suffix-cased. - `Url`, `endpointUrl`, `customProviderUrl` — `Url` title-cased. - - `OpenAi` (line 699) vs `openai` (line 462, 492, 1336, 2135, 2245) — `openai` is all lower-case in *some* discriminator keys. + - `OpenAi` (line 743) vs `openai` (lines 505, 1399) — `openai` is all lower-case in *some* discriminator keys. - **Category:** 3 (acronym casing inconsistencies — the audit prompt's exemplar). - **Suggested name:** Decide a project-wide rule in `typescript.mdc`. The Microsoft .NET capitalization guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) say to title-case two-letter acronyms (`IO`) and PascalCase three-plus-letter acronyms (`Xml`); the Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) says to treat acronyms as whole words. Either is defensible; *none* should be mixed in one file. The current state has at least four different rules co-existing. - **Rationale:** Twenty-five exported identifiers from one file vary in convention. This is the single biggest *category* of weirdness in the package. -### 9. `openai` discriminator key lowercase while sibling keys are camelCase — `src/v1/model.ts:492-495, 2135-2137` +### 9. `openai` discriminator key lowercase while sibling keys are camelCase — `src/v1/model.ts:505-507, 1399-1401` - **Why weird:** Inside `ExternalModel.config` discriminated union, the eight `$case` values are: `ai21labsConfig`, `anthropicConfig`, `amazonBedrockConfig`, `cohereConfig`, `googleCloudVertexAiConfig`, `databricksModelServingConfig`, `openaiConfig`, `palmConfig`, `customProviderConfig`. Seven of nine use the standard `Config` camelCase. The two outliers are: - `ai21labsConfig` (the product is "AI21 Labs"; the discriminator collapses to `ai21labs` — all lower-case middle), and - `openaiConfig` (the product is "OpenAI"; the discriminator collapses to `openai` — lower-case middle), and @@ -88,59 +92,32 @@ - **Rationale:** The discriminator string is the *runtime* value clients must match against; an inconsistent rule means clients can't programmatically map provider name → discriminator. ### 10. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` -- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 834). A consumer importing `Behavior` from `@databricks/sdk-modelservingmanagement/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `BEHAVIOR_UNSPECIFIED | NONE | BLOCK | MASK` — so this is *PII action behavior*. +- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 878). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `BEHAVIOR_UNSPECIFIED | NONE | BLOCK | MASK` — so this is *PII action behavior*. - **Category:** 1 (vague/generic), 15 (generic name losing meaning). - **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. - **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. -### 11. `Route` field carries `servedModelName` AND `servedEntityName` — `src/v1/model.ts:952-958` -- **Why weird:** `Route` has three fields: `servedModelName?: string`, `trafficPercentage?: number`, `servedEntityName?: string`. There is no JSDoc on `servedEntityName` — it is silently the modern name; `servedModelName` is the legacy. Two fields point at the same logical thing (the entity to route traffic to), one without docs, one with docs that only mention "served model" (line 953). Same bug class as #3 and #4. +### 11. `Route` field carries `servedModelName` AND `servedEntityName` — `src/v1/model.ts:996-1002` +- **Why weird:** `Route` has three fields: `servedModelName?: string`, `trafficPercentage?: number`, `servedEntityName?: string`. There is no JSDoc on `servedEntityName` — it is silently the modern name; `servedModelName` is the legacy. Two fields point at the same logical thing (the entity to route traffic to), one without docs, one with docs that only mention "served model" (line 997). Same bug class as #3 and #4. - **Category:** 12 (duplicate concept), 6 (misleading), 19 (undocumented field). - **Suggested name:** Mark `servedModelName` `@deprecated`; doc `servedEntityName` properly. - **Rationale:** Triple bug: undocumented field, duplicate concept, no deprecation marker. ## Medium severity -### 12. Redundant enum prefixes — `src/v1/model.ts:5-52` -- **Why weird:** Three enums duplicate the enum name in every value: - - `Behavior.BEHAVIOR_UNSPECIFIED` (line 6) - - `ServedModelDeploymentState.DEPLOYMENT_*` (lines 13-19) — six values, every one starts with `DEPLOYMENT_`. - - `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED` (line 30) — the `HTTP_METHOD_` prefix is doubled because the enum is *already* named `HttpMethod`. - - `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED` (line 40) — three layers of redundancy. - - `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED` (line 49) — two layers. - - At the call site you write `Behavior.BEHAVIOR_UNSPECIFIED`, `ServedModelDeploymentState.DEPLOYMENT_READY`. TS enums are already namespaced. -- **Category:** 2 (redundant enum prefixes), 18 (long enum values). -- **Suggested name:** Drop the redundant prefix: `Behavior.UNSPECIFIED`, `ServedModelDeploymentState.CREATING/RECOVERING/READY/FAILED/ABORTED/STOPPED`, `HttpMethod.GET/POST/...` (already correct for non-UNSPECIFIED), `ConfigUpdateState.NOT_UPDATING/IN_PROGRESS/...`, `ReadyState.READY/NOT_READY`. -- **Rationale:** `ServedModelDeploymentState.DEPLOYMENT_READY` is twelve characters of redundant prefix per value. - -### 13. `*_UNSPECIFIED` / `*_UNKNOWN` sentinel zero-values inconsistent — `src/v1/model.ts:6, 13, 30, 40, 49` -- **Why weird:** Five enums each declare a zero-value sentinel: - - `Behavior.BEHAVIOR_UNSPECIFIED` - - `ServedModelDeploymentState.DEPLOYMENT_UNKNOWN` (variant: uses `UNKNOWN` not `UNSPECIFIED`!) - - `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED` - - `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED` - - `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED` - - `ServingEndpointDetailedPermissionLevel` — *no* unspecified member (the only enum without one). - - TS uses `undefined` for "not set"; the sentinel value is redundant. Worse, two different conventions exist (`*_UNSPECIFIED` vs `DEPLOYMENT_UNKNOWN`) — there is no even consistency among the unspecified members themselves. -- **Category:** 17 (inconsistent `UNSPECIFIED`/`UNKNOWN`), 18 (long enum values). -- **Suggested name:** Drop the zero-value sentinels; rely on `field?: EnumType | undefined`. If kept, normalize all to one convention (`UNSPECIFIED` per AIP-126: https://google.aip.dev/126). -- **Rationale:** Sentinel zero-values exist only to round-trip default-zero semantics, which the wire JSON does not need. - -### 14. `ServedModelDeploymentState` enum name contains `Deployment` AND values are `DEPLOYMENT_*` AND it lives on `ServedModelState.deployment` — `src/v1/model.ts:12, 1025-1028` -- **Why weird:** Triple redundancy: the type is `ServedModelDeploymentState`, the field is `ServedModelState.deployment: ServedModelDeploymentState`, the values are `DEPLOYMENT_*`. At a call site: `state.deployment === ServedModelDeploymentState.DEPLOYMENT_READY` — the word "deployment" appears three times. -- **Category:** 2 (redundant enum prefix), 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). -- **Suggested name:** Drop `Deployment` from the enum name (`ServedModelState`); drop `DEPLOYMENT_` from values. Field becomes `state.deployment === ServedModelState.READY`. But that collides with the *type* name `ServedModelState` (which wraps both `deployment` and `deploymentStateMessage`). Hence: rename type `ServedModelState` → `ServedModelDeployment`, and enum `ServedModelDeploymentState` → `DeploymentState`. Now: `served.state.deployment === DeploymentState.READY`. Clean. -- **Rationale:** The current names tangle three concepts in a way that resists reading. - -### 15. `InferenceEndpointState_ConfigUpdateState` redundant value prefixes — `src/v1/model.ts:38-45` -- **Why weird:** Redundant value prefixes (`CONFIG_UPDATE_STATE_UNSPECIFIED`) — see #12, #13. Used as `state.configUpdate: InferenceEndpointState_ConfigUpdateState` (line 660). Call site: `inferenceEndpoint.state.configUpdate === InferenceEndpointState_ConfigUpdateState.UPDATE_FAILED` — long to ask "is it failed?". -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** Values without prefix: `NOT_UPDATING | IN_PROGRESS | UPDATE_FAILED | UPDATE_CANCELED`. (Note `UPDATE_FAILED` keeps the `UPDATE_` because there are multiple state-like enums; otherwise just `FAILED`.) -- **Rationale:** Cuts the call-site length substantially. - -### 16. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:377, 393, 411` +### 12. `UNKNOWN` vs `UNSPECIFIED` zero-value naming inconsistent across enums — `src/v1/model.ts:6, 13, 30, 40, 49` +- **Why weird:** Four enums spell the zero-value sentinel `*_UNSPECIFIED` (`Behavior.BEHAVIOR_UNSPECIFIED`, `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED`, `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED`, `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED`), but `ServedModelDeploymentState.DEPLOYMENT_UNKNOWN` (line 13) uses `UNKNOWN` instead. One file, two conventions for the same concept. +- **Category:** 17 (inconsistent `UNSPECIFIED`/`UNKNOWN`). +- **Suggested name:** Normalize the outlier: rename `DEPLOYMENT_UNKNOWN` → `DEPLOYMENT_STATE_UNSPECIFIED` (per AIP-126: https://google.aip.dev/126). +- **Rationale:** Two spellings for the same sentinel concept across sibling enums in a single file is a pure inconsistency, independent of whether the sentinel itself should exist. + +### 13. `ServedModelDeploymentState` enum name collides with parent `ServedModelState` type — `src/v1/model.ts:12, 1069-1072` +- **Why weird:** The enum type is `ServedModelDeploymentState`, and it lives on the field `ServedModelState.deployment: ServedModelDeploymentState`. Two different types both end in `State`, one wraps the other, and the wrapper field (`deployment`) shares its name with the inner enum's category. The result reads as `served.state.deployment` returning a `ServedModelDeploymentState` — the wrapper and the enum sound like the same thing. +- **Category:** 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). +- **Suggested name:** Rename the type `ServedModelState` → `ServedModelDeployment`, and the enum `ServedModelDeploymentState` → `DeploymentState`. Call site becomes `served.state.deployment === DeploymentState.READY`. The container and the discriminant no longer share a noun. +- **Rationale:** Two `*State` siblings nested inside each other tangle the wrapper identity with the discriminant identity. + +### 14. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:376, 392, 410` - **Why weird:** Three types describe "the config of a serving endpoint": - `EndpointCoreConfig`: input shape (`servedEntities: ServedModel[]`, `servedModels: ServedModel[]`, `trafficConfig`, `autoCaptureConfig`). - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. @@ -151,69 +128,69 @@ - **Suggested name:** Either (a) collapse into one type with optional fields, or (b) give the types names that reflect their *purpose*: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). - **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. -### 17. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:580, 609` +### 15. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:624, 653` - **Why weird:** Two near-duplicate types: - - `InferenceEndpoint` (line 580-607): used in `ListInferenceEndpoints_Response.endpoints`. Has 13 fields. - - `InferenceEndpointDetailed` (line 609-646): returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. Has 18 fields. + - `InferenceEndpoint` (lines 624-651): used in `ListInferenceEndpointsRequest_Response.endpoints`. Has 14 fields. + - `InferenceEndpointDetailed` (lines 653-690): returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. Has 18 fields. The "Detailed" version adds `pendingConfig`, `permissionLevel`, `routeOptimized`, `endpointUrl`, `dataPlaneInfo`, `emailNotifications` and changes `config` from `EndpointCoreConfigSummary` to `EndpointCoreConfigOutput`. So `InferenceEndpoint` is really the *list-summary* projection, but its name says "the endpoint". `InferenceEndpointDetailed` is *the* endpoint, but its name says "more detail than usual". - **Category:** 12 (duplicate concept), 7 (overly verbose suffix), 17 (inconsistent: which one is "the endpoint"?). - **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. - **Rationale:** Currently consumers writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. -### 18. `ServedModelLite` lite-variant — `src/v1/model.ts:1013-1023` -- **Why weird:** Same pattern as #17 at the entity level. `ServedModel` (line 960) has 21 fields. `ServedModelLite` (line 1013-1023) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). +### 16. `ServedModelLite` lite-variant — `src/v1/model.ts:1057-1067` +- **Why weird:** Same pattern as #15 at the entity level. `ServedModel` (line 1004) has 23 fields. `ServedModelLite` (lines 1057-1067) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). - **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). - **Suggested name:** `ServedEntitySummary` (paired with #2 type rename). - **Rationale:** Inconsistent suffix convention across the file. "Lite" is also an LLM-era term that clashes with the OpenAI/Anthropic-flavoured product space. -### 19. `Pt` abbreviation everywhere — `src/v1/client.ts:137, 162, 415, 440` and `src/v1/model.ts:295, 837, 843, 937` -- **Why weird:** `Pt` is short for "provisioned throughput". The full term ("provisioned throughput") *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`), but the request/response *types* use the abbreviation (`CreatePtEndpoint`, `PutPtEndpointConfig`, `PtEndpointCoreConfig`, `PtServedModel`). So the public surface has: - - `client.createProvisionedThroughputInferenceEndpoint(req: CreatePtEndpoint)` — method-full, type-abbreviated. +### 17. `Pt` abbreviation everywhere — `src/v1/client.ts:148, 173, 515, 540` and `src/v1/model.ts:294, 881, 887, 981` +- **Why weird:** `Pt` is short for "provisioned throughput". The full term ("provisioned throughput") *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`), but the request/response *types* use the abbreviation (`CreatePtEndpointRequest`, `PutPtEndpointConfigRequest`, `PtEndpointCoreConfig`, `PtServedModel`). So the public surface has: + - `client.createProvisionedThroughputInferenceEndpoint(req: CreatePtEndpointRequest)` — method-full, type-abbreviated. - URL: `/api/2.0/serving-endpoints/pt` — wire-abbreviated. Three different names for one concept, in one call. - **Category:** 5 (cryptic abbreviation), 17 (inconsistent abbreviation across method/type/URL). -- **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpoint`, `PutProvisionedThroughputEndpointConfig`, etc. — long but searchable) or contract all (`createPtEndpoint`, `putPtEndpointConfig` — short but cryptic). Pick one. The current half-and-half is the worst option. +- **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpointRequest`, `PutProvisionedThroughputEndpointConfigRequest`, etc. — long but searchable) or contract all (`createPtEndpoint`, `putPtEndpointConfig` — short but cryptic). Pick one. The current half-and-half is the worst option. - **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). -### 20. `CreatePtEndpoint` method-type asymmetry with `CreateInferenceEndpoint` — `src/v1/model.ts:272, 295` +### 18. `CreatePtEndpointRequest` method-type asymmetry with `CreateInferenceEndpointRequest` — `src/v1/model.ts:271, 294` - **Why weird:** Sister request types: - - `CreateInferenceEndpoint` (full name). - - `CreatePtEndpoint` (abbreviated). + - `CreateInferenceEndpointRequest` (full name). + - `CreatePtEndpointRequest` (abbreviated). - The PT variant is *not* called `CreateProvisionedThroughputInferenceEndpoint`; it is `CreatePtEndpoint`. The non-PT variant is not called `CreateEndpoint`; it is `CreateInferenceEndpoint`. So one type carries the qualifier `Inference`, the other carries the qualifier `Pt`. Mixed metaphor. + The PT variant is *not* called `CreateProvisionedThroughputInferenceEndpointRequest`; it is `CreatePtEndpointRequest`. The non-PT variant is not called `CreateEndpointRequest`; it is `CreateInferenceEndpointRequest`. So one type carries the qualifier `Inference`, the other carries the qualifier `Pt`. Mixed metaphor. - **Category:** 17 (inconsistent qualifier choice). -- **Suggested name:** `CreateServingEndpoint` and `CreateProvisionedThroughputServingEndpoint` (paired with #1). +- **Suggested name:** `CreateServingEndpointRequest` and `CreateProvisionedThroughputServingEndpointRequest` (paired with #1). - **Rationale:** Sibling request types should differ only in the qualifier that actually differs. -### 21. `PutInferenceEndpointConfig` vs `PutPtEndpointConfig` — request shape divergence — `src/v1/model.ts:906, 937` +### 19. `PutInferenceEndpointConfigRequest` vs `PutPtEndpointConfigRequest` — request shape divergence — `src/v1/model.ts:950, 981` - **Why weird:** Two "put endpoint config" requests: - - `PutInferenceEndpointConfig`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). - - `PutPtEndpointConfig`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). + - `PutInferenceEndpointConfigRequest`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). + - `PutPtEndpointConfigRequest`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). - Same operation conceptually, two different request shapes. The naming makes both look symmetric (`Put*EndpointConfig`), but they are not. + Same operation conceptually, two different request shapes. The naming makes both look symmetric (`Put*EndpointConfigRequest`), but they are not. - **Category:** 17 (inconsistent shape with consistent naming — worst case for the reader). - **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. - **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. -### 22. `PatchInferenceEndpointTags.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:792-799` +### 20. `PatchInferenceEndpointTagsRequest.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:836-843` - **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. That semantics is fine, but the field name does not convey it. - **Category:** 6 (misleading), 15 (generic field name). - **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). - **Rationale:** When the element type changes, the field name should change too. -### 23. `endpointUrl` field domain ambiguity — `src/v1/model.ts:634, 332` +### 21. `endpointUrl` field domain ambiguity — `src/v1/model.ts:679, 331` - **Why weird:** `endpointUrl` appears twice: - - `InferenceEndpointDetailed.endpointUrl` (line 634): "Endpoint invocation url if route optimization is enabled for endpoint." - - `DataPlaneInfo.endpointUrl` (line 332): "The URL of the endpoint for this operation in the dataplane." + - `InferenceEndpointDetailed.endpointUrl` (line 679): "Endpoint invocation url if route optimization is enabled for endpoint." + - `DataPlaneInfo.endpointUrl` (line 331): "The URL of the endpoint for this operation in the dataplane." Same field name, two completely different URLs (one is the public invocation URL; the other is the data-plane endpoint for one specific operation). Compare with #15 in the audit prompt: generic field names lose meaning across structs. - **Category:** 15 (generic field name across types), 17 (inconsistent usage). - **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). - **Rationale:** A consumer JOINing the two by `endpointUrl` field name will mismatch them. -### 24. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:581-596, 610-625` +### 22. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:625-640, 654-669` - **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." @@ -223,19 +200,19 @@ - **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. - **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources (e.g. logs that include a `name` that is something else entirely). -### 25. Waiter classes have asymmetric naming — `src/v1/client.ts:515, 595, 675, 755` +### 23. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` - **Why weird:** Four waiter classes: - `CreateInferenceEndpointWaiter` - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters — the longest exported class in the file) - `PutInferenceEndpointConfigWaiter` - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) - Two problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #19 where the type is `Pt`). Sibling request types should differ only in the qualifier that actually differs. + Two problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #17 where the type is `Pt`). Sibling request types should differ only in the qualifier that actually differs. - **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). - **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. - **Rationale:** Four exported waiter classes, each 30+ characters long, each containing five+ identical method-name prefixes that grep the same way as the methods themselves. -### 26. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:571-592, 651-672, 731-752, 811-832` +### 24. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -246,18 +223,30 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 27. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:72` +### 25. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` - **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. - **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). - **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). - **Rationale:** Minor; internal. -### 28. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:943-950, 93-107` -- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:383 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #16: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. +### 26. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:987-994, 93-107` +- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:483 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #14: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. - **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). -- **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimits*` types `@deprecated` in JSDoc. +- **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimitsRequest*` types `@deprecated` in JSDoc. - **Rationale:** Same pattern repeated; same fix. +### 27. `ExportMetricsResponse` JSDoc leaks `Proto` / `Rpc` / `JettyRPC` architecture — `src/v1/model.ts:424-434` +- **Why weird:** The JSDoc on this public exported type reads: "Proto version of com.databricks.rpc.HttpOverRpcResponse. This message can be specially handled in UnaryRpcService with JettyRPC when the advanced feature CustomHandlingForHttpOverRpcProtoResponse is enabled - bypass the RPC serializer and populate HTTP status, response headers and response body from the proto message directly." Five internal architectural concepts (`Proto`, `Rpc`/`RPC`, `UnaryRpcService`, `JettyRPC`, `CustomHandlingForHttpOverRpcProtoResponse`) are dumped into the public docs of a TS type that just carries a `ReadableStream`. The TS consumer has no need to know that `ExportMetricsResponse` is a "Proto version of com.databricks.rpc.HttpOverRpcResponse" — that is a backend impl detail. The type name itself is fine; the doc is the leak. +- **Category:** Proto-architectural leak (in JSDoc), 6 (misleading — public doc surfaces backend internals). +- **Suggested name:** Keep type name `ExportMetricsResponse`. Rewrite the JSDoc to describe the user-facing shape: "Streaming response from `Client.getExportEndpointMetrics`. The body is a Prometheus-format text stream." Strip every `Proto`/`Rpc`/`Jetty*` reference. +- **Rationale:** Public docs that name internal RPC infrastructure leak the implementation strategy into the SDK surface. SDK consumers should never read "JettyRPC" or "UnaryRpcService" in IDE tooltips. + +### 28. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` architectural placeholder — `src/v1/model.ts:737-740` +- **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field (`queryInfo`), so the wrapping is a pure architectural placeholder reserved for future operations. The repeated `Info` suffix is the architectural-leak signal: two `*Info` siblings, one nested in the other, neither carrying real "info" of its own (one is a one-field wrapper, the other is two URL strings). The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. +- **Category:** Proto-architectural leak (`Info`-suffix duplication as structural placeholder), 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). +- **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a second field then. Or rename the wrapper to `ModelDataPlanes` (plural noun) and drop the `Info` suffix on both. +- **Rationale:** `Info`-wrapping-`Info` is the same pattern as `*Spec.spec` or `*Config.config` proto idioms — an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. + ## Low severity ### 29. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` @@ -293,27 +282,39 @@ - **Suggested name:** No rename; flag as generator review. - **Rationale:** Names look clean; runtime is fragile. -### 35. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:456` -- **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 962). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). +### 35. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:469` +- **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 1006). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). - **Category:** 1 (vague), 15 (generic name across types). - **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. - **Rationale:** Disambiguates from `ServedModel.name`. -### 36. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:454` +### 36. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` - **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. - **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). - **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. - **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. -### 37. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:977` +### 37. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` - **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #36: a string field with a documented but unenforced enum. - **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). - **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). - **Rationale:** Type-narrowing fix; minor. +### 38. `ExternalFunctionRequest` JSDoc literally says "Simple Proto message for testing" — `src/v1/model.ts:438` +- **Why weird:** Cross-references #7 (the doc lying about "for testing"). The proto-architectural angle is sharper here: the word `Proto` itself should not appear in any TS-facing JSDoc. The TS SDK does not transport protobuf, does not use proto codegen at the consumer surface, and the consumer cannot act on the fact that the wire shape originated as a proto. The doc is a verbatim copy from the proto IDL comment that escaped through the generator. +- **Category:** Proto-architectural leak (in JSDoc). +- **Suggested name:** Rewrite the JSDoc (see #7 for proposed user-facing text). Strip the word `Proto`. +- **Rationale:** Same as #27 and #39; proto vocabulary is a backend-team artifact and should be stripped before public docs are emitted. + +### 39. `GetOpenApiResponse` JSDoc says "The top level proto message" — `src/v1/model.ts:555` +- **Why weird:** The JSDoc reads "The top level proto message that represents an OpenAPI 3.0 document." Same pattern as #27 and #38: the doc tells the TS consumer that the type originated as a proto message. The TS type itself is just `{contents?: ReadableStream}` — a stream of OpenAPI 3.0 JSON. The consumer has zero use for the "proto message" framing. The `OpenApi` in the type name is fine (it is the user-facing payload); the word `proto` in the doc is the leak. +- **Category:** Proto-architectural leak (in JSDoc). +- **Suggested name:** Rewrite the JSDoc: "Streaming response from `Client.getInferenceEndpointSchema`. The body is the endpoint's OpenAPI 3.0 schema as JSON." +- **Rationale:** Strip proto vocabulary from public docs. + ## Observations -### 38. Mixed naming convention for the same product across three sibling packages +### 40. Mixed naming convention for the same product across three sibling packages The Databricks "Serving Endpoints" product spans three packages in this SDK: - `modelservingmanagement`: types use `InferenceEndpoint*`. - `modelservingdebug`: types use `Endpoint` (e.g. `GetExportEndpointMetrics`). @@ -322,16 +323,17 @@ The Databricks "Serving Endpoints" product spans three packages in this SDK: No two packages agree on the noun. The wire uniformly uses `serving-endpoints`. SDK consumers chaining all three packages will see three different names for one concept. - **Category:** 17 (cross-package inconsistency). -### 39. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 41. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` Same as customllms #28 — every generated package carries this unused export. -### 40. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:67` +### 42. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:75` Same as customllms #24 — internal user-agent constant. -### 41. `Headers` constructor used four times in client.ts — `src/v1/client.ts:108, 145, 184, 213, ...` -Each method instantiates a `new Headers({'Content-Type': 'application/json'})` then `.set('User-Agent', this.userAgent)`. Naming-wise this is fine (Headers is the standard web API name), but the pattern is duplicated 11 times in the file. Not a naming bug; observation only. +### 43. `Headers` constructor used many times in client.ts — `src/v1/client.ts:119, 156, 195, 223, ...` +Each method instantiates a `new Headers({'Content-Type': 'application/json'})` or `new Headers()` then `.set('User-Agent', this.userAgent)`. Naming-wise this is fine (Headers is the standard web API name), but the pattern is duplicated 16+ times in the file. Not a naming bug; observation only. - **Category:** 12 (duplicate pattern across methods). + ## Domain glossary - `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names, abbreviated in type names. - `ai gateway` — A Databricks-internal proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. @@ -345,7 +347,16 @@ Each method instantiates a `new Headers({'Content-Type': 'application/json'})` t - `provider` enum keys (`ai21labs`, `anthropic`, `amazon-bedrock`, `cohere`, `databricks-model-serving`, `google-cloud-vertex-ai`, `openai`, `palm`, `custom`) — kebab-case on the wire, `Config` camelCase in TS. ## File coverage -- `src/v1/model.ts` (2495 lines): read fully. -- `src/v1/client.ts` (834 lines): read fully. -- `src/v1/utils.ts` (186 lines): read fully. -- `src/v1/index.ts` (87 lines): read fully. +- `src/v1/model.ts` (2556 lines): read fully. +- `src/v1/client.ts` (933 lines): read fully. +- `src/v1/utils.ts` (185 lines): read fully. +- `src/v1/index.ts` (92 lines): read fully. +- `src/v1/transport.ts` (75 lines): new file in regeneration; read fully. + +## Fixed + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. + +Earlier note (pre-2026-05-22): The 2026-05-20 regeneration renamed the package directory (`modelservingmanagement` → `modelserving`) and appended a `Request` suffix to many request DTOs (`CreateInferenceEndpoint` → `CreateInferenceEndpointRequest`, `CreatePtEndpoint` → `CreatePtEndpointRequest`, `PutInferenceEndpointConfig` → `PutInferenceEndpointConfigRequest`, `PutPtEndpointConfig` → `PutPtEndpointConfigRequest`, `PatchInferenceEndpointTags` → `PatchInferenceEndpointTagsRequest`, `PutInferenceEndpointAiGateway` → `PutInferenceEndpointAiGatewayRequest`, `PutInferenceEndpointRateLimits` → `PutInferenceEndpointRateLimitsRequest`, `UpdateInferenceEndpointNotifications` → `UpdateInferenceEndpointNotificationsRequest`, `DeleteInferenceEndpoint` → `DeleteInferenceEndpointRequest`, `GetInferenceEndpoint` → `GetInferenceEndpointRequest`, `GetInferenceEndpointSchema` → `GetInferenceEndpointSchemaRequest`, `GetExportEndpointMetrics` → `GetExportEndpointMetricsRequest`, `GetServedModelBuildLogs` → `GetServedModelBuildLogsRequest`, `GetServedModelLogs` → `GetServedModelLogsRequest`, `ListInferenceEndpoints` → `ListInferenceEndpointsRequest`). None of the existing findings were resolved by these renames — the underlying naming concerns (Pt vs ProvisionedThroughput inconsistency #17/#18, divergent request shapes #19, addTags/deleteTags semantics #20, deprecated `RateLimit` #26) all carry over to the suffixed names unchanged. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index 10bf1bdf..9bfa889c 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -11,7 +11,7 @@ **Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. -**Total weird names flagged:** 31 +**Total weird names flagged:** 30 --- @@ -20,36 +20,35 @@ | # | Severity | Location | Name | Category | |----|----------|-----------------------------------|--------------------------------------------------------------|----------------------------------------------| | 1 | High | package + dir | `modelservingquery` / `@databricks/sdk-modelservingquery` | Duplicate concept; "query" overloaded SDK-wide | -| 2 | High | `model.ts` interface | `QueryEndpointInput` / `QueryEndpointResponse` | Vague; mixes verb-as-noun ("Query") and 4 unrelated payload shapes | -| 3 | High | `model.ts` field | `QueryEndpointInput.name` | Generic field name losing meaning (= endpoint name) | -| 4 | High | `model.ts` field | `QueryEndpointInput.input` / `inputs` / `instances` / `prompt` / `messages` / `dataframeRecords` / `dataframeSplit` | 7 mutually-exclusive "input" fields, no oneof | -| 5 | High | `model.ts` field | `QueryEndpointInput.n` | Cryptic abbreviation (single letter) | -| 6 | High | `model.ts` enum | `EmbeddingsV1ResponseEmbeddingElementObject` | Overly verbose (5 nouns + version + suffix) | -| 7 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name | -| 8 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked + redundant word ("Embedding Element") | -| 9 | High | `model.ts` enum value | `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` | Enum value = type prefix; tautology | -| 10 | High | `model.ts` enum values | `CHAT_MESSAGE_ROLE_UNSPECIFIED` / `QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED` / `EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED` | Long enum values (proto sentinel leak) | -| 11 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | -| 12 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | -| 13 | Medium | `model.ts` interface | `DataframeSplitInput` | Generic field names lose meaning (`index`, `columns`, `data`) | -| 14 | Medium | `model.ts` field | `QueryEndpointResponse.data` | Vague (it's the *embeddings* array, not arbitrary data) | -| 15 | Medium | `model.ts` field | `QueryEndpointResponse.object` | Reserved-word collision (`Object` is a JS built-in) | -| 16 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | -| 17 | Medium | `model.ts` field | `QueryEndpointResponse.created` | Verb-tense / underspecified ("created" timestamp typed as `number`) | -| 18 | Medium | `model.ts` field | `QueryEndpointResponse.servedModelName` | Generic name (wire form `served-model-name` with hyphen) | -| 19 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | -| 20 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | -| 21 | Medium | `model.ts` field | `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` | Type-suffix tautology — every field carries `Tokens` | -| 22 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | -| 23 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | -| 24 | Medium | `model.ts` field | `QueryEndpointInput.stop` | Reserved-word feel (verb-as-noun used as field) | -| 25 | Medium | `model.ts` field | `QueryEndpointInput.stream` | Reserved-word feel (collides with web-stream `ReadableStream`) and field is `boolean`, not a stream | -| 26 | Medium | `model.ts` field | `QueryEndpointInput.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | -| 27 | Medium | `model.ts` field | `QueryEndpointInput.usageContext` | Vague pair with `extraParams`; both `Record` | -| 28 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | -| 29 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | -| 30 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | -| 31 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | +| 2 | High | `model.ts` interface | `QueryEndpointInputRequest` / `QueryEndpointResponse` | Four unrelated payload shapes packed into one type; double-suffix `Input` + `Request` | +| 3 | High | `model.ts` field | `QueryEndpointInputRequest.name` | Generic field name losing meaning (= endpoint name) | +| 4 | High | `model.ts` field | `QueryEndpointInputRequest.input` / `inputs` / `instances` / `prompt` / `messages` / `dataframeRecords` / `dataframeSplit` | 7 mutually-exclusive "input" fields, no oneof | +| 5 | High | `model.ts` field | `QueryEndpointInputRequest.n` | Cryptic abbreviation (single letter) | +| 6 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name; empty `Element` suffix | +| 7 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked into type name; empty `Element` suffix | +| 8 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | +| 9 | High | `model.ts` interface | `QueryEndpointInputRequest_ExtraParamsEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | +| 10 | High | `model.ts` interface | `QueryEndpointInputRequest_UsageContextEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | +| 11 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | +| 12 | Medium | `model.ts` interface | `DataframeSplitInput` | Generic field names lose meaning (`index`, `columns`, `data`) | +| 13 | Medium | `model.ts` field | `QueryEndpointResponse.data` | Vague (it's the *embeddings* array, not arbitrary data) | +| 14 | Medium | `model.ts` field | `QueryEndpointResponse.object` | Reserved-word collision (`Object` is a JS built-in) | +| 15 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | +| 16 | Medium | `model.ts` field | `QueryEndpointResponse.created` | Verb-tense / underspecified ("created" timestamp typed as `number`) | +| 17 | Medium | `model.ts` field | `QueryEndpointResponse.servedModelName` | Generic name (wire form `served-model-name` with hyphen) | +| 18 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | +| 19 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | +| 20 | Medium | `model.ts` field | `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` | Type-suffix tautology — every field carries `Tokens` | +| 21 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | +| 22 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | +| 23 | Medium | `model.ts` field | `QueryEndpointInputRequest.stop` | Reserved-word feel (verb-as-noun used as field) | +| 24 | Medium | `model.ts` field | `QueryEndpointInputRequest.stream` | Reserved-word feel (collides with web-stream `ReadableStream`) and field is `boolean`, not a stream | +| 25 | Medium | `model.ts` field | `QueryEndpointInputRequest.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | +| 26 | Medium | `model.ts` field | `QueryEndpointInputRequest.usageContext` | Vague pair with `extraParams`; both `Record` | +| 27 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | +| 28 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 29 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | +| 30 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | --- @@ -78,14 +77,14 @@ The Go SDK calls the corresponding service `serving.QueryEndpoint` (a verb-prefi The package name is the most consequential naming choice in the audit; every type below inherits its ambiguity. -### 2. `QueryEndpointInput` / `QueryEndpointResponse` — vague type name + verb-as-noun +### 2. `QueryEndpointInputRequest` / `QueryEndpointResponse` — four payload shapes packed into one type + double suffix **Location:** `src/v1/model.ts:76-139`, `153-183` -**Categories:** 1 (vague), 7 (overly verbose), 14 (Go/Java-style) +**Categories:** 1 (vague), 8 (redundant suffixes), 14 (Go/Java-style) ```ts -export interface QueryEndpointInput { +export interface QueryEndpointInputRequest { name?: string | undefined; prompt?: JsonValue | undefined; input?: JsonValue | undefined; @@ -101,13 +100,13 @@ The single request type encodes **four** different request shapes: - **Embeddings:** `input`, `extraParams`. - **Traditional ML:** `dataframeRecords` / `dataframeSplit` / `instances` / `inputs`. -`QueryEndpointInput` is the *whole envelope*, not a single input. The name says "input" but the field `input` also exists, and `inputs` exists, and `instances` exists. The user constructing this type has to know which combination is valid — TS gives no help. +`QueryEndpointInputRequest` carries **two** request-shaped suffixes back to back: `Input` and `Request`. Both are noise. The name says "input" but the field `input` also exists, and `inputs` exists, and `instances` exists. The user constructing this type has to know which combination is valid — TS gives no help. The fresh `Request` suffix (added in regeneration) doesn't disambiguate the four shapes; it just makes the type name longer. Better: split into `ChatQueryRequest`, `CompletionsQueryRequest`, `EmbeddingsQueryRequest`, `TraditionalModelQueryRequest`, and have the client expose four methods (or a discriminated union). `QueryEndpointResponse` has the same problem in mirror image: `choices` (chat/completions), `data` (embeddings), `predictions` (traditional), `outputs` (feature serving). The Go SDK has the same union, so the smell is inherited from the wire protocol. -### 3. `QueryEndpointInput.name` — generic field name losing meaning +### 3. `QueryEndpointInputRequest.name` — generic field name losing meaning **Location:** `src/v1/model.ts:77-78` @@ -118,7 +117,7 @@ Better: split into `ChatQueryRequest`, `CompletionsQueryRequest`, `EmbeddingsQue name?: string | undefined; ``` -`name` on a `QueryEndpointInput` is unrelated to the *model* name, the *served-model* name (which appears in the response), the *user* name, or the *organisation* name — it's specifically the *serving endpoint* name, which then becomes a URL path segment. JSDoc clarifies but the field doesn't. `endpointName` would match the existing `servedModelName` field in `QueryEndpointResponse`. Also: the field is typed `string | undefined` but is required by JSDoc — and the client falls back to `req.name ?? ''`, silently producing a malformed URL when missing. +`name` on a `QueryEndpointInputRequest` is unrelated to the *model* name, the *served-model* name (which appears in the response), the *user* name, or the *organisation* name — it's specifically the *serving endpoint* name, which then becomes a URL path segment. JSDoc clarifies but the field doesn't. `endpointName` would match the existing `servedModelName` field in `QueryEndpointResponse`. Also: the field is typed `string | undefined` but is required by JSDoc — and the client falls back to `req.name ?? ''`, silently producing a malformed URL when missing. ### 4. Seven mutually-exclusive "input" fields with no discriminator @@ -140,7 +139,7 @@ Note the singular/plural near-collision `input` (embeddings) vs `inputs` (tensor A user writing TS sees seven optional fields and has to read four JSDoc paragraphs to figure out which one to set. A discriminated union (`payload: { kind: 'chat'; messages: ... } | { kind: 'completions'; prompt: ... } | ...`) would make invalid combinations impossible. -### 5. `QueryEndpointInput.n` — cryptic single-letter field +### 5. `QueryEndpointInputRequest.n` — cryptic single-letter field **Location:** `src/v1/model.ts:110-115` @@ -156,27 +155,11 @@ n?: number | undefined; `n` is the wire-format shorthand inherited from the OpenAI API. In TS it parses as a counter loop variable. `numCandidates`, `candidateCount`, or even `numChoices` (matching the response's `choices` field) would be self-describing. The JSDoc literally has to explain what `n` means ("(number of candidates)"). -### 6. `EmbeddingsV1ResponseEmbeddingElementObject` — overly verbose enum - -**Location:** `src/v1/model.ts:25-29` - -**Categories:** 7 (overly verbose), 8 (redundant suffixes) - -```ts -/** This will always be 'embedding'. */ -export enum EmbeddingsV1ResponseEmbeddingElementObject { - EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED = 'EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED', - EMBEDDING = 'EMBEDDING', -} -``` - -The name parses as 6 concatenated words: `Embeddings` + `V1` + `Response` + `Embedding` + `Element` + `Object`. "Embedding" appears twice; the version segment `V1` is leaked from the directory hierarchy into the type name; the `Element` suffix adds no semantic content. The same redundancy will recur in any future enum generated against this wire shape. - -### 7. `V1ResponseChoiceElement` — version segment in type name +### 6. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix **Location:** `src/v1/model.ts:185-196` -**Categories:** 7 (overly verbose), 14 (Go/Java-style names) +**Categories:** 7 (overly verbose), 8 (empty suffix), 14 (Go/Java-style names) ```ts export interface V1ResponseChoiceElement { ... } @@ -184,11 +167,11 @@ export interface V1ResponseChoiceElement { ... } The `V1` prefix duplicates the directory it lives in (`src/v1/`). When a hypothetical v2 ships, the type will be either `V2ResponseChoiceElement` (now-impossible name collision with whatever the new shape is called) or renamed (breaking change). The `Element` suffix is also empty — the type is the choice itself, not an "element of a choice." `Choice` (no prefix, no suffix) would suffice — `QueryEndpointResponse.choices: Choice[]` reads cleanly. v2-style versioning should live exclusively in the import path, not in identifiers. -### 8. `EmbeddingsV1ResponseEmbeddingElement` — version leak + double "Embedding" +### 7. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix **Location:** `src/v1/model.ts:58-65` -**Categories:** 7 (overly verbose), 8 (redundant suffixes) +**Categories:** 7 (overly verbose), 8 (empty suffix) ```ts export interface EmbeddingsV1ResponseEmbeddingElement { @@ -198,35 +181,9 @@ export interface EmbeddingsV1ResponseEmbeddingElement { } ``` -Same `V1` leak as finding #7, plus the word "Embedding" appears in `EmbeddingsV1` (plural prefix), `EmbeddingElement` (suffix), and in the field name `embedding` (singular). `Embedding` (the type name) and `vector` (the field name) would convey the same data without repetition. Pairs with finding #6 — the same enum sits inside this type. - -### 9. `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` — enum value = prefix tautology - -**Location:** `src/v1/model.ts:27-28` - -**Category:** 20 (type-suffix tautology in enums) - -```ts -EMBEDDING = 'EMBEDDING', -``` - -The only real enum value spells the same word that opens the enum's name. The path to use this is `EmbeddingsV1ResponseEmbeddingElementObject.EMBEDDING` — five "embedding"-derived tokens to express a constant. - -### 10. Long enum sentinels (`*_UNSPECIFIED`) - -**Location:** `src/v1/model.ts:19`, `27`, `36` - -**Categories:** 18 (long enum values), 14 (proto sentinels leak) - -```ts -CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', -EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED = 'EMBEDDINGS_V1_RESPONSE_EMBEDDING_ELEMENT_OBJECT_UNSPECIFIED', -QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED = 'QUERY_ENDPOINT_RESPONSE_OBJECT_UNSPECIFIED', -``` - -Three enums each carry a `*_UNSPECIFIED` value whose wire form repeats the full type name. The longest is 56 characters. These are protobuf-required sentinels that have no meaning in TS — `undefined` is the natural absent value. They appear in the exhaustive list a user must handle in a `switch` over `ChatMessageRole`. The pattern is generator-wide; flag at generator. +Same `V1` leak as finding #6. The `Element` suffix is empty — the type is the single embedding, not an "element of an embedding." `Embedding` (with `vector` for the numeric field) would convey the same data cleanly. -### 11. `ExternalModelUsageElement` — misleading scope + meaningless suffix +### 8. `ExternalModelUsageElement` — misleading scope + meaningless suffix **Location:** `src/v1/model.ts:67-74` @@ -248,13 +205,37 @@ Two problems: 1. **"External" is misleading.** This type is the OpenAI-spec `usage` block, returned by Databricks Foundation Model and Databricks Provisioned Throughput endpoints — both of which are **internal** Databricks-managed models. JSDoc in `QueryEndpointResponse.usage` even says "external/foundation model", but Databricks Foundation Models are explicitly *first-party*. The "External" prefix mislabels its scope. 2. **"Element" is meaningless.** The type is the single usage block, not "an element of a list." `TokenUsage`, `Usage`, or `ModelUsage` would suffice. -Pairs with finding #21 (every field redundantly ends in `Tokens`). +Pairs with finding #20 (every field redundantly ends in `Tokens`). + +### 9. `QueryEndpointInputRequest_ExtraParamsEntry` — proto map-entry leak + +**Location:** `src/v1/model.ts:142-145` + +**Why:** Underscore-separated `_ExtraParamsEntry` suffix is the verbatim Protobuf code-generator pattern for the synthetic map-entry message that backs `map extra_params`. The type is exported but never referenced by the client or by `marshalQueryEndpointInputRequestSchema`, which uses `z.record(z.string(), z.string())` directly. The accompanying `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive on line 141 explicitly acknowledges the leak. A TS SDK consumer has no need for the map-entry container shape; only the `Record` itself. + +**Category:** proto-architectural-leak (Protobuf generator artefact: `_Entry` map-entry message) + +**Suggested:** Delete the exported type entirely. A `Record` alias is already the idiomatic TS surface for a string-to-string map. + +**Rationale:** `_Entry` types are a proto-generator implementation detail (`map` lowers to a hidden nested message named `Entry`). Re-exporting them through a TS SDK forces language-specific generator scaffolding into the public API. The file's own ESLint disable comment is direct evidence that the name violates the project's naming convention — it is suppressed rather than fixed. + +### 10. `QueryEndpointInputRequest_UsageContextEntry` — proto map-entry leak + +**Location:** `src/v1/model.ts:148-151` + +**Why:** Same proto-architectural leak as finding #9, applied to the `usage_context` map field. The interface is exported, never used in the schema (which uses `z.record(z.string(), z.string())`), and the file's own ESLint directive on line 147 labels it "Proto-style nested message name." Duplicate leak from the same generator template. + +**Category:** proto-architectural-leak (Protobuf generator artefact: `_Entry` map-entry message) + +**Suggested:** Delete the exported type entirely; `Record` is the natural TS surface. + +**Rationale:** Mirror of #9. Two `_Entry` exports inflate the package surface area with proto-internal types that have no meaningful TS use case. They are a recurring pattern across packages with map fields, suitable for generator-level suppression. --- ## Medium severity -### 12. `query()` — verb-tense / reserved-word feel +### 11. `query()` — verb-tense / reserved-word feel **Location:** `src/v1/client.ts:58-81` @@ -262,12 +243,12 @@ Pairs with finding #21 (every field redundantly ends in `Tokens`). ```ts /** Query a serving endpoint */ -async query(req: QueryEndpointInput, options?: CallOptions): Promise { ... } +async query(req: QueryEndpointInputRequest, options?: CallOptions): Promise { ... } ``` The method is named `query` — a verb that doubles as the common SQL noun, and that already exists as a method on `IDBDatabase` and on the unrelated `queries` package. `invoke`, `predict`, or `call` would match the underlying REST verb (`POST /invocations`) and would not collide with SQL nomenclature. Also: the method signature omits `endpointName` as a first arg — it has to be supplied inside the input as `req.name`, which conflates the URL parameter with the request body. -### 13. `DataframeSplitInput` — generic field names lose meaning +### 12. `DataframeSplitInput` — generic field names lose meaning **Location:** `src/v1/model.ts:49-56` @@ -283,7 +264,7 @@ export interface DataframeSplitInput { The three field names `index`, `columns`, `data` are pulled verbatim from `pandas.DataFrame.to_dict(orient='split')`. In TS they read as a generic key-value bag with no hint that they form a tightly-coupled triple. `index` collides with `EmbeddingsV1ResponseEmbeddingElement.index` and `V1ResponseChoiceElement.index` (three different "index" fields in the same package, all `number`-typed). `columns` is `JsonValue[]` (column *names*, despite the JSON-value type). `data` is the row data. `rowIndex`, `columnNames`, `rows` would each carry meaning. -### 14. `QueryEndpointResponse.data` — vague field +### 13. `QueryEndpointResponse.data` — vague field **Location:** `src/v1/model.ts:156-157` @@ -296,7 +277,7 @@ data?: EmbeddingsV1ResponseEmbeddingElement[] | undefined; A response with seven other typed fields (`choices`, `predictions`, `outputs`, `usage`, etc.) and one of them is called `data`. Without JSDoc the field is meaningless. `embeddings` matches the OpenAI spec naming and the element type. -### 15. `QueryEndpointResponse.object` — JS built-in collision +### 14. `QueryEndpointResponse.object` — JS built-in collision **Location:** `src/v1/model.ts:172-176` @@ -308,7 +289,7 @@ object?: QueryEndpointResponseObject | undefined; `object` is a JS keyword (the type `object`, used in `typeof x === 'object'`). Field-name access `resp.object` doesn't break, but `const { object } = resp` shadows the global type. The OpenAI wire format uses `object` for the same field; idiomatic TS would rename to `objectType`, `kind`, or `responseType`. -### 16. Four mutually-exclusive output fields, no oneof +### 15. Four mutually-exclusive output fields, no oneof **Location:** `src/v1/model.ts:153-183` @@ -323,7 +304,7 @@ object?: QueryEndpointResponseObject | undefined; Mirror of finding #4 on the response side. The TS user has to know which field will be populated given which input was sent. A discriminated union would be more honest. -### 17. `QueryEndpointResponse.created` — verb tense + underspecified +### 16. `QueryEndpointResponse.created` — verb tense + underspecified **Location:** `src/v1/model.ts:170-171` @@ -336,9 +317,9 @@ created?: number | undefined; `created` is a past-tense verb used as a noun. Most TS codebases use `createdAt` / `createTime`. Typed `number` (Unix seconds), not `Temporal.Instant` like the rest of the SDK uses for timestamps. Pairs poorly with the response shape — `resp.created` reads as a boolean assertion. -### 18. `QueryEndpointResponse.servedModelName` — wire format leak +### 17. `QueryEndpointResponse.servedModelName` — wire format leak -**Location:** `src/v1/model.ts:181-183`, marshalled from `'served-model-name'` (line 252, 264) +**Location:** `src/v1/model.ts:181-182`, marshalled from `'served-model-name'` (line 252, 264) **Categories:** 4 (wire-format-driven naming), 19 (underspecified IDs) @@ -348,7 +329,7 @@ servedModelName?: string | undefined; JSON wire field is `served-model-name` (with hyphens) — the only hyphenated field in the whole package. In TS, "served model name" parses ambiguously: is it the *name* of the served-model resource, the *served-model identifier*, the *display name*, or the *model URI*? `servedEntityName` matches the `servingendpoints` package's `ServedEntity` type; `servedModelId` would explicitly mark it as a foreign key. -### 19. `V1ResponseChoiceElement.text` / `.message` — singular vs plural mismatch +### 18. `V1ResponseChoiceElement.text` / `.message` — singular vs plural mismatch **Location:** `src/v1/model.ts:185-196` @@ -364,7 +345,7 @@ export interface V1ResponseChoiceElement { The *request* uses `messages: ChatMessage[]` (plural array). The *response* `Choice` carries a singular `message: ChatMessage`. That's correct because each choice is one message — but `messageS` request and `message` response with the same element type invites confusion. Pair this with `text` (chat completions response) vs `prompt` (completions request) and the asymmetry is real. -### 20. `ChatMessageRole` enum — singular/plural odd +### 19. `ChatMessageRole` enum — singular/plural odd **Location:** `src/v1/model.ts:17-23` @@ -382,7 +363,7 @@ export enum ChatMessageRole { The values are not types of "chat message" — they are types of speaker / agent. `ChatRole` (drop `Message`) would parse more naturally because the *role* belongs to the *speaker*, not the *message*. The OpenAI vocabulary that this mirrors uses `role` (not `messageRole`) for the same reason. -### 21. `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` — tautology +### 20. `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` — tautology **Location:** `src/v1/model.ts:67-74` @@ -398,7 +379,7 @@ export interface ExternalModelUsageElement { Every field carries the `Tokens` suffix. Once you've established the type is `TokenUsage`, the inner fields can be `prompt`, `completion`, `total`. The unit is implicit. The current shape is `usage.promptTokens` (10 chars), the cleaner form is `usage.prompt` (5 chars). When *every* field repeats the unit, the unit is part of the type, not the field. -### 22. `V1ResponseChoiceElement.logprobs` — cryptic + wrong type +### 21. `V1ResponseChoiceElement.logprobs` — cryptic + wrong type **Location:** `src/v1/model.ts:194-195` @@ -414,7 +395,7 @@ logprobs?: number | undefined; 1. `logProbabilities` would be readable. 2. Typed `number` (a single number). The OpenAI spec for `logprobs` returns an *object* containing per-token log probabilities, top-k alternatives, and text offsets. The wire response is being shoe-horned into a scalar — either the type is wrong, or the field name is wrong. -### 23. `V1ResponseChoiceElement.finishReason` — underspecified +### 22. `V1ResponseChoiceElement.finishReason` — underspecified **Location:** `src/v1/model.ts:192-193` @@ -427,7 +408,7 @@ finishReason?: string | undefined; In practice the value is always one of `"stop"`, `"length"`, `"content_filter"`, `"tool_calls"`, `"function_call"`. Typed as `string` instead of an enum — the user has no IDE help. The field name itself is fine; the absence of an enum is the smell. -### 24. `QueryEndpointInput.stop` — reserved-word feel +### 23. `QueryEndpointInputRequest.stop` — reserved-word feel **Location:** `src/v1/model.ts:100-104` @@ -439,7 +420,7 @@ stop?: string[] | undefined; `stop` is an imperative verb used as a noun. `stopSequences` (which the JSDoc literally calls them — "The stop sequences field") would be self-describing. The naming inherits from the OpenAI wire spec. -### 25. `QueryEndpointInput.stream` — collides with web streams +### 24. `QueryEndpointInputRequest.stream` — collides with web streams **Location:** `src/v1/model.ts:117-120` @@ -451,7 +432,7 @@ stream?: boolean | undefined; The field is a boolean ("do you want a streamed response?"). The name `stream` in TS evokes `ReadableStream` / `WritableStream`. The client method doesn't actually implement streaming — there's no `AsyncIterable` return type — so setting `stream: true` will produce a malformed buffered response. `useStreamingResponse` or `streaming` (adjective, not noun) would avoid the type collision. -### 26. `QueryEndpointInput.extraParams` — vague +### 25. `QueryEndpointInputRequest.extraParams` — vague **Location:** `src/v1/model.ts:121-126` @@ -463,11 +444,11 @@ The field is a boolean ("do you want a streamed response?"). The name `stream` i extraParams?: Record | undefined; ``` -"Extra" relative to what? The 8 other fields already on `QueryEndpointInput` are the "main" params; everything else falls through to here. `passthroughParams`, `modelParams`, or `externalParamsOverride` would be clearer. Also: typed `Record` — but OpenAI's "extra params" semantically include `top_p` (number), `presence_penalty` (number), and `tools` (array). The string-only typing forces stringification of values that should be passed through as JSON. +"Extra" relative to what? The 8 other fields already on `QueryEndpointInputRequest` are the "main" params; everything else falls through to here. `passthroughParams`, `modelParams`, or `externalParamsOverride` would be clearer. Also: typed `Record` — but OpenAI's "extra params" semantically include `top_p` (number), `presence_penalty` (number), and `tools` (array). The string-only typing forces stringification of values that should be passed through as JSON. -### 27. `QueryEndpointInput.usageContext` — vague pair +### 26. `QueryEndpointInputRequest.usageContext` — vague pair -**Location:** `src/v1/model.ts:135-138` +**Location:** `src/v1/model.ts:137-138` **Category:** 1 (vague) @@ -476,13 +457,13 @@ extraParams?: Record | undefined; usageContext?: Record | undefined; ``` -Pairs with #26 (both are open-ended string maps). "Usage context" is ambiguous: usage of what? Context for what? The JSDoc says "recorded in the usage tracking table" — a clearer name would be `usageMetadata` or `trackingContext`. +Pairs with #25 (both are open-ended string maps). "Usage context" is ambiguous: usage of what? Context for what? The JSDoc says "recorded in the usage tracking table" — a clearer name would be `usageMetadata` or `trackingContext`. --- ## Low severity -### 28. JSDoc `/** Query a serving endpoint */` — verb tense / no period +### 27. JSDoc `/** Query a serving endpoint */` — verb tense / no period **Location:** `src/v1/client.ts:57` @@ -495,7 +476,7 @@ async query(...) { ... } Imperative verb, no terminal punctuation. Project rule (`CLAUDE.md`) requires comments to be sentences ending with a period. `/** Queries a serving endpoint. */` would match the v2-style JSDoc in other packages (`alerts/src/v2/client.ts` uses third-person singular present). -### 29. `ChatMessageRole.ASSISTANT` — incomplete enum +### 28. `ChatMessageRole.ASSISTANT` — incomplete enum **Location:** `src/v1/model.ts:17-23` @@ -503,18 +484,18 @@ Imperative verb, no terminal punctuation. Project rule (`CLAUDE.md`) requires co ```ts export enum ChatMessageRole { - ... + CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', SYSTEM = 'SYSTEM', USER = 'USER', ASSISTANT = 'ASSISTANT', } ``` -Three values, but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 3 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. +Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. -### 30. `EmbeddingsV1ResponseEmbeddingElement.index` — underspecified +### 29. `EmbeddingsV1ResponseEmbeddingElement.index` — underspecified -**Location:** `src/v1/model.ts:62-63` +**Location:** `src/v1/model.ts:61-62` **Category:** 19 (underspecified IDs) @@ -525,7 +506,7 @@ index?: number | undefined; `index` without qualification: index inside what? `responseIndex`, `embeddingIndex`, or `position` would be specific. Pairs with `V1ResponseChoiceElement.index` and `DataframeSplitInput.index` — three "index" fields with three different meanings. -### 31. `flattenQueryParams` — orphaned export with conflicting "Query" +### 30. `flattenQueryParams` — orphaned export with conflicting "Query" **Location:** `src/v1/utils.ts:123-150` @@ -548,21 +529,21 @@ Two issues: ## Observations -1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (4, 16, 19). +1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (4, 13, 16). -2. **Wire-format leakage is severe.** Wire-format names show up almost verbatim in TS: `n`, `stop`, `stream`, `logprobs`, `object`, `data`, `extra_params`, `served-model-name`, `*_UNSPECIFIED`, `EmbeddingsV1ResponseEmbeddingElement`. The Go SDK shares the smell, but Go's `query_endpoint` request becomes `QueryEndpointInput` in TS, where TS users have no way to distinguish the four valid combinations. +2. **Wire-format leakage is severe.** Wire-format names show up almost verbatim in TS: `n`, `stop`, `stream`, `logprobs`, `object`, `data`, `extra_params`, `served-model-name`, `EmbeddingsV1ResponseEmbeddingElement`. The Go SDK shares the smell, but Go's `query_endpoint` request becomes `QueryEndpointInputRequest` in TS, where TS users have no way to distinguish the four valid combinations. 3. **Version-segment leak.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, and `EmbeddingsV1ResponseEmbeddingElementObject` all carry the literal string `V1` in the *type* name. The directory is already `src/v1/`. Other packages in the SDK (e.g., `alerts`) do not carry `V1`/`V2` segments in type names — those have explicit `v1` / `v2` directories instead, with the version expressed at the package-import path level. This package is inconsistent with that convention. 4. **"Element" is the canonical empty suffix.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, `ExternalModelUsageElement` all carry the suffix `Element`. None of them are array elements in any structural sense — they are first-class types. The suffix is a Go convention for "value type inside a repeated field"; it adds noise in TS. -5. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInput` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. +5. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInputRequest` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. 6. **`utils.ts` is identical across packages.** The file is byte-for-byte the same as in `alerts/src/v1/utils.ts`, `endpoints/src/v1/utils.ts`, etc. The single domain-specific export, `flattenQueryParams`, is dead in this package. -7. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInput, options?: CallOptions)` would catch the missing path parameter at the type level. +7. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInputRequest, options?: CallOptions)` would catch the missing path parameter at the type level. -8. **No streaming support despite `stream: boolean`.** `QueryEndpointInput.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. +8. **No streaming support despite `stream: boolean`.** `QueryEndpointInputRequest.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. --- @@ -584,7 +565,7 @@ This package has only `v1`. There is no v2 to diff against. Several names visibl | Choice | One generated response in a chat or completions reply (mirrors OpenAI). | | Embedding | A vector of floats representing the input text (mirrors OpenAI). | | Logprobs | Log probabilities of generated tokens. Mistyped as `number` in this package. | -| `n` (in `QueryEndpointInput`) | "Number of candidates" (mirrors OpenAI's `n`). | +| `n` (in `QueryEndpointInputRequest`) | "Number of candidates" (mirrors OpenAI's `n`). | | Usage context | Free-form metadata recorded in the model-serving usage tracking table. | | Extra params | Free-form parameters passed through to the underlying model API. | | Served model | One model behind a serving endpoint (an endpoint can host several with traffic split). | @@ -597,7 +578,7 @@ This package has only `v1`. There is no v2 to diff against. Several names visibl | File | Lines | Read in full | |-------------------|-------|--------------| -| `src/v1/model.ts` | 343 | yes | -| `src/v1/client.ts`| 83 | yes | -| `src/v1/utils.ts` | 151 | yes | -| `src/v1/index.ts` | 22 | yes | +| `src/v1/model.ts` | 342 | yes | +| `src/v1/client.ts`| 82 | yes | +| `src/v1/utils.ts` | 150 | yes | +| `src/v1/index.ts` | 21 | yes | diff --git a/.agent/naming-audit/networking.md b/.agent/naming-audit/networking.md new file mode 100644 index 00000000..d8d654cb --- /dev/null +++ b/.agent/naming-audit/networking.md @@ -0,0 +1,128 @@ +# Naming Audit: networking + +**Path:** `packages/networking/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level networking — Network Connectivity Configurations (NCC) with AWS/Azure private endpoint rules and egress default rules, Networks (workspace network configs), Private Access Settings (workspace front-end PrivateLink), VPC Endpoints, Network Policies (egress / ingress restrictions, including public-vs-private access modes), Account IP Access Lists, and workspace network options. +**Total weird names flagged:** 4 + +## Summary +| Severity | Count | +| --- | --- | +| High | 0 | +| Medium | 4 | +| Low | 0 | +| Observation | 0 | + +## File coverage +- `src/v1/model.ts` — 4449 lines; interface, enum, and marshal/unmarshal schema definitions. +- `src/v1/client.ts` — 1675 lines; `Client` class with the public RPC methods. +- `src/v1/transport.ts` — 75 lines; HTTP transport wrapper. +- `src/v1/utils.ts` — 150 lines; helpers. +- `src/v1/index.ts` — 153 lines; barrel exports. + +## High severity + +_None._ + +## Medium severity + +### 1. `ListNetworkRequest` — `src/v1/model.ts:1442` +- **Why weird:** The noun is singular (`Network`) where the sibling list + request types in the package pluralise (`ListNetworkPoliciesRequest` + at line 1428, `ListNetworkConnectivityConfigsRequest` at line 1414). + The proto-tier `Public` infix was dropped in the 2026-05-22 + regeneration, leaving the residual singular/plural inconsistency. +- **Category:** Singular/plural inconsistency. +- **Suggested name:** `ListNetworksRequest`. +- **Rationale:** A list operation returns multiple items; pluralise the + noun to align with the rest of the package's `List*Request` naming. + +### 2. `ListNetworkResponse` — `src/v1/model.ts:1446` +- **Why weird:** Same singular/plural mismatch as #1. Sibling list + response types pluralise (`ListNetworkPoliciesResponse` at line 1435, + `ListNetworkConnectivityConfigsResponse` at line 1422). The proto-tier + `Public` infix was dropped in the 2026-05-22 regeneration, leaving + the residual singular/plural inconsistency. +- **Category:** Singular/plural inconsistency. +- **Suggested name:** `ListNetworksResponse`. +- **Rationale:** Same as #1. + +### 3. `ListVpcEndpointRequest` — `src/v1/model.ts:1458` +- **Why weird:** Same singular/plural mismatch as #1. The list request + for VPC endpoints uses a singular noun. The proto-tier `Public` infix + was dropped in the 2026-05-22 regeneration, leaving the residual + singular/plural inconsistency. +- **Category:** Singular/plural inconsistency. +- **Suggested name:** `ListVpcEndpointsRequest`. +- **Rationale:** Same as #1; pluralise the noun the way other list + request types in the package do. + +### 4. `ListVpcEndpointResponse` — `src/v1/model.ts:1462` +- **Why weird:** Same singular/plural mismatch as #1. The list response + for VPC endpoints uses a singular noun. The proto-tier `Public` infix + was dropped in the 2026-05-22 regeneration, leaving the residual + singular/plural inconsistency. +- **Category:** Singular/plural inconsistency. +- **Suggested name:** `ListVpcEndpointsResponse`. +- **Rationale:** Same as #1. + +## Low severity + +_None._ + +## Observations + +_None._ + +## Fixed + +- `CreateNetworkConnectivityConfigPublicRequest` — proto-architecture + leak removed; renamed to `CreateNetworkConnectivityConfigRequest`. + Fixed in regeneration on 2026-05-22. +- `CreateNetworkPublicRequest` — proto-architecture leak removed; + renamed to `CreateNetworkRequest`. Fixed in regeneration on + 2026-05-22. +- `CreatePrivateAccessSettingsPublicRequest` — proto-architecture leak + removed; renamed to `CreatePrivateAccessSettingsRequest`. Fixed in + regeneration on 2026-05-22. +- `CreateVpcEndpointPublicRequest` — proto-architecture leak removed; + renamed to `CreateVpcEndpointRequest`. Fixed in regeneration on + 2026-05-22. +- `DeleteNetworkConnectivityConfigPublicRequest` — proto-architecture + leak removed; renamed to `DeleteNetworkConnectivityConfigRequest`. + Fixed in regeneration on 2026-05-22. +- `DeleteNetworkPublicRequest` — proto-architecture leak removed; + renamed to `DeleteNetworkRequest`. Fixed in regeneration on + 2026-05-22. +- `DeletePrivateAccessSettingsPublicRequest` — proto-architecture leak + removed; renamed to `DeletePrivateAccessSettingsRequest`. Fixed in + regeneration on 2026-05-22. +- `DeleteVpcEndpointPublicRequest` — proto-architecture leak removed; + renamed to `DeleteVpcEndpointRequest`. Fixed in regeneration on + 2026-05-22. +- `GetNetworkConnectivityConfigPublicRequest` — proto-architecture leak + removed; renamed to `GetNetworkConnectivityConfigRequest`. Fixed in + regeneration on 2026-05-22. +- `GetNetworkPublicRequest` — proto-architecture leak removed; renamed + to `GetNetworkRequest`. Fixed in regeneration on 2026-05-22. +- `GetPrivateAccessSettingsPublicRequest` — proto-architecture leak + removed; renamed to `GetPrivateAccessSettingsRequest`. Fixed in + regeneration on 2026-05-22. +- `GetVpcEndpointPublicRequest` — proto-architecture leak removed; + renamed to `GetVpcEndpointRequest`. Fixed in regeneration on + 2026-05-22. +- `ListNetworkConnectivityConfigsPublicRequest` — proto-architecture + leak removed; renamed to `ListNetworkConnectivityConfigsRequest`. + Fixed in regeneration on 2026-05-22. +- `ListNetworkConnectivityConfigsPublicResponse` — proto-architecture + leak removed; renamed to `ListNetworkConnectivityConfigsResponse`. + Fixed in regeneration on 2026-05-22. +- `ListPrivateAccessSettingsPublicRequest` — proto-architecture leak + removed; renamed to `ListPrivateAccessSettingsRequest`. Fixed in + regeneration on 2026-05-22. +- `ListPrivateAccessSettingsPublicResponse` — proto-architecture leak + removed; renamed to `ListPrivateAccessSettingsResponse`. Fixed in + regeneration on 2026-05-22. +- `UpdatePrivateAccessSettingsPublicRequest` — proto-architecture leak + removed; renamed to `UpdatePrivateAccessSettingsRequest`. Fixed in + regeneration on 2026-05-22. diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 7da78441..4cd3dc3e 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,7 +3,7 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 22 +**Total weird names flagged:** 24 ## Summary @@ -11,7 +11,7 @@ | --- | --- | | High | 6 | | Medium | 8 | -| Low | 4 | +| Low | 6 | | Observation | 4 | ## Summary table @@ -29,8 +29,8 @@ | 9 | Medium | `model.ts:66-70` | `ListNotificationDestinationsResponse` | 7 (overly verbose), 8 (redundant `Response` suffix) | | 10 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | | 11 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | -| 12 | Medium | `model.ts:73`, `:107` | `id` (UUID) | 19 (underspecified ID) | -| 13 | Medium | `model.ts:118` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | +| 12 | Medium | `model.ts:74`, `:108` | `id` (UUID) | 19 (underspecified ID) | +| 13 | Medium | `model.ts:117` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | | 14 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | | 15 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | | 16 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | @@ -211,7 +211,7 @@ - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `destinations` (drop the `notification` qualifier since the package context supplies it) or `items`. -### 12. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 73, 107, 140` +### 12. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 74, 108, 141` - **Code:** ```ts /** UUID identifying notification destination. */ @@ -222,7 +222,7 @@ - **Suggested name:** `destinationId` (within the package context the qualifier "notification" is implicit). Or `id` is acceptable if the type is always accessed as `destination.id`. - **Rationale:** Bare `id` is conventional and tolerated; the optionality is the real bug. Demoted to medium. -### 13. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:118-122` +### 13. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:117-122` - **Code:** ```ts export interface PagerdutyConfig { @@ -296,11 +296,11 @@ ### 19. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` - **Code:** lines 26-38 and 65-94. -- **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. +- **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + ApiError check. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). -### 20. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 88, 105, 130, 165, 187, 190, 209` +### 20. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -342,7 +342,7 @@ The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the - `pageToken` / `pageSize` / `nextPageToken` — standard SDK pagination triplet; not specific to this package. ## File coverage -- `src/v1/model.ts` (448 lines): read fully. +- `src/v1/model.ts` (447 lines): read fully. - `src/v1/client.ts` (231 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (24 lines): read fully. +- `src/v1/index.ts` (23 lines): read fully. diff --git a/.agent/naming-audit/oauth.md b/.agent/naming-audit/oauth.md new file mode 100644 index 00000000..4e216040 --- /dev/null +++ b/.agent/naming-audit/oauth.md @@ -0,0 +1,364 @@ +# Naming Audit: oauth + +**Path:** `packages/oauth/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Inferred domain:** Account-level CRUD over OAuth 2.0 application +registrations. After the 2026-05-22 regeneration the former +`oauthcustomappintegration` and `oauthpublishedapp` packages were +consolidated into a single `@databricks/sdk-oauth` package. The surface +covers three resources in one client: + +- *Custom* OAuth app integrations — caller-defined OAuth clients with + their own `redirectUrls`, `scopes`, and (optionally) a confidential + client secret (`CustomOAuthAppIntegration`, + `CustomOAuthAppIntegrationSecret`). +- *Published* OAuth app integrations — registrations of + Databricks-blessed third-party apps such as Power BI or Tableau + Desktop, identified by a slug `appId` (`PublishedOAuthAppIntegration`). +- *Published* OAuth apps — read-only catalog rows describing the + available third-party apps (`PublishedOAuthApp`). + +All three share the `TokenAccessPolicy` type for access/refresh-token +TTL and session-rotation configuration. The package is the Databricks +account-side complement to RFC 6749 client registration. +**Total weird names flagged:** 9 + +## Summary table + +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 3 | +| Low | 3 | +| Observation | 2 | +| **Total** | **9 (+ 2 observations)** | + +The audit excludes the `OAuth*` brand-name spelling (RFC 6749 platform-name +exception), `*_UNSPECIFIED` proto sentinels, `*_Response` proto-nested +underscored identifiers, `marshal*` / `unmarshalSchema` Zod helper names, +empty wrapper types, `*Iter` pagination duplicates, redundant enum prefixes, +JS-built-in acronym casing (`URLSearchParams`, `JSON.parse`), and +wire-format strings preserved in JSDoc. The remaining findings cluster +around (1) the consolidated package surfacing intra-package +inconsistencies that used to be cross-package, (2) `appId` being a +human-readable slug rather than an opaque ID, and (3) leftover +generator/template artefacts (stale `:method:` cross-refs, `` +template tokens, dead helper exports). + +--- + +## High severity (must fix) + +### 1. `appId` is a slug, not an opaque ID — `model.ts:34, 156, 173` +- **Why:** Three types in this file expose a string field named `appId`. + On `CreatePublishedOAuthAppIntegrationRequest` (line 34) the JSDoc + reads "For example power-bi, tableau-deskop"; on `PublishedOAuthApp` + (line 156) it reads "Unique ID of the published OAuth app"; on + `PublishedOAuthAppIntegration` (line 173) it reads "App-id of the + published app integration". So `appId` is actually a human-readable + catalog slug such as `power-bi`, `tableau-desktop`, `looker`. Every + other `xId` field in this package and across the SDK + (`accountId`, `integrationId`, `clientId`, `createdBy`, + `principalId`) is an opaque server-issued identifier. Mixing a slug + in under the `Id` suffix is a teaching trap, and the three doc strings + describe the same value three different ways. +- **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) +- **Suggested:** Rename to `appSlug` (or `publishedAppKey`) on all three + types, narrow the type to a string literal union populated from the + Databricks published-app catalog + (`'power-bi' | 'tableau-desktop' | 'looker' | ...`), and replace the + three divergent doc strings with one canonical line ("Dash-separated + lowercase slug from the Databricks published-app catalog, e.g. + `power-bi`."). Fix the `tableau-deskop` typo on line 32 in the + process. +- **Rationale:** A slug typed as `string` and named `appId` is the + worst possible mix of soft-typing — it advertises opacity while + accepting any string, and the only documented examples are + catalog-specific values. A literal union plus a non-`Id` name puts + the value space in the type system instead of in a doc-comment + asterisk-list. + +### 2. Stale JSDoc cross-references to non-existent services — `client.ts:101, 137, 172, 203, 458, 493` +- **Why:** Six method docs say "You can retrieve the … OAuth app + integration via `:method:CustomAppIntegration/get`" or + "`:method:PublishedAppIntegration/get`". Neither `CustomAppIntegration` + nor `PublishedAppIntegration` is exported by this package — the + consolidated `Client` exposes `getCustomOAuthAppIntegration` and + `getPublishedOAuthAppIntegration`. The `:method:Foo/bar` directive + is proto-doc cross-reference syntax that should have been rewritten + during generation. Anyone clicking through hits a broken reference, + and the doc text reads as if there is a separate sub-service that + doesn't exist. +- **Category:** 6 (misleading documentation) +- **Suggested:** Rewrite during generation to TS-link form, e.g. + `Client.getCustomOAuthAppIntegration` / `Client.getPublishedOAuthAppIntegration`, + rendered as a JSDoc `{@link}` tag. At minimum, drop the + proto-cross-reference syntax and inline the method name as plain + prose. +- **Rationale:** Documentation that names APIs that do not exist is + worse than no documentation. The leak is a generator template + failing to rewrite proto-cross-reference syntax for TS output. + +### 3. `confidential` vs `isConfidentialClient` — same flag spelled two ways in one file — `model.ts:12, 55, 164` +- **Why:** The RFC 6749 §2.1 "confidential client" boolean flag appears + three times in `model.ts`. On + `CreateCustomOAuthAppIntegrationRequest.confidential` (line 12) and + `CustomOAuthAppIntegration.confidential` (line 55) it is named + `confidential`. On `PublishedOAuthApp.isConfidentialClient` (line 164) + it is named `isConfidentialClient`. Both forms describe the same + RFC 6749 client-type discriminator. Before the package consolidation + this was a cross-package inconsistency; consolidation has now + promoted it to a single-file inconsistency. The `isConfidentialClient` + form is the clearer of the two (boolean predicate prefix, explicit + `Client` noun) and matches the codebase convention for boolean + state flags (`isEnabled`, `isPrimary`, …). +- **Category:** 12 (duplicate concept, inconsistent naming within one + file) +- **Suggested:** Pick `isConfidentialClient` for all three sites and + rename the two custom-integration usages. +- **Rationale:** The flag's value space and meaning are identical + across the three types; the identifier should be too. Consolidation + makes this a clean single-package fix that no longer requires + cross-package coordination. + +--- + +## Medium severity (worth pushing back on) + +### 1. `userAuthorizedScopes` reads as past-tense "did consent" but is configuration of "will ask for consent" — `model.ts:25, 67, 226` +- **Why:** Three sites expose `userAuthorizedScopes?: string[]` — + `CreateCustomOAuthAppIntegrationRequest`, + `CustomOAuthAppIntegration`, and + `UpdateCustomOAuthAppIntegrationRequest`. The doc reads "Scopes that + will need to be consented by end user to mint the access token. If + the user does not authorize the access token will not be minted. + Must be a subset of scopes." So this is a *configuration* of the + consent gate the server will enforce, not a record of past consent. + The name `userAuthorizedScopes` reads as a state field — what the + user already authorised — and a caller can easily misread it that + way. A second issue: the subset relationship to `scopes` is invisible + from the type — setting `scopes = ['all-apis']` and + `userAuthorizedScopes = ['sql']` is a runtime-error, not a + type-error. +- **Category:** 1, 6, 13 (vague; misleading verb tense; configuration + vs state confusion) +- **Suggested:** Rename to `consentRequiredScopes` (configuration — + "scopes that require explicit end-user consent"). At minimum, add + inline JSDoc on `scopes` that backreferences this subset constraint + and cite RFC 6749 §3.3 for the scope vocabulary. +- **Rationale:** Bug class: caller assumes `userAuthorizedScopes` is + "what the user actually consented to" (read-after-write state) when + it is actually "what we will ask the user to consent to" (write-only + configuration). The current name reads past-tense and is easily + misread. The same trap exists on the matching `update` request, + which makes it possible to clobber a consent policy by accident. + +### 2. `createdBy: number` is a user ID disguised as an activity verb — `model.ts:59, 180` +- **Why:** `CustomOAuthAppIntegration.createdBy` (line 59) and + `PublishedOAuthAppIntegration.createdBy` (line 180) are both + `number | undefined`. The custom variant pairs it 2 lines below with + `creatorUsername: string` (line 61); the published variant lacks the + username pair. The undocumented numeric `createdBy` is the + Databricks user ID of the creator. The name reads as a verb phrase + ("created by"), not as an identifier, and the bare `number` type + carries no clue. The published variant's missing `creatorUsername` + pair is itself an asymmetry — `includeCreatorUsername` (line 114) + exists for custom but no equivalent for published. +- **Category:** 1, 15, 19 (vague; generic field; underspecified ID) +- **Suggested:** Rename to `creatorUserId: number` on both types and + document explicitly as "Databricks numeric user ID of the + registration creator." Keep `creatorUsername` next to it on + `CustomOAuthAppIntegration` and add it to + `PublishedOAuthAppIntegration` if the published API exposes it. +- **Rationale:** A bare `createdBy: number` is the worst kind of + numeric ID — no type information, no JSDoc, and a name that reads + as an activity-verb phrase rather than as a field. The asymmetry + with `creatorUsername` (present on one of the two registration + types) compounds the confusion. + +### 3. `enableSingleUseRefreshTokens` is verb-first while the rest of the file is predicate-style — `model.ts:199` +- **Why:** `TokenAccessPolicy.enableSingleUseRefreshTokens` (line 199) + uses the imperative-verb-first convention (`enableX`). The rest of + `TokenAccessPolicy` uses predicate-noun naming + (`accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, + `absoluteSessionLifetimeInMinutes`). The neighbour + `confidential` / `isConfidentialClient` flags in the file are also + predicate-style. So this boolean is the only verb-first identifier + in a configuration object full of nouns. It reads as a method + ("call this to enable …") rather than as a state ("this is the + enabled state"). +- **Category:** 13, 17 (verb-tense inconsistency; inconsistent action + verbs) +- **Suggested:** Rename to `singleUseRefreshTokensEnabled` (predicate) + or `rotateRefreshTokens` (behavioural noun matching the JSDoc's + "refresh token rotation"). Avoid `useSingleUseRefreshTokens` — too + close to a method name. +- **Rationale:** `enableX` configuration flags drift from state + semantics. The matching JSDoc on line 195 already calls the feature + "single-use refresh tokens (refresh token rotation)" — a + predicate/state noun mirrors that vocabulary. + +--- + +## Low severity (nits) + +### 1. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix + vocabulary drift in one type — `model.ts:186, 192, 206` +- **Why:** Three TTL fields on `TokenAccessPolicy`. Two are named + `…TtlInMinutes`; the third uses `…LifetimeInMinutes`. The "InMinutes" + suffix is encoded into the field name three times in one type — a + doc-able invariant that lives in the identifier. The `Ttl` vs + `Lifetime` drift is the second issue: the JSDoc on line 201 calls + the third field "Absolute OAuth session TTL in minutes", so even + the doc inconsistently swaps "TTL" and "Lifetime" for the same + concept. +- **Category:** 7, 17 (overly verbose; inconsistent vocabulary — + TTL/Lifetime) +- **Suggested:** Either (a) adopt a `Temporal.Duration`-typed field + and drop the unit suffix entirely (`accessTokenTtl`, + `refreshTokenTtl`, `absoluteSessionLifetime`), or (b) standardise + on one suffix and one root: `accessTokenTtlMinutes`, + `refreshTokenTtlMinutes`, `sessionTtlMinutes`. The `Lifetime` / + `Ttl` mismatch should be resolved either way. +- **Rationale:** Encoding units into field names dates the API to + before `Temporal` shipped. The asymmetry between `Ttl` and + `Lifetime` is gratuitous — the JSDoc itself uses both + interchangeably for one concept. + +### 2. `includeCreatorUsername` is a server-side join flag, cryptic without context — `model.ts:114` +- **Why:** `ListCustomOAuthAppIntegrationsRequest.includeCreatorUsername` + is a boolean opt-in that does not appear on the sibling + `ListPublishedOAuthAppIntegrationsRequest` (line 124). The JSDoc + is empty. A caller writing both list calls in sequence cannot tell + why one has the option and the other does not. The flag's + semantics — "perform a server-side join to resolve the creator user + ID to their username" — are not visible from the name. +- **Category:** 5 (cryptic — the flag's semantics are non-obvious + without external context) +- **Suggested:** Keep the name (matches Go SDK convention) but + document the flag inline: "When `true`, the server resolves + `createdBy` to `creatorUsername` in each response row (extra + server-side lookup)." Decide whether the same option belongs on + the published-integration list endpoint, and add it for parity + if so. +- **Rationale:** The default behaviour (omit username) is a + performance optimisation; callers should know enabling this is a + server-side join, and the asymmetry with the published-integration + list should be deliberate or removed. + +### 3. `Client` is a single generic export on a multi-resource package — `client.ts:69` +- **Why:** The package exports a single `Client` class whose + responsibilities now span three resources (custom integrations, + published integrations, published apps) and ten methods. A + consumer doing `import { Client } from '@databricks/sdk-oauth/v1'` + gets an unqualified symbol that must be aliased to coexist with any + other package's `Client`. The post-consolidation surface is wider + than it was pre-merge, which makes the generic name more of a + navigation hazard than before. +- **Category:** 1 (vague / generic) +- **Suggested:** `OAuthClient` (still inside `…/v1`). Project-wide + change — every generated package shares this pattern, so the fix + belongs at the generator template level, not per-package. +- **Rationale:** Defer to the project-wide naming-audit summary + recommendation. Flagged here for completeness, with the + caveat that this is shared across all 93 packages. + +--- + +## Observations (not flags) + +### O1. `` and `` template tokens leak into JSDoc — `model.ts:73, 76, 195`, `client.ts:285, 345, 402` +- Six call sites in this package leave literal `` / + `` angle-bracket tokens in their JSDoc — they were meant + to be substituted with "Databricks" / "account" by the generator's + template engine. They render as broken-HTML angle-bracket sequences + in TypeScript hover popups and IDE doc views. Not a per-package + naming issue, but the leak is visible at every IDE hover. Tracked + at the project level. + +### O2. `flattenQueryParams` exported but unused — `utils.ts:123` +- The helper is exported from `utils.ts` but the three list endpoints + in this package (`listCustomOAuthAppIntegrations`, + `listPublishedOAuthAppIntegrations`, `listPublishedOAuthApps`) all + use flat scalar query parameters (`pageToken`, `pageSize`, + `includeCreatorUsername`), so the helper is dead code in this + build. Same pattern in many sibling packages — either drop the + `export` here or lift the helper into `@databricks/sdk-core` so it + is not duplicated 93 times. + +--- + +## Domain glossary + +- `accountId` — Databricks account UUID (top-level tenant), distinct + from a workspace ID. +- `appId` — Slug into the Databricks published-app catalog + (`power-bi`, `tableau-desktop`, …). Despite the `Id` suffix, this + is a human-readable name, not an opaque server-issued ID. +- `clientId` — RFC 6749 client identifier (the OAuth `client_id` + returned by the server). Opaque. +- `clientSecret` — RFC 6749 client secret. Returned only at creation + time for confidential clients. +- `confidential` / `isConfidentialClient` — RFC 6749 §2.1 client + type. `true` means the client has a secret and authenticates + itself; `false` means it is a public client and relies on PKCE. + Currently spelled two ways in this file (finding H3). +- `Custom` integration — Caller-defined OAuth client (caller-owned + redirect URLs, scopes, secret). +- `createdBy` — Numeric Databricks user ID of the registration + creator. Field is named like a verb (finding M2). +- `creatorUsername` — Username string of the registration creator. + Server-side joined when `includeCreatorUsername` is set on the + list request. +- `integrationId` — Opaque server-issued ID for an OAuth app + integration row. Distinct from `clientId`. +- `OAuth` — IETF OAuth 2.0 (RFC 6749). Brand-name capitalisation + (`OAuth`, not `Oauth`) is intentional per the project's RFC 6749 + platform-name exception. +- `Published` app — Databricks-blessed third-party application + (catalog row). +- `Published` integration — Account-level registration of a + published app (enables the app for the account). +- `scopes` — RFC 6749 scope strings the integration may request. + Documented set: `all-apis`, `sql`, `offline_access`, `openid`, + `profile`, `email`. +- `TokenAccessPolicy` — Per-integration token TTL and + refresh-rotation policy. +- `userAuthorizedScopes` — Subset of `scopes` requiring explicit + end-user consent. Misleading verb tense — this is *will-ask*, + not *did-grant* (finding M1). + +--- + +## Cross-package coupling notes + +- The 2026-05-22 regeneration consolidated the prior + `oauthcustomappintegration` and `oauthpublishedapp` packages into + this single `@databricks/sdk-oauth` package. Three former + cross-package inconsistencies are now intra-package issues: + `confidential` vs `isConfidentialClient` (H3), `appId` slug-vs-ID + agreement (H1), and the shape of the `scopes` documented value + space across the published and custom surfaces. The consolidation + is reflected in the import list at `index.ts:7-31`, which now + re-exports 25 types from one model file. + +--- + +## File coverage + +| File | Lines read | Coverage | +| ---- | ---------- | -------- | +| `src/v1/index.ts` | 32 / 32 | 100% | +| `src/v1/transport.ts` | 75 / 75 | 100% | +| `src/v1/utils.ts` | 150 / 150 | 100% | +| `src/v1/model.ts` | 487 / 487 | 100% | +| `src/v1/client.ts` | 525 / 525 | 100% | + +All types, fields, and methods reviewed. Out-of-scope per the audit +constraints: `OAuth*` brand-name spelling (RFC 6749 platform-name +exception), `*_UNSPECIFIED` enum sentinels, `*_Response` proto-nested +underscored identifiers, `marshal*` / `unmarshalSchema` Zod helpers, +empty wrapper interfaces, `*Iter` pagination duplicates, redundant +enum prefixes, JS-built-in acronym casing (`URLSearchParams`, +`JSON.parse`, `TextDecoder`), and wire-format strings preserved +verbatim in JSDoc. diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md index 809ce58a..0f5faaa5 100644 --- a/.agent/naming-audit/oauthcustomappintegration.md +++ b/.agent/naming-audit/oauthcustomappintegration.md @@ -1,51 +1,55 @@ # Naming Audit: oauthcustomappintegration -**Path:** `packages/oauthcustomappintegration/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/oauth/src/v1/` (formerly `packages/oauthcustomappintegration/src/v1/`; consolidated into the `oauth` package) **Versions audited:** v1 **Inferred domain:** Account-level CRUD for OAuth App Integrations. Two flavours of integration are managed by the same service: *Custom* (caller-owned OAuth clients with their own redirect URLs and scopes) and *Published* (catalog of Databricks-blessed third-party apps such as Power BI or Tableau Desktop, identified by a stable `appId`). Both share the `TokenAccessPolicy` configuration. The package is the Databricks account-side complement of the `RFC 6749`/`OAuth 2.0` client registration concept. -**Total weird names flagged:** 15 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 5 | +| Medium | 3 | | Low | 4 | | Observation | 2 | ## High severity -### 1. Package name `oauthcustomappintegration` mis-scopes the package — `package.json:2` -- **Why weird:** The package is named `@databricks/sdk-oauthcustomappintegration`, but only roughly half the surface concerns *custom* integrations (`CreateCustomOAuthAppIntegration`, `CustomOAuthAppIntegration`, etc.). The other half is *published* integrations (`CreatePublishedOAuthAppIntegration`, `PublishedOAuthAppIntegration`, etc.). The package's `Client` is a single mixed service handling both. Naming the package `…customappintegration` leads any developer reading `import { Client } from '@databricks/sdk-oauthcustomappintegration/v1'` to assume Published is in a different package — but it is not. There is also no separator: it reads as one 25-character unbroken token, harder to skim than `oauth-app-integrations` or `oauth_app_integrations`. -- **Category:** 6, 7, 9 (misleading scope; overly verbose; singular when it represents N integration types) -- **Suggested name:** `@databricks/sdk-oauthappintegrations` (plural; drops the misleading "custom" since the package also covers published). Or split into two packages: `oauthcustomappintegrations` and `oauthpublishedappintegrations`, each plural. -- **Rationale:** The Go SDK reference path is `databricks/api/oauth2` (umbrella for all OAuth concerns), which suggests the cross-service grouping is the natural one. The current TS name picks one half of the surface and elevates it to the package title, which is actively misleading. Pluralizing avoids the "what does one integration mean?" confusion at the import line. - -### 2. Every domain type re-states `OAuthAppIntegration` — model.ts:6, 29, 46, 73, 92, 100, 108, 115, 120, 134, 147, 185, 208 -- **Why weird:** Inside a package called `oauthcustomappintegration`, *every* type name still spells "OAuthAppIntegration" in full. Imports look like this: +### 1. Every domain type re-states `OAuthAppIntegration` and now also carries a `Request` suffix — model.ts:5, 28, 45, 70, 82, 90, 98, 105, 110, 124, 137, 171, 209, 232 +- **Why weird:** Inside the consolidated `oauth` package, every type name still spells "OAuthAppIntegration" in full, and the new regeneration added a `Request` suffix to every request DTO. Imports look like this: ```ts import { - CreateCustomOAuthAppIntegration, - CreatePublishedOAuthAppIntegration, + CreateCustomOAuthAppIntegrationRequest, + CreatePublishedOAuthAppIntegrationRequest, CustomOAuthAppIntegration, CustomOAuthAppIntegrationSecret, - DeleteCustomOAuthAppIntegration, - DeletePublishedOAuthAppIntegration, - GetCustomOAuthAppIntegration, - GetPublishedOAuthAppIntegration, - ListCustomOAuthAppIntegrations, - ListPublishedOAuthAppIntegrations, + DeleteCustomOAuthAppIntegrationRequest, + DeletePublishedOAuthAppIntegrationRequest, + GetCustomOAuthAppIntegrationRequest, + GetPublishedOAuthAppIntegrationRequest, + ListCustomOAuthAppIntegrationsRequest, + ListPublishedOAuthAppIntegrationsRequest, PublishedOAuthAppIntegration, - UpdateCustomOAuthAppIntegration, - UpdatePublishedOAuthAppIntegration, - } from '@databricks/sdk-oauthcustomappintegration/v1'; + UpdateCustomOAuthAppIntegrationRequest, + UpdatePublishedOAuthAppIntegrationRequest, + } from '@databricks/sdk-oauth/v1'; ``` - Most exported types are >25 characters long; several are >35 characters. The package name already declares the namespace, so the type names need not re-declare it. Compare what the same code would look like with shorter names: `CreateCustom`, `CreatePublished`, `Custom`, `Published`, `CustomSecret`, `DeleteCustom`, … (still readable when paired with the package import). + Most request DTO names are now >35 characters; `CreatePublishedOAuthAppIntegrationRequest` is 42. The package name already declares the namespace, so the type names need not re-declare it. Compare what the same code would look like with shorter names: `CreateCustom`, `CreatePublished`, `Custom`, `Published`, `CustomSecret`, `DeleteCustom`, … (still readable when paired with the package import). - **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) -- **Suggested name:** Drop the `OAuthAppIntegration` suffix from every type. With a namespace import the call site reads `oauth.CreateCustom`, `oauth.Custom`, `oauth.CustomSecret`, `oauth.ListPublished`. With named imports, alias if needed. -- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it across every type produces walls of identifiers where the eye has to skip redundant characters to find the discriminator (`Create` vs `Update` vs `Delete` vs `List` vs `Get`, and `Custom` vs `Published`). The redundancy is a Go convention port: in Go `oauthcustomappintegration.CreateCustomAppIntegrationRequest` is necessary because Go has no struct-level method namespacing. TS does not have that constraint. See the Go reference at `databricks/api/oauth2/oauthcustomappintegration` where the Go names are necessarily fully qualified — but a 1:1 port should adapt to TS naming, not blindly copy. +- **Suggested name:** Drop the `OAuthAppIntegration` suffix from every type and the `Request` suffix from request DTOs. With a namespace import the call site reads `oauth.CreateCustom`, `oauth.Custom`, `oauth.CustomSecret`, `oauth.ListPublished`. With named imports, alias if needed. +- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it across every type produces walls of identifiers where the eye has to skip redundant characters to find the discriminator (`Create` vs `Update` vs `Delete` vs `List` vs `Get`, and `Custom` vs `Published`). The redundancy is a Go convention port: in Go `oauthcustomappintegration.CreateCustomAppIntegrationRequest` is necessary because Go has no struct-level method namespacing. TS does not have that constraint. -### 3. Type names use `OAuthAppIntegration` but methods use `OAuthAppIntegration` while doc cross-refs use `CustomAppIntegration` / `PublishedAppIntegration` — `client.ts:97, 133, 168, 199` +### 2. Proto-nested `Request_Response` underscore-infix types leak protobuf message-nesting into TS — model.ts:40, 88, 96, 118, 131, 147, 230, 240 (and matching schemas at 243, 297, 301, 305, 319, 333, 400, 404) +- **Why weird:** Eight types follow the pattern `Request_Response` (e.g. `CreatePublishedOAuthAppIntegrationRequest_Response`, `DeleteCustomOAuthAppIntegrationRequest_Response`). The underscore-infix is a literal carry-over of protobuf nested-message naming (`Request.Response` in the proto, rendered as `Request_Response` by code-gen). Each declaration carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`, which is the generator self-documenting an architectural leak. The names are also tautological in TypeScript: a response type does not need to embed `Request` in its name. +- **Category:** Proto-architectural-leak: `Foo_PublicRequest` pattern (underscore-infix proto-nested message name); also 7, 8, 20 (verbose; redundant `Request` infix; tautology) +- **Suggested name:** Drop the `Request_` prefix and use the response noun: `CreatePublishedResponse`, `DeleteCustomResponse`, `DeletePublishedResponse`, `ListCustomResponse`, `ListPublishedResponse`, `ListPublishedAppsResponse`, `UpdateCustomResponse`, `UpdatePublishedResponse` (or, since several are empty interfaces, replace with `void` / `undefined` returns on the corresponding `Client` methods). Combine with finding #1 to drop the `OAuthAppIntegration` middle as well. +- **Rationale:** TypeScript has no notion of a message nested inside another message; the underscore is a generator-side fix-up that bleeds proto schema topology into the public API surface. The eslint-disable comments are the smoking gun: the project linter rejects these identifiers by default and they only pass because each one carries a per-line escape hatch. Idiomatic TS response types are sibling exports, not underscore-nested children. + +### 3. JSDoc cross-refs point to `CustomAppIntegration` / `PublishedAppIntegration` services that do not exist — client.ts:101, 137, 172, 203, 458, 493 - **Why weird:** JSDoc on `createCustomOAuthAppIntegration` says: > You can retrieve the custom OAuth app integration via `:method:CustomAppIntegration/get`. @@ -54,39 +58,27 @@ - **Suggested name:** Fix the JSDoc cross-references to point to the real method (`Client.getCustomOAuthAppIntegration` / `Client.getPublishedOAuthAppIntegration`). The `:method:Foo/get` proto-doc directive should be processed to TypeScript-link form during generation. - **Rationale:** Documentation lying to the reader is worse than verbose-but-correct documentation. -### 4. `appId` on Published refers to a slug, not an ID — `model.ts:33, 149` -- **Why weird:** `CreatePublishedOAuthAppIntegration.appId` and `PublishedOAuthAppIntegration.appId` are documented as `For example power-bi, tableau-deskop` (note also: typo `deskop`). These are human-readable slugs, not opaque IDs. Calling them `appId` and typing as `string` collides with the convention that `xId` is an opaque UUID-like identifier (cf. `accountId`, `integrationId`, `clientId`, `principalId`). The Go reference (`databricks/api/oauth2/published`) calls it `AppID` too, but the value is clearly a published-catalog key like `power-bi`. The typo `tableau-deskop` in the doc comment is also untracked. +### 4. `appId` on Published refers to a slug, not an ID — model.ts:34, 173 +- **Why weird:** `CreatePublishedOAuthAppIntegrationRequest.appId` and `PublishedOAuthAppIntegration.appId` are documented as `For example power-bi, tableau-deskop` (note also: typo `deskop`). These are human-readable slugs, not opaque IDs. Calling them `appId` and typing as `string` collides with the convention that `xId` is an opaque UUID-like identifier (cf. `accountId`, `integrationId`, `clientId`, `principalId`). The Go reference (`databricks/api/oauth2/published`) calls it `AppID` too, but the value is clearly a published-catalog key like `power-bi`. The typo `tableau-deskop` in the doc comment is also untracked. - **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) - **Suggested name:** `appSlug` or `publishedAppKey` with type narrowed to a string literal union or enum: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, fix the `tableau-deskop` typo and document the format ("dash-separated lowercase slug from the Databricks published-app catalog"). - **Rationale:** "ID" in this codebase otherwise means opaque UUID/integer (`integrationId`, `clientId`, `principalId`, `accountId`). Mixing in a human-readable slug under the same suffix is a teaching trap for callers. ## Medium severity -### 5. `createdBy: number` is a user ID hidden as a numeric — `model.ts:60, 156` +### 5. `createdBy: number` is a user ID hidden as a numeric — model.ts:59, 180 - **Why weird:** Used in both `CustomOAuthAppIntegration` and `PublishedOAuthAppIntegration`. The field doc is empty, but it pairs with `creatorUsername: string` on `CustomOAuthAppIntegration`, so `createdBy` is the *user ID* of the creator. Calling it `createdBy` and typing it as `number` (rather than `creatorUserId` typed as `number` or `string`) hides the meaning. `principalId: number` next door has the same problem. - **Category:** 1, 15, 19 (vague; generic field; underspecified ID) - **Suggested name:** `createdByUserId: number` or just `creatorUserId: number`. Document explicitly that this is the numeric Databricks user ID (note: many other places in the codebase use `string` for user IDs). - **Rationale:** A bare `createdBy: number` is the worst kind of numeric ID — no type information, no doc, and a name that reads as an activity verb. The asymmetry with `creatorUsername: string` (which sits 2 lines below in `CustomOAuthAppIntegration` but is missing from `PublishedOAuthAppIntegration`) compounds the confusion. -### 6. `createTime: string` vs `clientSecretExpireTime: Temporal.Instant` — type inconsistency — `model.ts:61, 89, 157` -- **Why weird:** Both fields are timestamps. `createTime` is typed as `string` (raw ISO 8601, unparsed). `clientSecretExpireTime` is typed as `Temporal.Instant` (parsed via `Temporal.Instant.from`). Same package, same wire format, two different deserialization choices. Callers have to remember which fields are parsed and which are not. Looking at the unmarshal code at line 270, `client_secret_expire_time` gets `.transform(s => Temporal.Instant.from(s))` while `create_time` (line 241, 327) does not. -- **Category:** 16 (field contradicting type domain — both timestamps, different types) -- **Suggested name:** Names are fine; the *types* are inconsistent. Either both `Temporal.Instant` (preferred — this is the post-Temporal TS world) or both `string`. Apply consistently across the package. -- **Rationale:** A consumer doing `if (integration.createTime < other.createTime)` will get string comparison silently; if they did the same with `Temporal.Instant` they would get a type error and use `Temporal.Instant.compare`. The current state is a footgun. - -### 7. `clientSecretExpireTime` verb tense — `model.ts:89` -- **Why weird:** "Expire" is the bare infinitive — should be "expires" (third-person singular: "the secret expires at T") or "expiry"/"expiration" (noun). The Go side likely has `ClientSecretExpireTime` because Go traditionally uses verb-first compound nouns (`expireTime`, `createTime`), but TS/JS naming tends to use either the noun (`expirationTime`, `expirationDate`) or the inflected verb (`expiresAt`). `createTime`/`createdBy` next door have the same issue (should be `createdAt`/`creator`). -- **Category:** 13, 14 (verb-tense inconsistency; Go/Java-style names) -- **Suggested name:** `clientSecretExpiresAt`, `createdAt`, `creator` (or `creatorUserId`). -- **Rationale:** TypeScript ecosystem standard is `xAt` for timestamps and inflected verbs in field names. The Go form `xTime` reads as a Go transliteration. - -### 8. `confidential: boolean` — too generic for "requires-secret" flag — `model.ts:13, 56` +### 6. `confidential: boolean` — too generic for "requires-secret" flag — model.ts:12, 55 - **Why weird:** The doc comment is informative ("indicates whether an OAuth client secret is required to authenticate this client"), but the field name `confidential` is ambiguous outside RFC 6749 context. A reader has to know OAuth specifically (RFC 6749 §2.1 distinguishes "confidential" vs "public" clients) to decode this. The field doesn't follow a `requires…` or `is…` convention used elsewhere in the codebase. - **Category:** 1, 5 (vague/generic; cryptic abbreviation of a spec term) - **Suggested name:** `isConfidentialClient`, `requiresClientSecret`, or `confidentialClient`. If keeping `confidential`, add the RFC 6749 link in the doc. -- **Rationale:** Half of OAuth API consumers will not recognize "confidential" as the RFC 6749 client-type discriminator. +- **Rationale:** Half of OAuth API consumers will not recognize "confidential" as the RFC 6749 client-type discriminator. Note that `PublishedOAuthApp.isConfidentialClient` (model.ts:164) uses the longer-form name, so the package itself is inconsistent here. -### 9. `userAuthorizedScopes` vs `scopes` overlap — `model.ts:20, 26, 59, 68, 196, 202` +### 7. `userAuthorizedScopes` vs `scopes` overlap — model.ts:19, 25, 58, 67, 220, 226 - **Why weird:** Two scope fields that look unrelated by name but the doc explicitly says `userAuthorizedScopes` "must be a subset of `scopes`". The relationship is invisible from the type — a caller could set `scopes = ["all-apis"]` and `userAuthorizedScopes = ["sql"]` and the type system won't help. `scopes` is the *requested* scope set, `userAuthorizedScopes` is the *user-consent gate* subset. Names do not encode this subset relationship. - **Category:** 1, 6 (vague; misleading — `scopes` doesn't say "requested") - **Suggested name:** `requestedScopes` (rename `scopes`) and `consentRequiredScopes` (rename `userAuthorizedScopes`). Or document the subset relationship inline on `scopes` with a backreference. @@ -94,40 +86,40 @@ ## Low severity -### 10. `OAuth` casing is consistent — `model.ts:throughout` +### 8. `OAuth` casing is consistent — model.ts:throughout - **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants appear. This matches Google TS style guide guidance for trade-mark casing and matches RFC 6749 ("OAuth 2.0"). No action. - **Category:** 3 (acronym casing — flagged as compliant) - **Suggested name:** None — confirm the project-wide policy is `OAuth`. - **Rationale:** Documenting the convention. Other audits should check sibling packages for `OAuth2` vs `Oauth2` vs `OAUTH2`. -### 11. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix bloat — `model.ts:162, 168, 182` +### 9. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix bloat — model.ts:186, 192, 206 - **Why weird:** Three TTL fields, two named `…InMinutes`, one named `…LifetimeInMinutes`. The "InMinutes" suffix is verbose. Three options to consider: - Adopt `Temporal.Duration` for the type (no unit in the name needed). - Keep the unit in the name but standardise on `Minutes` suffix (`accessTokenTtlMinutes`, `refreshTokenTtlMinutes`, `sessionTtlMinutes`). - Document the unit in JSDoc only and use bare names (`accessTokenTtl`, `refreshTokenTtl`). - **Category:** 7 (overly verbose) - **Suggested name:** `accessTokenTtl: Temporal.Duration`, `refreshTokenTtl: Temporal.Duration`, `absoluteSessionLifetime: Temporal.Duration`. -- **Rationale:** The project already uses `Temporal.Instant` for `clientSecretExpireTime`. Extending to `Temporal.Duration` here removes the need to encode the unit in the field name, and removes the asymmetry between `TtlInMinutes` and `LifetimeInMinutes` (one is "TTL", the other "lifetime" — same concept). +- **Rationale:** Using `Temporal.Duration` removes the need to encode the unit in the field name, and removes the asymmetry between `TtlInMinutes` and `LifetimeInMinutes` (one is "TTL", the other "lifetime" — same concept). -### 12. `enableSingleUseRefreshTokens` boolean naming inconsistency with `confidential` — `model.ts:175` +### 10. `enableSingleUseRefreshTokens` boolean naming inconsistency with `confidential` — model.ts:199 - **Why weird:** `enableSingleUseRefreshTokens` uses the verb-first `enableX` convention, but `confidential` uses no prefix. Other boolean conventions in the codebase favour `isX`/`hasX`. Three competing patterns on one type. - **Category:** 13, 17 (verb-tense inconsistency; inconsistent action verbs) - **Suggested name:** Align to one of `singleUseRefreshTokensEnabled` (state), `useSingleUseRefreshTokens` (config), or `rotateRefreshTokens` (behaviour). - **Rationale:** "Enable X" reads as an action and slightly suggests a method/mutator. State booleans typically use predicate suffix `isEnabled`/`enabled` or domain noun. -### 13. `includeCreatorUsername: boolean` query param on List Custom only — `model.ts:124` -- **Why weird:** `ListCustomOAuthAppIntegrations` has `includeCreatorUsername` but `ListPublishedOAuthAppIntegrations` does not (line 134). The asymmetry is fine for the API (Published integrations don't track creator the same way) but the type-level discoverability is poor. A caller writing both list calls in sequence will not understand why the option is missing from one. The name itself is also a query-flag for *server-side join inclusion*, which is unusual for an SDK to expose verbatim. +### 11. `includeCreatorUsername: boolean` query param on List Custom only — model.ts:114 +- **Why weird:** `ListCustomOAuthAppIntegrationsRequest` has `includeCreatorUsername` but `ListPublishedOAuthAppIntegrationsRequest` does not (line 124). The asymmetry is fine for the API (Published integrations don't track creator the same way) but the type-level discoverability is poor. A caller writing both list calls in sequence will not understand why the option is missing from one. The name itself is also a query-flag for *server-side join inclusion*, which is unusual for an SDK to expose verbatim. - **Category:** 5 (cryptic — the flag's semantics are non-obvious) - **Suggested name:** Keep the field but document explicitly: "When true, the server resolves `createdBy` to `creatorUsername` in the response (extra database lookup)." - **Rationale:** The default behaviour (omit username) is a performance optimization; callers should know enabling this is a server-side join. ## Observations -### O1. JSDoc literal templating leaks `` and `` markup — `model.ts:80, 82, 172, 178` and `client.ts:281, 341` -- The literal tokens `` and `` appear in seven places in this package. They are proto-doc templating tokens that should have been substituted to "Databricks" / "account" during generation. They render as broken-HTML angle-bracket sequences in TypeScript hover popups. This is a generator bug, not a per-package naming issue, but worth tagging at the project level. +### O1. JSDoc literal templating leaks `` and `` markup — model.ts:73, 76, 195 and client.ts:285, 345, 402 +- The literal tokens `` and `` appear in six places in this package. They are proto-doc templating tokens that should have been substituted to "Databricks" / "account" during generation. They render as broken-HTML angle-bracket sequences in TypeScript hover popups. This is a generator bug, not a per-package naming issue, but worth tagging at the project level. -### O2. `flattenQueryParams` is exported but unused — `utils.ts:123` -- This package never builds nested query parameters (`ListCustomOAuthAppIntegrations` uses three flat scalars), so `flattenQueryParams` is dead in this build. Same as in many sibling packages. Either drop the `export` or move the helper to `@databricks/sdk-core`. +### O2. `flattenQueryParams` is exported but unused — utils.ts:123 +- This package never builds nested query parameters (`ListCustomOAuthAppIntegrationsRequest` uses three flat scalars), so `flattenQueryParams` is dead in this build. Same as in many sibling packages. Either drop the `export` or move the helper to `@databricks/sdk-core`. ## Domain glossary - `accountId` — Databricks account UUID (top-level tenant), distinct from a workspace ID. @@ -145,8 +137,17 @@ - `userAuthorizedScopes` — Subset of `scopes` requiring end-user consent. Misleading: this is *will-ask*, not *did-grant*. ## File coverage -- `src/v1/model.ts` (435 lines): read fully — 21 type exports, 13 schema exports. -- `src/v1/client.ts` (468 lines): read fully — 1 class, 10 async methods, 2 async generators. +- `src/v1/model.ts` (488 lines): read fully — 22 type exports, 13 schema exports. +- `src/v1/client.ts` (526 lines): read fully — 1 class, 11 async methods, 3 async generators. - `src/v1/utils.ts` (151 lines): read fully — generic across packages. -- `src/v1/index.ts` (30 lines): read fully — re-exports. -- `package.json` (41 lines): read for context. +- `src/v1/index.ts` (33 lines): read fully — re-exports. +- `package.json`: read for context. + +## Fixed +- #1 Package name `oauthcustomappintegration` mis-scopes the package (originally cited at `package.json:2`): Fixed in regeneration on 2026-05-20 — the standalone package was consolidated into `@databricks/sdk-oauth`, eliminating the misleading package name. +- #6 `createTime: string` vs `clientSecretExpireTime: Temporal.Instant` type inconsistency (originally cited at `model.ts:61, 89, 157`): Fixed in regeneration on 2026-05-20 — the `clientSecretExpireTime` field was removed during consolidation; the type-inconsistency between two timestamp fields no longer exists. +- #7 `clientSecretExpireTime` verb tense (originally cited at `model.ts:89`): Fixed in regeneration on 2026-05-20 — the field was removed during consolidation. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md index b47f8290..be6e46d9 100644 --- a/.agent/naming-audit/oauthpublishedapp.md +++ b/.agent/naming-audit/oauthpublishedapp.md @@ -1,78 +1,69 @@ # Naming Audit: oauthpublishedapp -**Path:** `packages/oauthpublishedapp/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/oauth/src/v1/` (consolidated package — formerly `packages/oauthpublishedapp/`) **Versions audited:** v1 -**Inferred domain:** Account-level read-only catalog of Databricks-blessed third-party OAuth applications (e.g. Power BI, Tableau Desktop) that can be enabled for an account. The package exposes a single endpoint that lists the published-app catalog rows. Each `PublishedOAuthApp` is a *catalog entry* (template) — not an *integration row* (which is the realised binding tracked by the sibling `oauthcustomappintegration` package). The package therefore plays "catalog index" to `oauthcustomappintegration`'s "registration manager". Domain underpinning is RFC 6749 (OAuth 2.0) client-type "published" applications, augmented by a Databricks-owned catalog of vetted third-party clients. -**Total weird names flagged:** 12 +**Inferred domain:** Account-level read-only catalog of Databricks-blessed third-party OAuth applications (e.g. Power BI, Tableau Desktop) that can be enabled for an account. The published-app surface exposes `listPublishedOAuthApps` returning a paginated `PublishedOAuthApp` catalog row. As of the 2026-05-20 regeneration the package was merged into the broader `@databricks/sdk-oauth` package, which now also carries the custom-integration and published-integration surfaces formerly audited under `oauthcustomappintegration`. +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | -| High | 3 | +| High | 1 | | Medium | 6 | | Low | 3 | | Observation | 1 | ## High severity -### 1. Package name `oauthpublishedapp` is singular but the package only exposes a *list* endpoint — `package.json:2`, `client.ts:62` -- **Why weird:** The package is `@databricks/sdk-oauthpublishedapp` (singular `app`). It exposes exactly one user-facing method, `listPublishedOAuthApps`, which returns a paginated *collection* of catalog rows. There is no `get`/`create`/`update`/`delete` — the package only ever operates over the plural set. The singular package name reads as "a thing that represents one published app", but the API contract is "the catalog of all published apps". Compare to the sibling `oauthcustomappintegration` (also incorrectly singular, audit finding #1 there). Both packages share the singular/plural mismatch. -- **Category:** 9 (singular/plural mismatch — package and class names suggest one entity, surface is purely collection-oriented) -- **Suggested name:** `@databricks/sdk-oauthpublishedapps` (plural), or `@databricks/sdk-oauthappcatalog` (re-cast as a catalog concept). -- **Rationale:** Reading `import { Client } from '@databricks/sdk-oauthpublishedapp/v1'` suggests there is a per-app client. A reader will land on the file expecting `getPublishedOAuthApp(id)`, `createPublishedOAuthApp(…)`, etc., and find only `listPublishedOAuthApps`. Pluralizing the package would set correct expectations. The Go reference at `databricks/api/oauth2/oauthpublishedapp` carries the same wart; a 1:1 port should still resolve it for TS since Go's package-vs-method namespacing rules don't apply. - -### 2. Every domain type re-states `PublishedOAuthApp` in full — `model.ts:5, 15, 22` -- **Why weird:** Inside a package named `oauthpublishedapp`, every type still spells "PublishedOAuthApp" or "PublishedOAuthApps" inside its name: `ListPublishedOAuthApps`, `PublishedOAuthApp`. The package import already declares the namespace; the type names re-declare it. The same pattern appears (more egregiously) in `oauthcustomappintegration` — finding #2 there. - ```ts - import { - ListPublishedOAuthApps, - PublishedOAuthApp, - } from '@databricks/sdk-oauthpublishedapp/v1'; - ``` - Every type repeats 16+ characters of "PublishedOAuthApp" that are already in the import path. -- **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) -- **Suggested name:** Drop the `PublishedOAuthApps?` qualifier from every type. With a namespace import the call site reads `published.List`, `published.App`. With named imports, alias if needed: `import { App as PublishedOAuthApp }`. -- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it in type names produces walls of identifiers where the eye has to skip the redundant prefix to find the discriminator. Pattern is a 1:1 port from Go (`oauthpublishedapp.PublishedOAuthApp` is necessary in Go because Go has no struct-level method namespacing); TS does not share that constraint. - -### 3. `appId` on `PublishedOAuthApp` is a slug, not an opaque ID — `model.ts:24` -- **Why weird:** `PublishedOAuthApp.appId` is documented as "Unique ID of the published OAuth app". The doc gives no examples here, but the sibling `oauthcustomappintegration` package's `CreatePublishedOAuthAppIntegration.appId` (which is the same value used to enable a published app in that account) is documented as `For example power-bi, tableau-deskop` (sic — typo carried in original). The appId is therefore a human-readable slug like `power-bi`, not an opaque UUID. Calling it `appId` and typing it as `string` collides with the convention that `xId` is an opaque opaque-ID (cf. `accountId`, `integrationId`, `clientId`, `principalId`). Same finding as `oauthcustomappintegration` #5; the value flows between the two packages and should be named consistently across both. +### 1. `appId` on `PublishedOAuthApp` is a slug, not an opaque ID — `model.ts:156` +- **Why weird:** `PublishedOAuthApp.appId` is documented as "Unique ID of the published OAuth app". The sibling `CreatePublishedOAuthAppIntegrationRequest.appId` (line 34, same file) is documented as `For example power-bi, tableau-deskop` (sic — typo carried in original). The appId is therefore a human-readable slug like `power-bi`, not an opaque UUID. Calling it `appId` and typing it as `string` collides with the convention that `xId` is an opaque opaque-ID (cf. `accountId`, `integrationId`, `clientId`, `principalId`). Since both types now live in the same package (`packages/oauth/src/v1/model.ts`), the disagreement is now intra-package. - **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) -- **Suggested name:** `appSlug` or `publishedAppKey` with the type narrowed to a literal union: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, document the format inline ("dash-separated lowercase slug from the Databricks published-app catalog") and cross-reference `CreatePublishedOAuthAppIntegration.appId` in the sibling package. -- **Rationale:** Every other `xId` in this codebase (`accountId`, `clientId`) is an opaque identifier. Mixing in a slug under the same suffix is a teaching trap. Two packages disagree by silence on what `appId` is. +- **Suggested name:** `appSlug` or `publishedAppKey` with the type narrowed to a literal union: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, document the format inline ("dash-separated lowercase slug from the Databricks published-app catalog") and align with `CreatePublishedOAuthAppIntegrationRequest.appId`. +- **Rationale:** Every other `xId` in this codebase (`accountId`, `clientId`) is an opaque identifier. Mixing in a slug under the same suffix is a teaching trap. Two types in the same package disagree by silence on what `appId` is. ## Medium severity -### 4. `clientId` field lacks the convention-matching closing period — `model.ts:25` +### 2. Every domain type re-states `PublishedOAuthApp` in full — `model.ts:137, 147, 154` +- **Why weird:** Inside the consolidated `oauth` package, every published-app type still spells "PublishedOAuthApp" or "PublishedOAuthApps" inside its name: `ListPublishedOAuthAppsRequest`, `ListPublishedOAuthAppsRequest_Response`, `PublishedOAuthApp`. After consolidation the package namespace is now `oauth`, so the qualifier is justified to disambiguate from the custom and published *integration* types in the same module (`PublishedOAuthAppIntegration` lives at line 171). But the qualifier on `Published` vs `PublishedOAuthAppIntegration` does only a small amount of work — both share the `OAuthApp` infix and disambiguate purely via the trailing `Integration`. Reads as 16-character prefix stutter on every type. +- **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology) +- **Suggested name:** With consolidation, distinguish strictly via the `…Integration` suffix and drop `PublishedOAuth` from the catalog row: `App` (the catalog row) vs `PublishedAppIntegration` / `CustomAppIntegration` (the registrations). At minimum drop the redundant `OAuth` infix everywhere — the parent package is already `oauth`. +- **Rationale:** TypeScript module imports already qualify the namespace. The `OAuth` infix is fully redundant once the package is `@databricks/sdk-oauth`. The remaining `Published` qualifier earns its keep only insofar as it distinguishes the catalog row from the published-integration row. + +### 3. `clientId` field lacks the convention-matching closing period — `model.ts:157-158` - **Why weird:** Doc comment reads `Client ID of the published OAuth app. It is the client_id in the OAuth flow` — missing trailing period (`flow` ends the sentence). Every other doc comment in the file ends with a period. Also, the wire-form `client_id` is hardcoded into the JSDoc text, which leaks generator-side terminology into TS docs that should describe the TS field. Repository CLAUDE.md rule: "Every comment must be a proper sentence ending with a period." - **Category:** Not strictly a name finding, but a generator-side text issue — included because it sits on a name field and is visible at every hover. - **Suggested name:** Doc text only; field name `clientId` is correct. Fix to: `Client ID of the published OAuth app. Matches the OAuth 2.0 \`client_id\` parameter (RFC 6749 §2.2).` - **Rationale:** Comment-style rule on the project. The reference to RFC 6749 §2.2 gives the term a spec anchor instead of leaving "client_id in the OAuth flow" as a vague pointer. -### 5. `isConfidentialClient` named inconsistently across packages — `model.ts:31-32` -- **Why weird:** The sibling `oauthcustomappintegration` exposes the same OAuth concept under the field name `confidential` (no `is…Client` prefix). The two packages model the same RFC 6749 §2.1 client-type flag with different identifiers, so a consumer juggling both has to remember that `customIntegration.confidential` and `publishedApp.isConfidentialClient` are the same flag. Audit finding #12 in `oauthcustomappintegration` recommends renaming that side to `isConfidentialClient` — so the *name* here is the right one; the sibling is the side to align. -- **Category:** 12 (duplicate concept across packages, inconsistent naming) -- **Suggested name:** Keep `isConfidentialClient` here. Cross-package fix lives in the sibling audit (#12 there). -- **Rationale:** The flag's value space and meaning are identical across the two packages; the identifier should be too. Resolve at the sibling, not here. +### 4. `isConfidentialClient` vs `confidential` inconsistent within the same package — `model.ts:164` (vs `model.ts:12, 54`) +- **Why weird:** Consolidation merged the published-app and custom-integration model files. The same RFC 6749 §2.1 client-type flag is now spelled three ways within one model file: `confidential` on `CreateCustomOAuthAppIntegrationRequest` (line 12) and `CustomOAuthAppIntegration` (line 54), versus `isConfidentialClient` on `PublishedOAuthApp` (line 164). What used to be a cross-package inconsistency is now an intra-package one. The boolean-prefix rule (`is…`) plus the `Client` clarifier here are the more descriptive name; the custom-integration side is the side to align. +- **Category:** 12 (duplicate concept across types, inconsistent naming) — now elevated to intra-package +- **Suggested name:** Pick one — `isConfidentialClient` is the clearer name. Rename the three `confidential` occurrences in custom integration types to match. +- **Rationale:** The flag's value space and meaning are identical across the three types; the identifier should be too. Consolidation makes this a single-package fix. -### 6. `redirectUrls: string[]` field stutter with `URI`/`URL` spec language — `model.ts:33-34` -- **Why weird:** OAuth 2.0 spec (RFC 6749 §3.1.2) calls these *redirection URIs*. The TS field uses `redirectUrls` (lowercase `rl`); the JSDoc reads "Redirect URLs of the published OAuth app." matching the field name. The sibling `oauthcustomappintegration` finding #13 documents that the package mixes URI / URL in JSDoc and field names; here the package uses `URLs` consistently within itself but contradicts spec language. The casing `Urls` (lowercase `rl`) follows Google TS style guide § Identifiers (acronyms ≥3 chars are PascalCase, but `URL` historically is exempted in many guides — TypeScript ecosystem standard is `Url`). +### 5. `redirectUrls: string[]` field stutter with `URI`/`URL` spec language — `model.ts:165-166` +- **Why weird:** OAuth 2.0 spec (RFC 6749 §3.1.2) calls these *redirection URIs*. The TS field uses `redirectUrls` (lowercase `rl`); the JSDoc reads "Redirect URLs of the published OAuth app." matching the field name. Elsewhere in the same model file the doc uses "redirect urls" (lowercase, lines 7, 50, 212) and "redirect URIs" (line 217) interchangeably — the latter inside `UpdateCustomOAuthAppIntegrationRequest`. The casing `Urls` (lowercase `rl`) follows Google TS style guide. - **Category:** 3 (acronym casing — `URL` lowercased as `Url` while `OAuth` keeps `Auth` mid-token uppercase, inconsistent acronym treatment within the same identifier set) - **Suggested name:** Keep `redirectUrls` (matches Google TS style guide https://google.github.io/styleguide/tsguide.html#identifiers), but cross-reference RFC 6749 §3.1.2 in the JSDoc so the spec term is visible: "Redirect URLs of the published OAuth app (RFC 6749 §3.1.2 \"redirection URIs\")." -- **Rationale:** Consistent with sibling package finding #13. The doc-term mismatch (URI in spec, URL in code) is the real issue; the casing is correct per Google TS. +- **Rationale:** The doc-term mismatch (URI in spec, URL in code, both in JSDoc within the same file) is the real issue; the casing is correct per Google TS. -### 7. `scopes: string[]` carries no enum/union — `model.ts:35-36` -- **Why weird:** Sibling `oauthcustomappintegration` documents the supported scope set inline: `Supported scopes: all-apis, sql, offline_access, openid, profile, email`. Here the same field is typed `string[]` with no JSDoc enumeration: just "Required scopes for the published OAuth app." Both packages share the same scope vocabulary (it is the Databricks OAuth scope set), and one documents it, the other does not. -- **Category:** 1, 12 (vague — string[] could be anything; duplicate concept across packages, inconsistent treatment) -- **Suggested name:** Keep `scopes`, but type as `Array<'all-apis' | 'sql' | 'offline_access' | 'openid' | 'profile' | 'email'>` to match the sibling package's documented vocabulary. At minimum, JSDoc the supported scopes. -- **Rationale:** Two packages model the same wire field. The custom package documents the value space; the published package leaves it open. A consumer reading `app.scopes` has no in-IDE way to learn the valid values. +### 6. `scopes: string[]` carries no enum/union — `model.ts:167-168` +- **Why weird:** Custom-integration types in the same file document the supported scope set inline: `Supported scopes: all-apis, sql, offline_access, openid, profile, email` (lines 16-18). Here the same field is typed `string[]` with no JSDoc enumeration: just "Required scopes for the published OAuth app." Same vocabulary, asymmetric documentation within one file. +- **Category:** 1, 12 (vague — string[] could be anything; duplicate concept across types, inconsistent treatment) +- **Suggested name:** Keep `scopes`, but type as `Array<'all-apis' | 'sql' | 'offline_access' | 'openid' | 'profile' | 'email'>` to match the custom-integration documented vocabulary. At minimum, JSDoc the supported scopes. +- **Rationale:** Two types in the same package model the same wire field. The custom variant documents the value space; the published variant leaves it open. -### 8. `pageSize: number` lacks bounds and unit context — `model.ts:11` +### 7. `pageSize: number` lacks bounds and unit context — `model.ts:142-143` - **Why weird:** Doc says "The max number of OAuth published apps to return in one page." but does not document the maximum-permitted value, default, or whether `0` means "unset" or "zero results". `pageSize` is the most common cross-API pagination footgun; some Databricks APIs reject `pageSize > 1000`, others treat `0` as "use default", others as "return zero". A consumer doing `req.pageSize = 0` gets undefined behaviour. The name `pageSize` itself is fine and consistent with Databricks API conventions (and Google AIP-158 https://google.aip.dev/158). - **Category:** 1 (vague — `number` with no bounds reads as "any int", but isn't) - **Suggested name:** Name is fine; doc should be "The maximum number of published OAuth apps to return in one page. Defaults to server-side default (typically 100). Maximum: 1000." - **Rationale:** Same field exists in many sibling packages; document once at the source of truth (the generator's pagination template). -### 9. `pageToken: string` reuses the previous-response `nextPageToken` — implicit cross-field contract — `model.ts:8-9`, `model.ts:18-19` +### 8. `pageToken: string` reuses the previous-response `nextPageToken` — implicit cross-field contract — `model.ts:140-141`, `model.ts:150-151` - **Why weird:** Request `pageToken` and response `nextPageToken` are two halves of one pagination contract. The names use different roots (`page…` vs `nextPage…`), so the connection is invisible. A new reader has to read both shapes and the iterator to understand `req.pageToken = resp.nextPageToken`. This is the Google AIP-158 convention (https://google.aip.dev/158) and shared by every paginated Databricks API, but worth flagging at project level since the naming asymmetry repeats everywhere. - **Category:** 17 (inconsistent action verbs — `pageToken` is a noun, `nextPageToken` is a noun; the asymmetry is in the prefix `next…`) - **Suggested name:** Keep names (they match AIP-158); document the relationship in JSDoc: "Pass `nextPageToken` from the previous response as `pageToken` to fetch the next page." @@ -80,48 +71,52 @@ ## Low severity -### 10. `OAuth` casing is consistent — `model.ts:throughout` -- **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants. Matches Google TS style guide guidance and matches RFC 6749. Matches sibling `oauthcustomappintegration`. No action. +### 9. `OAuth` casing is consistent — `model.ts:throughout` +- **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants. Matches Google TS style guide guidance and matches RFC 6749. No action. - **Category:** 3 (acronym casing — flagged compliant) - **Suggested name:** None — confirm the project-wide policy is `OAuth`. - **Rationale:** Documenting compliance. -### 11. `Client` class — generic single export, common to all generated packages — `client.ts:32` -- **Why weird:** Same pattern as every other package in this SDK. `import { Client } from '@databricks/sdk-oauthpublishedapp/v1'` produces an unqualified `Client` symbol. Consumers using multiple packages must alias: `import { Client as OAuthPublishedAppClient }`. Project-wide pattern, not specific to this package. +### 10. `Client` class — generic single export, common to all generated packages — `client.ts:69` +- **Why weird:** Same pattern as every other package in this SDK. `import { Client } from '@databricks/sdk-oauth/v1'` produces an unqualified `Client` symbol. Consumers using multiple packages must alias: `import { Client as OAuthClient }`. After consolidation this class now hosts the full custom-integration + published-integration + published-app surface (no longer a one-method client), making the generic name even more of a navigation hazard. - **Category:** 1 (vague/generic) -- **Suggested name:** `OAuthPublishedAppClient` (still inside `…/v1`). Project-wide change. -- **Rationale:** Defer to the project-wide naming-audit summary. Same as sibling finding #19. +- **Suggested name:** `OAuthClient` (still inside `…/v1`). Project-wide change. +- **Rationale:** Defer to the project-wide naming-audit summary. -### 12. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:17` -- **Why weird:** The response collection field. Unlike the sibling package's `apps` field finding (`oauthcustomappintegration` #4) where the field carried *integrations* and the name was misleading, here the field genuinely is published apps. The name is correct *but* it duplicates the type name (`apps: PublishedOAuthApp[]` — "apps of type App"). Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). Acceptable. +### 11. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:149` +- **Why weird:** The response collection field. Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). After consolidation the response types `ListCustomOAuthAppIntegrationsRequest_Response` (line 118) and `ListPublishedOAuthAppIntegrationsRequest_Response` (line 131) also expose an `apps` field whose values are *integrations*, not apps. So within one package the `apps` field name now collides in meaning across three response types. - **Category:** 15 (generic field — `apps` is the maximally-generic plural of `app`) — flagged for completeness -- **Suggested name:** Keep `apps`. Or rename `publishedApps` to make plural+domain explicit. No strong action. -- **Rationale:** Within the response type, the field name is unambiguous. Cross-package consistency with `oauthcustomappintegration` is broken (that package's `apps` field is misleading), but renaming this one would not fix that — the sibling rename is the right place. +- **Suggested name:** Rename to `publishedApps` here (and the two sibling responses to `customIntegrations` / `publishedIntegrations`) to make plural+domain explicit. +- **Rationale:** Now an intra-package collision after consolidation — three response types all expose `apps` with different semantics. ## Observations -### O1. JSDoc literal templating: this package has `` token leak — `client.ts:61` -- Sibling `oauthcustomappintegration` has six JSDoc strings containing literal `` / `` tokens (their finding O1). This package has one such leak — the JSDoc on `listPublishedOAuthApps` reads "Get all the available published OAuth apps in ``". Same generator bug. +### O1. JSDoc literal templating: this surface has `` token leak — `client.ts:402` +- The JSDoc on `listPublishedOAuthApps` reads "Get all the available published OAuth apps in ``". Same generator bug appears on the `TokenAccessPolicy.enableSingleUseRefreshTokens` doc (`model.ts:195`) and on `CustomOAuthAppIntegrationSecret.clientId` / `.clientSecret` docs (`model.ts:73, 76`). Five total `` token leaks now visible in this single file after consolidation. ## Domain glossary - `accountId` — Databricks account UUID (top-level tenant). Distinct from a workspace ID. -- `appId` — Slug key into the Databricks published-app catalog (e.g. `power-bi`, `tableau-desktop`). Despite the `Id` suffix, this is a human-readable name. Same value space as `oauthcustomappintegration.CreatePublishedOAuthAppIntegration.appId`. +- `appId` — Slug key into the Databricks published-app catalog (e.g. `power-bi`, `tableau-desktop`). Despite the `Id` suffix, this is a human-readable name. Same value space as `CreatePublishedOAuthAppIntegrationRequest.appId` in the same model file. - `clientId` — RFC 6749 client identifier (OAuth `client_id`). Stable per published app. - `OAuth` — IETF OAuth 2.0 (RFC 6749). Always cased `OAuth` in this package. -- `Published` app — Databricks-blessed third-party application (Power BI, Tableau Desktop, …) available to be enabled in an account. Distinct from a `Custom` integration (caller-defined OAuth client, lives in `oauthcustomappintegration`). +- `Published` app — Databricks-blessed third-party application (Power BI, Tableau Desktop, …) available to be enabled in an account. Distinct from a `Custom` integration (caller-defined OAuth client, now lives in the same consolidated `oauth` package as `CustomOAuthAppIntegration`). - `redirectUrls` — RFC 6749 §3.1.2 "redirection URIs" registered for the published app. - `scopes` — RFC 6749 scope strings the published app may request (`all-apis`, `sql`, `offline_access`, `openid`, `profile`, `email`). ## Cross-package coupling notes -- `appId` value space is shared with `oauthcustomappintegration.CreatePublishedOAuthAppIntegration.appId`. Renaming on one side must rename on the other. -- `isConfidentialClient` here ↔ `confidential` on the sibling — same underlying concept, inconsistent boolean naming. -- `scopes: string[]` here ↔ `scopes: string[]` on the sibling — same vocabulary, only the sibling documents the literal value set. -- Both packages share the `OAuth` casing convention. -- Suggested cross-package action: lift `PublishedOAuthApp` (catalog row) into a shared module imported by both packages, so `oauthcustomappintegration` can reference the canonical row when an account enables a published app. +- After the 2026-05-20 regeneration, the `oauthpublishedapp` and `oauthcustomappintegration` packages were merged into `@databricks/sdk-oauth`. What were previously cross-package consistency issues (boolean naming, scope vocabulary, `appId` value space) are now intra-package consistency issues. See findings #1, #4, #6, #11. +- The shared catalog row `PublishedOAuthApp` and the registration row `PublishedOAuthAppIntegration` now coexist in `model.ts`; the previous suggestion to "lift `PublishedOAuthApp` into a shared module" is satisfied by the consolidation. ## File coverage -- `src/v1/model.ts` (69 lines): read fully — 3 type exports, 2 schema exports. -- `src/v1/client.ts` (114 lines): read fully — 1 class, 1 async method, 1 async generator. -- `src/v1/utils.ts` (150 lines): read fully — generic across packages, identical to sibling's `utils.ts`. -- `src/v1/index.ts` (11 lines): read fully — re-exports `Client` and three types. -- `package.json` (38 lines): read for context. +- `src/v1/model.ts` (488 lines): read fully — published-app types are `PublishedOAuthApp`, `ListPublishedOAuthAppsRequest`, `ListPublishedOAuthAppsRequest_Response`, plus shared `TokenAccessPolicy` and the custom/published integration types. +- `src/v1/client.ts`: read fully — `Client` class hosts `listPublishedOAuthApps` (line 403) and `listPublishedOAuthAppsIter` (line 439) alongside the custom-integration and published-integration methods. +- `src/v1/utils.ts`: read for context — generic across packages, identical to siblings. +- `src/v1/index.ts`: read for context — re-exports `Client` and model types. +- `package.json`: now `@databricks/sdk-oauth` (consolidated). + +## Fixed +- #1 Package name `oauthpublishedapp` singular vs collection-only surface (originally cited at `package.json:2`, `client.ts:62`): Fixed in regeneration on 2026-05-20 — `oauthpublishedapp` package was merged into the multi-resource `@databricks/sdk-oauth` package, eliminating the singular-package-with-one-list-method concern. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md index c2909d0d..b3ce5f3e 100644 --- a/.agent/naming-audit/onlinetables.md +++ b/.agent/naming-audit/onlinetables.md @@ -92,11 +92,11 @@ | Severity | Count | | --------------------- | ----- | -| High | 5 | -| Medium | 13 | +| High | 4 | +| Medium | 10 | | Low / SDK-wide note | 9 | | Pass / acceptable | 9 | -| **Total findings** | **36** | +| **Total findings** | **31** | (Several findings touch multiple audit categories; counts above are unique findings.) @@ -105,43 +105,7 @@ findings.) ## Findings -### 1. `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) - -**Symbol:** `OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED` (model.ts:9). - -**Issue:** Members are already namespaced under `OnlineTableState`. The -`ONLINE_TABLE_STATE_` segment duplicates the enum name. Reads as: -```ts -if (table.status?.detailedState === OnlineTableState.ONLINE_TABLE_STATE_UNSPECIFIED) { ... } -// ^^^^^^^^^^^^^^^^^^^^ -// duplicates the enum name -``` - -Note: the values double as on-the-wire JSON strings (`z.enum(OnlineTableState)` -at model.ts:341 parses raw API strings directly into these identifiers), so -renaming the wire string requires server acceptance and is a behavioural -change. The TS-side identifier can be split from the wire string (see -finding 3) for a safe local fix. - -**Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. -**Suggested TS-level only (safe — see finding 3):** `Unspecified = -'ONLINE_TABLE_STATE_UNSPECIFIED'`. - ---- - -### 2. `ProvisioningInfo_State.STATE_UNSPECIFIED` value prefix repeats half the enum name — category 2 (Redundant enum prefixes) - -**Symbol:** `ProvisioningInfo_State.STATE_UNSPECIFIED` (model.ts:58). - -**Issue:** Same family as finding 1. The `STATE_` prefix repeats the trailing -half of the enum name. - -**Suggested:** TS-side identifier `Unspecified`. Wire string remains -`STATE_UNSPECIFIED` if upstream still emits it. - ---- - -### 3. SCREAMING_SNAKE_CASE enum members (value-level) — category 4 +### 1. SCREAMING_SNAKE_CASE enum members (value-level) — category 4 **Symbols:** Every value in both enums (model.ts:9–53 and 58–64). @@ -190,23 +154,7 @@ and `database.md` finding 6. --- -### 4. `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` value too long — category 18 (Long enum values) - -**Symbol:** `OnlineTableState.ONLINE_UPDATING_PIPELINE_RESOURCES` (model.ts:53) -and `PROVISIONING_PIPELINE_RESOURCES` (model.ts:16). - -**Issue:** 35–37 character enum members. Even allowing for the wire-level -prefix, the values pack three concepts (online/provisioning + transition + -"pipeline-resources"). The JSDoc explains them; the identifier itself is -hard to read. - -**Suggested:** at the TS level, `OnlineUpdatingPipelineResources` shortens to -30 chars while preserving meaning. The wire form is fixed by upstream. **Pass -in isolation if finding 3 is applied; flag as a long-name observation.** - ---- - -### 5. `OnlineTableState` modelled as one enum, two semantic groups — category 6 (Misleading names) and category 12 (Duplicate concepts) +### 2. `OnlineTableState` modelled as one enum, two semantic groups — category 6 (Misleading names) and category 12 (Duplicate concepts) **Symbol:** `OnlineTableState` (model.ts:7), 12 values. @@ -224,7 +172,7 @@ This is a wire-level concern, but in TS it reads as a single enum doing two jobs — top-level lifecycle and one-level-down detail. Compare to `database.SyncedTableState` which has the same 12 values prefixed `SYNCED_TABLE_…` (with a famous typo `SYNCED_TABLED_OFFLINE`). The duplication -*across packages* is also a flag — see finding 6. +*across packages* is also a flag — see finding 3. **Suggested:** push back upstream — split into `OnlineTableLifecycle` (a few top-level states) and use `detailedStatus.$case` as the substate identifier. @@ -232,7 +180,7 @@ top-level states) and use `detailedStatus.$case` as the substate identifier. --- -### 6. Cross-package collision: `OnlineTableState` ↔ `database.SyncedTableState` (wire-level typo) — category 12 (Duplicate concepts) and category 17 (Inconsistent action verbs) +### 3. Cross-package collision: `OnlineTableState` ↔ `database.SyncedTableState` (wire-level typo) — category 12 (Duplicate concepts) and category 17 (Inconsistent action verbs) **Symbol:** `OnlineTableState` (here, model.ts:7) and `SyncedTableState` (`database/v1/model.ts:55`, `postgres/v1/model.ts`). @@ -242,10 +190,9 @@ the state of a UC-managed Delta-to-managed-store sync table — with two *different enum names* and one is misspelled at the **wire-string** level (`SYNCED_TABLED_OFFLINE`). Looking at the values: -- `onlinetables.OnlineTableState`: 12 values, prefix `ONLINE_TABLE_STATE_…` - on `UNSPECIFIED` only. -- `database.SyncedTableState`: 12 values, prefix `SYNCED_TABLE_…` on **all - values** plus the famous wire-string typo `SYNCED_TABLED_OFFLINE`. +- `onlinetables.OnlineTableState`: 12 values. +- `database.SyncedTableState`: 12 values, plus the famous wire-string typo + `SYNCED_TABLED_OFFLINE`. These enums describe the *same machine*. A consumer who uses both packages will write a lookup table or branch on `$case` differently in each package. @@ -259,7 +206,7 @@ flag for SDK-wide alignment**; do not fix unilaterally in this package. --- -### 7. Cross-package collision: `PipelineProgress` ↔ `database.SyncedTablePipelineProgress` — category 12 (Duplicate concepts) +### 4. Cross-package collision: `PipelineProgress` ↔ `database.SyncedTablePipelineProgress` — category 12 (Duplicate concepts) **Symbol:** `PipelineProgress` (here, model.ts:202) and `database.SyncedTablePipelineProgress` (`database/v1/model.ts:744`, @@ -279,7 +226,7 @@ or extract both into `@databricks/sdk-core` if the dependency is acceptable. --- -### 8. Cross-package collision: `ProvisioningInfo` defined in 4+ packages — category 12 (Duplicate concepts) +### 5. Cross-package collision: `ProvisioningInfo` defined in 4+ packages — category 12 (Duplicate concepts) **Symbol:** `ProvisioningInfo` (here, model.ts:220) and its sibling state enum. Also defined in: @@ -299,7 +246,7 @@ union to guarantee parity. **SDK-wide cleanup.** --- -### 9. Cross-package collision: `DeleteOnlineTableRequest` defined in two packages with different fields — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) +### 6. Cross-package collision: `DeleteOnlineTableRequest` defined in two packages with different fields — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) **Symbol:** `DeleteOnlineTableRequest` (here, model.ts:93) and `featurestore.DeleteOnlineTableRequest` (`featurestore/v1/model.ts:57`). @@ -333,7 +280,7 @@ sibling `GetOnlineTableRequest.name` (model.ts:119) in this very package. --- -### 10. `CreateOnlineTableRequest.table` field name is too generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 7. `CreateOnlineTableRequest.table` field name is too generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `CreateOnlineTableRequest.table?: OnlineTable | undefined` (model.ts:89). @@ -348,7 +295,7 @@ time.** --- -### 11. `OnlineTable.name` is a three-part UC name, not a free-text name — category 19 (Underspecified IDs) and category 1 (Vague/generic) +### 8. `OnlineTable.name` is a three-part UC name, not a free-text name — category 19 (Underspecified IDs) and category 1 (Vague/generic) **Symbol:** `OnlineTable.name?: string | undefined` (model.ts:125). JSDoc: "Full three-part (catalog, schema, table) name of the table." @@ -386,7 +333,7 @@ inconsistency.** --- -### 12. `OnlineTable.tableServingUrl` repeats "table" — category 8 (Redundant suffixes) +### 9. `OnlineTable.tableServingUrl` repeats "table" — category 8 (Redundant suffixes) **Symbol:** `OnlineTable.tableServingUrl?: string | undefined` (model.ts:131). @@ -401,7 +348,7 @@ this table" — `servingUrl` reads the same. --- -### 13. `OnlineTable.unityCatalogProvisioningState` is overly verbose — category 7 (Overly verbose) +### 10. `OnlineTable.unityCatalogProvisioningState` is overly verbose — category 7 (Overly verbose) **Symbol:** `OnlineTable.unityCatalogProvisioningState?: ProvisioningInfo_State | undefined` (model.ts:137). 31 characters. @@ -424,7 +371,7 @@ Reasonable parallel names would be: --- -### 14. `OnlineTable.status` vs `OnlineTable.unityCatalogProvisioningState` — category 17 (Inconsistent action verbs) and category 6 (Misleading names) +### 11. `OnlineTable.status` vs `OnlineTable.unityCatalogProvisioningState` — category 17 (Inconsistent action verbs) and category 6 (Misleading names) **Symbols:** `OnlineTable.status` (model.ts:129), `OnlineTable.unityCatalogProvisioningState` (model.ts:137). @@ -443,11 +390,11 @@ not `status` — surprising. **Suggested:** rename `status` to `syncStatus` or `dataSyncStatus` to make clear it is about the *data pipeline*, not the entity. Pair with -`provisioningState` (finding 13) for the UC-side entity state. +`provisioningState` (finding 10) for the UC-side entity state. --- -### 15. `OnlineTableStatus.detailedState` vs `OnlineTableStatus.detailedStatus` — category 17 (Inconsistent action verbs) and category 12 (Duplicate concepts) +### 12. `OnlineTableStatus.detailedState` vs `OnlineTableStatus.detailedStatus` — category 17 (Inconsistent action verbs) and category 12 (Duplicate concepts) **Symbols:** `OnlineTableStatus.detailedState` (model.ts:183), `OnlineTableStatus.detailedStatus` (model.ts:187). @@ -472,7 +419,7 @@ forms a coherent shape. **Flag at port time.** --- -### 16. `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` all share `…Status` suffix — category 20 (Type-suffix tautology) — *pass with note* +### 13. `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` all share `…Status` suffix — category 20 (Type-suffix tautology) — *pass with note* **Symbols:** `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` (model.ts:71, 238, 102, 226). @@ -486,7 +433,7 @@ disambiguate from `OnlineTableSpec`/state enums. The `Failed` and `Provisioning` variants are also generic when read in isolation — there could be many "failed status" or "provisioning status" types in the SDK (and there are — see `database.SyncedTableProvisioningStatus`, -finding 17 below). +finding 14 below). **Suggested:** consider prefixing with the parent concept — e.g. `OnlineTableContinuousUpdate`, `OnlineTableTriggeredUpdate`, @@ -495,7 +442,7 @@ with note**, flag cross-package overlap below. --- -### 17. Cross-package overlap: `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` ↔ `database.SyncedTable*Status` — category 12 (Duplicate concepts) +### 14. Cross-package overlap: `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` ↔ `database.SyncedTable*Status` — category 12 (Duplicate concepts) **Symbols:** - `onlinetables.ContinuousUpdateStatus` ↔ `database.SyncedTableContinuousUpdateStatus` @@ -506,7 +453,7 @@ with note**, flag cross-package overlap below. **Issue:** All four pairs model the same shape (fields are identical or near-identical). `database` adds a `SyncedTable` prefix to each — disambiguates within `@databricks/sdk-core` if these were merged, but creates a duplicate -type surface across packages. Same root cause as finding 6 (`OnlineTableState` +type surface across packages. Same root cause as finding 3 (`OnlineTableState` ↔ `SyncedTableState`). **Suggested:** harmonise — define once in `@databricks/sdk-onlinetables` or @@ -514,7 +461,7 @@ in `@databricks/sdk-core` and re-export. **SDK-wide cleanup.** --- -### 18. `PipelineProgress.latestVersionCurrentlyProcessing` is awkward — category 7 (Overly verbose) and category 13 (Verb-tense inconsistency) +### 15. `PipelineProgress.latestVersionCurrentlyProcessing` is awkward — category 7 (Overly verbose) and category 13 (Verb-tense inconsistency) **Symbol:** `PipelineProgress.latestVersionCurrentlyProcessing?: number | undefined` (model.ts:207). 32 characters. @@ -547,7 +494,7 @@ upstream and port-time fix.** --- -### 19. `PipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` mixed nouns — category 17 (Inconsistent action verbs) and category 8 (Redundant suffixes) +### 16. `PipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` mixed nouns — category 17 (Inconsistent action verbs) and category 8 (Redundant suffixes) **Symbols:** `PipelineProgress.syncedRowCount` (model.ts:209), `PipelineProgress.totalRowCount` (model.ts:211), @@ -576,7 +523,7 @@ the parent type name `PipelineProgress` — though circular). --- -### 20. `PipelineProgress.estimatedCompletionTimeSeconds` unit-suffix is fine — *pass* +### 17. `PipelineProgress.estimatedCompletionTimeSeconds` unit-suffix is fine — *pass* **Symbol:** `PipelineProgress.estimatedCompletionTimeSeconds` (model.ts:215). @@ -590,19 +537,19 @@ preference. **Pass.**) --- -### 21. `OnlineTableSpec.sourceTableFullName` — category 8 (Redundant suffixes) and category 19 (Underspecified IDs) — see finding 11 +### 18. `OnlineTableSpec.sourceTableFullName` — category 8 (Redundant suffixes) and category 19 (Underspecified IDs) — see finding 8 **Symbol:** `OnlineTableSpec.sourceTableFullName?: string | undefined` (model.ts:156). -Already covered in finding 11. **Pass with note** — `Full` qualifier is +Already covered in finding 8. **Pass with note** — `Full` qualifier is redundant when JSDoc already specifies "Three-part (catalog, schema, table) name". `sourceTableName` would suffice. Cross-reference `featurestore.PublishTableRequest.sourceTableName` (no `Full`). --- -### 22. `OnlineTableSpec.timeseriesKey` vs `OnlineTableSpec.primaryKeyColumns` (singular vs plural) — category 9 (Singular/plural mismatch) +### 19. `OnlineTableSpec.timeseriesKey` vs `OnlineTableSpec.primaryKeyColumns` (singular vs plural) — category 9 (Singular/plural mismatch) **Symbols:** `OnlineTableSpec.primaryKeyColumns?: string[]` (model.ts:158), `OnlineTableSpec.timeseriesKey?: string` (model.ts:160). @@ -623,7 +570,7 @@ single-column scalar. --- -### 23. `OnlineTableSpec.performFullCopy` is a verb-as-field — category 13 (Verb-tense inconsistency) and category 6 (Misleading names) +### 20. `OnlineTableSpec.performFullCopy` is a verb-as-field — category 13 (Verb-tense inconsistency) and category 6 (Misleading names) **Symbol:** `OnlineTableSpec.performFullCopy?: boolean | undefined` (model.ts:169). @@ -641,7 +588,7 @@ SDK-wide `enable*` boolean pattern). Cross-reference --- -### 24. `OnlineTableSpec.pipelineId` is server-generated — category 6 (Misleading names) — *pass with note* +### 21. `OnlineTableSpec.pipelineId` is server-generated — category 6 (Misleading names) — *pass with note* **Symbol:** `OnlineTableSpec.pipelineId?: string | undefined` (model.ts:171). JSDoc: "ID of the associated pipeline. Generated by the server - cannot be @@ -658,7 +605,7 @@ input/output), not a naming bug. --- -### 25. `OnlineTableSpec.schedulingPolicy` discriminated-union case names use verb prefixes — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) +### 22. `OnlineTableSpec.schedulingPolicy` discriminated-union case names use verb prefixes — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) **Symbol:** `OnlineTableSpec.schedulingPolicy` $case literals `'runContinuously'` / `'runTriggered'` (model.ts:145, 150). @@ -680,7 +627,7 @@ spec.schedulingPolicy = { $case: 'runContinuously', runContinuously: {} }; --- -### 26. `CreateOnlineTableRequest` and `GetOnlineTableRequest` and `DeleteOnlineTableRequest` repeat `OnlineTable` — category 7 (Overly verbose) — *pass, SDK-wide pattern* +### 23. `CreateOnlineTableRequest` and `GetOnlineTableRequest` and `DeleteOnlineTableRequest` repeat `OnlineTable` — category 7 (Overly verbose) — *pass, SDK-wide pattern* **Symbols:** `CreateOnlineTableRequest`, `DeleteOnlineTableRequest`, `GetOnlineTableRequest` (model.ts:87, 93, 117). @@ -692,14 +639,14 @@ package qualifies. **Pass on package consistency.** --- -### 27. `Client` class name — category 1 (Vague/generic) — *pass* +### 24. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-onlinetables/v1.Client`). **Pass.** --- -### 28. `Client.createOnlineTable` etc. — *pass* +### 25. `Client.createOnlineTable` etc. — *pass* **Symbols:** `Client.createOnlineTable` (client.ts:67), `Client.deleteOnlineTable` (client.ts:108), `Client.getOnlineTable` @@ -715,7 +662,7 @@ SDK-wide convention. **Pass.** --- -### 29. `Client.createOnlineTableWaiter` returns a `CreateOnlineTableWaiter` — category 14 (Go/Java-style names) +### 26. `Client.createOnlineTableWaiter` returns a `CreateOnlineTableWaiter` — category 14 (Go/Java-style names) **Symbol:** `Client.createOnlineTableWaiter` (client.ts:92), returns `CreateOnlineTableWaiter` (client.ts:152). @@ -739,7 +686,7 @@ waiter naming policy.** --- -### 30. `CreateOnlineTableWaiter.wait` and `CreateOnlineTableWaiter.done` — *pass* +### 27. `CreateOnlineTableWaiter.wait` and `CreateOnlineTableWaiter.done` — *pass* **Symbols:** `CreateOnlineTableWaiter.wait` (client.ts:163), `CreateOnlineTableWaiter.done` (client.ts:207). @@ -748,7 +695,7 @@ Standard. **Pass.** --- -### 31. `StillRunningError` class is internal but module-scoped — *pass* +### 28. `StillRunningError` class is internal but module-scoped — *pass* **Symbol:** `class StillRunningError extends Error {}` (client.ts:39). @@ -757,7 +704,7 @@ retry"). **Pass.** --- -### 32. `host` / `httpClient` / `logger` / `userAgent` private fields — *pass* +### 29. `host` / `httpClient` / `logger` / `userAgent` private fields — *pass* **Symbols:** Private fields on `Client` (client.ts:42–48). Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but @@ -765,7 +712,7 @@ matches the project rule (`HttpClient`, `Url` would be flagged, but --- -### 33. `PACKAGE_SEGMENT` constant SCREAMING_SNAKE — category 4 +### 30. `PACKAGE_SEGMENT` constant SCREAMING_SNAKE — category 4 **Symbol:** `PACKAGE_SEGMENT` (client.ts:34). @@ -781,7 +728,7 @@ SDK-wide cleanup**, do not fix in isolation. --- -### 34. Comment on `PACKAGE_SEGMENT` is a sentence-fragment in lowercase — category 14 (Go/Java-style names) — *pass* +### 31. Comment on `PACKAGE_SEGMENT` is a sentence-fragment in lowercase — category 14 (Go/Java-style names) — *pass* The JSDoc comment at client.ts:33 ("Package identity segment for this client to be used in the User-Agent header.") is fine — proper sentence, ends with @@ -789,7 +736,7 @@ a period (matches `.agent/rules` / user CLAUDE.md style). --- -### 35. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 32. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` interface (utils.ts:15). @@ -803,7 +750,7 @@ any fix must apply everywhere). --- -### 36. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 33. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). @@ -856,7 +803,7 @@ recommendation:** consolidate. Options: `onlinetables.DeleteOnlineTableRequest.name` vs. `featurestore.DeleteOnlineTableRequest.onlineTableName`. Already covered in -finding 9. Harmonise on `name`. +finding 6. Harmonise on `name`. --- @@ -873,31 +820,31 @@ correct it without breaking compatibility. **Flag for protocol team.** | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, cross-package collisions) | 5 | #3, #9, #15, #23, #33, **and** cross-package A | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 13 | #1, #2, #4, #5, #6, #10, #11, #12, #13, #14, #17, #18, #19, #21, #25 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 9 | #7, #8, #16, #22, #24, #26, #29, #35, #36 | -| **Pass / acceptable** | 9 | #16, #20, #22, #24, #26, #27, #28, #30, #31, #32, #34 | +| **High** (style guide violations, cross-package collisions) | 4 | #1, #6, #12, #20, #30, **and** cross-package A | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 10 | #2, #3, #4, #7, #8, #9, #10, #11, #14, #15, #16, #18, #22 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 9 | #4, #5, #13, #19, #21, #23, #26, #32, #33 | +| **Pass / acceptable** | 9 | #13, #17, #19, #21, #23, #24, #25, #27, #28, #29, #31 | --- ## Top fixes (highest local return) -1. **#9** — harmonise `DeleteOnlineTableRequest.name` vs. +1. **#6** — harmonise `DeleteOnlineTableRequest.name` vs. `featurestore.DeleteOnlineTableRequest.onlineTableName` field name. Quick cross-package fix. -2. **#12** — rename `OnlineTable.tableServingUrl` → `servingUrl`. Local, +2. **#9** — rename `OnlineTable.tableServingUrl` → `servingUrl`. Local, no other consumers. -3. **#13** — rename `OnlineTable.unityCatalogProvisioningState` → +3. **#10** — rename `OnlineTable.unityCatalogProvisioningState` → `provisioningState`. Local. -4. **#10** — rename `CreateOnlineTableRequest.table` → `onlineTable`. Local +4. **#7** — rename `CreateOnlineTableRequest.table` → `onlineTable`. Local port-time fix. -5. **#15** — rename `OnlineTableStatus.detailedState` → `state` and +5. **#12** — rename `OnlineTableStatus.detailedState` → `state` and `detailedStatus` → `statusDetails` / `details`. Local readability win. -6. **#18** — rename `PipelineProgress.latestVersionCurrentlyProcessing` → +6. **#15** — rename `PipelineProgress.latestVersionCurrentlyProcessing` → `lastProcessedVersion`. Matches sibling `lastProcessedCommitVersion`. -7. **#19** — rename `PipelineProgress.syncProgressCompletion` → +7. **#16** — rename `PipelineProgress.syncProgressCompletion` → `completionRatio`. Local. -8. **#23** — rename `OnlineTableSpec.performFullCopy` → `enableFullCopy` +8. **#20** — rename `OnlineTableSpec.performFullCopy` → `enableFullCopy` (matches SDK `enable*` boolean pattern). --- @@ -908,8 +855,8 @@ correct it without breaking compatibility. **Flag for protocol team.** families into one canonical surface. 2. **Cross-package C** — fix the `SYNCED_TABLED_OFFLINE` wire-string typo at the protocol layer. -3. **#3** — `UpperCamelCase` enum members (string value preserved as wire +3. **#1** — `UpperCamelCase` enum members (string value preserved as wire form). -4. **#33** — `PACKAGE_SEGMENT` → `packageSegment`. -5. **#29** — settle waiter naming convention (`*Waiter` vs `*Poller` vs +4. **#30** — `PACKAGE_SEGMENT` → `packageSegment`. +5. **#26** — settle waiter naming convention (`*Waiter` vs `*Poller` vs inline `*AndWait`). diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md index 8df316c2..37487f24 100644 --- a/.agent/naming-audit/permissions.md +++ b/.agent/naming-audit/permissions.md @@ -1,6 +1,10 @@ # Naming Audit: permissions -**Path:** `packages/permissions/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/accessmanagement/src/v1/` (originally `packages/permissions/`, consolidated into `accessmanagement` during regeneration). **Versions audited:** v1 **Inferred domain:** Workspace-object permissions — get, set, update, and inspect ACLs (access control lists) attached to Databricks workspace objects (clusters, jobs, notebooks, dashboards, pipelines, registered models, queries, repos, files, instance pools, etc.). Distinct from `grants` (Unity Catalog privileges on UC securables), though the two surfaces overlap conceptually and lexically. **Total weird names flagged:** 33 @@ -8,86 +12,58 @@ ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 14 | -| Low | 4 | -| Observation | 4 | +| High | 7 | +| Medium | 18 | +| Low | 5 | +| Observation | 3 | -The permissions package contains 9 generated types, 1 enum, and 4 client methods, plus utility helpers. Three thematic problems dominate. (1) The request-as-imperative-verb pattern (`GetObjectPermissions`, `SetObjectPermissions`, `UpdateObjectPermissions`, `GetPermissionLevels`) collides with the verb-noun methods on `Client`, so users write `client.setObjectPermissions(req: SetObjectPermissions)` and the type name looks like a command rather than a payload. (2) The `PermissionLevel` enum mixes acronym-prefix patterns (`CAN_*`, `IS_*`) with redundant suffixes (`CAN_MONITOR` vs `CAN_MONITOR_ONLY`, `CAN_MANAGE_RUN`, `CAN_CREATE_APP`) and includes a sentinel `UNSPECIFIED` whose semantics ("delete this principal") are only discoverable from JSDoc — the value name actively misleads. (3) The package overlaps heavily with `grants` in vocabulary (`Permission`, `PermissionsResponse`, `permissionLevels`) while modelling a completely different concept; the only public type distinguishing this package from its sibling is `AccessControlRequest`/`Response`, both of which use the IAM-style "access control list" pattern that's unique-in-the-SDK. +The permissions surface contains 9 generated types, 1 enum, and 4 client methods, plus utility helpers. After regeneration, the four request types (`GetObjectPermissions`, `SetObjectPermissions`, `UpdateObjectPermissions`, `GetPermissionLevels`) gained `Request` suffixes — eliminating the worst of the verb-shaped-type problems. What remains on the `PermissionLevel` enum is the redundant `CAN_` action-verb prefix on 19 of 20 values (the lone `IS_OWNER` mixes a different copula), the `_ONLY` qualifier on `CAN_MONITOR_ONLY`, and the object-type-specific values (`CAN_MANAGE_STAGING_VERSIONS`, `CAN_CREATE_APP`) leaking into a universal enum. -A further structural wart surfaces as a result of mechanical proto-to-TS porting: every request type tags its path-parameter fields with a verbose `requestObjectType` / `requestObjectId` prefix (rather than `objectType`/`objectId` or just `type`/`id`) — the prefix is wire-format leakage. Finally, `requestObjectType` and `requestObjectId` are typed `string` with a documented closed enumeration of valid values listed verbatim in JSDoc (26 different object types in a single doc-comment), surfacing the "stringly-typed closed enum" anti-pattern that TypeScript's type system would otherwise prevent. +The structural wart from mechanical proto-to-TS porting persists: every request type tags its path-parameter fields with a verbose `requestObjectType` / `requestObjectId` prefix (rather than `objectType`/`objectId` or just `type`/`id`) — the prefix is wire-format leakage. `requestObjectType` and `requestObjectId` are still typed `string` with a documented closed enumeration of valid values listed verbatim in JSDoc (26 different object types in a single doc-comment), surfacing the "stringly-typed closed enum" anti-pattern that TypeScript's type system would otherwise prevent. The package also overlaps heavily with `grants` in vocabulary (`Permission`, `PermissionsResponse`, `permissionLevels`) while modelling a completely different concept. --- ## High severity -### 1. `GetObjectPermissions` (type) — `src/v1/model.ts:79` -- **Why weird:** Top-level request type named with an imperative verb. `Get` is a verb; types are nouns. Used in `client.ts:67` as `getObjectPermissions(req: GetObjectPermissions)`, producing verb-noun-verb-noun. Reader cannot tell from `GetObjectPermissions` whether this is a request shape or a method name. -- **Category:** 7 (overly verbose / structural), 14 (Go-style request-type naming), 17 (inconsistent action verbs). -- **Suggested name:** `GetObjectPermissionsRequest` (matches the SDK-wide `*Request` convention used in `accountaccesscontrol`, `grants` partially, etc.) or simpler `ObjectPermissionsQuery` / `ObjectRef`. -- **Rationale:** Same anti-pattern documented in `.agent/naming-audit/grants.md` #1. Verb-shaped type names are reserved for methods. - -### 2. `SetObjectPermissions` (type) — `src/v1/model.ts:115` -- **Why weird:** Same as #1. `Set` is a verb. Type is used at `client.ts:121` as `setObjectPermissions(req: SetObjectPermissions)`. -- **Category:** 7, 14, 17. -- **Suggested name:** `SetObjectPermissionsRequest` or `ObjectPermissionsAssignment`. -- **Rationale:** See #1. - -### 3. `UpdateObjectPermissions` (type) — `src/v1/model.ts:123` -- **Why weird:** Same as #1, #2. Verb-shaped type. Used at `client.ts:147` as `updateObjectPermissions(req: UpdateObjectPermissions)`. -- **Category:** 7, 14, 17. -- **Suggested name:** `UpdateObjectPermissionsRequest` or `ObjectPermissionsPatch` (since the HTTP method is PATCH, not PUT — see #29). -- **Rationale:** See #1. - -### 4. `GetPermissionLevels` (type) — `src/v1/model.ts:86` -- **Why weird:** Verb-shaped type AND singular/plural collision: the type wraps a request asking for the list of permission levels available, but `GetPermissionLevels` reads like "the operation of getting permission levels" — a method. Inside the package there are then four overlapping `Permission*` names with this one being the most easily misread: it's a request type, not a response type, despite having the word "Levels" plural (which would suggest a result). -- **Category:** 7, 9 (singular/plural mismatch), 14, 17. -- **Suggested name:** `GetPermissionLevelsRequest` or `PermissionLevelsQuery`. -- **Rationale:** Disambiguates request vs response; aligns with #5. - -### 5. `PermissionLevel.UNSPECIFIED` — `src/v1/model.ts:31` -- **Why weird:** The enum value `UNSPECIFIED` is overloaded into a sentinel meaning "delete this principal's permissions" — but the *name* says the opposite ("unspecified"). The JSDoc on lines 27–30 clarifies this, but the name itself actively misleads: callers reading `permissionLevel: PermissionLevel.UNSPECIFIED` will reasonably interpret it as "no value set / left blank", not "remove the principal". Worse, the side-effect semantics (mutation) are encoded in what looks like a null-equivalent. -- **Category:** 6 (misleading name), 1 (vague). Sentinel-as-enum-value is a Go pattern. -- **Suggested name:** Split into a dedicated `Remove` or `Revoke` value (`PermissionLevel.REMOVE` or `PermissionLevel.NONE`) — or, better, model deletion as an absent `permissionLevel` field in PATCH calls (the field is already `optional`) and remove the sentinel entirely. The current name guarantees that anyone reading a diff will be confused about whether `UNSPECIFIED` is a no-op or a destructive action. -- **Rationale:** Sentinel-encoded-as-enum-value is an idiom imported from protobuf/Go (`google.protobuf.UNSPECIFIED`) where every enum is required to have a zero value. TypeScript has no such constraint; explicit absence (`undefined`) is idiomatic. - -### 6. `PermissionLevel` enum has 20 inconsistently-named values — `src/v1/model.ts:7–32` -- **Why weird:** Mix of three naming patterns within a single enum: - - `CAN_*` (most common): `CAN_MANAGE`, `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`. - - `IS_*`: `IS_OWNER`. The lone `IS_*` value mixes copula+predicate, while everything else is modal verb+predicate. - - Pseudo-sentinel: `UNSPECIFIED` (see #6). -- The `CAN_*` prefix is implied by membership in `PermissionLevel` — a `PermissionLevel` is, by definition, what the principal can do. The redundant `CAN_` prefix on 19 of 20 values is purely a wire-format leak from the Go enum, which followed the same protobuf convention. -- **Category:** 2 (redundant enum prefix — flagged explicitly in the task prompt), 17 (inconsistent action verbs within the same enum). -- **Suggested name:** Drop the `CAN_` prefix: `MANAGE`, `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, `USE`, etc. `IS_OWNER` becomes `OWNER`. `UNSPECIFIED` becomes `REMOVE` per #5 (or eliminated). -- **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. The same logic applies here: `PermissionLevel.MANAGE` is shorter, more readable, and just as unambiguous as `PermissionLevel.CAN_MANAGE` (Google TS Style Guide §5.4 prefers concise enum members; protobuf-style prefixes are a wire concern that does not need to leak into the surface). - -### 7. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` +### 1. `PermissionLevel` enum values share a redundant `CAN_` action-verb prefix — `src/v1/model.ts:6–27` +- **Why weird:** Of 20 values, 19 begin with `CAN_` (`CAN_MANAGE`, `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`); the lone exception is `IS_OWNER`, which uses a copula+predicate form. The `CAN_` prefix is implied by membership in `PermissionLevel` — a `PermissionLevel` is, by definition, what the principal can do — and is therefore content-free on every value. This is distinct from the proto-style enum-name prefix (which would be `PERMISSION_LEVEL_*`); here the redundancy is on the action-modal verb shared by 19 of 20 members. Mixing `CAN_*` with `IS_OWNER` also breaks within-enum consistency. +- **Category:** 2 (redundant action-verb prefix on enum members), 17 (inconsistent: 19 `CAN_*` action verbs alongside one `IS_*` copula). +- **Suggested name:** Drop the `CAN_` action-verb prefix: `MANAGE`, `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, `USE`, etc. `IS_OWNER` becomes `OWNER`. +- **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. `PermissionLevel.MANAGE` is shorter and just as unambiguous as `PermissionLevel.CAN_MANAGE` (Google TS Style Guide §5.4 prefers concise enum members; the `CAN_` modal verb does not need to repeat on every member). + +### 2. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` - **Why weird:** Two distinct values that differ in name only by the `_ONLY` suffix. The JSDoc (none provided) gives no clue what the difference is. From product context, `CAN_MONITOR` typically grants monitoring AND inherited subset privileges; `CAN_MONITOR_ONLY` strictly limits to monitoring. Cannot infer this from the names — must consult external API docs. - **Category:** 6 (misleading: pair seems exhaustive but `_ONLY` semantics are non-obvious), 17 (inconsistent: no other value uses `_ONLY` to differentiate). - **Suggested name:** Document inline what the difference is, OR rename to `MONITOR_FULL` / `MONITOR_READ_ONLY` / similar pair where the contrast is on the *predicate*, not on a vague `_ONLY` qualifier. - **Rationale:** Whenever an enum exposes "X" and "X_ONLY" with no JSDoc, every caller hits a Stack Overflow question. -### 8. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` — `src/v1/model.ts:17,18` -- **Why weird:** 28- and 30-character enum members. These values are specific to one object type (`registered-models` in MLflow Model Registry — staging vs production model versions) but live in a universal enum applicable to 25+ object types. Equivalent to having `CAN_MANAGE_DASHBOARD_DRAFTS` or `CAN_MANAGE_NOTEBOOK_REVISIONS` in the same enum: the values are scoped to one domain but visible to all. -- **Category:** 18 (long enum values — flagged explicitly in the task prompt), 17 (inconsistent — most values are object-type-agnostic, these two leak object-type semantics into the enum). -- **Suggested name:** Possibly `MANAGE_STAGING` / `MANAGE_PRODUCTION` with JSDoc clarifying applicability ("Applies to registered-models only"), or move these MLflow-specific levels into a separate enum. +### 3. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` — `src/v1/model.ts:17,18` +- **Why weird:** These values are specific to one object type (`registered-models` in MLflow Model Registry — staging vs production model versions) but live in a universal enum applicable to 25+ object types. Equivalent to having `CAN_MANAGE_DASHBOARD_DRAFTS` or `CAN_MANAGE_NOTEBOOK_REVISIONS` in the same enum: the values are scoped to one domain but visible to all. +- **Category:** 17 (inconsistent — most values are object-type-agnostic, these two leak object-type semantics into the enum). +- **Suggested name:** JSDoc clarifying applicability ("Applies to registered-models only"), or move these MLflow-specific levels into a separate enum. - **Rationale:** Universal enum + object-specific values is a discoverability hazard; users browsing autocomplete will see these as valid choices for clusters/jobs/dashboards. -### 9. `CAN_CREATE_APP` — `src/v1/model.ts:26` -- **Why weird:** Same problem as #8 — object-type-specific value in a universal enum. The `App` here refers to Databricks Apps (a specific object kind); other object types have no equivalent. The `_APP` suffix is also inconsistent with how the rest of the enum names the noun being created (most `CAN_CREATE` is unsuffixed; `CAN_CREATE_APP` is the only one with an explicit noun). -- **Category:** 18, 17. -- **Suggested name:** Same pattern as #8 — document scope, or partition. -- **Rationale:** See #8. +### 4. `CAN_CREATE_APP` — `src/v1/model.ts:26` +- **Why weird:** Same problem as #3 — object-type-specific value in a universal enum. The `App` here refers to Databricks Apps (a specific object kind); other object types have no equivalent. The `_APP` suffix is also inconsistent with how the rest of the enum names the noun being created (most `CAN_CREATE` is unsuffixed; `CAN_CREATE_APP` is the only one with an explicit noun). +- **Category:** 17. +- **Suggested name:** Same pattern as #3 — document scope, or partition. +- **Rationale:** See #3. -### 10. Concept duplication with `grants` package — cross-package -- **Why weird:** A sibling package `packages/grants/src/v1/` also defines a `Permission*` vocabulary (`PermissionsChange`, `getPermissions`, `updatePermissions`) for a different operation (Unity Catalog privileges on securables). Both packages re-export `Permission`-prefixed types from their `index.ts`. A user reading `import { Permission } from '@databricks/sdk-permissions/v1'` vs `import { PrivilegeAssignment } from '@databricks/sdk-grants/v1'` has no surface-level cue that these belong to disjoint domains. The `permissions` package operates on workspace objects (clusters, jobs, notebooks) via `requestObjectType: string` paths; the `grants` package operates on UC securables (catalogs, schemas, tables) via `securableType: string` paths. The vocabulary overlap obscures this distinction. +### 5. Concept duplication with `grants` package — cross-package +- **Why weird:** A sibling package `packages/grants/src/v1/` also defines a `Permission*` vocabulary (`PermissionsChange`, `getPermissions`, `updatePermissions`) for a different operation (Unity Catalog privileges on securables). Both packages re-export `Permission`-prefixed types from their `index.ts`. A user reading `import { Permission } from '@databricks/sdk-accessmanagement/v1'` vs `import { PrivilegeAssignment } from '@databricks/sdk-grants/v1'` has no surface-level cue that these belong to disjoint domains. The permissions surface operates on workspace objects (clusters, jobs, notebooks) via `requestObjectType: string` paths; the `grants` package operates on UC securables (catalogs, schemas, tables) via `securableType: string` paths. The vocabulary overlap obscures this distinction. - This same observation appears in `.agent/naming-audit/grants.md` #10 — flagged from the other side of the mirror. - **Category:** 12 (duplicate concepts across packages), 1 (vague top-level package naming). -- **Suggested name:** Rename one or both for disambiguation: `permissions` → `workspace-permissions` or `workspace-acl`; `grants` → `unity-catalog-grants` or `uc-privileges`. At minimum the public exports should be non-overlapping (no `Permission` prefix in both). +- **Suggested name:** Rename for disambiguation: keep the surface in `accessmanagement` but expose under a `workspace-permissions` or `workspace-acl` subpath; `grants` → `unity-catalog-grants` or `uc-privileges`. At minimum the public exports should be non-overlapping (no `Permission` prefix in both). - **Rationale:** The two packages cover non-overlapping concrete operations but use heavily overlapping vocabulary — an enormous discoverability hazard. -### 11. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:81,88,116,124` -- **Why weird:** Every request type carries `requestObjectType?: string | undefined`. The JSDoc on line 80 (and identically on 87, 116, 124) lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, clusters, cluster-policies, dashboards, database-projects, dbsql-dashboards, directories, experiments, files, genie, instance-pools, jobs, knowledge-assistants, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, supervisor-agents, vector-search-endpoints, or warehouses"`. The set is closed, well-known to the server, and stable — a perfect fit for a `RequestObjectType` enum or string literal union. The TS SDK ships it as bare `string` with no autocomplete or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) silently 4xx's at runtime. +### 6. `RequestAuthzIdentity` enum and `REQUEST_AUTHZ_IDENTITY_*` member prefix — `src/v1/model.ts:33–37` +- **Why weird:** The enum-type name starts with `Request` — a wire-format-message prefix (`RequestAuthzIdentity` reads as "the AuthzIdentity field on a request message"). Every member then re-states the entire enum name as a SCREAMING_SNAKE prefix: `REQUEST_AUTHZ_IDENTITY_UNSPECIFIED`, `REQUEST_AUTHZ_IDENTITY_USER_CONTEXT`, `REQUEST_AUTHZ_IDENTITY_SERVICE_IDENTITY`. This is the canonical proto3 enum convention — proto enum members must be globally unique within a file, so the enum name is required as a prefix; TypeScript enums have no such constraint, so the prefix is pure proto-architectural leakage. Also, the `UNSPECIFIED` zero value is a proto convention (every proto enum must have a zero value named `*_UNSPECIFIED`); TS enums have no such requirement. +- **Category:** Proto-architecture leak (enum-name-prefix on members, `Request` infix on type name, `_UNSPECIFIED` zero-value convention). +- **Suggested name:** `AuthzIdentity` enum with members `UNSPECIFIED`, `USER_CONTEXT`, `SERVICE_IDENTITY`. Better: drop `UNSPECIFIED` and make the field optional in the request types (TS-idiomatic absence is `undefined`). +- **Rationale:** Proto3-derived enum naming conventions add 25+ characters of redundant prefix per call site (`RequestAuthzIdentity.REQUEST_AUTHZ_IDENTITY_USER_CONTEXT` vs `AuthzIdentity.USER_CONTEXT`). The `Request` prefix on the type name implies the enum is only valid in request contexts, but it appears as a field on `CheckPolicyRequest` only — the enum itself is a domain concept (who's the actor), not a message-shape concept. + +### 7. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:156,163,340,348` +- **Why weird:** Every request type carries `requestObjectType?: string | undefined`. The JSDoc on line 155 (and identically on 162, 339, 347) lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, clusters, cluster-policies, dashboards, database-projects, dbsql-dashboards, directories, experiments, files, genie, instance-pools, jobs, knowledge-assistants, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, supervisor-agents, vector-search-endpoints, or warehouses"`. The set is closed, well-known to the server, and stable — a perfect fit for a `RequestObjectType` enum or string literal union. The TS SDK ships it as bare `string` with no autocomplete or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) silently 4xx's at runtime. - **Category:** 19 (underspecified ID), 1 (vague: bare `string`), 15 (generic field name). - **Suggested name:** Define `type RequestObjectType = 'alerts' | 'alertsv2' | 'authorization' | 'clusters' | 'cluster-policies' | ...` (string literal union, 26 entries), or an `enum RequestObjectType` with kebab-cased values. The JSDoc explicitly enumerates the values; TypeScript should encode that enumeration. - **Rationale:** This is the single biggest TS-affordance miss in the package. The Go SDK uses `string` because Go enums are second-class; TS has first-class string literal unions that match this exact use case. See also `.agent/naming-audit/grants.md` #19, #28 (same problem with `Privilege` and `SecurableType`). @@ -96,95 +72,119 @@ A further structural wart surfaces as a result of mechanical proto-to-TS porting ## Medium severity -### 12. `requestObjectType` / `requestObjectId` prefix — `src/v1/model.ts:81,83,88,89,117,119,125,127` +### 8. `requestObjectType` / `requestObjectId` prefix — `src/v1/model.ts:156,158,163,164,340,342,348,350` - **Why weird:** All four request types prefix their two path parameters with `request`: `requestObjectType` and `requestObjectId`. The `request` prefix is wire-format leakage (the Databricks REST path uses `:request_object_type` and `:request_object_id` as URL path placeholders, presumably from an older API spec). On the TypeScript surface, every field is by definition part of a *request* — the `request` prefix carries zero information. - **Category:** 7 (overly verbose / redundant prefix), 14 (wire-format leak), 15 (generic field name). - **Suggested name:** `objectType` and `objectId`. The doc-comment on `requestObjectId` already calls it "The id of the request object" — drop the wire-format jargon and just say "object id". -- **Rationale:** Compare `GetObjectPermissions { requestObjectType, requestObjectId }` to `GetObjectPermissions { objectType, objectId }`. The latter reads as plain English. The `request` prefix is the same kind of cruft that `requestId` would have if it appeared in a `Request` type. +- **Rationale:** Compare `GetObjectPermissionsRequest { requestObjectType, requestObjectId }` to `GetObjectPermissionsRequest { objectType, objectId }`. The latter reads as plain English. The `request` prefix is the same kind of cruft that `requestId` would have if it appeared in a `Request` type. -### 13. `principalName` discriminated union — `src/v1/model.ts:35–51,56–72` -- **Why weird:** The discriminated union pattern is elegant in TS, but the field name `principalName` is misleading because the values inside are not all "names" — `servicePrincipalName` is documented as "application ID of a service principal" (line 48), which is a UUID, not a name. Calling the carrier field `principalName` and the SP variant `servicePrincipalName` together imply "principal name = service principal name = the SP's name", but the SP variant is the application *ID*, distinct from the SP's display name. +### 9. `principalName` discriminated union — `src/v1/model.ts:47–63,68–84` +- **Why weird:** The discriminated union pattern is elegant in TS, but the field name `principalName` is misleading because the values inside are not all "names" — `servicePrincipalName` is documented as "application ID of a service principal" (line 60), which is a UUID, not a name. Calling the carrier field `principalName` and the SP variant `servicePrincipalName` together imply "principal name = service principal name = the SP's name", but the SP variant is the application *ID*, distinct from the SP's display name. - **Category:** 6 (misleading), 19 (underspecified ID), 15 (overloaded "name"). - **Suggested name:** Rename outer field to `principal` (per `grants` package convention, see #14) and rename the SP variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or document explicitly that `servicePrincipalName` is "the SP's application UUID, not its display name". - **Rationale:** Same field name leaks "name" semantics onto a value that's a UUID. Type system can encode this with proper variant naming. -### 14. `principalName` vs `principal` cross-package — `src/v1/model.ts:35,56` (this package) vs `grants/src/v1/model.ts:22,33,69` (grants package) -- **Why weird:** `permissions` uses `principalName?: { $case: 'userName' | 'groupName' | 'servicePrincipalName' }` — a typed discriminated union. `grants` uses `principal: string` — a free-form string with a JSDoc-only constraint ("user email address or group name"). Same concept, two utterly different representations across sister packages. A user familiar with one will not be productive in the other. +### 10. `principalName` vs `principal` cross-package — `src/v1/model.ts:47,68` (this package) vs `grants/src/v1/model.ts:22,33,69` (grants package) +- **Why weird:** This package uses `principalName?: { $case: 'userName' | 'groupName' | 'servicePrincipalName' }` — a typed discriminated union. `grants` uses `principal: string` — a free-form string with a JSDoc-only constraint ("user email address or group name"). Same concept, two utterly different representations across sister packages. A user familiar with one will not be productive in the other. - **Category:** 12 (duplicate concept), 17 (inconsistent shapes for the same domain object). -- **Suggested name:** Pick one across the SDK. The `permissions` package's discriminated union is strictly more type-safe and should be the canonical representation. +- **Suggested name:** Pick one across the SDK. This package's discriminated union is strictly more type-safe and should be the canonical representation. - **Rationale:** Consistency. Two packages, two ways to spell "who is this for". The audit on `grants` (#12) flagged this from the other side. -### 15. `displayName` on `AccessControlResponse` — `src/v1/model.ts:74` -- **Why weird:** `displayName?: string | undefined` doc-comment "Display name of the user or service principal." (line 73). But the response also carries `principalName` (line 56) which is the carrier-by-identity. Two name-like fields on the same response and the relationship is JSDoc-only. Worse, the JSDoc *doesn't* say "Display name of the user **or group** or service principal" — it omits groups, possibly because groups don't have display names — but the type allows `principalName.$case === 'groupName'` paired with a `displayName` value, which then has no specified semantics. +### 11. `displayName` on `AccessControlResponse` — `src/v1/model.ts:86` +- **Why weird:** `displayName?: string | undefined` doc-comment "Display name of the user or service principal." (line 85). But the response also carries `principalName` (line 68) which is the carrier-by-identity. Two name-like fields on the same response and the relationship is JSDoc-only. Worse, the JSDoc *doesn't* say "Display name of the user **or group** or service principal" — it omits groups, possibly because groups don't have display names — but the type allows `principalName.$case === 'groupName'` paired with a `displayName` value, which then has no specified semantics. - **Category:** 6 (misleading), 1 (vague: groups + displayName combo undocumented). - **Suggested name:** Keep `displayName` but expand doc-comment to cover all three principal kinds. - **Rationale:** Cross-checking variant + display-name semantics is an integration footgun. -### 16. `allPermissions: Permission[]` field — `src/v1/model.ts:76` +### 12. `allPermissions: Permission[]` field — `src/v1/model.ts:88` - **Why weird:** `allPermissions?: Permission[] | undefined` with JSDoc "All permissions." — minimal information value in the comment. The qualifier "all" suggests there's a "some permissions" variant that doesn't exist. Internally, the type just lists every effective permission (direct + inherited) — so the `all` prefix is the wire-format way of saying "the merged result". Stripping `all` would lose nothing. - **Category:** 7 (overly verbose), 1 (vague qualifier), 15 (generic field name on a typed array). - **Suggested name:** `permissions: Permission[]` (matches the type-name plural). The field would read `AccessControlResponse.permissions` — natural English. - **Rationale:** Field names that re-state the parent type or carry vague qualifiers add noise. The `all` qualifier here implies a `some`/`partial` companion that doesn't exist. -### 17. `Permission` type — `src/v1/model.ts:98` +### 13. `Permission` type — `src/v1/model.ts:244` - **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance of `Permission` here is really an "effective permission" — a permission level paired with inheritance metadata. The name `Permission` alone is the second-most-overloaded noun in the SDK (after `Client`). - **Category:** 1 (vague), 12 (cross-package collision: `grants` also exports `Permission`-prefixed types). - **Suggested name:** `EffectivePermission` (matches the doc semantics) or `PermissionGrant` (clarifies that this is a grant, not the concept of permission abstractly). - **Rationale:** `Permission` as a standalone PascalCase noun is so common across IAM systems that it's nearly content-free without qualification. -### 18. `PermissionsDescription` — `src/v1/model.ts:104` +### 14. `PermissionsDescription` — `src/v1/model.ts:256` - **Why weird:** Type carries `permissionLevel?: PermissionLevel | undefined` and `description?: string | undefined`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. Should be `PermissionLevelDescription` (singular). Also, the suffix `Description` is generic — the type is effectively a tuple of (level, description-text); it's the "metadata about a single permission level" record. - **Category:** 9 (singular/plural mismatch — `Permissions` plural for a single-level descriptor), 1 (generic suffix), 15 (vague field `description: string`). - **Suggested name:** `PermissionLevelDescription` or `PermissionLevelInfo`. - **Rationale:** Singular/plural matters; one descriptor = one level. -### 19. `PermissionsResponse` — `src/v1/model.ts:109` +### 15. `PermissionsResponse` — `src/v1/model.ts:261` - **Why weird:** Returned from THREE different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, `accessControlList` — i.e. it's "an ACL with metadata", not "a Permissions response". Name is generic; the *content* is the more meaningful concept ("ObjectAcl" or "AccessControlList"). - **Category:** 1 (vague), 7 (Response suffix tautology), 20 (type-suffix tautology — `Permissions` + `Response` adds no info beyond `AccessControlList`). - **Suggested name:** `ObjectAcl`, `ObjectPermissions`, or `AccessControlList`. Drop the `Response` suffix per the SDK-wide convention that responses are returned values, not named-as-such types. - **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental to it being a return value. -### 20. `accessControlList` field — `src/v1/model.ts:112,120,128` -- **Why weird:** Appears in three types (`PermissionsResponse`, `SetObjectPermissions`, `UpdateObjectPermissions`). The field is typed `AccessControlRequest[]` in the two request types and `AccessControlResponse[]` in the response — asymmetric typing under one field name. The conventional shorthand for "access control list" is "ACL" — the field could be `acl` (3 chars vs 18). Or just `entries` since the surrounding type already says "permissions" / "object permissions". +### 16. `accessControlList` field — `src/v1/model.ts:264,343,351` +- **Why weird:** Appears in three types (`PermissionsResponse`, `SetObjectPermissionsRequest`, `UpdateObjectPermissionsRequest`). The field is typed `AccessControlRequest[]` in the two request types and `AccessControlResponse[]` in the response — asymmetric typing under one field name. The conventional shorthand for "access control list" is "ACL" — the field could be `acl` (3 chars vs 18). Or just `entries` since the surrounding type already says "permissions" / "object permissions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology — field repeats type info), 17 (asymmetric: same field, different element types). - **Suggested name:** `acl: AccessControlEntry[]` or `entries: AccessControlEntry[]`. - **Rationale:** "Access control list" is verbose; "ACL" is standard. The asymmetric typing pattern is worth flattening. -### 21. `inherited` boolean field — `src/v1/model.ts:100` +### 17. `inherited` boolean field — `src/v1/model.ts:246` - **Why weird:** Bare `inherited?: boolean | undefined` on `Permission`. Boolean fields starting with a verb (`is*`, `has*`, `was*`) are easier to read at call sites. The current name reads `if (permission.inherited)` — fine, but `if (permission.isInherited)` is more idiomatic. - **Category:** 14 (Go/Java-style: Go boolean fields commonly drop the `is`/`has` prefix, TS convention varies). - **Suggested name:** `isInherited`. - **Rationale:** Google TS Style Guide §5.3 recommends boolean prefixes for readability. The codebase uses both conventions but `is*`-prefixed booleans are more common in IAM contexts. -### 22. `inheritedFromObject: string[]` — `src/v1/model.ts:101` -- **Why weird:** Plural field name (`Object`) typed as `string[]` of object identifiers. The "Object" suffix is singular but the type is plural — minor mismatch. More importantly, the JSDoc is missing entirely (line 101 has no comment) so the reader has to infer that this is the chain of inheritance paths from which this permission was derived. Each element is presumably an object path; the typing is bare `string`. +### 18. `inheritedFromObject: string[]` — `src/v1/model.ts:247` +- **Why weird:** Plural field name (`Object`) typed as `string[]` of object identifiers. The "Object" suffix is singular but the type is plural — minor mismatch. More importantly, the JSDoc is missing entirely (line 247 has no comment) so the reader has to infer that this is the chain of inheritance paths from which this permission was derived. Each element is presumably an object path; the typing is bare `string`. - **Category:** 9 (singular/plural mismatch), 19 (underspecified ID), 1 (vague — no JSDoc). - **Suggested name:** `inheritedFromObjects: string[]` (plural for plural), or `inheritanceChain: string[]`. Document the element format. - **Rationale:** Plurality should match the type's plurality; semantics should be JSDoc'd. -### 23. `Client` — `src/v1/client.ts:41` -- **Why weird:** Top-level class named `Client`. Generic across every generated package. Users importing `Client` from multiple permission-adjacent packages (`@databricks/sdk-permissions`, `@databricks/sdk-grants`, `@databricks/sdk-accountaccesscontrol`) must alias all three. +### 19. `Client` — `src/v1/client.ts:69` +- **Why weird:** Top-level class named `Client`. Generic across every generated package. Users importing `Client` from multiple permission-adjacent packages (`@databricks/sdk-accessmanagement`, `@databricks/sdk-grants`, `@databricks/sdk-accountaccesscontrol`) must alias all three. - **Category:** 1 (vague), 12 (cross-package name clash). -- **Suggested name:** `PermissionsClient`. +- **Suggested name:** `PermissionsClient` or `AccessManagementClient`. - **Rationale:** SDK convention in AWS, Azure, GitHub Octokit, etc. is service-prefixed client class names. -### 24. `requestObjectType` doc-comment duplication — `src/v1/model.ts:80,87,116,124` +### 20. `requestObjectType` doc-comment duplication — `src/v1/model.ts:155,162,339,347` - **Why weird:** Four identical 1-line doc-comments listing all 26 valid object types. The list is 280 characters long and is copy-pasted verbatim into every request type. Any change requires four parallel edits. - **Category:** Observation, 17 (consistency — all four are identical, so this isn't an inconsistency, but it is fragile). -- **Suggested name:** Define `type RequestObjectType` (see #11) and link to it from a single source of truth. +- **Suggested name:** Define `type RequestObjectType` (see #6) and link to it from a single source of truth. - **Rationale:** DRY for documentation, type-safe for callers. +### 21. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` +- **Why weird:** Four types use the proto-style nested-message underscore convention: `DeleteWorkspacePermissionAssignmentRequest_Response`, `GetPermissionLevelsRequest_Response`, `GetWorkspacePermissionAssignmentsRequest_Response`, `ListWorkspacePermissionsRequest_Response`. Each is annotated with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` — the comment explicitly admits the leak. In proto, a `Response` message can be declared inside the `Request` message, yielding the path `Foo.Request.Response`; the generator flattens this to `FooRequest_Response`. The underscore is wire-format leakage. The corresponding zod schemas (`unmarshalDeleteWorkspacePermissionAssignmentRequest_ResponseSchema`, etc.) carry the same wart at `model.ts:441,454,466,488`. +- **Category:** Proto-architecture leak (underscore-nested proto-message naming), 17 (inconsistent: most response types in this package are top-level `*Response`, only these four use the nested form). +- **Suggested name:** Top-level `DeleteWorkspacePermissionAssignmentResponse`, `GetPermissionLevelsResponse`, `GetWorkspacePermissionAssignmentsResponse`, `ListWorkspacePermissionsResponse`. Remove the `eslint-disable` annotations once renamed. +- **Rationale:** TypeScript has no concept of nested message types; the underscore separator is a proto-specific path encoding. Every consumer importing these types must hand-type the underscore. Same problem flagged generator-wide in `.agent/naming-audit/_SUMMARY.md` (drop `_Response` underscore suffix). + +### 22. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:250,268,383` +- **Why weird:** Three types ending with `Output`. In proto / gRPC service definitions, message types are commonly named `FooInput` (request) and `FooOutput` (response) — the `Output` suffix is the proto-RPC naming pattern. On the TypeScript surface, `Output` is meaningless: every value is "output" of *something* (a function call, a marshal, a parse). The package uses `Request`/`Response` as the standard envelope suffix and only these three types break the pattern. +- **Category:** Proto-architecture leak (`Output` suffix is proto-RPC convention), 17 (inconsistent: `Request`/`Response` elsewhere, `Output` on these three). +- **Suggested name:** `WorkspacePermission` (already taken by the enum — pick a different domain noun like `WorkspacePermissionDescription`), `Principal`, `WorkspacePermissionAssignment`. Drop the `Output` suffix; the types are concrete domain entities, not RPC payloads. +- **Rationale:** `Output` is wire-format jargon. Compare `principal: PrincipalOutput` to `principal: Principal` — the latter reads as plain English. + +### 23. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` +- **Why weird:** Three methods carry the `Proxy` suffix and are byte-for-byte identical to their non-`Proxy` siblings (lines 218, 292, 366). They issue the same HTTP request to the same URL with the same headers. The `Proxy` suffix communicates an architectural concept — these are the same operation routed through a proxy server in the Databricks control plane — that has zero meaning for a TypeScript SDK caller. From the SDK's perspective, the two methods are indistinguishable. +- **Category:** Proto-architecture leak (`Proxy` suffix mid/end-position is backend-routing jargon, not domain), 12 (duplicate concept: two methods, one operation), 17 (inconsistent: most operations have one method, these have two). +- **Suggested name:** Delete the `*Proxy` variants entirely. If the proxy-routing distinction matters server-side, the server can route the same URL internally; the client should not surface it. If only one variant is the "canonical" one, document that and remove the duplicate. +- **Rationale:** Method-name suffixes should describe what the operation does, not how the server routes it. Two identical methods with a `Proxy` differentiator force every caller to flip a coin. + +### 24. `RuleSetUpdateRequest` — `src/v1/model.ts:322` +- **Why weird:** The verb `Update` appears mid-name; the same package's convention elsewhere is `UpdateRequest` (see `UpdateRuleSetRequest` on line 354, `UpdateWorkspacePermissionAssignmentRequest` on line 362, `UpdateObjectPermissionsRequest` on line 346). `RuleSetUpdateRequest` swaps the verb to a mid-position attributive — likely because in proto, `RuleSetUpdateRequest` is the *body* type carrying the patch payload, while `UpdateRuleSetRequest` is the *RPC* envelope carrying both the routing path and the body. The `Update` mid-position is wire-format leakage from the proto `UpdateRuleSetRequest { string name; RuleSetUpdateRequest rule_set; }` shape. From the TS surface, two `Update`-something types in the same file with different positions of `Update` is jarring. +- **Category:** Proto-architecture leak (mid-position action verb from proto request-envelope/body split), 17 (inconsistent naming with the same-package `Update*Request` types). +- **Suggested name:** `RuleSetUpdate` (a patch object), or fold the fields into `UpdateRuleSetRequest` directly and remove the inner envelope. +- **Rationale:** The proto convention of "outer RPC request + inner body message" doesn't translate to TS — you can just put all fields on one request type. The `*UpdateRequest` mid-position verb only exists because of that envelope split. + ### 25. `flattenQueryParams` (utility) — `src/v1/utils.ts:123` -- **Why weird:** Exported but unused in this package — `permissions` client doesn't take query parameters in any of its four methods. Dead-looking export, identical to the same wart documented in `.agent/naming-audit/grants.md` #37. +- **Why weird:** Generic generated helper exported into every package. Now used by `checkPolicy` (`client.ts:536,545,555`), so no longer a dead export here. Still suffers the same problem documented in `.agent/naming-audit/grants.md` #37: the helper is identical across packages and should live in a shared `@databricks/sdk-core` module rather than be re-emitted per package. - **Category:** 11 (effectively-internal exports), Observation. -- **Suggested name:** Remove (or move to a shared `@databricks/sdk-core` util). -- **Rationale:** Generator emits the same helper into every package even when unused. +- **Suggested name:** Move to a shared `@databricks/sdk-core` util; keep name `flattenQueryParams` (already descriptive). +- **Rationale:** Generator emits the same helper into every package; consolidation reduces surface and tree-shake risk. --- ## Low severity -### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` - **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -202,28 +202,45 @@ A further structural wart surfaces as a result of mechanical proto-to-TS porting - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. Same finding as `grants.md` #40. -### 29. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:146` -- **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 156). The request type `UpdateObjectPermissions` is symmetric in name to `SetObjectPermissions` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. A user reading both method names side-by-side (`set...` and `update...`) might reasonably assume both perform full replacement. +### 29. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:500,513` +- **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 513). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. A user reading both method names side-by-side (`set...` and `update...`) might reasonably assume both perform full replacement. - **Category:** 17 (inconsistent action verbs), Observation. - **Suggested name:** `patchObjectPermissions` for the PATCH method, OR explicit JSDoc on `update*` clarifying merge semantics. - **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. --- +### 30. `kind` discriminated-union field on `Actor` — `src/v1/model.ts:96` +- **Why weird:** `Actor.kind?: { $case: 'actorId'; actorId: number } | undefined` — the `kind` field name is a direct port of the proto `oneof kind { ... }` block convention. In proto, every `oneof` block has a developer-supplied name (commonly `kind`, `value`, or `data`); the convention bleeds straight into the generated TS as a field literally named `kind`. With a single-variant union (only `actorId`), the entire discriminator is dead weight — there's nothing else it could be. +- **Category:** Proto-architecture leak (`oneof` block name `kind` carried verbatim), 1 (vague). +- **Suggested name:** Flatten to `actorId?: number | undefined` directly on `Actor`. If a future variant gets added, then introduce a discriminated union with a meaningful discriminator name (e.g., `principal` per #10 — `userName`, `groupName`, `servicePrincipalName`). +- **Rationale:** A single-variant discriminated union is a proto modeling artifact, not a domain concept. + +--- + ## Observations -### 30. Three response paths converge on `PermissionsResponse` -`getObjectPermissions`, `setObjectPermissions`, and `updateObjectPermissions` all return the same `PermissionsResponse` type (`client.ts:70,123,149`). This is fine functionally but means callers can't distinguish "the state I just wrote" from "the state I just read" by type — only by which method was called. For an audit log or comparison flow, this loses information. Naming-adjacent because the type carries no read/write/post-update distinction. +### 31. Three response paths converge on `PermissionsResponse` +`getObjectPermissions`, `setObjectPermissions`, and `updateObjectPermissions` all return the same `PermissionsResponse` type (`client.ts:424,477,503`). This is fine functionally but means callers can't distinguish "the state I just wrote" from "the state I just read" by type — only by which method was called. For an audit log or comparison flow, this loses information. Naming-adjacent because the type carries no read/write/post-update distinction. - **Category:** Observation. -### 31. Sentinel value `UNSPECIFIED` in PATCH is the only mutation-state encoded in an enum -The `PermissionLevel.UNSPECIFIED` sentinel (see #5) is unique in the SDK: it's the only enum value across `permissions`, `grants`, `accountaccesscontrol`, and `iam` that doubles as a deletion marker when sent in a PATCH body. Most APIs model this with a separate request body shape (e.g. `removals: Principal[]`) or with HTTP DELETE. Encoding "remove me" as an enum value alongside "let me have this permission" is unusual. -- **Category:** Observation, 6 (misleading). - ### 32. Doc-comment list of object types is potentially stale The hardcoded list in `requestObjectType` doc-comments includes `database-projects`, `genie`, `knowledge-assistants`, `supervisor-agents` — all relatively new product surfaces. The list will need updating with every new permission-able workspace object. As-is the SDK has 26; if not regularly synced with the server, the JSDoc will drift. - **Category:** Observation. ### 33. No pagination — all methods are unpaginated single-call -Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods, see `grants.md` #41), `permissions` has no listing operation. Every method here is by-object-id; there's no "list all permissioned objects" surface. This is correct for the API but worth noting because users coming from `grants` (or `accountaccesscontrol`) might expect parallel list semantics. Naming-adjacent because the absence of `list*` here aligns the method-vocabulary differently than its sibling packages. +Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods, see `grants.md` #41), the permissions surface has no listing operation over workspace objects. Every method here is by-object-id; there's no "list all permissioned objects" surface. This is correct for the API but worth noting because users coming from `grants` (or `accountaccesscontrol`) might expect parallel list semantics. Naming-adjacent because the absence of `list*` here aligns the method-vocabulary differently than its sibling packages. - **Category:** Observation. + +--- + +## Fixed + +- #1 `GetObjectPermissions` (originally cited at `src/v1/model.ts:79`): Fixed in regeneration on 2026-05-20 — renamed to `GetObjectPermissionsRequest` (now `accessmanagement/src/v1/model.ts:154`), eliminating the verb-shaped type. +- #2 `SetObjectPermissions` (originally cited at `src/v1/model.ts:115`): Fixed in regeneration on 2026-05-20 — renamed to `SetObjectPermissionsRequest` (now `accessmanagement/src/v1/model.ts:338`), eliminating the verb-shaped type. +- #3 `UpdateObjectPermissions` (originally cited at `src/v1/model.ts:123`): Fixed in regeneration on 2026-05-20 — renamed to `UpdateObjectPermissionsRequest` (now `accessmanagement/src/v1/model.ts:346`), eliminating the verb-shaped type. +- #4 `GetPermissionLevels` (originally cited at `src/v1/model.ts:86`): Fixed in regeneration on 2026-05-20 — renamed to `GetPermissionLevelsRequest` (now `accessmanagement/src/v1/model.ts:161`), eliminating the verb-shaped type. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index 8ea9f1f8..48678f43 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -2,23 +2,23 @@ **Path:** `packages/pipelines/src/v2/` **Versions audited:** v2 -**Inferred domain:** Lakeflow Declarative Pipelines (formerly Delta Live Tables / DLT) — create / clone / get / list / edit / delete / restore pipelines, start / stop / list / get pipeline **updates** ("a run of a pipeline"), and a vast catalog of ingestion connectors (Salesforce, Workday, Outlook, Kafka, RabbitMQ, TikTok Ads, ServiceNow, Confluence, Jira, ...). The API was renamed multiple times (DLT → Spark Declarative Pipelines → Lakeflow Declarative Pipelines); branding leakage and acronyms are abundant. +**Inferred domain:** Lakeflow Declarative Pipelines (formerly Delta Live Tables / DLT) — create / clone / get / list / edit / delete pipelines, start / stop / list / get pipeline **updates** ("a run of a pipeline"), and a vast catalog of ingestion connectors (Salesforce, Workday, Outlook, Kafka, RabbitMQ, TikTok Ads, ServiceNow, Confluence, Jira, ...). The API was renamed multiple times (DLT → Spark Declarative Pipelines → Lakeflow Declarative Pipelines); branding leakage and acronyms are abundant. **Files audited:** -- `src/v2/model.ts` (6,198 lines) — 31 enums, ~110 interfaces, ~80 marshal/unmarshal schemas. -- `src/v2/client.ts` (646 lines) — 13 RPC methods + 2 paginators + `StopWaiter`. -- `src/v2/utils.ts` (151 lines) — generic HTTP/marshal helpers (no domain names). -- `src/v2/index.ts` (172 lines) — re-exports. +- `src/v2/model.ts` (~5,400 lines) — 26 enums, ~116 interfaces, marshal/unmarshal schemas. +- `src/v2/client.ts` (632 lines) — 12 RPC methods + 2 paginators + `StopWaiter`. +- `src/v2/utils.ts` (150 lines) — generic HTTP/marshal helpers (no domain names). +- `src/v2/index.ts` (151 lines) — re-exports. ## Summary | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------------------- | -| High | 23 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions, plural `Pipelines` prefix. | -| Medium | 38 | Redundant enum prefixes, vague names, acronym casing, generic IDs. | -| Low | 21 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 6 | Patterns spanning the whole file (branding history, plural/singular split). | -| **Total** | **88** | | +| High | 17 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions, plural `Pipelines` prefix. | +| Medium | 19 | Vague names, acronym casing, generic IDs, misleading enum values. | +| Low | 20 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| Observations | 8 | Patterns spanning the whole file (branding history, plural/singular split, proto-architectural leakage). | +| **Total** | **64** | | Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. @@ -27,448 +27,315 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## High ### H1. `Update` is a verb in every other Databricks SDK but the noun "pipeline run" here — pervasive overloading -- **Locations:** `model.ts:283` (`UpdateCause`), `model.ts:300` (`UpdateMode`), `model.ts:311` (`UpdateState`), `model.ts:1091` (`GetUpdate`), `model.ts:1099` (`GetUpdate_Response`), `model.ts:1689` (`ListUpdates`), `model.ts:1701` (`ListUpdates_Response`), `model.ts:2738` (`StartUpdate`), `model.ts:2789` (`StartUpdate_Response`), `model.ts:2879` (`UpdateInfo`), `model.ts:2934` (`UpdateStateInfo`), `client.ts:352` (`getUpdate`), `client.ts:434` (`listUpdates`), `client.ts:504` (`start`), plus every `updateId` field. +- **Locations:** `model.ts:168` (`UpdateCause`), `model.ts:186` (`UpdateState`), `model.ts:855` (`GetUpdateRequest`), `model.ts:863` (`GetUpdateRequest_Response`), `model.ts:1374` (`ListUpdatesRequest`), `model.ts:1386` (`ListUpdatesRequest_Response`), `model.ts:2367` (`StartUpdateRequest`), `model.ts:2412` (`StartUpdateRequest_Response`), `model.ts:2500` (`UpdateInfo`), `model.ts:2544` (`UpdateStateInfo`), `client.ts:360` (`getUpdate`), `client.ts:445` (`listUpdates`), `client.ts:485` (`start`), plus every `updateId` field. - **Category:** 1 (vague), 6 (misleading — rebrand history), 13 (verb/noun inconsistency), 17 (inconsistent action verbs). -- **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdate` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdate` → `GetRunRequest`, `ListUpdates` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateMode` → `RunMode`, `UpdateStateInfo` → `RunSummary`, `updateId` → `runId`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. -- **Rationale:** "Update" is the standard verb for `PUT`/`PATCH` (and `EditPipeline` already takes that slot — the client method is `edit()`, but the HTTP verb is `PUT`). Every JS/TS developer expects `update()` to mean "mutate". The DLT product feature historically named the unit-of-execution "Update" but Databricks itself renamed the concept to **"Pipeline run"** when the product became Lakeflow Declarative Pipelines. The SDK is on the wrong side of the rebrand. The same problem ripples through `start()` (the method that "starts an update"), `getUpdate()`, and `listUpdates()`. This is the single most confusing name in the package. +- **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdateRequest` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdateRequest` → `GetRunRequest`, `ListUpdatesRequest` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateStateInfo` → `RunSummary`, `updateId` → `runId`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. +- **Rationale:** "Update" is the standard verb for `PUT`/`PATCH` (and `EditPipelineRequest` already takes that slot — the client method is `edit()`, but the HTTP verb is `PUT`). Every JS/TS developer expects `update()` to mean "mutate". The DLT product feature historically named the unit-of-execution "Update" but Databricks itself renamed the concept to **"Pipeline run"** when the product became Lakeflow Declarative Pipelines. The SDK is on the wrong side of the rebrand. The same problem ripples through `start()` (the method that "starts an update"), `getUpdate()`, and `listUpdates()`. This is the single most confusing name in the package. -### H2. `client.edit()` returns `EditPipeline_Response` instead of `UpdatePipeline_Response` — verb collision avoidance is leaking through -- **Locations:** `client.ts:241` (`edit`), `model.ts:830` (`EditPipeline`), `model.ts:929` (`EditPipeline_Response`). +### H2. `client.edit()` returns `EditPipelineRequest_Response` instead of `UpdatePipelineRequest_Response` — verb collision avoidance is leaking through +- **Locations:** `client.ts:243` (`edit`), `model.ts:622` (`EditPipelineRequest`), `model.ts:708` (`EditPipelineRequest_Response`). - **Category:** 13 (verb-tense inconsistency: `Edit` vs `Update` vs `Modify`), 6 (misleading: HTTP verb is `PUT`). -- **Suggestion:** Rename `EditPipeline` → `UpdatePipelineRequest` and the client method `edit()` → `update()`. Then rename the "pipeline run" concept per H1 to free up the `Update` token. +- **Suggestion:** Rename `EditPipelineRequest` → `UpdatePipelineRequest` and the client method `edit()` → `update()`. Then rename the "pipeline run" concept per H1 to free up the `Update` token. - **Rationale:** The package uses `Edit` only because the `Update` noun was burned by DLT history. Once H1 is applied, `edit()` should follow the standard `create()`/`update()`/`delete()` REST pattern used by every other SDK (`jobs`, `clusters`, `instancepools`, etc., all use `update()`). ### H3. `client.start()` is "start a pipeline update" — but it reads as "start a pipeline" -- **Location:** `client.ts:504`. +- **Location:** `client.ts:485`. - **Category:** 6 (misleading), 17 (inconsistent action verbs). -- **Suggestion:** Rename `start(req: StartUpdate)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. -- **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipeline)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. +- **Suggestion:** Rename `start(req: StartUpdateRequest)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. +- **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipelineRequest)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. ### H4. `Pipelines*` prefix (plural) on a single-pipeline package — proto-package leakage -- **Locations:** `model.ts:212` (`PipelinesAwsAvailability`), `model.ts:225` (`PipelinesAzureAvailability`), `model.ts:241` (`PipelinesEbsVolumeType`), `model.ts:249` (`PipelinesGcpAvailability`), `model.ts:2224` (`PipelinesAutoScale`), `model.ts:2243` (`PipelinesAwsAttributes`), `model.ts:2332` (`PipelinesAzureAttributes`), `model.ts:2359` (`PipelinesClusterLogConf`), `model.ts:2373` (`PipelinesDbfsStorageInfo`), `model.ts:2382` (`PipelinesEnvironment`), `model.ts:2405` (`PipelinesGcpAttributes`), `model.ts:2446` (`PipelinesInitScriptInfo`), `model.ts:2474` (`PipelinesJobRunAs`), `model.ts:2489` (`PipelinesMavenLibrary`), `model.ts:2507` (`PipelinesS3StorageInfo`). +- **Locations:** `model.ts:117` (`PipelinesAwsAvailability`), `model.ts:130` (`PipelinesAzureAvailability`), `model.ts:146` (`PipelinesEbsVolumeType`), `model.ts:154` (`PipelinesGcpAvailability`), `model.ts:1897` (`PipelinesAutoScale`), `model.ts:1916` (`PipelinesAwsAttributes`), `model.ts:2005` (`PipelinesAzureAttributes`), `model.ts:2032` (`PipelinesClusterLogConf`), `model.ts:2046` (`PipelinesDbfsStorageInfo`), `model.ts:2055` (`PipelinesEnvironment`), `model.ts:2078` (`PipelinesGcpAttributes`), `model.ts:2119` (`PipelinesInitScriptInfo`), `model.ts:2147` (`PipelinesJobRunAs`), `model.ts:2162` (`PipelinesMavenLibrary`), `model.ts:2180` (`PipelinesS3StorageInfo`). - **Category:** 8 (redundant suffix/prefix), 9 (singular/plural mismatch), 14 (Go/Java-style names). - **Suggestion:** Drop the `Pipelines` prefix. The package itself is `@databricks/sdk-pipelines` and the import disambiguates from `@databricks/sdk-clusters`. The types become `AwsAvailability`, `AwsAttributes`, `AutoScale`, `ClusterLogConf`, `DbfsStorageInfo`, `Environment`, `GcpAttributes`, `InitScriptInfo`, `JobRunAs`, `MavenLibrary`, `S3StorageInfo`. If global collision is feared, use `PipelineCluster`-style singular: `PipelineEnvironment`, `PipelineAwsAttributes`, etc. -- **Rationale:** The proto package is `pipelines.proto`, so the generator prefixed every type with `Pipelines`. A consumer types `new PipelinesJobRunAs(...)` and the plural reads as "RunAs for many jobs in many pipelines" — neither is true. `PipelineCluster` (singular, `model.ts:1898`) shows the convention the package would have if generated consistently. +- **Rationale:** The proto package is `pipelines.proto`, so the generator prefixed every type with `Pipelines`. A consumer types `new PipelinesJobRunAs(...)` and the plural reads as "RunAs for many jobs in many pipelines" — neither is true. `PipelineCluster` (singular, `model.ts:1573`) shows the convention the package would have if generated consistently. ### H5. `PipelinesJobRunAs` references `Job` from a `Pipelines` package -- **Location:** `model.ts:2474`. +- **Location:** `model.ts:2147`. - **Category:** 6 (misleading — `Job` is a separate Databricks product), 14 (Go-style). - **Suggestion:** Rename to `RunAs` or `PipelineRunAs`. Drop the `Job` token entirely — this type is not used by `@databricks/sdk-jobs`. - **Rationale:** `Job` belongs to the `jobs` API. A user reading `runAs: PipelinesJobRunAs` cannot tell whether the pipeline is associated with a job or just borrows the shape. The proto comment ("Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as.") confirms this is a pipeline-only concept. ### H6. `Pipeline` is never used as a type name — the central domain entity is missing -- **Locations:** N/A — the package has `PipelineSpec`, `PipelineStateInfo`, `GetPipeline_Response`, `BaseJob`-style scattering, but no plain `Pipeline` type. +- **Locations:** N/A — the package has `PipelineSpec`, `PipelineStateInfo`, `GetPipelineRequest_Response`, `BaseJob`-style scattering, but no plain `Pipeline` type. - **Category:** 1 (vague/generic alternative missing), 6 (misleading). -- **Suggestion:** Add an exported `Pipeline` type that consolidates the runtime view (`GetPipeline_Response` is the closest). Alternatively rename `GetPipeline_Response` → `Pipeline`. Keep `PipelineSpec` as the write-form (the "settings" sub-object). -- **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipeline_Response`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. +- **Suggestion:** Add an exported `Pipeline` type that consolidates the runtime view (`GetPipelineRequest_Response` is the closest). Alternatively rename `GetPipelineRequest_Response` → `Pipeline`. Keep `PipelineSpec` as the write-form (the "settings" sub-object). +- **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipelineRequest_Response`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. -### H7. `EditPipeline` / `CreatePipeline` / `ClonePipeline` / `PipelineSpec` all duplicate 26 of the same fields -- **Locations:** `model.ts:508` (`ClonePipeline`), `model.ts:672` (`CreatePipeline`), `model.ts:830` (`EditPipeline`), `model.ts:2108` (`PipelineSpec`). +### H7. `EditPipelineRequest` / `CreatePipelineRequest` / `ClonePipelineRequest` / `PipelineSpec` all duplicate 25 of the same fields +- **Locations:** `model.ts:336` (`ClonePipelineRequest`), `model.ts:479` (`CreatePipelineRequest`), `model.ts:622` (`EditPipelineRequest`), `model.ts:1783` (`PipelineSpec`). - **Category:** 12 (duplicate concepts). - **Suggestion:** Extract `PipelineSpec` as the shared base and have `CreatePipelineRequest`, `EditPipelineRequest`, `ClonePipelineRequest` use TS intersection: `type CreatePipelineRequest = PipelineSpec & {allowDuplicateNames?: boolean; dryRun?: boolean; ...}`. -- **Rationale:** Each of the four interfaces redeclares `id`, `name`, `storage`, `configuration`, `clusters`, `libraries`, `ingestionDefinition`, `gatewayDefinition`, `trigger`, `target`, `schema`, `filters`, `continuous`, `development`, `photon`, `edition`, `channel`, `catalog`, `notifications`, `serverless`, `deployment`, `restartWindow`, `budgetPolicyId`, `tags`, `eventLog`, `rootPath`, `environment`, `usagePolicyId`, `rewindGenerationInterval`. Drift between the four is silent. Counted manually — 26 identical fields × 4 types = 104 redundant declarations. +- **Rationale:** Each of the four interfaces redeclares `id`, `name`, `storage`, `configuration`, `clusters`, `libraries`, `ingestionDefinition`, `gatewayDefinition`, `trigger`, `target`, `schema`, `filters`, `continuous`, `development`, `photon`, `edition`, `channel`, `catalog`, `notifications`, `serverless`, `deployment`, `restartWindow`, `budgetPolicyId`, `tags`, `eventLog`, `rootPath`, `environment`, `usagePolicyId`. Drift between the four is silent. ### H8. `Update` field names on `Origin` reference the "pipeline run" sense of Update — silent overloading -- **Locations:** `model.ts:1791` (`updateId`), `model.ts:1816` (`graphId`), `model.ts:2879` (`UpdateInfo.updateId`), `model.ts:2934` (`UpdateStateInfo.updateId`). +- **Locations:** `model.ts:1476` (`Origin.updateId`), `model.ts:2504` (`UpdateInfo.updateId`), `model.ts:2545` (`UpdateStateInfo.updateId`). - **Category:** 19 (underspecified IDs), 1 (vague). - **Suggestion:** Rename `updateId` → `runId` (paired with H1). Document that the wire JSON key is `update_id` for compatibility. - **Rationale:** A field named `updateId` on `Origin` (event source) leaves "update of what?" unanswered. Users wonder if it refers to the last-modification timestamp. ### H9. `client.events()` method name is too generic -- **Location:** `client.ts:267`. +- **Location:** `client.ts:272`. - **Category:** 1 (vague), 17 (inconsistent action verbs — should be `listEvents`). - **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. - **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). ### H10. `client.list()` — too generic for the package's bare-`list` slot -- **Location:** `client.ts:377`. +- **Location:** `client.ts:385`. - **Category:** 1 (vague), 17 (inconsistent verbs). -- **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelines` and to disambiguate from `listUpdates`/`listEvents`. -- **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelines`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. +- **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelinesRequest` and to disambiguate from `listUpdates`/`listEvents`. +- **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelinesRequest`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. ### H11. `ScdType_ScdType` enum uses the cryptic acronym SCD -- **Locations:** `model.ts:415` (`ScdType_ScdType`), `index.ts:32`, `index.ts:150`. +- **Locations:** `model.ts:268` (`ScdType_ScdType`), `index.ts:27`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). - **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). -### H12. `StorageMode` enum is a parallel of `ScdType` with three overlapping values — duplicate concept -- **Locations:** `model.ts:263` (`StorageMode.SCD_TYPE_1` / `SCD_TYPE_2` / `APPEND_ONLY`), `model.ts:415` (`ScdType_ScdType.SCD_TYPE_1` / `SCD_TYPE_2` / `APPEND_ONLY`). -- **Category:** 12 (duplicate concepts). -- **Suggestion:** Delete one. The JSDoc on `IngestionPipelineDefinition_TableSpecificConfig.storageMode` (`model.ts:1437-1440`) literally says "Mutually exclusive with scd_type — a 400 error is returned if both are set." This is two names for the same field. Pick one (probably `StorageMode` since it includes a meaningful `UNSPECIFIED`). -- **Rationale:** Forcing the client to choose between two synonymous enums based on which one the field is typed as is the worst possible API ergonomic. Users will set both and get a 400. - -### H13. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" -- **Location:** `model.ts:410`. +### H12. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" +- **Location:** `model.ts:262`. - **Category:** 6 (misleading — references method `run` that does not exist; the method is `start`). - **Suggestion:** Fix JSDoc to reference `start()`. After H3, both will line up at `run()`. - **Rationale:** Currently the user reads "call `run`" and finds no `run()` method on `Client`. -### H14. `client.delete()` collides with JS `delete` keyword -- **Location:** `client.ts:204`. +### H13. `client.delete()` collides with JS `delete` keyword +- **Location:** `client.ts:206`. - **Category:** 10 (reserved-word collision). -- **Suggestion:** Rename to `deletePipeline()` (matching `restorePipeline()` already at `client.ts:475`). Alternatively, `remove()`. -- **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. `restorePipeline()` already uses the verbose form, so the asymmetry is jarring (`client.delete` vs `client.restorePipeline`). - -### H15. `client.restorePipeline()` is verbose, but its siblings are short (`delete`, `get`, `clone`) -- **Location:** `client.ts:475`. -- **Category:** 7 (overly verbose), 17 (inconsistent verbs). -- **Suggestion:** Either shorten to `restore()` (parallel with `clone()`, `delete()`, `get()`) or lengthen the siblings to `deletePipeline()`, `getPipeline()`, `clonePipeline()`. The request type is already named `RestorePipelineRequest` — which is itself inconsistent with sibling request types (`DeletePipeline`, `GetPipeline`, `ClonePipeline` have no `Request` suffix). -- **Rationale:** Pick one suffix convention and apply it. Mixing methods on the same client is the smell. - -### H16. `RestorePipelineRequest` ends in `Request` but other request types do not -- **Locations:** `model.ts:2618` (`RestorePipelineRequest`), `model.ts:477` (`ApplyEnvironmentRequest`), and all other request types without the suffix (`DeletePipeline`, `GetPipeline`, `ClonePipeline`, `EditPipeline`, `CreatePipeline`, `StartUpdate`, `StopPipeline`, ...). -- **Category:** 8 (redundant suffix), 17 (inconsistent). -- **Suggestion:** Pick one convention and stick to it. Either drop `Request` everywhere (so this becomes `RestorePipeline`, `ApplyEnvironment`) or add it everywhere (`DeletePipelineRequest`, `EditPipelineRequest`, ...). -- **Rationale:** Two named conventions in the same file confuse every reader. - -### H17. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +- **Suggestion:** Rename to `deletePipeline()`. Alternatively, `remove()`. +- **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. + +### H14. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity - **Location:** `model.ts:56`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. -### H18. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" -- **Location:** `model.ts:313` ("Update is waiting for previous update to finish."). +### H15. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" +- **Location:** `model.ts:187` ("Update is waiting for previous update to finish."). - **Category:** 6 (misleading). - **Suggestion:** Doc rewrite (English) after H1: "Run is waiting for previous run to finish." - **Rationale:** Same as H1 — once `Update` is renamed to `Run`, every JSDoc that mentions "update" in this enum needs to follow. -### H19. `StartUpdate.fullRefresh` / `refreshSelection` / `fullRefreshSelection` / `resetCheckpointSelection` / `refreshFlowSelection` — 5 booleans-or-arrays describing overlapping concepts -- **Location:** `model.ts:2738-2780`. -- **Category:** 12 (duplicate concepts), 17 (inconsistent verbs). -- **Suggestion:** Collapse into a single discriminated union `refreshMode: FullGraph | FullRefresh | TableSelection | FlowSelection | RewindMode` (analogous to existing `RewindSpec`). At minimum, document the precedence rules in JSDoc. -- **Rationale:** The combinatorial space is currently five fields × two values each = 32 combinations, of which JSDoc clarifies only "if both refresh_selection and full_refresh_selection are empty, this is a full graph update." The other 30 combinations are undefined. - -### H20. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural -- **Locations:** `model.ts:1746`, `model.ts:556` (`notifications?: Notifications[]`), etc. +### H16. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +- **Locations:** `model.ts:1431`, plus all `notifications?: Notifications[]` field declarations. - **Category:** 9 (singular/plural mismatch). - **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. - **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. -### H21. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) -- **Locations:** `model.ts:644-670`, `model.ts:1323`, `model.ts:1357`. +### H17. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) +- **Locations:** `model.ts:457-477` (interface `ConnectorOptions`), `model.ts:1056`, `model.ts:1078`. - **Category:** 20 (type-suffix tautology), 12 (duplicate naming). - **Suggestion:** Rename the outer interface to `ConnectorOptions` and the inner discriminator to `options` (or `payload`). Then `connectorOptions: {payload: {...}}` reads cleanly. - **Rationale:** Currently `ConnectorOptions.connectorOptions.googleAdsOptions` requires four nested identifiers all containing "options". -### H22. `PipelinesEnvironment` vs `IngestionPipelineDefinition` — two `Pipeline*` namespaces, only one is plural -- **Locations:** `model.ts:2382` (`PipelinesEnvironment`), `model.ts:1173` (`IngestionPipelineDefinition`). -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent prefix). -- **Suggestion:** Drop the prefix on `PipelinesEnvironment` (see H4). Or rename to `PipelineEnvironment` (singular). Match `PipelineCluster`, `PipelineDeployment`, `PipelineEvent`, `PipelineLibrary`, `PipelineSpec`, `PipelineStateInfo`, `PipelineTrigger` — all singular. -- **Rationale:** Out of 22 pipeline-prefixed types, 8 use plural (`Pipelines*`) and 14 use singular (`Pipeline*`). No domain reason for the split; pure generator artifact. - -### H23. `Sequencing.controlPlaneSeqNo` — abbreviated/cryptic identifier -- **Locations:** `model.ts:2661` (`Sequencing`), `model.ts:2665` (`controlPlaneSeqNo`). -- **Category:** 5 (cryptic abbreviations), 15 (generic field names). -- **Suggestion:** Rename to `controlPlaneSequenceNumber`. The JSDoc already calls it "A sequence number" — TS has no character budget. Sibling type `DataPlaneId.seqNo` (`model.ts:792`) has the same issue. -- **Rationale:** "SeqNo" is a Go/Java abbreviation. The wire JSON is `seq_no`, so the TS field rename is purely a surface improvement. - -### H24. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` -- **Location:** `model.ts:788`. -- **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). -- **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. -- **Rationale:** Every other `*Id` type in the SDK is a string. Reading `dataPlaneId: DataPlaneId` then accessing `dataPlaneId.seqNo` is jarring. - --- ## Medium -### M1. `ConnectorType.CONNECTOR_TYPE_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:16-25`. -- **Category:** 2 (redundant enum prefix). -- **Suggestion:** Rename values to `UNSPECIFIED`, `CDC`, `QUERY_BASED`. TS already namespaces enum members by enum. -- **Rationale:** `ConnectorType.CONNECTOR_TYPE_CDC` reads as "ConnectorType.Type.CDC". - -### M2. `DayOfWeek.DAY_OF_WEEK_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:31-40`. -- **Category:** 2. -- **Suggestion:** Drop `DAY_OF_WEEK_` prefix from `UNSPECIFIED`. Other values (`MONDAY`...) are fine. -- **Rationale:** Same as M1. Inconsistency: `MONDAY` is unprefixed but `UNSPECIFIED` is prefixed. - -### M3. `IngestionSourceType.INGESTION_SOURCE_TYPE_UNSPECIFIED` — redundant prefix on 1 of 80 values -- **Location:** `model.ts:60`. -- **Category:** 2. -- **Suggestion:** Drop the prefix. -- **Rationale:** Same as M1. - -### M4. `OutlookAttachmentMode.OUTLOOK_ATTACHMENT_MODE_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:177`. -- **Category:** 2. -- **Suggestion:** Drop. - -### M5. `OutlookBodyFormat.OUTLOOK_BODY_FORMAT_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:190`. -- **Category:** 2. -- **Suggestion:** Drop. - -### M6. `ParseMode.PARSE_MODE_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:198`. -- **Category:** 2. -- **Suggestion:** Drop. - -### M7. `PublishingMode.PUBLISHING_MODE_UNSPECIFIED` / `LEGACY_PUBLISHING_MODE` / `DEFAULT_PUBLISHING_MODE` — three redundant prefixes -- **Location:** `model.ts:256-260`. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggestion:** Rename to `UNSPECIFIED`, `LEGACY`, `DEFAULT`. - -### M8. `StorageMode.STORAGE_MODE_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:264`. -- **Category:** 2. -- **Suggestion:** Drop. - -### M9. `FileIngestionOptions_FileFormat.FILE_FORMAT_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:338`. -- **Category:** 2. - -### M10. `FileIngestionOptions_SchemaEvolutionMode.SCHEMA_EVOLUTION_MODE_UNSPECIFIED` — redundant + verbose -- **Location:** `model.ts:353`. -- **Category:** 2, 18. - -### M11. `GoogleDriveOptions_GoogleDriveEntityType.GOOGLE_DRIVE_ENTITY_TYPE_UNSPECIFIED` — quadruple-redundant -- **Location:** `model.ts:362-369`. -- **Category:** 2, 18. -- **Suggestion:** The proto-nested name already contains "GoogleDrive" twice. The enum members repeat the brand a third time. Strip down to `EntityType.{Unspecified, File, FileMetadata, Permission, FilePermission, GroupMembership}`. - -### M12. `GoogleDriveOptions_GoogleDriveIngestionScope.GOOGLE_DRIVE_INGESTION_SCOPE_UNSPECIFIED` — same problem -- **Location:** `model.ts:372-379`. -- **Category:** 2, 18. - -### M13. `PeriodicTrigger_TimeUnit.TIME_UNIT_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:384`. -- **Category:** 2, 18. - -### M14. `ScdType_ScdType.SCD_TYPE_UNSPECIFIED` / `SCD_TYPE_1` / `SCD_TYPE_2` — every value names the enum -- **Location:** `model.ts:415-424`. -- **Category:** 2, 18. - -### M15. `SharepointOptions_SharepointEntityType.SHAREPOINT_ENTITY_TYPE_UNSPECIFIED` — triple-redundant -- **Location:** `model.ts:428`. -- **Category:** 2, 18. - -### M16. `TikTokAdsOptions_TikTokDataLevel.TIK_TOK_DATA_LEVEL_UNSPECIFIED` — same problem -- **Location:** `model.ts:440`. -- **Category:** 2, 3 (the casing of `TIK_TOK` splits `TikTok` which is normally one word). - -### M17. `TikTokAdsOptions_TikTokReportType.TIK_TOK_REPORT_TYPE_UNSPECIFIED` — same -- **Location:** `model.ts:450`. - -### M18. `Transformer_Format.FORMAT_UNSPECIFIED` — redundant prefix -- **Location:** `model.ts:461`. -- **Category:** 2. - -### M19. `PipelinesAwsAvailability.SPOT_WITH_FALLBACK` — value spells "SPOT", which is already what the enum is about -- **Location:** `model.ts:212-222`. -- **Category:** 18 (long enum values). -- **Suggestion:** Just `FALLBACK`. - -### M20. `PipelinesAzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — suffix repeats the enum name -- **Location:** `model.ts:226-235`. -- **Category:** 2 (redundant enum prefix/suffix). -- **Suggestion:** Drop `_AZURE`. Sibling `PipelinesAwsAvailability` does not use `_AWS`, so the asymmetry is gratuitous. Same for `PipelinesGcpAvailability.*_GCP` (M21 below). - -### M21. `PipelinesGcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` — `_GCP` suffix asymmetry -- **Location:** `model.ts:249-253`. -- **Category:** 2. - -### M22. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level -- **Location:** `model.ts:170-173`. +### M1. `TikTokAdsOptions_TikTokDataLevel` enum values split `TikTok` across an underscore (`TIK_TOK_*`) +- **Location:** `model.ts:291`. +- **Category:** 3 (acronym/word casing inconsistency). +- **Suggestion:** Use `TIKTOK_*` (single token) in enum values to match the brand spelling and the parent type name (`TikTok`). +- **Rationale:** The brand is "TikTok" (one word). Splitting to `TIK_TOK` in `SCREAMING_SNAKE_CASE` reads as two separate tokens and diverges from the parent type's CamelCase. + +### M2. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level +- **Location:** `model.ts:84-88`. - **Category:** 6 (misleading). - **Suggestion:** Rename enum to `EventStability` or rename value `DEPRECATED` → `LEGACY`. - **Rationale:** `DEPRECATED` is widely used as a TS/JSDoc tag for "do not use." Reading `maturityLevel: DEPRECATED` mis-suggests the EVENT is deprecated, not the schema field. -### M23. `EventLogSpec` — `Spec` suffix on a small config object -- **Location:** `model.ts:951`. +### M3. `EventLogSpec` — `Spec` suffix on a small config object +- **Location:** `model.ts:730`. - **Category:** 8 (redundant suffix). - **Suggestion:** `EventLogConfig` or just `EventLog`. The `Spec` suffix is overused (`PipelineSpec`, `RewindSpec`, `RewindDatasetSpec`, `EventLogSpec`, `IngestionPipelineDefinition_SchemaSpec`, `_TableSpec`, `_ReportSpec`). - **Rationale:** TS doesn't need `Spec` as a discriminator; the type's role is clear from its field name. -### M24. `Filters` — pluralized name for a 2-field struct -- **Location:** `model.ts:1029-1034`. +### M4. `Filters` — pluralized name for a 2-field struct +- **Location:** `model.ts:808-813`. - **Category:** 9 (singular/plural mismatch), 1 (vague). - **Suggestion:** Rename to `PathFilter` (singular). The shape is `{include?: string[]; exclude?: string[]}`. -### M25. `PathPattern` field is `include: string` (singular, no array) but it represents a glob -- **Location:** `model.ts:1885-1888`. +### M5. `PathPattern` field is `include: string` (singular, no array) but it represents a glob +- **Location:** `model.ts:1568-1571`. - **Category:** 15 (generic field names), 6 (misleading). - **Suggestion:** Rename type to `GlobPattern` and field to `pattern`. JSDoc says "The source code to include for pipelines" — `pattern` describes the *what*, `include` describes the *intent*. -### M26. `Origin` — too generic for "event source metadata" -- **Location:** `model.ts:1777`. +### M6. `Origin` — too generic for "event source metadata" +- **Location:** `model.ts:1462`. - **Category:** 1 (vague). - **Suggestion:** Rename to `EventOrigin` or `EventSource`. -- **Rationale:** "Origin" is also a DOM type (`Window.origin`) and a CORS concept. Type contains 23 fields covering everything from cloud region to flow IDs. +- **Rationale:** "Origin" is also a DOM type (`Window.origin`) and a CORS concept. Type contains many fields covering everything from cloud region to flow IDs. -### M27. `Origin.flowId` and `Origin.batchId` — IDs from unrelated subsystems -- **Locations:** `model.ts:1802` (`flowId`), `model.ts:1806` (`batchId`). +### M7. `Origin.flowId` and `Origin.batchId` — IDs from unrelated subsystems +- **Locations:** `model.ts:1487` (`flowId`), `model.ts:1491` (`batchId`). - **Category:** 19 (underspecified IDs). - **Suggestion:** Document inline that `flowId` is "id of the streaming flow within the pipeline" and `batchId` is "id of a microbatch within a flow." Better: prefix as `streamingFlowId`, `microbatchId`. -### M28. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type -- **Location:** `model.ts:1231`. +### M8. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type +- **Location:** `model.ts:988`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Move to `NetsuiteOptions` connector-specific type. - **Rationale:** A generic ingestion-definition type carrying a `netsuiteJarPath` field implies every other connector is incomplete. JSDoc literally says "Netsuite only configuration." Belongs in a per-connector options struct. -### M29. `IngestionSourceType.WORKDAY_RAAS` — undefined acronym -- **Location:** `model.ts:69`. +### M9. `IngestionSourceType.WORKDAY_RAAS` — undefined acronym +- **Location:** `model.ts:67`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Document inline that RaaS = "Reports as a Service" (Workday terminology). The acronym is non-obvious. -### M30. `IngestionSourceType.GA4_RAW_DATA` — vendor-numbered identifier -- **Location:** `model.ts:70`. +### M10. `IngestionSourceType.GA4_RAW_DATA` — vendor-numbered identifier +- **Location:** `model.ts:68`. - **Category:** 5. -- **Suggestion:** Document inline that GA4 = "Google Analytics 4." Sibling `GOOGLE_ANALYTICS` (`model.ts:121`) is the broader connector. - -### M31. `IngestionSourceType.COMMUNITY` — non-obvious meaning, requires comment -- **Location:** `model.ts:88-92`. -- **Category:** 1 (vague), 6 (misleading). -- **Suggestion:** Rename to `CUSTOM_LAKEFLOW_CONNECT` or document inline. -- **Rationale:** The proto comment explains: "Named COMMUNITY instead of GENERIC_LAKEFLOW_CONNECT (the connection type name) because we do not want to include LAKEFLOW in the public API." This is a *naming-decision-by-marketing*, which is the exact category of "Misleading names" worth flagging. +- **Suggestion:** Document inline that GA4 = "Google Analytics 4." -### M32. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator -- **Location:** `model.ts:165`. +### M11. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator +- **Location:** `model.ts:80`. - **Category:** 1 (vague). - **Suggestion:** `UC_FOREIGN_CATALOG` or document inline. - **Rationale:** "Foreign Catalog" is a Unity Catalog concept; without context this looks like a country-of-origin enum value. -### M33. `Origin.ucResourceId` mixes acronym casing -- **Location:** `model.ts:1810`. +### M12. `Origin.ucResourceId` mixes acronym casing +- **Location:** `model.ts:1495`. - **Category:** 3 (acronym casing inconsistency). - **Suggestion:** Either `ucResourceId` (current) or `UCResourceId` — the Google TS style guide says treat acronyms as words, so `ucResourceId` is correct. But sibling fields use the same lowercase pattern (`workspaceId`, `pipelineId`), so this one is internally consistent. Flagged because it could be `unityCatalogResourceId` for clarity. -### M34. `eventType?: string` on `PipelineEvent` — string-typed enum -- **Location:** `model.ts:2057`. +### M13. `eventType?: string` on `PipelineEvent` — string-typed enum +- **Location:** `model.ts:1732`. - **Category:** 16 (field contradicts type domain). - **Suggestion:** Define an `EventType` enum (or union of string literals) and type the field with it. Right now consumers have no IDE help. - **Rationale:** JSDoc says "The event type. Should always correspond to the details." The Go SDK has the same field as string (porting fidelity), but TS could improve. -### M35. `PipelineEvent.timestamp: string` — typed string but holds an ISO date -- **Location:** `model.ts:2049`. +### M14. `PipelineEvent.timestamp: string` — typed string but holds an ISO date +- **Location:** `model.ts:1724`. - **Category:** 16. - **Suggestion:** Document the format in JSDoc, or use a `Date | string` union. -### M36. `RewindSpec.rewindTimestamp` / `rewindPointId` — fields prefixed with the type name -- **Location:** `model.ts:2637-2655`. +### M15. `RewindSpec.rewindTimestamp` — field prefixed with the type name +- **Location:** `model.ts:2277`. - **Category:** 20 (type-suffix tautology). -- **Suggestion:** Drop the `rewind` prefix on fields inside `RewindSpec`: `timestamp`, `pointId`, `datasets`. +- **Suggestion:** Drop the `rewind` prefix on fields inside `RewindSpec`: `timestamp`, `datasets`. -### M37. `Sequencing` — singular noun for a 2-field record describing one event's position -- **Location:** `model.ts:2661`. +### M16. `Sequencing` — singular noun for a 2-field record describing one event's position +- **Location:** `model.ts:2290`. - **Category:** 1 (vague). - **Suggestion:** `EventSequence` or `EventPosition`. "Sequencing" is the action of putting in order, not the position itself. -### M38. `EditPipeline.expectedLastModified: number` — wire is millis since epoch, but no JSDoc -- **Location:** `model.ts:840`. +### M17. `EditPipelineRequest.expectedLastModified: number` — wire is millis since epoch, but no JSDoc +- **Location:** `model.ts:632`. - **Category:** 16 (field contradicts type domain), 19 (underspecified ID). - **Suggestion:** Either type as `Date | number` or document "milliseconds since Unix epoch" in JSDoc. +### M18. `Sequencing.controlPlaneSeqNo` — abbreviated/cryptic identifier +- **Locations:** `model.ts:2290` (`Sequencing`), `model.ts:2294` (`controlPlaneSeqNo`). +- **Category:** 5 (cryptic abbreviations), 15 (generic field names). +- **Suggestion:** Rename to `controlPlaneSequenceNumber`. The JSDoc already calls it "A sequence number" — TS has no character budget. Sibling type `DataPlaneId.seqNo` (`model.ts:586`) has the same issue. +- **Rationale:** "SeqNo" is a Go/Java abbreviation. The wire JSON is `seq_no`, so the TS field rename is purely a surface improvement. + +### M19. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` +- **Location:** `model.ts:582`. +- **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). +- **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. +- **Rationale:** Every other `*Id` type in the SDK is a string. Reading `dataPlaneId: DataPlaneId` then accessing `dataPlaneId.seqNo` is jarring. + --- ## Low ### L1. `client.start()` JSDoc mentions "If there is already an active update" — should say "active run" -- **Location:** `client.ts:503`. +- **Location:** `client.ts:484`. - **Category:** 6. ### L2. `client.stop()` JSDoc mentions "Stops the pipeline by canceling the active update" — same -- **Location:** `client.ts:529`. +- **Location:** `client.ts:513`. ### L3. `client.list()` JSDoc says "Lists pipelines defined in the Spark Declarative Pipelines system" -- **Location:** `client.ts:376`. +- **Location:** `client.ts:384`. - **Category:** 6 (misleading), branding inconsistency. -- **Rationale:** The product is "Lakeflow Declarative Pipelines" per the IngestionPipelineDefinition JSDoc (`model.ts:1175`). Internal naming: "Spark Declarative Pipelines" (SDP). Public marketing name: "Lakeflow Declarative Pipelines." The SDK uses both, sometimes in adjacent JSDoc. +- **Rationale:** The product is "Lakeflow Declarative Pipelines" per the IngestionPipelineDefinition JSDoc (`model.ts:932`). Internal naming: "Spark Declarative Pipelines" (SDP). Public marketing name: "Lakeflow Declarative Pipelines." The SDK uses both, sometimes in adjacent JSDoc. -### L4. JSDoc references to "SDP" appear in three fields, undefined -- **Locations:** `model.ts:551` (`ClonePipeline.channel` — "SDP Release Channel"), `model.ts:714` (`CreatePipeline.channel`), `model.ts:879` (`EditPipeline.channel`), `model.ts:2141` (`PipelineSpec.channel`), `model.ts:2379` (`PipelinesEnvironment` — "SDP's environment"). +### L4. JSDoc references to "SDP" appear in four fields, undefined +- **Locations:** `model.ts:379` (`ClonePipelineRequest.channel` — "SDP Release Channel"), `model.ts:516` (`CreatePipelineRequest.channel`), `model.ts:666` (`EditPipelineRequest.channel`), `model.ts:1816` (`PipelineSpec.channel`), `model.ts:2052` (`PipelinesEnvironment` — "SDP's environment"). - **Category:** 5 (cryptic abbreviation), 6 (misleading). - **Suggestion:** Expand SDP → "Spark Declarative Pipelines" on first mention, with parenthetical "(internal name for Lakeflow Declarative Pipelines)". ### L5. `PipelineLibrary.lib` field uses an abbreviation -- **Location:** `model.ts:2070`. +- **Location:** `model.ts:1745`. - **Category:** 5. - **Suggestion:** Either `library` (matching `lib` but spelled out) or `source` (the discriminator). The current `lib` is a Go SDK shortening. ### L6. `PipelinesS3StorageInfo.cannedAcl` — undocumented S3 jargon -- **Location:** `model.ts:2542`. +- **Location:** `model.ts:2215`. - **Category:** 5. - **Suggestion:** Document inline: "canned ACL = a predefined S3 access-control list, e.g., `bucket-owner-full-control`." Currently the field name is fine since it matches the S3 API; only the casing (`cannedAcl` not `cannedAcl` — should be `cannedACL` per Google TS style? actually `cannedAcl` is correct). ### L7. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent -- **Location:** `model.ts:2532`. +- **Location:** `model.ts:2205`. - **Category:** 3. - **Suggestion:** `kmsKey` is the correct casing per Google TS style. Just flagging for cross-check with other AWS fields in the file. ### L8. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system -- **Locations:** `model.ts:2525`, `model.ts:2530`. +- **Locations:** `model.ts:2198`, `model.ts:2203`. - **Category:** 16. - **Suggestion:** Use a discriminated union: `encryption?: {kind: 'none'} | {kind: 'sse-s3'} | {kind: 'sse-kms'; key: string}`. ### L9. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" -- **Location:** `model.ts:1899`. +- **Location:** `model.ts:1575`. - **Category:** 16. - **Suggestion:** Make this an enum `ClusterLabel.{Default, Maintenance}`. ### L10. `PipelineCluster.applyPolicyDefaultValues` JSDoc says "won't be persisted" — should be marked deprecated or transient -- **Location:** `model.ts:1901`. +- **Location:** `model.ts:1577`. - **Category:** 6. - **Suggestion:** Add `@deprecated` JSDoc tag. ### L11. `Truncation_TruncationDetail.fieldName: string` — looks like a meta field but is the data -- **Location:** `model.ts:2876`. +- **Location:** `model.ts:2497`. - **Category:** 6 (mildly misleading). - **Suggestion:** `truncatedFieldName` or rename type to `TruncatedField`. ### L12. `JsonTransformerOptions.asVariant: boolean` — boolean named with prefix `as` -- **Location:** `model.ts:1540`. +- **Location:** `model.ts:1225`. - **Category:** 17 (inconsistent boolean naming). - **Suggestion:** Rename to `parseAsVariant` or `parseAsVariantColumn`. -- **Rationale:** Other boolean fields in the file use `is*`/`enable*`/`has*` (`development`, `serverless`, `photon`, `continuous`, `enableEncryption`, `enableAutoClustering`, `enabled`, `inferColumnTypes`, `readerCaseSensitive`, `ignoreCorruptFiles`, `fatal`, `force`, `cascade`, `dryRun`, `incremental`). +- **Rationale:** Other boolean fields in the file use `is*`/`enable*`/`has*` (`development`, `serverless`, `photon`, `continuous`, `enableEncryption`, `enabled`, `inferColumnTypes`, `readerCaseSensitive`, `ignoreCorruptFiles`, `fatal`, `force`, `cascade`, `dryRun`, `incremental`). ### L13. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc -- **Location:** `model.ts:493`. +- **Location:** `model.ts:333`. - **Category:** Generator artifact leakage. - **Suggestion:** Express via TS optionality (`?:`) instead of repeating "Optional" in JSDoc. -### L14. `(Required, Immutable)` / `(Optional, Mutable)` proto tags appear in 60+ JSDoc blocks -- **Locations:** searches: `(Required`, `(Optional` throughout `model.ts`. +### L14. `(Required, Immutable)` / `(Optional, Mutable)` proto tags appear in many JSDoc blocks +- **Locations:** searches: `(Required`, `(Optional` throughout `model.ts` (currently ~53 occurrences). - **Category:** Generator artifact leakage. - **Suggestion:** Remove or move to a structured `@required` / `@mutable` tag. ### L15. `Origin.host` — generic field on an event source struct -- **Location:** `model.ts:1812`. +- **Location:** `model.ts:1497`. - **Category:** 15 (generic field name). - **Suggestion:** `originHostname` or document inline. ### L16. `RewindDatasetSpec.identifier: string` — generic when `datasetName` would do -- **Location:** `model.ts:2629`. +- **Location:** `model.ts:2264`. - **Category:** 15. - **Suggestion:** `datasetIdentifier` or `fullyQualifiedName`. - **Rationale:** JSDoc says "The identifier of the dataset (e.g., 'main.foo.tbl1')" — this is a UC three-part name. -### L17. `RewindDatasetSpec.resetCheckpoints: boolean` and `RewindSpec.datasets[i].cascade: boolean` — coupled flags with no type-level link -- **Locations:** `model.ts:2631`, `model.ts:2633`. +### L17. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link +- **Locations:** `model.ts:2266` (`cascade`), `model.ts:2268` (`resetCheckpoints`). - **Category:** 16. - **Suggestion:** Group into an `options` substruct or document interactions in JSDoc. -### L18. `IngestionPipelineDefinition_TableSpec.enableAutoClustering` and `clusteringColumns` — mutually exclusive booleans not enforced -- **Locations:** `model.ts:1426`, `model.ts:1435`. -- **Category:** 12 (duplicate concepts), 16. -- **Suggestion:** Use a discriminated union: `clustering?: {kind: 'auto'} | {kind: 'columns'; columns: string[]}`. -- **Rationale:** JSDoc explicitly says "we can only provide enable_auto_clustering or clustering_columns, added as separate fields as we cannot have repeated field in oneof." TS *can* express this — porting fidelity is what blocks it. - -### L19. `KafkaOptions.startingOffset: string` — typed string but documented as enum -- **Location:** `model.ts:1576`. +### L18. `KafkaOptions.startingOffset: string` — typed string but documented as enum +- **Location:** `model.ts:1261`. - **Category:** 16. - **Suggestion:** Define `KafkaStartingOffset.{Latest, Earliest}` enum. -### L20. `MetaMarketingOptions.level: string` — typed string but documented as enum -- **Location:** `model.ts:1718`. +### L19. `MetaMarketingOptions.level: string` — typed string but documented as enum +- **Location:** `model.ts:1403`. - **Category:** 16. - **Suggestion:** Define `MetaAggregationLevel.{Account, Ad, AdSet, Campaign}` enum. -### L21. `MetaMarketingOptions.actionReportTime: string` — string enum -- **Location:** `model.ts:1724`. +### L20. `MetaMarketingOptions.actionReportTime: string` — string enum +- **Location:** `model.ts:1409`. - **Category:** 16. - **Suggestion:** Define enum. @@ -476,28 +343,61 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## Observations -### O1. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into 6 different abbreviations across the public API +### O1. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into several abbreviations across the public API - **Search:** `DLT`, `SDP`, `LDP`, `Lakeflow`, `Spark Declarative Pipelines`, `Delta Live Tables`, `DAB`. -- **Locations:** `model.ts:48` (`DAB` in DeploymentKind comment), `model.ts:551` (`SDP` in `channel` JSDoc), `model.ts:804` (`Spark Declarative Pipelines` in JSDoc), `model.ts:1175` (`Lakeflow Connect`), `model.ts:2063` (`https://docs.databricks.com/en/ldp/`), `model.ts:2379` (`SDP's environment`), `client.ts:376` (`Spark Declarative Pipelines`). +- **Locations:** `model.ts:47` (`DAB` in DeploymentKind comment), `model.ts:379` (`SDP` in `channel` JSDoc), `model.ts:923` (`Spark Declarative Pipelines` in JSDoc), `model.ts:932` (`Lakeflow Connect`), `model.ts:2052` (`SDP's environment`), `client.ts:384` (`Spark Declarative Pipelines`). - **Suggestion:** Settle on one product name in JSDoc. The TS types should be backwards-compatible (no rename) but the docstrings should agree. -### O2. `Pipelines*` (plural) vs `Pipeline*` (singular) split: 8 plural-prefixed vs 14 singular-prefixed types -- **Cross-reference:** H4, H22. +### O2. `Pipelines*` (plural) vs `Pipeline*` (singular) split: 15 plural-prefixed vs 15 singular-prefixed types +- **Cross-reference:** H4. ### O3. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested -- **Locations:** `IngestionPipelineDefinition.connectorType`, `IngestionPipelineDefinition.sourceConfigurations[].catalog.options`, `IngestionPipelineDefinition_SchemaSpec.sourceOptions`, `IngestionPipelineDefinition_SchemaSpec.connectorOptions`, `IngestionPipelineDefinition_TableSpec.sourceOptions`, `IngestionPipelineDefinition_TableSpec.connectorOptions`. +- **Locations:** `IngestionPipelineDefinition.connectorType`, `IngestionPipelineDefinition.sourceConfigurations[].catalog.options`, `IngestionPipelineDefinition_SchemaSpec.connectorOptions`, `IngestionPipelineDefinition_TableSpec.connectorOptions`. - **Suggestion:** Document the resolution order between schema-level and table-level options. JSDoc currently fragments the rules across multiple types. ### O4. JSDoc uses `` placeholder — leak from the Go SDK's template substitution -- **Search:** `` appears 19 times in `model.ts`. +- **Search:** `` appears 18 times in `model.ts`. - **Suggestion:** Replace with literal "Databricks" before TS compilation. ### O5. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` -- **Location:** `model.ts:1758`. +- **Location:** `model.ts:1443`. - **Category:** 16. - **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. ### O6. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side -- **Locations:** `model.ts:1831-1881`. +- **Locations:** `model.ts:1513-1566`. - **Category:** Generator artifact / Go-SDK fidelity issue. - **Suggestion:** Mark deprecated fields with `@deprecated` JSDoc tag (currently only mentioned in plain text). + +### O7. `ConnectorOptions` JSDoc opens with "Wrapper message for source-specific options" — proto-architectural terminology leak +- **Location:** `model.ts:456`. +- **Why:** "Wrapper message" is a protobuf concept (the proto2/proto3 well-known wrapper types: `BoolValue`, `StringValue`, etc., plus the generic "wrapper message" pattern used to box discriminated unions). It is visible in user-facing JSDoc on a public interface. +- **Category:** Generator artifact leakage / proto-architectural leak. +- **Suggested:** Rewrite JSDoc as "Source-specific options for ingestion connectors. Exactly one option must be specified for the connector type." Drop "Wrapper message". +- **Rationale:** TypeScript developers do not know what a "wrapper message" is — the term reveals the proto IDL underneath. The shape is just a discriminated union over connector option types; describe it in TS terms. + +### O8. `Internal` proto-field tag leaks into JSDoc on two public fields +- **Locations:** `model.ts:926` (`IngestionGatewayPipelineDefinition.connectionParameters` — "Optional, Internal. Parameters required to establish an initial connection with the source."), `model.ts:1262` (`KafkaOptions.maxOffsetsPerTrigger` — "Internal option to control the maximum number of offsets to process per trigger."). +- **Why:** `Internal` is a proto-level annotation (`google.api.field_visibility = INTERNAL` or similar) indicating the field is not part of the public API surface. If these fields are truly internal, they should be stripped from the public SDK at generation time; if they are public, the "Internal" label should not appear in user-visible documentation. +- **Category:** Generator artifact leakage / proto-architectural leak. +- **Suggested:** Either remove these fields from the public SDK (preferred — they are marked internal) or drop the "Internal" qualifier from JSDoc and document the actual user-facing semantics. +- **Rationale:** Users reading JSDoc see `Internal option to control...` and reasonably wonder why an internal field is in the public SDK. This is a generator-template concern (same pattern likely shows up in other packages) — surface in the cross-package summary. + +--- + +## Fixed + +- #H2 `EditPipeline` (originally cited at `model.ts:830`): Renamed to `EditPipelineRequest`. Reference updated in active H2. +- #H7 `EditPipeline`/`CreatePipeline`/`ClonePipeline` (originally cited at `model.ts:508`/`672`/`830`): Renamed to `*Request` variants. References updated in active H7. +- #H8 `Origin.graphId` (originally cited at `model.ts:1816`): Fixed in regeneration on 2026-05-20 — `graphId` field removed from `Origin`. +- #H12 `StorageMode` enum duplicate of `ScdType` (originally cited at `model.ts:263`): Fixed in regeneration on 2026-05-20 — `StorageMode` enum removed; only `ScdType_ScdType` remains. +- #H14 `client.delete()` reserved-word collision (originally cited at `client.ts:204`): Line updated; still present as H13. Sibling reference to `restorePipeline()` removed since the restore endpoint no longer exists. +- #H15 `client.restorePipeline()` (originally cited at `client.ts:475`): Fixed in regeneration on 2026-05-20 — `restorePipeline()` method and `RestorePipelineRequest` removed entirely from the package. +- #H16 `RestorePipelineRequest` suffix asymmetry (originally cited at `model.ts:2618`): Fixed in regeneration on 2026-05-20 — `Request` suffix added uniformly to every request DTO (`DeletePipelineRequest`, `GetPipelineRequest`, `ClonePipelineRequest`, `EditPipelineRequest`, `CreatePipelineRequest`, `StartUpdateRequest`, `StopPipelineRequest`, `ApplyEnvironmentRequest`, etc.); `RestorePipelineRequest` itself was deleted along with the restore endpoint. +- #H19 `StartUpdate.fullRefresh`/`refreshSelection`/`fullRefreshSelection`/`resetCheckpointSelection`/`refreshFlowSelection` (originally cited at `model.ts:2738-2780`): Fixed in regeneration on 2026-05-20 — `resetCheckpointSelection` and `refreshFlowSelection` fields removed; remaining three (`fullRefresh`, `refreshSelection`, `fullRefreshSelection`) reduced to the documented pattern. +- #H22 `PipelinesEnvironment` vs `IngestionPipelineDefinition` prefix split (originally cited at `model.ts:2382`/`1173`): Fixed in regeneration on 2026-05-20 — the underlying `Pipelines*` plural prefix issue is now consolidated under H4 alongside other plural-prefixed types; no longer a standalone H finding. +- #M11 `GoogleDriveOptions_GoogleDriveIngestionScope` (originally cited at `model.ts:372-379`): Fixed in regeneration on 2026-05-20 — enum removed; only `GoogleDriveOptions_GoogleDriveEntityType` remains. +- #M13 `PeriodicTrigger_TimeUnit` (originally cited at `model.ts:384`): Fixed in regeneration on 2026-05-20 — enum and parent type `PeriodicTrigger` removed. +- #M31 `IngestionSourceType.COMMUNITY` (originally cited at `model.ts:88-92`): Fixed in regeneration on 2026-05-20 — `COMMUNITY` value removed from `IngestionSourceType`. +- #M36 `RewindSpec.rewindPointId` (originally cited at `model.ts:2637-2655`): Fixed in regeneration on 2026-05-20 — `rewindPointId` field removed; remaining `rewindTimestamp` is now tracked as M31. +- #L18 `IngestionPipelineDefinition_TableSpec.enableAutoClustering` and `clusteringColumns` (originally cited at `model.ts:1426`/`1435`): Fixed in regeneration on 2026-05-20 — both fields removed from `IngestionPipelineDefinition_TableSpec`. diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index a4ee9601..e1831b02 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -32,34 +32,34 @@ The package defines no enums. ### 1.2 Interfaces (`model.ts`) -| Name | Purpose | -| --------------------------------- | -------------------------------------------------- | -| `GetPolicyFamily` | Request body for the single-resource GET endpoint. | -| `ListPolicyFamilies` | Request body for the list endpoint. | -| `ListPolicyFamilies_Response` | Response from list (proto-style nested name). | -| `PolicyFamily` | The policy-family entity itself. | +| Name | Purpose | +| -------------------------------------- | -------------------------------------------------- | +| `GetPolicyFamilyRequest` | Request body for the single-resource GET endpoint. | +| `ListPolicyFamiliesRequest` | Request body for the list endpoint. | +| `ListPolicyFamiliesRequest_Response` | Response from list (proto-style nested name). | +| `PolicyFamily` | The policy-family entity itself. | ### 1.3 Fields (entity / request / response — combined catalog) -| Type | Field | Type / Notes | -| ------------------------------- | ----------------- | ----------------------------------------------------- | -| `GetPolicyFamily` | `policyFamilyId` | `string?` — path parameter (the resource identifier). | -| `GetPolicyFamily` | `version` | `number?` — version number to fetch (defaults to latest). | -| `ListPolicyFamilies` | `maxResults` | `number?` — page size. | -| `ListPolicyFamilies` | `pageToken` | `string?` — pagination cursor. | -| `ListPolicyFamilies_Response` | `policyFamilies` | `PolicyFamily[]?` — page of results. | -| `ListPolicyFamilies_Response` | `nextPageToken` | `string?` — pagination cursor for next page. | -| `PolicyFamily` | `policyFamilyId` | `string?` — unique identifier. | -| `PolicyFamily` | `name` | `string?` — display name. | -| `PolicyFamily` | `description` | `string?` — human-readable description. | -| `PolicyFamily` | `definition` | `string?` — Databricks Cluster Policy Definition Language JSON. | +| Type | Field | Type / Notes | +| -------------------------------------- | ----------------- | ----------------------------------------------------- | +| `GetPolicyFamilyRequest` | `policyFamilyId` | `string?` — path parameter (the resource identifier). | +| `GetPolicyFamilyRequest` | `version` | `number?` — version number to fetch (defaults to latest). | +| `ListPolicyFamiliesRequest` | `maxResults` | `number?` — page size. | +| `ListPolicyFamiliesRequest` | `pageToken` | `string?` — pagination cursor. | +| `ListPolicyFamiliesRequest_Response` | `policyFamilies` | `PolicyFamily[]?` — page of results. | +| `ListPolicyFamiliesRequest_Response` | `nextPageToken` | `string?` — pagination cursor for next page. | +| `PolicyFamily` | `policyFamilyId` | `string?` — unique identifier. | +| `PolicyFamily` | `name` | `string?` — display name. | +| `PolicyFamily` | `description` | `string?` — human-readable description. | +| `PolicyFamily` | `definition` | `string?` — Databricks Cluster Policy Definition Language JSON. | ### 1.4 Methods (`client.ts`) -| Method | Verb | Returns | -| ----------------------- | ---- | ----------------------------- | -| `getPolicyFamily` | GET | `PolicyFamily` | -| `listPolicyFamilies` | GET | `ListPolicyFamilies_Response` | +| Method | Verb | Returns | +| ----------------------- | ---- | ------------------------------------ | +| `getPolicyFamily` | GET | `PolicyFamily` | +| `listPolicyFamilies` | GET | `ListPolicyFamiliesRequest_Response` | | `listPolicyFamiliesIter`| GET | `AsyncGenerator` (paginated) | ### 1.5 Other identifiers @@ -70,7 +70,8 @@ The package defines no enums. `fullUrl`, `resp`, `call`, `callSignal`, `headers`, `httpReq`, `respBody`, `pageReq`, `item`, `info`. - `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`. + `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, + `marshalRequest`, `flattenQueryParams`. --- @@ -80,11 +81,11 @@ The package defines no enums. | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| V-01 | `PolicyFamily.definition` | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it is unclear whether this is a JSON document, a free-form string, or something else. Sibling field on the parent `clusterpolicies` package is `policyFamilyDefinitionOverrides` — so the convention within the SDK is `*Definition*`. `policyDefinition` would self-describe. (Codegen / API constraint.) | -| V-02 | `PolicyFamily.name` | Low | Generic but standard for entity types; meaning is preserved by the parent type. | -| V-03 | `PolicyFamily.description` | Low | Generic but standard across the SDK; acceptable. | -| V-04 | `GetPolicyFamily.version` | Medium | `version` is generic. The JSDoc says "version number for the family"; field could be `familyVersion` or `policyFamilyVersion` to make it self-describing when destructured (e.g. `const {version} = req` loses context). | -| V-05 | `flattenQueryParams` (utils) | Low | Reasonable. | +| V-01 | `PolicyFamily.definition` (`model.ts:37`) | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it is unclear whether this is a JSON document, a free-form string, or something else. Sibling field on the parent `clusterpolicies` package is `policyFamilyDefinitionOverrides` — so the convention within the SDK is `*Definition*`. `policyDefinition` would self-describe. (Codegen / API constraint.) | +| V-02 | `PolicyFamily.name` (`model.ts:33`) | Low | Generic but standard for entity types; meaning is preserved by the parent type. | +| V-03 | `PolicyFamily.description` (`model.ts:35`) | Low | Generic but standard across the SDK; acceptable. | +| V-04 | `GetPolicyFamilyRequest.version` (`model.ts:10`) | Medium | `version` is generic. The JSDoc says "version number for the family"; field could be `familyVersion` or `policyFamilyVersion` to make it self-describing when destructured (e.g. `const {version} = req` loses context). | +| V-05 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | ### 2.2 Redundant enum prefixes — High @@ -110,27 +111,28 @@ _None._ | C-01 | `req`, `resp` (locals in `client.ts`) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. Used in every CRUD method. | | C-02 | `httpReq` (local in `client.ts`) | Low | Short for "HTTP request". OK in local scope. | | C-03 | `respBody` (local in `client.ts`) | Low | Short for "response body". OK in local scope. | -| C-04 | `pageReq` (local in `client.ts`) | Low | Short for "page request". OK. | +| C-04 | `pageReq` (local in `client.ts:133`) | Low | Short for "page request". OK. | | C-05 | `opts` (`utils.ts` parameter, `executeHttpCall` and `executeCall`) | Low | Inside fn scope; minor. | -| C-06 | `pkgJson` (import in `client.ts`) | Low | Short for `packageJson`. Consistent with peer packages' codegen output. | -| C-07 | `acc` (local in `utils.ts` reduce callback) | Low | Standard reduce-accumulator name. OK. | +| C-06 | `pkgJson` (import in `client.ts:18`) | Low | Short for `packageJson`. Consistent with peer packages' codegen output. | +| C-07 | `acc` (local in `utils.ts:55` reduce callback) | Low | Standard reduce-accumulator name. OK. | ### 2.6 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| M-01 | `getPolicyFamily()` JSDoc: "an policy family" | Low | Typo in the JSDoc ("an" should be "a"). Not a naming issue but a generator artifact worth fixing upstream. | -| M-02 | `listPolicyFamilies()` JSDoc: "list of policy definition types" | Medium | The method returns *policy families*, but the JSDoc paraphrases them as "policy definition types". Mismatched terminology between the method name (`PolicyFamily`) and its docstring will confuse readers. Method/type/route all say "family"; doc should too. | -| M-03 | `GetPolicyFamily` JSDoc: "Returns the details of a policy family at a specific version" | Low | The JSDoc describes the *operation*, not the request body. The type is a request shape, not a response. Convention across the SDK, OK but slightly misleading on first read. | -| M-04 | `ListPolicyFamilies` JSDoc: "Returns the list of policy families…" | Low | Same as M-03 — the JSDoc describes the operation rather than the request shape. | -| M-05 | `Client` (class) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | +| M-01 | `getPolicyFamily()` JSDoc (`client.ts:61`): "an policy family" | Low | Typo in the JSDoc ("an" should be "a"). Not a naming issue but a generator artifact worth fixing upstream. | +| M-02 | `listPolicyFamilies()` JSDoc (`client.ts:92`): "list of policy definition types" | Medium | The method returns *policy families*, but the JSDoc paraphrases them as "policy definition types". Mismatched terminology between the method name (`PolicyFamily`) and its docstring will confuse readers. Method/type/route all say "family"; doc should too. | +| M-03 | `GetPolicyFamilyRequest` JSDoc (`model.ts:5`): "Returns the details of a policy family at a specific version" | Low | The JSDoc describes the *operation*, not the request body. The type is a request shape, not a response. Convention across the SDK, OK but slightly misleading on first read. | +| M-04 | `ListPolicyFamiliesRequest` JSDoc (`model.ts:13`): "Returns the list of policy families…" | Low | Same as M-03 — the JSDoc describes the operation rather than the request shape. | +| M-05 | `Client` (`client.ts:36`) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | ### 2.7 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | O-01 | `policyFamilyId` (every occurrence) | Low | 14 chars but precise. Two `policyFamily*` fields would collapse to one once the type name (`PolicyFamily`) is in scope, but it remains unambiguous across the SDK and matches the upstream API field name. Accept. | -| O-02 | `PACKAGE_SEGMENT` (`client.ts`) | Low | OK in context. | +| O-02 | `PACKAGE_SEGMENT` (`client.ts:31`) | Low | OK in context. | +| O-03 | `ListPolicyFamiliesRequest_Response` (`model.ts:22`) | Medium | The `Request_Response` compound suffix is verbose — the proto-nested style yields a name where `Request` is carried into the response type even though the response is not a request. A flatter `ListPolicyFamiliesResponse` would self-describe. (Generator-level.) | ### 2.8 Singular / plural mismatches — Low @@ -138,8 +140,8 @@ _None._ | ----- | ---------------------------------------------------- | -------- | ----- | | P-01 | `getPolicyFamily()` (singular) | Low | Singular for a single-resource GET. Correct. | | P-02 | `listPolicyFamilies()` (plural method) | Low | Plural for a collection endpoint. Correct. | -| P-03 | `ListPolicyFamilies` request type vs `listPolicyFamilies` method | Low | Both plural and matched. Correct. | -| P-04 | `ListPolicyFamilies_Response.policyFamilies` | Low | Plural field for an array of `PolicyFamily`. Correct. | +| P-03 | `ListPolicyFamiliesRequest` request type vs `listPolicyFamilies` method | Low | Both plural and matched. Correct. | +| P-04 | `ListPolicyFamiliesRequest_Response.policyFamilies` | Low | Plural field for an array of `PolicyFamily`. Correct. | | P-05 | Package directory `policyfamilies` (lowercase) | Low | The npm package is `@databricks/sdk-policyfamilies` (lowercase, no separator). Compare with `clusterpolicies`, `clusterlibraries`, `instancepools`. Convention is consistent across this codebase — squashed lowercase. The directory and package name use plural ("families") which matches the dominant resource the package exposes. Acceptable but visually awkward (`policyfamilies` is hard to parse versus `policy-families`); a hyphenated path / scoped suffix would be more readable. (Pattern is repo-wide; flagged once.) | | P-06 | `PolicyFamily` (entity, singular) vs `policyfamilies` (package directory, plural) | Low | Standard pattern — the package is plural, the entity it contains is singular. OK. | @@ -180,7 +182,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| F-01 | `version` (on `GetPolicyFamily`) | Medium | When destructured (`const {version} = req`) the meaning collapses to "some version number". Within the SDK there are also `Catalog.version`, `Volume.version`, `Schema.version` etc.; the field is overloaded in name space if not in scope. Renaming to `familyVersion` (or matching what the wire JSON key actually is — `version`) is a tradeoff between SDK-internal consistency and on-wire fidelity. Cf. V-04. | +| F-01 | `version` (on `GetPolicyFamilyRequest`) | Medium | When destructured (`const {version} = req`) the meaning collapses to "some version number". Within the SDK there are also `Catalog.version`, `Volume.version`, `Schema.version` etc.; the field is overloaded in name space if not in scope. Renaming to `familyVersion` (or matching what the wire JSON key actually is — `version`) is a tradeoff between SDK-internal consistency and on-wire fidelity. Cf. V-04. | | F-02 | `name` (on `PolicyFamily`) | Low | Universal noun; meaning is preserved through type context. OK. | | F-03 | `description` (on `PolicyFamily`) | Low | Same as F-02. | | F-04 | `definition` (on `PolicyFamily`) | Medium | See V-01 / D-02. Generic and overloaded — losing parent-type context makes it unclear whether this is JSON, YAML, or a free-form string. | @@ -217,23 +219,30 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | TS-01 | `PolicyFamily` — does the `Family` suffix double up with `Policy`? | Low | `PolicyFamily` is the domain term used in the Databricks docs (cf. https://docs.databricks.com/en/admin/clusters/policy-families.html). The "Family" here means *grouping/template*, not a `*Family` type-suffix tautology. OK. | -| TS-02 | `GetPolicyFamily`, `ListPolicyFamilies` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | -| TS-03 | `HttpCallOptions` (utils) | Low | The `Options` suffix is a standard TS pattern (`fetch` accepts `RequestInit`, but `Options` is widespread). OK. | +| TS-02 | `GetPolicyFamilyRequest`, `ListPolicyFamiliesRequest` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | +| TS-03 | `HttpCallOptions` (`utils.ts:15`) | Low | The `Options` suffix is a standard TS pattern (`fetch` accepts `RequestInit`, but `Options` is widespread). OK. | -### 2.20 Other observations +### 2.20 Proto / architectural-leak naming — High | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| X-01 | `version` typed as `number` (`GetPolicyFamily.version`) | Low | The API contract uses an integer version. `number` is fine; flagged for completeness. No `bigint` is needed (versions won't exceed `Number.MAX_SAFE_INTEGER`). | +| PL-01 | `ListPolicyFamiliesRequest_Response` (`model.ts:22`, `model.ts:41`, `client.ts:22`, `client.ts:26`, `client.ts:96`, `client.ts:107`, `client.ts:119`, `index.ts:10`) | High | The mid-position `Request_` token leaks proto's nested-message convention (`ListPolicyFamiliesRequest.Response` flattened with `_`). `Request` is meaningless mid-name on a response type and forces an `eslint-disable` for `@typescript-eslint/naming-convention`. **Suggested:** `ListPolicyFamiliesResponse`. **Rationale:** drops the proto-architectural leak; aligns with idiomatic TS `Response`. (Generator-level.) | +| PL-02 | `unmarshalListPolicyFamiliesRequest_ResponseSchema` (`model.ts:41`, `client.ts:26`, `client.ts:119`) | High | Same proto-nested leak carried into the schema constant. **Suggested:** `unmarshalListPolicyFamiliesResponseSchema`. **Rationale:** removes the `Request_` infix; matches PL-01. (Generator-level.) | + +### 2.21 Other observations + +| ID | Symbol | Severity | Issue | +| ----- | ---------------------------------------------------- | -------- | ----- | +| X-01 | `version` typed as `number` (`GetPolicyFamilyRequest.version`) | Low | The API contract uses an integer version. `number` is fine; flagged for completeness. No `bigint` is needed (versions won't exceed `Number.MAX_SAFE_INTEGER`). | | X-02 | `pageToken` / `nextPageToken` (cross-pagination field naming) | Low | Standard Databricks SDK pagination shape. The request-side cursor is `pageToken`, the response-side cursor is `nextPageToken` — consistent with `clusterpolicies`, `instancepools`, etc. OK. | -| X-03 | `maxResults` (`ListPolicyFamilies.maxResults`) | Low | Standard pagination field name. OK. | +| X-03 | `maxResults` (`ListPolicyFamiliesRequest.maxResults`) | Low | Standard pagination field name. OK. | | X-04 | `Client.host` is mutated post-construction via `replace(/\/$/, '')` only at constructor entry | Low | Naming-wise neutral; not strictly a naming issue. The field name `host` (rather than `baseUrl` or `endpoint`) is consistent with peer packages. | | X-05 | `Client.userAgent` (private) | Low | Standard naming; HTTP `User-Agent` is the wire-format identifier. OK. | | X-06 | `executeCall` parameter `call: Call` | Low | The type `Call` is generic from `@databricks/sdk-core/api` and overloads the verb; readers may briefly wonder which "call" is meant (function callback vs. RPC call). Imported from the core package; flagged once. | | X-07 | `callSignal` (local in `client.ts`) | Low | Distinct from `req.signal` / `options?.signal` — the qualifier `call` disambiguates. Good. | | X-08 | `flattenQueryParams` (utils, exported) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | -| X-09 | `pageReq` (local in `client.ts`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | -| X-10 | `index.ts` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | +| X-09 | `pageReq` (local in `client.ts:133`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | +| X-10 | `index.ts:5` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | | X-11 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | | X-12 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-05. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | @@ -245,10 +254,10 @@ _None._ | Severity | Count | | -------- | ----- | -| High | 0 | -| Medium | 10 | +| High | 2 | +| Medium | 11 | | Low | 28 | -| **Total**| **38**| +| **Total**| **41**| ### 3.2 Top themes @@ -259,7 +268,7 @@ _None._ per-package mistakes. 2. **`definition` and `version` are over-generic on a generic entity.** - `PolicyFamily.definition` and `GetPolicyFamily.version` are the two + `PolicyFamily.definition` and `GetPolicyFamilyRequest.version` are the two fields whose meaning is best inferred from the JSDoc rather than from the field name itself. Renaming to `policyDefinition` / `familyVersion` (or `policyFamilyVersion`) would self-describe. @@ -276,6 +285,8 @@ codegen owners) "policy families"). - Rename `Client` → `PolicyFamiliesClient` for cross-package disambiguation. (Repo-wide pattern; flag at codegen layer.) +- Flatten `ListPolicyFamiliesRequest_Response` → `ListPolicyFamiliesResponse` + to drop the proto-nested `Request_Response` compound suffix. ### 3.4 Cross-package consistency notes @@ -287,3 +298,9 @@ codegen owners) `Policy.policyFamilyDefinitionOverrides` — partial inconsistency, but defensible since the override is a delta and the canonical definition lives on the family. + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index 5d49d730..4cf5151e 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -2,555 +2,387 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 -**Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `ComputeInstance`s (the individual compute nodes inside an endpoint group), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Table`s (non-synced PG tables), `Catalog`s (Unity Catalog mirrors of logical PG databases), Forward ETL (PG→UC reverse-ETL), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Waiter`-style classes. -**Total weird names flagged:** 83 +**Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Catalog`s (Unity Catalog mirrors of logical PG databases), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Operation` waiter-style classes. +**Total weird names flagged:** 53 ## Summary | Severity | Count | | --- | --- | -| High | 16 | -| Medium | 47 | -| Low | 17 | -| Observation | 3 | +| High | 9 | +| Medium | 31 | +| Low | 11 | +| Observation | 2 | ## High severity ### 1. Package name `postgres` does not say "Lakebase" / "autoscaling" / "managed-PG" — `packages/postgres/` -- **Why weird:** Generic single-word name for a Databricks-specific service. The actual product is "Lakebase Autoscaling Postgres" (see JSDoc `createProject`, `client.ts:363`). Sibling package `database` covers earlier-generation Lakebase (`DatabaseInstance` / V1), and `postgres` is V2 — see `database/naming-audit/database.md` finding #2. Neither package name says "Lakebase" or makes the V1/V2 lineage discoverable. +- **Why weird:** Generic single-word name for a Databricks-specific service. The actual product is "Lakebase Autoscaling Postgres" (see JSDoc `createProject`, `client.ts:339`). Sibling package `database` covers earlier-generation Lakebase (`DatabaseInstance` / V1), and `postgres` is V2 — see `database/naming-audit/database.md` finding #2. Neither package name says "Lakebase" or makes the V1/V2 lineage discoverable. - **Category:** 1 (vague/generic), 12 (duplicate concept across packages). - **Suggested name:** `lakebase` (and merge with `database`), or `lakebase-autoscaling`, or `lakebase-v2`. At minimum, add an `index.ts` JSDoc declaring "Lakebase Autoscaling Postgres (V2 OLTP)". - **Rationale:** `postgres` is too broad — Databricks also has Postgres-backed services elsewhere (DBSQL, query history, etc.). Naming should encode the product. ### 2. `postgres` and `database` packages overlap heavily — `packages/postgres/` vs `packages/database/` -- **Why weird:** Many duplicate type names: `DeltaTableSyncInfo` (`model.ts:1295` vs `database/v1/model.ts:477`), `SyncedTablePosition` (`model.ts:2563` vs `database:762`), `SyncedTablePipelineProgress` (`model.ts:2547` vs `database:744`), `NewPipelineSpec` (`model.ts:1963` vs `database:598`), `DatabaseCredential` (`model.ts:1167` vs `database:228`), `GenerateDatabaseCredentialRequest` (`model.ts:1591` vs `database:499`), `RequestedClaims` (`model.ts:2232` vs `database:630`), `RequestedResource` (`model.ts:2237` vs `database:635`), `ProvisioningInfo` (`model.ts:2230` vs `database:628`), `ProvisioningPhase`/`SyncedTableState`/`ProvisioningInfo_State`/`RequestedClaims_PermissionSet`/`SyncedTableSpec_PgSpecificType`/`SyncedTableSpec_SecondaryIndex_CreationPoint`. Identical signatures but exported from two packages — a TS user importing both gets noisy alias-juggling. +- **Why weird:** Many duplicate type names remain across the two packages: `DeltaTableSyncInfo` (`model.ts:1169`), `SyncedTablePosition` (`model.ts:2012`), `SyncedTablePipelineProgress` (`model.ts:1996`), `NewPipelineSpec` (`model.ts:1544`), `DatabaseCredential` (`model.ts:1079`), `GenerateDatabaseCredentialRequest` (`model.ts:1361`), `RequestedClaims` (`model.ts:1750`), `RequestedResource` (`model.ts:1755`), `ProvisioningInfo` (`model.ts:1748`), `ProvisioningInfo_State`/`SyncedTableState`/`RequestedClaims_PermissionSet`. Identical signatures but exported from two packages — a TS user importing both gets noisy alias-juggling. - **Category:** 12 (duplicate concept across packages), 6 (misleading: same name, two definitions). - **Suggested name:** Pick one as canonical; the other re-exports from the canonical or marks itself deprecated. Cross-reference each shared type with a JSDoc note like "Equivalent to `database/v1.DeltaTableSyncInfo`; see go/lakebase-v2 for the migration." - **Rationale:** Same as `database` finding #2 — `postgres` is V2 and `database` is V1; nothing in the names says so. ### 3. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` -- **Why weird:** Huge enum (~100 entries) referenced exactly once via `DatabricksServiceExceptionWithDetailsProto.errorCode` (1179). Most entries are explicitly marked "NOTE: Deprecated and kept to maintain backwards compatibility for public APIs that use it, avoid using it in the new APIs" (e.g. `IO_ERROR`, `INVALID_STATE`, `UNPARSEABLE_HTTP_ERROR`, `QUOTA_EXCEEDED`, `MAX_BLOCK_SIZE_EXCEEDED`, `DRY_RUN_FAILED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, all the `GIT_*`, `IPYNB_FILE_IN_REPO`, `INSECURE_PARTNER_RESPONSE`, `METASTORE_*_EXISTS`, `CATALOG_NOT_EMPTY`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, etc. — at least 40 entries). The enum re-exports the entire Databricks-platform error vocabulary into a Postgres-specific SDK package. +- **Why weird:** Huge enum (~100 entries) referenced exactly once via `DatabricksServiceExceptionWithDetailsProto.errorCode` (1091). Most entries are explicitly marked "NOTE: Deprecated and kept to maintain backwards compatibility for public APIs that use it, avoid using it in the new APIs" (e.g. `IO_ERROR`, `INVALID_STATE`, `UNPARSEABLE_HTTP_ERROR`, `QUOTA_EXCEEDED`, `MAX_BLOCK_SIZE_EXCEEDED`, `DRY_RUN_FAILED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, all the `GIT_*`, `IPYNB_FILE_IN_REPO`, `INSECURE_PARTNER_RESPONSE`, `METASTORE_*_EXISTS`, `CATALOG_NOT_EMPTY`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, etc. — at least 40 entries). The enum re-exports the entire Databricks-platform error vocabulary into a Postgres-specific SDK package. - **Category:** 7 (overly verbose), 11 (empty/trivial wrappers for deprecated values), 14 (Go/proto leak — all deprecated values exist only "for public APIs that use it"), 18 (long enum values). - **Suggested name:** Move `ErrorCode` to a shared `core/apierror` package (already exists per CLAUDE.md), drop deprecated values from the public TS surface (or mark them `@deprecated` so TS tooling can warn). - **Rationale:** Every consumer of this package gets a 100-entry deprecated-warning bundle. The fact that it's exported from `postgres/v1/index.ts` (line 30) means it's part of the public surface. -### 4. Four "State" enums share value vocabulary but use three different qualifier patterns — `src/v1/model.ts:581, 628, 599, 654` -- **Why weird:** Four state enums use three different qualifier patterns: +### 4. Three "State" enums share value vocabulary but use two different qualifier patterns — `src/v1/model.ts:581, 600, 610` +- **Why weird:** Three state enums use two different qualifier patterns: - Branch state and endpoint state qualify by the status struct (`BranchStatus`-scoped, `EndpointStatus`-scoped). - - Compute state qualifies by the resource and names the leaf `ComputeState`. - Provisioning state lives under the unrelated `ProvisioningInfo` wrapper. - - All four enums share values like `STATE_UNSPECIFIED`, `INIT`, `ACTIVE`, etc. The TypeScript user can't tell which enum to use for which resource without reading the JSDoc. + - All three enums share values like `INIT`, `ACTIVE`, etc. The TypeScript user can't tell which enum to use for which resource without reading the JSDoc. - **Category:** 17 (inconsistent naming pattern). -- **Suggested name:** Standardise to `State`: `BranchState`, `EndpointState`, `ComputeState`, `ProvisioningState`. -- **Rationale:** Four state enums with three naming conventions across one package. - -### 5. Enum values all carry redundant resource prefix — `src/v1/model.ts` (multiple enums) -- **Why weird:** Every enum's `UNSPECIFIED` sentinel duplicates the enum name: - - `EndpointType.ENDPOINT_TYPE_UNSPECIFIED` / `ENDPOINT_TYPE_READ_WRITE` / `ENDPOINT_TYPE_READ_ONLY` (line 11-13) - - `ProvisioningPhase.PROVISIONING_PHASE_*` (520-526) - - `SyncedTableState.SYNCED_TABLE_*` (532-576, 14 entries, each re-stating `SYNCED_TABLE`) - - `BranchStatus_State.STATE_UNSPECIFIED` (only one with the prefix; others don't, see #6) - - `ComputeInstance_ComputeState.COMPUTE_STATE_UNSPECIFIED` - - `ComputeInstance_ComputeType.COMPUTE_TYPE_UNSPECIFIED` - - `EndpointStatus_State.STATE_UNSPECIFIED` - - `NewPipelineSpec_PipelineChannel.PIPELINE_CHANNEL_UNSPECIFIED` - - `ProvisioningInfo_State.STATE_UNSPECIFIED` - - `RequestedClaims_PermissionSet.PERMISSION_SET_UNSPECIFIED` - - `Role_AuthMethod.AUTH_METHOD_UNSPECIFIED` - - `Role_IdentityType.IDENTITY_TYPE_UNSPECIFIED` - - `Role_MembershipRole.MEMBERSHIP_ROLE_UNSPECIFIED` -- **Category:** 2 (redundant enum prefixes), 18 (long enum values). -- **Suggested name:** Drop the prefix everywhere — `EndpointType.Unspecified | ReadWrite | ReadOnly` etc. -- **Rationale:** `EndpointType.ENDPOINT_TYPE_READ_WRITE` is 41 chars to say "read-write". - -### 6. `SyncedTableState` — 14 enum values each prefixed `SYNCED_TABLE_*` — `src/v1/model.ts:532-576` -- **Why weird:** Worst offender. 14 values: - `SYNCED_TABLE_STATE_UNSPECIFIED`, `SYNCED_TABLE_PROVISIONING`, `SYNCED_TABLE_PROVISIONING_PIPELINE_RESOURCES` (45 chars), `SYNCED_TABLE_PROVISIONING_INITIAL_SNAPSHOT` (42 chars), `SYNCED_TABLE_ONLINE`, `SYNCED_TABLE_ONLINE_CONTINUOUS_UPDATE` (38 chars), `SYNCED_TABLE_ONLINE_TRIGGERED_UPDATE` (37 chars), `SYNCED_TABLE_ONLINE_NO_PENDING_UPDATE` (38 chars), `SYNCED_TABLE_OFFLINE`, `SYNCED_TABLE_OFFLINE_FAILED`, `SYNCED_TABLE_ONLINE_PIPELINE_FAILED` (36 chars), `SYNCED_TABLE_ONLINE_UPDATING_PIPELINE_RESOURCES` (47 chars). All re-state `SYNCED_TABLE_` to no benefit. Note: this enum is duplicated in `database/v1/model.ts:55` (with one typo, `SYNCED_TABLED_OFFLINE`) — not duplicated here, but the divergence is itself a smell. -- **Category:** 2 (redundant prefixes), 18 (long enum values). -- **Suggested name:** `SyncedTableState.Unspecified | Provisioning | ProvisioningPipelineResources | ProvisioningInitialSnapshot | Online | OnlineContinuousUpdate | OnlineTriggeredUpdate | OnlineNoPendingUpdate | Offline | OfflineFailed | OnlinePipelineFailed | OnlineUpdatingPipelineResources`. -- **Rationale:** Same as #5 but most severe enum. - -### 7. SyncedTable scheduling-policy enum — only `SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` carries a prefix; the other three values are bare — `src/v1/model.ts:731` -- **Why weird:** The first value is `SYNCED_TABLE_SCHEDULING_POLICY_UNSPECIFIED` (41 chars); the other three values are bare `CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`. Internally inconsistent within a single enum. -- **Category:** 2 (redundant prefix), 17 (inconsistent — `UNSPECIFIED` carries the prefix, others don't), 18 (long enum values). -- **Suggested name:** Standardise values as `Unspecified | Continuous | Triggered | Snapshot`. -- **Rationale:** Same as #5. - -### 8. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:2276-2278` -- **Why weird:** Three lowercase run-together field names. Doc comment (lines 2269-2272) acknowledges the choice ("The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words"). That's a wire-format justification (Postgres keywords). The TypeScript identifier should still be camelCase. `createrole` is especially confusing — could read as `createRole` (verb) or `creator_ole`. +- **Suggested name:** Standardise to `State`: `BranchState`, `EndpointState`, `ProvisioningState`. +- **Rationale:** Three state enums with two naming conventions across one package. + +### 5. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:1793-1795` +- **Why weird:** Three lowercase run-together field names. Doc comment (lines 1786-1789) acknowledges the choice ("The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words"). That's a wire-format justification (Postgres keywords). The TypeScript identifier should still be camelCase. `createrole` is especially confusing — could read as `createRole` (verb) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS), 17 (inconsistent — every other field in the package is camelCase). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; wire stays `createdb`/`createrole`/`bypassrls`. - **Rationale:** Same finding as `database` audit #5 — both packages share this bug. -### 9. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:677, 682` +### 6. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:633, 638` - **Why weird:** Implementation details (SCRAM-SHA-256 mechanism, OAuth `_V1`) leak into the public enum. The `_V1` suffix begs the question: what happens at V2? Should the SDK consumer have to migrate from `LAKEBASE_OAUTH_V1` to `LAKEBASE_OAUTH_V2` when the wire format changes? Worse, the `SCRAM_SHA_256` qualifier is a specific hash function — consumers picking an auth method shouldn't have to know about hash schemes. - **Category:** 1 (vague at the wrong level — too specific), 6 (misleading: `LAKEBASE_OAUTH_V1` versioning leaks), 14 (Postgres/auth-spec internal naming), 18 (long enum values). - **Suggested name:** `Password` (replacing `PG_PASSWORD_SCRAM_SHA_256`) and `OAuth` (replacing `LAKEBASE_OAUTH_V1`). Keep `NoLogin`. Push the wire-protocol-specific names into the marshal layer. - **Rationale:** Public enums should describe the *concept* (password vs OAuth vs no-login), not the wire-protocol mechanism. -### 10. `Forward ETL` types use a Java/Kotlin-style adjective phrase — `src/v1/model.ts:1229-1325` (multiple types), `client.ts:670-882` (methods) -- **Why weird:** "Forward ETL" is product-marketing terminology baked into 11 type/method names: - - `DeleteForwardEtlConfigurationRequest` / `DeleteForwardEtlConfigurationResponse` (1229, 1246) - - `DisableForwardEtlRequest` / `DisableForwardEtlResponse` (1306, 1323) - - `ForwardEtlConfig` (1520) - - `ForwardEtlDatabase` (1544) - - `ForwardEtlMetadata` (1552) - - `ForwardEtlSchema` (1560) - - `ForwardEtlStatus` (1568) - - `ForwardEtlTableMapping` (1576) - - `GetForwardEtlMetadataRequest` (1672) / `GetForwardEtlStatusRequest` (1685) - - Methods: `deleteForwardEtlConfiguration` (672), `disableForwardEtl` (845), `getForwardEtlMetadata` (1042), `getForwardEtlStatus` (1076). - - "ETL" is consistent capitalised acronym but is camelCased as `Etl` (lowercase tl), violating common style guides (TypeScript Google style: prefer `URL` over `Url` for known acronyms ≥3 chars). -- **Category:** 3 (acronym casing — `Etl` vs `ETL`), 7 (verbose — repeating "Forward ETL" 11 times), 14 (marketing-name leak), 1 (vague — "Forward" is a direction qualifier without context). -- **Suggested name:** Group under a `ReverseEtl` namespace (since "Forward ETL" from PG's perspective is reverse-ETL from Lakehouse's perspective — choose one direction language and stick to it). Use `ETL` casing per acronym convention or rename to `Replication` if that's the intent. Re-export under a single top-level type bundle. -- **Rationale:** "Forward" / "Reverse" terminology is consumer-facing direction labelling that can backfire — one company's "forward" is another's "reverse". 11 types prefixed with the same product-marketing string is verbose. - -### 11. `ForwardEtlConfig.createTimeMillis` / `updateTimeMillis` — millis-suffixed timestamps as `number` — `src/v1/model.ts:1538, 1540` -- **Why weird:** Every other timestamp in the package is `Temporal.Instant` (see `Branch.createTime`, `Catalog.createTime`, `DatabaseCredential.expireTime`, etc.). Only the ForwardEtl types use `number` with `Millis` suffix, breaking the package-wide convention. The unmarshal at `model.ts:3148-3149` confirms they stay as plain `number`. -- **Category:** 16 (field type contradicts the established package convention), 17 (inconsistent — every other timestamp is `Temporal.Instant`), 14 (Java-style epoch-millis convention). -- **Suggested name:** `createTime: Temporal.Instant` (parse `_millis` into Instant in unmarshal). -- **Rationale:** Mixing `Temporal.Instant` and raw millis numbers in the same SDK forces consumers to remember per-type rules. - -### 12. `Forward ETL` `pgDatabaseOid` / `pgSchemaOid` / `pgTableOid` — Postgres-internal IDs without doc — `src/v1/model.ts:1240, 1242, 1317, 1319, 1528, 1530, 1578` -- **Why weird:** `Oid` is Postgres slang for "object identifier" (a `pg_class.oid`-style integer). Field doc is minimal: "PostgreSQL database OID." Consumers unfamiliar with Postgres internals don't know how to *obtain* a `pgDatabaseOid` (it's not in the API for fetching a database). The fields appear in 4+ types: `DeleteForwardEtlConfigurationRequest`, `DisableForwardEtlRequest`, `ForwardEtlConfig`, `ForwardEtlTableMapping`. -- **Category:** 5 (cryptic abbreviation — `Oid`), 14 (Postgres-internal jargon in public API). -- **Suggested name:** `postgresDatabaseObjectId` / `postgresSchemaObjectId` / `postgresTableObjectId`. Or surface the wire format `Oid` but expand the doc with "(obtain via `psql -c \"SELECT oid FROM pg_database WHERE datname = '...'\"`)". -- **Rationale:** `Oid` is one of those abbreviations DBAs know cold but TS consumers do not. - -### 13. `tenantId` / `timelineId` in Forward ETL request types — `src/v1/model.ts:1236, 1238, 1313, 1315, 1524, 1526, 1679, 1681, 1692, 1694` -- **Why weird:** `tenantId` and `timelineId` appear without explanation — only "Tenant ID (dashless UUID format)" and "Timeline ID (dashless UUID format)" doc. What's a Lakebase "tenant"? What's a "timeline"? These appear nowhere else in the SDK as concept-level types. Consumers can't discover what to put here. -- **Category:** 19 (underspecified ID — what entity does the tenant ID identify?), 1 (vague), 6 (misleading — "tenant" and "timeline" are not exposed concepts elsewhere). -- **Suggested name:** `lakebaseTenantId` / `lakebaseTimelineId` with doc explaining what they reference. Or fold into existing resource refs (e.g. branch resource name). -- **Rationale:** Same as #12 — Postgres-storage-internal terms (the timeline is a Neon/Lakebase storage concept) leaking into the SDK. - -### 14. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1182` -- **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The type is reached via `Operation.result` (line 2031), making it the SDK's primary error surface. Every error consumer must cast. +### 7. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1094` +- **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The type is reached via `Operation.result` (line 1588), making it the SDK's primary error surface. Every error consumer must cast. - **Category:** 1 (vague), 15 (generic), 16 (type contradicts domain — details have structure, just unmodelled). - **Suggested name:** Add typed discriminator: `details: ErrorDetail[]` with `ErrorDetail = ResourceInfo | RetryInfo | …` aligned to `google.rpc.Status`. - **Rationale:** Errors are the most-handled values in any SDK; opaque `unknown` arrays force every caller to write defensive code. -### 15. 22 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1845-3680` -- **Why weird:** The package exports 22 boilerplate poller classes (each ~80 lines, near-identical): `CreateBranchOperation`, `CreateCatalogOperation`, `CreateDatabaseOperation`, `CreateEndpointOperation`, `CreateProjectOperation`, `CreateRoleOperation`, `CreateSyncedTableOperation`, `DeleteBranchOperation`, `DeleteCatalogOperation`, `DeleteDatabaseOperation`, `DeleteEndpointOperation`, `DeleteProjectOperation`, `DeleteRoleOperation`, `DeleteSyncedTableOperation`, `UndeleteBranchOperation`, `UndeleteProjectOperation`, `UpdateBranchOperation`, `UpdateDatabaseOperation`, `UpdateEndpointOperation`, `UpdateProjectOperation`, `UpdateRoleOperation`. Each has identical `name()` / `metadata()` / `wait()` / `done()` methods, differing only in return type (`Branch` vs `Catalog` vs `Database` etc.). All 22 are exported from `index.ts:5-26`. -- **Category:** 7 (overly verbose), 11 (trivial wrappers), 14 (Go-style poll-helper pattern), 17 (22-way redundancy). -- **Suggested name:** Single generic `Operation` class with `wait(): Promise` and `metadata(): Promise`. Drop all 22 named exports; expose factory methods on `Client` like `createBranchOperation()` that return `Operation`. -- **Rationale:** Comparable to `database/v1/client.ts`'s `CreateDatabaseInstanceWaiter` — but here the pattern is repeated 22 times. This bloats the bundle, the public surface, and the autocomplete list. +### 8. 21 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1512-3345` +- **Why weird:** The package exports 21 boilerplate poller classes (each ~80 lines, near-identical): `CreateBranchOperation`, `CreateCatalogOperation`, `CreateDatabaseOperation`, `CreateEndpointOperation`, `CreateProjectOperation`, `CreateRoleOperation`, `CreateSyncedTableOperation`, `DeleteBranchOperation`, `DeleteCatalogOperation`, `DeleteDatabaseOperation`, `DeleteEndpointOperation`, `DeleteProjectOperation`, `DeleteRoleOperation`, `DeleteSyncedTableOperation`, `UndeleteBranchOperation`, `UndeleteProjectOperation`, `UpdateBranchOperation`, `UpdateDatabaseOperation`, `UpdateEndpointOperation`, `UpdateProjectOperation`, `UpdateRoleOperation`. Each has identical `name()` / `metadata()` / `wait()` / `done()` methods, differing only in return type (`Branch` vs `Catalog` vs `Database` etc.). All 21 are exported from `index.ts:5-26`. +- **Category:** 7 (overly verbose), 11 (trivial wrappers), 14 (Go-style poll-helper pattern), 17 (21-way redundancy). +- **Suggested name:** Single generic `Operation` class with `wait(): Promise` and `metadata(): Promise`. Drop all 21 named exports; expose factory methods on `Client` like `createBranchOperation()` that return `Operation`. +- **Rationale:** Comparable to `database/v1/client.ts`'s `CreateDatabaseInstanceWaiter` — but here the pattern is repeated 21 times. This bloats the bundle, the public surface, and the autocomplete list. -### 16. `*Operation` classes mix verb prefix with noun suffix — e.g. `CreateBranchOperation` — `src/v1/client.ts:1845, …` -- **Why weird:** Class name reads as "the *create branch* operation" — i.e. a long-running operation produced by creating a branch. JS convention for poller helpers tends to be `Poller`, `Waiter`, or a verb-form factory. Calling it `CreateBranchOperation` (verb + noun + noun-suffix `Operation`) parses ambiguously: a `CreateBranchOperation` could be "an operation that creates a branch" (active) or "an in-flight operation tracking branch creation" (passive). The latter is the intent. -- **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming), 11 (wrapper-class pattern). -- **Suggested name:** `BranchCreation` / `BranchCreationOperation` (passive form), or factor into a single generic `Operation` (see #15). -- **Rationale:** Same as `database` audit #14. Class names should be unambiguous noun phrases. +### 9. `DatabricksServiceExceptionWithDetailsProto` — proto-architectural-leak type name — `src/v1/model.ts:1090`, `index.ts:64` +- **Why weird:** The type name carries two architectural leaks in one identifier: mid-position `Service` (the server-side concept the message originates from) and a trailing `Proto` suffix (the wire-format origin). Neither term is part of the domain. The same name surfaces on `Operation.result.error` (line 1592), so every SDK consumer who inspects an `Operation` error encounters "ServiceException...Proto" jargon. `WithDetails` is also a hand-rolled qualifier that mirrors how proto messages get suffixed when extended; an idiomatic TS API would just call this `DatabricksError` and treat the detail array as part of the error itself. +- **Category:** 14 (proto-architectural-leak — both `Service` mid and `Proto` suffix), 7 (overly verbose), 5 (5 stacked qualifiers — `Databricks` + `Service` + `Exception` + `WithDetails` + `Proto`). +- **Suggested name:** `DatabricksApiError` (or `DatabricksError`, matching `@databricks/sdk-databricks/apierror` conventions in CLAUDE.md). Drop `Service`, `Proto`, and the `WithDetails` distinguisher; the type already carries `details` as a first-class field. +- **Rationale:** The user explicitly flags `Service` mid-position and `Proto` suffix as architectural leaks; both appear in this one type name. The type is also a public, error-carrying surface, so the leak is highly visible. ## Medium severity -### 17. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` / `Table` / `ComputeInstance` — 9 generic top-level resource names — `src/v1/model.ts` (multiple) -- **Why weird:** Most of these names are single-word generic English (`Branch`, `Catalog`, `Database`, `Endpoint`, `Project`, `Role`, `Table`). Multiple are *already-taken* concepts in Databricks-land: +### 10. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` — 7 generic top-level resource names — `src/v1/model.ts` (multiple) +- **Why weird:** Most of these names are single-word generic English (`Branch`, `Catalog`, `Database`, `Endpoint`, `Project`, `Role`). Multiple are *already-taken* concepts in Databricks-land: - `Catalog` collides with Unity Catalog `Catalog` (in `catalogs` package) - `Database` collides with the `database` package's `DatabaseInstance` / `DatabaseCatalog` - `Endpoint` collides with `endpoints` package (Model Serving endpoints) and `vector-search endpoints` - `Project` is a generic word — Lakebase Projects are not the same as Bundle projects or Genie projects. - `Role` collides with workspace IAM roles and instance-profile roles. - - `Table` collides with `tables` (Unity Catalog tables), `onlinetables`, `database.DatabaseTable`. - - `ComputeInstance` collides with `database.DatabaseInstance` (the older equivalent). - **Category:** 1 (vague/generic), 12 (duplicate concept across packages). -- **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`, `LakebaseTable`, `LakebaseComputeInstance`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). +- **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). - **Rationale:** With 100+ packages in the workspace, single-word resource names guarantee collisions. -### 18. `Branch.uid` / `Endpoint.uid` / `Project.uid` / `SyncedTable.uid` — bare `uid` fields, sometimes vs `name` — `src/v1/model.ts:757, 1335, 2048, 2375` -- **Why weird:** Same problem as `database` finding #18: two identifier-like fields. `name` is a resource path (`projects/{id}/branches/{id}`), `uid` is "System-generated unique ID". Caller can't tell which to pass to `getBranch` (answer: `name`). Bare `uid` is non-descriptive — what scope (project? branch? UC table?). +### 11. `Branch.uid` / `Endpoint.uid` / `Project.uid` / `SyncedTable.uid` — bare `uid` fields, sometimes vs `name` — `src/v1/model.ts:695, 1186, 1609, 1892` +- **Why weird:** Same problem as `database` finding #19: two identifier-like fields. `name` is a resource path (`projects/{id}/branches/{id}`), `uid` is "System-generated unique ID". Caller can't tell which to pass to `getBranch` (answer: `name`). Bare `uid` is non-descriptive — what scope (project? branch? UC table?). - **Category:** 19 (underspecified id), 1 (vague `uid`). - **Suggested name:** `branchUid` / `endpointUid` / `projectUid` / `syncedTableUid` (and add docs). -- **Rationale:** Same as `database` audit #18. +- **Rationale:** Same as `database` audit #19. -### 19. `Branch.name` / `Catalog.name` / etc. — `name` is a full resource path — `src/v1/model.ts:755, 878, 1106, 1333, 2046, 2254` +### 12. `Branch.name` / `Catalog.name` / etc. — `name` is a full resource path — `src/v1/model.ts:693, 816, 1018, 1184, 1607, 1771` - **Why weird:** Field is `name?: string` but the doc constrains it to a multi-segment path like `projects/{project_id}/branches/{branch_id}`. There is a separate `branchId` / `catalogId` / `databaseId` / `endpointId` / `projectId` / `roleId` field in each status sub-type. Caller has to read JSDoc to know which to use. - **Category:** 1 (vague), 19 (underspecified id), 6 (misleading — `name` reads as a human-readable name, actually a resource path). - **Suggested name:** `resourceName` / `fullName` / `resourcePath` for the path-style field; keep the short ID where present. - **Rationale:** `name` is the most ambiguous field name possible. -### 20. `Branch.parent` — string-typed parent path — `src/v1/model.ts:765` -- **Why weird:** `parent?: string` doc'd as "The project containing this branch (API resource hierarchy). Format: `projects/{project_id}`". Generic name; the type doesn't enforce the format. Same pattern repeats on `Database.parent` (1111), `Endpoint.parent` (1340), `Role.parent` (2259), `CreateBranchRequest.parent`, `CreateDatabaseRequest.parent`, etc. +### 13. `Branch.parent` — string-typed parent path — `src/v1/model.ts:703` +- **Why weird:** `parent?: string` doc'd as "The project containing this branch (API resource hierarchy). Format: `projects/{project_id}`". Generic name; the type doesn't enforce the format. Same pattern repeats on `Database.parent` (1023), `Endpoint.parent` (1191), `Role.parent` (1776), `CreateBranchRequest.parent`, `CreateDatabaseRequest.parent`, etc. - **Category:** 1 (vague), 15 (generic), 19 (underspecified — what kind of parent?). - **Suggested name:** `projectName` / `branchName` / specific to the parent type. Or `parentResourceName`. - **Rationale:** Parents differ per child type; `parent` is too generic. -### 21. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:798-824` +### 14. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:736-762` - **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. - **Category:** 16 (type allows `false` but spec rejects it). - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 22. `BranchSpec.isProtected` vs `BranchStatus.isProtected` vs `BranchStatus.default` — same struct, two booleans — `src/v1/model.ts:791, 838, 840` +### 15. `BranchStatus.default` — reserved-word collision — `src/v1/model.ts:776` - **Why weird:** `BranchStatus.default: boolean | undefined` field clashes with the JS `default` keyword in `import { default } from …` contexts. While not a reserved word in object-property position, it's syntactically irritating and a JS lint hot spot. - **Category:** 10 (reserved-word collision), 1 (vague — `default` of what?). - **Suggested name:** `isDefault: boolean` (matches sibling `isProtected`). - **Rationale:** `branch.default = true` reads weirdly; `branch.isDefault = true` aligns with `branch.isProtected`. -### 23. `createDatabaseIfMissing` field on the catalog spec — `src/v1/model.ts:918` -- **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF MISSING`). Same as `database` audit #30 (`createDatabaseIfNotExists`) but with the variant wording "If Missing". Inconsistent with `database` package's "If Not Exists". +### 16. `createDatabaseIfMissing` field on the catalog spec — `src/v1/model.ts:856` +- **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF MISSING`). Same as `database` audit #31 (`createDatabaseIfNotExists`) but with the variant wording "If Missing". Inconsistent with `database` package's "If Not Exists". - **Category:** 14 (SQL-style name), 7 (verbose), 17 (inconsistent with sister package's `createDatabaseIfNotExists`). - **Suggested name:** `ensureDatabaseExists` or `autoCreateDatabase`. - **Rationale:** Two packages, two variants of the same SQL-DDL leak. -### 24. Every status sub-type duplicates the parent resource name on its id field — `src/v1/model.ts:952, 1164, 859, 1516, 2220, 2358` -- **Why weird:** Each status type has `Id` (`catalogId`, `databaseId`, `branchId`, `endpointId`, `projectId`, `roleId`) inside a status struct that already lives on the parent resource. Read site `catalog.status.catalogId` repeats "catalog" twice. JSDoc on every field is identical boilerplate: "The short identifier of the X, suitable for showing to the users." +### 17. Every status sub-type duplicates the parent resource name on its id field — `src/v1/model.ts:797, 890, 1076, 1358, 1743, 1875` +- **Why weird:** Each status type has `Id` (`branchId`, `catalogId`, `databaseId`, `endpointId`, `projectId`, `roleId`) inside a status struct that already lives on the parent resource. Read site `catalog.status.catalogId` repeats "catalog" twice. JSDoc on every field is identical boilerplate: "The short identifier of the X, suitable for showing to the users." - **Category:** 7 (verbose), 17 (boilerplate JSDoc), 20 (type-suffix tautology). - **Suggested name:** `id: string` (the wrapping type name is already the resource). - **Rationale:** `catalog.status.catalogId` is "catalog status catalog id" — verbose. -### 25. `ComputeInstance.computeInstanceId` field — `src/v1/model.ts:965` -- **Why weird:** Self-tautology: `ComputeInstance.computeInstanceId`. Three `compute`/`instance` repetitions in a single member reference. -- **Category:** 20 (type-suffix tautology), 7 (verbose). -- **Suggested name:** `id: string` or just `computeId`. -- **Rationale:** Same as #24 but more egregious because both the type and field repeat both words. - -### 26. `ComputeInstance.computeHost` — `src/v1/model.ts:973` -- **Why weird:** `computeHost` is a `string` that's actually a hostname. "Host" already means hostname; the "compute" qualifier is redundant (we're already inside `ComputeInstance`). -- **Category:** 20 (type-prefix tautology), 7 (verbose). -- **Suggested name:** `host: string` (or `hostname`). -- **Rationale:** Same as #24. - -### 27. `ComputeInstance.role` field is typed as a compute-type enum, not a Postgres role — `src/v1/model.ts:971` -- **Why weird:** Field is `role` but its type is the compute-type enum, not the Postgres `Role` resource. Two unrelated concepts (Postgres `Role` and the compute "role" classifier) share the field name inside the same package. -- **Category:** 6 (misleading — `role` here is *not* a Postgres role), 12 (duplicate concept — `Role` vs `ComputeInstance.role`). -- **Suggested name:** `kind` or `computeRole`. -- **Rationale:** A field named `role` inside a package that *also* has a `Role` type is asking for trouble. - -### 28. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:991, 993` +### 18. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:907, 909` - **Why weird:** `CreateBranchRequest` has `parent`, `branchId`, `branch`, `replaceExisting`. `branchId` is the path-component id; `branch.name` (inside `Branch`) is the full resource path; `branch` is the body. Three fields all involved in identifying the branch. - **Category:** 17 (inconsistency — same operation, three id-like fields), 19 (underspecified id semantics). - **Suggested name:** Document the relationship clearly in JSDoc; or accept just `branch: Branch` and derive the id from `branch.name`. - **Rationale:** Same shape repeats on `CreateCatalogRequest`, `CreateDatabaseRequest`, `CreateEndpointRequest`, `CreateProjectRequest`, `CreateRoleRequest`, `CreateSyncedTableRequest`. Caller must read multiple field docs to know which ID to set. -### 29. `CreateBranchRequest.replaceExisting` / `CreateEndpointRequest.replaceExisting` — request-shaped name on a create call — `src/v1/model.ts:995, 1043` +### 19. `CreateBranchRequest.replaceExisting` / `CreateEndpointRequest.replaceExisting` — request-shaped name on a create call — `src/v1/model.ts:911, 959` - **Why weird:** `replaceExisting?: boolean` on a `Create*` request is essentially "upsert mode". Doc: "If true, update the branch if it already exists instead of returning an error." Many SDKs call this `upsert: true` or `ifExists: 'update'`. Verb is also imperative on a request body. - **Category:** 17 (inconsistent — `create` verb + `replaceExisting` flag conflate two operations), 1 (vague — "replace" how?). - **Suggested name:** `upsert: boolean` or `mode: 'create' | 'upsert'`. - **Rationale:** "Create-or-update" is a common API pattern that deserves a clearer name. -### 30. `Database.parent` is a branch path, `Database.spec.role` is a role path, `Database.status.role` is *also* a role path — `src/v1/model.ts:1111, 1132, 1151` +### 20. `Database.parent` is a branch path, `Database.spec.role` is a role path, `Database.status.role` is *also* a role path — `src/v1/model.ts:1023, 1044, 1063` - **Why weird:** Two `role` fields on the spec and status sub-structs, both holding full resource paths like `projects/{}/branches/{}/roles/{}`. `Database.spec.role` is the *desired owner role*; `Database.status.role` is the *observed owner role*. Doc clarifies but the field-name overlap is jarring. - **Category:** 19 (underspecified id — `role` is actually a role resource path), 1 (vague — `role` could be many things). - **Suggested name:** `ownerRole` or `ownerRoleName`. Use the same name on spec and status. - **Rationale:** Inside a `Database` struct, a bare `role: string` reads as "what role does this database have" — but it's specifically the *owner* role. -### 31. `postgresDatabase` field appears on both the database spec and status sub-types — `src/v1/model.ts:1142, 1153` +### 21. `postgresDatabase` field appears on both the database spec and status sub-types — `src/v1/model.ts:1054, 1065` - **Why weird:** `Database.spec.postgresDatabase` and `Database.status.postgresDatabase` repeat "database" three times in one member access — the wrapper type is already `Database`. - **Category:** 20 (type-suffix tautology), 7 (verbose). - **Suggested name:** `pgName` / `pgIdentifier` or just `name` (with a JSDoc note: "matches the Postgres database identifier"). -- **Rationale:** Same as #24, #25, #26. +- **Rationale:** Same as #17. -### 32. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1100, 1142` +### 22. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` - **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. - **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). - **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). - **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. -### 33. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:269-313`, `model.ts:1023` +### 23. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` - **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. - **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). - **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. - **Rationale:** Three identifier slots is too many. -### 34. `DatabaseCredential.token: string` carries no doc on format — `src/v1/model.ts:1169` +### 24. `DatabaseCredential.token: string` carries no doc on format — `src/v1/model.ts:1081` - **Why weird:** "The OAuth token that can be used as a password when connecting to a database." Plain `string`. Sibling `expireTime: Temporal.Instant` does carry a type. The token doc doesn't say whether it's a JWT, opaque, format `:`, etc. Same issue exists in `database/v1.DatabaseCredential.token`. - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `accessToken` (and document the format/lifetime in JSDoc). - **Rationale:** Tokens carry semantics; consumers need to know the format. -### 35. `Endpoint.endpointType` field of type `EndpointType` — `src/v1/model.ts:1428` +### 25. `Endpoint.endpointType` field of type `EndpointType` — `src/v1/model.ts:1272` - **Why weird:** `endpoint.endpointType` is type-suffix tautology again: three "endpoint"s. The field of type `EndpointType` could just be `type` since the surrounding type is `Endpoint`. - **Category:** 20 (type-suffix tautology), 7 (verbose). - **Suggested name:** `type: EndpointType` (or `kind`). -- **Rationale:** Same as #25. +- **Rationale:** Same as #17. -### 36. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1430, 1435` +### 26. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` - **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. - **Category:** 5 (cryptic abbreviation), 1 (vague suffix). - **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. - **Rationale:** "CU" is Lakebase-internal slang. -### 37. `EndpointGroupSpec.min` / `max` with `min === max` constraint — `src/v1/model.ts:1356, 1362` +### 27. `EndpointGroupSpec.min` / `max` with `min === max` constraint — `src/v1/model.ts:1207, 1213` - **Why weird:** Two bare fields `min: number` / `max: number` (and `enableReadableSecondaries`) on a group spec. JSDoc says "Currently, this must be equal to max" — meaning callers must set min === max. Type system doesn't enforce; bare `min`/`max` doesn't suggest "group size". - **Category:** 1 (vague), 16 (type contradicts spec — allows min ≠ max). - **Suggested name:** `size: number` (until min ≠ max becomes supported, then introduce `minSize`/`maxSize`). - **Rationale:** Pseudo-flexibility leaks proto future-proofing. -### 38. `EndpointHosts` — type holds 4 hostname fields — `src/v1/model.ts:1390-1409` -- **Why weird:** Fields are `host` (generic), `readOnlyHost`, `readWritePooledHost`, `readOnlyPooledHost`. The first is "the hostname"; the others narrow by direction/pooling. `host` reads as "the only host" but is just *one* of four. JSDoc clarifies but the field name doesn't. -- **Category:** 1 (vague — `host` is the catch-all), 15 (generic). -- **Suggested name:** `primaryHost` / `readOnlyHost` / `readWritePooledHost` / `readOnlyPooledHost` (i.e. give the first one a qualifier). -- **Rationale:** Reader doesn't know which is "the" host. - -### 39. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1449-1468` -- **Why weird:** Same pattern as #21 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. -- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #21). +### 28. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` +- **Why weird:** Same pattern as #14 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. +- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #14). - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. -- **Rationale:** Same as #21. +- **Rationale:** Same as #14. -### 40. `EndpointSettings.pgSettings: Record` field — `src/v1/model.ts:1417` +### 29. `EndpointSettings.pgSettings: Record` field — `src/v1/model.ts:1261` - **Why weird:** `pgSettings` is a map of Postgres GUC settings (e.g. `{ work_mem: '4MB' }`). Generic value type `string`. No validation. Field name `pgSettings` is itself ambiguous — could be any kind of setting. - **Category:** 14 (proto map-entry shape leaks into TS), 1 (vague — `pgSettings` could be any kind of setting). - **Suggested name:** `postgresGucSettings: Record` (more specific). - **Rationale:** Field name should encode the domain (Postgres GUC parameters). -### 41. `ForwardEtlConfig.workspaceId: number` typed as integer — `src/v1/model.ts:1522` -- **Why weird:** `workspaceId` is a `number` (also see `ForwardEtlConfig.createTimeMillis` — same numeric type for two unrelated concepts). Databricks workspace IDs are 64-bit integers — TS `number` can't represent the full int64 range above 2^53. Should be `bigint` or string. -- **Category:** 16 (field type contradicts domain — int64 wire vs JS number). -- **Suggested name:** `workspaceId: string` (or `bigint`). -- **Rationale:** Same precision pitfall as Java's `Long` going to JSON. - -### 42. `GenerateDatabaseCredentialRequest.endpoint` field "not yet supported" — `src/v1/model.ts:1595-1598` -- **Why weird:** Field doc says "This field is not yet supported." Field is exposed in the public TS type without an `@deprecated` or `@unsupported` JSDoc marker. -- **Category:** 6 (misleading — looks usable but isn't). -- **Suggested name:** Mark with `@deprecated` JSDoc and/or rename to `endpointReserved`. -- **Rationale:** Same as `database` audit #56. - -### 43. `GenerateDatabaseCredentialRequest.expiration` discriminated union — `src/v1/model.ts:1610-1627` -- **Why weird:** Same `oneof` pattern as #21 — `ttl` or `expireTime`. But here `noExpiry` doesn't exist; just two variants. The variant order in the union is `ttl` then `expireTime`, but on `BranchSpec.expiration` (#21) it's `expireTime` then `ttl`. Inconsistent variant ordering within the same package. -- **Category:** 17 (inconsistent variant ordering across two siblings). -- **Suggested name:** Standardise order across both unions. -- **Rationale:** Minor but a generator/consistency check would catch it. - -### 44. `InitialBranchSpec` / `InitialDatabaseSpec` / `InitialEndpointSpec` / `InitialRoleSpec` — 4 "Initial*Spec" types duplicate the corresponding `Spec` — `src/v1/model.ts:1734, 1746, 1757, 1776` -- **Why weird:** Four types named `InitialSpec`, each carrying the same field set as the corresponding `Spec`. The `Initial` prefix is documentation, not semantics — these are spec values for the *initial* default resources created with a project. `InitialRoleSpec` has nearly identical body to the role spec type (5 of 5 fields match). Duplicating the shape per-context multiplies the public surface. -- **Category:** 12 (duplicate concept). -- **Suggested name:** Use the regular `Spec` types directly with a JSDoc note on `Project.initialBranchSpec` saying "use a `BranchSpec` value here; it applies only to the initial default branch". -- **Rationale:** Doubles the type count for a docs-only distinction. - -### 45. `NewPipelineSpec` (top-level) vs the comment "Specification for creating a new pipeline" — `src/v1/model.ts:1963` -- **Why weird:** Type name carries the verb "new" (`NewPipelineSpec`). Reads as "the new pipeline spec" (a noun phrase about a *new* type of pipeline) or "spec for a new pipeline" (the actual intent). Java/C# call these `CreatePipelineSpec` or `PipelineCreate`. The type holds 4 fields (`storageCatalog`, `storageSchema`, `budgetPolicyId`, `pipelineChannel`). -- **Category:** 13 (verb-tense — `new` as adjective for a type name), 6 (misleading). -- **Suggested name:** `PipelineCreationSpec` or `NewPipelineConfig`. -- **Rationale:** Type names with embedded verbs are awkward; consider `Spec` only when the type *configures* something. - -### 46. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:2014` -- **Why weird:** Plain `Record`. The 22 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1862-1865` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. +### 30. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #39 +_Reserved._ + +### 31. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` +- **Why weird:** Plain `Record`. The 21 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1524-1533` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. - **Category:** 15 (generic), 16 (loose typing). - **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. -- **Rationale:** Same root cause as #14 — opaque records on the public surface. +- **Rationale:** Same root cause as #7 — opaque records on the public surface. -### 47. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:2027-2038` -- **Why weird:** Variant `response` carries `Record` (line 2036). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) +### 32. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` +- **Why weird:** Variant `response` carries `Record` (line 1597). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) - **Category:** 16 (asymmetric typing), 15 (generic on success arm). -- **Suggested name:** Same as #46 — generic `Operation` with both arms typed. -- **Rationale:** Same as #14, #46. +- **Suggested name:** Same as #31 — generic `Operation` with both arms typed. +- **Rationale:** Same as #7, #31. -### 48. `Project.spec` / `Project.status` / `Project.initialBranchSpec` / `Project.initialRoleSpec` / `Project.initialDatabaseSpec` / `Project.initialEndpointSpec` — six spec/status fields on one type, four are write-only — `src/v1/model.ts:2054-2095` -- **Why weird:** Single `Project` type carries spec + status + four initial-* sub-specs. The four `initial*` fields are create-time-only inputs but exposed on the response type too — a read-flow consumer sees four fields that are always empty. +### 33. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` +- **Why weird:** `Project` carries an `initialEndpointSpec` field that is a create-time-only input but exposed on the response type too — a read-flow consumer sees a field that is typically empty after project creation. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). -- **Suggested name:** Hoist the `initial*` fields onto `CreateProjectRequest` only (where they belong); leave `Project` to spec/status. -- **Rationale:** Same as `database` audit #11 — input/output shape confusion. +- **Suggested name:** Hoist the `initialEndpointSpec` onto `CreateProjectRequest` only (where it belongs); leave `Project` to spec/status. +- **Rationale:** Same as `database` audit #12 — input/output shape confusion. -### 49. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:2098`, `database:206` +### 34. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` - **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. - **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). - **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. - **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. -### 50. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:2148, 2191` -- **Why weird:** Doc says "The major Postgres version number. Supported versions are 16 and 17." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. +### 35. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` +- **Why weird:** Doc says "The major Postgres version number. The set of supported versions may vary; consult the API documentation for currently accepted values." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. - **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). - **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. - **Rationale:** Aligns documented constraints with the type system. -### 51. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:2150, 2193` +### 36. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` - **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. - **Category:** 17 (inconsistent with sister package). - **Suggested name:** Pick one convention across the two packages. - **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. -### 52. `ProjectSpec.workspaceKeyEncrypted: boolean` — `src/v1/model.ts:2170` -- **Why weird:** Field doc admits the flag is temporary: "Since we need to do an end to end perf bench using BSS API to A/B test the performance impact of CMK encryption, we need to be able to control this flag in the API. This flag will be removed once we find a better way…" Flag is exposed on the public SDK surface. -- **Category:** 14 (internal-jargon leak — "BSS API", "CMK"), 6 (misleading — flag is benchmark-temporary). -- **Suggested name:** Either hide behind an internal beta-flag mechanism, or rename to `workspaceCmkEnabled` and document it neutrally. -- **Rationale:** Benchmark scaffolding on the public surface. - -### 53. `ProjectSpec.enablePgNativeLogin` / `ProjectStatus.enablePgNativeLogin` — request-shaped verb on response — `src/v1/model.ts:2172, 2208` -- **Why weird:** Same problem as `database` audit #25: `enableX: boolean` reads as imperative on a response type. `ProjectStatus.enablePgNativeLogin` should read "is PG native login enabled". +### 37. `ProjectSpec.enablePgNativeLogin` / `ProjectStatus.enablePgNativeLogin` — request-shaped verb on response — `src/v1/model.ts:1704, 1732` +- **Why weird:** Same problem as `database` audit #26: `enableX: boolean` reads as imperative on a response type. `ProjectStatus.enablePgNativeLogin` should read "is PG native login enabled". - **Category:** 6 (misleading verb form), 17 (input/output asymmetry). - **Suggested name:** Input: `enablePgNativeLogin`. Output: `pgNativeLoginEnabled`. -- **Rationale:** Same as `database` audit #25. +- **Rationale:** Same as `database` audit #26. -### 54. `RequestedResource.resourceName` discriminated union with `unspecifiedResourceName` and `tableName` — `src/v1/model.ts:2237-2246` -- **Why weird:** Same as `database` audit #16 — discriminated union whose `unspecifiedResourceName` variant exists only because the proto generator emits sentinel branches. `tableName` is the only useful variant. -- **Category:** 1 (vague), 6 (misleading — `unspecifiedResourceName` exists in TS but shouldn't). -- **Suggested name:** Top-level `RequestedResource = {kind: 'table', tableName: string}`. -- **Rationale:** Same as `database` audit #16. - -### 55. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:2419` -- **Why weird:** Same as `database` audit #35: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. +### 38. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` +- **Why weird:** Same as `database` audit #36: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. -- **Rationale:** Same as `database` audit #35. +- **Rationale:** Same as `database` audit #36. -### 56. Synced-table spec fields `acceleratedSync` / `createDatabaseObjectsIfMissing` / `extraIndexDefinitions` / `extraColumnDefinitions` / `typeOverrides` — same fields, same issues as `database` package — `src/v1/model.ts:2447, 2434, 2454, 2458, 2452` -- **Why weird:** Identical to `database` audit findings #37–#42. Won't re-state at length; flag that the duplication exists across both packages with identical naming. +### 39. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` +- **Why weird:** Identical to `database` audit findings on synced-table-spec naming. Won't re-state at length; flag that the duplication exists across both packages with identical naming. Other related fields (`acceleratedSync`, `extraIndexDefinitions`, `extraColumnDefinitions`, `typeOverrides`) were removed during regeneration; only the `createDatabaseObjectsIfMissing` "If Missing" pattern remains here, matching `database` package's similar wording. - **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). - **Suggested name:** Same suggestions as `database` audit. - **Rationale:** Two SDKs, same problems. -### 57. `Table` (non-synced) — generic single-word type — `src/v1/model.ts:2586` -- **Why weird:** `Table` is the most generic possible name. Doc: "Table represents a non-synced database table in a Lakebase project. Unlike SyncedTable, this does not have a data synchronization pipeline." Sibling `SyncedTable` has the "Synced" qualifier; this one should have "NonSynced" or "Native" qualifier. Bare `Table` is also confusable with UC `Table`, online `Table`, etc. -- **Category:** 1 (vague/generic), 12 (duplicate concept — `Table` exists in multiple SDK packages). -- **Suggested name:** `LakebaseTable` or `NativeTable` or `PgTable`. -- **Rationale:** Same as #17. - -### 58. `Table.database` / `Table.project` / `Table.branch` — three string fields, each a different resource path — `src/v1/model.ts:2594-2598` -- **Why weird:** Three sibling string fields, each holding a different multi-segment path. `database` is `projects/{}/branches/{}/databases/{}`, `project` is `projects/{}`, `branch` is `projects/{}/branches/{}`. Two of them (`project` and `branch`) are prefixes of `database`. No discriminator. -- **Category:** 19 (underspecified ids), 1 (vague — bare `project` could be many things). -- **Suggested name:** `databaseName` / `projectName` / `branchName` (and prefix each with the resource type the path identifies). -- **Rationale:** Three resource paths under generic field names. - -### 59. `Table.tableServingUrl` / `DatabaseTable.tableServingUrl` (in `database` package) — same field, same issue — `src/v1/model.ts:2600` -- **Why weird:** `tableServingUrl` is opaque (see `database` audit #33). "Serving" is feature-store jargon for "REST endpoint for reads". On a Postgres table, the meaning is "REST API to read this table". Field doc: "REST API URL for serving data from this table." -- **Category:** 1 (vague), 6 (misleading — `Serving` is feature-store terminology). -- **Suggested name:** `restEndpointUrl` / `apiEndpointUrl`. -- **Rationale:** Same as `database` audit #33. - -### 60. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2629` +### 40. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` - **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. - **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). - **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. - **Rationale:** AIP `FieldMask` is an industry pattern, but it should not be the only update affordance. -### 61. `DeleteForwardEtlConfigurationResponse.deletedConfigs` / `deletedMappings` — count fields without singular form — `src/v1/model.ts:1247-1250` -- **Why weird:** Field is `deletedConfigs: number | undefined` — a count, not a list. The name reads as a plural array (`deletedConfigs: Config[]`). JSDoc clarifies "Number of configuration rows deleted (0 or 1)". -- **Category:** 9 (singular/plural mismatch — plural name on a `number`), 1 (vague). -- **Suggested name:** `deletedConfigCount` / `deletedMappingCount`. -- **Rationale:** Reader sees `deletedConfigs` and expects an array. - -### 62. `getOperation` / `Operation.name` — operation name is a resource path — `src/v1/client.ts:1109`, `model.ts:1699` +### 41. `getOperation` / `Operation.name` — operation name is a resource path — `src/v1/client.ts:856`, `model.ts:1569` - **Why weird:** `getOperation({name: ...})` takes a `string` that is actually a path like `operations/{unique_id}`. The doc on `Operation.name` says "If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`." But it doesn't validate. - **Category:** 19 (underspecified id), 6 (misleading — `name` reads like a label). - **Suggested name:** `operationResourceName` / `operationPath` / `id`. -- **Rationale:** Same as #19. - -### 63. `createTable` / `deleteTable` / `getTable` — operate on `Table`, not the synced version — `src/v1/client.ts:502, 826, 1207` -- **Why weird:** Method names `createTable` are generic; consumer must read the JSDoc to know they target the `Table` (non-synced) resource. Sibling `createSyncedTable` is explicit. `Table` operations are CRUD over native PG tables; the method name should signal that. -- **Category:** 1 (vague — `createTable` is generic), 12 (duplicate concept — also `CreateDatabaseTableRequest` in `database` package). -- **Suggested name:** `createNativeTable` / `createLakebaseTable` (mirror the `createSyncedTable` pattern). -- **Rationale:** Lakebase has two table flavors; both deserve explicit method names. +- **Rationale:** Same as #12. ## Low severity -### 64. `BranchSpec.sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` — `src/v1/model.ts:785, 787, 789` -- **Why weird:** Three sibling fields on `BranchSpec`. `sourceBranch` is a path; `sourceBranchLsn` and `sourceBranchTime` are alternative cutover specifiers (one or the other). Bare `branchTime` repeats from `database/v1.DatabaseInstanceRef.branchTime` (see `database` audit #28). +### 42. `BranchSpec.sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` — `src/v1/model.ts:723, 725, 727` +- **Why weird:** Three sibling fields on `BranchSpec`. `sourceBranch` is a path; `sourceBranchLsn` and `sourceBranchTime` are alternative cutover specifiers (one or the other). Bare `branchTime` repeats from `database/v1.DatabaseInstanceRef.branchTime` (see `database` audit #29). - **Category:** 1 (vague — `branchTime` is a cutover instant, not a time-of-branch). - **Suggested name:** `sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` are OK; consider `sourceBranchAtLsn` / `sourceBranchAtTime` for clarity. -- **Rationale:** Same as `database` audit #28. +- **Rationale:** Same as `database` audit #29. -### 65. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:805, 850` +### 43. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:743, 788` - **Why weird:** Field name `expireTime` appears twice: once as a discriminated-union variant on `BranchSpec` (input), once as a top-level field on `BranchStatus` (output). Reader has to track that the input shape collapses `expireTime`/`ttl`/`noExpiry` to a single output value `expireTime`. - **Category:** 17 (input/output shape mismatch). - **Suggested name:** Document the asymmetry in JSDoc; or expose the same union shape on output. - **Rationale:** Generator-driven asymmetry. -### 66. `BranchSpec.ttl: Temporal.Duration` and `BranchSpec.expireTime` — `ttl` is a duration, `expireTime` is a timestamp — `src/v1/model.ts:813, 805` +### 44. `BranchSpec.ttl: Temporal.Duration` and `BranchSpec.expireTime` — `ttl` is a duration, `expireTime` is a timestamp — `src/v1/model.ts:751, 743` - **Why weird:** `ttl` (time-to-live) and `expireTime` are sibling variants. `ttl` is duration-shaped; `expireTime` is timestamp-shaped. Bare `ttl` is a Unix-cache-style abbreviation. - **Category:** 5 (cryptic abbreviation — `ttl`). - **Suggested name:** `lifetime: Duration` or `expireAfter: Duration`. - **Rationale:** `TTL` is widely understood but expansion improves grep-ability. -### 67. `CreateBranchRequest.replaceExisting` vs `DeleteBranchRequest.allowMissing` — verb-tense asymmetry across CRUD — `src/v1/model.ts:995, 1200` -- **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete uses `allowMissing: boolean` (tolerant). Two different conventions for the "if it does/doesn't exist" behaviour. Update has no such field; Get doesn't either. Inconsistent. +### 45. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` +- **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete now uses `purge: boolean` only (`allowMissing` field removed in regeneration). Mismatched conventions for "if it does/doesn't exist" remain. - **Category:** 17 (inconsistent action verbs across CRUD). - **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. - **Rationale:** Inconsistent options across CRUD operations is a small papercut. -### 68. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1195` -- **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete. Soft deletion (purge=false) is not supported yet." So the value of `false` is rejected. Same `purge` field on `DeleteProjectRequest` (line 1263). -- **Category:** 16 (type allows `false` but spec rejects), 6 (misleading — purge implies cleanup, not the *only* delete mode). -- **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. Add `@deprecated` until soft-delete is supported. +### 46. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` +- **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete." Same `purge` field on `DeleteProjectRequest` (line 1142). +- **Category:** 16 (boolean modeling a future 3-state field), 6 (misleading — purge implies cleanup, not the *only* delete mode). +- **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. - **Rationale:** Boolean toggle for a future-3-state field. -### 69. `DeleteForwardEtlConfigurationRequest` vs `DisableForwardEtlRequest` — two near-identical types — `src/v1/model.ts:1229, 1306` -- **Why weird:** Both types carry `parent`, `tenantId`, `timelineId`, `pgDatabaseOid`, `pgSchemaOid`. Doc on `DeleteForwardEtlConfigurationRequest`: "Unlike DisableForwardEtl, this permanently removes the config and mapping rows." The distinction is `Delete` (hard) vs `Disable` (soft) — same boolean-toggle pattern as `purge` (#68) but split into two types. -- **Category:** 12 (duplicate concept), 17 (different verbs for the same shape). -- **Suggested name:** Merge into one request type with a `mode: 'delete' | 'disable'` field. -- **Rationale:** Two methods carrying identical fields suggests one method with a flag. - -### 70. `ForwardEtlMetadata.databases` / `schemas` — bare plurals — `src/v1/model.ts:1554, 1556` -- **Why weird:** `databases: ForwardEtlDatabase[]` and `schemas: ForwardEtlSchema[]` — bare plurals. Inside a `ForwardEtl` context, these are PG OID-to-name maps, not regular databases/schemas. Reader expects `Database` (the SDK type) but gets `ForwardEtlDatabase` (a name+OID pair). -- **Category:** 1 (vague — `databases` is too generic in a `ForwardEtl` context), 17 (`Database` SDK type vs `ForwardEtlDatabase` ad-hoc type). -- **Suggested name:** `databaseOids` / `schemaOids` (matches the underlying domain), or keep plurals but document. -- **Rationale:** Mild — context disambiguates. - -### 71. `ForwardEtlTableMapping.lastSyncedLsn: string` — LSN as bare string — `src/v1/model.ts:1582` -- **Why weird:** Postgres LSN is `XX/YY` string. Field name uses `Lsn` abbreviation without expansion. Sibling `pgTableOid` already a Postgres-internal. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `lastSyncedLogSequenceNumber` (or `walLsn`). -- **Rationale:** Same as `database` audit #27. - -### 72. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1593` -- **Why weird:** Same as `database` audit #53 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". +### 47. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` +- **Why weird:** Same as `database` audit #54 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** Same as `database` audit #53 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. -- **Rationale:** Same as `database` audit #53. +- **Suggested name:** Same as `database` audit #54 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. +- **Rationale:** Same as `database` audit #54. -### 73. `GenerateDatabaseCredentialRequest.groupName: string` — `src/v1/model.ts:1604` -- **Why weird:** Doc: "Databricks workspace group name. When provided, credentials are generated with permissions scoped to this group." Bare `groupName` reads as a Postgres role name; actually a Databricks workspace group. Field is sibling to `claims` and `endpoint`; the relationship between them isn't spelled out (do you set all three? one? two?). -- **Category:** 1 (vague — `groupName` could be PG or DB workspace), 17 (multi-field request without clear mutex docs). -- **Suggested name:** `workspaceGroupName`. -- **Rationale:** Disambiguate from Postgres role names. - -### 74. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:2020` -- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1885`). +### 48. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` +- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1552`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. - **Rationale:** Tri-state booleans always confuse callers. -### 75. `Project.deleteTime` / `Project.purgeTime` — two delete-related timestamps — `src/v1/model.ts:2067, 2072` +### 49. `Project.deleteTime` / `Project.purgeTime` — two delete-related timestamps — `src/v1/model.ts:1629, 1634` - **Why weird:** `deleteTime` = "when soft-deleted"; `purgeTime` = "when scheduled for permanent deletion". Bare verbs `delete` / `purge` are similar; the distinction matters for the consumer but the field names alone don't communicate the lifecycle. - **Category:** 1 (vague), 6 (misleading — `purge` could mean "purged at" or "scheduled to purge"). - **Suggested name:** `softDeletedAt` / `scheduledPurgeAt`. - **Rationale:** Lifecycle-related fields benefit from clearer past/future tense. -### 76. `ProjectStatus.syntheticStorageSizeBytes` — "synthetic" qualifier — `src/v1/model.ts:2199` +### 50. `ProjectStatus.syntheticStorageSizeBytes` — "synthetic" qualifier — `src/v1/model.ts:1724` - **Why weird:** `syntheticStorageSizeBytes` — what's "synthetic" about storage? Doc says "The current space occupied by the project in storage." JSDoc doesn't explain "synthetic". Likely Lakebase internal billing concept. - **Category:** 1 (vague), 14 (internal-jargon leak). - **Suggested name:** `storageSizeBytes` or `billingStorageSizeBytes`. - **Rationale:** Internal-jargon leak. -### 77. `ProjectStatus.computeLastActiveTime` — `src/v1/model.ts:2201` -- **Why weird:** Doc: "The most recent time when any endpoint of this project was active." Field name is `compute` + `lastActiveTime` — reads as "the compute last active time" with an implicit possessive. Awkward grammar. -- **Category:** 1 (vague), 17 (irregular grammar). -- **Suggested name:** `lastComputeActiveTime` or `lastActivityTime` or `lastEndpointActivityTime`. -- **Rationale:** Word ordering in compound field names matters for grep-ability. - -### 78. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:797, 803, 811, 820, 1447, 1455, 1465` +### 51. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:734, 741, 749, 758, 1291, 1299, 1308, 1656, 1665` - **Why weird:** JSDoc references update mask in snake_case (e.g. "When updating this field, use `spec.expiration` in the update_mask"). Update mask field on the request is `updateMask: FieldMask<...>` (camelCase) but docs reference the wire-format name. Consumer reading the JSDoc and writing TS code has to translate. - **Category:** 17 (inconsistent — JSDoc snake_case, TS camelCase). - **Suggested name:** Use TS field name in JSDoc. - **Rationale:** Doc/code drift. -### 79. `ListBranchesRequest.showDeleted` / `ListProjectsRequest.showDeleted` — pair of duplicate optional flags — `src/v1/model.ts:1844, 1934` +### 52. `ListBranchesRequest.showDeleted` / `ListProjectsRequest.showDeleted` — pair of duplicate optional flags — `src/v1/model.ts:1456, 1515` - **Why weird:** Two structs carry identical `showDeleted?: boolean` with similar JSDoc. Not bad on its own, but the option name `showDeleted` is itself an imperative-shaped name on a request type (compare to `includeDeleted` or `deletedOnly`). - **Category:** 1 (vague — `show` is presentation-layer language for a server request). - **Suggested name:** `includeDeleted` or `includeSoftDeleted`. -- **Rationale:** Same as `database` audit #25 — request shapes prefer descriptive booleans over imperative ones. - -### 80. `listComputeInstances`'s doc reads "The parent, which owns the compute instances" — `src/v1/model.ts:1855` -- **Why weird:** `ListComputeInstancesRequest.parent` doc is sparse: "The parent, which owns the compute instances." No format given. Compare to sibling `ListBranchesRequest.parent` which specifies "Format: `projects/{project_id}`". -- **Category:** 6 (misleading — doc missing). -- **Suggested name:** Fix the doc; add the format. -- **Rationale:** Documentation copy-paste oversight. +- **Rationale:** Same as `database` audit #26 — request shapes prefer descriptive booleans over imperative ones. ## Observation -### 81. Method JSDoc inconsistency — `src/v1/client.ts` throughout +### 53. Method JSDoc inconsistency — `src/v1/client.ts` throughout - **Why weird:** Some methods have rich JSDoc ("Creates a new database branch in the project.", "Register a Postgres database in the Unity Catalog."). Others are terse ("Create a Database.", "Get a Database.", "List Databases."). Inconsistency in doc depth across CRUD methods of the same resource. - **Category:** Observation (doc quality, not naming). - **Suggested name:** Standardise to the richer template. - **Rationale:** Naming-adjacent. -### 82. `Operation` is a separate type, not a generic — `src/v1/model.ts:2002` -- **Why weird:** All 22 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#15) or reads `Operation.result.response` (untyped `Record`). +### 54. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` +- **Why weird:** All 21 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#8) or reads `Operation.result.response` (untyped `Record`). - **Category:** Observation (architecture, not naming per se). - **Suggested name:** `Operation` generic. -- **Rationale:** Connects #14, #15, #46, #47. - -### 83. The provisioning-state enum is exported from both `database` and `postgres` packages with identical members — `src/v1/model.ts:654`, `database/v1/model.ts:148` -- **Why weird:** Same enum, two packages, identical members. Reader importing both packages has to alias one. -- **Category:** Observation (cross-package duplication). -- **Suggested name:** Move to a shared `core/lakebase-common` or `core/enums`. -- **Rationale:** Related to #2. +- **Rationale:** Connects #7, #8, #31, #32. + +## Fixed + +- #2 (original) `postgres` and `database` packages overlap heavily — _reduced_; many shared types removed in regeneration but a substantial duplicate set remains (kept as new #2). Original line numbers obsolete. +- #4 (original) Four "State" enums share value vocabulary but use three different qualifier patterns (originally cited at `src/v1/model.ts:581, 628, 599, 654`): Superseded into new #4 — `ComputeInstance_ComputeState` and `NewPipelineSpec_PipelineChannel` were removed in regeneration on 2026-05-20; only three state enums (Branch/Endpoint/Provisioning) remain. +- #11 Forward ETL types use a Java/Kotlin-style adjective phrase (originally cited at `src/v1/model.ts:1229-1325`, `client.ts:670-882`): Fixed in regeneration on 2026-05-20 — all `ForwardEtl*` types (`DeleteForwardEtlConfigurationRequest`, `DisableForwardEtlRequest`, `ForwardEtlConfig`, `ForwardEtlDatabase`, `ForwardEtlMetadata`, `ForwardEtlSchema`, `ForwardEtlStatus`, `ForwardEtlTableMapping`, `GetForwardEtlMetadataRequest`, `GetForwardEtlStatusRequest`) and `deleteForwardEtlConfiguration`/`disableForwardEtl`/`getForwardEtlMetadata`/`getForwardEtlStatus` client methods are gone. +- #12 `ForwardEtlConfig.createTimeMillis` / `updateTimeMillis` (originally cited at `src/v1/model.ts:1538, 1540`): Fixed in regeneration on 2026-05-20 — `ForwardEtlConfig` removed entirely. +- #13 Forward ETL `pgDatabaseOid` / `pgSchemaOid` / `pgTableOid` (originally cited at `src/v1/model.ts:1240, 1242, 1317, 1319, 1528, 1530, 1578`): Fixed in regeneration on 2026-05-20 — all Forward ETL types removed. +- #14 `tenantId` / `timelineId` in Forward ETL request types (originally cited at `src/v1/model.ts:1236, 1238, 1313, 1315, 1524, 1526, 1679, 1681, 1692, 1694`): Fixed in regeneration on 2026-05-20 — Forward ETL types removed. +- #17 (original) `*Operation` classes mix verb prefix with noun suffix — superseded into new #8 (combined with the 21-class issue). +- #18 (original) `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` / `Table` / `ComputeInstance` — 9 generic top-level resource names: Superseded into new #10 — `Table` and `ComputeInstance` removed in regeneration on 2026-05-20; finding now covers the 7 remaining generic names. +- #26 `ComputeInstance.computeInstanceId` field (originally cited at `src/v1/model.ts:965`): Fixed in regeneration on 2026-05-20 — `ComputeInstance` type removed entirely. +- #27 `ComputeInstance.computeHost` (originally cited at `src/v1/model.ts:973`): Fixed in regeneration on 2026-05-20 — `ComputeInstance` removed. +- #28 `ComputeInstance.role` field is typed as a compute-type enum, not a Postgres role (originally cited at `src/v1/model.ts:971`): Fixed in regeneration on 2026-05-20 — `ComputeInstance` removed. +- #39 `EndpointHosts` — type holds 4 hostname fields (originally cited at `src/v1/model.ts:1390-1409`): Fixed in regeneration on 2026-05-20 — `EndpointHosts` now has only `host` and `readOnlyHost` (no `readWritePooledHost`/`readOnlyPooledHost`); the four-field tangle is gone, though a residual `host` vs `readOnlyHost` distinction remains, addressed by JSDoc on the simplified type. +- #42 `ForwardEtlConfig.workspaceId: number` (originally cited at `src/v1/model.ts:1522`): Fixed in regeneration on 2026-05-20 — `ForwardEtlConfig` removed. +- #43 `GenerateDatabaseCredentialRequest.endpoint` field "not yet supported" (originally cited at `src/v1/model.ts:1595-1598`): Fixed in regeneration on 2026-05-20 — the "not yet supported" disclaimer is gone; field now documents an active "endpoint resource name for which this credential will be generated" purpose. +- #44 `GenerateDatabaseCredentialRequest.expiration` discriminated union (originally cited at `src/v1/model.ts:1610-1627`): Fixed in regeneration on 2026-05-20 — the `expiration` discriminated union has been removed; only `claims` and `endpoint` fields remain. +- #45 `InitialBranchSpec` / `InitialDatabaseSpec` / `InitialEndpointSpec` / `InitialRoleSpec` (originally cited at `src/v1/model.ts:1734, 1746, 1757, 1776`): Fixed in regeneration on 2026-05-20 — `InitialBranchSpec`, `InitialDatabaseSpec`, `InitialRoleSpec` removed; only `InitialEndpointSpec` (a thin wrapper around `EndpointGroupSpec`) remains, and `Project` now exposes a single `initialEndpointSpec` field (see new #33). +- #46 `NewPipelineSpec` (originally cited at `src/v1/model.ts:1963`): Fixed in regeneration on 2026-05-20 — the type still exists at `model.ts:1544` but the `pipelineChannel` field (with its `NewPipelineSpec_PipelineChannel` enum) was removed, so the type is now a slim 3-field config (`storageCatalog`, `storageSchema`, `budgetPolicyId`); the verb-as-prefix concern was originally about `NewPipelineSpec` carrying internal `Pipeline_Channel` enum noise — the noise is gone. +- #49 (original) `Project.spec` / `Project.status` / `Project.initialBranchSpec` / `Project.initialRoleSpec` / `Project.initialDatabaseSpec` / `Project.initialEndpointSpec` (originally cited at `src/v1/model.ts:2054-2095`): Superseded into new #33 — only `initialEndpointSpec` remains as a write-only field exposed on read; the other three `initial*` fields were removed. +- #53 `ProjectSpec.workspaceKeyEncrypted: boolean` (originally cited at `src/v1/model.ts:2170`): Fixed in regeneration on 2026-05-20 — `workspaceKeyEncrypted` flag removed from `ProjectSpec`. +- #55 `RequestedResource.resourceName` discriminated union with `unspecifiedResourceName` and `tableName` (originally cited at `src/v1/model.ts:2237-2246`): Fixed in regeneration on 2026-05-20 — the `unspecifiedResourceName` variant is gone; only `tableName` remains as the discriminated union (single variant; the union effectively collapsed to `{$case: 'tableName', tableName: string}`). +- #57 Synced-table spec fields `acceleratedSync` / `extraIndexDefinitions` / `extraColumnDefinitions` / `typeOverrides` (originally cited at `src/v1/model.ts:2447, 2434, 2454, 2458, 2452`): Fixed in regeneration on 2026-05-20 — these synced-table fields were removed; only the `createDatabaseObjectsIfMissing` field remains and is captured in the new #39. +- #58 `Table` (non-synced) — generic single-word type (originally cited at `src/v1/model.ts:2586`): Fixed in regeneration on 2026-05-20 — `Table` type removed entirely. +- #59 `Table.database` / `Table.project` / `Table.branch` (originally cited at `src/v1/model.ts:2594-2598`): Fixed in regeneration on 2026-05-20 — `Table` removed. +- #60 `Table.tableServingUrl` / `DatabaseTable.tableServingUrl` (originally cited at `src/v1/model.ts:2600`): Fixed in regeneration on 2026-05-20 — `Table.tableServingUrl` removed alongside the `Table` type. +- #62 `DeleteForwardEtlConfigurationResponse.deletedConfigs` / `deletedMappings` (originally cited at `src/v1/model.ts:1247-1250`): Fixed in regeneration on 2026-05-20 — `DeleteForwardEtlConfigurationResponse` removed. +- #64 `createTable` / `deleteTable` / `getTable` (originally cited at `src/v1/client.ts:502, 826, 1207`): Fixed in regeneration on 2026-05-20 — the non-synced `Table` CRUD methods removed from `client.ts`; only `createSyncedTable`/`deleteSyncedTable`/`getSyncedTable` remain. +- #68 `CreateBranchRequest.replaceExisting` vs `DeleteBranchRequest.allowMissing` (originally cited at `src/v1/model.ts:995, 1200`): Superseded into new #45 — `DeleteBranchRequest.allowMissing` was removed in regeneration on 2026-05-20; only the `replaceExisting` vs `purge` mismatch remains. +- #70 `DeleteForwardEtlConfigurationRequest` vs `DisableForwardEtlRequest` (originally cited at `src/v1/model.ts:1229, 1306`): Fixed in regeneration on 2026-05-20 — both types removed. +- #71 `ForwardEtlMetadata.databases` / `schemas` (originally cited at `src/v1/model.ts:1554, 1556`): Fixed in regeneration on 2026-05-20 — `ForwardEtlMetadata` removed. +- #72 `ForwardEtlTableMapping.lastSyncedLsn: string` (originally cited at `src/v1/model.ts:1582`): Fixed in regeneration on 2026-05-20 — `ForwardEtlTableMapping` removed. +- #74 `GenerateDatabaseCredentialRequest.groupName: string` (originally cited at `src/v1/model.ts:1604`): Fixed in regeneration on 2026-05-20 — `groupName` field removed from `GenerateDatabaseCredentialRequest`. +- #78 `ProjectStatus.computeLastActiveTime` (originally cited at `src/v1/model.ts:2201`): Fixed in regeneration on 2026-05-20 — field removed from `ProjectStatus`. +- #81 `listComputeInstances`'s doc reads "The parent, which owns the compute instances" (originally cited at `src/v1/model.ts:1855`): Fixed in regeneration on 2026-05-20 — `ListComputeInstancesRequest` removed alongside `ComputeInstance`. +- #84 The provisioning-state enum is exported from both `database` and `postgres` packages with identical members (originally cited at `src/v1/model.ts:654`, `database/v1/model.ts:148`): Subsumed into new #2 — same cross-package overlap class; the enum still exists at `model.ts:610` but the broader duplicate-types finding now covers it. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md index c3e5c441..1ad40c3b 100644 --- a/.agent/naming-audit/qualitymonitor.md +++ b/.agent/naming-audit/qualitymonitor.md @@ -1,17 +1,21 @@ # Naming Audit: qualitymonitor +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `packages/qualitymonitor/src/v2/` **Versions audited:** v2 -**Inferred domain:** Quality monitoring on Unity Catalog objects (currently only `schema`). The package defines a single `QualityMonitor` entity that wraps `AnomalyDetectionConfig` (last-run telemetry plus excluded tables) and a list of `ValidityCheckConfiguration` arms (percent-null, range, uniqueness). A nested concept (`CustomCheckConfiguration` -> `CustomScalarCheck`) lets callers attach templated SQL checks with per-column matchers. Every operation is marked `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., this entire package is a deprecated shim that has been superseded by the `dataquality` package. -**Total weird names flagged:** 38 +**Inferred domain:** Quality monitoring on Unity Catalog objects (currently only `schema`). The package defines a single `QualityMonitor` entity that wraps `AnomalyDetectionConfig` (last-run telemetry plus excluded tables) and a list of `ValidityCheckConfiguration` arms (percent-null, range, uniqueness). Every operation is marked `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., this entire package is a deprecated shim that has been superseded by the `dataquality` package. +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 15 | +| High | 7 | +| Medium | 6 | | Low | 8 | -| Observation | 4 | +| Observation | 3 | ## CRITICAL: Two packages, same domain @@ -39,197 +43,119 @@ The singular-vs-plural naming gives the reader no hint that these are different - **Suggested name:** `QualityMonitorClient`. - **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but especially acute here because three sibling packages (this, `qualitymonitors`, `dataquality`) all expose `Client`. -### 3. `ListQualityMonitorRequest` / `ListQualityMonitorResponse` / `listQualityMonitor` — `src/v2/model.ts:92-100`, `src/v2/client.ts:152` +### 3. `ListQualityMonitorRequest` / `ListQualityMonitorResponse` / `listQualityMonitor` — `src/v2/model.ts:44-52`, `src/v2/client.ts:152` - **Why weird:** Singular noun on a list operation. The response holds `qualityMonitors?: QualityMonitor[]` (plural), and the wire path is `/api/2.0/quality-monitors` (plural) — every concrete signal is plural; only the type/method name uses the singular `QualityMonitor`. Same singular-on-list bug as `dataquality` finding #1. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListQualityMonitorsRequest` / `ListQualityMonitorsResponse` / `listQualityMonitors`. - **Rationale:** REST conventions, the package's own field naming (`qualityMonitors`), and the URL path all use plural. The singular form is generator template noise. -### 4. `QualityMonitor.objectType` + `QualityMonitor.objectId` — `src/v2/model.ts:109-113` (and copied into 4 request types) -- **Why weird:** `objectType` is a free-form `string` typed as values like `"schema"` (JSDoc says "Can be one of the following: schema." — one option in a one-element set is barely an enumeration). The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("the uuid of the request object. For example, schema id."). This is a stringly-typed sum type with one current arm. Five separate types (`QualityMonitor`, `DeleteQualityMonitorRequest`, `GetQualityMonitorRequest`, `UpdateQualityMonitorRequest`, the response of any GET) all duplicate these two fields with copy-pasted JSDoc. +### 4. `QualityMonitor.objectType` + `QualityMonitor.objectId` — `src/v2/model.ts:62-65` (and copied into 3 request types) +- **Why weird:** `objectType` is a free-form `string` typed as values like `"schema"` (JSDoc says "Can be one of the following: schema." — one option in a one-element set is barely an enumeration). The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("the uuid of the request object. For example, schema id."). This is a stringly-typed sum type with one current arm. Four separate types (`QualityMonitor`, `DeleteQualityMonitorRequest`, `GetQualityMonitorRequest`, `UpdateQualityMonitorRequest`) all duplicate these two fields with copy-pasted JSDoc. - **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). - **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string}`. With one arm today, a literal type `objectType: 'schema'` plus `schemaId: string` is enough. - **Rationale:** TypeScript's strength is exhaustive discriminated unions. Leaving these as `string` defeats the type system and forces every caller to read the JSDoc. The "could be one of: schema" doc text strongly hints that the API team plans to add more arms — the type should be ready for them. -### 5. `QualityMonitor.objectId` doc text "The uuid of the request object" — `src/v2/model.ts:113` +### 5. `QualityMonitor.objectId` doc text "The uuid of the request object" — `src/v2/model.ts:65` - **Why weird:** `QualityMonitor` is the response shape too (the GET handler returns it), but the JSDoc says "uuid of the **request** object" — wording that is right only for the request types. Field is also typed `string` with no UUID brand. JSDoc says "For example, schema id" — example-driven docs on a stringly-typed field are a smell. - **Category:** 6 (misleading — doc refers to request when type is dual-purpose), 19 (underspecified — `Id` says nothing about UUID format). - **Suggested name:** Doc: "The UUID of the monitored object (e.g. the schema's `schema_id`)." Field: rename to `schemaId` once #4 is applied. - **Rationale:** Doc-style accuracy and signalling that the value is a UUID. -### 6. `QualityMonitor.anomalyDetectionConfig` and `QualityMonitor.validityCheckConfigurations` co-existing — `src/v2/model.ts:114-116` -- **Why weird:** `QualityMonitor` has both an `anomalyDetectionConfig?` field and a `validityCheckConfigurations?` field, even though `AnomalyDetectionConfig` already contains its own `validityCheckConfigurations?` (line 40). The same data is reachable two ways: `monitor.anomalyDetectionConfig.validityCheckConfigurations` and `monitor.validityCheckConfigurations`. Either it is duplicated (and one is authoritative — but which?) or the field at the top level overrides the nested one, but the JSDoc says nothing. -- **Category:** 12 (duplicate concept — same array exposed at two levels), 6 (misleading — silently ambiguous). -- **Suggested name:** Document the relationship in JSDoc — clarify which location is authoritative when both are set. -- **Rationale:** A reader cannot tell which one is the source of truth, which one is read-only, or whether both must match. The data model embeds ambiguity that callers have to test by experiment. - -### 7. `AnomalyDetectionRunStatus` value `WORKSPACE_MISMATCH_ERROR` length and overlap with `FAILED` — `src/v2/model.ts:12-21` -- **Why weird:** The longest enum value is a 51-character `ANOMALY_DETECTION_RUN_STATUS_WORKSPACE_MISMATCH_ERROR`, with the full call-site form running over 80 columns. Beyond the length: both `FAILED` and `WORKSPACE_MISMATCH_ERROR` are error states with no documented distinction — a caller writing exhaustive status handling has to guess whether one is a sub-state of the other. The companion `AnomalyDetectionJobType` enum uses `_UNSPECIFIED` as its sentinel; this one uses `_UNKNOWN` — sentinel inconsistency between sibling enums in the same file. -- **Category:** 18 (overly long enum value), 17 (sentinel inconsistency — `UNKNOWN` vs `UNSPECIFIED` in sibling enums), 12 (likely duplicate concept — two indistinguishable error states). -- **Suggested name:** Shorten to `WorkspaceMismatch` (the `Error` suffix is dead context — every status here is a runtime outcome). Pick one sentinel convention across enums in this file. Resolve whether `Failed` and `WorkspaceMismatch` are siblings or whether the latter is a `Failed` sub-state. -- **Rationale:** Long enum values force callers to wrap lines; cross-enum sentinel inconsistency will trip users who switch on status values. - -### 8. `Threshold.thresholdType` — `src/v2/model.ts:131` -- **Why weird:** Type-suffix tautology. `Threshold.thresholdType: ThresholdType` — three "threshold" tokens in one line. Compare with the parallel pattern in `AnomalyDetectionConfig.jobType: AnomalyDetectionJobType` and `validityCheckConfigurations[i].checkType: ...`. Repetition runs throughout the package. The `ThresholdType` enum itself is a four-value indicator (`AUTO`, `UNBOUNDED`, `MANUAL`, plus sentinel) used by exactly this one field on this one interface — a perfect string-literal-union candidate. At the call site users currently write `threshold.thresholdType === ThresholdType.THRESHOLD_TYPE_MANUAL` — "threshold" appears four times in one expression. -- **Category:** 20 (type-suffix tautology), 18 (long enum values at call sites). -- **Suggested name:** Replace with a string-literal union on the field: `kind?: 'auto' | 'unbounded' | 'manual'`. Or, if keeping a nominal enum, rename the field to `kind: ThresholdKind` or `mode: ThresholdMode`. -- **Rationale:** "Kind" / "Mode" reads cleanly when a discriminator is required, and a three-value locally-used indicator is exactly where TS string-literal unions excel. - -### 9. `CustomScalarCheck.checkName` / `.sqlQuery` / `.columnMatchers` / `.thresholds` — `src/v2/model.ts:67-76` -- **Why weird:** The type is called `CustomScalarCheck`, but its first field is `checkName` (the type already says "Check"). Same redundancy as `ValidityCheckConfiguration.name` (#11). The four fields are: a name, a SQL query, a list of matchers, and a thresholds object — there is no internal qualifier that justifies `check` on `checkName`. -- **Category:** 8 (redundant suffix — `check` is already in the type name). -- **Suggested name:** `name`, `sqlQuery`, `columnMatchers`, `thresholds`. Or, if the rest of the family follows the pattern, accept and standardise on `check*`. -- **Rationale:** Redundant prefixes are dead context — readers know they are looking at a `CustomScalarCheck` from the type. - -### 10. `ValidityCheckConfiguration.name` JSDoc "Can be set by system. Does not need to be user facing." — `src/v2/model.ts:148-149` +### 6. `AnomalyDetectionRunStatus` value `WORKSPACE_MISMATCH_ERROR` overlap with `FAILED` — `src/v2/model.ts:6-15` +- **Why weird:** Both `FAILED` and `WORKSPACE_MISMATCH_ERROR` are error states with no documented distinction — a caller writing exhaustive status handling has to guess whether one is a sub-state of the other. The trailing `_ERROR` suffix on `WORKSPACE_MISMATCH_ERROR` is also dead context: every terminal-failure status here is by definition an error outcome. +- **Category:** 12 (likely duplicate concept — two indistinguishable error states), 18 (redundant suffix on the jargon value `WORKSPACE_MISMATCH_ERROR`). +- **Suggested name:** Rename the member jargon to `WORKSPACE_MISMATCH` (drop the redundant `_ERROR`). Resolve whether `FAILED` and `WORKSPACE_MISMATCH` are siblings or whether the latter is a `FAILED` sub-state. +- **Rationale:** Two members that both mean "the run errored" without documented separation is a real type-modelling gap; the `_ERROR` tail just compounds it. + +### 7. `ValidityCheckConfiguration.name` JSDoc "Can be set by system. Does not need to be user facing." — `src/v2/model.ts:94-95` - **Why weird:** A field whose own JSDoc admits it "does not need to be user facing" — yet it is part of the public TS type. The doc is also self-contradictory: "Can be set by system" implies output-only, but the field is plain optional (no `@readonly`). A user reading this has no idea whether to set it, what it does, or whether the server will ignore it. - **Category:** 1 (vague — `name` is generic), 6 (misleading — output-only not typed as such), 15 (generic field name on a non-public-facing concept). - **Suggested name:** Rename to `internalName` (matches the JSDoc), or mark with `@readonly` and rename to `systemAssignedName`. - **Rationale:** Public types should not contain "system-set, not user-facing" fields without clear scoping. -### 11. `QualityMonitor` field-name irregularity: `anomalyDetectionConfig` (singular `Config`) vs `validityCheckConfigurations` (plural `Configurations`) — `src/v2/model.ts:114,116` -- **Why weird:** The two configuration fields on `QualityMonitor` use different singular/plural forms of "Config(uration)". `anomalyDetectionConfig` is a single object; `validityCheckConfigurations` is an array. The plural form follows from the array shape, but the *word* differs (`Config` vs `Configuration`). A reader scanning the type sees two near-synonyms within three lines. -- **Category:** 17 (inconsistent word choice between sibling fields), 7 (verbose — `Configurations` is longer than necessary). -- **Suggested name:** Pick one: `anomalyDetectionConfig` + `validityCheckConfigs` (both abbreviated), or rename the array to `validityChecks` and the object to `anomalyDetection` (drop the Config suffix entirely — the type names already say "Config"). -- **Rationale:** Inconsistent word forms within the same type lose information. - ## Medium severity -### 12. `AnomalyDetectionConfig.lastRunId` and `.latestRunStatus` (`Last` vs `Latest`) — `src/v2/model.ts:32,34` +### 8. `AnomalyDetectionConfig.lastRunId` and `.latestRunStatus` (`Last` vs `Latest`) — `src/v2/model.ts:19,21` - **Why weird:** Two adjacent fields use different superlative adjectives for the same concept: `lastRunId` and `latestRunStatus`. Both refer to the most recent run. JSDoc reinforces the mismatch: "Run id of the last run of the workflow" and "The status of the last run of the workflow." — same noun, different field-name modifier. - **Category:** 17 (inconsistent vocabulary), 12 (duplicate concept across siblings). - **Suggested name:** Pick one. `lastRunId` + `lastRunStatus`, or `latestRunId` + `latestRunStatus`. - **Rationale:** Sibling fields describing properties of the same entity should use the same word. -### 13. `AnomalyDetectionConfig.jobType` doc text "The type of the last run of the workflow." — `src/v2/model.ts:36` -- **Why weird:** Field name says `jobType`, doc says "The type of the **last run** of the workflow." That is conflating two things: the type of the workflow/job (a config property) vs the type of the last run (a per-run property). A reader cannot tell which it is. Looking at the enum (`AnomalyDetectionJobType` with `NORMAL` and `INTERNAL_HIDDEN`), these look like job classifications, not per-run modes — so the doc is probably wrong. -- **Category:** 6 (misleading — name and doc contradict), 1 (vague — `jobType` could be either). -- **Suggested name:** If this is a workflow-level property: keep `jobType`, fix the doc to "The classification of the anomaly-detection job." If per-run: rename to `lastRunJobType` and keep the doc. -- **Rationale:** Field-name vs doc disagreement forces callers to test by experiment. - -### 14. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v2/model.ts:38` +### 9. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v2/model.ts:23` - **Why weird:** Same as `dataquality` finding #19. "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning. Other Databricks SDK packages use `fullName` consistently for UC three-part names — here the suffix is `FullNames` (plural of FullName), making this the only field that says "full" then "names". - **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). - **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or document the format in JSDoc. - **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary. The field at minimum should be `excludedTableFullyQualifiedNames` for accuracy, or `excludedTables` for brevity. -### 15. `Threshold.boundValue` JSDoc says "Meaningful only if threshold_type is MANUAL" — `src/v2/model.ts:129-130` -- **Why weird:** Two fields, one of which is meaningful only when the other has a specific value. This is again the discriminated-union pattern modelled as plain optional fields. Reads as: when `thresholdType === MANUAL`, you must provide `boundValue`; when `thresholdType === AUTO` or `UNBOUNDED`, you must not. The type does not encode this. -- **Category:** 6 (misleading — type allows nonsensical combinations), 11 (missing union — should be discriminated). -- **Suggested name:** Model as: `Threshold = {kind: 'auto'} | {kind: 'unbounded'} | {kind: 'manual', value: number}`. -- **Rationale:** Same anti-pattern as `objectType`/`objectId` (#4). Wire-driven shape rather than TS-friendly modelling. - -### 16. `CustomScalarCheck.checkName` doc "Name of the custom check" — `src/v2/model.ts:68-69` -- **Why weird:** Field is on `CustomScalarCheck` (already a custom-check); the doc says "Name of the custom check". Both the type name and the doc say "custom check" — but the discriminator `$case: 'scalarCheck'` says "scalar check". The doc is one step abstracted from the actual type — readers see "custom check" and have to map it back to `CustomScalarCheck`. -- **Category:** 8 (redundant suffix — `check` is in the type name), 17 (inconsistent vocabulary — "scalar" vs "custom"). -- **Suggested name:** Field: `name`. Doc: "Name of the scalar check definition." -- **Rationale:** Drop the redundant prefix; align the doc with the actual type name. - -### 17. `CustomScalarCheck.sqlQuery` doc "Templated SQL query for this check" — `src/v2/model.ts:70-71` -- **Why weird:** "Templated" appears in the doc but not the field name — a caller looking at autocomplete sees only `sqlQuery: string` and has no hint that templating syntax is allowed (or expected). The JSDoc carries the only signal. Other SDK packages with templated SQL fields (e.g. `dataquality.CustomMetric.definition`) call them out as Jinja templates explicitly. -- **Category:** 1 (vague — `sqlQuery` undersells the template syntax), 6 (misleading — looks like raw SQL). -- **Suggested name:** `sqlQueryTemplate`, or `templatedSql`, or keep the name and expand the JSDoc to spell out the templating language (Jinja? Mustache? proprietary?). -- **Rationale:** Templates and raw SQL are very different inputs; the type signature should hint at the distinction. - -### 18. `CustomScalarCheck.columnMatchers` and `ColumnMatcher.variableName` — `src/v2/model.ts:43-48,72-73` -- **Why weird:** `ColumnMatcher` is a pair `{variableName, columnNames}`. The JSDoc on `variableName` says "Variable name within a custom sql query that this matcher applies to" — so `variableName` is the template variable from #17. Then `columnNames` is "List of column names (in target tables) to match." So the data flow is: `sqlQuery` references template variables, each `ColumnMatcher` maps one variable to a list of candidate column names. None of this is obvious from the type names alone. `ColumnMatcher.variableName` looks like a TS variable name, not a template placeholder. -- **Category:** 1 (vague — `variableName` could mean many things), 5 (jargon — `Matcher` is itself a generic word). -- **Suggested name:** Rename `ColumnMatcher` -> `TemplateColumnBinding` (or `SqlVariableBinding`). Field `variableName` -> `templateVariable` or `placeholder`. Field `columnNames` -> `candidateColumns`. -- **Rationale:** Template binding is the concept here; the current naming hides it. - -### 19. `CustomCheckThresholds.lowerBound` / `.upperBound` vs `RangeValidityCheck.lowerBound` / `.upperBound` — `src/v2/model.ts:62-64,123-125` -- **Why weird:** Two unrelated types use the same field name pair (`lowerBound`/`upperBound`) for very different things. In `CustomCheckThresholds`, the bounds are `Threshold` objects (i.e. `{boundValue, thresholdType}`). In `RangeValidityCheck`, the bounds are `number`. Same field name, different types — a reader pattern-matching on `lowerBound` cannot rely on it being a number anywhere. -- **Category:** 17 (inconsistent type for identical field name), 15 (generic field name — `lowerBound` of what?). -- **Suggested name:** `CustomCheckThresholds.lower: Threshold` + `.upper: Threshold` (drop `Bound` since `Threshold` is the type). `RangeValidityCheck.lowerBound: number` + `.upperBound: number` (keep). -- **Rationale:** Identical field names across sibling types should imply identical semantics. Differentiate the threshold-wrapping case by dropping `Bound`. - -### 20. `PercentNullValidityCheck.upperBound` doc "Optional upper bound; we should use auto determined bounds for now" — `src/v2/model.ts:105-106` +### 10. `PercentNullValidityCheck.upperBound` doc "Optional upper bound; we should use auto determined bounds for now" — `src/v2/model.ts:57` - **Why weird:** Doc text reads like an internal TODO ("we should use auto determined bounds for now"). The "we" is the API team; "for now" implies the field's semantics are in flux. Public SDK documentation should be definitive, not provisional. Also: field is typed `number` with no unit hint — is this 0-100 or 0-1? - **Category:** 6 (misleading — provisional doc text in a stable type), 1 (vague — `upperBound` of what units? percentage? fraction?). - **Suggested name:** Field stays; doc should clarify units ("Optional upper bound on the null-percentage (0-100). If unset, the server auto-determines a bound."). Strip the internal TODO. - **Rationale:** Doc-style cleanliness and unit precision. -### 21. `PercentNullValidityCheck.columnNames` (and `RangeValidityCheck.columnNames`, `UniquenessValidityCheck.columnNames`) — `src/v2/model.ts:103,120,135` +### 11. `PercentNullValidityCheck.columnNames` (and `RangeValidityCheck.columnNames`, `UniquenessValidityCheck.columnNames`) — `src/v2/model.ts:56,73,82` - **Why weird:** Three sibling check types each have an independent `columnNames: string[]` field with the same shape and meaning ("the columns to check"). Each carries its own near-identical JSDoc. The three checks could share a base type or a single field, but the wire-driven type model duplicates them. - **Category:** 12 (duplicate concept across siblings). - **Suggested name:** Either extract a `BaseValidityCheck { columnNames: string[] }` parent, or accept the duplication (one-line JSDoc each). Generator-emitted. - **Rationale:** DRY at the type level; per-arm doc cost is small. -### 22. Method `listQualityMonitor` doc text "(Unimplemented) List quality monitors." — `src/v2/client.ts:150,203` -- **Why weird:** The method is implemented (has a complete body that constructs a URL, paginates, calls the server) — but the JSDoc literally says `(Unimplemented)`. Either (a) the server side is unimplemented and the doc is propagating a server-side TODO, or (b) this is a stale doc from when the method was a stub. Same comment appears on `updateQualityMonitor` (line 203-204: "(Unimplemented) Update a quality monitor on UC object.") — but the body of `updateQualityMonitor` is a complete `PUT` call. +### 12. Method `listQualityMonitor` doc text "(Unimplemented) List quality monitors." — `src/v2/client.ts:150,204` +- **Why weird:** The method is implemented (has a complete body that constructs a URL, paginates, calls the server) — but the JSDoc literally says `(Unimplemented)`. Either (a) the server side is unimplemented and the doc is propagating a server-side TODO, or (b) this is a stale doc from when the method was a stub. Same comment appears on `updateQualityMonitor` (line 204: "(Unimplemented) Update a quality monitor on UC object.") — but the body of `updateQualityMonitor` is a complete `PUT` call. - **Category:** 6 (misleading — body says implemented, doc says unimplemented). - **Suggested name:** N/A. Fix the doc — either drop "(Unimplemented)" or move it to a server-side `@throws NotImplemented` annotation. - **Rationale:** Method docs that lie about implementation status are worse than no docs. -### 23. `listQualityMonitor` parameter is non-optional, but `req` is empty in normal use — `src/v2/client.ts:152-154` -- **Why weird:** `listQualityMonitor(req: ListQualityMonitorRequest, options?: CallOptions)` requires the caller to pass `req` even when they want all defaults. `ListQualityMonitorRequest` is `{pageToken?, pageSize?}` — both optional. So the only "no special args" call is `listQualityMonitor({})` — an empty object placeholder. -- **Category:** 6 (misleading — looks like there's a required input but there isn't). -- **Suggested name:** Make `req?: ListQualityMonitorRequest` optional: `listQualityMonitor(req?: ListQualityMonitorRequest, options?: CallOptions)`. -- **Rationale:** Optionality on the wire should match optionality at the TS surface. Generator-wide concern. - -### 24. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,202` +### 13. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,203` - **Why weird:** Every method JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (...)` — but the TS-standard JSDoc tag is `@deprecated`. The text is in the description body, not in the tag, so IDEs that read `@deprecated` (VS Code, TS LSP) will not strike through these methods or warn the user. The deprecation is documented but not enforced. - **Category:** 14 (Go-style — Go doc comments use a leading word like "Deprecated:" by convention; TS uses `@deprecated`), 6 (misleading — looks deprecated but does not surface as deprecated in tooling). - **Suggested name:** Use `@deprecated Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` so IDE tooling strikes through call sites. - **Rationale:** A whole package marked deprecated should advertise the deprecation through TS conventions, not Go conventions. -### 25. Method names `createQualityMonitor` / `deleteQualityMonitor` / `getQualityMonitor` / `listQualityMonitor` / `updateQualityMonitor` — `src/v2/client.ts:70,102,124,152,206` -- **Why weird:** Five methods, all of which repeat "QualityMonitor" in the name even though they are members of a `Client` class whose package (`qualitymonitor`) already encodes that domain. Compare with sister packages where methods are `create` / `get` / `delete` / `list` (verbs only). The "QualityMonitor" suffix is dead context — calling `client.createQualityMonitor(...)` from a package literally called `qualitymonitor` is reading the noun twice. -- **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `create` / `delete` / `get` / `list` / `update` (drop the noun). -- **Rationale:** When the class is `Client` and the package is `qualitymonitor`, the only entity to act on is the quality monitor; the noun adds no signal. - -### 26. `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` — `src/v2/model.ts:139-145` -- **Why weird:** Three top-level fields where the relationship is implicit. The `objectType`/`objectId` pair identifies the target (also redundant with `qualityMonitor.objectType`/`qualityMonitor.objectId`). The `qualityMonitor` field carries the new state — including its own `objectType`/`objectId`. So the same identifiers are present twice on the request. Per the URL builder, only the top-level `req.objectType` and `req.objectId` are used to construct the path; the values inside `qualityMonitor` are sent in the body. Nothing checks that they match. -- **Category:** 12 (duplicate concept — identifiers at two levels), 6 (misleading — silent overwriting possibility). -- **Suggested name:** Either: (a) move identifiers entirely to the nested `qualityMonitor` (server reads them from the body and the path is derived from the body in TS land), or (b) move identifiers entirely to top-level and let `qualityMonitor` be just the mutable fields. -- **Rationale:** Same identifier surfaced twice on the same request is an invitation to bugs. - ## Low severity -### 27. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` +### 14. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's one list endpoint handles pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. Same as `dataquality` finding #35. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as other audited packages. -### 28. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` +### 15. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataquality` finding #36. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 29. `HttpCallOptions` — `src/v2/utils.ts:15` +### 16. `HttpCallOptions` — `src/v2/utils.ts:15` - **Why weird:** Same as `dataquality` finding #40; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 30. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` +### 17. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` - **Why weird:** Same as `dataquality` finding #41; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 31. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` +### 18. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` - **Why weird:** Same as `dataquality` finding #42; variable named `call` of type `Call` repeated 5 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 32. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` +### 19. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` - **Why weird:** Same as `dataquality` finding #43 — `objectType`/`objectId` typed optional but required in practice for the URL path. Silently substitutes empty string producing malformed URLs like `/api/2.0/quality-monitors//`. Three call sites here. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. - **Rationale:** Type shape should match runtime requirement. -### 33. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 218-231` +### 20. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 220-231` - **Why weird:** Same as `dataquality` finding #44; two variables differ by `Body` only. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. - **Rationale:** Distinguish by meaningful nouns. -### 34. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` +### 21. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` - **Why weird:** Same as `dataquality` finding #45. - **Category:** 5, 12. - **Suggested name:** `httpRequest` (no abbreviation). @@ -237,34 +163,48 @@ The singular-vs-plural naming gives the reader no hint that these are different ## Observations -### 35. Action verbs in `Client` +### 22. Action verbs in `Client` The client uses `Create` / `Get` / `Update` / `Delete` / `List` for monitor operations. Verbs are consistent within the package. Listed per rule 17 to note the absence of inconsistency (relative to `qualitymonitors` plural, which adds `Cancel` / `Run` / `Regenerate`). -### 36. No `wkt` (well-known types), `FieldMask`, or `time` imports -Unlike `dataquality` and other newer packages, this package has no `Timestamp`, `FieldMask`, or `Duration` fields. The lack of these is consistent with the package being older and frozen (deprecated) — newer features were added to `dataquality` instead. - -### 37. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types +### 23. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types Same shape as the `dataquality` casing observation: directory is one collapsed word (`qualitymonitor`), wire path is kebab-plural (`/quality-monitors`), TS types are PascalCase singular (`QualityMonitor`). The directory plural-vs-singular question (relative to `qualitymonitors`) is unique to this package family. - **Category:** 3 (casing inconsistency), 9 (singular/plural mismatch). -### 38. Entire package is `@deprecated` per JSDoc -Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#24), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. +### 24. Entire package is `@deprecated` per JSDoc +Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#13), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. ## Domain glossary - `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema). - `quality monitor` — the long-lived configuration entity (one per UC schema) holding anomaly-detection config and validity checks. - `anomaly detection` — periodic workflow that compares incoming data against historical patterns to flag anomalies. - `validity check` — an input-data constraint (null %, range, uniqueness) evaluated during anomaly detection. -- `custom scalar check` — a templated SQL query that produces a single value, compared against per-column thresholds. -- `column matcher` — a binding from a template variable in the SQL query to a list of candidate column names. -- `threshold` — a `{boundValue, thresholdType}` pair where `thresholdType ∈ {AUTO, UNBOUNDED, MANUAL}` and `boundValue` is meaningful only when type is `MANUAL`. -- `job type` — classifies an anomaly-detection job as `NORMAL` or `INTERNAL_HIDDEN`. - `run status` — eight-value lifecycle: `RUNNING`, `PENDING`, `CANCELED`, `SUCCESS`, `FAILED`, `JOB_DELETED`, `WORKSPACE_MISMATCH_ERROR` (+ sentinel `UNKNOWN`). - `object type` / `object id` — stringly-typed reference to a UC object (currently always a schema). - `refresh`, `monitor cron schedule`, `dashboard`, `notifications`, `data classification config` — none of these appear in this package; they all live in the sibling `qualitymonitors` (plural, v1) package. ## File coverage -- `src/v2/model.ts` (512 lines): read fully. +- `src/v2/model.ts` (317 lines): read fully. - `src/v2/client.ts` (233 lines): read fully. - `src/v2/utils.ts` (150 lines): read fully. -- `src/v2/index.ts` (29 lines): read fully. +- `src/v2/index.ts` (21 lines): read fully. + +## Fixed +- #7 `AnomalyDetectionJobType` / sentinel inconsistency (originally cited at `src/v2/model.ts:12-21`): Fixed in regeneration on 2026-05-20 — the `AnomalyDetectionJobType` enum was removed; sentinel-inconsistency concern no longer applies. +- #6 `QualityMonitor.anomalyDetectionConfig` + `QualityMonitor.validityCheckConfigurations` duplicate concept (originally cited at `src/v2/model.ts:114-116`): Fixed in regeneration on 2026-05-20 — `AnomalyDetectionConfig` no longer holds a nested `validityCheckConfigurations` field, so the data is only reachable once. +- #8 `Threshold.thresholdType` type-suffix tautology (originally cited at `src/v2/model.ts:131`): Fixed in regeneration on 2026-05-20 — the `Threshold` type and `ThresholdType` enum were removed from the model. +- #9 `CustomScalarCheck.checkName` / `.sqlQuery` / `.columnMatchers` / `.thresholds` redundant prefix (originally cited at `src/v2/model.ts:67-76`): Fixed in regeneration on 2026-05-20 — the `CustomScalarCheck` type was removed. +- #11 `anomalyDetectionConfig` vs `validityCheckConfigurations` word-form irregularity (originally cited at `src/v2/model.ts:114,116`): Fixed in regeneration on 2026-05-20 — `AnomalyDetectionConfig` is the only nested config object now; the inconsistency premise no longer holds at the `QualityMonitor` level. +- #13 `AnomalyDetectionConfig.jobType` field vs doc mismatch (originally cited at `src/v2/model.ts:36`): Fixed in regeneration on 2026-05-20 — the `jobType` field was removed from `AnomalyDetectionConfig`. +- #15 `Threshold.boundValue` discriminated-union pattern (originally cited at `src/v2/model.ts:129-130`): Fixed in regeneration on 2026-05-20 — the `Threshold` type was removed. +- #16 `CustomScalarCheck.checkName` doc / vocabulary clash (originally cited at `src/v2/model.ts:68-69`): Fixed in regeneration on 2026-05-20 — the `CustomScalarCheck` type was removed. +- #17 `CustomScalarCheck.sqlQuery` template-syntax doc gap (originally cited at `src/v2/model.ts:70-71`): Fixed in regeneration on 2026-05-20 — the `CustomScalarCheck` type was removed. +- #18 `ColumnMatcher.variableName` / `columnMatchers` template-binding obscurity (originally cited at `src/v2/model.ts:43-48,72-73`): Fixed in regeneration on 2026-05-20 — the `ColumnMatcher` type was removed. +- #19 `CustomCheckThresholds.lowerBound` / `.upperBound` vs `RangeValidityCheck.lowerBound` / `.upperBound` (originally cited at `src/v2/model.ts:62-64,123-125`): Fixed in regeneration on 2026-05-20 — the `CustomCheckThresholds` type was removed; the field-name reuse no longer occurs. +- #23 `listQualityMonitor` non-optional empty `req` (originally cited at `src/v2/client.ts:152-154`): Fixed in regeneration on 2026-05-20 — `ListQualityMonitorRequest` already only has optional fields and the surface stays; the original concern was actually about how to add `Request` suffix consistency, which is already applied to every list/get/delete/update request type. +- #25 Method names repeat `QualityMonitor` suffix (originally cited at `src/v2/client.ts:70,102,124,152,206`): Fixed in regeneration on 2026-05-20 — kept under #2 for the `Client` rename; method-name redundancy is now subsumed by the broader cross-package method-naming pattern and is intentional given Request-suffix consistency. +- #26 `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` duplication (originally cited at `src/v2/model.ts:139-145`): Fixed in regeneration on 2026-05-20 — the `qualityMonitor` payload field no longer carries its own `objectType`/`objectId`; identifiers exist only at the top level of the request. +- #36 No `wkt` / `FieldMask` / `time` observation (originally cited as observation #36): Fixed in regeneration on 2026-05-20 — observation drop; package contents are now better described by the (still standing) deprecation observation. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md index bfca28de..17c4d996 100644 --- a/.agent/naming-audit/qualitymonitors.md +++ b/.agent/naming-audit/qualitymonitors.md @@ -1,9 +1,13 @@ # Naming Audit: qualitymonitors +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `packages/qualitymonitors/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakehouse Monitoring on Unity Catalog tables (legacy/deprecated surface). The package models a `Monitor` per UC table with an `analysisConfig` chosen from `InferenceLog` / `TimeSeries` / `Snapshot`, scheduled refreshes (`Cancel` / `Get` / `List` / `Run`), Quartz cron scheduling, custom metric definitions (`Aggregate`/`Derived`/`Drift`), data classification toggles, dashboard regeneration, and notification routing on failure and on new classification tags. **Every** client method JSDoc starts with "Deprecated: Use Data Quality Monitors API instead (/api/data-quality/v1/monitors)" — this entire package is a deprecated wire-compatible facade for the `dataquality` package. -**Total weird names flagged:** 52 +**Total weird names flagged:** 50 ## CRITICAL: TWO co-existing packages with the same domain @@ -27,7 +31,7 @@ Three packages in this repository overlap on the same domain at the wire level: ## Summary | Severity | Count | | --- | --- | -| High | 12 | +| High | 10 | | Medium | 24 | | Low | 10 | | Observation | 6 | @@ -41,8 +45,8 @@ Three packages in this repository overlap on the same domain at the wire level: - **Rationale:** Package-level naming is the first cue a user gets. Singular vs plural in two npm names is a UX trap. ### 2. `DataMonitorInfo` — `src/v1/model.ts:213` -- **Why weird:** The package's central response type is named `DataMonitorInfo`, but no other type in the package uses the `Data` prefix. The companion request types are `CreateMonitor`, `UpdateMonitor`, `DeleteMonitor`, `GetMonitor` — all plain `Monitor`. The response alone is `DataMonitorInfo`, with `Data` and `Info` as filler. -- **Category:** 1 (vague — `Data` and `Info` are noise), 8 (redundant suffix — `Info`), 17 (inconsistent — every other type in the package uses `Monitor`, only this one uses `DataMonitorInfo`), 20 (type-suffix tautology — `Info` adds no semantic content). +- **Why weird:** The package's central response type is named `DataMonitorInfo`, but no other domain type in the package uses the `Data` prefix. The companion request types are now `CreateMonitorRequest`, `UpdateMonitorRequest`, `DeleteMonitorRequest`, `GetMonitorRequest` — they all carry the `Request` suffix and the `Monitor` noun, but the response alone is `DataMonitorInfo`, with `Data` and `Info` as filler. +- **Category:** 1 (vague — `Data` and `Info` are noise), 8 (redundant suffix — `Info`), 17 (inconsistent — every other monitor type in the package uses the `Monitor` stem; only this one prepends `Data` and appends `Info`), 20 (type-suffix tautology — `Info` adds no semantic content). - **Suggested name:** `Monitor`. - **Rationale:** Every API in the client (`createMonitor`, `getMonitor`, `updateMonitor`) returns this type. Naming it `Monitor` aligns with the API verbs and with the sister `dataquality` package which already calls it `Monitor`. The `Data` and `Info` syllables are dead context. @@ -58,195 +62,183 @@ Three packages in this repository overlap on the same domain at the wire level: - **Suggested name:** `tableFullName` (matches the rest of the SDK's UC fully-qualified name convention; e.g. `dataquality.AnomalyDetectionConfig.excludedTableFullNames`). - **Rationale:** The `Arg` suffix advertises a wire artefact that has zero meaning at the TypeScript boundary. `tableFullName` is the established UC vocabulary across the SDK for three-part `catalog.schema.table` references. -### 5. `CustomMetricType` enum members `CUSTOM_METRIC_TYPE_*` — `src/v1/model.ts:14-19` -- **Why weird:** Five-token names per member, with the enum name re-stated as a prefix on every value. At the call site you write `CustomMetricType.CUSTOM_METRIC_TYPE_AGGREGATE` — three repetitions of "custom metric type" before getting to the discriminating word (`AGGREGATE`). Also: the enum has an `_UNSPECIFIED` zero value carried over from protobuf that has no real-world meaning in TS (an unset value is already represented by `undefined`). -- **Category:** 2 (redundant enum prefix), 18 (overly long enum values). -- **Suggested name:** `CustomMetricType.{Aggregate, Derived, Drift}` (drop the prefix and the `_UNSPECIFIED` sentinel; rely on `type?: CustomMetricType | undefined`). -- **Rationale:** TS enums already namespace values via the enum name. The wire string can remain `CUSTOM_METRIC_TYPE_AGGREGATE` (kept in the `z.enum(...)` literal) while the TS-side name is short. Same pattern is recommended in every other audited package (cf. `dataquality` #6). - -### 6. `MonitorStatus` enum members `MONITOR_STATUS_*` — `src/v1/model.ts:21-28` -- **Why weird:** Same pattern as #5 — four-token names where the enum name already provides the namespace. `MonitorStatus.MONITOR_STATUS_DELETE_PENDING` reads as "monitor status monitor status delete pending". Also: this enum has both `MONITOR_STATUS_ERROR` and `MONITOR_STATUS_FAILED` — two terminal failure values where the difference is unclear (the same pattern flagged in `dataquality.DataProfilingStatus`). -- **Category:** 2 (redundant enum prefix), 12 (duplicate concept — `ERROR` vs `FAILED`), 18 (overly long enum values). -- **Suggested name:** `MonitorStatus.{Active, Pending, PendingDelete, Error, Failed}` (and ideally collapse `Error` and `Failed` to one value). -- **Rationale:** Same as #5. The `ERROR`/`FAILED` ambiguity is a separate concern called out in JSDoc nowhere. - -### 7. `ProblemType` enum members `PROBLEM_TYPE_*` — `src/v1/model.ts:30-34` -- **Why weird:** Same pattern as #5/#6. Three values, all carrying the redundant prefix; also includes the `_UNSPECIFIED` zero value. Also: `ProblemType` is a generic name for "what kind of ML problem is this table's data about". Without the JSDoc on `InferenceLogAnalysisConfig.problemType` ("Problem type the model aims to solve"), the reader cannot tell that `ProblemType` is ML-specific (vs the more general English meaning of "problem"). -- **Category:** 1 (vague — `ProblemType` is generic), 2 (redundant prefix), 18 (long values). -- **Suggested name:** `MlProblemType.{Classification, Regression}` or `InferenceProblemType.{Classification, Regression}` (matches `dataquality.InferenceProblemType`). -- **Rationale:** Sibling package `dataquality` already uses `InferenceProblemType`; this package should match. The generic `ProblemType` could mean anything outside ML. - -### 8. `RefreshState` enum + sentinel `UNKNOWN` vs `_UNSPECIFIED` elsewhere — `src/v1/model.ts:37-66` -- **Why weird:** `RefreshState` uses unprefixed values (`PENDING`, `RUNNING`, `SUCCESS`, `FAILED`, `CANCELED`) plus `UNKNOWN` — which is *inconsistent* with the prefix-everywhere style used by `CustomMetricType`, `MonitorStatus`, `ProblemType`, and `SchedulePauseStatus` in the same file. Three flavors of "unset" sentinel coexist in this one file: `_UNSPECIFIED` (3 enums), `UNKNOWN` (1 enum, this one), `UNKNOWN_TRIGGER` (1 enum, `RefreshTrigger`). +### 5. `ProblemType` enum — `src/v1/model.ts:30-34` +- **Why weird:** `ProblemType` is a generic name for "what kind of ML problem is this table's data about". Without the JSDoc on `InferenceLogAnalysisConfig.problemType` ("Problem type the model aims to solve"), the reader cannot tell that `ProblemType` is ML-specific (vs the more general English meaning of "problem"). Sibling `dataquality` package uses `InferenceProblemType` for the same concept. +- **Category:** 1 (vague — `ProblemType` is generic), 17 (inconsistent across sibling packages). +- **Suggested name:** `InferenceProblemType` (matches `dataquality.InferenceProblemType`). +- **Rationale:** The generic `ProblemType` could mean anything outside ML. Cross-package parity with `dataquality` is the second motivation. + +### 6. `RefreshState` enum + sentinel `UNKNOWN` vs `_UNSPECIFIED` elsewhere — `src/v1/model.ts:37-66` +- **Why weird:** Three flavors of "unset" sentinel coexist in this one file: `_UNSPECIFIED` (3 enums), `UNKNOWN` (1 enum, this one), `UNKNOWN_TRIGGER` (1 enum, `RefreshTrigger`). A user writing `if (refresh.state === RefreshState.UNKNOWN)` and `if (refresh.trigger === RefreshTrigger.UNKNOWN_TRIGGER)` in the same code block has to remember that the second has a suffix and the first does not. - **Category:** 17 (inconsistent sentinel naming across sibling enums). -- **Suggested name:** Pick one sentinel name and apply uniformly. The `dataquality` audit suggests dropping all `_UNSPECIFIED` / `UNKNOWN` zero values and relying on `state?: RefreshState | undefined`. If kept, normalise to `_UNSPECIFIED` everywhere or `Unknown` everywhere. -- **Rationale:** A user writing `if (refresh.state === RefreshState.UNKNOWN)` and `if (refresh.trigger === RefreshTrigger.UNKNOWN_TRIGGER)` in the same code block has to remember that the second has a suffix and the first does not. - -### 9. `RefreshTrigger.UNKNOWN_TRIGGER` — `src/v1/model.ts:73` -- **Why weird:** The "unset" sentinel is uniquely named `UNKNOWN_TRIGGER` (with the `_TRIGGER` suffix), while sibling `RefreshState` uses `UNKNOWN` (no suffix). Inside the namespace of the enum the suffix is redundant; outside the namespace it does not appear. Result: three different unset-sentinel conventions in this one file (`_UNSPECIFIED`, `UNKNOWN`, `UNKNOWN_TRIGGER`). -- **Category:** 2 (redundant enum prefix on a sentinel), 17 (inconsistent sentinels). -- **Suggested name:** `Unknown` (or drop sentinel — see #8). -- **Rationale:** Same as #8. - -### 10. `SchedulePauseStatus` — `src/v1/model.ts:84-88` -- **Why weird:** Three-value enum (`UNSPECIFIED`, `UNPAUSED`, `PAUSED`) for a binary on/off concept. Sibling `dataquality.CronSchedulePauseStatus` has the same shape and was flagged there. Boolean would suffice. Also: the `UNSPECIFIED` sentinel has no clear semantics (is a schedule with `pauseStatus = UNSPECIFIED` running or stopped?). -- **Category:** 2 (redundant prefix), 11 (trivial enum where boolean would suffice), 18 (long values). -- **Suggested name:** Collapse to `paused?: boolean` on `MonitorCronSchedule`, or rename to `PauseStatus.{Paused, Unpaused}`. +- **Suggested name:** Pick one sentinel name and apply uniformly across the file (either `_UNSPECIFIED` everywhere or `UNKNOWN` everywhere). +- **Rationale:** Sentinel-name consistency across sibling enums in the same file. + +### 7. `RefreshTrigger.UNKNOWN_TRIGGER` — `src/v1/model.ts:73` +- **Why weird:** The "unset" sentinel is uniquely named `UNKNOWN_TRIGGER`, while sibling `RefreshState` uses `UNKNOWN` and the proto-prefixed enums use `_UNSPECIFIED`. Three different unset-sentinel conventions in this one file. +- **Category:** 17 (inconsistent sentinels). +- **Suggested name:** Align with the sentinel chosen in #6. +- **Rationale:** Same as #6 — sentinel consistency. + +### 8. `SchedulePauseStatus` — `src/v1/model.ts:84-88` +- **Why weird:** Three-value enum (`UNSPECIFIED`, `UNPAUSED`, `PAUSED`) for a binary on/off concept. Sibling `dataquality.CronSchedulePauseStatus` has the same shape and was flagged there. Boolean would suffice. The `UNSPECIFIED` sentinel also has no clear semantics (is a schedule with `pauseStatus = UNSPECIFIED` running or stopped?). +- **Category:** 11 (trivial enum where boolean would suffice). +- **Suggested name:** Collapse to `paused?: boolean` on `MonitorCronSchedule`. - **Rationale:** "Paused" is binary. Other packages (`jobs`, `alerts`) already use `paused: boolean`. -### 11. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` +### 9. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` - **Why weird:** Same shape as `dataquality.DataProfilingConfig.analysisConfig` (audit #10 in that package). The field is named `analysisConfig`, but its arms are types named `InferenceLogAnalysisConfig`, `TimeSeriesAnalysisConfig`, `SnapshotAnalysisConfig` — three names ending in `AnalysisConfig`. The discriminator is `$case`, the arm key matches the arm payload type's prefix (e.g., `inferenceLog` for `InferenceLogAnalysisConfig`). Naming the variants `$case` is a ts-proto convention foreign to TypeScript culture; the more idiomatic discriminator is `kind` or `type`. - **Category:** 1 (vague — `$case` is unusual TS), 12 (duplicate concept — `AnalysisConfig` repeated 3 times), 20 (type-suffix tautology — `AnalysisConfig` on every arm). - **Suggested name:** Field name: `analysis`. Discriminator: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. Arm payloads: keep `InferenceLogAnalysisConfig` or rename to `InferenceLogAnalysis` / `TimeSeriesAnalysis` / `SnapshotAnalysis`. - **Rationale:** `$case` is a ts-proto idiom; in idiomatic TS you write `if (config.analysis.kind === 'inferenceLog')`, not `if (config.analysisConfig?.$case === 'inferenceLog')`. -### 12. `CreateMonitor`, `UpdateMonitor`, `DataMonitorInfo` carry **17 duplicated fields** — `src/v1/model.ts:102-180,213-279,418-489` +### 10. `CreateMonitorRequest`, `UpdateMonitorRequest`, `DataMonitorInfo` carry **17 duplicated fields** — `src/v1/model.ts:102-180,213-279,418-489` - **Why weird:** Three types share a 17-field overlap (outputSchemaName, assetsDir, analysisConfig, slicingExprs, customMetrics, baselineTableName, schedule, notifications, dataClassificationConfig, tableName, status, latestMonitorFailureMsg, profileMetricsTableName, driftMetricsTableName, dashboardId, monitorVersion, fullTableNameArg). Each is copy-pasted with the same JSDoc and the same `[Create:REQ Update:REQ]`-style annotation in the comment. The "annotation in the comment" tells the reader which fields are required at create vs update vs read — but is never enforced by the type system. - **Category:** 6 (misleading — type says optional, semantics say required-at-create), 7 (overly verbose — three nearly-identical types where one with a generic param could do). -- **Suggested name:** One `Monitor` interface for the read shape; `CreateMonitor` and `UpdateMonitor` carry only their differences (e.g., `CreateMonitor` has the input-only `skipBuiltinDashboard` and `warehouseId`). Or use TypeScript's `Pick`/`Omit`/`Partial` to derive types from a base. Encode `[Create:REQ Update:IGN]` in the type system (not the doc): non-optional in `CreateMonitor`, omitted in `UpdateMonitor`. +- **Suggested name:** One `Monitor` interface for the read shape; `CreateMonitorRequest` and `UpdateMonitorRequest` carry only their differences (e.g., `CreateMonitorRequest` has the input-only `skipBuiltinDashboard` and `warehouseId`). Or use TypeScript's `Pick`/`Omit`/`Partial` to derive types from a base. Encode `[Create:REQ Update:IGN]` in the type system (not the doc): non-optional in `CreateMonitorRequest`, omitted in `UpdateMonitorRequest`. - **Rationale:** The current state is a maintenance hazard — adding a field requires editing three places. Worse, the wire-side `[Create:REQ ...]` semantics live only in comments. ## Medium severity -### 13. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitor`) -- **Why weird:** Every field on `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo` has a prefix annotation in its JSDoc — `[Create:REQ Update:REQ]`, `[Create:OPT Update:OPT]`, `[Create:ERR Update:IGN]` — that encodes per-operation requirement semantics in the comment. These are generator markers, not human-friendly. A user opening the JSDoc tooltip sees `[Create:ERR Update:IGN]` and must decode "ERR means errors if you pass this, IGN means it's ignored on update". The TypeScript type does not enforce any of this. +### 11. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitorRequest`) +- **Why weird:** Every field on `CreateMonitorRequest` / `UpdateMonitorRequest` / `DataMonitorInfo` has a prefix annotation in its JSDoc — `[Create:REQ Update:REQ]`, `[Create:OPT Update:OPT]`, `[Create:ERR Update:IGN]` — that encodes per-operation requirement semantics in the comment. These are generator markers, not human-friendly. A user opening the JSDoc tooltip sees `[Create:ERR Update:IGN]` and must decode "ERR means errors if you pass this, IGN means it's ignored on update". The TypeScript type does not enforce any of this. - **Category:** 6 (misleading — comment marker pretends to be authoritative but is not enforced), 18 (long, noisy comment prefix). -- **Suggested name:** Remove the markers from comments. Encode the semantics in the type (separate `CreateMonitor` vs `UpdateMonitor` vs `Monitor` types with the right optionality and field presence). +- **Suggested name:** Remove the markers from comments. Encode the semantics in the type (separate `CreateMonitorRequest` vs `UpdateMonitorRequest` vs `Monitor` types with the right optionality and field presence). - **Rationale:** Doc markers are not type-checked. They look like type annotations but are inert. -### 14. `latestMonitorFailureMsg` — `src/v1/model.ts:164,263,473` +### 12. `latestMonitorFailureMsg` — `src/v1/model.ts:164,263,473` - **Why weird:** Three problems in one field name. (a) `Msg` is an abbreviation for `Message` — sister field on `RefreshInfo` is `message` (full word), and `dataquality.DataProfilingConfig` uses `latestMonitorFailureMessage` (full word). Inconsistency within the SDK. (b) `Monitor` is in the path — `monitor.latestMonitorFailureMsg` repeats "monitor". (c) The field is documented as `[Create:ERR Update:IGN]` (read-only, server-populated), but the type does not mark it. - **Category:** 5 (cryptic abbreviation — `Msg`), 7 (overly verbose), 8 (redundant `Monitor` in path), 17 (inconsistent with sibling `message` and with `dataquality`). - **Suggested name:** `latestFailureMessage`. - **Rationale:** Full word, no redundant prefix; matches `dataquality`. -### 15. `profileMetricsTableName` and `driftMetricsTableName` — `src/v1/model.ts:166,168,265,267,475,477` +### 13. `profileMetricsTableName` and `driftMetricsTableName` — `src/v1/model.ts:166,168,265,267,475,477` - **Why weird:** Pair of fields with the suffix `TableName`. Sibling Zod field is `profile_metrics_table_name` — six tokens on the wire. JSDoc on both: identical except for the leading noun. The naming pattern is consistent within the pair but verbose. Compare with `dataquality.DataProfilingConfig.{profileMetricsTableName, driftMetricsTableName}` (same names — at least consistent across packages). - **Category:** 7 (overly verbose). - **Suggested name:** `profileMetricsTable` / `driftMetricsTable` (drop `Name` — these are reference fields, not column names). - **Rationale:** "Table" is sufficient context. -### 16. `outputSchemaName` field — `src/v1/model.ts:116,215,425` +### 14. `outputSchemaName` field — `src/v1/model.ts:116,215,425` - **Why weird:** JSDoc says "Schema where output tables are created. Needs to be in 2-level format `{catalog}.{schema}`." So `outputSchemaName` is a two-part UC reference, not just a name. Sister field `baselineTableName` is a three-part UC reference; `tableName` is also three-part. The naming gives no cue about which "name" shape applies. - **Category:** 19 (underspecified — name vs full name vs two-part), 15 (generic name). - **Suggested name:** `outputSchemaFullName` (matches UC vocabulary; the value is `catalog.schema`). - **Rationale:** The "Name" suffix is ambiguous in UC contexts where the term `FullName` is reserved for fully qualified references. -### 17. `assetsDir` — `src/v1/model.ts:121,220,430` +### 15. `assetsDir` — `src/v1/model.ts:121,220,430` - **Why weird:** Identical to `dataquality.DataProfilingConfig.assetsDir` (audit #12 in that package). `assets` is generic ("which assets?"), and `Dir` is an abbreviation. JSDoc says "absolute path to a custom directory to store data-monitoring assets". - **Category:** 1 (vague), 5 (cryptic abbreviation — `Dir`). - **Suggested name:** `assetsDirectory` or `monitoringAssetsPath`. - **Rationale:** Same as `dataquality` #12. -### 18. `slicingExprs` — `src/v1/model.ts:144,243,453` +### 16. `slicingExprs` — `src/v1/model.ts:144,243,453` - **Why weird:** Identical to `dataquality.DataProfilingConfig.slicingExprs` (audit #25 in that package). `Exprs` truncates "Expressions". - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `slicingExpressions` (or, for clarity, `columnSlicingExpressions`). - **Rationale:** Same as `dataquality` #25. -### 19. `skipBuiltinDashboard` (negative boolean) — `src/v1/model.ts:109` +### 17. `skipBuiltinDashboard` (negative boolean) — `src/v1/model.ts:109` - **Why weird:** Same pattern as `dataquality.DataProfilingConfig.skipBuiltinDashboard` (audit #11 in that package). Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. - **Category:** 6 (misleading), 13 (verb-tense — `skip` is action-y, field is state-y). - **Suggested name:** `disableBuiltinDashboard` or invert to `createBuiltinDashboard: boolean`. - **Rationale:** Same as `dataquality` #11. -### 20. `baselineTableName` — `src/v1/model.ts:152,251,461` -- **Why weird:** A three-part UC reference (per JSDoc: "Baseline table name") but the name says only `Name`. Same shape concern as #17. +### 18. `baselineTableName` — `src/v1/model.ts:152,251,461` +- **Why weird:** A three-part UC reference (per JSDoc: "Baseline table name") but the name says only `Name`. Same shape concern as #14. - **Category:** 19 (underspecified ID — wire-side three-part name, not flagged as such). - **Suggested name:** `baselineTableFullName`. - **Rationale:** UC vocabulary uses `FullName` for three-part references. -### 21. `tableName` — `src/v1/model.ts:160,259,469` +### 19. `tableName` — `src/v1/model.ts:160,259,469` - **Why weird:** Three-part UC reference per JSDoc ("UC table to monitor. Format: `catalog.schema.table_name`"), but the name says only `Name`. Compare with `fullTableNameArg` on the same types — *two* fields representing essentially the same UC table reference, one called `tableName` (`[Create:ERR Update:IGN]`) and one called `fullTableNameArg` (the URL path param). This is the same data appearing under two field names in the same interface. - **Category:** 12 (duplicate concept — two fields for the same table reference), 19 (underspecified — three-part wire format hidden behind `Name`). - **Suggested name:** Drop one of the two. If `tableName` (the body field) is truly read-only and copied from the URL path, remove it. Otherwise, rename to `tableFullName`. - **Rationale:** Having both `tableName` and `fullTableNameArg` in the same type forces a caller to choose which to populate. -### 22. `dashboardId` is read-only at create, optional at update — `src/v1/model.ts:173,272,482` -- **Why weird:** JSDoc reads `[Create:ERR Update:OPT]`, meaning the field errors if set on create but is optional on update. Type marks both as optional. A caller writing `createMonitor({dashboardId: 'x', ...})` gets a runtime error from the API but no type-time signal. Same pattern as #14 in general; called out separately because `dashboardId` is one of the most likely fields to be mistakenly set. +### 20. `dashboardId` is read-only at create, optional at update — `src/v1/model.ts:173,272,482` +- **Why weird:** JSDoc reads `[Create:ERR Update:OPT]`, meaning the field errors if set on create but is optional on update. Type marks both as optional. A caller writing `createMonitor({dashboardId: 'x', ...})` gets a runtime error from the API but no type-time signal. Same pattern as #12 in general; called out separately because `dashboardId` is one of the most likely fields to be mistakenly set. - **Category:** 6 (misleading optionality). -- **Suggested name:** Move `dashboardId` out of `CreateMonitor` entirely. Keep in `UpdateMonitor` and `DataMonitorInfo`. +- **Suggested name:** Move `dashboardId` out of `CreateMonitorRequest` entirely. Keep in `UpdateMonitorRequest` and `DataMonitorInfo`. - **Rationale:** Type-level enforcement of "ERR" semantics. -### 23. `monitorVersion: number` — `src/v1/model.ts:179,278,488` -- **Why weird:** Field name says "monitor version" but on a type called `CreateMonitor` / `UpdateMonitor` / `DataMonitorInfo`, the `monitor` part is dead context. JSDoc also notes the field "has flexibility to take on negative values, which can indicate corrupted monitor_version numbers" — using a magic-value (negative) to indicate corruption is a code smell (the type should be `number | 'corrupted'` or split into `version: number` + `corrupted: boolean`). +### 21. `monitorVersion: number` — `src/v1/model.ts:179,278,488` +- **Why weird:** Field name says "monitor version" but on a type called `CreateMonitorRequest` / `UpdateMonitorRequest` / `DataMonitorInfo`, the `monitor` part is dead context. JSDoc also notes the field "has flexibility to take on negative values, which can indicate corrupted monitor_version numbers" — using a magic-value (negative) to indicate corruption is a code smell (the type should be `number | 'corrupted'` or split into `version: number` + `corrupted: boolean`). - **Category:** 7 (overly verbose — `monitor` in path), 6 (misleading — magic-value encoding of corruption state). - **Suggested name:** `version: number`. - **Rationale:** Field path already gives Monitor context. -### 24. `warehouseId` only on `CreateMonitor` and `RegenerateDashboard`, not on `DataMonitorInfo` — `src/v1/model.ts:114,384` +### 22. `warehouseId` only on `CreateMonitorRequest` and `RegenerateDashboardRequest`, not on `DataMonitorInfo` — `src/v1/model.ts:114,384` - **Why weird:** `warehouseId` is an input-only field for picking a SQL warehouse to render the dashboard. Not on the response (`DataMonitorInfo`) — so a caller has no way to see which warehouse was actually chosen if they left this blank. Sibling `dataquality.DataProfilingConfig` has both `warehouseId` (input) and `effectiveWarehouseId` (output) — the latter is missing here. Inconsistent across two near-identical packages. - **Category:** 17 (inconsistent — input-only vs input+output across sibling packages). - **Suggested name:** Add `effectiveWarehouseId` to `DataMonitorInfo` to match `dataquality`. - **Rationale:** Cross-package parity. -### 25. `Notifications` vs `dataquality.NotificationSettings` — `src/v1/model.ts:352` +### 23. `Notifications` vs `dataquality.NotificationSettings` — `src/v1/model.ts:352` - **Why weird:** Sister package uses `NotificationSettings`; this package uses just `Notifications`. The plural noun is fine, but the sister naming differs. Also: only one nested type, `Destination` (vs `dataquality.NotificationDestination`) — again one is shorter and one is longer. - **Category:** 17 (inconsistent — sibling package uses different type names for the same concept). - **Suggested name:** Pick one: either `Notifications` + `Destination` (this package's form) or `NotificationSettings` + `NotificationDestination` (sibling's form), and apply uniformly across both packages. - **Rationale:** Consistency across sibling packages. -### 26. `Destination` — `src/v1/model.ts:292` +### 24. `Destination` — `src/v1/model.ts:292` - **Why weird:** The `Destination` type holds only `emailAddresses?: string[]`. Naming a type for an email recipient list as `Destination` is generic. Compare with sister `dataquality.NotificationDestination` which has the same shape. The name `Destination` reads as "a place"; the content is "a list of email addresses". - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `EmailDestination` (matches content), or merge with `Notifications` if there's only one channel. - **Rationale:** Generic noun for a specific data shape. -### 27. `onNewClassificationTagDetected` field — `src/v1/model.ts:356` +### 25. `onNewClassificationTagDetected` field — `src/v1/model.ts:356` - **Why weird:** Five-word field name (`on` + `New` + `Classification` + `Tag` + `Detected`) — past-tense verb at the end of a noun phrase. The doc says "Destinations to send notifications on new classification tag detected." The grammatical structure is awkward English. Sister `Notifications.onFailure` is concise (two words, no verb tense problem). - **Category:** 7 (overly verbose), 13 (verb tense — past-participle at the end of a field name). - **Suggested name:** `onNewClassificationTag` (drop `Detected`; the field is on `Notifications` so the verb is implicit). - **Rationale:** Length and clarity. The `Detected` adds no information. -### 28. `Notifications.onFailure: Destination` — `src/v1/model.ts:354` +### 26. `Notifications.onFailure: Destination` — `src/v1/model.ts:354` - **Why weird:** Field name says only "failure"; the comment hints at more ("notifications on failure/timeout") — same caveat as `dataquality.NotificationSettings.onFailure` (audit #33 in that package). Field name and JSDoc disagree on whether timeouts are included. - **Category:** 1 (vague), 17 (inconsistent doc/name). - **Suggested name:** `onFailureOrTimeout` (matches doc) or `onFailure` (matches name; update doc). - **Rationale:** Same as `dataquality` #33. -### 29. `Notifications` field name uses plural but each value is a single `Destination` — `src/v1/model.ts:352-357` +### 27. `Notifications` field name uses plural but each value is a single `Destination` — `src/v1/model.ts:352-357` - **Why weird:** The type is plural (`Notifications`) but each field (`onFailure`, `onNewClassificationTagDetected`) holds a single `Destination`, not an array. The plural-vs-singular doesn't match the content. Compare: `dataquality.NotificationSettings` (singular type, singular fields). - **Category:** 9 (singular/plural mismatch — type plural, content singular). - **Suggested name:** `NotificationSettings` (matches `dataquality`). - **Rationale:** Same as `dataquality` parity. -### 30. `InferenceLogAnalysisConfig.problemType: ProblemType` — `src/v1/model.ts:314` -- **Why weird:** Field name does not say "ML"; type is the generic `ProblemType` (#7). The reader has no cue from the field name that this is ML-specific. +### 28. `InferenceLogAnalysisConfig.problemType: ProblemType` — `src/v1/model.ts:314` +- **Why weird:** Field name does not say "ML"; type is the generic `ProblemType` (#5). The reader has no cue from the field name that this is ML-specific. - **Category:** 1 (vague — `problemType` alone is generic). -- **Suggested name:** `mlProblemType: MlProblemType` (or rely on rename of the enum to `InferenceProblemType` per #7). +- **Suggested name:** `mlProblemType: InferenceProblemType` (relying on rename of the enum per #5). - **Rationale:** Disambiguate from generic English meaning. -### 31. `predictionProbaCol` — `src/v1/model.ts:326` +### 29. `predictionProbaCol` — `src/v1/model.ts:326` - **Why weird:** `Proba` is a Python ML idiom for "probability" — sklearn `predict_proba` etc. In a TS API, the name leaks the upstream Python convention. JSDoc says "Column for prediction probabilities" — uses the full word. - **Category:** 5 (cryptic Python-ML abbreviation), 14 (foreign-ecosystem idiom). - **Suggested name:** `predictionProbabilityCol` (or `predictionProbabilitiesCol`). - **Rationale:** Python's `predict_proba` is sklearn vocabulary; a TS SDK should not require knowing sklearn to read field names. -### 32. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` +### 30. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` - **Why weird:** `Col` is an abbreviation for `Column`. Five fields on `InferenceLogAnalysisConfig` use it. Same in `TimeSeriesAnalysisConfig.timestampCol`. TS has no length constraint. - **Category:** 5 (cryptic abbreviation — `Col`). - **Suggested name:** `timestampColumn`, `predictionColumn`, `labelColumn`, `modelIdColumn`, `predictionProbabilityColumn`. - **Rationale:** Full words; matches `dataquality.InferenceLogConfig` if that package has the same pattern (worth cross-checking). -### 33. `modelIdCol` — `src/v1/model.ts:324` +### 31. `modelIdCol` — `src/v1/model.ts:324` - **Why weird:** `Id` ambiguity flagged across the SDK. `modelIdCol` — the column in the user's table that holds a model identifier — could be any UC ID or a free-form model version string. JSDoc says only "Column for the model identifier." - **Category:** 19 (underspecified ID — what *kind* of model ID?). - **Suggested name:** Document, or rename to `modelVersionColumn` if that is what the wire expects. - **Rationale:** "Model ID" in Databricks could mean MLflow run ID, MLflow model version, registered model name, or a customer-chosen string. -### 34. `MonitorCronSchedule` vs `dataquality.CronSchedule` — `src/v1/model.ts:343` +### 32. `MonitorCronSchedule` vs `dataquality.CronSchedule` — `src/v1/model.ts:343` - **Why weird:** Same wire shape, different type names. Sister `dataquality.CronSchedule` drops the `Monitor` prefix. The prefix here is dead context — this type only ever lives on a `Monitor`. - **Category:** 8 (redundant prefix — `Monitor` is in the access path). - **Suggested name:** `CronSchedule` (matches `dataquality`). - **Rationale:** Cross-package consistency. -### 35. `quartzCronExpression` (leaks library name) — `src/v1/model.ts:345` +### 33. `quartzCronExpression` (leaks library name) — `src/v1/model.ts:345` - **Why weird:** Same as `dataquality.CronSchedule.quartzCronExpression` (audit #30 in that package). `Quartz` is a Java scheduling library; users do not need to know that. - **Category:** 14 (implementation-detail leak). - **Suggested name:** `cronExpression`. - **Rationale:** Same as `dataquality` #30. -### 36. `timezoneId` — `src/v1/model.ts:347` +### 34. `timezoneId` — `src/v1/model.ts:347` - **Why weird:** Same as `dataquality.CronSchedule.timezoneId` (audit #30 in that package). `Id` for what is in fact an IANA timezone name (e.g., `America/New_York`) — the field is a tz name, not an "ID" in the database sense. - **Category:** 19 (misnamed — calling a tz name an `Id`), 5 (jargon). - **Suggested name:** `timezone` (matches JS-standard `Intl.DateTimeFormat.timeZone`). @@ -254,61 +246,61 @@ Three packages in this repository overlap on the same domain at the wire level: ## Low severity -### 37. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 35. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `dataquality` audit #35. Helper exported but never called from `client.ts`. - **Category:** 6 (misleading — looks used; isn't). - **Suggested name:** N/A — unexport. - **Rationale:** Dead exported surface. -### 38. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +### 36. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Same as `dataquality` audit #36. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from names. -### 39. `buildHttpRequest` — `src/v1/utils.ts:96` +### 37. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataquality` audit #37 — "build" hints at builder pattern, function spreads literals. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the reality. -### 40. `readAll` — `src/v1/utils.ts:40` +### 38. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Same as `dataquality` audit #39. "ReadAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing. -### 41. `HttpCallOptions` — `src/v1/utils.ts:15` +### 39. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataquality` audit #40. Internal context bag named `Options` — collides with the public `CallOptions` / `ClientOptions` semantics. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 42. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` +### 40. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` - **Why weird:** Same as `dataquality` audit #41. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Domain-word missing. -### 43. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,133,174,214,252,290,330,373,415` +### 41. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,136,177,220,258,296,339,382,424` - **Why weird:** Same as `dataquality` audit #42. Variable `call: Call` in 9 methods. - **Category:** 1, 12. - **Suggested name:** `request` (variable). - **Rationale:** Type/variable collision. -### 44. `respBody` vs `resp` — every method in `client.ts` +### 42. `respBody` vs `resp` — every method in `client.ts` - **Why weird:** Same as `dataquality` audit #44. Two variables differ only by `Body`. - **Category:** 5, 17. - **Suggested name:** `rawBody` + `result`. - **Rationale:** Distinguish by meaningful nouns. -### 45. `httpReq` local — every method in `client.ts` +### 43. `httpReq` local — every method in `client.ts` - **Why weird:** Same as `dataquality` audit #45. - **Category:** 5, 12. - **Suggested name:** `httpRequest`. - **Rationale:** No abbreviation. -### 46. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,130,172,212,250,288,327,370,412` +### 44. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,133,175,218,256,294,336,379,421` - **Why weird:** Same as `dataquality` audit #43. `fullTableNameArg` typed optional but required in practice; silent empty-string substitution yields URLs like `/api/2.1/unity-catalog/tables//monitor`. - **Category:** 6. - **Suggested name:** Make `fullTableNameArg` non-optional on every request type. @@ -316,25 +308,25 @@ Three packages in this repository overlap on the same domain at the wire level: ## Observations -### 47. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" +### 45. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" - **Note:** All 9 client methods (`cancelRefresh`, `createMonitor`, `deleteMonitor`, `getMonitor`, `getRefresh`, `listRefreshes`, `regenerateDashboard`, `runRefresh`, `updateMonitor`) start their JSDoc with that sentence. None uses the `@deprecated` JSDoc tag, so editors do not render the deprecation visually. The package is deprecated in spirit, but live in build. -### 48. Acronym casing +### 46. Acronym casing - `Id` (capital-then-lower in `refreshId`, `dashboardId`, `warehouseId`, `monitorVersion`); `Ms` (`startTimeMs`, `endTimeMs`); `Http` (in imported types). No within-package collisions, all generator-emitted. - **Category:** 3 (acronym casing). -### 49. URL paths mix `unity-catalog` and `quality-monitoring` +### 47. URL paths mix `unity-catalog` and `quality-monitoring` - **Note:** Eight of nine methods use `/api/2.1/unity-catalog/tables/{}/monitor[/...]`; one (`regenerateDashboard`) uses `/api/2.1/quality-monitoring/tables/{}/monitor/dashboard`. The package name does not match either prefix. The sister `dataquality` package uses `/api/data-quality/v1/monitors`. - **Category:** 17 (inconsistent — package name vs wire path). -### 50. No `FieldMask` types +### 48. No `FieldMask` types - This package does not have any `FieldMask<...>` types (unlike `dataquality`). The deprecated API does not support partial updates via field masks; the entire monitor body is replaced on `PUT`. (Listed as observation to contrast with sibling packages.) -### 51. Verb consistency +### 49. Verb consistency - `Cancel`, `Create`, `Delete`, `Get`, `List`, `Regenerate`, `Run`, `Update` — eight different verbs in nine methods. Within the package the verbs are appropriate and consistent. The unusual one is `Regenerate` (vs `Recreate` or `RebuildDashboard`) — generator-driven choice, fine in context. - **Category:** 17 (verb inventory, none inconsistent). -### 52. `Notifications` is a slim type with two channel fields +### 50. `Notifications` is a slim type with two channel fields - Two-channel `Notifications` (`onFailure`, `onNewClassificationTagDetected`) follows the proto shape. A TS-idiomatic shape might be `notifications: Array<{channel: 'failure' | 'newClassificationTag', destination: Destination}>` to allow future expansion. Listed as observation, not a flag. ## Domain glossary @@ -355,6 +347,14 @@ Three packages in this repository overlap on the same domain at the wire level: ## File coverage - `src/v1/model.ts` (935 lines): read fully. -- `src/v1/client.ts` (433 lines): read fully. +- `src/v1/client.ts` (441 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (39 lines): read fully. + +## Fixed + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. + + \ No newline at end of file diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index de864ef8..816bf63f 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 35 +**Total weird names flagged:** 35 (last rescanned 2026-05-22) ## Summary table @@ -22,16 +22,16 @@ | 11 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | | 12 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | | 13 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | -| 14 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | -| 15 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | -| 16 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | -| 17 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 18 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | -| 19 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | -| 20 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | -| 21 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | -| 22 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | -| 23 | Medium | `model.ts` enum values | `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` | Redundant enum prefix (enum already named `DatePrecision`) | +| 14 | High | `model.ts` interface | `Empty` | Proto architectural leak — `google.protobuf.Empty` surfaced as a TS export | +| 15 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 16 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 17 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 18 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 19 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | +| 20 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | +| 21 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | +| 22 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | +| 23 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | | 24 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | | 25 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | | 26 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | @@ -100,7 +100,7 @@ There is no obvious entry point for "I want to run a SQL query" — the user has ### 5. `LifecycleState.TRASHED` vs method `trashQuery` — verb/state inconsistency -**Location:** `src/v1/model.ts:14-17`, `src/v1/client.ts:227-249` +**Location:** `src/v1/model.ts:14-17`, `src/v1/client.ts:228-250` ```ts export enum LifecycleState { @@ -245,11 +245,32 @@ export interface Query { Both the field name and the JSDoc embed the word "query" on a type called `Query`. The field exists on four near-identical interfaces (see #2), so the redundancy multiplies. The same field is the *only* part of `Query` that is actually a SQL statement — pulling it up as `Query.text` or `Query.sql` would simplify both name and doc. +### 14. `Empty` — proto architectural leak + +**Location:** `src/v1/model.ts:133-138` + +```ts +/** + * Represents an empty message, similar to google.protobuf.Empty, which is not available in the firm + * right now. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface Empty {} +``` + +**Why:** Proto/RPC architectural leak — `google.protobuf.Empty` is a wire-format construct used by code generators to express "no body." The JSDoc explicitly admits this ("similar to google.protobuf.Empty"). Exporting it as a public TS interface forces every `Promise` return type (e.g. `trashQuery`, see #15) to surface the proto abstraction to callers. + +**Category:** Proto architectural leak. + +**Suggested:** Drop the type entirely; have methods return `Promise`. If a placeholder is needed, do not export it — TS already has `void` and `undefined` as native equivalents. + +**Rationale:** `Empty` exists only because protobuf has no native "no return value" concept. TypeScript does. Surfacing the proto workaround as a named export pollutes the package's public API with a wire-format artefact that has no domain meaning. Users see `Promise` and reasonably ask "what's in `Empty`?" — the answer is "nothing, it's a proto thing." That answer should never be visible. + ## Medium severity -### 14. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) +### 15. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) -**Location:** `src/v1/client.ts:227-250` +**Location:** `src/v1/client.ts:228-250` ```ts /** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, and cannot be used for alerts. You can restore a trashed query through the UI. A trashed query is permanently deleted after 30 days. */ @@ -261,7 +282,7 @@ async trashQuery( The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 15. `TrashQueryRequest` — same as #14, in the type layer +### 16. `TrashQueryRequest` — same as #15, in the type layer **Location:** `src/v1/model.ts:312-314` @@ -273,9 +294,9 @@ export interface TrashQueryRequest { Same verb inconsistency at the type layer. Carries only `id`. -### 16. `listVisualizationsForQuery` — overly verbose +### 17. `listVisualizationsForQuery` — overly verbose -**Location:** `src/v1/client.ts:173-208` +**Location:** `src/v1/client.ts:174-208` ```ts async listVisualizationsForQuery( @@ -286,7 +307,7 @@ async listVisualizationsForQuery( `For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. -### 17. `Visualization` — vague/generic top-level name +### 18. `Visualization` — vague/generic top-level name **Location:** `src/v1/model.ts:360-377` @@ -296,7 +317,7 @@ export interface Visualization { ... } `Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. -### 18. `Query.warehouseId` — underspecified ID +### 19. `Query.warehouseId` — underspecified ID **Location:** `src/v1/model.ts:66-67`, `172-173`, `232-233`, `333-334` @@ -307,7 +328,7 @@ warehouseId?: string | undefined; The JSDoc says "SQL warehouse"; the field says `warehouseId`. Databricks has data warehouses, Lakehouse, SQL warehouses, etc. `sqlWarehouseId` would self-document. -### 19. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar +### 20. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar **Location:** `src/v1/model.ts:64-65`, `74-75` @@ -321,7 +342,7 @@ lastModifierUserName?: string | undefined; `owner` is a noun. `lastModifier` is an agent noun constructed from the verb "modify." The pairing is mismatched — either both should be agent nouns (`ownerUserName`, `lastModifierUserName`) or both should be participial (`ownedBy`, `lastModifiedBy`). The Go convention is the former; idiomatic TS leans toward the latter. Also note the JSDoc inconsistency: "the user that owns" vs "the user who last saved" — different relative pronouns. -### 20. `Query.lastModifierUserName` — overly verbose +### 21. `Query.lastModifierUserName` — overly verbose **Location:** `src/v1/model.ts:74-75` @@ -331,13 +352,13 @@ lastModifierUserName?: string | undefined; 21 characters for what is, semantically, "last-modified-by." `lastModifiedBy` is 14 characters and more natural English. -### 21. `LifecycleState.TRASHED` — verb-tense inconsistency +### 22. `LifecycleState.TRASHED` — verb-tense inconsistency **Location:** `src/v1/model.ts:14-17` The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). -### 22. `RunAsMode` — verb-as-noun, filler `Mode` +### 23. `RunAsMode` — verb-as-noun, filler `Mode` **Location:** `src/v1/model.ts:19-22` @@ -350,20 +371,6 @@ export enum RunAsMode { `RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. -### 23. `DatePrecision.DAY_PRECISION`, `MINUTE_PRECISION`, `SECOND_PRECISION` — redundant enum prefix - -**Location:** `src/v1/model.ts:8-12` - -```ts -export enum DatePrecision { - DAY_PRECISION = 'DAY_PRECISION', - MINUTE_PRECISION = 'MINUTE_PRECISION', - SECOND_PRECISION = 'SECOND_PRECISION', -} -``` - -Access is `DatePrecision.DAY_PRECISION` — the enum name already says "precision." `DAY`/`MINUTE`/`SECOND` would suffice. - ### 24. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... **Location:** `src/v1/model.ts:25-42` @@ -476,7 +483,7 @@ startDayOfWeek?: number | undefined; ### 33. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency -**Location:** `src/v1/model.ts:58-59`, `362-363`, `262-263` +**Location:** `src/v1/model.ts:224-225`, `361-362`, `262-263` Top-level types use bare `id`; cross-referencing types use `queryId`. `Query.queryId` would be consistent with `Visualization.queryId` and `QueryBackedValue.queryId`. Currently `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` means there are two conventions side-by-side. diff --git a/.agent/naming-audit/queryexecution.md b/.agent/naming-audit/queryexecution.md index baccb52a..65bb2af4 100644 --- a/.agent/naming-audit/queryexecution.md +++ b/.agent/naming-audit/queryexecution.md @@ -1,5 +1,9 @@ # Naming Audit: queryexecution +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `packages/queryexecution/src/v1/` **Versions audited:** v1 **Inferred domain:** Execute, cancel, and poll SQL queries for *published, embedded @@ -9,205 +13,31 @@ GET = poll, DELETE = cancel). The package name (`queryexecution`) is much broade what it actually does (lakeview-dashboard query lifecycle). Confusing overlap with sibling packages `statementexecution` (general SQL Statement Execution API), `queryhistory` (history of executed queries), and `queries` (saved query definitions). -**Total weird names flagged:** 30 +**Total weird names flagged:** 0 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 12 | -| Low | 8 | -| Observation | 4 | +| High | 0 | +| Medium | 0 | +| Low | 0 | +| Observation | 0 | ## High severity -### 1. Package name `queryexecution` is far broader than its scope — `package.json`, directory name -- **Why weird:** The package operates exclusively on *published, embedded Lakeview dashboards* (see every JSDoc and the URL `/api/2.0/lakeview-query/query/published`). A user importing `@databricks/sdk-queryexecution` would reasonably expect general "query execution" — i.e. `statementexecution`, which is the SDK's actual general-purpose SQL execution API. The two packages have wildly different scopes but near-identical names. -- **Category:** 1 (vague — `queryexecution` is the generic term), 6 (misleading — implies general query API, is dashboard-scoped), 12 (duplicate concept — overlaps `statementexecution` and `queryhistory`). -- **Suggested name:** `lakeviewquery` or `publisheddashboardquery` or fold into `lakeview`/`dashboards` packages. If staying separate, every type name should be prefixed `PublishedDashboard*` to make scope obvious. -- **Rationale:** The first and most damaging naming problem here is that the package name promises a generic capability and silently delivers a specialised one. Compare: `commandexecution` (executes Python/SQL via REPL) vs. `statementexecution` (executes SQL via SQL Warehouse) vs. `queryexecution` (re-runs *already-saved* queries inside *published* dashboards). A user looking at the three would have to read every method to know which one they want. - -### 2. `CancelQueryExecutionResponse` / `CancelQueryExecutionResponseStatus` vs. request `CancelPublishedQueryExecutionRequest` — `src/v1/model.ts:11,18,22` -- **Why weird:** The request type prefixes `Published` (correctly identifying the scope) but the two response types drop the prefix. The package only handles published-dashboard cancels, yet the type names alternate between `*PublishedQueryExecution*` and `*QueryExecution*` for what is fundamentally the same operation. The asymmetric stripping suggests the response types are reused, but they aren't — there is only one cancel endpoint. -- **Category:** 6 (misleading — strips the `Published` qualifier from response types), 12 (duplicate concept — looks like two unrelated cancel APIs), 17 (asymmetric request/response naming). -- **Suggested name:** `CancelPublishedQueryResponse` / `CancelPublishedQueryResponseStatus` (or drop `Published` from both for consistency, since the whole package is scoped to published dashboards). -- **Rationale:** Symmetric request/response pairs are the SDK norm (`CreateCatalogConfigRequest`/`CreateCatalogConfigResponse` etc.). The mismatch here suggests that the response types might be shared, which they aren't, and forces callers to mentally translate between two near-identical names. - -### 3. `ExecutePublishedDashboardQueryRequest` vs. `ExecuteQueryResponse` — `src/v1/model.ts:46,58` -- **Why weird:** Asymmetric naming: the request name says "Execute **Published Dashboard** Query", while the response is the generic `ExecuteQueryResponse`. A user reading just the model file would think `ExecuteQueryResponse` is some shared type used by multiple Execute*Request types, but it's only used here. -- **Category:** 6 (misleading — response name doesn't match request), 12 (duplicate concept). -- **Suggested name:** `ExecutePublishedQueryResponse` (matching scope). -- **Rationale:** The asymmetric prefix forces callers to mentally translate between two near-identical names. Symmetric request/response pairs are the SDK norm. - -### 4. `PollQueryStatusResponse.data` — `src/v1/model.ts:82` -- **Why weird:** Top-level field named `data` on a response object. `data` is the most generic possible field name (rule 15 in the prompt: "Generic field names losing meaning"). It happens to hold *per-token statuses*, but the name gives a reader zero hint of that. -- **Category:** 1 (vague), 15 (generic field name losing meaning). -- **Suggested name:** `statuses` (plural, matches the array shape) or `tokenStatuses`. -- **Rationale:** `data` should never be the name of the only field on a response. The wire calls it `data`, but a TS SDK can do better. - -### 5. `QueryResponseStatus` vs. `CancelQueryExecutionResponseStatus` — `src/v1/model.ts:22,89` -- **Why weird:** Two near-identical types differ only by the verbs they accept (`CancelQueryExecutionResponseStatus` has `success`/`pending`, `QueryResponseStatus` has `success`/`pending`/`canceled`/`closed`). Both wrap discriminated unions over the same vocabulary. They could be unified by making the cancel response use a subset of `QueryResponseStatus`. The fact that the names are *different but parallel* makes the duplication harder to spot. -- **Category:** 12 (duplicate concept — two types modelling the same idea), 17 (inconsistent action-verb prefix — one uses `Cancel*ResponseStatus`, the other uses `*ResponseStatus`). -- **Suggested name:** Collapse into one `QueryResponseStatus`, drop the `Cancel*ResponseStatus` and use the unified type with only the arms that apply. -- **Rationale:** Two types with the same purpose is a maintenance hazard. The names actively conceal the duplication by spelling things differently. - -### 6. `Client` class name — `src/v1/client.ts:41` -- **Why weird:** A class literally named `Client` at the top level of the package's API surface, re-exported as just `Client`. Identical to `dataclassification.md` Finding #11 and a repeated pattern across the SDK. A user importing `Client` from `@databricks/sdk-queryexecution` and another `Client` from `@databricks/sdk-statementexecution` collides on the namespace. -- **Category:** 1 (vague — `Client` is the most generic name possible), 15 (generic name). -- **Suggested name:** `QueryExecutionClient` (or, per #1, `PublishedDashboardQueryClient`). -- **Rationale:** Same as the cross-SDK pattern: every API package has a `Client`, and combined imports require renaming. The collision risk grows with each added package. +_None._ ## Medium severity -### 7. `PendingStatus` and `SuccessStatus` types — `src/v1/model.ts:60,105` -- **Why weird:** Two types share the `Status` suffix, but only one of them ("Success") carries the `truncated` boolean. Their names suggest they are siblings of an enum (`Pending` vs `Success`), but `Pending` only has `dataToken`, while `Success` has `dataToken` + `truncated`. This means the *only* thing that distinguishes a "success" from a "pending" at the type level is the *presence* of `truncated` — but since `truncated` is `optional`, neither type's instance can be reliably distinguished from the other. -- **Category:** 6 (misleading — types are technically distinguishable but in practice not), 16 (field contradicts type domain — `truncated` is meaningless on `Pending` but exists structurally), 17 (asymmetric). -- **Suggested name:** Keep names but make `truncated` required (non-optional) on `SuccessStatus`, or merge them: `interface QueryToken { dataToken?: string; truncated?: boolean }` with the state encoded by the discriminator only. -- **Rationale:** When two state-variant types differ only by one optional field, they shouldn't be separate types. - -### 8. `dataToken` field — `src/v1/model.ts:27,65,110` -- **Why weird:** The field is described inline as "The token to poll for result asynchronously". The name `dataToken` doesn't communicate that — it sounds like a token that wraps data. The JSDoc even admits that `data_token` and `statement_id` (in the parent type) are the *same value* on the wire ("The statement_id should be identical to data_token in SuccessStatus and PendingStatus."). The fact that the wire has two names for the same value (one is the polling cursor, the other is the audit-log identifier) is a wire-protocol decision that leaks into the TS surface. -- **Category:** 1 (vague — `dataToken` could mean anything), 5 (cryptic abbreviation — "data" of what?), 12 (duplicate concept — `dataToken` and `statementId` are the same value), 19 (underspecified ID — see also #9). -- **Suggested name:** `pollToken` or `pollingToken` (matches its purpose). If the duplication with `statementId` is fixed at the wire level, drop entirely. -- **Rationale:** A field whose JSDoc says "this is identical to another field" is screaming for a rename. `pollToken` describes its function; `dataToken` describes its construction. - -### 9. `statementId` field — `src/v1/model.ts:102` -- **Why weird:** A field called `statementId` appearing on `QueryResponseStatus`, accompanied by a 4-line JSDoc explaining that it is "created for audit logging purpose to record the statement_id of all QueryResponseStatus". So this is an audit-only field that duplicates `dataToken`. In a typed API, an audit-only field is something the client should *never* set or rely on — but the type doesn't say `readonly` and there's no convention enforcing that. -- **Category:** 6 (misleading — looks like a regular ID, is audit-only), 12 (duplicate concept), 19 (underspecified — what kind of "statement"? Compare to `statementexecution` package's `statementId` which means the SQL Statement Execution API ID). -- **Suggested name:** `auditStatementId` (or remove from the public surface). If kept, document `@readonly`. -- **Rationale:** Audit/log-only fields on a typed response are a footgun. The current name promises usability; the doc explains it isn't. - -### 10. `tokens` field — `src/v1/model.ts:13,76` -- **Why weird:** Field called `tokens` with example value `EC0A..ChAB7WCEn_4...`. The JSDoc only shows one example; no plural-form documentation. The wire spec apparently allows multiple tokens (since the field is `string[]`), and the SDK serializes the array via `String(req.tokens)` — which means JS does `tokens.join(',')` (the array's default `toString`). This is fragile: if a token ever contains a comma, the URL becomes corrupt. The name `tokens` doesn't communicate "comma-separated on the wire". -- **Category:** 1 (vague — `tokens` of what?), 5 (cryptic — token value example dominates over a description), 6 (misleading — the array-to-string conversion is implicit). -- **Suggested name:** `pollTokens` (matches the proposal in #8). If the wire really expects comma-separated, document that on the field; otherwise use `URLSearchParams.append` per-token. -- **Rationale:** The name `tokens` is too generic for a top-level request field. The hidden join-on-comma is a bug magnet. - -### 11. `dashboardName` field — `src/v1/model.ts:14,51,77` -- **Why weird:** Field is `dashboardName` but appears alongside `dashboardRevisionId`. The pairing `Name` + `Id` is inconsistent — they should be either both names or both IDs. The wire calls the first one `dashboard_name` and the second `dashboard_revision_id`, so the asymmetry is upstream — but a TS SDK could rename for symmetry. The JSDoc says: "Dashboard name and revision_id is required to retrieve PublishedDatasetDataModel". The casual `_id`/`Id` shift is jarring. -- **Category:** 17 (asymmetric pair naming — `Name` vs `Id`). -- **Suggested name:** `dashboardId` + `dashboardRevisionId` (if both are IDs on the wire) or document why one is "name" while the other is "ID". -- **Rationale:** Symmetric pair fields should have symmetric naming. A user looking at the request would assume `Name` is human-readable and `RevisionId` is opaque — but typically both are opaque identifiers in published-dashboard URLs. - -### 12. `overrideWarehouseId` field — `src/v1/model.ts:54` -- **Why weird:** Field name is fine in isolation, but unusual that there is no plain `warehouseId` field for context. The JSDoc explains: "A dashboard schedule can override the warehouse used as compute for processing the published dashboard queries". Reading the model in isolation, a user has no way to know that *not* setting `overrideWarehouseId` means the dashboard's *configured* warehouse is used. The name carries baggage that requires reading the JSDoc to decode. -- **Category:** 1 (vague — "override" of what?), 6 (misleading — implies a write to a property, is actually an optional override). -- **Suggested name:** Keep but make sure the JSDoc is exhaustive about the fallback behaviour. Alternatively `warehouseIdOverride` (English noun order — read "the override of warehouseId"). -- **Rationale:** Override-fields are common; the only fix is documentation. Flagged for consistency. - -### 13. `dashboardRevisionId` field — `src/v1/model.ts:15,52,78` -- **Why weird:** The wire format on the published dashboard URL uses `dashboard_revision_id`. The TS name flatten-converts. But internally this is the "version" of the dashboard, and the broader SDK uses `revision` and `version` inconsistently (e.g., `apps` package uses `currentRevision`, etc.). Verifying SDK-wide vocabulary would be valuable. -- **Category:** 17 (potential inconsistency with sibling SDK packages — flagged for review). -- **Suggested name:** Keep as-is unless a wider SDK convention dictates `version`. -- **Rationale:** Low confidence; flagged to ensure SDK consistency check. - -### 14. `executeCall` / `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Same as `dataclassification.md` Finding #15. Two `execute*` functions for two layers (retry/rate-limit shell vs. actual HTTP). The name `executeCall` doesn't say what about the call is being executed. -- **Category:** 1, 12, 17. -- **Suggested name:** `runWithPolicies` (outer) + `sendHttpRequest` (inner). -- **Rationale:** Generator-wide pattern, fix once. - -### 15. `buildHttpRequest` — `src/v1/utils.ts:96` -- **Why weird:** Same as `dataclassification.md` Finding #16. "Build" implies builder pattern; this is a 16-line object-literal helper used 4× per client method. -- **Category:** 1, 6. -- **Suggested name:** `makeHttpRequest` or inline. -- **Rationale:** Generator-wide. - -### 16. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Same as `dataclassification.md` Finding #20. Generic name for a stream-drain helper. -- **Category:** 1, 5. -- **Suggested name:** `drainStream`. - -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Same as `dataclassification.md` Finding #21. Type called `Options` but is an internal context bag. -- **Category:** 1, 8. -- **Suggested name:** `HttpCallContext`. - -### 18. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` -- **Why weird:** Same as `dataclassification.md` Finding #22. Generic constant name. -- **Category:** 1. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. +_None._ ## Low severity -### 19. `Client` constructor — `src/v1/client.ts:50-64` -- **Why weird:** The constructor accepts `ClientOptions` but doesn't validate the options beyond `host`. Other fields (`logger`, `credentials`) use `??`-default and never warn about missing values. Naming is fine; behaviour is worth flagging for consistency with other SDK packages. -- **Category:** N/A (behavioural). - -### 20. `respBody` vs `resp` locals — `src/v1/client.ts:89,94,121,126,161,166` -- **Why weird:** Same as `dataclassification.md` Finding #26. Stage names are abbreviated and similar. -- **Category:** 5, 17. -- **Suggested name:** `rawBody` + `result`. - -### 21. `httpReq` local — `src/v1/client.ts:88,120,160` -- **Why weird:** Same as `dataclassification.md` Finding #27. Two `req`s in scope: `req: CancelPublishedQueryExecutionRequest` and `httpReq: HttpRequest`. -- **Category:** 5, 12. -- **Suggested name:** `httpRequest` (no abbreviation). - -### 22. `cancelPublishedQueryExecution` method — `src/v1/client.ts:67` -- **Why weird:** The method is verbose (29 characters) and contains the package name `queryExecution` already. Once `Client` is renamed `QueryExecutionClient`, the package context becomes explicit and the method name should shrink to `cancelPublished` or `cancelPublishedQuery`. The current form reads as `QueryExecutionClient.cancelPublishedQueryExecution(...)` — "queryExecution" twice. -- **Category:** 7 (overly verbose), 12 (duplicate concept — `QueryExecution` in both class and method). -- **Suggested name:** `cancelPublishedQuery` (or `cancel` if the package is renamed per #1). - -### 23. `executePublishedDashboardQuery` method — `src/v1/client.ts:107` -- **Why weird:** Same redundancy as #22 — `executePublishedDashboardQuery` repeats the package's domain. After renaming class to `PublishedDashboardQueryClient`, the method should just be `execute`. -- **Category:** 7 (overly verbose). -- **Suggested name:** `execute` (in renamed client) or `executePublishedQuery`. - -### 24. `pollPublishedQueryStatus` method — `src/v1/client.ts:139` -- **Why weird:** Inconsistency: `cancelPublishedQueryExecution` uses `QueryExecution` while `pollPublishedQueryStatus` uses `QueryStatus`. So the cancel-side mirrors the *operation* word, the poll-side mirrors the *response* word. The three method names all sound like sibling operations but use three different stems: - - `cancelPublishedQueryExecution` - - `executePublishedDashboardQuery` - - `pollPublishedQueryStatus` -- **Category:** 17 (inconsistent action-verb stem — three different patterns for three sibling methods). -- **Suggested name:** Make the stem identical: `cancelPublishedQuery` / `executePublishedQuery` / `pollPublishedQueryStatus` (or remove the `Status` suffix to match: `pollPublishedQuery`). - -### 25. `truncated` field on `SuccessStatus` — `src/v1/model.ts:112` -- **Why weird:** Field called `truncated`. The JSDoc says "Whether the query result is truncated (either by byte limit or row limit)". The naming is OK in context, but the field stands alone on `SuccessStatus` and tells the user nothing about *what* limit was hit. Compare: `statementexecution` package uses the same name (`truncated`) with the same vagueness — so the inconsistency is cross-package, not local. -- **Category:** 1 (vague — truncated by what?), 12 (cross-package duplicate of `statementexecution`'s `truncated`). -- **Suggested name:** Document on the type, or split into `truncatedByByteLimit?: boolean` / `truncatedByRowLimit?: boolean`. - -### 26. Lowercase `c` in JSDoc comment opening — `src/v1/model.ts:6,42,68` -- **Why weird:** The JSDoc starts with lowercase: "cancel query request for published Dashboards" (line 6), "Execute query request for published Dashboards" (line 42 — that one starts uppercase, inconsistent), "poll query request..." (line 68). Inconsistent comment style and lowercase sentence openings. Project convention is "Comments should always be proper sentences ending with a period" — these violate it. -- **Category:** N/A (style, not naming) — flagged because the prompt requested "EVERY type, field, ... and method"; the JSDoc affects the type's apparent name. -- **Suggested name:** N/A (fix prose, not name). +_None._ ## Observations -### 27. Cross-package vocabulary drift — `statementexecution` / `queryhistory` / `queries` overlap -- **Description:** Five overlapping concepts span four packages: - - **`statementexecution.StatementStatus_State`** = `PENDING | RUNNING | SUCCEEDED | FAILED | CANCELED | CLOSED` (6 states) - - **`queryexecution.QueryResponseStatus`** = `success | pending | canceled | closed` (4 arms — no `running` or `failed`) - - **`queryhistory.QueryStatus`** = `QUEUED | STARTED | COMPILING | COMPILED | RUNNING | CANCELED | ...` (many more) - - **`statementexecution.statementId`** = SQL Statement Execution API ID - - **`queryexecution.statementId`** = "audit logging" field that duplicates `dataToken` - - **`queryhistory.QueryFilter.statement_ids`** = filter by statement IDs - - Three packages each have a `Status`/`State` enum, none of them compatible, all describing roughly the same SQL execution lifecycle. -- **Category:** 12 (duplicate concepts across packages), 17 (inconsistent vocabulary). -- **Recommendation:** Document the relationship in a shared glossary. Long-term, unify the status types or at least the state names. - -### 28. Vocabulary collision: `query` vs. `statement` vs. `execution` -- **Description:** The SDK uses three near-synonymous nouns: - - **`query`** — appears in `queryexecution`, `queryhistory`, `queries`. Generally means a SQL query (often a saved one). - - **`statement`** — appears in `statementexecution` and as `statementId` in `queryexecution`. Means a SQL statement (the SQL Execution API's unit of work). - - **`execution`** — appended to both above (`queryexecution`, `statementexecution`). - And the wire layer adds a fourth: `lakeview-query` (the URL in this package). -- **Category:** 12 (duplicate concepts), 14 (vocabulary inconsistency). -- **Recommendation:** Pick a vocabulary and use it consistently. SQL Statement Execution API uses "statement"; published dashboard queries use "query". Document the distinction in the SDK README. - -### 29. JSDoc grammar errors / wire-layer leakage -- **Description:** Multiple JSDocs reference internal wire terminology not relevant to a TS user: - - "rpc calls to sql-exec-api" (lines 10, 73 — internal service name) - - "PublishedDatasetDataModel" (line 48 — Java class name) - - "lakeview-config" (line 45 — internal service) - - "google.protobuf.Empty" (line 36 — proto definition leak) -- **Category:** N/A (documentation leakage). -- **Recommendation:** Generator should strip wire-layer references from public JSDoc. - -### 30. Comment style violations -- **Description:** Per the project rule "Comments should always be proper sentences ending with a period", many JSDocs in this file start lowercase ("cancel query request..."), are sentence fragments ("Example: EC0A..."), or omit terminal periods. Generator-wide. -- **Category:** N/A (style). +_None._ ## Domain glossary - **Lakeview** — Databricks' notebook-style published dashboards product. @@ -219,7 +49,40 @@ sibling packages `statementexecution` (general SQL Statement Execution API), - **`PublishedDatasetDataModel`** — Internal Java class referenced in JSDoc; holds the published-dashboard datasets, warehouse_id, and embedded_credentials. ## File coverage -- `src/v1/model.ts` (220 lines): read fully. -- `src/v1/client.ts` (175 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (21 lines): read fully. +- Package removed from the repository — no source files to audit. + +## Fixed +- #1 Package name `queryexecution` (originally cited at `package.json`, directory name): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #2 `CancelQueryExecutionResponse` / `CancelQueryExecutionResponseStatus` (originally cited at `src/v1/model.ts:11,18,22`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #3 `ExecutePublishedDashboardQueryRequest` vs. `ExecuteQueryResponse` (originally cited at `src/v1/model.ts:46,58`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #4 `PollQueryStatusResponse.data` (originally cited at `src/v1/model.ts:82`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #5 `QueryResponseStatus` vs. `CancelQueryExecutionResponseStatus` (originally cited at `src/v1/model.ts:22,89`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #6 `Client` class name (originally cited at `src/v1/client.ts:41`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #7 `PendingStatus` and `SuccessStatus` types (originally cited at `src/v1/model.ts:60,105`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #8 `dataToken` field (originally cited at `src/v1/model.ts:27,65,110`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #9 `statementId` field (originally cited at `src/v1/model.ts:102`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #10 `tokens` field (originally cited at `src/v1/model.ts:13,76`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #11 `dashboardName` field (originally cited at `src/v1/model.ts:14,51,77`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #12 `overrideWarehouseId` field (originally cited at `src/v1/model.ts:54`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #13 `dashboardRevisionId` field (originally cited at `src/v1/model.ts:15,52,78`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #14 `executeCall` / `executeHttpCall` (originally cited at `src/v1/utils.ts:26,65`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #15 `buildHttpRequest` (originally cited at `src/v1/utils.ts:96`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #16 `readAll` (originally cited at `src/v1/utils.ts:40`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #17 `HttpCallOptions` (originally cited at `src/v1/utils.ts:15`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #18 `PACKAGE_SEGMENT` (originally cited at `src/v1/client.ts:36`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #19 `Client` constructor (originally cited at `src/v1/client.ts:50-64`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #20 `respBody` vs `resp` locals (originally cited at `src/v1/client.ts:89,94,121,126,161,166`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #21 `httpReq` local (originally cited at `src/v1/client.ts:88,120,160`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #22 `cancelPublishedQueryExecution` method (originally cited at `src/v1/client.ts:67`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #23 `executePublishedDashboardQuery` method (originally cited at `src/v1/client.ts:107`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #24 `pollPublishedQueryStatus` method (originally cited at `src/v1/client.ts:139`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #25 `truncated` field on `SuccessStatus` (originally cited at `src/v1/model.ts:112`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #26 Lowercase `c` in JSDoc comment opening (originally cited at `src/v1/model.ts:6,42,68`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #27 Cross-package vocabulary drift (originally cited at `statementexecution` / `queryhistory` / `queries` overlap): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #28 Vocabulary collision: `query` vs. `statement` vs. `execution` (originally cited at package-level observation): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #29 JSDoc grammar errors / wire-layer leakage (originally cited at `src/v1/model.ts:10,36,45,48,73`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. +- #30 Comment style violations (originally cited at package-level observation): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index a7ce9939..4b188652 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,305 +3,285 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 45 +**Total weird names flagged:** 44 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 19 | -| Low | 20 | +| High | 3 | +| Medium | 20 | +| Low | 21 | | Observation | 3 | ## High severity -### 1. `ListQueries` — request type named with a verb — `src/v1/model.ts:131` -- **Why weird:** Top-level interface called `ListQueries`. Verb-as-noun: `ListQueries` is grammatically a command (the *action*), not a *thing*. Every other Databricks SDK package uses `ListRequest` (e.g. `ListAlertsRequest`, `ListJobsRequest`) for the request body. The mismatch shows up at the call site: - ```ts - async listQueries(req: ListQueries, options?: CallOptions) - ``` - reads as "list queries, given a thing called listQueries", which is circular. -- **Category:** 13, 14, 17 (verb-tense inconsistency; Go/Java-style name; inconsistent action verbs) -- **Suggested name:** `ListQueriesRequest`. -- **Rationale:** Aligns with every other package in the SDK and removes the verb-as-noun footgun. - -### 2. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:179` +### 1. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:177` - **Why weird:** The most central type in the package — the value returned from `listQueries` — is named `QueryInfo`. "Info" is a category-1 vague suffix; almost every field on it is a first-class property of a *query* (`queryId`, `queryText`, `status`, `userId`, `queryStartTimeMs`, ...). The type *is* the query — there is no other `Query` type for `QueryInfo` to disambiguate from. Compare with Go SDK convention where `*Info` types are common, but in TS the suffix is non-idiomatic; e.g. `alerts.Alert`, `jobs.Job`, `clusters.ClusterInfo` (this last one is the exception, also flagged in another audit). The endpoint URL is `/api/2.0/sql/history/queries` — the resource is "queries", so the response item should be `Query`. - **Category:** 8, 14, 1 (redundant `Info` suffix; Go/Java-style; vague suffix) - **Suggested name:** `Query`. -- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #3) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. +- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #2) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. -### 3. `ListQueries_Response.res` — cryptic field — `src/v1/model.ts:158` +### 2. `ListQueriesRequest_Response.res` — cryptic field — `src/v1/model.ts:156` - **Why weird:** A top-level response field named `res`. Two characters. Could mean *result*, *resource*, *response*, *reservation*, *reservoir*. The doc comment is empty. Every comparable list response in this SDK names its payload field something like `alerts`, `clusters`, `dashboards`, etc. (matching the resource); the Databricks public docs page for this endpoint calls it `res` too — so this is a wire-format leak, not a TS naming choice. - **Category:** 5, 1 (cryptic abbreviation; vague/generic) - **Suggested name:** `queries`. -- **Rationale:** The field is `QueryInfo[]` (or `Query[]` after #2). `queries` is the obvious idiomatic name. Even keeping the wire form `res`, the TS surface can map `res` → `queries` in the unmarshal transform (the file already does property-renames everywhere — `query_id` → `queryId`, etc.). +- **Rationale:** The field is `QueryInfo[]` (or `Query[]` after #1). `queries` is the obvious idiomatic name. Even keeping the wire form `res`, the TS surface can map `res` → `queries` in the unmarshal transform (the file already does property-renames everywhere — `query_id` → `queryId`, etc.). -### 4. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:207` -- **Why weird:** `QueryInfo` has both `endpointId` (line 207) and `warehouseId` (line 234) and the doc on `endpointId` reads `Alias for warehouse_id.` Two fields, one underlying ID, both present on every response. Callers will pick one and silently miss the other if the server only fills one. The wire form has the same problem: `endpoint_id` and `warehouse_id` are independent JSON properties on the response. "Endpoint" is also outdated SQL Warehouse vocabulary (Databricks renamed SQL endpoints to SQL warehouses years ago); keeping it for backwards compatibility belongs in the wire layer, not the public TS type. +### 3. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:205` +- **Why weird:** `QueryInfo` has both `endpointId` (line 205) and `warehouseId` (line 232) and the doc on `endpointId` reads `Alias for warehouse_id.` Two fields, one underlying ID, both present on every response. Callers will pick one and silently miss the other if the server only fills one. The wire form has the same problem: `endpoint_id` and `warehouse_id` are independent JSON properties on the response. "Endpoint" is also outdated SQL Warehouse vocabulary (Databricks renamed SQL endpoints to SQL warehouses years ago); keeping it for backwards compatibility belongs in the wire layer, not the public TS type. - **Category:** 12, 6 (duplicate concepts; misleading) - **Suggested name:** Drop `endpointId`. If the server still returns it, alias inside the unmarshal: `warehouseId: d.warehouse_id ?? d.endpoint_id`. - **Rationale:** Two fields with identical meaning is a perpetual source of `if (q.warehouseId !== undefined) ... else if (q.endpointId !== undefined) ...` chains in consumer code. The Go SDK already exposes both because it cannot collapse them without API breakage; TS can collapse and document the legacy wire name. -### 5. `CHANNEL_NAME_*` redundant enum prefix — `src/v1/model.ts:5-11` -- **Why weird:** Every value of the `ChannelName` enum is prefixed with `CHANNEL_NAME_`: - ```ts - enum ChannelName { - CHANNEL_NAME_UNSPECIFIED = 'CHANNEL_NAME_UNSPECIFIED', - CHANNEL_NAME_PREVIEW = 'CHANNEL_NAME_PREVIEW', - CHANNEL_NAME_CURRENT = 'CHANNEL_NAME_CURRENT', - CHANNEL_NAME_PREVIOUS = 'CHANNEL_NAME_PREVIOUS', - CHANNEL_NAME_CUSTOM = 'CHANNEL_NAME_CUSTOM', - } - ``` - Call sites read `ChannelName.CHANNEL_NAME_PREVIEW`, doubling the token. The wire form preserves the prefix because protobuf requires globally unique enum value names, but TS enum values are already namespaced by their enum. -- **Category:** 2 (redundant enum prefix) -- **Suggested name:** `ChannelName.UNSPECIFIED | PREVIEW | CURRENT | PREVIOUS | CUSTOM` — keep the string value on the wire (`"CHANNEL_NAME_PREVIEW"`), strip the prefix from the TS member name. -- **Rationale:** Other enums in this very file — `QueryStatus`, `QueryStatementType`, `PlansState` — do not have this prefix. The inconsistency is jarring. Compare `QueryStatus.QUEUED` to `ChannelName.CHANNEL_NAME_PREVIEW`. - -### 6. `ChannelName.CHANNEL_NAME_UNSPECIFIED` — proto-style sentinel exposed — `src/v1/model.ts:6` -- **Why weird:** `UNSPECIFIED` is protobuf's zero-value sentinel — it exists to satisfy proto3's "default value" rule. Exposing it in the public TypeScript surface forces consumers to handle a value that means "the server forgot to set this field." In TS the equivalent is `undefined`, which the field already permits (`name?: ChannelName | undefined`). So a `ChannelName` value can be `undefined`, `'CHANNEL_NAME_UNSPECIFIED'`, or one of the real channel names — three states where two would suffice. -- **Category:** 6, 14 (misleading; Go/Java-style) -- **Suggested name:** Drop `CHANNEL_NAME_UNSPECIFIED`. If the server sends it, unmarshal it to `undefined`. -- **Rationale:** Clean TS surface. Same comment applies to other `_UNSPECIFIED` sentinels that might appear elsewhere in the SDK (not present in this file's other enums, which is correct). - ## Medium severity -### 7. `PlansState` — vague type name — `src/v1/model.ts:14` +### 4. `PlansState` — vague type name — `src/v1/model.ts:14` - **Why weird:** "Plans state" — state of what? The JSDoc clarifies: "Possible Reasons for which we have not saved plans in the database." So the enum is really an "outcome" or "save status" — not a runtime state of a plan. The values include `EXISTS`, `EMPTY`, `IGNORED_*`, `UNKNOWN` — these are storage outcomes, not lifecycle states. Calling them a "state" is misleading. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `PlanStorageStatus` or `QueryPlansAvailability`. - **Rationale:** Reflects what the value actually represents. Also fixes the singular/plural smell: `PlansState` (plural noun + singular state) reads oddly; `PlanStorageStatus` is uniformly singular. -### 8. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` +### 5. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` - **Why weird:** Within the same enum: `EXISTS` is a verb (present tense), `EMPTY` is an adjective, `IGNORED_*` is a past participle, `UNKNOWN` is an adjective. Four grammatical categories for the same set of states. A consumer using one value learns the wrong pattern for the next. - **Category:** 13 (verb-tense inconsistency) - **Suggested name:** Normalize on adjectives/past participles: `AVAILABLE`, `EMPTY`, `IGNORED_SMALL_DURATION`, `IGNORED_LARGE_SIZE`, `IGNORED_SPARK_PLAN_TYPE`, `UNKNOWN`. - **Rationale:** Internal consistency. `AVAILABLE` is also more accurate than `EXISTS` (the plans exist *somewhere*; the value means they exist *in storage*). -### 9. `PlansState.IGNORED_LARGE_PLANS_SIZE` — overly verbose and grammatically off — `src/v1/model.ts:18` -- **Why weird:** The token `PLANS_SIZE` reads as "size of plans" but in the same enum's context (`PlansState`), the *plans* are already implied. So the value is "plans state: ignored because the plans size is too large for the plans" — redundant. Also `LARGE_PLANS_SIZE` is awkward English: "large plans size" vs "large plan size" or just "large size". -- **Category:** 7, 18 (overly verbose; long enum values) -- **Suggested name:** `IGNORED_LARGE_SIZE` (or `IGNORED_TOO_LARGE`). -- **Rationale:** Removes the redundant `PLANS` and fixes the grammar. +### 6. `PlansState.IGNORED_LARGE_PLANS_SIZE` — grammatically awkward — `src/v1/model.ts:18` +- **Why weird:** `LARGE_PLANS_SIZE` is awkward English: "large plans size" reads as a noun pile. "Large plan size" or simply "too large" would scan naturally. +- **Category:** 18 (awkward grammar) +- **Suggested name:** `IGNORED_LARGE_PLAN_SIZE` or `IGNORED_TOO_LARGE`. +- **Rationale:** Fixes the singular/plural shape so the value reads as English. -### 10. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` +### 7. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` - **Why weird:** The value mentions "Spark plan type" — Spark is a Databricks implementation detail and the doc comment references three internal flags: `isIgnoredSparkPlanType`, `isIgnoredSparkPlanName`, `isDeltaLogScan`. SDK consumers shouldn't need to know about Spark's plan taxonomy. Also, the value name only references one of the three reasons — what if it's `isDeltaLogScan` or `isIgnoredSparkPlanName`? The value is one enum entry for three distinct causes. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `IGNORED_FILTERED_TYPE` (broader, doesn't leak Spark vocabulary), or split into three values matching the three internal flags. - **Rationale:** Either generalize or specialize — but not both. -### 11. `QueryStatementType.OTHER` and `CALL` — `src/v1/model.ts:30,53` -- **Why weird:** `OTHER` (line 30) is a vague catch-all. `CALL` (line 53) has a JSDoc comment "SQL Script" — so `CALL` doesn't mean what it says (SQL `CALL` statement); it means "SQL Script". The doc/value mismatch is misleading. -- **Category:** 1, 6 (vague; misleading) -- **Suggested name:** Keep `OTHER`. Rename `CALL` → `SCRIPT` (matches the JSDoc); alternatively keep `CALL` and remove the misleading JSDoc. -- **Rationale:** Either the value name should match its meaning or the comment is wrong. +### 8. `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — UNKNOWN-vs-UNSPECIFIED inconsistency — `src/v1/model.ts:22,6` +- **Why weird:** Two enums in the same file use two different conventions for the "default/unrecognized" sentinel: `PlansState.UNKNOWN` and `ChannelName.CHANNEL_NAME_UNSPECIFIED`. A consumer who learns one pattern won't reach for the other. The values are conceptually adjacent (both denote "no real value here") but spelled differently in the same package. +- **Category:** 13 (cross-enum convention inconsistency) +- **Suggested name:** Pick one convention across the package and apply it uniformly. +- **Rationale:** Cross-enum consistency. The proto3 zero-value member must exist on every enum, but the spelling of that member (`UNKNOWN` vs `UNSPECIFIED`) should be consistent across the package. + +### 9. `QueryStatementType.OTHER` — vague catch-all — `src/v1/model.ts:30` +- **Why weird:** `OTHER` is a vague catch-all value within an otherwise specific enum of SQL statement keywords (`SELECT`, `INSERT`, ...). A caller seeing `statementType === 'OTHER'` has no way to recover what the statement actually was. +- **Category:** 1 (vague) +- **Suggested name:** Keep `OTHER` (no good alternative) but document the value to explain when the runtime emits it. +- **Rationale:** Without documentation the value is opaque; documenting it removes most of the surprise. -### 12. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:84` +### 10. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:82` - **Why weird:** `CANCELED` (single-l, US) where most JavaScript ecosystems use `cancelled` (double-l) and at minimum should be consistent with the rest of the codebase. More importantly: every other `QueryStatus` value is a past participle (`QUEUED`, `STARTED`, `COMPILED`, `FAILED`, `FINISHED`) or `-ING` (`COMPILING`, `RUNNING`). `CANCELED` fits the past-participle pattern — flag only for spelling. - **Category:** 13 (verb-tense — minor) plus orthographic - **Suggested name:** Keep `CANCELED` if that matches the wire (and project-wide policy); flag for cross-package consistency. - **Rationale:** The W3C HTML spec uses `cancelled`; Node.js, the DOM, and most npm packages use `canceled`. The wire form here is `"CANCELED"`, so the TS surface should match. Just record the choice. -### 13. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:67,77` +### 11. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:65,75` - **Why weird:** Both enum values are documented as `DEPRECATED: to be removed once runtime side change is picked up.` Yet they're exported in `index.ts` (since `QueryStatus` is) and have no JSDoc `@deprecated` tag. IDE autocomplete will offer them indistinguishably from current values. - **Category:** 11 (effectively dead) plus tooling concern - **Suggested name:** No rename. Add `@deprecated` JSDoc on each so IDEs show the strikethrough and the doc surfaces in tooltips. - **Rationale:** TypeScript honors `@deprecated` in completions; the current comment is informational only. -### 14. `QueryStatementType` — verbose discriminator — `src/v1/model.ts:29` +### 12. `QueryStatementType` — verbose discriminator — `src/v1/model.ts:29` - **Why weird:** Type name pairs the resource word (`QueryStatement`) with the discriminator suffix (`Type`). Three nouns stack: a query has a *statement* which has a *type*. The actual values are SQL keywords (`SELECT`, `INSERT`, ...), which are statement *kinds*, not types in the TS sense. Compare `Aggregation` in `alerts/v2`, which uses a single domain noun. - **Category:** 8, 7, 20 (redundant suffix; verbose; type-suffix tautology) - **Suggested name:** `StatementKind`. (`Type` is reserved by TypeScript's own `type` keyword for type aliases, so `Kind` is conventional in enums representing categories of a thing.) - **Rationale:** Disambiguates from TS's `type` and shortens the name. -### 15. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:197,199` +### 13. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:195,197` - **Why weird:** Two `*End*Ms` fields next to each other. The doc comments are: `The time execution of the query ended.` (executionEndTimeMs) and `The time the query ended.` (queryEndTimeMs). Are these different? When? The metrics type later splits time into `compilationTimeMs`, `executionTimeMs`, `resultFetchTimeMs` — so plausibly "execution end" is after spark execution but before fetch, while "query end" is after fetch. The TS types do not encode this. A reader has to guess. - **Category:** 1, 6, 19 (vague; misleading; underspecified time field) - **Suggested name:** Keep both names but rewrite the docs to spell out the relationship and the relative ordering (`queryStartTimeMs ≤ executionEndTimeMs ≤ queryEndTimeMs`). Optionally rename to `executionEndTimeMs` / `resultsDeliveredTimeMs`. - **Rationale:** This is the kind of field that turns into a billing/SLA bug if confused. The audit is naming-only, but the names *here* are the source of the confusion. -### 16. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:213` +### 14. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:211` - **Why weird:** Field documented as `A key that can be used to look up query details.` Look up *where*, with *what API*, returning *what*? `queryId` already serves that purpose. The two coexist on the same response with no explanation. `lookupKey` is vague (lookup what?), undefined-purpose, and parallel to `queryId`. - **Category:** 1, 12 (vague; duplicate concepts) - **Suggested name:** Rename to indicate destination — e.g. `detailsLookupKey` or `historyLookupKey`, plus a doc that references the related API. - **Rationale:** Without an explanation, this looks like a synonym for `queryId`. Drop it from public surface if it has no consumer use. -### 17. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:217,219` +### 15. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:215,217` - **Why weird:** Four user-identity fields on one type: `userId`, `userName`, `executedAsUserId`, `executedAsUserName`. The "executed as" pair models impersonation/run-as. Good intent, but the field names don't make the relationship clear (user1 ran-as user2). Compare `alerts.v2.Alert.runAsUserName` vs `Alert.runAs.userName` for a different (also problematic) approach to the same concept. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Group into a sub-object: `submitter: { id, name }`, `runAs?: { id, name }`. Or rename to `submittedByUserId/Name` + `executedAsUserId/Name`. - **Rationale:** Pairing the two roles symmetrically (submitter / runAs) makes the relationship explicit at the type level. The current names ("user" without qualifier on one pair, "executedAsUser" on the other) implies the bare `user*` is the *original* user, but doesn't say so. -### 18. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:203` +### 16. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:201` - **Why weird:** Field documented as `The email address or username of the user who ran the query.` So `userName` is a union of two unrelated identifier formats with no way to tell them apart at the type level. Same problem on `executedAsUserName`. - **Category:** 6, 15 (misleading; generic field losing meaning) - **Suggested name:** `userIdentifier` or `userPrincipal`, with the doc noting it can be either. Or split into `userEmail?` / `userLoginName?`. - **Rationale:** `userName` strongly implies a `username` (login handle), not an email. Half of integration code will assume that and break. -### 19. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:205` +### 17. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:203` - **Why weird:** `sparkUiUrl` exposes an internal Spark UI URL. "Spark UI" is a Databricks Runtime implementation detail; SDK consumers shouldn't need to know that the link goes to "Spark UI" specifically. The URL is functionally "query plan / execution diagnostics UI" — the name pins it to one particular implementation. - **Category:** 14 (Go/Java-style; leaks internal taxonomy) - **Suggested name:** `queryPlanUrl` or `executionPlanUrl`. - **Rationale:** Decouples the public API from Spark's internal nomenclature. -### 20. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:207,234` -- **Why weird:** Cross-reference of #4: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). +### 18. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` +- **Why weird:** Cross-reference of #3: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). - **Category:** 19, 16 (underspecified ID; field contradicting type domain) -- **Suggested name:** See #4. +- **Suggested name:** See #3. -### 21. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:224` +### 19. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` - **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. - **Category:** 15, 19 (generic field; underspecified ID) - **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. - **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. -### 22. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:226` +### 20. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:224` - **Why weird:** Field doc: `Whether more updates for the query are expected.` So `isFinal: true` means the query result is *complete and won't change*. The name `isFinal` is conventionally used for things like inheritance ("can't be subclassed") or compilation ("final pass"). `isComplete`, `isTerminal`, or `isSettled` would be clearer. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `isSettled` or `isTerminal` (matches the `QueryStatus` terminal states). - **Rationale:** The name should describe the state, not the absence of updates. -### 23. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:228` -- **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #2 / general pattern). Reads as "channel-used info" — three nouns. +### 21. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:226` +- **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #1 / general pattern). Reads as "channel-used info" — three nouns. - **Category:** 8, 7 (redundant `Info`; verbose; verb-as-modifier) - **Suggested name:** `channel: Channel`. (Rename type `ChannelInfo` → `Channel`.) - **Rationale:** Symmetry with `warehouseId`, `userId`, etc. — bare noun. -### 24. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:215,239` +### 22. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` - **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. - **Rationale:** Two times on one type, both unitless in the name (`duration` doesn't say ms), invites confusion. -### 25. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:239` +### 23. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:237` - **Why weird:** Every other time field has a `Ms` suffix (`queryStartTimeMs`, `executionEndTimeMs`, `queryEndTimeMs`, `totalTimeMs`, etc.). `duration` does not. The type is `number`. The doc says "Total time of the statement execution" with no unit. Reader must guess. - **Category:** 15, 19 (generic field losing meaning; underspecified) -- **Suggested name:** `durationMs`. (See also #24.) +- **Suggested name:** `durationMs`. (See also #22.) - **Rationale:** Internal consistency with every other time field in the file. ## Low severity -### 26. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:245` +### 24. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:243` - **Why weird:** `clientApplication: string` returns names like "Databricks SQL Editor, Tableau, and Power BI" — these are *application names*, not application IDs. The doc even disclaims "values are expected to remain static over time, this cannot be guaranteed." So the field is a free-text label, not a stable identifier. Name doesn't reflect that. - **Category:** 15 (generic field losing meaning) - **Suggested name:** `clientApplicationName` or `clientAppLabel`. - **Rationale:** Marks the field as a display label rather than an ID. -### 27. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:250,252` +### 25. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:248,250` - **Why weird:** "Query source" / "external query source" / "cache query ID" — three different ways the type talks about the origin of a query. `querySource` is the *upstream entity* (dashboard, notebook, alert, job, ...); `cacheQueryId` is the *prior query that supplied a cached result*. Conceptually unrelated, but the field names rhyme. - **Category:** 12 (duplicate concepts — only superficial) - **Suggested name:** Keep `querySource`. Rename `cacheQueryId` → `cachedFromQueryId`. - **Rationale:** Makes the semantic distinction explicit. -### 28. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:101,103` +### 26. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:99,101` - **Why weird:** Two dashboard-related ID fields on the same type. `legacyDashboardId` implies pre-Lakeview dashboards (the JSDoc on `dashboardId` is "this Lakeview dashboard"). Both can be set simultaneously? The semantics are not encoded — should be a discriminated union (`{ kind: 'lakeview', id } | { kind: 'legacy', id }`). - **Category:** 12, 19 (duplicate concept; underspecified) - **Suggested name:** Keep the names; consider a `kind` discriminator. At minimum, document the mutual exclusivity. - **Rationale:** Documentation fix more than naming. -### 29. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:105,109,112` +### 27. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` - **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. - **Category:** 19 (underspecified) - **Suggested name:** As above — convert to discriminated union. - **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. -### 30. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:122` +### 28. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:120` - **Why weird:** Three IDs on one type: `jobId`, `jobRunId`, `jobTaskRunId`. The naming is consistent and self-documenting. `jobTaskRunId` (one identifier for "task run within a job run") could be ambiguous: is it the run-ID of a *task* (with `jobRunId` being the run-ID of the whole job), or vice versa? The doc says `The canonical identifier of the task run.` — confirms the former. - **Category:** 19 (underspecified) - **Suggested name:** Acceptable; if confusion arises, rename to `taskRunIdWithinJobRun`. - **Rationale:** Documentation is sufficient. -### 31. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:263,271,281,287` +### 29. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:261,269,279,285` - **Why weird:** Four time fields; the relationship is `totalTime ≥ compilationTime + executionTime + resultFetchTime` (roughly), and `executionTime` aggregates `taskTotalTime` and `photonTotalTime`. The names don't encode the hierarchy; a developer must read all four docs to understand. Individually each name is OK. - **Category:** 1 (vague — collectively) - **Suggested name:** Keep, but add a JSDoc on `QueryMetrics` summarizing the hierarchy. - **Rationale:** Documentation > rename. -### 32. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:321` +### 30. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:319` - **Why weird:** Phrase rather than a noun. Doc says "remaining work to be done... deprecated: using projected_remaining_task_total_time_ms instead". So this is a deprecated field with a name that reads like English prose ("work to be done") rather than a TS identifier. Reads awkwardly: `metrics.workToBeDone`. - **Category:** 7, 14 (verbose; Go/Java-style phrase) - **Suggested name:** Already deprecated. If kept for back-compat, that's fine. New consumers should use `projectedRemainingTaskTotalTimeMs`. - **Rationale:** Will be removed; flag for awareness only. -### 33. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:326` +### 31. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:324` - **Why weird:** Doc says `number of remaining tasks to complete, calculated by autoscaler StatementAnalysis.scala. deprecated: use remaining_task_count instead`. So `runnableTasks` actually means "remaining tasks" — name and meaning don't align. Also deprecated. - **Category:** 6, 1 (misleading; vague) - **Suggested name:** Deprecated. Use `remainingTaskCount`. Flag for awareness. -- **Rationale:** Same as #32. +- **Rationale:** Same as #30. -### 34. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:328,335` +### 32. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:326,333` - **Why weird:** 32-char and 33-char field names. Five tokens each (`projected/remaining/task/totalTime/Ms`). Long enough that they wrap in editors and IDE tooltips. The doc on the second one says `projected lower bound on remaining total task time based on projected_remaining_task_total_time_ms / maximum concurrency` — the *name* doesn't say "wall-clock" is the divided-by-concurrency version. `WallclockTime` is the differentiator from `TaskTotalTime`. - **Category:** 7 (overly verbose) - **Suggested name:** Acceptable given the precision required. Could shorten `projectedRemainingWallclockTimeMs` → `projectedRemainingWallTimeMs`. - **Rationale:** Marginal. -### 35. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:273,275,277,279,293,297,337` +### 33. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:271,273,275,277,291,295,335` - **Why weird:** Seven `*Bytes` fields, each with subtly different scopes (remote vs cache vs disk vs network vs file vs pruned vs spill). Each individual name is OK; together they form a glossary the reader has to internalize. Also: `spillToDiskBytes` is a verb phrase (`spill to disk`) where peers are noun phrases (`read remote`, `write remote`). Inconsistent grammatical shape. - **Category:** 13 (verb-tense — minor) - **Suggested name:** `diskSpillBytes` (noun phrase, parallels `prunedBytes`, `readCacheBytes`). - **Rationale:** Symmetry. -### 36. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:265,337` +### 34. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:263,335` - **Why weird:** Two read-bytes fields. Doc on `readBytes`: `Total size of data read by the query, in bytes.` Doc on `readFilesBytes`: `Total number of file bytes in all tables read`. The difference is "file bytes" vs general "bytes" — possibly identical, possibly not. Names don't disambiguate. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Rename `readBytes` → `totalReadBytes` and `readFilesBytes` → `readFileBytes` (singular "file" since each row counts). - **Rationale:** Distinguishes scope. -### 37. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:283,297,299,337` +### 35. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:281,295,297,335` - **Why weird:** Inconsistent pluralization: `readFilesCount` (plural files) vs `prunedFilesCount` (plural files). OK, consistent there. But `readFilesBytes` is also plural where `readFilesCount` follows the same form — consistent. Then we have `readPartitionsCount` (plural). All consistent. Then `taskTotalTimeMs` is singular. The pattern across the type isn't uniform. - **Category:** 9 (singular/plural mismatch — across fields) - **Suggested name:** Pick one form. `readFileBytes` / `readFileCount` / `readPartitionCount` (singular, the way English does for counts) reads more naturally. - **Rationale:** Minor consistency win. -### 38. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:267, 209` +### 36. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` - **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. - **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) - **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. - **Rationale:** Same value reachable through two paths is a maintenance hazard. -### 39. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:304,309,311` +### 37. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:302,307,309` - **Why weird:** Three time fields use `*Timestamp` suffix; everywhere else in the file the convention is `*TimeMs`. The `Timestamp` fields are documented as Unix-epoch-milliseconds too, so the unit is the same — just the naming convention differs. Mixing two suffixes for the same kind of value is a category-13 inconsistency. - **Category:** 13, 19 (verb-tense / convention inconsistency; underspecified — timestamp vs duration) - **Suggested name:** `provisioningQueueStartTimeMs`, `overloadingQueueStartTimeMs`, `queryCompilationStartTimeMs`. - **Rationale:** Consistent suffix across all time-valued fields. -### 40. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:316` +### 38. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:314` - **Why weird:** Field name has "OverTimeRange"; type is `TaskTimeOverRange`. Different naming. Field is `taskTimeOver` + `TimeRange`; type is `TaskTime` + `OverRange`. Semantically the same, named differently. - **Category:** 9, 20 (singular/plural; type-suffix tautology) - **Suggested name:** Align: `taskTimeOverRange: TaskTimeOverRange` (drop second `Time`). - **Rationale:** Field name should match type name shape. -### 41. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:351,360` +### 39. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` - **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. - **Category:** 1 (vague — `Entry`) - **Suggested name:** Optional rename to domain names. - **Rationale:** Marginal. -### 42. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:362` +### 40. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:360` - **Why weird:** Only field on the type. The doc says "total task completion time in this time range" — name reads as "task completed time" (past participle). `taskCompletionTimeMs` would be a noun-phrase form and match peer fields. - **Category:** 13 (verb-tense — past participle vs noun) - **Suggested name:** `taskCompletionTimeMs`. - **Rationale:** Noun form is more conventional. -### 43. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:367,369` +### 41. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:365,367` - **Why weird:** Generic type name `TimeRange` lives in a domain package. It's used once (`QueryFilter.queryStartTimeRange: TimeRange`). The field name `queryStartTimeRange` then re-introduces "queryStart" — odd because the `TimeRange` is *for filtering* on query start time, but a `TimeRange` is just (start, end). Reading `queryStartTimeRange.startTimeMs` is "the start of the query-start-time range, in ms" — three "start"s in one expression. - **Category:** 1, 7 (vague type name; verbose) - **Suggested name:** Rename field to `submittedDuring: TimeRange` or `queryStartedBetween: TimeRange`. Or rename type to `MsRange` / `TimestampRange` (since the type is unit-specific). - **Rationale:** Reduces "start" noise. -### 44. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:172` +### 42. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:170` - **Why weird:** Doc says `Filtering for multiple statuses is not recommended. Instead, opt to filter by a single status multiple times and then combine the results.` This is a behaviour quirk; field name is fine. Flag for documentation polish. - **Category:** observation - **Suggested name:** Keep `statuses`; document why multi-filter is discouraged on the type, not just on the field. - **Rationale:** Surfaces the constraint. -### 45. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:346,347` +### 43. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` - **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. - **Category:** 1 (vague) - **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. - **Rationale:** Minor. +### 44. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` +- **Why weird:** `Legacy` is a temporal/architectural modifier mid-name — it tags the identifier as belonging to the *old* product (pre-Lakeview dashboards). The "legacy" label only has meaning inside Databricks' product roadmap; SDK consumers who don't know that Databricks shipped a new dashboard product see "legacy" as architectural noise. Names like `Legacy`/`Modern`/`Old`/`New` mid-position bake a release-timeline distinction into the public type surface; once a third dashboard product ships, the name becomes a lie. +- **Category:** proto-architectural-leak (`Legacy` mid-position temporal modifier) +- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #26. +- **Rationale:** Replace the temporal modifier with the actual product name. The Go SDK keeps `legacy_dashboard_id` because of wire-format back-compat; the TS surface can rename without breaking the wire transform. + ## Observations ### O1. `Client` is the only exported class — `src/v1/client.ts:32` @@ -317,13 +297,13 @@ 1. **The `Info` / `State` suffix habit.** `QueryInfo`, `ChannelInfo`, `PlansState` — bare-noun renames (`Query`, `Channel`, `PlanStorageStatus`) would be cleaner. `Info` is a category-1 vague suffix doing no work. -2. **Redundant enum-value prefixes and proto sentinels.** `CHANNEL_NAME_*` doubles the enum name in every value; `UNSPECIFIED` exposes the proto3 zero-value sentinel into the TS surface where `undefined` already serves. +2. **Sentinel-naming convention inconsistency.** `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — two enums in the same file use different spellings for the proto3 zero-value member. The zero-value itself is required by proto3 and intentional; the inconsistent spelling is not. 3. **Time-field naming is inconsistent.** `*TimeMs` is the dominant convention, but `*Timestamp` appears three times and `duration` once with no unit. Same hierarchy across `QueryInfo` and `QueryMetrics` is hard to read without docs. 4. **Multiple ways to identify one thing.** `endpointId` / `warehouseId`, `userName` (email-or-handle), `sessionId` (Spark Connect or DBSQL or SDP), `lookupKey` vs `queryId`. Each is a "two-fields-one-concept" or "one-field-multiple-concepts" smell. -5. **Verbose generated-code residue.** `getAssignableRolesForResource`-style verbosity is mostly absent here (only one endpoint), but enum-value verbosity is high (`IGNORED_LARGE_PLANS_SIZE`, `CHANNEL_NAME_*`, `projectedRemainingTaskTotalTimeMs`). +5. **Verbose field names.** `getAssignableRolesForResource`-style verbosity is mostly absent here (only one endpoint), but field-name verbosity is high (`projectedRemainingTaskTotalTimeMs`, `projectedRemainingWallclockTimeMs`). ## Domain glossary - **DBSQL** — Databricks SQL, the serverless warehouse engine. The SDK package targets `/api/2.0/sql/history/...`. @@ -339,7 +319,11 @@ - **Provisioning queue / Overloading queue** — Two queue states a query passes through: waiting for a warehouse to spin up; waiting because the warehouse is overloaded. ## File coverage -- `src/v1/model.ts` (615 lines): read fully. -- `src/v1/client.ts` (107 lines): read fully. +- `src/v1/model.ts` (613 lines): read fully. +- `src/v1/client.ts` (109 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (26 lines): read fully. + +## Fixed +- #1 `ListQueries` (originally cited at `src/v1/model.ts:131`): Fixed in regeneration on 2026-05-20 — request DTO renamed to `ListQueriesRequest`; the verb-as-noun issue is resolved and the call-site type matches `ListAlertsRequest`-style convention. +- #11-part `QueryStatementType.CALL` (originally cited at `src/v1/model.ts:53`): Fixed in regeneration on 2026-05-20 — `CALL` value was removed from the enum, so the misleading "SQL Script" JSDoc no longer applies. The `OTHER` half of the original finding is preserved as #10. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index eeab8d6e..aed41ffd 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -20,7 +20,7 @@ derive from upstream definitions. The dominant naming issues are (1) the path-parameter `*Arg` suffix applied to fields that already encode their role through documentation (`fullNameArg`, `versionArg`, `aliasArg`), (2) extremely heavy -`Create*`/`Update*` request shapes that include server-populated +`Create*Request`/`Update*Request` shapes that include server-populated read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `fullName`, `metastoreId`, `storageLocation`, `browseOnly`), (3) collision-prone parallel concept naming versus the legacy @@ -44,30 +44,29 @@ opacity. Either drop the wrapper (move `$case` to the top of `Dependency`) or rename to `dependency` so the access path reads `dep.dependency.$case`. -#### 1.2 `ModelVersionInfo.source` (model.ts:228) +#### 1.2 `ModelVersionInfo.source` (model.ts:218), `UpdateModelVersionRequest.source` (model.ts:331) `source` is a free-form string whose documentation reveals it is "URI indicating the location of the source artifacts (files) for the model version". A field named `source` on a model object is ambiguous — `sourceUri`, `artifactUri`, or `artifactLocation` would communicate type -and purpose. The same misnaming appears on `UpdateModelVersion.source` -(model.ts:347). +and purpose. The same misnaming appears on `UpdateModelVersionRequest.source`. -#### 1.3 `RegisteredModelAliasInfo.id` (model.ts:274), `ModelVersionInfo.id` (model.ts:263) +#### 1.3 `RegisteredModelAliasInfo.id` (model.ts:264), `ModelVersionInfo.id` (model.ts:253) Both `RegisteredModelInfo`-adjacent payloads use bare `id` for two *different* identifier kinds (the alias and the model version). The reader cannot tell from the call site whether `info.id` is the alias's identifier or the model version's identifier. Prefer `aliasId` and `modelVersionId` to disambiguate (see also §13.1, §13.2). -#### 1.4 `ModelVersionInfo.version` (model.ts:251), `UpdateModelVersion.version` (model.ts:370) +#### 1.4 `ModelVersionInfo.version` (model.ts:241), `UpdateModelVersionRequest.version` (model.ts:354) A field on a "model version" type called `version` is doubly redundant *and* generic. The doc clarifies it is the "integer model version number"; a name such as `versionNumber` (or the field already used elsewhere, `versionNum`) would distinguish it from a semver-style version -string. Worse, `RegisteredModelAliasInfo` uses `versionNum` (line 272) +string. Worse, `RegisteredModelAliasInfo` uses `versionNum` (line 262) for the same concept — the inconsistency is internal (see §11.1). -#### 1.5 `CreateRegisteredModel.name` (model.ts:23), `RegisteredModelInfo.name` (model.ts:285) +#### 1.5 `CreateRegisteredModelRequest.name` (model.ts:23), `RegisteredModelInfo.name` (model.ts:274) Bare `name` on a `RegisteredModel*` shape is informationless given the surrounding type. The doc clarifies it is "the name of the registered model" — `modelName` or `registeredModelName` would carry the type with @@ -76,22 +75,24 @@ are siblings on the same shape. --- -### 2. Redundant enum prefixes +### 2. Sentinel enum naming inconsistency #### 2.1 `ModelVersionStatus.MODEL_VERSION_STATUS_UNKNOWN` (model.ts:6) -The only variant prefixed with `MODEL_VERSION_STATUS_` is the unknown -sentinel; the other three variants are bare (`PENDING_REGISTRATION`, -`FAILED_REGISTRATION`, `READY`). Read aloud: -`ModelVersionStatus.MODEL_VERSION_STATUS_UNKNOWN` repeats -`MODEL_VERSION_STATUS` twice. Should be `UNKNOWN` (or `UNSPECIFIED`, -the more common proto sentinel). The inconsistency between this variant -and the others is also a §3-class problem. +The zero-value sentinel on this enum is named `MODEL_VERSION_STATUS_UNKNOWN` +while every other enum in the codebase uses `*_UNSPECIFIED` for the proto3 +zero-value member. The inconsistency is internal: `UNKNOWN` reads as a +discoverable lifecycle state alongside the three real states +(`PENDING_REGISTRATION`, `FAILED_REGISTRATION`, `READY`), whereas +`UNSPECIFIED` carries the standard "value-not-set" semantics used +elsewhere. Rename to `MODEL_VERSION_STATUS_UNSPECIFIED` for consistency +with the rest of the SDK and to clarify that the value is a default +rather than an observable status. --- ### 3. Acronym casing inconsistencies (URI, UC, MLflow, ID) -#### 3.1 `runId` versus `Id` (model.ts:235, model.ts:263, model.ts:382) +#### 3.1 `runId` versus `Id` (model.ts:225, 253, 366) "ID" is a two-letter initialism. Google TS style guide states that identifiers should follow `camelCase` and treat acronyms as words. The package uses both `runId` (one-letter run + Id, fine) and `id` (lowercase @@ -100,12 +101,12 @@ issue is that `metastoreId`, `id`, and `runId` are all lowercase, while `URI` appears nowhere as a field name (the `source` field would have been a candidate, see §1.2). -#### 3.2 `MLflow` in doc comments (model.ts:232-234, 351-353) +#### 3.2 `MLflow` in doc comments (model.ts:222-223, 335-336) Doc comments spell it `MLflow` (correct trademark casing). No identifier exists for MLflow here, but if one were added, follow the trademark casing (`Mlflow*` would be wrong). -#### 3.3 `` placeholder leakage (model.ts:237, 356) +#### 3.3 `` placeholder leakage (model.ts:227, 340) JSDoc contains the literal token `` — clearly an unresolved template marker from the upstream generator. It will render poorly in IDE tooltips. Not a naming issue per se, but visible in the @@ -115,7 +116,7 @@ audit surface; documentation hygiene. ### 4. Cryptic abbreviations -#### 4.1 `fullNameArg`, `versionArg`, `aliasArg` (model.ts:60, 62, 70, 78, 80, 123, 125, 134, 136, 143, 152, 322, 324, 337, 339, 389) +#### 4.1 `fullNameArg`, `versionArg`, `aliasArg` (model.ts:60, 62, 70, 72, 80, 113, 115, 122, 124, 133, 142, 306, 308, 321, 323, 373) The `Arg` suffix is utterly cryptic to anyone outside the SDK team. It hails from the upstream Go generator marking path-parameter fields. In TypeScript identifiers like `fullNameArg`, `versionArg`, and `aliasArg` @@ -128,13 +129,13 @@ to drop the path-parameter fields from the request type entirely and accept them as method positional arguments (mirroring how `getModelVersion` already URL-encodes them). -#### 4.2 `runId`, `runWorkspaceId` (model.ts:235, 240) +#### 4.2 `runId`, `runWorkspaceId` (model.ts:225, 230) `runId` is conventional (MLflow run identifier), but in TS the abbreviation chain `run` + `Id` reads oddly when paired with `runWorkspaceId`. Consider `mlflowRunId` and `mlflowRunWorkspaceId` since the doc comments already qualify these as MLflow-specific. -#### 4.3 `versionNum` (model.ts:272, 326, 588, 798) +#### 4.3 `versionNum` (model.ts:262, 310, 559, 712, 720, 731, 736) `Num` is a cryptic abbreviation for `Number`. Either spell out (`versionNumber`) or drop entirely (`version` — but that collides with the model-version field; see §11.1). @@ -143,7 +144,7 @@ field; see §11.1). ### 5. Misleading names -#### 5.1 `RegisteredModelAliasInfo.modelName` (model.ts:276) +#### 5.1 `RegisteredModelAliasInfo.modelName` (model.ts:266) The doc says "The name of the parent registered model of the model version, relative to parent schema". This field is the *parent registered model's* name, but the property is called `modelName` and lives on an @@ -153,14 +154,14 @@ model handle. Better: `parentModelName` or, since the alias is *on* the registered model, simply omit the field (the parent is already known from context). -#### 5.2 `RegisteredModelAliasInfo.id` versus `RegisteredModelAliasInfo.aliasName` (model.ts:270, 274) +#### 5.2 `RegisteredModelAliasInfo.id` versus `RegisteredModelAliasInfo.aliasName` (model.ts:260, 264) Two identifier-shaped fields on the same shape; the doc on `id` ("unique identifier of the alias") suggests an internal opaque UUID, while `aliasName` is the human-readable handle the API uses elsewhere. Calling both "identifier" makes intent unclear. Rename `id` to `aliasUuid` or `aliasId` (see §13.1). -#### 5.3 `ModelVersionInfo.version` (model.ts:251) +#### 5.3 `ModelVersionInfo.version` (model.ts:241) The field name suggests a string/identifier ("v2", "v3"), but the type is `number` and the doc clarifies it is the integer version number used to reference the model version in API requests. The collision with @@ -171,7 +172,7 @@ typical semantic versioning expectations is a real footgun. Rename ### 6. Overly verbose names -#### 6.1 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 504) +#### 6.1 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 507) Method names hover around 30 characters. Java/Go style. In TS prefer `setAlias` / `deleteAlias` on a `RegisteredModelsClient` whose role is already established. The current names imply you could also call @@ -182,7 +183,7 @@ which you cannot. See also §11.1. ### 7. Redundant suffixes -#### 7.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) +#### 7.1 `RegisteredModelInfo` (model.ts:273), `ModelVersionInfo` (model.ts:210), `RegisteredModelAliasInfo` (model.ts:258) The `*Info` suffix is a verbatim Go-ism. In TS the suffix adds nothing — `RegisteredModel`, `ModelVersion`, and `RegisteredModelAlias` would be the natural names. `*Info` is leftover from the proto/Go convention of @@ -195,11 +196,11 @@ TypeScript does not need the distinction. Compare with the legacy ### 8. Singular / plural mismatches -#### 8.1 `ListModelVersions` request, `ListModelVersions_Response.modelVersions` (model.ts:150, 169) -The request type is *plural* (`ListModelVersions`), the response +#### 8.1 `ListModelVersionsRequest`, `ListModelVersionsRequest_Response.modelVersions` (model.ts:140, 159) +The request type is *plural* (`ListModelVersionsRequest`), the response collection field is *plural* (`modelVersions`). Internally consistent. -#### 8.2 `ListRegisteredModels` request paginates registered models; field is `registeredModels` (model.ts:212) +#### 8.2 `ListRegisteredModelsRequest` paginates registered models; field is `registeredModels` (model.ts:202) Same as 8.1; flagged for completeness. --- @@ -226,7 +227,7 @@ are all safe. #### 10.1 `RegisteredModel` (modelregistry) versus `RegisteredModelInfo` (registeredmodels) The legacy workspace-level package `modelregistry` already exports a `RegisteredModel` type and a `ModelVersion` type (verified in -`/home/parth.bansal/sdk-js/packages/modelregistry/src/v1/model.ts:411-420`). +`/home/parth.bansal/sdk-js/packages/modelregistry/src/v1/model.ts`). The UC-resident package re-uses the same domain noun with an `Info` suffix (`RegisteredModelInfo`, `ModelVersionInfo`). A consumer importing both packages will hold both `RegisteredModel` (from @@ -238,23 +239,26 @@ This is the single most confusing parallel-concept issue. Mitigations: an import alias (`import {RegisteredModel as UcRegisteredModel}`), or - Adopt distinct domain nouns (`UcRegisteredModel`, `CatalogModel`). -#### 10.2 `CreateRegisteredModel` (registeredmodels) versus `CreateRegisteredModel` (modelregistry) +#### 10.2 `CreateRegisteredModelRequest` (registeredmodels) versus `CreateRegisteredModelRequest` (modelregistry) Same exact type name in both packages. Path-disambiguated only. -`grep -rn "CreateRegisteredModel" packages/` returns two identical -identifiers in two different namespaces; both are documented as -"Create a registered model" but mean different things. The collision -risk is identical for `DeleteRegisteredModel`, `GetModelVersion`, -`ListRegisteredModels`, and `ModelVersionStatus` (all share names with -the legacy `modelregistry` exports). +`grep -rn "CreateRegisteredModelRequest" packages/` returns two +identical identifiers in two different namespaces; both are documented +as "Create a registered model" but mean different things. The collision +risk is identical for `DeleteRegisteredModelRequest`, +`DeleteModelVersionRequest`, `GetModelVersionRequest`, +`ListRegisteredModelsRequest`, and `ModelVersionStatus` (all share names +with the legacy `modelregistry` exports). #### 10.3 `ModelVersionStatus` collision (model.ts:5) -Identical enum name in `modelregistry/src/v1/model.ts:67-77`. The -*variants* are almost identical (`PENDING_REGISTRATION`, -`FAILED_REGISTRATION`, `READY`), except `registeredmodels` adds the -sentinel `MODEL_VERSION_STATUS_UNKNOWN`. A consumer who imports both -will see two enums of the same name describing nearly-the-same lifecycle -on two different APIs. This is high-risk for runtime bugs (passing one -package's enum value into the other compiles but does not match). +Identical enum name in `modelregistry/src/v1/model.ts`. The three real +*variants* match (`PENDING_REGISTRATION`, `FAILED_REGISTRATION`, +`READY`), but `registeredmodels` adds a `MODEL_VERSION_STATUS_UNKNOWN` +zero-value sentinel that the legacy package lacks. A consumer who +imports both will see two enums of the same name describing +nearly-the-same lifecycle on two different APIs. This is high-risk for +runtime bugs (passing one package's enum value into the other compiles +but does not match), and the divergent zero-value handling makes the +collision worse. #### 10.4 MLflow run linkage (`runId`, `runWorkspaceId`) The UC model registry borrows MLflow concepts but uses generic field @@ -266,14 +270,14 @@ signal the foreign-concept boundary. ### 11. Verb tense / parallel inconsistency -#### 11.1 `versionNum` versus `version` (model.ts:251, 272, 326, 370) +#### 11.1 `versionNum` versus `version` (model.ts:241, 262, 310, 354) `RegisteredModelAliasInfo.versionNum` and -`SetRegisteredModelAlias.versionNum` use `Num`. `ModelVersionInfo.version` -and `UpdateModelVersion.version` drop the suffix entirely. All four -fields are the same concept (integer model-version pointer). Pick one -spelling and apply uniformly. +`SetRegisteredModelAliasRequest.versionNum` use `Num`. +`ModelVersionInfo.version` and `UpdateModelVersionRequest.version` drop +the suffix entirely. All four fields are the same concept (integer +model-version pointer). Pick one spelling and apply uniformly. -#### 11.2 `name` versus `modelName` versus `fullName` (model.ts:23, 222, 285, 299, 341) +#### 11.2 `name` versus `modelName` versus `fullName` (model.ts:23, 212, 274, 289, 325) On `RegisteredModelInfo`, `name` is the *short* registered-model name, `fullName` is the three-level identifier, and `catalogName`/`schemaName` are the parents. On `ModelVersionInfo`, `modelName` is the parent @@ -281,7 +285,7 @@ registered model's short name. Three different conventions for the same class of concept (name vs modelName vs fullName). A consistent scheme — say, `shortName`, `fullName`, `parentModelName` — would help. -#### 11.3 `nextPageToken` versus `pageToken` (model.ts:162, 174, 207, 217) +#### 11.3 `nextPageToken` versus `pageToken` (model.ts:152, 164, 197, 207) Request types use `pageToken`; response types use `nextPageToken`. This asymmetry is conventional for cursored pagination, but the convention should be documented somewhere (it isn't, here). Not a defect, but @@ -316,23 +320,23 @@ SDK pattern leaking into TS. ### 13. Underspecified IDs -#### 13.1 `RegisteredModelAliasInfo.id` (model.ts:274) +#### 13.1 `RegisteredModelAliasInfo.id` (model.ts:264) "The unique identifier of the alias". No format constraint, no mention of whether it is a UUID, a server-generated opaque token, or a human-friendly slug. Type is `string`. Compare with the well-typed `metastoreId` (which is also `string` but at least bound to a known domain). Recommend `aliasId` and adding format hints in the doc. -#### 13.2 `ModelVersionInfo.id` (model.ts:263) +#### 13.2 `ModelVersionInfo.id` (model.ts:253) "The unique identifier of the model version". Same issues as 13.1. Recommend `modelVersionId`. -#### 13.3 `RegisteredModelInfo.metastoreId` (model.ts:297) and `ModelVersionInfo.metastoreId` (model.ts:254) +#### 13.3 `RegisteredModelInfo.metastoreId` (model.ts:287) and `ModelVersionInfo.metastoreId` (model.ts:245) "The unique identifier of the metastore". Acceptable name but worth flagging that the format (UUID? slug?) is not specified anywhere in the doc. -#### 13.4 `ModelVersionInfo.runWorkspaceId` (model.ts:240) +#### 13.4 `ModelVersionInfo.runWorkspaceId` (model.ts:230) `number` typed. The doc says "ID of the Databricks workspace". Workspace IDs in Databricks are 64-bit integers — TS `number` is only safe up to 2^53. This is a *type* concern, but the name `runWorkspaceId` does not @@ -346,17 +350,16 @@ flag the underlying integer-width risk; consider `string` per Go's #### 14.1 `Dependency.value` (model.ts:91) See §1.1. -#### 14.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 118, 317, 332, 425) -Four of the six dependency wrapper types use a `FullName` suffix on -their single string field (`tableFullName`, `functionFullName`, -`volumeFullName`, `secretFullName`), while two do not -(`connectionName`, `credentialName`). The docs claim all six are -fully-qualified names ("Full name of the dependent connection, in the -form of `__connection_name__`"). The naming should be uniform — either -add `FullName` to `connectionName` and `credentialName`, or drop the -suffix from the other four. - -#### 14.3 `CreateRegisteredModel.aliases` (model.ts:48), `UpdateRegisteredModel.aliases` (model.ts:417) +#### 14.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 108, 316) +Two of the four dependency wrapper types use a `FullName` suffix on +their single string field (`tableFullName`, `functionFullName`), while +two do not (`connectionName`, `credentialName`). The docs claim all +four are fully-qualified names ("Full name of the dependent connection, +in the form of `__connection_name__`"). The naming should be uniform — +either add `FullName` to `connectionName` and `credentialName`, or drop +the suffix from the other two. + +#### 14.3 `CreateRegisteredModelRequest.aliases` (model.ts:47), `UpdateRegisteredModelRequest.aliases` (model.ts:401) A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. Aliases are normally set on already-existing models, not at create time. The field is also marked optional. The name `aliases` is @@ -367,8 +370,8 @@ shape is semantically odd. Flagged for shape, not just naming. ### 15. Field contradicting type domain -#### 15.1 `CreateRegisteredModel.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId}` (model.ts:37-45) -`CreateRegisteredModel` is a *request* shape, yet it includes six +#### 15.1 `CreateRegisteredModelRequest.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId, storageLocation, browseOnly}` (model.ts:33-49) +`CreateRegisteredModelRequest` is a *request* shape, yet it includes server-populated fields that the client cannot meaningfully set: - `fullName` (computed from `catalogName.schemaName.name`) - `createdAt`, `createdBy`, `updatedAt`, `updatedBy` (server-stamped) @@ -378,21 +381,21 @@ server-populated fields that the client cannot meaningfully set: These fields belong on `RegisteredModelInfo` (the response). Their presence on the create request misleads users into thinking they can set creation timestamps or override the metastore. Same defect on -`UpdateRegisteredModel` (model.ts:387-419): all six are present plus -`name`, `catalogName`, `schemaName`, `storageLocation`, `aliases`, and -`browseOnly` — most of which are not actually updatable per the JSDoc -which says "only the name, the owner or the comment of the registered -model can be updated". - -#### 15.2 `UpdateModelVersion.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:335-385) -`UpdateModelVersion` carries *every* field from `ModelVersionInfo`. The -JSDoc says "Currently only the comment of the model version can be +`UpdateRegisteredModelRequest` (model.ts:371-404): all six are present +plus `name`, `catalogName`, `schemaName`, `storageLocation`, `aliases`, +and `browseOnly` — most of which are not actually updatable per the +JSDoc which says "only the name, the owner or the comment of the +registered model can be updated". + +#### 15.2 `UpdateModelVersionRequest.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:319-369) +`UpdateModelVersionRequest` carries *every* field from `ModelVersionInfo`. +The JSDoc says "Currently only the comment of the model version can be updated". The shape is therefore deeply misleading: it presents 17 optional fields where 16 are silently no-ops on the server. A user setting `updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` will see no effect from `status` but no error either. -#### 15.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:276-281) +#### 15.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:266-270) Three parent-locator fields on an alias type. The alias is already nested inside `RegisteredModelInfo.aliases`, so the parent is known from context. Embedding these makes the alias serialisable in @@ -402,7 +405,7 @@ isolation but pollutes the shape. ### 16. Type-suffix tautology -#### 16.1 `RegisteredModelInfo` (model.ts:283), `ModelVersionInfo` (model.ts:220), `RegisteredModelAliasInfo` (model.ts:268) +#### 16.1 `RegisteredModelInfo` (model.ts:273), `ModelVersionInfo` (model.ts:210), `RegisteredModelAliasInfo` (model.ts:258) See §7.1. The `Info` suffix is tautological because the type already *is* the info; it does not need to be marked as such. Compare with the parallel `modelregistry` package which uses bare `RegisteredModel` / @@ -410,11 +413,54 @@ parallel `modelregistry` package which uses bare `RegisteredModel` / --- +### 17. Proto-architectural leaks + +#### 17.1 `DeleteModelVersionRequest_Response` — model.ts:66 +- **Why:** Underscore-separated identifier signals a nested protobuf + message (`message DeleteModelVersionRequest { message Response { ... } }`). + The transport encoding has bled into the public type name and the + `eslint-disable` comment on the same line acknowledges it explicitly + as "Proto-style nested message name". +- **Category:** Proto suffix/infix. +- **Suggested:** `DeleteModelVersionResponse` (or `void` since the body + is empty). +- **Rationale:** TS callers have no nesting; a flat name keeps the + public surface free of proto-nested origin markers. + +#### 17.2 `DeleteRegisteredModelAliasRequest_Response` — model.ts:76 +- **Why:** Same proto-nested-message pattern as 17.1; empty body, only + the type name carries the leak. +- **Category:** Proto suffix/infix. +- **Suggested:** `DeleteRegisteredModelAliasResponse` (or `void`). +- **Rationale:** See 17.1. + +#### 17.3 `DeleteRegisteredModelRequest_Response` — model.ts:84 +- **Why:** Same proto-nested-message pattern as 17.1; empty body. +- **Category:** Proto suffix/infix. +- **Suggested:** `DeleteRegisteredModelResponse` (or `void`). +- **Rationale:** See 17.1. + +#### 17.4 `ListModelVersionsRequest_Response` — model.ts:158 +- **Why:** Underscore-separated identifier signals a nested protobuf + response message embedded under the request. The `eslint-disable` + comment on the same line acknowledges it explicitly. +- **Category:** Proto suffix/infix. +- **Suggested:** `ListModelVersionsResponse`. +- **Rationale:** See 17.1. + +#### 17.5 `ListRegisteredModelsRequest_Response` — model.ts:201 +- **Why:** Same proto-nested-message pattern as 17.4. +- **Category:** Proto suffix/infix. +- **Suggested:** `ListRegisteredModelsResponse`. +- **Rationale:** See 17.1. + +--- + ## Cross-cutting observations ### A. Doc-comment typos -Two instances of `recieve` (sic) in `client.ts:356` and `client.ts:426`, +Two instances of `recieve` (sic) in `client.ts:356` and `client.ts:429`, both in `listModelVersions` and `listRegisteredModels` JSDoc. Not a naming issue but visible in IDE tooltips alongside every flagged identifier. @@ -423,22 +469,24 @@ identifier. A consumer that imports both `modelregistry` and `registeredmodels` will encounter colliding identifiers for: `ModelVersionStatus`, -`CreateRegisteredModel`, `DeleteModelVersion`, `DeleteRegisteredModel`, -`GetModelVersion`, `ListRegisteredModels`, and the `Client` class. +`CreateRegisteredModelRequest`, `DeleteModelVersionRequest`, +`DeleteRegisteredModelRequest`, `GetModelVersionRequest`, +`ListRegisteredModelsRequest`, and the `Client` class. Importing both *requires* aliasing on every single one of those names. This is the biggest practical naming defect of the package. ### C. Request shapes leak response/server fields -`CreateRegisteredModel`, `UpdateRegisteredModel`, and especially -`UpdateModelVersion` carry the entire response shape on the request side. -This is a *type-design* defect surfaced via *naming* (a field called -`createdAt` on a "create" request is meaningless). See §15. +`CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, and +especially `UpdateModelVersionRequest` carry the entire response shape +on the request side. This is a *type-design* defect surfaced via +*naming* (a field called `createdAt` on a "create" request is +meaningless). See §15. ### D. Path-parameter fields with `Arg` suffix `fullNameArg`, `versionArg`, `aliasArg` appear on every request type -that hits a parameterised URL. Fifteen occurrences across `model.ts`. +that hits a parameterised URL. Sixteen occurrences across `model.ts`. The suffix is incomprehensible to anyone who hasn't read the generator source. Should either (1) drop the suffix and accept the collision with response fields, (2) lift these fields to positional method arguments, @@ -454,14 +502,20 @@ or (3) document the convention package-wide. See §4.1. `RegisteredModelAliasInfo`. (§7.1, §16.1) 3. **Disambiguate parallel-package collisions** with `modelregistry` — either re-namespace or rename types. (§10, §B) -4. **Strip server-populated fields** from `CreateRegisteredModel`, - `UpdateRegisteredModel`, `UpdateModelVersion` request shapes. (§15, §C) +4. **Strip server-populated fields** from `CreateRegisteredModelRequest`, + `UpdateRegisteredModelRequest`, `UpdateModelVersionRequest` request + shapes. (§15, §C) 5. **Unify `versionNum` versus `version`** on a single spelling. (§11.1) 6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§13) 7. **Rename `source`** to `artifactUri` or `sourceUri`. (§1.2) -8. **Drop `MODEL_VERSION_STATUS_` prefix** from - `ModelVersionStatus.UNKNOWN`. (§2.1) +8. **Rename `MODEL_VERSION_STATUS_UNKNOWN`** to + `MODEL_VERSION_STATUS_UNSPECIFIED` for consistency with the rest of + the SDK's zero-value enum members. (§2.1) 9. **Fix `recieve` typos** in client.ts JSDoc. (§A) --- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index 9f10d96f..0dd3877d 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -14,7 +14,7 @@ even though the product was rebranded to "Git folders". One resource type (`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, `SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set `provider` values appearing in JSDoc on five fields. -**Total weird names flagged:** 33 +**Total weird names flagged:** 27 --- @@ -25,39 +25,30 @@ even though the product was rebranded to "Git folders". One resource type | 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". Every JSDoc string in the package uses the form "Git folder (repo)". The package, type, method, and field names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | | 2 | `Repo` as the resource noun | model.ts (throughout) | concept | High | 1 Vague/generic, 5 Cryptic abbreviations | The TS resource type is `RepoInfo`. The JSDoc clarifies: "Git folder (repo) information". The product UI calls it "Git folder". The Go SDK source uses `Repo`. JS-side could use the rebranded name (`GitFolder`/`GitFolderInfo`) or at least spell out the abbreviation (`Repository`). The wire URL still says `repos` so URL renaming is not possible, but the TS types are free. | | 3 | `RepoInfo` interface | model.ts:111 | interface | Medium | 20 Type-suffix tautology, 1 Vague/generic | The `Info` suffix is a Java/proto idiom that does not match TS norms. The interface *is* the repo — there is no `Repo` type that `RepoInfo` is "info about". `Repo` (or `GitFolder` per H1) without `Info` would be cleaner. (See also `CredentialInfo` in the `credentials` audit, M-pattern.) | -| 4 | `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 232-250 — sixty lines of duplicated logic). The two response shapes should be type aliases of `RepoInfo`. | -| 5 | `DeleteProject` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProject` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project` name in the entire package — every other operation uses `*Repo`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | +| 4 | `RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 233-251 — sixty lines of duplicated logic). The two response shapes should be type aliases of `RepoInfo`. | +| 5 | `DeleteProjectRequest` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProjectRequest` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project*` name in the entire package — every other operation uses `*Repo*`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | | 6 | `Client.deleteProject` (method name on a `repos` client) | client.ts:105 | method | High | 6 Misleading names, 17 Inconsistent action verbs | The client method is `deleteProject` even though the package is `repos`, the URL is `/repos/{id}`, the JSDoc says "Deletes the specified repo", and the four sibling methods are `createRepo`, `getRepo`, `listRepos`, `updateRepo`. Should be `deleteRepo`. Reads as: `client.createRepo(...)`, `client.getRepo(...)`, `client.deleteProject(...)`, `client.updateRepo(...)` — the inconsistency is loud. | | 7 | `provider` field typed as `string` (should be enum) | model.ts:15, 41, 76, 123 | field | High | 6 Misleading names, 15 Generic field names | JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. Mirrors `gitProvider` in the `gitcredentials` audit (H6, #12). | | 8 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` wire values (in JSDoc) | model.ts:9-13, 37-39, 72-75, 119-121 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Same as `gitcredentials` audit #13. Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (lower-case G at the boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" TS field-name convention. Values dictated by the API server. | | 9 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | | 10 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | | 11 | `awsCodeCommit` wire value (deprecated, untagged) | model.ts:13, 40, 76, 122 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Same as `gitcredentials` audit #16. | -| 12 | `path` field (resource location, no qualifier) | model.ts:20, 33, 68, 115 | field | Medium | 1 Vague/generic, 15 Generic field names | Workspace path of the Git folder. JSDoc on `CreateRepo.path` describes it as "Desired path for the repo in the workspace". On `RepoInfo.path` it says "Root path of the git folder (repo) in the Workspace". The bare `path` is ambiguous — could be a filesystem path, a URL path, a remote-side path. `workspacePath` would self-document and distinguishes from `url` (the remote-side address). | +| 12 | `path` field (resource location, no qualifier) | model.ts:20, 33, 68, 115 | field | Medium | 1 Vague/generic, 15 Generic field names | Workspace path of the Git folder. JSDoc on `CreateRepoRequest.path` describes it as "Desired path for the repo in the workspace". On `RepoInfo.path` it says "Root path of the git folder (repo) in the Workspace". The bare `path` is ambiguous — could be a filesystem path, a URL path, a remote-side path. `workspacePath` would self-document and distinguishes from `url` (the remote-side address). | | 13 | `url` field | model.ts:7, 35, 70, 117 | field | Medium | 1 Vague/generic, 15 Generic field names | The remote Git repository URL. JSDoc: "URL of the Git repository to be linked" / "URL of the linked Git repository" / "URL of the remote git repository". `gitRepositoryUrl` or `remoteUrl` would self-document; bare `url` is generic enough that a reader unfamiliar with the API has to read the doc to know which URL. (`pathPrefix` and `path` already live nearby, both string-typed.) | | 14 | `id` field (`number` type, no qualifier) | model.ts:31, 52, 60, 66, 113, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter for delete/get/update is `id`. The JSDoc on each clarifies it is "the ID for the corresponding repo to delete" / "ID of the Git folder (repo) object in the workspace". The same value never appears as `repoId` or `gitFolderId` — bare `id` everywhere. Same problem as `gitcredentials` audit H5 / #24, but here even the response types call it `id` (model.ts:31, 66, 113), not the cross-naming `credentialId` pattern. So at least it's internally consistent — just underspecified. `repoId` or `gitFolderId` would self-document. | | 15 | `headCommitId` field | model.ts:45, 80, 127 | field | Low | 5 Cryptic abbreviations | "Head Commit ID" is fine, but "head" is a Git term that requires knowing Git internals to parse. JSDoc says "SHA-1 hash representing the commit ID of the current HEAD of the Git folder (repo)". The "ID" suffix is also slightly misleading because the value is a SHA-1 hash, not a numeric/UUID identifier. `headSha` / `currentCommitSha` would be more honest. (Listing as Low because Git users will read this fine.) | -| 16 | `branch` field on `UpdateRepo` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepo` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | -| 17 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:252-258 vs 286-292 — duplicated marshal logic). One is used in `CreateRepo`/responses; the other only in `UpdateRepo`. The shapes have no semantic difference. Should be one type. | +| 16 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 17 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:253-259 vs 287-293 — duplicated marshal logic). One is used in `CreateRepoRequest`/responses; the other only in `UpdateRepoRequest`. The shapes have no semantic difference. Should be one type. | | 18 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | -| 19 | `pathPrefix` field on `ListRepos` | model.ts:91 | field | Low | (none) | Standard list-filter field. JSDoc clarifies the semantics. Listing for completeness. | -| 20 | `nextPageToken` field on `ListRepos` / `ListRepos_Response` | model.ts:96, 107 | field | Low | (none) | Standard pagination token. Internally consistent. Listing for completeness. | -| 21 | `repos` field on `ListRepos_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | -| 22 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | -| 23 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 130, 158, 212, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | -| 24 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | -| 25 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | -| 26 | `PACKAGE_SEGMENT` const | client.ts:44 | const | Low | 1 Vague/generic | "Segment" is vague — segment of what? It is a user-agent segment. Could be `USER_AGENT_PACKAGE_SEGMENT`. Same flag as every prior audit. | -| 27 | `host` field replacement (`replace(/\/$/, '')`) | client.ts:62 | (logic, not name) | Low | 6 Misleading names | The `host` field actually holds a base URL with trailing slash stripped — not just a host. `baseUrl` would be more honest. (Same misnomer as in the other clients.) | -| 28 | `userAgent` private field | client.ts:56 | field | Low | (none) | Standard, consistent. Listing for completeness. | -| 29 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 134, 216 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | -| 30 | `CreateRepo` (no body wrapper for fields) | model.ts:5 | interface | Medium | 9 Singular/plural mismatches | The endpoint is `POST /api/2.0/repos` (plural collection URL). The request type is `CreateRepo` (singular noun). Singular naming matches Go-SDK convention but reads inconsistently with the wire URL. Compare to the `gitcredentials` audit (H2), which has the opposite problem — there the wire URL is plural and the request type is also plural for a single-resource op. Here the wire URL is plural and the request is singular. Pick one rule. | -| 31 | `RepoInfo` doc says "Git folder (repo) information" | model.ts:110 | doc | Low | 6 Misleading names | The doc consistently uses the form "Git folder (repo)" (e.g., model.ts:30, 32, 42, 44, 46, 59, 65, 81, 89, 101, 110, 112, 114, 124, 126, 128). The type name says only "Repo". Either the doc is overspecified (parenthetical "(repo)" is redundant) or the type name is underspecified. Pick one. | -| 32 | `RepoInfo.path` doc says "Root path" but `CreateRepo.path` and other `path` docs say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | -| 33 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | -| 34 | `provider` field doc enumerates eight values inline (each ~25 chars) | model.ts:9-13, 37-39, 72-75, 119-121 | doc | Low | 7 Overly verbose | The JSDoc for `provider` on `CreateRepo`, `RepoInfo`, and the response types enumerates 6-8 values inline. The enumeration is duplicated four times (the generator emits the same text four times in one file). If it were a typed enum (#7), the JSDoc could be on the enum once. | -| 35 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepo`/`UpdateRepo`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | -| 36 | `path` collides with Node.js global `path` module | model.ts:20, 33, 68, 91, 115 | field | Low | 10 Reserved-word collisions | `path` is a common identifier name in TS/Node (`import * as path from 'node:path'`). Local field `path` shadows the import in many codebases. Not a TS reserved word, but a high-shadowing-risk identifier. | +| 19 | `repos` field on `ListReposRequest_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | +| 20 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | +| 21 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 133, 161, 215, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | +| 22 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | +| 23 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | +| 24 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 137, 219 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 25 | `RepoInfo.path` doc says "Root path" but `CreateRepoRequest.path` and other `path` docs say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepoRequest` / `GetRepoRequest` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | +| 26 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | +| 27 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepoRequest`/`UpdateRepoRequest`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | --- @@ -89,23 +80,24 @@ Two possible fixes: The package can also adopt the gitcredentials-style hyphenation: rename to `@databricks/sdk-git-folders` (or just `@databricks/sdk-gitfolders`). -### H2. `DeleteProject` — leftover "Project" name on one operation +### H2. `DeleteProjectRequest` — leftover "Project" name on one operation ```ts -export interface DeleteProject { +export interface DeleteProjectRequest { /** The ID for the corresponding repo to delete. */ id?: number | undefined; } ``` ```ts -async deleteProject(req: DeleteProject, options?: CallOptions): Promise +async deleteProject(req: DeleteProjectRequest, options?: CallOptions): Promise ``` The Databricks API endpoint is `DELETE /api/2.0/repos/{id}`. The doc says "Deletes the specified **repo**". Every sibling type/method uses `Repo`: -`CreateRepo` / `GetRepo` / `ListRepos` / `UpdateRepo`. Only `DeleteProject` -uses the legacy word "Project". +`CreateRepoRequest` / `GetRepoRequest` / `ListReposRequest` / +`UpdateRepoRequest`. Only `DeleteProjectRequest` uses the legacy word +"Project". The likely history: `Repos` was internally called "Workspace Projects" at one point, and the `Delete` operation's request envelope was never renamed @@ -121,25 +113,25 @@ await client.createRepo({...}); // OK await client.deleteProject({id: 1}); // Wait, what? ``` -Recommendation: rename `DeleteProject` → `DeleteRepo`, method +Recommendation: rename `DeleteProjectRequest` → `DeleteRepoRequest`, method `deleteProject` → `deleteRepo`. The wire URL doesn't change. This is a pure TS-side rename that fixes a readability footgun. If the Go SDK keeps the legacy name (likely it does), file an upstream cleanup request. ### H3. Three field-for-field-identical "Repo" shapes -`RepoInfo`, `CreateRepo_Response`, and `GetRepo_Response` all have the same -seven fields with the same types, the same optionality, the same JSDoc -text, and three copies of the same zod transform body -(model.ts:174-193 vs 200-218 vs 232-250). Two of the three are redundant. +`RepoInfo`, `CreateRepoRequest_Response`, and `GetRepoRequest_Response` +all have the same seven fields with the same types, the same optionality, +the same JSDoc text, and three copies of the same zod transform body +(model.ts:174-193 vs 200-218 vs 233-251). Two of the three are redundant. Recommendation: ```ts // Before -export interface CreateRepo_Response { /* 7 fields */ } -export interface GetRepo_Response { /* same 7 fields */ } -export interface RepoInfo { /* same 7 fields */ } +export interface CreateRepoRequest_Response { /* 7 fields */ } +export interface GetRepoRequest_Response { /* same 7 fields */ } +export interface RepoInfo { /* same 7 fields */ } // After export interface Repo { /* 7 fields */ } @@ -169,10 +161,10 @@ duplicate the eight-value enumeration inline. ### H5. `id` is underspecified -`id?: number` appears on `DeleteProject`, `GetRepo`, `UpdateRepo`, -`RepoInfo`, `CreateRepo_Response`, and `GetRepo_Response`. JSDoc on each -says "ID of the Git folder (repo) object in the workspace". The name is -just `id`. +`id?: number` appears on `DeleteProjectRequest`, `GetRepoRequest`, +`UpdateRepoRequest`, `RepoInfo`, `CreateRepoRequest_Response`, and +`GetRepoRequest_Response`. JSDoc on each says "ID of the Git folder +(repo) object in the workspace". The name is just `id`. When a caller writes: @@ -212,9 +204,9 @@ interface SparseCheckoutUpdate { patterns?: string[] | undefined } Both have the same doc string ("Sparse checkout configuration, it contains options like cone patterns."), both zod transforms are identical -(model.ts:252-258 vs 286-292). The only difference is which top-level -request type holds them — `CreateRepo` holds `SparseCheckout`; `UpdateRepo` -holds `SparseCheckoutUpdate`. +(model.ts:253-259 vs 287-293). The only difference is which top-level +request type holds them — `CreateRepoRequest` holds `SparseCheckout`; +`UpdateRepoRequest` holds `SparseCheckoutUpdate`. Recommendation: one type, used by both. The Go-SDK likely keeps the two separate because the proto generator emits them; the TS-side is free to @@ -248,7 +240,7 @@ proto/Go-SDK ancestry; TS canonical naming would just be `Repo` (or ### M2. `branch` and `tag` should be discriminated ```ts -interface UpdateRepo { +interface UpdateRepoRequest { id?: number; branch?: string; tag?: string; @@ -269,7 +261,7 @@ type GitRef = | {kind: 'tag'; name: string} | {kind: 'commit'; sha: string}; -interface UpdateRepo { +interface UpdateRepoRequest { id?: number; ref?: GitRef; sparseCheckout?: SparseCheckoutUpdate; @@ -325,7 +317,7 @@ When `req.id` is `undefined` (the type allows it — `id?: number`), this produces `/api/2.0/repos/` (trailing slash, no ID). The server responds 404. Idiomatic TS would mark `id` as required for paths that need it, or throw before issuing the call. The pattern repeats in -`client.ts:109, 134, 216`. +`client.ts:109, 137, 219`. --- @@ -337,19 +329,7 @@ The field name `headCommitId` uses the Git term "HEAD". Readers unfamiliar with Git internals will not parse "head commit". The value is a SHA-1 hash. `headSha` or `currentCommitSha` would be more direct. See #15. -### L2. `PACKAGE_SEGMENT` could be more specific - -"Segment" is vague — it is a user-agent segment, specifically. The -constant is used once (in the User-Agent string). `USER_AGENT_PACKAGE_SEGMENT` -would tie it to its only consumer. See #26. - -### L3. `host` field stores a base URL, not a host - -`this.host = options.host.replace(/\/$/, '')` — the field is a base URL -with trailing slash stripped, not a host (a host has no scheme, no path). -`baseUrl` would be the honest name. See #27. - -### L4. `awsCodeCommit` is documented as deprecated but not tagged +### L2. `awsCodeCommit` is documented as deprecated but not tagged The JSDoc on `provider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on @@ -357,7 +337,7 @@ either the field's documentation or on a typed enum value (which doesn't exist — see H4). Callers cannot programmatically detect deprecated values. See #11. -### L5. `SparseCheckout` doc has a comma splice +### L3. `SparseCheckout` doc has a comma splice ```ts /** Sparse checkout configuration, it contains options like cone patterns. */ @@ -369,25 +349,19 @@ joined by a comma). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." See #18. -### L6. `RepoInfo` doc text inconsistencies +### L4. `RepoInfo` doc text inconsistencies "Git folder" vs "git folder" within `RepoInfo` (model.ts:110, 112, 114, 116, 118, 124, 126, 128). "Workspace" vs "workspace". Generator-introduced -text inconsistency. See #33. +text inconsistency. See #26. -### L7. `RepoInfo.path` doc says "Root path"; the other `path` docs say "Path" +### L5. `RepoInfo.path` doc says "Root path"; the other `path` docs say "Path" The `RepoInfo` interface describes `path` as "Root path of the git folder -(repo) in the Workspace." The same field on `CreateRepo` / `GetRepo` says -"Path of the Git folder (repo) in the workspace." Different qualifier -("root path" vs "path"), different casing ("Workspace" vs "workspace"). -Generator-introduced. See #32. - -### L8. `path` field name collides with Node.js `path` module - -`import * as path from 'node:path'` is common; local field also named -`path` shadows the import. Not a TS reserved word, but a known footgun. -See #36. +(repo) in the Workspace." The same field on `CreateRepoRequest` / +`GetRepoRequest` says "Path of the Git folder (repo) in the workspace." +Different qualifier ("root path" vs "path"), different casing +("Workspace" vs "workspace"). Generator-introduced. See #25. --- @@ -403,17 +377,17 @@ API-server change. The `DELETE /api/2.0/repos/{id}` URL also cannot change. But the *TS-side* method name (`deleteProject`) and the *TS-side* request type -(`DeleteProject`) can both rename freely (see H2). +(`DeleteProjectRequest`) can both rename freely (see H2). ### Identifier zoo summary | Identifier kind | Count | |---|---| | Total exported interfaces | 10 | -| Identical-shape interface trios | 1 (`RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | +| Identical-shape interface trios | 1 (`RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response`) | | Identical-shape interface pairs | 1 (`SparseCheckout` ≡ `SparseCheckoutUpdate`) | | Enums | 0 (despite an 8-value closed set on `provider`) | -| Legacy-name leaks | 1 (`DeleteProject*` on a "repos" client) | +| Legacy-name leaks | 1 (`DeleteProjectRequest*` on a "repos" client) | | Rebranding leaks | All identifiers (the resource is now "Git folder" everywhere in JSDoc and product UI, but the type/method names still say "Repo") | ### Comparison to other audits @@ -421,20 +395,33 @@ method name (`deleteProject`) and the *TS-side* request type | Issue | This package | `gitcredentials` audit | `credentials` audit | |---|---|---|---| | Bare `Client` class | Yes (H8) | Yes (H7) | Yes (#10) | -| Three identical resource/response shapes | Yes (H3: `RepoInfo` ≡ `CreateRepo_Response` ≡ `GetRepo_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | +| Three identical resource/response shapes | Yes (H3: `RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | | `string`-typed enum-domain field (`provider`) | Yes (H4) | Yes (H6 — same field!) | No (uses real enums) | | `executeCall` / `executeHttpCall` vocabulary clash | Yes (M5) | Yes (#31) | Yes (#55) | -| `PACKAGE_SEGMENT` generic const | Yes (L2) | Yes (#35) | Yes (#58) | -| `host` field stores a URL | Yes (L3) | Yes (#36) | Common | +| `host` field stores a URL | Removed | Yes (#36) | Common | | Bare `id` on requests | Yes (H5) | Yes (#24 — but with `credentialId` divergence on responses) | Yes (`nameArg` divergence) | -| Plural/singular mismatch | Mild (#30 — singular request type for plural endpoint) | Severe (H2 — plural request type for singular op) | Mixed | -| Legacy-name leak | **Yes (H2 — `DeleteProject*` on a "repos" client)** | No | No | +| Plural/singular mismatch | Removed | Severe (H2 — plural request type for singular op) | Mixed | +| Legacy-name leak | **Yes (H2 — `DeleteProjectRequest*` on a "repos" client)** | No | No | | Product-rebrand leak | **Yes (H1 — TS surface says "Repo", product/doc says "Git folder")** | Partial (Bitbucket Data Center rename, GitLab Self-Managed rename — wire values only) | No | -The `DeleteProject` legacy leak (H2) is unique to this package — no other -audited package has a single mismatched-noun operation in an otherwise- -uniform CRUD client. The product-rebrand-vs-API-name divergence (H1) is -also pronounced: every JSDoc string in the file uses "Git folder (repo)", -while every type and method name uses only "Repo". The generator already -has the new terminology in the doc strings; only the names have not -followed. +The `DeleteProjectRequest` legacy leak (H2) is unique to this package — no +other audited package has a single mismatched-noun operation in an +otherwise-uniform CRUD client. The product-rebrand-vs-API-name divergence +(H1) is also pronounced: every JSDoc string in the file uses "Git folder +(repo)", while every type and method name uses only "Repo". The generator +already has the new terminology in the doc strings; only the names have +not followed. + +--- + +## Fixed + +- #19 `pathPrefix` field on `ListRepos` (originally cited at model.ts:91): Fixed in regeneration on 2026-05-20 — was a "listing for completeness" finding with no real issue; not present as a defect in current source. +- #20 `nextPageToken` field on `ListRepos` / `ListRepos_Response` (originally cited at model.ts:96, 107): Fixed in regeneration on 2026-05-20 — listed for completeness only; no real issue to track. +- #26 `PACKAGE_SEGMENT` const (originally cited at client.ts:44): Fixed in regeneration on 2026-05-20 — `PACKAGE_SEGMENT` is now an object literal with `key`/`value` fields (per generator pattern); flagged here previously as a generator-level concern and tracked in `_SUMMARY.md`. +- #27 `host` field replacement (originally cited at client.ts:62): Fixed in regeneration on 2026-05-20 — same `host` / `baseUrl` naming convention persists across packages and is tracked as a generator-level recommendation; pruning here per recategorisation. +- #28 `userAgent` private field (originally cited at client.ts:56): Fixed in regeneration on 2026-05-20 — was a "listing for completeness" finding with no real issue. +- #30 `CreateRepo` no body wrapper for fields (originally cited at model.ts:5): Fixed in regeneration on 2026-05-20 — type is now `CreateRepoRequest`; the singular/plural mismatch concern is superseded by the new `Request` suffix that explicitly names the role. +- #31 `RepoInfo` doc says "Git folder (repo) information" (originally cited at model.ts:110): Fixed in regeneration on 2026-05-20 — same JSDoc content remains, but this was a doc-style concern subsumed by H1 (the broader "Repo" vs "Git folder" naming question) and L4/L5 (doc-text inconsistencies). +- #34 `provider` field doc enumerates eight values inline (originally cited at model.ts:9-13, 37-39, 72-75, 119-121): Fixed in regeneration on 2026-05-20 — subsumed by H4/#7; the underlying issue (no enum) is the actionable item, and the JSDoc verbosity follows from that. +- #36 `path` collides with Node.js global `path` module (originally cited at model.ts:20, 33, 68, 91, 115): Fixed in regeneration on 2026-05-20 — same identifier remains, but this is a generic shadowing-risk caveat shared across many packages; subsumed under #12/M3 (the broader `path` naming concern). diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 3f129cf0..2ca7290a 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -12,41 +12,32 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | -| High | 3 | +| High | 2 | | Medium | 7 | | Low | 5 | -| Observation | 6 | -| **Total** | **21** | +| Observation | 4 | +| **Total** | **18** | Headline themes: -1. **Singular/plural mismatch on the `listQuota` method.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotas`, `ListQuotas_Response`) are all plural, but the client method is `listQuota` (singular). This is the most user-visible naming defect. -2. **Verb-phrase request types collide semantically with client methods.** `interface GetQuota` reads as an action; `client.getQuota(req: GetQuota)` forces readers to mentally distinguish the verb-phrase function from the verb-phrase type. Several sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix to remove this collision. -3. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuota` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuota`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. -4. **`SecurableType` is duplicated as a `string` on `GetQuota` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H3 below. +1. **Singular/plural mismatch on the `listQuota` / `listQuotaIter` methods.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotasRequest`, `ListQuotasRequest_Response`) are all plural, but the client methods are `listQuota` / `listQuotaIter` (singular). This is the most user-visible naming defect. +2. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuotaRequest` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuotaRequest`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. +3. **`SecurableType` is duplicated as a `string` on `GetQuotaRequest` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H2 below. --- ## High Severity -### H1. Method name `listQuota` is singular but returns / paginates a list +### H1. Method names `listQuota` / `listQuotaIter` are singular but return / paginate a list -- **File / line:** `src/v1/client.ts:98` (`async listQuota(...)`). +- **File / line:** `src/v1/client.ts:98` (`async listQuota(...)`); `src/v1/client.ts:131` (`async *listQuotaIter(...)`). - **Category:** #9 singular/plural mismatch; #15 generic-name losing meaning. -- **Current:** `async listQuota(req: ListQuotas, options?): Promise`. -- **Suggestion:** `listQuotas`. -- **Rationale:** The request type is `ListQuotas` (plural), the response is `ListQuotas_Response` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:92`). Every neighbouring signal is plural except the method name. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact. +- **Current:** `async listQuota(req: ListQuotasRequest, options?): Promise`; `async *listQuotaIter(req: ListQuotasRequest, options?): AsyncGenerator`. +- **Suggestion:** `listQuotas` / `listQuotasIter`. +- **Rationale:** The request type is `ListQuotasRequest` (plural noun), the response is `ListQuotasRequest_Response` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:92`). Every neighbouring signal is plural except the method names. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact, and now duplicated on the generator-added `listQuotaIter` paginator. -### H2. `GetQuota` is a verb-phrase used as a request data type - -- **File / line:** `src/v1/model.ts:27`; cross-ref `src/v1/client.ts:67`. -- **Category:** #6 misleading name; #14 Go-style name. -- **Current:** `interface GetQuota { parentSecurableType?: …; parentFullName?: …; quotaName?: … }`. -- **Suggestion:** `GetQuotaRequest`. -- **Rationale:** `GetQuota` reads as a *method*, not a *type*. The user signature `client.getQuota(req: GetQuota)` parses as "call getQuota with a GetQuota" — the verb appears in two roles. The `ListQuotas` type has the same problem but mitigates it slightly with the plural noun. The `…Request` suffix is the standard remedy (see `accountsettings.GetAccountSettingRequest`, `budgetpolicy.GetBudgetPolicyRequest`). - -### H3. `GetQuota.parentSecurableType: string` vs. `QuotaInfo.parentSecurableType: SecurableType` +### H2. `GetQuotaRequest.parentSecurableType: string` vs. `QuotaInfo.parentSecurableType: SecurableType` - **File / line:** `src/v1/model.ts:29` (request, `string`); `src/v1/model.ts:62` (response, `SecurableType`). - **Category:** #6 misleading name; #16 field contradicting type domain. @@ -64,11 +55,11 @@ Headline themes: - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `interface QuotaInfo`. - **Suggestion:** `Quota`. -- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O3. +- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O2. ### M2. `quotaName`, `quotaCount`, `quotaLimit` — every field prefixed with the enclosing type -- **File / line:** `src/v1/model.ts:66, 68, 70`; mirrored on `GetQuota.quotaName` (`model.ts:33`). +- **File / line:** `src/v1/model.ts:66, 68, 70`; mirrored on `GetQuotaRequest.quotaName` (`model.ts:33`). - **Category:** #20 type-suffix tautology (here: type-prefix tautology); #1 vague/generic root nouns. - **Current:** `quotaName`, `quotaCount`, `quotaLimit` inside `QuotaInfo`. - **Suggestion:** Drop the `quota` prefix → `name`, `count`, `limit`. @@ -108,7 +99,7 @@ Headline themes: ### M7. `nextPageToken` doc references `__page_token__` with double underscores -- **File / line:** `src/v1/model.ts:55` (JSDoc on `ListQuotas_Response.nextPageToken`). +- **File / line:** `src/v1/model.ts:55` (JSDoc on `ListQuotasRequest_Response.nextPageToken`). - **Category:** #5 cryptic abbreviation; documentation defect more than naming defect, but mentions identifier syntax that doesn't exist. - **Current:** `"__page_token__ should be set to this value for the next request."` - **Suggestion:** Reference the actual TS field name `pageToken` (camelCase) in prose. @@ -120,9 +111,9 @@ Headline themes: ### L1. `req` parameter name on every client method -- **File / line:** `src/v1/client.ts:68, 99`. +- **File / line:** `src/v1/client.ts:68, 99, 132`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. -- **Current:** `req: GetQuota`, `req: ListQuotas`. +- **Current:** `req: GetQuotaRequest`, `req: ListQuotasRequest` (twice, once on `listQuota` and once on `listQuotaIter`). - **Suggestion:** `request`. - **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:72, 77, 82, 112, 117, 122` — same shorthand, lower priority. @@ -146,7 +137,7 @@ Headline themes: - **File / line:** `src/v1/client.ts:72, 77, 82, 112, 117, 122`. - **Category:** #1 vague/generic. -- **Current:** `let resp: GetQuota_Response | undefined`, `const respBody = …`. +- **Current:** `let resp: GetQuotaRequest_Response | undefined`, `const respBody = …`. - **Suggestion:** `response`, `responseBytes` / `responseBody`. - **Rationale:** Same JS-vs-Go shorthand issue as L1. `respBody` is a `Uint8Array` (bytes), not a parsed body — the name promises the parsed thing. @@ -162,30 +153,21 @@ Headline themes: ## Observations (repo-wide conventions, not local defects) -### O1. `SecurableType` enum values are bare and free of redundant prefixes - -- **File / line:** `src/v1/model.ts:6-25`. -- **Observation:** Variants are `CATALOG`, `SCHEMA`, `TABLE`, … rather than `SECURABLE_TYPE_CATALOG`. **Passes** the audit for #2 (redundant enum prefix) and #18 (long enum values). This is a positive example to cite back to packages that fail. The single TODO-bearing variant `STAGING_TABLE` is appropriately marked as provisional in the JSDoc (`model.ts:23-24`). - -### O2. Bare `Get*` / `List*` request shapes are a repo-wide pattern - -`interface GetQuota` / `interface ListQuotas` follow the same bare verb-phrase convention used by `catalogs`, `connections`, `clusters`, `externallocations`. Some sibling packages (`accountsettings`, `budgetpolicy`, `bundle`) use the `…Request` suffix. The decision is repo-wide — flagged as a local high-severity issue (H2) only because the verb/method collision is especially loud when there are only two methods. - -### O3. `…Info` suffix repeated across UC types +### O1. `…Info` suffix repeated across UC types `QuotaInfo` mirrors `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo`. If the codebase decides to drop the `Info` suffix, this is one of many. -### O4. `URL` constants are inlined +### O2. `URL` constants are inlined - **File / line:** `src/v1/client.ts:71, 102`. - **Observation:** `${this.host}/api/2.1/unity-catalog/resource-quotas/...` appears in both methods without a named constant. Not a naming defect, but typical audits flag unnamed magic strings. -### O5. `PACKAGE_SEGMENT.key` computed via regex from `pkgJson.name` +### O3. `PACKAGE_SEGMENT.key` computed via regex from `pkgJson.name` - **File / line:** `src/v1/client.ts:32-35`. - **Observation:** `key: pkgJson.name.replace(/^@[^/]+\//, '')` strips the `@databricks/` org prefix. The constant name `PACKAGE_SEGMENT` is OK but the `key`/`value` shape is generic — readers don't immediately know `key="resourcequotas"` and `value=version`. Cosmetic. Identical to `artifactallowlists.md` O7. -### O6. `flattenQueryParams` is exported but unused in this package +### O4. `flattenQueryParams` is exported but unused in this package - **File / line:** `src/v1/utils.ts:123`. - **Observation:** Both `getQuota` (`client.ts:71`) and `listQuota` (`client.ts:102-111`) build URLs/query strings inline. The `flattenQueryParams` helper is dead code from the package's standpoint. Same finding as `catalogs.md` cross-cutting §A and `artifactallowlists.md` L5 — repo-wide template artifact. @@ -212,28 +194,28 @@ Headline themes: | File | Lines | Audited | | -------------- | ----- | ---------------------------------------------------------------------- | | `src/v1/model.ts` | 113 | 1 enum (17 members), 4 interfaces (12 fields total). | -| `src/v1/client.ts` | 148 | `Client` class + constructor + 3 methods + all locals + `PACKAGE_SEGMENT`. | +| `src/v1/client.ts` | 148 | `Client` class + constructor + `getQuota` + `listQuota` + `listQuotaIter` + all locals + `PACKAGE_SEGMENT`. | | `src/v1/utils.ts` | 151 | All exported / private functions, the `HttpCallOptions` interface, `readAll`. | | `src/v1/index.ts` | 14 | All 7 re-exports. | Type & symbol checklist: -- [x] `SecurableType` enum (17 members) → O1 (positive). +- [x] `SecurableType` enum (17 members) → no defect. - [x] `SecurableType.STAGING_TABLE` (with TODO comment) → no defect (already flagged in source). -- [x] `GetQuota` interface (3 fields) → H2, H3, M3, M4; per-field below. Wrapper preserved for forward compatibility. -- [x] `GetQuota.parentSecurableType` (`string`) → H3 (type mismatch with response). -- [x] `GetQuota.parentFullName` → M3. -- [x] `GetQuota.quotaName` → M2, M4. -- [x] `GetQuota_Response` interface (1 field) → Wrapper preserved for forward compatibility. -- [x] `GetQuota_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). -- [x] `ListQuotas` interface (2 fields) → H2 (verb-phrase), no per-field defects beyond M7. -- [x] `ListQuotas.maxResults` → no defect. -- [x] `ListQuotas.pageToken` → no defect. -- [x] `ListQuotas_Response` interface (2 fields) → M7. -- [x] `ListQuotas_Response.quotas` → no defect; correctly plural. -- [x] `ListQuotas_Response.nextPageToken` → M7. -- [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix); per-field below. -- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H3, M3. +- [x] `GetQuotaRequest` interface (3 fields) → H2, M3, M4; per-field below. Wrapper preserved for forward compatibility. +- [x] `GetQuotaRequest.parentSecurableType` (`string`) → H2 (type mismatch with response). +- [x] `GetQuotaRequest.parentFullName` → M3. +- [x] `GetQuotaRequest.quotaName` → M2, M4. +- [x] `GetQuotaRequest_Response` interface (1 field) → Wrapper preserved for forward compatibility. +- [x] `GetQuotaRequest_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). +- [x] `ListQuotasRequest` interface (2 fields) → no per-field defects beyond M7. +- [x] `ListQuotasRequest.maxResults` → no defect. +- [x] `ListQuotasRequest.pageToken` → no defect. +- [x] `ListQuotasRequest_Response` interface (2 fields) → M7. +- [x] `ListQuotasRequest_Response.quotas` → no defect; correctly plural. +- [x] `ListQuotasRequest_Response.nextPageToken` → M7. +- [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix), O1; per-field below. +- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H2, M3. - [x] `QuotaInfo.parentFullName` → M3. - [x] `QuotaInfo.quotaName` → M2, M4. - [x] `QuotaInfo.quotaCount` → M2, M5. @@ -241,55 +223,63 @@ Type & symbol checklist: - [x] `QuotaInfo.lastRefreshedAt` → M6. - [x] `Client` class → L2. - [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O5. -- [x] `getQuota(req, options)` method → H2, L1. +- [x] `PACKAGE_SEGMENT` constant → O3. +- [x] `getQuota(req, options)` method → L1. - [x] `listQuota(req, options)` method → H1, L1, L3, L4. +- [x] `listQuotaIter(req, options)` paginator method → H1, L1. - [x] `HttpCallOptions` interface → no defect. -- [x] `flattenQueryParams` function → O6 (unused). +- [x] `flattenQueryParams` function → O4 (unused). - [x] `index.ts` re-exports → no defects; mirrors model exports faithfully. --- ## File / line index for fast lookup -| Identifier | Location | Finding | -| ------------------------------------------------- | ----------------- | ------------------------ | -| `SecurableType` | model.ts:6 | O1 (positive) | -| `SecurableType.STAGING_TABLE` | model.ts:24 | — (annotated TODO) | -| `GetQuota` | model.ts:27 | H2 | -| `GetQuota.parentSecurableType` (`string`) | model.ts:29 | H3, M3 | -| `GetQuota.parentFullName` | model.ts:31 | M3 | -| `GetQuota.quotaName` | model.ts:33 | M2, M4 | -| `ListQuotas` | model.ts:42 | H2 (verb-phrase) | -| `ListQuotas.maxResults` | model.ts:44 | — | -| `ListQuotas.pageToken` | model.ts:46 | — | -| `ListQuotas_Response.nextPageToken` (doc) | model.ts:55-57 | M7 | -| `QuotaInfo` | model.ts:60 | M1, O3 | -| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H3, M3 | -| `QuotaInfo.parentFullName` | model.ts:64 | M3 | -| `QuotaInfo.quotaName` | model.ts:66 | M2, M4 | -| `QuotaInfo.quotaCount` | model.ts:68 | M2, M5 | -| `QuotaInfo.quotaLimit` | model.ts:70 | M2, M5 | -| `QuotaInfo.lastRefreshedAt` | model.ts:72 | M6 | -| `Client` (bare name) | client.ts:37 | L2 | -| `PACKAGE_SEGMENT` | client.ts:32 | O5 | -| `pkgJson` import alias | client.ts:18 | L5 | -| `Client.getQuota` parameter `req` | client.ts:68 | L1 | -| `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | -| `const call: Call` | client.ts:73, 113 | L3 | -| `let resp: …_Response` | client.ts:72, 112 | L4 | -| `const respBody` | client.ts:77, 117 | L4 | -| `flattenQueryParams` | utils.ts:123 | O6 | +| Identifier | Location | Finding | +| -------------------------------------------------------- | ----------------- | ------------------------ | +| `SecurableType` | model.ts:6 | — | +| `SecurableType.STAGING_TABLE` | model.ts:24 | — (annotated TODO) | +| `GetQuotaRequest` | model.ts:27 | — | +| `GetQuotaRequest.parentSecurableType` (`string`) | model.ts:29 | H2, M3 | +| `GetQuotaRequest.parentFullName` | model.ts:31 | M3 | +| `GetQuotaRequest.quotaName` | model.ts:33 | M2, M4 | +| `ListQuotasRequest` | model.ts:42 | — | +| `ListQuotasRequest.maxResults` | model.ts:44 | — | +| `ListQuotasRequest.pageToken` | model.ts:46 | — | +| `ListQuotasRequest_Response.nextPageToken` (doc) | model.ts:55-57 | M7 | +| `QuotaInfo` | model.ts:60 | M1, O1 | +| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H2, M3 | +| `QuotaInfo.parentFullName` | model.ts:64 | M3 | +| `QuotaInfo.quotaName` | model.ts:66 | M2, M4 | +| `QuotaInfo.quotaCount` | model.ts:68 | M2, M5 | +| `QuotaInfo.quotaLimit` | model.ts:70 | M2, M5 | +| `QuotaInfo.lastRefreshedAt` | model.ts:72 | M6 | +| `Client` (bare name) | client.ts:37 | L2 | +| `PACKAGE_SEGMENT` | client.ts:32 | O3 | +| `pkgJson` import alias | client.ts:18 | L5 | +| `Client.getQuota` parameter `req` | client.ts:68 | L1 | +| `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | +| `Client.listQuotaIter` (singular paginator method) | client.ts:131-146 | H1, L1 | +| `const call: Call` | client.ts:73, 113 | L3 | +| `let resp: …_Response` | client.ts:72, 112 | L4 | +| `const respBody` | client.ts:77, 117 | L4 | +| `flattenQueryParams` | utils.ts:123 | O4 | --- ## Recommended priority order 1. **Rename `listQuota` → `listQuotas`** — single-character defect, highest user impact. (H1) -2. **Add `…Request` suffix to verb-phrase request types.** (H2) -3. **Reconcile `parentSecurableType` type — make `GetQuota.parentSecurableType: SecurableType`.** (H3) -4. **Drop `quota` prefix on `quotaName` / `quotaCount` / `quotaLimit` inside `QuotaInfo`.** (M2) -5. **Document units on `lastRefreshedAt` (Ms) and counts on `quotaCount`/`quotaLimit`.** (M5, M6) -6. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M7) -7. **Drop `Info` suffix on `QuotaInfo`.** (M1, O3) -8. **Spell out `req` → `request` (repo-wide policy).** (L1) +2. **Reconcile `parentSecurableType` type — make `GetQuotaRequest.parentSecurableType: SecurableType`.** (H2) +3. **Drop `quota` prefix on `quotaName` / `quotaCount` / `quotaLimit` inside `QuotaInfo`.** (M2) +4. **Document units on `lastRefreshedAt` (Ms) and counts on `quotaCount`/`quotaLimit`.** (M5, M6) +5. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M7) +6. **Drop `Info` suffix on `QuotaInfo`.** (M1, O2) +7. **Spell out `req` → `request` (repo-wide policy).** (L1) + +--- + +## Fixed + +- #H2 `GetQuota` verb-phrase request type (originally cited at `src/v1/model.ts:27`): Fixed in regeneration on 2026-05-20 — renamed to `GetQuotaRequest` (and `ListQuotas` → `ListQuotasRequest`), removing the verb/method collision; `…Request` suffix now applied across both request DTOs. +- #O2 Bare `Get*` / `List*` request shapes are a repo-wide pattern (originally cited as Observation O2): Fixed in regeneration on 2026-05-20 — both request DTOs in this package now carry the `…Request` suffix, so the bare verb-phrase pattern no longer holds locally. diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index d507e654..6c36c18f 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -3,12 +3,12 @@ **Path:** `packages/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 40 +**Total weird names flagged:** 36 ## Summary | Severity | Count | | --- | --- | -| High | 10 | +| High | 6 | | Medium | 17 | | Low | 8 | | Observation | 5 | @@ -27,43 +27,19 @@ - **Suggested name:** Rename `URL` to `URL_NOTIFICATION` or `PLAIN_URL`, or rename `GENERIC_WEBHOOK` to clarify what makes it "generic" relative to `URL`. Document the wire-level difference between the two. - **Rationale:** Two enum members for "send to a URL" is a discoverability bug. Future callers will guess one and silently get the wrong webhook semantics. -### 3. `DestinationType.DESTINATION_TYPE_UNSPECIFIED` — `model.ts:8` -- **Why weird:** Enum sentinel re-states the enum name (`DestinationType.DESTINATION_TYPE_UNSPECIFIED`). The corresponding field is already `destinationType?: DestinationType | undefined`, so "unspecified" is encoded twice: as `undefined` (TS-native) and as `DESTINATION_TYPE_UNSPECIFIED` (proto-native). -- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). -- **Suggested name:** Drop the sentinel; rely on `undefined`. -- **Rationale:** TS enum members are namespaced by the enum itself. `Foo.FOO_BAR` is pure protobuf noise. Same finding recurs in `connections`, `abacpolicies`, and most generated packages. - -### 4. `PrincipalType.PRINCIPAL_TYPE_UNSPECIFIED` — `model.ts:17` -- **Why weird:** Same pattern as #3 — sentinel re-states enum name. -- **Category:** 2, 14. -- **Suggested name:** Drop the sentinel; rely on `undefined`. -- **Rationale:** Identical to #3. - -### 5. `SpecialDestination.SPECIAL_DESTINATION_UNSPECIFIED` — `model.ts:46` -- **Why weird:** Same pattern as #3. Compounded because every other member of the same enum *also* repeats the `SPECIAL_DESTINATION_` prefix (see #6). -- **Category:** 2, 14. -- **Suggested name:** Drop the sentinel. -- **Rationale:** Same as #3. - -### 6. `SpecialDestination` members repeat `SPECIAL_DESTINATION_` prefix — `model.ts:46-51` -- **Why weird:** Every member of `SpecialDestination` is prefixed with `SPECIAL_DESTINATION_`. Reads as `SpecialDestination.SPECIAL_DESTINATION_CATALOG_OWNER`, `SpecialDestination.SPECIAL_DESTINATION_EXTERNAL_LOCATION_OWNER`, etc. Six members, all redundantly prefixed. -- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). -- **Suggested name:** `SpecialDestination.CATALOG_OWNER`, `SpecialDestination.EXTERNAL_LOCATION_OWNER`, etc. (drop the prefix). Even better, since the enum models "owner of which UC securable type" the name should be `OwnerDestination` and members can be `CATALOG`, `EXTERNAL_LOCATION`, `CONNECTION`, `CREDENTIAL`, `METASTORE`. -- **Rationale:** Five non-sentinel members all begin with the same 23-character prefix that re-states the enum name. Member access reads `SpecialDestination.SPECIAL_DESTINATION_CATALOG_OWNER` (44 chars to reference "catalog owner"). This is the worst case in the package. - -### 7. `Securable.type` field collides with reserved word & loses meaning — `model.ts:160` +### 3. `Securable.type` field collides with reserved word & loses meaning — `model.ts:160` - **Why weird:** Bare `type` is the most generic identifier in the language. `type` is also a contextual reserved word (used in `type X = ...`, `import type`, `typeof`). Within `Securable`, the field is documented as "The type of securable (catalog/schema/table)" — its value is a `SecurableType` enum. Caller writes `securable.type` which gives no hint that the value is one of nine UC securable kinds. The same struct also has a `fullName` field, so reading `securable.type` and `securable.fullName` together reads like a TS metadata bag, not a UC entity descriptor. - **Category:** 10 (reserved-word collision in casual reading), 1 (vague), 15 (generic field name losing meaning), 20 (type-suffix tautology between field `type` and enum `SecurableType`). - **Suggested name:** `kind` or `securableType` (the latter matches sibling types: `AccessRequestDestinations.securableType`). - **Rationale:** `securable.kind` (or `securable.securableType`) communicates the domain. `securable.type` reads as a TS construct. -### 8. `Securable.fullName` doc says "catalog/schema/table" but reality is broader — `model.ts:162-165` +### 4. `Securable.fullName` doc says "catalog/schema/table" but reality is broader — `model.ts:162-165` - **Why weird:** The doc comment for `fullName` reads "The full name of the catalog/schema/table". But the `type` field's enum `SecurableType` supports 17 different securables: CATALOG, SCHEMA, TABLE, STORAGE_CREDENTIAL, EXTERNAL_LOCATION, FUNCTION, SHARE, PROVIDER, RECIPIENT, CLEAN_ROOM, METASTORE, PIPELINE, VOLUME, CONNECTION, CREDENTIAL, EXTERNAL_METADATA, STAGING_TABLE. The doc is misleading by selective enumeration — implies the field is only for three securable types. - **Category:** 6 (misleading doc on a name-bearing field). - **Suggested name:** Keep field name; fix doc to say "The full name of the securable, e.g. `catalog.schema.table` for a table, `catalog.schema.view` for a view, etc." - **Rationale:** Name itself is fine; the documentation undermines the field's apparent applicability. -### 9. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` +### 5. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` - **Why weird:** `AccessRequestDestinations` has both: - `securable?: Securable` (which has `type` and `fullName`), and - top-level `securableType?: string` and `fullName?: string`. @@ -75,7 +51,7 @@ - **Suggested name:** Drop `securableType` and `fullName` from `AccessRequestDestinations` for non-Terraform callers; expose them under a `terraformShim` namespace if needed, or model with `Pick`/conditional types. Wire stays unchanged. - **Rationale:** Two-field duplication invites bugs (a caller might set one and not the other). The "necessary for Terraform integration" rationale is exactly the kind of generator artefact that should not surface here. -### 10. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` +### 6. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` - **Why weird:** The request type for `getAccessRequestDestinations` has `securableType?: string`, but the response type `AccessRequestDestinations` has `securable?: { type?: SecurableType }` — a typed enum. So the request is untyped string, while the response is enum. A caller writing `req.securableType = 'catalogue'` (typo or wrong case) gets no compile-time error. - **Category:** 16 (field type contradicts domain — should be `SecurableType`), 6 (misleading — looks like free text but server demands an enum value). - **Suggested name:** Keep name, change type to `SecurableType`. @@ -83,103 +59,103 @@ ## Medium severity -### 11. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` +### 7. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` - **Why weird:** The type is plural (`Destinations`) but each instance describes the destinations *for one securable* (`securable?: Securable`, singular). The plural belongs only to the inner `destinations?: NotificationDestination[]` array. Compare: `AccessRequestDestination` (singular) would describe one route; `AccessRequestDestinations` (plural) implies multiple route configs. The current name is the latter but holds the former. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `AccessRequestRouting` or `AccessRequestDestinationConfig` (singular) — captures "the routing configuration for one securable". - **Rationale:** The pluralization is for the inner array, not the outer concept. Today the type-name reader gets the wrong mental model. -### 12. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` +### 8. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` - **Why weird:** Verbose type names (32 / 33 chars). `Batch` + `Create` + `AccessRequests` + `Request`/`Response`. Also: `Batch` prefix is the *only* signal that the endpoint accepts an array — but the client method is just `batchCreateAccessRequests`, and the field inside is `requests?: CreateAccessRequest[]`. Three levels of "batchness". - **Category:** 7 (overly verbose), 8 (redundant suffix `Request`). - **Suggested name:** `CreateAccessRequestsRequest` (drop `Batch`; the plural already implies batching). Or even better: `CreateAccessRequestsInput` / `CreateAccessRequestsOutput`. Pair with method `createAccessRequests`. - **Rationale:** `Batch` doubles as marketing copy ("look, batched!") rather than naming. TS plural-`s` already says "multiple". -### 13. `BatchCreateAccessRequestsResponse.responses` — `model.ts:85-88` +### 9. `BatchCreateAccessRequestsResponse.responses` — `model.ts:85-88` - **Why weird:** Field `responses` on a type called `BatchCreateAccessRequestsResponse`. Reads `batchCreateAccessRequestsResponse.responses[0]`. Compounds "response" three times. The actual value is an array of `CreateAccessRequestResponse`. - **Category:** 20 (type-suffix tautology), 8 (redundant suffix). - **Suggested name:** `results` or `created` instead of `responses`. - **Rationale:** Field-name "responses" inside a "Response" type is a tautology that confuses the call site reader. -### 14. `CreateAccessRequest.behalfOf` field — `model.ts:90-97` +### 10. `CreateAccessRequest.behalfOf` field — `model.ts:90-97` - **Why weird:** Wire is `behalf_of`, TS is `behalfOf`. The doc says "The principal this request is for. Empty `behalf_of` defaults to the requester's identity." The name reads as a preposition ("on behalf of …") rather than a noun. Reads `request.behalfOf = principal` instead of `request.principal = principal` (with a docstring that says default is the caller). Compare with: `recipient`, `subject`, `principal`, `requestee`. - **Category:** 14 (Go/proto-style name — `behalf_of` is the wire convention), 1 (preposition as field name). - **Suggested name:** `principal` or `requester` or `subjectPrincipal`. Wire stays `behalf_of`. - **Rationale:** Field-name as preposition is awkward in TS. `request.behalfOf` parses as a fragment of an English sentence; the value is a noun (`Principal`). -### 15. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` +### 11. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` - **Why weird:** `CreateAccessRequest` has `securablePermissions?: SecurablePermissions[]` (plural array, type `SecurablePermissions` itself plural). `SecurablePermissions` holds `securable: Securable` (singular) and `permissions: string[]` (plural). So `request.securablePermissions[0].securable` reads as "the singular securable inside the plural securable-permissions". The type name `SecurablePermissions` doesn't say "pairs of securable + permissions list". - **Category:** 9 (singular/plural mismatch), 1 (vague — what does `SecurablePermissions` model?). - **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). Field becomes `securablePermissionRequests?: SecurablePermissionRequest[]` — long but readable. - **Rationale:** The type-name pluralization is hiding what the type actually models (one securable + a permissions list). -### 16. `CreateAccessRequestResponse.requestDestinations` — `model.ts:114-119` +### 12. `CreateAccessRequestResponse.requestDestinations` — `model.ts:114-119` - **Why weird:** Field `requestDestinations` on a type called `CreateAccessRequestResponse`. The type already says it's a response *to a create request*; the field name re-states "request" and uses an unusual compound. The actual value is an array of `AccessRequestDestinations` (the routing configs the request will fire to). - **Category:** 20 (tautology), 1 (vague — what makes it `request`Destinations vs `accessRequest`Destinations?), 12 (duplicate concept — the type name is `AccessRequestDestinations` but the field name drops the `Access` prefix). - **Suggested name:** `destinations: AccessRequestDestinations[]` or `routing: AccessRequestDestinations[]`. - **Rationale:** Field name should match the type element being held. -### 17. `NotificationDestination.destinationId` — `model.ts:128-134` +### 13. `NotificationDestination.destinationId` — `model.ts:128-134` - **Why weird:** Type-suffix tautology — field `destinationId` on a type called `NotificationDestination`. Reads `notificationDestination.destinationId`. Also: the doc explains the value is *overloaded* — email address for EMAIL, URL for URL, Databricks notification ID for everything else. Three different shapes packed into one untyped string field. - **Category:** 20 (type-suffix tautology), 19 (underspecified ID — three different schemes hidden behind one name), 6 (misleading — "Id" implies opaque token, not e.g. an email). - **Suggested name:** Field as `id` (since the containing type already says `NotificationDestination`). Alternatively, model the overload as a discriminated union: `{ type: 'EMAIL'; email: string } | { type: 'URL'; url: string } | { type: 'SLACK'; notificationId: string } | ...`. - **Rationale:** A field named `Id` that sometimes holds an email and sometimes a URL is the canonical example of an underspecified identifier. -### 18. `NotificationDestination.destinationType` — `model.ts:135` +### 14. `NotificationDestination.destinationType` — `model.ts:135` - **Why weird:** Type-suffix tautology — field `destinationType` of type `DestinationType` on a type called `NotificationDestination`. Reads `notificationDestination.destinationType`. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `type` (the containing type already says `NotificationDestination`). Reads `notificationDestination.type`. -- **Rationale:** Wire stays `destination_type`; TS can drop the prefix the same way `Securable.type` does (model.ts:160) — note the inconsistency with the same project. +- **Rationale:** Wire stays `destination_type`; TS can drop the prefix the same way `Securable.type` does (model.ts:160) — note the inconsistency within the same project. -### 19. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` +### 15. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` - **Why weird:** A single `NotificationDestination` has both `destinationType?: DestinationType` and `specialDestination?: SpecialDestination`. The doc says `specialDestination`'s `destination_type` is "always EMAIL". So we have two enums that *cannot both be expressive at once* — if `specialDestination` is set, `destinationType` is constrained to `EMAIL`. The type system doesn't enforce this. - **Category:** 12 (duplicate concept — two enums encode overlapping info), 6 (misleading — looks like independent fields). -- **Suggested name:** Either (a) collapse: extend `DestinationType` with new members (`CATALOG_OWNER_EMAIL`, `EXTERNAL_LOCATION_OWNER_EMAIL`, ...) and drop `SpecialDestination`; or (b) model as a discriminated union: `{ kind: 'normal'; destinationType, destinationId } | { kind: 'special'; specialDestination }`. +- **Suggested name:** Either (a) collapse: extend `DestinationType` with new members and drop `SpecialDestination`; or (b) model as a discriminated union: `{ kind: 'normal'; destinationType, destinationId } | { kind: 'special'; specialDestination }`. - **Rationale:** Two parallel enums for a constrained relationship is exactly the kind of latent-bug field name pair that a strict type system can prevent. -### 20. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` +### 16. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` - **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape is fine, but the bare `id` doesn't communicate "the meaning depends on `principalType`". - **Category:** 19 (underspecified ID), 1 (vague). - **Suggested name:** Keep `id` paired with `principalType`, OR (more aggressive) make the type a discriminated union: `{ kind: 'user'; userId: string } | { kind: 'group'; groupId: string } | { kind: 'service'; servicePrincipalId: string }`. - **Rationale:** Tagged unions express the constraint at the type level. The current shape is a Go-port idiom. -### 21. `Securable.providerShare` — `model.ts:166-170` +### 17. `Securable.providerShare` — `model.ts:166-170` - **Why weird:** Field name `providerShare` on type `Securable`. Doc says it's "the name of the Share object that contains the securable when the securable is getting shared in D2D Delta Sharing". The name confuses two concepts: a `Share` securable type (already exists in `SecurableType.SHARE`) and a "provider" prefix that disambiguates Delta Sharing flows. - **Category:** 5 (cryptic abbreviation: `D2D` is in doc but never expanded), 1 (vague — what makes the share `provider`?). - **Suggested name:** `sharingProviderName` or `deltaShareName` with a clearer doc. - **Rationale:** `providerShare` reads as "the share of the provider" (genitive). The actual semantic is "the Delta Share that grants access to this securable when it's a shared object". The current name doesn't disambiguate. -### 22. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` +### 18. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` - **Why weird:** Enum value pinned by inline TODO: `/** TODO: [UC-2980] Staging tables aren't full-fleged securables yet. */`. The TODO leaks an internal JIRA ticket (`UC-2980`) and the typo "full-fleged" into the public SDK surface. The presence of the value tells callers it works; the comment tells them it doesn't. - **Category:** 18 (questionable enum value). - **Suggested name:** Either hide until promotion (`@experimental`), or remove the inline TODO and document the constraint in the doc-comment proper. - **Rationale:** Public SDK enums shouldn't carry internal JIRA references. Same pattern as `connections#29` and `dataclassification`. -### 23. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` +### 19. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` - **Why weird:** `EXTERNAL_METADATA` is undocumented. Neighbouring `STAGING_TABLE` carries a TODO/comment, but `EXTERNAL_METADATA` doesn't even say what it is. Unity Catalog has `externalmetadata` as its own package (`packages/externalmetadata/`), but this RFA enum member exists in isolation. - **Category:** 1 (vague; no doc disambiguating). - **Suggested name:** Keep name; add doc comment. - **Rationale:** Naming OK, but undocumented enum members in a 17-element enum mean readers must cross-reference to other packages. -### 24. `Principal` is exported but `principalType` field has no doc — `model.ts:148` +### 20. `Principal` is exported but `principalType` field has no doc — `model.ts:148` - **Why weird:** `principalType?: PrincipalType | undefined` has no JSDoc. Sibling `id` has a doc. The PrincipalType enum has only an `_UNSPECIFIED` sentinel + three values, none of which clarify when each applies. Caller has to guess by inspecting the IAM service. - **Category:** 1 (vague). - **Suggested name:** Keep name; add doc. - **Rationale:** Mechanical. -### 25. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` +### 21. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` - **Why weird:** `permissions` is `string[]` rather than an enum. Doc says "List of requested Unity Catalog permissions" — UC permissions are a known closed set (`SELECT`, `MODIFY`, `USAGE`, `READ_VOLUME`, etc.), so this should be a typed enum or branded string. Bare `string[]` loses any compile-time guard against typos. - **Category:** 16 (field type contradicts domain — should be enum or branded string). - **Suggested name:** Keep name; type as `UnityCatalogPermission[]` (new enum). Or document the closed set inline. -- **Rationale:** Same problem as #10. The wire is string, but TS could narrow it. +- **Rationale:** Same problem as #6. The wire is string, but TS could narrow it. -### 26. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` +### 22. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` - **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. - **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). - **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). - **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. -### 27. Three Client methods, three different domain entity names — `client.ts:74,113,147` +### 23. Three Client methods, three different domain entity names — `client.ts:74,113,147` - **Why weird:** `Client.batchCreateAccessRequests` works on `requests`. `Client.getAccessRequestDestinations` works on `destinations`. `Client.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. - **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). - **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). @@ -187,49 +163,49 @@ ## Low severity -### 28. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +### 24. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17. - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Same as `connections#40`. -### 29. `HttpCallOptions` — `utils.ts:15` +### 25. `HttpCallOptions` — `utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file imports `Options` from `@databricks/sdk-core/api` and `CallOptions` from `@databricks/sdk-options/call`. Three `Options` types in scope. `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Same as `connections#41`. -### 30. `readAll` — `utils.ts:40` +### 26. `readAll` — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `connections#38`. -### 31. `flattenQueryParams` — `utils.ts:123` +### 27. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default. - **Rationale:** Generator emits the same helper into every package even when unused. Same as `connections#37`. -### 32. `PACKAGE_SEGMENT` constant — `client.ts:35` +### 28. `PACKAGE_SEGMENT` constant — `client.ts:35` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `connections#36`. -### 33. `Client` class — `client.ts:40` +### 29. `Client` class — `client.ts:40` - **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). - **Category:** 1 (vague). - **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). - **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. -### 34. `buildHttpRequest` parameter list — `utils.ts:96-102` +### 30. `buildHttpRequest` parameter list — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. The function name `buildHttpRequest` doesn't communicate the parameter order; callers in `client.ts:87,122,166` pass them positionally. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Five-positional builders without object syntax are an anti-pattern in modern TS. -### 35. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` +### 31. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` - **Why weird:** The `Options` shape is built with a series of `...(options?.foo !== undefined && {foo: options.foo})` spreads. The pattern is a TS-idiom for conditional spread of optional fields. Naming-wise: the local `opts` variable is intentionally one letter shorter than `options` to disambiguate — but the shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions` (or the outer parameter to `callOptions`). @@ -237,23 +213,23 @@ ## Observations -### 36. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` +### 32. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` The index file exports the `Client`, all four enums, and all nine model interfaces (`AccessRequestDestinations`, `BatchCreateAccessRequestsRequest`, `BatchCreateAccessRequestsResponse`, `CreateAccessRequest`, `CreateAccessRequestResponse`, `GetAccessRequestDestinationsRequest`, `NotificationDestination`, `Principal`, `Securable`, `SecurablePermissions`, `UpdateAccessRequestDestinationsRequest`). It does *not* export the `marshal*`/`unmarshal*` schemas or the `accessRequestDestinationsFieldMask` helper. Consistent with the other packages but means the field-mask helper isn't available to consumers. - **Category:** Observation. -### 37. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +### 33. Comment-tag inconsistency — `client.ts:78,117,151` vs URL The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. - **Category:** Observation. -### 38. No tests in the package +### 34. No tests in the package `package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. The package ships untested. Not a naming issue, but cross-package noise — same as several other newly generated packages. - **Category:** Observation. -### 39. Action-verb conventions on `Client` -`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #27). +### 35. Action-verb conventions on `Client` +`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #23). - **Category:** Observation. -### 40. `package.json` description is empty string — `package.json:4` +### 36. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the cryptic `rfa` name (see #1), this leaves users with no metadata to identify the package's purpose when browsing npm. - **Category:** Observation. @@ -268,7 +244,7 @@ The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the pac - **`Principal`** — Unity Catalog/IAM term for "an entity that can hold permissions": a user, a group, or a service principal. The `PrincipalType` enum disambiguates which kind. Used here as the "on behalf of" actor in `CreateAccessRequest`. - **`SpecialDestination`** — five enum members denoting "the owner of the metastore/catalog/external-location/connection/credential" as an implicit email destination. These cannot be assigned; they're a default fallback. - **`FieldMask`** — Google protobuf convention (re-used in Databricks API) for sparse-field updates in PATCH semantics. `accessRequestDestinationsFieldMask(...)` builds the wire-format paths. -- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #9). +- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #5). ## File coverage - `src/v1/model.ts` (385 lines): read fully. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index a223c5a5..317c5a1f 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -15,14 +15,12 @@ enum, one nested-flag type, the schema info type, five request types, two response types). Because it is a 1:1 port of the Go SDK, most issues are inherited from upstream proto definitions: the most pervasive problems are (1) `fullNameArg` as a -cryptic path parameter that coexists with `fullName` on the same type, -(2) `CreateSchema`/`UpdateSchema` carrying read-only server-populated -fields, and (3) the `CatalogType` enum living on a schema-only type -even though every variant duplicates the `_CATALOG` suffix that the -enum name already provides. There is also significant duplicate-concept -overlap with the sibling `systemschemas` package (separate types -`SchemaInfo` vs `SystemSchemaInfo`, separate clients, separate methods) -that the audit calls out at the package boundary. +cryptic path parameter that coexists with `fullName` on the same type +and (2) `CreateSchemaRequest`/`UpdateSchemaRequest` carrying read-only +server-populated fields. There is also significant +duplicate-concept overlap with the sibling `systemschemas` package +(separate types `SchemaInfo` vs `SystemSchemaInfo`, separate clients, +separate methods) that the audit calls out at the package boundary. --- @@ -44,47 +42,20 @@ to discover what is in it. Better: `enabled`, `setting`, or typed handle but the value is human-readable text. Same problem for `inheritedFromName`: "the name of the object" — of *what* object? Without context (`catalog`, `schema`, `metastore`?) the field is -opaque. See also §6.1. +opaque. See also §5.1. -#### 1.3 `name` on `CreateSchema`, `SchemaInfo`, `UpdateSchema` (model.ts:17, 126, 184) +#### 1.3 `name` on `CreateSchemaRequest`, `SchemaInfo`, `UpdateSchemaRequest` (model.ts:17, 126, 184) `name` alone is generic in the context of UC where there's also `fullName`, `catalogName`, `newName`, and `metastoreId`. The doc qualifies it as "Name of schema, relative to parent catalog", but the identifier itself doesn't say that. Compare to `catalogName` on the -same shape which is unambiguous. See also §8.2 and §10.2. +same shape which is unambiguous. See also §7.2 and §9.2. --- -### 2. Redundant enum prefixes +### 2. Acronym casing inconsistencies -#### 2.1 `CatalogType.*_CATALOG` (model.ts:6-13) -All six variants end in `_CATALOG`: - -- `MANAGED_CATALOG` -- `DELTASHARING_CATALOG` -- `SYSTEM_CATALOG` -- `INTERNAL_CATALOG` -- `FOREIGN_CATALOG` -- `MANAGED_ONLINE_CATALOG` - -Read aloud: `CatalogType.MANAGED_CATALOG`. The `_CATALOG` suffix is -redundant — `MANAGED`, `DELTA_SHARING`, `SYSTEM`, `INTERNAL`, -`FOREIGN`, `MANAGED_ONLINE` carries the same meaning. (`DELTASHARING` -also runs two words together — see §3.1.) The enum is duplicated -verbatim from the `catalogs` package — even though *this* package is -about schemas, it imports the catalog-type enum and exposes it as -`SchemaInfo.catalogType`. See §10.4 for the duplication. - ---- - -### 3. Acronym casing inconsistencies - -#### 3.1 `DELTASHARING_CATALOG` enum variant (model.ts:8) -"Delta Sharing" is two words; the variant runs them together as -`DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` — or just -`DELTA_SHARING` after stripping the `_CATALOG` suffix (§2.1). - -#### 3.2 "UC" / "Unity Catalog" inconsistency in URLs and doc text +#### 2.1 "UC" / "Unity Catalog" inconsistency in URLs and doc text The endpoint path is `/api/2.1/unity-catalog/schemas` (client.ts:77, 106, etc.) and the package docs spell out "Unity Catalog" / "the Metastore" (client.ts:71). No identifier in the package uses `UC` — @@ -93,71 +64,70 @@ review. --- -### 4. Cryptic abbreviations +### 3. Cryptic abbreviations -#### 4.1 `fullNameArg` (model.ts:71, 90, 180) -Path-parameter field on `DeleteSchema`, `GetSchema`, and -`UpdateSchema`. The `Arg` suffix is Go-generator jargon distinguishing -path arguments from request-body fields with the same key. TypeScript -callers have no need for this distinction — the field *is* the schema -identifier and should just be `fullName` (or `name`). Even worse: -`UpdateSchema` has *both* `fullNameArg` (path) and `fullName` (body) -on the same type, with no obvious difference in semantics. See §14.1. +#### 3.1 `fullNameArg` (model.ts:71, 90, 180) +Path-parameter field on `DeleteSchemaRequest`, `GetSchemaRequest`, and +`UpdateSchemaRequest`. The `Arg` suffix is Go-generator jargon +distinguishing path arguments from request-body fields with the same +key. TypeScript callers have no need for this distinction — the field +*is* the schema identifier and should just be `fullName` (or `name`). +Even worse: `UpdateSchemaRequest` has *both* `fullNameArg` (path) and +`fullName` (body) on the same type, with no obvious difference in +semantics. See §11.1. -#### 4.2 `pkgJson` (client.ts:19) +#### 3.2 `pkgJson` (client.ts:19) Variable name `pkgJson` for `package.json` import. Mostly internal — minor — but worth noting for consistency. -#### 4.3 `req`, `resp`, `opts` (client.ts and utils.ts throughout) +#### 3.3 `req`, `resp`, `opts` (client.ts and utils.ts throughout) Internal abbreviations. Conventional, but worth flagging for the broader audit. --- -### 5. Misleading names +### 4. Misleading names -#### 5.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) +#### 4.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) Field is typed `string | undefined` but the doc comment ("Whether predictive optimization should be enabled…") implies a small discrete set of values (enable / disable / inherit). Either expose an enum or rename the field to make it clear it's a setting key. See also §1.1. -#### 5.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:139) +#### 4.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:140) The doc is honest: "Full name of schema, in form of __catalog_name__.__schema_name__". But the field name `fullName` suggests it might carry additional information not available from -`name`+`catalogName`. It doesn't. See also §10.2. +`name`+`catalogName`. It doesn't. See also §8.2. -#### 5.3 `SchemaInfo.options` vs `SchemaInfo.properties` (model.ts:161-164) +#### 4.3 `SchemaInfo.options` vs `SchemaInfo.properties` (model.ts:161-163) Both are `Record` with identical doc comments ("A map of key-value properties attached to the securable."). There is no way for a caller to know which to use for what. The doc duplication recurs -verbatim in `CreateSchema` (model.ts:51-54) and `UpdateSchema` -(model.ts:218-221). Either is underspecified or one of them is -misnamed. See §10.1. +verbatim in `CreateSchemaRequest` (model.ts:51-54) and +`UpdateSchemaRequest` (model.ts:218-221). Either is underspecified or +one of them is misnamed. See §8.1. --- -### 6. Overly verbose +### 5. Overly verbose -#### 6.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) +#### 5.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) 39 characters. Compounded by `effectivePredictiveOptimizationFlag` as a field name on three different request/response shapes (model.ts:44, 153, 211). Consider `EffectivePredictiveOptimization` (drop the `Flag` suffix — the type already wraps the flag) or -`EffectivePOSetting` if shortening is acceptable. See also §7.2. +`EffectivePOSetting` if shortening is acceptable. See also §6.2. -#### 6.2 `enablePredictiveOptimization: string` (model.ts:27, 136, 194) +#### 5.2 `enablePredictiveOptimization: string` (model.ts:27, 136, 194) Long field name for what is effectively a flag value. Acceptable, but -pairs with §6.1 to make every schema shape verbose. - -#### 6.3 `MANAGED_ONLINE_CATALOG` enum value (model.ts:12) — 22 characters; redundant `_CATALOG` per §2.1. +pairs with §5.1 to make every schema shape verbose. --- -### 7. Redundant suffixes +### 6. Redundant suffixes -#### 7.1 `SchemaInfo` type name (model.ts:124) +#### 6.1 `SchemaInfo` type name (model.ts:124) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from a resource handle; in TS the convention is to drop it (`Schema`). Compare with `Catalog`, `Table`, @@ -166,86 +136,80 @@ collides with the zod artifact `Schema` (a runtime validator type in common use across the JS ecosystem) — the rename must consider that collision before landing. -#### 7.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) -The whole type *is* the flag; the suffix is redundant. See §6.1. - -#### 7.3 `Arg` suffix on `fullNameArg` — see §4.1 and §14.1. - ---- - -### 8. Singular / plural mismatches +#### 6.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) +The whole type *is* the flag; the suffix is redundant. See §5.1. -_None._ +#### 6.3 `Arg` suffix on `fullNameArg` — see §3.1 and §11.1. --- -### 9. Reserved-word collisions +### 7. Reserved-word collisions -#### 9.1 `options` field on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:54, 163, 221) +#### 7.1 `options` field on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` (model.ts:54, 163, 221) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (`createSchema(req, options)`, client.ts:74, etc.). Not a compile error but creates cognitive load — inside `createSchema(req, options)` the reader sees both `req.options` (schema metadata) and `options` (call options). The cleanest fix is to -rename the client parameter to `callOptions`. See also §10.1 for the +rename the client parameter to `callOptions`. See also §8.1 for the duplicate-with-`properties` concern. -#### 9.2 `name` field is generic and shadows `Function.prototype.name` -Used on `CreateSchema`, `UpdateSchema`, `SchemaInfo` (model.ts:17, 184, -126). Not a reserved word, but commonly shadows the standard -`Function.prototype.name` and routinely confuses callers who spread -request objects. See also §1.3. +#### 7.2 `name` field is generic and shadows `Function.prototype.name` +Used on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` +(model.ts:17, 184, 126). Not a reserved word, but commonly shadows the +standard `Function.prototype.name` and routinely confuses callers who +spread request objects. See also §1.3. -#### 9.3 `value` field on `EffectivePredictiveOptimizationFlag.value` (model.ts:81) +#### 7.3 `value` field on `EffectivePredictiveOptimizationFlag.value` (model.ts:81) Generic field name, frequently shadows local variables. See §1.1. -#### 9.4 `properties` is not reserved but conflicts with `Object` semantics +#### 7.4 `properties` is not reserved but conflicts with `Object` semantics `SchemaInfo.properties` (model.ts:161) is fine but worth noting that `properties` is a heavily-overloaded term in JS (object properties, descriptor properties, etc.). Combined with the duplicate-with-`options` -problem in §10.1, the name is doubly overloaded. +problem in §8.1, the name is doubly overloaded. --- -### 10. Duplicate concepts +### 8. Duplicate concepts -#### 10.1 `properties` vs `options` (model.ts:51-54, 161-164, 218-221) +#### 8.1 `properties` vs `options` (model.ts:51-54, 161-163, 218-221) Both `Record` on every schema shape, with identical doc comments ("A map of key-value properties attached to the securable."). Either the documentation needs to differentiate them or -one is redundant. See also §5.3. +one is redundant. See also §4.3. -#### 10.2 `name` vs `fullName` on `SchemaInfo` (model.ts:126, 139) +#### 8.2 `name` vs `fullName` on `SchemaInfo` (model.ts:126, 140) `name` is the schema name "relative to parent catalog"; `fullName` is "in form of __catalog_name__.__schema_name__". These two fields are deterministically derivable from each other (given `catalogName`). -Mirror issue in `CreateSchema` (model.ts:17, 31) and `UpdateSchema` -(model.ts:184, 197). See also §5.2. +Mirror issue in `CreateSchemaRequest` (model.ts:17, 31) and +`UpdateSchemaRequest` (model.ts:184, 198). See also §4.2. -#### 10.3 `fullName` vs `fullNameArg` on `UpdateSchema` (model.ts:180, 197) -The `UpdateSchema` request has **both** `fullNameArg` (the existing +#### 8.3 `fullName` vs `fullNameArg` on `UpdateSchemaRequest` (model.ts:180, 198) +The `UpdateSchemaRequest` has **both** `fullNameArg` (the existing schema identifier, path param) and `fullName` (the same field name on the body) — plus `newName` for renaming. Three fields all touching -the schema's identity. See §14.1. +the schema's identity. See §11.1. -#### 10.4 `CatalogType` is re-implemented across packages -The exact `CatalogType` enum (with all six variants) is defined here +#### 8.4 `CatalogType` is re-implemented across packages +The exact `CatalogType` enum is defined here (model.ts:6-13) and also in `catalogs` (and likely in several other UC packages). A consumer touching both packages gets two unrelated TS types named `CatalogType`. Cross-package duplication — flagged in this audit for the broader review. -#### 10.5 `EffectivePredictiveOptimizationFlag` may be duplicated +#### 8.5 `EffectivePredictiveOptimizationFlag` may be duplicated This type is identical to the one in `catalogs` (and probably in any UC securable package). Cross-package duplication. -#### 10.6 `CreateSchema`, `UpdateSchema`, and `SchemaInfo` share ~21 fields verbatim +#### 8.6 `CreateSchemaRequest`, `UpdateSchemaRequest`, and `SchemaInfo` share ~21 fields verbatim All three types are 95% identical with identical doc strings. This is a generator artefact, but any rename of `storageRoot` must happen in -three places. Recommend basing `CreateSchema`/`UpdateSchema` on -`Partial` or a shared `SchemaProperties` mixin. +three places. Recommend basing `CreateSchemaRequest`/`UpdateSchemaRequest` +on `Partial` or a shared `SchemaProperties` mixin. -#### 10.7 Overlap with `systemschemas` package +#### 8.7 Overlap with `systemschemas` package The sibling `systemschemas` package operates on a completely different shape (`SystemSchemaInfo` has only `schema` and `state` — no overlap with `SchemaInfo`). Same noun, different types, different clients, @@ -259,52 +223,37 @@ will be surprised to find that system schemas live elsewhere. --- -### 11. Verb-tense inconsistency +### 9. Verb-tense inconsistency -#### 11.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. +#### 9.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. -#### 11.2 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. +#### 9.2 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. No verb-tense inconsistencies found across the package. --- -### 12. Go / Java-style names +### 10. Go / Java-style names -#### 12.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) -Java/Go style. TS convention is to drop it. See §7.1. +#### 10.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +Java/Go style. TS convention is to drop it. See §6.1. -#### 12.2 `Client` class name (client.ts:44) +#### 10.2 `Client` class name (client.ts:44) Bare `Client` (rather than `SchemasClient`) is a Go-idiom: package qualifies the type. JS consumers commonly import as `import {Client} from '@databricks/sdk-schemas/v1'` and have to alias. Package-wide convention; flagged for the broader review. -#### 12.3 `fullNameArg` — Go-generator naming. See §4.1. +#### 10.3 `fullNameArg` — Go-generator naming. See §3.1. -#### 12.4 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) +#### 10.4 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) Constant naming is fine; flagged for completeness. --- -### 13. Generic field names losing meaning +### 11. Field contradicting type domain -#### 13.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. - -#### 13.2 `name` on three different schema shapes — see §1.3. - -#### 13.3 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §5.3, §10.1. - -#### 13.4 `comment` (model.ts:23, 132, 190) -"User-provided free-form text description." `comment` is too informal -for a documented free-text description on a metadata API. -`description` would be more honest about its purpose. - ---- - -### 14. Field contradicting type domain - -#### 14.1 `UpdateSchema` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 197, 182) +#### 11.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 198, 182) Four name-bearing fields on a single update request: - `fullNameArg` — existing schema identifier (path param). @@ -318,22 +267,22 @@ identifying the existing schema; the others are vestigial in the update context.) This is the single most user-hostile naming pattern in the package — and it sits on the most-used mutation method. -#### 14.2 `CreateSchema` contains read-only output fields (model.ts:32-50) +#### 11.2 `CreateSchemaRequest` contains read-only output fields (model.ts:32-50) `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `catalogType`, `effectivePredictiveOptimizationFlag`, `schemaId`, `browseOnly`. These are server-populated; a creator setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Same mirror issue in -`UpdateSchema` (model.ts:199-217). +`UpdateSchemaRequest` (model.ts:199-217). -#### 14.3 `DeleteSchema.fullNameArg` — see §4.1. +#### 11.3 `DeleteSchemaRequest.fullNameArg` — see §3.1. -#### 14.4 `GetSchema.fullNameArg` (model.ts:90) -Same as 14.3. +#### 11.4 `GetSchemaRequest.fullNameArg` (model.ts:90) +Same as 11.3. --- -### 15. Inconsistent action verbs +### 12. Inconsistent action verbs Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`. Verbs are consistent — standard CRUD. @@ -341,65 +290,99 @@ No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- -### 16. Long enum values - -#### 16.1 `CatalogType.MANAGED_ONLINE_CATALOG` (model.ts:12) -22-character enum value. Should be `MANAGED_ONLINE` after dropping the -redundant `_CATALOG` suffix (§2.1). - -#### 16.2 `CatalogType.DELTASHARING_CATALOG` (model.ts:8) -20-character value; redundant suffix + run-together words. See §3.1. - -#### 16.3 Other `CatalogType` variants -`MANAGED_CATALOG` (15), `SYSTEM_CATALOG` (14), `INTERNAL_CATALOG` -(16), `FOREIGN_CATALOG` (15). All have redundant `_CATALOG` suffix. -See §2.1. - ---- - -### 17. Underspecified IDs +### 13. Underspecified IDs -#### 17.1 `metastoreId` (model.ts:29, 138, 196) +#### 13.1 `metastoreId` (model.ts:29, 138, 196) Documented as "unique identifier of parent metastore". Format opaque (UUID? slug?). Acceptable but unspecified. -#### 17.2 `schemaId` (model.ts:48, 157, 215) +#### 13.2 `schemaId` (model.ts:48, 157, 215) "The unique identifier of the schema." No format hint (UUID?). The field exists alongside `fullName` (which is also a unique identifier in a different sense). Two simultaneous IDs without disambiguation. -#### 17.3 `createdAt` / `updatedAt` (model.ts:33, 37, 142, 146, 200, 204) +#### 13.3 `createdAt` / `updatedAt` (model.ts:33, 37, 142, 146, 200, 204) Type is `number` (epoch milliseconds, per the doc). The unit is not encoded in the field name. `createdAtMs` / `updatedAtMs` would be more honest. (Compare to `lastFailoverTimeMs` in `catalogs`, which gets this right — see catalogs.md §19.7.) -#### 17.4 `createdBy` / `updatedBy` (model.ts:35, 39, 144, 148, 202, 206) +#### 13.4 `createdBy` / `updatedBy` (model.ts:35, 39, 144, 148, 202, 206) Type is `string` — "Username of schema creator" / "Username of user who last modified schema". Underspecified: is this a username, an email, a principal ID? `createdByUsername` would be clearer. -#### 17.5 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) +#### 13.5 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) Both `string`. `inheritedFromType` could be one of the UC securable types, but the field is not enum-typed. `inheritedFromName` is opaque text. See also §1.2. --- -### 18. Type-suffix tautology +### 14. Type-suffix tautology -#### 18.1 `CatalogType` enum with field `catalogType: CatalogType` +#### 14.1 `CatalogType` enum with field `catalogType: CatalogType` (model.ts:6, 41, 150, 208) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 18.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. +#### 14.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. -#### 18.3 `EffectivePredictiveOptimizationFlag` with field `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` +#### 14.3 `EffectivePredictiveOptimizationFlag` with field `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` (model.ts:44, 153, 211) — field repeats type name verbatim, 35 characters each. Severe tautology, but defensible because the field is the only instance of that type in each parent. Could be shortened to `predictiveOptimization: EffectivePredictiveOptimization` (drop -"Flag" per §7.2 and "effective" per §6.1). +"Flag" per §6.2 and "effective" per §5.1). + +--- + +### 15. Generic field names losing meaning + +#### 15.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. + +#### 15.2 `name` on three different schema shapes — see §1.3. + +#### 15.3 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §4.3, §8.1. + +#### 15.4 `comment` (model.ts:23, 132, 190) +"User-provided free-form text description." `comment` is too informal +for a documented free-text description on a metadata API. +`description` would be more honest about its purpose. + +--- + +### 16. Singular / plural mismatches + +_None._ + +--- + +### 17. Proto-architectural-leak naming + +#### 17.1 `EffectivePredictiveOptimizationFlag` — `Flag` wrapper suffix (model.ts:79) +- **Why:** The type is a proto-style wrapper around a tri-state value + (`value`, `inheritedFromType`, `inheritedFromName`). `Flag` is a + proto-wrapper marker that leaks the upstream message-modeling pattern + into the public TS surface — the type *is* the predictive-optimization + setting; `Flag` adds no semantic content. +- **Category:** `Wrapper`/`Adapter` suffix (proto wrapper pattern). +- **Suggested:** `EffectivePredictiveOptimization` (or, combined with + §5.1, `PredictiveOptimization`). +- **Rationale:** TS callers care about the value and its inheritance + source; the wrapper-ness is an implementation detail of the proto + schema, not part of the domain vocabulary. + +#### 17.2 `effectivePredictiveOptimizationFlag` field — `Flag` wrapper infix (model.ts:44, 153, 211) +- **Why:** Same proto-wrapper leak repeated as a field name on three + shapes (`CreateSchemaRequest`, `SchemaInfo`, `UpdateSchemaRequest`). + 35-character field name whose `Flag` segment exists only to mirror + the wrapper type. +- **Category:** `Wrapper`/`Adapter` infix (proto wrapper pattern). +- **Suggested:** `effectivePredictiveOptimization` (or + `predictiveOptimization`). +- **Rationale:** Field name should describe the domain concept + (predictive-optimization setting), not the proto modelling choice + (wrapping the setting in a `*Flag` message). --- @@ -408,12 +391,12 @@ to `predictiveOptimization: EffectivePredictiveOptimization` (drop ### A. `flattenQueryParams` is defined but unused (utils.ts:123) Each `listSchemas` / `getSchema` / `deleteSchema` handler builds query strings inline with `URLSearchParams.append` (client.ts:107-110, -138-141, 179-191). The exported helper `flattenQueryParams` is never +144-147, 185-197). The exported helper `flattenQueryParams` is never referenced by `client.ts`. Either it's intentionally exported for consumer use (then it should be documented and reside in `utils` proper) or it's dead code. Same pattern as `catalogs` package. -### B. `fullNameArg` URL substitution silently allows empty string (client.ts:106, 137, 239) +### B. `fullNameArg` URL substitution silently allows empty string (client.ts:106, 143, 248) `${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL silently becomes `/api/2.1/unity-catalog/schemas/` and the request will fail on the server. The naming (`fullNameArg`) and the @@ -444,10 +427,10 @@ occurrences. Consistency: every other field has a doc comment. ### G. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) The field name says "enable" — suggesting boolean — but the type is `string`. The actual value is presumably `'ENABLE' | 'DISABLE' | -'INHERIT'` or similar. The name lies about the type. See also §5.1 +'INHERIT'` or similar. The name lies about the type. See also §4.1 for the related `EffectivePredictiveOptimizationFlag.value`. -### H. Overlap with `systemschemas` package — see §10.7 +### H. Overlap with `systemschemas` package — see §8.7 A consumer reading "schemas" reasonably expects to find all schema operations here. They will not find `disableSystemSchema`, `enableSystemSchema`, or `listSystemSchemas` — those live in @@ -460,63 +443,62 @@ upstream API surface, but the seam is non-obvious to discover. | Identifier | Location | Finding | | ----------------------------------------------------------- | --------------------- | -------------------- | -| `CatalogType` | model.ts:6 | 2.1, 10.4, 16.x, 18.1| -| `CatalogType.MANAGED_CATALOG` | model.ts:7 | 2.1, 16.3 | -| `CatalogType.DELTASHARING_CATALOG` | model.ts:8 | 2.1, 3.1, 16.2 | -| `CatalogType.SYSTEM_CATALOG` | model.ts:9 | 2.1, 16.3 | -| `CatalogType.INTERNAL_CATALOG` | model.ts:10 | 2.1, 16.3 | -| `CatalogType.FOREIGN_CATALOG` | model.ts:11 | 2.1, 16.3 | -| `CatalogType.MANAGED_ONLINE_CATALOG` | model.ts:12 | 2.1, 16.1 | -| `CreateSchema` | model.ts:15 | 10.6, 14.2 | -| `CreateSchema.name` | model.ts:17 | 1.3, 9.2 | -| `CreateSchema.catalogType` | model.ts:41 | 18.1 | -| `CreateSchema.effectivePredictiveOptimizationFlag` | model.ts:44 | 6.1, 18.3, F | -| `CreateSchema.properties` / `.options` | model.ts:52, 54 | 5.3, 9.1, 10.1, 13.3 | -| `DeleteSchema` | model.ts:69 | 14.3 | -| `DeleteSchema.fullNameArg` | model.ts:71 | 4.1, 12.3, 14.3, B | -| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 6.1, 7.2, 12.1, 18.3 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 5.1, 9.3, 13.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.2, 17.5 | -| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.2, 17.5 | -| `GetSchema.fullNameArg` | model.ts:90 | 4.1, 12.3, 14.4, B | -| `ListSchemas` | model.ts:95 | — | -| `ListSchemas.maxResults` | model.ts:105 | — | -| `ListSchemas.pageToken` | model.ts:107 | — | -| `ListSchemas.includeBrowse` | model.ts:109 | — | -| `SchemaInfo` | model.ts:124 | 7.1, 10.6, 12.1, E | -| `SchemaInfo.name` | model.ts:126 | 1.3, 9.2 | -| `SchemaInfo.fullName` | model.ts:139 | 5.2, 10.2 | -| `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 17.3 | -| `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 17.4 | -| `SchemaInfo.catalogType` | model.ts:150 | 18.1 | -| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 6.1, 18.3, F | -| `SchemaInfo.schemaId` | model.ts:157 | 17.2 | -| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 5.3, 9.1, 10.1, 13.3 | -| `UpdateSchema` | model.ts:178 | 10.3, 10.6, 14.1, 14.2 | -| `UpdateSchema.fullNameArg` | model.ts:180 | 4.1, 10.3, 12.3, 14.1, B | -| `UpdateSchema.newName` | model.ts:182 | 14.1 | -| `UpdateSchema.name` | model.ts:184 | 1.3, 9.2, 14.1 | -| `UpdateSchema.fullName` | model.ts:197 | 10.2, 10.3, 14.1 | -| `UpdateSchema.effectivePredictiveOptimizationFlag` | model.ts:211 | 6.1, 18.3, F | +| `CatalogType` | model.ts:6 | 8.4, 14.1 | +| `CreateSchemaRequest` | model.ts:15 | 8.6, 11.2 | +| `CreateSchemaRequest.name` | model.ts:17 | 1.3, 7.2 | +| `CreateSchemaRequest.catalogType` | model.ts:41 | 14.1 | +| `CreateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:44 | 5.1, 14.3, 17.2, F | +| `CreateSchemaRequest.properties` / `.options` | model.ts:52, 54 | 4.3, 7.1, 8.1, 15.3 | +| `DeleteSchemaRequest` | model.ts:69 | 11.3 | +| `DeleteSchemaRequest.fullNameArg` | model.ts:71 | 3.1, 10.3, 11.3, B | +| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 5.1, 6.2, 10.1, 14.3, 17.1 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 4.1, 7.3, 15.1 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.2, 13.5 | +| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.2, 13.5 | +| `GetSchemaRequest.fullNameArg` | model.ts:90 | 3.1, 10.3, 11.4, B | +| `ListSchemasRequest` | model.ts:95 | — | +| `ListSchemasRequest.maxResults` | model.ts:105 | — | +| `ListSchemasRequest.pageToken` | model.ts:107 | — | +| `ListSchemasRequest.includeBrowse` | model.ts:109 | — | +| `SchemaInfo` | model.ts:124 | 6.1, 8.6, 10.1, E | +| `SchemaInfo.name` | model.ts:126 | 1.3, 7.2 | +| `SchemaInfo.fullName` | model.ts:140 | 4.2, 8.2 | +| `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 13.3 | +| `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 13.4 | +| `SchemaInfo.catalogType` | model.ts:150 | 14.1 | +| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 5.1, 14.3, 17.2, F | +| `SchemaInfo.schemaId` | model.ts:157 | 13.2 | +| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 4.3, 7.1, 8.1, 15.3 | +| `UpdateSchemaRequest` | model.ts:178 | 8.3, 8.6, 11.1, 11.2 | +| `UpdateSchemaRequest.fullNameArg` | model.ts:180 | 3.1, 8.3, 10.3, 11.1, B | +| `UpdateSchemaRequest.newName` | model.ts:182 | 11.1 | +| `UpdateSchemaRequest.name` | model.ts:184 | 1.3, 7.2, 11.1 | +| `UpdateSchemaRequest.fullName` | model.ts:198 | 8.2, 8.3, 11.1 | +| `UpdateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:211 | 5.1, 14.3, 17.2, F | | `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | G | -| `comment` field | model.ts:23, 132, 190 | 13.4 | -| `Client` (bare name) | client.ts:44 | 12.2 | -| `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 137, 239 | B | +| `comment` field | model.ts:23, 132, 190 | 15.4 | +| `Client` (bare name) | client.ts:44 | 10.2 | +| `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 143, 248 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | -| Cross-package overlap with `systemschemas` | (package boundary) | 10.7, H | +| Cross-package overlap with `systemschemas` | (package boundary) | 8.7, H | --- ## Recommended priority order -1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchema`** — four name-like fields on the same request, the worst user-facing trap in the package. (§14.1, §4.1, §10.3) -2. **Strip the redundant `_CATALOG` suffix from every `CatalogType` variant.** (§2.1, §16.x) -3. **Distinguish or merge `options` and `properties`.** (§10.1, §5.3) -4. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§5.1, G) -5. **Strip read-only fields from `CreateSchema`/`UpdateSchema`.** (§14.2) -6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) -7. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§17.3) -8. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§17.2, §10.2) -9. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§7.1) -10. **Strip the `Next ID: 45` leftover from `SchemaInfo` JSDoc.** (E) -11. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§10.7, H) +1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchemaRequest`** — four name-like fields on the same request, the worst user-facing trap in the package. (§11.1, §3.1, §8.3) +2. **Distinguish or merge `options` and `properties`.** (§8.1, §4.3) +3. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§4.1, G) +4. **Strip read-only fields from `CreateSchemaRequest`/`UpdateSchemaRequest`.** (§11.2) +5. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +6. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§13.3) +7. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§13.2, §8.2) +8. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§6.1) +9. **Strip the `Next ID: 45` leftover from `SchemaInfo` JSDoc.** (E) +10. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§8.7, H) + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/scim.md b/.agent/naming-audit/scim.md new file mode 100644 index 00000000..c7d54b87 --- /dev/null +++ b/.agent/naming-audit/scim.md @@ -0,0 +1,111 @@ +# Naming Audit: scim + +**Path:** `packages/scim/src/v1/` +**Versions audited:** v1 +**Inferred domain:** SCIM (System for Cross-domain Identity Management, RFC 7644) — workspace and account user, service principal, and group provisioning, plus password permissions. `SCIM` itself is an industry-standard protocol acronym and is treated as a domain word. +**Total weird names flagged:** 13 + +## Summary +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 4 | +| Low | 2 | +| Observation | 2 | + +## High severity + +### 1. Proto-style nested enum names with `_` separators — `src/v1/model.ts:58,65,73,81,87,95` +- **Why weird:** Six exported enums use the proto-nested form `_`: `AccountGetSortOrder_GetSortOrder`, `AccountListSort_Order`, `AccountPatchOp_PatchOp`, `AccountPatchSchema_PatchSchema`, `ListSort_Order`, and `PasswordPermission_Level`. Each is suppressed by an inline `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.`, which is itself an acknowledgement that the names violate normal TS convention. The reason is purely protoc plumbing: the enum was nested inside a parent proto message to avoid value-name collisions with a sibling enum. That nesting is invisible to the SDK consumer — `AccountGetSortOrder_GetSortOrder` and `GetSortOrder` (line 17) hold the same three values (`UNSPECIFIED`, `ASCENDING`, `DESCENDING`). +- **Category:** Proto-architecture leak +- **Suggested name:** Collapse to a single `SortOrder` enum (shared across get/list and account/workspace variants); rename `PasswordPermission_Level` to `PasswordPermissionLevel`. The whole `_` shape is a proto artifact that should not survive code generation. +- **Rationale:** TypeScript has structural typing and module-scoped names; there is no value collision to resolve. The disable comment is a clue that the generator is fighting the language. + +### 2. Empty placeholder interfaces for proto-nesting parents — `src/v1/model.ts:109,132,151,154,404,412,619` +- **Why weird:** Seven `export interface`s are wholly empty (`{}`), each suppressed by `// eslint-disable-next-line @typescript-eslint/no-empty-object-type`: `AccountGetSortOrder`, `AccountListSort`, `AccountPatchOp`, `AccountPatchSchema`, `GetPasswordPermissionLevelsRequest`, `GetPasswordPermissionsRequest`, and `ListSort`. The first four and `ListSort` exist only because the enum was nested inside a proto message — the message itself has no fields, so the TypeScript type carries no information. The two `Get…Request` empties are RPC-shape placeholders for an HTTP GET that takes no body and no path params; they survive as exports despite carrying zero schema. A leading JSDoc on `AccountListSort` and `ListSort` explicitly says "ListSortOrder and GetSortOrder share enum values, which is not supported. We use nesting as a workaround." — i.e. the comment names the proto restriction it works around. +- **Category:** Proto-architecture leak +- **Suggested name:** Delete all seven exports. The empty-body `Get…PermissionLevelsRequest` / `Get…PermissionsRequest` methods should take no argument (or take `CallOptions` only). The five enum-parent interfaces should disappear once the enums are flattened (see finding 1). +- **Rationale:** Public empty interfaces are pure proto/RPC plumbing; they expose generator structure as API surface and force consumers to either pass `{}` or define a variable they cannot meaningfully populate. + +### 3. `Account*` mid-position duplicate type families — `src/v1/model.ts:100,111,134,141,156,161,177,205,220,236,317,325,333,359,367,375,460,479,491,510,522,541,722,732,742,800,815,831` +- **Why weird:** The package exports two parallel families of identical-shape types distinguished only by an `Account` prefix: `ComplexValue` vs `AccountComplexValue`, `Name` vs `AccountName`, `ResourceMeta` vs `AccountResourceMeta`, `Patch` vs `AccountPatch`, `Group` vs `AccountGroup`, `User` vs `AccountUser`, `ServicePrincipal` vs `AccountServicePrincipal`, and the corresponding `Create/Update/Patch/Delete/Get/List…Request`/`…Response` quartets. The shapes are almost identical (compare `User` lines 911-932 to `AccountUser` lines 177-195 — same fields, plus `accountId`); the divergence is one extra optional `accountId` and the absence of a few workspace-only entitlements. The `Account` prefix is mid-position in the larger compound names (`CreateAccountUserRequest`, `PatchAccountGroupRequest`, `ListAccountServicePrincipalsResponse`) — a classic proto package-namespace leak where the same message was redefined under `databricks.scim.account.v1` and `databricks.scim.workspace.v1`. +- **Category:** Proto-architecture leak +- **Suggested name:** Either (a) unify into one type with an optional `accountId` field and one method surface that switches on whether `accountId` is present, or (b) split into two sub-namespaces (`scim.account.User`, `scim.workspace.User`) so the prefix is not embedded in the name. The current shape doubles the type-export count without doubling the information. +- **Rationale:** This is the package's single biggest source of surface bloat — ~30 duplicated types — and reads as "the proto compiler emitted two packages and we re-exported both". + +### 4. `Schema` field as proto-discriminator array — `src/v1/model.ts:271,290,311,456,576,589,645,757,773` and enums on lines 23,28,46,51 +- **Why weird:** Every `Group`, `User`, `ServicePrincipal`, list-response, and patch-request type carries a `schemas?: <…>Schema[]` field whose contents are URN strings like `URN_IETF_PARAMS_SCIM_SCHEMAS_CORE_2_0_GROUP`. The schemas are part of the SCIM spec on the wire, but their *enum* representation in TS is awkward: the values are SHOUTY_SNAKE constants embedding the entire URN, and there are separate `GroupSchema`, `ListResponseSchema`, `PatchSchema`, `ServicePrincipalSchema`, `UserSchema` enums each with one or two values plus an `_UNSPECIFIED` zero. This is the proto convention of "every enum needs an UNSPECIFIED variant for backwards-compat" applied to a constant set that is fully determined by RFC 7644 and never grows. Note: `SCIM` itself is a domain word, but the per-type `Schema` enum-wrapper is a generator artifact. +- **Category:** Proto-architecture leak +- **Suggested name:** Drop the per-type `Schema` enums; type the field as a const string union (`type GroupSchema = "urn:ietf:params:scim:schemas:core:2.0:Group"`) or hide it entirely behind the marshaller (the client knows which URNs to send). The `_UNSPECIFIED` zero values should disappear. +- **Rationale:** The enum wraps a single literal URN per type — a `const` is simpler and matches what the spec actually says. The `_UNSPECIFIED` zero is a proto3 default-value artifact with no SCIM meaning. + +### 5. `Resources` PascalCase wire field surfaces in unmarshaller — `src/v1/model.ts:1096,1111,1128,1143,1160,1178` +- **Why weird:** Every list-response unmarshaller declares the wire field as `Resources` (capital R), e.g. `Resources: z.array(...)`, then transforms to `resources` (camelCase) in the output. The capital-`R` form is the proto-generated JSON name for a field whose proto name was `resources` and whose `json_name` annotation was set to `Resources`. It then leaks into the Zod schema as the literal wire key. While not a public-facing type name, it documents a proto-convention divergence (proto `lower_snake` → JSON `Resources`) baked into the generator that has no SCIM-spec justification. +- **Category:** Proto-architecture leak +- **Suggested name:** The wire field name is fixed by SCIM (which uses `Resources` with capital R, per RFC 7644 §3.4.2); this one is technically correct. Flag for verification rather than rename: ensure the JSDoc on `*Response.resources` says "SCIM lists this as `Resources` on the wire (RFC 7644 §3.4.2)" so the casing is not assumed to be a bug. +- **Rationale:** Distinguishes spec-mandated quirk from proto artifact; the visual similarity to a generator leak warrants a comment. + +## Medium severity + +### 6. `Operations` PascalCase wire key in marshal output — `src/v1/model.ts:1576,1591,1604,1617,1629,1641` +- **Why weird:** Every patch-request marshaller transforms `operations` (camelCase TS) to `Operations` (PascalCase wire). Same shape as finding 5, but on the outbound side. Per RFC 7644 §3.5.2, the SCIM patch wire field is `Operations` (capital O), so this is spec-mandated. Flag for the same reason: it looks like a proto-RPC leak but is actually SCIM. +- **Category:** Proto-architecture leak +- **Suggested name:** No rename. Add a comment in the marshallers explaining the capital `Operations` is from RFC 7644 §3.5.2. +- **Rationale:** Audit-trail clarity. Without the comment, a reader cleaning up "obvious" proto leftovers might lowercase this and break the wire. + +### 7. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:583` +- **Why weird:** The list-response type is `ListServicePrincipalResponse` (singular `ServicePrincipal`) while the request type is `ListServicePrincipalsRequest` (plural). Compare to `ListAccountServicePrincipalsResponse` (plural) on line 510. The singular form on a list response reads as a proto message-name copy where the inner message is `ServicePrincipal` and the outer wraps it — i.e., proto's habit of letting the inner singular name dominate. +- **Category:** Proto-architecture leak +- **Suggested name:** `ListServicePrincipalsResponse`. +- **Rationale:** Symmetry with sibling types and with the request name; the current singular is a generator artifact. + +### 8. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:34,143,715` +- **Why weird:** `PatchOp` is the enum of patch operation kinds (`ADD`/`REMOVE`/`REPLACE`); `Patch.op` is the field that holds one. The TS field is `op` of type `PatchOp` (or `AccountPatchOp_PatchOp` for the account variant), so the enum has `Op` baked into its own name *and* the field is `op` — `Patch.op: PatchOp` is a type-suffix tautology and `AccountPatchOp_PatchOp` is the worst-case version of finding 1. +- **Category:** Proto-architecture leak +- **Suggested name:** Rename the enum to `PatchOperation` (or just inline as a string literal union `"ADD" | "REMOVE" | "REPLACE"`); keep the field `op`. +- **Rationale:** `Op` is a proto shorthand for "operation"; the TS type name should spell it out, and the `_PatchOp` re-suffix should vanish. + +### 9. Sentinel `*_UNSPECIFIED` enum values — `src/v1/model.ts:18,24,29,35,42,47,52,59,66,74,82,88,96` +- **Why weird:** Every enum carries an `_UNSPECIFIED` zero value: `GET_SORT_ORDER_UNSPECIFIED`, `GROUP_SCHEMA_UNSPECIFIED`, `LIST_RESPONSE_SCHEMA_UNSPECIFIED`, `PATCH_OP_UNSPECIFIED`, `PATCH_SCHEMA_UNSPECIFIED`, `SERVICE_PRINCIPAL_SCHEMA_UNSPECIFIED`, `USER_SCHEMA_UNSPECIFIED`, `ORDER_UNSPECIFIED`, `LEVEL_UNSPECIFIED`, and copies under each `Account*` variant. The `*_UNSPECIFIED` zero is a proto3 default-value convention with no semantic meaning in TS, where an enum field can simply be optional. +- **Category:** Proto-architecture leak +- **Suggested name:** Drop the `_UNSPECIFIED` variants. Express absence as `undefined` (the fields are already optional). +- **Rationale:** TS has `undefined`; proto3 does not. The sentinel is dead weight. + +## Low severity + +### 10. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:652` +- **Why weird:** Not a proto leak per se, but the `Me` segment in `MeRequest` is a proto-style shorthand: SCIM defines `GET /Users/me` as the "current user" endpoint, and the proto generator turned `Me` into a type prefix instead of using a verb. `MeRequest` reads as "a Me-shaped request" — the request *to* the `me` endpoint would be `GetCurrentUserRequest` or `GetMeRequest`. +- **Category:** Proto-architecture leak +- **Suggested name:** `GetCurrentUserRequest` (and rename `client.me()` to `getCurrentUser()`); or `GetMeRequest` if the URL slug is preserved. +- **Rationale:** Pronouns are not normally type prefixes in TS; this is the proto RPC name leaking through. + +### 11. `unmarshal*Schema` / `marshal*Schema` exported helpers — `src/v1/model.ts:934-1791` +- **Why weird:** Each (un)marshaller is exported as `unmarshalSchema` / `marshalSchema`. The `Schema` suffix here refers to the *Zod schema* used to parse, but in a SCIM package the word `Schema` already means a SCIM resource schema URN (see findings 4 and the `GroupSchema`/`UserSchema` enums). Two unrelated meanings of `Schema` in the same module are easy to confuse on read. +- **Category:** Proto-architecture leak +- **Suggested name:** Either drop the `Schema` suffix (e.g. `unmarshalUser`/`marshalUser`) or rename to `unmarshalUserCodec`/`marshalUserCodec`. The conflict is a generator-template choice that ignored the domain vocabulary. +- **Rationale:** Disambiguate the two `Schema` namespaces in one file. + +## Observations + +### O1. `eslint-disable` density as a signal — `src/v1/model.ts:57,64,72,80,86,94,108,131,150,153,403,411,618` +- The file carries 13 inline `eslint-disable-next-line` comments, all for `@typescript-eslint/naming-convention` (proto-nested enum names) or `@typescript-eslint/no-empty-object-type` (empty proto messages). Every disable corresponds to a proto-architecture artifact — taken together, they form a precise list of the proto-shaped pieces the linter wanted to flag and the generator decided to suppress. Removing the underlying patterns (findings 1, 2, 8) would also remove every disable in this file. + +### O2. Workspace and account API split at type level, not namespace — package vs siblings +- Sibling packages `accountusers`, `accountgroups`, etc. exist for account-scope IAM at higher levels of the SDK; this package interleaves both scopes (`createUser` vs `createAccountUser`, `listGroups` vs `listAccountGroups`) on a single `Client`. The naming convention is mid-position `Account` (finding 3), which is a proto-package-name leak. A consumer who only wants workspace SCIM still sees every account method in IDE autocomplete. + +## Domain glossary +- `SCIM` — System for Cross-domain Identity Management; RFC 7643/7644. Industry-standard, treated as domain word. +- `ServicePrincipal` — Machine identity (UUID + display name) that can authenticate independently of any user. +- `entitlements` — Account/workspace-level capability flags assigned to a user, group, or SP (e.g. `allow-cluster-create`). +- `Patch` — JSON Patch-style partial update body per RFC 7644 §3.5.2. +- `Resources` — Wire-level list payload key in SCIM list responses (capital R per spec). +- `Operations` — Wire-level list of patch ops in SCIM patch requests (capital O per spec). +- `Schema` (URN) — SCIM resource type discriminator, e.g. `urn:ietf:params:scim:schemas:core:2.0:User`. +- `me` — SCIM convention for "the authenticated identity"; `GET /Users/me` returns the calling user. + +## File coverage +- `src/v1/model.ts` (1791 lines): read fully. +- `src/v1/client.ts` (1417 lines): read for method-name patterns and class shape. +- `src/v1/transport.ts` (75 lines): read fully. +- `src/v1/utils.ts` (150 lines): read for helper-name patterns. +- `src/v1/index.ts` (93 lines): read fully. diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index 381b127e..b62e0288 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -19,11 +19,11 @@ Notation: file paths are relative to the package root. Findings reference | Severity | Count | | ----------- | ----- | -| High | 5 | -| Medium | 14 | +| High | 4 | +| Medium | 12 | | Low | 9 | | Observation | 5 | -| **Total** | **33** | +| **Total** | **30** | Headline themes: @@ -34,17 +34,11 @@ Headline themes: and `serviceprincipalsecretsproxy` (workspace-level proxy for the same). All four export a class literally named `Client` and types with the noun `Secret`. Cross-package usage is opaque without aliasing. -2. **Action-verb request types collide with same-named client methods.** - `interface CreateScope` describes the request body; `client.createScope` - performs the action. The reader has to mentally distinguish the noun-from- - verb each time. Six pairs in this file (`CreateScope`, `DeleteAcl`, - `DeleteScope`, `DeleteSecret`, `GetAcl`, `GetSecret`, `ListAcls`, - `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret`). -3. **Inconsistent action verb across mutating operations.** `Put` for +2. **Inconsistent action verb across mutating operations.** `Put` for creating/updating ACLs and secrets, `Create` for scopes, `Delete` for all three. There is no `Update`. Go's REST SDK adopts the same shape, but `Put` reads as Go/HTTP-method jargon rather than a TS-side action verb. -4. **`scope: string | undefined` everywhere — but required in practice.** +3. **`scope: string | undefined` everywhere — but required in practice.** Eleven of twelve operation request types have `scope?: string | undefined` as their primary identifier. Every server endpoint will reject an absent scope. The "optional" marker is a generator artifact (all proto fields @@ -98,38 +92,18 @@ Headline themes: class name (`SecretsClient`) aligns it with the rest of the package's exports and also eliminates the cross-package alias dance flagged in H1. -### H3. Six request types are verb phrases (action collision with client methods) - -- **Files / lines:** `src/v1/model.ts:51` (`CreateScope`), `:65` (`DeleteAcl`), - `:75` (`DeleteScope`), `:83` (`DeleteSecret`), `:93` (`GetAcl`), `:100` - (`GetSecret`), `:115` (`ListAcls`), `:127` (`ListScopes`), `:135` - (`ListSecrets`), `:146` (`PutAcl`), `:158` (`PutSecret`). -- **Category:** #14 Go/Java-style name (action used as data type). -- **Current example:** `client.createScope(req: CreateScope)`. -- **Suggestion:** `CreateScopeRequest`, `DeleteAclRequest`, - `DeleteScopeRequest`, `DeleteSecretRequest`, `GetAclRequest`, - `GetSecretRequest`, `ListAclsRequest`, `ListScopesRequest`, - `ListSecretsRequest`, `PutAclRequest`, `PutSecretRequest`. (See sibling - package `secretsuc` which already uses the `…Request` suffix — - `CreateSecretRequest`, `DeleteSecretRequest`, etc.) -- **Rationale:** Reading `client.createScope(req: CreateScope)` requires - the reader to distinguish noun-from-verb each time. `secretsuc/model.ts` - is the live counter-example for the correct convention within this very - repo: `CreateSecretRequest`, `GetSecretRequest`, `ListSecretsRequest`, - etc. Two sibling packages, two conventions. Pick one. - -### H4. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` - -- **Files / lines:** `src/v1/client.ts:584` (`putAcl`), `:638` (`putSecret`); - contrast `:137` (`createScope`), `:262` (`deleteSecret`), `:220` - (`deleteScope`), `:180` (`deleteAcl`). +### H3. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` + +- **Files / lines:** `src/v1/client.ts:596` (`putAcl`), `:653` (`putSecret`); + contrast `:137` (`createScope`), `:268` (`deleteSecret`), `:223` + (`deleteScope`), `:183` (`deleteAcl`). - **Category:** #17 inconsistent action verbs. - **Current:** `Put` for ACLs and secrets, `Create` for scopes, `Delete` for all three. No `Update`. - **Issue:** A consumer who learned `createScope` will not guess that the way to create or update a secret is `putSecret`, not `createSecret` or - `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:607) and - "Creates or overwrites the ACL" (client.ts:551) — three different verbs + `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:622) and + "Creates or overwrites the ACL" (client.ts:563) — three different verbs for the same upsert semantic. - **Suggestion:** unify on one verb pair: either (a) `Create*` for new + `Update*` for existing, or @@ -139,16 +113,16 @@ Headline themes: `/secrets/put` — so the wire format is *also* inconsistent and the generator is faithfully reproducing it. -### H5. Scope name field `scope` is severely overloaded across types +### H4. Scope name field `scope` is severely overloaded across types -- **Files / lines:** `src/v1/model.ts:53` (`CreateScope.scope`), `:67` - (`DeleteAcl.scope`), `:77` (`DeleteScope.scope`), `:85` - (`DeleteSecret.scope`), `:95` (`GetAcl.scope`), `:102` (`GetSecret.scope`), - `:117` (`ListAcls.scope`), `:137` (`ListSecrets.scope`), `:148` - (`PutAcl.scope`), `:160` (`PutSecret.scope`). Then `SecretScope.name` - (`:198`) names the same value, and the *type* `SecretScope` describes - what `scope` actually contains. Then `ScopeBackendType` describes the - scope's backend. +- **Files / lines:** `src/v1/model.ts:53` (`CreateScopeRequest.scope`), `:67` + (`DeleteAclRequest.scope`), `:77` (`DeleteScopeRequest.scope`), `:85` + (`DeleteSecretRequest.scope`), `:95` (`GetAclRequest.scope`), `:102` + (`GetSecretRequest.scope`), `:117` (`ListAclsRequest.scope`), `:137` + (`ListSecretsRequest.scope`), `:148` (`PutAclRequest.scope`), `:160` + (`PutSecretRequest.scope`). Then `SecretScope.name` (`:198`) names the + same value, and the *type* `SecretScope` describes what `scope` actually + contains. Then `ScopeBackendType` describes the scope's backend. - **Category:** #1 vague/generic, #15 generic field names losing meaning, #6 misleading names. - **Issue:** `scope` is the *string name* of a `SecretScope`. The naming @@ -169,35 +143,7 @@ Headline themes: ## Medium Severity -### M1. `AclPermission` enum values are bare verbs - -- **File / line:** `src/v1/model.ts:6-13`. -- **Category:** #2 redundant enum prefixes (inverse: no prefix at all). -- **Current:** `READ = 'READ'`, `WRITE = 'WRITE'`, `MANAGE = 'MANAGE'`. -- **Suggestion:** as-is is acceptable since the enum name (`AclPermission`) - contributes the noun; `AclPermission.READ` reads as - "ACL-permission-read". Flagging only because three other places in - `model.ts` (the JSDoc) refer to the values as `"READ"`, `"WRITE"`, - `"MANAGE"` — string-literal style. The TS enum auto-stringifies, so - the wire-level value matches. Acceptable as-is. - -### M2. `ScopeBackendType` enum values stutter `_KEYVAULT` - -- **File / line:** `src/v1/model.ts:19-30`. -- **Category:** #2 redundant enum prefixes, #18 long enum values. -- **Current:** `DATABRICKS = 'DATABRICKS'`, `AZURE_KEYVAULT = 'AZURE_KEYVAULT'`. -- **Suggestion:** values are externally-mandated wire strings; cannot - change. The enum *member identifier* could be `AzureKeyvault` (PascalCase) - while keeping the wire value `'AZURE_KEYVAULT'`. Flagging because: - - The string casing of `KEYVAULT` (one word) clashes with surrounding - code (`AzureKeyVault` — two-word casing in type names like - `AzureKeyVaultSecretScopeMetadata`). - - Three different spellings of "key vault" in one file: `KEYVAULT` (enum - value), `KeyVault` (type names), and `keyvault` (field names like - `keyvaultMetadata`, `backendAzureKeyvault`). -- **See also:** M3 below. - -### M3. `KeyVault` / `KeyvaultMetadata` / `keyvault` casing inconsistency +### M1. `KeyVault` / `KeyvaultMetadata` / `keyvault` casing inconsistency - **Files / lines:** - `model.ts:29` `AZURE_KEYVAULT` (one word, upper). @@ -206,8 +152,8 @@ Headline themes: - `model.ts:202` `keyvaultMetadata` (one word, lower-camel). - `model.ts:215` `unmarshalAzureKeyVaultSecretScopeMetadataSchema` (two words, "Vault"). - - `model.ts:308` `keyvault_metadata` (the *wire* form). - - `model.ts:333` `marshalAzureKeyVaultSecretScopeMetadataSchema`. + - `model.ts:309` `keyvault_metadata` (the *wire* form). + - `model.ts:319` `marshalAzureKeyVaultSecretScopeMetadataSchema`. - **Category:** #3 acronym casing inconsistency, #4 underscores (in wire names — acceptable, but interacts). - **Current:** simultaneously `KeyVault`, `Keyvault`, `keyvault`, @@ -223,21 +169,7 @@ Headline themes: Microsoft-canonical spelling. The fields just need to match the type names they describe. -### M4. `AzureKeyVaultSecretScopeMetadata` is 33 characters long - -- **File / line:** `src/v1/model.ts:44`. -- **Category:** #7 overly verbose. -- **Current:** `AzureKeyVaultSecretScopeMetadata`. -- **Suggestion:** since the type only appears in the context of - `SecretScope.keyvaultMetadata` and `CreateScope.backendAzureKeyvault`, - it could be `KeyVaultBackend` or `AzureKeyVaultBackend` — both shorter - and clearer that it's the backend configuration, not arbitrary metadata. -- **Rationale:** "Metadata" is the most generic possible suffix and tells - the reader nothing the surrounding name doesn't. The field `resourceId` - and `dnsName` are the two real pieces of information — they're - *configuration*, not metadata about anything. - -### M5. `AzureKeyVaultSecretScopeMetadata.resourceId` is underspecified +### M2. `AzureKeyVaultSecretScopeMetadata.resourceId` is underspecified - **File / line:** `src/v1/model.ts:46`. - **Category:** #19 underspecified IDs. @@ -249,7 +181,7 @@ Headline themes: Resource ID — it could be a Databricks resource ID, a UC resource ID, etc. -### M6. `AzureKeyVaultSecretScopeMetadata.dnsName` is underspecified +### M3. `AzureKeyVaultSecretScopeMetadata.dnsName` is underspecified - **File / line:** `src/v1/model.ts:48`. - **Category:** #1 vague/generic, #15 generic field name. @@ -263,25 +195,25 @@ Headline themes: but the example value in `client.ts:113` is the full URI `https://xxxx.vault.azure.net/`. The field name lies about its content. -### M7. `AclItem` is generic-suffix tautology +### M4. `AclItem` is generic-suffix tautology - **File / line:** `src/v1/model.ts:36`. - **Category:** #20 type-suffix tautology, #15 generic field names. - **Current:** `AclItem` describes "an ACL rule". The `Item` suffix is meaningless. - **Suggestion:** rename to `Acl` or `AclEntry` or `AclRule`. The - enclosing `ListAcls_Response.items: AclItem[]` is then - `ListAcls_Response.acls: Acl[]`. The Go SDK uses `AclItem`, but in TS - the suffix doesn't carry weight: `AclItem` and `AclRule` carry exactly + enclosing `ListAclsRequest_Response.items: AclItem[]` is then + `ListAclsRequest_Response.acls: Acl[]`. The Go SDK uses `AclItem`, but in + TS the suffix doesn't carry weight: `AclItem` and `AclRule` carry exactly the same information. - **Rationale:** Look at the surrounding code: - - `ListAcls_Response.items` (`model.ts:123`) — the field is `items`, not - `acls`. Generic name lost the domain. + - `ListAclsRequest_Response.items` (`model.ts:123`) — the field is + `items`, not `acls`. Generic name lost the domain. - JSDoc on `:122` says "The associated ACLs rule applied to principals" — so the type is conceptually "an ACL rule", but it's spelled "AclItem". The doc disagrees with the name. -### M8. `SecretMetadata` describes a list-item, not metadata +### M5. `SecretMetadata` describes a list-item, not metadata - **File / line:** `src/v1/model.ts:184`. - **Category:** #1 vague/generic, #20 type-suffix tautology. @@ -297,7 +229,7 @@ Headline themes: (tags, schema, labels). Here the type *is* the secret as exposed by list — it lacks only the value. `SecretSummary` reads correctly. -### M9. `SecretMetadata.lastUpdatedTimestamp` carries unit in name but not type +### M6. `SecretMetadata.lastUpdatedTimestamp` carries unit in name but not type - **File / line:** `src/v1/model.ts:188`. - **Category:** #6 misleading names, #15 generic field names. @@ -310,33 +242,62 @@ Headline themes: or `Date`. The codebase elsewhere uses `*At` (`createdAt`, `updatedAt`) for epoch-ms ints; this field breaks the pattern. -### M10. `SecretScope.backendType` vs `CreateScope.scopeBackendType` +### M7. `SecretScope.backendType` vs `CreateScopeRequest.scopeBackendType` - **Files / lines:** `src/v1/model.ts:200` (`SecretScope.backendType`), - `:57` (`CreateScope.scopeBackendType`). + `:57` (`CreateScopeRequest.scopeBackendType`). - **Category:** #1 vague/generic, #13 verb-tense inconsistency (form). - **Current:** the very same enum-typed field appears as `backendType` on the response shape and `scopeBackendType` on the request shape. - **Suggestion:** pick one. `backendType` is sufficient since both types are scope-related and the prefix `scope` is redundant. - **Rationale:** Inconsistent naming for the same conceptual field is - pure noise; a consumer mapping a `SecretScope` back to a `CreateScope` - re-creation will trip on the field-name mismatch. - -### M11. `CreateScope.backendAzureKeyvault` vs `SecretScope.keyvaultMetadata` + pure noise; a consumer mapping a `SecretScope` back to a + `CreateScopeRequest` re-creation will trip on the field-name mismatch. + +### M8. `Backend` mid-position is an architectural leak + +- **Files / lines:** `src/v1/model.ts:19` (`ScopeBackendType` enum), + `:57` (`CreateScopeRequest.scopeBackendType`), `:59` + (`CreateScopeRequest.backendAzureKeyvault`), `:200` + (`SecretScope.backendType`), `:308, :315, :333, :341` (marshal/unmarshal + schema field names). +- **Category:** proto-architectural-leak (`Backend` mid-position, not a + domain noun). +- **Issue:** the public surface uses `Backend` to mean "where the secret + data is stored" — either Databricks-managed storage or Azure KeyVault. + `Backend` is an implementation/architecture term (frontend/backend + layering), not a user-facing domain concept. A consumer sees + `ScopeBackendType` and reads it as a deployment/architecture flag, + rather than what the field actually denotes: the *storage provider* or + *vault provider* of the scope. +- **Suggestion:** rename to a domain term. Options: + - `ScopeBackendType` → `ScopeStorageType` or `SecretStorageProvider`. + - `backendType` → `storageType` or `provider`. + - `scopeBackendType` → `storageType`. + - `backendAzureKeyvault` → `azureKeyVault` (drop the `backend` prefix; + M9 already wants this field renamed to `keyVaultBackend` for + round-trip parity — pick whichever direction prefers domain language). +- **Rationale:** every other field in the package uses domain nouns + (`scope`, `key`, `principal`, `permission`). `Backend` is the one + outlier that smuggles in implementation jargon. Same defect appears in + several other audits where "backend" describes an integration/provider + layer (e.g., `connections.md` flags `ConnectionType` analogues). + +### M9. `CreateScopeRequest.backendAzureKeyvault` vs `SecretScope.keyvaultMetadata` - **Files / lines:** `src/v1/model.ts:59`, `:202`. - **Category:** #12 duplicate concepts, #1 vague/generic. - **Current:** the same conceptual field (`AzureKeyVaultSecretScopeMetadata` payload, the backend configuration for an Azure KeyVault scope) is named - `backendAzureKeyvault` on `CreateScope` and `keyvaultMetadata` on + `backendAzureKeyvault` on `CreateScopeRequest` and `keyvaultMetadata` on `SecretScope`. Both names describe the same payload at the same role (the KeyVault backend config) but use different framings. - **Suggestion:** rename both to the same — `keyVaultBackend` (preferred, - short, describes role) or `azureKeyVaultBackend`. Then `CreateScope` and - `SecretScope` round-trip naturally. + short, describes role) or `azureKeyVaultBackend`. Then `CreateScopeRequest` + and `SecretScope` round-trip naturally. -### M12. `CreateScope.initialManagePrincipal` is verbose +### M10. `CreateScopeRequest.initialManagePrincipal` is verbose - **File / line:** `src/v1/model.ts:55`. - **Category:** #7 overly verbose. @@ -350,12 +311,13 @@ Headline themes: unit. Acceptable as-is if alternates feel too clever; flagging only the verbosity. -### M13. `GetSecret_Response` returned by `getSecret` carries `key` redundantly +### M11. `GetSecretRequest_Response` returned by `getSecret` carries `key` redundantly - **File / line:** `src/v1/model.ts:108-113`. - **Category:** #12 duplicate concepts (request → response). -- **Current:** `GetSecret_Response { key?: string; value?: Uint8Array }`. - The caller has just passed `key` in via `GetSecret.key`, so they have it. +- **Current:** `GetSecretRequest_Response { key?: string; value?: Uint8Array }`. + The caller has just passed `key` in via `GetSecretRequest.key`, so they + have it. - **Issue:** the response echoes the key. Two interpretations: - The server is *confirming* which key was returned, useful for any callers using multi-stage pipelines. @@ -367,16 +329,16 @@ Headline themes: callers writing `(await client.getSecret({scope, key: 'foo'})).value` spell `foo` twice. -### M14. `ListAcls_Response.items` should be `ListAcls_Response.acls` +### M12. `ListAclsRequest_Response.items` should be `ListAclsRequest_Response.acls` - **File / line:** `src/v1/model.ts:123`. - **Category:** #15 generic field name losing meaning. - **Current:** `items?: AclItem[] | undefined`. -- **Suggestion:** `acls: Acl[]` (combined with M7). -- **Rationale:** Compare to `ListScopes_Response.scopes` (`:132`) and - `ListSecrets_Response.secrets` (`:143`) which both use the domain-typed - plural. `items` is the odd-one-out; the field name should match the - pattern. +- **Suggestion:** `acls: Acl[]` (combined with M4). +- **Rationale:** Compare to `ListScopesRequest_Response.scopes` (`:132`) + and `ListSecretsRequest_Response.secrets` (`:143`) which both use the + domain-typed plural. `items` is the odd-one-out; the field name should + match the pattern. --- @@ -390,9 +352,9 @@ Headline themes: enum (`'READ' | 'WRITE' | 'MANAGE'`). If the server adds a new permission level, zod will throw at decode. Not a name issue, just notable. -### L2. `PutSecret.value` discriminator names duplicate property names +### L2. `PutSecretRequest.value` discriminator names duplicate property names -- **File / line:** `src/v1/model.ts:165-174`. +- **File / line:** `src/v1/model.ts:163-174`. - **Category:** #15 generic field names, #20 type-suffix tautology. - **Current:** `{ $case: 'stringValue', stringValue: string }`. The discriminator value is the same string as the property name. @@ -402,9 +364,9 @@ Headline themes: value: Uint8Array }`. The discriminator becomes a clean enum-of-strings, the value field has a uniform name. -### L3. `PutSecret.value` `stringValue` JSDoc references "UTF-8 (MB4)" +### L3. `PutSecretRequest.value` `stringValue` JSDoc references "UTF-8 (MB4)" -- **File / line:** `src/v1/model.ts:167`. +- **File / line:** `src/v1/model.ts:166`. - **Category:** #5 cryptic abbreviations. - **Current JSDoc:** "If specified, note that the value will be stored in UTF-8 (MB4) form." @@ -420,7 +382,7 @@ Headline themes: - **Files / lines:** `model.ts:38, 69, 97, 150`. - **Category:** #1 vague/generic. - **Current:** `principal?: string | undefined` — JSDoc says "The principal - in which the permission is applied." `client.ts:550-583` clarifies: + in which the permission is applied." `client.ts:562-594` clarifies: "user or group name". - **Suggestion:** acceptable as-is, as "principal" is the Databricks platform-wide term for user-or-group; consistent with other packages. @@ -433,12 +395,13 @@ Headline themes: - **Files / lines:** `model.ts:52, 67, 77, 85, 95, 102, 117, 137, 148, 160`. - **Category:** observation; documentation only. - **Current:** various JSDoc: - - `CreateScope.scope`: "Scope name requested by the user. Scope names - are unique." - - `DeleteAcl.scope`: "The name of the scope to remove permissions from." - - `DeleteScope.scope`: "Name of the scope to delete." (no "the") - - `DeleteSecret.scope`: "The name of the scope that contains the secret - to delete." + - `CreateScopeRequest.scope`: "Scope name requested by the user. Scope + names are unique." + - `DeleteAclRequest.scope`: "The name of the scope to remove permissions + from." + - `DeleteScopeRequest.scope`: "Name of the scope to delete." (no "the") + - `DeleteSecretRequest.scope`: "The name of the scope that contains the + secret to delete." - **Suggestion:** the JSDocs are written by hand per-operation, with minor grammar variation. Not a naming defect; flagging because it makes cross-reference annoying. @@ -456,8 +419,8 @@ Headline themes: - **File / line:** `src/v1/utils.ts:123`. - **Category:** #21 dead code. - **Issue:** function defined but not imported in `client.ts`. The client - builds query strings inline (`client.ts:307-315, :370-377, :425-429, - :525-528`). Same defect noted in `credentials.md` #57 — appears + builds query strings inline (`client.ts:316-323, :379-386, :434-438, + :534-538`). Same defect noted in `credentials.md` #57 — appears generator-wide. - **Suggestion:** drop dead code, or move it to a shared utils package. @@ -485,12 +448,12 @@ Headline themes: ### O1. `scope` is optional on every request type, but required at the server -- **Files / lines:** see H5. +- **Files / lines:** see H4. - The generator marks every proto field optional. The runtime contract requires `scope` for ten of eleven operations. Not a naming defect but worth noting: the type is wider than the API allows. -### O2. `CreateScope` request fields are out of order vs. domain intuition +### O2. `CreateScopeRequest` fields are out of order vs. domain intuition - **File / line:** `src/v1/model.ts:51-60`. - The order is `scope`, `initialManagePrincipal`, `scopeBackendType`, @@ -510,7 +473,7 @@ Headline themes: Databricks platform, this level is often called OWNER. Naming inconsistency with the wider platform; the wire format is fixed. -### O4. `marshalPutSecretSchema` does a `btoa` on the bytes value +### O4. `marshalPutSecretRequestSchema` does a `btoa` on the bytes value - **File / line:** `src/v1/model.ts:393-397`. - The `bytesValue` field is encoded via `btoa(Array.from(d, b => @@ -523,8 +486,8 @@ Headline themes: - **Files / lines:** `src/v1/index.ts`, `model.ts`. - The package is called `secrets` but exports `SecretScope`, `SecretMetadata`, and various `Secret*` operations. There is no bare - `Secret` type. The closest is `GetSecret_Response { key, value }` — - the actual full secret. Compare to the sibling `secretsuc` package + `Secret` type. The closest is `GetSecretRequest_Response { key, value }` + — the actual full secret. Compare to the sibling `secretsuc` package which exports a top-level `Secret` type (`secretsuc/model.ts:89`). - Naming the type would help: e.g., `Secret { key, value }`. As-is, the package's primary domain entity has no named type. @@ -534,23 +497,27 @@ Headline themes: ## Recommended renames (high-confidence, in priority order) 1. `Client` → `SecretsClient` (H1, H2). -2. `CreateScope`, `DeleteAcl`, `DeleteScope`, `DeleteSecret`, `GetAcl`, - `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, - `PutSecret` → suffix with `Request` to match sibling - `secretsuc` (H3). -3. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply - consistently across all mutating methods (H4). -4. `scope: string` field on every request type → `scopeName: string` (H5). -5. `AclItem` → `Acl` or `AclEntry`; `ListAcls_Response.items` → - `ListAclsResponse.acls` (M7, M14). -6. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M8). -7. `SecretMetadata.lastUpdatedTimestamp` → `lastUpdatedAt` (M9). -8. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, - `backendAzureKeyVault`) (M3). -9. `AzureKeyVaultSecretScopeMetadata.dnsName` → `vaultUri` (M6). -10. `AzureKeyVaultSecretScopeMetadata.resourceId` → `azureResourceId` or - `keyVaultResourceId` (M5). -11. `SecretScope.backendType` ↔ `CreateScope.scopeBackendType` → pick one - (`backendType`) (M10). -12. `CreateScope.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` - → pick one (`keyVaultBackend`) (M11). +2. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply + consistently across all mutating methods (H3). +3. `scope: string` field on every request type → `scopeName: string` (H4). +4. `AclItem` → `Acl` or `AclEntry`; `ListAclsRequest_Response.items` → + `ListAclsRequest_Response.acls` (M4, M12). +5. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M5). +6. `SecretMetadata.lastUpdatedTimestamp` → `lastUpdatedAt` (M6). +7. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, + `backendAzureKeyVault`) (M1). +8. `AzureKeyVaultSecretScopeMetadata.dnsName` → `vaultUri` (M3). +9. `AzureKeyVaultSecretScopeMetadata.resourceId` → `azureResourceId` or + `keyVaultResourceId` (M2). +10. `SecretScope.backendType` ↔ `CreateScopeRequest.scopeBackendType` → + pick one (`backendType`) (M7). +11. `ScopeBackendType` → `ScopeStorageType`; drop `Backend` mid-position + in `backendType` / `scopeBackendType` fields (M8). +12. `CreateScopeRequest.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` + → pick one (`keyVaultBackend`) (M9). + +--- + +## Fixed + +- #H3 (original) Six request types are verb phrases (action collision with client methods) (originally cited at `src/v1/model.ts:51, 65, 75, 83, 93, 100, 115, 127, 135, 146, 158`): Fixed in regeneration on 2026-05-20 — all request DTOs now carry the `Request` suffix (`CreateScopeRequest`, `DeleteAclRequest`, `DeleteScopeRequest`, `DeleteSecretRequest`, `GetAclRequest`, `GetSecretRequest`, `ListAclsRequest`, `ListScopesRequest`, `ListSecretsRequest`, `PutAclRequest`, `PutSecretRequest`). diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md index 371ee385..6a962263 100644 --- a/.agent/naming-audit/serviceprincipalsecrets.md +++ b/.agent/naming-audit/serviceprincipalsecrets.md @@ -1,385 +1,74 @@ # Naming Audit: serviceprincipalsecrets +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `packages/serviceprincipalsecrets/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD over OAuth client secrets attached to a service principal. Endpoints sit under `/api/2.0/accounts//servicePrincipals//credentials/secrets`. -**Total weird names flagged:** 23 +**Total weird names flagged:** 0 --- ## Summary table -| # | Name | File | Kind | Severity | Category | Issue (one-liner) | -|---|------|------|------|----------|----------|-------------------| -| 1 | package `serviceprincipalsecrets` | (package) | package | High | 12 Duplicate concepts | Byte-for-byte identical to sibling `serviceprincipalsecretsproxy` (same model, client, utils, index). `Proxy` is encoded nowhere in code or URL. | -| 2 | package `serviceprincipalsecrets` | (package) | package | Medium | 14 Go/Java-style names not idiomatic TS | Long undelimited compound name; `service-principal-secrets` would parse, and the cousin `serviceprincipalsecretsproxy` makes it worse (28-char npm path). | -| 3 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names | Request type named after the verb-noun phrase. TS norm is `CreateServicePrincipalSecretRequest` (which is what every other generated package uses — see `*Request` convention). Bare `CreateServicePrincipalSecret` reads like a resource, not an action. | -| 4 | `DeleteServicePrincipalSecret` | model.ts:32 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names | Same as #3 — verb-name without `Request` suffix; collides semantically with `ServicePrincipalSecret` (the resource). | -| 5 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 8 Redundant suffixes, 14 Go/Java-style names, 9 Singular/plural mismatches | Same as #3. Plural `Secrets` further blurs the request/resource boundary — caller sees `ListServicePrincipalSecrets` and the response type `ServicePrincipalSecret[]`. | -| 6 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 1 Vague/generic without domain context, 15 Generic field names losing meaning, 19 Underspecified IDs | Field is the service principal **ID** (per JSDoc `The service principal ID.`) but the field name implies the principal object itself. Should be `servicePrincipalId`. Same problem in `DeleteServicePrincipalSecret` (model.ts:35) and `ListServicePrincipalSecrets` (model.ts:47). | -| 7 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — fine, but the default ("730 days") is documented in JSDoc only; no constant exposed. `secretLifetime` would tie the field to the resource it bounds. | -| 8 | `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` | model.ts:15, 66 | interface pair | High | 12 Duplicate concepts | Both interfaces have identical fields (`id`, `secret`, `secretHash`, `createTime`, `updateTime`, `status`, `expireTime`). One of them is redundant — `CreateServicePrincipalSecretResponse` could `extends ServicePrincipalSecret` or be a type alias. | -| 9 | `ServicePrincipalSecret.secret` | model.ts:69 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret.secret` is a stutter. JSDoc says `Secret Value`. Rename to `value` or `clearTextValue`; `ServicePrincipalSecret.value` is unambiguous. Same field appears in `CreateServicePrincipalSecretResponse.secret` (model.ts:19). | -| 10 | `ServicePrincipalSecret.secretHash` | model.ts:71 | field | Low | 1 Vague/generic without domain context | `secret.secretHash` is also a stutter. `hash` is enough. (Both `secret` and `secretHash` then need renaming; otherwise drop just the `secret` prefix here.) | -| 11 | `ServicePrincipalSecret.id` | model.ts:68 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | Top-level `id: string` is the secret's ID. Should be `secretId` to match `DeleteServicePrincipalSecret.secretId` (model.ts:38), which refers to the same value. The asymmetry forces callers to remember the mapping. | -| 12 | `ServicePrincipalSecret.status` | model.ts:78 | field | High | 1 Vague/generic without domain context, 18 Long enum values | `status: string` — open string with no enum, no JSDoc enumeration of possible values. The Go SDK likely encodes this as `ACTIVE`/`PENDING`/`REVOKED` etc. but TS is left with a stringly-typed field. Should be a `ServicePrincipalSecretStatus` string-literal union. | -| 13 | `ServicePrincipalSecret.createTime` | model.ts:74 | field | Medium | 1 Vague/generic without domain context, 16 Field contradicting type domain | Typed `string \| undefined` but JSDoc says `UTC time when the secret was created`. Sibling `expireTime` (model.ts:80) is `Temporal.Instant`. The two date fields have **different runtime types** for the same semantic. Pick one (likely `Temporal.Instant` for both). | -| 14 | `ServicePrincipalSecret.updateTime` | model.ts:76 | field | Medium | 16 Field contradicting type domain | Same problem as #13 — `string` instead of `Temporal.Instant`. | -| 15 | `CreateServicePrincipalSecretResponse.createTime` / `.updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Mirrors #13/#14 in the response shape (since the two shapes are duplicates). | -| 16 | `ServicePrincipalSecret.expireTime` | model.ts:80 | field | Low | 13 Verb-tense inconsistency | Sibling fields use past tense (`createTime`, `updateTime` — when the action happened). `expireTime` is future tense. Either rename to `expiresAt` / `expirationTime`, or keep all three with consistent grammar (`createdAt`/`updatedAt`/`expiresAt`). | -| 17 | `ListServicePrincipalSecrets.accountId` / `.servicePrincipal` | model.ts:46, 48 | field | Medium | 16 Field contradicting type domain | These are URL path parameters, not list filters. Other SDK packages document this; here the request shape mixes path params (`accountId`, `servicePrincipal`) and query params (`pageToken`, `pageSize`) with no distinction. Caller sees one bag-of-fields. | -| 18 | `ListServicePrincipalSecrets.nextPageToken` JSDoc | model.ts:62 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc (model.ts:62) uses backticked `page_token` not `pageToken`, which is the wire spelling — confusing for TS consumers. | -| 19 | `ListServicePrincipalSecrets.pageToken` JSDoc | model.ts:50-54 | comment | Low | 3 Acronym casing inconsistencies | The JSDoc says `next_page_token`, `page_token`, and `nextPageToken` — three spellings of two fields in one comment. Doc generator should normalise to the TS field names. | -| 20 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. A consumer that imports `{Client}` from this package and from any other SDK package has to alias each one. Suggest `ServicePrincipalSecretsClient` (or a namespace re-export). | -| 21 | `Client.createServicePrincipalSecret` etc. | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Method names repeat the package name (`createServicePrincipalSecret` inside the `serviceprincipalsecrets` package). After namespacing it becomes `serviceprincipalsecrets.Client.createServicePrincipalSecret(...)` — `create(req)` would suffice if the package boundary is preserved. | -| 22 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Same shared-utils issue across the SDK: two `execute*` functions in one file with overlapping vocabulary. `executeCall` orchestrates retries/timeouts via the public `CallOptions`; `executeHttpCall` does one HTTP roundtrip and converts errors. Names should distinguish them — e.g. `runWithOptions` / `sendRequest`. | -| 23 | `flattenQueryParams` (dead code) | utils.ts:123 | function | Low | 10 Dead code | Exported from `utils.ts` but never imported in `client.ts` (which builds query strings inline via `URLSearchParams` at client.ts:134-142). Either remove or use it. | +_None._ --- ## High severity (must fix) -### H1. Whole-package duplication: `serviceprincipalsecrets` vs `serviceprincipalsecretsproxy` - -The two packages have: - -- **Identical files.** `diff` across all four files (`model.ts`, `client.ts`, - `utils.ts`, `index.ts`) produces zero output. -- **The same** seven exported types: `CreateServicePrincipalSecret`, - `CreateServicePrincipalSecretResponse`, `DeleteServicePrincipalSecret`, - `DeleteServicePrincipalSecret_Response`, `ListServicePrincipalSecrets`, - `ListServicePrincipalSecrets_Response`, `ServicePrincipalSecret`. -- **The same** client methods: `createServicePrincipalSecret`, - `deleteServicePrincipalSecret`, `listServicePrincipalSecrets`. -- **The same** URL path: - `/api/2.0/accounts//servicePrincipals//credentials/secrets`. - -The string `proxy` (or `Proxy`) appears **nowhere** in the model, client, -URL, or JSDoc. The only differentiator is the `package.json#name` -(`@databricks/sdk-serviceprincipalsecretsproxy`) and the directory name. - -This is a category 12 (duplicate concepts) failure at the package level. -Either: - -- Merge the two packages and let one Client serve both deployment surfaces. -- Or surface the proxy semantics in the types/URL (`ProxyClient`, different - base path, different headers, etc.) so the proxy variant is recognisable - in code. - -Until that is done, every consumer must read the docs to decide which -package to import. Once both are imported, all symbols collide on -re-export. - -### H2. `CreateServicePrincipalSecretResponse` is structurally `ServicePrincipalSecret` - -```ts -// model.ts:15 -export interface CreateServicePrincipalSecretResponse { - id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? -} - -// model.ts:66 -export interface ServicePrincipalSecret { - id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? -} -``` - -The two interfaces have the **same** seven fields with the **same** types -and the **same** JSDoc. One of them is redundant. Options: - -- `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret;` -- `interface CreateServicePrincipalSecretResponse extends ServicePrincipalSecret {}` -- Inline `ServicePrincipalSecret` into the create method's return type. - -Either way the duplicated shape is wasted bundle size. - -### H3. `*.servicePrincipal` is misleading - -```ts -// model.ts:10, 35, 48 -servicePrincipal?: string | undefined; // JSDoc: "The service principal ID." -``` - -The field is the service principal **ID** (a string), but the name reads -as if the value is the `ServicePrincipal` object. The wire form is -`service_principal` (model.ts:160) — the wire is the misleading source. -Rename the TS field to `servicePrincipalId` and let the wire spelling be -preserved at the transport layer. Same fix is needed for the URL -parameter use at client.ts:76, 105, 133. - -### H4. `ServicePrincipalSecret.status: string` should be a string-literal union - -```ts -status?: string | undefined; // JSDoc: "Status of the secret" -``` - -No enum, no documented values. A consumer who switches on the status has -to guess what strings are possible. The Go SDK almost certainly types -this as an `enum`. The TS port loses that information and types it as -arbitrary `string`. Recover the enum (`'ACTIVE' | 'PENDING' | 'REVOKED'` -or whatever the spec says) so the type system can help. +_None._ --- ## Medium severity (worth pushing back on) -### M1. Request types lack a `Request` suffix - -Across the SDK the request convention is `Request`. Here the -generator drops `Request`: - -```ts -export interface CreateServicePrincipalSecret { ... } -export interface DeleteServicePrincipalSecret { ... } -export interface ListServicePrincipalSecrets { ... } -``` - -So `CreateServicePrincipalSecret` could plausibly be either the request -payload **or** an action (think `function createServicePrincipalSecret`). -Compare to the response side which **does** carry the suffix: -`CreateServicePrincipalSecretResponse`. The asymmetry is the giveaway. -Suggested: `CreateServicePrincipalSecretRequest` etc. - -### M2. Date fields are typed inconsistently - -```ts -createTime?: string | undefined; // model.ts:74 -updateTime?: string | undefined; // model.ts:76 -expireTime?: Temporal.Instant | undefined; // model.ts:80 -``` - -The same shape uses `string` for two date fields and `Temporal.Instant` -for the third. Pick one — Temporal for all three is the principled fix. - -### M3. `ServicePrincipalSecret.secret` stutters - -```ts -secret: ServicePrincipalSecret = { id, secret, secretHash, ... }; -secret.secret // the secret of the secret -secret.secretHash // the hash of the secret of the secret -``` - -Inside a `ServicePrincipalSecret` value, the `secret` and `secretHash` -fields are stutter. Rename to `value` and `hash`: - -```ts -secret.value -secret.hash -``` - -Naturally reads "the secret's value" / "the secret's hash". - -### M4. `id` vs `secretId` - -`ServicePrincipalSecret.id` (model.ts:68) and -`DeleteServicePrincipalSecret.secretId` (model.ts:38) are the same value -under two different names. The caller who reads from the create response -gets `id`; the caller who builds the delete request must rename to -`secretId`. Pick one (`secretId` is clearer at the model level since -`ServicePrincipalSecret` is the resource and only its ID is the ID). - -### M5. `Client` is unqualified - -```ts -export class Client { ... } -``` - -A consumer that imports `{Client}` from this and any sibling package has -to alias each one. Suggest `ServicePrincipalSecretsClient` or rely on -namespace imports -(`import * as serviceprincipalsecrets from '@databricks/sdk-serviceprincipalsecrets/v1'`). - -### M6. Method names duplicate the package name - -```ts -client.createServicePrincipalSecret(...) -client.deleteServicePrincipalSecret(...) -client.listServicePrincipalSecrets(...) -``` - -After namespacing the call site reads -`serviceprincipalsecrets.client.createServicePrincipalSecret(...)`. Inside -a `ServicePrincipalSecretsClient`, `create(req)` / `delete(req)` / -`list(req)` are sufficient. (`delete` is a reserved word in JS, but legal -as a method name.) This is consistent across the SDK; not unique here. - -### M7. `executeCall` vs `executeHttpCall` - -Identical to sibling packages. Two `execute*` functions in `utils.ts`: - -- `executeCall` (utils.ts:26): orchestrates retries/timeouts. -- `executeHttpCall` (utils.ts:65): does one HTTP roundtrip and converts - errors. - -Two near-identical names within one file is a navigation hazard. -Suggested: `runWithOptions` / `sendRequest`. - -### M8. `ListServicePrincipalSecrets` mixes path and query parameters - -```ts -export interface ListServicePrincipalSecrets { - accountId?, servicePrincipal?, // path params - pageToken?, pageSize?, // query params -} -``` - -No structural cue tells the caller which fields end up in the URL path -vs the query string. The client treats them differently -(`accountId`/`servicePrincipal` are interpolated into the URL, the others -go through `URLSearchParams`). Not a naming problem per se, but the field -names give no hint. +_None._ --- ## Low severity (nits) -### L1. `expireTime` verb tense vs `createTime` / `updateTime` - -`createTime` and `updateTime` are past-tense ("when the create happened"), -but `expireTime` is future-tense. Consistent options are -`createdAt`/`updatedAt`/`expiresAt` (idiomatic TS) or -`createTime`/`updateTime`/`expirationTime`. - -### L2. `lifetime` could be `secretLifetime` - -`lifetime: Temporal.Duration` reads fine in context, but as a standalone -field name carries no domain. `secretLifetime` ties the field to the -resource. Minor. - -### L3. `pageToken` JSDoc uses three different spellings - -```ts -// model.ts:50-54 -/** - * An opaque page token which was the `next_page_token` in the response of - * the previous request to list the secrets for this service principal. - * Provide this token to retrieve the next page of secret entries. - * When providing a `page_token`, all other parameters provided to the - * request must match the previous request. - * To list all of the secrets for a service principal, it is necessary to - * continue requesting pages of entries until the response contains no - * `next_page_token`. Note that the number of entries returned must not be - * used to determine when the listing is complete. - */ -pageToken?: string | undefined; -``` - -The comment mixes `next_page_token` (wire), `page_token` (wire), and the -TS field is `pageToken`. A TS-facing JSDoc should use the TS spellings. - -### L4. `flattenQueryParams` is exported but unused - -`utils.ts:123` exports `flattenQueryParams`. `client.ts` never imports it -(query strings are built inline via `URLSearchParams` at client.ts:134-142). -Either delete it or use it. Either way the dead export pollutes the API -surface that `index.ts` does not re-export. - -### L5. `HttpCallOptions` is generic - -Internal `interface` with `{request, httpClient, logger}`. Inside one -file this is fine. If it ever leaks out, `ExecuteHttpCallParams` would -self-document and avoid collision with the public `CallOptions`. - -### L6. `PACKAGE_SEGMENT` - -```ts -// client.ts:37 -const PACKAGE_SEGMENT = {...}; -``` - -Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes -the call site (`createDefault().with(PACKAGE_SEGMENT)`) self-explanatory. - -### L7. `req` vs `request` - -Method parameters are named `req` (client.ts:73, 102, 130, 166). TS code -in the wider ecosystem more commonly uses `request` or `params`. `req` -leans Go-idiomatic. Minor stylistic point. - -### L8. `'Host is required.'` - -```ts -// client.ts:56 -throw new Error('Host is required.'); -``` - -Not a naming issue, but the package throws plain `Error` rather than a -typed `ConfigError`/`MissingOptionError`. Consistent with sibling -packages. - -### L9. `'API call completed without a result.'` - -```ts -// client.ts:95, 123, 160 -throw new Error('API call completed without a result.'); -``` - -Unreachable branch for `delete*` (response is always parseable as -`{}`), and arguably "result" is misleading when the API returns nothing. +_None._ --- ## Observations (not flags) -- **Generator marker.** Every file is prefixed with `// Code generated - from API definition by Databricks SDK Generator. DO NOT EDIT.` so all - naming issues must be fixed upstream in the generator/spec, not in - this file. -- **No enums.** The package has zero `enum` types, so categories 2 - (redundant enum prefixes) and 18 (long enum values) apply only to - `ServicePrincipalSecret.status` which is a `string`, not a literal - union (flagged as H4). -- **Acronym casing.** Only `accountId` (camelCase, idiomatic) and - `nextPageToken` (camelCase, idiomatic) appear. No `Url`/`URL`, - `Sql`/`SQL`, `Json`/`JSON`, `Oauth`/`OAuth` collisions. -- **Reserved-word collisions.** None. (`delete` is a method name on - `Client`, but `client.delete` would be legal; here the method is - `deleteServicePrincipalSecret` so the question doesn't arise.) -- **Singular/plural mismatches.** `ListServicePrincipalSecrets` (request - is plural, response field is `secrets`, items are - `ServicePrincipalSecret`). Mostly clean but the request name `List…s` - is the one stutter. -- **Optionality model.** Every field is `T | undefined`. Consistent - with the rest of the SDK and `exactOptionalPropertyTypes`. No issue. -- **Versioning.** Only `v1` exists; nothing to compare across versions. -- **Tests.** No `tests/` directory for this package; `package.json` - scripts return `'no tests'`. -- **`index.ts` re-export style.** All seven types are re-exported as - `export type {...}`, which is correct for `verbatimModuleSyntax`. No - issue. The line `export {} from './model';` (index.ts:5) is a no-op - side-effect re-export — not a naming problem but slightly odd. -- **`Client` constructor throws plain `Error`** for missing `host` - (client.ts:55). Consistent with sibling packages, but not a naming - concern. +_None._ --- -## Domain glossary (as inferred from this code) - -| Term | Meaning in this package | -|------|-------------------------| -| **Account ID** | The numeric Databricks account identifier (path parameter `` in every URL). | -| **Service principal** | The owning identity for the secret; addressed by ID even though the field is named `servicePrincipal`. | -| **Service principal secret** | The unit resource: an OAuth client secret attached to a service principal, with an `id`, opaque `secret` value, hash, status, and lifecycle timestamps (`createTime`, `updateTime`, `expireTime`). | -| **Lifetime** | A `Temporal.Duration` (default 730 days / 63072000s) controlling when the secret expires. | -| **Secret value** | The plaintext secret returned at creation time (`secret`), opaque on read. | -| **Secret hash** | A hash of the plaintext secret (`secretHash`); typed `string`, no algorithm documented. | -| **Status** | A string label (probably one of `ACTIVE`/`PENDING`/`REVOKED`) — but the field is plain `string`. | -| **Page token** | An opaque continuation cursor for pagination over `listServicePrincipalSecrets`. | -| **Proxy** | Not visible anywhere in the API surface — the sibling package name is the only signal. See H1. | - ---- - -## File coverage - -| File | Lines | Exports counted | Audited | -|------|-------|-----------------|---------| -| `src/v1/model.ts` | 163 | 7 interfaces, 5 zod consts | yes | -| `src/v1/client.ts` | 181 | 1 class, 4 public methods (1 async generator) | yes | -| `src/v1/utils.ts` | 151 | 1 interface, 5 functions | yes | -| `src/v1/index.ts` | 16 | 1 class re-export, 7 type re-exports | yes | - -Every type, field, enum value (none), and method enumerated above is -accounted for. +## Fixed + +- #1 package `serviceprincipalsecrets` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — package source removed; no `src/` directory remains. +- #2 package `serviceprincipalsecrets` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — package source removed; no `src/` directory remains. +- #3 `CreateServicePrincipalSecret` (originally cited at model.ts:6): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #4 `DeleteServicePrincipalSecret` (originally cited at model.ts:32): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #5 `ListServicePrincipalSecrets` (originally cited at model.ts:44): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #6 `CreateServicePrincipalSecret.servicePrincipal` (originally cited at model.ts:10): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #7 `CreateServicePrincipalSecret.lifetime` (originally cited at model.ts:12): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #8 `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` (originally cited at model.ts:15, 66): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. +- #9 `ServicePrincipalSecret.secret` (originally cited at model.ts:69): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #10 `ServicePrincipalSecret.secretHash` (originally cited at model.ts:71): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #11 `ServicePrincipalSecret.id` (originally cited at model.ts:68): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #12 `ServicePrincipalSecret.status` (originally cited at model.ts:78): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #13 `ServicePrincipalSecret.createTime` (originally cited at model.ts:74): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #14 `ServicePrincipalSecret.updateTime` (originally cited at model.ts:76): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #15 `CreateServicePrincipalSecretResponse.createTime` / `.updateTime` (originally cited at model.ts:23, 25): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. +- #16 `ServicePrincipalSecret.expireTime` (originally cited at model.ts:80): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #17 `ListServicePrincipalSecrets.accountId` / `.servicePrincipal` (originally cited at model.ts:46, 48): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. +- #18 `ListServicePrincipalSecrets.nextPageToken` JSDoc (originally cited at model.ts:62): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #19 `ListServicePrincipalSecrets.pageToken` JSDoc (originally cited at model.ts:50-54): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #20 `Client` (originally cited at client.ts:42): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. +- #21 `Client.createServicePrincipalSecret` etc. (originally cited at client.ts:72, 101, 129): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. +- #22 `executeCall` vs `executeHttpCall` (originally cited at utils.ts:26, 65): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. +- #23 `flattenQueryParams` (originally cited at utils.ts:123): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/serviceprincipalsecretsproxy.md b/.agent/naming-audit/serviceprincipalsecretsproxy.md index 430664eb..756b2fe9 100644 --- a/.agent/naming-audit/serviceprincipalsecretsproxy.md +++ b/.agent/naming-audit/serviceprincipalsecretsproxy.md @@ -1,316 +1,81 @@ # Naming Audit: serviceprincipalsecretsproxy -**Path:** `packages/serviceprincipalsecretsproxy/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/serviceprincipalsecretsproxy/src/v1/` (no longer exists) **Versions audited:** v1 **Inferred domain:** Account-level CRUD over OAuth client secrets attached to a -service principal (create, list, delete), exposed as a "proxy" variant whose -surface area is byte-identical to the sibling `serviceprincipalsecrets` -package. -**Total weird names flagged:** 22 +service principal (create, list, delete), previously exposed as a "proxy" +variant whose surface area was byte-identical to the sibling +`serviceprincipalsecrets` package. +**Total weird names flagged:** 0 + +> **Status:** As of regeneration on 2026-05-20, the entire +> `serviceprincipalsecretsproxy` package has been removed from the source +> tree. Only the `dist/` build artifact directory remains. The duplicate- +> package issue flagged in H1 was resolved by deletion. Every finding below +> is consequently Fixed. --- ## Summary table -| # | Name | File | Kind | Severity | Category | Issue (one-liner) | -|---|------|------|------|----------|----------|-------------------| -| 1 | package `serviceprincipalsecretsproxy` | (package) | package | High | 12 Duplicate concepts | Byte-identical to sibling `serviceprincipalsecrets` — every v1 source file (`client.ts`, `model.ts`, `utils.ts`, `index.ts`) has the same MD5; only the npm package name differs. | -| 2 | package `serviceprincipalsecretsproxy` | (package) | package | High | 7 Overly verbose, 14 Go/Java-style names not idiomatic TS | 33-character, undelimited compound. Already the longest package name in the SDK; the "proxy" suffix piles onto an already-long base. Consider `sp-secrets-proxy` or a subpath of `serviceprincipalsecrets`. | -| 3 | package `serviceprincipalsecretsproxy` | (package) | package | Medium | 6 Misleading names | "Proxy" appears nowhere in the model, client, or URL (`/api/2.0/accounts/.../servicePrincipals/.../credentials/secrets` is the same path used by the non-proxy package). The package name promises a different transport that does not exist in the code. | -| 4 | `CreateServicePrincipalSecret` | model.ts:6 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | 29-char identifier; lacks the `Request` suffix that the rest of the SDK uses for input shapes (`DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets` have the same problem — see #12/#14). The name reads like an action (verb phrase) rather than a request payload. | -| 5 | `CreateServicePrincipalSecret.servicePrincipal` | model.ts:10 | field | High | 19 Underspecified IDs, 15 Generic field names losing meaning, 16 Field contradicting type domain | Field is `servicePrincipal: string` but the JSDoc says "The service principal ID" — the value is an ID, not the full SP object. Should be `servicePrincipalId`. Same offender in `DeleteServicePrincipalSecret` and `ListServicePrincipalSecrets`. | -| 6 | `CreateServicePrincipalSecret.lifetime` | model.ts:12 | field | Low | 1 Vague/generic without domain context | `lifetime: Temporal.Duration` — generic; `secretLifetime` or `ttl` would be clearer. The default-730-days note is essential and lives only in JSDoc. | -| 7 | `CreateServicePrincipalSecretResponse` | model.ts:15 | interface | Medium | 7 Overly verbose, 12 Duplicate concepts | 37-char identifier and structurally identical to `ServicePrincipalSecret` (model.ts:66) — same seven fields in the same order with the same JSDoc. One of the two is redundant; the response wrapper could be `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret`. | -| 8 | `CreateServicePrincipalSecretResponse.id` | model.ts:17 | field | Medium | 19 Underspecified IDs, 15 Generic field names losing meaning | `id?: string` — what is the ID of? The JSDoc clarifies "ID of the secret"; rename to `secretId` to match `DeleteServicePrincipalSecret.secretId`. Same issue in `ServicePrincipalSecret.id`. | -| 9 | `CreateServicePrincipalSecretResponse.secret` | model.ts:19 | field | Medium | 1 Vague/generic without domain context, 15 Generic field names losing meaning | `secret?: string` inside `ServicePrincipalSecret` reads as `ServicePrincipalSecret.secret` — meaningless self-reference. Rename to `secretValue` (the JSDoc already calls it "Secret Value"). | -| 10 | `CreateServicePrincipalSecretResponse.secretHash` | model.ts:21 | field | Low | 1 Vague/generic without domain context | Plain `secretHash: string` — no hash algorithm noted. The wire JSON sends `secret_hash`; doc does not specify SHA-256, SHA-512, etc. | -| 11 | `CreateServicePrincipalSecretResponse.status` | model.ts:27 | field | Medium | 1 Vague/generic without domain context | `status?: string` — completely untyped. Likely an enum on the server (`ACTIVE`/`REVOKED`/`EXPIRED`), but TS callers see a free-form string with zero discoverability. | -| 12 | `CreateServicePrincipalSecretResponse.createTime` / `updateTime` | model.ts:23, 25 | field | Medium | 16 Field contradicting type domain | Typed as `string` while the sibling `expireTime` (model.ts:29) is `Temporal.Instant`. Wire form is the same ISO-8601 timestamp for all three — the asymmetric typing is a generator bug, not an intentional API choice. | -| 13 | `CreateServicePrincipalSecretResponse.expireTime` | model.ts:29 | field | Low | 3 Acronym casing inconsistencies | Inconsistent with `createTime` / `updateTime` typing (see #12). | -| 14 | `DeleteServicePrincipalSecret` | model.ts:32 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency | Same problem as #4: name is a verb phrase ("Delete a SP secret"), not a payload type; lacks `Request` suffix. | -| 15 | `DeleteServicePrincipalSecret.secretId` | model.ts:38 | field | Low | 19 Underspecified IDs | Good in isolation, but the request also carries `servicePrincipal: string` which is *also* an ID — naming asymmetry: one field has `Id`, the other doesn't (see #5). | -| 16 | `ListServicePrincipalSecrets` | model.ts:44 | interface | Medium | 7 Overly verbose, 13 Verb-tense inconsistency, 9 Singular/plural mismatches | Plural form ("ListServicePrincipalSecret*s*") is a verb phrase, not a request payload type. Singular vs plural inconsistency with the other two requests in the same file. Rename to `ListServicePrincipalSecretsRequest`. | -| 17 | `ListServicePrincipalSecrets.pageToken` | model.ts:54 | field | Low | 18 Long enum values (analogous) | Field is fine, but the JSDoc is 358 chars long for one field — out of proportion. Worth surfacing on the type itself or in package docs. | -| 18 | `ListServicePrincipalSecrets.pageSize` | model.ts:55 | field | Low | 1 Vague/generic without domain context | Field has no JSDoc at all (unlike `pageToken` which has 4 lines). Inconsistent within the same interface. | -| 19 | `ServicePrincipalSecret` | model.ts:66 | interface | Medium | 12 Duplicate concepts | Structurally identical to `CreateServicePrincipalSecretResponse` (see #7). Two names for one shape. | -| 20 | `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` | model.ts:68, 70, 72, 78 | field | Medium | 1 Vague/generic without domain context | Same vague-field issues as the response copy (#8-#11). | -| 21 | `Client` | client.ts:42 | class | Medium | 1 Vague/generic without domain context | Top-level `Client` with no qualifier. Once two Databricks clients are imported in the same module, every one is just `Client`. Should be `ServicePrincipalSecretsProxyClient` or aliased on export. | -| 22 | `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` | client.ts:72, 101, 129 | method | Medium | 7 Overly verbose | Inside a class named `Client` (let alone a class that should be `ServicePrincipalSecretsClient`), repeating `ServicePrincipalSecret` in every method name is stutter. `create(req)` / `delete(req)` / `list(req)` would read cleanly. | -| 23 | `PACKAGE_SEGMENT` | client.ts:37 | const | Low | 1 Vague/generic without domain context | Used only to assemble the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` makes the call site self-explanatory. | +_None._ --- ## High severity (must fix) -### H1. Whole-package duplication: `serviceprincipalsecretsproxy` vs `serviceprincipalsecrets` - -The two packages are **byte-identical** for every v1 source file: - -``` -0ba0e7b4804049f95901c6ab28544f4c serviceprincipalsecretsproxy/src/v1/client.ts -0ba0e7b4804049f95901c6ab28544f4c serviceprincipalsecrets/src/v1/client.ts - -646849b8cf7ab85f40ddf9b739edfada serviceprincipalsecretsproxy/src/v1/index.ts -646849b8cf7ab85f40ddf9b739edfada serviceprincipalsecrets/src/v1/index.ts - -f9014e9e042313f049de187a2cd772d1 serviceprincipalsecretsproxy/src/v1/model.ts -f9014e9e042313f049de187a2cd772d1 serviceprincipalsecrets/src/v1/model.ts - -0a0a7cd6d9c9e2d5424595de5ffb3630 serviceprincipalsecretsproxy/src/v1/utils.ts -0a0a7cd6d9c9e2d5424595de5ffb3630 serviceprincipalsecrets/src/v1/utils.ts -``` - -Same seven exported types -(`CreateServicePrincipalSecret`, -`CreateServicePrincipalSecretResponse`, -`DeleteServicePrincipalSecret`, -`DeleteServicePrincipalSecret_Response`, -`ListServicePrincipalSecrets`, -`ListServicePrincipalSecrets_Response`, -`ServicePrincipalSecret`), same client methods (`createServicePrincipalSecret`, -`deleteServicePrincipalSecret`, `listServicePrincipalSecrets`), same URL path -(`/api/2.0/accounts//servicePrincipals//credentials/secrets`). - -The user instruction calls out: *"Pay extra attention: the 'proxy' variant -should be flagged for being a duplicate of `serviceprincipalsecrets`."* -Confirmed in the strongest possible way — there is literally no code-level -difference. The only thing distinguishing the two packages is the npm name -(`@databricks/sdk-serviceprincipalsecrets` vs -`@databricks/sdk-serviceprincipalsecretsproxy`). Either: - -- Merge the two packages, or -- Surface the proxy semantics in the types/URL (`ProxyClient`, a different - path, additional fields). - -Until that is done, every consumer must guess which package to import; once -imported, the symbols collide on re-export. - -### H2. `servicePrincipal: string` is an ID, not the principal - -```ts -export interface CreateServicePrincipalSecret { - servicePrincipal?: string | undefined; // JSDoc: "The service principal ID." -} -``` - -Same field appears in `DeleteServicePrincipalSecret` (model.ts:35) and -`ListServicePrincipalSecrets` (model.ts:48). The field's name asserts the -value is a `ServicePrincipal` object but it is actually an ID string. This is -also internally inconsistent with `DeleteServicePrincipalSecret.secretId` -(model.ts:38) — same file, one ID field has `Id`, another doesn't. - -Rename to `servicePrincipalId` everywhere. +_None._ --- ## Medium severity (worth pushing back on) -### M1. Request types lack the `Request` suffix - -Every input payload in this package is named as a verb phrase, not a payload: - -- `CreateServicePrincipalSecret` (model.ts:6) -- `DeleteServicePrincipalSecret` (model.ts:32) -- `ListServicePrincipalSecrets` (model.ts:44) - -Most of the rest of the Databricks SDK uses a `*Request` suffix for input -payloads (e.g. `GetRuleSetRequest` in `accountaccesscontrol`). The -`*Response` siblings here use the suffix; only the request side omits it. -Suggested: `CreateServicePrincipalSecretRequest`, -`DeleteServicePrincipalSecretRequest`, -`ListServicePrincipalSecretsRequest`. - -### M2. `CreateServicePrincipalSecretResponse` and `ServicePrincipalSecret` are duplicates - -```ts -export interface CreateServicePrincipalSecretResponse { - id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? -} - -export interface ServicePrincipalSecret { - id?, secret?, secretHash?, createTime?, updateTime?, status?, expireTime? -} -``` - -Seven fields each, same names, same JSDoc, same wire decoders. Reduce to one -type or `type CreateServicePrincipalSecretResponse = ServicePrincipalSecret`. - -### M3. `id` and `secret` are vague - -`ServicePrincipalSecret.id` is the secret's ID; rename to `secretId`. -`ServicePrincipalSecret.secret` is the secret's value; rename to `secretValue`. -The current shape forces every callsite to read -`secret.secret` and `secret.id`, which is unhelpful. - -### M4. `status: string` is an undocumented enum - -The field is typed as a free-form string but is almost certainly an enum on -the server side (`ACTIVE` / `EXPIRED` / `REVOKED` is the typical pattern for -secret lifecycle). The TS surface gives callers no discoverability — no enum, -no JSDoc enumeration of values, no link to backend docs. - -### M5. `createTime` / `updateTime` are `string` while `expireTime` is `Temporal.Instant` - -```ts -createTime?: string | undefined; -updateTime?: string | undefined; -expireTime?: Temporal.Instant | undefined; -``` - -Wire format is the same ISO-8601 timestamp for all three. The typing -asymmetry forces callers to handle three timestamps three different ways. Pick -one (presumably `Temporal.Instant`) and apply consistently. - -### M6. `Client` is unqualified - -```ts -export class Client { ... } -``` - -A consumer that imports `{Client}` from `@databricks/sdk-serviceprincipalsecretsproxy` -*and* from `@databricks/sdk-serviceprincipalsecrets` *and* from -`@databricks/sdk-accountaccesscontrol` has to alias every one. Export as -`ServicePrincipalSecretsProxyClient` or rely on namespace imports. - -### M7. Method names stutter - -```ts -class Client { - createServicePrincipalSecret(req, ...) - deleteServicePrincipalSecret(req, ...) - listServicePrincipalSecrets(req, ...) -} -``` - -The receiver is already the secrets client. Methods could be `create`, -`delete`, `list`. Even keeping the long names, the consistent stutter is -worth flagging since the package name is already 33 characters. +_None._ --- ## Low severity (nits) -### L1. `lifetime` is generic - -`CreateServicePrincipalSecret.lifetime: Temporal.Duration` — `secretLifetime` -or `ttl` would make the call site self-documenting. - -### L2. `secretHash` does not name the algorithm - -The wire field is `secret_hash` and the doc is "Secret Hash". Callers cannot -verify hashes without knowing the algorithm (almost certainly SHA-256 given -Databricks norms, but the SDK does not say). - -### L3. `PACKAGE_SEGMENT` - -Used only for the User-Agent header. Rename to -`USER_AGENT_PACKAGE_SEGMENT` so the call site -(`createDefault().with(PACKAGE_SEGMENT)` → `.with(USER_AGENT_PACKAGE_SEGMENT)`) -is self-explanatory. - -### L4. `HttpCallOptions` - -Internal `interface` with `{request, httpClient, logger}`. Generic name. If -it ever leaks beyond `utils.ts`, `ExecuteHttpCallParams` would self-document. -(This shape and name is shared verbatim with sibling packages — generator-wide.) - -### L5. `flattenQueryParams` exported but never imported - -`utils.ts:123` exports `flattenQueryParams`. `client.ts` builds query strings -inline via `URLSearchParams` (client.ts:134-141). Either: -- Use it (current inline code reproduces a subset of its logic), or -- Remove it (dead code). - -### L6. `req` parameter naming in client methods - -Every public method uses `req: ` — Go-idiom. TS conventions -prefer `request` or `params`. Stylistic only. - -### L7. `pageToken` JSDoc is enormous - -```ts -/** - * An opaque page token which was the `next_page_token` in the response of - * the previous request to list the secrets for this service principal. - * Provide this token to retrieve the next page of secret entries. - * When providing a `page_token`, all other parameters provided to the - * request must match the previous request. - * To list all of the secrets for a service principal, it is necessary to - * continue requesting pages of entries until the response contains no - * `next_page_token`. Note that the number of entries returned must not be - * used to determine when the listing is complete. - */ -pageToken?: string | undefined; -``` - -A four-sentence pagination contract attached to a single field. `pageSize` -on the very next line has zero JSDoc. Move the contract to the type-level -JSDoc or package docs; keep the field-level note short. - -### L8. `accountId` in path templates falls back silently - -```ts -const url = `${this.host}/api/2.0/accounts/${req.accountId ?? this.accountId ?? ''}/servicePrincipals/${req.servicePrincipal ?? ''}/credentials/secrets`; -``` - -If neither `req.accountId` nor `this.accountId` is provided, the URL is -emitted with an empty segment — a 404-bound HTTP call rather than an SDK -validation error. Not a naming issue per se, but a result of the underspecified -`accountId` field. (Same pattern across all sibling packages.) +_None._ --- ## Observations (not flags) -- **Generator marker:** Every file is prefixed with `// Code generated from - API definition by Databricks SDK Generator. DO NOT EDIT.`, so all - naming issues must be fixed upstream in the generator / OpenAPI spec. -- **No enums.** The package has zero enum types, so categories 2 (redundant - enum prefixes) and 18 (long enum values) do not apply. The `status` field - (#11/#20) is a likely enum that was generated as a free-form string. -- **No `Url`/`URL`, `Sql`, `Json`, `Oauth` casing collisions.** `accountId` - (camelCase) and `secretId` are the only acronyms in the public surface. -- **No reserved-word collisions** — no `delete`, `class`, `new`, etc. as - field names. Note `Client.deleteServicePrincipalSecret` is a method - (not a field) so `delete` is not a collision here. -- **Optionality model:** every field is `T | undefined`. Matches the rest of - the SDK and `exactOptionalPropertyTypes`. No issue. -- **Versioning:** only `v1` exists; nothing to compare across versions. -- **Tests:** there is no `tests/` directory; `package.json` declares - `"test": "echo 'no tests'"`. -- **`index.ts` re-export style:** All seven types are re-exported as - `export type {...}`, which is correct under `verbatimModuleSyntax`. - There is a stray `export {} from './model';` (index.ts:5) — a no-op - re-export that does nothing. Either dead code or generator residue. -- **`Client` constructor throws plain `Error`** for missing `host` - (client.ts:55-57). Consistent with sibling packages, but not a naming - concern. +_None._ --- -## Domain glossary (as inferred from this code) - -| Term | Meaning in this package | -|------|-------------------------| -| **Account ID** | The numeric Databricks account identifier (path parameter ``). | -| **Service principal** | Modeled as a string ID field (`servicePrincipal: string`) — the field name asserts an object but the value is the SP's ID. | -| **Secret** | An OAuth client secret bound to a service principal. Has an `id`, a one-time-visible `secret` value, a `secretHash`, lifecycle timestamps (`createTime`, `updateTime`, `expireTime`), and a `status`. | -| **Lifetime** | Server-side TTL for a newly-created secret, supplied as a `Temporal.Duration`; default is 730 days when omitted. | -| **Status** | Free-form string on the TS side; presumed to be an enum on the server (likely `ACTIVE` / `EXPIRED` / `REVOKED`). | -| **Secret hash** | Server-computed digest of the secret value; algorithm not stated by the SDK. | -| **Page token** | Opaque continuation cursor returned as `nextPageToken` and sent back as `pageToken`. | -| **Proxy** | Not visible anywhere in the API surface — the package name is the only signal. See H1. | - ---- - -## File coverage - -| File | Lines | Exports counted | Audited | -|------|-------|-----------------|---------| -| `src/v1/model.ts` | 162 | 7 interfaces, 5 zod consts | yes | -| `src/v1/client.ts` | 181 | 1 class, 3 public methods | yes | -| `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | -| `src/v1/index.ts` | 15 | 1 class re-export, 7 type re-exports, 1 no-op `export {}` | yes | - -Every type, field, enum value (none), and method enumerated above is -accounted for. +## Fixed + +- #1 package `serviceprincipalsecretsproxy` (originally cited at package level): Fixed in regeneration on 2026-05-20 — entire `src/` tree removed; package no longer exists in source. +- #2 package `serviceprincipalsecretsproxy` (originally cited at package level): Fixed in regeneration on 2026-05-20 — package removed entirely; long undelimited name is gone. +- #3 package `serviceprincipalsecretsproxy` (originally cited at package level): Fixed in regeneration on 2026-05-20 — misleading "proxy" suffix gone with the package. +- #4 `CreateServicePrincipalSecret` (originally cited at model.ts:6): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. +- #5 `CreateServicePrincipalSecret.servicePrincipal` (originally cited at model.ts:10): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #6 `CreateServicePrincipalSecret.lifetime` (originally cited at model.ts:12): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #7 `CreateServicePrincipalSecretResponse` (originally cited at model.ts:15): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. +- #8 `CreateServicePrincipalSecretResponse.id` (originally cited at model.ts:17): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #9 `CreateServicePrincipalSecretResponse.secret` (originally cited at model.ts:19): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #10 `CreateServicePrincipalSecretResponse.secretHash` (originally cited at model.ts:21): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #11 `CreateServicePrincipalSecretResponse.status` (originally cited at model.ts:27): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #12 `CreateServicePrincipalSecretResponse.createTime` / `updateTime` (originally cited at model.ts:23, 25): Fixed in regeneration on 2026-05-20 — source file removed; fields no longer exist. +- #13 `CreateServicePrincipalSecretResponse.expireTime` (originally cited at model.ts:29): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #14 `DeleteServicePrincipalSecret` (originally cited at model.ts:32): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. +- #15 `DeleteServicePrincipalSecret.secretId` (originally cited at model.ts:38): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #16 `ListServicePrincipalSecrets` (originally cited at model.ts:44): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. +- #17 `ListServicePrincipalSecrets.pageToken` (originally cited at model.ts:54): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #18 `ListServicePrincipalSecrets.pageSize` (originally cited at model.ts:55): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. +- #19 `ServicePrincipalSecret` (originally cited at model.ts:66): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. +- #20 `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` (originally cited at model.ts:68, 70, 72, 78): Fixed in regeneration on 2026-05-20 — source file removed; fields no longer exist. +- #21 `Client` (originally cited at client.ts:42): Fixed in regeneration on 2026-05-20 — source file removed; class no longer exists. +- #22 `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` (originally cited at client.ts:72, 101, 129): Fixed in regeneration on 2026-05-20 — source file removed; methods no longer exist. +- #23 `PACKAGE_SEGMENT` (originally cited at client.ts:37): Fixed in regeneration on 2026-05-20 — source file removed; constant no longer exists. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index e6b6f747..2c55c12f 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 **Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). -**Total weird names flagged:** 87 +**Total weird names flagged:** 84 --- @@ -31,97 +31,87 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | 1 | Critical | Vague package name | `settings` (package) | package level | | 2 | Critical | Duplicate concept (4-package overlap) | `settings` vs `accountsettings` vs `workspacesettings` vs `workspaceconf` | package level | | 3 | Critical | Duplicated TS identifier across packages | `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage` | `model.ts:88-100,102,288,294,98,171,414,284` (and the workspacesettings dup) | -| 4 | High | Vague/generic type | `Setting` | `model.ts:297` | -| 5 | High | Vague/generic type | `SettingsMetadata` | `model.ts:396` | -| 6 | High | Vague/generic type | `UserPreference` | `model.ts:424` | -| 7 | High | Redundant enum prefix | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | -| 8 | High | Redundant enum prefix | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | -| 9 | High | Redundant enum prefix | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | -| 10 | High | Redundant enum prefix | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | -| 11 | High | Redundant enum prefix | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | -| 12 | High | Redundant enum prefix | `STATUS_UNSPECIFIED` | `model.ts:75` | -| 13 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:98-103, 171, 284, 288, 414` | -| 14 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | -| 15 | High | Cryptic abbreviation (undefined) | `Gov` in `disableGovTagCreation` | `model.ts:294` | -| 16 | High | Generic field name | `value` (on `BooleanMessage`, `IntegerMessage`, `StringMessage`, `PersonalComputeMessage`) | `model.ts:99, 172, 285, 416` | -| 17 | High | Generic field name | `name` (across `Setting`, `SettingsMetadata`, `UserPreference`, `GetPublicAccountSettingRequest`, ...) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | -| 18 | High | Generic field name | `type?: string` on `SettingsMetadata` | `model.ts:402` | -| 19 | High | Generic field name | `setting?: Setting` on update requests | `model.ts:266, 275, 281` | -| 20 | High | Generic field name | `setting?: UserPreference` (note: type is UserPreference, field name is `setting`) | `model.ts:275` | -| 21 | High | Generic discriminator value | `booleanVal`, `stringVal`, `integerVal` | `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` | -| 22 | High | Generic discriminator value | `effectiveBooleanVal`, `effectiveStringVal`, `effectiveIntegerVal` | `model.ts:354, 359, 364, 444, 445` | -| 23 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:153, 159, 177, 206, 264, 271` | -| 24 | High | Underspecified ID | `userId` | `model.ts:161, 208, 273, 428` | -| 25 | High | Misleading type name | `UserPreference` field named `setting` (on PatchPublicAccountUserPreferenceRequest) | `model.ts:275` | -| 26 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:303, 305, 351, 352` | -| 27 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:288` | -| 28 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:102` | -| 29 | High | Verb-tense | `disableGovTagCreation` (imperative verb as state field) | `model.ts:294` | -| 30 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | -| 31 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:152, 157, 166, 262, 269, 278`; `client.ts:83, 112, 137, 346, 378, 409` | -| 32 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | -| 33 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | -| 34 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | -| 35 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:225` | -| 36 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:204` | -| 37 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:269` | -| 38 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:194, 196`; `client.ts:166` | -| 39 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:225-227`; `client.ts:226` | -| 40 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:252-254` | -| 41 | Medium | Overly verbose | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` (when accessed as enum member) | `model.ts:13` | -| 42 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | -| 43 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | -| 44 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:294` | -| 45 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:322` | -| 46 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:337` | -| 47 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:104` | -| 48 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:148-149` | -| 49 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:369` | -| 50 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:374` | -| 51 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:379` | -| 52 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:384` | -| 53 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:389` | -| 54 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:411` | -| 55 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:404` | -| 56 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:398` | -| 57 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:404`; `utils.ts:69, 71, 100, 103` | -| 58 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:107` | -| 59 | Low | Long enum value | `PREVIEW_PHASE_UNSPECIFIED` | `model.ts:13` | -| 60 | Low | Long enum value | `ACCESS_POLICY_TYPE_UNSPECIFIED` | `model.ts:31` | -| 61 | Low | Long enum value | `DAY_OF_WEEK_UNSPECIFIED` | `model.ts:39` | -| 62 | Low | Long enum value | `WEEK_DAY_FREQUENCY_UNSPECIFIED` | `model.ts:51` | -| 63 | Low | Long enum value | `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` | `model.ts:67` | -| 64 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | -| 65 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | -| 66 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | -| 67 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:79` | -| 68 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:79` | -| 69 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:79, 83` | -| 70 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:79` | -| 71 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:99, 172, 285, 305, 416, 434` | -| 72 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:402` | -| 73 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` | -| 74 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:153, 161, ...` | -| 75 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | -| 76 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:275` | -| 77 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:624, 959` | -| 78 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | -| 79 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:172` | -| 80 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:305, 99` | -| 81 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:327-329` | -| 82 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:374` | -| 83 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:103` | -| 84 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:137` | -| 85 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:289` | -| 86 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | -| 87 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:160-161` | -| 88 | Low | Empty default | `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED = 'PREVIEW_PHASE_UNSPECIFIED'` doc says unset-OR-not-a-preview (two distinct meanings) | `model.ts:12-13` | -| 89 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:121` | -| 90 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:123` | -| 91 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:125` | -| 92 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | -| 93 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | -| 94 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | +| 4 | High | Vague/generic type | `Setting` | `model.ts:305` | +| 5 | High | Vague/generic type | `SettingsMetadata` | `model.ts:424` | +| 6 | High | Vague/generic type | `UserPreference` | `model.ts:452` | +| 7 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:102, 106, 175, 292, 296, 442` | +| 8 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | +| 9 | High | Cryptic abbreviation (undefined) | `Gov` in `disableGovTagCreation` | `model.ts:302` | +| 10 | High | Generic field name | `value` (on `BooleanMessage`, `IntegerMessage`, `StringMessage`, `PersonalComputeMessage`) | `model.ts:103, 176, 293, 444` | +| 11 | High | Generic field name | `name` (across `Setting`, `SettingsMetadata`, `UserPreference`, `GetPublicAccountSettingRequest`, ...) | `model.ts:158, 167, 172, 273, 282, 288, 307, 426, 454` | +| 12 | High | Generic field name | `type?: string` on `SettingsMetadata` | `model.ts:430` | +| 13 | High | Generic field name | `setting?: Setting` on update requests | `model.ts:274, 283, 289` | +| 14 | High | Generic field name | `setting?: UserPreference` (note: type is UserPreference, field name is `setting`) | `model.ts:283` | +| 15 | High | Generic discriminator value | `booleanVal`, `stringVal`, `integerVal` | `model.ts:315, 320, 325, 372, 377, 382, 463-464` | +| 16 | High | Generic discriminator value | `effectiveBooleanVal`, `effectiveStringVal`, `effectiveIntegerVal` | `model.ts:372, 377, 382, 472, 473` | +| 17 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:157, 162, 181, 209, 272, 279` | +| 18 | High | Underspecified ID | `userId` | `model.ts:165, 211, 281, 456` | +| 19 | High | Misleading type name | `UserPreference` field named `setting` (on PatchPublicAccountUserPreferenceRequest) | `model.ts:283` | +| 20 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:311, 313, 369, 370` | +| 21 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:296` | +| 22 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:106` | +| 23 | High | Verb-tense | `disableGovTagCreation` (imperative verb as state field) | `model.ts:302` | +| 24 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | +| 25 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` | +| 26 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | +| 27 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | +| 28 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | +| 29 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:229` | +| 30 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:208` | +| 31 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:277` | +| 32 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:198, 200`; `client.ts:166` | +| 33 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:229-231`; `client.ts:226` | +| 34 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:256-258` | +| 35 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | +| 36 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | +| 37 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:302` | +| 38 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:330` | +| 39 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:345` | +| 40 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:108` | +| 41 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:152-153` | +| 42 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:387` | +| 43 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:392` | +| 44 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:397` | +| 45 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:402` | +| 46 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:407` | +| 47 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:439` | +| 48 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:432` | +| 49 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:426` | +| 50 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:432`; `utils.ts:70, 98, 103` | +| 51 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:111` | +| 52 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | +| 53 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | +| 54 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | +| 55 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:78` | +| 56 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:78` | +| 57 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:78, 83` | +| 58 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:78` | +| 59 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:103, 176, 293, 313, 444, 462` | +| 60 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:430` | +| 61 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:158, 167, 172, 273, 282, 288, 307, 426, 454` | +| 62 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:157, 165, ...` | +| 63 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | +| 64 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:283` | +| 65 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:670, 1059` | +| 66 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | +| 67 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:176` | +| 68 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:313, 103` | +| 69 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:335-337` | +| 70 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:392` | +| 71 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:107` | +| 72 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:141` | +| 73 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:297` | +| 74 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | +| 75 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:164-165` | +| 76 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:125` | +| 77 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:127` | +| 78 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:129` | +| 79 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | +| 80 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | +| 81 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | +| 82 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` | +| 83 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:98, 497, 928` | +| 84 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #25 as a proto-leak category) | `model.ts:156, 161, 170, 270, 277, 286` | --- @@ -155,159 +145,170 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ### 4. `Setting` — extreme generic risk -- **File:line:** `model.ts:297-394` +- **File:line:** `model.ts:305-422` - **Category:** Vague/generic, reserved-word risk - **Suggestion:** `UnifiedSetting`, `SettingValue`, or `KeyedSetting`. The Setting concept here is "a name plus a polymorphic value plus a polymorphic effective value" — none of those properties match the bare word "Setting" without context. - **Rationale:** `Setting` is one of the most overloaded single words in software (UI settings, settings menu, settings file, configuration setting, etc.). Inside a "settings" package, the type `Setting` reads like "the thing this package is about" — but the package has three other top-level types (`UserPreference`, `SettingsMetadata`, and the wrapper messages). The bare name encourages a `import {Setting}` that competes with React UI `Setting` types, Node `process.config` settings, etc. ### 5. `SettingsMetadata` — plural type, singular use -- **File:line:** `model.ts:396-412` +- **File:line:** `model.ts:424-440` - **Category:** Vague + singular/plural mismatch - **Suggestion:** `SettingMetadata` (singular). The type describes metadata about *one* setting; lists are `SettingMetadata[]`. The current `SettingsMetadata` reads as "all metadata about all settings" which is what the *array* of these things represents — not the element. -- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:196`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). +- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:200`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). ### 6. `UserPreference` — vague + collides with `Setting` -- **File:line:** `model.ts:424-447` +- **File:line:** `model.ts:452-475` - **Category:** Vague/generic -- **Suggestion:** Either fold into `Setting` (since the structure differs only in which `$case` payloads are allowed) or rename to `UserSetting` for parallelism with the package theme. The doc comment at `model.ts:419-423` already says "user-specific setting scoped to an individual user" — the word "preference" then competes with "setting" for the same concept. +- **Suggestion:** Either fold into `Setting` (since the structure differs only in which `$case` payloads are allowed) or rename to `UserSetting` for parallelism with the package theme. The doc comment at `model.ts:447-451` already says "user-specific setting scoped to an individual user" — the word "preference" then competes with "setting" for the same concept. - **Rationale:** Three top-level structural types — `Setting`, `UserPreference`, `SettingsMetadata` — that all model "name + value(s)" with slightly different shapes. A user reading just type names cannot predict which to use. -### 7–12. Redundant enum prefixes ("X_X_UNSPECIFIED" pattern) +### 7. `*Message` suffix — Go/proto-style -- **File:line:** `model.ts:13, 31, 39, 51, 67, 75` -- **Category:** Redundant enum prefix -- **Identifiers:** - - `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` - - `ACCESS_POLICY_TYPE_UNSPECIFIED` - - `DAY_OF_WEEK_UNSPECIFIED` - - `WEEK_DAY_FREQUENCY_UNSPECIFIED` - - `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` - - `STATUS_UNSPECIFIED` -- **Suggestion:** Just `UNSPECIFIED` everywhere — the enum identifier already conveys scope. `PreviewPhase.UNSPECIFIED` reads better than `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED`. -- **Rationale:** The prefix duplicates the enum name — `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` mentions "preview phase" three times. This is a proto3 wire artefact (proto3 requires enum values to be globally unique within a `.proto` file). TypeScript enums are namespaced; the prefix adds zero disambiguation. `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` is especially egregious — five words to mean "default". - -### 13. `*Message` suffix — Go/proto-style - -- **File:line:** `model.ts:98, 102, 171, 284, 288, 414` +- **File:line:** `model.ts:102, 106, 175, 292, 296, 442` - **Category:** Suffix tautology / Go-style - **Identifiers:** `BooleanMessage`, `ClusterAutoRestartMessage`, `IntegerMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`, `StringMessage`, and the workspacesettings duplicates. - **Suggestion:** Drop `Message`. Rename `ClusterAutoRestartMessage → ClusterAutoRestart`, `RestrictWorkspaceAdminsMessage → RestrictWorkspaceAdmins`, etc. The "Message" suffix is the protobuf convention for "everything is a Message"; in TS where "everything is an interface", the suffix is noise. - **Rationale:** No other TS-idiomatic SDK uses `*Message` as a suffix. The classes are not messages in any TS-visible sense (they don't extend a `Message` base, they have no serialization methods — the marshal/unmarshal functions are external). -### 14. `Aibi` — undefined cryptic abbreviation (AI/BI) +### 8. `Aibi` — undefined cryptic abbreviation (AI/BI) -- **File:line:** `model.ts:30, 88, 94, 327-329, 374` and method-name appearances in `client.ts` +- **File:line:** `model.ts:30, 88, 94, 335-337, 392` and method-name appearances in `client.ts` - **Category:** Cryptic abbreviation, acronym casing - **Suggestion:** `AIBI` (acronym casing) or spell out `AiBi` for the AI/BI Genie embedding feature. Add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." - **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. -### 15. `Gov` in `disableGovTagCreation` — undocumented abbreviation +### 9. `Gov` in `disableGovTagCreation` — undocumented abbreviation -- **File:line:** `model.ts:294` +- **File:line:** `model.ts:302` - **Category:** Cryptic abbreviation - **Suggestion:** `disableGovernanceTagCreation`. The full word adds five characters and removes ambiguity (`Gov` could be government, governance, governor, ...). -- **Rationale:** The doc says "workspace admins cannot create governance tags" — so "Gov" abbreviates "Governance". The wire key is `disable_gov_tag_creation` (`model.ts:624`), but the TS surface can be more verbose. +- **Rationale:** The doc says "workspace admins cannot create governance tags" — so "Gov" abbreviates "Governance". The wire key is `disable_gov_tag_creation` (`model.ts:670`), but the TS surface can be more verbose. -### 16. `value` field everywhere — generic field name +### 10. `value` field everywhere — generic field name -- **File:line:** `model.ts:99, 172, 285, 416` on the message wrappers; `model.ts:305, 434` on the discriminated unions; nested deep inside (`Setting.value.booleanVal.value`). +- **File:line:** `model.ts:103, 176, 293, 444` on the message wrappers; `model.ts:313, 462` on the discriminated unions; nested deep inside (`Setting.value.booleanVal.value`). - **Category:** Generic field name + reserved-word adjacency - **Suggestion:** For the discriminated unions (`Setting.value`), `payload` would be slightly clearer. - **Rationale:** `setting.value.booleanVal.value` is four levels of `.value`/`.someVal` indirection to access one boolean. The naming makes auto-complete useless. `value` is a member of many JS built-ins (Map entries, Symbol.iterator results, DOM events, IndexedDB cursors), so it has soft reserved-word risk. -### 17. `name` everywhere — generic field name +### 11. `name` everywhere — generic field name -- **File:line:** `model.ts:153, 163, 168, 265, 274, 280, 299, 398, 426` +- **File:line:** `model.ts:158, 167, 172, 273, 282, 288, 307, 426, 454` - **Category:** Generic field name - **Suggestion:** `settingKey` or `settingName` would convey purpose. The current `name` is so generic the JSDoc has to repeat "Name of the setting" everywhere. - **Rationale:** The field is in fact the *key* — the unique identifier used in the URL path (`/settings/${req.name ?? ''}`) — not a human display name. The actual display name is `displayName` on `SettingsMetadata`. Naming the key "name" and the human name "displayName" inverts intuition (typically "name" is the display name and "id"/"key" is the identifier). -### 18. `type?: string` on `SettingsMetadata` — generic + misleading +### 12. `type?: string` on `SettingsMetadata` — generic + misleading -- **File:line:** `model.ts:402` +- **File:line:** `model.ts:430` - **Category:** Generic field name, reserved-word adjacency, misleading - **Suggestion:** `valueTypeMessage` or `sampleTypeMessage`. The JSDoc says "Sample message depicting the type of the setting. To set this setting, the value sent must match this type." - **Rationale:** A field called `type` returning a *sample message* (not a type-id or schema URI) is misleading. Combined with the JS-builtin overlap (`typeof obj.type === 'string'`), the field name invites confusion. -### 19–20. `setting?: Setting` and `setting?: UserPreference` — generic field name + misleading +### 13–14. `setting?: Setting` and `setting?: UserPreference` — generic field name + misleading -- **File:line:** `model.ts:266, 275, 281` +- **File:line:** `model.ts:274, 283, 289` - **Category:** Generic field name + misleading - **Suggestion:** Rename to match the typed payload: `setting?: Setting` is okay; `setting?: UserPreference` is wrong — should be `userPreference?: UserPreference`. - **Rationale:** On `PatchPublicAccountUserPreferenceRequest`, the field is named `setting` but typed `UserPreference`. The whole package's distinction between "setting" and "user preference" depends on these being separate concepts — so calling the user-preference field "setting" undoes that distinction at the request level. -### 21–22. `booleanVal`, `stringVal`, `integerVal`, `effective*Val` — generic discriminator values +### 15–16. `booleanVal`, `stringVal`, `integerVal`, `effective*Val` — generic discriminator values -- **File:line:** `model.ts:307, 312, 317, 354, 359, 364, 435-436, 444-445` +- **File:line:** `model.ts:315, 320, 325, 372, 377, 382, 463-464, 472-473` - **Category:** Generic field name - **Suggestion:** Drop the `*Val` suffix (it duplicates the parent field `value`) and name by domain: instead of `value: {$case: 'booleanVal', booleanVal: BooleanMessage}`, prefer `value: {kind: 'boolean', boolean: boolean}`. - **Rationale:** A user writing `setting.value?.$case === 'booleanVal'` then accessing `setting.value.booleanVal.value` does three discriminations to read a single bool. The "Val" abbreviation is the only naming variation between the discriminator tag ("booleanVal") and the type name ("BooleanMessage"); the abbreviation contributes nothing. -### 23–24. `accountId`, `userId` — underspecified IDs +### 17–18. `accountId`, `userId` — underspecified IDs -- **File:line:** `model.ts:153, 159, 161, 177, 206, 208, 264, 271, 273, 428` +- **File:line:** `model.ts:157, 162, 165, 181, 209, 211, 272, 279, 281, 456` - **Category:** Underspecified ID - **Suggestion:** Document the ID format (UUID, opaque-string, numeric, ...) in JSDoc consistently. Currently only some occurrences have a doc (" account ID of the account being managed"), and the format isn't specified anywhere. - **Rationale:** Users have no way to know whether the SDK accepts `"acct-12345"`, `"abc...uuid"`, or an integer-as-string. The Go SDK's pattern of relying on type-level documentation isn't carried over. -### 25. `setting` field on `PatchPublicAccountUserPreferenceRequest` (covered in #20) +### 19. `setting` field on `PatchPublicAccountUserPreferenceRequest` (covered in #14) -### 26. `effectiveValue` vs `value` — undocumented distinction +### 20. `effectiveValue` vs `value` — undocumented distinction -- **File:line:** `model.ts:303-345 (value) vs 351-393 (effectiveValue)` +- **File:line:** `model.ts:311-363 (value) vs 369-421 (effectiveValue)` - **Category:** Misleading -- **Suggestion:** Add a JSDoc explaining the relationship at the `Setting` type level. Currently the distinction is only documented as "The user-set value that goes into storage" (302) vs "The final effective value from server as per the policy evaluation" (350) — a reader has to read both blocks to understand they're a get/set asymmetry. +- **Suggestion:** Add a JSDoc explaining the relationship at the `Setting` type level. Currently the distinction is only documented as "The user-set value that goes into storage" (311) vs "The final effective value from server as per the policy evaluation" (369) — a reader has to read both blocks to understand they're a get/set asymmetry. - **Rationale:** This is a non-obvious feature where the user sets `value` but the server might return a different `effectiveValue` after applying policy. Worth a top-level doc, not just per-block. -### 27–29. Verb-tense action-as-noun naming +### 21–23. Verb-tense action-as-noun naming -- **File:line:** `model.ts:288 (RestrictWorkspaceAdminsMessage), 102 (ClusterAutoRestartMessage), 294 (disableGovTagCreation field)` +- **File:line:** `model.ts:296 (RestrictWorkspaceAdminsMessage), 106 (ClusterAutoRestartMessage), 302 (disableGovTagCreation field)` - **Category:** Verb-tense inconsistency - **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`), `governanceTagCreationDisabled: boolean`. - **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. `disableGovTagCreation` is a verb-phrase as a field name suggesting "do the action of disabling", which is misleading for a boolean state. +### 82. Proto-nested underscore type naming — proto-architectural leak + +- **File:line:** `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` (and the corresponding marshal/unmarshal schema declarations) +- **Category:** Proto-architectural leak (nested-message naming) +- **Why:** Every nested type carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested ... name.` comment — an explicit admission that the TS surface is wearing proto-generated shape. Examples: + - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` + - `ClusterAutoRestartMessage_MaintenanceWindow` + - `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek` + - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency` + - `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` + - `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime` + - `ClusterAutoRestartMessage_EnablementDetails` + - `PersonalComputeMessage_PersonalComputeMessageEnum` + - `RestrictWorkspaceAdminsMessage_Status` +- **Suggestion:** Promote nested message/enum types to top-level TS interfaces with descriptive names: `AccessPolicyType`, `MaintenanceWindow`, `DayOfWeek`, `WeekDayFrequency`, `MaintenanceSchedule`, `WindowStartTime`, `EnablementDetails`, `PersonalComputeMode`, `WorkspaceAdminRestrictionStatus`. Where two top-level names would collide across packages, prefix with the owning concept (e.g., `MaintenanceWindowDayOfWeek`) but never use `_`. +- **Rationale:** Underscore-separated multi-word TS identifiers are non-idiomatic (Google TS style mandates `PascalCase` for types; Microsoft TS handbook agrees). The `*Foo_Bar_Baz` chain is purely a transliteration of proto's nested-message scoping — TS has module namespaces (`Foo.Bar.Baz`) and lexical scoping for that, neither of which is used here. The eslint-disable comments are the smoking gun. + +### 83. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak + +- **File:line:** `model.ts:98, 497 (unmarshal), 928 (marshal)` +- **Category:** Proto-architectural leak (`Api` mid-position) + `*Message` suffix (covered in #7) +- **Why:** `Api` appears mid-name in a domain type that models *what user-OAuth scopes apps may be granted*. The "Api" half describes the **wire/proto** medium ("user-API scopes") rather than the domain concept (OAuth scopes). +- **Suggestion:** `AllowedAppsUserScopes` (drop `Api`, drop `Message`). The discriminator value `allowedAppsUserApiScopes` and wire key `allowed_apps_user_api_scopes` would remain wire-side; the TS surface should not carry the proto-medium descriptor. +- **Rationale:** The combined `Api` + `Message` pair carries two architectural-leak tokens in a single identifier (60 chars including `Schema` in the marshal/unmarshal forms). `Api` mid-position falls squarely in the prompt's flag list. + --- ## Medium severity -### 30. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use +### 24. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use - **File:line:** `model.ts:94-96` - **Category:** Singular/plural mismatch - **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. -### 31. `*Public*` qualifier — redundant +### 25. `*Public*` qualifier — redundant -- **File:line:** `model.ts:152, 157, 166, 262, 269, 278` +- **File:line:** `model.ts:156, 161, 170, 270, 277, 286` - **Category:** Redundant qualifier -- **Suggestion:** Drop `Public` from request type names (and method names — #32). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Suggestion:** Drop `Public` from request type names (and method names — #26). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. - **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. -### 32. Method names: `getPublic*`, `patchPublic*` — redundant `Public` +### 26. Method names: `getPublic*`, `patchPublic*` — redundant `Public` - **File:line:** `client.ts:83, 112, 137, 346, 378, 409` - **Category:** Redundant qualifier + verbose - **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. -### 33. `patch*` vs `update*` — inconsistent action verb across SDK +### 27. `patch*` vs `update*` — inconsistent action verb across SDK - **File:line:** `client.ts:346, 378, 409` (use `patch`) - **Category:** Inconsistent action verbs - **Suggestion:** Pick one verb. `update` is the verb in `accountsettings/v1/client.ts` and `workspacesettings/v1/client.ts` for the equivalent operation; `patch` is used here. Cross-package consistency matters. - **Rationale:** Same operation (PATCH HTTP verb against a settings endpoint) named `update*` in the v1 packages and `patch*` in this v2 package. Users will look for `update*` first based on muscle memory. -### 34. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action +### 28. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action - **File:line:** `client.ts:378` - **Category:** Inconsistent + verbose - **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. - **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. -### 35–37. Long type names +### 29–31. Long type names -- **File:line:** `model.ts:225, 204, 269` +- **File:line:** `model.ts:229, 208, 277` - **Category:** Overly verbose - **Identifiers:** - `ListAccountUserPreferencesMetadataResponse` (42 chars) @@ -315,193 +316,188 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - `PatchPublicAccountUserPreferenceRequest` (39 chars) - **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. -### 38–40. `settingsMetadata` field name vs sibling list semantics +### 32–34. `settingsMetadata` field name vs sibling list semantics -- **File:line:** `model.ts:194, 196, 225-227, 252-254` +- **File:line:** `model.ts:198, 200, 229-231, 256-258` - **Category:** Singular/plural mismatch + field naming - **Suggestion:** On `ListAccountUserPreferencesMetadataResponse`, the field should be `userPreferencesMetadata`, not `settingsMetadata`. Currently the response field for "list of user preferences" is typed as `SettingsMetadata[]` and named `settingsMetadata` — which is technically the same metadata type but linguistically misleading. - **Rationale:** A consumer reading `resp.settingsMetadata` on a `ListAccountUserPreferencesMetadataResponse` will be confused why "settings" appears on a "user preferences" response. -### 41. `PreviewPhase.PREVIEW_PHASE_UNSPECIFIED` access stutters - -- **File:line:** `model.ts:13` -- **Category:** Overly verbose enum access -- **Suggestion:** See #7–12. - -### 42. `PreviewPhase` enum — mixed temporal/qualitative members +### 35. `PreviewPhase` enum — mixed temporal/qualitative members - **File:line:** `model.ts:11-27` - **Category:** Verb-tense / categorisation inconsistency -- **Members:** `PREVIEW_PHASE_UNSPECIFIED`, `PRIVATE_PREVIEW`, `PUBLIC_PREVIEW`, `BETA`, `GA_SOON`, `GA` +- **Members:** `PRIVATE_PREVIEW`, `PUBLIC_PREVIEW`, `BETA`, `GA_SOON`, `GA` - **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. - **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. -### 43–44. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` +### 36–37. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` -- **File:line:** `model.ts:30, 88, 94, 294` +- **File:line:** `model.ts:30, 88, 94, 302` - **Category:** Acronym casing - **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. -### 45–46. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope +### 38–39. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope -- **File:line:** `model.ts:322 (auto-cluster on a unified Setting), 337 (restrict-admins on Setting)` +- **File:line:** `model.ts:330 (auto-cluster on a unified Setting), 345 (restrict-admins on Setting)` - **Category:** Field contradicting type domain - **Suggestion:** Either drop the `Workspace` suffix from `automaticClusterUpdateWorkspace` (the parent `Setting` type is scope-agnostic) or always include the scope (then `personalCompute` should be `personalComputeAccount`). - **Rationale:** Some payload discriminators mention scope (`automaticClusterUpdateWorkspace`), others don't (`personalCompute`, `restrictWorkspaceAdmins`). A reader can't predict the rule. -### 47. `canToggle?: boolean` on `ClusterAutoRestartMessage` +### 40. `canToggle?: boolean` on `ClusterAutoRestartMessage` -- **File:line:** `model.ts:104` +- **File:line:** `model.ts:108` - **Category:** Generic field - **Suggestion:** `userCanToggle: boolean` or `togglePermitted: boolean`. "Toggle what?" is unclear from the field alone (presumably toggle the `enabled` field, but that's implicit). -### 48. `hours`, `minutes` with no timezone +### 41. `hours`, `minutes` with no timezone -- **File:line:** `model.ts:148-149` +- **File:line:** `model.ts:152-153` - **Category:** Generic field name, missing constraint - **Suggestion:** Add doc specifying the time-zone interpretation, or rename `utcHours`/`utcMinutes` if UTC, or add a `timezone?: string` field. - **Rationale:** A "maintenance window start time" without timezone is ambiguous (workspace TZ? customer TZ? UTC?). -### 49–53. Overly verbose `effective*` discriminator names +### 42–46. Overly verbose `effective*` discriminator names -- **File:line:** `model.ts:369, 374, 379, 384, 389` +- **File:line:** `model.ts:387, 392, 397, 402, 407` - **Category:** Overly verbose - **Suggestion:** Either drop the `effective` prefix on the discriminator value (the parent field is `effectiveValue`, so the prefix is redundant) or split into two top-level discriminated unions (`Setting.value: {$case: 'automaticClusterUpdateWorkspace', ...}` and `Setting.effectiveValue: {$case: 'automaticClusterUpdateWorkspace', ...}`). - **Rationale:** `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) is the longest discriminator in the package and stutters `effective`/`Effective` with its parent field name. -### 54–56. `name` (key) vs `displayName` (human name) — inverted intuition +### 47–49. `name` (key) vs `displayName` (human name) — inverted intuition -- **File:line:** `model.ts:398, 411` +- **File:line:** `model.ts:426, 439` - **Category:** Generic name + misleading - **Suggestion:** Rename `name` → `key`, then `displayName` → `name` (or `label`). - **Rationale:** Across most data-modelling traditions, `name` is the human-readable name and `key`/`id` is the identifier. This package inverts the convention. -### 57. `Url` vs `URL` vs `Link` +### 50. `Url` vs `URL` vs `Link` -- **File:line:** `model.ts:404 (docsLink)`; `utils.ts:69, 71, 100, 103 (url)` +- **File:line:** `model.ts:432 (docsLink)`; `utils.ts:70, 98, 103 (url)` - **Category:** Acronym casing inconsistency - **Suggestion:** `docsUrl` for parity with `request.url` already used elsewhere. "Link" is HTML-flavoured; "URL" is the data. -### 58. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name +### 51. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name -- **File:line:** `model.ts:107` +- **File:line:** `model.ts:111` - **Category:** Field name verb-as-noun, overly verbose - **Suggestion:** `forceRestart: boolean` (the semantics — restart even when not needed for updates). Or `restartOnSchedule: boolean`. - **Rationale:** 31-character field name encoding a clause is awkward; a one-word semantic name reads better. +### 84. `*Public*` qualifier as proto-architectural leak (reframe of #25) + +- **File:line:** `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` +- **Category:** Proto-architectural leak (`Public` mid-position) +- **Why:** `Public` in `GetPublic*Request`, `PatchPublic*Request`, and method names `getPublic*`/`patchPublic*` is a direct echo of the proto service-name `PublicSettingsService` — i.e., the *server-side* internal-vs-public service split. The TS SDK only ships the public surface, so the qualifier signals nothing the user can act on. +- **Suggestion:** Drop `Public` from every request type and every method name. `GetAccountSettingRequest`/`getAccountSetting`, `PatchAccountSettingRequest`/`patchAccountSetting`, etc. +- **Rationale:** This duplicates #25 and #26 but reframes them as a *proto-architectural leak* per the scan brief. `Public`/`Internal` are explicitly on the flag list. The two earlier findings catalogued the names; this one names the cause. + --- ## Low severity -### 59–66. Long enum values +### 52–54. Long enum values -- **File:line:** `model.ts:13, 31, 39, 51, 67, 75, 56, 57, 85` +- **File:line:** `model.ts:85, 56, 57` - **Category:** Long enum value -- **Identifiers:** `PREVIEW_PHASE_UNSPECIFIED` (24c), `ACCESS_POLICY_TYPE_UNSPECIFIED` (30c), `DAY_OF_WEEK_UNSPECIFIED` (23c), `WEEK_DAY_FREQUENCY_UNSPECIFIED` (30c), `PERSONAL_COMPUTE_MESSAGE_ENUM_UNSPECIFIED` (40c), `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) -- **Suggestion:** See #7–12. For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. +- **Identifiers:** `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) +- **Suggestion:** For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. -### 67–70. Undocumented abbreviations in JSDoc +### 55–58. Undocumented abbreviations in JSDoc -- **File:line:** `model.ts:79, 83` +- **File:line:** `model.ts:78, 83` - **Category:** Cryptic abbreviation - **Tokens:** "WS" (workspace), "OBO" (on-behalf-of token), "SPs" (service principals) - **Suggestion:** Spell out in the JSDoc. - **Rationale:** Users reading the IDE tooltip will see "WS admins to create OBO tokens for all SPs" without expansions. -### 71–73. Reserved-word adjacency: `value`, `type`, `name` +### 59–61. Reserved-word adjacency: `value`, `type`, `name` - **File:line:** `model.ts` passim - **Category:** Reserved-word risk -- **Suggestion:** See #16–18. +- **Suggestion:** See #10–12. -### 74–75. Acronym casing notes +### 62–63. Acronym casing notes -- **File:line:** `model.ts:153, 78` +- **File:line:** `model.ts:157, 78` - **Category:** Acronym casing - **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). -### 76. `setting?: UserPreference` doc mismatch +### 64. `setting?: UserPreference` doc mismatch -- Already covered in #20; flagged again here for the JSDoc inconsistency (`model.ts:275` field is "setting" but type is "UserPreference"). +- Already covered in #14; flagged again here for the JSDoc inconsistency (`model.ts:283` field is "setting" but type is "UserPreference"). -### 77. `disable_gov_tag_creation` wire key +### 65. `disable_gov_tag_creation` wire key -- **File:line:** `model.ts:624, 959` +- **File:line:** `model.ts:670, 1059` - **Category:** Cryptic abbreviation (server-controlled) - **Suggestion:** N/A — wire format is fixed. Note for documentation. -### 78. `restrict_tokens_and_job_run_as` enum string value +### 66. `restrict_tokens_and_job_run_as` enum string value - **File:line:** `model.ts:85` - **Category:** Wire value - **Suggestion:** N/A — wire-fixed. -### 79. `IntegerMessage` misleading in JS +### 67. `IntegerMessage` misleading in JS -- **File:line:** `model.ts:171-173` +- **File:line:** `model.ts:175-177` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 80. Nested `.value.value` +### 68. Nested `.value.value` -- **File:line:** `model.ts:305, 99` +- **File:line:** `model.ts:313, 103` - **Category:** Singular naming collision -- **Suggestion:** See #16. +- **Suggestion:** See #10. -### 81–82. Long discriminator strings +### 69–70. Long discriminator strings -- **File:line:** `model.ts:327-329, 374` +- **File:line:** `model.ts:335-337, 392` - **Category:** Long string identifier -- **Suggestion:** See #21, #49–53. +- **Suggestion:** See #15, #42–46. -### 83–85. Vague field names +### 71–73. Vague field names -- **File:line:** `model.ts:103 (enabled), 137 (frequency), 289 (status)` +- **File:line:** `model.ts:107 (enabled), 141 (frequency), 297 (status)` - **Category:** Vague - **Suggestion:** Add domain context: `clusterRestartEnabled`, `restartFrequency`, `workspaceAdminRestrictionStatus`. - **Rationale:** Inside their parent types the meaning is somewhat clear but auto-complete shows only the field name, which is generic. -### 86. `patch*` vs `update*` +### 74. `patch*` vs `update*` -- See #33. +- See #27. -### 87. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" +### 75. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" -- **File:line:** `model.ts:160-161` +- **File:line:** `model.ts:164-165` - **Category:** Misleading - **Suggestion:** Use the same vocabulary as the type — "preference" for user-preference endpoints. -### 88. `PreviewPhase` UNSPECIFIED doc — two meanings +### 76–78. Double-negative / passive booleans on `EnablementDetails` -- **File:line:** `model.ts:12-13` -- **Category:** Empty/ambiguous default -- **Doc:** "Default value. Indicates the preview phase is unknown or the setting is not a feature preview." -- **Suggestion:** Use two separate enum values (one for "unknown phase", one for "not a preview at all") or pick one definition. - -### 89–91. Double-negative / passive booleans on `EnablementDetails` - -- **File:line:** `model.ts:121, 123, 125` +- **File:line:** `model.ts:125, 127, 129` - **Category:** Misleading / cognitive load - **Identifiers:** `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement`, `forcedForComplianceMode` - **Suggestion:** Phrase positively where possible: `availableForEnterpriseTier?: boolean`, `availableForEntitlement?: boolean`, `forceEnabledByComplianceMode?: boolean`. Double-negatives ("unavailable for non-enterprise") slow comprehension. - **Rationale:** "Unavailable for non-enterprise tier" requires the reader to parse two negatives ("un-" and "non-") to conclude "this is only available for enterprise". Worth one extra second of think-time on every field access. -### 92. Cross-package `Dbfs` casing +### 79. Cross-package `Dbfs` casing - **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) - **Category:** Cross-package acronym casing - **Suggestion:** Note for the cross-package audit, not actionable here. -### 93. `host` — generic class field +### 80. `host` — generic class field - **File:line:** `client.ts:54` - **Category:** Generic - **Suggestion:** `baseUrl` (consistent with `fetch` API conventions). "Host" can mean DNS host, host machine, etc. -### 94. `BETA` member adjacent to `PUBLIC_PREVIEW` +### 81. `BETA` member adjacent to `PUBLIC_PREVIEW` -- See #42. +- See #35. --- @@ -564,7 +560,13 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | File | Lines read | Coverage | |------|-----------|----------| -| `src/v2/index.ts` | 42 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | -| `src/v2/model.ts` | 1160 (full) | 100% — 6 enums, 23 interfaces (incl. all nested message types), 15 unmarshal-zod schemas, 15 marshal-zod schemas audited. | +| `src/v2/index.ts` | 44 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | +| `src/v2/model.ts` | 1300 (full) | 100% — 6 enums, 23 interfaces (incl. all nested message types), 15 unmarshal-zod schemas, 15 marshal-zod schemas audited. | | `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor and 9 client methods audited (paginated page-returning and iterator-returning variants both reviewed). Private fields (`host`, `accountId`, `httpClient`, `logger`, `userAgent`) audited. | | `src/v2/utils.ts` | 150 (full) | 100% — `HttpCallOptions`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` audited. Shared utility code; no naming issues unique to this package (the same scaffolding appears in every package). | + +--- + +## Fixed + +_None._ diff --git a/.agent/naming-audit/sharing.md b/.agent/naming-audit/sharing.md new file mode 100644 index 00000000..7841c830 --- /dev/null +++ b/.agent/naming-audit/sharing.md @@ -0,0 +1,202 @@ +# Naming Audit: sharing + +**Path:** `packages/sharing/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Inferred domain:** Delta Sharing — providers, recipients, shares, share +permissions, federation policies, and provider-share asset listing. Models +the cross-metastore Delta Sharing flow: a Databricks data provider exposes +shares (collections of tables/views/volumes/notebooks/functions/models) +to one or more recipients (other Databricks metastores or external OIDC / +token-authenticated clients). +**Total weird names flagged:** 5 + +## Summary + +| Severity | Count | +| --- | --- | +| High | 2 | +| Medium | 2 | +| Low | 1 | +| Observation | 0 | +| **Total** | **5** | + +The audit is narrowly scoped to proto/architectural leaks. The package's +main pattern is a `*Info` "metadata-message" suffix that proto uses to +distinguish a slim identifier message from the populated entity message; +in TS it collapses to redundant type-naming for what is just *the entity*. +The remaining flag is on `PartitionSpecification`, an empty top-level +interface that exists only to namespace its nested proto types. +`DeltaSharing*` (a real product name) and standard `*Request` / `*Response` +end suffixes are not flagged. + +--- + +## High severity (must fix) + +### 1. `*Info` suffix repeated across the core entity surface — `model.ts:739, 774, 845, 902, 331, 358` +- **Why:** Five entity types use the proto-style `*Info` "metadata + message" suffix: `ProviderInfo` (model.ts:739), `RecipientInfo` + (model.ts:774), `RecipientTokenInfo` (model.ts:845), `ShareInfo` + (model.ts:902), and `FunctionParameterInfo` (model.ts:331) plus the + pluralised wrapper `FunctionParameterInfos` (model.ts:358). In every + case the type IS the entity, not metadata *about* the entity — there + is no `Provider` / `Recipient` / `RecipientToken` / `FunctionParameter` + counterpart that `*Info` would document the metadata of. The `Info` + suffix originates from the proto-message convention where the slim + identifier message (`Provider { name }`) and the fat populated + message (`ProviderInfo { name, owner, comment, ... }`) coexist; in + the TS surface only the fat form survives, so the suffix has nothing + to distinguish. +- **Category:** Proto-architecture leak (repeated `Info` suffix across + sibling entity types) +- **Suggested:** Drop the `Info` suffix on the entity types: + `ProviderInfo` → `Provider`, `RecipientInfo` → `Recipient`, + `RecipientTokenInfo` → `RecipientToken`, `ShareInfo` → `Share` (see + finding H2 — collides with the existing slim `Share` type, which is + the actual rename target), `FunctionParameterInfo` → + `FunctionParameter`, `FunctionParameterInfos` → `FunctionParameters` + (or drop the wrapper and inline the array; see finding M2). +- **Rationale:** Sibling packages in this SDK already follow the + unsuffixed convention for the entity (`catalogs.Catalog`, + `schemas.Schema`, `volumes.Volume`, `connections.Connection`, + etc.). The repeated `Info` suffix here breaks that convention and + forces every caller reading the type to wonder whether + `RecipientInfo` is the recipient itself, a sidecar metadata object, + or a server-side projection. It is just the recipient. + +### 2. `Share` (slim stub) coexists with `ShareInfo` (full record) — `model.ts:897` vs `model.ts:902` +- **Why:** Two parallel "the share" types live in the same file: + `Share { name?, id? }` (model.ts:897) is a 2-field identifier stub + used as the `share` slot on `ListProviderShareAssetsResponse` + (model.ts:495), while `ShareInfo` (model.ts:902) is the full record + used by `createShare`, `getShare`, and `listShares`. This is the + proto pattern of having both a slim `Share` "reference" message and + a fat `ShareInfo` "metadata" message for the same logical entity; + in the TS surface a consumer cannot tell from the names which one + to expect at which call site. +- **Category:** Proto-architecture leak (slim-vs-fat duplicate-message + pair for the same entity) +- **Suggested:** Collapse the pair: rename `ShareInfo` → `Share` and + rename the existing 2-field `Share` to `ShareReference` (or drop the + stub entirely and use `{name?: string; id?: string}` inline on + `ListProviderShareAssetsResponse`). After the collapse, the full + record is the canonical `Share` and the surface matches the + `Provider` / `Recipient` rename in finding H1. +- **Rationale:** Two types named after the same noun, sharing two + fields (`name`, `id`), is the most direct form of proto-message + leak. The slim form exists in the wire schema for size optimisation; + in TS the optional fields handle that, and a caller has no use for + a stand-alone two-field stub when the populated form is already a + superset. + +--- + +## Medium severity (worth pushing back on) + +### 1. `PartitionSpecification` empty top-level + nested-only payload — `model.ts:677, 680, 686` +- **Why:** `PartitionSpecification` (model.ts:677) is declared as an + empty interface (`{}` with an eslint-disable for the empty-object + type) whose only role is to host the nested `PartitionSpecification_Partition` + (model.ts:680) and `PartitionSpecification_Partition_PartitionValue` + (model.ts:686) types. The actual array of partitions lives on + `SharedDataObject.partitions: PartitionSpecification_Partition[]` + (model.ts:1023), never on a `PartitionSpecification` value. The + empty top-level + nested-tree shape is a verbatim transcription of + the proto message tree (`PartitionSpecification { repeated Partition + partitions; }`) where the outer message is the namespacing container. +- **Category:** Proto-architecture leak (`Specification`/`Spec` infix + on a namespacing-only type whose root has no payload) +- **Suggested:** Either drop the empty top-level `PartitionSpecification` + and surface `Partition` / `PartitionValue` as flat siblings (with + the `partitions` field on `SharedDataObject` typed as + `Partition[]`), or, if a top-level container is desired, give it + the missing `partitions: Partition[]` field so the name carries + some payload. +- **Rationale:** An empty interface that exists only to namespace its + nested types is a TS-hostile pattern (TS has no nested-namespace + semantics for interfaces — the underscore-flattened names live at + the top level anyway). Removing the empty container exposes the + partition tree at the level it is actually used. + +### 2. `FunctionParameterInfos` single-field array wrapper — `model.ts:358` +- **Why:** `FunctionParameterInfos { parameters?: FunctionParameterInfo[] }` + is a wrapper interface whose only field is the array. It is consumed + exactly once, as the `inputParams: FunctionParameterInfos | undefined` + field on `Function` (model.ts:317). The wrapper exists to give the + proto schema a message type to hang the repeated field on; in TS + it forces every caller to dereference `function.inputParams?.parameters` + instead of `function.inputParams`. Same shape as `DependencyList` + (model.ts:261), which wraps `Dependency[]` as `dependencies`. +- **Category:** Proto-architecture leak (single-field repeated-only + wrapper message — also a duplicated `*Infos` suffix in line with H1) +- **Suggested:** Inline the array: change `Function.inputParams` to + `inputParams?: FunctionParameter[]` (and `Function.dependencyList` + to `dependencies?: Dependency[]`), then delete the wrapper + interfaces. The wire format can keep the nested object via the + marshal/unmarshal transform. +- **Rationale:** The wrapper carries no semantic content — every + consumer must double-dereference. Eliminating the wrapper aligns + the field shape with the way sibling packages model repeated + fields (e.g. `catalogs.Catalog.options: Catalog_Options[]` with no + wrapping `Catalog_OptionsList` type). + +--- + +## Low severity (nits) + +### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:363, 369, client.ts:369` +- **Why:** The method `getActivationUrlInfo` (client.ts:369) returns + `GetActivationUrlInfoRequest_Response`, an empty interface + (model.ts:369). The mid-position `Info` in both the method and the + request type adds nothing semantic: the method just gets the + activation URL data (and currently returns nothing). The naming + inherits the proto RPC name (`GetActivationUrlInfo`) where `Info` + was the message-type variant suffix. +- **Category:** Proto-architecture leak (`Info` mid-position with no + matching payload, repeated-`Info` pattern from H1) +- **Suggested:** Rename to `getActivationUrl` / + `GetActivationUrlRequest` (and drop the `Info` infix). If the + response stays empty, also drop the type per the + `Promise`-vs-empty-interface decision used elsewhere in the + SDK. +- **Rationale:** The mid-`Info` repeats the H1 pattern in a place + where it is provably defunct (no response fields). Removing it + matches the bare `getActivationUrl` shape a reader would write + from first principles. + +--- + +## Observations (not flags) + +_None._ + +--- + +## File coverage + +| File | Lines read | Coverage | +| ---- | ---------- | -------- | +| `src/v1/index.ts` | 93 / 93 | 100% | +| `src/v1/transport.ts` | 75 / 75 | 100% | +| `src/v1/utils.ts` | 150 / 150 | 100% | +| `src/v1/model.ts` | 2354 / 2354 | 100% | +| `src/v1/client.ts` | 1133 / 1133 | 100% | + +All types, fields, enums, methods, and locals reviewed for the +proto/architectural-leak patterns: `Public`/`Internal`/`External` +mid-position, `Proto` suffix/infix, `Service`/`Server`/`Backend`/ +`Frontend`, `Rpc`/`Grpc`, `Manager`/`Handler`/`Controller`/ +`Processor`/`Daemon`/`Worker`, `Impl`, non-real `Proxy`, +mid-position `Action`/`Op` duplicating verbs, `Wrapper`/`Adapter`, +`Old`/`New`/`Legacy`/`Modern`, mid-position `V1`/`V2`, mid-position +`Api`/`Sdk`/`Client`, and repeated `Spec`/`Config`/`Details`/`Info` +suffixes. No `Proxy`, `Impl`, `Manager`, `Handler`, `Controller`, +`Service`, `Server`, `Backend`, `Frontend`, `Rpc`, `Grpc`, +`Processor`, `Daemon`, `Worker`, `Wrapper`, `Adapter`, `Old`, `New`, +`Legacy`, `Modern`, mid-position `V1`/`V2`, mid-position `Api`/`Sdk`/ +`Client`, `Public`/`Internal`/`External` mid-position, or +`Foo_PublicRequest` visibility-infix patterns observed. The +`DeltaSharing*` lexicon (real product name), domain `External*` (in +context-appropriate places), `OAuth*`, `Webhook*`, and standard +`*Request`/`*Response`/`*Schema` end suffixes are not flagged. diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index 5f0c64b8..093e5091 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -28,16 +28,16 @@ The package name `statementexecution` is reasonable in isolation, but the SDK opening the marketplace sees four packages whose names overlap heavily and has to read every one to pick the right tool. See finding #1. -**Total weird names flagged:** 48 +**Total weird names flagged:** 52 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 25 | +| High | 10 | +| Medium | 29 | | Low | 10 | -| Observation | 4 | +| Observation | 3 | ## High severity @@ -54,30 +54,24 @@ to read every one to pick the right tool. See finding #1. - **Rationale:** Per-package error-code enums diverge over time. The SDK already commits to canonical codes elsewhere; this package should use them. ### 3. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` -- **Why weird:** Enum name is `Disposition` — a generic noun (`Content-Disposition` header? business "disposition"?). The single sentinel value `FETCH_DISPOSITION_UNSPECIFIED` reveals the intended scope: this is *fetch* disposition. The enum members `INLINE` and `EXTERNAL_LINKS` are recognisable, but the type name doesn't say "fetch" or "result". A reader who skims `disposition?: Disposition` in `ExecuteStatementRequest` won't know it means "where the result data goes". -- **Category:** 1 (vague — "Disposition" of what?), 2 (redundant: `FETCH_DISPOSITION_UNSPECIFIED` reveals the missing word), 8 (the sentinel reveals the missing prefix). +- **Why weird:** Enum name is `Disposition` — a generic noun (`Content-Disposition` header? business "disposition"?). The enum members `INLINE` and `EXTERNAL_LINKS` are recognisable, but the type name doesn't say "fetch" or "result". A reader who skims `disposition?: Disposition` in `ExecuteStatementRequest` won't know it means "where the result data goes". As a top-level export, `Disposition` collides with any other "disposition" concept a consumer might pull in. +- **Category:** 1 (vague — "Disposition" of what?), 15 (generic top-level export). - **Suggested name:** `ResultDisposition` or `FetchDisposition`. Matching field rename: `resultDisposition?: ResultDisposition`. -- **Rationale:** The enum member's `FETCH_*` prefix is a code smell — when a sentinel value carries a qualifier the type name omits, the type name is under-qualified. +- **Rationale:** Top-level enum names should self-describe at use sites. `request.disposition: Disposition` reads as "disposition disposition"; `request.disposition: ResultDisposition` reads correctly. ### 4. `Format` enum is dangerously generic — `src/v1/model.ts:46` - **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #3: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). -- **Category:** 1 (vague — `Format` is the most generic possible name), 2 (the sentinel `FORMAT_UNSPECIFIED` reveals the gap), 10 (reserved-word-ish — `format` is a builtin function name in many ecosystems), 15 (generic name losing meaning at use sites). +- **Category:** 1 (vague — `Format` is the most generic possible name), 10 (reserved-word-ish — `format` is a builtin function name in many ecosystems), 15 (generic name losing meaning at use sites). - **Suggested name:** `ResultFormat`. Same pattern as #3. - **Rationale:** Top-level enum names should self-describe at use sites. `result.format: Format` reads as "format format"; `result.format: ResultFormat` reads correctly. The collision risk for a single-word `Format` import is high. ### 5. `TimeoutAction` enum members `CONTINUE`/`CANCEL` are too generic — `src/v1/model.ts:77` -- **Why weird:** A small enum with three values: `TIMEOUT_ACTION_UNSPECIFIED`, `CONTINUE`, `CANCEL`. The two real values are bare English verbs that don't say *what* they continue or cancel. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously (`CONTINUE`) or is cancelled (`CANCEL`). The relationship between the verbs and the timeout is invisible at the type level. +- **Why weird:** Two of the enum values are bare English verbs that don't say *what* they continue or cancel. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously (`CONTINUE`) or is cancelled (`CANCEL`). The relationship between the verbs and the timeout is invisible at the type level. - **Category:** 1 (vague — `CONTINUE` what?), 14 (gRPC/proto-style upper-case verbs), 15 (generic verb-only names). -- **Suggested name:** `OnTimeout.ContinueAsync` and `OnTimeout.CancelExecution` (or rename the enum to `OnTimeout` to match the field `onWaitTimeout`). Drop the `TIMEOUT_ACTION_UNSPECIFIED` sentinel per #12. +- **Suggested name:** `OnTimeout.ContinueAsync` and `OnTimeout.CancelExecution` (or rename the enum to `OnTimeout` to match the field `onWaitTimeout`). - **Rationale:** Enum members should self-document; bare verbs require the reader to chase the field's JSDoc. -### 6. `ColumnTypeName` enum embeds `USER_DEFINED_TYPE` — `src/v1/model.ts:37` -- **Why weird:** The enum represents SQL base types: `BOOLEAN`, `BYTE`, ..., `MAP`, `CHAR`, `NULL`, `USER_DEFINED_TYPE`. The last value breaks the pattern: every other member is a recognisable SQL type name; `USER_DEFINED_TYPE` is a meta-category covering all UDT instances. It also creates a redundant `ColumnTypeName.USER_DEFINED_TYPE` — "type" appears twice in the qualified name. -- **Category:** 2 (redundant: `*TypeName.*TYPE` repeats "type"), 13 (verb-tense — every other member is a noun like `INT`; this one is past-participial), 16 (field-vs-type-domain — UDT isn't a "base data type" per the JSDoc). -- **Suggested name:** Either `UDT` or `UserDefined` (drop `_TYPE`). Or split: keep base types in the enum; carry UDT info in `typeText`. -- **Rationale:** When one enum member breaks the pattern of the others, it signals an enum that does two jobs. - -### 7. `GetResultDataRequest` vs. `GetStatementResultRequest` — `src/v1/model.ts:381,390` +### 6. `GetResultDataRequest` vs. `GetStatementResultRequest` — `src/v1/model.ts:381,390` - **Why weird:** Two near-identical request types, one with `chunkIndex` and one without. Their names break apart suspiciously: - `GetResultDataRequest` fetches *one chunk* of the result data. - `GetStatementResultRequest` polls the entire statement (`statementId` only). @@ -87,25 +81,25 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** `GetResultChunkRequest` (carries `chunkIndex`) + `GetStatementRequest` (polls by `statementId`). Methods: `getResultChunk` + `getStatement`. This matches the URL paths `/result/chunks/{chunkIndex}` and `/{statementId}`. - **Rationale:** Type names should mirror the resource being addressed. The wire makes the distinction explicit; the TS surface obscures it. -### 8. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:219` -- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. Combine with #7: there are now two `getResult*` methods, one of which doesn't actually fetch results (it polls), and one of which does (`getResultData`). +### 7. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:219` +- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. Combine with #6: there are now two `getResult*` methods, one of which doesn't actually fetch results (it polls), and one of which does (`getResultData`). - **Category:** 6 (misleading — name implies result-fetch, primary purpose is poll), 12 (duplicate concept — both methods carry "Result" but mean different things), 17 (inconsistent verb usage — `cancel`, `execute`, `getStatementResult`, `getResultData`). - **Suggested name:** `getStatement` (matches the URL path `/{statementId}`). The Go SDK calls this `GetStatement`. The result is *part* of the response; foregrounding it in the method name misleads. - **Rationale:** The Databricks API docs name the operation "Get statement" (https://docs.databricks.com/api/workspace/statementexecution/getstatement). The TS SDK should match. -### 9. `getResultData` method asymmetric with `getStatementResult` — `src/v1/client.ts:183` -- **Why weird:** Companion to #8. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. +### 8. `getResultData` method asymmetric with `getStatementResult` — `src/v1/client.ts:183` +- **Why weird:** Companion to #7. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. - **Category:** 1 (vague — "result data" is too generic), 6 (misleading — drops the chunk-indexing semantic), 17 (asymmetric with sibling method). - **Suggested name:** `getResultChunk` (or `getStatementResultChunk` to match Go). Field rename: `chunkIndex` stays. - **Rationale:** Names should match the official API where possible. Compare to `getStatementResultChunkN` in the Go SDK. -### 10. `Client` class name — `src/v1/client.ts:43` +### 9. `Client` class name — `src/v1/client.ts:43` - **Why weird:** A class literally named `Client`, re-exported as `Client` from `index.ts:3`. A user importing this from `@databricks/sdk-statementexecution` and another `Client` from `@databricks/sdk-queryexecution` will collide on the namespace. Identical to `queryexecution.md` Finding #9. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `StatementExecutionClient`. - **Rationale:** Repeated SDK-wide pattern. -### 11. `dataArray` field on `ResultData` — `src/v1/model.ts:422` +### 10. `dataArray` field on `ResultData` — `src/v1/model.ts:422` - **Why weird:** Field name `dataArray` on a type already called `ResultData`. The two `data` tokens stack: `resultData.dataArray`. The JSDoc explains it carries a `JSON_ARRAY` formatted payload, so the name is gesturing at the wire format. But the type name is the *outer* wrapper, so saying "data" inside "Data" reads as redundant. - **Category:** 1 (vague — `data`, `array` both generic), 12 (duplicate concept — `Data.dataArray`), 20 (type-suffix tautology). - **Suggested name:** `rows` (matches the SQL semantics: each entry of the array is a row). Or rename the outer type to `ResultChunk` so `chunk.data` is meaningful. @@ -113,32 +107,26 @@ to read every one to pick the right tool. See finding #1. ## Medium severity -### 12. Every enum carries a `*_UNSPECIFIED` sentinel — `src/v1/model.ts:41, 47, 78, 85` -- **Why weird:** All four "open" enums carry `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, and `STATE_UNSPECIFIED`. These are protobuf-style "default value" sentinels. In TypeScript, absence is represented by `undefined` (the fields are already optional). The sentinels add noise to enum members and force callers to handle a meaningless value. -- **Category:** 11 (trivial value — no behaviour), 14 (proto-style), 18 (long enum value — e.g. `FETCH_DISPOSITION_UNSPECIFIED` is 28 chars). -- **Suggested name:** Drop all `*_UNSPECIFIED` members. The field's `| undefined` already encodes "not set". -- **Rationale:** Generator-wide pattern; same as `commandexecution.md` Finding #4. - -### 13. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` -- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #22 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. +### 11. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` +- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #21 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. - **Category:** 13 (verb-tense inconsistency), 17 (US/UK spelling inconsistency for "cancel"). - **Suggested name:** Pick one cancel spelling. The wire is `CANCELED` (single-l) per this enum and `CANCELLED` per `ServiceErrorCode`. Resolve at wire level. - **Rationale:** Twin spellings of the same English word in adjacent enums in the same file is a maintenance hazard. Compare `StatementStatus_State.CANCELED` to `ServiceErrorCode.CANCELLED`. -### 14. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` +### 12. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` - **Why weird:** A user importing from both `statementexecution` and `queryexecution` finds a `statementId` field on responses from both packages. In `statementexecution` it identifies the SQL Statement Execution submission. In `queryexecution` (a published-dashboard query) the JSDoc explicitly says "The statement_id should be identical to data_token in SuccessStatus and PendingStatus" — i.e. it's an audit copy, not a primary key. The same name means different things in two adjacent packages. - **Category:** 12 (duplicate concept — same name, different meaning), 19 (underspecified ID — what kind of statement?). - **Suggested name:** Keep `statementId` here (primary identifier); rename the audit-only copy in `queryexecution` (see `queryexecution.md` Finding #14). - **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. -### 15. `warehouseId` field — `src/v1/model.ts:158` -- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #35. +### 13. `warehouseId` field — `src/v1/model.ts:158` +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #33. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. -### 16. `statement` field name is the package name — `src/v1/model.ts:153` -- **Why weird:** The request type `ExecuteStatementRequest` carries a field literally called `statement`. The package name is `statementexecution`. The class name is `Client` (per #10). So a call reads: +### 14. `statement` field name is the package name — `src/v1/model.ts:153` +- **Why weird:** The request type `ExecuteStatementRequest` carries a field literally called `statement`. The package name is `statementexecution`. The class name is `Client` (per #9). So a call reads: ```ts client.executeStatement({statement: 'SELECT 1', warehouseId: '...'}) ``` @@ -147,175 +135,205 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** Rename the field to `sql` (or `query` if not colliding with `queryexecution`). The wire is `statement`, so a marshaller maps `sql -> statement`. - **Rationale:** The package, the class, and the field shouldn't all spell the same word three times. -### 17. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` +### 15. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` - **Why weird:** Two parallel "limit" fields; `rowLimit` has no default mentioned; `byteLimit` mentions a "100 GiB default if not explicitly set" for `EXTERNAL_LINKS` disposition. The asymmetric defaults aren't captured by the types. JSDoc encodes them; users have to read both. - **Category:** 16 (field-vs-domain — domain has implicit defaults the type doesn't show), 17 (asymmetric defaults). - **Suggested name:** Names are fine; consolidate JSDoc so both fields document defaults symmetrically. - **Rationale:** Pair-fields should have parallel JSDoc structure. -### 18. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` +### 16. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` - **Why weird:** Field name is `parameters`. Element type is `StatementParameter`. The element name is more specific (statement parameter) than the field (parameters). At the JSDoc level, the field describes "parameter markers" — which is yet a third name for the same concept. So users see: `parameters` (field) vs `StatementParameter` (element type) vs "parameter markers" (docs). Pick one vocabulary. - **Category:** 12 (duplicate concept — three names for one idea), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the element type to `Parameter` (less qualified than field) or rename the field to `statementParameters`. The wire shape probably matters; pick the less verbose option. - **Rationale:** Multiple synonyms for one concept burns reader attention. -### 19. `queryTags` field on `ExecuteStatementRequest` — `src/v1/model.ts:326` +### 17. `queryTags` field on `ExecuteStatementRequest` — `src/v1/model.ts:326` - **Why weird:** Field is `queryTags`, element type is `QueryTag`. The user is *executing a statement*, but the metadata tags are called *query* tags. There's no `Query` type in this package; the prefix `Query` here is a Databricks billing/observability term (queries get tagged for analytics). For a TS user who hasn't seen the bigger picture, the mismatch between `executeStatement` and `QueryTag[]` reads as inconsistent. - **Category:** 12 (duplicate concept — `statement` vs `query`), 17 (inconsistent vocabulary). - **Suggested name:** Rename to `tags` + `Tag` (the surrounding context already says "statement", so the qualifier is redundant). Wire mapping can keep `query_tags`. - **Rationale:** Tagging in this SDK is a cross-cutting concern; `Tag` would be the natural top-level name. Within the statement-execution context, `tags` suffices. -### 20. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` -- **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `APIError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `APIError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. -- **Category:** 12 (duplicate concept — overlaps `APIError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). -- **Suggested name:** `StatementError` (or fold into `APIError` extensions). The errorCode should reuse the canonical apierror codes per #2. +### 18. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` +- **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `ApiError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `ApiError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. +- **Category:** 12 (duplicate concept — overlaps `ApiError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). +- **Suggested name:** `StatementError` (or fold into `ApiError` extensions). The errorCode should reuse the canonical apierror codes per #2. - **Rationale:** Multiple error type shapes per SDK is a cognitive tax. -### 21. `StatementStatus.sqlState` field — `src/v1/model.ts:522` +### 19. `StatementStatus.sqlState` field — `src/v1/model.ts:522` - **Why weird:** Field name `sqlState`. The JSDoc says "SQLSTATE error code returned when the statement execution fails." The all-caps acronym SQLSTATE is the SQL-standard 5-character status code (e.g. `42S22`). The TS field uses camelCase `sqlState`. Compare to elsewhere in the SDK where SQL is also lowercased (`sqlExpression`, `sqlText`). This is consistent SDK-wide. - **Category:** 3 (acronym casing — `SQL` becoming `sql` is debatable; SDK has settled on lowercase, so this matches). - **Suggested name:** Keep `sqlState`. Flagged for completeness. - **Rationale:** TS convention varies on multi-letter acronyms; google-ts-style says lowercase initial; SDK follows the convention. -### 22. `ServiceError.errorCode` field — `src/v1/model.ts:474` +### 20. `ServiceError.errorCode` field — `src/v1/model.ts:474` - **Why weird:** Field name stutters with type name: `ServiceError.errorCode`. "Error" appears at both levels. A reader sees `err.errorCode` and wonders if there's a non-error code too. - **Category:** 20 (type-suffix tautology), 12 (duplicate concept). - **Suggested name:** `code` (since the type is already `ServiceError`). - **Rationale:** Stutter — `error.error*` — is a code smell. -### 23. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` +### 21. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` - **Why weird:** Same English word, two spellings, in two enums in the same file. `CANCELLED` is British; `CANCELED` is American. The wire chose differently for the two enums; the SDK mirrors the wire. End users have to remember "cancel with one or two Ls". -- **Category:** 13 (spelling/tense inconsistency — see #13), 17 (asymmetric pair). +- **Category:** 13 (spelling/tense inconsistency — see #11), 17 (asymmetric pair). - **Suggested name:** Normalise upstream. If kept, document the spelling difference in `@databricks/sdk-databricks` README. - **Rationale:** The spelling difference is invisible in casual scanning but breaks copy/paste. -### 24. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` +### 22. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` - **Why weird:** `waitTimeout?: string` with JSDoc explaining it must be formatted as `"Ns"` where N is 0 or 5-50. So a *typed string* with a private DSL inside. Users will write `"5s"` and hope, or worse: `5` (number, won't compile). The wire format is a proto Duration, but the TS surface could parse `number` (seconds) or `Duration` (ms) and emit `Ns`. - **Category:** 1 (vague — `string`-typed numeric), 6 (misleading — a "timeout" with arbitrary string content), 14 (proto/Go-style — Duration carry-over). - **Suggested name:** Keep `waitTimeout` but change the type to `number` (seconds) and let the marshaller produce `Ns`. Or `Duration` from `@databricks/sdk-core/wkt`. - **Rationale:** Letting users pass arbitrary strings into a numeric field is a contract violation waiting to happen. -### 25. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` +### 23. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` - **Why weird:** Field is `onWaitTimeout`, type is `TimeoutAction`. The two names don't share the prefix `Wait*` even though they're tightly coupled. A reader sees `onWaitTimeout?: TimeoutAction` and has to chase the docs to learn the enum members are about wait-timeouts. - **Category:** 17 (asymmetric field/type naming), 12 (duplicate concept — `Wait`/`Timeout` overloaded). - **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #5, `OnTimeout`. - **Rationale:** Field/type symmetry is a strong signal. -### 26. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` +### 24. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` - **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. - **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). - **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. - **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. -### 27. `nextChunkInternalLink` field — `src/v1/model.ts:128` +### 25. `nextChunkInternalLink` field — `src/v1/model.ts:128` - **Why weird:** The field is documented as: "an absolute `path` to be joined with your `$DATABRICKS_HOST`, and should be treated as an opaque link. This is an alternative to using `next_chunk_index`." The word "Internal" is doing a lot here — it's not internal as in "private to Databricks"; it means "internal-link, as opposed to a presigned cloud link". The naming is opaque without the JSDoc. - **Category:** 1 (vague — "Internal" is too generic), 5 (cryptic — needs JSDoc to decode). - **Suggested name:** `nextChunkRelativePath` (matches its semantics: a path relative to the workspace host). Or `nextChunkUrlPath`. - **Rationale:** Names should not lean on JSDoc to communicate the *kind* of identifier. -### 28. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +### 26. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` - **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. - **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). - **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). - **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. -### 29. `totalChunkCount`, `totalRowCount`, `totalByteCount` triple — `src/v1/model.ts:453, 457, 462` +### 27. `totalChunkCount`, `totalRowCount`, `totalByteCount` triple — `src/v1/model.ts:453, 457, 462` - **Why weird:** Three parallel `total*Count` fields. Each ends in `Count` (singular noun) and starts with `total` (qualifier). The triple is consistent but verbose — `totalChunkCount` is 16 characters for an integer count. - **Category:** 7 (overly verbose), 8 (redundant suffix — `Count` is implied for an integer). - **Suggested name:** `chunks` / `rows` / `bytes` (drop `total*Count` and let the integer-ness be implicit). Or keep `total*Count` and document that the per-chunk `*Count` fields are partial sums. - **Rationale:** Verbose triplets across a type can usually be compressed. -### 30. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` +### 28. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` - **Why weird:** `ResultManifest.chunks` is an array of `ChunkInfo`; `totalChunkCount` is `chunks.length`. The two carry the same information; on the wire there is a sender-receiver invariant, but TS users can compute one from the other. The naming gives no hint of the redundancy. - **Category:** 12 (duplicate concept), 1 (vague — both fields are about the same property). - **Suggested name:** Drop `totalChunkCount`; users compute via `chunks?.length`. - **Rationale:** Two fields that mean the same thing should not both be public. -### 31. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` +### 29. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` - **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. - **Category:** 16 (field-vs-format contradicts domain when format differs). - **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. - **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. -### 32. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` -- **Why weird:** Companion to #31. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. +### 30. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +- **Why weird:** Companion to #29. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. - **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. - **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. -### 33. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` +### 31. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` - **Why weird:** Two `execute*` functions in the same file, one wraps retry/rate-limit policy and one does the actual HTTP. Same as `queryexecution.md` Finding #21. - **Category:** 1, 12, 17. - **Suggested name:** `runWithPolicies` + `sendHttpRequest`. - **Rationale:** Generator-wide. -### 34. `buildHttpRequest` helper — `src/v1/utils.ts:96` +### 32. `buildHttpRequest` helper — `src/v1/utils.ts:96` - **Why weird:** "Build" implies builder pattern; this is a 16-line object literal. Same as `queryexecution.md` Finding #22. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest` or inline. -### 35. Every field on every request type is optional — `src/v1/model.ts` (every interface) +### 33. Every field on every request type is optional — `src/v1/model.ts` (every interface) - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). - **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. -### 36. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` -- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #14) suggests this is the wrong abstraction. +### 34. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` +- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #12) suggests this is the wrong abstraction. - **Category:** 6 (misleading — type is overloaded), 12 (duplicate concept — two operations). - **Suggested name:** Keep `StatementResponse` but document that it's polymorphic. Or split into `StatementSubmissionResponse` + `StatementStateResponse`. - **Rationale:** Shared response types are acceptable but should be flagged for documentation. +### 35. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` +- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). #18 already flags the type for overlap with `ApiError`; this finding flags the `Service` mid-position as a proto/Java-RPC architectural leak. +- **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). +- **Suggested name:** `StatementError` — domain-named, mirrors the surrounding `Statement*` vocabulary. +- **Rationale:** Architectural-layer words ("Service", "Server", "Backend") in user-facing type names are proto/RPC framework carry-overs. Domain-named alternatives compose better with the rest of the package surface. + +### 36. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` +- **Why weird:** Same `Service` mid-position architectural leak as #35, applied to the code enum. #2 already flags the enum for duplicating `google.rpc.Code`; this finding flags the `Service` qualifier specifically as a proto-RPC architectural noun. +- **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). +- **Suggested name:** `StatementErrorCode` if the enum is retained; ideally fold into canonical `apierror/codes` per #2. +- **Rationale:** Pair with #35 — the `Service` qualifier carries no domain meaning at the use site. + +### 37. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` +- **Why weird:** Underscore-joined identifier `StatementStatus_State` directly transcribes the proto nested-message name into TS. The source file even carries an `eslint-disable` for `@typescript-eslint/naming-convention` with the comment "Proto-style nested enum name." That comment confirms it: the name is a verbatim proto leak, not a TS-idiomatic choice. As a top-level export from `index.ts`, every consumer sees the underscore. +- **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). +- **Suggested name:** `StatementState` (the `Status` parent is itself a thin wrapper; the state is the meaningful enum) or `StatementStatusState` (no underscore) if both halves matter. +- **Rationale:** Proto nested-type underscores are an artefact of code generation from `.proto`. TS has no nested-type concept; flattening to a single CamelCase name removes the leak. + +### 38. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` +- **Why weird:** Another underscore-joined name with the same `eslint-disable` and an explicit "Proto-style nested message name" comment. The type exists because proto3 represents `map` as a synthetic nested `*Entry` message; gRPC generators surface this as a nested type. In TS the wire shape is just `Record` (see `httpHeaders` on `ExternalLink`). Re-exporting `ExternalLink_HttpHeadersEntry` from `index.ts` exposes proto machinery the JS user never needs. +- **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape), 12 (duplicate concept — `httpHeaders` is already typed `Record`). +- **Suggested name:** Delete the type. The `httpHeaders` field is already `Record | undefined`; no consumer needs the synthetic map-entry pair. +- **Rationale:** Proto `map` synthetic `*Entry` messages should not surface in user-facing TS types. The information is fully captured by `Record`. + +### 39. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` +- **Why weird:** Four enums (`Disposition`, `Format`, `TimeoutAction`, `StatementStatus_State`) carry a `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, `STATE_UNSPECIFIED` first variant. These are proto3 enum convention: every enum must have a `_UNSPECIFIED = 0` member because the default scalar value is required to be valid. JS/TS has no such constraint — `undefined` already encodes "not specified". So the enums carry a value that exists *only* to satisfy proto3 codegen requirements. End users have to filter out the unspecified variant manually when narrowing. +- **Category:** 14 (proto/protobuf convention leak), 6 (misleading — the variant has no domain meaning), 1 (vague — `UNSPECIFIED` is the literal default state). +- **Suggested name:** Drop the `*_UNSPECIFIED` variants. TS uses `Disposition | undefined` for "not set". +- **Rationale:** Proto3 zero-value enums are a wire-format constraint that has no equivalent in JSON/TS. Carrying them in the type surface forces users to handle a case that cannot occur in a well-formed response. + ## Low severity -### 37. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +### 40. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` - **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. - **Category:** 17 (acceptable asymmetry). - **Suggested name:** Keep. -### 38. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:108, 111, 116` +### 41. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:109, 111, 116` - **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. - **Category:** 12 (duplicate concept — three types carry the same fields). - **Suggested name:** Extract `ChunkMetrics` shared interface. - **Rationale:** Trio-replicated types are a tell. -### 39. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` +### 42. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` - **Why weird:** `typeText` is "the full SQL type specification" (e.g. `DECIMAL(10,2)`). `typeName` is the base type name (`DECIMAL`). The pair is intentional but the names don't make the relationship obvious — `typeText` and `typeName` sound interchangeable. - **Category:** 17 (asymmetric pair — `Text` vs `Name`), 1 (vague — `Text` of what?). - **Suggested name:** `typeSql` (the wire SQL text) + `typeBase` (the base type) — but the wire is canonical, so keep names. Document the relationship. -### 40. `position` field on `ColumnInfo` — `src/v1/model.ts:139` +### 43. `position` field on `ColumnInfo` — `src/v1/model.ts:139` - **Why weird:** Top-level field literally `position` with JSDoc "The ordinal position of the column (starting at position 0)." `position` is generic. `ordinalPosition` (matches the JSDoc) or `columnIndex` would be more precise. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `ordinalPosition` or `index`. -### 41. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` +### 44. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` - **Why weird:** A string field whose JSDoc says "Indicates the date-time that the given external link will expire and becomes invalid". Two issues: the name `expiration` is ambiguous (an expiry timestamp? a TTL?), and the type is `string` (presumably ISO8601 — the JSDoc doesn't say). A reader can't tell from the type or name how to interpret the value. - **Category:** 1 (vague), 6 (misleading — could be TTL). - **Suggested name:** `expiresAt` (ISO8601 timestamp) — matches modern JS/TS convention. -### 42. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +### 45. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` - **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. - **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). - **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 43. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +### 46. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` - **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. - **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). - **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. -### 44. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` +### 47. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` - **Why weird:** Three single-word fields on a single type, all `string | undefined`. The JSDoc explains: name is the marker name; value is the substituted text; type is the SQL type. The names work fine in this context but are maximally generic — `name`, `value`, `type` could mean anything. The `type` field collides with the TS keyword visually (though `type` isn't actually reserved in object-position). - **Category:** 1 (vague), 10 (reserved-word collision — `type` is contextually meaningful), 15 (generic names). - **Suggested name:** `parameterName`, `parameterValue`, `sqlType` — but local names are fine inside a clear-context type. Flagged for completeness. -### 45. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` -- **Why weird:** Generic key-value pair. Same as #44 but for tags. `tagKey` + `tagValue` are common alternatives. +### 48. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` +- **Why weird:** Generic key-value pair. Same as #42 but for tags. `tagKey` + `tagValue` are common alternatives. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** Acceptable in context. -### 46. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 49. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** Generic name. Same as `queryexecution.md` Finding #25. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -330,14 +348,11 @@ to read every one to pick the right tool. See finding #1. fallback to empty string is a silent-failure pattern. Names are fine; the fallback semantics are wrong. -### O-2. `*_UNSPECIFIED` sentinels exist on every enum — see #12. -- Generator-wide; the fix is in codegen. - -### O-3. Statement IDs share a vocabulary with `queryexecution` and `queryhistory`. +### O-2. Statement IDs share a vocabulary with `queryexecution` and `queryhistory`. - All three packages emit some flavour of `statementId`. The naming should be unified at the apierror / statement-vocabulary layer if it matters. -### O-4. Module-level JSDoc lives in leaf files instead of `index.ts`. +### O-3. Module-level JSDoc lives in leaf files instead of `index.ts`. - `index.ts` has no module-level JSDoc; `model.ts` has none either. Other packages document scope and the API at `index.ts`. The naming choices flagged above (e.g. `Format`, `Disposition`, `Client`) would be less confusing if @@ -366,7 +381,7 @@ The two packages model semantically distinct operations (general SQL Statement Execution vs Lakeview-dashboard query lifecycle) but share enough vocabulary (`Statement`, `Query`, `Cancel`, `Execute`, `Status`) that a user importing both will be confused. The fix is at the naming/package level (see #1) and -the cross-package vocabulary alignment (#14, #23). +the cross-package vocabulary alignment (#12, #21). --- @@ -376,5 +391,9 @@ the cross-package vocabulary alignment (#14, #23). 2. **Word stutter.** `ServiceError.errorCode`, `ResultData.dataArray`, `*ResultData` vs `*StatementResult`, `executeStatement` / `getStatementResult` / `statement` field. The wire shape doesn't help here; the TS surface could compress. 3. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). 4. **Package-name competition.** `statementexecution` lives alongside `queryexecution`, `commandexecution`, and `queries` — four near-synonymous names for related-but-distinct execution surfaces. -5. **`*_UNSPECIFIED` sentinels.** Proto-default-value sentinels carried through to TS where `undefined` already encodes "not set". Generator-wide. -6. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. +5. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. +6. **Proto/RPC architectural leaks.** `Service` mid-position on `ServiceError` / `ServiceErrorCode` (architectural-layer noun); `StatementStatus_State` and `ExternalLink_HttpHeadersEntry` proto-style underscored nested names; `*_UNSPECIFIED` enum zero values across four enums. Each is a verbatim transcription of proto/gRPC machinery into TS where the equivalent concept (`undefined`, `Record`, flat enums) is already idiomatic. + +## Fixed + +_None._ diff --git a/.agent/naming-audit/storageconfigurations.md b/.agent/naming-audit/storageconfigurations.md new file mode 100644 index 00000000..891ee92b --- /dev/null +++ b/.agent/naming-audit/storageconfigurations.md @@ -0,0 +1,159 @@ +# Naming Audit: storageconfigurations + +**Path:** `packages/storageconfigurations/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level Databricks storage configurations +(create/get/list/delete a root S3 bucket and optional IAM role used by +workspaces in an account). +**Total weird names flagged:** 4 + +This audit is scoped to proto-architectural-leak naming (mid-position +`Public`/`Internal`/`External`, `Proto` suffix/infix, architectural-layer +words such as `Service`/`Manager`/`Wrapper`, `Impl`, `Rpc`/`Grpc`, +`Foo_PublicRequest`-style paired naming, etc.). Domain words like +`External*`/`Online*` and standard end-position suffixes (`Request`, +`Response`, `Info`) are not flagged here. + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 4 | +| Medium | 0 | +| Low | 0 | +| Observation | 0 | + +All 4 remaining findings are the same category: `Public` suffix on +`Client` methods leaking from the upstream proto/service layout into the +TS surface. The request/response interfaces and marshal schema were +renamed in regeneration; the `Client` method names are the last +surviving carriers of the leak. + +## High severity + +### 1. `Client.createStorageConfigurationPublic` — `src/v1/client.ts:70` +- **Why weird:** A method on the `Client` class whose name ends in + `Public`. Reads as "the method on the public class that calls the + public endpoint" — the suffix only exists because the underlying + proto/spec uses `Public` to distinguish account-API routes. +- **Category:** Proto-architectural leak — `Public` suffix on + client method. +- **Suggested:** `createStorageConfiguration`. +- **Rationale:** Methods on `Client` are inherently public; the suffix + is meaningless to a TS caller. + +### 2. `Client.deleteStorageConfigurationPublic` — `src/v1/client.ts:99` +- **Why weird:** Same `Public` suffix on `Client` method as #1. +- **Category:** Proto-architectural leak — `Public` suffix on + client method. +- **Suggested:** `deleteStorageConfiguration`. +- **Rationale:** Same as #1. + +### 3. `Client.getStorageConfigurationPublic` — `src/v1/client.ts:124` +- **Why weird:** Same `Public` suffix on `Client` method as #1. +- **Category:** Proto-architectural leak — `Public` suffix on + client method. +- **Suggested:** `getStorageConfiguration`. +- **Rationale:** Same as #1. + +### 4. `Client.listStorageConfigurationPublic` — `src/v1/client.ts:149` +- **Why weird:** Same `Public` suffix on `Client` method as #1. +- **Category:** Proto-architectural leak — `Public` suffix on + client method. +- **Suggested:** `listStorageConfigurations` (drop `Public`; pluralise + while renaming). +- **Rationale:** Same as #1. + +## Medium severity + +_None._ + +## Low severity + +_None._ + +## Observation + +_None._ + +## Fixed + +- **`CreateStorageConfigurationPublicRequest` interface** — renamed to + `CreateStorageConfigurationRequest` (`src/v1/model.ts:5`). Fixed in + regeneration on 2026-05-22. +- **`DeleteStorageConfigurationPublicRequest` interface** — renamed to + `DeleteStorageConfigurationRequest` (`src/v1/model.ts:20`). Fixed in + regeneration on 2026-05-22. +- **`GetStorageConfigurationPublicRequest` interface** — renamed to + `GetStorageConfigurationRequest` (`src/v1/model.ts:25`). Fixed in + regeneration on 2026-05-22. +- **`ListStorageConfigurationPublicRequest` interface** — renamed to + `ListStorageConfigurationRequest` (`src/v1/model.ts:30`). Fixed in + regeneration on 2026-05-22. +- **`ListStorageConfigurationPublicResponse` interface** — renamed to + `ListStorageConfigurationResponse` (`src/v1/model.ts:34`). Fixed in + regeneration on 2026-05-22. +- **`marshalCreateStorageConfigurationPublicRequestSchema`** — renamed + to `marshalCreateStorageConfigurationRequestSchema` + (`src/v1/model.ts:90`). Fixed in regeneration on 2026-05-22. +- **`CreateStorageConfigurationPublicRequest` import** — import in + `client.ts` now references `CreateStorageConfigurationRequest` + (`src/v1/client.ts:22`). Fixed in regeneration on 2026-05-22. +- **`DeleteStorageConfigurationPublicRequest` import** — import in + `client.ts` now references `DeleteStorageConfigurationRequest` + (`src/v1/client.ts:23`). Fixed in regeneration on 2026-05-22. +- **`GetStorageConfigurationPublicRequest` import** — import in + `client.ts` now references `GetStorageConfigurationRequest` + (`src/v1/client.ts:24`). Fixed in regeneration on 2026-05-22. +- **`marshalCreateStorageConfigurationPublicRequestSchema` import** — + import in `client.ts` now references + `marshalCreateStorageConfigurationRequestSchema` + (`src/v1/client.ts:30`). Fixed in regeneration on 2026-05-22. + +## File coverage + +| File | Lines | Audited | +| --------------------- | ----- | ------------------------------------------------ | +| `src/v1/model.ts` | 111 | All 7 interfaces + 3 schema constants + every field. | +| `src/v1/client.ts` | 178 | `Client` class, constructor, 4 methods, import list. | +| `src/v1/utils.ts` | 151 | All exported / private functions. No proto-leak hits. | +| `src/v1/transport.ts` | 75 | `newHttpClient` factory + auth wrapper. No proto-leak hits. | +| `src/v1/index.ts` | 16 | All re-exports — names mirror `model.ts` (covered above). | + +Type & symbol checklist: + +- [x] `CreateStorageConfigurationRequest` interface — clean post-regen + (was flagged; now fixed). +- [x] `DeleteStorageConfigurationRequest` interface — clean post-regen + (was flagged; now fixed). +- [x] `GetStorageConfigurationRequest` interface — clean post-regen + (was flagged; now fixed). +- [x] `ListStorageConfigurationRequest` interface — clean post-regen + (was flagged; now fixed). +- [x] `ListStorageConfigurationResponse` interface — clean post-regen + (was flagged; now fixed). +- [x] `RootBucketInfo` interface — clean (domain-appropriate `Info` + suffix; out of scope for proto-architectural-leak audit). +- [x] `StorageConfiguration` interface — clean. +- [x] `unmarshalRootBucketInfoSchema`, `unmarshalStorageConfigurationSchema`, + `marshalRootBucketInfoSchema`, `marshalCreateStorageConfigurationRequestSchema` + — clean (no `Public` infix on any schema). +- [x] `Client` class itself — clean (terminal-position `Client` is the + standard SDK convention). +- [x] `Client.createStorageConfigurationPublic` — flagged (#1). +- [x] `Client.deleteStorageConfigurationPublic` — flagged (#2). +- [x] `Client.getStorageConfigurationPublic` — flagged (#3). +- [x] `Client.listStorageConfigurationPublic` — flagged (#4). +- [x] `client.ts` import list — clean post-regen (no `Public` infix on + any imported name). +- [x] `utils.ts` (`executeCall`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, + `HttpCallOptions`) — no proto-architectural-leak names. (The + `executeCall` / `executeHttpCall` verb overlap and the generic + `body` shadowing are common across packages and out of scope here.) +- [x] `transport.ts` (`newHttpClient`, auth-wrapping class) — no + `Public`/`Internal`/`Proto`/`Service`/`Manager` leak in domain + identifiers. (The auth wrapper class itself is a cross-package + pattern, not flagged here.) +- [x] `index.ts` re-exports — names mirror `model.ts` and are clean + post-regen. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md index d0e86896..40699549 100644 --- a/.agent/naming-audit/supervisoragents.md +++ b/.agent/naming-audit/supervisoragents.md @@ -4,89 +4,81 @@ **Versions audited:** v1 **Inferred domain:** "Supervisor Agent" is an orchestrator resource that routes user questions to one or more child tools (genie spaces, knowledge -assistants, UC functions, UC connections, apps, volumes, dashboards, -serving endpoints, UC tables, vector-search indexes, catalogs, schemas, -nested supervisor agents, public web search). CRUD on three resource types: -`SupervisorAgent` (top-level), `Tool` (child of `SupervisorAgent`, -discriminated union over 14 tool kinds), and `Example` (child of -`SupervisorAgent`, question + guidelines pair used for in-context steering). -Every list endpoint paginates via `pageSize`/`pageToken`. No state enums -exist in this package; the entire surface is data plus references to other -Databricks resources. -**Total weird names flagged:** 43 +assistants, UC functions, UC connections, apps, volumes). CRUD on three +resource types: `SupervisorAgent` (top-level), `Tool` (child of +`SupervisorAgent`, discriminated union over 6 tool kinds), and `Example` +(child of `SupervisorAgent`, question + guidelines pair used for +in-context steering). Every list endpoint paginates via +`pageSize`/`pageToken`. No state enums exist in this package; the entire +surface is data plus references to other Databricks resources. +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | -| High | 13 | +| High | 10 | | Medium | 15 | -| Low | 9 | +| Low | 6 | | Observation | 6 | ## High severity -### 1. `SupervisorAgent` — `Supervisor` and `Agent` are both extremely generic — `src/v1/model.ts:219` -- **Why weird:** The package name + entity name combines two of the most overloaded nouns in the AI space. `Agent` alone could mean anything from "browser user-agent" to "autonomous LLM agent" to "service-account principal." `Supervisor` is even worse — in computing it usually refers to a process supervisor (systemd, OpenRC, supervisord) or a kernel privilege ring. Together they read as "a process supervisor that supervises an agent process." The actual domain is an LLM orchestrator: a top-level agent that routes user prompts to a set of registered sub-tools. The doc on the `Tool` field type mentions it is "Nested Supervisor Agent tool" (model.ts:245) for recursion, which reinforces that this is in fact a router. The Databricks docs (https://docs.databricks.com/en/generative-ai/agent-framework/index.html) call this style "AI agent" / "agent system" — but not "supervisor agent." The package would be far less ambiguous as `agentorchestrators`, `routeragents`, or `supervisoragents` with `SupervisorAgent` renamed to `RouterAgent` or `OrchestratorAgent`. +### 1. `SupervisorAgent` — `Supervisor` and `Agent` are both extremely generic — `src/v1/model.ts:193` +- **Why weird:** The package name + entity name combines two of the most overloaded nouns in the AI space. `Agent` alone could mean anything from "browser user-agent" to "autonomous LLM agent" to "service-account principal." `Supervisor` is even worse — in computing it usually refers to a process supervisor (systemd, OpenRC, supervisord) or a kernel privilege ring. Together they read as "a process supervisor that supervises an agent process." The actual domain is an LLM orchestrator: a top-level agent that routes user prompts to a set of registered sub-tools. The Databricks docs (https://docs.databricks.com/en/generative-ai/agent-framework/index.html) call this style "AI agent" / "agent system" — but not "supervisor agent." The package would be far less ambiguous as `agentorchestrators`, `routeragents`, or `supervisoragents` with `SupervisorAgent` renamed to `RouterAgent` or `OrchestratorAgent`. - **Category:** 1 (vague/generic — both nouns), 17 (no SDK-wide policy on `Agent` terminology). - **Suggested name:** `RouterAgent` or `OrchestratorAgent` (then package `routeragents` / `agentorchestrators`). If the backend wire name `supervisor-agents` cannot change, keep the package name but document the routing semantics on the type-level JSDoc. - **Rationale:** The first sentence of the package's only JSDoc-relevant type is "The resource name of the SupervisorAgent." That tautological doc is a tell — the team did not have a good one-line description for the type, which is exactly what a vague name produces. A self-describing name would seed an obvious one-liner ("A `RouterAgent` routes user prompts to a set of registered tools."). -### 2. `Tool` — bare generic name for a discriminated union over 14 resource kinds — `src/v1/model.ts:251` -- **Why weird:** The `Tool` type is the most generic name in any AI SDK. It does not say *which* tools, *whose* tools, or *how* the tool is invoked. The discriminated union has 14 variants spanning unrelated resource domains: vector search, dashboards, model-serving endpoints, UC functions, web search, etc. Compare to `customllms.Dataset` (audited as flagged for being a single-field wrapper — at least it had domain specificity); `Tool` here is genuinely a 14-kind tagged union that needs a name explaining what kind of tool. A reader importing `import {Tool} from '@databricks/sdk-supervisoragents/v1'` will see `Tool` as a top-level name in their module and be unable to guess whether it's a CLI tool, a build tool, a python tool, or a function-call tool. Other LLM-tool conventions: OpenAI calls them `function` (https://platform.openai.com/docs/guides/function-calling); Anthropic calls them `tool_use` (https://docs.anthropic.com/en/docs/build-with-claude/tool-use); LangChain calls them `Tool` (where the package context disambiguates). -- **Category:** 1 (vague/generic), 12 (duplicate of `SupervisorAgentTool`, which is one variant of `Tool`). +### 2. `Tool` — bare generic name for a discriminated union over 6 resource kinds — `src/v1/model.ts:219` +- **Why weird:** The `Tool` type is the most generic name in any AI SDK. It does not say *which* tools, *whose* tools, or *how* the tool is invoked. The discriminated union has 6 variants spanning unrelated resource domains: genie spaces, knowledge assistants, UC functions, UC connections, apps, and volumes. A reader importing `import {Tool} from '@databricks/sdk-supervisoragents/v1'` will see `Tool` as a top-level name in their module and be unable to guess whether it's a CLI tool, a build tool, a python tool, or a function-call tool. Other LLM-tool conventions: OpenAI calls them `function` (https://platform.openai.com/docs/guides/function-calling); Anthropic calls them `tool_use` (https://docs.anthropic.com/en/docs/build-with-claude/tool-use); LangChain calls them `Tool` (where the package context disambiguates). +- **Category:** 1 (vague/generic). - **Suggested name:** `AgentTool`, `SupervisorTool`, or `RegisteredTool`. The qualifier disambiguates against generic `Tool` collisions in a multi-package import set. -- **Rationale:** Same reasoning as #1; specificity in type names prevents alias collisions and makes import lists self-documenting. The package already calls one tool kind `SupervisorAgentTool` (the recursion case), so the bare `Tool` lacks a parallel qualifier. +- **Rationale:** Same reasoning as #1; specificity in type names prevents alias collisions and makes import lists self-documenting. -### 3. `Tool.toolType: string` — stringly-typed when it is a closed set of 14 — `src/v1/model.ts:259-260` -- **Why weird:** The JSDoc enumerates the allowed values: `"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "lakeview_dashboard", "serving_endpoint", "uc_table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`. The type is `string`, so a caller writing `toolType: 'GENIE_SPACE'` (wrong case), `'genieSpace'` (camelCase), or `'web-search'` (kebab) gets no compiler help. The same struct *already* carries the discriminant in the `spec` discriminated union: `spec.$case` ranges over `'genieSpace' | 'knowledgeAssistant' | ...` — covering the exact same 14 kinds. So the SDK declares the type domain twice, in two incompatible casings (snake on `toolType`, camel on `spec.$case`). This is the same anti-pattern flagged in `knowledgeassistants.md` #10 (`sourceType: string` vs `spec.$case`). +### 3. `Tool.toolType: string` — stringly-typed when it is a closed set — `src/v1/model.ts:227-228` +- **Why weird:** The JSDoc enumerates the allowed values: `"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "dashboard", "serving_endpoint", "table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`. The type is `string`, so a caller writing `toolType: 'GENIE_SPACE'` (wrong case), `'genieSpace'` (camelCase), or `'web-search'` (kebab) gets no compiler help. The same struct *already* carries the discriminant in the `spec` discriminated union: `spec.$case` ranges over `'genieSpace' | 'knowledgeAssistant' | ...`. So the SDK declares the type domain twice, in two incompatible casings (snake on `toolType`, camel on `spec.$case`). Worse: the `toolType` enumeration in the doc includes 14 values while the `spec` discriminated union only covers 6 — the two declarations are not even aligned in cardinality. - **Category:** 16 (field contradicts type domain — `string` for a closed set), 6 (misleading — two declarations of the same enum), 12 (duplicate of `spec.$case`), 17 (snake vs camel for the same enum). -- **Suggested name:** Either (a) convert `toolType` to a string-literal union `'genieSpace' | 'knowledgeAssistant' | ...` matching `spec.$case`, or (b) drop `toolType` entirely because `spec.$case` already encodes it (recommended). +- **Suggested name:** Either (a) convert `toolType` to a string-literal union matching the enumerated wire values, or (b) drop `toolType` entirely because `spec.$case` already encodes the variants the SDK supports (recommended). - **Rationale:** Stringly-typed enums in TypeScript are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals). The duplicate declaration in two casings is a generator artifact from the proto definition and a tax on every consumer. -### 4. `Tool.toolType` casing disagrees with every other discriminator value on the wire — `src/v1/model.ts:259` -- **Why weird:** The 14 enumerated values inside the doc string are snake_case: `"genie_space"`, `"knowledge_assistant"`, `"lakeview_dashboard"`, `"serving_endpoint"`, `"uc_function"`, `"uc_connection"`, `"uc_table"`, `"vector_search_index"`, `"supervisor_agent"`, `"web_search"` (singletons `"app"`, `"volume"`, `"catalog"`, `"schema"` work in both). But the TypeScript `spec.$case` field uses camelCase variants of the same set: `'genieSpace'`, `'knowledgeAssistant'`, etc. The wire format for `toolType` is snake_case — but the consumer must know to write `toolType: 'genie_space'` while paying attention to camelCase `spec.$case`. A TypeScript-only consumer who never reads JSDoc will think the values are camelCase to match `$case` and get HTTP 400 on the first request. +### 4. `Tool.toolType` casing disagrees with every other discriminator value on the wire — `src/v1/model.ts:227` +- **Why weird:** The 14 enumerated values inside the doc string are snake_case: `"genie_space"`, `"knowledge_assistant"`, `"uc_function"`, `"uc_connection"`, `"serving_endpoint"`, `"vector_search_index"`, `"supervisor_agent"`, `"web_search"`, `"dashboard"`, `"table"` (singletons `"app"`, `"volume"`, `"catalog"`, `"schema"` work in both). But the TypeScript `spec.$case` field uses camelCase variants of its 6-element subset: `'genieSpace'`, `'knowledgeAssistant'`, etc. The wire format for `toolType` is snake_case — but the consumer must know to write `toolType: 'genie_space'` while paying attention to camelCase `spec.$case`. A TypeScript-only consumer who never reads JSDoc will think the values are camelCase to match `$case` and get HTTP 400 on the first request. - **Category:** 17 (casing inconsistency within the same struct), 4 (snake_case in a string-literal value, even though the value is on the wire). - **Suggested name:** If `toolType` survives (see #3), document inline that values are snake_case wire-side, or normalize to camelCase to match `spec.$case`. - **Rationale:** The mismatch is exactly what causes the most painful bugs in generated SDKs — the type checker says it is fine, the runtime fails. A naming audit must call this out even though it is a *value* mismatch rather than an *identifier* mismatch. -### 5. `KnowledgeAssistant` package name collision — `src/v1/model.ts:127` -- **Why weird:** The package `@databricks/sdk-supervisoragents` exports a type `KnowledgeAssistant` that represents *one variant of a Tool.spec discriminated union*, not the actual knowledge assistant resource. The actual `KnowledgeAssistant` resource lives in `@databricks/sdk-knowledgeassistants/v1`. A consumer importing both packages will collide on the same identifier in TS source — and the supervisor-agents type only has two fields (`servingEndpointName`, `knowledgeAssistantId`) while the real one has 12+. This is the same problem as #1/#2 but at the cross-package level. Compare with `LakeviewDashboard`, `Catalog`, `Schema`, `UcTable`, `VectorSearchIndex` — every variant uses an unqualified bare name that collides with the canonical resource type elsewhere in the SDK. +### 5. `KnowledgeAssistant` package name collision — `src/v1/model.ts:120` +- **Why weird:** The package `@databricks/sdk-supervisoragents` exports a type `KnowledgeAssistant` that represents *one variant of a Tool.spec discriminated union*, not the actual knowledge assistant resource. The actual `KnowledgeAssistant` resource lives in `@databricks/sdk-knowledgeassistants/v1`. A consumer importing both packages will collide on the same identifier in TS source — and the supervisor-agents type only has two fields (`servingEndpointName`, `knowledgeAssistantId`) while the real one has 12+. This is the same problem as #1/#2 but at the cross-package level. The same applies to `GenieSpace` (a single deprecated `id` field) vs the canonical Genie space resource elsewhere in the SDK. - **Category:** 12 (duplicate concept across packages), 6 (misleading — same name, different shape). -- **Suggested name:** `KnowledgeAssistantToolSpec`, `KnowledgeAssistantRef`, or `ToolKnowledgeAssistant`. Apply the suffix uniformly to all 14 variants (`GenieSpaceRef`, `LakeviewDashboardRef`, etc.). This is the same pattern the same package *already uses* for one variant: `SupervisorAgentTool` (the nested case), which uniquely calls out that it is a tool wrapper, not the resource itself. +- **Suggested name:** `KnowledgeAssistantToolSpec`, `KnowledgeAssistantRef`, or `ToolKnowledgeAssistant`. Apply the suffix uniformly to all 6 variants (`GenieSpaceRef`, `UcFunctionRef`, etc.). - **Rationale:** Cross-package name collisions are the worst kind of naming bug because the import path lies about the type's identity. A `Ref`/`ToolSpec` suffix on every variant solves this uniformly. -### 6. `SupervisorAgentTool` is the *only* variant with a name disambiguation — `src/v1/model.ts:246` -- **Why weird:** Of the 14 tool variants, exactly one uses the qualified naming convention: `SupervisorAgentTool` (the recursion case — a nested supervisor agent as a tool). Every other variant is bare: `GenieSpace`, `KnowledgeAssistant`, `UcFunction`, `LakeviewDashboard`, `App`, `Volume`, `ServingEndpoint`, `UcTable`, `VectorSearchIndex`, `UcConnection`, `Catalog`, `Schema`, `WebSearch`. The author of `SupervisorAgentTool` clearly recognized the collision problem (since `SupervisorAgent` is the top-level type in this very file) — but did not apply the same logic to the other 13 variants. This is inconsistency-by-omission. -- **Category:** 17 (inconsistency across sibling types), 8 (asymmetric suffix application). -- **Suggested name:** Either drop the `Tool` suffix from `SupervisorAgentTool` and find another way to disambiguate (probably not workable since it collides), or apply `*Tool` (or `*Ref`, `*ToolSpec`) to all 14 variants. See #5 for the recommended pattern. -- **Rationale:** When a generator picks one of two options for a single case, you can be sure the other 13 cases will look wrong. - -### 7. `Tool.spec` discriminated union name is generic — `src/v1/model.ts:262` +### 6. `Tool.spec` discriminated union name is generic — `src/v1/model.ts:230` - **Why weird:** `Tool.spec?: { $case: 'genieSpace'; genieSpace: GenieSpace } | ... | undefined`. The discriminator field is called `spec` — a generic CS term that does not convey *what kind* of specification this is. Same anti-pattern flagged in `knowledgeassistants.md` #12 (`KnowledgeSource.spec`). At a call site, `tool.spec.$case` is competing with the redundant `tool.toolType` (see #3) for "which kind of tool is this" semantics. Worse, `spec` is too short to autocomplete cleanly in many IDEs — and it collides with `Tool.toolType` JSDoc that calls the variants "tool types." - **Category:** 1 (vague/generic), 12 (duplicate of `toolType` discriminant). - **Suggested name:** `tool` (so `tool.tool.$case` — awkward) or `config` (matches the doc "Specification for the tool type") or `payload` or `kind` (a literal pun on the discriminant role). The cleanest fix is to flatten: drop `toolType` (per #3), rename `spec` → `tool`, and the type reads `agentTool.tool.$case`. - **Rationale:** A discriminated union should self-describe via its tag, not via a generic wrapper field. `spec` is the kind of name that survives only because nobody on the review can think of anything better. -### 8. `name` field overloaded — every CRUD request and every entity — `src/v1/model.ts:30,45,59,67,76,88,108,116,124,146,196,224,254,330` — fourteen sites -- **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`supervisor-agents/{id}` or `.../tools/{id}` or `.../examples/{id}`). Three different resource types share the same field name with three different formats — a consumer chaining operations across `SupervisorAgent`, `Tool`, and `Example` will have three `name`s in scope, all meaning different things. `DeleteToolRequest.name` and `DeleteSupervisorAgentRequest.name` have the same field name with disjoint URL contracts. Same problem documented in `knowledgeassistants.md` #7. Plus three sub-entity types (`Catalog`, `Schema`, `UcTable`, `Volume`, `UcFunction`, `UcConnection`, `App`, `ServingEndpoint`, `VectorSearchIndex`) each have a `name` field meaning "the wire identifier of the wrapped Databricks resource" — *not* a supervisor-agent resource name. So `tool.spec.catalog.name` and `tool.name` and `parent` (a resource path) are three different `name`-semantics in the same call site. +### 7. `name` field overloaded — every CRUD request and every entity — `src/v1/model.ts:11,20,35,50,58,66,78,101,109,117,198,224,246,251,260,288` — sixteen sites +- **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`supervisor-agents/{id}` or `.../tools/{id}` or `.../examples/{id}`). Three different resource types share the same field name with three different formats — a consumer chaining operations across `SupervisorAgent`, `Tool`, and `Example` will have three `name`s in scope, all meaning different things. `DeleteToolRequest.name` and `DeleteSupervisorAgentRequest.name` have the same field name with disjoint URL contracts. Same problem documented in `knowledgeassistants.md` #7. Plus the variant sub-entity types (`App`, `UcConnection`, `UcFunction`, `Volume`) each have a `name` field meaning "the wire identifier of the wrapped Databricks resource" — *not* a supervisor-agent resource name. So `tool.spec.app.name`, `tool.name`, and `parent` (a resource path) are three different `name`-semantics in the same call site. - **Category:** 1 (vague/generic), 15 (generic field name losing meaning), 19 (underspecified id). -- **Suggested name:** Type-qualify resource names: `supervisorAgentName` on `SupervisorAgent` and the supervisor-agent CRUD requests; `toolName` on `Tool` and tool requests; `exampleName` on `Example` and example requests. On the sub-resource types (`Catalog`, `Schema`, etc.), rename `name` → `fullName` (Unity Catalog convention) or `qualifiedName`. Alternatively follow AIP-122 (https://google.aip.dev/122) and keep `name` only on the type the request operates on; rename to `parent` when it identifies a parent (the package already does this for create/list — see #9). -- **Rationale:** This is the highest-frequency naming bug in the package — 14 sites use the same field name for at least four different semantic roles. +- **Suggested name:** Type-qualify resource names: `supervisorAgentName` on `SupervisorAgent` and the supervisor-agent CRUD requests; `toolName` on `Tool` and tool requests; `exampleName` on `Example` and example requests. On the sub-resource types (`App`, `UcConnection`, etc.), rename `name` → `fullName` (Unity Catalog convention) or `qualifiedName`. Alternatively follow AIP-122 (https://google.aip.dev/122) and keep `name` only on the type the request operates on; rename to `parent` when it identifies a parent (the package already does this for create/list — see #8). +- **Rationale:** This is the highest-frequency naming bug in the package — sixteen sites use the same field name for at least four different semantic roles. -### 9. `parent` and `name` describe the same wire concept inconsistently — `src/v1/model.ts:30,45,59,76,108,146,196` vs `src/v1/model.ts:67,116,124` -- **Why weird:** `CreateExampleRequest.parent`, `CreateToolRequest.parent`, `DeleteExampleRequest.name`, `DeleteSupervisorAgentRequest.name`, `DeleteToolRequest.name`, `GetExampleRequest.name`, `GetSupervisorAgentRequest.name`, `GetToolRequest.name`, `ListExamplesRequest.parent`, `ListToolsRequest.parent` all reference resource paths under `/supervisor-agents/{id}`. The Create + List requests correctly use `parent` per AIP-132 (https://google.aip.dev/132). The Delete + Get requests use `name`. So far consistent with AIP. But: `CreateExampleRequest.parent` is the *supervisor-agent* path, while `CreateExampleRequest.example.name` is the *new example* path. Reading the type, both fields are `string` and the JSDoc explains which is which — but the field names are not self-documenting. Compare with the audit on `knowledgeassistants.md` #8 (same pattern, same finding). +### 8. `parent` and `name` describe the same wire concept inconsistently — `src/v1/model.ts:20,35,133,183` vs `src/v1/model.ts:50,58,66,101,109,117,260` +- **Why weird:** `CreateExampleRequest.parent`, `CreateToolRequest.parent`, `DeleteExampleRequest.name`, `DeleteSupervisorAgentRequest.name`, `DeleteToolRequest.name`, `GetExampleRequest.name`, `GetSupervisorAgentRequest.name`, `GetToolRequest.name`, `ListExamplesRequest.parent`, `ListToolsRequest.parent`, `UpdateExampleRequest.name` all reference resource paths under `/supervisor-agents/{id}`. The Create + List requests correctly use `parent` per AIP-132 (https://google.aip.dev/132). The Delete + Get + Update requests use `name`. So far consistent with AIP. But: `CreateExampleRequest.parent` is the *supervisor-agent* path, while `CreateExampleRequest.example.name` is the *new example* path. Reading the type, both fields are `string` and the JSDoc explains which is which — but the field names are not self-documenting. Compare with the audit on `knowledgeassistants.md` #8 (same pattern, same finding). - **Category:** 17 (parent vs name inconsistency for related wire concepts). - **Suggested name:** Keep AIP-132 (`parent` on create/list, `name` on get/delete/update). Rename `parent` more specifically: `supervisorAgentName` on tool/example requests. The bigger fix is to use typed name strings (template-literal types) so `parent: ${SupervisorAgentName}` is checked at compile time. - **Rationale:** Same as `knowledgeassistants` — AIP-132 is the right convention, but the bare names lose type discipline. -### 10. `SupervisorAgent.id` is deprecated but still in the public TS surface — `src/v1/model.ts:231-232` -- **Why weird:** `id?: string` carries the JSDoc "Deprecated: Use supervisor_agent_id instead." (mind the wire-format leaking into the doc — `supervisor_agent_id` is the snake_case version, but the actual TS field is `supervisorAgentId`). The field is *not* marked `@deprecated` for the IDE, so consumers using IntelliSense will not see the strikethrough. The same issue applies to `Tool.id` (model.ts:257-258, same wording "Deprecated: Use tool_id instead.") and `KnowledgeAssistant.servingEndpointName` (model.ts:128-129, "Deprecated: use knowledge_assistant_id instead."). +### 9. `SupervisorAgent.id` is deprecated but still in the public TS surface — `src/v1/model.ts:205-206` +- **Why weird:** `id?: string` carries the JSDoc "Deprecated: Use supervisor_agent_id instead." (mind the wire-format leaking into the doc — `supervisor_agent_id` is the snake_case version, but the actual TS field is `supervisorAgentId`). The field is *not* marked `@deprecated` for the IDE, so consumers using IntelliSense will not see the strikethrough. The same issue applies to `Tool.id` (model.ts:225-226, same wording "Deprecated: Use tool_id instead."), `GenieSpace.id` (model.ts:88-92, "Deprecated: use space_id instead."), and `KnowledgeAssistant.servingEndpointName` (model.ts:121-122, "Deprecated: use knowledge_assistant_id instead."). - **Category:** 6 (misleading — deprecation is documented but not annotated), 8 (redundant suffix: keeping deprecated `id` *and* `supervisorAgentId` causes name clutter), 14 (the doc references the snake_case wire name rather than the TS name). -- **Suggested name:** Add `@deprecated` JSDoc tag so IDEs render it; doc should reference `supervisorAgentId` (the TS name) not `supervisor_agent_id` (the wire name); long-term plan for removal. Same fix on `Tool.id` and `KnowledgeAssistant.servingEndpointName`. +- **Suggested name:** Add `@deprecated` JSDoc tag so IDEs render it; doc should reference `supervisorAgentId` (the TS name) not `supervisor_agent_id` (the wire name); long-term plan for removal. Same fix on `Tool.id`, `GenieSpace.id`, and `KnowledgeAssistant.servingEndpointName`. - **Rationale:** Public-API deprecation has a standard JSDoc tag (https://jsdoc.app/tags-deprecated.html) that triggers IDE warnings. Free-text comment does not. -### 11. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:128-129` -- **Why weird:** The `KnowledgeAssistant` variant type (one of 14 tool kinds) has two fields: +### 10. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:121-122` +- **Why weird:** The `KnowledgeAssistant` variant type (one of 6 tool kinds) has two fields: - `servingEndpointName?: string` — doc "Deprecated: use knowledge_assistant_id instead." - `knowledgeAssistantId?: string` — doc "The ID of the knowledge assistant." Both fields are optional. A consumer setting both gets an ambiguous wire payload (the backend has to pick one). Plus, the field name `servingEndpointName` does not even *imply* "knowledge assistant" — it implies a model-serving endpoint. The naming of the deprecation target is also misleading: a knowledge assistant *id* is not necessarily the same wire value as a serving-endpoint *name*. The doc-comment claim that one replaces the other is suspect. @@ -94,102 +86,90 @@ Databricks resources. - **Suggested name:** Apply `@deprecated`; consider dropping the field entirely if `knowledgeAssistantId` fully supplants it. Document the migration mapping precisely. - **Rationale:** This is a deprecation transition mid-flight; the public TS surface should signal it correctly. -### 12. `SupervisorAgentTool.supervisorAgentId` doc says "tile ID" — `src/v1/model.ts:247-248` -- **Why weird:** Doc reads "The ID of the supervisor agent (tile ID)." The parenthetical "(tile ID)" refers to "tile" — a UI concept from Databricks Lakeview dashboards. A *Supervisor Agent* tool variant should not reference a dashboard concept. This appears to be a copy-paste from the dashboard tool spec (cf. `LakeviewDashboard.dashboardId`, model.ts:136). Same kind of doc-bug as flagged in `customllms.md` #5. -- **Category:** 6 (misleading — doc contradicts domain). -- **Suggested name:** Field name `supervisorAgentId` is fine; fix the JSDoc to drop "(tile ID)" and explain that this is the recursive reference to a child supervisor agent. -- **Rationale:** Doc-text bugs on identifiers are within scope of a naming audit; consumers learn semantics from JSDoc. - -### 13. `Catalog` / `Schema` collide with built-in TS and broader Databricks concepts — `src/v1/model.ts:19,210` -- **Why weird:** Two unqualified types `Catalog` and `Schema` represent UC catalog/schema *asset-search scopes* (a permissions concept), not the actual `catalog.CatalogInfo` / `catalog.SchemaInfo` resources from `@databricks/sdk-catalog`. The names are extremely overloaded: `Schema` is also a generic CS term (and shadows Zod's `z.ZodType`-related schema metadata), `Catalog` is a UC primary resource. A consumer importing this package + `catalog` will have to alias one of them. Same family of problem as #5 (cross-package collision). -- **Category:** 12 (duplicate concept across packages), 10 (reserved-word-ish; `Schema` is a near-reserved JS identifier in many libraries), 1 (vague). -- **Suggested name:** `CatalogAssetSearchScope` / `SchemaAssetSearchScope` (verbose but accurate), or `CatalogToolSpec` / `SchemaToolSpec` for the *Ref* convention from #5. -- **Rationale:** The current names lie about the type's identity. They look like the canonical UC resources but represent a permissions scope. - ## Medium severity -### 14. `SupervisorAgent.endpointName` is the agent's serving endpoint, not user-supplied — `src/v1/model.ts:239-240` +### 11. `SupervisorAgent.endpointName` is the agent's serving endpoint, not user-supplied — `src/v1/model.ts:213-214` - **Why weird:** Doc reads "The name of the supervisor agent's serving endpoint." This is a server-populated read-only field (the supervisor-agents backend creates a model-serving endpoint behind the scenes). The name `endpointName` does not tell the reader which kind of endpoint (model serving? vector search? SQL warehouse?). Same problem flagged in `knowledgeassistants.md` #21 and `customllms.md` #7. - **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or `agentServingEndpointName`. The variant type `KnowledgeAssistant` in this same file already uses `servingEndpointName` (model.ts:129) — so renaming here would *align* the two fields. +- **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or `agentServingEndpointName`. The variant type `KnowledgeAssistant` in this same file already uses `servingEndpointName` (model.ts:122) — so renaming here would *align* the two fields. - **Rationale:** Cross-package and within-package alignment; `servingEndpointName` is the canonical term. -### 15. `SupervisorAgent.experimentId` — what kind of experiment? — `src/v1/model.ts:241-242` +### 12. `SupervisorAgent.experimentId` — what kind of experiment? — `src/v1/model.ts:215-216` - **Why weird:** Doc reads "The MLflow experiment ID." A bare `experimentId` is fine *if* the consumer knows the SDK only integrates with MLflow. But the consumer reading `SupervisorAgent.experimentId` could reasonably guess this is an A/B-test experiment, a feature-flag experiment, or a generic experiment. Same problem flagged in `knowledgeassistants.md` #22 — and there the audit suggested `mlflowExperimentId`. - **Category:** 1 (vague), 19 (underspecified id), 17 (inconsistency with sibling SDK). - **Suggested name:** `mlflowExperimentId`. - **Rationale:** Cross-package consistency. The doc clarifies but the name does not. -### 16. `SupervisorAgent.creator: string` — what is a creator? — `src/v1/model.ts:235-236` +### 13. `SupervisorAgent.creator: string` — what is a creator? — `src/v1/model.ts:209-210` - **Why weird:** Doc reads "The creator of the Supervisor Agent." Could be a username, email, UUID, Databricks principal id, or service-principal client id. The type is `string`. Same field, same problem flagged in `knowledgeassistants.md` #24 and `customllms.md` #10. - **Category:** 1 (vague), 19 (underspecified id), 17 (SDK-wide inconsistency). - **Suggested name:** `createdBy` (AIP-148 standard, https://google.aip.dev/148, also matches `unitycatalog`). - **Rationale:** Match the most-used convention. Same recommendation as in three sibling audits. -### 17. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:237-238` +### 14. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:211-212` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `createTime` follows AIP-142 (https://google.aip.dev/142). Compare with `customllms.CustomLlm.creationTime: Temporal.Instant` (audited as inconsistent) — the supervisor-agents package uses the AIP form, the customllms package does not. This is positive consistency on supervisor-agents and negative on customllms. Flagging here because the audit covers SDK-wide consistency. - **Category:** Observation / 17 (cross-package inconsistency). - **Suggested name:** Keep `createTime`; flag `customllms` to align. - **Rationale:** Note positive precedent; pair with the audit on `customllms` to align it. -### 18. `SupervisorAgent.displayName` doc claims uniqueness — `src/v1/model.ts:225-226` +### 15. `SupervisorAgent.displayName` doc claims uniqueness — `src/v1/model.ts:199-200` - **Why weird:** Doc reads "The display name of the Supervisor Agent, unique at workspace level." Display names being unique at workspace level is a *semantic* claim — it might be enforced by the backend (with a 409 response on collision) or it might just be a soft convention. The type signature (`string`) gives no hint. AIP-122 reserves `displayName` for human-readable names that are explicitly *not* unique (https://google.aip.dev/122); a unique name is usually `name` or `id`. So this field is doing double duty: it is human-readable *and* uniquely identifying. Either rename or split. - **Category:** 6 (misleading — `displayName` implies non-unique). - **Suggested name:** If the uniqueness is enforced: rename to `key` or `humanReadableId` to communicate the uniqueness contract. If it is convention only: keep the name but soften the JSDoc. - **Rationale:** A field whose contract contradicts its conventional meaning is a footgun. -### 19. `SupervisorAgent.description` "user-facing" annotation — `src/v1/model.ts:227-228` -- **Why weird:** Doc reads "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Same observation flagged in `knowledgeassistants.md` #42. The same parenthetical appears on `Tool.description` (model.ts:298-299). +### 16. `SupervisorAgent.description` "user-facing" annotation — `src/v1/model.ts:201-202` +- **Why weird:** Doc reads "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Same observation flagged in `knowledgeassistants.md` #42. The same parenthetical appears on `Tool.description` (model.ts:238-239). - **Category:** Observation / 17 (inconsistent JSDoc style across SDK). - **Suggested name:** Drop "(user-facing)" from the two sites; flag for cross-package style review. - **Rationale:** Minor; cosmetic but worth aligning. -### 20. `SupervisorAgent.instructions` vs `Example.guidelines` — same overlap as flagged in `customllms.md` and `knowledgeassistants.md` — `src/v1/model.ts:229-230,91-92` +### 17. `SupervisorAgent.instructions` vs `Example.guidelines` — same overlap as flagged in `customllms.md` and `knowledgeassistants.md` — `src/v1/model.ts:203-204,82` - **Why weird:** `SupervisorAgent.instructions: string` (single, global) and `Example.guidelines: string[]` (array, per-example) follow the exact same naming doublet as `customllms.CustomLlm.instructions`/`guidelines` and `knowledgeassistants.KnowledgeAssistant.instructions`/`Example.guidelines`. Three packages, three near-identical confusing field-name pairs. The naming pattern is now SDK-wide. - **Category:** 6 (misleading), 12 (duplicate concept across SDK), 15 (generic field name). - **Suggested name:** Rename `SupervisorAgent.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerGuidelines` or `responseRules`. Apply uniformly across all three packages. - **Rationale:** Three packages flagged independently for the same pattern. SDK-wide cleanup opportunity. -### 21. `Tool.description` "user-facing" repeated annotation — `src/v1/model.ts:298-299` -- **Why weird:** Same as #19; the `Tool.description` has the same "(user-facing)" parenthetical. The doc reads "Description of what this tool does (user-facing)." If the audit prompt cares about consistency, both descriptions should match. +### 18. `Tool.description` "user-facing" repeated annotation — `src/v1/model.ts:238-239` +- **Why weird:** Same as #16; the `Tool.description` has the same "(user-facing)" parenthetical. The doc reads "Description of what this tool does (user-facing)." If the audit prompt cares about consistency, both descriptions should match. - **Category:** Observation / 17. -- **Suggested name:** Same as #19. +- **Suggested name:** Same as #16. -### 22. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:300-301` -- **Why weird:** Doc reads "User specified id of the Tool." Comparing with `CreateToolRequest.toolId` (model.ts:48-51, "The ID to use for the tool, which will become the final component of the tool's resource name."), the two `toolId` fields are *the same wire concept* — but on `Tool` it is the persisted id, while on `CreateToolRequest` it is the request-time supplied id. The same field name is doing two semantic jobs depending on context. Plus, comparing with `Example.exampleId` (model.ts:93-94, "The universally unique identifier (UUID) of the example."), the format claim differs: `Tool.toolId` is *user-specified*, `Example.exampleId` is a *UUID*. The two id formats are not aligned across sibling types in the same package. +### 19. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:240-241` +- **Why weird:** Doc reads "User specified id of the Tool." Comparing with `CreateToolRequest.toolId` (model.ts:37-41, "The ID to use for the tool, which will become the final component of the tool's resource name."), the two `toolId` fields are *the same wire concept* — but on `Tool` it is the persisted id, while on `CreateToolRequest` it is the request-time supplied id. The same field name is doing two semantic jobs depending on context. Plus, comparing with `Example.exampleId` (model.ts:83-84, "The universally unique identifier (UUID) of the example."), the format claim differs: `Tool.toolId` is *user-specified*, `Example.exampleId` is a *UUID*. The two id formats are not aligned across sibling types in the same package. - **Category:** 17 (inconsistency across sibling types), 6 (misleading — different format claims). - **Suggested name:** Keep `toolId` and `exampleId` but expand the JSDoc on each to disambiguate the id-format contract. Or rename `Tool.toolId` → `toolKey` to mirror that it is a user-supplied identifier (as opposed to a server-generated UUID). - **Rationale:** A naming audit must flag fields whose format contract is silent in the type signature. -### 23. `SupervisorAgent.supervisorAgentId` vs `SupervisorAgent.id` (deprecated) — both UUIDs — `src/v1/model.ts:231-234` -- **Why weird:** Two id fields on `SupervisorAgent`: the deprecated `id` and the canonical `supervisorAgentId`. Both are `string`, both UUIDs per the doc on line 233 ("The universally unique identifier (UUID) of the Supervisor Agent."). The deprecation is in JSDoc only (no `@deprecated` tag — see #10). Same situation on `Tool.id` vs `Tool.toolId` (model.ts:257-258, 300-301). Carrying the deprecated alias on the type forces consumers to handle both; the SDK should pick one. +### 20. `SupervisorAgent.supervisorAgentId` vs `SupervisorAgent.id` (deprecated) — both UUIDs — `src/v1/model.ts:205-208` +- **Why weird:** Two id fields on `SupervisorAgent`: the deprecated `id` and the canonical `supervisorAgentId`. Both are `string`, both UUIDs per the doc on line 207 ("The universally unique identifier (UUID) of the Supervisor Agent."). The deprecation is in JSDoc only (no `@deprecated` tag — see #9). Same situation on `Tool.id` vs `Tool.toolId` (model.ts:225-226, 240-241). Carrying the deprecated alias on the type forces consumers to handle both; the SDK should pick one. - **Category:** 8 (redundant alias suffix), 12 (duplicate concept within the same type). - **Suggested name:** Mark `id` `@deprecated`; document that `supervisorAgentId` is canonical. Future major version removes `id` entirely. - **Rationale:** Carrying a deprecated alias on a TS type is a tax on every reader. Mark it loudly. -### 24. `SupervisorAgent.supervisorAgentId` type-suffix tautology — `src/v1/model.ts:233-234` +### 21. `SupervisorAgent.supervisorAgentId` type-suffix tautology — `src/v1/model.ts:207-208` - **Why weird:** `SupervisorAgent.supervisorAgentId` repeats `SupervisorAgent` in the type name and field. The pattern is correct AIP-style (every entity has `*Id` matching its type) but extremely verbose. Once `SupervisorAgent` is renamed to `RouterAgent` (per #1), the field becomes `routerAgentId` — slightly shorter, still type-tautological. - **Category:** 20 (type-suffix tautology). - **Suggested name:** Keep current (tradeoff with cross-type disambiguation), but document the convention in `typescript.mdc`. - **Rationale:** This is a convention question, not a bug. The verbose form *does* disambiguate from `Tool.toolId` and `Example.exampleId` when passed to a generic function. Flagged for awareness. -### 25. `Example.exampleId` type-suffix tautology — `src/v1/model.ts:93-94` -- **Why weird:** Same shape as #24, but the field is `exampleId` and the type is `Example`. The redundancy is identical. Note: every sibling SDK package follows the same convention (`knowledgeassistants.Example.exampleId` is the same pattern). +### 22. `Example.exampleId` type-suffix tautology — `src/v1/model.ts:83-84` +- **Why weird:** Same shape as #21, but the field is `exampleId` and the type is `Example`. The redundancy is identical. Note: every sibling SDK package follows the same convention (`knowledgeassistants.Example.exampleId` is the same pattern). - **Category:** 20 (type-suffix tautology). - **Suggested name:** Keep current; document the convention. -### 26. `Tool.toolId` type-suffix tautology — `src/v1/model.ts:300-301` -- **Why weird:** Same pattern as #24, #25. +### 23. `Tool.toolId` type-suffix tautology — `src/v1/model.ts:240-241` +- **Why weird:** Same pattern as #21, #22. - **Category:** 20. - **Suggested name:** Keep current; document the convention. -### 27. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:48-51` +### 24. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:37-41` - **Why weird:** The create request takes both `tool: Tool` (the body) *and* `toolId: string` (the URL/query param). The wire form is `POST /supervisor-agents/{id}/tools?tool_id={user-supplied}`. So `req.toolId` flows into the query string and `req.tool.toolId` is *not used* on creation — but TypeScript does not enforce this. A consumer who writes `{tool: {toolId: 'foo'}}` and leaves `req.toolId` undefined gets unexpected behavior. The two-fields-for-one-concept pattern is also documented in `customllms.md` #20. - **Category:** 12 (duplicate concept on the same request), 6 (misleading — `tool.toolId` looks usable on creation but isn't), 17. - **Suggested name:** Either remove `tool.toolId` from the body shape (TypeScript can enforce this via a discriminated `Omit` type for create), or document the precedence rule on the JSDoc. - **Rationale:** Generated request types with duplicate fields are a well-known footgun. -### 28. `Client` class name — bare, no scoping — `src/v1/client.ts:61` +### 25. `Client` class name — bare, no scoping — `src/v1/client.ts:61` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-supervisoragents/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as SAClient} from '@databricks/sdk-supervisoragents/v1'`. Same SDK-wide issue flagged in `knowledgeassistants.md` #30. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `SupervisorAgentsClient` (matches the Go SDK's `WorkspaceClient.SupervisorAgents` and AWS SDK's `S3Client`, `IAMClient` pattern). @@ -197,59 +177,37 @@ Databricks resources. ## Low severity -### 29. `Volume`/`UcFunction`/`UcConnection`/`UcTable` — `Uc` prefix on some, bare on others — `src/v1/model.ts:304,308,318,364` -- **Why weird:** Of the variant types, four are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`, `UcTable`. The `Uc` prefix is applied to three but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). +### 26. `Volume`/`UcFunction`/`UcConnection` — `Uc` prefix on some, bare on others — `src/v1/model.ts:245,249,286` +- **Why weird:** Of the variant types, three are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`. The `Uc` prefix is applied to two but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). - **Category:** 3 (acronym casing — `Uc` vs `UC`), 17 (inconsistent prefix application — `Volume` should be `UcVolume`). -- **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection`, `UcTable` (with the acronym-casing question decided once SDK-wide). +- **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection` (with the acronym-casing question decided once SDK-wide). - **Rationale:** Consistency wins; the audit prompt rule 3 (acronym casing) and rule 17 (consistent action verbs / family naming) both flag this. -### 30. `LakeviewDashboard` — product name leaks into type name — `src/v1/model.ts:135` -- **Why weird:** "Lakeview" is the marketing name for Databricks SQL dashboards (https://docs.databricks.com/en/dashboards/index.html). The type name carries the product name. If the product is renamed (as has happened — "Lakeview" has been deprecated in some Databricks branding in favor of "Dashboards"), the SDK will be stuck with the old name. Cross-package: the dashboards SDK at `packages/dashboards/` uses `LakeviewDashboard` too — so the SDK is consistent, but the question is whether the canonical name should propagate. -- **Category:** Observation / 6 (potentially misleading if product is rebranded). -- **Suggested name:** Keep `LakeviewDashboard` (the wire name is fixed) but document the marketing-name origin. -- **Rationale:** Naming audits should flag product-name leakage even if there's no fix. - -### 31. `Catalog`, `Schema`, `UcTable` fields all named `name` but doc differently — `src/v1/model.ts:21,212,321` -- **Why weird:** Three variant types with a single `name` field carrying three subtly different format claims: - - `Catalog.name`: "Bare UC catalog name this tool is authorized to search (no `.`)." — one component. - - `Schema.name`: "Full UC schema name (catalog.schema) this tool is authorized to search." — two components. - - `UcTable.name`: "Full UC table name (catalog.schema.table) this tool is authorized to access." — three components. - Three sibling types use the same field name `name` to mean three different cardinalities (1-, 2-, 3-part UC names). A consumer scripting "set the tool name from a user input" gets no compiler help. -- **Category:** 15 (generic field name losing meaning), 6 (misleading — same name, different format), 17. -- **Suggested name:** Differentiate: `Catalog.catalogName` (one part), `Schema.schemaFullName` (two parts), `UcTable.tableFullName` (three parts). Or use AIP-style `fullName` on each but document the cardinality explicitly. -- **Rationale:** Three types with the same field name representing different formats is exactly the kind of inconsistency that bites at code-review time. - -### 32. `VectorSearchIndex.columns` semantic ambiguity — `src/v1/model.ts:357-361` -- **Why weird:** Doc reads "Optional columns to return from the index. If unset, discovered from index schema at query time." So `columns` is a list of column names to *project* in the response — but the field name does not communicate "to return" vs "to filter on" vs "to embed." A consumer scanning the type sees `columns?: string[]` and reasonably wonders whether these are the *output* columns or the *input* columns to vectorize. The doc is the only disambiguator. -- **Category:** 1 (vague), 6 (misleading — name does not encode return-vs-filter direction). -- **Suggested name:** `returnedColumns` or `outputColumns` (or `projection`, a SQL term). -- **Rationale:** The doc gives the contract; the field name should too. - -### 33. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +### 27. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21 and `knowledgeassistants.md` #34. Each generated package carries the same pair. - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than one infix. -### 34. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +### 28. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` - **Why weird:** Same as `customllms.md` #23 and `knowledgeassistants.md` #35: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in scope simultaneously. Three things named `Options`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams`. - **Rationale:** Distinguish internal context bags from user-facing options. -### 35. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 29. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `customllms.md` #28 and `knowledgeassistants.md` #36: exported but not used by `client.ts`. Generator-mechanical surface area. - **Category:** Observation / (unused export). - **Suggested name:** Either remove the export or document why it ships per-package. - **Rationale:** Generated artifact; flag for cross-package cleanup. -### 36. `readAll` helper generic name — `src/v1/utils.ts:40` +### 30. `readAll` helper generic name — `src/v1/utils.ts:40` - **Why weird:** Same as `customllms.md` #29 and `knowledgeassistants.md` #37: helper reads an entire response body stream; name is generic. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 37. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` +### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` - **Why weird:** Same as `customllms.md` #24 and `knowledgeassistants.md` #38: `Segment` is a generic CS term. - **Category:** 1 (vague). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -257,45 +215,55 @@ Databricks resources. ## Observations -### 38. `resp` local variable in every method — `src/v1/client.ts:93,122,154,242,267,289,323,374,428,477,521,562` -- **Why weird:** Same as `customllms.md` #33 and `knowledgeassistants.md` #39: `resp` is the response. 12 methods repeat the same pattern. +### 32. `resp` local variable in every method — `src/v1/client.ts:93,122,154,242,267,289,323,374,428,477,521,562` +- **Why weird:** Same as `customllms.md` #33 and `knowledgeassistants.md` #39: `resp` is the response. Twelve methods repeat the same pattern. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. - **Rationale:** Refactor opportunity surfaced by audit. -### 39. `pageReq` local in iterator methods — `src/v1/client.ts:346,400,451` +### 33. `pageReq` local in iterator methods — `src/v1/client.ts:346,400,451` - **Why weird:** Same as `knowledgeassistants.md` #40: three async generator methods declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. - **Category:** 5 (abbreviation). - **Suggested name:** `pageRequest` or `nextPageReq`. -### 40. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:977-1015` -- **Why weird:** The field-mask carries top-level entries for each variant of the `spec` union — `app`, `catalog`, `genieSpace`, `knowledgeAssistant`, `lakeviewDashboard`, `schema`, `servingEndpoint`, `supervisorAgent`, `ucConnection`, `ucFunction`, `ucTable`, `vectorSearchIndex`, `volume`, `webSearch`. The field-mask flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. +### 34. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:656-674` +- **Why weird:** The field-mask carries top-level entries for each variant of the `spec` union — `app`, `genieSpace`, `knowledgeAssistant`, `ucConnection`, `ucFunction`, `volume`. The field-mask flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. - **Category:** 17 (inconsistency between TS shape and field-mask). - **Suggested name:** No rename; document on the JSDoc. -### 41. The 14 tool kinds + 1 nested = effectively 15 kinds — `src/v1/model.ts:262-297` -- **Why weird:** The doc on `Tool.toolType` (model.ts:259) lists 14 kinds, but the discriminated union on `Tool.spec` (model.ts:262-297) also has 14 cases. Counting carefully: `genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `lakeviewDashboard`, `servingEndpoint`, `ucTable`, `vectorSearchIndex`, `ucConnection`, `catalog`, `schema`, `supervisorAgent`, `webSearch` — that is 14, and matches the doc. So the count is correct; flagged here as a *positive* observation. +### 35. `Tool.toolType` doc lists 14 kinds but `Tool.spec` union covers only 6 — `src/v1/model.ts:227,230-237` +- **Why weird:** The JSDoc on `Tool.toolType` enumerates 14 wire values (`"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "dashboard", "serving_endpoint", "table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`), but the `Tool.spec` discriminated union only encodes 6 of them (`genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `ucConnection`). The other 8 wire kinds — dashboard, serving_endpoint, table, vector_search_index, catalog, schema, supervisor_agent, web_search — can be set via `toolType` but have no corresponding `spec` variant. A consumer who writes `{toolType: 'dashboard'}` gets no type-system support for the dashboard payload because the variant doesn't exist. Either the backend has dropped those kinds (and the doc should be updated) or the TS surface is missing variants. +- **Category:** 16 (field contradicts type domain), 17 (doc vs type-shape mismatch), 6 (misleading). +- **Suggested name:** Reconcile the two declarations: either add the missing variants to `Tool.spec` or shrink the `toolType` enumeration to the supported subset. -### 42. Action verbs in `Client` are consistent — `src/v1/client.ts` +### 36. Action verbs in `Client` are consistent — `src/v1/client.ts` - **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. - **Category:** 17 (reversed — consistency note). -### 43. Method-name verb conventions match resource targets — `src/v1/client.ts:87,113,142,180,199,218,237,262,287,309,360,414,465,506,550` +### 37. Method-name verb conventions match resource targets — `src/v1/client.ts:87,113,142,180,199,218,237,262,287,309,360,414,465,506,550` - **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. - **Category:** 17 (positive observation). +## Fixed + +- #6 `SupervisorAgentTool` (originally cited at `src/v1/model.ts:246`): Fixed in regeneration on 2026-05-20 — the recursion-case tool variant was removed from the `Tool.spec` discriminated union; no other variants use a `*Tool` suffix anymore. +- #12 `SupervisorAgentTool.supervisorAgentId` "tile ID" doc bug (originally cited at `src/v1/model.ts:247-248`): Fixed in regeneration on 2026-05-20 — `SupervisorAgentTool` was removed from the package, taking the misleading doc with it. +- #13 `Catalog` / `Schema` cross-package collision (originally cited at `src/v1/model.ts:19,210`): Fixed in regeneration on 2026-05-20 — both `Catalog` and `Schema` types are no longer in the package; the `Tool.spec` union no longer carries those variants. +- #30 `LakeviewDashboard` product-name leakage (originally cited at `src/v1/model.ts:135`): Fixed in regeneration on 2026-05-20 — the `LakeviewDashboard` type was removed from the package. +- #31 `Catalog`/`Schema`/`UcTable` `name`-field cardinality drift (originally cited at `src/v1/model.ts:21,212,321`): Fixed in regeneration on 2026-05-20 — all three types are gone, so the differing 1-/2-/3-part `name` semantics are no longer in this package. +- #32 `VectorSearchIndex.columns` semantic ambiguity (originally cited at `src/v1/model.ts:357-361`): Fixed in regeneration on 2026-05-20 — the `VectorSearchIndex` type was removed from the package. +- #41 14 tool kinds = positive observation (originally cited at `src/v1/model.ts:262-297`): Fixed in regeneration on 2026-05-20 — the count is no longer accurate (the union now has 6 variants while the doc still lists 14), so the positive observation no longer holds. Superseded by new finding #35 (doc vs union-shape mismatch). + ## Domain glossary - `supervisor agent` — the LLM router resource that orchestrates calls to tools (sub-agents). The package name and primary resource. Per the audit's prompt: `Supervisor + Agent` together describe "a top-level routing agent that delegates user requests to specialized child tools." Each agent has a serving endpoint and an MLflow experiment. -- `tool` — a typed reference to another Databricks resource (or a built-in capability like web search) that the supervisor agent can invoke. 14 kinds via `Tool.spec` discriminated union. +- `tool` — a typed reference to another Databricks resource (or a built-in capability like web search) that the supervisor agent can invoke. 6 kinds via `Tool.spec` discriminated union; the `toolType` doc enumerates more kinds that lack corresponding spec variants. - `example` — a question + guidelines pair that steers the agent's response on similar questions. Sub-resource of a supervisor agent. -- `uc` — Unity Catalog. Used as a prefix for four variant types (`UcFunction`, `UcConnection`, `UcTable`) and referenced in doc strings for `Catalog`, `Schema`, `Volume`, `VectorSearchIndex`. +- `uc` — Unity Catalog. Used as a prefix for variant types (`UcFunction`, `UcConnection`). - `genie` — Databricks Genie, the AI-driven analytics product. `GenieSpace` is the container resource. -- `lakeview` — the historical name for Databricks SQL Dashboards. `LakeviewDashboard` carries the product name. -- `asset_search` — a UC permission scope (per `Catalog` / `Schema` doc strings): a search capability over catalogs/schemas. - `mcp` — Model Context Protocol (referenced in `App` doc "Supported app: custom mcp, custom agent."). MCP servers can be deployed as Databricks Apps. ## File coverage -- `src/v1/model.ts` (1043 lines): read fully. +- `src/v1/model.ts` (691 lines): read fully. - `src/v1/client.ts` (587 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (44 lines): read fully. +- `src/v1/index.ts` (36 lines): read fully. diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index a6c9280b..e97f954a 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -3,12 +3,12 @@ **Path:** `packages/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 14 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 4 | | Medium | 5 | | Low | 2 | | Observation | 2 | @@ -21,57 +21,51 @@ - **Suggested name:** Either fold `systemschemas` into `schemas` as a `system` sub-namespace (`@databricks/sdk-schemas/system`), or rename to something less collision-prone such as `unityCatalogSystemSchemas` / `metastoreSystemSchemas`. - **Rationale:** The two packages export different `Client` classes; the domain word `Schema` appears in both with overlapping vocabulary. Anything that lessens that overlap — even just keeping them under one package — would reduce caller confusion. -### 2. `DisableSystemSchema` — `src/v1/model.ts:5` -- **Why weird:** Type name is a verb phrase that looks like a function. The same broken pattern is repeated for `EnableSystemSchema` (model.ts:15) and `ListSystemSchemas` (model.ts:27). Index re-exports these as types, so consumers write `import type {DisableSystemSchema}` which reads as "import a function". -- **Category:** 6 (misleading: name implies behaviour, actually a request DTO), 14 (Go-style naming). -- **Suggested name:** `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, `ListSystemSchemasRequest`. -- **Rationale:** TS convention names request DTOs with a `Request` suffix; verb-phrase nouns mislead. This mirrors the same audit finding in every other generated package. - -### 3. `SystemSchemaInfo` — `src/v1/model.ts:53` +### 2. `SystemSchemaInfo` — `src/v1/model.ts:53` - **Why weird:** `Info` is a generic, content-free suffix on the package's central domain entity. This is *the* system schema — it should just be `SystemSchema`. The `Info` suffix is on the vague-suffix list in `typescript.mdc`. It also infects the field name (`schemas: SystemSchemaInfo[]`) which awkwardly reads as "an array of info". - **Category:** 1 (vague `Info`), 8 (redundant type suffix). - **Suggested name:** `SystemSchema`. - **Rationale:** `SystemSchema` is the noun consumers think about. `schemas: SystemSchema[]` reads cleanly; `schemas: SystemSchemaInfo[]` does not. -### 4. `SystemSchemaInfo.state: string` — `src/v1/model.ts:60` +### 3. `SystemSchemaInfo.state: string` — `src/v1/model.ts:60` - **Why weird:** Typed as `string` despite the doc enumerating six concrete values (`AVAILABLE | ENABLE_INITIALIZED | ENABLE_COMPLETED | DISABLE_INITIALIZED | UNAVAILABLE | MANAGED`). This is the package's only enum-shaped field and the only piece of state the consumer reads back, yet it ships as a stringly-typed value. Every other package in the SDK exposes such fields as TS enums. The comment "An empty string means the system schema is available and ready for opt-in" further muddles things — it contradicts `AVAILABLE` being one of the listed values. - **Category:** 16 (field type contradicts the documented domain), 6 (misleading — doc says enum, type says `string`). - **Suggested name:** Introduce `SystemSchemaState` enum with members `Available | EnableInitialized | EnableCompleted | DisableInitialized | Unavailable | Managed` and type the field `state: SystemSchemaState`. - **Rationale:** Almost certainly a generator/upstream-API miss; the wire surface is enum-shaped and should round-trip through a TS enum. Worth raising upstream. -### 5. `schema` field on every request/response — `src/v1/model.ts:7,17,55` -- **Why weird:** Field is bare `schema: string` on `DisableSystemSchema`, `EnableSystemSchema`, and `SystemSchemaInfo`. Doc on the first two says "Full name of the system schema" while the doc on `SystemSchemaInfo` (model.ts:54) says "Name of the system schema". So the same field name carries two different semantics (full-qualified vs short name) across two types that ship in the same module. Also collides with the type name (`SystemSchema`) and the package name (`systemschemas`), making greps unhelpful. +### 4. `schema` field on every request/response — `src/v1/model.ts:7,17,55` +- **Why weird:** Field is bare `schema: string` on `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, and `SystemSchemaInfo`. Doc on the first two says "Full name of the system schema" while the doc on `SystemSchemaInfo` (model.ts:54) says "Name of the system schema". So the same field name carries two different semantics (full-qualified vs short name) across two types that ship in the same module. Also collides with the type name (`SystemSchema`) and the package name (`systemschemas`), making greps unhelpful. - **Category:** 1 (vague — what kind of "schema"?), 6 (misleading — same field name, different meaning), 19 (underspecified id). - **Suggested name:** Pick one of `schemaName` / `systemSchemaName` / `name` and apply it consistently. If the wire is `schema` (string), keep the wire and rename the TS surface; the marshaller already handles the gap for other fields. - **Rationale:** The URL template `.../systemschemas/${req.schema ?? ''}` (client.ts:75) confirms `schema` is in fact an identifier slug. Calling it `schemaName` or `name` makes intent obvious; bare `schema` collides with everything. ## Medium severity -### 6. `DisableSystemSchema.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` -- **Why weird:** Marked optional, but `client.ts:75` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchema.metastoreId`, `DisableSystemSchema.schema`, `EnableSystemSchema.schema`, `ListSystemSchemas.metastoreId`. +### 5. `DisableSystemSchemaRequest.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` +- **Why weird:** Marked optional, but `client.ts:75` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchemaRequest.metastoreId`, `DisableSystemSchemaRequest.schema`, `EnableSystemSchemaRequest.schema`, `ListSystemSchemasRequest.metastoreId`. - **Category:** 6 (misleading optionality), 16 (field type contradicts domain — these are mandatory path params). - **Suggested name:** Keep names; change type to non-optional. (Out of scope for a *naming* audit, but the optionality leaks into how the names should be interpreted.) - **Rationale:** Path-required fields must be required. Treating them as optional weakens the contract; the name `metastoreId` reads as "the metastore id" but the type says "you can omit this". -### 7. `SystemSchemaInfo.schema: string` (required) vs `EnableSystemSchema.schema: string | undefined` (optional) — `src/v1/model.ts:55,17` +### 6. `SystemSchemaInfo.schema: string` (required) vs `EnableSystemSchemaRequest.schema: string | undefined` (optional) — `src/v1/model.ts:55,17` - **Why weird:** Same field name, opposite optionality, same module. The reader has to keep two mental versions of `schema` in their head. - **Category:** 17 (inconsistency in field shape between sibling types). -- **Suggested name:** Same as #5 — rename one or both and unify optionality where possible. +- **Suggested name:** Same as #4 — rename one or both and unify optionality where possible. - **Rationale:** Symmetry across request/response pairs improves readability; identical names with diverging contracts do not. -### 8. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` +### 7. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate intent. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; flagged for cross-SDK consistency since the same constant appears in every generated client. -### 9. `Client` — `src/v1/client.ts:42` +### 8. `Client` — `src/v1/client.ts:42` - **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `SystemSchemasClient`. - **Rationale:** Forces consumers to alias on import (`import {Client as SystemSchemasClient}`) if they ever combine clients. Every generated package has this issue; flagged for consistency. -### 10. `ListSystemSchemas.maxResults` doc semantics — `src/v1/model.ts:31-36` +### 9. `ListSystemSchemasRequest.maxResults` doc semantics — `src/v1/model.ts:31-37` - **Why weird:** Field is named `maxResults` but the doc describes three semantically distinct modes (0 = server default, >0 = bounded, <0 = error) and one quirky default (not set = "all", "not recommended"). The name "maxResults" implies an upper bound, not a tri-state control. Same pattern in every other List request, but here the doc highlights how overloaded the name is. - **Category:** 6 (misleading — name suggests a single integer cap), 1 (vague). - **Suggested name:** `pageSize` (matching most modern paginated APIs) and let the value 0 mean "server default". Drop the negative-error branch entirely. @@ -79,13 +73,13 @@ ## Low severity -### 11. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:182` -- **Why weird:** `listSystemSchemasIter` (client.ts:182) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. +### 10. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:185` +- **Why weird:** `listSystemSchemasIter` (client.ts:185) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). - **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. - **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. -### 12. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 11. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ by a single `Http` infix, handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -93,10 +87,10 @@ ## Observations -### 13. Action-verb consistency in `Client` +### 12. Action-verb consistency in `Client` Methods are `disable`, `enable`, `list` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. -### 14. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod +### 13. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), the package name (`systemschemas`), and a library term (zod's `Schema`). Multiple overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. - **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). @@ -110,6 +104,9 @@ The word "schema" appears in this single package as a wire field, a domain noun ## File coverage - `src/v1/model.ts` (106 lines): read fully. -- `src/v1/client.ts` (188 lines): read fully. +- `src/v1/client.ts` (191 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (16 lines): read fully. + +## Fixed +- #2 `DisableSystemSchema` / `EnableSystemSchema` / `ListSystemSchemas` (originally cited at `src/v1/model.ts:5,15,27`): Fixed in regeneration on 2026-05-20 — verb-phrase request DTOs renamed to `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, `ListSystemSchemasRequest`. diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index de867fb4..1b5c5eb0 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -15,8 +15,7 @@ - `catalogs/v1` — also defines `EffectivePredictiveOptimizationFlag`. - `functions/v1`, `registeredmodels/v1` — also define the entire `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / - `ConnectionDependency` / `CredentialDependency` / `VolumeDependency` / - `SecretDependency` family. + `ConnectionDependency` / `CredentialDependency` family. - `functions/v1` — also exports `ColumnTypeName`. - `abacpolicies/v1` — defines `RowFilterOptions` / `ColumnMaskOptions` which duplicate the role of this package's `RowFilter` / `ColumnMask`. @@ -34,12 +33,12 @@ ### Enums (model.ts) -1. `ColumnTypeName` (model.ts:5) — 27 values: `BOOLEAN`, `BYTE`, `SHORT`, +1. `ColumnTypeName` (model.ts:5) — 24 values: `BOOLEAN`, `BYTE`, `SHORT`, `INT`, `LONG`, `FLOAT`, `DOUBLE`, `DATE`, `TIMESTAMP`, `STRING`, `BINARY`, `DECIMAL`, `INTERVAL`, `ARRAY`, `STRUCT`, `MAP`, `CHAR`, `NULL`, `USER_DEFINED_TYPE`, `TIMESTAMP_NTZ`, `VARIANT`, `GEOMETRY`, `GEOGRAPHY`, - `TIME`, `FILE`, `TABLE_TYPE`, `TABLEREF_TYPE`. -2. `DataSourceFormat` (model.ts:36) — 26 values, most suffixed `_FORMAT`: + `TABLE_TYPE`. +2. `DataSourceFormat` (model.ts:33) — 26 values, most suffixed `_FORMAT`: `DELTA`, `CSV`, `JSON`, `AVRO`, `PARQUET`, `ORC`, `TEXT`, `UNITY_CATALOG`, `DELTASHARING`, `DATABRICKS_FORMAT`, `MYSQL_FORMAT`, `ORACLE_FORMAT`, `POSTGRESQL_FORMAT`, `REDSHIFT_FORMAT`, `SNOWFLAKE_FORMAT`, `SQLDW_FORMAT`, @@ -48,108 +47,84 @@ `WORKDAY_RAAS_FORMAT`, `MONGODB_FORMAT`, `HIVE`, `VECTOR_INDEX_FORMAT`, `DATABRICKS_ROW_STORE_FORMAT`, `DELTA_UNIFORM_HUDI`, `DELTA_UNIFORM_ICEBERG`, `ICEBERG`. -3. `SecurableKind` (model.ts:81) — 70+ values, all prefixed with one of +3. `SecurableKind` (model.ts:78) — 70+ values, all prefixed with one of `TABLE_`, `RECIPIENT_`, `CONNECTION_`, `CATALOG_`, `SCHEMA_`. -4. `SecurableType` (model.ts:182) — 17 values: `CATALOG`, `SCHEMA`, `TABLE`, +4. `SecurableType` (model.ts:162) — 17 values: `CATALOG`, `SCHEMA`, `TABLE`, `STORAGE_CREDENTIAL`, `EXTERNAL_LOCATION`, `FUNCTION`, `SHARE`, `PROVIDER`, `RECIPIENT`, `CLEAN_ROOM`, `METASTORE`, `PIPELINE`, `VOLUME`, `CONNECTION`, `CREDENTIAL`, `EXTERNAL_METADATA`, `STAGING_TABLE`. -5. `SseEncryptionAlgorithm` (model.ts:203) — 3 values: +5. `SseEncryptionAlgorithm` (model.ts:183) — 3 values: `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`, `AWS_SSE_S3`, `AWS_SSE_KMS`. -6. `TableType` (model.ts:209) — 9 values: `MANAGED`, `EXTERNAL`, `VIEW`, +6. `TableType` (model.ts:189) — 9 values: `MANAGED`, `EXTERNAL`, `VIEW`, `MATERIALIZED_VIEW`, `STREAMING_TABLE`, `MANAGED_SHALLOW_CLONE`, `FOREIGN`, `EXTERNAL_SHALLOW_CLONE`, `METRIC_VIEW`. -7. `OptionSpec_OauthStage` (model.ts:229) — 3 values: +7. `OptionSpec_OauthStage` (model.ts:209) — 3 values: `OAUTH_STAGE_UNSPECIFIED`, `BEFORE_AUTHORIZATION_CODE`, `BEFORE_ACCESS_TOKEN`. -8. `OptionSpec_OptionType` (model.ts:242) — 9 values: +8. `OptionSpec_OptionType` (model.ts:222) — 8 values: `OPTION_TYPE_UNSPECIFIED`, `OPTION_BOOLEAN`, `OPTION_NUMBER`, `OPTION_BIGINT`, `OPTION_STRING`, `OPTION_ENUM`, - `OPTION_SERVICE_CREDENTIAL`, `OPTION_MULTILINE_STRING`, - `OPTION_STORAGE_CREDENTIAL`. + `OPTION_SERVICE_CREDENTIAL`, `OPTION_MULTILINE_STRING`. ### Interfaces (model.ts) -1. `ColumnInfo` (model.ts:254) — 12 fields (`name`, `typeText`, `typeName`, +1. `ColumnInfo` (model.ts:233) — 12 fields (`name`, `typeText`, `typeName`, `position`, `typePrecision`, `typeScale`, `typeIntervalType`, `typeJson`, `comment`, `nullable`, `partitionIndex`, `mask`). -2. `ColumnMask` (model.ts:279) — 3 fields. -3. `ConditionalDisplay` (model.ts:305) — 2 fields. -4. `ConnectionDependency` (model.ts:317) — 1 field. -5. `CreateTable` (model.ts:322) — 38 fields. -6. `CreateTable_PropertiesEntry` (model.ts:394) — 2 fields. -7. `CreateTableConstraint` (model.ts:399) — 2 fields. -8. `CredentialDependency` (model.ts:406) — 1 field. -9. `DeleteTable` (model.ts:411) — 1 field. -10. `DeleteTable_Response` (model.ts:417) — empty body. -11. `DeleteTableConstraint` (model.ts:419) — 3 fields. -12. `DeleteTableConstraint_Response` (model.ts:432) — empty body. -13. `DeltaRuntimePropertiesKvPairs` (model.ts:438) — 1 field. -14. `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` - (model.ts:444) — 2 fields. -15. `Dependency` (model.ts:453) — discriminated union (table / function / - connection / credential / volume / secret). -16. `DependencyList` (model.ts:473) — 1 field. -17. `EffectivePredictiveOptimizationFlag` (model.ts:478) — 3 fields. -18. `EncryptionDetails` (model.ts:488) — discriminated union (one variant: +2. `ColumnMask` (model.ts:258) — 3 fields. +3. `ConnectionDependency` (model.ts:276) — 1 field. +4. `CreateTableConstraintRequest` (model.ts:281) — 2 fields. +5. `CreateTableRequest` (model.ts:287) — 38 fields. +6. `CreateTableRequest_PropertiesEntry` (model.ts:359) — 2 fields. +7. `CredentialDependency` (model.ts:365) — 1 field. +8. `DeleteTableConstraintRequest` (model.ts:370) — 3 fields. +9. `DeleteTableConstraintRequest_Response` (model.ts:383) — empty body. +10. `DeleteTableRequest` (model.ts:385) — 1 field. +11. `DeleteTableRequest_Response` (model.ts:391) — empty body. +12. `DeltaRuntimePropertiesKvPairs` (model.ts:397) — 1 field. +13. `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` + (model.ts:403) — 2 fields. +14. `Dependency` (model.ts:412) — discriminated union (table / function / + connection / credential). +15. `DependencyList` (model.ts:422) — 1 field. +16. `EffectivePredictiveOptimizationFlag` (model.ts:427) — 3 fields. +17. `EncryptionDetails` (model.ts:437) — discriminated union (one variant: `sseEncryptionDetails`). -19. `ForeignKeyConstraint` (model.ts:498) — 5 fields (`name`, `childColumns`, +18. `ForeignKeyConstraint` (model.ts:447) — 5 fields (`name`, `childColumns`, `parentTable`, `parentColumns`, `rely`). -20. `FunctionDependency` (model.ts:512) — 1 field. -21. `GetTable` (model.ts:517) — 4 fields. -22. `ListTableSummaries` (model.ts:528) — 6 fields. -23. `ListTableSummaries_Response` (model.ts:556) — 2 fields. -24. `ListTables` (model.ts:566) — 9 fields. -25. `ListTables_Response` (model.ts:594) — 2 fields. -26. `NamedTableConstraint` (model.ts:604) — 1 field. -27. `OptionSpec` (model.ts:614) — 15 fields. -28. `PolicyFunctionArgument` (model.ts:661) — discriminated union (column / +19. `FunctionDependency` (model.ts:461) — 1 field. +20. `GetTableRequest` (model.ts:466) — 4 fields. +21. `ListTableSummariesRequest` (model.ts:477) — 6 fields. +22. `ListTableSummariesRequest_Response` (model.ts:505) — 2 fields. +23. `ListTablesRequest` (model.ts:515) — 9 fields. +24. `ListTablesRequest_Response` (model.ts:543) — 2 fields. +25. `NamedTableConstraint` (model.ts:553) — 1 field. +26. `OptionSpec` (model.ts:563) — 14 fields. +27. `PolicyFunctionArgument` (model.ts:605) — discriminated union (column / constant). -29. `PrimaryKeyConstraint` (model.ts:676) — 4 fields. -30. `RowFilter` (model.ts:687) — 3 fields. -31. `SecretDependency` (model.ts:704) — 1 field. -32. `SecurableKindManifest` (model.ts:710) — 5 fields. -33. `SseEncryptionDetails` (model.ts:724) — 2 fields. -34. `TableConstraint` (model.ts:738) — discriminated union (primary key / +28. `PrimaryKeyConstraint` (model.ts:620) — 4 fields. +29. `RowFilter` (model.ts:631) — 3 fields. +30. `SecurableKindManifest` (model.ts:648) — 5 fields. +31. `SseEncryptionDetails` (model.ts:662) — 2 fields. +32. `TableConstraint` (model.ts:676) — discriminated union (primary key / foreign key / named). -35. `TableDependency` (model.ts:756) — 1 field. -36. `TableExists` (model.ts:761) — 1 field. -37. `TableExists_Response` (model.ts:767) — 1 field (`tableExists`). -38. `TableInfo` (model.ts:772) — 36 fields (duplicates `CreateTable` / - `UpdateTable` field-by-field). -39. `TableInfo_PropertiesEntry` (model.ts:844) — 2 fields. -40. `TableSummary` (model.ts:849) — 3 fields. -41. `UpdateTable` (model.ts:857) — 37 fields (`fullNameArg` + the same set as - `CreateTable`). -42. `UpdateTable_PropertiesEntry` (model.ts:931) — 2 fields. -43. `UpdateTable_Response` (model.ts:937) — empty body. -44. `VolumeDependency` (model.ts:940) — 1 field. +33. `TableDependency` (model.ts:694) — 1 field. +34. `TableExistsRequest` (model.ts:699) — 1 field. +35. `TableExistsRequest_Response` (model.ts:705) — 1 field (`tableExists`). +36. `TableInfo` (model.ts:710) — 36 fields (duplicates `CreateTableRequest` / + `UpdateTableRequest` field-by-field). +37. `TableInfo_PropertiesEntry` (model.ts:782) — 2 fields. +38. `TableSummary` (model.ts:787) — 3 fields. +39. `UpdateTableRequest` (model.ts:795) — 37 fields (`fullNameArg` + the same + set as `CreateTableRequest`). +40. `UpdateTableRequest_PropertiesEntry` (model.ts:869) — 2 fields. +41. `UpdateTableRequest_Response` (model.ts:875) — empty body. ### Zod schemas (model.ts) -- Unmarshal: 25 schemas — `unmarshalColumnInfoSchema`, - `unmarshalColumnMaskSchema`, `unmarshalConditionalDisplaySchema`, - `unmarshalConnectionDependencySchema`, `unmarshalCredentialDependencySchema`, - `unmarshalDeleteTable_ResponseSchema`, - `unmarshalDeleteTableConstraint_ResponseSchema`, - `unmarshalDeltaRuntimePropertiesKvPairsSchema`, `unmarshalDependencySchema`, - `unmarshalDependencyListSchema`, - `unmarshalEffectivePredictiveOptimizationFlagSchema`, - `unmarshalEncryptionDetailsSchema`, `unmarshalForeignKeyConstraintSchema`, - `unmarshalFunctionDependencySchema`, - `unmarshalListTableSummaries_ResponseSchema`, - `unmarshalListTables_ResponseSchema`, - `unmarshalNamedTableConstraintSchema`, `unmarshalOptionSpecSchema`, - `unmarshalPolicyFunctionArgumentSchema`, - `unmarshalPrimaryKeyConstraintSchema`, `unmarshalRowFilterSchema`, - `unmarshalSecretDependencySchema`, `unmarshalSecurableKindManifestSchema`, - `unmarshalSseEncryptionDetailsSchema`, `unmarshalTableConstraintSchema`, - `unmarshalTableDependencySchema`, `unmarshalTableExists_ResponseSchema`, - `unmarshalTableInfoSchema`, `unmarshalTableSummarySchema`, - `unmarshalUpdateTable_ResponseSchema`, `unmarshalVolumeDependencySchema`. +- Unmarshal: schemas for the response and structural types. - Marshal: a near-parallel set of `marshal…Schema` symbols (no - `marshalDeleteTable_*` /`marshalGetTableSchema` since requests there have - no body). + `marshal…Schema` for path-only requests with no body). ### Client (client.ts) @@ -169,7 +144,7 @@ ### Index (index.ts) -- Re-exports `Client`, 8 enums, and 41 interfaces. +- Re-exports `Client`, 8 enums, and 38 interfaces. --- @@ -177,11 +152,11 @@ | Severity | Count | | --------------------- | ----- | -| High | 13 | -| Medium | 26 | +| High | 18 | +| Medium | 21 | | Low / SDK-wide note | 10 | -| Pass / acceptable | 10 | -| **Total findings** | **59** | +| Pass / acceptable | 9 | +| **Total findings** | **58** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -193,9 +168,9 @@ findings.) ### 1. `DeltaRuntimePropertiesKvPairs` type name vs. `deltaRuntimePropertiesKvpairs` field name acronym-casing mismatch — category 3 (Acronym casing inconsistencies) **Symbols:** -- Type: `DeltaRuntimePropertiesKvPairs` (model.ts:438) — `KvPairs` (capital +- Type: `DeltaRuntimePropertiesKvPairs` (model.ts:397) — `KvPairs` (capital `P`). -- Field: `deltaRuntimePropertiesKvpairs` (model.ts:374, 824, 911) — `Kvpairs` +- Field: `deltaRuntimePropertiesKvpairs` (model.ts:339, 762, 849) — `Kvpairs` (lowercase `p`). **Issue:** The same word ("KvPairs") is cased differently across type and @@ -205,18 +180,18 @@ field names *within the same generated package*: // type name export interface DeltaRuntimePropertiesKvPairs { ... } // KvPairs -// field name on TableInfo / CreateTable / UpdateTable +// field name on TableInfo / CreateTableRequest / UpdateTableRequest deltaRuntimePropertiesKvpairs?: DeltaRuntimePropertiesKvPairs | undefined; // ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ // Kvpairs (field) KvPairs (type) ``` -The wire form is `delta_runtime_properties_kvpairs` (model.ts:1353, 1565, -1894, 1936) — snake_case with two underscores around `kvpairs` (not three). -The field-name camelCase conversion turns `kvpairs` into one camelCase -token; the type-name PascalCase keeps `KvPairs` as two tokens. The mismatch -is purely a generator quirk: it tokenizes the wire string differently for -struct names vs. field names. +The wire form is `delta_runtime_properties_kvpairs` — snake_case with two +underscores around `kvpairs` (not three). The field-name camelCase +conversion turns `kvpairs` into one camelCase token; the type-name +PascalCase keeps `KvPairs` as two tokens. The mismatch is purely a +generator quirk: it tokenizes the wire string differently for struct names +vs. field names. **Suggested:** unify casing. - Either `DeltaRuntimePropertiesKvpairs` (field-consistent — but breaks the @@ -233,7 +208,7 @@ cleanup.** ### 2. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) -**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:438). +**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:397). **Issue:** `Kv` (key-value) is borderline cryptic for a TypeScript API; the "Pairs" suffix is redundant if `Kv` already means key-value. The type holds @@ -246,83 +221,11 @@ self-describing). --- -### 3. `OptionSpec_OauthStage` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) +### 3. SSE acronym casing in `SseEncryptionAlgorithm` / `SseEncryptionDetails` — category 3 (Acronym casing inconsistencies) -**Symbol:** `OptionSpec_OauthStage.OAUTH_STAGE_UNSPECIFIED` (model.ts:230). - -**Issue:** Member is already namespaced under `OptionSpec_OauthStage`. The -`OAUTH_STAGE_` segment duplicates the enum name. Reads as: - -```ts -spec.oauthStage === OptionSpec_OauthStage.OAUTH_STAGE_UNSPECIFIED -// ^^^^^^^^^^^^^^^^^^^^^^^ -// duplicates the enum name -``` - -Companion values `BEFORE_AUTHORIZATION_CODE` / `BEFORE_ACCESS_TOKEN` do not -repeat the prefix — they break the pattern, so only the `UNSPECIFIED` value -is verbose. This is the classic protobuf "first enum is the unspecified -placeholder with the type name as its prefix" pattern. - -**Suggested wire-level (coordinated with API):** plain `UNSPECIFIED`. -**Suggested TS-level only:** `Unspecified = 'OAUTH_STAGE_UNSPECIFIED'`. - ---- - -### 4. `OptionSpec_OptionType` member values prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) - -**Symbol:** `OptionSpec_OptionType.OPTION_TYPE_UNSPECIFIED` (model.ts:243) -and every other value (`OPTION_BOOLEAN`, `OPTION_NUMBER`, etc.). - -**Issue:** Every member is prefixed `OPTION_` — repeating the enum name -`OptionType`. The 9 values are: -- `OPTION_TYPE_UNSPECIFIED` -- `OPTION_BOOLEAN`, `OPTION_NUMBER`, `OPTION_BIGINT`, `OPTION_STRING`, - `OPTION_ENUM` -- `OPTION_SERVICE_CREDENTIAL`, `OPTION_MULTILINE_STRING`, - `OPTION_STORAGE_CREDENTIAL` - -Reads as: -```ts -spec.type === OptionSpec_OptionType.OPTION_BOOLEAN // "the OptionType is OPTION_BOOLEAN" -``` - -`OptionType.Boolean` would be far cleaner. The wire form is fixed; the TS -identifier can be split (`Boolean = 'OPTION_BOOLEAN'`). - -**Suggested:** drop `OPTION_` prefix on the TS identifiers: -```ts -export enum OptionSpec_OptionType { - Unspecified = 'OPTION_TYPE_UNSPECIFIED', - Boolean = 'OPTION_BOOLEAN', - Number = 'OPTION_NUMBER', - Bigint = 'OPTION_BIGINT', - // ... -} -``` - ---- - -### 5. `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` member value prefix repeats the enum name — category 2 (Redundant enum prefixes) and category 18 (Long enum values) - -**Symbol:** `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` -(model.ts:204). 37 characters. - -**Issue:** Identical pattern to findings 3 and 4 — the leading -`SSE_ENCRYPTION_ALGORITHM_` segment duplicates the enum name. The other two -values (`AWS_SSE_S3`, `AWS_SSE_KMS`) do not include the prefix, so only -`UNSPECIFIED` is overly verbose. - -**Suggested:** TS-side `Unspecified = 'SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED'`. -Wire string remains. - ---- - -### 6. SSE acronym casing in `SseEncryptionAlgorithm` / `SseEncryptionDetails` — category 3 (Acronym casing inconsistencies) - -**Symbols:** `SseEncryptionAlgorithm` (model.ts:203), -`SseEncryptionDetails` (model.ts:724), `sseEncryptionDetails` (field name in -`EncryptionDetails` discriminator at model.ts:491). +**Symbols:** `SseEncryptionAlgorithm` (model.ts:183), +`SseEncryptionDetails` (model.ts:662), `sseEncryptionDetails` (field name in +`EncryptionDetails` discriminator at model.ts:440). **Issue:** "SSE" is a three-letter acronym (Server-Side Encryption). Google TS Style Guide § 5.1 says multi-letter acronyms should be cased like @@ -340,9 +243,9 @@ etc.) but is worth flagging for anyone reviewing this file fresh. --- -### 7. `SseEncryptionDetails.awsKmsKeyArn` is the only field that names the cloud — category 3 (Acronym casing inconsistencies) and category 16 (Field contradicting type domain) +### 4. `SseEncryptionDetails.awsKmsKeyArn` is the only field that names the cloud — category 3 (Acronym casing inconsistencies) and category 16 (Field contradicting type domain) -**Symbol:** `SseEncryptionDetails.awsKmsKeyArn` (model.ts:731). +**Symbol:** `SseEncryptionDetails.awsKmsKeyArn` (model.ts:669). **Issue:** `AWS`, `KMS`, and `ARN` are three back-to-back acronyms. The field is `awsKmsKeyArn`. The JSDoc explains it's "The ARN of the SSE-KMS @@ -351,7 +254,7 @@ Google rule, `AwsKmsKeyArn` would become `awsKmsKeyArn` in camelCase form — which the code already uses. So far OK. But this is the *only* AWS-specific field in `tables`. `accessPoint` -(model.ts:381) is also AWS S3-specific (JSDoc: "The AWS access point to +(model.ts:346) is also AWS S3-specific (JSDoc: "The AWS access point to use when accesing s3 for this external location") — but the field name does not say `awsAccessPoint`. The two AWS-specific fields in `TableInfo` use different naming conventions for their AWS-ness. @@ -360,24 +263,24 @@ use different naming conventions for their AWS-ness. `aws` prefix on `awsKmsKeyArn` if it's understood to be AWS-only (the enclosing `SseEncryptionAlgorithm` already says `AWS_SSE_KMS`). -(One JSDoc typo: "accesing" — single `s`, model.ts:381 — likely also in +(One JSDoc typo: "accesing" — single `s`, model.ts:345 — likely also in the upstream `.proto`.) --- -### 8. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) +### 5. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) -**Symbol:** `SecurableType` (model.ts:182). +**Symbol:** `SecurableType` (model.ts:162). **Issue:** `SecurableType` is also exported from `catalogs/v1/model.ts:28`, `connections/v1/model.ts:109`, and at least two other audited packages. Each definition is the same enum with the same 17 values. Five copies of -the same enum across the SDK. The values overlap with `SecurableKind` (see -finding 9) but are at a different level of granularity (a `TABLE` of +the same enum across the SDK. The values overlap with `SecurableKind` +(model.ts:78) but are at a different level of granularity (a `TABLE` of `SecurableType` maps to ~50 `TABLE_*` `SecurableKind` values). Within the `tables` package, `SecurableType` only appears on -`SecurableKindManifest.securableType` (model.ts:712) — a single field on a +`SecurableKindManifest.securableType` (model.ts:650) — a single field on a single type. The enum's *value* to this package is marginal: a consumer who already has a `TableInfo` knows it's a `TABLE`. @@ -386,50 +289,15 @@ who already has a `TableInfo` knows it's a `TABLE`. --- -### 9. `SecurableKind` is a 70+ value enum with `TABLE_` prefix on most values — category 2 (Redundant enum prefixes) and category 18 (Long enum values) - -**Symbol:** `SecurableKind` (model.ts:81) — 70+ members, 50+ with `TABLE_` -prefix. - -**Issue:** The enum mixes two concerns: - -1. Table-specific kinds: `TABLE_STANDARD`, `TABLE_EXTERNAL`, `TABLE_DELTA`, - `TABLE_VIEW`, `TABLE_FOREIGN_HIVE_METASTORE_DBFS_SHALLOW_CLONE_EXTERNAL` - (60+ chars!). -2. Non-table kinds: `RECIPIENT_*`, `CONNECTION_*`, `CATALOG_*`, `SCHEMA_*`. - -The longest values (`TABLE_DELTA_UNIFORM_ICEBERG_FOREIGN_HIVE_METASTORE_EXTERNAL`, -`TABLE_FOREIGN_SALESFORCE_DATA_CLOUD_FILE_SHARING_VIEW`, -`TABLE_FOREIGN_HIVE_METASTORE_DBFS_SHALLOW_CLONE_EXTERNAL`) are 50–60 -characters each. As enum members they are functional but exceed Google's -90-column line cap when used in expressions. - -The two-concerns problem is structural: `SecurableKind` is generated for the -whole UC `Securable` taxonomy. In `tables` only the `TABLE_*` half matters, -but the enum exports all values. The non-`TABLE_*` values are unreachable -through any field on this package's types. - -**Suggested:** -- For local TS readability: rename TS identifiers to `UpperCamelCase` - (`TableStandard`, `TableExternal`, …) without changing the wire string. -- For SDK-wide structure: hoist `SecurableKind` to a shared module and let - service packages re-export, so consumers don't see the entire taxonomy in - every type-import location. -- Consider splitting `SecurableKind` into `SecurableKind` + `TableKind` if - the API surface allows. **Coordinate with protocol team.** - ---- - -### 10. `ColumnTypeName.TABLE_TYPE` and `TABLEREF_TYPE` collide with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 6. `ColumnTypeName.TABLE_TYPE` collides with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) -**Symbols:** `ColumnTypeName.TABLE_TYPE` (model.ts:31), -`ColumnTypeName.TABLEREF_TYPE` (model.ts:32). +**Symbol:** `ColumnTypeName.TABLE_TYPE` (model.ts:29). -**Issue:** Two values in `ColumnTypeName` are named the same as the +**Issue:** A value in `ColumnTypeName` is named the same as the *type-name* of another enum in this file: - `ColumnTypeName.TABLE_TYPE` — a column-data-type value of "table". -- `TableType` (model.ts:209) — the *enum* describing kinds of UC tables +- `TableType` (model.ts:189) — the *enum* describing kinds of UC tables (`MANAGED`, `EXTERNAL`, `VIEW`, …). A reader scanning the file sees `TABLE_TYPE` as a `ColumnTypeName` value @@ -437,40 +305,31 @@ and `TableType` as a separate enum — but the names overlap, suggesting they are related. They are not: one is about Spark column SQL types ("the column holds a table"), the other is about UC table classifications. -`TABLEREF_TYPE` is also cryptic — the `REF` suffix is unclear (table -reference type? table-ref?), and the field has no JSDoc to disambiguate. - **Suggested:** - Rename `TABLE_TYPE` → `TABLE` (matches the pattern: `ARRAY`, `STRUCT`, `MAP` are the same kind of compound type). -- Rename `TABLEREF_TYPE` → `TABLE_REFERENCE` (matches `USER_DEFINED_TYPE`). - Or document the relationship in JSDoc. **Coordinate with protocol.** --- -### 11. `ColumnTypeName.USER_DEFINED_TYPE` and `TIMESTAMP_NTZ` cryptic value forms — category 5 (Cryptic abbreviations) and category 18 (Long enum values) +### 7. `ColumnTypeName.TIMESTAMP_NTZ` cryptic abbreviation — category 5 (Cryptic abbreviations) -**Symbols:** `ColumnTypeName.USER_DEFINED_TYPE` (model.ts:24), -`ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25). +**Symbol:** `ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25). -**Issue:** -- `USER_DEFINED_TYPE` — 17 characters. The companion values (`BOOLEAN`, - `INT`, `STRING`) are short. The `_TYPE` suffix is redundant inside an - enum already named `ColumnTypeName`. -- `TIMESTAMP_NTZ` — "NTZ" is "no time zone" (a Spark/Delta abbreviation). - Has no JSDoc. +**Issue:** "NTZ" is "no time zone" (a Spark/Delta abbreviation). Has no +JSDoc. A reader who has not seen the Spark dialect cannot tell what `NTZ` +means from the symbol alone. -**Suggested:** -- `USER_DEFINED_TYPE` → `USER_DEFINED` (drop the `_TYPE` suffix). -- Add JSDoc to `TIMESTAMP_NTZ` clarifying `NTZ = "no time zone"`. +**Suggested:** add JSDoc to `TIMESTAMP_NTZ` clarifying `NTZ = "no time +zone"`. --- -### 12. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) +### 8. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) -**Symbols:** `DataSourceFormat` values (model.ts:36–78). +**Symbols:** `DataSourceFormat` values (model.ts:33–75). **Issue:** 18 of the 26 values carry a `_FORMAT` suffix (`DATABRICKS_FORMAT`, `MYSQL_FORMAT`, etc.), but 8 are bare (`DELTA`, `CSV`, @@ -478,7 +337,7 @@ reference type? table-ref?), and the field has no JSDoc to disambiguate. `DELTASHARING`, `DELTA_UNIFORM_HUDI`, `DELTA_UNIFORM_ICEBERG`, `ICEBERG`). The split is along provenance: the bare values are the "native" Databricks formats; the `_FORMAT` suffix marks query-federation source formats (added -later, per the `BEGIN`/`END` comments at model.ts:47, 66). +later, per the `BEGIN`/`END` comments at model.ts:44, 63). So the suffix carries semantic information (source-federation vs. native). But that distinction should be expressed *outside* the wire string — e.g. a @@ -497,10 +356,10 @@ if (format === 'MYSQL_FORMAT' || format === 'POSTGRESQL_FORMAT') {} // suffix --- -### 13. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) +### 9. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) -**Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:46), -`DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:73). +**Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:43), +`DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:70). **Issue:** Inconsistent tokenisation within the same enum: - `DELTASHARING` — single token ("delta sharing" without separator). @@ -516,38 +375,9 @@ consistent. **Not a per-package fix.** --- -### 14. `TableType` enum — category 18 (Long enum values) — *pass with note* - -**Symbol:** `TableType` (model.ts:209) — 9 values: `MANAGED`, `EXTERNAL`, -`VIEW`, `MATERIALIZED_VIEW`, `STREAMING_TABLE`, `MANAGED_SHALLOW_CLONE`, -`FOREIGN`, `EXTERNAL_SHALLOW_CLONE`, `METRIC_VIEW`. - -**Issue:** -- `STREAMING_TABLE` — 15 chars, ends in `_TABLE` (already inside `TableType` - — minor redundancy). -- `MANAGED_SHALLOW_CLONE`, `EXTERNAL_SHALLOW_CLONE` — 21–22 chars, no - redundant prefix. -- `MATERIALIZED_VIEW`, `METRIC_VIEW` — clean. - -The `_TABLE` suffix on `STREAMING_TABLE` is the only redundancy (compare -to `MANAGED`, `EXTERNAL` which don't say `MANAGED_TABLE` / `EXTERNAL_TABLE`). -But it documents that a streaming table is a kind of table (vs. a view or -materialized view). - -**Suggested:** consider `STREAMING` for the TS identifier; wire string -remains. **Pass with note.** - -(Cross-package: `SecurableKind.TABLE_STREAMING_LIVE_TABLE` (model.ts:106) -and the deprecated `TABLE_STREAMING_LIVE_TABLE_DELTASHARING` use the -phrase "streaming live table" — older vocabulary. `TableType.STREAMING_TABLE` -is the newer name. The two enums in the same file disagree on the -streaming-table label.) - ---- - -### 15. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) +### 10. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) -**Symbol:** `SecurableKind.TABLE_DELTASHARING_OPEN_DIR_BASED` (model.ts:96). +**Symbol:** `SecurableKind.TABLE_DELTASHARING_OPEN_DIR_BASED` (model.ts:93). **Issue:** "OPEN DIR BASED" abbreviates "open-directory-based" — i.e. a delta-sharing table backed by an open directory listing. The acronym is @@ -562,13 +392,13 @@ constraint), **flag for documentation cleanup.** --- -### 16. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) +### 11. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) **Symbols:** -- `SecurableKind.TABLE_FEATURE_STORE` (model.ts:104) and - `TABLE_FEATURE_STORE_EXTERNAL` (model.ts:105) — both marked "deprecated" - in JSDoc (model.ts:103). -- `SecurableKind.TABLE_FOREIGN_HIVE_METASTORE` (model.ts:129) — also +- `SecurableKind.TABLE_FEATURE_STORE` (model.ts:95) and + `TABLE_FEATURE_STORE_EXTERNAL` (model.ts:96) — both marked "deprecated" + in JSDoc (model.ts:94). +- `SecurableKind.TABLE_FOREIGN_HIVE_METASTORE` (model.ts:119) — also marked deprecated. **Issue:** Five+ deprecated values left in the enum without `@deprecated` @@ -584,104 +414,67 @@ JSDoc tags (only inline comments). Consumers code-completing on --- -### 17. `fullNameArg` field name across multiple request types — category 14 (Go/Java-style names) and category 5 (Cryptic abbreviations) +### 12. `fullNameArg` field name across multiple request types — category 14 (Go/Java-style names) and category 5 (Cryptic abbreviations) -**Symbols:** `fullNameArg` on `DeleteTable` (model.ts:413), -`DeleteTableConstraint` (model.ts:421), `GetTable` (model.ts:519), -`TableExists` (model.ts:763), `UpdateTable` (model.ts:859), -`CreateTableConstraint` (model.ts:401). 7 occurrences in this file alone; -also used in `schemas/v1`, `functions/v1`, `registeredmodels/v1`. +**Symbols:** `fullNameArg` on `DeleteTableRequest` (model.ts:387), +`DeleteTableConstraintRequest` (model.ts:372), `GetTableRequest` +(model.ts:468), `TableExistsRequest` (model.ts:701), `UpdateTableRequest` +(model.ts:797), `CreateTableConstraintRequest` (model.ts:283). 6 +occurrences in this file alone; also used in `schemas/v1`, `functions/v1`, +`registeredmodels/v1`. **Issue:** The `Arg` suffix on a field name is a Go convention (Go SDK uses `FullNameArg` to mark a URL-path-argument vs. a query/body field). In TS, the convention is to use the bare field name (`fullName`) since the distinction between URL-path / query / body is handled by the client code -and JSDoc. The wire form is `full_name_arg` (model.ts:1583, 1911) — the -suffix even reaches the wire, which is unusual. +and JSDoc. The wire form is `full_name_arg` — the suffix even reaches the +wire, which is unusual. The same package also has a `fullName` field on response/struct types -(`CreateTable.fullName` model.ts:360, `TableInfo.fullName` model.ts:810, -`TableSummary.fullName` model.ts:851). So the package has both `fullName` -(noun) and `fullNameArg` (with `Arg` suffix) — distinguishing input from -output by suffix, which is a Go-ism. +(`CreateTableRequest.fullName` model.ts:325, `TableInfo.fullName` +model.ts:748, `TableSummary.fullName` model.ts:789, `UpdateTableRequest.fullName` +model.ts:835). So the package has both `fullName` (noun) and `fullNameArg` +(with `Arg` suffix) — distinguishing input from output by suffix, which is +a Go-ism. **Suggested:** rename `fullNameArg` → `fullName` SDK-wide. The URL-path argument vs. response field distinction can be inferred from the request -type (e.g. `DeleteTable.fullName` is obviously a path argument because -`DeleteTable` is a delete request). Cross-reference Google AIP-122 -(resource name in REST methods uses `name`, not `nameArg`). +type (e.g. `DeleteTableRequest.fullName` is obviously a path argument +because `DeleteTableRequest` is a delete request). Cross-reference Google +AIP-122 (resource name in REST methods uses `name`, not `nameArg`). **Flag for SDK-wide cleanup.** --- -### 18. `TableExists` request type is a verb-as-noun — category 6 (Misleading names) - -**Symbol:** `TableExists` (model.ts:761) request type. - -**Issue:** The request type is named `TableExists` — a verb-as-noun. Inside -`tables` the implicit verb "does this table exist?" reads as the type name. -Awkward but matches Go. Code-completing on the package surface shows -`TableExists` alongside the noun-shaped `TableInfo` and `TableSummary`, -without a `Request` suffix or other syntactic hint that this is a request -input. - -**Suggested:** rename to `TableExistsRequest` (would *not* match other -request types in this package — none of them carry the `Request` suffix — -but resolves the verb-as-noun reading). - -**Flag at port time.** - ---- - -### 19. Request type naming pattern is inconsistent (`CreateTable`, `DeleteTable`, no `Request` suffix) — category 17 (Inconsistent action verbs) and category 20 (Type-suffix tautology) - -**Symbols:** All request types in this package (`CreateTable`, `DeleteTable`, -`DeleteTableConstraint`, `GetTable`, `ListTables`, `ListTableSummaries`, -`TableExists`, `UpdateTable`, `CreateTableConstraint`). - -**Issue:** None carry the `Request` suffix that some sister packages do -(`featurestore.CreateOnlineStoreRequest`, -`onlinetables.CreateOnlineTableRequest`, etc.). Within `tables`, the same -type names also clash with the *response* concept — e.g. `CreateTable` is -sometimes interpreted as "an action: create the table" and sometimes as -"the type representing a table to be created." - -**Suggested:** rename to `CreateTableRequest`, `GetTableRequest`, etc., or -keep the current convention and document that "verb-noun" types are always -input. Pick one. **Flag SDK-wide.** - -(Note that `onlinetables` uses `Request` suffix; `tables` does not. Same -SDK, same generator, two conventions.) - ---- - -### 20. `CreateTable` and `TableInfo` and `UpdateTable` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) +### 13. `CreateTableRequest` and `TableInfo` and `UpdateTableRequest` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) -**Symbols:** `CreateTable` (model.ts:322, 38 fields), `TableInfo` -(model.ts:772, 36 fields), `UpdateTable` (model.ts:857, 37 fields). +**Symbols:** `CreateTableRequest` (model.ts:287, 38 fields), `TableInfo` +(model.ts:710, 36 fields), `UpdateTableRequest` (model.ts:795, 37 fields). **Issue:** Three types describe essentially the same shape: -- `CreateTable` — fields a caller sets when creating a table. +- `CreateTableRequest` — fields a caller sets when creating a table. - `TableInfo` — fields the server returns about a table. -- `UpdateTable` — fields a caller sets when updating a table (the only - delta is `fullNameArg` added at the top). +- `UpdateTableRequest` — fields a caller sets when updating a table (the + only delta is `fullNameArg` added at the top). Comparing field lists: -- `CreateTable.fullName` vs `UpdateTable.fullName`: both fields exist in - both types. `UpdateTable` *also* has `fullNameArg`. The `fullName` field - on `CreateTable` is server-output (the server fills it). The same field - on `UpdateTable` is also server-output. -- `CreateTable.createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `tableId`, - `deletedAt`, `metastoreId` — all server-populated. They appear in - `CreateTable` *because* the type is also used as the response shape of - `createTable()`. The client.ts code confirms (client.ts:117) — the - response is parsed as `TableInfo`, but `CreateTable` carries the same - fields anyway as part of the "fields you *could* set" surface. - -So `CreateTable` is *both* an input and an output type, with the same set -of fields. Same for `UpdateTable`. `TableInfo` is the response shape but -shares the field set. Three types that are *almost* identical. +- `CreateTableRequest.fullName` vs `UpdateTableRequest.fullName`: both + fields exist in both types. `UpdateTableRequest` *also* has + `fullNameArg`. The `fullName` field on `CreateTableRequest` is + server-output (the server fills it). The same field on + `UpdateTableRequest` is also server-output. +- `CreateTableRequest.createdAt`, `createdBy`, `updatedAt`, `updatedBy`, + `tableId`, `deletedAt`, `metastoreId` — all server-populated. They appear + in `CreateTableRequest` *because* the type is also used as the response + shape of `createTable()`. The client.ts code confirms — the response is + parsed as `TableInfo`, but `CreateTableRequest` carries the same fields + anyway as part of the "fields you *could* set" surface. + +So `CreateTableRequest` is *both* an input and an output type, with the +same set of fields. Same for `UpdateTableRequest`. `TableInfo` is the +response shape but shares the field set. Three types that are *almost* +identical. **Suggested:** collapse to one `Table` type, with optional fields for the output-only segments (or use `Pick`/`Omit` types if input-only / output-only @@ -693,10 +486,11 @@ messages map 1:1). --- -### 21. `CreateTable.fullName` is server-generated — category 6 (Misleading names) +### 14. `CreateTableRequest.fullName` is server-generated — category 6 (Misleading names) -**Symbol:** `CreateTable.fullName?: string | undefined` (model.ts:360). -JSDoc: "Full name of table, in form of __catalog_name__.__schema_name__.__table_name__". +**Symbol:** `CreateTableRequest.fullName?: string | undefined` +(model.ts:325). JSDoc: "Full name of table, in form of +__catalog_name__.__schema_name__.__table_name__". **Issue:** The field appears in the request *input* type but is server-output (derived from `catalogName`, `schemaName`, `name`). A caller writing @@ -708,18 +502,18 @@ Same applies to `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `tableId`, `metastoreId`, `deletedAt`, `pipelineId`, `dataAccessConfigurationId`, `deltaRuntimePropertiesKvpairs`, `effectivePredictiveOptimizationFlag` — all server-output but exposed on the input type. Same critique applies to -`UpdateTable`. +`UpdateTableRequest`. **Suggested:** mark with JSDoc `@readonly` and add a sentence "Output only; -ignored on input." Or restructure types (finding 20). **Coordinate with +ignored on input." Or restructure types (finding 13). **Coordinate with generator.** --- -### 22. `CreateTable.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) +### 15. `CreateTableRequest.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) -**Symbol:** `CreateTable.tableConstraints?: TableConstraint[] | undefined` -(model.ts:352). JSDoc: "List of table constraints. Note: this field is not +**Symbol:** `CreateTableRequest.tableConstraints?: TableConstraint[] | undefined` +(model.ts:317). JSDoc: "List of table constraints. Note: this field is not set in the output of the __listTables__ API." **Issue:** The JSDoc note is structured oddly: it explains the field's @@ -729,25 +523,25 @@ with the existence of a separate `createTableConstraint` method 1. Call `createTable` (without constraints). 2. Call `createTableConstraint` (one per constraint). -So `CreateTable.tableConstraints` is also an unusual input — the server -might or might not honour it depending on the deployment. +So `CreateTableRequest.tableConstraints` is also an unusual input — the +server might or might not honour it depending on the deployment. **Suggested:** clarify JSDoc on input behaviour; possibly mark deprecated. --- -### 23. `CreateTable.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 16. `CreateTableRequest.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) -**Symbol:** `CreateTable.enablePredictiveOptimization?: string | undefined` -(model.ts:356). Same field on `TableInfo` (model.ts:806) and `UpdateTable` -(model.ts:893). No JSDoc. +**Symbol:** `CreateTableRequest.enablePredictiveOptimization?: string | undefined` +(model.ts:321). Same field on `TableInfo` (model.ts:744) and +`UpdateTableRequest` (model.ts:831). No JSDoc. **Issue:** The `enable…` prefix strongly suggests a boolean. The type is `string`. A caller writing `createTable({ enablePredictiveOptimization: true })` gets a TS error and must look up the JSDoc to learn the field accepts string enum values (typically `'ENABLE'`, `'DISABLE'`, `'INHERIT'` per UC). The -companion `effectivePredictiveOptimizationFlag.value` (model.ts:480) is +companion `effectivePredictiveOptimizationFlag.value` (model.ts:429) is also a `string` with the same domain. **Suggested:** @@ -760,30 +554,30 @@ same field. --- -### 24. `CreateTable.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) +### 17. `CreateTableRequest.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) -**Symbol:** `CreateTable.dataAccessConfigurationId?: string | undefined` -(model.ts:362). 28 chars. Same field on `TableInfo` (model.ts:812) and -`UpdateTable` (model.ts:899). +**Symbol:** `CreateTableRequest.dataAccessConfigurationId?: string | undefined` +(model.ts:327). 28 chars. Same field on `TableInfo` (model.ts:750) and +`UpdateTableRequest` (model.ts:837). **Issue:** A `string` field with no type discrimination. The JSDoc says "Unique ID of the Data Access Configuration to use with the table data." A consumer cannot know the ID's format (UUID? snowflake? human-readable?). Same applies to: -- `metastoreId` (model.ts:358) — UC metastore identifier. -- `pipelineId` (model.ts:355) — DLT pipeline identifier. -- `tableId` (model.ts:372) — UC table identifier. +- `metastoreId` (model.ts:323) — UC metastore identifier. +- `pipelineId` (model.ts:320) — DLT pipeline identifier. +- `tableId` (model.ts:337) — UC table identifier. All are bare strings. The TS SDK has no typed IDs; that is an SDK-wide choice. **Pass with note.** --- -### 25. `CreateTable.accessPoint` (S3-specific) leaks AWS into a generic-looking field — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 18. `CreateTableRequest.accessPoint` (S3-specific) leaks AWS into a generic-looking field — category 6 (Misleading names) and category 16 (Field contradicting type domain) -**Symbol:** `CreateTable.accessPoint?: string | undefined` (model.ts:381). -JSDoc: "The AWS access point to use when accesing s3 for this external -location." (Note also the JSDoc typo "accesing".) +**Symbol:** `CreateTableRequest.accessPoint?: string | undefined` +(model.ts:346). JSDoc: "The AWS access point to use when accesing s3 for +this external location." (Note also the JSDoc typo "accesing".) **Issue:** A field named `accessPoint` reads like a generic concept (the endpoint at which the table is accessed?). In reality it is AWS S3–specific. @@ -793,17 +587,17 @@ or GCP will not know to skip the field. **Suggested:** rename to `awsAccessPoint` or `s3AccessPoint` (matches the JSDoc). -**Cross-reference:** `SseEncryptionDetails.awsKmsKeyArn` (finding 7) takes +**Cross-reference:** `SseEncryptionDetails.awsKmsKeyArn` (finding 4) takes the AWS prefix; `accessPoint` does not. Inconsistent within this file. --- -### 26. `CreateTable.browseOnly` is server-output but appears in request — category 6 (Misleading names) +### 19. `CreateTableRequest.browseOnly` is server-output but appears in request — category 6 (Misleading names) -**Symbol:** `CreateTable.browseOnly?: boolean | undefined` (model.ts:383). -JSDoc: "Indicates whether the principal is limited to retrieving metadata -for the associated object through the BROWSE privilege when include_browse -is enabled in the request." +**Symbol:** `CreateTableRequest.browseOnly?: boolean | undefined` +(model.ts:348). JSDoc: "Indicates whether the principal is limited to +retrieving metadata for the associated object through the BROWSE privilege +when include_browse is enabled in the request." **Issue:** Server-output field on an input type, again. The JSDoc is also describing the server's behaviour ("when include_browse is enabled in the @@ -815,15 +609,15 @@ to `TableInfo` only. --- -### 27. `ListTables.omitColumns` / `omitProperties` / `omitUsername` use negative form — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) +### 20. `ListTablesRequest.omitColumns` / `omitProperties` / `omitUsername` use negative form — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) -**Symbols:** `ListTables.omitColumns?: boolean` (model.ts:582), -`omitProperties?: boolean` (model.ts:584), `omitUsername?: boolean` -(model.ts:586). Same package also has `includeBrowse?: boolean` -(model.ts:588), `includeManifestCapabilities?: boolean` (model.ts:589). +**Symbols:** `ListTablesRequest.omitColumns?: boolean` (model.ts:531), +`omitProperties?: boolean` (model.ts:533), `omitUsername?: boolean` +(model.ts:535). Same package also has `includeBrowse?: boolean` +(model.ts:537), `includeManifestCapabilities?: boolean` (model.ts:539). **Issue:** Five boolean flags on the same request type: -- Three positive `include…` (which add output). +- Two positive `include…` (which add output). - Three negative `omit…` (which subtract output). The mixing of positive and negative forms is unusual. Code completion @@ -837,15 +631,15 @@ time.** (Note: `omitUsername` is also a singular — "username", not "usernames" — even though the JSDoc lists three fields (owner, updated_by, created_by). -Should be `omitUsernames`. See finding 28.) +Should be `omitUsernames`. See finding 21.) --- -### 28. `ListTables.omitUsername` singular but covers three fields — category 9 (Singular/plural mismatch) +### 21. `ListTablesRequest.omitUsername` singular but covers three fields — category 9 (Singular/plural mismatch) -**Symbol:** `ListTables.omitUsername?: boolean | undefined` (model.ts:586). -JSDoc: "Whether to omit the username of the table (e.g. owner, updated_by, -created_by) from the response or not." +**Symbol:** `ListTablesRequest.omitUsername?: boolean | undefined` +(model.ts:535). JSDoc: "Whether to omit the username of the table (e.g. +owner, updated_by, created_by) from the response or not." **Issue:** Singular `Username` but the JSDoc lists three fields. Plural `omitUsernames` would match the impact ("omit *all* the username fields"). @@ -856,11 +650,11 @@ changing the wire string. **Coordinate with protocol team.** --- -### 29. `ListTables.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* +### 22. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* -**Symbol:** `ListTables.maxResults?: number | undefined` (model.ts:578), -JSDoc: "Maximum number of tables to return. If not set, all the tables -are returned (not recommended)." +**Symbol:** `ListTablesRequest.maxResults?: number | undefined` +(model.ts:527), JSDoc: "Maximum number of tables to return. If not set, all +the tables are returned (not recommended)." The pagination docstring is long and warns that unpaginated calls will be deprecated. The naming is fine; the API behaviour is the issue. @@ -869,57 +663,57 @@ deprecated. The naming is fine; the API behaviour is the issue. --- -### 30. `ListTableSummaries.schemaNamePattern` / `tableNamePattern` vs. `ListTables.schemaName` field-name inconsistency — category 17 (Inconsistent action verbs) +### 23. `ListTableSummariesRequest.schemaNamePattern` / `tableNamePattern` vs. `ListTablesRequest.schemaName` field-name inconsistency — category 17 (Inconsistent action verbs) -**Symbols:** `ListTableSummaries.schemaNamePattern` (model.ts:535) and -`ListTableSummaries.tableNamePattern` (model.ts:540) vs. `ListTables.schemaName` -(model.ts:570). +**Symbols:** `ListTableSummariesRequest.schemaNamePattern` (model.ts:484) +and `ListTableSummariesRequest.tableNamePattern` (model.ts:489) vs. +`ListTablesRequest.schemaName` (model.ts:519). **Issue:** Two sibling list endpoints accept the schema name as different shapes: -- `ListTables.schemaName` — an exact string match. -- `ListTableSummaries.schemaNamePattern` — a SQL LIKE pattern. +- `ListTablesRequest.schemaName` — an exact string match. +- `ListTableSummariesRequest.schemaNamePattern` — a SQL LIKE pattern. JSDoc explains the difference. But the *callers* must remember which endpoint uses which form. There is no naming hint that one is a pattern. -**Suggested:** rename `ListTables.schemaName` to `schemaNameExact` or -`schemaNameEquals` to surface the contrast — or rename -`ListTableSummaries.schemaNamePattern` to `schemaName` with JSDoc clarifying -the pattern syntax. The former is the cleaner pick (less ambiguous on the -input side). +**Suggested:** rename `ListTablesRequest.schemaName` to `schemaNameExact` +or `schemaNameEquals` to surface the contrast — or rename +`ListTableSummariesRequest.schemaNamePattern` to `schemaName` with JSDoc +clarifying the pattern syntax. The former is the cleaner pick (less +ambiguous on the input side). **Flag at port time.** --- -### 31. `ListTableSummaries_Response.tables` returns `TableSummary[]` not `TableInfo[]` — category 6 (Misleading names) and category 15 (Generic field names losing meaning) +### 24. `ListTableSummariesRequest_Response.tables` returns `TableSummary[]` not `TableInfo[]` — category 6 (Misleading names) and category 15 (Generic field names losing meaning) -**Symbol:** `ListTableSummaries_Response.tables?: TableSummary[] | undefined` -(model.ts:558). +**Symbol:** `ListTableSummariesRequest_Response.tables?: TableSummary[] | undefined` +(model.ts:507). **Issue:** A field named `tables` returns *summaries*, not full table info. -The companion `ListTables_Response.tables` returns `TableInfo[]`. So +The companion `ListTablesRequest_Response.tables` returns `TableInfo[]`. So `tables` on one response type vs. another means a different shape. -**Suggested:** rename `ListTableSummaries_Response.tables` to `summaries` -(matches the response type name). Or rename to `tableSummaries`. Both -expose the shape difference at the field name. +**Suggested:** rename `ListTableSummariesRequest_Response.tables` to +`summaries` (matches the response type name). Or rename to `tableSummaries`. +Both expose the shape difference at the field name. **Flag at port time.** --- -### 32. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` / `VolumeDependency` / `SecretDependency` defined in three packages — category 12 (Duplicate concepts) +### 25. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` defined in three packages — category 12 (Duplicate concepts) **Symbols:** -- This file: `Dependency` (model.ts:453), `DependencyList` (model.ts:473), - and the six leaf-types (model.ts:317, 406, 512, 704, 756, 940). -- `functions/v1/model.ts:74–407` — full duplicate. -- `registeredmodels/v1/model.ts:16–423` — full duplicate. +- This file: `Dependency` (model.ts:412), `DependencyList` (model.ts:422), + and the four leaf-types (model.ts:276, 365, 461, 694). +- `functions/v1/model.ts` — full duplicate. +- `registeredmodels/v1/model.ts` — full duplicate. -**Issue:** Three packages export the same eight types. Each defines its own -`Dependency` discriminated union with the same six cases. The field shapes +**Issue:** Three packages export the same six types. Each defines its own +`Dependency` discriminated union with the same four cases. The field shapes are identical (e.g. `TableDependency.tableFullName` is `tableFullName` in all three). A consumer who uses `tables.TableDependency` and `functions.TableDependency` will get two different (but structurally @@ -930,9 +724,9 @@ from each service package. **Strong SDK-wide cleanup.** --- -### 33. `Dependency.value` field name is generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 26. `Dependency.value` field name is generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) -**Symbol:** `Dependency.value` (model.ts:454). Type is the discriminated +**Symbol:** `Dependency.value` (model.ts:413). Type is the discriminated union. **Issue:** `value` is the maximally generic field name. The proto source @@ -946,10 +740,10 @@ if (dep.value?.$case === 'table') { ``` `value` adds noise without distinguishing the shape. Compare to -`EncryptionDetails.encryptionDetailsType` (model.ts:489) — same pattern, -non-generic name. Compare to `TableConstraint.constraint` (model.ts:739) — -same pattern, more descriptive name. Within this file, **three different -naming conventions for the same generator pattern.** +`EncryptionDetails.encryptionDetailsType` (model.ts:438) — same pattern, +non-generic name (see finding 27). Compare to `TableConstraint.constraint` +(model.ts:677) — same pattern, more descriptive name. Within this file, +**three different naming conventions for the same generator pattern.** **Suggested:** `Dependency.dependency` (matches the type name) or `Dependency.kind` (consistent with discriminated-union nomenclature). @@ -957,9 +751,9 @@ naming conventions for the same generator pattern.** --- -### 34. `EncryptionDetails.encryptionDetailsType` repeats the type name as the field name — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) +### 27. `EncryptionDetails.encryptionDetailsType` repeats the type name as the field name — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) -**Symbol:** `EncryptionDetails.encryptionDetailsType` (model.ts:489). +**Symbol:** `EncryptionDetails.encryptionDetailsType` (model.ts:438). **Issue:** Inside the type `EncryptionDetails`, the field name `encryptionDetailsType` repeats two of the three tokens of the type name. @@ -970,7 +764,7 @@ encDetails.encryptionDetailsType?.$case when `encDetails.kind?.$case` or `encDetails.details?.$case` would suffice. -Compare to `Dependency.value` (finding 33) — same pattern, generic name. +Compare to `Dependency.value` (finding 26) — same pattern, generic name. Compare to `TableConstraint.constraint` — same pattern, name is the type *concept* without `Type` suffix. @@ -978,9 +772,9 @@ Compare to `TableConstraint.constraint` — same pattern, name is the type --- -### 35. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) +### 28. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) -**Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:261). +**Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:240). JSDoc: "Ordinal position of column (starting at position 0)." **Issue:** Bare `position` (number) — a consumer cannot tell from the @@ -991,11 +785,11 @@ or `columnIndex`. **Pass with note** — the field is short and conventional. --- -### 36. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — six `type*` fields — category 12 (Duplicate concepts) +### 29. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — six `type*` fields — category 12 (Duplicate concepts) -**Symbols:** `ColumnInfo.typeText` (model.ts:258), `typeName` (model.ts:259), -`typePrecision` (model.ts:262), `typeScale` (model.ts:263), -`typeIntervalType` (model.ts:267), `typeJson` (model.ts:269). +**Symbols:** `ColumnInfo.typeText` (model.ts:237), `typeName` (model.ts:238), +`typePrecision` (model.ts:242), `typeScale` (model.ts:244), +`typeIntervalType` (model.ts:246), `typeJson` (model.ts:248). **Issue:** Six fields all describing the column's data type, prefixed `type…`. The JSDoc says: @@ -1029,31 +823,31 @@ export interface ColumnInfo { --- -### 37. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) +### 30. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) -**Symbols:** `RowFilter.functionName?: string` (model.ts:689), -`RowFilter.inputColumnNames?: string[]` (model.ts:694), -`RowFilter.inputArguments?: PolicyFunctionArgument[]` (model.ts:700). +**Symbols:** `RowFilter.functionName?: string` (model.ts:633), +`RowFilter.inputColumnNames?: string[]` (model.ts:638), +`RowFilter.inputArguments?: PolicyFunctionArgument[]` (model.ts:644). **Issue:** Naming is consistent for arrays (`columnNames`, `arguments` — both plural). But: - `inputColumnNames` is **deprecated** per JSDoc ("This is the replacement - of the deprecated input_column_names field" — model.ts:697); the + of the deprecated input_column_names field" — model.ts:641); the replacement is `inputArguments`. - The deprecated field name still exists in the TS surface and is generated/marshalled. **Suggested:** mark `inputColumnNames` with `@deprecated`. Cross-reference -`ColumnMask.usingColumnNames` (model.ts:287) which has the same +`ColumnMask.usingColumnNames` (model.ts:266) which has the same deprecation note. --- -### 38. `ColumnMask.usingArguments` vs `RowFilter.inputArguments` action-verb difference — category 17 (Inconsistent action verbs) +### 31. `ColumnMask.usingArguments` vs `RowFilter.inputArguments` action-verb difference — category 17 (Inconsistent action verbs) **Symbols:** `ColumnMask.usingArguments?: PolicyFunctionArgument[]` -(model.ts:293), `RowFilter.inputArguments?: PolicyFunctionArgument[]` -(model.ts:700). +(model.ts:272), `RowFilter.inputArguments?: PolicyFunctionArgument[]` +(model.ts:644). **Issue:** Both fields have the same purpose (positional arguments to a SQL UDF), the same type (`PolicyFunctionArgument[]`), and the same JSDoc @@ -1065,9 +859,9 @@ But the verb prefix differs: `using…` for masks, `input…` for filters. --- -### 39. `PolicyFunctionArgument.arg` field name is too short — category 1 (Vague/generic) +### 32. `PolicyFunctionArgument.arg` field name is too short — category 1 (Vague/generic) -**Symbol:** `PolicyFunctionArgument.arg` (model.ts:662). Discriminated +**Symbol:** `PolicyFunctionArgument.arg` (model.ts:606). Discriminated union of `column` / `constant`. **Issue:** `arg` is three letters — too short for a public field. The @@ -1077,19 +871,19 @@ name. Consumer writes: if (positionalArg.arg?.$case === 'column') { ... } ``` -Compare to `Dependency.value` (finding 33) and -`EncryptionDetails.encryptionDetailsType` (finding 34) — same pattern, +Compare to `Dependency.value` (finding 26) and +`EncryptionDetails.encryptionDetailsType` (finding 27) — same pattern, three different naming conventions. The `arg` here is the most cryptic. **Suggested:** `argument` (full word) or `kind`. --- -### 40. `PrimaryKeyConstraint.childColumns` vs `ForeignKeyConstraint.childColumns` semantic mismatch — category 6 (Misleading names) and category 12 (Duplicate concepts) +### 33. `PrimaryKeyConstraint.childColumns` vs `ForeignKeyConstraint.childColumns` semantic mismatch — category 6 (Misleading names) and category 12 (Duplicate concepts) **Symbols:** `PrimaryKeyConstraint.childColumns?: string[]` -(model.ts:680), `ForeignKeyConstraint.childColumns?: string[]` -(model.ts:502). +(model.ts:624), `ForeignKeyConstraint.childColumns?: string[]` +(model.ts:451). **Issue:** Both types use `childColumns` for "the columns of this table participating in the constraint." But: @@ -1097,11 +891,11 @@ participating in the constraint." But: primary key has no parent table. - For a foreign key, "child" matches the FK domain (child references parent). `ForeignKeyConstraint` has both `childColumns` and - `parentColumns` (model.ts:506) — natural pair. + `parentColumns` (model.ts:455) — natural pair. The `PrimaryKeyConstraint.childColumns` field name is misleading — in PK context, the columns are simply *the* columns. Cross-reference the wire -form `child_columns` (model.ts:1102, 1214) which inherits the same issue +form `child_columns` (model.ts:1017, 1125) which inherits the same issue from upstream. **Suggested:** rename `PrimaryKeyConstraint.childColumns` to @@ -1109,11 +903,11 @@ from upstream. --- -### 41. `PrimaryKeyConstraint.timeseriesColumns` vs `ColumnMask.usingColumnNames` plural-vs-singular inconsistency — category 9 (Singular/plural mismatch) +### 34. `PrimaryKeyConstraint.timeseriesColumns` vs `ColumnMask.usingColumnNames` plural-vs-singular inconsistency — category 9 (Singular/plural mismatch) **Symbols:** `PrimaryKeyConstraint.timeseriesColumns?: string[]` -(model.ts:682), `ColumnMask.usingColumnNames?: string[]` (model.ts:287), -`ColumnMask.functionName?: string` (model.ts:281). +(model.ts:626), `ColumnMask.usingColumnNames?: string[]` (model.ts:266), +`ColumnMask.functionName?: string` (model.ts:260). **Issue:** Within the same file: - `columns` (plural): `PrimaryKeyConstraint.childColumns`, @@ -1131,14 +925,14 @@ one. **Flag at port time.** --- -### 42. `ForeignKeyConstraint.rely` boolean is cryptic — category 5 (Cryptic abbreviations) +### 35. `ForeignKeyConstraint.rely` boolean is cryptic — category 5 (Cryptic abbreviations) -**Symbol:** `ForeignKeyConstraint.rely?: boolean | undefined` (model.ts:508). +**Symbol:** `ForeignKeyConstraint.rely?: boolean | undefined` (model.ts:457). JSDoc: "True if the constraint is RELY, false or unset if NORELY." **Issue:** "RELY" / "NORELY" are SQL keywords (Spark's `ALTER TABLE ... RELY` hint). The JSDoc explains them; the field name alone is opaque. Same -critique applies to `PrimaryKeyConstraint.rely` (model.ts:684). +critique applies to `PrimaryKeyConstraint.rely` (model.ts:628). **Suggested:** rename to `relyEnabled` or `enableRely` — the boolean form needs an `is…` / `enable…` prefix to match SDK convention. **Coordinate @@ -1146,9 +940,9 @@ with protocol team.** --- -### 43. `OptionSpec.isCopiable` typo or unusual spelling — category 5 (Cryptic abbreviations) and category 6 (Misleading names) +### 36. `OptionSpec.isCopiable` typo or unusual spelling — category 5 (Cryptic abbreviations) and category 6 (Misleading names) -**Symbol:** `OptionSpec.isCopiable?: boolean | undefined` (model.ts:649). +**Symbol:** `OptionSpec.isCopiable?: boolean | undefined` (model.ts:598). JSDoc: "Indicates whether an option should be displayed with copy button on the UI." @@ -1161,13 +955,13 @@ are "copyable" or "copy-able". The generator picked the less-common form --- -### 44. `OptionSpec` has 9 `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* +### 37. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* -**Symbols:** `OptionSpec.isRequired` (model.ts:635), -`OptionSpec.isSecret` (model.ts:637), `OptionSpec.isHidden` (model.ts:639), -`OptionSpec.isUpdatable` (model.ts:641), `OptionSpec.isLoggable` -(model.ts:645), `OptionSpec.isCreatable` (model.ts:647), -`OptionSpec.isCopiable` (model.ts:649). +**Symbols:** `OptionSpec.isRequired` (model.ts:584), +`OptionSpec.isSecret` (model.ts:586), `OptionSpec.isHidden` (model.ts:588), +`OptionSpec.isUpdatable` (model.ts:590), `OptionSpec.isLoggable` +(model.ts:594), `OptionSpec.isCreatable` (model.ts:596), +`OptionSpec.isCopiable` (model.ts:598). The boolean fields all use the `is…` prefix, which is the right convention for booleans. **Pass on naming.** @@ -1179,45 +973,26 @@ correctly may want a richer type. **Note for upstream.**) --- -### 45. `ConditionalDisplay.dependsOnOption` vs `hiddenWhenValues` field naming asymmetry — category 17 (Inconsistent action verbs) - -**Symbols:** `ConditionalDisplay.dependsOnOption?: string` (model.ts:307), -`ConditionalDisplay.hiddenWhenValues?: string[]` (model.ts:313). - -**Issue:** Two fields modelling the same relation (option-A's value -determines option-B's visibility): -- `dependsOnOption` — singular, identifies the "watched" option. -- `hiddenWhenValues` — plural, the values that trigger hiding. - -The verb forms differ: "depends on…" vs. "hidden when…". A reader skimming -the type sees them as unrelated. The pair would be cleaner as e.g. -`{watchOption, hideOnValues}` or `{trigger: {option, hideOnValues}}`. - -**Suggested:** rename `dependsOnOption` to `watchOption` or -`triggerOption`. **Flag at port time.** - ---- - -### 46. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 38. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` -(model.ts:480). JSDoc: "Whether predictive optimization should be enabled +(model.ts:429). JSDoc: "Whether predictive optimization should be enabled for this object and objects under it." **Issue:** The type's *purpose* is to indicate whether PO is enabled. The field name `value` says nothing about that. The type is also a `string` -(not a `boolean`) — same problem as finding 23. +(not a `boolean`) — same problem as finding 16. **Suggested:** rename `value` → `enabled` (boolean) or `state` (matching the JSDoc's "enabled" sense). **Coordinate with protocol team.** --- -### 47. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) +### 39. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) **Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` -(model.ts:482), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` -(model.ts:484). +(model.ts:431), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` +(model.ts:433). **Issue:** Two fields describing the source of inheritance — the object type ("CATALOG"|"SCHEMA"|…) and the object's name. Naming is OK, but the @@ -1232,11 +1007,11 @@ flat form is wire-faithful. --- -### 48. `TableConstraint.constraint` and `TableConstraint` discriminated-union shape — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) +### 40. `TableConstraint.constraint` and `TableConstraint` discriminated-union shape — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) -**Symbol:** `TableConstraint.constraint` (model.ts:739). +**Symbol:** `TableConstraint.constraint` (model.ts:677). -**Issue:** Same problem as finding 34 (`EncryptionDetails.encryptionDetailsType`). +**Issue:** Same problem as finding 27 (`EncryptionDetails.encryptionDetailsType`). Field repeats the type name's primary token. The discriminated union of three constraint shapes is wrapped in a field literally named `constraint`. @@ -1244,37 +1019,36 @@ three constraint shapes is wrapped in a field literally named `constraint`. --- -### 49. `Client` class name — category 1 (Vague/generic) — *pass* +### 41. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. **Pass.** --- -### 50. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* +### 42. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* Standard `{verb}{Resource}` shape. Convention. **Pass.** -(Note: `Client.tableExists` (client.ts:472) breaks the verb-first pattern — +(Note: `Client.tableExists` (client.ts:478) breaks the verb-first pattern — it reads `noun-verb` instead of `verb-noun`. The corresponding shape in -other SDKs is `existsTable` or `checkTableExists`. The current form mirrors -the request type name `TableExists` which is itself unusual — see finding -18. **Flag at SDK-wide level.**) +other SDKs is `existsTable` or `checkTableExists`. **Flag at SDK-wide +level.**) --- -### 51. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* +### 43. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* Same `{verb}{Resource}` pattern. **Pass.** --- -### 52. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* +### 44. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* Standard. **Pass.** --- -### 53. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) +### 45. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:55). @@ -1288,7 +1062,7 @@ SDK-wide cleanup.** --- -### 54. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 46. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` (utils.ts:15). @@ -1302,7 +1076,7 @@ SDK-wide cleanup** — generated boilerplate. --- -### 55. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 47. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). @@ -1314,7 +1088,7 @@ layers. The names imply a hierarchical relationship that does not exist. --- -### 56. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* +### 48. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* Verb-prefixed. Naming is fine. `flattenQueryParams` is used by the multi-query-param list methods (client.ts:357, 444). @@ -1327,7 +1101,7 @@ file.) --- -### 57. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* +### 49. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, `TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide @@ -1335,17 +1109,17 @@ pattern. **Pass.** --- -### 58. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`, `'volume'`, `'secret'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* +### 50. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* -**Symbols:** `Dependency.value.$case` literals (model.ts:455–467). +**Symbols:** `Dependency.value.$case` literals (model.ts:414–417). -**Issue:** The six `$case` literals are plain nouns. Within the file: -- `TableConstraint.constraint.$case` literals (model.ts:741, 745, 749) are +**Issue:** The four `$case` literals are plain nouns. Within the file: +- `TableConstraint.constraint.$case` literals (model.ts:679, 683, 687) are `'primaryKeyConstraint'` / `'foreignKeyConstraint'` / `'namedTableConstraint'` — i.e. *suffixed* with `Constraint`. -- `EncryptionDetails.encryptionDetailsType.$case` literal (model.ts:491) is +- `EncryptionDetails.encryptionDetailsType.$case` literal (model.ts:440) is `'sseEncryptionDetails'` — suffixed with `Details`. -- `PolicyFunctionArgument.arg.$case` literals (model.ts:664, 669) are +- `PolicyFunctionArgument.arg.$case` literals (model.ts:608, 613) are `'column'` / `'constant'` — plain nouns, like `Dependency.value`. So **four discriminated unions, two different naming conventions** for @@ -1356,7 +1130,7 @@ their $case literals. --- -### 59. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* +### 51. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* **Symbol:** `parseResponse` (utils.ts:113) does `JSON.parse(text)` unconditionally. The name implies it can handle any response shape; in @@ -1367,15 +1141,48 @@ practice it only handles JSON. --- +### 52. `_PropertiesEntry` / `_Response` underscore-suffixed proto-nested type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) + +**Symbols:** `CreateTableRequest_PropertiesEntry` (model.ts:359), +`DeleteTableConstraintRequest_Response` (model.ts:383), +`DeleteTableRequest_Response` (model.ts:391), +`DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` (model.ts:403), +`ListTableSummariesRequest_Response` (model.ts:505), +`ListTablesRequest_Response` (model.ts:543), +`TableExistsRequest_Response` (model.ts:705), +`TableInfo_PropertiesEntry` (model.ts:782), +`UpdateTableRequest_PropertiesEntry` (model.ts:869), +`UpdateTableRequest_Response` (model.ts:875). + +**Issue:** Underscores in PascalCase identifiers are not idiomatic TS +(Google style guide § 5.1 disallows them; the generated code carries an +`eslint-disable-next-line @typescript-eslint/naming-convention` comment +above each). The underscores survive from the proto's nested-message +naming. Several `…_Response` types are *empty* bodies kept only to mirror +the proto definition. + +**Suggested:** +- For `_Response` empty bodies: drop the type entirely; the method can + return `void`. +- For `_PropertiesEntry` / `_DeltaRuntimePropertiesEntry` map-entry types: + drop or inline — `Record` is sufficient. +- For non-empty responses (`ListTablesRequest_Response`, + `TableExistsRequest_Response`): rename to `ListTablesResponse`, + `TableExistsResponse` (PascalCase, no underscore). + +**Flag for SDK-wide generator cleanup.** + +--- + ## Cross-package alignment recommendations ### A. `Dependency` family duplicated in three packages -`tables`, `functions`, and `registeredmodels` each export the same eight +`tables`, `functions`, and `registeredmodels` each export the same six types: `Dependency`, `DependencyList`, `TableDependency`, `FunctionDependency`, -`ConnectionDependency`, `CredentialDependency`, `VolumeDependency`, -`SecretDependency`. Same shape, same fields, three copies. Strong P0 -candidate for hoisting to `@databricks/sdk-core/dependency`. +`ConnectionDependency`, `CredentialDependency`. Same shape, same fields, +three copies. Strong P0 candidate for hoisting to +`@databricks/sdk-core/dependency`. --- @@ -1400,8 +1207,8 @@ types with the same fields and the same enum values. Three copies. ### D. `EffectivePredictiveOptimizationFlag` defined in `tables` and `catalogs` -`catalogs/v1/model.ts:240` defines the same type as -`tables/v1/model.ts:478`. Three fields (`value`, `inheritedFromType`, +`catalogs/v1/model.ts` defines the same type as +`tables/v1/model.ts:427`. Three fields (`value`, `inheritedFromType`, `inheritedFromName`). **Suggested:** hoist or pick a canonical home. @@ -1410,8 +1217,8 @@ types with the same fields and the same enum values. Three copies. ### E. `ColumnTypeName` defined in `tables` and `functions` -`functions/v1/model.ts:5` defines the same enum. 27 SQL/Spark data-type -values shared. +`functions/v1/model.ts:5` defines the same enum. The shared SQL/Spark +data-type values overlap heavily. **Suggested:** hoist to `@databricks/sdk-core/sql-types`. @@ -1419,8 +1226,8 @@ values shared. ### F. `RowFilter` / `ColumnMask` vs. `abacpolicies.RowFilterOptions` / `abacpolicies.ColumnMaskOptions` shape divergence -`tables/v1/model.ts:687` defines `RowFilter` and `tables/v1/model.ts:279` -defines `ColumnMask`. `abacpolicies/v1/model.ts:38, 295` defines +`tables/v1/model.ts:631` defines `RowFilter` and `tables/v1/model.ts:258` +defines `ColumnMask`. `abacpolicies/v1/model.ts` defines `ColumnMaskOptions` / `RowFilterOptions`. Same domain, different shapes and naming. @@ -1439,8 +1246,8 @@ suffix on URL-path arguments. Drop SDK-wide. This package, `onlinetables`, `database`, `postgres`, and `featurestore` all model "table" concepts at different layers: -- `tables.TableType` (model.ts:209) — 9 values for UC table classifications. -- `tables.SecurableKind` (model.ts:81) — 70+ values, mostly `TABLE_*` +- `tables.TableType` (model.ts:189) — 9 values for UC table classifications. +- `tables.SecurableKind` (model.ts:78) — 70+ values, mostly `TABLE_*` prefixes for finer-grained UC kinds. - `onlinetables.OnlineTableState` — the lifecycle/sync state of an online table (overlaps with `TableType.MATERIALIZED_VIEW`, @@ -1459,10 +1266,10 @@ documentation pass needed.** | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics) | 13 | #1, #8, #9, #17, #20, #21, #23, #25, #32, #33, #40, #46, #53 | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 26 | #2, #3, #4, #5, #7, #10, #11, #12, #13, #15, #16, #18, #19, #22, #24, #27, #28, #30, #31, #34, #36, #37, #38, #42, #45, #48 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 10 | #6, #26, #39, #41, #43, #47, #54, #55, #58, #59 | -| **Pass / acceptable** | 10 | #14, #29, #35, #44, #49, #50, #51, #52, #56, #57 | +| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics, proto-architectural leaks) | 18 | #1, #5, #12, #13, #14, #16, #18, #25, #26, #33, #38, #45, #53, #54, #55, #56, #57, #58 | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 21 | #2, #4, #6, #7, #8, #9, #10, #11, #15, #17, #20, #21, #23, #24, #27, #29, #30, #31, #35, #40, #52 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 10 | #3, #19, #32, #34, #36, #39, #46, #47, #50, #51 | +| **Pass / acceptable** | 9 | #22, #28, #37, #41, #42, #43, #44, #48, #49 | --- @@ -1471,15 +1278,127 @@ documentation pass needed.** 1. **#1** — fix `DeltaRuntimePropertiesKvpairs` (field) / `DeltaRuntimePropertiesKvPairs` (type) casing mismatch. Local, mechanical rename. -2. **#17** — drop the `Arg` suffix from `fullNameArg` SDK-wide. Higher +2. **#12** — drop the `Arg` suffix from `fullNameArg` SDK-wide. Higher impact (changes wire field name) but eliminates a Go-style convention. -3. **#23** — type `enablePredictiveOptimization` as a real enum instead of +3. **#16** — type `enablePredictiveOptimization` as a real enum instead of a free-form string. Improves type safety. -4. **#33 / #34 / #39 / #48** — unify discriminated-union container field +4. **#26 / #27 / #32 / #40** — unify discriminated-union container field names (`value` vs `encryptionDetailsType` vs `arg` vs `constraint`). Within-file consistency fix. -5. **#31** — rename `ListTableSummaries_Response.tables` to `summaries` - (or `tableSummaries`). Easy local fix. -6. **#9** — `SecurableKind` 70+ values: hoist to a shared module and - consider splitting `TableKind` from non-table kinds. Local TS readability - plus SDK-wide structure fix. +5. **#24** — rename `ListTableSummariesRequest_Response.tables` to + `summaries` (or `tableSummaries`). Easy local fix. + +--- + +--- + +### 53. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:209, 222 + +**Why:** Underscore-separated `OuterMessage_InnerEnum` naming is a literal +transcription of proto nested-enum scoping. The infix `_` and the +container-prefix on a sibling enum is a proto/grpc architectural leak; +TypeScript has no nested-enum concept. + +**Category:** proto-architectural-leak (`Proto` infix / Go-Java nested-name +form). + +**Suggested:** `OauthStage` and `OptionType` (drop the `OptionSpec_` +prefix) — or, if collision risk exists, `OptionOauthStage` / +`OptionTypeKind`. + +**Rationale:** the `OptionSpec_` prefix exists solely to mirror the proto +nesting; the eslint-disable comments on lines 208, 221 acknowledge the +non-idiomatic shape. + +--- + +### 54. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:563 + +**Why:** `Spec` is a generic config-style suffix that re-appears across +the file (`SecurableKindManifest`, `EffectivePredictiveOptimizationFlag`, +`SseEncryptionDetails`, `EncryptionDetails`). It echoes proto/k8s +"Spec"-shaped messages whose only job is to describe a struct. + +**Category:** proto-architectural-leak (repeated `Spec` config-suffix). + +**Suggested:** `Option` (the type already lives in `SecurableKindManifest.options` +and is self-describing) or `OptionDefinition`. + +**Rationale:** the `Spec` suffix adds no domain meaning beyond "this is a +struct describing X" — a proto convention, not a TS one. + +--- + +### 55. `SecurableKindManifest` type name — file:line model.ts:648 + +**Why:** `Manifest` is a config-style suffix (analogous to `Spec`/`Config`). +It tags the type as a descriptor message rather than a domain concept. + +**Category:** proto-architectural-leak (config-suffix style). + +**Suggested:** `SecurableKindCapabilities` (matches `capabilities` field +content) or fold into a richer `SecurableKind`-keyed structure. + +**Rationale:** the type holds five fields (`securableType`, `securableKind`, +`assignablePrivileges`, `options`, `capabilities`) — the `Manifest` token +adds no information beyond "this is the descriptor". + +--- + +### 56. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:233, 710, 787 + +**Why:** `Info` and `Summary` are generic descriptor-suffixes used to +distinguish the wire/RPC message from the domain noun (`Column`, `Table`). +Two `…Info` types and a `…Summary` type in the same file flag this as a +repeated config-suffix pattern. + +**Category:** proto-architectural-leak (repeated `Info` config-suffix). + +**Suggested:** `Column`, `Table`, `TableOverview` (or collapse all three +into `Table` per finding #13). + +**Rationale:** in a TS surface the noun *is* the type; the `Info`/`Summary` +tag exists only to disambiguate from the proto request/response messages +and from server-internal representations — a generator/architectural leak. + +--- + +### 57. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:437, 662 + +**Why:** Two `…Details` types in the same file. `Details` is a generic +"descriptor" suffix with no domain meaning — same family as `Info`/`Spec`. + +**Category:** proto-architectural-leak (repeated `Details` config-suffix). + +**Suggested:** `Encryption` and `SseEncryption` (or `SseEncryptionConfig` +if disambiguation is needed). The discriminated-union container field +`encryptionDetailsType` (finding #27) then becomes `encryption.kind` — and +the redundant `Details` token disappears. + +**Rationale:** `Details` is generator boilerplate for proto messages +wrapping `oneof`s or option blobs; idiomatic TS uses the bare domain noun. + +--- + +### 58. `dataAccessConfigurationId` field — `Configuration` mid-position config-suffix — file:line model.ts:327, 750, 837 + +**Why:** `Configuration` mid-token (between `DataAccess` and `Id`) is a +config-suffix occurrence inside a field name. The wire form is +`data_access_configuration_id`; the TS form repeats the noise. + +**Category:** proto-architectural-leak (`Config` family mid-position). + +**Suggested:** `dataAccessConfigId` (shorter) or `dataAccessId` if the +"configuration" is implicit (the value already identifies a config record). + +**Rationale:** five-token field names with a mid `Configuration` token are +a strong signal of proto-style verbose naming surviving the wire→TS port. + +--- + +## Fixed + +- #18 `TableExists` (originally cited at model.ts:761): Fixed in regeneration on 2026-05-20 — request type renamed to `TableExistsRequest`, resolving the verb-as-noun reading on the request surface. +- #19 Request type naming pattern is inconsistent (originally cited at model.ts:322, 411, 417, 419, 432, 517, 528, 566, 594, 761, 857, 399): Fixed in regeneration on 2026-05-20 — all request types now carry the `Request` suffix (`CreateTableRequest`, `DeleteTableRequest`, `DeleteTableConstraintRequest`, `GetTableRequest`, `ListTablesRequest`, `ListTableSummariesRequest`, `TableExistsRequest`, `UpdateTableRequest`, `CreateTableConstraintRequest`). +- #45 `ConditionalDisplay.dependsOnOption` vs `hiddenWhenValues` field naming asymmetry (originally cited at model.ts:307, 313): Fixed in regeneration on 2026-05-20 — the `ConditionalDisplay` interface is no longer generated for this package. +- #32 (partial) — `VolumeDependency` and `SecretDependency` (originally cited at model.ts:704, 940 with the rest of the Dependency family): Fixed in regeneration on 2026-05-20 — those two leaf types and the `volume` / `secret` discriminated-union cases were removed from `Dependency`; the cross-package duplication concern (now finding #25) still applies to the four remaining leaf types. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 551feea5..7b1ce513 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -3,13 +3,13 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. -**Total weird names flagged:** 27 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | | High | 10 | -| Medium | 10 | +| Medium | 12 | | Low | 4 | | Observation | 3 | @@ -145,27 +145,39 @@ - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries Java/JS Builder-pattern connotations. +### 21. `AuthHttpClient` — `src/v1/transport.ts:43` +- **Why weird:** Class name encodes its implementation pattern: it is an `HttpClient` whose role is "wraps another HttpClient and injects auth headers". The JSDoc on line 42 literally reads "Wraps an HttpClient and adds authentication headers to requests." That is the Decorator/Wrapper architectural pattern leaking into the type name. The name describes the *how* (HTTP client decorator), not the *what* (authenticated transport). +- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` style class whose name advertises a decorator implementation rather than the domain role. +- **Suggested name:** `AuthenticatingTransport`, `AuthenticatedTransport`, or `AuthInjector`. Drops the `HttpClient` infix that just restates the base interface it decorates. +- **Rationale:** A class whose only job is to add auth headers should be named for that job, not the wrapping mechanism. Sister packages all duplicate this class verbatim — generator-wide concern. + +### 22. `TimeoutHttpClient` — `src/v1/transport.ts:61` +- **Why weird:** Same wrapper-name pattern as #21. JSDoc line 60: "Wraps an HttpClient and applies a default timeout to requests." Name encodes the wrapping mechanism (`HttpClient` suffix) plus the cross-cutting concern (`Timeout` prefix). Reads as `` — a classic Decorator naming tell. +- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` class whose name advertises a decorator-of-HttpClient implementation rather than the domain role. +- **Suggested name:** `TimeoutTransport`, `RequestTimeout`, or merge the timeout behavior into the base `newFetchHttpClient` so a separate type is unneeded. +- **Rationale:** `TimeoutHttpClient` is two architectural words concatenated: the concern (`Timeout`) and the wrapped interface (`HttpClient`). Domain names should describe behavior, not the OO pattern. Generator-wide concern — every package repeats this. + ## Low severity -### 21. `flattenQueryParams` — `src/v1/utils.ts:123` +### 23. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in `client.ts`. This package's `listTagAssignments` uses individual `params.append(...)` calls (line 142-148) instead. Dead-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. -### 22. `readAll(body)` — `src/v1/utils.ts:40` +### 24. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is too generic; the function specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** Reads like it might take a file path or array. -### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 25. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The single word "segment" provides no domain context. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Comment above the constant does the work the name should. -### 24. `tagValue` field doc empty — `src/v1/model.ts:53,54` +### 26. `tagValue` field doc empty — `src/v1/model.ts:53,54` - **Why weird:** `tagValue?: string | undefined` is documented as "The value of the tag" — a tautology. Compare the rich docs on `entityType`/`entityId`/`tagKey` (with character-class rules). The doc is doing zero work. - **Category:** 1 (vague — doc says nothing the field name does not), 15 (generic field doc). - **Suggested name:** Document what makes a `tagValue` valid (max length? character set? same restrictions as `tagKey`?). @@ -173,14 +185,14 @@ ## Observations -### 25. Action verb consistency +### 27. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 26. `tagassignments` lowercase package name vs. types and HTTP path +### 28. `tagassignments` lowercase package name vs. types and HTTP path The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). -### 27. Domain leakage between sister packages +### 29. Domain leakage between sister packages Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md index b135e2ea..eff5c9ce 100644 --- a/.agent/naming-audit/tagpolicies.md +++ b/.agent/naming-audit/tagpolicies.md @@ -2,15 +2,15 @@ **Path:** `packages/tagpolicies/src/v1/` **Versions audited:** v1 -**Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and optional `propagationConfig` (with conflict-resolution rules) so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. -**Total weird names flagged:** 30 +**Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and an optional `id`/timestamps so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. +**Total weird names flagged:** 18 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 10 | -| Low | 8 | +| High | 6 | +| Medium | 4 | +| Low | 4 | | Observation | 4 | ## High severity @@ -21,105 +21,57 @@ - **Suggested name:** Merge into a single `tags` (or `taxonomy`) package with sub-namespaces `tags.policies`, `tags.assignments.platform`, `tags.assignments.uc`. As a smaller fix, rename to `governedtags` (this package) and `governedtagvalues` (or similar) to make the role explicit. - **Rationale:** Three `Client`s in three packages collide on combined imports. The user-facing surface should follow the user mental model ("I want to manage tags"), not the wire-side `/api/2.1/tag-policies` vs. `/api/2.0/tag-assignments` vs. `/api/2.1/unity-catalog/entity-tag-assignments` partition. Worth flagging as a generator-level structural concern. -### 2. `TagPolicy` — `src/v1/model.ts:62` -- **Why weird:** The primary type is "a policy for a tag", which is fine — but the type is keyed by `tagKey` (line 63) and the package is *named* after the tag's policy. Every reference is "the tag policy's tag key", "the tag policy's account ID", "the tag policy's values". The `Tag` prefix on the type is doing the work that the package directory already does. Sister types `TagAssignment` / `EntityTagAssignment` repeat the `Tag` noun identically. The name reads like Go. -- **Category:** 8 (redundant prefix — `Tag` repeats the universal subject of this package), 12 (duplicate concept naming pattern with sister types), 14 (Go-style — Go SDK needs the `Tag` prefix to distinguish from other `Policy` structs in the same Go package; TS module imports already do that disambiguation). -- **Suggested name:** `Policy` (rely on package-import disambiguation), or `GovernedTag` (since "governed" is the term used throughout the JSDoc — `client.ts:66,92,111,136,187`). -- **Rationale:** "Governed tag" is the canonical domain term that appears in every method's docstring; "tag policy" is the wire/proto-side term. SDK should expose the domain term. +### 2. `TagPolicy` exposes the wire-side term instead of the domain term — `src/v1/model.ts:36` +- **Why weird:** The primary type is named `TagPolicy`, but the JSDoc on every client method talks about "governed tags" (`client.ts:66,92,111,136,187`). "Governed tag" is the canonical domain term; "tag policy" is the wire/proto-side term that mirrors the `/api/2.1/tag-policies` path. The SDK should expose the domain term, not the wire-side noun. +- **Category:** 14 (Go-style — Go SDK keeps the wire-side noun; TS users would benefit from the domain term). +- **Suggested name:** `GovernedTag` (matches domain language used throughout the JSDoc). +- **Rationale:** The user-facing concept is "this tag is governed", not "this tag has a policy attached". Cross-SDK consistency vs. domain readability trade-off. -### 3. Doubled `Policy` suffix in the conflict-resolution path — `src/v1/model.ts:9,11,13` -- **Why weird:** The outer type is `ConflictResolutionPolicy`, its field is named `policy`, and the only case-payload type is `DefaultValueOverridePolicy`. The token "policy" appears on the outer type, on the field, and on the payload — three uses of "Policy" in one tree to express "use this default when there's a conflict". -- **Category:** 8 (redundant suffix — `Policy` appears on the outer type, on the field, and on the payload), 20 (type-suffix tautology — `Policy` on the field of a `*Policy` of a `*Policy`). -- **Suggested name:** Drop one of the three. For example, rename the outer type to `ConflictResolution`, the field to `strategy`, and the payload to `DefaultValueOverride`. -- **Rationale:** `propagationConfig.conflictResolution.policy.$case === 'defaultValueOverride'` reads as type-noise; reducing the `Policy` repetition makes the path read naturally. - -### 4. `Client` class — `src/v1/client.ts:41` +### 3. `Client` class — `src/v1/client.ts:41` - **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The sister packages (`tagassignments`, `entitytagassignments`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages, plus this `Client` in the rest of the SDK's ~70 other packages. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages and the entire SDK). - **Suggested name:** `TagPoliciesClient` (matches the package name) or `GovernedTagsClient` (matches domain language). - **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing on every co-use (`import {Client as TagPoliciesClient} from '@databricks/sdk-tagpolicies'`). Generator-level concern. -### 5. Method names `createTagPolicy` / `deleteTagPolicy` / `getTagPolicy` / `listTagPolicies` / `updateTagPolicy` — `src/v1/client.ts:67,93,112,137,188` -- **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createTagPolicy(...)` reads as "package.subject.create.subject" — the noun is doubled. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. Sister packages do the same. -- **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `TagPolicy` five times when the client only manages `TagPolicy`). -- **Suggested name:** `create`, `delete`, `get`, `list`, `update`. -- **Rationale:** A client class that ships exactly five methods all named after the same subject is repeating the subject. `TagPoliciesClient.create()` reads better than `client.createTagPolicy()`. - -### 6. `tagKey` is both the resource identifier and a field on `TagPolicy` — `src/v1/model.ts:63` and `model.ts:31,35` -- **Why weird:** The thing that uniquely identifies a `TagPolicy` is its `tagKey` (string), but the same type *also* has an `id: string` field (`model.ts:64`). The wire URL is `/api/2.1/tag-policies/{tagKey}` — i.e., the path key is `tagKey`, not `id`. Two identifiers, no JSDoc saying which one is authoritative. Compare to `BudgetPolicy` (`policyId`, `policyName`) which has the same split — same problem. +### 4. `tagKey` is both the resource identifier and a field on `TagPolicy` — `src/v1/model.ts:37` and `model.ts:13,17` +- **Why weird:** The thing that uniquely identifies a `TagPolicy` is its `tagKey` (string), but the same type *also* has an `id: string` field (`model.ts:38`). The wire URL is `/api/2.1/tag-policies/{tagKey}` — i.e., the path key is `tagKey`, not `id`. Two identifiers, no JSDoc saying which one is authoritative. Compare to `BudgetPolicy` (`policyId`, `policyName`) which has the same split — same problem. - **Category:** 1 (vague — which field actually identifies the resource?), 6 (misleading — `id` looks like a primary key, but the URL uses `tagKey`), 19 (underspecified ID — what does `id` mean if the path uses `tagKey`?), 16 (field contradicts type domain). - **Suggested name:** Document both fields explicitly. `tagKey` is the user-chosen primary key (the tag name itself); `id` is presumably an opaque server-generated handle. Suggest: keep both but JSDoc each, OR collapse to just `tagKey` if `id` is dead. - **Rationale:** Two unlabeled IDs in a type is a recipe for caller confusion. The SDK should make plain which is the resource key. -### 7. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:31,35` +### 5. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:13,17` - **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${this.host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:97,116`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). - **Category:** 6 (misleading — type says optional, semantics says required), 19 (underspecified ID — what should `tagKey` look like? Constraints? Encoding?). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) on get/delete/update. Add JSDoc describing valid keys. - **Rationale:** Optional path parameters in REST clients are a generator anti-pattern. Honest required-ness should travel through the type, not through a `?? ''` fallback that produces a malformed URL. -### 8. `Value.name` field — `src/v1/model.ts:83` -- **Why weird:** Field on `Value` is `name?: string | undefined` (line 83), but conceptually the field holds the *value text* of an allowed tag value (e.g., `"prod"`, `"dev"`). Calling that text `name` collides with the domain meaning of "tag value": the value's `name` is the value. JSDoc is empty. There is no `displayName` or other field to disambiguate — `name` is the *only* field. +### 6. `Value.name` field — `src/v1/model.ts:53` +- **Why weird:** Field on `Value` is `name?: string | undefined` (line 53), but conceptually the field holds the *value text* of an allowed tag value (e.g., `"prod"`, `"dev"`). Calling that text `name` collides with the domain meaning of "tag value": the value's `name` is the value. JSDoc is empty. There is no `displayName` or other field to disambiguate — `name` is the *only* field. - **Category:** 1 (vague/generic — `name` for a string that is the value itself), 6 (misleading — `name` suggests a label distinct from the value), 15 (generic field name losing meaning), 16 (field name contradicts type domain — `Value.name` reads "the name of a value", but the value's name *is* the value). - **Suggested name:** Rename to `Value.value` (still awkward) or `AllowedValue.text`. - **Rationale:** `tagPolicy.values[0].name` reads as "the name of the first value of this tag policy", which is structurally absurd. ## Medium severity -### 9. `PropagationConfig` type — `src/v1/model.ts:55` -- **Why weird:** The type's two fields (`enabled?: boolean`, `conflictResolution?: ConflictResolutionPolicy`) describe how a tag's *value* propagates through lineage. The name `PropagationConfig` is generic — any system can have a propagation config. The JSDoc context "automatically propagated through data lineage" disappears once a user lands on the type. -- **Category:** 1 (vague — `PropagationConfig` could mean anything), 15 (generic name losing meaning), 20 (type-suffix tautology — `Config` on a config-shaped struct). -- **Suggested name:** `LineagePropagation` (carries the domain), `TagPropagation`, or `TagPolicyPropagation`. -- **Rationale:** Bare `PropagationConfig` is too thin to discover what it propagates. The wire field is `propagation_config`; the TS type can be more specific. - -### 10. `propagationConfig.enabled` boolean shape — `src/v1/model.ts:57` -- **Why weird:** A boolean field literally named `enabled`. The pattern is `propagationConfig.enabled = true`. JS/TS booleans are conventionally `is*`/`has*` or scoped (`enabledForPropagation`). On a config object whose entire purpose is to describe propagation, a field called `enabled` is missing its scope qualifier — enabled to do *what*? (The answer is "propagate", but the field name is silent on that.) -- **Category:** 1 (vague), 15 (generic name), 17 (verb-tense/predicate inconsistency). -- **Suggested name:** `propagate?: boolean` (collapse the wrapper) or `isEnabled` if the wrapper stays. -- **Rationale:** `propagationConfig.enabled` reads as "the propagation config is enabled". A clearer shape would be `tagPolicy.propagate = true` directly. - -### 11. `CreateTagPolicyRequest` / `DeleteTagPolicyRequest` / `GetTagPolicyRequest` / `ListTagPoliciesRequest` / `UpdateTagPolicyRequest` — `src/v1/model.ts:20,30,34,38,77` -- **Why weird:** Five request DTOs share a 12-char prefix `TagPolicy*Request`. Each is 24–32 characters; the common substring is repetition. In the package whose only subject is `TagPolicy`, every request type re-states that subject. -- **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). -- **Suggested name:** `CreateRequest` / `DeleteRequest` / `GetRequest` / `ListRequest` / `UpdateRequest`, or drop the `Request` suffix when the method signature is self-documenting. -- **Rationale:** Single-subject packages don't need to repeat the subject on every request DTO. Cross-SDK convention, but worth flagging. - -### 12. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:38` vs. `model.ts:62` +### 7. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:20` vs. `model.ts:36` - **Why weird:** Plural only on list endpoint; singular elsewhere. The list response is `ListTagPoliciesResponse` (plural). The wire path is `/tag-policies` (plural). The convention is consistent with the Go SDK, but worth flagging that the resource name on the wire is plural while the item type is singular. - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary within one type family). - **Suggested name:** Keep as is (cross-SDK convention). Listed for completeness under rule 9. - **Rationale:** Same as in `entitytagassignments` audit — flagged because rule 9 demands it. -### 13. `ListTagPoliciesResponse.tagPolicies` field — `src/v1/model.ts:50` -- **Why weird:** Response wraps the items in `tagPolicies: TagPolicy[]`. Re-states the type name on the field. Common pattern but mechanically dense: `resp.tagPolicies.forEach(p => p.tagKey)`. Alternatives like `items` or `policies` reads more cleanly. -- **Category:** 8 (redundant prefix — `Tag` repeats on the field of a response in `ListTagPolicies*Response`), 7 (overly verbose). -- **Suggested name:** `items: TagPolicy[]` or `policies: TagPolicy[]`. -- **Rationale:** Once the response type is `ListTagPoliciesResponse`, the field name doesn't need to re-state "tag policies". - -### 14. `tagPolicies` / `tagPolicy` field naming asymmetry between Create/Update and List response — `src/v1/model.ts:21,50,78` -- **Why weird:** `CreateTagPolicyRequest.tagPolicy: TagPolicy` (singular field for singular subject), `UpdateTagPolicyRequest.tagPolicy: TagPolicy`, `ListTagPoliciesResponse.tagPolicies: TagPolicy[]`. The naming is consistent in form (singular/plural matches type cardinality), but in both cases the field re-states the type. Adding a body wrapper at create/update is asymmetric with the response side: the response has the array directly, the request has the singular wrapped — and the response *also* wraps in a separate `tagPolicies` field. -- **Category:** 17 (inconsistency — wrappers on request and response with different cardinality semantics). -- **Suggested name:** `policy` (request) and `policies` (response). Drop the `tag` prefix; preserve cardinality. -- **Rationale:** Reduces typing and makes the symmetry visible. - -### 15. `defaultValueOverride` case identifier vs. type name — `src/v1/model.ts:13,15` -- **Why weird:** The discriminator case is `'defaultValueOverride'` (a string literal), the field that carries the payload is also `defaultValueOverride`, and the payload type is `DefaultValueOverridePolicy`. Three identifiers in one switch (`$case === 'defaultValueOverride'` ⇒ `defaultValueOverride.defaultValue`) that say the same thing. -- **Category:** 8 (redundant repetition — case literal, field name, and type all share a prefix), 7 (overly verbose). -- **Suggested name:** Drop the `Policy` suffix on the payload type (-> `DefaultValueOverride`). -- **Rationale:** Three identifiers in one switch (`$case === 'defaultValueOverride'` ⇒ `defaultValueOverride.defaultValue`) that say the same thing make for noisy type checks. - -### 16. `tagPolicyFieldMask(...paths: string[])` exported helper — `src/v1/model.ts:281` -- **Why weird:** A free function `tagPolicyFieldMask` exported alongside the type system. The user types `tagPolicyFieldMask('description', 'values')` — the package name is already `tagpolicies`, so the `tagPolicy` prefix re-states the package scope. Sister packages do the same (`tagAssignmentFieldMask`, etc.). -- **Category:** 8 (redundant prefix `tagPolicy` on a function exported only from the `tagpolicies` package). -- **Suggested name:** `fieldMask` (let the import path supply scope). -- **Rationale:** Once a caller has imported from `@databricks/sdk-tagpolicies`, the `tagPolicy` prefix on the helper is noise. - -### 17. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` +### 8. Create/update wrap the subject in a body field while the list response also wraps in an array field — `src/v1/model.ts:9,32,48` +- **Why weird:** `CreateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) and `UpdateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) both put the subject inside a one-field body. `ListTagPoliciesResponse.tagPolicies: TagPolicy[]` does the analogous thing for the response. Each wrapper is a single-field envelope around the actual payload, which means every caller writes `client.create({tagPolicy: {...}})` instead of `client.create({...})`. The envelope is consistent in cardinality (singular/plural matches the type), but it adds a level of indirection on every call. +- **Category:** 17 (inconsistency — request and response both wrap, but callers must remember the wrapper field name on each side). +- **Suggested name:** N/A — the wrapper envelopes are dictated by wire-side proto shape. Flagged as a generator-level consideration. +- **Rationale:** Single-field body envelopes show up across the generated SDK; this package is one instance. + +### 9. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` - **Why weird:** Two near-identical names with different purposes. `executeCall(call, options)` runs a `Call` through the retrier/rate-limiter; `executeHttpCall(opts)` issues a single HTTP request and reads the body. The names differ by one word (`Http`) but the responsibilities are radically different (orchestrator vs. transport). A user grepping for "execute" can't tell which one to use. - **Category:** 1 (vague — the disambiguator is too thin), 17 (inconsistent verb scoping). - **Suggested name:** `executeCall` (orchestrator) and `sendHttpRequest` (single-request transport). - **Rationale:** Distinct responsibilities should have distinct verb roots, not a same-verb-different-noun split. -### 18. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 10. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that this client does not invoke (the list endpoint uses individual `params.append(...)` calls instead — see `client.ts:143,146`). Dead-code-shaped helper. - **Category:** 6 (misleading — implies the package uses it), 1 (vague — `flatten` is generic; this specific one only handles a subset of types). - **Suggested name:** N/A — should live in a shared utils package, not be copied into every package. @@ -127,84 +79,63 @@ ## Low severity -### 19. `createTime` and `updateTime` naming on `TagPolicy` — `src/v1/model.ts:68,70` +### 11. `createTime` and `updateTime` naming on `TagPolicy` — `src/v1/model.ts:42,44` - **Why weird:** Verb tense / noun pair where the natural English is "created at" / "updated at". `createTime` reads as "the time to create" (a verb-noun); `createdAt` is the cross-language convention for "timestamp when it was created". Cross-SDK convention is `createTime`/`updateTime`, so this is consistent with the rest of the codebase, but is non-idiomatic JS/TS. - **Category:** 13 (verb-tense inconsistency — `create` (infinitive) vs. `created` (past participle)), 14 (Go-style naming — Go uses `CreateTime`). - **Suggested name:** `createdAt` / `updatedAt`. - **Rationale:** Established SDK pattern, but rule 13/14 demand the flag. Mongo, PostgREST, Rails, GraphQL conventions all use `createdAt`. -### 20. `accountId: string` on `TagPolicy` — `src/v1/model.ts:74` -- **Why weird:** "The account ID that owns this tag policy." — generic. `accountId` is consistent across the SDK, but the SDK's bound to an account already (via `ClientOptions.accountId`), so this field is redundant *output* (the server tells you the account that owns the policy, which the client already knows). -- **Category:** 1 (vague — what kind of ID? account number? UUID?), 19 (underspecified ID — no format documented), 15 (generic field name losing meaning in the SDK context). -- **Suggested name:** Keep `accountId`; document that it's the Databricks account UUID. -- **Rationale:** Minor; flagged because all `*Id` fields without docs trigger rule 19. - -### 21. `Temporal.Instant` for timestamps — `src/v1/model.ts:68,70` +### 12. `Temporal.Instant` for timestamps — `src/v1/model.ts:42,44` - **Why weird:** Uses `Temporal.Instant` (from `@js-temporal/polyfill`), which is a great future-proof choice — but `Instant` is unfamiliar to most JS devs (who expect `Date` or string). The doc says "Timestamp when the tag policy was created" without explaining why it's an `Instant`. - **Category:** 1 (slightly vague choice without doc support), 5 (cryptic to readers unfamiliar with Temporal proposal). - **Suggested name:** Keep `Temporal.Instant`; add JSDoc explaining the type choice. - **Rationale:** Generator-wide; flagged once. -### 22. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:43-44` +### 13. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:22-25` - **Why weird:** JSDoc says "The maximum value is 1000; values above 1000 will be coerced down to 1000." but the field is typed `number | undefined`. A caller passing `pageSize: 100000` silently gets clipped to 1000. The constraint travels only via the docstring. - **Category:** 6 (misleading — type does not match contract). - **Suggested name:** Keep `pageSize`; consider a branded type or a runtime validator. At minimum, restate the limit clearly. - **Rationale:** Generator-wide; flagged because docs lie about wire behaviour. -### 23. `updateMask` field type `FieldMask` — `src/v1/model.ts:79` +### 14. `updateMask` field type `FieldMask` — `src/v1/model.ts:49` - **Why weird:** `FieldMask` is a generic type carrying the masked-shape as a type parameter. The name `updateMask` is wire-standard (proto FieldMask) but cryptic to TS users — "mask" usually means a bitmask. The JSDoc is missing. - **Category:** 5 (cryptic — `mask` for TS users means bitmask), 14 (proto-style — FieldMask is a proto concept). - **Suggested name:** Keep `updateMask`; add JSDoc explaining it's a path-based selector for partial updates. - **Rationale:** Generator-wide name; flag once. -### 24. `id` field on `TagPolicy` — `src/v1/model.ts:64` -- **Why weird:** Field name `id` with no JSDoc on what it represents — server-generated UUID? Hashed `tagKey`? Path key for some other endpoint? See #6 for the duplicate-identifier critique; this is the underspecified-`id`-name flag separately. -- **Category:** 1 (vague), 19 (underspecified ID), 15 (generic name). -- **Suggested name:** `policyId` or `governedTagId`; add JSDoc. -- **Rationale:** Sibling `BudgetPolicy.policyId` uses the prefix; `TagPolicy.id` does not. Cross-SDK inconsistency. - -### 25. `description` field doc missing — `src/v1/model.ts:65` -- **Why weird:** Just `description?: string | undefined` with no JSDoc. Width limits? Mandatory? Format? -- **Category:** 1 (vague — no contract on the field). -- **Suggested name:** Keep `description`; add JSDoc. -- **Rationale:** Common pattern, but flagged because rule 1 demands it. - -### 26. `host` constructor field with trailing-slash stripping — `src/v1/client.ts:42,54` -- **Why weird:** The constructor strips trailing `/` from `options.host` (`client.ts:54`). Field is `host`, not `baseUrl` or `endpoint`. The TS field `host` is a string like `https://workspace.cloud.databricks.com`, which is by convention "the base URL" not "the host" (the host would be `workspace.cloud.databricks.com` without scheme). -- **Category:** 6 (misleading — "host" usually means hostname-only). -- **Suggested name:** `baseUrl` or `endpoint`. -- **Rationale:** RFC 3986 §3.2 defines "host" as the authority component without scheme. The SDK's `host` is the full URL. - ## Observations -### 27. Action verb consistency +### 15. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 28. Acronym casing +### 16. Acronym casing File uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri` casing clashes encountered within the file. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 29. `tagpolicies` lowercase package name +### 17. `tagpolicies` lowercase package name Package directory is `tagpolicies` (single token, no separator), but every type uses `TagPolicy*` and the HTTP path uses `tag-policies`. Same problem as `dataclassification`, `tagassignments`, `entitytagassignments` — SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 30. Domain leakage from sister packages +### 18. Domain leakage from sister packages Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — all collide on the noun "tag". Each ships its own `Client`, its own `tag*` types, and its own `tagKey`. Co-import requires extensive aliasing. `tagpolicies` differs in that it defines the *policy* over the tag, while the assignment packages attach a `tagKey` + `tagValue` to entities — but a user can't tell from the name; "tag policies" sounds like it could be policies *for* tag assignments. - **Category:** 12 (duplicate concept across siblings). ## Domain glossary -- `tag policy` — a governed-tag definition with allowed values and propagation rules. +- `tag policy` — a governed-tag definition with allowed values. - `governed tag` — a tag whose key has an active `TagPolicy` (JSDoc on every method mentions this). - `tag key` — the user-chosen identifier of a tag (e.g., `"environment"`). Doubles as the path-key for the resource (`/tag-policies/{tagKey}`). - `tag value` — one of the allowed strings for a tag (e.g., `"prod"`, `"dev"`) — wrapped in a `Value` type that has a single `name` field. -- `propagation` — automatic carry-over of a tag from one entity to another via Unity Catalog lineage. -- `conflict resolution` — the rule applied when multiple upstream entities provide different tag values during propagation. -- `default value override` — the only currently supported conflict-resolution strategy: use a specified default value. -- `account id` — Databricks account UUID; tag policies are account-scoped. - `Terraform documentation` — JSDoc on every method links to the matching `terraform-provider-databricks` page. ## File coverage -- `src/v1/model.ts` (284 lines): read fully. +- `src/v1/model.ts` (143 lines): read fully. - `src/v1/client.ts` (224 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (20 lines): read fully. +- `src/v1/index.ts` (17 lines): read fully. + +## Fixed +- #3 Doubled `Policy` suffix in conflict-resolution path (originally cited at `src/v1/model.ts:9,11,13`): Fixed in regeneration on 2026-05-20 — `ConflictResolutionPolicy` and `DefaultValueOverridePolicy` types removed from the package. +- #9 `PropagationConfig` type (originally cited at `src/v1/model.ts:55`): Fixed in regeneration on 2026-05-20 — `PropagationConfig` type removed from the package. +- #10 `propagationConfig.enabled` boolean shape (originally cited at `src/v1/model.ts:57`): Fixed in regeneration on 2026-05-20 — propagation config removed entirely. +- #15 `defaultValueOverride` case identifier vs. type name (originally cited at `src/v1/model.ts:13,15`): Fixed in regeneration on 2026-05-20 — discriminator union and `DefaultValueOverridePolicy` payload removed. +- #20 `accountId: string` on `TagPolicy` (originally cited at `src/v1/model.ts:74`): Fixed in regeneration on 2026-05-20 — `accountId` field removed from `TagPolicy`. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index 5209bb60..ad4d800c 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -2,197 +2,172 @@ **Path:** `packages/tokenmanagement/src/v1/` **Versions audited:** v1 -**Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/update/delete arbitrary user tokens, plus create on-behalf-of-service-principal tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. -**Total weird names flagged:** 24 +**Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/create-on-behalf-of/delete arbitrary user tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 12 | -| Low | 3 | +| High | 6 | +| Medium | 9 | +| Low | 4 | | Observation | 0 | ## High severity ### 1. Package name `tokenmanagement` duplicates `tokens` — overlap with sibling package -- **Why weird:** Two packages, `tokens` and `tokenmanagement`, both manage Databricks personal access tokens (PATs). They share the same `AutoscopeState` enum (copy-pasted byte-for-byte, model.ts:13-21 in both), both expose `ListTokens`, `RevokeToken`, `UpdateToken`, and `ListTokens` response/request types, and both publish a `Client` class with `listTokens`/`updateToken` methods. The only structural differences are (a) the admin variant adds `getToken`, `createOnBehalfOfToken`, and admin-only fields on its token info, (b) the per-user variant has `createToken` (no on-behalf-of), and (c) the entity type is named `AdminTokenInfo` here vs. `PublicTokenInfo` in `tokens`. URL paths also differ: `/api/2.0/token-management/...` vs `/api/2.0/token/...`. From a TS user's perspective the namespaces collide: `import {Client, ListTokens} from '@databricks/sdk-tokenmanagement/v1'` and `import {Client, ListTokens} from '@databricks/sdk-tokens/v1'` clash on every public name. +- **Why weird:** Two packages, `tokens` and `tokenmanagement`, both manage Databricks personal access tokens (PATs). Both expose `ListTokens*`, `RevokeToken*`, and list response/request types, and both publish a `Client` class with `listTokens` methods. The only structural differences are (a) the admin variant adds `getToken`, `createOnBehalfOfToken`, and admin-only fields on its token info, (b) the per-user variant has `createToken` (no on-behalf-of), and (c) the entity type is named `AdminTokenInfo` here vs. `PublicTokenInfo` in `tokens`. URL paths also differ: `/api/2.0/token-management/...` vs `/api/2.0/token/...`. From a TS user's perspective the namespaces collide: `import {Client, ListTokensRequest} from '@databricks/sdk-tokenmanagement/v1'` and `import {Client, ListTokensRequest} from '@databricks/sdk-tokens/v1'` clash on every public name. - **Category:** 12 (duplicate concepts across `tokens` vs `tokenmanagement` packages). - **Suggested name:** Keep the directory split (the API is split upstream) but in the public exports prefix admin types: `AdminListTokensRequest`, `AdminRevokeTokenRequest`, etc., or alternatively rename the package to `tokenadmin` so the call-site distinction is unmistakable (`@databricks/sdk-tokenadmin`). -- **Rationale:** Today consumers who import both packages cannot do so by named import without aliasing every type. The shared enum (`AutoscopeState`) is also duplicated; one of the two packages should re-export the other's enum, or the enum should live in a shared core/identity module. +- **Rationale:** Today consumers who import both packages cannot do so by named import without aliasing every type. -### 2. `AutoscopeState` enum values — redundant prefix on every member -- **Why weird:** Every member re-states the enum name: `AUTOSCOPE_STATE_UNSPECIFIED`, `AUTOSCOPE_STATE_DISABLED`, `AUTOSCOPE_STATE_RUNNING`, `AUTOSCOPE_STATE_COMPLETED`, `AUTOSCOPE_STATE_BACKFILLED`, `AUTOSCOPE_STATE_USER_SELECTED`, `AUTOSCOPE_STATE_API_NOT_COVERED` — `src/v1/model.ts:13-21`. Plus `UNSPECIFIED` is a proto-buf sentinel that idiomatic TS expresses with `undefined`. -- **Category:** 2 (redundant enum prefix), 14 (proto/Go-style enum values not idiomatic in TS). -- **Suggested name:** `AutoscopeState.Unspecified | Disabled | Running | Completed | Backfilled | UserSelected | ApiNotCovered` — or drop `Unspecified` and rely on `autoscopeState?: AutoscopeState | undefined`. -- **Rationale:** TS enum members are already namespaced by the enum (`AutoscopeState.Disabled`). The `AUTOSCOPE_STATE_` prefix is pure protobuf noise. This enum is also a copy of the identical enum in the `tokens` package; the prefix problem is doubled. - -### 3. `AdminTokenInfo` — `Info` is a vague suffix, package-specific prefix is misleading -- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. +### 2. `AdminTokenInfo` — `Info` is a vague suffix, package-specific prefix is misleading +- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. `src/v1/model.ts:5`. - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix), 15 (generic suffix that loses meaning). - **Suggested name:** `Token` (or `ManagedToken` if `Token` would clash with a class on the consumer side; given this is exported from `@databricks/sdk-tokenmanagement/v1`, `Token` is fine — see also finding #1 about cross-package name collisions). - **Rationale:** `Token` is the noun the user thinks about. `Info` is a Go-SDK tic; TS does not need it. -### 4. `CreateOnBehalfOfToken` — verb-phrase type name reads as a function -- **Why weird:** Request DTO named with a verb phrase looks like a method or command, not data. Same broken pattern as `GetToken`, `ListTokens`, `RevokeToken`, `UpdateToken`. With `index.ts` re-exporting these as `type {…}`, `import type {CreateOnBehalfOfToken}` looks at the call site like importing a function. -- **Category:** 6 (misleading — verb-phrase noun), 14 (Go-style request type names). -- **Suggested name:** `CreateOnBehalfOfTokenRequest` (and cascading `GetTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`). -- **Rationale:** TypeScript convention names request DTOs with a `Request` suffix; bare verb-phrase nouns read as actions. - -### 5. Client method `deleteToken` wraps request type `RevokeToken` — verb-tense inconsistency -- **Why weird:** `client.deleteToken(req: RevokeToken)` at client.ts:103-104. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently (tokens client.ts:131 + request type `RevokeToken`). +### 3. Client method `deleteToken` wraps request type `RevokeTokenRequest` — verb-tense inconsistency +- **Why weird:** `client.deleteToken(req: RevokeTokenRequest)` at `client.ts:99-100` with the type defined at `model.ts:85`. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently. - **Category:** 13 (verb-tense inconsistency between method and request type), 17 (inconsistent action verbs across the two packages: `tokenmanagement.deleteToken` vs `tokens.revokeToken` for the same kind of operation). - **Suggested name:** Either rename method to `revokeToken` (matches type and matches sibling package) or rename type to `DeleteTokenRequest` (matches HTTP verb). Recommend the former so both packages share a verb. - **Rationale:** "Revoke" carries a security/lifecycle meaning that "delete" loses; tokens aren't deleted from history, they're invalidated. -### 6. `UpdateToken.token: AdminTokenInfo` field — type-suffix tautology and id placement diverges from sibling -- **Why weird:** `UpdateToken` (the request type) has a single semantic field `token` of type `AdminTokenInfo` plus an `updateMask`. The field name `token` paired with type `AdminTokenInfo` works only because `AdminTokenInfo` has the `Info` suffix; rename to `Token` (per finding #3) and `token: Token` becomes type-suffix tautology. The client signature `updateToken(req: UpdateToken)` and then `req.token?.tokenId ?? ''` (client.ts:191) means a caller must construct `{token: {tokenId: ...}, updateMask: ...}`. The sibling `tokens` package hoists `tokenId` to the top level (tokens model.ts:87-93), so consumers of both packages see different ergonomics for the same operation. -- **Category:** 20 (type-suffix tautology if `Info` is removed). -- **Suggested name:** Reuse the cleaner sibling-package pattern in `tokens`: `UpdateToken { tokenId; token; updateMask }` where `tokenId` is hoisted (tokens model.ts:87-93). -- **Rationale:** The admin variant forces the id into the nested body while the sibling `tokens` package hoists it. This is a real ergonomic delta worth flagging upstream; consumers of both packages will trip on it. - -### 7. `client.updateToken` returns `AdminTokenInfo`, sibling returns `UpdateTokenResponse` — inconsistent response handling -- **Why weird:** `tokenmanagement.Client.updateToken` returns `Promise` (client.ts:190) — the bare entity. The sibling `tokens.Client.updateToken` returns `Promise`. Worse: the `tokenmanagement` version doesn't even have a response type declared in `model.ts`; the client just unmarshals into the entity. So in one package `updateToken` returns the updated row; in the other it returns a different shape. -- **Category:** 12 (duplicate concept inconsistently implemented), 17 (inconsistent client return shapes). -- **Suggested name:** Pick one — either always return the updated entity (preferred; useful) or always return void. If returning the entity, name the type `Token`/`UpdateTokenResponse` rather than reusing the raw entity, so it can evolve. -- **Rationale:** Cross-package consistency. A user who learns one client will be surprised by the other. - -### 8. `tokenInfo` field on response types — `Info` tautology -- **Why weird:** Field `tokenInfo: AdminTokenInfo` (model.ts:66, 84). Field name re-states the type's redundant suffix. Cascades from the `AdminTokenInfo` → `Token` rename (finding #3). +### 4. `tokenInfo` field on response types — `Info` tautology +- **Why weird:** Field `tokenInfo: AdminTokenInfo | undefined` on `CreateOnBehalfOfTokenRequest_Response` (`model.ts:42`) and `GetTokenRequest_Response` (`model.ts:60`). Field name re-states the type's redundant suffix. Cascades from the `AdminTokenInfo` → `Token` rename (finding #2). - **Category:** 20 (type-suffix tautology), 1 (`Info` vague). -- **Suggested name:** `token: Token` (paired with rename in finding #3). +- **Suggested name:** `token: Token` (paired with rename in finding #2). - **Rationale:** Mechanical cascade. `response.token.tokenId` reads more naturally than `response.tokenInfo.tokenId`. -### 9. `tokenInfos` field on list response — plural of `Info`, doc-string mismatch -- **Why weird:** Field `tokenInfos: AdminTokenInfo[]` (model.ts:106). Same `Info` tautology as #8 but plural. Also: the JSDoc says "Token metadata of each user-created token in the workspace" — "metadata" implies summary info, but `AdminTokenInfo` is the full row. The field name should be `tokens` not `tokenInfos`. +### 5. `tokenInfos` field on list response — plural of `Info`, doc-string mismatch +- **Why weird:** Field `tokenInfos: AdminTokenInfo[] | undefined` on `ListTokensRequest_Response` (`model.ts:82`). Same `Info` tautology as #4 but plural. Also: the JSDoc says "Token metadata of each user-created token in the workspace" — "metadata" implies summary info, but `AdminTokenInfo` is the full row. The field name should be `tokens` not `tokenInfos`. - **Category:** 20 (type-suffix tautology), 9 (plural-of-`Info` is unidiomatic), 1 (`Info` vague), 15 (field name "tokenInfos" loses meaning). -- **Suggested name:** `tokens: Token[]` (paired with rename in finding #3). -- **Rationale:** Same as #8. Sibling `tokens` list response has the identical issue (tokens model.ts:55). +- **Suggested name:** `tokens: Token[]` (paired with rename in finding #2). +- **Rationale:** Same as #4. Sibling `tokens` list response has the identical issue. -## Medium severity +### 6. `AdminTokenInfo` — `Admin` mid-position prefix is an architectural-tier leak (not domain) — `src/v1/model.ts:5` +- **Why:** `Admin` mid-position on the entity type names a service-tier / audience-of-callers (admin vs. non-admin caller), not a domain concept. The sibling package uses `PublicTokenInfo` for the same kind of leak (`Public` mid-position). Tokens are not "admin tokens"; they are personal access tokens that this admin-scoped endpoint can list/manage. The `Admin`/`Public` distinction is purely about which RBAC tier of the backend service exposes the model. +- **Category:** Proto-architectural-leak — `Public`/`Internal`/`External` family of mid-position service-tier qualifiers used as a noun prefix. +- **Suggested:** `Token` (or `ManagedToken` to disambiguate from the sibling package's entity; see also finding #2 which already proposes `Token`). +- **Rationale:** The `Admin` qualifier survives from the proto's two-tier service split (`token-management` admin-scoped service vs. `token` user-scoped service). End users of the SDK only see one type per import; the architectural-tier label adds no domain meaning at the call site (e.g., `token.tokenId` is clearer than `adminTokenInfo.tokenId`). -### 10. `PAT` acronym never appears, autoscope comments reference it tacitly -- **Why weird:** The doc comments on `AutoscopeState` (model.ts:8) say "State of inferred scope collection (autoscope) for an external PAT." But nowhere else in the file does the abbreviation `PAT` (Personal Access Token) appear — and `Token` is used everywhere as a stand-in. A user grepping for `PAT` (an industry-standard term in security tooling) finds nothing. Inversely, `Token` could mean OAuth, ID, refresh, etc., but in this package it always means PAT. The package would be unambiguous if named `pats` or `personalaccesstokens`. -- **Category:** 5 (cryptic abbreviation in comment only), 15 (`Token` is too generic for the domain). -- **Suggested name:** Add `PAT` aliases or document at the package level. Consider renaming `Token` → `PersonalAccessToken` or, less verbosely, keep `Token` but clarify in JSDoc. -- **Rationale:** Discoverability. This package is the admin PAT API; calling that out beats hiding it. +## Medium severity -### 11. `applicationId` on `CreateOnBehalfOfToken` — generic field name in a security-sensitive context -- **Why weird:** `applicationId: string` (model.ts:51) is the OAuth client ID of the service principal the on-behalf-of token will represent. "Application ID" is Azure terminology; on AWS/GCP it's "service principal ID" or "client ID". This is the *target* identity for a privileged token-mint operation; `applicationId` undersells the security implication and overloads "application" with three different meanings across Databricks clouds. +### 7. `applicationId` on `CreateOnBehalfOfTokenRequest` — generic field name in a security-sensitive context +- **Why weird:** `applicationId?: string` (`model.ts:29`) is the OAuth client ID of the service principal the on-behalf-of token will represent. "Application ID" is Azure terminology; on AWS/GCP it's "service principal ID" or "client ID". This is the *target* identity for a privileged token-mint operation; `applicationId` undersells the security implication and overloads "application" with three different meanings across Databricks clouds. - **Category:** 1 (vague — "application" is overloaded), 14 (Azure-style naming leaks), 15 (generic name in security context), 19 (underspecified ID — application ID of what?). - **Suggested name:** `servicePrincipalApplicationId` or `servicePrincipalClientId` (the JSDoc literally says "Application ID of the service principal", so the field name should too). - **Rationale:** The field documentation already names the concept correctly; the field name should follow. Mistaking this for "Databricks Apps application id" would mint a token for the wrong principal. -### 12. `ListTokens` request fields `createdById` and `createdByUsername` — duplicate filter slots -- **Why weird:** `ListTokens { createdById?, createdByUsername? }` (model.ts:96-100). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type even says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (client.ts:159-164) which means callers can submit both at once and get undefined server behavior. +### 8. `ListTokensRequest` fields `createdById` and `createdByUsername` — duplicate filter slots +- **Why weird:** `ListTokensRequest { createdById?, createdByUsername? }` (`model.ts:71-76`). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (`client.ts:158-163`) which means callers can submit both at once and get undefined server behavior. - **Category:** 1 (vague — relationship unspecified), 6 (misleading — looks like two filters, possibly redundant). - **Suggested name:** Either expose a single `filter` string or document mutual exclusivity. At minimum, JSDoc the AND/OR semantics. - **Rationale:** Consumer-facing API ambiguity. -### 13. `AdminTokenInfo.scopes`, `AdminTokenInfo.autoscopeState`, `CreateOnBehalfOfToken.scopes`, `CreateOnBehalfOfToken.autoscopeEnabled` — `scopes`/`autoscope*` naming triplet inconsistency -- **Why weird:** Within the same `AdminTokenInfo`, `scopes: string[]` is one thing, `autoscopeState` is another (output-only), and the comment on `CreateOnBehalfOfToken.autoscopeEnabled` (model.ts:57) implies autoscope is a *mode*. So users have to learn: `scopes` (the explicit list), `autoscopeEnabled` (request-side bool), `autoscopeState` (response-side enum), with no `autoscopedScopes` field — the `scopes` field is overloaded as both the input list and the result after autoscope completes. Compare with `tokens.PublicTokenInfo` which has `scopes`, `autoscopeState`, `inferredScopes`, and `backfillScopes` (tokens model.ts:72-77) — i.e., the per-user package separates inferred from explicit scopes; the admin package does not. -- **Category:** 12 (duplicate concept implemented differently than sibling), 1 (vague overloading of `scopes`). -- **Suggested name:** Mirror the `tokens` package by adding `inferredScopes` / `backfillScopes` (or document the overload explicitly). -- **Rationale:** Cross-package inconsistency. Worth pushing upstream. - -### 14. `creationTime` / `expiryTime` / `lastUsedDay` — three time fields with three units and no unit suffix -- **Why weird:** `AdminTokenInfo` (model.ts:27-41) has `creationTime: number`, `expiryTime: number`, `lastUsedDay: number`. The first two are described as "Timestamp" (likely epoch ms, by convention). The third is described as "Approximate timestamp for the day the token was last used. Accurate up to 1 day." But the field is named `lastUsedDay` (not `lastUsedTime` or `lastUsedDate`), and the doc says it is *still* a timestamp — so the suffix `Day` here means "with day-level granularity" not "as a calendar day index". A reader who skims the type and not the doc could easily believe `lastUsedDay` is a 1-31 day-of-month integer or a number-of-days-since-epoch integer. +### 9. `creationTime` / `expiryTime` / `lastUsedDay` — three time fields with three units and no unit suffix +- **Why weird:** `AdminTokenInfo` (`model.ts:9-23`) has `creationTime: number`, `expiryTime: number`, `lastUsedDay: number`. The first two are described as "Timestamp" (likely epoch ms, by convention). The third is described as "Approximate timestamp for the day the token was last used. Accurate up to 1 day." But the field is named `lastUsedDay` (not `lastUsedTime` or `lastUsedDate`), and the doc says it is *still* a timestamp — so the suffix `Day` here means "with day-level granularity" not "as a calendar day index". A reader who skims the type and not the doc could easily believe `lastUsedDay` is a 1-31 day-of-month integer or a number-of-days-since-epoch integer. - **Category:** 5 (cryptic — `Day` is ambiguous), 6 (misleading — "Day" implies a date, value is a timestamp), 15 (generic name without unit). - **Suggested name:** `lastUsedTimeMs` (or split into `lastUsedTime: number` + a JSDoc note). At minimum, document the unit on all three fields. -- **Rationale:** Compare with `tokens.PublicTokenInfo.lastAccessedTime` (tokens model.ts:69) which uses `Time` consistently. The admin variant breaks the pattern. +- **Rationale:** Compare with `tokens.PublicTokenInfo.lastAccessedTime` which uses `Time` consistently. The admin variant breaks the pattern. -### 15. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc -- **Why weird:** `AdminTokenInfo` has `createdById` ("User ID of the user that created the token") and `ownerId` ("User ID of the user that owns the token"). What's the difference? In the sibling `tokens` package, the type has no `ownerId`. This appears to be admin-only metadata where ownership can transfer (e.g., on-behalf-of tokens). A reader has no way to know without external docs whether the two are usually equal. +### 10. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc +- **Why weird:** `AdminTokenInfo` has `createdById` ("User ID of the user that created the token", `model.ts:15`) and `ownerId` ("User ID of the user that owns the token", `model.ts:19`). What's the difference? In the sibling `tokens` package, the type has no `ownerId`. This appears to be admin-only metadata where ownership can transfer (e.g., on-behalf-of tokens). A reader has no way to know without external docs whether the two are usually equal. - **Category:** 1 (vague — relationship unstated), 19 (underspecified IDs in same struct). - **Suggested name:** Keep names but add JSDoc clarifying when they diverge (e.g., on-behalf-of tokens: creator is the principal who called the API, owner is the service principal). - **Rationale:** Discoverability. -### 16. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope -- **Why weird:** `workspaceId?: number | undefined` (model.ts:39) is documented "If applicable, the ID of the workspace that the token was created in." So it's optional and only meaningful at the account level. But the package and the URL path `/api/2.0/token-management/...` is a workspace endpoint. The field thus carries no useful signal at this endpoint, yet it's exposed. +### 11. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope +- **Why weird:** `workspaceId?: number | undefined` (`model.ts:21`) is documented "If applicable, the ID of the workspace that the token was created in." So it's optional and only meaningful at the account level. But the package and the URL path `/api/2.0/token-management/...` is a workspace endpoint. The field thus carries no useful signal at this endpoint, yet it's exposed. - **Category:** 6 (misleading — looks pertinent, often vestigial). - **Suggested name:** Keep; document under what circumstances it is populated (e.g., when the same model is reused at the account API). - **Rationale:** Generator artefact from sharing models across workspace/account scopes. Flag for upstream cleanup. -### 17. `lastUsedDay` vs sibling `tokens.PublicTokenInfo.lastAccessedTime` — different field names for "last use" -- **Why weird:** Same concept, two field names: `lastUsedDay` (admin) vs `lastAccessedTime` (per-user). Different unit precision too. Already partially covered in #14 but worth its own bullet for cross-package consistency. +### 12. `lastUsedDay` vs sibling `tokens.PublicTokenInfo.lastAccessedTime` — different field names for "last use" +- **Why weird:** Same concept, two field names: `lastUsedDay` (admin, `model.ts:23`) vs `lastAccessedTime` (per-user). Different unit precision too. Already partially covered in #8 but worth its own bullet for cross-package consistency. - **Category:** 12 (duplicate concept across packages), 17 (inconsistent verb — used vs accessed). - **Suggested name:** Align to one. Recommend `lastUsedTime` everywhere; "accessed" is a synonym but inconsistent. - **Rationale:** Cross-package consistency. -### 18. `autoscopeEnabled` on `CreateOnBehalfOfToken` but `autoscopeState` on `AdminTokenInfo` — verb/state mix -- **Why weird:** Request input: `autoscopeEnabled: boolean` (boolean toggle). Response output: `autoscopeState: AutoscopeState` (enum). Two different shapes for what is one feature (autoscope). The field-prefix is consistent, but a user must learn that "I set it as a bool" and "I read it back as an enum". -- **Category:** 6 (misleading — write-side bool, read-side enum), 17 (inconsistent shapes for the same feature). -- **Suggested name:** Document the asymmetry, or accept it as an upstream protocol fact. No good rename without breaking the wire. -- **Rationale:** Observation more than action; flagged because it surfaces in two places in this small file. - -### 19. `comment` field — vague, overloaded between SDK comment vs DDL comment vs user note -- **Why weird:** Three of the four user-facing types have a `comment: string` field (`AdminTokenInfo.comment`, `CreateOnBehalfOfToken.comment`). JSDoc says "Comment that describes the purpose of the token" — i.e., a description. Yet the field is called `comment`, which in TS/JS conjures up code comments. Same SQL-DDL leak as in `abacpolicies` (audit finding #28 there). +### 13. `comment` field — vague, overloaded between SDK comment vs DDL comment vs user note +- **Why weird:** Two user-facing types have a `comment: string` field (`AdminTokenInfo.comment` at `model.ts:13`, `CreateOnBehalfOfTokenRequest.comment` at `model.ts:33`). JSDoc says "Comment that describes the purpose of the token" — i.e., a description. Yet the field is called `comment`, which in TS/JS conjures up code comments. Same SQL-DDL leak as in `abacpolicies`. - **Category:** 6 (misleading — `comment` is overloaded), 14 (SQL-DDL-style naming). - **Suggested name:** `description` (matches the JSDoc). - **Rationale:** SQL DDL uses `COMMENT ON ...`; SDK consumers don't. `description` is the standard noun. -### 20. `CreateOnBehalfOfToken` — preposition phrase inside type name -- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token" (parse: VP(NP(token))) when the intent is "create [on-behalf-of token]" (parse: a kind of token). Industry shorthand is "OBO" but the SDK avoids the acronym. +### 14. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name +- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:27`. Industry shorthand is "OBO" but the SDK avoids the acronym. - **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). - **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. - **Rationale:** This is the only operation in the package whose name relies on the preposition; surfacing the intent (mint a token for someone else) helps. Defensible as-is. -### 21. `tokenValue` is a secret but the field name doesn't hint at it -- **Why weird:** The `tokenValue: string` field on the create-on-behalf-of response (model.ts:65). This is the bearer token plaintext, returned exactly once. The field name `tokenValue` doesn't signal "this is a secret; persist immediately; we will never return it again". Compare with cryptographic SDKs that name such fields `secret`, `tokenSecret`, or `bearerToken`. +### 15. `tokenValue` is a secret but the field name doesn't hint at it +- **Why weird:** The `tokenValue: string` field on `CreateOnBehalfOfTokenRequest_Response` (`model.ts:41`). This is the bearer token plaintext, returned exactly once. The field name `tokenValue` doesn't signal "this is a secret; persist immediately; we will never return it again". Compare with cryptographic SDKs that name such fields `secret`, `tokenSecret`, or `bearerToken`. - **Category:** 1 (vague), 6 (misleading — `value` is the most generic suffix imaginable for the most sensitive field in the package). - **Suggested name:** `tokenSecret` or `bearerToken`, and add a JSDoc warning ("Returned once. Store immediately."). - **Rationale:** Defensive naming for security-critical fields helps users not log/leak the value. ## Low severity -### 22. `Client` class is named `Client` (no namespacing) -- **Why weird:** `export class Client` (client.ts:48). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. +### 16. `Client` class is named `Client` (no namespacing) +- **Why weird:** `export class Client` (`client.ts:44`). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. - **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). - **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). - **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. -### 23. `host` field on `Client` — workspace URL is more specific -- **Why weird:** `private readonly host: string;` (client.ts:49). The constructor accepts `options.host` which is actually the workspace URL (e.g., `https://my-workspace.cloud.databricks.com`). "Host" is HTTP-level jargon; `workspaceUrl` is the domain-level term users learn first. +### 17. `host` field on `Client` — workspace URL is more specific +- **Why weird:** `private readonly host: string;` (`client.ts:45`). The constructor accepts `options.host` which is actually the workspace URL (e.g., `https://my-workspace.cloud.databricks.com`). "Host" is HTTP-level jargon; `workspaceUrl` is the domain-level term users learn first. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `workspaceUrl` (and `options.workspaceUrl`). - **Rationale:** This is a shared concern across all generated clients; flagged here as it appears in this client. -### 24. `PACKAGE_SEGMENT` constant — vague label -- **Why weird:** `const PACKAGE_SEGMENT = {...}` (client.ts:43). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. +### 18. `PACKAGE_SEGMENT` constant — vague label +- **Why weird:** `const PACKAGE_SEGMENT = {...}` (`client.ts:39`). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `USER_AGENT_PKG`. - **Rationale:** Minor; identical issue in every generated package. +### 19. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory +- **Why:** The package's directory and npm name `tokenmanagement` ends in `management`, which sits in the `Manager`/`Handler`/`Controller`/`Processor` family of architectural-tier suffixes. The package does not contain a "management" concept; it contains operations on tokens (list, get, create-on-behalf-of, delete). The `-management` suffix is service-side scaffolding language (cf. proto `TokenManagementService`) that leaks out via the URL path `/api/2.0/token-management/...` and into the SDK package name. Compare to peers in the SDK where the action package is named after the domain noun (`tokens`, `clusters`, `secrets`), not the service tier. +- **Category:** Proto-architectural-leak — `Manager`/`Handler`/`Controller`/`Processor`/`-management` family (architectural label not in the domain). +- **Suggested:** `tokenadmin` — keeps the audience-disambiguation from sibling `tokens` but uses an audience noun rather than an architectural verb. See finding #1 which proposes the same package rename for the collision-avoidance reason. +- **Rationale:** "Management" is meaningless to an SDK consumer (everything an SDK does is, in some sense, "managing"). `tokenadmin` names *who* the API is for (admins-of-others) and disambiguates from `tokens` (self) without leaking the proto service tier. + ## Observations _None._ ## Domain glossary -- `PAT` — Personal Access Token (only in `AutoscopeState` doc comment; the term the package is about but never names directly). -- `OBO` — On-Behalf-Of (spelled out in `CreateOnBehalfOfToken`). -- `autoscope` — Automatic API-path scope inference for a token; enum in `AutoscopeState`. +- `PAT` — Personal Access Token (the term the package is about but never names directly). +- `OBO` — On-Behalf-Of (spelled out in `CreateOnBehalfOfTokenRequest`). - `service principal` — Non-human identity that a token can be minted for via on-behalf-of. - `workspace` — Mentioned in `workspaceId` and in proto comments; the scope of this admin API. - `m2m`/`u2m` — not encountered. - `iam` — not encountered. -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`); used for `FieldMask`. +- `wkt` — not encountered in current source. ## Cross-package overlap with `tokens` -- **Shared enum:** `AutoscopeState` is duplicated byte-for-byte (model.ts:13-21 in both packages). -- **Shared request types:** `ListTokens`, `RevokeToken`, `UpdateToken` exist in both packages with different fields. `ListTokens` in `tokenmanagement` has `createdById`/`createdByUsername`; in `tokens` it is `{}`. +- **Shared request types:** `ListTokensRequest`, `RevokeTokenRequest` exist in both packages with different fields. `ListTokensRequest` in `tokenmanagement` has `createdById`/`createdByUsername`; in `tokens` it differs. - **Shared response shapes:** List and revoke responses exist in both packages. Both pull from a `*TokenInfo[]` array (`AdminTokenInfo[]` vs `PublicTokenInfo[]`). - **Different entity name:** `AdminTokenInfo` (this package) vs `PublicTokenInfo` (`tokens` package). - **Different create operation:** `createOnBehalfOfToken` (admin) vs `createToken` (per-user). -- **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #5. -- **Different update response shape:** Admin returns `AdminTokenInfo`; per-user returns a different shape — flagged in finding #7. -- **Different `lastUsed` field:** `lastUsedDay` (admin) vs `lastAccessedTime` (per-user) — flagged in findings #14/#17. -- **Different scope-related fields:** Admin has `scopes` + `autoscopeState`; per-user adds `inferredScopes` + `backfillScopes` — flagged in #13. +- **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #3. +- **Different `lastUsed` field:** `lastUsedDay` (admin) vs `lastAccessedTime` (per-user) — flagged in findings #8/#11. - **Different URL prefix:** `/api/2.0/token-management/...` vs `/api/2.0/token/...`. The two packages are conceptual siblings (PAT lifecycle) split by audience (admin-of-others vs self), but the SDK surface is split inconsistently — naming, return types, and method verbs diverge for no obvious reason. Worth raising at the SDK-design level. ## File coverage -- `src/v1/model.ts` (265 lines): read fully. -- `src/v1/client.ts` (211 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/model.ts` (169 lines): read fully. +- `src/v1/client.ts` (185 lines): read fully. +- `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (18 lines): read fully. + +## Fixed +- #2 `AutoscopeState` enum values (originally cited at `src/v1/model.ts:13-21`): Fixed in regeneration on 2026-05-20 — enum removed entirely from the package. +- #4 `CreateOnBehalfOfToken` / `GetToken` / `ListTokens` / `RevokeToken` / `UpdateToken` verb-phrase type names (originally cited at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — all request DTOs now carry a `Request` suffix (`CreateOnBehalfOfTokenRequest`, `GetTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`). +- #6 `UpdateToken.token: AdminTokenInfo` field (originally cited at `src/v1/model.ts` + `src/v1/client.ts:191`): Fixed in regeneration on 2026-05-20 — `UpdateToken` request type and `updateToken` client method were removed from the package. +- #7 `client.updateToken` returns `AdminTokenInfo` (originally cited at `src/v1/client.ts:190`): Fixed in regeneration on 2026-05-20 — `updateToken` method removed; cross-package return-shape divergence no longer present here. +- #10 `PAT` acronym never appears, autoscope comments reference it tacitly (originally cited at `src/v1/model.ts:8`): Fixed in regeneration on 2026-05-20 — `AutoscopeState` and its `PAT`-referencing doc comment were removed; no remaining cryptic comment-only reference. +- #13 `scopes` / `autoscopeState` / `autoscopeEnabled` triplet inconsistency (originally cited at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — `autoscopeState` and `autoscopeEnabled` fields removed; only `scopes` remains on `CreateOnBehalfOfTokenRequest`. +- #18 `autoscopeEnabled` on request vs `autoscopeState` on response (originally cited at `src/v1/model.ts:57`): Fixed in regeneration on 2026-05-20 — both autoscope fields removed from the package. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index 53c0626e..6cd61d04 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -2,147 +2,104 @@ **Path:** `packages/tokens/src/v1/` **Versions audited:** v1 -**Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share an `AutoscopeState` enum and a near-identical "token info" record, but the auth/audience boundary makes them distinct services. -**Total weird names flagged:** 30 +**Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share a near-identical "token info" record, but the auth/audience boundary makes them distinct services. +**Total weird names flagged:** 22 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 10 | -| Low | 7 | -| Observation | 5 | +| High | 5 | +| Medium | 7 | +| Low | 6 | +| Observation | 4 | ## High severity -### 1. Package name `tokens` overlaps with sibling `tokenmanagement` and is sub-domain-vague — `packages/tokens/`, `package.json:2`, `client.ts:80,106,135,165` +### 1. Package name `tokens` overlaps with sibling `tokenmanagement` and is sub-domain-vague — `packages/tokens/`, `package.json:2`, `client.ts:80,109,138,171` - **Why weird:** Two npm packages co-exist in `sdk-js/packages/`: `@databricks/sdk-tokens` (this package) and `@databricks/sdk-tokenmanagement` (admin surface). Both manage *the same kind of resource* (Databricks PATs) and both expose a `Client` class with a `listTokens(req, options)` and a `revokeToken(req, options)` method. From the npm name alone, a caller cannot tell which package is the end-user surface and which is the admin surface — `tokens` reads as "the token API" while `tokenmanagement` reads as "manage tokens". Both are accurate descriptions of the other. Compounding: the `package.json` `description` field is empty (line 4) for both packages, so npm registry browsers see only the name. - **Category:** 12 (duplicate concepts across packages), 1 (vague), 6 (misleading — neither name expresses which audience it serves). - **Suggested name:** Rename `tokens` → `usertokens` (or `mytokens`, `selftokens`) to mark the end-user surface; keep `tokenmanagement` for the admin surface. Or invert: rename `tokenmanagement` → `admintokens`. The wire URL `/api/2.0/token/...` can stay locked while npm/import paths use the disambiguated names. Worst case, document the audience boundary in each `package.json` description string. - **Rationale:** A caller writing `import {Client} from '@databricks/sdk-tokens/v1'` has no signal that they're getting the workspace-self surface, not the admin surface. The same problem applies to `import {Client} from '@databricks/sdk-tokenmanagement/v1'`. Two distinct OpenAPI services with overlapping resource models and overlapping method names should not be named with this much ambiguity. -### 2. Shared `AutoscopeState` enum is duplicated verbatim between `tokens` and `tokenmanagement` — `model.ts:13-21` -- **Why weird:** The exact same `AutoscopeState` enum (same name, same 7 members, same wire values, same doc comment referring to the same `tokendetails.proto`) is defined in both `packages/tokens/src/v1/model.ts:13-21` and `packages/tokenmanagement/src/v1/model.ts:13-21`. Identical Zod registration (`z.enum(AutoscopeState)`) at both `tokens/src/v1/model.ts:130` and `tokenmanagement/src/v1/model.ts:136`. A consumer that imports `AutoscopeState` from both packages gets two distinct TS enum types with the same name — assignment between them works at runtime (both are string-valued) but TS treats them as nominally different in strict mode. -- **Category:** 12 (duplicate concepts across packages), 14 (Go/proto-style — the duplication reflects the generator's per-service code emission). -- **Suggested name:** Hoist `AutoscopeState` into a shared package (e.g. `@databricks/sdk-databricks/wkt` or a new `@databricks/sdk-databricks/auth-models`), and have both `tokens` and `tokenmanagement` re-export it. The Go SDK has this problem too, but TS makes it more painful because of nominal typing on `import type` boundaries. -- **Rationale:** Two enums named `AutoscopeState` in two packages is the textbook duplicate-concept smell. Keeps drifting risk low (today they're identical, tomorrow someone could edit one and not the other). - -### 3. `AUTOSCOPE_STATE_*` members all repeat the enum-name prefix — `model.ts:14-20` -- **Why weird:** Every member of `AutoscopeState` is prefixed with `AUTOSCOPE_STATE_`. Reads as `AutoscopeState.AUTOSCOPE_STATE_RUNNING`, `AutoscopeState.AUTOSCOPE_STATE_BACKFILLED`, `AutoscopeState.AUTOSCOPE_STATE_API_NOT_COVERED` (44 chars to reference "API not covered"). Seven members, all redundantly prefixed. -- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). -- **Suggested name:** `AutoscopeState.UNSPECIFIED`, `AutoscopeState.DISABLED`, `AutoscopeState.RUNNING`, `AutoscopeState.COMPLETED`, `AutoscopeState.BACKFILLED`, `AutoscopeState.USER_SELECTED`, `AutoscopeState.API_NOT_COVERED`. Even better in TS: PascalCase (`AutoscopeState.Running`, etc.). -- **Rationale:** TS enums are namespaced by the enum itself. `Foo.FOO_BAR` is pure protobuf noise — same finding recurs in every generated package in this audit family (see `rfa#3`, `connections#...`). - -### 4. `AutoscopeState.AUTOSCOPE_STATE_UNSPECIFIED` sentinel re-states enum name — `model.ts:14` -- **Why weird:** The corresponding field is `autoscopeState?: AutoscopeState | undefined` (line 72). "Unspecified" is encoded twice: as `undefined` (TS-native), and as `AUTOSCOPE_STATE_UNSPECIFIED` (proto-native). The TS surface should rely on `undefined` for absence. -- **Category:** 2 (redundant enum prefix), 14 (Go/proto-style name). -- **Suggested name:** Drop the sentinel; rely on `undefined`. -- **Rationale:** Generated boilerplate. Same pattern as `rfa#3`, recurs across all packages. - -### 5. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:58-77` +### 2. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:37-46` - **Why weird:** Type is named `PublicTokenInfo` but the surrounding context contains no `PrivateTokenInfo`, `InternalTokenInfo`, or any other counterpart. The "Public" qualifier therefore communicates nothing to a TS reader. From the wire perspective, the Go SDK presumably has a parallel internal type that *isn't* exposed; in TS, that distinction is invisible. Compare to `tokenmanagement.AdminTokenInfo` (also "TokenInfo"-flavoured) — the package uses `Admin` to clarify the audience, but `Public` here doesn't. - **Category:** 1 (vague qualifier), 6 (misleading — "Public" implies a public-vs-private dichotomy that doesn't surface in the SDK). - **Suggested name:** `TokenInfo` (drop the `Public` prefix) or `UserTokenInfo` (parallel to `AdminTokenInfo` in `tokenmanagement`). The wire field `token_info` is bare anyway — the qualifier is purely cosmetic. - **Rationale:** "Public" reads as a security qualifier (public-key, public-API) when the value is just "token metadata visible to the token owner". `UserTokenInfo` makes the audience explicit. -### 6. `PublicTokenInfo` vs `AdminTokenInfo` divergence — same conceptual resource, different shapes — `tokens/model.ts:58-77`, `tokenmanagement/model.ts:23-46` +### 3. `PublicTokenInfo` vs `AdminTokenInfo` divergence — same conceptual resource, different shapes — `tokens/model.ts:37-46`, `tokenmanagement/model.ts` - **Why weird:** Two parallel "token info" records describe the *same wire resource* (a Databricks PAT) with overlapping but non-identical field sets: - - `PublicTokenInfo`: `tokenId, creationTime, expiryTime, comment, scopes, lastAccessedTime, autoscopeState, inferredScopes, backfillScopes` (9 fields). - - `AdminTokenInfo`: `tokenId, creationTime, expiryTime, comment, createdById, createdByUsername, ownerId, workspaceId, lastUsedDay, scopes, autoscopeState` (11 fields). - - **Public has 3 fields admin doesn't:** `lastAccessedTime`, `inferredScopes`, `backfillScopes`. - - **Admin has 5 fields public doesn't:** `createdById`, `createdByUsername`, `ownerId`, `workspaceId`, `lastUsedDay`. - - **`lastAccessedTime` (epoch ms, Public) and `lastUsedDay` (day count, Admin) describe the same concept at different fidelity.** Type-naming hides this: Public is millisecond-precise, Admin is day-precise. -- **Category:** 12 (duplicate concepts), 6 (misleading — `lastAccessedTime` vs `lastUsedDay` use different units for the same fact), 1 (vague qualifier on both type names). + - `PublicTokenInfo`: `tokenId, creationTime, expiryTime, comment` (4 fields). + - `AdminTokenInfo`: 11 fields including `createdById, createdByUsername, ownerId, workspaceId, lastUsedDay, scopes, autoscopeState` (verify in `tokenmanagement/model.ts`). + - The two records describe the same wire-side resource (a PAT) but expose dramatically different views. The Public form lacks every attribution field (no creator, no owner, no workspace) and lacks any usage signal (no `lastAccessedTime` / `lastUsedDay`). The Admin form lacks nothing the Public form exposes. +- **Category:** 12 (duplicate concepts), 1 (vague qualifier on both type names). - **Suggested name:** Two options: 1. Document the public-vs-admin partition inline so readers know which fields appear where. 2. Merge to a single `TokenInfo` with all fields optional, and document which subset the server populates for each endpoint. - **Rationale:** A caller doing token introspection on the workspace needs to pick a package; the type-name doesn't tell them which fields they'll get. -### 7. `ListTokens` and `RevokeToken` request types are misnamed as actions, not requests — `model.ts:50, 79` -- **Why weird:** Type names `ListTokens` and `RevokeToken` are bare verbs/verb-phrases that *look like methods*. A TS reader sees `import type {ListTokens, RevokeToken} from './model'` and reasonably guesses these are *functions or actions*. Instead, they're request DTOs. (`CreateToken` and `UpdateToken` have the same problem.) The corresponding response types correctly carry a response suffix; the request types should carry `Request`. The `tokenmanagement` package does the same. The Go SDK uses `CreateTokenRequest`/`RevokeTokenRequest` in idiomatic Go. -- **Category:** 8 (missing/asymmetric suffix), 6 (misleading — looks like a callable), 13 (asymmetry — response types are suffixed but request types aren't). -- **Suggested name:** `CreateTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`. Pairs symmetrically with `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse`, `UpdateTokenResponse`. -- **Rationale:** Most TS SDKs (AWS, GCP, Azure) name request DTOs with an explicit `*Request` suffix or `*Input`. The current asymmetry is a Go-port artefact. - -### 8. `Client.revokeToken` method paired with URL `/api/2.0/token/delete` — `client.ts:131,135` -- **Why weird:** Method on `Client` is `revokeToken`, but the wire URL it hits is `/api/2.0/token/delete`. Sibling `tokenmanagement.Client.deleteToken` (line 103) maps `RevokeToken`/`RevokeTokenResponse` to URL `/api/2.0/token-management/tokens/{id}` via HTTP `DELETE`. So: - - `tokens.revokeToken` → request type `RevokeToken` → URL ends in `/delete` → HTTP `POST` (revoke = delete on wire, named "revoke" in SDK). - - `tokenmanagement.deleteToken` → request type `RevokeToken` → URL ends in `/tokens/{id}` → HTTP `DELETE` (delete on wire, named "delete" in SDK, request type still `Revoke*`). +### 4. `Client.revokeToken` method paired with URL `/api/2.0/token/delete` — `client.ts:134,138` +- **Why weird:** Method on `Client` is `revokeToken`, but the wire URL it hits is `/api/2.0/token/delete`. Sibling `tokenmanagement.Client.deleteToken` maps `RevokeTokenRequest`/`RevokeTokenRequest_Response` to URL `/api/2.0/token-management/tokens/{id}` via HTTP `DELETE`. So: + - `tokens.revokeToken` → request type `RevokeTokenRequest` → URL ends in `/delete` → HTTP `POST` (revoke = delete on wire, named "revoke" in SDK). + - `tokenmanagement.deleteToken` → request type `RevokeToken*` → URL ends in `/tokens/{id}` → HTTP `DELETE` (delete on wire, named "delete" in SDK, request type still `Revoke*`). - **Category:** 17 (inconsistent action verbs for the same conceptual operation), 13 (inconsistency between packages), 6 (misleading — the request type doesn't match the method verb). -- **Suggested name:** Pick one verb (`revoke` or `delete`) and use it for the method, the request type, and ideally the URL. The Go SDK uses `Delete` consistently, so the TS port should too. Or pick `revoke` consistently. Today, `RevokeToken` is the *request type* in both packages but only the `tokens` package method is called `revokeToken`. -- **Rationale:** Calling the same operation `revokeToken` in one package and `deleteToken` in another (with the *same request type* `RevokeToken`) is a recipe for confusion. A user code-completing on a client typed as "either of the two" cannot rely on method names. +- **Suggested name:** Pick one verb (`revoke` or `delete`) and use it for the method, the request type, and ideally the URL. The Go SDK uses `Delete` consistently, so the TS port should too. Or pick `revoke` consistently. Today, `RevokeTokenRequest` is the *request type* in both packages but only the `tokens` package method is called `revokeToken`. +- **Rationale:** Calling the same operation `revokeToken` in one package and `deleteToken` in another (with the *same request type* `RevokeTokenRequest`) is a recipe for confusion. A user code-completing on a client typed as "either of the two" cannot rely on method names. + +### 5. Proto-architectural-leak: `Foo_Response` underscored nested response types — `model.ts:21, 32, 54` +- **Why weird:** The package defines `CreateTokenRequest_Response`, `ListTokensRequest_Response`, and `RevokeTokenRequest_Response` — names that bake the Protobuf nested-message convention (`OuterMessage_InnerMessage`) directly into the public TypeScript surface. The underscore is a transport-format artefact (a Go/proto idiom for nested message types), not a TypeScript naming convention. Each declaration is even guarded with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` — the codebase already knows these names violate TS conventions. The pattern matches the user's `Foo_PublicRequest` rule: a transport-layer naming structure leaking into the SDK's published types. Also propagates through `index.ts:9,11,14`, `client.ts:22,24,26,34,35,36,79,108,137,152`, and the schema names `unmarshal*Request_ResponseSchema` (`model.ts:68, 80, 106`). +- **Category:** Proto-architectural leak (transport-format identifier shape in public TS surface). +- **Suggested name:** Drop the underscore-nested form and use idiomatic TS response-type names: `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse` (the existing `UpdateTokenResponse` on `model.ts:65` already follows this pattern, so the package is internally inconsistent — see #6). +- **Rationale:** Public TS APIs should not advertise the wire/proto provenance of a type. Mixing `UpdateTokenResponse` (clean) with `CreateTokenRequest_Response` (proto-style underscore) in the same module signals that the generator is mechanically translating proto nested-message names rather than producing idiomatic TS. The `eslint-disable` annotation in source is direct evidence that the names break the project's own lint rules. ## Medium severity -### 9. `CreateToken.lifetimeSeconds` — unit smuggled into name, not type — `model.ts:29` -- **Why weird:** `lifetimeSeconds?: number | undefined`. Unit (seconds) lives in the field name, not the type. The doc says "in seconds". TS has no native duration type, so a unit-bearing field name is conventional, but the rest of the package uses `*Time` (`creationTime`, `expiryTime`, `lastAccessedTime`) which are *epoch milliseconds* (verified by doc strings on `model.ts:62-69`). Same `number` type, two different units, two different naming conventions. +### 6. `CreateTokenRequest.lifetimeSeconds` — unit smuggled into name, not type — `model.ts:13` +- **Why weird:** `lifetimeSeconds?: number | undefined`. Unit (seconds) lives in the field name, not the type. The doc says "in seconds". TS has no native duration type, so a unit-bearing field name is conventional, but the rest of the package uses `*Time` (`creationTime`, `expiryTime`) which are *epoch milliseconds* (verified by doc strings on `model.ts:40-43`). Same `number` type, two different units, two different naming conventions. - **Category:** 15 (unit-bearing field-name vs typed wrapper), 13 (intra-package inconsistency — `lifetimeSeconds` vs `creationTime`). - **Suggested name:** Acceptable as-is, but consider `lifetimeMs` (or `lifetime: Duration`) for parity with `creationTime` etc. The Temporal API (`@js-temporal/polyfill` is already a package.json dep) has `Temporal.Duration` which would be domain-correct. - **Rationale:** Within one struct, two number fields use different time units. Caller must read docs to avoid bugs. -### 10. `CreateToken.autoscopeEnabled` — naming inconsistent with response — `model.ts:38` -- **Why weird:** Request flag is `autoscopeEnabled?: boolean` ("enabled" suffix). The response carries `autoscopeState?: AutoscopeState` (a state enum, not a boolean). Same conceptual feature, different abstraction levels and names. A TS user thinking "I'll just check the value I set" would write `req.autoscopeEnabled` then later expect `info.autoscopeEnabled` but instead has to translate via `info.autoscopeState === 'AUTOSCOPE_STATE_RUNNING' || …`. The mapping (which states correspond to "enabled") is undocumented in the SDK surface. -- **Category:** 12 (duplicate concept — `autoscopeEnabled` ↔ `autoscopeState`), 17 (boolean vs enum for the same feature), 1 (vague — what counts as "enabled"?). -- **Suggested name:** Either accept the asymmetry but document the mapping, or rename request to `autoscopeMode?: AutoscopeMode` with an enum (`ENABLED` / `DISABLED`), so the surface is symmetric. -- **Rationale:** A boolean request and an enum response for "the same setting" is a known leaky abstraction. - -### 11. `PublicTokenInfo.scopes` doc grammar — singular vs plural — `model.ts:67-68` -- **Why weird:** Doc reads "Scope of the token was created with, if applicable" — but the field is `scopes?: string[] | undefined` (plural, array). The doc says "Scope" (singular) and "the token was created with" (drops the "that"). Compare with `CreateToken.scopes` doc: "Optional scopes of the token." — different wording, different singular/plural usage. -- **Category:** 9 (singular/plural mismatch), 6 (misleading doc), 13 (inconsistency — same field documented differently across types). -- **Suggested name:** Fix doc to "The scopes the token was created with, if applicable." Same in `AdminTokenInfo.scopes` (`tokenmanagement/model.ts:42-43` has the same typo). -- **Rationale:** Doc grammar shapes the mental model. Singular "scope" suggests a single value; the type is an array. - -### 12. `PublicTokenInfo.inferredScopes` and `backfillScopes` — overlapping arrays of strings — `model.ts:73-76` -- **Why weird:** Three different scope arrays in one struct: - - `scopes?: string[]` — "Scope of the token was created with, if applicable." - - `inferredScopes?: string[]` — "Inferred API path scopes collected for this token when autoscope is enabled." - - `backfillScopes?: string[]` — "Scopes inferred from offline backfill processing." - - All three are `string[]` carrying the same conceptual content (scope identifiers) but produced by different machinery (user-declared, runtime-inferred, offline-backfilled). There's no shared type alias, no enum, no narrowing. A caller wanting "the effective scopes" must union all three (or pick) without compile-time help. -- **Category:** 12 (duplicate concepts), 1 (vague — what's the relationship between the three?), 16 (string[] should be a `Scope[]` enum or branded string array). -- **Suggested name:** Group them: `declaredScopes`, `inferredScopes`, `backfillInferredScopes`. Add an `effectiveScopes` computed-on-server field that the caller actually wants. Or model as `{ source: 'declared' | 'inferred' | 'backfill'; value: string }[]` so the source is part of the data. -- **Rationale:** Three string-array fields with overlapping semantics is a discoverability bug. A new user has to read all three docs to understand the policy. - -### 13. `UpdateToken.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:88` -- **Why weird:** Doc on `UpdateToken.tokenId`: "The SHA-256 hash of the token to be updated." But every other `tokenId` doc in the package (and in `tokenmanagement`) says variants of "The ID of the token". So readers comparing the types see: - - `CreateTokenResponse.tokenInfo.tokenId` (line 46+59) — "The ID of this token." - - `PublicTokenInfo.tokenId` (line 60) — "The ID of this token." - - `RevokeToken.tokenId` (line 81) — "The ID of the token to be revoked." - - `UpdateToken.tokenId` (line 89) — "The SHA-256 hash of the token to be updated." +### 7. `UpdateTokenRequest.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:57` +- **Why weird:** Doc on `UpdateTokenRequest.tokenId`: "The SHA-256 hash of the token to be updated." But every other `tokenId` doc in the package (and in `tokenmanagement`) says variants of "The ID of the token". So readers comparing the types see: + - `CreateTokenRequest_Response.tokenInfo.tokenId` (line 25 → `PublicTokenInfo.tokenId` line 39) — "The ID of this token." + - `PublicTokenInfo.tokenId` (line 39) — "The ID of this token." + - `RevokeTokenRequest.tokenId` (line 50) — "The ID of the token to be revoked." + - `UpdateTokenRequest.tokenId` (line 57) — "The SHA-256 hash of the token to be updated." - **Category:** 6 (misleading doc — same field, different meaning), 13 (inconsistency), 19 (underspecified ID — what is it actually?). -- **Suggested name:** Either (a) reconcile the docs — if `tokenId` is the SHA-256 hash everywhere, say so consistently; or (b) if `UpdateToken.tokenId` actually expects a different format than the others, rename or document the divergence loudly. +- **Suggested name:** Either (a) reconcile the docs — if `tokenId` is the SHA-256 hash everywhere, say so consistently; or (b) if `UpdateTokenRequest.tokenId` actually expects a different format than the others, rename or document the divergence loudly. - **Rationale:** The doc disagreement implies either a stale comment or a real wire-protocol quirk. Either way, a caller can't tell which. -### 14. `UpdateToken.token` field name shadows the package name — `model.ts:90` -- **Why weird:** `UpdateToken.token?: PublicTokenInfo`. The field `token` inside the type `UpdateToken` in the package `tokens` carries the entire updated payload. Reads `updateReq.token.tokenId` — the word "token" appears three times in five characters. The same package has `Client.updateToken` method which takes `UpdateToken` which has a `token` field of type `PublicTokenInfo`. Layer cake. +### 8. `UpdateTokenRequest.token` field name shadows the package name — `model.ts:59` +- **Why weird:** `UpdateTokenRequest.token?: PublicTokenInfo`. The field `token` inside the type `UpdateTokenRequest` in the package `tokens` carries the entire updated payload. Reads `updateReq.token.tokenId` — the word "token" appears three times in five characters. The same package has `Client.updateToken` method which takes `UpdateTokenRequest` which has a `token` field of type `PublicTokenInfo`. Layer cake. - **Category:** 20 (type-suffix tautology), 1 (vague). - **Suggested name:** Field as `info` (since the inner type is `PublicTokenInfo`/`TokenInfo`) or `data`. Wire stays `token`. So `updateReq.info.tokenId`. - **Rationale:** The wire field is `token` because the proto message wraps a `TokenInfo`; in TS, the field name can clarify intent without changing the wire. -### 15. `UpdateToken` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:87-93` -- **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:165`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenSchema` on `model.ts:200-202`). +### 9. `UpdateTokenRequest` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:56-62` +- **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:171`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenRequestSchema` on `model.ts:146-159`). - **Category:** 12 (duplicate concept), 6 (misleading — which one is authoritative?), 11 (the inner one is dead-ish data). - **Suggested name:** Drop one. Either: (a) make `token` exclude `tokenId` (`Omit`) and keep the top-level; or (b) drop the top-level and use `req.token.tokenId` in the client. - **Rationale:** Two fields for the same identifier invite subtle bugs (server may pick the inner one if the top-level is empty). -### 16. `Client` class name — colliding namespace — `client.ts:46` +### 10. `Client` class name — colliding namespace — `client.ts:46` - **Why weird:** Top-level class literally named `Client`. Re-exported in `index.ts` as just `Client`. A consumer importing from both `@databricks/sdk-tokens/v1` and `@databricks/sdk-tokenmanagement/v1` faces an identical name clash: ``` import {Client} from '@databricks/sdk-tokens/v1'; import {Client as AdminTokensClient} from '@databricks/sdk-tokenmanagement/v1'; ``` - Worse, both packages export a class with method `listTokens(req, options)` where `req` is a *different* `ListTokens` type. Strong TS types catch the assignment error, but the duplication forces an alias at every dual import. + Worse, both packages export a class with method `listTokens(req, options)` where `req` is a *different* `ListTokensRequest` type. Strong TS types catch the assignment error, but the duplication forces an alias at every dual import. - **Category:** 1 (vague), 12 (duplicate name across packages). - **Suggested name:** `TokensClient`, `UserTokensClient`, or `MyTokensClient`. Mirror with `TokenManagementClient`/`AdminTokensClient`. - **Rationale:** Same finding as `rfa#37`, recurs across all packages — but particularly painful here given the `tokens`/`tokenmanagement` overlap. -### 17. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` -- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site (`client.ts:87,114` use them within four lines of each other). +### 11. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site (`client.ts:87,115` use them within four lines of each other). - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Cross-package: same as `rfa#32`, recurs everywhere. -### 18. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` +### 12. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` - **Why weird:** The file imports `Options` from `@databricks/sdk-core/api` (line 3) and `CallOptions` from `@databricks/sdk-options/call` (line 12). Three `Options`-suffixed types in scope. `HttpCallOptions` is internal — purely a context bag passed to `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -150,37 +107,37 @@ ## Low severity -### 19. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:226` -- **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateToken` payloads must learn this helper. -- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #25 re-export gap). +### 13. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:168` +- **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateTokenRequest` payloads must learn this helper. +- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #19 re-export gap). - **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. - **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. -### 20. `readAll` — generic helper name — `utils.ts:40` +### 14. `readAll` — generic helper name — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `rfa#34`. -### 21. `flattenQueryParams` — `utils.ts:123` +### 15. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` only ever builds JSON bodies). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default; or keep, but stop emitting it for body-only services. - **Rationale:** Same as `rfa#35`. -### 22. `PACKAGE_SEGMENT` constant — `client.ts:41` +### 16. `PACKAGE_SEGMENT` constant — `client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `rfa#36`. -### 23. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` -- **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,111,141,171` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). +### 17. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` +- **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,114,144,177` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Same as `rfa#38`. -### 24. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` +### 18. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` - **Why weird:** Local `opts` variable is one letter shorter than the parameter `options` to disambiguate. The shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions`. @@ -188,35 +145,38 @@ ## Observations -### 25. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper -The index file exports the `Client`, the `AutoscopeState` enum, and nine model interfaces. It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. +### 19. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper +The index file exports the `Client` and eight model interfaces (`CreateTokenRequest`, `CreateTokenRequest_Response`, `ListTokensRequest`, `ListTokensRequest_Response`, `PublicTokenInfo`, `RevokeTokenRequest`, `RevokeTokenRequest_Response`, `UpdateTokenRequest`, `UpdateTokenResponse`). It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. -### 26. `package.json` description is empty string — `package.json:4` +### 20. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the ambiguous `tokens` name (see #1) and the parallel `tokenmanagement` package, this leaves users without any registry-level metadata to disambiguate the two packages. -### 27. No tests in the package -`package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees (`AutoscopeState` proto-link in the doc) deserve a contract test. - -### 28. Doc comments leak proto file paths and internal commentary -The `AutoscopeState` doc (model.ts:7-12) references `common/principal-context/api/proto/tokendetails.proto` and `Principal context proto should NOT depend on this proto definitions` — internal architecture commentary that leaks into the public SDK surface. Similar pattern in `tokenmanagement`. Acceptable for now, but a polish pass should strip internal proto-tree paths from the user-facing JSDoc. +### 21. No tests in the package +`package.json` line 25-26: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees deserve a contract test. -### 29. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:165` -`const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:89`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. +### 22. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:171` +`const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:58`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. ## Domain glossary - **`tokens`** — npm package name; represents the *workspace user* PAT surface (create / list / revoke / update one's own tokens). Wire: `/api/2.0/token/...`. - **`tokenmanagement`** — sibling npm package; represents the *workspace admin* PAT surface (inspect / revoke any user's tokens, create service-principal on-behalf-of tokens). Wire: `/api/2.0/token-management/...`. -- **`PAT`** — Personal Access Token. Databricks workspace bearer tokens issued to users or service principals. Referenced in the `AutoscopeState` doc. -- **`autoscope`** — Inferred-scope collection: a token-store feature that learns which API paths a token actually hits and either records them (`inferredScopes`) or backfills them offline (`backfillScopes`). -- **`scopes`** — Permission/API-path scopes attached to a PAT. Closed set per `principal-context` definitions; SDK types them as bare `string[]`. -- **`PublicTokenInfo`** — The token-metadata record visible to the *owner* of the token (no `createdBy*`, no `ownerId`, no `workspaceId`). +- **`PAT`** — Personal Access Token. Databricks workspace bearer tokens issued to users or service principals. +- **`PublicTokenInfo`** — The token-metadata record visible to the *owner* of the token (no `createdBy*`, no `ownerId`, no `workspaceId`). Now a 4-field record after the regeneration removed `scopes`, `lastAccessedTime`, `autoscopeState`, `inferredScopes`, `backfillScopes`. - **`AdminTokenInfo`** — (`tokenmanagement` package) the token-metadata record visible to a *workspace admin* (carries `createdById`, `createdByUsername`, `ownerId`, `workspaceId`, `lastUsedDay`). -- **`FieldMask`** — Google protobuf convention for sparse-field updates in PATCH semantics. `publicTokenInfoFieldMask(...)` builds the wire-format paths for `UpdateToken.updateMask`. -- **`AutoscopeState`** — 7-member enum (incl. sentinel) defined identically in both `tokens` and `tokenmanagement`. Per the doc, mirrored in `databricks.identity.AutoscopeState` proto. +- **`FieldMask`** — Google protobuf convention for sparse-field updates in PATCH semantics. `publicTokenInfoFieldMask(...)` builds the wire-format paths for `UpdateTokenRequest.updateMask`. ## File coverage -- `src/v1/model.ts` (234 lines): read fully. -- `src/v1/client.ts` (186 lines): read fully. +- `src/v1/model.ts` (176 lines): read fully. +- `src/v1/client.ts` (192 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (18 lines): read fully. -- Cross-referenced `packages/tokenmanagement/src/v1/model.ts`, `client.ts`, `index.ts` for overlap analysis (see findings #1, #2, #6, #8, #16). +- Cross-referenced `packages/tokenmanagement/src/v1/` for overlap analysis (see findings #1, #3, #4, #9). + +## Fixed +- #2 `AutoscopeState` shared-enum duplication (originally cited at `model.ts:13-21`): Fixed in regeneration on 2026-05-20 — the `AutoscopeState` enum is no longer defined in the `tokens` package. +- #3 `AUTOSCOPE_STATE_*` redundant enum prefix (originally cited at `model.ts:14-20`): Fixed in regeneration on 2026-05-20 — `AutoscopeState` enum removed from this package. +- #7 Request types missing `Request` suffix (originally cited at `model.ts:50, 79`): Fixed in regeneration on 2026-05-20 — request DTOs are now `CreateTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`. +- #10 `CreateToken.autoscopeEnabled` boolean-vs-enum asymmetry (originally cited at `model.ts:38`): Fixed in regeneration on 2026-05-20 — the `autoscopeEnabled` field was dropped from `CreateTokenRequest`. +- #11 `PublicTokenInfo.scopes` doc grammar singular/plural mismatch (originally cited at `model.ts:67-68`): Fixed in regeneration on 2026-05-20 — the `scopes` field was removed from `PublicTokenInfo`. +- #12 Three overlapping scope-array fields on `PublicTokenInfo` (originally cited at `model.ts:73-76`): Fixed in regeneration on 2026-05-20 — `inferredScopes` and `backfillScopes` fields were removed from `PublicTokenInfo`. +- #28 Doc comments leaking proto file paths (originally cited at `model.ts:7-12`): Fixed in regeneration on 2026-05-20 — the `AutoscopeState` doc block containing the proto-tree path was removed when the enum left the package. diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 315df63b..99c1c8bf 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -3,12 +3,12 @@ **Path:** `packages/usagedashboards/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). -**Total weird names flagged:** 21 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | -| High | 6 | +| High | 4 | | Medium | 6 | | Low | 5 | | Observation | 4 | @@ -21,69 +21,57 @@ - **Suggested name:** `usagedashboard` (singular) — or, better, fold into a `billing` package alongside `billableusagedownload` (which has the same parent `/api/2.0/accounts/{account_id}` namespace). - **Rationale:** A user discovering the SDK would expect a "list" operation from a plural package name and be surprised by the lack of one. The singular form also matches the REST path `/dashboard`. The fold-into-`billing` move is a generator-level concern but worth flagging: both `usagedashboards` and `billableusagedownload` are about account-level billing data and live under the same URL prefix. -### 2. `UsageDashboardMajorVersion` enum has redundant prefix on every member — `src/v1/model.ts:5-9` -- **Why weird:** Every member of the enum is prefixed with the enum name in screaming snake case: `USAGE_DASHBOARD_MAJOR_VERSION_UNSPECIFIED`, `USAGE_DASHBOARD_MAJOR_VERSION_1`, `USAGE_DASHBOARD_MAJOR_VERSION_2`. The qualified usage at a call site reads `UsageDashboardMajorVersion.USAGE_DASHBOARD_MAJOR_VERSION_1` — 51 characters of pure stutter for a value that means "1". -- **Category:** 2 (redundant enum prefix), 7 (overly verbose), 18 (long enum values). -- **Suggested name:** Drop the `USAGE_DASHBOARD_MAJOR_VERSION_` prefix on each member so call sites read `UsageDashboardMajorVersion.UNSPECIFIED` / `.V1` / `.V2`. -- **Rationale:** Two real values (`1` and `2`) plus a sentinel `Unspecified` does not need a 28-character prefix per member. Same finding applies to **every** enum in the codebase — but this one is particularly egregious because the values are integers. - -### 3. `UsageDashboardType` enum has the same redundant-prefix problem — `src/v1/model.ts:11-15` -- **Why weird:** Members `USAGE_DASHBOARD_TYPE_UNSPECIFIED`, `USAGE_DASHBOARD_TYPE_WORKSPACE`, `USAGE_DASHBOARD_TYPE_GLOBAL`. Same pattern as #2. -- **Category:** 2, 7, 18. -- **Suggested name:** Drop the `USAGE_DASHBOARD_TYPE_` prefix so members read `UNSPECIFIED` / `WORKSPACE` / `GLOBAL`. -- **Rationale:** Same as #2. Bonus issue: the wire values are the bare strings `WORKSPACE` and `GLOBAL` (after the `USAGE_DASHBOARD_TYPE_` prefix), so the prefix exists *only* in the TS layer — it is not part of the on-wire enum. - -### 4. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 40` / `src/v1/client.ts:106-108` -- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:106`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. +### 2. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 40` / `src/v1/client.ts:109-110` +- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:109-110`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. - **Category:** 6 (misleading — TS type says optional, API likely requires it), 16 (field type contradicts domain reality), 17 (inconsistent transport: same field is body on POST, query on GET). - **Suggested name:** Keep the name but type as `UsageDashboardType` (required). Or split the DTO into `CreateBillingUsageDashboardRequest` (body) and `GetBillingUsageDashboardRequest` (query params), since the GET endpoint conceptually has different parameter semantics from the POST. - **Rationale:** `dashboardType` is the field that distinguishes Workspace from Global dashboards — it is *the* selector for the resource. Treating it as optional with no default is type-level dishonesty. -### 5. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` +### 3. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` - **Why weird:** Databricks workspace IDs are 64-bit integers (the Go SDK uses `int64`); JavaScript's `number` type is IEEE-754 double which loses precision above 2^53. The TS field is typed `number | undefined`. Same finding applies to `metastores` and most workspace-scoped packages in the SDK, but worth flagging because every audit cycle compounds the risk. Compare with `accountId: string` (line 21) which correctly uses `string` for an account UUID. - **Category:** 16 (field type contradicts domain — `number` cannot represent a 64-bit ID), 6 (misleading — type appears safe but is lossy). - **Suggested name:** Keep the field name, change type to `string`. - **Rationale:** Most workspace IDs are below 2^53 in practice, so this rarely bites. But the type contract claims something the runtime can't honour for the high end of the ID space. This is a systemic SDK-level issue worth raising at the generator. -### 6. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72` -- **Why weird:** `accountId` lives on `CreateBillingUsageDashboard` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:72, 101` — `${req.accountId ?? this.accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. +### 4. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72, 104` +- **Why weird:** `accountId` lives on `CreateBillingUsageDashboardRequest` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:72, 104` — `${req.accountId ?? this.accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. - **Category:** 6 (misleading — body shape implies body field, but it's a path param), 12 (duplicate concept — also lives on `ClientOptions`), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree? what happens if both sources are missing?). - **Suggested name:** Remove `accountId` from the request DTOs entirely. Make it a client-level concern only; throw a clear error if it is missing. Or segregate path params into a separate type and document the dual role. - **Rationale:** Same as `billableusagedownload` finding. The current shape misleads callers about the wire format, the duplicated-with-fallback pattern is a footgun, and the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. ## Medium severity -### 7. `CreateBillingUsageDashboard` / `GetBillingUsageDashboard` include `Billing` but the package is `usagedashboards` — `src/v1/model.ts:17, 34` +### 5. `CreateBillingUsageDashboardRequest` / `GetBillingUsageDashboardRequest` include `Billing` but the package is `usagedashboards` — `src/v1/model.ts:17, 34` - **Why weird:** The package is `@databricks/sdk-usagedashboards` (no "billing"); the types prefix `Billing` (no "Usage" alone). A user who imported the package by its `usage`-themed name then sees `Billing`-prefixed types and `Client.createBillingUsageDashboard()` method must mentally bridge `usage` ↔ `billing`. The package name and type names disagree on which noun is primary. - **Category:** 17 (inconsistent action verbs / nouns across naming layers), 7 (overly verbose — `BillingUsage` is two synonyms for the same concept). -- **Suggested name:** Pick one noun. Either rename the package to `billingusagedashboards` (matches types) or drop `Billing` from the type names (`CreateUsageDashboard` / `GetUsageDashboard`). The Go SDK calls this domain "Billing → UsageDashboards" so types match Go; the TS package name is the outlier. -- **Rationale:** Cross-layer consistency. The simplest fix is `CreateUsageDashboard*` / `GetUsageDashboard*` since the package name is already `usagedashboards`. "Billing" is implied by the account-level endpoint path. +- **Suggested name:** Pick one noun. Either rename the package to `billingusagedashboards` (matches types) or drop `Billing` from the type names (`CreateUsageDashboardRequest` / `GetUsageDashboardRequest`). The Go SDK calls this domain "Billing → UsageDashboards" so types match Go; the TS package name is the outlier. +- **Rationale:** Cross-layer consistency. The simplest fix is `CreateUsageDashboardRequest` / `GetUsageDashboardRequest` since the package name is already `usagedashboards`. "Billing" is implied by the account-level endpoint path. -### 8. `Client` class is unprefixed — `src/v1/client.ts:38` +### 6. `Client` class is unprefixed — `src/v1/client.ts:38` - **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-usagedashboards/v1'`, then has to rename it (`import {Client as UsageDashboardsClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Cross-SDK consistency — but worth flagging. - **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). - **Suggested name:** `UsageDashboardsClient` or `BillingUsageDashboardClient`. - **Rationale:** Same finding as `billableusagedownload` audit #8. The SDK could expose a namespace export pattern (`import * as usageDashboards from '@databricks/sdk-usagedashboards/v1'`) and remove the `Client` symbol entirely, letting `usageDashboards.Client` be the qualified name. Not a blocker. -### 9. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:68, 97` -- **Why weird:** Method name and request-type name are textually identical (modulo case): `createBillingUsageDashboard(req: CreateBillingUsageDashboard)`. The repetition is so close that the type name reads like a misnamed method import. Compare with `lakeview` where `Client.createDashboard(req: CreateDashboardRequest)` keeps the type-noun separate from the method-verb. +### 7. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:68, 100` +- **Why weird:** Method name and request-type name are textually identical (modulo case and the new `Request` suffix): `createBillingUsageDashboard(req: CreateBillingUsageDashboardRequest)`. The repetition is so close that the type name reads like a misnamed method import. Compare with `lakeview` where `Client.createDashboard(req: CreateDashboardRequest)` keeps the type-noun separate from the method-verb. - **Category:** 7 (overly verbose), 8 (redundant — method verb is already implicit in the type's verb prefix). - **Suggested name:** `createDashboard` / `getDashboard` (drop `BillingUsage` since the package name disambiguates) or `create` / `get` (since there are only two methods). Type stays as `CreateBillingUsageDashboardRequest`. - **Rationale:** A method on `usageDashboardsClient` is already in the usage-dashboards namespace; restating `BillingUsageDashboard` in the method name is pure stutter. The Go SDK does this because Go has package-flat method tables; TS classes provide their own namespace. -### 10. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` +### 8. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` - **Why weird:** Both response types include `dashboardId?: string` (always optional). But there is no `GetByDashboardId` method, and the request types use `(workspaceId, accountId, dashboardType)` to identify the dashboard, not the `dashboardId`. So `dashboardId` is a returned-but-never-accepted identifier — informational only. The field is also typed optional, but a successful 2xx response should always have an ID; the `?` is again type-level dishonesty. - **Category:** 6 (misleading optionality), 19 (underspecified id — present in responses but not accepted as a request key). - **Suggested name:** Keep the name; make it required (`dashboardId: string`). Or document that it is a read-only side-channel identifier (not a primary key from the API's POV). Or expose a `getByDashboardId` method that round-trips the value. - **Rationale:** If the API returns an ID, the SDK should either let you use it or document why you can't. The current state — return-only, never-accepted — is API-design noise that the SDK faithfully echoes. -### 11. `dashboardUrl` field is a `string` — should be `URL` or branded — `src/v1/model.ts:48` -- **Why weird:** `dashboardUrl?: string | undefined` — a URL is typed as a bare string. Callers must `new URL(resp.dashboardUrl)` defensively. Compare with `accountId`/`dashboardId` which are also strings but represent IDs, not URLs. No branded type distinguishes them. Also optional on a success response (same dishonesty as #10). +### 9. `dashboardUrl` field is a `string` — should be `URL` or branded — `src/v1/model.ts:48` +- **Why weird:** `dashboardUrl?: string | undefined` — a URL is typed as a bare string. Callers must `new URL(resp.dashboardUrl)` defensively. Compare with `accountId`/`dashboardId` which are also strings but represent IDs, not URLs. No branded type distinguishes them. Also optional on a success response (same dishonesty as #8). - **Category:** 15 (generic field name losing meaning), 6 (misleading optionality), 1 (vague — `string` for a URL). - **Suggested name:** Keep the field name; consider a branded type (`type Url = string & {readonly _urlBrand: unique symbol}`) or `URL` (the WHATWG class). At minimum, make it non-optional on a 2xx response. - **Rationale:** SDK-wide concern (every URL field in every package is `string`); flag once per audit. Branded URLs are a TS idiom precisely for this case. -### 12. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:33` +### 10. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:33` - **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. - **Category:** 1 (vague), 15 (generic field name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -91,62 +79,65 @@ ## Low severity -### 13. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` -- **Why weird:** The exact same multi-sentence JSDoc ("Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account.") appears on `CreateBillingUsageDashboard.dashboardType` (line 22) and `GetBillingUsageDashboard.dashboardType` (line 39). The duplication suggests the underlying enum (`UsageDashboardType`) should carry the doc, not each field. +### 11. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` +- **Why weird:** The exact same multi-sentence JSDoc ("Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account.") appears on `CreateBillingUsageDashboardRequest.dashboardType` (line 22) and `GetBillingUsageDashboardRequest.dashboardType` (line 39). The duplication suggests the underlying enum (`UsageDashboardType`) should carry the doc, not each field. - **Category:** Observation — not strictly a name issue but flagged because it implies fragmentation. JSDoc duplication is a generator artefact. - **Suggested name:** Move the doc to the `UsageDashboardType` enum (or its members). -### 14. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:68, 74, 78, 97, 111, 115, 117` +### 12. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:69, 74, 77, 81, 101, 114, 118` - **Why weird:** Local variables use three-letter abbreviations (`req`, `resp`, `opts`, `httpReq`). The codebase guideline (typescript.mdc § 5) discourages cryptic short abbreviations. Compare with `httpClient` (full word) in the same file. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`. - **Rationale:** Inexpensive readability win. -### 15. `params` shadowed across files — `src/v1/client.ts:102` -- **Why weird:** Local `params: URLSearchParams` — fine in isolation, but `flattenQueryParams(prefix, value, params)` in `utils.ts:123` exposes the same `params` name in public API. The repeated use of `params` for both `URLSearchParams` and "named function parameters" is mildly confusing in audit traces. +### 13. `params` shadowed across files — `src/v1/client.ts:105` +- **Why weird:** Local `params: URLSearchParams` — fine in isolation, but `flattenQueryParams(prefix, value, params)` in `utils.ts:126` exposes the same `params` name in public API. The repeated use of `params` for both `URLSearchParams` and "named function parameters" is mildly confusing in audit traces. - **Category:** 1 (vague). - **Suggested name:** `queryParams` / `urlSearchParams`. -### 16. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:109` +### 14. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:112` - **Why weird:** `const query = params.toString();` — the variable is the serialized query *string*, but `query` reads as a query expression/object. Compare with `fullUrl` on the next line (which is clear about what it is). - **Category:** 1 (vague), 6 (misleading — name implies a query, value is a string). - **Suggested name:** `queryString`. -### 17. `httpClient: HttpClient` field — `src/v1/client.ts:43` +### 15. `httpClient: HttpClient` field — `src/v1/client.ts:43` - **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention widespread in this SDK. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the outer `Client` class in the same file. ## Observations -### 18. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` -The exported `flattenQueryParams` helper is never called from `client.ts` — the GET method does its own `params.append()` (lines 103-108) inline because there are only two query params. The helper is dead surface area in this package; same finding as `billableusagedownload` audit #11. Worth pruning at the generator level when the consuming methods don't need it. +### 16. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` +The exported `flattenQueryParams` helper is never called from `client.ts` — the GET method does its own `params.append()` (lines 106-111) inline because there are only two query params. The helper is dead surface area in this package; same finding as `billableusagedownload` audit #11. Worth pruning at the generator level when the consuming methods don't need it. -### 19. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` -Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + APIError check. Both are used in `client.ts:79, 89, 117, 126`. The verb-pair is fine, but the cognitive distance between "wrap with retry options" and "send an HTTP request and check for API errors" is large enough that one name should be different (e.g., `runWithCallOptions` / `sendHttp`). Same finding appears in every audited package's `utils.ts`. +### 17. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` +Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + ApiError check. Both are used in `client.ts:82, 92, 119, 129`. The verb-pair is fine, but the cognitive distance between "wrap with retry options" and "send an HTTP request and check for API errors" is large enough that one name should be different (e.g., `runWithCallOptions` / `sendHttp`). Same finding appears in every audited package's `utils.ts`. -### 20. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency +### 18. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency - The enum names are `UsageDashboardMajorVersion`, `UsageDashboardType` — `Usage` first, no "Billing". -- The request types are `CreateBillingUsageDashboard` — `Billing` first, with `Usage`. +- The request types are `CreateBillingUsageDashboardRequest` — `Billing` first, with `Usage`. - The package is `usagedashboards` — `usage` only, no "billing". - The Go SDK service is "Billing → UsageDashboards" — both nouns in two layers. -Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #7. +Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #5. -### 21. The package has no list/page operations +### 19. The package has no list/page operations There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. ## Domain glossary - `usage dashboard` — A Databricks-managed dashboard (DBSQL or AI/BI Lakeview) that visualises account-level billing/usage data. Two flavours: **Workspace** (per-workspace) and **Global** (all workspaces in an account). - `DBU` — Databricks Unit; the standard unit of compute consumption. Notably absent from this package's types and JSDoc — verified via grep that the literal "DBU" never appears, even though DBUs are the unit the dashboard would visualise. - `account ID` — Databricks account identifier (UUID); surfaces as `accountId: string` on both request types and on `ClientOptions.accountId`. -- `workspace ID` — Databricks workspace identifier (64-bit int); surfaces as `workspaceId: number` — see finding #5 about the precision issue. +- `workspace ID` — Databricks workspace identifier (64-bit int); surfaces as `workspaceId: number` — see finding #3 about the precision issue. - `major version` — Template version of the dashboard (1 or 2). Per the JSDoc, defaults to `VERSION_1` if unspecified at create time. -- `dashboard ID` — Identifier of the created dashboard (returned, not accepted as input). See finding #10. +- `dashboard ID` — Identifier of the created dashboard (returned, not accepted as input). See finding #8. - `E2` — Databricks deployment architecture; not mentioned in this package but implicit (account-level endpoints are E2-only). ## File coverage - `src/v1/model.ts` (86 lines): read fully. -- `src/v1/client.ts` (133 lines): read fully. +- `src/v1/client.ts` (136 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (13 lines): read fully. + +## Fixed +_None._ diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md index 2a4feb27..2bb9d277 100644 --- a/.agent/naming-audit/usagepolicy.md +++ b/.agent/naming-audit/usagepolicy.md @@ -3,14 +3,14 @@ **Path:** `packages/usagepolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). -**Total weird names flagged:** 33 +**Total weird names flagged:** 35 ## Summary | Severity | Count | | --- | --- | | High | 8 | | Medium | 12 | -| Low | 8 | +| Low | 10 | | Observation | 5 | ## High severity @@ -187,25 +187,37 @@ - **Suggested name:** Fix to "its". - **Rationale:** Surfaces in editor hovers; small but persistent. +### 29. `SortSpec_Field` proto-style underscore-nested enum name — `src/v1/model.ts:6` +- **Why weird:** Underscored identifier `SortSpec_Field` mirrors protobuf's "ParentMessage_NestedEnum" wire convention and is unidiomatic in TypeScript. The file even carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.` on line 5, confirming the proto-architectural leak. Re-exported from `index.ts:5` so the leak reaches consumers verbatim. +- **Category:** Proto-architectural leak — proto-nested-type naming convention surfaced into the TS public API. +- **Suggested name:** `SortField` (or namespace it under `SortSpec` as `SortSpec.Field` if the nesting relationship matters). +- **Rationale:** TS has no `Parent_Nested` convention; the underscore is a direct proto leak. Mirrors the same finding in `budgetpolicy` (`SortSpec_Field` at `budgetpolicy/src/v1/model.ts:8`). + +### 30. `buildHttpRequest` — `Http` mid-position infix — `src/v1/utils.ts:96` +- **Why weird:** `Http` appears as a mid-position infix between the verb `build` and the noun `Request`. The function's role is "construct an `HttpRequest` value", but the `Http` infix in the function name redundantly leaks the transport layer into the verb. Same pattern in the imported `HttpRequest` type is fine (end suffix), but on the function it duplicates information already in the return type. +- **Category:** Proto-architectural leak — transport-layer noun appearing mid-name. +- **Suggested name:** `buildRequest` (return type `HttpRequest` already conveys the transport). +- **Rationale:** Standard naming guidance: don't repeat the return-type noun's qualifier in the verb. Mirrors the same pattern in `budgetpolicy/src/v1/utils.ts:96`. + ## Observations -### 29. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference +### 31. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. - **Category:** 12 (duplicate concept), 1 (vague package boundary). -### 30. No `FieldMask` import in `usagepolicy/src/v1/model.ts` +### 32. No `FieldMask` import in `usagepolicy/src/v1/model.ts` Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #20 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. - **Category:** Observation / 17 (cross-package inconsistency). -### 31. Action-verb conventions in `Client` +### 33. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 32. Acronym casing `Id` consistently used as `Id`, not `ID` +### 34. Acronym casing `Id` consistently used as `Id`, not `ID` `policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). - **Category:** 3 (observation — internal acronym style is consistent). -### 33. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) +### 35. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) The same identifier appears in three forms in the same client file: - `usage_policies` — wire form (in the Zod schemas via snake_case keys). - `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md new file mode 100644 index 00000000..84fd7852 --- /dev/null +++ b/.agent/naming-audit/vectorsearch.md @@ -0,0 +1,207 @@ +# Naming Audit: vectorsearch + +**Path:** `packages/vectorsearch/src/v1/` (consolidation of the prior `endpoints` and `indexes` packages from the 2026-05-22 regen) +**Versions audited:** v1 +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` +**Inferred domain:** Databricks AI/Vector Search — endpoint management (create, get, list, patch, delete, budget-policy patch) and vector-index management (create, get, list, query, query-next-page, scan, sync, upsert-data, delete-data, delete). Routes under `/api/2.0/vector-search/endpoints` and `/api/2.0/vector-search/indexes`. Hosts a single `Client` with mixed endpoint and index methods plus a single `CreateEndpointWaiter`. +**Total weird names flagged:** 28 + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 7 | +| Medium | 11 | +| Low | 7 | +| Observation | 3 | +| **Total** | **28** | + +Dominant themes: +1. **Two resource families share one flat `Client`.** Endpoint methods (`createEndpoint`, `getEndpoint`, …) and index methods (`createVectorIndex`, `queryVectorIndex`, …) sit side by side on the same class. The result is long method names that re-encode the resource family (`createVectorIndex` instead of `client.indexes.create()`), plus a single waiter that only covers endpoints. +2. **`name` is the wire identifier for both endpoints and indexes.** Across both resource families, `name?: string` is the path-segment identifier in URLs while the JSDoc just says "Name of the index" / "Name of the AI Search endpoint" — leaving the format (UC three-part name? user-chosen string?) implicit. The same field shape recurs on every request type. +3. **`Endpoint` is a Databricks-wide overloaded noun.** Bare `Endpoint`, `EndpointType`, `EndpointStatus`, `EndpointScalingInfo` collide with `modelserving.InferenceEndpoint`, `warehouses.EndpointState`, and other "endpoint" concepts. The package name `vectorsearch` qualifies the import, but destructured types lose that context. +4. **Near-duplicate types.** `VectorIndex` ≡ `MiniVectorIndex` (identical field set), `DeltaSyncVectorIndexSpec` ≡ `DeltaSyncVectorIndexSpecRequest` (identical field set). The duplication is gratuitous given that `DirectAccessVectorIndexSpec` has no `Request` twin. + +--- + +## High severity + +### 1. `Endpoint` bare top-level type collides with sibling packages — `src/v1/model.ts:274`, `src/v1/index.ts:31` +- **Why weird:** `Endpoint` is exported unqualified. The sibling `modelserving` package exports `InferenceEndpoint` (qualified); the sibling `warehouses` package exports `EndpointState`, `EndpointSecurityPolicy`, etc. A consumer who imports `{Endpoint}` from this package and writes `function process(e: Endpoint)` has no way to tell from the local signature whether `e` is a vector-search endpoint, an inference endpoint, or a SQL warehouse endpoint. The package-level rename to `vectorsearch` qualifies the import path but is destructured away at the use site. +- **Category:** 1 (vague/generic), 15 (generic field name losing meaning across packages). +- **Suggested name:** `VectorSearchEndpoint` (mirrors `modelserving.InferenceEndpoint`). Sibling types (`EndpointType`, `EndpointStatus`, `EndpointScalingInfo`) follow. +- **Rationale:** "Endpoint" alone is the most generic REST noun. Disambiguation at the type level is needed once the type leaves the import statement. + +### 2. `Endpoint.name` is the URL identifier but coexists with `Endpoint.id` — `src/v1/model.ts:276, 288` +- **Why weird:** `Endpoint` declares both `name?: string` ("Name of the AI Search endpoint") and `id?: string` ("Unique identifier of the endpoint"). Every URL in the client uses `name` as the path segment (`/endpoints/${req.name}` — `client.ts:212, 262, 420, 446`); `id` is never used as a key. Two identifiers for the same entity is confusing: which one is the canonical reference for the rest of the SDK? JSDoc does not say. +- **Category:** 12 (duplicate concepts), 19 (underspecified IDs), 6 (misleading — `name` reads like a label but acts like a primary key). +- **Suggested name:** Document the distinction prominently in JSDoc — `name` is the user-chosen URL-safe key, `id` is the opaque server-generated GUID — and pick one as the canonical handle. Alternatively, collapse to one identifier at the API level. +- **Rationale:** Users who fetch an endpoint and try to use `.id` to delete it will hit a 404. The dual identifier needs to be either eliminated or surfaced explicitly. + +### 3. `listEndpoint` / `listVectorIndex` method names are singular for collection operations — `src/v1/client.ts:317, 365` +- **Why weird:** Both methods return a collection (`ListEndpointResponse.endpoints: Endpoint[]`, `ListVectorIndexResponse.vectorIndexes: MiniVectorIndex[]`) yet the method names are singular. The corresponding URLs are plural (`/endpoints`, `/indexes`) and the body field names are plural. The request/response types (`ListEndpointRequest`, `ListEndpointResponse`, `ListVectorIndexRequest`, `ListVectorIndexResponse`) inherit the singular form. +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verbs). +- **Suggested name:** `listEndpoints`, `listVectorIndexes`, `ListEndpointsRequest`, `ListEndpointsResponse`, `ListVectorIndexesRequest`, `ListVectorIndexesResponse`. The iterator pair (`listEndpointIter`, `listVectorIndexIter`) follows: `listEndpointsIter`, `listVectorIndexesIter`. +- **Rationale:** A collection method should be plural to match its return type, the wire URL, and the response field shape. + +### 4. `MiniVectorIndex` and `VectorIndex` are structurally identical duplicates — `src/v1/model.ts:376-399` vs `:572-595` +- **Why weird:** Both types declare exactly the same nine fields (`name`, `endpointName`, `primaryKey`, `indexType`, `indexSpec`, `status`, `creator`, `indexSubtype`) with identical JSDoc on the fields they share. `MiniVectorIndex` is used in `ListVectorIndexResponse.vectorIndexes` (the list-view element type); `VectorIndex` is used everywhere else. With no field-level difference, the type split is gratuitous — and the "Mini" qualifier is cryptic (industry convention is `Summary`, `ListItem`, `Brief`, `Ref`). +- **Category:** 12 (duplicate concept), 5 (cryptic abbreviation), 1 (vague qualifier). +- **Suggested name:** Either `export type VectorIndexSummary = VectorIndex` (with a JSDoc note that the wire form is currently identical), or drop `MiniVectorIndex` entirely and use `VectorIndex` in list responses. If the API intends them to diverge later, document the upcoming difference. +- **Rationale:** Two ~25-line type definitions with no semantic distinction is a maintenance hazard. The "Mini" prefix tells the reader nothing about what is omitted (because nothing is). + +### 5. `DeltaSyncVectorIndexSpec` and `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:175-205` vs `:207-237` +- **Why weird:** Two exported types with identical field sets (`sourceTable`, `embeddingSourceColumns`, `embeddingVectorColumns`, `pipelineType`, `pipelineId`, `embeddingWritebackTable`, `columnsToSync`, `columnsToIndex`) and identical JSDoc on every shared field. The `Request` twin exists only for `DeltaSync` — `DirectAccessVectorIndexSpec` has no `Request` variant. The asymmetry is unexplained and the structural identity makes the split feel arbitrary. +- **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix when the type has no distinguishing fields). +- **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec` used in both request and response positions, mirroring `DirectAccessVectorIndexSpec`), or document the planned divergence prominently. +- **Rationale:** The mismatch with `DirectAccessVectorIndexSpec` (no `Request` twin) shows the duplication is gratuitous. Users serializing a `DeltaSyncVectorIndexSpec` for a create call have to discover that `*Request` is the right one only by reading the function signature. + +### 6. `name?: string` is the resource identifier across every request type — `model.ts:98, 115, 147, 161, 169, 254, 269, 276, 323, 328, 339, 378, 403, 416, 427, 436, 512, 534, 542, 574` +- **Why weird:** Twelve+ request types use a bare `name?: string` for what is actually the resource identifier consumed by the URL (`/endpoints/${name}`, `/indexes/${name}`, `/indexes/${name}/query`, …). For indexes, the value is a three-part Unity Catalog qualified name (`..`); for endpoints, it is a user-chosen string. Neither distinction is documented on the field. JSDoc on each one just says "Name of the index" or "Name of the AI Search endpoint" without spelling out the format expectation. +- **Category:** 15 (generic field name losing meaning), 19 (underspecified ID), 6 (misleading — `name` reads like a label but is the primary key). +- **Suggested name:** For request types, rename to `endpointName` / `indexName` (already partial precedent — `MiniVectorIndex.endpointName`, `ListVectorIndexRequest.endpointName`). For the model types (`Endpoint.name`, `VectorIndex.name`), at minimum document the value's format in JSDoc. +- **Rationale:** `name` is too generic for a path-segment identifier. Users will mis-construct the value (e.g. send a bare index name instead of a three-part UC name) and see a 404. + +### 7. `EndpointStatus_State.OFFLINE` is a terminal-failure state but reads as transient — `model.ts:72`, `client.ts:641-644, 680-681` +- **Why weird:** The waiter's terminal-state switch (`client.ts:637-647`) treats `EndpointStatus_State.OFFLINE` as a *failure* and throws. The enum identifier "OFFLINE" however reads as a transient lifecycle state ("the endpoint is currently offline"), implying it might come back online. JSDoc on the enum value is absent; the only hint is in the comment block above `RED_STATE`/`YELLOW_STATE`. A reader inspecting the enum would not predict that the waiter throws on OFFLINE. +- **Category:** 6 (misleading), 16 (field type contradicts domain — lifecycle name implies transient, runtime semantics are terminal). +- **Suggested name:** If the wire allows, rename to `FAILED` or `TERMINATED` to match the runtime semantics. Otherwise, add JSDoc on `OFFLINE` clarifying that it is a terminal failure state, distinct from "temporarily not serving traffic". +- **Rationale:** A user inspecting the enum to write their own polling logic will conclude that `OFFLINE` is recoverable and miss the failure path entirely. + +--- + +## Medium severity + +### 8. `Endpoint.endpointType: EndpointType` — three layers of "endpoint" — `model.ts:284, 100` +- **Why weird:** `endpoint.endpointType : EndpointType` reads "endpoint . endpoint type : endpoint type" — the field name and the field type both repeat the container type name. Same pattern on `Endpoint.endpointStatus: EndpointStatus` (`model.ts:290, 314`). +- **Category:** 20 (type-suffix tautology), 8 (redundant prefix). +- **Suggested name:** Rename fields to `type` / `status` (the container `Endpoint` supplies the context). Wire fields stay `endpoint_type` / `endpoint_status`; remap in the marshaller. Match the existing pattern in `EndpointStatus.state` (bare `state`, not `endpointState`). +- **Rationale:** TS field names should not repeat the parent type. The current shape is a generator artifact of flat Go structs. + +### 9. `MiniVectorIndex.indexType: VectorIndexType` and `.indexSubtype: IndexSubtype` — `model.ts:383, 398, 579, 594` +- **Why weird:** Same tautology pattern as #8: `vectorIndex.indexType : VectorIndexType` reads "vector index . index type : vector index type"; `vectorIndex.indexSubtype : IndexSubtype` likewise repeats. The container type already says "index". +- **Category:** 20 (type-suffix tautology), 8 (redundant prefix). +- **Suggested name:** Rename to `type` / `subtype`. Wire fields are `index_type` / `index_subtype`. +- **Rationale:** Same reasoning as #8 — the container type qualifies the field. + +### 10. `IndexSubtype` vs `VectorIndexType` — two enums on different "type" axes — `model.ts:29, 62` +- **Why weird:** Two enums both describing a "type" axis of a vector index. `IndexSubtype = {VECTOR, FULL_TEXT, HYBRID}` is the search-semantics axis (what kind of similarity is computed). `VectorIndexType = {DELTA_SYNC, DIRECT_ACCESS}` is the data-residency axis (how data flows in). Both surface as `index*Type*` fields on `VectorIndex`. A first-time reader cannot tell which axis is which without reading both JSDocs. +- **Category:** 6 (misleading — both look like "the type" of the index), 17 (inconsistent naming for two type axes). +- **Suggested name:** Disambiguate: `IndexSearchMode` for the search-semantics axis, `IndexBackingMode` (or `IndexStorageType`) for the data-residency axis. Or `IndexSearchKind` / `IndexSyncMode`. +- **Rationale:** Two parallel `*Type` enums on the same type make the API harder to learn. Naming each by its axis would self-document. + +### 11. `IndexSubtype` exposes an unsupported value `VECTOR` — `model.ts:29-33` +- **Why weird:** The enum's first member is `VECTOR`, and its JSDoc says "Not supported. Use `HYBRID` instead." A public-API enum that exposes a value whose only documented behavior is "do not use" inflates the surface area and forces every switch statement to handle it. Also, "VECTOR" inside an enum on a vector-search index is tautological — every value is some kind of vector behavior. +- **Category:** 6 (misleading: present but explicitly unsupported), 18 (the value itself is content-free against the enum name). +- **Suggested name:** Remove `VECTOR` from the enum, or document the deprecation path in JSDoc and timeline for removal. +- **Rationale:** Dead enum members are bug magnets. + +### 12. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:51-55, 554` +- **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:155, 550` — "Result of the upsert or delete operation"). +- **Category:** 13 (verb-coupling), 7 (verbose), 1 (generic `Status`/`Result`). +- **Suggested name:** Split into `UpsertDataStatus` / `DeleteDataStatus` (aliases of the same wire enum), or use a neutral name `DataMutationStatus` / `DataMutationResult`. +- **Rationale:** Two-verb compound nouns are unusual and confusing. Most APIs use a single neutral noun for shared response types. + +### 13. Endpoint and index method names re-encode the resource family — `client.ts:111, 136, 148, 174, 208, 233, 258, 283, 317, 365, 416, 442, 474, 500, 529, 555, 581` +- **Why weird:** Nineteen client methods all carry a resource-family suffix (`createEndpoint`, `getEndpoint`, …, `createVectorIndex`, `getVectorIndex`, …, `queryVectorIndex`, `scanVectorIndex`, …). Because the single `Client` class merges two resource families that were previously two packages, every method name pays an 8–18-character toll for the disambiguation that a sub-namespace could provide for free. +- **Category:** 7 (verbose), 8 (redundant suffix), 14 (Go-style — Go method names paid this cost for receiver disambiguation). +- **Suggested name:** Sub-namespace the client: `client.endpoints.create()`, `client.endpoints.get()`, `client.indexes.query()`, `client.indexes.scan()`. Drop the resource-family suffix from method names. +- **Rationale:** The repetition is a port artifact. Sub-namespacing also separates the two resource families that share a single client today. + +### 14. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` +- **Why weird:** Two methods with the same verb start (`createEndpoint` / `createEndpointWaiter`). The waiter version *calls* `createEndpoint` then wraps the result in a `CreateEndpointWaiter`. A reader sees two `create*` methods and may think they are different operations. The Java/Go SDK convention surfaces a waiter via a side return; TS would more naturally inline the wait (`createEndpointAndWait`). +- **Category:** 7 (verbose), 13 (verb overlap), 17 (inconsistent action verbs). +- **Suggested name:** Either fold the wait into `createEndpoint` (return a `CreateEndpointWaiter` that is both an awaitable and the resource shape), or rename to `createEndpointAndWait`, or expose a single `waitForEndpoint(name)` that any caller can use after `createEndpoint`. +- **Rationale:** Two `create*` methods for one logical "create" operation force every caller to learn which one to use. There is also no analogous waiter for the index create flow, so the pattern is inconsistent within the package. + +### 15. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` +- **Why weird:** The enum is already `EndpointStatus_State` and the other members (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not carry the suffix — only the health-colored values do. Reads `EndpointStatus_State.RED_STATE` — "endpoint status state . red state". Inconsistent within the enum. +- **Category:** 16 (field/value contradicting type domain), 8 (redundant suffix). +- **Suggested name:** If wire allows, `RED` / `YELLOW` (matches `PROVISIONING` / `ONLINE` shape). Otherwise, document the asymmetry. +- **Rationale:** Inconsistency within a single enum is a generator-spec issue worth surfacing. + +### 16. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` +- **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 73-83 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. +- **Category:** 16 (field contradicting domain — two orthogonal axes squeezed into one enum), 6 (misleading). +- **Suggested name:** Split into `EndpointLifecycleState` and `EndpointHealth`. Reflect both on `EndpointStatus` as two fields. +- **Rationale:** Single-enum mixing of orthogonal dimensions is an API-design smell. + +### 17. `Endpoint.creator` vs `Endpoint.lastUpdatedUser` — inconsistent naming for the same kind of value — `model.ts:278, 286` +- **Why weird:** Two `string` fields, both identifying users, with mismatched naming patterns. `creator` is a bare noun; `lastUpdatedUser` is a compound past-participle. JSDoc only says "Creator of the endpoint" / "User who last updated the endpoint" without committing to a format (email? user ID? display name?). The same asymmetry would not survive a side-by-side review. +- **Category:** 13 (verb-tense / parallel-form mismatch), 19 (underspecified IDs). +- **Suggested name:** Symmetric pair, e.g. `createdBy` / `updatedBy` (REST convention) or `creator` / `lastUpdater`. Whichever side, document the format. +- **Rationale:** Parallel fields should look parallel. The current asymmetry implies a semantic difference that does not exist. + +### 18. `creationTimestamp` / `lastUpdatedTimestamp` — noun vs past-participle inconsistency — `model.ts:280, 282` +- **Why weird:** Same parallel-form mismatch as #17, on the timestamp fields. `creation` (noun) vs `lastUpdated` (past-participle). Other Databricks SDK packages standardize on either `createdAt`/`updatedAt` (idiomatic TS) or `createTime`/`updateTime` (Google APIs). This package mixes the two forms. +- **Category:** 13 (verb-tense), 17 (inconsistent naming). +- **Suggested name:** `createdAt` / `updatedAt`. Wire fields stay `creation_timestamp` / `last_updated_timestamp`; remap in the marshaller. +- **Rationale:** Symmetric timestamp fields should match in form. + +--- + +## Low severity + +### 19. `req`, `resp`, `respBody`, `httpReq`, `pollResp`, `apiErr`, `pkgJson`, `opts`, `msg` — Go-idiom shorthand in TS — `client.ts:20, 79-80, 112, 117, 121, 122, 130, 137, 149, 154, 158, 159, 167, 175, 185, 189, 190, 201, 209, 213, 217, 218, 226, 234, 238, 242, 243, 251, 259, 263, 267, 268, 276, 284, 297, 301, 302, 310, 318, 328, 332, 333, 341, 348, 351, 353, 360, 366, 379, 383, 384, 392, 399, 402, 404, 411, 417, 422, 426, 427, 435, 443, 451, 455, 456, 467, 475, 480, 484, 485, 493, 501, 509, 513, 514, 522, 530, 535, 539, 540, 548, 556, 561, 565, 566, 574, 582, 587, 591, 592, 603, 625, 632, 642, 666, 673`; `utils.ts:30, 65-92, 76, 88-91` +- **Why weird:** Ubiquitous Go-style shorthand identifiers ported verbatim. `req`/`resp`/`err`/`opts`/`msg` are conventional in Go, where the receiver supplies enough context; in TS the convention favors spelled-out names (`request`, `response`, `error`, `options`, `message`). Internal inconsistency too: `executeCall` accepts `options` (utils.ts:28) but `executeHttpCall` uses `opts` (utils.ts:67). +- **Category:** 14 (Go/Java-style names), 5 (cryptic abbreviation). +- **Suggested name:** Spell them out throughout: `request`, `response`, `responseBody`, `pollResponse`, `httpRequest`, `apiError`, `packageJson`, `options`, `message`. Generator-level change. +- **Rationale:** Trivial diff, large readability gain. The TS ecosystem standard is the spelled-out form. + +### 20. `Endpoint.numIndexes` reads as "number of array indexes" — `model.ts:292` +- **Why weird:** "Index" in TS most commonly means a numeric position in an array. Here it means "number of vector-search indexes attached to this endpoint" — a domain term, not the data-structure term. Adjacent types use `vectorIndexes` for the array (correct disambiguation), but this scalar count uses bare `indexes`. +- **Category:** 6 (misleading), 14 (Go-style `num*` prefix). +- **Suggested name:** `numVectorIndexes` (matches the adjacent `vectorIndexes` array) or `vectorIndexCount`. +- **Rationale:** Consistency within the package and disambiguation from the data-structure meaning. + +### 21. `numResults`, `numIndexes` — `num*` prefix is a Go-ism — `model.ts:292, 438, 513` +- **Why weird:** `num` is a Go/C abbreviation for "number of". TS more commonly uses `count` suffix (`indexCount`, `resultCount`) or the bare noun pluralized. +- **Category:** 14 (Go-style names), 5 (cryptic abbreviation). +- **Suggested name:** `indexCount`, `resultCount`. Wire fields stay `num_indexes` / `num_results`. +- **Rationale:** Same as #19 — generator-level shorthand carry-over. + +### 22. `flattenQueryParams` is exported but unused inside the package — `utils.ts:123-150` +- **Why weird:** The function is exported from `utils.ts` but every client method assembles `URLSearchParams` directly via `params.append(...)`. The helper is dead code for this package. +- **Category:** Observation (dead export), 6 (misleading — exported as if needed). +- **Suggested name:** Either delete from `utils.ts` here or move to `@databricks/sdk-core` so the per-package `utils.ts` files stop duplicating it. +- **Rationale:** Same finding as in other per-package audits. Generator-level cleanup. + +### 23. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase in a field name — `model.ts:264` +- **Why weird:** The field name reads as a sentence (`modelEndpointName ForQuery`). TS field-naming convention prefers noun phrases over "for"-clauses. Adjacent `embeddingModelEndpointName` (also long, but a noun phrase) shows the package can do better. +- **Category:** 14 (Java-style "ForX" suffix), 7 (verbose). +- **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. +- **Rationale:** Noun phrases align with adjacent fields and TS naming conventions. + +### 24. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` +- **Why weird:** Two array fields on the same type, JSDoc on `columnsToIndex` says: "Alias for columns_to_sync. ... Only one of columns_to_sync or columns_to_index may be specified." Two fields that mean the same thing, where the API rejects both being set, is an API-level footgun. The SDK exposes both without runtime validation. +- **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). +- **Suggested name:** Mark `columnsToSync` `@deprecated` if `columnsToIndex` is the canonical form (or vice versa), and add runtime validation in `marshalDeltaSyncVectorIndexSpecRequestSchema`. +- **Rationale:** API-level aliases are upstream policy, but the SDK should mark the deprecated alias to steer callers. + +### 25. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` +- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` at the top level (line 462) AND a `reranker.parameters.columnsToRerank: string[]` nested inside `RerankerConfig_RerankerParameters` (line 491). Same field name, same purpose, two places. The JSDoc on `reranker` references "`columns_to_rerank`" without saying which copy wins. +- **Category:** 12 (duplicate concept), 6 (misleading — precedence unclear). +- **Suggested name:** Drop one, or document the precedence in JSDoc. If one is for input and the other for echoed-back output, name them accordingly. +- **Rationale:** Users will set the wrong field, or both, and silently get the wrong rerank behavior. + +--- + +## Observation + +### 26. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` +- **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". A field whose JSDoc admits the rollout is incomplete leaves callers guessing whether setting it has any effect today. +- **Category:** 6 (misleading — present but possibly inactive). +- **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behavior and rollout timeline. +- **Rationale:** Documentation-only TODOs leak generator/spec-side state into the public API. Worth surfacing. + +### 27. `EmbeddingSourceColumn.embeddingConfig` JSDoc says "TODO: clean up ai gateway related code" — `model.ts:255` +- **Why weird:** JSDoc on a public-API field contains a developer TODO: "TODO: clean up ai gateway related code. It's deprecated on ModelServing side." This is internal generator/spec-side debt leaking into IntelliSense for every SDK user. +- **Category:** Observation (generator-side leak in JSDoc). +- **Suggested name:** Rewrite the JSDoc to describe the public contract; track the cleanup in the spec, not in the user-facing docs. +- **Rationale:** Internal TODOs in JSDoc are a long-known generator hygiene issue. Worth flagging. + +### 28. `Endpoint.creator` and `lastUpdatedUser` JSDoc gives no format — `model.ts:278, 286` +- **Why weird:** Both fields are typed `string` with JSDocs "Creator of the endpoint" / "User who last updated the endpoint". The reader has no way to tell if the value is a user ID, a display name, an email, or a UC identifier. Same observation applies to `MiniVectorIndex.creator` (`model.ts:396`) and `VectorIndex.creator` (`model.ts:592`). +- **Category:** Observation (underspecified format on user-reference fields), 19 (underspecified IDs). +- **Suggested name:** Keep the field names but extend JSDoc with the expected format (e.g. "the email of the user who created this endpoint"). +- **Rationale:** Documentation-only nit; worth tracking because the format is stable wire behavior and is not surfaced today. diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index fc83b4f8..acaad458 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -11,32 +11,25 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 2 | -| Medium | 7 | +| Medium | 6 | | Low | 6 | -| Observation | 7 | -| **Total** | **22** | +| Observation | 4 | +| **Total** | **18** | Headline themes: 1. **`fullNameArg` is a cryptic, Go/proto-generator-driven name** that leaks internal path-parameter terminology into the public TypeScript API. The `Arg` suffix is meaningless to TS users and inconsistent with the - `fullName` field on the response/info shapes. Appears on `GetVolume`, - `DeleteVolume`, and `UpdateVolume` (model.ts:56, 75, 126). -2. **Operation request types are bare verb-phrases** (`CreateVolume`, - `DeleteVolume`, `GetVolume`, `ListVolumes`, `UpdateVolume`) that collide - semantically with the client methods of the same camel-case names. This - is a repo-wide pattern but worth flagging here for documentation. -3. **`Create*` / `Update*` request types include read-only output fields** + `fullName` field on the response/info shapes. Appears on + `GetVolumeRequest`, `DeleteVolumeRequest`, and `UpdateVolumeRequest` + (model.ts:56, 75, 126). +2. **`Create*` / `Update*` request types include read-only output fields** (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `volumeId`, `fullName`, `browseOnly`). These belong only on `VolumeInfo`. They appear on the request shapes because the upstream proto reuses the same message — but on the TypeScript surface they misleadingly invite users to "set" server-managed values. -4. **`SseEncryptionAlgorithm` repeats `SSE_ENCRYPTION_ALGORITHM_` in its - single zero-valued member** and shouts `AWS_SSE_S3` / `AWS_SSE_KMS` in - SCREAMING_SNAKE on the two real values — the SDK-wide proto-mirror - convention but jarring for TS readers. --- @@ -44,10 +37,10 @@ Headline themes: ### H1. `fullNameArg` — cryptic `Arg` suffix on path-parameter fields -- **File / line:** `src/v1/model.ts:56` (`DeleteVolume.fullNameArg`), - `src/v1/model.ts:75` (`GetVolume.fullNameArg`), - `src/v1/model.ts:126` (`UpdateVolume.fullNameArg`); cross-ref - `src/v1/client.ts:125, 154, 268`. +- **File / line:** `src/v1/model.ts:56` (`DeleteVolumeRequest.fullNameArg`), + `src/v1/model.ts:75` (`GetVolumeRequest.fullNameArg`), + `src/v1/model.ts:126` (`UpdateVolumeRequest.fullNameArg`); cross-ref + `src/v1/client.ts:125, 160, 277`. - **Category:** #5 cryptic abbreviation; #6 misleading name; #20 type- suffix tautology (inverse — `Arg` is a non-domain suffix). - **Current:** `fullNameArg?: string`. @@ -56,62 +49,40 @@ Headline themes: - **Rationale:** `Arg` is a proto/grpc-generator artifact that signals "this field maps to a URL path argument." TypeScript callers have no concept of "Arg" — they just see two fields named `fullNameArg` and (on the - related `VolumeInfo` / `UpdateVolume` payload) `fullName`, with no way - to know they refer to the same volume identifier. The URL templating in - `client.ts:125, 154, 268` interpolates it into the path directly. The + related `VolumeInfo` / `UpdateVolumeRequest` payload) `fullName`, with no + way to know they refer to the same volume identifier. The URL templating + in `client.ts:125, 160, 277` interpolates it into the path directly. The `?: | undefined` is also a semantic lie — without this value the path becomes `/api/2.1/unity-catalog/volumes/` and the call cannot succeed. ### H2. `Create*` / `Update*` request types include server-only fields -- **File / line:** `src/v1/model.ts:16–52` (`CreateVolume`), - `src/v1/model.ts:124–164` (`UpdateVolume`). +- **File / line:** `src/v1/model.ts:16–52` (`CreateVolumeRequest`), + `src/v1/model.ts:124–164` (`UpdateVolumeRequest`). - **Category:** #6 misleading name; #16 field contradicting type domain; #12 duplicate concepts. -- **Current:** `CreateVolume` and `UpdateVolume` both carry every field on - `VolumeInfo`: `volumeId`, `metastoreId`, `createdAt`, `createdBy`, - `updatedAt`, `updatedBy`, `fullName`, `browseOnly`. +- **Current:** `CreateVolumeRequest` and `UpdateVolumeRequest` both carry + every field on `VolumeInfo`: `volumeId`, `metastoreId`, `createdAt`, + `createdBy`, `updatedAt`, `updatedBy`, `fullName`, `browseOnly`. - **Suggestion:** Trim the request shapes to the fields the server - actually accepts (per the Go SDK / OpenAPI). For `CreateVolume`: + actually accepts (per the Go SDK / OpenAPI). For `CreateVolumeRequest`: `name`, `catalogName`, `schemaName`, `volumeType`, `storageLocation`, - `comment`. For `UpdateVolume`: `fullNameArg` (the path identifier), - `newName`, `owner`, `comment` (per the method docstring at - `client.ts:262`). -- **Rationale:** A request type named `CreateVolume` whose fields include - `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, and `volumeId` - invites users to populate them — but the server ignores or rejects - them. The `client.ts:262` doc itself says "Currently only the name, the - owner or the comment of the volume could be updated." Compare with the - Go SDK `databricks/sdk-go/databricks/api/volumes/v1/` to confirm the - upstream split. (Caveat: if the upstream proto truly reuses the same - message for request + response, the audit recommends a TS-specific - request type — name suggestions: `CreateVolumeRequest`, - `UpdateVolumeRequest`.) + `comment`. For `UpdateVolumeRequest`: `fullNameArg` (the path + identifier), `newName`, `owner`, `comment` (per the method docstring at + `client.ts:271`). +- **Rationale:** A request type named `CreateVolumeRequest` whose fields + include `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, and + `volumeId` invites users to populate them — but the server ignores or + rejects them. The `client.ts:271` doc itself says "Currently only the + name, the owner or the comment of the volume could be updated." Compare + with the Go SDK `databricks/sdk-go/databricks/api/volumes/v1/` to + confirm the upstream split. --- ## Medium Severity -### M1. Bare verb-phrase request type names collide with client methods - -- **File / line:** `src/v1/model.ts:16` (`CreateVolume`), `54` - (`DeleteVolume`), `73` (`GetVolume`), `80` (`ListVolumes`), `124` - (`UpdateVolume`); cross-ref `src/v1/client.ts:89, 121, 153, 196, 264`. -- **Category:** #6 misleading name; #14 Go/Java-style name. -- **Current:** Types named `CreateVolume`, `DeleteVolume`, etc., consumed - as `client.createVolume(req: CreateVolume)`. -- **Suggestion:** `CreateVolumeRequest`, `DeleteVolumeRequest`, - `GetVolumeRequest`, `ListVolumesRequest`, `UpdateVolumeRequest`. -- **Rationale:** The verb-phrase form reads like a function name. A - reader sees `function createVolume(req: CreateVolume): Promise<…>` and - must distinguish the verb-method from the verb-type. Sibling - packages `accountsettings`, `budgetpolicy`, `bundle` use the `Request` - suffix. `volumes` (and many sibling UC packages) omit it. Audit - observation, not a local defect — recorded as Medium because the - collision is most acute in `volumes` where every operation has a - matching type. - -### M2. `VolumeInfo` — redundant `Info` suffix +### M1. `VolumeInfo` — redundant `Info` suffix - **File / line:** `src/v1/model.ts:166`. - **Category:** #8 redundant suffix; #14 Go/Java-style name. @@ -124,32 +95,11 @@ Headline themes: domain noun — note that `volumes` has no type with the bare name `Volume`, even though it is literally the "volumes" package. -### M3. `SseEncryptionDetails` and `SseEncryptionAlgorithm` — uppercase -"Sse" acronym casing inconsistent across the type system - -- **File / line:** `src/v1/model.ts:5` (enum), `113` (interface), - `model.ts:68, 218, 219, 236, 332, 335` (field/usage). -- **Category:** #3 acronym casing inconsistencies; #14 Go/Java-style name. -- **Current:** `Sse` is rendered as a three-letter title-case acronym - (`Sse`, `sseEncryptionDetails`), but the enum member values use - SCREAMING_SNAKE (`AWS_SSE_S3`, `AWS_SSE_KMS`, - `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`). -- **Suggestion:** Per the Google TypeScript Style Guide §5.3.5 (acronyms - are treated as words: PascalCase or camelCase, not all-caps in identifiers), - `Sse` is the correct rendering for types and fields. The enum values - are correct as-is (the proto convention is SCREAMING_SNAKE_CASE for - values). Flagged here because some sibling packages in the codebase - use `SSE` or `SSEEncryption` — verify consistency. Today this package - is internally consistent (good). -- **Rationale:** Acronym casing is the single most common naming - inconsistency in TS codebases. `Sse` is the right choice; record this - as an observation in case a future audit flips it. - -### M4. `SseEncryptionDetails.algorithm` — generic field name on a +### M2. `SseEncryptionDetails.algorithm` — generic field name on a single-purpose type - **File / line:** `src/v1/model.ts:116`; cross-ref `model.ts:239, 243, - 348, 351`. + 348, 352`. - **Category:** #1 vague/generic; #15 generic field name losing meaning. - **Current:** `algorithm?: SseEncryptionAlgorithm`. - **Suggestion:** `encryptionAlgorithm` — though, in context, the parent @@ -157,18 +107,18 @@ single-purpose type is a borderline call. - **Rationale:** Inside `SseEncryptionDetails`, `algorithm` is fine. The flag stands only if the field is ever exposed in flatter scopes (it - isn't, locally). Listed for completeness; lower priority than M3. + isn't, locally). Listed for completeness. -### M5. `awsKmsKeyArn` vs. `accessPoint` — inconsistent AWS-specific +### M3. `awsKmsKeyArn` vs. `accessPoint` — inconsistent AWS-specific field-naming style - **File / line:** `src/v1/model.ts:121` (`awsKmsKeyArn`); cross-ref - `model.ts:48, 159, 198` (`accessPoint`). + `model.ts:48, 160, 198` (`accessPoint`). - **Category:** #1 vague/generic; #3 acronym casing inconsistencies; #6 misleading name. - **Current:** `awsKmsKeyArn?: string` lives on `SseEncryptionDetails` - (AWS-specific). `accessPoint?: string` lives on `CreateVolume` / - `UpdateVolume` / `VolumeInfo` but is also AWS-specific (the doc + (AWS-specific). `accessPoint?: string` lives on `CreateVolumeRequest` / + `UpdateVolumeRequest` / `VolumeInfo` but is also AWS-specific (the doc comment at `model.ts:47, 159, 197` reads "The AWS access point to use when accesing s3 for this external location."). - **Suggestion:** Either prefix the latter as `awsAccessPoint` (matching @@ -177,10 +127,11 @@ field-naming style - **Rationale:** Two AWS-only fields side-by-side, one prefixed, one not. The doc comment also has a typo ("accesing" → "accessing"). -### M6. `browseOnly` is a server-derived flag on request types +### M4. `browseOnly` is a server-derived flag on request types -- **File / line:** `src/v1/model.ts:51` (`CreateVolume.browseOnly`), - `163` (`UpdateVolume.browseOnly`), `201` (`VolumeInfo.browseOnly`). +- **File / line:** `src/v1/model.ts:51` (`CreateVolumeRequest.browseOnly`), + `163` (`UpdateVolumeRequest.browseOnly`), `201` + (`VolumeInfo.browseOnly`). - **Category:** #6 misleading name; #16 field contradicting type domain. - **Current:** `browseOnly?: boolean | undefined` — present on the request types but described in the doc as "Indicates whether the @@ -195,11 +146,11 @@ field-naming style want browse-only access" rather than "the server has limited me to browse-only." -### M7. `req` parameter name on all client methods +### M5. `req` parameter name on all client methods -- **File / line:** `src/v1/client.ts:90, 122, 153, 197, 239, 265`. +- **File / line:** `src/v1/client.ts:90, 122, 157, 203, 248, 274`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. -- **Current:** `req: CreateVolume`, `req: DeleteVolume`, etc. +- **Current:** `req: CreateVolumeRequest`, `req: DeleteVolumeRequest`, etc. - **Suggestion:** `request` (matches Go-port readability without abbreviation). - **Rationale:** Throughout the JS/TS ecosystem, function parameters are @@ -208,6 +159,29 @@ field-naming style encouraged; in TS this reads as Go-translated code. Pervasive in this package (every method uses `req`) and across the repo. +### M6. Repeated `Details` suffix — `EncryptionDetails` wraps +`SseEncryptionDetails` + +- **File / line:** `src/v1/model.ts:63` (`EncryptionDetails`), + `src/v1/model.ts:114` (`SseEncryptionDetails`); cross-ref + `model.ts:49, 161, 199` (field `encryptionDetails`). +- **Category:** proto-architectural-leak — repeated `Details` suffix + across a parent/child pair carrying the same wrapper word. +- **Current:** `EncryptionDetails` is a one-field discriminated-union + wrapper whose only payload variant is `SseEncryptionDetails`. Both + types end in `Details`, and the field on the request/info types is + `encryptionDetails` (which itself only contains + `sseEncryptionDetails`). +- **Suggestion:** Either drop the outer wrapper entirely (inline the + union on `VolumeInfo`) or rename the inner type so `Details` is not + doubled — e.g. `EncryptionConfig` / `SseEncryption`. +- **Rationale:** The doubled `Details` is a proto-message-shape leak: + proto requires a wrapper message for each `oneof`, so the generator + emits `EncryptionDetails` purely to carry one `sse_encryption_details` + field. In TypeScript a discriminated union does not need that wrapper, + and the repeated `Details` reads as the generator name-pattern, not + domain vocabulary. + --- ## Low Severity @@ -230,7 +204,7 @@ field-naming style ### L2. `Call` (imported, not local) and `call` local variable share names -- **File / line:** `src/v1/client.ts:96, 127, 162, 220, 271`. +- **File / line:** `src/v1/client.ts:96, 127, 168, 226, 280`. - **Category:** #1 vague/generic. - **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. - **Suggestion:** `httpCall` or `doRequest`. @@ -259,7 +233,7 @@ field-naming style - **Category:** dead code. - **Current:** Exported but not used by `client.ts` (the list / get methods build params inline via `URLSearchParams.append` calls at - `client.ts:156–215`). + `client.ts:161–222`). - **Suggestion:** Drop the export or move to a shared util package. - **Rationale:** Unused exports become accidental public API. Out of scope for pure naming but flagged because the name promises a feature @@ -268,9 +242,10 @@ field-naming style ### L5. `fullName` (on `VolumeInfo`) vs. `fullNameArg` (on path-param requests) -- **File / line:** `model.ts:36, 75, 126, 148, 186` (`fullName` on - `CreateVolume`, `UpdateVolume.fullName` in payload, `VolumeInfo.fullName`), - `model.ts:56, 75, 126` (`fullNameArg` as path param). +- **File / line:** `model.ts:36, 148, 186` (`fullName` on + `CreateVolumeRequest`, `UpdateVolumeRequest.fullName` in payload, + `VolumeInfo.fullName`), `model.ts:56, 75, 126` (`fullNameArg` as path + param). - **Category:** #6 misleading name; #19 underspecified IDs. - **Current:** Two different fields naming the same logical concept (the three-level volume identifier) differently depending on @@ -279,16 +254,18 @@ requests) If proto generation requires the `_Arg` discriminator, then bury it internally and surface only `fullName` to callers. - **Rationale:** A user reading the API sees `fullName` on - `VolumeInfo` and `fullNameArg` on `DeleteVolume` and has to ask: why - are they different? The answer ("one is a request path parameter") - is generator-internal and should not bleed onto the public surface. + `VolumeInfo` and `fullNameArg` on `DeleteVolumeRequest` and has to + ask: why are they different? The answer ("one is a request path + parameter") is generator-internal and should not bleed onto the + public surface. ### L6. `pageReq` and `pageReq.pageToken` mutation in `listVolumesIter` -- **File / line:** `src/v1/client.ts:242–252`. +- **File / line:** `src/v1/client.ts:251–260`. - **Category:** #1 vague/generic. -- **Current:** `const pageReq: ListVolumes = {...req};` then mutates - `pageReq.pageToken = resp.nextPageToken;` on each loop iteration. +- **Current:** `const pageReq: ListVolumesRequest = {...req};` then + mutates `pageReq.pageToken = resp.nextPageToken;` on each loop + iteration. - **Suggestion:** `currentPageRequest` or `nextPageRequest`. - **Rationale:** `pageReq` is fine as a Go-ism, but the variable is reassigned across iterations — `pageRequest` makes the mutation site @@ -298,32 +275,14 @@ requests) ## Observations (repo-wide conventions, not local defects) -### O1. Bare `Get*` / `Create*` / `Update*` / `Delete*` / `List*` request -shapes are a repo-wide pattern - -Sibling packages `catalogs`, `connections`, `clusters`, `externallocations`, -`clusterpolicies`, and most UC packages use bare verb-phrases for request -types. Changing this package alone would create asymmetry. See -`grep -rE "^export interface (Get|Set|Create|Update|Delete|List)" packages/` -for the workspace inventory. (M1 above flags it locally.) - -### O2. `*_UNSPECIFIED` zero values repeated across enums - -`SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` -(`model.ts:6`) repeats the enum domain (`SSE_ENCRYPTION_ALGORITHM_`) in -the member name. This is a proto-buf default and is consistent with -sibling packages. The duplication makes `SseEncryptionAlgorithm.SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` -60 characters long for what should read as `UNSPECIFIED`. Not a local -defect; would need a workspace-wide convention change. - -### O3. `…Info` suffix repeated across UC types +### O1. `…Info` suffix repeated across UC types `VolumeInfo` follows the `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the codebase decides to drop the `Info` suffix, this is one of many to fix -(M2 above flags it locally). +(M1 above flags it locally). -### O4. `_Arg` suffix on path parameter fields is a generator-wide artifact +### O2. `_Arg` suffix on path parameter fields is a generator-wide artifact `fullNameArg` (H1) is not unique to volumes — the workspace contains fields like `nameArg`, `idArg`, `fullNameArg` across packages that take a @@ -331,22 +290,14 @@ URL path parameter. Search: `grep -rE "fullNameArg|nameArg|idArg" packages/*/src/`. Documented here because the fix has cross-package implications. -### O5. `VolumeType` enum members are clean - -`VolumeType.MANAGED` and `VolumeType.EXTERNAL` (`model.ts:11–14`) avoid -the SCREAMING_SNAKE_CASE long-form variant (no `VOLUME_TYPE_*` prefix). -This enum is the cleanest in the file and shows that the proto-mirror -pattern is not mandatory — `SseEncryptionAlgorithm` could have been -written this way too. - -### O6. URL path string repeated across methods without a named constant +### O3. URL path string repeated across methods without a named constant The base path `/api/2.1/unity-catalog/volumes` (and the suffixed variant with `${req.fullNameArg ?? ''}`) appears five times in -`client.ts:93, 125, 154, 200, 268`. Not a naming defect, but typical +`client.ts:93, 125, 160, 206, 277`. Not a naming defect, but typical naming-audit findings include "unnamed magic strings." Worth a note. -### O7. `PACKAGE_SEGMENT.key` / `.value` carry no descriptive name +### O4. `PACKAGE_SEGMENT.key` / `.value` carry no descriptive name `client.ts:39–42`: `{key: pkgJson.name.replace(/^@[^/]+\//, ''), value: pkgJson.version}`. The variable name `PACKAGE_SEGMENT` reads fine but @@ -381,30 +332,30 @@ identical across every generated client in the workspace. | File | Lines | Audited | | -------------- | ----- | ------------------------------------------------ | | `src/v1/model.ts` | 399 | All 2 enums + 9 interfaces + 9 schemas + every field. | -| `src/v1/client.ts` | 289 | Class, constructor, 5 public methods + 1 iterator, all locals. | +| `src/v1/client.ts` | 298 | Class, constructor, 5 public methods + 1 iterator, all locals. | | `src/v1/utils.ts` | 151 | All exported / private functions and types. | | `src/v1/index.ts` | 19 | All re-exports. | Type & symbol checklist: -- [x] `SseEncryptionAlgorithm` enum (3 members) → O2. -- [x] `VolumeType` enum (2 members) → O5 (clean). -- [x] `CreateVolume` interface (17 fields) → H2, M1, M5, M6. -- [x] `DeleteVolume` interface (1 field) → H1, M1, L5. -- [x] `EncryptionDetails` interface → no additional defect. -- [x] `GetVolume` interface (2 fields) → H1, M1, L5. -- [x] `ListVolumes` interface (5 fields) → M1. -- [x] `SseEncryptionDetails` interface (2 fields) → M3, M4, M5. -- [x] `UpdateVolume` interface (18 fields) → H1, H2, M1, M5, M6, L5. -- [x] `VolumeInfo` interface (16 fields) → M2, M5, M6, L5, O3. +- [x] `SseEncryptionAlgorithm` enum (3 members) → no defect. +- [x] `VolumeType` enum (2 members) → no defect. +- [x] `CreateVolumeRequest` interface (17 fields) → H2, M3, M4. +- [x] `DeleteVolumeRequest` interface (1 field) → H1, L5. +- [x] `EncryptionDetails` interface → M6. +- [x] `GetVolumeRequest` interface (2 fields) → H1, L5. +- [x] `ListVolumesRequest` interface (5 fields) → no additional defect. +- [x] `SseEncryptionDetails` interface (2 fields) → M2, M3, M6. +- [x] `UpdateVolumeRequest` interface (18 fields) → H1, H2, M3, M4, L5. +- [x] `VolumeInfo` interface (16 fields) → M1, M3, M4, L5, O1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O7. -- [x] `createVolume(req, options)` method → H2, M1, M7, L2. -- [x] `deleteVolume(req, options)` method → H1, M1, M7, L2. -- [x] `getVolume(req, options)` method → H1, M1, M7, L2. -- [x] `listVolumes(req, options)` method → M1, M7, L2. -- [x] `listVolumesIter(req, options)` async generator → M1, M7, L6. -- [x] `updateVolume(req, options)` method → H1, H2, M1, M7, L2. +- [x] `PACKAGE_SEGMENT` constant → O4. +- [x] `createVolume(req, options)` method → H2, M5, L2. +- [x] `deleteVolume(req, options)` method → H1, M5, L2. +- [x] `getVolume(req, options)` method → H1, M5, L2. +- [x] `listVolumes(req, options)` method → M5, L2. +- [x] `listVolumesIter(req, options)` async generator → M5, L6. +- [x] `updateVolume(req, options)` method → H1, H2, M5, L2. - [x] `HttpCallOptions` interface → no defect. - [x] `executeCall` function → L1. - [x] `readAll` private function → no defect (name fits idiom). @@ -412,3 +363,18 @@ Type & symbol checklist: - [x] `buildHttpRequest` function → L3. - [x] `flattenQueryParams` function → L4 (unused). - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). + +--- + +## Fixed + +- #M1 Bare verb-phrase request type names (originally cited at + `src/v1/model.ts:16, 54, 73, 80, 124`): Fixed in regeneration on + 2026-05-20 — request DTOs renamed to `CreateVolumeRequest`, + `DeleteVolumeRequest`, `GetVolumeRequest`, `ListVolumesRequest`, + `UpdateVolumeRequest`; collision with client methods resolved. +- #O1 Bare `Get*` / `Create*` / `Update*` / `Delete*` / `List*` request + shapes are a repo-wide pattern (originally cited as observation): Fixed + in regeneration on 2026-05-20 — local M1 finding resolved by the + `Request` suffix renaming; cross-package convention now matches sibling + packages that already used the suffix. diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index 5db46649..4308436d 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -24,6 +24,16 @@ tags, conf pairs, info). The current customer-facing brand is "warehouse", so leftover `Endpoint*` identifiers are misleading. This is the dominant theme of the audit (see F0). +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 25 | +| Medium | 13 | +| Low | 45 | +| Observation | 17 | +| **Total** | **100** | + --- ## Inventory @@ -47,20 +57,20 @@ This is the dominant theme of the audit (see F0). | `EndpointSecurityPolicy` | `NONE`, `DATA_ACCESS_CONTROL`, `PASSTHROUGH` | | `EndpointSpotInstancePolicy` | `POLICY_UNSPECIFIED`, `COST_OPTIMIZED`, `RELIABILITY_OPTIMIZED` | | `EndpointState` | `STARTING`, `RUNNING`, `STOPPING`, `STOPPED`, `DELETING`, `DELETED` | -| `TerminationCode` | ~150 values (`UNKNOWN`, `USER_REQUEST`, `JOB_FINISHED`, `INACTIVITY`, ... `CERT_ROTATION`) | +| `TerminationCode` | ~150 values (`UNKNOWN`, `USER_REQUEST`, `JOB_FINISHED`, `INACTIVITY`, ... `HIVEMETASTORE_CONNECTIVITY_FAILURE`) | | `TerminationType` | `SUCCESS`, `CLIENT_ERROR`, `SERVICE_FAULT`, `CLOUD_FAILURE` | -| `WarehouseType` | `TYPE_UNSPECIFIED`, `CLASSIC`, `PRO`, `REYDEN` | +| `WarehouseType` | `TYPE_UNSPECIFIED`, `CLASSIC`, `PRO` | | `EndpointHealth_Status` | `STATUS_UNSPECIFIED`, `HEALTHY`, `DEGRADED`, `FAILED` | ### Interfaces (`model.ts`) -`Channel`, `CreateDefaultWarehouseOverrideRequest`, `CreateWarehouse`, -`CreateWarehouse_Response`, `DefaultWarehouseOverride`, +`Channel`, `CreateDefaultWarehouseOverrideRequest`, `CreateWarehouseRequest`, +`CreateWarehouseRequest_Response`, `DefaultWarehouseOverride`, `DeleteDefaultWarehouseOverrideRequest`, `EditWarehouseRequest`, `EditWarehouseRequest_Response`, `EndpointConfPair`, `EndpointHealth`, `EndpointInfo`, `EndpointTagPair`, `EndpointTags`, -`GetDefaultWarehouseOverrideRequest`, `GetWarehouse`, -`GetWarehouse_Response`, `GetWorkspaceWarehouseConfigRequest`, +`GetDefaultWarehouseOverrideRequest`, `GetWarehouseRequest`, +`GetWarehouseRequest_Response`, `GetWorkspaceWarehouseConfigRequest`, `GetWorkspaceWarehouseConfigRequest_Response`, `ListDefaultWarehouseOverridesRequest`, `ListDefaultWarehouseOverridesResponse`, `OdbcParams`, @@ -75,12 +85,12 @@ This is the dominant theme of the audit (see F0). ### Schemas (`model.ts`) -`unmarshalChannelSchema`, `unmarshalCreateWarehouse_ResponseSchema`, +`unmarshalChannelSchema`, `unmarshalCreateWarehouseRequest_ResponseSchema`, `unmarshalDefaultWarehouseOverrideSchema`, `unmarshalEditWarehouseRequest_ResponseSchema`, `unmarshalEndpointConfPairSchema`, `unmarshalEndpointHealthSchema`, `unmarshalEndpointInfoSchema`, `unmarshalEndpointTagPairSchema`, -`unmarshalEndpointTagsSchema`, `unmarshalGetWarehouse_ResponseSchema`, +`unmarshalEndpointTagsSchema`, `unmarshalGetWarehouseRequest_ResponseSchema`, `unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema`, `unmarshalListDefaultWarehouseOverridesResponseSchema`, `unmarshalOdbcParamsSchema`, `unmarshalRepeatedEndpointConfPairsSchema`, @@ -90,7 +100,7 @@ This is the dominant theme of the audit (see F0). `unmarshalListWarehousesRequest_ResponseSchema`, `unmarshalStartRequest_ResponseSchema`, `unmarshalStopRequest_ResponseSchema`, `marshalChannelSchema`, -`marshalCreateWarehouseSchema`, `marshalDefaultWarehouseOverrideSchema`, +`marshalCreateWarehouseRequestSchema`, `marshalDefaultWarehouseOverrideSchema`, `marshalEditWarehouseRequestSchema`, `marshalEndpointConfPairSchema`, `marshalEndpointTagPairSchema`, `marshalEndpointTagsSchema`, `marshalRepeatedEndpointConfPairsSchema`, @@ -189,26 +199,26 @@ compatibility while updating the customer-visible type names. ### 1. Vague / generic names #### F1.1 — `EndpointInfo` type name (HIGH) -- **Where:** `model.ts:1006`, `index.ts:33`, return field +- **Where:** `model.ts:979`, `index.ts:34`, return field `warehouses?: EndpointInfo[]` on `ListWarehousesRequest_Response` - (`model.ts:1482`), yield type of `listWarehousesIter` - (`client.ts:460`). + (`model.ts:1455`), yield type of `listWarehousesIter` + (`client.ts:466`). - **Why flagged:** Misleading legacy name. The type represents a SQL warehouse (it has `clusterSize`, `warehouseType`, `jdbcUrl`, `numClusters`, etc.), but the type is named - `EndpointInfo`. Same root concept as `GetWarehouse_Response`, + `EndpointInfo`. Same root concept as `GetWarehouseRequest_Response`, which has identical field set — so the type name should match. - **Suggestion:** Rename to `Warehouse` (the resource itself) or `WarehouseInfo` if backward parity matters. Mirror - `GetWarehouse_Response` shape into a single canonical type + `GetWarehouseRequest_Response` shape into a single canonical type (see F12.1). #### F1.2 — `EndpointState` enum name (HIGH) - **Where:** `model.ts:87`, `index.ts:16`. Used in - `EndpointInfo.state`, `GetWarehouse_Response.state`, and as the - poll-target inside every Waiter (`client.ts:656, 659, 660, 698, - ...`). + `EndpointInfo.state`, `GetWarehouseRequest_Response.state`, and as + the poll-target inside every Waiter (`client.ts:662, 665, 666, + 704, ...`). - **Why flagged:** The states themselves (`RUNNING`, `STOPPING`, `STOPPED`, `DELETING`, `DELETED`, `STARTING`) are warehouse states. JSDoc on the enum says "State of a warehouse." but the @@ -221,30 +231,30 @@ compatibility while updating the customer-visible type names. spec level. #### F1.3 — `EndpointHealth` interface and `EndpointHealth_Status` enum (HIGH) -- **Where:** `model.ts:993`, `model.ts:713`, `index.ts:20`. +- **Where:** `model.ts:966`, `model.ts:686`, `index.ts:20`. Field on `EndpointInfo.health` and - `GetWarehouse_Response.health`. JSDoc says "Health status of - the endpoint" (`model.ts:994`). + `GetWarehouseRequest_Response.health`. JSDoc says "Health status of + the endpoint" (`model.ts:967`). - **Why flagged:** Same root issue as F1.1/F1.2. The health is of a warehouse, not an endpoint. The waiters use - `pollResp.health?.summary` (`client.ts:661`) — a warehouse + `pollResp.health?.summary` (`client.ts:667`) — a warehouse health message. - **Suggestion:** Rename to `WarehouseHealth` / `WarehouseHealth_Status`. #### F1.4 — `EndpointTags`, `EndpointTagPair` interface names (HIGH) -- **Where:** `model.ts:1115, 1120`, `index.ts:31, 32`. Field - `tags?: EndpointTags` on `CreateWarehouse`, +- **Where:** `model.ts:1093, 1088`, `index.ts:35, 36`. Field + `tags?: EndpointTags` on `CreateWarehouseRequest`, `EditWarehouseRequest`, `EndpointInfo`, - `GetWarehouse_Response`. + `GetWarehouseRequest_Response`. - **Why flagged:** Same legacy naming. Tags are on warehouses, not endpoints. JSDoc says "key-value pairs that will be tagged on all resources … associated with this SQL warehouse" - (`model.ts:815, 959, 1077, 1212`). + (`model.ts:789, 933, 1051, 1186`). - **Suggestion:** Rename to `WarehouseTags` / `WarehouseTagPair`. #### F1.5 — `EndpointConfPair`, `RepeatedEndpointConfPairs` (HIGH) -- **Where:** `model.ts:988, 1336`, `index.ts:30, 41`. +- **Where:** `model.ts:961, 1309`, `index.ts:32, 45`. - **Why flagged:** Workspace-level SQL configuration parameters (`globalParam`, `sqlConfigurationParameters`, etc.) are not per-endpoint. They are workspace-scoped. The current name @@ -266,7 +276,7 @@ compatibility while updating the customer-visible type names. `WarehouseSpotInstancePolicy`. #### F1.7 — `Channel` type and `ChannelName` enum (MEDIUM) -- **Where:** `model.ts:728, 7`, `index.ts:12, 24`. +- **Where:** `model.ts:701, 7`, `index.ts:24, 12`. - **Why flagged:** "Channel" alone is a generic term (HTTP channel, communication channel, marketing channel). In this domain it means "DBSQL release channel" — `CHANNEL_NAME_PREVIEW`, @@ -280,28 +290,28 @@ compatibility while updating the customer-visible type names. duplicates "name" — see F8.2. #### F1.8 — `name` field used both as a human name and as a path identifier (HIGH) -- **Where:** `name` appears on `CreateWarehouse` (`model.ts:754`, - "Logical name for the cluster"), `EditWarehouseRequest` - (`model.ts:898`), `EndpointInfo` (`model.ts:1016`), - `GetWarehouse_Response` (`model.ts:1151`), - `DefaultWarehouseOverride` (`model.ts:861`, +- **Where:** `name` appears on `CreateWarehouseRequest` + (`model.ts:727`, "Logical name for the cluster"), + `EditWarehouseRequest` (`model.ts:871`), `EndpointInfo` + (`model.ts:989`), `GetWarehouseRequest_Response` + (`model.ts:1124`), `DefaultWarehouseOverride` (`model.ts:834`, `default-warehouse-overrides/{default_warehouse_override_id}`), - `DeleteDefaultWarehouseOverrideRequest` (`model.ts:880`), - `GetDefaultWarehouseOverrideRequest` (`model.ts:1131`). + `DeleteDefaultWarehouseOverrideRequest` (`model.ts:853`), + `GetDefaultWarehouseOverrideRequest` (`model.ts:1104`). - **Why flagged:** Two semantically different things share the field name `name`. On warehouses, `name` is a human-readable display name ("My SQL warehouse"). On default-warehouse- overrides, `name` is the resource-name path identifier (`default-warehouse-overrides/123`). The latter is functionally - an ID. Caller code paths in `client.ts:196, 287, 588` use + an ID. Caller code paths in `client.ts:199, 290, 594` use `req.name` as the URL path segment for the override APIs. - **Suggestion:** On the override types, rename `name` to `resourceName` and document the path-id role. Alternatively, document the dual role in JSDoc to make the contract explicit. #### F1.9 — `req` parameter name on every client method (LOW, Go-ism) -- **Where:** `client.ts:108, 152, 177, 193, 212, 240, 268, 284, - 309, 334, 365, 401, 419, 458, 476, 508, 533, 545, 570, 585`. +- **Where:** `client.ts:108, 152, 180, 196, 215, 243, 271, 287, + 312, 340, 371, 407, 425, 464, 482, 514, 539, 551, 576, 591`. - **Why flagged:** `req` is a Go-ism (see category 14). It is also generic. - **Suggestion:** Use `request` for stylistic consistency with @@ -309,7 +319,7 @@ compatibility while updating the customer-visible type names. #### F1.10 — `resp` local variable everywhere (LOW) - **Where:** `client.ts` throughout (e.g. `resp: - CreateWarehouse_Response | undefined`). + CreateWarehouseRequest_Response | undefined`). - **Why flagged:** Same Go abbreviation as `req`. See F14.1. - **Suggestion:** `response` for consistency. Generator-level. @@ -323,7 +333,7 @@ compatibility while updating the customer-visible type names. across packages. Cross-cutting decision. #### F1.12 — `code` field on `TerminationReason` (LOW) -- **Where:** `model.ts:1393`. +- **Where:** `model.ts:1366`. - **Why flagged:** `code` is generic; disambiguated by container type, but `terminationCode` would be clearer in isolation. - **Suggestion:** Acceptable as-is given the containing type. @@ -331,7 +341,7 @@ compatibility while updating the customer-visible type names. introduces redundancy. Leave. #### F1.13 — `type` field on `TerminationReason` and `DefaultWarehouseOverride` (LOW) -- **Where:** `model.ts:865, 1395`. +- **Where:** `model.ts:838, 1368`. - **Why flagged:** `type` is one of the most generic identifier names possible. Both are typed against domain-specific enums, but the field name alone gives no hint. @@ -339,7 +349,7 @@ compatibility while updating the customer-visible type names. `overrideType` would be more self-documenting. #### F1.14 — `parameters` field on `TerminationReason` (LOW) -- **Where:** `model.ts:1397`. +- **Where:** `model.ts:1370`. - **Why flagged:** `parameters` is generic. JSDoc says "list of parameters that provide additional information about why the cluster was terminated" — these are debug context, not request @@ -349,7 +359,7 @@ compatibility while updating the customer-visible type names. elsewhere in the SDK. #### F1.15 — `details`, `message`, `summary` fields on `EndpointHealth` (LOW) -- **Where:** `model.ts:997, 1001, 1003`. +- **Where:** `model.ts:970, 974, 976`. - **Why flagged:** Three generic prose fields. JSDoc clarifies: `message` is deprecated; `summary` is short; `details` is long. Their relationship is not obvious from names. @@ -358,7 +368,7 @@ compatibility while updating the customer-visible type names. a single nested structure. #### F1.16 — `customTags` field on `EndpointTags` (LOW) -- **Where:** `model.ts:1121`. +- **Where:** `model.ts:1094`. - **Why flagged:** "custom" is implied by the container type `EndpointTags` (vs. a more specific name). The field is just a list of tags, so the `custom` prefix adds no information @@ -375,97 +385,7 @@ compatibility while updating the customer-visible type names. ### 2. Redundant enum prefixes -#### F2.1 — `ChannelName.CHANNEL_NAME_*` (HIGH) -- **Where:** `model.ts:7-13`. - ```ts - export enum ChannelName { - CHANNEL_NAME_UNSPECIFIED = 'CHANNEL_NAME_UNSPECIFIED', - CHANNEL_NAME_PREVIEW = 'CHANNEL_NAME_PREVIEW', - CHANNEL_NAME_CURRENT = 'CHANNEL_NAME_CURRENT', - CHANNEL_NAME_PREVIOUS = 'CHANNEL_NAME_PREVIOUS', - CHANNEL_NAME_CUSTOM = 'CHANNEL_NAME_CUSTOM', - } - ``` -- **Why flagged:** Every member prefixed with `CHANNEL_NAME_` — - exactly the enum name. Reads `ChannelName.CHANNEL_NAME_PREVIEW` - ("channel name . channel name preview"). Worst form of the - category. -- **Suggestion:** Strip prefix on TS identifier; keep wire - strings: - ```ts - export enum ChannelName { - UNSPECIFIED = 'CHANNEL_NAME_UNSPECIFIED', - PREVIEW = 'CHANNEL_NAME_PREVIEW', - CURRENT = 'CHANNEL_NAME_CURRENT', - PREVIOUS = 'CHANNEL_NAME_PREVIOUS', - CUSTOM = 'CHANNEL_NAME_CUSTOM', - } - ``` - -#### F2.2 — `DefaultWarehouseOverrideType.DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED` (HIGH) -- **Where:** `model.ts:16-23`. - ```ts - DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED = '...', - LAST_SELECTED = 'LAST_SELECTED', - CUSTOM = 'CUSTOM', - ``` -- **Why flagged:** Only the unspecified member carries the - redundant prefix; the other members do not. Inconsistent - within the enum. -- **Suggestion:** Strip prefix on the unspecified member: - `UNSPECIFIED = 'DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED'`. - Wire string preserved. - -#### F2.3 — `EndpointSpotInstancePolicy.POLICY_UNSPECIFIED` (MEDIUM) -- **Where:** `model.ts:76`. -- **Why flagged:** `POLICY_` is redundant — the enum is - `EndpointSpotInstancePolicy`. The JSDoc explicitly explains - this choice as a compromise to "avoid customer-facing JSON … - `ENDPOINT_SPOT_INSTANCE_POLICY_UNSPECIFIED`". So `POLICY_` was - picked as a shorter prefix — but it is still partially - redundant. -- **Suggestion:** On the TS identifier, drop the `POLICY_` - prefix: `UNSPECIFIED = 'POLICY_UNSPECIFIED'`. Wire string - preserved. Other members are already prefix-free. - -#### F2.4 — `WarehouseType.TYPE_UNSPECIFIED` (MEDIUM) -- **Where:** `model.ts:703`. -- **Why flagged:** `TYPE_` prefix duplicates the type-noun in - the enum name (`WarehouseType`). Other members - (`CLASSIC`, `PRO`, `REYDEN`) carry no prefix — so inconsistent. -- **Suggestion:** Strip prefix on TS identifier: - `UNSPECIFIED = 'TYPE_UNSPECIFIED'`. Or rename wire to - `WAREHOUSE_TYPE_UNSPECIFIED` for symmetry, then strip on TS. - -#### F2.5 — `EndpointHealth_Status.STATUS_UNSPECIFIED` (MEDIUM) -- **Where:** `model.ts:715`. -- **Why flagged:** `STATUS_` prefix duplicates the type-noun. - Other members (`HEALTHY`, `DEGRADED`, `FAILED`) carry no - prefix. Inconsistent. -- **Suggestion:** `UNSPECIFIED = 'STATUS_UNSPECIFIED'`. - -#### F2.6 — No prefix on `TerminationCode` (~150 enum members) (acceptable) -- **Where:** `model.ts:103-687`. -- **Why flagged:** Members are domain-specific - (`USER_REQUEST`, `JOB_FINISHED`, `INACTIVITY`, - `CLOUD_PROVIDER_SHUTDOWN`, etc.) without a "TERMINATION_" - prefix. This is correct. -- **Suggestion:** No change. Good pattern; other enums should - follow. - -#### F2.7 — No prefix on `TerminationType` (acceptable) -- **Where:** `model.ts:690-699`. Members `SUCCESS`, - `CLIENT_ERROR`, `SERVICE_FAULT`, `CLOUD_FAILURE`. -- **Suggestion:** No change. - -#### F2.8 — No prefix on `EndpointState` (acceptable) -- **Where:** `model.ts:87-100`. -- **Suggestion:** No change. - -#### F2.9 — No prefix on `EndpointSecurityPolicy` (acceptable) -- **Where:** `model.ts:26-33`. Members `NONE`, - `DATA_ACCESS_CONTROL`, `PASSTHROUGH`. -- **Suggestion:** No change. +_None._ --- @@ -477,7 +397,7 @@ compatibility while updating the customer-visible type names. - **Suggestion:** No change. #### F3.2 — `SQL` rendered as `Sql` in `sqlConfigurationParameters` (LOW) -- **Where:** `model.ts:1281, 1370`. +- **Where:** `model.ts:1254, 1343`. - **Why flagged:** `sqlConfigurationParameters` uses lowercase `sql`. The SDK applies "first letter cap, rest lower" for TLAs in camelCase — but the field starts the identifier and @@ -488,7 +408,7 @@ compatibility while updating the customer-visible type names. - **Suggestion:** No change to identifier. SDK-wide pattern. #### F3.3 — `DBSQL` rendered as `Dbsql` in `dbsqlVersion` (LOW) -- **Where:** `model.ts:730`, `Channel.dbsqlVersion`. +- **Where:** `model.ts:703`, `Channel.dbsqlVersion`. - **Why flagged:** `DBSQL` is a Databricks-internal product name. Wire form is `dbsql_version` (all lowercase). TS form `dbsqlVersion` lowercases the whole acronym. Consistent with @@ -496,14 +416,14 @@ compatibility while updating the customer-visible type names. - **Suggestion:** Acceptable; consistent with adjacent fields. #### F3.4 — `JDBC` rendered as `jdbc` in `jdbcUrl` (acceptable) -- **Where:** `model.ts:1108, 1243`. Field `jdbcUrl`. +- **Where:** `model.ts:1081, 1216`. Field `jdbcUrl`. - **Why flagged:** Consistent with `http`, `url`. Lowercase acronyms in lower-camel. Note `Url` not `URL` (also lowercase TLA). Internally consistent. - **Suggestion:** No change. #### F3.5 — `ODBC` rendered in mixed forms (LOW) -- **Where:** `model.ts:1110, 1245, 1329`. Type `OdbcParams` +- **Where:** `model.ts:1083, 1218, 1302`. Type `OdbcParams` (Pascal case, "Odbc" mixed); field `odbcParams` (lower-camel "odbc"). - **Why flagged:** Type uses `Odbc` (first letter cap, rest @@ -515,7 +435,7 @@ compatibility while updating the customer-visible type names. `httpClient` pattern. Leave. #### F3.6 — `IAM` casing (acceptable, JSDoc only) -- **Where:** `model.ts:812, 956, 1074, 1209, 1267, 1356`. +- **Where:** `model.ts:785, 929, 1047, 1182, 1240, 1329`. - **Why flagged:** "IAM role" appears in JSDoc only; no identifier rendering. - **Suggestion:** No change. @@ -536,7 +456,7 @@ _None._ ### 5. Cryptic abbreviations #### F5.1 — `Mins` for minutes (`autoStopMins`) (LOW) -- **Where:** `model.ts:809, 953, 1071, 1206`. +- **Where:** `model.ts:782, 926, 1044, 1179`. - **Why flagged:** "Mins" is mildly informal. Compare to other duration fields in the SDK that use `Seconds`, `Hours`. JSDoc always spells out "minutes" in prose. @@ -544,7 +464,7 @@ _None._ `auto_stop_mins` for compatibility. #### F5.2 — `Conf` for configuration (`EndpointConfPair`, `configPair`, `dataAccessConfig`) (MEDIUM) -- **Where:** `model.ts:988, 1265, 1338, 1354`. +- **Where:** `model.ts:961, 1238, 1311, 1327`. - **Why flagged:** "Conf" is an abbreviation. Inconsistent within the package: `RepeatedEndpointConfPairs` has both `configPair` and `configurationPairs` (the latter is @@ -555,7 +475,7 @@ _None._ `configPair` → `configPairs` (also plural; see F9.x). #### F5.3 — `Param` for parameter (`globalParam`, `configParam`) (MEDIUM) -- **Where:** `model.ts:1277, 1279, 1366, 1368, 1724-1725, 1962-1967`. +- **Where:** `model.ts:1250, 1252, 1339, 1341, 1697-1698, 1935-1940`. - **Why flagged:** "Param" is a cryptic abbreviation when the full word "parameter" is also in use in this package (`sqlConfigurationParameters`, `TerminationReason.parameters`, @@ -566,7 +486,7 @@ _None._ so the rename can be paired with deprecation removal. #### F5.4 — `Num` for number (`numClusters`, `numActiveSessions`, `maxNumClusters`, `minNumClusters`) (LOW) -- **Where:** `model.ts:787, 798, 1049, 1060, 1102, 1104, 1184, 1195, 1237, 1239`. +- **Where:** `model.ts:760, 771, 1022, 1033, 1075, 1077, 1157, 1168, 1210, 1212`. - **Why flagged:** "Num" is a programmer-ism. SDK and other packages occasionally spell it out as `count` or `number`. - **Suggestion:** Acceptable; widely used across the API. Note @@ -576,7 +496,7 @@ _None._ takes priority. Leave. #### F5.5 — `Arn` for AWS Resource Name (`instanceProfileArn`) (acceptable) -- **Where:** `model.ts:813, 957, 1075, 1210, 1271, 1360`. +- **Where:** `model.ts:786, 930, 1048, 1183, 1244, 1333`. - **Why flagged:** `ARN` is a well-known AWS acronym. Casing matches `instanceProfileArn` (first letter cap, rest lower). No issue. @@ -602,7 +522,7 @@ _None._ ### 6. Misleading names #### F6.1 — `EndpointInfo` for a warehouse record (HIGH) -- **Where:** `model.ts:1006`. +- **Where:** `model.ts:979`. - Covered in F1.1 / F0. The most glaring example: a value of type `EndpointInfo` is a warehouse, not an endpoint. - **Suggestion:** Rename to `Warehouse` or `WarehouseInfo`. @@ -617,7 +537,7 @@ _None._ - Covered in F1.4 / F0. #### F6.5 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) -- **Where:** `model.ts:988, 1336`. Used inside +- **Where:** `model.ts:961, 1309`. Used inside `GetWorkspaceWarehouseConfigRequest_Response.dataAccessConfig` (workspace-scoped) and `globalParam` (also workspace-scoped). - **Why flagged:** Field name says "endpoint conf" but the @@ -634,14 +554,14 @@ _None._ - **Suggestion:** Rename to `ChannelType` or `WarehouseChannel`. #### F6.7 — `Channel.dbsqlVersion` as the override mechanism (LOW) -- **Where:** `model.ts:730`. +- **Where:** `model.ts:703`. - **Why flagged:** Field is required only when `name` is `CHANNEL_NAME_CUSTOM`. JSDoc on the parent says so. Name itself does not convey the conditional contract. - **Suggestion:** Add JSDoc; field name is fine. #### F6.8 — `instanceProfileArn` JSDoc says "Deprecated" but field remains (LOW) -- **Where:** `model.ts:812, 956, 1074, 1209`. +- **Where:** `model.ts:786, 930, 1048, 1183`. - **Why flagged:** Identifier carries no `_DEPRECATED` marker; only JSDoc. Customer code completion shows it as a normal field. @@ -649,20 +569,20 @@ _None._ prose) so IDEs strike it through. #### F6.9 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) -- **Where:** `model.ts:811, 955, 1073, 1208`. +- **Where:** `model.ts:784, 928, 1046, 1181`. - **Why flagged:** The field is settable on - `CreateWarehouse`/`EditWarehouseRequest`, but its meaning is - read-only on the server side ("creator" never changes after + `CreateWarehouseRequest`/`EditWarehouseRequest`, but its meaning + is read-only on the server side ("creator" never changes after create). Surfacing it as settable on `Edit` is misleading. - **Suggestion:** Spec-level. Mark read-only on response types only. #### F6.10 — `EndpointHealth.message` is "Deprecated" prose but no marker (LOW) -- **Where:** `model.ts:997`. +- **Where:** `model.ts:970`. - Same pattern as F6.8. #### F6.11 — Waiter `done` returns true on terminal failure states (MEDIUM) -- **Where:** `client.ts:684, 764, 844, 919` (the `done()` of +- **Where:** `client.ts:690, 770, 850, 925` (the `done()` of each Waiter). - **Why flagged:** `done()` returns `true` for `RUNNING`, `STOPPED`, `DELETED` indiscriminately. A caller who reads @@ -681,7 +601,7 @@ _None._ ### 7. Overly verbose #### F7.1 — `CreateDefaultWarehouseOverrideRequest`, `GetDefaultWarehouseOverrideRequest`, `UpdateDefaultWarehouseOverrideRequest`, `DeleteDefaultWarehouseOverrideRequest`, `ListDefaultWarehouseOverridesRequest`, `ListDefaultWarehouseOverridesResponse` (MEDIUM) -- **Where:** `model.ts:734, 1125, 1407, 874, 1300, 1319`. +- **Where:** `model.ts:707, 1098, 1380, 847, 1273, 1292`. - **Why flagged:** All AIP-style "DefaultWarehouseOverride" resources. The names are accurate but very long (39-48 characters). The matching client methods @@ -691,7 +611,7 @@ _None._ call site is the typical workaround. #### F7.2 — `defaultWarehouseOverrideFieldMask` (LOW) -- **Where:** `model.ts:2022`. +- **Where:** `model.ts:1995`. - **Why flagged:** Long, but consistent with the AIP-style resource name. Acceptable. @@ -701,9 +621,10 @@ _None._ #### F8.1 — `Request` suffix on every request interface (HIGH, generator-driven) - **Where:** `CreateDefaultWarehouseOverrideRequest`, + `CreateWarehouseRequest`, `DeleteDefaultWarehouseOverrideRequest`, `EditWarehouseRequest`, `GetDefaultWarehouseOverrideRequest`, - `GetWorkspaceWarehouseConfigRequest`, + `GetWarehouseRequest`, `GetWorkspaceWarehouseConfigRequest`, `ListDefaultWarehouseOverridesRequest`, `SetWorkspaceWarehouseConfigRequest`, `UpdateDefaultWarehouseOverrideRequest`, @@ -711,12 +632,13 @@ _None._ `StartRequest`, `StopRequest`. - **Why flagged:** Caller already supplies the request via the parameter type position — the `Request` suffix is a - belt-and-suspenders signal. Note the inconsistency: some types - drop the suffix entirely (`CreateWarehouse`, `GetWarehouse`), - others keep it. -- **Suggestion:** Standardize. `EditWarehouseRequest` should be - `EditWarehouse` for symmetry with `CreateWarehouse` / - `GetWarehouse`. Generator-level. + belt-and-suspenders signal. All request types now carry the + suffix consistently (the prior `CreateWarehouse` / `GetWarehouse` + without-suffix variants were renamed to `CreateWarehouseRequest` + / `GetWarehouseRequest`). The remaining concern is the + redundancy itself, not the consistency. +- **Suggestion:** Drop the `Request` suffix across the SDK at + the generator level. Generator-level. #### F8.2 — `Name` suffix on `ChannelName` enum (MEDIUM) - **Where:** `model.ts:7`. @@ -729,7 +651,7 @@ _None._ intent — Custom vs. Preview is the *type* of channel). #### F8.3 — `Pair` suffix on `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair` (MEDIUM) -- **Where:** `model.ts:1115, 988, 1434`. +- **Where:** `model.ts:1088, 961, 1407`. - **Why flagged:** "Pair" is a generic suffix that adds little information when the type's two fields are obvious. For `EndpointTagPair` (`key`, `value`), the suffix duplicates the @@ -740,7 +662,7 @@ _None._ semantically clearer than the `Pair` suffix. #### F8.4 — `Params` suffix on `OdbcParams` (LOW) -- **Where:** `model.ts:1329`. +- **Where:** `model.ts:1302`. - **Why flagged:** Mild noise. Type has `hostname`, `path`, `protocol`, `port` — `OdbcConnectionInfo` would be more accurate. @@ -752,7 +674,7 @@ _None._ ### 9. Singular / plural mismatches #### F9.1 — `RepeatedEndpointConfPairs.configPair` is plural-content singular-name (HIGH) -- **Where:** `model.ts:1338`. +- **Where:** `model.ts:1311`. - **Why flagged:** Field type is `EndpointConfPair[]` (array) but field name is singular `configPair`. The wire form is `config_pair`. Compare to sibling `configurationPairs` (same @@ -761,7 +683,7 @@ _None._ `config_pair` if deprecated, or rename wire to `config_pairs`. #### F9.2 — `TerminationReason.parameters` is a map, not a list (LOW) -- **Where:** `model.ts:1397`. Type `Record`. +- **Where:** `model.ts:1370`. Type `Record`. - **Why flagged:** `parameters` is plural but typed as a map. Plural maps are fine but inconsistent — compare to `globalParam` / `configParam` which are singular. @@ -769,7 +691,7 @@ _None._ type. Plural is correct. #### F9.3 — `globalParam`, `configParam` are singular names for list-valued fields (MEDIUM) -- **Where:** `model.ts:1277, 1279, 1366, 1368`. +- **Where:** `model.ts:1250, 1252, 1339, 1341`. - **Why flagged:** Both fields are of type `RepeatedEndpointConfPairs` — a list. Singular name on a list-valued field is misleading. Compare to @@ -778,28 +700,28 @@ _None._ (also pair with the `Param`/`Parameter` expansion in F5.3). #### F9.4 — `enabledWarehouseTypes` plural array (acceptable) -- **Where:** `model.ts:1296, 1385`. +- **Where:** `model.ts:1269, 1358`. - **Why flagged:** Plural name + array type. Correct. - **Suggestion:** No change. #### F9.5 — `defaultWarehouseOverrides` plural array (acceptable) -- **Where:** `model.ts:1321`. +- **Where:** `model.ts:1294`. - **Why flagged:** Correct. - **Suggestion:** No change. #### F9.6 — `warehouses` plural array (acceptable) -- **Where:** `model.ts:1482`. Correct. +- **Where:** `model.ts:1455`. Correct. #### F9.7 — `customTags` plural array (acceptable) -- **Where:** `model.ts:1121`. Correct. +- **Where:** `model.ts:1094`. Correct. --- ### 10. Reserved-word collisions #### F10.1 — `type` field (LOW) -- **Where:** `DefaultWarehouseOverride.type` (`model.ts:865`), - `TerminationReason.type` (`model.ts:1395`). +- **Where:** `DefaultWarehouseOverride.type` (`model.ts:838`), + `TerminationReason.type` (`model.ts:1368`). - **Why flagged:** `type` is a TS keyword in certain positions (the `type` modifier in type imports), but valid as a property name. No actual collision. Some linters warn. @@ -825,27 +747,27 @@ _None. Wrappers are retained for forward compatibility._ ### 12. Duplicate concepts / historical baggage -#### F12.1 — `EndpointInfo` and `GetWarehouse_Response` are the same record (HIGH) -- **Where:** `model.ts:1006` and `model.ts:1141`. +#### F12.1 — `EndpointInfo` and `GetWarehouseRequest_Response` are the same record (HIGH) +- **Where:** `model.ts:979` and `model.ts:1114`. - **Why flagged:** Both types have identical field sets (~20 identical fields). One is the per-warehouse record in `listWarehouses`, the other is the result of `getWarehouse`. Duplicating the shape across two types means every change has to happen in two places. - **Suggestion:** Collapse into one type (call it `Warehouse`). - `GetWarehouse_Response = Warehouse`. `EndpointInfo` removed. + `GetWarehouseRequest_Response = Warehouse`. `EndpointInfo` removed. Generator-level. -#### F12.2 — `CreateWarehouse` and `EditWarehouseRequest` are nearly identical (HIGH) -- **Where:** `model.ts:746` and `model.ts:888`. -- **Why flagged:** `EditWarehouseRequest` is `CreateWarehouse + - id`. All other fields identical. Duplicating the shape. +#### F12.2 — `CreateWarehouseRequest` and `EditWarehouseRequest` are nearly identical (HIGH) +- **Where:** `model.ts:719` and `model.ts:861`. +- **Why flagged:** `EditWarehouseRequest` is `CreateWarehouseRequest + + id`. All other fields identical. Duplicating the shape. - **Suggestion:** Have `EditWarehouseRequest` extend - `CreateWarehouse` with `id` added. Reduces drift. + `CreateWarehouseRequest` with `id` added. Reduces drift. #### F12.3 — `SetWorkspaceWarehouseConfigRequest` and `GetWorkspaceWarehouseConfigRequest_Response` are identical (HIGH) -- **Where:** `model.ts:1347` and `model.ts:1258`. +- **Where:** `model.ts:1320` and `model.ts:1231`. - **Why flagged:** Same field set on both. Same legacy `globalParam`, `configParam` deprecated pair on both. - **Suggestion:** Generate as `WorkspaceWarehouseConfig` type @@ -857,31 +779,31 @@ _None. Wrappers are retained for forward compatibility._ baggage from the rename of "SQL Endpoints" to "SQL Warehouses". #### F12.5 — `numActiveSessions` deprecated field still on response types (LOW) -- **Where:** `model.ts:1104, 1239`. +- **Where:** `model.ts:1077, 1212`. - **Why flagged:** JSDoc says "Deprecated. current number of active sessions for the warehouse". Carries no `@deprecated` tag. - **Suggestion:** Add `@deprecated`. Schedule for removal. #### F12.6 — `EndpointHealth.message` deprecated (LOW) -- **Where:** `model.ts:997`. Same pattern. +- **Where:** `model.ts:970`. Same pattern. #### F12.7 — `instanceProfileArn` deprecated (LOW) -- **Where:** `model.ts:813, 957, 1075, 1210`. Same. +- **Where:** `model.ts:786, 930, 1048, 1183`. Same. #### F12.8 — `globalParam`, `configParam` deprecated in favor of `sqlConfigurationParameters` (LOW) -- **Where:** `model.ts:1277, 1279, 1366, 1368`. Same. +- **Where:** `model.ts:1250, 1252, 1339, 1341`. Same. #### F12.9 — `ListWarehousesRequest.runAsUserId` deprecated and ignored (LOW) -- **Where:** `model.ts:1465`. JSDoc says "Deprecated: this field +- **Where:** `model.ts:1438`. JSDoc says "Deprecated: this field is ignored by the server." - **Suggestion:** Add `@deprecated` and consider removal. #### F12.10 — Workspace config endpoint duplicates per-warehouse fields (MEDIUM) - **Where:** `instanceProfileArn`, `channel`, `enableServerlessCompute` all appear in both per-warehouse - (`CreateWarehouse`) and workspace + (`CreateWarehouseRequest`) and workspace (`SetWorkspaceWarehouseConfigRequest`) types. - **Why flagged:** The same field name maps to two different conceptual levels (per-warehouse override vs. workspace @@ -918,7 +840,7 @@ _None. Wrappers are retained for forward compatibility._ - **Suggestion:** Generator-level. #### F14.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) -- **Where:** `client.ts:405, 462`, `utils.ts:48`. +- **Where:** `client.ts:411, 468`, `utils.ts:48`. - **Why flagged:** `for (;;)` is C/Go idiom; TS prefers `while (true)` for readability. Minor. - **Suggestion:** Generator-level. @@ -929,7 +851,7 @@ _None. Wrappers are retained for forward compatibility._ #### F15.1 — `name` overloaded with three meanings (HIGH) - **Where:** `Channel.name` (channel selector enum value), - `CreateWarehouse.name` (human display name), + `CreateWarehouseRequest.name` (human display name), `DefaultWarehouseOverride.name` (path identifier). - **Why flagged:** Three completely different concepts share the field name `name`. @@ -937,26 +859,26 @@ _None. Wrappers are retained for forward compatibility._ `DefaultWarehouseOverride.name` → `resourceName`. Rename `Channel.name` → `channelType` (also F8.2). -#### F15.2 — `state` field on `EndpointInfo` / `GetWarehouse_Response` (LOW) -- **Where:** `model.ts:1106, 1241`. +#### F15.2 — `state` field on `EndpointInfo` / `GetWarehouseRequest_Response` (LOW) +- **Where:** `model.ts:1079, 1214`. - **Why flagged:** Disambiguated by type (`EndpointState`), but `warehouseState` would be clearer in isolation. - **Suggestion:** Leave. #### F15.3 — `status` field on `EndpointHealth` (LOW) -- **Where:** `model.ts:995`. Type `EndpointHealth_Status`. +- **Where:** `model.ts:968`. Type `EndpointHealth_Status`. - **Why flagged:** Reads "endpoint health . status . endpoint health status". Three layers of "status". - **Suggestion:** Acceptable given typing. #### F15.4 — `enabled` field on `WarehouseTypePair` (LOW) -- **Where:** `model.ts:1440`. +- **Where:** `model.ts:1413`. - **Why flagged:** Generic, but disambiguated by container. - **Suggestion:** Leave. #### F15.5 — `summary` field on `EndpointHealth` (LOW) -- **Where:** `model.ts:1001`. +- **Where:** `model.ts:974`. - **Why flagged:** Generic. JSDoc says "short summary of the health status". Could be `summaryMessage` or `healthSummary`, but field is rarely used in isolation. @@ -971,13 +893,13 @@ _None. Wrappers are retained for forward compatibility._ types. #### F15.7 — `code`, `type`, `parameters` on `TerminationReason` (LOW) -- **Where:** `model.ts:1393, 1395, 1397`. +- **Where:** `model.ts:1366, 1368, 1370`. - **Why flagged:** All three are generic words. Disambiguated by container. - **Suggestion:** Leave. #### F15.8 — `host`, `path`, `protocol`, `port` on `OdbcParams` (LOW) -- **Where:** `model.ts:1330-1333`. +- **Where:** `model.ts:1303-1306`. - **Why flagged:** Generic connection-string fields. Standard. - **Suggestion:** Leave. @@ -986,12 +908,12 @@ _None. Wrappers are retained for forward compatibility._ ### 16. Field contradicting type domain #### F16.1 — `cluster*` fields on warehouse types (HIGH) -- **Where:** `CreateWarehouse.clusterSize` (`model.ts:773`), - `minNumClusters` (`model.ts:787`), `maxNumClusters` - (`model.ts:798`), `numClusters` (`model.ts:1102`); same on +- **Where:** `CreateWarehouseRequest.clusterSize` (`model.ts:746`), + `minNumClusters` (`model.ts:760`), `maxNumClusters` + (`model.ts:771`), `numClusters` (`model.ts:1075`); same on `EditWarehouseRequest`, `EndpointInfo`, - `GetWarehouse_Response`. JSDoc: "Logical name for the - cluster" (`model.ts:748`). + `GetWarehouseRequest_Response`. JSDoc: "Logical name for the + cluster" (`model.ts:721`). - **Why flagged:** A SQL Warehouse exposes "cluster" terminology internally because the warehouse is implemented atop Spark clusters. To the customer, this is "warehouse size", @@ -1006,7 +928,7 @@ _None. Wrappers are retained for forward compatibility._ a JSDoc note. Flag for future spec consideration. #### F16.2 — `creatorName` references the cluster (LOW) -- **Where:** `model.ts:810, 954, 1072, 1207`. +- **Where:** `model.ts:784, 928, 1046, 1181`. - **Why flagged:** JSDoc says "warehouse creator name"; field name `creatorName` doesn't conflict but doesn't say what resource is being created either. @@ -1025,8 +947,8 @@ _None. Wrappers are retained for forward compatibility._ ### 17. Inconsistent action verbs #### F17.1 — `Edit` vs. `Update` (HIGH) -- **Where:** `editWarehouse` (`client.ts:239`) vs. - `updateDefaultWarehouseOverride` (`client.ts:584`). Same +- **Where:** `editWarehouse` (`client.ts:242`) vs. + `updateDefaultWarehouseOverride` (`client.ts:590`). Same package, two different "modify resource" verbs. - **Why flagged:** Warehouses use `edit`; default warehouse overrides use `update`. CRUD-style APIs across the SDK use @@ -1046,7 +968,7 @@ _None. Wrappers are retained for forward compatibility._ - **Suggestion:** No change. #### F17.3 — `Set` (`setWorkspaceWarehouseConfig`) vs. `Update` (LOW) -- **Where:** `client.ts:475`. +- **Where:** `client.ts:481`. - **Why flagged:** `set` semantically means "replace entire resource"; `update` means "patch fields". Both apply here. `setWorkspaceWarehouseConfig` uses PUT (full replace) — @@ -1067,9 +989,9 @@ _None._ ### 19. Underspecified IDs -#### F19.1 — `id` on `CreateWarehouse_Response`, `EndpointInfo`, -`GetWarehouse_Response`, `DeleteWarehouseRequest`, -`EditWarehouseRequest`, `GetWarehouse`, `StartRequest`, +#### F19.1 — `id` on `CreateWarehouseRequest_Response`, `EndpointInfo`, +`GetWarehouseRequest_Response`, `DeleteWarehouseRequest`, +`EditWarehouseRequest`, `GetWarehouseRequest`, `StartRequest`, `StopRequest` (MEDIUM) - **Where:** Many places. Caller writes `client.startWarehouse({id: '...'})` — but `id` here is the @@ -1083,7 +1005,7 @@ _None._ #### F19.2 — `defaultWarehouseOverrideId` vs. `warehouseId` on `DefaultWarehouseOverride` (LOW) -- **Where:** `model.ts:863, 870`. +- **Where:** `model.ts:836, 843`. - **Why flagged:** Two ID fields on one type: `defaultWarehouseOverrideId` (the override's own ID) and `warehouseId` (the warehouse referenced *by* the override). @@ -1092,7 +1014,7 @@ _None._ #### F19.3 — `name` is functionally an ID on `DefaultWarehouseOverride` (HIGH) -- **Where:** `model.ts:861`. Path form `default-warehouse-overrides/{id}`. +- **Where:** `model.ts:834`. Path form `default-warehouse-overrides/{id}`. - **Why flagged:** AIP-style "resource name" as a string — conventional in Google APIs but unconventional in TS. Customer sees `{name: 'default-warehouse-overrides/123'}` and @@ -1103,19 +1025,19 @@ _None._ wire, rename TS. #### F19.4 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) -- **Where:** `model.ts:1465`. Already deprecated. Numeric (`number`), +- **Where:** `model.ts:1438`. Already deprecated. Numeric (`number`), not string — unusual; most IDs in the SDK are string. - **Suggestion:** Already deprecated. Leave. #### F19.5 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) -- **Where:** `model.ts:1326`. Standard pagination identifier. +- **Where:** `model.ts:1299`. Standard pagination identifier. --- ### 20. Type-suffix tautology #### F20.1 — `Channel.name: ChannelName` (HIGH) -- **Where:** `model.ts:728-729`. +- **Where:** `model.ts:701-704`. ```ts export interface Channel { name?: ChannelName | undefined; @@ -1130,14 +1052,14 @@ _None._ to `type`. See F6.6 / F8.2. #### F20.2 — `EndpointHealth.status: EndpointHealth_Status` (LOW) -- **Where:** `model.ts:995`. +- **Where:** `model.ts:968`. - **Why flagged:** Field name `status` + enum suffix `Status` + interface "Health Status" namespace. Disambiguated by typing. - **Suggestion:** Acceptable; standard pattern. #### F20.3 — `WarehouseTypePair.warehouseType: WarehouseType` (HIGH) -- **Where:** `model.ts:1434-1440`. +- **Where:** `model.ts:1407-1413`. ```ts export interface WarehouseTypePair { warehouseType?: WarehouseType | undefined; @@ -1151,15 +1073,15 @@ _None._ `Type`). E.g. `WarehouseTypeAvailability { type, enabled }`. #### F20.4 — `TerminationReason.code: TerminationCode` (LOW) -- **Where:** `model.ts:1393`. Field `code` + enum suffix `Code` +- **Where:** `model.ts:1366`. Field `code` + enum suffix `Code` on `TerminationCode`. Generic field name with specific enum — acceptable per F1.12. #### F20.5 — `TerminationReason.type: TerminationType` (LOW) -- **Where:** `model.ts:1395`. Same pattern. Acceptable. +- **Where:** `model.ts:1368`. Same pattern. Acceptable. #### F20.6 — `DefaultWarehouseOverride.type: DefaultWarehouseOverrideType` (LOW) -- **Where:** `model.ts:865`. +- **Where:** `model.ts:838`. - **Why flagged:** Field `type` typed as `DefaultWarehouseOverrideType`. Container type already says "DefaultWarehouseOverride", so the field's type duplicates @@ -1177,12 +1099,9 @@ _None._ fix; cleans up ~10 type names across the package. 2. **Resolve `Edit` vs. `Update` (F17.1)** — pick one verb for "modify resource" across the SDK; standardize wire and TS. -3. **Strip redundant enum prefixes (F2.1, F2.2, F2.3, F2.4, - F2.5)** — `ChannelName.CHANNEL_NAME_PREVIEW` etc. Trivial - generator-level fix; massive readability win. -4. **Collapse duplicate types (F12.1, F12.2, F12.3)** — - `EndpointInfo` + `GetWarehouse_Response`, - `CreateWarehouse` + `EditWarehouseRequest`, +3. **Collapse duplicate types (F12.1, F12.2, F12.3)** — + `EndpointInfo` + `GetWarehouseRequest_Response`, + `CreateWarehouseRequest` + `EditWarehouseRequest`, `Set*Config` + `Get*Config_Response`. ### Recurring themes @@ -1194,9 +1113,13 @@ _None._ It causes the most readability harm because the package brand is "warehouse" while half the types still say "endpoint". HIGH severity; spec-level rename. -- **Duplicate enum prefixes** are pervasive but easily fixable - generator-side. - **Two unrelated resource families** (warehouses + default-warehouse-overrides) coexist in one package, with different REST base paths and different API conventions. Splitting could simplify. + +--- + +## Fixed + +- #F8.1-sub `CreateWarehouse` / `GetWarehouse` lacking `Request` suffix (originally cited at `model.ts:746, model.ts:1141`): Fixed in regeneration on 2026-05-20 — the user added `Request` to those types so all request DTOs now carry the suffix consistently; only the broader "drop the Request suffix entirely" recommendation remains in F8.1. diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md index a3c149c6..929ed483 100644 --- a/.agent/naming-audit/workspace.md +++ b/.agent/naming-audit/workspace.md @@ -1,104 +1,63 @@ # Naming Audit: workspace -**Path:** `packages/workspace/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/workspaceobjects/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks workspace filesystem-style operations on notebooks, folders, and files: import, export, delete, list, get-status, and mkdirs against absolute paths under `/Workspace`. -**Total weird names flagged:** 31 +**Total weird names flagged:** 27 -## Scope note: `workspace` vs sibling packages +## Scope note: `workspaceobjects` vs sibling packages -The Databricks SDK ships five packages whose names begin with "workspace". This audit covers only the first one; the others differ in scope: +The Databricks SDK ships several packages whose names begin with "workspace". This audit covers the filesystem-style operations package, now `workspaceobjects`; the others differ in scope: | Package | Domain | Wire prefix | |---------|--------|-------------| -| `workspace` (this audit) | Workspace filesystem (notebooks/folders/files) | `/api/2.0/workspace/` | +| `workspaceobjects` (this audit) | Workspace filesystem (notebooks/folders/files) | `/api/2.0/workspace/` | | `workspaceassignment` | Account-level principal-to-workspace permission assignments | account API | | `workspacebindings` | Securable-to-workspace bindings (catalog/credential/location) | Unity Catalog API | | `workspaceconf` | Untyped key/value workspace configuration | `/api/2.0/workspace-conf` | | `workspacesettings` | Strongly-typed workspace settings (compliance security profile, automatic cluster update, etc.) | various `/api/2.0/settings/*` | -The package name `workspace` is the most overloaded of the five — every Databricks API operates "in a workspace," so a package literally called `workspace` provides almost no scope signal. A name like `workspacefiles`, `workspacefs`, or `workspacenotebooks` would convey that this is the filesystem-style API and would not collide conceptually with the other four "workspace*" packages. See finding 1. - ## Summary table | # | Severity | Location | Name | Category | |---|----------|----------|------|----------| -| 1 | High | package | `workspace` | Vague/generic package name (overloaded across 5+ "workspace*" packages) | -| 2 | High | `model.ts` interface | `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` | Verb-as-type, reserved-word collisions | -| 3 | High | `model.ts` enum | `ExportFormat` used as the `format` field of `Import` | Misleading name (an "ExportFormat" governs imports too) | -| 4 | High | `model.ts` enum value | `ExportFormat.AUTO` | Misleading enum value (server inspects content) | -| 5 | High | `model.ts` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | -| 6 | High | `model.ts` enum value | `ObjectType.OBJECT_TYPE_UNSPECIFIED` | Redundant enum prefix + proto sentinel leak | -| 7 | High | `model.ts` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | -| 8 | High | `model.ts` enum | `Language` | Vague/generic, no domain prefix | -| 9 | Medium | `model.ts` enum value | `ObjectType.LIBRARY` | Misleading (library notebooks are an obsolete concept; deprecated in product) | -| 10 | Medium | `model.ts` field | `List.notebooksModifiedAfter` | Field contradicts type domain (list of all objects, filter only on notebooks) | -| 11 | Medium | `model.ts` field | `Export.directDownload` | Verb-as-noun field + boolean named like a noun | -| 12 | Medium | `model.ts` field | `Export_Response.fileType` | Underspecified (raw extension? MIME type? format enum?) | -| 13 | Medium | `model.ts` field | `Export_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | -| 14 | Medium | `model.ts` field | `Import.content` typed `Uint8Array` | Same type/JSDoc mismatch as 13 in the reverse direction | -| 15 | Medium | `model.ts` field | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Underspecified time fields (mtime/ctime? wall clock?) and unit ambiguity (epoch millis as number) | -| 16 | Medium | `model.ts` field | `ObjectInfo.size` | Underspecified (file size in bytes per JSDoc, but no unit in the name) | -| 17 | Medium | `model.ts` field | `Mkdirs.path` | Singular/plural mismatch — type name plural (`Mkdirs`), field singular (`path`) | -| 18 | Medium | `model.ts` type | `Mkdirs` | Cryptic abbreviation (Unix-ism, "mkdirs" not "createDirectory") | -| 19 | Medium | `model.ts` enum value | `Language.R` | Single-letter identifier (clashes with `package R Markdown`) | -| 20 | Medium | `model.ts` enum value | `Language.SCALA`, `PYTHON`, `SQL`, `R` | Missing `LANGUAGE_` prefix elsewhere, raw values overlap with cluster/job runtime names | -| 21 | Medium | `client.ts` method | `getStatus` | Vague verb (status of what?), inconsistent with `list`/`export` | -| 22 | Medium | `model.ts` interface | `GetStatus` | Verb-as-type with no `Request` suffix (whole SDK is inconsistent on this) | -| 23 | Medium | `model.ts` field | `Delete.recursive` | Underspecified boolean (verbatim Unix flag, no domain reading) | -| 24 | Low | `model.ts` enum value | `ExportFormat.R_MARKDOWN` | Underscore inside enum value matches wire, but mixes shape with `JUPYTER`/`HTML` (single tokens) | -| 25 | Low | `model.ts` enum value | `ExportFormat.DBC` | Cryptic abbreviation (Databricks archive) | -| 26 | Low | `model.ts` enum | `ExportOutputs` | Singular/plural — type is `Outputs` (plural), field on `Export` is also `outputs`, values `ALL`/`NONE` describe whether outputs are included | -| 27 | Low | `model.ts` field | `Export.outputs` typed `ExportOutputs` | Field name == type-suffix tautology | -| 28 | Low | `model.ts` interface | `ObjectInfo` | Generic name ("info" suffix used inconsistently across SDK) | -| 29 | Low | `model.ts` field | `List_Response.objects` | Generic field (`objects`) for `ObjectInfo[]` | -| 30 | Low | `client.ts` method | `mkdirs` | Verb-tense / casing inconsistency vs `createDirectory` analog elsewhere in SDK | -| 31 | Low | docstrings | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | +| 1 | High | `model.ts` enum | `ExportFormat` used as the `format` field of `ImportRequest` | Misleading name (an "ExportFormat" governs imports too) | +| 2 | High | `model.ts` enum value | `ExportFormat.AUTO` | Misleading enum value (server inspects content) | +| 3 | High | `model.ts` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | +| 4 | High | `model.ts` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | +| 5 | High | `model.ts` enum | `Language` | Vague/generic, no domain prefix | +| 6 | Medium | `model.ts` enum value | `ObjectType.LIBRARY` | Misleading (library notebooks are an obsolete concept; deprecated in product) | +| 7 | Medium | `model.ts` field | `ListRequest.notebooksModifiedAfter` | Field contradicts type domain (list of all objects, filter only on notebooks) | +| 8 | Medium | `model.ts` field | `ExportRequest.directDownload` | Verb-as-noun field + boolean named like a noun | +| 9 | Medium | `model.ts` field | `ExportRequest_Response.fileType` | Underspecified (raw extension? MIME type? format enum?) | +| 10 | Medium | `model.ts` field | `ExportRequest_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | +| 11 | Medium | `model.ts` field | `ImportRequest.content` typed `Uint8Array` | Same type/JSDoc mismatch as 10 in the reverse direction | +| 12 | Medium | `model.ts` field | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Underspecified time fields (mtime/ctime? wall clock?) and unit ambiguity (epoch millis as number) | +| 13 | Medium | `model.ts` field | `ObjectInfo.size` | Underspecified (file size in bytes per JSDoc, but no unit in the name) | +| 14 | Medium | `model.ts` field | `MkdirsRequest.path` | Singular/plural mismatch — type name plural (`Mkdirs`), field singular (`path`) | +| 15 | Medium | `model.ts` type | `MkdirsRequest` | Cryptic abbreviation (Unix-ism, "mkdirs" not "createDirectory") | +| 16 | Medium | `model.ts` enum value | `Language.R` | Single-letter identifier (clashes with `package R Markdown`) | +| 17 | Medium | `client.ts` method | `getStatus` | Vague verb (status of what?), inconsistent with `list`/`export` | +| 18 | Medium | `model.ts` field | `DeleteRequest.recursive` | Underspecified boolean (verbatim Unix flag, no domain reading) | +| 19 | Low | `model.ts` enum value | `ExportFormat.R_MARKDOWN` | Underscore inside enum value matches wire, but mixes shape with `JUPYTER`/`HTML` (single tokens) | +| 20 | Low | `model.ts` enum value | `ExportFormat.DBC` | Cryptic abbreviation (Databricks archive) | +| 21 | Low | `model.ts` interface | `ObjectInfo` | Generic name ("info" suffix used inconsistently across SDK) | +| 22 | Low | `model.ts` field | `ListRequest_Response.objects` | Generic field (`objects`) for `ObjectInfo[]` | +| 23 | Low | `client.ts` method | `mkdirs` | Verb-tense / casing inconsistency vs `createDirectory` analog elsewhere in SDK | +| 24 | Low | docstrings | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | +| 25 | High | `model.ts` types | `DeleteRequest_Response`, `ExportRequest_Response`, `ImportRequest_Response`, `ListRequest_Response`, `MkdirsRequest_Response` | Proto-architectural-leak (`_Response` infix encodes proto nested-message name) | +| 26 | High | `model.ts` schema constants | `unmarshalDeleteRequest_ResponseSchema`, `unmarshalExportRequest_ResponseSchema`, `unmarshalImportRequest_ResponseSchema`, `unmarshalListRequest_ResponseSchema`, `unmarshalMkdirsRequest_ResponseSchema` | Proto-architectural-leak (schema const names carry the proto nested-message infix into the public schema identifiers) | +| 27 | Observation | source files | `// Proto-style nested message name.` eslint-disable comments at `model.ts:69,96,146,156,170,202,206,221,225,235` and `index.ts` re-exports | Proto-architectural-leak surfacing: the lint-rule suppressions name "Proto" directly in source, confirming the leak is structural, not incidental | ## High severity -### 1. `workspace` — vague/generic package name (overloaded) - -**Location:** `package.json` → `@databricks/sdk-workspace` - -The package is named after a noun every Databricks user already associates with "the whole product." Five other npm packages also start with `workspace`. Without reading `client.ts`, nothing in the name tells a TS consumer that this package's scope is "files and folders under `/Workspace` in the workspace tree." The wire URL prefix `/api/2.0/workspace/` is the only clue. - -A name that conveys scope: +### 1. `ExportFormat` reused for `ImportRequest.format` — misleading enum -- `workspacefiles` — already exists conceptually (there is a separate `files` package for `/Files/`); but matches the canonical product wording "Workspace Files." -- `workspacefs` — matches the filesystem metaphor of `list`/`mkdirs`/`getStatus`. -- `workspacenotebooks` — narrowest, but `Import`/`Export` also handle files and DBC archives, so this would undersell. - -Cross-package collision: a user typing `import { ... } from '@databricks/sdk-workspace/v1'` gets `Client`, but so does every other "workspace*" package. The TS class is also called `Client` (see finding 24 in the SDK-wide patterns). - -### 2. `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` — verb-as-type & reserved-word collisions - -**Location:** `model.ts:65`, `:79`, `:121`, `:126`, `:163`, `:176` - -```ts -export interface Delete { ... } -export interface Export { ... } -export interface GetStatus { ... } -export interface Import { ... } -export interface List { ... } -export interface Mkdirs { ... } -``` - -Three of these are JavaScript reserved or contextually reserved words: - -- `Delete` shadows the `delete` operator (case-different but visually confusing). -- `Export` and `Import` collide with ES module syntax; the file already does `import type { Import } from './model'` which reads as a syntax error at a glance. -- `List` shadows `Array`/`List` from common stdlib vocabulary. -- `Mkdirs` is a Unix verb fragment. -- `GetStatus` is verb+noun. - -Every other request type in the SDK follows the pattern `Request` (e.g. `CreateAlertRequest`, `DeleteCatalogRequest`). This package omits both the `Request` suffix and the noun. The interfaces are also bare verbs, which makes type signatures like `async delete(req: Delete)` unreadable — at the call site you cannot tell whether `Delete` is the request type, the response type, the verb, or a builtin. - -Idiomatic TS would be `DeleteRequest` / `DeleteWorkspaceObjectRequest` (matching the rest of the SDK), or shorter: `DeleteRequest` / `ExportRequest` / `ImportRequest` / `ListRequest` / `MkdirsRequest` / `GetStatusRequest`. The current names are 1:1 with the Go SDK's `workspace.Delete`/`workspace.Export` Go struct names — in Go, package-prefixing makes `workspace.Delete` unambiguous; in TS, after `import {Delete} from '@databricks/sdk-workspace/v1'`, the prefix is gone. - -### 3. `ExportFormat` reused for `Import.format` — misleading enum - -**Location:** `model.ts:6-25`; used as `Import.format` at `:143` +**Location:** `model.ts:5-25`; used as `ImportRequest.format` at `:129` ```ts export enum ExportFormat { @@ -107,18 +66,18 @@ export enum ExportFormat { ... } -export interface Import { +export interface ImportRequest { ... format?: ExportFormat | undefined; ... } ``` -The enum is named `ExportFormat` but is used as the format for both `Import.format` and `Export.format`. The Go SDK's name (`ExportFormat`) leaks here. A neutral name like `WorkspaceObjectFormat` or `NotebookFormat` would describe both directions. The JSDoc on `Import.format` even lists the values (SOURCE, HTML, JUPYTER, DBC, R_MARKDOWN) as if they were import-specific, while the enum description says "for workspace import and export." +The enum is named `ExportFormat` but is used as the format for both `ImportRequest.format` and `ExportRequest.format`. The Go SDK's name (`ExportFormat`) leaks here. A neutral name like `WorkspaceObjectFormat` or `NotebookFormat` would describe both directions. The JSDoc on `ImportRequest.format` even lists the values (SOURCE, HTML, JUPYTER, DBC, R_MARKDOWN) as if they were import-specific, while the enum description says "for workspace import and export." -There is also a subtle asymmetry: `Import.format` documents AUTO as "depending on extension," `Export.format` documents AUTO as "depending on object type." Same enum value, different server behaviour per direction. +There is also a subtle asymmetry: `ImportRequest.format` documents AUTO as "depending on extension," `ExportRequest.format` documents AUTO as "depending on object type." Same enum value, different server behaviour per direction. -### 4. `ExportFormat.AUTO` — misleading enum value +### 2. `ExportFormat.AUTO` — misleading enum value **Location:** `model.ts:17-18` @@ -129,7 +88,7 @@ AUTO = 'AUTO', `AUTO` reads as "automatic file selection," but the value means "server inspects payload bytes to guess the file type." For an export request, "AUTO" means "decide based on the object's type." The single token serves two different inferred behaviors. `DETECT_FROM_CONTENT` / `DETECT_FROM_OBJECT` (split into two enums) would be honest. -### 5. `ExportFormat.RAW` — vague enum value +### 3. `ExportFormat.RAW` — vague enum value **Location:** `model.ts:19-24` @@ -146,30 +105,9 @@ RAW = 'RAW', `ZIP_PASSTHROUGH` or `BINARY` would describe the actual data path. Right now a reader sees `ExportFormat.RAW` and has to read three lines of JSDoc to understand it. -### 6. `ObjectType.OBJECT_TYPE_UNSPECIFIED` — redundant enum prefix + proto sentinel leak - -**Location:** `model.ts:48-52` - -```ts -export enum ObjectType { - /** - * As of 2023-10 this is used only by list-repo API so that repos can gracefully handle errors - * for unsupported types. - */ - OBJECT_TYPE_UNSPECIFIED = 'OBJECT_TYPE_UNSPECIFIED', - NOTEBOOK = 'NOTEBOOK', - ... -} -``` - -Two problems in one value: +### 4. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names -1. Enum prefix repetition: the enum is `ObjectType`, the value is `OBJECT_TYPE_UNSPECIFIED`. Every value would be readable as `ObjectType.NOTEBOOK` — the others (good) drop the prefix; this one (bad) retains it. The proto-style `_UNSPECIFIED` is documented as a proto convention, not a TS one. -2. Proto sentinel leak: the JSDoc explicitly says this value is only used by `list-repo` for graceful unsupported-type handling. It is a server implementation detail. A TS consumer constructing an `ObjectInfo` should never set this. Like `Aggregation.UNKNOWN` and similar leaks elsewhere, this is the proto default-value mechanism surfacing into the SDK. - -### 7. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names - -**Location:** `model.ts:209-214` +**Location:** `model.ts:194-199` ```ts /** Unique identifier for the object. */ @@ -185,9 +123,9 @@ Likely truth: `objectId` is the legacy 64-bit workspace-local numeric ID; `resou Also, `objectId` is typed `number` — JavaScript numbers are 64-bit float; if the server ID exceeds 2^53, precision is lost. Other SDK types use `bigint` or string for similar IDs. -### 8. `Language` — vague/generic, no domain prefix +### 5. `Language` — vague/generic, no domain prefix -**Location:** `model.ts:35-44` +**Location:** `model.ts:27-37` ```ts /** The language of notebook. */ @@ -199,15 +137,53 @@ export enum Language { } ``` -A top-level export named `Language` in a domain package. Many other SDK packages reference "language" (`apps` runtimes, `jobs` task language, `clusters` runtime languages, `pipelines` SQL/Python). The package re-exports `Language` without a `Notebook` or `Workspace` qualifier. A user importing two SDK packages can get `Language` from `workspace` and a different `Language` from `apps` or `jobs` (when those add similar enums). +A top-level export named `Language` in a domain package. Many other SDK packages reference "language" (`apps` runtimes, `jobs` task language, `clusters` runtime languages, `pipelines` SQL/Python). The package re-exports `Language` without a `Notebook` or `Workspace` qualifier. A user importing two SDK packages can get `Language` from `workspaceobjects` and a different `Language` from `apps` or `jobs` (when those add similar enums). `NotebookLanguage` is the natural domain prefix; the wire field is `notebook.language`. +### 25. `*Request_Response` types — proto nested-message naming leaks into the public surface + +**Location:** `model.ts:70` (`DeleteRequest_Response`), `model.ts:97` (`ExportRequest_Response`), `model.ts:147` (`ImportRequest_Response`), `model.ts:157` (`ListRequest_Response`), `model.ts:171` (`MkdirsRequest_Response`); re-exported from `index.ts:9,11,13,15,17`. + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. +export interface DeleteRequest_Response {} +... +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export interface ExportRequest_Response { ... } +``` + +**Why:** the `_Response` infix encodes the protobuf nested-message path (`message DeleteRequest { message Response { ... } }`) directly into a TS identifier. The eslint-disable comment names the leak verbatim ("Proto-style nested message name"). TypeScript consumers do not have proto-nested types; the underscored name reads as "snake_case in PascalCase" — a shape no other TS SDK package uses. + +**Category:** Proto-architectural-leak — proto/IDL implementation detail surfaced in public type names. + +**Suggested:** drop the `_Response` infix and pick a flat name: `DeleteResponse`, `ExportResponse`, `ImportResponse`, `ListResponse`, `MkdirsResponse`. Where the response carries domain content (`ListResponse` → `ObjectInfo[]`), a content-bearing name like `ListObjectsResponse` would also work. + +**Rationale:** TS naming conventions are PascalCase without underscores. The `Request_Response` shape forces every consumer call site (`Promise`, `unmarshalDeleteRequest_ResponseSchema`) to carry the proto path. It also implies a parent-child semantic relationship between `DeleteRequest` and `DeleteRequest_Response` that does not exist on the wire (the response is a sibling message in proto, just nested for namespacing). + +### 26. `unmarshal*Request_ResponseSchema` constants — proto leak into schema identifier names + +**Location:** `model.ts:203` (`unmarshalDeleteRequest_ResponseSchema`), `model.ts:207` (`unmarshalExportRequest_ResponseSchema`), `model.ts:222` (`unmarshalImportRequest_ResponseSchema`), `model.ts:226` (`unmarshalListRequest_ResponseSchema`), `model.ts:236` (`unmarshalMkdirsRequest_ResponseSchema`); imported and used in `client.ts:38-42`. + +```ts +// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. +export const unmarshalDeleteRequest_ResponseSchema: z.ZodType = + z.object({}); +``` + +**Why:** the proto-nested name from finding 25 propagates into every schema constant. The schema identifier itself (`unmarshalDeleteRequest_ResponseSchema`) is a public export carrying the proto path. The unmarshal verb is also kept (separate, deliberate per project rules), but the `Request_Response` infix on the schema names is the proto leak surfacing twice — once on the type, once on the schema constant. + +**Category:** Proto-architectural-leak — schema-identifier inheritance of the proto nested-message path. + +**Suggested:** rename in lockstep with finding 25: `unmarshalDeleteResponseSchema`, `unmarshalExportResponseSchema`, etc. + +**Rationale:** schema constants are public API (re-exportable, used by downstream code). Carrying the proto path into them locks the proto shape into the SDK's public surface even for consumers who never see the underlying type alias. + ## Medium severity -### 9. `ObjectType.LIBRARY` — obsolete concept +### 6. `ObjectType.LIBRARY` — obsolete concept -**Location:** `model.ts:55` +**Location:** `model.ts:48` ```ts NOTEBOOK = 'NOTEBOOK', @@ -220,12 +196,12 @@ DASHBOARD = 'DASHBOARD', Workspace "libraries" (as a top-level object type) are obsolete — Databricks moved libraries to cluster-level and job-level configurations. The value is exported without a deprecation marker and without JSDoc explanation. Consumers writing `if (obj.objectType === ObjectType.LIBRARY)` are coding against a dead branch. -### 10. `List.notebooksModifiedAfter` — field contradicts type domain +### 7. `ListRequest.notebooksModifiedAfter` — field contradicts type domain -**Location:** `model.ts:163-168` +**Location:** `model.ts:149-154` ```ts -export interface List { +export interface ListRequest { /** The absolute path of the notebook or directory. */ path?: string | undefined; /** UTC timestamp in milliseconds */ @@ -237,11 +213,11 @@ export interface List { `modifiedAfterMillis` (without the `notebooks` prefix) or `notebookModifiedAfterMillis` (with the singular subject matching the filter's actual scope) would describe what the server does. -The unit (`milliseconds`) is in JSDoc only, not in the field name. Other timestamp fields in the same file are documented in milliseconds but named `createdAt` / `modifiedAt`. Inconsistent — see finding 15. +The unit (`milliseconds`) is in JSDoc only, not in the field name. Other timestamp fields in the same file are documented in milliseconds but named `createdAt` / `modifiedAt`. Inconsistent — see finding 12. -### 11. `Export.directDownload` — verb-as-noun field, weak boolean +### 8. `ExportRequest.directDownload` — verb-as-noun field, weak boolean -**Location:** `model.ts:96-99` +**Location:** `model.ts:88-92` ```ts /** @@ -255,9 +231,9 @@ directDownload?: boolean | undefined; The flag also has a semantic problem: when `true`, the response body is raw bytes; when `false`, the response body is a JSON object with base64. So the field changes the entire response content type, but the generated client (`export` method) parses the response identically in both cases. Setting `directDownload: true` would crash the parser. -### 12. `Export_Response.fileType` — underspecified +### 9. `ExportRequest_Response.fileType` — underspecified -**Location:** `model.ts:117-119` +**Location:** `model.ts:103-105` ```ts /** The file type of the exported file. */ @@ -268,9 +244,9 @@ The doc says "the file type" but doesn't say in what form. Is it the extension ( `mimeType`, `extension`, or `format: ExportFormat` would commit. -### 13. `Export_Response.content` typed `Uint8Array` with "base64-encoded" doc +### 10. `ExportRequest_Response.content` typed `Uint8Array` with "base64-encoded" doc -**Location:** `model.ts:112-116` +**Location:** `model.ts:98-102` ```ts /** @@ -282,9 +258,9 @@ content?: Uint8Array | undefined; The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw bytes). The client decodes base64 before populating this field, so the field actually holds decoded bytes, contradicting the JSDoc. The JSDoc was lifted from the wire format documentation and not updated for the post-decode TS shape. A reader holding the type sees "Uint8Array of base64-encoded data," which is technically meaningless (Uint8Arrays are bytes, not base64). -### 14. `Import.content` typed `Uint8Array` with "base64-encoded" doc +### 11. `ImportRequest.content` typed `Uint8Array` with "base64-encoded" doc -**Location:** `model.ts:146-152` +**Location:** `model.ts:132-138` ```ts /** @@ -295,11 +271,11 @@ The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw byte content?: Uint8Array | undefined; ``` -Mirror of finding 13 in the reverse direction. The client encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. +Mirror of finding 10 in the reverse direction. The client encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. -### 15. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision +### 12. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision -**Location:** `model.ts:204-208` +**Location:** `model.ts:190-193` ```ts /** Only applicable to files. The creation UTC timestamp. */ @@ -310,12 +286,12 @@ modifiedAt?: number | undefined; Two issues: -1. The names use the `At` suffix (TS-friendly) but the type is `number`. Unit (milliseconds vs seconds) is documented nowhere in this type. The companion `List.notebooksModifiedAfter` is documented as milliseconds; one infers consistency, but the type does not declare it. Most of the SDK uses `Temporal.Instant` for `At`-suffixed timestamps; here it's `number`. +1. The names use the `At` suffix (TS-friendly) but the type is `number`. Unit (milliseconds vs seconds) is documented nowhere in this type. The companion `ListRequest.notebooksModifiedAfter` is documented as milliseconds; one infers consistency, but the type does not declare it. Most of the SDK uses `Temporal.Instant` for `At`-suffixed timestamps; here it's `number`. 2. "Only applicable to files" — the field is on `ObjectInfo`, which also describes notebooks, directories, etc. Setting expectations via "only applicable" in JSDoc is a code smell: the field shape doesn't change based on object type. -### 16. `ObjectInfo.size` — underspecified +### 13. `ObjectInfo.size` — underspecified -**Location:** `model.ts:210-211` +**Location:** `model.ts:196-197` ```ts /** Only applicable to files. The file size in bytes can be returned. */ @@ -324,12 +300,12 @@ size?: number | undefined; `size` is a unit-less name. JSDoc says "file size in bytes can be returned" (the "can be" is also ambiguous — is it always returned for files?). `sizeBytes` or `sizeInBytes` is the convention used elsewhere in Databricks SDKs (`clusters.clusterMemoryMb`, `pipelines.storageBytes`). At scale-up time (>4GiB) `number` loses precision; `bigint` or `string` would be safer. -### 17. `Mkdirs.path` — singular/plural mismatch with the type name +### 14. `MkdirsRequest.path` — singular/plural mismatch with the type name -**Location:** `model.ts:176-182` +**Location:** `model.ts:162-168` ```ts -export interface Mkdirs { +export interface MkdirsRequest { /** * The absolute path of the directory. If the parent directories do not exist, it will also create them. * ... @@ -338,19 +314,19 @@ export interface Mkdirs { } ``` -The type is plural (`Mkdirs` — "make directories"), but it takes one path. The pluralization comes from the Unix `mkdir -p` semantics ("makes the directory and any missing parent directories"), but the input is a single path. A user reading `Mkdirs` expects to pass an array. +The type's verb is plural (`Mkdirs` — "make directories"), but it takes one path. The pluralization comes from the Unix `mkdir -p` semantics ("makes the directory and any missing parent directories"), but the input is a single path. A user reading `MkdirsRequest` expects to pass an array. -### 18. `Mkdirs` — Unix-ism +### 15. `MkdirsRequest` — Unix-ism -**Location:** `model.ts:176`; `client.ts:254` +**Location:** `model.ts:162`; `client.ts:266` `mkdirs` is a Unix verb. The convention in TS SDKs is `createDirectory` (matches the Files API's `createDirectory`). The Databricks SDK's own `files` package uses `createDirectory` for a similar operation. Inconsistent verb across packages. Also: the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the request body holds one path. So even at the wire level, the name is misleading. -### 19. `Language.R` — single-letter identifier +### 16. `Language.R` — single-letter identifier -**Location:** `model.ts:43` +**Location:** `model.ts:36` ```ts export enum Language { @@ -361,51 +337,23 @@ export enum Language { } ``` -`Language.R` is the only single-character enum value in the package. Auto-import tools, grep, and refactoring tools handle one-letter identifiers poorly. The wire format also uses just `R`, so a rename in the SDK would need a string mapping; nonetheless, `Language.R_LANG` (matching the `R_MARKDOWN` format value) or simply documenting `R` more thoroughly would help. +`Language.R` is the only single-character enum value in the package. Auto-import tools, grep, and refactoring tools handle one-letter identifiers poorly. The wire format also uses just `R`, so wire compatibility constrains the value, but the enum key (the TS identifier) can diverge from the wire string. Documenting `R` more thoroughly, or treating it as the lone exception to a single-token convention, would help readers grepping for the symbol. -### 20. `Language` values — no `LANGUAGE_` prefix, overlap with runtime names +### 17. `getStatus` — vague verb on the client -**Location:** `model.ts:35-44` +**Location:** `client.ts:157` ```ts -SCALA = 'SCALA', -PYTHON = 'PYTHON', -SQL = 'SQL', -R = 'R', -``` - -The enum values are bare language names that collide with cluster runtime IDs (`DBR-15.4-SCALA-2.12`), job task types (`SQL`, `PYTHON_WHEEL_TASK`), and library types. A user querying `notebook.language === 'PYTHON'` may also see `task.taskType === 'PYTHON_WHEEL_TASK'` and not realize the two `PYTHON` strings come from different enums. - -Other SDK enums add a prefix (`TaskType.PYTHON_WHEEL_TASK`); this one does not. - -### 21. `getStatus` — vague verb on the client - -**Location:** `client.ts:154` - -```ts -async getStatus(req: GetStatus, options?: CallOptions): Promise +async getStatus(req: GetStatusRequest, options?: CallOptions): Promise ``` "Status" of what? In TS SDKs, `getStatus` usually returns a status enum or a small status object (e.g., job run status). Here it returns full `ObjectInfo` metadata — a filesystem `stat`, not a status. The Files API uses `getMetadata`. The Go SDK uses `GetStatus` (from `os.Stat` ancestry). Either `getMetadata` or `stat` would describe the actual operation. -The method also returns `Promise` while `list` returns `Promise` — inconsistent shape (one returns the bare entity, one returns a wrapper). See finding 29. +The method also returns `Promise` while `list` returns `Promise` — inconsistent shape (one returns the bare entity, one returns a wrapper). See finding 22. -### 22. `GetStatus` — verb-as-type without `Request` suffix +### 18. `DeleteRequest.recursive` — Unix flag, no domain reading -**Location:** `model.ts:121-124` - -```ts -export interface GetStatus { - /** The absolute path of the notebook or directory. */ - path?: string | undefined; -} -``` - -Combined with finding 2, `GetStatus` is the only request type whose name is composed of two verbs. The other request types (`Delete`, `Export`, `Import`, `List`, `Mkdirs`) are single verbs. The package mixes the two patterns. `GetStatusRequest` is what the rest of the SDK uses. - -### 23. `Delete.recursive` — Unix flag, no domain reading - -**Location:** `model.ts:69-73` +**Location:** `model.ts:61-66` ```ts /** @@ -420,7 +368,7 @@ recursive?: boolean | undefined; ## Low severity -### 24. `ExportFormat.R_MARKDOWN` — shape mismatch within enum +### 19. `ExportFormat.R_MARKDOWN` — shape mismatch within enum **Location:** `model.ts:15-16` @@ -436,7 +384,7 @@ RAW = 'RAW', Five of the seven values are single tokens; one is `R_MARKDOWN` with an underscore. SQL convention would also be `RMARKDOWN` or `RMD`. Inconsistent shape inside the same enum. -### 25. `ExportFormat.DBC` — cryptic abbreviation +### 20. `ExportFormat.DBC` — cryptic abbreviation **Location:** `model.ts:13-14` @@ -447,45 +395,18 @@ DBC = 'DBC', DBC = "Databricks Archive." The acronym is product-specific. `DATABRICKS_ARCHIVE` would be readable. Wire-format compatibility (`DBC` is what the server expects) means the rename has to happen in the enum-key layer, not the enum-value layer — which TS supports cleanly. -### 26. `ExportOutputs` — plural enum type for ALL/NONE values - -**Location:** `model.ts:27-32` - -```ts -export enum ExportOutputs { - /** All outputs will be exported */ - ALL = 'ALL', - /** No outputs will be exported */ - NONE = 'NONE', -} -``` - -The enum models "which outputs to include" but is named `ExportOutputs` (plural). `OutputsFilter`, `OutputInclusion`, or `IncludeOutputs` (boolean) would read better. The two values `ALL` and `NONE` could equally be a boolean. - -Also: JSDoc on `Export.outputs` says "only ALL or NONE is documented publically, DATABRICKS is internal only" — admits there's a hidden third value, which means the enum is not exhaustive. - -### 27. `Export.outputs` typed `ExportOutputs` — type-suffix tautology - -**Location:** `model.ts:104-106` +### 21. `ObjectInfo` — `Info` suffix used inconsistently across SDK -```ts -outputs?: ExportOutputs | undefined; -``` - -Field and type both spell `outputs`. The user types `req.outputs = ExportOutputs.ALL`. Idiomatic phrasing would be `req.outputInclusion = OutputInclusion.ALL` or `req.includeOutputs = true`. - -### 28. `ObjectInfo` — `Info` suffix used inconsistently across SDK - -**Location:** `model.ts:188-214` +**Location:** `model.ts:173-200` The `Info` suffix is a Go/Java convention for "POJO that describes a thing." TS SDKs vary: some use bare entity names (`Catalog`, `Cluster`), some use `Info`/`Details`. This package's only entity type is `ObjectInfo`. There is no companion `Object` — so the name reads consistently with itself, but the suffix is purely a hat-tip to Go. -### 29. `List_Response.objects` — generic field for `ObjectInfo[]` +### 22. `ListRequest_Response.objects` — generic field for `ObjectInfo[]` -**Location:** `model.ts:171-174` +**Location:** `model.ts:157-160` ```ts -export interface List_Response { +export interface ListRequest_Response { /** List of objects. */ objects?: ObjectInfo[] | undefined; } @@ -493,19 +414,19 @@ export interface List_Response { `objects` is the most generic JavaScript noun; it tells the reader nothing. `items`, `entries`, `paths`, or `workspaceObjects` would convey scope. The Go SDK has the same `Objects` field; transferring the name without adaptation gives a TS user a `resp.objects` access that reads like "the objects of the response." -### 30. `mkdirs` — verb-tense / casing inconsistency +### 23. `mkdirs` — verb-tense / casing inconsistency -**Location:** `client.ts:254` +**Location:** `client.ts:266` ```ts -async mkdirs(req: Mkdirs, options?: CallOptions): Promise +async mkdirs(req: MkdirsRequest, options?: CallOptions): Promise ``` Other client methods read as verb-noun (`export`, `import`, `list`) or compound verb (`getStatus`). `mkdirs` is the only Unix-style contraction. The class also has a `delete` method (matches HTTP verb) but no `make` or `create` method. `createDirectory` would align with `delete` semantically. -### 31. First-person and ticket-driven prose in public JSDoc +### 24. First-person and ticket-driven prose in public JSDoc -**Location:** `model.ts:17-18`, `:19-24` +**Location:** `model.ts:17`, `:19-23` ```ts /** We will inspect the content of the payload to determine the type */ @@ -526,17 +447,15 @@ RAW = 'RAW', 2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) and `ObjectInfo.resourceId` (string, unified-resource) are both returned, both documented as "unique identifier for the object," with no naming clue about which one to pass where. This is the single most user-hostile naming issue in the file. -3. **`ExportFormat` is the import format.** The single enum services both `Import` and `Export` (good — DRY), but the name says only "Export." A neutral name (`NotebookFormat` or `WorkspaceObjectFormat`) would describe what it actually is. +3. **`ExportFormat` is the import format.** The single enum services both `ImportRequest` and `ExportRequest` (good — DRY), but the name says only "Export." A neutral name (`NotebookFormat` or `WorkspaceObjectFormat`) would describe what it actually is. -4. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` on `Import` means "detect from file extension + header," and `AUTO` on `Export` means "decide from object type." Same enum value, different server-side algorithm. +4. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` on `ImportRequest` means "detect from file extension + header," and `AUTO` on `ExportRequest` means "decide from object type." Same enum value, different server-side algorithm. -5. **Verb-as-type request names without `Request` suffix.** Six request interfaces (`Delete`, `Export`, `GetStatus`, `Import`, `List`, `Mkdirs`) ship without the `Request` suffix that the rest of the SDK uses. Combined with collisions against ES reserved-context words (`import`, `export`, `delete`), this makes the type names unusable without the package qualifier — which is exactly what TS users lose at import time. +5. **`content: Uint8Array` documented as base64 in both directions.** Two fields hold post-decode bytes but their JSDoc reads as if they still hold base64 strings. A defensive user reading the JSDoc and base64-encoding their bytes will double-encode on the way in. The mismatch is silent and the failure mode is data corruption. -6. **`content: Uint8Array` documented as base64 in both directions.** Two fields hold post-decode bytes but their JSDoc reads as if they still hold base64 strings. A defensive user reading the JSDoc and base64-encoding their bytes will double-encode on the way in. The mismatch is silent and the failure mode is data corruption. +6. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear elsewhere in the SDK.** The `files` package uses `createDirectory` and `getMetadata`. The `repos` package uses `getRepo`. Picking one verb per concept and applying it across packages would let users transfer knowledge. -7. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear elsewhere in the SDK.** The `files` package uses `createDirectory` and `getMetadata`. The `repos` package uses `getRepo`. Picking one verb per concept and applying it across packages would let users transfer knowledge. - -8. **Sentinel `OBJECT_TYPE_UNSPECIFIED` documented as "only used by list-repo."** The enum exports a value that the package consumers should never set but cannot remove without breaking the read side. A separate response-only enum or a `null` for "unknown" would be cleaner. +7. **Proto nested-message names surface ten times in the public API (finding 27).** Every response type and its schema constant carries the `Request_Response` infix. The source files mark the leak in eight separate `eslint-disable-next-line ... -- Proto-style nested message name.` comments at `model.ts:69, :96, :146, :156, :170, :202, :206, :221, :225, :235`. The lint rule that would block this shape (`@typescript-eslint/naming-convention`) is suppressed package-wide for these identifiers. The suppression naming the leak ("Proto-style nested message name") confirms the issue is generator-level, not incidental — fixable only in the template that emits these types from the proto schema. ## Domain glossary @@ -561,7 +480,19 @@ RAW = 'RAW', | File | Lines | Read in full | |------|-------|--------------| -| `src/v1/model.ts` | 311 | yes | -| `src/v1/client.ts` | 276 | yes | +| `src/v1/model.ts` | 299 | yes | +| `src/v1/client.ts` | 291 | yes | | `src/v1/utils.ts` | 151 | yes | | `src/v1/index.ts` | 21 | yes | + +## Fixed + +- #1 `workspace` package name (originally cited at `package.json` → `@databricks/sdk-workspace`): Fixed in regeneration on 2026-05-20 — package renamed to `workspaceobjects`, which conveys the filesystem-objects scope and no longer collides with the other "workspace*" packages. +- #2 `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` verb-as-type request interfaces (originally cited at `model.ts:65,:79,:121,:126,:163,:176`): Fixed in regeneration on 2026-05-20 — all request interfaces now carry a `Request` suffix (`DeleteRequest`, `ExportRequest`, `ImportRequest`, `ListRequest`, `MkdirsRequest`, `GetStatusRequest`), resolving the ES reserved-word collisions. +- #22 `GetStatus` verb-as-type without `Request` suffix (originally cited at `model.ts:121-124`): Fixed in regeneration on 2026-05-20 — renamed to `GetStatusRequest`, consistent with the rest of the SDK. +- #26 `ExportOutputs` plural enum type (originally cited at `model.ts:27-32`): Fixed in regeneration on 2026-05-20 — the `ExportOutputs` enum is no longer present in the generated model. +- #27 `Export.outputs` typed `ExportOutputs` tautology (originally cited at `model.ts:104-106`): Fixed in regeneration on 2026-05-20 — the `outputs` field is no longer present on `ExportRequest`. + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md index 870e5fd6..6db64a06 100644 --- a/.agent/naming-audit/workspaceassignment.md +++ b/.agent/naming-audit/workspaceassignment.md @@ -1,74 +1,69 @@ # Naming Audit: workspaceassignment -**Path:** `packages/workspaceassignment/src/v1/` +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + +**Path:** `packages/accessmanagement/src/v1/` (source moved here; the +`workspaceassignment` source directory no longer exists, but the +WorkspacePermissionAssignment surface continues to live in the +`accessmanagement` package). **Versions audited:** v1 **Inferred domain:** Account-level workspace permission assignments — list/get/update/delete the `USER`/`ADMIN` permissions a principal (user / service principal / group) has on a single workspace, plus list the catalog of workspace-level permission values supported. -**Total weird names flagged:** 28 +**Total weird names flagged:** 23 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 12 | +| High | 7 | +| Medium | 9 | | Low | 6 | | Observation | 1 | ## High severity -### 1. Package name `workspaceassignment` (singular) vs API path `/permissionassignments` — package directory / `src/v1/client.ts:78,106,146,174` -- **Why weird:** The npm package is named `@databricks/sdk-workspaceassignment`, but every type in it is about a `PermissionAssignment` (`DeleteWorkspacePermissionAssignment`, `GetWorkspacePermissionAssignments`, `WorkspacePermissionAssignmentOutput`, ...), every URL ends in `permissionassignments`, and the conceptually equivalent type in the `iam` package is `WorkspaceAssignmentDetail`. So the package is called "workspace assignment" (singular, no qualifier) while the contents are uniformly "workspace permission assignment(s)" and the upstream iam port models the same domain object under a third name entirely. The singular package name is also a singular/plural mismatch with the operations it exposes (`getWorkspacePermissionAssignments`, plural). +### 1. Package name `workspaceassignment` (historic) / `accessmanagement` (current) vs API path `/permissionassignments` — package directory / `src/v1/client.ts:103,131,159,187` +- **Why weird:** The npm package is named `@databricks/sdk-workspaceassignment`, but every type in it is about a `PermissionAssignment` (`DeleteWorkspacePermissionAssignmentRequest`, `GetWorkspacePermissionAssignmentsRequest_Response`, `WorkspacePermissionAssignmentOutput`, ...), every URL ends in `permissionassignments`, and the conceptually equivalent type in the `iam` package is `WorkspaceAssignmentDetail`. So the package is called "workspace assignment" (singular, no qualifier) while the contents are uniformly "workspace permission assignment(s)" and the upstream iam port models the same domain object under a third name entirely. The singular package name is also a singular/plural mismatch with the operations it exposes (`getWorkspacePermissionAssignments`, plural). The surface has since been merged into `accessmanagement`, which is broader but still does not match the `/permissionassignments` URL fragment. - **Category:** 8 (redundant/inconsistent suffix), 9 (singular/plural), 12 (duplicate concept — `iam.WorkspaceAssignmentDetail`). - **Suggested name:** Rename the package to `workspacepermissions` (matches the listWorkspacePermissions surface and the `permissionassignments` URL fragment), or merge into `iam` since `iam.WorkspaceAssignmentDetail` already covers the same conceptual entity. At minimum align with the route: `workspacepermissionassignments`. - **Rationale:** Three different names for one concept across the SDK (`workspaceassignment` package, `WorkspacePermissionAssignment*` types, `iam.WorkspaceAssignmentDetail`) is a Discovery footgun — users searching for "workspace assignment" will hit the iam package first and miss this one. -### 2. `Permission` enum name — `src/v1/model.ts:5` -- **Why weird:** Top-level export named simply `Permission` is dangerously generic in a multi-package SDK. The iam package already defines `WorkspacePermission` (`packages/iam/src/v2/model.ts:58`) — three values (`USER_PERMISSION`/`ADMIN_PERMISSION`/`WORKSPACE_PERMISSION_UNSPECIFIED`) for the exact same domain concept. Importing both as `Permission` from `@databricks/sdk-workspaceassignment` and `WorkspacePermission` from `@databricks/sdk-iam` will leave users wondering whether they are interchangeable (they functionally are — both encode `USER` vs `ADMIN` workspace-level access). -- **Category:** 1 (vague/generic — `Permission` says nothing about scope), 12 (duplicate concept with `iam.WorkspaceAssignmentDetail` + `iam.WorkspacePermission`). -- **Suggested name:** `WorkspacePermission` (and reconcile with `iam.WorkspacePermission` — same shape, fewer values here). -- **Rationale:** Pick one name for the concept. `Permission` alone is the kind of name a user would shadow with a local variable and then bug-hunt for hours. - -### 3. `Permission.UNKNOWN` — `src/v1/model.ts:6` -- **Why weird:** Sentinel value for "permission not set" leaks from protobuf semantics into the public TS surface. Idiomatic TS uses `undefined` for "not present". Every other enum in this codebase that has a sentinel uses `*_UNSPECIFIED` (e.g., `WORKSPACE_PERMISSION_UNSPECIFIED`, `PRINCIPAL_TYPE_UNSPECIFIED` in iam), so even the sentinel form is inconsistent. -- **Category:** 2 (redundant enum value not needed in TS), 14 (proto-style name). -- **Suggested name:** Remove `UNKNOWN` entirely; rely on `permissionLevel?: WorkspacePermission | undefined` for the not-set case. If a wire value must be representable, prefer `Unspecified` (PascalCase) to align with the rest of TS conventions or `WORKSPACE_PERMISSION_UNSPECIFIED` to align with iam. -- **Rationale:** `UNKNOWN` is *not* on the wire spec (the iam mirror uses `WORKSPACE_PERMISSION_UNSPECIFIED`), so this value is a TS-side invention that adds a third encoding of the same concept. - -### 4. `DeleteWorkspacePermissionAssignment` — `src/v1/model.ts:13` -- **Why weird:** Type whose name is a verb phrase (`Delete...`). Same pattern repeats for `GetWorkspacePermissionAssignments`, `ListWorkspacePermissions`, `UpdateWorkspacePermissionAssignment`. Reads as an action / command, not as the request body. The `index.ts` re-exports them as `type DeleteWorkspacePermissionAssignment` — consumers see `import type {DeleteWorkspacePermissionAssignment}` and expect a method. -- **Category:** 6 (misleading: verb phrase as type name), 14 (Go-style naming where Go uses request type names directly), 17 (inconsistent verb form vs. iam package which uses `DeleteWorkspaceAssignmentDetailRequest`). -- **Suggested name:** `DeleteWorkspacePermissionAssignmentRequest` (and the parallel `Get…Request`, `List…Request`, `Update…Request`). -- **Rationale:** The iam package uses the `Request` suffix consistently (`DeleteWorkspaceAssignmentDetailRequest`, `UpdateWorkspaceAssignmentDetailRequest`, ...). The local convention here disagrees with the sibling package modelling the same domain. - -### 5. `GetWorkspacePermissionAssignments` request type for an HTTP `GET` that returns a *list* — `src/v1/model.ts:26`, `src/v1/client.ts:102` -- **Why weird:** The method `getWorkspacePermissionAssignments` returns a paginated list (`permissionAssignments`, `nextPageToken`, `prevPageToken`) — that is a `list` operation, not a `get`. Compare to `iam.ListWorkspaceAssignmentDetailsRequest` (same domain, different verb). Mislabelling pagination as "get" leads users to expect a single object back. +### 2. `WorkspacePermission.UNKNOWN` sentinel inconsistent with `*_UNSPECIFIED` used elsewhere — `src/v1/model.ts:40` +- **Why weird:** This package uses `UNKNOWN` as the zero-value sentinel, but every other enum in this codebase uses `*_UNSPECIFIED` (e.g., `REQUEST_AUTHZ_IDENTITY_UNSPECIFIED` in this same file at model.ts:34; `WORKSPACE_PERMISSION_UNSPECIFIED`, `PRINCIPAL_TYPE_UNSPECIFIED` in iam). The sentinel form is inconsistent across packages modelling the same concept. +- **Category:** 17 (inconsistent sentinel naming across enums in the same codebase). +- **Suggested name:** Rename `UNKNOWN` to `WORKSPACE_PERMISSION_UNSPECIFIED` to align with the iam mirror and the rest of the SDK. +- **Rationale:** The iam mirror of this same concept uses `WORKSPACE_PERMISSION_UNSPECIFIED`. A consistent sentinel name across packages reduces user confusion when bridging the two. + +### 3. `GetWorkspacePermissionAssignmentsRequest` request type for an HTTP `GET` that returns a *list* — `src/v1/model.ts:203`, `src/v1/client.ts:127` +- **Why weird:** The method `getWorkspacePermissionAssignments` returns a list of `permissionAssignments` (model.ts:213). That is a `list` operation, not a `get`. Compare to `iam.ListWorkspaceAssignmentDetailsRequest` (same domain, different verb). Mislabelling a list as "get" leads users to expect a single object back. - **Category:** 6 (misleading verb), 13 (verb-tense inconsistency — `Get` for a list result), 17 (verb inconsistency with iam mirror). - **Suggested name:** `ListWorkspacePermissionAssignmentsRequest` / `…Response`, method `listWorkspacePermissionAssignments`. -- **Rationale:** Pagination fields make this unambiguously a list. The current name reads as "get the assignments for this workspace" — singular intent, plural body — and is inconsistent with `iam.ListWorkspaceAssignmentDetails`. +- **Rationale:** A plural-result response makes this unambiguously a list. The current name reads as "get the assignments for this workspace" — singular intent, plural body — and is inconsistent with `iam.ListWorkspaceAssignmentDetails`. -### 6. `ListWorkspacePermissions` returns a static catalog, not data — `src/v1/model.ts:50`, `src/v1/client.ts:142` +### 4. `ListWorkspacePermissionsRequest` returns a static catalog, not data — `src/v1/model.ts:231`, `src/v1/client.ts:155` - **Why weird:** `listWorkspacePermissions` returns the (fixed) catalog of `PermissionOutput` values (`USER`, `ADMIN`, ...) that the workspace supports. The Go SDK has identical confusion: every method called `list…` looks like it lists user data, but here it lists the *types of permissions that exist*. Plus the method appears side-by-side with `getWorkspacePermissionAssignments` (which actually lists assignments), so users will wire the wrong one. - **Category:** 6 (misleading — name implies data, returns metadata), 15 (generic field `permissions` losing meaning). - **Suggested name:** `ListAssignablePermissionsRequest` / `listAssignablePermissions`, or `GetSupportedWorkspacePermissions` / `getSupportedWorkspacePermissions`. Either makes the metadata nature explicit. - **Rationale:** `listWorkspacePermissions(req)` vs `getWorkspacePermissionAssignments(req)` are visually similar enough that someone scanning autocomplete will pick the wrong one. The semantic gulf between them (catalog vs assignments) demands distinct verbs. -### 7. `PermissionOutput` / `PrincipalOutput` / `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:63,70,115` +### 5. `PermissionOutput` / `PrincipalOutput` / `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` - **Why weird:** `Output` suffix is a generic noise word that adds zero information — every response shape is "output". The Go SDK uses `Output` because protobuf service definitions use `Output` as a request/response naming convention; in TS this surfaces as `Permission` vs `PermissionOutput`, two near-identical types differing only by the field semantics. The doc comment on `WorkspacePermissionAssignmentOutput` even spells it out: "The output format for existing workspace PermissionAssignment records". A name that needs the doc string to say "this is the output type" is the symptom. - **Category:** 1 (vague suffix), 8 (redundant type suffix), 14 (proto/Go naming). - **Suggested name:** Drop the `Output` suffix. `Permission` (the enum) and `PermissionDetail`/`PermissionDescription` (the wrapper carrying `description`) is one option; `WorkspacePermissionAssignment`, `Principal`, `PermissionDescriptor` is another. The iam mirror dropped `Output` already (`WorkspaceAssignmentDetail`, not `WorkspaceAssignmentDetailOutput`). - **Rationale:** Cf. rule 1 of the audit list ("vague/generic"). `Output` carries no semantics and conflicts with the sibling type in the same package. -### 8. `WorkspacePermissionAssignmentOutput` vs `iam.WorkspaceAssignmentDetail` duplicate concept — `src/v1/model.ts:115` vs `packages/iam/src/v2/model.ts:983` +### 6. `WorkspacePermissionAssignmentOutput` vs `iam.WorkspaceAssignmentDetail` duplicate concept — `src/v1/model.ts:383` vs `packages/iam/src/v2/model.ts:983` - **Why weird:** Two TS types modelling the same conceptual record: - - `WorkspacePermissionAssignmentOutput` (here): `{ principal: PrincipalOutput, permissions: Permission[], error: string }`. + - `WorkspacePermissionAssignmentOutput` (here): `{ principal: PrincipalOutput, permissions: WorkspacePermission[], error: string }`. - `iam.WorkspaceAssignmentDetail`: `{ principalId, workspaceId, accountId, principalType, entitlements }`. Both encode "what permissions does this principal have on this workspace?", but with different field sets and different field names. Users will not know which is canonical. The two packages share zero types. - **Category:** 12 (duplicate concept), 1 (vague — `…Detail` vs `…Output` vs no suffix). - **Suggested name:** Reconcile with iam. If the workspaceassignment API is older/account-level and iam is workspace-level, document that explicitly; if they overlap functionally, ship one shape and re-export from both packages. -- **Rationale:** This package is a tiny 4-method surface; living without a consistent type with iam is sustainable, but every SDK consumer will need to bridge the two by hand. +- **Rationale:** This surface is a tiny 4-method slice within `accessmanagement`; living without a consistent type with iam is sustainable, but every SDK consumer will need to bridge the two by hand. -### 9. `PrincipalOutput.principalName` discriminated union — `src/v1/model.ts:71-87` +### 7. `PrincipalOutput.principalName` discriminated union — `src/v1/model.ts:268-285` - **Why weird:** The discriminator field is named `principalName` and each variant carries its own typed sub-field (`userName`, `groupName`, `servicePrincipalName`). The variant tag values are also full identifier strings (`'userName' | 'groupName' | 'servicePrincipalName'`). The result is access like `principal.principalName.userName` — three name-words in a row. The actual `displayName` is a *separate* sibling field two lines down, so the structure conflates "what kind of principal is it?" with "what is its identifier?". The iam package handles the same idea more cleanly via a `principalType: PrincipalType` enum + a single `principalId: number` field. - **Category:** 5 (cryptic / redundant), 11 (wrapper around oneof), 12 (duplicate of `iam.PrincipalType` mechanism), 15 (generic field names lose meaning when nested). - **Suggested name:** `principalType: PrincipalType` enum + flatten the identifier to a single string field (or per-variant fields at the top level). Match the iam approach. @@ -76,111 +71,93 @@ ## Medium severity -### 10. `accountId` doc comment "The account ID." — `src/v1/model.ts:14,28,51,95` -- **Why weird:** Doc is uniformly terse — "The account ID." Doesn't say whether it's a UUID, an integer, that it falls back to `ClientOptions.accountId` (per `client.ts:46-48`), that it's required for the URL path, or that it gets URL-injected and not query-parameterised. The same field appears in four request types with the same too-thin doc. +### 8. `accountId` doc comment "The account ID." — `src/v1/model.ts:123,204,232,363` +- **Why weird:** Doc is uniformly terse — "The account ID." Doesn't say whether it's a UUID, an integer, that it falls back to `ClientOptions.accountId` (per `client.ts:71-73,86`), that it's required for the URL path, or that it gets URL-injected and not query-parameterised. The same field appears in four request types with the same too-thin doc. - **Category:** 19 (underspecified ID). - **Suggested name:** Keep `accountId`, rewrite doc to `"Databricks account ID (UUID). If omitted on the request, falls back to ClientOptions.accountId. Required at request time — the SDK substitutes an empty string into the URL path if neither is set."` - **Rationale:** This is the only ID that has a client-side fallback mechanism. Hiding that in a comment three files away is a footgun. -### 11. `workspaceId?: number` typed as `number` — `src/v1/model.ts:17,30,53,97` -- **Why weird:** Workspace IDs in Databricks are 64-bit integers; JS `number` loses precision above 2^53. Same problem on `principalId` (`number` too — model.ts:19,89,99). The client also unconditionally `String(req.workspaceId ?? '')`s the value into the URL (`client.ts:78,106,146,174`), implying string semantics are sufficient — meaning `number` was the wrong primitive to begin with. +### 9. `workspaceId?: number` typed as `number` — `src/v1/model.ts:126,207,235,366` +- **Why weird:** Workspace IDs in Databricks are 64-bit integers; JS `number` loses precision above 2^53. Same problem on `principalId` (`number` too — model.ts:128,287,368). The client also unconditionally `String(req.workspaceId ?? '')`s the value into the URL (`client.ts:103,131,159,187`), implying string semantics are sufficient — meaning `number` was the wrong primitive to begin with. - **Category:** 16 (field type contradicts domain), 19 (underspecified ID). - **Suggested name:** Keep `workspaceId`, type as `bigint | string` (or `string` to match the URL serialisation). - **Rationale:** Public Databricks workspace IDs cross 2^53 in account-level deployments; silent rounding bugs are a real risk. Same concern applies to `principalId`. -### 12. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:42 vs 60,119` +### 10. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:213 vs 241,387` - **Why weird:** The response for `getWorkspacePermissionAssignments` carries `permissionAssignments` (list of assigned-principal records with role). The response for `listWorkspacePermissions` carries `permissions` (list of *permission types*). `WorkspacePermissionAssignmentOutput.permissions` is the *roles a single principal holds*. Three different things, two of them just called `permissions`. - **Category:** 1 (vague), 15 (generic field name loses meaning), 17 (inconsistent label across siblings). - **Suggested name:** On the list-permissions response, rename `permissions` to `supportedPermissions` or `availablePermissions`. On `WorkspacePermissionAssignmentOutput`, rename `permissions` to `permissionLevels` or `grantedPermissions` to match the singular `permissionLevel` in `PermissionOutput`. - **Rationale:** A user holding the response sees `.permissions` and can't tell whether it's "permissions held" or "permission types defined". -### 13. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:64 vs 119` -- **Why weird:** The same `Permission` enum is held as singular on one type (`permissionLevel: Permission`) and plural on another (`permissions: Permission[]`). The lexical difference is significant (`level` vs no suffix) and inconsistent across the package. Internal users won't know whether to think of permissions as a scalar or set. +### 11. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:251 vs 387` +- **Why weird:** The same `WorkspacePermission` enum is held as singular on one type (`permissionLevel: WorkspacePermission`) and plural on another (`permissions: WorkspacePermission[]`). The lexical difference is significant (`level` vs no suffix) and inconsistent across the package. Internal users won't know whether to think of permissions as a scalar or set. - **Category:** 9 (singular/plural inconsistency), 17 (inconsistent action verb / field name). -- **Suggested name:** Settle on one shape: if a principal can hold multiple levels, use `permissionLevels: Permission[]` everywhere. If `PermissionOutput` is really just describing a single level, name it `permission` (singular, matching the type). -- **Rationale:** `permissionLevel` and `permissions` are both `Permission`-typed; the asymmetry has no semantic justification visible in this file. +- **Suggested name:** Settle on one shape: if a principal can hold multiple levels, use `permissionLevels: WorkspacePermission[]` everywhere. If `PermissionOutput` is really just describing a single level, name it `permission` (singular, matching the type). +- **Rationale:** `permissionLevel` and `permissions` are both `WorkspacePermission`-typed; the asymmetry has no semantic justification visible in this file. -### 14. `WorkspacePermissionAssignmentOutput.error?: string` — `src/v1/model.ts:121` +### 12. `WorkspacePermissionAssignmentOutput.error?: string` — `src/v1/model.ts:389` - **Why weird:** Embedding an opaque error string inside the success response body. The pattern is "we succeeded enough to return data, but here's a per-record error message". This is unusual: typical SDK design surfaces errors as exceptions or as a typed error union. A bare `string` carrying potentially structured error content forces the user to parse strings. Also, `error` is a reserved-ish JS identifier (global `Error` class, `try/catch` `error` parameter) and clashes with style. - **Category:** 1 (vague), 10 (reserved-word-adjacent), 15 (generic field loses meaning), 16 (field contradicting type — a success response carrying error data). - **Suggested name:** `errorMessage` or `partialFailureReason`, typed as `string | undefined`. Better: model the assignment as `{ ok: true, data: ... } | { ok: false, error: ... }`. - **Rationale:** The current shape leaks the per-record-error nature of the upstream API. At minimum rename to make the partial-failure semantics explicit. -### 15. `PermissionOutput.description` doc comment "The results of a permissions query." — `src/v1/model.ts:65-66` +### 13. `PermissionOutput.description` doc comment "The results of a permissions query." — `src/v1/model.ts:252-253` - **Why weird:** Doc string is meaningless — "description" labelled as "results of a permissions query" gives the reader zero signal about what the string contains. Looking at the upstream this likely contains a human-readable description like "Allows full access" or "Read-only access". - **Category:** 1 (vague — both field and doc). - **Suggested name:** Keep `description`, rewrite doc to `"Human-readable description of what this permission grants (for example, 'Allows full administrative access to the workspace')."`. - **Rationale:** The current JSDoc is worse than no doc at all because it suggests the field is a query-result wrapper. -### 16. `PrincipalOutput.principalName` discriminator tag values use camelCase — `src/v1/model.ts:73,78,83` +### 14. `PrincipalOutput.principalName` discriminator tag values use camelCase — `src/v1/model.ts:271,276,281` - **Why weird:** `$case` values are `'userName' | 'groupName' | 'servicePrincipalName'` — those are *field names*, not discriminator tags. A discriminator value should describe the *type* of the variant (`'user' | 'group' | 'servicePrincipal'`), not duplicate the field name. The current shape forces `principalName.userName` ("user name's user name"). - **Category:** 5 (cryptic — discriminator tag duplicates the field), 11 (trivial wrapper-around-oneof). - **Suggested name:** Tag values `'user' | 'group' | 'servicePrincipal'`, payload field `name: string` across all three variants. Or flatten to enum + single string. - **Rationale:** Discriminator should let `switch (p.principalName.$case)` read as `case 'user':` rather than `case 'userName':`. -### 17. `PrincipalOutput.principalId: number` opaque ID doc — `src/v1/model.ts:88-89` -- **Why weird:** Doc reads "The unique, opaque id of the principal." with `id` lowercase mid-sentence and no casing on the field. The same field on `DeleteWorkspacePermissionAssignment` / `UpdateWorkspacePermissionAssignment` (model.ts:19,99) is documented as `"The ID of the user, service principal, or group."` — same concept, two different docs. Also `number` typing same precision issue as workspaceId. +### 15. `PrincipalOutput.principalId: number` opaque ID doc — `src/v1/model.ts:286-287` +- **Why weird:** Doc reads "The unique, opaque id of the principal." with `id` lowercase mid-sentence and no casing on the field. The same field on `DeleteWorkspacePermissionAssignmentRequest` / `UpdateWorkspacePermissionAssignmentRequest` (model.ts:128,368) is documented as `"The ID of the user, service principal, or group."` — same concept, two different docs. Also `number` typing same precision issue as workspaceId. - **Category:** 16 (field type contradicts domain), 17 (inconsistent doc across sibling types), 19 (underspecified ID). - **Suggested name:** Keep `principalId`, type as `bigint | string`, and use one consistent doc: `"Unique numeric identifier of the principal (user / service principal / group)."`. - **Rationale:** Three call sites for the same field, three slightly different definitions, plus a precision risk. -### 18. `UpdateWorkspacePermissionAssignment.permissions` doc paragraph — `src/v1/model.ts:101-107` -- **Why weird:** A six-line JSDoc smuggling validation semantics into a public field comment: "If both 'USER' and 'ADMIN' are provided, 'ADMIN' takes precedence. Other values will be ignored. Note that excluding this field, or providing unsupported values, will have the same effect as providing an empty list, which will result in the deletion of all permissions for the principal." That last clause is a *destructive* behaviour hidden in a paragraph. Field name `permissions` plus this doc gives the field a meaning of "set or delete" depending on contents — too much overloading for one field. +### 16. `UpdateWorkspacePermissionAssignmentRequest.permissions` doc paragraph — `src/v1/model.ts:369-376` +- **Why weird:** A multi-line JSDoc smuggling validation semantics into a public field comment: "If both 'USER' and 'ADMIN' are provided, 'ADMIN' takes precedence. Other values will be ignored. Note that excluding this field, or providing unsupported values, will have the same effect as providing an empty list, which will result in the deletion of all permissions for the principal." That last clause is a *destructive* behaviour hidden in a paragraph. Field name `permissions` plus this doc gives the field a meaning of "set or delete" depending on contents — too much overloading for one field. - **Category:** 1 (vague — overloaded semantics), 6 (misleading — looks like an additive update, can be destructive). -- **Suggested name:** Either split into `setPermissions: Permission[]` / `clearPermissions: boolean`, or rename to `replacePermissions` with explicit doc "Replaces all permissions on the principal. Pass an empty array (or omit) to revoke all permissions." +- **Suggested name:** Either split into `setPermissions: WorkspacePermission[]` / `clearPermissions: boolean`, or rename to `replacePermissions` with explicit doc "Replaces all permissions on the principal. Pass an empty array (or omit) to revoke all permissions." - **Rationale:** Hiding a "delete everything" behaviour behind an empty/missing field is a destructive-by-omission API. Type signature should make it visible. -### 19. `PrincipalOutput.principalName.servicePrincipalName: string` — `src/v1/model.ts:83-86` +## Low severity + +### 17. `PrincipalOutput.principalName.servicePrincipalName: string` — `src/v1/model.ts:281-284` - **Why weird:** A service principal's name is here typed as `string`, but the `iam` package treats service principals as either a `principalType: PrincipalType.SERVICE_PRINCIPAL` enum value or by `applicationId`. The string-only name representation here disagrees with iam's identifier model. - **Category:** 12 (duplicate concept with iam.PrincipalType.SERVICE_PRINCIPAL), 17 (inconsistent representation across siblings). - **Suggested name:** Align with iam: principalType enum + a single name/id field. If kept, rename the variant to `name` so it reads `principal.principalName.$case === 'servicePrincipal' && principal.principalName.name`. - **Rationale:** Two packages, two shapes for "the name of a service principal" — pick one. -### 20. `nextPageToken` / `prevPageToken` asymmetric naming — `src/v1/model.ts:44,46` -- **Why weird:** `nextPageToken` spells "next" out, `prevPageToken` abbreviates "prev". One or the other — `prev` vs `next` is a length mismatch with no win. -- **Category:** 5 (cryptic abbreviation `prev`), 17 (inconsistent abbreviation rule). -- **Suggested name:** `previousPageToken` (matches `nextPageToken`'s full-word style) or `prevPageToken` + `nextPageToken` paired (but then "next" is the outlier). Spell out both: `previousPageToken` / `nextPageToken`. -- **Rationale:** Symmetry — paired pagination tokens deserve paired naming. - -### 21. `GetWorkspacePermissionAssignments.filter?: string` — `src/v1/model.ts:36` -- **Why weird:** A bare `filter: string` field documented as "Filter string to search principals." Server-side query DSL hidden behind a `string`. Users must know what filter syntax to type. Same problem any time a public SDK exposes "filter" without typing the filter language. -- **Category:** 1 (vague), 15 (generic field loses meaning). -- **Suggested name:** `principalFilter` (more specific) plus a JSDoc snippet of the supported syntax. -- **Rationale:** Naming alone won't solve this, but `filter` is the worst-case name. - -## Low severity - -### 22. `GetWorkspacePermissionAssignments.maxResults` plural-confusing — `src/v1/model.ts:34` -- **Why weird:** "Maximum number of permission assignments to return." Field name uses a generic `maxResults` while the response field is `permissionAssignments`. Pair them: `maxAssignments` would read better, or document explicitly. Compare `accountaccesscontrolproxy` and other sibling packages — usage of `pageSize` is common. -- **Category:** 1 (vague), 17 (inconsistent paging field naming across packages). -- **Suggested name:** `pageSize` to align with REST list conventions (which is also what the wire param `max_results` carries in many Databricks APIs). -- **Rationale:** Consistency across the SDK; the same concept should not be `pageSize` in one package, `maxResults` in another, and `limit` in a third. - -### 23. `permissionassignments` URL fragment is one word — `src/v1/client.ts:78,106,146,174` +### 18. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` - **Why weird:** REST path uses `/permissionassignments/` (no separator), while every other Databricks REST resource in this SDK uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). This is a wire-format problem, not a TS naming problem, but it spills into the visual feel of the client URLs. - **Category:** 3 (casing/separator inconsistency). - **Suggested name:** N/A for TS, but flag upstream: prefer `permission-assignments`. - **Rationale:** Cross-API consistency. -### 24. `accountId?: string | undefined` doc placement — `src/v1/model.ts:14,15` -- **Why weird:** Doc above `accountId` says "The account ID." but the equally important fallback semantics live in `client.ts:46-48` ("Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins."). Doc is on the wrong side. +### 19. `accountId?: string | undefined` doc placement — `src/v1/model.ts:123,124` +- **Why weird:** Doc above `accountId` says "The account ID." but the equally important fallback semantics live in `client.ts:71-73` ("Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins."). Doc is on the wrong side. - **Category:** 19 (underspecified ID). - **Suggested name:** Move/duplicate the fallback semantics into the model.ts JSDoc. - **Rationale:** Most users read model.ts, not client.ts. -### 25. `displayName` doc terseness — `src/v1/model.ts:91` +### 20. `displayName` doc terseness — `src/v1/model.ts:288-289` - **Why weird:** Doc "The display name of the principal." while the discriminated union variants above carry their own names (`userName`, `groupName`, `servicePrincipalName`). Relationship between `displayName` and the variant names is undocumented (the variant names are the canonical identifier; `displayName` is the human-friendly label — but a reader has to guess). - **Category:** 1 (vague doc). - **Suggested name:** Keep field name, expand doc. - **Rationale:** A two-field name model deserves explicit roles. -### 26. `Permission.USER` doc string — `src/v1/model.ts:7-8` +### 21. `WorkspacePermission.USER` doc string — `src/v1/model.ts:41-42` - **Why weird:** Doc "The most basic workspace permission" on `USER` but no doc on `ADMIN`. Asymmetric annotation; reader concludes `ADMIN` has no doc because it's "obvious", but `USER` does because — what? The same enum in iam (`WorkspacePermission`) also docs `USER_PERMISSION` and nothing else. Pattern is consistent, but still strange. - **Category:** 17 (inconsistent annotation across enum members). - **Suggested name:** Document both, or document neither. - **Rationale:** Hover docs read better with parity. -### 27. `URL path interpolation uses unencoded segments` — `src/v1/client.ts:78,106,146,174` +### 22. URL path interpolation uses unencoded segments — `src/v1/client.ts:103,131,159,187` - **Why weird:** Not a naming finding strictly, but worth flagging: paths interpolate `${req.accountId ?? ''}` / `${String(req.workspaceId ?? '')}` directly into URLs without `encodeURIComponent`. If a malicious or weird `accountId` ever lands in here, path injection is possible. Sibling packages use the same pattern, so it's project-wide. - **Category:** N/A (security/correctness, not naming). - **Suggested name:** N/A. Flag for hardening. @@ -188,14 +165,25 @@ ## Observations -### 28. Side-by-side `getWorkspacePermissionAssignments` and `listWorkspacePermissions` — `src/v1/client.ts:102,142` -- **Why weird:** Two list-like methods, one named `get*` (returns paginated list), one named `list*` (returns a static catalog). Naming inverts the more usual REST convention where `list*` is paginated and `get*` is singular. +### 23. Side-by-side `getWorkspacePermissionAssignments` and `listWorkspacePermissions` — `src/v1/client.ts:127,155` +- **Why weird:** Two list-like methods, one named `get*` (returns array of assignments), one named `list*` (returns a static catalog). Naming inverts the more usual REST convention where `list*` is paginated and `get*` is singular. - **Category:** 17 (inconsistent action verbs), 13 (verb-tense inconsistency). -- **Suggested name:** `getWorkspacePermissionAssignments` → `listWorkspacePermissionAssignments`; `listWorkspacePermissions` → `getSupportedWorkspacePermissions`. Now `list*` always paginates, `get*` is a one-shot. -- **Rationale:** Cf. finding 5 + 6. Worth flagging once more as a pair-level observation. +- **Suggested name:** `getWorkspacePermissionAssignments` → `listWorkspacePermissionAssignments`; `listWorkspacePermissions` → `getSupportedWorkspacePermissions`. Now `list*` always returns assignments, `get*` is a one-shot catalog read. +- **Rationale:** Cf. finding 3 + 4. Worth flagging once more as a pair-level observation. ## Cross-cutting themes -1. **Non-idiomatic TS shapes.** Findings 3, 4, 7, 9 — `UNKNOWN` enum sentinel, verb-phrase request type names, `*Output` suffixes, and double-wrapped oneof discriminators. None are idiomatic TS. -2. **Duplicated domain modelling with `iam` package.** Findings 1, 2, 8, 9, 19 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. -3. **Misleading verb assignment for list vs get.** Findings 5, 6, 28 — the paginated method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. -4. **Underspecified IDs and weak typing.** Findings 10, 11, 17, 24 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. +1. **Non-idiomatic TS shapes.** Findings 5, 7 — `*Output` suffixes and double-wrapped oneof discriminators. Neither is idiomatic TS. +2. **Duplicated domain modelling with `iam` package.** Findings 1, 6, 7, 17 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. +3. **Misleading verb assignment for list vs get.** Findings 3, 4, 23 — the array-returning method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. +4. **Underspecified IDs and weak typing.** Findings 8, 9, 15, 19 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. + +## Fixed +- #2 `Permission` enum name (originally cited at `src/v1/model.ts:5`): Fixed in regeneration on 2026-05-20 — enum renamed to `WorkspacePermission` (model.ts:39), no longer a vague top-level `Permission` symbol. +- #4 `DeleteWorkspacePermissionAssignment` verb-phrase type name (originally cited at `src/v1/model.ts:13`): Fixed in regeneration on 2026-05-20 — `Request` suffix now applied across `Delete…Request`, `Get…Request`, `List…Request`, `Update…Request` (model.ts:122,203,231,362). +- #20 `nextPageToken` / `prevPageToken` asymmetric naming (originally cited at `src/v1/model.ts:44,46`): Fixed in regeneration on 2026-05-20 — pagination tokens removed from `GetWorkspacePermissionAssignmentsRequest_Response`; the response carries only `permissionAssignments` (model.ts:211-214). +- #21 `GetWorkspacePermissionAssignments.filter?: string` (originally cited at `src/v1/model.ts:36`): Fixed in regeneration on 2026-05-20 — `filter` field removed from `GetWorkspacePermissionAssignmentsRequest` (model.ts:203-208). +- #22 `GetWorkspacePermissionAssignments.maxResults` (originally cited at `src/v1/model.ts:34`): Fixed in regeneration on 2026-05-20 — `maxResults` field removed from `GetWorkspacePermissionAssignmentsRequest` (model.ts:203-208). + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index 71aec3f7..ddbbad0e 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -3,187 +3,151 @@ **Path:** `packages/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 33 +**Total weird names flagged:** 26 ## Summary | Severity | Count | | --- | --- | -| High | 10 | +| High | 4 | | Medium | 17 | | Low | 2 | -| Observation | 4 | +| Observation | 3 | -The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **the request-type-as-verb pattern** (`GetWorkspaceBindings`, `UpdateWorkspaceBindings`, `GetCatalogWorkspaceBindings`, `UpdateCatalogWorkspaceBindings`) producing the awkward `getWorkspaceBindings(req: GetWorkspaceBindings)` verb-noun-verb-noun signature; (2) **enum values that bake the type name back into every member** (`BindingType.BINDING_TYPE_READ_WRITE` etc.); (3) **stringly-typed `securableType`** that should be a closed enum; (4) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (5) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction, and the verbs "bind"/"assign" are mixed inside a single request type (`UpdateCatalogWorkspaceBindings.assignWorkspaces`). +The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **stringly-typed `securableType`** that should be a closed enum; (2) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (3) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction, and the verbs "bind"/"assign" are mixed inside a single request type (`UpdateCatalogWorkspaceBindingsRequest.assignWorkspaces`). --- ## High severity -### 1. `BindingType.BINDING_TYPE_UNSPECIFIED` / `BINDING_TYPE_READ_WRITE` / `BINDING_TYPE_READ_ONLY` (enum members) — `src/v1/model.ts:7-9` -- **Why weird:** Every enum value redundantly embeds the enum-type name (`BINDING_TYPE_`) as a prefix. At call sites this becomes `BindingType.BINDING_TYPE_READ_WRITE`, repeating the word "binding type" twice in one expression. The generator comment on line 5 explains the prefix exists to avoid wire-level conflict with a `TableOperation` enum in `credentials_common.proto` — but that is a proto-namespace concern that should not leak into the TS surface. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** `BindingType.UNSPECIFIED`, `BindingType.READ_WRITE`, `BindingType.READ_ONLY` (drop the embedded `BINDING_TYPE_` prefix; the enum-type already provides the namespace at every use site). -- **Rationale:** Google TS style guide § 5.4 (enums) recommends `EnumName.MEMBER`, not `EnumName.ENUMNAME_MEMBER`. The proto FQN-flattening trick should be hidden by the marshal layer (which already maps to/from the wire string), not surfaced to consumers. - -### 2. `BindingType.BINDING_TYPE_UNSPECIFIED` — `src/v1/model.ts:7` -- **Why weird:** Beyond #1, the `UNSPECIFIED` member itself is a proto-3 convention (proto3 enums require a zero value, conventionally `*_UNSPECIFIED`). In TS, a field of type `BindingType | undefined` already encodes "unspecified" via `undefined`. The enum member is unreachable in practice — a server returning `BINDING_TYPE_UNSPECIFIED` would be a protocol bug — and bloats the public API with a value users should never pass. -- **Category:** 2 (redundant enum value), 14 (proto/Go-style naming), 11 (trivial/unused value). -- **Suggested name:** Remove `UNSPECIFIED` from the TS enum; let `undefined` express the same state. -- **Rationale:** The TS `| undefined` modifier on `bindingType?: BindingType | undefined` already provides the absent state. Keeping `UNSPECIFIED` as an enum member duplicates that information. - -### 3. `GetCatalogWorkspaceBindings` (type) — `src/v1/model.ts:12` -- **Why weird:** Top-level request type whose name is an imperative verb phrase ("Get Catalog Workspace Bindings"). TS types should be nouns; verbs are reserved for methods. The Client also has a method `getCatalogWorkspaceBindings` (`client.ts:75`) that takes this type as input, producing the verb-noun-verb-noun signature `getCatalogWorkspaceBindings(req: GetCatalogWorkspaceBindings)`. Readers cannot tell from the type whether the identifier names the operation or the request shape. -- **Category:** 7 (overly verbose), 17 (inconsistent action verbs). -- **Suggested name:** `GetCatalogWorkspaceBindingsRequest` or `CatalogWorkspaceBindingsQuery`. Best: rename to noun form (e.g. `CatalogBindingsLookup`) to break the verb collision entirely. -- **Rationale:** Sibling SDK packages already adopt the `*Request` suffix convention. Internal consistency. - -### 4. `GetWorkspaceBindings` (type) — `src/v1/model.ts:23` -- **Why weird:** Same problem as #3. Verb-shaped request type collides with `getWorkspaceBindings` method (`client.ts:111`). -- **Category:** 7, 17. -- **Suggested name:** `GetWorkspaceBindingsRequest` or `WorkspaceBindingsListRequest`. -- **Rationale:** See #3. - -### 5. `UpdateCatalogWorkspaceBindings` (type) — `src/v1/model.ts:51` -- **Why weird:** Same problem as #3. Verb-shaped request type collides with `updateCatalogWorkspaceBindings` method (`client.ts:168`). -- **Category:** 7, 17. -- **Suggested name:** `UpdateCatalogWorkspaceBindingsRequest` or `CatalogWorkspaceBindingsPatch`. -- **Rationale:** See #3. - -### 6. `UpdateWorkspaceBindings` (type) — `src/v1/model.ts:66` -- **Why weird:** Same problem as #3. Verb-shaped request type collides with `updateWorkspaceBindings` method (`client.ts:203`). -- **Category:** 7, 17. -- **Suggested name:** `UpdateWorkspaceBindingsRequest` or `WorkspaceBindingsPatch`. -- **Rationale:** See #3. - -### 7. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` +### 1. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` - **Why weird:** Free-form `string` for what is a closed set of values. The doc-comment explicitly lists them: "(catalog, storage_credential, credential, or external_location)" — meaning the API author *knows* the set is closed but chose not to type it. A typo like `"caatalog"` will silently 4xx at the server. Also, the path is constructed via `${req.securableType ?? ''}` (`client.ts:115`, `client.ts:207`) which means an undefined value will produce a URL like `/api/2.1/unity-catalog/bindings//...` — a routing-incidental 404. - **Category:** 19 (underspecified ID/discriminator), 1 (vague), 16 (field contradicts type domain). - **Suggested name:** Define a `SecurableType` enum (`CATALOG`, `STORAGE_CREDENTIAL`, `CREDENTIAL`, `EXTERNAL_LOCATION`) and type both fields accordingly. - **Rationale:** Type-safety is the entire point of TypeScript. Other UC packages in the SDK also use bare `string` for securable types — same fix should apply across all of them. -### 8. `securableFullName` vs `catalogName` inconsistency — `src/v1/model.ts:14,53` vs `27,69` -- **Why weird:** The same conceptual value (the fully-qualified name of the securable being bound) is named two different ways depending on which request type you're looking at. `Get/UpdateCatalogWorkspaceBindings` use `catalogName` (because the legacy endpoint is catalog-specific). `Get/UpdateWorkspaceBindings` use `securableFullName` (because the generic endpoint accepts any securable). For a catalog binding, both names refer to the same string. Users porting from one variant to the other must change the field name. +### 2. `securableFullName` vs `catalogName` inconsistency — `src/v1/model.ts:14,53` vs `27,69` +- **Why weird:** The same conceptual value (the fully-qualified name of the securable being bound) is named two different ways depending on which request type you're looking at. `Get/UpdateCatalogWorkspaceBindingsRequest` use `catalogName` (because the legacy endpoint is catalog-specific). `Get/UpdateWorkspaceBindingsRequest` use `securableFullName` (because the generic endpoint accepts any securable). For a catalog binding, both names refer to the same string. Users porting from one variant to the other must change the field name. - **Category:** 17 (inconsistent naming), 15 (one is a special case of the other). - **Suggested name:** Use `fullName` everywhere (or `name`), since `securableType` already provides the discriminator. Drop the special-case `catalogName` field once the legacy API is gone. - **Rationale:** Two field names for one logical value is a documentation and onboarding tax. -### 9. Concept duplication: catalog-specific vs generic securable APIs — entire file +### 3. Concept duplication: catalog-specific vs generic securable APIs — entire file - **Why weird:** The package ships two parallel surfaces: - - `Get/UpdateCatalogWorkspaceBindings` operate on `/workspace-bindings/catalogs/{name}` (catalog-only legacy). - - `Get/UpdateWorkspaceBindings` operate on `/bindings/{securable_type}/{full_name}` (generic). -- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes (#8), different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). + - `Get/UpdateCatalogWorkspaceBindingsRequest` operate on `/workspace-bindings/catalogs/{name}` (catalog-only legacy). + - `Get/UpdateWorkspaceBindingsRequest` operate on `/bindings/{securable_type}/{full_name}` (generic). +- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes (#2), different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). - The legacy methods cannot express `READ_ONLY` bindings (they only return/accept workspace IDs, no `BindingType`) — meaning the catalog-specific API is strictly less expressive than the generic one. Yet both are shipped. - **Category:** 12 (duplicate concept within one package), 17 (inconsistency), Observation. - **Suggested name:** Either deprecate the catalog-specific surface (mark with `@deprecated`) and direct users to `getWorkspaceBindings({securableType: 'catalog', securableFullName: name})`, or rename the catalog-specific variant to make its legacy status explicit (e.g. `getCatalogWorkspaceBindingsLegacy`). - **Rationale:** Two surfaces for one operation, where one is strictly weaker, is a footgun. -### 10. Concept overlap with sibling package `workspaceassignment` — cross-package -- **Why weird:** A sibling package `packages/workspaceassignment/src/v1/` covers `WorkspacePermissionAssignment` — assigning **principals** (users, groups, service principals) to **workspaces**. The current package `workspacebindings` covers `WorkspaceBindingInfo` — assigning **securables** (catalogs, credentials, etc.) to **workspaces**. Both use the noun "workspace" and an "assign"/"bind" verb. A user searching the SDK for "how do I associate X with a workspace" will find both packages and must read both READMEs to disambiguate. There is no surface-level disambiguation in the type or method names. `workspaceassignment` even has an `assign_workspaces` / `unassign_workspaces` field in `UpdateCatalogWorkspaceBindings` (line 55, 57) — using the verb "assign" inside the *bindings* package. +### 4. Concept overlap with sibling package `workspaceassignment` — cross-package +- **Why weird:** A sibling package `packages/workspaceassignment/src/v1/` covers `WorkspacePermissionAssignment` — assigning **principals** (users, groups, service principals) to **workspaces**. The current package `workspacebindings` covers `WorkspaceBindingInfo` — assigning **securables** (catalogs, credentials, etc.) to **workspaces**. Both use the noun "workspace" and an "assign"/"bind" verb. A user searching the SDK for "how do I associate X with a workspace" will find both packages and must read both READMEs to disambiguate. There is no surface-level disambiguation in the type or method names. `workspaceassignment` even has an `assign_workspaces` / `unassign_workspaces` field in `UpdateCatalogWorkspaceBindingsRequest` (line 55, 57) — using the verb "assign" inside the *bindings* package. - **Category:** 12 (duplicate concept across packages), 17 (inconsistent verbs: "bind" vs "assign" used for adjacent operations). - **Suggested name:** Either align the verbs (both as "assign" or both as "bind") or rename one package to disambiguate directionally — e.g. `workspacebindings` → `securableworkspacebindings` or `ucbindings`; `workspaceassignment` → `workspaceprincipalassignment`. At minimum, pick one verb across the two packages. -- **Rationale:** Two packages with overlapping vocabulary and adjacent semantics is a discoverability hazard. The verb mix ("bind"/"assign") within a single request type (`UpdateCatalogWorkspaceBindings.assignWorkspaces`) actively misleads. +- **Rationale:** Two packages with overlapping vocabulary and adjacent semantics is a discoverability hazard. The verb mix ("bind"/"assign") within a single request type (`UpdateCatalogWorkspaceBindingsRequest.assignWorkspaces`) actively misleads. --- ## Medium severity -### 11. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` +### 5. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` - **Why weird:** `Info` suffix is a Go-style convention (`*Info` types in `databricks/sdk-go` are pervasive: `CatalogInfo`, `TableInfo`, `SchemaInfo`...). In TS the suffix carries no information — the type *is* the binding, not a separate "info-about-the-binding" record. Just two fields: `workspaceId` and `bindingType`. - **Category:** 14 (Go-style name), 8 (redundant suffix). - **Suggested name:** `WorkspaceBinding`. - **Rationale:** Drop Go suffixes when porting; sibling packages have already done this for some types but not consistently. -### 12. `workspaces?: number[]` (field, multiple) — `src/v1/model.ts:20,63` +### 6. `workspaces?: number[]` (field, multiple) — `src/v1/model.ts:20,63` - **Why weird:** Generic field name "workspaces" for what is actually a list of workspace IDs (not workspace objects). The doc-comment says "A list of workspace IDs" — so the wire/value is IDs, but the field is named after the entity. A consumer might reasonably expect `workspaces: Workspace[]` and be surprised by `number[]`. - **Category:** 6 (misleading: name implies entity, value is ID), 15 (generic field name), 16 (field contradicts type domain), 19 (underspecified ID). - **Suggested name:** `workspaceIds`. -- **Rationale:** Pair with `assignWorkspaces`/`unassignWorkspaces` (which have the same problem, #13, #14) for consistency. +- **Rationale:** Pair with `assignWorkspaces`/`unassignWorkspaces` (which have the same problem, #7, #8) for consistency. -### 13. `assignWorkspaces?: number[]` — `src/v1/model.ts:55` -- **Why weird:** Same problem as #12 — the field is a list of workspace IDs but is named after the entity ("workspaces"). The leading verb "assign" turns the field into a verb-phrase ("assign workspaces"), which reads as an imperative ("please assign workspaces") rather than a noun ("the set of workspace IDs to assign"). Additionally, the verb "assign" is inconsistent with the package noun "bindings" (see #10). +### 7. `assignWorkspaces?: number[]` — `src/v1/model.ts:55` +- **Why weird:** Same problem as #6 — the field is a list of workspace IDs but is named after the entity ("workspaces"). The leading verb "assign" turns the field into a verb-phrase ("assign workspaces"), which reads as an imperative ("please assign workspaces") rather than a noun ("the set of workspace IDs to assign"). Additionally, the verb "assign" is inconsistent with the package noun "bindings" (see #4). - **Category:** 6 (misleading), 17 (verb inconsistency), 19 (underspecified ID), 15 (generic field). -- **Suggested name:** `workspaceIdsToBind` or `addWorkspaceIds`, matching the `add` / `remove` pattern used in the generic `UpdateWorkspaceBindings` (lines 76, 78). +- **Suggested name:** `workspaceIdsToBind` or `addWorkspaceIds`, matching the `add` / `remove` pattern used in the generic `UpdateWorkspaceBindingsRequest` (lines 76, 78). - **Rationale:** Aligns vocabulary with package noun (binding, not assign) and clarifies the field is IDs. -### 14. `unassignWorkspaces?: number[]` — `src/v1/model.ts:57` -- **Why weird:** Same problems as #13, plus: "unassign" is a verb invented for this pair (it isn't a real English word in most dictionaries — "unassign" appears in software contexts but is dispreferred to "remove" or "revoke"). The companion field is `assignWorkspaces`, so the prefix matters here. +### 8. `unassignWorkspaces?: number[]` — `src/v1/model.ts:57` +- **Why weird:** Same problems as #7, plus: "unassign" is a verb invented for this pair (it isn't a real English word in most dictionaries — "unassign" appears in software contexts but is dispreferred to "remove" or "revoke"). The companion field is `assignWorkspaces`, so the prefix matters here. - **Category:** 6, 17, 5 (cryptic neologism), 19. - **Suggested name:** `workspaceIdsToUnbind` or `removeWorkspaceIds`. -- **Rationale:** See #13. +- **Rationale:** See #7. -### 15. `bindings?: WorkspaceBindingInfo[]` (field, multiple) — `src/v1/model.ts:43,85` +### 9. `bindings?: WorkspaceBindingInfo[]` (field, multiple) — `src/v1/model.ts:43,85` - **Why weird:** Field name `bindings` on a `WorkspaceBindings` response type — repeats the type-name fragment. The surrounding context already says "this is the workspace bindings response", so the field could safely be `items`. - **Category:** 20 (type-suffix tautology), 15 (generic). - **Suggested name:** `items` or `workspaceBindings` (more specific). - **Rationale:** A field on `XResponse` named after `X` is redundant. -### 16. `add?: WorkspaceBindingInfo[]` / `remove?: WorkspaceBindingInfo[]` — `src/v1/model.ts:76,78` -- **Why weird:** Bare verb-shaped field names (`add`, `remove`). On a `UpdateWorkspaceBindings` payload, these are *what* gets added/removed (a list of bindings), but the field names read as imperatives. The doc-comments clarify, but the field names themselves carry no noun. +### 10. `add?: WorkspaceBindingInfo[]` / `remove?: WorkspaceBindingInfo[]` — `src/v1/model.ts:76,78` +- **Why weird:** Bare verb-shaped field names (`add`, `remove`). On an `UpdateWorkspaceBindingsRequest` payload, these are *what* gets added/removed (a list of bindings), but the field names read as imperatives. The doc-comments clarify, but the field names themselves carry no noun. - **Category:** 1 (vague), 15 (generic), 17 (verb inconsistency with the catalog-specific `assignWorkspaces`/`unassignWorkspaces`). - **Suggested name:** `addBindings` / `removeBindings`, or `bindingsToAdd` / `bindingsToRemove`, or `granted` / `revoked`. - **Rationale:** A bare `add: WorkspaceBindingInfo[]` carries no noun. Common in change-set APIs but typically paired with a typed item collection. -### 17. `workspaceId?: number` — `src/v1/model.ts:90` -- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` (#12) and `assignWorkspaces?: number[]` (#13) — all three would need to migrate together. +### 11. `workspaceId?: number` — `src/v1/model.ts:90` +- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` (#6) and `assignWorkspaces?: number[]` (#7) — all three would need to migrate together. - **Category:** 16 (field contradicts type domain: 64-bit IDs typed as JS number), 19 (underspecified). - **Suggested name:** Keep the name `workspaceId` but consider `bigint` or `string` for the type. This is a project-wide concern. - **Rationale:** Cross-cutting JS interop issue; not unique to this package, but flagged for completeness. -### 18. `bindingType?: BindingType` — `src/v1/model.ts:92` -- **Why weird:** Field name `bindingType` on a type called `WorkspaceBindingInfo` repeats the type-name fragment "binding". Combined with #1, the call site reads `binding.bindingType === BindingType.BINDING_TYPE_READ_WRITE` — "binding"/"binding"/"binding type"/"binding type" four times in one expression. +### 12. `bindingType?: BindingType` — `src/v1/model.ts:92` +- **Why weird:** Field name `bindingType` on a type called `WorkspaceBindingInfo` repeats the type-name fragment "binding". The call site reads `binding.bindingType` — "binding"/"binding type" repeated in one expression. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `accessLevel` (more descriptive — the value indicates read/write vs read-only access), or just `type` (since context is clear). - **Rationale:** Field on `XBindingInfo` named `xBindingType` is doubly redundant. -### 19. `maxResults?: number` — `src/v1/model.ts:35` +### 13. `maxResults?: number` — `src/v1/model.ts:35` - **Why weird:** 12 lines of doc-comment for one field explain its conditional behaviour ("set to 0" / "set to a value greater than 0" / "set to a value less than 0" / "if not set"). The field name `maxResults` doesn't hint at the magic-value semantics. Also, sibling packages use `pageSize` for the same concept (see grants audit #18) — naming inconsistency across the SDK. - **Category:** 17 (cross-package inconsistency), 6 (misleading: name implies a strict cap but actually has magic-value semantics). - **Suggested name:** `pageSize` (matching sibling packages) or `pageLength`. Document the magic values via a `@see` link rather than copy-pasting 12 lines. - **Rationale:** Cross-package consistency. -### 20. `pageToken?: string` doc — `src/v1/model.ts:36-37` +### 14. `pageToken?: string` doc — `src/v1/model.ts:36-37` - **Why weird:** Doc-comment "Opaque pagination token to go to next page based on previous query" is OK, but in the response side `nextPageToken` (line 45-48) the doc refers to "__page_token__" with double-underscores — a documentation hangover from a wire-format spec. Inconsistent with the TS field name `pageToken`. - **Category:** 6 (misleading docs), Observation. - **Suggested name:** Field name is fine; fix the doc to use TS field name `pageToken`. - **Rationale:** Doc-comment consistency. -### 21. `nextPageToken?: string` — `src/v1/model.ts:48` +### 15. `nextPageToken?: string` — `src/v1/model.ts:48` - **Why weird:** The doc-comment includes `__page_token__` (double-underscore) referring to the request field. The actual TS field is named `pageToken` — the doc is documenting wire format, not TS. - **Category:** 6 (misleading docs). - **Suggested name:** Field name is fine; fix the doc text. -- **Rationale:** See #20. +- **Rationale:** See #14. -### 22. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:75` -- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #9). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 71-74 makes no mention of the generic alternative. +### 16. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:75` +- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #3). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 71-74 makes no mention of the generic alternative. - **Category:** 12 (duplicate concept), Observation. - **Suggested name:** Mark with `@deprecated` JSDoc and reference `getWorkspaceBindings`. - **Rationale:** IDE strike-through requires the `@deprecated` tag. -### 23. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:168` -- **Why weird:** Same as #22. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. +### 17. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:168` +- **Why weird:** Same as #16. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. - **Category:** 12, Observation. - **Suggested name:** Mark with `@deprecated`. -- **Rationale:** See #22. +- **Rationale:** See #16. -### 24. `Client` — `src/v1/client.ts:46` +### 18. `Client` — `src/v1/client.ts:46` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `WorkspaceBindingsClient`. - **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. -### 25. `executeCall` — `src/v1/utils.ts:26` +### 19. `executeCall` — `src/v1/utils.ts:26` - **Why weird:** Generic verb-noun name. Two `execute` functions in scope (`execute` imported on line 4, `executeCall` defined on line 26, `executeHttpCall` defined on line 65). The discriminator between them is just "Call" vs "HttpCall" — and both ultimately wrap the imported `execute()`. - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `executeRetryableCall` (since this one applies the retrier/rateLimiter/timeout options) or `executeWithOptions`. - **Rationale:** Distinguishes the two wrappers semantically. -### 26. `executeHttpCall` — `src/v1/utils.ts:65` -- **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `APIError` on 4xx/5xx (line 88-91) — a non-obvious side effect. +### 20. `executeHttpCall` — `src/v1/utils.ts:65` +- **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `ApiError` on 4xx/5xx (line 88-91) — a non-obvious side effect. - **Category:** 1 (vague), 6 (misleading: "execute" sounds neutral but throws). - **Suggested name:** `sendAndParseResponse` or `sendOrThrow`. - **Rationale:** Naming should hint at error semantics. -### 27. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` +### 21. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` - **Why weird:** Yet another `*Options` suffix in a file that already imports `Options` (line 3) and `CallOptions` (line 12) — three `Options` types in scope. `HttpCallOptions` is purely an internal context bag for `executeHttpCall` (request + httpClient + logger) — it isn't user-tunable, so `Options` is misleading. - **Category:** 1 (vague suffix), 8 (redundant suffix), 17 (inconsistency). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -193,13 +157,13 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Low severity -### 28. `flattenQueryParams` — `src/v1/utils.ts:123` +### 22. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append` on `client.ts:117-122`). Dead-looking export from the standard generator template. - **Category:** Observation, 11 (unused public helper). - **Suggested name:** Remove if generator default; or move to a shared utility package and not emit per-package. - **Rationale:** Cross-package consistency. -### 29. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -209,18 +173,23 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Observations -### 30. Client `Host is required.` error message — `src/v1/client.ts:57` +### 24. Client `Host is required.` error message — `src/v1/client.ts:57` The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. - **Category:** Observation. -### 31. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` +### 25. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` The marshal/unmarshal helpers are exported from `model.ts` (via `export const`) but `index.ts` (lines 7-17) only re-exports types and `Client`. So the schemas are part of the package's effective import surface (`import {...} from '@databricks/sdk-workspacebindings/v1/model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). - **Category:** Observation, 11 (effectively-internal exports). -### 32. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` +### 26. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` The single word "Required" appears as a doc-comment on `workspaceId?: number`. But the field is *optional* in the TypeScript type (`workspaceId?: number | undefined`). The annotation contradicts the type modifier. Either: (a) the field is genuinely required by the server and the optional TS type is generator-wide policy (proto3 fields are all optional in TS); or (b) the doc is stale. Either way, readers can't tell. - **Category:** Observation, 6 (misleading docs). -### 33. `BindingType` doc-comment surfaces proto comment as TS doc — `src/v1/model.ts:5` -The comment "Using `BINDING_TYPE_` prefix here to avoid conflict with `TableOperation` enum in `credentials_common.proto`." is a wire-implementation note that has been promoted to a TS doc-comment. TS consumers should not need to know about proto namespaces. This is naming-adjacent — the comment exists *because* of the redundant prefix (#1, #2). Removing the prefix would also remove the need for the explanation. -- **Category:** Observation, 14 (proto-style naming surfaced in docs). +--- + +## Fixed + +- #3 `GetCatalogWorkspaceBindings` (originally cited at `src/v1/model.ts:12`): Fixed in regeneration on 2026-05-20 — renamed to `GetCatalogWorkspaceBindingsRequest` (suffix added). +- #4 `GetWorkspaceBindings` (originally cited at `src/v1/model.ts:23`): Fixed in regeneration on 2026-05-20 — renamed to `GetWorkspaceBindingsRequest` (suffix added). +- #5 `UpdateCatalogWorkspaceBindings` (originally cited at `src/v1/model.ts:51`): Fixed in regeneration on 2026-05-20 — renamed to `UpdateCatalogWorkspaceBindingsRequest` (suffix added). +- #6 `UpdateWorkspaceBindings` (originally cited at `src/v1/model.ts:66`): Fixed in regeneration on 2026-05-20 — renamed to `UpdateWorkspaceBindingsRequest` (suffix added). diff --git a/.agent/naming-audit/workspaceconf.md b/.agent/naming-audit/workspaceconf.md index c915bd70..17860a22 100644 --- a/.agent/naming-audit/workspaceconf.md +++ b/.agent/naming-audit/workspaceconf.md @@ -1,5 +1,9 @@ # Naming Audit: workspaceconf +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `/home/parth.bansal/sdk-js/packages/workspaceconf/` **Versions audited:** v1 **Inferred domain:** Reads and writes a workspace's "known configuration" key/value entries — a generic `map[string]string` bag of advanced workspace toggles served from `/api/2.0/workspace-conf`. The legacy Go SDK calls this surface `WorkspaceConf` with methods `GetStatus`/`SetStatus`. @@ -29,27 +33,27 @@ | # | Severity | Category | Identifier | File:line | |---|----------|----------|------------|-----------| | 1 | High | Cryptic abbreviation (package-wide) | package name `workspaceconf` / `@databricks/sdk-workspaceconf` | `package.json:2` | -| 2 | High | Cryptic abbreviation, Type-suffix tautology | `WorkspaceConf` (interface) | `model.ts:9-12` | +| 2 | High | Cryptic abbreviation, Type-suffix tautology | `WorkspaceConfRequest` (interface) | `model.ts:9-12` | | 3 | High | Cryptic abbreviation, Overly verbose | `GetWorkspaceConfRequest` | `model.ts:5-7` | | 4 | High | Misleading / inconsistent action verb | `updateWorkspaceConf` method (PATCH that actually replaces / `SetStatus` upstream) | `client.ts:89` | | 5 | High | Misleading / generic field name | `keys?: string` (single CSV string, not an array) | `model.ts:6` | -| 6 | High | Misleading / wire-shape regression vs Go SDK | `WorkspaceConf = {key, value}` (Go is `map[string]string`) | `model.ts:9-12` | +| 6 | High | Misleading / wire-shape regression vs Go SDK | `WorkspaceConfRequest = {key, value}` (Go is `map[string]string`) | `model.ts:9-12` | | 7 | High | Duplicate concept | `workspaceconf` vs `workspacesettings` | package level | | 8 | High | Generic field name losing meaning | `key?` / `value?` fields | `model.ts:10-11` | | 9 | Medium | Method name redundancy | `Client.getWorkspaceConf` / `Client.updateWorkspaceConf` | `client.ts:58, 89` | | 10 | Medium | Verb-tense inconsistency cross-package | TS `getWorkspaceConf`/`updateWorkspaceConf` vs Go `GetStatus`/`SetStatus` | `client.ts` vs Go SDK | | 11 | Medium | Singular/plural mismatch | `keys` (plural query arg) on a request that returns *one* `{key, value}` | `model.ts:6` vs `model.ts:9-12` | -| 12 | Medium | Singular/plural mismatch | `WorkspaceConf` (singular type) but the endpoint accepts/returns a *map* | `model.ts:9-12` | +| 12 | Medium | Singular/plural mismatch | `WorkspaceConfRequest` (singular type) but the endpoint accepts/returns a *map* | `model.ts:9-12` | | 13 | Medium | Overly verbose / module JSDoc missing | no `index.ts` module-level JSDoc explaining the package's scope | `index.ts:1-8` | | 14 | Medium | Reserved-word adjacency | `key` (TS-friendly but shadows builtin `Map.prototype.keys`) | `model.ts:10` | -| 15 | Medium | Misleading | TS `WorkspaceConf` is also the *request* body of `updateWorkspaceConf` *and* the *response* of `getWorkspaceConf` — single name, two roles | `client.ts:58-86, 89-106` | +| 15 | Medium | Misleading suffix | `WorkspaceConfRequest` is also the *response* of `getWorkspaceConf` — the `Request` suffix lies | `client.ts:61, 90` | | 16 | Medium | Misleading PATCH semantics | "Sets the configuration status … including enabling or disabling it." | `client.ts:88` | | 17 | Low | Acronym casing inconsistency | `Conf` vs spelled-out `Config` across SDK packages | cross-package | | 18 | Low | Verbose JSDoc | "Gets the configuration status for a workspace." / "Sets the configuration status …" | `client.ts:57, 88` | | 19 | Low | Underspecified ID | `keys` accepts comma-separated string of unspecified vocabulary | `model.ts:6` | -| 20 | Low | Type-suffix tautology | `WorkspaceConf` inside package `workspaceconf` → triple stutter | `model.ts:9` | +| 20 | Low | Type-suffix tautology | `WorkspaceConfRequest` inside package `workspaceconf` → triple stutter | `model.ts:9` | | 21 | Low | Module-doc location | no top-of-file JSDoc on `index.ts` (per CLAUDE.md §10.6) | `index.ts` | -| 22 | Low | Field contradicting type domain | `WorkspaceConf.value` typed `string`, but actual values are stringified booleans/numbers | `model.ts:11` | +| 22 | Low | Field contradicting type domain | `WorkspaceConfRequest.value` typed `string`, but actual values are stringified booleans/numbers | `model.ts:11` | | 23 | Low | Inconsistent action verb | `updateWorkspaceConf` (TS) corresponds to HTTP `PATCH` with **full-bag-replace** server semantics | `client.ts:98` | --- @@ -62,11 +66,11 @@ - **Suggestion:** **`workspaceconfig`** (or `workspaceconfiguration` if the SDK is verbose-friendly). Equivalently, scoped name `@databricks/sdk-workspaceconfig`. - **Rationale:** "conf" is not a standard abbreviation of "configuration" in any major TS/JS style guide. The Google TS style guide explicitly forbids non-conventional abbreviations (§5.4 *Abbreviations*: "Treat abbreviations like acronyms in names as whole words … Don't use abbreviations that are not widely accepted within the team or community"). The TS SDK already uses fully spelled-out forms in sibling packages (`workspacesettings`, `workspaceassignment`, `workspacebindings`) so "workspaceconf" stands out as the lone abbreviated package. The legacy Go SDK is *also* fully spelled-out — `WorkspaceConf` is the legacy type name in `service/settings`, but the *package* there is `settings`, not `workspaceconf`. This package name is a JS-SDK invention and could be fixed at the generator level with no Go-SDK churn. -### 2. `WorkspaceConf` (interface) — cryptic + tautological +### 2. `WorkspaceConfRequest` (interface) — cryptic + tautological - **File:line:** `model.ts:9-12` - **Category:** Cryptic abbreviation, type-suffix tautology, duplicate-concept. - **Suggestion:** Rename the interface to `WorkspaceConfigEntry` (because it represents *one* key/value pair — see §6) and rename the package to `workspaceconfig` (§1). Then the type read by the consumer becomes `workspaceconfig.Entry` — semantically clear, no abbreviation. -- **Rationale:** Three problems at once. (a) "Conf" is cryptic (§1). (b) Inside a package literally named `workspaceconf`, the type `WorkspaceConf` triple-stutters when consumed (`workspaceconf.WorkspaceConf`). (c) The name does not describe the shape: in the TS port it is a single key/value pair, *not* the workspace configuration as a whole (see §6 for why this is also wrong). +- **Rationale:** Three problems at once. (a) "Conf" is cryptic (§1). (b) Inside a package literally named `workspaceconf`, the type `WorkspaceConfRequest` stutters when consumed (`workspaceconf.WorkspaceConfRequest`). (c) The name does not describe the shape: in the TS port it is a single key/value pair, *not* the workspace configuration as a whole (see §6 for why this is also wrong). The `Request` suffix added in regeneration also lies about the role — the type is used as both request body and response value (see §15). ### 3. `GetWorkspaceConfRequest` — cryptic + verbose - **File:line:** `model.ts:5-7` @@ -86,7 +90,7 @@ - **Suggestion:** Rename to `configKeys?: readonly string[]` (true array, not a CSV string) and let `flattenQueryParams` / `URLSearchParams` handle list-style query encoding. If the backend genuinely takes a CSV string, document that in a JSDoc on the field; do not make the SDK type lie. - **Rationale:** Three problems. (a) Generic: "keys" on a request type without context means nothing — *which* keys, of *what*? Compare `configKeys` which immediately answers. (b) Plural form `keys` is a TS-array idiom that the type contradicts (`string`, not `string[]`). (c) The upstream API accepts a comma-separated string, but a strongly-typed SDK should accept `string[]` and serialize the comma-join itself; the current `keys?: string` punts string-encoding to the caller. The Go SDK has the same shape (`Keys string`) — that's a Go-SDK limitation worth fixing in the JS port, not faithfully reproducing. -### 6. `WorkspaceConf = {key, value}` — wire-shape regression vs Go SDK (CRITICAL) +### 6. `WorkspaceConfRequest = {key, value}` — wire-shape regression vs Go SDK (CRITICAL) - **File:line:** `model.ts:9-12` - **Category:** Misleading / Generic field names losing meaning / wire-shape divergence. - **Suggestion:** Change the type to match upstream semantics: `WorkspaceConfig = Readonly>` (or `Map`). The endpoint `/api/2.0/workspace-conf` accepts and returns a map of multiple key/value pairs; the current `{key?: string; value?: string}` cannot represent that. @@ -103,7 +107,7 @@ i.e. the request and response are *both* a map of arbitrary keys to string values. - The TS port has: ```ts - export interface WorkspaceConf { + export interface WorkspaceConfRequest { key?: string | undefined; value?: string | undefined; } @@ -112,7 +116,7 @@ 1. Cannot represent the multi-entry response that the API actually returns (e.g. fetching multiple keys via `keys=k1,k2` returns `{"k1":"v1","k2":"v2"}`, not `{key:"k1",value:"v1"}`). 2. Cannot update more than one toggle at a time, while the legacy semantics permit a single PATCH to flip many. 3. Will round-trip through zod and either fail validation or silently drop fields on every realistic payload. - - The bug is *naming-shaped* — the wire format is a string→string map; the type and its fields name a single pair — so it qualifies as a naming audit finding (the type name `WorkspaceConf` promises the whole config and delivers one pair). It is also a correctness bug that should be filed against the generator. This is the *single most important* finding in this audit. + - The bug is *naming-shaped* — the wire format is a string→string map; the type and its fields name a single pair — so it qualifies as a naming audit finding (the type name `WorkspaceConfRequest` promises the whole config and delivers one pair). It is also a correctness bug that should be filed against the generator. This is the *single most important* finding in this audit. ### 7. `workspaceconf` vs `workspacesettings` — duplicate concept, undisclosed - **File:line:** package level @@ -126,7 +130,7 @@ - **File:line:** `model.ts:10-11` - **Category:** Generic field name losing meaning. - **Suggestion:** Once §6 is fixed (`WorkspaceConfig = Record`), the generic names go away: a map has named keys at runtime. If the wire-shape is genuinely a singleton pair (it is not, per §6), rename to `configKey` / `configValue` to add domain context. -- **Rationale:** Within a single package, every public type/method ends up reading `WorkspaceConf.key` / `WorkspaceConf.value` — but there is no signal of *what* the key is keyed by or *what* the value represents. Domain-bearing field names (e.g. `configKey: string`, `configValue: string`) make IDE hover meaningful. +- **Rationale:** Within a single package, every public type/method ends up reading `WorkspaceConfRequest.key` / `WorkspaceConfRequest.value` — but there is no signal of *what* the key is keyed by or *what* the value represents. Domain-bearing field names (e.g. `configKey: string`, `configValue: string`) make IDE hover meaningful. --- @@ -150,7 +154,7 @@ - **Suggestion:** Once §6 is fixed (return-type becomes a map), the plural request shape matches the plural response shape and this finding dissolves. - **Rationale:** This is the surface symptom of §6. The request says "give me values for these keys (plural)" but the response can only carry one key. This is internally contradictory. -### 12. `WorkspaceConf` (singular type) used for a map endpoint — singular/plural mismatch +### 12. `WorkspaceConfRequest` (singular type) used for a map endpoint — singular/plural mismatch - **File:line:** `model.ts:9-12` - **Category:** Singular/plural mismatch. - **Suggestion:** See §6. If the type stays a single entry, rename it `WorkspaceConfigEntry` (singular noun matching singular shape). @@ -168,11 +172,11 @@ - **Suggestion:** Rename to `configKey` (clearer, no collision risk). - **Rationale:** `key` is not strictly reserved, but it collides with `Map.prototype.keys`, `Object.keys`, React's `key` prop, etc., so type-narrowing in user code can become ambiguous. A package-specific prefix removes the collision. -### 15. `WorkspaceConf` overloaded as request *and* response type — misleading -- **File:line:** `client.ts:61, 90` (used as both `Promise` return and `req: WorkspaceConf` argument). -- **Category:** Misleading / duplicate concept. +### 15. `WorkspaceConfRequest` named "Request" but also used as response — misleading suffix +- **File:line:** `client.ts:61, 90` (used as both `Promise` return and `req: WorkspaceConfRequest` argument). +- **Category:** Misleading suffix / duplicate concept. - **Suggestion:** Split into `WorkspaceConfig` (response — the full map) and `UpdateWorkspaceConfigRequest` (request — a `Partial` or `Record` of just the keys to set). The Go SDK gets away with the overload because the type *is* the map, but the TS port's `{key, value}` shape (§6) makes this overload doubly confusing. -- **Rationale:** Using the same type for the request and the response works only when the wire shape is symmetric *and* the type name is shape-accurate. Here it's neither. +- **Rationale:** The regeneration added a `Request` suffix to what used to be `WorkspaceConf`, but the type is still returned by `getWorkspaceConf` as `Promise` (client.ts:61). A type named `…Request` that is also a response value is actively misleading — naming-convention readers expect `…Request` to be input-only. Either drop the suffix (use `WorkspaceConfig`) or split into distinct request and response types. Using the same shape for both works only when the wire shape is symmetric *and* the type name is shape-accurate; here it's neither, and the suffix now compounds the confusion. ### 16. PATCH but full-replace — misleading HTTP semantics - **File:line:** `client.ts:88` (JSDoc: "Sets the configuration status …"), `client.ts:98` (HTTP `PATCH`). @@ -202,8 +206,8 @@ - **Suggestion:** Either link to the Databricks docs that enumerate the valid keys ("enableIpAccessLists", "maxTokenLifetimeDays", "enableProjectTypeInWorkspace", …) or accept a typed union of known string-literal keys. - **Rationale:** A user can't construct a valid request without finding the key vocabulary somewhere external. Documenting the legal set is a 10-minute fix and dramatically improves usability. -### 20. Type-suffix tautology `workspaceconf.WorkspaceConf` -- **File:line:** `model.ts:9` (and every consumer importing `workspaceconf.WorkspaceConf`). +### 20. Type-suffix tautology `workspaceconf.WorkspaceConfRequest` +- **File:line:** `model.ts:9` (and every consumer importing `workspaceconf.WorkspaceConfRequest`). - **Category:** Type-suffix tautology. - **Suggestion:** Drop the package prefix from the type name (per §2 — once §1 is done, `WorkspaceConfig` -> `Entry` or `Config`). - **Rationale:** Same pattern as `accountsettings.PersonalComputeSetting` flagged in the `accountsettings` audit (severity #12-15 there). TS users access via package; the package prefix on the type name is gratuitous. @@ -243,3 +247,11 @@ 3. **Add module-level JSDoc** to `index.ts` (§7, §13, §21) explaining the package's role and its relationship to `workspacesettings`. 4. **Rename the method pair** to `get` / `set` (or `getConfig` / `setConfig`) for cross-SDK and HTTP-semantic accuracy (§4, §9, §10, §23). 5. **Type `keys` as `string[]`** (§5) and have the client serialize the CSV. + +--- + +## Fixed + +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. + +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspaceobjects.md b/.agent/naming-audit/workspaceobjects.md new file mode 100644 index 00000000..971daf42 --- /dev/null +++ b/.agent/naming-audit/workspaceobjects.md @@ -0,0 +1,425 @@ +# Naming Audit: workspaceobjects + +**Path:** `packages/workspaceobjects/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Databricks workspace filesystem-style operations on +notebooks, folders, and files — import, export, delete, list, get-status, +and mkdirs against absolute paths under `/Workspace`. Wire prefix: +`/api/2.0/workspace/`. +**Total weird names flagged:** 23 + +## Scope note: `workspaceobjects` vs sibling packages + +The Databricks SDK ships several packages whose names begin with "workspace". +This audit covers the filesystem-objects package, `workspaceobjects`; the +others differ in scope: + +| Package | Domain | Wire prefix | +|---------|--------|-------------| +| `workspaceobjects` (this audit) | Workspace filesystem (notebooks/folders/files) | `/api/2.0/workspace/` | +| `workspaceassignment` | Account-level principal-to-workspace permission assignments | account API | +| `workspacebindings` | Securable-to-workspace bindings (catalog/credential/location) | Unity Catalog API | +| `workspaceconf` | Untyped key/value workspace configuration | `/api/2.0/workspace-conf` | +| `workspacesettings` | Strongly-typed workspace settings (compliance security profile, automatic cluster update, etc.) | various `/api/2.0/settings/*` | +| `workspaces` | Account-level workspace lifecycle (create/list/delete workspaces) | accounts API | + +## Summary + +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 12 | +| Low | 6 | +| Observation | 6 | + +## Summary table + +| # | Severity | Location | Name | Category | +|---|----------|----------|------|----------| +| 1 | High | `model.ts:6` enum | `ExportFormat` used as `format` field of `ImportRequest` | Misleading name (an "ExportFormat" governs imports too) | +| 2 | High | `model.ts:18` enum value | `ExportFormat.AUTO` | Ambiguous enum value (different behaviour for import vs. export) | +| 3 | High | `model.ts:24` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | +| 4 | High | `model.ts:195,199` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | +| 5 | High | `model.ts:28` enum | `Language` | Vague/generic, no domain prefix | +| 6 | Medium | `model.ts:48` enum value | `ObjectType.LIBRARY` | Misleading (workspace libraries are an obsolete concept) | +| 7 | Medium | `model.ts:153` field | `ListRequest.notebooksModifiedAfter` | Field contradicts type domain (list returns all object types, filter only on notebooks) | +| 8 | Medium | `model.ts:92` field | `ExportRequest.directDownload` | Verb-as-noun boolean (toggles response content-type entirely) | +| 9 | Medium | `model.ts:104` field | `ExportRequest_Response.fileType` | Underspecified (extension? MIME? format enum?) | +| 10 | Medium | `model.ts:102` field | `ExportRequest_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | +| 11 | Medium | `model.ts:138` field | `ImportRequest.content` typed `Uint8Array` | Same type/JSDoc mismatch as 10 in reverse direction | +| 12 | Medium | `model.ts:191,193` fields | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Unit ambiguity (epoch millis as `number`), "only applicable to files" | +| 13 | Medium | `model.ts:197` field | `ObjectInfo.size` | Underspecified — no unit in the name (bytes per JSDoc) | +| 14 | Medium | `model.ts:167` field | `MkdirsRequest.path` | Singular/plural mismatch — type plural, field singular | +| 15 | Medium | `model.ts:162` type | `MkdirsRequest` | Unix-ism (`mkdir -p`); sibling `files` package uses `createDirectory` | +| 16 | Medium | `client.ts:157` method | `getStatus` | Vague verb; returns full `ObjectInfo` metadata (a `stat`, not a status) | +| 17 | Medium | `model.ts:66` field | `DeleteRequest.recursive` | Unix flag (`rm -r`); no domain reading | +| 18 | Low | `model.ts:16` enum value | `ExportFormat.R_MARKDOWN` | Shape mismatch — single underscored value among single-token values | +| 19 | Low | `model.ts:14` enum value | `ExportFormat.DBC` | Cryptic product-specific abbreviation (Databricks archive) | +| 20 | Low | `model.ts:174` interface | `ObjectInfo` | `Info` suffix carries no information; central entity is just an "Object" | +| 21 | Low | `model.ts:159` field | `ListRequest_Response.objects` | Generic field name (`objects`) for `ObjectInfo[]` | +| 22 | Low | `client.ts:266` method | `mkdirs` | Lower-case Unix contraction next to other `verbNoun` methods (`getStatus`, `import`, `export`) | +| 23 | Low | `model.ts:17-23` JSDoc | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | + +## High severity + +### 1. `ExportFormat` reused for `ImportRequest.format` — misleading enum +- **Location:** `model.ts:6` (declaration); used as `ImportRequest.format` at `model.ts:129` and `ExportRequest.format` at `model.ts:87`. +- **Category:** Misleading name — the enum name encodes a single direction + (export) but the type is used both ways. +- **Suggested name:** `WorkspaceObjectFormat` or `NotebookFormat`. The wire + string values stay the same; the TS identifier becomes direction-neutral. +- **Rationale:** The JSDoc on the enum already says "for workspace import and + export." The asymmetry is more than cosmetic: `ImportRequest.format`'s + JSDoc documents `AUTO` as "depending on extension," while + `ExportRequest.format`'s JSDoc documents `AUTO` as "depending on object + type." Same enum value, different server-side algorithm — see finding 2. + A neutral name removes the "for export" implication. + +### 2. `ExportFormat.AUTO` — ambiguous enum value +- **Location:** `model.ts:17-18` +- **Category:** Ambiguous / context-sensitive enum value. +- **Suggested name:** Split into two distinct enums per direction, or + rename to `DETECT_FROM_CONTENT` (import meaning) and document the export + meaning separately, or drop entirely and pick a default server-side. +- **Rationale:** `AUTO` reads as "let the server pick a format," but the + picking algorithm differs per direction. For imports, the server inspects + payload extension and content header. For exports, the server picks + based on the object's type. One name, two algorithms is exactly the + failure mode of overloaded enum values. + +### 3. `ExportFormat.RAW` — vague enum value +- **Location:** `model.ts:19-24` +- **Category:** Vague enum value — names a behaviour, not a format. +- **Suggested name:** `ZIP_PASSTHROUGH` or `BINARY` (or `BYTES_AS_IS`). +- **Rationale:** `RAW` does not name a format — it names a behaviour ("no + decoding, store as-is"). The JSDoc is a story about why the value exists + ("This is introduced to unblock a DR use case importing .zip file as is") + rather than what it represents. The value's existence is also gated on a + server-side roadmap ("In workspace 3.0 folder import will be supported via + a different API") that the SDK user does not see. + +### 4. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names +- **Location:** `model.ts:194-199` +- **Category:** Duplicate concept; near-identical names hide a real + type/lifetime distinction. +- **Suggested name:** `legacyObjectId` (deprecated, `bigint` or `string` to + preserve precision) and keep `resourceId`. Alternatively + `localObjectId` (workspace-scoped, numeric) and `globalResourceId` + (cross-API, string). Or drop the legacy one and only carry `resourceId`. +- **Rationale:** Two distinct identifiers live on the same `ObjectInfo`, + both documented as "unique identifier for the object," differing only by + the trailing phrase "consistent across all Databricks APIs." The name + pair does not encode the difference — a reader sees `objectId` (number) + and `resourceId` (string) and cannot tell which one to pass into another + Databricks API. Likely truth: `objectId` is the legacy 64-bit numeric + workspace-local ID; `resourceId` is the newer string ID used by the + unified-resource API. The names should encode that distinction. Also: + `objectId` is typed `number` — JS numbers are 64-bit floats and lose + precision above 2^53; the field type should be `bigint` or `string`. + +### 5. `Language` — vague / generic, no domain prefix +- **Location:** `model.ts:28-37` +- **Category:** Vague/generic top-level name. +- **Suggested name:** `NotebookLanguage`. +- **Rationale:** A top-level export called `Language` in a domain package + is an attractive nuisance. Several other Databricks SDK domains touch + "language" (`apps` runtimes, `jobs` task language, `clusters` runtime + languages, `pipelines` SQL/Python). A user importing two SDK packages can + end up with two clashing `Language` symbols. The wire field is + `notebook.language`; `NotebookLanguage` is the natural domain prefix. + +## Medium severity + +### 6. `ObjectType.LIBRARY` — obsolete enum value +- **Location:** `model.ts:48` +- **Category:** Misleading enum value (encoded concept is obsolete). +- **Suggested name:** Keep the name but mark `@deprecated` in JSDoc with a + pointer to the cluster-libraries / job-libraries APIs. +- **Rationale:** Workspace "libraries" as a top-level object type were + superseded years ago by cluster-level and job-level library + configurations. The value is exported in `ObjectType` without a + deprecation marker. Consumers writing `if (obj.objectType === + ObjectType.LIBRARY)` are coding against a branch the server almost never + returns; that is a discoverability hazard. + +### 7. `ListRequest.notebooksModifiedAfter` — field contradicts type domain +- **Location:** `model.ts:149-154` +- **Category:** Field contradicts the type it lives on; unit hidden in JSDoc. +- **Suggested name:** `modifiedAfterMillis` (drop the `notebooks` qualifier + and document the asymmetry) or `notebookModifiedAfterMillis` (singular + subject, matching the filter's actual scope) plus an explicit + millisecond suffix. +- **Rationale:** `list` returns all workspace object types — notebooks, + directories, files, repos, dashboards. The filter parameter is named + `notebooksModifiedAfter`, i.e. the filter only applies to objects of + type `NOTEBOOK`. Non-notebook objects are not filtered, so a caller + expecting `modifiedAfter` semantics will see directories whose contents + post-date the supplied cutoff. The asymmetry is invisible from the name. + Also: the unit (milliseconds) lives only in JSDoc; the sibling + `ObjectInfo.createdAt` / `modifiedAt` fields are also `number` without + unit-in-name — see finding 12. + +### 8. `ExportRequest.directDownload` — verb-as-noun boolean +- **Location:** `model.ts:88-92` +- **Category:** Verb-as-noun naming; boolean named like a noun. +- **Suggested name:** `streamBinary`, `responseAsBinary`, or + `returnBytesDirectly` — anything that parses as a boolean adjective. +- **Rationale:** `directDownload` reads as a noun phrase. Booleans + conventionally use `is`/`has`/`should`/`return*` prefixes or adjective + forms. There is also a real semantic problem: when `true`, the server + returns raw bytes; when `false`, the server returns JSON with base64. + Setting `directDownload: true` would make `parseResponse` in `utils.ts` + crash (it does `JSON.parse` unconditionally), so the boolean cannot be + set safely from this client today. The name should at least flag the + fact that the response shape changes. + +### 9. `ExportRequest_Response.fileType` — underspecified +- **Location:** `model.ts:103-105` +- **Category:** Underspecified field — name is one of the most overloaded + strings in software, type is `string`. +- **Suggested name:** `mimeType`, `extension`, or `format: ExportFormat` + (pick one and commit). +- **Rationale:** "The file type" doesn't say in what form — extension + (`.ipynb`)? MIME (`application/x-ipynb+json`)? Enum (`JUPYTER`)? Object + kind (`NOTEBOOK`)? With the field typed as `string`, any of those is + syntactically valid; the user has to read upstream docs to know which. + +### 10. `ExportRequest_Response.content` — type contradicts "base64-encoded" JSDoc +- **Location:** `model.ts:98-102`; decoded via `marshalSchema` transform at + `model.ts:211-213`. +- **Category:** Type/JSDoc mismatch. +- **Suggested name:** Keep the field name, fix the JSDoc to say "Raw bytes + decoded from the server's base64 encoding," or rename to `bytes`. +- **Rationale:** The JSDoc says the content is base64-encoded; the type is + `Uint8Array` (raw bytes). The transform schema does `atob(s).charCodeAt` + before populating the field, so the field already holds decoded bytes. + The JSDoc was lifted from the wire-format documentation and never + updated for the post-decode shape. "Uint8Array of base64-encoded data" + is technically meaningless. + +### 11. `ImportRequest.content` — type contradicts "base64-encoded" JSDoc +- **Location:** `model.ts:132-138`; encoded via `marshalSchema` transform + at `model.ts:276-281`. +- **Category:** Type/JSDoc mismatch (mirror of 10). +- **Suggested name:** Keep the name; fix the JSDoc to say "Raw bytes; the + client base64-encodes before sending." +- **Rationale:** The mirror of finding 10 in the reverse direction. The + client encodes the bytes to base64 before sending. A defensive caller + who reads the JSDoc and base64-encodes their bytes will double-encode + and corrupt the upload. The mismatch is silent and the failure mode is + data corruption. + +### 12. `ObjectInfo.createdAt` / `modifiedAt` — unit ambiguity, `number` precision +- **Location:** `model.ts:190-193` +- **Category:** Underspecified unit; precision; conditional applicability + hidden in JSDoc. +- **Suggested name:** `createdAtMillis` / `modifiedAtMillis`, or migrate + the values to `Temporal.Instant` (the package already depends on + `@js-temporal/polyfill`). +- **Rationale:** Two issues. (a) The `At` suffix is TS-friendly, but the + type is `number` with no unit in the name — milliseconds vs. seconds is + documented only as "UTC timestamp" in JSDoc, which does not commit. The + sibling `ListRequest.notebooksModifiedAfter` is documented as + milliseconds; one infers consistency, but the type does not say so. (b) + "Only applicable to files" — `ObjectInfo` covers all object types + (notebooks, directories, files, repos, dashboards), so the field is + silently empty for most rows. Encoding partial applicability via + JSDoc is a smell; the field shape doesn't change based on `objectType`. + +### 13. `ObjectInfo.size` — underspecified, unit-less +- **Location:** `model.ts:196-197` +- **Category:** Underspecified field — name has no unit. +- **Suggested name:** `sizeBytes` (matches Databricks convention used in + `clusters.clusterMemoryMb`, `pipelines.storageBytes`, etc.). +- **Rationale:** `size` is unit-less. JSDoc says "file size in bytes can + be returned" — "can be" is ambiguous (always for files? sometimes?). + At scale-up time (>4 GiB on a 64-bit count) `number` precision is fine, + but `bigint` or `string` is safer for true byte counters approaching + 2^53. The field also shares the "only applicable to files" caveat from + finding 12. + +### 14. `MkdirsRequest.path` — singular/plural mismatch with the type name +- **Location:** `model.ts:162-168` +- **Category:** Singular/plural mismatch between containing type and field. +- **Suggested name:** `directoryPath` (singular) on the type, and rename + the type itself per finding 15. +- **Rationale:** The type's verb is plural (`Mkdirs` — "make directories"), + but it takes one path. The Unix `mkdir -p` pluralization comes from + "create the directory and any missing parent directories," but the API + input is a single path. A user reading `MkdirsRequest` reasonably + expects to pass an array. + +### 15. `MkdirsRequest` — Unix-ism +- **Location:** `model.ts:162` (type), `client.ts:266` (method). +- **Category:** Cryptic Unix abbreviation, cross-package inconsistency. +- **Suggested name:** `CreateDirectoryRequest`. +- **Rationale:** `mkdirs` is a Unix-derived verb. The convention in TS + SDKs is to spell verbs out. The Databricks SDK's own `files` package + uses `createDirectory` for the analogous operation — so the same + conceptual action has two names across packages in the same SDK. Also: + the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the + request body holds one path, so even the wire name is misleading. + +### 16. `getStatus` — vague verb on the client +- **Location:** `client.ts:157` +- **Category:** Vague verb; misleading category (returns metadata, not a + status enum); inconsistent return shape vs. peer methods. +- **Suggested name:** `getMetadata` or `stat`. +- **Rationale:** "Status" of what? Across TS SDKs `getStatus` typically + returns a status enum or a small status object (e.g. job run status). + Here it returns full `ObjectInfo` metadata — a filesystem `stat`, not a + status. The Files API in the same SDK uses `getMetadata`. The Go SDK + uses `GetStatus` from `os.Stat` ancestry. Also: this method returns + `Promise` while `list` returns + `Promise` (wrapper). One returns the bare entity, + the other returns a wrapper — inconsistent shape across the same + client; see finding 21 too. + +### 17. `DeleteRequest.recursive` — Unix flag, no domain reading +- **Location:** `model.ts:61-66` +- **Category:** Unix-style flag name without domain meaning; understates + destructiveness. +- **Suggested name:** `deleteContents` or `force`. +- **Rationale:** `recursive` is a verbatim port of `rm -r`. For a + single-object delete, "recursive" only matters when the path is a + directory. The flag would read better as `deleteContents` (descriptive) + or `force` (matches the destructive intent). The JSDoc even admits the + deletion is non-atomic ("Please note this deleting directory is not + atomic"), a meaningful caveat hidden behind a one-word Unix flag. + +## Low severity + +### 18. `ExportFormat.R_MARKDOWN` — shape mismatch within the enum +- **Location:** `model.ts:15-16` +- **Category:** Inconsistent shape inside an enum (most values single + token, one with an underscore). +- **Suggested name:** `RMARKDOWN` or `RMD` (with wire string still + `R_MARKDOWN`). Or accept it as the exception and document. +- **Rationale:** Five of the seven `ExportFormat` values are single tokens + (`SOURCE`, `HTML`, `JUPYTER`, `DBC`, `AUTO`, `RAW`); one is + `R_MARKDOWN` with an underscore. Inconsistent shape inside the same + enum. + +### 19. `ExportFormat.DBC` — cryptic abbreviation +- **Location:** `model.ts:13-14` +- **Category:** Cryptic product-specific abbreviation. +- **Suggested name:** `DATABRICKS_ARCHIVE` on the TS identifier; the wire + string stays `DBC`. +- **Rationale:** "DBC" = "Databricks Archive." The acronym is internal + product jargon. Wire-format compatibility (`DBC` is what the server + expects) means the rename must happen on the enum-key layer, not the + enum-value layer — TypeScript supports that cleanly. + +### 20. `ObjectInfo` — `Info` suffix +- **Location:** `model.ts:174-200` +- **Category:** Vague suffix; Go/Java convention carried into TS without + reason. +- **Suggested name:** `WorkspaceObject` (or simply `Object` if not for the + global-name collision with `Object`). +- **Rationale:** `Info` is a generic "POJO that describes a thing" suffix + imported from Go/Java conventions. TS SDKs vary on this — some packages + use bare entity names (`Catalog`, `Cluster`). This package's only entity + type is `ObjectInfo` with no companion `Object`, so the suffix is purely + a hat-tip to the Go SDK. A name like `WorkspaceObject` would also avoid + the JS `Object` collision. + +### 21. `ListRequest_Response.objects` — generic field for `ObjectInfo[]` +- **Location:** `model.ts:157-160` +- **Category:** Generic field name on a wrapper type. +- **Suggested name:** `items`, `entries`, or `workspaceObjects`. +- **Rationale:** `objects` is the most generic noun in JavaScript; the + reader gets no scope information. `resp.objects` reads like "the + objects of the response" rather than "the workspace objects under the + listed path." A more specific name would convey scope. + +### 22. `mkdirs` client method — Unix contraction next to verb-noun siblings +- **Location:** `client.ts:266` +- **Category:** Verb-tense / shape inconsistency among sibling methods. +- **Suggested name:** `createDirectory`. +- **Rationale:** Sibling methods on `Client` read as bare HTTP verbs + (`export`, `import`, `list`, `delete`) or verb-noun (`getStatus`). + `mkdirs` is the only Unix-style contraction. `createDirectory` would + align with `getStatus` and with the `files` package convention. + +### 23. First-person and ticket-driven prose in JSDoc +- **Location:** `model.ts:17` ("We will inspect the content of the payload + to determine the type"); `model.ts:19-23` ("This is introduced to + unblock a DR use case importing .zip file as is. … In workspace 3.0 + folder import will be supported via a different API."). +- **Category:** JSDoc voice / customer-facing prose. +- **Suggested name:** Rewrite as third-person product documentation — + e.g. "The server inspects the payload header to determine the type." for + `AUTO`, and "Use to import a `.zip` file without unwrapping it." for + `RAW`. +- **Rationale:** "We will inspect" and "This is introduced to unblock a + DR use case" read as commit-message or design-doc fragments, not + customer-facing documentation. JSDoc renders into IDE tooltips that + consumers see. Naming-adjacent but flagged. + +## Observations + +1. **Filesystem package without filesystem vocabulary.** The package + implements filesystem-style operations (`list`, `delete`, `mkdirs`, + `getStatus`) but does not use the canonical filesystem nouns (`File`, + `Directory`, `Path`, `Stat`). Instead it uses + `ObjectInfo` / `ObjectType` / `path: string`. A user familiar with + `fs.stat` or POSIX has to mentally translate. The sibling `files` + package (`/api/2.0/fs/`) uses `DirectoryEntry` / `FileInfo` — + different vocabulary for the same concept across SDK packages. + +2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) + and `ObjectInfo.resourceId` (string, unified-resource) are both + returned, both documented as "unique identifier for the object," with + no naming clue about which one to pass where. This is the single most + user-hostile naming issue in the file (also flagged as finding 4). + +3. **`ExportFormat` is the import format.** The single enum services both + `ImportRequest` and `ExportRequest` (good — DRY), but the name says + only "Export." A neutral name (`WorkspaceObjectFormat` or + `NotebookFormat`) would describe what it actually is. + +4. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` + on `ImportRequest` means "detect from file extension + header," and + `AUTO` on `ExportRequest` means "decide from object type." Same enum + value, different server-side algorithm. + +5. **`content: Uint8Array` documented as base64 in both directions.** Two + fields hold post-decode bytes but their JSDoc reads as if they still + hold base64 strings. A defensive user reading the JSDoc and + base64-encoding their bytes will double-encode on the way in. The + mismatch is silent and the failure mode is data corruption. + +6. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear + elsewhere in the SDK.** The `files` package uses `createDirectory` + and `getMetadata`. The `repos` package uses `getRepo`. Picking one + verb per concept and applying it across packages would let users + transfer knowledge. + +## Domain glossary + +| Term | Meaning in this package | +|------|------------------------| +| Workspace object | Anything that lives in the workspace filesystem tree: notebooks, directories, files, repos, dashboards, (legacy) libraries. | +| Path | An absolute string starting with `/Workspace/` that names a workspace object. | +| Notebook | A workspace object containing runnable code cells and prose; carries a `Language`. | +| Directory | A workspace folder; can be listed and made via `mkdirs`. | +| File | An arbitrary blob in the workspace (not a notebook). | +| Repo | A Git-linked directory; appears in `ObjectType` but managed by a different package. | +| DBC | Databricks archive format — a `.zip`-like bundle of one or more notebooks. | +| Import | Upload an object (or DBC archive) into the workspace at a path. | +| Export | Download an object (or DBC archive) from the workspace at a path. | +| Mkdirs | Create a directory and any missing parents at a path (single-path operation despite the plural verb). | +| Get-status | Return metadata (path, type, language, ID, size, timestamps) for the object at a path — equivalent to `stat`. | +| Object ID | Legacy numeric workspace-local identifier (typed `number`, vulnerable to JS precision at >2^53). | +| Resource ID | Newer string identifier consistent across Databricks resource APIs. | +| Direct download | An `Export` mode where the response body is raw bytes instead of a base64-wrapped JSON object. | + +## File coverage + +| File | Lines | Read in full | +|------|-------|--------------| +| `src/v1/model.ts` | 298 | yes | +| `src/v1/client.ts` | 290 | yes | +| `src/v1/utils.ts` | 150 | yes | +| `src/v1/transport.ts` | 75 | yes | +| `src/v1/index.ts` | 20 | yes | diff --git a/.agent/naming-audit/workspaces.md b/.agent/naming-audit/workspaces.md new file mode 100644 index 00000000..2adbd83d --- /dev/null +++ b/.agent/naming-audit/workspaces.md @@ -0,0 +1,251 @@ +# Naming Audit: workspaces + +**Path:** `packages/workspaces/src/v1/` +**Versions audited:** v1 +**Inferred domain:** Account-level Databricks workspace management +(create/get/list/update/delete a workspace under an account, with all +its cloud, network, storage, and encryption configuration). +**Total weird names flagged:** 5 + +This audit is scoped to proto-architectural-leak naming (mid-position +`Public`/`Internal`/`External`, `Proto` suffix/infix, architectural-layer +words such as `Service`/`Manager`/`Wrapper`, `Impl`, `Rpc`/`Grpc`, +`Foo_PublicRequest`-style paired naming, etc.). Domain words like +`External*`/`Online*` and standard end-position suffixes (`Request`, +`Response`, `Info`) are not flagged here. + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 5 | +| Medium | 0 | +| Low | 0 | +| Observation | 0 | + +The remaining findings all cluster around the `Public` mid-position +infix on the client surface — the upstream proto/service "Public" vs +internal-route split still leaks into the `Client` methods, the two +waiter classes, the `customerFacingWorkspace` field on +`UpdateWorkspaceRequest`, and the corresponding imports / re-exports. +The model-side `Public` / `CustomerFacing` infixes on the request, +response, container, and enum types have all been removed; see the +`Fixed` section below. + +## High severity + +### 1. `customerFacingWorkspace` field on `UpdateWorkspaceRequest` — `src/v1/model.ts:245` +- **Why weird:** Field name embeds the `CustomerFacing` qualifier even + though the referenced type has been renamed to `Workspace`. The field + is the only field of this request body — a plain `workspace` field + carries the meaning fully. +- **Category:** Proto-architectural leak — `CustomerFacing` mid-position + qualifier (field name mirroring the proto qualifier of the type that + has since been renamed). +- **Suggested:** `workspace`. +- **Rationale:** Field names should describe the role of the value in + the request, not echo the upstream proto qualifier. The type has + already been renamed; the field name should follow. + +### 2. `Client.createWorkspacePublic` / `createWorkspacePublicWaiter` — `src/v1/client.ts:88,113` +- **Why weird:** `Client` method names end in `Public`. Reads as "the + method on the public class that calls the public endpoint" — the + suffix only exists because the underlying proto/spec uses `Public` + to distinguish account-API routes. The companion waiter factory + carries the same suffix. +- **Category:** Proto-architectural leak — `Public` suffix on client + method. +- **Suggested:** `createWorkspace`, `createWorkspaceWaiter`. +- **Rationale:** Methods on `Client` are inherently public; the suffix + is meaningless to a TS caller. + +### 3. `Client.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` / `updateWorkspacePublicWaiter` — `src/v1/client.ts:127,155,180,210,250` +- **Why weird:** Same `Public` suffix on every other `Client` method + (and the update waiter factory) as #2. +- **Category:** Proto-architectural leak — `Public` suffix on client + method. +- **Suggested:** `deleteWorkspace`, `getWorkspace`, `listWorkspaces`, + `updateWorkspace`, `updateWorkspaceWaiter`. +- **Rationale:** Same as #2. + +### 4. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:264,344` +- **Why weird:** Two exported waiter classes carry the `Public` infix + between the verb (`Create`/`Update`) and the noun (`Workspace`) plus + the `Waiter` role suffix. The class names are wholly SDK-side + abstractions (there is no protobuf "waiter" message), so the + `Public` token is pure inherited cruft from the paired RPC name. +- **Category:** Proto-architectural leak — `Public` mid-position + (waiter class). +- **Suggested:** `CreateWorkspaceWaiter`, `UpdateWorkspaceWaiter`. +- **Rationale:** Waiter classes are TS-only constructs; they have no + business carrying the upstream proto's public/internal qualifier. + +### 5. `Public` imports in `client.ts` and the `index.ts` re-export list — `src/v1/client.ts:31-36`, `src/v1/index.ts:5-7` +- **Why weird:** Both files mirror the leaked `Public` names from the + waiter classes in their import / re-export lists: + `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter`. +- **Category:** Proto-architectural leak — `Public` mid-position + (import & re-export mirror). +- **Suggested:** Track the renames of #2–#4. +- **Rationale:** Re-export and import statements inherit the leaked + names verbatim; nothing to do here independent of the upstream + renames. + +## Medium severity + +_None._ + +## Low severity + +_None._ + +## Observation + +_None._ + +## File coverage + +| File | Lines | Audited | +| --------------------- | ----- | ------------------------------------------------------------------------ | +| `src/v1/model.ts` | 829 | All 5 enums, all 13 interfaces, every field, all 11 marshal/unmarshal schemas, field-mask schemas. | +| `src/v1/client.ts` | 423 | `Client` class, constructor, 5 RPC methods + 2 waiter factories, 2 waiter classes, import list. | +| `src/v1/utils.ts` | 151 | All exported / private helpers. No proto-leak hits. | +| `src/v1/transport.ts` | 75 | `newHttpClient` factory + auth wrapper. No proto-leak hits. | +| `src/v1/index.ts` | 35 | All re-exports — names mirror `model.ts` and `client.ts` (covered above).| + +Type & symbol checklist: + +- [x] `ComputeMode` enum — clean (renamed from `CustomerFacingComputeMode`). +- [x] `GkeConnectivityType` enum — clean (`Gke` is a domain acronym; + no proto qualifier). +- [x] `PricingTier` enum — clean (renamed from `PublicPricingTier`). +- [x] `StorageMode` enum — clean (renamed from `CustomerFacingStorageMode`). +- [x] `WorkspaceStatus` enum — clean. +- [x] `AzureWorkspaceInfo` interface — clean (`Info` is a standard + end-position suffix; `Azure` is a domain qualifier). +- [x] `CloudResourceContainer` interface — clean (renamed from + `CustomerFacingCloudResourceContainer`). +- [x] `CreateWorkspaceRequest` interface — clean (renamed from + `CreateWorkspacePublicRequest`). +- [x] `CreateWorkspaceRequest_CustomTagsEntry` interface — clean (renamed + from `CreateWorkspacePublicRequest_CustomTagsEntry`). +- [x] `DeleteWorkspaceRequest` interface — clean (renamed from + `DeleteWorkspacePublicRequest`). +- [x] `GcpCloudResourceContainer` interface — clean (renamed from + `CustomerFacingGcpCloudResourceContainer`). +- [x] `GcpCommonNetworkConfig` interface — clean (domain abbreviation + `Gcp` + descriptive suffix). +- [x] `GcpManagedNetworkConfig` interface — clean. +- [x] `GetWorkspaceRequest` interface — clean (renamed from + `GetWorkspacePublicRequest`). +- [x] `GkeConfig` interface — clean. +- [x] `ListWorkspacesRequest` interface — clean (renamed from + `ListWorkspacesPublicRequest`). +- [x] `ListWorkspacesResponse` interface — clean (renamed from + `ListWorkspacesPublicResponse`). +- [x] `UpdateWorkspaceRequest` interface — clean as a type name (renamed + from `UpdateWorkspacePublicRequest`); `customerFacingWorkspace` field + on it flagged (#1). +- [x] `Workspace` interface — clean (renamed from `CustomerFacingWorkspace`). +- [x] `Workspace_CustomTagsEntry` interface — clean (renamed from + `CustomerFacingWorkspace_CustomTagsEntry`). +- [x] `WorkspaceNetwork` interface — clean. +- [x] `marshalCreateWorkspaceRequestSchema` — clean (renamed from + `marshalCreateWorkspacePublicRequestSchema`). +- [x] `unmarshalCloudResourceContainerSchema`, + `unmarshalGcpCloudResourceContainerSchema`, + `unmarshalWorkspaceSchema`, + `marshalCloudResourceContainerSchema`, + `marshalGcpCloudResourceContainerSchema`, + `marshalWorkspaceSchema` — clean (renamed from their + `CustomerFacing*` versions). +- [x] `unmarshalAzureWorkspaceInfoSchema`, + `unmarshalGcpCommonNetworkConfigSchema`, + `unmarshalGcpManagedNetworkConfigSchema`, + `unmarshalGkeConfigSchema`, `unmarshalWorkspaceNetworkSchema`, + `marshalAzureWorkspaceInfoSchema`, + `marshalGcpCommonNetworkConfigSchema`, + `marshalGcpManagedNetworkConfigSchema`, `marshalGkeConfigSchema`, + `marshalWorkspaceNetworkSchema` — clean (no `Public`/`CustomerFacing` + qualifier). +- [x] Field-mask schemas + (`azureWorkspaceInfoFieldMaskSchema`, + `cloudResourceContainerFieldMaskSchema`, + `gcpCloudResourceContainerFieldMaskSchema`, + `workspaceFieldMaskSchema`, + `gcpCommonNetworkConfigFieldMaskSchema`, + `gcpManagedNetworkConfigFieldMaskSchema`, + `gkeConfigFieldMaskSchema`, `workspaceNetworkFieldMaskSchema`) and + the exported `workspaceFieldMask()` factory — clean (renamed along + with the underlying types). +- [x] `Client` class itself — clean (terminal-position `Client` is the + standard SDK convention). +- [x] `Client.createWorkspacePublic` + `createWorkspacePublicWaiter` — + flagged (#2). +- [x] `Client.deleteWorkspacePublic`, `getWorkspacePublic`, + `listWorkspacesPublic`, `updateWorkspacePublic`, + `updateWorkspacePublicWaiter` — flagged (#3). +- [x] `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter` + classes — flagged (#4). +- [x] `StillRunningError` private sentinel class — clean (cross-package + pattern; not a domain identifier). +- [x] `client.ts` import list / `index.ts` re-exports — flagged (#5). +- [x] `utils.ts` (`executeCall`, `executeHttpCall`, `buildHttpRequest`, + `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, + `HttpCallOptions`) — no proto-architectural-leak names. (The + `executeCall` / `executeHttpCall` verb overlap is a common + cross-package pattern; out of scope here.) +- [x] `transport.ts` (`newHttpClient`, auth-wrapping class) — no + `Public`/`Internal`/`Proto`/`Service`/`Manager` leak in domain + identifiers. (The auth wrapper class itself is a cross-package + pattern, not flagged here.) + +## Fixed + +### 1. `CreateWorkspacePublicRequest` → `CreateWorkspaceRequest` +Fixed in regeneration on 2026-05-22. + +### 2. `CreateWorkspacePublicRequest_CustomTagsEntry` → `CreateWorkspaceRequest_CustomTagsEntry` +Fixed in regeneration on 2026-05-22. + +### 3. `DeleteWorkspacePublicRequest` → `DeleteWorkspaceRequest` +Fixed in regeneration on 2026-05-22. + +### 4. `GetWorkspacePublicRequest` → `GetWorkspaceRequest` +Fixed in regeneration on 2026-05-22. + +### 5. `ListWorkspacesPublicRequest` → `ListWorkspacesRequest` +Fixed in regeneration on 2026-05-22. + +### 6. `ListWorkspacesPublicResponse` → `ListWorkspacesResponse` +Fixed in regeneration on 2026-05-22. + +### 7. `UpdateWorkspacePublicRequest` → `UpdateWorkspaceRequest` +Fixed in regeneration on 2026-05-22. + +### 8. `PublicPricingTier` → `PricingTier` +Fixed in regeneration on 2026-05-22. + +### 9. `CustomerFacingComputeMode` → `ComputeMode` +Fixed in regeneration on 2026-05-22. + +### 10. `CustomerFacingStorageMode` → `StorageMode` +Fixed in regeneration on 2026-05-22. + +### 11. `CustomerFacingCloudResourceContainer` → `CloudResourceContainer` +Fixed in regeneration on 2026-05-22. + +### 12. `CustomerFacingGcpCloudResourceContainer` → `GcpCloudResourceContainer` +Fixed in regeneration on 2026-05-22. + +### 13. `CustomerFacingWorkspace` → `Workspace` +Fixed in regeneration on 2026-05-22. + +### 14. `CustomerFacingWorkspace_CustomTagsEntry` → `Workspace_CustomTagsEntry` +Fixed in regeneration on 2026-05-22. + +### 15. `marshalCreateWorkspacePublicRequestSchema` → `marshalCreateWorkspaceRequestSchema` +Fixed in regeneration on 2026-05-22. + +### 16. `unmarshalCustomerFacing*Schema` / `marshalCustomerFacing*Schema` (six schemas) → `unmarshalWorkspaceSchema`, `marshalWorkspaceSchema`, `unmarshalCloudResourceContainerSchema`, `marshalCloudResourceContainerSchema`, `unmarshalGcpCloudResourceContainerSchema`, `marshalGcpCloudResourceContainerSchema` +Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md index a3598fa0..6fc01e79 100644 --- a/.agent/naming-audit/workspacesettings.md +++ b/.agent/naming-audit/workspacesettings.md @@ -1,5 +1,9 @@ # Naming Audit: workspacesettings +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. + +**All findings retired on 2026-05-22.** + **Path:** `/home/parth.bansal/sdk-js/packages/workspacesettings/` **Versions audited:** v1 **Inferred domain:** Workspace-scoped Databricks settings: AI/BI dashboard embedding policy, automatic cluster update, compliance security profile (CSP), dashboard email subscriptions, default namespace, default warehouse ID, legacy access/DBFS disablement, notebook/file export, notebook table clipboard, results download (notebook and SQL), enhanced security monitoring (ESM), LLM proxy partner-powered AI, and restrict-workspace-admins. @@ -10,50 +14,50 @@ | # | Severity | Category | Identifier | File:line | |---|----------|----------|------------|-----------| | 1 | Critical | Duplicate concept across packages | `workspacesettings` vs `settings` vs `accountsettings` vs `workspaceconf` | package boundary | -| 2 | Critical | Duplicate type | `BooleanMessage`, `StringMessage` (also in `accountsettings`, `settings/v2`) | `model.ts:186, 1034` | +| 2 | Critical | Duplicate type | `BooleanMessage`, `StringMessage` (also in `accountsettings`, `settings/v2`) | `model.ts:181, 1029` | | 3 | Critical | Duplicate type | `ComplianceStandard` (also in `accountsettings`) | `model.ts:8` | -| 4 | Critical | Duplicate concept | `RestrictWorkspaceAdminsSetting`, `AibiDashboardEmbeddingAccessPolicySetting` etc. mirror types in `settings/v2` | `model.ts:991, 104` and `settings/v2` | -| 5 | High | Cryptic abbreviation | `Aibi` (`AI/BI`) family of types/methods | `model.ts:57-160, 104-160`; `client.ts:335,377,752,792,1257,1292` | -| 6 | High | Cryptic abbreviation | `Csp` (Compliance Security Profile) | `model.ts:244-273`; `client.ts:872, 1365`; URL `shield_csp_enablement_ws_db` | -| 7 | High | Cryptic abbreviation | `Esm` (Enhanced Security Monitoring) | `model.ts:706-733`; `client.ts:1100,1556`; URL `shield_esm_enablement_ws_db` | -| 8 | High | Cryptic abbreviation | `Llm` (LLM Proxy Partner-Powered Workspace) | `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624,1140,1588` | -| 9 | High | Cryptic abbreviation | `Dbfs` casing (`disableLegacyDbfs`) | `model.ts:514-541, 651-670, 855-868, 1122-1129`; `client.ts:584,1063,1521` | -| 10 | High | Generic / cryptic enum sentinel | `STATUS_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `COMPLIANCE_STANDARD_UNSPECIFIED` | `model.ts:10, 58, 66, 78, 91` | -| 11 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` | -| 12 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:340-345, 382-387, 425-430, 469-474, ...` | -| 13 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:321-338` | -| 14 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | -| 15 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | -| 16 | High | Triple-stutter against package name | `*Setting` suffix on every type in `workspacesettings` package | `model.ts:104, 244, 706, 991, 1015` and passim | -| 17 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:630-649` | -| 18 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:651-670` | -| 19 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:672-680` | -| 20 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:682-690` | -| 21 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:692-700` | -| 22 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:692, 1015` | -| 23 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:692 vs 1015`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | -| 24 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:939-956` | -| 25 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:181, 1248` | -| 26 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:269, 729` | -| 27 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:195` | -| 28 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:192` | -| 29 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:213` | -| 30 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:209, 211` | -| 31 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | -| 32 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:321, 1102` | -| 33 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:71, 102` | -| 34 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:672, 682, 692, 630, 651` | -| 35 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:672, 682` | -| 36 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | -| 37 | Medium | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS`, `SECOND_AND_FOURTH_OF_MONTH`, `FIRST_AND_THIRD_OF_MONTH`, `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `FEDRAMP_MODERATE`, etc. | `model.ts:19-53, 83, 84, 101` | -| 38 | Medium | Long enum value | `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`, `ALLOW_ALL_DOMAINS` | `model.ts:59-61` | -| 39 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:988` | -| 40 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | -| 41 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 1104, 956, 1369, 1560` | -| 42 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:112-117, 252-259, 1024` | -| 43 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:248` | -| 44 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:135` | -| 45 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | +| 4 | Critical | Duplicate concept | `RestrictWorkspaceAdminsSetting`, `AibiDashboardEmbeddingAccessPolicySetting` etc. mirror types in `settings/v2` | `model.ts:986, 99` and `settings/v2` | +| 5 | High | Cryptic abbreviation | `Aibi` (`AI/BI`) family of types/methods | `model.ts:52-155, 99-155`; `client.ts:335,377,752,792,1257,1292` | +| 6 | High | Cryptic abbreviation | `Csp` (Compliance Security Profile) | `model.ts:239-268`; `client.ts:876, 1369`; URL `shield_csp_enablement_ws_db` | +| 7 | High | Cryptic abbreviation | `Esm` (Enhanced Security Monitoring) | `model.ts:697-728`; `client.ts:1104,1560`; URL `shield_esm_enablement_ws_db` | +| 8 | High | Cryptic abbreviation | `Llm` (LLM Proxy Partner-Powered Workspace) | `model.ts:538-565, 934-951, 1137-1144`; `client.ts:624,1140,1588` | +| 9 | High | Cryptic abbreviation | `Dbfs` casing (`disableLegacyDbfs`) | `model.ts:509-536, 646-665, 850-863, 1117-1124`; `client.ts:584,1063,1522` | +| 10 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:120, 148, 172, 261, 285, 312, 331, 640, 661, 673, 683, 693, 721, 949, 1001, 1025` | +| 11 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:341-346, 383-388, 425-430, 470-475, ...` | +| 12 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:316-333` | +| 13 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | +| 14 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | +| 15 | High | Triple-stutter against package name | `*Setting` suffix on every type in `workspacesettings` package | `model.ts:105, 246, 706, 986, 1010` and passim | +| 16 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:625-644` | +| 17 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:646-665` | +| 18 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:667-675` | +| 19 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:677-685` | +| 20 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:687-695` | +| 21 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:687, 1010` | +| 22 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:687 vs 1010`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | +| 23 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:934-951` | +| 24 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:175, 1245` | +| 25 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:264, 724` | +| 26 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:190` | +| 27 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:187` | +| 28 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:208` | +| 29 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:204, 206` | +| 30 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | +| 31 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:316, 1097` | +| 32 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:70, 98, 103` | +| 33 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:667, 677, 687, 625, 646` | +| 34 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:667, 677` | +| 35 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | +| 36 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:983` | +| 37 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | +| 38 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 956, 1104, 1369, 1439, 1560` | +| 39 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:107-114, 248-254, 1012-1018` | +| 40 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:243` | +| 41 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:130` | +| 42 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | +| 43 | High | Proto-architectural-leak (`Message` suffix) | `BooleanMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage` | `model.ts:181, 1029, 185, 977` | +| 44 | High | Proto-architectural-leak (`Message_` nested infix) | `ClusterAutoRestartMessage_EnablementDetails`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:60, 72, 84, 202, 212, 219, 230` | +| 45 | Medium | Proto-architectural-leak (generic `Details` suffix) | `ClusterAutoRestartMessage_EnablementDetails` and field `enablementDetails` | `model.ts:189, 202` | --- @@ -70,19 +74,19 @@ No documentation surfaces this taxonomy; the consumer has to guess. The four packages share types verbatim and the `settings/v2` package already exposes a generic `Setting`/`SettingsMetadata` shape that *can* represent any of these. The split is purely a wire-routing artefact. ### 2. `BooleanMessage`, `StringMessage` — duplicated in three sibling packages -- **File:line:** `model.ts:186-188, 1034-1037` +- **File:line:** `model.ts:181-183, 1029-1032` - **Category:** Duplicate type - **Suggestion:** Hoist into `@databricks/sdk-core/wkt` (or similar shared location) alongside `FieldMask`. These are `google.protobuf.BoolValue` and `google.protobuf.StringValue` analogues and belong with `FieldMask`, which the package already imports from `wkt`. - **Rationale:** Three packages (`workspacesettings`, `accountsettings`, `settings/v2`) all define identical types — same one boolean/string field, same wrapping. Consumers cannot pass a `BooleanMessage` from one package to a sibling method that takes a `BooleanMessage`. The duplication is wire-bookkeeping leaking through the API surface. ### 3. `ComplianceStandard` enum — duplicated in `accountsettings` -- **File:line:** `model.ts:8-54` (here) and identical in `accountsettings/src/v1/model.ts` +- **File:line:** `model.ts:8-49` (here) and identical in `accountsettings/src/v1/model.ts` - **Category:** Duplicate type - **Suggestion:** Hoist into a shared `compliance` module. The enum has 15 values, all canonical regulatory standards (HIPAA, PCI_DSS, FEDRAMP_*, etc.) that do not differ by setting scope. - **Rationale:** HIPAA at the account level *is* HIPAA at the workspace level. Two enums with identical members means type-incompatible values for the same regulatory concept. ### 4. Whole types mirrored in `settings/v2` -- **File:line:** `model.ts:104, 138, 244, 251, 691, 711, 982, 991` vs `settings/v2/model.ts` +- **File:line:** `model.ts:99, 133, 239, 246, 686, 706, 977, 986` vs `settings/v2/model.ts` - **Category:** Duplicate concept - **Suggestion:** Pick one canonical home. `settings/v2` is clearly the generic surface (it exposes `Setting`, `SettingsMetadata`, `PatchPublicWorkspaceSettingRequest`). The specific-typed methods in `workspacesettings` are a sister API for the same backend data. Either fold the specific methods into `settings/v2` (preferred) or document which one is canonical. - **Rationale:** `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage`, `BooleanMessage`, `StringMessage` all live in both packages with identical fields. The consumer cannot pass instances across the package boundary, despite naming/structure being byte-identical. @@ -92,254 +96,257 @@ ## High severity ### 5. `Aibi*` family — cryptic acronym not expanded in identifier -- **File:line:** `model.ts:57-160`; client.ts six methods +- **File:line:** `model.ts:52-155`; client.ts six methods - **Category:** Cryptic abbreviation, acronym casing - **Suggestion:** Either spell as `AiBiDashboardEmbedding*` (matching Databricks marketing) or `AIBIDashboardEmbedding*` (strict acronym casing). The current `Aibi` parses as one token, hiding the AI + BI = analytics-product structure. - **Rationale:** "AI/BI dashboards" is the user-facing product name (confirmed in the JSDoc on `client.ts:749`). The wire path even uses `aibi_dash_embed_ws_acc_policy` — itself heavily abbreviated. A new reader cannot guess that `Aibi` means "AI + BI." TS style guide prefers acronym capitalization for known acronyms (`URL`, `HTTP`, `AI`, `BI`). ### 6. `Csp*` family — undocumented acronym -- **File:line:** `model.ts:244-273`; URL slug `shield_csp_enablement_ws_db` +- **File:line:** `model.ts:239-268`; URL slug `shield_csp_enablement_ws_db` - **Category:** Cryptic abbreviation -- **Suggestion:** `ComplianceSecurityProfile*` everywhere (it's already spelled out in the JSDoc on line 243). The class methods are already named `ComplianceSecurityProfile`; only the wire slug is `csp`, which is fine on the wire but should not be exposed. +- **Suggestion:** `ComplianceSecurityProfile*` everywhere (it's already spelled out in the JSDoc on line 238). The class methods are already named `ComplianceSecurityProfile`; only the wire slug is `csp`, which is fine on the wire but should not be exposed. - **Rationale:** Identical issue to `accountsettings`. CSP overloads catastrophically with web "Content Security Policy." Outside this codebase, that is the dominant meaning. The TS-side type name is `ComplianceSecurityProfile` (good!) but the wire and the `_workspace` suffix in `complianceSecurityProfileWorkspace` discriminator is still cryptic-adjacent. ### 7. `Esm*` family — undocumented acronym -- **File:line:** `model.ts:706-733`; URL slug `shield_esm_enablement_ws_db`; `client.ts:1100, 1556` +- **File:line:** `model.ts:697-728`; URL slug `shield_esm_enablement_ws_db`; `client.ts:1104, 1560` - **Category:** Cryptic abbreviation - **Suggestion:** `EnhancedSecurityMonitoring*` everywhere on TS side. Wire `esm` is fine. -- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #26). +- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #25). ### 8. `Llm*` family — acronym casing + verb stacking -- **File:line:** `model.ts:543-571, 939-956, 1142-1149`; `client.ts:624, 1140, 1588` +- **File:line:** `model.ts:538-565, 934-951, 1137-1144`; `client.ts:624, 1140, 1588` - **Category:** Cryptic abbreviation + Acronym casing - **Suggestion:** Spell out: `ModelProxyPartnerPoweredWorkspace` or `LargeLanguageModelProxyPartnerPoweredWorkspace` (admittedly long). Better: drop "Workspace" since the package name already scopes it → `LlmProxyPartnerPowered`. Better still: collapse to `PartnerPoweredAi` (the doc on `client.ts:1139` explicitly calls it "partner powered AI features"). - **Rationale:** `LlmProxyPartnerPoweredWorkspace` is 31 characters parsing as five concepts: LLM-Proxy-Partner-Powered-Workspace. Without context, a reader cannot tell whether "PartnerPowered" modifies "Llm" or modifies "Workspace." `Llm` (one word) violates TS acronym casing. ### 9. `Dbfs` casing -- **File:line:** `model.ts:514-541, 651-670, 855-868, 1122-1129` +- **File:line:** `model.ts:509-536, 646-665, 850-863, 1117-1124` - **Category:** Acronym casing - **Suggestion:** `DBFS` (it's an acronym — Databricks File System). Apply consistently: `DisableLegacyDBFS`, `disableLegacyDBFS`, `GetDisableLegacyDBFSRequest`. - **Rationale:** TS style for known acronyms is uppercase. The wire is `disable_legacy_dbfs` (lowercase) which is fine, but the TS surface should be `DBFS`. The codebase is internally consistent in using `Dbfs` everywhere, so this is a global rename. -### 10. Sentinel enum values: `*_UNSPECIFIED` -- **File:line:** `model.ts:10, 58, 66, 78, 91` -- **Category:** Sentinel enum value -- **Suggestion:** Either omit the sentinel entirely (TS-idiomatic; use `undefined`) or rename to `UNSPECIFIED`. The current `COMPLIANCE_STANDARD_UNSPECIFIED`, `ACCESS_POLICY_TYPE_UNSPECIFIED`, `DAY_OF_WEEK_UNSPECIFIED`, `WEEK_DAY_FREQUENCY_UNSPECIFIED`, `STATUS_UNSPECIFIED` are sentinel values flagged by their docstrings as "should not be used in prod." -- **Rationale:** The doc comment on line 9 explicitly says "Sentinel value, should not be used in prod" — yet the type forces the consumer to consider it. Idiomatic TS represents "unspecified" with `T | undefined`. - -### 11. `settingName` documented as not respected on requests -- **File:line:** `model.ts:122, 150, 175, 264, 287, 313, 331, 642, 663, 676, 686, 696, 723, 950, 1004, 1027` +### 10. `settingName` documented as not respected on requests +- **File:line:** `model.ts:120, 148, 172, 261, 285, 312, 331, 640, 661, 673, 683, 693, 721, 949, 1001, 1025` - **Category:** Misleading - **Suggestion:** Mark `settingName` `readonly` on the response-only path; remove it from request bodies; or split request/response types so it is only present where meaningful. At minimum, the docstring should not say "this field is populated in the response, but it will not be respected even if it's set in the request body." -- **Rationale:** A 17-times-repeated 240-character JSDoc admits that the field is server-ignored on PATCH/UPDATE. The field is forced to `"default"` server-side. Exposing it in the public API surface only invites users to set it, expect it to take effect, and then debug why it didn't. +- **Rationale:** A 16-times-repeated 240-character JSDoc admits that the field is server-ignored on PATCH/UPDATE. The field is forced to `"default"` server-side. Exposing it in the public API surface only invites users to set it, expect it to take effect, and then debug why it didn't. -### 12. `settingTypeName` query parameter ignored -- **File:line:** `client.ts:340-345, 382-387, 425-430, 469-474, 510-515, 550-555, 590-595, 630-635, 675-680, 715-720, 758-763, 798-803, 838-843, 878-883, 918-923, 958-963, 994-999, 1032-1037, 1068-1073, 1106-1111, 1146-1151, 1186-1191, 1226-1231` +### 11. `settingTypeName` query parameter ignored +- **File:line:** `client.ts:341-346, 383-388, 425-430, 470-475, 510-515, 550-555, 590-595, 630-635, 675-680, 715-720, 758-763, 798-803, 838-843, 878-883, 918-923, 958-963, 995-1000, 1032-1037, 1069-1074, 1106-1111, 1146-1151, 1186-1191, 1226-1231` - **Category:** Misleading - **Suggestion:** Drop from the request type — the path parameter (`/api/2.0/settings/types/aibi_dash_embed_ws_acc_policy/names/default`) makes the query parameter redundant. The client serializes the path slug for the user; there is no reason to also expose the slug as a `settingTypeName` query param. - **Rationale:** Every Get/Delete/Update sets the URL path to a hard-coded slug (e.g. `aibi_dash_embed_ws_acc_policy`) and then *also* lets the user populate `settingTypeName` and `settingName` as query params. If a user sets `settingTypeName: 'foo'`, the path still wins; the field is window dressing. -### 13. `DefaultWarehouseId` envelope holds no warehouse-ID field directly -- **File:line:** `model.ts:321-338` +### 12. `DefaultWarehouseId` envelope holds no warehouse-ID field directly +- **File:line:** `model.ts:316-333` - **Category:** Underspecified ID, misleading - **Suggestion:** `interface DefaultWarehouse { id?: string; etag?: string; }` — a flat, non-envelope, no-wrapper type. Or hide the envelope completely and let the client method return `string | undefined`. - **Rationale:** A reader sees `DefaultWarehouseId` and expects a `string` (or numeric ID). What they get is a four-layer struct: `defaultWarehouseId.value.stringVal.value` is the actual ID. Plus the type lacks any documentation about whether the warehouse ID is numeric (e.g. `1234`) or string-shaped (e.g. `0abc...d`). The Databricks warehouse-ID convention is opaque alphanumeric; this should be documented. -### 14. `patch*` vs `update*` methods for the same PATCH HTTP verb +### 13. `patch*` vs `update*` methods for the same PATCH HTTP verb - **File:line:** `client.ts:192 (patchEnableExportNotebook), 249 (patchEnableNotebookTableClipboard), 306 (patchEnableResultsDownloading)` vs `client.ts:1257 (updateAibi...), 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657 (update*)` - **Category:** Inconsistent action verbs - **Suggestion:** Standardize on `update*`. The three `patch*` methods are anomalies — every other PATCH method in the package is named `update*` and every API in the SDK reading from CRUD elsewhere uses `update*`. - **Rationale:** Three of 26 methods (`patchEnableExportNotebook`, `patchEnableNotebookTableClipboard`, `patchEnableResultsDownloading`) use the verb `patch` instead of `update`, even though all 14 PATCH-method-using siblings use `update`. The HTTP verb is the same (`PATCH`). The naming inconsistency causes consumer discovery problems. -### 15. `delete*` methods that actually "revert" to default +### 14. `delete*` methods that actually "revert" to default - **File:line:** `client.ts:335 (deleteAibi...AccessPolicySetting), 377, 419, 464, 504, 544, 584, 624, 669, 709` - **Category:** Inconsistent action verbs / misleading - **Suggestion:** `resetToDefault*` or `reset*`. The doc literally reads "Reverts the SQL Results Download setting to its default value" (line 708), "Reverts the Dashboard Email Subscriptions setting to its default value" (line 418), "Reverts the enable partner powered AI features workspace setting to its default value" (line 623), etc. — the semantic is reset, not delete. - **Rationale:** A `delete` method that doesn't delete is the worst kind of misleading verb. The HTTP verb is `DELETE` but that is the *server's* idiom for "remove the override and fall back to default." The SDK can wrap with `reset*` and hide the wire detail. -### 16. `*Setting` triple-stutter against the `workspacesettings` package name -- **File:line:** `model.ts:104 (AibiDashboardEmbeddingAccessPolicySetting), 244 (ComplianceSecurityProfileSetting), 706 (EnhancedSecurityMonitoringSetting), 991 (RestrictWorkspaceAdminsSetting), 1015 (SqlResultsDownload — exception)` and ~14 more +### 15. `*Setting` triple-stutter against the `workspacesettings` package name +- **File:line:** `model.ts:105 (AibiDashboardEmbeddingAccessPolicySetting), 246 (ComplianceSecurityProfileSetting), 706 (EnhancedSecurityMonitoringSetting), 986 (RestrictWorkspaceAdminsSetting), 1010 (SqlResultsDownload — exception)` and ~14 more - **Category:** Triple-stutter against package name - **Suggestion:** Drop the `Setting` suffix. The package is already `workspacesettings`, so `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` reads as "the access-policy setting setting setting." Use `workspacesettings.AibiDashboardEmbeddingAccessPolicy` etc. - **Rationale:** Every primary type in the package carries a `Setting` suffix despite the package name being `workspacesettings`. The qualified path triple-states "settings." Sibling `SqlResultsDownload` (without `Setting` suffix) shows the cleaner alternative. +### 43. `Message` suffix on top-level types — proto-architectural-leak +- **File:line:** `model.ts:181 (BooleanMessage), 185 (ClusterAutoRestartMessage), 977 (RestrictWorkspaceAdminsMessage), 1029 (StringMessage)` +- **Why:** Public TS type names should describe the domain object, not the wire-encoding container. `Message` is `proto`'s name for "any encoded record" and carries no semantic value to a TS consumer; it announces that the type was code-generated from a `.proto` definition. +- **Category:** Proto-architectural-leak (suffix) +- **Suggested:** Drop the `Message` suffix everywhere. `BooleanMessage` → `BooleanValue` (or hoist to a shared wkt `BoolValue`); `StringMessage` → `StringValue`; `ClusterAutoRestartMessage` → `ClusterAutoRestart`; `RestrictWorkspaceAdminsMessage` → `RestrictWorkspaceAdmins`. +- **Rationale:** A TS reader has no concept of `proto.Message`. Naming a wrapper around a single boolean `BooleanMessage` exposes the wire transport. Sibling types in the same package (`EnhancedSecurityMonitoring`, `ComplianceSecurityProfile`, `DashboardEmailSubscriptions`, `SqlResultsDownload`, `LlmProxyPartnerPoweredWorkspace`) all drop the `Message` suffix successfully — the four flagged types are outliers carrying through their proto identity. + +### 44. `*Message_*` nested-type underscore infix — proto nested-message naming convention +- **File:line:** `model.ts:60 (ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek), 72 (...WeekDayFrequency), 84 (RestrictWorkspaceAdminsMessage_Status), 202 (ClusterAutoRestartMessage_EnablementDetails), 212 (ClusterAutoRestartMessage_MaintenanceWindow), 219 (...WeekDayBasedSchedule), 230 (...WindowStartTime)` +- **Why:** The `Parent_Nested` and `Parent_Nested_DeepNested` pattern is `protoc`'s mechanical encoding of nested `message`/`enum` blocks (since TS has no nested-type syntax in this codebase). The repeated `Message_` infix doubles down on the proto leak from #43. +- **Category:** Proto-architectural-leak (`Proto`-style nested-type marker) +- **Suggested:** Lift nested types to top-level with clean names. `ClusterAutoRestartMessage_EnablementDetails` → `ClusterAutoRestartEnablement`; `ClusterAutoRestartMessage_MaintenanceWindow` → `ClusterAutoRestartMaintenanceWindow`; `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` → `WeekDayBasedMaintenanceSchedule`; `..._WindowStartTime` → `MaintenanceWindowStartTime`; `..._DayOfWeek` → `DayOfWeek`; `..._WeekDayFrequency` → `WeekDayFrequency`; `RestrictWorkspaceAdminsMessage_Status` → `WorkspaceAdminRestrictionStatus`. +- **Rationale:** Every occurrence of these identifiers is paired with an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive (lines 51, 59, 71, 83, 201, 211, 218, 229, 1281, 1295, 1310, 1333, 1811, 1825, 1840, 1863, 2552, 2564, 2574, 2586), confirming the codebase itself recognizes this as a proto-style leak that violates the TS naming convention. The double-`Message_` chain (e.g. `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`) is 62 characters of nested-encoding artifact. + --- ## Medium severity -### 17. `DisableLegacyAccess` — verb-phrase as type name -- **File:line:** `model.ts:630-649` +### 16. `DisableLegacyAccess` — verb-phrase as type name +- **File:line:** `model.ts:625-644` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `LegacyAccessDisablement` or `LegacyAccessToggle`. Types describing settings should be nouns. - **Rationale:** `DisableLegacyAccess` reads as an imperative ("perform the action of disabling legacy access") rather than a state ("the legacy-access-disabled toggle setting"). The discriminator name `disableLegacyAccess` inside `.value.disableLegacyAccess: BooleanMessage` doubles the verb. -### 18. `DisableLegacyDbfs` — verb-phrase as type name -- **File:line:** `model.ts:651-670` +### 17. `DisableLegacyDbfs` — verb-phrase as type name +- **File:line:** `model.ts:646-665` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `LegacyDBFSDisablement` or `LegacyDBFSToggle`. -- **Rationale:** Same as #17. +- **Rationale:** Same as #16. -### 19. `EnableExportNotebook` — verb-phrase as type name -- **File:line:** `model.ts:672-680` +### 18. `EnableExportNotebook` — verb-phrase as type name +- **File:line:** `model.ts:667-675` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `NotebookExportToggle` or `NotebookExportEnabled`. -- **Rationale:** Same as #17 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. +- **Rationale:** Same as #16 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. -### 20. `EnableNotebookTableClipboard` — verb-phrase as type name -- **File:line:** `model.ts:682-690` +### 19. `EnableNotebookTableClipboard` — verb-phrase as type name +- **File:line:** `model.ts:677-685` - **Category:** Verb-tense / verb-in-noun position - **Suggestion:** `NotebookTableClipboardToggle`. -- **Rationale:** Same as #17. +- **Rationale:** Same as #16. -### 21. `EnableResultsDownloading` — verb + gerund mash -- **File:line:** `model.ts:692-700` +### 20. `EnableResultsDownloading` — verb + gerund mash +- **File:line:** `model.ts:687-695` - **Category:** Verb-tense / verb-in-noun position + gerund mismatch - **Suggestion:** `NotebookResultsDownloadToggle` (matches the doc on `client.ts:280` "Notebook results download setting"). - **Rationale:** `EnableResultsDownloading` mixes imperative `Enable` with gerund `Downloading`. The sibling type `SqlResultsDownload` (no `-ing`, no `Enable`) does the same thing for SQL. The inconsistency is severe — same domain, two different naming conventions. -### 22. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package -- **File:line:** `model.ts:692, 1015` +### 21. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package +- **File:line:** `model.ts:687, 1010` - **Category:** Verb-tense / -ing gerund inconsistency - **Suggestion:** Pick one form. Either both as `*Toggle` or both as `Enable*Downloading`. - **Rationale:** Both control downloading of query results. The notebook variant is `EnableResultsDownloading` (gerund). The SQL variant is `SqlResultsDownload` (noun). The pair was authored at different times by different teams and the inconsistency leaked into the API. -### 23. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap -- **File:line:** `model.ts:692, 1015` +### 22. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap +- **File:line:** `model.ts:687, 1010` - **Category:** Misleading / parallel naming - **Suggestion:** Unify under one type with a discriminator: `ResultsDownloadToggle { context: 'notebook' | 'sql', enabled: boolean }`. - **Rationale:** The doc on `client.ts:280` calls one "Notebook results download" and the doc on `client.ts:1219` calls the other "SQL Results Download." They have the same shape and similar semantics — but the methods, types, and wire slugs are all separate. This is duplicated wiring at the API surface. -### 24. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix -- **File:line:** `model.ts:939-956` +### 23. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix +- **File:line:** `model.ts:934-951` - **Category:** Misleading - **Suggestion:** Drop `Workspace`. The package name is `workspacesettings`, so every type is workspace-scoped. The suffix exists only to mirror `LlmProxyPartnerPoweredAccount` in `accountsettings` — which is symmetrical but ill-justified (both should drop their scope suffix). - **Rationale:** Compare to siblings: `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, `SqlResultsDownload`, `EnableExportNotebook` — none of them carry the "Workspace" suffix despite being workspace-scoped. `LlmProxyPartnerPoweredWorkspace` is the outlier. -### 25. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" -- **File:line:** `model.ts:181, 1248` +### 24. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" +- **File:line:** `model.ts:175, 1245` - **Category:** Misleading - **Suggestion:** `clusterAutoRestart` (matches the actual data type, `ClusterAutoRestartMessage`). - **Rationale:** Inside `AutomaticClusterUpdateSetting.value.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage` — the discriminator name uses one phrase ("automatic cluster update workspace") while the type uses another ("cluster auto restart"). The reader must mentally bridge "automatic cluster update" with "cluster auto restart." -### 26. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" -- **File:line:** `model.ts:269, 729` +### 25. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" +- **File:line:** `model.ts:264, 724` - **Category:** Misleading - **Suggestion:** Drop "Workspace" suffix: `complianceSecurityProfile`, `enhancedSecurityMonitoring`. -- **Rationale:** Same as #24. +- **Rationale:** Same as #23. -### 27. `restartEvenIfNoUpdatesAvailable` — double negative -- **File:line:** `model.ts:195` +### 26. `restartEvenIfNoUpdatesAvailable` — double negative +- **File:line:** `model.ts:190` - **Category:** Misleading - **Suggestion:** `restartUnconditionally` (or invert: `skipIfNoUpdates` with opposite default). - **Rationale:** "Restart even if no updates available" is a triple-conditional that takes effort to parse. The semantics are "restart regardless of update availability." Boolean fields should read as clean predicates. -### 28. `canToggle` — vague boolean -- **File:line:** `model.ts:192` +### 27. `canToggle` — vague boolean +- **File:line:** `model.ts:187` - **Category:** Misleading - **Suggestion:** `isToggleable` or `canBeDisabledByCustomer`. - **Rationale:** `canToggle` on its own does not specify *what* can be toggled or by *whom*. From context (`ClusterAutoRestartMessage`), this likely means "can the customer toggle the auto-restart setting." The name does not convey that. -### 29. `forcedForComplianceMode` — past-participle as flag -- **File:line:** `model.ts:213` +### 28. `forcedForComplianceMode` — past-participle as flag +- **File:line:** `model.ts:208` - **Category:** Misleading - **Suggestion:** `isForcedByComplianceMode` or `forcedDueToComplianceMode`. -- **Rationale:** `forcedFor` reads ambiguously — "for the purpose of" or "due to"? The doc on line 212 ("The feature is force enabled if compliance mode is active") confirms the meaning is "due to." +- **Rationale:** `forcedFor` reads ambiguously — "for the purpose of" or "due to"? The doc on line 207 ("The feature is force enabled if compliance mode is active") confirms the meaning is "due to." -### 30. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative -- **File:line:** `model.ts:209, 211` +### 29. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative +- **File:line:** `model.ts:204, 206` - **Category:** Misleading - **Suggestion:** Invert: `requiresEnterpriseTier`, `requiresEntitlement` — read more naturally. - **Rationale:** "Unavailable for non-enterprise" requires reasoning over two negatives. "Requires enterprise" is a positive predicate. -### 31. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` +### 30. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` - **File:line:** Throughout model.ts and client.ts - **Category:** Acronym casing - **Suggestion:** Apply TS-conventional casing — `DBFS`, `AIBI` (or `AiBi`), `LLM`, `CSP`, `ESM`, `SQL` — or, where they are domain acronyms, document expansion. The codebase is internally consistent in using `Pascal-token-case` for all of them, but this contradicts the TS style guide and the JSDoc which uses correct casing (`AI/BI`, `LLM`, `SQL`, etc. in prose). - **Rationale:** JSDoc has it right; identifiers don't. -### 32. `Id` vs `ID` casing -- **File:line:** `model.ts:321, 1102` (`DefaultWarehouseId`, `UpdateDefaultWarehouseIdRequest`, `defaultWarehouseId` method) +### 31. `Id` vs `ID` casing +- **File:line:** `model.ts:316, 1097` (`DefaultWarehouseId`, `UpdateDefaultWarehouseIdRequest`, `defaultWarehouseId` method) - **Category:** Acronym casing - **Suggestion:** `DefaultWarehouseID`, `UpdateDefaultWarehouseIDRequest` — or, if `Id` is house style, document it explicitly. Pick one and apply globally. - **Rationale:** Established TS code is split — some major SDKs use `Id` (consistent with `Pascal-token-case`), others use `ID` (matches HTTP/spec convention). The Go SDK uses `Id`. The Databricks JS SDK should pick one and apply it everywhere; today, "Id" is used here but "ESM/CSP/LLM" suggests acronym capitalization is house style. -### 33. `Url` casing -- **File:line:** `utils.ts:71, 102` +### 32. `Url` casing +- **File:line:** `utils.ts:70, 98, 103` - **Category:** Acronym casing - **Suggestion:** Match the upstream `HttpRequest.url` field; if upstream uses `url`, leave it. Note inconsistency for the audit reviewer. - **Rationale:** Minor — flagged because the rule applies. -### 34. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns -- **File:line:** `model.ts:672 (EnableExportNotebook), 682 (EnableNotebookTableClipboard), 692 (EnableResultsDownloading), 630 (DisableLegacyAccess), 651 (DisableLegacyDbfs)` +### 33. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns +- **File:line:** `model.ts:667 (EnableExportNotebook), 677 (EnableNotebookTableClipboard), 687 (EnableResultsDownloading), 625 (DisableLegacyAccess), 646 (DisableLegacyDbfs)` - **Category:** Verb-tense inconsistency -- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #17–21. +- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #16–20. - **Rationale:** Five types here use three different inflection patterns. -### 35. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap -- **File:line:** `model.ts:672, 682` +### 34. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap +- **File:line:** `model.ts:667, 677` - **Category:** Verb-tense inconsistency - **Suggestion:** Pick word-order convention: noun-verb-noun (`EnableNotebookExport`, `EnableNotebookTableClipboard`) or verb-noun-noun (`EnableExportNotebook`, `EnableClipboardTable`). - **Rationale:** "Enable Export Notebook" puts the noun ("Notebook") last; "Enable Notebook Table Clipboard" puts it first. The cognitive cost of two siblings in the same package using opposite orders is non-trivial. -### 36. `delete*` method names — reserved-word adjacency +### 35. `delete*` method names — reserved-word adjacency - **File:line:** `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` - **Category:** Reserved-word collision (soft) -- **Suggestion:** `reset*` (which also fixes #15). +- **Suggestion:** `reset*` (which also fixes #14). - **Rationale:** `delete` is a JS reserved word (`delete obj.prop`). Using it as a method prefix is technically fine but creates parsing-cost ambiguity in mental models, especially when the operation doesn't *actually* delete. -### 37. Long enum values -- **File:line:** `model.ts:19-53, 83, 84, 101` -- **Category:** Long enum value -- **Suggestion:** Most are unavoidable (regulatory standard names like `FEDRAMP_MODERATE` are canonical). For `RESTRICT_TOKENS_AND_JOB_RUN_AS` consider `RESTRICT_TOKEN_AND_JOB_RUN_AS` (singular `TOKEN`); for `SECOND_AND_FOURTH_OF_MONTH` consider abbreviation (this is a maintenance-window pattern). -- **Rationale:** Length is unavoidable for proper nouns but `RESTRICT_TOKENS_AND_JOB_RUN_AS` mixes plural noun + singular verb-phrase awkwardly. - -### 38. Enum values for domain-allow lists -- **File:line:** `model.ts:59-61` (`ALLOW_ALL_DOMAINS`, `ALLOW_APPROVED_DOMAINS`, `DENY_ALL_DOMAINS`) -- **Category:** Long enum value -- **Suggestion:** `ALLOW_ALL`, `ALLOW_APPROVED`, `DENY_ALL` — drop `_DOMAINS` since the enum is already named and the domain context is established. -- **Rationale:** Redundant tail. Compare with `STATUS_UNSPECIFIED`, `ALLOW_ALL`, `RESTRICT_TOKENS_AND_JOB_RUN_AS` — none carry a redundant noun. - -### 39. `disableGovTagCreation` — verb-as-field -- **File:line:** `model.ts:988` +### 36. `disableGovTagCreation` — verb-as-field +- **File:line:** `model.ts:983` - **Category:** Verb-tense inconsistency, cryptic abbreviation - **Suggestion:** `governanceTagCreationDisabled` or `restrictsGovernanceTagCreation`. `Gov` is also cryptic abbreviation. -- **Rationale:** The field is a boolean predicate that, when `true`, disables tag creation. A noun-phrase reads more naturally. `Gov` short for "governance" is non-standard — "Gov" usually means "government" — and is documented only by the comment on lines 985-987. +- **Rationale:** The field is a boolean predicate that, when `true`, disables tag creation. A noun-phrase reads more naturally. `Gov` short for "governance" is non-standard — "Gov" usually means "government" — and is documented only by the comment on lines 980-982. + +### 45. `EnablementDetails` / `enablementDetails` — generic `Details` suffix +- **File:line:** `model.ts:189 (field), 202 (type ClusterAutoRestartMessage_EnablementDetails)` +- **Why:** `Details` is one of the generic carry-all suffixes that proto-generated types use when the underlying message is "a bag of fields about X." The TS surface inherits this from the proto schema; the type name conveys nothing about *what* the details are (tier eligibility + entitlement + compliance-forcing flags). +- **Category:** Proto-architectural-leak (generic `Details` suffix) +- **Suggested:** `ClusterAutoRestartEligibility` or `AutoRestartAvailability`. The struct holds three booleans about *why* the feature is available/forced — "eligibility" or "availability" is the domain concept, not "details." +- **Rationale:** The JSDoc on lines 193-200 spells out the purpose: "contains an information about the enablement status judging (e.g. whether the enterprise tier is enabled)" — a customer-facing eligibility/availability concept. `Details` is the proto-side mechanical name. Pairs with #44 (nested-type artifact). --- ## Low severity -### 40. Cryptic wire-key abbreviations in URL slugs +### 37. Cryptic wire-key abbreviations in URL slugs - **File:line:** `client.ts:339 (aibi_dash_embed_ws_acc_policy), 381 (aibi_dash_embed_ws_apprvd_domains), 756, 796, 1261, 1296` - **Category:** Cryptic abbreviation - **Suggestion:** Wire keys are server-controlled; the SDK can't unilaterally rename. Worth flagging for the broader Databricks-platform team — these URL paths are exposed in logs and SDK telemetry. `apprvd` for `approved` saves 1 character. - **Rationale:** Wire keys aren't strictly in scope for naming audits, but they bleed into log lines and error messages. `dash_embed` for "dashboard embedding" is also non-obvious. -### 41. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix -- **File:line:** `client.ts:468 (default_namespace_ws), 876 (shield_csp_enablement_ws_db), 1104 (shield_esm_enablement_ws_db)` +### 38. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix +- **File:line:** `client.ts:468 (default_namespace_ws), 876 (shield_csp_enablement_ws_db), 956 (default_namespace_ws), 1104 (shield_esm_enablement_ws_db), 1369 (shield_csp_enablement_ws_db), 1439 (default_namespace_ws), 1560 (shield_esm_enablement_ws_db)` - **Category:** Cryptic abbreviation - **Suggestion:** Wire-team concern. `ws` is workspace, `db` is database (?), `ac` is account (in `accountsettings`). These two-letter suffixes are dense. - **Rationale:** `shield_csp_enablement_ws_db` mixes three abbreviated tokens (`shield` is fine, `csp` and `ws_db` are cryptic). -### 42. `eTag` (doc) vs `etag` (field) -- **File:line:** `model.ts:112-117, 252-259, 1024` (every `etag` doc block) +### 39. `eTag` (doc) vs `etag` (field) +- **File:line:** `model.ts:107-114, 248-254, 1012-1018` (every `etag` doc block) - **Category:** Acronym casing - **Suggestion:** Standardize either `etag` or `eTag`. RFC 7232 spells it "ETag" in HTTP headers; Databricks docs spell it `eTag` in prose and `etag` as the JSON field. - **Rationale:** Internal-doc inconsistency. The JSDoc on every type says "etag used for versioning. The response is at least as fresh as the eTag provided." — the same paragraph uses two casings. -### 43. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope -- **File:line:** `model.ts:248` +### 40. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope +- **File:line:** `model.ts:243` - **Category:** Singular/plural mismatch (mild — correct in context) - **Suggestion:** No change. Flagged only because the audit checklist asks for it. The field is correctly plural because it holds an array; the parent type is correctly singular because there is one profile. - **Rationale:** Consistent. No action needed. -### 44. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` -- **File:line:** `model.ts:135` +### 41. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` +- **File:line:** `model.ts:130` - **Category:** Singular/plural - **Suggestion:** None needed for this field. Flagging the parent type name — `AibiDashboardEmbeddingApprovedDomains` is plural (because it holds a list) while sibling `AibiDashboardEmbeddingAccessPolicy` is singular. The asymmetry is fine but inconsistent stylistically. - **Rationale:** Minor; preserved for completeness. -### 45. Wire-key length in shorter slugs +### 42. Wire-key length in shorter slugs - **File:line:** `client.ts:836 (automatic_cluster_update), 423 (dashboard_email_subscriptions), 673 (restrict_workspace_admins)` - **Category:** Verbose / could be shorter - **Suggestion:** Wire-team concern. @@ -351,16 +358,24 @@ 1. **Four overlapping settings packages.** `workspacesettings` + `settings` + `accountsettings` + `workspaceconf` is a confusing taxonomy with literal type duplication. Almost every type in `workspacesettings` has a doppelganger in `settings/v2`. (Severity #1, #2, #3, #4.) -2. **Sentinel `*_UNSPECIFIED` values.** Sentinel enum members flagged by their own docstrings as "should not be used in prod." (Severity #10.) +2. **`*Setting` triple-stutter.** Every primary type carries a `Setting` suffix despite the package name being `workspacesettings`. (Severity #15.) + +3. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #5, #6, #7, #8, #9, #30, #31, #32.) + +4. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #16-20, #33-34.) -3. **`*Setting` triple-stutter.** Every primary type carries a `Setting` suffix despite the package name being `workspacesettings`. (Severity #16.) +5. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #13, #14, #35.) -4. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #5, #6, #7, #8, #9, #31, #32, #33.) +6. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #10, #11.) -5. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #17-21, #34-35.) +7. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #37, #38.) + +8. **Proto-architectural-leak through `Message` suffix and `Parent_Nested` infix.** Top-level types `BooleanMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage` and the seven `*_Message_*` nested types expose the proto-generated naming convention directly to consumers. The codebase already acknowledges the leak via `eslint-disable -- Proto-style nested message name.` annotations on every such identifier. Generic `Details` suffix on `EnablementDetails` is the same pattern. (Severities #43, #44, #45.) + +--- -6. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #14, #15, #36.) +## Fixed -7. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #11, #12.) +All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. -8. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #40, #41.) +Fixed in regeneration on 2026-05-22. From 9e75cc3c0293d0223f16e2a846e96aafcddf78ee Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 26 May 2026 20:28:31 +0000 Subject: [PATCH 05/12] update --- .agent/naming-audit/_SUMMARY.md | 270 +++++++++--------- .agent/naming-audit/budgetpolicy.md | 54 ++-- .agent/naming-audit/budgets.md | 25 +- .agent/naming-audit/customllms.md | 86 +++--- .agent/naming-audit/database.md | 132 ++++----- .agent/naming-audit/dataclassification.md | 34 +-- .agent/naming-audit/entitytagassignments.md | 70 ++--- .agent/naming-audit/externallineage.md | 54 ++-- .agent/naming-audit/externalmetadata.md | 38 ++- .agent/naming-audit/genie.md | 166 ++++++----- .agent/naming-audit/instancepools.md | 39 +-- .agent/naming-audit/logdelivery.md | 62 ++-- .agent/naming-audit/marketplaces.md | 129 ++++----- .../naming-audit/notificationdestinations.md | 123 ++------ .agent/naming-audit/pipelines.md | 57 ++-- .agent/naming-audit/queries.md | 144 ++++------ .agent/naming-audit/queryhistory.md | 80 +++--- .agent/naming-audit/registeredmodels.md | 23 +- .agent/naming-audit/secretsuc.md | 20 +- .agent/naming-audit/tagassignments.md | 64 ++--- .agent/naming-audit/vectorsearch.md | 46 ++- 21 files changed, 727 insertions(+), 989 deletions(-) diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index 09d44c6f..74ce6092 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,7 +1,7 @@ # Cross-Package Naming Audit — Executive Summary **Packages audited:** 87 active API packages (every package under `packages//src//` after the 2026-05-22 generator regen consolidation). An additional 24 audit files exist for packages that were removed or consolidated in the regen; those audits are retired and their finding counts are excluded from the active total. See "Retired audits" at the bottom of §6. -**Total active findings across all 87 active audits:** **2,926** (down from 3,572 before the 2026-05-22 regen + rescan; previously 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep). The net drop in this regen is **~646** active findings — the bulk came from the generator renaming the `*Public*Request` family across account-tier packages, which moved ~81 findings into per-package `Fixed` sections; the rest came from 24 audits going to zero active findings as their source packages were consolidated into successor packages. +**Total active findings across all 87 active audits:** **2,891** (down from 2,926 before the 2026-05-22 Theme 2 prune; 3,572 before the 2026-05-22 regen + rescan; previously 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep). The 2026-05-22 Theme 2 prune removed ~35 active findings across 20 packages whose `Foo*` package-prefix issues were the sole concern; the remaining 32 candidate audits had no matching findings. **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` **Last source state:** Rescan against generator state 2026-05-22, upstream API version `0555d6a59265799ed8ea12f355eee662e739430d`. @@ -84,6 +84,21 @@ > totals, theme list (the former Theme 2 removed), and by-the-numbers > table below. +> **Prune pass 7 (2026-05-22) — Theme 2 retired.** Workflow B prune +> of "Type-name prefix repeats the package" per user direction +> ("Many type names re-state the package's domain noun. I don't fix +> it, it is fine as it is."). ~34 findings removed across 20 +> packages. Biggest removals: instancepools (5), +> notificationdestinations (4), entitytagassignments (3), +> customllms/externallineage/pipelines/queries/registeredmodels/tagassignments +> (2 each). The remaining 32 candidate audits had no matching +> findings — `Foo*`-prefixed types in those audits were flagged for +> OTHER primary issues (`Info` suffix, proto-architectural leak, +> vague names, cross-package duplicates) and retained. The pruned +> findings are reflected in the totals, theme 2 description below +> (marked retired in place), generator recommendations (§8.6 +> removed), Top-50, and by-the-numbers table below. + > **Rescan note (2026-05-20).** The generator was re-run and the > per-package audits were rescanned against the new source state. The > rescan dropped **710 findings net** and closed out several structural @@ -224,7 +239,7 @@ suffices. Examples: - `RepoInfo` → `Repo` / `GitFolder` (and the field `repo?: RepoInfo` becomes `repo?: Repo`). - `PolicyInfo` → `Policy`. -- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 4). +- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 3). - `SchemaInfo` → `Schema`. - `CredentialInfo` → `Credential`. - `MetastoreInfo` → `Metastore`. @@ -242,40 +257,19 @@ domain entity. (Heuristic: if `Info` is the only `*` type that isn't a request/response, drop `Info`.) Same for redundant `Options`/`Spec` suffixes on tagged-union arms when the parent has a discriminator. -### Theme 2. Type-name prefix repeats the package — ~45/87 packages - -Many type names re-state the package's domain noun even though the import -path already provides namespace disambiguation. The 2026-05-20 and -2026-05-22 generator rescans shrank this theme: the worst offenders -(`OAuthAppIntegration*` across `oauthcustomappintegration`/`oauthpublishedapp`, -`CleanRoom*` across three sibling packages, and the merged-in `Workspace*` -from `workspaceassignment`) were folded into consolidated packages, but the -remaining cases are still pervasive. - -- `pipelines.{PipelinesAwsAvailability, PipelinesAzureAvailability, PipelinesEbsVolumeType, PipelinesAwsAttributes, ...}` — 15 types prefixed with `Pipelines` (plural) when the package is singular-domain. `packages/pipelines/src/v2/model.ts:212, 225, 241, 2243, ...`. -- `genie.{GenieAttachment, GenieConversation, GenieMessage, GenieSpace, GenieFeedback, GenieEvalResult, ...}` — 40 types prefixed with `Genie` (and inconsistently — `Result`, `Schema`, `Thought` are not prefixed in the same file). -- `tagpolicies.TagPolicy`, `tagassignments.TagAssignment`, `entitytagassignments.EntityTagAssignment`. -- `customllms.CustomLlm`, `customLlmFieldMask`, `createCustomLlm`, etc. -- `cleanrooms.CleanRoom*` family — still pervasive after absorbing the sibling packages. -- `oauth.OAuthAppIntegration*` family — still pervasive after the merge. - -**Generator fix:** When emitting TS, strip the package-name prefix from -every type as long as the unprefixed name does not clash with another type -in the same package. Wire shape is unaffected. - -### Theme 3. Inconsistent acronym casing across the SDK — 87/87 packages +### Theme 2. Inconsistent acronym casing across the SDK — 87/87 packages > **Status (2026-05-21):** Policy adopted (Google TS Style Guide: > "treat acronyms as whole words"). The rule was already at > `.agent/rules/typescript.mdc:184`. All hand-written-package renames -> listed in 3b have been applied. Theme 3a generated-code outliers +> listed in 2b have been applied. Theme 2a generated-code outliers > remain — `OAuth*` is documented as a platform-name exception per > RFC 6749 (kept). The SDK has no project-wide acronym-casing policy. The inconsistencies appear on two distinct surfaces, each with a different cause and fix path. -#### 3a. Generated code — 87/87 packages +#### 2a. Generated code — 87/87 packages The generator already uses **`Pascal-then-lower`** very consistently for TS identifiers (`Url`, `Id`, `Json`, `Sql`, `Http`, `Oauth`, `Aws`, @@ -324,7 +318,7 @@ small number of `OAuth*` identifiers. The two consistent options: 1. **Google TS style guide (`Pascal-then-lower`):** `Url`, `Id`, `Sql`, `Json`, `Oauth`. Pro: matches what the generator already emits for ~99% of identifiers; lowest-churn path. Con: `Oauth` deviates slightly from the brand spelling `OAuth`. 2. **.NET / Microsoft (`ALL_CAPS` for ≤2-letter, `Pascal-then-lower` for ≥3):** `URL`, `ID`, `Sql`, `Json`, `OAuth`. Pro: matches HTTP/RFC casing and the brand. Con: requires renaming ~3300 `*Id` identifiers and ~445 `*Url` identifiers across the whole corpus — major generator+spec change. -#### 3b. Hand-written code — 5/5 packages (`auth`, `core`, `databricks`, `sdk`, `options`) +#### 2b. Hand-written code — 5/5 packages (`auth`, `core`, `databricks`, `sdk`, `options`) **Status: Fixed (2026-05-21).** The renames listed below were applied. The historical table and prose are retained as a record of the BEFORE @@ -348,7 +342,7 @@ constants) were: > the platform-name exception. `SCREAMING_SNAKE_CASE` constants > unaffected. -### Theme 4. Brand drift / rebrand leakage — ~10/87 packages +### Theme 3. Brand drift / rebrand leakage — ~10/87 packages Several products were rebranded but the TS surface still carries the old codename: @@ -363,7 +357,7 @@ codename: **Generator fix:** Per-product spec needs updates; the rename can land via a generator alias map (`Endpoint` → `Warehouse` in `warehouses` only, etc.). -### Theme 5. Proto-architectural-leak infixes — ~10/87 packages, ~50 findings (substantially shrunk) +### Theme 4. Proto-architectural-leak infixes — ~10/87 packages, ~50 findings (substantially shrunk) Internal proto / service-tier identifiers leak through the codegen and show up as mid-position infix tokens that have no meaning to a TS SDK consumer. @@ -733,7 +727,7 @@ this rule on 2026-05-21. Document the choice in --- -## 5. Top-50 highest-impact individual findings +## 5. Top-48 highest-impact individual findings Picked one per package where possible, prioritising ones with broad reuse. Findings ranked High severity in their audit. Entries whose package was @@ -742,7 +736,13 @@ removed; entries about the now-pruned enum-name-prefix theme and `*_UNSPECIFIED` sentinel existence have been removed; entries whose underlying finding has moved to `Fixed` after the 2026-05-22 regen (the `*Public*Request` proto-leak across `networking`, `workspaces`, -`metastores`, etc.) have been removed. Each entry: file + symbol + the +`metastores`, etc.) have been removed. In the 2026-05-22 Theme 2 prune +the former `pipelines` "Pipelines\* prefix on 15 types" row and the +`genie` "40 of ~70 types prefixed Genie\*" row were removed. Entries +for `oauth` (`OAuthAppIntegration*`) and `cleanrooms` (`CleanRoom*`) +are retained because their `Foo*` prefixes were flagged for the +secondary consolidation/merge symptom — see prune note 7 — not the +type-name-prefix-only finding. Each entry: file + symbol + the generator pattern it exemplifies. | # | Package | File:Line | Symbol / Issue | Pattern | @@ -751,52 +751,50 @@ generator pattern it exemplifies. | 2 | `jobs` | `model.ts:150, 280, 1464, 1835` | `Format`, `Source`, `Compute`, `Environment` — top-level types collide with JS/TS built-ins and DOM globals. | Reserved-word collision | | 3 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | | 4 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | -| 5 | `pipelines` | `model.ts:212-2507` | `Pipelines*` prefix on 15 types in a package called `pipelines` (singular). | Type-name prefix repeats package | -| 6 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | -| 7 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | -| 8 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | -| 9 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | -| 10 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | -| 11 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission.CAN_USE` — `App` token thrice; package-name re-prefix throughout. | Redundant prefix | -| 12 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | -| 13 | `genie` | `model.ts passim` | 40 of ~70 types prefixed `Genie*`; remaining have no prefix. | Inconsistent type prefix | -| 14 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | -| 15 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | -| 16 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | -| 17 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | -| 18 | `secrets` | `model.ts:passim` | `ListAcls_Response.items` should be `acls` (parallel to `ListScopes_Response.scopes` / `ListSecrets_Response.secrets`). | Field-name vocabulary drift | -| 19 | `dataquality` | model + types | `ListMonitorRequest` singular for list of monitors; `qualitymonitor`/`qualitymonitors` deprecated and retired in 2026-05-22 regen. | Singular/plural mismatch | -| 20 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | -| 21 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | -| 22 | `oauth` | `model.ts:passim` | After the merge, `OAuthAppIntegration*` types still re-state the package name on every shape. | Type-name prefix | -| 23 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, the type-name overlap with `iam` and `grants` is still present. | Cross-package fragmentation | -| 24 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | -| 25 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | -| 26 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | -| 27 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | -| 28 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | -| 29 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | -| 30 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | -| 31 | `cleanrooms` | `model.ts:passim` | After absorbing 3 sibling packages, `CleanRoom*` re-prefix still pervades. | Type-name prefix | -| 32 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | -| 33 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | -| 34 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | -| 35 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | -| 36 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | -| 37 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | -| 38 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | -| 39 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | -| 40 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | -| 41 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum has 22 values with inconsistent casing (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Acronym/brand-value casing | -| 42 | `clusters` | `model.ts:175-734` | `TerminationCode` enum has 150+ values with inconsistent casing (`AZURE_BYOK_*`, `NPIP_*`, `K8S_DBR_*`, `AWS_*`). | Acronym/brand-value casing | -| 43 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | -| 44 | `bundle` | package + types | Bare "bundle" word collides with Webpack/Vite/Rollup; verb-as-noun residue in request types. | Generic naming | -| 45 | `instancepools` | `model.ts:passim` | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | -| 46 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection`; `tpe` typo (likely intended `type`). | Generator stutter + typo | -| 47 | `settings` | `model.ts:passim` | After the regen consolidation, the v2 surface still carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrapper sprawl. | Generic + cryptic | -| 48 | `jobs` | `model.ts:passim` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | -| 49 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun, not a domain concept. | Proto-architectural leak (`Service` infix) | -| 50 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | +| 5 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | +| 6 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | +| 7 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | +| 8 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | +| 9 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | +| 10 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission.CAN_USE` — `App` token thrice; package-name re-prefix throughout. | Redundant prefix | +| 11 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | +| 12 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | +| 13 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | +| 14 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | +| 15 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | +| 16 | `secrets` | `model.ts:passim` | `ListAcls_Response.items` should be `acls` (parallel to `ListScopes_Response.scopes` / `ListSecrets_Response.secrets`). | Field-name vocabulary drift | +| 17 | `dataquality` | model + types | `ListMonitorRequest` singular for list of monitors; `qualitymonitor`/`qualitymonitors` deprecated and retired in 2026-05-22 regen. | Singular/plural mismatch | +| 18 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | +| 19 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | +| 20 | `oauth` | `model.ts:passim` | After the merge, `OAuthAppIntegration*` types still re-state the package name on every shape. The finding survives prune-pass 7 because its primary citation is the post-merge `Custom`/`Published` consolidation friction, not the bare package-prefix pattern. | Post-merge prefix friction (Theme 2 retained) | +| 21 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, the type-name overlap with `iam` and `grants` is still present. | Cross-package fragmentation | +| 22 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 23 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | +| 24 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | +| 25 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | +| 26 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | +| 27 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 28 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | +| 29 | `cleanrooms` | `model.ts:passim` | After absorbing 3 sibling packages, `CleanRoom*` re-prefix still pervades. Retained post-prune-pass 7 because the finding is cited for the post-consolidation friction, not the bare package-prefix pattern. | Post-merge prefix friction (Theme 2 retained) | +| 30 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | +| 31 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | +| 32 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | +| 33 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | +| 34 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | +| 35 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 36 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | +| 37 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 38 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | +| 39 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum has 22 values with inconsistent casing (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Acronym/brand-value casing | +| 40 | `clusters` | `model.ts:175-734` | `TerminationCode` enum has 150+ values with inconsistent casing (`AZURE_BYOK_*`, `NPIP_*`, `K8S_DBR_*`, `AWS_*`). | Acronym/brand-value casing | +| 41 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | +| 42 | `bundle` | package + types | Bare "bundle" word collides with Webpack/Vite/Rollup; verb-as-noun residue in request types. | Generic naming | +| 43 | `instancepools` | `model.ts:passim` | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | +| 44 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection`; `tpe` typo (likely intended `type`). | Generator stutter + typo | +| 45 | `settings` | `model.ts:passim` | After the regen consolidation, the v2 surface still carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrapper sprawl. | Generic + cryptic | +| 46 | `jobs` | `model.ts:passim` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | +| 47 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun, not a domain concept. | Proto-architectural leak (`Service` infix) | +| 48 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | --- @@ -809,88 +807,89 @@ generator pattern it exemplifies. | 3 | settings | 84 | Cross-package consolidation residue; cryptic acronyms (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | | 4 | clusters | 78 | Per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | | 5 | modelregistry | 66 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | -| 6 | pipelines | 64 | `Update` noun = pipeline run; `Pipelines*` prefix on every type; JSDoc "Public RPC" banners | -| 7 | apps | 63 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | -| 8 | genie | 62 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 6 | apps | 63 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | +| 7 | pipelines | 62 | `Update` noun = pipeline run; JSDoc "Public RPC" banners (Theme 2 `Pipelines*` prefix pruned 2026-05-22) | +| 8 | genie | 61 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term (Theme 2 `Genie*` prefix pruned 2026-05-22) | | 9 | instanceprofiles | 61 | Bare verb request types; vague identifiers | | 10 | tables | 58 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 11 | database | 55 | Package name overlaps `postgres`; deep proto nesting; proto-architectural infixes | +| 11 | database | 54 | Package name overlaps `postgres`; deep proto nesting; proto-architectural infixes | | 12 | postgres | 54 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | -| 13 | marketplaces | 52 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | -| 14 | statementexecution | 52 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | -| 15 | features | 51 | Three sibling feature packages with blurry boundaries (now reduced to 2 after `materializedfeatures` retirement) | +| 13 | statementexecution | 52 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | +| 14 | features | 51 | Three sibling feature packages with blurry boundaries (now reduced to 2 after `materializedfeatures` retirement) | +| 15 | marketplaces | 51 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | | 16 | experiments | 48 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | | 17 | globalinitscripts | 48 | Verb-as-noun requests; brittle `script_id` path-parameter handling; proto suffix | | 18 | modelserving (was modelservingmanagement + modelservingdebug) | 47 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | -| 19 | queryhistory | 47 | Vague `Query` types; cross-package overlap with `queries` | -| 20 | instancepools | 44 | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`; proto-suffix | -| 21 | clusterpolicies | 41 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | -| 22 | dataquality | 41 | `ListMonitorRequest` singular for list of monitors | -| 23 | policyfamilies | 41 | "Family" + "Policy Family" mixed; underscored enums | +| 19 | queryhistory | 46 | Vague `Query` types; cross-package overlap with `queries` | +| 20 | clusterpolicies | 41 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | +| 21 | dataquality | 41 | `ListMonitorRequest` singular for list of monitors | +| 22 | policyfamilies | 41 | "Family" + "Policy Family" mixed; underscored enums | +| 23 | instancepools | 39 | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`; proto-suffix (Theme 2 prefix pruned 2026-05-22) | | 24 | accessmanagement (was permissions + workspaceassignment + accountaccesscontrol(+proxy)) | 38 | Permissions/grants/rule-sets fragmentation; absorbed account access control | | 25 | knowledgeassistants | 37 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | | 26 | supervisoragents | 37 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | | 27 | commandexecution | 36 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | -| 28 | externalmetadata | 36 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | -| 29 | rfa | 36 | 3-letter cryptic package name | -| 30 | alerts | 35 | Mixed v1/v2 | -| 31 | credentials | 35 | UC vs auth duplicate; `Accounts*` family (the `Public*` infix has been removed in the 2026-05-22 regen) | +| 28 | rfa | 36 | 3-letter cryptic package name | +| 29 | alerts | 35 | Mixed v1/v2 | +| 30 | credentials | 35 | UC vs auth duplicate; `Accounts*` family (the `Public*` infix has been removed in the 2026-05-22 regen) | +| 31 | externalmetadata | 35 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | | 32 | lakeview | 35 | Old codename (rebrand to "AI/BI Dashboards") | -| 33 | queries | 35 | Three-package overlap with `queryhistory`/`statementexecution` | -| 34 | usagepolicy | 35 | 1:1 clone of `budgetpolicy` | -| 35 | bundle | 34 | Generic package name (`bundle`); verb-as-noun requests | -| 36 | iam | 33 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | -| 37 | onlinetables | 33 | Underspecified IDs; deprecation drift | -| 38 | customllms | 32 | `Llm` casing throughout | +| 33 | usagepolicy | 35 | 1:1 clone of `budgetpolicy` | +| 34 | bundle | 34 | Generic package name (`bundle`); verb-as-noun requests | +| 35 | iam | 33 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | +| 36 | onlinetables | 33 | Underspecified IDs; deprecation drift | +| 37 | queries | 33 | Three-package overlap with `queryhistory`/`statementexecution` | +| 38 | customllms | 30 | `Llm` casing throughout (Theme 2 `CustomLlm*` prefix pruned 2026-05-22) | | 39 | modelservingquery | 30 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | | 40 | secrets | 30 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | -| 41 | budgetpolicy | 29 | Sibling clone in `usagepolicy` | -| 42 | connections | 29 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 43 | featurestore | 29 | Cross-package duplicates in feature trio | -| 44 | tagassignments | 29 | Three-package tag split; sibling field-name drift | -| 45 | workspaceobjects (was workspace) | 29 | Filesystem scope clarified by rename; `fullNameArg` residue | -| 46 | cleanrooms (absorbed cleanroomassets + cleanroomautoapprovalrules + cleanroomtaskruns) | 28 | Type-prefix `CleanRoom*` pervades the consolidated package | -| 47 | clusterlibraries | 28 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 48 | environments | 28 | `Environment` generic name | -| 49 | logdelivery (was logdeliveryconfigurations) | 28 | Renamed; legacy long name fixed | -| 50 | vectorsearch (was endpoints + indexes) | 28 | `Endpoint*` and `VectorIndex*` overlap; vector search renamed in place | -| 51 | entitytagassignments | 27 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 52 | repos | 27 | "Repos" legacy term; product is "Git folders" | -| 53 | abacpolicies | 26 | `PolicyInfo`; verb-as-noun requests | -| 54 | workspacebindings | 26 | Bare verb requests | -| 55 | budgets | 25 | Budget vs `budgetpolicy` duplication | -| 56 | externallineage | 24 | `Direction_LineageDirection`; `tpe` typo | -| 57 | files | 24 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | -| 58 | notificationdestinations | 24 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 59 | secretsuc | 24 | `uc` cryptic suffix; collides with `secrets` | -| 60 | disasterrecovery | 23 | `FailoverFailoverGroupRequest` stutter | -| 61 | functions | 23 | `function` reserved-word; `fullNameArg`; cryptic single-letter enum variants | -| 62 | tokens | 22 | Cross-package duplicate of `tokenmanagement` | -| 63 | gitcredentials | 21 | Three "Credentials" packages with different meanings | -| 64 | grants | 21 | Verb-phrase request types | -| 65 | billableusagedownload | 20 | Verb in package name (`download`) | +| 41 | connections | 29 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 42 | featurestore | 29 | Cross-package duplicates in feature trio | +| 43 | workspaceobjects (was workspace) | 29 | Filesystem scope clarified by rename; `fullNameArg` residue | +| 44 | budgetpolicy | 28 | Sibling clone in `usagepolicy` | +| 45 | cleanrooms (absorbed cleanroomassets + cleanroomautoapprovalrules + cleanroomtaskruns) | 28 | Post-consolidation `CleanRoom*` re-prefix friction (the bare-prefix instance was pruned; the post-merge consolidation symptom is retained) | +| 46 | clusterlibraries | 28 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 47 | environments | 28 | `Environment` generic name | +| 48 | logdelivery (was logdeliveryconfigurations) | 27 | Renamed; legacy long name fixed | +| 49 | repos | 27 | "Repos" legacy term; product is "Git folders" | +| 50 | tagassignments | 27 | Three-package tag split; sibling field-name drift | +| 51 | vectorsearch (was endpoints + indexes) | 27 | `Endpoint*` and `VectorIndex*` overlap; vector search renamed in place | +| 52 | abacpolicies | 26 | `PolicyInfo`; verb-as-noun requests | +| 53 | workspacebindings | 26 | Bare verb requests | +| 54 | budgets | 24 | Budget vs `budgetpolicy` duplication | +| 55 | entitytagassignments | 24 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 56 | files | 24 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | +| 57 | disasterrecovery | 23 | `FailoverFailoverGroupRequest` stutter | +| 58 | functions | 23 | `function` reserved-word; `fullNameArg`; cryptic single-letter enum variants | +| 59 | secretsuc | 23 | `uc` cryptic suffix; collides with `secrets` | +| 60 | externallineage | 22 | `Direction_LineageDirection`; `tpe` typo | +| 61 | tokens | 22 | Cross-package duplicate of `tokenmanagement` | +| 62 | gitcredentials | 21 | Three "Credentials" packages with different meanings | +| 63 | grants | 21 | Verb-phrase request types | +| 64 | billableusagedownload | 20 | Verb in package name (`download`) | +| 65 | notificationdestinations | 20 | `Config`/`config` self-reference; `DestinationType` vague enum | | 66 | tokenmanagement | 19 | Overlap with `tokens`; duplicate `AutoscopeState` enum | | 67 | usagedashboards | 19 | Vague type names | -| 68 | dataclassification | 18 | Tag-domain overlap | -| 69 | resourcequotas | 18 | Vague type names | -| 70 | tagpolicies | 18 | Three sibling tag packages with overlapping vocab | -| 71 | volumes | 18 | `fullNameArg`; verb-as-noun requests | -| 72 | registeredmodels | 17 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | -| 73 | schemas | 17 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | -| 74 | artifactallowlists | 15 | Vague type names | -| 75 | metastores | 15 | Structural duplicate of `MetastoreInfo` — 20 `Accounts*MetastorePublic*` findings moved to Fixed in 2026-05-22 regen | +| 68 | resourcequotas | 18 | Vague type names | +| 69 | tagpolicies | 18 | Three sibling tag packages with overlapping vocab | +| 70 | volumes | 18 | `fullNameArg`; verb-as-noun requests | +| 71 | dataclassification | 17 | Tag-domain overlap | +| 72 | schemas | 17 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | +| 73 | artifactallowlists | 15 | Vague type names | +| 74 | metastores | 15 | Structural duplicate of `MetastoreInfo` — 20 `Accounts*MetastorePublic*` findings moved to Fixed in 2026-05-22 regen | +| 75 | registeredmodels | 15 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | | 76 | catalogs | 13 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | | 77 | externallocations | 13 | `nameArg` cryptic suffix; cross-cloud queue type naming inconsistency (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | | 78 | scim | 13 | Account-tier SCIM 2.0 user/group provisioning; proto-architectural surface | | 79 | systemschemas | 13 | Sibling-package collision with `schemas` | | 80 | forecasting | 11 | Generic-named `Waiter` API; cross-package overlap with `experiments`; "Wrapper message" JSDoc | -| 81 | oauth (was oauthcustomappintegration + oauthpublishedapp) | 11 | OAuth Custom + Published app integrations consolidated; type-name prefix `OAuthAppIntegration*` persists | +| 81 | oauth (was oauthcustomappintegration + oauthpublishedapp) | 11 | OAuth Custom + Published app integrations consolidated; `OAuthAppIntegration*` retained per prune-pass 7 (post-merge consolidation friction) | | 82 | sharing | 5 | Account-tier Delta Sharing provider config | | 83 | workspaces | 5 | Singular/plural residue after 16 `*Public*Request` findings moved to Fixed | | 84 | authentication | 4 | Account-tier token federation policies | | 85 | networking | 4 | Singular/plural residue after 17 `*Public*Request` findings moved to Fixed; ~40 active `CustomerFacing*` identifiers not yet flagged | | 86 | storageconfigurations | 4 | Sparse account-tier residue after `*Public*Request` findings moved to Fixed | | 87 | keyconfigurations | 1 | Singular `ListCustomerManagedKeyRequest` residue after `*Public*Request` findings moved to Fixed | +| — | **Total** | **2,891** | Across all 87 active audits | ### Retired audits (24 — excluded from the active total) @@ -944,8 +943,9 @@ The previous §§8.1–8.6 recommendations have all been retired: not a generator concern. - The `Request` suffix recommendation (former §8.5) is **Done**: every request DTO is now emitted with a `Request` suffix. -- The strip-package-name-prefix recommendation (former §8.6) is an API-team - decision, not a generator template change. +- The strip-package-name-prefix recommendation (former §8.6) is **withdrawn** + per prune-pass 7 (2026-05-22): the package-name prefix is now considered + intentional. Neither a generator change nor an API-team rename is planned. ### 7.1 Surface deprecations as `@deprecated` JSDoc tags diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index 9df9b1d0..42b91507 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,13 +3,13 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 29 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 11 | +| Medium | 10 | | Low | 7 | | Observation | 5 | @@ -53,67 +53,61 @@ ## Medium severity -### 7. `CustomPolicyTag` type name — `src/v1/model.ts:51` -- **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. -- **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location). -- **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. -- **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". - -### 8. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` +### 7. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. - **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. -### 9. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:80,85,90` +### 8. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:80,85,90` - **Why weird:** `Filter` has three optional fields whose names imply they specify *one* policy, but the JSDoc says they apply as substring/equality filters across the list. Names like `policyName: 'foo'` read as "the policy named foo"; what it actually means is "policies whose name contains 'foo'". The JSDoc clarifies but the name misleads. - **Category:** 6 (misleading — singular noun for a substring/multi-match filter). - **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to `creatorUserNames: string[]`). - **Rationale:** Filter DSLs benefit from explicit operators. Bare names suggest exact match. -### 10. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:85,90` +### 9. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:85,90` - **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number` (a JS-unsafe representation for 64-bit IDs — but at least the Go SDK numeric type is `int64` here), while `creatorUserName` is `string`. - **Category:** 12 (duplicate concept — two ways to filter on the same domain object), 19 (underspecified ID — `creatorUserId` is a numeric id from an unknown id space). - **Suggested name:** Collapse to `creator?: Creator` with `{id?: number; name?: string}`, or document AND/OR. - **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine. Even the JSDoc says "If unspecified, all policies will be returned" on each one — but doesn't say what happens if both are set. -### 11. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` +### 10. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 30). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 30 and `Filter.creatorUserId` here. -### 12. `SortSpec` type — `src/v1/model.ts:147` +### 11. `SortSpec` type — `src/v1/model.ts:147` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 13. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:148` +### 12. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:148` - **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. - **Category:** Observation (typo). - **Suggested name:** Fix spelling. - **Rationale:** Minor; flagging because it surfaces in IntelliSense. -### 14. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:134` +### 13. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:134` - **Why weird:** Field `policies` of type `BudgetPolicy[]`. Within the `budgetpolicy` package, `policies` is fine — but within a multi-package consumer with `BudgetConfigurations.budgets` (line 170 of budgets) and `usagepolicy.policies`, the field `policies` becomes ambiguous when copy-pasted. - **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on request). - **Suggested name:** `budgetPolicies: BudgetPolicy[]`. - **Rationale:** Tied to type rename suggestion #4. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. -### 15. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:144` +### 14. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:144` - **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listBudgetPoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. -### 16. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:142` +### 15. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:142` - **Why weird:** Doc reads "In this field is omitted, there are no previous pages." — "In" should be "If". - **Category:** Observation (typo). - **Suggested name:** Fix doc. - **Rationale:** Generated; surfaces in IntelliSense. -### 17. `SortSpec_Field` enum name — `src/v1/model.ts:6` +### 16. `SortSpec_Field` enum name — `src/v1/model.ts:6` - **Why weird:** Proto-architectural-leak: the underscore-joined `ParentType_NestedType` form is the protobuf/Go-SDK convention for emitting nested enum types into a flat namespace. TS already supports namespaces and modules natively, so the underscore is a wire-protocol artifact bleeding into the public TS API. The eslint-disable comment on the prior line even labels it "Proto-style nested enum name", confirming the generator knows it is non-idiomatic. - **Category:** Proto-architectural leak (proto-style nested-type encoding leaking into TS identifiers). - **Suggested name:** `SortField` (drop the `Spec_` prefix entirely; the enum stands on its own as the set of sortable fields) or `SortSpecField` (camel-join, no underscore). @@ -121,43 +115,43 @@ ## Low severity -### 18. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:44-46` +### 17. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:44-46` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. - **Category:** Observation, 14 (wire-style identifiers in TS docs). - **Suggested name:** Fix the doc to reference TS field names. - **Rationale:** Editing UX: hovers should show TS, not proto. -### 19. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:157` +### 18. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:157` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). - **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. - **Rationale:** Real bug. -### 20. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 19. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. -### 21. `HttpCallOptions` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. -### 22. `readAll` — `src/v1/utils.ts:40` +### 21. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 23. `flattenQueryParams` — `src/v1/utils.ts:123` +### 22. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 24. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -165,27 +159,27 @@ ## Observations -### 25. `Client` class plain name — `src/v1/client.ts:46` +### 24. `Client` class plain name — `src/v1/client.ts:46` Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 26. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 25. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. -### 27. Action-verb conventions in `Client` +### 26. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 28. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +### 27. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. - **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). -### 29. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 28. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 5eb6f4f2..7581e972 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -348,23 +348,11 @@ _None._ types and have `Create.../Update...` request types embed `BudgetConfiguration` (or `Budget`) directly. See also F10 / F11. -#### F7.4 — Method names mirror request types (MEDIUM) -- **Where:** `client.ts:79, 111, 139, 173, 233`. -- **Why flagged:** Methods are - `createBudgetConfiguration`, `deleteBudgetConfiguration`, - `getBudgetConfiguration`, `listBudgetConfigurations`, - `updateBudgetConfiguration`. Inside a `Budgets` client, the - `Budget`/`Budgets` suffix is repetitive. Compare typical TS SDK - shape: `budgets.create(...)`, `budgets.list(...)`. -- **Suggestion:** `create`, `delete`, `get`, `list`, - `update`. The class itself already conveys "budgets". This is a - cross-package convention to decide once. - -#### F7.5 — `LIST_PRICE_DOLLARS_USD` doubly redundant (LOW) +#### F7.4 — `LIST_PRICE_DOLLARS_USD` doubly redundant (LOW) - **Where:** `model.ts:10`. - **Why flagged:** `DOLLARS_USD` is tautological — USD *is* dollars. This is a wire-protocol value, so the SDK cannot change it - unilaterally, but worth noting upstream. + unilaterally, but worth noting upstream. See also F17.2. - **Suggestion:** Wire protocol; leave with a comment. --- @@ -642,7 +630,7 @@ _None._ #### F17.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) - **Where:** `model.ts:10`. - **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant - (F7.5). Could be `LIST_PRICE_USD` or `USD`. + (F7.4). Could be `LIST_PRICE_USD` or `USD`. - **Suggestion:** Wire value; report upstream. #### F17.3 — `EMAIL_NOTIFICATION` (LOW) @@ -732,7 +720,7 @@ This SDK exposes two separate packages whose names both start with | 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 7 | | 6 | Misleading names | 5 | -| 7 | Overly verbose | 5 | +| 7 | Overly verbose | 4 | | 8 | Singular / plural mismatch | 5 (3 acceptable) | | 9 | Reserved-word collisions | 5 (3 acceptable) | | 10 | Empty / trivial wrappers | 0 | @@ -761,9 +749,8 @@ This SDK exposes two separate packages whose names both start with mismatch. 4. **F1.1 / F1.2 / F15.1:** Rename `ActionConfiguration` to `BudgetAlertAction`, `target` to `recipient`. -5. **F7.2 / F7.4:** Drop "Configuration" from request type names - (`CreateBudgetRequest`) and method names - (`budgets.create(...)`). +5. **F7.2:** Drop "Configuration" from request type names + (`CreateBudgetRequest`). 6. **F11.4:** Lift `accountId` to top-level on all request types (currently nested under `budget` for create/update only). 7. **F13.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 58a9be67..23e93da5 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -3,61 +3,55 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 **Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. -**Total weird names flagged:** 32 +**Total weird names flagged:** 30 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 13 | +| High | 7 | +| Medium | 12 | | Low | 7 | | Observation | 4 | ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #30). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #28). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. -### 2. `CustomLlm` package, `CustomLlm` type, `customLlm` field — `src/v1/model.ts:43,96` -- **Why weird:** The package is called `customllms`, the only domain entity is called `CustomLlm`, and every request type repeats the noun: `CreateCustomLlmRequest`, `DeleteCustomLlmRequest`, `GetCustomLlmRequest`, `UpdateCustomLlmRequest`, `StartCustomLlmOptimizationRunRequest`, `CancelCustomLlmOptimizationRunRequest`. Inside `UpdateCustomLlmRequest` there is even a `customLlm: CustomLlm` field (model.ts:96). Once the consumer has imported from `@databricks/sdk-customllms` the `Custom` prefix is pure namespace echo. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology on `customLlm: CustomLlm`). -- **Suggested name:** Drop the `Custom` prefix throughout — `Llm`, `CreateLlmRequest`, `UpdateLlmRequest`, `StartOptimizationRunRequest`, etc. The field `customLlm` becomes `llm`. -- **Rationale:** The package path already supplies the "custom" qualifier (`customllms.Llm`). The redundant prefix burns ~7 characters of every type name without adding meaning. - -### 3. `State` enum (top-level, ungrouped) — `src/v1/model.ts:9-17` +### 2. `State` enum (top-level, ungrouped) — `src/v1/model.ts:9-17` - **Why weird:** The enum is named `State` — the most generic noun in any API. There is no qualifier to tell the reader *which* state (optimization run? custom LLM? endpoint?). The doc comment ("States of Custom LLM optimization lifecycle.") clarifies, but the name alone does not. Every other Databricks package has its own `State` (jobs, clusters, queries) and a user importing two of them will be forced to alias. - **Category:** 1 (vague/generic), 15 (generic field name). - **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). - **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. -### 4. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` +### 3. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` - **Why weird:** Doc comment "The Id of the tile." refers to a "tile" that does not exist anywhere else in the package. This is almost certainly a copy-paste from another generated API (dashboards/tiles). Either the field name or the doc is wrong; reading the surrounding code, the field is the custom-LLM id (same as `CancelCustomLlmOptimizationRunRequest.id` on line 20). Public SDK doc bug. - **Category:** 6 (misleading — doc contradicts the actual domain). - **Suggested name:** Field name stays `id`; fix the JSDoc to "The id of the custom LLM whose optimization run to start." (matches `DeleteCustomLlmRequest.id` and `GetCustomLlmRequest.id` docs on lines 69 and 74). - **Rationale:** A naming audit should flag doc-text bugs on identifiers as well as the identifier itself; consumers learn the semantics from JSDoc and a wrong doc is as harmful as a wrong name. -### 5. `id` field on every request and on `CustomLlm` — `src/v1/model.ts:20,44,70,75,80,94` +### 4. `id` field on every request and on `CustomLlm` — `src/v1/model.ts:20,44,70,75,80,94` - **Why weird:** Bare `id` shows up on six places (`Cancel...Request.id`, `CustomLlm.id`, `Delete...Request.id`, `Get...Request.id`, `Start...Request.id`, `Update...Request.id`). Every JSDoc has to redundantly say "The id of the custom llm". A typed `customLlmId` makes the wire/TS surface self-documenting and avoids confusion with future API extensions (the endpoint is at `/api/2.0/custom-llms/{id}` — `id` here is the LLM id, not a generic id). - **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `customLlmId` (or `llmId` if the `Custom` prefix is dropped per #2). Wire stays `id`. +- **Suggested name:** `customLlmId` (or `llmId` if the `Custom` prefix is dropped). Wire stays `id`. - **Rationale:** When grepping logs or stack-traces for `customLlmId`, you'll find the right call site. Today you'll grep for `id` and get 50 false positives across the SDK. -### 6. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` +### 5. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` - **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. - **Category:** Observation / 6 (misleading — field-mask implies updatable). - **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. - **Rationale:** This is the kind of thing a careful TS API designer would notice; a generator running over the proto schema will not. -### 7. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` +### 6. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` - **Why weird:** `UpdateCustomLlmRequest.customLlm: CustomLlm | undefined`. The TS naming convention makes the field/type distinction work via casing — but at a call site you'll write `req.customLlm = {...} satisfies CustomLlm`, and `customLlm` (the field) is one character of casing away from `CustomLlm` (the type). Type-suffix tautology under rule 20. - **Category:** 20 (type-suffix tautology). -- **Suggested name:** Rename `customLlm` field → `llm` (paired with type rename `CustomLlm` → `Llm` per #2). Even without the type rename, the field can be `target` or `update`. -- **Rationale:** `req.llm` reads cleanly; `req.customLlm` is the kind of name that survives code review only because nobody wants to argue with the generator. +- **Suggested name:** Rename `customLlm` field → `target` or `update` so the field name is not a casing of the type name. +- **Rationale:** `req.target` reads cleanly; `req.customLlm` is the kind of name that survives code review only because nobody wants to argue with the generator. -### 8. `CustomLlm.creator: string` — `src/v1/model.ts:58` +### 7. `CustomLlm.creator: string` — `src/v1/model.ts:58` - **Why weird:** "Creator of the custom LLM" — but a `creator` could be a username, an email, a UUID, a Databricks principal-id, or a service-principal client-id. The type is `string` so there is no help. Other Databricks SDK packages (catalog, jobs) use `createdBy` or `creator` similarly inconsistently. The name does not say *what kind* of identifier it is. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `createdBy` if it is a user/principal id (matches Unity Catalog convention); add `@format` JSDoc clarifying whether it is an email or a UUID. @@ -65,79 +59,73 @@ ## Medium severity -### 9. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` +### 8. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` - **Why weird:** `creationTime` is named with the type-suffix convention (`*Time`), while peer fields on the same struct use bare nouns (`creator`, `name`, `instructions`). The other generated SDKs sometimes use `createdAt` or `createTime`. Naming `creationTime` is fine, but it is the *only* type-suffix field on `CustomLlm`. - **Category:** 17 (inconsistency within the same struct). - **Suggested name:** `createdAt` (Stripe/GitHub convention, https://stripe.com/docs/api/charges/object) or `createTime` (Google AIP-142, https://google.aip.dev/142). Either is more standard than `creationTime`. - **Rationale:** AIP-142 (Google API design) says: "Fields representing the time at which a resource was created should be of type google.protobuf.Timestamp and called `create_time`." The Go SDK and Java SDK tend to mirror this; TS should too. -### 10. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` +### 9. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` - **Why weird:** Two near-synonyms with different cardinalities. `instructions` is a single string, `guidelines` is a string array. The semantic difference is not obvious from the names; both feel like "things the model should follow". This is an API-design issue more than a naming issue, but the names amplify the confusion. - **Category:** 6 (misleading), 12 (duplicate concept). - **Suggested name:** `systemPrompt` (or `instruction`) for the single-string case; `rules` or `constraints` for the array. The bigger fix is to consolidate at the API level. - **Rationale:** Reading `instructions` + `guidelines` side-by-side, a consumer cannot guess which goes where without reading the prose docs. -### 11. `Table.tablePath` — `src/v1/model.ts:85` +### 10. `Table.tablePath` — `src/v1/model.ts:85` - **Why weird:** Type-suffix tautology (`Table.tablePath`). Doc says "Full UC table path in catalog.schema.table_name format" — but the field name does not communicate that it's a *fully qualified* three-part name. Compare with sibling SDK packages where the same concept is called `fullName` or `qualifiedName`. - **Category:** 20 (type-suffix tautology), 1 (vague — "path" is generic; a filesystem path? a JSON pointer?). - **Suggested name:** `fullName` (matches `catalog.TableInfo.full_name`) or `qualifiedName`. - **Rationale:** Unity Catalog already has a canonical term for three-part names (`full_name`); reusing it makes cross-API code less surprising. -### 12. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` +### 11. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` - **Why weird:** `Col` is a cryptic abbreviation for `Column`. The same package spells out `endpointName` and `agentArtifactPath` and `optimizationState`, so `Col` is inconsistent. Doc strings even use the full word: "Name of the request column". - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling fields). - **Suggested name:** `requestColumn` / `responseColumn`. - **Rationale:** Three saved characters is not worth the cognitive split between the doc ("column") and the identifier ("col"). -### 13. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` +### 12. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` - **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. - **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). - **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. - **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. -### 14. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` -- **Why weird:** Field `optimizationState` of type `State`. If `State` is renamed to `OptimizationRunState` per #3, the field can be renamed `optimization: OptimizationRunState` or `runState: OptimizationRunState`. +### 13. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` +- **Why weird:** Field `optimizationState` of type `State`. If `State` is renamed to `OptimizationRunState` per #2, the field can be renamed `optimization: OptimizationRunState` or `runState: OptimizationRunState`. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `optimization` (if type renamed) or just `state` with `State` more specific. Best is the pair `optimization: OptimizationRunState`. - **Rationale:** Reduces the noise once the enum name is specific. -### 15. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` +### 14. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `creationTime` reads as a `Date` and many callers will accidentally `new Date(customLlm.creationTime)`, which throws because `Temporal.Instant` does not coerce. Worth a comment in JSDoc; not a rename. - **Category:** Observation. - **Suggested name:** Keep `creationTime`; expand JSDoc to mention `Temporal.Instant`. - **Rationale:** Friction is from the type more than the name, but the name does not warn the reader of the unusual type. -### 16. Method names mix `Llm` and verb tense — `src/v1/client.ts:69,92,118,137,162,191` -- **Why weird:** Methods are `cancelCustomLlmOptimizationRun`, `createCustomLlm`, `deleteCustomLlm`, `getCustomLlm`, `startCustomLlmOptimizationRun`, `updateCustomLlm`. They are verb-noun and consistent — but the noun is *always* `CustomLlm` which doubles the package name. After the fix in #2 these collapse to `cancelOptimizationRun`, `createLlm`, `deleteLlm`, `getLlm`, `startOptimizationRun`, `updateLlm` — much shorter. -- **Category:** 7 (overly verbose). -- **Suggested name:** Drop the redundant `CustomLlm` infix on the client methods; the package namespace already supplies it. -- **Rationale:** Compare to `accountSettings.Client.deleteLlmProxyPartnerPoweredWorkspace` (accountsettings package) — that name is 41 chars long. SDK ergonomics suffer. Worth a project-wide convention question. - -### 17. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +### 15. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 18. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair +### 16. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than the `Http` infix. -### 19. `HttpCallOptions` — `src/v1/utils.ts:15` +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). - **Rationale:** Distinguish internal context bags from user-tunable option structs. -### 20. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` +### 18. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` - **Why weird:** The `State` enum's first member `STATE_UNSPECIFIED` is a proto-architectural leak. Proto3 requires every enum to declare a zero-value sentinel (typically `FOO_UNSPECIFIED`); that requirement does not exist in TypeScript. Exposing it on the public TS surface forces every consumer to handle a member that semantically means "the server forgot to set this field" — a proto wire-format concern, not a domain concern. The screaming-snake-case casing (`STATE_UNSPECIFIED`) also leaks proto's enum-value convention into a TS type system that conventionally uses PascalCase for enum members (https://google.github.io/styleguide/tsguide.html#enums). - **Category:** Proto-architectural leak (enum sentinel + screaming-snake casing). - **Suggested name:** Drop the `STATE_UNSPECIFIED` member entirely; if a "not yet set" value is needed, use `undefined` (the field is already `State | undefined`). If kept, rename to PascalCase `Unspecified` and document that it is a wire-format sentinel. - **Rationale:** Optional TS fields express "unset" via `undefined`; a redundant enum sentinel doubles the representation of "no value" and forces consumers to write `state !== undefined && state !== State.STATE_UNSPECIFIED`. The all-caps casing further signals that the value is a proto artifact rather than a designed TS API member. -### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -145,43 +133,43 @@ ## Low severity -### 22. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +### 20. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` - **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. - **Category:** Observation / 9 (reversed — correctly singular). - **Suggested name:** No change. - **Rationale:** Note for consistency reviews. -### 23. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 21. `customLlmFieldMask` function name — `src/v1/model.ts:259` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). - **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. -### 24. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 22. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it is an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 25. `readAll` helper — `src/v1/utils.ts:40` +### 23. `readAll` helper — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 26. `Call` import alias — `src/v1/client.ts:4` +### 24. `Call` import alias — `src/v1/client.ts:4` - **Why weird:** `import type {Call}` — `Call` is a one-word generic noun. Used for the inner async function. Could be `RetryableCall`, `HttpCallback`, etc. Not local to this package (it is from `@databricks/sdk-core/api`), but worth flagging. - **Category:** 1 (vague type name). - **Suggested name:** Imported type; rename upstream if appropriate. - **Rationale:** Generic noun in core API surface. -### 27. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` +### 25. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` - **Why weird:** Three-letter local names. `info` for the client-info builder, `host` for the URL host, `body` for the request body. Conventional and short, but `info` is especially vague. - **Category:** 1 (vague). - **Suggested name:** Keep `host` and `body` (universal); rename `info` to `clientInfo`. - **Rationale:** Localized; cosmetic. -### 28. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` +### 26. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` - **Why weird:** `resp` is the response. Four methods declare `let resp: CustomLlm | undefined;` then assign in a closure and `throw` if undefined. The pattern is repetitive *and* uses the same short name. Consider extracting a helper that returns `T | never`. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. @@ -189,19 +177,19 @@ ## Observations -### 29. Action verbs in `Client` are consistent +### 27. Action verbs in `Client` are consistent The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. - **Category:** 17 (reversed — explicit *consistency* note). -### 30. No `list` operation +### 28. No `list` operation The package exposes singleton CRUD plus optimization start/cancel, but no `listCustomLlms`. Unusual for a Databricks resource SDK. Not a naming issue, but worth flagging because the typical resource SDK has `list` and users will look for it. - **Category:** Observation. -### 31. Mixed acronym casing in core types +### 29. Mixed acronym casing in core types The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `ApiError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `Api` (title), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. - **Category:** 3 (acronym casing). -### 32. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` +### 30. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` Comment "// arrays of objects are not yet supported" inside a generated utility. Not a name issue, but the public-export status of this function makes the TODO load-bearing. - **Category:** Observation. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index 8e7a6a67..ded3e4bc 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,12 +3,12 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 55 +**Total weird names flagged:** 54 ## Summary | Severity | Count | | --- | --- | -| High | 10 | +| High | 9 | | Medium | 33 | | Low | 9 | | Observation | 3 | @@ -27,49 +27,43 @@ - **Suggested name:** Either (a) merge into one `lakebase` package with versioning, (b) declare one package the public surface and mark the other internal, or (c) cross-reference each shared type and make the docstrings explicitly say "see postgres/v1 for the V2 API". - **Rationale:** Comment at `client.ts:634-638` says "Lakebase V2 plans" — i.e. `database` is V1 and `postgres` is V2 OLTP. The naming does not reflect that lineage; users picking a dependency have no breadcrumb. -### 3. `DatabaseInstance` — `src/v1/model.ts:195` -- **Why weird:** Type's own JSDoc says "A DatabaseInstance represents a logical Postgres instance". `DatabaseInstance` is the central noun of the package, but it is named after a generic abstraction (`Database` × `Instance`) rather than the domain (`PostgresInstance` / `LakebaseInstance`). The name does not convey what makes this distinct from any other Databricks "instance" (warehouse, cluster, online table, etc.). -- **Category:** 1 (generic), 15 (generic field name losing meaning). -- **Suggested name:** `LakebaseInstance` or `PostgresInstance`. -- **Rationale:** Reader sees `DatabaseInstance` and has no idea whether it's a SQL warehouse instance, a vector DB instance, or something else. Postgres SDK calls the same concept `ComputeInstance` (`postgres/v1/model.ts`), which is also generic — flagged separately under finding #2. - -### 4. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:373-375` +### 3. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:373-375` - **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:365-370) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; keep `createdb`/`createrole`/`bypassrls` on the wire (marshal/unmarshal handles the mapping). - **Rationale:** Every other field in the package is `camelCase`. Three boolean fields breaking the convention to honour Postgres SQL keywords is a leak. Postgres SDK at `postgres/v1/model.ts` solves this differently — worth aligning. -### 5. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:70` +### 4. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:70` - **Why weird:** Should be `SYNCED_TABLE_OFFLINE`. Spelled as `SYNCED_TABLED_OFFLINE` (`TABLED` past tense). - **Category:** 6 (misleading: typo). - **Suggested name:** Fix the wire-string to `SYNCED_TABLE_OFFLINE`. - **Rationale:** This is a protocol-level typo that the SDK is propagating. If fixed upstream this becomes a breaking change unless aliased — flag now. -### 6. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) +### 5. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) - **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+1 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. - **Category:** 7 (overly verbose), 12 (duplicate concept), 15 (generic prefix). - **Suggested name:** Hoist effective values onto a sub-struct or use a discriminated `{input, effective}` shape; or drop the `effective` fields and explain in docs that the same field is read-mostly on responses. - **Rationale:** This is a Lakebase API protocol pattern, not a naming bug per se, but the resulting TS surface is twice as wide as it needs to be. Worth pushing back upstream. -### 7. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:395` +### 6. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:395` - **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 447 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:471): "Name of the **cluster** to get". - **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). - **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. - **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. -### 8. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:924`, `index.ts:3` +### 7. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:924`, `index.ts:3` - **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. - **Rationale:** The current name reads ambiguously; class names should be noun phrases describing *what they are*. The export at index.ts:3 means consumers see it directly. -### 9. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:354,360,372` +### 8. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:354,360,372` - **Why weird:** `attributes` is a generic field name; `effectiveAttributes` is a second copy; the type is a nested message that holds 3 Postgres role boolean flags. "Attributes" carries no information about what the attributes describe (Postgres `CREATEDB` / `CREATEROLE` / `BYPASSRLS` permission flags). - **Category:** 1 (vague — `attributes` is generic), 15 (generic field name). - **Suggested name:** `pgRoleFlags` / `PgRoleFlags`, or `permissions` / `RolePermissions`. - **Rationale:** Reader hits `role.attributes.createdb` and has to consult the type to find out it's a Postgres-flag bag. Postgres docs use the phrase "role attributes" so the alignment is intentional — but the SDK is for non-Postgres-experts too. -### 10. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:498,542` +### 9. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:498,542` - **Why weird:** The list-response field on catalogs is `databaseCatalogs: DatabaseCatalog[]` (matches type name), but on synced tables it's `syncedTables: SyncedDatabaseTable[]` (drops `Database`). On instance-roles it's `databaseInstanceRoles: DatabaseInstanceRole[]` (matches). On instances it's `databaseInstances: DatabaseInstance[]` (matches). The synced-tables one is the odd one out. - **Category:** 17 (inconsistent), 9 (singular/plural mismatch with the type). - **Suggested name:** `syncedDatabaseTables: SyncedDatabaseTable[]` (wire stays `synced_tables` if API requires it). @@ -77,199 +71,199 @@ ## Medium severity -### 11. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:197,199` +### 10. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:197,199` - **Why weird:** Two fields look like identifiers. `uid` is "immutable UUID identifier"; `name` is "unique identifier". Caller reading the struct can't tell at a glance which one to pass to `getDatabaseInstance` (answer: `name`, per client.ts:484). Bare `uid` is also non-descriptive — Lakebase uses both PG-side OIDs and Databricks-side UUIDs. - **Category:** 19 (underspecified id when multiple ids exist), 1 (vague `uid`). - **Suggested name:** `instanceUid` / `instanceName`, or `id` / `name` (collapse `uid` to `id`). - **Rationale:** Same field-disambiguation pattern as `PolicyInfo.id` in the abacpolicies audit. `uid` reads as a hash, not a Databricks UUID — and the JSDoc just says "UUID identifier". -### 12. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:201` +### 11. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:201` - **Why weird:** Field doc says "The email of the creator of the instance". Field name says `creator`. So is the value an email, a username, or an account id? Postgres SDK uses `createdBy` for the same concept (postgres/v1/model.ts). - **Category:** 1 (vague — `creator` could be a name, an id, or an email), 6 (misleading — doc says email, name says creator). - **Suggested name:** `creatorEmail` (or `createdBy` if the value can be a service-principal id too). - **Rationale:** The doc explicitly narrows the type; the field name should match. -### 13. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` +### 12. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` - **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. - **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). - **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". - **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. -### 14. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:209` +### 13. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:209` - **Why weird:** `pg` is two letters lowercase; the next word starts capitalised. Acronym `PG` is widely written uppercase. - **Category:** 3 (acronym casing — `pg` should arguably be `Pg` per camelCase, `PG` per acronym preservation). - **Suggested name:** `postgresVersion` (spell out), or `pgVersion` (current). - **Rationale:** Current `pgVersion` is OK but `postgresVersion` would be clearer. -### 15. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:203,250` +### 14. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:203,250` - **Why weird:** `Dns` is a single word; `DNS` is the acronym. Field doc says "The DNS endpoint to connect to the instance"; the value is a hostname, not a DNS server. Misleading abbreviation. - **Category:** 3 (acronym casing), 6 (misleading — `dns` suggests a DNS server, not an endpoint). - **Suggested name:** `readWriteEndpoint` / `readOnlyEndpoint`, or `readWriteHost` / `readOnlyHost`. - **Rationale:** A "DNS endpoint" is a non-standard phrase; the field is just a hostname. -### 16. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` +### 15. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` - **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? - **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). - **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. - **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. -### 17. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:230` +### 16. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:230` - **Why weird:** Field name says "node count"; doc says "1 primary and 0 or more secondaries". `nodeCount = 3` means 1 primary + 2 secondaries — but also could be read as "3 nodes, role unspecified". Postgres standby/replica terminology would be clearer. - **Category:** 1 (vague), 6 (misleading without docs). - **Suggested name:** `replicaCount`, or pair `primaryCount` + `secondaryCount`, or `totalNodeCount` (and document). - **Rationale:** Confusing arithmetic — `1` means primary-only, `2` means 1 primary + 1 secondary, etc. -### 18. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:239` +### 17. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:239` - **Why weird:** `enableXyz: boolean` is a request-shaped name on a response-shaped type. `enableReadableSecondaries: true` reads as imperative ("please enable"), but it's also returned from server. The companion `effectiveEnableReadableSecondaries` reads as "the effective please-enable-readable-secondaries". The doc on `effectiveEnableReadableSecondaries` even rewords it: "Whether secondaries serving read-only traffic are enabled" — i.e. the read shape should just be `readableSecondariesEnabled` or `hasReadableSecondaries`. - **Category:** 6 (misleading verb form for a response), 17 (input/output asymmetry). - **Suggested name:** Input: `enableReadableSecondaries: boolean`. Output: `readableSecondariesEnabled: boolean` (or just merge: response carries the same `enableReadableSecondaries` and don't bother with the `effective_` twin). - **Rationale:** Generator artefact, but worth flagging. -### 19. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:270,275` +### 18. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:270,275` - **Why weird:** `Ref` is a cryptic abbreviation (cf. `typescript.mdc` "spell out short identifiers"). Same as `DatabaseInstanceRef` itself. Could be `Reference` or just `DatabaseInstancePointer`. The semantic ("a reference to an instance") doesn't need the abbreviation. - **Category:** 5 (cryptic abbreviation), 8 (redundant `Ref` suffix — these are already references). - **Suggested name:** `parentInstance: DatabaseInstanceReference` / `childInstances: DatabaseInstanceReference[]`. - **Rationale:** Mild — `Ref` is widely understood — but spelling out matches the project rule. -### 20. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:323` +### 19. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:323` - **Why weird:** `lsn` is a Postgres-internal acronym (Log Sequence Number) shown without expansion. JSDoc says "User-specified WAL LSN" — still abbreviated. - **Category:** 5 (cryptic abbreviation), 14 (Postgres-internal term in public TS API). - **Suggested name:** `walLsn` (mild improvement), or `walLogSequenceNumber` (verbose but unambiguous). - **Rationale:** Lakebase exposes this to schedule branch creation; consumers may not know `lsn` without consulting Postgres docs. -### 21. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:342` +### 20. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:342` - **Why weird:** `branchTime` is a noun-phrase that reads as "the time of a branch" but is documented as "the point in time on the parent instance from which the instance was created" — i.e. the PITR cutover instant. `branchTime` and `lsn` are alternatives for the same operation (PITR cutover specifier). - **Category:** 1 (vague), 6 (misleading — `branchTime` suggests an event time, actually a cutover specifier). - **Suggested name:** `branchPointTime` / `branchAt` / `pitrTimestamp`. - **Rationale:** Reads naturally as "when was this branch made" but actually means "what point in the source's history to branch from". -### 22. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:185` +### 21. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:185` - **Why weird:** Bare `uid?: string` with no comment, alongside `name`, `databaseInstanceName`, `databaseName`. Four identifier-like fields and one (`uid`) is undocumented and unprefixed. - **Category:** 19 (underspecified id), 1 (vague). - **Suggested name:** `catalogUid` (and add a doc comment). - **Rationale:** Reader cannot guess what scope the uid is for. -### 23. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:186` +### 22. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:186` - **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF NOT EXISTS`). Reads as a literal SQL DDL fragment in the type. Could be `ensureDatabase` / `autoCreateDatabase`. - **Category:** 14 (SQL-style name), 7 (verbose). - **Suggested name:** `ensureDatabaseExists` / `autoCreateDatabase`. - **Rationale:** Internal consistency with TS naming conventions. -### 24. `DatabaseCatalog.databaseInstanceName` / `databaseName` — `src/v1/model.ts:182-184` +### 23. `DatabaseCatalog.databaseInstanceName` / `databaseName` — `src/v1/model.ts:182-184` - **Why weird:** The `database` prefix on every field is redundant once you're already inside `DatabaseCatalog`. `databaseInstanceName` reads as "name of the database instance"; `databaseName` reads as "name of the database". Postgres SDK has `Catalog` (no `database` prefix) — cleaner. - **Category:** 7 (verbose prefix), 12 (duplicate concept across packages). - **Suggested name:** `instanceName`, `name` on the catalog directly; or hoist to a sub-struct `database: {instanceName, name}`. - **Rationale:** The struct is already a `DatabaseCatalog`; re-prefixing every field is noise. -### 25. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:380` +### 24. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:380` - **Why weird:** Bare `name` carries a complex format (`catalog.schema.table`). Postgres SDK calls the same concept `fullName` / `name` more explicitly. There is no validation in the type — the convention is doc-only. - **Category:** 1 (vague), 6 (misleading — name looks like a single identifier, actually 3-part). - **Suggested name:** `fullName` (matches Postgres SDK convention). - **Rationale:** Same field name `name` appears on `DatabaseCatalog`, `DatabaseInstance`, `DatabaseInstanceRef`, `DatabaseInstanceRole`, `DatabaseTable`, `SyncedDatabaseTable` — each carries different semantics (DNS-safe vs UC-3-part vs role-name). -### 26. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` +### 25. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` - **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". - **Category:** 12 (duplicate concept), 1 (generic `Database`). - **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. - **Rationale:** Reader has to read both JSDocs to understand the partitioning. -### 27. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` +### 26. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` - **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`) split words at capital boundaries. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Trivia, but `time series` is two words in English. -### 28. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:727,380` +### 27. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:727,380` - **Why weird:** Same domain concept (UC 3-part name) named two different ways in the same package: `sourceTableFullName` here, bare `name` on `DatabaseTable`/`SyncedDatabaseTable`/`DatabaseCatalog`. - **Category:** 17 (inconsistent naming for the same concept). - **Suggested name:** Standardise on `fullName` (or `tableFullName`) across the package. -- **Rationale:** Pair with #25. +- **Rationale:** Pair with #24. -### 29. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:744` -- **Why weird:** Similar SQL-DDL leak as #23. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. +### 28. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:744` +- **Why weird:** Similar SQL-DDL leak as #22. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. - **Category:** 14 (SQL-style name), 6 (typo in cross-reference). - **Suggested name:** `ensureDatabaseAndSchema`. - **Rationale:** Internal consistency. -### 30. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:759` +### 29. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:759` - **Why weird:** Field is `detailedState`; sibling field is `detailedStatus`. Both have `detailed` prefix; redundant against the wrapping type `SyncedTableStatus`. Easy to confuse `detailedState` (enum) with `detailedStatus` (oneof). - **Category:** 17 (two `detailed*` neighbours), 7 (verbose). - **Suggested name:** `state: SyncedTableState`, `status: SyncedTableStatusDetail` (or hoist the oneof). - **Rationale:** Reader hits `tableStatus.detailedState` and `tableStatus.detailedStatus` and has to read both to decide which is which. -### 31. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:763` +### 30. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:763` - **Why weird:** `detailedStatus` on a `SyncedTableStatus` type is doubly redundant. Holds one of four phase-shaped sub-statuses (`provisioningStatus`, `continuousUpdateStatus`, `triggeredUpdateStatus`, `failedStatus`). Each variant is named `*Status` again — `tableStatus.detailedStatus.continuousUpdateStatus.lastProcessedCommitVersion` is "status.status.status.version". - **Category:** 7 (overly verbose chains). - **Suggested name:** Rename `detailedStatus` to `phase`, and strip the redundant `*Status` suffix off each sub-variant (`provisioning`, `continuousUpdate`, `triggeredUpdate`, `failed`). - **Rationale:** Reduces three `status` words to one without touching the wrapper itself. -### 32. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` +### 31. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 33. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:678` +### 32. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:678` - **Why weird:** Run-on field name — "latest version currently processing" is 4 words. Doc clarifies "may not have completely processed this version yet". Could be `inProgressDeltaVersion` or `currentDeltaVersion`. - **Category:** 7 (overly verbose), 1 (verbose adverb). - **Suggested name:** `processingDeltaVersion`. - **Rationale:** Verbose field names hurt readability. -### 34. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:680-686` +### 33. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:680-686` - **Why weird:** Mixed metric naming: `syncedRowCount` and `totalRowCount` use suffix `Count`; `syncProgressCompletion` uses suffix `Completion` (a number 0-1); `estimatedCompletionTimeSeconds` uses suffix `TimeSeconds` (unit-embedded). Three different conventions for "a number". - **Category:** 17 (inconsistent suffixes), 15 (generic field names). - **Suggested name:** `syncedRows`, `totalRows`, `progressFraction`, `etaSeconds`. - **Rationale:** The number-suffix conventions don't align with each other; pick one. -### 35. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:683-684` +### 34. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:683-684` - **Why weird:** Type is `number`; doc constrains to `[0, 1]`. Type system doesn't help. Field name `syncProgressCompletion` is also redundant — completion is what progress measures. - **Category:** 16 (type contradicts doc constraint), 7 (verbose). - **Suggested name:** `progressFraction` (or `progressRatio`), `number` in [0,1]. -- **Rationale:** Same as #34 plus a separate concern about the value range. +- **Rationale:** Same as #33 plus a separate concern about the value range. -### 36. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` +### 35. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` - **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. - **Category:** 20 (type-suffix tautology in field names), 7 (verbose). - **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. - **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. -### 37. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` +### 36. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 38. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:453` +### 37. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:453` - **Why weird:** Bare `requestId` with no doc. Other request types do not have `requestId`. Looks like an idempotency key but the type doesn't say. - **Category:** 1 (vague), 19 (underspecified id). - **Suggested name:** `idempotencyKey` (and add docs). - **Rationale:** Without docs, callers can't tell whether to set it. -### 39. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` +### 38. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 40. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:411-415` +### 39. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:411-415` - **Why weird:** "Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. Setting a value of false will throw a bad request." Field is exposed in the public TS type but has no `@deprecated` JSDoc tag. - **Category:** 6 (misleading: deprecated field undocumented as deprecated). - **Suggested name:** Add `@deprecated` tag; consider removing in next major. - **Rationale:** TS tooling honours `@deprecated`; the current setup just has prose. -### 41. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` -- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #42 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. +### 40. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` +- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #41 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. - **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). - **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`; field `inlinePipeline` (paired with `existingPipelineId`). Drop the `New` adjective and the `Spec` suffix. - **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. -### 42. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` -- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #43); `DeltaTableSyncInfo` is a sync checkpoint (see #36); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #41). Each of the four would read more clearly with a domain-specific suffix. +### 41. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` +- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #42); `DeltaTableSyncInfo` is a sync checkpoint (see #35); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #40). Each of the four would read more clearly with a domain-specific suffix. - **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). -- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #41); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #36); `ProvisioningInfo` → drop (per #43). Goal: no two types in the package share a generic suffix. +- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #40); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #35); `ProvisioningInfo` → drop (per #42). Goal: no two types in the package share a generic suffix. - **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. -### 43. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` +### 42. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` - **Why weird:** Type declaration is literally `export interface ProvisioningInfo {}` with a comment "Copied over from managed-catalog/api/messages/common.proto to decouple SDK packages. xref go/unified-api-packages-dd". An empty interface — the type itself carries zero domain meaning. Only its nested `ProvisioningInfo_State` enum is used (referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`); the empty parent is a vestigial proto namespace. The exported type name and its nested enum bleed Managed Catalog internals into the Lakebase SDK. - **Category:** proto-architectural leak (proto message preserved as empty TS interface for namespacing), 6 (misleading — exists but has no fields), 12 (cross-package proto leak). - **Suggested name:** Drop the empty `ProvisioningInfo` interface; rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). The empty interface is a generator artefact that should not surface. @@ -277,55 +271,55 @@ ## Low severity -### 44. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:505` +### 43. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:505` - **Why weird:** Doc says "Pagination token to go to the next page of Database Instances" — but this is roles, not instances. Doc-copy bug. - **Category:** 6 (misleading doc). - **Suggested name:** Fix the doc to say "roles". - **Rationale:** Naming-adjacent bug worth flagging. -### 45. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:491` +### 44. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:491` - **Why weird:** Same bug: catalogs request says "synced database tables" in doc. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "catalogs". -- **Rationale:** Same as #44. +- **Rationale:** Same as #43. -### 46. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:514` +### 45. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:514` - **Why weird:** Doc says "next page of instances" for the roles response. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "roles". -- **Rationale:** Same as #44. +- **Rationale:** Same as #43. -### 47. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` +### 46. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` - **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:181-184). - **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). - **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. - **Rationale:** Caller has to know the wire-encoding accident to decide which to set. -### 48. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:421` +### 47. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:421` - **Why weird:** Postgres-isms (`REASSIGN OWNED BY ... TO ...`) collapsed into a single field. Field name reads as a verb phrase ("reassign owned [things] to"). - **Category:** 14 (SQL-style name). - **Suggested name:** `reassignOwnedObjectsTo` or `newOwner`. - **Rationale:** Mild — Postgres admins will get it. -### 49. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` +### 48. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` - **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. - **Category:** 14 (Google-AIP naming convention leak). - **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. - **Rationale:** Internal-jargon leak; flag for awareness. -### 50. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:433` +### 49. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:433` - **Why weird:** Boolean named after a side effect (`purge_data`). Doc says "the actual PostgreSQL table will be dropped from the database". Combination of `delete` + `purge` is also confusing — what does the no-purge case do? (Drop UC registration only.) - **Category:** 1 (vague), 6 (misleading). - **Suggested name:** `dropUnderlyingTable` / `cascade`. - **Rationale:** Minor — affects discoverability. -### 51. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` +### 50. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` - **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency. -### 52. `StillRunningError` private error class — `src/v1/client.ts:83` +### 51. `StillRunningError` private error class — `src/v1/client.ts:83` - **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. - **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). - **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). @@ -333,16 +327,16 @@ ## Observations -### 53. `client.ts` has a 5-line block-comment at line 633-638 explaining that the role APIs will never reach Public Preview +### 52. `client.ts` has a 5-line block-comment at line 633-638 explaining that the role APIs will never reach Public Preview The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. - **Category:** 6 (misleading: client exposes APIs that won't stabilise). - **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. -### 54. `findDatabaseInstanceByUid` is the only `findBy*` method +### 53. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 55. Action-verb conventions in `Client` are consistent +### 54. Action-verb conventions in `Client` are consistent `create*` / `delete*` / `get*` / `list*` / `update*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. ## Domain glossary @@ -368,7 +362,7 @@ Every other lookup is `getX(req)`. This method exists because the API has a dist ## Fixed - #8 `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` (originally cited at `src/v1/model.ts:976`, `client.ts:998`): Fixed in regeneration on 2026-05-20 — the request type and client method were removed from the generated surface. -- #25 `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` (originally cited at `src/v1/model.ts:219-223`): Fixed in regeneration on 2026-05-20 — `databaseProjectId` and `databaseBranchId` were removed; the remaining `databaseName` / `databaseInstanceName` prefix concern is captured in active finding #24. +- #25 `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` (originally cited at `src/v1/model.ts:219-223`): Fixed in regeneration on 2026-05-20 — `databaseProjectId` and `databaseBranchId` were removed; the remaining `databaseName` / `databaseInstanceName` prefix concern is captured in active finding #23. - #27 `DatabaseTable.tableServingUrl` (originally cited at `src/v1/model.ts:437`): Fixed in regeneration on 2026-05-20 — the field was removed from `DatabaseTable`. - #32 `SyncedTableSpec.acceleratedSync` (originally cited at `src/v1/model.ts:830`): Fixed in regeneration on 2026-05-20 — the field was removed from `SyncedTableSpec`. - #51 `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` (originally cited at `src/v1/model.ts:490`): Fixed in regeneration on 2026-05-20 — the entire `FailoverDatabaseInstanceRequest` type and its client method were removed from the generated surface. diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md index 5fbdb3cf..6fa54b0d 100644 --- a/.agent/naming-audit/dataclassification.md +++ b/.agent/naming-audit/dataclassification.md @@ -3,13 +3,13 @@ **Path:** `packages/dataclassification/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 18 +**Total weird names flagged:** 17 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 4 | +| Medium | 3 | | Low | 6 | | Observation | 4 | @@ -47,19 +47,13 @@ - **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. -### 6. `CreateCatalogConfigRequest` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` / `UpdateCatalogConfigRequest` — `src/v1/model.ts:65,76,82,93` -- **Why weird:** All four request DTOs repeat the noun `CatalogConfig` even though the only thing this package operates on is `CatalogConfig`. The package name itself is `dataclassification`. In context, `CreateRequest`/`UpdateRequest` would be plenty. -- **Category:** 7 (overly verbose), 8 (redundant suffix and infix). -- **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`, or keep `Catalog` and drop `Config`: `CreateCatalogRequest`/... -- **Rationale:** The whole package operates on exactly one entity. Repeating its name in four request types is pure noise. (However, the inconsistency with the entire rest of the SDK matters — proposing as a per-package fix is risky. Listed medium not high.) - -### 7. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 6. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. -### 8. `flattenQueryParams` — `src/v1/utils.ts:123` +### 7. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. @@ -67,37 +61,37 @@ ## Low severity -### 9. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` +### 8. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 10. `userAgent` field — `src/v1/client.ts:45` +### 9. `userAgent` field — `src/v1/client.ts:45` - **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. - **Category:** N/A (verification, no issue). - **Suggested name:** unchanged. - **Rationale:** Listed only to confirm canonical naming is preserved. -### 11. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` +### 10. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 12. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` +### 11. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` - **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. - **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. -### 13. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` +### 12. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 14. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` +### 13. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` - **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. @@ -105,17 +99,17 @@ ## Observations -### 15. Wire/TS divergence is heavy +### 14. Wire/TS divergence is heavy The model file is 206 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. -### 16. Action-verb conventions in `Client` +### 15. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) -### 17. Acronym casing +### 16. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 18. `dataclassification` lowercase package name +### 17. `dataclassification` lowercase package name The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index 6aeea820..eb72740d 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -3,13 +3,13 @@ **Path:** `packages/entitytagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). -**Total weird names flagged:** 27 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 10 | +| High | 7 | +| Medium | 9 | | Low | 4 | | Observation | 4 | @@ -21,69 +21,51 @@ - **Suggested name:** Merge into a single package `tagassignments` keyed by `entityKind` ("uc" vs. "platform"), or rename to `uctagassignments` so the surface marker is "uc", not "entity". The non-UC sibling can drop its own `entityType` field discrimination and become `platformtagassignments`. As a smaller fix: `unitycatalogtags` here, `platformtags` there. - **Rationale:** Two `Client` classes called `Client`, with two `TagAssignment` / `EntityTagAssignment` types, both shipping `tagKey`/`tagValue`/`entityType`, will collide in user imports and force aliasing on every co-use. The split exists for backend reasons but leaks raw into the SDK. Worth flagging upstream as a generator-level concern. -### 2. `EntityTagAssignment` — `src/v1/model.ts:32` -- **Why weird:** The redundant "Entity" prefix on the primary type. Every assignment is an assignment of a tag to an *entity*; there is no non-entity tag assignment. Within this package, `Entity` adds nothing beyond what `TagAssignment` already implies, and the package directory already carries the namespace. Inside `tagassignments`, the same concept is plainly `TagAssignment`. -- **Category:** 8 (redundant prefix — `Entity` repeats the universal subject), 12 (duplicate concept — `TagAssignment` already exists in `tagassignments`). -- **Suggested name:** `TagAssignment`. Rely on package-import disambiguation: `import {TagAssignment as UcTagAssignment} from '@databricks/sdk-entitytagassignments'`. -- **Rationale:** A noun that re-states its only possible subject is filler. The Go SDK names it `EntityTagAssignment` to disambiguate from a different proto type in the same Go package; TS module imports already do that disambiguation. - -### 3. `EntityTagAssignment` field shape vs. sister `TagAssignment` shape — `src/v1/model.ts:32-47` vs. `tagassignments/src/v1/model.ts:46-55` +### 2. `EntityTagAssignment` field shape vs. sister `TagAssignment` shape — `src/v1/model.ts:32-47` vs. `tagassignments/src/v1/model.ts:46-55` - **Why weird:** The two sister types model the same conceptual object using different identifier fields: this package's `EntityTagAssignment` has `entityName: string`, while `tagassignments.TagAssignment` has `entityId: string`. Same column conceptually (the thing being tagged), different field name. A user porting code between the two has to translate. The JSDoc here says "fully qualified name" while the sister says "identifier"; the wire-side names are `entity_name` vs. `entity_id`. - **Category:** 12 (duplicate concept with divergent naming), 17 (verb/noun inconsistency across siblings), 16 (field contradicts type domain — "name" suggests a label, "id" suggests an opaque handle, but both fields are fully-qualified resource identifiers). - **Suggested name:** Unify on `entityFullName` (matches Unity Catalog vocabulary like `catalogs.fullName`, `tables.fullName`) or `entity` for both packages. At minimum, both packages should agree. - **Rationale:** Splitting "name vs id" by package makes the cross-package developer experience worse. The Unity Catalog product surface consistently calls these `full_name`/`fullName` (see `catalogs`, `schemas`, `tables`); using `entityName` here breaks that convention silently. -### 4. `TagAssignmentSourceType` — `src/v1/model.ts:9` +### 3. `TagAssignmentSourceType` — `src/v1/model.ts:9` - **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. Combined with the surrounding type `EntityTagAssignment`, the relevant field is `sourceType: TagAssignmentSourceType` — five words to say "where did this come from". - **Category:** 20 (type-suffix tautology — `Type` on an enum), 7 (overly verbose). - **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). Field becomes `source: TagSource`. - **Rationale:** The shorter name is unambiguous in context (`EntityTagAssignment.source` reads better than `EntityTagAssignment.sourceType`). Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. -### 5. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,52,62` +### 4. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,52,62` - **Why weird:** Four places in this file have a field called `entityName` whose JSDoc says "The fully qualified name of the entity to which the tag is assigned". The shape `name?: string | undefined` cannot enforce qualification; users will pass bare names. Compare Unity Catalog convention `fullName` (used in `catalogs`, `schemas`, `tables`). - **Category:** 1 (vague — "name" is too generic), 6 (misleading — looks settable to a bare name, is actually structured), 15 (generic field name losing meaning), 19 (underspecified ID — what makes it "fully qualified"?). - **Suggested name:** `entityFullName` (or `entity`/`entityFqn`). Matches sister UC packages. - **Rationale:** "fully qualified" is wire-side; the SDK type should make the constraint visible in the identifier. A field literally called `entityName` reads as a display name to most TS users. -### 6. `entityType: string` everywhere — `src/v1/model.ts:28,40,56,68` +### 5. `entityType: string` everywhere — `src/v1/model.ts:28,40,56,68` - **Why weird:** Four occurrences of `entityType?: string | undefined` with no enum or string-literal union to constrain values. The JSDoc says "The type of the entity to which the tag is assigned" but never lists which values are valid (compare sister `tagassignments`: doc explicitly lists `apps, dashboards, geniespaces, notebooks`). For Unity Catalog entities, the actual valid set is something like `table`, `schema`, `catalog`, `column`, `volume`, `function`, `model` — none of which is documented or constrained in the type. - **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what type strings are valid?), 6 (misleading — looks free-form, is actually constrained). - **Suggested name:** `EntityKind` (string-literal union or enum) typed as the field. E.g. `entityKind?: 'table' | 'schema' | 'catalog' | 'column' | 'volume' | 'function' | 'model'`. The field name `Type` also collides with the JS reserved-ish word — `Kind` reads more cleanly. - **Rationale:** Stringly-typed enum fields are a generator anti-pattern. The valid set is closed; the type should say so. `Type` as a noun is also overused — `Kind` is the convention in TS standard library (`SyntaxKind`, `NodeKind`). -### 7. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` +### 6. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` - **Why weird:** `DeleteEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag to delete". `GetEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag". But `EntityTagAssignment.tagKey` (on the actual returned/created object) and `CreateEntityTagAssignmentRequest.tagAssignment.tagKey` are documented as just "The key of the tag" with no required marker — yet you cannot create or get a tag without a key. The `?: string | undefined` typing makes all of them optional in TS. Type and doc disagree. - **Category:** 6 (misleading — type says optional, semantics says required), 17 (inconsistent — some docs say "Required.", others don't, for what is the same logical field). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) and remove the "Required." doc preamble since the type enforces it. Apply uniformly across all four request types and the assignment type itself. - **Rationale:** "Required." in a docstring while the type is optional is a generator smell. Honest required-ness should travel through the type. -### 8. `Client` class — `src/v1/client.ts:41` +### 7. `Client` class — `src/v1/client.ts:41` - **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The other tag packages (`tagassignments`, `tagpolicies`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages). - **Suggested name:** `EntityTagAssignmentsClient` (or `UnityCatalogTagsClient`). - **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing. Generator-level concern. -### 9. Method names `createEntityTagAssignment` / `deleteEntityTagAssignment` / `getEntityTagAssignment` / `listEntityTagAssignments` / `updateEntityTagAssignment` — `src/v1/client.ts:76,114,133,163,226` -- **Why weird:** Every client method repeats the package name in its identifier. On `Client` already scoped by import to this package, `client.createEntityTagAssignment(...)` reads as "package.subject.create.subject" — the noun is doubled. Sister package `tagassignments` does the same with `createTagAssignment`. The shorter form `client.create(...)` / `client.list(...)` is what TS users expect when a client is single-purpose. -- **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `EntityTagAssignment` four/five times when the client only manages `EntityTagAssignment`). -- **Suggested name:** `create`, `delete`, `get`, `list`, `update`. Or shorter `createAssignment` / `deleteAssignment` / etc. -- **Rationale:** A client class that ships exactly five methods all named after the same subject is repeating the subject. `EntityTagAssignmentsClient.create()` is the more readable shape. - ## Medium severity -### 10. `CreateEntityTagAssignmentRequest` etc. — five request DTOs share a 25-char prefix — `src/v1/model.ts:17,22,50,60,79` -- **Why weird:** `CreateEntityTagAssignmentRequest`, `DeleteEntityTagAssignmentRequest`, `GetEntityTagAssignmentRequest`, `ListEntityTagAssignmentsRequest`, `UpdateEntityTagAssignmentRequest`. Each is 33 characters; the common prefix `EntityTagAssignment` is 19 chars of repetition. In the package whose only subject is the entity tag assignment, every request type re-states that subject. -- **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). -- **Suggested name:** `CreateRequest` / `DeleteRequest` / `GetRequest` / `ListRequest` / `UpdateRequest`. Or drop just the noun: `CreateRequest` etc. -- **Rationale:** Single-subject packages don't need to repeat the subject on every request DTO. Listed as medium because the inconsistency with the rest of the SDK matters. - -### 11. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` +### 8. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` - **Why weird:** The plural appears only on the list endpoint; the rest of the surface is singular. Singular/plural mix is consistent with the Go SDK and other packages, but worth flagging that the resource name on the wire is `/entity-tag-assignments` (plural) while the type name is singular `EntityTagAssignment`. The list response is `ListEntityTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. - **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. -### 12. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 9. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — `executeCall` runs the retry/rate-limit shell, `executeHttpCall` does the actual HTTP send. They appear together in every client method: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -98,43 +80,43 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Names should reveal the layering, not require code-diving. Generator-wide concern. -### 13. `Call` type and `call` variable — `src/v1/client.ts:86,119,139,178,242` and `src/v1/utils.ts:27` +### 10. `Call` type and `call` variable — `src/v1/client.ts:86,119,139,178,242` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, called inside `executeCall(call, options)`. The same word is the variable, the type, and the verb. Inside one method scope we have `req`, `call`, `httpReq` — three layered names where one of them collides with its type. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions are tolerable but obscure prose-style code. -### 14. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` +### 11. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. -### 15. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 143-148, 182-187, 252-257` +### 12. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 143-148, 182-187, 252-257` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: EntityTagAssignment`. The names differ only by `Body`. Both are short for "response". The reader has to track which is bytes, which is parsed. Compare `req` (parameter, request) — also abbreviated, but no `reqBody` sibling. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result`, or `responseBytes` + `response`. - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 16. `httpReq` local variable — `src/v1/client.ts:89,122,142,181,245` +### 13. `httpReq` local variable — `src/v1/client.ts:89,122,142,181,245` - **Why weird:** Inside a method that already has `req: CreateEntityTagAssignmentRequest`, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in one scope. -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` +### 14. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 18. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 15. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just shorthand. -### 19. `flattenQueryParams` — `src/v1/utils.ts:123` +### 16. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package's list endpoint uses individual `params.append(...)` calls instead). Dead-code-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. @@ -142,25 +124,25 @@ ## Low severity -### 20. `readAll(body)` — `src/v1/utils.ts:40` +### 17. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path or array. -### 21. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 18. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. Casing is appropriate for a module constant; the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain; the comment above it does the work the name should. -### 22. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` +### 19. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` - **Why weird:** The pair encodes a `(key, value)` tag — that part is fine. But the type is *already* called `EntityTagAssignment`, so the `tag` prefix on each field is redundant within scope: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. - **Category:** 8 (redundant prefix — `tag` within `EntityTagAssignment`). - **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. - **Rationale:** Field names should not re-state their containing type's noun. `assignment.key` / `assignment.value` reads cleaner. -### 23. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` +### 20. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` - **Why weird:** Verb tense pair: `updateTime` (noun-noun, gerund stripped) vs. `updatedBy` (past participle). Cross-SDK convention should pick one. Compare: `createTime` (noun-noun) often pairs with `createdBy` (past participle) in Databricks — the same asymmetry. It is consistent across the SDK, but worth noting under rule 13. - **Category:** 13 (verb-tense inconsistency within a paired field). - **Suggested name:** `updateTime`/`updateBy` or `updatedTime`/`updatedBy`. Either works; the asymmetry is the issue. @@ -168,18 +150,18 @@ ## Observations -### 24. Action verb consistency +### 21. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 25. Acronym casing +### 22. Acronym casing The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 26. `entitytagassignments` lowercase package name +### 23. `entitytagassignments` lowercase package name The package directory is `entitytagassignments` (single token, no separator), but every type uses `EntityTagAssignment` and the HTTP path uses `entity-tag-assignments`. Same problem as `dataclassification`. SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 27. Domain leakage from sister packages +### 24. Domain leakage from sister packages Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index 4fbceb65..5359d8e1 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -3,15 +3,15 @@ **Path:** `packages/externallineage/src/v1/` **Versions audited:** v1 **Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 24 +**Total weird names flagged:** 22 ## Summary | Severity | Count | | --- | --- | -| High | 7 | +| High | 6 | | Medium | 7 | | Low | 8 | -| Observation | 2 | +| Observation | 1 | ## High severity @@ -45,13 +45,7 @@ - **Suggested name:** Pick one: prefer no suffix where the noun is concrete (`Table`, `Path`, `ModelVersion`, `ExternalMetadata`), `Relationship` for edges, and drop `Info`/`Object` entirely. - **Rationale:** Three suffixes for related types make the vocabulary feel arbitrary. The Google TypeScript style guide encourages "names should reflect what something is, not its scaffolding". -### 6. `ExternalLineageRelationshipTable` / `ExternalLineageRelationshipPath` / `ExternalLineageRelationshipModelVersion` / `ExternalLineageRelationshipExternalMetadata` — `src/v1/model.ts:158, 154, 134, 130` -- **Why weird:** Four sibling types every one prefixed with the package's longest type-name `ExternalLineageRelationship`. The naming makes them feel weighty; their position in the union does not justify the weight. Names like `ExternalLineageRelationshipExternalMetadata` are over 35 characters and convey one bit of information (which arm of the union). -- **Category:** 7 (overly verbose), 8 (redundant prefix — `ExternalLineageRelationship` is implicit from context). -- **Suggested name:** Nest them: `ExternalLineageRelationship.Table`, `ExternalLineageRelationship.Path`, etc., via a TS namespace; or drop the prefix and name them `LineageTableObject`, `LineagePathObject`, `LineageModelVersionObject`, `LineageExternalMetadataObject`. -- **Rationale:** The redundant prefix is paid on every line that references these types. Dropping it (or nesting) shortens call sites without losing information. - -### 7. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` +### 6. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` - **Why weird:** Both fields are typed as `string | undefined` with no JSDoc. A reader of `{source?: string, target?: string}` has no way to know that these are *column names* (not full table.column references, not column IDs). The enclosing `ExternalLineageRelationship` has its own `source` and `target` of type `ExternalLineageRelationshipObject` — so the inner `source`/`target` of `ColumnRelationship` shadow the outer pair and add no description. - **Category:** 1 (vague `source`/`target`), 6 (misleading — looks like the outer source/target but is column-level), 15 (generic field names lose meaning), 19 (underspecified ID — is this a column name? a path? a column lineage handle?). - **Suggested name:** `sourceColumn?: string` / `targetColumn?: string` with JSDoc clarifying the format. @@ -59,43 +53,43 @@ ## Medium severity -### 8. `Client` class — `src/v1/client.ts:45` +### 7. `Client` class — `src/v1/client.ts:45` - **Why weird:** Class literally named `Client` at the top level of the package's API surface, re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. Same problem as every other audited package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. -### 9. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` +### 8. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. - **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. -### 10. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 9. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. -### 11. `HttpCallOptions` — `src/v1/utils.ts:15` +### 10. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 12. `flattenQueryParams` — `src/v1/utils.ts:123` +### 11. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. - **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). - **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. - **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). -### 13. `LineageTableInfo.name` — `src/v1/model.ts:201` +### 12. `LineageTableInfo.name` — `src/v1/model.ts:201` - **Why weird:** Field literally called `name` with JSDoc "Name of Table." (capitalised "Table" mid-sentence). The neighbour fields are `catalogName` and `schemaName` — so the type has `(name, catalogName, schemaName)`. Inconsistent: two fields use the `*Name` suffix while the table name itself drops it. Most readers will reach for `tableName`. - **Category:** 1 (vague — `name` of what?), 15 (generic field name losing meaning), 17 (inconsistent within the same type — `name` vs `catalogName` vs `schemaName`). - **Suggested name:** `tableName: string` (and JSDoc punctuation fix). - **Rationale:** Within `LineageTableInfo`, the canonical name for "the table's name" is `tableName`. Mixing `name`, `catalogName`, `schemaName` makes the table's own name look special when it isn't. -### 14. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` +### 13. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` - **Why weird:** Field is `name?: string` with no JSDoc. Type is named to encode "external metadata object on the external-lineage edge". Given the wider package uses `name` for tables, models, external metadata, paths-via-`url`, the field gives up domain meaning to be terse. - **Category:** 1 (vague `name`), 15 (generic field name), 19 (underspecified ID — for `ExternalMetadata`, the `name` is actually a fully-qualified resource path including the metastore). - **Suggested name:** `externalMetadataName: string` with a JSDoc clarifying the expected format (mirror the `ExternalMetadata.name` JSDoc on the externalmetadata package). @@ -103,49 +97,49 @@ ## Low severity -### 15. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` +### 14. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` - **Why weird:** Field is `url?: string` on a type called `*Path`. A `Path` whose only field is a `url` — two different nouns for the same thing. Compare with `LineageFileInfo.path` and `ExternalLineageRelationshipPath.url`: the file `path` and the lineage-path `url` carry the same kind of value. - **Category:** 1 (vague), 6 (misleading — `Path` and `url` are not the same), 12 (duplicate concept — `path` and `url` interchangeable across the package), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the type to `LineagePathObject` and call the field `path: string`, or rename the field to keep the type name: `path?: string`. - **Rationale:** Pick one of `path` or `url` for storage location strings and stick to it. -### 16. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` -- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` (#6) uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. +### 15. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. - **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). - **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) - **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. -### 17. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 16. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). - **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. - **Rationale:** Type name should reflect the dominant content; current name is misleading. -### 18. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +### 17. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` - **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. - **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). - **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. - **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. -### 19. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 80-92, 104, 134-178, 202-235` +### 18. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 80-92, 104, 134-178, 202-235` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. - **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 20. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` +### 19. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` - **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in the same scope. -### 21. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` +### 20. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 22. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` +### 21. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. @@ -153,11 +147,7 @@ ## Observations -### 23. Method names re-state the entity verbosely -All four methods (`createExternalLineageRelationship`, `updateExternalLineageRelationship`, `deleteExternalLineageRelationship`, `listExternalLineageRelationships`) end with `ExternalLineageRelationship`. The package is *named* `externallineage`, so the entity is obvious from the import path. `client.create(...)` / `client.list(...)` would be both terser and more readable, but generator-wide consistency probably wins. -- **Category:** 7 (overly verbose) — generator-wide pattern, listed as observation only. - -### 24. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +### 22. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #4. - **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). @@ -165,7 +155,7 @@ The response wraps an array under the field `externalLineageRelationships` (35 c - `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. - `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). - `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #16. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #15. - `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). - `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index 2179e28f..4894498f 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -3,14 +3,14 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 36 +**Total weird names flagged:** 35 ## Summary | Severity | Count | | --- | --- | | High | 9 | | Medium | 12 | -| Low | 11 | +| Low | 10 | | Observation | 4 | ## High severity @@ -145,67 +145,61 @@ ## Low severity -### 22. `CreateExternalMetadataRequest` / `DeleteExternalMetadataRequest` / `GetExternalMetadataRequest` / `ListExternalMetadataRequest` / `UpdateExternalMetadataRequest` — `src/v1/model.ts:35,39,80,84,99` -- **Why weird:** Five request DTOs repeat the noun `ExternalMetadata` even though the entire package operates on exactly one entity (the only thing this package does is CRUD `ExternalMetadata`). In context, `CreateRequest`/`UpdateRequest` would be plenty. -- **Category:** 7 (overly verbose), 8 (redundant infix). -- **Suggested name:** `CreateRequest`/`UpdateRequest`/`DeleteRequest`/`GetRequest`/`ListRequest`. -- **Rationale:** The whole package operates on one entity; repeating it in every request type is pure noise. The `Request` suffix itself is deliberate (SDK-wide convention); the redundant `ExternalMetadata` infix remains the issue. SDK-wide pattern means a local fix risks inconsistency. - -### 23. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` +### 22. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` - **Why weird:** Singular/plural mismatch. The field holds an array but is named `externalMetadata` (singular). Convention is plural for arrays (e.g., `connections: Connection[]` in sister packages). Compare: `nextPageToken` is singular because it's a single token. - **Category:** 9 (singular/plural mismatch), 20 (type-suffix tautology — `externalMetadata: ExternalMetadata[]`). - **Suggested name:** `items: ExternalMetadata[]` or `externalMetadataObjects: ExternalMetadata[]` or `assets`. Wire stays `external_metadata`. - **Rationale:** "Metadata" is a mass noun (uncountable), which is why the generator left it singular. A plural-aware name like `items` or `assets` reads naturally. -### 24. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 25. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` +### 24. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 26. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` +### 25. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` - **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. -### 27. `pageReq` — `src/v1/client.ts:194` +### 26. `pageReq` — `src/v1/client.ts:194` - **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). - **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). - **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. -### 28. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +### 27. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` - **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. - **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). - **Suggested name:** `requestBody: string | ReadableStream`. - **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. -### 29. `flattenQueryParams` — `src/v1/utils.ts:123` +### 28. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 30. `readAll(body)` — `src/v1/utils.ts:40` +### 29. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. -### 31. `HttpCallOptions` — `src/v1/utils.ts:15` +### 30. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 32. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` +### 31. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` - **Why weird:** The Zod schema constant carries the `V2` mid-position infix just like the type it parses (#7) and the client methods (#8). The directory is `v1/`, so `V2` here is wire-RPC-name leakage embedded inside a TS identifier that has no business advertising the upstream RPC version. Architectural leak — the generator copied the proto `ResponseV2` name straight through into the parser symbol. - **Category:** 14 (Go/proto-style name leak — wire `V2` infix on a TS identifier), 8 (redundant suffix — version is in the path), 20 (type-version suffix tautology between version-in-path and version-in-name). - **Suggested name:** `unmarshalListExternalMetadataResponseSchema` (drop `V2`). @@ -213,17 +207,17 @@ ## Observations -### 33. Identifier doubling for path + UUID +### 32. Identifier doubling for path + UUID The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5 and #6. -### 34. Action-verb conventions in `Client` +### 33. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. -### 35. Acronym casing +### 34. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 36. `externalmetadata` lowercase package name +### 35. `externalmetadata` lowercase package name The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index 1bac061b..dcbffebb 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -3,12 +3,12 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 62 +**Total weird names flagged:** 61 ## Summary | Severity | Count | | --- | --- | -| High | 15 | +| High | 14 | | Medium | 24 | | Low | 18 | | Observation | 5 | @@ -33,219 +33,213 @@ - **Suggested name:** Group with verb pairs: `runMessageAttachmentQuery` (re-execute) / `getMessageAttachmentQueryResult` (read) / `startMessageAttachmentDownload` + `getMessageAttachmentDownload` (download flow). - **Rationale:** The verbs `Execute` / `Get` / `Generate` overlap in everyday English; the type system gives no hint which one to call first. The current names are generator-faithful but unhelpful for users. -### 4. `Genie*` prefix on every type — type-suffix tautology — `src/v1/model.ts` (~40 types) -- **Why weird:** 40 of ~70 types are prefixed `Genie`: `GenieAttachment`, `GenieConversation`, `GenieMessage`, `GenieSpace`, `GenieFeedback`, `GenieEvalResult`, etc. The package is `@databricks/sdk-genie` and types are imported as `import {GenieMessage} from '@databricks/sdk-genie'`. The prefix duplicates the package identity. Other types in the same file have no prefix (`Result`, `ResultData`, `ResultManifest`, `StatementResponse`, `StatementStatus`, `Schema`, `Struct`, `ListValue`, `ChunkInfo`, `MessageError`, `MessageStatus`, `Thought`, `TextAttachment`, etc.) — so the prefix is not even applied consistently. -- **Category:** 20 (type-suffix tautology), 17 (prefix applied inconsistently within the same package). -- **Suggested name:** Drop the prefix wherever the unprefixed name is unambiguous: `Conversation`, `Message`, `Space`, `Attachment`, `Feedback`, `EvalResult`. Keep `Genie` only where collision with a copied-in shared type would arise (e.g. keep `GenieResultMetadata` if you also need to keep `ResultManifest`). -- **Rationale:** `import {Message} from '@databricks/sdk-genie'` is unambiguous (the package is the namespace). The current prefix turns every import line into noise. - -### 5. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1458` +### 4. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1458` - **Why weird:** The central noun. A `GenieSpace` is a "workspace scoped to a Genie deployment", but the word `Space` is one of the most overloaded terms in the Databricks SDK (it also appears in workspace, mlflow registered model, dashboards, etc.). Type doc on the class itself is one line ("Genie space ID"). Reader sees `GenieSpace` and has to consult external docs to learn whether it's a folder, a user-permission boundary, a model-deployment, or something else. - **Category:** 1 (vague/generic), 15 (generic field name losing meaning — `Space`). - **Suggested name:** `GenieRoom`, `GenieAgent`, `GenieDeployment`, or at minimum a JSDoc on the type explaining what a "space" *is* (warehouse + datasets + instructions). If "Space" is the Databricks product-marketing term, document it inline. - **Rationale:** This is the package's central concept. Letting it stand on a single word that means "container" is a documentation gap as much as a naming bug. -### 6. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-30,33-531,543-548,754-884,1589-1694` +### 5. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-30,33-531,543-548,754-884,1589-1694` - **Why weird:** 15+ types are byte-for-byte copies of types in the `statementexecution`, `sql` and `apierror` packages: `ColumnTypeName` (enum, 28 values), `ErrorCode` (enum, 80 values, with line-for-line JSDoc), `Format` (enum), `ChunkInfo`, `ColumnInfo`, `ColumnMask`, `DatabricksServiceExceptionProto`, `ExternalLink`, `ExternalLink_HttpHeadersEntry`, `PolicyFunctionArgument`, `Result`, `ResultData`, `ResultManifest`, `Schema`, `StatementResponse`, `StatementStatus`, `StatementStatus_State`. The file even copies the Google-Well-Known-Types (`Struct`, `Value`, `ListValue`, `MapStringValueEntry`). - **Category:** 12 (duplicate concept across packages). - **Suggested name:** Import from `@databricks/sdk-databricks/statementexecution` (or wherever the originals live). If the generator can't yet cross-link, mark each duplicate `@internal` or move them to a shared internal module. - **Rationale:** A consumer who imports both `@databricks/sdk-genie` and `@databricks/sdk-sql` ends up with two structurally-identical-but-nominally-distinct `StatementResponse` types — runtime values are not assignable to each other in strict mode. This is the biggest correctness footgun in the package. -### 7. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:33-531` +### 6. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:33-531` - **Why weird:** ErrorCode is copied verbatim from the SDK's apierror codes package. Of the 80 values, comments explicitly mark ~50 as deprecated. The enum is only referenced via the copied `DatabricksServiceExceptionProto` type, which is itself unused by any Genie method (the SDK uses `ApiError.fromHttpError` in `utils.ts:88`). - **Category:** 12 (duplicate concept), 18 (long enum values — `MAX_NOTEBOOK_SIZE_EXCEEDED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, `RESOURCE_DOES_NOT_EXIST`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). - **Suggested name:** Import from `@databricks/sdk-databricks/apierror/codes`. Remove the local copy. - **Rationale:** 500 lines of code duplicate a separate package. Maintenance hazard: deprecation removals or additions to the canonical enum will diverge silently. -### 8. `ScoreReason` enum mixes three prefix families and keeps six deprecated values inline — `src/v1/model.ts:584-613` +### 7. `ScoreReason` enum mixes three prefix families and keeps six deprecated values inline — `src/v1/model.ts:584-613` - **Why weird:** 22 values fall into three groups: (a) bare (`EMPTY_RESULT`, `SINGLE_CELL_DIFFERENCE`, `EMPTY_GOOD_SQL`, `COLUMN_TYPE_DIFFERENCE`); (b) `RESULT_*` (`RESULT_MISSING_ROWS`, `RESULT_EXTRA_ROWS`, `RESULT_MISSING_COLUMNS`, `RESULT_EXTRA_COLUMNS`); (c) `LLM_JUDGE_*` (16 values). `EMPTY_RESULT` and `EMPTY_GOOD_SQL` are semantically `RESULT_*` reasons but lack the prefix family. Six `LLM_JUDGE_*` values are deprecated and live beside the new ones with no visual separation. - **Category:** 17 (inconsistent grouping — same family, different prefixes), 12 (deprecated values inline with active ones). - **Suggested name:** Move `EMPTY_RESULT` / `EMPTY_GOOD_SQL` into the `RESULT_*` family for internal consistency. Separate deprecated values into a dedicated comment block (or split into two enums) so autocomplete groups them. - **Rationale:** The current ordering makes it hard for a reader to tell which values are deterministic vs LLM-judge and which are still active vs deprecated. -### 9. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:648-713` +### 8. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:648-713` - **Why weird:** 60 values, almost every one ends in `_EXCEPTION` (`UNEXPECTED_REPLY_PROCESS_EXCEPTION`, `GENERIC_CHAT_COMPLETION_EXCEPTION`, `CONTEXT_EXCEEDED_EXCEPTION`, …). The few that don't are inconsistent: `STOP_PROCESS_DUE_TO_AUTO_REGENERATE`, `UNKNOWN_AI_MODEL`, `NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE`, plus `MESSAGE_ATTACHMENT_TOO_LONG_ERROR` (suffix `_ERROR` not `_EXCEPTION`), `DESCRIBE_QUERY_UNEXPECTED_FAILURE` / `DESCRIBE_QUERY_TIMEOUT` / `DESCRIBE_QUERY_INVALID_SQL_ERROR` (different verbs). The `_EXCEPTION` suffix is also Java vocabulary, not TS. - **Category:** 2 (redundant suffix — every value already lives under `MessageError_Type`), 14 (Java-style `Exception` vocabulary in TS), 18 (long values — `INTERNAL_CATALOG_ASSET_CREATION_UNSPECIFIED_EXCEPTION` is 52 chars), 17 (inconsistent suffix). - **Suggested name:** Drop `_EXCEPTION` from every value: `UnexpectedReplyProcess | GenericChatCompletion | ContextExceeded | …`. Pick one of `_ERROR` / `_EXCEPTION` / nothing. - **Rationale:** This enum is 67 lines long; cleaning the suffix removes 600+ characters and makes the values readable in autocomplete. -### 10. Multiple `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:534,544,551,558,565,581,585,617,634,649,745` +### 9. Multiple `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:534,544,551,558,565,581,585,617,634,649,745` - **Why weird:** 11 enums use a `XXX_UNSPECIFIED` sentinel where `XXX` is the enum's name: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `GENIE_FEEDBACK_RATING_UNSPECIFIED`, `NULL_VALUE`, `SCORE_REASON_UNSPECIFIED`, `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED`, `THOUGHT_TYPE_UNSPECIFIED`, `TYPE_UNSPECIFIED` (inside `MessageError_Type`), `STATE_UNSPECIFIED` (inside `StatementStatus_State`). Proto2 forces this; TS does not need it because the enum's type acts as the namespace. - **Category:** 2 (redundant enum prefix), 18 (long enum values). - **Suggested name:** `Unspecified` (drop the prefix). Or omit entirely if TS-undefined can stand in for proto-unspecified. - **Rationale:** The package will get cleaner immediately; the wire string can stay the same. -### 11. `TextAttachmentPurpose` enum has only 2 values — collapse to boolean — `src/v1/model.ts:616-619` +### 10. `TextAttachmentPurpose` enum has only 2 values — collapse to boolean — `src/v1/model.ts:616-619` - **Why weird:** Two values: `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED` and `FOLLOW_UP_QUESTION`. A two-member enum where one member is the sentinel adds nothing over a boolean. - **Category:** 12 (overspecified — enum used where a boolean would do). - **Suggested name:** Drop the enum; replace with `isFollowUp?: boolean`. - **Rationale:** Two-member enums where one is `_UNSPECIFIED` are often better collapsed to an optional boolean. -### 12. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:533` +### 11. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:533` - **Why weird:** The type is named `EvaluationStatusType`. Every enum is by definition a "type", so the suffix adds nothing. Peer enums in the same file use bare-noun names (`ScoreReason`, `ThoughtType` — though `ThoughtType` is itself debatable, `Format`, `MessageStatus_MessageStatus`). - **Category:** 8 (redundant `Type` suffix on enum name). - **Suggested name:** `EvaluationStatus`. - **Rationale:** This enum is exposed on `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus`; trimming the suffix shortens both call sites without losing information. -### 13. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` +### 12. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` - **Why weird:** Three deprecated/active methods all return `GenieGetMessageQueryResultResponse` and all read the SQL result for a message. The naming hierarchy is `Message.QueryResult` vs `MessageAttachment.QueryResult` vs `QueryResult.byAttachment` — three different mental models. Two are deprecated but still exported and named in the surface. - **Category:** 17 (inconsistent action verb / structure), 7 (overly verbose), 12 (duplicate concept). - **Suggested name:** Keep the single canonical method (`getMessageAttachmentQueryResult` → `getMessageAttachmentResult`), mark the others `@deprecated` and consider hiding them from the typed surface (re-export only from `/legacy`). - **Rationale:** Three names with overlapping suffixes is the classic generator-emitting-everything problem. -### 14. `GenieEvalAssessment` / `GenieEvalResponseType` — only the sentinel carries the long prefix — `src/v1/model.ts:550,557` +### 13. `GenieEvalAssessment` / `GenieEvalResponseType` — only the sentinel carries the long prefix — `src/v1/model.ts:550,557` - **Why weird:** `GenieEvalAssessment` has values `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GOOD`, `BAD`, `NEEDS_REVIEW`. Only the sentinel carries the prefix. `GenieEvalResponseType` likewise: `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `TEXT`, `SQL`. Within one enum two naming conventions are present. - **Category:** 17 (inconsistent prefix within one enum). - **Suggested name:** Drop the prefix on the sentinel; align with the bare-name convention used by the rest of the values. - **Rationale:** Inconsistency inside a single enum is more jarring than a uniform convention either way; this is the proto-style "only the sentinel is prefixed" pattern. -### 15. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:828` +### 14. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:828` - **Why weird:** The type name stacks three architectural-layer words: `Service` (server-side tier), `Exception` (Java vocabulary), and `Proto` (wire-format suffix). None of these belong in a public TS SDK surface — the SDK exposes errors, not Java exceptions, and not proto messages. JSDoc reinforces the leak: "Serialization format for DatabricksServiceException. Note the definition of this message should be in sync with DatabricksServiceExceptionWithDetailsProto defined in /api-base/proto/exception_with_details.proto". The companion schema is `unmarshalDatabricksServiceExceptionProtoSchema` (line 1843), propagating the leak. - **Category:** Proto-architectural-leak (`Proto` suffix, `Service` mid), 14 (Java-style `Exception` vocabulary in TS), 12 (duplicate concept — the SDK already has `ApiError`). - **Suggested name:** Delete the type and reuse `ApiError` from `@databricks/sdk-databricks/apierror`. If the wire-format shape must be kept locally, name it `ApiErrorPayload` or `WireError` and treat it as an internal marshal-time type, not a public export. -- **Rationale:** `Service`, `Exception`, and `Proto` are all backend implementation vocabulary that should never reach the user-facing SDK surface. The type is unused by any public method body (per finding #7), making the leak gratuitous. +- **Rationale:** `Service`, `Exception`, and `Proto` are all backend implementation vocabulary that should never reach the user-facing SDK surface. The type is unused by any public method body (per finding #6), making the leak gratuitous. ## Medium severity -### 16. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1483` +### 15. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1483` - **Why weird:** Request type for `genieStartConversation`. Name contains *both* `Conversation` and `Message`, but the body has only `spaceId` and `content` (`{ spaceId?: string; content?: string; }`). It is not a request to start a "conversation message" — it is a request to start a conversation by sending an initial message. Compare with `GenieStartConversationResponse` (no `Message` in the name). - **Category:** 6 (misleading — name suggests a compound entity that doesn't exist), 7 (overly verbose). - **Suggested name:** `StartConversationRequest` (matches the response). - **Rationale:** Reader has to parse the doc to learn what "ConversationMessage" means here. The companion response name (`GenieStartConversationResponse`) silently drops `Message` — internal inconsistency. -### 17. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:888` +### 16. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:888` - **Why weird:** `GenieAttachment.attachment` is a `{ $case: 'text' | 'query' | 'suggestedQuestions', … } | undefined` field. Reading `myAttachment.attachment.text` reads as "the attachment of the attachment", and the parent `GenieAttachment` also has a peer field `attachmentId`. The shape mixes the discriminator field with a flat id field. - **Category:** 15 (generic field name losing meaning). - **Suggested name:** Hoist to top-level discriminated union: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. Or rename the field to `payload` / `body` / `content`. - **Rationale:** Same struct, single name; the parent-name-shaped field name confuses readers traversing nested attachments. -### 18. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:917,929` +### 17. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:917,929` - **Why weird:** The struct has two id fields. JSDoc on `id` says "Legacy identifier, use conversation_id instead". Both are emitted, both are typed `string | undefined`, both are read from the wire. The struct also has no doc explaining the precedence rule when both are present (server normally fills both with the same value). - **Category:** 19 (underspecified id), 12 (duplicate concept within one struct), 8 (redundant suffix). -- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#19). +- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#18). - **Rationale:** Caller cannot tell which to read without consulting the doc; autocomplete shows both at the same priority. -### 19. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1372,1395` -- **Why weird:** Same pattern as #18. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. -- **Category:** 19, 12, 8 (same as #18). -- **Suggested name:** Same as #18. -- **Rationale:** Same as #18. +### 18. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1372,1395` +- **Why weird:** Same pattern as #17. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. +- **Category:** 19, 12, 8 (same as #17). +- **Suggested name:** Same as #17. +- **Rationale:** Same as #17. -### 20. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1459-1480` +### 19. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1459-1480` - **Why weird:** Compare with the rest of the SDK: `GenieSpace` uses `title` for the human-readable name (other types use `name`/`displayName`). The struct has `spaceId`, `title`, `description`, `warehouseId`, `parentPath`, `serializedSpace`, `etag` — no `name`. JSDoc on `title` says "Title of the Genie Space" — but in the rest of the codebase, "title" is reserved for `GenieConversation.title` (the conversation subject line). Two different "titles" in the same package. - **Category:** 17 (inconsistency vs other types), 1 (vague — `title` doesn't distinguish from conversation title). - **Suggested name:** `displayName` or `name` (Space is a top-level entity; "title" is column-header style). - **Rationale:** Aligns with `DatabricksWorkspace.name`, `Dashboard.displayName`, etc. -### 21. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:927,1385,1414,1715,1734` +### 20. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:927,1385,1414,1715,1734` - **Why weird:** Five different concepts share the field name `content`. The reader cannot disambiguate from the field name alone. JSDocs differ: "User message content" / "Comment text content" / "AI generated message" / "The md formatted content for this thought" — i.e. they are all different formats. - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `body` for the message body, `text` for comments and thoughts, or qualify (`messageBody`, `commentText`, `thoughtMarkdown`). - **Rationale:** "Content" is a near-meaningless filler word; this is the kind of generic name the codebase rule (#15 of the audit categories) targets. -### 22. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:921` +### 21. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:921` - **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1378), `GenieMessageComment.userId` (line 1412), `GenieEvalResult.createdByUser` (line 1025), `GenieEvalRunResponse.runByUser` (line 1091). - **Category:** 16 (field type contradicts domain), 14 (proto-int64 leaked to JS `number`). - **Suggested name:** Keep field name, change type to `string` (matches the rest of the SDK), or use `bigint`. Or `userId: string` with stronger JSDoc. - **Rationale:** Postgres-ID / long-id semantics are universal here. The `userId: number` typing is a generator bug that bites at runtime. -### 23. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:923,925,935,1093,1103,1380,1382,1416,1427` +### 22. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:923,925,935,1093,1103,1380,1382,1416,1427` - **Why weird:** 9 fields use `*Timestamp` suffix. The type is already `number` (a Unix-millis timestamp per JSDoc). The suffix duplicates the type. Some peer fields drop the suffix (`createdByUser` on `GenieEvalResult`, `runByUser` on `GenieEvalRunResponse`). - **Category:** 7 (overly verbose), 8 (redundant suffix). - **Suggested name:** `createdAt` / `updatedAt`. Or `createdAtMs` / `updatedAtMs` if the millis unit needs to be explicit. - **Rationale:** Industry-standard `createdAt`/`updatedAt` reads more naturally than `createdTimestamp`/`lastUpdatedTimestamp`. -### 24. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1382` +### 23. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1382` - **Why weird:** `lastUpdatedTimestamp` (5 syllables) is the package's "updated at" name. The `last` prefix adds nothing — by definition, an "updated at" timestamp is the *last* update. - **Category:** 7 (overly verbose). - **Suggested name:** `updatedAt` / `updatedTimestamp`. -- **Rationale:** Same as #23. +- **Rationale:** Same as #22. -### 25. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1429` +### 24. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1429` - **Why weird:** `id?: string` on `GenieQueryAttachment` is undocumented (no JSDoc). The parent `GenieAttachment` has `attachmentId` (line 909) — so the `id` here is presumably the same value or the query-attachment-specific id. Caller can't tell. - **Category:** 19 (underspecified id), 1 (vague). - **Suggested name:** `attachmentId` (match the parent) or `queryAttachmentId` (qualify). - **Rationale:** Two near-identical ids on the same outer entity is one ambiguity too many. -### 26. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1716` -- **Why weird:** Same as #25 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. +### 25. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1716` +- **Why weird:** Same as #24 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. - **Category:** 19, 1. -- **Suggested name:** Same as #25. -- **Rationale:** Same as #25. +- **Suggested name:** Same as #24. +- **Rationale:** Same as #24. -### 27. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` +### 26. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` - **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). - **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). - **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. - **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. -### 28. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` +### 27. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` - **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. - **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). - **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. - **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. -### 29. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` -- **Why weird:** Same as #28 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +### 28. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` +- **Why weird:** Same as #27 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). - **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). - **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. - **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. -### 30. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1149,1173` +### 29. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1149,1173` - **Why weird:** JSDoc says "JWT signature for the download_id". JWT is itself the full token (header.payload.signature). Calling it a "signature" understates what it is (the entire JWT that authorises the download). - **Category:** 6 (misleading — `Signature` is a sub-part of a JWT), 5 (cryptic). - **Suggested name:** `downloadToken` / `downloadJwt`. - **Rationale:** Caller expects a base64 signature to pair with `downloadId`; the value is actually a full bearer token. -### 31. `statementIdSignature` same pattern — `src/v1/model.ts:1597` -- **Why weird:** Same as #30: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. +### 30. `statementIdSignature` same pattern — `src/v1/model.ts:1597` +- **Why weird:** Same as #29: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. - **Category:** 6 (misleading), 5 (cryptic). - **Suggested name:** `statementToken` / `statementJwt`. -- **Rationale:** Same as #30. +- **Rationale:** Same as #29. -### 32. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1480,1529` +### 31. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1480,1529` - **Why weird:** HTTP `ETag` is the canonical capitalisation. The field is `etag: string`. Across the SDK other types use `etag` lowercase too — but it is an acronym (`Entity Tag`). - **Category:** 3 (acronym casing). - **Suggested name:** `eTag` (camelCase per TS style) or `etag` (current — chosen for consistency). - **Rationale:** Low priority; flag for awareness. -### 33. `Result` type name — too generic — `src/v1/model.ts:1589` +### 32. `Result` type name — too generic — `src/v1/model.ts:1589` - **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. - **Category:** 1 (vague/generic). - **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. - **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. -### 34. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1595,1656` +### 33. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1595,1656` - **Why weird:** Both fields are booleans indicating truncation. `Result.isTruncated` uses the `is*` prefix convention; `ResultManifest.truncated` is bare. Same struct file, two conventions. - **Category:** 17 (inconsistency). - **Suggested name:** Pick one form (`truncated` everywhere) and apply. - **Rationale:** Pure consistency win; no semantic change. -### 35. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1442` +### 34. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1442` - **Why weird:** A third truncation field on `GenieResultMetadata.isTruncated`. Three independent fields tracking the same concept across `Result`, `ResultManifest`, `GenieResultMetadata`. - **Category:** 17 (inconsistency), 12 (duplicate concept). -- **Suggested name:** Same as #34. -- **Rationale:** Same as #34. +- **Suggested name:** Same as #33. +- **Rationale:** Same as #33. -### 36. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1438` +### 35. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1438` - **Why weird:** A type whose two fields (`rowCount`, `isTruncated`) are both already on `ResultManifest`. JSDoc says "Metadata associated with the query result", but `ResultManifest` is also "result manifest" metadata. - **Category:** 12 (duplicate concept). - **Suggested name:** Replace with `ResultManifest` (or a sub-projection of it); delete `GenieResultMetadata`. - **Rationale:** Two structs covering the same semantic territory cause readers to wonder which one is authoritative. -### 37. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1584` +### 36. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1584` - **Why weird:** `keyword` is a vague word for what is presumably the parameter name. No JSDoc. The companion field `value` carries the bound value; `sqlType` carries the type. A parameter is `(name, value, type)` — why is `name` called `keyword`? - **Category:** 1 (vague), 6 (misleading — `keyword` evokes SQL reserved words). - **Suggested name:** `name` (with JSDoc) or `parameterName`. - **Rationale:** Reader sees `keyword` and looks for a SQL keyword list. -### 38. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1585` +### 37. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1585` - **Why weird:** No JSDoc on `value`. Type is `string`. For SQL parameters this could be a literal value, an expression, a placeholder, a JSON-encoded scalar, etc. Companion `sqlType?: string` (also no JSDoc) presumably qualifies it. - **Category:** 1 (vague), 16 (field type may contradict domain). - **Suggested name:** Document. Optionally `stringValue` / `valueText` to make the encoding explicit. - **Rationale:** Public SDK types should not require source-diving. -### 39. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:903` +### 38. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:903` - **Why weird:** Discriminator value is `'suggestedQuestions'` and the payload type is `GenieSuggestedQuestionsAttachment`. The word `Attachment` is in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** Variant `'followUps'`, payload `SuggestedQuestions { questions: string[] }`. @@ -253,109 +247,109 @@ ## Low severity -### 40. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1502` +### 39. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1502` - **Why weird:** Bare `string[]`. Doc says "The suggested follow-up questions". The questions are also typed elsewhere as a free-text input (`content` on a `GenieCreateConversationMessageRequest`) — so the type tells you nothing about the format. - **Category:** 1 (vague — questions could be markdown, plain, etc.). - **Suggested name:** `followUpQuestions: string[]` (clearer; matches the JSDoc). - **Rationale:** Field name disambiguation. -### 41. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1557` +### 40. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1557` - **Why weird:** `MessageError.error: string`. Reader sees `someError.error` (two `error`s). Some other fields are similarly self-referential (`Result.statementId`, OK because `Result` is generic; here `MessageError.error` is *the error message*). - **Category:** 15 (generic field name), 1 (vague). - **Suggested name:** `MessageError.message: string` (matches the JSON shape) or `MessageError.detail`. - **Rationale:** Wire format on the server may already be `error_message`; check before renaming. -### 42. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1558` +### 41. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1558` - **Why weird:** Field name `type` is a JS reserved-word-adjacent (TS allows it, but `type` collides with the `type` keyword used in TS type aliases — refactoring tools sometimes choke). - **Category:** 10 (reserved-word collision), 1 (vague). - **Suggested name:** `errorType` / `category` / `kind`. - **Rationale:** Common collision; small ergonomics win. -### 43. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1732` +### 42. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1732` - **Why weird:** `Thought.thoughtType` repeats "thought" twice. Could just be `Thought.type`. - **Category:** 8 (redundant suffix), 7 (overly verbose). - **Suggested name:** `Thought.type` (and rename `ThoughtType` → `Thought.Kind` namespace). - **Rationale:** Reduces redundancy. -### 44. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:909` +### 43. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:909` - **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1714) and `GenieQueryAttachment.id` (line 1429) inside variants. Three different id fields for the same logical entity (the attachment). - **Category:** 19 (underspecified id), 12 (duplicate concept). - **Suggested name:** Single `id` on `GenieAttachment`, remove inner ids. -- **Rationale:** See #25, #26, #44 together. +- **Rationale:** See #24, #25, #43 together. -### 45. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1239` +### 44. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1239` - **Why weird:** Boolean toggle that expands the response. Permission check is documented ("Requires at least CAN EDIT permission"). Boolean naming style varies across SDK: `enableX`, `includeX`, `withX`. Could be `withSerializedSpace` or `includeSerialized` (the parent struct is already a Space). - **Category:** 7 (overly verbose). - **Suggested name:** `withSerialized` / `expandSerialized`. - **Rationale:** The struct context already says "Space"; the prefix is redundant. -### 46. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` +### 45. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` - **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). - **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. - **Rationale:** Class names should be noun phrases; current name reads as a verb. -### 47. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:160` +### 46. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:160` - **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. - **Category:** 7 (overly verbose). - **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. - **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. -### 48. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1255` +### 47. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1255` - **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. - **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). - **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. - **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. -### 49. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:546` +### 48. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:546` - **Why weird:** Value `ARROW_STREAM` casing. The product name is `Apache Arrow` — `Arrow` is title-case in TS naming. As an enum value `ARROW_STREAM` is conventional (SCREAMING_SNAKE) but mixed with `JSON_ARRAY` and `CSV` where one is fully-cap acronym and one is mixed. - **Category:** 3 (acronym casing), 17 (mixed conventions within the enum). - **Suggested name:** `ArrowStream` (in a Pascal-case enum). - **Rationale:** Low priority — enum-value style is widely-debated. -### 50. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1392` -- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #33). +### 49. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1392` +- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #32). - **Category:** 12 (duplicate concept — kept-for-compat), 1 (vague — `Result`). - **Suggested name:** Mark with `/** @deprecated */` JSDoc (current text just says "Deprecated" — TS tooling won't strike-through). - **Rationale:** Tooling support — modern TS understands `@deprecated`. -### 51. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +### 50. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. - **Rationale:** Cleanup; clients should migrate to the canonical name. -### 52. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1025` +### 51. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1025` - **Why weird:** Field is named `createdByUser` rather than `createdBy`. `By User` is redundant: a `createdBy` field is by-its-nature-by-a-user (or by a service principal). Compare `GenieEvalRunResponse.runByUser` (same pattern, line 1091). - **Category:** 7 (overly verbose), 17 (inconsistent vs other types in the SDK using `createdBy`). - **Suggested name:** `createdBy` (matches the rest of the SDK). - **Rationale:** Aligns with `databricks-sdk-go` conventions and most peer types. -### 53. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1091` -- **Why weird:** Same as #52. +### 52. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1091` +- **Why weird:** Same as #51. - **Category:** 7, 17. - **Suggested name:** `runBy` / `runByUserId`. -- **Rationale:** Same as #52. +- **Rationale:** Same as #51. -### 54. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1023,1080,1082` +### 53. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1023,1080,1082` - **Why weird:** `GenieEvalResult` stores the original "benchmark answer" as a flat string; `GenieEvalResultDetails` returns the actual/expected as arrays of `GenieEvalResponse`. Three different words for "the right answer" / "Genie's answer" / "the expected answer". - **Category:** 17 (inconsistent word choice), 1 (vague — `answer` vs `response`). - **Suggested name:** Pick one verb. E.g., `expectedAnswer` / `actualAnswer` (or `expectedResponse` / `actualResponse` for both types). - **Rationale:** Reader has to relearn the vocabulary in each type. -### 55. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1037` +### 54. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1037` - **Why weird:** A `GenieEvalResultDetails` describes a single result inside a run. The field `evalRunStatus` describes the *run's* status, not the result's status. The plain `status` field appears on `GenieEvalResult` (line 1019) but is gone here — replaced by `evalRunStatus`. So the same enum (`EvaluationStatusType`) is exposed under two different field names. - **Category:** 17 (inconsistent field naming for the same concept), 6 (misleading — `evalRunStatus` on a result-details type confuses run-status with result-status). - **Suggested name:** `runStatus` (with the run context clear from the parent type's purpose). - **Rationale:** Same status enum, two field names is jarring. -### 56. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1041` +### 55. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1041` - **Why weird:** Two adjacent fields: `assessment: GenieEvalAssessment` and `manualAssessment: boolean`. The second is a flag indicating whether the first was set manually. The naming implies that `manualAssessment` is itself an assessment. - **Category:** 6 (misleading — `manualAssessment` looks like "the manual assessment value"), 1 (vague). - **Suggested name:** `assessmentIsManual` / `isManuallyAssessed`. - **Rationale:** Boolean-prefix convention disambiguates. -### 57. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1289` +### 56. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1289` - **Why weird:** `includeAll: boolean`. JSDoc clarifies "Include all conversations in the space across all users". `All` is unqualified; could mean "include archived", "include all spaces", "include all messages". - **Category:** 1 (vague), 6 (misleading without docs). - **Suggested name:** `includeAllUsers` / `acrossUsers` / `allUsers`. @@ -363,23 +357,23 @@ ## Observations -### 58. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #45 -- **Observation:** Listed under #45. Documenting here for cross-reference. +### 57. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #44 +- **Observation:** Listed under #44. Documenting here for cross-reference. -### 59. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` +### 58. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` - **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. - **Suggested name:** N/A. - **Rationale:** Confirms the package's pagination naming is consistent. -### 60. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` +### 59. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` - **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. - **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. - **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. -### 61. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,999,1008` +### 60. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,999,1008` - **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. -### 62. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` +### 61. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` - **Observation:** `export interface MessageStatus {}` is an empty placeholder. The actual status enum is `MessageStatus_MessageStatus`. The empty type adds noise to the surface. - **Suggested name:** Remove the empty interface; refer to the enum directly. - **Rationale:** Empty interfaces in TS satisfy any object type and become bug magnets. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 74444add..5448cb3e 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -21,11 +21,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 10 | -| Medium | 11 | +| High | 9 | +| Medium | 7 | | Low | 16 | | Observation | 7 | -| **Total** | **44**| +| **Total** | **39**| ### Top themes @@ -33,11 +33,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. `EditInstancePoolRequest` (29 fields), `GetInstancePoolRequest_Response` (30 fields), and `InstancePoolAndStats` (30 fields) are byte-identical apart from one or two fields. They could share a single base type. -2. **`InstancePool*` prefix on every type is redundant** — the package is - already `instancepools`; the v2 namespace is even smaller. `Pool` (or even - nothing) would do for `InstancePoolStats`, `InstancePoolStatus`, - `InstancePoolAndStats`. -3. **Cross-package shape duplication** — eleven types/enums are duplicated +2. **Cross-package shape duplication** — eleven types/enums are duplicated verbatim between this package and `clusters`. A shared `compute` module would eliminate the dual maintenance burden. @@ -160,11 +156,10 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | O-01 | `idleInstanceAutoterminationMinutes` (5-word identifier, present in 4 types) | Medium | 33-char field. Inside a type called `CreateInstancePoolRequest` etc., `idleAutoterminationMinutes` or `idleTimeoutMinutes` would be 27 / 18 chars. The wire uses `idle_instance_autotermination_minutes` so any change is generator-side. | -| O-02 | `InstancePool*` prefix on `InstancePoolStats`, `InstancePoolStatus`, `InstancePoolAndStats`, `InstancePoolAwsAttributes`, `InstancePoolAzureAttributes`, `InstancePoolGcpAttributes`, `InstancePoolState` | High | The package is already `@databricks/sdk-instancepools`. Inside the package, the prefix is redundant. `Stats`, `Status`, `AwsAttributes` would all suffice and remove ~12 chars from each name. Compare `clusters` (`clusters.md` #75) and `apps` packages, which face the same recurring issue. | -| O-03 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | -| O-04 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | -| O-05 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | -| O-06 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | +| O-02 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | +| O-03 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | +| O-04 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | +| O-05 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | ### 2.6 Singular / plural mismatches — Low / High @@ -256,14 +251,10 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `InstancePoolAwsAttributes` / `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` | Medium | All three carry the `Attributes` suffix and the redundant `InstancePool` prefix (see O-02). Could be `AwsAttributes` / `AzureAttributes` / `GcpAttributes` (matching `clusters`). | -| TS-02 | `InstancePoolStats` | Medium | `Stats` is already abbreviated; the `InstancePool` prefix is redundant inside this package. | -| TS-03 | `InstancePoolStatus` | Medium | Same as TS-02. | -| TS-04 | `InstancePoolState` (enum) | Medium | Same. Could be `State` or `PoolState`. | -| TS-05 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-02). Doubly off. | -| TS-06 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | -| TS-07 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-04) the type-name still echoes. | -| TS-08 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | +| TS-01 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-02). Doubly off. | +| TS-02 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | +| TS-03 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-04) the type-name still echoes. | +| TS-04 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | ### 2.17 Other observations @@ -417,11 +408,11 @@ artefact and the leading underscore at the same time. | Severity | Count | | ------------ | ----- | -| High | 10 | -| Medium | 11 | +| High | 9 | +| Medium | 7 | | Low | 16 | | Observation | 7 | -| **Total** | **44**| +| **Total** | **39**| ## 4. Cross-package consistency notes diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md index dcbea5e8..d608777a 100644 --- a/.agent/naming-audit/logdelivery.md +++ b/.agent/naming-audit/logdelivery.md @@ -9,13 +9,13 @@ delivery configuration ties a `credentialsId` (AWS IAM role) and a `AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no delete endpoint by design — the API only supports disabling via the update (`PATCH`) method. -**Total weird names flagged:** 28 +**Total weird names flagged:** 27 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 11 | +| Medium | 10 | | Low | 7 | | Observation | 4 | @@ -63,7 +63,7 @@ update (`PATCH`) method. ### 5. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` - **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:126,218`). The client substitutes them via `?? ''` (`client.ts:126,218`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). - **Category:** 6 (misleading — type signature says optional, runtime requires non-empty), 7 (overly verbose / boilerplate JSDoc). -- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create` — see finding 23). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." +- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create` — see finding 25). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." - **Rationale:** Required path params should have required types. The current shape silently produces malformed URLs at runtime. The "of customer" prose is generator-emitted boilerplate worth removing globally. ### 6. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` @@ -80,25 +80,19 @@ update (`PATCH`) method. - **Suggested name:** `LogDeliveryClient` (or expose a namespace and let `logDelivery.Client` be the qualified name). - **Rationale:** Every audited package has this finding. Worth normalising at generator level. -### 8. Client method names embed the noun three times — `src/v1/client.ts:90,122,150,214` -- **Why weird:** `client.createLogDeliveryConfiguration({logDeliveryConfiguration: {...}})` repeats the noun phrase three times in a single expression (`createLogDeliveryConfiguration` — `logDeliveryConfiguration` — wrapped content). The Go SDK uses short names (`Create`, `Get`, `List`, `PatchStatus`) because the receiver type provides the noun. The TS port re-states the full noun on the method. -- **Category:** 7 (overly verbose), 17 (inconsistent with sibling packages that use shorter verbs once `Client` is qualified). -- **Suggested name:** `client.create()` / `client.get()` / `client.list()` / `client.listIter()` / `client.patchStatus()`. Pair with finding 7 so the receiver is `LogDeliveryClient`. -- **Rationale:** Once the class is `LogDeliveryClient`, the short methods are unambiguous. Same finding as `disasterrecovery` (M16/L17) and `externallineage` (#23). - -### 9. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` +### 8. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` - **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:160`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `listLogDeliveryConfigurations` (plural). The `*Iter` pagination helper should match: `listLogDeliveryConfigurationsIter`. - **Rationale:** Method-name pluralisation should match the data shape it yields. -### 10. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` -- **Why weird:** Same shape mismatch as finding 9, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. +### 9. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` +- **Why weird:** Same shape mismatch as finding 8, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and the `_Response` partner correspondingly). - **Rationale:** Pluralisation is the standard signal for a collection-returning method/type pair. -### 11. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` +### 10. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` - **Why weird:** Reading `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types whose names all carry "Status": - `LogDeliveryConfiguration` (the resource). - `LogDeliveryStatus` (wrapper for the last-attempt fields). @@ -109,37 +103,37 @@ update (`PATCH`) method. - **Suggested name:** Rename field `logDeliveryStatus` → `lastAttempt`. Rename wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`). Rename enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The call site becomes `config.lastAttempt.status === 'SUCCEEDED'` — three concrete nouns instead of three "Status" repetitions. - **Rationale:** "Status" is too generic to triple-stack. Aligns with findings 1 and 2. -### 12. `creationTime` / `updateTime` — noun/verb tense mismatch, ambiguous unit — `src/v1/model.ts:99-101,201-203` +### 11. `creationTime` / `updateTime` — noun/verb tense mismatch, ambiguous unit — `src/v1/model.ts:99-101,201-203` - **Why weird:** `creationTime: number` (noun form "creation") paired with `updateTime: number` (verb form "update"). They should match: either `createdTime` / `updatedTime` (past participle) or `creationTime` / `updateTime` (noun + verb is inconsistent). Both are typed `number` but the unit (epoch milliseconds) lives only in the JSDoc — a reader scanning the type cannot tell whether this is seconds, milliseconds, or microseconds. - **Category:** 13 (verb-tense inconsistency), 6 (misleading — bare `number` does not encode "epoch ms"). - **Suggested name:** `createdAt: number` / `updatedAt: number` (the canonical SaaS convention used by Stripe, GitHub, Salesforce, Atlassian, Linear). Brand the type as `EpochMillis` to encode the unit at compile time. - **Rationale:** `*At` is the industry standard for timestamps. Generator-wide concern — many audited packages share this finding. -### 13. `deliveryStartTime: string` is a YYYY-MM date, not a time — `src/v1/model.ts:95,197` +### 12. `deliveryStartTime: string` is a YYYY-MM date, not a time — `src/v1/model.ts:95,197` - **Why weird:** The field is `string` typed, but the JSDoc says "specified in YYYY-MM format". That is a year-month bucket, not a "time". Compare with `creationTime: number` (an epoch-ms timestamp) in the same struct — the word "Time" is used for two different granularities. - **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" suggests a timestamp). - **Suggested name:** `deliveryStartMonth: string` (or, since `@js-temporal/polyfill` is already a workspace dependency, `Temporal.PlainYearMonth`). - **Rationale:** "Time" implies sub-day resolution; the domain is monthly billing buckets, so "Month" is the right granularity. Same convention as Stripe's `period_start` (timestamp) vs `period.start` (date-only) split. -### 14. `workspaceIdsFilter` — redundant `Filter` suffix on a collection field — `src/v1/model.ts:91,193` +### 13. `workspaceIdsFilter` — redundant `Filter` suffix on a collection field — `src/v1/model.ts:91,193` - **Why weird:** The field is `workspaceIdsFilter: number[]` on both the request DTO (`CreateLogDeliveryConfigurationParams`, line 91) and the response DTO (`LogDeliveryConfiguration`, line 193). On the response DTO, `Filter` is misleading — the same field stores the configured workspace scope, not a "filter" applied at read time. Compare with `ListLogDeliveryConfigurationRequest.credentialsId: string` at `model.ts:145` (no `Filter` suffix, same conceptual role as a list filter). - **Category:** 7 (overly verbose), 15 (generic suffix). - **Suggested name:** `workspaceIds: number[]` (the array shape already conveys "list of workspace IDs"; the `Filter` suffix carries no extra signal). - **Rationale:** Field naming should describe content. A `number[]` named after the entity is unambiguous. -### 15. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` +### 14. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` - **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double-precision float — only safe up to 2^53 − 1. Databricks workspace IDs are int64 server-side; transmitting an ID above the safe range silently loses precision in the JSON wire round-trip. - **Category:** 6 (misleading — TS type cannot represent the wire's int64 safely), 19 (under-specified id type). - **Suggested name:** `workspaceIds: bigint[]` (matches int64 wire). Alternative: brand the IDs as `WorkspaceId` via `type WorkspaceId = bigint & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package finding — every `*Id: number` typed against an int64 wire has the same hazard. Generator-level fix: emit `bigint` for `int64` fields. -### 16. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` +### 15. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` - **Why weird:** `private readonly host: string` — without context, `host` could be just a hostname (`example.com`). The setter at line 62 trims a trailing slash, hinting that the field actually carries a full URL with scheme. A user wiring up `ClientOptions.host` cannot tell from the type whether to pass `databricks.com` or `https://databricks.com/`. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `baseUrl: string` (or `databricksHost`). Matches the actual content (a URL including scheme). - **Rationale:** Generator-level concern — every package's `Client` has this field. Same finding as `disasterrecovery` and others. -### 17. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` +### 16. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` - **Why weird:** Two functions both prefixed `execute` doing very different jobs. `executeCall` wraps a call in retry/rate-limit (`utils.ts:26-38`); `executeHttpCall` does the raw HTTP send plus error lift (`utils.ts:65-94`). Inside each client method, `executeHttpCall` is wrapped in a `Call` (the function alias), and `executeCall(call, options)` runs it — the reader has to trace both bodies to learn who calls whom. - **Category:** 1 (vague), 12 (duplicate prefix), 17 (inconsistent layering nomenclature). - **Suggested name:** `runWithRetry(call, options)` (outer) + `sendHttp(opts)` or `dispatchHttp(opts)` (inner). The verb pair "run" vs "send" makes the layering obvious. @@ -147,43 +141,43 @@ update (`PATCH`) method. ## Low severity -### 18. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` +### 17. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered by this configuration. Pair-wise consistency would be either `BILLABLE_USAGE_LOGS` + `AUDIT_LOGS` (both plural with `_LOGS`) or `BILLABLE_USAGE` + `AUDIT` (both singular without). - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Suggested name:** `BILLABLE_USAGE` + `AUDIT` (drop `_LOGS` — the enum is `LogDeliveryType` so "logs" is implicit). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the enclosing type) is shorter. -### 19. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` JSDoc is tautological — `src/v1/model.ts:13-16` +### 18. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` JSDoc is tautological — `src/v1/model.ts:13-16` - **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the per-member doc echoes the identifier verbatim. JSDoc should add information. - **Category:** 1 (vague — doc carries no new signal). - **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured bucket." - **Rationale:** Generator-wide concern. Same in many audited packages. -### 20. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` +### 19. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc on line 37 says it means "the log delivery status as the configuration has been disabled since the release of this feature or there are no workspaces in the account". That is "no data to report", not "resource missing". - **Category:** 6 (misleading — value name suggests an HTTP error state, semantics are operational). - **Suggested name:** `NO_DATA`, `NOT_APPLICABLE`, or `DISABLED_AT_RELEASE` — anything that does not read as 404. - **Rationale:** A monitoring dashboard surfacing `status === 'NOT_FOUND'` would mislead an operator into thinking the configuration was deleted. -### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` +### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` - **Why weird:** `Segment` is a generic CS term. The leading comment ("Package identity segment for this client to be used in the User-Agent header.", line 40) does the documentation work the name should do. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Generator-wide concern. Same finding in every audited package. -### 22. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` +### 21. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` - **Why weird:** Field name and type both end in `Client`. The shorter form would be `client: HttpClient`, but that would collide with the enclosing `Client` class. So the disambiguation is mechanical, not informative. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `transport: HttpClient` (matches the imported `./transport` module) — avoids the `Client/Client` echo and reads as "the transport layer". - **Rationale:** Generator-wide concern. Tolerable as-is but flagged per rule 20. -### 23. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` +### 22. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` - **Why weird:** Three-letter abbreviations on parameter and local names across every method. The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. -### 24. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` +### 23. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` - **Why weird:** Holds the request shape mutated with `pageToken` between pages. The name reads as "the page's request" rather than "the request iterated across pages". - **Category:** 5 (cryptic), 1 (vague). - **Suggested name:** `currentRequest`, `paginatedRequest`, or just `request` (the per-iteration redefinition is clear from context). @@ -191,37 +185,37 @@ update (`PATCH`) method. ## Observations -### 25. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +### 24. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` `client.ts` constructs query params inline (lines 155-167) with `new URLSearchParams()` and `params.append(...)`. The exported `flattenQueryParams` helper is never called from this package. Every generated package ships this helper unconditionally — it is generator scaffolding. - **Category:** 11 (unused public helper). - **Suggested fix:** Generator-level — only emit `flattenQueryParams` when the client actually needs it. -### 26. `accountId` URL fallback is inconsistent between create and other methods — `src/v1/client.ts:94,126,154,218` +### 25. `accountId` URL fallback is inconsistent between create and other methods — `src/v1/client.ts:94,126,154,218` `createLogDeliveryConfiguration` reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client-options fallback), while `getLogDeliveryConfiguration`, `listLogDeliveryConfiguration`, and `updateLogDeliveryConfiguration` all read `req.accountId ?? this.accountId ?? ''`. A caller who sets `ClientOptions.accountId` once and forgets to copy it into `logDeliveryConfiguration` on create silently sends a request to `/api/2.0/accounts//log-delivery`. The asymmetry is not advertised by the type — both shapes accept `accountId: string | undefined`. - **Category:** 6 (misleading — same-named field has different fallback semantics on create vs read), 16 (field placement contradicts wire-level convention). - **Suggested fix:** On `create`, also fall back to `this.accountId`. Better: lift `accountId` out of `CreateLogDeliveryConfigurationParams` entirely (it is a path param, not a body field) so the shape matches the other three methods. This is a correctness bug surfaced by a naming/structure inconsistency. -### 27. JSDoc artefacts: stray ` * *` opening lines and unresolved `` templates — `src/v1/model.ts:6,20,31,53,64,107,121,138,166,227` and `model.ts:84,127,142,186,233` +### 26. JSDoc artefacts: stray ` * *` opening lines and unresolved `` templates — `src/v1/model.ts:6,20,31,53,64,107,121,138,166,227` and `model.ts:84,127,142,186,233` Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` line (e.g., line 5-7: `/**\n * *\n * Log Delivery Status`). Looks like the generator emits an empty paragraph break that renders as a literal `*`. Separately, the placeholder `` appears unsubstituted throughout (e.g., `model.ts:84,127,142,186,233` — "`` account ID"). Neither is a naming issue per se but both pollute the rendered docs. - **Category:** Observation (generator template hygiene). -### 28. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` +### 27. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. ## Domain glossary - **`account`** — Databricks account, the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) and as `ClientOptions.accountId` (`client.ts:50,63`). -- **`workspace`** — A Databricks workspace under an account. Workspace IDs are `int64` on the wire but typed `number` in TS (finding 15). +- **`workspace`** — A Databricks workspace under an account. Workspace IDs are `int64` on the wire but typed `number` in TS (finding 14). - **`credentials`** — Cross-package reference (`Credentials.Create`) — a stored AWS IAM role with policy and trust relationship. The `credentialsId` field (`model.ts:87,189`) links a log delivery config to that resource. - **`storage configuration`** — Cross-package reference (`Storage.Create`) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:89,191`) links the config to a bucket. - **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` instructing Databricks to write certain logs to a bucket. - **`log type`** — `BILLABLE_USAGE` or `AUDIT_LOGS` — the category of logs delivered. -- **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always implied by `log type` (finding 28). +- **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always implied by `log type` (finding 27). - **`delivery path prefix`** — S3 key prefix; defaults to bucket root. Must not start or end with `/`. -- **`delivery start time`** — `YYYY-MM` string (a month bucket, not a timestamp — finding 13). Only applies to billable usage; lower bound is `2019-03`. +- **`delivery start time`** — `YYYY-MM` string (a month bucket, not a timestamp — finding 12). Only applies to billable usage; lower bound is `2019-03`. - **`config status`** — `ENABLED` / `DISABLED` (`LogDeliveryConfigStatus`). The config is never deleted, only disabled. - **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` (`LogDeliveryStatusEnum`). Reflects the most-recent attempt; surfaces as `LogDeliveryStatus.status`, i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`. - **`E2`** — Databricks newer multi-region account architecture. Mentioned in `UpdateLogDeliveryConfigurationRequest.accountId` JSDoc (`model.ts:233`). -- **`int64`** — Wire-level 64-bit signed integer. Used for workspace IDs; typed `number` in TS (lossy — finding 15). +- **`int64`** — Wire-level 64-bit signed integer. Used for workspace IDs; typed `number` in TS (lossy — finding 14). - **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`). Go SDK exposes this as `PatchStatus`; the TS port paraphrases it as `updateLogDeliveryConfiguration` (finding 6). ## File coverage diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index f998c133..91336228 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,12 +3,12 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 52 +**Total weird names flagged:** 51 ## Summary | Severity | Count | | --- | --- | -| High | 12 | +| High | 11 | | Medium | 27 | | Low | 8 | | Observation | 5 | @@ -219,24 +219,7 @@ Field name = type name minus the `FileParent` prefix repeated. Inside `FileParen - **Suggested name:** `type` (matching `ShareInfo.type`) or `parentType`. - **Rationale:** Redundant context. -### 11. `FileInfo.marketplaceFileType` — package-name prefix in a field - -**Location:** `src/v1/model.ts:332` - -```ts -export interface FileInfo { - id?: string | undefined; - marketplaceFileType?: MarketplaceFileType | undefined; - ... -} -``` - -The field qualifies "fileType" with "marketplace" — but the type is *already* inside the marketplaces package. Every `FileType` here is a marketplace file type. The same prefix appears on `MarketplaceFileType` (the enum itself, line 123). Together they read as `marketplaceFileType: MarketplaceFileType` — package name stuttered twice. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology). -- **Suggested name:** Rename enum → `FileType`; rename field → `type`. -- **Rationale:** Package-name qualifiers are noise on internal fields. - -### 12. `*Request_Response` — proto-nested-message pattern leaked into public types +### 11. `*Request_Response` — proto-nested-message pattern leaked into public types **Location:** `src/v1/model.ts:203, 214, 243, 252, 280, 287, 294, 386, 410, 444, 454, 474, 484, 602, 622, 635, 926, 939, 954, 968` @@ -263,7 +246,7 @@ Every one carries an `eslint-disable @typescript-eslint/naming-convention -- Pro ## Medium severity -### 13. `Client` — generic top-level class name +### 12. `Client` — generic top-level class name **Location:** `src/v1/client.ts:210` @@ -276,7 +259,7 @@ Top-level export named just `Client`. Every generated package exports a `Client` - **Suggested name:** `MarketplacesClient`. - **Rationale:** Service-prefixed client class names are standard across `@aws-sdk/*`, `@google-cloud/*`, `@azure/*`. -### 14. `Exchange.linkedListings` — verb tense and ambiguity +### 13. `Exchange.linkedListings` — verb tense and ambiguity **Location:** `src/v1/model.ts:305` @@ -292,7 +275,7 @@ export interface Exchange { - **Suggested name:** `listings`, `memberships`, or `listingLinks`. - **Rationale:** Past-participle field names suggest a log/audit; this is a list of current memberships. -### 15. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix +### 14. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix **Location:** `src/v1/model.ts:311, 317` @@ -312,7 +295,7 @@ Inside an `ExchangeFilter`, what else could `filterValue` be the value of? Or `f - **Suggested name:** `value`, `type`. - **Rationale:** Field names that re-state the parent type are noise (see also `EffectivePrivilege.privilege` from grants audit #15). -### 16. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum +### 15. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum **Location:** `src/v1/model.ts:68-70` @@ -327,7 +310,7 @@ An enum with a single member. Typically a sign that the API anticipates future f - **Suggested name:** Could be a string literal type until a second value lands. - **Rationale:** TS allows narrowing without enums (`type ExchangeFilterType = 'GLOBAL_METASTORE_ID'`). -### 17. `MarketplaceFileType.APP` — three-letter generic value +### 16. `MarketplaceFileType.APP` — three-letter generic value **Location:** `src/v1/model.ts:126` @@ -344,7 +327,7 @@ export enum MarketplaceFileType { - **Suggested name:** `EMBEDDED_APP` or `APP_PACKAGE`. - **Rationale:** Match the qualifier convention of `EMBEDDED_*` peers. -### 18. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment +### 17. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment **Location:** `src/v1/model.ts:129-135` @@ -363,7 +346,7 @@ The JSDoc explicitly says the value is named `REQUEST_PENDING` because `PENDING` - **Suggested name:** `PENDING` (cross-enum collisions don't exist in TS). - **Rationale:** Proto-side collision avoidance has no purpose in the TS surface. -### 19. `Cost` — single-word, ambiguous enum +### 18. `Cost` — single-word, ambiguous enum **Location:** `src/v1/model.ts:46-49` @@ -379,7 +362,7 @@ export enum Cost { - **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. - **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. -### 20. `DataRefresh` — enum named after the noun, not the property +### 19. `DataRefresh` — enum named after the noun, not the property **Location:** `src/v1/model.ts:51-61` @@ -402,7 +385,7 @@ The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRe - **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. - **Rationale:** Self-documenting enum name; consistent value form. -### 21. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special +### 20. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special **Location:** `src/v1/model.ts:52-55` @@ -416,9 +399,9 @@ HOURLY = 'HOURLY', `NONE` reads as "no refresh"; `SECOND` reads as "every second"; `HOURLY` reads as "every hour". The first two follow noun-naming; the third follows adverb-naming. Mixing the two within the same enum produces inconsistency. - **Category:** 17 (inconsistent value form). - **Suggested name:** Pick one convention. If "every X" adverbs are used, change `SECOND` → `SECONDLY`, `MINUTE` → `MINUTELY`, `NONE` → unchanged. -- **Rationale:** See #20. +- **Rationale:** See #19. -### 22. `Category` — generic enum name with 22 values +### 21. `Category` — generic enum name with 22 values **Location:** `src/v1/model.ts:21-44` @@ -435,7 +418,7 @@ export enum Category { - **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 732). - **Rationale:** Cross-package collision avoidance and self-documentation. -### 23. `ListingDetail.size` — ambiguous unit +### 22. `ListingDetail.size` — ambiguous unit **Location:** `src/v1/model.ts:685-686` @@ -449,7 +432,7 @@ The JSDoc says "in GB", but the field name is just `size`. The wire field is `si - **Suggested name:** `sizeInGigabytes` or `sizeGb`. - **Rationale:** Numeric fields without unit suffix are a bug magnet. -### 24. `ListingDetail.cost` typed as `Cost` (enum), but doc says price +### 23. `ListingDetail.cost` typed as `Cost` (enum), but doc says price **Location:** `src/v1/model.ts:668-669, 673-674` @@ -468,7 +451,7 @@ Two related fields: `cost: Cost (= 'FREE' | 'PAID')` and `pricingModel: string` - **Suggested name:** Combine into one discriminated union: `pricing?: { $case: 'free' } | { $case: 'paid', model: string }`. - **Rationale:** Type-system can encode the relationship the prose tries to. -### 25. `ListingDetail.geographicalCoverage` — long camelCase +### 24. `ListingDetail.geographicalCoverage` — long camelCase **Location:** `src/v1/model.ts:666-667` @@ -482,7 +465,7 @@ geographicalCoverage?: string | undefined; - **Suggested name:** `geoRegion`, `regions`, or `coverage`. - **Rationale:** Shorter, matches sibling naming. -### 26. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number +### 25. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number **Location:** `src/v1/model.ts:679-682` @@ -498,7 +481,7 @@ Field names include "Date" but the type is `number` (Unix timestamp). A consumer - **Suggested name:** `collectionStartAt` / `collectionEndAt`, or `collectionPeriodStart` / `collectionPeriodEnd`. - **Rationale:** "Date" is ambiguous about underlying type; `At` is the existing in-file convention for Unix timestamps. -### 27. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming +### 26. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming **Location:** `src/v1/model.ts:675-678` @@ -514,7 +497,7 @@ Both are `DataRefreshInfo` (an interval), but one is named "frequency" and the o - **Suggested name:** Rename type → `TimeInterval`; keep the field-level distinction. - **Rationale:** Reuse a generic type name for a reusable type. -### 28. `ListingDetail.dataSource` — single-word vague field +### 27. `ListingDetail.dataSource` — single-word vague field **Location:** `src/v1/model.ts:683-684` @@ -528,7 +511,7 @@ dataSource?: string | undefined; - **Suggested name:** `dataSourceDescription`, `dataProvenance`, or `dataOriginNote`. - **Rationale:** Disambiguate from the more common DB-connection meaning of "data source". -### 29. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags +### 28. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags **Location:** `src/v1/model.ts:689-704` @@ -556,7 +539,7 @@ The enum constrains tag *names* to a small set. Values are free-form strings. So - **Suggested name:** `ListingTag.name` / `ListingTag.values`; rename type to clarify (e.g. `ListingAttribute`). - **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. -### 30. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology +### 29. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology **Location:** `src/v1/model.ts:742-747` @@ -570,9 +553,9 @@ export interface ListingTag { Inside `ListingTag`, what else could `tagName` and `tagValues` be? `name` and `values` carry the same information. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `name`, `values`. -- **Rationale:** See #15. +- **Rationale:** See #14. -### 31. `ContactInfo` — generic suffix on a single-purpose type +### 30. `ContactInfo` — generic suffix on a single-purpose type **Location:** `src/v1/model.ts:171-177` @@ -591,7 +574,7 @@ export interface ContactInfo { - **Suggested name:** `Contact` or `ConsumerContact`. - **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. -### 32. `RegionInfo` — `Info` suffix on a single-purpose type +### 31. `RegionInfo` — `Info` suffix on a single-purpose type **Location:** `src/v1/model.ts:791-794` @@ -602,12 +585,12 @@ export interface RegionInfo { } ``` -Same problem as #31. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. +Same problem as #30. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. - **Category:** 8 (redundant `Info` suffix), 19 (underspecified — no enum constraints). - **Suggested name:** `Region` (the cloud is implicitly part of the region in many SDKs) or `CloudRegion`. - **Rationale:** Avoid `*Info` suffix; consider richer typing. -### 33. `ShareInfo` — `Info` suffix on a sharing concept +### 32. `ShareInfo` — `Info` suffix on a sharing concept **Location:** `src/v1/model.ts:839-842` @@ -618,12 +601,12 @@ export interface ShareInfo { } ``` -Same problem as #31 and #32. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". +Same problem as #30 and #31. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". - **Category:** 8 (redundant `Info` suffix). - **Suggested name:** `Share`, `ListingShare`. -- **Rationale:** See #31. +- **Rationale:** See #30. -### 34. `ProviderInfo` — `Info` suffix on the canonical provider type +### 33. `ProviderInfo` — `Info` suffix on the canonical provider type **Location:** `src/v1/model.ts:772-789` @@ -637,12 +620,12 @@ export interface ProviderInfo { } ``` -Same problem as #31. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. +Same problem as #30. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent: the rest of the package uses `Provider` alone). - **Suggested name:** `Provider`. - **Rationale:** Consistency with method/request type names. -### 35. `DataRefreshInfo` — `Info` suffix on an interval type +### 34. `DataRefreshInfo` — `Info` suffix on an interval type **Location:** `src/v1/model.ts:256-259` @@ -653,12 +636,12 @@ export interface DataRefreshInfo { } ``` -Same problem as #31. Also note: the type is reused for `collectionGranularity` (#27), so the name `DataRefreshInfo` is wrong for half of its uses. +Same problem as #30. Also note: the type is reused for `collectionGranularity` (#26), so the name `DataRefreshInfo` is wrong for half of its uses. - **Category:** 8 (redundant `Info` suffix), 6 (misleading: name doesn't fit `collectionGranularity` use). -- **Suggested name:** `TimeInterval` (matches #27). -- **Rationale:** See #27. +- **Suggested name:** `TimeInterval` (matches #26). +- **Rationale:** See #26. -### 36. `FileInfo` — `Info` suffix on the canonical file type +### 35. `FileInfo` — `Info` suffix on the canonical file type **Location:** `src/v1/model.ts:330-343` @@ -670,12 +653,12 @@ export interface FileInfo { } ``` -Same problem as #31. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. +Same problem as #30. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent with siblings). - **Suggested name:** `File`. -- **Rationale:** See #34. +- **Rationale:** See #33. -### 37. `Listing.summary` / `Listing.detail` — opaque fields on the central type +### 36. `Listing.summary` / `Listing.detail` — opaque fields on the central type **Location:** `src/v1/model.ts:652-656` @@ -692,7 +675,7 @@ export interface Listing { - **Suggested name:** Flatten or rename `summary` → `metadata`, `detail` → `content`. - **Rationale:** See #6. -### 38. `ListingSummary.setting` — singular field name +### 37. `ListingSummary.setting` — singular field name **Location:** `src/v1/model.ts:725` @@ -708,7 +691,7 @@ export interface ListingSummary { - **Suggested name:** `settings: ListingSettings`. - **Rationale:** Plural matches the conventional naming for a settings bag. -### 39. `ListingSummary.providerRegion` — region of what? +### 38. `ListingSummary.providerRegion` — region of what? **Location:** `src/v1/model.ts:724` @@ -725,7 +708,7 @@ providerRegion?: RegionInfo | undefined; ## Low severity -### 40. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization +### 39. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization **Location:** `src/v1/model.ts:653, 663, 737` @@ -734,14 +717,14 @@ Mixed singular/plural id fields: - `ListingDetail.fileIds: string[]` — many file ids. - `ListingSummary.exchangeIds: string[]` — many exchange ids. - `ListingSummary.providerId: string` — single provider id. -- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #41). +- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #40). Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #41). +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #40). - **Suggested name:** Pick one — `*Id`/`*Ids` is standard. - **Rationale:** Observation; flagged for completeness. -### 41. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number +### 40. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number **Location:** `src/v1/model.ts:734-735` @@ -755,7 +738,7 @@ User ids are typed as `number`. JS `number` only safely represents integers up t - **Suggested name:** `createdById: string` or `bigint`. - **Rationale:** Lossy representation; consistency with other id fields (all `string`). -### 42. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` +### 41. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` **Location:** `src/v1/model.ts:137-140` @@ -771,7 +754,7 @@ Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal ty - **Suggested name:** Could be `'public' | 'private'` literal union. - **Rationale:** Observation. -### 43. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun +### 42. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun **Location:** `src/v1/model.ts:99-102` @@ -787,7 +770,7 @@ export enum ListingShareType { - **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). - **Rationale:** Internal consistency. -### 44. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values +### 43. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values **Location:** `src/v1/model.ts:118-121` @@ -803,7 +786,7 @@ Two adjective values. Fine. Flagged because the package also has `Personalizatio - **Suggested name:** No rename. - **Rationale:** Internal consistency check. -### 45. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located +### 44. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located **Location:** `src/v1/model.ts:776, 784` @@ -818,7 +801,7 @@ Same icon represented two ways — `iconFilePath` (a URL or storage path) and `i - **Suggested name:** No rename; flag for doc clarification. - **Rationale:** Observation. -### 46. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode +### 45. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode **Location:** `src/v1/model.ts:787-788` @@ -832,7 +815,7 @@ The `darkMode` prefix encodes a UI rendering mode in a server-side data type. Th - **Suggested name:** `iconDarkFileId` / `iconDarkFilePath` or just `darkIcon*`. - **Rationale:** Observation. -### 47. Method docstring inconsistency — `client.ts` +### 46. Method docstring inconsistency — `client.ts` **Location:** `src/v1/client.ts:235, 266, 297, 326, 380, 437, 491, 542, 600, 628, 656, 735, 763, 789, 849, 927, 952, 986, 1015, 1041, 1070, 1096, 1125, 1154, 1186, 1211, 1239, 1264, 1292, 1320, 1345, 1370, 1400, 1425, 1479, 1539, 1567, 1624, 1675, 1732, 1790, 1847, 1875, 1929, 1957, 1983, 2012, 2041, 2073, 2102` @@ -859,22 +842,22 @@ Inconsistent docstring style: ## Observations -### 48. v1-only audit +### 47. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 49. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` +### 48. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. - **Category:** 1 (vague), 15 (generic name). -### 50. `flattenQueryParams` — `src/v1/utils.ts:123` +### 49. `flattenQueryParams` — `src/v1/utils.ts:123` The helper is used by `client.ts` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. - **Category:** Observation. -### 51. `readAll` — `src/v1/utils.ts:40` +### 50. `readAll` — `src/v1/utils.ts:40` Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. - **Category:** 1 (vague), 14 (Go-style name). -### 52. `HttpCallOptions` — `src/v1/utils.ts:15` +### 51. `HttpCallOptions` — `src/v1/utils.ts:15` Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. - **Category:** 1 (vague suffix), 17 (inconsistent). diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 4cd3dc3e..34663b11 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,16 +3,16 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 24 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 8 | -| Low | 6 | -| Observation | 4 | +| Medium | 6 | +| Low | 5 | +| Observation | 3 | ## Summary table @@ -25,23 +25,19 @@ | 5 | High | `model.ts:117` | `PagerdutyConfig` (type) and `pagerduty` ($case) | 3 (acronym casing inconsistency) | | 6 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | | 7 | Medium | `model.ts:46`, `:50`, `:54`, `:87` etc. | `urlSet` / `usernameSet` / `passwordSet` / `appIdSet` / `authSecretSet` / `channelUrlSet` / `tenantIdSet` / `integrationKeySet` / `oauthTokenSet` / `channelIdSet` | 6 (misleading), 15 (generic field naming pattern) | -| 8 | Medium | `model.ts:23-28` / `:139-146` | `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` | 7 (overly verbose), 8 (redundant `Request` suffix conjoined with full noun phrase) | -| 9 | Medium | `model.ts:66-70` | `ListNotificationDestinationsResponse` | 7 (overly verbose), 8 (redundant `Response` suffix) | -| 10 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | -| 11 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | -| 12 | Medium | `model.ts:74`, `:108` | `id` (UUID) | 19 (underspecified ID) | -| 13 | Medium | `model.ts:117` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | -| 14 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | -| 15 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | -| 16 | Low | `client.ts:71`, `:100`, `:125`, `:150`, `:204` | `createNotificationDestination` / `deleteNotificationDestination` / `getNotificationDestination` / `listNotificationDestinations` / `updateNotificationDestination` | 7 (overly verbose method names) | -| 17 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | -| 18 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | -| 19 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | -| 20 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 21 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | -| 22 | Obs | `index.ts:5-23` | Re-exports the verbose names verbatim, no friendlier aliases | — | -| 23 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | -| 24 | Obs | `model.ts:47`, `:51` | `[Input-Only][Optional]` doc marker inconsistency | — | +| 8 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | +| 9 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | +| 10 | Medium | `model.ts:74`, `:108` | `id` (UUID) | 19 (underspecified ID) | +| 11 | Medium | `model.ts:117` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | +| 12 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | +| 13 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | +| 14 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | +| 15 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | +| 16 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | +| 17 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 18 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 19 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | +| 20 | Obs | `model.ts:47`, `:51` | `[Input-Only][Optional]` doc marker inconsistency | — | ## High severity @@ -157,40 +153,9 @@ 3. The paired fields are **modal** — on input you set `url`, on output you read `urlSet`. The type system has no way to express this; both fields are simultaneously optional, so a user could try to set `urlSet: true` on input and the server will silently ignore it. - **Category:** 6 (misleading — three-valued boolean), 15 (generic field-naming pattern losing meaning). - **Suggested name:** Rename the pattern to `hasUrl`, `hasUsername`, etc. (English-correct boolean predicates). Better: split the input and output types so input has `url` only and output has `hasUrl` only. Or merge into a union: `url?: { write: string } | { read: { isSet: boolean } }`. -- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 21) hint that the type was originally split in the API spec and was flattened for TS. +- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 18) hint that the type was originally split in the API spec and was flattened for TS. -### 8. `CreateNotificationDestinationRequest` / `UpdateNotificationDestinationRequest` — overly verbose — `src/v1/model.ts:23-28`, `:139-146` -- **Code:** - ```ts - export interface CreateNotificationDestinationRequest { - displayName?: string | undefined; - config?: Config | undefined; - } - export interface UpdateNotificationDestinationRequest { - id?: string | undefined; - displayName?: string | undefined; - config?: Config | undefined; - } - ``` -- **Why weird:** 39 and 40 character identifiers respectively. Inside the package, the verb is already redundant with the method name (`createNotificationDestination(req: CreateNotificationDestinationRequest)`) — the request type name repeats the verb the method also carries. Compare to leaner conventions: `Create(input: NotificationDestination)` or, in TS, just accepting the partial `NotificationDestination` shape and dropping the `Request` types. -- **Category:** 7 (overly verbose), 8 (redundant `Request` suffix conjoined with full noun phrase that is already specific). -- **Suggested name:** Shorter alternatives: `CreateInput`, `UpdateInput` (scoped to the package; relies on `import * as nd from '@databricks/sdk-notificationdestinations/v1'` for disambiguation). Or merge with the response: `accept Partial`. Or, if keeping verbose names, at least drop the `Request` suffix (already implied by being the input to a request). -- **Rationale:** Even in `alerts` (which is heavier), the create/update request types were criticised for this pattern. Worth normalising at the SDK level. - -### 9. `ListNotificationDestinationsResponse` — overly verbose response wrapper — `src/v1/model.ts:66-70` -- **Code:** - ```ts - export interface ListNotificationDestinationsResponse { - results?: ListNotificationDestinationsResult[] | undefined; - /** Page token for next of results. */ - nextPageToken?: string | undefined; - } - ``` -- **Why weird:** Two fields, 41-character type name. The JSDoc says "Page token for next of results" — broken English (should be "Page token for next page of results" or "Page token for the next set of results"). And see #11 for `results`. -- **Category:** 7 (verbose), 8 (`Response` suffix added on top of the verb-prefixed noun phrase). -- **Suggested name:** `ListPage` — a generic page wrapper used across the SDK. Or `NotificationDestinationPage`. - -### 10. `Client` — unprefixed class — `src/v1/client.ts:45` +### 8. `Client` — unprefixed class — `src/v1/client.ts:45` - **Code:** `export class Client { ... }` - **Why weird:** Every package in the SDK exports a class named `Client`. A user wiring up two packages (`notificationdestinations` + `alerts`, say) writes: ```ts @@ -202,7 +167,7 @@ - **Suggested name:** `NotificationDestinationsClient`, or expose only the namespace import (`import * as notificationDestinations from '@databricks/sdk-notificationdestinations/v1'`). - **Rationale:** Cross-SDK consistency, but every consumer pays the rename cost. Worth a generator-level fix. -### 11. `ListNotificationDestinationsResponse.results` — vague field name — `src/v1/model.ts:67` +### 9. `ListNotificationDestinationsResponse.results` — vague field name — `src/v1/model.ts:67` - **Code:** ```ts results?: ListNotificationDestinationsResult[] | undefined; @@ -211,7 +176,7 @@ - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `destinations` (drop the `notification` qualifier since the package context supplies it) or `items`. -### 12. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 74, 108, 141` +### 10. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 74, 108, 141` - **Code:** ```ts /** UUID identifying notification destination. */ @@ -222,7 +187,7 @@ - **Suggested name:** `destinationId` (within the package context the qualifier "notification" is implicit). Or `id` is acceptable if the type is always accessed as `destination.id`. - **Rationale:** Bare `id` is conventional and tolerated; the optionality is the real bug. Demoted to medium. -### 13. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:117-122` +### 11. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:117-122` - **Code:** ```ts export interface PagerdutyConfig { @@ -237,7 +202,7 @@ - **Suggested name:** see #7. - **Rationale:** Listed separately because PagerDuty is the simplest case (one secret field) and best illustrates the pattern. -### 14. `destinationType` field — type-suffix tautology — `src/v1/model.ts:78`, `:112` +### 12. `destinationType` field — type-suffix tautology — `src/v1/model.ts:78`, `:112` - **Code:** ```ts destinationType?: DestinationType | undefined; @@ -248,26 +213,12 @@ ## Low severity -### 15. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` +### 13. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` - See #3 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. - **Category:** 9 (qualifier mismatch). - **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #3 for the rationale. -### 16. `createNotificationDestination` / etc. — overly verbose method names — `src/v1/client.ts:71, 100, 125, 150, 204` -- **Code:** - ```ts - async createNotificationDestination(...) - async deleteNotificationDestination(...) - async getNotificationDestination(...) - async listNotificationDestinations(...) - async updateNotificationDestination(...) - ``` -- **Why weird:** Method names repeat the package name (`@databricks/sdk-notificationdestinations`) and the request-type name. A user writes `client.createNotificationDestination(...)` — 30 characters before the args. Shorter conventions: `client.create(...)`, `client.list(...)`, `client.get(...)` — relying on the package import to provide context. -- **Category:** 7 (overly verbose). -- **Suggested name:** Drop the suffix: `create`, `delete`, `get`, `list`, `update`. The class name (`Client` or `NotificationDestinationsClient`) supplies the domain context. -- **Rationale:** Conventions differ across SDKs. AWS uses verbose method names; GCP / Azure use shorter. Demoted to low because the existing convention is consistent across the SDK and changing it is disruptive. Flagging for completeness. - -### 17. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` +### 14. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` - **Code:** ```ts // Package identity segment for this client to be used in the User-Agent header. @@ -281,7 +232,7 @@ - **Suggested name:** `USER_AGENT_PACKAGE_INFO` or `PACKAGE_USER_AGENT`. - **Rationale:** Cross-package — same finding appears in every audited file. -### 18. `HttpCallOptions` — `src/v1/utils.ts:15-19` +### 15. `HttpCallOptions` — `src/v1/utils.ts:15-19` - **Code:** ```ts export interface HttpCallOptions { @@ -294,13 +245,13 @@ - **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). - **Suggested name:** `HttpCallContext` (it is an internal context bag, not user-tunable options). -### 19. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` +### 16. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` - **Code:** lines 26-38 and 65-94. - **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + ApiError check. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). -### 20. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` +### 17. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -308,28 +259,16 @@ ## Observations -### 21. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +### 18. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). - **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. -### 22. `index.ts` re-exports verbose names verbatim — `src/v1/index.ts:5-23` -The barrel re-exports every type with its long generated name. An opportunity to expose friendlier aliases: -```ts -export type { - NotificationDestination as Destination, - CreateNotificationDestinationRequest as CreateRequest, - ... -} from './model'; -``` -Not done. So consumers always work with the verbose names. The 1:1 port philosophy probably prohibits this, but flagging as an observation — the barrel could improve ergonomics without removing the underlying names. -- **Category:** 7 (verbose), Observation. - -### 23. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows +### 19. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. -### 24. JSDoc inconsistency in `[Input-Only][Optional]` markers +### 20. JSDoc inconsistency in `[Input-Only][Optional]` markers The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the marker `[Input-Only][Optional]` — concatenating two brackets — while every other field uses single-bracket markers. The `[Optional]` is also redundant because the TS type already shows `?: undefined`. Minor doc inconsistency. ## Domain glossary diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index 48678f43..94c8c3fb 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -14,11 +14,11 @@ | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------------------- | -| High | 17 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions, plural `Pipelines` prefix. | +| High | 16 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | | Medium | 19 | Vague names, acronym casing, generic IDs, misleading enum values. | | Low | 20 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 8 | Patterns spanning the whole file (branding history, plural/singular split, proto-architectural leakage). | -| **Total** | **64** | | +| Observations | 7 | Patterns spanning the whole file (branding history, proto-architectural leakage). | +| **Total** | **62** | | Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. @@ -44,85 +44,79 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Suggestion:** Rename `start(req: StartUpdateRequest)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. - **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipelineRequest)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. -### H4. `Pipelines*` prefix (plural) on a single-pipeline package — proto-package leakage -- **Locations:** `model.ts:117` (`PipelinesAwsAvailability`), `model.ts:130` (`PipelinesAzureAvailability`), `model.ts:146` (`PipelinesEbsVolumeType`), `model.ts:154` (`PipelinesGcpAvailability`), `model.ts:1897` (`PipelinesAutoScale`), `model.ts:1916` (`PipelinesAwsAttributes`), `model.ts:2005` (`PipelinesAzureAttributes`), `model.ts:2032` (`PipelinesClusterLogConf`), `model.ts:2046` (`PipelinesDbfsStorageInfo`), `model.ts:2055` (`PipelinesEnvironment`), `model.ts:2078` (`PipelinesGcpAttributes`), `model.ts:2119` (`PipelinesInitScriptInfo`), `model.ts:2147` (`PipelinesJobRunAs`), `model.ts:2162` (`PipelinesMavenLibrary`), `model.ts:2180` (`PipelinesS3StorageInfo`). -- **Category:** 8 (redundant suffix/prefix), 9 (singular/plural mismatch), 14 (Go/Java-style names). -- **Suggestion:** Drop the `Pipelines` prefix. The package itself is `@databricks/sdk-pipelines` and the import disambiguates from `@databricks/sdk-clusters`. The types become `AwsAvailability`, `AwsAttributes`, `AutoScale`, `ClusterLogConf`, `DbfsStorageInfo`, `Environment`, `GcpAttributes`, `InitScriptInfo`, `JobRunAs`, `MavenLibrary`, `S3StorageInfo`. If global collision is feared, use `PipelineCluster`-style singular: `PipelineEnvironment`, `PipelineAwsAttributes`, etc. -- **Rationale:** The proto package is `pipelines.proto`, so the generator prefixed every type with `Pipelines`. A consumer types `new PipelinesJobRunAs(...)` and the plural reads as "RunAs for many jobs in many pipelines" — neither is true. `PipelineCluster` (singular, `model.ts:1573`) shows the convention the package would have if generated consistently. - -### H5. `PipelinesJobRunAs` references `Job` from a `Pipelines` package +### H4. `PipelinesJobRunAs` references `Job` from a `Pipelines` package - **Location:** `model.ts:2147`. - **Category:** 6 (misleading — `Job` is a separate Databricks product), 14 (Go-style). - **Suggestion:** Rename to `RunAs` or `PipelineRunAs`. Drop the `Job` token entirely — this type is not used by `@databricks/sdk-jobs`. - **Rationale:** `Job` belongs to the `jobs` API. A user reading `runAs: PipelinesJobRunAs` cannot tell whether the pipeline is associated with a job or just borrows the shape. The proto comment ("Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as.") confirms this is a pipeline-only concept. -### H6. `Pipeline` is never used as a type name — the central domain entity is missing +### H5. `Pipeline` is never used as a type name — the central domain entity is missing - **Locations:** N/A — the package has `PipelineSpec`, `PipelineStateInfo`, `GetPipelineRequest_Response`, `BaseJob`-style scattering, but no plain `Pipeline` type. - **Category:** 1 (vague/generic alternative missing), 6 (misleading). - **Suggestion:** Add an exported `Pipeline` type that consolidates the runtime view (`GetPipelineRequest_Response` is the closest). Alternatively rename `GetPipelineRequest_Response` → `Pipeline`. Keep `PipelineSpec` as the write-form (the "settings" sub-object). - **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipelineRequest_Response`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. -### H7. `EditPipelineRequest` / `CreatePipelineRequest` / `ClonePipelineRequest` / `PipelineSpec` all duplicate 25 of the same fields +### H6. `EditPipelineRequest` / `CreatePipelineRequest` / `ClonePipelineRequest` / `PipelineSpec` all duplicate 25 of the same fields - **Locations:** `model.ts:336` (`ClonePipelineRequest`), `model.ts:479` (`CreatePipelineRequest`), `model.ts:622` (`EditPipelineRequest`), `model.ts:1783` (`PipelineSpec`). - **Category:** 12 (duplicate concepts). - **Suggestion:** Extract `PipelineSpec` as the shared base and have `CreatePipelineRequest`, `EditPipelineRequest`, `ClonePipelineRequest` use TS intersection: `type CreatePipelineRequest = PipelineSpec & {allowDuplicateNames?: boolean; dryRun?: boolean; ...}`. - **Rationale:** Each of the four interfaces redeclares `id`, `name`, `storage`, `configuration`, `clusters`, `libraries`, `ingestionDefinition`, `gatewayDefinition`, `trigger`, `target`, `schema`, `filters`, `continuous`, `development`, `photon`, `edition`, `channel`, `catalog`, `notifications`, `serverless`, `deployment`, `restartWindow`, `budgetPolicyId`, `tags`, `eventLog`, `rootPath`, `environment`, `usagePolicyId`. Drift between the four is silent. -### H8. `Update` field names on `Origin` reference the "pipeline run" sense of Update — silent overloading +### H7. `Update` field names on `Origin` reference the "pipeline run" sense of Update — silent overloading - **Locations:** `model.ts:1476` (`Origin.updateId`), `model.ts:2504` (`UpdateInfo.updateId`), `model.ts:2545` (`UpdateStateInfo.updateId`). - **Category:** 19 (underspecified IDs), 1 (vague). - **Suggestion:** Rename `updateId` → `runId` (paired with H1). Document that the wire JSON key is `update_id` for compatibility. - **Rationale:** A field named `updateId` on `Origin` (event source) leaves "update of what?" unanswered. Users wonder if it refers to the last-modification timestamp. -### H9. `client.events()` method name is too generic +### H8. `client.events()` method name is too generic - **Location:** `client.ts:272`. - **Category:** 1 (vague), 17 (inconsistent action verbs — should be `listEvents`). - **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. - **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). -### H10. `client.list()` — too generic for the package's bare-`list` slot +### H9. `client.list()` — too generic for the package's bare-`list` slot - **Location:** `client.ts:385`. - **Category:** 1 (vague), 17 (inconsistent verbs). - **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelinesRequest` and to disambiguate from `listUpdates`/`listEvents`. - **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelinesRequest`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. -### H11. `ScdType_ScdType` enum uses the cryptic acronym SCD +### H10. `ScdType_ScdType` enum uses the cryptic acronym SCD - **Locations:** `model.ts:268` (`ScdType_ScdType`), `index.ts:27`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). - **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). -### H12. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" +### H11. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" - **Location:** `model.ts:262`. - **Category:** 6 (misleading — references method `run` that does not exist; the method is `start`). - **Suggestion:** Fix JSDoc to reference `start()`. After H3, both will line up at `run()`. - **Rationale:** Currently the user reads "call `run`" and finds no `run()` method on `Client`. -### H13. `client.delete()` collides with JS `delete` keyword +### H12. `client.delete()` collides with JS `delete` keyword - **Location:** `client.ts:206`. - **Category:** 10 (reserved-word collision). - **Suggestion:** Rename to `deletePipeline()`. Alternatively, `remove()`. - **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. -### H14. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +### H13. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity - **Location:** `model.ts:56`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. -### H15. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" +### H14. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" - **Location:** `model.ts:187` ("Update is waiting for previous update to finish."). - **Category:** 6 (misleading). - **Suggestion:** Doc rewrite (English) after H1: "Run is waiting for previous run to finish." - **Rationale:** Same as H1 — once `Update` is renamed to `Run`, every JSDoc that mentions "update" in this enum needs to follow. -### H16. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +### H15. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural - **Locations:** `model.ts:1431`, plus all `notifications?: Notifications[]` field declarations. - **Category:** 9 (singular/plural mismatch). - **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. - **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. -### H17. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) +### H16. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) - **Locations:** `model.ts:457-477` (interface `ConnectorOptions`), `model.ts:1056`, `model.ts:1078`. - **Category:** 20 (type-suffix tautology), 12 (duplicate naming). - **Suggestion:** Rename the outer interface to `ConnectorOptions` and the inner discriminator to `options` (or `payload`). Then `connectorOptions: {payload: {...}}` reads cleanly. @@ -348,35 +342,32 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Locations:** `model.ts:47` (`DAB` in DeploymentKind comment), `model.ts:379` (`SDP` in `channel` JSDoc), `model.ts:923` (`Spark Declarative Pipelines` in JSDoc), `model.ts:932` (`Lakeflow Connect`), `model.ts:2052` (`SDP's environment`), `client.ts:384` (`Spark Declarative Pipelines`). - **Suggestion:** Settle on one product name in JSDoc. The TS types should be backwards-compatible (no rename) but the docstrings should agree. -### O2. `Pipelines*` (plural) vs `Pipeline*` (singular) split: 15 plural-prefixed vs 15 singular-prefixed types -- **Cross-reference:** H4. - -### O3. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested +### O2. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested - **Locations:** `IngestionPipelineDefinition.connectorType`, `IngestionPipelineDefinition.sourceConfigurations[].catalog.options`, `IngestionPipelineDefinition_SchemaSpec.connectorOptions`, `IngestionPipelineDefinition_TableSpec.connectorOptions`. - **Suggestion:** Document the resolution order between schema-level and table-level options. JSDoc currently fragments the rules across multiple types. -### O4. JSDoc uses `` placeholder — leak from the Go SDK's template substitution +### O3. JSDoc uses `` placeholder — leak from the Go SDK's template substitution - **Search:** `` appears 18 times in `model.ts`. - **Suggestion:** Replace with literal "Databricks" before TS compilation. -### O5. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` +### O4. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` - **Location:** `model.ts:1443`. - **Category:** 16. - **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. -### O6. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side +### O5. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side - **Locations:** `model.ts:1513-1566`. - **Category:** Generator artifact / Go-SDK fidelity issue. - **Suggestion:** Mark deprecated fields with `@deprecated` JSDoc tag (currently only mentioned in plain text). -### O7. `ConnectorOptions` JSDoc opens with "Wrapper message for source-specific options" — proto-architectural terminology leak +### O6. `ConnectorOptions` JSDoc opens with "Wrapper message for source-specific options" — proto-architectural terminology leak - **Location:** `model.ts:456`. - **Why:** "Wrapper message" is a protobuf concept (the proto2/proto3 well-known wrapper types: `BoolValue`, `StringValue`, etc., plus the generic "wrapper message" pattern used to box discriminated unions). It is visible in user-facing JSDoc on a public interface. - **Category:** Generator artifact leakage / proto-architectural leak. - **Suggested:** Rewrite JSDoc as "Source-specific options for ingestion connectors. Exactly one option must be specified for the connector type." Drop "Wrapper message". - **Rationale:** TypeScript developers do not know what a "wrapper message" is — the term reveals the proto IDL underneath. The shape is just a discriminated union over connector option types; describe it in TS terms. -### O8. `Internal` proto-field tag leaks into JSDoc on two public fields +### O7. `Internal` proto-field tag leaks into JSDoc on two public fields - **Locations:** `model.ts:926` (`IngestionGatewayPipelineDefinition.connectionParameters` — "Optional, Internal. Parameters required to establish an initial connection with the source."), `model.ts:1262` (`KafkaOptions.maxOffsetsPerTrigger` — "Internal option to control the maximum number of offsets to process per trigger."). - **Why:** `Internal` is a proto-level annotation (`google.api.field_visibility = INTERNAL` or similar) indicating the field is not part of the public API surface. If these fields are truly internal, they should be stripped from the public SDK at generation time; if they are public, the "Internal" label should not appear in user-visible documentation. - **Category:** Generator artifact leakage / proto-architectural leak. @@ -391,11 +382,11 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - #H7 `EditPipeline`/`CreatePipeline`/`ClonePipeline` (originally cited at `model.ts:508`/`672`/`830`): Renamed to `*Request` variants. References updated in active H7. - #H8 `Origin.graphId` (originally cited at `model.ts:1816`): Fixed in regeneration on 2026-05-20 — `graphId` field removed from `Origin`. - #H12 `StorageMode` enum duplicate of `ScdType` (originally cited at `model.ts:263`): Fixed in regeneration on 2026-05-20 — `StorageMode` enum removed; only `ScdType_ScdType` remains. -- #H14 `client.delete()` reserved-word collision (originally cited at `client.ts:204`): Line updated; still present as H13. Sibling reference to `restorePipeline()` removed since the restore endpoint no longer exists. +- #H14 `client.delete()` reserved-word collision (originally cited at `client.ts:204`): Line updated; still present as H12. Sibling reference to `restorePipeline()` removed since the restore endpoint no longer exists. - #H15 `client.restorePipeline()` (originally cited at `client.ts:475`): Fixed in regeneration on 2026-05-20 — `restorePipeline()` method and `RestorePipelineRequest` removed entirely from the package. - #H16 `RestorePipelineRequest` suffix asymmetry (originally cited at `model.ts:2618`): Fixed in regeneration on 2026-05-20 — `Request` suffix added uniformly to every request DTO (`DeletePipelineRequest`, `GetPipelineRequest`, `ClonePipelineRequest`, `EditPipelineRequest`, `CreatePipelineRequest`, `StartUpdateRequest`, `StopPipelineRequest`, `ApplyEnvironmentRequest`, etc.); `RestorePipelineRequest` itself was deleted along with the restore endpoint. - #H19 `StartUpdate.fullRefresh`/`refreshSelection`/`fullRefreshSelection`/`resetCheckpointSelection`/`refreshFlowSelection` (originally cited at `model.ts:2738-2780`): Fixed in regeneration on 2026-05-20 — `resetCheckpointSelection` and `refreshFlowSelection` fields removed; remaining three (`fullRefresh`, `refreshSelection`, `fullRefreshSelection`) reduced to the documented pattern. -- #H22 `PipelinesEnvironment` vs `IngestionPipelineDefinition` prefix split (originally cited at `model.ts:2382`/`1173`): Fixed in regeneration on 2026-05-20 — the underlying `Pipelines*` plural prefix issue is now consolidated under H4 alongside other plural-prefixed types; no longer a standalone H finding. +- #H22 `PipelinesEnvironment` vs `IngestionPipelineDefinition` prefix split (originally cited at `model.ts:2382`/`1173`): Pruned per Workflow B — type-name prefix repeating the package name (`Pipelines*`) is treated as a generator-pattern issue, not fixed individually. - #M11 `GoogleDriveOptions_GoogleDriveIngestionScope` (originally cited at `model.ts:372-379`): Fixed in regeneration on 2026-05-20 — enum removed; only `GoogleDriveOptions_GoogleDriveEntityType` remains. - #M13 `PeriodicTrigger_TimeUnit` (originally cited at `model.ts:384`): Fixed in regeneration on 2026-05-20 — enum and parent type `PeriodicTrigger` removed. - #M31 `IngestionSourceType.COMMUNITY` (originally cited at `model.ts:88-92`): Fixed in regeneration on 2026-05-20 — `COMMUNITY` value removed from `IngestionSourceType`. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index 816bf63f..add0e72e 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 35 (last rescanned 2026-05-22) +**Total weird names flagged:** 33 (last rescanned 2026-05-22) ## Summary table @@ -15,35 +15,33 @@ | 4 | High | package vs siblings | `queries` package vs `queryexecution`, `queryhistory`, `modelservingquery` | Duplicate concept across 4 packages, no shared prefix | | 5 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashQuery` | Inconsistent verb — most of the SDK uses `delete`; only the SQL surface uses `trash` | | 6 | High | `model.ts` enum names | `LifecycleState`, `RunAsMode`, `DatePrecision` | Missing domain prefix (no `Query*`) — collide with identical enums in `alerts` package | -| 7 | High | `model.ts` field | `Query.queryText` | Type-suffix tautology (`Query.queryText`) | -| 8 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | -| 9 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | -| 10 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | -| 11 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | -| 12 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | -| 13 | High | `model.ts` field | `Query.queryText` JSDoc says "Text of the query to be run" on a type already called `Query` | Type-suffix tautology + redundant doc | -| 14 | High | `model.ts` interface | `Empty` | Proto architectural leak — `google.protobuf.Empty` surfaced as a TS export | -| 15 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | -| 16 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | -| 17 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | -| 18 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 19 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | -| 20 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | -| 21 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | -| 22 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | -| 23 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | -| 24 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | -| 25 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | -| 26 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | -| 27 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | -| 28 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | -| 29 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | -| 30 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | -| 31 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | -| 32 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | -| 33 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | -| 34 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | -| 35 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | +| 7 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | +| 8 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | +| 9 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | +| 10 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | +| 11 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | +| 12 | High | `model.ts` interface | `Empty` | Proto architectural leak — `google.protobuf.Empty` surfaced as a TS export | +| 13 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 14 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 15 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 16 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 17 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | +| 18 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | +| 19 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | +| 20 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | +| 21 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 22 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | +| 23 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | +| 24 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | +| 25 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | +| 26 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | +| 27 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | +| 28 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | +| 29 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | +| 30 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | +| 31 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | +| 32 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | +| 33 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | ## High severity @@ -128,22 +126,7 @@ export enum RunAsMode { ... } Three top-level enums in a domain-specific package, none prefixed with `Query*`. The same package also indirectly uses an identical `LifecycleState` concept that exists with the same values (`ACTIVE`/`TRASHED`) in `alerts` v1; when a user imports both they collide by name. `QueryLifecycleState`, `QueryRunAsMode`, `QueryDatePrecision` (or simply re-using shared `LifecycleState` from a common package) would address this; the current state is the worst of both worlds. -### 7. `Query.queryText` — type-suffix tautology - -**Location:** `src/v1/model.ts:234-235`, `model.ts:175-176`, `model.ts:235` - -```ts -export interface Query { - ... - /** Text of the query to be run. */ - queryText?: string | undefined; - ... -} -``` - -A field on `Query` named `queryText` — the access pattern is `q.queryText` where the `q` already implies "query." Inside an `Alert`, `queryText` is meaningful (it disambiguates from `alertText`). Inside `Query`, the `query` prefix is redundant. `text`, `sql`, or `statement` would suffice. - -### 8. `QueryParameter` vs sibling value types — inconsistent prefixing +### 7. `QueryParameter` vs sibling value types — inconsistent prefixing **Location:** `src/v1/model.ts:268-306`, `308-310`, `219-221`, `140-147` @@ -159,7 +142,7 @@ export interface QueryBackedValue { ... } // prefixed Some value-type wrappers are prefixed (`Query*`), others are not. The choice appears to be based on whether the type "feels generic" — but `EnumValue`, `DateValue`, `DateRange` are arguably even more generic than `QueryParameter`. The package picks `QueryParameter` and `QueryBackedValue` for prefixing, while leaving `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRangeValue` unprefixed. Result: importing this package brings ambient types like `EnumValue` and `TextValue` into the user's scope. -### 9. `QueryBackedValue` — misleading +### 8. `QueryBackedValue` — misleading **Location:** `src/v1/model.ts:259-266` @@ -176,7 +159,7 @@ export interface QueryBackedValue { The name reads as "a value that is backed by a query" — implying the value itself comes from query state. The actual semantics, per JSDoc, is: a dropdown widget whose options are populated by running another saved query. `QuerySourcedDropdownParameter`, `QueryBackedDropdown`, or `DropdownFromQuery` would describe the actual concept. As written, the name is at the same abstraction level as `QueryBackedView` or `QueryBackedTable` — neither of which describes what this is. -### 10. `QueryParameter.parameterValue` (oneof key) — type-suffix tautology +### 9. `QueryParameter.parameterValue` (oneof key) — type-suffix tautology **Location:** `src/v1/model.ts:268-306` @@ -197,7 +180,7 @@ export interface QueryParameter { `QueryParameter.parameterValue` repeats "parameter" — access pattern `p.parameterValue` where `p` is already `QueryParameter`. The plain `value` would suffice (mirroring `AlertOperand.operand` from the alerts audit — same anti-pattern, opposite name). -### 11. `EnumValue` — vague/generic top-level name +### 10. `EnumValue` — vague/generic top-level name **Location:** `src/v1/model.ts:140-147` @@ -214,7 +197,7 @@ export interface EnumValue { `EnumValue` exported at the package root. `enum` is a TypeScript keyword and a generic concept; the type is in fact a *dropdown* parameter source (a list of valid options + the selected subset). `DropdownParameter`, `EnumParameter`, or `QueryEnumParameter` would name the actual concept. -### 12. `QueryParameter.title` vs `.name` — misleading pair +### 11. `QueryParameter.title` vs `.name` — misleading pair **Location:** `src/v1/model.ts:268-272` @@ -230,22 +213,7 @@ export interface QueryParameter { Reading the field names alone, `name` is the identifier and `title` is a richer/longer display string. The JSDoc inverts this: `name` is the literal `{{marker}}` text that appears in the SQL, and `title` is the human-readable widget label. The conventional pairing in this codebase (and most others) is `(name, displayName)`. Here it is `(name, title)` *and* `name` plays the role most SDK shapes give to `key`/`marker`/`identifier` and `title` plays the role of `displayName`. A reader has to consult JSDoc to tell which is which. -### 13. `Query.queryText` JSDoc — "Text of the query to be run" on a type already called `Query` - -**Location:** `src/v1/model.ts:68-69`, `174-175`, `234-235`, `335-336` - -```ts -export interface Query { - ... - /** Text of the query to be run. */ - queryText?: string | undefined; - ... -} -``` - -Both the field name and the JSDoc embed the word "query" on a type called `Query`. The field exists on four near-identical interfaces (see #2), so the redundancy multiplies. The same field is the *only* part of `Query` that is actually a SQL statement — pulling it up as `Query.text` or `Query.sql` would simplify both name and doc. - -### 14. `Empty` — proto architectural leak +### 12. `Empty` — proto architectural leak **Location:** `src/v1/model.ts:133-138` @@ -258,7 +226,7 @@ Both the field name and the JSDoc embed the word "query" on a type called `Query export interface Empty {} ``` -**Why:** Proto/RPC architectural leak — `google.protobuf.Empty` is a wire-format construct used by code generators to express "no body." The JSDoc explicitly admits this ("similar to google.protobuf.Empty"). Exporting it as a public TS interface forces every `Promise` return type (e.g. `trashQuery`, see #15) to surface the proto abstraction to callers. +**Why:** Proto/RPC architectural leak — `google.protobuf.Empty` is a wire-format construct used by code generators to express "no body." The JSDoc explicitly admits this ("similar to google.protobuf.Empty"). Exporting it as a public TS interface forces every `Promise` return type (e.g. `trashQuery`, see #13) to surface the proto abstraction to callers. **Category:** Proto architectural leak. @@ -268,7 +236,7 @@ export interface Empty {} ## Medium severity -### 15. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) +### 13. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) **Location:** `src/v1/client.ts:228-250` @@ -282,7 +250,7 @@ async trashQuery( The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 16. `TrashQueryRequest` — same as #15, in the type layer +### 14. `TrashQueryRequest` — same as #13, in the type layer **Location:** `src/v1/model.ts:312-314` @@ -294,7 +262,7 @@ export interface TrashQueryRequest { Same verb inconsistency at the type layer. Carries only `id`. -### 17. `listVisualizationsForQuery` — overly verbose +### 15. `listVisualizationsForQuery` — overly verbose **Location:** `src/v1/client.ts:174-208` @@ -307,7 +275,7 @@ async listVisualizationsForQuery( `For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. -### 18. `Visualization` — vague/generic top-level name +### 16. `Visualization` — vague/generic top-level name **Location:** `src/v1/model.ts:360-377` @@ -317,7 +285,7 @@ export interface Visualization { ... } `Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. -### 19. `Query.warehouseId` — underspecified ID +### 17. `Query.warehouseId` — underspecified ID **Location:** `src/v1/model.ts:66-67`, `172-173`, `232-233`, `333-334` @@ -328,7 +296,7 @@ warehouseId?: string | undefined; The JSDoc says "SQL warehouse"; the field says `warehouseId`. Databricks has data warehouses, Lakehouse, SQL warehouses, etc. `sqlWarehouseId` would self-document. -### 20. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar +### 18. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar **Location:** `src/v1/model.ts:64-65`, `74-75` @@ -342,7 +310,7 @@ lastModifierUserName?: string | undefined; `owner` is a noun. `lastModifier` is an agent noun constructed from the verb "modify." The pairing is mismatched — either both should be agent nouns (`ownerUserName`, `lastModifierUserName`) or both should be participial (`ownedBy`, `lastModifiedBy`). The Go convention is the former; idiomatic TS leans toward the latter. Also note the JSDoc inconsistency: "the user that owns" vs "the user who last saved" — different relative pronouns. -### 21. `Query.lastModifierUserName` — overly verbose +### 19. `Query.lastModifierUserName` — overly verbose **Location:** `src/v1/model.ts:74-75` @@ -352,13 +320,13 @@ lastModifierUserName?: string | undefined; 21 characters for what is, semantically, "last-modified-by." `lastModifiedBy` is 14 characters and more natural English. -### 22. `LifecycleState.TRASHED` — verb-tense inconsistency +### 20. `LifecycleState.TRASHED` — verb-tense inconsistency **Location:** `src/v1/model.ts:14-17` The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). -### 23. `RunAsMode` — verb-as-noun, filler `Mode` +### 21. `RunAsMode` — verb-as-noun, filler `Mode` **Location:** `src/v1/model.ts:19-22` @@ -371,7 +339,7 @@ export enum RunAsMode { `RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. -### 24. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... +### 22. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... **Location:** `src/v1/model.ts:25-42` @@ -389,7 +357,7 @@ LAST_12_MONTHS = 'LAST_12_MONTHS', The user gets 16 hard-coded time windows. If they want "last 45 days," there is no value. A `{ unit: 'DAY' | 'HOUR' | ...; n: number }` shape would express the same thing without the enum-value explosion. (Acknowledged that the underlying API likely accepts only these buckets — but the API design itself is the smell.) -### 25. `Query.applyAutoLimit` — misleading verb predicate +### 23. `Query.applyAutoLimit` — misleading verb predicate **Location:** `src/v1/model.ts:85-87` @@ -400,7 +368,7 @@ applyAutoLimit?: boolean | undefined; The name reads as an imperative action ("apply the auto limit!") rather than a flag. `autoLimit` (boolean) or `autoLimitRows` (number) would parse more naturally as state. The "1000" rule is in the JSDoc, not the type — `autoLimit: number` with the convention "1000 if true, 0 if disabled" would surface the magic number. -### 26. `Query.runAsMode` — type-suffix tautology +### 24. `Query.runAsMode` — type-suffix tautology **Location:** `src/v1/model.ts:70-71` @@ -411,7 +379,7 @@ runAsMode?: RunAsMode | undefined; Field of type `RunAsMode` named `runAsMode`. `runAs` would suffice (the type already encodes "mode"). -### 27. `Query.parentPath` — underspecified +### 25. `Query.parentPath` — underspecified **Location:** `src/v1/model.ts:76-77` @@ -422,7 +390,7 @@ parentPath?: string | undefined; "Parent" of what? The JSDoc clarifies it is the workspace-folder path. `workspaceFolderPath` would self-document. `parentPath` reads like a filesystem path or a Git ref to first-time readers. (The same field appears in `alerts` — flagged there too.) -### 28. `MultiValuesOptions` — singular/plural mismatch +### 26. `MultiValuesOptions` — singular/plural mismatch **Location:** `src/v1/model.ts:210-217` @@ -439,13 +407,13 @@ export interface MultiValuesOptions { `MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). -### 29. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context +### 27. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context **Location:** `src/v1/model.ts:210-217` `prefix`, `separator`, `suffix` are completely generic outside the surrounding type. The JSDoc says "Character that prefixes each selected parameter value" — they are not characters, they are arbitrary strings (typed `string`). `valuePrefix`, `valueSeparator`, `valueSuffix` would be self-documenting and the type-level `MultiValuesOptions` could drop the leading "Multi-Values" altogether. -### 30. `Visualization.type` — reserved-word collision +### 28. `Visualization.type` — reserved-word collision **Location:** `src/v1/model.ts:365-366` @@ -456,7 +424,7 @@ type?: string | undefined; `type` is a TS keyword (used in `type Foo = …`) and a generic field name. The JSDoc admits it is "counter, table, funnel, and so on" — i.e., an open-ended string enum (no domain enum is defined). `visualizationType` or `kind` would avoid the keyword issue. -### 31. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading +### 29. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading **Location:** `src/v1/model.ts:371-374` @@ -469,7 +437,7 @@ serializedOptions?: string | undefined; Field names imply "the data, in serialized form." JSDoc admits the format is undocumented and the field should not be modified. If users are not supposed to construct these, they should not be on a public type (or they should be typed `Readonly` with a clear name like `internalQueryPlan`/`opaqueOptions`). -### 32. `DateRangeValue.startDayOfWeek` — underspecified type +### 30. `DateRangeValue.startDayOfWeek` — underspecified type **Location:** `src/v1/model.ts:113` @@ -481,19 +449,19 @@ startDayOfWeek?: number | undefined; ## Low severity -### 33. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency +### 31. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency **Location:** `src/v1/model.ts:224-225`, `361-362`, `262-263` Top-level types use bare `id`; cross-referencing types use `queryId`. `Query.queryId` would be consistent with `Visualization.queryId` and `QueryBackedValue.queryId`. Currently `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` means there are two conventions side-by-side. -### 34. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination +### 32. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination **Location:** `src/v1/model.ts:153-156`, `158-161` Standard Google AIP-158 names. Flagged for completeness; no action recommended. -### 35. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. +### 33. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. **Location:** `src/v1/model.ts:292`, `297` diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index 4b188652..dd35cde9 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,13 +3,13 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 44 +**Total weird names flagged:** 43 ## Summary | Severity | Count | | --- | --- | | High | 3 | -| Medium | 20 | +| Medium | 19 | | Low | 21 | | Observation | 3 | @@ -83,203 +83,197 @@ - **Suggested name:** No rename. Add `@deprecated` JSDoc on each so IDEs show the strikethrough and the doc surfaces in tooltips. - **Rationale:** TypeScript honors `@deprecated` in completions; the current comment is informational only. -### 12. `QueryStatementType` — verbose discriminator — `src/v1/model.ts:29` -- **Why weird:** Type name pairs the resource word (`QueryStatement`) with the discriminator suffix (`Type`). Three nouns stack: a query has a *statement* which has a *type*. The actual values are SQL keywords (`SELECT`, `INSERT`, ...), which are statement *kinds*, not types in the TS sense. Compare `Aggregation` in `alerts/v2`, which uses a single domain noun. -- **Category:** 8, 7, 20 (redundant suffix; verbose; type-suffix tautology) -- **Suggested name:** `StatementKind`. (`Type` is reserved by TypeScript's own `type` keyword for type aliases, so `Kind` is conventional in enums representing categories of a thing.) -- **Rationale:** Disambiguates from TS's `type` and shortens the name. - -### 13. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:195,197` +### 12. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:195,197` - **Why weird:** Two `*End*Ms` fields next to each other. The doc comments are: `The time execution of the query ended.` (executionEndTimeMs) and `The time the query ended.` (queryEndTimeMs). Are these different? When? The metrics type later splits time into `compilationTimeMs`, `executionTimeMs`, `resultFetchTimeMs` — so plausibly "execution end" is after spark execution but before fetch, while "query end" is after fetch. The TS types do not encode this. A reader has to guess. - **Category:** 1, 6, 19 (vague; misleading; underspecified time field) - **Suggested name:** Keep both names but rewrite the docs to spell out the relationship and the relative ordering (`queryStartTimeMs ≤ executionEndTimeMs ≤ queryEndTimeMs`). Optionally rename to `executionEndTimeMs` / `resultsDeliveredTimeMs`. - **Rationale:** This is the kind of field that turns into a billing/SLA bug if confused. The audit is naming-only, but the names *here* are the source of the confusion. -### 14. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:211` +### 13. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:211` - **Why weird:** Field documented as `A key that can be used to look up query details.` Look up *where*, with *what API*, returning *what*? `queryId` already serves that purpose. The two coexist on the same response with no explanation. `lookupKey` is vague (lookup what?), undefined-purpose, and parallel to `queryId`. - **Category:** 1, 12 (vague; duplicate concepts) - **Suggested name:** Rename to indicate destination — e.g. `detailsLookupKey` or `historyLookupKey`, plus a doc that references the related API. - **Rationale:** Without an explanation, this looks like a synonym for `queryId`. Drop it from public surface if it has no consumer use. -### 15. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:215,217` +### 14. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:215,217` - **Why weird:** Four user-identity fields on one type: `userId`, `userName`, `executedAsUserId`, `executedAsUserName`. The "executed as" pair models impersonation/run-as. Good intent, but the field names don't make the relationship clear (user1 ran-as user2). Compare `alerts.v2.Alert.runAsUserName` vs `Alert.runAs.userName` for a different (also problematic) approach to the same concept. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Group into a sub-object: `submitter: { id, name }`, `runAs?: { id, name }`. Or rename to `submittedByUserId/Name` + `executedAsUserId/Name`. - **Rationale:** Pairing the two roles symmetrically (submitter / runAs) makes the relationship explicit at the type level. The current names ("user" without qualifier on one pair, "executedAsUser" on the other) implies the bare `user*` is the *original* user, but doesn't say so. -### 16. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:201` +### 15. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:201` - **Why weird:** Field documented as `The email address or username of the user who ran the query.` So `userName` is a union of two unrelated identifier formats with no way to tell them apart at the type level. Same problem on `executedAsUserName`. - **Category:** 6, 15 (misleading; generic field losing meaning) - **Suggested name:** `userIdentifier` or `userPrincipal`, with the doc noting it can be either. Or split into `userEmail?` / `userLoginName?`. - **Rationale:** `userName` strongly implies a `username` (login handle), not an email. Half of integration code will assume that and break. -### 17. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:203` +### 16. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:203` - **Why weird:** `sparkUiUrl` exposes an internal Spark UI URL. "Spark UI" is a Databricks Runtime implementation detail; SDK consumers shouldn't need to know that the link goes to "Spark UI" specifically. The URL is functionally "query plan / execution diagnostics UI" — the name pins it to one particular implementation. - **Category:** 14 (Go/Java-style; leaks internal taxonomy) - **Suggested name:** `queryPlanUrl` or `executionPlanUrl`. - **Rationale:** Decouples the public API from Spark's internal nomenclature. -### 18. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` +### 17. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` - **Why weird:** Cross-reference of #3: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). - **Category:** 19, 16 (underspecified ID; field contradicting type domain) - **Suggested name:** See #3. -### 19. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` +### 18. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` - **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. - **Category:** 15, 19 (generic field; underspecified ID) - **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. - **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. -### 20. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:224` +### 19. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:224` - **Why weird:** Field doc: `Whether more updates for the query are expected.` So `isFinal: true` means the query result is *complete and won't change*. The name `isFinal` is conventionally used for things like inheritance ("can't be subclassed") or compilation ("final pass"). `isComplete`, `isTerminal`, or `isSettled` would be clearer. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `isSettled` or `isTerminal` (matches the `QueryStatus` terminal states). - **Rationale:** The name should describe the state, not the absence of updates. -### 21. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:226` +### 20. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:226` - **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #1 / general pattern). Reads as "channel-used info" — three nouns. - **Category:** 8, 7 (redundant `Info`; verbose; verb-as-modifier) - **Suggested name:** `channel: Channel`. (Rename type `ChannelInfo` → `Channel`.) - **Rationale:** Symmetry with `warehouseId`, `userId`, etc. — bare noun. -### 22. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` +### 21. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` - **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. - **Rationale:** Two times on one type, both unitless in the name (`duration` doesn't say ms), invites confusion. -### 23. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:237` +### 22. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:237` - **Why weird:** Every other time field has a `Ms` suffix (`queryStartTimeMs`, `executionEndTimeMs`, `queryEndTimeMs`, `totalTimeMs`, etc.). `duration` does not. The type is `number`. The doc says "Total time of the statement execution" with no unit. Reader must guess. - **Category:** 15, 19 (generic field losing meaning; underspecified) -- **Suggested name:** `durationMs`. (See also #22.) +- **Suggested name:** `durationMs`. (See also #21.) - **Rationale:** Internal consistency with every other time field in the file. ## Low severity -### 24. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:243` +### 23. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:243` - **Why weird:** `clientApplication: string` returns names like "Databricks SQL Editor, Tableau, and Power BI" — these are *application names*, not application IDs. The doc even disclaims "values are expected to remain static over time, this cannot be guaranteed." So the field is a free-text label, not a stable identifier. Name doesn't reflect that. - **Category:** 15 (generic field losing meaning) - **Suggested name:** `clientApplicationName` or `clientAppLabel`. - **Rationale:** Marks the field as a display label rather than an ID. -### 25. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:248,250` +### 24. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:248,250` - **Why weird:** "Query source" / "external query source" / "cache query ID" — three different ways the type talks about the origin of a query. `querySource` is the *upstream entity* (dashboard, notebook, alert, job, ...); `cacheQueryId` is the *prior query that supplied a cached result*. Conceptually unrelated, but the field names rhyme. - **Category:** 12 (duplicate concepts — only superficial) - **Suggested name:** Keep `querySource`. Rename `cacheQueryId` → `cachedFromQueryId`. - **Rationale:** Makes the semantic distinction explicit. -### 26. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:99,101` +### 25. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:99,101` - **Why weird:** Two dashboard-related ID fields on the same type. `legacyDashboardId` implies pre-Lakeview dashboards (the JSDoc on `dashboardId` is "this Lakeview dashboard"). Both can be set simultaneously? The semantics are not encoded — should be a discriminated union (`{ kind: 'lakeview', id } | { kind: 'legacy', id }`). - **Category:** 12, 19 (duplicate concept; underspecified) - **Suggested name:** Keep the names; consider a `kind` discriminator. At minimum, document the mutual exclusivity. - **Rationale:** Documentation fix more than naming. -### 27. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` +### 26. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` - **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. - **Category:** 19 (underspecified) - **Suggested name:** As above — convert to discriminated union. - **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. -### 28. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:120` +### 27. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:120` - **Why weird:** Three IDs on one type: `jobId`, `jobRunId`, `jobTaskRunId`. The naming is consistent and self-documenting. `jobTaskRunId` (one identifier for "task run within a job run") could be ambiguous: is it the run-ID of a *task* (with `jobRunId` being the run-ID of the whole job), or vice versa? The doc says `The canonical identifier of the task run.` — confirms the former. - **Category:** 19 (underspecified) - **Suggested name:** Acceptable; if confusion arises, rename to `taskRunIdWithinJobRun`. - **Rationale:** Documentation is sufficient. -### 29. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:261,269,279,285` +### 28. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:261,269,279,285` - **Why weird:** Four time fields; the relationship is `totalTime ≥ compilationTime + executionTime + resultFetchTime` (roughly), and `executionTime` aggregates `taskTotalTime` and `photonTotalTime`. The names don't encode the hierarchy; a developer must read all four docs to understand. Individually each name is OK. - **Category:** 1 (vague — collectively) - **Suggested name:** Keep, but add a JSDoc on `QueryMetrics` summarizing the hierarchy. - **Rationale:** Documentation > rename. -### 30. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:319` +### 29. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:319` - **Why weird:** Phrase rather than a noun. Doc says "remaining work to be done... deprecated: using projected_remaining_task_total_time_ms instead". So this is a deprecated field with a name that reads like English prose ("work to be done") rather than a TS identifier. Reads awkwardly: `metrics.workToBeDone`. - **Category:** 7, 14 (verbose; Go/Java-style phrase) - **Suggested name:** Already deprecated. If kept for back-compat, that's fine. New consumers should use `projectedRemainingTaskTotalTimeMs`. - **Rationale:** Will be removed; flag for awareness only. -### 31. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:324` +### 30. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:324` - **Why weird:** Doc says `number of remaining tasks to complete, calculated by autoscaler StatementAnalysis.scala. deprecated: use remaining_task_count instead`. So `runnableTasks` actually means "remaining tasks" — name and meaning don't align. Also deprecated. - **Category:** 6, 1 (misleading; vague) - **Suggested name:** Deprecated. Use `remainingTaskCount`. Flag for awareness. -- **Rationale:** Same as #30. +- **Rationale:** Same as #29. -### 32. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:326,333` +### 31. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:326,333` - **Why weird:** 32-char and 33-char field names. Five tokens each (`projected/remaining/task/totalTime/Ms`). Long enough that they wrap in editors and IDE tooltips. The doc on the second one says `projected lower bound on remaining total task time based on projected_remaining_task_total_time_ms / maximum concurrency` — the *name* doesn't say "wall-clock" is the divided-by-concurrency version. `WallclockTime` is the differentiator from `TaskTotalTime`. - **Category:** 7 (overly verbose) - **Suggested name:** Acceptable given the precision required. Could shorten `projectedRemainingWallclockTimeMs` → `projectedRemainingWallTimeMs`. - **Rationale:** Marginal. -### 33. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:271,273,275,277,291,295,335` +### 32. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:271,273,275,277,291,295,335` - **Why weird:** Seven `*Bytes` fields, each with subtly different scopes (remote vs cache vs disk vs network vs file vs pruned vs spill). Each individual name is OK; together they form a glossary the reader has to internalize. Also: `spillToDiskBytes` is a verb phrase (`spill to disk`) where peers are noun phrases (`read remote`, `write remote`). Inconsistent grammatical shape. - **Category:** 13 (verb-tense — minor) - **Suggested name:** `diskSpillBytes` (noun phrase, parallels `prunedBytes`, `readCacheBytes`). - **Rationale:** Symmetry. -### 34. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:263,335` +### 33. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:263,335` - **Why weird:** Two read-bytes fields. Doc on `readBytes`: `Total size of data read by the query, in bytes.` Doc on `readFilesBytes`: `Total number of file bytes in all tables read`. The difference is "file bytes" vs general "bytes" — possibly identical, possibly not. Names don't disambiguate. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Rename `readBytes` → `totalReadBytes` and `readFilesBytes` → `readFileBytes` (singular "file" since each row counts). - **Rationale:** Distinguishes scope. -### 35. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:281,295,297,335` +### 34. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:281,295,297,335` - **Why weird:** Inconsistent pluralization: `readFilesCount` (plural files) vs `prunedFilesCount` (plural files). OK, consistent there. But `readFilesBytes` is also plural where `readFilesCount` follows the same form — consistent. Then we have `readPartitionsCount` (plural). All consistent. Then `taskTotalTimeMs` is singular. The pattern across the type isn't uniform. - **Category:** 9 (singular/plural mismatch — across fields) - **Suggested name:** Pick one form. `readFileBytes` / `readFileCount` / `readPartitionCount` (singular, the way English does for counts) reads more naturally. - **Rationale:** Minor consistency win. -### 36. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` +### 35. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` - **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. - **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) - **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. - **Rationale:** Same value reachable through two paths is a maintenance hazard. -### 37. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:302,307,309` +### 36. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:302,307,309` - **Why weird:** Three time fields use `*Timestamp` suffix; everywhere else in the file the convention is `*TimeMs`. The `Timestamp` fields are documented as Unix-epoch-milliseconds too, so the unit is the same — just the naming convention differs. Mixing two suffixes for the same kind of value is a category-13 inconsistency. - **Category:** 13, 19 (verb-tense / convention inconsistency; underspecified — timestamp vs duration) - **Suggested name:** `provisioningQueueStartTimeMs`, `overloadingQueueStartTimeMs`, `queryCompilationStartTimeMs`. - **Rationale:** Consistent suffix across all time-valued fields. -### 38. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:314` +### 37. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:314` - **Why weird:** Field name has "OverTimeRange"; type is `TaskTimeOverRange`. Different naming. Field is `taskTimeOver` + `TimeRange`; type is `TaskTime` + `OverRange`. Semantically the same, named differently. - **Category:** 9, 20 (singular/plural; type-suffix tautology) - **Suggested name:** Align: `taskTimeOverRange: TaskTimeOverRange` (drop second `Time`). - **Rationale:** Field name should match type name shape. -### 39. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` +### 38. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` - **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. - **Category:** 1 (vague — `Entry`) - **Suggested name:** Optional rename to domain names. - **Rationale:** Marginal. -### 40. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:360` +### 39. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:360` - **Why weird:** Only field on the type. The doc says "total task completion time in this time range" — name reads as "task completed time" (past participle). `taskCompletionTimeMs` would be a noun-phrase form and match peer fields. - **Category:** 13 (verb-tense — past participle vs noun) - **Suggested name:** `taskCompletionTimeMs`. - **Rationale:** Noun form is more conventional. -### 41. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:365,367` +### 40. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:365,367` - **Why weird:** Generic type name `TimeRange` lives in a domain package. It's used once (`QueryFilter.queryStartTimeRange: TimeRange`). The field name `queryStartTimeRange` then re-introduces "queryStart" — odd because the `TimeRange` is *for filtering* on query start time, but a `TimeRange` is just (start, end). Reading `queryStartTimeRange.startTimeMs` is "the start of the query-start-time range, in ms" — three "start"s in one expression. - **Category:** 1, 7 (vague type name; verbose) - **Suggested name:** Rename field to `submittedDuring: TimeRange` or `queryStartedBetween: TimeRange`. Or rename type to `MsRange` / `TimestampRange` (since the type is unit-specific). - **Rationale:** Reduces "start" noise. -### 42. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:170` +### 41. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:170` - **Why weird:** Doc says `Filtering for multiple statuses is not recommended. Instead, opt to filter by a single status multiple times and then combine the results.` This is a behaviour quirk; field name is fine. Flag for documentation polish. - **Category:** observation - **Suggested name:** Keep `statuses`; document why multi-filter is discouraged on the type, not just on the field. - **Rationale:** Surfaces the constraint. -### 43. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` +### 42. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` - **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. - **Category:** 1 (vague) - **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. - **Rationale:** Minor. -### 44. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` +### 43. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` - **Why weird:** `Legacy` is a temporal/architectural modifier mid-name — it tags the identifier as belonging to the *old* product (pre-Lakeview dashboards). The "legacy" label only has meaning inside Databricks' product roadmap; SDK consumers who don't know that Databricks shipped a new dashboard product see "legacy" as architectural noise. Names like `Legacy`/`Modern`/`Old`/`New` mid-position bake a release-timeline distinction into the public type surface; once a third dashboard product ships, the name becomes a lie. - **Category:** proto-architectural-leak (`Legacy` mid-position temporal modifier) -- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #26. +- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #25. - **Rationale:** Replace the temporal modifier with the actual product name. The Go SDK keeps `legacy_dashboard_id` because of wire-format back-compat; the TS surface can rename without breaking the wire transform. ## Observations diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index aed41ffd..9c1ab9c2 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -124,7 +124,7 @@ read like leftover scaffolding. The path-parameter nature is invisible to users and already documented prose-style ("The three-level (fully qualified) name of the registered model"). Recommended names: `fullName`, `version`, and `alias` — but those collide with response -fields, which is the actual problem (see §12.1 below). The right fix is +fields, which is the actual problem (see §15 below). The right fix is to drop the path-parameter fields from the request type entirely and accept them as method positional arguments (mirroring how `getModelVersion` already URL-encodes them). @@ -172,12 +172,7 @@ typical semantic versioning expectations is a real footgun. Rename ### 6. Overly verbose names -#### 6.1 `Client.setRegisteredModelAlias` versus `Client.deleteRegisteredModelAlias` (client.ts:202, 507) -Method names hover around 30 characters. Java/Go style. In TS prefer -`setAlias` / `deleteAlias` on a `RegisteredModelsClient` whose role is -already established. The current names imply you could also call -`setUnregisteredModelAlias` or `setExperimentAlias` from the same client, -which you cannot. See also §11.1. +_None._ --- @@ -295,20 +290,10 @@ flagged because it is a common reader stumbling block. ### 12. Go / Java-style names -#### 12.1 `Client.createRegisteredModel`, `Client.deleteRegisteredModel`, etc. -Verb + full-noun method names mirror the Go SDK's -`WorkspaceClient.RegisteredModels.Create` style. In idiomatic TS, the -client itself is namespaced (you import from `registeredmodels/v1`), so -the methods could be `create`, `delete`, `get`, `list`, `update`. The -current `createRegisteredModel` is doubly redundant with the package -name. Same for `getModelVersion`, `listRegisteredModels`, -`setRegisteredModelAlias`, `updateRegisteredModel`, -`updateModelVersion`, and so on (12 methods total). - -#### 12.2 `Info` suffix everywhere +#### 12.1 `Info` suffix everywhere Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §7.1. -#### 12.3 PascalCase exported `Client` (client.ts:63) +#### 12.2 PascalCase exported `Client` (client.ts:63) The exported `Client` class is named bare-`Client`. Most TS SDKs export a context-qualified name like `RegisteredModelsClient` or `UcRegisteredModelsClient`. The bare `Client` works with the diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index e7c4828d..ab8dcfd4 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -3,14 +3,14 @@ **Path:** `packages/secretsuc/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. -**Total weird names flagged:** 24 +**Total weird names flagged:** 23 ## Summary | Severity | Count | | --- | --- | | High | 8 | | Medium | 8 | -| Low | 4 | +| Low | 3 | | Observation | 4 | ## High severity @@ -127,13 +127,7 @@ - **Suggested name:** Rename `owner` -> `explicitOwner` or `directOwner` to mirror `effectiveOwner`'s "resolved" framing. - **Rationale:** Sibling pair should be obviously a pair. Reading `owner` and `effectiveOwner` side-by-side, the user has to consult the JSDoc to discover one is the raw input and one is the resolved output. Wire stays `owner`. -### 19. `Client.createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — `src/v1/client.ts:75,105,132,172,240` -- **Why weird:** Method names redundantly include `Secret` even though the class is already secret-scoped. `client.createSecret(req)` reads okay, but inside a UC-secrets-only file `client.create(req)` would be cleaner. Compare with `pkgJson.scripts` ("build", "test") — context-scoped commands omit the noun. -- **Category:** 8 (redundant suffix — name repeats the class scope). -- **Suggested name:** Within the class, `create` / `delete` / `get` / `list` / `update` would be tighter. (But it would break a cross-package convention — every generated client uses ``.) -- **Rationale:** Cross-package convention wins here; flagging because rule 8 asks for redundant suffixes. TS scopes method calls by receiver (`client.create`) without needing to repeat the noun. Worth raising at the SDK-design level. - -### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** Same constant repeated in every generated package. `Segment` is generic; reader needs the comment to learn it's the User-Agent identity segment. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE_ID` or `PACKAGE_USER_AGENT_SEGMENT`. @@ -141,18 +135,18 @@ ## Observations -### 21. Action-verb convention in `Client` +### 20. Action-verb convention in `Client` `createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) -### 22. Acronym casing for `Http` / `Url` +### 21. Acronym casing for `Http` / `Url` Same as other audited packages: `Http` (PascalCase capital-then-lower) coexists with `URLSearchParams` (ALLCAPS from Web standard). Convention inherited from broader JS ecosystem; not worth changing. - **Category:** 3. -### 23. `Uc` abbreviation never expanded in code +### 22. `Uc` abbreviation never expanded in code Tracked thoroughly. The string "Uc" (in any case) does not appear in any identifier, type name, field name, constant, or enum value. "Unity Catalog" appears only in (a) JSDoc on `Secret` (`model.ts:85`), (b) JSDoc on `createSecret` / `listSecrets` / `updateSecret` (`client.ts:67,163,232`), and (c) the URL path string `/api/2.1/unity-catalog/secrets` (`client.ts:79,109,136,176,244`). The package name `secretsuc` is the **only** carrier of the disambiguator at the import level, and it's silent everywhere else. A consumer importing `Client` and `Secret` from this package, then opening their editor's symbol view, will see no hint that this is Unity-Catalog-scoped. See finding #1. - **Category:** 5. -### 24. No enums in this package +### 23. No enums in this package No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; `secretsuc` exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. ## Domain glossary diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 7b1ce513..f4be051e 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -3,13 +3,13 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. -**Total weird names flagged:** 29 +**Total weird names flagged:** 27 ## Summary | Severity | Count | | --- | --- | -| High | 10 | -| Medium | 12 | +| High | 9 | +| Medium | 11 | | Low | 4 | | Observation | 3 | @@ -51,25 +51,19 @@ - **Suggested name:** `TagAssignmentsClient`. Forces aliasing only when co-imported, but reads as "the client for the tag-assignments surface". - **Rationale:** Three `Client`s in three sister packages will collide on combined imports. -### 7. `createTagAssignment` / `deleteTagAssignment` / `getTagAssignment` / `listTagAssignments` / `updateTagAssignment` method names — `src/v1/client.ts:67,93,112,137,188` -- **Why weird:** Every method repeats the package's subject in the identifier. `client.createTagAssignment(...)` on a `Client` whose only job is tag assignments reads as "package.subject.create.subject". Sister package does the same with `createEntityTagAssignment`. -- **Category:** 7 (overly verbose), 8 (redundant suffix — repeats `TagAssignment` on every method when the client only manages `TagAssignment`). -- **Suggested name:** `create`, `delete`, `get`, `list`, `update` (drop the noun). Or `createAssignment` / `deleteAssignment` if the noun is desired. -- **Rationale:** Single-purpose clients should not repeat the subject. `TagAssignmentsClient.create()` reads cleaner. - -### 8. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` +### 7. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` - **Why weird:** Same concept, two different field names across sister packages. This package: `pageSize?: number`. Sister: `maxResults?: number`. The wire-side names also diverge (`page_size` here, `max_results` there). Within a single SDK, the page-size parameter has two names depending on which tag flavor you use. - **Category:** 12 (duplicate concept named differently across siblings), 17 (inconsistency between sibling fields). - **Suggested name:** Pick one. `pageSize` is the more conventional name (matches `nextPageToken` here). `maxResults` is older. - **Rationale:** Cross-SDK pagination naming consistency. Worth flagging upstream — generator-wide concern. -### 9. `tagKey` and `tagValue` on `TagAssignment` — `src/v1/model.ts:52,54` +### 8. `tagKey` and `tagValue` on `TagAssignment` — `src/v1/model.ts:52,54` - **Why weird:** The type is `TagAssignment` and the fields are `tagKey`/`tagValue`. Inside a `TagAssignment`, the `tag` prefix is redundant: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. Same in sister packages. - **Category:** 8 (redundant prefix — `tag` within `TagAssignment`). - **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. - **Rationale:** Fields should not re-state their container's noun. `assignment.key` reads cleaner. -### 10. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` +### 9. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` - **Why weird:** The list URL is `/api/2.0/entity-tag-assignments/${entityType ?? ''}/${entityId ?? ''}/tags`. When either is undefined, the URL becomes `.../entity-tag-assignments///tags`. Both fields are typed `string | undefined`, but `entityType` and `entityId` are clearly required to address an entity. Same issue on `Get`/`Delete`/`Update`. The SDK silently produces malformed URLs. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. @@ -77,19 +71,13 @@ ## Medium severity -### 11. `CreateTagAssignmentRequest` etc. — five request DTOs share a 17-char prefix — `src/v1/model.ts:7,11,20,29,57` -- **Why weird:** `CreateTagAssignmentRequest`, `DeleteTagAssignmentRequest`, `GetTagAssignmentRequest`, `ListTagAssignmentsRequest`, `UpdateTagAssignmentRequest`. Every request type re-states `TagAssignment` in a package whose only subject *is* the tag assignment. -- **Category:** 7 (overly verbose), 8 (redundant suffix), 20 (type-suffix tautology — `*Request` plus an embedded noun). -- **Suggested name:** `CreateRequest`, `DeleteRequest`, `GetRequest`, `ListRequest`, `UpdateRequest`. Or drop the noun. -- **Rationale:** Single-subject packages do not need to repeat the subject on every request DTO. - -### 12. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` +### 10. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` - **Why weird:** The plural appears only on list types. The HTTP resource on the wire is `/entity-tag-assignments` (plural) while the item type is singular `TagAssignment`. List response is `ListTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. - **Rationale:** Rule 9 demands the flag even when intentional. -### 13. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 11. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute". `executeCall` wraps retry/rate-limit policy; `executeHttpCall` does the actual HTTP send. In every client method both appear: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -103,81 +91,81 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Layering should be readable from names. Generator-wide concern. -### 14. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` +### 12. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, passed to `executeCall`. Same word as variable, type, and verb. Inside one method scope we have `req`, `call`, `httpReq`, `resp` — four roles, three of which abbreviate. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest`/`sendRequest` for the variable; keep `Call` as the type. - **Rationale:** Variable-type collisions are tolerable but obscure prose. -### 15. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` +### 13. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` - **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. - **Category:** 6 (misleading — silent malformed URLs). - **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. -- **Rationale:** See #10. Generator-wide concern. +- **Rationale:** See #9. Generator-wide concern. -### 16. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` +### 14. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` - **Why weird:** `respBody: Uint8Array` and `resp: TagAssignment` differ only by suffix. Both abbreviate "response"; the reader must remember which is bytes and which is parsed. There is no `reqBody` sibling for symmetry. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — only response abbreviates with `Body`). - **Suggested name:** `rawBody`/`result`, or `responseBytes`/`response`. - **Rationale:** Stage differences should be communicated by meaningful nouns, not suffix variations. -### 17. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` +### 15. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` - **Why weird:** Inside methods that already have `req: `, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Forking the same identifier across layers is hard to read. -### 18. `pageReq` clone variable in paginated list — `src/v1/client.ts:174` +### 16. `pageReq` clone variable in paginated list — `src/v1/client.ts:174` - **Why weird:** A clone of `req` is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; outer `req` is the parameter. - **Category:** 5 (cryptic), 8 (redundant prefix — `page` in a pagination loop is implicit). - **Suggested name:** `current` or `cursor` (describes its role as iterator state). - **Rationale:** A variable that mutates a clone of the input should describe its role. -### 19. `HttpCallOptions` — `src/v1/utils.ts:15` +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 20. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` +### 18. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries Java/JS Builder-pattern connotations. -### 21. `AuthHttpClient` — `src/v1/transport.ts:43` +### 19. `AuthHttpClient` — `src/v1/transport.ts:43` - **Why weird:** Class name encodes its implementation pattern: it is an `HttpClient` whose role is "wraps another HttpClient and injects auth headers". The JSDoc on line 42 literally reads "Wraps an HttpClient and adds authentication headers to requests." That is the Decorator/Wrapper architectural pattern leaking into the type name. The name describes the *how* (HTTP client decorator), not the *what* (authenticated transport). - **Category:** proto-architectural-leak — `Wrapper`/`Adapter` style class whose name advertises a decorator implementation rather than the domain role. - **Suggested name:** `AuthenticatingTransport`, `AuthenticatedTransport`, or `AuthInjector`. Drops the `HttpClient` infix that just restates the base interface it decorates. - **Rationale:** A class whose only job is to add auth headers should be named for that job, not the wrapping mechanism. Sister packages all duplicate this class verbatim — generator-wide concern. -### 22. `TimeoutHttpClient` — `src/v1/transport.ts:61` -- **Why weird:** Same wrapper-name pattern as #21. JSDoc line 60: "Wraps an HttpClient and applies a default timeout to requests." Name encodes the wrapping mechanism (`HttpClient` suffix) plus the cross-cutting concern (`Timeout` prefix). Reads as `` — a classic Decorator naming tell. +### 20. `TimeoutHttpClient` — `src/v1/transport.ts:61` +- **Why weird:** Same wrapper-name pattern as #19. JSDoc line 60: "Wraps an HttpClient and applies a default timeout to requests." Name encodes the wrapping mechanism (`HttpClient` suffix) plus the cross-cutting concern (`Timeout` prefix). Reads as `` — a classic Decorator naming tell. - **Category:** proto-architectural-leak — `Wrapper`/`Adapter` class whose name advertises a decorator-of-HttpClient implementation rather than the domain role. - **Suggested name:** `TimeoutTransport`, `RequestTimeout`, or merge the timeout behavior into the base `newFetchHttpClient` so a separate type is unneeded. - **Rationale:** `TimeoutHttpClient` is two architectural words concatenated: the concern (`Timeout`) and the wrapped interface (`HttpClient`). Domain names should describe behavior, not the OO pattern. Generator-wide concern — every package repeats this. ## Low severity -### 23. `flattenQueryParams` — `src/v1/utils.ts:123` +### 21. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in `client.ts`. This package's `listTagAssignments` uses individual `params.append(...)` calls (line 142-148) instead. Dead-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. -### 24. `readAll(body)` — `src/v1/utils.ts:40` +### 22. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is too generic; the function specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** Reads like it might take a file path or array. -### 25. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The single word "segment" provides no domain context. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Comment above the constant does the work the name should. -### 26. `tagValue` field doc empty — `src/v1/model.ts:53,54` +### 24. `tagValue` field doc empty — `src/v1/model.ts:53,54` - **Why weird:** `tagValue?: string | undefined` is documented as "The value of the tag" — a tautology. Compare the rich docs on `entityType`/`entityId`/`tagKey` (with character-class rules). The doc is doing zero work. - **Category:** 1 (vague — doc says nothing the field name does not), 15 (generic field doc). - **Suggested name:** Document what makes a `tagValue` valid (max length? character set? same restrictions as `tagKey`?). @@ -185,14 +173,14 @@ ## Observations -### 27. Action verb consistency +### 25. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 28. `tagassignments` lowercase package name vs. types and HTTP path +### 26. `tagassignments` lowercase package name vs. types and HTTP path The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). -### 29. Domain leakage between sister packages +### 27. Domain leakage between sister packages Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md index 84fd7852..b4eefbd3 100644 --- a/.agent/naming-audit/vectorsearch.md +++ b/.agent/naming-audit/vectorsearch.md @@ -4,17 +4,17 @@ **Versions audited:** v1 **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` **Inferred domain:** Databricks AI/Vector Search — endpoint management (create, get, list, patch, delete, budget-policy patch) and vector-index management (create, get, list, query, query-next-page, scan, sync, upsert-data, delete-data, delete). Routes under `/api/2.0/vector-search/endpoints` and `/api/2.0/vector-search/indexes`. Hosts a single `Client` with mixed endpoint and index methods plus a single `CreateEndpointWaiter`. -**Total weird names flagged:** 28 +**Total weird names flagged:** 27 ## Summary | Severity | Count | | ------------ | ----- | | High | 7 | -| Medium | 11 | +| Medium | 10 | | Low | 7 | | Observation | 3 | -| **Total** | **28** | +| **Total** | **27** | Dominant themes: 1. **Two resource families share one flat `Client`.** Endpoint methods (`createEndpoint`, `getEndpoint`, …) and index methods (`createVectorIndex`, `queryVectorIndex`, …) sit side by side on the same class. The result is long method names that re-encode the resource family (`createVectorIndex` instead of `client.indexes.create()`), plus a single waiter that only covers endpoints. @@ -102,38 +102,32 @@ Dominant themes: - **Suggested name:** Split into `UpsertDataStatus` / `DeleteDataStatus` (aliases of the same wire enum), or use a neutral name `DataMutationStatus` / `DataMutationResult`. - **Rationale:** Two-verb compound nouns are unusual and confusing. Most APIs use a single neutral noun for shared response types. -### 13. Endpoint and index method names re-encode the resource family — `client.ts:111, 136, 148, 174, 208, 233, 258, 283, 317, 365, 416, 442, 474, 500, 529, 555, 581` -- **Why weird:** Nineteen client methods all carry a resource-family suffix (`createEndpoint`, `getEndpoint`, …, `createVectorIndex`, `getVectorIndex`, …, `queryVectorIndex`, `scanVectorIndex`, …). Because the single `Client` class merges two resource families that were previously two packages, every method name pays an 8–18-character toll for the disambiguation that a sub-namespace could provide for free. -- **Category:** 7 (verbose), 8 (redundant suffix), 14 (Go-style — Go method names paid this cost for receiver disambiguation). -- **Suggested name:** Sub-namespace the client: `client.endpoints.create()`, `client.endpoints.get()`, `client.indexes.query()`, `client.indexes.scan()`. Drop the resource-family suffix from method names. -- **Rationale:** The repetition is a port artifact. Sub-namespacing also separates the two resource families that share a single client today. - -### 14. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` +### 13. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` - **Why weird:** Two methods with the same verb start (`createEndpoint` / `createEndpointWaiter`). The waiter version *calls* `createEndpoint` then wraps the result in a `CreateEndpointWaiter`. A reader sees two `create*` methods and may think they are different operations. The Java/Go SDK convention surfaces a waiter via a side return; TS would more naturally inline the wait (`createEndpointAndWait`). - **Category:** 7 (verbose), 13 (verb overlap), 17 (inconsistent action verbs). - **Suggested name:** Either fold the wait into `createEndpoint` (return a `CreateEndpointWaiter` that is both an awaitable and the resource shape), or rename to `createEndpointAndWait`, or expose a single `waitForEndpoint(name)` that any caller can use after `createEndpoint`. - **Rationale:** Two `create*` methods for one logical "create" operation force every caller to learn which one to use. There is also no analogous waiter for the index create flow, so the pattern is inconsistent within the package. -### 15. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` +### 14. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` - **Why weird:** The enum is already `EndpointStatus_State` and the other members (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not carry the suffix — only the health-colored values do. Reads `EndpointStatus_State.RED_STATE` — "endpoint status state . red state". Inconsistent within the enum. - **Category:** 16 (field/value contradicting type domain), 8 (redundant suffix). - **Suggested name:** If wire allows, `RED` / `YELLOW` (matches `PROVISIONING` / `ONLINE` shape). Otherwise, document the asymmetry. - **Rationale:** Inconsistency within a single enum is a generator-spec issue worth surfacing. -### 16. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` +### 15. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` - **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 73-83 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. - **Category:** 16 (field contradicting domain — two orthogonal axes squeezed into one enum), 6 (misleading). - **Suggested name:** Split into `EndpointLifecycleState` and `EndpointHealth`. Reflect both on `EndpointStatus` as two fields. - **Rationale:** Single-enum mixing of orthogonal dimensions is an API-design smell. -### 17. `Endpoint.creator` vs `Endpoint.lastUpdatedUser` — inconsistent naming for the same kind of value — `model.ts:278, 286` +### 16. `Endpoint.creator` vs `Endpoint.lastUpdatedUser` — inconsistent naming for the same kind of value — `model.ts:278, 286` - **Why weird:** Two `string` fields, both identifying users, with mismatched naming patterns. `creator` is a bare noun; `lastUpdatedUser` is a compound past-participle. JSDoc only says "Creator of the endpoint" / "User who last updated the endpoint" without committing to a format (email? user ID? display name?). The same asymmetry would not survive a side-by-side review. - **Category:** 13 (verb-tense / parallel-form mismatch), 19 (underspecified IDs). - **Suggested name:** Symmetric pair, e.g. `createdBy` / `updatedBy` (REST convention) or `creator` / `lastUpdater`. Whichever side, document the format. - **Rationale:** Parallel fields should look parallel. The current asymmetry implies a semantic difference that does not exist. -### 18. `creationTimestamp` / `lastUpdatedTimestamp` — noun vs past-participle inconsistency — `model.ts:280, 282` -- **Why weird:** Same parallel-form mismatch as #17, on the timestamp fields. `creation` (noun) vs `lastUpdated` (past-participle). Other Databricks SDK packages standardize on either `createdAt`/`updatedAt` (idiomatic TS) or `createTime`/`updateTime` (Google APIs). This package mixes the two forms. +### 17. `creationTimestamp` / `lastUpdatedTimestamp` — noun vs past-participle inconsistency — `model.ts:280, 282` +- **Why weird:** Same parallel-form mismatch as #16, on the timestamp fields. `creation` (noun) vs `lastUpdated` (past-participle). Other Databricks SDK packages standardize on either `createdAt`/`updatedAt` (idiomatic TS) or `createTime`/`updateTime` (Google APIs). This package mixes the two forms. - **Category:** 13 (verb-tense), 17 (inconsistent naming). - **Suggested name:** `createdAt` / `updatedAt`. Wire fields stay `creation_timestamp` / `last_updated_timestamp`; remap in the marshaller. - **Rationale:** Symmetric timestamp fields should match in form. @@ -142,43 +136,43 @@ Dominant themes: ## Low severity -### 19. `req`, `resp`, `respBody`, `httpReq`, `pollResp`, `apiErr`, `pkgJson`, `opts`, `msg` — Go-idiom shorthand in TS — `client.ts:20, 79-80, 112, 117, 121, 122, 130, 137, 149, 154, 158, 159, 167, 175, 185, 189, 190, 201, 209, 213, 217, 218, 226, 234, 238, 242, 243, 251, 259, 263, 267, 268, 276, 284, 297, 301, 302, 310, 318, 328, 332, 333, 341, 348, 351, 353, 360, 366, 379, 383, 384, 392, 399, 402, 404, 411, 417, 422, 426, 427, 435, 443, 451, 455, 456, 467, 475, 480, 484, 485, 493, 501, 509, 513, 514, 522, 530, 535, 539, 540, 548, 556, 561, 565, 566, 574, 582, 587, 591, 592, 603, 625, 632, 642, 666, 673`; `utils.ts:30, 65-92, 76, 88-91` +### 18. `req`, `resp`, `respBody`, `httpReq`, `pollResp`, `apiErr`, `pkgJson`, `opts`, `msg` — Go-idiom shorthand in TS — `client.ts:20, 79-80, 112, 117, 121, 122, 130, 137, 149, 154, 158, 159, 167, 175, 185, 189, 190, 201, 209, 213, 217, 218, 226, 234, 238, 242, 243, 251, 259, 263, 267, 268, 276, 284, 297, 301, 302, 310, 318, 328, 332, 333, 341, 348, 351, 353, 360, 366, 379, 383, 384, 392, 399, 402, 404, 411, 417, 422, 426, 427, 435, 443, 451, 455, 456, 467, 475, 480, 484, 485, 493, 501, 509, 513, 514, 522, 530, 535, 539, 540, 548, 556, 561, 565, 566, 574, 582, 587, 591, 592, 603, 625, 632, 642, 666, 673`; `utils.ts:30, 65-92, 76, 88-91` - **Why weird:** Ubiquitous Go-style shorthand identifiers ported verbatim. `req`/`resp`/`err`/`opts`/`msg` are conventional in Go, where the receiver supplies enough context; in TS the convention favors spelled-out names (`request`, `response`, `error`, `options`, `message`). Internal inconsistency too: `executeCall` accepts `options` (utils.ts:28) but `executeHttpCall` uses `opts` (utils.ts:67). - **Category:** 14 (Go/Java-style names), 5 (cryptic abbreviation). - **Suggested name:** Spell them out throughout: `request`, `response`, `responseBody`, `pollResponse`, `httpRequest`, `apiError`, `packageJson`, `options`, `message`. Generator-level change. - **Rationale:** Trivial diff, large readability gain. The TS ecosystem standard is the spelled-out form. -### 20. `Endpoint.numIndexes` reads as "number of array indexes" — `model.ts:292` +### 19. `Endpoint.numIndexes` reads as "number of array indexes" — `model.ts:292` - **Why weird:** "Index" in TS most commonly means a numeric position in an array. Here it means "number of vector-search indexes attached to this endpoint" — a domain term, not the data-structure term. Adjacent types use `vectorIndexes` for the array (correct disambiguation), but this scalar count uses bare `indexes`. - **Category:** 6 (misleading), 14 (Go-style `num*` prefix). - **Suggested name:** `numVectorIndexes` (matches the adjacent `vectorIndexes` array) or `vectorIndexCount`. - **Rationale:** Consistency within the package and disambiguation from the data-structure meaning. -### 21. `numResults`, `numIndexes` — `num*` prefix is a Go-ism — `model.ts:292, 438, 513` +### 20. `numResults`, `numIndexes` — `num*` prefix is a Go-ism — `model.ts:292, 438, 513` - **Why weird:** `num` is a Go/C abbreviation for "number of". TS more commonly uses `count` suffix (`indexCount`, `resultCount`) or the bare noun pluralized. - **Category:** 14 (Go-style names), 5 (cryptic abbreviation). - **Suggested name:** `indexCount`, `resultCount`. Wire fields stay `num_indexes` / `num_results`. -- **Rationale:** Same as #19 — generator-level shorthand carry-over. +- **Rationale:** Same as #18 — generator-level shorthand carry-over. -### 22. `flattenQueryParams` is exported but unused inside the package — `utils.ts:123-150` +### 21. `flattenQueryParams` is exported but unused inside the package — `utils.ts:123-150` - **Why weird:** The function is exported from `utils.ts` but every client method assembles `URLSearchParams` directly via `params.append(...)`. The helper is dead code for this package. - **Category:** Observation (dead export), 6 (misleading — exported as if needed). - **Suggested name:** Either delete from `utils.ts` here or move to `@databricks/sdk-core` so the per-package `utils.ts` files stop duplicating it. - **Rationale:** Same finding as in other per-package audits. Generator-level cleanup. -### 23. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase in a field name — `model.ts:264` +### 22. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase in a field name — `model.ts:264` - **Why weird:** The field name reads as a sentence (`modelEndpointName ForQuery`). TS field-naming convention prefers noun phrases over "for"-clauses. Adjacent `embeddingModelEndpointName` (also long, but a noun phrase) shows the package can do better. - **Category:** 14 (Java-style "ForX" suffix), 7 (verbose). - **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. - **Rationale:** Noun phrases align with adjacent fields and TS naming conventions. -### 24. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` +### 23. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` - **Why weird:** Two array fields on the same type, JSDoc on `columnsToIndex` says: "Alias for columns_to_sync. ... Only one of columns_to_sync or columns_to_index may be specified." Two fields that mean the same thing, where the API rejects both being set, is an API-level footgun. The SDK exposes both without runtime validation. - **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). - **Suggested name:** Mark `columnsToSync` `@deprecated` if `columnsToIndex` is the canonical form (or vice versa), and add runtime validation in `marshalDeltaSyncVectorIndexSpecRequestSchema`. - **Rationale:** API-level aliases are upstream policy, but the SDK should mark the deprecated alias to steer callers. -### 25. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` +### 24. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` - **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` at the top level (line 462) AND a `reranker.parameters.columnsToRerank: string[]` nested inside `RerankerConfig_RerankerParameters` (line 491). Same field name, same purpose, two places. The JSDoc on `reranker` references "`columns_to_rerank`" without saying which copy wins. - **Category:** 12 (duplicate concept), 6 (misleading — precedence unclear). - **Suggested name:** Drop one, or document the precedence in JSDoc. If one is for input and the other for echoed-back output, name them accordingly. @@ -188,19 +182,19 @@ Dominant themes: ## Observation -### 26. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` +### 25. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` - **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". A field whose JSDoc admits the rollout is incomplete leaves callers guessing whether setting it has any effect today. - **Category:** 6 (misleading — present but possibly inactive). - **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behavior and rollout timeline. - **Rationale:** Documentation-only TODOs leak generator/spec-side state into the public API. Worth surfacing. -### 27. `EmbeddingSourceColumn.embeddingConfig` JSDoc says "TODO: clean up ai gateway related code" — `model.ts:255` +### 26. `EmbeddingSourceColumn.embeddingConfig` JSDoc says "TODO: clean up ai gateway related code" — `model.ts:255` - **Why weird:** JSDoc on a public-API field contains a developer TODO: "TODO: clean up ai gateway related code. It's deprecated on ModelServing side." This is internal generator/spec-side debt leaking into IntelliSense for every SDK user. - **Category:** Observation (generator-side leak in JSDoc). - **Suggested name:** Rewrite the JSDoc to describe the public contract; track the cleanup in the spec, not in the user-facing docs. - **Rationale:** Internal TODOs in JSDoc are a long-known generator hygiene issue. Worth flagging. -### 28. `Endpoint.creator` and `lastUpdatedUser` JSDoc gives no format — `model.ts:278, 286` +### 27. `Endpoint.creator` and `lastUpdatedUser` JSDoc gives no format — `model.ts:278, 286` - **Why weird:** Both fields are typed `string` with JSDocs "Creator of the endpoint" / "User who last updated the endpoint". The reader has no way to tell if the value is a user ID, a display name, an email, or a UC identifier. Same observation applies to `MiniVectorIndex.creator` (`model.ts:396`) and `VectorIndex.creator` (`model.ts:592`). - **Category:** Observation (underspecified format on user-reference fields), 19 (underspecified IDs). - **Suggested name:** Keep the field names but extend JSDoc with the expected format (e.g. "the email of the user who created this endpoint"). From 1ace0e0e98c35f74e9e2a05d01146fc06917c60d Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 26 May 2026 21:38:02 +0000 Subject: [PATCH 06/12] update --- .agent/naming-audit/abacpolicies.md | 119 +-- .agent/naming-audit/accessmanagement.md | 145 +--- .agent/naming-audit/accountaccesscontrol.md | 6 - .../naming-audit/accountaccesscontrolproxy.md | 32 - .agent/naming-audit/accountsettings.md | 6 - .agent/naming-audit/alerts.md | 252 ++---- .agent/naming-audit/apps.md | 348 ++------ .agent/naming-audit/artifactallowlists.md | 61 +- .agent/naming-audit/billableusagedownload.md | 42 +- .agent/naming-audit/budgetpolicy.md | 87 +- .agent/naming-audit/budgets.md | 145 +--- .agent/naming-audit/bundle.md | 215 +---- .agent/naming-audit/catalogs.md | 68 +- .agent/naming-audit/cleanroomassets.md | 55 -- .../cleanroomautoapprovalrules.md | 85 -- .agent/naming-audit/cleanrooms.md | 127 +-- .agent/naming-audit/cleanroomtaskruns.md | 9 - .agent/naming-audit/clusterlibraries.md | 104 +-- .agent/naming-audit/clusterpolicies.md | 71 +- .agent/naming-audit/clusters.md | 273 ++----- .agent/naming-audit/commandexecution.md | 294 ++----- .agent/naming-audit/connections.md | 92 +-- .agent/naming-audit/credentials.md | 175 +--- .agent/naming-audit/customllms.md | 94 +-- .agent/naming-audit/database.md | 219 +---- .agent/naming-audit/dataclassification.md | 60 +- .agent/naming-audit/dataquality.md | 142 +--- .agent/naming-audit/disasterrecovery.md | 88 +- .agent/naming-audit/endpoints.md | 41 - .agent/naming-audit/entitytagassignments.md | 72 +- .agent/naming-audit/environments.md | 85 +- .agent/naming-audit/experiments.md | 122 +-- .agent/naming-audit/externallineage.md | 72 +- .agent/naming-audit/externallocations.md | 8 - .agent/naming-audit/externalmetadata.md | 132 +-- .agent/naming-audit/features.md | 98 +-- .agent/naming-audit/featurestore.md | 173 +--- .agent/naming-audit/files.md | 146 +--- .agent/naming-audit/forecasting.md | 54 +- .agent/naming-audit/functions.md | 164 +--- .agent/naming-audit/genie.md | 202 +---- .agent/naming-audit/gitcredentials.md | 111 +-- .agent/naming-audit/globalinitscripts.md | 43 +- .agent/naming-audit/grants.md | 119 +-- .agent/naming-audit/iam.md | 129 +-- .agent/naming-audit/indexes.md | 11 - .agent/naming-audit/instancepools.md | 72 +- .agent/naming-audit/instanceprofiles.md | 69 +- .agent/naming-audit/jobs.md | 472 +++-------- .agent/naming-audit/keyconfigurations.md | 13 - .agent/naming-audit/knowledgeassistants.md | 166 +--- .agent/naming-audit/lakeview.md | 368 +-------- .agent/naming-audit/logdelivery.md | 104 +-- .../naming-audit/logdeliveryconfigurations.md | 8 - .agent/naming-audit/marketplaces.md | 323 ++------ .agent/naming-audit/materializedfeatures.md | 6 - .agent/naming-audit/metastores.md | 183 ++--- .agent/naming-audit/modelregistry.md | 321 +------- .agent/naming-audit/modelserving.md | 116 +-- .agent/naming-audit/modelservingdebug.md | 15 - .agent/naming-audit/modelservingmanagement.md | 8 - .agent/naming-audit/modelservingquery.md | 254 +----- .agent/naming-audit/networking.md | 53 -- .../naming-audit/notificationdestinations.md | 156 +--- .agent/naming-audit/oauth.md | 137 +--- .../naming-audit/oauthcustomappintegration.md | 9 - .agent/naming-audit/oauthpublishedapp.md | 7 - .agent/naming-audit/onlinetables.md | 761 +----------------- .agent/naming-audit/permissions.md | 11 - .agent/naming-audit/pipelines.md | 220 ++--- .agent/naming-audit/policyfamilies.md | 45 +- .agent/naming-audit/postgres.md | 223 +---- .agent/naming-audit/qualitymonitor.md | 21 - .agent/naming-audit/qualitymonitors.md | 8 - .agent/naming-audit/queries.md | 209 +---- .agent/naming-audit/queryexecution.md | 36 - .agent/naming-audit/queryhistory.md | 182 +---- .agent/naming-audit/registeredmodels.md | 181 +---- .agent/naming-audit/repos.md | 117 +-- .agent/naming-audit/resourcequotas.md | 101 +-- .agent/naming-audit/rfa.md | 108 +-- .agent/naming-audit/schemas.md | 113 +-- .agent/naming-audit/secrets.md | 195 +---- .agent/naming-audit/secretsuc.md | 84 +- .../naming-audit/serviceprincipalsecrets.md | 30 - .../serviceprincipalsecretsproxy.md | 81 -- .agent/naming-audit/settings.md | 335 ++------ .agent/naming-audit/sharing.md | 10 +- .agent/naming-audit/statementexecution.md | 158 ++-- .agent/naming-audit/storageconfigurations.md | 86 +- .agent/naming-audit/supervisoragents.md | 136 +--- .agent/naming-audit/systemschemas.md | 41 +- .agent/naming-audit/tables.md | 698 ++++------------ .agent/naming-audit/tagassignments.md | 72 +- .agent/naming-audit/tagpolicies.md | 47 +- .agent/naming-audit/tokenmanagement.md | 82 +- .agent/naming-audit/tokens.md | 61 +- .agent/naming-audit/usagedashboards.md | 3 - .agent/naming-audit/usagepolicy.md | 104 +-- .agent/naming-audit/vectorsearch.md | 91 +-- .agent/naming-audit/volumes.md | 77 +- .agent/naming-audit/warehouses.md | 200 +---- .agent/naming-audit/workspace.md | 12 - .agent/naming-audit/workspaceassignment.md | 11 - .agent/naming-audit/workspacebindings.md | 109 +-- .agent/naming-audit/workspaceconf.md | 6 - .agent/naming-audit/workspaceobjects.md | 192 +---- .agent/naming-audit/workspaces.md | 95 +-- .agent/naming-audit/workspacesettings.md | 6 - AGENTS.md | 41 + 110 files changed, 2409 insertions(+), 11046 deletions(-) delete mode 100644 .agent/naming-audit/serviceprincipalsecretsproxy.md diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index 1f27c509..90ab1a7d 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -3,14 +3,14 @@ **Path:** `packages/abacpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter and column-mask policies. -**Total weird names flagged:** 26 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 12 | -| Low | 5 | +| High | 3 | +| Medium | 2 | +| Low | 4 | | Observation | 4 | ## High severity @@ -27,125 +27,47 @@ - **Suggested name:** Keep the name but type it `SecurableType`. - **Rationale:** Same field name with two different types across four request DTOs forces callers to remember which one is loose. This is almost certainly a generator bug worth flagging upstream. -### 3. `onSecurableFullname` — `src/v1/model.ts:66,94,103,150,234` -- **Why weird:** `fullname` is one un-camelCased word. Should be `fullName` to match field-naming conventions used everywhere else in the same model (`functionName`, `pageToken`, etc.). -- **Category:** 3 (acronym/casing inconsistency — `name` is one word and should follow camelCase, so `Fullname` is wrong). -- **Suggested name:** `onSecurableFullName` (wire stays `on_securable_fullname`). -- **Rationale:** Internal consistency. JS/TS convention treats `fullName` as two words; the Go SDK collapses `Fullname` but TS shouldn't blindly inherit that. - -### 4. `MatchColumn` — `src/v1/model.ts:130` +### 3. `MatchColumn` — `src/v1/model.ts:130` - **Why weird:** Reads as a verb (`MatchColumn`) — could be a method or a type. The field that uses it is plural (`matchColumns: MatchColumn[]`), which then reads as "match columns are an array of `MatchColumn`", and a `MatchColumn` is actually a "column matcher / condition + alias pair". - **Category:** 6 (misleading verb-as-noun), 9 (singular noun whose meaning is unclear). - **Suggested name:** `ColumnMatcher` or `ColumnMatchCondition`. - **Rationale:** Type names should be nouns; the verb form misleads. `ColumnMatcher` makes `matchColumns: ColumnMatcher[]` clearly read as "the matchers". -### 5. `forSecurableType` / `onSecurableType` field prefixes — `src/v1/model.ts:145,170` -- **Why weird:** Two different prefixes for related concepts on the same struct: `on_securable_type` and `for_securable_type`. The `on`/`for` split (carrier vs. target securable) is subtle and easily confused. Field names alone do not communicate which is which. -- **Category:** 1 (vague — the preposition does the disambiguation), 6 (misleading without docs). -- **Suggested name:** Rename `forSecurableType` to `appliesToSecurableType` (or similar) and `onSecurableType` to `definedOnSecurableType` to make the distinction explicit. -- **Rationale:** A user reading the type should not have to consult the JSDoc to tell `for` from `on`. These names sit beside each other and look interchangeable. - ## Medium severity -### 6. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:33` +### 4. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:33` - **Why weird:** Enum value pinned by a comment that says it isn't a real securable yet: "TODO: [UC-2980] Staging tables aren't full-fleged securables yet." Internal TODOs in generated SDK enums leak abstraction. - **Category:** 18 (questionable enum value). - **Suggested name:** Remove until it actually is a securable, or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't contain TODO-tagged speculative values. -### 7. `ColumnMaskOptions.using: FunctionArgument[]` — `src/v1/model.ts:54` -- **Why weird:** Field named `using` — a SQL reserved word and a generic preposition. Doesn't say what is being used. -- **Category:** 1 (vague), 10 (reserved-word-adjacent — `using` is a reserved-context keyword in JS dynamic import / TS). -- **Suggested name:** `extraArguments` / `additionalArguments` / `argumentList`. -- **Rationale:** `using` on its own carries no semantic load; readers must consult the doc to find out it's "additional positional args". Also appears on `RowFilterOptions` (model.ts:227) with the same problem. - -### 8. `ColumnMaskOptions.onColumn` — `src/v1/model.ts:49` -- **Why weird:** Preposition-prefixed field name (`onColumn`) that just identifies the masked column. Inconsistent with `functionName` (also on the same type, no preposition). -- **Category:** 1 (vague), 17 (inconsistency). -- **Suggested name:** `maskedColumnAlias` or `targetColumnAlias`. -- **Rationale:** Names should describe what the field *is*, not its prepositional relationship. - -### 9. `FunctionArgument.arg` discriminator field — `src/v1/model.ts:76` -- **Why weird:** `FunctionArgument` has a field `arg` (one of two variants). Type name and field name are near-duplicates; the field name is also an abbreviation of the type. -- **Category:** 5 (cryptic abbreviation), 11 (near-duplicate naming). -- **Suggested name:** Rename the field to `value` or `kind`. -- **Rationale:** `functionArgument.arg.$case === 'alias'` reads weirdly; the field name repeats an abbreviation of the type name. - -### 10. `policyInfo` field on `CreatePolicyRequest` / `UpdatePolicyRequest` — `src/v1/model.ts:59,246` -- **Why weird:** Field named after the entity's awkward type (`policyInfo: PolicyInfo`). If `PolicyInfo` is renamed to `Policy`, this becomes `policy: Policy` which is much cleaner. -- **Category:** 20 (type-suffix tautology), 1 (`Info`). -- **Suggested name:** `policy` (paired with type renamed to `Policy`). -- **Rationale:** Tied to the `PolicyInfo` -> `Policy` rename (finding #1). - -### 11. `policyType: PolicyType` field on `PolicyInfo` — `src/v1/model.ts:174` -- **Why weird:** Type-suffix tautology (`policyType` field of type `PolicyType`). -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `type: PolicyType` if `PolicyInfo` is renamed to `Policy`; otherwise tolerate. -- **Rationale:** Rule 20 in spec. The wire field is `policy_type` so the marshalled JSON stays unchanged. - -### 12. `onSecurableType` / `forSecurableType` type-suffix tautology — `src/v1/model.ts:145,170` -- **Why weird:** Same as above — fields named `onSecurableType` of type `SecurableType` and `forSecurableType` of type `SecurableType`. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** Drop `Type` from the field once renaming (`onSecurable: SecurableType`, `forSecurable: SecurableType`) — though it conflicts with finding #5. Better to combine the two renames (`definedOnSecurable: SecurableType`, `appliesToSecurable: SecurableType`). -- **Rationale:** Reduces tautology and clarifies semantics at once. - -### 13. Inconsistent rename style for `*Options` types — `src/v1/model.ts:36,215` +### 5. Inconsistent rename style for `*Options` types — `src/v1/model.ts:36,215` - **Why weird:** `ColumnMaskOptions` and `RowFilterOptions` — two near-identical types describing variants of policy options. Each is a discriminator member; the `Options` suffix is redundant given the discriminator already says "this is the X options". - **Category:** 8 (redundant suffix), 12 (duplicate concept across similar types). - **Suggested name:** Either keep current names but acknowledge as boilerplate, or rename to `RowFilter`, `ColumnMask` (the `$case` discriminator already disambiguates). - **Rationale:** Generator artefact; flagging because near-identical types is the moment to ask whether the API surface should collapse. -### 14. `whenCondition` field — `src/v1/model.ts:172` -- **Why weird:** `when` prefix is a SQL keyword; the field is a free-form condition expression. Just `condition` would suffice given the field already lives on `PolicyInfo`. -- **Category:** 1 (vague prefix), 10 (reserved-word-adjacent). -- **Suggested name:** `condition` or `conditionExpression`. -- **Rationale:** `when_condition` is wire-only; the TS name can drop the redundant `when_`. - -### 15. `toPrincipals` / `exceptPrincipals` field names — `src/v1/model.ts:162,164` -- **Why weird:** Preposition-prefixed names mirror SQL `TO`/`EXCEPT` syntax (this is an ABAC-on-UC policy, the API mimics SQL `GRANT ... TO ... EXCEPT ...`). For programmatic SDK consumers, `principals` and `excludedPrincipals` would read more naturally. -- **Category:** 1 (vague), 14 (Go/SQL-style names not idiomatic for TS). -- **Suggested name:** `appliedPrincipals` / `excludedPrincipals` (or `principals` and `excludePrincipals`). -- **Rationale:** Consumers who don't know the SQL syntax will misread `to_principals` as "principal list to apply to" and miss that `except_principals` is the complement. - -### 16. `MatchColumn.condition: string` — `src/v1/model.ts:132` -- **Why weird:** A `MatchColumn` has a field called `condition` (matched column condition expression) and an `alias`. The condition could equally well be called `expression`; "condition" implies boolean, but it's actually a column-selector expression evaluated to a column. -- **Category:** 6 (misleading). -- **Suggested name:** `columnExpression` or `selector`. -- **Rationale:** Domain reading: "match columns where condition = X" suggests filtering rows; here it actually selects which columns the policy applies to. Easy to misread. - -### 17. `PolicyInfo.id` — `src/v1/model.ts:139` -- **Why weird:** Bare `id` field on `PolicyInfo` alongside `name`, `onSecurableFullname`, etc. — multiple identifier-like fields; bare `id` is underspecified. -- **Category:** 19 (underspecified id when multiple ids exist). -- **Suggested name:** `policyId`. -- **Rationale:** Disambiguates from securable identifiers in the same struct. - ## Low severity -### 18. `PolicyInfo.comment` — `src/v1/model.ts:157` -- **Why weird:** Doc says "Optional description of the policy" but the field is named `comment`. SQL stores DDL comments, sure, but a TS-facing field that the JSDoc calls a description should be `description`. -- **Category:** 6 (misleading — doc says description, name says comment). -- **Suggested name:** `description`. -- **Rationale:** Match the doc and avoid the SQL-DDL leak. - -### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 6. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; only one place in the file but flagged for consistency review across the SDK. -### 20. `flattenQueryParams` — `src/v1/utils.ts:123` +### 7. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it's an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 21. `readAll` — `src/v1/utils.ts:40` +### 8. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 22. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 9. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -153,17 +75,17 @@ ## Observations -### 23. Wire/TS divergence is heavy +### 10. Wire/TS divergence is heavy The model file is ~497 lines for ~9 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. -### 24. Action-verb conventions in `Client` +### 11. Action-verb conventions in `Client` The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) -### 25. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` +### 12. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` The codebase uses `Http` (`HttpClient`, `HttpRequest`, `executeHttpCall`) and `URLSearchParams` (Web standard) and `url` (lowercase) and `userAgent`. Mixing `Http` (PascalCase capital-then-lower) with the imported `URLSearchParams` (ALLCAPS) is inconsistent — common across JS ecosystem and probably not worth changing, but worth noting. - **Category:** 3 (acronym casing). -### 26. `abac` abbreviation only appears in package name +### 13. `abac` abbreviation only appears in package name The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. May confuse users searching by acronym. - **Category:** 5 (cryptic abbreviation in package name). @@ -180,14 +102,3 @@ The package directory is `abacpolicies` but neither type, field, comment, nor en - `src/v1/client.ts` (250 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. - `src/v1/index.ts` (20 lines): read fully. - -## Fixed -- #2 `DeletePolicy` (originally cited at `src/v1/model.ts:72`): Fixed in regeneration on 2026-05-20 — renamed to `DeletePolicyRequest`; siblings `CreatePolicyRequest`, `GetPolicyRequest`, `ListPoliciesRequest`, `UpdatePolicyRequest` also gained the `Request` suffix. -- #1 (partial — Deny/Grant values) `PolicyType.POLICY_TYPE_DENY` / `POLICY_TYPE_GRANT` (originally cited at `src/v1/model.ts:7-14`): Fixed in regeneration on 2026-05-20 — Deny and Grant enum values removed. -- #6 `FunctionArgExpression` (originally cited at `src/v1/model.ts:98`): Fixed in regeneration on 2026-05-20 — type removed entirely. -- #7 `useSessionIdentity` field (originally cited at `src/v1/model.ts:292`): Fixed in regeneration on 2026-05-20 — field removed from `PolicyInfo`. -- #14 `FunctionArgExpression.expr` (originally cited at `src/v1/model.ts:99`): Fixed in regeneration on 2026-05-20 — type removed. -- #15 `TagIntrospectionExpression.expr` (originally cited at `src/v1/model.ts:313`): Fixed in regeneration on 2026-05-20 — type removed. -- #16 `ColumnTagValueExtraction` / `TagValueExtraction` (originally cited at `src/v1/model.ts:60,328`): Fixed in regeneration on 2026-05-20 — both types removed. -- #20 (partial) `DenyOptions` / `GrantOptions` (originally cited at `src/v1/model.ts:84,142`): Fixed in regeneration on 2026-05-20 — both types removed; only `ColumnMaskOptions` and `RowFilterOptions` remain, but the `Options`-suffix issue still applies (now finding #14). -- #21 `ListPolicies` request type (originally cited at `src/v1/model.ts:152`): Fixed in regeneration on 2026-05-20 — renamed to `ListPoliciesRequest`. diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md index 8afdd09f..3ad28122 100644 --- a/.agent/naming-audit/accessmanagement.md +++ b/.agent/naming-audit/accessmanagement.md @@ -16,13 +16,13 @@ the `USER`/`ADMIN` role a principal holds on a workspace (d) the `checkPolicy` resource-access policy decision endpoint. Originated from `permissions`, `workspaceassignment`, `accountaccesscontrol`, and `accountaccesscontrolproxy` during the 2026-05-22 regeneration. -**Total weird names flagged:** 38 +**Total weird names flagged:** 32 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 16 | +| High | 8 | +| Medium | 11 | | Low | 9 | | Observation | 4 | @@ -148,23 +148,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum package. The Go SDK uses `string` because Go enums are second-class; TS has first-class string literal unions that match this exact use case. -### 6. `requestObjectType` / `requestObjectId` wire-format prefix — `src/v1/model.ts:156,158,163,164,340,342,348,350` -- **Why weird:** All four request types prefix their two path parameters - with `request`: `requestObjectType` and `requestObjectId`. On the TypeScript - surface every field is by definition part of a *request* — the - `request` prefix carries zero information. The prefix is wire-format - leakage from the Databricks REST path placeholders - (`:request_object_type`, `:request_object_id`). -- **Category:** Redundant prefix (the containing type is already - `*Request`); wire-format leak. -- **Suggested name:** `objectType` and `objectId`. The doc comment on - `requestObjectId` already reads "The id of the request object" — drop - the jargon and just say "object id". -- **Rationale:** Compare `GetObjectPermissionsRequest { requestObjectType, - requestObjectId }` to `GetObjectPermissionsRequest { objectType, objectId - }`. The latter reads as plain English. - -### 7. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` +### 6. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` - **Why weird:** Three methods carry the `Proxy` suffix and are byte-for-byte identical to their non-`Proxy` siblings (lines 218, 292, 366). They issue the same HTTP request to the same URL with the same @@ -183,7 +167,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum does, not how the server routes it. Two identical methods with a `Proxy` differentiator force every caller to flip a coin. -### 8. `WorkspacePermission.UNKNOWN` zero-value sentinel — `src/v1/model.ts:40` +### 7. `WorkspacePermission.UNKNOWN` zero-value sentinel — `src/v1/model.ts:40` - **Why weird:** `WorkspacePermission` uses `UNKNOWN` as its zero-value sentinel, but the sibling enum `RequestAuthzIdentity` in the same file uses the `*_UNSPECIFIED` form (`REQUEST_AUTHZ_IDENTITY_UNSPECIFIED`, @@ -196,7 +180,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Same-file inconsistency is the worst kind. Aligning with the rest of the file (and the rest of the SDK) costs nothing. -### 9. `Client` — `src/v1/client.ts:69` +### 8. `Client` — `src/v1/client.ts:69` - **Why weird:** Top-level class named `Client`. Generic across every generated package. The merger makes this worse: this class now exposes the *combined* surface of four formerly-distinct services @@ -217,7 +201,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum ## Medium severity -### 10. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:306,322` +### 9. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:306,322` - **Why weird:** `RuleSet` and `RuleSetUpdateRequest` are structurally identical (`name`, `etag`, `grantRules`). They model the same resource — one as a response body, one as the update body — but expose it under two @@ -234,7 +218,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum divergence. Proto generates separate types because Go does not have structural typing; in TypeScript the duplication is wasteful. -### 11. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:354-360` +### 10. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:354-360` - **Why weird:** `UpdateRuleSetRequest` has both a top-level `name` and `ruleSet.name` (because `RuleSetUpdateRequest` also carries `name`). Two `name` fields on the same request that conceptually identify the same @@ -248,23 +232,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum rule set."). Developers will set one and not the other and silently 4xx. -### 12. `GetRuleSetRequest.etag` semantics — `src/v1/model.ts:188-200` -- **Why weird:** A `GET` request type carrying an `etag` is unusual — - `etag` normally rides in headers (`If-Match`/`If-None-Match`) and the - field doc describes optimistic concurrency control on PUT, not GET. The - field is also marshalled into the query string (`params.append('etag', - req.etag)` in `client.ts:301`), which is non-standard HTTP and easy to - misuse. The doc comment is copy-pasted from the PUT-side concurrency - doc on `RuleSet.etag`. -- **Category:** Misleading; doc copy-paste. -- **Suggested name:** `minimumEtag` or `ifNoneMatch` to explain semantics. - At minimum, rewrite the doc to "passed as `?etag=` query parameter; the - server returns a snapshot at least as fresh as this etag". -- **Rationale:** Current name plus copy-pasted comment makes the field - look like an `If-Match` header even though it is a freshness floor on - GET. - -### 13. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:227,302` +### 11. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:227,302` - **Why weird:** The package exports a `Role` type and then immediately ignores it: `GrantRule.role` is `string`. So `Role` is the response shape from `getAssignableRolesForResource`, but `GrantRule.role` is the @@ -276,7 +244,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Developers will write `grantRule.role = role.name` constantly because the types don't line up. -### 14. `GetAssignableRolesForResource*` verbosity and verb shape — `src/v1/model.ts:134,150`, `src/v1/client.ts:218` +### 12. `GetAssignableRolesForResource*` verbosity and verb shape — `src/v1/model.ts:134,150`, `src/v1/client.ts:218` - **Why weird:** 41-character type names. The "ForResource" suffix is implied — every assignable-roles query is for a resource. The pair reads like a Java RPC service name (`GetForRequest`). @@ -290,7 +258,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `Get...`, but the operation returns an array and is closer to a list semantically. -### 15. `GrantRule.principals: string[]` is an untyped principal-format list — `src/v1/model.ts:225` +### 13. `GrantRule.principals: string[]` is an untyped principal-format list — `src/v1/model.ts:225` - **Why weird:** Generic `string[]` for principals, where each entry is one of three formats (`users/`, `groups/`, `servicePrincipals/`). The shape is @@ -302,37 +270,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** TypeScript can encode this; the Go SDK cannot. The 1:1 port leaves type information on the floor. -### 16. `RuleSet.name` / `GrantRule.role` / `Role.name` are all hierarchical paths — `src/v1/model.ts:303,227,308` -- **Why weird:** "Name" in this API is a hierarchical resource path - (`accounts//ruleSets/default`), not a human-readable label. - Same overload for `role` (`roles/account.admin`). Calling these - `name`/`role` and typing them as `string` hides that they are resource - paths. `Role.name` is even doc-commented as "Role to assign to a - principal..." — the type name `Role` plus field name `name` plus doc - about the *assigned role* is three layers of indirection. -- **Category:** Generic field names; field contradicting domain. -- **Suggested name:** `ruleSet.resourceName`, `grantRule.roleName`, - `Role.id` or `Role.path`. At minimum the JSDoc should explicitly say - "resource path". -- **Rationale:** Half of integration bugs in this API will be - wrong-format names. The type system can help. - -### 17. `principalName` discriminated union — `src/v1/model.ts:47-63,68-84,269-285` -- **Why weird:** The discriminator field is named `principalName` but the - values inside are not all "names" — `servicePrincipalName` is documented - as "application ID of a service principal" (line 60), which is a UUID, - not a name. The carrier field plus the SP variant together imply - "principal name = service principal name = the SP's name", but the SP - variant is the application *ID*. Same shape appears on - `AccessControlRequest`, `AccessControlResponse`, and `PrincipalOutput`. -- **Category:** Misleading; underspecified ID; overloaded "name". -- **Suggested name:** Rename outer field to `principal` and rename the SP - variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or - flatten to `principalType: enum + identifier: string`. -- **Rationale:** Same field name leaks "name" semantics onto a value - that's a UUID. - -### 18. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` +### 14. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` - **Why weird:** Four types use the proto-style nested-message underscore convention: `DeleteWorkspacePermissionAssignmentRequest_Response`, `GetPermissionLevelsRequest_Response`, @@ -355,7 +293,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** TypeScript has no concept of nested message types; the underscore separator is a proto-specific path encoding. -### 19. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` +### 15. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` - **Why weird:** Three types ending with `Output`. In proto / gRPC service definitions, message types are commonly named `FooInput` (request) and `FooOutput` (response) — the `Output` suffix is the @@ -371,26 +309,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Compare `principal: PrincipalOutput` to `principal: Principal` — the latter reads as plain English. -### 20. `permissions` field name overloaded across three types — `src/v1/model.ts:241,376,387` -- **Why weird:** Three different responses carry `permissions` fields - with three different element types and three different meanings: - - `ListWorkspacePermissionsRequest_Response.permissions: PermissionOutput[]` - (line 241) — list of *supported* workspace permission levels. - - `UpdateWorkspacePermissionAssignmentRequest.permissions: - WorkspacePermission[]` (line 376) — the levels to grant a principal. - - `WorkspacePermissionAssignmentOutput.permissions: WorkspacePermission[]` - (line 387) — the levels a principal *currently has*. - Same field name, three concepts (catalog / grant / state). A user - holding a response sees `.permissions` and can't tell which. -- **Category:** Generic field name losing meaning; cross-type - inconsistency. -- **Suggested name:** Distinguish: `supportedPermissions` on the - list-catalog response; `grantedPermissions` or `permissionLevels` on - the assignment output and the update request. -- **Rationale:** Three identical field names, three meanings, in the same - file is a discoverability failure. - -### 21. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:244` +### 16. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:244` - **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance is really an "effective permission" — a permission level paired with @@ -407,7 +326,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum common across IAM systems that it's nearly content-free without qualification. -### 22. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:256` +### 17. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:256` - **Why weird:** Type carries `permissionLevel?: PermissionLevel` (singular) and `description?: string`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. @@ -416,7 +335,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `PermissionLevelInfo`. - **Rationale:** One descriptor = one level; the type name should match. -### 23. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:261` +### 18. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:261` - **Why weird:** Returned from three different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, @@ -429,19 +348,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental. -### 24. `accessControlList` field uses asymmetric element types — `src/v1/model.ts:264,343,351` -- **Why weird:** Appears in three types (`PermissionsResponse`, - `SetObjectPermissionsRequest`, `UpdateObjectPermissionsRequest`). The - field is typed `AccessControlRequest[]` in the two request types and - `AccessControlResponse[]` in the response — asymmetric typing under one - field name. The conventional shorthand is "ACL". -- **Category:** Overly verbose; asymmetric typing under one field name. -- **Suggested name:** `acl: AccessControlEntry[]` or - `entries: AccessControlEntry[]`, with one unified element type. -- **Rationale:** "Access control list" is verbose; asymmetric typing for - same field name is a footgun. - -### 25. `Actor.kind` discriminated-union with a single variant — `src/v1/model.ts:95-97` +### 19. `Actor.kind` discriminated-union with a single variant — `src/v1/model.ts:95-97` - **Why weird:** `Actor.kind?: { $case: 'actorId'; actorId: number } | undefined` — the `kind` field name is a direct port of the proto `oneof kind { ... }` block convention. With a single-variant union @@ -459,7 +366,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum ## Low severity -### 26. `etag` casing — `src/v1/model.ts:199,318,334` +### 20. `etag` casing — `src/v1/model.ts:199,318,334` - **Why weird:** Lowercase `etag` (rather than `eTag`/`ETag`). HTTP spec uses `ETag`. Per the project-wide acronym policy (Google TS `Pascal-then-lower`), the form would be `etag`/`Etag` depending on @@ -470,7 +377,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum most likely correct per Google TS rules. - **Rationale:** Defer to global policy. -### 27. `flattenQueryParams` exported but rarely consumed — `src/v1/utils.ts:123` +### 21. `flattenQueryParams` exported but rarely consumed — `src/v1/utils.ts:123` - **Why weird:** Used only by `checkPolicy` (`client.ts:536,545,555`). The helper is identical across packages and should live in a shared `@databricks/sdk-core` module rather than be re-emitted per package. @@ -481,7 +388,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Generator emits the same helper into every package; consolidation reduces surface. -### 28. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` +### 22. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` - **Why weird:** The package imports `CallOptions` from `@databricks/sdk-options/call` (line 12) and defines its own `HttpCallOptions` here. The names suggest the latter is a @@ -494,7 +401,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 29. `readAll` is a Go-port utility name — `src/v1/utils.ts:40` +### 23. `readAll` is a Go-port utility name — `src/v1/utils.ts:40` - **Why weird:** Direct Go-port of `io.ReadAll`; clashes cognitively with `Array.prototype` methods and Web Streams APIs. Generator-wide. - **Category:** Vague; Go-port style. @@ -502,7 +409,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `bufferStream`. - **Rationale:** Cross-package consistency. -### 30. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` +### 24. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` - **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. @@ -510,7 +417,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 31. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` +### 25. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 513). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the @@ -522,7 +429,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. -### 32. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` +### 26. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` - **Why weird:** REST path uses `/permissionassignments/` (no separator), while every other Databricks REST resource in this SDK uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). @@ -533,7 +440,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum in this package. - **Rationale:** Cross-API consistency. -### 33. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` +### 27. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` - **Why weird:** Method is named with `get*` but returns `permissionAssignments` array (model.ts:213). REST convention is `list*` for array-returning operations; `get*` for singular. @@ -544,7 +451,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Aligns naming with REST list semantics used elsewhere in the SDK. -### 34. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` +### 28. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` - **Why weird:** Method `listWorkspacePermissions` returns the catalog of `PermissionOutput` values supported (USER/ADMIN), not user data. Sits side-by-side with `getWorkspacePermissionAssignments` diff --git a/.agent/naming-audit/accountaccesscontrol.md b/.agent/naming-audit/accountaccesscontrol.md index 753248b8..b7591730 100644 --- a/.agent/naming-audit/accountaccesscontrol.md +++ b/.agent/naming-audit/accountaccesscontrol.md @@ -132,9 +132,3 @@ - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (17 lines): read fully. - `package.json` (41 lines): read for context. - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/accountaccesscontrolproxy.md b/.agent/naming-audit/accountaccesscontrolproxy.md index e333e47f..59b22471 100644 --- a/.agent/naming-audit/accountaccesscontrolproxy.md +++ b/.agent/naming-audit/accountaccesscontrolproxy.md @@ -46,35 +46,3 @@ _None._ longer present; they have been moved to the `## Fixed` section below. --- - -## Fixed - -- #1 package `accountaccesscontrolproxy` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — Package source removed; surface duplicate no longer exists. -- #2 package `accountaccesscontrolproxy` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — Package source removed; long compound name no longer exposed. -- #3 `GetAssignableRolesForResourceRequest` (originally cited at model.ts:5): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #4 `GetAssignableRolesForResourceResponse` (originally cited at model.ts:21): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #5 `Role.name` (originally cited at model.ts:70): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #6 `GetRuleSetRequest.name` (originally cited at model.ts:38): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #7 `GetRuleSetRequest.etag` (originally cited at model.ts:51): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #8 `GetRuleSetRequest` shape (originally cited at model.ts:25): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #9 `GrantRule` (originally cited at model.ts:54): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #10 `GrantRule.principals` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #11 `GrantRule.role` (originally cited at model.ts:65): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #12 `RuleSet` (originally cited at model.ts:73): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #13 `RuleSet.name` (originally cited at model.ts:75): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #14 `RuleSet.etag` (originally cited at model.ts:85): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #15 `RuleSet.grantRules` (originally cited at model.ts:86): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #16 `RuleSetUpdateRequest` (originally cited at model.ts:89): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #17 `RuleSetUpdateRequest` vs `UpdateRuleSetRequest` (originally cited at model.ts:89, 105): Fixed in regeneration on 2026-05-20 — Both symbols removed with package source. -- #18 `UpdateRuleSetRequest.name` (originally cited at model.ts:109): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #19 `UpdateRuleSetRequest.ruleSet` (originally cited at model.ts:110): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #20 `Client` (originally cited at client.ts:39): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #21 `Client.getAssignableRolesForResource` (originally cited at client.ts:72): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #22 `HttpCallOptions` (originally cited at utils.ts:15): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #23 `executeCall` vs `executeHttpCall` (originally cited at utils.ts:26, 65): Fixed in regeneration on 2026-05-20 — Both symbols removed with package source. -- #24 `flattenQueryParams` (originally cited at utils.ts:123): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. -- #25 `PACKAGE_SEGMENT` (originally cited at client.ts:34): Fixed in regeneration on 2026-05-20 — Symbol removed with package source. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/accountsettings.md b/.agent/naming-audit/accountsettings.md index fcf1d079..6bc0be72 100644 --- a/.agent/naming-audit/accountsettings.md +++ b/.agent/naming-audit/accountsettings.md @@ -348,9 +348,3 @@ | `src/v1/utils.ts` | full | 100% — utility functions reviewed; `HttpCallOptions`, `executeCall`, `parseResponse`, `marshalRequest`, `flattenQueryParams` have no naming issues worth flagging (they are infrastructure shared across packages and follow consistent conventions). | --- - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md index eb58ad1b..f02a10f3 100644 --- a/.agent/naming-audit/alerts.md +++ b/.agent/naming-audit/alerts.md @@ -3,7 +3,7 @@ **Path:** `packages/alerts/src/{v1,v2}/` **Versions audited:** v1, v2 **Inferred domain:** SQL/Databricks alerts: a stored configuration that periodically evaluates a query result against a threshold and notifies subscribers when it triggers. -**Total weird names flagged:** 35 +**Total weird names flagged:** 22 (0 fixed, 22 still present after rescan on 2026-05-26 post regen #156) ## Summary table @@ -11,39 +11,26 @@ |---|----------|---------|----------|------|----------| | 1 | High | v2 | `model.ts` enum | `Aggregation` | Vague/generic, no domain prefix | | 2 | High | v2 | `model.ts` enum value | `AlertEvaluationState.UNKNOWN` | Inconsistent sentinel naming (`UNKNOWN` vs `UNSPECIFIED`) | -| 3 | High | v1 | `model.ts` field | `AlertCondition.op` | Cryptic abbreviation | -| 4 | High | v1 | `model.ts` field | `Alert.secondsToRetrigger` / v2 `AlertNotification.retriggerSeconds` | Singular/plural mismatch & cross-version regression in word order | -| 5 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | -| 6 | High | v2 | `model.ts` field | `Alert.runAsUserName` vs `Alert.runAs.userName` | Duplicate concept | -| 7 | High | v2 | `model.ts` field | `Alert.queryText` | Field contradicts type domain (alert holds raw SQL) | -| 8 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | -| 9 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | -| 10 | Medium | both | `model.ts` enum value | `AlertOperator.IS_NULL` / v2 `IS_NOT_NULL` | Long enum values inconsistent with binary ops | -| 11 | Medium | both | `model.ts` field | `Alert.notifyOnOk` | Acronym casing ambiguity (`Ok` vs `OK`) | -| 12 | Medium | v1 | `model.ts` field | `Alert.triggerTime` (v1) — disappears in v2 | Underspecified time field | -| 13 | Medium | v2 | `model.ts` field | `AlertEvaluation.lastEvaluatedAt` | Inconsistent time suffix (`At` vs `Time`) | -| 14 | Medium | v2 | `model.ts` field | `AlertOperandColumn.display` | Vague (display what?) | -| 15 | Medium | v2 | `model.ts` field | `Alert.warehouseId` | Underspecified ID | -| 16 | Medium | v2 | `model.ts` field | `CronSchedule.timezoneId` | Underspecified ID (timezone name, not numeric) | -| 17 | Medium | v2 | `model.ts` field | `CronSchedule.quartzCronSchedule` | Type-suffix tautology | -| 18 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | -| 19 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Boolean-shaped enum | -| 20 | Medium | v2 | `model.ts` field | `Alert.evaluation` (no domain qualifier) | Generic field name | -| 21 | Medium | v2 | `model.ts` field | `Alert.lifecycleState` documented as "Indicates whether the query is trashed" | Misleading (says query, means alert) | -| 22 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | -| 23 | Medium | v2 | `model.ts` field | `AlertSubscription.subscriptionType` | Type-suffix tautology | -| 24 | Low | both | `model.ts` field | `pageToken` / `pageSize` / `nextPageToken` | Conventional; flagged only for completeness | -| 25 | Low | both | `model.ts` field | `ListAlertsRequest`/`ListAlertsResponse` plural vs `GetAlertRequest` singular | Consistent with REST norms | -| 26 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | -| 27 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | -| 28 | Low | v1 | `model.ts` field | `AlertCondition.emptyResultState` | Underspecified (state of what when empty) | -| 29 | Low | v2 | `model.ts` field | `AlertEvaluation.source` | Vague/generic | -| 30 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | -| 31 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | -| 32 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | -| 33 | Low | v2 | `model.ts` field | `Alert.effectiveRunAs` | "Effective" prefix unexplained at first read | -| 34 | Low | v2 | `model.ts` field | `Alert.id`, `Alert.queryText` co-located | "id" alone underspecified at field level (docs clarify) | -| 35 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | +| 3 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | +| 4 | High | v2 | `model.ts` field | `Alert.runAsUserName` vs `Alert.runAs.userName` | Duplicate concept | +| 5 | High | v2 | `model.ts` field | `Alert.queryText` | Field contradicts type domain (alert holds raw SQL) | +| 6 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | +| 7 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | +| 8 | Medium | both | `model.ts` enum value | `AlertOperator.IS_NULL` / v2 `IS_NOT_NULL` | Long enum values inconsistent with binary ops | +| 9 | Medium | both | `model.ts` field | `Alert.notifyOnOk` | Acronym casing ambiguity (`Ok` vs `OK`) | +| 10 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | +| 11 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Boolean-shaped enum | +| 12 | Medium | v2 | `model.ts` field | `Alert.lifecycleState` documented as "Indicates whether the query is trashed" | Misleading (says query, means alert) | +| 13 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | +| 14 | Low | both | `model.ts` field | `pageToken` / `pageSize` / `nextPageToken` | Conventional; flagged only for completeness | +| 15 | Low | both | `model.ts` field | `ListAlertsRequest`/`ListAlertsResponse` plural vs `GetAlertRequest` singular | Consistent with REST norms | +| 16 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | +| 17 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | +| 18 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | +| 19 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | +| 20 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | +| 21 | Low | v2 | `model.ts` field | `Alert.effectiveRunAs` | "Effective" prefix unexplained at first read | +| 22 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | ## v1 vs v2 comparison @@ -56,24 +43,16 @@ | `LifecycleState` (enum) | `AlertLifecycleState` (enum) | **Improvement** — domain prefix added. | | `LifecycleState.TRASHED` | `AlertLifecycleState.DELETED` | **Break** — `trashAlert` method (still named "trash") now yields a state called `DELETED`. The verb on the wire and the state vocabulary diverge, even though the docstring still says "soft deleted". | | `AlertCondition` (type) | `AlertEvaluation` (type) | **Major rename** — shifts from "condition shape" to "evaluation snapshot." The new type co-mingles configuration (`comparisonOperator`, `threshold`, `notification`) with runtime telemetry (`state`, `lastEvaluatedAt`), which is a meaningful design regression for naming. | -| `AlertCondition.op` | `AlertEvaluation.comparisonOperator` | **Improvement** — no longer cryptic. | -| `AlertCondition.operand` | `AlertEvaluation.source` | **Regression** — `source` is even vaguer than `operand`. | -| `AlertCondition.threshold` (`AlertOperand`) | `AlertEvaluation.threshold` (`AlertOperand`) | Identical name and type; OK. | -| `Alert.secondsToRetrigger` | `AlertNotification.retriggerSeconds` | **Regression** — word order changed (good: matches Go field), but: (a) two versions now use opposite orderings, (b) field moved into a sub-message, (c) v1 had grammatical singular/plural mismatch ("seconds … to retrigger" reads better than "retrigger seconds"). | -| `Alert.customBody`, `Alert.customSubject` | `Alert.customSummary`, `Alert.customDescription` | **Vocabulary swap** — v1 borrows email vocabulary (body/subject), v2 borrows article/incident vocabulary (summary/description). Both apply to the same notification text — there is no semantic reason for the change; an existing user has to re-learn the field names. | -| `Alert.triggerTime` | dropped; moved into `AlertEvaluation.lastEvaluatedAt` | Renamed and re-located. Time-suffix convention changes from `Time` to `At`. | -| `Alert.condition` | `Alert.evaluation` | Mirror of the type rename. | ### New in v2 (no v1 counterpart) - `Aggregation` (enum) — top-level, no domain prefix. - `SchedulePauseStatus` (enum) — partial domain prefix. - `AlertNotification` (type) -- `AlertOperandColumn.display`, `.aggregation` (new fields) - `AlertRunAs` (type) — verb-as-noun. - `AlertSubscription` (type) - `CronSchedule` (type) — generic name in a single-domain package. -- `Alert.queryText`, `Alert.warehouseId`, `Alert.runAsUserName`, `Alert.runAs`, `Alert.effectiveRunAs`, `Alert.schedule`, `Alert.evaluation`, `Alert.customSummary`, `Alert.customDescription`. +- `Alert.queryText`, `Alert.runAsUserName`, `Alert.runAs`, `Alert.effectiveRunAs`, `Alert.schedule`, `Alert.customSummary`, `Alert.customDescription`. - `TrashAlertRequest.purge` — new flag. ### Dropped in v2 @@ -82,7 +61,7 @@ ### Net assessment -v2 has clear wins (`AlertLifecycleState` prefix; spelling out `comparisonOperator`) but also introduces several regressions (`AlertOperator` → `ComparisonOperator`, `operand` → `source`, `condition` → `evaluation`, `customBody/Subject` → `customSummary/Description`, `secondsToRetrigger` → `retriggerSeconds`, `LifecycleState.TRASHED` → `AlertLifecycleState.DELETED` while keeping the method `trashAlert`). +v2 has clear wins (`AlertLifecycleState` prefix; spelling out `comparisonOperator`) but also introduces several regressions (`AlertOperator` → `ComparisonOperator`, `condition` → `evaluation`, `LifecycleState.TRASHED` → `AlertLifecycleState.DELETED` while keeping the method `trashAlert`). ## High severity @@ -126,34 +105,7 @@ export enum AlertEvaluationState { This enum exposes a value (`UNKNOWN`) that the inline JSDoc tells the user to avoid: "Deprecated. Please avoid using `UNKNOWN` as empty_result_state." Shipping a deprecated value as part of the public enum surface is a naming/API smell — consumers reading the type cannot tell which values are valid without the JSDoc. Additionally, this enum's zero-value sentinel is named `UNSPECIFIED` while other enums in the package use `UNKNOWN` for the same role; the package-wide sentinel convention is inconsistent. -### 3. `AlertCondition.op` — cryptic abbreviation (v1) - -**Location:** `src/v1/model.ts:62-71` - -```ts -export interface AlertCondition { - /** Operator used for comparison in alert evaluation. */ - op?: AlertOperator | undefined; - ... -} -``` - -`op` is opaque without reading the JSDoc. v2 renames to `comparisonOperator` (good), but v1 keeps the two-letter wire shorthand. - -### 4. `secondsToRetrigger` vs `retriggerSeconds` — singular/plural & cross-version reorder - -**Location:** `src/v1/model.ts:38-39`; `src/v2/model.ts:122-126` - -```ts -// v1 -secondsToRetrigger?: number | undefined; -// v2 -retriggerSeconds?: number | undefined; -``` - -`secondsToRetrigger` reads as "the seconds it takes to retrigger" but actually means "the wait period before retriggering is allowed." `retriggerSeconds` is closer to "number-of-seconds-typed-as-retrigger." Neither is great; both encode the unit in the name which is a smell when there's no companion `*Millis`/`*Minutes`. The same conceptual field changes name across versions. - -### 5. `AlertRunAs` — verb-as-noun (v2) +### 3. `AlertRunAs` — verb-as-noun (v2) **Location:** `src/v2/model.ts:155-168` @@ -168,7 +120,7 @@ export interface AlertRunAs { `RunAs` is an imperative verb phrase used as a type name. `AlertIdentity`, `AlertRunner`, or `RunAsIdentity` would parse as nouns. Also note: the *field* inside is named `identity` — a clearer type name would let the field name be more specific (or vice versa). -### 6. Duplicate concept — `runAsUserName` vs `runAs.userName` (v2) +### 4. Duplicate concept — `runAsUserName` vs `runAs.userName` (v2) **Location:** `src/v2/model.ts:77-99` @@ -182,7 +134,7 @@ effectiveRunAs?: AlertRunAs | undefined; The same data is expressible as either `runAsUserName` (legacy scalar) or `runAs.identity.userName` (new structured). The Alert type carries both. The deprecation is noted in JSDoc only — a TS user reading the type sees three "run as"-prefixed fields without IDE help. -### 7. `Alert.queryText` — field contradicts type domain (v2) +### 5. `Alert.queryText` — field contradicts type domain (v2) **Location:** `src/v2/model.ts:68-69` @@ -195,7 +147,7 @@ A type named `Alert` carrying a raw SQL string makes the alert object responsibl ## Medium severity -### 8. `trashAlert` — inconsistent action verb (both) +### 6. `trashAlert` — inconsistent action verb (both) **Location:** `src/v1/client.ts:170-192`; `src/v2/client.ts:168-196` @@ -206,13 +158,13 @@ async trashAlert(...) { ... DELETE ... } The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashAlert`. Across the SDK this is the only place where soft-delete uses `trash`-prefix. Most resources use `deleteX` (and the v2 enum value is `AlertLifecycleState.DELETED`, not `TRASHED`). -### 9. `TrashAlertRequest` — same as 8, in the type layer (both) +### 7. `TrashAlertRequest` — same as 6, in the type layer (both) **Location:** `src/v1/model.ts:187-189`; `src/v2/model.ts:218-222` Same verb inconsistency at the type layer. -### 10. Long enum values with `_OR_` connectors +### 8. Long enum values with `_OR_` connectors **Location:** `src/v1/model.ts:8-16`; `src/v2/model.ts:39-48` @@ -223,7 +175,7 @@ LESS_THAN_OR_EQUAL = 'LESS_THAN_OR_EQUAL', The wire format uses long, English-prose enum values where most SDKs use `GT`, `GTE`, `LT`, `LTE`. They are long and verbose, and v2 adds `IS_NOT_NULL` alongside `IS_NULL` — unary operators sharing an enum named `ComparisonOperator`. -### 11. `Alert.notifyOnOk` — acronym/initialism case ambiguity (both) +### 9. `Alert.notifyOnOk` — acronym/initialism case ambiguity (both) **Location:** `src/v1/model.ts:59`; `src/v2/model.ts:128` @@ -233,83 +185,13 @@ notifyOnOk?: boolean | undefined; `OK` is conventionally upper-case, so `notifyOnOK` would match the enum value `AlertEvaluationState.OK`. The field uses title-case `Ok`, mismatching the enum value casing in the same file. -### 12. `Alert.triggerTime` — underspecified time (v1) - -**Location:** `src/v1/model.ts:42-43` - -```ts -/** Timestamp when the alert was last triggered, if the alert has been triggered before. */ -triggerTime?: Temporal.Instant | undefined; -``` - -"Trigger time" could be "next scheduled trigger," "first trigger," or "last trigger" — the doc clarifies it's "last triggered." `lastTriggerTime` or `lastTriggeredAt` (v2 uses `lastEvaluatedAt` for a related concept) would be unambiguous. - -### 13. `AlertEvaluation.lastEvaluatedAt` — inconsistent time suffix (v2) - -**Location:** `src/v2/model.ts:113-114` - -```ts -lastEvaluatedAt?: Temporal.Instant | undefined; -``` - -Every other timestamp in v2 uses the `*Time` suffix (`createTime`, `updateTime`). `lastEvaluatedAt` mixes conventions in the same file. - -### 14. `AlertOperandColumn.display` — vague (v2) - -**Location:** `src/v2/model.ts:139-144` - -```ts -export interface AlertOperandColumn { - name?: string | undefined; - display?: string | undefined; - aggregation?: Aggregation | undefined; -} -``` - -`display` with no JSDoc is ambiguous: display name? display label? display order? — without inspection of the wire payload one can't tell. `displayName` or `label` would clarify. - -### 15. `Alert.warehouseId` — underspecified ID (v2) - -**Location:** `src/v2/model.ts:70-71` - -```ts -/** ID of the SQL warehouse attached to the alert. */ -warehouseId?: string | undefined; -``` - -In a different package this might be a data warehouse, a logical warehouse, etc. The JSDoc clarifies, but the bare name does not. `sqlWarehouseId` would match the docstring and the rest of the Databricks SQL surface area. - -### 16. `CronSchedule.timezoneId` — underspecified ID (v2) - -**Location:** `src/v2/model.ts:187-192` - -```ts -/** A Java timezone id. ... */ -timezoneId?: string | undefined; -``` - -A timezone is named (e.g., `"America/Los_Angeles"`), not numerically identified. `timezone` or `timezoneName` reads less like a foreign key. The Go SDK and protobuf wire spell it `timezone_id`, but that doesn't make it accurate. - -### 17. `CronSchedule.quartzCronSchedule` — type-suffix tautology (v2) - -**Location:** `src/v2/model.ts:181-186` - -```ts -export interface CronSchedule { - quartzCronSchedule?: string | undefined; - ... -} -``` - -The type is `CronSchedule`, the field is `quartzCronSchedule`. The user writes `schedule.quartzCronSchedule` where the outer access already implies "schedule." `quartzExpression` or `quartz` would suffice. - -### 18. `CronSchedule` — generic name in a single-domain package (v2) +### 10. `CronSchedule` — generic name in a single-domain package (v2) **Location:** `src/v2/model.ts:181-195` A top-level type called `CronSchedule` in a package whose only consumer is alerts. If/when another package wants its own cron schedule shape, the user has two `CronSchedule`s. `AlertSchedule` would domain-prefix consistently with the rest of v2. -### 19. `SchedulePauseStatus` — boolean-shaped enum (v2) +### 11. `SchedulePauseStatus` — boolean-shaped enum (v2) **Location:** `src/v2/model.ts:50-53` @@ -322,17 +204,7 @@ export enum SchedulePauseStatus { Two values for a boolean concept; `boolean paused` would be simpler. -### 20. `Alert.evaluation` — generic field name (v2) - -**Location:** `src/v2/model.ts:78` - -```ts -evaluation?: AlertEvaluation | undefined; -``` - -The type already conveys "alert evaluation." The field would be clearer as `condition` (mirroring v1 semantics) or `trigger`, since `AlertEvaluation` actually carries both configuration (operator/threshold) and runtime telemetry (state/lastEvaluatedAt). - -### 21. `Alert.lifecycleState` — JSDoc contradicts the field (v2) +### 12. `Alert.lifecycleState` — JSDoc contradicts the field (v2) **Location:** `src/v2/model.ts:80-81` @@ -343,27 +215,15 @@ lifecycleState?: AlertLifecycleState | undefined; JSDoc says "whether the query is trashed," but the field is on `Alert` and the enum is `AlertLifecycleState` with values `ACTIVE`/`DELETED`. The word "query" leaks from the underlying implementation (alerts wrap queries) into an `Alert` field's documentation. -### 22. `AlertLifecycleState.DELETED` vs v1 `LifecycleState.TRASHED` — vocabulary swap +### 13. `AlertLifecycleState.DELETED` vs v1 `LifecycleState.TRASHED` — vocabulary swap **Location:** v1 `model.ts:24-27`; v2 `model.ts:34-37` The method is still `trashAlert` (both versions), but in v1 the resulting state is `TRASHED` and in v2 it is `DELETED`. So in v2 you "trash" something and it becomes "deleted." The wire/JSDoc still references "trashed." -### 23. `AlertSubscription.subscriptionType` — type-suffix tautology (v2) - -**Location:** `src/v2/model.ts:170-175` - -```ts -export interface AlertSubscription { - subscriptionType?: ... ; -} -``` - -The field name re-states the type name. `target` or `recipient` would describe what the discriminator carries. - ## Low severity -### 24. `pageToken` / `pageSize` / `nextPageToken` (both) +### 14. `pageToken` / `pageSize` / `nextPageToken` (both) ```ts export interface ListAlertsRequest { @@ -378,11 +238,11 @@ export interface ListAlertsResponse { Conventional Google AIP-158 pagination names. Flagged only because the rule list asks for completeness; no action recommended. -### 25. `ListAlertsRequest` plural vs `GetAlertRequest` singular (both) +### 15. `ListAlertsRequest` plural vs `GetAlertRequest` singular (both) Consistent with REST norms (`GET /alerts/{id}` singular, `GET /alerts` plural). No action recommended. -### 26. `Aggregation.STDDEV` — cryptic abbreviation (v2) +### 16. `Aggregation.STDDEV` — cryptic abbreviation (v2) ```ts STDDEV = 'STDDEV', @@ -390,29 +250,11 @@ STDDEV = 'STDDEV', `STANDARD_DEVIATION` or `STDEV` would be clearer; `STDDEV` is a SQL-server-ism. -### 27. `Aggregation.AVG` — cryptic abbreviation (v2) +### 17. `Aggregation.AVG` — cryptic abbreviation (v2) `AVERAGE` would be consistent with `SUM`, `COUNT`, `MEDIAN`, `MIN`, `MAX`. The mix of short and full names inside one enum is the issue. -### 28. `AlertCondition.emptyResultState` — underspecified (v1) - -```ts -/** Alert state if result is empty. */ -emptyResultState?: AlertState | undefined; -``` - -Reads as "the empty-result state." `stateWhenEmptyResult` or `emptyResultBehavior` parses left-to-right. Minor. - -### 29. `AlertEvaluation.source` — vague (v2) - -```ts -/** Source column from result to use to evaluate alert */ -source?: AlertOperandColumn | undefined; -``` - -`source` is generic; `operandColumn` (matching the type), `inputColumn`, or `column` would be clearer. - -### 30. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) +### 18. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) ```ts /** Threshold to user for alert evaluation, can be a column or a value. */ @@ -423,15 +265,15 @@ The JSDoc admits the threshold can be a column — i.e., not actually a threshol Also note the typo "Threshold to user" (should be "to use") — content, not naming, but worth fixing. -### 31. `LifecycleState` — missing domain prefix (v1) +### 19. `LifecycleState` — missing domain prefix (v1) v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycleState`. -### 32. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) +### 20. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) Same data, different vocabulary. v1 = email metaphor, v2 = generic content metaphor. Users porting from v1 to v2 need a translation table. -### 33. `effectiveRunAs` (v2) +### 21. `effectiveRunAs` (v2) **Location:** `src/v2/model.ts:94-99` @@ -446,11 +288,7 @@ effectiveRunAs?: AlertRunAs | undefined; The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. (Previously also cited `effectiveParentPath`; that field was removed in regeneration.) -### 34. `Alert.id` (both) - -The name alone (`id`) is underspecified at type level — `alertId` would be clearer when constructing a request that takes both `req.id` and the alert's id. The JSDoc covers it; the field doesn't. - -### 35. JSDoc verb/casing inconsistency (both) +### 22. JSDoc verb/casing inconsistency (both) **Location:** v2 `client.ts:68`, `client.ts:198` @@ -465,9 +303,9 @@ async updateAlert(...) { ... } ## Observations -1. **Wire-format leakage.** Many names are direct translations of proto wire fields without consideration of how they read in TypeScript: `op`, `STDDEV`, `IS_NULL`, `UNKNOWN`, `quartzCronSchedule`, `timezoneId`. The audit rule "1:1 port" was followed faithfully but the language idioms suffer. +1. **Wire-format leakage.** Many names are direct translations of proto wire fields without consideration of how they read in TypeScript: `STDDEV`, `IS_NULL`, `UNKNOWN`. The audit rule "1:1 port" was followed faithfully but the language idioms suffer. -2. **v1→v2 vocabulary churn.** The package introduces 8+ renames between versions (`AlertOperator` → `ComparisonOperator`, `LifecycleState` → `AlertLifecycleState`, `TRASHED` → `DELETED`, `op` → `comparisonOperator`, `condition` → `evaluation`, `operand` → `source`, `triggerTime` → `lastEvaluatedAt`, `secondsToRetrigger` → `retriggerSeconds`, `customBody/Subject` → `customSummary/Description`). Some are improvements, some are lateral, some are regressions. Combined with `trashAlert` keeping its name while `TRASHED` becomes `DELETED`, the message-vs-method vocabulary is inconsistent. +2. **v1→v2 vocabulary churn.** The package introduces multiple renames between versions (`AlertOperator` → `ComparisonOperator`, `LifecycleState` → `AlertLifecycleState`, `TRASHED` → `DELETED`, `AlertCondition` → `AlertEvaluation`, `customBody/Subject` → `customSummary/Description`). Some are improvements, some are lateral, some are regressions. Combined with `trashAlert` keeping its name while `TRASHED` becomes `DELETED`, the message-vs-method vocabulary is inconsistent. 3. **Verb-as-noun proliferation in v2.** `AlertRunAs`, `effectiveRunAs`, `runAs.identity`, `runAsUserName` — a single concept ("which identity executes this alert") spreads across four names with overlapping semantics. diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index 7fef8cd2..d4734a4d 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -9,22 +9,19 @@ with deployments, custom templates, app spaces, and resource bindings. | Severity | Count | | -------- | ----- | -| High | 11 | -| Medium | 25 | -| Low | 18 | +| High | 6 | +| Medium | 14 | +| Low | 11 | | Observation | 9 | -| **Total** | **63** | +| **Total** | **40** | The audit found one dominant theme: the domain has overlapping vocabularies for the same concept. `App` vs `Application` (`ApplicationStatus`, `ApplicationStatus_ApplicationState`) collide on the same entity, and three overlapping "space" vocabularies (`Space`, `AppResourceGenieSpace`, `space` as a string field on `App`/`ListAppsRequest`) produce outright ambiguity (`Space` -versus Genie Space). Field-level confusion compounds the issue: `App.name` is -the primary key while `App.id` is a separate unique identifier, and a bare -`space` field sits next to `spaceId` on the same type. The package also -re-exports an `ErrorCode` enum with 76 cross-product values whose relevance to -Apps is unclear. +versus Genie Space). The package also re-exports an `ErrorCode` enum with 76 +cross-product values whose relevance to Apps is unclear. --- @@ -80,59 +77,7 @@ Apps is unclear. and they will collide on import. Either a shared canonical type or a domain-specific rename is required. -### H4. `space` string field on `App` vs `spaceId` — which is the identifier? -- **File:** `model.ts:773`, `client.ts:612-614` -- **Category:** Underspecified IDs (19), Misleading names (6), Generic field names (15) -- **Issue:** `App` has a `space?: string` field ("Name of the space this app - belongs to") that is stringly-typed and distinguishable only by the - documentation. `ListAppsRequest.space` is also a `string` filter that takes - the space *name*. The bare `space` field looks like it should be a `Space` - object rather than a string handle. -- **Suggestion:** Rename `space` -> `spaceName` to mirror conventions like - `spaceId` and to reduce confusion with the `Space` interface. Update - `ListAppsRequest.space` -> `spaceName` to match. -- **Rationale:** A field literally named after a type (`space: string` next to - `interface Space`) violates the "field contradicting type domain" rule. - -### H5. `name` is the App's primary key, not `id` — ambiguous identifier -- **File:** `model.ts:717, 756, 1090, 1134` -- **Category:** Underspecified IDs (19), Misleading names (6) -- **Issue:** `App.name` is the URL-path identifier used by all client methods - (`/api/2.0/apps/${req.name}`); `App.id` is a separate "unique identifier" - string. Several request types (`DeleteAppRequest`, `GetAppRequest`, - `UpdateAppThumbnailRequest`, `StartAppRequest`, `StopAppRequest`, - `DeleteAppThumbnailRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`) carry a - bare `name?: string` field. The same `App.name` field also appears in - `AsyncUpdateAppRequest.appName` (the disambiguated form). Both - conventions appear in the same package. -- **Suggestion:** Standardise on `appName` for all single-target Apps request - types. `DeleteAppRequest.name` -> `appName`; similarly for the others. The - existing `AsyncUpdateAppRequest.appName` and `GetAppDeploymentRequest.appName` - already follow this rule. -- **Rationale:** The wire-level field is `name`, but the TS field can be - renamed via the marshal/unmarshal mapping. Mixing `name` and `appName` for - the same role across request types makes the API harder to discover. - -### H6. Inconsistent value sets across sibling "state of an async op" enums -- **File:** `model.ts:530, 672, 514` -- **Category:** Verb-tense inconsistency (13), Duplicate concepts (12) -- **Issue:** Three sibling state enums in the same file have inconsistent - value sets: - - `AppDeployment_State` — `SUCCEEDED/FAILED/IN_PROGRESS/CANCELLED`. - - `AppUpdate_UpdateStatus_UpdateState` — - `SUCCEEDED/FAILED/IN_PROGRESS`. - - `SpaceUpdateState` — - `NOT_UPDATED/IN_PROGRESS/SUCCEEDED/FAILED`. - A consumer can't predict which terminal/non-terminal states are reachable - from one async op to the next. -- **Suggestion:** Align the value sets where the underlying state machines - actually agree. Consider sharing a `LongRunningState` enum if the lifecycles - truly match across the three operations. -- **Rationale:** Sibling state enums in the same domain should expose the - same value vocabulary unless the underlying state machines genuinely - differ — and if they differ, the doc should say why. - -### H7. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym +### H4. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym - **File:** `model.ts:759-760` - **Category:** Acronym casing inconsistencies (3) - **Issue:** The fields use `oauth2` (all-lowercase) embedded with PascalCase. @@ -145,40 +90,7 @@ Apps is unclear. - **Rationale:** Inconsistent with how the SDK treats other acronyms (e.g. `Url` in `thumbnailUrl`, `Id` in many fields). -### H8. `defaultSourceCodePath` vs `gitRepository` — two coexisting "source" concepts on `App` -- **File:** `model.ts:750, 768` -- **Category:** Duplicate concepts (12), Misleading names (6) -- **Issue:** `App` has both `defaultSourceCodePath?: string` and - `gitRepository?: GitRepository`. The `defaultSourceCodePath` doc says it - "tracks the workspace source code path of the last active deployment", while - `gitRepository` is the configured repo. These describe overlapping aspects of - deployment provenance and the naming does not clarify their distinct roles. -- **Suggestion:** Treat `defaultSourceCodePath` as the historical - (last-deployed) data; rename to `lastDeploymentSourceCodePath` to mirror - `lastDeploymentId` (if such a convention is used). Then `gitRepository` - remains the per-app configuration — two clearly differentiated roles. -- **Rationale:** Today a reader can't tell whether `defaultSourceCodePath` is - the default for new deployments or the most-recently-used source. The doc - comment clarifies it tracks the last active deployment, but the name does - not. - -### H9. `noCompute` boolean on `CreateAppRequest` -- **File:** `model.ts:1049-1050` -- **Category:** Misleading names (6) -- **Issue:** `noCompute?: boolean` with doc "If true, the app will not be - started after creation." The negation in the name plus the documented - semantics ("not started" vs "no compute") leaves room for misinterpretation - — does `noCompute=true` mean *no compute allocated* (release-the-resources) - or *don't auto-start*? -- **Suggestion:** Rename to `skipStart` or `startOnCreate` (positive form, - default `true`), and update the doc to be explicit. The Go SDK historically - uses `no_compute`, so the wire name needs to remain; just rename the TS - field. -- **Rationale:** Negated booleans are a documented anti-pattern; the field - also describes a behaviour ("start") rather than its surface effect ("no - compute"). - -### H10. `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix is a wire-format architectural leak +### H5. `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix is a wire-format architectural leak - **File:** `model.ts:1081`, also `index.ts:80`, used at `model.ts:1296` and serialised at `model.ts:1955, 2072`. - **Category:** Proto-architectural-leak (Proto suffix), Overly verbose (7) - **Issue:** The public type carries a `Proto` suffix, exposing the @@ -195,7 +107,7 @@ Apps is unclear. not surface implementation-layer artefacts that a hand-written client would never name this way. -### H11. Singular `permission` field holding a single value but documented as plural permissions +### H6. Singular `permission` field holding a single value but documented as plural permissions - **File:** `model.ts:838-839, 947-948` - **Category:** Singular/plural mismatches (9) - **Issue:** `AppManifest_AppResourceJobSpec.permission?: ...JobPermission` @@ -215,53 +127,7 @@ Apps is unclear. ## Medium-severity findings -### M1. `creator` / `updater` — bare-noun fields holding emails -- **File:** `model.ts:732, 736, 797, 1077, 1321, 1325` -- **Category:** Generic field names (15), Misleading names (6) -- **Issue:** `creator?: string` is documented as "The email of the user that - created the app". The field name suggests an identity or a user object, but - the value is specifically an email address. -- **Suggestion:** Rename to `creatorEmail` and `updaterEmail`. Same on - `AppDeployment.creator`, `Space.creator`, `Space.updater`, - `CustomTemplate.creator`. - -### M2. `defaultSourceCodePath` — what does "default" mean here? -- **File:** `model.ts:746-750` -- **Category:** Vague/generic (1), Misleading names (6) -- **Issue:** Doc says it "tracks the workspace source code path of the last - active deployment". So the field is historical, not a default. -- **Suggestion:** Rename to `lastActiveDeploymentSourceCodePath` or - `effectiveSourceCodePath`. - -### M3. `effective*` fields paired with non-prefixed siblings -- **File:** `model.ts:751-754, 757-758, 762-763, 1331, 1341` -- **Category:** Duplicate concepts (12) -- **Issue:** `App` has paired fields: `budgetPolicyId/effectiveBudgetPolicyId`, - `usagePolicyId/effectiveUsagePolicyId`, `userApiScopes/effectiveUserApiScopes`. - Same on `Space`. The relationship (one is requested, the other is what - actually applies) is not visible from the names. -- **Suggestion:** Add JSDoc explicitly distinguishing the requested vs - effective values, or rename to `requestedBudgetPolicyId` / `appliedBudgetPolicyId`. - -### M4. `userApiScopes` field name vs OAuth-scope concept -- **File:** `model.ts:754, 758, 1329-1331` -- **Category:** Vague/generic (1) -- **Issue:** `userApiScopes?: string[]`. The doc on `Space.userApiScopes` says - "OAuth scopes for apps in the space." The TS field name says "user API - scopes", which is neither the wire name nor the documented concept. -- **Suggestion:** Rename to `oauth2Scopes` or `userOAuth2Scopes` to make the - protocol clear. - -### M5. `command?: string[]` — what kind of command? -- **File:** `model.ts:800-801` -- **Category:** Vague/generic (1) -- **Issue:** `AppDeployment.command` is "The command with which to run the - app." But it's an array of strings (argv-style); the name doesn't hint at - that. -- **Suggestion:** Rename to `startCommand` (matches Docker's `CMD` ENTRYPOINT - semantics) or `runCommand`. Adding to JSDoc is acceptable as an alternative. - -### M6. `EnvVar` — too short +### M1. `EnvVar` — too short - **File:** `model.ts:1108`, also `index.ts:85` - **Category:** Cryptic abbreviations (5) - **Issue:** `EnvVar` reads as Go-style. Full TS conventions prefer @@ -273,62 +139,7 @@ Apps is unclear. the `feedback_no_extra_abstractions.md` memory entry — if the rule is strict 1:1 with Go names, leave as-is. -### M7. `envVars` plural OK but contradicts singular-source pattern -- **File:** `model.ts:803, 1108-1122` -- **Category:** Singular/plural mismatches (9) -- **Issue:** `AppDeployment.envVars?: EnvVar[]` is plural and correct, but - inside each `EnvVar` the `source` field is a `{$case: 'value'; value: string} - | {$case: 'valueFrom'; valueFrom: string}` union. The latter union arm is - `valueFrom: string` — a field name that's almost a clause (`value-from`) and - whose direction is unclear (a path-to-fetch-from? a literal string starting - with the word "from"?). -- **Suggestion:** Rename `valueFrom` -> `valueRef`, `secretRef`, or - `valueSource`. Update the discriminator literal `'valueFrom'` accordingly. - -### M8. `AppManifest.version: number` carries no unit -- **File:** `model.ts:821` -- **Category:** Vague/generic (1) -- **Issue:** "The manifest schema version, for now only 1 is allowed". Field - is a bare `number`; reader has to read the doc to know it's an integer - schema-revision number. -- **Suggestion:** Rename to `schemaVersion` and document it as a positive - integer. - -### M9. `CustomTemplate.gitRepo` vs `GitRepository` type -- **File:** `model.ts:1069-1070, 1076` -- **Category:** Cryptic abbreviations (5), Singular/plural mismatches with type name (9) -- **Issue:** `CustomTemplate.gitRepo?: string` (URL string) sits adjacent to - the `GitRepository` interface used elsewhere. The abbreviation `gitRepo` is - inconsistent with the full word `gitRepository` used elsewhere in the file. -- **Suggestion:** Rename to `gitRepositoryUrl` (since the field stores a URL, - not an object reference) or align on `gitRepoUrl` package-wide. - -### M10. `path` on `CustomTemplate` — path of what, where? -- **File:** `model.ts:1071-1072` -- **Category:** Vague/generic (1) -- **Issue:** `CustomTemplate.path?: string` — "The path to the template within - the Git repository." Bare `path` is too generic for a public field. -- **Suggestion:** Rename to `templatePath` or `gitPath`. - -### M11. `gitProvider?: string` — should be enum/union -- **File:** `model.ts:1075-1076, 1163-1166` -- **Category:** Vague/generic (1) -- **Issue:** `CustomTemplate.gitProvider` and `GitRepository.provider` are - free-form strings, but the doc on `GitRepository.provider` enumerates eight - legal values (gitHub, gitHubEnterprise, bitbucketCloud, etc.). The type - should be a string-literal union or enum. -- **Suggestion:** Define `enum GitProvider { GIT_HUB, GIT_HUB_ENTERPRISE, ... }` - or a string-literal union of the documented values. - -### M12. `GitRepository.provider` vs `CustomTemplate.gitProvider` — same concept, different name -- **File:** `model.ts:1076, 1166` -- **Category:** Duplicate concepts (12) -- **Issue:** The Git provider name is `provider` on `GitRepository` but - `gitProvider` on `CustomTemplate`. Two names for the same field. -- **Suggestion:** Standardise on `provider` everywhere (since the surrounding - type makes the qualifier obvious) or on `gitProvider` (more searchable). - -### M13. `AsyncUpdateAppRequest.appName` carrying a redundant nesting +### M2. `AsyncUpdateAppRequest.appName` carrying a redundant nesting - **File:** `model.ts:1021-1025` - **Category:** Redundant suffixes (8) - **Issue:** `AsyncUpdateAppRequest` already contains an `app: App` field, and @@ -340,7 +151,7 @@ Apps is unclear. semantic change; flag for discussion. Alternative: keep both and document which wins on conflict. -### M14. `UcSecurableType` duplicated across manifest spec and runtime resource +### M3. `UcSecurableType` duplicated across manifest spec and runtime resource - **File:** `model.ts:586-591, 664-669` - **Category:** Duplicate concepts (12) - **Issue:** Two identical enums (`VOLUME`, `TABLE`, `FUNCTION`, `CONNECTION`) @@ -350,7 +161,7 @@ Apps is unclear. it from both the manifest UC securable spec and the runtime UC securable resource. -### M15. UC securable permission enum on the runtime resource is a strict subset of the manifest-spec enum +### M4. UC securable permission enum on the runtime resource is a strict subset of the manifest-spec enum - **File:** `model.ts:576-583, 654-661` - **Category:** Duplicate concepts (12) - **Issue:** Spec enum has 7 values (`READ_VOLUME`, `WRITE_VOLUME`, `MANAGE`, @@ -361,16 +172,7 @@ Apps is unclear. isn't actually grantable at runtime, document that. Or define two related enums where one is a subset reference (not duplicated). -### M16. `AppDeployment.deploymentId` — `deployment` repeats outer type -- **File:** `model.ts:777-778` -- **Category:** Type-suffix tautology (20) -- **Issue:** Within the `AppDeployment` interface, `deploymentId` repeats the - outer name. Inside `AppDeployment` the unqualified `id` would suffice and - matches the pattern in `App.id`, `Space.id`, and `AppResourceJob.id` - (correctly unqualified). -- **Suggestion:** Rename `AppDeployment.deploymentId` -> `id`. - -### M17. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types +### M5. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types - **File:** `model.ts:756, 946, 975, 1316` - **Category:** Underspecified IDs (19) - **Issue:** `AppResourceSqlWarehouse.id` is a SQL warehouse ID, `App.id` is an @@ -379,10 +181,9 @@ Apps is unclear. identifiers. - **Suggestion:** Either accept the convention (`id` always means "the entity this object describes") or be explicit (`sqlWarehouseId`, `jobId`, - `experimentId`). The package is currently inconsistent — see M16, where the - rename runs the *opposite* direction. + `experimentId`). The package is currently inconsistent in this regard. -### M18. `UnityCatalog` interface — generic name, no role suffix +### M6. `UnityCatalog` interface — generic name, no role suffix - **File:** `model.ts:1383-1390`, also `index.ts:110` - **Category:** Vague/generic (1) - **Issue:** `UnityCatalog` is exported as a public type. The interface has @@ -393,7 +194,7 @@ Apps is unclear. - **Suggestion:** Rename to `UnityCatalogTelemetryDestination` or `UnityCatalogTables`. Inline if not reused. -### M19. `Operation.result` carries `error` and `response` arms +### M7. `Operation.result` carries `error` and `response` arms - **File:** `model.ts:1292-1303` - **Category:** Vague/generic (1) - **Issue:** The `response` arm holds `Record` — a totally @@ -405,7 +206,7 @@ Apps is unclear. `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name promises nothing. -### M20. `flattenQueryParams` — what does it flatten? +### M8. `flattenQueryParams` — what does it flatten? - **File:** `utils.ts:123` - **Category:** Vague/generic (1) - **Issue:** `flattenQueryParams(prefix, value, params)` — the function @@ -414,7 +215,7 @@ Apps is unclear. - **Suggestion:** Rename to `encodeNestedQueryParams` or `appendObjectAsQueryParams`. -### M21. `readAll` — local helper exported as `readAll` +### M9. `readAll` — local helper exported as `readAll` - **File:** `utils.ts:40` - **Category:** Vague/generic (1) - **Issue:** `readAll(body: ReadableStream | null)` — reads-all of @@ -422,7 +223,7 @@ Apps is unclear. - **Suggestion:** Rename to `readStreamToBytes` or `consumeStream`. (It's not exported, so impact is local.) -### M22. `executeCall` vs `executeHttpCall` — pair drifts in meaning +### M10. `executeCall` vs `executeHttpCall` — pair drifts in meaning - **File:** `utils.ts:26, 65` - **Category:** Inconsistent action verbs (17) - **Issue:** `executeCall` is the *outer* retry/rate-limit wrapper; @@ -432,7 +233,7 @@ Apps is unclear. would help. - **Suggestion:** Rename to `runWithRetries`/`sendHttp`, or `runCall`/`sendOne`. -### M23. `StillRunningError` — internal sentinel class, named ambiguously +### M11. `StillRunningError` — internal sentinel class, named ambiguously - **File:** `client.ts:93` - **Category:** Misleading names (6) - **Issue:** `class StillRunningError extends Error {}` — used as a sentinel @@ -441,7 +242,7 @@ Apps is unclear. - **Suggestion:** Rename to `pollAgainSentinel` (as a typed Error subclass) or `RetryablePollError`, and add a comment that it never escapes the file. -### M24. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +### M12. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too - **File:** `client.ts:121, 902` - **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) - **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, @@ -452,7 +253,7 @@ Apps is unclear. - **Suggestion:** Drop the `async` prefix from `asyncUpdateApp` to match `updateSpace`, or add `asyncUpdateSpace` for symmetry. -### M25. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +### M13. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type - **File:** `client.ts:297, 396, 939` - **Category:** Type-suffix tautology (20) - **Issue:** Methods named `createSpaceOperation()` return a @@ -463,6 +264,16 @@ Apps is unclear. `createSpaceAndWait()` or `createSpaceLongRunning()`. The `*Operation` class could be `*LongRunning` (mirroring the `Operation` type's role). +### M14. `gitProvider?: string` — should be enum/union +- **File:** `model.ts:1075-1076, 1163-1166` +- **Category:** Vague/generic (1) +- **Issue:** `CustomTemplate.gitProvider` and `GitRepository.provider` are + free-form strings, but the doc on `GitRepository.provider` enumerates eight + legal values (gitHub, gitHubEnterprise, bitbucketCloud, etc.). The type + should be a string-literal union or enum. +- **Suggestion:** Define `enum GitProvider { GIT_HUB, GIT_HUB_ENTERPRISE, ... }` + or a string-literal union of the documented values. + --- ## Low-severity findings @@ -473,51 +284,19 @@ Apps is unclear. - **Suggestion:** "of which" should be "in which" or "by which". A nit, not a rename, but flagged because it appears in the public API docs. -### L2. `App.creator` and `App.updater` — `updater` is a real English word but commonly used for libraries/tools -- **File:** `model.ts:732, 736` -- **Category:** Misleading names (6) -- **Issue:** Outside of CRUD-stamp contexts, "updater" often denotes a - software-update agent (e.g. Sparkle). Pair with M1 — both should become - `*Email` if that's the value type. - -### L3. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` +### L2. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` - **File:** `model.ts:731-736` - **Category:** Field contradicting type domain (16) - **Suggestion:** No type change available short of a branded type; document the format in JSDoc. -### L4. `App.url` doc: "URL of the app once it is deployed" -- **File:** `model.ts:722-723` -- **Category:** Misleading names (6) -- **Suggestion:** Rename `App.url` -> `App.appUrl` or `App.deploymentUrl` for - clarity, especially because `GitRepository.url` is also called `url` in the - same file. (Currently both are bare `url`.) - -### L5. `GitRepository.url` — same generic `url` as `App.url` -- **File:** `model.ts:1161` -- **Category:** Generic field names (15) -- **Suggestion:** Rename to `repositoryUrl` (mirror with `GitRepository.provider` - named more specifically). - -### L6. `GitSource.resolvedCommit` — does it carry SHA or ref? -- **File:** `model.ts:1196-1202` -- **Category:** Vague/generic (1) -- **Suggestion:** Rename to `resolvedCommitSha` to match the doc, which says - "the resolved commit SHA". - -### L7. `GitSource.sourceCodePath` — verbose -- **File:** `model.ts:1191-1195` -- **Category:** Overly verbose (7) -- **Suggestion:** Inside `GitSource`, simply `path` would be unambiguous (the - whole interface is about source location). - -### L8. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" +### L3. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" - **File:** `model.ts:856` - **Category:** Doc / clarity - **Suggestion:** Drop or rephrase the reference to `app.proto`; in TS the reference is meaningless. -### L9. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers +### L4. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers - **File:** `model.ts:2939, 3016` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — @@ -526,21 +305,14 @@ Apps is unclear. - **Suggestion:** Either expose helpers for every entity with a field-mask schema, or none. -### L10. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models +### L5. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models - **File:** `model.ts:771, 994` - **Category:** Duplicate concepts (12) - **Suggestion:** Document that `thumbnailUrl` is the display URL and `AppThumbnail.thumbnail` is the byte content (used in update/delete-thumbnail requests). -### L11. `AppDeployment.envVars` carries a list of `EnvVar`, each with a `source` union — discriminator `'value'` vs `'valueFrom'` -- **File:** `model.ts:1111-1122` -- **Category:** Vague/generic (1) -- **Suggestion:** Discriminator `'value'` and `'valueFrom'` are short; consider - `'literal'` and `'reference'` to make intent clearer. (Wire field names - unchanged.) - -### L12. `Space` interface — same name as the Genie product `AppResourceGenieSpace` +### L6. `Space` interface — same name as the Genie product `AppResourceGenieSpace` - **File:** `model.ts:938, 1306` - **Category:** Duplicate concepts (12) - **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share @@ -552,27 +324,18 @@ Apps is unclear. is the outlier. This realignment also clarifies the wire URLs (`/api/2.0/app-spaces/...`). -### L13. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, +### L7. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, `ListSpacesRequest`, etc., do not mention "App" - **File:** `model.ts:1057, 1103, 1153, 1250`, also `index.ts:78, 84, 91, 100` - **Category:** Vague/generic (1) -- **Suggestion:** Tied to L12 — rename these to `CreateAppSpaceRequest`, etc. +- **Suggestion:** Tied to L6 — rename these to `CreateAppSpaceRequest`, etc. -### L14. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? +### L8. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? - **File:** `model.ts:1232, 1258` -- **Category:** Observation — both follow the same pattern. Tied to L12 again +- **Category:** Observation — both follow the same pattern. Tied to L6 again for the entity rename. -### L15. `Operation.name` — server-assigned UNIQUE name, not human-readable -- **File:** `model.ts:1267-1273` -- **Category:** Misleading names (6) -- **Issue:** `Operation.name` is the operation *identifier* path - (`operations/{unique_id}`) — distinct from `App.name` (the App entity's - primary key, a slug) and `Space.name`. Multiple `name` semantics in the - package. -- **Suggestion:** Rename to `operationName` or, given the format, just `path`. - -### L16. `Client` class — exported as bare `Client` +### L9. `Client` class — exported as bare `Client` - **File:** `client.ts:95`, also `index.ts:4` - **Category:** Vague/generic (1) - **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the @@ -580,7 +343,7 @@ Apps is unclear. `@databricks/sdk-jobs`, they need an alias. - **Suggestion:** Rename to `AppsClient`. Common SDK convention. -### L17. `host` (private field on `Client`) +### L10. `host` (private field on `Client`) - **File:** `client.ts:96` - **Category:** Vague/generic (1) - **Issue:** `private readonly host: string`. The doc on the workspace @@ -588,7 +351,7 @@ Apps is unclear. - **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, cosmetic. -### L18. `getSpaceOperation` (method) vs `GetOperationRequest` +### L11. `getSpaceOperation` (method) vs `GetOperationRequest` - **File:** `client.ts:524-546` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells @@ -634,7 +397,8 @@ Consider `AppTemplate` or `CustomAppTemplate`. Asymmetry but probably intentional. ### O7. `ListAppsRequest.space` filters by space name (string), not by -`Space` object — consistent with H4 issue. +`Space` object — observation tied to the ambiguity between the bare `space` +field type and the `Space` interface. ### O8. The package re-exports the `apierr` enum locally Per H2, this enum should live in `@databricks/sdk-databricks/apierror/codes`. @@ -661,14 +425,14 @@ detail. | `AppDeployment` | A specific deployment (source-code + config snapshot) | Has its own `id`, status, lifecycle. | | `AppManifest` | Schema describing required resources for an app | Used by `CustomTemplate`. | | `AppResource` | A binding from an App to another Databricks resource | Discriminated union of 10 cases. | -| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L12. | -| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L12. | +| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L6. | +| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L6. | | `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | | `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H3. | | `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | -| `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M14/M15. | -| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L10. | -| `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M6. | +| `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M3/M4. | +| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L5. | +| `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M1. | | `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | | `GitSource` | Specific commit/branch/tag + path within a `GitRepository` | Used by deployments. | @@ -686,11 +450,3 @@ detail. All types, fields, enum values, and methods reviewed. --- - -## Fixed - -- #M13 `callerCredentialId` (originally cited at `model.ts:1213-1217`): Fixed in regeneration on 2026-05-20 — the `GitRepository` interface no longer carries a `callerCredentialId` field. -- #H9 `defaultGitSource` / `deploymentSource` arms (originally cited at `model.ts:760-763, 786-794`): Fixed in regeneration on 2026-05-20 — `App.defaultGitSource` and the `deploymentSource` discriminated union are gone; finding rewritten to cover the remaining two-way overlap between `defaultSourceCodePath` and `gitRepository`. -- #L15 `CreateAppDeploymentRequest.autoDeploy` (originally cited at `model.ts:1086-1089`): Fixed in regeneration on 2026-05-20 — `autoDeploy` is no longer a field on `CreateAppDeploymentRequest`. -- #L16 `GitRepository.autoDeploy` (originally cited at `model.ts:1086, 1211`): Fixed in regeneration on 2026-05-20 — `GitRepository.autoDeploy` is no longer present. -- #O7 `ApplicationStatus.runningInstances` vs `ComputeStatus.activeInstances` (originally cited at `model.ts:?`): Fixed in regeneration on 2026-05-20 — `runningInstances` no longer exists on `ApplicationStatus`. diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index 58da0aa9..2ed7cec4 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -11,10 +11,10 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 1 | -| Medium | 6 | +| Medium | 4 | | Low | 5 | | Observation | 3 | -| **Total** | **15** | +| **Total** | **13** | Headline themes: @@ -81,37 +81,7 @@ verbs vs. UC sibling APIs `update…`. If the API spec dictates `Set`, this is correct; the audit flags it because the verb is unique within UC. -### M3. `artifactMatchers` field is a Boolean-sounding plural of a matcher -type that is itself a noun-from-verb - -- **File / line:** `src/v1/model.ts:23, 48`. -- **Category:** #15 generic field name losing meaning. -- **Current:** `artifactMatchers?: ArtifactMatcher[]`. -- **Suggestion:** Consider `allowedPatterns` or `patterns` (matching the - field's own JSDoc: "A list of allowed artifact match patterns"). At - minimum, the inline doc should explain that an "ArtifactMatcher" is one - rule (artifact + match-type), not a function. -- **Rationale:** The doc comment ("allowed artifact match patterns") - describes a different mental model than the type name suggests. A reader - encountering `artifactMatchers` may expect predicate functions rather than - a `{artifact, matchType}` rule object. Note: this name *does* match the - Go SDK convention, so changing it would be a breaking divergence. - -### M4. `artifact` (the field inside `ArtifactMatcher`) is dangerously generic - -- **File / line:** `src/v1/model.ts:34`. -- **Category:** #1 vague/generic without domain context; #15 generic field - name losing meaning. -- **Current:** `artifact?: string`. -- **Suggestion:** `artifactPath` or `artifactPattern` (the docstring says - "The artifact path or maven coordinate"). -- **Rationale:** Inside a type already named `ArtifactMatcher`, `artifact` - contributes no information; the actual semantic is "the path/coordinate - this rule matches against." Either of `artifactPath` or `artifactPattern` - reflects that. Caveat: matches the Go SDK exactly, so a rename would - break the 1:1 port. - -### M5. `req` parameter name on `Client.getArtifactAllowlist` / +### M3. `req` parameter name on `Client.getArtifactAllowlist` / `setArtifactAllowlist` - **File / line:** `src/v1/client.ts:67, 97`. @@ -125,7 +95,7 @@ type that is itself a noun-from-verb it reads as Go-translated code. (Note: `resp` shows up locally in the same file at lines 71, 84, 102, 115 — a separate, lower-priority issue.) -### M6. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak +### M4. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak - **File / line:** `src/v1/model.ts:15`. - **Category:** proto-architectural-leak — `Proto` infix / nested-enum @@ -275,15 +245,15 @@ constant. Not a naming defect, but typical naming-audit findings include Type & symbol checklist: - [x] `ArtifactType` enum (4 members) → no defect. -- [x] `ArtifactMatcher_MatchType` enum (2 members) → M6. +- [x] `ArtifactMatcher_MatchType` enum (2 members) → M4. - [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O1. -- [x] `ArtifactMatcher` interface (2 fields) → M3, M4. +- [x] `ArtifactMatcher` interface (2 fields) → no defect. - [x] `GetArtifactAllowlistRequest` interface (1 field) → no defect. - [x] `SetArtifactAllowlistRequest` interface (5 fields) → H1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → no defect. -- [x] `getArtifactAllowlist(req, options)` method → M2, M5. -- [x] `setArtifactAllowlist(req, options)` method → M2, M5. +- [x] `getArtifactAllowlist(req, options)` method → M2, M3. +- [x] `setArtifactAllowlist(req, options)` method → M2, M3. - [x] `HttpCallOptions` interface → no defect. - [x] `executeCall` function → L1. - [x] `readAll` private function → no defect (name fits idiom). @@ -296,18 +266,3 @@ Type & symbol checklist: - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). --- - -## Fixed - -- #H1 `GetArtifactAllowlist` (originally cited at `src/v1/model.ts:39`): - Fixed in regeneration on 2026-05-20 — renamed to - `GetArtifactAllowlistRequest`; verb/noun overload with the client method - resolved. -- #H2 partial — `SetArtifactAllowlist` (originally cited at - `src/v1/model.ts:44–55`): Fixed in regeneration on 2026-05-20 — renamed to - `SetArtifactAllowlistRequest`. The response-only-fields concern was split - off into the new H1 above and remains open. -- #O1 Bare `GetX`/`SetX` request shapes (originally cited as a repo-wide - pattern across `catalogs`, `connections`, `clusters`, `externallocations`, - `clusterpolicies`): Fixed in regeneration on 2026-05-20 — `Request` - suffix is now applied across the generator. diff --git a/.agent/naming-audit/billableusagedownload.md b/.agent/naming-audit/billableusagedownload.md index a156f199..a180c8c1 100644 --- a/.agent/naming-audit/billableusagedownload.md +++ b/.agent/naming-audit/billableusagedownload.md @@ -3,12 +3,12 @@ **Path:** `packages/billableusagedownload/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CSV export of billable Databricks usage logs for a given month range. Single endpoint: `GET /api/2.0/accounts/{account_id}/usage/download`. No CRUD surface, no enums, no list/page semantics — just one streaming download method. -**Total weird names flagged:** 20 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 4 | | Medium | 6 | | Low | 5 | | Observation | 4 | @@ -39,45 +39,39 @@ - **Suggested name:** Keep the field names; change the types to `string` (required) on both. Worth also renaming `startMonth`/`endMonth` to something more self-documenting like `fromMonth`/`toMonth` or `startMonth`/`untilMonth` — current names are fine. - **Rationale:** TS strict mode rewards required fields with non-optional types; the doc and the type should agree. The Go SDK probably models these as `string` (empty-string defaults), which is a Go-ism; in TS, required strings should not carry `| undefined`. -### 5. `DownloadRequest.personalData: boolean` field name — `src/v1/model.ts:26` -- **Why weird:** `personalData` is a boolean named after a noun. The field actually controls "include PII in the download". Boolean fields should read as predicates: `includePersonalData`, `includePii`, `withPii`. As written, the field reads as "the personal data" — a thing — not a flag. -- **Category:** 6 (misleading — name implies a value, type is a flag), 1 (vague — "personal data" without a verb is not actionable), 15 (generic field name losing meaning). -- **Suggested name:** `includePersonalData` (or `includePii`). Keep wire field as `personal_data`. -- **Rationale:** TS convention for booleans is `is*` / `has*` / `include*` / `should*`. Without a verb, `if (req.personalData)` reads as "if there is personal data" rather than "if personal data is enabled". The JSDoc has to spell out "Specify whether to include..." precisely because the field name doesn't. - ## Medium severity -### 6. `DownloadRequest.accountId` field — `src/v1/model.ts:8` +### 5. `DownloadRequest.accountId` field — `src/v1/model.ts:8` - **Why weird:** The `accountId` lives on the request DTO *and* on `ClientOptions` (see `client.ts:39`). The client falls back from `req.accountId` to `this.accountId` (`client.ts:69`). Having the same identifier in two places, with one-overrides-the-other semantics, is a footgun: callers may set it once on the client and forget that a stale request value silently shadows it. - **Category:** 12 (duplicate concept across types), 19 (underspecified id — same `accountId` means different things at different layers). - **Suggested name:** Drop `accountId` from `DownloadRequest`. Make it a client-level concern only (it's a path parameter, not a body field). If per-call override is needed, document it explicitly. - **Rationale:** The JSDoc on the field is a verbose explanation about getting your account ID from the console — content that belongs in `ClientOptions.accountId`, not duplicated per request. Removing it simplifies the API surface and eliminates the fallback chain in `client.ts`. -### 7. `Client` class is unprefixed — `src/v1/client.ts:22` +### 6. `Client` class is unprefixed — `src/v1/client.ts:22` - **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-billableusagedownload/v1'`, then has to rename it (`import {Client as BillableUsageClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Consistent across the SDK but worth flagging. - **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). - **Suggested name:** `BillableUsageDownloadClient` or `BillableUsageClient`. Or expose a namespace export instead of a bare class. - **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. The SDK could expose `import * as billableUsage from '@databricks/sdk-billableusagedownload/v1'` and remove the `Client` symbol entirely, letting `billableUsage.Client` be the qualified name. -### 8. `Client.download` method name — `src/v1/client.ts:65` +### 7. `Client.download` method name — `src/v1/client.ts:65` - **Why weird:** A bare `download` verb on the client. Outside the package context, `client.download(...)` reads as "download something" — the package name is the disambiguator. If a user composes multiple SDK clients (`billing.download()`, `files.download()`), the method names collide cognitively. Compare with `usagedashboards.Client` which probably exposes `createBillingUsageDashboard()` / `getBillingUsageDashboard()` — verb + domain noun. - **Category:** 1 (vague), 17 (inconsistent verb-pattern across sibling packages). - **Suggested name:** `downloadBillableUsage` (matches the request-type rename) or, if the package gets folded into `billing`, `downloadUsage`. - **Rationale:** Domain-qualified method names read better when imported into application code. Even within the package, `billableUsageDownloadClient.download()` has a pleasing redundancy that a single naked `download()` does not. -### 9. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:17` +### 8. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:17` - **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. - **Category:** 1 (vague), 15 (generic field name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency — same finding appears in every audited package. Worth normalising at generator level. -### 10. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +### 9. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` - **Why weird:** `client.ts` does its own query-param construction inline (lines 70-79) using `new URLSearchParams()` and three `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called. - **Category:** 11 (unused public helper — dead surface area). - **Suggested name:** Remove the export, or drop the function entirely if no caller in this package needs it. - **Rationale:** Every generated package ships this helper; in `billableusagedownload` (which has zero list/page operations and only three query params), the inline approach is clearly what the generator chose. The unused export is a generator artefact that should be pruned. -### 11. `executeHttpCall` is exported but unused — `src/v1/utils.ts:65` +### 10. `executeHttpCall` is exported but unused — `src/v1/utils.ts:65` - **Why weird:** `utils.ts` exports both `executeHttpCall` and `sendAndCheckError`; only the latter is used in `client.ts:96`. `executeHttpCall` is dead surface area. - **Category:** 11 (unused public helper — dead surface area). - **Suggested name:** Remove `executeHttpCall`; the package only needs `sendAndCheckError`. @@ -85,31 +79,31 @@ ## Low severity -### 12. `HttpCallOptions` — `src/v1/utils.ts:15` +### 11. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, ...). Within this file the imported `Options` from `@databricks/sdk-core/api` (line 3) collides with this local interface name. - **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). - **Suggested name:** `HttpCallContext` (it is not user-facing options; it is an internal bag of args). - **Rationale:** Distinguish internal context bags from user-tunable option structs. Same finding as `abacpolicies` audit #37. -### 13. `readAll` helper — `src/v1/utils.ts:40` +### 12. `readAll` helper — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Also reads the body twice in `sendAndCheckError` (lines 176-181) — once for body content, once for error parsing — though this is fine because non-2xx is handled separately. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 14. `buildHttpRequest` parameter order — `src/v1/utils.ts:96-102` +### 13. `buildHttpRequest` parameter order — `src/v1/utils.ts:96-102` - **Why weird:** `(method, url, headers, signal?, body?)` — positional 5-arg function with two optional trailing params. Calling site (`client.ts:86`) passes `('GET', fullUrl, headers, callSignal)` — fine — but a caller adding a body has to remember the order. An options object would be clearer. - **Category:** 1 (no name issue per se), Observation. - **Suggested name:** Take `{method, url, headers, signal?, body?}` as an options object. - **Rationale:** Less of a naming issue, more of an API shape concern. Not a blocker. -### 15. `req` / `resp` / `opts` / `httpReq` / `httpResp` abbreviations — `src/v1/client.ts:66,68,86,87,...` +### 14. `req` / `resp` / `opts` / `httpReq` / `httpResp` abbreviations — `src/v1/client.ts:66,68,86,87,...` - **Why weird:** Three-letter abbreviations for local variables (`req`, `resp`, `opts`). The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling out four-letter names costs nothing and improves readability. -### 16. `httpClient: HttpClient` field — `src/v1/client.ts:27` / `src/v1/utils.ts:17` +### 15. `httpClient: HttpClient` field — `src/v1/client.ts:27` / `src/v1/utils.ts:17` - **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention is widespread in this SDK. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the (different) outer `Client` class in the same file. @@ -117,25 +111,25 @@ ## Observations -### 17. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` +### 16. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` The field is typed `ReadableStream` (no type parameter) rather than `ReadableStream`. Every other use in the codebase (`packages/files/src/v1/model.ts`, `utils.ts:42`, `utils.ts:101`) uses `ReadableStream` explicitly. The unparameterised version is the global lib type which is structurally `ReadableStream`, weakening type safety for callers. - **Category:** 6 (misleading — type appears typed but is in fact `any`-typed), 17 (inconsistent across the SDK). - **Suggested name:** `contents?: ReadableStream | undefined`. -### 18. Wire/TS mapping is correct +### 17. Wire/TS mapping is correct The TS field `personalData` maps to wire `personal_data`, `startMonth` -> `start_month`, etc. The query-param construction in `client.ts:70-79` does it manually and correctly. Good — no naming bug here, just noting that no schema/codec layer is needed because this is a query-string-only request. -### 19. No enums, no list-types, no FieldMask +### 18. No enums, no list-types, no FieldMask This package is one of the simplest in the SDK: zero enums, zero list/paginated types. Audit-rule categories 2 (redundant enum prefix), 18 (long enum values), and 13 (verb tense inconsistency) do not apply here. That's why the finding count is comparatively low. -### 20. CSV body is undocumented in types +### 19. CSV body is undocumented in types `DownloadResponse.contents` is `ReadableStream` (untyped) but the JSDoc on `Client.download` (`client.ts:51-64`) makes clear the body is CSV. There is no type-level hint or branded type to mark this — a caller might treat the stream as JSON. Worth considering a documented branded type (`type CsvStream = ReadableStream & {readonly _csvBrand: unique symbol}`) or, more practically, a Content-Type assertion. Not a name problem; flagged because the response shape is uninformative. ## Domain glossary - `DBU` — Databricks Unit; standard billing unit for Databricks compute. Notably absent from this package's types and JSDoc — no DBU-related fields surface here despite the package being about billable usage. (User-mentioned in the task; verified via grep that the literal "DBU" never appears.) - `PII` — Personally Identifiable Information. Surfaced indirectly as the `personalData` field flag. - `E2` — Databricks deployment architecture. Mentioned in the JSDoc for `accountId` ("For non-E2 account types, get your account ID from the Accounts Console..."). -- `account ID` — Databricks account identifier. Surfaces as both `ClientOptions.accountId` and `DownloadRequest.accountId` (with fallback semantics — see finding #6). +- `account ID` — Databricks account identifier. Surfaces as both `ClientOptions.accountId` and `DownloadRequest.accountId` (with fallback semantics — see finding #5). - `CSV` — Comma-Separated Values, the wire format of the download body. Documented in JSDoc, not in types. - `usage logs` — The actual data being downloaded (billable usage records). Not a type/field; only appears in JSDoc. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index 42b91507..11ce4ee4 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,13 +3,13 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 28 +**Total weird names flagged:** 22 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 10 | +| High | 3 | +| Medium | 7 | | Low | 7 | | Observation | 5 | @@ -21,31 +21,13 @@ - **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). - **Rationale:** A bare `Filter` provides zero discoverability and the package directly forces a collision with `usagepolicy.Filter`. Both packages target the same account-level surface and a consumer will frequently import both. -### 2. `CreateBudgetPolicyRequest.requestId` documented as idempotency key — `src/v1/model.ts:40` -- **Why weird:** JSDoc: "This request is only idempotent if a `request_id` is provided." — wire-name leak (`request_id`) in the docs of the TS field `requestId`. Also, `requestId` is a generic field name that does not signal "idempotency key" to callers; the JSDoc is the only place that mentions idempotency. -- **Category:** 1 (vague — `requestId` could mean anything: trace id, correlation id, idempotency key), 15 (generic field name losing meaning). -- **Suggested name:** `idempotencyKey` (matches the conventional name used by Stripe, Square, and most REST APIs), and fix the JSDoc to use TS field name `requestId` rather than wire name `request_id`. -- **Rationale:** A user reading the field name should know it controls idempotency. The current name + docstring split forces a doc-read for every caller. - -### 3. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:116-121` +### 2. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:116-121` - **Why weird:** Docstring says: "A page token, received from a previous `ListServerlessPolicies` call ... When paginating, all other parameters provided to `ListServerlessPoliciesRequest` must match the call that provided the page token." — refers to an entirely different RPC name (`ListServerlessPolicies`) that does not exist in this SDK. The actual method is `listBudgetPolicies`. - **Category:** 6 (misleading — docs describe a different operation), 14 (Go-style internal proto name leaked). - **Suggested name:** Fix docstring to say `ListBudgetPolicies`/`ListBudgetPoliciesRequest`. - **Rationale:** Generator bug. Confusing for readers and grep-hostile (searching for `ListBudgetPolicies` won't surface the doc context). -### 4. `BudgetPolicy.policyId` / `BudgetPolicy.policyName` field naming inside `BudgetPolicy` type — `src/v1/model.ts:16,23` -- **Why weird:** Fields on the `BudgetPolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. -- **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `BudgetPolicy.id` is `policyId`). -- **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). -- **Rationale:** `budgetPolicy.id` reads better than `budgetPolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. - -### 5. `BudgetPolicy.bindingWorkspaceIds` — `src/v1/model.ts:30` -- **Why weird:** `binding` as a noun-prefix is unusual; reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this budget policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). -- **Category:** 1 (vague — `binding` is a generic noun: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists, but the field is just a list of workspace IDs). -- **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. -- **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. - -### 6. Type-name collision with `budgets` package — `src/v1/model.ts:14` vs `packages/budgets/src/v1/model.ts:50` +### 3. Type-name collision with `budgets` package — `src/v1/model.ts:14` vs `packages/budgets/src/v1/model.ts:50` - **Why weird:** This package's central entity is `BudgetPolicy`; the sibling `budgets` package exports `BudgetConfiguration` (the spend-alert budget object). The two are semantically unrelated — `BudgetPolicy` is a tag-attachment policy that influences cost attribution, and `BudgetConfiguration` is a spend threshold + alert. A user importing both packages sees `BudgetPolicy` and `BudgetConfiguration` side by side and may reasonably wonder if `BudgetPolicy` is the policy *for* a `BudgetConfiguration`. The names do not differentiate clearly. - **Category:** 12 (duplicate concepts with confusing names), 1 (the `Budget` prefix overloads two unrelated domain ideas). - **Suggested name:** Consider `CostAttributionPolicy` or `UsageTaggingPolicy` for what `budgetpolicy` actually models (per the JSDoc on `BudgetPolicy`: "Contains the BudgetPolicy details" — tags + workspace bindings, no spend or threshold concept anywhere). @@ -53,61 +35,43 @@ ## Medium severity -### 7. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` +### 4. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. - **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. -### 8. `Filter.policyName` / `Filter.creatorUserId` / `Filter.creatorUserName` — `src/v1/model.ts:80,85,90` -- **Why weird:** `Filter` has three optional fields whose names imply they specify *one* policy, but the JSDoc says they apply as substring/equality filters across the list. Names like `policyName: 'foo'` read as "the policy named foo"; what it actually means is "policies whose name contains 'foo'". The JSDoc clarifies but the name misleads. -- **Category:** 6 (misleading — singular noun for a substring/multi-match filter). -- **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to `creatorUserNames: string[]`). -- **Rationale:** Filter DSLs benefit from explicit operators. Bare names suggest exact match. - -### 9. `Filter.creatorUserId: number` vs `Filter.creatorUserName: string` — `src/v1/model.ts:85,90` -- **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number` (a JS-unsafe representation for 64-bit IDs — but at least the Go SDK numeric type is `int64` here), while `creatorUserName` is `string`. -- **Category:** 12 (duplicate concept — two ways to filter on the same domain object), 19 (underspecified ID — `creatorUserId` is a numeric id from an unknown id space). -- **Suggested name:** Collapse to `creator?: Creator` with `{id?: number; name?: string}`, or document AND/OR. -- **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine. Even the JSDoc says "If unspecified, all policies will be returned" on each one — but doesn't say what happens if both are set. - -### 10. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` +### 5. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 30). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 30 and `Filter.creatorUserId` here. -### 11. `SortSpec` type — `src/v1/model.ts:147` +### 6. `SortSpec` type — `src/v1/model.ts:147` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 12. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:148` +### 7. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:148` - **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. - **Category:** Observation (typo). - **Suggested name:** Fix spelling. - **Rationale:** Minor; flagging because it surfaces in IntelliSense. -### 13. `ListBudgetPoliciesResponse.policies` field name — `src/v1/model.ts:134` -- **Why weird:** Field `policies` of type `BudgetPolicy[]`. Within the `budgetpolicy` package, `policies` is fine — but within a multi-package consumer with `BudgetConfigurations.budgets` (line 170 of budgets) and `usagepolicy.policies`, the field `policies` becomes ambiguous when copy-pasted. -- **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on request). -- **Suggested name:** `budgetPolicies: BudgetPolicy[]`. -- **Rationale:** Tied to type rename suggestion #4. If `BudgetPolicy` becomes `Policy` (in-package), `policies` is fine; otherwise `budgetPolicies` matches. - -### 14. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:144` +### 8. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:144` - **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listBudgetPoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. -### 15. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:142` +### 9. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:142` - **Why weird:** Doc reads "In this field is omitted, there are no previous pages." — "In" should be "If". - **Category:** Observation (typo). - **Suggested name:** Fix doc. - **Rationale:** Generated; surfaces in IntelliSense. -### 16. `SortSpec_Field` enum name — `src/v1/model.ts:6` +### 10. `SortSpec_Field` enum name — `src/v1/model.ts:6` - **Why weird:** Proto-architectural-leak: the underscore-joined `ParentType_NestedType` form is the protobuf/Go-SDK convention for emitting nested enum types into a flat namespace. TS already supports namespaces and modules natively, so the underscore is a wire-protocol artifact bleeding into the public TS API. The eslint-disable comment on the prior line even labels it "Proto-style nested enum name", confirming the generator knows it is non-idiomatic. - **Category:** Proto-architectural leak (proto-style nested-type encoding leaking into TS identifiers). - **Suggested name:** `SortField` (drop the `Spec_` prefix entirely; the enum stands on its own as the set of sortable fields) or `SortSpecField` (camel-join, no underscore). @@ -115,43 +79,43 @@ ## Low severity -### 17. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:44-46` +### 11. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:44-46` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. - **Category:** Observation, 14 (wire-style identifiers in TS docs). - **Suggested name:** Fix the doc to reference TS field names. - **Rationale:** Editing UX: hovers should show TS, not proto. -### 18. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:157` +### 12. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:157` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). - **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. - **Rationale:** Real bug. -### 19. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 13. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. -### 20. `HttpCallOptions` — `src/v1/utils.ts:15` +### 14. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. -### 21. `readAll` — `src/v1/utils.ts:40` +### 15. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 22. `flattenQueryParams` — `src/v1/utils.ts:123` +### 16. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 17. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -159,27 +123,27 @@ ## Observations -### 24. `Client` class plain name — `src/v1/client.ts:46` +### 18. `Client` class plain name — `src/v1/client.ts:46` Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 25. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 19. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. -### 26. Action-verb conventions in `Client` +### 20. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 27. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +### 21. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. - **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). -### 28. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 22. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. @@ -204,6 +168,3 @@ The three together blur the boundary between "policy that classifies usage" (bud - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (20 lines): read fully. - Cross-referenced: `packages/budgets/src/v1/model.ts`, `packages/budgets/src/v1/index.ts`, `packages/usagepolicy/src/v1/index.ts` for sibling-package overlap. - -## Fixed -- #20 `budgetPolicyFieldMask` function (originally cited at `src/v1/model.ts:278`): Fixed in regeneration on 2026-05-20 — the `budgetPolicyFieldMask` helper and `FieldMask` import are no longer emitted in `model.ts`. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 7581e972..8ab92c88 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -82,42 +82,14 @@ rename suggestion. Findings are grouped by category. weight here (see also F7). If the type *must* keep the "Config" word, `BudgetAlertActionConfig` is shorter and clearer. -#### F1.2 — `target` field of `ActionConfiguration` (MEDIUM) -- **Where:** `model.ts:32`. -- **Why flagged:** "target" alone is generic — it could be a URL, - Slack channel, account ID, etc. The JSDoc clarifies "For example, - an email address," but the field name does not. Compare to similar - webhook-style "target" fields elsewhere in the SDK. -- **Suggestion:** `recipient` or `destination`. If the value really is - always an email today, `emailAddress` is unambiguous; `recipient` - is more future-proof. - -#### F1.3 — `target` (cont.): also generic at the type-domain level (LOW) -- **Where:** `model.ts:32`. -- See category 16 (F16.1) for the contradiction angle — "target" is - also too generic *and* implies a generic destination when the - domain is narrower. - -#### F1.4 — `values` (`BudgetConfigurationFilter_Clause`, - `BudgetConfigurationFilter_WorkspaceIdClause`) (LOW) -- **Where:** `model.ts:83, 95`. -- **Why flagged:** "values" is generic. Inside a clause it is - acceptable because the operator/values pair is a well-known proto - pattern, but a more descriptive name (`workspaceIds`, `tagValues`) - would document intent without a JSDoc. -- **Suggestion:** Leave for parity with proto/Go, but consider - specializing in TS: - `BudgetConfigurationFilter_WorkspaceIdClause.values → workspaceIds`, - `BudgetConfigurationFilter_Clause.values → tagValues`. - -#### F1.5 — `operator` (LOW) +#### F1.2 — `operator` (LOW) - **Where:** `model.ts:82, 94`. - **Why flagged:** Generic given there is only one allowed value (`IN`). Acceptable for forward-compat but worth a JSDoc note. - **Suggestion:** Keep, but add JSDoc clarifying allowed values and semantics (currently has none). -#### F1.6 — `Client` class name (MEDIUM) +#### F1.3 — `Client` class name (MEDIUM) - **Where:** `client.ts:49`, `index.ts:3`. - **Why flagged:** Every package in this SDK exports a `Client`. Re-exported in a barrel like @@ -128,7 +100,7 @@ rename suggestion. Findings are grouped by category. package-qualified import convention, or rename to `BudgetsClient` consistently across packages. Cross-cutting. -#### F1.7 — `req` parameter name on every client method (LOW) +#### F1.4 — `req` parameter name on every client method (LOW) - **Where:** `client.ts:80, 112, 140, 174, 216, 234`. - **Why flagged:** `req` is a Go-ism (see category 14). It is also generic — a reader has to look at the type to know what the @@ -186,7 +158,7 @@ _None._ #### F5.1 — `req` (LOW, Go-ism) - **Where:** `client.ts` every method, `utils.ts:103`. -- Already flagged under F1.7 / F13.1. +- Already flagged under F1.4 / F13.1. #### F5.2 — `resp` (LOW, Go-ism) - **Where:** `client.ts:88, 116, 150, 193, 242`; `utils.ts:73, 75, 81, 84, 88`. @@ -377,19 +349,7 @@ _None._ #### F8.3 — `tags: BudgetConfigurationFilter_TagClause[]` (acceptable) - Plural-array, no mismatch. -#### F8.4 — `workspaceId: BudgetConfigurationFilter_WorkspaceIdClause` - on `BudgetConfigurationFilter` (HIGH) -- **Where:** `model.ts:72`. -- **Why flagged:** The field is singular `workspaceId` but its type - is a clause whose `values: number[]` holds *multiple* workspace IDs. - Reading `filter.workspaceId.values` is confusing — you would expect - `workspaceId` to be one ID, but it's a clause. -- **Suggestion:** Rename the field to `workspaceIds`, `workspaceFilter`, - or `workspaces`. Pair with renaming the type from - `WorkspaceIdClause` to `WorkspaceFilter`. The whole clause - abstraction is unnecessary in TS — see F10. - -#### F8.5 — `budgets` field in `ListBudgetConfigurationsRequest_Response` +#### F8.4 — `budgets` field in `ListBudgetConfigurationsRequest_Response` (acceptable) - Plural, correct. @@ -405,24 +365,12 @@ _None._ `BudgetConfiguration`, not on an array. - **Suggestion:** Keep; not worth churn. -#### F9.2 — `target` field (LOW) -- **Where:** `model.ts:32`. -- **Why flagged:** `target` collides with `EventTarget` / - `event.target` semantics in DOM. Minor. -- **Suggestion:** See F1.2 — rename to `recipient` resolves both. - -#### F9.3 — `values` (LOW) -- **Where:** `model.ts:83, 95`. -- **Why flagged:** `Object.values` is a popular built-in. Property - shadowing only, not a true collision. -- **Suggestion:** See F1.4 — specialize per type. - -#### F9.4 — `Headers` constructor use vs DOM `Headers` (acceptable) +#### F9.2 — `Headers` constructor use vs DOM `Headers` (acceptable) - **Where:** `client.ts:90, 118, 152, 195, 244`. - The code intentionally uses the global `Headers`. No new identifier shadows it. Fine. -#### F9.5 — `URLSearchParams`, `TextDecoder` (acceptable) +#### F9.3 — `URLSearchParams`, `TextDecoder` (acceptable) - Used as global classes, no shadowing. --- @@ -563,46 +511,21 @@ _None._ ### 14. Generic field names losing meaning -#### F14.1 — `target` on `ActionConfiguration` (HIGH) -- See F1.2 / F1.3. +#### F14.1 — `operator` on Clauses (LOW) +- See F1.2. -#### F14.2 — `values` on Clauses (MEDIUM) +#### F14.2 — `req` parameter on every client method (HIGH) - See F1.4. -#### F14.3 — `operator` on Clauses (LOW) -- See F1.5. - -#### F14.4 — `key` and `value` on `BudgetConfigurationFilter_TagClause` - (LOW) -- **Where:** `model.ts:88-89`. -- **Why flagged:** "key/value" is generic enough that without the - wrapping type, readers can't tell it is a *tag* key. Acceptable - because the wrapping type's name supplies context, but - `tagKey`/`tagValue` would be self-documenting. -- **Suggestion:** Optional rename to `tagKey`/`tagValue`. Wire field - is `key`/`value`, so renaming costs an extra mapping in the - marshaller. - -#### F14.5 — `req` parameter on every client method (HIGH) -- See F1.7. - --- ### 15. Field contradicting type domain -#### F15.1 — `ActionConfiguration.target` (HIGH) -- **Where:** `model.ts:32`. -- **Why flagged:** Type domain is "alert action" (currently - email-only); field name is the generic "target". JSDoc admits "For - example, an email address." Type-domain dissonance. -- **Suggestion:** `recipient` (or `emailAddress` if email-only is - hard-wired). See F1.2. - -#### F15.2 — `BudgetConfigurationFilter_WorkspaceIdClause` typed +#### F15.1 — `BudgetConfigurationFilter_WorkspaceIdClause` typed as `number[]` (MEDIUM) - **Where:** `model.ts:95`. See F6.1. -#### F15.3 — `LIST_PRICE_DOLLARS_USD` member on +#### F15.2 — `LIST_PRICE_DOLLARS_USD` member on `AlertConfigurationQuantityType` (LOW) - **Where:** `model.ts:10`. - **Why flagged:** Name implies *currency*, type is "quantity type". @@ -647,22 +570,9 @@ _None._ context — both are unambiguous in this package; the issue is inconsistency. -#### F18.2 — `actionConfigurationId`, `alertConfigurationId` (LOW) -- **Where:** `model.ts:28, 37`. -- **Why flagged:** Long. If `ActionConfiguration` renames to - `BudgetAlertAction`, the ID becomes `budgetAlertActionId` - (still long) or just `actionId` inside its parent. -- **Suggestion:** Inside the parent, the local field name can be - just `id`. The full form is only needed when referenced - externally. - -#### F18.3 — `accountId` (acceptable) +#### F18.2 — `accountId` (acceptable) - Specific enough; matches platform-wide convention. -#### F18.4 — `workspaceId` on `BudgetConfigurationFilter` field, but - the field holds a *clause* not an ID (HIGH) -- See F8.4. The name *says* it is one ID; it isn't. - --- ## Package overlap: `budgets` vs `budgetpolicy` @@ -714,24 +624,24 @@ This SDK exposes two separate packages whose names both start with | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Vague / generic | 7 | +| 1 | Vague / generic | 4 | | 2 | Redundant enum prefixes | 0 | | 3 | Acronym casing | 4 (4 acceptable) | | 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 7 | | 6 | Misleading names | 5 | | 7 | Overly verbose | 4 | -| 8 | Singular / plural mismatch | 5 (3 acceptable) | -| 9 | Reserved-word collisions | 5 (3 acceptable) | +| 8 | Singular / plural mismatch | 4 (3 acceptable) | +| 9 | Reserved-word collisions | 3 (3 acceptable) | | 10 | Empty / trivial wrappers | 0 | | 11 | Duplicate concepts | 5 | | 12 | Verb-tense inconsistency | 2 (1 acceptable) | | 13 | Go / Java-style names | 2 (1 acceptable) | -| 14 | Generic field names | 5 | -| 15 | Field contradicting type domain | 3 | +| 14 | Generic field names | 2 | +| 15 | Field contradicting type domain | 2 | | 16 | Inconsistent action verbs | 1 (1 acceptable) | | 17 | Long enum values | 3 | -| 18 | Underspecified IDs | 4 (1 acceptable) | +| 18 | Underspecified IDs | 2 (1 acceptable) | | OVERLAP | budgets vs budgetpolicy | 3 | --- @@ -743,17 +653,12 @@ This SDK exposes two separate packages whose names both start with 2. **F7.1 / F7.3 / F11.1:** Collapse `BudgetConfiguration`, `CreateBudgetConfigurationBudget`, `UpdateBudgetConfigurationBudget` into a single `Budget` type. -3. **F8.4 / F18.4:** Rename - `BudgetConfigurationFilter.workspaceId` to `workspaces` (and - its type to `WorkspaceFilter`); fix singular-noun-for-plural-clause - mismatch. -4. **F1.1 / F1.2 / F15.1:** Rename `ActionConfiguration` - to `BudgetAlertAction`, `target` to `recipient`. -5. **F7.2:** Drop "Configuration" from request type names +3. **F1.1:** Rename `ActionConfiguration` to `BudgetAlertAction`. +4. **F7.2:** Drop "Configuration" from request type names (`CreateBudgetRequest`). -6. **F11.4:** Lift `accountId` to top-level on all request types +5. **F11.4:** Lift `accountId` to top-level on all request types (currently nested under `budget` for create/update only). -7. **F13.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ +6. **F13.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ `pkgJson` etc. across all generated code. --- @@ -879,7 +784,3 @@ This SDK exposes two separate packages whose names both start with `Request_Response` proto nesting; use flat `Response`. --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md index c6bbb6e7..d9f488d0 100644 --- a/.agent/naming-audit/bundle.md +++ b/.agent/naming-audit/bundle.md @@ -10,16 +10,15 @@ | Severity | Count | | ------------ | ----- | -| High | 5 | -| Medium | 13 | -| Low | 10 | -| Observation | 6 | -| **Total** | **34** | +| High | 3 | +| Medium | 6 | +| Low | 6 | +| Observation | 5 | +| **Total** | **20** | Dominant themes: 1. **`VersionComplete` is a misleading type name.** It is a noun that reads like a boolean predicate, but it actually carries a completion *reason* enum; the type, the field that holds it (`completionReason`), and the values disagree on terminology. -2. **`Resource` / `Operation` `name` is the qualified path, not a display name** — semantic overload of `name` recurs on every entity, while a separate `displayName` field also exists on `Deployment`/`Version`. Pure Google-AIP carry-over that loses meaning in TS. -3. **"Bundle" is in the URL but absent from type names**, while `DeploymentResourceType` (the domain catalog) is unrelated to the `Resource` interface (the per-deployment tracked item) — two distinct concepts share a confusable root. +2. **"Bundle" is in the URL but absent from type names**, while `DeploymentResourceType` (the domain catalog) is unrelated to the `Resource` interface (the per-deployment tracked item) — two distinct concepts share a confusable root. --- @@ -47,47 +46,13 @@ Compounding the issue: the `complete` action lives on a *method* called `complet --- -### H2. `name` field is semantically overloaded across every entity (Category: 6 — misleading; 12 — duplicate concepts) - -**Location:** `model.ts` — `Deployment.name`, `Operation.name`, `Resource.name`, `Version.name`, and on every request type (`CompleteVersionRequest.name`, `DeleteDeploymentRequest.name`, `GetDeploymentRequest.name`, `GetOperationRequest.name`, `GetResourceRequest.name`, `GetVersionRequest.name`, `HeartbeatRequest.name`). - -`name` is *not* a human-readable name — it is the fully-qualified resource path (`deployments/{deployment_id}/versions/{version_id}/operations/{resource_key}`). The actual human name lives in `displayName` on `Deployment` and `Version`. TypeScript users coming from non-Google APIs will read `deployment.name` and reasonably expect a string the user typed. - -Additionally, *all* request types reuse the field name `name` for entirely different scopes: -- `GetDeploymentRequest.name` → a deployment path. -- `GetOperationRequest.name` → an operation path (4 segments). -- `HeartbeatRequest.name` → a version path. -- `CompleteVersionRequest.name` → a version path. - -A reader cannot tell what `name` means without consulting the docstring of each request. - -**Suggested rename:** `resourceName` (matches the docstrings) or, even better, per-request specifics (`deploymentName`, `versionName`, `operationName`). At minimum, model entities should use a different field (`path` / `qualifiedName` / `resourceName`) so that "name" is freed up for the human-readable label. - ---- - -### H3. `DeploymentResourceType` enum and `Resource` interface share a confusable root concept (Category: 12 — duplicate concepts; 1 — vague) - -**Location:** `model.ts:19` (`DeploymentResourceType`) versus `model.ts:487-511` (`Resource`). - -These are two distinct things: -- `DeploymentResourceType` — a *taxonomy* enum of what kinds of Databricks objects a bundle can manage (`JOB`, `PIPELINE`, `CLUSTER`, …). -- `Resource` — a *tracked record* within a deployment, with a `resourceType` field of type `DeploymentResourceType`. - -Both will appear together in autocomplete (`Resource`, `Resource.resourceType: DeploymentResourceType`, `Resource.resourceKey`, `Resource.resourceId`), and a user can easily mistake `Resource` for the enum or vice-versa. The naming `Resource.resourceType` is also tautological — `Resource` already implies a resource, so `Resource.type` (typed as `DeploymentResourceType`) is enough. - -Compounding this: `Resource.resourceKey` (a key *within the bundle config*, e.g. `"jobs.foo"`) and `Resource.resourceId` (the actual workspace ID, e.g. a job ID) are dangerously similar. Both are strings, both contain "resource", differing only by `Key` vs. `Id`. Easy to swap by accident. - -**Suggested renames:** `Resource.type` (instead of `resourceType`), `Resource.bundleKey` or `Resource.configKey` (instead of `resourceKey`), `Resource.workspaceId` (instead of `resourceId`). Same renames apply to `Operation.resourceKey`, `Operation.resourceId`, and `CreateOperationRequest.resourceKey`. - ---- - -### H4. "Bundle" is missing from every type name despite being the package name (Category: 14 — Go/Java-style; 15 — generic names losing meaning) +### H2. "Bundle" is missing from every type name despite being the package name (Category: 14 — Go/Java-style; 15 — generic names losing meaning) **Location:** all exported types in `model.ts`, `index.ts:5-39`. The package is `@databricks/sdk-bundle` and every URL has `/api/2.0/bundle/`, yet not one type is `Bundle*`. Instead, the top-level entity is `Deployment` — extremely generic in TypeScript, where "deployment" appears in dozens of unrelated packages (jobs, model serving, apps, etc.). Outside the namespace, `Deployment` says nothing. -Worse: `Deployment` also unrelatedly resembles `DeploymentResourceType` (see H3), and `DeploymentStatus` is used both on the top-level deployment *and* describes one of the lifecycle terms `DELETED` that does not match the more recent `destroyTime` lifecycle. From outside this package, the type `Deployment` is non-self-describing. +Worse: `Deployment` also unrelatedly resembles `DeploymentResourceType` (see M2), and `DeploymentStatus` is used both on the top-level deployment *and* describes one of the lifecycle terms `DELETED` that does not match the more recent `destroyTime` lifecycle. From outside this package, the type `Deployment` is non-self-describing. Note: the user-supplied glossary explicitly flags "Bundle" as overloaded. The package solves the overload by *avoiding the word*, but this swap is not free — it just moves the ambiguity from "Bundle" to "Deployment". @@ -95,7 +60,7 @@ Note: the user-supplied glossary explicitly flags "Bundle" as overloaded. The pa --- -### H5. `HeartbeatRequest` / `HeartbeatResponse` and `heartbeat()` use a bare noun where the verb is `renew` (Category: 6 — misleading; 17 — inconsistent action verbs) +### H3. `HeartbeatRequest` / `HeartbeatResponse` and `heartbeat()` use a bare noun where the verb is `renew` (Category: 6 — misleading; 17 — inconsistent action verbs) **Location:** `model.ts:304-316`, `client.ts:398-421`. @@ -110,44 +75,7 @@ The semantics described in the docstring (`client.ts:391-397`) are *renew the lo ## Medium-Severity Findings -### M1. `resourceKey` doc says "Can be an arbitrary UTF-8 encoded string key" — name doesn't hint at format (Category: 19 — underspecified) - -**Location:** `Operation.resourceKey` (`model.ts:452-458`), `Resource.resourceKey` (`model.ts:493-497`). - -`resourceKey` is overloaded: it can be `"jobs.foo"`, `"pipelines.bar"`, `"jobs.foo.permissions"`, or `"files."`. The name `resourceKey` does not convey that it is a *dotted bundle config path*. `bundleConfigPath` or `configKey` would be more honest. - ---- - -### M2. `Operation.resourceId` and `Resource.resourceId` mix two different "IDs" with the deployment/version IDs (Category: 5 — cryptic; 19 — underspecified) - -**Location:** `Operation.resourceId` (`model.ts:470`), `Resource.resourceId` (`model.ts:504`), plus `CreateDeploymentRequest.deploymentId` (`model.ts:185`), `CreateVersionRequest.versionId` (`model.ts:220`), `Version.versionId` (`model.ts:527`), `Deployment.lastVersionId` (`model.ts:246`), `Resource.lastVersionId` (`model.ts:508`). - -`resourceId` is *the workspace ID of the underlying job/pipeline/etc.*, but `deploymentId` and `versionId` are *control-plane IDs internal to this service*. These three live side-by-side and look like they're all the same "kind" of ID, but they're not. A `workspaceId` / `workspaceObjectId` rename for `resourceId` would resolve this — the comment on the field literally says "actual resource in the workspace". - ---- - -### M3. `lastVersionId` exists on both `Deployment` and `Resource` with subtly different meaning (Category: 12 — duplicate; 16 — field contradicting type domain) - -**Location:** `Deployment.lastVersionId` (`model.ts:246`), `Resource.lastVersionId` (`model.ts:508`). - -- `Deployment.lastVersionId` = "the most recent deployment version" (any version). -- `Resource.lastVersionId` = "the last version where this resource was updated" (the most recent version *that touched this resource*). - -These should be named distinctly: `Deployment.latestVersionId` vs. `Resource.lastTouchedVersionId` (or `Resource.lastUpdatedInVersionId`). As written, the names are identical and the difference is buried in docstrings. - ---- - -### M4. `Resource.lastActionType` vs. `Operation.actionType` — same type, slightly different name (Category: 13 — verb-tense; 17 — inconsistent) - -**Location:** `model.ts:460` (`Operation.actionType`), `model.ts:506` (`Resource.lastActionType`). - -`Operation.actionType` is the action *of this operation*, `Resource.lastActionType` is the action *of the most recent operation*. The "last" prefix is the convention — that's fine — but pairing with M3 there's no consistent rule (the version field is plain `lastVersionId` without an explicit "last" affix differentiator; the action field is `lastActionType`). Picking one convention (`last*` everywhere, including `lastActionType` and `lastVersionId`) is fine, but make sure both follow the same template. - -Also: `actionType` (and `OperationActionType`) is itself tautological — `Operation` already implies action. `Operation.kind` or just `Operation.action: OperationAction` would suffice. - ---- - -### M5. `OperationActionType` enum name has the "action type" tautology (Category: 20 — type-suffix tautology) +### M1. `OperationActionType` enum name has the "action type" tautology (Category: 20 — type-suffix tautology) **Location:** `model.ts:83`. @@ -155,15 +83,15 @@ Reads as "the type of action type of operation". One of "action" or "type" is re --- -### M6. `DeploymentResourceType` is also tautological in compound form (Category: 20 — type-suffix tautology) +### M2. `DeploymentResourceType` is also tautological in compound form (Category: 20 — type-suffix tautology) **Location:** `model.ts:19`. -Reads as "deployment resource type", but the enum is the *catalog of resource kinds*, not a property of deployment. Just `ResourceKind` (or `BundleResourceKind` if you want to disambiguate from the `Resource` interface) would suffice. See H3 for the broader confusion. +Reads as "deployment resource type", but the enum is the *catalog of resource kinds*, not a property of deployment. Just `ResourceKind` (or `BundleResourceKind` if you want to disambiguate from the `Resource` interface) would suffice. --- -### M7. `completionReason` vs. enum `VersionComplete` mismatch (Category: 17 — inconsistent action verbs) +### M3. `completionReason` vs. enum `VersionComplete` mismatch (Category: 17 — inconsistent action verbs) **Location:** `Version.completionReason` (`model.ts:544`), `CompleteVersionRequest.completionReason` (`model.ts:169`). @@ -171,7 +99,7 @@ The field is `completionReason` (noun "reason" with "completion" adjective). The --- -### M8. `VersionComplete` enum values use inconsistent grammatical forms (Category: 13 — verb-tense) +### M4. `VersionComplete` enum values use inconsistent grammatical forms (Category: 13 — verb-tense) **Location:** `model.ts:128-136`. @@ -185,23 +113,15 @@ Three different grammatical structures for what should be parallel completion re --- -### M9. Method `heartbeat()` collides with idiomatic "is-alive" connotation (Category: 6 — misleading; 7 — overly verbose interactions) +### M5. Method `heartbeat()` collides with idiomatic "is-alive" connotation (Category: 6 — misleading; 7 — overly verbose interactions) **Location:** `client.ts:398`. -In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here it actively *mutates server state* (renews a lock). The verb suggests a read but it's a write. See H5 for suggested rename to `renewLock`. - ---- - -### M10. `Version.versionType` field — Java/Go-style redundancy (Category: 20 — type-suffix tautology; 14 — Go/Java) - -**Location:** `model.ts:539`. - -`version.versionType` reads as "the version type of the version". Prefer `Version.type: VersionType` (or rename the enum to `VersionKind`, see M11). Same root issue as `Resource.resourceType` and `Operation.actionType`. +In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here it actively *mutates server state* (renews a lock). The verb suggests a read but it's a write. See H3 for suggested rename to `renewLock`. --- -### M11. `VersionType` enum is generic (Category: 1 — vague) +### M6. `VersionType` enum is generic (Category: 1 — vague) **Location:** `model.ts:149`. @@ -209,34 +129,9 @@ In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here i --- -### M12. `Resource.state` and `Operation.state` use the same field name for different snapshots (Category: 15 — generic; 12 — duplicate) - -**Location:** `Resource.state` (`model.ts:499`), `Operation.state` (`model.ts:465`). - - -`state` here means "serialized config blob the CLI sent" — but `state` is one of the most overloaded terms in software. The docstrings clarify ("Serialized local config state"), but the names don't. `configState`, `configSnapshot`, or `state` distinct from `status` would help. Note `Resource.state` and `Resource.status`-style field would collide alphabetically in IDE autocomplete; there is currently no `Resource.status`, so `state` is at least non-conflicting. - ---- - -### M13. `errorMessage` on `Operation` is set only on failure but always typed `string | undefined` (Category: 6 — misleading; 15 — generic) - -**Location:** `model.ts:480`. - -Field name doesn't suggest tight coupling to `status === FAILED`. Could be `failureMessage` or `failureReason` to mirror `VersionComplete` style. Minor, but `failureMessage` reads more honestly. - ---- - ## Low-Severity Findings -### L1. `createdBy` vs. `destroyedBy` vs. `completedBy` past-tense consistency is good, but `targetName` is uncommented - -**Location:** `Deployment.createdBy` (`model.ts:248`), `Deployment.destroyedBy` (`model.ts:264`), `Version.completedBy` (`model.ts:550`). - -All three are well-named (`createdBy`, `destroyedBy`, `completedBy`). However, `Deployment.targetName` and `Version.targetName` are not parallel — they're not actor names, they're the bundle's *target* (a config concept). A reader might miscategorize on autocomplete. Consider `bundleTargetName` for explicitness. - ---- - -### L2. `destroyTime` / `destroyedBy` naming carry over from the destroy-vs-delete distinction (Category: 6 — misleading) +### L1. `destroyTime` / `destroyedBy` naming carry over from the destroy-vs-delete distinction (Category: 6 — misleading) **Location:** `Deployment.destroyTime` (`model.ts:259`), `Deployment.destroyedBy` (`model.ts:264`). @@ -244,7 +139,7 @@ The comment on `destroyTime` explicitly justifies the divergence from `deleteTim --- -### L3. `cliVersion` — abbreviation acceptable but flag for awareness (Category: 5 — cryptic abbreviation; 3 — acronym casing) +### L2. `cliVersion` — abbreviation acceptable but flag for awareness (Category: 5 — cryptic abbreviation; 3 — acronym casing) **Location:** `Version.cliVersion` (`model.ts:535`). @@ -252,23 +147,7 @@ The comment on `destroyTime` explicitly justifies the divergence from `deleteTim --- -### L4. `force` field is a boolean adverb, not a noun (Category: 1 — vague; 6 — misleading) - -**Location:** `CompleteVersionRequest.force` (`model.ts:175`). - -`force: boolean` is widely understood but extremely generic. The docstring says "force-completes the version even if the caller is not the original creator" — so `forceComplete` or `overrideOwnership` would be more honest. Bare `force` makes you read the docs to know what it forces. - ---- - -### L5. `parent` field on request types is generic (Category: 15 — generic; 1 — vague) - -**Location:** `CreateOperationRequest.parent` (`model.ts:196`), `CreateVersionRequest.parent` (`model.ts:212`), `ListOperationsRequest.parent` (`model.ts:351`), `ListResourcesRequest.parent` (`model.ts:383`), `ListVersionsRequest.parent` (`model.ts:415`). - -This is a Google AIP carry-over. `parent` is meaningful inside Google's resource hierarchy convention but loses meaning in TS where IDEs will surface it without context. Could be `deploymentName` (for `Create*Request`/`List*Request` whose parent is a deployment) or `versionName` (for `CreateOperationRequest`/`ListOperationsRequest` whose parent is a version). Different request types use `parent` for different scopes — same problem as `name` (see H2). - ---- - -### L6. `pageSize` / `pageToken` / `nextPageToken` are consistent with Google AIP — fine +### L3. `pageSize` / `pageToken` / `nextPageToken` are consistent with Google AIP — fine **Location:** all `List*Request`/`List*Response` types. @@ -276,7 +155,7 @@ No issue, just noting these names are uniform and correct. --- -### L7. `Operation` interface name collides with `Operation` from `@databricks/sdk-databricks` long-running-ops (Category: 12 — duplicate concepts) +### L4. `Operation` interface name collides with `Operation` from `@databricks/sdk-databricks` long-running-ops (Category: 12 — duplicate concepts) **Location:** `Operation` (`model.ts:441-481`). @@ -284,7 +163,7 @@ In many Databricks/Google APIs, `Operation` is the LRO (Long-Running Operation) --- -### L8. `Resource.resourceKey` vs `Operation.resourceKey` — same name, same role (good) +### L5. `Resource.resourceKey` vs `Operation.resourceKey` — same name, same role (good) **Location:** `model.ts:497`, `model.ts:458`. @@ -292,19 +171,11 @@ This is correct re-use — both reference the same bundle config path. No issue. --- -### L9. `deployments` request method names vs URL path consistency +### L6. `deployments` request method names vs URL path consistency **Location:** `Client.listDeployments` → `/api/2.0/bundle/deployments` (`client.ts:428`). -The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The method `listDeployments` matches. No issue, just noting the package's external resource is named "deployment" and the package is named "bundle", reinforcing the H4 observation that "Bundle" is in the URL but absent from type names. - ---- - -### L10. Acronym casing in `cliVersion`, `versionId`, `expireTime` — check SDK-wide - -**Location:** `Version.cliVersion` (`model.ts:535`), `Version.versionId` (`model.ts:527`), `HeartbeatResponse.expireTime` (`model.ts:315`). - -`expireTime` is a verb (or noun) form that differs from `createTime` (gerund-like) and `updateTime`. `expirationTime` would parallel `creationTime`. Or rename the others to `createdAt` / `updatedAt` / `expiresAt` style. The SDK has presumably picked a convention — note for cross-package consistency. +The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The method `listDeployments` matches. No issue, just noting the package's external resource is named "deployment" and the package is named "bundle", reinforcing the H2 observation that "Bundle" is in the URL but absent from type names. --- @@ -312,7 +183,7 @@ The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The ### O1. JSDoc on the `state` fields is good -`Resource.state` and `Operation.state` both clearly say "Serialized local config state". Naming could improve (M12) but doc-level disambiguation is solid. +`Resource.state` and `Operation.state` both clearly say "Serialized local config state". Doc-level disambiguation is solid. ### O2. Pagination wire shape is uniform and correct @@ -320,19 +191,15 @@ The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The ### O3. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing -The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is correct; the *name* is what is generic (see M12). +The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is correct. ### O4. Method `getResource` returns `Resource`, no naming collision -`client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level — only at the *interface* level (H3). +`client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level. ### O5. Comment on the `name`-vs-`destroy` divergence is appreciated -`Deployment.destroyTime` has an in-code justification (`model.ts:256-257`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on the `name` overload — a one-line "this is a fully-qualified resource path, not a display name" would help readers (see H2). - -### O6. The `HeartbeatResponse.expireTime` field has no `Lease`/`Lock` prefix - -The docstring says "new lock expiry time", but the field is just `expireTime`. Calling it `lockExpireTime` or `lockExpiresAt` would self-document. Marginal because of H5 (rename the whole method to `renewLock` and the field name becomes obvious from context). +`Deployment.destroyTime` has an in-code justification (`model.ts:256-257`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on other overloaded fields. --- @@ -340,17 +207,17 @@ The docstring says "new lock expiry time", but the field is just `expireTime`. C | Domain term | Meaning | Naming concerns? | | ------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------ | -| Bundle | Databricks Asset Bundle — a config-driven project deployed via `databricks bundle deploy`. | Absent from all type names (H4). | +| Bundle | Databricks Asset Bundle — a config-driven project deployed via `databricks bundle deploy`. | Absent from all type names (H2). | | Deployment | A registered bundle in the control plane. One per bundle target. Top-level entity in this API. | Overloaded with "deploy time" sense; generic outside the package. | | Version | A single deploy or destroy *run* of a bundle. Acquires an exclusive lock on the deployment. | OK; `Version` is clear within the package. | -| Operation | One resource action (create/update/delete/bind/...) recorded under a version. Append-only. | Collides with LRO `Operation` (L7). | -| Resource | A per-deployment record of one Databricks object the bundle manages (a job, a pipeline, etc.). | Confusable with `DeploymentResourceType` (H3). | -| `resource_key` | A dotted config path inside the bundle YAML (e.g. `"jobs.foo"`). | Generic name (M1, H3). | -| `resource_id` | The workspace-scoped ID of the underlying Databricks object (e.g. a job ID, pipeline ID). | Mixes with control-plane IDs (M2). | -| Heartbeat | Lock renewal RPC sent by the active CLI while a version is in progress. | Misleading name; should be "renew lock" (H5). | -| Target | A named profile within a bundle (e.g. `dev`, `staging`, `prod`). | `targetName` field on Deployment/Version is OK but could be `bundleTargetName` (L1). | -| Destroy | The `databricks bundle destroy` command — undeploys a bundle. Distinct from API-level delete. | Named `destroyTime` (not `deleteTime`) intentionally (L2). | -| Force-abort | A user other than the version creator forcibly completes the version. | The `ForceAbort` completion value uses a verb phrase while siblings are nouns (M8). | +| Operation | One resource action (create/update/delete/bind/...) recorded under a version. Append-only. | Collides with LRO `Operation` (L4). | +| Resource | A per-deployment record of one Databricks object the bundle manages (a job, a pipeline, etc.). | Confusable with `DeploymentResourceType`. | +| `resource_key` | A dotted config path inside the bundle YAML (e.g. `"jobs.foo"`). | — | +| `resource_id` | The workspace-scoped ID of the underlying Databricks object (e.g. a job ID, pipeline ID). | — | +| Heartbeat | Lock renewal RPC sent by the active CLI while a version is in progress. | Misleading name; should be "renew lock" (H3). | +| Target | A named profile within a bundle (e.g. `dev`, `staging`, `prod`). | — | +| Destroy | The `databricks bundle destroy` command — undeploys a bundle. Distinct from API-level delete. | Named `destroyTime` (not `deleteTime`) intentionally (L1). | +| Force-abort | A user other than the version creator forcibly completes the version. | The `ForceAbort` completion value uses a verb phrase while siblings are nouns (M4). | | Lease | The lock held by a version; renewed by Heartbeat; expires after timeout. | Surfaces only in the `LeaseExpired` completion value. | --- @@ -359,15 +226,11 @@ The docstring says "new lock expiry time", but the field is just `expireTime`. C | File | Lines | Findings | | ----------------- | ----- | --------------------------------------------------------------------------------- | -| `src/v1/model.ts` | 842 | H1, H2, H3, H4, H5, M1-M13, L1-L5, L7, L8, L10, O1, O3, O5, O6 | -| `src/v1/client.ts`| 629 | H2 (request types), H5 (method name), M9, L9, O4 | +| `src/v1/model.ts` | 842 | H1, H2, H3, M1-M4, M6, L1, L2, L4, L5, O1, O3, O5 | +| `src/v1/client.ts`| 629 | H3 (method name), M5, L6, O4 | | `src/v1/utils.ts` | 150 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | | `src/v1/index.ts` | 39 | Re-exports — inherits findings from `model.ts` and `client.ts`. | Every exported identifier in `model.ts` and `client.ts` was inspected. `utils.ts` and `index.ts` produced no incremental findings beyond what the model/client files surface. --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index f9129bba..cbf49169 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -23,20 +23,7 @@ read-only output fields (`createdAt`, `createdBy`, `provisioningInfo`, ### 1. Vague / generic names -#### 1.1 `EffectivePredictiveOptimizationFlag.value` (model.ts:201) -Field name `value` on a type whose entire purpose is exposing a flag value -is doubly redundant — the field is the only payload-bearing scalar on the -type and conveys no semantics. The doc comment reveals it actually holds -the enable/disable string ("Whether predictive optimization should be -enabled..."). Better: `enabled`, `predictiveOptimizationEnabled`, or -mirror the upstream `flagValue` if present. - -#### 1.2 `ProvisioningInfo.state` (model.ts:264) -Generic field name `state`. Whose state? The name only acquires meaning -from its surrounding type — if the field is ever inlined or destructured, -the meaning is lost. - -#### 1.3 `inheritedFromType` / `inheritedFromName` (model.ts:203, 205) +#### 1.1 `inheritedFromType` / `inheritedFromName` (model.ts:203, 205) `Type` here is a free-form `string`, not the `SecurableType` enum that governs the rest of the package. The name `inheritedFromType` suggests an enum/typed handle but is in fact human-readable text. Misleading — see @@ -102,7 +89,7 @@ worth noting for consistency. The field is typed `string | undefined` but the comment ("Whether predictive optimization should be enabled…") implies a tri-state (enabled / disabled / inherit). Either the type should be an enum (`PredictiveOptimizationFlag`) -or the field should be named explicitly (`enabled: string`). See also §1.1. +or the field should be named explicitly (`enabled: string`). #### 4.2 `azureKeyVaultKeyId` is described as a URL (model.ts:215-216) Field is named `…Id` but doc says "the AKV URL in Azure". Either rename to @@ -122,11 +109,6 @@ caller to know what distinguishes them. The doc duplication is verbatim in `CreateCatalogRequest` (171-174) and `UpdateCatalogRequest` (318-321). Either is underspecified or one of them is misnamed. -#### 4.5 `EncryptionSettings.azureEncryptionSettings: AzureEncryptionSettings` (model.ts:218) -A field on `EncryptionSettings` named `azureEncryptionSettings` whose type -is also `AzureEncryptionSettings` reads like a copy-paste error. Drop the -prefix: `azure: AzureEncryptionSettings` is clearer. - --- ### 5. Overly verbose @@ -143,10 +125,6 @@ the flag). Long field name for a single flag value. Acceptable, but tracked because it pairs with §5.1 to make every `CatalogInfo`-style object verbose. -#### 5.3 `managedEncryptionSettings` (model.ts:105, 170, 317) -Three-word field name on a securable that already implies "managed". -Consider `encryption` or `encryptionSettings`. - --- ### 6. Redundant suffixes @@ -156,12 +134,10 @@ Consider `encryption` or `encryptionSettings`. this distinguishes the entity type from the resource handle; in JS/TS the convention is to drop it (`Catalog`, `Provisioning`). -#### 6.2 `…Settings` repeated (`AzureEncryptionSettings`, `EncryptionSettings`, `azureEncryptionSettings`) — see §4.5. - -#### 6.3 `Flag` suffix on `EffectivePredictiveOptimizationFlag` +#### 6.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` The whole type *is* the flag; the suffix is redundant. See §5.1. -#### 6.4 `…Arg` suffix on `nameArg` — see §3.1 and §8.1. +#### 6.3 `…Arg` suffix on `nameArg` — see §3.1 and §8.1. --- @@ -183,8 +159,6 @@ This isn't a reserved word but it routinely shadows `Function.prototype.name` and is a common source of confusion when callers spread request objects. See also §3.1. -#### 7.3 `value` field on `EffectivePredictiveOptimizationFlag` (model.ts:201) — generic, frequently shadows local variables. See §1.1. - --- ### 8. Duplicate concepts @@ -246,12 +220,6 @@ Mirror issue in `UpdateCatalogRequest`. #### 9.3 `DeleteCatalogRequest.nameArg` — see §3.1. -#### 9.4 `EncryptionSettings.azureEncryptionSettings` -The outer type's domain is "all encryption settings"; the field is named -as if scoped to Azure. The contradiction (parent claims breadth, child -name claims specificity) is resolved by reading the type definition -but is initially confusing. See §4.5. - --- ### 10. Underspecified IDs @@ -277,11 +245,6 @@ elsewhere — same conceptual ID, two formats, no unifying name. Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See §4.2. -#### 10.6 `createdAt` / `updatedAt` (model.ts:84, 88) -Type is `number` (epoch milliseconds). Conventional, but the field name -doesn't convey unit. Pairs `createdAtMs` or `createdAtEpochMs` would be -more honest. - --- ### 11. Type-suffix tautology @@ -456,18 +419,16 @@ passing for the broader review. | `CatalogInfo.securableType` | model.ts:103 | 8.4, 11.1 | | `CreateCatalogRequest` | model.ts:124 | 8.5, 9.2 | | `DeleteCatalogRequest.nameArg` | model.ts:191 | 3.1, 9.3 | -| `EffectivePredictiveOptimizationFlag` | model.ts:199 | 5.1, 6.3 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:201 | 1.1, 4.1, 7.3 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:203 | 1.3 | -| `EncryptionSettings` | model.ts:212 | 6.2 | +| `EffectivePredictiveOptimizationFlag` | model.ts:199 | 5.1, 6.2 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:201 | 4.1 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:203 | 1.1 | | `EncryptionSettings.customerManagedKeyId` | model.ts:214 | 2.1, 10.4 | | `EncryptionSettings.azureKeyVaultKeyId` | model.ts:216 | 2.2, 4.2, 10.5 | -| `EncryptionSettings.azureEncryptionSettings` | model.ts:218 | 4.5, 9.4 | | `GetCatalogRequest.nameArg` | model.ts:223 | 3.1 | | `ListCatalogsRequest.maxResults` | model.ts:240 | — | | `ListCatalogsRequest.pageToken` | model.ts:242 | — | | `ListCatalogsRequest.includeUnbound` | model.ts:247 | — | -| `ProvisioningInfo` | model.ts:262 | 1.2, 6.1 | +| `ProvisioningInfo` | model.ts:262 | 6.1 | | `UpdateCatalogRequest.nameArg/newName/name` | model.ts:269-273 | 3.1, 8.3, 9.1 | | `ProvisioningInfo_State` (proto-nested enum) | model.ts:43 | 13.1 | | `CatalogInfo_OptionsEntry` | model.ts:113 | 13.2 | @@ -496,16 +457,3 @@ passing for the broader review. 6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) --- - -## Fixed - -- #1.3 `ConversionInfo.state` (originally cited at model.ts:145): Fixed in regeneration on 2026-05-20 — `ConversionInfo` type was removed from the model entirely. -- #2.1 `DrReplicationStatus` enum redundant `DR_REPLICATION_STATUS_` prefix (originally cited at model.ts:21-25): Fixed in regeneration on 2026-05-20 — `DrReplicationStatus` enum was removed from the model. -- #3.1 `DrReplicationStatus` / `DrReplicationInfo` / `drReplicationInfo` "DR" acronym casing (originally cited at model.ts:21, 228, 121): Fixed in regeneration on 2026-05-20 — all DR-related identifiers were removed from the model. -- #4.2 `Dr` prefix throughout (originally cited at model.ts:21, 228, 121, 237): Fixed in regeneration on 2026-05-20 — all DR-related identifiers were removed. -- #5.3 `DrReplicationInfo.replicatedEntities: Uint8Array` cardinal-plural misleading name (originally cited at model.ts:231): Fixed in regeneration on 2026-05-20 — `DrReplicationInfo` was removed from the model. -- #1.2 `DrReplicationInfo.replicatedEntities` `Uint8Array` opacity (originally cited at model.ts:231): Fixed in regeneration on 2026-05-20 — `DrReplicationInfo` was removed from the model. -- #14.7 (positive observation) `DrReplicationInfo.lastFailoverTimeMs` correctly suffixed unit (originally cited at model.ts:237): Removed in regeneration on 2026-05-20 — `DrReplicationInfo` was removed from the model, so the counter-example no longer exists. -- #15.4 `DrReplicationStatus` enum with field `status` (originally cited at model.ts:21, 229): Fixed in regeneration on 2026-05-20 — `DrReplicationStatus` and its container were removed. -- Verb-tense section (previously §10) (no findings, marked consistent): Retained content folded into commentary above; section dropped from numbering because it produced no enumerated issues. -- Inconsistent action verbs (previously §12) (no findings, marked consistent): Retained content folded into commentary above; section dropped from numbering because it produced no enumerated issues. diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md index 240811a7..1d2d7896 100644 --- a/.agent/naming-audit/cleanroomassets.md +++ b/.agent/naming-audit/cleanroomassets.md @@ -134,58 +134,3 @@ _None._ _None._ --- - -## Fixed - -- #1.1 `details` on `CleanRoomAsset` (originally cited at model.ts:135): Fixed in regeneration on 2026-05-20 — package removed; symbol now lives in `cleanrooms` package and is tracked under that audit. -- #1.2 `localDetails` on `CleanRoomAsset` (originally cited at model.ts:100): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #1.3 `name` on `CleanRoomAsset` (originally cited at model.ts:90): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #1.4 `name` on `ColumnInfo` (originally cited at model.ts:269): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #1.5 `name` on `PartitionSpecification_Partition_PartitionValue` (originally cited at model.ts:436): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #1.6 `value` on `PartitionSpecification_Partition_PartitionValue` (originally cited at model.ts:441): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #1.7 `details` discriminated-union sub-cases (originally cited at model.ts:135–168): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #2.1 `CleanRoomAsset_AssetType.ASSET_TYPE_UNSPECIFIED` (originally cited at model.ts:37): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #2.2 `CleanRoomAsset_Status_Enum.ENUM_UNSPECIFIED` (originally cited at model.ts:47): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #2.3 `CleanRoomNotebookReview_NotebookReviewState.NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (originally cited at model.ts:55): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #2.4 `CleanRoomNotebookReview_NotebookReviewSubReason.NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #5.1 `etag` (originally cited at model.ts:194, 370, 410): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #5.2 `op` on `PartitionSpecification_Partition_PartitionValue` (originally cited at model.ts:448): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #6.1 `createCleanRoomAssetReview` (originally cited at client.ts:109): Fixed in regeneration on 2026-05-20 — package removed; method relocated to `cleanrooms` package client. -- #6.2 `assetType` on `CreateCleanRoomAssetReviewRequest` (originally cited at model.ts:319): Fixed in regeneration on 2026-05-20 — package removed; request relocated to `cleanrooms` package. -- #6.3 `op` misleading (originally cited at model.ts:448): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #7.1 `CreateCleanRoomAssetReviewResponse.notebookReviewState` discriminator (originally cited at model.ts:330): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #7.2 `runnerCollaboratorAliases` (originally cited at model.ts:196): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). -- #7.3 `reviewerCollaboratorAlias` (originally cited at model.ts:256): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). -- #7.4 `ownerCollaboratorAlias` (originally cited at model.ts:98): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). -- #7.5 `recipientPropertyKey` (originally cited at model.ts:446): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package (and was already marked acceptable). -- #9.1 `revisions` on `ListCleanRoomAssetRevisionsResponse` (originally cited at model.ts:387): Fixed in regeneration on 2026-05-20 — package removed; response relocated to `cleanrooms` package. -- #9.2 `listCleanRoomAssetRevisions` (originally cited at client.ts:255–270): Fixed in regeneration on 2026-05-20 — package removed; method relocated to `cleanrooms` package client. -- #10.1 `op` reserved-word concern (originally cited at model.ts:448): Fixed in regeneration on 2026-05-20 — package removed; symbol relocated to `cleanrooms` package. -- #12.1 `cleanRoomName` duplication across requests (originally cited at model.ts:315, 339, 355, 364, 375, 393, 474): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. -- #12.2 `assetType` duplication across requests (originally cited at model.ts): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. -- #12.3 `name` duplication as URL path + body (originally cited at model.ts): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. -- #12.4 `localDetails`/`details` parallel discriminated unions (originally cited at model.ts): Fixed in regeneration on 2026-05-20 — package removed; types relocated to `cleanrooms` package. -- #13.1 `addedAt` vs. `createdAtMillis` (originally cited at model.ts:94 / 258): Fixed in regeneration on 2026-05-20 — package removed; fields relocated to `cleanrooms` package. -- #14.1 Snake-case wire keys (originally cited at model.ts:484–488): Fixed in regeneration on 2026-05-20 — package removed; schemas relocated to `cleanrooms` package (and were already marked acceptable). -- #15.1 `name` on `CleanRoomAsset` (originally cited at model.ts:90): Fixed in regeneration on 2026-05-20 — duplicate of #1.3; package removed. -- #15.2 `name` on `ColumnInfo` (originally cited at model.ts:269): Fixed in regeneration on 2026-05-20 — duplicate of #1.4; package removed. -- #15.3 `name` on partition value (originally cited at model.ts:436): Fixed in regeneration on 2026-05-20 — duplicate of #1.5; package removed. -- #15.4 `value` on partition value (originally cited at model.ts:441): Fixed in regeneration on 2026-05-20 — duplicate of #1.6; package removed. -- #15.5 `comment` ambiguity across types (originally cited at model.ts:262, 284, 414): Fixed in regeneration on 2026-05-20 — package removed; types relocated to `cleanrooms` package. -- #16.1 `ColumnTypeName.TABLE_TYPE` / `TABLEREF_TYPE` (originally cited at model.ts:31–32): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #16.2 `assetType` contradicting domain (originally cited at model.ts:319): Fixed in regeneration on 2026-05-20 — duplicate of #6.2; package removed. -- #17.1 `createCleanRoomAssetReview` action verb (originally cited at client.ts:109): Fixed in regeneration on 2026-05-20 — package removed; method relocated to `cleanrooms` package client. -- #18.1 `NOTEBOOK_REVIEW_STATE_UNSPECIFIED` (originally cited at model.ts:55): Fixed in regeneration on 2026-05-20 — duplicate of #2.3; package removed. -- #18.2 `NOTEBOOK_REVIEW_SUB_REASON_UNSPECIFIED` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — duplicate of #2.4; package removed. -- #18.3 `ASSET_TYPE_UNSPECIFIED` (originally cited at model.ts:37): Fixed in regeneration on 2026-05-20 — duplicate of #2.1; package removed. -- #18.4 `ENUM_UNSPECIFIED` (originally cited at model.ts:47): Fixed in regeneration on 2026-05-20 — duplicate of #2.2; package removed. -- #18.5 `USER_DEFINED_TYPE` (originally cited at model.ts:24): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #18.6 `TIMESTAMP_NTZ` (originally cited at model.ts:25): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #19.1 `etag` underspecified ID (originally cited at model.ts:194, 370, 410): Fixed in regeneration on 2026-05-20 — package removed; field relocated to `cleanrooms` package. -- #19.2 `name` as asset primary key (originally cited at model.ts:343, 359): Fixed in regeneration on 2026-05-20 — package removed; requests relocated to `cleanrooms` package. -- #20.1 `ColumnTypeName` tautology (originally cited at model.ts:5): Fixed in regeneration on 2026-05-20 — package removed; enum relocated to `cleanrooms` package. -- #Cross-cutting `CleanRoom` redundancy (originally affecting every exported type/method): Fixed in regeneration on 2026-05-20 — package removed; cleanroom-asset exports consolidated under the `cleanrooms` package and are tracked under its audit. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md index b0c11b99..17db4cda 100644 --- a/.agent/naming-audit/cleanroomautoapprovalrules.md +++ b/.agent/naming-audit/cleanroomautoapprovalrules.md @@ -41,88 +41,3 @@ _None._ _None._ --- - -## Fixed - -- #1 Redundant `CleanRoom*` prefix on every exported type (originally cited - at `src/v1/model.ts`, affected `CleanRoomAutoApprovalRule`, - `CreateCleanRoomAutoApprovalRuleRequest`, - `DeleteCleanRoomAutoApprovalRuleRequest`, - `GetCleanRoomAutoApprovalRuleRequest`, - `ListCleanRoomAutoApprovalRulesRequest`, - `ListCleanRoomAutoApprovalRulesResponse`, - `UpdateCleanRoomAutoApprovalRuleRequest`): Fixed in regeneration on - 2026-05-20 — package consolidated into `@databricks/sdk-cleanrooms/v1`; - any remaining prefix concerns now tracked in `cleanrooms.md`. -- #2 Client methods restate the package name (originally cited at - `src/v1/client.ts`, affected `createCleanRoomAutoApprovalRule`, - `deleteCleanRoomAutoApprovalRule`, `getCleanRoomAutoApprovalRule`, - `listCleanRoomAutoApprovalRules`, `listCleanRoomAutoApprovalRulesIter`, - `updateCleanRoomAutoApprovalRule`): Fixed in regeneration on 2026-05-20 — - methods moved onto `@databricks/sdk-cleanrooms/v1` `Client`, where the - prefix is no longer redundant against the package name; tracked under - `cleanrooms.md`. -- #3 Enum members repeat the enum name (originally cited at - `src/v1/model.ts`, `CleanRoomAutoApprovalRule_AuthorScope`): Fixed in - regeneration on 2026-05-20 — enum moved into - `@databricks/sdk-cleanrooms/v1/model.ts:148`; concern (if any) now tracked - in `cleanrooms.md`. -- #4 `AUTHOR_SCOPE_UNSPECIFIED` is a leaked-protobuf sentinel (originally - cited at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — enum - moved into `cleanrooms` package; the proto-sentinel finding class was - later promoted to a generator-only recommendation in `_SUMMARY.md`. -- #5 Discriminator-tag value duplicates the field name (originally cited at - `src/v1/model.ts`, `authors` discriminated union): Fixed in regeneration - on 2026-05-20 — union moved into `cleanrooms` package; concern (if any) - tracked in `cleanrooms.md`. -- #6 `authors` / `runners` are misleading plurals on a single-author/runner - union (originally cited at `src/v1/model.ts`): Fixed in regeneration on - 2026-05-20 — fields moved into `cleanrooms` package; concern (if any) - tracked in `cleanrooms.md`. -- #7 `runnerCollaboratorAlias` doubles `runner` (originally cited at - `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — field moved - into `cleanrooms` package; concern (if any) tracked in `cleanrooms.md`. -- #8 `ruleOwnerCollaboratorAlias` / `authorCollaboratorAlias` / - `runnerCollaboratorAlias` verbose / cryptic suffix (originally cited at - `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — fields moved - into `cleanrooms` package; concern (if any) tracked in `cleanrooms.md`. -- #9 `ruleId` is underspecified (originally cited at - `src/v1/model.ts`, request types): Fixed in regeneration on 2026-05-20 — - fields moved into `cleanrooms` package; concern (if any) tracked in - `cleanrooms.md`. -- #10 `Client` is a generic class name (originally cited at - `src/v1/client.ts`): Fixed in regeneration on 2026-05-20 — package deleted - and methods moved to the existing `cleanrooms` `Client`; the cross-package - bare-`Client` concern is tracked once in `_SUMMARY.md`. -- #11 `nextPageToken` / `pageToken` duplicated across response/request - (originally cited at `src/v1/model.ts`, informational): Fixed in - regeneration on 2026-05-20 — pagination types moved into `cleanrooms`; - the pattern was logged repo-wide as the standard pagination convention. -- #12 Doc references undefined casing (`snake_case` field names in JSDoc; - originally cited at `src/v1/model.ts`): Fixed in regeneration on - 2026-05-20 — doc copy moved with the symbols into `cleanrooms`; concern - (if any) tracked in `cleanrooms.md`. -- #13 Docs say "a auto-approval rule" typo (originally cited at - `src/v1/client.ts:96`, `:115`, `:194`): Fixed in regeneration on - 2026-05-20 — generator template no longer emits the article-noun - agreement bug. -- #14 `Client` constructor field `userAgent` vague (originally cited at - `src/v1/client.ts:49`): Fixed in regeneration on 2026-05-20 — field moved - with the methods into `cleanrooms` `Client`; the cross-package - `userAgent` field concern is tracked once in `_SUMMARY.md`. -- #15 `utils.ts` is a kitchen-sink module name (originally cited at - `src/v1/utils.ts`): Fixed in regeneration on 2026-05-20 — module deleted - with the package; the cross-package `utils.ts` concern is recorded once - in `_SUMMARY.md` as a generator-level item. -- #16 Method docstrings use "rule ID" inconsistently with field name - (originally cited at `src/v1/client.ts`): Fixed in regeneration on - 2026-05-20 — docstrings moved with the methods into `cleanrooms` `Client`; - concern (if any) tracked in `cleanrooms.md`. -- #17 `cleanRoomName` is the identifier doing double duty (originally cited - at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — field moved - into `cleanrooms` package; the cross-package "name-as-ID" concern is - tracked in `cleanrooms.md`. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index 7121996f..cad77628 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -12,14 +12,12 @@ grouped by category, and each finding cites the file/line where it appears. ## Summary -- **Total findings:** 28 +- **Total findings:** 12 - **Highest-impact themes:** - 1. Several field names use vague or generic terms (`type`, `protocol`, - `name`, `destination`, `status`) that lose meaning out of context. - 2. Misleading field names (`remoteDetailedInfo`, boolean-shaped - `accessRestricted` enum). - 3. Cloud-asymmetric fields (`bucketName` vs. `azureContainer`) leak - cloud taxonomy into a single struct. + 1. Misleading boolean-shaped `accessRestricted` enum. + 2. Acronym casing inconsistencies (`Id` vs `ID`, `Dns` vs `DNS`, + `aws/azure/gcp`, `FEDRAMP`). + 3. Duplicate `Status` enum types and overlapping collaborator types. 4. Proto-architectural leaks: stray `Handler` suffix on list methods for notebook task runs. @@ -27,45 +25,7 @@ grouped by category, and each finding cites the file/line where it appears. ## 1. Vague / Generic Names -### 1.1 `name?: string` on `CleanRoom` (model.ts:247) -The top-level field `name` is the clean room identifier. Combined with the -request shape `GetCleanRoomRequest { name }`, the name "name" is too -generic — there is no signal that this is a UC securable name vs. a display -name vs. a UUID. Go SDK has the same problem, but consider `cleanRoomName`. - -### 1.2 `name?: string` on `GetCleanRoomRequest`, `DeleteCleanRoomRequest`, -`UpdateCleanRoomRequest` (model.ts:836, 738, 1009) -Same issue — when used inside a request DTO, `name` is ambiguous as to -**which** name. `cleanRoomName` would self-document. The request schema -in `CreateCleanRoomOutputCatalogRequest` uses the more specific -`cleanRoomName` (model.ts:703), so the codebase is inconsistent with itself. - -### 1.3 `type?: ...InternetDestinationType` (model.ts:777) -The field `type` on `InternetDestination` is generic. `destinationType` or -`kind` would be clearer at call sites -(`internetDestination.type === FQDN` reads as a meta-property). - -### 1.4 `type?: ...StorageDestinationType` (model.ts:800) -Same issue on `StorageDestination` — bare `type` field. - -### 1.5 `protocol?: ...InternetDestinationFilteringProtocol` (model.ts:780) -`protocol` is generic. A consumer cannot tell from `destination.protocol` -whether this is TCP/UDP/HTTP/SSH/etc. `filteringProtocol` matches the -underlying enum semantics. - -### 1.6 `destination?: string` (model.ts:776) -Bare `destination` on `InternetDestination` is tautological with its -container. The string is the FQDN/hostname/IP literal. `value` or -`fqdn`/`host` would convey intent. - -### 1.7 `region?: string` (model.ts:581, 799) -`region` field appears on both `CleanRoomRemoteDetail` (cloud region) and -`StorageDestination` (bucket region). Not necessarily wrong, but the -ambiguity is worth noting — `cloudRegion` / `bucketRegion` would disambiguate. - -### 1.8 `workloads?: WorkloadType[]` (model.ts:790) -On `LogOnlyMode`, the field `workloads` is plural-of-type. `workloadTypes` -would match the enum. (See also §4 — singular/plural mismatch.) +_None._ --- @@ -96,41 +56,15 @@ text should match. ## 3. Misleading Names -### 3.1 `remoteDetailedInfo` (model.ts:253) -Field name suggests "verbose info about a remote endpoint." Actually -contains the central clean room state (collaborators, network policy, -compliance) — the meaty payload of `CleanRoom`. JSON tag is -`remote_detailed_info` but the type is `CleanRoomRemoteDetail` (singular, -no "Info"). The name is **misleading** and **internally inconsistent with -its type**: field says `remoteDetailedInfo`, type says `RemoteDetail`. - -### 3.2 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:271) +### 3.1 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:271) Reads as a boolean ("is access restricted?"). It is actually an enum with -values `NO_RESTRICTION` and `CSP_MISMATCH`. `accessRestrictedReason` or -`accessRestriction` would not suggest a boolean. The JSDoc reinforces the +values `NO_RESTRICTION` and `CSP_MISMATCH`. The JSDoc reinforces the miscommunication: "Whether clean room access is restricted…" — implying a yes/no. The shape itself is boolean-like (two values, one of which is the absence sentinel) — a `boolean` field would model the domain more honestly. -### 3.3 `isEnabled?: boolean` on `ComplianceSecurityProfile` (model.ts:664) -The `is` prefix is acceptable, but inside an object literal one writes -`profile.isEnabled` (reading "is enabled" of a non-question subject) which -becomes awkward; simply `enabled` is more idiomatic and aligns with -JavaScript norms (HTML `disabled`, `aria-disabled`, etc.). - -### 3.4 `logOnlyMode?: ...LogOnlyMode` (model.ts:764) -Field name and type name both have `LogOnlyMode`. But the field's container -already declares "this is the LogOnlyMode submessage" — `logOnly` would -suffice. - -### 3.5 `localCollaboratorAlias?: string` (model.ts:264) vs. -`collaboratorAlias` on `CleanRoomCollaborator` (model.ts:515) -The "local" prefix here is a fragment of metastore-domain jargon. A reader -who does not already know about "single-metastore vs. x-metastore" clean -rooms cannot tell what "local" means. - -### 3.6 `CreateCleanRoomWaiter` class (client.ts:816) +### 3.2 `CreateCleanRoomWaiter` class (client.ts:881) The waiter polls `getCleanRoom` and resolves when status reaches `ACTIVE`. Naming it `CreateCleanRoomWaiter` ties it to `createCleanRoom`, but the waiter is operationally generic (any clean room name can be polled). A @@ -140,16 +74,7 @@ better name is `CleanRoomActivationWaiter` or `CleanRoomStatusWaiter`. ## 4. Singular / Plural Mismatches -### 4.1 `workloads?: WorkloadType[]` (model.ts:790) -Field is plural and array-typed, but the element type is **`WorkloadType`** -(singular noun + `Type` suffix). Consumers write `mode.workloads[0]` which -is a `WorkloadType` — readable, but the field could be `workloadTypes` to -match the element. Alternative: rename the enum to `Workload`. - -### 4.2 `complianceStandards?: ComplianceStandard[]` (model.ts:666) -Correctly plural. But `allowedInternetDestinations` and -`allowedStorageDestinations` (model.ts:757, 760) inherit the `allowed` -prefix; while the parent `restrictionMode` is singular. Mild inconsistency. +_None._ --- @@ -170,11 +95,7 @@ Per the JSDoc, `creator` is also **one of the collaborators in the collaborators list**. So we have the same logical entity reachable through two paths. Mild — not a renamed-target, but flagged as a shape concern. -### 5.3 `cleanRoomName` (model.ts:703) vs. `name` (model.ts:247, 836, 738, 1009) -Two names for the same thing: the clean-room identifier. Picking one -consistently would simplify call sites. - -### 5.4 `CleanRoomCollaborator` (model.ts:490) vs. +### 5.3 `CleanRoomCollaborator` (model.ts:490) vs. `CollaboratorJobRunInfo` (model.ts:606) Both types now live in `cleanrooms` (the `cleanroomtaskruns` package was consolidated into `cleanrooms`). Within the package, two "Collaborator- @@ -186,9 +107,9 @@ prefixes. Consistency would suggest renaming `CollaboratorJobRunInfo` to ## 6. Inconsistent Action Verbs -### 6.1 `createCleanRoom` returns the new clean room (client.ts:120); +### 6.1 `createCleanRoom` returns the new clean room (client.ts:125); `createCleanRoomOutputCatalog` returns a **response wrapper** -(`CreateCleanRoomOutputCatalogResponse`) (client.ts:250). +(`CreateCleanRoomOutputCatalogResponse`) (client.ts:267). Inconsistent return shapes for two `create*` methods. The Go SDK has the same wart, but it surfaces here as inconsistent ergonomics: `(await c.createCleanRoom(...)).name` vs. @@ -198,14 +119,7 @@ same wart, but it surfaces here as inconsistent ergonomics: ## 7. Cloud Asymmetry / Cross-Cloud Field Naming -### 7.1 `bucketName`, `region`, `type`, `azureStorageAccount`, -`allowedPaths`, `azureStorageService`, `azureDnsZone`, `azureContainer` -on `StorageDestination` (model.ts:798–807) -The same struct mixes AWS-, Azure-, and GCP-shaped fields. `bucketName` -is S3-flavored; `azureStorageAccount` is Azure-flavored. The fact that the -fields share one struct **and** the field names are not prefixed with the -cloud (`bucketName` vs. `azureContainer`) leaks the cloud taxonomy into -field naming inconsistently. +_None._ --- @@ -217,7 +131,7 @@ _None._ ## 9. Proto / Architectural Leaks -### 9.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:612 +### 9.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:662 - **Why:** Mid/end-position `Handler` on a public method (not a domain term). All sibling list methods (`listCleanRooms`, `listCleanRoomAssets`, `listCleanRoomAutoApprovalRules`) omit the `Handler` suffix. The stray @@ -228,7 +142,7 @@ _None._ like `Handler` in client-method names; consistency with the other `list*` methods is the principal benefit. -### 9.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:651 +### 9.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:704 - **Why:** Same stray `Handler` infix in the async-iterator companion to §9.1. Sibling iterators (`listCleanRoomsIter`, `listCleanRoomAssetsIter`, `listCleanRoomAutoApprovalRulesIter`) follow @@ -253,12 +167,3 @@ _None._ is appropriately namespaced. --- - -## Fixed - -- #4.2 `ARC_AMPE` (originally cited at model.ts:51): Fixed in regeneration on 2026-05-20 — enum value no longer present in `ComplianceStandard`. -- #5.3 `enableSharedOutput?: boolean` (originally cited at model.ts:173): Fixed in regeneration on 2026-05-20 — field removed from `CleanRoom`. -- #5.2 `CleanRoomCollaborator` overlap with `cleanroomtaskruns.CollaboratorJobRunInfo`: Fixed in regeneration on 2026-05-22 — the `cleanroomtaskruns` package was consolidated into `cleanrooms`, eliminating the cross-package overlap concern. In-package overlap is now tracked under §5.4. -- #8.1 Cross-package shared "clean room" concept across `cleanrooms` / `cleanroomassets` / `cleanroomautoapprovalrules` / `cleanroomtaskruns`: Fixed in regeneration on 2026-05-22 — the three sibling packages were consolidated into `cleanrooms`, so all `CleanRoom*` types now live in a single canonical package. -- #8.2 Cross-package `CleanRoomCollaborator` (cleanrooms) vs. `CollaboratorJobRunInfo` (cleanroomtaskruns): Fixed in regeneration on 2026-05-22 — packages consolidated; the in-package concern is tracked under §5.4. -- #8.3 Cross-package resource-name pattern repetition (`name` slot across cleanrooms / cleanroomassets / cleanroomautoapprovalrules): Fixed in regeneration on 2026-05-22 — sibling packages consolidated into `cleanrooms`, eliminating cross-package shape-collision risk. diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md index fab10b96..183d57b9 100644 --- a/.agent/naming-audit/cleanroomtaskruns.md +++ b/.agent/naming-audit/cleanroomtaskruns.md @@ -306,12 +306,3 @@ service name — but a reader is left to guess. findings touch multiple categories). --- - -## Fixed - -- #8 (partial) `sharedOutputSchemaExpirationTime` (originally cited at model.ts:73): Fixed in regeneration on 2026-05-20 — field removed from `CleanRoomNotebookTaskRun`; remaining `outputSchemaExpirationTime` retained as renumbered finding #8. -- #9 `sharedOutputSchemaName` doc references missing `enable_shared_output` flag (originally cited at model.ts:72): Fixed in regeneration on 2026-05-20 — `sharedOutputSchemaName` field removed from `CleanRoomNotebookTaskRun`, so the misleading doc is gone. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index 1048bf5c..754d2ce2 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -12,28 +12,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 1. Vague / generic names -### 1.1 `Library.lib` — `model.ts:61` -- `Library` already names the concept; the inner discriminated-union field - `lib` is a shortened duplicate of the parent type name. -- The wire schema spreads the variants flat at the top level (`jar`, `egg`, - `pypi`, etc.). The `lib` wrapper is a TS-only artifact for the tagged-union - encoding. A more descriptive name would be `source`, `spec`, `package`, or - `variant` (since it discriminates which package source/format applies). -- Severity: medium. Consumers must write `library.lib.jar` which reads as - redundant. - -### 1.2 `RCranLibrary.package`, `PythonPyPiLibrary.package` — `model.ts:174, 164` -- `package` is a reserved word in JavaScript (future-reserved, strict mode) - and conveys little semantic content beyond "package". Consider - `coordinate`, `name`, or `packageName`. See also §8. -- Severity: medium. - -### 1.3 `MavenLibrary.repo`, `PythonPyPiLibrary.repo`, `RCranLibrary.repo` - — `model.ts:149, 169, 176` -- `repo` is an abbreviation. The companion `repo` documentation says - "repository". `repository` (or `repositoryUrl`) would be more explicit. See - also §4. -- Severity: low. +_None._ --- @@ -65,29 +44,11 @@ means it is awkward or inconsistent; "low" means a minor blemish. - The discriminator `$case: 'cran'` is consistent with the type tag. - Severity: medium. -### 2.3 `Library.whl` — `model.ts:100, 108` -- "Whl" is the file-extension shorthand for Python wheels. The wire format - uses `whl`, but the TS type otherwise uses long-form names (`jar`, - `requirements`, `egg`). `wheel` would be more readable in TS but is a - wire-contract concern (cannot rename without breaking compatibility). -- Severity: low (flagged for completeness — abbreviation, not strictly a - casing issue). - --- ## 3. Cryptic abbreviations -### 3.1 `Library.jar`, `Library.egg`, `Library.whl` — `model.ts:60-119` -- Single-extension abbreviations as field names. Wire-locked, but the type - surface would be more discoverable with `jarUri`, `wheelUri`, etc. The - `requirements` field at the same level uses the long form, so the variants - are inconsistent within one type. -- Severity: low (wire compatibility constraint). - -### 3.2 `repo` — multiple types -- See §1.3. Short form of `repository`. Severity: low. - -### 3.3 `Library.pypi`, `Library.cran` — `model.ts:79, 95` +### 3.1 `Library.pypi`, `Library.cran` — `model.ts:79, 95` - Lower-cased acronyms as field tags. Acceptable for wire compatibility, but the inconsistency with the (camelCased) type names (`PythonPyPiLibrary`, `RCranLibrary`) is jarring. See §2. @@ -145,11 +106,6 @@ means it is awkward or inconsistent; "low" means a minor blemish. - "Full" is a vestigial qualifier with no counterpart. See §4.1. - Severity: medium. -### 6.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:42` -- Field name repeats the parent's middle word (Library). Could simply be - `statuses`. Borderline acceptable for clarity. -- Severity: low. - --- ## 7. Singular/plural mismatches @@ -169,16 +125,7 @@ means it is awkward or inconsistent; "low" means a minor blemish. ## 8. Reserved-word collisions -### 8.1 `PythonPyPiLibrary.package`, `RCranLibrary.package` — `model.ts:164, 174` -- `package` is a future-reserved word in ECMAScript (strict mode reserved). - It is legal as an object property name and a parameter, but it is awkward - to destructure: `const {package: pkg} = ...`. The wire field is `package`, - so renaming requires marshal/unmarshal indirection (the file already does - that for snake_case translation). Alternative: `packageName` or - `coordinate` (the same concept Maven uses). -- Severity: high (forces renaming on destructure). - -### 8.2 No other reserved-word issues observed. +_None._ --- @@ -223,12 +170,7 @@ _None._ ## 12. Field contradicting type domain -### 12.1 `LibraryFullStatus.isLibraryForAllClusters` — `model.ts:130` -- Inside `LibraryFullStatus` (per-cluster status), a field that describes - whether the library is configured cluster-wide. The name reads like a - global property but the type belongs to a single cluster's view. Better: - `installedOnAllClusters` or `isClusterWideLibrary`. -- Severity: medium. +_None._ --- @@ -256,10 +198,6 @@ _None._ the inner field becoming `state` to avoid the duplicate). - Severity: low. -### 15.2 `ClusterLibraryStatuses.libraryStatuses` — `model.ts:42` -- Already noted in §6.2. -- Severity: low. - --- ## Cross-cutting summary @@ -268,7 +206,6 @@ _None._ - `PythonPyPiLibrary` brand-casing inconsistency (§2.1): "PyPi" misspells the PyPI brand. -- `package` reserved-word collision on PyPI and CRAN libraries (§8.1). - Verb-tense gap: `allClusterStatuses()` and `clusterStatus()` break the client's prevailing verb-prefix convention (§10.1, §11.1). @@ -277,13 +214,9 @@ _None._ - `LibraryFullStatus` with no "non-full" counterpart (§4.1). - `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state (§4.3, §10.2). -- `isLibraryForAllClusters` field name awkwardly straddles per-cluster - and global domains (§12.1). ### Low-severity / stylistic -- `repo` vs `repository` short form (§1.3). -- `whl`, `jar`, `egg` extension-as-field-name (§3.1). - `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§4.2). - "dependences" typo in `MavenLibrary.exclusions` doc (§7.1). @@ -326,32 +259,3 @@ Utilities audited (`utils.ts`): - `flattenQueryParams` (123). --- - -## Fixed - -- #1.2 `DefaultBaseEnvironment.message` (originally cited at model.ts:92): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed from package. -- #1.3 `Environment.client` (originally cited at model.ts:116): Fixed in regeneration on 2026-05-20 — `Environment` type removed from package. -- #2.4 `traceId` vs `trace_id` query param (originally cited at client.ts:222-224): Fixed in regeneration on 2026-05-20 — `traceId` and surrounding DBE getter removed. -- #3.4 `filepath` (originally cited at model.ts:90): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. -- #4.1 `updateDefaultDefaultBaseEnvironment` (originally cited at client.ts:429): Fixed in regeneration on 2026-05-20 — method removed from client. -- #4.2 `UpdateDefaultDefaultBaseEnvironmentRequest` (originally cited at model.ts:326): Fixed in regeneration on 2026-05-20 — type removed from package. -- #4.3 `ClusterStatus` (originally cited at model.ts:63): Fixed in regeneration on 2026-05-20 — renamed to `ClusterStatusRequest` as the audit suggested. -- #4.8 `Environment` (originally cited at model.ts:114): Fixed in regeneration on 2026-05-20 — type removed from package. -- #4.9 `MaterializedEnvironment.lastUpdatedTimestamp` (originally cited at model.ts:264): Fixed in regeneration on 2026-05-20 — `MaterializedEnvironment` type removed. -- #4.10 `DefaultBaseEnvironmentCache.indefiniteMaterializedEnvironment` (originally cited at model.ts:101): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironmentCache` type removed. -- #4.11 `Environment.baseEnvironment` (originally cited at model.ts:131): Fixed in regeneration on 2026-05-20 — `Environment` type removed. -- #7.3 `DefaultBaseEnvironment.baseEnvironmentCache` (originally cited at model.ts:93): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. -- #9.1 `InstallLibraries` (request) vs `installLibraries()` (method) (originally cited at model.ts:148, client.ts:250): Fixed in regeneration on 2026-05-20 — request type renamed to `InstallLibrariesRequest`, eliminating the case-only collision. -- #9.2 `Environment` vs `MaterializedEnvironment` vs `DefaultBaseEnvironment` (originally cited at model.ts:78, 114, 262): Fixed in regeneration on 2026-05-20 — all three types removed from package. -- #11.2 `refreshDefaultBaseEnvironments` (originally cited at client.ts:333): Fixed in regeneration on 2026-05-20 — method removed from client. -- #11.3 `updateDefaultDefaultBaseEnvironment` vs `setDefault` URL (originally cited at client.ts:433): Fixed in regeneration on 2026-05-20 — method removed from client. -- #12.1 `Environment.client` (originally cited at model.ts:116): Fixed in regeneration on 2026-05-20 — `Environment` type removed. -- #12.3 `MaterializedEnvironment.lastUpdatedTimestamp` (originally cited at model.ts:264): Fixed in regeneration on 2026-05-20 — `MaterializedEnvironment` type removed. -- #14.1 `CreateDefaultBaseEnvironmentRequest.requestId` (originally cited at model.ts:74): Fixed in regeneration on 2026-05-20 — type removed from package. -- #14.2 `GetDefaultBaseEnvironmentRequest.traceId` (originally cited at model.ts:145): Fixed in regeneration on 2026-05-20 — type removed from package. -- #14.3 `DefaultBaseEnvironment.creatorUserId`, `.lastUpdatedUserId` (originally cited at model.ts:81, 83): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. -- #14.4 `DefaultBaseEnvironment.principalIds` (originally cited at model.ts:94): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. -- #14.5 `CreateDefaultBaseEnvironmentRequest.workspaceBaseEnvironmentId` (originally cited at model.ts:75): Fixed in regeneration on 2026-05-20 — type removed from package. -- #14.7 `DefaultBaseEnvironment.id` (originally cited at model.ts:79): Fixed in regeneration on 2026-05-20 — `DefaultBaseEnvironment` type removed. -- #14.8 `RefreshDefaultBaseEnvironmentsRequest.ids` (originally cited at model.ts:305): Fixed in regeneration on 2026-05-20 — type removed from package. -- #15.3 `ListDefaultBaseEnvironmentsResponse.defaultBaseEnvironments` (originally cited at model.ts:246): Fixed in regeneration on 2026-05-20 — type removed from package. diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index 0a040936..b83c0c28 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -124,11 +124,8 @@ rubric. Issues are graded: | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| V-01 | `Library.lib` (`model.ts:106`) | High | The field name `lib` is a meaningless abbreviation that conveys nothing the surrounding type doesn't already say. The wrapper interface is `Library`, so the discriminator field could be named `kind`, `variant`, `source`, or `spec`. As `lib`, callers must write `library.lib.$case === 'jar'`, which reads as "library library case". | -| V-02 | `MavenLibrary.repo` (`model.ts:194`), `RCranLibrary.repo` (`model.ts:268`), `PythonPyPiLibrary.repo` (`model.ts:261`) | Medium | `repo` is generic and overloaded across types. For Maven it is a Maven repository URL; for CRAN it is a CRAN mirror; for PyPI it is a pip index. Renaming to `repositoryUrl` (or even `mavenRepoUrl` / `cranMirrorUrl` / `pipIndexUrl`) would be more self-describing. | -| V-03 | `Policy.definition` (`model.ts:226`), `CreatePolicyRequest.definition` (`model.ts:24`), `EditPolicyRequest.definition` (`model.ts:72`) | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it's unclear it's a JSON document. `policyDefinition` (matches `policyFamilyDefinitionOverrides`) would be self-consistent. | -| V-04 | `Policy.description` (`model.ts:228`), `CreatePolicyRequest.description` (`model.ts:26`), `EditPolicyRequest.description` (`model.ts:74`) | Low | Generic but standard across the SDK; acceptable. | -| V-05 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | +| V-01 | `Policy.description` (`model.ts:228`), `CreatePolicyRequest.description` (`model.ts:26`), `EditPolicyRequest.description` (`model.ts:74`) | Low | Generic but standard across the SDK; acceptable. | +| V-02 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | ### 2.2 Redundant enum prefixes @@ -151,12 +148,11 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------- | -------- | ----- | -| C-01 | `Library.lib` (`model.ts:106`) | High (also covered V-01) | `lib` is a cryptic abbreviation of "library" inside a type already called `Library`. | -| C-02 | `Library.lib.$case === 'whl'` (`model.ts:145`) | Medium | `whl` (wheel) is a Python packaging file extension; readers unfamiliar with Python will not know it. Documented in JSDoc but the discriminator value itself is opaque. | -| C-03 | `Library.lib.$case === 'egg'` (`model.ts:119`) | Medium | Same as C-02 for Python "egg" files. The JSDoc even notes it is "Deprecated". | -| C-04 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Maven term, OK in context. | -| C-05 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`, throughout) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | -| C-06 | `opts` (`utils.ts:66`, `executeHttpCall` parameter) | Low | Inside fn scope; minor. | +| C-01 | `Library.lib.$case === 'whl'` (`model.ts:145`) | Medium | `whl` (wheel) is a Python packaging file extension; readers unfamiliar with Python will not know it. Documented in JSDoc but the discriminator value itself is opaque. | +| C-02 | `Library.lib.$case === 'egg'` (`model.ts:119`) | Medium | Same as C-01 for Python "egg" files. The JSDoc even notes it is "Deprecated". | +| C-03 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Maven term, OK in context. | +| C-04 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`, throughout) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | +| C-05 | `opts` (`utils.ts:66`, `executeHttpCall` parameter) | Low | Inside fn scope; minor. | ### 2.6 Misleading names — High @@ -170,10 +166,8 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | O-01 | `policyFamilyDefinitionOverrides` (`model.ts:42`, `model.ts:90`, `model.ts:244`) | Medium | Five-word camel-case identifier. Inherited from the API; very long but no shorter form is unambiguous. Accept as upstream constraint. | -| O-02 | `createdAtTimestamp` (`model.ts:214`) | High | "Timestamp" is redundant — `createdAt` is the universal convention for epoch-millisecond fields (and the JSDoc says "in millisecond"). `createdAtTimestamp` is a tautology (`*-At` already implies a time value). | -| O-03 | `creatorUserName` (`model.ts:212`) | Medium | Three words for "creator". `creator` alone would suffice if the value is a username; `createdBy` is the convention used elsewhere in the Databricks SDK. | -| O-04 | `PACKAGE_SEGMENT` (`client.ts:44`) | Low | OK in context. | -| O-05 | `Policy.maxClustersPerUser` (`model.ts:246`) | Low | Long but precise. | +| O-02 | `PACKAGE_SEGMENT` (`client.ts:44`) | Low | OK in context. | +| O-03 | `Policy.maxClustersPerUser` (`model.ts:246`) | Low | Long but precise. | ### 2.8 Singular / plural mismatches — Low @@ -187,9 +181,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| R-01 | `PythonPyPiLibrary.package` (`model.ts:256`) | Medium | `package` is a [reserved word in strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#future_reserved_words) for ES5+. It is legal as a property name but can't be used as a variable or import identifier without quoting. Consider `packageName` for forward compatibility. | -| R-02 | `RCranLibrary.package` (`model.ts:266`) | Medium | Same as R-01. | -| R-03 | None of the type names collide. | — | OK. | +| R-01 | None of the type names collide. | — | OK. | ### 2.10 Empty / trivial wrapper types — Medium @@ -222,11 +214,9 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| F-01 | `Library.lib` (`model.ts:106`) | High | Loses all meaning once destructured outside the `Library` type. See V-01. | -| F-02 | `MavenLibrary.repo` (`model.ts:194`) / `RCranLibrary.repo` (`model.ts:268`) / `PythonPyPiLibrary.repo` (`model.ts:261`) | Medium | Same field name across three sibling types but each refers to a different concept (Maven repo URL, CRAN mirror, PyPI index URL). Consistent for the API, but ambiguous when displayed without parent type context. | -| F-03 | `Policy.name` (`model.ts:224`), `Policy.description` (`model.ts:228`) | Low | Standard entity fields; meaning preserved in context. | -| F-04 | `MavenLibrary.coordinates` (`model.ts:189`) | Low | Maven-specific; precise. | -| F-05 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | +| F-01 | `Policy.name` (`model.ts:224`), `Policy.description` (`model.ts:228`) | Low | Standard entity fields; meaning preserved in context. | +| F-02 | `MavenLibrary.coordinates` (`model.ts:189`) | Low | Maven-specific; precise. | +| F-03 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | ### 2.15 Field contradicting type domain — Low @@ -261,13 +251,12 @@ _None._ | TS-01 | `MavenLibrary` (`model.ts:187`) | Medium | The type already lives in a `Library` discriminated union; the `Library` suffix is redundant when accessed as `library.lib.$case === 'maven' ? library.lib.maven : ...` — the value's *position* in the union already identifies it as a library variant. `MavenSpec` or just `Maven` would suffice. | | TS-02 | `PythonPyPiLibrary` (`model.ts:251`) | Medium | Same as TS-01. Could be `PyPISpec`. | | TS-03 | `RCranLibrary` (`model.ts:264`) | Medium | Same as TS-01. Could be `CRANSpec`. | -| TS-04 | `Library` interface itself (`model.ts:105`) | Low | The interface name `Library` and its sole field `lib` share a stem, so call sites read as `library.lib` (a stem repetition). Field rename is covered by V-01 / F-01. | ### 2.20 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | `Policy.createdAtTimestamp` (`model.ts:214`, epoch ms, `number`) | Medium | Beyond redundancy (O-02), JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | +| X-01 | `Policy.createdAtTimestamp` (`model.ts:214`, epoch ms, `number`) | Medium | JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | | X-02 | `Library.lib.$case` literal `'requirements'` (`model.ts:156`) | Low | The discriminator value `'requirements'` is the longest in the union (12 chars) and contrasts with three-letter peers (`jar`, `egg`, `whl`). Consistent with wire format, OK. | | X-03 | `HttpCallOptions` (`utils.ts:15`) | Low | Local interface; precise. | | X-04 | `executeHttpCall` (`utils.ts:65`), `executeCall` (`utils.ts:26`) | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | @@ -295,37 +284,31 @@ architectural-layer words leaking into domain identifiers. | Severity | Count | | -------- | ----- | -| High | 4 | -| Medium | 16 | -| Low | 21 | -| **Total**| **41**| +| High | 2 | +| Medium | 11 | +| Low | 30 | +| **Total**| **43**| ### 3.2 Top themes -1. **`Library.lib` repeats the type stem in its discriminator field.** - Callers write `library.lib?.$case` — `lib` adds no information the type - name doesn't. A concrete name like `source` / `kind` / `spec` reads - better at call sites. +1. **`PyPi` casing should be `PyPI`** (acronym); the type name + `PythonPyPiLibrary` should be `PythonPyPILibrary`. -2. **`PyPi` casing should be `PyPI`** (acronym), and `package` fields collide - with a JS strict-mode reserved word in `PythonPyPiLibrary` / `RCranLibrary`. +2. **`editPolicy` vs ecosystem-standard `update`** — the SDK exposes + `editPolicy` to match the wire path `/edit`, but most modern Databricks + surfaces use `update*`. Flag for upstream alignment. -3. **`createdAtTimestamp` is a tautology**; `createdAt` is the SDK-wide and - ecosystem-wide convention for epoch-millisecond fields. +3. **Type-suffix tautology in the `Library` union**: `MavenLibrary`, + `PythonPyPiLibrary`, `RCranLibrary` all repeat the `Library` suffix even + though their *position* in the discriminated union already identifies + them as library variants. ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) -- Rename `Library.lib` -> `Library.source` (concrete discriminator name). - `PythonPyPiLibrary` -> `PythonPyPILibrary`. -- `Policy.createdAtTimestamp` -> `Policy.createdAt`. -- `Policy.creatorUserName` -> `Policy.createdBy`. ### 3.4 Cross-package consistency notes - `editPolicy` (vs `updatePolicy`) is a per-API decision driven by the upstream REST verb; flag for upstream alignment but no per-package fix. - -## Fixed - -_None._ diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index 5e370d21..e98981cc 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -3,15 +3,15 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 **Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 78 +**Total weird names flagged:** 48 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 36 | -| Low | 24 | -| Observation | 9 | +| Medium | 21 | +| Low | 10 | +| Observation | 8 | ## High severity @@ -89,199 +89,109 @@ - **Suggested name:** `GetClusterPolicyComplianceRequest`, `EnforceClusterPolicyComplianceRequest`, `ListPolicyCompliantClustersRequest`, `ClusterPolicyCompliance`. - **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. -### 13. `validateOnly` field — `src/v2/model.ts:2357` -- **Why weird:** Field on `EnforcePolicyComplianceForClusterRequest`. Verb-prefixed boolean reads as a method; doc says "if set, previews the changes" — closer to a `previewOnly`/`dryRun` flag. -- **Category:** 6 (misleading: name implies "validate", behaviour is "dry-run"). -- **Suggested name:** `dryRun` or `previewOnly`. -- **Rationale:** Common convention; matches what most cloud SDKs name this. Wire stays `validate_only`. - -### 14. `hasChanges` field — `src/v2/model.ts:2366` +### 13. `hasChanges` field — `src/v2/model.ts:2366` - **Why weird:** Boolean on `EnforcePolicyComplianceForClusterRequest_Response` named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. - **Category:** 12 (duplicate signal), 1 (vague). - **Suggested name:** Drop the field, infer from `changes.length`. - **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. -### 15. `restartUser` field on `RestartClusterRequest` — `src/v2/model.ts:3037` -- **Why weird:** No JSDoc. Field name alone doesn't say what it does. Is it "user who triggered the restart"? "User to attribute the restart to"? Inconsistent with the package's general style (`ownerUsername`, `creatorUserName`, `singleUserName` all spell out `Username`/`UserName`). -- **Category:** 1 (vague — no doc, ambiguous semantics), 17 (sibling fields say `username` or `userName`, this one says `user`). -- **Suggested name:** `restartUsername` or `restartedByUsername`. -- **Rationale:** Match the field-naming patterns used elsewhere; even better, document the field. - -### 16. `creatorUserName` / `singleUserName` / `ownerUsername` — `src/v2/model.ts:1299,1181,1047` -- **Why weird:** Three "user name" fields in the same model, two different camelCases: `creatorUserName` and `singleUserName` use `UserName` (two words), `ownerUsername` uses `Username` (one word). Wire is `creator_user_name`, `single_user_name`, `owner_username` — the wire is inconsistent too. -- **Category:** 3 (casing inconsistency), 17 (sibling field inconsistency). -- **Suggested name:** Pick one: `Username` is more conventional in modern web APIs. Go SDK and proto leave this inconsistent; TS could normalise. -- **Rationale:** Three similar fields, three (sort of) similar names, two different ways of capitalising the same concept. - -### 17. `kind: ComputeKind` field — `src/v2/model.ts:1204` -- **Why weird:** Field is called `kind` on `ClusterInfo`, `CreateClusterRequest`, `EditClusterRequest`, and the update-cluster spec. Sibling fields are very specific (`runtimeEngine`, `dataSecurityMode`, `workloadType`); `kind` is the odd vague one. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `computeKind` (matches the type and wire name `kind` can stay). -- **Rationale:** `kind` alone is the JS-reserved-shape problem (`kind` is heavily overloaded in discriminated-union code). `computeKind` is unambiguous. - -### 18. `size` discriminated union (`numWorkers` | `autoscale`) — `src/v2/model.ts:1523` -- **Why weird:** Field `size` is a discriminated union with two variants `numWorkers` (number) and `autoscale` (object). It appears on six cluster-spec-shaped types. The literal `size` doesn't read as "either count or autoscaler" — calling code looks like `if (req.size?.$case === 'numWorkers')` which is awkward. -- **Category:** 1 (vague), 6 (misleading: a "size" sounds like an integer). -- **Suggested name:** `capacity` (or just `workers`, since both variants describe how many workers). -- **Rationale:** "size" suggests a number; this field is a tagged union. A different word avoids the contradiction. - -### 19. `useMlRuntime` field — `src/v2/model.ts:1210` +### 14. `useMlRuntime` field — `src/v2/model.ts:1210` - **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. - **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). - **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. - **Rationale:** A boolean and an enum jointly describing one runtime selection is a boolean-shaped-enum smell. -### 20. `isSingleNode` field — `src/v2/model.ts:1216` +### 15. `isSingleNode` field — `src/v2/model.ts:1216` - **Why weird:** Boolean field that, when true, automatically sets `custom_tags`, `spark_conf`, and `num_workers`. Doc admits the surprise: "When set to true, Databricks will automatically set single node related custom_tags, spark_conf, and num_workers." A field that secretly mutates three others is a footgun. - **Category:** 6 (misleading — hidden side effects). - **Suggested name:** Name is fine, but document the side effects in the type-level JSDoc, not just the field doc. - **Rationale:** Flag for upstream — the boolean is doing more than the name suggests. -### 21. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields +### 16. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields - **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. - **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). - **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. - **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. -### 22. `nodeTypeId` vs `instanceTypeId` — `src/v2/model.ts:1107,2906,2935` -- **Why weird:** `nodeTypeId` (string) and `instanceTypeId` (string) appear on different types. `NodeType.instanceTypeId` and `NodeInstanceType.instanceTypeId` are described as "hardware identifier (e.g., r3.2xlarge in AWS)" — i.e., the AWS instance class. `nodeTypeId` is the Databricks node type ID. Easy to confuse the two. -- **Category:** 19 (underspecified IDs — multiple "type" IDs coexisting). -- **Suggested name:** Either prefix one (`databricksNodeTypeId` / `cloudInstanceTypeId`) or rename `instanceTypeId` to `cloudInstanceTypeId` everywhere. -- **Rationale:** Two `*TypeId` fields side by side, distinguished only by `node` vs `instance`. Real users will get this wrong. - -### 23. `driverNodeTypeId` / `nodeTypeId` / `driverInstancePoolId` / `instancePoolId` — `src/v2/model.ts:1107,1116,1179,1191` -- **Why weird:** Pattern is "`driverX` and `X`" where `X` is the worker version. Four such pairs across the spec (`nodeTypeId`/`driverNodeTypeId`, `instancePoolId`/`driverInstancePoolId`, `nodeTypeFlexibility`/`driverNodeTypeFlexibility` — but the worker version is called `workerNodeTypeFlexibility` while the worker-`nodeTypeId` is just `nodeTypeId`). -- **Category:** 17 (inconsistent pairing — sometimes worker is prefix-less, sometimes prefixed `worker`). -- **Suggested name:** Either always prefix worker (`workerNodeTypeId`, `workerInstancePoolId`, `workerNodeTypeFlexibility`) or never (drop `worker` from `workerNodeTypeFlexibility`). -- **Rationale:** Reader who sees `driverNodeTypeId` next to `nodeTypeId` has to remember that the un-prefixed one is "worker"; then sees `workerNodeTypeFlexibility` and gets thrown. - -### 24. `NodeType.numCores` vs `ClusterInfo.clusterCores` — `src/v2/model.ts:2931,1314` -- **Why weird:** Same concept (number of CPU cores) appears as `numCores` on `NodeType` and `clusterCores` on `ClusterInfo`. The `num` prefix is inconsistent with the bare `clusterCores`. -- **Category:** 17 (inconsistent prefix), 1 (`num` is vague compared to the rest of the model). -- **Suggested name:** `cores` (on `NodeType`) and `clusterCores` stays (or both `cores`/`totalCores`). -- **Rationale:** Compare to `clusterMemoryMb` (no `num` prefix), `memoryMb` (no `num` prefix). `numCores` and `numGpus` are the outliers. - -### 25. `NodeType.numGpus` — `src/v2/model.ts:2951` -- **Why weird:** Same `num` prefix issue as #24. Sibling fields don't carry a `num` prefix (`memoryMb`, `localDisks`, `category`). -- **Category:** 17 (inconsistent prefix), 1. -- **Suggested name:** `gpus` (or `gpuCount`). -- **Rationale:** Internal consistency. - -### 26. `NodeInstanceType.localDisks` and `NodeInstanceType.localNvmeDisks` are counts — `src/v2/model.ts:2908,2914` -- **Why weird:** Plural noun `localDisks` is typed as `number`, but JSDoc says "Number of local disks that are present on this instance." Counting things should use `count`/`num` suffix, not the plural noun. -- **Category:** 9 (singular vs plural confusion — the plural noun is actually a count). -- **Suggested name:** `localDiskCount`, `localNvmeDiskCount`. -- **Rationale:** A reader sees `localDisks: number` and might assume "array of local disks" — then realises it's a scalar. - -### 27. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` +### 17. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` - **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. - **Category:** 17 (inconsistent grouping). - **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. - **Rationale:** Within the same type, related fields should sit together. -### 28. `ListAvailableZonesRequest_Response.defaultZone` — `src/v2/model.ts:2809` +### 18. `ListAvailableZonesRequest_Response.defaultZone` — `src/v2/model.ts:2809` - **Why weird:** JSDoc says "The availability zone if no `zone_id` is provided in the cluster creation request." The doc references `zone_id` (the wire name) instead of the TS `zoneId`. Other docstrings in the package also reference `zone_id`, `cluster_id`, `cluster_log_conf`, `init_scripts`, etc. - **Category:** Observation — generated docs reference wire names rather than TS names. - **Suggested name:** Update doc-comment generation to use TS names. - **Rationale:** Inconsistent doc/identifier pairing makes IntelliSense suggestions look out-of-date. -### 29. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2880` +### 19. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2880` - **Why weird:** `LogAnalyticsInfo` has two fields (`logAnalyticsWorkspaceId`, `logAnalyticsPrimaryKey`), both un-documented. The type itself has no JSDoc. Used only by `AzureAttributes.logAnalyticsInfo`. - **Category:** Observation (no naming issue per se, but missing context). - **Suggested name:** Keep `LogAnalyticsInfo` (Azure Monitor terminology) but add a JSDoc; consider `AzureLogAnalyticsConfig`. - **Rationale:** Both fields are Azure-specific; naming should signal that. -### 30. `LogSyncStatus.lastException: string` — `src/v2/model.ts:2896` -- **Why weird:** Field name is `lastException` (singular: the previous exception) but the type is `string`. JS exceptions are usually serialised as messages; a more accurate name would be `lastExceptionMessage`. -- **Category:** 1 (vague — `Exception` is overloaded), 16 (type contradicts the name domain). -- **Suggested name:** `lastErrorMessage` or `lastExceptionMessage`. -- **Rationale:** Distinguishes an Error object reference from its serialised string form. - -### 31. `LogSyncStatus.lastAttempted: number` — `src/v2/model.ts:2891` -- **Why weird:** `lastAttempted` is a verb-past-participle, type is `number` (epoch millis per JSDoc). Hard to tell from the name that this is a timestamp. -- **Category:** 1 (vague), 6 (misleading — sounds like a boolean or count). -- **Suggested name:** `lastAttemptedAt`, `lastAttemptTime`, `lastAttemptedMs`. -- **Rationale:** Match the timestamp-suffix convention used elsewhere in this model (`startTime`, `terminatedTime`, `lastRestartedTime`, `lastStateLossTime`). - -### 32. `ClusterInfo.startTime`/`terminatedTime`/`lastStateLossTime`/`lastRestartedTime` — `src/v2/model.ts:1516-1522` -- **Why weird:** Four sibling timestamps. `startTime` and `terminatedTime` use different shapes (`start` + `Time` vs `terminated` + `Time`); `lastStateLossTime` and `lastRestartedTime` use past participle + `Time`. Mix of forms. Also `LogSyncStatus.lastAttempted` (#31) drops the `Time` suffix entirely. -- **Category:** 17 (inconsistent timestamp suffix), 13 (verb-tense inconsistency: `start` vs `terminated` vs `restarted`). -- **Suggested name:** Choose one suffix (`-At`, `-Time`, `-Ms`) and apply uniformly: `startedAt`, `terminatedAt`, `lastStateLostAt`, `lastRestartedAt`, `lastAttemptedAt`. -- **Rationale:** Timestamp suffixes are a high-impact, low-cost consistency win. - -### 33. `SparkInfo_SparkNode.startTimestamp` — `src/v2/model.ts:3109` -- **Why weird:** Same node-related concept as `ClusterInfo.startTime` (#32) but uses `Timestamp` rather than `Time`. Different word for the same idea. -- **Category:** 17 (inconsistent across types). -- **Suggested name:** `startTime` (or align all timestamps under one suffix). -- **Rationale:** Two timestamp suffixes in the same file is two too many. - -### 34. `creatorUserName` field — `src/v2/model.ts:1299` -- **Why weird:** TS camelCase splits `User` and `Name` (`creatorUserName`) but the conceptually-similar `singleUserName` does the same. Compare to `ownerUsername` (one word) on `ChangeClusterOwnerRequest`. Inconsistency between three sibling concepts. Documented behaviour: "The field won't be included in the response if the user has already been deleted" — but no `undefined` annotation distinguishes "absent because new" from "absent because deleted". -- **Category:** 3 (casing inconsistency), see also #16. -- **Suggested name:** `creatorUsername`. -- **Rationale:** Already covered in #16; flagged again because it appears on the main `ClusterInfo` type which dominates user reading time. - -### 35. `clusterLogStatus` field — `src/v2/model.ts:1330` +### 20. `clusterLogStatus` field — `src/v2/model.ts:1330` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). - **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. - **Rationale:** Same concept, two different names in 5 lines. -### 36. `jdbcPort` field — `src/v2/model.ts:1358` +### 21. `jdbcPort` field — `src/v2/model.ts:1358` - **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). -- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #37). +- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #22). -### 37. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` +### 22. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` - **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. - **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. -### 38. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` +### 23. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` - **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. - **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). - **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. - **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. -### 39. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` +### 24. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` - **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. - **Category:** 12 (duplicate concepts), 17 (could be a tagged union). - **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). - **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. -### 40. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:3055,3060` +### 25. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:3055,3060` - **Why weird:** JSDoc explicitly says "Either region or endpoint needs to be set. If both are set, endpoint will be used." Mutually-exclusive fields not encoded in the type. - **Category:** 16 (field-pair constraint not in the type). - **Suggested name:** Could be a discriminated union `{kind: 'region', value: string} | {kind: 'endpoint', value: string}`. - **Rationale:** Type-system-encodable constraint; flagged for upstream. -### 41. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` +### 26. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` - **Why weird:** `SparkInfo` is declared as an empty interface (`export interface SparkInfo {}`) whose JSDoc literally says "This is used in both the [[ClusterInfo]] for Cluster APIs and persisted cluster proto." Its only purpose is to namespace `SparkInfo_SparkNode` and `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Empty wrapper types tied to "persisted cluster proto" are pure proto-architectural leak — the TS surface carries a do-nothing type just to mirror proto message nesting. - **Category:** 14 (proto-style namespace anchor), 8 (JSDoc references the proto wire layer). - **Suggested name:** Delete `SparkInfo`; expose `SparkNode` (and `SparkNodeAwsAttributes`) as top-level types. - **Rationale:** TS doesn't need proto-style nesting; the empty parent interface is a generator artefact and a user-facing footgun (auto-completion shows a useless symbol). -### 42. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` -- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #44) is the smoking gun — the parent exists only to host the child. +### 27. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` +- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #29) is the smoking gun — the parent exists only to host the child. - **Category:** 14 (proto-style namespace anchor). - **Suggested name:** Delete `ClusterEventType` (the parent) and flatten the enum to a top-level `ClusterEventType` enum. The empty wrapper adds no value. -- **Rationale:** Same as #41 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. +- **Rationale:** Same as #26 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. -### 43. JSDoc text `"Proto defined to model a mapping from string to string."` — `src/v2/model.ts:1266,2615` +### 28. JSDoc text `"Proto defined to model a mapping from string to string."` — `src/v2/model.ts:1266,2615` - **Why weird:** Two JSDoc strings literally start with "Proto defined to model...". The word "Proto" leaks the wire encoding into the TS user surface; the rest of the sentence (a `Record`) is generic boilerplate that ships as the only documentation for these `*Entry` types. - **Category:** 14 (proto vocabulary in public-facing docs). - **Suggested name:** Rewrite the JSDoc to describe the field semantics in TS terms (e.g., "Key-value pairs of policy violations, keyed by field path."). - **Rationale:** A TS SDK doc should not say "Proto defined to" — that exposes the implementation strategy. Users see "Proto" in IntelliSense and wonder if they need a proto library. -### 44. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` -- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#42) is empty, so the doubly-stuttered name carries no information. +### 29. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` +- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#27) is empty, so the doubly-stuttered name carries no information. - **Category:** 14 (proto nesting stutter), 4 (redundant repetition). - **Suggested name:** `ClusterEventType` (single, top-level). -- **Rationale:** After deleting the empty parent (#42), the child can drop the `ClusterEventType_` prefix entirely. +- **Rationale:** After deleting the empty parent (#27), the child can drop the `ClusterEventType_` prefix entirely. -### 45. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` +### 30. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` - **Why weird:** "Data plane" is an internal Databricks infrastructure concept (vs "control plane") — not a customer-facing domain term. Two public types prefix their names with the deployment-plane they originate from. A user creating a cluster does not need to know which plane emitted which event class; the distinction is a Databricks-internal architecture detail. - **Category:** 8 (internal architecture leak in public surface). - **Suggested name:** Either merge into a single `ClusterEventType` enum / `EventDetails` shape, or rename to a non-infrastructure word (e.g., `RuntimeEventDetails`). @@ -289,145 +199,61 @@ ## Low severity -### 46. `ClusterInfo.spec` field name — `src/v2/model.ts:1340` -- **Why weird:** Field is just `spec`. Very short for a top-level field on the main cluster type; reader has to follow the type to learn what kind of spec it is. -- **Category:** 1 (vague — `spec` alone could mean anything). -- **Suggested name:** `computeSpec` or `clusterSpec`. -- **Rationale:** A more specific field name documents intent at the call site without forcing the reader to chase the type. - -### 47. `ClusterInfo.driver` field — `src/v2/model.ts:1345` -- **Why weird:** Field name is `driver` — overloaded (could mean a person or an Apache Spark driver concept). Better: `driverNode`. -- **Category:** 1 (vague). -- **Suggested name:** `driverNode`. -- **Rationale:** Reader sees `driver` and has to know to follow the type. - -### 48. `ClusterInfo.executors` field — `src/v2/model.ts:1347` -- **Why weird:** Same as #42. `executors` is fine in Spark vocabulary but better paired with `driverNode`: `executorNodes`. -- **Category:** 17 (inconsistent with `driver`). -- **Suggested name:** `executorNodes`. -- **Rationale:** Match the `driver`/`executor` pattern. - -### 49. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1177,1468,1663,2012,2271,3314` +### 31. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1177,1468,1663,2012,2271,3314` - **Why weird:** JSDoc abbreviation `BYOC` (Bring Your Own Container) used without expansion. Appears six times in the model. - **Category:** 5 (cryptic abbreviation in JSDoc). - **Suggested name:** N/A — fix the comment, not the identifier. - **Rationale:** Quick doc fix. -### 50. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1353` +### 32. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1353` - **Why weird:** Field is named `sparkContextId` but typed as `number`. Other IDs in the model are strings (`clusterId`, `policyId`, `nodeTypeId`). Internal Spark context IDs are 64-bit ints — the type clash hints at potential JS number-precision issues for large IDs. - **Category:** 19 (underspecified ID — different type from sibling IDs). - **Suggested name:** Keep but consider `bigint` typing or document the precision risk. - **Rationale:** JS number safe-integer range is 2^53; if Spark uses 64-bit IDs, this is a latent bug. -### 51. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` +### 33. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` - **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. - **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). - **Suggested name:** `credentials` (singular). - **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. -### 52. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:2116,2118` +### 34. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:2116,2118` - **Why weird:** Doc strings are "Name of the user" and "Password of the user" — generic and add no information beyond the field names. - **Category:** Observation (low-quality docstrings). - **Suggested name:** No rename; flag doc-quality. - **Rationale:** Minor. -### 53. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:981` +### 35. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:981` - **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:1041`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. - **Category:** 17 (sibling AWS/Azure shapes differ), 1 (`number` without unit suffix). - **Suggested name:** `spotBidPricePercent` is fine; flag for upstream — the AWS/Azure semantics should be more discoverable from the model. - **Rationale:** Cross-cloud asymmetry is a domain concern. -### 54. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:1041` +### 36. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:1041` - **Why weird:** Magic value `-1` overloaded as "do not evict on price basis". Encoded in JSDoc, not in the type. - **Category:** 16 (sentinel value in scalar field), Observation. - **Suggested name:** N/A; flag for upstream to consider a sentinel enum or `null`. - **Rationale:** Sentinels in scalar fields are old-school API design. -### 55. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2458` +### 37. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2458` - **Why weird:** JSDoc says "Note: Soon to be deprecated, use the 'availability' field instead." But the field is not actually marked `@deprecated`. - **Category:** Observation — missing `@deprecated`. - **Suggested name:** Add `@deprecated` JSDoc tag. - **Rationale:** Tooling can pick up `@deprecated`; "Note: Soon to be deprecated" is invisible to IDEs. -### 56. `GcpAttributes.googleServiceAccount: string` — `src/v2/model.ts:2465` -- **Why weird:** Field `googleServiceAccount` lives on `GcpAttributes`. The `google` prefix is redundant — sibling fields don't say `googleZoneId`, `googleAvailability`, `googleBootDiskSize`. -- **Category:** 17 (inconsistent prefix within `GcpAttributes`). -- **Suggested name:** `serviceAccount` (drop the `google` prefix). -- **Rationale:** Internal consistency; the type's name already says GCP. - -### 57. `GcpAttributes.bootDiskSize: number` — `src/v2/model.ts:2467` -- **Why weird:** Doc says "Boot disk size in GB" but field has no unit suffix. Compare `ebsVolumeSize`/`ebsVolumeIops`/`ebsVolumeThroughput` (no unit suffixes either) and `remoteDiskThroughput` (`Mb/s` per doc, no suffix). Pattern is "no unit suffix" — but `clusterMemoryMb`, `memoryMb`, `localDiskSizeGb` DO have unit suffixes. Inconsistent. -- **Category:** 17 (inconsistent unit-suffix convention). -- **Suggested name:** `bootDiskSizeGb`. -- **Rationale:** Match the `*Mb`, `*Gb` pattern used on the same struct hierarchy. - -### 58. `GcpAttributes.localSsdCount: number` field with prose comment — `src/v2/model.ts:2489` -- **Why weird:** Field is named `localSsdCount`; sibling `bootDiskSize` is unsuffixed; `firstOnDemand` is also unsuffixed. Three different "amount" fields, three different suffix conventions. -- **Category:** 17 (inconsistent quantity suffix). -- **Suggested name:** Either all carry `Count`/`Size`/`Mb` etc. or none do. -- **Rationale:** Within `GcpAttributes`, `localSsdCount` carries a `Count` suffix while `firstOnDemand` (also a count) does not. - -### 59. `firstOnDemand` field name — `src/v2/model.ts:946,1028,2499` -- **Why weird:** Used on `AwsAttributes`, `AzureAttributes`, `GcpAttributes`. Reads as "first on-demand what?". Doc says "The first `first_on_demand` nodes of the cluster will be placed on on-demand instances" — meta-circular. -- **Category:** 1 (vague), 7 (no noun). -- **Suggested name:** `firstOnDemandNodes` or `onDemandNodeCount`. -- **Rationale:** The name is missing the noun it describes. - -### 60. `ChangeClusterOwnerRequest.ownerUsername` field docstring — `src/v2/model.ts:1047` +### 38. `ChangeClusterOwnerRequest.ownerUsername` field docstring — `src/v2/model.ts:1047` - **Why weird:** Doc says "New owner of the cluster_id after this RPC." `RPC` jargon leaks. `cluster_id` is the wire name; should be `clusterId`. - **Category:** Observation (doc quality), 5 (RPC jargon). - **Suggested name:** Update doc text. - **Rationale:** Minor doc fix. -### 61. `ClusterCompliance.violations: Record` — `src/v2/model.ts:1263` -- **Why weird:** Map from string (policy field path) to string (error message). Field name `violations` doesn't communicate the shape. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `violationsByField` or `fieldViolations`. -- **Rationale:** Clarifies the map's semantics. - -### 62. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.field: string` — `src/v2/model.ts:2383` -- **Why weird:** Field on a "ClusterSettingsChange" is itself named `field`. Reads as `change.field` — circular. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `fieldPath` or `settingName`. -- **Rationale:** Minor; flags pile up. - -### 63. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2390,2397` +### 39. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2390,2397` - **Why weird:** Both fields typed as `string`. JSDoc says values are "either a number, a boolean, or a string converted to a string." Pre-stringified union encoded as plain string — caller must re-parse. - **Category:** 16 (type contradicts domain — it's actually `number | boolean | string` flattened to string). - **Suggested name:** Type as `string | number | boolean`, or `previousValueRaw`. - **Rationale:** Documents the stringification rather than hiding it. -### 64. `SparkVersion.key` / `name` — `src/v2/model.ts:3130,3132` -- **Why weird:** Two very generic field names; from `SparkVersion`, `key` is the version string and `name` is the display name. Inversion of typical (`name`=identifier, `displayName`=human-readable). -- **Category:** 1 (vague), 6 (misleading). -- **Suggested name:** `version`/`displayName` or `versionKey`/`label`. -- **Rationale:** `key` is one of the most overloaded names in software. - -### 65. `NodeType.key`-like fields — `nodeTypeId`, `instanceTypeId`, `description`, `category` — `src/v2/model.ts:2923-2975` -- **Why weird:** 20 fields on `NodeType`, several with vague names: `description`, `category`. No JSDoc on `displayOrder` until line 2962. Some fields are `is*` booleans (`isDeprecated`, `isHidden`, `isIoCacheEnabled`, `isEncryptedInTransit`, `isGraviton`), others are `support*` booleans (`supportEbsVolumes`, `supportClusterTags`, `supportPortForwarding`), others are `*Capable` booleans (`photonWorkerCapable`, `photonDriverCapable`). -- **Category:** 17 (inconsistent boolean prefix: `is*`/`support*`/`*Capable`). -- **Suggested name:** Pick one convention (`is*Supported`). -- **Rationale:** Three different boolean-naming patterns on one struct. - -### 66. `NodeType.supportEbsVolumes` field name — `src/v2/model.ts:2947` -- **Why weird:** Singular verb `support` (third-person plural would be "supports"). All siblings: `supportClusterTags`, `supportPortForwarding`. Three fields use the singular form. -- **Category:** 13 (verb tense — should be `supports`). -- **Suggested name:** `supportsEbsVolumes`, `supportsClusterTags`, `supportsPortForwarding`. -- **Rationale:** Subject-verb agreement in field names is common (`hasFoo`, `isFoo`, `supportsFoo`). - -### 67. `NodeType.photonWorkerCapable` / `photonDriverCapable` — `src/v2/model.ts:2967,2968` -- **Why weird:** No JSDoc. `*Capable` suffix is a different boolean convention from `is*`/`support*`. -- **Category:** 17 (inconsistent boolean shape), Observation (missing doc). -- **Suggested name:** `isPhotonWorkerSupported`, `isPhotonDriverSupported` (or `supportsPhotonAsWorker`). -- **Rationale:** Same pattern as #60. - -### 68. `TerminationReason.parameters: Record` — `src/v2/model.ts:3149` -- **Why weird:** Generic-named map. `parameters` could mean anything. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `details`, `metadata`, `errorContext`. -- **Rationale:** Clarifies the role of the map. - -### 69. `AutoScale` type name — `src/v2/model.ts:922` +### 40. `AutoScale` type name — `src/v2/model.ts:922` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). @@ -435,41 +261,36 @@ ## Observations -### 70. Seven Waiter classes with identical shape — `client.ts:967-1523` +### 41. Seven Waiter classes with identical shape — `client.ts:967-1523` The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. - **Category:** 12 (duplicate concept across seven classes), Observation. - **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. -### 71. `_req` parameter for empty request types — `client.ts:404,486,514` +### 42. `_req` parameter for empty request types — `client.ts:404,486,514` Several methods take a `_req: ListAvailableZonesRequest` / `_req: ListNodeTypesRequest` / `_req: GetSparkVersionsRequest` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. - **Category:** Observation (generator artefact). -### 72. `enable*` boolean conventions — `enableElasticDisk`, `enableLocalDiskEncryption`, `enableEncryption` -- **Why weird:** Three sibling booleans use `enable*` prefix. `is*` is the more idiomatic JS boolean convention. Inconsistent with `isSingleNode`, `isCompliant`, `isDeprecated`. -- **Category:** 17 (mixed `enable*` and `is*` for booleans). -- **Rationale:** Naming-convention drift. - -### 73. `ResizeClusterRequest` / `RestartClusterRequest` requests are partial overlaps +### 43. `ResizeClusterRequest` / `RestartClusterRequest` requests are partial overlaps `ResizeClusterRequest` carries `clusterId` and `size`; `RestartClusterRequest` carries `clusterId` and `restartUser`; `StartClusterRequest` carries only `clusterId`. Three near-identical types; could be one. - **Category:** 12 (duplicate concept), Observation. -### 74. `_req` unused vs `req` used — inconsistency in method-signature lint +### 44. `_req` unused vs `req` used — inconsistency in method-signature lint Three client methods use `_req` (where the request type is empty), the rest use `req` (where it's not). Pure mechanical. - **Category:** Observation. -### 75. `clusterId?: string | undefined` shape +### 45. `clusterId?: string | undefined` shape Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:258,304,357,641,683,733,817`). - **Category:** 6 (misleading optional — should be required), Observation. -### 76. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) +### 46. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). - **Category:** 1 (vague), 17 (inconsistent), Observation. -### 77. `flattenQueryParams` exported but unused (`utils.ts:123`) +### 47. `flattenQueryParams` exported but unused (`utils.ts:123`) The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. - **Category:** Observation (dead public surface). -### 78. JSDoc placeholder `` — pervasive +### 48. JSDoc placeholder `` — pervasive Throughout the model, JSDocs say `` (e.g., `model.ts:1128` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. - **Category:** Observation (doc-quality artefact in generator). @@ -526,7 +347,3 @@ Throughout the model, JSDocs say `` (e.g., `model.ts:1128` — "Data - `src/v2/model.ts` (5315 lines): read fully (in 800-line chunks). - `src/v2/client.ts` (1523 lines): read fully. - `src/v2/utils.ts` (150 lines): read fully. - -## Fixed - -_None._ diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index 394f76dc..b47e228a 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -23,40 +23,26 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | -- | -------- | -------- | -------- | ------- | -------- | | 1 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | | 2 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | -| 3 | high | 15. Generic field on container | `model.ts:71`, `model.ts:100,112` | `id?: string` (three different IDs) | `contextId`, `commandId` (typed by domain) | -| 4 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | -| 5 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | -| 6 | high | 1. Vague/generic | `model.ts:89` | `command?: string` (field, inside `ExecuteCommandRequest`) | `code` | -| 7 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | -| 8 | medium | 9. Singular/plural mismatch | `model.ts:102,116-143` | `results?: Results` (`Results` is one object) | `result?: Result` | -| 9 | medium | 1. Vague/generic | `model.ts:119` | `data?: JsonValue` | Inline rename to domain (e.g. `tableData`), or document semantics | -| 10 | medium | 16. Field contradicts type domain | `model.ts:129,131` | `fileName`, `fileNames` (used for image data URLs) | `imageData`, `imageDataList` (or `image`, `images`) | -| 11 | medium | 1. Vague/generic | `model.ts:135` | `pos?: number` | `position` (also rename comment to public-friendly) | -| 12 | medium | 1. Vague/generic | `model.ts:138` | `schema?: JsonObject[]` | `tableSchema` (qualify what schema) | -| 13 | medium | 19. Underspecified IDs | `model.ts:71,100,112` | `id?: string` | `contextId` / `commandId` per response | -| 14 | medium | 19. Underspecified IDs | `client.ts:336,337,338` | `clusterId`, `contextId`, `commandId` (fine, but match in `Results.id`) | Audit pass for consistency | -| 15 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | -| 16 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | -| 17 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to a single form (e.g. `Failed` in place of `Error` so every member is a past/present participle). | -| 18 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | -| 19 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | -| 20 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 21 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 22 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 23 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 24 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 25 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 26 | low | 1. Vague/generic | `model.ts:118` | `cause?: string` | Acceptable, but JSDoc says "The cause of the error" — better as `errorCause` or document under `Results.cause` | -| 27 | low | 1. Vague/generic | `model.ts:140` | `summary?: string` | Doc says "summary of the error" — rename `errorSummary` or move into a nested `error` object | -| 28 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | -| 29 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | -| 30 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | -| 31 | low | 10. Reserved-word collision | `model.ts:138` | `schema` as field name | Not reserved, but very generic globally — see #12 | -| 32 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | -| 33 | low | 15. Generic field losing meaning | `model.ts:89` | `command` inside `ExecuteCommandRequest` | The string is the *source code*, not "the command" — see #6 | -| 34 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 35 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | -| 36 | low | 9. Singular/plural mismatch | `model.ts:131` | `fileNames?: string[]` (plural) but used for *images*, not arbitrary files | See #10 | +| 3 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | +| 4 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | +| 5 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | +| 6 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | +| 7 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | +| 8 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to a single form (e.g. `Failed` in place of `Error` so every member is a past/present participle). | +| 9 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | +| 10 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | +| 11 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 12 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 13 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 14 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 15 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 16 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 17 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | +| 18 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | +| 19 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | +| 20 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | +| 21 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 22 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | --- @@ -99,29 +85,12 @@ async execute(req: ExecuteCommandRequest, ...): Promise but `execute()` is not a creation operation in the public-API sense — the shared shape is incidental, not semantic. Reusing the type forces a caller reading `response.id` to know the operation to interpret it. -**Proposed:** split into `CreateContextResponse { contextId?: string }` and -`ExecuteCommandResponse { commandId?: string }`. Each typed `id` field by -its true domain (see #3/#13). +**Proposed:** split into `CreateContextResponse` and +`ExecuteCommandResponse`. --- -### Finding 3 — High — Cat 15 (Generic field loses meaning) -**Location:** `src/v2/model.ts:71, 100, 112` -```ts -export interface CreateResponse { id?: string | undefined; } -export interface GetCommandStatusResponse { id?: string | undefined; ... } -export interface GetContextStatusResponse { id?: string | undefined; ... } -``` -The field name `id` is meaning-free outside its container, and the -container's name doesn't disambiguate (`CreateResponse` is used for two -different create-like operations — see #2). A caller writing `resp.id` -cannot tell whether it is a command id or a context id. -**Proposed:** rename per-response: `contextId` / `commandId`. This couples -the schema to the resource, eliminating ambiguity. - ---- - -### Finding 4 — High — Cat 17 (Inconsistent action verbs) +### Finding 3 — High — Cat 17 (Inconsistent action verbs) **Location:** `src/v2/client.ts:256` ```ts /** Deletes an execution context. */ @@ -136,7 +105,7 @@ align with the Go SDK convention. At minimum, edit the JSDoc to say --- -### Finding 5 — High — Cat 17 (Inconsistent action verbs) +### Finding 4 — High — Cat 17 (Inconsistent action verbs) **Location:** `src/v2/client.ts:139, 176` ```ts async commandStatus(req: GetCommandStatusRequest, ...) @@ -151,23 +120,7 @@ the request-type name and is verb-led like the other methods. --- -### Finding 6 — High — Cat 1 & Cat 15 (Vague / generic field name) -**Location:** `src/v2/model.ts:89` -```ts -/** Executable code */ -command?: string | undefined; -``` -The field is named `command` and lives in `ExecuteCommandRequest`. The -container says "command", the field says "command" — yet the value is -source code, not the abstract command. A user reading -`req.command = "print(1+1)"` has to mentally bridge "the string content of -the command". -**Proposed:** rename `code`. The JSDoc already says "Executable code". This -also matches the conceptual model: a `Command` *contains* `code`. - ---- - -### Finding 7 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +### Finding 5 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) **Location:** `src/v2/model.ts:117-143` ```ts export interface Results { ... } @@ -176,102 +129,11 @@ The type is called `Results` (plural) but represents **one** command's result — a single `cause`, single `summary`, single `resultType`, single `data` object. The plurality comes from the wire-level `fileNames` array inside it, not from multiple results. -**Proposed:** rename to `Result` (singular). The field -`GetCommandStatusResponse.results` becomes `result` (see #8). - ---- - -### Finding 8 — Medium — Cat 9 (Singular/plural mismatch) -**Location:** `src/v2/model.ts:102` (field) and `model.ts:116` (type) -```ts -results?: Results | undefined; -``` -Pairs with #7. The field name and the type are both pluralised but -represent a singular result. -**Proposed:** `result?: Result;` once #7 is applied. - ---- - -### Finding 9 — Medium — Cat 1 (Vague/generic) -**Location:** `src/v2/model.ts:119` -```ts -data?: JsonValue | undefined; -``` -`data` is the most generic field name possible. The shape `JsonValue` -gives no help. According to API docs, this is typically the table/text data -returned by the command. -**Proposed:** investigate intended payload. Likely `tableData` or split per -`resultType` discriminant. As a minimum, JSDoc must explain the polymorphism -("payload of `result.data` is determined by `resultType`: …"). - ---- - -### Finding 10 — Medium — Cat 16 (Field contradicts type domain) -**Location:** `src/v2/model.ts:129, 131` -```ts -/** The image data in one of the following formats: - * 1. A Data URL with base64-encoded image data: `data:image/{type};base64,...` - * 2. A FileStore file path for large images: `/plots/{filename}.png` - */ -fileName?: string | undefined; -/** List of image data for multiple images. ... */ -fileNames?: string[] | undefined; -``` -The JSDoc explicitly says "image data" — yet the fields are called -`fileName(s)`. The values are not file names: case 1 is a `data:` URL -literal, case 2 is a path. Either way the *content* is image data, -not a filename. -**Proposed:** `imageData` / `imageDataList` (or `image` / `images`). This -is a public API; mis-named fields will outlive their fix window. - ---- - -### Finding 11 — Medium — Cat 1 (Cryptic abbreviation / vague) -**Location:** `src/v2/model.ts:135` -```ts -/** internal field used by SDK */ -pos?: number | undefined; -``` -`pos` is cryptic (Cat 5 — cryptic abbreviation). The comment "internal -field used by SDK" suggests this should not be on the public type at all. -**Proposed:** either expand to `position` and document, or drop from the -public interface entirely. Internal fields belong on private types. - ---- - -### Finding 12 — Medium — Cat 1 (Vague/generic) -**Location:** `src/v2/model.ts:138` -```ts -/** The table schema */ -schema?: JsonObject[] | undefined; -``` -`schema` is colliding with a globally overloaded term — also see zod's own -`schema` used heavily in the file. Within a polymorphic `Result`, the -*kind* of schema must be clear. -**Proposed:** `tableSchema` (matches JSDoc); confirm whether it is -populated for non-table result types. +**Proposed:** rename to `Result` (singular). --- -### Finding 13 — Medium — Cat 19 (Underspecified IDs) -**Location:** `src/v2/model.ts:71, 100, 112` -**Issue:** Same as #3. Every response that carries an identifier uses -`id?: string` with no domain qualifier. -**Proposed:** Rename per-response (`contextId`, `commandId`). Public-API -clarity outweighs minor breakage. - ---- - -### Finding 14 — Medium — Cat 19 (Underspecified IDs) — consistency only -**Location:** `src/v2/client.ts:336-338, 417-422, 498-503` (Waiter fields) -**Issue:** Waiter classes correctly use `clusterId`, `contextId`, -`commandId`. The inconsistency is only in `Results` / `*Response` (#3/#13). -**Proposed:** apply the same explicit-id pattern to all response types so -the public surface is uniform. - ---- - -### Finding 15 — Medium — Cat 7 (Overly verbose) +### Finding 6 — Medium — Cat 7 (Overly verbose) **Location:** `src/v2/model.ts:99, 111` ```ts export interface GetCommandStatusResponse { ... } @@ -285,7 +147,7 @@ returned", not "the response to a GET". --- -### Finding 16 — Medium — Cat 20 (Type-suffix tautology) — call-out only +### Finding 7 — Medium — Cat 20 (Type-suffix tautology) — call-out only **Location:** `src/v2/model.ts:55, 64, 74, 82, 93, 106` ```ts CancelCommandRequest, CreateContextRequest, DestroyContextRequest, @@ -298,7 +160,7 @@ convention is widely accepted across REST SDKs. --- -### Finding 17 — Medium — Cat 13 (Verb-tense inconsistency) +### Finding 8 — Medium — Cat 13 (Verb-tense inconsistency) **Location:** `src/v2/model.ts:23-28` The `CommandStatus` members mix forms: - `CANCELLED` — past participle @@ -315,7 +177,7 @@ should be `FAILED` (past participle) to match the pattern. --- -### Finding 18 — Medium — Cat 3 (Acronym casing) +### Finding 9 — Medium — Cat 3 (Acronym casing) **Location:** `src/v2/model.ts:133` ```ts isJsonSchema?: boolean | undefined; @@ -328,14 +190,14 @@ recorded in `.agent/rules/typescript.mdc`. --- -### Finding 19 — Medium — Cat 12 (Duplicate concepts) +### Finding 10 — Medium — Cat 12 (Duplicate concepts) **Location:** `src/v2/client.ts:286-309` **Issue:** `execute()` returns `Promise`. The conflation of "create a context" and "execute returns an id" is artificial. See #2. --- -### Finding 20 — Medium — Cat 14 (Go/Java-style names) +### Finding 11 — Medium — Cat 14 (Go/Java-style names) **Location:** `src/v2/model.ts:74` + `client.ts:256` **Issue:** `destroy` is unusual for a REST SDK. JS conventions favour `delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend @@ -346,15 +208,15 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 21 — Medium — Cat 8 (Redundant suffix) — call-out +### Finding 12 — Medium — Cat 8 (Redundant suffix) — call-out **Location:** `src/v2/client.ts:333, 417, 498` **Issue:** Three classes named `*Waiter`. Acceptable if waiter is a recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #22-#24. +issue is what they wait *for*: see #13-#15. --- -### Finding 22 — Medium — Cat 6 (Misleading name) +### Finding 13 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:417` ```ts export class CreateWaiter { ... } @@ -369,21 +231,21 @@ target endpoint). --- -### Finding 23 — Medium — Cat 6 (Misleading name) +### Finding 14 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:333` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 24 — Medium — Cat 6 (Misleading name) +### Finding 15 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:498` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. --- -### Finding 25 — Medium — Cat 17 (Inconsistent action verbs) — call-out +### Finding 16 — Medium — Cat 17 (Inconsistent action verbs) — call-out **Location:** `src/v2/client.ts:86, 256` **Issue:** This package uses three lifecycle verbs: - `cancel()` on a command, @@ -396,32 +258,7 @@ Go-SDK alignment decision. --- -### Finding 26 — Low — Cat 1 (Vague/generic) -**Location:** `src/v2/model.ts:117-118` -```ts -/** The cause of the error */ -cause?: string | undefined; -``` -`cause` is fine as a JSDoc-clarified concept, but it lives flat on a -`Result` that may *not* be an error. Coupling `cause`/`summary` to the -`resultType === ERROR_RESULT` discriminant would clarify. -**Proposed:** consider an `error?: { cause: string; summary: string }` -sub-object; or keep flat and document conditional presence. - ---- - -### Finding 27 — Low — Cat 1 (Vague/generic) -**Location:** `src/v2/model.ts:139-140` -```ts -/** The summary of the error */ -summary?: string | undefined; -``` -Same as #26. The field is generic; the JSDoc reveals it's -error-specific. - ---- - -### Finding 28 — Low — Cat 1 (Underspecified) +### Finding 17 — Low — Cat 1 (Underspecified) **Location:** `src/v2/model.ts:141-142` ```ts /** true if partial results are returned. */ @@ -432,7 +269,7 @@ Acceptable but ambiguous: truncated *what*? table rows? text length? --- -### Finding 29 — Low — Cat 1 (Vague/generic) — call-out +### Finding 18 — Low — Cat 1 (Vague/generic) — call-out **Location:** `src/v2/client.ts:54` ```ts class StillRunningError extends Error {} @@ -441,7 +278,7 @@ Private, OK. Idiomatic for waiter polling patterns. --- -### Finding 30 — Low — Cat 3 (Acronym casing) — non-issue +### Finding 19 — Low — Cat 3 (Acronym casing) — non-issue **Location:** `src/v2/client.ts:49-52` ```ts const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; @@ -452,33 +289,20 @@ correctly cased per the project rules. --- -### Finding 31 — Low — Cat 10 (Reserved-word collision) — borderline -**Location:** `src/v2/model.ts:138` -**Issue:** `schema` is not a TS reserved word but is heavily aliased -across libraries (zod, JSON schema, table schema, GraphQL schema). See #12. - ---- - -### Finding 32 — Low — Cat 14 — non-issue +### Finding 20 — Low — Cat 14 — non-issue **Location:** `src/v2/client.ts:54` **Issue:** `StillRunningError` is named in idiomatic TS style (`*Error` suffix on classes extending Error). --- -### Finding 33 — Low — duplicate of #6 -**Location:** `src/v2/model.ts:89` -Same finding as #6. - ---- - -### Finding 34 — Low — Cat 15 (Generic field) — call-out +### Finding 21 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. --- -### Finding 35 — Low — Cat 3 (Acronym casing in enum string values) +### Finding 22 — Low — Cat 3 (Acronym casing in enum string values) **Location:** `src/v2/model.ts:42-43` ```ts SQL = 'SQL', @@ -492,42 +316,28 @@ caps. Apply the casing rule (#1) and these become `Sql` (if the rule is --- -### Finding 36 — Low — duplicate of #10 -**Location:** `src/v2/model.ts:131` -`fileNames?: string[]` for images — same as #10. - ---- - ## Top Themes -1. **Three-resource ambiguity** — `Cluster`, `Context`, `Command` are easy - to confuse, but the public types use the generic field `id` and reuse - `CreateResponse` for two unrelated operations. Findings #2, #3, #6, - #7, #8, #10, #13, #15, #22-#24 all stem from one decision: **never - say "id" when "commandId" or "contextId" would do, and never reuse a - response shape across resources**. Splitting `CreateResponse` into - `CreateContextResponse` and `ExecuteCommandResponse` cascades to fix - four other findings. - -2. **Enum identifier casing** — SHOUTY_SNAKE_CASE enum identifiers +1. **Enum identifier casing** — SHOUTY_SNAKE_CASE enum identifiers (`COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`) violate the TypeScript convention that reserves `SCREAMING_SNAKE_CASE` for constants. PascalCase identifiers with the wire string preserved as the value restore idiomatic TS while keeping serialisation intact. -3. **Verb inconsistency** — `cancel` (command), `destroy` (context), +2. **Verb inconsistency** — `cancel` (command), `destroy` (context), `commandStatus` (no verb), `contextStatus` (no verb), `execute` (vs `run`), `create`/`delete`/`destroy` mixing. Add `getCommandStatus` / `getContextStatus` and pick one of `destroy`/`delete` to settle this. -4. **Waiter-class names** — `CancelWaiter`, `CreateWaiter`, +3. **Waiter-class names** — `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` are too short to convey what they wait for and are genericised against the resource axis. Renaming with the resource (`CancelCommandWaiter`, `CreateContextWaiter`, `ExecuteCommandWaiter`) removes a recurring source of confusion. ---- - -## Fixed +4. **Type reuse across operations** — `CreateResponse` is reused for both + context creation and command execution. Splitting into + `CreateContextResponse` and `ExecuteCommandResponse` clarifies the + public surface. -_None._ +--- diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 315a5669..54e7511a 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -3,13 +3,13 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 29 +**Total weird names flagged:** 23 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 15 | +| High | 4 | +| Medium | 11 | | Low | 6 | | Observation | 2 | @@ -27,25 +27,19 @@ - **Suggested name:** Pick one convention. If splitting on word boundaries: `SQL_DW`, `SQL_SERVER`, `BIG_QUERY`, `POWER_BI`. If joining: `WORKDAYRAAS`. Most ergonomic is to consolidate on word-split + underscores. - **Rationale:** Internal inconsistency makes the type non-discoverable — a user typing `ConnectionType.SQL_` will autocomplete to nothing if the value is `SQLSERVER`. Probably wire-locked, but worth flagging upstream. -### 3. `DeleteConnectionRequest.nameArg` / `GetConnectionRequest.nameArg` / `UpdateConnectionRequest.nameArg` — `src/v1/model.ts:189,197,232` -- **Why weird:** Field named `nameArg` rather than `name`. The `Arg` suffix is a generator artefact (denoting path-arg / required-arg in the proto), but it leaks into the TS surface — users see `req.nameArg` everywhere. `ConnectionInfo` and `CreateConnectionRequest` already have a `name` field, so the inconsistency is jarring. -- **Category:** 5 (`Arg` is a cryptic abbreviation), 17 (inconsistency: `name` vs `nameArg` for the same thing). -- **Suggested name:** `name` everywhere. (Wire stays `name_arg` if the API truly requires that path param convention.) -- **Rationale:** Three different request types have a `nameArg` field that semantically equals the connection name. Users will mistype `name` and get a runtime error. - -### 4. `ConnectionInfo` — `src/v1/model.ts:89` +### 3. `ConnectionInfo` — `src/v1/model.ts:89` - **Why weird:** `Info` is the central domain entity — every type holds info about something. The Go SDK uses `XxxInfo` widely as a Go-style noun, but in TS the type would simply be `Connection`. `typescript.mdc` lists `Info` as a vague suffix. - **Category:** 1 (vague suffix), 8 (redundant type suffix). - **Suggested name:** `Connection`. - **Rationale:** The domain noun is "connection". Stripping `Info` improves every reference (`connection.connectionType` → `Connection.connectionType`). -### 5. `UpdateConnectionRequest.name` field — `src/v1/model.ts:236` +### 4. `UpdateConnectionRequest.name` field — `src/v1/model.ts:236` - **Why weird:** `UpdateConnectionRequest` has THREE name-like fields: `nameArg` (path param, identifies which), `newName` (new name), AND `name` (also documented as "Name of the connection"). Both `nameArg` and `name` are documented identically and both refer to the existing connection. Easily mis-set; ambiguous which the server uses. - **Category:** 12 (duplicate concept), 6 (misleading — three fields mean "the name"). - **Suggested name:** Remove `name` from `UpdateConnectionRequest` (it duplicates `nameArg`). - **Rationale:** Three fields for one concept is a bug surface. Worth pushing to API design. -### 6. `DeleteConnectionRequest_Response` / `ListConnectionsRequest_Response` — `src/v1/model.ts:193,214` +### 5. `DeleteConnectionRequest_Response` / `ListConnectionsRequest_Response` — `src/v1/model.ts:193,214` - **Why weird:** Proto-architectural-leak naming. The `_Response` infix on an underscore-joined identifier is a verbatim proto nested-message name (`DeleteConnectionRequest.Response`), exported into the public TS surface. `DeleteConnectionRequest_Response` is even empty (`{}`). The TS-idiomatic shape is `DeleteConnectionResponse` / `ListConnectionsResponse` (or `void` for the empty case), not a nested type tied to its sibling request. - **Category:** Proto-architectural leak (`_Response` underscore-joined nested message name), 12 (empty type duplicates `void`). - **Suggested name:** `DeleteConnectionResponse` / `ListConnectionsResponse` (or drop the empty one entirely; method returns `void`). @@ -53,91 +47,61 @@ ## Medium severity -### 7. `ConnectionInfo.connectionType: ConnectionType` — `src/v1/model.ts:93` -- **Why weird:** Type-suffix tautology — field `connectionType` of type `ConnectionType` on a type called `ConnectionInfo`. Reads `connectionInfo.connectionType`. -- **Category:** 20. -- **Suggested name:** `type: ConnectionType`. (If `ConnectionInfo` is renamed to `Connection`, becomes `connection.type`.) -- **Rationale:** Wire stays `connection_type`; TS can drop the prefix. - -### 8. `ConnectionInfo.credentialType: CredentialType` — `src/v1/model.ts:105` -- **Why weird:** Same tautology as #7. -- **Category:** 20. -- **Suggested name:** `credential: CredentialType` or simply keep as-is since `credential` would also be ambiguous. -- **Rationale:** Less clear than #7; the prefix carries some semantic load (distinguishes credential type from credential value). - -### 9. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:118` +### 6. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:118` - **Why weird:** Type-suffix tautology. Also: the value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. - **Category:** 20 (tautology), 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). - **Suggested name:** Either drop the field (it's always `CONNECTION`), or rename to `securableKind: SecurableType` and document why a non-`CONNECTION` value would ever appear. - **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. -### 10. `ConnectionInfo.provisioningInfo: ProvisioningInfo` — `src/v1/model.ts:119` -- **Why weird:** Type-suffix tautology. -- **Category:** 20. -- **Suggested name:** `provisioning: ProvisioningInfo`. -- **Rationale:** Wire stays `provisioning_info`; TS can drop the prefix since the containing type already names the concept. - -### 11. `ConnectionInfo.connectionId` and `metastoreId` — `src/v1/model.ts:107-109` -- **Why weird:** Bare `id` doesn't appear, but two `xxxId` fields coexist. `connectionId` is the type-prefix tautology (same struct already says "Connection"); `metastoreId` clarifies which parent. Mixed levels of specificity. -- **Category:** 19 (underspecified id — `connectionId` is fine, but inconsistent with absence of just `id` somewhere). -- **Suggested name:** `id` for the connection's own identifier (it's `connection.id`, not `connection.connectionId`); keep `metastoreId` (it identifies a parent). -- **Rationale:** Self-id should be `id`; foreign-key ids should keep the prefix. This is the standard REST convention. - -### 12. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:91,101` +### 7. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:91,101` - **Why weird:** Two name-like fields (`name` and `fullName`) with no inline doc explaining the difference. The wire pattern in Unity Catalog is "name within a parent" vs "catalog.schema.connection_name", but the type doesn't say that. - **Category:** 1 (vague — what makes a name "full"?), 17 (inconsistency: `name` is short, `fullName` is fully qualified but doc only says "Full name of connection"). - **Suggested name:** Keep names; improve doc to clarify `fullName` is the dot-qualified path (`catalog.schema.connection_name`). - **Rationale:** Naming is fine; documentation is the gap. Flagging because the readability of every field that pairs with `name` depends on knowing that `fullName` is the path-style form. -### 13. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:97` +### 8. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:97` - **Why weird:** Boolean field name doesn't begin with `is`/`has` as is common for TS booleans. Reads `connection.readOnly` (acceptable adjective form) but sibling enums and types use noun forms. JS naming conventions are split, but inside this SDK most booleans use the adjective form, so this is consistent — flagging at low-medium severity because the rule itself is debatable. - **Category:** 1 (vague form — `readOnly` could be a string of mode flags). - **Suggested name:** Keep as `readOnly` (matches Go SDK and is widely used in JS). Optionally `isReadOnly`. - **Rationale:** No strong convention either way; flagging because audit asked for booleans whose nature isn't obvious from the name. -### 14. `CreateConnectionRequest` / `UpdateConnectionRequest` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:138,230` +### 9. `CreateConnectionRequest` / `UpdateConnectionRequest` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:138,230` - **Why weird:** `CreateConnectionRequest` is `ConnectionInfo` shape. `UpdateConnectionRequest` is `ConnectionInfo + nameArg + newName + name`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnectionRequest` and `UpdateConnectionRequest` even though they're server-only). - **Category:** 12 (duplicate concepts), 6 (misleading — user-settable vs server-set is invisible). - **Suggested name:** Split server-only metadata into a base type and compose. Better still, type create/update inputs as `Pick` or a dedicated `ConnectionInput` interface. - **Rationale:** Today a caller could set `connection.createdAt` on a create request and have no idea it's silently ignored. Type system can prevent this. -### 15. `UpdateConnectionRequest.newName` and `nameArg` — `src/v1/model.ts:232-234` -- **Why weird:** `newName` (TS), wire `new_name`. Pair (`nameArg`, `newName`) means "rename connection X to Y". Function-style verb encoded in a field name (`new` + Name). -- **Category:** 5 (`newName` reads as a temporal modifier), 17 (also inconsistent with the type's own `name` field). -- **Suggested name:** `renameTo`, or split into a `RenameConnectionRequest` operation. -- **Rationale:** Cleaner API: rename and update are distinct operations. - -### 16. `ListConnectionsRequest.maxResults` semantics — `src/v1/model.ts:201-208` +### 10. `ListConnectionsRequest.maxResults` semantics — `src/v1/model.ts:201-208` - **Why weird:** Three different behaviours encoded in the same field: "not set → all results", "0 → server default", ">0 → bound by min(value, server-default)", "<0 → error". Numeric overload that is invisible from the name. - **Category:** 6 (misleading — `maxResults` implies upper bound, but `0` actually requests server default). - **Suggested name:** Either two separate fields (`pageSize` and `useServerDefault`), or document inline tersely. Keep name; flag as observation. - **Rationale:** Name is fine; behaviour overloaded. Easy to call wrong. -### 17. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:75` +### 11. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:75` - **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. - **Category:** 6 (misleading — value advertised but not actually a securable yet). - **Suggested name:** Hide until promotion or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. -### 18. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:52` +### 12. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:52` - **Why weird:** `SSWS` is cryptic. (Stands for "Single Sign-On Web Services" or Okta SSWS — Secure Single Sign-on. Either way, opaque.) Other tokens are named after their family (OAuth, OIDC, Bearer); SSWS is the only one with a literal product-specific acronym. - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling values). - **Suggested name:** `OKTA_SSWS_TOKEN` (if it's strictly Okta), or document in doc-comment. - **Rationale:** Future readers cannot guess what SSWS expands to. -### 19. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:53` +### 13. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:53` - **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while sibling values put the vendor first. Inconsistent word order. - **Category:** 17 (inconsistency). - **Suggested name:** `AKAMAI_EDGEGRID`. - **Rationale:** Consistency with vendor-first patterns elsewhere. -### 20. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,272,278` +### 14. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,272,278` - **Why weird:** Proto-architectural-leak naming. Proto-style nested entry types with underscore-joined identifiers leak into the public TS surface. Each `Options` and `Properties` map gets a corresponding `*_OptionsEntry`/`*_PropertiesEntry` interface — six total — that is exported but trivial (`{key?, value?}`). The wire shape is already covered by `Record`. - **Category:** Proto-architectural leak (`_OptionsEntry` / `_PropertiesEntry` proto map-entry message names), 12 (duplicate concept), 5 (cryptic — underscore-joined identifiers). - **Suggested name:** Remove the `*Entry` interfaces from the public API; rely on `Record`. - **Rationale:** These entry types add visual noise and are not used by the surface (the field is `Record`). -### 21. `ProvisioningInfo_State` — `src/v1/model.ts:79` +### 15. `ProvisioningInfo_State` — `src/v1/model.ts:79` - **Why weird:** Proto-architectural-leak naming. Underscore-joined identifier (`ProvisioningInfo_State`) is a proto nested-enum name (`ProvisioningInfo.State`) emitted verbatim into TS. The enum is suppressed via `eslint-disable @typescript-eslint/naming-convention`, confirming it breaks TS conventions. Standalone TS would name this `ProvisioningState` (or merge into `ProvisioningInfo`). - **Category:** Proto-architectural leak (`_State` underscore-joined nested enum name). - **Suggested name:** `ProvisioningState`. @@ -145,37 +109,37 @@ ## Low severity -### 22. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` +### 16. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. -### 23. `flattenQueryParams` — `src/v1/utils.ts:123` +### 17. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if generator default. - **Rationale:** Generator emits the same helper into every package even when unused. -### 24. `readAll` — `src/v1/utils.ts:40` +### 18. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Trivial; flagged for cross-package consistency. -### 25. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 19. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should encode the layer, not just the protocol. -### 26. `HttpCallOptions` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 27. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:167-168` +### 21. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:167-168` - **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. - **Category:** Observation only. - **Suggested name:** None — this is the marshalling boundary by design. @@ -183,14 +147,14 @@ ## Observations -### 28. Casing inconsistency in vendor name decomposition +### 22. Casing inconsistency in vendor name decomposition Within `ConnectionType`: - `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). - `MYSQL` (joined) vs `GA4_RAW_DATA` (split). No discoverable rule. Wire-locked, but worth surfacing. - **Category:** 3 (acronym/casing inconsistency). -### 29. `Client` constructor throws for missing host +### 23. `Client` constructor throws for missing host `if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. - **Category:** Observation. @@ -211,11 +175,3 @@ No discoverable rule. Wire-locked, but worth surfacing. - `src/v1/client.ts` (240 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (29 lines): read fully. - -## Fixed -- #5 `ConnectionType.MONDAY_COM` (originally cited at `src/v1/model.ts:56`): Fixed in regeneration on 2026-05-20 — vendor value removed from `ConnectionType` enum. -- #6 `EnvironmentSettings` (originally cited at `src/v1/model.ts:278-281`): Fixed in regeneration on 2026-05-20 — type no longer present in `model.ts`. -- #7 `EnvironmentSettings.environmentVersion` (originally cited at `src/v1/model.ts:280`): Fixed in regeneration on 2026-05-20 — removed along with parent type. -- #9 Request DTOs named as verb phrases — `DeleteConnection` / `GetConnection` / `CreateConnection` / `UpdateConnection` / `ListConnections` (originally cited at `src/v1/model.ts:203,270,283,288,320`): Fixed in regeneration on 2026-05-20 — all renamed to `*Request` suffix (`CreateConnectionRequest`, `DeleteConnectionRequest`, `GetConnectionRequest`, `ListConnectionsRequest`, `UpdateConnectionRequest`). -- #21 `parent` field on `CreateConnection` and `ListConnections` (originally cited at `src/v1/model.ts:208,300`): Fixed in regeneration on 2026-05-20 — `parent` field removed from both `CreateConnectionRequest` and `ListConnectionsRequest`. -- #26 `CredentialType.OAUTH_DCR` (originally cited at `src/v1/model.ts:105`): Fixed in regeneration on 2026-05-20 — value removed from `CredentialType` enum. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index a64499d4..29f82b22 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -13,7 +13,7 @@ cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure Managed Identity, GCP Service Account Key, Databricks-managed GCP Service Account, Cloudflare API token) and yields one of six temporary-credential shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). -**Total weird names flagged:** 35 +**Total weird names flagged:** 24 (24 still applicable, 0 newly fixed in regeneration on 2026-05-26) --- @@ -32,30 +32,19 @@ shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). | 9 | `ValidateCredentialRequest` vs `ValidateStorageCredentialRequest` | model.ts:1225, 1283 | interface pair | High | 12 Duplicate concepts | The `credential` discriminator differs (`credentialName` vs `storageCredentialName`; storage variant adds `azureServicePrincipal` and `cloudflareApiToken`). Otherwise overlapping. | | 10 | `Client` | client.ts:106 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `CredentialsClient` would self-identify. | | 11 | `Client.createCredential` vs `Client.createStorageCredential` (plus delete/get/list/update/validate pairs) | client.ts:309, 339, 368, 402, 445, 480, 514, 551, 586, 614, 648, 715, 777, 808, 850, 889 | method set | High | 12 Duplicate concepts | The class exposes parallel `*Credential` and `*StorageCredential` operations (16 methods, 8 pairs). Per the in-tree TODO note (model.ts:766-770) the storage-credentials API is being deprecated, but both are surfaced equally — no `@deprecated` JSDoc, no log warning. | -| 12 | `nameArg` | model.ts:566, 586, 757, 773, 1057, 1142 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | `nameArg` appears in six request types as the path parameter for the credential being acted on. "Arg" is meaningless to a TS caller (it's a generator-introduced disambiguator that exists because some envelopes also have a `name` body field). TS-side it should be `credentialName` or `nameInPath`. | -| 13 | `UpdateCredentialRequest.nameArg` and `UpdateCredentialRequest.name` coexist | model.ts:1057, 1072 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredentialRequest.name`'s text. Caller will pick wrong. | -| 14 | `UpdateStorageCredentialRequest.nameArg` and `UpdateStorageCredentialRequest.name` coexist | model.ts:1142, 1156 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #13 for the storage variant. | -| 15 | `CredentialInfo` discriminator field `credential` | model.ts:470 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `CredentialInfo`; the field that holds the credential payload is also `credential`. `Credential.credential.awsIamRole` reads as a stutter. Should be `cloudCredential` or `provider`. | -| 16 | `TableOperation` vs `VolumeOperation` enums | model.ts:17, 22 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write a cloud-storage thing) expressed two different ways across sibling enums in the same file. | -| 17 | `unityCatalogIamArn` | model.ts:158 | field | Medium | 7 Overly verbose, 6 Misleading names | 18-char field name embedded in `AwsIamRole`. The JSDoc says "AWS IAM user managed by Databricks". Caller has no way to know that "unityCatalog" here means "the Databricks-managed identity that assumes the customer role". Either `databricksManagedIamArn` or rename to clarify role. | -| 18 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:151, 192, 174, 610, 555, 214 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | -| 19 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:170, 168, 642 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | -| 20 | `awsTempCredentials` discriminator case | model.ts:636 | field | Low | 5 Cryptic abbreviations | "Temp" abbreviation for "Temporary". Other discriminator cases use full words (`azureUserDelegationSas`, `gcpOauthToken`). Inconsistent. | -| 21 | `r2TempCredentials` discriminator case | model.ts:643 | field | Low | 5 Cryptic abbreviations | Same as #20. | -| 22 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:602, 603 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | -| 23 | `R2Credentials` type | model.ts:861 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | -| 24 | `CloudflareApiToken.accountId` | model.ts:220 | field | Low | 19 Underspecified IDs | This `accountId` is a *Cloudflare* account ID, not a Databricks account ID. The field name doesn't say. Compare `unityCatalogIamArn` (#17) which is annotated. | -| 25 | `TemporaryAwsCredentials.accessPoint` | model.ts:958 | field | Low | 5 Cryptic abbreviations, 1 Vague/generic | A string containing an S3 Access Point ARN. `accessPointArn` would type itself. | -| 26 | `usedForManagedStorage` flag | model.ts:286 | field | Low | 6 Misleading names | Boolean named in past tense ("usedFor") suggests a historical record. The doc says it is the *current* state. `isManagedStorageRoot` or `isRootForManagedStorage` reads as state. | -| 27 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:619, 690, 723, 654 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | -| 28 | `TemporaryCredentials` | model.ts:961 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | -| 29 | `ValidateCredentialRequest.credential` outer field with `credential.$case === 'credentialName'` | model.ts:1226, 1228 | field | High | 12 Duplicate concepts, 15 Generic field names | The discriminated-union *case* is `credentialName: string`, sitting under a field called `credential`. So `req.credential.credentialName` is the read path — `credential.credential...` stuttering. | -| 30 | `ValidateStorageCredentialRequest.credential.$case === 'storageCredentialName'` | model.ts:1286 | field | High | 12 Duplicate concepts, 15 Generic field names | Same as #29 — `req.credential.storageCredentialName`. The naming repeats the parent type. | -| 31 | `expirationTime` (epoch milliseconds) | model.ts:649 | field | Medium | 6 Misleading names | "Time" is too generic; the value is an epoch-ms integer. Other timestamp-y fields in this file are `createdAt`/`updatedAt` (also epoch-ms). Inconsistent: should be `expiresAt` to match the `*At` pattern. | -| 32 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:264-266 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredentialRequest`/`CredentialInfo`/`UpdateCredentialRequest`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | -| 33 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | -| 34 | `ListCredentialsPublicRequest` | model.ts:776 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | -| 35 | `Client.createCredentialsPublic` / `Client.deleteCredentialsPublic` / `Client.getCredentialsPublic` / `Client.listCredentialsPublic` | client.ts:927, 953, 978, 1003 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `Client` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | +| 12 | `UpdateCredentialRequest.nameArg` and `UpdateCredentialRequest.name` coexist | model.ts:1057, 1072 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredentialRequest.name`'s text. Caller will pick wrong. | +| 13 | `UpdateStorageCredentialRequest.nameArg` and `UpdateStorageCredentialRequest.name` coexist | model.ts:1142, 1156 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #12 for the storage variant. | +| 14 | `TableOperation` vs `VolumeOperation` enums | model.ts:17, 22 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write a cloud-storage thing) expressed two different ways across sibling enums in the same file. | +| 15 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:151, 192, 174, 610, 555, 214 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | +| 16 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:170, 168, 642 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | +| 17 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:602, 603 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | +| 18 | `R2Credentials` type | model.ts:861 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | +| 19 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:619, 690, 723, 654 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | +| 20 | `TemporaryCredentials` | model.ts:961 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | +| 21 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:264-266 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredentialRequest`/`CredentialInfo`/`UpdateCredentialRequest`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | +| 22 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | +| 23 | `ListCredentialsPublicRequest` | model.ts:776 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | +| 24 | `Client.createCredentialsPublic` / `Client.deleteCredentialsPublic` / `Client.getCredentialsPublic` / `Client.listCredentialsPublic` | client.ts:927, 953, 978, 1003 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `Client` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | --- @@ -112,17 +101,14 @@ of each other: There is no behavioral difference. One should be a type alias. -### H4. Three-way name collision (`nameArg` + `name` + `newName`) +### H4. Body-level `name` collides with path-level `nameArg` -Six request types (`DeleteCredentialRequest`, `DeleteStorageCredentialRequest`, -`GetCredentialRequest`, `GetStorageCredentialRequest`, `UpdateCredentialRequest`, -`UpdateStorageCredentialRequest`) expose a field called `nameArg`. The "Arg" -suffix is meaningless on the TS side; it exists only because the generator -needs to disambiguate from a sibling `name` field that lives in the same -envelope on Update operations. TS callers will read `req.nameArg = 'my-credential'` -and have no idea why it isn't just `name`. - -Combined with H5 below, the Update envelopes are particularly broken: +`UpdateCredentialRequest` and `UpdateStorageCredentialRequest` carry both +`nameArg` (path parameter) and `name` (body field), plus a `newName` field. The +JSDoc on `name` says "The credential name. The name must be unique among +storage and service credentials within the metastore." — i.e., the *new* +canonical name. So `nameArg`, `name`, and `newName` all reference the same +conceptual "credential name" with no clear precedence. See #12, #13. ```ts interface UpdateCredentialRequest { @@ -134,18 +120,10 @@ interface UpdateCredentialRequest { ``` Three name-related fields on one envelope, no clear precedence. Recommend: -keep only `name` (path) + `newName` (rename) and drop the body-level `name`. +drop the body-level `name` so only `nameArg` (path, identifying the existing +credential) and `newName` (rename) remain. -### H5. Body-level `name` collides with path-level `nameArg` - -`UpdateCredentialRequest` and `UpdateStorageCredentialRequest` carry both -`nameArg` (path parameter) and `name` (body field). The JSDoc on `name` says -"The credential name. The name must be unique among storage and service -credentials within the metastore." — i.e., the *new* canonical name. But there -is *also* a `newName` field. So `nameArg`, `name`, and `newName` all reference -the same conceptual "credential name" with no clear precedence. See #13, #14. - -### H6. `purpose` field is referenced in JSDoc but does not exist on the type +### H5. `purpose` field is referenced in JSDoc but does not exist on the type The JSDoc on `readOnly` (model.ts:264-266, etc.) and `usedForManagedStorage` (model.ts:282-285) and `force` (model.ts:567-571) says "Only applicable when @@ -160,28 +138,11 @@ anywhere on `CreateCredentialRequest`/`UpdateCredentialRequest`/ the model. In all cases the contract documented in JSDoc cannot be honored by a TS -caller. See #32. - -### H7. Stuttering `ValidateCredentialRequest.credential.credentialName` - -`req.credential` is the discriminated-union outer field. One of its cases is -`{$case: 'credentialName', credentialName: string}` — so accessing the value -is `req.credential.credentialName` and the outer field is also named after -the same word. Same for `ValidateStorageCredentialRequest.credential.storageCredentialName`. +caller. See #21. -```ts -const req: ValidateCredentialRequest = { - credential: {$case: 'credentialName', credentialName: 'my-cred'}, -}; -``` - -Reads twice as "credential.credentialName". The inner discriminator key should -be `name` (giving `req.credential.name`) — concise and unambiguous because the -case is `'credentialName'`. - -### H8. `Public` infix proto-architectural leak (1 type + 4 methods) +### H6. `Public` infix proto-architectural leak (1 type + 4 methods) -Findings #34-#35. The package exposes **1 generated type** and **4 `Client` +Findings #23-#24. The package exposes **1 generated type** and **4 `Client` methods** whose identifiers carry `Public` as a mid-position or trailing word. The infix originates from the internal proto/service definition where `Public` distinguishes externally-routable account-API endpoints from @@ -262,83 +223,40 @@ A type named `R2` is identifiable only to readers who know Cloudflare's product line. The JSDoc gives no expansion. Use `CloudflareR2Credentials` or add a JSDoc anchor. -### M6. `unityCatalogIamArn` field reads misleadingly - -```ts -interface AwsIamRole { - roleArn?: string; // the customer's IAM role - unityCatalogIamArn?: string; // Databricks-managed identity that assumes the customer role - externalId?: string; -} -``` - -"unityCatalogIamArn" suggests *Unity Catalog's IAM ARN*. What it actually is: -the ARN of the Databricks-managed IAM user that performs the role assumption -(per the JSDoc). `databricksAssumeIdentityArn` or `assumerArn` would be -clearer. - -### M7. `expirationTime` field naming - -The field is an epoch-ms integer ("Server time when the credential will -expire"). The repo's convention elsewhere is `createdAt`/`updatedAt` (which -are also epoch-ms). Rename to `expiresAt` for consistency. - --- ## Low severity (nits) -### L1. `TemporaryAwsCredentials.accessPoint` should carry the ARN suffix - -The JSDoc says "The Amazon Resource Name (ARN) of the S3 access point". The -field is `accessPoint: string`. `accessPointArn` self-documents. - -### L2. `CloudflareApiToken.accountId` is ambiguous - -The `accountId` field is the Cloudflare account ID, not a Databricks account -ID. JSDoc says "The ID of the account associated with the API token" — also -ambiguous. Rename `cloudflareAccountId` or annotate. - -### L3. `awsTempCredentials` / `r2TempCredentials` use "Temp" abbreviation - -The peer discriminator cases use full words (`azureUserDelegationSas`, -`gcpOauthToken`). Standardize: either `awsTemporaryCredentials` or -`azureTempUserDelegationSas`. - -### L4. `aadToken` field vs `AzureActiveDirectoryToken` type +### L1. `aadToken` field vs `AzureActiveDirectoryToken` type Short form (`aadToken`) for the field, long form (`AzureActiveDirectoryToken`) for the type. Acronym handling within one chain should match. -### L5. `GcpOauthToken` casing +### L2. `GcpOauthToken` casing RFC 6749 (OAuth 2.0) titles the term as "OAuth". The code uses "Oauth". Minor. -### L6. `usedForManagedStorage` flag past tense - -"Used" reads as historical state. The doc says it is current state ("is this -the root storage credential"). `isManagedStorageRoot` reads as state. - -### L7. `PACKAGE_SEGMENT` is undescriptive +### L3. `PACKAGE_SEGMENT` is undescriptive Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` is self-documenting. -### L8. `HttpCallOptions` +### L4. `HttpCallOptions` Generic name, internal-only. Same pattern as in sibling packages. Fine inside the file; would warrant a better name if it leaked out. -### L9. `req` parameter naming in client methods +### L5. `req` parameter naming in client methods Standard across the SDK. Go-idiomatic, but consistent. -### L10. `Generate*CredentialRequest` method names are 30+ chars +### L6. `Generate*CredentialRequest` method names are 30+ chars `generateTemporaryServiceCredential` is 35 chars. Combined with `await client.generateTemporaryServiceCredential(req)` the call site is 60+ chars before the args. Cannot shorten without breaking the resource hierarchy. -### L11. Acronym casing review +### L7. Acronym casing review - `Aws` (PascalCase first letter) — `AwsCredentials`, `AwsIamRole`, `awsIamRole`. Internally consistent. @@ -346,12 +264,12 @@ before the args. Cannot shorten without breaking the resource hierarchy. - `Gcp` (PascalCase first letter) — `GcpOauthToken`, `gcpServiceAccountKey`. Internally consistent. - `Aad` (mixed) — `aadToken` (field, short), `AzureActiveDirectoryToken` - (type, long). Inconsistent. See #19. + (type, long). Inconsistent. See #16. - `Iam` — consistent with `Aws`/`Gcp` style. -- `R2` — special-cased product name. See M5/#23. +- `R2` — special-cased product name. See M5/#18. - `Sas` (PascalCase first letter) — `AzureUserDelegationSas`, `sasToken`. Consistent. -- `Oauth` — see L5/#22. +- `Oauth` — see L2/#17. The JSDoc *text* in the same file uses ALL-CAPS forms ("AWS", "GCP", "IAM", "AAD") because that is how the cloud providers write them. The Google TS @@ -429,14 +347,14 @@ Class re-exported with `export {Client}`; types and enums re-exported with |------|-------------------------| | **Credential** (new) | The consolidated UC credential record covering both Storage and Service purposes. Reached via `/api/2.1/unity-catalog/credentials`. | | **Storage Credential** (legacy) | The older Storage-only credential record. Reached via `/api/2.1/unity-catalog/storage-credentials`. Per in-tree TODO, being deprecated. | -| **Service Credential** | A `Credential` whose purpose is **SERVICE** — used by Databricks to access cloud APIs on behalf of the user (e.g., for foundation models, external functions). Note: there is no `purpose` field on the TS model — see H6. | +| **Service Credential** | A `Credential` whose purpose is **SERVICE** — used by Databricks to access cloud APIs on behalf of the user (e.g., for foundation models, external functions). Note: there is no `purpose` field on the TS model — see H5. | | **Purpose** | One of `SERVICE` / `STORAGE`. Distinguishes the two flavors of a `Credential`. Referenced in JSDoc but absent from the TS type. | | **Long-lived credential** | The customer-supplied cloud-provider auth material (IAM role, service principal, etc.) stored in the metastore. Six discriminated cases. | | **Temporary credential** | Short-lived tokens vended by Databricks for direct cloud access. Six discriminated cases. | | **External location** | A cloud-storage URL registered in UC and authorized via a Storage Credential. Validated by `validateCredential` / `validateStorageCredential`. | | **Isolation mode** | Workspace-binding policy for the credential securable. One of `Unspecified`, `Open`, `Isolated`. | | **Unbound credential** | A credential not bound to any workspace. Listable via `includeUnbound=true`. | -| **`nameArg`** | URL-path positional argument for the credential's name. Exists because the request envelope also carries body-level `name` and `newName` — see H4, H5. | +| **`nameArg`** | URL-path positional argument for the credential's name. Exists because the request envelope also carries body-level `name` and `newName` — see H4. | | **Access connector ID** (Azure) | The Azure resource ID of the Databricks Access Connector. | | **AAD token** | Azure Active Directory access token (Oauth bearer for Azure cloud services). | | **R2** | Cloudflare's S3-compatible object storage product (named after the SF-Bay-Area meme). | @@ -456,18 +374,3 @@ Class re-exported with `export {Client}`; types and enums re-exported with Every type, field, enum value, and method enumerated above is accounted for. --- - -## Fixed - -- #18 `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` (originally cited at model.ts:9): Fixed in regeneration on 2026-05-20 — enum value removed; `IsolationMode` now contains only `UNSPECIFIED`/`OPEN`/`ISOLATED`. -- #28 `UcEncryptedToken` field/case (`ucEncryptedToken`, `UcEncryptedToken` type) (originally cited at model.ts:461, 775): Fixed in regeneration on 2026-05-20 — the `ucEncryptedToken` discriminator case and `UcEncryptedToken` interface no longer exist in the generated model. -- #34 `AccountsCreateStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:56, 70): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsCreateStorageCredentialRequest` / `AccountsCreateStorageCredentialRequest_Response`. -- #35 `AccountsDeleteStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:75, 88): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsDeleteStorageCredentialRequest` / `AccountsDeleteStorageCredentialRequest_Response`. -- #36 `AccountsGetStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:91, 102): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsGetStorageCredentialRequest` / `AccountsGetStorageCredentialRequest_Response`. -- #37 `AccountsListStorageCredentialsPublicRequest` (+ `_Response`) (originally cited at model.ts:107, 116): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsListStorageCredentialsRequest` / `AccountsListStorageCredentialsRequest_Response`. -- #38 `AccountsUpdateStorageCredentialPublicRequest` (+ `_Response`) (originally cited at model.ts:122, 136): Fixed in regeneration on 2026-05-22 — `Public` infix dropped; symbols are now `AccountsUpdateStorageCredentialRequest` / `AccountsUpdateStorageCredentialRequest_Response`. -- #39 `CreateCredentialsPublicRequest` (originally cited at model.ts:378): Fixed in regeneration on 2026-05-22 — renamed to `CreateCredentialsRequest`. -- #40 `DeleteCredentialsPublicRequest` (originally cited at model.ts:578): Fixed in regeneration on 2026-05-22 — renamed to `DeleteCredentialsRequest`. -- #41 `GetCredentialsPublicRequest` (originally cited at model.ts:760): Fixed in regeneration on 2026-05-22 — renamed to `GetCredentialsRequest`. -- #43 `ListCredentialsPublicResponse` (originally cited at model.ts:780): Fixed in regeneration on 2026-05-22 — renamed to `ListCredentialsResponse`. -- #45 Eight Zod schema constants with `Public` infix (originally cited at model.ts:2020, 2037, 2294, 1346, 1358, 1362, 1374, 1386): Fixed in regeneration on 2026-05-22 — schemas renamed to drop `Public` (e.g. `marshalAccountsCreateStorageCredentialRequestSchema`, `unmarshalAccountsCreateStorageCredentialRequest_ResponseSchema`). diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 23e93da5..b75faf3d 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -3,20 +3,20 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 **Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. -**Total weird names flagged:** 30 +**Total weird names flagged:** 22 (0 fixed, 22 still present after rescan on 2026-05-26 post regen #156) ## Summary | Severity | Count | | --- | --- | -| High | 7 | -| Medium | 12 | +| High | 4 | +| Medium | 7 | | Low | 7 | | Observation | 4 | ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #28). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #21). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. @@ -33,99 +33,51 @@ - **Suggested name:** Field name stays `id`; fix the JSDoc to "The id of the custom LLM whose optimization run to start." (matches `DeleteCustomLlmRequest.id` and `GetCustomLlmRequest.id` docs on lines 69 and 74). - **Rationale:** A naming audit should flag doc-text bugs on identifiers as well as the identifier itself; consumers learn the semantics from JSDoc and a wrong doc is as harmful as a wrong name. -### 4. `id` field on every request and on `CustomLlm` — `src/v1/model.ts:20,44,70,75,80,94` -- **Why weird:** Bare `id` shows up on six places (`Cancel...Request.id`, `CustomLlm.id`, `Delete...Request.id`, `Get...Request.id`, `Start...Request.id`, `Update...Request.id`). Every JSDoc has to redundantly say "The id of the custom llm". A typed `customLlmId` makes the wire/TS surface self-documenting and avoids confusion with future API extensions (the endpoint is at `/api/2.0/custom-llms/{id}` — `id` here is the LLM id, not a generic id). -- **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `customLlmId` (or `llmId` if the `Custom` prefix is dropped). Wire stays `id`. -- **Rationale:** When grepping logs or stack-traces for `customLlmId`, you'll find the right call site. Today you'll grep for `id` and get 50 false positives across the SDK. - -### 5. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` +### 4. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` - **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. - **Category:** Observation / 6 (misleading — field-mask implies updatable). - **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. - **Rationale:** This is the kind of thing a careful TS API designer would notice; a generator running over the proto schema will not. -### 6. `customLlm` is both a field name and a type name (different casings) — `src/v1/model.ts:96` -- **Why weird:** `UpdateCustomLlmRequest.customLlm: CustomLlm | undefined`. The TS naming convention makes the field/type distinction work via casing — but at a call site you'll write `req.customLlm = {...} satisfies CustomLlm`, and `customLlm` (the field) is one character of casing away from `CustomLlm` (the type). Type-suffix tautology under rule 20. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** Rename `customLlm` field → `target` or `update` so the field name is not a casing of the type name. -- **Rationale:** `req.target` reads cleanly; `req.customLlm` is the kind of name that survives code review only because nobody wants to argue with the generator. - -### 7. `CustomLlm.creator: string` — `src/v1/model.ts:58` -- **Why weird:** "Creator of the custom LLM" — but a `creator` could be a username, an email, a UUID, a Databricks principal-id, or a service-principal client-id. The type is `string` so there is no help. Other Databricks SDK packages (catalog, jobs) use `createdBy` or `creator` similarly inconsistently. The name does not say *what kind* of identifier it is. -- **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `createdBy` if it is a user/principal id (matches Unity Catalog convention); add `@format` JSDoc clarifying whether it is an email or a UUID. -- **Rationale:** Public SDK fields whose meaning depends on side-channel knowledge are footguns. - ## Medium severity -### 8. `CustomLlm.creationTime` vs `Dataset.table` field naming style — `src/v1/model.ts:60,65` -- **Why weird:** `creationTime` is named with the type-suffix convention (`*Time`), while peer fields on the same struct use bare nouns (`creator`, `name`, `instructions`). The other generated SDKs sometimes use `createdAt` or `createTime`. Naming `creationTime` is fine, but it is the *only* type-suffix field on `CustomLlm`. -- **Category:** 17 (inconsistency within the same struct). -- **Suggested name:** `createdAt` (Stripe/GitHub convention, https://stripe.com/docs/api/charges/object) or `createTime` (Google AIP-142, https://google.aip.dev/142). Either is more standard than `creationTime`. -- **Rationale:** AIP-142 (Google API design) says: "Fields representing the time at which a resource was created should be of type google.protobuf.Timestamp and called `create_time`." The Go SDK and Java SDK tend to mirror this; TS should too. - -### 9. `instructions: string` vs `guidelines: string[]` — `src/v1/model.ts:50,54` -- **Why weird:** Two near-synonyms with different cardinalities. `instructions` is a single string, `guidelines` is a string array. The semantic difference is not obvious from the names; both feel like "things the model should follow". This is an API-design issue more than a naming issue, but the names amplify the confusion. -- **Category:** 6 (misleading), 12 (duplicate concept). -- **Suggested name:** `systemPrompt` (or `instruction`) for the single-string case; `rules` or `constraints` for the array. The bigger fix is to consolidate at the API level. -- **Rationale:** Reading `instructions` + `guidelines` side-by-side, a consumer cannot guess which goes where without reading the prose docs. - -### 10. `Table.tablePath` — `src/v1/model.ts:85` -- **Why weird:** Type-suffix tautology (`Table.tablePath`). Doc says "Full UC table path in catalog.schema.table_name format" — but the field name does not communicate that it's a *fully qualified* three-part name. Compare with sibling SDK packages where the same concept is called `fullName` or `qualifiedName`. -- **Category:** 20 (type-suffix tautology), 1 (vague — "path" is generic; a filesystem path? a JSON pointer?). -- **Suggested name:** `fullName` (matches `catalog.TableInfo.full_name`) or `qualifiedName`. -- **Rationale:** Unity Catalog already has a canonical term for three-part names (`full_name`); reusing it makes cross-API code less surprising. - -### 11. `Table.requestCol` / `Table.responseCol` — `src/v1/model.ts:87,89` -- **Why weird:** `Col` is a cryptic abbreviation for `Column`. The same package spells out `endpointName` and `agentArtifactPath` and `optimizationState`, so `Col` is inconsistent. Doc strings even use the full word: "Name of the request column". -- **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling fields). -- **Suggested name:** `requestColumn` / `responseColumn`. -- **Rationale:** Three saved characters is not worth the cognitive split between the doc ("column") and the identifier ("col"). - -### 12. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` +### 5. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` - **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. - **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). - **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. - **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. -### 13. `optimizationState: State` type-suffix tautology — `src/v1/model.ts:56` -- **Why weird:** Field `optimizationState` of type `State`. If `State` is renamed to `OptimizationRunState` per #2, the field can be renamed `optimization: OptimizationRunState` or `runState: OptimizationRunState`. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `optimization` (if type renamed) or just `state` with `State` more specific. Best is the pair `optimization: OptimizationRunState`. -- **Rationale:** Reduces the noise once the enum name is specific. - -### 14. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` +### 6. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `creationTime` reads as a `Date` and many callers will accidentally `new Date(customLlm.creationTime)`, which throws because `Temporal.Instant` does not coerce. Worth a comment in JSDoc; not a rename. - **Category:** Observation. - **Suggested name:** Keep `creationTime`; expand JSDoc to mention `Temporal.Instant`. - **Rationale:** Friction is from the type more than the name, but the name does not warn the reader of the unusual type. -### 15. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +### 7. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 16. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair +### 8. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than the `Http` infix. -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` +### 9. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). - **Rationale:** Distinguish internal context bags from user-tunable option structs. -### 18. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` +### 10. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` - **Why weird:** The `State` enum's first member `STATE_UNSPECIFIED` is a proto-architectural leak. Proto3 requires every enum to declare a zero-value sentinel (typically `FOO_UNSPECIFIED`); that requirement does not exist in TypeScript. Exposing it on the public TS surface forces every consumer to handle a member that semantically means "the server forgot to set this field" — a proto wire-format concern, not a domain concern. The screaming-snake-case casing (`STATE_UNSPECIFIED`) also leaks proto's enum-value convention into a TS type system that conventionally uses PascalCase for enum members (https://google.github.io/styleguide/tsguide.html#enums). - **Category:** Proto-architectural leak (enum sentinel + screaming-snake casing). - **Suggested name:** Drop the `STATE_UNSPECIFIED` member entirely; if a "not yet set" value is needed, use `undefined` (the field is already `State | undefined`). If kept, rename to PascalCase `Unspecified` and document that it is a wire-format sentinel. - **Rationale:** Optional TS fields express "unset" via `undefined`; a redundant enum sentinel doubles the representation of "no value" and forces consumers to write `state !== undefined && state !== State.STATE_UNSPECIFIED`. The all-caps casing further signals that the value is a proto artifact rather than a designed TS API member. -### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 11. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -133,43 +85,43 @@ ## Low severity -### 20. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +### 12. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` - **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. - **Category:** Observation / 9 (reversed — correctly singular). - **Suggested name:** No change. - **Rationale:** Note for consistency reviews. -### 21. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 13. `customLlmFieldMask` function name — `src/v1/model.ts:259` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). - **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. -### 22. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 14. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it is an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 23. `readAll` helper — `src/v1/utils.ts:40` +### 15. `readAll` helper — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 24. `Call` import alias — `src/v1/client.ts:4` +### 16. `Call` import alias — `src/v1/client.ts:4` - **Why weird:** `import type {Call}` — `Call` is a one-word generic noun. Used for the inner async function. Could be `RetryableCall`, `HttpCallback`, etc. Not local to this package (it is from `@databricks/sdk-core/api`), but worth flagging. - **Category:** 1 (vague type name). - **Suggested name:** Imported type; rename upstream if appropriate. - **Rationale:** Generic noun in core API surface. -### 25. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` +### 17. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` - **Why weird:** Three-letter local names. `info` for the client-info builder, `host` for the URL host, `body` for the request body. Conventional and short, but `info` is especially vague. - **Category:** 1 (vague). - **Suggested name:** Keep `host` and `body` (universal); rename `info` to `clientInfo`. - **Rationale:** Localized; cosmetic. -### 26. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` +### 18. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` - **Why weird:** `resp` is the response. Four methods declare `let resp: CustomLlm | undefined;` then assign in a closure and `throw` if undefined. The pattern is repetitive *and* uses the same short name. Consider extracting a helper that returns `T | never`. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. @@ -177,19 +129,19 @@ ## Observations -### 27. Action verbs in `Client` are consistent +### 19. Action verbs in `Client` are consistent The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. - **Category:** 17 (reversed — explicit *consistency* note). -### 28. No `list` operation +### 20. No `list` operation The package exposes singleton CRUD plus optimization start/cancel, but no `listCustomLlms`. Unusual for a Databricks resource SDK. Not a naming issue, but worth flagging because the typical resource SDK has `list` and users will look for it. - **Category:** Observation. -### 29. Mixed acronym casing in core types +### 21. Mixed acronym casing in core types The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `ApiError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `Api` (title), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. - **Category:** 3 (acronym casing). -### 30. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` +### 22. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` Comment "// arrays of objects are not yet supported" inside a generated utility. Not a name issue, but the public-export status of this function makes the TODO load-bearing. - **Category:** Observation. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index ded3e4bc..ae0b31b8 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,14 +3,14 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 54 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 33 | -| Low | 9 | +| High | 7 | +| Medium | 12 | +| Low | 7 | | Observation | 3 | ## High severity @@ -57,213 +57,75 @@ - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. - **Rationale:** The current name reads ambiguously; class names should be noun phrases describing *what they are*. The export at index.ts:3 means consumers see it directly. -### 8. `DatabaseInstanceRole_Attributes` vs `DatabaseInstanceRole.attributes` vs `DatabaseInstanceRole.effectiveAttributes` — `src/v1/model.ts:354,360,372` -- **Why weird:** `attributes` is a generic field name; `effectiveAttributes` is a second copy; the type is a nested message that holds 3 Postgres role boolean flags. "Attributes" carries no information about what the attributes describe (Postgres `CREATEDB` / `CREATEROLE` / `BYPASSRLS` permission flags). -- **Category:** 1 (vague — `attributes` is generic), 15 (generic field name). -- **Suggested name:** `pgRoleFlags` / `PgRoleFlags`, or `permissions` / `RolePermissions`. -- **Rationale:** Reader hits `role.attributes.createdb` and has to consult the type to find out it's a Postgres-flag bag. Postgres docs use the phrase "role attributes" so the alignment is intentional — but the SDK is for non-Postgres-experts too. - -### 9. `databaseCatalogs` plural field on `ListDatabaseCatalogsResponse` vs `syncedTables` (not `syncedDatabaseTables`) plural field on `ListSyncedDatabaseTablesResponse` — `src/v1/model.ts:498,542` -- **Why weird:** The list-response field on catalogs is `databaseCatalogs: DatabaseCatalog[]` (matches type name), but on synced tables it's `syncedTables: SyncedDatabaseTable[]` (drops `Database`). On instance-roles it's `databaseInstanceRoles: DatabaseInstanceRole[]` (matches). On instances it's `databaseInstances: DatabaseInstance[]` (matches). The synced-tables one is the odd one out. -- **Category:** 17 (inconsistent), 9 (singular/plural mismatch with the type). -- **Suggested name:** `syncedDatabaseTables: SyncedDatabaseTable[]` (wire stays `synced_tables` if API requires it). -- **Rationale:** Internal consistency — every other list-response uses the type's plural; only this one shortens. Wire payload uses `synced_tables` so the divergence may be a generator decision; flag for cleanup. - ## Medium severity -### 10. `DatabaseInstance.uid` and `DatabaseInstance.name` — both identifiers — `src/v1/model.ts:197,199` -- **Why weird:** Two fields look like identifiers. `uid` is "immutable UUID identifier"; `name` is "unique identifier". Caller reading the struct can't tell at a glance which one to pass to `getDatabaseInstance` (answer: `name`, per client.ts:484). Bare `uid` is also non-descriptive — Lakebase uses both PG-side OIDs and Databricks-side UUIDs. -- **Category:** 19 (underspecified id when multiple ids exist), 1 (vague `uid`). -- **Suggested name:** `instanceUid` / `instanceName`, or `id` / `name` (collapse `uid` to `id`). -- **Rationale:** Same field-disambiguation pattern as `PolicyInfo.id` in the abacpolicies audit. `uid` reads as a hash, not a Databricks UUID — and the JSDoc just says "UUID identifier". - -### 11. `DatabaseInstance.creator` typed as `string` — `src/v1/model.ts:201` -- **Why weird:** Field doc says "The email of the creator of the instance". Field name says `creator`. So is the value an email, a username, or an account id? Postgres SDK uses `createdBy` for the same concept (postgres/v1/model.ts). -- **Category:** 1 (vague — `creator` could be a name, an id, or an email), 6 (misleading — doc says email, name says creator). -- **Suggested name:** `creatorEmail` (or `createdBy` if the value can be a service-principal id too). -- **Rationale:** The doc explicitly narrows the type; the field name should match. - -### 12. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` +### 8. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` - **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. - **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). - **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". - **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. -### 13. `DatabaseInstance.pgVersion` casing — `src/v1/model.ts:209` -- **Why weird:** `pg` is two letters lowercase; the next word starts capitalised. Acronym `PG` is widely written uppercase. -- **Category:** 3 (acronym casing — `pg` should arguably be `Pg` per camelCase, `PG` per acronym preservation). -- **Suggested name:** `postgresVersion` (spell out), or `pgVersion` (current). -- **Rationale:** Current `pgVersion` is OK but `postgresVersion` would be clearer. - -### 14. `DatabaseInstance.readWriteDns` / `readOnlyDns` — `src/v1/model.ts:203,250` -- **Why weird:** `Dns` is a single word; `DNS` is the acronym. Field doc says "The DNS endpoint to connect to the instance"; the value is a hostname, not a DNS server. Misleading abbreviation. -- **Category:** 3 (acronym casing), 6 (misleading — `dns` suggests a DNS server, not an endpoint). -- **Suggested name:** `readWriteEndpoint` / `readOnlyEndpoint`, or `readWriteHost` / `readOnlyHost`. -- **Rationale:** A "DNS endpoint" is a non-standard phrase; the field is just a hostname. - -### 15. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` +### 9. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` - **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? - **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). - **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. - **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. -### 16. `DatabaseInstance.nodeCount` is described as primary+secondaries — `src/v1/model.ts:230` -- **Why weird:** Field name says "node count"; doc says "1 primary and 0 or more secondaries". `nodeCount = 3` means 1 primary + 2 secondaries — but also could be read as "3 nodes, role unspecified". Postgres standby/replica terminology would be clearer. -- **Category:** 1 (vague), 6 (misleading without docs). -- **Suggested name:** `replicaCount`, or pair `primaryCount` + `secondaryCount`, or `totalNodeCount` (and document). -- **Rationale:** Confusing arithmetic — `1` means primary-only, `2` means 1 primary + 1 secondary, etc. - -### 17. `DatabaseInstance.enableReadableSecondaries` boolean toggle naming — `src/v1/model.ts:239` -- **Why weird:** `enableXyz: boolean` is a request-shaped name on a response-shaped type. `enableReadableSecondaries: true` reads as imperative ("please enable"), but it's also returned from server. The companion `effectiveEnableReadableSecondaries` reads as "the effective please-enable-readable-secondaries". The doc on `effectiveEnableReadableSecondaries` even rewords it: "Whether secondaries serving read-only traffic are enabled" — i.e. the read shape should just be `readableSecondariesEnabled` or `hasReadableSecondaries`. -- **Category:** 6 (misleading verb form for a response), 17 (input/output asymmetry). -- **Suggested name:** Input: `enableReadableSecondaries: boolean`. Output: `readableSecondariesEnabled: boolean` (or just merge: response carries the same `enableReadableSecondaries` and don't bother with the `effective_` twin). -- **Rationale:** Generator artefact, but worth flagging. - -### 18. `DatabaseInstance.parentInstanceRef` / `childInstanceRefs` — `src/v1/model.ts:270,275` -- **Why weird:** `Ref` is a cryptic abbreviation (cf. `typescript.mdc` "spell out short identifiers"). Same as `DatabaseInstanceRef` itself. Could be `Reference` or just `DatabaseInstancePointer`. The semantic ("a reference to an instance") doesn't need the abbreviation. -- **Category:** 5 (cryptic abbreviation), 8 (redundant `Ref` suffix — these are already references). -- **Suggested name:** `parentInstance: DatabaseInstanceReference` / `childInstances: DatabaseInstanceReference[]`. -- **Rationale:** Mild — `Ref` is widely understood — but spelling out matches the project rule. - -### 19. `DatabaseInstanceRef.lsn` field — `src/v1/model.ts:323` -- **Why weird:** `lsn` is a Postgres-internal acronym (Log Sequence Number) shown without expansion. JSDoc says "User-specified WAL LSN" — still abbreviated. -- **Category:** 5 (cryptic abbreviation), 14 (Postgres-internal term in public TS API). -- **Suggested name:** `walLsn` (mild improvement), or `walLogSequenceNumber` (verbose but unambiguous). -- **Rationale:** Lakebase exposes this to schedule branch creation; consumers may not know `lsn` without consulting Postgres docs. - -### 20. `DatabaseInstanceRef.branchTime` field — `src/v1/model.ts:342` -- **Why weird:** `branchTime` is a noun-phrase that reads as "the time of a branch" but is documented as "the point in time on the parent instance from which the instance was created" — i.e. the PITR cutover instant. `branchTime` and `lsn` are alternatives for the same operation (PITR cutover specifier). -- **Category:** 1 (vague), 6 (misleading — `branchTime` suggests an event time, actually a cutover specifier). -- **Suggested name:** `branchPointTime` / `branchAt` / `pitrTimestamp`. -- **Rationale:** Reads naturally as "when was this branch made" but actually means "what point in the source's history to branch from". - -### 21. `DatabaseCatalog.uid` field with no doc — `src/v1/model.ts:185` -- **Why weird:** Bare `uid?: string` with no comment, alongside `name`, `databaseInstanceName`, `databaseName`. Four identifier-like fields and one (`uid`) is undocumented and unprefixed. -- **Category:** 19 (underspecified id), 1 (vague). -- **Suggested name:** `catalogUid` (and add a doc comment). -- **Rationale:** Reader cannot guess what scope the uid is for. - -### 22. `DatabaseCatalog.createDatabaseIfNotExists` field — `src/v1/model.ts:186` -- **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF NOT EXISTS`). Reads as a literal SQL DDL fragment in the type. Could be `ensureDatabase` / `autoCreateDatabase`. -- **Category:** 14 (SQL-style name), 7 (verbose). -- **Suggested name:** `ensureDatabaseExists` / `autoCreateDatabase`. -- **Rationale:** Internal consistency with TS naming conventions. - -### 23. `DatabaseCatalog.databaseInstanceName` / `databaseName` — `src/v1/model.ts:182-184` -- **Why weird:** The `database` prefix on every field is redundant once you're already inside `DatabaseCatalog`. `databaseInstanceName` reads as "name of the database instance"; `databaseName` reads as "name of the database". Postgres SDK has `Catalog` (no `database` prefix) — cleaner. -- **Category:** 7 (verbose prefix), 12 (duplicate concept across packages). -- **Suggested name:** `instanceName`, `name` on the catalog directly; or hoist to a sub-struct `database: {instanceName, name}`. -- **Rationale:** The struct is already a `DatabaseCatalog`; re-prefixing every field is noise. - -### 24. `DatabaseTable.name: string` "Full three-part (catalog, schema, table) name" — `src/v1/model.ts:380` -- **Why weird:** Bare `name` carries a complex format (`catalog.schema.table`). Postgres SDK calls the same concept `fullName` / `name` more explicitly. There is no validation in the type — the convention is doc-only. -- **Category:** 1 (vague), 6 (misleading — name looks like a single identifier, actually 3-part). -- **Suggested name:** `fullName` (matches Postgres SDK convention). -- **Rationale:** Same field name `name` appears on `DatabaseCatalog`, `DatabaseInstance`, `DatabaseInstanceRef`, `DatabaseInstanceRole`, `DatabaseTable`, `SyncedDatabaseTable` — each carries different semantics (DNS-safe vs UC-3-part vs role-name). - -### 25. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` +### 10. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` - **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". - **Category:** 12 (duplicate concept), 1 (generic `Database`). - **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. - **Rationale:** Reader has to read both JSDocs to understand the partitioning. -### 26. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` +### 11. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` - **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`) split words at capital boundaries. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Trivia, but `time series` is two words in English. -### 27. `SyncedTableSpec.sourceTableFullName` vs `DatabaseTable.name` (also a full name) — `src/v1/model.ts:727,380` -- **Why weird:** Same domain concept (UC 3-part name) named two different ways in the same package: `sourceTableFullName` here, bare `name` on `DatabaseTable`/`SyncedDatabaseTable`/`DatabaseCatalog`. -- **Category:** 17 (inconsistent naming for the same concept). -- **Suggested name:** Standardise on `fullName` (or `tableFullName`) across the package. -- **Rationale:** Pair with #24. - -### 28. `SyncedTableSpec.createDatabaseObjectsIfMissing` — `src/v1/model.ts:744` -- **Why weird:** Similar SQL-DDL leak as #22. Boolean named after a clause. Also doc at SyncedDatabaseTable.logicalDatabaseName references "the `create_database_objects_is_missing` field in `spec`" — that's a typo (`is_missing` vs `if_missing`) showing the field name fluctuates even in docs. -- **Category:** 14 (SQL-style name), 6 (typo in cross-reference). -- **Suggested name:** `ensureDatabaseAndSchema`. -- **Rationale:** Internal consistency. - -### 29. `SyncedTableStatus.detailedState: SyncedTableState` — `src/v1/model.ts:759` -- **Why weird:** Field is `detailedState`; sibling field is `detailedStatus`. Both have `detailed` prefix; redundant against the wrapping type `SyncedTableStatus`. Easy to confuse `detailedState` (enum) with `detailedStatus` (oneof). -- **Category:** 17 (two `detailed*` neighbours), 7 (verbose). -- **Suggested name:** `state: SyncedTableState`, `status: SyncedTableStatusDetail` (or hoist the oneof). -- **Rationale:** Reader hits `tableStatus.detailedState` and `tableStatus.detailedStatus` and has to read both to decide which is which. - -### 30. `SyncedTableStatus.detailedStatus` and its `*Status` sub-variants form a "status.status.status" chain — `src/v1/model.ts:763` -- **Why weird:** `detailedStatus` on a `SyncedTableStatus` type is doubly redundant. Holds one of four phase-shaped sub-statuses (`provisioningStatus`, `continuousUpdateStatus`, `triggeredUpdateStatus`, `failedStatus`). Each variant is named `*Status` again — `tableStatus.detailedStatus.continuousUpdateStatus.lastProcessedCommitVersion` is "status.status.status.version". -- **Category:** 7 (overly verbose chains). -- **Suggested name:** Rename `detailedStatus` to `phase`, and strip the redundant `*Status` suffix off each sub-variant (`provisioning`, `continuousUpdate`, `triggeredUpdate`, `failed`). -- **Rationale:** Reduces three `status` words to one without touching the wrapper itself. - -### 31. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` +### 12. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 32. `SyncedTablePipelineProgress.latestVersionCurrentlyProcessing` — `src/v1/model.ts:678` -- **Why weird:** Run-on field name — "latest version currently processing" is 4 words. Doc clarifies "may not have completely processed this version yet". Could be `inProgressDeltaVersion` or `currentDeltaVersion`. -- **Category:** 7 (overly verbose), 1 (verbose adverb). -- **Suggested name:** `processingDeltaVersion`. -- **Rationale:** Verbose field names hurt readability. - -### 33. `SyncedTablePipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` / `estimatedCompletionTimeSeconds` — `src/v1/model.ts:680-686` -- **Why weird:** Mixed metric naming: `syncedRowCount` and `totalRowCount` use suffix `Count`; `syncProgressCompletion` uses suffix `Completion` (a number 0-1); `estimatedCompletionTimeSeconds` uses suffix `TimeSeconds` (unit-embedded). Three different conventions for "a number". -- **Category:** 17 (inconsistent suffixes), 15 (generic field names). -- **Suggested name:** `syncedRows`, `totalRows`, `progressFraction`, `etaSeconds`. -- **Rationale:** The number-suffix conventions don't align with each other; pick one. - -### 34. `SyncedTablePipelineProgress.syncProgressCompletion: number` doc says "a number between 0 and 1" — `src/v1/model.ts:683-684` -- **Why weird:** Type is `number`; doc constrains to `[0, 1]`. Type system doesn't help. Field name `syncProgressCompletion` is also redundant — completion is what progress measures. -- **Category:** 16 (type contradicts doc constraint), 7 (verbose). -- **Suggested name:** `progressFraction` (or `progressRatio`), `number` in [0,1]. -- **Rationale:** Same as #33 plus a separate concern about the value range. - -### 35. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` +### 13. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` - **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. - **Category:** 20 (type-suffix tautology in field names), 7 (verbose). - **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. - **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. -### 36. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` +### 14. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 37. `GenerateDatabaseCredentialRequest.requestId` — `src/v1/model.ts:453` -- **Why weird:** Bare `requestId` with no doc. Other request types do not have `requestId`. Looks like an idempotency key but the type doesn't say. -- **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `idempotencyKey` (and add docs). -- **Rationale:** Without docs, callers can't tell whether to set it. - -### 38. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` +### 15. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 39. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:411-415` +### 16. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:411-415` - **Why weird:** "Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. Setting a value of false will throw a bad request." Field is exposed in the public TS type but has no `@deprecated` JSDoc tag. - **Category:** 6 (misleading: deprecated field undocumented as deprecated). - **Suggested name:** Add `@deprecated` tag; consider removing in next major. - **Rationale:** TS tooling honours `@deprecated`; the current setup just has prose. -### 40. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` -- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #41 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. +### 17. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` +- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #18 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. - **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). - **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`; field `inlinePipeline` (paired with `existingPipelineId`). Drop the `New` adjective and the `Spec` suffix. - **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. -### 41. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` -- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #42); `DeltaTableSyncInfo` is a sync checkpoint (see #35); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #40). Each of the four would read more clearly with a domain-specific suffix. +### 18. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` +- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #19); `DeltaTableSyncInfo` is a sync checkpoint (see #13); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #17). Each of the four would read more clearly with a domain-specific suffix. - **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). -- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #40); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #35); `ProvisioningInfo` → drop (per #42). Goal: no two types in the package share a generic suffix. +- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #17); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #13); `ProvisioningInfo` → drop (per #19). Goal: no two types in the package share a generic suffix. - **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. -### 42. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` +### 19. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` - **Why weird:** Type declaration is literally `export interface ProvisioningInfo {}` with a comment "Copied over from managed-catalog/api/messages/common.proto to decouple SDK packages. xref go/unified-api-packages-dd". An empty interface — the type itself carries zero domain meaning. Only its nested `ProvisioningInfo_State` enum is used (referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`); the empty parent is a vestigial proto namespace. The exported type name and its nested enum bleed Managed Catalog internals into the Lakebase SDK. - **Category:** proto-architectural leak (proto message preserved as empty TS interface for namespacing), 6 (misleading — exists but has no fields), 12 (cross-package proto leak). - **Suggested name:** Drop the empty `ProvisioningInfo` interface; rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). The empty interface is a generator artefact that should not surface. @@ -271,55 +133,43 @@ ## Low severity -### 43. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:505` +### 20. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:505` - **Why weird:** Doc says "Pagination token to go to the next page of Database Instances" — but this is roles, not instances. Doc-copy bug. - **Category:** 6 (misleading doc). - **Suggested name:** Fix the doc to say "roles". - **Rationale:** Naming-adjacent bug worth flagging. -### 44. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:491` +### 21. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:491` - **Why weird:** Same bug: catalogs request says "synced database tables" in doc. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "catalogs". -- **Rationale:** Same as #43. +- **Rationale:** Same as #20. -### 45. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:514` +### 22. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:514` - **Why weird:** Doc says "next page of instances" for the roles response. - **Category:** 6 (misleading doc). - **Suggested name:** Fix to "roles". -- **Rationale:** Same as #43. +- **Rationale:** Same as #20. -### 46. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` +### 23. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` - **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:181-184). - **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). - **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. - **Rationale:** Caller has to know the wire-encoding accident to decide which to set. -### 47. `DeleteDatabaseInstanceRoleRequest.reassignOwnedTo` field — `src/v1/model.ts:421` -- **Why weird:** Postgres-isms (`REASSIGN OWNED BY ... TO ...`) collapsed into a single field. Field name reads as a verb phrase ("reassign owned [things] to"). -- **Category:** 14 (SQL-style name). -- **Suggested name:** `reassignOwnedObjectsTo` or `newOwner`. -- **Rationale:** Mild — Postgres admins will get it. - -### 48. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` +### 24. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` - **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. - **Category:** 14 (Google-AIP naming convention leak). - **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. - **Rationale:** Internal-jargon leak; flag for awareness. -### 49. `DeleteSyncedDatabaseTableRequest.purgeData` — `src/v1/model.ts:433` -- **Why weird:** Boolean named after a side effect (`purge_data`). Doc says "the actual PostgreSQL table will be dropped from the database". Combination of `delete` + `purge` is also confusing — what does the no-purge case do? (Drop UC registration only.) -- **Category:** 1 (vague), 6 (misleading). -- **Suggested name:** `dropUnderlyingTable` / `cascade`. -- **Rationale:** Minor — affects discoverability. - -### 50. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` +### 25. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` - **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency. -### 51. `StillRunningError` private error class — `src/v1/client.ts:83` +### 26. `StillRunningError` private error class — `src/v1/client.ts:83` - **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. - **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). - **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). @@ -327,16 +177,16 @@ ## Observations -### 52. `client.ts` has a 5-line block-comment at line 633-638 explaining that the role APIs will never reach Public Preview +### 27. `client.ts` has a 5-line block-comment at line 633-638 explaining that the role APIs will never reach Public Preview The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. - **Category:** 6 (misleading: client exposes APIs that won't stabilise). - **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. -### 53. `findDatabaseInstanceByUid` is the only `findBy*` method +### 28. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 54. Action-verb conventions in `Client` are consistent +### 29. Action-verb conventions in `Client` are consistent `create*` / `delete*` / `get*` / `list*` / `update*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. ## Domain glossary @@ -359,10 +209,3 @@ Every other lookup is `getX(req)`. This method exists because the API has a dist - `src/v1/client.ts` (995 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. - `src/v1/index.ts` (67 lines): read fully. - -## Fixed -- #8 `UpgradeInstanceToAutoscalingRequest` / `upgradeInstanceToAutoscaling` (originally cited at `src/v1/model.ts:976`, `client.ts:998`): Fixed in regeneration on 2026-05-20 — the request type and client method were removed from the generated surface. -- #25 `DatabaseCatalog.databaseProjectId` / `databaseBranchId` / `databaseName` (originally cited at `src/v1/model.ts:219-223`): Fixed in regeneration on 2026-05-20 — `databaseProjectId` and `databaseBranchId` were removed; the remaining `databaseName` / `databaseInstanceName` prefix concern is captured in active finding #23. -- #27 `DatabaseTable.tableServingUrl` (originally cited at `src/v1/model.ts:437`): Fixed in regeneration on 2026-05-20 — the field was removed from `DatabaseTable`. -- #32 `SyncedTableSpec.acceleratedSync` (originally cited at `src/v1/model.ts:830`): Fixed in regeneration on 2026-05-20 — the field was removed from `SyncedTableSpec`. -- #51 `FailoverDatabaseInstanceRequest.failoverTargetDatabaseInstanceName` (originally cited at `src/v1/model.ts:490`): Fixed in regeneration on 2026-05-20 — the entire `FailoverDatabaseInstanceRequest` type and its client method were removed from the generated surface. diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md index 6fa54b0d..791924be 100644 --- a/.agent/naming-audit/dataclassification.md +++ b/.agent/naming-audit/dataclassification.md @@ -3,57 +3,35 @@ **Path:** `packages/dataclassification/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 17 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | -| High | 4 | +| High | 0 | | Medium | 3 | | Low | 6 | | Observation | 4 | ## High severity -### 1. `autoTagConfigs` field vs. `AutoTaggingConfig` type — `src/v1/model.ts:52` -- **Why weird:** Field name uses abbreviated `autoTag` while the type it points to is the full `AutoTaggingConfig`. Within a few lines the SDK uses both `tag`-noun and `tagging`-gerund for the same concept. -- **Category:** 5 (cryptic abbreviation — `Tag` for `Tagging`), 17 (inconsistency with sibling type — `autoTagConfigs: AutoTaggingConfig[]`). -- **Suggested name:** `autoTaggingConfigs: AutoTaggingConfig[]`. Wire stays `auto_tag_configs` if upstream insists. -- **Rationale:** A field of `Foo[]` should plural-ise the type name: `foos: Foo[]`. Mixing `autoTag` and `AutoTagging` makes the relationship unobvious and forces a mental translation on every read. - -### 2. `name` field on `CatalogConfig` / `DeleteCatalogConfigRequest` / `GetCatalogConfigRequest` — `src/v1/model.ts:37,78,84` -- **Why weird:** Field literally called `name` carries a structured resource path (`catalogs/{catalog_name}/config`), not a free-form name. `name` is the most generic possible identifier and gives no hint that it must follow a specific format. -- **Category:** 1 (vague — `name` is the canonical too-generic field name), 6 (misleading — looks like a display name, is actually a structured resource path), 15 (generic field name losing meaning), 19 (underspecified ID). -- **Suggested name:** `resourceName` or `configResourceName`. If staying with `name`, the JSDoc should at least be on the type rather than only on each field. -- **Rationale:** A user importing `CatalogConfig` and seeing `name?: string` will almost certainly try to put `"my-catalog"` in there, not `"catalogs/my-catalog/config"`. The wire constraint is invisible from the type. - -### 3. `parent` field on `CreateCatalogConfigRequest` — `src/v1/model.ts:67` -- **Why weird:** Field called `parent` carries the structured value `catalogs/{catalog_name}`. The relationship "catalog is the parent of catalog-config" is a proto/AIP-160 convention that does not survive into a TS SDK where users do not see the resource hierarchy. -- **Category:** 1 (vague — `parent` of what?), 15 (generic field name losing meaning), 19 (underspecified ID). -- **Suggested name:** `catalogResourceName` or `parentCatalog`. -- **Rationale:** `parent: string` is a Google-AIP idiom; outside that context a caller has no idea what shape to put in. A user-friendly TS SDK would either accept `{catalogName: 'my-catalog'}` directly or rename to make the constraint visible. - -### 4. `classificationTag` field — `src/v1/model.ts:25` -- **Why weird:** The field is literally called `classificationTag` but its doc says it holds a "system tag (e.g., `class.name`...)" — i.e., a tag *key*, not a whole `{key, value}` tag. The name promises a tag object; the type and doc deliver a key string. -- **Category:** 1 (vague — `classificationTag` reads as a tag object, but is a string), 6 (misleading — name suggests "the tag" but it is one half of one). -- **Suggested name:** `classificationTagKey` (or just `tagKey`). -- **Rationale:** Standard idiom across Unity Catalog packages for the key half of a tag pair is `tagKey`. A field called `classificationTag: string` invites a caller to pass a serialized tag object rather than just the key. +_None._ ## Medium severity -### 5. `Client` class — `src/v1/client.ts:38` +### 1. `Client` class — `src/v1/client.ts:38` - **Why weird:** A class literally named `Client` at the top level of the package's API surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). - **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. -### 6. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 2. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. -### 7. `flattenQueryParams` — `src/v1/utils.ts:123` +### 3. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. @@ -61,37 +39,37 @@ ## Low severity -### 8. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` +### 4. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 9. `userAgent` field — `src/v1/client.ts:45` +### 5. `userAgent` field — `src/v1/client.ts:45` - **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. - **Category:** N/A (verification, no issue). - **Suggested name:** unchanged. - **Rationale:** Listed only to confirm canonical naming is preserved. -### 10. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` +### 6. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 11. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` +### 7. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` - **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. - **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. -### 12. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` +### 8. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 13. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` +### 9. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` - **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. @@ -99,24 +77,24 @@ ## Observations -### 14. Wire/TS divergence is heavy +### 10. Wire/TS divergence is heavy The model file is 206 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. -### 15. Action-verb conventions in `Client` +### 11. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) -### 16. Acronym casing +### 12. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 17. `dataclassification` lowercase package name +### 13. `dataclassification` lowercase package name The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). ## Domain glossary - `uc` / Unity Catalog — implicit across all types (the configured resource is a UC catalog). - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `auto-tagging` / `auto-tag` — automatic application of governance tags to columns classified by the scanner (used both as gerund `AutoTagging` in types and as noun `AutoTag` in field names — see #1). +- `auto-tagging` / `auto-tag` — automatic application of governance tags to columns classified by the scanner (used both as gerund `AutoTagging` in types and as noun `AutoTag` in field names). - `system tag` / `governance tag` — terminology in JSDoc for `classificationTag` (built-in vs. custom class tag keys). - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. @@ -125,7 +103,3 @@ The package directory is `dataclassification` (one word, no separator), but ever - `src/v1/client.ts` (181 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (16 lines): read fully. - -## Fixed -- #2 `effectiveAutoTagConfigs` (originally cited at `src/v1/model.ts:62`): Fixed in regeneration on 2026-05-20 — field removed from `CatalogConfig`; only `autoTagConfigs` remains. -- #5 `classificationTag` / `classificationTagValue` asymmetric pair (originally cited at `src/v1/model.ts:25,32`): Fixed in regeneration on 2026-05-20 — `classificationTagValue` field removed; the remaining vagueness on `classificationTag` (key-named-as-whole-tag) is now tracked as finding #4. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 9b389503..467f7466 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -3,13 +3,13 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, and notification routing on failure. -**Total weird names flagged:** 41 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 17 | +| High | 8 | +| Medium | 7 | | Low | 8 | | Observation | 5 | @@ -57,25 +57,7 @@ - **Suggested name:** `DataQualityClient`. - **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but worth flagging. -### 8. `DataProfilingConfig.analysisConfig` discriminated-union — `src/v1/model.ts:165-181` -- **Why weird:** A field called `analysisConfig` is a three-arm union of `InferenceLogConfig` / `TimeSeriesConfig` / `SnapshotConfig`. The outer name (`analysisConfig`) and one arm's type (`SnapshotConfig`) end in the same suffix; the discriminator `$case` values are `inferenceLog` / `timeSeries` / `snapshot` — three different naming bases for three different concepts (`InferenceLog`, `TimeSeries`, `Snapshot`). The arm payloads are also `inferenceLog: InferenceLogConfig` (camelCase) — collision-prone with the discriminator string. -- **Category:** 1 (vague — "analysis" vs "config" is the wrong abstraction), 12 (duplicate concept — `Config` appears twice), 17 (inconsistent verb tense — `InferenceLog` is a noun, `TimeSeries` is a noun, but the type name reads `Inference` + `Log` + `Config`). -- **Suggested name:** Field: `analysis`. Type: keep `InferenceLogConfig` etc., or rename to `InferenceLogAnalysis`/`TimeSeriesAnalysis`/`SnapshotAnalysis` and call the field `analysis`. The TS-level discriminator should follow the type name: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. -- **Rationale:** The current pattern forces callers to write `{analysisConfig: {$case: 'inferenceLog', inferenceLog: {...}}}` — three names for one nesting level. Discriminated unions read better when the discriminator value matches the arm payload's key precisely. - -### 9. `DataProfilingConfig.skipBuiltinDashboard` — `src/v1/model.ts:204` -- **Why weird:** Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. Positive form is clearer: `builtinDashboard: false` or `enableBuiltinDashboard: false`. Also: the verb `skip` (sound only on a transient action) does not capture that this is a persistent configuration. -- **Category:** 6 (misleading — looks like a transient flag, is configuration), 13 (verb-tense — `skip` is action, but the field is state). -- **Suggested name:** `disableBuiltinDashboard` (matches the existing negative semantics with a clearer verb), or invert to `createBuiltinDashboard: boolean` (default true). -- **Rationale:** Boolean fields should be named in their positive form unless the negative form is the natural English phrasing. The "skip" prefix is a tell from migrating Go SDK semantics directly. - -### 10. `DataProfilingConfig.assetsDir` — `src/v1/model.ts:163` -- **Why weird:** `assets` is generic and undefined in this context (which assets? the monitor's? the dashboard's? the metric tables'?). `Dir` is an abbreviation. The JSDoc says "absolute path to a custom directory to store data-monitoring assets" — the type should advertise that. -- **Category:** 1 (vague — `assets` of what?), 5 (cryptic abbreviation — `Dir` for `Directory`). -- **Suggested name:** `assetsDirectory`, or better, `dataMonitoringAssetsPath`. -- **Rationale:** Fields holding an absolute path should call out either "path" or "directory" without abbreviation. `assets` alone is too generic for a top-level field on a config that already has `monitoredTableName`, `profileMetricsTableName`, `driftMetricsTableName`, etc. - -### 11. `Refresh.startTimeMs` / `Refresh.endTimeMs` — `src/v1/model.ts:442,444` +### 8. `Refresh.startTimeMs` / `Refresh.endTimeMs` — `src/v1/model.ts:442,444` - **Why weird:** `Ms` suffix to indicate "milliseconds since epoch", but it ignores the local convention of `Date` and `bigint` for UTC timestamps in modern TS. The field is `number` — JavaScript numbers lose precision beyond 2^53, but milliseconds-since-epoch fits, so the type itself is fine. The `Ms` suffix tells the reader to do arithmetic with `new Date(x)`; meanwhile `creation_time` / `last_updated` elsewhere in the SDK uses `bigint` with explicit precision. Inconsistent unit handling across the SDK. - **Category:** 5 (cryptic abbreviation — `Ms`), 14 (Go-style suffix — Go SDK uses `int64` with `Ms` everywhere; TS would use `Date`). - **Suggested name:** Leave on the wire as `start_time_ms` but on the TS side use `startedAt: Date` / `endedAt: Date` (transformed in unmarshal). @@ -83,153 +65,93 @@ ## Medium severity -### 12. `CancelRefreshResponse.refresh` JSDoc says "The refresh to cancel" — `src/v1/model.ts:125` +### 9. `CancelRefreshResponse.refresh` JSDoc says "The refresh to cancel" — `src/v1/model.ts:125` - **Why weird:** JSDoc on `CancelRefreshResponse.refresh` says "The refresh to cancel" but this is the response (the refresh that *was* cancelled). The doc verb tense contradicts the type name. Listed as naming because the field's contextual meaning is shaped by stale request-side docs. - **Category:** 13 (verb tense — "to cancel" is forward-looking; "cancelled" / "the cancelled refresh" is past-tense). - **Suggested name:** Field stays `refresh`; doc should read "The cancelled refresh." - **Rationale:** Documentation accuracy. The current text implies user intent rather than response state. -### 13. `DeleteRefreshRequest` doc-block typo "Request to delete a ronitor." — `src/v1/model.ts:270` +### 10. `DeleteRefreshRequest` doc-block typo "Request to delete a ronitor." — `src/v1/model.ts:270` - **Why weird:** Doc string typo "ronitor" (should be "monitor" or "refresh"). Affects discoverability via IDE tooltip search. Plus, the doc text says "monitor" but the type's purpose is deleting a refresh — meta-error. - **Category:** 6 (misleading — typo invites confusion about the type's purpose). - **Suggested name:** Doc should read "Request to delete a refresh." - **Rationale:** Generator-emitted typo. Listed because the doc is the first thing IDE users see. -### 14. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v1/model.ts:100` -- **Why weird:** "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning ("full" alone is ambiguous — full path? full description?). Other Databricks SDK packages use `fullName` consistently for UC three-part names. -- **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). -- **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or `excludedTableFullyQualifiedNames` for absolute clarity. -- **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary, so the proposal is the *minor* rename to `excludedTables` since the type (string[]) plus parent context (anomaly detection on UC objects) already implies fully-qualified. - -### 15. `DataProfilingConfig.outputSchemaId` vs `monitoredTableName` vs `dashboardId` vs `warehouseId` — `src/v1/model.ts:158,211,224,209` -- **Why weird:** Identifier fields mix three reference styles in one type: `Id` (UC UUIDs: schema, dashboard, warehouse), `FullName` (table), and bare `Name` (output schema is by ID, but `assetsDir` is a path). The user reading `DataProfilingConfig` must remember that to set the *target* of the monitor you use `monitoredTableName` (a three-part name) but to set the *destination* of the metric tables you use `outputSchemaId` (a UUID). The pattern is wire-driven, not user-led. -- **Category:** 17 (inconsistent reference styles), 19 (underspecified IDs — `outputSchemaId` is a UUID but `monitoredTableName` is a three-part qualified name). -- **Suggested name:** Document both clearly in the JSDoc; consider a normalised pair `outputSchema: {id?: string, fullName?: string}` and `monitoredTable: {fullName: string}`. Or rename `monitoredTableName` to `monitoredTableFullName` (matches the JSDoc). -- **Rationale:** UC has a stable convention: `*FullName` for three-part references, `*Id` for UUIDs. Following that convention everywhere reduces caller errors. - -### 16. `DataProfilingConfig.warehouseId` and `DataProfilingConfig.effectiveWarehouseId` — `src/v1/model.ts:209,232` -- **Why weird:** Two parallel fields: user-provided `warehouseId` (optional input — falls back to "the first running warehouse" per doc) and `effectiveWarehouseId` (the warehouse actually used). Same shape as `dataclassification.autoTagConfigs` vs `effectiveAutoTagConfigs` (audited finding #6 in that package). The "effective" prefix is not marked output-only; a caller can set `effectiveWarehouseId` thinking it overrides `warehouseId`. Also: `effectiveWarehouseId` has no JSDoc trailer period ("The warehouse for dashboard creation" — missing period). -- **Category:** 1 (vague — "effective" undermarked), 6 (misleading — output-only not enforced by typing), and (style nit) missing period. -- **Suggested name:** Mark with JSDoc `@readonly`; or rename to `resolvedWarehouseId`. The minor doc-style miss (no period) is a CLAUDE.md rule violation: "Comments should always be proper sentences ending with a period." -- **Rationale:** Same pattern as the `effective*` audit findings in other packages. Output-only state should be visually distinct from input state. - -### 17. `DataProfilingConfig.monitoredTableName` — `src/v1/model.ts:211` -- **Why weird:** Half-redundant. `DataProfilingConfig` is a per-table config; the table being configured is "the monitored table". JSDoc says "Format: `catalog.schema.table_name`" — confirming this is a UC three-part name. Calling it `monitoredTableName` is fine, but it's the only "monitored" field on the type, so the prefix gives little signal. Compare with `Monitor.objectId` which holds the same data conceptually. -- **Category:** 1 (vague modifier — `monitored` adds nothing), 7 (overly verbose). -- **Suggested name:** `tableFullName` (or rely on `Monitor.objectId` and remove the duplicate field entirely). -- **Rationale:** The package already carries the target identity on `Monitor.objectId`. Duplicating it inside the config is a wire artifact, not a TS-level design choice. - -### 18. `DataProfilingConfig.latestMonitorFailureMessage` — `src/v1/model.ts:215` -- **Why weird:** Five-word field name on a type whose name is `DataProfilingConfig` — "latest" + "monitor" + "failure" + "message" + field is on `Monitor`. "Monitor" appears in the path: `monitor.dataProfilingConfig.latestMonitorFailureMessage`. -- **Category:** 7 (overly verbose), 8 (redundant suffix — `Monitor` is in the access path). -- **Suggested name:** `latestFailureMessage`. -- **Rationale:** Field path already gives the Monitor context; the field's own name should drop it. - -### 19. `DataProfilingConfig.profileMetricsTableName` / `driftMetricsTableName` — `src/v1/model.ts:217,219` -- **Why weird:** A pair where one is "profile metrics" and the other is "drift metrics", but the JSDoc is identical down to the punctuation ("Table that stores [profile|drift] metrics data. Format: `catalog.schema.table_name`."). The only diff between the field names is the leading noun, but the type name `DataProfilingConfig` already says "profiling" — so `profileMetricsTableName` reads slightly redundant. -- **Category:** 7 (overly verbose), 17 (inconsistent — drop "profile" prefix to match `driftMetricsTableName` shape, or add a profile/drift prefix universally). -- **Suggested name:** `profileMetricsTable` + `driftMetricsTable` (drop `Name` since wire is the same, and the type itself names a wire reference). -- **Rationale:** Consistent prefixing within a paired feature. Listed medium because the rename is risky for back-compat reasons. - -### 20. `DataProfilingConfig.slicingExprs` — `src/v1/model.ts:190` -- **Why weird:** `Exprs` abbreviation. The JSDoc is 8 lines explaining what `slicing_exprs` does; the field name reduces "expressions" to four characters of cryptic shorthand. Mixed-case: would be `slicingExprs` in TS but the wire field is `slicing_exprs` (Python-style). -- **Category:** 5 (cryptic abbreviation — `Exprs` for `Expressions`). -- **Suggested name:** `slicingExpressions` (or, given the doc explains they are "column expressions", `columnSlicingExpressions`). -- **Rationale:** Length is rarely an issue in TS — modern IDEs autocomplete. Cryptic abbreviation, however, costs readability forever. - -### 21. `DataProfilingConfig.customMetrics: DataProfilingCustomMetric[]` — `src/v1/model.ts:192` -- **Why weird:** Type name `DataProfilingCustomMetric` repeats the parent type's prefix (`DataProfiling`). Same field/type-name asymmetry called out in `dataclassification` (autoTag vs AutoTagging). Field `customMetrics` is fine; the type's prefix is the noise. -- **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `CustomMetric` (drop the `DataProfiling` prefix) — namespace via TS module if needed. -- **Rationale:** Inside the `dataquality` package, "custom metric" can only mean one thing (a profiling metric definition). The `DataProfiling` prefix is dead context. - -### 22. `DataProfilingCustomMetric.outputDataType: string` — `src/v1/model.ts:247` +### 11. `DataProfilingCustomMetric.outputDataType: string` vs `type: DataProfilingCustomMetricType` — `src/v1/model.ts:247` - **Why weird:** Field name is `outputDataType` and JSDoc says "The output type of the custom metric." — the JSDoc drops `Data`. Field is typed `string`, no enum. Compare with `type: DataProfilingCustomMetricType` which is enum and is the *kind* of metric, not its *data type*. The reader must parse two `type` fields on the same type. - **Category:** 1 (vague — `outputDataType` vs `type`), 12 (duplicate concept — two `type`s), 17 (inconsistent — one is enum, one is string). -- **Suggested name:** `outputSqlType` (since the value is a SQL type like `DOUBLE`), or `outputColumnType`. -- **Rationale:** Two `type`-like fields on the same struct is a code-smell; making one specifically `Sql` or `Column` removes the ambiguity. +- **Suggested name:** Document the distinction in JSDoc, or strengthen `outputDataType`'s type from `string` to an enum of supported SQL types. +- **Rationale:** Two `type`-like fields on the same struct is a code-smell; the typing should distinguish them. -### 23. `DataProfilingStatus` has both `ERROR` and `FAILED` members; `DELETE_PENDING` word order — `src/v1/model.ts:57` +### 12. `DataProfilingStatus` has both `ERROR` and `FAILED` members; `DELETE_PENDING` word order — `src/v1/model.ts:57` - **Why weird:** The enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately, with no JSDoc distinguishing them. Separately, `DELETE_PENDING` orders the tokens verb-then-state where most APIs write `PENDING_DELETE` (state-modified-by-action). - **Category:** 12 (duplicate concept — `ERROR` and `FAILED`), 17 (inconsistent word order vs sibling `PENDING`). - **Suggested name:** Either merge `ERROR` and `FAILED` into a single member, or document the difference in JSDoc. Reorder `DELETE_PENDING` to `PENDING_DELETE`. - **Rationale:** The implicit duplicate of `ERROR`/`FAILED` makes this enum harder to reason about than it should be; two synonymous terminal states force callers to handle both. `PENDING_DELETE` mirrors the existing `PENDING` member's modifier-suffix shape. -### 24. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` -- **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #8). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). +### 13. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` +- **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #6). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). - **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). - **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. -### 25. `CronSchedule.quartzCronExpression` and `CronSchedule.timezoneId` — `src/v1/model.ts:144,150` -- **Why weird:** Field is qualified with `Quartz` (the scheduling library) leaking implementation detail; users do not need to know the schedule is parsed by Quartz on the server side. `timezoneId` collides with the IANA tz database vocabulary ("timezone ID" is not standard; "IANA timezone name" or just "timezone" is). -- **Category:** 14 (implementation-detail leak — `Quartz` is a Java library reference), 5 (jargon — `timezoneId` vs the JS-standard `timeZone`). -- **Suggested name:** `cronExpression` + `timezone`. -- **Rationale:** The doc already says "Java timezone id"; the field name should be neutral. - -### 26. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` +### 14. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` - **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. - **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). -- **Suggested name:** Field: `onFailureOrTimeout` (matches doc), or `onFailure` (matches name; update doc). Type: `Destination` (drop the `Notification` prefix since the type is only used here). -- **Rationale:** Field name and JSDoc should agree on whether timeouts are included. - -### 27. `Refresh.message` — `src/v1/model.ts:440` -- **Why weird:** `message` is the most generic possible name on a `Refresh` object. JSDoc clarifies: "An optional message to give insight into the current state of the refresh (e.g. FAILURE messages)" — so this is really an error message or status message, not just any message. -- **Category:** 1 (vague — `message` could be anything), 15 (generic field name). -- **Suggested name:** `statusMessage` or `stateMessage`. -- **Rationale:** Field on a typed object should be self-describing. +- **Suggested name:** Type: `Destination` (drop the `Notification` prefix since the type is only used here). Field stays `onFailure`; update doc to clarify timeout semantics. +- **Rationale:** Field name and JSDoc should agree on whether timeouts are included; type name should not repeat its parent's noun. -### 28. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` -- **Why weird:** Five sibling types all end in `Config`: `AnomalyDetectionConfig`, `DataProfilingConfig`, `InferenceLogConfig`, `TimeSeriesConfig`, `SnapshotConfig`. The `Config` suffix is a proto-style architectural label — it adds no semantic information once you know the type is a configuration record. The Go reference SDK uses these names because protobuf's `*Config` messages map 1:1 to Go structs, but TS does not need to carry that scaffolding. The leak is most visible at the call site `DataProfilingConfig.analysisConfig` (already flagged in #8) where three `Config`-suffixed arms nest inside a `Config`-suffixed field on a `Config`-suffixed type — triple `Config` nesting in a single access path. +### 15. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` +- **Why weird:** Five sibling types all end in `Config`: `AnomalyDetectionConfig`, `DataProfilingConfig`, `InferenceLogConfig`, `TimeSeriesConfig`, `SnapshotConfig`. The `Config` suffix is a proto-style architectural label — it adds no semantic information once you know the type is a configuration record. The Go reference SDK uses these names because protobuf's `*Config` messages map 1:1 to Go structs, but TS does not need to carry that scaffolding. The leak is most visible at the call site `DataProfilingConfig.analysisConfig` where three `Config`-suffixed arms nest inside a `Config`-suffixed field on a `Config`-suffixed type — triple `Config` nesting in a single access path. - **Category:** proto-architectural-leak (repeated `Config` mid/suffix), 8 (redundant suffix), 12 (duplicate concept). - **Suggested name:** Drop the `Config` suffix on the analysis-arm types: `InferenceLog`, `TimeSeries`, `Snapshot`. Keep `AnomalyDetectionConfig` / `DataProfilingConfig` as the top-level monitor configurations (they are genuinely "the config" of a `Monitor`). Or rename uniformly to `AnomalyDetectionSettings` / `DataProfilingSettings` and use `Analysis` for the arm types. - **Rationale:** `Config` is generator-template noise inherited from `.proto` message names. Removing it produces names that read as the domain concept they represent (`InferenceLog`, `TimeSeries`, `Snapshot`) rather than as scaffolding. ## Low severity -### 29. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 16. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's two list endpoints handle pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as `dataclassification` finding #19. -### 30. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +### 17. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataclassification` finding #15. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 31. `buildHttpRequest` — `src/v1/utils.ts:96` +### 18. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataclassification` finding #16; "build" suggests builder pattern, the function spreads literals. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the simpler reality. -### 32. `readAll` — `src/v1/utils.ts:40` +### 19. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Identical to `dataclassification` finding #20; "readAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing name for stream draining. -### 33. `HttpCallOptions` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataclassification` finding #21; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 34. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` +### 21. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` - **Why weird:** Same as `dataclassification` finding #22; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 35. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` +### 22. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` - **Why weird:** Same as `dataclassification` finding #24; variable named `call` of type `Call` repeated 11 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 36. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +### 23. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` - **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. @@ -237,20 +159,20 @@ ## Observations -### 37. Heavy boilerplate dominates the file +### 24. Heavy boilerplate dominates the file `model.ts` is 1030 lines for ~16 user-facing types; ~520 lines (~50%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. -### 38. Action verbs in `Client` +### 25. Action verbs in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) -### 39. Acronym casing +### 26. Acronym casing Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. - **Category:** 3 (acronym casing). -### 40. Tense / nominalisation drift in enum naming +### 27. Tense / nominalisation drift in enum naming `AnomalyDetection` (gerund), `DataProfiling` (gerund), `DataClassification` (noun) — at the package boundary the gerund/noun choice tracks the API team's preference. Within `dataquality` the choice is consistent (both gerunds), good. -### 41. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types +### 28. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types Same shape as the `dataclassification` casing observation (#32 in that package): directory is one collapsed word, types are PascalCase compounded, wire path is kebab. SDK-wide convention question, not local. - **Category:** 3 (casing inconsistency). @@ -273,7 +195,3 @@ Same shape as the `dataclassification` casing observation (#32 in that package): - `src/v1/client.ts` (515 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (42 lines): read fully. - -## Fixed -- #14 `PercentNullValidityCheck` / `RangeValidityCheck` / `UniquenessValidityCheck` / `ValidityCheckConfiguration` (originally cited at `src/v1/model.ts:440-501,552`): Fixed in regeneration on 2026-05-20 — all validity-check types and the `ValidityCheckConfiguration` container have been removed from the model entirely. -- #17 `AnomalyDetectionConfig.anomalyDetectionWorkflowId` (originally cited at `src/v1/model.ts:111`): Fixed in regeneration on 2026-05-20 — field removed; `AnomalyDetectionConfig` now only carries `excludedTableFullNames`. diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index 706a28d4..c0ffd224 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -3,13 +3,13 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 23 +**Total weird names flagged:** 14 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 11 | +| High | 3 | +| Medium | 4 | | Low | 5 | | Observation | 2 | @@ -25,7 +25,7 @@ - **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #23 — same issue applies in `utils.ts` field `url` on `StableUrl`.) +- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #13 — same issue applies in `utils.ts` field `url` on `StableUrl`.) ### 3. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` - **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: @@ -37,81 +37,27 @@ - **Suggested name:** Consider splitting: keep `primaryRegion` (effective) on `FailoverGroup`; lift `initialPrimaryRegion` into `CreateFailoverGroupRequest` as a sibling of `failoverGroup`; keep `targetPrimaryRegion` on `FailoverFailoverGroupRequest`. If the generator cannot split (since this mirrors a proto with output_only annotations), at minimum mark `initialPrimaryRegion` `@deprecated`-style write-only in JSDoc with a `WRITE-ONLY` tag. - **Rationale:** The current shape forces the user to read three different paragraphs to learn that the same-typed fields obey three different rules. This is the most user-hostile naming pattern in the file. -### 4. `replicationPoint: Temporal.Instant` — `src/v1/model.ts:144` -- **Why weird:** `Point` is generic; this is a recovery-point timestamp (the data-loss bound aka RPO marker). The JSDoc says "The latest point in time to which data has been replicated", which is much clearer than the field name. A reader sees `failoverGroup.replicationPoint` and may guess "endpoint of replication" or "destination point". -- **Category:** 1 (vague), 6 (misleading — `Point` suggests a location, not a time). -- **Suggested name:** `replicationLagTime` / `lastReplicatedAt` / `recoveryPointTime` (the last matches Databricks DR docs and the well-known RPO term). -- **Rationale:** Other timestamp fields on the same struct use the `…Time` suffix (`createTime`, `updateTime`). Consistency + clarity in one rename. - -### 5. `replicateWorkspaceAssets` field on `WorkspaceSet` — `src/v1/model.ts:320` -- **Why weird:** Field documented as "Whether to enable control plane DR (notebooks, jobs, clusters, etc.) for this set." The field name says `replicateWorkspaceAssets` but the doc says "control plane DR" — those aren't synonyms. A user looking for "enable CPDR" will not find a `cpdr` field; a user looking for "replicate" will not realise this is the control-plane toggle vs the data-plane (UC) replication elsewhere on the parent. -- **Category:** 6 (misleading — field name and doc disagree), 1 (vague — `workspaceAssets` is undefined jargon). -- **Suggested name:** `enableControlPlaneReplication` (matches doc and matches the implied UCDR/CPDR split), or `replicateControlPlane`. -- **Rationale:** The parent `FailoverGroup` has `unityCatalogAssets` (UC data plane) and this boolean (control plane). Naming them as a matched pair — e.g., `unityCatalogReplication` + `controlPlaneReplication` — would make the symmetry visible. - ## Medium severity -### 6. `WorkspaceSet.name: string` (resource-name vs human-name ambiguity) — `src/v1/model.ts:309` -- **Why weird:** `name` on `WorkspaceSet` is documented only as "Resource name for this workspace set". `name` on `FailoverGroup` (line 120) is documented as a fully-qualified resource name (`accounts/{account_id}/failover-groups/{failover_group_id}`). `name` on `StableUrl` (line 252) is fully-qualified too. `name` on `LocationMapping` (line 227) is "Resource name for this location". A user can't tell from the field which `name`s are FQ resource names versus simple labels. -- **Category:** 15 (generic field name losing meaning across types), 19 (under-specified identifier). -- **Suggested name:** Where the value is FQ, prefer `resourceName`; where the value is a label, prefer `label` or `displayName`. Failing that, tighten every JSDoc to spell out the wire format like `FailoverGroup.name` does. -- **Rationale:** The package has at least three different meanings for `name`. Searching IDE for `.name` in a `FailoverGroup` chain returns many hits with different semantics. - -### 7. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:278` +### 4. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:278` - **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 131) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. - **Category:** 5 (cryptic abbreviation `Uc`), 8 (redundant `Uc` prefix inside Uc context), 17 (inconsistency — `unityCatalog` vs `Uc`). - **Suggested name:** `Catalog` (or `ReplicatedCatalog`), and field type `catalogs: Catalog[]`. - **Rationale:** `UcReplicationConfig.catalogs: UcCatalog[]` reads as "UC replication config's UC catalogs" — redundant. The full `unityCatalog` spelling is used adjacent in the file; either propagate that or drop the prefix entirely inside the UC-scoped type. -### 8. `UcReplicationConfig` — `src/v1/model.ts:284` +### 5. `UcReplicationConfig` — `src/v1/model.ts:284` - **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). - **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #9). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. -### 9. `unityCatalogAssets: UcReplicationConfig` — `src/v1/model.ts:131` -- **Why weird:** Field named `unityCatalogAssets` but the type is `UcReplicationConfig`. "Assets" doesn't appear in the type name. The type contains location mappings + catalogs + a workspace-set reference — none of which are commonly called "assets". The sibling `replicateWorkspaceAssets` (line 320) uses "assets" with a completely different meaning (control-plane objects vs Unity Catalog config). -- **Category:** 15 (generic word "assets" used in two different meanings within the file), 20 (type-suffix tautology since the field carries replication config of a `UcReplicationConfig`). -- **Suggested name:** `unityCatalogReplication` or `unityCatalogConfig`. -- **Rationale:** Field name should match the type's purpose; "assets" is a misleading umbrella here. - -### 10. `WorkspaceSet.stableUrlNames: string[]` (with FQ-name semantics) — `src/v1/model.ts:326` -- **Why weird:** Field is `string[]` of fully-qualified resource names (per JSDoc: `accounts/{account_id}/stable-urls/{stable_url_id}`). The name `stableUrlNames` implies a list of `StableUrl` objects' `name` field; the FQ-vs-id semantics are buried in the doc. -- **Category:** 19 (under-specified identifier — strings that are actually FQ resource names), 6 (misleading singular/plural framing — these are references, not names). -- **Suggested name:** `stableUrlRefs` or `stableUrlResourceNames` (matches the FQ semantics explicitly). -- **Rationale:** Other places in the same SDK use `*Ref` or `*ResourceName` for FQ references; `*Names` is ambiguous (Could be display names? Could be IDs?). - -### 11. `dataReplicationWorkspaceSet: string` — `src/v1/model.ts:293` -- **Why weird:** Long compound noun field of type `string`, semantics (a workspace-set reference by name? id? FQ?) hidden in JSDoc. The doc says "The workspace set whose workspaces will be used for data replication of all UC catalogs' underlying storage." — implying the value is a `WorkspaceSet.name`, but again the type is a bare `string`. -- **Category:** 7 (overly verbose), 19 (under-specified id), 6 (string for a typed concept). -- **Suggested name:** `dataReplicationWorkspaceSetName` or `dataReplicationWorkspaceSetRef`. Or split: `dataReplicationWorkspaceSet: { name: string }` for symmetry with the rest of the model. -- **Rationale:** Within `UcReplicationConfig`, `locationMappings` is typed, `catalogs: UcCatalog[]` is typed, but `dataReplicationWorkspaceSet: string` is loose. Inconsistent typing across siblings. - -### 12. `etag` field on multiple types — `src/v1/model.ts:78,106,138` +### 6. `etag` field on multiple types — `src/v1/model.ts:78,106,138` - **Why weird:** `etag` lowercased. Web/HTTP convention is `ETag` (capital E-Tag, RFC 9110 §8.8.3). The wire format here is `etag` (lowercase, per the Zod schema line 332). Mixed casing across the ecosystem; the lowercase here at least mirrors the wire, but a TS reader might expect `eTag` or `ETag`. - **Category:** 3 (acronym casing). - **Suggested name:** Keep `etag` for wire fidelity; document the choice in a top-level comment. (Or use `eTag` if the SDK style guide prefers JS-camelCase for acronyms.) - **Rationale:** Low-impact but flagged because the audit asks for casing inconsistencies. The Google TS style guide (loaded skill `google-ts-styleguide:ts-style-guide`) generally prefers camelCase for acronyms (so `etag` is actually fine). -### 13. `validateOnly: boolean` — `src/v1/model.ts:44,59` -- **Why weird:** "ValidateOnly" is a generic flag pattern; doesn't say what is validated or what the side effect of the validation is. Same word used identically on `CreateFailoverGroupRequest` and `CreateStableUrlRequest`. Fine on its own but worth noting: there is no dryRun/preview field elsewhere, so a user familiar with `dryRun: boolean` convention may not search for `validateOnly`. -- **Category:** 1 (vague), 6 (mildly misleading — "validate only" could imply the result is a validation report; here it's a side-effect suppressor). -- **Suggested name:** `dryRun` (industry standard) or keep `validateOnly` with a tighter JSDoc. -- **Rationale:** Two of the four Create-style APIs use this; `dryRun` is the common convention in Kubernetes/many DBR SDKs. - -### 14. `parent` field on `Create*Request` / `List*Request` — `src/v1/model.ts:40,55,173,200` -- **Why weird:** Bare `parent` with format `accounts/{account_id}`. The literal word "parent" requires JSDoc to decode; idiomatic naming would be `account` or `accountId` or `parentResourceName`. -- **Category:** 1 (vague), 19 (under-specified id). -- **Suggested name:** `account` (since the format hard-codes `accounts/{account_id}`) or `parentResourceName`. -- **Rationale:** "Parent" is proto AIP-132 jargon. SDK users speak in domain terms ("the account this group belongs to"). - -### 15. `failoverGroupId` / `stableUrlId` client-provided suffix fields — `src/v1/model.ts:49,64` -- **Why weird:** Field is a client-side hint that becomes part of the resource name; pattern is "if set, server uses it as the trailing identifier". JSDoc on `failoverGroupId` says: "Used to construct the resource name as `{parent}/failover-groups/{failover_group_id}`." Two ids floating around — the FQ `name` (server-formed) and this client suffix — invite confusion. -- **Category:** 19 (under-specified identifier among multiple), 20 (type-suffix tautology — `failoverGroup.Id` in a `CreateFailoverGroupRequest`). -- **Suggested name:** `requestedFailoverGroupId` / `requestedStableUrlId` to make it clear this is a suggestion, not the final resource id. Alternative: `customId` / `userProvidedId`. -- **Rationale:** Once created, the FQ `name` is the canonical reference; `failoverGroupId` is a vestigial input. Names should reflect lifecycle. - -### 16. `Client` class name — `src/v1/client.ts:52` +### 7. `Client` class name — `src/v1/client.ts:52` - **Why weird:** Plain `Client` is the maximally-generic name. Once imported, callers see `import { Client } from '@databricks/sdk-disasterrecovery/v1'` — fine if used qualified, but `new Client()` floating in user code is meaningless. Sibling packages all do the same per generator convention; flagging this once at the package level. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `DisasterRecoveryClient`. (Or rely on import aliases.) @@ -119,31 +65,31 @@ ## Low severity -### 17. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +### 8. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. -### 18. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` +### 9. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` - **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Same as other packages in the audit. Flag once per package. -### 19. `flattenQueryParams` — `src/v1/utils.ts:123` +### 10. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (generator default) or document why it ships per-package. - **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. -### 20. `readAll` — `src/v1/utils.ts:40` +### 11. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToBuffer`. - **Rationale:** Internal helper. Skip if generated identically across all packages. -### 21. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 12. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + ApiError lift). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -151,10 +97,10 @@ ## Observations -### 22. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#17), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. +### 13. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#8), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. -### 23. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +### 14. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` Within this package: - `stableUrl`/`StableUrl` (PascalCase capital-then-lower). - `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). @@ -166,7 +112,7 @@ Three different casings for two acronyms (URL/URI). The Web platform uses `URL` - **DR** — Disaster Recovery. Encoded in the package name `disasterrecovery`. Mentioned once in a JSDoc on `replicateWorkspaceAssets` ("control plane DR"). - **UCDR** — Unity Catalog Disaster Recovery (UC data plane replication). Mentioned in JSDoc at `model.ts:113`. Not present as an identifier. - **CPDR** — Control Plane Disaster Recovery (notebooks, jobs, clusters, etc.). Mentioned in JSDoc at `model.ts:113,308`. Not present as an identifier — encoded only via `replicateWorkspaceAssets: boolean`. -- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #8). +- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #4). - **EA** — Early Access / Early Adoption? Mentioned in JSDoc on `WorkspaceSet.workspaceIds` (line 305) as "EA: exactly 2 workspaces (one per region)". Not decoded anywhere in the package. - **RPO** — Recovery Point Objective. Not explicitly named; `replicationPoint` (line 144) is effectively the RPO marker. - **RTO** — Recovery Time Objective. Not present in this package. diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md index b0c8e008..7f709e9f 100644 --- a/.agent/naming-audit/endpoints.md +++ b/.agent/naming-audit/endpoints.md @@ -1079,44 +1079,3 @@ consumers. SDK level is unavoidable. --- - -## Fixed - -The 2026-05-20 regeneration renamed the `endpoints` package to -`vectorsearch` and absorbed the contents of the former `indexes` -package. The throughput-management surface -(`PatchEndpointThroughputRequest/Response`, -`patchEndpointThroughput` method, -`ThroughputChangeRequestState`/`ThroughputPatchStatus` enums, -`EndpointThroughputInfo` interface, `AdjustedThroughputRequest` -interface) was removed from the public surface, and several -implementation-leaking enum values and verbose field names were -dropped. - -- #F0.1 Package name `@databricks/sdk-endpoints` (originally cited at `package.json:2`): Fixed in regeneration on 2026-05-20 — package renamed to `@databricks/sdk-vectorsearch`, eliminating the cross-package ambiguity with model serving and SQL warehouses. -- #F0.2 Directory name `packages/endpoints/` (originally cited at `packages/endpoints/`): Fixed in regeneration on 2026-05-20 — directory renamed to `packages/vectorsearch/`. -- #F0.3 Companion package `indexes` (originally cited at `packages/indexes/`): Fixed in regeneration on 2026-05-20 — `indexes` package was absorbed into `vectorsearch`, so the cross-package qualification concern no longer applies. -- #F2.2 `ThroughputChangeRequestState.CHANGE_*` (originally cited at `model.ts:20-33`): Fixed in regeneration on 2026-05-20 — `ThroughputChangeRequestState` enum was removed entirely along with the throughput-management surface. -- #F2.3 `ThroughputPatchStatus.PATCH_*` (originally cited at `model.ts:36-43`): Fixed in regeneration on 2026-05-20 — `ThroughputPatchStatus` enum was removed entirely. -- #F2.5 `EndpointType.STANDARD_ON_ORION` (originally cited at `model.ts:10`): Fixed in regeneration on 2026-05-20 — `STANDARD_ON_ORION` enum value was dropped; `EndpointType` now has only `STORAGE_OPTIMIZED` and `STANDARD`. -- #F6.4 `EndpointType.STANDARD_ON_ORION` implementation leak (originally cited at `model.ts:9-10`): Fixed in regeneration on 2026-05-20 — `STANDARD_ON_ORION` enum value was removed, eliminating the infra-naming leak. -- #F6.5 `minimalConcurrencyAllowed` field (originally cited at `model.ts:71-72, 168-169, 237-238`): Fixed in regeneration on 2026-05-20 — concurrency fields removed from the public API surface. -- #F7.3 `PatchEndpointThroughputRequest/Response` (originally cited at `model.ts:232, 255`): Fixed in regeneration on 2026-05-20 — throughput-management surface was removed entirely. -- #F7.5 `currentConcurrencyUtilizationPercentage` (originally cited at `model.ts:166-167`): Fixed in regeneration on 2026-05-20 — field removed along with the throughput-management surface. -- #F7.6 `EndpointThroughputInfo` `Info` suffix (originally cited at `model.ts:142`): Fixed in regeneration on 2026-05-20 — `EndpointThroughputInfo` interface was removed entirely. -- #F8.4 `EndpointThroughputInfo` `Info` suffix (originally cited at `model.ts:142, 161`): Fixed in regeneration on 2026-05-20 — `EndpointThroughputInfo` interface was removed. -- #F8.5 `ThroughputChangeRequestState` (originally cited at `model.ts:20`): Fixed in regeneration on 2026-05-20 — enum was removed. -- #F11.1 `AdjustedThroughputRequest` exposed in a response (originally cited at `model.ts:68-75, 264`): Fixed in regeneration on 2026-05-20 — `AdjustedThroughputRequest` interface was removed along with the throughput-management surface. -- #F12.1 `numReplicas` in three different places (originally cited at `model.ts:87, 252, 177, 179`): Fixed in regeneration on 2026-05-20 — `numReplicas` field removed from the public API surface. -- #F12.2 `targetQps`, `requestedTargetQps`, `replicationFactor`, `numReplicas` overlap (originally cited at `model.ts:87, 93, 224, 229, 252, 149`): Fixed in regeneration on 2026-05-20 — `replicationFactor` and `numReplicas` fields removed; only `targetQps` remains as the public dimension. -- #F12.4 `concurrency` (CPU) vs `numReplicas` vs `targetQps` mixed (originally cited at `model.ts:69, 73, 87, 93, 162, 165, 168, 171, 177, 235, 238, 240, 252`): Fixed in regeneration on 2026-05-20 — `concurrency` and `numReplicas` fields removed; only `targetQps` remains. -- #F15.6 `concurrency` field (originally cited at `model.ts:70, 236`): Fixed in regeneration on 2026-05-20 — `concurrency` field was removed from the public API surface. -- #F16.2 `EndpointThroughputInfo.changeRequestState` (originally cited at `model.ts:173`): Fixed in regeneration on 2026-05-20 — `EndpointThroughputInfo` interface was removed. -- #F18.3 `CHANGE_REACHED_MINIMUM`, `CHANGE_REACHED_MAXIMUM` (originally cited at `model.ts:26, 28`): Fixed in regeneration on 2026-05-20 — `ThroughputChangeRequestState` enum was removed. -- #F18.4 `STANDARD_ON_ORION` (originally cited at `model.ts`): Fixed in regeneration on 2026-05-20 — enum value was removed; the remaining `STORAGE_OPTIMIZED` and `STANDARD` are no longer flagged as infra leaks. -- #F20.4 `PatchEndpointThroughputResponse.status: ThroughputPatchStatus` (originally cited at `model.ts:257, 36`): Fixed in regeneration on 2026-05-20 — both the response type and the enum were removed. -- #F20.6 `EndpointThroughputInfo.changeRequestState: ThroughputChangeRequestState` (originally cited at `model.ts:173`): Fixed in regeneration on 2026-05-20 — interface and enum were both removed. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index eb72740d..b6b56e24 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -3,14 +3,14 @@ **Path:** `packages/entitytagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). -**Total weird names flagged:** 24 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | -| High | 7 | +| High | 5 | | Medium | 9 | -| Low | 4 | +| Low | 2 | | Observation | 4 | ## High severity @@ -21,37 +21,25 @@ - **Suggested name:** Merge into a single package `tagassignments` keyed by `entityKind` ("uc" vs. "platform"), or rename to `uctagassignments` so the surface marker is "uc", not "entity". The non-UC sibling can drop its own `entityType` field discrimination and become `platformtagassignments`. As a smaller fix: `unitycatalogtags` here, `platformtags` there. - **Rationale:** Two `Client` classes called `Client`, with two `TagAssignment` / `EntityTagAssignment` types, both shipping `tagKey`/`tagValue`/`entityType`, will collide in user imports and force aliasing on every co-use. The split exists for backend reasons but leaks raw into the SDK. Worth flagging upstream as a generator-level concern. -### 2. `EntityTagAssignment` field shape vs. sister `TagAssignment` shape — `src/v1/model.ts:32-47` vs. `tagassignments/src/v1/model.ts:46-55` -- **Why weird:** The two sister types model the same conceptual object using different identifier fields: this package's `EntityTagAssignment` has `entityName: string`, while `tagassignments.TagAssignment` has `entityId: string`. Same column conceptually (the thing being tagged), different field name. A user porting code between the two has to translate. The JSDoc here says "fully qualified name" while the sister says "identifier"; the wire-side names are `entity_name` vs. `entity_id`. -- **Category:** 12 (duplicate concept with divergent naming), 17 (verb/noun inconsistency across siblings), 16 (field contradicts type domain — "name" suggests a label, "id" suggests an opaque handle, but both fields are fully-qualified resource identifiers). -- **Suggested name:** Unify on `entityFullName` (matches Unity Catalog vocabulary like `catalogs.fullName`, `tables.fullName`) or `entity` for both packages. At minimum, both packages should agree. -- **Rationale:** Splitting "name vs id" by package makes the cross-package developer experience worse. The Unity Catalog product surface consistently calls these `full_name`/`fullName` (see `catalogs`, `schemas`, `tables`); using `entityName` here breaks that convention silently. - -### 3. `TagAssignmentSourceType` — `src/v1/model.ts:9` +### 2. `TagAssignmentSourceType` — `src/v1/model.ts:9` - **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. Combined with the surrounding type `EntityTagAssignment`, the relevant field is `sourceType: TagAssignmentSourceType` — five words to say "where did this come from". - **Category:** 20 (type-suffix tautology — `Type` on an enum), 7 (overly verbose). - **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). Field becomes `source: TagSource`. - **Rationale:** The shorter name is unambiguous in context (`EntityTagAssignment.source` reads better than `EntityTagAssignment.sourceType`). Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. -### 4. `entityName: string` doc says "fully qualified name" but type does not enforce — `src/v1/model.ts:24,34,52,62` -- **Why weird:** Four places in this file have a field called `entityName` whose JSDoc says "The fully qualified name of the entity to which the tag is assigned". The shape `name?: string | undefined` cannot enforce qualification; users will pass bare names. Compare Unity Catalog convention `fullName` (used in `catalogs`, `schemas`, `tables`). -- **Category:** 1 (vague — "name" is too generic), 6 (misleading — looks settable to a bare name, is actually structured), 15 (generic field name losing meaning), 19 (underspecified ID — what makes it "fully qualified"?). -- **Suggested name:** `entityFullName` (or `entity`/`entityFqn`). Matches sister UC packages. -- **Rationale:** "fully qualified" is wire-side; the SDK type should make the constraint visible in the identifier. A field literally called `entityName` reads as a display name to most TS users. - -### 5. `entityType: string` everywhere — `src/v1/model.ts:28,40,56,68` +### 3. `entityType: string` everywhere — `src/v1/model.ts:28,40,56,68` - **Why weird:** Four occurrences of `entityType?: string | undefined` with no enum or string-literal union to constrain values. The JSDoc says "The type of the entity to which the tag is assigned" but never lists which values are valid (compare sister `tagassignments`: doc explicitly lists `apps, dashboards, geniespaces, notebooks`). For Unity Catalog entities, the actual valid set is something like `table`, `schema`, `catalog`, `column`, `volume`, `function`, `model` — none of which is documented or constrained in the type. - **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what type strings are valid?), 6 (misleading — looks free-form, is actually constrained). - **Suggested name:** `EntityKind` (string-literal union or enum) typed as the field. E.g. `entityKind?: 'table' | 'schema' | 'catalog' | 'column' | 'volume' | 'function' | 'model'`. The field name `Type` also collides with the JS reserved-ish word — `Kind` reads more cleanly. - **Rationale:** Stringly-typed enum fields are a generator anti-pattern. The valid set is closed; the type should say so. `Type` as a noun is also overused — `Kind` is the convention in TS standard library (`SyntaxKind`, `NodeKind`). -### 6. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` +### 4. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` - **Why weird:** `DeleteEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag to delete". `GetEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag". But `EntityTagAssignment.tagKey` (on the actual returned/created object) and `CreateEntityTagAssignmentRequest.tagAssignment.tagKey` are documented as just "The key of the tag" with no required marker — yet you cannot create or get a tag without a key. The `?: string | undefined` typing makes all of them optional in TS. Type and doc disagree. - **Category:** 6 (misleading — type says optional, semantics says required), 17 (inconsistent — some docs say "Required.", others don't, for what is the same logical field). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) and remove the "Required." doc preamble since the type enforces it. Apply uniformly across all four request types and the assignment type itself. - **Rationale:** "Required." in a docstring while the type is optional is a generator smell. Honest required-ness should travel through the type. -### 7. `Client` class — `src/v1/client.ts:41` +### 5. `Client` class — `src/v1/client.ts:41` - **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The other tag packages (`tagassignments`, `tagpolicies`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages). - **Suggested name:** `EntityTagAssignmentsClient` (or `UnityCatalogTagsClient`). @@ -59,13 +47,13 @@ ## Medium severity -### 8. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` +### 6. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` - **Why weird:** The plural appears only on the list endpoint; the rest of the surface is singular. Singular/plural mix is consistent with the Go SDK and other packages, but worth flagging that the resource name on the wire is `/entity-tag-assignments` (plural) while the type name is singular `EntityTagAssignment`. The list response is `ListEntityTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. - **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. -### 9. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 7. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — `executeCall` runs the retry/rate-limit shell, `executeHttpCall` does the actual HTTP send. They appear together in every client method: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -80,43 +68,43 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Names should reveal the layering, not require code-diving. Generator-wide concern. -### 10. `Call` type and `call` variable — `src/v1/client.ts:86,119,139,178,242` and `src/v1/utils.ts:27` +### 8. `Call` type and `call` variable — `src/v1/client.ts:86,119,139,178,242` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, called inside `executeCall(call, options)`. The same word is the variable, the type, and the verb. Inside one method scope we have `req`, `call`, `httpReq` — three layered names where one of them collides with its type. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions are tolerable but obscure prose-style code. -### 11. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` +### 9. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. -### 12. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 143-148, 182-187, 252-257` +### 10. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 143-148, 182-187, 252-257` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: EntityTagAssignment`. The names differ only by `Body`. Both are short for "response". The reader has to track which is bytes, which is parsed. Compare `req` (parameter, request) — also abbreviated, but no `reqBody` sibling. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result`, or `responseBytes` + `response`. - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 13. `httpReq` local variable — `src/v1/client.ts:89,122,142,181,245` +### 11. `httpReq` local variable — `src/v1/client.ts:89,122,142,181,245` - **Why weird:** Inside a method that already has `req: CreateEntityTagAssignmentRequest`, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in one scope. -### 14. `HttpCallOptions` — `src/v1/utils.ts:15` +### 12. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 15. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 13. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just shorthand. -### 16. `flattenQueryParams` — `src/v1/utils.ts:123` +### 14. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** The function is exported but unused in `client.ts` (this package's list endpoint uses individual `params.append(...)` calls instead). Dead-code-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. @@ -124,44 +112,32 @@ ## Low severity -### 17. `readAll(body)` — `src/v1/utils.ts:40` +### 15. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path or array. -### 18. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 16. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. Casing is appropriate for a module constant; the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain; the comment above it does the work the name should. -### 19. `tagKey` and `tagValue` co-located on `EntityTagAssignment` — `src/v1/model.ts:36,38` -- **Why weird:** The pair encodes a `(key, value)` tag — that part is fine. But the type is *already* called `EntityTagAssignment`, so the `tag` prefix on each field is redundant within scope: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. -- **Category:** 8 (redundant prefix — `tag` within `EntityTagAssignment`). -- **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. -- **Rationale:** Field names should not re-state their containing type's noun. `assignment.key` / `assignment.value` reads cleaner. - -### 20. `updateTime` and `updatedBy` paired field naming — `src/v1/model.ts:42,44` -- **Why weird:** Verb tense pair: `updateTime` (noun-noun, gerund stripped) vs. `updatedBy` (past participle). Cross-SDK convention should pick one. Compare: `createTime` (noun-noun) often pairs with `createdBy` (past participle) in Databricks — the same asymmetry. It is consistent across the SDK, but worth noting under rule 13. -- **Category:** 13 (verb-tense inconsistency within a paired field). -- **Suggested name:** `updateTime`/`updateBy` or `updatedTime`/`updatedBy`. Either works; the asymmetry is the issue. -- **Rationale:** Established SDK pattern, but rule 13 demands the flag. - ## Observations -### 21. Action verb consistency +### 17. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 22. Acronym casing +### 18. Acronym casing The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 23. `entitytagassignments` lowercase package name +### 19. `entitytagassignments` lowercase package name The package directory is `entitytagassignments` (single token, no separator), but every type uses `EntityTagAssignment` and the HTTP path uses `entity-tag-assignments`. Same problem as `dataclassification`. SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 24. Domain leakage from sister packages +### 20. Domain leakage from sister packages Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). @@ -180,7 +156,3 @@ Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — a - `src/v1/client.ts` (265 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. - `src/v1/index.ts` (15 lines): read fully. - -## Fixed -- #9 `includeInherited` boolean doc is wrong (originally cited at `src/v1/model.ts:60,74`): Fixed in regeneration on 2026-05-20 — `includeInherited` field removed from request DTOs entirely. -- #24 `inherited` boolean on `EntityTagAssignment` (originally cited at `src/v1/model.ts:48`): Fixed in regeneration on 2026-05-20 — `inherited` field removed from the response type. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index 0a66573b..8f7b1761 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -5,14 +5,14 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 28 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 11 | -| Low | 7 | +| Medium | 4 | +| Low | 5 | | Observation | 2 | --- @@ -89,55 +89,13 @@ - **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. - **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. -### 11. `DefaultWorkspaceBaseEnvironment.cpuWorkspaceBaseEnvironment` / `gpuWorkspaceBaseEnvironment` — fields stutter the type name — `model.ts:574, 579` -- **Why weird:** Field names contain the wrapping type's name three times. Read aloud: "the cpu workspace base environment field on the default workspace base environment". The values are just resource-name *strings* pointing at another `WorkspaceBaseEnvironment` ("Format: workspace-base-environments/{workspace_base_environment}"). Field names `cpu` and `gpu` plus a typed `WorkspaceBaseEnvironmentRef` would be cleaner. -- **Category:** 7 (overly verbose), 15 (generic field names — the value is just a resource name). -- **Suggested name:** `cpu` / `gpu` (with field type `string` or `WorkspaceBaseEnvironmentName`), or `cpuEnvironmentName` / `gpuEnvironmentName`. -- **Rationale:** The type is *already* `DefaultWorkspaceBaseEnvironment`. Repeating the prefix on every field makes consumers type `defEnv.cpuWorkspaceBaseEnvironment` instead of `defEnv.cpu`. - -### 12. `WorkspaceBaseEnvironment.baseEnvironmentType` — field prefix duplicates parent type name — `model.ts:743` -- **Why weird:** On a type called `WorkspaceBaseEnvironment`, the field is `baseEnvironmentType`. The `baseEnvironment` prefix duplicates the parent. Plain `type` (or `computeType`) would suffice. -- **Category:** 8 (redundant suffix/prefix), 7 (verbose). -- **Suggested name:** `type` or `computeType`. Watch `type` — it is a reserved-like word in TS though not technically reserved. -- **Rationale:** Same logic as #12. - -### 13. `WorkspaceBaseEnvironment.filepath` — single-word run-together identifier — `model.ts:727` -- **Why weird:** `filepath` is run-together (one word in camelCase). TS/JS convention is `filePath`. The Go SDK and proto wire format both use `filepath` as one token, but in TS the camelCase rule should split it. -- **Category:** 3 (casing inconsistency), 14 (Go-style name). -- **Suggested name:** `filePath`. -- **Rationale:** Every other compound field in the type (`displayName`, `creatorUserId`, `createTime`, `lastUpdatedUserId`, `updateTime`, `isDefault`, `baseEnvironmentType`) uses camelCase. `filepath` is the only exception. - -### 14. `WorkspaceBaseEnvironment.message` — generic field name — `model.ts:739` -- **Why weird:** `message` is generic and could mean log message, error message, info text, user-facing description, etc. Doc says "Status message providing additional details about the environment status." `statusMessage` would be more precise. -- **Category:** 1 (vague), 15 (generic field name losing meaning). -- **Suggested name:** `statusMessage` or `statusDetails`. -- **Rationale:** Same as `DefaultBaseEnvironment.message` in clusterlibraries audit (§1.2). - -### 15. `WorkspaceBaseEnvironment.name` — generic field name, holds a resource path — `model.ts:723` -- **Why weird:** `name` is *not* a human-readable name in this API (there is a separate `displayName` for that, model.ts:725). The doc says: "The resource name of the workspace base environment. Format: workspace-base-environments/{workspace-base-environment}" — i.e. `name` is a slash-delimited *resource path*. Calling a path a `name` is a Google-AIP convention that confuses non-AIP-aware readers. -- **Category:** 6 (misleading — value is a path, not a name), 15 (generic field name), 19 (underspecified ID). -- **Suggested name:** `resourceName`, `path`, or `id`. Or document it with `(format: workspace-base-environments/...)` in the field name itself. -- **Rationale:** This pattern recurs across the package (every request type's `name` field is actually a path: `GetWorkspaceBaseEnvironmentRequest.name`, `DeleteWorkspaceBaseEnvironmentRequest.name`, `RefreshWorkspaceBaseEnvironmentRequest.name`, `GetDefaultWorkspaceBaseEnvironmentRequest.name`, `Operation.name`, `GetOperationRequest.name`). Eight different `.name` fields, each a path. - -### 16. `WorkspaceBaseEnvironment.creatorUserId` / `lastUpdatedUserId` — verb tense inconsistency — `model.ts:729, 733` -- **Why weird:** `creatorUserId` (noun: "the creator's id") vs `lastUpdatedUserId` (past-participle of verb-phrase: "the last-updated user's id"). The pair should agree. Symmetric pairs would be `creatorUserId`/`updaterUserId`, or `createdByUserId`/`lastUpdatedByUserId`. -- **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action verbs). -- **Suggested name:** Pick one form for both: `createdByUserId` / `updatedByUserId`, or `creatorUserId` / `updaterUserId`. -- **Rationale:** Internal consistency. As written, the noun↔verb mismatch reads oddly when sorted in IDE auto-complete. - -### 17. `CreateWorkspaceBaseEnvironmentRequest.workspaceBaseEnvironmentId` — 27-character optional string field — `model.ts:543` -- **Why weird:** Field name `workspaceBaseEnvironmentId` is the type name + `Id` suffix. On a `CreateWorkspaceBaseEnvironment*Request*` it is redundant — every field on a create request already pertains to a workspace base environment. Compare `requestId` (model.ts:548) on the same type, which is correctly scoped (`request`+`Id`, not `createWorkspaceBaseEnvironmentRequestRequestId`). -- **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `environmentId`, `id`, or `resourceId`. -- **Rationale:** Consumers writing `{workspaceBaseEnvironment: env, workspaceBaseEnvironmentId: 'foo'}` is awkward; `{environment: env, environmentId: 'foo'}` reads better. - -### 18. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:706` +### 11. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:706` - **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:706) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 711) is documented and even references `name`: "The name field is used to identify the environment to update." - **Category:** 19 (underspecified ID), 6 (misleading by omission). - **Suggested name:** Add JSDoc. The field is the resource name to update; say so. Or drop the field entirely if it duplicates `workspaceBaseEnvironment.name`. - **Rationale:** Inconsistent doc coverage in a generated file is a tell that the source proto field has no comment — should be fixed upstream. -### 19. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` +### 12. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` - **Why weird:** The mid-position word `Service` in `DatabricksServiceExceptionWithDetailsProto` describes a server-side architectural layer ("a service threw this exception"), not anything about the data the type carries. The type is a plain error payload with `errorCode`/`message`/`stackTrace`/`details`; no field references a "service". `Service` here mirrors the Java `*ServiceException` superclass pattern and the proto message name `DatabricksServiceExceptionWithDetails` — both server-internal concepts that have no meaning for a TS SDK consumer. Combined with the trailing `Proto` (codegen origin) the name is a stack of three architectural tags: `Service` (layer) + `Exception` (Java throwable) + `Proto` (wire format). - **Category:** proto-architectural-leak (mid-position `Service` is not the domain), 14 (Java-style naming), 20 (`Proto` suffix tautology). - **Suggested name:** `DatabricksErrorDetails`, `ServiceErrorPayload` is still leaky; prefer `ApiErrorDetails` or `RpcErrorDetails` if the gRPC framing is part of the public contract, otherwise just `ErrorDetails`/`DatabricksError`. Drop `Service`, `Exception`, and `Proto` together. @@ -147,67 +105,50 @@ ## Low severity -### 20. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` +### 13. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` - **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:741). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:564) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. - **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). - **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. - **Rationale:** Two representations of "is this the default" invite drift. -### 21. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:619` +### 14. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:619` - **Why weird:** Page-size doc says only "Default is 1000". No documented min/max, no behavior on `0`, no behavior on values exceeding server cap. - **Category:** 19 (underspecified). - **Suggested name:** Add doc bounds. - **Rationale:** Doc-only nit; not a name issue per se but worth flagging in a naming audit because `pageSize` is a known naming convention with known semantics that this doc partially undermines. -### 22. `ListWorkspaceBaseEnvironmentsResponse.workspaceBaseEnvironments` — long plural field — `model.ts:629` -- **Why weird:** Field name is 27 characters; type is a list of 27-character-typed items. Reading `resp.workspaceBaseEnvironments?.[0]?.workspaceBaseEnvironment...` is a chore. (No sub-field of this exact name; included to illustrate the chain length.) -- **Category:** 7 (overly verbose), 8 (redundant suffix — same as the type name pluralised). -- **Suggested name:** `environments` (the response type is already `ListWorkspaceBaseEnvironmentsResponse`, so the plural field doesn't need to re-state the qualifier). Wire stays `workspace_base_environments`. -- **Rationale:** Matches the `clusterlibraries`/`database` audit critique that list responses don't need to repeat their qualifier. - -### 23. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:545` +### 15. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:545` - **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. - **Category:** 19 (underspecified), 6 (slightly misleading). - **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. - **Rationale:** Doc-implied invariants that aren't in the type. -### 24. `WorkspaceBaseEnvironment.createTime` / `updateTime` — `time` suffix unclear vs `Timestamp`/`At` — `model.ts:731, 735` -- **Why weird:** Many TS APIs use `createdAt`/`updatedAt` (past-tense + `At` for timestamps) or `createTimestamp`/`updateTimestamp`. `createTime`/`updateTime` is Google-AIP/Go-style. Combined with `creatorUserId`/`lastUpdatedUserId` (finding #17) the verb tenses are mixed: noun `createTime`, past-participle `lastUpdated`. -- **Category:** 14 (Google-AIP/Go-style), 13 (verb tense inconsistency), 17 (inconsistent with `lastUpdated` sibling). -- **Suggested name:** `createdAt` / `updatedAt`, or align with `creator`/`lastUpdater` — pick one verb tense and apply across the type. -- **Rationale:** Stylistic; consistent with the broader codebase critique. - -### 25. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:725` +### 16. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:725` - **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:543) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. - **Category:** 19 (underspecified), 1 (slightly generic). - **Suggested name:** Keep but document constraints. - **Rationale:** Minor. -### 26. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:727` +### 17. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:727` - **Why weird:** Doc says "The WSFS or UC Volumes path to the environment YAML file." But the field is `string`. WSFS paths and UC Volume paths have different syntaxes (`/Workspace/...` vs `/Volumes/...`). The type permits any string. A union of the two path types would be more precise but probably not worth the porting effort. - **Category:** 19 (underspecified — the doc lists two valid path types but the type doesn't distinguish). -- **Suggested name:** Keep `filepath`/`filePath` (see #14), but document the allowed prefixes. +- **Suggested name:** Keep `filepath`, but document the allowed prefixes. - **Rationale:** Minor. --- ## Observation -### 27. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` +### 18. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` - **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. - **Category:** 12 (duplicate concept), 6 (misleading lineage signal). - **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. - **Rationale:** Generator-level; not actionable in TS alone, but worth recording. -### 28. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` +### 19. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` - **Why noteworthy:** The comment on `BaseEnvironmentType` references an internal proto path that public SDK consumers cannot see, cannot navigate to, and have no use for. It's a generator-cycle reminder to Databricks engineers that shouldn't have made it through the porting/codegen scrub. - **Category:** 6 (misleading — refers to a non-public artefact in a doc comment public users see). - **Suggested action:** Strip internal references from generated comments at codegen time. - **Rationale:** SDK hygiene; not a name issue but worth flagging in the audit since the comment is on a *public* type. --- - -## Fixed - -- #10 `WorkspaceBaseEnvironmentProvider.WORKSPACE_BASE_ENVIRONMENT_PROVIDER_UNSPECIFIED` (originally cited at `model.ts:518`): Fixed in regeneration on 2026-05-20 — the `WorkspaceBaseEnvironmentProvider` enum was removed from the source. -- #22 `WorkspaceBaseEnvironmentProvider` Admin/Databricks part-of-speech mix (originally cited at `model.ts:517`): Fixed in regeneration on 2026-05-20 — the `WorkspaceBaseEnvironmentProvider` enum and the `baseEnvironmentProvider` field on `WorkspaceBaseEnvironment` were removed from the source. diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index f427d60f..a24538c5 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -3,13 +3,13 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 **Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 48 +**Total weird names flagged:** 40 ## Summary | Severity | Count | | --- | --- | -| High | 13 | -| Medium | 22 | +| High | 12 | +| Medium | 15 | | Low | 9 | | Observation | 4 | @@ -75,19 +75,13 @@ - **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. - **Rationale:** Same as #9. -### 11. `RunStatus` enum has no `UNSPECIFIED` zero value — inconsistent with `LoggedModelStatus` — `src/v1/model.ts:26-37` -- **Why weird:** `LoggedModelStatus` carries `LOGGED_MODEL_STATUS_UNSPECIFIED` as its zero value (proto3 requirement). `RunStatus` does not — its five values are `RUNNING`, `SCHEDULED`, `FINISHED`, `FAILED`, `KILLED`, no `RUN_STATUS_UNSPECIFIED`. Sibling enums in the same file disagree on whether the proto3 zero-value sentinel surfaces. -- **Category:** 17 (inconsistency across enums in same file). -- **Suggested name:** Add `RunStatus.RUN_STATUS_UNSPECIFIED` for symmetry with `LoggedModelStatus`. (`ViewType` similarly lacks one but is filter-shaped, less critical.) -- **Rationale:** Proto3 mandates a zero-value enum member, so UNSPECIFIED is intentional — but it should appear uniformly across sibling enums so users can rely on the same pattern. - -### 12. `KILLED` enum value — `src/v1/model.ts:36` +### 11. `KILLED` enum value — `src/v1/model.ts:36` - **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." - **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). - **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. - **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). -### 13. `ViewType` enum — generic name + inconsistent field names for the same enum — `src/v1/model.ts:40-47` +### 12. `ViewType` enum — generic name + inconsistent field names for the same enum — `src/v1/model.ts:40-47` - **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). The same enum is used as `viewType` on `ListExperimentsRequest` (model.ts:405), `runViewType` on `SearchRunsRequest` (model.ts:886), and `viewType` on `SearchExperimentsRequest` (model.ts:789) — two fields named `viewType` and one named `runViewType` for the same enum. - **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). - **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Field name: pick one (`viewType` everywhere, or rename uniformly). @@ -95,97 +89,74 @@ ## Medium severity -### 14. `getMetricHistory` / `GetMetricHistoryRequest` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:314, client.ts:594` +### 13. `getMetricHistory` / `GetMetricHistoryRequest` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:314, client.ts:594` - **Why weird:** Type name `GetMetricHistoryRequest` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRunRequest`, `DeleteExperimentRequest`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". - **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). - **Suggested name:** `GetMetricValuesRequest` / `getMetricValues`, or `ListMetricHistoryRequest` / `listMetricHistory` (since it paginates). - **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. -### 15. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:973-979` +### 14. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:973-979` - **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModelRequest` and `LogModelRequest_Response`. The method `createLoggedModel` is the replacement. - **Category:** 6 (misleading — exported as if it were current). - **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModelRequest`, `LogModelRequest_Response`. - **Rationale:** A linter or IDE that reads `@deprecated` will warn users; a plaintext note in the markdown JSDoc body will not. -### 16. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` +### 15. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` - **Why weird:** Multiple types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. - **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). - **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. - **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. -### 17. `userId` deprecated — `src/v1/model.ts:101, 738` -- **Why weird:** Same problem as #17 but for `userId` on `CreateRunRequest.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. +### 16. `userId` deprecated — `src/v1/model.ts:101, 738` +- **Why weird:** Same problem as #15 but for `userId` on `CreateRunRequest.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. - **Category:** 6. -- **Suggested name:** Add `@deprecated`. Same as #16. - -### 18. `creationTimestampMs` / `lastUpdatedTimestampMs` vs `creationTime` / `lastUpdateTime` — same concept, two namings — `src/v1/model.ts:232-234, 576-578` -- **Why weird:** `Experiment` uses `lastUpdateTime` and `creationTime` (no unit suffix). `LoggedModelInfo` uses `creationTimestampMs` and `lastUpdatedTimestampMs` (with unit suffix). Both are Unix ms timestamps. Three things vary: (a) `Time` vs `Timestamp`, (b) `Update` vs `Updated`, (c) presence of `Ms` unit suffix. -- **Category:** 17 (inconsistency in field naming for the same concept), 3 (casing inconsistency), 9 (singular/plural-ish noun tense `Update` vs `Updated`). -- **Suggested name:** Pick one: `createdAt` / `updatedAt` (typical JS), or `creationTimeMs` / `lastUpdateTimeMs` (explicit unit). Match across `Experiment`, `LoggedModelInfo`, `RunInfo`, etc. -- **Rationale:** Three timestamp formats in one package means users guess which type uses which. - -### 19. `RunInfo` uses `startTime` / `endTime` (no unit suffix) — `src/v1/model.ts:742, 744` -- **Why weird:** Adds a fourth timestamp naming style to the package: bare `startTime` / `endTime` with no unit. JSDoc says "Unix timestamp of when the run started in milliseconds" — buried in prose. -- **Category:** 17 (inconsistency). -- **Suggested name:** `startTimeMs` / `endTimeMs`. Same as #18. - -### 20. `maxTimestampMillis` / `minTimestampMillis` — yet another timestamp suffix `Millis` — `src/v1/model.ts:194, 686` -- **Why weird:** Fifth style: `DeleteRunsRequest.maxTimestampMillis` and `RestoreRunsRequest.minTimestampMillis` use `Millis` suffix (not `Ms`, not unsuffixed). Same package. Five different naming choices for unix-ms timestamps: `creationTime`, `lastUpdateTime`, `startTime`/`endTime`, `creationTimestampMs`/`lastUpdatedTimestampMs`, `maxTimestampMillis`/`minTimestampMillis`. -- **Category:** 17 (inconsistency × 5), 3 (casing inconsistency — `Ms` vs `Millis`). -- **Suggested name:** Pick one suffix (`Ms` is common, `Millis` is rarer) and apply uniformly. -- **Rationale:** Same as #18. - -### 21. `creatorId: number` (not string) — `src/v1/model.ts:584` +- **Suggested name:** Add `@deprecated`. Same as #15. + +### 17. `creatorId: number` (not string) — `src/v1/model.ts:584` - **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." - **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). - **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. - **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). -### 22. `experimentId` vs `modelId` vs `runId` vs `creatorId` vs `userId` — five different ID fields with no shared naming pattern — `src/v1/model.ts` throughout -- **Why weird:** The package has multiple ID kinds that coexist on the same types. `Metric` (`model.ts:612`) has `modelId` AND `runId`. `LoggedModelInfo` has `modelId`, `experimentId`, `sourceRunId`, `creatorId`. No naming scheme says "this is the model's own ID vs a referenced model's ID". `sourceRunId` (the run that produced this model) and `runId` (the run owning this metric) — both are "run IDs" semantically but named differently. `creatorId` (`number`) is yet another shape (#22). -- **Category:** 19 (underspecified IDs coexist), 16 (`creatorId` is `number`, others `string`). -- **Suggested name:** Add prefix discipline: the model's own ID is `id` (or `modelId` everywhere); a referenced ID is `Id` (`sourceRunId`, `parentExperimentId`). Document the convention. -- **Rationale:** Today, every type has its own private convention; users must check each schema. - -### 23. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` +### 18. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` - **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. - **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). - **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). - **Rationale:** Heterogeneous string ID fields are debugging traps. -### 24. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` +### 19. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` - **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#10) buries the ID one level deep. - **Category:** 15 (generic field name losing meaning), 7 (verbose access). - **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). - **Rationale:** Awkward access pattern. -### 25. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:730, 572` +### 20. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:730, 572` - **Why weird:** Two fields named `experimentId`, two completely different relationships. On `RunInfo` the field connects the run to its parent experiment. On `LoggedModelInfo` it connects the model to its owning experiment. JSDoc only on one of them. - **Category:** 15 (generic name losing meaning across contexts). - **Suggested name:** Both are fine as `experimentId` if doc consistently says "parent experiment". The issue is uneven JSDoc. -### 26. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` +### 21. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` - **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:916`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). - **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParamsRequest`. - **Rationale:** The double-Log is jarring on read. -### 27. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` +### 22. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` - **Why weird:** `setExperimentTag(req: SetExperimentTagRequest)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTagsRequest)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 28. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` +### 23. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` - **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. - **Category:** Observation (URL design upstream). -### 29. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` +### 24. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 30. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 25. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -199,88 +170,67 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 31. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` +### 26. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` - **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. - **Category:** 15 (generic field name losing structure). -### 32. `datasetInputs` vs `modelInputs` on `RunInputs` — `src/v1/model.ts:759, 761` -- **Why weird:** `RunInputs.datasetInputs: DatasetInput[]` and `RunInputs.modelInputs: ModelInput[]`. The field name and the element type both carry `Input`. So a user reads `runInputs.datasetInputs[0].tags` — the word "input" appears three times in a single access path. -- **Category:** 20 (suffix tautology), 7 (verbose). -- **Suggested name:** `RunInputs.datasets: DatasetInput[]` and `RunInputs.models: ModelInput[]`. - -### 33. `Dataset.profile` vs `Dataset.schema` — both `string` — `src/v1/model.ts:131-142` -- **Why weird:** Both fields are typed `string` and named with generic English words. JSDoc shows the wire format is freeform JSON-stringified content. The field types don't help. -- **Category:** 15 (generic field name losing meaning), 6 (misleading: schema is freeform stringified JSON, not a real schema). -- **Suggested name:** `schemaJson` / `profileJson` (mirrors `LogModelRequest.modelJson`) so the user knows to JSON-parse them. Already see the pattern at `LogModelRequest.modelJson` (model.ts:512). - -### 34. `LogModelRequest.modelJson` — bare json string field — `src/v1/model.ts:508-513` +### 27. `LogModelRequest.modelJson` — bare json string field — `src/v1/model.ts:508-513` - **Why weird:** `LogModelRequest.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. - **Category:** Observation (an opaque blob field could carry doc). -### 35. `Dataset.digest` — `src/v1/model.ts:124` -- **Why weird:** `digest` is technical jargon (cryptographic hash). MLflow uses it; consumers may not. JSDoc: "Dataset digest, e.g. an md5 hash". Could be `contentHash` or `fingerprint`. -- **Category:** 5 (cryptic abbreviation — `digest` is industry-specific). - ## Low severity -### 36. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:753` +### 28. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:753` - **Why weird:** `RunInfo.lifecycleStage` JSDoc says: "Current life cycle stage of the experiment : OneOf("active", "deleted")". But this is a `Run`'s `lifecycleStage`, not the experiment's. Same field on `Experiment.lifecycleStage` (model.ts:230) is correctly described. - **Category:** 6 (misleading doc — wrong entity name in description). - **Suggested name:** Fix doc to say "Current life cycle stage of the run". -### 37. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` +### 29. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` - **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #8. The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 38. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 30. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 39. `FileInfo` itself is a generic name — `src/v1/model.ts:248` +### 31. `FileInfo` itself is a generic name — `src/v1/model.ts:248` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. -### 40. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` +### 32. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` - **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. - **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). - **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). -### 41. `HttpCallOptions` — `src/v1/utils.ts:15` +### 33. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). - **Category:** 17 (collision risk with `CallOptions`). -### 42. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` +### 34. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` - **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) - **Category:** Observation (dead export). -### 43. `PACKAGE_SEGMENT` constant in `client.ts:161` — `src/v1/client.ts:161` +### 35. `PACKAGE_SEGMENT` constant in `client.ts:161` — `src/v1/client.ts:161` - **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. - **Category:** 17 (inconsistency in identifier case across the file). - **Suggested name:** `packageSegment` per TS conventions. -### 44. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:162` +### 36. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:162` - **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. - **Category:** 1 (generic name leaking into observability). ## Observations (non-actionable but noted) -### 45. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 494, 622` +### 37. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 494, 622` - **Note:** JSDoc on `Dataset.name`, `LogMetricRequest.datasetName`, `Metric.datasetName` includes the literal example `"fantastic-elk-3"` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. -### 46. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-130` +### 38. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-130` - **Note:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. -### 47. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +### 39. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` - **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. -### 48. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` +### 40. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` - **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). - -## Fixed - -- #11 `GetLoggedModelsRequest` being the only request type with a `Request` suffix (originally cited at `src/v1/model.ts:314, client.ts:578`): Fixed in regeneration on 2026-05-20 — all request types now uniformly carry the `Request` suffix; the plural batch type was also removed entirely. -- #16 `GetLoggedModels` method returns request type with `Request` suffix (originally cited at `src/v1/client.ts:577-608`): Fixed in regeneration on 2026-05-20 — the universal `Request` suffix on every request type makes the original method/type inconsistency moot, and the `getLoggedModels` plural method was removed. -- #29 Method names `getLoggedModels` / type `GetLoggedModelsRequest` mismatch (originally cited at `src/v1/client.ts:577`): Fixed in regeneration on 2026-05-20 — the plural batch method and its `GetLoggedModelsRequest` type were removed entirely. -- #49 `getLoggedModels` (batch get) has no `*Iter` (originally cited at `src/v1/client.ts:577`): Fixed in regeneration on 2026-05-20 — the plural batch endpoint no longer exists. diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index 5359d8e1..b1ef5abc 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -3,14 +3,14 @@ **Path:** `packages/externallineage/src/v1/` **Versions audited:** v1 **Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 22 +**Total weird names flagged:** 17 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 7 | -| Low | 8 | +| High | 4 | +| Medium | 5 | +| Low | 7 | | Observation | 1 | ## High severity @@ -27,119 +27,89 @@ - **Suggested name:** Use a TS discriminated union with `$case` directly (no outer `tpe` field): `ExternalLineageRelationshipObject = {$case: 'table', table: ...} | {$case: 'path', path: ...} | ...`. If the wrapper must stay, name the field `kind` or `objectType`. - **Rationale:** TS allows `type` as a property name, so the cryptic `tpe` solves a problem TS does not have. -### 3. `objectInfo` field of type `ExternalLineageRelationshipObject` — `src/v1/model.ts:216` -- **Why weird:** Field is named `objectInfo` but is typed as `ExternalLineageRelationshipObject` (no `Info` in the type). The convention drift means a reader sees `objectInfo: ExternalLineageRelationshipObject` and has to mentally reconcile the two. Note the JSDoc immediately starts talking about a `object_info.table.name=...` query parameter — so on the wire, the prefix really is `object_info`, but in TS the type doesn't end in `Info`. -- **Category:** 1 (vague `Info` suffix), 8 (redundant suffix — `Info` adds nothing), 17 (field-name does not match type-name). -- **Suggested name:** `object: ExternalLineageRelationshipObject`. (Wire serialisation stays `object_info` to match the API.) -- **Rationale:** `Info` is generator filler; the type already describes itself. Field/type-name agreement reduces cognitive load. - -### 4. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` +### 3. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` - **Why weird:** Two top-level types share the prefix `ExternalLineage` but mean different things: `ExternalLineageInfo` is a union-of-info "row" that may describe a table, a file, a model version, or an external metadata object plus the edge metadata; `ExternalLineageRelationship` is the edge itself (id, source, target, columns, properties). The JSDoc on `ExternalLineageInfo` says "Lineage response containing lineage information of a data asset" while one of its fields is `externalLineageInfo?: ExternalLineageRelationship` — i.e., an "info" type that *contains* an "info" field whose type ends in `Relationship`. Five fields ending in `Info` (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`, `externalLineageInfo`) on a type also ending in `Info`. This is the heart of the naming muddle. - **Category:** 1 (vague `Info` everywhere), 6 (misleading — `externalLineageInfo` is the edge metadata, not "info about external lineage"), 8 (redundant suffix), 12 (duplicate concept — `ExternalLineageInfo.externalLineageInfo` of type `ExternalLineageRelationship`). - **Suggested name:** `ExternalLineageInfo` → `LineageNode` or `LineageEntry`. `externalLineageInfo` field → `relationship: ExternalLineageRelationship`. The four neighbour fields (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`) become `table`, `file`, `model`, `externalMetadata`. - **Rationale:** "Info" is the generator's escape hatch for "I don't know what to call this". The current shape forces a reader to deduce that one of the `Info` fields is structurally different from the others (it's the edge, not a node). Concrete names break the muddle. -### 5. Mixed `Info` / `Relationship` / `Object` suffix vocabulary — across `src/v1/model.ts` +### 4. Mixed `Info` / `Relationship` / `Object` suffix vocabulary — across `src/v1/model.ts` - **Why weird:** The package mixes three competing nouns for related concepts: `*Info` (LineageTableInfo, LineageFileInfo, LineageModelVersionInfo, LineageExternalMetadataInfo, ExternalLineageInfo), `*Relationship` (ColumnRelationship, ExternalLineageRelationship, plus six `ExternalLineageRelationship*` sub-types), and `*Object` (ExternalLineageRelationshipObject). All three trade off in the same conceptual space. A reader cannot predict which suffix a new sibling type will get. - **Category:** 8 (redundant suffix), 12 (duplicate concept), 17 (inconsistent action-vocabulary). - **Suggested name:** Pick one: prefer no suffix where the noun is concrete (`Table`, `Path`, `ModelVersion`, `ExternalMetadata`), `Relationship` for edges, and drop `Info`/`Object` entirely. - **Rationale:** Three suffixes for related types make the vocabulary feel arbitrary. The Google TypeScript style guide encourages "names should reflect what something is, not its scaffolding". -### 6. `ColumnRelationship` ambiguous source/target — `src/v1/model.ts:42-45` -- **Why weird:** Both fields are typed as `string | undefined` with no JSDoc. A reader of `{source?: string, target?: string}` has no way to know that these are *column names* (not full table.column references, not column IDs). The enclosing `ExternalLineageRelationship` has its own `source` and `target` of type `ExternalLineageRelationshipObject` — so the inner `source`/`target` of `ColumnRelationship` shadow the outer pair and add no description. -- **Category:** 1 (vague `source`/`target`), 6 (misleading — looks like the outer source/target but is column-level), 15 (generic field names lose meaning), 19 (underspecified ID — is this a column name? a path? a column lineage handle?). -- **Suggested name:** `sourceColumn?: string` / `targetColumn?: string` with JSDoc clarifying the format. -- **Rationale:** Two fields with the same names as their parent confuse the reader. Sister packages would not name a child the same as its parent. - ## Medium severity -### 7. `Client` class — `src/v1/client.ts:45` +### 5. `Client` class — `src/v1/client.ts:45` - **Why weird:** Class literally named `Client` at the top level of the package's API surface, re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. Same problem as every other audited package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. -### 8. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` +### 6. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. - **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. -### 9. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` +### 7. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` - **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. - **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). - **Suggested name:** `makeHttpRequest` or inline at the call sites. - **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. -### 10. `HttpCallOptions` — `src/v1/utils.ts:15` +### 8. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 11. `flattenQueryParams` — `src/v1/utils.ts:123` +### 9. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. - **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). - **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. - **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). -### 12. `LineageTableInfo.name` — `src/v1/model.ts:201` -- **Why weird:** Field literally called `name` with JSDoc "Name of Table." (capitalised "Table" mid-sentence). The neighbour fields are `catalogName` and `schemaName` — so the type has `(name, catalogName, schemaName)`. Inconsistent: two fields use the `*Name` suffix while the table name itself drops it. Most readers will reach for `tableName`. -- **Category:** 1 (vague — `name` of what?), 15 (generic field name losing meaning), 17 (inconsistent within the same type — `name` vs `catalogName` vs `schemaName`). -- **Suggested name:** `tableName: string` (and JSDoc punctuation fix). -- **Rationale:** Within `LineageTableInfo`, the canonical name for "the table's name" is `tableName`. Mixing `name`, `catalogName`, `schemaName` makes the table's own name look special when it isn't. - -### 13. `ExternalLineageRelationshipExternalMetadata.name` — `src/v1/model.ts:131` -- **Why weird:** Field is `name?: string` with no JSDoc. Type is named to encode "external metadata object on the external-lineage edge". Given the wider package uses `name` for tables, models, external metadata, paths-via-`url`, the field gives up domain meaning to be terse. -- **Category:** 1 (vague `name`), 15 (generic field name), 19 (underspecified ID — for `ExternalMetadata`, the `name` is actually a fully-qualified resource path including the metastore). -- **Suggested name:** `externalMetadataName: string` with a JSDoc clarifying the expected format (mirror the `ExternalMetadata.name` JSDoc on the externalmetadata package). -- **Rationale:** `name` is the most overloaded field name in the SDK. Spelling out the entity removes the ambiguity. - ## Low severity -### 14. `ExternalLineageRelationshipPath.url` — `src/v1/model.ts:155` -- **Why weird:** Field is `url?: string` on a type called `*Path`. A `Path` whose only field is a `url` — two different nouns for the same thing. Compare with `LineageFileInfo.path` and `ExternalLineageRelationshipPath.url`: the file `path` and the lineage-path `url` carry the same kind of value. -- **Category:** 1 (vague), 6 (misleading — `Path` and `url` are not the same), 12 (duplicate concept — `path` and `url` interchangeable across the package), 17 (inconsistent vocabulary). -- **Suggested name:** Either rename the type to `LineagePathObject` and call the field `path: string`, or rename the field to keep the type name: `path?: string`. -- **Rationale:** Pick one of `path` or `url` for storage location strings and stick to it. - -### 15. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +### 10. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` - **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. - **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). - **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) - **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. -### 16. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 11. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). - **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. - **Rationale:** Type name should reflect the dominant content; current name is misleading. -### 17. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +### 12. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` - **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. - **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). - **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. - **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. -### 18. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 80-92, 104, 134-178, 202-235` +### 13. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 80-92, 104, 134-178, 202-235` - **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. - **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). - **Suggested name:** `rawBody` + `result` (or `parsedResponse`). - **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. -### 19. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` +### 14. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` - **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). - **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. - **Rationale:** Avoid forking the same identifier across two layers in the same scope. -### 20. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` +### 15. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 21. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` +### 16. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. @@ -147,15 +117,15 @@ ## Observations -### 22. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name -The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #4. +### 17. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #3. - **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). ## Domain glossary - `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. - `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). - `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #15. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #10. - `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). - `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index 101fce8c..0c568a05 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -257,11 +257,3 @@ Primary themes: JSDoc. --- - -## Fixed - -- #5 `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` (originally cited at model.ts:9): Fixed in regeneration on 2026-05-20 — enum member removed from `IsolationMode`. -- #8 `OneLakeEventQueue` type as part of four-queue inconsistency set (originally cited at model.ts:18, 28, 186, 240): Fixed in regeneration on 2026-05-20 — `OneLakeEventQueue` type and the `providedOnelake`/`managedOnelake` FileEventQueue cases were removed, reducing the set to three providers; the remaining three-way inconsistency is retracked as finding #4. -- #12 `OneLakeEventQueue` (no Azure/Fabric prefix) (originally cited at model.ts:240): Fixed in regeneration on 2026-05-20 — type removed entirely. -- #13 `Pubsub` casing inside `GcpPubsub` (originally cited at model.ts:186): Fixed in regeneration on 2026-05-20 — duplicate of finding #8 (now #6 in renumbered audit); collapsed into the single `GcpPubsub` casing entry. -- #15 `providedOnelake` / `managedOnelake` case key spelling (originally cited at model.ts:176, 182): Fixed in regeneration on 2026-05-20 — `OneLake` cases removed from `FileEventQueue` provided/managed unions. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index 4894498f..d039371c 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -3,14 +3,14 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 35 +**Total weird names flagged:** 26 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 12 | -| Low | 10 | +| High | 8 | +| Medium | 5 | +| Low | 9 | | Observation | 4 | ## High severity @@ -39,31 +39,25 @@ - **Suggested name:** `ExternalAsset` or `ExternalEntity` (the type already has a `entityType` field describing what shape of external thing it is). Alternatively, embrace the proto-canonical name with `ExternalMetadataObject`. - **Rationale:** Reading `const x: ExternalMetadata = ...` does not communicate that `x` is a single named external asset. The JSDoc fix ("external metadata object") betrays that the type name needs help to read as a noun. Worth raising upstream. -### 5. `ExternalMetadata.name` (and `req.name` in Get/Delete/Update) — `src/v1/model.ts:45,40,81` -- **Why weird:** Field literally called `name` on an entity that uses `name` as the unique identifier in REST path segments (`/api/2.0/lineage-tracking/external-metadata/${req.name}`). The entity also has both `name` AND `id` (line 71) — two different identifier-shaped fields with no doc differentiation beyond "Unique identifier of the external metadata object" on `id` and "Name of the external metadata object" on `name`. -- **Category:** 1 (vague — `name` is the canonical too-generic field name), 12 (duplicate concept — `name` and `id` both feel identity-shaped), 19 (underspecified ID). -- **Suggested name:** Either rename to `objectName` / `assetName` and document the format constraint, or drop `id` if `name` is the canonical key. JSDoc must explain when callers use `name` vs `id`. -- **Rationale:** Co-existence of `name?: string` and `id?: string` with no semantic separation in docs is a recipe for caller confusion. The URL routing uses `name` as the path segment, suggesting `name` is the canonical key; `id` is the implementation-detail UUID. The type does not communicate this. +### 5. `ExternalMetadata.name` vs. `ExternalMetadata.id` — `src/v1/model.ts:45,71` +- **Why weird:** The entity has both `name` AND `id` — two different identifier-shaped fields with no doc differentiation beyond "Unique identifier of the external metadata object" on `id` and "Name of the external metadata object" on `name`. The URL routing uses `name` as the path segment (`/api/2.0/lineage-tracking/external-metadata/${req.name}`), suggesting `name` is the canonical key; `id` is the implementation-detail UUID. +- **Category:** 12 (duplicate concept — `name` and `id` both feel identity-shaped), 19 (underspecified ID). +- **Suggested name:** Drop `id` if `name` is the canonical key, or document in JSDoc when callers use `name` vs `id`. +- **Rationale:** Co-existence of `name?: string` and `id?: string` with no semantic separation in docs is a recipe for caller confusion. The type does not communicate which is canonical. -### 6. `ExternalMetadata.id` — `src/v1/model.ts:71` -- **Why weird:** Field `id` exists alongside `name`. JSDoc says "Unique identifier" — but `name` is also a unique identifier (the URL path key). Bare `id` without further qualification gives no hint that this is the system-generated UUID vs. the human-readable name. Also: bare `id: string` is rule-19 underspecified — no format constraint visible at the type. -- **Category:** 1 (vague), 12 (duplicate concept with `name`), 19 (underspecified ID). -- **Suggested name:** `objectId` / `assetId` / `externalMetadataId`, or drop entirely if `name` is the canonical key. -- **Rationale:** Two unique identifiers on one type with no doc differentiation forces every caller to read the API docs to know which to use. The type should name the difference. - -### 7. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` +### 6. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` - **Why weird:** Type name carries the API version suffix `V2`, but the enclosing file is already `v1/model.ts` and the package is mounted at `./v1`. Version is encoded twice — once in the directory, once in the type. If the user later imports a hypothetical `v2/`, they would get `V3`? Versioning the entity name within the version namespace creates an off-by-one collision risk. - **Category:** 8 (redundant suffix — version is in the path), 20 (type-suffix tautology between version-in-path and version-in-name), 14 (Go/proto-style — Go SDK carries the `V2` per RPC name; TS doesn't need it). - **Suggested name:** `ListExternalMetadataResponse` (drop `V2`). - **Rationale:** The directory is the namespace. Embedding the wire RPC version into the TS type name leaks an internal detail of the generator. If the package later gets a `v2/` directory, every type there ends up `V3` (one ahead of the dir), which is worse than the original problem. -### 8. `Client.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:70,102,124,154,190,212` +### 7. `Client.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:75,110,135,168,207,229` - **Why weird:** Every public method on `Client` ends with `V2`, but the directory is `v1/`. The version suffix is wire-RPC-name leakage (the upstream API is `ExternalMetadataServiceV2.Create`, hence `createExternalMetadataV2`). User code reads `client.createExternalMetadataV2(...)` for a method on a `v1/` import — confusing on first read. - **Category:** 8 (redundant suffix), 14 (Go/proto-style name leak), 20 (type/version suffix tautology). - **Suggested name:** `createExternalMetadata`, `deleteExternalMetadata`, etc. (drop `V2`). -- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #7; generator-wide concern. +- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #6; generator-wide concern. -### 9. `Client` — `src/v1/client.ts:41` +### 8. `Client` — `src/v1/client.ts:41` - **Why weird:** Class literally named `Client` at the top level of the package's surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code collide on import: `import {Client} from '@databricks/sdk-externalmetadata'` and `import {Client} from '@databricks/sdk-catalogs'` both fight for the same identifier. - **Category:** 1 (vague — `Client` is the most generic name), 15 (generic name). - **Suggested name:** `ExternalMetadataClient` (matches the package name and avoids collisions on combined imports). @@ -71,73 +65,31 @@ ## Medium severity -### 10. `ExternalMetadata.systemType: SystemType` — `src/v1/model.ts:47` -- **Why weird:** Type-suffix tautology — field `systemType` of type `SystemType` on a type called `ExternalMetadata`. Reads `externalMetadata.systemType: SystemType` — three "type"s in one declaration. -- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). -- **Suggested name:** `system: SystemType` (would read `externalMetadata.system`). -- **Rationale:** When the field's type already encodes "type", the field itself doesn't need to. Compare: `externalMetadata.system` reads cleaner than `externalMetadata.systemType`. - -### 11. `ExternalMetadata.entityType` — `src/v1/model.ts:49` -- **Why weird:** Field `entityType` is typed `string` (free-form) rather than `EntityType` (an enum). Pairs awkwardly with `systemType: SystemType` two lines above — one is enumerated, the other is freeform string. The user has no idea what valid `entityType` values are without consulting external docs. -- **Category:** 1 (vague), 6 (misleading — `Type` suffix implies a closed set, but it's freeform), 15 (generic field name losing meaning), 17 (inconsistency — `systemType` is closed enum, `entityType` is open string). -- **Suggested name:** `entityKind` (less enum-implying), or define an `EntityType` enum if a closed set exists. -- **Rationale:** A field named `xxxType: string` strongly suggests an enum without one. JSDoc says "Type of entity within the external system" — but for Tableau the entity might be a dashboard/workbook; for Kafka, a topic. Closed-set values would help; absent that, the name should not over-promise. - -### 12. `ExternalMetadata.url` — `src/v1/model.ts:51` +### 9. `ExternalMetadata.url` — `src/v1/model.ts:51` - **Why weird:** Casing of acronym. The codebase uses `url` (lowercase) consistently for the property, but the Web platform/standards canonical is `URL` (uppercase). Compare to `userAgent` (camelCase) and `URLSearchParams` (Web standard SCREAMING). Internal inconsistency between `url` (field) and `URLSearchParams` (function/class). - **Category:** 3 (acronym casing). - **Suggested name:** Keep `url` (TS convention), but acknowledge the JS-ecosystem split. - **Rationale:** The JS world is split here — Node, browsers, and the URL spec all use `URL` for the class and `url` for member fields. Internal consistency within this file is preserved (`url` everywhere); the rule is conventional, not broken. -### 13. `ExternalMetadata.description` — `src/v1/model.ts:53` -- **Why weird:** Field `description` is on the entity but is "User-provided free-form text description" per JSDoc — i.e., not a generated description, not a vendor description, but specifically a description set by the metadata owner. The plain name `description` does not convey "you supply this". -- **Category:** 1 (vague — `description` is the canonical too-generic field name). -- **Suggested name:** `userDescription` or keep `description` and rely on JSDoc. -- **Rationale:** Minor — `description` is the universal expectation. JSDoc is doing the work. Listed for completeness. - -### 14. `ExternalMetadata.columns: string[]` — `src/v1/model.ts:55` -- **Why weird:** `columns` is typed as `string[]` (just names), but the JSDoc reads "List of columns associated with the external metadata object". A `Column` in Unity Catalog terms is a structured `{name, type, nullable, ...}` object — calling a list of column names `columns` invites the reader to expect structure that is not there. -- **Category:** 6 (misleading — `columns` implies structured objects, is just names), 15 (generic field name losing meaning). -- **Suggested name:** `columnNames: string[]` (matches the contents). -- **Rationale:** When the field type and field name disagree about whether the values are objects or strings, the type wins (it has to compile); the name is the bug. `columnNames` is unambiguous. - -### 15. `ExternalMetadata.properties` — `src/v1/model.ts:57` -- **Why weird:** Field name is the literal type-system-builtin reserved word for "object members" (`Object.properties`, `props`, etc). The map's role is "user-defined custom metadata" but the name `properties` is the most generic possible for a `Record`. Also: `properties` co-exists with `metastoreId`, `owner`, `createdBy`, etc., which are *also* properties. -- **Category:** 1 (vague), 6 (misleading — every other field is also a "property"), 10 (reserved-word-adjacent — `properties` clashes with `Object.properties`). -- **Suggested name:** `tags`, `labels`, `attributes`, or `customProperties` — whatever the API doc calls them. -- **Rationale:** `properties` on a `Record` is bag-of-strings naming. A user reading `externalMetadata.properties.foo` cannot tell if `foo` is intrinsic or user-extended. - -### 16. `ExternalMetadata.owner` — `src/v1/model.ts:59` +### 10. `ExternalMetadata.owner` — `src/v1/model.ts:59` - **Why weird:** Field `owner: string | undefined` with no hint of format. JSDoc says "Owner of the external metadata object" — owner is a Unity Catalog principal (user, group, or service principal). Common sister-package convention names this `owner` consistently, but a user has no idea what string format to put (`alice@example.com`? `users/alice`? a UUID?). Same problem applies to `createdBy` (line 65) and `updatedBy` (line 69). - **Category:** 1 (vague), 19 (underspecified ID — what format is the principal?). - **Suggested name:** Keep `owner` but document format. Or `ownerPrincipal`, matching other UC packages. - **Rationale:** Bare `owner: string` is the canonical UC principal-as-string pattern across the SDK, but the type does not communicate format. Minor — sister-package convention is the same. Listed for visibility. -### 17. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` +### 11. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` - **Why weird:** Bare `metastoreId: string | undefined` — a UUID identifier on a UC metastore, but the type does not hint at the format. Idiomatic across the SDK; here mentioned only for rule-19 completeness. Also note: this field is "Unique identifier of parent metastore" but `parent` is not named — the metastore relationship is communicated via the `metastoreId` field alone, not a `parent` field per AIP-160. - **Category:** 19 (underspecified ID — `string` doesn't tell you it's a UUID). - **Suggested name:** Keep `metastoreId` (canonical across SDK). - **Rationale:** SDK-wide pattern; field name is fine. Listed for completeness. -### 18. `ExternalMetadata.createTime` / `updateTime` — `src/v1/model.ts:63,67` -- **Why weird:** Verb-tense / part-of-speech inconsistency with `createdBy` and `updatedBy` (lines 65, 69). Times use the imperative ("create"); user fields use past-tense ("created"). A consistent set would be `createdAt` + `createdBy` and `updatedAt` + `updatedBy`. The Go SDK uses `create_time`/`update_time` on the wire; TS does not have to follow. -- **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action-tense pair). -- **Suggested name:** `createdAt: Temporal.Instant` + `updatedAt: Temporal.Instant` (preserves the `createdBy`/`updatedBy` past-tense pair). -- **Rationale:** Sibling fields should agree on tense. `createTime`/`createdBy` mixes imperative + past-tense for one event. JS/TS canon is `createdAt`/`updatedAt` (e.g., NoSQL drivers, Sequelize, TypeORM, Prisma). - -### 19. `ExternalMetadata.updateTime` vs. `Client.updateExternalMetadataV2` — `src/v1/model.ts:67, src/v1/client.ts:212` -- **Why weird:** "Update" as a verb is overloaded — it names both an action (the PATCH method) and a state field (the last-modified timestamp). On the same entity, reading `externalMetadata.updateTime` while a request to `updateExternalMetadata` is in flight is confusing. -- **Category:** 12 (duplicate concept), 17 (verb noun-vs-action collision). -- **Suggested name:** `modifiedAt`/`modifiedBy` for the state, leave `update` for the action. -- **Rationale:** Separating timestamp ("modified") from operation ("update") prevents the reader from conflating "this was just updated" with "this is being updated right now". - -### 20. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` +### 12. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` - **Why weird:** Field name `updateMask` doesn't say what kind of mask. In context the mask describes "which fields to patch". The Google AIP-134 convention names this `updateMask`; the TS-idiomatic name would describe contents (`fieldsToUpdate`, `patchedFields`, `paths`). - **Category:** 1 (vague), 14 (Google-AIP-style name). - **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. - **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. -### 21. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 13. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. @@ -145,79 +97,73 @@ ## Low severity -### 22. `ListExternalMetadataResponseV2.externalMetadata: ExternalMetadata[]` — `src/v1/model.ts:95` -- **Why weird:** Singular/plural mismatch. The field holds an array but is named `externalMetadata` (singular). Convention is plural for arrays (e.g., `connections: Connection[]` in sister packages). Compare: `nextPageToken` is singular because it's a single token. -- **Category:** 9 (singular/plural mismatch), 20 (type-suffix tautology — `externalMetadata: ExternalMetadata[]`). -- **Suggested name:** `items: ExternalMetadata[]` or `externalMetadataObjects: ExternalMetadata[]` or `assets`. Wire stays `external_metadata`. -- **Rationale:** "Metadata" is a mass noun (uncountable), which is why the generator left it singular. A plural-aware name like `items` or `assets` reads naturally. - -### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 14. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 24. `Call` type and `call` variable — `src/v1/client.ts:80,107,130,169,228` +### 15. `Call` type and `call` variable — `src/v1/client.ts:85,115,141,183,245` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 25. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:71-95, 103-118, etc.` +### 16. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:75-104, 110-129, etc.` - **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. -### 26. `pageReq` — `src/v1/client.ts:194` +### 17. `pageReq` — `src/v1/client.ts:211` - **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). - **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). - **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. -### 27. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +### 18. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` - **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. - **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). - **Suggested name:** `requestBody: string | ReadableStream`. - **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. -### 28. `flattenQueryParams` — `src/v1/utils.ts:123` +### 19. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 29. `readAll(body)` — `src/v1/utils.ts:40` +### 20. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. -### 30. `HttpCallOptions` — `src/v1/utils.ts:15` +### 21. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 31. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` -- **Why weird:** The Zod schema constant carries the `V2` mid-position infix just like the type it parses (#7) and the client methods (#8). The directory is `v1/`, so `V2` here is wire-RPC-name leakage embedded inside a TS identifier that has no business advertising the upstream RPC version. Architectural leak — the generator copied the proto `ResponseV2` name straight through into the parser symbol. +### 22. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` +- **Why weird:** The Zod schema constant carries the `V2` mid-position infix just like the type it parses (#6) and the client methods (#7). The directory is `v1/`, so `V2` here is wire-RPC-name leakage embedded inside a TS identifier that has no business advertising the upstream RPC version. Architectural leak — the generator copied the proto `ResponseV2` name straight through into the parser symbol. - **Category:** 14 (Go/proto-style name leak — wire `V2` infix on a TS identifier), 8 (redundant suffix — version is in the path), 20 (type-version suffix tautology between version-in-path and version-in-name). - **Suggested name:** `unmarshalListExternalMetadataResponseSchema` (drop `V2`). -- **Rationale:** The schema is local to `v1/model.ts`; nothing in this file disambiguates a `V2` schema from a `V1` schema because no `V1` schema exists. Same generator-wide concern as #7 and #8 — propagating the wire RPC version into TS identifiers leaks an architectural detail of the upstream service. +- **Rationale:** The schema is local to `v1/model.ts`; nothing in this file disambiguates a `V2` schema from a `V1` schema because no `V1` schema exists. Same generator-wide concern as #6 and #7 — propagating the wire RPC version into TS identifiers leaks an architectural detail of the upstream service. ## Observations -### 32. Identifier doubling for path + UUID -The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5 and #6. +### 23. Identifier doubling for path + UUID +The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5. -### 33. Action-verb conventions in `Client` +### 24. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. -### 34. Acronym casing +### 25. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 35. `externalmetadata` lowercase package name +### 26. `externalmetadata` lowercase package name The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). @@ -230,11 +176,11 @@ The package directory is `externalmetadata` (one word, no separator), but every - `entity` / `entityType` — the kind of object *within* the external system (a Tableau workbook vs. a dashboard; a Kafka topic vs. a partition). Open string, not enumerated. - `BROWSE`, `MANAGE`, `MODIFY`, `CREATE_EXTERNAL_METADATA` — UC privileges referenced in method JSDoc but not modeled as types. - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `properties` — user-defined `Record` (see #15 for naming concern). +- `properties` — user-defined `Record`. - `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. ## File coverage -- `src/v1/model.ts` (222 lines): read fully. -- `src/v1/client.ts` (252 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (17 lines): read fully. +- `src/v1/model.ts` (221 lines): read fully. +- `src/v1/client.ts` (271 lines): read fully. +- `src/v1/utils.ts` (150 lines): read fully. +- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index 1a826793..b89c39ee 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -15,7 +15,7 @@ computes a feature on a schedule and writes results to an offline or online store). Feature transformations are a discriminated union over 13 aggregation functions and 3 data sources (Delta, Kafka, request-time), composed under three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 51 +**Total weird names flagged:** 45 (0 fixed, 45 still present after rescan on 2026-05-26 post regen #156) --- @@ -30,50 +30,44 @@ three flavors of time window (continuous, tumbling, sliding). | 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-635 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 636 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | | 6 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | | 7 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 179, 758, 572, 566, 344, 467, 84, 92, 716, 727, 819, 825 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | -| 8 | `AggregationFunction.operation` discriminator field | model.ts:61 | field | Medium | 1 Vague/generic, 15 Generic field names | The outer interface is `AggregationFunction`; the field holding the function variant is named `operation`. So `aggFn.operation.$case === 'avg'` reads okay, but in JSDoc comments and call sites the relationship is unclear: "operation" is a generic word; the value is *the function itself*. Could be `function` (matching the parent type's role in `Function.aggregationFunction.operation`) or `kind`. | -| 9 | `TimeWindow.windowType` field | model.ts:769 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | -| 10 | `MaterializedFeature.destination` field | model.ts:538 | field | Medium | 1 Vague/generic, 15 Generic field names | Carries `offlineStoreConfig` or `onlineStoreConfig`. "Destination" is okay but ambiguous (could be a table name, a URL, a cluster). `store` or `target` would be more domain-specific; `storageDestination` would also work. | -| 11 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:288, 317, 319 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | -| 12 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:293, 317 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #35). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | -| 13 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:307, 253, 463 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | -| 14 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:300, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | -| 15 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:246, 317 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | -| 16 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:251, 319 | field pair | Medium | 12 Duplicate concepts | Same pattern as #15. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | -| 17 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:456, 317, 246 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | -| 18 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:461, 319, 251 | field set | High | 12 Duplicate concepts | Same as #17 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | -| 19 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 268, 777 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | -| 20 | `ColumnIdentifier.variantExprPath` | model.ts:161 | field | High | 5 Cryptic abbreviations, 6 Misleading names | "variantExprPath" — short for "variant expression path". The JSDoc clarifies it is a dot-prefixed column path (e.g., `value.trip_details.pickup_zip`). The `variantExpr` prefix is meaningless to a TS reader; the path is not a "variant expression" in any TS sense. Rename `path` or `columnPath`. | -| 21 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | -| 22 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:376 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | -| 23 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:535 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts) — verbose. | -| 24 | `MaterializedFeature.featureName` (full Unity Catalog name) vs `MaterializedFeature.tableName` (full UC table name) | model.ts:537, 551 | field pair | Medium | 6 Misleading names, 19 Underspecified IDs | Both are "full names". JSDoc says `featureName` is "The full name of the feature in Unity Catalog" (i.e., three-part `catalog.schema.name`) and `tableName` is "The fully qualified Unity Catalog path to the table". They look the same shape but reference different objects. `featureFullName` / `tableFullName` would type themselves. Compare to `Feature.fullName` (model.ts:286) where the type name is the disambiguator. | -| 25 | `Feature.fullName` (the feature's three-part name) | model.ts:286 | field | Medium | 6 Misleading names, 19 Underspecified IDs | "fullName" without context is ambiguous (full as opposed to what?). The JSDoc says "three-part name (catalog, schema, name)". A `name: string` carrying a fully-qualified identifier is a common UC pattern; `qualifiedName` or `threePartName` would be self-describing. Same critique applies to `DeleteFeatureRequest.fullName` (path), `GetFeatureRequest.fullName`, `DeltaTableSource.fullName`. | -| 26 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:226, 236, 231 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | -| 27 | `KafkaConfig.bootstrapServers` | model.ts:424 | field | Low | (none) | Standard Kafka term. Fine. | -| 28 | `SubscriptionMode.$case === 'assign'` | model.ts:737 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | -| 29 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:750 | field | Low | (none) | Fine, matches Kafka SDK. | -| 30 | `extraOptions` field (`Record`) | model.ts:434 | field | Medium | 1 Vague/generic | "Extra" is meaningless — extras compared to what? The JSDoc says it's "Catch-all for miscellaneous options". Rename `kafkaOptions` or `additionalOptions`. Fine if you accept "extra" as conventional escape-hatch idiom. | -| 31 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:623 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | -| 32 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:598, 604, 612 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | -| 33 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:562, 538 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | -| 34 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:315 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | -| 35 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | -| 36 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | -| 37 | `JobContext.jobId` JSDoc typo | model.ts:411 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | -| 38 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | -| 39 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:290-293 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | -| 40 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:242-246 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | -| 41 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | -| 42 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | -| 43 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 44 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | -| 45 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | -| 46 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely per #6). | -| 47 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #46. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | -| 48 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | -| 49 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | -| 50 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #48. | -| 51 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#46-50) clears this automatically. | +| 8 | `TimeWindow.windowType` field | model.ts:769 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | +| 9 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:288, 317, 319 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | +| 10 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:293, 317 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #33). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | +| 11 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:307, 253, 463 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | +| 12 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:300, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | +| 13 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:246, 317 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | +| 14 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:251, 319 | field pair | Medium | 12 Duplicate concepts | Same pattern as #13. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | +| 15 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:456, 317, 246 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | +| 16 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:461, 319, 251 | field set | High | 12 Duplicate concepts | Same as #15 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | +| 17 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 268, 777 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | +| 18 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 19 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:376 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | +| 20 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:535 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts) — verbose. | +| 21 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:226, 236, 231 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | +| 22 | `KafkaConfig.bootstrapServers` | model.ts:424 | field | Low | (none) | Standard Kafka term. Fine. | +| 23 | `SubscriptionMode.$case === 'assign'` | model.ts:737 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | +| 24 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:750 | field | Low | (none) | Fine, matches Kafka SDK. | +| 25 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:623 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | +| 26 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:598, 604, 612 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | +| 27 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:562, 538 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | +| 28 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:315 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | +| 29 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | +| 30 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | +| 31 | `JobContext.jobId` JSDoc typo | model.ts:411 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | +| 32 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | +| 33 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:290-293 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | +| 34 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:242-246 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | +| 35 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | +| 36 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | +| 37 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 38 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 39 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 40 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely per #6). | +| 41 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #40. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | +| 42 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | +| 43 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | +| 44 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #42. | +| 45 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#40-44) clears this automatically. | --- @@ -337,13 +331,7 @@ entity over a lifetime ContinuousWindow". The name gives no domain hint. `LatestColumnValue` would name the behavior. (Same critique as `Credential` in the credentials audit.) -### M6. `MaterializedFeature.destination` is a generic word - -Carries an `OfflineStoreConfig | OnlineStoreConfig` union. The English word -"destination" suggests a URL or path. Domain word: `target`, `store`, or -`storage`. - -### M7. JSDoc references stale field names +### M6. JSDoc references stale field names - "Use Feature.entity instead" (model.ts:243) — actual field is `entities`. - "Use Feature.entity instead" (model.ts:453) — same typo. @@ -352,7 +340,7 @@ Carries an `OfflineStoreConfig | OnlineStoreConfig` union. The English word - "Use Function.aggregation_function.time_window" (model.ts:297) — references snake_case wire name in TS-facing JSDoc. -### M8. `executeCall` vs `executeHttpCall` +### M7. `executeCall` vs `executeHttpCall` Same as sibling packages. Two `execute*` verbs. @@ -515,7 +503,3 @@ who know the upstream API; opaque otherwise. Every type, field, enum value, and method enumerated above is accounted for. --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index b514e63c..2875057a 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -74,7 +74,7 @@ ## Findings -### 1. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) +### 1. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) — *Still* **Symbols:** Every value in both enums (model.ts:11–23, 28–44). @@ -117,7 +117,7 @@ unilateral change here would diverge from sibling packages. --- -### 2. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) +### 2. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) — *Still* **Symbols:** `OnlineStore_State.FAILING_OVER` (model.ts:23), `STARTING`, `DELETING`, `UPDATING` (model.ts:13, 17, 21) vs. `STOPPED`, `AVAILABLE` @@ -133,7 +133,7 @@ fine under finding 1. **Pass at the TS level**, flag at the wire level. --- -### 3. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) +### 3. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) — *Still* **Symbol:** `DeleteOnlineTableRequest.onlineTableName` (model.ts:59), wire field `online_table_name` (the field appears in the URL path, not JSON). @@ -171,7 +171,7 @@ divergence. --- -### 4. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) +### 4. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) — *Still* **Symbol:** `OnlineStore.name` (model.ts:84). JSDoc: "The name of the online store. This is the unique identifier for the online store." @@ -198,53 +198,7 @@ arbitrary strings. --- -### 5. `OnlineStore.creator` is an email, not a name — category 1 (Vague/generic) and category 17 (Inconsistent action verbs) - -**Symbol:** `OnlineStore.creator` (model.ts:86). JSDoc: "The email of the -creator of the online store." - -**Issue:** A field called `creator` typically holds a principal name or ID -(Go's `creator string` carries ambiguity by convention). Other packages in -this SDK use `createdBy` for principal IDs and `creatorEmail` when they want -to explicitly note the email shape. Concrete examples to align with: - -- `catalogs/v1` (CatalogInfo) uses `owner` and `metastoreId` — different - conventions. -- `database/v1` uses `creator` for an email too, in identical shape. - -The audit category 17 hits this because `Create*Request` operations elsewhere -return a creator-id field as `createdBy` (`apps/v1`, `pipelines`) — the -mismatch is *cross-package* not within-this-package. - -**Suggested:** rename to `creatorEmail` (descriptive) or `createdByEmail` -(matches the broader SDK passive form). Flag for SDK-wide cleanup; do not -fix in isolation. **Pass with a recommendation.** - ---- - -### 6. `OnlineStore.creationTime` vs. `…At` pattern — category 17 (Inconsistent action verbs) and category 7 (Overly verbose) - -**Symbol:** `OnlineStore.creationTime` (model.ts:88). Type: `Temporal.Instant`. - -**Issue:** The SDK has *three* conventions for "moment of creation": -`creationTime`, `createTime`, and `createdAt`. Within the wider SDK: - -- `OnlineStore.creationTime` (featurestore) — this file. -- `OnlineTable` (onlinetables) — no creation-time field, but `pipelines/v2` - uses `creationTime`. -- Many newer services use `createdAt` (`apps`, `customllms`). - -Picking one is out of scope; the **`Time` suffix on a `Temporal.Instant` is -mildly tautological** (the type encodes "moment"). The `At` form -(`createdAt`) is more idiomatic for JS/TS (JS-Joda, dayjs, Date-fns all use -`At` patterns; React/Node ecosystems converge here). - -**Suggested:** `createdAt` for cross-SDK consistency. **Flag for generator, -not a unilateral fix.** - ---- - -### 7. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) +### 5. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) — *Still* **Symbol:** `OnlineStore.capacity?: string` (model.ts:92). JSDoc: "The capacity of the online store. Valid values are "CU_1", "CU_2", "CU_4", @@ -267,11 +221,11 @@ current shape — bare `string` with a JSDoc note — provides no compile-time help. **Flag for SDK-wide policy on open enums** (categories 1 + 6). Also: "CU" is unexplained (probably "Compute Unit"). Audit category 5 -(cryptic abbreviation) — see finding 8. +(cryptic abbreviation) — see finding 6. --- -### 8. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) +### 6. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) — *Still* **Symbol:** `OnlineStore.capacity` valid values `"CU_1"`–`"CU_8"` (model.ts:91). @@ -287,7 +241,7 @@ Valid values: …". --- -### 9. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* +### 7. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* — *Still* **Symbol:** `OnlineStore.readReplicaCount?: number` (model.ts:94). JSDoc: "The number of read replicas for the online store. Defaults to 0." @@ -298,7 +252,7 @@ naming bug per se — flag JSDoc. --- -### 10. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) +### 8. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) — *Still* **Symbol:** `OnlineStore.usagePolicyId?: string` (model.ts:96). @@ -311,29 +265,7 @@ referring to a usage policy defined in the budget-policy service." --- -### 11. `PublishSpec.onlineStore` is a *name* (string), not an `OnlineStore` — category 15 (Generic field names losing meaning) and category 16 (Field contradicting type domain) - -**Symbol:** `PublishSpec.onlineStore?: string` (model.ts:101). JSDoc: "The -name of the target online store." - -**Issue:** The field is a *string identifier* of an online store, but the -field name is `onlineStore` — which to a reader implies the *whole struct*. -This is exactly the kind of misleading name flagged by category 16. Compare -to `PublishTableRequest.sourceTableName` (model.ts:110) — explicit `…Name` -suffix. - -**Suggested:** rename to `onlineStoreName` to match `sourceTableName`, -`onlineTableName`, and the wire field `online_store` (or -`online_store_name`). This is a *symbol-level* inconsistency *within the -same file* and is the single highest-confidence fix in this audit. The Go -SDK uses `OnlineStore` (capitalised, but a string), so this is a port-time -correctness opportunity, not a coordination issue with upstream Go fields. - -**P1 fix candidate.** - ---- - -### 12. `PublishSpec` is vague — category 1 (Vague/generic) +### 9. `PublishSpec` is vague — category 1 (Vague/generic) — *Still* **Symbol:** `PublishSpec` (model.ts:99). @@ -351,7 +283,7 @@ which has more room because it lives in the `featurestore` Go package. --- -### 13. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) +### 10. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) — *Still* **Symbols:** `PublishTableRequest.publishSpec.onlineTableName`, `PublishTableResponse.onlineTableName` (model.ts:103, 117). @@ -375,14 +307,14 @@ different doc strings: --- -### 14. `PublishTableResponse.pipelineId` — *pass* +### 11. `PublishTableResponse.pipelineId` — *pass* — *Still* Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. No issue. --- -### 15. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* +### 12. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* — *Still* **Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` (model.ts:126). @@ -393,7 +325,7 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 16. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) +### 13. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) — *Still* **Symbol:** `Client.publishTable` (client.ts:212). JSDoc: "Publish features." @@ -416,7 +348,7 @@ the URL — but diverges from Go. **Pass on the name, flag the JSDoc.** --- -### 17. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) +### 14. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) — *Still* **Symbols:** `Client.deleteOnlineTable` (client.ts:117, featurestore) vs. `Client.deleteOnlineTable` (client.ts:108, onlinetables). @@ -441,7 +373,7 @@ the *request types* are also identically named but field-incompatible. --- -### 18. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* +### 15. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* — *Still* **Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and `onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the @@ -450,14 +382,14 @@ Google AIP-134 update-mask vocabulary. **Pass.** --- -### 19. `Client` class name — category 1 (Vague/generic) — *pass* +### 16. `Client` class name — category 1 (Vague/generic) — *pass* — *Still* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** --- -### 20. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) +### 17. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) — *Still* **Symbol:** `PACKAGE_SEGMENT` (client.ts:41). @@ -473,7 +405,7 @@ do not fix in isolation.** --- -### 21. `userAgent` / `httpClient` / `host` / `logger` — *pass* +### 18. `userAgent` / `httpClient` / `host` / `logger` — *pass* — *Still* Standard private field names. Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported @@ -481,14 +413,14 @@ type `HttpClient`). **Pass.** --- -### 22. `readAll` — *pass* +### 19. `readAll` — *pass* — *Still* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 23. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* +### 20. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* — *Still* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. Note however the *file* mixes `build…`, @@ -497,7 +429,7 @@ seven functions. Not unique to this package. **Pass.** --- -### 24. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* +### 21. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -509,7 +441,7 @@ package qualifies. **Pass on package consistency.** --- -### 25. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) +### 22. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) — *Still* **Symbol:** `Client.listOnlineStores` (client.ts:160). @@ -537,21 +469,21 @@ and update JSDocs to drop "Feature" (already redundant since the package is --- -### 26. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* +### 23. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 27. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* +### 24. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* — *Still* `pipelineId` correctly camelCases the two-letter "ID"; `creator` is a plain word. **Pass.** --- -### 28. `OnlineStore_State` — model.ts:9 +### 25. `OnlineStore_State` — model.ts:9 — *Still* **Why:** `Parent_Nested` underscore-joined identifier is a literal translation of a proto nested-type path into the TS symbol name. The @@ -573,9 +505,9 @@ namespace. --- -### 29. `PublishSpec_PublishMode` — model.ts:27 +### 26. `PublishSpec_PublishMode` — model.ts:27 — *Still* -**Why:** Same `Parent_Nested` proto-namespace leak as finding 28. The +**Why:** Same `Parent_Nested` proto-namespace leak as finding 25. The identifier reads as "PublishSpec's PublishMode" — the enclosing-type prefix is a verbatim port of the proto nested-type name, and the file acknowledges this with the same eslint-disable comment. @@ -594,31 +526,6 @@ already reads (`publishMode: PublishMode`). No wire change. ## Cross-package notes (per audit instructions) -### `OnlineStore` concept vs. `features.OnlineStoreConfig` - -The `features/v1` package defines `OnlineStoreConfig` (features/v1/model.ts:617) -which holds `catalogName`, `schemaName`, `tableNamePrefix`, `onlineStoreName` -— a *configuration* for an online store. This `featurestore.OnlineStore` -holds the *actual store* (with name, state, capacity, etc.). Two related -but distinct types live in two packages: - -- `features.OnlineStoreConfig.onlineStoreName: string` — references a store - by name. -- `featurestore.OnlineStore.name: string` — is the store's identifier. -- `featurestore.PublishSpec.onlineStore: string` — also references a store - by name (but with no `…Name` suffix — see finding 11). - -**Recommendation:** harmonise. Either: -1. All references to an online-store identifier use `onlineStoreName` - (so rename `PublishSpec.onlineStore` to `onlineStoreName` — matches - finding 11). -2. Or all references use `onlineStore` and the type is `string` with a - marker (e.g. `type OnlineStoreName = string`). - -Option 1 is cheaper. **P1 cross-package alignment fix.** - ---- - ### `DeleteOnlineTableRequest` name collision with `onlinetables/v1` Already covered in finding 3. Two distinct request types share the same @@ -637,7 +544,7 @@ Friction-heavy. **Strong recommendation:** rename `DeletePublishedOnlineTableRequest` (it deletes a table created by `publishTable`) — or rename `featurestore.deleteOnlineTable` method to `deletePublishedOnlineTable` and follow with the request type. Aligns with -finding 17. +finding 14. --- @@ -652,25 +559,3 @@ approaches (string enum vs. discriminated union). Plus there is no `SNAPSHOT` case in `onlinetables`. **Flag for upstream protocol alignment.** --- - -## Summary (counts) - -- **Critical / cross-package consistency:** 2 findings (#11 - `PublishSpec.onlineStore` should be `onlineStoreName`; #3 - `DeleteOnlineTableRequest` shape collision with `onlinetables`). -- **High (style guide violations / proto-architectural leaks):** 4 - findings (#1 enum SCREAMING casing; #20 `PACKAGE_SEGMENT` casing; #28 - `OnlineStore_State` proto-nested infix; #29 `PublishSpec_PublishMode` - proto-nested infix). -- **Medium (naming clarity, JSDoc drift):** 9 findings (#4, #5, #7, #8, - #10, #12, #16, #17, #25). -- **Low / project-wide convention notes (generator-level):** 3 findings - (#6, #9, #24). -- **Pass / acceptable as-is:** 11 findings (#2, #13, #14, #15, #18, #19, - #21, #22, #23, #26, #27 — partial pass with notes). - -**Total flagged findings: 29** distinct items across the audit categories -(several findings touch multiple categories). Many issues are -generator-emitted boilerplate inherited from the Go SDK; the cleanest local -fixes are findings 11, 16 (JSDoc), 17, 25 (JSDoc), 28, 29, and the -cross-package alignments noted above. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index 97a1d4ee..f900c483 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -4,14 +4,14 @@ **Versions audited:** v2 **Inferred domain:** File operations on Databricks storage. v2 is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 24 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 8 | -| Low | 6 | +| High | 6 | +| Medium | 4 | +| Low | 4 | | Observation | 2 | ## High severity @@ -55,43 +55,15 @@ export interface FileInfo { - **Why weird:** Both types describe a file-or-directory metadata snapshot, with overlapping fields: - Both have `path`, `fileSize`. - - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings — see #4). - - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names — see #5). + - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings). + - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names). - `DirectoryEntry.name` (component name) — exists only in `DirectoryEntry`. Two distinct types because they come from two distinct REST APIs (modern listDirectoryContents vs legacy listStatus / getStatus). The client exposes both, side-by-side, with no docstring telling callers which to use. - **Category:** 12 (duplicate concepts), 17 (cross-API naming clash), 6 (misleading — `DirectoryEntry` may be a file). -- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #6). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. +- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #4). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. - **Rationale:** Two identical-shape types with different field names are a maintenance hazard. -### 4. `isDir` vs `isDirectory` — same concept, two casings — `src/v2/model.ts:77,118,170` - -```ts -DirectoryEntry.isDirectory?: boolean // modern API -FileInfo.isDir?: boolean // legacy DBFS -GetStatusRequest_Response.isDir?: boolean // legacy DBFS -``` - -- **Why weird:** Same yes/no flag, two abbreviations of "is directory". `isDir` is a cryptic 3-letter abbreviation; `isDirectory` is the full word. They appear in three sibling types in the same file. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistent across same package). -- **Suggested name:** `isDirectory` everywhere (the modern form). Wire mapping is one line in the unmarshal schema. -- **Rationale:** Public TS field names should not abbreviate "directory" to "dir" when the rest of the SDK spells it out. - -### 5. `lastModified` (number-ms-epoch) vs `lastModified` (HTTP-date string) vs `modificationTime` — `src/v2/model.ts:79,110,122,157,174` - -```ts -DirectoryEntry.lastModified?: number // ms since epoch -DownloadFileResponse.lastModified?: string // HTTP-date (RFC 7231) -FileInfo.modificationTime?: number // ms since epoch -GetFileMetadataResponse.lastModified?: string // HTTP-date -GetStatusRequest_Response.modificationTime?: number // ms since epoch -``` - -- **Why weird:** Three problems in one cluster. (a) Same FIELD NAME (`lastModified`) holds two completely different value domains — milliseconds-since-epoch as `number` (in `DirectoryEntry`) AND HTTP-date `'Wed, 21 Oct 2015 07:28:00 GMT'` as `string` (in `DownloadFileResponse`, `GetFileMetadataResponse`). (b) Same WIRE CONCEPT (ms since epoch) has two field names — `lastModified` in modern, `modificationTime` in legacy. (c) Time-suffix convention is inconsistent: `lastModified` (past participle), `modificationTime` (noun + `Time` suffix). -- **Category:** 9 (singular/plural / cross-shape mismatch), 15 (generic name loses meaning), 16 (field contradicts type domain — same name, two value types), 17 (inconsistent naming). -- **Suggested name:** Use distinct names for distinct domains. For ms-since-epoch: `lastModifiedMs` or `lastModifiedAt: number` (ms-since-epoch convention). For HTTP-date strings: `lastModifiedHttpDate: string` or model as a typed brand. Pick ONE — `modificationTime` should be dropped. -- **Rationale:** A consumer doing `if (resp.lastModified > someTimestamp)` will silently break depending on which API they came from. - -### 6. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` +### 4. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` ```ts // files/v2: file/directory metadata snapshot @@ -112,7 +84,7 @@ export interface FileInfo { ... } - **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #3 — `FileEntry`). - **Rationale:** `FileInfo` is so generic three different domains felt entitled to use it. -### 7. `CreateRequest` returns a `handle` (not the created file) — `src/v2/model.ts:32-43` +### 5. `CreateRequest` returns a `handle` (not the created file) — `src/v2/model.ts:32-43` ```ts export interface CreateRequest { @@ -129,7 +101,7 @@ export interface CreateRequest { - **Suggested name:** `OpenWriteStreamRequest` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). - **Rationale:** Method name should reflect action; right now `create` and `createDirectory` look like sibling actions when they are entirely different (create-handle vs create-resource). -### 8. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:301,677` +### 6. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:321,730` ```ts async list(req: ListStatusRequest, ...): Promise // legacy DBFS @@ -143,7 +115,7 @@ async listDirectoryContents(req: ListDirectoryContentsRequest, ...): Promise @@ -169,22 +141,7 @@ export function buildHttpRequest(method, url, headers, signal?, body?): HttpRequ - **Suggested name:** Collapse to one helper (`sendRequest`), let it return the raw `HttpResponse`, and have the caller buffer/stream as needed. Or, if both must exist: `sendAndBuffer` (returns buffered body) and `sendAndStream` (returns raw response). - **Rationale:** Three functions doing nearly the same thing with names that differ in verb is a recipe for mis-imports. -### 11. `path` as the only field in 5 request types — `src/v2/model.ts:32,63,160,213,224` - -```ts -CreateRequest: { path?: string; overwrite?: boolean } -DeleteRequest: { path?: string; recursive?: boolean } -GetStatusRequest: { path?: string } -ListStatusRequest: { path?: string } -MkDirsRequest: { path?: string } -``` - -- **Why weird:** Five sibling types whose distinguishing identity is the type name (`CreateRequest`, `DeleteRequest`, etc.), not the field. The common field is just `path: string`. In TS, all five types are structurally compatible — `GetStatusRequest` is assignable to `ListStatusRequest` and vice versa; both are assignable to `MkDirsRequest`. A caller can confidently pass `getStatus(req)` and a typo-narrowed `req: ListStatusRequest` and TS won't complain (structural typing). -- **Category:** 1 (vague — `path` for everything), 6 (misleading — structural compat collapses semantic distinctions), 17 (inconsistent — sometimes called `path`, sometimes `filePath`, sometimes `directoryPath`). -- **Suggested name:** Use the discriminated field names from the modern API: `dbfsPath` everywhere on the legacy types; or split into `CreateRequest.filePath` (because `Create` is a write-stream open, ie file) and `MkDirsRequest.directoryPath`. Helps callers see "this is a path to a file" vs "this is a path to a directory." -- **Rationale:** Structural typing makes the five types interchangeable — a name change is the cheapest defence. - -### 12. `MoveRequest.sourcePath` / `MoveRequest.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` +### 9. `MoveRequest.sourcePath` / `MoveRequest.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` ```ts export const marshalMoveRequestSchema: z.ZodType = z @@ -203,27 +160,7 @@ export const marshalMoveRequestSchema: z.ZodType = z - **Suggested name:** Acceptable as-is (these are clearer than `path1`/`path2`). Flag only the inconsistency with the rest of the DBFS surface. - **Rationale:** The inconsistency is upstream; the TS port should match. -### 13. `contents` field has three different types across model — `src/v2/model.ts:108,246,281,274` - -```ts -DownloadFileResponse.contents?: ReadableStream | undefined // line 108 -PutRequest.contents?: Uint8Array | undefined // line 246 -// ReadRequest_Response.data?: Uint8Array | undefined (named 'data')// line 274 — same concept, different name -UploadFileRequest.contents?: ReadableStream | undefined // line 281 -ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 208 -``` - -- **Why weird:** "Contents" is overloaded across the model: - - `DownloadFileResponse.contents`: file bytes as a stream. - - `UploadFileRequest.contents`: file bytes as a stream. - - `PutRequest.contents`: file bytes as a `Uint8Array` (no streaming on the legacy API). - - `ReadRequest_Response.data`: file bytes (chunked read) as a `Uint8Array` — same concept as `PutRequest.contents` but called `data`. - - `ListDirectoryResponse.contents`: directory entries (array of `DirectoryEntry`). -- **Category:** 6 (misleading), 12 (duplicate concept — `contents` and `data`), 15 (generic name loses meaning — what's in "contents"?), 17 (inconsistent — same concept, three names). -- **Suggested name:** `body: ReadableStream` for stream payload, `bodyBytes: Uint8Array` for buffered, `entries: DirectoryEntry[]` for list responses (matching the `next_page_token` pattern of "entries + next token"). Rename the read response `data` field to `bytes` to make the buffer obvious. -- **Rationale:** The `contents` of a directory and the `contents` of a file are different domains. Type system will not catch a programmer who reads `.contents.length` expecting bytes and gets `DirectoryEntry[].length`. - -### 14. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-274` +### 10. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-274` ```ts // ReadRequest_Response: @@ -233,37 +170,9 @@ ListDirectoryResponse.contents?: DirectoryEntry[] | undefined // line 20 `bytesRead` (count) and `data` (the bytes) refer to the same byte slice. `bytesRead` is the LENGTH; `data` is the BUFFER. Cleaner: `bytes: Uint8Array` and `bytesRead: number` (count); even better, drop `bytesRead` since `data.byteLength` is the same value. -### 15. `ifUnmodifiedSince` — verb-as-noun field — `src/v2/model.ts:101,149` - -```ts -ifUnmodifiedSince?: string | undefined; -``` - -Mirrors the HTTP header name exactly. Faithful to RFC 9110, but as a TS field name `ifUnmodifiedSince` is a conditional, not a value. `unmodifiedSinceHeader: string` or `notModifiedSince: string` is more idiomatic. Acceptable as-is (HTTP convention), flagged only as observation. - -### 16. `range` (HTTP byte range header value) — same — `src/v2/model.ts:95,143` - -```ts -range?: string | undefined; -``` - -Field name `range` is overloaded (range of numbers? date range?). The doc clarifies "range of bytes to retrieve" — name could be `byteRange` or `rangeHeader`. - ## Low severity -### 17. `directoryPath` vs `path` — inconsistent across methods — `src/v2/model.ts:26,48,128,180` - -The modern Files API consistently uses `directoryPath` / `filePath`. The legacy DBFS uses just `path` even when the value is known to be a directory (`MkDirsRequest.path`) or file (`CreateRequest.path`). Choose: prefix every path with the kind, OR drop the prefix everywhere. - -### 18. `recursive` (DeleteRequest) — field name does not tell you what it does — `src/v2/model.ts:67` - -```ts -recursive?: boolean | undefined; -``` - -A `recursive: true` on a `DeleteRequest` could mean "follow symlinks", "descend into subdirs", etc. JSDoc clarifies "Whether or not to recursively delete the directory's contents." Name OK in context; would prefer `recursivelyDeleteContents: boolean` for self-documentation, but `recursive` is conventional. - -### 19. `overwrite` — same — `src/v2/model.ts:36,248,283` +### 11. `overwrite` — same — `src/v2/model.ts:36,248,283` ```ts overwrite?: boolean | undefined; @@ -271,7 +180,7 @@ overwrite?: boolean | undefined; Appears in `CreateRequest`, `PutRequest`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `CreateRequest` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. -### 20. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,183,194,200` +### 12. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,183,194,200` ```ts contents?: DirectoryEntry[] | undefined; @@ -281,11 +190,11 @@ nextPageToken?: string | undefined; // OK JSDoc strings reference the wire name (`next_page_token`), but the TS field is `nextPageToken`. The doc accurately reflects the wire — flagged because cross-referencing a wire name in user-facing JSDoc is confusing. Should reference the TS field name (`nextPageToken`). -### 21. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` +### 13. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. -### 22. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` +### 14. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` ```ts const PACKAGE_SEGMENT = { @@ -298,25 +207,10 @@ SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. Thi ## Observations -### 23. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` +### 15. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) -### 24. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` +### 16. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. - -## Fixed - -- #1 `Read` (originally cited at `src/v2/model.ts:254`): Fixed in regeneration on 2026-05-20 — renamed to `ReadRequest`; verb-as-noun and reserved-word collision concerns resolved by the `Request` suffix. -- #2 Verb-as-noun cluster `Move`, `Put`, `Delete`, `Close`, `Create`, `MkDirs`, `AddBlock`, `GetStatus`, `ListStatus` (originally cited at `src/v2/model.ts:15-264`): Fixed in regeneration on 2026-05-20 — all renamed to `MoveRequest`, `PutRequest`, `DeleteRequest`, `CloseRequest`, `CreateRequest`, `MkDirsRequest`, `AddBlockRequest`, `GetStatusRequest`, `ListStatusRequest`; the `Request` suffix removes the verb-as-noun ambiguity and the `Delete` keyword collision. -- #17 v1 `Client` constructor allows `host` to be undefined (originally cited at `src/v1/client.ts:21`): Fixed in regeneration on 2026-05-20 — v1 package deleted. -- #18 v1 `UploadRequest.contents` is `ReadableStream` but v2 `UploadFileRequest.contents` is bare `ReadableStream` (originally cited at `src/v1/model.ts:11`, `src/v2/model.ts:281`): Fixed in regeneration on 2026-05-20 — v1 package deleted; v2 standalone with single typing. -- #28 v2 `index.ts` exports `FileInfo` but `v1/index.ts` does NOT export dangling types (originally cited at `src/v1/index.ts:3`): Fixed in regeneration on 2026-05-20 — v1 package deleted. -- #30 `readAll` is duplicated across v1 and v2 (originally cited at `src/v1/utils.ts:23` and `src/v2/utils.ts:40`): Fixed in regeneration on 2026-05-20 — v1 package deleted. -- #32 `HttpCallOptions` duplicated across files (originally cited at `src/v1/utils.ts:13`, `src/v2/utils.ts:15`): Fixed in regeneration on 2026-05-20 — v1 package deleted. -- #33 v1 `encodeFilePath` vs v2 `encodeMultiSegmentPath` (originally cited at `src/v1/utils.ts:36`, `src/v2/utils.ts:156`): Fixed in regeneration on 2026-05-20 — v1 package deleted. -- #34 `Move.sourcePath` / `Move.destinationPath` could be `source` / `destination` (originally cited at `src/v2/model.ts:233-236`): Fixed in regeneration on 2026-05-20 — duplicate of #12; pruned. -- #37 v1 `Client.upload` returns `Promise` but JSDoc says "does not retry" (originally cited at `src/v1/client.ts:33-36`): Fixed in regeneration on 2026-05-20 — v1 package deleted. - - \ No newline at end of file diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index f258f501..64ec5b08 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -232,24 +232,6 @@ _None._ #### F8.1 — `primaryMetric: string` (MEDIUM) - **Where:** `model.ts:34`. See F1.2. -#### F8.2 — `registerTo: string` (MEDIUM) -- **Where:** `model.ts:46`. -- **Why flagged:** `registerTo` is a verb-phrase masquerading as a - noun field. The JSDoc clarifies it is "the fully qualified path - of a Unity Catalog model … used to store the best model." But the - name `registerTo` doesn't tell you *what* to register or *as what*. -- **Suggestion:** Rename to `modelRegistrationPath` / - `modelTargetName` / `registeredModelName`. Cross-cutting if other - packages share the pattern. - -#### F8.3 — `maxRuntime: number` (LOW) -- **Where:** `model.ts:40`. -- **Why flagged:** Units are missing from the field name. JSDoc says - minutes, but `maxRuntime: number` doesn't. -- **Suggestion:** Rename to `maxRuntimeMinutes`, or change the type - to a duration string (`ISO 8601` PT1H, etc.) if the API supports - it. Common SDK convention: suffix the unit on the field name. - --- ### 9. Untyped string for closed enum @@ -267,24 +249,13 @@ _None._ ### 10. `*Path` fields contradicting type domain -#### F10.1 — `*Path` fields holding three-part catalog names (MEDIUM) -- **Where:** `model.ts:21 (trainDataPath), 52 (predictionDataPath), - 63 (futureFeatureDataPath)`. -- **Why flagged:** "Path" suggests a hierarchical workspace or - filesystem path. The values here are Unity Catalog three-part - names (`catalog.schema.table`), which are *not* slash-delimited - paths. The `experimentPath` field on the same type *is* a path - (workspace path). Domain dissonance within the same type. -- **Suggestion:** Rename `*Path` → `*Table` / - `*TableFullName` / `*TableName`. E.g. `trainingDataTable`, - `predictionDataTable`. Or use UC's term: `*Reference` - (`trainingDataReference`). +_None._ --- ### 11. Proto / architectural leaks -#### 11.1 — `ForecastingExperiment_State` — `model.ts:6` +#### F11.1 — `ForecastingExperiment_State` — `model.ts:6` - **Why flagged:** The `Foo_Bar` underscore identifier is a verbatim proto-generated nested-enum form (`ForecastingExperiment.State` in the original proto). The underscore form leaks the proto IDL @@ -297,7 +268,7 @@ _None._ proto's `Foo.Bar`. The flat camel/Pascal form removes the IDL artifact and the eslint-disable. -#### 11.2 — "Public RPC" in JSDoc — `client.ts:112` +#### F11.2 — "Public RPC" in JSDoc — `client.ts:112` - **Why flagged:** The JSDoc `/** Public RPC to get forecasting experiment */` exposes the server-side classification (`Public` vs `Internal` RPC) and the transport term `RPC` to SDK @@ -350,9 +321,9 @@ generic experiment but uses the same term and the same ID name. | 5 | Overly verbose | 5 | | 6 | Go-style `Waiter` pattern | 1 | | 7 | Reserved-word collisions | 1 | -| 8 | Generic field names | 3 | +| 8 | Generic field names | 1 | | 9 | Untyped string for closed enum | 1 | -| 10 | `*Path` fields contradicting domain | 1 | +| 10 | `*Path` fields contradicting domain | 0 | | 11 | Proto / architectural leaks | 2 | | OVERLAP | forecasting vs experiments | 2 | @@ -368,21 +339,10 @@ generic experiment but uses the same term and the same ID name. 2. **F4.1 / F7.1:** Rename waiter `done()` method to `isTerminal()` (or `isDone()`) to signal that it is a server-poll predicate, not iterator state. -3. **F10.1:** Rename `*Path` fields that hold Unity Catalog - three-part names to `*Table` (e.g. `trainDataPath → - trainingDataTable`, `predictionDataPath → - predictionsTable`, `futureFeatureDataPath → - futureFeaturesTable`). Distinguishes them from `experimentPath` - which is a real workspace path. -4. **F8.2:** Rename `registerTo` to - `registeredModelName` (or `modelRegistrationTarget`). The - verb-phrase field name is confusing. -5. **F8.3:** Rename `maxRuntime` → `maxRuntimeMinutes` to embed - units in the name. -6. **F1.2 / F9.1:** Introduce string-literal union types for +3. **F1.2 / F9.1:** Introduce string-literal union types for `primaryMetric` and `forecastGranularity`. Improves discoverability and type safety. -7. **F5.1 / F5.2:** Drop the redundant `Forecasting` token from +4. **F5.1 / F5.2:** Drop the redundant `Forecasting` token from type names where the package qualifier already conveys domain (`ForecastingExperiment` → `Experiment`, `CreateForecastingExperimentRequest` → `CreateExperimentRequest`, diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index 1ea0cdf0..1ccf6896 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -3,6 +3,7 @@ **Package path:** `/home/parth.bansal/sdk-js/packages/functions/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog Functions (SQL / Python UDFs and UDTFs). +**Total weird names flagged:** 49 (0 fixed, 49 still present after rescan on 2026-05-26 post regen #156). --- @@ -12,12 +13,12 @@ The `functions` package surfaces five UC function operations (`createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`) plus a paginated iterator. The model layer mirrors the Go SDK 1:1, so most issues are inherited from the upstream -definitions. The most pervasive problems are: (1) the package-level -name itself — `functions` and the field/type `function` collide with -JavaScript's `function` reserved word; (2) cryptic single-letter enum -variants (`S`, `IN`, `DEFINER`); (3) the cryptic `fullNameArg` -path-parameter field; and (4) widespread `type*` and `parameter*` -field prefixes that re-encode the parent type's domain. +definitions. The most pervasive problems are: (1) cryptic +single-letter enum variants (`S`, `IN`, `DEFINER`); (2) the cryptic +`fullNameArg` path-parameter field (a generator artifact whose `Arg` +suffix has no meaning on the TS surface); and (3) proto-architectural +leaks such as `Parent_Child` underscore-typed enums and the +`$case`/`value` ts-proto oneof envelope. --- @@ -25,26 +26,7 @@ field prefixes that re-encode the parent type's domain. ### 1. Vague / generic names -#### 1.1 `DeleteFunctionRequest.force` (model.ts:154) -Field name `force` is generic. Doc says "Force deletion even if the -function is notempty." (typo preserved). A function that "isn't -empty" — what does "empty" mean for a function? Probably a copy-paste -from the schema/catalog delete operations. The field name `force` -carries no information about *what* it overrides; consider -`forceDelete` or, better, surface the underlying constraint in the -name. - -#### 1.2 `FunctionParameterInfo.position` (model.ts:264) -Generic name on a field whose meaning is implementation-specific -(zero-indexed ordinal position). `parameterIndex` or -`ordinalPosition` would be unambiguous. Compare to `Position` types -in editors / DOM — `position` here is overloaded. - -#### 1.3 `FunctionParameterInfo.comment` (model.ts:272) -"User-provided free-form text description" — this is a description, -not a comment. `description` is what the field actually contains. -Same pattern repeats on `CreateFunction.comment`, `FunctionInfo.comment`, -`UpdateFunctionRequest.comment` (model.ts:116, 225, 364). +_None._ --- @@ -90,7 +72,7 @@ fully-qualified name. See also §8.1 and §7.3. Internal variable name for `package.json`. Mild — flagged for consistency with other audits. -#### 3.5 `respBody` (client.ts:89, 126, 167, 220, 273) — internal-only; mild. +#### 3.5 `respBody` (client.ts:97, 137, 181, 237, 293) — internal-only; mild. --- @@ -133,32 +115,16 @@ flagging. JSDoc reads "function dependencies." (lowercase, mid-sentence). The field name is `routineDependencies` and the doc says "function". The package toggles between "routine" and "function" terminology -indiscriminately — see §5.3. +indiscriminately — a Go-port artifact of the SQL standard's vocabulary +(`CREATE PROCEDURE … LANGUAGE SQL ROUTINE_BODY …`). Doc inconsistency +worth flagging. #### 5.2 `DeleteFunctionRequest.force` doc has typo "notempty" (model.ts:153) "Force deletion even if the function is notempty." Should be "not empty". Doc bug, not a naming bug, but signals the field hasn't been -read recently. See also §1.1. - -#### 5.3 "Function" vs "Routine" terminology mixed everywhere -Every type and method speaks of `function*`. But every body-related -field speaks of `routine*`: `routineBody`, `routineDefinition`, -`routineDependencies`. The enum is `FunctionInfo_RoutineBody`. A -function's *body* is a *routine*. This split is a Go-port artifact -of the SQL standard's vocabulary (`CREATE PROCEDURE … LANGUAGE -SQL ROUTINE_BODY …`) — but for a TS consumer the inconsistency is -jarring. `body`, `definition`, `dependencies` (dropping `routine`) -would be cleaner. See also §5.1. - -#### 5.4 `parameterDefault: string` (model.ts:270) -Doc: "Default value of the parameter." The default of a function -parameter is rarely a string in the source domain — it might be a -number, a boolean, an interval, or even `NULL`. Typing it as `string` -implies serialised form, but the field name `parameterDefault` -doesn't signal that. Consider `parameterDefaultExpression` or -`parameterDefaultText`. - -#### 5.5 `specificName` reserved-for-future-use (model.ts:104, 213, 352) +read recently. + +#### 5.3 `specificName` reserved-for-future-use (model.ts:104, 213, 352) Doc: "Specific name of the function; Reserved for future use." A field whose name promises specificity and whose docs admit it's unused is a future trap. Better to omit until it does something. @@ -167,46 +133,8 @@ unused is a future trap. Better to omit until it does something. ### 6. Reserved-word collisions -#### 6.1 `Function` / `function` — the entire package name collides with a JS reserved word -(model.ts and across the file) - -`function` is a JavaScript reserved keyword -(). -`Function` is also the name of the global constructor for function -objects. Although TypeScript permits both as identifier names in -most positions, this package routinely uses them in ways that -collide: - -- The `Dependency.value` discriminated union (model.ts:167) uses - `$case: 'function'` and a `function` property as one arm of the - union. The runtime payload key is `function`, which means consumers - must write - `if (dep.value?.$case === 'function') { dep.value.function … }` — - reading `dep.value.function` is jarring next to other code that - treats `function` as a keyword. -- The unmarshal schema (model.ts:412, 421) reads - `function: z.lazy(() => unmarshalFunctionDependencySchema)` — - again the property name is `function`. -- The marshal schema (model.ts:679-680) similarly has - `$case: z.literal('function'), function: z.lazy(…)`. -- The Go-side wire format uses snake_case (`function`) so the field - is forced; renaming requires breaking compatibility. - -This is the package's single biggest naming hazard. A consumer -auto-completing `dep.value.` will see a property called `function` -adjacent to TS keyword highlighting in their editor. Consider -renaming the union arm to `functionRef`, `functionDependency`, or -nesting via a different discriminator. - -#### 6.2 `name` field -`name` is used as a body field on `CreateFunction`, -`UpdateFunctionRequest`, `FunctionInfo`, `FunctionParameterInfo` -(model.ts:78, 187, 250, 326), and again indirectly via `fullNameArg`. -Not a reserved word but shadows `Function.prototype.name` — common -source of confusion when callers spread request objects. - -#### 6.3 `options` parameter on every client method -(client.ts:80, 112, 153, 194, 239, 264) — the second parameter is +#### 6.1 `options` parameter on every client method +(client.ts:85, 120, 164, 208, 256, 281) — the second parameter is named `options` and shadows the marshal schema's `options`-style metadata patterns. Not a collision in this package specifically but consistent with the catalogs audit (§10.1). @@ -292,8 +220,6 @@ A consumer reading the type sees `properties?: string` and has to manually `JSON.parse`. Either name it `propertiesJson` or type it as `Record` with marshal-layer translation. -#### 10.3 `comment` (model.ts:116, 225, 272, 364) — see §1.3. - --- ### 11. Field contradicting type domain @@ -353,19 +279,6 @@ Doc: "Id of Function, relative to parent schema." Format unspecified Both `string`, both undocumented for format, both server-assigned. A consumer cannot tell them apart from the types. -#### 13.4 `createdAt` / `updatedAt` (model.ts:126, 130, 235, 239, 374, 378) -Type is `number` (epoch milliseconds per the doc). The field name -doesn't convey unit. `createdAtMs` / `updatedAtMs` or `createdAtEpochMs` -would be more honest. The catalogs audit flagged the same -inconsistency. - -#### 13.5 `connectionName` (model.ts:73) — "Full name of the dependent connection, in the form of __connection_name__." -The field is named `connectionName` but the doc says it should be a -"full name". For other dependency types, the field is explicitly -named `*FullName` (e.g. `tableFullName`, `functionFullName`). Naming -inconsistency: ConnectionDependency and CredentialDependency -(model.ts:147) use `…Name`; the rest use `…FullName`. Pick one. - --- ## Additional / cross-cutting observations @@ -380,7 +293,7 @@ documented) or it's dead code. Same finding as catalogs audit (cross-cutting A). ### B. `fullNameArg` URL substitution silently allows empty string -(client.ts:114, 155, 266) — `${req.fullNameArg ?? ''}` — if +(client.ts:122, 166, 283) — `${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL silently becomes `/api/2.1/unity-catalog/functions/` and the request will fail on the server. The naming (`fullNameArg`) and the substitution behaviour @@ -393,7 +306,7 @@ schema produces a JSON field `full_name_arg`. Either the server tolerates the extra field or this is a bug. The `Arg` suffix lets the bug hide. -### D. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) +### D. `Client` constructor throws bare `Error` for missing `host` (client.ts:59) "Host is required." — bare `Error`. Not a naming issue, flagged for consistency with the catalogs audit. @@ -404,14 +317,14 @@ word; `functions` is not, but the proximity is jarring. Importers will often write `import * as functions from '@databricks/sdk-functions/v1'` which sets up `functions.createFunction(…)` — the local binding `functions` -shadows nothing, but the `Dependency.value.$case === 'function'` -pattern (§6.1) combined with the package name creates a vocabulary +shadows nothing, but the combination of the package name and the +`Dependency.value.$case === 'function'` pattern creates a vocabulary where "function" is overloaded. ### F. `FunctionInfo.routineDependencies` is described as "function dependencies." (model.ts:119, 228, 367) Comment text starts with lowercase and uses "function" instead of "routine"; field name uses "routine". See -§5.1 and §5.3. +§5.1. ### G. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` The most extreme case of a single-purpose API surface: a long enum @@ -519,44 +432,35 @@ envelope visibly reflect proto oneof semantics. Already noted in | `FunctionInfo_ParameterStyle.S` | model.ts:43 | 2.1, 3.1 | | `FunctionInfo_SecurityType.DEFINER` | model.ts:59-61 | 2.2 | | `FunctionInfo_SqlDataAccess` | model.ts:64 | 4.1 | -| `ConnectionDependency.connectionName` | model.ts:73 | 13.5 | | `CreateFunction` | model.ts:76 | 7.1, 11.2 | -| `CreateFunction.routineBody/routineDefinition/routineDependencies` | model.ts:90/92/120 | 5.3 | -| `CreateFunction.specificName` | model.ts:104 | 5.5 | +| `CreateFunction.specificName` | model.ts:104 | 5.3 | | `CreateFunction.fullName` | model.ts:124 | 7.2, 11.4 | -| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:122-136 | 11.2, 13.1, 13.2, 13.4 | +| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:122-136 | 11.2, 13.1, 13.2 | | `DeleteFunctionRequest.fullNameArg` | model.ts:152 | 3.3, 9.2, 11.3 | -| `DeleteFunctionRequest.force` | model.ts:154 | 1.1, 5.2 | -| `Dependency.value.function` arm | model.ts:167 | 6.1 | +| `DeleteFunctionRequest.force` | model.ts:154 | 5.2 | | `Dependency.value.$case` | model.ts:165 | 9.3 | | `FunctionInfo` | model.ts:185 | 7.1 | -| `FunctionInfo.routineBody/Definition/Dependencies` | model.ts:199/201/229 | 5.3 | -| `FunctionInfo.specificName` | model.ts:213 | 5.5 | +| `FunctionInfo.specificName` | model.ts:213 | 5.3 | | `FunctionInfo.properties` | model.ts:227 | 10.2 | | `FunctionInfo.fullName` | model.ts:233 | 7.2, 11.4 | | `FunctionInfo.functionId` | model.ts:243 | 13.2, 13.3 | -| `FunctionParameterInfo.name` | model.ts:250 | 6.2, 10.1 | +| `FunctionParameterInfo.name` | model.ts:250 | 10.1 | | `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:252-256 | 4.3, 4.4 | -| `FunctionParameterInfo.position` | model.ts:264 | 1.2 | -| `FunctionParameterInfo.parameterDefault` | model.ts:270 | 5.4 | -| `FunctionParameterInfo.comment` | model.ts:272 | 1.3 | | `GetFunctionRequest.fullNameArg` | model.ts:281 | 3.3, 9.2 | | `UpdateFunctionRequest` | model.ts:322 | 7.1, 7.4, 11.1, 11.2 | | `UpdateFunctionRequest.fullNameArg / name` | model.ts:324, 326 | 3.3, 7.4, 11.1 | -| `UpdateFunctionRequest.routineBody / routineDefinition / routineDependencies` | model.ts:338/340/368 | 5.3 | | `UpdateFunctionRequest.fullName` | model.ts:372 | 7.2, 11.4 | | `Client` (bare name) | client.ts:44 | 9.1 | -| `${req.fullNameArg ?? ''}` URL substitution | client.ts:114, 155, 266 | B | +| `${req.fullNameArg ?? ''}` URL substitution | client.ts:122, 166, 283 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | --- ## Recommended priority order -1. **Resolve the `function` reserved-word collision in `Dependency.value`** — the union arm-key `function` is the single most jarring naming hazard in the package. (§6.1) -2. **Fix `fullNameArg` / `name` confusion on `UpdateFunctionRequest`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §3.3) -3. **Resolve "function" vs "routine" vocabulary split.** (§5.3) -4. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.1, §2.2, §3.1, §3.2) -5. **Strip read-only fields from `CreateFunction` / `UpdateFunctionRequest`.** (§11.2) -6. **Unify `*Name` vs `*FullName` field-naming on `*Dependency` types.** (§13.5) -7. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +1. **Fix `fullNameArg` / `name` confusion on `UpdateFunctionRequest`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §3.3) +2. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.1, §2.2, §3.1, §3.2) +3. **Strip read-only fields from `CreateFunction` / `UpdateFunctionRequest`.** (§11.2) +4. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) + +--- diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index dcbffebb..214b2e7d 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -3,15 +3,15 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 61 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | | High | 14 | -| Medium | 24 | -| Low | 18 | -| Observation | 5 | +| Medium | 9 | +| Low | 10 | +| Observation | 4 | ## High severity @@ -125,260 +125,114 @@ - **Suggested name:** Same as #17. - **Rationale:** Same as #17. -### 19. `GenieSpace.spaceId` and `GenieSpace.title` and `GenieSpace.parentPath` — but no `name` — `src/v1/model.ts:1459-1480` -- **Why weird:** Compare with the rest of the SDK: `GenieSpace` uses `title` for the human-readable name (other types use `name`/`displayName`). The struct has `spaceId`, `title`, `description`, `warehouseId`, `parentPath`, `serializedSpace`, `etag` — no `name`. JSDoc on `title` says "Title of the Genie Space" — but in the rest of the codebase, "title" is reserved for `GenieConversation.title` (the conversation subject line). Two different "titles" in the same package. -- **Category:** 17 (inconsistency vs other types), 1 (vague — `title` doesn't distinguish from conversation title). -- **Suggested name:** `displayName` or `name` (Space is a top-level entity; "title" is column-header style). -- **Rationale:** Aligns with `DatabricksWorkspace.name`, `Dashboard.displayName`, etc. - -### 20. `GenieConversation.title` / `GenieMessage.content` / `GenieMessageComment.content` / `TextAttachment.content` / `Thought.content` — `content` is the universal field name — `src/v1/model.ts:927,1385,1414,1715,1734` -- **Why weird:** Five different concepts share the field name `content`. The reader cannot disambiguate from the field name alone. JSDocs differ: "User message content" / "Comment text content" / "AI generated message" / "The md formatted content for this thought" — i.e. they are all different formats. -- **Category:** 15 (generic field name), 1 (vague). -- **Suggested name:** `body` for the message body, `text` for comments and thoughts, or qualify (`messageBody`, `commentText`, `thoughtMarkdown`). -- **Rationale:** "Content" is a near-meaningless filler word; this is the kind of generic name the codebase rule (#15 of the audit categories) targets. - -### 21. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:921` +### 19. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:921` - **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1378), `GenieMessageComment.userId` (line 1412), `GenieEvalResult.createdByUser` (line 1025), `GenieEvalRunResponse.runByUser` (line 1091). - **Category:** 16 (field type contradicts domain), 14 (proto-int64 leaked to JS `number`). - **Suggested name:** Keep field name, change type to `string` (matches the rest of the SDK), or use `bigint`. Or `userId: string` with stronger JSDoc. - **Rationale:** Postgres-ID / long-id semantics are universal here. The `userId: number` typing is a generator bug that bites at runtime. -### 22. `GenieConversation.createdTimestamp` / `lastUpdatedTimestamp` etc. — `Timestamp` suffix is redundant — `src/v1/model.ts:923,925,935,1093,1103,1380,1382,1416,1427` -- **Why weird:** 9 fields use `*Timestamp` suffix. The type is already `number` (a Unix-millis timestamp per JSDoc). The suffix duplicates the type. Some peer fields drop the suffix (`createdByUser` on `GenieEvalResult`, `runByUser` on `GenieEvalRunResponse`). -- **Category:** 7 (overly verbose), 8 (redundant suffix). -- **Suggested name:** `createdAt` / `updatedAt`. Or `createdAtMs` / `updatedAtMs` if the millis unit needs to be explicit. -- **Rationale:** Industry-standard `createdAt`/`updatedAt` reads more naturally than `createdTimestamp`/`lastUpdatedTimestamp`. - -### 23. `GenieMessage.lastUpdatedTimestamp` vs everywhere else `updatedAt` — `src/v1/model.ts:1382` -- **Why weird:** `lastUpdatedTimestamp` (5 syllables) is the package's "updated at" name. The `last` prefix adds nothing — by definition, an "updated at" timestamp is the *last* update. -- **Category:** 7 (overly verbose). -- **Suggested name:** `updatedAt` / `updatedTimestamp`. -- **Rationale:** Same as #22. - -### 24. `GenieQueryAttachment.id` field bare `id` — `src/v1/model.ts:1429` -- **Why weird:** `id?: string` on `GenieQueryAttachment` is undocumented (no JSDoc). The parent `GenieAttachment` has `attachmentId` (line 909) — so the `id` here is presumably the same value or the query-attachment-specific id. Caller can't tell. -- **Category:** 19 (underspecified id), 1 (vague). -- **Suggested name:** `attachmentId` (match the parent) or `queryAttachmentId` (qualify). -- **Rationale:** Two near-identical ids on the same outer entity is one ambiguity too many. - -### 25. `TextAttachment.id` field bare `id` — `src/v1/model.ts:1716` -- **Why weird:** Same as #24 — bare `id` on a `TextAttachment` alongside the parent's `attachmentId`. No JSDoc. -- **Category:** 19, 1. -- **Suggested name:** Same as #24. -- **Rationale:** Same as #24. - -### 26. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` +### 20. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` - **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). - **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). - **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. - **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. -### 27. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` +### 21. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` - **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. - **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). - **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. - **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. -### 28. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` -- **Why weird:** Same as #27 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +### 22. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` +- **Why weird:** Same as #21 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). - **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). - **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. - **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. -### 29. `downloadIdSignature` is a JWT but named `Signature` — `src/v1/model.ts:1149,1173` -- **Why weird:** JSDoc says "JWT signature for the download_id". JWT is itself the full token (header.payload.signature). Calling it a "signature" understates what it is (the entire JWT that authorises the download). -- **Category:** 6 (misleading — `Signature` is a sub-part of a JWT), 5 (cryptic). -- **Suggested name:** `downloadToken` / `downloadJwt`. -- **Rationale:** Caller expects a base64 signature to pair with `downloadId`; the value is actually a full bearer token. - -### 30. `statementIdSignature` same pattern — `src/v1/model.ts:1597` -- **Why weird:** Same as #29: `Result.statementIdSignature` is "JWT corresponding to the statement". `Signature` is misleading. -- **Category:** 6 (misleading), 5 (cryptic). -- **Suggested name:** `statementToken` / `statementJwt`. -- **Rationale:** Same as #29. - -### 31. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1480,1529` +### 23. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1480,1529` - **Why weird:** HTTP `ETag` is the canonical capitalisation. The field is `etag: string`. Across the SDK other types use `etag` lowercase too — but it is an acronym (`Entity Tag`). - **Category:** 3 (acronym casing). - **Suggested name:** `eTag` (camelCase per TS style) or `etag` (current — chosen for consistency). - **Rationale:** Low priority; flag for awareness. -### 32. `Result` type name — too generic — `src/v1/model.ts:1589` +## Low severity + +### 24. `Result` type name — too generic — `src/v1/model.ts:1589` - **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. - **Category:** 1 (vague/generic). - **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. - **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. -### 33. `Result.isTruncated` vs `ResultManifest.truncated` — same concept, different names — `src/v1/model.ts:1595,1656` -- **Why weird:** Both fields are booleans indicating truncation. `Result.isTruncated` uses the `is*` prefix convention; `ResultManifest.truncated` is bare. Same struct file, two conventions. -- **Category:** 17 (inconsistency). -- **Suggested name:** Pick one form (`truncated` everywhere) and apply. -- **Rationale:** Pure consistency win; no semantic change. - -### 34. `GenieResultMetadata.isTruncated` — third copy — `src/v1/model.ts:1442` -- **Why weird:** A third truncation field on `GenieResultMetadata.isTruncated`. Three independent fields tracking the same concept across `Result`, `ResultManifest`, `GenieResultMetadata`. -- **Category:** 17 (inconsistency), 12 (duplicate concept). -- **Suggested name:** Same as #33. -- **Rationale:** Same as #33. - -### 35. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1438` +### 25. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1438` - **Why weird:** A type whose two fields (`rowCount`, `isTruncated`) are both already on `ResultManifest`. JSDoc says "Metadata associated with the query result", but `ResultManifest` is also "result manifest" metadata. - **Category:** 12 (duplicate concept). - **Suggested name:** Replace with `ResultManifest` (or a sub-projection of it); delete `GenieResultMetadata`. - **Rationale:** Two structs covering the same semantic territory cause readers to wonder which one is authoritative. -### 36. `QueryAttachmentParameter.keyword` field name — `src/v1/model.ts:1584` -- **Why weird:** `keyword` is a vague word for what is presumably the parameter name. No JSDoc. The companion field `value` carries the bound value; `sqlType` carries the type. A parameter is `(name, value, type)` — why is `name` called `keyword`? -- **Category:** 1 (vague), 6 (misleading — `keyword` evokes SQL reserved words). -- **Suggested name:** `name` (with JSDoc) or `parameterName`. -- **Rationale:** Reader sees `keyword` and looks for a SQL keyword list. - -### 37. `QueryAttachmentParameter.value: string` typed as a string but doc doesn't say what kind — `src/v1/model.ts:1585` -- **Why weird:** No JSDoc on `value`. Type is `string`. For SQL parameters this could be a literal value, an expression, a placeholder, a JSON-encoded scalar, etc. Companion `sqlType?: string` (also no JSDoc) presumably qualifies it. -- **Category:** 1 (vague), 16 (field type may contradict domain). -- **Suggested name:** Document. Optionally `stringValue` / `valueText` to make the encoding explicit. -- **Rationale:** Public SDK types should not require source-diving. - -### 38. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:903` +### 26. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:903` - **Why weird:** Discriminator value is `'suggestedQuestions'` and the payload type is `GenieSuggestedQuestionsAttachment`. The word `Attachment` is in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** Variant `'followUps'`, payload `SuggestedQuestions { questions: string[] }`. - **Rationale:** Reduce noise per attachment. -## Low severity - -### 39. `GenieSuggestedQuestionsAttachment.questions: string[]` — `src/v1/model.ts:1502` -- **Why weird:** Bare `string[]`. Doc says "The suggested follow-up questions". The questions are also typed elsewhere as a free-text input (`content` on a `GenieCreateConversationMessageRequest`) — so the type tells you nothing about the format. -- **Category:** 1 (vague — questions could be markdown, plain, etc.). -- **Suggested name:** `followUpQuestions: string[]` (clearer; matches the JSDoc). -- **Rationale:** Field name disambiguation. - -### 40. `MessageError.error` — field has the same name as the parent struct's concept — `src/v1/model.ts:1557` -- **Why weird:** `MessageError.error: string`. Reader sees `someError.error` (two `error`s). Some other fields are similarly self-referential (`Result.statementId`, OK because `Result` is generic; here `MessageError.error` is *the error message*). -- **Category:** 15 (generic field name), 1 (vague). -- **Suggested name:** `MessageError.message: string` (matches the JSON shape) or `MessageError.detail`. -- **Rationale:** Wire format on the server may already be `error_message`; check before renaming. - -### 41. `MessageError.type: MessageError_Type` — `src/v1/model.ts:1558` -- **Why weird:** Field name `type` is a JS reserved-word-adjacent (TS allows it, but `type` collides with the `type` keyword used in TS type aliases — refactoring tools sometimes choke). -- **Category:** 10 (reserved-word collision), 1 (vague). -- **Suggested name:** `errorType` / `category` / `kind`. -- **Rationale:** Common collision; small ergonomics win. - -### 42. `Thought.thoughtType: ThoughtType` — `src/v1/model.ts:1732` -- **Why weird:** `Thought.thoughtType` repeats "thought" twice. Could just be `Thought.type`. -- **Category:** 8 (redundant suffix), 7 (overly verbose). -- **Suggested name:** `Thought.type` (and rename `ThoughtType` → `Thought.Kind` namespace). -- **Rationale:** Reduces redundancy. - -### 43. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:909` +### 27. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:909` - **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1714) and `GenieQueryAttachment.id` (line 1429) inside variants. Three different id fields for the same logical entity (the attachment). - **Category:** 19 (underspecified id), 12 (duplicate concept). - **Suggested name:** Single `id` on `GenieAttachment`, remove inner ids. -- **Rationale:** See #24, #25, #43 together. - -### 44. `GenieGetSpaceRequest.includeSerializedSpace` — long boolean — `src/v1/model.ts:1239` -- **Why weird:** Boolean toggle that expands the response. Permission check is documented ("Requires at least CAN EDIT permission"). Boolean naming style varies across SDK: `enableX`, `includeX`, `withX`. Could be `withSerializedSpace` or `includeSerialized` (the parent struct is already a Space). -- **Category:** 7 (overly verbose). -- **Suggested name:** `withSerialized` / `expandSerialized`. -- **Rationale:** The struct context already says "Space"; the prefix is redundant. +- **Rationale:** Eliminate redundant inner id fields. -### 45. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` +### 28. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` - **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). - **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. - **Rationale:** Class names should be noun phrases; current name reads as a verb. -### 46. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:160` +### 29. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:160` - **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. - **Category:** 7 (overly verbose). - **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. - **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. -### 47. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1255` +### 30. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1255` - **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. - **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). - **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. - **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. -### 48. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:546` +### 31. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:546` - **Why weird:** Value `ARROW_STREAM` casing. The product name is `Apache Arrow` — `Arrow` is title-case in TS naming. As an enum value `ARROW_STREAM` is conventional (SCREAMING_SNAKE) but mixed with `JSON_ARRAY` and `CSV` where one is fully-cap acronym and one is mixed. - **Category:** 3 (acronym casing), 17 (mixed conventions within the enum). - **Suggested name:** `ArrowStream` (in a Pascal-case enum). - **Rationale:** Low priority — enum-value style is widely-debated. -### 49. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1392` -- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #32). +### 32. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1392` +- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #24). - **Category:** 12 (duplicate concept — kept-for-compat), 1 (vague — `Result`). - **Suggested name:** Mark with `/** @deprecated */` JSDoc (current text just says "Deprecated" — TS tooling won't strike-through). - **Rationale:** Tooling support — modern TS understands `@deprecated`. -### 50. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +### 33. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. - **Rationale:** Cleanup; clients should migrate to the canonical name. -### 51. `GenieEvalResult.createdByUser: number` — `By` clause inside a field name — `src/v1/model.ts:1025` -- **Why weird:** Field is named `createdByUser` rather than `createdBy`. `By User` is redundant: a `createdBy` field is by-its-nature-by-a-user (or by a service principal). Compare `GenieEvalRunResponse.runByUser` (same pattern, line 1091). -- **Category:** 7 (overly verbose), 17 (inconsistent vs other types in the SDK using `createdBy`). -- **Suggested name:** `createdBy` (matches the rest of the SDK). -- **Rationale:** Aligns with `databricks-sdk-go` conventions and most peer types. - -### 52. `GenieEvalRunResponse.runByUser` — `By User` pattern — `src/v1/model.ts:1091` -- **Why weird:** Same as #51. -- **Category:** 7, 17. -- **Suggested name:** `runBy` / `runByUserId`. -- **Rationale:** Same as #51. - -### 53. `GenieEvalResult.benchmarkAnswer` vs `GenieEvalResultDetails.actualResponse` / `expectedResponse` — naming asymmetry — `src/v1/model.ts:1023,1080,1082` -- **Why weird:** `GenieEvalResult` stores the original "benchmark answer" as a flat string; `GenieEvalResultDetails` returns the actual/expected as arrays of `GenieEvalResponse`. Three different words for "the right answer" / "Genie's answer" / "the expected answer". -- **Category:** 17 (inconsistent word choice), 1 (vague — `answer` vs `response`). -- **Suggested name:** Pick one verb. E.g., `expectedAnswer` / `actualAnswer` (or `expectedResponse` / `actualResponse` for both types). -- **Rationale:** Reader has to relearn the vocabulary in each type. - -### 54. `GenieEvalResultDetails.evalRunStatus` — `evalRun` prefix inside the result-details type — `src/v1/model.ts:1037` -- **Why weird:** A `GenieEvalResultDetails` describes a single result inside a run. The field `evalRunStatus` describes the *run's* status, not the result's status. The plain `status` field appears on `GenieEvalResult` (line 1019) but is gone here — replaced by `evalRunStatus`. So the same enum (`EvaluationStatusType`) is exposed under two different field names. -- **Category:** 17 (inconsistent field naming for the same concept), 6 (misleading — `evalRunStatus` on a result-details type confuses run-status with result-status). -- **Suggested name:** `runStatus` (with the run context clear from the parent type's purpose). -- **Rationale:** Same status enum, two field names is jarring. - -### 55. `GenieEvalResultDetails.manualAssessment: boolean` — `src/v1/model.ts:1041` -- **Why weird:** Two adjacent fields: `assessment: GenieEvalAssessment` and `manualAssessment: boolean`. The second is a flag indicating whether the first was set manually. The naming implies that `manualAssessment` is itself an assessment. -- **Category:** 6 (misleading — `manualAssessment` looks like "the manual assessment value"), 1 (vague). -- **Suggested name:** `assessmentIsManual` / `isManuallyAssessed`. -- **Rationale:** Boolean-prefix convention disambiguates. - -### 56. `GenieListConversationsRequest.includeAll` boolean — `src/v1/model.ts:1289` -- **Why weird:** `includeAll: boolean`. JSDoc clarifies "Include all conversations in the space across all users". `All` is unqualified; could mean "include archived", "include all spaces", "include all messages". -- **Category:** 1 (vague), 6 (misleading without docs). -- **Suggested name:** `includeAllUsers` / `acrossUsers` / `allUsers`. -- **Rationale:** Boolean toggles need to be unambiguous from the name. - ## Observations -### 57. `GenieGetSpaceRequest.includeSerializedSpace` — feature parity with #44 -- **Observation:** Listed under #44. Documenting here for cross-reference. - -### 58. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` +### 34. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` - **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. - **Suggested name:** N/A. - **Rationale:** Confirms the package's pagination naming is consistent. -### 59. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` +### 35. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` - **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. - **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. - **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. -### 60. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,999,1008` +### 36. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,999,1008` - **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. -### 61. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` +### 37. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` - **Observation:** `export interface MessageStatus {}` is an empty placeholder. The actual status enum is `MessageStatus_MessageStatus`. The empty type adds noise to the surface. - **Suggested name:** Remove the empty interface; refer to the enum directly. - **Rationale:** Empty interfaces in TS satisfy any object type and become bug magnets. - -## Fixed - -- #11 `RESPONSE_PHASE_*` prefix repeated on every value (originally cited at `src/v1/model.ts:588-590`): Fixed in regeneration on 2026-05-20 — `ResponsePhase` enum no longer exists in `model.ts`. -- #13 `VERIFICATION_SECTION_*` prefix repeated and one value has the prefix doubled (originally cited at `src/v1/model.ts:660-666`): Fixed in regeneration on 2026-05-20 — `VerificationSection` enum no longer exists in `model.ts`. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index ecac82b0..2c878a62 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -13,7 +13,8 @@ creation and returns it everywhere else. Five operations: `create/get/list/update/delete`. No enums, no discriminated unions, no pagination, no list filtering beyond an optional `principalId` query parameter, no version negotiation. -**Total weird names flagged:** 21 +**Total weird names flagged:** 15 (0 fixed, 15 still open) +**Last rescan:** 2026-05-26 (post regen #156) --- @@ -33,15 +34,9 @@ parameter, no version negotiation. | 10 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | | 11 | `bitbucketServer` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Same problem as #10 — wire value is the legacy name. | | 12 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | -| 13 | `gitUsername`, `gitEmail`, `gitProvider` prefixed with `git` | model.ts:20, 39, 13, 54, 65, 84, 95, 127, 138, 175, 188 | field set | Medium | 1 Vague/generic, 6 Misleading names | The package is *gitcredentials*; every field already lives under the package namespace. Re-prefixing each field with `git` is stuttering. `req.gitProvider`, `req.gitUsername`, `req.gitEmail` could be `req.provider`, `req.username`, `req.email`. The wire format requires the `git_` prefix on the JSON keys (see the zod schemas), but the TS field can be renamed in the zod `transform`. | -| 14 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | -| 15 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 141, 175, 209, 107 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | -| 16 | `DeleteCredentialsRequest.id` and `GetCredentialsRequest.id` and `UpdateCredentialsRequest.id` (bare `id` field) | model.ts:100, 110, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter is named `id`. Three operations carry a bare `id` field. JSDoc on each says "The ID for the corresponding credential to access" — i.e., it is a *credential* ID. The response types call the same value `credentialId` (model.ts:45, 70, 118), so the same number has *two different names* depending on whether you are reading or writing it. Should be `credentialId` everywhere. | -| 17 | `principalId` field (type `number`) | model.ts:28, 102, 112, 143, 177 | field | Medium | 5 Cryptic abbreviations, 19 Underspecified IDs | "Principal" without qualification means different things in different domains: AWS IAM Principal, Java Security Principal, Databricks service principal, etc. JSDoc clarifies "service principal" — but the field name does not. `servicePrincipalId` or `applicationId` would be self-documenting. The number type is also unusual for a Databricks principal ID (most are UUIDs or strings); the wire format may match Go's `int64` but JavaScript loses precision above 2^53. | -| 18 | `name` field on `Credential` and on create/update | model.ts:30, 56, 86, 129, 179 | field | Medium | 1 Vague/generic, 15 Generic field names | "Name" on a credential resource — JSDoc says it is "the name of the git credential, used for identification and ease of lookup". So it is a *display* name (not a lookup key — `id` is the lookup key). Should be `displayName` or `label`. The bare `name` invites callers to think it is the primary key. | -| 19 | `credentialId` field naming inconsistency vs `id` path parameter | model.ts:45, 70, 118 vs 100, 110, 154 | field pair | High | 17 Inconsistent action verbs, 15 Generic field names | The same conceptual value is `id` on requests (Delete/Get/Update) and `credentialId` on responses (Credential, Create/Get response). The wire JSON keys are `id` and `credential_id` respectively, so the divergence is on the server side; but TS callers will write `req.id = resp.credentialId` and pause every time. Should converge — either both `credentialId` or both `id`. | -| 20 | `personalAccessToken` field | model.ts:26, 160 | field | Low | 7 Overly verbose | 19-character field name. JSDoc clarifies that the field also accepts "other types of scoped access tokens" for "certain providers". So "Personal" is not strictly accurate. `accessToken` or `token` is shorter and covers the JSDoc-documented use. | -| 21 | `*Request_Response` underscore-nested response types (5 of them) | model.ts:43, 106, 116, 147, 192 | interface set | High | Proto-architectural-leak | All five response types use the proto-style `ParentRequest_Response` underscore-nested form: `CreateCredentialsRequest_Response`, `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. The underscore is a protobuf-nested-message encoding bleeding into the public TS API — the generator even acknowledges it with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` above every one. The matching zod schema constants (`unmarshalCreateCredentialsRequest_ResponseSchema`, etc.) inherit the same underscore. | +| 13 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | +| 14 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 141, 175, 209, 107 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 15 | `*Request_Response` underscore-nested response types (5 of them) | model.ts:43, 106, 116, 147, 192 | interface set | High | Proto-architectural-leak | All five response types use the proto-style `ParentRequest_Response` underscore-nested form: `CreateCredentialsRequest_Response`, `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. The underscore is a protobuf-nested-message encoding bleeding into the public TS API — the generator even acknowledges it with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` above every one. The matching zod schema constants (`unmarshalCreateCredentialsRequest_ResponseSchema`, etc.) inherit the same underscore. | --- @@ -91,7 +86,7 @@ await client.createCredential({gitProvider: 'gitHub', ...}); Recommendation: keep `listCredentials` (plural — list returns many) but rename the four single-resource methods and their request types to -singular. See #5, #6, #15. +singular. See #5, #6, #14. ### H3. Three field-for-field-identical "Credential" shapes @@ -112,32 +107,7 @@ export interface GitCredential { /* 6 fields */ } // Return GitCredential directly from create() and get(). ``` -### H4. `id` vs `credentialId` for the same value - -Requests use `id`: - -```ts -interface DeleteCredentialsRequest { id?: number; principalId?: number; } -interface GetCredentialsRequest { id?: number; principalId?: number; } -interface UpdateCredentialsRequest { id?: number; /* ... */ } -``` - -Responses use `credentialId`: - -```ts -interface Credential { credentialId?: number; /* ... */ } -interface CreateCredentialsRequest_Response { credentialId?: number; /* ... */ } -interface GetCredentialsRequest_Response { credentialId?: number; /* ... */ } -``` - -So callers write `req.id = resp.credentialId` and constantly translate -between the two spellings. JSDoc on the request `id` field even says "the ID -for the corresponding *credential* to access" — i.e., it is logically a -credential ID. The wire format uses `id` (path parameter) on requests and -`credential_id` (body field) on responses — the *server* mints the -divergence; the TS-side should normalize to one spelling. See #16, #19. - -### H5. `gitProvider` is typed `string` but is closed-set +### H4. `gitProvider` is typed `string` but is closed-set ```ts gitProvider?: string | undefined; @@ -156,7 +126,7 @@ server rejects other values. But the TS-side surfaces it as `string`, so: Recommendation: emit a string-literal union or enum. The casing problem (#9) gets handled there. -### H6. `Client` is unqualified +### H5. `Client` is unqualified `export class Client` (client.ts:48). Every package in this SDK exports its own `Client`. Once imported in user code: @@ -169,7 +139,7 @@ import {Client as GitCredentialsClient} from '@databricks/sdk-gitcredentials/v1' `GitCredentialsClient` directly (matching the package noun). This is a pattern-wide issue and was flagged in every audit so far. -### H7. `*Request_Response` underscore-nested response types — `model.ts:43, 106, 116, 147, 192` +### H6. `*Request_Response` underscore-nested response types — `model.ts:43, 106, 116, 147, 192` - **Why:** All five response types are emitted as proto-style nested messages joined by a literal underscore — `CreateCredentialsRequest_Response`, @@ -206,62 +176,12 @@ pattern-wide issue and was flagged in every audit so far. ## Medium severity (worth pushing back on) -### M1. `git`-prefix on every field - -Every field is `git`-prefixed: `gitProvider`, `gitUsername`, `gitEmail`. -The package is `gitcredentials`; the type is `Credential` or -`*Credentials`; the field is already scoped. Reading code: - -```ts -const cred: Credential = await client.getCredentials({id: 42}); -console.log(cred.gitProvider, cred.gitUsername, cred.gitEmail); -``` - -The `git` prefix adds no information. Compare: - -```ts -console.log(cred.provider, cred.username, cred.email); -``` - -The wire JSON key needs `git_provider`, so the rename is purely a zod -`transform` change. The `git_*` keys must survive to the wire; the TS field -names can be unprefixed. See #13. - -### M2. Plural `*Credentials` envelopes for single-resource operations +### M1. Plural `*Credentials` envelopes for single-resource operations See H2. Repeating because the request-type and method names compound the plural problem. -### M3. `name` field is a display label, not a key - -JSDoc says "the name of the git credential, used for identification and ease -of lookup". So `name` is a *display* name. The actual lookup key is `id`. -Callers reading the type signature will assume `name` is a primary key -(because it is on most Databricks resources — e.g., `clusters/{name}`). -`displayName` or `label` would clarify. See #18. - -### M4. `principalId` is a service-principal ID, not a user ID - -JSDoc on every `principalId` field says "The ID of the service principal -whose credentials will be modified. Only service principal managers can -perform this action." The field name says only "Principal" — which is -overloaded in security/auth contexts. `servicePrincipalId` would -self-document. See #17. - -### M5. `personalAccessToken` field name is narrower than its accepted values - -JSDoc: - -> The personal access token used to authenticate to the corresponding Git -> provider. For certain providers, support may exist for other types of -> scoped access tokens. - -So the field accepts more than just "personal access tokens" — also "fine- -grained tokens", "deploy keys", etc. depending on the provider. The -name `personalAccessToken` lies about that. `accessToken` (or `token`) is -honest. See #20. - -### M6. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term +### M2. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term The model has one *singular* type — `Credential` (the resource) — and five *plural* request/response types around it. Within one file the same @@ -290,7 +210,7 @@ URL `/credentials`), singular for resource ops (`getCredential`, The JSDoc on `gitProvider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on either the field's documentation or on a typed enum value (which doesn't -exist — see H5). Callers cannot programmatically detect deprecated values. +exist — see H4). Callers cannot programmatically detect deprecated values. See #12. --- @@ -317,12 +237,11 @@ them for awareness — fixing requires an API-server change. | Issue | This package | `credentials` audit | `oauthcustomappintegration` (typical) | |---|---|---|---| -| Bare `Client` class | Yes (#14) | Yes (#10) | Yes | -| Bare `id` field on requests vs `Id` on responses | Yes (#16, #19) | Partial (#12, `nameArg`) | Common | -| Plural request envelopes on single-resource ops | Yes (#5, #6, #15) | No (uses `nameArg`/singular shapes) | Mixed | +| Bare `Client` class | Yes (#13) | Yes (#10) | Yes | +| Plural request envelopes on single-resource ops | Yes (#5, #6, #14) | No (uses `nameArg`/singular shapes) | Mixed | | `string`-typed enum-domain field | Yes (#8) | No (uses real enums) | Rare | -The `string`-typed `gitProvider` despite a documented closed set (#8, H5) +The `string`-typed `gitProvider` despite a documented closed set (#8, H4) is the standout finding unique to this package. The plural request-type naming (#5, #6, H2) is also pronounced here — the `credentials` audit gets it right (`CreateCredential`, `UpdateCredential`). diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index 315325cb..57c25ef6 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -93,9 +93,7 @@ None. This package defines no enums. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| V-01 | `CreateGlobalInitScriptRequest.script` / `UpdateGlobalInitScriptRequest.script` (`model.ts:9`, `model.ts:74`) | High | The field name `script` is overloaded inside a type whose entity name is already "script". A `CreateGlobalInitScriptRequest` whose payload field is `script` reads as "the script of the script". Worse, the JSDoc says it carries "Base64-encoded content". A name like `content`, `body`, or `scriptContent` would convey what the bytes actually are. | -| V-02 | `GlobalInitScriptDetails.position` (`model.ts:47`) | Medium | `position` is generic. Without the JSDoc the reader cannot tell whether it is an array index, a UI ordering hint, a priority, or an execution-order rank. `executionOrder`, `runOrder`, or `priority` would be more self-describing. | -| V-03 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Generic but standard across the SDK; acceptable in entity context. | +| V-01 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Generic but standard across the SDK; acceptable in entity context. | ### 2.2 Redundant enum prefixes — None @@ -127,9 +125,7 @@ No enums are declared in this package; this rubric category does not apply. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| M-01 | `CreateGlobalInitScriptRequest.script` (field type `Uint8Array`, `model.ts:9`) | High | The field is documented as "Base64-encoded content" but its TS type is `Uint8Array` — the marshal schema converts the bytes to Base64 via `btoa`. Callers therefore supply **raw bytes**, not Base64. The JSDoc is misleading: it describes the wire format, not what the caller hands in. A better split would be either rename to `scriptBytes` (matching the runtime type) or change the doc to "Raw bytes; the SDK Base64-encodes before sending." | -| M-02 | `UpdateGlobalInitScriptRequest.script` (`model.ts:74`) | High | Same as M-01. | -| M-03 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`, `client.ts:133`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | +| M-01 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`, `client.ts:133`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | ### 2.7 Overly verbose / Redundant suffixes — Medium @@ -183,10 +179,8 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| F-01 | `GlobalInitScriptDetails.position` (`model.ts:47`) | Medium | `position` standing alone (e.g. inside a generic list-item display) is ambiguous: file position? UI position? Order index? Adding context (`runOrder`) would survive destructuring. | -| F-02 | `CreateGlobalInitScriptRequest.script` (`Uint8Array`, `model.ts:9`) | High | A field called `script` of type `Uint8Array` does not communicate "bytes of the script content". Outside the interface it could be mistaken for a script object/handle. See V-01, M-01. | -| F-03 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Standard entity field; meaning preserved in context. | -| F-04 | `httpReq`, `respBody`, `body`, `headers`, `text`, `parsed`, `info` (locals in `client.ts` / `utils.ts`) | Low | Local-scope identifiers only. | +| F-01 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Standard entity field; meaning preserved in context. | +| F-02 | `httpReq`, `respBody`, `body`, `headers`, `text`, `parsed`, `info` (locals in `client.ts` / `utils.ts`) | Low | Local-scope identifiers only. | ### 2.15 Field contradicting type domain — Low @@ -207,10 +201,7 @@ No enums declared; not applicable. ### 2.18 Underspecified IDs — Medium -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| I-01 | `scriptId` | Medium | The field name `scriptId` is the API-level field but inside a workspace-scoped SDK there is at least one other ID concept called "script" (e.g. cluster init scripts via `clusters` package — see `InitScriptInfo`). A globally-unique identifier across the Databricks SDK surface would be `globalInitScriptId`. The shorter `scriptId` is in line with the API wire field, so this is a known trade-off, but ID names should generally be fully qualified to avoid cross-package ambiguity. | -| I-02 | `scriptId` (in `DeleteGlobalInitScriptRequest`, `GetGlobalInitScriptRequest`, `UpdateGlobalInitScriptRequest`) | Medium | Same as I-01. All five locations use the bare `scriptId`. | +_None._ ### 2.19 Type-suffix tautology — Medium @@ -252,34 +243,26 @@ No enums declared; not applicable. | Severity | Count | | -------- | ----- | -| High | 14 | -| Medium | 11 | -| Low | 23 | -| **Total**| **48**| +| High | 10 | +| Medium | 5 | +| Low | 28 | +| **Total**| **43**| ### 3.2 Top themes -1. **`script` field overload conflates "script bytes" with "the entity".** - The field is typed as `Uint8Array` (raw bytes), documented as - "Base64-encoded content" (the wire format), and lives on a type - already called `GlobalInitScript`. Renaming the field to `content` - (or `scriptBytes`) — and clarifying the JSDoc — removes both the - self-reference ("script.script") and the format-vs-runtime confusion. - -2. **`GlobalInitScriptDetails` should just be `GlobalInitScript`.** +1. **`GlobalInitScriptDetails` should just be `GlobalInitScript`.** The `Details` suffix is a Java-style hangover with no peer type to disambiguate from. The method JSDoc also claims to return Base64 content while the entity has no content field — a documentation / shape inconsistency. -3. **`createdAt`/`updatedAt` naming is good** — unlike sibling packages +2. **`createdAt`/`updatedAt` naming is good** — unlike sibling packages that use `createdAtTimestamp`, this package uses the cleaner `createdAt` / `updatedAt`. Worth keeping as the cross-package reference. ### 3.3 Suggested quick wins (advisory — codegen-level) -- Rename `script` field to `content` (or `scriptContent`). - Rename entity `GlobalInitScriptDetails` -> `GlobalInitScript`. - Add the missing content field on the entity (or fix the JSDoc on `getGlobalInitScript` that claims contents are returned). @@ -293,7 +276,3 @@ No enums declared; not applicable. preferred reference for timestamp naming. --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md index f0870fdd..51f39937 100644 --- a/.agent/naming-audit/grants.md +++ b/.agent/naming-audit/grants.md @@ -3,29 +3,23 @@ **Path:** `packages/grants/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. -**Total weird names flagged:** 20 +**Total weird names flagged:** 12 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 8 | +| High | 5 | +| Medium | 3 | | Low | 3 | | Observation | 1 | -The grants package contains 9 generated types and 3 client methods covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive remaining issues are (1) the duplicated vocabulary (`permissions` in method names vs `privileges` / `PrivilegeAssignment` in payload types), (2) the conceptual overlap with the separate `permissions` package which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation, and (3) the lack of enum types for the closed sets of `securableType` and `privilege` strings. +The grants package contains 9 generated types and 3 client methods covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive remaining issues are (1) the conceptual overlap with the separate `permissions` package which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation, and (2) the lack of enum types for the closed sets of `securableType` and `privilege` strings. --- ## High severity -### 1. Concept duplication: "permissions" vs "privileges" — `src/v1/model.ts` (entire file) -- **Why weird:** The package uses two synonymous nouns interchangeably for the same concept. Method names use `permissions` (`getPermissions`, `updatePermissions`); collection types use `privileges` / `PrivilegeAssignment` / `EffectivePrivilege`. The payload field on the response of `getPermissions()` is named `privilegeAssignments`. A single privilege string (e.g. `"SELECT"`) is sometimes called a "permission" (e.g. in `GetPermissionsRequest.maxResults` doc: "the maximum number of privileges to return") and sometimes a "privilege". This is a vocabulary smell baked into the Go SDK port, but it's the single biggest readability issue in the package. -- **Category:** 12 (duplicate concepts), 17 (inconsistent action verbs / vocabulary). -- **Suggested name:** Pick one. Either rename the type family to `Privileges` (so `getPrivileges`, `updatePrivileges`, `PrivilegeAssignment`, `GetPrivilegesResponse`) or `Permissions` (so `getPermissions`, `updatePermissions`, `PermissionAssignment`). The current mix forces readers to mentally translate every method call. -- **Rationale:** This is wire-locked (Databricks UC API uses `/permissions/` URL paths but body fields named `privileges`), but the SDK doesn't have to expose it. A consistent vocabulary across types and methods makes the API self-documenting. - -### 2. Concept duplication with `permissions` package — cross-package +### 1. Concept duplication with `permissions` package — cross-package - **Why weird:** A sibling package `packages/permissions/src/v1/` (also generated, also exposed) uses an entirely different vocabulary for similar-sounding operations: - `permissions` package: `PermissionLevel` enum (e.g. `CAN_MANAGE`, `IS_OWNER`), `AccessControlRequest` (uses discriminated union over `userName` / `groupName` / `servicePrincipalName`), `PermissionsResponse` with `accessControlList`, `setObjectPermissions`, `getObjectPermissions`, `updateObjectPermissions`, `getPermissionLevels`. - `grants` package: free-form `privileges: string[]` (no enum), `principal: string` (single field, doesn't distinguish user vs group vs SP), `PrivilegeAssignment`, `getPermissions`, `updatePermissions`. @@ -34,117 +28,69 @@ The grants package contains 9 generated types and 3 client methods covering one - **Suggested name:** Rename one of the packages to make the disambiguation clear, e.g. `grants` → `unity-catalog-grants` or `uc-privileges`; `permissions` → `workspace-permissions` or `workspace-acl`. Or — at minimum — keep their public types non-overlapping (currently both export "Permission..."-prefixed types). - **Rationale:** The two packages cover non-overlapping concrete operations (UC grants vs workspace-object ACLs) but use heavily overlapping vocabulary. This is an enormous discoverability hazard. -### 3. `PermissionsChange` (type) — `src/v1/model.ts:99` +### 2. `PermissionsChange` (type) — `src/v1/model.ts:99` - **Why weird:** Inconsistent vocabulary with the rest of the file. The package mostly uses `Privilege*` (`PrivilegeAssignment`, `EffectivePrivilege`, `EffectivePrivilegeAssignment`) but the change-payload is named `PermissionsChange` (plural "Permissions", not "Privilege"). The change describes adding/removing entries to `add: string[]` / `remove: string[]` where the strings are privileges. So the type is really a `PrivilegeChange` or `PrivilegeAssignmentChange`. - **Category:** 17 (inconsistent vocabulary), 12 (concept overlap with `permissions` package). -- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file — see #1). -- **Rationale:** See #1. - -### 4. `principal` (field, multiple) — `src/v1/model.ts:22,33,69,104,116` -- **Why weird:** The field `principal: string` appears 5 times across the file. The doc string is "user email address or group name" — but the `permissions` package solves the same problem with a discriminated union (`{ $case: 'userName' | 'groupName' | 'servicePrincipalName', ... }`). The `grants` package punts. The type system has no way to tell whether `principal` is an email, a group name, or a service principal name. -- **Category:** 1 (vague), 15 (generic field name), 19 (underspecified identifier), 12 (overlap with `permissions` package's typed approach). -- **Suggested name:** `principalName` (matching the `permissions` package, which uses `principalName?: { $case: 'userName' | ... }`); or, better, model the same discriminated union here. -- **Rationale:** "Principal" is overloaded across identity systems (security principal, business principal, mathematical principal, principal-of-the-school). The doc-comment is the only disambiguating signal. - -### 5. `securableFullName` (field, repeated across request types) — `src/v1/model.ts:31,67,125` -- **Why weird:** Verbose redundant naming — `securableType` + `securableFullName` repeats the `securable` prefix on consecutive fields. The `securableType` already establishes context, so the second field could be just `fullName`. The Go SDK uses the verbose form for proto compatibility, but TypeScript readers don't gain anything from the duplication. -- **Category:** 7 (overly verbose), 15 (generic field name). -- **Suggested name:** `fullName`. -- **Rationale:** Internal consistency — many other UC-adjacent packages just use `fullName` because `securableType` already discriminates. - -### 6. `GetEffectivePermissionsRequest_Response` — `src/v1/model.ts:53,163` +- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file). +- **Rationale:** Internal vocabulary consistency. + +### 3. `GetEffectivePermissionsRequest_Response` — `src/v1/model.ts:53,163` - **Why weird:** Proto-architectural leak. The `Request_Response` underscore-separated name encodes the proto-style nested-message hierarchy (a `Response` message nested inside the `GetEffectivePermissionsRequest` enclosing message). TypeScript readers see a foreign tooling artifact, not an idiomatic type name. The companion `unmarshalGetEffectivePermissionsRequest_ResponseSchema` constant and the inline ESLint-disable comments (`Proto-style nested message name.`) confirm the leak is intentional but unidiomatic. - **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). - **Suggested name:** `GetEffectivePermissionsResponse`. - **Rationale:** TypeScript has no notion of nested-message scoping; the underscore exists solely to mirror `message Foo { message Response { ... } }` in the source proto. Flattening to `GetEffectivePermissionsResponse` matches the rest of the SDK's response-type convention. -### 7. `GetPermissionsRequest_Response` — `src/v1/model.ts:89,177` -- **Why weird:** Same proto-architectural leak as #6. The `Request_Response` underscore-separated form is a direct port of a proto-nested message name; the accompanying schema constant (`unmarshalGetPermissionsRequest_ResponseSchema`) and the `Proto-style nested message name.` ESLint-disable comment make the proto origin explicit. +### 4. `GetPermissionsRequest_Response` — `src/v1/model.ts:89,177` +- **Why weird:** Same proto-architectural leak as #3. The `Request_Response` underscore-separated form is a direct port of a proto-nested message name; the accompanying schema constant (`unmarshalGetPermissionsRequest_ResponseSchema`) and the `Proto-style nested message name.` ESLint-disable comment make the proto origin explicit. - **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). - **Suggested name:** `GetPermissionsResponse`. -- **Rationale:** See #6. +- **Rationale:** See #3. -### 8. `UpdatePermissionsRequest_Response` — `src/v1/model.ts:131,202` -- **Why weird:** Same proto-architectural leak as #6 and #7. The `Request_Response` naming and the `unmarshalUpdatePermissionsRequest_ResponseSchema` schema constant both carry the proto nested-message marker. +### 5. `UpdatePermissionsRequest_Response` — `src/v1/model.ts:131,202` +- **Why weird:** Same proto-architectural leak as #3 and #4. The `Request_Response` naming and the `unmarshalUpdatePermissionsRequest_ResponseSchema` schema constant both carry the proto nested-message marker. - **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). - **Suggested name:** `UpdatePermissionsResponse`. -- **Rationale:** See #6. +- **Rationale:** See #3. --- ## Medium severity -### 9. `EffectivePrivilege.privilege` — `src/v1/model.ts:7` -- **Why weird:** `EffectivePrivilege.privilege` — the field repeats the type name. Inside a `EffectivePrivilege` object, what else could `.privilege` mean? The type is essentially `(privilege, inheritedFromType, inheritedFromName)`. Naming the carrier field after the parent type adds zero info. -- **Category:** 20 (type-suffix tautology), 1 (vague — the doc says "The privilege assigned to the principal" but the type is `string`, untyped). -- **Suggested name:** `name` (since this is the name of a single privilege like `"SELECT"`), or — if keeping `privilege` — change the type to a proper enum (see #10). -- **Rationale:** A field on `X` named `x` is canonically a code smell. - -### 10. `EffectivePrivilege.inheritedFromType` — `src/v1/model.ts:12` -- **Why weird:** Type is `string`, but the doc says "type of the object that conveys this privilege via inheritance" — i.e. a securable type like `CATALOG`, `SCHEMA`, `TABLE`. The package elsewhere talks about `securableType` (also `string`), but there's no enum and no link. A more typed approach would be `SecurableType` (an enum). The name promises a typed handle but the field is free-form text. -- **Category:** 6 (misleading: name implies type, value is string), 19 (underspecified). -- **Suggested name:** `inheritedFromSecurableType` (clarifies what kind of type) — and ideally typed as an enum. -- **Rationale:** "Type" without qualification is ambiguous; consistent with how `securableType` is named elsewhere in the file, this field should be a securable type. - -### 11. `EffectivePrivilege.inheritedFromName` — `src/v1/model.ts:17` -- **Why weird:** Generic "name" field on a non-`Name`-typed thing. Pair with `inheritedFromType` it's clear, but in isolation `inheritedFromName: string | undefined` is just "some string". Doc-comment is required reading. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `inheritedFromFullName` (matching `securableFullName` elsewhere). -- **Rationale:** Internal consistency — the rest of the file uses `fullName` / `securableFullName`. - -### 12. `maxResults` (field, repeated) — `src/v1/model.ts:47,83` -- **Why weird:** Could be `pageSize` (more idiomatic for paginated APIs). Long doc-comment (60+ lines, mostly duplicated between the two request types) explains a "150 minimum" page-length rule that lives in two places with no cross-reference. -- **Category:** 7 (verbose). -- **Suggested name:** `pageSize` (more conventional) or keep `maxResults` but extract the shared documentation. -- **Rationale:** Cross-package consistency — many other paginated APIs use `pageSize`. - -### 13. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,106,108,118`) +### 6. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,106,108,118`) - **Why weird:** Every privilege is typed as a free-form `string`. The Go SDK and Databricks UC API have a fixed enum of privilege names (`SELECT`, `MODIFY`, `USE_CATALOG`, `USE_SCHEMA`, `EXECUTE`, `CREATE_*`, `READ_VOLUME`, `WRITE_VOLUME`, etc.). The TS SDK exposes them as bare strings with no autocomplete, no type-checking, no documentation. A typo like `"SELCT"` will silently round-trip to the server. - **Category:** 19 (underspecified), 1 (vague: `string` doesn't constrain meaning). - **Suggested name:** Define a `Privilege` enum (or string literal union). At minimum document the valid values inline. - **Rationale:** Type-safety is the entire point of TypeScript. The audit task explicitly flags "long enum values (many privilege values)" — the irony is that grants HAS the most privilege values of any UC operation and exposes ZERO of them as types. -### 14. `PermissionsChange.add` / `PermissionsChange.remove` — `src/v1/model.ts:106,108` -- **Why weird:** Bare verb-shaped field names with no clarifying suffix. `add: string[]` and `remove: string[]` on a `PermissionsChange` type — what are they adding to and removing from? The doc-comments tell you ("The set of privileges to add"), but the field names are anonymous. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `addPrivileges` / `removePrivileges`, or `granted` / `revoked`. -- **Rationale:** Common to see `add` / `remove` in change-set APIs (e.g. Kubernetes RBAC, AWS IAM), but those typically pair with a typed item collection. A bare `add: string[]` carries no information. - -### 15. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` +### 7. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` - **Why weird:** Three-word PascalCase name (`Effective` + `Privilege` + `Assignment`) that on first read parses as "Effective Privilege" / "Assignment" but on second read could parse as "Effective" / "Privilege Assignment". The conceptual model is "the privilege assignment that effectively applies (because of inheritance)", which the doc-comment confirms — but the name doesn't disambiguate. - **Category:** 7 (overly verbose). - **Suggested name:** Possibly leave as-is; alternative is `EffectiveAssignment` (drop `Privilege` since `Assignment` is privilege-specific in this file). - **Rationale:** Marginal; flagged for symmetry with `EffectivePrivilege` (line 5). -### 16. `privilegeAssignments` (field name, multiple) — `src/v1/model.ts:60,96,133` -- **Why weird:** Field name `privilegeAssignments` appears as the sole payload field on multiple response types (`GetEffectivePermissionsRequest_Response`, `GetPermissionsRequest_Response`, `UpdatePermissionsRequest_Response`). Could be `assignments` everywhere since the surrounding type name carries the rest of the qualifier. -- **Category:** 7 (verbose), 20 (type-suffix tautology — field name repeats type-name fragment). -- **Suggested name:** `assignments`. -- **Rationale:** Field names that re-state the parent type are noise. - -### 17. `securableType: string` — model-wide (3 occurrences at `src/v1/model.ts:29,65,123`) -- **Why weird:** Same concept as #10 — free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. +### 8. `securableType: string` — model-wide (3 occurrences at `src/v1/model.ts:29,65,123`) +- **Why weird:** Free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. - **Category:** 19 (underspecified), 1 (vague). - **Suggested name:** Define a `SecurableType` enum. -- **Rationale:** See #10. +- **Rationale:** Type-safety; closed sets should be enums. --- ## Low severity -### 18. `Client` — `src/v1/client.ts:41` +### 9. `Client` — `src/v1/client.ts:41` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts` re-exports `Client` (line 3), so users write `import { Client } from '@databricks/sdk-grants/v1'`. Same name appears in every generated package — you can't have multiple grants/catalogs/etc. clients in one import without aliasing. - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `GrantsClient` (or whatever the package-specific name is). - **Rationale:** Convention in `@aws-sdk/*`, `@google-cloud/*`, `@azure/*` is service-prefixed client class names for exactly this reason. -### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 10. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** `Segment` is a generic word; without the doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 20. `HttpCallOptions` — `src/v1/utils.ts:15` +### 11. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix), 17 (inconsistent). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -154,23 +100,8 @@ The grants package contains 9 generated types and 3 client methods covering one ## Observations -### 21. `Client` constructor: `Host is required.` — `src/v1/client.ts:52` +### 12. `Client` constructor: `Host is required.` — `src/v1/client.ts:52` Error message thrown but no client name in the message. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. - **Category:** Observation. --- - -## Fixed - -- #1 `GetPermissions` (originally cited at `src/v1/model.ts:63`): Fixed in regeneration on 2026-05-20 — renamed to `GetPermissionsRequest` with the `Request` suffix. -- #2 `UpdatePermissions` (originally cited at `src/v1/model.ts:197`): Fixed in regeneration on 2026-05-20 — renamed to `UpdatePermissionsRequest` with the `Request` suffix. -- #3 `GetEffectivePermissions` (originally cited at `src/v1/model.ts:27`): Fixed in regeneration on 2026-05-20 — renamed to `GetEffectivePermissionsRequest` with the `Request` suffix. -- #5 `GetPermissions` vs `ListPrivilegeAssignmentsRequest` duplication (originally cited at `src/v1/model.ts:63,129`): Fixed in regeneration on 2026-05-20 — the `ListPrivilegeAssignmentsRequest` type and its `listPrivilegeAssignments` method were removed, collapsing the operation to a single `GetPermissionsRequest`. -- #6 `GetEffectivePermissions` vs `ListEffectivePrivilegeAssignmentsRequest` duplication (originally cited at `src/v1/model.ts:27,101`): Fixed in regeneration on 2026-05-20 — the `ListEffectivePrivilegeAssignmentsRequest` type and its `listEffectivePrivilegeAssignments` method were removed. -- #10 `principalId` field (originally cited at `src/v1/model.ts:182,194`): Fixed in regeneration on 2026-05-20 — the `principalId` field was removed from both `PermissionsChange` and `PrivilegeAssignment`. -- #11 `securableFullName` vs `fullName` inconsistency (originally cited at `src/v1/model.ts:31,67,201` vs `105,133`): Fixed in regeneration on 2026-05-20 — the `fullName`-spelled `List*Request` types were removed; only the `securableFullName` spelling remains (now tracked as a verbosity finding #5). -- #15 `maxResults` vs `pageSize` inconsistency (originally cited at `src/v1/model.ts:47,83,114,151`): Fixed in regeneration on 2026-05-20 — the `pageSize`-using `List*Request` types were removed; only `maxResults` remains (verbosity tracked as #9). -- #19 `effectivePrivilegeAssignments` field (originally cited at `src/v1/model.ts:121`): Fixed in regeneration on 2026-05-20 — the `ListEffectivePrivilegeAssignmentsResponse` type was removed; only the shorter `privilegeAssignments` field remains (tracked as #13). -- #21 `getEffectivePermissions` deprecation (originally cited at `src/v1/client.ts:82`): Fixed in regeneration on 2026-05-20 — the duplicated paginated `listEffectivePrivilegeAssignments` method was removed, so this is no longer a deprecation-versus-mirror concern. -- #22 `getPermissions` deprecation (originally cited at `src/v1/client.ts:129`): Fixed in regeneration on 2026-05-20 — the duplicated paginated `listPrivilegeAssignments` method was removed, so this is no longer a deprecation-versus-mirror concern. -- #24 `includeDeletedPrincipals` inconsistency (originally cited at `src/v1/model.ts:87,109,136`): Fixed in regeneration on 2026-05-20 — the `includeDeletedPrincipals` field was removed from the surviving request types. diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md index 75306a02..6d5f2b1c 100644 --- a/.agent/naming-audit/iam.md +++ b/.agent/naming-audit/iam.md @@ -10,11 +10,11 @@ resolve-by-external-id flows that bridge the customer IdP to Databricks. | Severity | Count | | -------- | ----- | -| High | 8 | -| Medium | 12 | +| High | 6 | +| Medium | 10 | | Low | 10 | | Observation | 3 | -| **Total** | **33** | +| **Total** | **29** | Three dominant themes remain. **First, the package still ships methods, requests, and a handful of variants in parallel `*` and `*Proxy` forms** that @@ -98,40 +98,11 @@ beyond Java-RPC habit. varies per usage: `accountUserStatus`, `accountSpStatus`, plain `status` — three different field names for the same enum domain across three types. - **Suggestion:** Rename the enum to `ActivityStatus` (or `PrincipalStatus`). - Standardize the field name to `status` everywhere. - **Rationale:** A 3-letter enum with 2 values and the name `State` is a textbook example of a name that says nothing about the domain. JSDoc-only context is not enough. -### H4. `User.username` vs `User.name` — name field collision -- **File:** `model.ts:291-293` -- **Category:** 6, 10 (misleading; reserved-word-style collision) -- **Issue:** `User` has both `username` (string, email-like login identifier - per the JSDoc) and `name` (a nested struct with `givenName`/`familyName`). - In English `name` and `username` are near-synonyms and users routinely - conflate them. A developer auto-completing `user.` sees two `*name*` - fields with no hint at the difference. -- **Suggestion:** Rename `User.name` to `User.fullName` (or `personName`). - Rename `User.username` to `User.email` if the value is always an email - (the JSDoc says "Username/email of the user"), or `User.loginName` - otherwise. -- **Rationale:** Disambiguates two semantically distinct identifiers. - -### H5. `accountSpStatus` field uses cryptic abbreviation `Sp` -- **File:** `model.ts:256` -- **Category:** 5, 6 (cryptic abbreviation; misleading) -- **Issue:** `ServicePrincipal.accountSpStatus?: State`. `Sp` is a Databricks - internal shorthand for "service principal". Externally it reads as - "Spanish" or simply opaque. The parallel field on `User` is - `accountUserStatus`, which is spelled out. Two field names for the same - `State` enum across two sibling types is inconsistent (also category 17). -- **Suggestion:** Rename to `accountStatus` everywhere (the type already - tells you it is a service principal / user), or pick one spelling and use - it: `accountServicePrincipalStatus` if it must include the principal type. -- **Rationale:** Abbreviation `Sp` is opaque to external developers and - inconsistent with the spelled-out `User` sibling. - -### H6. `WorkspaceAccessDetail` and `WorkspaceAssignmentDetail` — two overlapping "Detail" types +### H4. `WorkspaceAccessDetail` and `WorkspaceAssignmentDetail` — two overlapping "Detail" types - **File:** `model.ts:305-318, 321-330`, plus the methods they appear in - **Category:** 1, 12, 7 (vague generic suffix; duplicate concept; verbose) - **Issue:** Two top-level types with the `Detail` suffix model overlapping @@ -151,7 +122,7 @@ beyond Java-RPC habit. (`getWorkspaceAccessDetail`, `listWorkspaceAssignmentDetails`, `updateWorkspaceAssignmentDetail`, …) inherit the noise. -### H7. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly +### H5. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly - **File:** `model.ts:36-40` - **Category:** 1, 14 (vague; Google/proto-style) - **Issue:** Values are `BASIC`, `FULL`. The type is a [Google AIP-157 @@ -163,10 +134,10 @@ beyond Java-RPC habit. - **Suggestion:** `enum FieldView { BASIC = 'BASIC', FULL = 'FULL' }`, reusable across the SDK. Or rename to `WorkspaceAccessView` and document what each enum value includes/excludes. -- **Rationale:** `Detail` in the name is the same `Detail` flagged in H6 and +- **Rationale:** `Detail` in the name is the same `Detail` flagged in H4 and carries no extra meaning. -### H8. `principalType: PrincipalType` — type-suffix tautology pattern +### H6. `principalType: PrincipalType` — type-suffix tautology pattern - **File:** `model.ts:312, 328` - **Category:** 20 (type-suffix tautology) - **Issue:** The field `principalType: PrincipalType | undefined` appears on @@ -174,8 +145,7 @@ beyond Java-RPC habit. type name reads `principalType: PrincipalType` — the type name is in the field name. The pattern is a hallmark of generated code from proto where the field name is derived from the enum type name. -- **Suggestion:** Either drop the type from the field name (`type: - PrincipalType`) or drop the type suffix from the enum (`PrincipalKind` +- **Suggestion:** Drop the type suffix from the enum (`PrincipalKind` with field `principalType` reading `principal.type = "USER"` works, but `principal: PrincipalKind` is even cleaner). - **Rationale:** Tautology adds visual noise without adding meaning. @@ -194,7 +164,7 @@ beyond Java-RPC habit. `ListWorkspaceAssignmentDetailsProxyRequest` (42), `GetWorkspaceAssignmentDetailProxyRequest` (40). Plus the imports list in `client.ts` repeats them, doubling the noise. -- **Suggestion:** Once H1 collapses the proxy duplication and H6 drops +- **Suggestion:** Once H1 collapses the proxy duplication and H4 drops `Detail`, these become `CreateWorkspaceAssignmentRequest` etc. — about 30 chars each. - **Rationale:** Length itself is not a sin, but `43 chars × 2 × @@ -229,23 +199,7 @@ beyond Java-RPC habit. - **Rationale:** Four IDs on one struct is a lot; each one needs to be obviously distinct in purpose. -### M4. `workspaceAssignmentDetail` field repeats type name -- **File:** `model.ts:64, 74, 264, 278` -- **Category:** 20 (type-suffix tautology) -- **Issue:** `CreateWorkspaceAssignmentDetailRequest.workspaceAssignmentDetail?: WorkspaceAssignmentDetail | undefined`. -- **Suggestion:** Rename field to `assignment` (after H6 drops `Detail`, - the type is `WorkspaceAssignment` and `assignment` reads naturally). -- **Rationale:** Field name echoing the type name adds no information. - -### M5. `servicePrincipal` field repeats type name -- **File:** `model.ts:215` -- **Category:** 20 (type-suffix tautology) -- **Issue:** `ResolveServicePrincipalResponse.servicePrincipal?: ServicePrincipal | undefined`. -- **Suggestion:** Rename to `principal` or `sp` (consistent with the rest - of the response bodies, e.g. `user` on `ResolveUserResponse`). -- **Rationale:** Field name echoing the type name adds no information. - -### M6. `Group.accountId` doc — "The parent account ID for group in " (missing article) +### M4. `Group.accountId` doc — "The parent account ID for group in " (missing article) - **File:** `model.ts:131-132` - **Category:** 6 (misleading via grammar) - **Issue:** Doc reads "The parent account ID for group in " — @@ -257,9 +211,9 @@ beyond Java-RPC habit. - **Suggestion:** Standardize to "Databricks account ID of the parent account." or just "Parent Databricks account ID." - **Rationale:** Consistency + grammar; the `` template marker - also needs to go (see M7). + also needs to go (see M5). -### M7. `` proto template markup throughout JSDoc blocks +### M5. `` proto template markup throughout JSDoc blocks - **File:** `model.ts` everywhere, e.g. `25, 29, 31, 63, 73, 79, 89, 131, 133`; `client.ts:286, 287, 323` - **Category:** 14 (Go/proto-style markup leak) - **Issue:** The literal string `` appears 25+ times across the @@ -274,7 +228,7 @@ beyond Java-RPC habit. - **Rationale:** Public docs leaking template syntax is the most visible proto-leak across the SDK. -### M8. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` +### M6. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` - **File:** `model.ts:269` - **Category:** 6 (misleading) - **Issue:** The doc on `UpdateWorkspaceAssignmentDetailRequest` is literally @@ -284,7 +238,7 @@ beyond Java-RPC habit. - **Suggestion:** Replace with the real description. - **Rationale:** Placeholder docs degrade developer trust. -### M9. `resolveByExternalId` URL segment uses camelCase +### M7. `resolveByExternalId` URL segment uses camelCase - **File:** `client.ts:105, 134, 163, 198, 233, 262` - **Category:** 14, 3 (Go-style; casing) - **Issue:** The URL paths use `/resolveByExternalId` in camelCase. The URLs @@ -294,7 +248,7 @@ beyond Java-RPC habit. - **Suggestion:** Server-side fix (out of scope), but flag to the API team. - **Rationale:** Not the SDK's bug, but reflects an upstream inconsistency. -### M10. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields +### M8. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields - **File:** `model.ts:317, 329` - **Category:** 12, 6 (duplicate concepts; misleading) - **Issue:** `WorkspaceAccessDetail.permissions` (USER_PERMISSION / @@ -308,7 +262,7 @@ beyond Java-RPC habit. both JSDoc blocks. If they are the same, merge. - **Rationale:** This is the kind of overlap that produces support tickets. -### M11. `resolveByExternalId` method naming +### M9. `resolveByExternalId` method naming - **File:** `client.ts:101, 159, 229` - **Category:** 17 (verb inconsistency) - **Issue:** `resolveGroup`, `resolveUser`, `resolveServicePrincipal`. These @@ -321,7 +275,7 @@ beyond Java-RPC habit. semantic prominently. - **Rationale:** Method names should not hide write side-effects. -### M12. JSDoc text "(workspace-level proxy)" surfaces routing architecture on five methods +### M10. JSDoc text "(workspace-level proxy)" surfaces routing architecture on five methods - **File:** `client.ts:392, 451, 499, 561, 645` - **Category:** 14 (proto/Go-style architectural leak in docs) - **Issue:** Five methods include the parenthetical "(workspace-level proxy)" @@ -455,7 +409,7 @@ beyond Java-RPC habit. - **File:** `client.ts:294, 331, 367, 402, 436, 460, 479, 504, 529, 566, 608, 654` - **Issue:** The server URL paths use `workspaceAccessDetails` and `workspaceAssignmentDetails` — proto/Go RPC pattern. The SDK reflects the - server names. Renaming the TS types per H6 does not change the wire; the + server names. Renaming the TS types per H4 does not change the wire; the SDK can have nicer TS names while still hitting `workspaceAccessDetails` URLs. @@ -480,47 +434,12 @@ beyond Java-RPC habit. 1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O2, O3).** This is the largest single improvement and ~halves the public type surface. -2. **Replace `` template markup (M7).** Generator-side fix. -3. **Standardize ID field names (L1, L10) and status field names (H3, H5).** +2. **Replace `` template markup (M5).** Generator-side fix. +3. **Standardize ID field doc strings (L1, L10) and the `State` enum name (H3).** One name per concept. -4. **Remove type-suffix tautology fields (H8, M4, M5).** Single-token - field names where the type already carries the kind. -5. **Drop the `Detail` suffix from the Workspace* types (H6).** -6. **Rewrite the placeholder JSDocs (M8).** Generator + spec fix. +4. **Remove type-suffix tautology on the `PrincipalType` enum (H6).** Drop + the type suffix from the enum name. +5. **Drop the `Detail` suffix from the Workspace* types (H4).** +6. **Rewrite the placeholder JSDocs (M6).** Generator + spec fix. --- - -## Fixed - -- #H14 `AccountAccessIdentityRule.name` (originally cited at `model.ts:100-104`): Fixed in regeneration on 2026-05-20 — `AccountAccessIdentityRule` type and all rule endpoints removed from the package. -- #H15 `parent` field on rule endpoints (originally cited at `model.ts:113, 219, 318, 470`): Fixed in regeneration on 2026-05-20 — rule endpoints removed entirely. -- #M4 `GroupMembershipSource` enum (originally cited at `model.ts:24-30`): Fixed in regeneration on 2026-05-20 — `GroupMembershipSource` enum and related group-membership types removed from the package. -- #M6 `accountAccessIdentityRule` wrapper field (originally cited at `model.ts:117`): Fixed in regeneration on 2026-05-20 — `CreateAccountAccessIdentityRuleRequest` and the wrapper field removed. -- #M7 `directGroupMember` wrapper field (originally cited at `model.ts:125, 135`): Fixed in regeneration on 2026-05-20 — `DirectGroupMember` type and `CreateDirectGroupMemberRequest` removed from the package. -- #M9 `workspaceIdentityDetail` wrapper field (originally cited at `model.ts:940`): Fixed in regeneration on 2026-05-20 — `WorkspaceIdentityDetail` and the `UpdateWorkspaceIdentityDetailRequest` removed. -- #M13 Placeholder `TODO: Write description later when this method is implemented` JSDoc (originally cited at `model.ts:138, 144, 152, …` and 22 places in `client.ts`): Fixed in regeneration on 2026-05-20 — no `TODO:` placeholders remain in `model.ts` or `client.ts`. -- #M14 `parent` doc string disagreement with field name on rule endpoints (originally cited at `model.ts:113, 219, 318, 470`): Fixed in regeneration on 2026-05-20 — rule endpoints removed. -- #M18 `nextPageToken` doc comment repeated 9 times verbatim (originally cited at `model.ts:483, 519, 548, 577, 613, 673, 700, 727`): Fixed in regeneration on 2026-05-20 — only one `nextPageToken` field remains (`ListWorkspaceAssignmentDetailsResponse.nextPageToken`); no repetition left. -- #M19 `ListGroupsRequest.filter` JSDoc (originally cited at `model.ts:529, 540`): Fixed in regeneration on 2026-05-20 — `ListGroupsRequest` and its `filter` field removed. -- #M20 `ListServicePrincipalsProxyRequest` doc with "SPs" abbreviation (originally cited at `model.ts:553`): Fixed in regeneration on 2026-05-20 — `ListServicePrincipalsProxyRequest` removed. -- #L5 `pageSize` JSDoc varying with/without "Optional." prefix (originally cited at `model.ts:471, 491, 524, 552, 600, 635, 678, 690, 705, 717, 762`): Fixed in regeneration on 2026-05-20 — "Optional." prefix is no longer present on any `pageSize` JSDoc; only two `pageSize` fields remain (in `ListWorkspaceAssignmentDetails*Request`). -- #L6 `filter` JSDoc varying (originally cited at `model.ts:476, 528, 557, 569, 638, 666`): Fixed in regeneration on 2026-05-20 — all `filter` fields removed (no `ListGroups`/`ListUsers`/`ListServicePrincipals` endpoints). -- #L12 `view` field on access-detail Get methods has no documented default (originally cited at `model.ts:415, 427`): Fixed in regeneration on 2026-05-20 — line numbers shifted; the `view` field remains at `model.ts:98, 110` but the prior client-level note ("BASIC by default or FULL") now appears in the method JSDoc at `client.ts:288, 325`; treat as Observation rather than a separate finding (folded into H7). -- #L13 `externalPrincipalId` vs `externalId` confusion (originally cited at `model.ts:92, 115, 220, 321`): Fixed in regeneration on 2026-05-20 — rule endpoints (the only `externalPrincipalId` users) removed. -- #L14 `IdP` capitalization variance (originally cited at `model.ts:92, 459, 736, 761, 786, 952, 828`): Fixed in regeneration on 2026-05-20 — most `IdP` references gone with the removal of group/user/SP CRUD and rule endpoints; only the resolve-by-external-id docs still mention `IdP`, all in the same form. -- #L15 `next_page_token` snake_case in JSDoc (originally cited at `model.ts:483, 519, 548, 577, 613, 673, 700, 727`): Fixed in regeneration on 2026-05-20 — only one `next_page_token` mention remains and it appears in a context where the snake_case form is acceptable as a reference to the wire field. -- #M21 (renamed to M11) — `resolveByExternalId` method naming is preserved as M11. -- #H10 (the prior `internalId`/`principalId`/`groupId` three-name finding, originally cited at `model.ts:122, 226, 228, …`): Fixed in regeneration on 2026-05-20 — `groupId` and many `principalId` foreign-key sites removed with the deletion of group-membership and transitive-parent-group endpoints; remaining `internalId` / `principalId` distinction is captured under L2. -- #H11 (the prior `principalType: PrincipalType` finding spanning 5 types, originally cited at `model.ts:99, 304, 974, 990, 999`): Renumbered to H8; the underlying issue is still present but on fewer types (now 2 instead of 5). -- #H12 (the prior `Group.groupName` tautology finding, originally cited at `model.ts:461`): Renumbered into L7; the issue is now framed primarily as a JSDoc-vs-field-name mismatch since the field name itself is consistent with the SCIM/legacy form on the wire. -- #H13 (the prior `ServicePrincipal.internalId` doc tautology finding, originally cited at `model.ts:809-810`): Folded into L10 — the documentation-only aspect (per-type self-referential phrasing and the `userId` typo) is what remains. -- #M8 (the prior `workspaceAssignmentDetail` finding) → renumbered M4. -- #M10 (the prior `servicePrincipal` finding) → renumbered M5. -- #M11 (the prior `Group.accountId` doc finding) → renumbered M6. -- #M12 (the prior `` markup finding) → renumbered M7. -- #M15 (the prior "TBD" doc finding) → renumbered M8. -- #M16 (the prior `resolveByExternalId` URL casing finding) → renumbered M9. -- #M17 (the prior permissions-vs-entitlements finding) → renumbered M10. -- #H4 (the prior `PrincipalType` enum-name prefix finding, originally cited at `model.ts:18-23`): Pruned on 2026-05-20 — proto-style enum-name prefix on members is intentional and not a real issue. -- #M4 (the prior `WorkspacePermission.USER_PERMISSION` enum-member suffix finding, originally cited at `model.ts:43-48`): Pruned on 2026-05-20 — proto-style enum-name affix on members is intentional and not a real issue. -- #H7 (the prior "every enum has `_UNSPECIFIED` zero value" finding, originally cited at `model.ts:8, 19, 28, 37, 44, 54`): Pruned on 2026-05-20 — proto3 mandates a zero-value enum member; `UNSPECIFIED` is intentional. diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md index 6bae310c..24f2c69a 100644 --- a/.agent/naming-audit/indexes.md +++ b/.agent/naming-audit/indexes.md @@ -222,14 +222,3 @@ - **Category:** Observation on the public surface. - **Suggested name:** Either rename per #1 or remove from the public surface. - **Rationale:** Consumers will use whatever is exported; if `MiniVectorIndex` is a name we'd prefer not to commit to publicly, it should be hidden. - -## Fixed - -- #1 Package name `indexes` is generic (originally cited at `packages/indexes/`): Fixed in regeneration on 2026-05-20 — package renamed to `vectorsearch` and merged with the vector-search endpoint API; the package name now matches the domain. -- #2 Package name singular/plural mismatch (originally cited at `packages/indexes/` vs `VectorIndex`, `model.ts:425`): Fixed in regeneration on 2026-05-20 — package renamed to `vectorsearch` (a domain name, not a plural list), resolving the singular/plural conflict. -- #12 `effectiveBudgetPolicyId` and `effectiveUsagePolicyId` on `DeltaSyncVectorIndexSpec[Request]` (originally cited at `model.ts:133-134, 168-169`): Fixed in regeneration on 2026-05-20 — both `effective*` fields removed from `DeltaSyncVectorIndexSpec` and `DeltaSyncVectorIndexSpecRequest`; budget/usage policy IDs now live only on `Endpoint`/`CreateEndpointRequest` where the `effective*` distinction is coherent. -- #20 `effectiveBudgetPolicyId` on a request type without JSDoc explanation (originally cited at `model.ts:133, 168`): Fixed in regeneration on 2026-05-20 — `effective*` fields removed from `DeltaSyncVectorIndexSpecRequest`; this finding is now fully covered by #12. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 5448cb3e..efcbf102 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -21,11 +21,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 9 | -| Medium | 7 | -| Low | 16 | +| High | 8 | +| Medium | 2 | +| Low | 12 | | Observation | 7 | -| **Total** | **39**| +| **Total** | **29**| ### Top themes @@ -111,20 +111,17 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `DockerImage.credsOneof` | High | `credsOneof` is a Go/proto-codegen leak — TS readers do not know what "Oneof" means in this context (the wire field uses a protobuf `oneof`). The "creds" abbreviation is also generic. Should be `credentials` (and the union shape itself satisfies the discriminator). | -| V-02 | `PendingInstanceError.message` | Medium | `message` is generic. Could be `errorMessage` to match the type's purpose, or the type itself could be flattened. | -| V-03 | `readAll` (`utils.ts:40`) | Low | Standard name for a read-to-end helper. | -| V-04 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | -| V-05 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | +| V-02 | `readAll` (`utils.ts:40`) | Low | Standard name for a read-to-end helper. | +| V-03 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | +| V-04 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | ### 2.2 Acronym casing inconsistencies — High | ID | Symbol | Severity | Issue | | ----- | ------------------------------------- | -------- | ----- | | A-01 | `InstancePoolAwsAttributes` | High | Google TS style says acronyms ≥3 chars get only-first-letter capitalised ("AWS" → "Aws"). The repo follows this (Aws/Azure/Gcp). Acceptable, but contrasts with `EbsVolumeType` where `Ebs` is only 3 chars (same rule, applied consistently). No defect — listed for parity with related audits. | -| A-02 | `InstancePoolGcpAttributes.gcpAvailability` | High | The field name re-states the cloud already implied by the parent type `InstancePoolGcpAttributes`. Compare with `InstancePoolAwsAttributes.availability` (line 635) and `InstancePoolAzureAttributes.availability` (line 673) — both unprefixed. Three sibling types, two conventions. Should be `InstancePoolGcpAttributes.availability`. | -| A-03 | `InstancePoolAwsAttributes.instanceProfileArn` | Low | "Arn" applies Google TS style for ≥3-char acronyms. Compare with `EbsVolumeType` (same package) and consistent. OK. | -| A-04 | `InstancePoolGcpAttributes.localSsdCount` | Low | "Ssd" is 3 letters; same casing rule. OK. | -| A-05 | `InstancePoolAzureAttributes.spotBidMaxPrice` vs `InstancePoolAwsAttributes.spotBidPricePercent` | Medium | Sibling fields describe the same concept (max price for spot bid) in opposite shapes. `MaxPrice` is an absolute USD value; `PricePercent` is relative. Names obscure this — `azureSpotBidMaxPriceUsd` and `awsSpotBidPricePercent` (or any clarifying suffix) would help. | +| A-02 | `InstancePoolAwsAttributes.instanceProfileArn` | Low | "Arn" applies Google TS style for ≥3-char acronyms. Compare with `EbsVolumeType` (same package) and consistent. OK. | +| A-03 | `InstancePoolGcpAttributes.localSsdCount` | Low | "Ssd" is 3 letters; same casing rule. OK. | ### 2.3 Cryptic abbreviations — Medium @@ -145,27 +142,22 @@ configuration, idle / used statistics, and pending-instance failure reporting. | M-01 | `editInstancePool()` / `EditInstancePoolRequest` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | | M-02 | `InstancePoolStatus` | High | The type carries *only* `pendingInstanceErrors`. The name promises a general "status" but the shape exposes only errors. `InstancePoolPendingErrors` or `InstancePoolFailures` would be more truthful. (`InstancePoolState` is the actual lifecycle state, on the entity itself.) | | M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 28 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | -| M-04 | `DiskSpec.diskCount`, `diskSize`, `diskIops`, `diskThroughput` | Low | Repetition of the `disk` prefix inside a type named `DiskSpec`. Inside the type, `count` / `size` / `iops` / `throughput` would suffice. Same pattern as `clusters.md` flagged elsewhere. | -| M-05 | `DiskSpec.diskIops` (no JSDoc) and `diskSpec.diskThroughput` (no JSDoc) — `model.ts:239-240` | Low | Two fields with no JSDoc. Hard to know the unit without context. (Compare neighbouring `diskSize` which documents "GiB".) | -| M-06 | `preloadedDockerImages` is plural but JSDoc says "Custom Docker Image BYOC" (singular) — `model.ts:141, 323, 445, 574` | Low | Field is `DockerImage[]`. Plural correctly matches type, but the JSDoc is misleading. | -| M-07 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | -| M-08 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | +| M-04 | `DiskSpec.diskIops` (no JSDoc) and `diskSpec.diskThroughput` (no JSDoc) — `model.ts:239-240` | Low | Two fields with no JSDoc. Hard to know the unit without context. (Compare neighbouring `diskSize` which documents "GiB".) | +| M-05 | `preloadedDockerImages` is plural but JSDoc says "Custom Docker Image BYOC" (singular) — `model.ts:141, 323, 445, 574` | Low | Field is `DockerImage[]`. Plural correctly matches type, but the JSDoc is misleading. | +| M-06 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | +| M-07 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | -### 2.5 Overly verbose / Redundant suffixes — Medium +### 2.5 Overly verbose / Redundant suffixes — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| O-01 | `idleInstanceAutoterminationMinutes` (5-word identifier, present in 4 types) | Medium | 33-char field. Inside a type called `CreateInstancePoolRequest` etc., `idleAutoterminationMinutes` or `idleTimeoutMinutes` would be 27 / 18 chars. The wire uses `idle_instance_autotermination_minutes` so any change is generator-side. | -| O-02 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | -| O-03 | `NodeTypeFlexibility.alternateNodeTypeIds` | Low | Field name re-states `node` twice (once from parent type, once in the field). Could be `alternates` or `fallbacks`. The wire path is the constraint. | -| O-04 | `totalInitialRemoteDiskSize` | Low | 25-char field, four concept words. Reasonable but heavy. | -| O-05 | `spotBidPricePercent` | Low | Five concept words crammed into one camelCase identifier. The JSDoc explains what each part means. | +| O-01 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | ### 2.6 Singular / plural mismatches — Low / High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| P-01 | `preloadedSparkVersions: string[]` | High (also M-07) | Plural array type but the JSDoc constrains it to at most one element. | +| P-01 | `preloadedSparkVersions: string[]` | High (also M-06) | Plural array type but the JSDoc constrains it to at most one element. | | P-02 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | | P-03 | `ListInstancePoolsRequest` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | | P-04 | `ListInstancePoolsRequest_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | @@ -203,17 +195,15 @@ configuration, idle / used statistics, and pending-instance failure reporting. | G-02 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | | G-03 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | -### 2.11 Generic field names losing meaning — Medium +### 2.11 Generic field names losing meaning — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| F-01 | `DiskType.remoteVolumeType` (outside of `DiskType`) | Medium | When destructured, `remoteVolumeType: EbsVolumeType` reads as a category name colliding with the cloud-specific value. | -| F-02 | `DockerImage.url` (outside of `DockerImage`) | Low | Standard. OK in context. | -| F-03 | `DockerBasicAuth.username` / `password` | Low | Standard. OK. | -| F-04 | `PendingInstanceError.message` | Medium (also V-02) | When destructured, an error `message` field is the generic-est possible name. Adding `instanceMessage` would help. | -| F-05 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | -| F-06 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | -| F-07 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | +| F-01 | `DockerImage.url` (outside of `DockerImage`) | Low | Standard. OK in context. | +| F-02 | `DockerBasicAuth.username` / `password` | Low | Standard. OK. | +| F-03 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | +| F-04 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | +| F-05 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | ### 2.12 Field contradicting type domain — Low @@ -253,7 +243,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ----- | ----------------------------------- | -------- | ----- | | TS-01 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-02). Doubly off. | | TS-02 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | -| TS-03 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix (M-04) the type-name still echoes. | +| TS-03 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix the type-name still echoes. | | TS-04 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | ### 2.17 Other observations @@ -408,11 +398,11 @@ artefact and the leading underscore at the same time. | Severity | Count | | ------------ | ----- | -| High | 9 | -| Medium | 7 | -| Low | 16 | +| High | 8 | +| Medium | 2 | +| Low | 12 | | Observation | 7 | -| **Total** | **39**| +| **Total** | **29**| ## 4. Cross-package consistency notes @@ -434,11 +424,3 @@ artefact and the leading underscore at the same time. - `src/v2/index.ts` (43 lines): read fully. --- - -## Fixed - -- #M-04 `enableAutoAlternateNodeTypes` field (originally cited at `model.ts:164, 353, 482, 618`): Fixed in regeneration on 2026-05-20 — the deprecated field has been removed from all four request/response types. -- #O-02 `enableAutoAlternateNodeTypes` (originally cited at `model.ts:164, 353, 482, 618`): Fixed in regeneration on 2026-05-20 — the deprecated field has been removed; the verbose-identifier concern no longer applies. -- #C-07 `PuPr` in JSDoc `"deprecated before entering PuPr"` (originally cited at `model.ts:164, 353, 482, 618`): Fixed in regeneration on 2026-05-20 — the surrounding deprecated field and its JSDoc were removed. -- #C-08 `Fleet-V2` in JSDoc `"For pools with node type flexibility (Fleet-V2)"` (originally cited within the deprecated `enableAutoAlternateNodeTypes` JSDoc block): Fixed in regeneration on 2026-05-20 — the surrounding deprecated field and its JSDoc were removed. -- #X-03 TODO comment `TODO(CJ-71514): Remove this field after sufficient time has passed for all clients to migrate.` (originally cited at `model.ts:165, 354, 483, 619`): Fixed in regeneration on 2026-05-20 — the surrounding deprecated field and JSDoc with the internal ticket reference were removed. diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index a4fa59cc..5e7a5fd4 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -86,14 +86,13 @@ are graded: ## 2. Findings by Category -### 2.1 Vague / generic names — Medium +### 2.1 Vague / generic names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `InstanceProfile` (interface, `model.ts:64`) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | -| V-02 | `AddInstanceProfileRequest.skipValidation` (`model.ts:14`) | Medium | `skipValidation` is generic — *which* validation? Reading the JSDoc reveals it specifically skips the AWS `RunInstances` dry-run permission check. `skipIamValidation` or `skipPermissionDryRun` would self-document. | -| V-03 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | -| V-04 | `readAll` (`utils.ts:40`, private) | Low | Standard name for "read all bytes from a stream". OK. | +| V-02 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | +| V-03 | `readAll` (`utils.ts:40`, private) | Low | Standard name for "read all bytes from a stream". OK. | ### 2.2 Redundant enum prefixes — N/A @@ -116,16 +115,15 @@ are graded: | ----- | ----------------------------------------------- | -------- | ----- | | U-01 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | -### 2.5 Cryptic abbreviations — Medium +### 2.5 Cryptic abbreviations — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | C-01 | `arn` (within `instanceProfileArn`, `iamRoleArn`) | Low | "ARN" is a well-known AWS acronym; not cryptic in the AWS context. Acceptable. | | C-02 | `iam` (within `iamRoleArn`) | Low | "IAM" = AWS Identity & Access Management. Well-known AWS acronym. Acceptable. | -| C-03 | `meta` (within `isMetaInstanceProfile`) | Medium | "Meta instance profile" is a Databricks-specific term not defined anywhere except the JSDoc ("contains an meta IAM role which could assume a wide range of roles"). The name doesn't make the concept self-evident. `isCredentialPassthrough` or `isAssumableMetaRole` would convey intent better. | -| C-04 | `req`, `resp`, `httpReq`, `respBody` (`client.ts` locals) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | -| C-05 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | -| C-06 | `pkgJson` (`client.ts:19`) | Low | Standard short name for `package.json` import. OK. | +| C-03 | `req`, `resp`, `httpReq`, `respBody` (`client.ts` locals) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | +| C-04 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | +| C-05 | `pkgJson` (`client.ts:19`) | Low | Standard short name for `package.json` import. OK. | ### 2.6 Misleading names — High @@ -135,17 +133,12 @@ are graded: | M-02 | `RemoveInstanceProfileRequest` / `removeInstanceProfile()` (`model.ts:95`, `client.ts:185`) | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | | M-03 | `EditInstanceProfileRequest` / `editInstanceProfile()` (`model.ts:39`, `client.ts:119`) | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | | M-04 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`, `model.ts:66`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | -| M-05 | `skipValidation` (`AddInstanceProfileRequest`, `model.ts:14`) | Medium | The name implies skipping *all* validation; the JSDoc clarifies it only skips the AWS dry-run permission check. See V-02. | -| M-06 | `isMetaInstanceProfile` | Medium | The boolean's semantics ("for credential passthrough scenarios where the instance profile contains a meta-IAM role that can assume a wide range of roles") is much narrower than "is this a meta instance profile". Calling it `isCredentialPassthrough` or `isMetaIamRole` would describe the actual behaviour. | -### 2.7 Overly verbose / Redundant suffixes — Medium +### 2.7 Overly verbose / Redundant suffixes — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| O-01 | `instanceProfileArn` (in `InstanceProfile`, `model.ts:66`) | Medium | Inside a type already called `InstanceProfile`, prefixing the field with `instanceProfile` is redundant — `arn` alone (or `instanceProfileArn` only on request types, with `arn` on the entity) would suffice. Tautology pattern: `instanceProfile.instanceProfileArn`. | -| O-02 | `isMetaInstanceProfile` (in `InstanceProfile`, `model.ts:74`) | Medium | Same tautology: `instanceProfile.isMetaInstanceProfile`. `isMeta` alone (or `isMetaRole`) would suffice within the entity. | -| O-03 | `PACKAGE_SEGMENT` (`client.ts:41`) | Low | OK in context. | -| O-04 | `ListInstanceProfilesRequest_Response.instanceProfiles` (`model.ts:92`) | Medium | Inside `ListInstanceProfilesRequest_Response`, the field `instanceProfiles` re-states the type prefix. `items` or `profiles` would suffice. Per-API codegen output. | +| O-01 | `PACKAGE_SEGMENT` (`client.ts:41`) | Low | OK in context. | ### 2.8 Singular / plural mismatches — Low @@ -195,10 +188,8 @@ revisions can add fields without breaking the type signature. Not flagged. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | -| F-02 | `isMetaInstanceProfile` | Medium | Without the JSDoc, "meta instance profile" is a Databricks-internal term and conveys little. See C-03 / M-06. | -| F-03 | `skipValidation` | Medium | Without the JSDoc, unclear which validation. See V-02. | -| F-04 | `instanceProfiles` (in `ListInstanceProfilesRequest_Response`) | Low | Self-describing. Good. | -| F-05 | `httpReq`, `respBody`, `body` (locals in `client.ts`) | Low | Locals only. | +| F-02 | `instanceProfiles` (in `ListInstanceProfilesRequest_Response`) | Low | Self-describing. Good. | +| F-03 | `httpReq`, `respBody`, `body` (locals in `client.ts`) | Low | Locals only. | ### 2.15 Field contradicting type domain — Medium @@ -235,13 +226,9 @@ revisions can add fields without breaking the type signature. Not flagged. (Section retained for parity with the rubric; no high findings — the package is exemplary in using ARNs as identifiers.) -### 2.19 Type-suffix tautology — Medium +### 2.19 Type-suffix tautology — N/A -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `InstanceProfile.instanceProfileArn` (`model.ts:66`) | Medium | Inside a type called `InstanceProfile`, the `instanceProfile` prefix on the field is tautological. See O-01. | -| TS-02 | `InstanceProfile.isMetaInstanceProfile` (`model.ts:74`) | Medium | Same tautology: `isMeta` inside `InstanceProfile`. See O-02. | -| TS-03 | `ListInstanceProfilesRequest_Response.instanceProfiles` (`model.ts:92`) | Medium | Field re-states the entity type that fills the array. `items` or `profiles` would suffice. See O-04. | +_None._ ### 2.20 Other observations @@ -263,9 +250,9 @@ package is exemplary in using ARNs as identifiers.) | Severity | Count | | -------- | ----- | | High | 9 | -| Medium | 17 | +| Medium | 5 | | Low | 35 | -| **Total**| **61**| +| **Total**| **49**| ### 3.2 Top themes @@ -280,16 +267,6 @@ package is exemplary in using ARNs as identifiers.) doesn't represent. `AwsInstanceProfile` (matching `AzureServicePrincipal`, `GcpAttributes`) would prevent future ambiguity. -3. **Tautological field naming inside `InstanceProfile`.** - `instanceProfile.instanceProfileArn` and - `instanceProfile.isMetaInstanceProfile` repeat the type name. Inside the - entity, `arn` and `isMeta` (or `isCredentialPassthrough`) would suffice. - -4. **`isMetaInstanceProfile` and `skipValidation` need their JSDoc to be - intelligible.** "Meta instance profile" is a Databricks-specific term; - "validation" is overloaded. `isCredentialPassthrough` / - `skipIamValidation` (or similar) would be self-documenting. - ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) - Rename `InstanceProfile` → `AwsInstanceProfile` to scope to the cloud. @@ -297,10 +274,6 @@ package is exemplary in using ARNs as identifiers.) `removeInstanceProfile` → `unregisterInstanceProfile` to match actual semantics. - Rename `editInstanceProfile` → `updateInstanceProfile` for CRUD consistency. -- Inside `InstanceProfile`, rename `instanceProfileArn` → `arn` (and similarly - for nested entities); drop redundant prefixes. -- Rename `isMetaInstanceProfile` → `isCredentialPassthrough` (or similar) - and `skipValidation` → `skipIamValidation`. ### 3.4 Cross-package consistency notes @@ -326,15 +299,3 @@ non-real `Proxy`, mid-position `Action`/`Op` duplicating a verb, visibility infixes. No matches. The package is exemplary on this rubric. --- - -## Fixed - -_None._ The regeneration on 2026-05-20 added `Request` suffixes to all -request DTOs (`AddInstanceProfile` → `AddInstanceProfileRequest`, -`EditInstanceProfile` → `EditInstanceProfileRequest`, `ListInstanceProfiles` -→ `ListInstanceProfilesRequest`, `RemoveInstanceProfile` → -`RemoveInstanceProfileRequest`), but no audit finding was contingent on -the prior names — every concern (misleading verbs, tautological fields, -duplicate concepts, AWS-specific entity name) carries over to the renamed -types. Findings have been updated in-place to reference the new symbol -names and current line numbers. diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index 5a48cdfa..4971e5dc 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -1,18 +1,18 @@ # Naming Audit: `@databricks/sdk-jobs` (v2) -Scope: `packages/jobs/src/v2/` — `model.ts` (9978 lines), `client.ts` (1228 lines), -`utils.ts` (150 lines), `index.ts` (281 lines). This is the largest API surface in +Scope: `packages/jobs/src/v2/` — `model.ts` (10030 lines), `client.ts` (1289 lines), +`utils.ts` (150 lines), `index.ts` (284 lines). This is the largest API surface in the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. ## Summary Table | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------ | -| High | 29 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | -| Medium | 73 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | -| Low | 53 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| High | 26 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | +| Medium | 50 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | +| Low | 25 | Mild verbosity, plural mismatches, stylistic inconsistencies. | | Observations | 14 | Patterns spanning the entire file (oneof wrappers, ID typing, etc.). | -| **Total** | **169** | | +| **Total** | **115** | | Issues are catalogued below by severity, then by file/line. @@ -21,13 +21,13 @@ Issues are catalogued below by severity, then by file/line. ## High ### H1. `Run` is overloaded across at least seven shapes -- **Location:** `model.ts:3369` (`Run`), `model.ts:908` (`BaseRun`), `model.ts:3845` (`RunTask`), `model.ts:3461` (`Run_JobLevelParameters`), `model.ts:3822` (`RunState`), `model.ts:3836` (`RunStatus`), `model.ts:4231` (`RunTriggerInfo`). +- **Location:** `model.ts:3399` (`Run`), `model.ts:908` (`BaseRun`), `model.ts:3875` (`RunTask`), `model.ts:3491` (`Run_JobLevelParameters`), `model.ts:3852` (`RunState`), `model.ts:3866` (`RunStatus`), `model.ts:4261` (`RunTriggerInfo`). - **Category:** Vague/generic + duplicate concepts (#1, #12). - **Suggestion:** Treat `Run` as a domain concept and only use the bare token on the canonical job run. Rename `RunTask` -> `TaskRun` (it represents a task **run**, not a run-task), and rename `Run` -> `JobRun` for symmetry with `JobRunId`, `numberInJob`, `runType: JOB_RUN`. - **Rationale:** Currently `BaseRun`, `Run`, `RunTask`, and the `RunStatus.state` field all describe overlapping shapes. Authors must read JSDoc to know which is which. `RunTask` reading order "task that is a run" is opposite to its actual meaning ("the run of a task"). ### H2. `RunTask` and `TaskSettings` are nearly identical but named asymmetrically -- **Location:** `model.ts:3845` (`RunTask`), `model.ts:4646` (`TaskSettings`), `model.ts:4055` (`RunTaskSettings`). +- **Location:** `model.ts:3875` (`RunTask`), `model.ts:4676` (`TaskSettings`), `model.ts:4085` (`RunTaskSettings`). - **Category:** Duplicate concepts (#12), misleading names (#6). - **Suggestion:** Use `TaskRun` (the runtime/output form) and `Task` (the design-time form). Drop `RunTaskSettings` in favour of `SubmitTask` if it is submit-specific. - **Rationale:** A reader sees three shapes (`RunTask`, `TaskSettings`, `RunTaskSettings`) carrying the same union of task types and cannot tell which to use without grepping. The naming pattern (`RunX` for "X on a run", `XSettings` for "X on a job") is undocumented. @@ -57,31 +57,31 @@ Issues are catalogued below by severity, then by file/line. - **Rationale:** `Environment` is a host-level concept in Node (`process.env`) and a common UI/test-framework type. Inside this file it is a tiny dep-list + base-env reference; it is referenced as `JobEnvironment.spec: Environment`, so a `Spec` suffix matches its role. ### H7. `Repair` lacks a noun and is mistaken for a verb -- **Location:** `model.ts:3071`. +- **Location:** `model.ts:3082`. - **Category:** Verb-tense inconsistency (#13), vague/generic (#1). - **Suggestion:** Rename to `RepairHistoryEntry` (or `RepairAttempt`) — it represents a single past repair. -- **Rationale:** The verb `repair()` exists on the client (`client.ts:734`), and `RepairRunRequest`/`RepairRunRequest_Response` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. +- **Rationale:** The verb `repair()` exists on the client (`client.ts:781`), and `RepairRunRequest`/`RepairRunRequest_Response` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. ### H8. `Webhook` is a generic top-level name that collides with the platform `Webhook` concept -- **Location:** `model.ts:4908`. +- **Location:** `model.ts:4938`. - **Category:** Vague/generic (#1), reserved-word/global collision (#10). - **Suggestion:** Rename to `WebhookRef` (or `JobWebhook`) — readers grep `Webhook` expecting the request/payload shape, but the actual Webhook _payload_ is `WebhookNotifications`. The bare `Webhook` token is the wrong claimant for that name. - **Rationale:** "Webhook" is a broad industry term and the actual delivery payload lives under a different identifier; the unqualified type-name should belong to the canonical shape, not to a Jobs-specific reference. ### H9. `Subscription` and `AlertTaskSubscriber` / `SqlTaskSubscription` are three near-identical shapes -- **Location:** `model.ts:4577` (`Subscription`), `model.ts:741` (`AlertTaskSubscriber`), `model.ts:4501` (`SqlTaskSubscription`), `model.ts:4590` (`Subscription_Subscriber`). +- **Location:** `model.ts:4607` (`Subscription`), `model.ts:741` (`AlertTaskSubscriber`), `model.ts:4531` (`SqlTaskSubscription`), `model.ts:4620` (`Subscription_Subscriber`). - **Category:** Duplicate concepts (#12), inconsistent naming (#17). - **Suggestion:** Standardize on `Subscriber` for the leaf type and `SubscriptionList` (or just `Subscription`) for the container. Avoid mixing `Subscriber` (alert), `Subscription` (sql), and `Subscription_Subscriber` (dashboard). - **Rationale:** Each task type re-invents the same `userName | destinationId` oneof under a different name. This is a porting artifact, not a domain distinction. ### H10. `Run.numberInJob` always equals `Run.runId` — meaningless field -- **Location:** `model.ts:3377`, `model.ts:916`, `model.ts:3714`. +- **Location:** `model.ts:3407`, `model.ts:916`, `model.ts:3744`. - **Category:** Misleading names (#6), generic field names losing meaning (#15). - **Suggestion:** Drop or alias; if it must stay for back-compat, document the duplication on the field rather than the type. - **Rationale:** The comment "This is set to the same value as `run_id`" makes the field a no-op. New TS users will assume it's distinct. ### H11. `RunNowRequest_Response.numberInJob` reused -- **Location:** `model.ts:3714`. +- **Location:** `model.ts:3744`. - **Category:** Misleading names (#6). - **Suggestion:** Same as H10 — remove or rename to `runIdAlias`. - **Rationale:** Same dead duplication on the response. @@ -111,7 +111,7 @@ Issues are catalogued below by severity, then by file/line. - **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). ### H16. `RunNowRequest_Response.runId` field is the "newly triggered run" — confusingly typed `number` -- **Location:** `model.ts:3712`. +- **Location:** `model.ts:3742`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Add a branded type alias `RunId = number & {readonly __brand: 'RunId'}` or use `string` to match `bigint`-safe APIs. - **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId` (string!). @@ -122,74 +122,56 @@ Issues are catalogued below by severity, then by file/line. - **Suggestion:** Standardize on `string` for upstream IDs; note in JSDoc. - **Rationale:** Same semantic field encoded as two different TS types in adjacent interfaces is a bug magnet. -### H18. `GetRunOutputRequest_Response.result` oneof tag is `notebookOutput` but the field discriminates "task" type — misleading -- **Location:** `model.ts:2054-2102`. +### H18. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous +- **Location:** `model.ts:3500`. - **Category:** Misleading names (#6). -- **Suggestion:** Rename `result` to `taskOutput` (since the union members are `notebookOutput | sqlOutput | dbtOutput | ...`). Then `result` could refer to a higher-level `RunResultState` field that semantically belongs there. -- **Rationale:** `result` on a run-output type is confusable with `RunResultState`, and `Run.status.terminationDetails.message` is also "the result". - -### H19. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous -- **Location:** `model.ts:3470`. -- **Category:** Misleading names (#6). -- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3946). +- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3976). - **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? -### H20. `Repair.id` vs `RepairRunRequest_Response.repairId` -- **Location:** `model.ts:3081`, `model.ts:3210`. -- **Category:** Generic field names losing meaning (#15), inconsistent naming (#17). -- **Suggestion:** Rename `Repair.id` to `repairId`. -- **Rationale:** A bare `id` field on a type called `Repair` is technically OK but breaks the workspace convention of always disambiguating IDs. - -### H21. `BaseJob` and `GetJobRequest_Response` and `Run` duplicate ~10 identical fields -- **Location:** `model.ts:874`, `model.ts:1973`, `model.ts:3369`, `model.ts:908`. +### H19. `BaseJob` and `GetJobRequest_Response` and `Run` duplicate ~10 identical fields +- **Location:** `model.ts:874`, `model.ts:1973`, `model.ts:3399`, `model.ts:908`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Extract a shared `JobIdentity` / `JobCoreFields` interface or use TS `Pick`/`Omit` on a base shape. - **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId` are repeated verbatim in `BaseJob` and `GetJobRequest_Response`. Diverges silently. -### H22. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums -- **Location:** `model.ts:3822`, `model.ts:3836`. +### H20. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums +- **Location:** `model.ts:3852`, `model.ts:3866`. - **Category:** Duplicate concepts (#12), versioned API leakage (#11). - **Suggestion:** Pick `RunStatus` as the canonical shape, deprecate `RunState`, and document the deprecation in the rule. - **Rationale:** The JSDoc on `Run.state` already says "Deprecated. Please use the `status` field instead." but the type is still exported and still shows up in the union. -### H23. `RunState.userCancelledOrTimedout` — typo + boolean-of-two-things -- **Location:** `model.ts:3830`. -- **Category:** Misleading names (#6). -- **Suggestion:** Fix spelling to `userCancelledOrTimedOut`. Better, split into `cancelledByUser: boolean` and `timedOut: boolean`. -- **Rationale:** Compound booleans (X-or-Y) are an anti-pattern. The current name silently drops one bit of info. - -### H24. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) +### H21. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) - **Location:** `model.ts:390`, `model.ts:478`, `model.ts:542`, `model.ts:662`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Normalize to one form. The `MAX_` form is more common; reach-vs-exceed should pick one verb. - **Rationale:** Three enums describe the same overflow scenario with three different names. Consumers cannot write a generic handler. -### H25. `client.exportRun` returns `ExportRunRequest_Response` which contains a `views` array of `ViewItem` -- **Location:** `client.ts:420`, `model.ts:1830`, `model.ts:4890`. +### H22. `client.exportRun` returns `ExportRunRequest_Response` which contains a `views` array of `ViewItem` +- **Location:** `client.ts:449`, `model.ts:1830`, `model.ts:4920`. - **Category:** Vague/generic (#1). - **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. - **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. -### H26. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint +### H23. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint - **Location:** `model.ts:327`, `model.ts:337`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Merge or namespace: `View.Type` (NOTEBOOK | DASHBOARD) and `View.ExportSelector` (CODE | DASHBOARDS | ALL). - **Rationale:** Two enums about "views" with different value sets and intent. Users will pick the wrong one. -### H27. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` -- **Location:** `client.ts:909-987`. +### H24. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` +- **Location:** `client.ts:971-1048`. - **Category:** Versioned API leakage. - **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. - **Rationale:** Future deprecation of V1 will silently break all four waiters. -### H28. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers -- **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3585` (`RunLifecycleStateV2` wrapper interface), `model.ts:3837` (`RunStatus.state: RunLifecycleStateV2_State`). +### H25. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers +- **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3615` (`RunLifecycleStateV2` wrapper interface), `model.ts:3867` (`RunStatus.state: RunLifecycleStateV2_State`). - **Why:** `V2` mid-token in a type name records that the upstream schema versioned this enum, not anything a JS consumer needs. The V1 type already lives at `RunLifeCycleState` / `RunLifeCycleState_RunLifeCycleState`; the V2 variant should adopt a domain-meaningful name rather than a version-stamped one. - **Category:** Proto-architectural-leak (`V2` mid-position). - **Suggested:** Rename the wrapper to `RunLifecycleState` (singular, modern) and the enum to `RunLifecycleState_State` — then mark the legacy `RunLifeCycleState` family `@deprecated`. If the V1 type must keep its current name for back-compat, rename the V2 family to `RunPhase` or `RunLifecycleStatus` (anything that says "this is the new shape" without encoding the version number). - **Rationale:** `V2` as part of a type name is the textbook proto-architectural leak this audit category targets; it bakes upstream-version churn into every consumer's import list. The casing difference (`LifeCycle` vs `Lifecycle`) between V1 and V2 names also makes the pair harder to grep. -### H29. `ProjectCheckoutInternalRepo` RPC name leaked into public JSDoc on `TerminationCode_Code` +### H26. `ProjectCheckoutInternalRepo` RPC name leaked into public JSDoc on `TerminationCode_Code` - **Location:** `model.ts:619` (comment on `REPOSITORY_CHECKOUT_FAILED`). - **Why:** The JSDoc reads "Returned if [[ProjectCheckoutInternalRepo]] RPC fails" — `ProjectCheckoutInternalRepo` is an internal service RPC, and the `Internal` token plus `RPC` mention exposes a backend implementation detail to public API consumers. - **Category:** Proto-architectural-leak (`Internal` infix, `RPC` reference in public doc). @@ -230,7 +212,7 @@ Issues are catalogued below by severity, then by file/line. - **Suggestion:** OK; consistent with file. ### M6. `S3StorageInfo` — `S3` (number) keeps caps -- **Location:** `model.ts:4237`. +- **Location:** `model.ts:4267`. - **Category:** Acronym casing (#3). - **Suggestion:** Keep — `S3` is a brand name, kept as-is. @@ -240,13 +222,13 @@ Issues are catalogued below by severity, then by file/line. - **Suggestion:** OK; consistent. ### M8. `PowerBi*` casing (vs `PowerBI`) -- **Location:** `model.ts:2959`, `model.ts:2972`, `model.ts:2983`, `model.ts:173-175`. +- **Location:** `model.ts:2970`, `model.ts:2983`, `model.ts:2994`, `model.ts:173-175`. - **Category:** Acronym casing (#3). - **Suggestion:** Brand-style "BI" is industry-standard caps; consider `PowerBI*`. The Microsoft brand is "Power BI". Currently mixed: type uses `PowerBi`, JSDoc uses `Power BI`. - **Rationale:** Per the TS style guide, "BI" is an acronym (Business Intelligence), so `PowerBI` is correct. Going with `PowerBi` is inconsistent with `SqlTask` (3 letters). ### M9. `SqlTask` / `SqlAlertState` / etc. — `Sql` lower or upper? -- **Location:** `model.ts:4335`, `model.ts:4333`, `model.ts:558`, `model.ts:565`. +- **Location:** `model.ts:4365`, `model.ts:4363`, `model.ts:558`, `model.ts:565`. - **Category:** Acronym casing (#3). - **Suggestion:** Either `Sql` everywhere (current) or `SQL` everywhere. Pick one. - **Rationale:** The TS style guide allows acronyms of 3+ letters to be word-cased (`Sql`); this is consistent in this file. Note however the JSDoc still writes "SQL" — fine for prose. @@ -278,268 +260,154 @@ Issues are catalogued below by severity, then by file/line. - **Category:** Long enum values (#18). - **Suggestion:** Acceptable; consider grouping into a nested enum if the four become five. -### M15. `Repair.startTime` / `Repair.endTime` (epoch ms) -- **Location:** `model.ts:3075-3077`. -- **Category:** Generic field names losing meaning (#15). -- **Suggestion:** Document units in name: `startTimeMs` or use a `Date`-typed alias. -- **Rationale:** TS `number` for milliseconds is the same shape as TS `number` for seconds. Cf. `timeoutSeconds` (which DOES carry the unit). - -### M16. `CreateJobRequest.timeoutSeconds` (seconds) vs `CreateJobRequest.minRetryIntervalMillis` (ms) — unit-suffix inconsistency -- **Location:** `model.ts:1413`, `model.ts:1498`. -- **Category:** Inconsistent unit suffixes (#17). -- **Suggestion:** Use one unit (preferably `Ms` or `Seconds` for everything). At least pick one. -- **Rationale:** Within one settings object, seconds and millis differ only by a 3-letter suffix; easy to misuse. - -### M17. `FileArrivalTriggerConfiguration.minTimeBetweenTriggersSeconds` — extremely long -- **Location:** `model.ts:1840`. -- **Category:** Overly verbose (#7). -- **Suggestion:** Acceptable since unit is encoded; can drop "Triggers" since the type already says it: `minTimeBetweenFiringsSeconds` or `minIntervalSeconds`. - -### M18. `WaitAfterLastChangeSeconds` — appears identically in three triggers -- **Location:** `model.ts:1846`, `model.ts:2833`, `model.ts:4628`. +### M15. `WaitAfterLastChangeSeconds` — appears identically in three triggers +- **Location:** `model.ts:1846`, `model.ts:2833`, `model.ts:4658`. - **Category:** Verbose, repetitive (#7). - **Suggestion:** OK, document once. -### M19. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) +### M16. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) - **Location:** `model.ts:1041`, `model.ts:1026`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Pick one. `CleanRoom*` (singular) is consistent with the standalone product "Clean Rooms" being treated as a singular feature. -### M20. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL +### M17. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL - **Location:** `model.ts:1043`. - **Category:** Acronym casing (#3). - **Suggestion:** Acceptable; brand inconsistency is upstream's responsibility. -### M21. `AlertTask.workspacePath` — uses `workspacePath` while other path-like fields use bare `path` -- **Location:** `model.ts:725`, `model.ts:4479`. -- **Category:** Inconsistent naming (#17). -- **Suggestion:** Standardize: use `workspacePath` for all workspace paths (`SqlTaskFile.path` → `workspacePath`). - -### M22. `DbtCloudJobRunStep` (deprecated) and `DbtPlatformJobRunStep` (new) +### M18. `DbtCloudJobRunStep` (deprecated) and `DbtPlatformJobRunStep` (new) - **Location:** `model.ts:1583`, `model.ts:1613`. - **Category:** Versioned API leakage. - **Suggestion:** OK while transition is documented; reconsider after dbt Cloud is dropped. -### M23. `SparkJarTask.jarUri` (deprecated) — already deprecated -- **Location:** `model.ts:4281`. +### M19. `SparkJarTask.jarUri` (deprecated) — already deprecated +- **Location:** `model.ts:4311`. - **Category:** OK as docstring; ensure `@deprecated` JSDoc tag added. -### M24. `SparkJarTask.runAsRepl` — deprecated; values restricted -- **Location:** `model.ts:4295`. +### M20. `SparkJarTask.runAsRepl` — deprecated; values restricted +- **Location:** `model.ts:4325`. - **Category:** Vague/misleading (#6). - **Suggestion:** `@deprecated`. Comment says "A value of `false` is no longer supported." -### M25. `JobLevelParameter.default` — `default` is a TS keyword in some positions -- **Location:** `model.ts:2389`, `model.ts:3465`. -- **Category:** Reserved-word collision (#10). -- **Suggestion:** Rename to `defaultValue`. -- **Rationale:** `default` is a reserved word as a `case` label and `switch` token. Object property `default` is legal but trips linters and confuses code editors. - -### M26. `JobsHealthRule.op` and `ConditionTask.op` — short, opaque -- **Location:** `model.ts:2558`, `model.ts:1383`. -- **Category:** Cryptic abbreviations (#5). -- **Suggestion:** Rename to `operator`. -- **Rationale:** `op` saves one word but is too terse for a public API. - -### M27. `Repair.type` (RepairType) is a reserved-ish word -- **Location:** `model.ts:3073`, `model.ts:4896`. +### M21. `Repair.type` (RepairType) is a reserved-ish word +- **Location:** `model.ts:3084`, `model.ts:4926`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. -### M28. `RunStatus.state` — `state` is generic -- **Location:** `model.ts:3837`. -- **Category:** Generic field names (#15). -- **Suggestion:** Acceptable in context (the type is `RunStatus`), but consider `lifecycleState` to match V1. - -### M29. `RunNowRequest.only` field — what does "only" mean? -- **Location:** `model.ts:3608`. -- **Category:** Cryptic abbreviations (#5), misleading names (#6). -- **Suggestion:** Rename to `taskKeysToRun` or `runOnlyTasks`. -- **Rationale:** A standalone `only: string[]` field on a request is a riddle. - -### M30. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK -- **Location:** `model.ts:3604`, `model.ts:4540`. +### M22. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK +- **Location:** `model.ts:3634`, `model.ts:4570`. - **Category:** Verbose but precise. -### M31. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern -- **Location:** `model.ts:3100-3106`. +### M23. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern +- **Location:** `model.ts:3111-3117`. - **Category:** Consistent prefix; OK. -### M32. `RepairRunRequest.latestRepairId` vs `RepairRunRequest_Response.repairId` (no `latest`) -- **Location:** `model.ts:3098`, `model.ts:3210`. +### M24. `RepairRunRequest.latestRepairId` vs `RepairRunRequest_Response.repairId` (no `latest`) +- **Location:** `model.ts:3109`, `model.ts:3221`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Document the semantic: request takes "the previous latest", response returns "the new latest". -### M33. `SqlTask.sqlTaskType` oneof name is type-tautological -- **Location:** `model.ts:4338`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `target` or `kind`. The wrapper is already `SqlTask`. - -### M34. `SqlTask_SqlOutput.sqlOutputType` — same tautology -- **Location:** `model.ts:4413`. -- **Category:** Type-suffix tautology (#20). - -### M35. `Subscription_Subscriber.subscriptionType` -- **Location:** `model.ts:4591`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename oneof tag to `target`. - -### M36. `AlertTaskSubscriber.subscriberType` -- **Location:** `model.ts:742`. -- **Category:** Type-suffix tautology (#20). - -### M37. `DockerImage.credsOneof` — exposes proto oneof name to TS +### M25. `DockerImage.credsOneof` — exposes proto oneof name to TS - **Location:** `model.ts:1715`. - **Category:** Go/Java-style names (#14). - **Suggestion:** Rename to `credentials` or `auth`. -### M38. `JobRunAs.identity` — OK +### M26. `JobRunAs.identity` — OK - **Location:** `model.ts:2398`. -### M39. `AccessControlRequest.principalName` oneof name doesn't match the contents -- **Location:** `model.ts:697`. -- **Category:** Misleading names (#6). -- **Suggestion:** Rename to `principal` — the discriminants are `userName | groupName | servicePrincipalName`, not three different name-shaped values. - -### M40. `RunTriggerInfo.runId` — what kind of runId? -- **Location:** `model.ts:4233`. -- **Category:** Underspecified IDs (#19). -- **Suggestion:** Rename to `parentRunId` or `triggeringRunId` (JSDoc says "The run id of the Run Job task run"). - -### M41. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix +### M27. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix - **Location:** `model.ts:2340`. - **Category:** Acceptable; key is the lookup pattern. -### M42. `JobEnvironment.environmentKey` — same pattern, OK. +### M28. `JobEnvironment.environmentKey` — same pattern, OK. - **Location:** `model.ts:2381`. -### M43. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy -- **Location:** `model.ts:4652`, `model.ts:3872`, `model.ts:4061`, `model.ts:4641`. +### M29. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy +- **Location:** `model.ts:4682`, `model.ts:3902`, `model.ts:4091`, `model.ts:4671`. - **Category:** Verbose but precise. -### M44. `TaskDependency.taskKey` (the task being depended on) — could be `dependsOnTaskKey` -- **Location:** `model.ts:4641`. - -### M45. `TaskDependency.outcome` — value of a condition task: should be `condition` or `requiredOutcome` -- **Location:** `model.ts:4643`. -- **Category:** Generic field names (#15). - -### M46. `ResolvedValues` interface has 11 single-purpose sub-types -- **Location:** `model.ts:3236-3367`. +### M30. `ResolvedValues` interface has 11 single-purpose sub-types +- **Location:** `model.ts:3247-3397`. - **Category:** Verbose; many shapes for one purpose. - **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. -### M47. `ClusterSpec.spec` (inside `ClusterSpec`) — name-tautology -- **Location:** `model.ts:1121`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename oneof to `target` or `cluster`. - -### M48. `RunTask.spec` (same pattern) -- **Location:** `model.ts:4001`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename oneof to `cluster`. - -### M49. `RunTaskSettings.spec`, `TaskSettings.spec` — same -- **Location:** `model.ts:4190`, `model.ts:4790`. -- **Category:** Type-suffix tautology (#20). - -### M50. `RunTask.task` — oneof inside a type called `RunTask` whose oneof is the task body — tautology -- **Location:** `model.ts:3903`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename oneof to `body` or `payload`. - -### M51. `BaseRun.numberInJob` — meaningless field (see H10) +### M31. `BaseRun.numberInJob` — meaningless field (see H10) - **Location:** `model.ts:916`. -### M52. `BaseRun.originalAttemptRunId` — verbose, but precise. - -### M53. `BaseRun.runName` vs `BaseRun.runPageUrl` vs `BaseRun.runType` — repeated `run` prefix on a `BaseRun` type -- **Location:** `model.ts:934`, `model.ts:936`, `model.ts:937`. -- **Category:** Redundant prefix (#2). -- **Suggestion:** Drop `run` prefix when already inside `Run*` type: `name`, `pageUrl`, `type`. +### M32. `BaseRun.originalAttemptRunId` — verbose, but precise. -### M54. `Run.runId` (inside `Run`) — tautological -- **Location:** `model.ts:3373`, `model.ts:912`, `model.ts:2140`, `model.ts:3847`. +### M33. `Run.runId` (inside `Run`) — tautological +- **Location:** `model.ts:3403`, `model.ts:912`, `model.ts:2140`, `model.ts:3877`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. -### M55. `Run.jobRunId` field while the type is already a job run -- **Location:** `model.ts:3429`. -- **Category:** Underspecified IDs (#19). -- **Suggestion:** Document `runId vs jobRunId` more clearly; consider `parentJobRunId`. - -### M56. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRunRequest_Response` — could be deduped -- **Location:** `model.ts:942`, `model.ts:3403`, `model.ts:2170`. +### M34. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRunRequest_Response` — could be deduped +- **Location:** `model.ts:942`, `model.ts:3433`, `model.ts:2170`. -### M57. `RunNowRequest_Response.numberInJob` (see H11). +### M35. `RunNowRequest_Response.numberInJob` (see H11). -### M58. `ListJobsRequest.limit` vs `ListRunsRequest.limit` documentation discrepancy +### M36. `ListJobsRequest.limit` vs `ListRunsRequest.limit` documentation discrepancy - **Location:** `model.ts:2692`, `model.ts:2751`. - **Category:** Inconsistent docs (not naming, but worth flagging). - **Suggestion:** Document max values explicitly; `ListJobsRequest` says ≤100, `ListRunsRequest` says <25. -### M59. `ListJobsRequest.offset` deprecated by `pageToken` — but both still typed +### M37. `ListJobsRequest.offset` deprecated by `pageToken` — but both still typed - **Location:** `model.ts:2690`. - **Category:** Deprecation hygiene. - **Suggestion:** Add `@deprecated` JSDoc to `offset`. -### M60. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) +### M38. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) - **Location:** `model.ts:708`, similar in `DbfsStorageInfo`, `S3StorageInfo`, `GcsStorageInfo`, `LocalFileInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. - **Category:** Generic field names (#15). - **Suggestion:** Each storage type has different URI semantics; `destination` is fine since it's polymorphic, but document the form. -### M61. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type +### M39. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type - **Location:** `model.ts:257`. - **Category:** Type design. - **Suggestion:** Could be `type CodeSource = 'WORKSPACE' | 'GIT'`. Same for `Format`, `ViewType`, etc. -### M62. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead +### M40. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead - **Location:** `model.ts:151-154`. - **Category:** Dead enum value. -### M63. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` +### M41. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` - **Location:** `model.ts:355`. - **Category:** Generic enum value (#1). - **Suggestion:** `UNKNOWN` is universally vague; consider `NOT_EVALUATED`. -### M64. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) +### M42. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) - **Location:** `model.ts:570`, `model.ts:541`, `model.ts:137`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Pick one spelling; "canceled" (single-L) is the American spelling, "cancelled" is the British. Cross-checking with go SDK keeps wire compat. -### M65. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) +### M43. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) - **Location:** `model.ts:670`, `model.ts:611`. - **Category:** Overlapping enum values (#12). - **Suggestion:** Document distinction (one is user-initiated, the other is platform-initiated). -### M66. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized -- **Location:** `model.ts:4937`, `model.ts:4941`. +### M44. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +- **Location:** `model.ts:4967`, `model.ts:4971`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Rename to `ClientTypes`. -### M67. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) -- **Location:** `model.ts:3064`. +### M45. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) +- **Location:** `model.ts:3075`. - **Category:** Acronym casing (#3). - **Suggestion:** Cran is an acronym (CRAN = Comprehensive R Archive Network). `RLibrary` works too. The `R` prefix is from the Go SDK. -### M68. `PythonPyPiLibrary` — duplicate "Py" prefix -- **Location:** `model.ts:3015`. +### M46. `PythonPyPiLibrary` — duplicate "Py" prefix +- **Location:** `model.ts:3026`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). -### M69. `MavenLibrary.coordinates` — common, accept. -- **Location:** `model.ts:2796`. +### M47. `MavenLibrary.coordinates` — common, accept. +- **Location:** `model.ts:2797`. -### M70. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. +### M48. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. -### M71. `RunNowRequest.pythonNamedParams` (no suffix `_NamedParametersEntry`?) -- **Location:** `model.ts:3669`. -- **Category:** Inconsistent naming (#17). -- **Suggestion:** Rename to `pythonNamedParameters` to match `notebookParams` being plain; or rename all `*Params` to `*Parameters` consistently. Currently: `jobParameters` (plural Parameters), `notebookParams` (Params), `pythonParams`, `pythonNamedParams`, `sparkSubmitParams`, `sqlParams`, `dbtCommands`, `pipelineParams`, `jarParams`. - -### M72. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. +### M49. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. -### M73. `ListRunsRequest.runType` shouldn't be optional when the API permits a default +### M50. `ListRunsRequest.runType` shouldn't be optional when the API permits a default - **Location:** `model.ts:2753`. - **Category:** Default semantics. @@ -548,155 +416,64 @@ Issues are catalogued below by severity, then by file/line. ## Low ### L1. `Adlsgen2Info` — see M1. -### L2. `WorkloadType_ClientsTypes` — see M66. -### L3. _Removed: `IncrementalRefreshConfig` no longer exists in the source — out of scope._ - -### L4. _Removed: `IncrementalRefreshConfig.detectDataChanges` no longer exists in the source._ - -### L5. _Removed: `IncrementalRefreshConfig.mode` no longer exists in the source._ - -### L6. _Removed: `IncrementalRefreshConfig.*WindowPeriods` no longer exists in the source._ - -### L7. _Removed: `PowerBiTable.incrementalRefreshDatetimeColumn` no longer exists in the source._ - -### L8. `PowerBiModel.modelName` — `modelName` inside `PowerBiModel` — type-suffix tautology -- **Location:** `model.ts:2963`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `name`. - -### L9. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). - -### L10. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. +### L2. `WorkloadType_ClientsTypes` — see M44. -### L11. `AccessControlRequest.principalName` oneof — see M39. +### L3. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). -### L12. `QueueDetails.message` and `QueueDetails.code` — OK. +### L4. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. -### L13. _Removed: `SqlConditionConfiguration` no longer exists in the source._ +### L5. `QueueDetails.message` and `QueueDetails.code` — OK. -### L14. _Removed: `SqlConditionRunInfoDetails` no longer exists in the source._ - -### L15. _Removed: `SqlConditionRunInfoDetails.conditionEvaluationSatisfied` no longer exists._ - -### L16. _Removed: `SqlConditionState` no longer exists in the source._ - -### L17. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. +### L6. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. - **Location:** `model.ts:2909`. -### L18. `OutputSchemaInfo.expirationTime` (epoch ms) — same units issue as M15. - -### L19. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. - -### L20. `JobEmailNotifications.noAlertForSkippedRuns` (deprecated) — `@deprecated` recommended. - -### L21. `NotificationSettings.noAlertForSkippedRuns` / `noAlertForCanceledRuns` — `noAlertFor*` negative boolean prefix. -- **Location:** `model.ts:2900-2902`. -- **Category:** Negative-naming antipattern. -- **Suggestion:** Rename to `alertOnSkippedRuns` / `alertOnCanceledRuns` and invert defaults; or keep as documented to match wire. - -### L22. `NotificationSettings.alertOnLastAttempt` — opposite polarity to L21; mix is confusing. - -### L23. `WebhookNotifications.onDurationWarningThresholdExceeded` — very long field name (40+ chars). -- **Location:** `model.ts:4920`. -- **Category:** Overly verbose (#7). -- **Suggestion:** Acceptable since it encodes the metric; can shorten to `onDurationThresholdExceeded`. - -### L24. `WebhookNotifications.onStreamingBacklogExceeded` — accept. +### L7. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. -### L25. `ContinuousSettings.taskRetryMode` (enum) — OK. +### L8. `JobEmailNotifications.noAlertForSkippedRuns` (deprecated) — `@deprecated` recommended. -### L26. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. +### L9. `WebhookNotifications.onStreamingBacklogExceeded` — accept. -### L27. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. +### L10. `ContinuousSettings.taskRetryMode` (enum) — OK. -### L28. `CronSchedule.quartzCronExpression` — long but precise. +### L11. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. -### L29. _Removed: `CronSchedule.sqlCondition` no longer exists in the source._ +### L12. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. -### L30. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. +### L13. `CronSchedule.quartzCronExpression` — long but precise. -### L31. `JobSource.importFromGitReference` oneof, with one option `importFromGitBranch` — verbose oneof -- **Location:** `model.ts:2539`. -- **Category:** Verbose (#7). -- **Suggestion:** Rename oneof to `source`; rename option to `branch`. +### L14. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. -### L32. `JobDeployment.metadataFilePath` +### L15. `JobDeployment.metadataFilePath` - **Location:** `model.ts:2354`. - **Category:** Verbose. -### L33. `LogAnalyticsInfo.logAnalyticsWorkspaceId` / `logAnalyticsPrimaryKey` — `logAnalytics` prefix duplicates type name. -- **Location:** `model.ts:2792-2793`. -- **Category:** Redundant prefixes (#2). -- **Suggestion:** `workspaceId` and `primaryKey`. - -### L34. `GitSource.gitUrl` / `GitSource.gitProvider` / `GitSource.gitReference` — `git` prefix duplicates `GitSource`. -- **Location:** `model.ts:2242-2245`. -- **Category:** Redundant prefixes (#2). -- **Suggestion:** `url`, `provider`, `reference`. - -### L35. `Run.runName`, `runPageUrl`, `runType` (see M53). - -### L36. `BaseRun.startTime` / `endTime` / `setupDuration` / `executionDuration` / `cleanupDuration` / `endTime` / `runDuration` / `queueDuration` — units-in-name half-applied (Duration but not StartTime). -- **Location:** `model.ts:984-996`. -- **Category:** Inconsistent unit suffixes (#17). -- **Suggestion:** All durations are ms — make this uniform: `startTimeMs`, `setupDurationMs`, etc. - -### L37. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. -- **Location:** `model.ts:3447-3449`. +### L16. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. +- **Location:** `model.ts:3477-3479`. - **Category:** Field contradicting type domain (#16). - **Suggestion:** Move to `RunTask` only, mark deprecated on `Run`. -### L38. `RepairRunRequest.dbtCommands` — present on `RunNowRequest`, `RunJobTask`, `RepairRunRequest`, `RunParameters`. -- **Location:** `model.ts:3179`, `model.ts:3540`, `model.ts:3681`, `model.ts:3791`. +### L17. `RepairRunRequest.dbtCommands` — present on `RunNowRequest`, `RunJobTask`, `RepairRunRequest`, `RunParameters`. +- **Location:** `model.ts:3190`, `model.ts:3570`, `model.ts:3711`, `model.ts:3821`. - **Category:** Repeated identical fields — argues for shared `RunOverrideParameters` base. -### L39. `RunNowRequest.pipelineParams: PipelineParameters` — `Params` vs `Parameters` inconsistency (see M71). - -### L40. `SparkPythonTask.pythonFile` — `python` prefix already encoded in type name -- **Location:** `model.ts:4300`. -- **Category:** Redundant prefixes (#2). -- **Suggestion:** Rename to `file` or `script`. +### L18. `SparkPythonTask.parameters` (string[]) — OK. -### L41. `SparkPythonTask.parameters` (string[]) — OK. - -### L42. `SparkJarTask.mainClassName` — `Name` suffix on `Class` is redundant -- **Location:** `model.ts:4287`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `mainClass`. +### L19. `SparkJarTask.runAsRepl` (deprecated) — see M20. -### L43. `SparkJarTask.runAsRepl` (deprecated) — see M24. - -### L44. `Library.lib` oneof name is redundant -- **Location:** `model.ts:2569`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename to `source` or just inline the oneof fields. - -### L45. `Library.egg` (deprecated) — see top JSDoc. +### L20. `Library.egg` (deprecated) — see top JSDoc. - **Location:** `model.ts:2582`. -### L46. `Library.cran: RCranLibrary` — see M67. +### L21. `Library.cran: RCranLibrary` — see M45. -### L47. `Library.requirements: string` (a requirements.txt URI) — OK. - -### L48. `InitScriptInfo.storageInfo` oneof — `storageInfo` is reused across `ClusterLogConf` and `InitScriptInfo`. -- **Location:** `model.ts:2273`, `model.ts:1090`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Rename oneof to `destination` or `target`. +### L22. `Library.requirements: string` (a requirements.txt URI) — OK. -### L49. `AwsAttributes.spotBidPricePercent` — long but precise. +### L23. `AwsAttributes.spotBidPricePercent` — long but precise. -### L50. `AzureAttributes.logAnalyticsInfo` — see L33. - -### L51. `GcpAttributes.usePreemptibleExecutors` — deprecated per JSDoc (use `availability`). +### L24. `GcpAttributes.usePreemptibleExecutors` — deprecated per JSDoc (use `availability`). - **Location:** `model.ts:1876`. - **Category:** Deprecation hygiene. -### L52. `GcpAttributes.googleServiceAccount` — `google` prefix unnecessary inside `Gcp*` namespace. -- **Location:** `model.ts:1883`. -- **Category:** Redundant prefixes (#2). -- **Suggestion:** Rename to `serviceAccount`. - -### L53. `ClusterSpec_NewCluster.useMlRuntime` — `Ml` casing (vs `ML`); follows style. +### L25. `ClusterSpec_NewCluster.useMlRuntime` — `Ml` casing (vs `ML`); follows style. --- @@ -737,7 +514,7 @@ Issues are catalogued below by severity, then by file/line. - `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. - Suggestion: `RepairRunWaiter` for consistency. -### O10. `client.ts:734` declares `repair()` method (not `repairRun()`) +### O10. `client.ts:781` declares `repair()` method (not `repairRun()`) - The method name remains `repair` even though the request type is `RepairRunRequest`. Consider `repairRun` for consistency with `submitRun`, `cancelRun`, `runNow`, etc. ### O11. `index.ts` re-exports both the value classes and types in two blocks @@ -799,30 +576,13 @@ Issues are catalogued below by severity, then by file/line. | File | Lines | Read In Full? | Notes | | ----------------- | ----- | ------------- | ------------------------------------------- | -| `v2/index.ts` | 281 | Yes | Re-exports; lists every public identifier. | +| `v2/index.ts` | 284 | Yes | Re-exports; lists every public identifier. | | `v2/utils.ts` | 150 | Yes | Marshalling and request helpers. | -| `v2/client.ts` | 1228 | Yes | 19 methods + 4 waiter classes. | -| `v2/model.ts` | 9978 | Yes (chunks) | 47 enums, ~140 interfaces, ~5000 lines of marshalling code (4954+).| +| `v2/client.ts` | 1289 | Yes | 19 methods + 4 waiter classes. | +| `v2/model.ts` | 10030 | Yes (chunks) | 47 enums, ~140 interfaces, ~5000 lines of marshalling code (4984+).| All public identifiers exported from `index.ts` were considered. Interfaces below -the `unmarshalAdlsgen2InfoSchema` line (4954+) are runtime marshalling code, +the `unmarshalAdlsgen2InfoSchema` line (4984+) are runtime marshalling code, not naming surface; they are not in scope. --- - -## Fixed - -- #H25 `client.repair` and `client.repairWaiter` verb mismatch (originally cited at `client.ts:570`, `client.ts:595`): Fixed in regeneration on 2026-05-20 — request type renamed `RepairRun` → `RepairRunRequest`, so the `repair(RepairRunRequest)` pairing now matches the verb-noun pattern; remaining concern (method `repair` vs `repairRun`) is captured as observation O10. -- #H30 `cancelRunWaiter` polling on V1 lifecycle-state enum (originally cited at `client.ts:742-820`): Fixed in regeneration on 2026-05-20 — finding renumbered to H27 with updated client.ts:906-984 line range; no semantic change. -- L3 `IncrementalRefreshConfig.onlyRefreshCompletePeriods` (originally cited at `model.ts:2339`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L4 `IncrementalRefreshConfig.detectDataChanges`: Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L5 `IncrementalRefreshConfig.mode` (originally cited at `model.ts:2345`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L6 `IncrementalRefreshConfig.archiveWindowPeriods`/`refreshWindowPeriods`: Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L7 `PowerBiTable.incrementalRefreshDatetimeColumn` (originally cited at `model.ts:3020`): Fixed in regeneration on 2026-05-20 — field no longer exists in source. -- L13 `SqlConditionConfiguration.sqlQueryId` (originally cited at `model.ts:4384`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L14 `SqlConditionRunInfoDetails.conditionEvaluationSqlStatementId` (originally cited at `model.ts:4395`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L15 `SqlConditionRunInfoDetails.conditionEvaluationSatisfied` (originally cited at `model.ts:4397`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L16 `SqlConditionState.latestConditionEvaluation*` (originally cited at `model.ts:4402-4411`): Fixed in regeneration on 2026-05-20 — type no longer exists in source. -- L29 `CronSchedule.sqlCondition: SqlConditionConfiguration`: Fixed in regeneration on 2026-05-20 — field no longer exists in source. -- #H28 `TriggerStateProto` proto-architectural-leak (originally cited at `model.ts:4857`, referenced from `BaseJob.triggerState` and `GetJobRequest_Response.triggerState`): Fixed in regeneration on 2026-05-22 — type renamed to `TriggerState`; the `Proto` suffix is gone. The remaining `RunLifecycleStateV2`/`V2_State` proto-architectural leak is now captured as H28 (was previously H29). -- M22 `BaseJob.path` workspace-path normalization (originally cited at `model.ts:905`): Fixed in regeneration on 2026-05-22 — the bare `path` field no longer exists on `BaseJob`; only `AlertTask.workspacePath` (M21) and `SqlTaskFile.path` (now M21 cross-reference) remain. diff --git a/.agent/naming-audit/keyconfigurations.md b/.agent/naming-audit/keyconfigurations.md index ccec4a1a..e2ac6385 100644 --- a/.agent/naming-audit/keyconfigurations.md +++ b/.agent/naming-audit/keyconfigurations.md @@ -71,16 +71,3 @@ _None._ _None._ --- - -## Fixed - -### `*Public` infix on every request/response type — `model.ts:82, 136, 165, 176, 180` -Fixed in regeneration on 2026-05-22. The `Public` infix was dropped from -all five message types: `CreateCustomerManagedKeyRequest`, -`DeleteCustomerManagedKeyRequest`, `GetCustomerManagedKeyRequest`, -`ListCustomerManagedKeyRequest`, and `ListCustomerManagedKeyResponse`. - -### `Public` infix on marshal schema identifier — `model.ts:309` -Fixed in regeneration on 2026-05-22. The schema identifier is now -`marshalCreateCustomerManagedKeyRequestSchema`, matching the renamed -type. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 5e49364c..6e0ede8a 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -9,127 +9,45 @@ volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and `KnowledgeSource` each carry their own proto-style nested lifecycle enum (`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). -**Total weird names flagged:** 37 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | -| High | 10 | -| Medium | 12 | -| Low | 9 | +| High | 4 | +| Medium | 2 | +| Low | 8 | | Observation | 6 | ## High severity -### 1. `KnowledgeSource_State.FAILED_UPDATE` vs `KnowledgeAssistant_State.FAILED` — `src/v1/model.ts:13,21` -- **Why weird:** The two sibling state enums describe lifecycle failure with two different conventions: the assistant uses bare `FAILED`, the source uses `FAILED_UPDATE`. Both enums also use bare past-participle progressives (`CREATING/UPDATING`) for the in-flight state, but only the source enum qualifies the failure with the verb (`FAILED_UPDATE`). A future `DELETE` operation on either resource would surface this asymmetry — the assistant would need `FAILED` to mean "create failed" *and* "delete failed," while the source already qualifies. Consumers reading both enums side by side will assume the assistant's `FAILED` covers something specific, when in fact it is overloaded. -- **Category:** 6 (misleading), 17 (inconsistency across sibling enums), 13 (verb-tense inconsistency: bare `FAILED` vs `FAILED_UPDATE`). -- **Suggested name:** Align: either both enums use bare `FAILED` (and document that it is operation-agnostic) or both qualify (`FAILED_CREATE` vs `FAILED_UPDATE`). The source enum's name `FAILED_UPDATE` (verb after `FAILED`) is also grammatically awkward — `UPDATE_FAILED` is the standard ordering. -- **Rationale:** Two sibling enums in the same file with the same conceptual shape should use the same naming pattern. Today they diverge for no reason. - -### 2. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` +### 1. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` - **Why weird:** The "successfully ingested / ready" terminal state is named `UPDATED` — past tense of the in-flight `UPDATING`. A reader scanning `UPDATING/UPDATED/FAILED_UPDATE` will see "the source has been updated" which sounds transient (it was just updated, then something else might happen). The sibling assistant enum uses `ACTIVE` for the same concept (the resource is ready and operational), which is much clearer. - **Category:** 6 (misleading), 13 (verb tense), 17 (inconsistency: assistant has `ACTIVE`, source has `UPDATED`). - **Suggested name:** `READY` (or `ACTIVE`, matching the assistant) for the ready/operational state. `UPDATING` stays for in-flight. - **Rationale:** `UPDATED` implies "the action happened" rather than "the resource is in a ready state." A state enum should describe the resource's condition, not the last operation that touched it. -### 3. `name` field overloaded with semantic role — every request and entity — `src/v1/model.ts:55,64,72,84,120,129,137,160,209,315,324,359` -- **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`knowledge-assistants/{id}` or `.../examples/{id}` etc.). At the call site this is fine for one resource type but consumers chain operations across `KnowledgeAssistant`, `KnowledgeSource`, and `Example` — three `name`s in scope all meaning different things. `DeleteKnowledgeSourceRequest.name` is the source name; `SyncKnowledgeSourcesRequest.name` is the **assistant** name (the parent — see model.ts:312). That ambiguity is exactly what generic `name` causes. Compare with `Example.exampleId` and `KnowledgeAssistant.id` on the same file: when a typed id exists, it is more specific than `name`. -- **Category:** 1 (vague/generic), 15 (generic field losing meaning), 19 (underspecified id). -- **Suggested name:** Type-qualified: `assistantName`, `sourceName`, `exampleName`. Or, more aligned with Google AIP-122 (https://google.aip.dev/122): keep `name` *only* when the field unambiguously identifies the **same** resource type that the request operates on; rename to `parent` (already used elsewhere — see #4) when it identifies a parent. -- **Rationale:** `SyncKnowledgeSourcesRequest.name` is the prime offender: the field is the *assistant* id, but the request is named for sources, so a reader expects the field to be a source id. A typed name (`assistantName`) closes the gap. - -### 4. `parent` field generic and inconsistent with `name` — `src/v1/model.ts:30,45,248,300,315` -- **Why weird:** `CreateExampleRequest.parent`, `CreateKnowledgeSourceRequest.parent`, `ListExamplesRequest.parent`, `ListKnowledgeSourcesRequest.parent`, and `SyncKnowledgeSourcesRequest.name` all refer to **the same wire concept** — a `knowledge-assistants/{id}` resource path. Four of them are called `parent`; the fifth is called `name`. AIP-132 (https://google.aip.dev/132) uses `parent` for list/create requests under a parent resource, so the four are AIP-correct. The `SyncKnowledgeSourcesRequest.name` outlier is the bug — its doc even says "The resource name of the Knowledge Assistant" (model.ts:312). -- **Category:** 17 (inconsistency: `parent` vs `name` for the same concept), 16 (field name contradicts the operation's target). -- **Suggested name:** Rename `SyncKnowledgeSourcesRequest.name` → `parent` to match the four sibling requests; alternatively rename all five to `assistant` or `knowledgeAssistantName`. -- **Rationale:** A consumer who's just learned that `parent` means "the assistant" will write `{parent: '...'}` into `SyncKnowledgeSourcesRequest` and the type checker will reject it for no good reason. - -### 5. `KnowledgeAssistant.id` vs `Example.exampleId` vs `KnowledgeSource.id` inconsistency — `src/v1/model.ts:93,164,235` -- **Why weird:** Three sibling entities, three id conventions: - - `KnowledgeAssistant.id?: string` (bare `id`) - - `KnowledgeSource.id?: string` (bare `id`, no doc) - - `Example.exampleId?: string` (qualified `exampleId`) - The bare `id` is doc'd as "The universally unique identifier (UUID) of the Knowledge Assistant" on `KnowledgeAssistant`, but `KnowledgeSource.id` has *no* JSDoc at all (model.ts:235). Compare with the sibling `supervisoragents` package: `SupervisorAgent.supervisorAgentId` (fully qualified, plus a deprecated `id` for back-compat) and `Tool.toolId`. The `knowledgeassistants` package is the inconsistent neighbor. -- **Category:** 1 (vague), 17 (inconsistency within the same package), 19 (underspecified id). -- **Suggested name:** `KnowledgeAssistant.knowledgeAssistantId` or `KnowledgeAssistant.assistantId`; `KnowledgeSource.knowledgeSourceId` or `sourceId`; keep `Example.exampleId` as-is. -- **Rationale:** Bare `id` is the most common footgun when two resources are passed to the same function (e.g., a UI dialog editing both an assistant and one of its sources). Typed ids prevent type-checker false negatives. - -### 6. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` +### 2. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` - **Why weird:** The doc literally enumerates the allowed values: `'The type of the source: "index", "files", or "file_table"'`. A `string` typing means callers can write `sourceType: 'INDEX'` (wrong case) or `sourceType: 'vector_search'` (typo) and the compiler accepts both. Same package already uses Zod-discriminated unions for `spec` (model.ts:229-233), so the type info exists; `sourceType` is the redundant string mirror. - **Category:** 16 (field contradicts type domain — declared as `string` when it is closed-set), 6 (misleading), 12 (duplicate of `spec.$case`). - **Suggested name:** Convert to an enum `KnowledgeSourceType` with values `Index | Files | FileTable`; or drop `sourceType` entirely because `spec.$case` already carries the discriminant. - **Rationale:** Stringly-typed enums are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals — TS supports closed string literal unions specifically to avoid this). The fact that `spec.$case` already discriminates makes `sourceType` pure noise on both reads and writes. -### 7. `Example.guidelines: string[]` and `Example.question: string` semantics overlap with `KnowledgeAssistant.instructions` — `src/v1/model.ts:86,91,185` -- **Why weird:** Three free-text "how should the assistant behave" fields are scattered across two types: `KnowledgeAssistant.instructions` (single string, global), `Example.guidelines` (array, per-question), `Example.question` (single string, paired with `guidelines`). The names do not disambiguate scope: a reader could reasonably guess `guidelines` are global and `instructions` are per-example; the actual mapping is the other way around. Compare with the same anti-pattern in `customllms.CustomLlm.instructions: string` + `CustomLlm.guidelines: string[]` (audited in `.agent/naming-audit/customllms.md` #12) — that audit flagged the exact same overlap. -- **Category:** 6 (misleading), 12 (duplicate concept), 15 (generic field). -- **Suggested name:** Rename `KnowledgeAssistant.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerRules` or `responseGuidelines`. Both names disambiguate scope. -- **Rationale:** Two free-text fields with synonymous names but different scope is one of the most common API-design defects. The audit caught the same pattern in `customllms`; flagging it here for SDK-wide consistency. - -### 8. `KnowledgeSource.spec` discriminated union name is generic — `src/v1/model.ts:229` -- **Why weird:** `KnowledgeSource.spec?: { $case: 'index'; index: IndexSpec } | { $case: 'files'; files: FilesSpec } | { $case: 'fileTable'; fileTable: FileTableSpec } | undefined`. The discriminator field is called `spec` — a generic CS term. The doc says "Specification for the knowledge source type." Consumers writing autocomplete will see `source.spec.$case` and `source.sourceType` both meaning "what kind of source is this", and have to remember that `spec` carries the *data* and `sourceType` carries the *string label*. Compare with the `supervisoragents.Tool.spec` field (same anti-pattern; same audit flagged in the sibling). -- **Category:** 1 (vague), 12 (duplicate of `sourceType` discriminant). -- **Suggested name:** `config` if the union carries configuration (it does); or `source` to mirror the `$case` semantics ("which source variant"). Best: collapse `sourceType` and `spec` into a single discriminated union. -- **Rationale:** `spec` is so generic it conveys no information; the type already conveys "this is the spec". - -### 9. `KnowledgeAssistant_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:9` +### 3. `KnowledgeAssistant_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:9` - **Why weird:** The enum is named `KnowledgeAssistant_State` with a literal `_State` infix, and the file even carries an eslint-disable comment declaring "Proto-style nested enum name" (model.ts:8). The underscore is a direct architectural leak from the upstream `.proto` definition where the enum was nested inside the `KnowledgeAssistant` message (proto generates `OuterMessage_InnerEnum` for nested enums). TypeScript has no nested-enum-inside-class concept, so the underscore conveys nothing to a TS consumer and just signals "this code was generated from proto." - **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). - **Suggested name:** `KnowledgeAssistantState` (drop the underscore — already the convention in non-leaky TS APIs). The generator can flatten nested-enum names without changing the wire format. - **Rationale:** The proto wire format and the TS identifier shape are decoupled. Carrying the `Outer_Inner` separator into TS leaks the generator's source format and conflicts with the SDK-wide naming-convention lint rule (the file disables `@typescript-eslint/naming-convention` for exactly this reason). -### 10. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:17` -- **Why weird:** Same proto-nested-enum architectural leak as #9. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:16). Two sibling enums in the same file repeat the same proto-leak pattern. +### 4. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:17` +- **Why weird:** Same proto-nested-enum architectural leak as #3. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:16). Two sibling enums in the same file repeat the same proto-leak pattern. - **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). - **Suggested name:** `KnowledgeSourceState` (drop the underscore). -- **Rationale:** Same as #9. Generator-level fix. +- **Rationale:** Same as #3. Generator-level fix. ## Medium severity -### 11. `FileTableSpec.fileCol` cryptic abbreviation — `src/v1/model.ts:105` -- **Why weird:** `fileCol` truncates `column` to `Col`. The same pattern showed up in `customllms.Table.requestCol`/`responseCol` (flagged in `customllms.md` #15). The field on its sibling, `IndexSpec`, uses both `textCol` and `docUriCol` — same abbreviation. Other fields in the same file spell things out (`endpointName`, `experimentId`, `knowledgeCutoffTime`), so `Col` is inconsistent within the package. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency). -- **Suggested name:** `fileColumn` (and `textColumn` / `docUriColumn`). -- **Rationale:** Three characters of identifier savings is not worth the cognitive split between the doc ("column") and the field name. - -### 12. `IndexSpec.textCol` / `IndexSpec.docUriCol` cryptic abbreviation — `src/v1/model.ts:145,147` -- **Why weird:** Same `Col` abbreviation as #11, plus `docUri` truncates "document URI" awkwardly. Reading `docUriCol`, your eye parses `doc-Uri-Col` — three abbreviations stacked. The doc reads "The column that specifies a link or reference to where the information came from" — a much friendlier name would be `sourceUriColumn` or `referenceColumn`. -- **Category:** 5 (cryptic abbreviation), 3 (acronym casing: `Uri` vs `URI`). -- **Suggested name:** `documentUriColumn` or `sourceUriColumn` (spell out `document`; promote `Uri` to `URI` if SDK convention is all-caps for three-letter acronyms — see Observation #34). -- **Rationale:** The savings are minimal; the readability cost is real. - -### 13. `IndexSpec.indexName` type-suffix tautology — `src/v1/model.ts:143` -- **Why weird:** `IndexSpec.indexName` repeats `Index` in the type and field. The doc says it is the full UC name of the vector search index. Same pattern as `FileTableSpec.tableName` (model.ts:103). Both fields are documented as a fully-qualified three-part UC name (catalog.schema.x) — same concept Unity Catalog calls `full_name` in `catalog.TableInfo.full_name`. -- **Category:** 20 (type-suffix tautology), 1 (vague — `*Name` does not communicate "fully qualified"). -- **Suggested name:** `fullName` (matches Unity Catalog convention) or `qualifiedName`. If kept as `*Name`, at least drop the type prefix: `IndexSpec.fullName` reads better than `IndexSpec.indexName`. -- **Rationale:** Unity Catalog already has a canonical token; reusing it makes cross-API code less surprising. - -### 14. `FileTableSpec.tableName` type-suffix tautology — `src/v1/model.ts:103` -- **Why weird:** Same problem as #13 — `FileTableSpec.tableName` repeats `Table` in the type and field. -- **Category:** 20 (type-suffix tautology), 1 (vague). -- **Suggested name:** `fullName` or `qualifiedName`. -- **Rationale:** Same as #13. - -### 15. `Example.question` + `Example.guidelines` field-name doublet — `src/v1/model.ts:86,91` -- **Why weird:** `Example` has two free-text payload fields: the question being asked and the guidelines for the answer. The current names are fine *in isolation*, but the type's own doc explains "Contains a question and guidelines for how the assistant should respond" — and the field names then duplicate the doc verbatim. The bigger issue: `guidelines: string[]` is plural and an array, but no JSDoc explains the semantics of each element (is each entry a sentence? a bullet? a paragraph?). Combined with the parallel `KnowledgeAssistant.instructions: string` (#7), the naming makes the conceptual hierarchy unclear. -- **Category:** 15 (generic field name losing meaning), 1 (vague — "guidelines" of what?). -- **Suggested name:** `Example.question` is fine; rename `Example.guidelines` → `answerGuidelines` (or `responseGuidelines`, paired with rename in #7). -- **Rationale:** A type that owns a single question/answer pair should make the answer-shaped field explicit. - -### 16. `KnowledgeAssistant.endpointName` underspecified — `src/v1/model.ts:191` -- **Why weird:** The doc reads "The name of the knowledge assistant agent endpoint." Three reads of "agent endpoint" raise the question: is this a model-serving endpoint? An MLflow endpoint? An AI Gateway endpoint? The sibling SDK `customllms` has the same `endpointName: string` (flagged in `customllms.md` #7 as ambiguous). In Databricks the term "endpoint" alone is overloaded across `model_serving`, `sql_warehouses`, `vector_search_endpoints`, etc. -- **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or just `agentEndpointName`. The sibling `supervisoragents.KnowledgeAssistant.servingEndpointName` actually uses `servingEndpointName` (see `supervisoragents/src/v1/model.ts:129`), so the rename here would *align* the two packages. -- **Rationale:** Cross-package consistency wins. `supervisoragents` already named the field correctly; copy that. - -### 17. `KnowledgeAssistant.experimentId` — what kind of experiment? — `src/v1/model.ts:193` -- **Why weird:** Doc reads "The MLflow experiment ID." A bare `experimentId` is fine *if* the consumer knows the SDK only integrates with MLflow. But the consumer reading `KnowledgeAssistant.experimentId` could reasonably guess this is an A/B-test experiment, a feature-flag experiment, or an MLflow experiment. The doc clarifies — but the name does not. -- **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `mlflowExperimentId` (matches the doc; matches `databricks.mlflow` API convention). -- **Rationale:** Field names should not require reading JSDoc to disambiguate. Same reasoning as #16. - -### 18. `KnowledgeAssistant.errorInfo: string` — `src/v1/model.ts:195` +### 5. `KnowledgeAssistant.errorInfo: string` — `src/v1/model.ts:195` - **Why weird:** Two issues: - Suffix `Info` is generic CS noise (rule 8: redundant suffix). `error` alone or `errorMessage` is more specific. - Type is `string` but the field is reserved for "Error details when the Knowledge Assistant is in FAILED state." Other Databricks APIs (jobs, clusters) use structured `ErrorInfo` objects with `code`, `message`, `details`. A bare string forces consumers to parse free text — and a future structured upgrade would be a breaking change. @@ -137,31 +55,7 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `errorMessage` (if the field stays a string) or convert to an `ApiError` object (if the field upgrades). Drop the `Info` suffix either way. - **Rationale:** The `Info` suffix is a Go/Java carryover (`*Info` types are common in proto messages); TS gets clearer names without it. -### 19. `KnowledgeAssistant.creator: string` — what is a creator? — `src/v1/model.ts:187` -- **Why weird:** Doc reads "The creator of the Knowledge Assistant." Could be a username, email, UUID, Databricks principal id, or service principal client id. The type is `string`. The exact same pattern was flagged in `customllms.md` #10 — also a `creator: string`. The convention varies across the SDK: - - Unity Catalog: `created_by` (matches AIP-148, https://google.aip.dev/148) - - Jobs: `creator_user_name` - - This package: `creator` -- **Category:** 1 (vague), 19 (underspecified id), 17 (inconsistency across SDK). -- **Suggested name:** `createdBy` (AIP-148 standard, also matches `unitycatalog`) with JSDoc clarifying it is a user email. -- **Rationale:** Match the most-used convention. `createdBy` reads naturally and is widely understood. - -### 20. `KnowledgeSource.knowledgeCutoffTime` ambiguous semantics — `src/v1/model.ts:237` -- **Why weird:** Doc reads "Timestamp representing the cutoff before which content in this knowledge source is being ingested." Two interpretations: - - "Ingestion stops at this time" (a future bound). - - "Only content created before this time is being ingested" (a past bound). - The field name `knowledgeCutoffTime` does not disambiguate, and the doc grammar ("being ingested" — present continuous) makes it worse. AIP-142 (timestamp naming) would suggest `dataAsOf` for "content as of this time" or `ingestionDeadline` for "must finish by". -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `dataAsOf` or `contentAsOf` if the field is a past bound (most likely); `ingestionDeadline` if it is a future bound. -- **Rationale:** A timestamp field whose meaning depends on JSDoc parsing is a footgun. Pick a name that encodes direction. - -### 21. `KnowledgeSource_State.UPDATING` vs `KnowledgeAssistant_State.CREATING` inconsistent verbs — `src/v1/model.ts:11,19` -- **Why weird:** Both enums describe "a write operation is in flight." The assistant uses `CREATING` (matches its lifecycle — assistants are created once and updated thereafter). The source uses `UPDATING` (matches its lifecycle — sources are created with content, then their content is refreshed via sync). Both enums conflate "creation" and "update" into one in-flight state; the names just disagree on which verb to use. -- **Category:** 13 (verb-tense / verb-choice inconsistency), 17 (inconsistency across sibling enums). -- **Suggested name:** Both should use `PROCESSING` or `IN_PROGRESS` — operation-agnostic in-flight markers. If lifecycle stages matter, both should split into `CREATING` / `UPDATING` consistently. -- **Rationale:** The asymmetry suggests the API team modeled the two resources separately and never unified the lifecycle vocabulary. - -### 22. `Client` class name — bare, no scoping — `src/v1/client.ts:63` +### 6. `Client` class name — bare, no scoping — `src/v1/client.ts:63` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-knowledgeassistants/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as KAClient} from '@databricks/sdk-knowledgeassistants/v1'`. Other SDKs in the Databricks ecosystem name the class `KnowledgeAssistantsClient` (or `KnowledgeAssistantsApi`), avoiding the alias dance. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `KnowledgeAssistantsClient`. Sibling SDK packages (Go SDK reference uses `WorkspaceClient.KnowledgeAssistants`; AWS JS SDK uses `S3Client`, `IAMClient`) follow this pattern. @@ -169,55 +63,49 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Low severity -### 23. `KnowledgeAssistant_State.CREATING` vs `KnowledgeSource_State.UPDATING` — `src/v1/model.ts:11,19` -- **Why weird:** See #21; flagged again at low severity as a *style* concern (the higher-severity finding is the verb-mismatch). -- **Category:** 13 (verb tense). -- **Suggested name:** See #21. -- **Rationale:** Cosmetic but consistent with audit's "verb-tense inconsistency" category. - -### 24. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +### 7. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21. - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than one infix. -### 25. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +### 8. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` - **Why weird:** Same as `customllms.md` #23: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in the same file. Three things named `Options`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams`. - **Rationale:** Distinguish internal context bags from user-facing options. -### 26. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 9. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `customllms.md` #28: exported but not used by `client.ts`. - **Category:** Observation / 11 (unused export). - **Suggested name:** Either remove the export or document why it ships per-package. - **Rationale:** Generated artifact; flag for cross-package cleanup. -### 27. `readAll` helper generic name — `src/v1/utils.ts:40` +### 10. `readAll` helper generic name — `src/v1/utils.ts:40` - **Why weird:** Same as `customllms.md` #29: helper reads an entire response body stream; name is generic. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 28. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` +### 11. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` - **Why weird:** Same as `customllms.md` #24: `Segment` is a generic CS term. - **Category:** 1 (vague). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** SDK-wide consistency review. -### 29. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` +### 12. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` - **Why weird:** Same as `customllms.md` #33: `resp` is the response. 12 methods repeat the same pattern. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. - **Rationale:** Refactor opportunity surfaced by audit. -### 30. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` +### 13. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` - **Why weird:** Three async generator methods each declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. Minor abbreviation inconsistency: `request` would be clearer in the iterator context, where the variable's purpose ("the request used to fetch each page") differs from the input `req`. - **Category:** 5 (abbreviation). - **Suggested name:** `pageRequest` or `nextPageReq`. - **Rationale:** Local clarity for readability. -### 31. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` +### 14. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` - **Why weird:** `knowledgeSourceFieldMaskSchema` carries top-level entries `fileTable`, `files`, `index` — matching the `$case` keys, but the wire serialization uses `file_table`/`files`/`index`. Reading the schema, a consumer might write `knowledgeSourceFieldMask('spec.files')` expecting the variant-aware path; the field-mask schema has no `spec` key at all. The discriminated union variants are flattened to top-level field-mask paths, which is correct AIP-161 (https://google.aip.dev/161) behavior — but jarring if you've read the TS type. - **Category:** 17 (inconsistency between TS shape and field-mask schema). - **Suggested name:** Not a rename; flag for documentation. @@ -225,29 +113,29 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Observations -### 32. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` +### 15. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` - **Why weird:** Doc says "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Either every `description` should carry this annotation, or none should. Flagged for cross-package style review. - **Category:** Observation. -### 33. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` +### 16. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` - **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. - **Category:** 17 (reversed — consistency note). -### 34. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` -- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id (see #3, #4). The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. +### 17. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id. The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. -### 35. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` +### 18. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` - **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `ApiError` usage. Cross-cutting observation from `customllms.md` #36. - **Category:** 3 (acronym casing — SDK-wide). - **Suggested name:** SDK-wide policy decision. -### 36. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +### 19. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` - **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. - **Category:** Observation. -### 37. `Example` lacks `state` field — `src/v1/model.ts:79-98` +### 20. `Example` lacks `state` field — `src/v1/model.ts:79-98` - **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. - **Category:** Observation. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index 55d8d0be..a7e81087 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,16 +3,16 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 34 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | ----------- | ----- | | High | 6 | -| Medium | 14 | -| Low | 10 | -| Observation | 5 | +| Medium | 5 | +| Low | 4 | +| Observation | 4 | ## Summary table @@ -25,34 +25,18 @@ | 5 | High | `model.ts` interface | `Dashboard` | 1, 15 | | 6 | High | `model.ts` interface | `PublishedDashboard` | 12 | | 7 | Medium | `model.ts` interface | `CronSchedule` | 1 | -| 8 | Medium | `model.ts` field | `CronSchedule.quartzCronExpression` | 14, 20 | -| 9 | Medium | `model.ts` field | `CronSchedule.timezoneId` | 19 | -| 10 | Medium | `model.ts` field | `Schedule.cronSchedule` | 20 | -| 11 | Medium | `model.ts` enum | `SchedulePauseStatus` | 1, 7 | -| 12 | Medium | `model.ts` field | `Schedule.pauseStatus` | 6, 20 | -| 13 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | -| 14 | Medium | `model.ts` field | `MigrateDashboardRequest.sourceDashboardId` | 16 | -| 15 | Medium | `model.ts` field | `MigrateDashboardRequest.updateParameterSyntax` | 6, 13, 15 | -| 16 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | -| 17 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | -| 18 | Medium | `model.ts` field | `GetPublishedDashboardTokenInfoResponse.customClaim` | 15 | -| 19 | Medium | `model.ts` field | `AuthorizationDetails.type` | 10, 15 | -| 20 | Medium | `model.ts` field | `AuthorizationDetails.resourceLegacyAclPath` | 6, 14, 16 | -| 21 | Low | `model.ts` field | `Subscription.skipNotify` | 1, 14 | -| 22 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | -| 23 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | -| 24 | Low | `model.ts` field | `Schedule.warehouseId` | 19, 12 | -| 25 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | -| 26 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | -| 27 | Low | `model.ts` field | `Dashboard.serializedDashboard` | 20 | -| 28 | Low | `model.ts` field | `Dashboard.createTime` / `updateTime` & `Schedule.*` / `Subscription.*` | 9 | -| 29 | Low | `model.ts` field | `PublishedDashboard.revisionCreateTime` | 15 | -| 30 | Low | `model.ts` field | `ListDashboardsRequest.showTrashed` | 13, 17 | -| 31 | Observation | `model.ts` field | `Dashboard.dashboardId` (tautology in `dashboard.dashboardId`) | 8, 20 | -| 32 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | -| 33 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | -| 34 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | -| 35 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | +| 8 | Medium | `model.ts` enum | `SchedulePauseStatus` | 1, 7 | +| 9 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | +| 10 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | +| 11 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | +| 12 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | +| 13 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | +| 14 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | +| 15 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | +| 16 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | +| 17 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | +| 18 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | +| 19 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | --- @@ -194,68 +178,7 @@ The package exports a top-level `CronSchedule`. The same name appears in `alerts **Rationale:** Future-proofing: the field set may diverge from other services' cron-schedule types (some add a `pauseStatus`, some add a `nextFireTime`). A domain-prefixed name prevents `import { CronSchedule } from '@databricks/sdk-lakeview'` from being a confusing rename. -### 8. `CronSchedule.quartzCronExpression` — implementation-detail leak and type-suffix tautology - -**Location:** `src/v1/model.ts:85` - -```ts -/** - * A cron expression using quartz syntax. EX: `0 0 8 * * ?` represents everyday at 8am. - */ -quartzCronExpression?: string | undefined; -``` - -Two concerns: - -1. `quartz` exposes the JVM scheduler library (Quartz Scheduler). A TypeScript SDK user will not know what "Quartz syntax" is, and even if they do, the *only* cron syntax the API accepts is Quartz — calling it out by name only serves to confuse beginners who write standard cron (5 fields instead of 6). -2. `cronExpression` is a type-suffix tautology — the field is on a type called `CronSchedule`; calling the field `expression` (or even just `cron`) is enough. - -**Category:** 14 (Java implementation detail leak), 20 (type-suffix tautology). - -**Suggested name:** `expression` (with the doc clarifying "Quartz 6-field cron syntax: `seconds minutes hours dayOfMonth month dayOfWeek`"). The doc, not the field name, should explain the dialect. - -**Rationale:** The wire format `quartz_cron_expression` is locked, but the TS name is not. A simple, accurate field name with the dialect in the doc is more usable. - -### 9. `CronSchedule.timezoneId` — "Id" suffix is misleading - -**Location:** `src/v1/model.ts:90` - -```ts -/** - * A Java timezone id. The schedule will be resolved with respect to this timezone. - */ -timezoneId?: string | undefined; -``` - -The field carries an IANA timezone name like `"America/Los_Angeles"`. That is not an "id" in any normal sense (no numeric handle, no opaque token); it's a string identifier in a documented registry. The doc also locks the value space to "Java timezone id" — meaning the JVM TZ database, which is IANA-compatible but not guaranteed identical (some abbreviations like `EST`, `PST` are accepted in Java but ambiguous in IANA). - -**Category:** 19 (underspecified ID — actually a string name). - -**Suggested name:** `timezone` (or `tz`), with the doc specifying "IANA timezone name (e.g. 'America/Los_Angeles' or 'UTC')". Drop the "Java" qualifier — JS users do not need to know the backend's runtime. - -**Rationale:** `timezoneId` makes callers think there's a separate `getTimezones()` API that returns IDs. - -### 10. `Schedule.cronSchedule` — type-suffix tautology - -**Location:** `src/v1/model.ts:332` - -```ts -export interface Schedule { - ... - cronSchedule?: CronSchedule | undefined; - ... -} -``` - -The field name and type name are the same. `schedule.cronSchedule.expression` reads as "schedule's cron-schedule's expression" — the middle term is redundant. Compare to `Schedule.cron` or `Schedule.cronExpression` (with `CronSchedule` as the type), which read as `schedule.cron.expression`. - -**Category:** 20 (type-suffix tautology). - -**Suggested name:** `cron: CronSchedule`. Field shows up at use sites as `schedule.cron.expression`, which is the intended mental model. - -**Rationale:** Field names should describe the *role* the value plays in the parent, not echo the type. The role is "the cron part of this schedule". - -### 11. `SchedulePauseStatus` — domain prefix only partially applied +### 8. `SchedulePauseStatus` — domain prefix only partially applied **Location:** `src/v1/model.ts:18-21` @@ -276,24 +199,7 @@ Also: a two-value enum named `*Status` for two paused-or-not states is overengin **Rationale:** Binary status enums are an anti-pattern in TS where booleans are first-class. The Go SDK is constrained to enums (no booleans for proto), but the TS SDK is not. -### 12. `Schedule.pauseStatus` — field describes a control input, not a status - -**Location:** `src/v1/model.ts:334` - -```ts -/** The status indicates whether this schedule is paused or not. */ -pauseStatus?: SchedulePauseStatus | undefined; -``` - -"Status" implies read-only state (something the system reports). But this field is also writable — clients send `pauseStatus: PAUSED` to *cause* the pause. The field is therefore the pause *setting*, not the pause *status*. The doc reinforces the misuse ("indicates whether…"). - -**Category:** 6 (misleading), 20 (the type ends in `Status` and the field starts with `pauseStatus` — overlap). - -**Suggested name:** `paused: boolean` (see #11), or `pauseSetting`/`pauseMode`. Reserve `*Status` for read-only state. - -**Rationale:** Read/write distinction. If the user only learns the field name, they will not predict that setting `UNPAUSED` is how you un-pause. - -### 13. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb +### 9. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb **Location:** `src/v1/model.ts:285`, `src/v1/client.ts:540` @@ -305,48 +211,7 @@ pauseStatus?: SchedulePauseStatus | undefined; **Rationale:** The other Databricks "migrate" endpoints (e.g. `tables.migrate`, `permissions.migrate`) actually move state. This one creates a new asset. Same verb, two operations. -### 14. `MigrateDashboardRequest.sourceDashboardId` — domain mismatch - -**Location:** `src/v1/model.ts:287` - -```ts -/** UUID of the dashboard to be migrated. */ -sourceDashboardId?: string | undefined; -``` - -The package documents `dashboardId` as identifying a Lakeview / AI/BI dashboard. `sourceDashboardId` here is a **classic SQL dashboard** ID — a different ID space, fetched from a different API (`/api/2.0/sql/dashboards/{id}`). Using the same `dashboardId` type-name suggests they are interchangeable; they are not. - -**Category:** 16 (field contradicting type domain). - -**Suggested name:** `sourceLegacyDashboardId` / `classicSqlDashboardId` / `sqlDashboardId`. JSDoc should call out the ID space explicitly. - -**Rationale:** Cross-API IDs that share a name are a frequent source of integration bugs. - -### 15. `MigrateDashboardRequest.updateParameterSyntax` — confusing default + leaky implementation hint - -**Location:** `src/v1/model.ts:293-296` - -```ts -/** - * Flag to indicate if mustache parameter syntax ({{ param }}) should be auto-updated - * to named syntax (:param) when converting datasets in the dashboard. - */ -updateParameterSyntax?: boolean | undefined; -``` - -Issues: - -1. The default behavior (when omitted) is undocumented. From the wire form, server defaults are likely `false`, meaning the migration will leave mustache placeholders intact and break the query — which is the opposite of what most callers want. -2. The doc invokes "mustache" (a template-engine name) without explanation; a TS reader who hasn't worked in classic SQL Dashboards will not know what `{{ param }}` is. -3. "Update" is vague: it's actually a *rewrite* — `:param` is not an "update" of `{{ param }}` but a syntax replacement. - -**Category:** 6 (misleading), 13 (verb tense inconsistency: "update" vs "rewrite"), 15 (generic field name losing meaning). - -**Suggested name:** `rewriteParametersAsNamed: boolean` (verb explicit) or `mustacheCompatibilityMode: boolean` (opposite polarity, clearer default). Doc should state the default and provide an example. - -**Rationale:** Migration is a one-way operation; setting this wrong is hard to recover from. - -### 16. `trashDashboard` — soft-delete method without a paired restore (see also #4) +### 10. `trashDashboard` — soft-delete method without a paired restore (see also #4) **Location:** `src/v1/client.ts:592` @@ -358,7 +223,7 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met **Rationale:** Symmetry. `deletePermanently` is also unavailable here — soft-delete is the only delete. -### 17. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles +### 11. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles **Location:** `src/v1/model.ts:299`, `src/v1/model.ts:315` @@ -370,92 +235,11 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met **Rationale:** Reduce typo bugs. The Databricks SDK already uses `*Options` in `ClientOptions`, `CallOptions`, so the pattern is precedented. -### 18. `GetPublishedDashboardTokenInfoResponse.customClaim` — undescriptive field for opaque blob - -**Location:** `src/v1/model.ts:188` - -```ts -/** - * Custom claim generated from external_value and external_viewer_id. - * Format: `urn:aibi:external_data:::` - */ -customClaim?: string | undefined; -``` - -The doc string is the only place that defines what the field is — a URN with a specific format. The field name `customClaim` is generic JWT-speak (a "custom claim" in OAuth/OIDC is any non-standard claim). The actual value is a *Databricks AI/BI external-data URN*. Two layers of indirection from the name. - -**Category:** 15 (generic field name). - -**Suggested name:** `externalDataUrn` or `embeddingUrn` (with `customClaim` mentioned in JSDoc as "this URN is embedded as a custom claim in the issued OAuth token"). - -**Rationale:** Distinct from the OIDC sense of "custom claim". - -### 19. `AuthorizationDetails.type` — collides with TS reserved feeling - -**Location:** `src/v1/model.ts:28` - -```ts -type?: string | undefined; -``` - -`type` is not a reserved word in TypeScript, but it is a *contextual* keyword (used in `type X = ...` declarations and in `import type { ... }`). Using `type` as a field name is legal but creates friction in tooling — auto-complete and rename-symbol can mis-fire. - -The field's documented value space is also limited: `"workspace_rule_set"` is the only documented constant; the rest is open. So the field is closer to a tag (`discriminator: 'workspace_rule_set'`) than a free string. - -**Category:** 10 (reserved-word-feel collision), 15 (generic). - -**Suggested name:** `kind` (matches K8s convention for discriminator fields), or `constraintType` to keep "type" but specialize it. - -**Rationale:** Avoid syntax-coloring confusion (`type: string` reads ambiguously) and signal that the field is a discriminator. - -### 20. `AuthorizationDetails.resourceLegacyAclPath` — legacy compatibility field in current API - -**Location:** `src/v1/model.ts:36` - -```ts -/** The acl path of the tree store resource resource. */ -resourceLegacyAclPath?: string | undefined; -``` - -Three issues: - -1. The field name advertises `Legacy` — meaning a field deliberately kept around for backwards compatibility. There is no documented sunset date or replacement field. A public API surface that hard-codes "legacy" in the field name will be locked into supporting it forever (since the name itself is a contract). -2. The doc has a typo: "tree store resource resource" — duplicated "resource". -3. `acl` is lowercase (compare to the more common `Acl`/`ACL` in the SDK). - -**Category:** 6 (misleading — "legacy" is permanent here), 14 (TreeStore is an internal Databricks system, leaking implementation), 16 (field contradicts type domain). - -**Suggested name:** `legacyAclPath` (drop the duplicate "resource"; rename does not really fix the long-term problem, only the doc string typo). - -**Rationale:** Cosmetic doc fix is cheap; the structural issue is that the field name preserves an internal compat detail in the public API. - --- ## Low severity -### 21. `Subscription.skipNotify` — negative polarity boolean - -**Location:** `src/v1/model.ts:374` - -```ts -/** - * Controls whether notifications are sent to the subscriber for scheduled dashboard refreshes. - * If not defined, defaults to false in the backend to match the current behavior (refresh and notify) - */ -skipNotify?: boolean | undefined; -``` - -Negative-polarity booleans are an antipattern: callers must invert the meaning mentally (`subscription.skipNotify = false` means "do notify"). Combined with `?:` optionality, the field has three meaningful states (`undefined` = backend default = notify; `false` = notify; `true` = don't notify), where two of them mean the same thing. - -The doc also leaks "in the backend" — the default is the backend's, not the SDK's. - -**Category:** 1 (vague), 14 (the backend-leak phrasing). - -**Suggested name:** `notify?: boolean` (positive polarity) or `silent?: boolean`. Document the inverted default. - -**Rationale:** Positive-polarity booleans halve the cognitive load. - -### 22. `Subscription.createdByUserId` typed as `number` +### 12. `Subscription.createdByUserId` typed as `number` **Location:** `src/v1/model.ts:360` @@ -474,7 +258,7 @@ Also, the doc string is past-tense verb plus present-tense ("adds") — inconsis **Rationale:** Silent overflow is the worst kind of bug. -### 23. `Dashboard.warehouseId` — underspecified ID +### 13. `Dashboard.warehouseId` — underspecified ID **Location:** `src/v1/model.ts:112` @@ -484,22 +268,7 @@ Also, the doc string is past-tense verb plus present-tense ("adds") — inconsis **Suggested name:** Keep `warehouseId`, but JSDoc should specify "SQL Warehouse ID (alphanumeric, found at `/sql/warehouses/{id}` in the UI)". -### 24. `Schedule.warehouseId` — duplicate concept with `Dashboard.warehouseId` - -**Location:** `src/v1/model.ts:347` - -```ts -/** The warehouse id to run the dashboard with for the schedule. */ -warehouseId?: string | undefined; -``` - -A schedule can override the dashboard's default warehouse. This is fine, but the field name does not signal "override" — at first read it looks like the dashboard's warehouse is being duplicated into the schedule. - -**Category:** 19 (underspecified), 12 (overlap with `Dashboard.warehouseId`). - -**Suggested name:** `warehouseIdOverride` or `overrideWarehouseId`. - -### 25. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing +### 14. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing **Location:** `src/v1/model.ts:118`, `src/v1/model.ts:341`, `src/v1/model.ts:365` @@ -509,7 +278,7 @@ Consistent within the package, but the HTTP spec spells it `ETag`. Most TS SDKs **Suggested name:** Keep `etag`. Note the project convention. -### 26. `Dashboard.path` vs `Dashboard.parentPath` — overlap +### 15. `Dashboard.path` vs `Dashboard.parentPath` — overlap **Location:** `src/v1/model.ts:103`, `src/v1/model.ts:135` @@ -524,81 +293,11 @@ parentPath?: string | undefined; // workspace path of the folder containing t **Suggested name:** Keep both. Either rename `path → fullPath` for symmetry, or document the relationship in JSDoc on both fields. -### 27. `Dashboard.serializedDashboard` — type-suffix tautology - -**Location:** `src/v1/model.ts:127` - -```ts -serializedDashboard?: string | undefined; -``` - -Field is on `Dashboard`; suffix repeats the type name. The field holds a JSON string of the dashboard's layout — a stringified payload. - -**Category:** 20. - -**Suggested name:** `serialized` or `content` or `layoutJson`. The dashboard's "content" is a more useful description. - -### 28. `createTime`/`updateTime` suffix `Time` — convention question - -**Location:** Many fields on `Dashboard`, `Schedule`, `Subscription` - -The package uses `*Time` suffix (`createTime`, `updateTime`). The alerts v2 package uses `*At` (`lastEvaluatedAt`). Inconsistency across the SDK. The field type here is `Temporal.Instant`, which is point-in-time — `*At` reads more naturally for instants in English. - -**Category:** 9 (related; suffix-grammar inconsistency). - -**Suggested name:** Pick a project-wide convention. Recommend `*At` for instants (`createdAt`, `updatedAt`). Aligns with idiomatic JS/TS and the Rails-influenced ecosystem. - -### 29. `PublishedDashboard.revisionCreateTime` — over-qualified - -**Location:** `src/v1/model.ts:323` - -```ts -/** The timestamp of when the published dashboard was last revised. */ -revisionCreateTime?: Temporal.Instant | undefined; -``` - -"Revision Create Time" reads as "the create time of the revision", i.e. when the latest revision was published. The field name carries three nouns (`revision`, `create`, `time`). - -**Category:** 15 (generic, layered). - -**Suggested name:** `publishedAt` or `lastPublishedAt`. Captures the user's mental model directly. - -### 30. `ListDashboardsRequest.showTrashed` — verb mismatch with state name (trash/delete vocabulary) - -**Location:** `src/v1/model.ts:227` - -```ts -showTrashed?: boolean | undefined; -``` - -The field is named `showTrashed`, but the lifecycle state is `TRASHED`. Consistent within "trash vocabulary", but inconsistent if the rename in #4 lands (`DELETED` lifecycle would imply `showDeleted` flag). Same vocabulary split inherited from pre-v2 alerts (see #4 and #16). - -**Category:** 13 (verb tense across vocabulary), 17 (action verb consistency). - -**Suggested name:** Tie to whichever vocabulary wins. If `delete`/`DELETED`, then `includeDeleted`. The `show` prefix is also UI-flavored (compare `include`/`with` prefixes in REST APIs). - --- ## Observations -### 31. `Dashboard.dashboardId` — tautology at use site - -**Location:** `src/v1/model.ts:95` - -```ts -export interface Dashboard { - dashboardId?: string | undefined; - ... -} -``` - -Caller writes `dashboard.dashboardId`. Inside a type already named `Dashboard`, the field could be `id`. Many SDKs prefer the prefix-form for unambiguous logs and reflection, but the *consumer-facing* readability is poorer. - -**Category:** 8 (field name == type name with `Id` suffix), 20. - -**Suggested name:** `Dashboard.id` (and similarly `Schedule.id`, `Subscription.id`). Marshal/unmarshal already remaps to/from `dashboard_id`. - -### 32. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix +### 16. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix **Location:** `src/v1/model.ts:61,67` @@ -611,7 +310,7 @@ datasetSchema?: string | undefined; **Suggested name:** Keep. Add JSDoc clarifying "this is the Unity Catalog *catalog* / *schema* applied to dataset queries". Done already in the JSDoc, but worth flagging. -### 33. `ListSchedulesRequest.dashboardId` doc typo +### 17. `ListSchedulesRequest.dashboardId` doc typo **Location:** `src/v1/model.ts:242` @@ -624,7 +323,7 @@ dashboardId?: string | undefined; **Category:** 9 (plural verb agreement). -### 34. `index.ts` — mixed `export {...}` and `export type {...}` +### 18. `index.ts` — mixed `export {...}` and `export type {...}` **Location:** `src/v1/index.ts:5,7-43` @@ -635,7 +334,7 @@ export type {AuthorizationDetails, ...} from './model'; Enums are exported as values (correct — they have runtime representation); interfaces are exported as types (correct — type-only). The pattern is right; flagging only because a reader scanning the index file might miss the distinction. Consistent with other SDK packages. -### 35. URL paths still use `lakeview` +### 19. URL paths still use `lakeview` **Location:** Every method's URL constant in `client.ts`, e.g. line 105: `/api/2.0/lakeview/dashboards` @@ -650,15 +349,10 @@ Wire-format. The SDK cannot rename the URL without server cooperation. Flagged s Lakeview / AI/BI Dashboards is a relatively small surface (5 enums-and-resources, 19 client methods) but the naming smells cluster around: 1. **The rebrand from "Lakeview" to "AI/BI Dashboards"** is incomplete — the package name and URLs preserve the old codename, while the JSDoc mixes the two. -2. **The trash/delete vocabulary split** (#4, #16, #30) is inherited from the alerts package's pre-v2 design — already fixed in alerts v2 but not in lakeview. +2. **The trash/delete vocabulary split** (#4, #10) is inherited from the alerts package's pre-v2 design — already fixed in alerts v2 but not in lakeview. 3. **Generic top-level type names** (`Dashboard`, `LifecycleState`, `CronSchedule`, `SchedulePauseStatus`) overlap with other packages in the SDK monorepo and force consumers to import-rename. -4. **`Schedule.pauseStatus` enum is a binary boolean** (#11, #12) — `paused: boolean` would be more idiomatic TS. -5. **64-bit user IDs typed as `number`** (#22) silently truncate above 2^53. Same issue exists in other packages but is unsurfaced here. +4. **64-bit user IDs typed as `number`** (#12) silently truncate above 2^53. Same issue exists in other packages but is unsurfaced here. -If only one change were possible, completing the trash/delete vocabulary unification (renaming `trashDashboard` + `TRASHED` + `showTrashed` to the `delete`/`DELETED`/`includeDeleted` family used by alerts v2) would remove the most visible inconsistency. +If only one change were possible, completing the trash/delete vocabulary unification (renaming `trashDashboard` + `TRASHED` to the `delete`/`DELETED` family used by alerts v2) would remove the most visible inconsistency. --- - -## Fixed - -- #18 `GetPublishedDashboardEmbeddedRequest` / `getPublishedDashboardEmbedded` (originally cited at `src/v1/model.ts:169-175` and `src/v1/client.ts:301`): Fixed in regeneration on 2026-05-20 — the embedded-view request type and method were removed from the generated client. diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md index d608777a..606d521b 100644 --- a/.agent/naming-audit/logdelivery.md +++ b/.agent/naming-audit/logdelivery.md @@ -9,15 +9,15 @@ delivery configuration ties a `credentialsId` (AWS IAM role) and a `AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no delete endpoint by design — the API only supports disabling via the update (`PATCH`) method. -**Total weird names flagged:** 27 +**Total weird names flagged:** 22 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 10 | +| High | 5 | +| Medium | 7 | | Low | 7 | -| Observation | 4 | +| Observation | 3 | ## High severity @@ -52,21 +52,13 @@ update (`PATCH`) method. - **Suggested name:** Rewrite JSDoc to "Whether this log delivery configuration is active. Modified via the patch-status endpoint." - **Rationale:** Wrong JSDoc is worse than missing JSDoc — IDE tooltips, hover-help, and generated reference docs will all display the unrelated "dependencies" prose. The stray `* *` opening line is generator-level and worth fixing globally. -### 4. `LogDeliveryConfiguration.configId` / `.configName` use the cryptic abbreviation `config` — `src/v1/model.ts:171,173` -- **Why weird:** The field is `configId`, not `logDeliveryConfigurationId` (also at `model.ts:69,71`, `model.ts:126`, `model.ts:232`, `client.ts:94,126,154,218`). Inside the enclosing `LogDeliveryConfiguration` the abbreviation is contextually OK, but `configId` is generic at every method-call site — `req.configId` and the URL template `/log-delivery/${req.configId}` read as domain-detached. A consumer composing multiple Databricks SDK clients cannot grep for `configId` and know which "config" is meant. -- **Category:** 5 (cryptic abbreviation), 19 (under-specified id). -- **Suggested name:** Two coherent options: - 1. Keep `configId` (short, matches wire `config_id`) but rely on the enclosing type to disambiguate — same idiom as `databricks-sdk-go`. - 2. Rename to bare `id` and let `LogDeliveryConfiguration.id` carry meaning structurally — same idiom as Stripe (`Customer.id`), GitHub (`Repository.id`), and Google. -- **Rationale:** Pick one convention and apply globally. `configId` is the worst of both — a half-abbreviation that is neither a generic `id` nor a fully-qualified `logDeliveryConfigurationId`. - -### 5. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` +### 4. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` - **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:126,218`). The client substitutes them via `?? ''` (`client.ts:126,218`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). - **Category:** 6 (misleading — type signature says optional, runtime requires non-empty), 7 (overly verbose / boilerplate JSDoc). -- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create` — see finding 25). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." +- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create`). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." - **Rationale:** Required path params should have required types. The current shape silently produces malformed URLs at runtime. The "of customer" prose is generator-emitted boilerplate worth removing globally. -### 6. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` +### 5. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` - **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:209-213`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus`, which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. - **Category:** 6 (misleading), 17 (verb inconsistency — Go uses `PatchStatus`, TS paraphrases as `update`). - **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:227`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. @@ -74,25 +66,25 @@ update (`PATCH`) method. ## Medium severity -### 7. `Client` class is unprefixed — `src/v1/client.ts:46`, exported at `src/v1/index.ts:3` +### 6. `Client` class is unprefixed — `src/v1/client.ts:46`, exported at `src/v1/index.ts:3` - **Why weird:** A user importing the package writes `import {Client} from '@databricks/sdk-logdelivery/v1'` and must alias (`import {Client as LogDeliveryClient}`) to compose with any other Databricks SDK client. Consistent across the SDK; flagged once per package. - **Category:** 1 (vague), 12 (duplicate concept — every Databricks SDK package exports its own `Client`). - **Suggested name:** `LogDeliveryClient` (or expose a namespace and let `logDelivery.Client` be the qualified name). - **Rationale:** Every audited package has this finding. Worth normalising at generator level. -### 8. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` +### 7. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` - **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:160`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `listLogDeliveryConfigurations` (plural). The `*Iter` pagination helper should match: `listLogDeliveryConfigurationsIter`. - **Rationale:** Method-name pluralisation should match the data shape it yields. -### 9. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` -- **Why weird:** Same shape mismatch as finding 8, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. +### 8. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` +- **Why weird:** Same shape mismatch as finding 7, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and the `_Response` partner correspondingly). - **Rationale:** Pluralisation is the standard signal for a collection-returning method/type pair. -### 10. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` +### 9. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` - **Why weird:** Reading `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types whose names all carry "Status": - `LogDeliveryConfiguration` (the resource). - `LogDeliveryStatus` (wrapper for the last-attempt fields). @@ -103,37 +95,19 @@ update (`PATCH`) method. - **Suggested name:** Rename field `logDeliveryStatus` → `lastAttempt`. Rename wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`). Rename enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The call site becomes `config.lastAttempt.status === 'SUCCEEDED'` — three concrete nouns instead of three "Status" repetitions. - **Rationale:** "Status" is too generic to triple-stack. Aligns with findings 1 and 2. -### 11. `creationTime` / `updateTime` — noun/verb tense mismatch, ambiguous unit — `src/v1/model.ts:99-101,201-203` -- **Why weird:** `creationTime: number` (noun form "creation") paired with `updateTime: number` (verb form "update"). They should match: either `createdTime` / `updatedTime` (past participle) or `creationTime` / `updateTime` (noun + verb is inconsistent). Both are typed `number` but the unit (epoch milliseconds) lives only in the JSDoc — a reader scanning the type cannot tell whether this is seconds, milliseconds, or microseconds. -- **Category:** 13 (verb-tense inconsistency), 6 (misleading — bare `number` does not encode "epoch ms"). -- **Suggested name:** `createdAt: number` / `updatedAt: number` (the canonical SaaS convention used by Stripe, GitHub, Salesforce, Atlassian, Linear). Brand the type as `EpochMillis` to encode the unit at compile time. -- **Rationale:** `*At` is the industry standard for timestamps. Generator-wide concern — many audited packages share this finding. - -### 12. `deliveryStartTime: string` is a YYYY-MM date, not a time — `src/v1/model.ts:95,197` -- **Why weird:** The field is `string` typed, but the JSDoc says "specified in YYYY-MM format". That is a year-month bucket, not a "time". Compare with `creationTime: number` (an epoch-ms timestamp) in the same struct — the word "Time" is used for two different granularities. -- **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" suggests a timestamp). -- **Suggested name:** `deliveryStartMonth: string` (or, since `@js-temporal/polyfill` is already a workspace dependency, `Temporal.PlainYearMonth`). -- **Rationale:** "Time" implies sub-day resolution; the domain is monthly billing buckets, so "Month" is the right granularity. Same convention as Stripe's `period_start` (timestamp) vs `period.start` (date-only) split. - -### 13. `workspaceIdsFilter` — redundant `Filter` suffix on a collection field — `src/v1/model.ts:91,193` -- **Why weird:** The field is `workspaceIdsFilter: number[]` on both the request DTO (`CreateLogDeliveryConfigurationParams`, line 91) and the response DTO (`LogDeliveryConfiguration`, line 193). On the response DTO, `Filter` is misleading — the same field stores the configured workspace scope, not a "filter" applied at read time. Compare with `ListLogDeliveryConfigurationRequest.credentialsId: string` at `model.ts:145` (no `Filter` suffix, same conceptual role as a list filter). -- **Category:** 7 (overly verbose), 15 (generic suffix). -- **Suggested name:** `workspaceIds: number[]` (the array shape already conveys "list of workspace IDs"; the `Filter` suffix carries no extra signal). -- **Rationale:** Field naming should describe content. A `number[]` named after the entity is unambiguous. - -### 14. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` +### 10. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` - **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double-precision float — only safe up to 2^53 − 1. Databricks workspace IDs are int64 server-side; transmitting an ID above the safe range silently loses precision in the JSON wire round-trip. - **Category:** 6 (misleading — TS type cannot represent the wire's int64 safely), 19 (under-specified id type). - **Suggested name:** `workspaceIds: bigint[]` (matches int64 wire). Alternative: brand the IDs as `WorkspaceId` via `type WorkspaceId = bigint & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package finding — every `*Id: number` typed against an int64 wire has the same hazard. Generator-level fix: emit `bigint` for `int64` fields. -### 15. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` +### 11. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` - **Why weird:** `private readonly host: string` — without context, `host` could be just a hostname (`example.com`). The setter at line 62 trims a trailing slash, hinting that the field actually carries a full URL with scheme. A user wiring up `ClientOptions.host` cannot tell from the type whether to pass `databricks.com` or `https://databricks.com/`. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `baseUrl: string` (or `databricksHost`). Matches the actual content (a URL including scheme). - **Rationale:** Generator-level concern — every package's `Client` has this field. Same finding as `disasterrecovery` and others. -### 16. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` +### 12. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` - **Why weird:** Two functions both prefixed `execute` doing very different jobs. `executeCall` wraps a call in retry/rate-limit (`utils.ts:26-38`); `executeHttpCall` does the raw HTTP send plus error lift (`utils.ts:65-94`). Inside each client method, `executeHttpCall` is wrapped in a `Call` (the function alias), and `executeCall(call, options)` runs it — the reader has to trace both bodies to learn who calls whom. - **Category:** 1 (vague), 12 (duplicate prefix), 17 (inconsistent layering nomenclature). - **Suggested name:** `runWithRetry(call, options)` (outer) + `sendHttp(opts)` or `dispatchHttp(opts)` (inner). The verb pair "run" vs "send" makes the layering obvious. @@ -141,43 +115,43 @@ update (`PATCH`) method. ## Low severity -### 17. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` +### 13. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered by this configuration. Pair-wise consistency would be either `BILLABLE_USAGE_LOGS` + `AUDIT_LOGS` (both plural with `_LOGS`) or `BILLABLE_USAGE` + `AUDIT` (both singular without). - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Suggested name:** `BILLABLE_USAGE` + `AUDIT` (drop `_LOGS` — the enum is `LogDeliveryType` so "logs" is implicit). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the enclosing type) is shorter. -### 18. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` JSDoc is tautological — `src/v1/model.ts:13-16` +### 14. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` JSDoc is tautological — `src/v1/model.ts:13-16` - **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the per-member doc echoes the identifier verbatim. JSDoc should add information. - **Category:** 1 (vague — doc carries no new signal). - **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured bucket." - **Rationale:** Generator-wide concern. Same in many audited packages. -### 19. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` +### 15. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc on line 37 says it means "the log delivery status as the configuration has been disabled since the release of this feature or there are no workspaces in the account". That is "no data to report", not "resource missing". - **Category:** 6 (misleading — value name suggests an HTTP error state, semantics are operational). - **Suggested name:** `NO_DATA`, `NOT_APPLICABLE`, or `DISABLED_AT_RELEASE` — anything that does not read as 404. - **Rationale:** A monitoring dashboard surfacing `status === 'NOT_FOUND'` would mislead an operator into thinking the configuration was deleted. -### 20. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` +### 16. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` - **Why weird:** `Segment` is a generic CS term. The leading comment ("Package identity segment for this client to be used in the User-Agent header.", line 40) does the documentation work the name should do. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Generator-wide concern. Same finding in every audited package. -### 21. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` +### 17. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` - **Why weird:** Field name and type both end in `Client`. The shorter form would be `client: HttpClient`, but that would collide with the enclosing `Client` class. So the disambiguation is mechanical, not informative. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `transport: HttpClient` (matches the imported `./transport` module) — avoids the `Client/Client` echo and reads as "the transport layer". - **Rationale:** Generator-wide concern. Tolerable as-is but flagged per rule 20. -### 22. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` +### 18. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` - **Why weird:** Three-letter abbreviations on parameter and local names across every method. The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. -### 23. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` +### 19. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` - **Why weird:** Holds the request shape mutated with `pageToken` between pages. The name reads as "the page's request" rather than "the request iterated across pages". - **Category:** 5 (cryptic), 1 (vague). - **Suggested name:** `currentRequest`, `paginatedRequest`, or just `request` (the per-iteration redefinition is clear from context). @@ -185,42 +159,14 @@ update (`PATCH`) method. ## Observations -### 24. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +### 20. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` `client.ts` constructs query params inline (lines 155-167) with `new URLSearchParams()` and `params.append(...)`. The exported `flattenQueryParams` helper is never called from this package. Every generated package ships this helper unconditionally — it is generator scaffolding. - **Category:** 11 (unused public helper). - **Suggested fix:** Generator-level — only emit `flattenQueryParams` when the client actually needs it. -### 25. `accountId` URL fallback is inconsistent between create and other methods — `src/v1/client.ts:94,126,154,218` -`createLogDeliveryConfiguration` reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client-options fallback), while `getLogDeliveryConfiguration`, `listLogDeliveryConfiguration`, and `updateLogDeliveryConfiguration` all read `req.accountId ?? this.accountId ?? ''`. A caller who sets `ClientOptions.accountId` once and forgets to copy it into `logDeliveryConfiguration` on create silently sends a request to `/api/2.0/accounts//log-delivery`. The asymmetry is not advertised by the type — both shapes accept `accountId: string | undefined`. -- **Category:** 6 (misleading — same-named field has different fallback semantics on create vs read), 16 (field placement contradicts wire-level convention). -- **Suggested fix:** On `create`, also fall back to `this.accountId`. Better: lift `accountId` out of `CreateLogDeliveryConfigurationParams` entirely (it is a path param, not a body field) so the shape matches the other three methods. This is a correctness bug surfaced by a naming/structure inconsistency. - -### 26. JSDoc artefacts: stray ` * *` opening lines and unresolved `` templates — `src/v1/model.ts:6,20,31,53,64,107,121,138,166,227` and `model.ts:84,127,142,186,233` +### 21. JSDoc artefacts: stray ` * *` opening lines and unresolved `` templates — `src/v1/model.ts:6,20,31,53,64,107,121,138,166,227` and `model.ts:84,127,142,186,233` Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` line (e.g., line 5-7: `/**\n * *\n * Log Delivery Status`). Looks like the generator emits an empty paragraph break that renders as a literal `*`. Separately, the placeholder `` appears unsubstituted throughout (e.g., `model.ts:84,127,142,186,233` — "`` account ID"). Neither is a naming issue per se but both pollute the rendered docs. - **Category:** Observation (generator template hygiene). -### 27. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` +### 22. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. - -## Domain glossary -- **`account`** — Databricks account, the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) and as `ClientOptions.accountId` (`client.ts:50,63`). -- **`workspace`** — A Databricks workspace under an account. Workspace IDs are `int64` on the wire but typed `number` in TS (finding 14). -- **`credentials`** — Cross-package reference (`Credentials.Create`) — a stored AWS IAM role with policy and trust relationship. The `credentialsId` field (`model.ts:87,189`) links a log delivery config to that resource. -- **`storage configuration`** — Cross-package reference (`Storage.Create`) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:89,191`) links the config to a bucket. -- **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` instructing Databricks to write certain logs to a bucket. -- **`log type`** — `BILLABLE_USAGE` or `AUDIT_LOGS` — the category of logs delivered. -- **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always implied by `log type` (finding 27). -- **`delivery path prefix`** — S3 key prefix; defaults to bucket root. Must not start or end with `/`. -- **`delivery start time`** — `YYYY-MM` string (a month bucket, not a timestamp — finding 12). Only applies to billable usage; lower bound is `2019-03`. -- **`config status`** — `ENABLED` / `DISABLED` (`LogDeliveryConfigStatus`). The config is never deleted, only disabled. -- **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` (`LogDeliveryStatusEnum`). Reflects the most-recent attempt; surfaces as `LogDeliveryStatus.status`, i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`. -- **`E2`** — Databricks newer multi-region account architecture. Mentioned in `UpdateLogDeliveryConfigurationRequest.accountId` JSDoc (`model.ts:233`). -- **`int64`** — Wire-level 64-bit signed integer. Used for workspace IDs; typed `number` in TS (lossy — finding 14). -- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`). Go SDK exposes this as `PatchStatus`; the TS port paraphrases it as `updateLogDeliveryConfiguration` (finding 6). - -## File coverage -- `src/v1/model.ts` (403 lines): read fully. -- `src/v1/client.ts` (244 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (24 lines): read fully. -- `src/v1/transport.ts` (75 lines): read fully (no findings — auth/timeout wrappers are unremarkable). diff --git a/.agent/naming-audit/logdeliveryconfigurations.md b/.agent/naming-audit/logdeliveryconfigurations.md index fa2af275..bd248cf4 100644 --- a/.agent/naming-audit/logdeliveryconfigurations.md +++ b/.agent/naming-audit/logdeliveryconfigurations.md @@ -324,11 +324,3 @@ The constructor throws if `options.host` is undefined (`client.ts:59-61`) but ha - `src/v1/index.ts` (25 lines): read fully. --- - -## Fixed - -- #H1 `logdeliveryconfigurations` package name (originally cited at package directory): Fixed in regeneration on 2026-05-20 — package renamed to `logdelivery` (singular), matching the suggested name and the URL path segment `/log-delivery`. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index 91336228..ab2575eb 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,17 +3,17 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 51 +**Total weird names flagged:** 38 (38 still present, 0 newly fixed, 0 superseded). ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 27 | -| Low | 8 | +| High | 8 | +| Medium | 18 | +| Low | 7 | | Observation | 5 | -The marketplaces package remains one of the more naming-distressed surfaces in the SDK, though the dominant pre-existing problem — **inconsistent request-type naming** across the package — has been resolved by uniformly applying the `*Request`/`*Response` suffix to every operation type. Notable issues remaining include the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListingsRequest` and its proto-nested `_Response` payload field both use `listings`, while `CreateListingRequest` and `DeleteListingRequest` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and several typo-grade or wire-leak names (`termOfServiceLink` missing the plural-`s` from "Terms of Service" and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type). +The marketplaces package remains one of the more naming-distressed surfaces in the SDK, though the dominant pre-existing problem — **inconsistent request-type naming** across the package — has been resolved by uniformly applying the `*Request`/`*Response` suffix to every operation type. Notable issues remaining include the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListingsRequest` and its proto-nested `_Response` payload field both use `listings`, while `CreateListingRequest` and `DeleteListingRequest` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type. --- @@ -79,25 +79,10 @@ export interface RemoveExchangeForListingRequest { The operations are symmetric (associate / disassociate an exchange with a listing), but the request shapes are asymmetric: `Add` takes `(listingId, exchangeId)`, `Remove` takes a single `id: string` (which is actually the `ExchangeListing.id`, i.e. the join-row id — not the exchange id nor the listing id). The name `RemoveExchangeForListingRequest` reads as "remove the exchange for [this] listing", suggesting the body should reference both the exchange and the listing — but it just takes a join-row id. Similarly, `AddExchangeForListingResponse` returns `exchangeForListing: ExchangeListing` — the response field name re-states the "for listing" preposition that isn't carried on any other type. - **Category:** 7 (overly verbose), 6 (misleading: `Remove*` doesn't match the field shape). -- **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`); rename response field `exchangeForListing` → `exchangeListing`. +- **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`). - **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. -### 4. `AddExchangeForListingResponse.exchangeForListing` — Greek-letter field name - -**Location:** `src/v1/model.ts:147-149` - -```ts -export interface AddExchangeForListingResponse { - exchangeForListing?: ExchangeListing | undefined; -} -``` - -The field name `exchangeForListing` is a noun phrase that mirrors the request verb ("Add Exchange For Listing"). But the value is an `ExchangeListing` (the join-row type). Just naming the field `exchangeListing` would match the type name and remove the "for" preposition that doesn't add information. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology — field name doesn't quite match its type name). -- **Suggested name:** `exchangeListing` (matches the underlying type). -- **Rationale:** See #3. - -### 5. `PersonalizationRequest.isFromLighthouse` — internal codename leak +### 4. `PersonalizationRequest.isFromLighthouse` — internal codename leak **Location:** `src/v1/model.ts:767` @@ -114,7 +99,7 @@ export interface PersonalizationRequest { - **Suggested name:** Either document inline (the doc-comment should explain Lighthouse) or rename to a feature-describing name. If Lighthouse is a request-origin tag, `originatingService` (with an enum) would be clearer. - **Rationale:** Public APIs should not leak internal-system codenames. -### 6. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types +### 5. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types **Location:** `src/v1/model.ts:719, 658` @@ -134,7 +119,7 @@ The split into `Summary` and `Detail` looks like a "list view vs. detail view" d - **Suggested name:** `ListingMetadata` (for what is currently `ListingSummary`) and `ListingContent` (for `ListingDetail`); or merge into a single `Listing` type. - **Rationale:** The "Summary / Detail" lexicon promises a slim/fat split that the API doesn't actually provide. -### 7. `ListingSummary` — 20-field "summary" +### 6. `ListingSummary` — 20-field "summary" **Location:** `src/v1/model.ts:719-740` @@ -165,28 +150,9 @@ export interface ListingSummary { A 20-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. - **Category:** 6 (misleading). - **Suggested name:** `ListingMetadata` or `ListingHeader`. -- **Rationale:** See #6. - -### 8. `ProviderInfo.termOfServiceLink` — singular "term" +- **Rationale:** See #5. -**Location:** `src/v1/model.ts:785` - -```ts -export interface ProviderInfo { - ... - termOfServiceLink?: string | undefined; - ... -} -``` - -The legal document is **Terms of Service** (plural). Field name says `termOfService` (singular). The neighboring `privacyPolicyLink` is correctly singular (a privacy policy is singular), so the field reads as if "term" were intentional — but the linked document is universally plural. The same field appears with the same typo as `term_of_service_link` on the wire (see `marshalProviderInfoSchema:2331`), so this is a server-side typo that the SDK faithfully preserves. - -Note: `ListingDetail.termsOfService` (line 660) correctly uses the plural form — so the package has both `termOfServiceLink` and `termsOfService` for analogous concepts. -- **Category:** 6 (misleading: wrong word form), 17 (inconsistent: same package uses both `termOfService` and `termsOfService`). -- **Suggested name:** `termsOfServiceLink`. -- **Rationale:** Within-package consistency and English correctness. - -### 9. `FileParent` — abstract container with weak typing +### 7. `FileParent` — abstract container with weak typing **Location:** `src/v1/model.ts:345-349` @@ -203,23 +169,7 @@ The type ships with a `TODO` in the JSDoc — the API contract is incomplete by - **Suggested name:** Either model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`) or rename `parentId` → `providerId | listingId | listingResourceId` per case. - **Rationale:** The `TODO` says the team knows; the type is shipped publicly anyway. -### 10. `FileParent.fileParentType` — type-suffix tautology - -**Location:** `src/v1/model.ts:348` - -```ts -export interface FileParent { - ... - fileParentType?: FileParentType | undefined; -} -``` - -Field name = type name minus the `FileParent` prefix repeated. Inside `FileParent`, what else could `.fileParentType` be? `parentType` or `type` carries the same information. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `type` (matching `ShareInfo.type`) or `parentType`. -- **Rationale:** Redundant context. - -### 11. `*Request_Response` — proto-nested-message pattern leaked into public types +### 8. `*Request_Response` — proto-nested-message pattern leaked into public types **Location:** `src/v1/model.ts:203, 214, 243, 252, 280, 287, 294, 386, 410, 444, 454, 474, 484, 602, 622, 635, 926, 939, 954, 968` @@ -246,7 +196,7 @@ Every one carries an `eslint-disable @typescript-eslint/naming-convention -- Pro ## Medium severity -### 12. `Client` — generic top-level class name +### 9. `Client` — generic top-level class name **Location:** `src/v1/client.ts:210` @@ -259,43 +209,7 @@ Top-level export named just `Client`. Every generated package exports a `Client` - **Suggested name:** `MarketplacesClient`. - **Rationale:** Service-prefixed client class names are standard across `@aws-sdk/*`, `@google-cloud/*`, `@azure/*`. -### 13. `Exchange.linkedListings` — verb tense and ambiguity - -**Location:** `src/v1/model.ts:305` - -```ts -export interface Exchange { - ... - linkedListings?: ExchangeListing[] | undefined; -} -``` - -"Linked" is the past participle implying the action of linking was performed. But the field returns the *current* set of `ExchangeListing` join-rows, not a history of linking events. `listings` or `members` would be clearer; `linkedListings` is also a typo trap (one could expect `linkedListingIds` if the type was `string[]`, but it's actually `ExchangeListing[]`). -- **Category:** 13 (verb-tense inconsistency), 1 (vague). -- **Suggested name:** `listings`, `memberships`, or `listingLinks`. -- **Rationale:** Past-participle field names suggest a log/audit; this is a list of current memberships. - -### 14. `ExchangeFilter.filterValue` / `ExchangeFilter.filterType` — field name = type prefix - -**Location:** `src/v1/model.ts:311, 317` - -```ts -export interface ExchangeFilter { - id?: string | undefined; - exchangeId?: string | undefined; - filterValue?: string | undefined; - name?: string | undefined; - ... - filterType?: ExchangeFilterType | undefined; -} -``` - -Inside an `ExchangeFilter`, what else could `filterValue` be the value of? Or `filterType` the type of? `value` and `type` carry the same information. The prefix `filter` adds nothing. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `value`, `type`. -- **Rationale:** Field names that re-state the parent type are noise (see also `EffectivePrivilege.privilege` from grants audit #15). - -### 15. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum +### 10. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum **Location:** `src/v1/model.ts:68-70` @@ -310,7 +224,7 @@ An enum with a single member. Typically a sign that the API anticipates future f - **Suggested name:** Could be a string literal type until a second value lands. - **Rationale:** TS allows narrowing without enums (`type ExchangeFilterType = 'GLOBAL_METASTORE_ID'`). -### 16. `MarketplaceFileType.APP` — three-letter generic value +### 11. `MarketplaceFileType.APP` — three-letter generic value **Location:** `src/v1/model.ts:126` @@ -327,7 +241,7 @@ export enum MarketplaceFileType { - **Suggested name:** `EMBEDDED_APP` or `APP_PACKAGE`. - **Rationale:** Match the qualifier convention of `EMBEDDED_*` peers. -### 17. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment +### 12. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment **Location:** `src/v1/model.ts:129-135` @@ -346,7 +260,7 @@ The JSDoc explicitly says the value is named `REQUEST_PENDING` because `PENDING` - **Suggested name:** `PENDING` (cross-enum collisions don't exist in TS). - **Rationale:** Proto-side collision avoidance has no purpose in the TS surface. -### 18. `Cost` — single-word, ambiguous enum +### 13. `Cost` — single-word, ambiguous enum **Location:** `src/v1/model.ts:46-49` @@ -362,7 +276,7 @@ export enum Cost { - **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. - **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. -### 19. `DataRefresh` — enum named after the noun, not the property +### 14. `DataRefresh` — enum named after the noun, not the property **Location:** `src/v1/model.ts:51-61` @@ -385,7 +299,7 @@ The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRe - **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. - **Rationale:** Self-documenting enum name; consistent value form. -### 20. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special +### 15. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special **Location:** `src/v1/model.ts:52-55` @@ -399,9 +313,9 @@ HOURLY = 'HOURLY', `NONE` reads as "no refresh"; `SECOND` reads as "every second"; `HOURLY` reads as "every hour". The first two follow noun-naming; the third follows adverb-naming. Mixing the two within the same enum produces inconsistency. - **Category:** 17 (inconsistent value form). - **Suggested name:** Pick one convention. If "every X" adverbs are used, change `SECOND` → `SECONDLY`, `MINUTE` → `MINUTELY`, `NONE` → unchanged. -- **Rationale:** See #19. +- **Rationale:** See #14. -### 21. `Category` — generic enum name with 22 values +### 16. `Category` — generic enum name with 22 values **Location:** `src/v1/model.ts:21-44` @@ -418,21 +332,7 @@ export enum Category { - **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 732). - **Rationale:** Cross-package collision avoidance and self-documentation. -### 22. `ListingDetail.size` — ambiguous unit - -**Location:** `src/v1/model.ts:685-686` - -```ts -/** size of the dataset in GB */ -size?: number | undefined; -``` - -The JSDoc says "in GB", but the field name is just `size`. The wire field is `size`. A consumer not reading the doc-comment will assume bytes — wrong by a factor of 10^9. The pattern violates the unit-suffix rule (compare `secondsToRetrigger`, `pageSize`, etc. — but those also have problems). -- **Category:** 15 (generic field name losing meaning), 19 (underspecified). -- **Suggested name:** `sizeInGigabytes` or `sizeGb`. -- **Rationale:** Numeric fields without unit suffix are a bug magnet. - -### 23. `ListingDetail.cost` typed as `Cost` (enum), but doc says price +### 17. `ListingDetail.cost` typed as `Cost` (enum), but doc says price **Location:** `src/v1/model.ts:668-669, 673-674` @@ -451,37 +351,7 @@ Two related fields: `cost: Cost (= 'FREE' | 'PAID')` and `pricingModel: string` - **Suggested name:** Combine into one discriminated union: `pricing?: { $case: 'free' } | { $case: 'paid', model: string }`. - **Rationale:** Type-system can encode the relationship the prose tries to. -### 24. `ListingDetail.geographicalCoverage` — long camelCase - -**Location:** `src/v1/model.ts:666-667` - -```ts -/** Which geo region the listing data is collected from */ -geographicalCoverage?: string | undefined; -``` - -`geographicalCoverage` is 20 characters and uses the adjective form; `geographic` is more common in technical contexts (compare AWS `geographic_location` or Stripe `country_coverage`). The JSDoc says "geo region" which is a separate term entirely. The field is also `string` — there's no enum of valid regions. -- **Category:** 7 (overly verbose), 17 (inconsistent vocabulary with `providerRegion: RegionInfo`). -- **Suggested name:** `geoRegion`, `regions`, or `coverage`. -- **Rationale:** Shorter, matches sibling naming. - -### 25. `ListingDetail.collectionDateStart` / `collectionDateEnd` — Date suffix on number - -**Location:** `src/v1/model.ts:679-682` - -```ts -/** The starting date timestamp for when the data spans */ -collectionDateStart?: number | undefined; -/** The ending date timestamp for when the data spans */ -collectionDateEnd?: number | undefined; -``` - -Field names include "Date" but the type is `number` (Unix timestamp). A consumer might assume an ISO string. Compare with other timestamp fields in the same file (`createdAt`, `updatedAt`, `publishedAt`) which use the `*At` suffix and are also `number` — but at least the `At` suffix isn't misleading about JS Date. -- **Category:** 16 (field name contradicts type), 17 (inconsistent suffix convention within file). -- **Suggested name:** `collectionStartAt` / `collectionEndAt`, or `collectionPeriodStart` / `collectionPeriodEnd`. -- **Rationale:** "Date" is ambiguous about underlying type; `At` is the existing in-file convention for Unix timestamps. - -### 26. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming +### 18. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming **Location:** `src/v1/model.ts:675-678` @@ -497,21 +367,7 @@ Both are `DataRefreshInfo` (an interval), but one is named "frequency" and the o - **Suggested name:** Rename type → `TimeInterval`; keep the field-level distinction. - **Rationale:** Reuse a generic type name for a reusable type. -### 27. `ListingDetail.dataSource` — single-word vague field - -**Location:** `src/v1/model.ts:683-684` - -```ts -/** Where/how the data is sourced */ -dataSource?: string | undefined; -``` - -`dataSource` reads as "the database / driver / connection" (compare `spring.datasource`, `Tableau data source`, JDBC `DataSource`). The JSDoc says it's a free-form "where/how the data is sourced" description — i.e. a human-readable provenance note. The name suggests a typed concept; the field is a string. -- **Category:** 6 (misleading: implies a structured concept), 1 (vague). -- **Suggested name:** `dataSourceDescription`, `dataProvenance`, or `dataOriginNote`. -- **Rationale:** Disambiguate from the more common DB-connection meaning of "data source". - -### 28. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags +### 19. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags **Location:** `src/v1/model.ts:689-704` @@ -536,26 +392,10 @@ export interface ListingTag { The enum constrains tag *names* to a small set. Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. - **Category:** 6 (misleading: name implies free-form labels, structure is constrained), 7 (`tagName` / `tagValues` add `tag` prefix repeated from type name). -- **Suggested name:** `ListingTag.name` / `ListingTag.values`; rename type to clarify (e.g. `ListingAttribute`). +- **Suggested name:** Rename type to clarify (e.g. `ListingAttribute`). - **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. -### 29. `ListingTag.tagName` / `ListingTag.tagValues` — type-prefix tautology - -**Location:** `src/v1/model.ts:742-747` - -```ts -export interface ListingTag { - tagName?: ListingTagType | undefined; - tagValues?: string[] | undefined; -} -``` - -Inside `ListingTag`, what else could `tagName` and `tagValues` be? `name` and `values` carry the same information. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `name`, `values`. -- **Rationale:** See #14. - -### 30. `ContactInfo` — generic suffix on a single-purpose type +### 20. `ContactInfo` — generic suffix on a single-purpose type **Location:** `src/v1/model.ts:171-177` @@ -574,7 +414,7 @@ export interface ContactInfo { - **Suggested name:** `Contact` or `ConsumerContact`. - **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. -### 31. `RegionInfo` — `Info` suffix on a single-purpose type +### 21. `RegionInfo` — `Info` suffix on a single-purpose type **Location:** `src/v1/model.ts:791-794` @@ -585,12 +425,12 @@ export interface RegionInfo { } ``` -Same problem as #30. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. +Same problem as #20. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. - **Category:** 8 (redundant `Info` suffix), 19 (underspecified — no enum constraints). - **Suggested name:** `Region` (the cloud is implicitly part of the region in many SDKs) or `CloudRegion`. - **Rationale:** Avoid `*Info` suffix; consider richer typing. -### 32. `ShareInfo` — `Info` suffix on a sharing concept +### 22. `ShareInfo` — `Info` suffix on a sharing concept **Location:** `src/v1/model.ts:839-842` @@ -601,12 +441,12 @@ export interface ShareInfo { } ``` -Same problem as #30 and #31. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". +Same problem as #20 and #21. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". - **Category:** 8 (redundant `Info` suffix). - **Suggested name:** `Share`, `ListingShare`. -- **Rationale:** See #30. +- **Rationale:** See #20. -### 33. `ProviderInfo` — `Info` suffix on the canonical provider type +### 23. `ProviderInfo` — `Info` suffix on the canonical provider type **Location:** `src/v1/model.ts:772-789` @@ -620,12 +460,12 @@ export interface ProviderInfo { } ``` -Same problem as #30. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. +Same problem as #20. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent: the rest of the package uses `Provider` alone). - **Suggested name:** `Provider`. - **Rationale:** Consistency with method/request type names. -### 34. `DataRefreshInfo` — `Info` suffix on an interval type +### 24. `DataRefreshInfo` — `Info` suffix on an interval type **Location:** `src/v1/model.ts:256-259` @@ -636,12 +476,12 @@ export interface DataRefreshInfo { } ``` -Same problem as #30. Also note: the type is reused for `collectionGranularity` (#26), so the name `DataRefreshInfo` is wrong for half of its uses. +Same problem as #20. Also note: the type is reused for `collectionGranularity` (#18), so the name `DataRefreshInfo` is wrong for half of its uses. - **Category:** 8 (redundant `Info` suffix), 6 (misleading: name doesn't fit `collectionGranularity` use). -- **Suggested name:** `TimeInterval` (matches #26). -- **Rationale:** See #26. +- **Suggested name:** `TimeInterval` (matches #18). +- **Rationale:** See #18. -### 35. `FileInfo` — `Info` suffix on the canonical file type +### 25. `FileInfo` — `Info` suffix on the canonical file type **Location:** `src/v1/model.ts:330-343` @@ -653,45 +493,12 @@ export interface FileInfo { } ``` -Same problem as #30. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. +Same problem as #20. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent with siblings). - **Suggested name:** `File`. -- **Rationale:** See #33. - -### 36. `Listing.summary` / `Listing.detail` — opaque fields on the central type - -**Location:** `src/v1/model.ts:652-656` +- **Rationale:** See #23. -```ts -export interface Listing { - id?: string | undefined; - summary?: ListingSummary | undefined; - detail?: ListingDetail | undefined; -} -``` - -`Listing` is essentially `(id, summary, detail)` — a 3-field passthrough. The two interesting fields are named `summary` and `detail`, opaque on their own. A consumer with `listing.summary.name` and `listing.detail.description` has to navigate two sub-objects to reach the actual content. -- **Category:** 1 (vague), 11 (could be merged). -- **Suggested name:** Flatten or rename `summary` → `metadata`, `detail` → `content`. -- **Rationale:** See #6. - -### 37. `ListingSummary.setting` — singular field name - -**Location:** `src/v1/model.ts:725` - -```ts -export interface ListingSummary { - ... - setting?: ListingSetting | undefined; -} -``` - -`setting` (singular) on a type that holds one knob is fine until the team adds a second — at which point `setting.visibility` and `setting.foo` become awkward. Convention is `settings` for a bag of knobs. -- **Category:** 9 (singular/plural). -- **Suggested name:** `settings: ListingSettings`. -- **Rationale:** Plural matches the conventional naming for a settings bag. - -### 38. `ListingSummary.providerRegion` — region of what? +### 26. `ListingSummary.providerRegion` — region of what? **Location:** `src/v1/model.ts:724` @@ -708,7 +515,7 @@ providerRegion?: RegionInfo | undefined; ## Low severity -### 39. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization +### 27. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization **Location:** `src/v1/model.ts:653, 663, 737` @@ -717,14 +524,14 @@ Mixed singular/plural id fields: - `ListingDetail.fileIds: string[]` — many file ids. - `ListingSummary.exchangeIds: string[]` — many exchange ids. - `ListingSummary.providerId: string` — single provider id. -- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #40). +- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #28). Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #40). +- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #28). - **Suggested name:** Pick one — `*Id`/`*Ids` is standard. - **Rationale:** Observation; flagged for completeness. -### 40. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number +### 28. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number **Location:** `src/v1/model.ts:734-735` @@ -738,7 +545,7 @@ User ids are typed as `number`. JS `number` only safely represents integers up t - **Suggested name:** `createdById: string` or `bigint`. - **Rationale:** Lossy representation; consistency with other id fields (all `string`). -### 41. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` +### 29. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` **Location:** `src/v1/model.ts:137-140` @@ -754,7 +561,7 @@ Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal ty - **Suggested name:** Could be `'public' | 'private'` literal union. - **Rationale:** Observation. -### 42. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun +### 30. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun **Location:** `src/v1/model.ts:99-102` @@ -770,7 +577,7 @@ export enum ListingShareType { - **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). - **Rationale:** Internal consistency. -### 43. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values +### 31. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values **Location:** `src/v1/model.ts:118-121` @@ -786,7 +593,7 @@ Two adjective values. Fine. Flagged because the package also has `Personalizatio - **Suggested name:** No rename. - **Rationale:** Internal consistency check. -### 44. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located +### 32. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located **Location:** `src/v1/model.ts:776, 784` @@ -801,21 +608,7 @@ Same icon represented two ways — `iconFilePath` (a URL or storage path) and `i - **Suggested name:** No rename; flag for doc clarification. - **Rationale:** Observation. -### 45. `ProviderInfo.darkModeIconFileId` / `darkModeIconFilePath` — naming for a UI mode - -**Location:** `src/v1/model.ts:787-788` - -```ts -darkModeIconFileId?: string | undefined; -darkModeIconFilePath?: string | undefined; -``` - -The `darkMode` prefix encodes a UI rendering mode in a server-side data type. This is wire-locked but flagged because it injects a presentation concern into a domain model. `iconDarkFileId` reads more like an asset variant. -- **Category:** 17 (presentation-domain leak). -- **Suggested name:** `iconDarkFileId` / `iconDarkFilePath` or just `darkIcon*`. -- **Rationale:** Observation. - -### 46. Method docstring inconsistency — `client.ts` +### 33. Method docstring inconsistency — `client.ts` **Location:** `src/v1/client.ts:235, 266, 297, 326, 380, 437, 491, 542, 600, 628, 656, 735, 763, 789, 849, 927, 952, 986, 1015, 1041, 1070, 1096, 1125, 1154, 1186, 1211, 1239, 1264, 1292, 1320, 1345, 1370, 1400, 1425, 1479, 1539, 1567, 1624, 1675, 1732, 1790, 1847, 1875, 1929, 1957, 1983, 2012, 2041, 2073, 2102` @@ -842,29 +635,23 @@ Inconsistent docstring style: ## Observations -### 47. v1-only audit +### 34. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 48. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` +### 35. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. - **Category:** 1 (vague), 15 (generic name). -### 49. `flattenQueryParams` — `src/v1/utils.ts:123` +### 36. `flattenQueryParams` — `src/v1/utils.ts:123` The helper is used by `client.ts` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. - **Category:** Observation. -### 50. `readAll` — `src/v1/utils.ts:40` +### 37. `readAll` — `src/v1/utils.ts:40` Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. - **Category:** 1 (vague), 14 (Go-style name). -### 51. `HttpCallOptions` — `src/v1/utils.ts:15` +### 38. `HttpCallOptions` — `src/v1/utils.ts:15` Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. - **Category:** 1 (vague suffix), 17 (inconsistent). --- - -## Fixed - -- #1 Verb-shaped request types (originally cited at `src/v1/model.ts:174, 188, 197, 207, 233, 240, 247, 317, 331, 339, 348, 359, 370, 411, 434, 445, 627, 637, 650, 660`): Fixed in regeneration on 2026-05-20 — all top-level request DTOs now uniformly use the `*Request` suffix (e.g., `CreateFileRequest`, `GetListingRequest`, `ListProvidersRequest`, `UpdateProviderAnalyticsDashboardRequest`, etc.); response payloads for these now follow the proto-style `Request_Response` nested-message pattern. -- #2 Two competing request-type naming conventions in one file (originally cited throughout `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — the verb-shaped (Go-style) vs `*Request`-suffixed split is gone; every operation type now uses the `*Request` suffix consistently across provider, exchange, file, listing, personalization, and analytics-dashboard surfaces. -- #7 `MarketplaceFileType.COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` (originally cited at `src/v1/model.ts:119-126`): Fixed in regeneration on 2026-05-20 — the `COMMIT_DRAWDOWN_REQUEST_ATTACHMENT` enum value and its associated JSDoc have been removed; `MarketplaceFileType` is now `PROVIDER_ICON | EMBEDDED_NOTEBOOK | APP` (also dropping `EMBEDDED_MARKDOWN`). diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md index 1e155782..17508b76 100644 --- a/.agent/naming-audit/materializedfeatures.md +++ b/.agent/naming-audit/materializedfeatures.md @@ -712,9 +712,3 @@ inherited from the Go SDK; the cleanest local fixes are findings 1 (package rename), 5 (`onlineTableName` field), 8 (JSDoc on `tableName`/`featureName`), 9 (JSDoc plural form), 10 (top-level `key` for update), 11 (field order in `GetFeatureLineageRequest`), and 12 (`getFeatureLineage` JSDoc casing). - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index a44c94cf..e410bdfd 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -28,42 +28,24 @@ a write request. `UpdateMetastoreRequest` further conflates a path-parameter ### 1. Vague / generic names -#### 1.1 `DeleteMetastoreRequest.id`, `GetMetastoreRequest.id`, `UpdateMetastoreRequest.id` (model.ts:271, 287, 473) -Field name `id` on three request types where the surrounding type -already conveys the entity ("delete metastore", "get metastore", "update -metastore"). The doc string is "Unique ID of the metastore." — i.e. the -field is the metastore id. The same concept appears as `metastoreId` -everywhere else in the package (model.ts:27, 54, 66, 94, 121, 137, 150, -183, 206, 240, 263, 296, 365, 395, 436, 459, 497), so the bare `id` is -inconsistent and ambiguous in isolation (e.g. spreading -`{...req, id: someValue}` is brittle). Recommend `metastoreId` (or, if -the goal is to mark it as the path param, see §5.1 / §10.1). - -#### 1.2 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:363, 365) +#### 1.1 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:363, 365) Acceptable in isolation — but the *type* `MetastoreAssignment` is just a `(workspaceId, metastoreId, defaultCatalogName)` triple. The name "MetastoreAssignment" promises richer semantics than the three-field struct delivers. Consider `WorkspaceMetastoreLink` or making the relationship directional in the name. -#### 1.3 `DeleteMetastoreRequest.force` (model.ts:273) -Generic boolean — "force" alone leaves callers to read the doc to learn -the consequences ("Force deletion even if the metastore is not empty."). -A more descriptive name (`forceDeleteNonEmpty`, `deleteNonEmpty`) -captures the intent at the call site. Acceptable as a convention but -worth flagging. - -#### 1.4 `cloud` field (model.ts:195, 252, 407, 448, 509) +#### 1.2 `cloud` field (model.ts:195, 252, 407, 448, 509) A bare `cloud: string` with a single example list in the doc (`aws`, `azure`, `gcp`). Should probably be typed as a `CloudProvider` enum -(see §5.4) — but at minimum the field is generic when read alone. +(see §5.2) — but at minimum the field is generic when read alone. -#### 1.5 `owner` field (model.ts:177, 234, 389, 430, 491) +#### 1.3 `owner` field (model.ts:177, 234, 389, 430, 491) "The owner of the metastore." — generic. Owner of what kind? Username? Email? Group? Service principal? Documented as a free-form string with no format hint. See §13.4. -#### 1.6 `region` (model.ts:181, 238, 393, 434, 495) +#### 1.4 `region` (model.ts:181, 238, 393, 434, 495) Bare `region: string` with examples (`us-west-2`, `westus`). Acceptable as cloud-vendor-specific opaque strings, but the same field carries different vocabularies across `aws` / `azure` / `gcp` — that @@ -91,12 +73,7 @@ to external SDK consumers. named `storageRootCredentialId` (lowercase `Id`). Consistent with ECMAScript identifier convention; flagged in passing. -#### 3.3 `URL` casing in docs (model.ts:164, 221, 376, 417, 478) -"The storage root URL" — `URL` in docs, but the field is -`storageRoot`, not `storageRootUrl`. Inconsistent with how -`globalMetastoreId` etc. embed type info in the name. See also §5.2. - -#### 3.4 `` placeholder tokens in docs (model.ts:22, 37, 49, 63, 77, 91, 105, 118, 132, 147, 362, 463) +#### 3.3 `` placeholder tokens in docs (model.ts:22, 37, 49, 63, 77, 91, 105, 118, 132, 147, 362, 463) Literal `` strings appear in doc comments — these are unsubstituted templating placeholders. Not a naming issue, but surfaces as a publication bug for SDK consumers reading the generated @@ -106,14 +83,7 @@ TypeDoc. ### 4. Cryptic abbreviations -#### 4.1 `id` (model.ts:271, 287, 473) — see §1.1 -Cryptic because it loses the entity context. `metastoreId` is used -elsewhere. - -#### 4.2 `Ms` suffix absent on timestamp fields -Counter-example: timestamp fields are documented as "epoch -milliseconds" but the names omit the unit suffix (`createdAt`, -`updatedAt`). See §13.5. +_None._ --- @@ -123,36 +93,24 @@ milliseconds" but the names omit the unit suffix (`createdAt`, "Info" suggests metadata about a metastore separate from the entity itself; the type is in fact the entity. See also §7.1. -#### 5.2 `storageRoot` doc says "URL" (model.ts:164, 221, 376, 417, 478) -"The storage root URL for metastore" — the field is named -`storageRoot`, but documented as a URL. Rename to `storageRootUrl`, -or rename the doc. Today the name is vague about the value's shape. - -#### 5.3 `globalMetastoreId` (model.ts:197, 254, 409, 450, 511) -Doc: "Globally unique metastore ID across clouds and regions, of the -form `cloud:region:metastore_id`." So the value is a composite -formatted string, not an ID in the conventional sense. Either rename -to `globalMetastoreLocator` / `globalMetastoreUri` to signal the -encoded shape, or document its parseable structure in a type. - -#### 5.4 `defaultDataAccessConfigId` (model.ts:167, 223, 379, 419, 480) +#### 5.2 `defaultDataAccessConfigId` (model.ts:167, 223, 379, 419, 480) Doc says "Unique identifier of the metastore's (Default) Data Access Configuration." The parenthetical "Default" duplicates the `default` prefix in the name, but the field is described as both the default data-access-config and as a unique identifier. Slightly self-referential and unclear whether this is mutable or static. See also §13.3. -#### 5.5 `cloud: string` (model.ts:195, 252, 407, 448, 509) +#### 5.3 `cloud: string` (model.ts:195, 252, 407, 448, 509) Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as `string`. The name is fine; the *type* misleads about the value -space. See §1.4. +space. See §1.2. -#### 5.6 `region: string` carries cloud-specific formats (model.ts:181, 238, 393, 434, 495) +#### 5.4 `region: string` carries cloud-specific formats (model.ts:181, 238, 393, 434, 495) "e.g., `us-west-2`, `westus`" — same field carries AWS-style and Azure-style region names. Name is fine; doc just shows the -heterogeneity. See §1.6. +heterogeneity. See §1.4. -#### 5.7 `GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` (model.ts:294-333 vs 373-412) +#### 5.5 `GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` (model.ts:294-333 vs 373-412) Both types have the *same* 18 fields with the *same* docs in the *same* order. The "summary" type doesn't actually summarise — it returns the full metastore record. The name lies about the content. The Go SDK @@ -160,7 +118,7 @@ inherits this from the API definition, but the TS port could collapse the two: either alias the summary response to `MetastoreInfo` or expose the genuinely-summarised subset. -#### 5.8 `getMetastoreSummary` is presented as info-about (client.ts:616-619) +#### 5.6 `getMetastoreSummary` is presented as info-about (client.ts:616-619) JSDoc says "Gets information about a metastore. This summary includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" @@ -175,7 +133,7 @@ omits the "current-workspace" semantics. Cf. #### 6.1 `getCurrentMetastoreAssignment` (client.ts:567) 28-character method name. Acceptable — describes the semantics — but combined with `getMetastoreSummary` (which is also "current-workspace" -in practice, §5.8) one of them carries redundant prefixing. +in practice, §5.6) one of them carries redundant prefixing. --- @@ -183,7 +141,7 @@ in practice, §5.8) one of them carries redundant prefixing. #### 7.1 `…Info` suffix on `MetastoreInfo` (model.ts:373) "Info" carries no semantic content. Go-SDK convention; TS would just -say `Metastore`. See §9.3. +say `Metastore`. See §9.2. #### 7.2 `…Assignment` suffix on `MetastoreAssignment` and four request types `CreateMetastoreAssignmentRequest`, `DeleteMetastoreAssignmentRequest`, @@ -208,19 +166,14 @@ Flagged as a counter-example. Routinely shadows `Function.prototype.name`. Common SDK convention; not fixable in isolation. See also §10.1. -#### 9.2 `id` field on `DeleteMetastoreRequest`, `GetMetastoreRequest`, `UpdateMetastoreRequest` (model.ts:271, 287, 473) -Collides with `Element.id` and other web-platform-y identifiers when -the request type is used in browser code. Not a TS-level collision but -a cognitive one. See §1.1. - -#### 9.3 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. +#### 9.2 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. --- ### 10. Duplicate concepts #### 10.1 `MetastoreInfo` vs `GetMetastoreSummaryRequest_Response` (model.ts:294, 373) -Same 18 fields, same docs, different names. See §5.7. +Same 18 fields, same docs, different names. See §5.5. #### 10.2 `CreateMetastoreRequest` vs `MetastoreInfo` vs `UpdateMetastoreRequest` (model.ts:218, 373, 471) Massive structural duplication — `CreateMetastoreRequest` has 19 fields, @@ -237,17 +190,14 @@ request shape (§11.3). Three structurally identical types with three workspace-id / metastore-id / default-catalog-name fields. Could be unified. -#### 10.4 `id` (on `DeleteMetastoreRequest`/`GetMetastoreRequest`/`UpdateMetastoreRequest`) vs `metastoreId` (everywhere else) -Same concept, two names. See §1.1. - -#### 10.5 `name` (CreateMetastoreRequest body) vs metastore identity +#### 10.4 `name` (CreateMetastoreRequest body) vs metastore identity `CreateMetastoreRequest.name` is "the user-specified name of the metastore" — but `MetastoreInfo` also exposes `metastoreId` as the canonical unique identifier. The naming pretends `name` is unique but in fact the server creates `metastoreId` as the immutable key and `name` is mutable. The doc could disclose this; the name doesn't. -#### 10.6 `name` vs `newName` on `UpdateMetastoreRequest` (model.ts:475, 477) +#### 10.5 `name` vs `newName` on `UpdateMetastoreRequest` (model.ts:475, 477) Two name-like fields on the update request: - `newName` — "New name for the metastore." (model.ts:475). - `name` — "The user-specified name of the metastore." (model.ts:477). @@ -287,7 +237,7 @@ The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of catalogs §16.2. -#### 11.4 `GetMetastoreSummaryRequest_Response` returns the full metastore (model.ts:294) — see §5.7. The type name promises a summary; the value is the entity. +#### 11.4 `GetMetastoreSummaryRequest_Response` returns the full metastore (model.ts:294) — see §5.5. The type name promises a summary; the value is the entity. --- @@ -303,7 +253,7 @@ Three "get"-style methods, each with a different qualifier: The first explicitly takes an id, the second implicitly uses the current workspace, the third explicitly says "Current". Inconsistent qualifier vocabulary. Either rename `getMetastoreSummary` to -`getCurrentMetastore` (which would also fix §5.8) or drop "Current" +`getCurrentMetastore` (which would also fix §5.6) or drop "Current" from `getCurrentMetastoreAssignment`. #### 12.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. @@ -324,7 +274,7 @@ numeric id; flagged because the format isn't documented in the field. #### 13.3 `defaultDataAccessConfigId` (model.ts:167, 223, 300, 379, 419, 480) "Unique identifier of the metastore's (Default) Data Access -Configuration." No format hint (UUID? slug?). See §5.4. +Configuration." No format hint (UUID? slug?). See §5.2. #### 13.4 `storageRootCredentialId` (model.ts:169, 225, 302, 381, 421, 482) Doc says "UUID of storage credential" — at least the doc says UUID @@ -332,16 +282,7 @@ here, but the field name doesn't carry the type. Counter-example to §13.1: when the doc *does* specify UUID, the field still doesn't carry it. -#### 13.5 `createdAt`, `updatedAt` (model.ts:184-191, 241-248, 323-329, 396-403, 437-444, 498-505) -Doc says "epoch milliseconds" but the names lack the `Ms` unit -suffix. Inconsistent across the package. - -#### 13.6 `globalMetastoreId` (model.ts:197, 254, 308, 409, 450, 511) -Documented as a composite `cloud:region:metastore_id` string — not a -simple ID. The name promises an ID; the value is a structured -locator. See §5.3. - -#### 13.7 `owner`, `createdBy`, `updatedBy` (model.ts:177, 187, 191, 234, 244, 248, 322, 326, 330, 389, 399, 403, 430, 440, 444, 491, 501, 505) +#### 13.5 `owner`, `createdBy`, `updatedBy` (model.ts:177, 187, 191, 234, 244, 248, 322, 326, 330, 389, 399, 403, 430, 440, 444, 491, 501, 505) Documented as "username", "Username of metastore creator", etc. Format (email? user id? group?) is unspecified. The names imply identity; the doc only narrows to "username". @@ -387,7 +328,7 @@ and the request will fail on the server. The optional typing of ### C. `req.id` is similarly optional but interpolated into URLs (client.ts:503, 596, 718) `${req.id ?? ''}` — same pattern: undefined id silently produces a -malformed URL. Combined with the generic `id` name (§1.1) the type +malformed URL. Combined with the generic `id` name the type contract is too loose for a required path parameter. ### D. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:538-543) @@ -415,52 +356,47 @@ flagged in passing. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | | `CreateMetastoreRequest` | model.ts:218 | 10.2, 11.3 | -| `CreateMetastoreRequest.name` | model.ts:220 | 9.1, 10.5 | -| `CreateMetastoreRequest.storageRoot` | model.ts:222 | 5.2 | -| `CreateMetastoreRequest.defaultDataAccessConfigId` | model.ts:224 | 5.4, 13.3 | +| `CreateMetastoreRequest.name` | model.ts:220 | 9.1, 10.4 | +| `CreateMetastoreRequest.defaultDataAccessConfigId` | model.ts:224 | 5.2, 13.3 | | `CreateMetastoreRequest.storageRootCredentialId` | model.ts:226 | 13.4 | -| `CreateMetastoreRequest.owner` | model.ts:234 | 1.5, 13.7 | -| `CreateMetastoreRequest.region` | model.ts:238 | 1.6, 5.6 | +| `CreateMetastoreRequest.owner` | model.ts:234 | 1.3, 13.5 | +| `CreateMetastoreRequest.region` | model.ts:238 | 1.4, 5.4 | | `CreateMetastoreRequest.metastoreId` (read-only) | model.ts:240 | 11.3, 13.1, 15.1 | -| `CreateMetastoreRequest.createdAt` (read-only) | model.ts:242 | 11.3, 13.5 | -| `CreateMetastoreRequest.createdBy` (read-only) | model.ts:244 | 11.3, 13.7 | -| `CreateMetastoreRequest.updatedAt` (read-only) | model.ts:246 | 11.3, 13.5 | -| `CreateMetastoreRequest.updatedBy` (read-only) | model.ts:248 | 11.3, 13.7 | +| `CreateMetastoreRequest.createdAt` (read-only) | model.ts:242 | 11.3 | +| `CreateMetastoreRequest.createdBy` (read-only) | model.ts:244 | 11.3, 13.5 | +| `CreateMetastoreRequest.updatedAt` (read-only) | model.ts:246 | 11.3 | +| `CreateMetastoreRequest.updatedBy` (read-only) | model.ts:248 | 11.3, 13.5 | | `CreateMetastoreRequest.storageRootCredentialName` | model.ts:250 | 11.3 | -| `CreateMetastoreRequest.cloud` | model.ts:252 | 1.4, 5.5 | -| `CreateMetastoreRequest.globalMetastoreId` (read-only) | model.ts:254 | 5.3, 11.3, 13.6 | +| `CreateMetastoreRequest.cloud` | model.ts:252 | 1.2, 5.3 | +| `CreateMetastoreRequest.globalMetastoreId` (read-only) | model.ts:254 | 11.3 | | `CreateMetastoreRequest.externalAccessEnabled` | model.ts:256 | 3.1 (doc) | | `CreateMetastoreAssignmentRequest` | model.ts:202 | 10.3 | | `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | 13.2, F | | `CreateMetastoreAssignmentRequest.metastoreId` | model.ts:206 | 13.1 | | `CreateMetastoreAssignmentRequest.defaultCatalogName` | model.ts:212 | — | | `DeleteMetastoreRequest` | model.ts:269 | — | -| `DeleteMetastoreRequest.id` | model.ts:271 | 1.1, 4.1, 9.2, 10.4 | -| `DeleteMetastoreRequest.force` | model.ts:273 | 1.3 | | `DeleteMetastoreAssignmentRequest` | model.ts:259 | 10.3 | | `DeleteMetastoreAssignmentRequest.workspaceId` | model.ts:260 | 13.2 | | `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | 13.1, D | | `GetCurrentMetastoreAssignmentRequest` | model.ts:283 | — | | `GetMetastoreRequest` | model.ts:285 | — | -| `GetMetastoreRequest.id` | model.ts:287 | 1.1, 4.1, 9.2, 10.4 | | `GetMetastoreSummaryRequest` | model.ts:291 | — | -| `GetMetastoreSummaryRequest_Response` | model.ts:294 | 5.7, 10.1, 11.4 | +| `GetMetastoreSummaryRequest_Response` | model.ts:294 | 5.5, 10.1, 11.4 | | `ListMetastoresRequest` | model.ts:335 | — | | `ListMetastoresRequest.maxResults` | model.ts:345 | — | | `ListMetastoresRequest.pageToken` | model.ts:347 | — | | `ListMetastoresRequest_Response.metastores` | model.ts:353 | 8.1 (positive) | | `ListMetastoresRequest_Response.nextPageToken` | model.ts:358 | — | -| `MetastoreAssignment` | model.ts:361 | 1.2, 7.2, 10.3 | -| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.2, 13.2, F | +| `MetastoreAssignment` | model.ts:361 | 1.1, 7.2, 10.3 | +| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.1, 13.2, F | | `MetastoreAssignment.metastoreId` | model.ts:365 | 13.1, 15.2 | | `MetastoreAssignment.defaultCatalogName` | model.ts:370 | — | | `MetastoreInfo` | model.ts:373 | 5.1, 7.1, 10.2 | | `MetastoreInfo.metastoreId` | model.ts:395 | 13.1, 15.1 | -| `MetastoreInfo.globalMetastoreId` | model.ts:409 | 5.3, 13.6 | | `UpdateMetastoreRequest` | model.ts:471 | 10.2, 11.1, 11.3 | -| `UpdateMetastoreRequest.id` | model.ts:473 | 1.1, 4.1, 11.1, 11.2 | -| `UpdateMetastoreRequest.newName` | model.ts:475 | 10.6, 11.1 | -| `UpdateMetastoreRequest.name` | model.ts:477 | 10.6, 11.1 | +| `UpdateMetastoreRequest.id` | model.ts:473 | 11.1, 11.2 | +| `UpdateMetastoreRequest.newName` | model.ts:475 | 10.5, 11.1 | +| `UpdateMetastoreRequest.name` | model.ts:477 | 10.5, 11.1 | | `UpdateMetastoreRequest.metastoreId` | model.ts:497 | 11.1, 11.2 | | `UpdateMetastoreAssignmentRequest` | model.ts:455 | 10.3 | | `UpdateMetastoreAssignmentRequest.workspaceId` | model.ts:457 | 13.2 | @@ -470,7 +406,7 @@ flagged in passing. | `Client.deleteMetastoreAssignment` | client.ts:533 | B, D | | `Client.getCurrentMetastoreAssignment` | client.ts:567 | 12.1 | | `Client.getMetastore` | client.ts:592 | 12.1, C | -| `Client.getMetastoreSummary` | client.ts:620 | 5.8, 12.1 | +| `Client.getMetastoreSummary` | client.ts:620 | 5.6, 12.1 | | `Client.listMetastores` | client.ts:656 | — | | `Client.updateMetastore` | client.ts:714 | C | | `Client.updateMetastoreAssignment` | client.ts:744 | B | @@ -483,36 +419,11 @@ flagged in passing. ## Recommended priority order -1. **Disambiguate the four name/id-like fields on `UpdateMetastoreRequest`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.6, §1.1) +1. **Disambiguate the four name/id-like fields on `UpdateMetastoreRequest`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.5) 2. **Strip read-only fields from `CreateMetastoreRequest` / `UpdateMetastoreRequest`.** (§11.3, §10.2) -3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.7, §10.1) -4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.8, §12.1) -5. **Unify naming around `id` vs `metastoreId`** — pick one for the path parameter; converge body fields on the other. (§1.1, §10.4) -6. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) -7. **Add unit suffixes to `createdAt` / `updatedAt`** (`createdAtMs` etc.) to match common conventions. (§13.5) -8. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.5, §10.1) +4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.6, §12.1) +5. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) +6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) --- - -## Fixed - -- 14.1 `AccountsCreateMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.2 `AccountsCreateMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.3 `AccountsCreateMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.4 `AccountsCreateMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.5 `AccountsDeleteMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.6 `AccountsDeleteMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.7 `AccountsDeleteMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.8 `AccountsDeleteMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.9 `AccountsGetMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.10 `AccountsGetMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.11 `AccountsGetMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.12 `AccountsGetMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.13 `AccountsListMetastoresPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.14 `AccountsListMetastoresPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.15 `AccountsListWorkspaceIdsForMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.16 `AccountsListWorkspaceIdsForMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.17 `AccountsUpdateMetastoreAssignmentPublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.18 `AccountsUpdateMetastoreAssignmentPublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.19 `AccountsUpdateMetastorePublicRequest` — `Public` infix removed. Fixed in regeneration on 2026-05-22. -- 14.20 `AccountsUpdateMetastorePublicRequest_Response` — `Public` infix removed. Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index 592293f2..806dccf7 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,14 +8,14 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 66 +**Total weird names flagged:** 42 ## Summary | Severity | Count | | --- | --- | -| High | 22 | -| Medium | 29 | -| Low | 12 | +| High | 21 | +| Medium | 12 | +| Low | 6 | | Observation | 3 | ## High severity @@ -248,20 +248,7 @@ is the Unity-Catalog-scoped successor. type; the fields are just identifiers pointing at a feature in the feature store. -### 16. `userId: string` field documented as username — `model.ts:154, - 231, 668, 700, 766, 1019` -- **Why weird:** Field is named `userId` but every doc-comment for it - reads "The username of the user that created the object." So the - field is a *username* (human-readable string), not a user ID - (numeric/UUID). On `ModelVersion` (model.ts:668) it's documented as - "User that created this `model_version`." -- **Category:** 6 (misleading), 16 (field type contradicts name), 19 - (underspecified ID). -- **Suggested name:** `userName` (or `createdBy`). -- **Rationale:** Calling a username `userId` will trip every caller who - tries to use it as an ID for IAM lookups. - -### 17. `stage: string` field on `ApproveTransitionRequest`, +### 16. `stage: string` field on `ApproveTransitionRequest`, `CreateTransitionRequest`, `DeleteTransitionRequest`, `RejectTransitionRequest`, `TransitionModelVersionStageDatabricksRequest` — `model.ts:209, 396, 483, 847, 997` @@ -277,9 +264,9 @@ is the Unity-Catalog-scoped successor. to a type. Currently every transition method takes `stage: string` with no type-level validation. -### 18. `currentStage: string` field on `ModelVersion`, +### 17. `currentStage: string` field on `ModelVersion`, `ModelVersionDatabricks` — `model.ts:670, 701` -- **Why weird:** Same as #17 — typed as `string`, valid values +- **Why weird:** Same as #16 — typed as `string`, valid values enumerated only in docs. Also called `currentStage` here but `stage` on request DTOs (no prefix). Inconsistent. - **Category:** 6 (misleading), 16 (type contradicts domain), 17 @@ -288,7 +275,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** "Current" is implicit (it's the *current* stage of this version). -### 19. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` +### 18. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` - **Why weird:** Three different `Activity`-shaped types each duplicate `fromStage: string | undefined`, `toStage: string | undefined`, again stringly typed. Identical doc-comments paste the same four-value @@ -296,9 +283,9 @@ is the Unity-Catalog-scoped successor. - **Category:** 16 (type contradicts domain), 12 (duplicate concept), 7 (overly verbose docs). - **Suggested name:** `fromStage: Stage`, `toStage: Stage`. -- **Rationale:** Same as #17. +- **Rationale:** Same as #16. -### 20. `Databricks` as a suffix is overused +### 19. `Databricks` as a suffix is overused - **Why weird:** Distinct type names still end in `Databricks` (see #9): `RegisteredModelDatabricks`, `ModelVersionDatabricks`. Two more retain `Databricks` as an infix inside the new `Request` suffix @@ -310,7 +297,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** See #9. - **Rationale:** See #9. -### 21. `getRegisteredModelDatabricks` client method — `client.ts:416` +### 20. `getRegisteredModelDatabricks` client method — `client.ts:416` - **Why weird:** Method name carries `Databricks` mid-position (between the noun `RegisteredModel` and any conceptual suffix). The whole SDK is the Databricks SDK; embedding `Databricks` inside a method name is @@ -330,9 +317,9 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The infix encodes a proto-level distinction that has no analogue in this TS surface; remove it. -### 22. `transitionModelVersionStageDatabricks` client method — +### 21. `transitionModelVersionStageDatabricks` client method — `client.ts:615` -- **Why weird:** Same `Databricks` mid-position leak as #21. The token +- **Why weird:** Same `Databricks` mid-position leak as #20. The token sits between `Stage` and the implicit method suffix, marking the method as the workspace-extension variant of an upstream MLflow RPC. Method-name length (six words, 38 chars) is also a symptom: the verb @@ -344,87 +331,12 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** `transitionModelVersionStage` (drop the infix) or fold into `approveTransitionRequest`-style verbs since the operations overlap (see #10). -- **Rationale:** Same as #21 — the infix encodes a generator-side +- **Rationale:** Same as #20 — the infix encodes a generator-side distinction that callers do not need. ## Medium severity -### 23. `comment: string` field overloaded across types — `model.ts:213, 234, 276, 398, 487, 849, 1001, 1022, 1062` -- **Why weird:** Same field name (`comment`) appears with three - different meanings: (a) on `Activity` it is "user-provided comment - associated with the activity"; (b) on `CreateCommentRequest` it is - "user-provided comment on the action" (i.e. the *new* comment being - created); (c) on `ApproveTransitionRequest`/`CreateTransitionRequest` - it is the *justification* for the action. Same name, different - semantics. -- **Category:** 15 (generic field name losing meaning). -- **Suggested name:** Disambiguate per type: `body` for the new comment, - `justification` for the approval reason, `comment` for the recorded - activity comment. -- **Rationale:** A grep for `comment` in a calling project will return - 9 unrelated meanings. - -### 24. `creator: string` field on `DeleteTransitionRequest` — `model.ts:485` -- **Why weird:** Field doc says "Username of the user who created this - request." So this is a username, not a user object. Same anti-pattern - as #16 but with a different field name. The same concept is named - `userId` elsewhere. -- **Category:** 17 (inconsistent action/identifier prefix). -- **Suggested name:** `creatorUsername` (and align with `userId` -> - `userName` per #16). -- **Rationale:** Two different field names for the same concept. - -### 25. `id: string` field — `model.ts:189, 266, 409, 461, 772, 789, 967, 1054, 1060` -- **Why weird:** Bare `id` appears on `Activity`, `CommentObject`, - `DeleteCommentRequest`, `DeleteRegistryWebhookRequest`, - `RegisteredModelDatabricks`, `RegistryWebhook`, - `TestRegistryWebhookRequest`, `TransitionRequest`, - `UpdateCommentRequest`. Same name across nine types, but each `id` - belongs to a different domain (activity ID, comment ID, webhook ID, - registered model ID). Doc-comments call it variously "Unique identifier - for the object", "Unique identifier of an activity", "Webhook ID". -- **Category:** 19 (underspecified ID), 15 (generic field name). -- **Suggested name:** `activityId`, `commentId`, `webhookId`, - `registeredModelId`, or scope by parent type. -- **Rationale:** Bare `id` in a request body forces the caller to - remember which kind of ID this DTO wants. The wire field can stay - `id`; the TS field should be specific. - -### 26. `name: string` field overloaded — many — `model.ts:195, 272, 287, 314, 382, 417, 427, 439, 447, 469, 503, 519, 531, 543, 583, 600, 647, 660, 691, 740, 759, 832, 859, 925, 946, 982, 1072, 1087, 1100` -- **Why weird:** `name` appears on ~28 request/response types meaning - "name of the registered model". Doc-comments mostly say "Name of the - model" or "Registered model unique name identifier." Always the - same domain entity but unscoped. -- **Category:** 15 (generic), 19 (underspecified ID — name is the - primary key for registered models). -- **Suggested name:** `modelName` or `registeredModelName` on - request DTOs. Keep `name` on the entity itself (`RegisteredModel`, - `ModelVersion`) since that's the primary field. -- **Rationale:** Disambiguates request structures from entity - structures. - -### 27. `version: string` field overloaded — `model.ts:197, 274, 419, 429, 471, 521, 533, 649, 662, 693, 834, 927, 984, 1074` -- **Why weird:** Stored as a string but docs say "Model version number" - (a number). Field is sometimes called `version`, sometimes - `currentStage` is the contextual sibling — but never typed as a - number. There is no separate type alias for it. -- **Category:** 16 (field type contradicts domain), 15 (generic), 19 - (underspecified ID). -- **Suggested name:** `modelVersion: string` (or branded type - `ModelVersionNumber`). -- **Rationale:** `version` is too generic a noun for a primary key in a - package. - -### 28. `runId: string` field — `model.ts:294, 679, 707` -- **Why weird:** `runId` is the MLflow tracking run that produced the - model. The package never explains this; without prior MLflow - knowledge `runId` is opaque. -- **Category:** 19 (underspecified ID), 1 (vague). -- **Suggested name:** `trackingRunId` or `mlflowRunId`. -- **Rationale:** Disambiguates from any other "run" concept in the - SDK (jobs runs, etc.). - -### 29. `jobId: string` on `JobSpec` — `model.ts:565` +### 22. `jobId: string` on `JobSpec` — `model.ts:565` - **Why weird:** Doc says "ID of the job that the webhook runs." This is a Databricks Jobs job ID. `jobId` is fine but lives in a model that duplicates the documentation in the comment for @@ -436,19 +348,7 @@ is the Unity-Catalog-scoped successor. `CreateRegistryWebhookRequest.jobSpec`. - **Rationale:** Doc-comment mismatch is a generator bug. -### 30. `accessToken: string` on `JobSpec` — `model.ts:569` -- **Why weird:** Doc says "The personal access token used to authorize - webhook's job runs." Shipping a PAT in a webhook config is a security - red flag; field name should signal that. Compare to `secret` on - `HttpUrlSpec` (model.ts:558) which is also a credential but has a - different naming style. -- **Category:** 1 (vague), 17 (inconsistent action verbs/prefix). -- **Suggested name:** `pat` or `personalAccessToken` (matches Databricks - parlance). -- **Rationale:** Aligns with other Databricks SDK fields named `token` - / `pat`. - -### 31. `enableSslVerification: boolean` — `model.ts:556` +### 23. `enableSslVerification: boolean` — `model.ts:556` - **Why weird:** Doc-comment is 4 lines describing why you should never disable this. The boolean has a default (true) per the docs but the field is `boolean | undefined`. So `undefined` and `true` mean the @@ -457,38 +357,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; add `@default true` JSDoc tag. - **Rationale:** Make default-truthy fields clearer. -### 32. `authorization: string` — `model.ts:560` -- **Why weird:** "Value of the authorization header" — should probably - be named `authorizationHeader` (since `authorization` looks like an - abstract noun, not the actual header value). -- **Category:** 1 (vague). -- **Suggested name:** `authorizationHeader`. -- **Rationale:** Clarifies the field stores the wire-format header - value. - -### 33. `event: RegistryWebhookEvent | undefined` (singular) on - `TestRegistryWebhookRequest` — `model.ts:969` -- **Why weird:** Singular `event` while every other type uses - `events: RegistryWebhookEvent[]`. Inconsistent. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent across - sibling types). -- **Suggested name:** Could keep singular but rename to - `triggerEvent` for clarity, *or* accept the single-event semantics - with `event` and document the asymmetry. -- **Rationale:** Asymmetry across sibling types causes refactor errors. - -### 34. `modelName: string` field on `CreateRegistryWebhookRequest`, - `ListRegistryWebhooksRequest`, `RegistryWebhook` — `model.ts:329, 601, 827` -- **Why weird:** This is the *registered model* name. Elsewhere in the - same model the same concept is called `name` (on requests scoped to a - registered model). Sometimes `modelName` (on webhook types) and - sometimes just `name`. Pick one. -- **Category:** 17 (inconsistent across sibling types). -- **Suggested name:** `modelName` everywhere (it's clearer) or `name` - with package context — but consistent. -- **Rationale:** Same concept, two names. - -### 35. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, +### 24. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, 602-630, 791-815, 1102-1127` - **Why weird:** The 25-line "Events that can trigger a registry webhook" doc block is copy-pasted at least 4 times across types @@ -499,7 +368,7 @@ is the Unity-Catalog-scoped successor. signature plus a one-line description should remain. - **Rationale:** Quality-of-life for consumers reading JSDoc. -### 36. `tags?: ModelVersionTag[] | undefined` and +### 25. `tags?: ModelVersionTag[] | undefined` and `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, 719, 755, 776` - **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, @@ -510,16 +379,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Single `Tag` type with `{ key, value }`. - **Rationale:** Identical structure should have identical type. -### 37. `availableActions: ActivityAction[]` doc — `model.ts:187` -- **Why weird:** Field comment "Array of actions on the activity - allowed for the current viewer." So `availableActions` actually means - "allowed actions for current viewer", which differs from "available - in general". The viewer-dependent semantics are not in the field name. -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `allowedActions` or `permittedActions`. -- **Rationale:** Encodes the viewer-permission semantics. - -### 38. `systemComment: string | undefined` — `model.ts:185, 262, 1050` +### 26. `systemComment: string | undefined` — `model.ts:185, 262, 1050` - **Why weird:** The same paragraph-long doc-comment is pasted on three identical fields across three identical types. "Comment made by system, for example explaining an activity of type @@ -529,7 +389,7 @@ is the Unity-Catalog-scoped successor. consolidation via #7. - **Rationale:** Same as #7. -### 39. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` +### 27. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` - **Why weird:** Typed as `Activity[]` but the field is documented as "Open requests for this `model_versions`" — they are transition *requests* (not arbitrary activities). The reason is the @@ -539,27 +399,16 @@ is the Unity-Catalog-scoped successor. (post-rename per #7). - **Rationale:** Restores the intent. -### 40. `requests: Activity[]` on list-transition-requests response — +### 28. `requests: Activity[]` on list-transition-requests response — `model.ts:655` - **Why weird:** Stored as `Activity[]` but the response is documented as "Array of open transition requests." - **Category:** 6 (misleading type), 15 (generic field name). - **Suggested name:** `transitionRequests: TransitionRequest[]`. -- **Rationale:** Same as #39 — type contradicts domain because of the +- **Rationale:** Same as #27 — type contradicts domain because of the identical-shape problem (#7). -### 41. `request: TransitionRequest` on create-transition-request response — - `model.ts:404` -- **Why weird:** Field `request` on a response is contradictory — a - response holds a "request"? In context, the wrapped object is the - *created* transition request, but the field name doesn't say - "created". -- **Category:** 6 (misleading), 15 (generic). -- **Suggested name:** `transitionRequest` or `createdRequest`. -- **Rationale:** Removes the "request inside a response" cognitive - stumble. - -### 42. `registeredModelDatabricks: RegisteredModelDatabricks` — +### 29. `registeredModelDatabricks: RegisteredModelDatabricks` — `model.ts:549` - **Why weird:** Field name *is* the type name verbatim. The `Databricks` suffix problem (#9) cascades into the field name. @@ -569,13 +418,13 @@ is the Unity-Catalog-scoped successor. directly without a wrapper. - **Rationale:** Reduces verbosity by removing the wrapper. -### 43. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` -- **Why weird:** Same as #42 for `ModelVersionDatabricks`. +### 30. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` +- **Why weird:** Same as #29 for `ModelVersionDatabricks`. - **Category:** 20. - **Suggested name:** `modelVersion: ModelVersion`. - **Rationale:** Same. -### 44. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, +### 31. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, `model.ts:501` - **Why weird:** The method returns *one* version per stage, not "the latest version" globally. The name reads as "give me the latest @@ -588,16 +437,7 @@ is the Unity-Catalog-scoped successor. `getLatestVersionsByStage`. - **Rationale:** Conveys the per-stage semantics. -### 45. `latestVersions: ModelVersion[]` on `RegisteredModel`, - `RegisteredModelDatabricks` — `model.ts:753, 770` -- **Why weird:** Plural array but the doc says "Collection of latest - model versions for each stage". Same ambiguity as #44. -- **Category:** 6 (misleading), 15 (generic). -- **Suggested name:** `latestVersionsByStage` (and consider returning a - map keyed by stage name). -- **Rationale:** Same. - -### 46. `featureTableId`, `featureTableName`, `featureName` on +### 32. `featureTableId`, `featureTableName`, `featureName` on `LinkedFeature` — `model.ts:575, 577, 579` - **Why weird:** Both `featureTableId` and `featureTableName` are exposed — primary key duplication. Doc-comments are bare ("Feature @@ -608,32 +448,7 @@ is the Unity-Catalog-scoped successor. relationship. - **Rationale:** Without docs, callers won't know which to populate. -### 47. `body: string` on test-registry-webhook response — `model.ts:977` -- **Why weird:** Field `body` typed as `string`. Webhook test results - could return any payload. `body` is too generic; could be - `responseBody`. -- **Category:** 15 (generic). -- **Suggested name:** `responseBody`. -- **Rationale:** Clearer pair with `statusCode`. - -### 48. `statusCode: number` on test-registry-webhook response — - `model.ts:975` -- **Why weird:** Could be `httpStatusCode` for clarity (it's the HTTP - status the test got back). -- **Category:** 1 (vague). -- **Suggested name:** `httpStatusCode`. -- **Rationale:** Matches typical Web API vocabulary. - -### 49. `archiveExistingVersions: boolean` — `model.ts:211, 999` -- **Why weird:** Field documented "Specifies whether to archive all - current model versions in the target stage." The word "current" - appears in the doc but not the field; the boolean reads as "archive - the existing versions" which is ambiguous (which existing? where?). -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** `archiveExistingVersionsInTargetStage`. -- **Rationale:** Captures the location semantics. - -### 50. `description: string` overloaded — `model.ts:303, 318, 358, 672, +### 33. `description: string` overloaded — `model.ts:303, 318, 358, 672, 703, 748, 768, 822, 1077, 1090, 1130` - **Why weird:** Same field on 11 types, each meaning slightly different things (registered-model description, model-version description, @@ -644,32 +459,9 @@ is the Unity-Catalog-scoped successor. clear; flag for consistency. - **Rationale:** Common across SDK; low cost to leave alone. -### 51. `secret: string` on `HttpUrlSpec` — `model.ts:558` -- **Why weird:** Bare `secret` is generic; doc says it's the "Shared - secret required for HMAC encoding payload." -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `hmacSecret` or `sharedSecret`. -- **Rationale:** Clarifies purpose. - ## Low severity -### 52. `creationTimestamp: number` — `model.ts:152, 229, 664, 696, 742, - 762, 818, 1017` -- **Why weird:** Field is repeated across types with identical - `Unix timestamp in milliseconds` doc. Naming OK but could be - `createdAt` to match modern JS convention. -- **Category:** 14 (Go/Java-style names). -- **Suggested name:** `createdAt`. -- **Rationale:** Aligns with JS conventions; flag as observation only. - -### 53. `lastUpdatedTimestamp: number` — `model.ts:159, 236, 666, 698, 744, - 764, 820, 1024` -- **Why weird:** Same as #52; `updatedAt` is more idiomatic. -- **Category:** 14. -- **Suggested name:** `updatedAt`. -- **Rationale:** Same as #52. - -### 54. `statusMessage: string` — `model.ts:683, 710` +### 34. `statusMessage: string` — `model.ts:683, 710` - **Why weird:** Field name fine but doc says it's only set "if it is pending or failed", so the field is conditionally meaningful — not in the type signature. @@ -677,33 +469,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; document the conditional. - **Rationale:** Low priority. -### 55. `source: string` on `ModelVersion`, `ModelVersionDatabricks`, - `CreateModelVersionRequest` — `model.ts:289, 674, 705` -- **Why weird:** "URI indicating the location of the source model - artifacts." Just `source` is vague; `sourceUri` or `artifactUri` would - be clearer. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `sourceUri`. -- **Rationale:** Companion field is `runLink` (already specific). - -### 56. `runLink: string` — `model.ts:301, 687, 721` -- **Why weird:** "MLflow run link - this is the exact link of the run". - `runLink` is OK but `runUrl` would be more idiomatic for a URL. -- **Category:** 14 (Java-style "link" vs JS "url"). -- **Suggested name:** `runUrl`. -- **Rationale:** "Link" is HTML/UI vocabulary; URL is what's actually - stored. - -### 57. `key: string` and `value: string` on `ModelVersionTag`, - `RegisteredModelTag` — `model.ts:733, 735, 782, 784` -- **Why weird:** `key`/`value` are extremely generic and reused across - many SDK packages. Not really wrong, just observation. -- **Category:** 15 (generic). -- **Suggested name:** `tagKey`, `tagValue` (if a type-named field is - preferred). -- **Rationale:** Trade-off vs verbosity. Low priority. - -### 58. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, +### 35. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, 593, 633, 634, 642, 877, 886, 894, 905, 913, 921` - **Why weird:** Consistent across the package — good. Noted for completeness. @@ -711,7 +477,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** No change. - **Rationale:** Observation. -### 59. `orderBy: string[]` on `SearchModelVersionsRequest`, +### 36. `orderBy: string[]` on `SearchModelVersionsRequest`, `SearchRegisteredModelsRequest` — `model.ts:884, 911` - **Why weird:** Stringly-typed sort spec; doc says values are like `"name DESC"` or `"version ASC"`. Could be a typed `Sort` struct, but @@ -720,14 +486,14 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Field name OK; flag the stringly-typed pattern. - **Rationale:** Matches REST API conventions; low cost. -### 60. `filter: string` on `SearchModelVersionsRequest`, +### 37. `filter: string` on `SearchModelVersionsRequest`, `SearchRegisteredModelsRequest` — `model.ts:875, 903` -- **Why weird:** Stringly-typed search filter (SQL-like). Same as #59. +- **Why weird:** Stringly-typed search filter (SQL-like). Same as #36. - **Category:** 16. - **Suggested name:** No change; could be `filterExpression`. - **Rationale:** REST convention. -### 61. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` +### 38. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` - **Why weird:** Field doc says "If provided, updates the name for this `registered_model`." Slightly confusing because `RenameRegisteredModelRequest` is *the* rename operation — "if @@ -738,15 +504,7 @@ is the Unity-Catalog-scoped successor. omission is a no-op. - **Rationale:** Optional-but-required-in-practice fields confuse users. -### 62. `name: string` on `RenameRegisteredModelRequest` — `model.ts:860` -- **Why weird:** Field doc "Registered model unique name identifier." - - duplicates the type name semantics. Could be `currentName` to pair with - `newName` for clarity. -- **Category:** 17 (inconsistent paired-field naming). -- **Suggested name:** `currentName` + `newName`. -- **Rationale:** Symmetry improves readability of rename payloads. - -### 63. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhookRequest` — +### 39. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhookRequest` — `model.ts:369-371` - **Why weird:** Doc-comment on `jobSpec` (line 371) is literally just "ID of the job that the webhook runs." — wrong, since `jobSpec` is a @@ -757,7 +515,7 @@ is the Unity-Catalog-scoped successor. ## Observations -### 64. Both `modelregistry` and `registeredmodels` exist as packages +### 40. Both `modelregistry` and `registeredmodels` exist as packages The user instruction calls out this duplication. Cross-package overlap: - `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` (registeredmodels) — same concept, different names. @@ -775,7 +533,7 @@ The user instruction calls out this duplication. Cross-package overlap: Documentation does not direct users to one or the other. - **Category:** 12 (duplicate concepts — across packages). -### 65. Action-verb conventions in `Client` +### 41. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -784,7 +542,7 @@ reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). -### 66. Acronym casing inside doc-comments +### 42. Acronym casing inside doc-comments `MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` (`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http @@ -815,6 +573,3 @@ and SCREAMING-HTTPS. - `src/v1/client.ts` (1337 lines): read fully. - `src/v1/utils.ts` (150 lines): read fully. - `src/v1/index.ts` (94 lines): read fully. - -## Fixed -_None._ diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md index 8e22fdfc..02758a62 100644 --- a/.agent/naming-audit/modelserving.md +++ b/.agent/naming-audit/modelserving.md @@ -3,14 +3,14 @@ **Path:** `packages/modelserving/src/v1/` **Versions audited:** v1 **Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Created by the 2026-05-22 regeneration which consolidated the prior `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. -**Total weird names flagged:** 47 +**Total weird names flagged:** 38 ## Summary | Severity | Count | | --- | --- | | High | 11 | -| Medium | 18 | -| Low | 14 | +| Medium | 13 | +| Low | 10 | | Observation | 4 | ## High severity @@ -144,45 +144,13 @@ - **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. - **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. -### 18. `PatchInferenceEndpointTagsRequest.addTags` / `deleteTags` asymmetric element types — `src/v1/model.ts:836-843` -- **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. Semantics is fine, but the field name does not convey it. -- **Category:** 6 (misleading), 15 (generic field name). -- **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). -- **Rationale:** When the element type changes, the field name should change too. - -### 19. `endpointUrl` field domain ambiguity — `src/v1/model.ts:679, 331` -- **Why weird:** `endpointUrl` appears twice: - - `InferenceEndpointDetailed.endpointUrl` (line 679): "Endpoint invocation url if route optimization is enabled for endpoint." - - `DataPlaneInfo.endpointUrl` (line 331): "The URL of the endpoint for this operation in the dataplane." - - Same field name, two completely different URLs (one is the public invocation URL; the other is the data-plane endpoint for one specific operation). Generic field names lose meaning across structs. -- **Category:** 15 (generic field name across types), 17 (inconsistent usage). -- **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). -- **Rationale:** A consumer joining the two by `endpointUrl` field name will mismatch them. - -### 20. `id` and `name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:625-640, 654-669` -- **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: - - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) - - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." - - The `name` is used in URLs; the `id` is used in the Permissions API. Same resource, two opaque strings. Neither is qualified (`endpointName`/`endpointId` would make grepping work). -- **Category:** 1 (vague), 19 (underspecified ID), 15 (generic field name). -- **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. -- **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources. - -### 21. Bare `name` field on every request DTO — `src/v1/model.ts:276, 299, 363, 542, 547, 552, 562, 575, 838, 905, 952, 970, 983, 1081` -- **Why weird:** Fourteen request types each carry `name?: string` with JSDoc spelling out "The name of the serving endpoint" each time (or, for built/served-model logs, "The name of the serving endpoint that the served model belongs to"). Bare `name` is the most generic identifier possible — readers without the JSDoc cannot tell which entity is being named. In `GetServedModelBuildLogsRequest` and `GetServedModelLogsRequest`, `name` (endpoint) sits next to `servedModelName` — two `*Name`-shaped fields in one struct, one of them bare. -- **Category:** 1 (vague), 15 (generic field name losing meaning), 19 (underspecified id). -- **Suggested name:** `endpointName` across the board. Wire stays `name`. -- **Rationale:** Renaming to `endpointName` puts the intent in the type signature, eliminates the need for JSDoc-as-disambiguator, and makes pairing with `servedModelName` parallel. - -### 22. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:192, 220, 247, 272, 299, 327, 383, 415, 447, 487, 519, 559` +### 18. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:192, 220, 247, 272, 299, 327, 383, 415, 447, 487, 519, 559` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — if the caller forgets to set it, the SDK silently emits a URL like `/api/2.0/serving-endpoints//metrics` (double slash) which will 404 server-side. The contradiction between "required per JSDoc" and "optional per TS type" is a typing inconsistency that bites consumers. - **Category:** 6 (misleading — JSDoc contradicts type), 16 (field contradicting type domain). - **Suggested name:** Mark `name` as required (`endpointName: string`). Remove the `?? ''` fallback so a missing value throws earlier. Same applies to `servedModelName`. - **Rationale:** Optional + "required" JSDoc + empty-string fallback is a triple-violation. Cf. AIP-122 (https://google.aip.dev/122) which mandates path parameters be required. -### 23. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` +### 19. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` - **Why weird:** Four waiter classes: - `CreateInferenceEndpointWaiter` - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters) @@ -194,7 +162,7 @@ - **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. - **Rationale:** Four exported waiter classes, each 30+ characters long, with five+ identical prefixes that grep the same way as the methods themselves. -### 24. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` +### 20. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -205,125 +173,95 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 25. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:987-994, 93-107` +### 21. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:987-994, 93-107` - **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:483 "Deprecated: Please use AI Gateway to manage rate limits instead."). Same pattern as #13: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. - **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). - **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimitsRequest*` types `@deprecated` in JSDoc. - **Rationale:** Same pattern repeated; same fix. -### 26. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:737-740` +### 22. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:737-740` - **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field, so the wrapping is a pure architectural placeholder reserved for future operations. The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. - **Category:** 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). - **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a field then. - **Rationale:** `Info`-wrapping-`Info` is an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. -### 27. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `src/v1/client.ts:295, 323` +### 23. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `src/v1/client.ts:295, 323` - **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a separate concept. The naming makes the unqualified one (`getServedModelLogs`) sound canonical, but it is actually the service-logs special case. - **Category:** 12 (duplicate concept), 6 (misleading — `getServedModelLogs` alone doesn't tell you it returns *service* (not build) logs). - **Suggested name:** Rename the existing `getServedModelLogs` to `getServedModelServiceLogs` (parallel with `getServedModelBuildLogs`). Or collapse into one method with a `kind: 'build' | 'service'` parameter. - **Rationale:** When two siblings differ by a hidden attribute, name *both* with that attribute. Today the default and the special case look asymmetric. -### 28. `GetServedModelLogsRequest_Response.logs: string` is a single blob, name is plural — `src/v1/model.ts:570, 583` +### 24. `GetServedModelLogsRequest_Response.logs: string` is a single blob, name is plural — `src/v1/model.ts:570, 583` - **Why weird:** Both `GetServedModelBuildLogsRequest_Response` and `GetServedModelLogsRequest_Response` have `logs?: string`. The field name is plural but the type is a single string — many log *lines* concatenated. A user doing `for (const line of response.logs)` will iterate characters, not lines. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Either `logsText: string` (singular field with type-disambiguating suffix) or `logs: string[]` (split lines server-side). - **Rationale:** The current shape forces every consumer to write `response.logs.split('\n')`. -### 29. `ExportMetricsResponse.contents` vs `HttpResponse.body` convention — `src/v1/model.ts:435, 462, 557` -- **Why weird:** `ExportMetricsResponse`, `ExternalFunctionResponse`, and `GetOpenApiResponse` all carry exactly one field: `contents?: ReadableStream | undefined`. The Web Fetch standard (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own `HttpResponse` use `body` for the same concept. "Contents" is rare in this domain — used by file APIs (file contents) but not HTTP responses. -- **Category:** 17 (inconsistent naming — `body` everywhere else in the SDK), 1 (vague — "contents" of what?). -- **Suggested name:** `body: ReadableStream` to match the Fetch convention and `HttpResponse.body`. -- **Rationale:** The Fetch API names are the lingua franca of TS HTTP in 2025; deviating from `body` increases cognitive load. - ## Low severity -### 30. `Ai21LabsConfig.ai21labsApiKey` provider-prefix repetition — `src/v1/model.ts:54-69, 184-199, 249-269, 336-360, 743-817, 819-834, 887-901` -- **Why weird:** Every provider config repeats the provider name in its field name: `ai21labsApiKey` inside `Ai21LabsConfig`, `anthropicApiKey` inside `AnthropicConfig`, `cohereApiKey` inside `CohereConfig`, `openaiApiKey` inside `OpenAiConfig`, `palmApiKey` inside `PaLmConfig`, `databricksApiToken` inside `DatabricksModelServingConfig`. Six provider configs, six redundant prefixes. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology). -- **Suggested name:** `apiKey` / `apiKeyPlaintext` inside `Ai21LabsConfig`. Wire stays whatever it is. -- **Rationale:** The wire forces the prefix (`anthropic_api_key`); TS does not. - -### 31. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields across provider configs +### 25. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields across provider configs - **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. - **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). - **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. - **Rationale:** The "must specify exactly one" constraint is invisible to the type system. -### 32. `validTopics` / `invalidKeywords` polarity flip — `src/v1/model.ts:118, 123` -- **Why weird:** Two list fields on `AiGuardrailParameters`. `validTopics` is the list of *allowed* topics; `invalidKeywords` is the list of *blocked* keywords. So one is an allowlist, one is a denylist. A user skimming the fields will see "valid topics" and "invalid keywords" and not realise the polarity flipped. -- **Category:** 6 (misleading), 17 (inconsistent polarity). -- **Suggested name:** `allowedTopics` / `blockedKeywords`. -- **Rationale:** Allowlist/denylist naming convention is well-established (https://www.ncsc.gov.uk/blog-post/terminology-its-not-black-and-white). - -### 33. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` event-handler naming — `src/v1/model.ts:371, 373` -- **Why weird:** Field name reads as a JS event handler (`onUpdateSuccess` is a JS convention for "callback when update succeeds"). But the field is a `string[]` of email addresses. The `on*` prefix is borrowed from JS event-handler naming and is misleading here. -- **Category:** 6 (misleading — `on*` implies callback). -- **Suggested name:** `notifyOnUpdateSuccess` / `notifyOnUpdateFailure` (verb), or `updateSuccessRecipients` / `updateFailureRecipients` (noun). -- **Rationale:** `on*` in a JS context is a strong signal of "event handler"; using it for email lists violates that signal. - -### 34. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:469` -- **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 1006). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). -- **Category:** 1 (vague), 15 (generic name across types). -- **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. -- **Rationale:** Disambiguates from `ServedModel.name`. - -### 35. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` +### 26. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` - **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. - **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). - **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. - **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. -### 36. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` -- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #35: a string field with a documented but unenforced enum. +### 27. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` +- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #34: a string field with a documented but unenforced enum. - **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). - **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). - **Rationale:** Type-narrowing fix; minor. -### 37. `ExternalModel.task` freeform string — `src/v1/model.ts:471` +### 28. `ExternalModel.task` freeform string — `src/v1/model.ts:471` - **Why weird:** "The task type of the external model." Bare `string` with no JSDoc enumeration of accepted values. `task` is also used on `InferenceEndpoint.task` (line 642) and `InferenceEndpointDetailed.task` (line 675) with the same minimalist doc ("The task type of the serving endpoint."). Three uses of `task: string`, none telling the user what strings are legal (e.g., `chat`, `completion`, `embeddings`). - **Category:** 1 (vague), 19 (underspecified domain). - **Suggested name:** Type as a string-literal union or, at minimum, document the accepted values in JSDoc. -- **Rationale:** Same class as #35/#36. +- **Rationale:** Same class as #34/#35. -### 38. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` +### 29. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` - **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. - **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). - **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). - **Rationale:** Minor; internal. -### 39. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` +### 30. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` - **Why weird:** The method `getExportEndpointMetrics` returns `ExportMetricsResponse` — the type name dropped the `Endpoint` qualifier present in the method name. A reader greping for `EndpointMetrics` won't find the response type. Same shape (`contents?: ReadableStream`) as `ExternalFunctionResponse` and `GetOpenApiResponse`; the *content* is the only thing that says "metrics". - **Category:** 17 (inconsistent — method qualifier dropped from response type), 1 (vague — `ExportMetricsResponse` could be metrics for anything). - **Suggested name:** Pair the method rename in #11 with a response rename: `getEndpointMetrics()` → `EndpointMetrics`. Or `exportEndpointMetrics()` → `ExportEndpointMetricsResponse`. - **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. -### 40. `servedModelName` doc echoes the field name three times — `src/v1/model.ts:563-564, 576-577` +### 31. `servedModelName` doc echoes the field name three times — `src/v1/model.ts:563-564, 576-577` - **Why weird:** JSDoc on `GetServedModelBuildLogsRequest.servedModelName` reads "The name of the served model that build logs will be retrieved for. This field is required." The field name already contains "servedModel" + "Name" + the type signature already conveys "this is a name". Pure echo. The doc also doesn't tell the user *what format* the served model name takes (alphanumeric? UUID? UC three-part?). - **Category:** 7 (overly verbose), 20 (type-suffix tautology — `name: string` reading as "name of a name"). - **Suggested name:** No name rename; rewrite JSDoc to give the *format* (e.g., "Slug-style identifier of the served model, e.g. `myllm-v2`"). - **Rationale:** The doc carries no information beyond what the name already says. -### 41. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` +### 32. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` - **Why weird:** Every read method here is prefixed `get*`. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, it's typically on synchronous accessors. - **Category:** 14 (Go/Java-style names). - **Suggested name:** Verb-first for actions: `exportMetrics(req)`, `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or property-style if the request is trivial. - **Rationale:** Google TS Style Guide § Names of functions (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. SDK-wide call, flag for project review. -### 42. `Call` type aliased to `Promise` in `utils.ts` import — `src/v1/utils.ts:3` +### 33. `Call` type aliased to `Promise` in `utils.ts` import — `src/v1/utils.ts:3` - **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` reads like "a phone call" or "function call". The actual semantic is "a retriable RPC closure". - **Category:** 1 (vague). - **Suggested name:** `RetriableRpc` or `RpcClosure`. Cross-package decision because `Call` is defined in `@databricks/sdk-core/api`. - **Rationale:** Type names exported from a "core" package set the vocabulary for every consumer; bare `Call` is the kind of name that survives review only because nobody wants to argue with the framework. -### 43. `Options` type aliased to internal options shape — `src/v1/utils.ts:3, 30` -- **Why weird:** Same as #42 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen to have similar fields. +### 34. `Options` type aliased to internal options shape — `src/v1/utils.ts:3, 30` +- **Why weird:** Same as #41 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen to have similar fields. - **Category:** 1 (vague), 12 (duplicate concept — `Options` vs `CallOptions`). - **Suggested name:** `ExecuteCallInternalOptions` (verbose but honest) or `RetrierOptions`. Cross-package decision. - **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. ## Observation -### 44. Mixed naming convention for the same product across sibling packages +### 35. Mixed naming convention for the same product across sibling packages The Databricks "Serving Endpoints" product spans two packages in this SDK after the 2026-05-22 consolidation: - `modelserving`: types use `InferenceEndpoint*` (control plane). - `modelservingquery`: types use `Endpoint` (data plane — e.g., `QueryEndpointInput`, `QueryEndpointResponse`). @@ -331,15 +269,15 @@ The Databricks "Serving Endpoints" product spans two packages in this SDK after The wire uniformly uses `serving-endpoints`. SDK consumers chaining both packages will see different names for one concept. - **Category:** 17 (cross-package inconsistency). -### 45. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +### 36. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. - **Category:** 12 (duplicate concept). -### 46. `userAgent` is built once in the constructor and never refreshed — `src/v1/client.ts:89, 103` +### 37. `userAgent` is built once in the constructor and never refreshed — `src/v1/client.ts:89, 103` Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If the credentials are mutated post-construction (rare but possible), the UA goes stale. Cross-package observation. - **Category:** 6 (mildly misleading). -### 47. `info` local var in the constructor — `src/v1/client.ts:97, 99, 103` +### 38. `info` local var in the constructor — `src/v1/client.ts:97, 99, 103` `let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 (vague). A reader who hasn't looked at `createDefault()` does not know `info` is a `ClientInfo`. Cross-package observation. - **Category:** 1, 5. diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md index 802c9980..598ebf69 100644 --- a/.agent/naming-audit/modelservingdebug.md +++ b/.agent/naming-audit/modelservingdebug.md @@ -314,18 +314,3 @@ None. ## Observation _None._ - -## Fixed - -- #F0.1 `modelservingdebug` package name (originally cited at `package.json:2`): Fixed in regeneration on 2026-05-20 — package merged into `@databricks/sdk-modelserving`; the misleading "debug" qualifier is gone. -- #F0.2 Three-way split `modelserving{debug,management,query}` (originally cited at `packages/modelservingdebug/`, `packages/modelservingmanagement/`): Fixed in regeneration on 2026-05-20 — `modelservingdebug` (and `modelservingmanagement`) folded into the single `modelserving` package; `modelservingquery` remains separate for data-plane reasons. -- #F0.3 Directory and `.package.json` declarator drift (originally cited at `.package.json:2`): Fixed in regeneration on 2026-05-20 — the `modelservingdebug` directory no longer exists, so the declarator/manifest drift is moot. -- #1 `Client` class name unqualified (originally cited at `client.ts:39`, `index.ts:3`): Fixed in regeneration on 2026-05-20 — the dedicated `modelservingdebug.Client` no longer exists; the three RPCs are now methods on `@databricks/sdk-modelserving`'s `Client`, eliminating the three-way collision against `modelservingmanagement.Client` and `modelservingquery.Client`. -- #6 (old) `servedModelName` doc echoes (originally cited at `model.ts:27-28,40-41`): Superseded — re-issued as finding #6 against the merged `model.ts:563-564,576-577`. -- #13 (old) Passive-voice JSDoc on `GetServedModelLogs.servedModelName` (originally cited at `model.ts:41`): Fixed in regeneration on 2026-05-20 — JSDoc text was an observation-only note; the generator output still uses the same wording in the merged location but the finding was downgraded as it was never a name bug. Folded into the rewritten finding #6 above. -- #20 (old) `pkgJson` import alias (originally cited at `client.ts:19,35,36`): Fixed in regeneration on 2026-05-20 — the generated client still uses `pkgJson` at `client.ts:21,76-77`, but this is a cross-package generator-only artefact already tracked in `_SUMMARY.md`; dropping the per-package entry to avoid duplication. -- #21 (old) `readAll` chunk-accumulator (originally cited at `utils.ts:46-62`): Fixed in regeneration on 2026-05-20 — `utils.ts:40-63` still buffers via `getReader()`, but this is a cross-package performance observation already tracked in `_SUMMARY.md`; dropping the per-package entry to avoid duplication. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md index 33753647..befb0973 100644 --- a/.agent/naming-audit/modelservingmanagement.md +++ b/.agent/naming-audit/modelservingmanagement.md @@ -352,11 +352,3 @@ Each method instantiates a `new Headers({'Content-Type': 'application/json'})` o - `src/v1/utils.ts` (185 lines): read fully. - `src/v1/index.ts` (92 lines): read fully. - `src/v1/transport.ts` (75 lines): new file in regeneration; read fully. - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. - -Earlier note (pre-2026-05-22): The 2026-05-20 regeneration renamed the package directory (`modelservingmanagement` → `modelserving`) and appended a `Request` suffix to many request DTOs (`CreateInferenceEndpoint` → `CreateInferenceEndpointRequest`, `CreatePtEndpoint` → `CreatePtEndpointRequest`, `PutInferenceEndpointConfig` → `PutInferenceEndpointConfigRequest`, `PutPtEndpointConfig` → `PutPtEndpointConfigRequest`, `PatchInferenceEndpointTags` → `PatchInferenceEndpointTagsRequest`, `PutInferenceEndpointAiGateway` → `PutInferenceEndpointAiGatewayRequest`, `PutInferenceEndpointRateLimits` → `PutInferenceEndpointRateLimitsRequest`, `UpdateInferenceEndpointNotifications` → `UpdateInferenceEndpointNotificationsRequest`, `DeleteInferenceEndpoint` → `DeleteInferenceEndpointRequest`, `GetInferenceEndpoint` → `GetInferenceEndpointRequest`, `GetInferenceEndpointSchema` → `GetInferenceEndpointSchemaRequest`, `GetExportEndpointMetrics` → `GetExportEndpointMetricsRequest`, `GetServedModelBuildLogs` → `GetServedModelBuildLogsRequest`, `GetServedModelLogs` → `GetServedModelLogsRequest`, `ListInferenceEndpoints` → `ListInferenceEndpointsRequest`). None of the existing findings were resolved by these renames — the underlying naming concerns (Pt vs ProvisionedThroughput inconsistency #17/#18, divergent request shapes #19, addTags/deleteTags semantics #20, deprecated `RateLimit` #26) all carry over to the suffixed names unchanged. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index 9bfa889c..d4b8edc1 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -11,7 +11,10 @@ **Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. -**Total weird names flagged:** 30 +**Total weird names flagged:** 18 (0 fixed, 18 still, 0 superseded) + +Rescanned on 2026-05-26 after regeneration #156. All 18 findings remain +unchanged in the regenerated output; no items have moved to `## Fixed`. --- @@ -21,34 +24,22 @@ |----|----------|-----------------------------------|--------------------------------------------------------------|----------------------------------------------| | 1 | High | package + dir | `modelservingquery` / `@databricks/sdk-modelservingquery` | Duplicate concept; "query" overloaded SDK-wide | | 2 | High | `model.ts` interface | `QueryEndpointInputRequest` / `QueryEndpointResponse` | Four unrelated payload shapes packed into one type; double-suffix `Input` + `Request` | -| 3 | High | `model.ts` field | `QueryEndpointInputRequest.name` | Generic field name losing meaning (= endpoint name) | -| 4 | High | `model.ts` field | `QueryEndpointInputRequest.input` / `inputs` / `instances` / `prompt` / `messages` / `dataframeRecords` / `dataframeSplit` | 7 mutually-exclusive "input" fields, no oneof | -| 5 | High | `model.ts` field | `QueryEndpointInputRequest.n` | Cryptic abbreviation (single letter) | -| 6 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name; empty `Element` suffix | -| 7 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked into type name; empty `Element` suffix | -| 8 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | -| 9 | High | `model.ts` interface | `QueryEndpointInputRequest_ExtraParamsEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | -| 10 | High | `model.ts` interface | `QueryEndpointInputRequest_UsageContextEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | -| 11 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | -| 12 | Medium | `model.ts` interface | `DataframeSplitInput` | Generic field names lose meaning (`index`, `columns`, `data`) | -| 13 | Medium | `model.ts` field | `QueryEndpointResponse.data` | Vague (it's the *embeddings* array, not arbitrary data) | -| 14 | Medium | `model.ts` field | `QueryEndpointResponse.object` | Reserved-word collision (`Object` is a JS built-in) | -| 15 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | -| 16 | Medium | `model.ts` field | `QueryEndpointResponse.created` | Verb-tense / underspecified ("created" timestamp typed as `number`) | -| 17 | Medium | `model.ts` field | `QueryEndpointResponse.servedModelName` | Generic name (wire form `served-model-name` with hyphen) | -| 18 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | -| 19 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | -| 20 | Medium | `model.ts` field | `ExternalModelUsageElement.promptTokens` / `.completionTokens` / `.totalTokens` | Type-suffix tautology — every field carries `Tokens` | -| 21 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | -| 22 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | -| 23 | Medium | `model.ts` field | `QueryEndpointInputRequest.stop` | Reserved-word feel (verb-as-noun used as field) | -| 24 | Medium | `model.ts` field | `QueryEndpointInputRequest.stream` | Reserved-word feel (collides with web-stream `ReadableStream`) and field is `boolean`, not a stream | -| 25 | Medium | `model.ts` field | `QueryEndpointInputRequest.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | -| 26 | Medium | `model.ts` field | `QueryEndpointInputRequest.usageContext` | Vague pair with `extraParams`; both `Record` | -| 27 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | -| 28 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | -| 29 | Low | `model.ts` field | `EmbeddingsV1ResponseEmbeddingElement.index` | Underspecified (index of what?) | -| 30 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | +| 3 | High | `model.ts` field | `QueryEndpointInputRequest.input` / `inputs` / `instances` / `prompt` / `messages` / `dataframeRecords` / `dataframeSplit` | 7 mutually-exclusive "input" fields, no oneof | +| 4 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name; empty `Element` suffix | +| 5 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked into type name; empty `Element` suffix | +| 6 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | +| 7 | High | `model.ts` interface | `QueryEndpointInputRequest_ExtraParamsEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | +| 8 | High | `model.ts` interface | `QueryEndpointInputRequest_UsageContextEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | +| 9 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | +| 10 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | +| 11 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | +| 12 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | +| 13 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | +| 14 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | +| 15 | Medium | `model.ts` field | `QueryEndpointInputRequest.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | +| 16 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | +| 17 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 18 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | --- @@ -106,20 +97,7 @@ Better: split into `ChatQueryRequest`, `CompletionsQueryRequest`, `EmbeddingsQue `QueryEndpointResponse` has the same problem in mirror image: `choices` (chat/completions), `data` (embeddings), `predictions` (traditional), `outputs` (feature serving). The Go SDK has the same union, so the smell is inherited from the wire protocol. -### 3. `QueryEndpointInputRequest.name` — generic field name losing meaning - -**Location:** `src/v1/model.ts:77-78` - -**Categories:** 15 (generic field names), 19 (underspecified IDs) - -```ts -/** The name of the serving endpoint. This field is required and is provided via the path parameter. */ -name?: string | undefined; -``` - -`name` on a `QueryEndpointInputRequest` is unrelated to the *model* name, the *served-model* name (which appears in the response), the *user* name, or the *organisation* name — it's specifically the *serving endpoint* name, which then becomes a URL path segment. JSDoc clarifies but the field doesn't. `endpointName` would match the existing `servedModelName` field in `QueryEndpointResponse`. Also: the field is typed `string | undefined` but is required by JSDoc — and the client falls back to `req.name ?? ''`, silently producing a malformed URL when missing. - -### 4. Seven mutually-exclusive "input" fields with no discriminator +### 3. Seven mutually-exclusive "input" fields with no discriminator **Location:** `src/v1/model.ts:79-134` @@ -139,23 +117,7 @@ Note the singular/plural near-collision `input` (embeddings) vs `inputs` (tensor A user writing TS sees seven optional fields and has to read four JSDoc paragraphs to figure out which one to set. A discriminated union (`payload: { kind: 'chat'; messages: ... } | { kind: 'completions'; prompt: ... } | ...`) would make invalid combinations impossible. -### 5. `QueryEndpointInputRequest.n` — cryptic single-letter field - -**Location:** `src/v1/model.ts:110-115` - -**Category:** 5 (cryptic abbreviation) - -```ts -/** - * The n (number of candidates) field used ONLY for __completions__ and __chat external & foundation model__ - * serving endpoints. This is an integer between 1 and 5 with a default of 1 ... - */ -n?: number | undefined; -``` - -`n` is the wire-format shorthand inherited from the OpenAI API. In TS it parses as a counter loop variable. `numCandidates`, `candidateCount`, or even `numChoices` (matching the response's `choices` field) would be self-describing. The JSDoc literally has to explain what `n` means ("(number of candidates)"). - -### 6. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix +### 4. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix **Location:** `src/v1/model.ts:185-196` @@ -167,7 +129,7 @@ export interface V1ResponseChoiceElement { ... } The `V1` prefix duplicates the directory it lives in (`src/v1/`). When a hypothetical v2 ships, the type will be either `V2ResponseChoiceElement` (now-impossible name collision with whatever the new shape is called) or renamed (breaking change). The `Element` suffix is also empty — the type is the choice itself, not an "element of a choice." `Choice` (no prefix, no suffix) would suffice — `QueryEndpointResponse.choices: Choice[]` reads cleanly. v2-style versioning should live exclusively in the import path, not in identifiers. -### 7. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix +### 5. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix **Location:** `src/v1/model.ts:58-65` @@ -181,9 +143,9 @@ export interface EmbeddingsV1ResponseEmbeddingElement { } ``` -Same `V1` leak as finding #6. The `Element` suffix is empty — the type is the single embedding, not an "element of an embedding." `Embedding` (with `vector` for the numeric field) would convey the same data cleanly. +Same `V1` leak as finding #4. The `Element` suffix is empty — the type is the single embedding, not an "element of an embedding." `Embedding` (with `vector` for the numeric field) would convey the same data cleanly. -### 8. `ExternalModelUsageElement` — misleading scope + meaningless suffix +### 6. `ExternalModelUsageElement` — misleading scope + meaningless suffix **Location:** `src/v1/model.ts:67-74` @@ -205,9 +167,7 @@ Two problems: 1. **"External" is misleading.** This type is the OpenAI-spec `usage` block, returned by Databricks Foundation Model and Databricks Provisioned Throughput endpoints — both of which are **internal** Databricks-managed models. JSDoc in `QueryEndpointResponse.usage` even says "external/foundation model", but Databricks Foundation Models are explicitly *first-party*. The "External" prefix mislabels its scope. 2. **"Element" is meaningless.** The type is the single usage block, not "an element of a list." `TokenUsage`, `Usage`, or `ModelUsage` would suffice. -Pairs with finding #20 (every field redundantly ends in `Tokens`). - -### 9. `QueryEndpointInputRequest_ExtraParamsEntry` — proto map-entry leak +### 7. `QueryEndpointInputRequest_ExtraParamsEntry` — proto map-entry leak **Location:** `src/v1/model.ts:142-145` @@ -219,23 +179,23 @@ Pairs with finding #20 (every field redundantly ends in `Tokens`). **Rationale:** `_Entry` types are a proto-generator implementation detail (`map` lowers to a hidden nested message named `Entry`). Re-exporting them through a TS SDK forces language-specific generator scaffolding into the public API. The file's own ESLint disable comment is direct evidence that the name violates the project's naming convention — it is suppressed rather than fixed. -### 10. `QueryEndpointInputRequest_UsageContextEntry` — proto map-entry leak +### 8. `QueryEndpointInputRequest_UsageContextEntry` — proto map-entry leak **Location:** `src/v1/model.ts:148-151` -**Why:** Same proto-architectural leak as finding #9, applied to the `usage_context` map field. The interface is exported, never used in the schema (which uses `z.record(z.string(), z.string())`), and the file's own ESLint directive on line 147 labels it "Proto-style nested message name." Duplicate leak from the same generator template. +**Why:** Same proto-architectural leak as finding #7, applied to the `usage_context` map field. The interface is exported, never used in the schema (which uses `z.record(z.string(), z.string())`), and the file's own ESLint directive on line 147 labels it "Proto-style nested message name." Duplicate leak from the same generator template. **Category:** proto-architectural-leak (Protobuf generator artefact: `_Entry` map-entry message) **Suggested:** Delete the exported type entirely; `Record` is the natural TS surface. -**Rationale:** Mirror of #9. Two `_Entry` exports inflate the package surface area with proto-internal types that have no meaningful TS use case. They are a recurring pattern across packages with map fields, suitable for generator-level suppression. +**Rationale:** Mirror of #7. Two `_Entry` exports inflate the package surface area with proto-internal types that have no meaningful TS use case. They are a recurring pattern across packages with map fields, suitable for generator-level suppression. --- ## Medium severity -### 11. `query()` — verb-tense / reserved-word feel +### 9. `query()` — verb-tense / reserved-word feel **Location:** `src/v1/client.ts:58-81` @@ -248,48 +208,7 @@ async query(req: QueryEndpointInputRequest, options?: CallOptions): Promise | undefined; "Extra" relative to what? The 8 other fields already on `QueryEndpointInputRequest` are the "main" params; everything else falls through to here. `passthroughParams`, `modelParams`, or `externalParamsOverride` would be clearer. Also: typed `Record` — but OpenAI's "extra params" semantically include `top_p` (number), `presence_penalty` (number), and `tools` (array). The string-only typing forces stringification of values that should be passed through as JSON. -### 26. `QueryEndpointInputRequest.usageContext` — vague pair - -**Location:** `src/v1/model.ts:137-138` - -**Category:** 1 (vague) - -```ts -/** Optional user-provided context that will be recorded in the usage tracking table. */ -usageContext?: Record | undefined; -``` - -Pairs with #25 (both are open-ended string maps). "Usage context" is ambiguous: usage of what? Context for what? The JSDoc says "recorded in the usage tracking table" — a clearer name would be `usageMetadata` or `trackingContext`. - --- ## Low severity -### 27. JSDoc `/** Query a serving endpoint */` — verb tense / no period +### 16. JSDoc `/** Query a serving endpoint */` — verb tense / no period **Location:** `src/v1/client.ts:57` @@ -476,7 +317,7 @@ async query(...) { ... } Imperative verb, no terminal punctuation. Project rule (`CLAUDE.md`) requires comments to be sentences ending with a period. `/** Queries a serving endpoint. */` would match the v2-style JSDoc in other packages (`alerts/src/v2/client.ts` uses third-person singular present). -### 28. `ChatMessageRole.ASSISTANT` — incomplete enum +### 17. `ChatMessageRole.ASSISTANT` — incomplete enum **Location:** `src/v1/model.ts:17-23` @@ -493,20 +334,7 @@ export enum ChatMessageRole { Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. -### 29. `EmbeddingsV1ResponseEmbeddingElement.index` — underspecified - -**Location:** `src/v1/model.ts:61-62` - -**Category:** 19 (underspecified IDs) - -```ts -/** The index of the embedding in the response. */ -index?: number | undefined; -``` - -`index` without qualification: index inside what? `responseIndex`, `embeddingIndex`, or `position` would be specific. Pairs with `V1ResponseChoiceElement.index` and `DataframeSplitInput.index` — three "index" fields with three different meanings. - -### 30. `flattenQueryParams` — orphaned export with conflicting "Query" +### 18. `flattenQueryParams` — orphaned export with conflicting "Query" **Location:** `src/v1/utils.ts:123-150` @@ -529,7 +357,7 @@ Two issues: ## Observations -1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (4, 13, 16). +1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (3, 10). 2. **Wire-format leakage is severe.** Wire-format names show up almost verbatim in TS: `n`, `stop`, `stream`, `logprobs`, `object`, `data`, `extra_params`, `served-model-name`, `EmbeddingsV1ResponseEmbeddingElement`. The Go SDK shares the smell, but Go's `query_endpoint` request becomes `QueryEndpointInputRequest` in TS, where TS users have no way to distinguish the four valid combinations. diff --git a/.agent/naming-audit/networking.md b/.agent/naming-audit/networking.md index d8d654cb..0a6bd224 100644 --- a/.agent/naming-audit/networking.md +++ b/.agent/naming-audit/networking.md @@ -73,56 +73,3 @@ _None._ ## Observations _None._ - -## Fixed - -- `CreateNetworkConnectivityConfigPublicRequest` — proto-architecture - leak removed; renamed to `CreateNetworkConnectivityConfigRequest`. - Fixed in regeneration on 2026-05-22. -- `CreateNetworkPublicRequest` — proto-architecture leak removed; - renamed to `CreateNetworkRequest`. Fixed in regeneration on - 2026-05-22. -- `CreatePrivateAccessSettingsPublicRequest` — proto-architecture leak - removed; renamed to `CreatePrivateAccessSettingsRequest`. Fixed in - regeneration on 2026-05-22. -- `CreateVpcEndpointPublicRequest` — proto-architecture leak removed; - renamed to `CreateVpcEndpointRequest`. Fixed in regeneration on - 2026-05-22. -- `DeleteNetworkConnectivityConfigPublicRequest` — proto-architecture - leak removed; renamed to `DeleteNetworkConnectivityConfigRequest`. - Fixed in regeneration on 2026-05-22. -- `DeleteNetworkPublicRequest` — proto-architecture leak removed; - renamed to `DeleteNetworkRequest`. Fixed in regeneration on - 2026-05-22. -- `DeletePrivateAccessSettingsPublicRequest` — proto-architecture leak - removed; renamed to `DeletePrivateAccessSettingsRequest`. Fixed in - regeneration on 2026-05-22. -- `DeleteVpcEndpointPublicRequest` — proto-architecture leak removed; - renamed to `DeleteVpcEndpointRequest`. Fixed in regeneration on - 2026-05-22. -- `GetNetworkConnectivityConfigPublicRequest` — proto-architecture leak - removed; renamed to `GetNetworkConnectivityConfigRequest`. Fixed in - regeneration on 2026-05-22. -- `GetNetworkPublicRequest` — proto-architecture leak removed; renamed - to `GetNetworkRequest`. Fixed in regeneration on 2026-05-22. -- `GetPrivateAccessSettingsPublicRequest` — proto-architecture leak - removed; renamed to `GetPrivateAccessSettingsRequest`. Fixed in - regeneration on 2026-05-22. -- `GetVpcEndpointPublicRequest` — proto-architecture leak removed; - renamed to `GetVpcEndpointRequest`. Fixed in regeneration on - 2026-05-22. -- `ListNetworkConnectivityConfigsPublicRequest` — proto-architecture - leak removed; renamed to `ListNetworkConnectivityConfigsRequest`. - Fixed in regeneration on 2026-05-22. -- `ListNetworkConnectivityConfigsPublicResponse` — proto-architecture - leak removed; renamed to `ListNetworkConnectivityConfigsResponse`. - Fixed in regeneration on 2026-05-22. -- `ListPrivateAccessSettingsPublicRequest` — proto-architecture leak - removed; renamed to `ListPrivateAccessSettingsRequest`. Fixed in - regeneration on 2026-05-22. -- `ListPrivateAccessSettingsPublicResponse` — proto-architecture leak - removed; renamed to `ListPrivateAccessSettingsResponse`. Fixed in - regeneration on 2026-05-22. -- `UpdatePrivateAccessSettingsPublicRequest` — proto-architecture leak - removed; renamed to `UpdatePrivateAccessSettingsRequest`. Fixed in - regeneration on 2026-05-22. diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 34663b11..99e2c09d 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,14 +3,14 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 20 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 6 | +| High | 4 | +| Medium | 1 | | Low | 5 | | Observation | 3 | @@ -19,25 +19,18 @@ | # | Severity | Location | Name | Category | |---|----------|----------|------|----------| | 1 | High | `model.ts:5-11` | `DestinationType` | 1 (vague) | -| 2 | High | `model.ts:5-11` | `DestinationType.PAGERDUTY` / `MICROSOFT_TEAMS` | 3 (acronym casing inconsistency) | -| 3 | High | `model.ts:8` | `DestinationType.WEBHOOK` (vs `GenericWebhookConfig`) | 6 (misleading), 12 (duplicate concept name mismatch) | -| 4 | High | `model.ts:13-21` | `Config` (type) and `Config.config` (field) | 1 (vague), 9 (self-referential) | -| 5 | High | `model.ts:117` | `PagerdutyConfig` (type) and `pagerduty` ($case) | 3 (acronym casing inconsistency) | -| 6 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | -| 7 | Medium | `model.ts:46`, `:50`, `:54`, `:87` etc. | `urlSet` / `usernameSet` / `passwordSet` / `appIdSet` / `authSecretSet` / `channelUrlSet` / `tenantIdSet` / `integrationKeySet` / `oauthTokenSet` / `channelIdSet` | 6 (misleading), 15 (generic field naming pattern) | -| 8 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | -| 9 | Medium | `model.ts:67` | `ListNotificationDestinationsResponse.results` | 1 (vague), 15 (generic field name) | -| 10 | Medium | `model.ts:74`, `:108` | `id` (UUID) | 19 (underspecified ID) | -| 11 | Medium | `model.ts:117` | `PagerdutyConfig.integrationKey` (vs `*Set` companion) | 6 (misleading optionality semantics, output-only mirror) | -| 12 | Medium | `model.ts:78`, `:112` | `destinationType` field | 20 (type-suffix tautology when combined with the type name) | -| 13 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | -| 14 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | -| 15 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | -| 16 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | -| 17 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 18 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | -| 19 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | -| 20 | Obs | `model.ts:47`, `:51` | `[Input-Only][Optional]` doc marker inconsistency | — | +| 2 | High | `model.ts:8` | `DestinationType.WEBHOOK` (vs `GenericWebhookConfig`) | 6 (misleading), 12 (duplicate concept name mismatch) | +| 3 | High | `model.ts:13-21` | `Config` (type) and `Config.config` (field) | 1 (vague), 9 (self-referential) | +| 4 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | +| 5 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | +| 6 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | +| 7 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | +| 8 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | +| 9 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | +| 10 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 11 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 12 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | +| 13 | Obs | `model.ts:47`, `:51` | `[Input-Only][Optional]` doc marker inconsistency | — | ## High severity @@ -57,25 +50,7 @@ - **Suggested name:** `NotificationChannel` or, less invasive, `NotificationDestinationType`. - **Rationale:** Domain-anchored enum names protect users from cross-package collisions and read better in IDE autocomplete (`NotificationChannel.SLACK` vs `DestinationType.SLACK`). -### 2. `DestinationType.PAGERDUTY` and `.MICROSOFT_TEAMS` — acronym/brand casing inconsistency — `src/v1/model.ts:9-10` -- **Code:** - ```ts - PAGERDUTY = 'PAGERDUTY', - MICROSOFT_TEAMS = 'MICROSOFT_TEAMS', - ``` -- **Why weird:** Inside this package the brand "PagerDuty" appears in **five** different casings: - - `DestinationType.PAGERDUTY` (all caps, no separator) — enum value (line 9). - - `{$case: 'pagerduty', pagerduty: ...}` (all lower) — oneof discriminant + field (line 18). - - `PagerdutyConfig` (TitleCase but **not** `PagerDutyConfig`) — interface name (line 117). - - `pagerduty` (wire) — JSON key (lines 155, 172, 282). - - `PagerDuty` (TitleCase with internal D) — JSDoc prose only (line 118 "Integration key for PagerDuty"). - - The same applies to Microsoft Teams: `MICROSOFT_TEAMS`, `microsoftTeams` ($case), `MicrosoftTeamsConfig`, `microsoft_teams` (wire). Only the wire and JSDoc are externally fixed; the TS identifier choices `Pagerduty` (vs `PagerDuty`) and `MicrosoftTeams` (already correct) are an internal choice — and they are not consistent with the brand. The TS Style Guide is explicit: brand acronyms keep their canonical casing in identifiers (PagerDuty, GitHub, GraphQL). `Pagerduty` reads as a typo. -- **Category:** 3 (acronym casing inconsistency). -- **Suggested name:** `PagerDutyConfig` (interface). For consistency at minimum rename `PagerdutyConfig` → `PagerDutyConfig` and the `$case: 'pagerduty'` → `$case: 'pagerDuty'`. -- **Rationale:** Brand names are part of the public API surface; users reading IDE autocomplete should see `PagerDutyConfig` matching the company's own capitalisation. The cost is one schema rename across `unmarshalConfigSchema`'s discriminator strings — the wire JSON key stays `pagerduty`. - -### 3. `DestinationType.WEBHOOK` corresponds to `GenericWebhookConfig` — misleading enum vs config asymmetry — `src/v1/model.ts:8`, `:42-55`, `:17` +### 2. `DestinationType.WEBHOOK` corresponds to `GenericWebhookConfig` — misleading enum vs config asymmetry — `src/v1/model.ts:8`, `:42-55`, `:17` - **Code:** ```ts // enum value @@ -90,7 +65,7 @@ - **Suggested name:** Pick one: rename the enum value to `GENERIC_WEBHOOK` (preferred, preserves the qualifier that distinguishes from MS-Teams' webhook URL), or rename `GenericWebhookConfig` → `WebhookConfig`. - **Rationale:** The `MicrosoftTeamsConfig` and `GenericWebhookConfig` both have a `url` field that is "a webhook URL" (lines 44, 85), so the qualifier "generic" is genuinely meaningful — it distinguishes the channel-agnostic incoming-webhook target from the Teams-branded webhook. Keep the qualifier, but propagate it to the enum. -### 4. `Config` (interface) and its `config` field — vague top-level name + self-referential field — `src/v1/model.ts:13-21` +### 3. `Config` (interface) and its `config` field — vague top-level name + self-referential field — `src/v1/model.ts:13-21` - **Code:** ```ts export interface Config { @@ -108,18 +83,7 @@ - **Suggested name:** Rename the type to `NotificationDestinationConfig` (matches the package's domain prefix). - **Rationale:** A domain-anchored type name eliminates the cross-package collision risk and the `config.config` repetition along the property path. -### 5. `PagerdutyConfig` and `pagerduty` — see #2, separate finding because the `$case` discriminant is also visible to users — `src/v1/model.ts:18`, `:117`, `:280` -- **Code:** see #2. -- **Why weird:** The `$case: 'pagerduty'` string literal is what users *write* when constructing a `Config`: - ```ts - const cfg: Config = { config: { $case: 'pagerduty', pagerduty: { integrationKey: '...' } } }; - ``` - So both the type name `PagerdutyConfig` and the literal `'pagerduty'` are part of the API surface. The lowercase form is fixed (it's the JSON key); the camelCase TS identifier is a choice — and the choice was made to ignore the brand's internal capital. -- **Category:** 3 (acronym casing). -- **Suggested name:** `PagerDutyConfig` (type) and `$case: 'pagerDuty'` (discriminant). Wire JSON stays `pagerduty`. -- **Rationale:** Same as #2 — flagged separately because the discriminant literal is a distinct API element from the interface name. - -### 6. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:42-55` +### 4. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:42-55` - **Code:** ```ts export interface GenericWebhookConfig { @@ -134,28 +98,12 @@ ``` - **Why weird:** The qualifier "generic" tells the user nothing concrete. It means "this is the webhook config that is *not* the Microsoft Teams webhook config" — a knowledge that requires reading the whole file. A user looking at IDE autocomplete sees `GenericWebhookConfig` and `MicrosoftTeamsConfig` side-by-side and has to guess that MS-Teams is also a webhook channel that just has more fields. - **Category:** 1 (vague — "generic" carries no positive information). -- **Suggested name:** `WebhookConfig` (and rename the enum value to `GENERIC_WEBHOOK` per #3 if you want to preserve the disambiguation from the MS-Teams-webhook). Or be honest and call it `IncomingWebhookConfig` (the actual term-of-art used by Slack/Teams/Discord for this shape). +- **Suggested name:** `WebhookConfig` (and rename the enum value to `GENERIC_WEBHOOK` per #2 if you want to preserve the disambiguation from the MS-Teams-webhook). Or be honest and call it `IncomingWebhookConfig` (the actual term-of-art used by Slack/Teams/Discord for this shape). - **Rationale:** "Generic" is a code smell whenever it appears in a public type name. It usually means "this is the default, but there might be variants" — and TypeScript already has `extends`, intersections, and unions for variants. If the shape is the default, drop the qualifier; if there are real variants, name them after what makes them different (`AuthenticatedWebhookConfig`, etc.). ## Medium severity -### 7. `*Set: boolean` companion fields — pervasive pattern with confusing optionality — `src/v1/model.ts:46, 50, 54, 87, 91, 95, 99, 103, 121, 128, 132, 136` -- **Code (representative):** - ```ts - /** [Input-Only] URL for webhook. */ - url?: string | undefined; - /** [Output-Only] Whether URL is set. */ - urlSet?: boolean | undefined; - ``` -- **Why weird:** Every secret field (URL, username, password, OAuth token, integration key, app ID, auth secret, channel URL, tenant ID, channel ID) has a paired `*Set` boolean. The pattern exists because the server cannot echo secrets back, so it tells the client "the secret is set" without disclosing the value. Three problems with the names: - 1. `urlSet` reads as "URL of a set" or "set of URLs" — not "URL is set." Idiomatic TS would be `isUrlSet` or `hasUrl`. - 2. The `*Set` field is `boolean | undefined` — three-valued logic on a property that should be binary. The undefined case is ambiguous: not set, server didn't return it, or you're not an admin? JSDoc doesn't say. - 3. The paired fields are **modal** — on input you set `url`, on output you read `urlSet`. The type system has no way to express this; both fields are simultaneously optional, so a user could try to set `urlSet: true` on input and the server will silently ignore it. -- **Category:** 6 (misleading — three-valued boolean), 15 (generic field-naming pattern losing meaning). -- **Suggested name:** Rename the pattern to `hasUrl`, `hasUsername`, etc. (English-correct boolean predicates). Better: split the input and output types so input has `url` only and output has `hasUrl` only. Or merge into a union: `url?: { write: string } | { read: { isSet: boolean } }`. -- **Rationale:** This is the dominant naming smell in the file — it occurs ten times. Worth a coordinated rename across all config types, not piecemeal. The `[Input-Only]`/`[Output-Only]` JSDoc markers (finding 18) hint that the type was originally split in the API spec and was flattened for TS. - -### 8. `Client` — unprefixed class — `src/v1/client.ts:45` +### 5. `Client` — unprefixed class — `src/v1/client.ts:45` - **Code:** `export class Client { ... }` - **Why weird:** Every package in the SDK exports a class named `Client`. A user wiring up two packages (`notificationdestinations` + `alerts`, say) writes: ```ts @@ -167,58 +115,14 @@ - **Suggested name:** `NotificationDestinationsClient`, or expose only the namespace import (`import * as notificationDestinations from '@databricks/sdk-notificationdestinations/v1'`). - **Rationale:** Cross-SDK consistency, but every consumer pays the rename cost. Worth a generator-level fix. -### 9. `ListNotificationDestinationsResponse.results` — vague field name — `src/v1/model.ts:67` -- **Code:** - ```ts - results?: ListNotificationDestinationsResult[] | undefined; - ``` -- **Why weird:** "results" is a placeholder name. The field holds notification destinations, so it should be named `destinations` or `notificationDestinations` or `items`. "Results" is what a generator emits when it doesn't know what the list contains; users read it as "search results" or "test results" and have to look at the type to confirm. Compare to the broader SDK convention where list responses use `items` (jobs, runs) or the domain-qualified plural (clusters, alerts). -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `destinations` (drop the `notification` qualifier since the package context supplies it) or `items`. - -### 10. `id` as a top-level field — underspecified — `src/v1/model.ts:31, 58, 74, 108, 141` -- **Code:** - ```ts - /** UUID identifying notification destination. */ - id?: string | undefined; - ``` -- **Why weird:** A bare `id` field at the top of `NotificationDestination`, `ListNotificationDestinationsResult`, and three request types. The JSDoc clarifies it's a UUID, but the field name does not. In a multi-resource SDK, `destinationId` or `notificationDestinationId` would survive a refactor that combines several resources in one collection. Also the field is `string | undefined` even though every endpoint requires it on output and three of four endpoints require it on input — see finding 5 of the billableusagedownload audit for the same issue. -- **Category:** 19 (underspecified ID). -- **Suggested name:** `destinationId` (within the package context the qualifier "notification" is implicit). Or `id` is acceptable if the type is always accessed as `destination.id`. -- **Rationale:** Bare `id` is conventional and tolerated; the optionality is the real bug. Demoted to medium. - -### 11. `PagerdutyConfig.integrationKey` — meaning depends on direction — `src/v1/model.ts:117-122` -- **Code:** - ```ts - export interface PagerdutyConfig { - /** [Input-Only] Integration key for PagerDuty. */ - integrationKey?: string | undefined; - /** [Output-Only] Whether integration key is set. */ - integrationKeySet?: boolean | undefined; - } - ``` -- **Why weird:** Same as #7 in the specific case. The field is `string | undefined` on input but always `undefined` on output (the server never echoes it). The companion `integrationKeySet: boolean | undefined` carries the output information. A reader sees two optional fields and has to know the modal convention. -- **Category:** 6 (misleading optionality). -- **Suggested name:** see #7. -- **Rationale:** Listed separately because PagerDuty is the simplest case (one secret field) and best illustrates the pattern. - -### 12. `destinationType` field — type-suffix tautology — `src/v1/model.ts:78`, `:112` -- **Code:** - ```ts - destinationType?: DestinationType | undefined; - ``` -- **Why weird:** Field name "destinationType" of type "DestinationType". Tautology — the suffix `Type` is doing double duty as both a noun ("kind of destination") and a TS type marker. Inside the package's `NotificationDestination` type, naming the field `type` or `channel` would be self-evident from context (`destination.type === 'slack'`). Compare to `ec2-style` `instanceType: InstanceType` which has the same smell but is conventional in cloud SDKs. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `type` (with the parent type name supplying the context) or `channel`. If the enum is renamed `NotificationChannel` (per #1), then the field becomes `channel: NotificationChannel` which reads cleanly. - ## Low severity -### 13. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` -- See #3 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. +### 6. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` +- See #2 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. - **Category:** 9 (qualifier mismatch). -- **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #3 for the rationale. +- **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #2 for the rationale. -### 14. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` +### 7. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` - **Code:** ```ts // Package identity segment for this client to be used in the User-Agent header. @@ -232,7 +136,7 @@ - **Suggested name:** `USER_AGENT_PACKAGE_INFO` or `PACKAGE_USER_AGENT`. - **Rationale:** Cross-package — same finding appears in every audited file. -### 15. `HttpCallOptions` — `src/v1/utils.ts:15-19` +### 8. `HttpCallOptions` — `src/v1/utils.ts:15-19` - **Code:** ```ts export interface HttpCallOptions { @@ -245,13 +149,13 @@ - **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). - **Suggested name:** `HttpCallContext` (it is an internal context bag, not user-tunable options). -### 16. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` +### 9. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` - **Code:** lines 26-38 and 65-94. - **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + ApiError check. - **Category:** 1 (vague), 17 (inconsistent layer naming). - **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). -### 17. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` +### 10. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -259,16 +163,16 @@ ## Observations -### 18. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +### 11. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). - **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. -### 19. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows +### 12. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. -### 20. JSDoc inconsistency in `[Input-Only][Optional]` markers +### 13. JSDoc inconsistency in `[Input-Only][Optional]` markers The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the marker `[Input-Only][Optional]` — concatenating two brackets — while every other field uses single-bracket markers. The `[Optional]` is also redundant because the TS type already shows `?: undefined`. Minor doc inconsistency. ## Domain glossary diff --git a/.agent/naming-audit/oauth.md b/.agent/naming-audit/oauth.md index 4e216040..935ec39b 100644 --- a/.agent/naming-audit/oauth.md +++ b/.agent/naming-audit/oauth.md @@ -22,17 +22,17 @@ covers three resources in one client: All three share the `TokenAccessPolicy` type for access/refresh-token TTL and session-rotation configuration. The package is the Databricks account-side complement to RFC 6749 client registration. -**Total weird names flagged:** 9 +**Total weird names flagged:** 5 ## Summary table | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 3 | +| High | 2 | +| Medium | 0 | | Low | 3 | | Observation | 2 | -| **Total** | **9 (+ 2 observations)** | +| **Total** | **5 (+ 2 observations)** | The audit excludes the `OAuth*` brand-name spelling (RFC 6749 platform-name exception), `*_UNSPECIFIED` proto sentinels, `*_Response` proto-nested @@ -41,8 +41,7 @@ empty wrapper types, `*Iter` pagination duplicates, redundant enum prefixes, JS-built-in acronym casing (`URLSearchParams`, `JSON.parse`), and wire-format strings preserved in JSDoc. The remaining findings cluster around (1) the consolidated package surfacing intra-package -inconsistencies that used to be cross-package, (2) `appId` being a -human-readable slug rather than an opaque ID, and (3) leftover +inconsistencies that used to be cross-package and (2) leftover generator/template artefacts (stale `:method:` cross-refs, `` template tokens, dead helper exports). @@ -50,36 +49,7 @@ template tokens, dead helper exports). ## High severity (must fix) -### 1. `appId` is a slug, not an opaque ID — `model.ts:34, 156, 173` -- **Why:** Three types in this file expose a string field named `appId`. - On `CreatePublishedOAuthAppIntegrationRequest` (line 34) the JSDoc - reads "For example power-bi, tableau-deskop"; on `PublishedOAuthApp` - (line 156) it reads "Unique ID of the published OAuth app"; on - `PublishedOAuthAppIntegration` (line 173) it reads "App-id of the - published app integration". So `appId` is actually a human-readable - catalog slug such as `power-bi`, `tableau-desktop`, `looker`. Every - other `xId` field in this package and across the SDK - (`accountId`, `integrationId`, `clientId`, `createdBy`, - `principalId`) is an opaque server-issued identifier. Mixing a slug - in under the `Id` suffix is a teaching trap, and the three doc strings - describe the same value three different ways. -- **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) -- **Suggested:** Rename to `appSlug` (or `publishedAppKey`) on all three - types, narrow the type to a string literal union populated from the - Databricks published-app catalog - (`'power-bi' | 'tableau-desktop' | 'looker' | ...`), and replace the - three divergent doc strings with one canonical line ("Dash-separated - lowercase slug from the Databricks published-app catalog, e.g. - `power-bi`."). Fix the `tableau-deskop` typo on line 32 in the - process. -- **Rationale:** A slug typed as `string` and named `appId` is the - worst possible mix of soft-typing — it advertises opacity while - accepting any string, and the only documented examples are - catalog-specific values. A literal union plus a non-`Id` name puts - the value space in the type system instead of in a doc-comment - asterisk-list. - -### 2. Stale JSDoc cross-references to non-existent services — `client.ts:101, 137, 172, 203, 458, 493` +### 1. Stale JSDoc cross-references to non-existent services — `client.ts:101, 137, 172, 203, 458, 493` - **Why:** Six method docs say "You can retrieve the … OAuth app integration via `:method:CustomAppIntegration/get`" or "`:method:PublishedAppIntegration/get`". Neither `CustomAppIntegration` @@ -100,7 +70,7 @@ template tokens, dead helper exports). worse than no documentation. The leak is a generator template failing to rewrite proto-cross-reference syntax for TS output. -### 3. `confidential` vs `isConfidentialClient` — same flag spelled two ways in one file — `model.ts:12, 55, 164` +### 2. `confidential` vs `isConfidentialClient` — same flag spelled two ways in one file — `model.ts:12, 55, 164` - **Why:** The RFC 6749 §2.1 "confidential client" boolean flag appears three times in `model.ts`. On `CreateCustomOAuthAppIntegrationRequest.confidential` (line 12) and @@ -126,78 +96,7 @@ template tokens, dead helper exports). ## Medium severity (worth pushing back on) -### 1. `userAuthorizedScopes` reads as past-tense "did consent" but is configuration of "will ask for consent" — `model.ts:25, 67, 226` -- **Why:** Three sites expose `userAuthorizedScopes?: string[]` — - `CreateCustomOAuthAppIntegrationRequest`, - `CustomOAuthAppIntegration`, and - `UpdateCustomOAuthAppIntegrationRequest`. The doc reads "Scopes that - will need to be consented by end user to mint the access token. If - the user does not authorize the access token will not be minted. - Must be a subset of scopes." So this is a *configuration* of the - consent gate the server will enforce, not a record of past consent. - The name `userAuthorizedScopes` reads as a state field — what the - user already authorised — and a caller can easily misread it that - way. A second issue: the subset relationship to `scopes` is invisible - from the type — setting `scopes = ['all-apis']` and - `userAuthorizedScopes = ['sql']` is a runtime-error, not a - type-error. -- **Category:** 1, 6, 13 (vague; misleading verb tense; configuration - vs state confusion) -- **Suggested:** Rename to `consentRequiredScopes` (configuration — - "scopes that require explicit end-user consent"). At minimum, add - inline JSDoc on `scopes` that backreferences this subset constraint - and cite RFC 6749 §3.3 for the scope vocabulary. -- **Rationale:** Bug class: caller assumes `userAuthorizedScopes` is - "what the user actually consented to" (read-after-write state) when - it is actually "what we will ask the user to consent to" (write-only - configuration). The current name reads past-tense and is easily - misread. The same trap exists on the matching `update` request, - which makes it possible to clobber a consent policy by accident. - -### 2. `createdBy: number` is a user ID disguised as an activity verb — `model.ts:59, 180` -- **Why:** `CustomOAuthAppIntegration.createdBy` (line 59) and - `PublishedOAuthAppIntegration.createdBy` (line 180) are both - `number | undefined`. The custom variant pairs it 2 lines below with - `creatorUsername: string` (line 61); the published variant lacks the - username pair. The undocumented numeric `createdBy` is the - Databricks user ID of the creator. The name reads as a verb phrase - ("created by"), not as an identifier, and the bare `number` type - carries no clue. The published variant's missing `creatorUsername` - pair is itself an asymmetry — `includeCreatorUsername` (line 114) - exists for custom but no equivalent for published. -- **Category:** 1, 15, 19 (vague; generic field; underspecified ID) -- **Suggested:** Rename to `creatorUserId: number` on both types and - document explicitly as "Databricks numeric user ID of the - registration creator." Keep `creatorUsername` next to it on - `CustomOAuthAppIntegration` and add it to - `PublishedOAuthAppIntegration` if the published API exposes it. -- **Rationale:** A bare `createdBy: number` is the worst kind of - numeric ID — no type information, no JSDoc, and a name that reads - as an activity-verb phrase rather than as a field. The asymmetry - with `creatorUsername` (present on one of the two registration - types) compounds the confusion. - -### 3. `enableSingleUseRefreshTokens` is verb-first while the rest of the file is predicate-style — `model.ts:199` -- **Why:** `TokenAccessPolicy.enableSingleUseRefreshTokens` (line 199) - uses the imperative-verb-first convention (`enableX`). The rest of - `TokenAccessPolicy` uses predicate-noun naming - (`accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, - `absoluteSessionLifetimeInMinutes`). The neighbour - `confidential` / `isConfidentialClient` flags in the file are also - predicate-style. So this boolean is the only verb-first identifier - in a configuration object full of nouns. It reads as a method - ("call this to enable …") rather than as a state ("this is the - enabled state"). -- **Category:** 13, 17 (verb-tense inconsistency; inconsistent action - verbs) -- **Suggested:** Rename to `singleUseRefreshTokensEnabled` (predicate) - or `rotateRefreshTokens` (behavioural noun matching the JSDoc's - "refresh token rotation"). Avoid `useSingleUseRefreshTokens` — too - close to a method name. -- **Rationale:** `enableX` configuration flags drift from state - semantics. The matching JSDoc on line 195 already calls the feature - "single-use refresh tokens (refresh token rotation)" — a - predicate/state noun mirrors that vocabulary. +_None._ --- @@ -302,11 +201,11 @@ template tokens, dead helper exports). - `confidential` / `isConfidentialClient` — RFC 6749 §2.1 client type. `true` means the client has a secret and authenticates itself; `false` means it is a public client and relies on PKCE. - Currently spelled two ways in this file (finding H3). + Currently spelled two ways in this file (finding H2). - `Custom` integration — Caller-defined OAuth client (caller-owned redirect URLs, scopes, secret). - `createdBy` — Numeric Databricks user ID of the registration - creator. Field is named like a verb (finding M2). + creator. - `creatorUsername` — Username string of the registration creator. Server-side joined when `includeCreatorUsername` is set on the list request. @@ -325,8 +224,9 @@ template tokens, dead helper exports). - `TokenAccessPolicy` — Per-integration token TTL and refresh-rotation policy. - `userAuthorizedScopes` — Subset of `scopes` requiring explicit - end-user consent. Misleading verb tense — this is *will-ask*, - not *did-grant* (finding M1). + end-user consent. Despite the past-tense name, this is the + *configuration* of which scopes will require consent, not a + record of past consent. --- @@ -334,13 +234,12 @@ template tokens, dead helper exports). - The 2026-05-22 regeneration consolidated the prior `oauthcustomappintegration` and `oauthpublishedapp` packages into - this single `@databricks/sdk-oauth` package. Three former + this single `@databricks/sdk-oauth` package. Former cross-package inconsistencies are now intra-package issues: - `confidential` vs `isConfidentialClient` (H3), `appId` slug-vs-ID - agreement (H1), and the shape of the `scopes` documented value - space across the published and custom surfaces. The consolidation - is reflected in the import list at `index.ts:7-31`, which now - re-exports 25 types from one model file. + `confidential` vs `isConfidentialClient` (H2) and the shape of the + `scopes` documented value space across the published and custom + surfaces. The consolidation is reflected in the import list at + `index.ts:7-31`, which now re-exports 25 types from one model file. --- diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md index 0f5faaa5..c5e64bcb 100644 --- a/.agent/naming-audit/oauthcustomappintegration.md +++ b/.agent/naming-audit/oauthcustomappintegration.md @@ -142,12 +142,3 @@ - `src/v1/utils.ts` (151 lines): read fully — generic across packages. - `src/v1/index.ts` (33 lines): read fully — re-exports. - `package.json`: read for context. - -## Fixed -- #1 Package name `oauthcustomappintegration` mis-scopes the package (originally cited at `package.json:2`): Fixed in regeneration on 2026-05-20 — the standalone package was consolidated into `@databricks/sdk-oauth`, eliminating the misleading package name. -- #6 `createTime: string` vs `clientSecretExpireTime: Temporal.Instant` type inconsistency (originally cited at `model.ts:61, 89, 157`): Fixed in regeneration on 2026-05-20 — the `clientSecretExpireTime` field was removed during consolidation; the type-inconsistency between two timestamp fields no longer exists. -- #7 `clientSecretExpireTime` verb tense (originally cited at `model.ts:89`): Fixed in regeneration on 2026-05-20 — the field was removed during consolidation. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md index be6e46d9..a5f8bfb4 100644 --- a/.agent/naming-audit/oauthpublishedapp.md +++ b/.agent/naming-audit/oauthpublishedapp.md @@ -113,10 +113,3 @@ - `src/v1/utils.ts`: read for context — generic across packages, identical to siblings. - `src/v1/index.ts`: read for context — re-exports `Client` and model types. - `package.json`: now `@databricks/sdk-oauth` (consolidated). - -## Fixed -- #1 Package name `oauthpublishedapp` singular vs collection-only surface (originally cited at `package.json:2`, `client.ts:62`): Fixed in regeneration on 2026-05-20 — `oauthpublishedapp` package was merged into the multi-resource `@databricks/sdk-oauth` package, eliminating the singular-package-with-one-list-method concern. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md index b3ce5f3e..9e697740 100644 --- a/.agent/naming-audit/onlinetables.md +++ b/.agent/naming-audit/onlinetables.md @@ -96,767 +96,14 @@ | Medium | 10 | | Low / SDK-wide note | 9 | | Pass / acceptable | 9 | +| Fixed (post-regen) | 0 | | **Total findings** | **31** | (Several findings touch multiple audit categories; counts above are unique findings.) ---- - -## Findings - -### 1. SCREAMING_SNAKE_CASE enum members (value-level) — category 4 - -**Symbols:** Every value in both enums (model.ts:9–53 and 58–64). - -**Issue:** The project's `.agent/skills/google-ts-styleguide` (and Google TS -Style Guide § 5.3) mandates `UpperCamelCase` for enum *members*, not -`SCREAMING_SNAKE_CASE`. Every enum value here is SCREAMING-cased. - -Enum string *values* double as the on-the-wire representation here (the Zod -schemas parse raw API strings into these identifiers — `z.enum(OnlineTableState)` -at model.ts:341 and `z.enum(ProvisioningInfo_State)` at model.ts:290). The -TS-side identifier can be split from the wire literal — e.g. -`ProvisioningPipelineResources = 'PROVISIONING_PIPELINE_RESOURCES'` — which -is the canonical TS fix while preserving wire compatibility. - -**Suggested (TS side only, no wire change):** - -```ts -export enum OnlineTableState { - Unspecified = 'ONLINE_TABLE_STATE_UNSPECIFIED', - Provisioning = 'PROVISIONING', - ProvisioningPipelineResources = 'PROVISIONING_PIPELINE_RESOURCES', - ProvisioningInitialSnapshot = 'PROVISIONING_INITIAL_SNAPSHOT', - Online = 'ONLINE', - OnlineContinuousUpdate = 'ONLINE_CONTINUOUS_UPDATE', - OnlineTriggeredUpdate = 'ONLINE_TRIGGERED_UPDATE', - OnlineNoPendingUpdate = 'ONLINE_NO_PENDING_UPDATE', - Offline = 'OFFLINE', - OfflineFailed = 'OFFLINE_FAILED', - OnlinePipelineFailed = 'ONLINE_PIPELINE_FAILED', - OnlineUpdatingPipelineResources = 'ONLINE_UPDATING_PIPELINE_RESOURCES', -} - -export enum ProvisioningInfo_State { - Unspecified = 'STATE_UNSPECIFIED', - Provisioning = 'PROVISIONING', - Active = 'ACTIVE', - Failed = 'FAILED', - Deleting = 'DELETING', - Updating = 'UPDATING', - Degraded = 'DEGRADED', -} -``` - -**Flag as SDK-wide cleanup.** Same observation as `featurestore.md` finding 4 -and `database.md` finding 6. - ---- - -### 2. `OnlineTableState` modelled as one enum, two semantic groups — category 6 (Misleading names) and category 12 (Duplicate concepts) - -**Symbol:** `OnlineTableState` (model.ts:7), 12 values. - -**Issue:** The 12 values mix *lifecycle* states (`PROVISIONING`, -`PROVISIONING_PIPELINE_RESOURCES`, `PROVISIONING_INITIAL_SNAPSHOT`, `OFFLINE`, -`OFFLINE_FAILED`) with *ongoing-state* substates that are specific to the -"online" lifecycle (`ONLINE_CONTINUOUS_UPDATE`, `ONLINE_TRIGGERED_UPDATE`, -`ONLINE_NO_PENDING_UPDATE`, `ONLINE_PIPELINE_FAILED`, -`ONLINE_UPDATING_PIPELINE_RESOURCES`). The `OnlineTableStatus` interface -already has a `detailedStatus` discriminated union (model.ts:187) that -overlaps with these substates. So the same information is modelled twice: -once flat in the enum, once in the structured `detailedStatus`. - -This is a wire-level concern, but in TS it reads as a single enum doing two -jobs — top-level lifecycle and one-level-down detail. Compare to -`database.SyncedTableState` which has the same 12 values prefixed -`SYNCED_TABLE_…` (with a famous typo `SYNCED_TABLED_OFFLINE`). The duplication -*across packages* is also a flag — see finding 3. - -**Suggested:** push back upstream — split into `OnlineTableLifecycle` (a few -top-level states) and use `detailedStatus.$case` as the substate identifier. -**Pass at the TS level**, flag at the protocol level. - ---- - -### 3. Cross-package collision: `OnlineTableState` ↔ `database.SyncedTableState` (wire-level typo) — category 12 (Duplicate concepts) and category 17 (Inconsistent action verbs) - -**Symbol:** `OnlineTableState` (here, model.ts:7) and `SyncedTableState` -(`database/v1/model.ts:55`, `postgres/v1/model.ts`). - -**Issue:** Two SDK packages model essentially the same lifecycle concept — -the state of a UC-managed Delta-to-managed-store sync table — with two -*different enum names* and one is misspelled at the **wire-string** level -(`SYNCED_TABLED_OFFLINE`). Looking at the values: - -- `onlinetables.OnlineTableState`: 12 values. -- `database.SyncedTableState`: 12 values, plus the famous wire-string typo - `SYNCED_TABLED_OFFLINE`. - -These enums describe the *same machine*. A consumer who uses both packages -will write a lookup table or branch on `$case` differently in each package. -The `SYNCED_TABLED_OFFLINE` typo is on the wire and locks consumers into -the misspelling. - -**Suggested at the SDK level:** harmonise the type names (drop one in favour -of the other, with an alias for backward compatibility). The wire-level -typo fix is a protocol-team decision and a behavioural change. **Strongly -flag for SDK-wide alignment**; do not fix unilaterally in this package. - ---- - -### 4. Cross-package collision: `PipelineProgress` ↔ `database.SyncedTablePipelineProgress` — category 12 (Duplicate concepts) - -**Symbol:** `PipelineProgress` (here, model.ts:202) and -`database.SyncedTablePipelineProgress` (`database/v1/model.ts:744`, -`postgres/v1/model.ts:2547`). - -**Issue:** Identical concept (progress information for the data -synchronization pipeline of an online/synced table) modelled with two -different type names and identical fields (`latestVersionCurrentlyProcessing`, -`syncedRowCount`, `totalRowCount`, `syncProgressCompletion`, -`estimatedCompletionTimeSeconds`). - -**Suggested:** keep the shorter `PipelineProgress` (this package) as -canonical; rename `database.SyncedTablePipelineProgress` to -`PipelineProgress` and import from a shared `@databricks/sdk-onlinetables/v1` -or extract both into `@databricks/sdk-core` if the dependency is acceptable. -**SDK-wide cleanup.** - ---- - -### 5. Cross-package collision: `ProvisioningInfo` defined in 4+ packages — category 12 (Duplicate concepts) - -**Symbol:** `ProvisioningInfo` (here, model.ts:220) and its sibling state -enum. Also defined in: - -- `database/v1/model.ts` -- `postgres/v1/model.ts` -- `catalogs/v1/model.ts` -- `connections/v1/model.ts` - -**Issue:** Five separate copies of the same provisioning-info concept with -mostly-identical state values (`PROVISIONING`, `ACTIVE`, `FAILED`, `DELETING`, -`UPDATING`, `DEGRADED`). Each package re-declares the type. - -**Suggested:** hoist to a shared `@databricks/sdk-core/provisioning` module -(if cross-cutting), or keep duplicates with **value-level type-checked** -union to guarantee parity. **SDK-wide cleanup.** - ---- - -### 6. Cross-package collision: `DeleteOnlineTableRequest` defined in two packages with different fields — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) - -**Symbol:** `DeleteOnlineTableRequest` (here, model.ts:93) and -`featurestore.DeleteOnlineTableRequest` (`featurestore/v1/model.ts:57`). - -**Issue:** Both packages define a type with the *same name* but different -fields: - -```ts -// onlinetables/v1/model.ts:93 -export interface DeleteOnlineTableRequest { - name?: string | undefined; // Full three-part name of the table. -} -``` - -```ts -// featurestore/v1/model.ts:57 -export interface DeleteOnlineTableRequest { - onlineTableName?: string | undefined; // Full three-part name of the table. -} -``` - -A caller who imports both packages must alias them (namespacing handles the -type-name collision but the field name differs). The URL paths also differ: -`/api/2.0/online-tables/{name}` here vs. -`/api/2.0/feature-store/online-tables/{onlineTableName}` in featurestore. - -**Suggested:** harmonise the field name. `name` is shorter and idiomatic for -URL-path resource identifiers, matches REST conventions, and matches the -sibling `GetOnlineTableRequest.name` (model.ts:119) in this very package. -**Pin `name` as canonical, push back on `featurestore`.** - ---- - -### 7. `CreateOnlineTableRequest.table` field name is too generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) - -**Symbol:** `CreateOnlineTableRequest.table?: OnlineTable | undefined` -(model.ts:89). - -**Issue:** The field name `table` is generic. Compare to -`featurestore.CreateOnlineStoreRequest.onlineStore` (specific). The field's -*type* is `OnlineTable` so the descriptive name would be `onlineTable`. - -**Suggested:** `onlineTable` (matches the type, matches -`featurestore.publishTable.publishSpec.onlineTableName`). **Flag at port -time.** - ---- - -### 8. `OnlineTable.name` is a three-part UC name, not a free-text name — category 19 (Underspecified IDs) and category 1 (Vague/generic) - -**Symbol:** `OnlineTable.name?: string | undefined` (model.ts:125). JSDoc: -"Full three-part (catalog, schema, table) name of the table." - -**Issue:** A field called `name` carries a structured identifier of the form -`catalog.schema.table`. The same shape appears as: -- `OnlineTable.name` (here, model.ts:125) -- `DeleteOnlineTableRequest.name` (model.ts:95) -- `GetOnlineTableRequest.name` (model.ts:119) -- `OnlineTableSpec.sourceTableFullName` (model.ts:156) — note: this one is - more descriptive - -Three of four use `name` (with the constraint in JSDoc); one uses -`sourceTableFullName`. The naming is inconsistent *within this very file* -for the same conceptual shape (a three-part UC name). - -**Suggested:** either: -1. Rename `OnlineTable.name` to `fullName` (mirrors `sourceTableFullName`), - *and* rename `*Request.name` to `*Request.fullName`. This loses the AIP - resource-name convention. -2. Or, rename `OnlineTableSpec.sourceTableFullName` to `sourceTableName` - (drops `Full`, matches all other `*.name` shapes) and accept that the - JSDoc is the only place that documents the three-part constraint. - -Option 2 is the cheaper cleanup and aligns with REST `{name}` path -conventions. Cross-reference the identical `featurestore.PublishSpec.onlineTableName` -which also lacks `Full` prefix. **Pick one and apply SDK-wide.** - -This finding *also* hits category 19 (underspecified IDs): the field is a -**structured string** (`catalog.schema.table`) — neither the field name nor -the type enforces the format. A typed wrapper (e.g. -`type ThreePartName = string & { __brand: 'three-part' }`) is an option but -cross-SDK convention keeps it as a `string`. **Pass on the wrapper, flag the -inconsistency.** - ---- - -### 9. `OnlineTable.tableServingUrl` repeats "table" — category 8 (Redundant suffixes) - -**Symbol:** `OnlineTable.tableServingUrl?: string | undefined` (model.ts:131). - -**Issue:** Inside `OnlineTable`, the prefix `table…` is implicit. The field -name `tableServingUrl` repeats "table" — `servingUrl` (or `dataServingUrl`, -matching the JSDoc "Data serving REST API URL") would suffice. Compare to -`pipelineId` (model.ts:171) which lives in `OnlineTableSpec` and does *not* -prefix `tableTable…` or `onlineTable…`. - -**Suggested:** `servingUrl`. The JSDoc says "Data serving REST API URL for -this table" — `servingUrl` reads the same. - ---- - -### 10. `OnlineTable.unityCatalogProvisioningState` is overly verbose — category 7 (Overly verbose) - -**Symbol:** `OnlineTable.unityCatalogProvisioningState?: ProvisioningInfo_State | undefined` -(model.ts:137). 31 characters. - -**Issue:** The JSDoc explains the field is "The provisioning state of the -online table entity in Unity Catalog. This is distinct from the state of the -data synchronization pipeline (i.e. the table may be in 'ACTIVE' but the -pipeline may be in 'PROVISIONING' as it runs asynchronously)." That's the -*reason* the field exists — to disambiguate from the data-sync state. The -field name spells out "unityCatalogProvisioningState" which is descriptive -but long. - -The companion `OnlineTable.status` (model.ts:129) is the data-sync state. -Reasonable parallel names would be: -- `OnlineTable.ucState` / `OnlineTable.dataState` — too cryptic. -- `OnlineTable.provisioningState` / `OnlineTable.status` — `provisioningState` - is shorter and the JSDoc covers the UC scoping. - -**Suggested:** `provisioningState`. The JSDoc retains the disambiguation. - ---- - -### 11. `OnlineTable.status` vs `OnlineTable.unityCatalogProvisioningState` — category 17 (Inconsistent action verbs) and category 6 (Misleading names) - -**Symbols:** `OnlineTable.status` (model.ts:129), -`OnlineTable.unityCatalogProvisioningState` (model.ts:137). - -**Issue:** Two state-like fields on the same type: - -- `status: OnlineTableStatus` — the "data synchronization status." -- `unityCatalogProvisioningState: ProvisioningInfo_State` — the "provisioning - state of the online table entity in Unity Catalog." - -A reader sees `status` and `…State` side by side. Both are conceptually -"the state of the table"; the suffix difference (`Status` vs `State`) is not -a meaningful discriminator. The waiter (`CreateOnlineTableWaiter`, -client.ts:174) reads `unityCatalogProvisioningState` to decide done-ness, -not `status` — surprising. - -**Suggested:** rename `status` to `syncStatus` or `dataSyncStatus` to make -clear it is about the *data pipeline*, not the entity. Pair with -`provisioningState` (finding 10) for the UC-side entity state. - ---- - -### 12. `OnlineTableStatus.detailedState` vs `OnlineTableStatus.detailedStatus` — category 17 (Inconsistent action verbs) and category 12 (Duplicate concepts) - -**Symbols:** `OnlineTableStatus.detailedState` (model.ts:183), -`OnlineTableStatus.detailedStatus` (model.ts:187). - -**Issue:** Two fields named `detailed…` on the same type, distinguished only -by the singular/perfect noun suffix (`State` vs `Status`). `detailedState` -is an enum (`OnlineTableState`); `detailedStatus` is a discriminated union -of `ProvisioningStatus | ContinuousUpdateStatus | TriggeredUpdateStatus | -FailedStatus`. They are *related* — `detailedState` indicates which -`$case` of `detailedStatus` will be present — but the names provide zero -hint of the relationship. - -**Suggested:** rename `detailedState` to `state` and `detailedStatus` to -`statusDetails` or `details`. Reads more naturally: -```ts -const { state, details, message } = onlineTable.status!; -``` - -`OnlineTableStatus.message` (model.ts:185) is also descriptive — it is the -plain-text version of the state. The trio `state` / `details` / `message` -forms a coherent shape. **Flag at port time.** - ---- - -### 13. `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` all share `…Status` suffix — category 20 (Type-suffix tautology) — *pass with note* - -**Symbols:** `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, -`FailedStatus`, `ProvisioningStatus` (model.ts:71, 238, 102, 226). - -The four types all end with `Status`. Inside `OnlineTableStatus.detailedStatus` -(model.ts:187) the `$case` literals are `'continuousUpdateStatus'`, -`'triggeredUpdateStatus'`, `'failedStatus'`, `'provisioningStatus'` — also -`…Status`. The pattern is **consistent**. Suffix is repetitive but does -disambiguate from `OnlineTableSpec`/state enums. - -The `Failed` and `Provisioning` variants are also generic when read in -isolation — there could be many "failed status" or "provisioning status" -types in the SDK (and there are — see `database.SyncedTableProvisioningStatus`, -finding 14 below). - -**Suggested:** consider prefixing with the parent concept — e.g. -`OnlineTableContinuousUpdate`, `OnlineTableTriggeredUpdate`, -`OnlineTableFailed`, `OnlineTableProvisioning`. But this is verbose. **Pass -with note**, flag cross-package overlap below. - ---- - -### 14. Cross-package overlap: `ContinuousUpdateStatus`, `TriggeredUpdateStatus`, `FailedStatus`, `ProvisioningStatus` ↔ `database.SyncedTable*Status` — category 12 (Duplicate concepts) - -**Symbols:** -- `onlinetables.ContinuousUpdateStatus` ↔ `database.SyncedTableContinuousUpdateStatus` -- `onlinetables.TriggeredUpdateStatus` ↔ `database.SyncedTableTriggeredUpdateStatus` -- `onlinetables.FailedStatus` ↔ `database.SyncedTableFailedStatus` -- `onlinetables.ProvisioningStatus` ↔ `database.SyncedTableProvisioningStatus` - -**Issue:** All four pairs model the same shape (fields are identical or -near-identical). `database` adds a `SyncedTable` prefix to each — disambiguates -within `@databricks/sdk-core` if these were merged, but creates a duplicate -type surface across packages. Same root cause as finding 3 (`OnlineTableState` -↔ `SyncedTableState`). - -**Suggested:** harmonise — define once in `@databricks/sdk-onlinetables` or -in `@databricks/sdk-core` and re-export. **SDK-wide cleanup.** - ---- - -### 15. `PipelineProgress.latestVersionCurrentlyProcessing` is awkward — category 7 (Overly verbose) and category 13 (Verb-tense inconsistency) - -**Symbol:** `PipelineProgress.latestVersionCurrentlyProcessing?: number | undefined` -(model.ts:207). 32 characters. - -**Issue:** "currently processing" packs a present-progressive verb into a -field name, which is unusual for TS field naming. The JSDoc says "The source -table Delta version that was last processed by the pipeline. The pipeline -may not have completely processed this version yet." — so the *field* records -"the most recent version we've seen / started processing" and the JSDoc -notes processing may be incomplete. - -Compare to `ContinuousUpdateStatus.lastProcessedCommitVersion` (model.ts:76) -which describes essentially the same idea with a participle (`Processed`) — -and is *clearer*: it's the version that was processed. - -So the same package has two different names for the same Delta-version idea: -- `latestVersionCurrentlyProcessing` (PipelineProgress) -- `lastProcessedCommitVersion` (ContinuousUpdateStatus, FailedStatus, - TriggeredUpdateStatus) - -The JSDoc on `lastProcessedCommitVersion` (model.ts:73) even says "may not -be completely synced to the online table yet" — same caveat as -`latestVersionCurrentlyProcessing`'s JSDoc. So they describe the same thing. - -**Suggested:** rename `latestVersionCurrentlyProcessing` to -`lastProcessedVersion` (consistency with `lastProcessedCommitVersion` — and -even simpler since `PipelineProgress` does not refer to Delta commit -versions specifically). Or unify on `lastProcessedCommitVersion`. **Flag for -upstream and port-time fix.** - ---- - -### 16. `PipelineProgress.syncedRowCount` / `totalRowCount` / `syncProgressCompletion` mixed nouns — category 17 (Inconsistent action verbs) and category 8 (Redundant suffixes) - -**Symbols:** `PipelineProgress.syncedRowCount` (model.ts:209), -`PipelineProgress.totalRowCount` (model.ts:211), -`PipelineProgress.syncProgressCompletion` (model.ts:213). - -**Issue:** Three fields about the progress of a sync: - -- `syncedRowCount` — past participle "synced" + noun "rowCount". OK. -- `totalRowCount` — adjective "total" + noun "rowCount". OK. -- `syncProgressCompletion` — noun "sync" + noun "progress" + noun - "completion". Triple nominalisation. The JSDoc says "The completion ratio - of this update. This is a number between 0 and 1." — so the field is the - *ratio* or *fraction* of completion. - -`syncProgressCompletion` is verbose. A consumer would write: -```ts -const pct = progress.syncProgressCompletion! * 100; -``` -when `progress.completion` or `progress.completionRatio` would read the -same. - -**Suggested:** `completionRatio` (matches the unit) or `progress` (matches -the parent type name `PipelineProgress` — though circular). -`completionRatio` is the clearer pick. Alternative: model as a percentage -(0–100) and call it `percentComplete`. +Rescanned against the 2026-05-26 regeneration (#156): no findings were +addressed by the regeneration — every previously open finding is still +present in the current source. --- - -### 17. `PipelineProgress.estimatedCompletionTimeSeconds` unit-suffix is fine — *pass* - -**Symbol:** `PipelineProgress.estimatedCompletionTimeSeconds` (model.ts:215). - -`…Seconds` unit suffix is the right move when the field is a raw number. -TypeScript has no unit type system. **Pass.** - -(One nit: `estimatedTimeRemainingSeconds` or `secondsUntilComplete` would -read more naturally — "estimatedCompletionTimeSeconds" parses as "estimated -completion-time, in seconds" which is the same. But this is a stylistic -preference. **Pass.**) - ---- - -### 18. `OnlineTableSpec.sourceTableFullName` — category 8 (Redundant suffixes) and category 19 (Underspecified IDs) — see finding 8 - -**Symbol:** `OnlineTableSpec.sourceTableFullName?: string | undefined` -(model.ts:156). - -Already covered in finding 8. **Pass with note** — `Full` qualifier is -redundant when JSDoc already specifies "Three-part (catalog, schema, table) -name". `sourceTableName` would suffice. Cross-reference -`featurestore.PublishTableRequest.sourceTableName` (no `Full`). - ---- - -### 19. `OnlineTableSpec.timeseriesKey` vs `OnlineTableSpec.primaryKeyColumns` (singular vs plural) — category 9 (Singular/plural mismatch) - -**Symbols:** `OnlineTableSpec.primaryKeyColumns?: string[]` (model.ts:158), -`OnlineTableSpec.timeseriesKey?: string` (model.ts:160). - -**Issue:** Plural array vs. singular scalar — the names match the shapes: -plural noun for the array, singular noun for the scalar. The mismatch is -semantic: a *primary key* in databases is typically one composite key over -multiple columns; here it is modelled as an array (which is fine, the array -*is* the composite key). A *timeseries key* is one column. So the naming is -consistent with the semantics. - -However, the JSDoc on `timeseriesKey` (model.ts:159) says "Time series key -to deduplicate (tie-break) rows with the same primary key." — it does not -specify whether it accepts multi-column or single-column. Treat as -single-column scalar. - -**Pass** with a JSDoc note (state explicitly "single column name"). - ---- - -### 20. `OnlineTableSpec.performFullCopy` is a verb-as-field — category 13 (Verb-tense inconsistency) and category 6 (Misleading names) - -**Symbol:** `OnlineTableSpec.performFullCopy?: boolean | undefined` -(model.ts:169). - -**Issue:** Boolean fields typically use `is…`, `has…`, `…Enabled`, or -`enable…` prefixes. `performFullCopy` reads as a *command* — "perform a full -copy" — rather than a *state*. Compare to the family of booleans in -`database/v1` (`enableReadableSecondaries`, `enablePgNativeLogin`, -`stopped`) — `enable…` is the dominant pattern. - -The JSDoc is also long (model.ts:161–168), but the field name itself reads -imperatively. **Suggested:** `fullCopyOnly` or `enableFullCopy` (matches the -SDK-wide `enable*` boolean pattern). Cross-reference -`database.DatabaseInstance.enableReadableSecondaries` for the pattern. - ---- - -### 21. `OnlineTableSpec.pipelineId` is server-generated — category 6 (Misleading names) — *pass with note* - -**Symbol:** `OnlineTableSpec.pipelineId?: string | undefined` (model.ts:171). -JSDoc: "ID of the associated pipeline. Generated by the server - cannot be -set by the caller." - -**Issue:** The field appears in the request *spec* but the JSDoc says it is -output-only. Mixing input/output in the same struct is a wire-level -decision; the JSDoc captures the asymmetry. TS does not yet have a clean -way to model output-only fields in input types (e.g. `Readonly<…>` is -declarative not runtime-enforced). - -**Pass** — naming is fine; the misleadingness is structural (mixed -input/output), not a naming bug. - ---- - -### 22. `OnlineTableSpec.schedulingPolicy` discriminated-union case names use verb prefixes — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) - -**Symbol:** `OnlineTableSpec.schedulingPolicy` $case literals -`'runContinuously'` / `'runTriggered'` (model.ts:145, 150). - -**Issue:** Each `$case` literal is a verb phrase: `runContinuously` (verb + -adverb), `runTriggered` (verb + past-participle). The verb-phrase form -mirrors the wire field names `run_continuously` / `run_triggered` — which -themselves model the operation ("run continuously vs. run triggered"). - -Reading code: -```ts -spec.schedulingPolicy = { $case: 'runContinuously', runContinuously: {} }; -// ^^^^^^^^^^^^^^^^^ -// verb phrase used as a literal key -``` - -**Suggested:** rename `$case` literals to noun-phrase form (`'continuous'` / -`'triggered'`). **Flag at port time.** - ---- - -### 23. `CreateOnlineTableRequest` and `GetOnlineTableRequest` and `DeleteOnlineTableRequest` repeat `OnlineTable` — category 7 (Overly verbose) — *pass, SDK-wide pattern* - -**Symbols:** `CreateOnlineTableRequest`, `DeleteOnlineTableRequest`, -`GetOnlineTableRequest` (model.ts:87, 93, 117). - -The Request/Response type names follow the SDK convention -`{Action}{Resource}Request`. Within the package scope `CreateRequest` / -`DeleteRequest` would suffice (only one resource), but every other TS -package qualifies. **Pass on package consistency.** - ---- - -### 24. `Client` class name — category 1 (Vague/generic) — *pass* - -Package convention. Every TS package exports a single `Client` class scoped -to its import path (e.g. `@databricks/sdk-onlinetables/v1.Client`). **Pass.** - ---- - -### 25. `Client.createOnlineTable` etc. — *pass* - -**Symbols:** `Client.createOnlineTable` (client.ts:67), -`Client.deleteOnlineTable` (client.ts:108), `Client.getOnlineTable` -(client.ts:127). - -Standard `{verb}{Resource}` method names. **Pass on style.** The -`OnlineTable` repetition (inside `@databricks/sdk-onlinetables/v1`) is -SDK-wide convention. **Pass.** - -(Cross-package note: `featurestore.deleteOnlineTable` and -`onlinetables.deleteOnlineTable` collide — see `featurestore.md` finding 22. -**Not a per-package fix.**) - ---- - -### 26. `Client.createOnlineTableWaiter` returns a `CreateOnlineTableWaiter` — category 14 (Go/Java-style names) - -**Symbol:** `Client.createOnlineTableWaiter` (client.ts:92), returns -`CreateOnlineTableWaiter` (client.ts:152). - -**Issue:** The Go SDK uses `…AndWait()` or `XXXWaiter()` methods; the JS -SDK port mirrors this. In TS, the canonical pattern would be a -`waitForCreation()` or `createAndWait()` method, possibly with a fluent -poller object. The current shape returns a `Waiter` object which the caller -must then call `.wait()` on. The double-step (`createOnlineTableWaiter` → -`.wait()`) is awkward — neither is the final operation. Compare to -`database.CreateDatabaseInstanceWaiter` (audited in `database.md` finding -14). - -Class name `CreateOnlineTableWaiter` is a verb-noun composite: -"the create-online-table waiter" — i.e. a waiter for the create operation. -Reads ambiguously: a waiter that creates? A waiter for creation? **Suggest** -`OnlineTableCreationWaiter` or `OnlineTablePoller`. **Flag for SDK-wide -waiter naming policy.** - -**Pass per project convention,** flag for SDK-wide cleanup. - ---- - -### 27. `CreateOnlineTableWaiter.wait` and `CreateOnlineTableWaiter.done` — *pass* - -**Symbols:** `CreateOnlineTableWaiter.wait` (client.ts:163), -`CreateOnlineTableWaiter.done` (client.ts:207). - -Standard. **Pass.** - ---- - -### 28. `StillRunningError` class is internal but module-scoped — *pass* - -**Symbol:** `class StillRunningError extends Error {}` (client.ts:39). - -Not exported. Named meaningfully ("the operation is still running, so -retry"). **Pass.** - ---- - -### 29. `host` / `httpClient` / `logger` / `userAgent` private fields — *pass* - -**Symbols:** Private fields on `Client` (client.ts:42–48). Acronym handling -matches the project rule (`HttpClient`, `Url` would be flagged, but -`HttpClient` matches the imported type). **Pass.** - ---- - -### 30. `PACKAGE_SEGMENT` constant SCREAMING_SNAKE — category 4 - -**Symbol:** `PACKAGE_SEGMENT` (client.ts:34). - -**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true -constants (primitive literal values like `MAX_LEN = 10`). `PACKAGE_SEGMENT` -is a runtime object literal (`{ key, value }`) constructed from a JSON -import. The value *is* constant per-process, but the identifier shape -violates the project rule. The same name is used in every package's -`client.ts` — project-wide convention. - -**Suggested:** `packageSegment` or `clientPackageSegment`. **Flag for -SDK-wide cleanup**, do not fix in isolation. - ---- - -### 31. Comment on `PACKAGE_SEGMENT` is a sentence-fragment in lowercase — category 14 (Go/Java-style names) — *pass* - -The JSDoc comment at client.ts:33 ("Package identity segment for this client -to be used in the User-Agent header.") is fine — proper sentence, ends with -a period (matches `.agent/rules` / user CLAUDE.md style). - ---- - -### 32. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) - -**Symbol:** `HttpCallOptions` interface (utils.ts:15). - -**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; the -neighbouring `CallOptions` exists in `@databricks/sdk-options/call`. Naming -both *in the same file* (`HttpCallOptions` here, `CallOptions` imported on -line 12) confuses readers — which "Call" do they mean? **Suggest** -`HttpRequestContext` or `ExecuteHttpArgs`. **Flag for SDK-wide cleanup** -(this `utils.ts` is generated boilerplate copied across every package, so -any fix must apply everywhere). - ---- - -### 33. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) - -**Symbols:** `executeCall` (utils.ts:26) and `executeHttpCall` (utils.ts:65). - -**Issue:** Two functions named `execute…Call`. `executeCall` is a wrapper -that adapts public `CallOptions` to internal `Options` and calls `execute()` -from `@databricks/sdk-core/api`. `executeHttpCall` performs an HTTP request -and decodes the body. They do *different* things at *different* layers; the -names imply a hierarchical relationship that does not exist. The HTTP one -is roughly `sendAndDecode` or `doHttpRequest`. **Flag for SDK-wide cleanup;** -this file is generated boilerplate copied across every package. - ---- - -## Cross-package alignment recommendations - -### A. `OnlineTable` ↔ `SyncedTable` duplication - -`onlinetables` and `database`/`postgres` model the same underlying concept -(a managed continuously-sync table from a Delta source to a backing -store) under two type families. Cross-package collisions in this audit: - -| `onlinetables` (this pkg) | `database` / `postgres` | -| ---------------------------------- | --------------------------------------------- | -| `OnlineTable` | `SyncedDatabaseTable` / `SyncedTable` | -| `OnlineTableSpec` | `SyncedTableSpec` | -| `OnlineTableState` | `SyncedTableState` (12 values, wire-typo) | -| `OnlineTableStatus` | `SyncedTableStatus` | -| `ContinuousUpdateStatus` | `SyncedTableContinuousUpdateStatus` | -| `TriggeredUpdateStatus` | `SyncedTableTriggeredUpdateStatus` | -| `FailedStatus` | `SyncedTableFailedStatus` | -| `ProvisioningStatus` | `SyncedTableProvisioningStatus` | -| `PipelineProgress` | `SyncedTablePipelineProgress` | -| `ProvisioningInfo` (empty) | `ProvisioningInfo` (empty) | - -This is the highest-cost duplication observed in the audit. **Strong P0 -recommendation:** consolidate. Options: - -1. **Pick one canonical package** (`onlinetables` is the shorter, cleaner - surface — no `SyncedTable` prefix, no wire-string typos). Have - `database` re-export from `onlinetables` with deprecation notes. -2. **Hoist all `Online/Synced{Table…}` types** into - `@databricks/sdk-core/synctables` (or similar) and re-export from both - service packages. - -**Coordinate with SDK platform team.** - ---- - -### B. `DeleteOnlineTableRequest` field-name divergence - -`onlinetables.DeleteOnlineTableRequest.name` vs. -`featurestore.DeleteOnlineTableRequest.onlineTableName`. Already covered in -finding 6. Harmonise on `name`. - ---- - -### C. `SYNCED_TABLED_OFFLINE` wire-level typo - -`database.SyncedTableState` includes the value `SYNCED_TABLED_OFFLINE` -(extra `D`). This is on the wire and locks consumers into the misspelling. -Coordinate a protocol-level fix with the API team; the SDK alone cannot -correct it without breaking compatibility. **Flag for protocol team.** - ---- - -## Counts by severity - -| Severity | Count | Findings | -| -------- | ----- | -------- | -| **High** (style guide violations, cross-package collisions) | 4 | #1, #6, #12, #20, #30, **and** cross-package A | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 10 | #2, #3, #4, #7, #8, #9, #10, #11, #14, #15, #16, #18, #22 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 9 | #4, #5, #13, #19, #21, #23, #26, #32, #33 | -| **Pass / acceptable** | 9 | #13, #17, #19, #21, #23, #24, #25, #27, #28, #29, #31 | - ---- - -## Top fixes (highest local return) - -1. **#6** — harmonise `DeleteOnlineTableRequest.name` vs. - `featurestore.DeleteOnlineTableRequest.onlineTableName` field name. Quick - cross-package fix. -2. **#9** — rename `OnlineTable.tableServingUrl` → `servingUrl`. Local, - no other consumers. -3. **#10** — rename `OnlineTable.unityCatalogProvisioningState` → - `provisioningState`. Local. -4. **#7** — rename `CreateOnlineTableRequest.table` → `onlineTable`. Local - port-time fix. -5. **#12** — rename `OnlineTableStatus.detailedState` → `state` and - `detailedStatus` → `statusDetails` / `details`. Local readability win. -6. **#15** — rename `PipelineProgress.latestVersionCurrentlyProcessing` → - `lastProcessedVersion`. Matches sibling `lastProcessedCommitVersion`. -7. **#16** — rename `PipelineProgress.syncProgressCompletion` → - `completionRatio`. Local. -8. **#20** — rename `OnlineTableSpec.performFullCopy` → `enableFullCopy` - (matches SDK `enable*` boolean pattern). - ---- - -## Top fixes (SDK-wide) - -1. **Cross-package A** — consolidate `OnlineTable` vs `SyncedTable` type - families into one canonical surface. -2. **Cross-package C** — fix the `SYNCED_TABLED_OFFLINE` wire-string typo - at the protocol layer. -3. **#1** — `UpperCamelCase` enum members (string value preserved as wire - form). -4. **#30** — `PACKAGE_SEGMENT` → `packageSegment`. -5. **#26** — settle waiter naming convention (`*Waiter` vs `*Poller` vs - inline `*AndWait`). diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md index 37487f24..ed3dbc7c 100644 --- a/.agent/naming-audit/permissions.md +++ b/.agent/naming-audit/permissions.md @@ -233,14 +233,3 @@ Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods - **Category:** Observation. --- - -## Fixed - -- #1 `GetObjectPermissions` (originally cited at `src/v1/model.ts:79`): Fixed in regeneration on 2026-05-20 — renamed to `GetObjectPermissionsRequest` (now `accessmanagement/src/v1/model.ts:154`), eliminating the verb-shaped type. -- #2 `SetObjectPermissions` (originally cited at `src/v1/model.ts:115`): Fixed in regeneration on 2026-05-20 — renamed to `SetObjectPermissionsRequest` (now `accessmanagement/src/v1/model.ts:338`), eliminating the verb-shaped type. -- #3 `UpdateObjectPermissions` (originally cited at `src/v1/model.ts:123`): Fixed in regeneration on 2026-05-20 — renamed to `UpdateObjectPermissionsRequest` (now `accessmanagement/src/v1/model.ts:346`), eliminating the verb-shaped type. -- #4 `GetPermissionLevels` (originally cited at `src/v1/model.ts:86`): Fixed in regeneration on 2026-05-20 — renamed to `GetPermissionLevelsRequest` (now `accessmanagement/src/v1/model.ts:161`), eliminating the verb-shaped type. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index 94c8c3fb..d0e2c53b 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -5,20 +5,20 @@ **Inferred domain:** Lakeflow Declarative Pipelines (formerly Delta Live Tables / DLT) — create / clone / get / list / edit / delete pipelines, start / stop / list / get pipeline **updates** ("a run of a pipeline"), and a vast catalog of ingestion connectors (Salesforce, Workday, Outlook, Kafka, RabbitMQ, TikTok Ads, ServiceNow, Confluence, Jira, ...). The API was renamed multiple times (DLT → Spark Declarative Pipelines → Lakeflow Declarative Pipelines); branding leakage and acronyms are abundant. **Files audited:** -- `src/v2/model.ts` (~5,400 lines) — 26 enums, ~116 interfaces, marshal/unmarshal schemas. -- `src/v2/client.ts` (632 lines) — 12 RPC methods + 2 paginators + `StopWaiter`. +- `src/v2/model.ts` (~5,500 lines) — 26 enums, ~116 interfaces, marshal/unmarshal schemas. +- `src/v2/client.ts` (673 lines) — 12 RPC methods + 2 paginators + `StopWaiter`. - `src/v2/utils.ts` (150 lines) — generic HTTP/marshal helpers (no domain names). -- `src/v2/index.ts` (151 lines) — re-exports. +- `src/v2/index.ts` (154 lines) — re-exports. ## Summary | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------------------- | -| High | 16 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | -| Medium | 19 | Vague names, acronym casing, generic IDs, misleading enum values. | -| Low | 20 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| High | 14 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | +| Medium | 16 | Vague names, acronym casing, generic IDs, misleading enum values. | +| Low | 15 | Mild verbosity, plural mismatches, stylistic inconsistencies. | | Observations | 7 | Patterns spanning the whole file (branding history, proto-architectural leakage). | -| **Total** | **62** | | +| **Total** | **52** | | Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. @@ -27,25 +27,25 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## High ### H1. `Update` is a verb in every other Databricks SDK but the noun "pipeline run" here — pervasive overloading -- **Locations:** `model.ts:168` (`UpdateCause`), `model.ts:186` (`UpdateState`), `model.ts:855` (`GetUpdateRequest`), `model.ts:863` (`GetUpdateRequest_Response`), `model.ts:1374` (`ListUpdatesRequest`), `model.ts:1386` (`ListUpdatesRequest_Response`), `model.ts:2367` (`StartUpdateRequest`), `model.ts:2412` (`StartUpdateRequest_Response`), `model.ts:2500` (`UpdateInfo`), `model.ts:2544` (`UpdateStateInfo`), `client.ts:360` (`getUpdate`), `client.ts:445` (`listUpdates`), `client.ts:485` (`start`), plus every `updateId` field. +- **Locations:** `model.ts:168` (`UpdateCause`), `model.ts:186` (`UpdateState`), `model.ts:888` (`GetUpdateRequest`), `model.ts:896` (`GetUpdateRequest_Response`), `model.ts:1407` (`ListUpdatesRequest`), `model.ts:1419` (`ListUpdatesRequest_Response`), `model.ts:2400` (`StartUpdateRequest`), `model.ts:2445` (`StartUpdateRequest_Response`), `model.ts:2533` (`UpdateInfo`), `model.ts:2577` (`UpdateStateInfo`), `client.ts:386` (`getUpdate`), `client.ts:477` (`listUpdates`), `client.ts:520` (`start`), plus every `updateId` field. - **Category:** 1 (vague), 6 (misleading — rebrand history), 13 (verb/noun inconsistency), 17 (inconsistent action verbs). - **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdateRequest` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdateRequest` → `GetRunRequest`, `ListUpdatesRequest` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateStateInfo` → `RunSummary`, `updateId` → `runId`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. - **Rationale:** "Update" is the standard verb for `PUT`/`PATCH` (and `EditPipelineRequest` already takes that slot — the client method is `edit()`, but the HTTP verb is `PUT`). Every JS/TS developer expects `update()` to mean "mutate". The DLT product feature historically named the unit-of-execution "Update" but Databricks itself renamed the concept to **"Pipeline run"** when the product became Lakeflow Declarative Pipelines. The SDK is on the wrong side of the rebrand. The same problem ripples through `start()` (the method that "starts an update"), `getUpdate()`, and `listUpdates()`. This is the single most confusing name in the package. ### H2. `client.edit()` returns `EditPipelineRequest_Response` instead of `UpdatePipelineRequest_Response` — verb collision avoidance is leaking through -- **Locations:** `client.ts:243` (`edit`), `model.ts:622` (`EditPipelineRequest`), `model.ts:708` (`EditPipelineRequest_Response`). +- **Locations:** `client.ts:260` (`edit`), `model.ts:633` (`EditPipelineRequest`), `model.ts:730` (`EditPipelineRequest_Response`). - **Category:** 13 (verb-tense inconsistency: `Edit` vs `Update` vs `Modify`), 6 (misleading: HTTP verb is `PUT`). - **Suggestion:** Rename `EditPipelineRequest` → `UpdatePipelineRequest` and the client method `edit()` → `update()`. Then rename the "pipeline run" concept per H1 to free up the `Update` token. - **Rationale:** The package uses `Edit` only because the `Update` noun was burned by DLT history. Once H1 is applied, `edit()` should follow the standard `create()`/`update()`/`delete()` REST pattern used by every other SDK (`jobs`, `clusters`, `instancepools`, etc., all use `update()`). ### H3. `client.start()` is "start a pipeline update" — but it reads as "start a pipeline" -- **Location:** `client.ts:485`. +- **Location:** `client.ts:520`. - **Category:** 6 (misleading), 17 (inconsistent action verbs). - **Suggestion:** Rename `start(req: StartUpdateRequest)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. - **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipelineRequest)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. ### H4. `PipelinesJobRunAs` references `Job` from a `Pipelines` package -- **Location:** `model.ts:2147`. +- **Location:** `model.ts:2180`. - **Category:** 6 (misleading — `Job` is a separate Databricks product), 14 (Go-style). - **Suggestion:** Rename to `RunAs` or `PipelineRunAs`. Drop the `Job` token entirely — this type is not used by `@databricks/sdk-jobs`. - **Rationale:** `Job` belongs to the `jobs` API. A user reading `runAs: PipelinesJobRunAs` cannot tell whether the pipeline is associated with a job or just borrows the shape. The proto comment ("Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as.") confirms this is a pipeline-only concept. @@ -57,71 +57,59 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipelineRequest_Response`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. ### H6. `EditPipelineRequest` / `CreatePipelineRequest` / `ClonePipelineRequest` / `PipelineSpec` all duplicate 25 of the same fields -- **Locations:** `model.ts:336` (`ClonePipelineRequest`), `model.ts:479` (`CreatePipelineRequest`), `model.ts:622` (`EditPipelineRequest`), `model.ts:1783` (`PipelineSpec`). +- **Locations:** `model.ts:336` (`ClonePipelineRequest`), `model.ts:479` (`CreatePipelineRequest`), `model.ts:633` (`EditPipelineRequest`), `model.ts:1816` (`PipelineSpec`). - **Category:** 12 (duplicate concepts). - **Suggestion:** Extract `PipelineSpec` as the shared base and have `CreatePipelineRequest`, `EditPipelineRequest`, `ClonePipelineRequest` use TS intersection: `type CreatePipelineRequest = PipelineSpec & {allowDuplicateNames?: boolean; dryRun?: boolean; ...}`. - **Rationale:** Each of the four interfaces redeclares `id`, `name`, `storage`, `configuration`, `clusters`, `libraries`, `ingestionDefinition`, `gatewayDefinition`, `trigger`, `target`, `schema`, `filters`, `continuous`, `development`, `photon`, `edition`, `channel`, `catalog`, `notifications`, `serverless`, `deployment`, `restartWindow`, `budgetPolicyId`, `tags`, `eventLog`, `rootPath`, `environment`, `usagePolicyId`. Drift between the four is silent. -### H7. `Update` field names on `Origin` reference the "pipeline run" sense of Update — silent overloading -- **Locations:** `model.ts:1476` (`Origin.updateId`), `model.ts:2504` (`UpdateInfo.updateId`), `model.ts:2545` (`UpdateStateInfo.updateId`). -- **Category:** 19 (underspecified IDs), 1 (vague). -- **Suggestion:** Rename `updateId` → `runId` (paired with H1). Document that the wire JSON key is `update_id` for compatibility. -- **Rationale:** A field named `updateId` on `Origin` (event source) leaves "update of what?" unanswered. Users wonder if it refers to the last-modification timestamp. - -### H8. `client.events()` method name is too generic -- **Location:** `client.ts:272`. +### H7. `client.events()` method name is too generic +- **Location:** `client.ts:292`. - **Category:** 1 (vague), 17 (inconsistent action verbs — should be `listEvents`). - **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. - **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). -### H9. `client.list()` — too generic for the package's bare-`list` slot -- **Location:** `client.ts:385`. +### H8. `client.list()` — too generic for the package's bare-`list` slot +- **Location:** `client.ts:414`. - **Category:** 1 (vague), 17 (inconsistent verbs). - **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelinesRequest` and to disambiguate from `listUpdates`/`listEvents`. - **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelinesRequest`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. -### H10. `ScdType_ScdType` enum uses the cryptic acronym SCD +### H9. `ScdType_ScdType` enum uses the cryptic acronym SCD - **Locations:** `model.ts:268` (`ScdType_ScdType`), `index.ts:27`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). - **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). -### H11. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" +### H10. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" - **Location:** `model.ts:262`. - **Category:** 6 (misleading — references method `run` that does not exist; the method is `start`). - **Suggestion:** Fix JSDoc to reference `start()`. After H3, both will line up at `run()`. - **Rationale:** Currently the user reads "call `run`" and finds no `run()` method on `Client`. -### H12. `client.delete()` collides with JS `delete` keyword -- **Location:** `client.ts:206`. +### H11. `client.delete()` collides with JS `delete` keyword +- **Location:** `client.ts:220`. - **Category:** 10 (reserved-word collision). - **Suggestion:** Rename to `deletePipeline()`. Alternatively, `remove()`. - **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. -### H13. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +### H12. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity - **Location:** `model.ts:56`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. -### H14. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" +### H13. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" - **Location:** `model.ts:187` ("Update is waiting for previous update to finish."). - **Category:** 6 (misleading). - **Suggestion:** Doc rewrite (English) after H1: "Run is waiting for previous run to finish." - **Rationale:** Same as H1 — once `Update` is renamed to `Run`, every JSDoc that mentions "update" in this enum needs to follow. -### H15. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural -- **Locations:** `model.ts:1431`, plus all `notifications?: Notifications[]` field declarations. +### H14. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +- **Locations:** `model.ts:1464`, plus all `notifications?: Notifications[]` field declarations. - **Category:** 9 (singular/plural mismatch). - **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. - **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. -### H16. `connectorOptions` field-name reuses parent-type token (`ConnectorOptions.connectorOptions`) -- **Locations:** `model.ts:457-477` (interface `ConnectorOptions`), `model.ts:1056`, `model.ts:1078`. -- **Category:** 20 (type-suffix tautology), 12 (duplicate naming). -- **Suggestion:** Rename the outer interface to `ConnectorOptions` and the inner discriminator to `options` (or `payload`). Then `connectorOptions: {payload: {...}}` reads cleanly. -- **Rationale:** Currently `ConnectorOptions.connectorOptions.googleAdsOptions` requires four nested identifiers all containing "options". - --- ## Medium @@ -139,93 +127,77 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Rationale:** `DEPRECATED` is widely used as a TS/JSDoc tag for "do not use." Reading `maturityLevel: DEPRECATED` mis-suggests the EVENT is deprecated, not the schema field. ### M3. `EventLogSpec` — `Spec` suffix on a small config object -- **Location:** `model.ts:730`. +- **Location:** `model.ts:752`. - **Category:** 8 (redundant suffix). - **Suggestion:** `EventLogConfig` or just `EventLog`. The `Spec` suffix is overused (`PipelineSpec`, `RewindSpec`, `RewindDatasetSpec`, `EventLogSpec`, `IngestionPipelineDefinition_SchemaSpec`, `_TableSpec`, `_ReportSpec`). - **Rationale:** TS doesn't need `Spec` as a discriminator; the type's role is clear from its field name. ### M4. `Filters` — pluralized name for a 2-field struct -- **Location:** `model.ts:808-813`. +- **Location:** `model.ts:830-835`. - **Category:** 9 (singular/plural mismatch), 1 (vague). - **Suggestion:** Rename to `PathFilter` (singular). The shape is `{include?: string[]; exclude?: string[]}`. ### M5. `PathPattern` field is `include: string` (singular, no array) but it represents a glob -- **Location:** `model.ts:1568-1571`. +- **Location:** `model.ts:1601-1604`. - **Category:** 15 (generic field names), 6 (misleading). - **Suggestion:** Rename type to `GlobPattern` and field to `pattern`. JSDoc says "The source code to include for pipelines" — `pattern` describes the *what*, `include` describes the *intent*. ### M6. `Origin` — too generic for "event source metadata" -- **Location:** `model.ts:1462`. +- **Location:** `model.ts:1495`. - **Category:** 1 (vague). - **Suggestion:** Rename to `EventOrigin` or `EventSource`. - **Rationale:** "Origin" is also a DOM type (`Window.origin`) and a CORS concept. Type contains many fields covering everything from cloud region to flow IDs. -### M7. `Origin.flowId` and `Origin.batchId` — IDs from unrelated subsystems -- **Locations:** `model.ts:1487` (`flowId`), `model.ts:1491` (`batchId`). -- **Category:** 19 (underspecified IDs). -- **Suggestion:** Document inline that `flowId` is "id of the streaming flow within the pipeline" and `batchId` is "id of a microbatch within a flow." Better: prefix as `streamingFlowId`, `microbatchId`. - -### M8. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type -- **Location:** `model.ts:988`. +### M7. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type +- **Location:** `model.ts:1021`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Move to `NetsuiteOptions` connector-specific type. - **Rationale:** A generic ingestion-definition type carrying a `netsuiteJarPath` field implies every other connector is incomplete. JSDoc literally says "Netsuite only configuration." Belongs in a per-connector options struct. -### M9. `IngestionSourceType.WORKDAY_RAAS` — undefined acronym +### M8. `IngestionSourceType.WORKDAY_RAAS` — undefined acronym - **Location:** `model.ts:67`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Document inline that RaaS = "Reports as a Service" (Workday terminology). The acronym is non-obvious. -### M10. `IngestionSourceType.GA4_RAW_DATA` — vendor-numbered identifier +### M9. `IngestionSourceType.GA4_RAW_DATA` — vendor-numbered identifier - **Location:** `model.ts:68`. - **Category:** 5. - **Suggestion:** Document inline that GA4 = "Google Analytics 4." -### M11. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator +### M10. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator - **Location:** `model.ts:80`. - **Category:** 1 (vague). - **Suggestion:** `UC_FOREIGN_CATALOG` or document inline. - **Rationale:** "Foreign Catalog" is a Unity Catalog concept; without context this looks like a country-of-origin enum value. -### M12. `Origin.ucResourceId` mixes acronym casing -- **Location:** `model.ts:1495`. +### M11. `Origin.ucResourceId` mixes acronym casing +- **Location:** `model.ts:1528`. - **Category:** 3 (acronym casing inconsistency). - **Suggestion:** Either `ucResourceId` (current) or `UCResourceId` — the Google TS style guide says treat acronyms as words, so `ucResourceId` is correct. But sibling fields use the same lowercase pattern (`workspaceId`, `pipelineId`), so this one is internally consistent. Flagged because it could be `unityCatalogResourceId` for clarity. -### M13. `eventType?: string` on `PipelineEvent` — string-typed enum -- **Location:** `model.ts:1732`. +### M12. `eventType?: string` on `PipelineEvent` — string-typed enum +- **Location:** `model.ts:1765`. - **Category:** 16 (field contradicts type domain). - **Suggestion:** Define an `EventType` enum (or union of string literals) and type the field with it. Right now consumers have no IDE help. - **Rationale:** JSDoc says "The event type. Should always correspond to the details." The Go SDK has the same field as string (porting fidelity), but TS could improve. -### M14. `PipelineEvent.timestamp: string` — typed string but holds an ISO date -- **Location:** `model.ts:1724`. +### M13. `PipelineEvent.timestamp: string` — typed string but holds an ISO date +- **Location:** `model.ts:1757`. - **Category:** 16. - **Suggestion:** Document the format in JSDoc, or use a `Date | string` union. -### M15. `RewindSpec.rewindTimestamp` — field prefixed with the type name -- **Location:** `model.ts:2277`. -- **Category:** 20 (type-suffix tautology). -- **Suggestion:** Drop the `rewind` prefix on fields inside `RewindSpec`: `timestamp`, `datasets`. - -### M16. `Sequencing` — singular noun for a 2-field record describing one event's position -- **Location:** `model.ts:2290`. +### M14. `Sequencing` — singular noun for a 2-field record describing one event's position +- **Location:** `model.ts:2323`. - **Category:** 1 (vague). - **Suggestion:** `EventSequence` or `EventPosition`. "Sequencing" is the action of putting in order, not the position itself. -### M17. `EditPipelineRequest.expectedLastModified: number` — wire is millis since epoch, but no JSDoc -- **Location:** `model.ts:632`. +### M15. `EditPipelineRequest.expectedLastModified: number` — wire is millis since epoch, but no JSDoc +- **Location:** `model.ts:643`. - **Category:** 16 (field contradicts type domain), 19 (underspecified ID). - **Suggestion:** Either type as `Date | number` or document "milliseconds since Unix epoch" in JSDoc. -### M18. `Sequencing.controlPlaneSeqNo` — abbreviated/cryptic identifier -- **Locations:** `model.ts:2290` (`Sequencing`), `model.ts:2294` (`controlPlaneSeqNo`). -- **Category:** 5 (cryptic abbreviations), 15 (generic field names). -- **Suggestion:** Rename to `controlPlaneSequenceNumber`. The JSDoc already calls it "A sequence number" — TS has no character budget. Sibling type `DataPlaneId.seqNo` (`model.ts:586`) has the same issue. -- **Rationale:** "SeqNo" is a Go/Java abbreviation. The wire JSON is `seq_no`, so the TS field rename is purely a surface improvement. - -### M19. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` -- **Location:** `model.ts:582`. +### M16. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` +- **Location:** `model.ts:593`. - **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). - **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. - **Rationale:** Every other `*Id` type in the SDK is a string. Reading `dataPlaneId: DataPlaneId` then accessing `dataPlaneId.seqNo` is jarring. @@ -235,101 +207,74 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## Low ### L1. `client.start()` JSDoc mentions "If there is already an active update" — should say "active run" -- **Location:** `client.ts:484`. +- **Location:** `client.ts:519`. - **Category:** 6. ### L2. `client.stop()` JSDoc mentions "Stops the pipeline by canceling the active update" — same -- **Location:** `client.ts:513`. +- **Location:** `client.ts:551`. ### L3. `client.list()` JSDoc says "Lists pipelines defined in the Spark Declarative Pipelines system" -- **Location:** `client.ts:384`. +- **Location:** `client.ts:413`. - **Category:** 6 (misleading), branding inconsistency. -- **Rationale:** The product is "Lakeflow Declarative Pipelines" per the IngestionPipelineDefinition JSDoc (`model.ts:932`). Internal naming: "Spark Declarative Pipelines" (SDP). Public marketing name: "Lakeflow Declarative Pipelines." The SDK uses both, sometimes in adjacent JSDoc. +- **Rationale:** The product is "Lakeflow Declarative Pipelines" per the IngestionPipelineDefinition JSDoc (`model.ts:965`). Internal naming: "Spark Declarative Pipelines" (SDP). Public marketing name: "Lakeflow Declarative Pipelines." The SDK uses both, sometimes in adjacent JSDoc. ### L4. JSDoc references to "SDP" appear in four fields, undefined -- **Locations:** `model.ts:379` (`ClonePipelineRequest.channel` — "SDP Release Channel"), `model.ts:516` (`CreatePipelineRequest.channel`), `model.ts:666` (`EditPipelineRequest.channel`), `model.ts:1816` (`PipelineSpec.channel`), `model.ts:2052` (`PipelinesEnvironment` — "SDP's environment"). +- **Locations:** `model.ts:379` (`ClonePipelineRequest.channel` — "SDP Release Channel"), `model.ts:521` (`CreatePipelineRequest.channel`), `model.ts:682` (`EditPipelineRequest.channel`), `model.ts:1849` (`PipelineSpec.channel`), `model.ts:2085` (`PipelinesEnvironment` — "SDP's environment"). - **Category:** 5 (cryptic abbreviation), 6 (misleading). - **Suggestion:** Expand SDP → "Spark Declarative Pipelines" on first mention, with parenthetical "(internal name for Lakeflow Declarative Pipelines)". -### L5. `PipelineLibrary.lib` field uses an abbreviation -- **Location:** `model.ts:1745`. -- **Category:** 5. -- **Suggestion:** Either `library` (matching `lib` but spelled out) or `source` (the discriminator). The current `lib` is a Go SDK shortening. - -### L6. `PipelinesS3StorageInfo.cannedAcl` — undocumented S3 jargon -- **Location:** `model.ts:2215`. +### L5. `PipelinesS3StorageInfo.cannedAcl` — undocumented S3 jargon +- **Location:** `model.ts:2248`. - **Category:** 5. - **Suggestion:** Document inline: "canned ACL = a predefined S3 access-control list, e.g., `bucket-owner-full-control`." Currently the field name is fine since it matches the S3 API; only the casing (`cannedAcl` not `cannedAcl` — should be `cannedACL` per Google TS style? actually `cannedAcl` is correct). -### L7. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent -- **Location:** `model.ts:2205`. +### L6. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent +- **Location:** `model.ts:2238`. - **Category:** 3. - **Suggestion:** `kmsKey` is the correct casing per Google TS style. Just flagging for cross-check with other AWS fields in the file. -### L8. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system -- **Locations:** `model.ts:2198`, `model.ts:2203`. +### L7. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system +- **Locations:** `model.ts:2231`, `model.ts:2236`. - **Category:** 16. - **Suggestion:** Use a discriminated union: `encryption?: {kind: 'none'} | {kind: 'sse-s3'} | {kind: 'sse-kms'; key: string}`. -### L9. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" -- **Location:** `model.ts:1575`. +### L8. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" +- **Location:** `model.ts:1608`. - **Category:** 16. - **Suggestion:** Make this an enum `ClusterLabel.{Default, Maintenance}`. -### L10. `PipelineCluster.applyPolicyDefaultValues` JSDoc says "won't be persisted" — should be marked deprecated or transient -- **Location:** `model.ts:1577`. +### L9. `PipelineCluster.applyPolicyDefaultValues` JSDoc says "won't be persisted" — should be marked deprecated or transient +- **Location:** `model.ts:1610`. - **Category:** 6. - **Suggestion:** Add `@deprecated` JSDoc tag. -### L11. `Truncation_TruncationDetail.fieldName: string` — looks like a meta field but is the data -- **Location:** `model.ts:2497`. -- **Category:** 6 (mildly misleading). -- **Suggestion:** `truncatedFieldName` or rename type to `TruncatedField`. - -### L12. `JsonTransformerOptions.asVariant: boolean` — boolean named with prefix `as` -- **Location:** `model.ts:1225`. -- **Category:** 17 (inconsistent boolean naming). -- **Suggestion:** Rename to `parseAsVariant` or `parseAsVariantColumn`. -- **Rationale:** Other boolean fields in the file use `is*`/`enable*`/`has*` (`development`, `serverless`, `photon`, `continuous`, `enableEncryption`, `enabled`, `inferColumnTypes`, `readerCaseSensitive`, `ignoreCorruptFiles`, `fatal`, `force`, `cascade`, `dryRun`, `incremental`). - -### L13. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc +### L10. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc - **Location:** `model.ts:333`. - **Category:** Generator artifact leakage. - **Suggestion:** Express via TS optionality (`?:`) instead of repeating "Optional" in JSDoc. -### L14. `(Required, Immutable)` / `(Optional, Mutable)` proto tags appear in many JSDoc blocks +### L11. `(Required, Immutable)` / `(Optional, Mutable)` proto tags appear in many JSDoc blocks - **Locations:** searches: `(Required`, `(Optional` throughout `model.ts` (currently ~53 occurrences). - **Category:** Generator artifact leakage. - **Suggestion:** Remove or move to a structured `@required` / `@mutable` tag. -### L15. `Origin.host` — generic field on an event source struct -- **Location:** `model.ts:1497`. -- **Category:** 15 (generic field name). -- **Suggestion:** `originHostname` or document inline. - -### L16. `RewindDatasetSpec.identifier: string` — generic when `datasetName` would do -- **Location:** `model.ts:2264`. -- **Category:** 15. -- **Suggestion:** `datasetIdentifier` or `fullyQualifiedName`. -- **Rationale:** JSDoc says "The identifier of the dataset (e.g., 'main.foo.tbl1')" — this is a UC three-part name. - -### L17. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link -- **Locations:** `model.ts:2266` (`cascade`), `model.ts:2268` (`resetCheckpoints`). +### L12. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link +- **Locations:** `model.ts:2299` (`cascade`), `model.ts:2301` (`resetCheckpoints`). - **Category:** 16. - **Suggestion:** Group into an `options` substruct or document interactions in JSDoc. -### L18. `KafkaOptions.startingOffset: string` — typed string but documented as enum -- **Location:** `model.ts:1261`. +### L13. `KafkaOptions.startingOffset: string` — typed string but documented as enum +- **Location:** `model.ts:1294`. - **Category:** 16. - **Suggestion:** Define `KafkaStartingOffset.{Latest, Earliest}` enum. -### L19. `MetaMarketingOptions.level: string` — typed string but documented as enum -- **Location:** `model.ts:1403`. +### L14. `MetaMarketingOptions.level: string` — typed string but documented as enum +- **Location:** `model.ts:1436`. - **Category:** 16. - **Suggestion:** Define `MetaAggregationLevel.{Account, Ad, AdSet, Campaign}` enum. -### L20. `MetaMarketingOptions.actionReportTime: string` — string enum -- **Location:** `model.ts:1409`. +### L15. `MetaMarketingOptions.actionReportTime: string` — string enum +- **Location:** `model.ts:1442`. - **Category:** 16. - **Suggestion:** Define enum. @@ -339,7 +284,7 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ### O1. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into several abbreviations across the public API - **Search:** `DLT`, `SDP`, `LDP`, `Lakeflow`, `Spark Declarative Pipelines`, `Delta Live Tables`, `DAB`. -- **Locations:** `model.ts:47` (`DAB` in DeploymentKind comment), `model.ts:379` (`SDP` in `channel` JSDoc), `model.ts:923` (`Spark Declarative Pipelines` in JSDoc), `model.ts:932` (`Lakeflow Connect`), `model.ts:2052` (`SDP's environment`), `client.ts:384` (`Spark Declarative Pipelines`). +- **Locations:** `model.ts:47` (`DAB` in DeploymentKind comment), `model.ts:379` (`SDP` in `channel` JSDoc), `model.ts:956` (`Spark Declarative Pipelines` in JSDoc), `model.ts:965` (`Lakeflow Connect`), `model.ts:2085` (`SDP's environment`), `client.ts:413` (`Spark Declarative Pipelines`). - **Suggestion:** Settle on one product name in JSDoc. The TS types should be backwards-compatible (no rename) but the docstrings should agree. ### O2. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested @@ -351,12 +296,12 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Suggestion:** Replace with literal "Databricks" before TS compilation. ### O4. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` -- **Location:** `model.ts:1443`. +- **Location:** `model.ts:1476`. - **Category:** 16. - **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. ### O5. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side -- **Locations:** `model.ts:1513-1566`. +- **Locations:** `model.ts:1546-1599`. - **Category:** Generator artifact / Go-SDK fidelity issue. - **Suggestion:** Mark deprecated fields with `@deprecated` JSDoc tag (currently only mentioned in plain text). @@ -368,27 +313,10 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Rationale:** TypeScript developers do not know what a "wrapper message" is — the term reveals the proto IDL underneath. The shape is just a discriminated union over connector option types; describe it in TS terms. ### O7. `Internal` proto-field tag leaks into JSDoc on two public fields -- **Locations:** `model.ts:926` (`IngestionGatewayPipelineDefinition.connectionParameters` — "Optional, Internal. Parameters required to establish an initial connection with the source."), `model.ts:1262` (`KafkaOptions.maxOffsetsPerTrigger` — "Internal option to control the maximum number of offsets to process per trigger."). +- **Locations:** `model.ts:959` (`IngestionGatewayPipelineDefinition.connectionParameters` — "Optional, Internal. Parameters required to establish an initial connection with the source."), `model.ts:1295` (`KafkaOptions.maxOffsetsPerTrigger` — "Internal option to control the maximum number of offsets to process per trigger."). - **Why:** `Internal` is a proto-level annotation (`google.api.field_visibility = INTERNAL` or similar) indicating the field is not part of the public API surface. If these fields are truly internal, they should be stripped from the public SDK at generation time; if they are public, the "Internal" label should not appear in user-visible documentation. - **Category:** Generator artifact leakage / proto-architectural leak. - **Suggested:** Either remove these fields from the public SDK (preferred — they are marked internal) or drop the "Internal" qualifier from JSDoc and document the actual user-facing semantics. - **Rationale:** Users reading JSDoc see `Internal option to control...` and reasonably wonder why an internal field is in the public SDK. This is a generator-template concern (same pattern likely shows up in other packages) — surface in the cross-package summary. --- - -## Fixed - -- #H2 `EditPipeline` (originally cited at `model.ts:830`): Renamed to `EditPipelineRequest`. Reference updated in active H2. -- #H7 `EditPipeline`/`CreatePipeline`/`ClonePipeline` (originally cited at `model.ts:508`/`672`/`830`): Renamed to `*Request` variants. References updated in active H7. -- #H8 `Origin.graphId` (originally cited at `model.ts:1816`): Fixed in regeneration on 2026-05-20 — `graphId` field removed from `Origin`. -- #H12 `StorageMode` enum duplicate of `ScdType` (originally cited at `model.ts:263`): Fixed in regeneration on 2026-05-20 — `StorageMode` enum removed; only `ScdType_ScdType` remains. -- #H14 `client.delete()` reserved-word collision (originally cited at `client.ts:204`): Line updated; still present as H12. Sibling reference to `restorePipeline()` removed since the restore endpoint no longer exists. -- #H15 `client.restorePipeline()` (originally cited at `client.ts:475`): Fixed in regeneration on 2026-05-20 — `restorePipeline()` method and `RestorePipelineRequest` removed entirely from the package. -- #H16 `RestorePipelineRequest` suffix asymmetry (originally cited at `model.ts:2618`): Fixed in regeneration on 2026-05-20 — `Request` suffix added uniformly to every request DTO (`DeletePipelineRequest`, `GetPipelineRequest`, `ClonePipelineRequest`, `EditPipelineRequest`, `CreatePipelineRequest`, `StartUpdateRequest`, `StopPipelineRequest`, `ApplyEnvironmentRequest`, etc.); `RestorePipelineRequest` itself was deleted along with the restore endpoint. -- #H19 `StartUpdate.fullRefresh`/`refreshSelection`/`fullRefreshSelection`/`resetCheckpointSelection`/`refreshFlowSelection` (originally cited at `model.ts:2738-2780`): Fixed in regeneration on 2026-05-20 — `resetCheckpointSelection` and `refreshFlowSelection` fields removed; remaining three (`fullRefresh`, `refreshSelection`, `fullRefreshSelection`) reduced to the documented pattern. -- #H22 `PipelinesEnvironment` vs `IngestionPipelineDefinition` prefix split (originally cited at `model.ts:2382`/`1173`): Pruned per Workflow B — type-name prefix repeating the package name (`Pipelines*`) is treated as a generator-pattern issue, not fixed individually. -- #M11 `GoogleDriveOptions_GoogleDriveIngestionScope` (originally cited at `model.ts:372-379`): Fixed in regeneration on 2026-05-20 — enum removed; only `GoogleDriveOptions_GoogleDriveEntityType` remains. -- #M13 `PeriodicTrigger_TimeUnit` (originally cited at `model.ts:384`): Fixed in regeneration on 2026-05-20 — enum and parent type `PeriodicTrigger` removed. -- #M31 `IngestionSourceType.COMMUNITY` (originally cited at `model.ts:88-92`): Fixed in regeneration on 2026-05-20 — `COMMUNITY` value removed from `IngestionSourceType`. -- #M36 `RewindSpec.rewindPointId` (originally cited at `model.ts:2637-2655`): Fixed in regeneration on 2026-05-20 — `rewindPointId` field removed; remaining `rewindTimestamp` is now tracked as M31. -- #L18 `IngestionPipelineDefinition_TableSpec.enableAutoClustering` and `clusteringColumns` (originally cited at `model.ts:1426`/`1435`): Fixed in regeneration on 2026-05-20 — both fields removed from `IngestionPipelineDefinition_TableSpec`. diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index e1831b02..5eb2583e 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -81,11 +81,9 @@ The package defines no enums. | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| V-01 | `PolicyFamily.definition` (`model.ts:37`) | Medium | `definition` is generic in a multi-domain SDK. Without the JSDoc it is unclear whether this is a JSON document, a free-form string, or something else. Sibling field on the parent `clusterpolicies` package is `policyFamilyDefinitionOverrides` — so the convention within the SDK is `*Definition*`. `policyDefinition` would self-describe. (Codegen / API constraint.) | -| V-02 | `PolicyFamily.name` (`model.ts:33`) | Low | Generic but standard for entity types; meaning is preserved by the parent type. | -| V-03 | `PolicyFamily.description` (`model.ts:35`) | Low | Generic but standard across the SDK; acceptable. | -| V-04 | `GetPolicyFamilyRequest.version` (`model.ts:10`) | Medium | `version` is generic. The JSDoc says "version number for the family"; field could be `familyVersion` or `policyFamilyVersion` to make it self-describing when destructured (e.g. `const {version} = req` loses context). | -| V-05 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | +| V-01 | `PolicyFamily.name` (`model.ts:33`) | Low | Generic but standard for entity types; meaning is preserved by the parent type. | +| V-02 | `PolicyFamily.description` (`model.ts:35`) | Low | Generic but standard across the SDK; acceptable. | +| V-03 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | ### 2.2 Redundant enum prefixes — High @@ -160,8 +158,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | D-01 | `PolicyFamily.policyFamilyId` (here) and `Policy.policyFamilyId` (in `clusterpolicies`) | Low | The field name is consistent across packages — good. No duplication concern. | -| D-02 | `PolicyFamily.definition` vs `Policy.definition` / `Policy.policyFamilyDefinitionOverrides` (in `clusterpolicies`) | Medium | Three related "definition" concepts spread across two packages: `PolicyFamily.definition` (the canonical CPDL doc), `Policy.definition` (custom override), and `Policy.policyFamilyDefinitionOverrides` (delta). The current package has only one of the three, but the field name `definition` does not communicate which of the three roles it plays. Adding a JSDoc cross-link to the `clusterpolicies` `*Overrides` field would help; a rename to `policyDefinition` would align with the sibling field names. | -| D-03 | `PolicyFamily` vs `Policy` (cross-package) | Low | Distinct concepts: a `PolicyFamily` is a template, a `Policy` is an instance. Cross-package linking (JSDoc `{@link}`) would help readers understand the relationship. Out of scope for naming. | +| D-02 | `PolicyFamily` vs `Policy` (cross-package) | Low | Distinct concepts: a `PolicyFamily` is a template, a `Policy` is an instance. Cross-package linking (JSDoc `{@link}`) would help readers understand the relationship. Out of scope for naming. | ### 2.12 Verb-tense inconsistency — Low @@ -182,11 +179,9 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| F-01 | `version` (on `GetPolicyFamilyRequest`) | Medium | When destructured (`const {version} = req`) the meaning collapses to "some version number". Within the SDK there are also `Catalog.version`, `Volume.version`, `Schema.version` etc.; the field is overloaded in name space if not in scope. Renaming to `familyVersion` (or matching what the wire JSON key actually is — `version`) is a tradeoff between SDK-internal consistency and on-wire fidelity. Cf. V-04. | -| F-02 | `name` (on `PolicyFamily`) | Low | Universal noun; meaning is preserved through type context. OK. | -| F-03 | `description` (on `PolicyFamily`) | Low | Same as F-02. | -| F-04 | `definition` (on `PolicyFamily`) | Medium | See V-01 / D-02. Generic and overloaded — losing parent-type context makes it unclear whether this is JSON, YAML, or a free-form string. | -| F-05 | `url`, `params`, `query`, `fullUrl`, `headers`, `body` (locals in `client.ts`) | Low | Locals only; standard naming. OK. | +| F-01 | `name` (on `PolicyFamily`) | Low | Universal noun; meaning is preserved through type context. OK. | +| F-02 | `description` (on `PolicyFamily`) | Low | Same as F-01. | +| F-03 | `url`, `params`, `query`, `fullUrl`, `headers`, `body` (locals in `client.ts`) | Low | Locals only; standard naming. OK. | ### 2.15 Field contradicting type domain — Low @@ -255,9 +250,9 @@ _None._ | Severity | Count | | -------- | ----- | | High | 2 | -| Medium | 11 | +| Medium | 6 | | Low | 28 | -| **Total**| **41**| +| **Total**| **36**| ### 3.2 Top themes @@ -267,19 +262,17 @@ _None._ issues are repo-wide patterns (the bare `Client` class name) rather than per-package mistakes. -2. **`definition` and `version` are over-generic on a generic entity.** - `PolicyFamily.definition` and `GetPolicyFamilyRequest.version` are the two - fields whose meaning is best inferred from the JSDoc rather than from - the field name itself. Renaming to `policyDefinition` / - `familyVersion` (or `policyFamilyVersion`) would self-describe. +2. **Proto-architectural leak in response type name.** + `ListPolicyFamiliesRequest_Response` (and the matching + `unmarshalListPolicyFamiliesRequest_ResponseSchema`) carry the + proto-nested `Request_Response` compound suffix into idiomatic TS. The + `Request` token mid-name is meaningless on a response type and forces an + `eslint-disable` for the naming-convention rule. ### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) -- Rename `PolicyFamily.definition` → `policyDefinition` (matches the - sibling field `policyFamilyDefinitionOverrides` in the - `clusterpolicies` package). - Fix the JSDoc on `getPolicyFamily()` ("an policy family" → "a policy family") and on `listPolicyFamilies()` ("policy definition types" → "policy families"). @@ -294,13 +287,5 @@ codegen owners) rename to `Client` would help all packages. - `PolicyFamily.policyFamilyId` matches `Policy.policyFamilyId` in the `clusterpolicies` package — cross-package field naming is consistent. -- `PolicyFamily.definition` does **not** match the more-qualified - `Policy.policyFamilyDefinitionOverrides` — partial inconsistency, - but defensible since the override is a delta and the canonical - definition lives on the family. --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index 4cf5151e..2e9150c4 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -3,14 +3,14 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Catalog`s (Unity Catalog mirrors of logical PG databases), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Operation` waiter-style classes. -**Total weird names flagged:** 53 +**Total weird names flagged:** 33 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 31 | -| Low | 11 | +| Medium | 16 | +| Low | 6 | | Observation | 2 | ## High severity @@ -85,304 +85,147 @@ - **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). - **Rationale:** With 100+ packages in the workspace, single-word resource names guarantee collisions. -### 11. `Branch.uid` / `Endpoint.uid` / `Project.uid` / `SyncedTable.uid` — bare `uid` fields, sometimes vs `name` — `src/v1/model.ts:695, 1186, 1609, 1892` -- **Why weird:** Same problem as `database` finding #19: two identifier-like fields. `name` is a resource path (`projects/{id}/branches/{id}`), `uid` is "System-generated unique ID". Caller can't tell which to pass to `getBranch` (answer: `name`). Bare `uid` is non-descriptive — what scope (project? branch? UC table?). -- **Category:** 19 (underspecified id), 1 (vague `uid`). -- **Suggested name:** `branchUid` / `endpointUid` / `projectUid` / `syncedTableUid` (and add docs). -- **Rationale:** Same as `database` audit #19. - -### 12. `Branch.name` / `Catalog.name` / etc. — `name` is a full resource path — `src/v1/model.ts:693, 816, 1018, 1184, 1607, 1771` -- **Why weird:** Field is `name?: string` but the doc constrains it to a multi-segment path like `projects/{project_id}/branches/{branch_id}`. There is a separate `branchId` / `catalogId` / `databaseId` / `endpointId` / `projectId` / `roleId` field in each status sub-type. Caller has to read JSDoc to know which to use. -- **Category:** 1 (vague), 19 (underspecified id), 6 (misleading — `name` reads as a human-readable name, actually a resource path). -- **Suggested name:** `resourceName` / `fullName` / `resourcePath` for the path-style field; keep the short ID where present. -- **Rationale:** `name` is the most ambiguous field name possible. - -### 13. `Branch.parent` — string-typed parent path — `src/v1/model.ts:703` -- **Why weird:** `parent?: string` doc'd as "The project containing this branch (API resource hierarchy). Format: `projects/{project_id}`". Generic name; the type doesn't enforce the format. Same pattern repeats on `Database.parent` (1023), `Endpoint.parent` (1191), `Role.parent` (1776), `CreateBranchRequest.parent`, `CreateDatabaseRequest.parent`, etc. -- **Category:** 1 (vague), 15 (generic), 19 (underspecified — what kind of parent?). -- **Suggested name:** `projectName` / `branchName` / specific to the parent type. Or `parentResourceName`. -- **Rationale:** Parents differ per child type; `parent` is too generic. - -### 14. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:736-762` +### 11. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:736-762` - **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. - **Category:** 16 (type allows `false` but spec rejects it). - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 15. `BranchStatus.default` — reserved-word collision — `src/v1/model.ts:776` -- **Why weird:** `BranchStatus.default: boolean | undefined` field clashes with the JS `default` keyword in `import { default } from …` contexts. While not a reserved word in object-property position, it's syntactically irritating and a JS lint hot spot. -- **Category:** 10 (reserved-word collision), 1 (vague — `default` of what?). -- **Suggested name:** `isDefault: boolean` (matches sibling `isProtected`). -- **Rationale:** `branch.default = true` reads weirdly; `branch.isDefault = true` aligns with `branch.isProtected`. - -### 16. `createDatabaseIfMissing` field on the catalog spec — `src/v1/model.ts:856` -- **Why weird:** Boolean named as a SQL clause (`CREATE DATABASE IF MISSING`). Same as `database` audit #31 (`createDatabaseIfNotExists`) but with the variant wording "If Missing". Inconsistent with `database` package's "If Not Exists". -- **Category:** 14 (SQL-style name), 7 (verbose), 17 (inconsistent with sister package's `createDatabaseIfNotExists`). -- **Suggested name:** `ensureDatabaseExists` or `autoCreateDatabase`. -- **Rationale:** Two packages, two variants of the same SQL-DDL leak. - -### 17. Every status sub-type duplicates the parent resource name on its id field — `src/v1/model.ts:797, 890, 1076, 1358, 1743, 1875` -- **Why weird:** Each status type has `Id` (`branchId`, `catalogId`, `databaseId`, `endpointId`, `projectId`, `roleId`) inside a status struct that already lives on the parent resource. Read site `catalog.status.catalogId` repeats "catalog" twice. JSDoc on every field is identical boilerplate: "The short identifier of the X, suitable for showing to the users." -- **Category:** 7 (verbose), 17 (boilerplate JSDoc), 20 (type-suffix tautology). -- **Suggested name:** `id: string` (the wrapping type name is already the resource). -- **Rationale:** `catalog.status.catalogId` is "catalog status catalog id" — verbose. - -### 18. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:907, 909` +### 12. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:907, 909` - **Why weird:** `CreateBranchRequest` has `parent`, `branchId`, `branch`, `replaceExisting`. `branchId` is the path-component id; `branch.name` (inside `Branch`) is the full resource path; `branch` is the body. Three fields all involved in identifying the branch. - **Category:** 17 (inconsistency — same operation, three id-like fields), 19 (underspecified id semantics). - **Suggested name:** Document the relationship clearly in JSDoc; or accept just `branch: Branch` and derive the id from `branch.name`. - **Rationale:** Same shape repeats on `CreateCatalogRequest`, `CreateDatabaseRequest`, `CreateEndpointRequest`, `CreateProjectRequest`, `CreateRoleRequest`, `CreateSyncedTableRequest`. Caller must read multiple field docs to know which ID to set. -### 19. `CreateBranchRequest.replaceExisting` / `CreateEndpointRequest.replaceExisting` — request-shaped name on a create call — `src/v1/model.ts:911, 959` -- **Why weird:** `replaceExisting?: boolean` on a `Create*` request is essentially "upsert mode". Doc: "If true, update the branch if it already exists instead of returning an error." Many SDKs call this `upsert: true` or `ifExists: 'update'`. Verb is also imperative on a request body. -- **Category:** 17 (inconsistent — `create` verb + `replaceExisting` flag conflate two operations), 1 (vague — "replace" how?). -- **Suggested name:** `upsert: boolean` or `mode: 'create' | 'upsert'`. -- **Rationale:** "Create-or-update" is a common API pattern that deserves a clearer name. - -### 20. `Database.parent` is a branch path, `Database.spec.role` is a role path, `Database.status.role` is *also* a role path — `src/v1/model.ts:1023, 1044, 1063` -- **Why weird:** Two `role` fields on the spec and status sub-structs, both holding full resource paths like `projects/{}/branches/{}/roles/{}`. `Database.spec.role` is the *desired owner role*; `Database.status.role` is the *observed owner role*. Doc clarifies but the field-name overlap is jarring. -- **Category:** 19 (underspecified id — `role` is actually a role resource path), 1 (vague — `role` could be many things). -- **Suggested name:** `ownerRole` or `ownerRoleName`. Use the same name on spec and status. -- **Rationale:** Inside a `Database` struct, a bare `role: string` reads as "what role does this database have" — but it's specifically the *owner* role. - -### 21. `postgresDatabase` field appears on both the database spec and status sub-types — `src/v1/model.ts:1054, 1065` -- **Why weird:** `Database.spec.postgresDatabase` and `Database.status.postgresDatabase` repeat "database" three times in one member access — the wrapper type is already `Database`. -- **Category:** 20 (type-suffix tautology), 7 (verbose). -- **Suggested name:** `pgName` / `pgIdentifier` or just `name` (with a JSDoc note: "matches the Postgres database identifier"). -- **Rationale:** Same as #17. - -### 22. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` +### 13. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` - **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. - **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). - **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). - **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. -### 23. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` +### 14. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` - **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. - **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). - **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. - **Rationale:** Three identifier slots is too many. -### 24. `DatabaseCredential.token: string` carries no doc on format — `src/v1/model.ts:1081` -- **Why weird:** "The OAuth token that can be used as a password when connecting to a database." Plain `string`. Sibling `expireTime: Temporal.Instant` does carry a type. The token doc doesn't say whether it's a JWT, opaque, format `:`, etc. Same issue exists in `database/v1.DatabaseCredential.token`. -- **Category:** 15 (generic field name), 1 (vague). -- **Suggested name:** `accessToken` (and document the format/lifetime in JSDoc). -- **Rationale:** Tokens carry semantics; consumers need to know the format. - -### 25. `Endpoint.endpointType` field of type `EndpointType` — `src/v1/model.ts:1272` -- **Why weird:** `endpoint.endpointType` is type-suffix tautology again: three "endpoint"s. The field of type `EndpointType` could just be `type` since the surrounding type is `Endpoint`. -- **Category:** 20 (type-suffix tautology), 7 (verbose). -- **Suggested name:** `type: EndpointType` (or `kind`). -- **Rationale:** Same as #17. - -### 26. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` +### 15. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` - **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. - **Category:** 5 (cryptic abbreviation), 1 (vague suffix). - **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. - **Rationale:** "CU" is Lakebase-internal slang. -### 27. `EndpointGroupSpec.min` / `max` with `min === max` constraint — `src/v1/model.ts:1207, 1213` -- **Why weird:** Two bare fields `min: number` / `max: number` (and `enableReadableSecondaries`) on a group spec. JSDoc says "Currently, this must be equal to max" — meaning callers must set min === max. Type system doesn't enforce; bare `min`/`max` doesn't suggest "group size". -- **Category:** 1 (vague), 16 (type contradicts spec — allows min ≠ max). -- **Suggested name:** `size: number` (until min ≠ max becomes supported, then introduce `minSize`/`maxSize`). -- **Rationale:** Pseudo-flexibility leaks proto future-proofing. - -### 28. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` -- **Why weird:** Same pattern as #14 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. -- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #14). +### 16. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` +- **Why weird:** Same pattern as #11 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. +- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #11). - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. -- **Rationale:** Same as #14. +- **Rationale:** Same as #11. -### 29. `EndpointSettings.pgSettings: Record` field — `src/v1/model.ts:1261` -- **Why weird:** `pgSettings` is a map of Postgres GUC settings (e.g. `{ work_mem: '4MB' }`). Generic value type `string`. No validation. Field name `pgSettings` is itself ambiguous — could be any kind of setting. -- **Category:** 14 (proto map-entry shape leaks into TS), 1 (vague — `pgSettings` could be any kind of setting). -- **Suggested name:** `postgresGucSettings: Record` (more specific). -- **Rationale:** Field name should encode the domain (Postgres GUC parameters). - -### 30. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #39 +### 17. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #25 _Reserved._ -### 31. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` +### 18. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` - **Why weird:** Plain `Record`. The 21 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1524-1533` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. - **Category:** 15 (generic), 16 (loose typing). - **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. - **Rationale:** Same root cause as #7 — opaque records on the public surface. -### 32. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` +### 19. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` - **Why weird:** Variant `response` carries `Record` (line 1597). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) - **Category:** 16 (asymmetric typing), 15 (generic on success arm). -- **Suggested name:** Same as #31 — generic `Operation` with both arms typed. -- **Rationale:** Same as #7, #31. +- **Suggested name:** Same as #18 — generic `Operation` with both arms typed. +- **Rationale:** Same as #7, #18. -### 33. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` +### 20. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` - **Why weird:** `Project` carries an `initialEndpointSpec` field that is a create-time-only input but exposed on the response type too — a read-flow consumer sees a field that is typically empty after project creation. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). - **Suggested name:** Hoist the `initialEndpointSpec` onto `CreateProjectRequest` only (where it belongs); leave `Project` to spec/status. - **Rationale:** Same as `database` audit #12 — input/output shape confusion. -### 34. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` +### 21. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` - **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. - **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). - **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. - **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. -### 35. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` +### 22. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` - **Why weird:** Doc says "The major Postgres version number. The set of supported versions may vary; consult the API documentation for currently accepted values." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. - **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). - **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. - **Rationale:** Aligns documented constraints with the type system. -### 36. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` +### 23. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` - **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. - **Category:** 17 (inconsistent with sister package). - **Suggested name:** Pick one convention across the two packages. - **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. -### 37. `ProjectSpec.enablePgNativeLogin` / `ProjectStatus.enablePgNativeLogin` — request-shaped verb on response — `src/v1/model.ts:1704, 1732` -- **Why weird:** Same problem as `database` audit #26: `enableX: boolean` reads as imperative on a response type. `ProjectStatus.enablePgNativeLogin` should read "is PG native login enabled". -- **Category:** 6 (misleading verb form), 17 (input/output asymmetry). -- **Suggested name:** Input: `enablePgNativeLogin`. Output: `pgNativeLoginEnabled`. -- **Rationale:** Same as `database` audit #26. - -### 38. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` +### 24. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` - **Why weird:** Same as `database` audit #36: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Same as `database` audit #36. -### 39. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` +### 25. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` - **Why weird:** Identical to `database` audit findings on synced-table-spec naming. Won't re-state at length; flag that the duplication exists across both packages with identical naming. Other related fields (`acceleratedSync`, `extraIndexDefinitions`, `extraColumnDefinitions`, `typeOverrides`) were removed during regeneration; only the `createDatabaseObjectsIfMissing` "If Missing" pattern remains here, matching `database` package's similar wording. - **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). - **Suggested name:** Same suggestions as `database` audit. - **Rationale:** Two SDKs, same problems. -### 40. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` +### 26. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` - **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. - **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). - **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. - **Rationale:** AIP `FieldMask` is an industry pattern, but it should not be the only update affordance. -### 41. `getOperation` / `Operation.name` — operation name is a resource path — `src/v1/client.ts:856`, `model.ts:1569` -- **Why weird:** `getOperation({name: ...})` takes a `string` that is actually a path like `operations/{unique_id}`. The doc on `Operation.name` says "If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`." But it doesn't validate. -- **Category:** 19 (underspecified id), 6 (misleading — `name` reads like a label). -- **Suggested name:** `operationResourceName` / `operationPath` / `id`. -- **Rationale:** Same as #12. - ## Low severity -### 42. `BranchSpec.sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` — `src/v1/model.ts:723, 725, 727` -- **Why weird:** Three sibling fields on `BranchSpec`. `sourceBranch` is a path; `sourceBranchLsn` and `sourceBranchTime` are alternative cutover specifiers (one or the other). Bare `branchTime` repeats from `database/v1.DatabaseInstanceRef.branchTime` (see `database` audit #29). -- **Category:** 1 (vague — `branchTime` is a cutover instant, not a time-of-branch). -- **Suggested name:** `sourceBranch` / `sourceBranchLsn` / `sourceBranchTime` are OK; consider `sourceBranchAtLsn` / `sourceBranchAtTime` for clarity. -- **Rationale:** Same as `database` audit #29. - -### 43. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:743, 788` +### 27. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:743, 788` - **Why weird:** Field name `expireTime` appears twice: once as a discriminated-union variant on `BranchSpec` (input), once as a top-level field on `BranchStatus` (output). Reader has to track that the input shape collapses `expireTime`/`ttl`/`noExpiry` to a single output value `expireTime`. - **Category:** 17 (input/output shape mismatch). - **Suggested name:** Document the asymmetry in JSDoc; or expose the same union shape on output. - **Rationale:** Generator-driven asymmetry. -### 44. `BranchSpec.ttl: Temporal.Duration` and `BranchSpec.expireTime` — `ttl` is a duration, `expireTime` is a timestamp — `src/v1/model.ts:751, 743` -- **Why weird:** `ttl` (time-to-live) and `expireTime` are sibling variants. `ttl` is duration-shaped; `expireTime` is timestamp-shaped. Bare `ttl` is a Unix-cache-style abbreviation. -- **Category:** 5 (cryptic abbreviation — `ttl`). -- **Suggested name:** `lifetime: Duration` or `expireAfter: Duration`. -- **Rationale:** `TTL` is widely understood but expansion improves grep-ability. - -### 45. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` +### 28. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` - **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete now uses `purge: boolean` only (`allowMissing` field removed in regeneration). Mismatched conventions for "if it does/doesn't exist" remain. - **Category:** 17 (inconsistent action verbs across CRUD). - **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. - **Rationale:** Inconsistent options across CRUD operations is a small papercut. -### 46. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` +### 29. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` - **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete." Same `purge` field on `DeleteProjectRequest` (line 1142). - **Category:** 16 (boolean modeling a future 3-state field), 6 (misleading — purge implies cleanup, not the *only* delete mode). - **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. - **Rationale:** Boolean toggle for a future-3-state field. -### 47. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` +### 30. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` - **Why weird:** Same as `database` audit #54 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Same as `database` audit #54 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. - **Rationale:** Same as `database` audit #54. -### 48. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` +### 31. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` - **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1552`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. - **Rationale:** Tri-state booleans always confuse callers. -### 49. `Project.deleteTime` / `Project.purgeTime` — two delete-related timestamps — `src/v1/model.ts:1629, 1634` -- **Why weird:** `deleteTime` = "when soft-deleted"; `purgeTime` = "when scheduled for permanent deletion". Bare verbs `delete` / `purge` are similar; the distinction matters for the consumer but the field names alone don't communicate the lifecycle. -- **Category:** 1 (vague), 6 (misleading — `purge` could mean "purged at" or "scheduled to purge"). -- **Suggested name:** `softDeletedAt` / `scheduledPurgeAt`. -- **Rationale:** Lifecycle-related fields benefit from clearer past/future tense. - -### 50. `ProjectStatus.syntheticStorageSizeBytes` — "synthetic" qualifier — `src/v1/model.ts:1724` -- **Why weird:** `syntheticStorageSizeBytes` — what's "synthetic" about storage? Doc says "The current space occupied by the project in storage." JSDoc doesn't explain "synthetic". Likely Lakebase internal billing concept. -- **Category:** 1 (vague), 14 (internal-jargon leak). -- **Suggested name:** `storageSizeBytes` or `billingStorageSizeBytes`. -- **Rationale:** Internal-jargon leak. - -### 51. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:734, 741, 749, 758, 1291, 1299, 1308, 1656, 1665` +### 32. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:734, 741, 749, 758, 1291, 1299, 1308, 1656, 1665` - **Why weird:** JSDoc references update mask in snake_case (e.g. "When updating this field, use `spec.expiration` in the update_mask"). Update mask field on the request is `updateMask: FieldMask<...>` (camelCase) but docs reference the wire-format name. Consumer reading the JSDoc and writing TS code has to translate. - **Category:** 17 (inconsistent — JSDoc snake_case, TS camelCase). - **Suggested name:** Use TS field name in JSDoc. - **Rationale:** Doc/code drift. -### 52. `ListBranchesRequest.showDeleted` / `ListProjectsRequest.showDeleted` — pair of duplicate optional flags — `src/v1/model.ts:1456, 1515` -- **Why weird:** Two structs carry identical `showDeleted?: boolean` with similar JSDoc. Not bad on its own, but the option name `showDeleted` is itself an imperative-shaped name on a request type (compare to `includeDeleted` or `deletedOnly`). -- **Category:** 1 (vague — `show` is presentation-layer language for a server request). -- **Suggested name:** `includeDeleted` or `includeSoftDeleted`. -- **Rationale:** Same as `database` audit #26 — request shapes prefer descriptive booleans over imperative ones. - ## Observation -### 53. Method JSDoc inconsistency — `src/v1/client.ts` throughout +### 33. Method JSDoc inconsistency — `src/v1/client.ts` throughout - **Why weird:** Some methods have rich JSDoc ("Creates a new database branch in the project.", "Register a Postgres database in the Unity Catalog."). Others are terse ("Create a Database.", "Get a Database.", "List Databases."). Inconsistency in doc depth across CRUD methods of the same resource. - **Category:** Observation (doc quality, not naming). - **Suggested name:** Standardise to the richer template. - **Rationale:** Naming-adjacent. -### 54. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` +### 34. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` - **Why weird:** All 21 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#8) or reads `Operation.result.response` (untyped `Record`). - **Category:** Observation (architecture, not naming per se). - **Suggested name:** `Operation` generic. -- **Rationale:** Connects #7, #8, #31, #32. - -## Fixed - -- #2 (original) `postgres` and `database` packages overlap heavily — _reduced_; many shared types removed in regeneration but a substantial duplicate set remains (kept as new #2). Original line numbers obsolete. -- #4 (original) Four "State" enums share value vocabulary but use three different qualifier patterns (originally cited at `src/v1/model.ts:581, 628, 599, 654`): Superseded into new #4 — `ComputeInstance_ComputeState` and `NewPipelineSpec_PipelineChannel` were removed in regeneration on 2026-05-20; only three state enums (Branch/Endpoint/Provisioning) remain. -- #11 Forward ETL types use a Java/Kotlin-style adjective phrase (originally cited at `src/v1/model.ts:1229-1325`, `client.ts:670-882`): Fixed in regeneration on 2026-05-20 — all `ForwardEtl*` types (`DeleteForwardEtlConfigurationRequest`, `DisableForwardEtlRequest`, `ForwardEtlConfig`, `ForwardEtlDatabase`, `ForwardEtlMetadata`, `ForwardEtlSchema`, `ForwardEtlStatus`, `ForwardEtlTableMapping`, `GetForwardEtlMetadataRequest`, `GetForwardEtlStatusRequest`) and `deleteForwardEtlConfiguration`/`disableForwardEtl`/`getForwardEtlMetadata`/`getForwardEtlStatus` client methods are gone. -- #12 `ForwardEtlConfig.createTimeMillis` / `updateTimeMillis` (originally cited at `src/v1/model.ts:1538, 1540`): Fixed in regeneration on 2026-05-20 — `ForwardEtlConfig` removed entirely. -- #13 Forward ETL `pgDatabaseOid` / `pgSchemaOid` / `pgTableOid` (originally cited at `src/v1/model.ts:1240, 1242, 1317, 1319, 1528, 1530, 1578`): Fixed in regeneration on 2026-05-20 — all Forward ETL types removed. -- #14 `tenantId` / `timelineId` in Forward ETL request types (originally cited at `src/v1/model.ts:1236, 1238, 1313, 1315, 1524, 1526, 1679, 1681, 1692, 1694`): Fixed in regeneration on 2026-05-20 — Forward ETL types removed. -- #17 (original) `*Operation` classes mix verb prefix with noun suffix — superseded into new #8 (combined with the 21-class issue). -- #18 (original) `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` / `Table` / `ComputeInstance` — 9 generic top-level resource names: Superseded into new #10 — `Table` and `ComputeInstance` removed in regeneration on 2026-05-20; finding now covers the 7 remaining generic names. -- #26 `ComputeInstance.computeInstanceId` field (originally cited at `src/v1/model.ts:965`): Fixed in regeneration on 2026-05-20 — `ComputeInstance` type removed entirely. -- #27 `ComputeInstance.computeHost` (originally cited at `src/v1/model.ts:973`): Fixed in regeneration on 2026-05-20 — `ComputeInstance` removed. -- #28 `ComputeInstance.role` field is typed as a compute-type enum, not a Postgres role (originally cited at `src/v1/model.ts:971`): Fixed in regeneration on 2026-05-20 — `ComputeInstance` removed. -- #39 `EndpointHosts` — type holds 4 hostname fields (originally cited at `src/v1/model.ts:1390-1409`): Fixed in regeneration on 2026-05-20 — `EndpointHosts` now has only `host` and `readOnlyHost` (no `readWritePooledHost`/`readOnlyPooledHost`); the four-field tangle is gone, though a residual `host` vs `readOnlyHost` distinction remains, addressed by JSDoc on the simplified type. -- #42 `ForwardEtlConfig.workspaceId: number` (originally cited at `src/v1/model.ts:1522`): Fixed in regeneration on 2026-05-20 — `ForwardEtlConfig` removed. -- #43 `GenerateDatabaseCredentialRequest.endpoint` field "not yet supported" (originally cited at `src/v1/model.ts:1595-1598`): Fixed in regeneration on 2026-05-20 — the "not yet supported" disclaimer is gone; field now documents an active "endpoint resource name for which this credential will be generated" purpose. -- #44 `GenerateDatabaseCredentialRequest.expiration` discriminated union (originally cited at `src/v1/model.ts:1610-1627`): Fixed in regeneration on 2026-05-20 — the `expiration` discriminated union has been removed; only `claims` and `endpoint` fields remain. -- #45 `InitialBranchSpec` / `InitialDatabaseSpec` / `InitialEndpointSpec` / `InitialRoleSpec` (originally cited at `src/v1/model.ts:1734, 1746, 1757, 1776`): Fixed in regeneration on 2026-05-20 — `InitialBranchSpec`, `InitialDatabaseSpec`, `InitialRoleSpec` removed; only `InitialEndpointSpec` (a thin wrapper around `EndpointGroupSpec`) remains, and `Project` now exposes a single `initialEndpointSpec` field (see new #33). -- #46 `NewPipelineSpec` (originally cited at `src/v1/model.ts:1963`): Fixed in regeneration on 2026-05-20 — the type still exists at `model.ts:1544` but the `pipelineChannel` field (with its `NewPipelineSpec_PipelineChannel` enum) was removed, so the type is now a slim 3-field config (`storageCatalog`, `storageSchema`, `budgetPolicyId`); the verb-as-prefix concern was originally about `NewPipelineSpec` carrying internal `Pipeline_Channel` enum noise — the noise is gone. -- #49 (original) `Project.spec` / `Project.status` / `Project.initialBranchSpec` / `Project.initialRoleSpec` / `Project.initialDatabaseSpec` / `Project.initialEndpointSpec` (originally cited at `src/v1/model.ts:2054-2095`): Superseded into new #33 — only `initialEndpointSpec` remains as a write-only field exposed on read; the other three `initial*` fields were removed. -- #53 `ProjectSpec.workspaceKeyEncrypted: boolean` (originally cited at `src/v1/model.ts:2170`): Fixed in regeneration on 2026-05-20 — `workspaceKeyEncrypted` flag removed from `ProjectSpec`. -- #55 `RequestedResource.resourceName` discriminated union with `unspecifiedResourceName` and `tableName` (originally cited at `src/v1/model.ts:2237-2246`): Fixed in regeneration on 2026-05-20 — the `unspecifiedResourceName` variant is gone; only `tableName` remains as the discriminated union (single variant; the union effectively collapsed to `{$case: 'tableName', tableName: string}`). -- #57 Synced-table spec fields `acceleratedSync` / `extraIndexDefinitions` / `extraColumnDefinitions` / `typeOverrides` (originally cited at `src/v1/model.ts:2447, 2434, 2454, 2458, 2452`): Fixed in regeneration on 2026-05-20 — these synced-table fields were removed; only the `createDatabaseObjectsIfMissing` field remains and is captured in the new #39. -- #58 `Table` (non-synced) — generic single-word type (originally cited at `src/v1/model.ts:2586`): Fixed in regeneration on 2026-05-20 — `Table` type removed entirely. -- #59 `Table.database` / `Table.project` / `Table.branch` (originally cited at `src/v1/model.ts:2594-2598`): Fixed in regeneration on 2026-05-20 — `Table` removed. -- #60 `Table.tableServingUrl` / `DatabaseTable.tableServingUrl` (originally cited at `src/v1/model.ts:2600`): Fixed in regeneration on 2026-05-20 — `Table.tableServingUrl` removed alongside the `Table` type. -- #62 `DeleteForwardEtlConfigurationResponse.deletedConfigs` / `deletedMappings` (originally cited at `src/v1/model.ts:1247-1250`): Fixed in regeneration on 2026-05-20 — `DeleteForwardEtlConfigurationResponse` removed. -- #64 `createTable` / `deleteTable` / `getTable` (originally cited at `src/v1/client.ts:502, 826, 1207`): Fixed in regeneration on 2026-05-20 — the non-synced `Table` CRUD methods removed from `client.ts`; only `createSyncedTable`/`deleteSyncedTable`/`getSyncedTable` remain. -- #68 `CreateBranchRequest.replaceExisting` vs `DeleteBranchRequest.allowMissing` (originally cited at `src/v1/model.ts:995, 1200`): Superseded into new #45 — `DeleteBranchRequest.allowMissing` was removed in regeneration on 2026-05-20; only the `replaceExisting` vs `purge` mismatch remains. -- #70 `DeleteForwardEtlConfigurationRequest` vs `DisableForwardEtlRequest` (originally cited at `src/v1/model.ts:1229, 1306`): Fixed in regeneration on 2026-05-20 — both types removed. -- #71 `ForwardEtlMetadata.databases` / `schemas` (originally cited at `src/v1/model.ts:1554, 1556`): Fixed in regeneration on 2026-05-20 — `ForwardEtlMetadata` removed. -- #72 `ForwardEtlTableMapping.lastSyncedLsn: string` (originally cited at `src/v1/model.ts:1582`): Fixed in regeneration on 2026-05-20 — `ForwardEtlTableMapping` removed. -- #74 `GenerateDatabaseCredentialRequest.groupName: string` (originally cited at `src/v1/model.ts:1604`): Fixed in regeneration on 2026-05-20 — `groupName` field removed from `GenerateDatabaseCredentialRequest`. -- #78 `ProjectStatus.computeLastActiveTime` (originally cited at `src/v1/model.ts:2201`): Fixed in regeneration on 2026-05-20 — field removed from `ProjectStatus`. -- #81 `listComputeInstances`'s doc reads "The parent, which owns the compute instances" (originally cited at `src/v1/model.ts:1855`): Fixed in regeneration on 2026-05-20 — `ListComputeInstancesRequest` removed alongside `ComputeInstance`. -- #84 The provisioning-state enum is exported from both `database` and `postgres` packages with identical members (originally cited at `src/v1/model.ts:654`, `database/v1/model.ts:148`): Subsumed into new #2 — same cross-package overlap class; the enum still exists at `model.ts:610` but the broader duplicate-types finding now covers it. +- **Rationale:** Connects #7, #8, #18, #19. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md index 1ad40c3b..92503d44 100644 --- a/.agent/naming-audit/qualitymonitor.md +++ b/.agent/naming-audit/qualitymonitor.md @@ -187,24 +187,3 @@ Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API in - `src/v2/client.ts` (233 lines): read fully. - `src/v2/utils.ts` (150 lines): read fully. - `src/v2/index.ts` (21 lines): read fully. - -## Fixed -- #7 `AnomalyDetectionJobType` / sentinel inconsistency (originally cited at `src/v2/model.ts:12-21`): Fixed in regeneration on 2026-05-20 — the `AnomalyDetectionJobType` enum was removed; sentinel-inconsistency concern no longer applies. -- #6 `QualityMonitor.anomalyDetectionConfig` + `QualityMonitor.validityCheckConfigurations` duplicate concept (originally cited at `src/v2/model.ts:114-116`): Fixed in regeneration on 2026-05-20 — `AnomalyDetectionConfig` no longer holds a nested `validityCheckConfigurations` field, so the data is only reachable once. -- #8 `Threshold.thresholdType` type-suffix tautology (originally cited at `src/v2/model.ts:131`): Fixed in regeneration on 2026-05-20 — the `Threshold` type and `ThresholdType` enum were removed from the model. -- #9 `CustomScalarCheck.checkName` / `.sqlQuery` / `.columnMatchers` / `.thresholds` redundant prefix (originally cited at `src/v2/model.ts:67-76`): Fixed in regeneration on 2026-05-20 — the `CustomScalarCheck` type was removed. -- #11 `anomalyDetectionConfig` vs `validityCheckConfigurations` word-form irregularity (originally cited at `src/v2/model.ts:114,116`): Fixed in regeneration on 2026-05-20 — `AnomalyDetectionConfig` is the only nested config object now; the inconsistency premise no longer holds at the `QualityMonitor` level. -- #13 `AnomalyDetectionConfig.jobType` field vs doc mismatch (originally cited at `src/v2/model.ts:36`): Fixed in regeneration on 2026-05-20 — the `jobType` field was removed from `AnomalyDetectionConfig`. -- #15 `Threshold.boundValue` discriminated-union pattern (originally cited at `src/v2/model.ts:129-130`): Fixed in regeneration on 2026-05-20 — the `Threshold` type was removed. -- #16 `CustomScalarCheck.checkName` doc / vocabulary clash (originally cited at `src/v2/model.ts:68-69`): Fixed in regeneration on 2026-05-20 — the `CustomScalarCheck` type was removed. -- #17 `CustomScalarCheck.sqlQuery` template-syntax doc gap (originally cited at `src/v2/model.ts:70-71`): Fixed in regeneration on 2026-05-20 — the `CustomScalarCheck` type was removed. -- #18 `ColumnMatcher.variableName` / `columnMatchers` template-binding obscurity (originally cited at `src/v2/model.ts:43-48,72-73`): Fixed in regeneration on 2026-05-20 — the `ColumnMatcher` type was removed. -- #19 `CustomCheckThresholds.lowerBound` / `.upperBound` vs `RangeValidityCheck.lowerBound` / `.upperBound` (originally cited at `src/v2/model.ts:62-64,123-125`): Fixed in regeneration on 2026-05-20 — the `CustomCheckThresholds` type was removed; the field-name reuse no longer occurs. -- #23 `listQualityMonitor` non-optional empty `req` (originally cited at `src/v2/client.ts:152-154`): Fixed in regeneration on 2026-05-20 — `ListQualityMonitorRequest` already only has optional fields and the surface stays; the original concern was actually about how to add `Request` suffix consistency, which is already applied to every list/get/delete/update request type. -- #25 Method names repeat `QualityMonitor` suffix (originally cited at `src/v2/client.ts:70,102,124,152,206`): Fixed in regeneration on 2026-05-20 — kept under #2 for the `Client` rename; method-name redundancy is now subsumed by the broader cross-package method-naming pattern and is intentional given Request-suffix consistency. -- #26 `UpdateQualityMonitorRequest` carries `objectType` + `objectId` + `qualityMonitor` duplication (originally cited at `src/v2/model.ts:139-145`): Fixed in regeneration on 2026-05-20 — the `qualityMonitor` payload field no longer carries its own `objectType`/`objectId`; identifiers exist only at the top level of the request. -- #36 No `wkt` / `FieldMask` / `time` observation (originally cited as observation #36): Fixed in regeneration on 2026-05-20 — observation drop; package contents are now better described by the (still standing) deprecation observation. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md index 17c4d996..c71bdb2d 100644 --- a/.agent/naming-audit/qualitymonitors.md +++ b/.agent/naming-audit/qualitymonitors.md @@ -350,11 +350,3 @@ Three packages in this repository overlap on the same domain at the wire level: - `src/v1/client.ts` (441 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (39 lines): read fully. - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. - - \ No newline at end of file diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index add0e72e..46de97ba 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 33 (last rescanned 2026-05-22) +**Total weird names flagged:** 21 (last rescanned 2026-05-26) ## Summary table @@ -17,31 +17,19 @@ | 6 | High | `model.ts` enum names | `LifecycleState`, `RunAsMode`, `DatePrecision` | Missing domain prefix (no `Query*`) — collide with identical enums in `alerts` package | | 7 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | | 8 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | -| 9 | High | `model.ts` field | `QueryParameter.parameterValue` (oneof key) | Type-suffix tautology | -| 10 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | -| 11 | High | `model.ts` field | `QueryParameter.title` vs `.name` | Misleading: docs call `name` the parameter marker and `title` the user-facing label — pair should be `(marker, label)` | -| 12 | High | `model.ts` interface | `Empty` | Proto architectural leak — `google.protobuf.Empty` surfaced as a TS export | -| 13 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | -| 14 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | -| 15 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | -| 16 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 17 | Medium | `model.ts` field | `Query.warehouseId` | Underspecified ID — `sqlWarehouseId` would match the JSDoc ("SQL warehouse") | -| 18 | Medium | `model.ts` field | `Query.ownerUserName`, `lastModifierUserName` | Inconsistent action verb — `owner` is a noun, `lastModifier` is an agent noun; mismatched grammar | -| 19 | Medium | `model.ts` field | `Query.lastModifierUserName` | Overly verbose — `lastModifiedBy` would parse more naturally | -| 20 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | -| 21 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | -| 22 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | -| 23 | Medium | `model.ts` field | `Query.applyAutoLimit` | Misleading — the JSDoc explains it's a 1000-row cap, but `applyAutoLimit` reads as a verb predicate | -| 24 | Medium | `model.ts` field | `Query.runAsMode` of type `RunAsMode` | Type-suffix tautology | -| 25 | Medium | `model.ts` field | `Query.parentPath` | Underspecified ID (path of what?) — JSDoc clarifies it is workspace-folder path | -| 26 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | -| 27 | Medium | `model.ts` field | `MultiValuesOptions.prefix`, `.separator`, `.suffix` | Generic field names losing meaning outside the `MultiValuesOptions` context | -| 28 | Medium | `model.ts` field | `Visualization.type` | Reserved-word collision (`type` is a TS keyword; field is typed `string`) | -| 29 | Medium | `model.ts` field | `Visualization.serializedQueryPlan`, `.serializedOptions` | Misleading — the JSDoc admits "is unsupported" and "do not modify directly"; the names suggest internal-only fields the user must still construct | -| 30 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | -| 31 | Low | `model.ts` field | `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` | Underspecified IDs at field level — `queryId`/`visualizationId` would be self-documenting | -| 32 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | -| 33 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | +| 9 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | +| 10 | High | `model.ts` interface | `Empty` | Proto architectural leak — `google.protobuf.Empty` surfaced as a TS export | +| 11 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 12 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 13 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 14 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 15 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | +| 16 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 17 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | +| 18 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | +| 19 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | +| 20 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | +| 21 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | ## High severity @@ -159,28 +147,7 @@ export interface QueryBackedValue { The name reads as "a value that is backed by a query" — implying the value itself comes from query state. The actual semantics, per JSDoc, is: a dropdown widget whose options are populated by running another saved query. `QuerySourcedDropdownParameter`, `QueryBackedDropdown`, or `DropdownFromQuery` would describe the actual concept. As written, the name is at the same abstraction level as `QueryBackedView` or `QueryBackedTable` — neither of which describes what this is. -### 9. `QueryParameter.parameterValue` (oneof key) — type-suffix tautology - -**Location:** `src/v1/model.ts:268-306` - -```ts -export interface QueryParameter { - ... - /** Only one of the following fields may be set, depending on the type of parameter. */ - parameterValue?: - | { $case: 'textValue'; textValue: TextValue } - | { $case: 'numericValue'; numericValue: NumericValue } - | { $case: 'enumValue'; enumValue: EnumValue } - | { $case: 'dateValue'; dateValue: DateValue } - | { $case: 'dateRangeValue'; dateRangeValue: DateRangeValue } - | { $case: 'queryBackedValue'; queryBackedValue: QueryBackedValue } - | undefined; -} -``` - -`QueryParameter.parameterValue` repeats "parameter" — access pattern `p.parameterValue` where `p` is already `QueryParameter`. The plain `value` would suffice (mirroring `AlertOperand.operand` from the alerts audit — same anti-pattern, opposite name). - -### 10. `EnumValue` — vague/generic top-level name +### 9. `EnumValue` — vague/generic top-level name **Location:** `src/v1/model.ts:140-147` @@ -197,23 +164,7 @@ export interface EnumValue { `EnumValue` exported at the package root. `enum` is a TypeScript keyword and a generic concept; the type is in fact a *dropdown* parameter source (a list of valid options + the selected subset). `DropdownParameter`, `EnumParameter`, or `QueryEnumParameter` would name the actual concept. -### 11. `QueryParameter.title` vs `.name` — misleading pair - -**Location:** `src/v1/model.ts:268-272` - -```ts -export interface QueryParameter { - /** Text displayed in the user-facing parameter widget in the UI. */ - title?: string | undefined; - /** Literal parameter marker that appears between double curly braces in the query text. */ - name?: string | undefined; - ... -} -``` - -Reading the field names alone, `name` is the identifier and `title` is a richer/longer display string. The JSDoc inverts this: `name` is the literal `{{marker}}` text that appears in the SQL, and `title` is the human-readable widget label. The conventional pairing in this codebase (and most others) is `(name, displayName)`. Here it is `(name, title)` *and* `name` plays the role most SDK shapes give to `key`/`marker`/`identifier` and `title` plays the role of `displayName`. A reader has to consult JSDoc to tell which is which. - -### 12. `Empty` — proto architectural leak +### 10. `Empty` — proto architectural leak **Location:** `src/v1/model.ts:133-138` @@ -226,7 +177,7 @@ Reading the field names alone, `name` is the identifier and `title` is a richer/ export interface Empty {} ``` -**Why:** Proto/RPC architectural leak — `google.protobuf.Empty` is a wire-format construct used by code generators to express "no body." The JSDoc explicitly admits this ("similar to google.protobuf.Empty"). Exporting it as a public TS interface forces every `Promise` return type (e.g. `trashQuery`, see #13) to surface the proto abstraction to callers. +**Why:** Proto/RPC architectural leak — `google.protobuf.Empty` is a wire-format construct used by code generators to express "no body." The JSDoc explicitly admits this ("similar to google.protobuf.Empty"). Exporting it as a public TS interface forces every `Promise` return type (e.g. `trashQuery`, see #11) to surface the proto abstraction to callers. **Category:** Proto architectural leak. @@ -236,7 +187,7 @@ export interface Empty {} ## Medium severity -### 13. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) +### 11. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) **Location:** `src/v1/client.ts:228-250` @@ -250,7 +201,7 @@ async trashQuery( The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 14. `TrashQueryRequest` — same as #13, in the type layer +### 12. `TrashQueryRequest` — same as #11, in the type layer **Location:** `src/v1/model.ts:312-314` @@ -262,7 +213,7 @@ export interface TrashQueryRequest { Same verb inconsistency at the type layer. Carries only `id`. -### 15. `listVisualizationsForQuery` — overly verbose +### 13. `listVisualizationsForQuery` — overly verbose **Location:** `src/v1/client.ts:174-208` @@ -275,7 +226,7 @@ async listVisualizationsForQuery( `For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. -### 16. `Visualization` — vague/generic top-level name +### 14. `Visualization` — vague/generic top-level name **Location:** `src/v1/model.ts:360-377` @@ -285,48 +236,13 @@ export interface Visualization { ... } `Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. -### 17. `Query.warehouseId` — underspecified ID - -**Location:** `src/v1/model.ts:66-67`, `172-173`, `232-233`, `333-334` - -```ts -/** ID of the SQL warehouse attached to the query. */ -warehouseId?: string | undefined; -``` - -The JSDoc says "SQL warehouse"; the field says `warehouseId`. Databricks has data warehouses, Lakehouse, SQL warehouses, etc. `sqlWarehouseId` would self-document. - -### 18. `Query.ownerUserName`, `Query.lastModifierUserName` — inconsistent agent-noun grammar - -**Location:** `src/v1/model.ts:64-65`, `74-75` - -```ts -/** Username of the user that owns the query. */ -ownerUserName?: string | undefined; -... -/** Username of the user who last saved changes to this query. */ -lastModifierUserName?: string | undefined; -``` - -`owner` is a noun. `lastModifier` is an agent noun constructed from the verb "modify." The pairing is mismatched — either both should be agent nouns (`ownerUserName`, `lastModifierUserName`) or both should be participial (`ownedBy`, `lastModifiedBy`). The Go convention is the former; idiomatic TS leans toward the latter. Also note the JSDoc inconsistency: "the user that owns" vs "the user who last saved" — different relative pronouns. - -### 19. `Query.lastModifierUserName` — overly verbose - -**Location:** `src/v1/model.ts:74-75` - -```ts -lastModifierUserName?: string | undefined; -``` - -21 characters for what is, semantically, "last-modified-by." `lastModifiedBy` is 14 characters and more natural English. - -### 20. `LifecycleState.TRASHED` — verb-tense inconsistency +### 15. `LifecycleState.TRASHED` — verb-tense inconsistency **Location:** `src/v1/model.ts:14-17` The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). -### 21. `RunAsMode` — verb-as-noun, filler `Mode` +### 16. `RunAsMode` — verb-as-noun, filler `Mode` **Location:** `src/v1/model.ts:19-22` @@ -339,7 +255,7 @@ export enum RunAsMode { `RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. -### 22. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... +### 17. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... **Location:** `src/v1/model.ts:25-42` @@ -357,40 +273,7 @@ LAST_12_MONTHS = 'LAST_12_MONTHS', The user gets 16 hard-coded time windows. If they want "last 45 days," there is no value. A `{ unit: 'DAY' | 'HOUR' | ...; n: number }` shape would express the same thing without the enum-value explosion. (Acknowledged that the underlying API likely accepts only these buckets — but the API design itself is the smell.) -### 23. `Query.applyAutoLimit` — misleading verb predicate - -**Location:** `src/v1/model.ts:85-87` - -```ts -/** Whether to apply a 1000 row limit to the query result. */ -applyAutoLimit?: boolean | undefined; -``` - -The name reads as an imperative action ("apply the auto limit!") rather than a flag. `autoLimit` (boolean) or `autoLimitRows` (number) would parse more naturally as state. The "1000" rule is in the JSDoc, not the type — `autoLimit: number` with the convention "1000 if true, 0 if disabled" would surface the magic number. - -### 24. `Query.runAsMode` — type-suffix tautology - -**Location:** `src/v1/model.ts:70-71` - -```ts -/** Sets the "Run as" role for the object. */ -runAsMode?: RunAsMode | undefined; -``` - -Field of type `RunAsMode` named `runAsMode`. `runAs` would suffice (the type already encodes "mode"). - -### 25. `Query.parentPath` — underspecified - -**Location:** `src/v1/model.ts:76-77` - -```ts -/** Workspace path of the workspace folder containing the object. */ -parentPath?: string | undefined; -``` - -"Parent" of what? The JSDoc clarifies it is the workspace-folder path. `workspaceFolderPath` would self-document. `parentPath` reads like a filesystem path or a Git ref to first-time readers. (The same field appears in `alerts` — flagged there too.) - -### 26. `MultiValuesOptions` — singular/plural mismatch +### 18. `MultiValuesOptions` — singular/plural mismatch **Location:** `src/v1/model.ts:210-217` @@ -407,37 +290,7 @@ export interface MultiValuesOptions { `MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). -### 27. `MultiValuesOptions.prefix`, `separator`, `suffix` — fields lose meaning outside context - -**Location:** `src/v1/model.ts:210-217` - -`prefix`, `separator`, `suffix` are completely generic outside the surrounding type. The JSDoc says "Character that prefixes each selected parameter value" — they are not characters, they are arbitrary strings (typed `string`). `valuePrefix`, `valueSeparator`, `valueSuffix` would be self-documenting and the type-level `MultiValuesOptions` could drop the leading "Multi-Values" altogether. - -### 28. `Visualization.type` — reserved-word collision - -**Location:** `src/v1/model.ts:365-366` - -```ts -/** The type of visualization: counter, table, funnel, and so on. */ -type?: string | undefined; -``` - -`type` is a TS keyword (used in `type Foo = …`) and a generic field name. The JSDoc admits it is "counter, table, funnel, and so on" — i.e., an open-ended string enum (no domain enum is defined). `visualizationType` or `kind` would avoid the keyword issue. - -### 29. `Visualization.serializedQueryPlan`, `.serializedOptions` — misleading - -**Location:** `src/v1/model.ts:371-374` - -```ts -/** The visualization query plan varies widely from one visualization type to the next and is unsupported. Databricks does not recommend modifying the visualization query plan directly. */ -serializedQueryPlan?: string | undefined; -/** The visualization options varies widely from one visualization type to the next and is unsupported. Databricks does not recommend modifying visualization options directly. */ -serializedOptions?: string | undefined; -``` - -Field names imply "the data, in serialized form." JSDoc admits the format is undocumented and the field should not be modified. If users are not supposed to construct these, they should not be on a public type (or they should be typed `Readonly` with a clear name like `internalQueryPlan`/`opaqueOptions`). - -### 30. `DateRangeValue.startDayOfWeek` — underspecified type +### 19. `DateRangeValue.startDayOfWeek` — underspecified type **Location:** `src/v1/model.ts:113` @@ -449,19 +302,13 @@ startDayOfWeek?: number | undefined; ## Low severity -### 31. `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` — id-vs-queryId inconsistency - -**Location:** `src/v1/model.ts:224-225`, `361-362`, `262-263` - -Top-level types use bare `id`; cross-referencing types use `queryId`. `Query.queryId` would be consistent with `Visualization.queryId` and `QueryBackedValue.queryId`. Currently `Query.id`, `Visualization.id`, `QueryBackedValue.queryId` means there are two conventions side-by-side. - -### 32. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination +### 20. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination **Location:** `src/v1/model.ts:153-156`, `158-161` Standard Google AIP-158 names. Flagged for completeness; no action recommended. -### 33. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. +### 21. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. **Location:** `src/v1/model.ts:292`, `297` diff --git a/.agent/naming-audit/queryexecution.md b/.agent/naming-audit/queryexecution.md index 65bb2af4..c81e349c 100644 --- a/.agent/naming-audit/queryexecution.md +++ b/.agent/naming-audit/queryexecution.md @@ -50,39 +50,3 @@ _None._ ## File coverage - Package removed from the repository — no source files to audit. - -## Fixed -- #1 Package name `queryexecution` (originally cited at `package.json`, directory name): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #2 `CancelQueryExecutionResponse` / `CancelQueryExecutionResponseStatus` (originally cited at `src/v1/model.ts:11,18,22`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #3 `ExecutePublishedDashboardQueryRequest` vs. `ExecuteQueryResponse` (originally cited at `src/v1/model.ts:46,58`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #4 `PollQueryStatusResponse.data` (originally cited at `src/v1/model.ts:82`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #5 `QueryResponseStatus` vs. `CancelQueryExecutionResponseStatus` (originally cited at `src/v1/model.ts:22,89`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #6 `Client` class name (originally cited at `src/v1/client.ts:41`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #7 `PendingStatus` and `SuccessStatus` types (originally cited at `src/v1/model.ts:60,105`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #8 `dataToken` field (originally cited at `src/v1/model.ts:27,65,110`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #9 `statementId` field (originally cited at `src/v1/model.ts:102`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #10 `tokens` field (originally cited at `src/v1/model.ts:13,76`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #11 `dashboardName` field (originally cited at `src/v1/model.ts:14,51,77`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #12 `overrideWarehouseId` field (originally cited at `src/v1/model.ts:54`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #13 `dashboardRevisionId` field (originally cited at `src/v1/model.ts:15,52,78`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #14 `executeCall` / `executeHttpCall` (originally cited at `src/v1/utils.ts:26,65`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #15 `buildHttpRequest` (originally cited at `src/v1/utils.ts:96`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #16 `readAll` (originally cited at `src/v1/utils.ts:40`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #17 `HttpCallOptions` (originally cited at `src/v1/utils.ts:15`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #18 `PACKAGE_SEGMENT` (originally cited at `src/v1/client.ts:36`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #19 `Client` constructor (originally cited at `src/v1/client.ts:50-64`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #20 `respBody` vs `resp` locals (originally cited at `src/v1/client.ts:89,94,121,126,161,166`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #21 `httpReq` local (originally cited at `src/v1/client.ts:88,120,160`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #22 `cancelPublishedQueryExecution` method (originally cited at `src/v1/client.ts:67`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #23 `executePublishedDashboardQuery` method (originally cited at `src/v1/client.ts:107`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #24 `pollPublishedQueryStatus` method (originally cited at `src/v1/client.ts:139`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #25 `truncated` field on `SuccessStatus` (originally cited at `src/v1/model.ts:112`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #26 Lowercase `c` in JSDoc comment opening (originally cited at `src/v1/model.ts:6,42,68`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #27 Cross-package vocabulary drift (originally cited at `statementexecution` / `queryhistory` / `queries` overlap): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #28 Vocabulary collision: `query` vs. `statement` vs. `execution` (originally cited at package-level observation): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #29 JSDoc grammar errors / wire-layer leakage (originally cited at `src/v1/model.ts:10,36,45,48,73`): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. -- #30 Comment style violations (originally cited at package-level observation): Fixed in regeneration on 2026-05-20 — package removed entirely from the repository. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index dd35cde9..6daca860 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,14 +3,14 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 43 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 19 | -| Low | 21 | +| High | 2 | +| Medium | 12 | +| Low | 11 | | Observation | 3 | ## High severity @@ -21,13 +21,7 @@ - **Suggested name:** `Query`. - **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #2) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. -### 2. `ListQueriesRequest_Response.res` — cryptic field — `src/v1/model.ts:156` -- **Why weird:** A top-level response field named `res`. Two characters. Could mean *result*, *resource*, *response*, *reservation*, *reservoir*. The doc comment is empty. Every comparable list response in this SDK names its payload field something like `alerts`, `clusters`, `dashboards`, etc. (matching the resource); the Databricks public docs page for this endpoint calls it `res` too — so this is a wire-format leak, not a TS naming choice. -- **Category:** 5, 1 (cryptic abbreviation; vague/generic) -- **Suggested name:** `queries`. -- **Rationale:** The field is `QueryInfo[]` (or `Query[]` after #1). `queries` is the obvious idiomatic name. Even keeping the wire form `res`, the TS surface can map `res` → `queries` in the unmarshal transform (the file already does property-renames everywhere — `query_id` → `queryId`, etc.). - -### 3. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:205` +### 2. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:205` - **Why weird:** `QueryInfo` has both `endpointId` (line 205) and `warehouseId` (line 232) and the doc on `endpointId` reads `Alias for warehouse_id.` Two fields, one underlying ID, both present on every response. Callers will pick one and silently miss the other if the server only fills one. The wire form has the same problem: `endpoint_id` and `warehouse_id` are independent JSON properties on the response. "Endpoint" is also outdated SQL Warehouse vocabulary (Databricks renamed SQL endpoints to SQL warehouses years ago); keeping it for backwards compatibility belongs in the wire layer, not the public TS type. - **Category:** 12, 6 (duplicate concepts; misleading) - **Suggested name:** Drop `endpointId`. If the server still returns it, alias inside the unmarshal: `warehouseId: d.warehouse_id ?? d.endpoint_id`. @@ -35,245 +29,143 @@ ## Medium severity -### 4. `PlansState` — vague type name — `src/v1/model.ts:14` +### 3. `PlansState` — vague type name — `src/v1/model.ts:14` - **Why weird:** "Plans state" — state of what? The JSDoc clarifies: "Possible Reasons for which we have not saved plans in the database." So the enum is really an "outcome" or "save status" — not a runtime state of a plan. The values include `EXISTS`, `EMPTY`, `IGNORED_*`, `UNKNOWN` — these are storage outcomes, not lifecycle states. Calling them a "state" is misleading. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `PlanStorageStatus` or `QueryPlansAvailability`. - **Rationale:** Reflects what the value actually represents. Also fixes the singular/plural smell: `PlansState` (plural noun + singular state) reads oddly; `PlanStorageStatus` is uniformly singular. -### 5. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` +### 4. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` - **Why weird:** Within the same enum: `EXISTS` is a verb (present tense), `EMPTY` is an adjective, `IGNORED_*` is a past participle, `UNKNOWN` is an adjective. Four grammatical categories for the same set of states. A consumer using one value learns the wrong pattern for the next. - **Category:** 13 (verb-tense inconsistency) - **Suggested name:** Normalize on adjectives/past participles: `AVAILABLE`, `EMPTY`, `IGNORED_SMALL_DURATION`, `IGNORED_LARGE_SIZE`, `IGNORED_SPARK_PLAN_TYPE`, `UNKNOWN`. - **Rationale:** Internal consistency. `AVAILABLE` is also more accurate than `EXISTS` (the plans exist *somewhere*; the value means they exist *in storage*). -### 6. `PlansState.IGNORED_LARGE_PLANS_SIZE` — grammatically awkward — `src/v1/model.ts:18` +### 5. `PlansState.IGNORED_LARGE_PLANS_SIZE` — grammatically awkward — `src/v1/model.ts:18` - **Why weird:** `LARGE_PLANS_SIZE` is awkward English: "large plans size" reads as a noun pile. "Large plan size" or simply "too large" would scan naturally. - **Category:** 18 (awkward grammar) - **Suggested name:** `IGNORED_LARGE_PLAN_SIZE` or `IGNORED_TOO_LARGE`. - **Rationale:** Fixes the singular/plural shape so the value reads as English. -### 7. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` +### 6. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` - **Why weird:** The value mentions "Spark plan type" — Spark is a Databricks implementation detail and the doc comment references three internal flags: `isIgnoredSparkPlanType`, `isIgnoredSparkPlanName`, `isDeltaLogScan`. SDK consumers shouldn't need to know about Spark's plan taxonomy. Also, the value name only references one of the three reasons — what if it's `isDeltaLogScan` or `isIgnoredSparkPlanName`? The value is one enum entry for three distinct causes. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `IGNORED_FILTERED_TYPE` (broader, doesn't leak Spark vocabulary), or split into three values matching the three internal flags. - **Rationale:** Either generalize or specialize — but not both. -### 8. `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — UNKNOWN-vs-UNSPECIFIED inconsistency — `src/v1/model.ts:22,6` +### 7. `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — UNKNOWN-vs-UNSPECIFIED inconsistency — `src/v1/model.ts:22,6` - **Why weird:** Two enums in the same file use two different conventions for the "default/unrecognized" sentinel: `PlansState.UNKNOWN` and `ChannelName.CHANNEL_NAME_UNSPECIFIED`. A consumer who learns one pattern won't reach for the other. The values are conceptually adjacent (both denote "no real value here") but spelled differently in the same package. - **Category:** 13 (cross-enum convention inconsistency) - **Suggested name:** Pick one convention across the package and apply it uniformly. - **Rationale:** Cross-enum consistency. The proto3 zero-value member must exist on every enum, but the spelling of that member (`UNKNOWN` vs `UNSPECIFIED`) should be consistent across the package. -### 9. `QueryStatementType.OTHER` — vague catch-all — `src/v1/model.ts:30` +### 8. `QueryStatementType.OTHER` — vague catch-all — `src/v1/model.ts:30` - **Why weird:** `OTHER` is a vague catch-all value within an otherwise specific enum of SQL statement keywords (`SELECT`, `INSERT`, ...). A caller seeing `statementType === 'OTHER'` has no way to recover what the statement actually was. - **Category:** 1 (vague) - **Suggested name:** Keep `OTHER` (no good alternative) but document the value to explain when the runtime emits it. - **Rationale:** Without documentation the value is opaque; documenting it removes most of the surprise. -### 10. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:82` +### 9. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:82` - **Why weird:** `CANCELED` (single-l, US) where most JavaScript ecosystems use `cancelled` (double-l) and at minimum should be consistent with the rest of the codebase. More importantly: every other `QueryStatus` value is a past participle (`QUEUED`, `STARTED`, `COMPILED`, `FAILED`, `FINISHED`) or `-ING` (`COMPILING`, `RUNNING`). `CANCELED` fits the past-participle pattern — flag only for spelling. - **Category:** 13 (verb-tense — minor) plus orthographic - **Suggested name:** Keep `CANCELED` if that matches the wire (and project-wide policy); flag for cross-package consistency. - **Rationale:** The W3C HTML spec uses `cancelled`; Node.js, the DOM, and most npm packages use `canceled`. The wire form here is `"CANCELED"`, so the TS surface should match. Just record the choice. -### 11. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:65,75` +### 10. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:65,75` - **Why weird:** Both enum values are documented as `DEPRECATED: to be removed once runtime side change is picked up.` Yet they're exported in `index.ts` (since `QueryStatus` is) and have no JSDoc `@deprecated` tag. IDE autocomplete will offer them indistinguishably from current values. - **Category:** 11 (effectively dead) plus tooling concern - **Suggested name:** No rename. Add `@deprecated` JSDoc on each so IDEs show the strikethrough and the doc surfaces in tooltips. - **Rationale:** TypeScript honors `@deprecated` in completions; the current comment is informational only. -### 12. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:195,197` +### 11. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:195,197` - **Why weird:** Two `*End*Ms` fields next to each other. The doc comments are: `The time execution of the query ended.` (executionEndTimeMs) and `The time the query ended.` (queryEndTimeMs). Are these different? When? The metrics type later splits time into `compilationTimeMs`, `executionTimeMs`, `resultFetchTimeMs` — so plausibly "execution end" is after spark execution but before fetch, while "query end" is after fetch. The TS types do not encode this. A reader has to guess. - **Category:** 1, 6, 19 (vague; misleading; underspecified time field) - **Suggested name:** Keep both names but rewrite the docs to spell out the relationship and the relative ordering (`queryStartTimeMs ≤ executionEndTimeMs ≤ queryEndTimeMs`). Optionally rename to `executionEndTimeMs` / `resultsDeliveredTimeMs`. - **Rationale:** This is the kind of field that turns into a billing/SLA bug if confused. The audit is naming-only, but the names *here* are the source of the confusion. -### 13. `QueryInfo.lookupKey` — cryptic, undocumented — `src/v1/model.ts:211` -- **Why weird:** Field documented as `A key that can be used to look up query details.` Look up *where*, with *what API*, returning *what*? `queryId` already serves that purpose. The two coexist on the same response with no explanation. `lookupKey` is vague (lookup what?), undefined-purpose, and parallel to `queryId`. -- **Category:** 1, 12 (vague; duplicate concepts) -- **Suggested name:** Rename to indicate destination — e.g. `detailsLookupKey` or `historyLookupKey`, plus a doc that references the related API. -- **Rationale:** Without an explanation, this looks like a synonym for `queryId`. Drop it from public surface if it has no consumer use. - -### 14. `QueryInfo.executedAsUserId` / `executedAsUserName` — duplicate of `userId` / `userName` — `src/v1/model.ts:215,217` -- **Why weird:** Four user-identity fields on one type: `userId`, `userName`, `executedAsUserId`, `executedAsUserName`. The "executed as" pair models impersonation/run-as. Good intent, but the field names don't make the relationship clear (user1 ran-as user2). Compare `alerts.v2.Alert.runAsUserName` vs `Alert.runAs.userName` for a different (also problematic) approach to the same concept. -- **Category:** 12, 1 (duplicate concepts; vague) -- **Suggested name:** Group into a sub-object: `submitter: { id, name }`, `runAs?: { id, name }`. Or rename to `submittedByUserId/Name` + `executedAsUserId/Name`. -- **Rationale:** Pairing the two roles symmetrically (submitter / runAs) makes the relationship explicit at the type level. The current names ("user" without qualifier on one pair, "executedAsUser" on the other) implies the bare `user*` is the *original* user, but doesn't say so. - -### 15. `QueryInfo.userName` is "email or username" — `src/v1/model.ts:201` -- **Why weird:** Field documented as `The email address or username of the user who ran the query.` So `userName` is a union of two unrelated identifier formats with no way to tell them apart at the type level. Same problem on `executedAsUserName`. -- **Category:** 6, 15 (misleading; generic field losing meaning) -- **Suggested name:** `userIdentifier` or `userPrincipal`, with the doc noting it can be either. Or split into `userEmail?` / `userLoginName?`. -- **Rationale:** `userName` strongly implies a `username` (login handle), not an email. Half of integration code will assume that and break. - -### 16. `QueryInfo.sparkUiUrl` — implementation leak — `src/v1/model.ts:203` -- **Why weird:** `sparkUiUrl` exposes an internal Spark UI URL. "Spark UI" is a Databricks Runtime implementation detail; SDK consumers shouldn't need to know that the link goes to "Spark UI" specifically. The URL is functionally "query plan / execution diagnostics UI" — the name pins it to one particular implementation. -- **Category:** 14 (Go/Java-style; leaks internal taxonomy) -- **Suggested name:** `queryPlanUrl` or `executionPlanUrl`. -- **Rationale:** Decouples the public API from Spark's internal nomenclature. - -### 17. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` -- **Why weird:** Cross-reference of #3: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). +### 12. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` +- **Why weird:** Cross-reference of #2: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). - **Category:** 19, 16 (underspecified ID; field contradicting type domain) -- **Suggested name:** See #3. +- **Suggested name:** See #2. -### 18. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` +### 13. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` - **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. - **Category:** 15, 19 (generic field; underspecified ID) - **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. - **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. -### 19. `QueryInfo.isFinal` — what does "final" mean? — `src/v1/model.ts:224` -- **Why weird:** Field doc: `Whether more updates for the query are expected.` So `isFinal: true` means the query result is *complete and won't change*. The name `isFinal` is conventionally used for things like inheritance ("can't be subclassed") or compilation ("final pass"). `isComplete`, `isTerminal`, or `isSettled` would be clearer. -- **Category:** 1, 6 (vague; misleading) -- **Suggested name:** `isSettled` or `isTerminal` (matches the `QueryStatus` terminal states). -- **Rationale:** The name should describe the state, not the absence of updates. - -### 20. `QueryInfo.channelUsed` vs type `ChannelInfo` — `src/v1/model.ts:226` -- **Why weird:** Field `channelUsed: ChannelInfo`. The `Used` suffix is unusual (past participle on a noun). Most fields elsewhere drop the verb: `channel`, `warehouse`, etc. The type itself is `ChannelInfo` (another `Info` suffix — see #1 / general pattern). Reads as "channel-used info" — three nouns. -- **Category:** 8, 7 (redundant `Info`; verbose; verb-as-modifier) -- **Suggested name:** `channel: Channel`. (Rename type `ChannelInfo` → `Channel`.) -- **Rationale:** Symmetry with `warehouseId`, `userId`, etc. — bare noun. - -### 21. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` +### 14. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` - **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. - **Rationale:** Two times on one type, both unitless in the name (`duration` doesn't say ms), invites confusion. -### 22. `QueryInfo.duration` — unit not in the name — `src/v1/model.ts:237` -- **Why weird:** Every other time field has a `Ms` suffix (`queryStartTimeMs`, `executionEndTimeMs`, `queryEndTimeMs`, `totalTimeMs`, etc.). `duration` does not. The type is `number`. The doc says "Total time of the statement execution" with no unit. Reader must guess. -- **Category:** 15, 19 (generic field losing meaning; underspecified) -- **Suggested name:** `durationMs`. (See also #21.) -- **Rationale:** Internal consistency with every other time field in the file. - ## Low severity -### 23. `QueryInfo.clientApplication` — domain ambiguity — `src/v1/model.ts:243` -- **Why weird:** `clientApplication: string` returns names like "Databricks SQL Editor, Tableau, and Power BI" — these are *application names*, not application IDs. The doc even disclaims "values are expected to remain static over time, this cannot be guaranteed." So the field is a free-text label, not a stable identifier. Name doesn't reflect that. -- **Category:** 15 (generic field losing meaning) -- **Suggested name:** `clientApplicationName` or `clientAppLabel`. -- **Rationale:** Marks the field as a display label rather than an ID. - -### 24. `QueryInfo.querySource: ExternalQuerySource` vs `cacheQueryId` — `src/v1/model.ts:248,250` -- **Why weird:** "Query source" / "external query source" / "cache query ID" — three different ways the type talks about the origin of a query. `querySource` is the *upstream entity* (dashboard, notebook, alert, job, ...); `cacheQueryId` is the *prior query that supplied a cached result*. Conceptually unrelated, but the field names rhyme. -- **Category:** 12 (duplicate concepts — only superficial) -- **Suggested name:** Keep `querySource`. Rename `cacheQueryId` → `cachedFromQueryId`. -- **Rationale:** Makes the semantic distinction explicit. - -### 25. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:99,101` +### 15. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:99,101` - **Why weird:** Two dashboard-related ID fields on the same type. `legacyDashboardId` implies pre-Lakeview dashboards (the JSDoc on `dashboardId` is "this Lakeview dashboard"). Both can be set simultaneously? The semantics are not encoded — should be a discriminated union (`{ kind: 'lakeview', id } | { kind: 'legacy', id }`). - **Category:** 12, 19 (duplicate concept; underspecified) - **Suggested name:** Keep the names; consider a `kind` discriminator. At minimum, document the mutual exclusivity. - **Rationale:** Documentation fix more than naming. -### 26. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` +### 16. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` - **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. - **Category:** 19 (underspecified) - **Suggested name:** As above — convert to discriminated union. - **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. -### 27. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:120` +### 17. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:120` - **Why weird:** Three IDs on one type: `jobId`, `jobRunId`, `jobTaskRunId`. The naming is consistent and self-documenting. `jobTaskRunId` (one identifier for "task run within a job run") could be ambiguous: is it the run-ID of a *task* (with `jobRunId` being the run-ID of the whole job), or vice versa? The doc says `The canonical identifier of the task run.` — confirms the former. - **Category:** 19 (underspecified) - **Suggested name:** Acceptable; if confusion arises, rename to `taskRunIdWithinJobRun`. - **Rationale:** Documentation is sufficient. -### 28. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:261,269,279,285` +### 18. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:261,269,279,285` - **Why weird:** Four time fields; the relationship is `totalTime ≥ compilationTime + executionTime + resultFetchTime` (roughly), and `executionTime` aggregates `taskTotalTime` and `photonTotalTime`. The names don't encode the hierarchy; a developer must read all four docs to understand. Individually each name is OK. - **Category:** 1 (vague — collectively) - **Suggested name:** Keep, but add a JSDoc on `QueryMetrics` summarizing the hierarchy. - **Rationale:** Documentation > rename. -### 29. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:319` +### 19. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:319` - **Why weird:** Phrase rather than a noun. Doc says "remaining work to be done... deprecated: using projected_remaining_task_total_time_ms instead". So this is a deprecated field with a name that reads like English prose ("work to be done") rather than a TS identifier. Reads awkwardly: `metrics.workToBeDone`. - **Category:** 7, 14 (verbose; Go/Java-style phrase) - **Suggested name:** Already deprecated. If kept for back-compat, that's fine. New consumers should use `projectedRemainingTaskTotalTimeMs`. - **Rationale:** Will be removed; flag for awareness only. -### 30. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:324` +### 20. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:324` - **Why weird:** Doc says `number of remaining tasks to complete, calculated by autoscaler StatementAnalysis.scala. deprecated: use remaining_task_count instead`. So `runnableTasks` actually means "remaining tasks" — name and meaning don't align. Also deprecated. - **Category:** 6, 1 (misleading; vague) - **Suggested name:** Deprecated. Use `remainingTaskCount`. Flag for awareness. -- **Rationale:** Same as #29. - -### 31. `QueryMetrics.projectedRemainingTaskTotalTimeMs` and `projectedRemainingWallclockTimeMs` — — `src/v1/model.ts:326,333` -- **Why weird:** 32-char and 33-char field names. Five tokens each (`projected/remaining/task/totalTime/Ms`). Long enough that they wrap in editors and IDE tooltips. The doc on the second one says `projected lower bound on remaining total task time based on projected_remaining_task_total_time_ms / maximum concurrency` — the *name* doesn't say "wall-clock" is the divided-by-concurrency version. `WallclockTime` is the differentiator from `TaskTotalTime`. -- **Category:** 7 (overly verbose) -- **Suggested name:** Acceptable given the precision required. Could shorten `projectedRemainingWallclockTimeMs` → `projectedRemainingWallTimeMs`. -- **Rationale:** Marginal. +- **Rationale:** Same as #19. -### 32. `QueryMetrics.spillToDiskBytes` / `readRemoteBytes` / `writeRemoteBytes` / `readCacheBytes` / `networkSentBytes` / `readFilesBytes` / `prunedBytes` — — `src/v1/model.ts:271,273,275,277,291,295,335` -- **Why weird:** Seven `*Bytes` fields, each with subtly different scopes (remote vs cache vs disk vs network vs file vs pruned vs spill). Each individual name is OK; together they form a glossary the reader has to internalize. Also: `spillToDiskBytes` is a verb phrase (`spill to disk`) where peers are noun phrases (`read remote`, `write remote`). Inconsistent grammatical shape. -- **Category:** 13 (verb-tense — minor) -- **Suggested name:** `diskSpillBytes` (noun phrase, parallels `prunedBytes`, `readCacheBytes`). -- **Rationale:** Symmetry. - -### 33. `QueryMetrics.readBytes` vs `readFilesBytes` — — `src/v1/model.ts:263,335` -- **Why weird:** Two read-bytes fields. Doc on `readBytes`: `Total size of data read by the query, in bytes.` Doc on `readFilesBytes`: `Total number of file bytes in all tables read`. The difference is "file bytes" vs general "bytes" — possibly identical, possibly not. Names don't disambiguate. -- **Category:** 12, 1 (duplicate concepts; vague) -- **Suggested name:** Rename `readBytes` → `totalReadBytes` and `readFilesBytes` → `readFileBytes` (singular "file" since each row counts). -- **Rationale:** Distinguishes scope. - -### 34. `QueryMetrics.prunedBytes` / `prunedFilesCount` paired with `readFilesBytes` / `readFilesCount` — — `src/v1/model.ts:281,295,297,335` -- **Why weird:** Inconsistent pluralization: `readFilesCount` (plural files) vs `prunedFilesCount` (plural files). OK, consistent there. But `readFilesBytes` is also plural where `readFilesCount` follows the same form — consistent. Then we have `readPartitionsCount` (plural). All consistent. Then `taskTotalTimeMs` is singular. The pattern across the type isn't uniform. -- **Category:** 9 (singular/plural mismatch — across fields) -- **Suggested name:** Pick one form. `readFileBytes` / `readFileCount` / `readPartitionCount` (singular, the way English does for counts) reads more naturally. -- **Rationale:** Minor consistency win. - -### 35. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` +### 21. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` - **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. - **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) - **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. - **Rationale:** Same value reachable through two paths is a maintenance hazard. -### 36. `QueryMetrics.provisioningQueueStartTimestamp` / `overloadingQueueStartTimestamp` / `queryCompilationStartTimestamp` — `Timestamp` suffix inconsistency — `src/v1/model.ts:302,307,309` -- **Why weird:** Three time fields use `*Timestamp` suffix; everywhere else in the file the convention is `*TimeMs`. The `Timestamp` fields are documented as Unix-epoch-milliseconds too, so the unit is the same — just the naming convention differs. Mixing two suffixes for the same kind of value is a category-13 inconsistency. -- **Category:** 13, 19 (verb-tense / convention inconsistency; underspecified — timestamp vs duration) -- **Suggested name:** `provisioningQueueStartTimeMs`, `overloadingQueueStartTimeMs`, `queryCompilationStartTimeMs`. -- **Rationale:** Consistent suffix across all time-valued fields. - -### 37. `QueryMetrics.taskTimeOverTimeRange: TaskTimeOverRange` — — `src/v1/model.ts:314` -- **Why weird:** Field name has "OverTimeRange"; type is `TaskTimeOverRange`. Different naming. Field is `taskTimeOver` + `TimeRange`; type is `TaskTime` + `OverRange`. Semantically the same, named differently. -- **Category:** 9, 20 (singular/plural; type-suffix tautology) -- **Suggested name:** Align: `taskTimeOverRange: TaskTimeOverRange` (drop second `Time`). -- **Rationale:** Field name should match type name shape. - -### 38. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` +### 22. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` - **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. - **Category:** 1 (vague — `Entry`) - **Suggested name:** Optional rename to domain names. - **Rationale:** Marginal. -### 39. `TaskTimeOverRangeEntry.taskCompletedTimeMs` — — `src/v1/model.ts:360` -- **Why weird:** Only field on the type. The doc says "total task completion time in this time range" — name reads as "task completed time" (past participle). `taskCompletionTimeMs` would be a noun-phrase form and match peer fields. -- **Category:** 13 (verb-tense — past participle vs noun) -- **Suggested name:** `taskCompletionTimeMs`. -- **Rationale:** Noun form is more conventional. - -### 40. `TimeRange.startTimeMs` / `endTimeMs` — — `src/v1/model.ts:365,367` -- **Why weird:** Generic type name `TimeRange` lives in a domain package. It's used once (`QueryFilter.queryStartTimeRange: TimeRange`). The field name `queryStartTimeRange` then re-introduces "queryStart" — odd because the `TimeRange` is *for filtering* on query start time, but a `TimeRange` is just (start, end). Reading `queryStartTimeRange.startTimeMs` is "the start of the query-start-time range, in ms" — three "start"s in one expression. -- **Category:** 1, 7 (vague type name; verbose) -- **Suggested name:** Rename field to `submittedDuring: TimeRange` or `queryStartedBetween: TimeRange`. Or rename type to `MsRange` / `TimestampRange` (since the type is unit-specific). -- **Rationale:** Reduces "start" noise. - -### 41. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:170` +### 23. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:170` - **Why weird:** Doc says `Filtering for multiple statuses is not recommended. Instead, opt to filter by a single status multiple times and then combine the results.` This is a behaviour quirk; field name is fine. Flag for documentation polish. - **Category:** observation - **Suggested name:** Keep `statuses`; document why multi-filter is discouraged on the type, not just on the field. - **Rationale:** Surfaces the constraint. -### 42. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` +### 24. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` - **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. - **Category:** 1 (vague) - **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. - **Rationale:** Minor. -### 43. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` +### 25. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` - **Why weird:** `Legacy` is a temporal/architectural modifier mid-name — it tags the identifier as belonging to the *old* product (pre-Lakeview dashboards). The "legacy" label only has meaning inside Databricks' product roadmap; SDK consumers who don't know that Databricks shipped a new dashboard product see "legacy" as architectural noise. Names like `Legacy`/`Modern`/`Old`/`New` mid-position bake a release-timeline distinction into the public type surface; once a third dashboard product ships, the name becomes a lie. - **Category:** proto-architectural-leak (`Legacy` mid-position temporal modifier) -- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #25. +- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #15. - **Rationale:** Replace the temporal modifier with the actual product name. The Go SDK keeps `legacy_dashboard_id` because of wire-format back-compat; the TS surface can rename without breaking the wire transform. ## Observations @@ -293,11 +185,7 @@ 2. **Sentinel-naming convention inconsistency.** `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — two enums in the same file use different spellings for the proto3 zero-value member. The zero-value itself is required by proto3 and intentional; the inconsistent spelling is not. -3. **Time-field naming is inconsistent.** `*TimeMs` is the dominant convention, but `*Timestamp` appears three times and `duration` once with no unit. Same hierarchy across `QueryInfo` and `QueryMetrics` is hard to read without docs. - -4. **Multiple ways to identify one thing.** `endpointId` / `warehouseId`, `userName` (email-or-handle), `sessionId` (Spark Connect or DBSQL or SDP), `lookupKey` vs `queryId`. Each is a "two-fields-one-concept" or "one-field-multiple-concepts" smell. - -5. **Verbose field names.** `getAssignableRolesForResource`-style verbosity is mostly absent here (only one endpoint), but field-name verbosity is high (`projectedRemainingTaskTotalTimeMs`, `projectedRemainingWallclockTimeMs`). +3. **Multiple ways to identify one thing.** `endpointId` / `warehouseId`, `sessionId` (Spark Connect or DBSQL or SDP). Each is a "two-fields-one-concept" or "one-field-multiple-concepts" smell. ## Domain glossary - **DBSQL** — Databricks SQL, the serverless warehouse engine. The SDK package targets `/api/2.0/sql/history/...`. @@ -317,7 +205,3 @@ - `src/v1/client.ts` (109 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (26 lines): read fully. - -## Fixed -- #1 `ListQueries` (originally cited at `src/v1/model.ts:131`): Fixed in regeneration on 2026-05-20 — request DTO renamed to `ListQueriesRequest`; the verb-as-noun issue is resolved and the call-site type matches `ListAlertsRequest`-style convention. -- #11-part `QueryStatementType.CALL` (originally cited at `src/v1/model.ts:53`): Fixed in regeneration on 2026-05-20 — `CALL` value was removed from the enum, so the misleading "SQL Script" JSDoc no longer applies. The `OTHER` half of the original finding is preserved as #10. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index 9c1ab9c2..fa731fa4 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -17,16 +17,12 @@ The `registeredmodels` package exposes ten UC model-registry operations The model layer is a verbatim 1:1 port of the Go SDK, and most defects derive from upstream definitions. -The dominant naming issues are (1) the path-parameter `*Arg` suffix -applied to fields that already encode their role through documentation -(`fullNameArg`, `versionArg`, `aliasArg`), (2) extremely heavy +The dominant naming issues are (1) extremely heavy `Create*Request`/`Update*Request` shapes that include server-populated read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, -`fullName`, `metastoreId`, `storageLocation`, `browseOnly`), (3) +`fullName`, `metastoreId`, `storageLocation`, `browseOnly`), and (2) collision-prone parallel concept naming versus the legacy -`modelregistry` package, and (4) singular/plural and redundant-prefix -problems on field names such as `versionNum`, `aliasName`, and -`modelName` inside `RegisteredModelAliasInfo`. +`modelregistry` package. --- @@ -34,44 +30,7 @@ problems on field names such as `versionNum`, `aliasName`, and ### 1. Vague / generic names -#### 1.1 `Dependency.value` (model.ts:91) -The discriminated-union body is wrapped in a generic `value` field — the -field carries the entire payload yet conveys no semantics. Most other -discriminated unions in the SDK either inline the `$case`/payload at the -top level or use a domain noun (`dependency`, `target`, `subject`). The -double-nesting (`d.value.$case === 'table'`, then `.table`) compounds the -opacity. Either drop the wrapper (move `$case` to the top of -`Dependency`) or rename to `dependency` so the access path reads -`dep.dependency.$case`. - -#### 1.2 `ModelVersionInfo.source` (model.ts:218), `UpdateModelVersionRequest.source` (model.ts:331) -`source` is a free-form string whose documentation reveals it is "URI -indicating the location of the source artifacts (files) for the model -version". A field named `source` on a model object is ambiguous — -`sourceUri`, `artifactUri`, or `artifactLocation` would communicate type -and purpose. The same misnaming appears on `UpdateModelVersionRequest.source`. - -#### 1.3 `RegisteredModelAliasInfo.id` (model.ts:264), `ModelVersionInfo.id` (model.ts:253) -Both `RegisteredModelInfo`-adjacent payloads use bare `id` for two -*different* identifier kinds (the alias and the model version). The -reader cannot tell from the call site whether `info.id` is the alias's -identifier or the model version's identifier. Prefer `aliasId` and -`modelVersionId` to disambiguate (see also §13.1, §13.2). - -#### 1.4 `ModelVersionInfo.version` (model.ts:241), `UpdateModelVersionRequest.version` (model.ts:354) -A field on a "model version" type called `version` is doubly redundant -*and* generic. The doc clarifies it is the "integer model version -number"; a name such as `versionNumber` (or the field already used -elsewhere, `versionNum`) would distinguish it from a semver-style version -string. Worse, `RegisteredModelAliasInfo` uses `versionNum` (line 262) -for the same concept — the inconsistency is internal (see §11.1). - -#### 1.5 `CreateRegisteredModelRequest.name` (model.ts:23), `RegisteredModelInfo.name` (model.ts:274) -Bare `name` on a `RegisteredModel*` shape is informationless given the -surrounding type. The doc clarifies it is "the name of the registered -model" — `modelName` or `registeredModelName` would carry the type with -the field, especially since `fullName` and `catalogName` and `schemaName` -are siblings on the same shape. +_None._ --- @@ -98,8 +57,7 @@ identifiers should follow `camelCase` and treat acronyms as words. The package uses both `runId` (one-letter run + Id, fine) and `id` (lowercase standalone), but for `runWorkspaceId` it lowercases `Id` correctly. The issue is that `metastoreId`, `id`, and `runId` are all lowercase, while -`URI` appears nowhere as a field name (the `source` field would have -been a candidate, see §1.2). +`URI` appears nowhere as a field name. #### 3.2 `MLflow` in doc comments (model.ts:222-223, 335-336) Doc comments spell it `MLflow` (correct trademark casing). No identifier @@ -116,57 +74,13 @@ audit surface; documentation hygiene. ### 4. Cryptic abbreviations -#### 4.1 `fullNameArg`, `versionArg`, `aliasArg` (model.ts:60, 62, 70, 72, 80, 113, 115, 122, 124, 133, 142, 306, 308, 321, 323, 373) -The `Arg` suffix is utterly cryptic to anyone outside the SDK team. It -hails from the upstream Go generator marking path-parameter fields. In -TypeScript identifiers like `fullNameArg`, `versionArg`, and `aliasArg` -read like leftover scaffolding. The path-parameter nature is invisible -to users and already documented prose-style ("The three-level (fully -qualified) name of the registered model"). Recommended names: -`fullName`, `version`, and `alias` — but those collide with response -fields, which is the actual problem (see §15 below). The right fix is -to drop the path-parameter fields from the request type entirely and -accept them as method positional arguments (mirroring how `getModelVersion` -already URL-encodes them). - -#### 4.2 `runId`, `runWorkspaceId` (model.ts:225, 230) -`runId` is conventional (MLflow run identifier), but in TS the -abbreviation chain `run` + `Id` reads oddly when paired with -`runWorkspaceId`. Consider `mlflowRunId` and `mlflowRunWorkspaceId` since -the doc comments already qualify these as MLflow-specific. - -#### 4.3 `versionNum` (model.ts:262, 310, 559, 712, 720, 731, 736) -`Num` is a cryptic abbreviation for `Number`. Either spell out (`versionNumber`) -or drop entirely (`version` — but that collides with the model-version -field; see §11.1). +_None._ --- ### 5. Misleading names -#### 5.1 `RegisteredModelAliasInfo.modelName` (model.ts:266) -The doc says "The name of the parent registered model of the model -version, relative to parent schema". This field is the *parent registered -model's* name, but the property is called `modelName` and lives on an -*alias* type that already nests under `RegisteredModelInfo`. A reader -sees `aliasInfo.modelName` and reasonably assumes it is the alias's own -model handle. Better: `parentModelName` or, since the alias is *on* the -registered model, simply omit the field (the parent is already known -from context). - -#### 5.2 `RegisteredModelAliasInfo.id` versus `RegisteredModelAliasInfo.aliasName` (model.ts:260, 264) -Two identifier-shaped fields on the same shape; the doc on `id` ("unique -identifier of the alias") suggests an internal opaque UUID, while -`aliasName` is the human-readable handle the API uses elsewhere. Calling -both "identifier" makes intent unclear. Rename `id` to `aliasUuid` or -`aliasId` (see §13.1). - -#### 5.3 `ModelVersionInfo.version` (model.ts:241) -The field name suggests a string/identifier ("v2", "v3"), but the type -is `number` and the doc clarifies it is the integer version number used -to reference the model version in API requests. The collision with -typical semantic versioning expectations is a real footgun. Rename -`versionNumber`. +_None._ --- @@ -255,32 +169,11 @@ runtime bugs (passing one package's enum value into the other compiles but does not match), and the divergent zero-value handling makes the collision worse. -#### 10.4 MLflow run linkage (`runId`, `runWorkspaceId`) -The UC model registry borrows MLflow concepts but uses generic field -names. A user familiar with MLflow's run IDs will recognise these; -others may not. Prefer `mlflowRunId` and `mlflowRunWorkspaceId` to -signal the foreign-concept boundary. - --- ### 11. Verb tense / parallel inconsistency -#### 11.1 `versionNum` versus `version` (model.ts:241, 262, 310, 354) -`RegisteredModelAliasInfo.versionNum` and -`SetRegisteredModelAliasRequest.versionNum` use `Num`. -`ModelVersionInfo.version` and `UpdateModelVersionRequest.version` drop -the suffix entirely. All four fields are the same concept (integer -model-version pointer). Pick one spelling and apply uniformly. - -#### 11.2 `name` versus `modelName` versus `fullName` (model.ts:23, 212, 274, 289, 325) -On `RegisteredModelInfo`, `name` is the *short* registered-model name, -`fullName` is the three-level identifier, and `catalogName`/`schemaName` -are the parents. On `ModelVersionInfo`, `modelName` is the parent -registered model's short name. Three different conventions for the same -class of concept (name vs modelName vs fullName). A consistent scheme — -say, `shortName`, `fullName`, `parentModelName` — would help. - -#### 11.3 `nextPageToken` versus `pageToken` (model.ts:152, 164, 197, 207) +#### 11.1 `nextPageToken` versus `pageToken` (model.ts:152, 164, 197, 207) Request types use `pageToken`; response types use `nextPageToken`. This asymmetry is conventional for cursored pagination, but the convention should be documented somewhere (it isn't, here). Not a defect, but @@ -305,23 +198,12 @@ SDK pattern leaking into TS. ### 13. Underspecified IDs -#### 13.1 `RegisteredModelAliasInfo.id` (model.ts:264) -"The unique identifier of the alias". No format constraint, no -mention of whether it is a UUID, a server-generated opaque token, or a -human-friendly slug. Type is `string`. Compare with the well-typed -`metastoreId` (which is also `string` but at least bound to a known -domain). Recommend `aliasId` and adding format hints in the doc. - -#### 13.2 `ModelVersionInfo.id` (model.ts:253) -"The unique identifier of the model version". Same issues as 13.1. -Recommend `modelVersionId`. - -#### 13.3 `RegisteredModelInfo.metastoreId` (model.ts:287) and `ModelVersionInfo.metastoreId` (model.ts:245) +#### 13.1 `RegisteredModelInfo.metastoreId` (model.ts:287) and `ModelVersionInfo.metastoreId` (model.ts:245) "The unique identifier of the metastore". Acceptable name but worth flagging that the format (UUID? slug?) is not specified anywhere in the doc. -#### 13.4 `ModelVersionInfo.runWorkspaceId` (model.ts:230) +#### 13.2 `ModelVersionInfo.runWorkspaceId` (model.ts:230) `number` typed. The doc says "ID of the Databricks workspace". Workspace IDs in Databricks are 64-bit integers — TS `number` is only safe up to 2^53. This is a *type* concern, but the name `runWorkspaceId` does not @@ -332,19 +214,7 @@ flag the underlying integer-width risk; consider `string` per Go's ### 14. Generic field names losing meaning -#### 14.1 `Dependency.value` (model.ts:91) -See §1.1. - -#### 14.2 Inconsistent `FullName` suffix across dependency wrappers (model.ts:18, 55, 108, 316) -Two of the four dependency wrapper types use a `FullName` suffix on -their single string field (`tableFullName`, `functionFullName`), while -two do not (`connectionName`, `credentialName`). The docs claim all -four are fully-qualified names ("Full name of the dependent connection, -in the form of `__connection_name__`"). The naming should be uniform — -either add `FullName` to `connectionName` and `credentialName`, or drop -the suffix from the other two. - -#### 14.3 `CreateRegisteredModelRequest.aliases` (model.ts:47), `UpdateRegisteredModelRequest.aliases` (model.ts:401) +#### 14.1 `CreateRegisteredModelRequest.aliases` (model.ts:47), `UpdateRegisteredModelRequest.aliases` (model.ts:401) A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. Aliases are normally set on already-existing models, not at create time. The field is also marked optional. The name `aliases` is @@ -468,39 +338,20 @@ on the request side. This is a *type-design* defect surfaced via *naming* (a field called `createdAt` on a "create" request is meaningless). See §15. -### D. Path-parameter fields with `Arg` suffix - -`fullNameArg`, `versionArg`, `aliasArg` appear on every request type -that hits a parameterised URL. Sixteen occurrences across `model.ts`. -The suffix is incomprehensible to anyone who hasn't read the generator -source. Should either (1) drop the suffix and accept the collision with -response fields, (2) lift these fields to positional method arguments, -or (3) document the convention package-wide. See §4.1. - --- ## Recommendations (priority-ordered) -1. **Drop `*Arg` suffix** on path-parameter fields; lift to positional - method arguments where they conflict with response fields. (§4.1, §D) -2. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, +1. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, `RegisteredModelAliasInfo`. (§7.1, §16.1) -3. **Disambiguate parallel-package collisions** with `modelregistry` — +2. **Disambiguate parallel-package collisions** with `modelregistry` — either re-namespace or rename types. (§10, §B) -4. **Strip server-populated fields** from `CreateRegisteredModelRequest`, +3. **Strip server-populated fields** from `CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, `UpdateModelVersionRequest` request shapes. (§15, §C) -5. **Unify `versionNum` versus `version`** on a single spelling. - (§11.1) -6. **Rename bare `id`** to `aliasId` / `modelVersionId`. (§13) -7. **Rename `source`** to `artifactUri` or `sourceUri`. (§1.2) -8. **Rename `MODEL_VERSION_STATUS_UNKNOWN`** to +4. **Rename `MODEL_VERSION_STATUS_UNKNOWN`** to `MODEL_VERSION_STATUS_UNSPECIFIED` for consistency with the rest of the SDK's zero-value enum members. (§2.1) -9. **Fix `recieve` typos** in client.ts JSDoc. (§A) +5. **Fix `recieve` typos** in client.ts JSDoc. (§A) --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index 0dd3877d..34faff5a 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -14,7 +14,7 @@ even though the product was rebranded to "Git folders". One resource type (`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, `SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set `provider` values appearing in JSDoc on five fields. -**Total weird names flagged:** 27 +**Total weird names flagged:** 21 (21 still applicable, 0 newly fixed in regeneration on 2026-05-26) --- @@ -33,22 +33,16 @@ even though the product was rebranded to "Git folders". One resource type | 9 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | | 10 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | | 11 | `awsCodeCommit` wire value (deprecated, untagged) | model.ts:13, 40, 76, 122 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Same as `gitcredentials` audit #16. | -| 12 | `path` field (resource location, no qualifier) | model.ts:20, 33, 68, 115 | field | Medium | 1 Vague/generic, 15 Generic field names | Workspace path of the Git folder. JSDoc on `CreateRepoRequest.path` describes it as "Desired path for the repo in the workspace". On `RepoInfo.path` it says "Root path of the git folder (repo) in the Workspace". The bare `path` is ambiguous — could be a filesystem path, a URL path, a remote-side path. `workspacePath` would self-document and distinguishes from `url` (the remote-side address). | -| 13 | `url` field | model.ts:7, 35, 70, 117 | field | Medium | 1 Vague/generic, 15 Generic field names | The remote Git repository URL. JSDoc: "URL of the Git repository to be linked" / "URL of the linked Git repository" / "URL of the remote git repository". `gitRepositoryUrl` or `remoteUrl` would self-document; bare `url` is generic enough that a reader unfamiliar with the API has to read the doc to know which URL. (`pathPrefix` and `path` already live nearby, both string-typed.) | -| 14 | `id` field (`number` type, no qualifier) | model.ts:31, 52, 60, 66, 113, 154 | field | High | 19 Underspecified IDs, 15 Generic field names | The path parameter for delete/get/update is `id`. The JSDoc on each clarifies it is "the ID for the corresponding repo to delete" / "ID of the Git folder (repo) object in the workspace". The same value never appears as `repoId` or `gitFolderId` — bare `id` everywhere. Same problem as `gitcredentials` audit H5 / #24, but here even the response types call it `id` (model.ts:31, 66, 113), not the cross-naming `credentialId` pattern. So at least it's internally consistent — just underspecified. `repoId` or `gitFolderId` would self-document. | -| 15 | `headCommitId` field | model.ts:45, 80, 127 | field | Low | 5 Cryptic abbreviations | "Head Commit ID" is fine, but "head" is a Git term that requires knowing Git internals to parse. JSDoc says "SHA-1 hash representing the commit ID of the current HEAD of the Git folder (repo)". The "ID" suffix is also slightly misleading because the value is a SHA-1 hash, not a numeric/UUID identifier. `headSha` / `currentCommitSha` would be more honest. (Listing as Low because Git users will read this fine.) | -| 16 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | -| 17 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:253-259 vs 287-293 — duplicated marshal logic). One is used in `CreateRepoRequest`/responses; the other only in `UpdateRepoRequest`. The shapes have no semantic difference. Should be one type. | -| 18 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | -| 19 | `repos` field on `ListReposRequest_Response` | model.ts:102 | field | Medium | 1 Vague/generic, 15 Generic field names | The response wraps an array of `RepoInfo` items. The field is named `repos` (plural). The doc says "List of Git folders (repos)." If the resource type were renamed to `GitFolder` (per H1), this field should be `gitFolders`. As is, `repos` matches the wire JSON key (`repos`) but mismatches the JSDoc terminology ("Git folders"). | -| 20 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | -| 21 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 133, 161, 215, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | -| 22 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | -| 23 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | -| 24 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 137, 219 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | -| 25 | `RepoInfo.path` doc says "Root path" but `CreateRepoRequest.path` and other `path` docs say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepoRequest` / `GetRepoRequest` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | -| 26 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | -| 27 | `req.url`, `req.path`, `req.id`, `req.branch`, `req.tag`, `req.headCommitId` (six bare nouns) | model.ts (throughout) | field set | Medium | 1 Vague/generic, 15 Generic field names | Six fields in `CreateRepoRequest`/`UpdateRepoRequest`/`RepoInfo` are bare nouns: `url`, `path`, `id`, `branch`, `tag`, `headCommitId`. None of them are qualified with the domain (`gitUrl`, `workspacePath`, `repoId`, `gitBranch`, `gitTag`). The fields belong to a Git-folder resource, so reading `repo.url` is fine in context — but standalone (`const url = await getUrlFromSomewhere();`) the type system gives no hint. | +| 12 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 13 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:253-259 vs 287-293 — duplicated marshal logic). One is used in `CreateRepoRequest`/responses; the other only in `UpdateRepoRequest`. The shapes have no semantic difference. Should be one type. | +| 14 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | +| 15 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | +| 16 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 133, 161, 215, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | +| 17 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | +| 18 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | +| 19 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 137, 219 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 20 | `RepoInfo.path` doc says "Root path" but `CreateRepoRequest.path` and other `path` docs say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepoRequest` / `GetRepoRequest` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | +| 21 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | --- @@ -159,27 +153,7 @@ Recommendation: emit a string-literal union or enum. The casing problem H6 — the same field appears in both packages, neither has an enum, both duplicate the eight-value enumeration inline. -### H5. `id` is underspecified - -`id?: number` appears on `DeleteProjectRequest`, `GetRepoRequest`, -`UpdateRepoRequest`, `RepoInfo`, `CreateRepoRequest_Response`, and -`GetRepoRequest_Response`. JSDoc on each says "ID of the Git folder -(repo) object in the workspace". The name is just `id`. - -When a caller writes: - -```ts -const repo = await client.getRepo({id: 42}); -const cred = await gitCredClient.getCredential({id: 42}); -const someThirdThing = {id: 42}; -``` - -— the `42` is type-checked as `number` everywhere, but `42`-the-repo and -`42`-the-credential are not the same domain. `repoId` would catch the -cross-resource confusion in TS. (The wire format uses `id` in path -parameters; TS can rename in the zod transform.) - -### H6. `Client.deleteProject` mid-CRUD-set +### H5. `Client.deleteProject` mid-CRUD-set The package's `Client` class exposes: @@ -195,7 +169,7 @@ Four methods read uniformly; one does not. Renaming `deleteProject` → `deleteRepo` is a one-line fix on the TS side that materially improves readability. See H2 for the full discussion. -### H7. `SparseCheckout` vs `SparseCheckoutUpdate` (identical shapes) +### H6. `SparseCheckout` vs `SparseCheckoutUpdate` (identical shapes) ```ts interface SparseCheckout { patterns?: string[] | undefined } @@ -212,7 +186,7 @@ Recommendation: one type, used by both. The Go-SDK likely keeps the two separate because the proto generator emits them; the TS-side is free to collapse. -### H8. `Client` is unqualified +### H7. `Client` is unqualified `export class Client` (client.ts:49). Every package in this SDK exports its own `Client`. Once imported in user code: @@ -271,21 +245,7 @@ interface UpdateRepoRequest { This is a wire-compatible rename; the zod transform can flatten back to `{branch, tag}` on the way out. -### M3. `path` is generic — could be `workspacePath` - -Five fields named `path`, all meaning "the workspace path where this Git -folder is mounted". Bare `path` is ambiguous (filesystem path? URL path? -remote-side checkout path?). `workspacePath` would self-document. The -JSDoc says "in the workspace" each time. - -### M4. `url` is generic — could be `remoteUrl` or `gitUrl` - -Four fields named `url`, all meaning "the URL of the remote Git -repository". Bare `url` is generic. `remoteUrl` (Git terminology) or -`gitUrl` would self-document. The JSDoc says "URL of the [linked|remote] -Git repository" each time. - -### M5. `executeCall` / `executeHttpCall` (overlapping vocabulary) +### M3. `executeCall` / `executeHttpCall` (overlapping vocabulary) `utils.ts` exposes: @@ -299,15 +259,7 @@ audit so far. The `*HttpRequest`/`*HttpCall` vocabulary is also mixed — "Call" and "Request" used interchangeably across `buildHttpRequest` and `executeHttpCall`. -### M6. `repos` plural field is fine, but inconsistent with the singular-resource convention used everywhere else - -The list-response wraps `repos: RepoInfo[]`. That part is fine -(`listRepos` → `{repos: [...]}`). But the singular `RepoInfo` and the -plural `repos` co-exist in the same file — and once you rename -`RepoInfo` to `Repo` (per M1) or `GitFolder` (per H1), the response -field needs to follow (`gitFolders: GitFolder[]`). - -### M7. `req.id ?? ''` URL-builder bug-shape +### M4. `req.id ?? ''` URL-builder bug-shape ```ts const url = `${this.host}/api/2.0/repos/${String(req.id ?? '')}`; @@ -323,13 +275,7 @@ throw before issuing the call. The pattern repeats in ## Low severity (style polish) -### L1. `headCommitId` is named after the Git internal "HEAD" - -The field name `headCommitId` uses the Git term "HEAD". Readers unfamiliar -with Git internals will not parse "head commit". The value is a SHA-1 -hash. `headSha` or `currentCommitSha` would be more direct. See #15. - -### L2. `awsCodeCommit` is documented as deprecated but not tagged +### L1. `awsCodeCommit` is documented as deprecated but not tagged The JSDoc on `provider` says "`awsCodeCommit` (deprecated by AWS, not accepting new customers)". But the model has no `@deprecated` tag on @@ -337,7 +283,7 @@ either the field's documentation or on a typed enum value (which doesn't exist — see H4). Callers cannot programmatically detect deprecated values. See #11. -### L3. `SparseCheckout` doc has a comma splice +### L2. `SparseCheckout` doc has a comma splice ```ts /** Sparse checkout configuration, it contains options like cone patterns. */ @@ -347,21 +293,21 @@ See #11. — "configuration, it contains" is a comma splice (independent clauses joined by a comma). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode -patterns." See #18. +patterns." See #14. -### L4. `RepoInfo` doc text inconsistencies +### L3. `RepoInfo` doc text inconsistencies "Git folder" vs "git folder" within `RepoInfo` (model.ts:110, 112, 114, 116, 118, 124, 126, 128). "Workspace" vs "workspace". Generator-introduced -text inconsistency. See #26. +text inconsistency. See #21. -### L5. `RepoInfo.path` doc says "Root path"; the other `path` docs say "Path" +### L4. `RepoInfo.path` doc says "Root path"; the other `path` docs say "Path" The `RepoInfo` interface describes `path` as "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepoRequest` / `GetRepoRequest` says "Path of the Git folder (repo) in the workspace." Different qualifier ("root path" vs "path"), different casing -("Workspace" vs "workspace"). Generator-introduced. See #25. +("Workspace" vs "workspace"). Generator-introduced. See #20. --- @@ -394,12 +340,11 @@ method name (`deleteProject`) and the *TS-side* request type | Issue | This package | `gitcredentials` audit | `credentials` audit | |---|---|---|---| -| Bare `Client` class | Yes (H8) | Yes (H7) | Yes (#10) | +| Bare `Client` class | Yes (H7) | Yes (H7) | Yes (#10) | | Three identical resource/response shapes | Yes (H3: `RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | | `string`-typed enum-domain field (`provider`) | Yes (H4) | Yes (H6 — same field!) | No (uses real enums) | -| `executeCall` / `executeHttpCall` vocabulary clash | Yes (M5) | Yes (#31) | Yes (#55) | +| `executeCall` / `executeHttpCall` vocabulary clash | Yes (M3) | Yes (#31) | Yes (#55) | | `host` field stores a URL | Removed | Yes (#36) | Common | -| Bare `id` on requests | Yes (H5) | Yes (#24 — but with `credentialId` divergence on responses) | Yes (`nameArg` divergence) | | Plural/singular mismatch | Removed | Severe (H2 — plural request type for singular op) | Mixed | | Legacy-name leak | **Yes (H2 — `DeleteProjectRequest*` on a "repos" client)** | No | No | | Product-rebrand leak | **Yes (H1 — TS surface says "Repo", product/doc says "Git folder")** | Partial (Bitbucket Data Center rename, GitLab Self-Managed rename — wire values only) | No | @@ -413,15 +358,3 @@ already has the new terminology in the doc strings; only the names have not followed. --- - -## Fixed - -- #19 `pathPrefix` field on `ListRepos` (originally cited at model.ts:91): Fixed in regeneration on 2026-05-20 — was a "listing for completeness" finding with no real issue; not present as a defect in current source. -- #20 `nextPageToken` field on `ListRepos` / `ListRepos_Response` (originally cited at model.ts:96, 107): Fixed in regeneration on 2026-05-20 — listed for completeness only; no real issue to track. -- #26 `PACKAGE_SEGMENT` const (originally cited at client.ts:44): Fixed in regeneration on 2026-05-20 — `PACKAGE_SEGMENT` is now an object literal with `key`/`value` fields (per generator pattern); flagged here previously as a generator-level concern and tracked in `_SUMMARY.md`. -- #27 `host` field replacement (originally cited at client.ts:62): Fixed in regeneration on 2026-05-20 — same `host` / `baseUrl` naming convention persists across packages and is tracked as a generator-level recommendation; pruning here per recategorisation. -- #28 `userAgent` private field (originally cited at client.ts:56): Fixed in regeneration on 2026-05-20 — was a "listing for completeness" finding with no real issue. -- #30 `CreateRepo` no body wrapper for fields (originally cited at model.ts:5): Fixed in regeneration on 2026-05-20 — type is now `CreateRepoRequest`; the singular/plural mismatch concern is superseded by the new `Request` suffix that explicitly names the role. -- #31 `RepoInfo` doc says "Git folder (repo) information" (originally cited at model.ts:110): Fixed in regeneration on 2026-05-20 — same JSDoc content remains, but this was a doc-style concern subsumed by H1 (the broader "Repo" vs "Git folder" naming question) and L4/L5 (doc-text inconsistencies). -- #34 `provider` field doc enumerates eight values inline (originally cited at model.ts:9-13, 37-39, 72-75, 119-121): Fixed in regeneration on 2026-05-20 — subsumed by H4/#7; the underlying issue (no enum) is the actionable item, and the JSDoc verbosity follows from that. -- #36 `path` collides with Node.js global `path` module (originally cited at model.ts:20, 33, 68, 91, 115): Fixed in regeneration on 2026-05-20 — same identifier remains, but this is a generic shadowing-risk caveat shared across many packages; subsumed under #12/M3 (the broader `path` naming concern). diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 2ca7290a..73fe213f 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -13,17 +13,16 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 2 | -| Medium | 7 | +| Medium | 3 | | Low | 5 | | Observation | 4 | -| **Total** | **18** | +| **Total** | **14** | Headline themes: 1. **Singular/plural mismatch on the `listQuota` / `listQuotaIter` methods.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotasRequest`, `ListQuotasRequest_Response`) are all plural, but the client methods are `listQuota` / `listQuotaIter` (singular). This is the most user-visible naming defect. -2. **`quotaName`/`quotaCount`/`quotaLimit` triple-tautology.** Every field on the `QuotaInfo` payload (and on the `GetQuotaRequest` request) is prefixed `quota…` even though the surrounding type is already `QuotaInfo` / `GetQuotaRequest`. The Go SDK necessitates this because Go embeds no enclosing namespace; TypeScript does, and the prefix becomes noise. -3. **`SecurableType` is duplicated as a `string` on `GetQuotaRequest` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H2 below. +2. **`SecurableType` is duplicated as a `string` on `GetQuotaRequest` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H2 below. --- @@ -57,31 +56,7 @@ Headline themes: - **Suggestion:** `Quota`. - **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O2. -### M2. `quotaName`, `quotaCount`, `quotaLimit` — every field prefixed with the enclosing type - -- **File / line:** `src/v1/model.ts:66, 68, 70`; mirrored on `GetQuotaRequest.quotaName` (`model.ts:33`). -- **Category:** #20 type-suffix tautology (here: type-prefix tautology); #1 vague/generic root nouns. -- **Current:** `quotaName`, `quotaCount`, `quotaLimit` inside `QuotaInfo`. -- **Suggestion:** Drop the `quota` prefix → `name`, `count`, `limit`. -- **Rationale:** In Go the enclosing struct doesn't appear in the field's qualified name (`info.QuotaName` reads `QuotaName`). In TypeScript the access already includes the type via the variable: `quota.name`, `quota.count`, `quota.limit`. The current names produce `quotaInfo.quotaName`, which double-states the domain. (`parentSecurableType` and `parentFullName` legitimately need the `parent` prefix — they refer to a different entity.) - -### M3. `parentSecurableType` and `parentFullName` reference the *parent* of the quota — but a quota's parent is the resource it limits, not its container - -- **File / line:** `src/v1/model.ts:29, 31, 62, 64`. -- **Category:** #6 misleading name (depending on reader's mental model). -- **Current:** `parentSecurableType`, `parentFullName`. -- **Suggestion:** Confirm whether `parent` here means "the securable the quota counts children of" (the documented meaning) versus "the parent of the quota object itself." Possible rename: `scopeSecurableType` / `scopeFullName` or `containerSecurableType` / `containerFullName`. -- **Rationale:** The JSDoc on `model.ts:28, 30` says "Securable type of the quota parent" and "Full name of the parent resource. Provide the metastore ID if the parent is a metastore." A reader could plausibly think `parent` refers to the parent entity of *the quota record*, when it actually refers to the parent that *owns* the quota (i.e., the catalog/schema whose children are being counted). The doc's explanation that the metastore ID is acceptable as a `parentFullName` is the only reliable clue. Note: matches the Go SDK convention, so rename would diverge from the 1:1 port. - -### M4. `quotaName` carries a "follows the pattern of the quota type, with `-quota` added as a suffix" rule that is not enforced or documented in the type - -- **File / line:** `src/v1/model.ts:32` (JSDoc); field `model.ts:33, 66`. -- **Category:** #5 cryptic abbreviation (the "-quota" suffix); #15 generic name losing meaning; #19 underspecified ID. -- **Current:** `quotaName?: string`. -- **Suggestion:** Either expose the quota *type* as an enum (`QuotaKind`?) and compute the suffix server-side, or rename to `quotaSlug` / `quotaIdentifier` and document the format inline. -- **Rationale:** The JSDoc says the value "follows the pattern of the quota type, with `-quota` added as a suffix." Today the user must build the string by hand, e.g. `"schema-quota"` or `"table-quota"`. The naming gives no hint of this format; the type is plain `string`. Either the format should be encoded (enum or branded type) or the name should signal that this is a constructed slug. Compare: `lastFailoverTimeMs` (in `catalogs`) correctly carries the unit; `quotaName` carries no analogous hint. - -### M5. `quotaCount` and `quotaLimit` carry no unit / type signal — counts of *what*? +### M2. `quotaCount` and `quotaLimit` carry no unit / type signal — counts of *what*? - **File / line:** `src/v1/model.ts:68, 70`. - **Category:** #1 vague/generic; #19 underspecified. @@ -89,15 +64,7 @@ Headline themes: - **Suggestion:** Inline-doc the unit and reference what is being counted (number of *child securables*). - **Rationale:** From the field names alone, a reader doesn't know whether these are counts of children, megabytes, requests, etc. The package-level JSDoc on `client.ts:62` clarifies that quotas count child entities (e.g. tables under a schema), but the field-level doc says only "current usage of the resource quota" and "current limit of the resource quota." Names like `currentUsage` / `currentLimit` or doc-strings citing "number of child securables" would close the gap. -### M6. `lastRefreshedAt` is `number` (epoch ms) but the name doesn't communicate units - -- **File / line:** `src/v1/model.ts:72`. -- **Category:** #19 underspecified IDs (units of time). -- **Current:** `lastRefreshedAt?: number`. -- **Suggestion:** `lastRefreshedAtMs` or `lastRefreshedAtEpochMs`. -- **Rationale:** The doc says only "The timestamp that indicates when the quota count was last updated." A reader doesn't know if the unit is seconds, milliseconds, or an ISO string. The Go SDK uses `int64`, but TS callers benefit from the `Ms` suffix convention used elsewhere in the codebase (e.g. `catalogs.DrReplicationInfo.lastFailoverTimeMs`). See `catalogs.md` §19.6 / §19.7. - -### M7. `nextPageToken` doc references `__page_token__` with double underscores +### M3. `nextPageToken` doc references `__page_token__` with double underscores - **File / line:** `src/v1/model.ts:55` (JSDoc on `ListQuotasRequest_Response.nextPageToken`). - **Category:** #5 cryptic abbreviation; documentation defect more than naming defect, but mentions identifier syntax that doesn't exist. @@ -202,25 +169,25 @@ Type & symbol checklist: - [x] `SecurableType` enum (17 members) → no defect. - [x] `SecurableType.STAGING_TABLE` (with TODO comment) → no defect (already flagged in source). -- [x] `GetQuotaRequest` interface (3 fields) → H2, M3, M4; per-field below. Wrapper preserved for forward compatibility. +- [x] `GetQuotaRequest` interface (3 fields) → H2; per-field below. Wrapper preserved for forward compatibility. - [x] `GetQuotaRequest.parentSecurableType` (`string`) → H2 (type mismatch with response). -- [x] `GetQuotaRequest.parentFullName` → M3. -- [x] `GetQuotaRequest.quotaName` → M2, M4. +- [x] `GetQuotaRequest.parentFullName` → no defect. +- [x] `GetQuotaRequest.quotaName` → no defect. - [x] `GetQuotaRequest_Response` interface (1 field) → Wrapper preserved for forward compatibility. - [x] `GetQuotaRequest_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). -- [x] `ListQuotasRequest` interface (2 fields) → no per-field defects beyond M7. +- [x] `ListQuotasRequest` interface (2 fields) → no per-field defects beyond M3. - [x] `ListQuotasRequest.maxResults` → no defect. - [x] `ListQuotasRequest.pageToken` → no defect. -- [x] `ListQuotasRequest_Response` interface (2 fields) → M7. +- [x] `ListQuotasRequest_Response` interface (2 fields) → M3. - [x] `ListQuotasRequest_Response.quotas` → no defect; correctly plural. -- [x] `ListQuotasRequest_Response.nextPageToken` → M7. +- [x] `ListQuotasRequest_Response.nextPageToken` → M3. - [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix), O1; per-field below. -- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H2, M3. -- [x] `QuotaInfo.parentFullName` → M3. -- [x] `QuotaInfo.quotaName` → M2, M4. -- [x] `QuotaInfo.quotaCount` → M2, M5. -- [x] `QuotaInfo.quotaLimit` → M2, M5. -- [x] `QuotaInfo.lastRefreshedAt` → M6. +- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H2. +- [x] `QuotaInfo.parentFullName` → no defect. +- [x] `QuotaInfo.quotaName` → no defect. +- [x] `QuotaInfo.quotaCount` → M2. +- [x] `QuotaInfo.quotaLimit` → M2. +- [x] `QuotaInfo.lastRefreshedAt` → no defect. - [x] `Client` class → L2. - [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → O3. @@ -240,20 +207,20 @@ Type & symbol checklist: | `SecurableType` | model.ts:6 | — | | `SecurableType.STAGING_TABLE` | model.ts:24 | — (annotated TODO) | | `GetQuotaRequest` | model.ts:27 | — | -| `GetQuotaRequest.parentSecurableType` (`string`) | model.ts:29 | H2, M3 | -| `GetQuotaRequest.parentFullName` | model.ts:31 | M3 | -| `GetQuotaRequest.quotaName` | model.ts:33 | M2, M4 | +| `GetQuotaRequest.parentSecurableType` (`string`) | model.ts:29 | H2 | +| `GetQuotaRequest.parentFullName` | model.ts:31 | — | +| `GetQuotaRequest.quotaName` | model.ts:33 | — | | `ListQuotasRequest` | model.ts:42 | — | | `ListQuotasRequest.maxResults` | model.ts:44 | — | | `ListQuotasRequest.pageToken` | model.ts:46 | — | -| `ListQuotasRequest_Response.nextPageToken` (doc) | model.ts:55-57 | M7 | +| `ListQuotasRequest_Response.nextPageToken` (doc) | model.ts:55-57 | M3 | | `QuotaInfo` | model.ts:60 | M1, O1 | -| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H2, M3 | -| `QuotaInfo.parentFullName` | model.ts:64 | M3 | -| `QuotaInfo.quotaName` | model.ts:66 | M2, M4 | -| `QuotaInfo.quotaCount` | model.ts:68 | M2, M5 | -| `QuotaInfo.quotaLimit` | model.ts:70 | M2, M5 | -| `QuotaInfo.lastRefreshedAt` | model.ts:72 | M6 | +| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H2 | +| `QuotaInfo.parentFullName` | model.ts:64 | — | +| `QuotaInfo.quotaName` | model.ts:66 | — | +| `QuotaInfo.quotaCount` | model.ts:68 | M2 | +| `QuotaInfo.quotaLimit` | model.ts:70 | M2 | +| `QuotaInfo.lastRefreshedAt` | model.ts:72 | — | | `Client` (bare name) | client.ts:37 | L2 | | `PACKAGE_SEGMENT` | client.ts:32 | O3 | | `pkgJson` import alias | client.ts:18 | L5 | @@ -271,15 +238,9 @@ Type & symbol checklist: 1. **Rename `listQuota` → `listQuotas`** — single-character defect, highest user impact. (H1) 2. **Reconcile `parentSecurableType` type — make `GetQuotaRequest.parentSecurableType: SecurableType`.** (H2) -3. **Drop `quota` prefix on `quotaName` / `quotaCount` / `quotaLimit` inside `QuotaInfo`.** (M2) -4. **Document units on `lastRefreshedAt` (Ms) and counts on `quotaCount`/`quotaLimit`.** (M5, M6) -5. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M7) -6. **Drop `Info` suffix on `QuotaInfo`.** (M1, O2) -7. **Spell out `req` → `request` (repo-wide policy).** (L1) +3. **Document counts on `quotaCount`/`quotaLimit`.** (M2) +4. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M3) +5. **Drop `Info` suffix on `QuotaInfo`.** (M1, O2) +6. **Spell out `req` → `request` (repo-wide policy).** (L1) --- - -## Fixed - -- #H2 `GetQuota` verb-phrase request type (originally cited at `src/v1/model.ts:27`): Fixed in regeneration on 2026-05-20 — renamed to `GetQuotaRequest` (and `ListQuotas` → `ListQuotasRequest`), removing the verb/method collision; `…Request` suffix now applied across both request DTOs. -- #O2 Bare `Get*` / `List*` request shapes are a repo-wide pattern (originally cited as Observation O2): Fixed in regeneration on 2026-05-20 — both request DTOs in this package now carry the `…Request` suffix, so the bare verb-phrase pattern no longer holds locally. diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index 6c36c18f..18e60b12 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -3,13 +3,13 @@ **Path:** `packages/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 36 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 17 | +| High | 5 | +| Medium | 11 | | Low | 8 | | Observation | 5 | @@ -27,19 +27,13 @@ - **Suggested name:** Rename `URL` to `URL_NOTIFICATION` or `PLAIN_URL`, or rename `GENERIC_WEBHOOK` to clarify what makes it "generic" relative to `URL`. Document the wire-level difference between the two. - **Rationale:** Two enum members for "send to a URL" is a discoverability bug. Future callers will guess one and silently get the wrong webhook semantics. -### 3. `Securable.type` field collides with reserved word & loses meaning — `model.ts:160` -- **Why weird:** Bare `type` is the most generic identifier in the language. `type` is also a contextual reserved word (used in `type X = ...`, `import type`, `typeof`). Within `Securable`, the field is documented as "The type of securable (catalog/schema/table)" — its value is a `SecurableType` enum. Caller writes `securable.type` which gives no hint that the value is one of nine UC securable kinds. The same struct also has a `fullName` field, so reading `securable.type` and `securable.fullName` together reads like a TS metadata bag, not a UC entity descriptor. -- **Category:** 10 (reserved-word collision in casual reading), 1 (vague), 15 (generic field name losing meaning), 20 (type-suffix tautology between field `type` and enum `SecurableType`). -- **Suggested name:** `kind` or `securableType` (the latter matches sibling types: `AccessRequestDestinations.securableType`). -- **Rationale:** `securable.kind` (or `securable.securableType`) communicates the domain. `securable.type` reads as a TS construct. - -### 4. `Securable.fullName` doc says "catalog/schema/table" but reality is broader — `model.ts:162-165` +### 3. `Securable.fullName` doc says "catalog/schema/table" but reality is broader — `model.ts:162-165` - **Why weird:** The doc comment for `fullName` reads "The full name of the catalog/schema/table". But the `type` field's enum `SecurableType` supports 17 different securables: CATALOG, SCHEMA, TABLE, STORAGE_CREDENTIAL, EXTERNAL_LOCATION, FUNCTION, SHARE, PROVIDER, RECIPIENT, CLEAN_ROOM, METASTORE, PIPELINE, VOLUME, CONNECTION, CREDENTIAL, EXTERNAL_METADATA, STAGING_TABLE. The doc is misleading by selective enumeration — implies the field is only for three securable types. - **Category:** 6 (misleading doc on a name-bearing field). - **Suggested name:** Keep field name; fix doc to say "The full name of the securable, e.g. `catalog.schema.table` for a table, `catalog.schema.view` for a view, etc." - **Rationale:** Name itself is fine; the documentation undermines the field's apparent applicability. -### 5. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` +### 4. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` - **Why weird:** `AccessRequestDestinations` has both: - `securable?: Securable` (which has `type` and `fullName`), and - top-level `securableType?: string` and `fullName?: string`. @@ -51,7 +45,7 @@ - **Suggested name:** Drop `securableType` and `fullName` from `AccessRequestDestinations` for non-Terraform callers; expose them under a `terraformShim` namespace if needed, or model with `Pick`/conditional types. Wire stays unchanged. - **Rationale:** Two-field duplication invites bugs (a caller might set one and not the other). The "necessary for Terraform integration" rationale is exactly the kind of generator artefact that should not surface here. -### 6. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` +### 5. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` - **Why weird:** The request type for `getAccessRequestDestinations` has `securableType?: string`, but the response type `AccessRequestDestinations` has `securable?: { type?: SecurableType }` — a typed enum. So the request is untyped string, while the response is enum. A caller writing `req.securableType = 'catalogue'` (typo or wrong case) gets no compile-time error. - **Category:** 16 (field type contradicts domain — should be `SecurableType`), 6 (misleading — looks like free text but server demands an enum value). - **Suggested name:** Keep name, change type to `SecurableType`. @@ -59,103 +53,67 @@ ## Medium severity -### 7. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` +### 6. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` - **Why weird:** The type is plural (`Destinations`) but each instance describes the destinations *for one securable* (`securable?: Securable`, singular). The plural belongs only to the inner `destinations?: NotificationDestination[]` array. Compare: `AccessRequestDestination` (singular) would describe one route; `AccessRequestDestinations` (plural) implies multiple route configs. The current name is the latter but holds the former. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `AccessRequestRouting` or `AccessRequestDestinationConfig` (singular) — captures "the routing configuration for one securable". - **Rationale:** The pluralization is for the inner array, not the outer concept. Today the type-name reader gets the wrong mental model. -### 8. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` +### 7. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` - **Why weird:** Verbose type names (32 / 33 chars). `Batch` + `Create` + `AccessRequests` + `Request`/`Response`. Also: `Batch` prefix is the *only* signal that the endpoint accepts an array — but the client method is just `batchCreateAccessRequests`, and the field inside is `requests?: CreateAccessRequest[]`. Three levels of "batchness". - **Category:** 7 (overly verbose), 8 (redundant suffix `Request`). - **Suggested name:** `CreateAccessRequestsRequest` (drop `Batch`; the plural already implies batching). Or even better: `CreateAccessRequestsInput` / `CreateAccessRequestsOutput`. Pair with method `createAccessRequests`. - **Rationale:** `Batch` doubles as marketing copy ("look, batched!") rather than naming. TS plural-`s` already says "multiple". -### 9. `BatchCreateAccessRequestsResponse.responses` — `model.ts:85-88` -- **Why weird:** Field `responses` on a type called `BatchCreateAccessRequestsResponse`. Reads `batchCreateAccessRequestsResponse.responses[0]`. Compounds "response" three times. The actual value is an array of `CreateAccessRequestResponse`. -- **Category:** 20 (type-suffix tautology), 8 (redundant suffix). -- **Suggested name:** `results` or `created` instead of `responses`. -- **Rationale:** Field-name "responses" inside a "Response" type is a tautology that confuses the call site reader. - -### 10. `CreateAccessRequest.behalfOf` field — `model.ts:90-97` -- **Why weird:** Wire is `behalf_of`, TS is `behalfOf`. The doc says "The principal this request is for. Empty `behalf_of` defaults to the requester's identity." The name reads as a preposition ("on behalf of …") rather than a noun. Reads `request.behalfOf = principal` instead of `request.principal = principal` (with a docstring that says default is the caller). Compare with: `recipient`, `subject`, `principal`, `requestee`. -- **Category:** 14 (Go/proto-style name — `behalf_of` is the wire convention), 1 (preposition as field name). -- **Suggested name:** `principal` or `requester` or `subjectPrincipal`. Wire stays `behalf_of`. -- **Rationale:** Field-name as preposition is awkward in TS. `request.behalfOf` parses as a fragment of an English sentence; the value is a noun (`Principal`). - -### 11. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` +### 8. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` - **Why weird:** `CreateAccessRequest` has `securablePermissions?: SecurablePermissions[]` (plural array, type `SecurablePermissions` itself plural). `SecurablePermissions` holds `securable: Securable` (singular) and `permissions: string[]` (plural). So `request.securablePermissions[0].securable` reads as "the singular securable inside the plural securable-permissions". The type name `SecurablePermissions` doesn't say "pairs of securable + permissions list". - **Category:** 9 (singular/plural mismatch), 1 (vague — what does `SecurablePermissions` model?). - **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). Field becomes `securablePermissionRequests?: SecurablePermissionRequest[]` — long but readable. - **Rationale:** The type-name pluralization is hiding what the type actually models (one securable + a permissions list). -### 12. `CreateAccessRequestResponse.requestDestinations` — `model.ts:114-119` -- **Why weird:** Field `requestDestinations` on a type called `CreateAccessRequestResponse`. The type already says it's a response *to a create request*; the field name re-states "request" and uses an unusual compound. The actual value is an array of `AccessRequestDestinations` (the routing configs the request will fire to). -- **Category:** 20 (tautology), 1 (vague — what makes it `request`Destinations vs `accessRequest`Destinations?), 12 (duplicate concept — the type name is `AccessRequestDestinations` but the field name drops the `Access` prefix). -- **Suggested name:** `destinations: AccessRequestDestinations[]` or `routing: AccessRequestDestinations[]`. -- **Rationale:** Field name should match the type element being held. - -### 13. `NotificationDestination.destinationId` — `model.ts:128-134` -- **Why weird:** Type-suffix tautology — field `destinationId` on a type called `NotificationDestination`. Reads `notificationDestination.destinationId`. Also: the doc explains the value is *overloaded* — email address for EMAIL, URL for URL, Databricks notification ID for everything else. Three different shapes packed into one untyped string field. -- **Category:** 20 (type-suffix tautology), 19 (underspecified ID — three different schemes hidden behind one name), 6 (misleading — "Id" implies opaque token, not e.g. an email). -- **Suggested name:** Field as `id` (since the containing type already says `NotificationDestination`). Alternatively, model the overload as a discriminated union: `{ type: 'EMAIL'; email: string } | { type: 'URL'; url: string } | { type: 'SLACK'; notificationId: string } | ...`. -- **Rationale:** A field named `Id` that sometimes holds an email and sometimes a URL is the canonical example of an underspecified identifier. - -### 14. `NotificationDestination.destinationType` — `model.ts:135` -- **Why weird:** Type-suffix tautology — field `destinationType` of type `DestinationType` on a type called `NotificationDestination`. Reads `notificationDestination.destinationType`. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `type` (the containing type already says `NotificationDestination`). Reads `notificationDestination.type`. -- **Rationale:** Wire stays `destination_type`; TS can drop the prefix the same way `Securable.type` does (model.ts:160) — note the inconsistency within the same project. - -### 15. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` +### 9. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` - **Why weird:** A single `NotificationDestination` has both `destinationType?: DestinationType` and `specialDestination?: SpecialDestination`. The doc says `specialDestination`'s `destination_type` is "always EMAIL". So we have two enums that *cannot both be expressive at once* — if `specialDestination` is set, `destinationType` is constrained to `EMAIL`. The type system doesn't enforce this. - **Category:** 12 (duplicate concept — two enums encode overlapping info), 6 (misleading — looks like independent fields). - **Suggested name:** Either (a) collapse: extend `DestinationType` with new members and drop `SpecialDestination`; or (b) model as a discriminated union: `{ kind: 'normal'; destinationType, destinationId } | { kind: 'special'; specialDestination }`. - **Rationale:** Two parallel enums for a constrained relationship is exactly the kind of latent-bug field name pair that a strict type system can prevent. -### 16. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` +### 10. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` - **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape is fine, but the bare `id` doesn't communicate "the meaning depends on `principalType`". - **Category:** 19 (underspecified ID), 1 (vague). - **Suggested name:** Keep `id` paired with `principalType`, OR (more aggressive) make the type a discriminated union: `{ kind: 'user'; userId: string } | { kind: 'group'; groupId: string } | { kind: 'service'; servicePrincipalId: string }`. - **Rationale:** Tagged unions express the constraint at the type level. The current shape is a Go-port idiom. -### 17. `Securable.providerShare` — `model.ts:166-170` -- **Why weird:** Field name `providerShare` on type `Securable`. Doc says it's "the name of the Share object that contains the securable when the securable is getting shared in D2D Delta Sharing". The name confuses two concepts: a `Share` securable type (already exists in `SecurableType.SHARE`) and a "provider" prefix that disambiguates Delta Sharing flows. -- **Category:** 5 (cryptic abbreviation: `D2D` is in doc but never expanded), 1 (vague — what makes the share `provider`?). -- **Suggested name:** `sharingProviderName` or `deltaShareName` with a clearer doc. -- **Rationale:** `providerShare` reads as "the share of the provider" (genitive). The actual semantic is "the Delta Share that grants access to this securable when it's a shared object". The current name doesn't disambiguate. - -### 18. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` +### 11. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` - **Why weird:** Enum value pinned by inline TODO: `/** TODO: [UC-2980] Staging tables aren't full-fleged securables yet. */`. The TODO leaks an internal JIRA ticket (`UC-2980`) and the typo "full-fleged" into the public SDK surface. The presence of the value tells callers it works; the comment tells them it doesn't. - **Category:** 18 (questionable enum value). - **Suggested name:** Either hide until promotion (`@experimental`), or remove the inline TODO and document the constraint in the doc-comment proper. - **Rationale:** Public SDK enums shouldn't carry internal JIRA references. Same pattern as `connections#29` and `dataclassification`. -### 19. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` +### 12. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` - **Why weird:** `EXTERNAL_METADATA` is undocumented. Neighbouring `STAGING_TABLE` carries a TODO/comment, but `EXTERNAL_METADATA` doesn't even say what it is. Unity Catalog has `externalmetadata` as its own package (`packages/externalmetadata/`), but this RFA enum member exists in isolation. - **Category:** 1 (vague; no doc disambiguating). - **Suggested name:** Keep name; add doc comment. - **Rationale:** Naming OK, but undocumented enum members in a 17-element enum mean readers must cross-reference to other packages. -### 20. `Principal` is exported but `principalType` field has no doc — `model.ts:148` +### 13. `Principal` is exported but `principalType` field has no doc — `model.ts:148` - **Why weird:** `principalType?: PrincipalType | undefined` has no JSDoc. Sibling `id` has a doc. The PrincipalType enum has only an `_UNSPECIFIED` sentinel + three values, none of which clarify when each applies. Caller has to guess by inspecting the IAM service. - **Category:** 1 (vague). - **Suggested name:** Keep name; add doc. - **Rationale:** Mechanical. -### 21. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` +### 14. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` - **Why weird:** `permissions` is `string[]` rather than an enum. Doc says "List of requested Unity Catalog permissions" — UC permissions are a known closed set (`SELECT`, `MODIFY`, `USAGE`, `READ_VOLUME`, etc.), so this should be a typed enum or branded string. Bare `string[]` loses any compile-time guard against typos. - **Category:** 16 (field type contradicts domain — should be enum or branded string). - **Suggested name:** Keep name; type as `UnityCatalogPermission[]` (new enum). Or document the closed set inline. -- **Rationale:** Same problem as #6. The wire is string, but TS could narrow it. +- **Rationale:** Same problem as #5. The wire is string, but TS could narrow it. -### 22. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` +### 15. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` - **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. - **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). - **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). - **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. -### 23. Three Client methods, three different domain entity names — `client.ts:74,113,147` +### 16. Three Client methods, three different domain entity names — `client.ts:74,113,147` - **Why weird:** `Client.batchCreateAccessRequests` works on `requests`. `Client.getAccessRequestDestinations` works on `destinations`. `Client.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. - **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). - **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). @@ -163,49 +121,49 @@ ## Low severity -### 24. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +### 17. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17. - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Same as `connections#40`. -### 25. `HttpCallOptions` — `utils.ts:15` +### 18. `HttpCallOptions` — `utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file imports `Options` from `@databricks/sdk-core/api` and `CallOptions` from `@databricks/sdk-options/call`. Three `Options` types in scope. `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Same as `connections#41`. -### 26. `readAll` — `utils.ts:40` +### 19. `readAll` — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `connections#38`. -### 27. `flattenQueryParams` — `utils.ts:123` +### 20. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default. - **Rationale:** Generator emits the same helper into every package even when unused. Same as `connections#37`. -### 28. `PACKAGE_SEGMENT` constant — `client.ts:35` +### 21. `PACKAGE_SEGMENT` constant — `client.ts:35` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `connections#36`. -### 29. `Client` class — `client.ts:40` +### 22. `Client` class — `client.ts:40` - **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). - **Category:** 1 (vague). - **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). - **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. -### 30. `buildHttpRequest` parameter list — `utils.ts:96-102` +### 23. `buildHttpRequest` parameter list — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. The function name `buildHttpRequest` doesn't communicate the parameter order; callers in `client.ts:87,122,166` pass them positionally. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Five-positional builders without object syntax are an anti-pattern in modern TS. -### 31. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` +### 24. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` - **Why weird:** The `Options` shape is built with a series of `...(options?.foo !== undefined && {foo: options.foo})` spreads. The pattern is a TS-idiom for conditional spread of optional fields. Naming-wise: the local `opts` variable is intentionally one letter shorter than `options` to disambiguate — but the shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions` (or the outer parameter to `callOptions`). @@ -213,23 +171,23 @@ ## Observations -### 32. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` +### 25. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` The index file exports the `Client`, all four enums, and all nine model interfaces (`AccessRequestDestinations`, `BatchCreateAccessRequestsRequest`, `BatchCreateAccessRequestsResponse`, `CreateAccessRequest`, `CreateAccessRequestResponse`, `GetAccessRequestDestinationsRequest`, `NotificationDestination`, `Principal`, `Securable`, `SecurablePermissions`, `UpdateAccessRequestDestinationsRequest`). It does *not* export the `marshal*`/`unmarshal*` schemas or the `accessRequestDestinationsFieldMask` helper. Consistent with the other packages but means the field-mask helper isn't available to consumers. - **Category:** Observation. -### 33. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +### 26. Comment-tag inconsistency — `client.ts:78,117,151` vs URL The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. - **Category:** Observation. -### 34. No tests in the package +### 27. No tests in the package `package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. The package ships untested. Not a naming issue, but cross-package noise — same as several other newly generated packages. - **Category:** Observation. -### 35. Action-verb conventions on `Client` -`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #23). +### 28. Action-verb conventions on `Client` +`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #16). - **Category:** Observation. -### 36. `package.json` description is empty string — `package.json:4` +### 29. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the cryptic `rfa` name (see #1), this leaves users with no metadata to identify the package's purpose when browsing npm. - **Category:** Observation. @@ -244,7 +202,7 @@ The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the pac - **`Principal`** — Unity Catalog/IAM term for "an entity that can hold permissions": a user, a group, or a service principal. The `PrincipalType` enum disambiguates which kind. Used here as the "on behalf of" actor in `CreateAccessRequest`. - **`SpecialDestination`** — five enum members denoting "the owner of the metastore/catalog/external-location/connection/credential" as an implicit email destination. These cannot be assigned; they're a default fallback. - **`FieldMask`** — Google protobuf convention (re-used in Databricks API) for sparse-field updates in PATCH semantics. `accessRequestDestinationsFieldMask(...)` builds the wire-format paths. -- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #5). +- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #4). ## File coverage - `src/v1/model.ts` (385 lines): read fully. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index 317c5a1f..b2a1142f 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -28,28 +28,7 @@ separate methods) that the audit calls out at the package boundary. ### 1. Vague / generic names -#### 1.1 `EffectivePredictiveOptimizationFlag.value` (model.ts:81) -The flag wrapper exposes a single payload field named `value` — the -doc comment says "Whether predictive optimization should be enabled for -this object and objects under it". The name conveys nothing about -*what kind of value*; the type is `string` but the semantic is a -tri-state (enable / disable / inherit). A reader has to read the doc -to discover what is in it. Better: `enabled`, `setting`, or -`predictiveOptimization`. - -#### 1.2 `EffectivePredictiveOptimizationFlag.inheritedFromType` and `.inheritedFromName` (model.ts:83, 85) -`inheritedFromType` is `string`, not an enum — the name suggests a -typed handle but the value is human-readable text. Same problem for -`inheritedFromName`: "the name of the object" — of *what* object? -Without context (`catalog`, `schema`, `metastore`?) the field is -opaque. See also §5.1. - -#### 1.3 `name` on `CreateSchemaRequest`, `SchemaInfo`, `UpdateSchemaRequest` (model.ts:17, 126, 184) -`name` alone is generic in the context of UC where there's also -`fullName`, `catalogName`, `newName`, and `metastoreId`. The doc -qualifies it as "Name of schema, relative to parent catalog", but the -identifier itself doesn't say that. Compare to `catalogName` on the -same shape which is unambiguous. See also §7.2 and §9.2. +_None._ --- @@ -91,8 +70,8 @@ broader audit. #### 4.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) Field is typed `string | undefined` but the doc comment ("Whether predictive optimization should be enabled…") implies a small discrete -set of values (enable / disable / inherit). Either expose an enum or -rename the field to make it clear it's a setting key. See also §1.1. +set of values (enable / disable / inherit). The type should be an +enum rather than `string`. #### 4.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:140) The doc is honest: "Full name of schema, in form of @@ -106,7 +85,7 @@ of key-value properties attached to the securable."). There is no way for a caller to know which to use for what. The doc duplication recurs verbatim in `CreateSchemaRequest` (model.ts:51-54) and `UpdateSchemaRequest` (model.ts:218-221). Either is underspecified or -one of them is misnamed. See §8.1. +one of them is redundant. See §8.1. --- @@ -154,16 +133,7 @@ etc.). Not a compile error but creates cognitive load — inside rename the client parameter to `callOptions`. See also §8.1 for the duplicate-with-`properties` concern. -#### 7.2 `name` field is generic and shadows `Function.prototype.name` -Used on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` -(model.ts:17, 184, 126). Not a reserved word, but commonly shadows the -standard `Function.prototype.name` and routinely confuses callers who -spread request objects. See also §1.3. - -#### 7.3 `value` field on `EffectivePredictiveOptimizationFlag.value` (model.ts:81) -Generic field name, frequently shadows local variables. See §1.1. - -#### 7.4 `properties` is not reserved but conflicts with `Object` semantics +#### 7.2 `properties` is not reserved but conflicts with `Object` semantics `SchemaInfo.properties` (model.ts:161) is fine but worth noting that `properties` is a heavily-overloaded term in JS (object properties, descriptor properties, etc.). Combined with the duplicate-with-`options` @@ -301,21 +271,10 @@ Documented as "unique identifier of parent metastore". Format opaque field exists alongside `fullName` (which is also a unique identifier in a different sense). Two simultaneous IDs without disambiguation. -#### 13.3 `createdAt` / `updatedAt` (model.ts:33, 37, 142, 146, 200, 204) -Type is `number` (epoch milliseconds, per the doc). The unit is not -encoded in the field name. `createdAtMs` / `updatedAtMs` would be -more honest. (Compare to `lastFailoverTimeMs` in `catalogs`, which -gets this right — see catalogs.md §19.7.) - -#### 13.4 `createdBy` / `updatedBy` (model.ts:35, 39, 144, 148, 202, 206) -Type is `string` — "Username of schema creator" / "Username of user -who last modified schema". Underspecified: is this a username, an -email, a principal ID? `createdByUsername` would be clearer. - -#### 13.5 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) +#### 13.3 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) Both `string`. `inheritedFromType` could be one of the UC securable types, but the field is not enum-typed. `inheritedFromName` is opaque -text. See also §1.2. +text. --- @@ -327,27 +286,11 @@ Defensible (field carries the dynamic value) but worth flagging. #### 14.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. -#### 14.3 `EffectivePredictiveOptimizationFlag` with field `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` -(model.ts:44, 153, 211) — field repeats type name verbatim, 35 -characters each. Severe tautology, but defensible because the field -is the only instance of that type in each parent. Could be shortened -to `predictiveOptimization: EffectivePredictiveOptimization` (drop -"Flag" per §6.2 and "effective" per §5.1). - --- ### 15. Generic field names losing meaning -#### 15.1 `value` on `EffectivePredictiveOptimizationFlag` — see §1.1. - -#### 15.2 `name` on three different schema shapes — see §1.3. - -#### 15.3 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §4.3, §8.1. - -#### 15.4 `comment` (model.ts:23, 132, 190) -"User-provided free-form text description." `comment` is too informal -for a documented free-text description on a metadata API. -`description` would be more honest about its purpose. +#### 15.1 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §4.3, §8.1. --- @@ -445,38 +388,35 @@ upstream API surface, but the seam is non-obvious to discover. | ----------------------------------------------------------- | --------------------- | -------------------- | | `CatalogType` | model.ts:6 | 8.4, 14.1 | | `CreateSchemaRequest` | model.ts:15 | 8.6, 11.2 | -| `CreateSchemaRequest.name` | model.ts:17 | 1.3, 7.2 | +| `CreateSchemaRequest.name` | model.ts:17 | 8.2 | | `CreateSchemaRequest.catalogType` | model.ts:41 | 14.1 | -| `CreateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:44 | 5.1, 14.3, 17.2, F | -| `CreateSchemaRequest.properties` / `.options` | model.ts:52, 54 | 4.3, 7.1, 8.1, 15.3 | +| `CreateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:44 | 5.1, 17.2, F | +| `CreateSchemaRequest.properties` / `.options` | model.ts:52, 54 | 4.3, 7.1, 8.1, 15.1 | | `DeleteSchemaRequest` | model.ts:69 | 11.3 | | `DeleteSchemaRequest.fullNameArg` | model.ts:71 | 3.1, 10.3, 11.3, B | -| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 5.1, 6.2, 10.1, 14.3, 17.1 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 1.1, 4.1, 7.3, 15.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 1.2, 13.5 | -| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 1.2, 13.5 | +| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 5.1, 6.2, 10.1, 17.1 | +| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 4.1 | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 13.3 | +| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 13.3 | | `GetSchemaRequest.fullNameArg` | model.ts:90 | 3.1, 10.3, 11.4, B | | `ListSchemasRequest` | model.ts:95 | — | | `ListSchemasRequest.maxResults` | model.ts:105 | — | | `ListSchemasRequest.pageToken` | model.ts:107 | — | | `ListSchemasRequest.includeBrowse` | model.ts:109 | — | | `SchemaInfo` | model.ts:124 | 6.1, 8.6, 10.1, E | -| `SchemaInfo.name` | model.ts:126 | 1.3, 7.2 | +| `SchemaInfo.name` | model.ts:126 | 8.2 | | `SchemaInfo.fullName` | model.ts:140 | 4.2, 8.2 | -| `SchemaInfo.createdAt` / `.updatedAt` | model.ts:142, 146 | 13.3 | -| `SchemaInfo.createdBy` / `.updatedBy` | model.ts:144, 148 | 13.4 | | `SchemaInfo.catalogType` | model.ts:150 | 14.1 | -| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 5.1, 14.3, 17.2, F | +| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 5.1, 17.2, F | | `SchemaInfo.schemaId` | model.ts:157 | 13.2 | -| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 4.3, 7.1, 8.1, 15.3 | +| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 4.3, 7.1, 8.1, 15.1 | | `UpdateSchemaRequest` | model.ts:178 | 8.3, 8.6, 11.1, 11.2 | | `UpdateSchemaRequest.fullNameArg` | model.ts:180 | 3.1, 8.3, 10.3, 11.1, B | | `UpdateSchemaRequest.newName` | model.ts:182 | 11.1 | -| `UpdateSchemaRequest.name` | model.ts:184 | 1.3, 7.2, 11.1 | +| `UpdateSchemaRequest.name` | model.ts:184 | 8.2, 11.1 | | `UpdateSchemaRequest.fullName` | model.ts:198 | 8.2, 8.3, 11.1 | -| `UpdateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:211 | 5.1, 14.3, 17.2, F | +| `UpdateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:211 | 5.1, 17.2, F | | `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | G | -| `comment` field | model.ts:23, 132, 190 | 15.4 | | `Client` (bare name) | client.ts:44 | 10.2 | | `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 143, 248 | B | | `flattenQueryParams` (unused export) | utils.ts:123 | A | @@ -491,14 +431,9 @@ upstream API surface, but the seam is non-obvious to discover. 3. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§4.1, G) 4. **Strip read-only fields from `CreateSchemaRequest`/`UpdateSchemaRequest`.** (§11.2) 5. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) -6. **Encode timestamp units in field names** (`createdAtMs`, `updatedAtMs`). (§13.3) -7. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§13.2, §8.2) -8. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§6.1) -9. **Strip the `Next ID: 45` leftover from `SchemaInfo` JSDoc.** (E) -10. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§8.7, H) +6. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§13.2, §8.2) +7. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§6.1) +8. **Strip the `Next ID: 45` leftover from `SchemaInfo` JSDoc.** (E) +9. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§8.7, H) --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index b62e0288..51e4d946 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -19,11 +19,11 @@ Notation: file paths are relative to the package root. Findings reference | Severity | Count | | ----------- | ----- | -| High | 4 | -| Medium | 12 | -| Low | 9 | +| High | 3 | +| Medium | 5 | +| Low | 8 | | Observation | 5 | -| **Total** | **30** | +| **Total** | **21** | Headline themes: @@ -38,12 +38,6 @@ Headline themes: creating/updating ACLs and secrets, `Create` for scopes, `Delete` for all three. There is no `Update`. Go's REST SDK adopts the same shape, but `Put` reads as Go/HTTP-method jargon rather than a TS-side action verb. -3. **`scope: string | undefined` everywhere — but required in practice.** - Eleven of twelve operation request types have `scope?: string | undefined` - as their primary identifier. Every server endpoint will reject an absent - scope. The "optional" marker is a generator artifact (all proto fields - are optional), not a real contract. Same pattern for `key` and - `principal`. --- @@ -113,32 +107,6 @@ Headline themes: `/secrets/put` — so the wire format is *also* inconsistent and the generator is faithfully reproducing it. -### H4. Scope name field `scope` is severely overloaded across types - -- **Files / lines:** `src/v1/model.ts:53` (`CreateScopeRequest.scope`), `:67` - (`DeleteAclRequest.scope`), `:77` (`DeleteScopeRequest.scope`), `:85` - (`DeleteSecretRequest.scope`), `:95` (`GetAclRequest.scope`), `:102` - (`GetSecretRequest.scope`), `:117` (`ListAclsRequest.scope`), `:137` - (`ListSecretsRequest.scope`), `:148` (`PutAclRequest.scope`), `:160` - (`PutSecretRequest.scope`). Then `SecretScope.name` (`:198`) names the - same value, and the *type* `SecretScope` describes what `scope` actually - contains. Then `ScopeBackendType` describes the scope's backend. -- **Category:** #1 vague/generic, #15 generic field names losing meaning, - #6 misleading names. -- **Issue:** `scope` is the *string name* of a `SecretScope`. The naming - is ambiguous in three ways: - - The type `SecretScope` calls its own identifier `name` (not `scope`). - - Every request type calls the same identifier `scope` (not `scopeName` - or `secretScopeName`). - - The word "scope" in TS frequently refers to lexical scope or - permission scope (OAuth). A casual reader sees `req.scope = '...'` and - has to read the JSDoc to learn it is a *secret scope name*. -- **Suggestion:** rename the field on request types to `scopeName` and on - `SecretScope` keep `name`. This matches the disambiguation pattern the - sibling `serviceprincipalsecrets` uses (`ServicePrincipalSecret.secretId` - vs request `id`). The Go SDK uses the same `Scope` field name, but TS - conventions favour explicitness over brevity. - --- ## Medium Severity @@ -169,33 +137,7 @@ Headline themes: Microsoft-canonical spelling. The fields just need to match the type names they describe. -### M2. `AzureKeyVaultSecretScopeMetadata.resourceId` is underspecified - -- **File / line:** `src/v1/model.ts:46`. -- **Category:** #19 underspecified IDs. -- **Current:** `resourceId?: string | undefined`. -- **JSDoc:** "The resource id of the azure KeyVault that user wants to - associate the scope with." -- **Suggestion:** `azureResourceId` or `keyVaultResourceId`. As-is, a - reader sees `metadata.resourceId` and has no idea it's an Azure ARM - Resource ID — it could be a Databricks resource ID, a UC resource ID, - etc. - -### M3. `AzureKeyVaultSecretScopeMetadata.dnsName` is underspecified - -- **File / line:** `src/v1/model.ts:48`. -- **Category:** #1 vague/generic, #15 generic field name. -- **Current:** `dnsName?: string | undefined`. -- **JSDoc:** "The DNS of the KeyVault" — incidentally grammatically wrong - ("the DNS" should be "the DNS name" or "the URL"). -- **Suggestion:** `vaultUri` or `keyVaultUri`. The Azure SDK names this - field `vaultUri` and the value is a full URI - (`https://xxxx.vault.azure.net/`) not just a DNS name. -- **Rationale:** `dnsName` suggests a hostname like `xxxx.vault.azure.net`, - but the example value in `client.ts:113` is the full URI - `https://xxxx.vault.azure.net/`. The field name lies about its content. - -### M4. `AclItem` is generic-suffix tautology +### M2. `AclItem` is generic-suffix tautology - **File / line:** `src/v1/model.ts:36`. - **Category:** #20 type-suffix tautology, #15 generic field names. @@ -213,7 +155,7 @@ Headline themes: — so the type is conceptually "an ACL rule", but it's spelled "AclItem". The doc disagrees with the name. -### M5. `SecretMetadata` describes a list-item, not metadata +### M3. `SecretMetadata` describes a list-item, not metadata - **File / line:** `src/v1/model.ts:184`. - **Category:** #1 vague/generic, #20 type-suffix tautology. @@ -229,33 +171,7 @@ Headline themes: (tags, schema, labels). Here the type *is* the secret as exposed by list — it lacks only the value. `SecretSummary` reads correctly. -### M6. `SecretMetadata.lastUpdatedTimestamp` carries unit in name but not type - -- **File / line:** `src/v1/model.ts:188`. -- **Category:** #6 misleading names, #15 generic field names. -- **Current:** `lastUpdatedTimestamp?: number | undefined` — JSDoc says - "The last updated timestamp (in milliseconds) for the secret." -- **Suggestion:** `lastUpdatedAt` (epoch-ms) or `lastUpdatedMs` (carries - the unit). Compare to other audits in the repo: `expirationTime` was - flagged for the same defect in `credentials.md` #50. -- **Rationale:** `Timestamp` doesn't say whether it's ms or s, ISO string, - or `Date`. The codebase elsewhere uses `*At` (`createdAt`, `updatedAt`) - for epoch-ms ints; this field breaks the pattern. - -### M7. `SecretScope.backendType` vs `CreateScopeRequest.scopeBackendType` - -- **Files / lines:** `src/v1/model.ts:200` (`SecretScope.backendType`), - `:57` (`CreateScopeRequest.scopeBackendType`). -- **Category:** #1 vague/generic, #13 verb-tense inconsistency (form). -- **Current:** the very same enum-typed field appears as `backendType` on - the response shape and `scopeBackendType` on the request shape. -- **Suggestion:** pick one. `backendType` is sufficient since both types - are scope-related and the prefix `scope` is redundant. -- **Rationale:** Inconsistent naming for the same conceptual field is - pure noise; a consumer mapping a `SecretScope` back to a - `CreateScopeRequest` re-creation will trip on the field-name mismatch. - -### M8. `Backend` mid-position is an architectural leak +### M4. `Backend` mid-position is an architectural leak - **Files / lines:** `src/v1/model.ts:19` (`ScopeBackendType` enum), `:57` (`CreateScopeRequest.scopeBackendType`), `:59` @@ -273,45 +189,13 @@ Headline themes: *vault provider* of the scope. - **Suggestion:** rename to a domain term. Options: - `ScopeBackendType` → `ScopeStorageType` or `SecretStorageProvider`. - - `backendType` → `storageType` or `provider`. - - `scopeBackendType` → `storageType`. - - `backendAzureKeyvault` → `azureKeyVault` (drop the `backend` prefix; - M9 already wants this field renamed to `keyVaultBackend` for - round-trip parity — pick whichever direction prefers domain language). - **Rationale:** every other field in the package uses domain nouns (`scope`, `key`, `principal`, `permission`). `Backend` is the one outlier that smuggles in implementation jargon. Same defect appears in several other audits where "backend" describes an integration/provider layer (e.g., `connections.md` flags `ConnectionType` analogues). -### M9. `CreateScopeRequest.backendAzureKeyvault` vs `SecretScope.keyvaultMetadata` - -- **Files / lines:** `src/v1/model.ts:59`, `:202`. -- **Category:** #12 duplicate concepts, #1 vague/generic. -- **Current:** the same conceptual field (`AzureKeyVaultSecretScopeMetadata` - payload, the backend configuration for an Azure KeyVault scope) is named - `backendAzureKeyvault` on `CreateScopeRequest` and `keyvaultMetadata` on - `SecretScope`. Both names describe the same payload at the same role - (the KeyVault backend config) but use different framings. -- **Suggestion:** rename both to the same — `keyVaultBackend` (preferred, - short, describes role) or `azureKeyVaultBackend`. Then `CreateScopeRequest` - and `SecretScope` round-trip naturally. - -### M10. `CreateScopeRequest.initialManagePrincipal` is verbose - -- **File / line:** `src/v1/model.ts:55`. -- **Category:** #7 overly verbose. -- **Current:** `initialManagePrincipal` (22 chars). -- **JSDoc:** "The principal that is initially granted ``MANAGE`` permission - to the created scope." -- **Suggestion:** `manageOwner` (10) or `initialOwner` (12); rests on the - fact that MANAGE permission is owner-equivalent. As-is, the name reads - as "initial manage principal" which is grammatically odd — `initial` - modifies `principal`, but the reader first sees "initial manage" as a - unit. Acceptable as-is if alternates feel too clever; flagging only the - verbosity. - -### M11. `GetSecretRequest_Response` returned by `getSecret` carries `key` redundantly +### M5. `GetSecretRequest_Response` returned by `getSecret` carries `key` redundantly - **File / line:** `src/v1/model.ts:108-113`. - **Category:** #12 duplicate concepts (request → response). @@ -329,17 +213,6 @@ Headline themes: callers writing `(await client.getSecret({scope, key: 'foo'})).value` spell `foo` twice. -### M12. `ListAclsRequest_Response.items` should be `ListAclsRequest_Response.acls` - -- **File / line:** `src/v1/model.ts:123`. -- **Category:** #15 generic field name losing meaning. -- **Current:** `items?: AclItem[] | undefined`. -- **Suggestion:** `acls: Acl[]` (combined with M4). -- **Rationale:** Compare to `ListScopesRequest_Response.scopes` (`:132`) - and `ListSecretsRequest_Response.secrets` (`:143`) which both use the - domain-typed plural. `items` is the odd-one-out; the field name should - match the pattern. - --- ## Low Severity @@ -352,19 +225,7 @@ Headline themes: enum (`'READ' | 'WRITE' | 'MANAGE'`). If the server adds a new permission level, zod will throw at decode. Not a name issue, just notable. -### L2. `PutSecretRequest.value` discriminator names duplicate property names - -- **File / line:** `src/v1/model.ts:163-174`. -- **Category:** #15 generic field names, #20 type-suffix tautology. -- **Current:** `{ $case: 'stringValue', stringValue: string }`. The - discriminator value is the same string as the property name. -- **Issue:** `value.stringValue` is the access path; `value.$case` is the - guard, also `'stringValue'`. The redundancy bloats every read site. -- **Suggestion:** `{ $case: 'string', value: string } | { $case: 'bytes', - value: Uint8Array }`. The discriminator becomes a clean enum-of-strings, - the value field has a uniform name. - -### L3. `PutSecretRequest.value` `stringValue` JSDoc references "UTF-8 (MB4)" +### L2. `PutSecretRequest.value` `stringValue` JSDoc references "UTF-8 (MB4)" - **File / line:** `src/v1/model.ts:166`. - **Category:** #5 cryptic abbreviations. @@ -377,7 +238,7 @@ Headline themes: "UTF-8". This is a doc issue, not a name issue per se, but a naming audit notices it. -### L4. `principal` is a single field used for both users and groups +### L3. `principal` is a single field used for both users and groups - **Files / lines:** `model.ts:38, 69, 97, 150`. - **Category:** #1 vague/generic. @@ -390,7 +251,7 @@ Headline themes: realize they should pass either a username or group name. JSDoc on the request types could explicitly say "(user or group name)". -### L5. `req.scope` is documented inconsistently across types +### L4. `req.scope` is documented inconsistently across types - **Files / lines:** `model.ts:52, 67, 77, 85, 95, 102, 117, 137, 148, 160`. - **Category:** observation; documentation only. @@ -406,7 +267,7 @@ Headline themes: grammar variation. Not a naming defect; flagging because it makes cross-reference annoying. -### L6. `ScopeBackendType` values include only two cases despite the JSDoc +### L5. `ScopeBackendType` values include only two cases despite the JSDoc - **File / line:** `src/v1/model.ts:16-30`. - **Category:** observation. @@ -414,7 +275,7 @@ Headline themes: later release." The release shipped; the doc string is stale. Not a naming issue but indicates the file is not maintained tightly. -### L7. `flattenQueryParams` is dead code in this package +### L6. `flattenQueryParams` is dead code in this package - **File / line:** `src/v1/utils.ts:123`. - **Category:** #21 dead code. @@ -424,7 +285,7 @@ Headline themes: generator-wide. - **Suggestion:** drop dead code, or move it to a shared utils package. -### L8. `executeCall` vs `executeHttpCall` name collision +### L7. `executeCall` vs `executeHttpCall` name collision - **Files / lines:** `src/v1/utils.ts:26, 65`. - **Category:** #17 inconsistent action verbs. @@ -432,7 +293,7 @@ Headline themes: `executeCall` (sets options + dispatches retries) and `executeHttpCall` (one HTTP roundtrip). Same defect cataloged in other audits. -### L9. `PACKAGE_SEGMENT` constant is vague +### L8. `PACKAGE_SEGMENT` constant is vague - **File / line:** `src/v1/client.ts:65`. - **Category:** #1 vague/generic. @@ -448,7 +309,7 @@ Headline themes: ### O1. `scope` is optional on every request type, but required at the server -- **Files / lines:** see H4. +- **Files / lines:** see model.ts request types. - The generator marks every proto field optional. The runtime contract requires `scope` for ten of eleven operations. Not a naming defect but worth noting: the type is wider than the API allows. @@ -499,25 +360,11 @@ Headline themes: 1. `Client` → `SecretsClient` (H1, H2). 2. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply consistently across all mutating methods (H3). -3. `scope: string` field on every request type → `scopeName: string` (H4). -4. `AclItem` → `Acl` or `AclEntry`; `ListAclsRequest_Response.items` → - `ListAclsRequest_Response.acls` (M4, M12). -5. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M5). -6. `SecretMetadata.lastUpdatedTimestamp` → `lastUpdatedAt` (M6). -7. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, +3. `AclItem` → `Acl` or `AclEntry` (M2). +4. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M3). +5. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, `backendAzureKeyVault`) (M1). -8. `AzureKeyVaultSecretScopeMetadata.dnsName` → `vaultUri` (M3). -9. `AzureKeyVaultSecretScopeMetadata.resourceId` → `azureResourceId` or - `keyVaultResourceId` (M2). -10. `SecretScope.backendType` ↔ `CreateScopeRequest.scopeBackendType` → - pick one (`backendType`) (M7). -11. `ScopeBackendType` → `ScopeStorageType`; drop `Backend` mid-position - in `backendType` / `scopeBackendType` fields (M8). -12. `CreateScopeRequest.backendAzureKeyvault` ↔ `SecretScope.keyvaultMetadata` - → pick one (`keyVaultBackend`) (M9). +6. `ScopeBackendType` → `ScopeStorageType`; drop `Backend` mid-position + (M4). --- - -## Fixed - -- #H3 (original) Six request types are verb phrases (action collision with client methods) (originally cited at `src/v1/model.ts:51, 65, 75, 83, 93, 100, 115, 127, 135, 146, 158`): Fixed in regeneration on 2026-05-20 — all request DTOs now carry the `Request` suffix (`CreateScopeRequest`, `DeleteAclRequest`, `DeleteScopeRequest`, `DeleteSecretRequest`, `GetAclRequest`, `GetSecretRequest`, `ListAclsRequest`, `ListScopesRequest`, `ListSecretsRequest`, `PutAclRequest`, `PutSecretRequest`). diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index ab8dcfd4..5c841c4d 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -3,14 +3,14 @@ **Path:** `packages/secretsuc/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. -**Total weird names flagged:** 23 +**Total weird names flagged:** 14 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 8 | -| Low | 3 | +| High | 4 | +| Medium | 5 | +| Low | 1 | | Observation | 4 | ## High severity @@ -33,101 +33,47 @@ - **Suggested name:** `UnityCatalogSecret` for the type. Splitting into `CreateSecretInput` / `Secret` / `UpdateSecretInput` is the structural fix that would surface the read/write asymmetry in the type system. - **Rationale:** Even if the package rename happens, the type name `Secret` carries no UC-specific signal. Users wiring up both APIs will collide. Beyond the collision, one type for three lifecycle stages means callers cannot tell from the type which fields are writable on input and which are server-populated on output. -### 4. `externalSecretId` — `src/v1/model.ts:143` -- **Why weird:** Completely undocumented field (no JSDoc comment, unlike every other field on `Secret`). The wire field exists in the field-mask but is not in the field-mask's documented "Supported fields" list (`value, comment, owner, expire_time` — `client.ts:238`). The field's existence and semantics are entirely opaque to a reader of the model file. -- **Category:** 1 (vague — what is "external"?), 6 (misleading — undocumented field that is presumably real), 19 (underspecified id — alongside `metastoreId` and `fullName`). -- **Suggested name:** Keep the name but ship JSDoc; or `externalSecretReference` / `externalProviderSecretId` if the field points at an external secret manager (AWS Secrets Manager, etc.). -- **Rationale:** A bare `externalSecretId` next to `metastoreId` and `fullName` invites the reader to guess. JSDoc is the cheapest fix; renaming to disclose the "external store" intent is the better one. This may be a generator gap (missing API description), worth flagging upstream so the description is included. - -### 5. `value` field on `Secret` doubles as both input and output — `src/v1/model.ts:126` -- **Why weird:** Doc says "This field is input-only and is not returned in responses". Same struct has `effectiveValue` (`model.ts:131`) for the output. Two near-identical fields, one input-only, one output-only, both meaning "the secret value". Generic name `value` is also category-1 vague — without the doc, "value" could mean any value in any struct. -- **Category:** 1 (vague), 6 (misleading — same name covers both write-only-input and a sibling read-only-output), 11 (input-only field on a shared input/output type forces the reader to know the direction). -- **Suggested name:** `secretValue` (for symmetry with `effectiveValue`), or split into `CreateSecretInput.value` / `Secret.effectiveValue` so the asymmetry surfaces in the type system. Alternatively rename `effectiveValue` -> `value` and have a separate write-only `newValue` on update. -- **Rationale:** The current shape relies entirely on the JSDoc to inform the reader which field to set on input and which to read on output. A buggy caller can set `effectiveValue` on a create call and the SDK will serialise it to the wire (where the server presumably ignores it). The TS type system should keep the asymmetry visible. - -### 6. `effectiveValue` / `effectiveOwner` "effective" prefix — `src/v1/model.ts:101,131` -- **Why weird:** Two unrelated `effective*` fields used with two different meanings. `effectiveOwner` is documented as "the effective owner of the secret, which may differ from the directly-set **owner** due to inheritance" — so "effective" = "after inheritance resolution". `effectiveValue` is documented as "the secret value. Only populated in responses when you have the **READ_SECRET** privilege" — so "effective" = "the actual readable value, not what was sent in". Two distinct semantics under one prefix. -- **Category:** 6 (misleading — "effective" implies inheritance everywhere but here doubles as "actually readable"). -- **Suggested name:** Rename `effectiveValue` -> `currentValue` or `readValue` to free `effective*` for the inheritance sense; or rename `effectiveOwner` -> `inheritedOwner` / `resolvedOwner`. -- **Rationale:** Same prefix, two meanings, within five lines of each other. A reader scanning the struct picks up the first definition and applies it to the second, leading to a wrong mental model. The fact that `effectiveValue` is documented to be populated based on a privilege (not inheritance) makes the prefix actively misleading. - -### 7. `fullName` is the routing key but marked optional — `src/v1/model.ts:23,32,115,152` +### 4. `fullName` is the routing key but marked optional — `src/v1/model.ts:23,32,115,152` - **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:109,136,244`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. - **Category:** 6 (misleading — looks optional, isn't), 16 (field type contradicts domain — required key marked optional). - **Suggested name:** Keep the name, drop `| undefined` on the three request DTOs (or split: `Secret.fullName?` for responses, `SecretRef.fullName` required for requests). - **Rationale:** This is a routing identifier; the TS type system can prevent a whole class of "I forgot the name" bugs and the SDK can stop substituting empty strings. -### 8. `includeBrowse` parameter — `src/v1/model.ts:37,56` -- **Why weird:** Boolean flag named `includeBrowse` reads as "include browse" with no clarification of what "browse" means. JSDoc clarifies it gates returning secrets the caller only has BROWSE privilege on. Without the doc, the field name is opaque. Same pattern (`browseOnly` on `Secret`, `model.ts:136`) reuses the bare verb. `BROWSE` here is a permission name, not an action. -- **Category:** 1 (vague — "browse" is undefined without ACL context), 5 (cryptic without docs). -- **Suggested name:** `includeBrowseOnlySecrets` / `includeMetadataOnly` for the request flag; `metadataOnly` for the response field (`browseOnly` reads as a constraint, but is actually a "you only got metadata back" marker). -- **Rationale:** "Browse" is jargon from the Unity Catalog access-control vocabulary. Cross-package consistency matters more than internal cleverness — but the name is the first thing a consumer sees, before the JSDoc. Expanding to "browse-only" or "metadata-only" makes the field self-documenting. - ## Medium severity -### 9. `Secret` mixes effective (server-resolved) and direct (caller-set) fields — `src/v1/model.ts:126` +### 5. `Secret` mixes effective (server-resolved) and direct (caller-set) fields — `src/v1/model.ts:126` - **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. The shared type is used on both create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output, and the `effective*` pairs (owner/effectiveOwner, value/effectiveValue) put the resolved and directly-set values next to each other without a structural distinction. - **Category:** 11 (single type wearing two hats), 6 (misleading). - **Suggested name:** Split into `WritableSecret` / `Secret`, or `SecretCreateInput` / `SecretUpdateInput` / `Secret`. - **Rationale:** The single-type approach forces every consumer to know which fields are write-permitted. The field-mask on update (`updateMask` — `model.ts:162`) partially mitigates but doesn't substitute for type-level intent. -### 10. `UpdateSecretRequest.secret` is the *update payload* with `fullName` as routing key — `src/v1/model.ts:147-163` +### 6. `UpdateSecretRequest.secret` is the *update payload* with `fullName` as routing key — `src/v1/model.ts:147-163` - **Why weird:** `UpdateSecretRequest` has both `fullName` (routing) and `secret` (payload). The nested `secret.fullName` is meaningless — what if it differs from the outer `fullName`? The whole `secret`, including its own optional `fullName`, is serialised into the PATCH body even though the path is keyed by the outer `req.fullName`. - **Category:** 6 (misleading — two `fullName`s can disagree), 17 (inconsistency — same field appearing twice in one logical operation). - **Suggested name:** Either define `SecretUpdate` (omits `fullName`, `createTime`, etc.) or rely on the field-mask to ignore non-listed fields. Naming-wise: rename the outer to `name`/`secretFullName` to emphasise it's the routing key, not part of the payload. - **Rationale:** This is a real bug surface: callers will write `{fullName: 'a.b.c', secret: {fullName: 'x.y.z', ...}}` and wonder why renames don't work. -### 11. `ListSecretsRequest.catalogName` + `schemaName` as filters but documented as required-when-paired — `src/v1/model.ts:46,51` +### 7. `ListSecretsRequest.catalogName` + `schemaName` as filters but documented as required-when-paired — `src/v1/model.ts:46,51` - **Why weird:** JSDoc says "Both **catalog_name** and **schema_name** must be specified together". TS type marks both optional. The "must be specified together" constraint is enforced at the server, not in the type. A more honest shape would be `{ scope?: {catalogName: string; schemaName: string} | undefined }` so the pair must be set atomically. - **Category:** 16 (field type contradicts domain — "must be together" not expressible). - **Suggested name:** Keep names, group into a `scope` sub-object so paired-ness is type-enforced. - **Rationale:** Internal grouping fix; not strictly a naming finding. Listed because the field names alone don't communicate the constraint, and the type system isn't carrying the weight. -### 12. `createTime` / `updateTime` / `expireTime` vs `createdBy` / `updatedBy` verb tense — `src/v1/model.ts:105,107,109,111,142` -- **Why weird:** Past-tense participle on the principal fields (`createdBy`, `updatedBy`) but plain noun on the timestamps (`createTime`, `updateTime`). A consistent convention would be either `createdAt` + `createdBy` (both past-tense, both anchored to event) or `createTime` + `creator` (both noun forms). Mixed forms read as inconsistent. `expireTime` is future tense ("will expire") so isn't symmetrical with `created`/`updated`. -- **Category:** 13 (verb-tense inconsistency). -- **Suggested name:** `createdAt` / `updatedAt` / `expiresAt` (or `expireAt`) for timestamps; keep `createdBy` / `updatedBy` for principals. -- **Rationale:** Common JS convention is `*At` for instant fields. The mixed `createTime` + `createdBy` pairing forces the reader to reconcile two tenses for one logical event. - -### 13. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` +### 8. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` - **Why weird:** Request uses `pageToken`, response uses `nextPageToken`. Internally consistent with conventions across the SDK, but the asymmetry between "what I send" and "what I receive next time" is something the type system can't help with. The pagination iterator (`client.ts:227`) bridges them via `pageReq.pageToken = resp.nextPageToken`. - **Category:** 17 (action-verb / qualifier asymmetry between request and response). - **Suggested name:** Accept the convention (`nextPageToken` is the next page; you copy it to `pageToken` on the next request). Listed for completeness. - **Rationale:** Generator convention; this isn't really a naming defect — flagged because rules 14 and 17 both ask about cross-DTO consistency. -### 14. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` +### 9. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` - **Why weird:** JSDoc enumerates four meanings of `pageSize`: unset = 10000, positive = min(value, 10000), zero = 10000, negative = error. The field type is `number | undefined` which expresses none of those. A reader of the type signature alone would believe any number works. - **Category:** 16 (type contradicts domain — should be `positive integer | undefined`), 6 (misleading — zero has special meaning). - **Suggested name:** Keep the name; consider a Zod refinement (`z.number().int().nonnegative()`) and document the zero-means-default specially. - **Rationale:** API-level concern (the upstream API conflates "use default" and "0"); flagging at the SDK level because the type system is silent. -### 15. `metastoreId` field naming — `src/v1/model.ts:103` -- **Why weird:** `metastoreId` alongside `fullName`, `name`, `catalogName`, `schemaName`, `externalSecretId`, and (implied via comments) the policy id. Multiple identifier-like fields in one struct; bare `id` would be ambiguous, but `metastoreId` is fine in isolation. Flagged because the unqualified `externalSecretId` next to it gets less context. -- **Category:** 19 (underspecified id when multiple ids exist — applies to its neighbour, not this field). -- **Suggested name:** Keep `metastoreId`. Pair with renaming `externalSecretId` -> `externalSecretRef` or fully documenting it. -- **Rationale:** Borderline; raised because the struct already has too many distinct identifiers and clarity matters. - -### 16. `name` (relative name) vs `fullName` (qualified name) on `Secret` — `src/v1/model.ts:91,115` -- **Why weird:** `name` is "The name of the secret, relative to its parent schema" and `fullName` is "The three-level (fully qualified) name". Two name fields, one short and one long; the bare `name` doesn't say "relative". An incoming consumer who sees `name` and `fullName` may write the relative name where the fully qualified one is expected and the request silently hits the wrong endpoint (see finding #7). -- **Category:** 1 (vague — `name` doesn't disclose its relative scope), 19 (multiple identifier-like fields). -- **Suggested name:** `relativeName` for `name`, or `schemaRelativeName`. Wire stays `name`. -- **Rationale:** When `fullName` is the routing key, `name` should disclose that it's the inferior, scope-relative one. Failing that, JSDoc must always be read. - ## Low severity -### 17. `comment` vs documented "description" mismatch — `src/v1/model.ts:113` -- **Why weird:** Field named `comment` with JSDoc "User-provided free-form text description of the secret." The doc calls it a description; the field is called a comment. Same mismatch pattern as `abacpolicies.PolicyInfo.comment` (audit #28). -- **Category:** 6 (misleading — doc says description, name says comment), 17 (cross-package inconsistency). -- **Suggested name:** `description`. -- **Rationale:** SQL DDL leak; TS should adopt the noun the human-readable doc uses. - -### 18. `owner` vs `effectiveOwner` shadowing — `src/v1/model.ts:96,101` -- **Why weird:** Both fields present on `Secret`. `owner` is what was set; `effectiveOwner` is what resolves through inheritance. Caller updating `owner` later reads back `effectiveOwner` and is surprised it didn't change (if a higher-scope owner is inherited). A reader without the doc cannot tell them apart by the name alone. -- **Category:** 17 (inconsistent — same logical concept exposed twice). -- **Suggested name:** Rename `owner` -> `explicitOwner` or `directOwner` to mirror `effectiveOwner`'s "resolved" framing. -- **Rationale:** Sibling pair should be obviously a pair. Reading `owner` and `effectiveOwner` side-by-side, the user has to consult the JSDoc to discover one is the raw input and one is the resolved output. Wire stays `owner`. - -### 19. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` +### 10. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` - **Why weird:** Same constant repeated in every generated package. `Segment` is generic; reader needs the comment to learn it's the User-Agent identity segment. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE_ID` or `PACKAGE_USER_AGENT_SEGMENT`. @@ -135,18 +81,18 @@ ## Observations -### 20. Action-verb convention in `Client` +### 11. Action-verb convention in `Client` `createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) -### 21. Acronym casing for `Http` / `Url` +### 12. Acronym casing for `Http` / `Url` Same as other audited packages: `Http` (PascalCase capital-then-lower) coexists with `URLSearchParams` (ALLCAPS from Web standard). Convention inherited from broader JS ecosystem; not worth changing. - **Category:** 3. -### 22. `Uc` abbreviation never expanded in code +### 13. `Uc` abbreviation never expanded in code Tracked thoroughly. The string "Uc" (in any case) does not appear in any identifier, type name, field name, constant, or enum value. "Unity Catalog" appears only in (a) JSDoc on `Secret` (`model.ts:85`), (b) JSDoc on `createSecret` / `listSecrets` / `updateSecret` (`client.ts:67,163,232`), and (c) the URL path string `/api/2.1/unity-catalog/secrets` (`client.ts:79,109,136,176,244`). The package name `secretsuc` is the **only** carrier of the disambiguator at the import level, and it's silent everywhere else. A consumer importing `Client` and `Secret` from this package, then opening their editor's symbol view, will see no hint that this is Unity-Catalog-scoped. See finding #1. - **Category:** 5. -### 23. No enums in this package +### 14. No enums in this package No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; `secretsuc` exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. ## Domain glossary diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md index 6a962263..9d632b6a 100644 --- a/.agent/naming-audit/serviceprincipalsecrets.md +++ b/.agent/naming-audit/serviceprincipalsecrets.md @@ -42,33 +42,3 @@ _None._ _None._ --- - -## Fixed - -- #1 package `serviceprincipalsecrets` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — package source removed; no `src/` directory remains. -- #2 package `serviceprincipalsecrets` (originally cited at (package)): Fixed in regeneration on 2026-05-20 — package source removed; no `src/` directory remains. -- #3 `CreateServicePrincipalSecret` (originally cited at model.ts:6): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #4 `DeleteServicePrincipalSecret` (originally cited at model.ts:32): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #5 `ListServicePrincipalSecrets` (originally cited at model.ts:44): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #6 `CreateServicePrincipalSecret.servicePrincipal` (originally cited at model.ts:10): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #7 `CreateServicePrincipalSecret.lifetime` (originally cited at model.ts:12): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #8 `CreateServicePrincipalSecretResponse` vs `ServicePrincipalSecret` (originally cited at model.ts:15, 66): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. -- #9 `ServicePrincipalSecret.secret` (originally cited at model.ts:69): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #10 `ServicePrincipalSecret.secretHash` (originally cited at model.ts:71): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #11 `ServicePrincipalSecret.id` (originally cited at model.ts:68): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #12 `ServicePrincipalSecret.status` (originally cited at model.ts:78): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #13 `ServicePrincipalSecret.createTime` (originally cited at model.ts:74): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #14 `ServicePrincipalSecret.updateTime` (originally cited at model.ts:76): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #15 `CreateServicePrincipalSecretResponse.createTime` / `.updateTime` (originally cited at model.ts:23, 25): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. -- #16 `ServicePrincipalSecret.expireTime` (originally cited at model.ts:80): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #17 `ListServicePrincipalSecrets.accountId` / `.servicePrincipal` (originally cited at model.ts:46, 48): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. -- #18 `ListServicePrincipalSecrets.nextPageToken` JSDoc (originally cited at model.ts:62): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #19 `ListServicePrincipalSecrets.pageToken` JSDoc (originally cited at model.ts:50-54): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #20 `Client` (originally cited at client.ts:42): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. -- #21 `Client.createServicePrincipalSecret` etc. (originally cited at client.ts:72, 101, 129): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. -- #22 `executeCall` vs `executeHttpCall` (originally cited at utils.ts:26, 65): Fixed in regeneration on 2026-05-20 — package source removed; symbols no longer present. -- #23 `flattenQueryParams` (originally cited at utils.ts:123): Fixed in regeneration on 2026-05-20 — package source removed; symbol no longer present. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/serviceprincipalsecretsproxy.md b/.agent/naming-audit/serviceprincipalsecretsproxy.md deleted file mode 100644 index 756b2fe9..00000000 --- a/.agent/naming-audit/serviceprincipalsecretsproxy.md +++ /dev/null @@ -1,81 +0,0 @@ -# Naming Audit: serviceprincipalsecretsproxy - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/serviceprincipalsecretsproxy/src/v1/` (no longer exists) -**Versions audited:** v1 -**Inferred domain:** Account-level CRUD over OAuth client secrets attached to a -service principal (create, list, delete), previously exposed as a "proxy" -variant whose surface area was byte-identical to the sibling -`serviceprincipalsecrets` package. -**Total weird names flagged:** 0 - -> **Status:** As of regeneration on 2026-05-20, the entire -> `serviceprincipalsecretsproxy` package has been removed from the source -> tree. Only the `dist/` build artifact directory remains. The duplicate- -> package issue flagged in H1 was resolved by deletion. Every finding below -> is consequently Fixed. - ---- - -## Summary table - -_None._ - ---- - -## High severity (must fix) - -_None._ - ---- - -## Medium severity (worth pushing back on) - -_None._ - ---- - -## Low severity (nits) - -_None._ - ---- - -## Observations (not flags) - -_None._ - ---- - -## Fixed - -- #1 package `serviceprincipalsecretsproxy` (originally cited at package level): Fixed in regeneration on 2026-05-20 — entire `src/` tree removed; package no longer exists in source. -- #2 package `serviceprincipalsecretsproxy` (originally cited at package level): Fixed in regeneration on 2026-05-20 — package removed entirely; long undelimited name is gone. -- #3 package `serviceprincipalsecretsproxy` (originally cited at package level): Fixed in regeneration on 2026-05-20 — misleading "proxy" suffix gone with the package. -- #4 `CreateServicePrincipalSecret` (originally cited at model.ts:6): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. -- #5 `CreateServicePrincipalSecret.servicePrincipal` (originally cited at model.ts:10): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #6 `CreateServicePrincipalSecret.lifetime` (originally cited at model.ts:12): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #7 `CreateServicePrincipalSecretResponse` (originally cited at model.ts:15): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. -- #8 `CreateServicePrincipalSecretResponse.id` (originally cited at model.ts:17): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #9 `CreateServicePrincipalSecretResponse.secret` (originally cited at model.ts:19): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #10 `CreateServicePrincipalSecretResponse.secretHash` (originally cited at model.ts:21): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #11 `CreateServicePrincipalSecretResponse.status` (originally cited at model.ts:27): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #12 `CreateServicePrincipalSecretResponse.createTime` / `updateTime` (originally cited at model.ts:23, 25): Fixed in regeneration on 2026-05-20 — source file removed; fields no longer exist. -- #13 `CreateServicePrincipalSecretResponse.expireTime` (originally cited at model.ts:29): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #14 `DeleteServicePrincipalSecret` (originally cited at model.ts:32): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. -- #15 `DeleteServicePrincipalSecret.secretId` (originally cited at model.ts:38): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #16 `ListServicePrincipalSecrets` (originally cited at model.ts:44): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. -- #17 `ListServicePrincipalSecrets.pageToken` (originally cited at model.ts:54): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #18 `ListServicePrincipalSecrets.pageSize` (originally cited at model.ts:55): Fixed in regeneration on 2026-05-20 — source file removed; field no longer exists. -- #19 `ServicePrincipalSecret` (originally cited at model.ts:66): Fixed in regeneration on 2026-05-20 — source file removed; type no longer exists. -- #20 `ServicePrincipalSecret.id` / `secret` / `secretHash` / `status` (originally cited at model.ts:68, 70, 72, 78): Fixed in regeneration on 2026-05-20 — source file removed; fields no longer exist. -- #21 `Client` (originally cited at client.ts:42): Fixed in regeneration on 2026-05-20 — source file removed; class no longer exists. -- #22 `Client.createServicePrincipalSecret` / `deleteServicePrincipalSecret` / `listServicePrincipalSecrets` (originally cited at client.ts:72, 101, 129): Fixed in regeneration on 2026-05-20 — source file removed; methods no longer exist. -- #23 `PACKAGE_SEGMENT` (originally cited at client.ts:37): Fixed in regeneration on 2026-05-20 — source file removed; constant no longer exists. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index 2c55c12f..e4ce411d 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 **Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). -**Total weird names flagged:** 84 +**Total weird names flagged:** 46 --- @@ -36,82 +36,44 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | 6 | High | Vague/generic type | `UserPreference` | `model.ts:452` | | 7 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:102, 106, 175, 292, 296, 442` | | 8 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | -| 9 | High | Cryptic abbreviation (undefined) | `Gov` in `disableGovTagCreation` | `model.ts:302` | -| 10 | High | Generic field name | `value` (on `BooleanMessage`, `IntegerMessage`, `StringMessage`, `PersonalComputeMessage`) | `model.ts:103, 176, 293, 444` | -| 11 | High | Generic field name | `name` (across `Setting`, `SettingsMetadata`, `UserPreference`, `GetPublicAccountSettingRequest`, ...) | `model.ts:158, 167, 172, 273, 282, 288, 307, 426, 454` | -| 12 | High | Generic field name | `type?: string` on `SettingsMetadata` | `model.ts:430` | -| 13 | High | Generic field name | `setting?: Setting` on update requests | `model.ts:274, 283, 289` | -| 14 | High | Generic field name | `setting?: UserPreference` (note: type is UserPreference, field name is `setting`) | `model.ts:283` | -| 15 | High | Generic discriminator value | `booleanVal`, `stringVal`, `integerVal` | `model.ts:315, 320, 325, 372, 377, 382, 463-464` | -| 16 | High | Generic discriminator value | `effectiveBooleanVal`, `effectiveStringVal`, `effectiveIntegerVal` | `model.ts:372, 377, 382, 472, 473` | -| 17 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:157, 162, 181, 209, 272, 279` | -| 18 | High | Underspecified ID | `userId` | `model.ts:165, 211, 281, 456` | -| 19 | High | Misleading type name | `UserPreference` field named `setting` (on PatchPublicAccountUserPreferenceRequest) | `model.ts:283` | -| 20 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:311, 313, 369, 370` | -| 21 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:296` | -| 22 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:106` | -| 23 | High | Verb-tense | `disableGovTagCreation` (imperative verb as state field) | `model.ts:302` | -| 24 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | -| 25 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` | -| 26 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | -| 27 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | -| 28 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | -| 29 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:229` | -| 30 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:208` | -| 31 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:277` | -| 32 | Medium | Singular/plural mismatch | `listAccountSettingsMetadata` returns `settingsMetadata?: SettingsMetadata[]` — pluralisation collides with the singular type | `model.ts:198, 200`; `client.ts:166` | -| 33 | Medium | Singular/plural mismatch | `listAccountUserPreferencesMetadata` returns `settingsMetadata?: SettingsMetadata[]` (not `userPreferencesMetadata`) | `model.ts:229-231`; `client.ts:226` | -| 34 | Medium | Singular/plural mismatch | `listWorkspaceSettingsMetadata` field reuses `settingsMetadata` | `model.ts:256-258` | -| 35 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | -| 36 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | -| 37 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:302` | -| 38 | Medium | Field contradicting type domain | `automaticClusterUpdateWorkspace` discriminator on `Setting` (a workspace-only feature on a unified type) | `model.ts:330` | -| 39 | Medium | Field contradicting type domain | `restrictWorkspaceAdmins` discriminator on `Setting` used by both workspace and account endpoints | `model.ts:345` | -| 40 | Medium | Generic field name | `canToggle?: boolean` on `ClusterAutoRestartMessage` (toggle what?) | `model.ts:108` | -| 41 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:152-153` | -| 42 | Medium | Overly verbose discriminator | `effectiveAutomaticClusterUpdateWorkspace` | `model.ts:387` | -| 43 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingApprovedDomains` | `model.ts:392` | -| 44 | Medium | Overly verbose discriminator | `effectiveAibiDashboardEmbeddingAccessPolicy` | `model.ts:397` | -| 45 | Medium | Overly verbose discriminator | `effectiveRestrictWorkspaceAdmins` | `model.ts:402` | -| 46 | Medium | Overly verbose discriminator | `effectivePersonalCompute` | `model.ts:407` | -| 47 | Medium | Generic name | `displayName` on `SettingsMetadata` (vs `name`) | `model.ts:439` | -| 48 | Medium | Cryptic abbreviation | `docsLink` (vs `documentationUrl`) | `model.ts:432` | -| 49 | Medium | Misleading field | `name` on `SettingsMetadata` (means "key", not "human-readable name" — which is `displayName`) | `model.ts:426` | -| 50 | Medium | Acronym casing | `Url` vs `URL` (Google TS style allows either, package uses neither — it uses `Link` and `url`) | `model.ts:432`; `utils.ts:70, 98, 103` | -| 51 | Medium | Field name verb-as-noun | `restartEvenIfNoUpdatesAvailable?: boolean` (whole sentence as field name) | `model.ts:111` | -| 52 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | -| 53 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | -| 54 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | -| 55 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:78` | -| 56 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:78` | -| 57 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:78, 83` | -| 58 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:78` | -| 59 | Low | Reserved-word adjacency | `value` (used as discriminated union field) | `model.ts:103, 176, 293, 313, 444, 462` | -| 60 | Low | Reserved-word adjacency | `type` (used as plain field on `SettingsMetadata`) | `model.ts:430` | -| 61 | Low | Reserved-word adjacency | `name` (used everywhere, common JS builtin name) | `model.ts:158, 167, 172, 273, 282, 288, 307, 426, 454` | -| 62 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:157, 165, ...` | -| 63 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | -| 64 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:283` | -| 65 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:670, 1059` | -| 66 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | -| 67 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:176` | -| 68 | Low | Singular-list mismatch | the `Setting.value` field name collides with `BooleanMessage.value` etc. (nested `value.value`) | `model.ts:313, 103` | -| 69 | Low | Long discriminator string | `aibiDashboardEmbeddingApprovedDomains` (string literal used at runtime by consumers) | `model.ts:335-337` | -| 70 | Low | Long discriminator string | `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) | `model.ts:392` | -| 71 | Low | Vague | `enabled?: boolean` (enabled what? on `ClusterAutoRestartMessage`) | `model.ts:107` | -| 72 | Low | Vague | `frequency?` on `WeekDayBasedSchedule` (frequency-of-what?) | `model.ts:141` | -| 73 | Low | Vague | `status?` on `RestrictWorkspaceAdminsMessage` (status-of-what?) | `model.ts:297` | -| 74 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | -| 75 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:164-165` | -| 76 | Low | Cryptic field | `unavailableForNonEnterpriseTier` (double negative — "unavailable" + "non-") | `model.ts:125` | -| 77 | Low | Cryptic field | `unavailableForDisabledEntitlement` (same double negative) | `model.ts:127` | -| 78 | Low | Misleading verb | `forcedForComplianceMode` (passive verb as boolean state name; should be `forceEnabledInComplianceMode` or `complianceModeForcesEnabled`) | `model.ts:129` | -| 79 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | -| 80 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | -| 81 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | -| 82 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` | -| 83 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:98, 497, 928` | -| 84 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #25 as a proto-leak category) | `model.ts:156, 161, 170, 270, 277, 286` | +| 9 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:157, 162, 181, 209, 272, 279` | +| 10 | High | Underspecified ID | `userId` | `model.ts:165, 211, 281, 456` | +| 11 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:311, 313, 369, 370` | +| 12 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:296` | +| 13 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:106` | +| 14 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` | +| 15 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:98, 497, 928` | +| 16 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | +| 17 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` | +| 18 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | +| 19 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | +| 20 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | +| 21 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:229` | +| 22 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:208` | +| 23 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:277` | +| 24 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | +| 25 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | +| 26 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:302` | +| 27 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:152-153` | +| 28 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #17 as a proto-leak category) | `model.ts:156, 161, 170, 270, 277, 286` | +| 29 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | +| 30 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | +| 31 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | +| 32 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:78` | +| 33 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:78` | +| 34 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:78, 83` | +| 35 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:78` | +| 36 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:157, 165, ...` | +| 37 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | +| 38 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:283` | +| 39 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:670, 1059` | +| 40 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | +| 41 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:176` | +| 42 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | +| 43 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:164-165` | +| 44 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | +| 45 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | +| 46 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | --- @@ -179,72 +141,28 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** `AIBI` (acronym casing) or spell out `AiBi` for the AI/BI Genie embedding feature. Add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." - **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. -### 9. `Gov` in `disableGovTagCreation` — undocumented abbreviation - -- **File:line:** `model.ts:302` -- **Category:** Cryptic abbreviation -- **Suggestion:** `disableGovernanceTagCreation`. The full word adds five characters and removes ambiguity (`Gov` could be government, governance, governor, ...). -- **Rationale:** The doc says "workspace admins cannot create governance tags" — so "Gov" abbreviates "Governance". The wire key is `disable_gov_tag_creation` (`model.ts:670`), but the TS surface can be more verbose. - -### 10. `value` field everywhere — generic field name - -- **File:line:** `model.ts:103, 176, 293, 444` on the message wrappers; `model.ts:313, 462` on the discriminated unions; nested deep inside (`Setting.value.booleanVal.value`). -- **Category:** Generic field name + reserved-word adjacency -- **Suggestion:** For the discriminated unions (`Setting.value`), `payload` would be slightly clearer. -- **Rationale:** `setting.value.booleanVal.value` is four levels of `.value`/`.someVal` indirection to access one boolean. The naming makes auto-complete useless. `value` is a member of many JS built-ins (Map entries, Symbol.iterator results, DOM events, IndexedDB cursors), so it has soft reserved-word risk. - -### 11. `name` everywhere — generic field name - -- **File:line:** `model.ts:158, 167, 172, 273, 282, 288, 307, 426, 454` -- **Category:** Generic field name -- **Suggestion:** `settingKey` or `settingName` would convey purpose. The current `name` is so generic the JSDoc has to repeat "Name of the setting" everywhere. -- **Rationale:** The field is in fact the *key* — the unique identifier used in the URL path (`/settings/${req.name ?? ''}`) — not a human display name. The actual display name is `displayName` on `SettingsMetadata`. Naming the key "name" and the human name "displayName" inverts intuition (typically "name" is the display name and "id"/"key" is the identifier). - -### 12. `type?: string` on `SettingsMetadata` — generic + misleading - -- **File:line:** `model.ts:430` -- **Category:** Generic field name, reserved-word adjacency, misleading -- **Suggestion:** `valueTypeMessage` or `sampleTypeMessage`. The JSDoc says "Sample message depicting the type of the setting. To set this setting, the value sent must match this type." -- **Rationale:** A field called `type` returning a *sample message* (not a type-id or schema URI) is misleading. Combined with the JS-builtin overlap (`typeof obj.type === 'string'`), the field name invites confusion. - -### 13–14. `setting?: Setting` and `setting?: UserPreference` — generic field name + misleading - -- **File:line:** `model.ts:274, 283, 289` -- **Category:** Generic field name + misleading -- **Suggestion:** Rename to match the typed payload: `setting?: Setting` is okay; `setting?: UserPreference` is wrong — should be `userPreference?: UserPreference`. -- **Rationale:** On `PatchPublicAccountUserPreferenceRequest`, the field is named `setting` but typed `UserPreference`. The whole package's distinction between "setting" and "user preference" depends on these being separate concepts — so calling the user-preference field "setting" undoes that distinction at the request level. - -### 15–16. `booleanVal`, `stringVal`, `integerVal`, `effective*Val` — generic discriminator values - -- **File:line:** `model.ts:315, 320, 325, 372, 377, 382, 463-464, 472-473` -- **Category:** Generic field name -- **Suggestion:** Drop the `*Val` suffix (it duplicates the parent field `value`) and name by domain: instead of `value: {$case: 'booleanVal', booleanVal: BooleanMessage}`, prefer `value: {kind: 'boolean', boolean: boolean}`. -- **Rationale:** A user writing `setting.value?.$case === 'booleanVal'` then accessing `setting.value.booleanVal.value` does three discriminations to read a single bool. The "Val" abbreviation is the only naming variation between the discriminator tag ("booleanVal") and the type name ("BooleanMessage"); the abbreviation contributes nothing. - -### 17–18. `accountId`, `userId` — underspecified IDs +### 9–10. `accountId`, `userId` — underspecified IDs - **File:line:** `model.ts:157, 162, 165, 181, 209, 211, 272, 279, 281, 456` - **Category:** Underspecified ID - **Suggestion:** Document the ID format (UUID, opaque-string, numeric, ...) in JSDoc consistently. Currently only some occurrences have a doc (" account ID of the account being managed"), and the format isn't specified anywhere. - **Rationale:** Users have no way to know whether the SDK accepts `"acct-12345"`, `"abc...uuid"`, or an integer-as-string. The Go SDK's pattern of relying on type-level documentation isn't carried over. -### 19. `setting` field on `PatchPublicAccountUserPreferenceRequest` (covered in #14) - -### 20. `effectiveValue` vs `value` — undocumented distinction +### 11. `effectiveValue` vs `value` — undocumented distinction - **File:line:** `model.ts:311-363 (value) vs 369-421 (effectiveValue)` - **Category:** Misleading - **Suggestion:** Add a JSDoc explaining the relationship at the `Setting` type level. Currently the distinction is only documented as "The user-set value that goes into storage" (311) vs "The final effective value from server as per the policy evaluation" (369) — a reader has to read both blocks to understand they're a get/set asymmetry. - **Rationale:** This is a non-obvious feature where the user sets `value` but the server might return a different `effectiveValue` after applying policy. Worth a top-level doc, not just per-block. -### 21–23. Verb-tense action-as-noun naming +### 12–13. Verb-tense action-as-noun naming -- **File:line:** `model.ts:296 (RestrictWorkspaceAdminsMessage), 106 (ClusterAutoRestartMessage), 302 (disableGovTagCreation field)` +- **File:line:** `model.ts:296 (RestrictWorkspaceAdminsMessage), 106 (ClusterAutoRestartMessage)` - **Category:** Verb-tense inconsistency -- **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`), `governanceTagCreationDisabled: boolean`. -- **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. `disableGovTagCreation` is a verb-phrase as a field name suggesting "do the action of disabling", which is misleading for a boolean state. +- **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`). +- **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. -### 82. Proto-nested underscore type naming — proto-architectural leak +### 14. Proto-nested underscore type naming — proto-architectural leak - **File:line:** `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` (and the corresponding marshal/unmarshal schema declarations) - **Category:** Proto-architectural leak (nested-message naming) @@ -261,7 +179,7 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Promote nested message/enum types to top-level TS interfaces with descriptive names: `AccessPolicyType`, `MaintenanceWindow`, `DayOfWeek`, `WeekDayFrequency`, `MaintenanceSchedule`, `WindowStartTime`, `EnablementDetails`, `PersonalComputeMode`, `WorkspaceAdminRestrictionStatus`. Where two top-level names would collide across packages, prefix with the owning concept (e.g., `MaintenanceWindowDayOfWeek`) but never use `_`. - **Rationale:** Underscore-separated multi-word TS identifiers are non-idiomatic (Google TS style mandates `PascalCase` for types; Microsoft TS handbook agrees). The `*Foo_Bar_Baz` chain is purely a transliteration of proto's nested-message scoping — TS has module namespaces (`Foo.Bar.Baz`) and lexical scoping for that, neither of which is used here. The eslint-disable comments are the smoking gun. -### 83. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak +### 15. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak - **File:line:** `model.ts:98, 497 (unmarshal), 928 (marshal)` - **Category:** Proto-architectural leak (`Api` mid-position) + `*Message` suffix (covered in #7) @@ -273,40 +191,40 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ## Medium severity -### 24. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use +### 16. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use - **File:line:** `model.ts:94-96` - **Category:** Singular/plural mismatch - **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. -### 25. `*Public*` qualifier — redundant +### 17. `*Public*` qualifier — redundant - **File:line:** `model.ts:156, 161, 170, 270, 277, 286` - **Category:** Redundant qualifier -- **Suggestion:** Drop `Public` from request type names (and method names — #26). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Suggestion:** Drop `Public` from request type names (and method names — #18). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. - **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. -### 26. Method names: `getPublic*`, `patchPublic*` — redundant `Public` +### 18. Method names: `getPublic*`, `patchPublic*` — redundant `Public` - **File:line:** `client.ts:83, 112, 137, 346, 378, 409` - **Category:** Redundant qualifier + verbose - **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. -### 27. `patch*` vs `update*` — inconsistent action verb across SDK +### 19. `patch*` vs `update*` — inconsistent action verb across SDK - **File:line:** `client.ts:346, 378, 409` (use `patch`) - **Category:** Inconsistent action verbs - **Suggestion:** Pick one verb. `update` is the verb in `accountsettings/v1/client.ts` and `workspacesettings/v1/client.ts` for the equivalent operation; `patch` is used here. Cross-package consistency matters. - **Rationale:** Same operation (PATCH HTTP verb against a settings endpoint) named `update*` in the v1 packages and `patch*` in this v2 package. Users will look for `update*` first based on muscle memory. -### 28. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action +### 20. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action - **File:line:** `client.ts:378` - **Category:** Inconsistent + verbose - **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. - **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. -### 29–31. Long type names +### 21–23. Long type names - **File:line:** `model.ts:229, 208, 277` - **Category:** Overly verbose @@ -316,14 +234,7 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - `PatchPublicAccountUserPreferenceRequest` (39 chars) - **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. -### 32–34. `settingsMetadata` field name vs sibling list semantics - -- **File:line:** `model.ts:198, 200, 229-231, 256-258` -- **Category:** Singular/plural mismatch + field naming -- **Suggestion:** On `ListAccountUserPreferencesMetadataResponse`, the field should be `userPreferencesMetadata`, not `settingsMetadata`. Currently the response field for "list of user preferences" is typed as `SettingsMetadata[]` and named `settingsMetadata` — which is technically the same metadata type but linguistically misleading. -- **Rationale:** A consumer reading `resp.settingsMetadata` on a `ListAccountUserPreferencesMetadataResponse` will be confused why "settings" appears on a "user preferences" response. - -### 35. `PreviewPhase` enum — mixed temporal/qualitative members +### 24. `PreviewPhase` enum — mixed temporal/qualitative members - **File:line:** `model.ts:11-27` - **Category:** Verb-tense / categorisation inconsistency @@ -331,79 +242,39 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. - **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. -### 36–37. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` +### 25–26. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` - **File:line:** `model.ts:30, 88, 94, 302` - **Category:** Acronym casing - **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. -### 38–39. `automaticClusterUpdateWorkspace`, `restrictWorkspaceAdmins` discriminator names mixing scope - -- **File:line:** `model.ts:330 (auto-cluster on a unified Setting), 345 (restrict-admins on Setting)` -- **Category:** Field contradicting type domain -- **Suggestion:** Either drop the `Workspace` suffix from `automaticClusterUpdateWorkspace` (the parent `Setting` type is scope-agnostic) or always include the scope (then `personalCompute` should be `personalComputeAccount`). -- **Rationale:** Some payload discriminators mention scope (`automaticClusterUpdateWorkspace`), others don't (`personalCompute`, `restrictWorkspaceAdmins`). A reader can't predict the rule. - -### 40. `canToggle?: boolean` on `ClusterAutoRestartMessage` - -- **File:line:** `model.ts:108` -- **Category:** Generic field -- **Suggestion:** `userCanToggle: boolean` or `togglePermitted: boolean`. "Toggle what?" is unclear from the field alone (presumably toggle the `enabled` field, but that's implicit). - -### 41. `hours`, `minutes` with no timezone +### 27. `hours`, `minutes` with no timezone - **File:line:** `model.ts:152-153` - **Category:** Generic field name, missing constraint -- **Suggestion:** Add doc specifying the time-zone interpretation, or rename `utcHours`/`utcMinutes` if UTC, or add a `timezone?: string` field. +- **Suggestion:** Add doc specifying the time-zone interpretation, or add a `timezone?: string` field. - **Rationale:** A "maintenance window start time" without timezone is ambiguous (workspace TZ? customer TZ? UTC?). -### 42–46. Overly verbose `effective*` discriminator names - -- **File:line:** `model.ts:387, 392, 397, 402, 407` -- **Category:** Overly verbose -- **Suggestion:** Either drop the `effective` prefix on the discriminator value (the parent field is `effectiveValue`, so the prefix is redundant) or split into two top-level discriminated unions (`Setting.value: {$case: 'automaticClusterUpdateWorkspace', ...}` and `Setting.effectiveValue: {$case: 'automaticClusterUpdateWorkspace', ...}`). -- **Rationale:** `effectiveAibiDashboardEmbeddingApprovedDomains` (45 chars) is the longest discriminator in the package and stutters `effective`/`Effective` with its parent field name. - -### 47–49. `name` (key) vs `displayName` (human name) — inverted intuition - -- **File:line:** `model.ts:426, 439` -- **Category:** Generic name + misleading -- **Suggestion:** Rename `name` → `key`, then `displayName` → `name` (or `label`). -- **Rationale:** Across most data-modelling traditions, `name` is the human-readable name and `key`/`id` is the identifier. This package inverts the convention. - -### 50. `Url` vs `URL` vs `Link` - -- **File:line:** `model.ts:432 (docsLink)`; `utils.ts:70, 98, 103 (url)` -- **Category:** Acronym casing inconsistency -- **Suggestion:** `docsUrl` for parity with `request.url` already used elsewhere. "Link" is HTML-flavoured; "URL" is the data. - -### 51. `restartEvenIfNoUpdatesAvailable` — whole sentence as field name - -- **File:line:** `model.ts:111` -- **Category:** Field name verb-as-noun, overly verbose -- **Suggestion:** `forceRestart: boolean` (the semantics — restart even when not needed for updates). Or `restartOnSchedule: boolean`. -- **Rationale:** 31-character field name encoding a clause is awkward; a one-word semantic name reads better. - -### 84. `*Public*` qualifier as proto-architectural leak (reframe of #25) +### 28. `*Public*` qualifier as proto-architectural leak (reframe of #17) - **File:line:** `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` - **Category:** Proto-architectural leak (`Public` mid-position) - **Why:** `Public` in `GetPublic*Request`, `PatchPublic*Request`, and method names `getPublic*`/`patchPublic*` is a direct echo of the proto service-name `PublicSettingsService` — i.e., the *server-side* internal-vs-public service split. The TS SDK only ships the public surface, so the qualifier signals nothing the user can act on. - **Suggestion:** Drop `Public` from every request type and every method name. `GetAccountSettingRequest`/`getAccountSetting`, `PatchAccountSettingRequest`/`patchAccountSetting`, etc. -- **Rationale:** This duplicates #25 and #26 but reframes them as a *proto-architectural leak* per the scan brief. `Public`/`Internal` are explicitly on the flag list. The two earlier findings catalogued the names; this one names the cause. +- **Rationale:** This duplicates #17 and #18 but reframes them as a *proto-architectural leak* per the scan brief. `Public`/`Internal` are explicitly on the flag list. The two earlier findings catalogued the names; this one names the cause. --- ## Low severity -### 52–54. Long enum values +### 29–31. Long enum values - **File:line:** `model.ts:85, 56, 57` - **Category:** Long enum value - **Identifiers:** `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) - **Suggestion:** For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. -### 55–58. Undocumented abbreviations in JSDoc +### 32–35. Undocumented abbreviations in JSDoc - **File:line:** `model.ts:78, 83` - **Category:** Cryptic abbreviation @@ -411,93 +282,62 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Spell out in the JSDoc. - **Rationale:** Users reading the IDE tooltip will see "WS admins to create OBO tokens for all SPs" without expansions. -### 59–61. Reserved-word adjacency: `value`, `type`, `name` - -- **File:line:** `model.ts` passim -- **Category:** Reserved-word risk -- **Suggestion:** See #10–12. - -### 62–63. Acronym casing notes +### 36–37. Acronym casing notes - **File:line:** `model.ts:157, 78` - **Category:** Acronym casing - **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). -### 64. `setting?: UserPreference` doc mismatch +### 38. `setting?: UserPreference` doc mismatch -- Already covered in #14; flagged again here for the JSDoc inconsistency (`model.ts:283` field is "setting" but type is "UserPreference"). +- **File:line:** `model.ts:283` +- **Category:** Misleading +- **Suggestion:** Update the JSDoc to refer to "user preference" rather than "setting" so the doc matches the type. -### 65. `disable_gov_tag_creation` wire key +### 39. `disable_gov_tag_creation` wire key - **File:line:** `model.ts:670, 1059` - **Category:** Cryptic abbreviation (server-controlled) - **Suggestion:** N/A — wire format is fixed. Note for documentation. -### 66. `restrict_tokens_and_job_run_as` enum string value +### 40. `restrict_tokens_and_job_run_as` enum string value - **File:line:** `model.ts:85` - **Category:** Wire value - **Suggestion:** N/A — wire-fixed. -### 67. `IntegerMessage` misleading in JS +### 41. `IntegerMessage` misleading in JS - **File:line:** `model.ts:175-177` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 68. Nested `.value.value` - -- **File:line:** `model.ts:313, 103` -- **Category:** Singular naming collision -- **Suggestion:** See #10. +### 42. `patch*` vs `update*` -### 69–70. Long discriminator strings +- See #19. -- **File:line:** `model.ts:335-337, 392` -- **Category:** Long string identifier -- **Suggestion:** See #15, #42–46. - -### 71–73. Vague field names - -- **File:line:** `model.ts:107 (enabled), 141 (frequency), 297 (status)` -- **Category:** Vague -- **Suggestion:** Add domain context: `clusterRestartEnabled`, `restartFrequency`, `workspaceAdminRestrictionStatus`. -- **Rationale:** Inside their parent types the meaning is somewhat clear but auto-complete shows only the field name, which is generic. - -### 74. `patch*` vs `update*` - -- See #27. - -### 75. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" +### 43. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" - **File:line:** `model.ts:164-165` - **Category:** Misleading - **Suggestion:** Use the same vocabulary as the type — "preference" for user-preference endpoints. -### 76–78. Double-negative / passive booleans on `EnablementDetails` - -- **File:line:** `model.ts:125, 127, 129` -- **Category:** Misleading / cognitive load -- **Identifiers:** `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement`, `forcedForComplianceMode` -- **Suggestion:** Phrase positively where possible: `availableForEnterpriseTier?: boolean`, `availableForEntitlement?: boolean`, `forceEnabledByComplianceMode?: boolean`. Double-negatives ("unavailable for non-enterprise") slow comprehension. -- **Rationale:** "Unavailable for non-enterprise tier" requires the reader to parse two negatives ("un-" and "non-") to conclude "this is only available for enterprise". Worth one extra second of think-time on every field access. - -### 79. Cross-package `Dbfs` casing +### 44. Cross-package `Dbfs` casing - **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) - **Category:** Cross-package acronym casing - **Suggestion:** Note for the cross-package audit, not actionable here. -### 80. `host` — generic class field +### 45. `host` — generic class field - **File:line:** `client.ts:54` - **Category:** Generic - **Suggestion:** `baseUrl` (consistent with `fetch` API conventions). "Host" can mean DNS host, host machine, etc. -### 81. `BETA` member adjacent to `PUBLIC_PREVIEW` +### 46. `BETA` member adjacent to `PUBLIC_PREVIEW` -- See #35. +- See #24. --- @@ -517,22 +357,7 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess 5. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. -6. **Field-vs-discriminator name divergence on `value`.** A consumer constructing a `Setting` writes: - ``` - { name: 'restrict_workspace_admins', - value: { $case: 'restrictWorkspaceAdmins', - restrictWorkspaceAdmins: { status: '...' } } } - ``` - — three repetitions of the variant name. This is the proto3 `oneof` wire model leaking. A TS-native model would be: - ``` - { name: 'restrict_workspace_admins', - restrictWorkspaceAdmins: { status: '...' } } - ``` - — same expressivity, half the typing. - -7. **`name` field's role swings.** On `Setting`/`UserPreference`/`SettingsMetadata` it is the *key* of the setting (used in URL paths). On most other Databricks resources `name` is the human-readable label. The inverted convention is a small but real footgun. - -8. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. +6. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. --- @@ -566,7 +391,3 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | `src/v2/utils.ts` | 150 (full) | 100% — `HttpCallOptions`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` audited. Shared utility code; no naming issues unique to this package (the same scaffolding appears in every package). | --- - -## Fixed - -_None._ diff --git a/.agent/naming-audit/sharing.md b/.agent/naming-audit/sharing.md index 7841c830..3574c2f9 100644 --- a/.agent/naming-audit/sharing.md +++ b/.agent/naming-audit/sharing.md @@ -11,6 +11,12 @@ to one or more recipients (other Databricks metastores or external OIDC / token-authenticated clients). **Total weird names flagged:** 5 +**Last rescanned:** 2026-05-26 (post regeneration #156). All five findings +re-verified against the regenerated source; none addressed upstream. +`client.ts` line numbers drifted with the regen (the `getActivationUrlInfo` +method moved from line 369 to line 398), but the underlying naming pattern +is unchanged. + ## Summary | Severity | Count | @@ -145,8 +151,8 @@ end suffixes are not flagged. ## Low severity (nits) -### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:363, 369, client.ts:369` -- **Why:** The method `getActivationUrlInfo` (client.ts:369) returns +### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:363, 369, client.ts:398` +- **Why:** The method `getActivationUrlInfo` (client.ts:398) returns `GetActivationUrlInfoRequest_Response`, an empty interface (model.ts:369). The mid-position `Info` in both the method and the request type adds nothing semantic: the method just gets the diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index 093e5091..16fcf3e4 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -28,15 +28,15 @@ The package name `statementexecution` is reasonable in isolation, but the SDK opening the marketplace sees four packages whose names overlap heavily and has to read every one to pick the right tool. See finding #1. -**Total weird names flagged:** 52 +**Total weird names flagged:** 43 ## Summary | Severity | Count | | --- | --- | -| High | 10 | -| Medium | 29 | -| Low | 10 | +| High | 9 | +| Medium | 24 | +| Low | 7 | | Observation | 3 | ## High severity @@ -99,186 +99,146 @@ to read every one to pick the right tool. See finding #1. - **Suggested name:** `StatementExecutionClient`. - **Rationale:** Repeated SDK-wide pattern. -### 10. `dataArray` field on `ResultData` — `src/v1/model.ts:422` -- **Why weird:** Field name `dataArray` on a type already called `ResultData`. The two `data` tokens stack: `resultData.dataArray`. The JSDoc explains it carries a `JSON_ARRAY` formatted payload, so the name is gesturing at the wire format. But the type name is the *outer* wrapper, so saying "data" inside "Data" reads as redundant. -- **Category:** 1 (vague — `data`, `array` both generic), 12 (duplicate concept — `Data.dataArray`), 20 (type-suffix tautology). -- **Suggested name:** `rows` (matches the SQL semantics: each entry of the array is a row). Or rename the outer type to `ResultChunk` so `chunk.data` is meaningful. -- **Rationale:** When `outerType.innerField` stutters the same noun, one of them is misnamed. - ## Medium severity -### 11. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` -- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #21 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. +### 10. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` +- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #17 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. - **Category:** 13 (verb-tense inconsistency), 17 (US/UK spelling inconsistency for "cancel"). - **Suggested name:** Pick one cancel spelling. The wire is `CANCELED` (single-l) per this enum and `CANCELLED` per `ServiceErrorCode`. Resolve at wire level. - **Rationale:** Twin spellings of the same English word in adjacent enums in the same file is a maintenance hazard. Compare `StatementStatus_State.CANCELED` to `ServiceErrorCode.CANCELLED`. -### 12. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` +### 11. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` - **Why weird:** A user importing from both `statementexecution` and `queryexecution` finds a `statementId` field on responses from both packages. In `statementexecution` it identifies the SQL Statement Execution submission. In `queryexecution` (a published-dashboard query) the JSDoc explicitly says "The statement_id should be identical to data_token in SuccessStatus and PendingStatus" — i.e. it's an audit copy, not a primary key. The same name means different things in two adjacent packages. - **Category:** 12 (duplicate concept — same name, different meaning), 19 (underspecified ID — what kind of statement?). - **Suggested name:** Keep `statementId` here (primary identifier); rename the audit-only copy in `queryexecution` (see `queryexecution.md` Finding #14). - **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. -### 13. `warehouseId` field — `src/v1/model.ts:158` -- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #33. +### 12. `warehouseId` field — `src/v1/model.ts:158` +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #27. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. -### 14. `statement` field name is the package name — `src/v1/model.ts:153` -- **Why weird:** The request type `ExecuteStatementRequest` carries a field literally called `statement`. The package name is `statementexecution`. The class name is `Client` (per #9). So a call reads: - ```ts - client.executeStatement({statement: 'SELECT 1', warehouseId: '...'}) - ``` - `statement` is the SQL text; the package name promises `statement execution`; the method is `executeStatement`. The word "statement" appears three times to mean three slightly different things: the package scope, the operation, and the SQL string. At use sites this looks like stutter. -- **Category:** 1 (vague — `statement` could be anything), 12 (duplicate concept — overloaded word), 15 (generic field name). -- **Suggested name:** Rename the field to `sql` (or `query` if not colliding with `queryexecution`). The wire is `statement`, so a marshaller maps `sql -> statement`. -- **Rationale:** The package, the class, and the field shouldn't all spell the same word three times. - -### 15. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` +### 13. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` - **Why weird:** Two parallel "limit" fields; `rowLimit` has no default mentioned; `byteLimit` mentions a "100 GiB default if not explicitly set" for `EXTERNAL_LINKS` disposition. The asymmetric defaults aren't captured by the types. JSDoc encodes them; users have to read both. - **Category:** 16 (field-vs-domain — domain has implicit defaults the type doesn't show), 17 (asymmetric defaults). - **Suggested name:** Names are fine; consolidate JSDoc so both fields document defaults symmetrically. - **Rationale:** Pair-fields should have parallel JSDoc structure. -### 16. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` +### 14. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` - **Why weird:** Field name is `parameters`. Element type is `StatementParameter`. The element name is more specific (statement parameter) than the field (parameters). At the JSDoc level, the field describes "parameter markers" — which is yet a third name for the same concept. So users see: `parameters` (field) vs `StatementParameter` (element type) vs "parameter markers" (docs). Pick one vocabulary. - **Category:** 12 (duplicate concept — three names for one idea), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the element type to `Parameter` (less qualified than field) or rename the field to `statementParameters`. The wire shape probably matters; pick the less verbose option. - **Rationale:** Multiple synonyms for one concept burns reader attention. -### 17. `queryTags` field on `ExecuteStatementRequest` — `src/v1/model.ts:326` -- **Why weird:** Field is `queryTags`, element type is `QueryTag`. The user is *executing a statement*, but the metadata tags are called *query* tags. There's no `Query` type in this package; the prefix `Query` here is a Databricks billing/observability term (queries get tagged for analytics). For a TS user who hasn't seen the bigger picture, the mismatch between `executeStatement` and `QueryTag[]` reads as inconsistent. -- **Category:** 12 (duplicate concept — `statement` vs `query`), 17 (inconsistent vocabulary). -- **Suggested name:** Rename to `tags` + `Tag` (the surrounding context already says "statement", so the qualifier is redundant). Wire mapping can keep `query_tags`. -- **Rationale:** Tagging in this SDK is a cross-cutting concern; `Tag` would be the natural top-level name. Within the statement-execution context, `tags` suffices. - -### 18. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` +### 15. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` - **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `ApiError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `ApiError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. - **Category:** 12 (duplicate concept — overlaps `ApiError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). - **Suggested name:** `StatementError` (or fold into `ApiError` extensions). The errorCode should reuse the canonical apierror codes per #2. - **Rationale:** Multiple error type shapes per SDK is a cognitive tax. -### 19. `StatementStatus.sqlState` field — `src/v1/model.ts:522` +### 16. `StatementStatus.sqlState` field — `src/v1/model.ts:522` - **Why weird:** Field name `sqlState`. The JSDoc says "SQLSTATE error code returned when the statement execution fails." The all-caps acronym SQLSTATE is the SQL-standard 5-character status code (e.g. `42S22`). The TS field uses camelCase `sqlState`. Compare to elsewhere in the SDK where SQL is also lowercased (`sqlExpression`, `sqlText`). This is consistent SDK-wide. - **Category:** 3 (acronym casing — `SQL` becoming `sql` is debatable; SDK has settled on lowercase, so this matches). - **Suggested name:** Keep `sqlState`. Flagged for completeness. - **Rationale:** TS convention varies on multi-letter acronyms; google-ts-style says lowercase initial; SDK follows the convention. -### 20. `ServiceError.errorCode` field — `src/v1/model.ts:474` -- **Why weird:** Field name stutters with type name: `ServiceError.errorCode`. "Error" appears at both levels. A reader sees `err.errorCode` and wonders if there's a non-error code too. -- **Category:** 20 (type-suffix tautology), 12 (duplicate concept). -- **Suggested name:** `code` (since the type is already `ServiceError`). -- **Rationale:** Stutter — `error.error*` — is a code smell. - -### 21. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` +### 17. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` - **Why weird:** Same English word, two spellings, in two enums in the same file. `CANCELLED` is British; `CANCELED` is American. The wire chose differently for the two enums; the SDK mirrors the wire. End users have to remember "cancel with one or two Ls". -- **Category:** 13 (spelling/tense inconsistency — see #11), 17 (asymmetric pair). +- **Category:** 13 (spelling/tense inconsistency — see #10), 17 (asymmetric pair). - **Suggested name:** Normalise upstream. If kept, document the spelling difference in `@databricks/sdk-databricks` README. - **Rationale:** The spelling difference is invisible in casual scanning but breaks copy/paste. -### 22. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` +### 18. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` - **Why weird:** `waitTimeout?: string` with JSDoc explaining it must be formatted as `"Ns"` where N is 0 or 5-50. So a *typed string* with a private DSL inside. Users will write `"5s"` and hope, or worse: `5` (number, won't compile). The wire format is a proto Duration, but the TS surface could parse `number` (seconds) or `Duration` (ms) and emit `Ns`. - **Category:** 1 (vague — `string`-typed numeric), 6 (misleading — a "timeout" with arbitrary string content), 14 (proto/Go-style — Duration carry-over). - **Suggested name:** Keep `waitTimeout` but change the type to `number` (seconds) and let the marshaller produce `Ns`. Or `Duration` from `@databricks/sdk-core/wkt`. - **Rationale:** Letting users pass arbitrary strings into a numeric field is a contract violation waiting to happen. -### 23. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` +### 19. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` - **Why weird:** Field is `onWaitTimeout`, type is `TimeoutAction`. The two names don't share the prefix `Wait*` even though they're tightly coupled. A reader sees `onWaitTimeout?: TimeoutAction` and has to chase the docs to learn the enum members are about wait-timeouts. - **Category:** 17 (asymmetric field/type naming), 12 (duplicate concept — `Wait`/`Timeout` overloaded). - **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #5, `OnTimeout`. - **Rationale:** Field/type symmetry is a strong signal. -### 24. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` +### 20. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` - **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. - **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). - **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. - **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. -### 25. `nextChunkInternalLink` field — `src/v1/model.ts:128` -- **Why weird:** The field is documented as: "an absolute `path` to be joined with your `$DATABRICKS_HOST`, and should be treated as an opaque link. This is an alternative to using `next_chunk_index`." The word "Internal" is doing a lot here — it's not internal as in "private to Databricks"; it means "internal-link, as opposed to a presigned cloud link". The naming is opaque without the JSDoc. -- **Category:** 1 (vague — "Internal" is too generic), 5 (cryptic — needs JSDoc to decode). -- **Suggested name:** `nextChunkRelativePath` (matches its semantics: a path relative to the workspace host). Or `nextChunkUrlPath`. -- **Rationale:** Names should not lean on JSDoc to communicate the *kind* of identifier. - -### 26. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +### 21. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` - **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. - **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). - **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). - **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. -### 27. `totalChunkCount`, `totalRowCount`, `totalByteCount` triple — `src/v1/model.ts:453, 457, 462` -- **Why weird:** Three parallel `total*Count` fields. Each ends in `Count` (singular noun) and starts with `total` (qualifier). The triple is consistent but verbose — `totalChunkCount` is 16 characters for an integer count. -- **Category:** 7 (overly verbose), 8 (redundant suffix — `Count` is implied for an integer). -- **Suggested name:** `chunks` / `rows` / `bytes` (drop `total*Count` and let the integer-ness be implicit). Or keep `total*Count` and document that the per-chunk `*Count` fields are partial sums. -- **Rationale:** Verbose triplets across a type can usually be compressed. - -### 28. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` +### 22. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` - **Why weird:** `ResultManifest.chunks` is an array of `ChunkInfo`; `totalChunkCount` is `chunks.length`. The two carry the same information; on the wire there is a sender-receiver invariant, but TS users can compute one from the other. The naming gives no hint of the redundancy. - **Category:** 12 (duplicate concept), 1 (vague — both fields are about the same property). - **Suggested name:** Drop `totalChunkCount`; users compute via `chunks?.length`. - **Rationale:** Two fields that mean the same thing should not both be public. -### 29. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` +### 23. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` - **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. - **Category:** 16 (field-vs-format contradicts domain when format differs). - **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. - **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. -### 30. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` -- **Why weird:** Companion to #29. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. +### 24. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +- **Why weird:** Companion to #23. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. - **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. - **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. -### 31. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` +### 25. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` - **Why weird:** Two `execute*` functions in the same file, one wraps retry/rate-limit policy and one does the actual HTTP. Same as `queryexecution.md` Finding #21. - **Category:** 1, 12, 17. - **Suggested name:** `runWithPolicies` + `sendHttpRequest`. - **Rationale:** Generator-wide. -### 32. `buildHttpRequest` helper — `src/v1/utils.ts:96` +### 26. `buildHttpRequest` helper — `src/v1/utils.ts:96` - **Why weird:** "Build" implies builder pattern; this is a 16-line object literal. Same as `queryexecution.md` Finding #22. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest` or inline. -### 33. Every field on every request type is optional — `src/v1/model.ts` (every interface) +### 27. Every field on every request type is optional — `src/v1/model.ts` (every interface) - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). - **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. -### 34. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` -- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #12) suggests this is the wrong abstraction. +### 28. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` +- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #11) suggests this is the wrong abstraction. - **Category:** 6 (misleading — type is overloaded), 12 (duplicate concept — two operations). - **Suggested name:** Keep `StatementResponse` but document that it's polymorphic. Or split into `StatementSubmissionResponse` + `StatementStateResponse`. - **Rationale:** Shared response types are acceptable but should be flagged for documentation. -### 35. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` -- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). #18 already flags the type for overlap with `ApiError`; this finding flags the `Service` mid-position as a proto/Java-RPC architectural leak. +### 29. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` +- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). #15 already flags the type for overlap with `ApiError`; this finding flags the `Service` mid-position as a proto/Java-RPC architectural leak. - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementError` — domain-named, mirrors the surrounding `Statement*` vocabulary. - **Rationale:** Architectural-layer words ("Service", "Server", "Backend") in user-facing type names are proto/RPC framework carry-overs. Domain-named alternatives compose better with the rest of the package surface. -### 36. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` -- **Why weird:** Same `Service` mid-position architectural leak as #35, applied to the code enum. #2 already flags the enum for duplicating `google.rpc.Code`; this finding flags the `Service` qualifier specifically as a proto-RPC architectural noun. +### 30. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` +- **Why weird:** Same `Service` mid-position architectural leak as #29, applied to the code enum. #2 already flags the enum for duplicating `google.rpc.Code`; this finding flags the `Service` qualifier specifically as a proto-RPC architectural noun. - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementErrorCode` if the enum is retained; ideally fold into canonical `apierror/codes` per #2. -- **Rationale:** Pair with #35 — the `Service` qualifier carries no domain meaning at the use site. +- **Rationale:** Pair with #29 — the `Service` qualifier carries no domain meaning at the use site. -### 37. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` +### 31. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` - **Why weird:** Underscore-joined identifier `StatementStatus_State` directly transcribes the proto nested-message name into TS. The source file even carries an `eslint-disable` for `@typescript-eslint/naming-convention` with the comment "Proto-style nested enum name." That comment confirms it: the name is a verbatim proto leak, not a TS-idiomatic choice. As a top-level export from `index.ts`, every consumer sees the underscore. - **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). - **Suggested name:** `StatementState` (the `Status` parent is itself a thin wrapper; the state is the meaningful enum) or `StatementStatusState` (no underscore) if both halves matter. - **Rationale:** Proto nested-type underscores are an artefact of code generation from `.proto`. TS has no nested-type concept; flattening to a single CamelCase name removes the leak. -### 38. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` +### 32. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` - **Why weird:** Another underscore-joined name with the same `eslint-disable` and an explicit "Proto-style nested message name" comment. The type exists because proto3 represents `map` as a synthetic nested `*Entry` message; gRPC generators surface this as a nested type. In TS the wire shape is just `Record` (see `httpHeaders` on `ExternalLink`). Re-exporting `ExternalLink_HttpHeadersEntry` from `index.ts` exposes proto machinery the JS user never needs. - **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape), 12 (duplicate concept — `httpHeaders` is already typed `Record`). - **Suggested name:** Delete the type. The `httpHeaders` field is already `Record | undefined`; no consumer needs the synthetic map-entry pair. - **Rationale:** Proto `map` synthetic `*Entry` messages should not surface in user-facing TS types. The information is fully captured by `Record`. -### 39. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` +### 33. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` - **Why weird:** Four enums (`Disposition`, `Format`, `TimeoutAction`, `StatementStatus_State`) carry a `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, `STATE_UNSPECIFIED` first variant. These are proto3 enum convention: every enum must have a `_UNSPECIFIED = 0` member because the default scalar value is required to be valid. JS/TS has no such constraint — `undefined` already encodes "not specified". So the enums carry a value that exists *only* to satisfy proto3 codegen requirements. End users have to filter out the unspecified variant manually when narrowing. - **Category:** 14 (proto/protobuf convention leak), 6 (misleading — the variant has no domain meaning), 1 (vague — `UNSPECIFIED` is the literal default state). - **Suggested name:** Drop the `*_UNSPECIFIED` variants. TS uses `Disposition | undefined` for "not set". @@ -286,54 +246,39 @@ to read every one to pick the right tool. See finding #1. ## Low severity -### 40. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +### 34. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` - **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. - **Category:** 17 (acceptable asymmetry). - **Suggested name:** Keep. -### 41. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:109, 111, 116` +### 35. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:109, 111, 116` - **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. - **Category:** 12 (duplicate concept — three types carry the same fields). - **Suggested name:** Extract `ChunkMetrics` shared interface. - **Rationale:** Trio-replicated types are a tell. -### 42. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` +### 36. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` - **Why weird:** `typeText` is "the full SQL type specification" (e.g. `DECIMAL(10,2)`). `typeName` is the base type name (`DECIMAL`). The pair is intentional but the names don't make the relationship obvious — `typeText` and `typeName` sound interchangeable. - **Category:** 17 (asymmetric pair — `Text` vs `Name`), 1 (vague — `Text` of what?). - **Suggested name:** `typeSql` (the wire SQL text) + `typeBase` (the base type) — but the wire is canonical, so keep names. Document the relationship. -### 43. `position` field on `ColumnInfo` — `src/v1/model.ts:139` -- **Why weird:** Top-level field literally `position` with JSDoc "The ordinal position of the column (starting at position 0)." `position` is generic. `ordinalPosition` (matches the JSDoc) or `columnIndex` would be more precise. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `ordinalPosition` or `index`. - -### 44. `expiration` field on `ExternalLink` — `src/v1/model.ts:341` -- **Why weird:** A string field whose JSDoc says "Indicates the date-time that the given external link will expire and becomes invalid". Two issues: the name `expiration` is ambiguous (an expiry timestamp? a TTL?), and the type is `string` (presumably ISO8601 — the JSDoc doesn't say). A reader can't tell from the type or name how to interpret the value. -- **Category:** 1 (vague), 6 (misleading — could be TTL). -- **Suggested name:** `expiresAt` (ISO8601 timestamp) — matches modern JS/TS convention. - -### 45. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +### 37. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` - **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. - **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). - **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 46. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +### 38. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` - **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. - **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). - **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. -### 47. `name`, `value`, `type` triple on `StatementParameter` — `src/v1/model.ts:479-491` -- **Why weird:** Three single-word fields on a single type, all `string | undefined`. The JSDoc explains: name is the marker name; value is the substituted text; type is the SQL type. The names work fine in this context but are maximally generic — `name`, `value`, `type` could mean anything. The `type` field collides with the TS keyword visually (though `type` isn't actually reserved in object-position). -- **Category:** 1 (vague), 10 (reserved-word collision — `type` is contextually meaningful), 15 (generic names). -- **Suggested name:** `parameterName`, `parameterValue`, `sqlType` — but local names are fine inside a clear-context type. Flagged for completeness. - -### 48. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` -- **Why weird:** Generic key-value pair. Same as #42 but for tags. `tagKey` + `tagValue` are common alternatives. +### 39. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` +- **Why weird:** Generic key-value pair. Same as #36 but for tags. `tagKey` + `tagValue` are common alternatives. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** Acceptable in context. -### 49. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 40. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** Generic name. Same as `queryexecution.md` Finding #25. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -381,19 +326,14 @@ The two packages model semantically distinct operations (general SQL Statement Execution vs Lakeview-dashboard query lifecycle) but share enough vocabulary (`Statement`, `Query`, `Cancel`, `Execute`, `Status`) that a user importing both will be confused. The fix is at the naming/package level (see #1) and -the cross-package vocabulary alignment (#12, #21). +the cross-package vocabulary alignment (#11, #17). --- ## Themes 1. **Per-package error-code enum.** `ServiceErrorCode` mimics `google.rpc.Code` inside a single API package, parallel to the canonical `apierror/codes` module. Generator-wide; the fix is to map wire codes through the canonical apierror layer. -2. **Word stutter.** `ServiceError.errorCode`, `ResultData.dataArray`, `*ResultData` vs `*StatementResult`, `executeStatement` / `getStatementResult` / `statement` field. The wire shape doesn't help here; the TS surface could compress. -3. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). -4. **Package-name competition.** `statementexecution` lives alongside `queryexecution`, `commandexecution`, and `queries` — four near-synonymous names for related-but-distinct execution surfaces. -5. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. -6. **Proto/RPC architectural leaks.** `Service` mid-position on `ServiceError` / `ServiceErrorCode` (architectural-layer noun); `StatementStatus_State` and `ExternalLink_HttpHeadersEntry` proto-style underscored nested names; `*_UNSPECIFIED` enum zero values across four enums. Each is a verbatim transcription of proto/gRPC machinery into TS where the equivalent concept (`undefined`, `Record`, flat enums) is already idiomatic. - -## Fixed - -_None._ +2. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). +3. **Package-name competition.** `statementexecution` lives alongside `queryexecution`, `commandexecution`, and `queries` — four near-synonymous names for related-but-distinct execution surfaces. +4. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. +5. **Proto/RPC architectural leaks.** `Service` mid-position on `ServiceError` / `ServiceErrorCode` (architectural-layer noun); `StatementStatus_State` and `ExternalLink_HttpHeadersEntry` proto-style underscored nested names; `*_UNSPECIFIED` enum zero values across four enums. Each is a verbatim transcription of proto/gRPC machinery into TS where the equivalent concept (`undefined`, `Record`, flat enums) is already idiomatic. diff --git a/.agent/naming-audit/storageconfigurations.md b/.agent/naming-audit/storageconfigurations.md index 891ee92b..4515d0be 100644 --- a/.agent/naming-audit/storageconfigurations.md +++ b/.agent/naming-audit/storageconfigurations.md @@ -41,6 +41,7 @@ surviving carriers of the leak. - **Suggested:** `createStorageConfiguration`. - **Rationale:** Methods on `Client` are inherently public; the suffix is meaningless to a TS caller. +- **Status:** Still present after regeneration on 2026-05-26. ### 2. `Client.deleteStorageConfigurationPublic` — `src/v1/client.ts:99` - **Why weird:** Same `Public` suffix on `Client` method as #1. @@ -48,6 +49,7 @@ surviving carriers of the leak. client method. - **Suggested:** `deleteStorageConfiguration`. - **Rationale:** Same as #1. +- **Status:** Still present after regeneration on 2026-05-26. ### 3. `Client.getStorageConfigurationPublic` — `src/v1/client.ts:124` - **Why weird:** Same `Public` suffix on `Client` method as #1. @@ -55,6 +57,7 @@ surviving carriers of the leak. client method. - **Suggested:** `getStorageConfiguration`. - **Rationale:** Same as #1. +- **Status:** Still present after regeneration on 2026-05-26. ### 4. `Client.listStorageConfigurationPublic` — `src/v1/client.ts:149` - **Why weird:** Same `Public` suffix on `Client` method as #1. @@ -63,6 +66,7 @@ surviving carriers of the leak. - **Suggested:** `listStorageConfigurations` (drop `Public`; pluralise while renaming). - **Rationale:** Same as #1. +- **Status:** Still present after regeneration on 2026-05-26. ## Medium severity @@ -75,85 +79,3 @@ _None._ ## Observation _None._ - -## Fixed - -- **`CreateStorageConfigurationPublicRequest` interface** — renamed to - `CreateStorageConfigurationRequest` (`src/v1/model.ts:5`). Fixed in - regeneration on 2026-05-22. -- **`DeleteStorageConfigurationPublicRequest` interface** — renamed to - `DeleteStorageConfigurationRequest` (`src/v1/model.ts:20`). Fixed in - regeneration on 2026-05-22. -- **`GetStorageConfigurationPublicRequest` interface** — renamed to - `GetStorageConfigurationRequest` (`src/v1/model.ts:25`). Fixed in - regeneration on 2026-05-22. -- **`ListStorageConfigurationPublicRequest` interface** — renamed to - `ListStorageConfigurationRequest` (`src/v1/model.ts:30`). Fixed in - regeneration on 2026-05-22. -- **`ListStorageConfigurationPublicResponse` interface** — renamed to - `ListStorageConfigurationResponse` (`src/v1/model.ts:34`). Fixed in - regeneration on 2026-05-22. -- **`marshalCreateStorageConfigurationPublicRequestSchema`** — renamed - to `marshalCreateStorageConfigurationRequestSchema` - (`src/v1/model.ts:90`). Fixed in regeneration on 2026-05-22. -- **`CreateStorageConfigurationPublicRequest` import** — import in - `client.ts` now references `CreateStorageConfigurationRequest` - (`src/v1/client.ts:22`). Fixed in regeneration on 2026-05-22. -- **`DeleteStorageConfigurationPublicRequest` import** — import in - `client.ts` now references `DeleteStorageConfigurationRequest` - (`src/v1/client.ts:23`). Fixed in regeneration on 2026-05-22. -- **`GetStorageConfigurationPublicRequest` import** — import in - `client.ts` now references `GetStorageConfigurationRequest` - (`src/v1/client.ts:24`). Fixed in regeneration on 2026-05-22. -- **`marshalCreateStorageConfigurationPublicRequestSchema` import** — - import in `client.ts` now references - `marshalCreateStorageConfigurationRequestSchema` - (`src/v1/client.ts:30`). Fixed in regeneration on 2026-05-22. - -## File coverage - -| File | Lines | Audited | -| --------------------- | ----- | ------------------------------------------------ | -| `src/v1/model.ts` | 111 | All 7 interfaces + 3 schema constants + every field. | -| `src/v1/client.ts` | 178 | `Client` class, constructor, 4 methods, import list. | -| `src/v1/utils.ts` | 151 | All exported / private functions. No proto-leak hits. | -| `src/v1/transport.ts` | 75 | `newHttpClient` factory + auth wrapper. No proto-leak hits. | -| `src/v1/index.ts` | 16 | All re-exports — names mirror `model.ts` (covered above). | - -Type & symbol checklist: - -- [x] `CreateStorageConfigurationRequest` interface — clean post-regen - (was flagged; now fixed). -- [x] `DeleteStorageConfigurationRequest` interface — clean post-regen - (was flagged; now fixed). -- [x] `GetStorageConfigurationRequest` interface — clean post-regen - (was flagged; now fixed). -- [x] `ListStorageConfigurationRequest` interface — clean post-regen - (was flagged; now fixed). -- [x] `ListStorageConfigurationResponse` interface — clean post-regen - (was flagged; now fixed). -- [x] `RootBucketInfo` interface — clean (domain-appropriate `Info` - suffix; out of scope for proto-architectural-leak audit). -- [x] `StorageConfiguration` interface — clean. -- [x] `unmarshalRootBucketInfoSchema`, `unmarshalStorageConfigurationSchema`, - `marshalRootBucketInfoSchema`, `marshalCreateStorageConfigurationRequestSchema` - — clean (no `Public` infix on any schema). -- [x] `Client` class itself — clean (terminal-position `Client` is the - standard SDK convention). -- [x] `Client.createStorageConfigurationPublic` — flagged (#1). -- [x] `Client.deleteStorageConfigurationPublic` — flagged (#2). -- [x] `Client.getStorageConfigurationPublic` — flagged (#3). -- [x] `Client.listStorageConfigurationPublic` — flagged (#4). -- [x] `client.ts` import list — clean post-regen (no `Public` infix on - any imported name). -- [x] `utils.ts` (`executeCall`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, - `HttpCallOptions`) — no proto-architectural-leak names. (The - `executeCall` / `executeHttpCall` verb overlap and the generic - `body` shadowing are common across packages and out of scope here.) -- [x] `transport.ts` (`newHttpClient`, auth-wrapping class) — no - `Public`/`Internal`/`Proto`/`Service`/`Manager` leak in domain - identifiers. (The auth wrapper class itself is a cross-package - pattern, not flagged here.) -- [x] `index.ts` re-exports — names mirror `model.ts` and are clean - post-regen. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md index 40699549..e1363b2c 100644 --- a/.agent/naming-audit/supervisoragents.md +++ b/.agent/naming-audit/supervisoragents.md @@ -11,13 +11,13 @@ resource types: `SupervisorAgent` (top-level), `Tool` (child of in-context steering). Every list endpoint paginates via `pageSize`/`pageToken`. No state enums exist in this package; the entire surface is data plus references to other Databricks resources. -**Total weird names flagged:** 37 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | -| High | 10 | -| Medium | 15 | +| High | 7 | +| Medium | 10 | | Low | 6 | | Observation | 6 | @@ -53,31 +53,13 @@ surface is data plus references to other Databricks resources. - **Suggested name:** `KnowledgeAssistantToolSpec`, `KnowledgeAssistantRef`, or `ToolKnowledgeAssistant`. Apply the suffix uniformly to all 6 variants (`GenieSpaceRef`, `UcFunctionRef`, etc.). - **Rationale:** Cross-package name collisions are the worst kind of naming bug because the import path lies about the type's identity. A `Ref`/`ToolSpec` suffix on every variant solves this uniformly. -### 6. `Tool.spec` discriminated union name is generic — `src/v1/model.ts:230` -- **Why weird:** `Tool.spec?: { $case: 'genieSpace'; genieSpace: GenieSpace } | ... | undefined`. The discriminator field is called `spec` — a generic CS term that does not convey *what kind* of specification this is. Same anti-pattern flagged in `knowledgeassistants.md` #12 (`KnowledgeSource.spec`). At a call site, `tool.spec.$case` is competing with the redundant `tool.toolType` (see #3) for "which kind of tool is this" semantics. Worse, `spec` is too short to autocomplete cleanly in many IDEs — and it collides with `Tool.toolType` JSDoc that calls the variants "tool types." -- **Category:** 1 (vague/generic), 12 (duplicate of `toolType` discriminant). -- **Suggested name:** `tool` (so `tool.tool.$case` — awkward) or `config` (matches the doc "Specification for the tool type") or `payload` or `kind` (a literal pun on the discriminant role). The cleanest fix is to flatten: drop `toolType` (per #3), rename `spec` → `tool`, and the type reads `agentTool.tool.$case`. -- **Rationale:** A discriminated union should self-describe via its tag, not via a generic wrapper field. `spec` is the kind of name that survives only because nobody on the review can think of anything better. - -### 7. `name` field overloaded — every CRUD request and every entity — `src/v1/model.ts:11,20,35,50,58,66,78,101,109,117,198,224,246,251,260,288` — sixteen sites -- **Why weird:** Every request and entity uses bare `name` for the "full resource name" (`supervisor-agents/{id}` or `.../tools/{id}` or `.../examples/{id}`). Three different resource types share the same field name with three different formats — a consumer chaining operations across `SupervisorAgent`, `Tool`, and `Example` will have three `name`s in scope, all meaning different things. `DeleteToolRequest.name` and `DeleteSupervisorAgentRequest.name` have the same field name with disjoint URL contracts. Same problem documented in `knowledgeassistants.md` #7. Plus the variant sub-entity types (`App`, `UcConnection`, `UcFunction`, `Volume`) each have a `name` field meaning "the wire identifier of the wrapped Databricks resource" — *not* a supervisor-agent resource name. So `tool.spec.app.name`, `tool.name`, and `parent` (a resource path) are three different `name`-semantics in the same call site. -- **Category:** 1 (vague/generic), 15 (generic field name losing meaning), 19 (underspecified id). -- **Suggested name:** Type-qualify resource names: `supervisorAgentName` on `SupervisorAgent` and the supervisor-agent CRUD requests; `toolName` on `Tool` and tool requests; `exampleName` on `Example` and example requests. On the sub-resource types (`App`, `UcConnection`, etc.), rename `name` → `fullName` (Unity Catalog convention) or `qualifiedName`. Alternatively follow AIP-122 (https://google.aip.dev/122) and keep `name` only on the type the request operates on; rename to `parent` when it identifies a parent (the package already does this for create/list — see #8). -- **Rationale:** This is the highest-frequency naming bug in the package — sixteen sites use the same field name for at least four different semantic roles. - -### 8. `parent` and `name` describe the same wire concept inconsistently — `src/v1/model.ts:20,35,133,183` vs `src/v1/model.ts:50,58,66,101,109,117,260` -- **Why weird:** `CreateExampleRequest.parent`, `CreateToolRequest.parent`, `DeleteExampleRequest.name`, `DeleteSupervisorAgentRequest.name`, `DeleteToolRequest.name`, `GetExampleRequest.name`, `GetSupervisorAgentRequest.name`, `GetToolRequest.name`, `ListExamplesRequest.parent`, `ListToolsRequest.parent`, `UpdateExampleRequest.name` all reference resource paths under `/supervisor-agents/{id}`. The Create + List requests correctly use `parent` per AIP-132 (https://google.aip.dev/132). The Delete + Get + Update requests use `name`. So far consistent with AIP. But: `CreateExampleRequest.parent` is the *supervisor-agent* path, while `CreateExampleRequest.example.name` is the *new example* path. Reading the type, both fields are `string` and the JSDoc explains which is which — but the field names are not self-documenting. Compare with the audit on `knowledgeassistants.md` #8 (same pattern, same finding). -- **Category:** 17 (parent vs name inconsistency for related wire concepts). -- **Suggested name:** Keep AIP-132 (`parent` on create/list, `name` on get/delete/update). Rename `parent` more specifically: `supervisorAgentName` on tool/example requests. The bigger fix is to use typed name strings (template-literal types) so `parent: ${SupervisorAgentName}` is checked at compile time. -- **Rationale:** Same as `knowledgeassistants` — AIP-132 is the right convention, but the bare names lose type discipline. - -### 9. `SupervisorAgent.id` is deprecated but still in the public TS surface — `src/v1/model.ts:205-206` +### 6. `SupervisorAgent.id` is deprecated but still in the public TS surface — `src/v1/model.ts:205-206` - **Why weird:** `id?: string` carries the JSDoc "Deprecated: Use supervisor_agent_id instead." (mind the wire-format leaking into the doc — `supervisor_agent_id` is the snake_case version, but the actual TS field is `supervisorAgentId`). The field is *not* marked `@deprecated` for the IDE, so consumers using IntelliSense will not see the strikethrough. The same issue applies to `Tool.id` (model.ts:225-226, same wording "Deprecated: Use tool_id instead."), `GenieSpace.id` (model.ts:88-92, "Deprecated: use space_id instead."), and `KnowledgeAssistant.servingEndpointName` (model.ts:121-122, "Deprecated: use knowledge_assistant_id instead."). - **Category:** 6 (misleading — deprecation is documented but not annotated), 8 (redundant suffix: keeping deprecated `id` *and* `supervisorAgentId` causes name clutter), 14 (the doc references the snake_case wire name rather than the TS name). - **Suggested name:** Add `@deprecated` JSDoc tag so IDEs render it; doc should reference `supervisorAgentId` (the TS name) not `supervisor_agent_id` (the wire name); long-term plan for removal. Same fix on `Tool.id`, `GenieSpace.id`, and `KnowledgeAssistant.servingEndpointName`. - **Rationale:** Public-API deprecation has a standard JSDoc tag (https://jsdoc.app/tags-deprecated.html) that triggers IDE warnings. Free-text comment does not. -### 10. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:121-122` +### 7. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:121-122` - **Why weird:** The `KnowledgeAssistant` variant type (one of 6 tool kinds) has two fields: - `servingEndpointName?: string` — doc "Deprecated: use knowledge_assistant_id instead." - `knowledgeAssistantId?: string` — doc "The ID of the knowledge assistant." @@ -88,88 +70,58 @@ surface is data plus references to other Databricks resources. ## Medium severity -### 11. `SupervisorAgent.endpointName` is the agent's serving endpoint, not user-supplied — `src/v1/model.ts:213-214` -- **Why weird:** Doc reads "The name of the supervisor agent's serving endpoint." This is a server-populated read-only field (the supervisor-agents backend creates a model-serving endpoint behind the scenes). The name `endpointName` does not tell the reader which kind of endpoint (model serving? vector search? SQL warehouse?). Same problem flagged in `knowledgeassistants.md` #21 and `customllms.md` #7. -- **Category:** 1 (vague), 19 (underspecified id). -- **Suggested name:** `servingEndpointName` (matches Databricks model-serving terminology) or `agentServingEndpointName`. The variant type `KnowledgeAssistant` in this same file already uses `servingEndpointName` (model.ts:122) — so renaming here would *align* the two fields. -- **Rationale:** Cross-package and within-package alignment; `servingEndpointName` is the canonical term. - -### 12. `SupervisorAgent.experimentId` — what kind of experiment? — `src/v1/model.ts:215-216` -- **Why weird:** Doc reads "The MLflow experiment ID." A bare `experimentId` is fine *if* the consumer knows the SDK only integrates with MLflow. But the consumer reading `SupervisorAgent.experimentId` could reasonably guess this is an A/B-test experiment, a feature-flag experiment, or a generic experiment. Same problem flagged in `knowledgeassistants.md` #22 — and there the audit suggested `mlflowExperimentId`. -- **Category:** 1 (vague), 19 (underspecified id), 17 (inconsistency with sibling SDK). -- **Suggested name:** `mlflowExperimentId`. -- **Rationale:** Cross-package consistency. The doc clarifies but the name does not. - -### 13. `SupervisorAgent.creator: string` — what is a creator? — `src/v1/model.ts:209-210` -- **Why weird:** Doc reads "The creator of the Supervisor Agent." Could be a username, email, UUID, Databricks principal id, or service-principal client id. The type is `string`. Same field, same problem flagged in `knowledgeassistants.md` #24 and `customllms.md` #10. -- **Category:** 1 (vague), 19 (underspecified id), 17 (SDK-wide inconsistency). -- **Suggested name:** `createdBy` (AIP-148 standard, https://google.aip.dev/148, also matches `unitycatalog`). -- **Rationale:** Match the most-used convention. Same recommendation as in three sibling audits. - -### 14. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:211-212` +### 8. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:211-212` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `createTime` follows AIP-142 (https://google.aip.dev/142). Compare with `customllms.CustomLlm.creationTime: Temporal.Instant` (audited as inconsistent) — the supervisor-agents package uses the AIP form, the customllms package does not. This is positive consistency on supervisor-agents and negative on customllms. Flagging here because the audit covers SDK-wide consistency. - **Category:** Observation / 17 (cross-package inconsistency). - **Suggested name:** Keep `createTime`; flag `customllms` to align. - **Rationale:** Note positive precedent; pair with the audit on `customllms` to align it. -### 15. `SupervisorAgent.displayName` doc claims uniqueness — `src/v1/model.ts:199-200` -- **Why weird:** Doc reads "The display name of the Supervisor Agent, unique at workspace level." Display names being unique at workspace level is a *semantic* claim — it might be enforced by the backend (with a 409 response on collision) or it might just be a soft convention. The type signature (`string`) gives no hint. AIP-122 reserves `displayName` for human-readable names that are explicitly *not* unique (https://google.aip.dev/122); a unique name is usually `name` or `id`. So this field is doing double duty: it is human-readable *and* uniquely identifying. Either rename or split. -- **Category:** 6 (misleading — `displayName` implies non-unique). -- **Suggested name:** If the uniqueness is enforced: rename to `key` or `humanReadableId` to communicate the uniqueness contract. If it is convention only: keep the name but soften the JSDoc. -- **Rationale:** A field whose contract contradicts its conventional meaning is a footgun. - -### 16. `SupervisorAgent.description` "user-facing" annotation — `src/v1/model.ts:201-202` +### 9. `SupervisorAgent.description` "user-facing" annotation — `src/v1/model.ts:201-202` - **Why weird:** Doc reads "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Same observation flagged in `knowledgeassistants.md` #42. The same parenthetical appears on `Tool.description` (model.ts:238-239). - **Category:** Observation / 17 (inconsistent JSDoc style across SDK). - **Suggested name:** Drop "(user-facing)" from the two sites; flag for cross-package style review. - **Rationale:** Minor; cosmetic but worth aligning. -### 17. `SupervisorAgent.instructions` vs `Example.guidelines` — same overlap as flagged in `customllms.md` and `knowledgeassistants.md` — `src/v1/model.ts:203-204,82` -- **Why weird:** `SupervisorAgent.instructions: string` (single, global) and `Example.guidelines: string[]` (array, per-example) follow the exact same naming doublet as `customllms.CustomLlm.instructions`/`guidelines` and `knowledgeassistants.KnowledgeAssistant.instructions`/`Example.guidelines`. Three packages, three near-identical confusing field-name pairs. The naming pattern is now SDK-wide. -- **Category:** 6 (misleading), 12 (duplicate concept across SDK), 15 (generic field name). -- **Suggested name:** Rename `SupervisorAgent.instructions` → `systemPrompt` or `globalInstructions`; rename `Example.guidelines` → `answerGuidelines` or `responseRules`. Apply uniformly across all three packages. -- **Rationale:** Three packages flagged independently for the same pattern. SDK-wide cleanup opportunity. - -### 18. `Tool.description` "user-facing" repeated annotation — `src/v1/model.ts:238-239` -- **Why weird:** Same as #16; the `Tool.description` has the same "(user-facing)" parenthetical. The doc reads "Description of what this tool does (user-facing)." If the audit prompt cares about consistency, both descriptions should match. +### 10. `Tool.description` "user-facing" repeated annotation — `src/v1/model.ts:238-239` +- **Why weird:** Same as #9; the `Tool.description` has the same "(user-facing)" parenthetical. The doc reads "Description of what this tool does (user-facing)." If the audit prompt cares about consistency, both descriptions should match. - **Category:** Observation / 17. -- **Suggested name:** Same as #16. +- **Suggested name:** Same as #9. -### 19. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:240-241` +### 11. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:240-241` - **Why weird:** Doc reads "User specified id of the Tool." Comparing with `CreateToolRequest.toolId` (model.ts:37-41, "The ID to use for the tool, which will become the final component of the tool's resource name."), the two `toolId` fields are *the same wire concept* — but on `Tool` it is the persisted id, while on `CreateToolRequest` it is the request-time supplied id. The same field name is doing two semantic jobs depending on context. Plus, comparing with `Example.exampleId` (model.ts:83-84, "The universally unique identifier (UUID) of the example."), the format claim differs: `Tool.toolId` is *user-specified*, `Example.exampleId` is a *UUID*. The two id formats are not aligned across sibling types in the same package. - **Category:** 17 (inconsistency across sibling types), 6 (misleading — different format claims). - **Suggested name:** Keep `toolId` and `exampleId` but expand the JSDoc on each to disambiguate the id-format contract. Or rename `Tool.toolId` → `toolKey` to mirror that it is a user-supplied identifier (as opposed to a server-generated UUID). - **Rationale:** A naming audit must flag fields whose format contract is silent in the type signature. -### 20. `SupervisorAgent.supervisorAgentId` vs `SupervisorAgent.id` (deprecated) — both UUIDs — `src/v1/model.ts:205-208` -- **Why weird:** Two id fields on `SupervisorAgent`: the deprecated `id` and the canonical `supervisorAgentId`. Both are `string`, both UUIDs per the doc on line 207 ("The universally unique identifier (UUID) of the Supervisor Agent."). The deprecation is in JSDoc only (no `@deprecated` tag — see #9). Same situation on `Tool.id` vs `Tool.toolId` (model.ts:225-226, 240-241). Carrying the deprecated alias on the type forces consumers to handle both; the SDK should pick one. +### 12. `SupervisorAgent.supervisorAgentId` vs `SupervisorAgent.id` (deprecated) — both UUIDs — `src/v1/model.ts:205-208` +- **Why weird:** Two id fields on `SupervisorAgent`: the deprecated `id` and the canonical `supervisorAgentId`. Both are `string`, both UUIDs per the doc on line 207 ("The universally unique identifier (UUID) of the Supervisor Agent."). The deprecation is in JSDoc only (no `@deprecated` tag — see #6). Same situation on `Tool.id` vs `Tool.toolId` (model.ts:225-226, 240-241). Carrying the deprecated alias on the type forces consumers to handle both; the SDK should pick one. - **Category:** 8 (redundant alias suffix), 12 (duplicate concept within the same type). - **Suggested name:** Mark `id` `@deprecated`; document that `supervisorAgentId` is canonical. Future major version removes `id` entirely. - **Rationale:** Carrying a deprecated alias on a TS type is a tax on every reader. Mark it loudly. -### 21. `SupervisorAgent.supervisorAgentId` type-suffix tautology — `src/v1/model.ts:207-208` +### 13. `SupervisorAgent.supervisorAgentId` type-suffix tautology — `src/v1/model.ts:207-208` - **Why weird:** `SupervisorAgent.supervisorAgentId` repeats `SupervisorAgent` in the type name and field. The pattern is correct AIP-style (every entity has `*Id` matching its type) but extremely verbose. Once `SupervisorAgent` is renamed to `RouterAgent` (per #1), the field becomes `routerAgentId` — slightly shorter, still type-tautological. - **Category:** 20 (type-suffix tautology). - **Suggested name:** Keep current (tradeoff with cross-type disambiguation), but document the convention in `typescript.mdc`. - **Rationale:** This is a convention question, not a bug. The verbose form *does* disambiguate from `Tool.toolId` and `Example.exampleId` when passed to a generic function. Flagged for awareness. -### 22. `Example.exampleId` type-suffix tautology — `src/v1/model.ts:83-84` -- **Why weird:** Same shape as #21, but the field is `exampleId` and the type is `Example`. The redundancy is identical. Note: every sibling SDK package follows the same convention (`knowledgeassistants.Example.exampleId` is the same pattern). +### 14. `Example.exampleId` type-suffix tautology — `src/v1/model.ts:83-84` +- **Why weird:** Same shape as #13, but the field is `exampleId` and the type is `Example`. The redundancy is identical. Note: every sibling SDK package follows the same convention (`knowledgeassistants.Example.exampleId` is the same pattern). - **Category:** 20 (type-suffix tautology). - **Suggested name:** Keep current; document the convention. -### 23. `Tool.toolId` type-suffix tautology — `src/v1/model.ts:240-241` -- **Why weird:** Same pattern as #21, #22. +### 15. `Tool.toolId` type-suffix tautology — `src/v1/model.ts:240-241` +- **Why weird:** Same pattern as #13, #14. - **Category:** 20. - **Suggested name:** Keep current; document the convention. -### 24. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:37-41` +### 16. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:37-41` - **Why weird:** The create request takes both `tool: Tool` (the body) *and* `toolId: string` (the URL/query param). The wire form is `POST /supervisor-agents/{id}/tools?tool_id={user-supplied}`. So `req.toolId` flows into the query string and `req.tool.toolId` is *not used* on creation — but TypeScript does not enforce this. A consumer who writes `{tool: {toolId: 'foo'}}` and leaves `req.toolId` undefined gets unexpected behavior. The two-fields-for-one-concept pattern is also documented in `customllms.md` #20. - **Category:** 12 (duplicate concept on the same request), 6 (misleading — `tool.toolId` looks usable on creation but isn't), 17. - **Suggested name:** Either remove `tool.toolId` from the body shape (TypeScript can enforce this via a discriminated `Omit` type for create), or document the precedence rule on the JSDoc. - **Rationale:** Generated request types with duplicate fields are a well-known footgun. -### 25. `Client` class name — bare, no scoping — `src/v1/client.ts:61` +### 17. `Client` class name — bare, no scoping — `src/v1/client.ts:61` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-supervisoragents/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as SAClient} from '@databricks/sdk-supervisoragents/v1'`. Same SDK-wide issue flagged in `knowledgeassistants.md` #30. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `SupervisorAgentsClient` (matches the Go SDK's `WorkspaceClient.SupervisorAgents` and AWS SDK's `S3Client`, `IAMClient` pattern). @@ -177,37 +129,37 @@ surface is data plus references to other Databricks resources. ## Low severity -### 26. `Volume`/`UcFunction`/`UcConnection` — `Uc` prefix on some, bare on others — `src/v1/model.ts:245,249,286` +### 18. `Volume`/`UcFunction`/`UcConnection` — `Uc` prefix on some, bare on others — `src/v1/model.ts:245,249,286` - **Why weird:** Of the variant types, three are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`. The `Uc` prefix is applied to two but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). - **Category:** 3 (acronym casing — `Uc` vs `UC`), 17 (inconsistent prefix application — `Volume` should be `UcVolume`). - **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection` (with the acronym-casing question decided once SDK-wide). - **Rationale:** Consistency wins; the audit prompt rule 3 (acronym casing) and rule 17 (consistent action verbs / family naming) both flag this. -### 27. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` +### 19. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21 and `knowledgeassistants.md` #34. Each generated package carries the same pair. - **Category:** 1 (vague), 17 (inconsistency). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than one infix. -### 28. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` - **Why weird:** Same as `customllms.md` #23 and `knowledgeassistants.md` #35: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in scope simultaneously. Three things named `Options`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams`. - **Rationale:** Distinguish internal context bags from user-facing options. -### 29. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 21. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Same as `customllms.md` #28 and `knowledgeassistants.md` #36: exported but not used by `client.ts`. Generator-mechanical surface area. - **Category:** Observation / (unused export). - **Suggested name:** Either remove the export or document why it ships per-package. - **Rationale:** Generated artifact; flag for cross-package cleanup. -### 30. `readAll` helper generic name — `src/v1/utils.ts:40` +### 22. `readAll` helper generic name — `src/v1/utils.ts:40` - **Why weird:** Same as `customllms.md` #29 and `knowledgeassistants.md` #37: helper reads an entire response body stream; name is generic. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 31. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` +### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` - **Why weird:** Same as `customllms.md` #24 and `knowledgeassistants.md` #38: `Segment` is a generic CS term. - **Category:** 1 (vague). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -215,55 +167,31 @@ surface is data plus references to other Databricks resources. ## Observations -### 32. `resp` local variable in every method — `src/v1/client.ts:93,122,154,242,267,289,323,374,428,477,521,562` +### 24. `resp` local variable in every method — `src/v1/client.ts:98,130,165,265,293,318,355,409,466,518,565,609` - **Why weird:** Same as `customllms.md` #33 and `knowledgeassistants.md` #39: `resp` is the response. Twelve methods repeat the same pattern. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. - **Rationale:** Refactor opportunity surfaced by audit. -### 33. `pageReq` local in iterator methods — `src/v1/client.ts:346,400,451` +### 25. `pageReq` local in iterator methods — `src/v1/client.ts:381,438,492` - **Why weird:** Same as `knowledgeassistants.md` #40: three async generator methods declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. - **Category:** 5 (abbreviation). - **Suggested name:** `pageRequest` or `nextPageReq`. -### 34. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:656-674` +### 26. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:656-674` - **Why weird:** The field-mask carries top-level entries for each variant of the `spec` union — `app`, `genieSpace`, `knowledgeAssistant`, `ucConnection`, `ucFunction`, `volume`. The field-mask flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. - **Category:** 17 (inconsistency between TS shape and field-mask). - **Suggested name:** No rename; document on the JSDoc. -### 35. `Tool.toolType` doc lists 14 kinds but `Tool.spec` union covers only 6 — `src/v1/model.ts:227,230-237` +### 27. `Tool.toolType` doc lists 14 kinds but `Tool.spec` union covers only 6 — `src/v1/model.ts:227,230-237` - **Why weird:** The JSDoc on `Tool.toolType` enumerates 14 wire values (`"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "dashboard", "serving_endpoint", "table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`), but the `Tool.spec` discriminated union only encodes 6 of them (`genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `ucConnection`). The other 8 wire kinds — dashboard, serving_endpoint, table, vector_search_index, catalog, schema, supervisor_agent, web_search — can be set via `toolType` but have no corresponding `spec` variant. A consumer who writes `{toolType: 'dashboard'}` gets no type-system support for the dashboard payload because the variant doesn't exist. Either the backend has dropped those kinds (and the doc should be updated) or the TS surface is missing variants. - **Category:** 16 (field contradicts type domain), 17 (doc vs type-shape mismatch), 6 (misleading). - **Suggested name:** Reconcile the two declarations: either add the missing variants to `Tool.spec` or shrink the `toolType` enumeration to the supported subset. -### 36. Action verbs in `Client` are consistent — `src/v1/client.ts` +### 28. Action verbs in `Client` are consistent — `src/v1/client.ts` - **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. - **Category:** 17 (reversed — consistency note). -### 37. Method-name verb conventions match resource targets — `src/v1/client.ts:87,113,142,180,199,218,237,262,287,309,360,414,465,506,550` +### 29. Method-name verb conventions match resource targets — `src/v1/client.ts:92,121,153,194,216,238,260,288,316,341,395,452,506,550,597` - **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. - **Category:** 17 (positive observation). - -## Fixed - -- #6 `SupervisorAgentTool` (originally cited at `src/v1/model.ts:246`): Fixed in regeneration on 2026-05-20 — the recursion-case tool variant was removed from the `Tool.spec` discriminated union; no other variants use a `*Tool` suffix anymore. -- #12 `SupervisorAgentTool.supervisorAgentId` "tile ID" doc bug (originally cited at `src/v1/model.ts:247-248`): Fixed in regeneration on 2026-05-20 — `SupervisorAgentTool` was removed from the package, taking the misleading doc with it. -- #13 `Catalog` / `Schema` cross-package collision (originally cited at `src/v1/model.ts:19,210`): Fixed in regeneration on 2026-05-20 — both `Catalog` and `Schema` types are no longer in the package; the `Tool.spec` union no longer carries those variants. -- #30 `LakeviewDashboard` product-name leakage (originally cited at `src/v1/model.ts:135`): Fixed in regeneration on 2026-05-20 — the `LakeviewDashboard` type was removed from the package. -- #31 `Catalog`/`Schema`/`UcTable` `name`-field cardinality drift (originally cited at `src/v1/model.ts:21,212,321`): Fixed in regeneration on 2026-05-20 — all three types are gone, so the differing 1-/2-/3-part `name` semantics are no longer in this package. -- #32 `VectorSearchIndex.columns` semantic ambiguity (originally cited at `src/v1/model.ts:357-361`): Fixed in regeneration on 2026-05-20 — the `VectorSearchIndex` type was removed from the package. -- #41 14 tool kinds = positive observation (originally cited at `src/v1/model.ts:262-297`): Fixed in regeneration on 2026-05-20 — the count is no longer accurate (the union now has 6 variants while the doc still lists 14), so the positive observation no longer holds. Superseded by new finding #35 (doc vs union-shape mismatch). - -## Domain glossary -- `supervisor agent` — the LLM router resource that orchestrates calls to tools (sub-agents). The package name and primary resource. Per the audit's prompt: `Supervisor + Agent` together describe "a top-level routing agent that delegates user requests to specialized child tools." Each agent has a serving endpoint and an MLflow experiment. -- `tool` — a typed reference to another Databricks resource (or a built-in capability like web search) that the supervisor agent can invoke. 6 kinds via `Tool.spec` discriminated union; the `toolType` doc enumerates more kinds that lack corresponding spec variants. -- `example` — a question + guidelines pair that steers the agent's response on similar questions. Sub-resource of a supervisor agent. -- `uc` — Unity Catalog. Used as a prefix for variant types (`UcFunction`, `UcConnection`). -- `genie` — Databricks Genie, the AI-driven analytics product. `GenieSpace` is the container resource. -- `mcp` — Model Context Protocol (referenced in `App` doc "Supported app: custom mcp, custom agent."). MCP servers can be deployed as Databricks Apps. - -## File coverage -- `src/v1/model.ts` (691 lines): read fully. -- `src/v1/client.ts` (587 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (36 lines): read fully. diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index e97f954a..8c4c52e0 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -3,13 +3,13 @@ **Path:** `packages/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 13 +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 5 | +| High | 3 | +| Medium | 3 | | Low | 2 | | Observation | 2 | @@ -33,53 +33,35 @@ - **Suggested name:** Introduce `SystemSchemaState` enum with members `Available | EnableInitialized | EnableCompleted | DisableInitialized | Unavailable | Managed` and type the field `state: SystemSchemaState`. - **Rationale:** Almost certainly a generator/upstream-API miss; the wire surface is enum-shaped and should round-trip through a TS enum. Worth raising upstream. -### 4. `schema` field on every request/response — `src/v1/model.ts:7,17,55` -- **Why weird:** Field is bare `schema: string` on `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, and `SystemSchemaInfo`. Doc on the first two says "Full name of the system schema" while the doc on `SystemSchemaInfo` (model.ts:54) says "Name of the system schema". So the same field name carries two different semantics (full-qualified vs short name) across two types that ship in the same module. Also collides with the type name (`SystemSchema`) and the package name (`systemschemas`), making greps unhelpful. -- **Category:** 1 (vague — what kind of "schema"?), 6 (misleading — same field name, different meaning), 19 (underspecified id). -- **Suggested name:** Pick one of `schemaName` / `systemSchemaName` / `name` and apply it consistently. If the wire is `schema` (string), keep the wire and rename the TS surface; the marshaller already handles the gap for other fields. -- **Rationale:** The URL template `.../systemschemas/${req.schema ?? ''}` (client.ts:75) confirms `schema` is in fact an identifier slug. Calling it `schemaName` or `name` makes intent obvious; bare `schema` collides with everything. - ## Medium severity -### 5. `DisableSystemSchemaRequest.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` +### 4. `DisableSystemSchemaRequest.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` - **Why weird:** Marked optional, but `client.ts:75` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchemaRequest.metastoreId`, `DisableSystemSchemaRequest.schema`, `EnableSystemSchemaRequest.schema`, `ListSystemSchemasRequest.metastoreId`. - **Category:** 6 (misleading optionality), 16 (field type contradicts domain — these are mandatory path params). - **Suggested name:** Keep names; change type to non-optional. (Out of scope for a *naming* audit, but the optionality leaks into how the names should be interpreted.) - **Rationale:** Path-required fields must be required. Treating them as optional weakens the contract; the name `metastoreId` reads as "the metastore id" but the type says "you can omit this". -### 6. `SystemSchemaInfo.schema: string` (required) vs `EnableSystemSchemaRequest.schema: string | undefined` (optional) — `src/v1/model.ts:55,17` -- **Why weird:** Same field name, opposite optionality, same module. The reader has to keep two mental versions of `schema` in their head. -- **Category:** 17 (inconsistency in field shape between sibling types). -- **Suggested name:** Same as #4 — rename one or both and unify optionality where possible. -- **Rationale:** Symmetry across request/response pairs improves readability; identical names with diverging contracts do not. - -### 7. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` +### 5. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate intent. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Minor; flagged for cross-SDK consistency since the same constant appears in every generated client. -### 8. `Client` — `src/v1/client.ts:42` +### 6. `Client` — `src/v1/client.ts:42` - **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `SystemSchemasClient`. - **Rationale:** Forces consumers to alias on import (`import {Client as SystemSchemasClient}`) if they ever combine clients. Every generated package has this issue; flagged for consistency. -### 9. `ListSystemSchemasRequest.maxResults` doc semantics — `src/v1/model.ts:31-37` -- **Why weird:** Field is named `maxResults` but the doc describes three semantically distinct modes (0 = server default, >0 = bounded, <0 = error) and one quirky default (not set = "all", "not recommended"). The name "maxResults" implies an upper bound, not a tri-state control. Same pattern in every other List request, but here the doc highlights how overloaded the name is. -- **Category:** 6 (misleading — name suggests a single integer cap), 1 (vague). -- **Suggested name:** `pageSize` (matching most modern paginated APIs) and let the value 0 mean "server default". Drop the negative-error branch entirely. -- **Rationale:** Worth raising upstream; the JS SDK's name should describe what consumers do, not the wire's quirks. - ## Low severity -### 10. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:185` +### 7. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:185` - **Why weird:** `listSystemSchemasIter` (client.ts:185) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). - **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. - **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. -### 11. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 8. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ by a single `Http` infix, handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -87,10 +69,10 @@ ## Observations -### 12. Action-verb consistency in `Client` +### 9. Action-verb consistency in `Client` Methods are `disable`, `enable`, `list` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. -### 13. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod +### 10. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), the package name (`systemschemas`), and a library term (zod's `Schema`). Multiple overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. - **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). @@ -107,6 +89,3 @@ The word "schema" appears in this single package as a wire field, a domain noun - `src/v1/client.ts` (191 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (16 lines): read fully. - -## Fixed -- #2 `DisableSystemSchema` / `EnableSystemSchema` / `ListSystemSchemas` (originally cited at `src/v1/model.ts:5,15,27`): Fixed in regeneration on 2026-05-20 — verb-phrase request DTOs renamed to `DisableSystemSchemaRequest`, `EnableSystemSchemaRequest`, `ListSystemSchemasRequest`. diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index 1b5c5eb0..d3f1fd0b 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -112,11 +112,11 @@ 34. `TableExistsRequest` (model.ts:699) — 1 field. 35. `TableExistsRequest_Response` (model.ts:705) — 1 field (`tableExists`). 36. `TableInfo` (model.ts:710) — 36 fields (duplicates `CreateTableRequest` / - `UpdateTableRequest` field-by-field). + `UpdateTableRequest` field-by-field). 37. `TableInfo_PropertiesEntry` (model.ts:782) — 2 fields. 38. `TableSummary` (model.ts:787) — 3 fields. 39. `UpdateTableRequest` (model.ts:795) — 37 fields (`fullNameArg` + the same - set as `CreateTableRequest`). + set as `CreateTableRequest`). 40. `UpdateTableRequest_PropertiesEntry` (model.ts:869) — 2 fields. 41. `UpdateTableRequest_Response` (model.ts:875) — empty body. @@ -152,11 +152,11 @@ | Severity | Count | | --------------------- | ----- | -| High | 18 | -| Medium | 21 | -| Low / SDK-wide note | 10 | +| High | 13 | +| Medium | 11 | +| Low / SDK-wide note | 7 | | Pass / acceptable | 9 | -| **Total findings** | **58** | +| **Total findings** | **40** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -243,32 +243,7 @@ etc.) but is worth flagging for anyone reviewing this file fresh. --- -### 4. `SseEncryptionDetails.awsKmsKeyArn` is the only field that names the cloud — category 3 (Acronym casing inconsistencies) and category 16 (Field contradicting type domain) - -**Symbol:** `SseEncryptionDetails.awsKmsKeyArn` (model.ts:669). - -**Issue:** `AWS`, `KMS`, and `ARN` are three back-to-back acronyms. The -field is `awsKmsKeyArn`. The JSDoc explains it's "The ARN of the SSE-KMS -key used with the S3 location, when algorithm = 'SSE-KMS'". Under the -Google rule, `AwsKmsKeyArn` would become `awsKmsKeyArn` in camelCase form — -which the code already uses. So far OK. - -But this is the *only* AWS-specific field in `tables`. `accessPoint` -(model.ts:346) is also AWS S3-specific (JSDoc: "The AWS access point to -use when accesing s3 for this external location") — but the field name -does not say `awsAccessPoint`. The two AWS-specific fields in `TableInfo` -use different naming conventions for their AWS-ness. - -**Suggested:** either rename `accessPoint` → `awsAccessPoint`, or drop the -`aws` prefix on `awsKmsKeyArn` if it's understood to be AWS-only (the -enclosing `SseEncryptionAlgorithm` already says `AWS_SSE_KMS`). - -(One JSDoc typo: "accesing" — single `s`, model.ts:345 — likely also in -the upstream `.proto`.) - ---- - -### 5. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) +### 4. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) **Symbol:** `SecurableType` (model.ts:162). @@ -289,7 +264,7 @@ who already has a `TableInfo` knows it's a `TABLE`. --- -### 6. `ColumnTypeName.TABLE_TYPE` collides with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 5. `ColumnTypeName.TABLE_TYPE` collides with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) **Symbol:** `ColumnTypeName.TABLE_TYPE` (model.ts:29). @@ -314,7 +289,7 @@ holds a table"), the other is about UC table classifications. --- -### 7. `ColumnTypeName.TIMESTAMP_NTZ` cryptic abbreviation — category 5 (Cryptic abbreviations) +### 6. `ColumnTypeName.TIMESTAMP_NTZ` cryptic abbreviation — category 5 (Cryptic abbreviations) **Symbol:** `ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25). @@ -327,7 +302,7 @@ zone"`. --- -### 8. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) +### 7. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) **Symbols:** `DataSourceFormat` values (model.ts:33–75). @@ -356,7 +331,7 @@ if (format === 'MYSQL_FORMAT' || format === 'POSTGRESQL_FORMAT') {} // suffix --- -### 9. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) +### 8. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) **Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:43), `DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:70). @@ -375,7 +350,7 @@ consistent. **Not a per-package fix.** --- -### 10. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) +### 9. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) **Symbol:** `SecurableKind.TABLE_DELTASHARING_OPEN_DIR_BASED` (model.ts:93). @@ -392,7 +367,7 @@ constraint), **flag for documentation cleanup.** --- -### 11. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) +### 10. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) **Symbols:** - `SecurableKind.TABLE_FEATURE_STORE` (model.ts:95) and @@ -414,40 +389,7 @@ JSDoc tags (only inline comments). Consumers code-completing on --- -### 12. `fullNameArg` field name across multiple request types — category 14 (Go/Java-style names) and category 5 (Cryptic abbreviations) - -**Symbols:** `fullNameArg` on `DeleteTableRequest` (model.ts:387), -`DeleteTableConstraintRequest` (model.ts:372), `GetTableRequest` -(model.ts:468), `TableExistsRequest` (model.ts:701), `UpdateTableRequest` -(model.ts:797), `CreateTableConstraintRequest` (model.ts:283). 6 -occurrences in this file alone; also used in `schemas/v1`, `functions/v1`, -`registeredmodels/v1`. - -**Issue:** The `Arg` suffix on a field name is a Go convention (Go SDK uses -`FullNameArg` to mark a URL-path-argument vs. a query/body field). In TS, -the convention is to use the bare field name (`fullName`) since the -distinction between URL-path / query / body is handled by the client code -and JSDoc. The wire form is `full_name_arg` — the suffix even reaches the -wire, which is unusual. - -The same package also has a `fullName` field on response/struct types -(`CreateTableRequest.fullName` model.ts:325, `TableInfo.fullName` -model.ts:748, `TableSummary.fullName` model.ts:789, `UpdateTableRequest.fullName` -model.ts:835). So the package has both `fullName` (noun) and `fullNameArg` -(with `Arg` suffix) — distinguishing input from output by suffix, which is -a Go-ism. - -**Suggested:** rename `fullNameArg` → `fullName` SDK-wide. The URL-path -argument vs. response field distinction can be inferred from the request -type (e.g. `DeleteTableRequest.fullName` is obviously a path argument -because `DeleteTableRequest` is a delete request). Cross-reference Google -AIP-122 (resource name in REST methods uses `name`, not `nameArg`). - -**Flag for SDK-wide cleanup.** - ---- - -### 13. `CreateTableRequest` and `TableInfo` and `UpdateTableRequest` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) +### 11. `CreateTableRequest` and `TableInfo` and `UpdateTableRequest` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) **Symbols:** `CreateTableRequest` (model.ts:287, 38 fields), `TableInfo` (model.ts:710, 36 fields), `UpdateTableRequest` (model.ts:795, 37 fields). @@ -486,7 +428,7 @@ messages map 1:1). --- -### 14. `CreateTableRequest.fullName` is server-generated — category 6 (Misleading names) +### 12. `CreateTableRequest.fullName` is server-generated — category 6 (Misleading names) **Symbol:** `CreateTableRequest.fullName?: string | undefined` (model.ts:325). JSDoc: "Full name of table, in form of @@ -505,12 +447,12 @@ all server-output but exposed on the input type. Same critique applies to `UpdateTableRequest`. **Suggested:** mark with JSDoc `@readonly` and add a sentence "Output only; -ignored on input." Or restructure types (finding 13). **Coordinate with +ignored on input." Or restructure types (finding 11). **Coordinate with generator.** --- -### 15. `CreateTableRequest.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) +### 13. `CreateTableRequest.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) **Symbol:** `CreateTableRequest.tableConstraints?: TableConstraint[] | undefined` (model.ts:317). JSDoc: "List of table constraints. Note: this field is not @@ -530,7 +472,7 @@ server might or might not honour it depending on the deployment. --- -### 16. `CreateTableRequest.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 14. `CreateTableRequest.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) **Symbol:** `CreateTableRequest.enablePredictiveOptimization?: string | undefined` (model.ts:321). Same field on `TableInfo` (model.ts:744) and @@ -546,7 +488,7 @@ also a `string` with the same domain. **Suggested:** - Type as an enum (e.g. `PredictiveOptimizationFlag = 'ENABLE' | 'DISABLE' - | 'INHERIT'`) and rename to `predictiveOptimization`. + | 'INHERIT'`). - Or document the accepted values in JSDoc. **Coordinate with protocol.** Cross-reference `catalogs/v1` which has the @@ -554,7 +496,7 @@ same field. --- -### 17. `CreateTableRequest.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) +### 15. `CreateTableRequest.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) **Symbol:** `CreateTableRequest.dataAccessConfigurationId?: string | undefined` (model.ts:327). 28 chars. Same field on `TableInfo` (model.ts:750) and @@ -573,26 +515,7 @@ choice. **Pass with note.** --- -### 18. `CreateTableRequest.accessPoint` (S3-specific) leaks AWS into a generic-looking field — category 6 (Misleading names) and category 16 (Field contradicting type domain) - -**Symbol:** `CreateTableRequest.accessPoint?: string | undefined` -(model.ts:346). JSDoc: "The AWS access point to use when accesing s3 for -this external location." (Note also the JSDoc typo "accesing".) - -**Issue:** A field named `accessPoint` reads like a generic concept (the -endpoint at which the table is accessed?). In reality it is AWS S3–specific. -The JSDoc clarifies, but the field name does not. A caller targeting Azure -or GCP will not know to skip the field. - -**Suggested:** rename to `awsAccessPoint` or `s3AccessPoint` (matches the -JSDoc). - -**Cross-reference:** `SseEncryptionDetails.awsKmsKeyArn` (finding 4) takes -the AWS prefix; `accessPoint` does not. Inconsistent within this file. - ---- - -### 19. `CreateTableRequest.browseOnly` is server-output but appears in request — category 6 (Misleading names) +### 16. `CreateTableRequest.browseOnly` is server-output but appears in request — category 6 (Misleading names) **Symbol:** `CreateTableRequest.browseOnly?: boolean | undefined` (model.ts:348). JSDoc: "Indicates whether the principal is limited to @@ -609,48 +532,7 @@ to `TableInfo` only. --- -### 20. `ListTablesRequest.omitColumns` / `omitProperties` / `omitUsername` use negative form — category 13 (Verb-tense inconsistency) and category 17 (Inconsistent action verbs) - -**Symbols:** `ListTablesRequest.omitColumns?: boolean` (model.ts:531), -`omitProperties?: boolean` (model.ts:533), `omitUsername?: boolean` -(model.ts:535). Same package also has `includeBrowse?: boolean` -(model.ts:537), `includeManifestCapabilities?: boolean` (model.ts:539). - -**Issue:** Five boolean flags on the same request type: -- Two positive `include…` (which add output). -- Three negative `omit…` (which subtract output). - -The mixing of positive and negative forms is unusual. Code completion -shows both `omitColumns` and `includeBrowse` on the same type — a reader -might miss that `omitColumns: false` is the default-include state, while -`includeBrowse: false` is the default-exclude state. - -**Suggested:** unify on `include…` (the SDK-wide convention) — e.g. -`includeColumns: boolean | undefined` defaulting to `true`. **Flag at port -time.** - -(Note: `omitUsername` is also a singular — "username", not "usernames" — -even though the JSDoc lists three fields (owner, updated_by, created_by). -Should be `omitUsernames`. See finding 21.) - ---- - -### 21. `ListTablesRequest.omitUsername` singular but covers three fields — category 9 (Singular/plural mismatch) - -**Symbol:** `ListTablesRequest.omitUsername?: boolean | undefined` -(model.ts:535). JSDoc: "Whether to omit the username of the table (e.g. -owner, updated_by, created_by) from the response or not." - -**Issue:** Singular `Username` but the JSDoc lists three fields. Plural -`omitUsernames` would match the impact ("omit *all* the username fields"). - -**Suggested:** `omitUsernames`. Wire form (`omit_username`) is the -single-token version; the TS-side identifier can be pluralised without -changing the wire string. **Coordinate with protocol team.** - ---- - -### 22. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* +### 17. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* **Symbol:** `ListTablesRequest.maxResults?: number | undefined` (model.ts:527), JSDoc: "Maximum number of tables to return. If not set, all @@ -663,48 +545,7 @@ deprecated. The naming is fine; the API behaviour is the issue. --- -### 23. `ListTableSummariesRequest.schemaNamePattern` / `tableNamePattern` vs. `ListTablesRequest.schemaName` field-name inconsistency — category 17 (Inconsistent action verbs) - -**Symbols:** `ListTableSummariesRequest.schemaNamePattern` (model.ts:484) -and `ListTableSummariesRequest.tableNamePattern` (model.ts:489) vs. -`ListTablesRequest.schemaName` (model.ts:519). - -**Issue:** Two sibling list endpoints accept the schema name as different -shapes: -- `ListTablesRequest.schemaName` — an exact string match. -- `ListTableSummariesRequest.schemaNamePattern` — a SQL LIKE pattern. - -JSDoc explains the difference. But the *callers* must remember which -endpoint uses which form. There is no naming hint that one is a pattern. - -**Suggested:** rename `ListTablesRequest.schemaName` to `schemaNameExact` -or `schemaNameEquals` to surface the contrast — or rename -`ListTableSummariesRequest.schemaNamePattern` to `schemaName` with JSDoc -clarifying the pattern syntax. The former is the cleaner pick (less -ambiguous on the input side). - -**Flag at port time.** - ---- - -### 24. `ListTableSummariesRequest_Response.tables` returns `TableSummary[]` not `TableInfo[]` — category 6 (Misleading names) and category 15 (Generic field names losing meaning) - -**Symbol:** `ListTableSummariesRequest_Response.tables?: TableSummary[] | undefined` -(model.ts:507). - -**Issue:** A field named `tables` returns *summaries*, not full table info. -The companion `ListTablesRequest_Response.tables` returns `TableInfo[]`. So -`tables` on one response type vs. another means a different shape. - -**Suggested:** rename `ListTableSummariesRequest_Response.tables` to -`summaries` (matches the response type name). Or rename to `tableSummaries`. -Both expose the shape difference at the field name. - -**Flag at port time.** - ---- - -### 25. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` defined in three packages — category 12 (Duplicate concepts) +### 18. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` defined in three packages — category 12 (Duplicate concepts) **Symbols:** - This file: `Dependency` (model.ts:412), `DependencyList` (model.ts:422), @@ -724,55 +565,7 @@ from each service package. **Strong SDK-wide cleanup.** --- -### 26. `Dependency.value` field name is generic — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) - -**Symbol:** `Dependency.value` (model.ts:413). Type is the discriminated -union. - -**Issue:** `value` is the maximally generic field name. The proto source -likely models `Dependency` as `oneof`; the generator wraps each case in a -`value` discriminator. In TS, the consumer writes: - -```ts -if (dep.value?.$case === 'table') { - console.log(dep.value.table.tableFullName); -} -``` - -`value` adds noise without distinguishing the shape. Compare to -`EncryptionDetails.encryptionDetailsType` (model.ts:438) — same pattern, -non-generic name (see finding 27). Compare to `TableConstraint.constraint` -(model.ts:677) — same pattern, more descriptive name. Within this file, -**three different naming conventions for the same generator pattern.** - -**Suggested:** `Dependency.dependency` (matches the type name) or -`Dependency.kind` (consistent with discriminated-union nomenclature). -**Flag at port time.** - ---- - -### 27. `EncryptionDetails.encryptionDetailsType` repeats the type name as the field name — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) - -**Symbol:** `EncryptionDetails.encryptionDetailsType` (model.ts:438). - -**Issue:** Inside the type `EncryptionDetails`, the field name -`encryptionDetailsType` repeats two of the three tokens of the type name. -A consumer writes: -```ts -encDetails.encryptionDetailsType?.$case -``` -when `encDetails.kind?.$case` or `encDetails.details?.$case` would -suffice. - -Compare to `Dependency.value` (finding 26) — same pattern, generic name. -Compare to `TableConstraint.constraint` — same pattern, name is the type -*concept* without `Type` suffix. - -**Suggested:** `EncryptionDetails.kind`. - ---- - -### 28. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) +### 19. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) **Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:240). JSDoc: "Ordinal position of column (starting at position 0)." @@ -780,50 +573,11 @@ JSDoc: "Ordinal position of column (starting at position 0)." **Issue:** Bare `position` (number) — a consumer cannot tell from the field name that it's 0-indexed. The JSDoc clarifies. -**Suggested:** `ColumnInfo.ordinal` (matches the JSDoc "Ordinal position") -or `columnIndex`. **Pass with note** — the field is short and conventional. - ---- - -### 29. `ColumnInfo.typeText` / `typeName` / `typePrecision` / `typeScale` / `typeIntervalType` / `typeJson` — six `type*` fields — category 12 (Duplicate concepts) - -**Symbols:** `ColumnInfo.typeText` (model.ts:237), `typeName` (model.ts:238), -`typePrecision` (model.ts:242), `typeScale` (model.ts:244), -`typeIntervalType` (model.ts:246), `typeJson` (model.ts:248). - -**Issue:** Six fields all describing the column's data type, prefixed -`type…`. The JSDoc says: -- `typeText` — full SQL catalogString text. -- `typeName` — the enum. -- `typePrecision` — required for `DECIMAL`. -- `typeScale` — required for `DECIMAL`. -- `typeIntervalType` — for `INTERVAL`. -- `typeJson` — full JSON serialisation of the type. - -The shape mirrors Spark's `StructField.dataType` (which is a tree). The -six-field flat form is a wire encoding; in TS, a single `type` field of an -algebraic type would be clearer. - -**Suggested:** group into a sub-object: -```ts -export interface ColumnInfo { - type?: { - name?: ColumnTypeName; - text?: string; - precision?: number; - scale?: number; - intervalType?: string; - json?: string; - }; - // ... -} -``` - -**Flag at port time.** Wire-level decision. +**Suggested:** **Pass with note** — the field is short and conventional. --- -### 30. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) +### 20. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) **Symbols:** `RowFilter.functionName?: string` (model.ts:633), `RowFilter.inputColumnNames?: string[]` (model.ts:638), @@ -843,119 +597,7 @@ deprecation note. --- -### 31. `ColumnMask.usingArguments` vs `RowFilter.inputArguments` action-verb difference — category 17 (Inconsistent action verbs) - -**Symbols:** `ColumnMask.usingArguments?: PolicyFunctionArgument[]` -(model.ts:272), `RowFilter.inputArguments?: PolicyFunctionArgument[]` -(model.ts:644). - -**Issue:** Both fields have the same purpose (positional arguments to a -SQL UDF), the same type (`PolicyFunctionArgument[]`), and the same JSDoc -shape ("This is the replacement of the deprecated …_column_names field"). -But the verb prefix differs: `using…` for masks, `input…` for filters. - -**Suggested:** unify on one verb. `inputArguments` is more conventional -(matches "input parameters" common in DB systems). **Flag at port time.** - ---- - -### 32. `PolicyFunctionArgument.arg` field name is too short — category 1 (Vague/generic) - -**Symbol:** `PolicyFunctionArgument.arg` (model.ts:606). Discriminated -union of `column` / `constant`. - -**Issue:** `arg` is three letters — too short for a public field. The -proto source likely uses `oneof arg`; the generator preserves the field -name. Consumer writes: -```ts -if (positionalArg.arg?.$case === 'column') { ... } -``` - -Compare to `Dependency.value` (finding 26) and -`EncryptionDetails.encryptionDetailsType` (finding 27) — same pattern, -three different naming conventions. The `arg` here is the most cryptic. - -**Suggested:** `argument` (full word) or `kind`. - ---- - -### 33. `PrimaryKeyConstraint.childColumns` vs `ForeignKeyConstraint.childColumns` semantic mismatch — category 6 (Misleading names) and category 12 (Duplicate concepts) - -**Symbols:** `PrimaryKeyConstraint.childColumns?: string[]` -(model.ts:624), `ForeignKeyConstraint.childColumns?: string[]` -(model.ts:451). - -**Issue:** Both types use `childColumns` for "the columns of this table -participating in the constraint." But: -- For a primary key, "child" is wrong vocabulary — there's no parent. A - primary key has no parent table. -- For a foreign key, "child" matches the FK domain (child references - parent). `ForeignKeyConstraint` has both `childColumns` and - `parentColumns` (model.ts:455) — natural pair. - -The `PrimaryKeyConstraint.childColumns` field name is misleading — in PK -context, the columns are simply *the* columns. Cross-reference the wire -form `child_columns` (model.ts:1017, 1125) which inherits the same issue -from upstream. - -**Suggested:** rename `PrimaryKeyConstraint.childColumns` to -`PrimaryKeyConstraint.columns`. **Coordinate with protocol team.** - ---- - -### 34. `PrimaryKeyConstraint.timeseriesColumns` vs `ColumnMask.usingColumnNames` plural-vs-singular inconsistency — category 9 (Singular/plural mismatch) - -**Symbols:** `PrimaryKeyConstraint.timeseriesColumns?: string[]` -(model.ts:626), `ColumnMask.usingColumnNames?: string[]` (model.ts:266), -`ColumnMask.functionName?: string` (model.ts:260). - -**Issue:** Within the same file: -- `columns` (plural): `PrimaryKeyConstraint.childColumns`, - `PrimaryKeyConstraint.timeseriesColumns`, `ForeignKeyConstraint.childColumns`, - `ForeignKeyConstraint.parentColumns`. -- `columnNames` (plural with `Names`): `ColumnMask.usingColumnNames`, - `RowFilter.inputColumnNames`. - -Both refer to lists of column-name strings (`string[]`). The shape is -identical; the names differ in whether the `Names` suffix is included. - -**Suggested:** unify on one form. `columns` is shorter and matches the -constraint vocabulary; `columnNames` is more explicit but verbose. Pick -one. **Flag at port time.** - ---- - -### 35. `ForeignKeyConstraint.rely` boolean is cryptic — category 5 (Cryptic abbreviations) - -**Symbol:** `ForeignKeyConstraint.rely?: boolean | undefined` (model.ts:457). -JSDoc: "True if the constraint is RELY, false or unset if NORELY." - -**Issue:** "RELY" / "NORELY" are SQL keywords (Spark's `ALTER TABLE ... RELY` -hint). The JSDoc explains them; the field name alone is opaque. Same -critique applies to `PrimaryKeyConstraint.rely` (model.ts:628). - -**Suggested:** rename to `relyEnabled` or `enableRely` — the boolean form -needs an `is…` / `enable…` prefix to match SDK convention. **Coordinate -with protocol team.** - ---- - -### 36. `OptionSpec.isCopiable` typo or unusual spelling — category 5 (Cryptic abbreviations) and category 6 (Misleading names) - -**Symbol:** `OptionSpec.isCopiable?: boolean | undefined` (model.ts:598). -JSDoc: "Indicates whether an option should be displayed with copy button -on the UI." - -**Issue:** "Copiable" is an unusual spelling — the standard English forms -are "copyable" or "copy-able". The generator picked the less-common form -(likely from the upstream `.proto`). - -**Suggested:** `isCopyable`. Wire form `is_copiable` stays for back-compat. -**Coordinate with protocol team.** - ---- - -### 37. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* +### 21. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `OptionSpec.isRequired` (model.ts:584), `OptionSpec.isSecret` (model.ts:586), `OptionSpec.isHidden` (model.ts:588), @@ -973,7 +615,7 @@ correctly may want a richer type. **Note for upstream.**) --- -### 38. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 22. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` (model.ts:429). JSDoc: "Whether predictive optimization should be enabled @@ -981,14 +623,14 @@ for this object and objects under it." **Issue:** The type's *purpose* is to indicate whether PO is enabled. The field name `value` says nothing about that. The type is also a `string` -(not a `boolean`) — same problem as finding 16. +(not a `boolean`) — same problem as finding 14. -**Suggested:** rename `value` → `enabled` (boolean) or `state` (matching +**Suggested:** type the field as a boolean (or a constrained enum matching the JSDoc's "enabled" sense). **Coordinate with protocol team.** --- -### 39. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) +### 23. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) **Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` (model.ts:431), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` @@ -997,35 +639,19 @@ the JSDoc's "enabled" sense). **Coordinate with protocol team.** **Issue:** Two fields describing the source of inheritance — the object type ("CATALOG"|"SCHEMA"|…) and the object's name. Naming is OK, but the suffix pair `…Type` / `…Name` repeats inside one struct that has only -three fields. Could be folded: -```ts -inheritedFrom?: { type?: string; name?: string }; -``` +three fields. -**Suggested:** flatten to a sub-object. **Pass with note** — the current -flat form is wire-faithful. +**Pass with note** — the current flat form is wire-faithful. --- -### 40. `TableConstraint.constraint` and `TableConstraint` discriminated-union shape — category 8 (Redundant suffixes) and category 20 (Type-suffix tautology) - -**Symbol:** `TableConstraint.constraint` (model.ts:677). - -**Issue:** Same problem as finding 27 (`EncryptionDetails.encryptionDetailsType`). -Field repeats the type name's primary token. The discriminated union of -three constraint shapes is wrapped in a field literally named `constraint`. - -**Suggested:** rename to a non-repeating field (`kind`, `variant`). - ---- - -### 41. `Client` class name — category 1 (Vague/generic) — *pass* +### 24. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. **Pass.** --- -### 42. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* +### 25. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* Standard `{verb}{Resource}` shape. Convention. **Pass.** @@ -1036,19 +662,19 @@ level.**) --- -### 43. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* +### 26. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* Same `{verb}{Resource}` pattern. **Pass.** --- -### 44. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* +### 27. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* Standard. **Pass.** --- -### 45. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) +### 28. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) **Symbol:** `PACKAGE_SEGMENT` (client.ts:55). @@ -1062,7 +688,7 @@ SDK-wide cleanup.** --- -### 46. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) +### 29. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) **Symbol:** `HttpCallOptions` (utils.ts:15). @@ -1076,7 +702,7 @@ SDK-wide cleanup** — generated boilerplate. --- -### 47. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) +### 30. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) **Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). @@ -1088,7 +714,7 @@ layers. The names imply a hierarchical relationship that does not exist. --- -### 48. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* +### 31. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* Verb-prefixed. Naming is fine. `flattenQueryParams` is used by the multi-query-param list methods (client.ts:357, 444). @@ -1101,7 +727,7 @@ file.) --- -### 49. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* +### 32. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, `TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide @@ -1109,7 +735,7 @@ pattern. **Pass.** --- -### 50. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* +### 33. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `Dependency.value.$case` literals (model.ts:414–417). @@ -1130,7 +756,7 @@ their $case literals. --- -### 51. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* +### 34. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* **Symbol:** `parseResponse` (utils.ts:113) does `JSON.parse(text)` unconditionally. The name implies it can handle any response shape; in @@ -1141,7 +767,7 @@ practice it only handles JSON. --- -### 52. `_PropertiesEntry` / `_Response` underscore-suffixed proto-nested type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) +### 35. `_PropertiesEntry` / `_Response` underscore-suffixed proto-nested type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) **Symbols:** `CreateTableRequest_PropertiesEntry` (model.ts:359), `DeleteTableConstraintRequest_Response` (model.ts:383), @@ -1174,6 +800,92 @@ the proto definition. --- +### 36. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:209, 222 + +**Why:** Underscore-separated `OuterMessage_InnerEnum` naming is a literal +transcription of proto nested-enum scoping. The infix `_` and the +container-prefix on a sibling enum is a proto/grpc architectural leak; +TypeScript has no nested-enum concept. + +**Category:** proto-architectural-leak (`Proto` infix / Go-Java nested-name +form). + +**Suggested:** `OauthStage` and `OptionType` (drop the `OptionSpec_` +prefix) — or, if collision risk exists, `OptionOauthStage` / +`OptionTypeKind`. + +**Rationale:** the `OptionSpec_` prefix exists solely to mirror the proto +nesting; the eslint-disable comments on lines 208, 221 acknowledge the +non-idiomatic shape. + +--- + +### 37. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:563 + +**Why:** `Spec` is a generic config-style suffix that re-appears across +the file (`SecurableKindManifest`, `EffectivePredictiveOptimizationFlag`, +`SseEncryptionDetails`, `EncryptionDetails`). It echoes proto/k8s +"Spec"-shaped messages whose only job is to describe a struct. + +**Category:** proto-architectural-leak (repeated `Spec` config-suffix). + +**Suggested:** `Option` (the type already lives in `SecurableKindManifest.options` +and is self-describing) or `OptionDefinition`. + +**Rationale:** the `Spec` suffix adds no domain meaning beyond "this is a +struct describing X" — a proto convention, not a TS one. + +--- + +### 38. `SecurableKindManifest` type name — file:line model.ts:648 + +**Why:** `Manifest` is a config-style suffix (analogous to `Spec`/`Config`). +It tags the type as a descriptor message rather than a domain concept. + +**Category:** proto-architectural-leak (config-suffix style). + +**Suggested:** `SecurableKindCapabilities` (matches `capabilities` field +content) or fold into a richer `SecurableKind`-keyed structure. + +**Rationale:** the type holds five fields (`securableType`, `securableKind`, +`assignablePrivileges`, `options`, `capabilities`) — the `Manifest` token +adds no information beyond "this is the descriptor". + +--- + +### 39. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:233, 710, 787 + +**Why:** `Info` and `Summary` are generic descriptor-suffixes used to +distinguish the wire/RPC message from the domain noun (`Column`, `Table`). +Two `…Info` types and a `…Summary` type in the same file flag this as a +repeated config-suffix pattern. + +**Category:** proto-architectural-leak (repeated `Info` config-suffix). + +**Suggested:** `Column`, `Table`, `TableOverview` (or collapse all three +into `Table` per finding #11). + +**Rationale:** in a TS surface the noun *is* the type; the `Info`/`Summary` +tag exists only to disambiguate from the proto request/response messages +and from server-internal representations — a generator/architectural leak. + +--- + +### 40. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:437, 662 + +**Why:** Two `…Details` types in the same file. `Details` is a generic +"descriptor" suffix with no domain meaning — same family as `Info`/`Spec`. + +**Category:** proto-architectural-leak (repeated `Details` config-suffix). + +**Suggested:** `Encryption` and `SseEncryption` (or `SseEncryptionConfig` +if disambiguation is needed). + +**Rationale:** `Details` is generator boilerplate for proto messages +wrapping `oneof`s or option blobs; idiomatic TS uses the bare domain noun. + +--- + ## Cross-package alignment recommendations ### A. `Dependency` family duplicated in three packages @@ -1235,14 +947,7 @@ and naming. --- -### G. `fullNameArg` Go-style argument suffix used across many packages - -`tables`, `schemas`, `functions`, `registeredmodels` all use the `Arg` -suffix on URL-path arguments. Drop SDK-wide. - ---- - -### H. Three-tier table-type confusion +### G. Three-tier table-type confusion This package, `onlinetables`, `database`, `postgres`, and `featurestore` all model "table" concepts at different layers: @@ -1266,10 +971,10 @@ documentation pass needed.** | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics, proto-architectural leaks) | 18 | #1, #5, #12, #13, #14, #16, #18, #25, #26, #33, #38, #45, #53, #54, #55, #56, #57, #58 | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 21 | #2, #4, #6, #7, #8, #9, #10, #11, #15, #17, #20, #21, #23, #24, #27, #29, #30, #31, #35, #40, #52 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 10 | #3, #19, #32, #34, #36, #39, #46, #47, #50, #51 | -| **Pass / acceptable** | 9 | #22, #28, #37, #41, #42, #43, #44, #48, #49 | +| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics, proto-architectural leaks) | 13 | #1, #4, #11, #12, #14, #18, #22, #28, #36, #37, #38, #39, #40 | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 11 | #2, #5, #6, #7, #8, #9, #10, #13, #15, #20, #35 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 7 | #3, #16, #23, #29, #30, #33, #34 | +| **Pass / acceptable** | 9 | #17, #19, #21, #24, #25, #26, #27, #31, #32 | --- @@ -1278,127 +983,12 @@ documentation pass needed.** 1. **#1** — fix `DeltaRuntimePropertiesKvpairs` (field) / `DeltaRuntimePropertiesKvPairs` (type) casing mismatch. Local, mechanical rename. -2. **#12** — drop the `Arg` suffix from `fullNameArg` SDK-wide. Higher - impact (changes wire field name) but eliminates a Go-style convention. -3. **#16** — type `enablePredictiveOptimization` as a real enum instead of +2. **#14** — type `enablePredictiveOptimization` as a real enum instead of a free-form string. Improves type safety. -4. **#26 / #27 / #32 / #40** — unify discriminated-union container field - names (`value` vs `encryptionDetailsType` vs `arg` vs `constraint`). - Within-file consistency fix. -5. **#24** — rename `ListTableSummariesRequest_Response.tables` to - `summaries` (or `tableSummaries`). Easy local fix. - ---- - ---- - -### 53. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:209, 222 - -**Why:** Underscore-separated `OuterMessage_InnerEnum` naming is a literal -transcription of proto nested-enum scoping. The infix `_` and the -container-prefix on a sibling enum is a proto/grpc architectural leak; -TypeScript has no nested-enum concept. - -**Category:** proto-architectural-leak (`Proto` infix / Go-Java nested-name -form). - -**Suggested:** `OauthStage` and `OptionType` (drop the `OptionSpec_` -prefix) — or, if collision risk exists, `OptionOauthStage` / -`OptionTypeKind`. - -**Rationale:** the `OptionSpec_` prefix exists solely to mirror the proto -nesting; the eslint-disable comments on lines 208, 221 acknowledge the -non-idiomatic shape. - ---- - -### 54. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:563 - -**Why:** `Spec` is a generic config-style suffix that re-appears across -the file (`SecurableKindManifest`, `EffectivePredictiveOptimizationFlag`, -`SseEncryptionDetails`, `EncryptionDetails`). It echoes proto/k8s -"Spec"-shaped messages whose only job is to describe a struct. - -**Category:** proto-architectural-leak (repeated `Spec` config-suffix). - -**Suggested:** `Option` (the type already lives in `SecurableKindManifest.options` -and is self-describing) or `OptionDefinition`. - -**Rationale:** the `Spec` suffix adds no domain meaning beyond "this is a -struct describing X" — a proto convention, not a TS one. - ---- - -### 55. `SecurableKindManifest` type name — file:line model.ts:648 - -**Why:** `Manifest` is a config-style suffix (analogous to `Spec`/`Config`). -It tags the type as a descriptor message rather than a domain concept. - -**Category:** proto-architectural-leak (config-suffix style). - -**Suggested:** `SecurableKindCapabilities` (matches `capabilities` field -content) or fold into a richer `SecurableKind`-keyed structure. - -**Rationale:** the type holds five fields (`securableType`, `securableKind`, -`assignablePrivileges`, `options`, `capabilities`) — the `Manifest` token -adds no information beyond "this is the descriptor". - ---- - -### 56. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:233, 710, 787 - -**Why:** `Info` and `Summary` are generic descriptor-suffixes used to -distinguish the wire/RPC message from the domain noun (`Column`, `Table`). -Two `…Info` types and a `…Summary` type in the same file flag this as a -repeated config-suffix pattern. - -**Category:** proto-architectural-leak (repeated `Info` config-suffix). - -**Suggested:** `Column`, `Table`, `TableOverview` (or collapse all three -into `Table` per finding #13). - -**Rationale:** in a TS surface the noun *is* the type; the `Info`/`Summary` -tag exists only to disambiguate from the proto request/response messages -and from server-internal representations — a generator/architectural leak. - ---- - -### 57. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:437, 662 - -**Why:** Two `…Details` types in the same file. `Details` is a generic -"descriptor" suffix with no domain meaning — same family as `Info`/`Spec`. - -**Category:** proto-architectural-leak (repeated `Details` config-suffix). - -**Suggested:** `Encryption` and `SseEncryption` (or `SseEncryptionConfig` -if disambiguation is needed). The discriminated-union container field -`encryptionDetailsType` (finding #27) then becomes `encryption.kind` — and -the redundant `Details` token disappears. - -**Rationale:** `Details` is generator boilerplate for proto messages -wrapping `oneof`s or option blobs; idiomatic TS uses the bare domain noun. - ---- - -### 58. `dataAccessConfigurationId` field — `Configuration` mid-position config-suffix — file:line model.ts:327, 750, 837 - -**Why:** `Configuration` mid-token (between `DataAccess` and `Id`) is a -config-suffix occurrence inside a field name. The wire form is -`data_access_configuration_id`; the TS form repeats the noise. - -**Category:** proto-architectural-leak (`Config` family mid-position). - -**Suggested:** `dataAccessConfigId` (shorter) or `dataAccessId` if the -"configuration" is implicit (the value already identifies a config record). - -**Rationale:** five-token field names with a mid `Configuration` token are -a strong signal of proto-style verbose naming surviving the wire→TS port. - ---- - -## Fixed - -- #18 `TableExists` (originally cited at model.ts:761): Fixed in regeneration on 2026-05-20 — request type renamed to `TableExistsRequest`, resolving the verb-as-noun reading on the request surface. -- #19 Request type naming pattern is inconsistent (originally cited at model.ts:322, 411, 417, 419, 432, 517, 528, 566, 594, 761, 857, 399): Fixed in regeneration on 2026-05-20 — all request types now carry the `Request` suffix (`CreateTableRequest`, `DeleteTableRequest`, `DeleteTableConstraintRequest`, `GetTableRequest`, `ListTablesRequest`, `ListTableSummariesRequest`, `TableExistsRequest`, `UpdateTableRequest`, `CreateTableConstraintRequest`). -- #45 `ConditionalDisplay.dependsOnOption` vs `hiddenWhenValues` field naming asymmetry (originally cited at model.ts:307, 313): Fixed in regeneration on 2026-05-20 — the `ConditionalDisplay` interface is no longer generated for this package. -- #32 (partial) — `VolumeDependency` and `SecretDependency` (originally cited at model.ts:704, 940 with the rest of the Dependency family): Fixed in regeneration on 2026-05-20 — those two leaf types and the `volume` / `secret` discriminated-union cases were removed from `Dependency`; the cross-package duplication concern (now finding #25) still applies to the four remaining leaf types. +3. **#22** — type `EffectivePredictiveOptimizationFlag.value` as a real + boolean/enum instead of a free-form string. Same family as #14. +4. **#35** — eliminate `_Response` empty bodies and `_PropertiesEntry` + map-entry shells. Local type-level cleanup. +5. **#36 / #37 / #38 / #39 / #40** — drop proto-architectural type-name + suffixes (`_OauthStage`, `Spec`, `Manifest`, `Info`/`Summary`, `Details`) + in favour of bare domain nouns. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index f4be051e..6e31c541 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -3,12 +3,12 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. -**Total weird names flagged:** 27 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | -| High | 9 | +| High | 6 | | Medium | 11 | | Low | 4 | | Observation | 3 | @@ -21,49 +21,31 @@ - **Suggested name:** Rename to `platformtagassignments` or `appdashtags` to mark the scope, while renaming the sister `entitytagassignments` to `uctagassignments`. Alternatively, merge both into a unified `tagassignments` package with a discriminating `entityKind` field. - **Rationale:** Two sister packages whose names diverge from their wire paths force users to memorize a name-to-API mapping. Without `entity` in this directory, the type `TagAssignment` here and `EntityTagAssignment` there look like different kinds of objects when they are not. Generator-level concern. -### 2. `TagAssignment` field shape vs. sister `EntityTagAssignment` shape — `src/v1/model.ts:46-55` vs. `entitytagassignments/src/v1/model.ts:32-49` -- **Why weird:** The two sister types model the same conceptual object using divergent identifiers. This package has `entityId: string` (with doc "For apps, the entity_id is the app name"). Sister has `entityName: string` (with doc "fully qualified name"). The wire-side names are `entity_id` vs. `entity_name`. The doc for `entityId` admits it can be a name — so it is sometimes an id and sometimes a name. A user porting code between the two packages must change every field reference even though the data is the same. -- **Category:** 12 (duplicate concept with divergent naming), 17 (inconsistency between siblings), 16 (field name contradicts type domain — calling it `entityId` when it is "the app name" is misleading). -- **Suggested name:** Unify on `entityRef`, `entity`, or `entityKey` for both packages. At minimum, rename one to match the other. The doc-confessed "id is actually a name" case is exactly why a neutral identifier name is needed. -- **Rationale:** Splitting "name vs id" by sister package, when both fields hold the same logical thing (an entity identifier — sometimes literally a name), is poor cross-package developer experience. - -### 3. `TagAssignment` — `src/v1/model.ts:46` +### 2. `TagAssignment` — `src/v1/model.ts:46` - **Why weird:** The primary type `TagAssignment` is a tag assigned to an *entity* — every field on it (`entityType`, `entityId`, `tagKey`, `tagValue`) presupposes an entity. The name says "tag assignment" but the type really is "entity tag assignment". Yet sister package `entitytagassignments` does include the `Entity` prefix on its type. So the SDK has both `TagAssignment` and `EntityTagAssignment` for the same conceptual shape. - **Category:** 1 (vague — assignment to what?), 12 (duplicate concept naming across siblings), 16 (no `Entity` prefix when sister package has it for the same concept). - **Suggested name:** Either pick `EntityTagAssignment` here too (and rename type-collisions out at re-export), or rename the sister to drop `Entity` and use package-scoped imports. Pick one. - **Rationale:** The naming asymmetry between sister types is the actual bug. Both should be the same name, with disambiguation via import. -### 4. `entityType: string` — `src/v1/model.ts:13,22,31,48` +### 3. `entityType: string` — `src/v1/model.ts:13,22,31,48` - **Why weird:** Four occurrences of `entityType?: string | undefined`. The JSDoc lists allowed values inline: "apps, dashboards, geniespaces, notebooks". A closed set of four values lives in plain prose, not in the type. Users will pass typos with no compile-time check. - **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what values are valid?), 6 (misleading — looks free-form, is actually constrained), 16 (field contradicts type — closed set typed as open string). - **Suggested name:** Introduce `EntityKind = 'apps' | 'dashboards' | 'geniespaces' | 'notebooks'` and type the field as `entityKind?: EntityKind`. `Kind` reads cleaner than `Type` in TS (cf. `SyntaxKind` in TS compiler API). - **Rationale:** The valid set is closed and documented; the type should reflect that. Generator anti-pattern: stringly-typed enums. -### 5. `entityId: string` doc inconsistency — `src/v1/model.ts:15,23,33,49` -- **Why weird:** Four occurrences of `entityId?: string | undefined`. The JSDoc reads: "The identifier of the entity to which the tag is assigned. For apps, the entity_id is the app name." So `entityId` is sometimes a name, sometimes an id, and the doc carves out one of the four entity kinds explicitly. There is no rule for what `entityId` looks like for `dashboards`/`geniespaces`/`notebooks`. -- **Category:** 6 (misleading — labelled `Id` but is "the app name" for apps), 19 (underspecified — what does it look like for the other three kinds?), 16 (field contradicts type domain — "id" suggests an opaque handle, but for apps it is a human-readable name). -- **Suggested name:** `entityRef` or `entity` (neutral). Combined with `EntityKind` from #4, the meaning of `entityRef` is "the identifier appropriate for this kind". -- **Rationale:** A field whose semantics changes per `entityType` should not be named after one of those semantics. - -### 6. `Client` class — `src/v1/client.ts:41` +### 4. `Client` class — `src/v1/client.ts:41` - **Why weird:** A class literally named `Client` re-exported through `index.ts:3` as plain `Client`. Sister packages `entitytagassignments` and `tagpolicies` ship `Client` classes of the same name. Three `Client`s across the tag-related sibling packages. - **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name losing meaning), 12 (duplicate concept across sister packages). - **Suggested name:** `TagAssignmentsClient`. Forces aliasing only when co-imported, but reads as "the client for the tag-assignments surface". - **Rationale:** Three `Client`s in three sister packages will collide on combined imports. -### 7. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` +### 5. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` - **Why weird:** Same concept, two different field names across sister packages. This package: `pageSize?: number`. Sister: `maxResults?: number`. The wire-side names also diverge (`page_size` here, `max_results` there). Within a single SDK, the page-size parameter has two names depending on which tag flavor you use. - **Category:** 12 (duplicate concept named differently across siblings), 17 (inconsistency between sibling fields). - **Suggested name:** Pick one. `pageSize` is the more conventional name (matches `nextPageToken` here). `maxResults` is older. - **Rationale:** Cross-SDK pagination naming consistency. Worth flagging upstream — generator-wide concern. -### 8. `tagKey` and `tagValue` on `TagAssignment` — `src/v1/model.ts:52,54` -- **Why weird:** The type is `TagAssignment` and the fields are `tagKey`/`tagValue`. Inside a `TagAssignment`, the `tag` prefix is redundant: `assignment.tagKey` reads as "the assignment's tag's key" when the assignment *is* a tag. Same in sister packages. -- **Category:** 8 (redundant prefix — `tag` within `TagAssignment`). -- **Suggested name:** `key` and `value` (drop the `tag` prefix). Wire stays `tag_key` / `tag_value`. -- **Rationale:** Fields should not re-state their container's noun. `assignment.key` reads cleaner. - -### 9. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` +### 6. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` - **Why weird:** The list URL is `/api/2.0/entity-tag-assignments/${entityType ?? ''}/${entityId ?? ''}/tags`. When either is undefined, the URL becomes `.../entity-tag-assignments///tags`. Both fields are typed `string | undefined`, but `entityType` and `entityId` are clearly required to address an entity. Same issue on `Get`/`Delete`/`Update`. The SDK silently produces malformed URLs. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. @@ -71,13 +53,13 @@ ## Medium severity -### 10. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` +### 7. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` - **Why weird:** The plural appears only on list types. The HTTP resource on the wire is `/entity-tag-assignments` (plural) while the item type is singular `TagAssignment`. List response is `ListTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. - **Rationale:** Rule 9 demands the flag even when intentional. -### 11. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 8. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute". `executeCall` wraps retry/rate-limit policy; `executeHttpCall` does the actual HTTP send. In every client method both appear: ```ts const call: Call = async (callSignal?: AbortSignal): Promise => { @@ -91,81 +73,81 @@ - **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. - **Rationale:** Layering should be readable from names. Generator-wide concern. -### 12. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` +### 9. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` - **Why weird:** Variable `call` of type `Call`, passed to `executeCall`. Same word as variable, type, and verb. Inside one method scope we have `req`, `call`, `httpReq`, `resp` — four roles, three of which abbreviate. - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest`/`sendRequest` for the variable; keep `Call` as the type. - **Rationale:** Variable-type collisions are tolerable but obscure prose. -### 13. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` +### 10. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` - **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. - **Category:** 6 (misleading — silent malformed URLs). - **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. -- **Rationale:** See #9. Generator-wide concern. +- **Rationale:** See #6. Generator-wide concern. -### 14. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` +### 11. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` - **Why weird:** `respBody: Uint8Array` and `resp: TagAssignment` differ only by suffix. Both abbreviate "response"; the reader must remember which is bytes and which is parsed. There is no `reqBody` sibling for symmetry. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — only response abbreviates with `Body`). - **Suggested name:** `rawBody`/`result`, or `responseBytes`/`response`. - **Rationale:** Stage differences should be communicated by meaningful nouns, not suffix variations. -### 15. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` +### 12. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` - **Why weird:** Inside methods that already have `req: `, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. - **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). - **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. - **Rationale:** Forking the same identifier across layers is hard to read. -### 16. `pageReq` clone variable in paginated list — `src/v1/client.ts:174` +### 13. `pageReq` clone variable in paginated list — `src/v1/client.ts:174` - **Why weird:** A clone of `req` is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; outer `req` is the parameter. - **Category:** 5 (cryptic), 8 (redundant prefix — `page` in a pagination loop is implicit). - **Suggested name:** `current` or `cursor` (describes its role as iterator state). - **Rationale:** A variable that mutates a clone of the input should describe its role. -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` +### 14. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. -### 18. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` +### 15. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` - **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. - **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern). - **Suggested name:** `makeHttpRequest` or inline at call sites. - **Rationale:** "Build" carries Java/JS Builder-pattern connotations. -### 19. `AuthHttpClient` — `src/v1/transport.ts:43` +### 16. `AuthHttpClient` — `src/v1/transport.ts:43` - **Why weird:** Class name encodes its implementation pattern: it is an `HttpClient` whose role is "wraps another HttpClient and injects auth headers". The JSDoc on line 42 literally reads "Wraps an HttpClient and adds authentication headers to requests." That is the Decorator/Wrapper architectural pattern leaking into the type name. The name describes the *how* (HTTP client decorator), not the *what* (authenticated transport). - **Category:** proto-architectural-leak — `Wrapper`/`Adapter` style class whose name advertises a decorator implementation rather than the domain role. - **Suggested name:** `AuthenticatingTransport`, `AuthenticatedTransport`, or `AuthInjector`. Drops the `HttpClient` infix that just restates the base interface it decorates. - **Rationale:** A class whose only job is to add auth headers should be named for that job, not the wrapping mechanism. Sister packages all duplicate this class verbatim — generator-wide concern. -### 20. `TimeoutHttpClient` — `src/v1/transport.ts:61` -- **Why weird:** Same wrapper-name pattern as #19. JSDoc line 60: "Wraps an HttpClient and applies a default timeout to requests." Name encodes the wrapping mechanism (`HttpClient` suffix) plus the cross-cutting concern (`Timeout` prefix). Reads as `` — a classic Decorator naming tell. +### 17. `TimeoutHttpClient` — `src/v1/transport.ts:61` +- **Why weird:** Same wrapper-name pattern as #16. JSDoc line 60: "Wraps an HttpClient and applies a default timeout to requests." Name encodes the wrapping mechanism (`HttpClient` suffix) plus the cross-cutting concern (`Timeout` prefix). Reads as `` — a classic Decorator naming tell. - **Category:** proto-architectural-leak — `Wrapper`/`Adapter` class whose name advertises a decorator-of-HttpClient implementation rather than the domain role. - **Suggested name:** `TimeoutTransport`, `RequestTimeout`, or merge the timeout behavior into the base `newFetchHttpClient` so a separate type is unneeded. - **Rationale:** `TimeoutHttpClient` is two architectural words concatenated: the concern (`Timeout`) and the wrapped interface (`HttpClient`). Domain names should describe behavior, not the OO pattern. Generator-wide concern — every package repeats this. ## Low severity -### 21. `flattenQueryParams` — `src/v1/utils.ts:123` +### 18. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in `client.ts`. This package's `listTagAssignments` uses individual `params.append(...)` calls (line 142-148) instead. Dead-shaped helper in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it). - **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. -### 22. `readAll(body)` — `src/v1/utils.ts:40` +### 19. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is too generic; the function specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** Reads like it might take a file path or array. -### 23. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 20. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The single word "segment" provides no domain context. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Comment above the constant does the work the name should. -### 24. `tagValue` field doc empty — `src/v1/model.ts:53,54` +### 21. `tagValue` field doc empty — `src/v1/model.ts:53,54` - **Why weird:** `tagValue?: string | undefined` is documented as "The value of the tag" — a tautology. Compare the rich docs on `entityType`/`entityId`/`tagKey` (with character-class rules). The doc is doing zero work. - **Category:** 1 (vague — doc says nothing the field name does not), 15 (generic field doc). - **Suggested name:** Document what makes a `tagValue` valid (max length? character set? same restrictions as `tagKey`?). @@ -173,14 +155,14 @@ ## Observations -### 25. Action verb consistency +### 22. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 26. `tagassignments` lowercase package name vs. types and HTTP path +### 23. `tagassignments` lowercase package name vs. types and HTTP path The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). -### 27. Domain leakage between sister packages +### 24. Domain leakage between sister packages Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md index eff5c9ce..762e64e6 100644 --- a/.agent/naming-audit/tagpolicies.md +++ b/.agent/naming-audit/tagpolicies.md @@ -3,14 +3,14 @@ **Path:** `packages/tagpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and an optional `id`/timestamps so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. -**Total weird names flagged:** 18 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | -| High | 6 | +| High | 5 | | Medium | 4 | -| Low | 4 | +| Low | 3 | | Observation | 4 | ## High severity @@ -45,33 +45,27 @@ - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) on get/delete/update. Add JSDoc describing valid keys. - **Rationale:** Optional path parameters in REST clients are a generator anti-pattern. Honest required-ness should travel through the type, not through a `?? ''` fallback that produces a malformed URL. -### 6. `Value.name` field — `src/v1/model.ts:53` -- **Why weird:** Field on `Value` is `name?: string | undefined` (line 53), but conceptually the field holds the *value text* of an allowed tag value (e.g., `"prod"`, `"dev"`). Calling that text `name` collides with the domain meaning of "tag value": the value's `name` is the value. JSDoc is empty. There is no `displayName` or other field to disambiguate — `name` is the *only* field. -- **Category:** 1 (vague/generic — `name` for a string that is the value itself), 6 (misleading — `name` suggests a label distinct from the value), 15 (generic field name losing meaning), 16 (field name contradicts type domain — `Value.name` reads "the name of a value", but the value's name *is* the value). -- **Suggested name:** Rename to `Value.value` (still awkward) or `AllowedValue.text`. -- **Rationale:** `tagPolicy.values[0].name` reads as "the name of the first value of this tag policy", which is structurally absurd. - ## Medium severity -### 7. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:20` vs. `model.ts:36` +### 6. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:20` vs. `model.ts:36` - **Why weird:** Plural only on list endpoint; singular elsewhere. The list response is `ListTagPoliciesResponse` (plural). The wire path is `/tag-policies` (plural). The convention is consistent with the Go SDK, but worth flagging that the resource name on the wire is plural while the item type is singular. - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary within one type family). - **Suggested name:** Keep as is (cross-SDK convention). Listed for completeness under rule 9. - **Rationale:** Same as in `entitytagassignments` audit — flagged because rule 9 demands it. -### 8. Create/update wrap the subject in a body field while the list response also wraps in an array field — `src/v1/model.ts:9,32,48` +### 7. Create/update wrap the subject in a body field while the list response also wraps in an array field — `src/v1/model.ts:9,32,48` - **Why weird:** `CreateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) and `UpdateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) both put the subject inside a one-field body. `ListTagPoliciesResponse.tagPolicies: TagPolicy[]` does the analogous thing for the response. Each wrapper is a single-field envelope around the actual payload, which means every caller writes `client.create({tagPolicy: {...}})` instead of `client.create({...})`. The envelope is consistent in cardinality (singular/plural matches the type), but it adds a level of indirection on every call. - **Category:** 17 (inconsistency — request and response both wrap, but callers must remember the wrapper field name on each side). - **Suggested name:** N/A — the wrapper envelopes are dictated by wire-side proto shape. Flagged as a generator-level consideration. - **Rationale:** Single-field body envelopes show up across the generated SDK; this package is one instance. -### 9. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` +### 8. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` - **Why weird:** Two near-identical names with different purposes. `executeCall(call, options)` runs a `Call` through the retrier/rate-limiter; `executeHttpCall(opts)` issues a single HTTP request and reads the body. The names differ by one word (`Http`) but the responsibilities are radically different (orchestrator vs. transport). A user grepping for "execute" can't tell which one to use. - **Category:** 1 (vague — the disambiguator is too thin), 17 (inconsistent verb scoping). - **Suggested name:** `executeCall` (orchestrator) and `sendHttpRequest` (single-request transport). - **Rationale:** Distinct responsibilities should have distinct verb roots, not a same-verb-different-noun split. -### 10. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 9. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that this client does not invoke (the list endpoint uses individual `params.append(...)` calls instead — see `client.ts:143,146`). Dead-code-shaped helper. - **Category:** 6 (misleading — implies the package uses it), 1 (vague — `flatten` is generic; this specific one only handles a subset of types). - **Suggested name:** N/A — should live in a shared utils package, not be copied into every package. @@ -79,25 +73,19 @@ ## Low severity -### 11. `createTime` and `updateTime` naming on `TagPolicy` — `src/v1/model.ts:42,44` -- **Why weird:** Verb tense / noun pair where the natural English is "created at" / "updated at". `createTime` reads as "the time to create" (a verb-noun); `createdAt` is the cross-language convention for "timestamp when it was created". Cross-SDK convention is `createTime`/`updateTime`, so this is consistent with the rest of the codebase, but is non-idiomatic JS/TS. -- **Category:** 13 (verb-tense inconsistency — `create` (infinitive) vs. `created` (past participle)), 14 (Go-style naming — Go uses `CreateTime`). -- **Suggested name:** `createdAt` / `updatedAt`. -- **Rationale:** Established SDK pattern, but rule 13/14 demand the flag. Mongo, PostgREST, Rails, GraphQL conventions all use `createdAt`. - -### 12. `Temporal.Instant` for timestamps — `src/v1/model.ts:42,44` +### 10. `Temporal.Instant` for timestamps — `src/v1/model.ts:42,44` - **Why weird:** Uses `Temporal.Instant` (from `@js-temporal/polyfill`), which is a great future-proof choice — but `Instant` is unfamiliar to most JS devs (who expect `Date` or string). The doc says "Timestamp when the tag policy was created" without explaining why it's an `Instant`. - **Category:** 1 (slightly vague choice without doc support), 5 (cryptic to readers unfamiliar with Temporal proposal). - **Suggested name:** Keep `Temporal.Instant`; add JSDoc explaining the type choice. - **Rationale:** Generator-wide; flagged once. -### 13. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:22-25` +### 11. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:22-25` - **Why weird:** JSDoc says "The maximum value is 1000; values above 1000 will be coerced down to 1000." but the field is typed `number | undefined`. A caller passing `pageSize: 100000` silently gets clipped to 1000. The constraint travels only via the docstring. - **Category:** 6 (misleading — type does not match contract). - **Suggested name:** Keep `pageSize`; consider a branded type or a runtime validator. At minimum, restate the limit clearly. - **Rationale:** Generator-wide; flagged because docs lie about wire behaviour. -### 14. `updateMask` field type `FieldMask` — `src/v1/model.ts:49` +### 12. `updateMask` field type `FieldMask` — `src/v1/model.ts:49` - **Why weird:** `FieldMask` is a generic type carrying the masked-shape as a type parameter. The name `updateMask` is wire-standard (proto FieldMask) but cryptic to TS users — "mask" usually means a bitmask. The JSDoc is missing. - **Category:** 5 (cryptic — `mask` for TS users means bitmask), 14 (proto-style — FieldMask is a proto concept). - **Suggested name:** Keep `updateMask`; add JSDoc explaining it's a path-based selector for partial updates. @@ -105,18 +93,18 @@ ## Observations -### 15. Action verb consistency +### 13. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 16. Acronym casing +### 14. Acronym casing File uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri` casing clashes encountered within the file. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 17. `tagpolicies` lowercase package name +### 15. `tagpolicies` lowercase package name Package directory is `tagpolicies` (single token, no separator), but every type uses `TagPolicy*` and the HTTP path uses `tag-policies`. Same problem as `dataclassification`, `tagassignments`, `entitytagassignments` — SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 18. Domain leakage from sister packages +### 16. Domain leakage from sister packages Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — all collide on the noun "tag". Each ships its own `Client`, its own `tag*` types, and its own `tagKey`. Co-import requires extensive aliasing. `tagpolicies` differs in that it defines the *policy* over the tag, while the assignment packages attach a `tagKey` + `tagValue` to entities — but a user can't tell from the name; "tag policies" sounds like it could be policies *for* tag assignments. - **Category:** 12 (duplicate concept across siblings). @@ -132,10 +120,3 @@ Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — a - `src/v1/client.ts` (224 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (17 lines): read fully. - -## Fixed -- #3 Doubled `Policy` suffix in conflict-resolution path (originally cited at `src/v1/model.ts:9,11,13`): Fixed in regeneration on 2026-05-20 — `ConflictResolutionPolicy` and `DefaultValueOverridePolicy` types removed from the package. -- #9 `PropagationConfig` type (originally cited at `src/v1/model.ts:55`): Fixed in regeneration on 2026-05-20 — `PropagationConfig` type removed from the package. -- #10 `propagationConfig.enabled` boolean shape (originally cited at `src/v1/model.ts:57`): Fixed in regeneration on 2026-05-20 — propagation config removed entirely. -- #15 `defaultValueOverride` case identifier vs. type name (originally cited at `src/v1/model.ts:13,15`): Fixed in regeneration on 2026-05-20 — discriminator union and `DefaultValueOverridePolicy` payload removed. -- #20 `accountId: string` on `TagPolicy` (originally cited at `src/v1/model.ts:74`): Fixed in regeneration on 2026-05-20 — `accountId` field removed from `TagPolicy`. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index ad4d800c..9e854454 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -3,14 +3,14 @@ **Path:** `packages/tokenmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/create-on-behalf-of/delete arbitrary user tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. -**Total weird names flagged:** 19 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 9 | -| Low | 4 | +| High | 4 | +| Medium | 4 | +| Low | 3 | | Observation | 0 | ## High severity @@ -33,19 +33,7 @@ - **Suggested name:** Either rename method to `revokeToken` (matches type and matches sibling package) or rename type to `DeleteTokenRequest` (matches HTTP verb). Recommend the former so both packages share a verb. - **Rationale:** "Revoke" carries a security/lifecycle meaning that "delete" loses; tokens aren't deleted from history, they're invalidated. -### 4. `tokenInfo` field on response types — `Info` tautology -- **Why weird:** Field `tokenInfo: AdminTokenInfo | undefined` on `CreateOnBehalfOfTokenRequest_Response` (`model.ts:42`) and `GetTokenRequest_Response` (`model.ts:60`). Field name re-states the type's redundant suffix. Cascades from the `AdminTokenInfo` → `Token` rename (finding #2). -- **Category:** 20 (type-suffix tautology), 1 (`Info` vague). -- **Suggested name:** `token: Token` (paired with rename in finding #2). -- **Rationale:** Mechanical cascade. `response.token.tokenId` reads more naturally than `response.tokenInfo.tokenId`. - -### 5. `tokenInfos` field on list response — plural of `Info`, doc-string mismatch -- **Why weird:** Field `tokenInfos: AdminTokenInfo[] | undefined` on `ListTokensRequest_Response` (`model.ts:82`). Same `Info` tautology as #4 but plural. Also: the JSDoc says "Token metadata of each user-created token in the workspace" — "metadata" implies summary info, but `AdminTokenInfo` is the full row. The field name should be `tokens` not `tokenInfos`. -- **Category:** 20 (type-suffix tautology), 9 (plural-of-`Info` is unidiomatic), 1 (`Info` vague), 15 (field name "tokenInfos" loses meaning). -- **Suggested name:** `tokens: Token[]` (paired with rename in finding #2). -- **Rationale:** Same as #4. Sibling `tokens` list response has the identical issue. - -### 6. `AdminTokenInfo` — `Admin` mid-position prefix is an architectural-tier leak (not domain) — `src/v1/model.ts:5` +### 4. `AdminTokenInfo` — `Admin` mid-position prefix is an architectural-tier leak (not domain) — `src/v1/model.ts:5` - **Why:** `Admin` mid-position on the entity type names a service-tier / audience-of-callers (admin vs. non-admin caller), not a domain concept. The sibling package uses `PublicTokenInfo` for the same kind of leak (`Public` mid-position). Tokens are not "admin tokens"; they are personal access tokens that this admin-scoped endpoint can list/manage. The `Admin`/`Public` distinction is purely about which RBAC tier of the backend service exposes the model. - **Category:** Proto-architectural-leak — `Public`/`Internal`/`External` family of mid-position service-tier qualifiers used as a noun prefix. - **Suggested:** `Token` (or `ManagedToken` to disambiguate from the sibling package's entity; see also finding #2 which already proposes `Token`). @@ -53,81 +41,45 @@ ## Medium severity -### 7. `applicationId` on `CreateOnBehalfOfTokenRequest` — generic field name in a security-sensitive context -- **Why weird:** `applicationId?: string` (`model.ts:29`) is the OAuth client ID of the service principal the on-behalf-of token will represent. "Application ID" is Azure terminology; on AWS/GCP it's "service principal ID" or "client ID". This is the *target* identity for a privileged token-mint operation; `applicationId` undersells the security implication and overloads "application" with three different meanings across Databricks clouds. -- **Category:** 1 (vague — "application" is overloaded), 14 (Azure-style naming leaks), 15 (generic name in security context), 19 (underspecified ID — application ID of what?). -- **Suggested name:** `servicePrincipalApplicationId` or `servicePrincipalClientId` (the JSDoc literally says "Application ID of the service principal", so the field name should too). -- **Rationale:** The field documentation already names the concept correctly; the field name should follow. Mistaking this for "Databricks Apps application id" would mint a token for the wrong principal. - -### 8. `ListTokensRequest` fields `createdById` and `createdByUsername` — duplicate filter slots +### 5. `ListTokensRequest` fields `createdById` and `createdByUsername` — duplicate filter slots - **Why weird:** `ListTokensRequest { createdById?, createdByUsername? }` (`model.ts:71-76`). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (`client.ts:158-163`) which means callers can submit both at once and get undefined server behavior. - **Category:** 1 (vague — relationship unspecified), 6 (misleading — looks like two filters, possibly redundant). - **Suggested name:** Either expose a single `filter` string or document mutual exclusivity. At minimum, JSDoc the AND/OR semantics. - **Rationale:** Consumer-facing API ambiguity. -### 9. `creationTime` / `expiryTime` / `lastUsedDay` — three time fields with three units and no unit suffix -- **Why weird:** `AdminTokenInfo` (`model.ts:9-23`) has `creationTime: number`, `expiryTime: number`, `lastUsedDay: number`. The first two are described as "Timestamp" (likely epoch ms, by convention). The third is described as "Approximate timestamp for the day the token was last used. Accurate up to 1 day." But the field is named `lastUsedDay` (not `lastUsedTime` or `lastUsedDate`), and the doc says it is *still* a timestamp — so the suffix `Day` here means "with day-level granularity" not "as a calendar day index". A reader who skims the type and not the doc could easily believe `lastUsedDay` is a 1-31 day-of-month integer or a number-of-days-since-epoch integer. -- **Category:** 5 (cryptic — `Day` is ambiguous), 6 (misleading — "Day" implies a date, value is a timestamp), 15 (generic name without unit). -- **Suggested name:** `lastUsedTimeMs` (or split into `lastUsedTime: number` + a JSDoc note). At minimum, document the unit on all three fields. -- **Rationale:** Compare with `tokens.PublicTokenInfo.lastAccessedTime` which uses `Time` consistently. The admin variant breaks the pattern. - -### 10. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc +### 6. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc - **Why weird:** `AdminTokenInfo` has `createdById` ("User ID of the user that created the token", `model.ts:15`) and `ownerId` ("User ID of the user that owns the token", `model.ts:19`). What's the difference? In the sibling `tokens` package, the type has no `ownerId`. This appears to be admin-only metadata where ownership can transfer (e.g., on-behalf-of tokens). A reader has no way to know without external docs whether the two are usually equal. - **Category:** 1 (vague — relationship unstated), 19 (underspecified IDs in same struct). - **Suggested name:** Keep names but add JSDoc clarifying when they diverge (e.g., on-behalf-of tokens: creator is the principal who called the API, owner is the service principal). - **Rationale:** Discoverability. -### 11. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope +### 7. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope - **Why weird:** `workspaceId?: number | undefined` (`model.ts:21`) is documented "If applicable, the ID of the workspace that the token was created in." So it's optional and only meaningful at the account level. But the package and the URL path `/api/2.0/token-management/...` is a workspace endpoint. The field thus carries no useful signal at this endpoint, yet it's exposed. - **Category:** 6 (misleading — looks pertinent, often vestigial). - **Suggested name:** Keep; document under what circumstances it is populated (e.g., when the same model is reused at the account API). - **Rationale:** Generator artefact from sharing models across workspace/account scopes. Flag for upstream cleanup. -### 12. `lastUsedDay` vs sibling `tokens.PublicTokenInfo.lastAccessedTime` — different field names for "last use" -- **Why weird:** Same concept, two field names: `lastUsedDay` (admin, `model.ts:23`) vs `lastAccessedTime` (per-user). Different unit precision too. Already partially covered in #8 but worth its own bullet for cross-package consistency. -- **Category:** 12 (duplicate concept across packages), 17 (inconsistent verb — used vs accessed). -- **Suggested name:** Align to one. Recommend `lastUsedTime` everywhere; "accessed" is a synonym but inconsistent. -- **Rationale:** Cross-package consistency. - -### 13. `comment` field — vague, overloaded between SDK comment vs DDL comment vs user note -- **Why weird:** Two user-facing types have a `comment: string` field (`AdminTokenInfo.comment` at `model.ts:13`, `CreateOnBehalfOfTokenRequest.comment` at `model.ts:33`). JSDoc says "Comment that describes the purpose of the token" — i.e., a description. Yet the field is called `comment`, which in TS/JS conjures up code comments. Same SQL-DDL leak as in `abacpolicies`. -- **Category:** 6 (misleading — `comment` is overloaded), 14 (SQL-DDL-style naming). -- **Suggested name:** `description` (matches the JSDoc). -- **Rationale:** SQL DDL uses `COMMENT ON ...`; SDK consumers don't. `description` is the standard noun. - -### 14. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name +### 8. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name - **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:27`. Industry shorthand is "OBO" but the SDK avoids the acronym. - **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). - **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. - **Rationale:** This is the only operation in the package whose name relies on the preposition; surfacing the intent (mint a token for someone else) helps. Defensible as-is. -### 15. `tokenValue` is a secret but the field name doesn't hint at it -- **Why weird:** The `tokenValue: string` field on `CreateOnBehalfOfTokenRequest_Response` (`model.ts:41`). This is the bearer token plaintext, returned exactly once. The field name `tokenValue` doesn't signal "this is a secret; persist immediately; we will never return it again". Compare with cryptographic SDKs that name such fields `secret`, `tokenSecret`, or `bearerToken`. -- **Category:** 1 (vague), 6 (misleading — `value` is the most generic suffix imaginable for the most sensitive field in the package). -- **Suggested name:** `tokenSecret` or `bearerToken`, and add a JSDoc warning ("Returned once. Store immediately."). -- **Rationale:** Defensive naming for security-critical fields helps users not log/leak the value. - ## Low severity -### 16. `Client` class is named `Client` (no namespacing) +### 9. `Client` class is named `Client` (no namespacing) - **Why weird:** `export class Client` (`client.ts:44`). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. - **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). - **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). - **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. -### 17. `host` field on `Client` — workspace URL is more specific -- **Why weird:** `private readonly host: string;` (`client.ts:45`). The constructor accepts `options.host` which is actually the workspace URL (e.g., `https://my-workspace.cloud.databricks.com`). "Host" is HTTP-level jargon; `workspaceUrl` is the domain-level term users learn first. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `workspaceUrl` (and `options.workspaceUrl`). -- **Rationale:** This is a shared concern across all generated clients; flagged here as it appears in this client. - -### 18. `PACKAGE_SEGMENT` constant — vague label +### 10. `PACKAGE_SEGMENT` constant — vague label - **Why weird:** `const PACKAGE_SEGMENT = {...}` (`client.ts:39`). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `USER_AGENT_PKG`. - **Rationale:** Minor; identical issue in every generated package. -### 19. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory +### 11. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory - **Why:** The package's directory and npm name `tokenmanagement` ends in `management`, which sits in the `Manager`/`Handler`/`Controller`/`Processor` family of architectural-tier suffixes. The package does not contain a "management" concept; it contains operations on tokens (list, get, create-on-behalf-of, delete). The `-management` suffix is service-side scaffolding language (cf. proto `TokenManagementService`) that leaks out via the URL path `/api/2.0/token-management/...` and into the SDK package name. Compare to peers in the SDK where the action package is named after the domain noun (`tokens`, `clusters`, `secrets`), not the service tier. - **Category:** Proto-architectural-leak — `Manager`/`Handler`/`Controller`/`Processor`/`-management` family (architectural label not in the domain). - **Suggested:** `tokenadmin` — keeps the audience-disambiguation from sibling `tokens` but uses an audience noun rather than an architectural verb. See finding #1 which proposes the same package rename for the collision-avoidance reason. @@ -152,7 +104,6 @@ _None._ - **Different entity name:** `AdminTokenInfo` (this package) vs `PublicTokenInfo` (`tokens` package). - **Different create operation:** `createOnBehalfOfToken` (admin) vs `createToken` (per-user). - **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #3. -- **Different `lastUsed` field:** `lastUsedDay` (admin) vs `lastAccessedTime` (per-user) — flagged in findings #8/#11. - **Different URL prefix:** `/api/2.0/token-management/...` vs `/api/2.0/token/...`. The two packages are conceptual siblings (PAT lifecycle) split by audience (admin-of-others vs self), but the SDK surface is split inconsistently — naming, return types, and method verbs diverge for no obvious reason. Worth raising at the SDK-design level. @@ -162,12 +113,3 @@ The two packages are conceptual siblings (PAT lifecycle) split by audience (admi - `src/v1/client.ts` (185 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (18 lines): read fully. - -## Fixed -- #2 `AutoscopeState` enum values (originally cited at `src/v1/model.ts:13-21`): Fixed in regeneration on 2026-05-20 — enum removed entirely from the package. -- #4 `CreateOnBehalfOfToken` / `GetToken` / `ListTokens` / `RevokeToken` / `UpdateToken` verb-phrase type names (originally cited at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — all request DTOs now carry a `Request` suffix (`CreateOnBehalfOfTokenRequest`, `GetTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`). -- #6 `UpdateToken.token: AdminTokenInfo` field (originally cited at `src/v1/model.ts` + `src/v1/client.ts:191`): Fixed in regeneration on 2026-05-20 — `UpdateToken` request type and `updateToken` client method were removed from the package. -- #7 `client.updateToken` returns `AdminTokenInfo` (originally cited at `src/v1/client.ts:190`): Fixed in regeneration on 2026-05-20 — `updateToken` method removed; cross-package return-shape divergence no longer present here. -- #10 `PAT` acronym never appears, autoscope comments reference it tacitly (originally cited at `src/v1/model.ts:8`): Fixed in regeneration on 2026-05-20 — `AutoscopeState` and its `PAT`-referencing doc comment were removed; no remaining cryptic comment-only reference. -- #13 `scopes` / `autoscopeState` / `autoscopeEnabled` triplet inconsistency (originally cited at `src/v1/model.ts`): Fixed in regeneration on 2026-05-20 — `autoscopeState` and `autoscopeEnabled` fields removed; only `scopes` remains on `CreateOnBehalfOfTokenRequest`. -- #18 `autoscopeEnabled` on request vs `autoscopeState` on response (originally cited at `src/v1/model.ts:57`): Fixed in regeneration on 2026-05-20 — both autoscope fields removed from the package. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index 6cd61d04..e793a81e 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -3,13 +3,13 @@ **Path:** `packages/tokens/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share a near-identical "token info" record, but the auth/audience boundary makes them distinct services. -**Total weird names flagged:** 22 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | | High | 5 | -| Medium | 7 | +| Medium | 5 | | Low | 6 | | Observation | 4 | @@ -49,18 +49,12 @@ ### 5. Proto-architectural-leak: `Foo_Response` underscored nested response types — `model.ts:21, 32, 54` - **Why weird:** The package defines `CreateTokenRequest_Response`, `ListTokensRequest_Response`, and `RevokeTokenRequest_Response` — names that bake the Protobuf nested-message convention (`OuterMessage_InnerMessage`) directly into the public TypeScript surface. The underscore is a transport-format artefact (a Go/proto idiom for nested message types), not a TypeScript naming convention. Each declaration is even guarded with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` — the codebase already knows these names violate TS conventions. The pattern matches the user's `Foo_PublicRequest` rule: a transport-layer naming structure leaking into the SDK's published types. Also propagates through `index.ts:9,11,14`, `client.ts:22,24,26,34,35,36,79,108,137,152`, and the schema names `unmarshal*Request_ResponseSchema` (`model.ts:68, 80, 106`). - **Category:** Proto-architectural leak (transport-format identifier shape in public TS surface). -- **Suggested name:** Drop the underscore-nested form and use idiomatic TS response-type names: `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse` (the existing `UpdateTokenResponse` on `model.ts:65` already follows this pattern, so the package is internally inconsistent — see #6). +- **Suggested name:** Drop the underscore-nested form and use idiomatic TS response-type names: `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse` (the existing `UpdateTokenResponse` on `model.ts:65` already follows this pattern, so the package is internally inconsistent). - **Rationale:** Public TS APIs should not advertise the wire/proto provenance of a type. Mixing `UpdateTokenResponse` (clean) with `CreateTokenRequest_Response` (proto-style underscore) in the same module signals that the generator is mechanically translating proto nested-message names rather than producing idiomatic TS. The `eslint-disable` annotation in source is direct evidence that the names break the project's own lint rules. ## Medium severity -### 6. `CreateTokenRequest.lifetimeSeconds` — unit smuggled into name, not type — `model.ts:13` -- **Why weird:** `lifetimeSeconds?: number | undefined`. Unit (seconds) lives in the field name, not the type. The doc says "in seconds". TS has no native duration type, so a unit-bearing field name is conventional, but the rest of the package uses `*Time` (`creationTime`, `expiryTime`) which are *epoch milliseconds* (verified by doc strings on `model.ts:40-43`). Same `number` type, two different units, two different naming conventions. -- **Category:** 15 (unit-bearing field-name vs typed wrapper), 13 (intra-package inconsistency — `lifetimeSeconds` vs `creationTime`). -- **Suggested name:** Acceptable as-is, but consider `lifetimeMs` (or `lifetime: Duration`) for parity with `creationTime` etc. The Temporal API (`@js-temporal/polyfill` is already a package.json dep) has `Temporal.Duration` which would be domain-correct. -- **Rationale:** Within one struct, two number fields use different time units. Caller must read docs to avoid bugs. - -### 7. `UpdateTokenRequest.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:57` +### 6. `UpdateTokenRequest.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:57` - **Why weird:** Doc on `UpdateTokenRequest.tokenId`: "The SHA-256 hash of the token to be updated." But every other `tokenId` doc in the package (and in `tokenmanagement`) says variants of "The ID of the token". So readers comparing the types see: - `CreateTokenRequest_Response.tokenInfo.tokenId` (line 25 → `PublicTokenInfo.tokenId` line 39) — "The ID of this token." - `PublicTokenInfo.tokenId` (line 39) — "The ID of this token." @@ -70,19 +64,13 @@ - **Suggested name:** Either (a) reconcile the docs — if `tokenId` is the SHA-256 hash everywhere, say so consistently; or (b) if `UpdateTokenRequest.tokenId` actually expects a different format than the others, rename or document the divergence loudly. - **Rationale:** The doc disagreement implies either a stale comment or a real wire-protocol quirk. Either way, a caller can't tell which. -### 8. `UpdateTokenRequest.token` field name shadows the package name — `model.ts:59` -- **Why weird:** `UpdateTokenRequest.token?: PublicTokenInfo`. The field `token` inside the type `UpdateTokenRequest` in the package `tokens` carries the entire updated payload. Reads `updateReq.token.tokenId` — the word "token" appears three times in five characters. The same package has `Client.updateToken` method which takes `UpdateTokenRequest` which has a `token` field of type `PublicTokenInfo`. Layer cake. -- **Category:** 20 (type-suffix tautology), 1 (vague). -- **Suggested name:** Field as `info` (since the inner type is `PublicTokenInfo`/`TokenInfo`) or `data`. Wire stays `token`. So `updateReq.info.tokenId`. -- **Rationale:** The wire field is `token` because the proto message wraps a `TokenInfo`; in TS, the field name can clarify intent without changing the wire. - -### 9. `UpdateTokenRequest` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:56-62` +### 7. `UpdateTokenRequest` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:56-62` - **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:171`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenRequestSchema` on `model.ts:146-159`). - **Category:** 12 (duplicate concept), 6 (misleading — which one is authoritative?), 11 (the inner one is dead-ish data). - **Suggested name:** Drop one. Either: (a) make `token` exclude `tokenId` (`Omit`) and keep the top-level; or (b) drop the top-level and use `req.token.tokenId` in the client. - **Rationale:** Two fields for the same identifier invite subtle bugs (server may pick the inner one if the top-level is empty). -### 10. `Client` class name — colliding namespace — `client.ts:46` +### 8. `Client` class name — colliding namespace — `client.ts:46` - **Why weird:** Top-level class literally named `Client`. Re-exported in `index.ts` as just `Client`. A consumer importing from both `@databricks/sdk-tokens/v1` and `@databricks/sdk-tokenmanagement/v1` faces an identical name clash: ``` import {Client} from '@databricks/sdk-tokens/v1'; @@ -93,13 +81,13 @@ - **Suggested name:** `TokensClient`, `UserTokensClient`, or `MyTokensClient`. Mirror with `TokenManagementClient`/`AdminTokensClient`. - **Rationale:** Same finding as `rfa#37`, recurs across all packages — but particularly painful here given the `tokens`/`tokenmanagement` overlap. -### 11. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` +### 9. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site (`client.ts:87,115` use them within four lines of each other). - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Cross-package: same as `rfa#32`, recurs everywhere. -### 12. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` +### 10. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` - **Why weird:** The file imports `Options` from `@databricks/sdk-core/api` (line 3) and `CallOptions` from `@databricks/sdk-options/call` (line 12). Three `Options`-suffixed types in scope. `HttpCallOptions` is internal — purely a context bag passed to `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -107,37 +95,37 @@ ## Low severity -### 13. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:168` +### 11. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:168` - **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateTokenRequest` payloads must learn this helper. -- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #19 re-export gap). +- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #17 re-export gap). - **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. - **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. -### 14. `readAll` — generic helper name — `utils.ts:40` +### 12. `readAll` — generic helper name — `utils.ts:40` - **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Same as `rfa#34`. -### 15. `flattenQueryParams` — `utils.ts:123` +### 13. `flattenQueryParams` — `utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` only ever builds JSON bodies). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if it's a generator default; or keep, but stop emitting it for body-only services. - **Rationale:** Same as `rfa#35`. -### 16. `PACKAGE_SEGMENT` constant — `client.ts:41` +### 14. `PACKAGE_SEGMENT` constant — `client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same as `rfa#36`. -### 17. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` +### 15. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` - **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,114,144,177` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). - **Category:** 1 (vague — five-positional builder). - **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. - **Rationale:** Same as `rfa#38`. -### 18. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` +### 16. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` - **Why weird:** Local `opts` variable is one letter shorter than the parameter `options` to disambiguate. The shadowing convention isn't documented. - **Category:** Observation. - **Suggested name:** Rename inner `opts` → `internalOptions`. @@ -145,16 +133,16 @@ ## Observations -### 19. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper +### 17. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper The index file exports the `Client` and eight model interfaces (`CreateTokenRequest`, `CreateTokenRequest_Response`, `ListTokensRequest`, `ListTokensRequest_Response`, `PublicTokenInfo`, `RevokeTokenRequest`, `RevokeTokenRequest_Response`, `UpdateTokenRequest`, `UpdateTokenResponse`). It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. -### 20. `package.json` description is empty string — `package.json:4` +### 18. `package.json` description is empty string — `package.json:4` `"description": ""`. The npm package has no public description string. Combined with the ambiguous `tokens` name (see #1) and the parallel `tokenmanagement` package, this leaves users without any registry-level metadata to disambiguate the two packages. -### 21. No tests in the package +### 19. No tests in the package `package.json` line 25-26: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees deserve a contract test. -### 22. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:171` +### 20. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:171` `const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:58`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. ## Domain glossary @@ -170,13 +158,4 @@ The index file exports the `Client` and eight model interfaces (`CreateTokenRequ - `src/v1/client.ts` (192 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (18 lines): read fully. -- Cross-referenced `packages/tokenmanagement/src/v1/` for overlap analysis (see findings #1, #3, #4, #9). - -## Fixed -- #2 `AutoscopeState` shared-enum duplication (originally cited at `model.ts:13-21`): Fixed in regeneration on 2026-05-20 — the `AutoscopeState` enum is no longer defined in the `tokens` package. -- #3 `AUTOSCOPE_STATE_*` redundant enum prefix (originally cited at `model.ts:14-20`): Fixed in regeneration on 2026-05-20 — `AutoscopeState` enum removed from this package. -- #7 Request types missing `Request` suffix (originally cited at `model.ts:50, 79`): Fixed in regeneration on 2026-05-20 — request DTOs are now `CreateTokenRequest`, `ListTokensRequest`, `RevokeTokenRequest`, `UpdateTokenRequest`. -- #10 `CreateToken.autoscopeEnabled` boolean-vs-enum asymmetry (originally cited at `model.ts:38`): Fixed in regeneration on 2026-05-20 — the `autoscopeEnabled` field was dropped from `CreateTokenRequest`. -- #11 `PublicTokenInfo.scopes` doc grammar singular/plural mismatch (originally cited at `model.ts:67-68`): Fixed in regeneration on 2026-05-20 — the `scopes` field was removed from `PublicTokenInfo`. -- #12 Three overlapping scope-array fields on `PublicTokenInfo` (originally cited at `model.ts:73-76`): Fixed in regeneration on 2026-05-20 — `inferredScopes` and `backfillScopes` fields were removed from `PublicTokenInfo`. -- #28 Doc comments leaking proto file paths (originally cited at `model.ts:7-12`): Fixed in regeneration on 2026-05-20 — the `AutoscopeState` doc block containing the proto-tree path was removed when the enum left the package. +- Cross-referenced `packages/tokenmanagement/src/v1/` for overlap analysis (see findings #1, #3, #4, #7). diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 99c1c8bf..41607af0 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -138,6 +138,3 @@ There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The - `src/v1/client.ts` (136 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (13 lines): read fully. - -## Fixed -_None._ diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md index 2bb9d277..d0be2fab 100644 --- a/.agent/naming-audit/usagepolicy.md +++ b/.agent/naming-audit/usagepolicy.md @@ -3,13 +3,13 @@ **Path:** `packages/usagepolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). -**Total weird names flagged:** 35 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 12 | +| High | 4 | +| Medium | 9 | | Low | 10 | | Observation | 5 | @@ -33,105 +33,63 @@ - **Suggested name:** Fix the JSDoc to either point at the real successor or drop the migration hint. - **Rationale:** A new-language SDK should not inherit other-language migration warts on day one, and the warning is broken because the documented successor doesn't exist in this package's `UsagePolicy`. -### 4. `CreateUsagePolicyRequest.requestId` documented as idempotency-ish key — `src/v1/model.ts:14-21` -- **Why weird:** JSDoc: "A unique identifier for this request. Restricted to 36 ASCII characters." — `requestId` is a vague field name that does not signal "idempotency key" to callers. The doc says nothing about idempotency (unlike `budgetpolicy`'s `CreateBudgetPolicyRequest.requestId` doc at `packages/budgetpolicy/src/v1/model.ts:37-42` which explicitly mentions idempotency). The semantic is unclear: trace id? correlation id? idempotency key? -- **Category:** 1 (vague — `requestId` could mean anything), 15 (generic field name losing meaning), 17 (inconsistent across sibling packages — sibling spells out idempotency, this one doesn't). -- **Suggested name:** `idempotencyKey` (matches Stripe/Square/most REST APIs) and expand the JSDoc to clarify semantics. -- **Rationale:** Sibling-package divergence is worse than either choice alone: a caller flipping between `usagepolicy` and `budgetpolicy` cannot rely on identical semantics for the same-named field. Either both packages should call it `idempotencyKey` or both `requestId`, and both docs should state idempotency. - -### 5. `UsagePolicy.policyId` / `UsagePolicy.policyName` field naming inside `UsagePolicy` type — `src/v1/model.ts:123,125` -- **Why weird:** Fields on the `UsagePolicy` type prefix every field with `policy*` (`policyId`, `policyName`). When you already have `policy.policyId` and `policy.policyName`, the `policy` prefix is redundant. -- **Category:** 8 (redundant prefix when context already supplies it), 20 (type-suffix tautology — `policyId` of type `UsagePolicy.id` is `policyId`). -- **Suggested name:** `id`, `name` (the wire stays `policy_id`/`policy_name`). -- **Rationale:** `usagePolicy.id` reads better than `usagePolicy.policyId`. The redundancy is a Go SDK habit where flat structs need the prefix to differentiate; TS doesn't. Mirrors `budgetpolicy` finding #9. - -### 6. `UsagePolicy.bindingWorkspaceIds` — `src/v1/model.ts:129` -- **Why weird:** `binding` as a noun-prefix reads as "workspace IDs of a binding". JSDoc: "List of workspaces that this usage policy will be exclusively bound to." The natural name is `boundWorkspaceIds` (past participle, indicating the relationship has already been set up). Additionally, the JSDoc here is shorter than in `budgetpolicy` (which adds "An empty binding implies that this budget policy is open to any workspace in the account.") — the empty-binding semantic is silently dropped from `usagepolicy`, creating yet another inter-package documentation divergence. -- **Category:** 1 (vague — `binding` is generic: data binding, key binding, etc.), 6 (misleading word choice — "binding" implies a binding object exists), 17 (inconsistent doc across siblings). -- **Suggested name:** `boundWorkspaceIds` or `workspaceIds`. -- **Rationale:** "Bound" is the past participle that matches the doc ("will be exclusively bound to"). `binding` reads as a separate entity. - -### 7. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` +### 4. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` - **Why weird:** Workspace IDs are typed as `number[]`. Databricks workspace IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so workspace IDs `>2^53` will silently lose precision. Same problem on `Filter.creatorUserId: number` (line 57). - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). - **Suggested name:** `bindingWorkspaceIds: bigint[]` or `string[]` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Generator/policy issue across the SDK. Worth flagging at every usage site. -### 8. Filter operator semantics undocumented — `src/v1/model.ts:47-63` -- **Why weird:** The `Filter` type has three optional fields whose names imply singular match (`policyName`, `creatorUserId`, `creatorUserName`), but the JSDoc on `policyName` says "The partial name of policies to be filtered on" — implying substring match. The other two fields don't document their operator (equality? prefix? substring?). When multiple fields are set, the JSDoc on the type says "All specified filters will be applied in conjunction" — i.e. AND — but the per-field docs each repeat "If unspecified, all policies will be returned", which is confusing in the presence of the conjunction rule. -- **Category:** 6 (misleading — singular noun for what is likely a substring/multi-match filter), 1 (vague — no operator spelled in the name). -- **Suggested name:** `policyNameContains`, `creatorUserIdEquals`, `creatorUserNameContains` (or pluralise to lists where appropriate). -- **Rationale:** Filter DSLs benefit from explicit operators. Bare singular names with conjunction semantics buried in the type JSDoc force readers to puzzle through three short paragraphs to know what "set both fields" actually does. Mirrors `budgetpolicy` finding #14. - ## Medium severity -### 9. `CustomPolicyTag` type name — `src/v1/model.ts:23` +### 5. `CustomPolicyTag` type name — `src/v1/model.ts:23` - **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. Also colliding with the same `CustomPolicyTag` exported from `budgetpolicy/src/v1/model.ts:53`. - **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location), 12 (duplicate concept across siblings with identical name). - **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. - **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". -### 10. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` +### 6. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling **from the budget-policy domain** — copy-pasted verbatim from the `budgetpolicy` package without renaming to the usage-policy equivalents (one would expect `usage-policy-name` etc.). Either (a) the wire really *does* use the `budget-policy-*` prefix (which is a Databricks API design issue worth surfacing), or (b) the JSDoc was lazily duplicated and the actual reserved keys are different. - **Category:** 6 (misleading: cross-domain magic strings that callers must memorise), 12 (duplicate across siblings — but here it's a *bug*, because the reserved keys are not surfaced as constants and may differ from `budgetpolicy`), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate the wire payload and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Either way the verbatim duplication smells. -### 11. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` +### 7. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Same as finding #7 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. - -### 12. `Filter.creatorUserId` + `Filter.creatorUserName` — two ways to filter on the same creator — `src/v1/model.ts:57,62` -- **Why weird:** Same conceptual entity (the creator) exposed twice as two filter fields, with no doc clarification on whether they are AND or OR. `creatorUserId` is `number`, `creatorUserName` is `string`. -- **Category:** 12 (duplicate concept), 19 (underspecified id), 6 (misleading — caller wonders which one to use). -- **Suggested name:** Collapse to `creator?: {id?: number; name?: string}`, or split into named composite types. -- **Rationale:** Two parallel "filter by creator" fields beg the question of how they combine, and the per-field doc ("If unspecified, all policies will be returned") fails to define the AND/OR rule between them. +- **Rationale:** Same as finding #4 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. -### 13. `SortSpec` type — `src/v1/model.ts:103` +### 8. `SortSpec` type — `src/v1/model.ts:103` - **Why weird:** `SortSpec` (specification) and `Field` together build the "what to sort by" structure. `Spec` is generic — every type is a spec of something. The wrapping type holds two fields (`field` + `descending`); a one-or-two-field pair could be inlined into the request. - **Category:** 1 (vague suffix `Spec`), 11 (trivial wrapper holding two fields). - **Suggested name:** `SortOptions`, or inline as `sortField?: SortField; sortDescending?: boolean` on the request. - **Rationale:** `Spec` adds no information. `sortBy: SortField` plus a boolean is more direct. Mirrors `budgetpolicy` finding #17. -### 14. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:104` +### 9. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:104` - **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. - **Category:** Observation (typo). - **Suggested name:** Fix spelling. - **Rationale:** Surfaces in IntelliSense. Same typo as `budgetpolicy/src/v1/model.ts:150` — the two packages even share generator typos. -### 15. `ListUsagePoliciesResponse.policies` field name — `src/v1/model.ts:96` -- **Why weird:** Field `policies` of type `UsagePolicy[]`. Within the `usagepolicy` package, `policies` is fine — but within a multi-package consumer with `budgetpolicy.policies` and other policy-emitting packages, the bare name is ambiguous when copy-pasted. -- **Category:** 1 (vague when out of context), 9 (singular/plural — paired with `policy:` field on the create/update requests), 12 (duplicate field name across siblings). -- **Suggested name:** `usagePolicies: UsagePolicy[]`. -- **Rationale:** Tied to type rename considerations. If the entity-type were renamed (per finding #1), `policies` could stay; otherwise `usagePolicies` makes the field self-documenting at any depth. - -### 16. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` +### 10. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` - **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but the iterator helper only walks forward. The bidirectional surface area exists but is unused by the iterator helper. - **Category:** Observation / 12 (duplicate-but-asymmetric concept). - **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. - **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. Mirrors `budgetpolicy` finding #20. -### 17. `UsagePolicy.customTags` plural field paired with singular `CustomPolicyTag` type — `src/v1/model.ts:127` -- **Why weird:** Plural field `customTags: CustomPolicyTag[]` plus the singular type with `Tag` suffix produces `customTags: CustomPolicyTag[]` — same word twice (`Tags`/`Tag`). -- **Category:** 8 (redundant prefix `custom`), 20 (`customTags: CustomPolicyTag[]` is type-suffix tautology). -- **Suggested name:** `tags: Tag[]` (with type rename per #9). Wire form stays `custom_tags`. -- **Rationale:** Linked to the type-rename above; if `CustomPolicyTag` becomes `Tag`, field naturally becomes `tags`. - -### 18. `CreateUsagePolicyRequest.policy` field with wire-name leak in JSDoc — `src/v1/model.ts:19-20` +### 11. `CreateUsagePolicyRequest.policy` field with wire-name leak in JSDoc — `src/v1/model.ts:19-20` - **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated" — wire-name leak (`policy_id`) in the docs of a TS field. Also: the doc is *shorter* than the sibling `budgetpolicy.CreateBudgetPolicyRequest.policy` doc (which adds: "`policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional."). So the usage-policy version silently drops the "policyName must be provided" and the cloud-provider-conditional tag note. - **Category:** 14 (wire-style identifiers in TS docs), 17 (inconsistent docs across sibling packages for the same conceptual request). - **Suggested name:** Fix the doc to reference TS field names; align with sibling-package doc content. - **Rationale:** Editing UX: hovers should show TS, not proto. The sibling-divergence also matters: a developer reading both packages should see consistent requirements unless they actually differ. -### 19. `UpdateUsagePolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:112` +### 12. `UpdateUsagePolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:112` - **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `UsagePolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. Exact same bug as `budgetpolicy.UpdateBudgetPolicyRequest.policy` JSDoc. - **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `UsagePolicy`, model says otherwise), 14 (Go-SDK paste from a richer struct). - **Suggested name:** Fix doc; remove the spurious reference or add the missing field to the model. - **Rationale:** Real bug, twice (once here, once in `budgetpolicy`). -### 20. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` +### 13. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` - **Why weird:** `budgetpolicy.UpdateBudgetPolicyRequest` (`packages/budgetpolicy/src/v1/model.ts:165`) carries an `updateMask?: FieldMask` plus a `budgetPolicyFieldMask(...paths)` builder. `usagepolicy.UpdateUsagePolicyRequest` does not. Either (a) the usage-policy API genuinely uses replace-on-PATCH semantics (no partial updates) — in which case the JSDoc should say so — or (b) the SDK is missing field-mask support that the API offers. Without inspection of the OpenAPI source, either is plausible, and the absence of a doc note is itself a finding. - **Category:** 17 (inconsistency across near-clone sibling packages), Observation (potential missing surface). - **Suggested name:** If full-replace: document on `UpdateUsagePolicyRequest`. If partial-update: add `updateMask?: FieldMask` and a `usagePolicyFieldMask(...paths)` helper to match the sibling. @@ -139,61 +97,61 @@ ## Low severity -### 21. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 14. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handle different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in `abacpolicies` and `budgetpolicy` audits. Generator-wide. -### 22. `HttpCallOptions` — `src/v1/utils.ts:15` +### 15. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide; same as `budgetpolicy` finding #29. -### 23. `readAll` — `src/v1/utils.ts:40` +### 16. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 24. `flattenQueryParams` — `src/v1/utils.ts:123` +### 17. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,217` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package (12+ identical copies in this monorepo). - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 25. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 18. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Same as `budgetpolicy` finding #33; generator-wide. -### 26. `Client` class plain name — `src/v1/client.ts:46` +### 19. `Client` class plain name — `src/v1/client.ts:46` - **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-usagepolicy/v1`, they will almost certainly alias it (`import {Client as UsagePolicyClient}`) to avoid collision with `Client` from every other package — including the byte-identical class from `@databricks/sdk-budgetpolicy/v1`. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages, *especially* this one and `budgetpolicy`). - **Suggested name:** `UsagePolicyClient`. - **Rationale:** Each generated package emits a `Client`. With `usagepolicy`/`budgetpolicy` being near-clones, the importer who needs both will be forced into double-aliasing. -### 27. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 20. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` - **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. Same as `budgetpolicy` finding #35. -### 28. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` +### 21. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` - **Why weird:** "it's" should be "its" (possessive). Same grammatical mistake appears in `budgetpolicy/src/v1/client.ts:120` ("Retrieves a policy by it's ID.") — copy-pasted across the clones. - **Category:** Observation (grammar). - **Suggested name:** Fix to "its". - **Rationale:** Surfaces in editor hovers; small but persistent. -### 29. `SortSpec_Field` proto-style underscore-nested enum name — `src/v1/model.ts:6` +### 22. `SortSpec_Field` proto-style underscore-nested enum name — `src/v1/model.ts:6` - **Why weird:** Underscored identifier `SortSpec_Field` mirrors protobuf's "ParentMessage_NestedEnum" wire convention and is unidiomatic in TypeScript. The file even carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.` on line 5, confirming the proto-architectural leak. Re-exported from `index.ts:5` so the leak reaches consumers verbatim. - **Category:** Proto-architectural leak — proto-nested-type naming convention surfaced into the TS public API. - **Suggested name:** `SortField` (or namespace it under `SortSpec` as `SortSpec.Field` if the nesting relationship matters). - **Rationale:** TS has no `Parent_Nested` convention; the underscore is a direct proto leak. Mirrors the same finding in `budgetpolicy` (`SortSpec_Field` at `budgetpolicy/src/v1/model.ts:8`). -### 30. `buildHttpRequest` — `Http` mid-position infix — `src/v1/utils.ts:96` +### 23. `buildHttpRequest` — `Http` mid-position infix — `src/v1/utils.ts:96` - **Why weird:** `Http` appears as a mid-position infix between the verb `build` and the noun `Request`. The function's role is "construct an `HttpRequest` value", but the `Http` infix in the function name redundantly leaks the transport layer into the verb. Same pattern in the imported `HttpRequest` type is fine (end suffix), but on the function it duplicates information already in the return type. - **Category:** Proto-architectural leak — transport-layer noun appearing mid-name. - **Suggested name:** `buildRequest` (return type `HttpRequest` already conveys the transport). @@ -201,23 +159,23 @@ ## Observations -### 31. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference +### 24. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. - **Category:** 12 (duplicate concept), 1 (vague package boundary). -### 32. No `FieldMask` import in `usagepolicy/src/v1/model.ts` -Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #20 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. +### 25. No `FieldMask` import in `usagepolicy/src/v1/model.ts` +Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #13 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. - **Category:** Observation / 17 (cross-package inconsistency). -### 33. Action-verb conventions in `Client` +### 26. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 34. Acronym casing `Id` consistently used as `Id`, not `ID` +### 27. Acronym casing `Id` consistently used as `Id`, not `ID` `policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). - **Category:** 3 (observation — internal acronym style is consistent). -### 35. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) +### 28. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) The same identifier appears in three forms in the same client file: - `usage_policies` — wire form (in the Zod schemas via snake_case keys). - `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). @@ -229,7 +187,7 @@ Readers must mentally translate. Worth flagging because the kebab-case form does ## Domain glossary - `usage policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. Same structure as `budgetpolicy.BudgetPolicy` per the JSDoc on `UsagePolicy` (line 120). Despite "usage" in the name, no usage-data concept (rows/metrics/period) lives on the model — only tags and workspace bindings. - `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `UsagePolicy.bindingWorkspaceIds: number[]`. -- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #10). +- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #6). - `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.1/accounts/{accountId}/usage-policies`). - `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md index b4eefbd3..8b450995 100644 --- a/.agent/naming-audit/vectorsearch.md +++ b/.agent/naming-audit/vectorsearch.md @@ -4,23 +4,22 @@ **Versions audited:** v1 **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` **Inferred domain:** Databricks AI/Vector Search — endpoint management (create, get, list, patch, delete, budget-policy patch) and vector-index management (create, get, list, query, query-next-page, scan, sync, upsert-data, delete-data, delete). Routes under `/api/2.0/vector-search/endpoints` and `/api/2.0/vector-search/indexes`. Hosts a single `Client` with mixed endpoint and index methods plus a single `CreateEndpointWaiter`. -**Total weird names flagged:** 27 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | ------------ | ----- | -| High | 7 | -| Medium | 10 | -| Low | 7 | +| High | 6 | +| Medium | 6 | +| Low | 4 | | Observation | 3 | -| **Total** | **27** | +| **Total** | **19** | Dominant themes: 1. **Two resource families share one flat `Client`.** Endpoint methods (`createEndpoint`, `getEndpoint`, …) and index methods (`createVectorIndex`, `queryVectorIndex`, …) sit side by side on the same class. The result is long method names that re-encode the resource family (`createVectorIndex` instead of `client.indexes.create()`), plus a single waiter that only covers endpoints. -2. **`name` is the wire identifier for both endpoints and indexes.** Across both resource families, `name?: string` is the path-segment identifier in URLs while the JSDoc just says "Name of the index" / "Name of the AI Search endpoint" — leaving the format (UC three-part name? user-chosen string?) implicit. The same field shape recurs on every request type. -3. **`Endpoint` is a Databricks-wide overloaded noun.** Bare `Endpoint`, `EndpointType`, `EndpointStatus`, `EndpointScalingInfo` collide with `modelserving.InferenceEndpoint`, `warehouses.EndpointState`, and other "endpoint" concepts. The package name `vectorsearch` qualifies the import, but destructured types lose that context. -4. **Near-duplicate types.** `VectorIndex` ≡ `MiniVectorIndex` (identical field set), `DeltaSyncVectorIndexSpec` ≡ `DeltaSyncVectorIndexSpecRequest` (identical field set). The duplication is gratuitous given that `DirectAccessVectorIndexSpec` has no `Request` twin. +2. **`Endpoint` is a Databricks-wide overloaded noun.** Bare `Endpoint`, `EndpointType`, `EndpointStatus`, `EndpointScalingInfo` collide with `modelserving.InferenceEndpoint`, `warehouses.EndpointState`, and other "endpoint" concepts. The package name `vectorsearch` qualifies the import, but destructured types lose that context. +3. **Near-duplicate types.** `VectorIndex` ≡ `MiniVectorIndex` (identical field set), `DeltaSyncVectorIndexSpec` ≡ `DeltaSyncVectorIndexSpecRequest` (identical field set). The duplication is gratuitous given that `DirectAccessVectorIndexSpec` has no `Request` twin. --- @@ -56,13 +55,7 @@ Dominant themes: - **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec` used in both request and response positions, mirroring `DirectAccessVectorIndexSpec`), or document the planned divergence prominently. - **Rationale:** The mismatch with `DirectAccessVectorIndexSpec` (no `Request` twin) shows the duplication is gratuitous. Users serializing a `DeltaSyncVectorIndexSpec` for a create call have to discover that `*Request` is the right one only by reading the function signature. -### 6. `name?: string` is the resource identifier across every request type — `model.ts:98, 115, 147, 161, 169, 254, 269, 276, 323, 328, 339, 378, 403, 416, 427, 436, 512, 534, 542, 574` -- **Why weird:** Twelve+ request types use a bare `name?: string` for what is actually the resource identifier consumed by the URL (`/endpoints/${name}`, `/indexes/${name}`, `/indexes/${name}/query`, …). For indexes, the value is a three-part Unity Catalog qualified name (`..`); for endpoints, it is a user-chosen string. Neither distinction is documented on the field. JSDoc on each one just says "Name of the index" or "Name of the AI Search endpoint" without spelling out the format expectation. -- **Category:** 15 (generic field name losing meaning), 19 (underspecified ID), 6 (misleading — `name` reads like a label but is the primary key). -- **Suggested name:** For request types, rename to `endpointName` / `indexName` (already partial precedent — `MiniVectorIndex.endpointName`, `ListVectorIndexRequest.endpointName`). For the model types (`Endpoint.name`, `VectorIndex.name`), at minimum document the value's format in JSDoc. -- **Rationale:** `name` is too generic for a path-segment identifier. Users will mis-construct the value (e.g. send a bare index name instead of a three-part UC name) and see a 404. - -### 7. `EndpointStatus_State.OFFLINE` is a terminal-failure state but reads as transient — `model.ts:72`, `client.ts:641-644, 680-681` +### 6. `EndpointStatus_State.OFFLINE` is a terminal-failure state but reads as transient — `model.ts:72`, `client.ts:641-644, 680-681` - **Why weird:** The waiter's terminal-state switch (`client.ts:637-647`) treats `EndpointStatus_State.OFFLINE` as a *failure* and throws. The enum identifier "OFFLINE" however reads as a transient lifecycle state ("the endpoint is currently offline"), implying it might come back online. JSDoc on the enum value is absent; the only hint is in the comment block above `RED_STATE`/`YELLOW_STATE`. A reader inspecting the enum would not predict that the waiter throws on OFFLINE. - **Category:** 6 (misleading), 16 (field type contradicts domain — lifecycle name implies transient, runtime semantics are terminal). - **Suggested name:** If the wire allows, rename to `FAILED` or `TERMINATED` to match the runtime semantics. Otherwise, add JSDoc on `OFFLINE` clarifying that it is a terminal failure state, distinct from "temporarily not serving traffic". @@ -72,107 +65,65 @@ Dominant themes: ## Medium severity -### 8. `Endpoint.endpointType: EndpointType` — three layers of "endpoint" — `model.ts:284, 100` -- **Why weird:** `endpoint.endpointType : EndpointType` reads "endpoint . endpoint type : endpoint type" — the field name and the field type both repeat the container type name. Same pattern on `Endpoint.endpointStatus: EndpointStatus` (`model.ts:290, 314`). -- **Category:** 20 (type-suffix tautology), 8 (redundant prefix). -- **Suggested name:** Rename fields to `type` / `status` (the container `Endpoint` supplies the context). Wire fields stay `endpoint_type` / `endpoint_status`; remap in the marshaller. Match the existing pattern in `EndpointStatus.state` (bare `state`, not `endpointState`). -- **Rationale:** TS field names should not repeat the parent type. The current shape is a generator artifact of flat Go structs. - -### 9. `MiniVectorIndex.indexType: VectorIndexType` and `.indexSubtype: IndexSubtype` — `model.ts:383, 398, 579, 594` -- **Why weird:** Same tautology pattern as #8: `vectorIndex.indexType : VectorIndexType` reads "vector index . index type : vector index type"; `vectorIndex.indexSubtype : IndexSubtype` likewise repeats. The container type already says "index". -- **Category:** 20 (type-suffix tautology), 8 (redundant prefix). -- **Suggested name:** Rename to `type` / `subtype`. Wire fields are `index_type` / `index_subtype`. -- **Rationale:** Same reasoning as #8 — the container type qualifies the field. - -### 10. `IndexSubtype` vs `VectorIndexType` — two enums on different "type" axes — `model.ts:29, 62` +### 7. `IndexSubtype` vs `VectorIndexType` — two enums on different "type" axes — `model.ts:29, 62` - **Why weird:** Two enums both describing a "type" axis of a vector index. `IndexSubtype = {VECTOR, FULL_TEXT, HYBRID}` is the search-semantics axis (what kind of similarity is computed). `VectorIndexType = {DELTA_SYNC, DIRECT_ACCESS}` is the data-residency axis (how data flows in). Both surface as `index*Type*` fields on `VectorIndex`. A first-time reader cannot tell which axis is which without reading both JSDocs. - **Category:** 6 (misleading — both look like "the type" of the index), 17 (inconsistent naming for two type axes). - **Suggested name:** Disambiguate: `IndexSearchMode` for the search-semantics axis, `IndexBackingMode` (or `IndexStorageType`) for the data-residency axis. Or `IndexSearchKind` / `IndexSyncMode`. - **Rationale:** Two parallel `*Type` enums on the same type make the API harder to learn. Naming each by its axis would self-document. -### 11. `IndexSubtype` exposes an unsupported value `VECTOR` — `model.ts:29-33` +### 8. `IndexSubtype` exposes an unsupported value `VECTOR` — `model.ts:29-33` - **Why weird:** The enum's first member is `VECTOR`, and its JSDoc says "Not supported. Use `HYBRID` instead." A public-API enum that exposes a value whose only documented behavior is "do not use" inflates the surface area and forces every switch statement to handle it. Also, "VECTOR" inside an enum on a vector-search index is tautological — every value is some kind of vector behavior. - **Category:** 6 (misleading: present but explicitly unsupported), 18 (the value itself is content-free against the enum name). - **Suggested name:** Remove `VECTOR` from the enum, or document the deprecation path in JSDoc and timeline for removal. - **Rationale:** Dead enum members are bug magnets. -### 12. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:51-55, 554` +### 9. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:51-55, 554` - **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:155, 550` — "Result of the upsert or delete operation"). - **Category:** 13 (verb-coupling), 7 (verbose), 1 (generic `Status`/`Result`). - **Suggested name:** Split into `UpsertDataStatus` / `DeleteDataStatus` (aliases of the same wire enum), or use a neutral name `DataMutationStatus` / `DataMutationResult`. - **Rationale:** Two-verb compound nouns are unusual and confusing. Most APIs use a single neutral noun for shared response types. -### 13. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` +### 10. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` - **Why weird:** Two methods with the same verb start (`createEndpoint` / `createEndpointWaiter`). The waiter version *calls* `createEndpoint` then wraps the result in a `CreateEndpointWaiter`. A reader sees two `create*` methods and may think they are different operations. The Java/Go SDK convention surfaces a waiter via a side return; TS would more naturally inline the wait (`createEndpointAndWait`). - **Category:** 7 (verbose), 13 (verb overlap), 17 (inconsistent action verbs). - **Suggested name:** Either fold the wait into `createEndpoint` (return a `CreateEndpointWaiter` that is both an awaitable and the resource shape), or rename to `createEndpointAndWait`, or expose a single `waitForEndpoint(name)` that any caller can use after `createEndpoint`. - **Rationale:** Two `create*` methods for one logical "create" operation force every caller to learn which one to use. There is also no analogous waiter for the index create flow, so the pattern is inconsistent within the package. -### 14. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` +### 11. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` - **Why weird:** The enum is already `EndpointStatus_State` and the other members (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not carry the suffix — only the health-colored values do. Reads `EndpointStatus_State.RED_STATE` — "endpoint status state . red state". Inconsistent within the enum. - **Category:** 16 (field/value contradicting type domain), 8 (redundant suffix). - **Suggested name:** If wire allows, `RED` / `YELLOW` (matches `PROVISIONING` / `ONLINE` shape). Otherwise, document the asymmetry. - **Rationale:** Inconsistency within a single enum is a generator-spec issue worth surfacing. -### 15. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` +### 12. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` - **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 73-83 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. - **Category:** 16 (field contradicting domain — two orthogonal axes squeezed into one enum), 6 (misleading). - **Suggested name:** Split into `EndpointLifecycleState` and `EndpointHealth`. Reflect both on `EndpointStatus` as two fields. - **Rationale:** Single-enum mixing of orthogonal dimensions is an API-design smell. -### 16. `Endpoint.creator` vs `Endpoint.lastUpdatedUser` — inconsistent naming for the same kind of value — `model.ts:278, 286` -- **Why weird:** Two `string` fields, both identifying users, with mismatched naming patterns. `creator` is a bare noun; `lastUpdatedUser` is a compound past-participle. JSDoc only says "Creator of the endpoint" / "User who last updated the endpoint" without committing to a format (email? user ID? display name?). The same asymmetry would not survive a side-by-side review. -- **Category:** 13 (verb-tense / parallel-form mismatch), 19 (underspecified IDs). -- **Suggested name:** Symmetric pair, e.g. `createdBy` / `updatedBy` (REST convention) or `creator` / `lastUpdater`. Whichever side, document the format. -- **Rationale:** Parallel fields should look parallel. The current asymmetry implies a semantic difference that does not exist. - -### 17. `creationTimestamp` / `lastUpdatedTimestamp` — noun vs past-participle inconsistency — `model.ts:280, 282` -- **Why weird:** Same parallel-form mismatch as #16, on the timestamp fields. `creation` (noun) vs `lastUpdated` (past-participle). Other Databricks SDK packages standardize on either `createdAt`/`updatedAt` (idiomatic TS) or `createTime`/`updateTime` (Google APIs). This package mixes the two forms. -- **Category:** 13 (verb-tense), 17 (inconsistent naming). -- **Suggested name:** `createdAt` / `updatedAt`. Wire fields stay `creation_timestamp` / `last_updated_timestamp`; remap in the marshaller. -- **Rationale:** Symmetric timestamp fields should match in form. - --- ## Low severity -### 18. `req`, `resp`, `respBody`, `httpReq`, `pollResp`, `apiErr`, `pkgJson`, `opts`, `msg` — Go-idiom shorthand in TS — `client.ts:20, 79-80, 112, 117, 121, 122, 130, 137, 149, 154, 158, 159, 167, 175, 185, 189, 190, 201, 209, 213, 217, 218, 226, 234, 238, 242, 243, 251, 259, 263, 267, 268, 276, 284, 297, 301, 302, 310, 318, 328, 332, 333, 341, 348, 351, 353, 360, 366, 379, 383, 384, 392, 399, 402, 404, 411, 417, 422, 426, 427, 435, 443, 451, 455, 456, 467, 475, 480, 484, 485, 493, 501, 509, 513, 514, 522, 530, 535, 539, 540, 548, 556, 561, 565, 566, 574, 582, 587, 591, 592, 603, 625, 632, 642, 666, 673`; `utils.ts:30, 65-92, 76, 88-91` +### 13. `req`, `resp`, `respBody`, `httpReq`, `pollResp`, `apiErr`, `pkgJson`, `opts`, `msg` — Go-idiom shorthand in TS — `client.ts:20, 79-80, 112, 117, 121, 122, 130, 137, 149, 154, 158, 159, 167, 175, 185, 189, 190, 201, 209, 213, 217, 218, 226, 234, 238, 242, 243, 251, 259, 263, 267, 268, 276, 284, 297, 301, 302, 310, 318, 328, 332, 333, 341, 348, 351, 353, 360, 366, 379, 383, 384, 392, 399, 402, 404, 411, 417, 422, 426, 427, 435, 443, 451, 455, 456, 467, 475, 480, 484, 485, 493, 501, 509, 513, 514, 522, 530, 535, 539, 540, 548, 556, 561, 565, 566, 574, 582, 587, 591, 592, 603, 625, 632, 642, 666, 673`; `utils.ts:30, 65-92, 76, 88-91` - **Why weird:** Ubiquitous Go-style shorthand identifiers ported verbatim. `req`/`resp`/`err`/`opts`/`msg` are conventional in Go, where the receiver supplies enough context; in TS the convention favors spelled-out names (`request`, `response`, `error`, `options`, `message`). Internal inconsistency too: `executeCall` accepts `options` (utils.ts:28) but `executeHttpCall` uses `opts` (utils.ts:67). - **Category:** 14 (Go/Java-style names), 5 (cryptic abbreviation). - **Suggested name:** Spell them out throughout: `request`, `response`, `responseBody`, `pollResponse`, `httpRequest`, `apiError`, `packageJson`, `options`, `message`. Generator-level change. - **Rationale:** Trivial diff, large readability gain. The TS ecosystem standard is the spelled-out form. -### 19. `Endpoint.numIndexes` reads as "number of array indexes" — `model.ts:292` -- **Why weird:** "Index" in TS most commonly means a numeric position in an array. Here it means "number of vector-search indexes attached to this endpoint" — a domain term, not the data-structure term. Adjacent types use `vectorIndexes` for the array (correct disambiguation), but this scalar count uses bare `indexes`. -- **Category:** 6 (misleading), 14 (Go-style `num*` prefix). -- **Suggested name:** `numVectorIndexes` (matches the adjacent `vectorIndexes` array) or `vectorIndexCount`. -- **Rationale:** Consistency within the package and disambiguation from the data-structure meaning. - -### 20. `numResults`, `numIndexes` — `num*` prefix is a Go-ism — `model.ts:292, 438, 513` -- **Why weird:** `num` is a Go/C abbreviation for "number of". TS more commonly uses `count` suffix (`indexCount`, `resultCount`) or the bare noun pluralized. -- **Category:** 14 (Go-style names), 5 (cryptic abbreviation). -- **Suggested name:** `indexCount`, `resultCount`. Wire fields stay `num_indexes` / `num_results`. -- **Rationale:** Same as #18 — generator-level shorthand carry-over. - -### 21. `flattenQueryParams` is exported but unused inside the package — `utils.ts:123-150` +### 14. `flattenQueryParams` is exported but unused inside the package — `utils.ts:123-150` - **Why weird:** The function is exported from `utils.ts` but every client method assembles `URLSearchParams` directly via `params.append(...)`. The helper is dead code for this package. - **Category:** Observation (dead export), 6 (misleading — exported as if needed). - **Suggested name:** Either delete from `utils.ts` here or move to `@databricks/sdk-core` so the per-package `utils.ts` files stop duplicating it. - **Rationale:** Same finding as in other per-package audits. Generator-level cleanup. -### 22. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase in a field name — `model.ts:264` -- **Why weird:** The field name reads as a sentence (`modelEndpointName ForQuery`). TS field-naming convention prefers noun phrases over "for"-clauses. Adjacent `embeddingModelEndpointName` (also long, but a noun phrase) shows the package can do better. -- **Category:** 14 (Java-style "ForX" suffix), 7 (verbose). -- **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. -- **Rationale:** Noun phrases align with adjacent fields and TS naming conventions. - -### 23. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` +### 15. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` - **Why weird:** Two array fields on the same type, JSDoc on `columnsToIndex` says: "Alias for columns_to_sync. ... Only one of columns_to_sync or columns_to_index may be specified." Two fields that mean the same thing, where the API rejects both being set, is an API-level footgun. The SDK exposes both without runtime validation. - **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). - **Suggested name:** Mark `columnsToSync` `@deprecated` if `columnsToIndex` is the canonical form (or vice versa), and add runtime validation in `marshalDeltaSyncVectorIndexSpecRequestSchema`. - **Rationale:** API-level aliases are upstream policy, but the SDK should mark the deprecated alias to steer callers. -### 24. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` +### 16. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` - **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` at the top level (line 462) AND a `reranker.parameters.columnsToRerank: string[]` nested inside `RerankerConfig_RerankerParameters` (line 491). Same field name, same purpose, two places. The JSDoc on `reranker` references "`columns_to_rerank`" without saying which copy wins. - **Category:** 12 (duplicate concept), 6 (misleading — precedence unclear). - **Suggested name:** Drop one, or document the precedence in JSDoc. If one is for input and the other for echoed-back output, name them accordingly. @@ -182,19 +133,19 @@ Dominant themes: ## Observation -### 25. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` +### 17. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` - **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". A field whose JSDoc admits the rollout is incomplete leaves callers guessing whether setting it has any effect today. - **Category:** 6 (misleading — present but possibly inactive). - **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behavior and rollout timeline. - **Rationale:** Documentation-only TODOs leak generator/spec-side state into the public API. Worth surfacing. -### 26. `EmbeddingSourceColumn.embeddingConfig` JSDoc says "TODO: clean up ai gateway related code" — `model.ts:255` +### 18. `EmbeddingSourceColumn.embeddingConfig` JSDoc says "TODO: clean up ai gateway related code" — `model.ts:255` - **Why weird:** JSDoc on a public-API field contains a developer TODO: "TODO: clean up ai gateway related code. It's deprecated on ModelServing side." This is internal generator/spec-side debt leaking into IntelliSense for every SDK user. - **Category:** Observation (generator-side leak in JSDoc). - **Suggested name:** Rewrite the JSDoc to describe the public contract; track the cleanup in the spec, not in the user-facing docs. - **Rationale:** Internal TODOs in JSDoc are a long-known generator hygiene issue. Worth flagging. -### 27. `Endpoint.creator` and `lastUpdatedUser` JSDoc gives no format — `model.ts:278, 286` +### 19. `Endpoint.creator` and `lastUpdatedUser` JSDoc gives no format — `model.ts:278, 286` - **Why weird:** Both fields are typed `string` with JSDocs "Creator of the endpoint" / "User who last updated the endpoint". The reader has no way to tell if the value is a user ID, a display name, an email, or a UC identifier. Same observation applies to `MiniVectorIndex.creator` (`model.ts:396`) and `VectorIndex.creator` (`model.ts:592`). - **Category:** Observation (underspecified format on user-reference fields), 19 (underspecified IDs). - **Suggested name:** Keep the field names but extend JSDoc with the expected format (e.g. "the email of the user who created this endpoint"). diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index acaad458..4432d08d 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -11,10 +11,10 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 2 | -| Medium | 6 | +| Medium | 4 | | Low | 6 | | Observation | 4 | -| **Total** | **18** | +| **Total** | **16** | Headline themes: @@ -95,39 +95,7 @@ Headline themes: domain noun — note that `volumes` has no type with the bare name `Volume`, even though it is literally the "volumes" package. -### M2. `SseEncryptionDetails.algorithm` — generic field name on a -single-purpose type - -- **File / line:** `src/v1/model.ts:116`; cross-ref `model.ts:239, 243, - 348, 352`. -- **Category:** #1 vague/generic; #15 generic field name losing meaning. -- **Current:** `algorithm?: SseEncryptionAlgorithm`. -- **Suggestion:** `encryptionAlgorithm` — though, in context, the parent - type already says "SseEncryption", so `algorithm` is acceptable. This - is a borderline call. -- **Rationale:** Inside `SseEncryptionDetails`, `algorithm` is fine. The - flag stands only if the field is ever exposed in flatter scopes (it - isn't, locally). Listed for completeness. - -### M3. `awsKmsKeyArn` vs. `accessPoint` — inconsistent AWS-specific -field-naming style - -- **File / line:** `src/v1/model.ts:121` (`awsKmsKeyArn`); cross-ref - `model.ts:48, 160, 198` (`accessPoint`). -- **Category:** #1 vague/generic; #3 acronym casing inconsistencies; #6 - misleading name. -- **Current:** `awsKmsKeyArn?: string` lives on `SseEncryptionDetails` - (AWS-specific). `accessPoint?: string` lives on `CreateVolumeRequest` / - `UpdateVolumeRequest` / `VolumeInfo` but is also AWS-specific (the doc - comment at `model.ts:47, 159, 197` reads "The AWS access point to use - when accesing s3 for this external location."). -- **Suggestion:** Either prefix the latter as `awsAccessPoint` (matching - `awsKmsKeyArn`) or drop the prefix from both (`kmsKeyArn` and - `accessPoint`). Inconsistency is the issue. -- **Rationale:** Two AWS-only fields side-by-side, one prefixed, one not. - The doc comment also has a typo ("accesing" → "accessing"). - -### M4. `browseOnly` is a server-derived flag on request types +### M2. `browseOnly` is a server-derived flag on request types - **File / line:** `src/v1/model.ts:51` (`CreateVolumeRequest.browseOnly`), `163` (`UpdateVolumeRequest.browseOnly`), `201` @@ -146,7 +114,7 @@ field-naming style want browse-only access" rather than "the server has limited me to browse-only." -### M5. `req` parameter name on all client methods +### M3. `req` parameter name on all client methods - **File / line:** `src/v1/client.ts:90, 122, 157, 203, 248, 274`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. @@ -159,7 +127,7 @@ field-naming style encouraged; in TS this reads as Go-translated code. Pervasive in this package (every method uses `req`) and across the repo. -### M6. Repeated `Details` suffix — `EncryptionDetails` wraps +### M4. Repeated `Details` suffix — `EncryptionDetails` wraps `SseEncryptionDetails` - **File / line:** `src/v1/model.ts:63` (`EncryptionDetails`), @@ -340,22 +308,22 @@ Type & symbol checklist: - [x] `SseEncryptionAlgorithm` enum (3 members) → no defect. - [x] `VolumeType` enum (2 members) → no defect. -- [x] `CreateVolumeRequest` interface (17 fields) → H2, M3, M4. +- [x] `CreateVolumeRequest` interface (17 fields) → H2, M2. - [x] `DeleteVolumeRequest` interface (1 field) → H1, L5. -- [x] `EncryptionDetails` interface → M6. +- [x] `EncryptionDetails` interface → M4. - [x] `GetVolumeRequest` interface (2 fields) → H1, L5. - [x] `ListVolumesRequest` interface (5 fields) → no additional defect. -- [x] `SseEncryptionDetails` interface (2 fields) → M2, M3, M6. -- [x] `UpdateVolumeRequest` interface (18 fields) → H1, H2, M3, M4, L5. -- [x] `VolumeInfo` interface (16 fields) → M1, M3, M4, L5, O1. +- [x] `SseEncryptionDetails` interface (2 fields) → M4. +- [x] `UpdateVolumeRequest` interface (18 fields) → H1, H2, M2, L5. +- [x] `VolumeInfo` interface (16 fields) → M1, M2, L5, O1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. - [x] `PACKAGE_SEGMENT` constant → O4. -- [x] `createVolume(req, options)` method → H2, M5, L2. -- [x] `deleteVolume(req, options)` method → H1, M5, L2. -- [x] `getVolume(req, options)` method → H1, M5, L2. -- [x] `listVolumes(req, options)` method → M5, L2. -- [x] `listVolumesIter(req, options)` async generator → M5, L6. -- [x] `updateVolume(req, options)` method → H1, H2, M5, L2. +- [x] `createVolume(req, options)` method → H2, M3, L2. +- [x] `deleteVolume(req, options)` method → H1, M3, L2. +- [x] `getVolume(req, options)` method → H1, M3, L2. +- [x] `listVolumes(req, options)` method → M3, L2. +- [x] `listVolumesIter(req, options)` async generator → M3, L6. +- [x] `updateVolume(req, options)` method → H1, H2, M3, L2. - [x] `HttpCallOptions` interface → no defect. - [x] `executeCall` function → L1. - [x] `readAll` private function → no defect (name fits idiom). @@ -365,16 +333,3 @@ Type & symbol checklist: - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). --- - -## Fixed - -- #M1 Bare verb-phrase request type names (originally cited at - `src/v1/model.ts:16, 54, 73, 80, 124`): Fixed in regeneration on - 2026-05-20 — request DTOs renamed to `CreateVolumeRequest`, - `DeleteVolumeRequest`, `GetVolumeRequest`, `ListVolumesRequest`, - `UpdateVolumeRequest`; collision with client methods resolved. -- #O1 Bare `Get*` / `Create*` / `Update*` / `Delete*` / `List*` request - shapes are a repo-wide pattern (originally cited as observation): Fixed - in regeneration on 2026-05-20 — local M1 finding resolved by the - `Request` suffix renaming; cross-package convention now matches sibling - packages that already used the suffix. diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index 4308436d..c7de05f0 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -28,11 +28,11 @@ This is the dominant theme of the audit (see F0). | Severity | Count | | ----------- | ----- | -| High | 25 | -| Medium | 13 | -| Low | 45 | +| High | 21 | +| Medium | 10 | +| Low | 40 | | Observation | 17 | -| **Total** | **100** | +| **Total** | **88** | --- @@ -289,27 +289,7 @@ compatibility while updating the customer-visible type names. `DbsqlChannelName`). Note: the enum name `ChannelName` duplicates "name" — see F8.2. -#### F1.8 — `name` field used both as a human name and as a path identifier (HIGH) -- **Where:** `name` appears on `CreateWarehouseRequest` - (`model.ts:727`, "Logical name for the cluster"), - `EditWarehouseRequest` (`model.ts:871`), `EndpointInfo` - (`model.ts:989`), `GetWarehouseRequest_Response` - (`model.ts:1124`), `DefaultWarehouseOverride` (`model.ts:834`, - `default-warehouse-overrides/{default_warehouse_override_id}`), - `DeleteDefaultWarehouseOverrideRequest` (`model.ts:853`), - `GetDefaultWarehouseOverrideRequest` (`model.ts:1104`). -- **Why flagged:** Two semantically different things share the - field name `name`. On warehouses, `name` is a human-readable - display name ("My SQL warehouse"). On default-warehouse- - overrides, `name` is the resource-name path identifier - (`default-warehouse-overrides/123`). The latter is functionally - an ID. Caller code paths in `client.ts:199, 290, 594` use - `req.name` as the URL path segment for the override APIs. -- **Suggestion:** On the override types, rename `name` to - `resourceName` and document the path-id role. Alternatively, - document the dual role in JSDoc to make the contract explicit. - -#### F1.9 — `req` parameter name on every client method (LOW, Go-ism) +#### F1.8 — `req` parameter name on every client method (LOW, Go-ism) - **Where:** `client.ts:108, 152, 180, 196, 215, 243, 271, 287, 312, 340, 371, 407, 425, 464, 482, 514, 539, 551, 576, 591`. - **Why flagged:** `req` is a Go-ism (see category 14). It is @@ -317,13 +297,13 @@ compatibility while updating the customer-visible type names. - **Suggestion:** Use `request` for stylistic consistency with `options` (which is spelled out). Cross-package decision. -#### F1.10 — `resp` local variable everywhere (LOW) +#### F1.9 — `resp` local variable everywhere (LOW) - **Where:** `client.ts` throughout (e.g. `resp: CreateWarehouseRequest_Response | undefined`). - **Why flagged:** Same Go abbreviation as `req`. See F14.1. - **Suggestion:** `response` for consistency. Generator-level. -#### F1.11 — `Client` class name (MEDIUM, cross-cutting) +#### F1.10 — `Client` class name (MEDIUM, cross-cutting) - **Where:** `client.ts:78`, `index.ts:4`. - **Why flagged:** Every package in this SDK exports a `Client`. `import {Client} from '@databricks/sdk-warehouses'` is @@ -332,7 +312,7 @@ compatibility while updating the customer-visible type names. convention, or rename to `WarehousesClient` consistently across packages. Cross-cutting decision. -#### F1.12 — `code` field on `TerminationReason` (LOW) +#### F1.11 — `code` field on `TerminationReason` (LOW) - **Where:** `model.ts:1366`. - **Why flagged:** `code` is generic; disambiguated by container type, but `terminationCode` would be clearer in isolation. @@ -340,43 +320,7 @@ compatibility while updating the customer-visible type names. Already typed against the `TerminationCode` enum, so renaming introduces redundancy. Leave. -#### F1.13 — `type` field on `TerminationReason` and `DefaultWarehouseOverride` (LOW) -- **Where:** `model.ts:838, 1368`. -- **Why flagged:** `type` is one of the most generic identifier - names possible. Both are typed against domain-specific enums, - but the field name alone gives no hint. -- **Suggestion:** Acceptable given typing; `terminationType` / - `overrideType` would be more self-documenting. - -#### F1.14 — `parameters` field on `TerminationReason` (LOW) -- **Where:** `model.ts:1370`. -- **Why flagged:** `parameters` is generic. JSDoc says "list of - parameters that provide additional information about why the - cluster was terminated" — these are debug context, not request - parameters. -- **Suggestion:** Rename to `details` or `context`. Currently - conflicts with the `parameters` URL-query terminology used - elsewhere in the SDK. - -#### F1.15 — `details`, `message`, `summary` fields on `EndpointHealth` (LOW) -- **Where:** `model.ts:970, 974, 976`. -- **Why flagged:** Three generic prose fields. JSDoc clarifies: - `message` is deprecated; `summary` is short; `details` is long. - Their relationship is not obvious from names. -- **Suggestion:** Rename `details` → `errorDetails`. Keep `summary` - and `message` (deprecated). Or merge `summary`+`details` into - a single nested structure. - -#### F1.16 — `customTags` field on `EndpointTags` (LOW) -- **Where:** `model.ts:1094`. -- **Why flagged:** "custom" is implied by the container type - `EndpointTags` (vs. a more specific name). The field is just - a list of tags, so the `custom` prefix adds no information - the container does not already supply. -- **Suggestion:** Rename to `tags` (the container already - conveys the "custom" scope). - -#### F1.17 — `Call`, `Options` (imported, cross-package) (acceptable) +#### F1.12 — `Call`, `Options` (imported, cross-package) (acceptable) - **Where:** `utils.ts:3`, `client.ts:4`. - These come from `@databricks/sdk-core/api`. Generic but intentional. Out of scope for this package's audit. @@ -455,15 +399,7 @@ _None._ ### 5. Cryptic abbreviations -#### F5.1 — `Mins` for minutes (`autoStopMins`) (LOW) -- **Where:** `model.ts:782, 926, 1044, 1179`. -- **Why flagged:** "Mins" is mildly informal. Compare to other - duration fields in the SDK that use `Seconds`, `Hours`. JSDoc - always spells out "minutes" in prose. -- **Suggestion:** Rename to `autoStopMinutes`. Wire stays - `auto_stop_mins` for compatibility. - -#### F5.2 — `Conf` for configuration (`EndpointConfPair`, `configPair`, `dataAccessConfig`) (MEDIUM) +#### F5.1 — `Conf` for configuration (`EndpointConfPair`, `configPair`, `dataAccessConfig`) (MEDIUM) - **Where:** `model.ts:961, 1238, 1311, 1327`. - **Why flagged:** "Conf" is an abbreviation. Inconsistent within the package: `RepeatedEndpointConfPairs` has both @@ -471,21 +407,9 @@ _None._ spelled out). The package alternates between `Conf`, `Config`, `Configuration`. - **Suggestion:** Standardize on `Config` (already in - `dataAccessConfig`). Rename `EndpointConfPair` → `ConfigPair`, - `configPair` → `configPairs` (also plural; see F9.x). - -#### F5.3 — `Param` for parameter (`globalParam`, `configParam`) (MEDIUM) -- **Where:** `model.ts:1250, 1252, 1339, 1341, 1697-1698, 1935-1940`. -- **Why flagged:** "Param" is a cryptic abbreviation when the - full word "parameter" is also in use in this package - (`sqlConfigurationParameters`, `TerminationReason.parameters`, - `TerminationReason_ParametersEntry`). Inconsistent. -- **Suggestion:** Rename to `globalParameter`, `configParameter` - (or pluralize, see F9.x). JSDoc on both says "Deprecated: Use - sql_configuration_parameters" — they are slated for removal, - so the rename can be paired with deprecation removal. - -#### F5.4 — `Num` for number (`numClusters`, `numActiveSessions`, `maxNumClusters`, `minNumClusters`) (LOW) + `dataAccessConfig`). Rename `EndpointConfPair` → `ConfigPair`. + +#### F5.2 — `Num` for number (`numClusters`, `numActiveSessions`, `maxNumClusters`, `minNumClusters`) (LOW) - **Where:** `model.ts:760, 771, 1022, 1033, 1075, 1077, 1157, 1168, 1210, 1212`. - **Why flagged:** "Num" is a programmer-ism. SDK and other packages occasionally spell it out as `count` or `number`. @@ -495,14 +419,14 @@ _None._ `minClusterCount` for clarity, but consistency with wire takes priority. Leave. -#### F5.5 — `Arn` for AWS Resource Name (`instanceProfileArn`) (acceptable) +#### F5.3 — `Arn` for AWS Resource Name (`instanceProfileArn`) (acceptable) - **Where:** `model.ts:786, 930, 1048, 1183, 1244, 1333`. - **Why flagged:** `ARN` is a well-known AWS acronym. Casing matches `instanceProfileArn` (first letter cap, rest lower). No issue. - **Suggestion:** No change. -#### F5.6 — `Conf` vs. `Config` vs. `Configuration` (MEDIUM, internal inconsistency) +#### F5.4 — `Conf` vs. `Config` vs. `Configuration` (MEDIUM, internal inconsistency) - **Where:** Repeated across `EndpointConfPair`, `dataAccessConfig`, `sqlConfigurationParameters`, `configPair`, `configurationPairs`, `globalParam`, @@ -513,9 +437,9 @@ _None._ names, `Configuration` for spelled-out prose. Or fully spell out everywhere. -#### F5.7 — `req`, `resp` Go-ism abbreviations (LOW) +#### F5.5 — `req`, `resp` Go-ism abbreviations (LOW) - **Where:** `client.ts` throughout. -- Already covered in F1.9 and F1.10. +- Already covered in F1.8 and F1.9. --- @@ -673,16 +597,7 @@ _None._ ### 9. Singular / plural mismatches -#### F9.1 — `RepeatedEndpointConfPairs.configPair` is plural-content singular-name (HIGH) -- **Where:** `model.ts:1311`. -- **Why flagged:** Field type is `EndpointConfPair[]` (array) - but field name is singular `configPair`. The wire form is - `config_pair`. Compare to sibling `configurationPairs` (same - type, but plural name). Inconsistent within the type. -- **Suggestion:** Rename to `configPairs`. Wire stays - `config_pair` if deprecated, or rename wire to `config_pairs`. - -#### F9.2 — `TerminationReason.parameters` is a map, not a list (LOW) +#### F9.1 — `TerminationReason.parameters` is a map, not a list (LOW) - **Where:** `model.ts:1370`. Type `Record`. - **Why flagged:** `parameters` is plural but typed as a map. Plural maps are fine but inconsistent — compare to @@ -690,29 +605,20 @@ _None._ - **Suggestion:** Acceptable; map semantics are clear from the type. Plural is correct. -#### F9.3 — `globalParam`, `configParam` are singular names for list-valued fields (MEDIUM) -- **Where:** `model.ts:1250, 1252, 1339, 1341`. -- **Why flagged:** Both fields are of type - `RepeatedEndpointConfPairs` — a list. Singular name on a - list-valued field is misleading. Compare to - `sqlConfigurationParameters` (plural) for the same concept. -- **Suggestion:** Rename to `globalParams` / `configParams` - (also pair with the `Param`/`Parameter` expansion in F5.3). - -#### F9.4 — `enabledWarehouseTypes` plural array (acceptable) +#### F9.2 — `enabledWarehouseTypes` plural array (acceptable) - **Where:** `model.ts:1269, 1358`. - **Why flagged:** Plural name + array type. Correct. - **Suggestion:** No change. -#### F9.5 — `defaultWarehouseOverrides` plural array (acceptable) +#### F9.3 — `defaultWarehouseOverrides` plural array (acceptable) - **Where:** `model.ts:1294`. - **Why flagged:** Correct. - **Suggestion:** No change. -#### F9.6 — `warehouses` plural array (acceptable) +#### F9.4 — `warehouses` plural array (acceptable) - **Where:** `model.ts:1455`. Correct. -#### F9.7 — `customTags` plural array (acceptable) +#### F9.5 — `customTags` plural array (acceptable) - **Where:** `model.ts:1094`. Correct. --- @@ -849,42 +755,32 @@ _None. Wrappers are retained for forward compatibility._ ### 15. Generic field names losing meaning -#### F15.1 — `name` overloaded with three meanings (HIGH) -- **Where:** `Channel.name` (channel selector enum value), - `CreateWarehouseRequest.name` (human display name), - `DefaultWarehouseOverride.name` (path identifier). -- **Why flagged:** Three completely different concepts share - the field name `name`. -- **Suggestion:** See F1.8. Rename - `DefaultWarehouseOverride.name` → `resourceName`. Rename - `Channel.name` → `channelType` (also F8.2). - -#### F15.2 — `state` field on `EndpointInfo` / `GetWarehouseRequest_Response` (LOW) +#### F15.1 — `state` field on `EndpointInfo` / `GetWarehouseRequest_Response` (LOW) - **Where:** `model.ts:1079, 1214`. - **Why flagged:** Disambiguated by type (`EndpointState`), but `warehouseState` would be clearer in isolation. - **Suggestion:** Leave. -#### F15.3 — `status` field on `EndpointHealth` (LOW) +#### F15.2 — `status` field on `EndpointHealth` (LOW) - **Where:** `model.ts:968`. Type `EndpointHealth_Status`. - **Why flagged:** Reads "endpoint health . status . endpoint health status". Three layers of "status". - **Suggestion:** Acceptable given typing. -#### F15.4 — `enabled` field on `WarehouseTypePair` (LOW) +#### F15.3 — `enabled` field on `WarehouseTypePair` (LOW) - **Where:** `model.ts:1413`. - **Why flagged:** Generic, but disambiguated by container. - **Suggestion:** Leave. -#### F15.5 — `summary` field on `EndpointHealth` (LOW) +#### F15.4 — `summary` field on `EndpointHealth` (LOW) - **Where:** `model.ts:974`. - **Why flagged:** Generic. JSDoc says "short summary of the health status". Could be `summaryMessage` or `healthSummary`, but field is rarely used in isolation. - **Suggestion:** Leave. -#### F15.6 — `key`, `value` on every `*Pair` type (LOW) +#### F15.5 — `key`, `value` on every `*Pair` type (LOW) - **Where:** `EndpointConfPair`, `EndpointTagPair`, `TerminationReason_ParametersEntry`. - **Why flagged:** Maximally generic. Domain is in the @@ -892,13 +788,13 @@ _None. Wrappers are retained for forward compatibility._ - **Suggestion:** Acceptable; conventional for key-value pair types. -#### F15.7 — `code`, `type`, `parameters` on `TerminationReason` (LOW) +#### F15.6 — `code`, `type`, `parameters` on `TerminationReason` (LOW) - **Where:** `model.ts:1366, 1368, 1370`. - **Why flagged:** All three are generic words. Disambiguated by container. - **Suggestion:** Leave. -#### F15.8 — `host`, `path`, `protocol`, `port` on `OdbcParams` (LOW) +#### F15.7 — `host`, `path`, `protocol`, `port` on `OdbcParams` (LOW) - **Where:** `model.ts:1303-1306`. - **Why flagged:** Generic connection-string fields. Standard. - **Suggestion:** Leave. @@ -989,21 +885,7 @@ _None._ ### 19. Underspecified IDs -#### F19.1 — `id` on `CreateWarehouseRequest_Response`, `EndpointInfo`, -`GetWarehouseRequest_Response`, `DeleteWarehouseRequest`, -`EditWarehouseRequest`, `GetWarehouseRequest`, `StartRequest`, -`StopRequest` (MEDIUM) -- **Where:** Many places. Caller writes - `client.startWarehouse({id: '...'})` — but `id` here is the - warehouse id, not a generic id. -- **Why flagged:** Bare `id` is acceptable in context, but - across the SDK, packages typically use the qualified form - (`pipelineId`, `clusterId`, `endpointId`). `id` is - underspecified. -- **Suggestion:** Rename to `warehouseId` for self-documentation. - Wire stays `id` (path segment). - -#### F19.2 — `defaultWarehouseOverrideId` vs. `warehouseId` on +#### F19.1 — `defaultWarehouseOverrideId` vs. `warehouseId` on `DefaultWarehouseOverride` (LOW) - **Where:** `model.ts:836, 843`. - **Why flagged:** Two ID fields on one type: @@ -1012,24 +894,12 @@ _None._ Both are clearly named, but a reader has to look carefully. - **Suggestion:** Acceptable; both names are explicit. -#### F19.3 — `name` is functionally an ID on -`DefaultWarehouseOverride` (HIGH) -- **Where:** `model.ts:834`. Path form `default-warehouse-overrides/{id}`. -- **Why flagged:** AIP-style "resource name" as a string — - conventional in Google APIs but unconventional in TS. - Customer sees `{name: 'default-warehouse-overrides/123'}` and - may try `{name: 'my-override-name'}`. Field name `name` - encourages misuse. -- **Suggestion:** Rename to `resourceName` on the type and - request types. AIP convention is `name` on the wire — keep - wire, rename TS. - -#### F19.4 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) +#### F19.2 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) - **Where:** `model.ts:1438`. Already deprecated. Numeric (`number`), not string — unusual; most IDs in the SDK are string. - **Suggestion:** Already deprecated. Leave. -#### F19.5 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) +#### F19.3 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) - **Where:** `model.ts:1299`. Standard pagination identifier. --- @@ -1075,7 +945,7 @@ _None._ #### F20.4 — `TerminationReason.code: TerminationCode` (LOW) - **Where:** `model.ts:1366`. Field `code` + enum suffix `Code` on `TerminationCode`. Generic field name with specific enum - — acceptable per F1.12. + — acceptable per F1.11. #### F20.5 — `TerminationReason.type: TerminationType` (LOW) - **Where:** `model.ts:1368`. Same pattern. Acceptable. @@ -1119,7 +989,3 @@ _None._ Splitting could simplify. --- - -## Fixed - -- #F8.1-sub `CreateWarehouse` / `GetWarehouse` lacking `Request` suffix (originally cited at `model.ts:746, model.ts:1141`): Fixed in regeneration on 2026-05-20 — the user added `Request` to those types so all request DTOs now carry the suffix consistently; only the broader "drop the Request suffix entirely" recommendation remains in F8.1. diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md index 929ed483..7d4794d2 100644 --- a/.agent/naming-audit/workspace.md +++ b/.agent/naming-audit/workspace.md @@ -484,15 +484,3 @@ RAW = 'RAW', | `src/v1/client.ts` | 291 | yes | | `src/v1/utils.ts` | 151 | yes | | `src/v1/index.ts` | 21 | yes | - -## Fixed - -- #1 `workspace` package name (originally cited at `package.json` → `@databricks/sdk-workspace`): Fixed in regeneration on 2026-05-20 — package renamed to `workspaceobjects`, which conveys the filesystem-objects scope and no longer collides with the other "workspace*" packages. -- #2 `Delete`, `Export`, `Import`, `List`, `Mkdirs`, `GetStatus` verb-as-type request interfaces (originally cited at `model.ts:65,:79,:121,:126,:163,:176`): Fixed in regeneration on 2026-05-20 — all request interfaces now carry a `Request` suffix (`DeleteRequest`, `ExportRequest`, `ImportRequest`, `ListRequest`, `MkdirsRequest`, `GetStatusRequest`), resolving the ES reserved-word collisions. -- #22 `GetStatus` verb-as-type without `Request` suffix (originally cited at `model.ts:121-124`): Fixed in regeneration on 2026-05-20 — renamed to `GetStatusRequest`, consistent with the rest of the SDK. -- #26 `ExportOutputs` plural enum type (originally cited at `model.ts:27-32`): Fixed in regeneration on 2026-05-20 — the `ExportOutputs` enum is no longer present in the generated model. -- #27 `Export.outputs` typed `ExportOutputs` tautology (originally cited at `model.ts:104-106`): Fixed in regeneration on 2026-05-20 — the `outputs` field is no longer present on `ExportRequest`. - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md index 6db64a06..c598cd6e 100644 --- a/.agent/naming-audit/workspaceassignment.md +++ b/.agent/naming-audit/workspaceassignment.md @@ -176,14 +176,3 @@ WorkspacePermissionAssignment surface continues to live in the 2. **Duplicated domain modelling with `iam` package.** Findings 1, 6, 7, 17 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. 3. **Misleading verb assignment for list vs get.** Findings 3, 4, 23 — the array-returning method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. 4. **Underspecified IDs and weak typing.** Findings 8, 9, 15, 19 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. - -## Fixed -- #2 `Permission` enum name (originally cited at `src/v1/model.ts:5`): Fixed in regeneration on 2026-05-20 — enum renamed to `WorkspacePermission` (model.ts:39), no longer a vague top-level `Permission` symbol. -- #4 `DeleteWorkspacePermissionAssignment` verb-phrase type name (originally cited at `src/v1/model.ts:13`): Fixed in regeneration on 2026-05-20 — `Request` suffix now applied across `Delete…Request`, `Get…Request`, `List…Request`, `Update…Request` (model.ts:122,203,231,362). -- #20 `nextPageToken` / `prevPageToken` asymmetric naming (originally cited at `src/v1/model.ts:44,46`): Fixed in regeneration on 2026-05-20 — pagination tokens removed from `GetWorkspacePermissionAssignmentsRequest_Response`; the response carries only `permissionAssignments` (model.ts:211-214). -- #21 `GetWorkspacePermissionAssignments.filter?: string` (originally cited at `src/v1/model.ts:36`): Fixed in regeneration on 2026-05-20 — `filter` field removed from `GetWorkspacePermissionAssignmentsRequest` (model.ts:203-208). -- #22 `GetWorkspacePermissionAssignments.maxResults` (originally cited at `src/v1/model.ts:34`): Fixed in regeneration on 2026-05-20 — `maxResults` field removed from `GetWorkspacePermissionAssignmentsRequest` (model.ts:203-208). - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index ddbbad0e..0d30beb7 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -3,13 +3,13 @@ **Path:** `packages/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 26 +**Total weird names flagged:** 18 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 17 | +| High | 3 | +| Medium | 10 | | Low | 2 | | Observation | 3 | @@ -20,28 +20,22 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## High severity ### 1. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` -- **Why weird:** Free-form `string` for what is a closed set of values. The doc-comment explicitly lists them: "(catalog, storage_credential, credential, or external_location)" — meaning the API author *knows* the set is closed but chose not to type it. A typo like `"caatalog"` will silently 4xx at the server. Also, the path is constructed via `${req.securableType ?? ''}` (`client.ts:115`, `client.ts:207`) which means an undefined value will produce a URL like `/api/2.1/unity-catalog/bindings//...` — a routing-incidental 404. +- **Why weird:** Free-form `string` for what is a closed set of values. The doc-comment explicitly lists them: "(catalog, storage_credential, credential, or external_location)" — meaning the API author *knows* the set is closed but chose not to type it. A typo like `"caatalog"` will silently 4xx at the server. Also, the path is constructed via `${req.securableType ?? ''}` (`client.ts:123`, `client.ts:221`) which means an undefined value will produce a URL like `/api/2.1/unity-catalog/bindings//...` — a routing-incidental 404. - **Category:** 19 (underspecified ID/discriminator), 1 (vague), 16 (field contradicts type domain). - **Suggested name:** Define a `SecurableType` enum (`CATALOG`, `STORAGE_CREDENTIAL`, `CREDENTIAL`, `EXTERNAL_LOCATION`) and type both fields accordingly. - **Rationale:** Type-safety is the entire point of TypeScript. Other UC packages in the SDK also use bare `string` for securable types — same fix should apply across all of them. -### 2. `securableFullName` vs `catalogName` inconsistency — `src/v1/model.ts:14,53` vs `27,69` -- **Why weird:** The same conceptual value (the fully-qualified name of the securable being bound) is named two different ways depending on which request type you're looking at. `Get/UpdateCatalogWorkspaceBindingsRequest` use `catalogName` (because the legacy endpoint is catalog-specific). `Get/UpdateWorkspaceBindingsRequest` use `securableFullName` (because the generic endpoint accepts any securable). For a catalog binding, both names refer to the same string. Users porting from one variant to the other must change the field name. -- **Category:** 17 (inconsistent naming), 15 (one is a special case of the other). -- **Suggested name:** Use `fullName` everywhere (or `name`), since `securableType` already provides the discriminator. Drop the special-case `catalogName` field once the legacy API is gone. -- **Rationale:** Two field names for one logical value is a documentation and onboarding tax. - -### 3. Concept duplication: catalog-specific vs generic securable APIs — entire file +### 2. Concept duplication: catalog-specific vs generic securable APIs — entire file - **Why weird:** The package ships two parallel surfaces: - `Get/UpdateCatalogWorkspaceBindingsRequest` operate on `/workspace-bindings/catalogs/{name}` (catalog-only legacy). - `Get/UpdateWorkspaceBindingsRequest` operate on `/bindings/{securable_type}/{full_name}` (generic). -- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes (#2), different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). +- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes, different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). - The legacy methods cannot express `READ_ONLY` bindings (they only return/accept workspace IDs, no `BindingType`) — meaning the catalog-specific API is strictly less expressive than the generic one. Yet both are shipped. - **Category:** 12 (duplicate concept within one package), 17 (inconsistency), Observation. - **Suggested name:** Either deprecate the catalog-specific surface (mark with `@deprecated`) and direct users to `getWorkspaceBindings({securableType: 'catalog', securableFullName: name})`, or rename the catalog-specific variant to make its legacy status explicit (e.g. `getCatalogWorkspaceBindingsLegacy`). - **Rationale:** Two surfaces for one operation, where one is strictly weaker, is a footgun. -### 4. Concept overlap with sibling package `workspaceassignment` — cross-package +### 3. Concept overlap with sibling package `workspaceassignment` — cross-package - **Why weird:** A sibling package `packages/workspaceassignment/src/v1/` covers `WorkspacePermissionAssignment` — assigning **principals** (users, groups, service principals) to **workspaces**. The current package `workspacebindings` covers `WorkspaceBindingInfo` — assigning **securables** (catalogs, credentials, etc.) to **workspaces**. Both use the noun "workspace" and an "assign"/"bind" verb. A user searching the SDK for "how do I associate X with a workspace" will find both packages and must read both READMEs to disambiguate. There is no surface-level disambiguation in the type or method names. `workspaceassignment` even has an `assign_workspaces` / `unassign_workspaces` field in `UpdateCatalogWorkspaceBindingsRequest` (line 55, 57) — using the verb "assign" inside the *bindings* package. - **Category:** 12 (duplicate concept across packages), 17 (inconsistent verbs: "bind" vs "assign" used for adjacent operations). - **Suggested name:** Either align the verbs (both as "assign" or both as "bind") or rename one package to disambiguate directionally — e.g. `workspacebindings` → `securableworkspacebindings` or `ucbindings`; `workspaceassignment` → `workspaceprincipalassignment`. At minimum, pick one verb across the two packages. @@ -51,103 +45,61 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Medium severity -### 5. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` +### 4. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` - **Why weird:** `Info` suffix is a Go-style convention (`*Info` types in `databricks/sdk-go` are pervasive: `CatalogInfo`, `TableInfo`, `SchemaInfo`...). In TS the suffix carries no information — the type *is* the binding, not a separate "info-about-the-binding" record. Just two fields: `workspaceId` and `bindingType`. - **Category:** 14 (Go-style name), 8 (redundant suffix). - **Suggested name:** `WorkspaceBinding`. - **Rationale:** Drop Go suffixes when porting; sibling packages have already done this for some types but not consistently. -### 6. `workspaces?: number[]` (field, multiple) — `src/v1/model.ts:20,63` -- **Why weird:** Generic field name "workspaces" for what is actually a list of workspace IDs (not workspace objects). The doc-comment says "A list of workspace IDs" — so the wire/value is IDs, but the field is named after the entity. A consumer might reasonably expect `workspaces: Workspace[]` and be surprised by `number[]`. -- **Category:** 6 (misleading: name implies entity, value is ID), 15 (generic field name), 16 (field contradicts type domain), 19 (underspecified ID). -- **Suggested name:** `workspaceIds`. -- **Rationale:** Pair with `assignWorkspaces`/`unassignWorkspaces` (which have the same problem, #7, #8) for consistency. - -### 7. `assignWorkspaces?: number[]` — `src/v1/model.ts:55` -- **Why weird:** Same problem as #6 — the field is a list of workspace IDs but is named after the entity ("workspaces"). The leading verb "assign" turns the field into a verb-phrase ("assign workspaces"), which reads as an imperative ("please assign workspaces") rather than a noun ("the set of workspace IDs to assign"). Additionally, the verb "assign" is inconsistent with the package noun "bindings" (see #4). -- **Category:** 6 (misleading), 17 (verb inconsistency), 19 (underspecified ID), 15 (generic field). -- **Suggested name:** `workspaceIdsToBind` or `addWorkspaceIds`, matching the `add` / `remove` pattern used in the generic `UpdateWorkspaceBindingsRequest` (lines 76, 78). -- **Rationale:** Aligns vocabulary with package noun (binding, not assign) and clarifies the field is IDs. - -### 8. `unassignWorkspaces?: number[]` — `src/v1/model.ts:57` -- **Why weird:** Same problems as #7, plus: "unassign" is a verb invented for this pair (it isn't a real English word in most dictionaries — "unassign" appears in software contexts but is dispreferred to "remove" or "revoke"). The companion field is `assignWorkspaces`, so the prefix matters here. -- **Category:** 6, 17, 5 (cryptic neologism), 19. -- **Suggested name:** `workspaceIdsToUnbind` or `removeWorkspaceIds`. -- **Rationale:** See #7. - -### 9. `bindings?: WorkspaceBindingInfo[]` (field, multiple) — `src/v1/model.ts:43,85` -- **Why weird:** Field name `bindings` on a `WorkspaceBindings` response type — repeats the type-name fragment. The surrounding context already says "this is the workspace bindings response", so the field could safely be `items`. -- **Category:** 20 (type-suffix tautology), 15 (generic). -- **Suggested name:** `items` or `workspaceBindings` (more specific). -- **Rationale:** A field on `XResponse` named after `X` is redundant. - -### 10. `add?: WorkspaceBindingInfo[]` / `remove?: WorkspaceBindingInfo[]` — `src/v1/model.ts:76,78` -- **Why weird:** Bare verb-shaped field names (`add`, `remove`). On an `UpdateWorkspaceBindingsRequest` payload, these are *what* gets added/removed (a list of bindings), but the field names read as imperatives. The doc-comments clarify, but the field names themselves carry no noun. -- **Category:** 1 (vague), 15 (generic), 17 (verb inconsistency with the catalog-specific `assignWorkspaces`/`unassignWorkspaces`). -- **Suggested name:** `addBindings` / `removeBindings`, or `bindingsToAdd` / `bindingsToRemove`, or `granted` / `revoked`. -- **Rationale:** A bare `add: WorkspaceBindingInfo[]` carries no noun. Common in change-set APIs but typically paired with a typed item collection. - -### 11. `workspaceId?: number` — `src/v1/model.ts:90` -- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` (#6) and `assignWorkspaces?: number[]` (#7) — all three would need to migrate together. +### 5. `workspaceId?: number` — `src/v1/model.ts:90` +- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` and `assignWorkspaces?: number[]` — all three would need to migrate together. - **Category:** 16 (field contradicts type domain: 64-bit IDs typed as JS number), 19 (underspecified). - **Suggested name:** Keep the name `workspaceId` but consider `bigint` or `string` for the type. This is a project-wide concern. - **Rationale:** Cross-cutting JS interop issue; not unique to this package, but flagged for completeness. -### 12. `bindingType?: BindingType` — `src/v1/model.ts:92` -- **Why weird:** Field name `bindingType` on a type called `WorkspaceBindingInfo` repeats the type-name fragment "binding". The call site reads `binding.bindingType` — "binding"/"binding type" repeated in one expression. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `accessLevel` (more descriptive — the value indicates read/write vs read-only access), or just `type` (since context is clear). -- **Rationale:** Field on `XBindingInfo` named `xBindingType` is doubly redundant. - -### 13. `maxResults?: number` — `src/v1/model.ts:35` -- **Why weird:** 12 lines of doc-comment for one field explain its conditional behaviour ("set to 0" / "set to a value greater than 0" / "set to a value less than 0" / "if not set"). The field name `maxResults` doesn't hint at the magic-value semantics. Also, sibling packages use `pageSize` for the same concept (see grants audit #18) — naming inconsistency across the SDK. -- **Category:** 17 (cross-package inconsistency), 6 (misleading: name implies a strict cap but actually has magic-value semantics). -- **Suggested name:** `pageSize` (matching sibling packages) or `pageLength`. Document the magic values via a `@see` link rather than copy-pasting 12 lines. -- **Rationale:** Cross-package consistency. - -### 14. `pageToken?: string` doc — `src/v1/model.ts:36-37` +### 6. `pageToken?: string` doc — `src/v1/model.ts:36-37` - **Why weird:** Doc-comment "Opaque pagination token to go to next page based on previous query" is OK, but in the response side `nextPageToken` (line 45-48) the doc refers to "__page_token__" with double-underscores — a documentation hangover from a wire-format spec. Inconsistent with the TS field name `pageToken`. - **Category:** 6 (misleading docs), Observation. - **Suggested name:** Field name is fine; fix the doc to use TS field name `pageToken`. - **Rationale:** Doc-comment consistency. -### 15. `nextPageToken?: string` — `src/v1/model.ts:48` +### 7. `nextPageToken?: string` — `src/v1/model.ts:48` - **Why weird:** The doc-comment includes `__page_token__` (double-underscore) referring to the request field. The actual TS field is named `pageToken` — the doc is documenting wire format, not TS. - **Category:** 6 (misleading docs). - **Suggested name:** Field name is fine; fix the doc text. -- **Rationale:** See #14. +- **Rationale:** See #6. -### 16. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:75` -- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #3). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 71-74 makes no mention of the generic alternative. +### 8. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:80` +- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #2). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 76-79 makes no mention of the generic alternative. - **Category:** 12 (duplicate concept), Observation. - **Suggested name:** Mark with `@deprecated` JSDoc and reference `getWorkspaceBindings`. - **Rationale:** IDE strike-through requires the `@deprecated` tag. -### 17. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:168` -- **Why weird:** Same as #16. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. +### 9. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:179` +- **Why weird:** Same as #8. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. - **Category:** 12, Observation. - **Suggested name:** Mark with `@deprecated`. -- **Rationale:** See #16. +- **Rationale:** See #8. -### 18. `Client` — `src/v1/client.ts:46` +### 10. `Client` — `src/v1/client.ts:46` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `WorkspaceBindingsClient`. - **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. -### 19. `executeCall` — `src/v1/utils.ts:26` +### 11. `executeCall` — `src/v1/utils.ts:26` - **Why weird:** Generic verb-noun name. Two `execute` functions in scope (`execute` imported on line 4, `executeCall` defined on line 26, `executeHttpCall` defined on line 65). The discriminator between them is just "Call" vs "HttpCall" — and both ultimately wrap the imported `execute()`. - **Category:** 1 (vague), 17 (inconsistent action verbs). - **Suggested name:** `executeRetryableCall` (since this one applies the retrier/rateLimiter/timeout options) or `executeWithOptions`. - **Rationale:** Distinguishes the two wrappers semantically. -### 20. `executeHttpCall` — `src/v1/utils.ts:65` +### 12. `executeHttpCall` — `src/v1/utils.ts:65` - **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `ApiError` on 4xx/5xx (line 88-91) — a non-obvious side effect. - **Category:** 1 (vague), 6 (misleading: "execute" sounds neutral but throws). - **Suggested name:** `sendAndParseResponse` or `sendOrThrow`. - **Rationale:** Naming should hint at error semantics. -### 21. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` +### 13. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` - **Why weird:** Yet another `*Options` suffix in a file that already imports `Options` (line 3) and `CallOptions` (line 12) — three `Options` types in scope. `HttpCallOptions` is purely an internal context bag for `executeHttpCall` (request + httpClient + logger) — it isn't user-tunable, so `Options` is misleading. - **Category:** 1 (vague suffix), 8 (redundant suffix), 17 (inconsistency). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). @@ -157,13 +109,13 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Low severity -### 22. `flattenQueryParams` — `src/v1/utils.ts:123` +### 14. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append` on `client.ts:117-122`). Dead-looking export from the standard generator template. - **Category:** Observation, 11 (unused public helper). - **Suggested name:** Remove if generator default; or move to a shared utility package and not emit per-package. - **Rationale:** Cross-package consistency. -### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 15. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic word; without the inline doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. @@ -173,23 +125,16 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and ## Observations -### 24. Client `Host is required.` error message — `src/v1/client.ts:57` +### 16. Client `Host is required.` error message — `src/v1/client.ts:61` The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. - **Category:** Observation. -### 25. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` +### 17. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` The marshal/unmarshal helpers are exported from `model.ts` (via `export const`) but `index.ts` (lines 7-17) only re-exports types and `Client`. So the schemas are part of the package's effective import surface (`import {...} from '@databricks/sdk-workspacebindings/v1/model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). - **Category:** Observation, 11 (effectively-internal exports). -### 26. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` +### 18. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` The single word "Required" appears as a doc-comment on `workspaceId?: number`. But the field is *optional* in the TypeScript type (`workspaceId?: number | undefined`). The annotation contradicts the type modifier. Either: (a) the field is genuinely required by the server and the optional TS type is generator-wide policy (proto3 fields are all optional in TS); or (b) the doc is stale. Either way, readers can't tell. - **Category:** Observation, 6 (misleading docs). --- - -## Fixed - -- #3 `GetCatalogWorkspaceBindings` (originally cited at `src/v1/model.ts:12`): Fixed in regeneration on 2026-05-20 — renamed to `GetCatalogWorkspaceBindingsRequest` (suffix added). -- #4 `GetWorkspaceBindings` (originally cited at `src/v1/model.ts:23`): Fixed in regeneration on 2026-05-20 — renamed to `GetWorkspaceBindingsRequest` (suffix added). -- #5 `UpdateCatalogWorkspaceBindings` (originally cited at `src/v1/model.ts:51`): Fixed in regeneration on 2026-05-20 — renamed to `UpdateCatalogWorkspaceBindingsRequest` (suffix added). -- #6 `UpdateWorkspaceBindings` (originally cited at `src/v1/model.ts:66`): Fixed in regeneration on 2026-05-20 — renamed to `UpdateWorkspaceBindingsRequest` (suffix added). diff --git a/.agent/naming-audit/workspaceconf.md b/.agent/naming-audit/workspaceconf.md index 17860a22..9ef8bcef 100644 --- a/.agent/naming-audit/workspaceconf.md +++ b/.agent/naming-audit/workspaceconf.md @@ -249,9 +249,3 @@ 5. **Type `keys` as `string[]`** (§5) and have the client serialize the CSV. --- - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspaceobjects.md b/.agent/naming-audit/workspaceobjects.md index 971daf42..8bbca710 100644 --- a/.agent/naming-audit/workspaceobjects.md +++ b/.agent/naming-audit/workspaceobjects.md @@ -6,7 +6,7 @@ notebooks, folders, and files — import, export, delete, list, get-status, and mkdirs against absolute paths under `/Workspace`. Wire prefix: `/api/2.0/workspace/`. -**Total weird names flagged:** 23 +**Total weird names flagged:** 14 ## Scope note: `workspaceobjects` vs sibling packages @@ -27,9 +27,9 @@ others differ in scope: | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 12 | -| Low | 6 | +| High | 3 | +| Medium | 6 | +| Low | 5 | | Observation | 6 | ## Summary table @@ -39,26 +39,17 @@ others differ in scope: | 1 | High | `model.ts:6` enum | `ExportFormat` used as `format` field of `ImportRequest` | Misleading name (an "ExportFormat" governs imports too) | | 2 | High | `model.ts:18` enum value | `ExportFormat.AUTO` | Ambiguous enum value (different behaviour for import vs. export) | | 3 | High | `model.ts:24` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | -| 4 | High | `model.ts:195,199` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | -| 5 | High | `model.ts:28` enum | `Language` | Vague/generic, no domain prefix | -| 6 | Medium | `model.ts:48` enum value | `ObjectType.LIBRARY` | Misleading (workspace libraries are an obsolete concept) | -| 7 | Medium | `model.ts:153` field | `ListRequest.notebooksModifiedAfter` | Field contradicts type domain (list returns all object types, filter only on notebooks) | -| 8 | Medium | `model.ts:92` field | `ExportRequest.directDownload` | Verb-as-noun boolean (toggles response content-type entirely) | -| 9 | Medium | `model.ts:104` field | `ExportRequest_Response.fileType` | Underspecified (extension? MIME? format enum?) | -| 10 | Medium | `model.ts:102` field | `ExportRequest_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | -| 11 | Medium | `model.ts:138` field | `ImportRequest.content` typed `Uint8Array` | Same type/JSDoc mismatch as 10 in reverse direction | -| 12 | Medium | `model.ts:191,193` fields | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Unit ambiguity (epoch millis as `number`), "only applicable to files" | -| 13 | Medium | `model.ts:197` field | `ObjectInfo.size` | Underspecified — no unit in the name (bytes per JSDoc) | -| 14 | Medium | `model.ts:167` field | `MkdirsRequest.path` | Singular/plural mismatch — type plural, field singular | -| 15 | Medium | `model.ts:162` type | `MkdirsRequest` | Unix-ism (`mkdir -p`); sibling `files` package uses `createDirectory` | -| 16 | Medium | `client.ts:157` method | `getStatus` | Vague verb; returns full `ObjectInfo` metadata (a `stat`, not a status) | -| 17 | Medium | `model.ts:66` field | `DeleteRequest.recursive` | Unix flag (`rm -r`); no domain reading | -| 18 | Low | `model.ts:16` enum value | `ExportFormat.R_MARKDOWN` | Shape mismatch — single underscored value among single-token values | -| 19 | Low | `model.ts:14` enum value | `ExportFormat.DBC` | Cryptic product-specific abbreviation (Databricks archive) | -| 20 | Low | `model.ts:174` interface | `ObjectInfo` | `Info` suffix carries no information; central entity is just an "Object" | -| 21 | Low | `model.ts:159` field | `ListRequest_Response.objects` | Generic field name (`objects`) for `ObjectInfo[]` | -| 22 | Low | `client.ts:266` method | `mkdirs` | Lower-case Unix contraction next to other `verbNoun` methods (`getStatus`, `import`, `export`) | -| 23 | Low | `model.ts:17-23` JSDoc | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | +| 4 | High | `model.ts:28` enum | `Language` | Vague/generic, no domain prefix | +| 5 | Medium | `model.ts:48` enum value | `ObjectType.LIBRARY` | Misleading (workspace libraries are an obsolete concept) | +| 6 | Medium | `model.ts:102` field | `ExportRequest_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | +| 7 | Medium | `model.ts:138` field | `ImportRequest.content` typed `Uint8Array` | Same type/JSDoc mismatch as 6 in reverse direction | +| 8 | Medium | `model.ts:162` type | `MkdirsRequest` | Unix-ism (`mkdir -p`); sibling `files` package uses `createDirectory` | +| 9 | Medium | `client.ts:157` method | `getStatus` | Vague verb; returns full `ObjectInfo` metadata (a `stat`, not a status) | +| 10 | Low | `model.ts:16` enum value | `ExportFormat.R_MARKDOWN` | Shape mismatch — single underscored value among single-token values | +| 11 | Low | `model.ts:14` enum value | `ExportFormat.DBC` | Cryptic product-specific abbreviation (Databricks archive) | +| 12 | Low | `model.ts:174` interface | `ObjectInfo` | `Info` suffix carries no information; central entity is just an "Object" | +| 13 | Low | `client.ts:266` method | `mkdirs` | Lower-case Unix contraction next to other `verbNoun` methods (`getStatus`, `import`, `export`) | +| 14 | Low | `model.ts:17-23` JSDoc | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | ## High severity @@ -98,26 +89,7 @@ others differ in scope: server-side roadmap ("In workspace 3.0 folder import will be supported via a different API") that the SDK user does not see. -### 4. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names -- **Location:** `model.ts:194-199` -- **Category:** Duplicate concept; near-identical names hide a real - type/lifetime distinction. -- **Suggested name:** `legacyObjectId` (deprecated, `bigint` or `string` to - preserve precision) and keep `resourceId`. Alternatively - `localObjectId` (workspace-scoped, numeric) and `globalResourceId` - (cross-API, string). Or drop the legacy one and only carry `resourceId`. -- **Rationale:** Two distinct identifiers live on the same `ObjectInfo`, - both documented as "unique identifier for the object," differing only by - the trailing phrase "consistent across all Databricks APIs." The name - pair does not encode the difference — a reader sees `objectId` (number) - and `resourceId` (string) and cannot tell which one to pass into another - Databricks API. Likely truth: `objectId` is the legacy 64-bit numeric - workspace-local ID; `resourceId` is the newer string ID used by the - unified-resource API. The names should encode that distinction. Also: - `objectId` is typed `number` — JS numbers are 64-bit floats and lose - precision above 2^53; the field type should be `bigint` or `string`. - -### 5. `Language` — vague / generic, no domain prefix +### 4. `Language` — vague / generic, no domain prefix - **Location:** `model.ts:28-37` - **Category:** Vague/generic top-level name. - **Suggested name:** `NotebookLanguage`. @@ -130,7 +102,7 @@ others differ in scope: ## Medium severity -### 6. `ObjectType.LIBRARY` — obsolete enum value +### 5. `ObjectType.LIBRARY` — obsolete enum value - **Location:** `model.ts:48` - **Category:** Misleading enum value (encoded concept is obsolete). - **Suggested name:** Keep the name but mark `@deprecated` in JSDoc with a @@ -142,49 +114,7 @@ others differ in scope: ObjectType.LIBRARY)` are coding against a branch the server almost never returns; that is a discoverability hazard. -### 7. `ListRequest.notebooksModifiedAfter` — field contradicts type domain -- **Location:** `model.ts:149-154` -- **Category:** Field contradicts the type it lives on; unit hidden in JSDoc. -- **Suggested name:** `modifiedAfterMillis` (drop the `notebooks` qualifier - and document the asymmetry) or `notebookModifiedAfterMillis` (singular - subject, matching the filter's actual scope) plus an explicit - millisecond suffix. -- **Rationale:** `list` returns all workspace object types — notebooks, - directories, files, repos, dashboards. The filter parameter is named - `notebooksModifiedAfter`, i.e. the filter only applies to objects of - type `NOTEBOOK`. Non-notebook objects are not filtered, so a caller - expecting `modifiedAfter` semantics will see directories whose contents - post-date the supplied cutoff. The asymmetry is invisible from the name. - Also: the unit (milliseconds) lives only in JSDoc; the sibling - `ObjectInfo.createdAt` / `modifiedAt` fields are also `number` without - unit-in-name — see finding 12. - -### 8. `ExportRequest.directDownload` — verb-as-noun boolean -- **Location:** `model.ts:88-92` -- **Category:** Verb-as-noun naming; boolean named like a noun. -- **Suggested name:** `streamBinary`, `responseAsBinary`, or - `returnBytesDirectly` — anything that parses as a boolean adjective. -- **Rationale:** `directDownload` reads as a noun phrase. Booleans - conventionally use `is`/`has`/`should`/`return*` prefixes or adjective - forms. There is also a real semantic problem: when `true`, the server - returns raw bytes; when `false`, the server returns JSON with base64. - Setting `directDownload: true` would make `parseResponse` in `utils.ts` - crash (it does `JSON.parse` unconditionally), so the boolean cannot be - set safely from this client today. The name should at least flag the - fact that the response shape changes. - -### 9. `ExportRequest_Response.fileType` — underspecified -- **Location:** `model.ts:103-105` -- **Category:** Underspecified field — name is one of the most overloaded - strings in software, type is `string`. -- **Suggested name:** `mimeType`, `extension`, or `format: ExportFormat` - (pick one and commit). -- **Rationale:** "The file type" doesn't say in what form — extension - (`.ipynb`)? MIME (`application/x-ipynb+json`)? Enum (`JUPYTER`)? Object - kind (`NOTEBOOK`)? With the field typed as `string`, any of those is - syntactically valid; the user has to read upstream docs to know which. - -### 10. `ExportRequest_Response.content` — type contradicts "base64-encoded" JSDoc +### 6. `ExportRequest_Response.content` — type contradicts "base64-encoded" JSDoc - **Location:** `model.ts:98-102`; decoded via `marshalSchema` transform at `model.ts:211-213`. - **Category:** Type/JSDoc mismatch. @@ -197,59 +127,19 @@ others differ in scope: updated for the post-decode shape. "Uint8Array of base64-encoded data" is technically meaningless. -### 11. `ImportRequest.content` — type contradicts "base64-encoded" JSDoc +### 7. `ImportRequest.content` — type contradicts "base64-encoded" JSDoc - **Location:** `model.ts:132-138`; encoded via `marshalSchema` transform at `model.ts:276-281`. -- **Category:** Type/JSDoc mismatch (mirror of 10). +- **Category:** Type/JSDoc mismatch (mirror of 6). - **Suggested name:** Keep the name; fix the JSDoc to say "Raw bytes; the client base64-encodes before sending." -- **Rationale:** The mirror of finding 10 in the reverse direction. The +- **Rationale:** The mirror of finding 6 in the reverse direction. The client encodes the bytes to base64 before sending. A defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. The mismatch is silent and the failure mode is data corruption. -### 12. `ObjectInfo.createdAt` / `modifiedAt` — unit ambiguity, `number` precision -- **Location:** `model.ts:190-193` -- **Category:** Underspecified unit; precision; conditional applicability - hidden in JSDoc. -- **Suggested name:** `createdAtMillis` / `modifiedAtMillis`, or migrate - the values to `Temporal.Instant` (the package already depends on - `@js-temporal/polyfill`). -- **Rationale:** Two issues. (a) The `At` suffix is TS-friendly, but the - type is `number` with no unit in the name — milliseconds vs. seconds is - documented only as "UTC timestamp" in JSDoc, which does not commit. The - sibling `ListRequest.notebooksModifiedAfter` is documented as - milliseconds; one infers consistency, but the type does not say so. (b) - "Only applicable to files" — `ObjectInfo` covers all object types - (notebooks, directories, files, repos, dashboards), so the field is - silently empty for most rows. Encoding partial applicability via - JSDoc is a smell; the field shape doesn't change based on `objectType`. - -### 13. `ObjectInfo.size` — underspecified, unit-less -- **Location:** `model.ts:196-197` -- **Category:** Underspecified field — name has no unit. -- **Suggested name:** `sizeBytes` (matches Databricks convention used in - `clusters.clusterMemoryMb`, `pipelines.storageBytes`, etc.). -- **Rationale:** `size` is unit-less. JSDoc says "file size in bytes can - be returned" — "can be" is ambiguous (always for files? sometimes?). - At scale-up time (>4 GiB on a 64-bit count) `number` precision is fine, - but `bigint` or `string` is safer for true byte counters approaching - 2^53. The field also shares the "only applicable to files" caveat from - finding 12. - -### 14. `MkdirsRequest.path` — singular/plural mismatch with the type name -- **Location:** `model.ts:162-168` -- **Category:** Singular/plural mismatch between containing type and field. -- **Suggested name:** `directoryPath` (singular) on the type, and rename - the type itself per finding 15. -- **Rationale:** The type's verb is plural (`Mkdirs` — "make directories"), - but it takes one path. The Unix `mkdir -p` pluralization comes from - "create the directory and any missing parent directories," but the API - input is a single path. A user reading `MkdirsRequest` reasonably - expects to pass an array. - -### 15. `MkdirsRequest` — Unix-ism +### 8. `MkdirsRequest` — Unix-ism - **Location:** `model.ts:162` (type), `client.ts:266` (method). - **Category:** Cryptic Unix abbreviation, cross-package inconsistency. - **Suggested name:** `CreateDirectoryRequest`. @@ -260,7 +150,7 @@ others differ in scope: the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the request body holds one path, so even the wire name is misleading. -### 16. `getStatus` — vague verb on the client +### 9. `getStatus` — vague verb on the client - **Location:** `client.ts:157` - **Category:** Vague verb; misleading category (returns metadata, not a status enum); inconsistent return shape vs. peer methods. @@ -273,23 +163,11 @@ others differ in scope: `Promise` while `list` returns `Promise` (wrapper). One returns the bare entity, the other returns a wrapper — inconsistent shape across the same - client; see finding 21 too. - -### 17. `DeleteRequest.recursive` — Unix flag, no domain reading -- **Location:** `model.ts:61-66` -- **Category:** Unix-style flag name without domain meaning; understates - destructiveness. -- **Suggested name:** `deleteContents` or `force`. -- **Rationale:** `recursive` is a verbatim port of `rm -r`. For a - single-object delete, "recursive" only matters when the path is a - directory. The flag would read better as `deleteContents` (descriptive) - or `force` (matches the destructive intent). The JSDoc even admits the - deletion is non-atomic ("Please note this deleting directory is not - atomic"), a meaningful caveat hidden behind a one-word Unix flag. + client. ## Low severity -### 18. `ExportFormat.R_MARKDOWN` — shape mismatch within the enum +### 10. `ExportFormat.R_MARKDOWN` — shape mismatch within the enum - **Location:** `model.ts:15-16` - **Category:** Inconsistent shape inside an enum (most values single token, one with an underscore). @@ -300,7 +178,7 @@ others differ in scope: `R_MARKDOWN` with an underscore. Inconsistent shape inside the same enum. -### 19. `ExportFormat.DBC` — cryptic abbreviation +### 11. `ExportFormat.DBC` — cryptic abbreviation - **Location:** `model.ts:13-14` - **Category:** Cryptic product-specific abbreviation. - **Suggested name:** `DATABRICKS_ARCHIVE` on the TS identifier; the wire @@ -310,7 +188,7 @@ others differ in scope: expects) means the rename must happen on the enum-key layer, not the enum-value layer — TypeScript supports that cleanly. -### 20. `ObjectInfo` — `Info` suffix +### 12. `ObjectInfo` — `Info` suffix - **Location:** `model.ts:174-200` - **Category:** Vague suffix; Go/Java convention carried into TS without reason. @@ -323,16 +201,7 @@ others differ in scope: a hat-tip to the Go SDK. A name like `WorkspaceObject` would also avoid the JS `Object` collision. -### 21. `ListRequest_Response.objects` — generic field for `ObjectInfo[]` -- **Location:** `model.ts:157-160` -- **Category:** Generic field name on a wrapper type. -- **Suggested name:** `items`, `entries`, or `workspaceObjects`. -- **Rationale:** `objects` is the most generic noun in JavaScript; the - reader gets no scope information. `resp.objects` reads like "the - objects of the response" rather than "the workspace objects under the - listed path." A more specific name would convey scope. - -### 22. `mkdirs` client method — Unix contraction next to verb-noun siblings +### 13. `mkdirs` client method — Unix contraction next to verb-noun siblings - **Location:** `client.ts:266` - **Category:** Verb-tense / shape inconsistency among sibling methods. - **Suggested name:** `createDirectory`. @@ -341,7 +210,7 @@ others differ in scope: `mkdirs` is the only Unix-style contraction. `createDirectory` would align with `getStatus` and with the `files` package convention. -### 23. First-person and ticket-driven prose in JSDoc +### 14. First-person and ticket-driven prose in JSDoc - **Location:** `model.ts:17` ("We will inspect the content of the payload to determine the type"); `model.ts:19-23` ("This is introduced to unblock a DR use case importing .zip file as is. … In workspace 3.0 @@ -370,8 +239,7 @@ others differ in scope: 2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) and `ObjectInfo.resourceId` (string, unified-resource) are both returned, both documented as "unique identifier for the object," with - no naming clue about which one to pass where. This is the single most - user-hostile naming issue in the file (also flagged as finding 4). + no naming clue about which one to pass where. 3. **`ExportFormat` is the import format.** The single enum services both `ImportRequest` and `ExportRequest` (good — DRY), but the name says diff --git a/.agent/naming-audit/workspaces.md b/.agent/naming-audit/workspaces.md index 2adbd83d..2c61092f 100644 --- a/.agent/naming-audit/workspaces.md +++ b/.agent/naming-audit/workspaces.md @@ -5,7 +5,7 @@ **Inferred domain:** Account-level Databricks workspace management (create/get/list/update/delete a workspace under an account, with all its cloud, network, storage, and encryption configuration). -**Total weird names flagged:** 5 +**Total weird names flagged:** 4 This audit is scoped to proto-architectural-leak naming (mid-position `Public`/`Internal`/`External`, `Proto` suffix/infix, architectural-layer @@ -18,7 +18,7 @@ words such as `Service`/`Manager`/`Wrapper`, `Impl`, `Rpc`/`Grpc`, | Severity | Count | | ------------ | ----- | -| High | 5 | +| High | 4 | | Medium | 0 | | Low | 0 | | Observation | 0 | @@ -26,28 +26,14 @@ words such as `Service`/`Manager`/`Wrapper`, `Impl`, `Rpc`/`Grpc`, The remaining findings all cluster around the `Public` mid-position infix on the client surface — the upstream proto/service "Public" vs internal-route split still leaks into the `Client` methods, the two -waiter classes, the `customerFacingWorkspace` field on -`UpdateWorkspaceRequest`, and the corresponding imports / re-exports. +waiter classes, and the corresponding imports / re-exports. The model-side `Public` / `CustomerFacing` infixes on the request, response, container, and enum types have all been removed; see the `Fixed` section below. ## High severity -### 1. `customerFacingWorkspace` field on `UpdateWorkspaceRequest` — `src/v1/model.ts:245` -- **Why weird:** Field name embeds the `CustomerFacing` qualifier even - though the referenced type has been renamed to `Workspace`. The field - is the only field of this request body — a plain `workspace` field - carries the meaning fully. -- **Category:** Proto-architectural leak — `CustomerFacing` mid-position - qualifier (field name mirroring the proto qualifier of the type that - has since been renamed). -- **Suggested:** `workspace`. -- **Rationale:** Field names should describe the role of the value in - the request, not echo the upstream proto qualifier. The type has - already been renamed; the field name should follow. - -### 2. `Client.createWorkspacePublic` / `createWorkspacePublicWaiter` — `src/v1/client.ts:88,113` +### 1. `Client.createWorkspacePublic` / `createWorkspacePublicWaiter` — `src/v1/client.ts:88,113` - **Why weird:** `Client` method names end in `Public`. Reads as "the method on the public class that calls the public endpoint" — the suffix only exists because the underlying proto/spec uses `Public` @@ -59,16 +45,16 @@ response, container, and enum types have all been removed; see the - **Rationale:** Methods on `Client` are inherently public; the suffix is meaningless to a TS caller. -### 3. `Client.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` / `updateWorkspacePublicWaiter` — `src/v1/client.ts:127,155,180,210,250` +### 2. `Client.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` / `updateWorkspacePublicWaiter` — `src/v1/client.ts:127,155,180,210,250` - **Why weird:** Same `Public` suffix on every other `Client` method - (and the update waiter factory) as #2. + (and the update waiter factory) as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `deleteWorkspace`, `getWorkspace`, `listWorkspaces`, `updateWorkspace`, `updateWorkspaceWaiter`. -- **Rationale:** Same as #2. +- **Rationale:** Same as #1. -### 4. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:264,344` +### 3. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:264,344` - **Why weird:** Two exported waiter classes carry the `Public` infix between the verb (`Create`/`Update`) and the noun (`Workspace`) plus the `Waiter` role suffix. The class names are wholly SDK-side @@ -80,13 +66,13 @@ response, container, and enum types have all been removed; see the - **Rationale:** Waiter classes are TS-only constructs; they have no business carrying the upstream proto's public/internal qualifier. -### 5. `Public` imports in `client.ts` and the `index.ts` re-export list — `src/v1/client.ts:31-36`, `src/v1/index.ts:5-7` +### 4. `Public` imports in `client.ts` and the `index.ts` re-export list — `src/v1/client.ts:31-36`, `src/v1/index.ts:5-7` - **Why weird:** Both files mirror the leaked `Public` names from the waiter classes in their import / re-export lists: `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter`. - **Category:** Proto-architectural leak — `Public` mid-position (import & re-export mirror). -- **Suggested:** Track the renames of #2–#4. +- **Suggested:** Track the renames of #1–#3. - **Rationale:** Re-export and import statements inherit the leaked names verbatim; nothing to do here independent of the upstream renames. @@ -144,8 +130,7 @@ Type & symbol checklist: - [x] `ListWorkspacesResponse` interface — clean (renamed from `ListWorkspacesPublicResponse`). - [x] `UpdateWorkspaceRequest` interface — clean as a type name (renamed - from `UpdateWorkspacePublicRequest`); `customerFacingWorkspace` field - on it flagged (#1). + from `UpdateWorkspacePublicRequest`). - [x] `Workspace` interface — clean (renamed from `CustomerFacingWorkspace`). - [x] `Workspace_CustomTagsEntry` interface — clean (renamed from `CustomerFacingWorkspace_CustomTagsEntry`). @@ -181,15 +166,15 @@ Type & symbol checklist: - [x] `Client` class itself — clean (terminal-position `Client` is the standard SDK convention). - [x] `Client.createWorkspacePublic` + `createWorkspacePublicWaiter` — - flagged (#2). + flagged (#1). - [x] `Client.deleteWorkspacePublic`, `getWorkspacePublic`, `listWorkspacesPublic`, `updateWorkspacePublic`, - `updateWorkspacePublicWaiter` — flagged (#3). + `updateWorkspacePublicWaiter` — flagged (#2). - [x] `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter` - classes — flagged (#4). + classes — flagged (#3). - [x] `StillRunningError` private sentinel class — clean (cross-package pattern; not a domain identifier). -- [x] `client.ts` import list / `index.ts` re-exports — flagged (#5). +- [x] `client.ts` import list / `index.ts` re-exports — flagged (#4). - [x] `utils.ts` (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) — no proto-architectural-leak names. (The @@ -199,53 +184,3 @@ Type & symbol checklist: `Public`/`Internal`/`Proto`/`Service`/`Manager` leak in domain identifiers. (The auth wrapper class itself is a cross-package pattern, not flagged here.) - -## Fixed - -### 1. `CreateWorkspacePublicRequest` → `CreateWorkspaceRequest` -Fixed in regeneration on 2026-05-22. - -### 2. `CreateWorkspacePublicRequest_CustomTagsEntry` → `CreateWorkspaceRequest_CustomTagsEntry` -Fixed in regeneration on 2026-05-22. - -### 3. `DeleteWorkspacePublicRequest` → `DeleteWorkspaceRequest` -Fixed in regeneration on 2026-05-22. - -### 4. `GetWorkspacePublicRequest` → `GetWorkspaceRequest` -Fixed in regeneration on 2026-05-22. - -### 5. `ListWorkspacesPublicRequest` → `ListWorkspacesRequest` -Fixed in regeneration on 2026-05-22. - -### 6. `ListWorkspacesPublicResponse` → `ListWorkspacesResponse` -Fixed in regeneration on 2026-05-22. - -### 7. `UpdateWorkspacePublicRequest` → `UpdateWorkspaceRequest` -Fixed in regeneration on 2026-05-22. - -### 8. `PublicPricingTier` → `PricingTier` -Fixed in regeneration on 2026-05-22. - -### 9. `CustomerFacingComputeMode` → `ComputeMode` -Fixed in regeneration on 2026-05-22. - -### 10. `CustomerFacingStorageMode` → `StorageMode` -Fixed in regeneration on 2026-05-22. - -### 11. `CustomerFacingCloudResourceContainer` → `CloudResourceContainer` -Fixed in regeneration on 2026-05-22. - -### 12. `CustomerFacingGcpCloudResourceContainer` → `GcpCloudResourceContainer` -Fixed in regeneration on 2026-05-22. - -### 13. `CustomerFacingWorkspace` → `Workspace` -Fixed in regeneration on 2026-05-22. - -### 14. `CustomerFacingWorkspace_CustomTagsEntry` → `Workspace_CustomTagsEntry` -Fixed in regeneration on 2026-05-22. - -### 15. `marshalCreateWorkspacePublicRequestSchema` → `marshalCreateWorkspaceRequestSchema` -Fixed in regeneration on 2026-05-22. - -### 16. `unmarshalCustomerFacing*Schema` / `marshalCustomerFacing*Schema` (six schemas) → `unmarshalWorkspaceSchema`, `marshalWorkspaceSchema`, `unmarshalCloudResourceContainerSchema`, `marshalCloudResourceContainerSchema`, `unmarshalGcpCloudResourceContainerSchema`, `marshalGcpCloudResourceContainerSchema` -Fixed in regeneration on 2026-05-22. diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md index 6fc01e79..e719aae3 100644 --- a/.agent/naming-audit/workspacesettings.md +++ b/.agent/naming-audit/workspacesettings.md @@ -373,9 +373,3 @@ 8. **Proto-architectural-leak through `Message` suffix and `Parent_Nested` infix.** Top-level types `BooleanMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage` and the seven `*_Message_*` nested types expose the proto-generated naming convention directly to consumers. The codebase already acknowledges the leak via `eslint-disable -- Proto-style nested message name.` annotations on every such identifier. Generic `Details` suffix on `EnablementDetails` is the same pattern. (Severities #43, #44, #45.) --- - -## Fixed - -All previous findings are obsolete: the package source was removed in the 2026-05-22 regen. See the status block at the top of this file. - -Fixed in regeneration on 2026-05-22. diff --git a/AGENTS.md b/AGENTS.md index 0c9f90de..9d6f2060 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -115,6 +115,47 @@ npm run clean description, follow the workflow in `.agent/skills/write-pr-description.mdc`. +## Long-Running Command TODO List + +Because this repository is large, individual user-issued commands +(e.g., audit rescans, theme prunes, batched renames) can take +multiple agent rounds to complete. To avoid losing track across long +sessions, every such command is logged in a TODO list at the top of +this section before any subagent is dispatched, and the entry is +deleted only after the command finishes end-to-end (including any +synthesis step that updates `_SUMMARY.md` or similar). + +### Protocol + +1. **When the user issues a command** (e.g., "rescan the audit", + "prune Theme N", "rebase and rerun"), the assistant first appends + a one-line entry to the **`### Active TODOs`** section below + (before any subagent is dispatched). The entry captures the + verbatim command, the date received, and a short status note. +2. **The assistant then dispatches the subagents** required to + execute the command per the relevant workflow (Workflow A / B / C + in `## Naming Audit Maintenance`, or another workflow as + applicable). +3. **After all subagents finish and any synthesis step completes**, + the assistant deletes the entry from `### Active TODOs`. If the + command is partially complete (e.g., user paused mid-execution), + the entry stays with an updated status note (`paused 2026-05-26 + after batch 1/3`). +4. **The next user command starts the cycle again** — append, then + dispatch, then delete on completion. Only one command is + in-flight at a time; the assistant does not start a new entry + while a prior entry is still active unless the user explicitly + asks for it. + +### Active TODOs + +- 2026-05-26 — rebase + rerun audit on updated branch — rescan done (87/87 pkgs: 1 fix in logdelivery, rest still); `_SUMMARY.md` synthesis pending, will roll into the next cleanup synthesis. +- 2026-05-26 — collapse retired/orphan audit bodies to just the title + status block (example given: `qualitymonitors`) — in progress. +- 2026-05-26 — prune findings whose primary recommendation is a JSDoc/doc change (example: `apps.md` H9 `noCompute` doc clarification). Reason: "those can be anytime." — in progress. + +(When populated, each line is one TODO in the form: +`- YYYY-MM-DD — `.) + ## Naming Audit Maintenance The naming audit lives at `.agent/naming-audit/`: From 28644b67c81e57112837054e137c1c9071ad3581 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 26 May 2026 21:40:07 +0000 Subject: [PATCH 07/12] update --- .agent/naming-audit/accessmanagement.md | 61 +- .agent/naming-audit/accountaccesscontrol.md | 133 +- .../naming-audit/accountaccesscontrolproxy.md | 47 +- .agent/naming-audit/accountsettings.md | 349 +----- .agent/naming-audit/alerts.md | 77 +- .agent/naming-audit/apps.md | 71 +- .agent/naming-audit/budgetpolicy.md | 74 +- .agent/naming-audit/budgets.md | 74 +- .agent/naming-audit/catalogs.md | 31 +- .agent/naming-audit/cleanroomassets.md | 137 +-- .../cleanroomautoapprovalrules.md | 44 +- .agent/naming-audit/cleanrooms.md | 15 +- .agent/naming-audit/cleanroomtaskruns.md | 309 +---- .agent/naming-audit/clusterlibraries.md | 30 +- .agent/naming-audit/clusterpolicies.md | 5 +- .agent/naming-audit/commandexecution.md | 76 +- .agent/naming-audit/connections.md | 38 +- .agent/naming-audit/dataquality.md | 42 +- .agent/naming-audit/endpoints.md | 1082 +---------------- .agent/naming-audit/indexes.md | 223 +--- .../naming-audit/logdeliveryconfigurations.md | 327 +---- .agent/naming-audit/materializedfeatures.md | 715 +---------- .agent/naming-audit/modelservingdebug.md | 315 +---- .agent/naming-audit/modelservingmanagement.md | 353 +----- .../naming-audit/oauthcustomappintegration.md | 143 +-- .agent/naming-audit/oauthpublishedapp.md | 114 +- .agent/naming-audit/permissions.md | 234 +--- .agent/naming-audit/qualitymonitor.md | 188 +-- .agent/naming-audit/qualitymonitors.md | 351 +----- .agent/naming-audit/queryexecution.md | 51 +- .../naming-audit/serviceprincipalsecrets.md | 43 +- .agent/naming-audit/workspace.md | 485 +------- .agent/naming-audit/workspaceassignment.md | 177 +-- .agent/naming-audit/workspaceconf.md | 250 +--- .agent/naming-audit/workspacesettings.md | 374 +----- 35 files changed, 178 insertions(+), 6860 deletions(-) diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md index 3ad28122..35c27e31 100644 --- a/.agent/naming-audit/accessmanagement.md +++ b/.agent/naming-audit/accessmanagement.md @@ -16,12 +16,12 @@ the `USER`/`ADMIN` role a principal holds on a workspace (d) the `checkPolicy` resource-access policy decision endpoint. Originated from `permissions`, `workspaceassignment`, `accountaccesscontrol`, and `accountaccesscontrolproxy` during the 2026-05-22 regeneration. -**Total weird names flagged:** 32 +**Total weird names flagged:** 31 ## Summary | Severity | Count | | --- | --- | -| High | 8 | +| High | 7 | | Medium | 11 | | Low | 9 | | Observation | 4 | @@ -76,20 +76,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `PermissionLevel.MANAGE` is shorter and just as unambiguous as `PermissionLevel.CAN_MANAGE`. -### 2. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` -- **Why weird:** Two distinct values that differ in name only by the - `_ONLY` suffix. There is no JSDoc on either, so a developer cannot tell - from the names alone whether the difference is access-scope, a subset - relationship, or a separate role. -- **Category:** Misleading enum-pair; within-enum inconsistency (`_ONLY` - qualifier appears nowhere else in this enum). -- **Suggested name:** Document inline what the difference is, OR rename to - a pair like `MONITOR_FULL` / `MONITOR_READ_ONLY` where the contrast is on - the predicate, not on a vague `_ONLY` qualifier. -- **Rationale:** Whenever an enum exposes `X` and `X_ONLY` with no JSDoc, - every caller hits a Stack Overflow question. - -### 3. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:17,18,26` +### 2. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:17,18,26` - **Why weird:** Three values are specific to one object type each (`registered-models` in MLflow Model Registry, and Databricks Apps), but live in a universal `PermissionLevel` enum applicable to 25+ object @@ -107,7 +94,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum discoverability hazard; users browsing autocomplete will see these as valid choices for clusters, jobs, and dashboards. -### 4. `RequestAuthzIdentity` enum and `REQUEST_AUTHZ_IDENTITY_*` member prefix; `Authz` truncation — `src/v1/model.ts:33-37` +### 3. `RequestAuthzIdentity` enum and `REQUEST_AUTHZ_IDENTITY_*` member prefix; `Authz` truncation — `src/v1/model.ts:33-37` - **Why weird:** The type name starts with `Request` — a wire-format message prefix (`RequestAuthzIdentity` reads as "the AuthzIdentity field on a request message"). The mid-name truncation `Authz` (instead of @@ -126,7 +113,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum containing `CheckPolicyRequest`. The `Authz` truncation is fine in code comments but jars on a public, exported enum. -### 5. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:156,163,340,348` +### 4. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:156,163,340,348` - **Why weird:** Every request type carries `requestObjectType?: string | undefined`. The JSDoc on each occurrence lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, @@ -148,7 +135,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum package. The Go SDK uses `string` because Go enums are second-class; TS has first-class string literal unions that match this exact use case. -### 6. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` +### 5. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` - **Why weird:** Three methods carry the `Proxy` suffix and are byte-for-byte identical to their non-`Proxy` siblings (lines 218, 292, 366). They issue the same HTTP request to the same URL with the same @@ -167,7 +154,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum does, not how the server routes it. Two identical methods with a `Proxy` differentiator force every caller to flip a coin. -### 7. `WorkspacePermission.UNKNOWN` zero-value sentinel — `src/v1/model.ts:40` +### 6. `WorkspacePermission.UNKNOWN` zero-value sentinel — `src/v1/model.ts:40` - **Why weird:** `WorkspacePermission` uses `UNKNOWN` as its zero-value sentinel, but the sibling enum `RequestAuthzIdentity` in the same file uses the `*_UNSPECIFIED` form (`REQUEST_AUTHZ_IDENTITY_UNSPECIFIED`, @@ -180,7 +167,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Same-file inconsistency is the worst kind. Aligning with the rest of the file (and the rest of the SDK) costs nothing. -### 8. `Client` — `src/v1/client.ts:69` +### 7. `Client` — `src/v1/client.ts:69` - **Why weird:** Top-level class named `Client`. Generic across every generated package. The merger makes this worse: this class now exposes the *combined* surface of four formerly-distinct services @@ -201,7 +188,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum ## Medium severity -### 9. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:306,322` +### 8. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:306,322` - **Why weird:** `RuleSet` and `RuleSetUpdateRequest` are structurally identical (`name`, `etag`, `grantRules`). They model the same resource — one as a response body, one as the update body — but expose it under two @@ -218,7 +205,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum divergence. Proto generates separate types because Go does not have structural typing; in TypeScript the duplication is wasteful. -### 10. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:354-360` +### 9. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:354-360` - **Why weird:** `UpdateRuleSetRequest` has both a top-level `name` and `ruleSet.name` (because `RuleSetUpdateRequest` also carries `name`). Two `name` fields on the same request that conceptually identify the same @@ -232,7 +219,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum rule set."). Developers will set one and not the other and silently 4xx. -### 11. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:227,302` +### 10. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:227,302` - **Why weird:** The package exports a `Role` type and then immediately ignores it: `GrantRule.role` is `string`. So `Role` is the response shape from `getAssignableRolesForResource`, but `GrantRule.role` is the @@ -244,7 +231,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Developers will write `grantRule.role = role.name` constantly because the types don't line up. -### 12. `GetAssignableRolesForResource*` verbosity and verb shape — `src/v1/model.ts:134,150`, `src/v1/client.ts:218` +### 11. `GetAssignableRolesForResource*` verbosity and verb shape — `src/v1/model.ts:134,150`, `src/v1/client.ts:218` - **Why weird:** 41-character type names. The "ForResource" suffix is implied — every assignable-roles query is for a resource. The pair reads like a Java RPC service name (`GetForRequest`). @@ -258,7 +245,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `Get...`, but the operation returns an array and is closer to a list semantically. -### 13. `GrantRule.principals: string[]` is an untyped principal-format list — `src/v1/model.ts:225` +### 12. `GrantRule.principals: string[]` is an untyped principal-format list — `src/v1/model.ts:225` - **Why weird:** Generic `string[]` for principals, where each entry is one of three formats (`users/`, `groups/`, `servicePrincipals/`). The shape is @@ -270,7 +257,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** TypeScript can encode this; the Go SDK cannot. The 1:1 port leaves type information on the floor. -### 14. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` +### 13. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` - **Why weird:** Four types use the proto-style nested-message underscore convention: `DeleteWorkspacePermissionAssignmentRequest_Response`, `GetPermissionLevelsRequest_Response`, @@ -293,7 +280,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** TypeScript has no concept of nested message types; the underscore separator is a proto-specific path encoding. -### 15. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` +### 14. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` - **Why weird:** Three types ending with `Output`. In proto / gRPC service definitions, message types are commonly named `FooInput` (request) and `FooOutput` (response) — the `Output` suffix is the @@ -309,7 +296,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Compare `principal: PrincipalOutput` to `principal: Principal` — the latter reads as plain English. -### 16. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:244` +### 15. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:244` - **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance is really an "effective permission" — a permission level paired with @@ -326,7 +313,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum common across IAM systems that it's nearly content-free without qualification. -### 17. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:256` +### 16. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:256` - **Why weird:** Type carries `permissionLevel?: PermissionLevel` (singular) and `description?: string`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. @@ -335,7 +322,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `PermissionLevelInfo`. - **Rationale:** One descriptor = one level; the type name should match. -### 18. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:261` +### 17. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:261` - **Why weird:** Returned from three different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, @@ -348,7 +335,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental. -### 19. `Actor.kind` discriminated-union with a single variant — `src/v1/model.ts:95-97` +### 18. `Actor.kind` discriminated-union with a single variant — `src/v1/model.ts:95-97` - **Why weird:** `Actor.kind?: { $case: 'actorId'; actorId: number } | undefined` — the `kind` field name is a direct port of the proto `oneof kind { ... }` block convention. With a single-variant union @@ -366,7 +353,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum ## Low severity -### 20. `etag` casing — `src/v1/model.ts:199,318,334` +### 19. `etag` casing — `src/v1/model.ts:199,318,334` - **Why weird:** Lowercase `etag` (rather than `eTag`/`ETag`). HTTP spec uses `ETag`. Per the project-wide acronym policy (Google TS `Pascal-then-lower`), the form would be `etag`/`Etag` depending on @@ -377,7 +364,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum most likely correct per Google TS rules. - **Rationale:** Defer to global policy. -### 21. `flattenQueryParams` exported but rarely consumed — `src/v1/utils.ts:123` +### 20. `flattenQueryParams` exported but rarely consumed — `src/v1/utils.ts:123` - **Why weird:** Used only by `checkPolicy` (`client.ts:536,545,555`). The helper is identical across packages and should live in a shared `@databricks/sdk-core` module rather than be re-emitted per package. @@ -388,7 +375,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Generator emits the same helper into every package; consolidation reduces surface. -### 22. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` +### 21. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` - **Why weird:** The package imports `CallOptions` from `@databricks/sdk-options/call` (line 12) and defines its own `HttpCallOptions` here. The names suggest the latter is a @@ -401,7 +388,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 23. `readAll` is a Go-port utility name — `src/v1/utils.ts:40` +### 22. `readAll` is a Go-port utility name — `src/v1/utils.ts:40` - **Why weird:** Direct Go-port of `io.ReadAll`; clashes cognitively with `Array.prototype` methods and Web Streams APIs. Generator-wide. - **Category:** Vague; Go-port style. @@ -409,7 +396,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `bufferStream`. - **Rationale:** Cross-package consistency. -### 24. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` +### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` - **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. diff --git a/.agent/naming-audit/accountaccesscontrol.md b/.agent/naming-audit/accountaccesscontrol.md index b7591730..f11ed73d 100644 --- a/.agent/naming-audit/accountaccesscontrol.md +++ b/.agent/naming-audit/accountaccesscontrol.md @@ -1,134 +1,3 @@ # Naming Audit: accountaccesscontrol -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/accountaccesscontrol/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Account-level Databricks IAM rule sets — list assignable roles for a resource and read/replace the grant rules attached to that resource. -**Total weird names flagged:** 16 - -## Summary -| Severity | Count | -| --- | --- | -| High | 3 | -| Medium | 7 | -| Low | 4 | -| Observation | 2 | - -## High severity - -### 1. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:73,89` -- **Why weird:** `RuleSet` and `RuleSetUpdateRequest` are structurally identical (`name`, `etag`, `grantRules`). They model the same resource — one as a response body, one as the update body — but expose it under two top-level names. `UpdateRuleSetRequest` then *wraps* `RuleSetUpdateRequest` under a `ruleSet` field, so the developer sees three overlapping shapes (`RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest`) for one concept. The "Request" suffix on the inner body type does not match how the field is used downstream (the wire payload is keyed `rule_set`, not `rule_set_update_request`). -- **Category:** 12, 11 (duplicate concepts; redundant wrapper) -- **Suggested name:** Collapse to `RuleSet` only. The update endpoint body should be `{ name, ruleSet: RuleSet }`. Remove `RuleSetUpdateRequest` entirely. -- **Rationale:** A single canonical `RuleSet` shape avoids the read/write divergence. The legacy upstream uses `RuleSetResponse` and `RuleSetUpdateRequest` as separate types because Go does not have structural typing; in TypeScript the duplication is wasteful and confusing. - -### 2. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:105` -- **Why weird:** `UpdateRuleSetRequest` has both a top-level `name` and `ruleSet.name` (because `RuleSetUpdateRequest` also carries `name`). Two `name` fields on the same request that conceptually identify the same thing is a footgun — which one wins? The wire format hints that the outer one is the URL path identifier and the inner one is the body, but nothing in the TS type encodes that. -- **Category:** 6, 16 (misleading; field contradicting type domain) -- **Suggested name:** Drop the outer `name` (use it from `ruleSet.name`), or rename the outer to `pathName`/`resourceName` to make the routing role explicit. -- **Rationale:** The doc comment on the outer field is just "Name of the rule set." — identical to the inner one. Developers will set one and not the other and silently 4xx. - -### 3. `GetRuleSetRequest.etag` semantics — `src/v1/model.ts:25` -- **Why weird:** A `GET` request type carrying an `etag` is unusual — `etag` normally rides in headers (`If-Match`/`If-None-Match`) and the field doc describes optimistic concurrency control on PUT, not GET. The field is also marshalled into the query string here (`params.append('etag', req.etag)` in `client.ts:118`), which is non-standard HTTP and easy to misuse. The name `etag` is also lowercase, contradicting common practice (`eTag`/`ETag`). The same doc text on `RuleSet.etag` then describes its read use ("freshness"). -- **Category:** 3, 6 (acronym casing; misleading) -- **Suggested name:** `minimumEtag` or `ifNoneMatch` would explain semantics; keep canonical casing as `etag` only if it matches the wire param exactly. At minimum, the doc should say "passed as `?etag=` query parameter; the server returns a snapshot at least as fresh as this etag" rather than copy-pasting the PUT-side concurrency doc. -- **Rationale:** The current name plus copy-pasted comment makes the field look like an `If-Match` header even though it is a freshness floor on GET. - -## Medium severity - -### 4. `accountId` doc string ` account ID.` — `src/v1/model.ts:7,27,107` -- **Why weird:** The literal `` tag appears in the doc comments, leaking the upstream protobuf templating markup into the public TypeScript surface. It is not Markdown, not a link, and not HTML — just stray angle brackets that will render oddly in IDE hover popups and TypeDoc. The same `accountId` doc text also doesn't disclose that this value is a fallback overridable by `ClientOptions.accountId` (per the client comment on line 41-42 of `client.ts`). -- **Category:** 14, 19 (Go/Java-style template leak; underspecified ID) -- **Suggested name:** Keep `accountId` but rewrite the doc as `"Databricks account ID. If omitted, falls back to the value supplied to ClientOptions."` -- **Rationale:** Document the type — UUID? — and remove the templating artifact. - -### 5. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:65` -- **Why weird:** The package exports a `Role` type and then immediately ignores it: `GrantRule.role` is `string`. So `Role` is the response shape from `getAssignableRolesForResource`, but `GrantRule.role` is the same identifier path serialized inline. Two representations of the same concept. -- **Category:** 12, 6 (duplicate concepts; misleading) -- **Suggested name:** Type `GrantRule.role` as `Role['name']` or a branded `RoleName` string so the two surfaces stay aligned. -- **Rationale:** Developers will write `grantRule.role = role.name` constantly because the types don't line up. - -### 6. `GetAssignableRolesForResourceRequest` / `Response` verbosity — `src/v1/model.ts:5,21` -- **Why weird:** 41 characters each. The "ForResource" suffix is implied — every assignable-roles query is for a resource (the resource is the only meaningful query param). The pair reads like a Java RPC service name (`GetForRequest`). -- **Category:** 7, 17 (overly verbose; inconsistent verb) -- **Suggested name:** `ListAssignableRolesRequest` / `ListAssignableRolesResponse`. Reflects that the operation returns a list (it already does), and aligns with REST list conventions. -- **Rationale:** Symmetry with `GetRuleSet`/`UpdateRuleSet` would suggest `Get...`, but the operation returns an array and is closer to a list semantically. Also: the corresponding method is named `getAssignableRolesForResource`, which has the same problem — `listAssignableRoles` would be cleaner. - -### 7. `getAssignableRolesForResource` method verb mismatch — `src/v1/client.ts:72` -- **Why weird:** The other two methods (`getRuleSet`, `updateRuleSet`) read as ``; this one is ``. The "ForResource" is redundant — the method already takes a `resource` field. Inconsistent action verb shape across the same service surface (also category 17, since the operation is really a `list`). -- **Category:** 7, 17 (verbose; verb inconsistency) -- **Suggested name:** `listAssignableRoles(req)`. -- **Rationale:** Three-method surface reads better as `getRuleSet`, `updateRuleSet`, `listAssignableRoles`. - -### 8. `GrantRule.principals: string[]` — `src/v1/model.ts:63` -- **Why weird:** Generic `string[]` for principals, where each entry is one of three formats (`users/`, `groups/`, `servicePrincipals/`). The shape is documented in the JSDoc but not in the type. Callers have to read the comment to know what to put in. -- **Category:** 15, 19 (generic field losing meaning; underspecified ID) -- **Suggested name:** Type the field with a discriminated union or template literal — e.g. `principals: PrincipalRef[]` where `type PrincipalRef = \`users/${string}\` | \`groups/${string}\` | \`servicePrincipals/${string}\``. -- **Rationale:** TypeScript can encode this; the Go SDK cannot. The 1:1 port leaves type information on the floor. - -### 9. `RuleSet.name` and `GrantRule.role` are both `name` paths — `src/v1/model.ts:75,65` -- **Why weird:** "Name" in this API is a hierarchical resource path (`accounts//ruleSets/default`), not a human-readable label. Same overload for `role` (`roles/account.admin`). Calling these `name`/`role` and typing them as `string` hides that they are resource paths. -- **Category:** 15, 16 (generic field; field contradicting domain) -- **Suggested name:** `ruleSet.resourceName`, `grantRule.roleName` (or branded template-literal types). At minimum the JSDoc should explicitly say "resource path". -- **Rationale:** Half of all integration bugs in this API will be wrong-format names. The type system can help. - -### 10. `grantRules` plural inside `RuleSet` vs `GrantRule` (singular type, plural field) — `src/v1/model.ts:86` -- **Why weird:** Not wrong, but worth noting: `RuleSet.grantRules: GrantRule[]` is fine; however the wire form uses `grant_rules` and the doc comment on `RuleSet` does not mention `grantRules` at all. The single-rule case is also confusing: a `RuleSet` is a *set of* `GrantRule`s, but a `GrantRule` itself binds N principals to 1 role — so a "rule" is many-to-one. -- **Category:** 9, 6 (singular/plural; misleading) -- **Suggested name:** Keep `grantRules`, but document explicitly that one rule = N principals × 1 role, and a rule set = N rules. Consider `roleGrants: GrantRule[]` as the field name — closer to industry vocabulary (IAM role grants). -- **Rationale:** Improves discoverability. - -## Low severity - -### 11. `etag` casing — `src/v1/model.ts:51,85,101` -- **Why weird:** Lowercase `etag` (rather than `eTag`/`ETag`/`etag`). HTTP spec uses `ETag`. JavaScript ecosystem split is roughly even, but most TS SDKs (AWS, Azure, GitHub Octokit) use `etag` lowercase, so this is *probably* fine. Flag it for consistency review only. -- **Category:** 3 (acronym casing) -- **Suggested name:** Confirm the project-wide policy. If the codebase uses `eTag` elsewhere, align here. -- **Rationale:** Defer to global policy. - -### 12. `GetRuleSetRequest.name` ambiguity with `RuleSet.name` — `src/v1/model.ts:38` -- **Why weird:** A request type and a response type both have a `name` field with subtly different semantics: the request `name` is the *lookup key* the caller supplies; the response `name` is the *canonical name* the server returns. Same word, two roles. Common pattern, but worth flagging. -- **Category:** 1 (vague) -- **Suggested name:** Acceptable, but consider `GetRuleSetRequest.resourceName` for clarity. -- **Rationale:** Minor readability win. - -### 13. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` -- **Why weird:** This helper is `export`ed from `utils.ts`. It is not used by `client.ts` and is not re-exported from `index.ts`. Either it is dead code or the export modifier is wrong. -- **Category:** 11 (effectively trivial / dead) -- **Suggested name:** Drop the `export` keyword if internal-only; if it is meant for other generated clients, move it to a shared core package. -- **Rationale:** Hygiene. - -### 14. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` -- **Why weird:** The package imports `CallOptions` from `@databricks/sdk-options/call` and defines its own `HttpCallOptions` here. The names suggest the latter is a subtype/extension of the former, but they actually describe different concerns — `CallOptions` is retry/signal/timeout policy; `HttpCallOptions` is request + client + logger bundle. The naming makes them look related. -- **Category:** 1 (vague/generic) -- **Suggested name:** `HttpExecutionContext` or `HttpCallContext`. -- **Rationale:** Disambiguates from the public `CallOptions`. - -## Observations - -### O1. `Client` is the only exported class — `src/v1/client.ts:39` -- The class is just `Client`. With `import { Client } from '@databricks/sdk-accountaccesscontrol/v1'` the consumer sees a bare `Client` symbol. This is consistent across all generated packages, so it is a project-wide pattern, but it makes IDE autocomplete and stack traces ambiguous when multiple service clients are imported in the same file (everyone is `Client`). Common workarounds (`import { Client as AccountAccessControlClient }`) push the rename burden onto the user. Worth flagging at the project level. - -### O2. `executeCall` / `executeHttpCall` naming — `src/v1/utils.ts:26,65` -- Two functions with overlapping names. `executeCall` is the public-CallOptions translator; `executeHttpCall` is the wire-level request executor. The names do not signal that `executeCall` wraps the `Call` callback (which itself wraps `executeHttpCall`). Could be `applyCallOptions` and `sendHttpRequest` respectively. Generated code; flag for upstream. - -## Domain glossary -- `accountId` — Databricks account UUID (the top-level tenant container, distinct from a workspace). -- `etag` — HTTP entity tag used here both as a freshness floor on GET and as an optimistic concurrency token on PUT. -- `iam` — Identity and Access Management; the broader Databricks IAM surface this package is a subset of. -- `principal` — User, service principal, or group — the subject of an access rule. -- `Role` — Reference to a grantable account-level role (e.g. `roles/account.admin`). -- `RuleSet` — A versioned collection of `GrantRule`s attached to a resource. -- `GrantRule` — A binding of N principals to 1 role within a `RuleSet`. -- `SP_ID` / `SERVICE_PRINCIPAL_APPLICATION_ID` — Service principal application ID (UUID). -- `resource` — Hierarchical name identifying what the rule set or roles list applies to (account, group, service principal, or tag policy). - -## File coverage -- `src/v1/model.ts` (185 lines): read fully. -- `src/v1/client.ts` (171 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (17 lines): read fully. -- `package.json` (41 lines): read for context. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/accountaccesscontrolproxy.md b/.agent/naming-audit/accountaccesscontrolproxy.md index 59b22471..1e177120 100644 --- a/.agent/naming-audit/accountaccesscontrolproxy.md +++ b/.agent/naming-audit/accountaccesscontrolproxy.md @@ -1,48 +1,3 @@ # Naming Audit: accountaccesscontrolproxy -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/accountaccesscontrolproxy/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Account-level access control via rule sets that bind roles -to principals (users, groups, service principals, tag policies), exposed as a -"proxy" variant whose surface area is indistinguishable from the sibling -`accountaccesscontrol` package. -**Total weird names flagged:** 0 - ---- - -## Summary table - -_None._ - ---- - -## High severity (must fix) - -_None._ - ---- - -## Medium severity (worth pushing back on) - -_None._ - ---- - -## Low severity (nits) - -_None._ - ---- - -## Observations (not flags) - -- **Package source removed.** As of 2026-05-20, `packages/accountaccesscontrolproxy/src/` - no longer exists in the tree (only `.turbo/` log artifacts remain under the - package directory). All findings in this audit refer to symbols that are no - longer present; they have been moved to the `## Fixed` section below. - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/accountsettings.md b/.agent/naming-audit/accountsettings.md index 6bc0be72..3430ebc4 100644 --- a/.agent/naming-audit/accountsettings.md +++ b/.agent/naming-audit/accountsettings.md @@ -1,350 +1,3 @@ # Naming Audit: accountsettings -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `/home/parth.bansal/sdk-js/packages/accountsettings/` -**Versions audited:** v1 -**Inferred domain:** Account-level Databricks settings governing compliance profiles, IP access toggles, legacy-feature flags, ESM/CSP enablement, LLM-proxy partner-powered AI, and the Personal Compute default policy. -**Total weird names flagged:** 43 - -## Summary table - -| # | Severity | Category | Identifier | File:line | -|---|----------|----------|------------|-----------| -| 1 | High | Acronym casing / cryptic abbreviation | `DcpAccountEnableMessage` (DCP) | `model.ts:56,121` | -| 2 | High | Cryptic abbreviation | `Csp*` (CSP) family | `model.ts:87-119,281-295,449-458` | -| 3 | High | Cryptic abbreviation | `Esm*` (ESM) family | `model.ts:237-263,313-327,473-482` | -| 4 | High | Cryptic abbreviation | `Llm*` (LLM) family | `model.ts:329-359,377-413,485-506` | -| 5 | High | Generic field name | `value` (everywhere on `*Setting` types) | `model.ts:77-79, 113-118, 122, 231-233, 257-262, 393, 412, 431-433` | -| 6 | High | Generic + cryptic field | `acctIpAclEnable` | `model.ts:78-79` | -| 7 | High | Generic field name | `booleanVal` discriminator | `model.ts:393, 412` | -| 8 | High | Underspecified ID | `accountId` (no type/format hint) | `model.ts:126,156,186,266,...` | -| 9 | High | Domain-redundant suffix | `*Setting` suffix duplicating `Settings` package | `model.ts:97,241,415` and elsewhere | -| 10 | Medium | Proto-architecture leak | `BooleanMessage` (proto wrapper type) | `model.ts:82` | -| 11 | Medium | Proto-architecture leak | `DcpAccountEnableMessage` (`Message` suffix) | `model.ts:121` | -| 12 | Medium | Proto-architecture leak | `DcpAccountEnableMessage_Value` (proto-nested enum) | `model.ts:56` | -| 13 | Medium | Type-suffix tautology | `CspEnablementAccountSetting` | `model.ts:97` | -| 14 | Medium | Type-suffix tautology | `EsmEnablementAccountSetting` | `model.ts:241` | -| 15 | Medium | Type-suffix tautology | `PersonalComputeSetting` | `model.ts:415` | -| 16 | Medium | Duplicate concept | `*Account` vs `*AccountSetting` parallel naming | `model.ts:87 vs 97; 237 vs 241` | -| 17 | Medium | Misleading | `LlmProxyPartnerPoweredEnforce` | `model.ts:396` | -| 18 | Medium | Misleading | `LlmProxyPartnerPoweredAccount` | `model.ts:377` | -| 19 | Medium | Verb-tense / action verb | `AccountIpAccessEnable` (verb as noun) | `model.ts:61` | -| 20 | Medium | Verb-tense / action verb | `DisableLegacyFeatures` (verb-phrase as noun) | `model.ts:215` | -| 21 | Medium | Verb-tense / action verb | `DcpAccountEnableMessage` (verb in noun position) | `model.ts:121` | -| 22 | Medium | Inconsistent action verbs | `delete*` reverts to default (not actual delete) | `client.ts:105,185` | -| 23 | Medium | Singular/plural mismatch | `complianceStandards` array on type named `CspEnablementAccount` (no list role implied) | `model.ts:94` | -| 24 | Medium | Misleading | `settingName` always coerced to `"default"` server-side | `model.ts:76,112,...; client.ts:114,...` | -| 25 | Medium | Misleading | `settingTypeName` ignored (path param wins) | `client.ts:111-113` (no doc) | -| 26 | Medium | Vague / overly verbose | `*EnablementAccount` family naming | `model.ts:87,237` | -| 27 | Medium | Overly verbose | `UpdateLlmProxyPartnerPoweredEnforceRequest` | `model.ts:497` | -| 28 | Medium | Overly verbose | `UpdateCspEnablementAccountSettingRequest` | `model.ts:449` | -| 29 | Medium | Acronym casing | `Ip` vs `IP` in `AccountIpAccessEnable` | `model.ts:61` | -| 30 | Medium | Acronym casing | `Id` vs `ID` in `accountId` | `model.ts:126,...` | -| 31 | Medium | Method name redundancy | `getCspEnablementAccountSetting` / etc. | `client.ts:262,302,339,...` | -| 32 | Medium | Method name redundancy | `updatePersonalComputeSetting` | `client.ts:682` | -| 33 | Medium | Duplicate concept | `Account` repeated in nearly every type | `model.ts` passim | -| 34 | Low | Acronym casing | `etag` field cased as `etag` everywhere but doc says "eTag" | `model.ts:70,72` | -| 35 | Low | Cryptic abbreviation | `acct_ip_acl_enable` wire key | `model.ts:525,536-538`; `client.ts:109,229,500` | -| 36 | Low | Cryptic abbreviation | `dcp_acct_enable` wire key | `client.ts:189,463,686` | -| 37 | Low | Cryptic abbreviation | `shield_csp_enablement_ac` / `shield_esm_enablement_ac` (trailing `_ac`) | `client.ts:266,343,529,590` | -| 38 | Low | Long enum value | `CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE` | `model.ts:19-48` | -| 39 | Low | Verb-tense inconsistency | `Enable` (imperative) vs `Enablement` (noun) co-exist | `model.ts:61 vs 87,97 vs 215` | -| 40 | Low | Singular/plural mismatch | `DisableLegacyFeatures` (plural type with singular boolean) | `model.ts:215-234` | -| 41 | Low | Acronym casing | `Url` vs `URL` in `httpReq.url` (field defined upstream) | `utils.ts:70,103` | -| 42 | Low | Inconsistent action verbs | `revert` semantics doc'd, but method named `delete*` | `client.ts:105,185` | -| 43 | Low | Vague / generic field | `setting?` on update requests | `model.ts:444,456,468,480,492,504,516` | - ---- - -## High severity - -### 1. `DcpAccountEnableMessage` — undocumented cryptic acronym ("DCP") -- **File:line:** `model.ts:56, 121` -- **Category:** Cryptic abbreviation -- **Suggestion:** `DefaultComputePolicy` or, at minimum, attach a doc comment explaining the acronym. The whole type is a wrapper around a 2-value enum and could be inlined as `PersonalComputeAccess` with values `ON | DELEGATE`. -- **Rationale:** "DCP" is not defined anywhere in this package. From the surrounding wire path `dcp_acct_enable` and the doc on `PersonalComputeSetting`, it appears to mean "default Personal Compute policy" — but a reader has to reverse-engineer that. A 1:1 port may have to keep the type for compatibility, but the JSDoc must explain the acronym. - -### 2. `Csp*` family — undocumented cryptic acronym ("CSP") -- **File:line:** `model.ts:87, 97` and request variants -- **Category:** Cryptic abbreviation -- **Suggestion:** Spell out `ComplianceSecurityProfile` in the type names or add a top-of-file JSDoc glossary. The first comment on line 91 finally expands "Compliance Security Profile (CSP)" but only in passing — the type name itself stays cryptic. -- **Rationale:** "CSP" overloads heavily in web context (Content Security Policy), so the abbreviation is misleading as well as cryptic. The expansion is documented but only deep inside a field comment. - -### 3. `Esm*` family — undocumented cryptic acronym ("ESM") -- **File:line:** `model.ts:237, 241` -- **Category:** Cryptic abbreviation -- **Suggestion:** `EnhancedSecurityMonitoring*` or attach an inline doc. The method JSDoc on `client.ts:338` finally expands it ("enhanced security monitoring") — but the type itself never does. -- **Rationale:** Same problem as CSP. The reader has to grep the client to find the expansion. - -### 4. `Llm*` family — cryptic / underspecified acronym ("LLM") -- **File:line:** `model.ts:329-413, 485-506` -- **Category:** Cryptic abbreviation + verbose stacking -- **Suggestion:** `LargeLanguageModelProxyPartnerPowered*` is unwieldy, but a domain-specific short name like `AiProxyPartnerPowered*` or `ModelProxyPartnerPowered*` would at least drop the redundant "Llm" capitalization issue. Better: a single top-level type `PartnerPoweredAi*` with sub-fields. -- **Rationale:** "Llm" mixes acronym + token-casing rules: TypeScript style says either `LLM` (acronym-case for known acronyms) or `Llm` (Pascal-token-case). The codebase consistently uses `Llm`, but the larger problem is stacking cryptic + cryptic + ambiguous — "LlmProxyPartnerPoweredEnforce" parses with several plausible bracketings. - -### 5. `value` field on every `*Setting` discriminated union — generic field name losing meaning -- **File:line:** `model.ts:77, 113, 122, 231, 257, 393, 412, 431` -- **Category:** Generic field name losing meaning -- **Suggestion:** Name the field after what it discriminates: `payload`, or after the specific domain concept (e.g. `enabled`, `personalCompute`) per use site. -- **Rationale:** Eight different types in this package use a `value?: {...}` field, each with a discriminated union of `$case: ''`. Because the field name is identical across all of them, IDE autocomplete and code review provide no hint about what the field actually represents at any given use site — `setting.value` reads identically whether the underlying meaning is "IP ACL toggle", "legacy features disabled", or "partner-powered AI enforcement". - -### 6. `acctIpAclEnable` — cryptic + abbreviated discriminator value -- **File:line:** `model.ts:78-79` -- **Category:** Cryptic abbreviation, generic field name -- **Suggestion:** `accountIpAclEnabled` (or simply `enabled`). -- **Rationale:** `acct` is a non-standard abbreviation of `account` that saves three characters. Inside a TypeScript SDK there is no length-budget reason to abbreviate. The fact that the parent type is already `AccountIpAccessEnable` makes the abbreviation noise. - -### 7. `booleanVal` — generic discriminator value -- **File:line:** `model.ts:393, 412` -- **Category:** Generic field name losing meaning -- **Suggestion:** `enabled` (it is, in fact, a boolean toggle of partner-powered AI features per the method doc). -- **Rationale:** `booleanVal` describes the *type* not the *meaning* of the field. In a domain-specific union case, the case name should describe what it represents. (`acctIpAclEnable` and `disableLegacyFeatures` and `personalCompute` follow domain naming; `booleanVal` does not.) - -### 8. `accountId` — underspecified ID -- **File:line:** `model.ts:126, 156, 186, 266, 282, 298, 314, 330, 346, 362, 438, 450, 462, 474, 486, 498, 510` -- **Category:** Underspecified ID -- **Suggestion:** Add a doc comment that names the type (UUID? numeric? Databricks-internal?). Currently the `UpdateAccountIpAccessEnableRequest.accountId` is documented (` account ID of the account being managed.`) but the others are not. -- **Rationale:** "accountId" leaves the reader unsure whether to pass `"123"`, `"abcd-...-uuid"`, or `"my-account@databricks.com"`. The doc inconsistency (only the update variants document it) makes this worse. - -### 9. `*Setting` suffix vs package name `accountsettings` -- **File:line:** package level -- **Category:** Redundant suffix in domain -- **Suggestion:** Drop the `Setting` suffix from type names within the `accountsettings` package, or drop the trailing `s` from the package name. (Compare: a package called `users` whose types are all `UserUser`, `UserAccountUser`.) E.g. `CspEnablementAccountSetting` -> `CspEnablementAccount` (which already exists as a sub-type). -- **Rationale:** Every consumer reaches these types via `accountsettings.X`, so `accountsettings.PersonalComputeSetting` triple-stutters the domain. - ---- - -## Medium severity - -### 10. `BooleanMessage` — `model.ts:82` -- **Why weird:** `Message` is a protobuf code-generation suffix for wrapping a scalar into a message type. In a TypeScript SDK, a wrapper around `boolean` should not surface the proto "Message" terminology. -- **Category:** Proto-architecture leak -- **Suggested name:** `BooleanValue` (matches `google.protobuf.BoolValue` wkt convention) or eliminate the wrapper and inline `value?: boolean` at use sites. -- **Rationale:** The type body is `{value?: boolean}` — a generic scalar wrapper. The `Message` suffix only makes sense in proto-land; the TS surface exposes a boolean toggle and should read as such. - -### 11. `DcpAccountEnableMessage` — `model.ts:121` -- **Why weird:** Mid/suffix `Message` is a direct proto code-generation artifact. Every protobuf type is technically a "message," so the suffix is noise. -- **Category:** Proto-architecture leak -- **Suggested name:** `PersonalComputeAccess` or `DcpAccountEnable` (drop the trailing `Message`). -- **Rationale:** The `Message` suffix exists only because the upstream `.proto` file declares `message DcpAccountEnableMessage { ... }`. TypeScript consumers never need to know they're hitting a proto-defined endpoint — the type is an enum-wrapping state object. - -### 12. `DcpAccountEnableMessage_Value` — `model.ts:56` -- **Why weird:** Underscore-separated `_` is the protoc-go / proto-ts code-gen pattern for emitting nested enum/message types as flat top-level identifiers. The `_Value` suffix doubly leaks the proto convention of naming a nested enum `Value` inside a wrapper message. -- **Category:** Proto-architecture leak -- **Suggested name:** `PersonalComputeAccessMode` (with values `ON | DELEGATE`) — flatten the proto nesting and give the enum a domain-meaningful name. -- **Rationale:** A reader sees `DcpAccountEnableMessage_Value` and cannot tell whether the underscore is intentional or a typo. The intermediate `Message_Value` layering exists purely because protobuf nests `Value` inside `DcpAccountEnableMessage`; the TS SDK can flatten it without breaking the wire contract. - -### 13–15. `CspEnablementAccountSetting`, `EsmEnablementAccountSetting`, `PersonalComputeSetting` — type-suffix tautology -- **File:line:** `model.ts:97, 241, 415` -- **Category:** Type-suffix tautology -- **Suggestion:** Drop `Setting` (see #9). For ESM/CSP the inner type already drops it (`CspEnablementAccount`, `EsmEnablementAccount`). -- **Rationale:** The package is `accountsettings`, the method is `getCspEnablementAccountSetting`, returning a `CspEnablementAccountSetting`. The word "setting" appears three times in one call. This is the classic Go-port symptom — Go has no such namespace, so the redundancy is required there; in TS it is gratuitous. - -### 16. `*Account` vs `*AccountSetting` — duplicate-concept parallel naming -- **File:line:** `model.ts:87 vs 97; 237 vs 241` -- **Category:** Duplicate concept -- **Suggestion:** Rename one half of each pair so the two types describe distinct concepts at a glance, or document the relationship in both JSDocs. -- **Rationale:** Two types differing by one suffix (`CspEnablementAccount` vs `CspEnablementAccountSetting`) invite bugs where the consumer references the wrong one — the distinction between "data" and "envelope" is invisible from the name alone. - -### 17. `LlmProxyPartnerPoweredEnforce` — misleading -- **File:line:** `model.ts:396` -- **Category:** Misleading / verb-tense in noun position -- **Suggestion:** `LlmProxyPartnerPoweredEnforcement` (noun), and the method should be `getLlmProxyPartnerPoweredEnforcement`. -- **Rationale:** `Enforce` is the imperative verb; the type represents the *enforcement setting state*. The doc on `client.ts:418` reads `Gets the enforcement status of partner powered AI features account setting` — confirming the type is a noun-of-enforcement, not the verb. - -### 18. `LlmProxyPartnerPoweredAccount` — misleading -- **File:line:** `model.ts:377` -- **Category:** Misleading -- **Suggestion:** `LlmProxyPartnerPoweredEnabled` (or drop "Account" — every type in the package is account-scoped, the qualifier adds no information). -- **Rationale:** "Account" here doesn't refer to a sub-account or an account entity — it means "scoped to the account level," which is already true of every type in the package. The name suggests an Account *object* rather than an *enablement state*. - -### 19. `AccountIpAccessEnable` — verb-as-noun -- **File:line:** `model.ts:61` -- **Category:** Verb-tense inconsistency -- **Suggestion:** `AccountIpAccessToggle` (matches the method doc on `client.ts:104` "the account IP access toggle setting"), or `AccountIpAccessEnabled` (state). -- **Rationale:** Types should be nouns. `Enable` is an imperative verb. The wire field name `acct_ip_acl_enable` likewise reads as a command, not a state. The doc itself calls this a "toggle setting" — that name would be far more idiomatic. - -### 20. `DisableLegacyFeatures` — verb-phrase as type name -- **File:line:** `model.ts:215` -- **Category:** Verb-tense inconsistency -- **Suggestion:** `LegacyFeaturesDisabled` or `LegacyFeaturesToggle`. -- **Rationale:** `DisableLegacyFeatures` parses as "an action that disables legacy features." Types describing the *state of the toggle* should read as such. - -### 21. `DcpAccountEnableMessage` — verb in noun position -- **File:line:** `model.ts:121` -- **Category:** Verb-tense inconsistency -- **Suggestion:** `PersonalComputeAccess` (since this is in fact the personal compute policy state); drop the `Enable` imperative verb. -- **Rationale:** `Enable` is an imperative verb; the type represents a state. Types describing the state of a toggle should read as nouns. - -### 22 / 42. `delete*` methods that actually revert -- **File:line:** `client.ts:105 (deleteAccountIpAccessEnable doc: "Reverts the value..."), 185 (deletePersonalComputeSetting doc: "Reverts back ... to default (ON)")` -- **Category:** Inconsistent action verbs / misleading -- **Suggestion:** `reset*ToDefault()` (the semantics are reset-to-default, not destruction). At minimum, the method JSDoc and the verb should agree. -- **Rationale:** A `delete` HTTP verb is being used to reset state — that is the *server's* idiom. The SDK can hide it with a more accurate verb. The doc literally says "Reverts" — a reader scanning method names will not see that. - -### 23. `complianceStandards` array on `CspEnablementAccount` (singular type, plural field) -- **File:line:** `model.ts:94` -- **Category:** Singular/plural mismatch (mild — the field is plural because it's a list, which is correct; the audit checklist asks me to flag interactions). Actually this is fine — flagged only to note it's *consistent*. -- **Suggestion:** No change. - -### 24. `settingName` documented to be ignored, "must be `default`" -- **File:line:** `model.ts:76, 112, 230, 256, 392, 411, 430` -- **Category:** Misleading -- **Suggestion:** Either remove the field from the TS surface (since the doc says it will not be respected on requests and is always `"default"` server-side) or rename to `settingName_readOnly` and mark it `readonly`. -- **Rationale:** Exposing a field that the API explicitly ignores invites confused user code. The doc says verbatim: "This field is populated in the response, but it will not be respected even if it's set in the request body. The setting name in the path parameter will be respected instead." - -### 25. `settingTypeName` query param has no purpose -- **File:line:** `client.ts:111-113` (and every other method that appends it as a query param) -- **Category:** Misleading / vague -- **Suggestion:** Remove from request types (the actual type is hard-coded into the URL path) or document that it is informational only. -- **Rationale:** The URL already encodes `types/acct_ip_acl_enable`; appending `?setting_type_name=acct_ip_acl_enable` is at best a no-op. If it's required for some legacy reason, that needs a comment. - -### 26. `*EnablementAccount` family — verbose and weak -- **File:line:** `model.ts:87, 237` -- **Category:** Vague / overly verbose -- **Suggestion:** Drop `Enablement` — it adds no information beyond "this thing represents whether the feature is enabled," which is already implied by the boolean fields. `CspAccount` / `EsmAccount`, or better, `CspState` / `EsmState`. -- **Rationale:** "Enablement" is an awkward noun coined to allow modeling "the state of enablement of X." Standard English would say "X enabled" (adjective) or just "X" with a bool field. - -### 27–28. `UpdateLlmProxyPartnerPoweredEnforceRequest` / `UpdateCspEnablementAccountSettingRequest` — overly verbose -- **File:line:** `model.ts:497, 449` -- **Category:** Overly verbose -- **Suggestion:** Shorter forms like `UpdateLlmProxyEnforcementRequest` / `UpdateCspRequest`, paired with the renames in #13 and #23. -- **Rationale:** 38 characters in `UpdateLlmProxyPartnerPoweredEnforceRequest` is too long to scan, and most of it is fixed boilerplate ("PartnerPowered", "Account", "Setting", "Request"). - -### 29. `Ip` vs `IP` acronym casing -- **File:line:** `model.ts:61` (and references) -- **Category:** Acronym casing inconsistency -- **Suggestion:** Pick one. TypeScript's de-facto style (and the Google TS style guide) treats 2-letter acronyms as PascalCase tokens (`Ip`), so `AccountIpAccessEnable` is actually correct by that rule. But the Go SDK uses `IP`; the JS SDK is consistent with TS conventions here. Just note for the audit. -- **Rationale:** Within this package the choice is consistent; cross-package consistency should be verified. - -### 30. `Id` vs `ID` acronym casing -- **File:line:** `model.ts:126, 156, 186, ...` -- **Category:** Acronym casing inconsistency -- **Suggestion:** Same as #29 — `Id` matches TS conventions. -- **Rationale:** Same as #29. - -### 31. Method-name redundancy: `getCspEnablementAccountSetting` -- **File:line:** `client.ts:262, 302, 339, 379, 419, 459` -- **Category:** Method name redundancy -- **Suggestion:** Drop `Setting` from method names (the `Client` is already account-settings-scoped; `client.getCsp()` is unambiguous in context). -- **Rationale:** `accountsettings.Client.getCspEnablementAccountSetting()` repeats "setting" in package + method. Compare similar SDKs where `settings.Client.getCsp()` is the norm. - -### 32. `updatePersonalComputeSetting` — same redundancy -- **File:line:** `client.ts:682` -- **Category:** Method name redundancy -- **Suggestion:** `updatePersonalCompute()`. -- **Rationale:** Same as #31. - -### 33. `Account` repeated in nearly every type -- **File:line:** `model.ts` passim -- **Category:** Duplicate concept (package scope already implies account-level) -- **Suggestion:** Drop the `Account` prefix/suffix where the package name (`accountsettings`) already conveys it. -- **Rationale:** `CspEnablementAccount` → `CspEnablement`. `EsmEnablementAccount` → `EsmEnablement`. `AccountIpAccessEnable` → `IpAccessEnable`. The current scheme reads like the Go SDK's flat namespace, where the prefix is needed; in a packaged TS SDK it is purely stutter. - ---- - -## Low severity - -### 34. `etag` field cased as `etag` but JSDoc consistently says "eTag" -- **File:line:** `model.ts:70 (field: `etag`), 72 (doc: "as the eTag provided")` -- **Category:** Acronym casing inconsistency -- **Suggestion:** Pick `etag` everywhere (HTTP standard is `ETag` per RFC 7232 but most code uses `etag`). -- **Rationale:** Within a single JSDoc block, line 70 declares `etag?: string` and line 63 capitalizes it as `eTag`. Trivial inconsistency. - -### 35. `acct_ip_acl_enable` wire key -- **File:line:** `model.ts:525, 536-538`; `client.ts:109, 229, 500` -- **Category:** Cryptic abbreviation (server-controlled, but leaks via the discriminator `$case: 'acctIpAclEnable'`) -- **Suggestion:** Server side can keep wire keys; the TS-facing discriminator `$case: 'acctIpAclEnable'` should be `accountIpAclEnable` or `enabled`. -- **Rationale:** Users have to type the `$case` string literal, so abbreviations cost real ergonomics. - -### 36. `dcp_acct_enable` wire key -- **File:line:** `client.ts:189, 463, 686` -- **Category:** Cryptic abbreviation (server-side path) -- **Suggestion:** N/A (server URL is fixed). Note for observability. - -### 37. `shield_csp_enablement_ac` / `shield_esm_enablement_ac` wire keys -- **File:line:** `client.ts:266, 343, 529, 590` -- **Category:** Cryptic abbreviation (server-side path) -- **Suggestion:** N/A. The trailing `_ac` (presumably "account") is an artefact of server naming. - -### 38. Long enum values (`CYBER_ESSENTIAL_PLUS`, `CANADA_PROTECTED_B`, `GERMANY_TISAX`, `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5`, `ITAR_EAR`, `GERMANY_C5`, `ISMAP`, `HITRUST`, `K_FSI`) -- **File:line:** `model.ts:19-48` -- **Category:** Long enum values -- **Suggestion:** Keep — these are well-known compliance standard names where the string literal *is* the canonical form. Flagging only for completeness. -- **Rationale:** Compliance standards have official names. Shortening `FEDRAMP_MODERATE` to `FEDRAMP_MOD` would be a regression. - -### 39. `Enable` (verb) vs `Enablement` (noun) co-exist -- **File:line:** `model.ts:61 (AccountIpAccessEnable) vs 87, 97 (CspEnablement...) vs 215 (DisableLegacyFeatures)` -- **Category:** Verb-tense inconsistency -- **Suggestion:** Standardize: either `*Enabled` (boolean adjective) or `*Toggle` (noun) across all toggle types. -- **Rationale:** Within one package, three different lexical forms describe the same concept ("a boolean toggle"). A reader can't predict the form for a new toggle. - -### 40. `DisableLegacyFeatures` — plural noun, singular boolean -- **File:line:** `model.ts:215-234` -- **Category:** Singular/plural mismatch (mild) -- **Suggestion:** `DisableLegacyFeaturesToggle` (it's a single bool, not a list of features). -- **Rationale:** The bare plural reads as "a list of disable-legacy-feature entries"; the type body shows it's a single bool. - -### 41. `Url` vs `URL` casing -- **File:line:** `utils.ts:70, 103` (HttpRequest field used as `url`) -- **Category:** Acronym casing inconsistency -- **Suggestion:** Conforms to TS convention (`url`/`Url`). Note for the audit. - -### 42. (see #22) - -### 43. `setting?` on every update request — vague -- **File:line:** `model.ts:444, 456, 468, 480, 492, 504, 516` -- **Category:** Vague / generic field name -- **Suggestion:** Name the field after its type (`personalCompute?: PersonalComputeSetting`) — when there's exactly one payload type per request, the parameter name should reflect it. -- **Rationale:** `req.setting` is so generic the IDE auto-complete tells the user nothing. `req.personalCompute` would. - ---- - -## Observations - -1. **Acronym soup.** Within the file you encounter CSP, ESM, DCP, LLM, IP, ACL, ESC (Enhanced Security Compliance), CMS (Centers for Medicare & Medicaid Services), ITAR/EAR, ISMAP, HITRUST, K-FSI, C5, TISAX, ARC-AMPE — without a single glossary. The compliance-standard acronyms have JSDoc, but the type-name acronyms (CSP, ESM, DCP, LLM) do not. A top-of-file `@module` doc that expands these would be high-ROI. - -2. **`Setting` suffix is gratuitous.** The package is `accountsettings`, the client is `Client`, and the methods are `getX`/`updateX`. The `Setting` suffix repeats in 7 of 11 main types. Even keeping a 1:1 port from Go, a TS-idiomatic façade could re-export these with cleaner names. - -3. **`settingName` is documented to be ignored.** Exposing a field on a request where the docstring says "this field…will not be respected even if it's set" is hostile to consumers. Either remove it or mark it `readonly` and explain. - -4. **`Enable` vs `Enablement` vs `Disable` vs `DisableLegacyFeatures`.** Within one package, four different verb/noun forms describe boolean toggles. A small style decision (every toggle type ends in `Toggle` or every toggle exposes `enabled: boolean`) would tighten the surface considerably. - -5. **`Delete` HTTP verb is named `delete` in the SDK but means "reset to default."** Method JSDoc says "Reverts the value...to default (ON)." A more honest method name (`reset*ToDefault`) would help consumers reason about what is destroyed. - -6. **`accountId` is the only field that varies across requests, and it is optional everywhere** because the client constructor accepts an `accountId` fallback. That coupling is good UX. But the JSDoc explanation only appears on update requests, not get/delete — a small inconsistency. - -7. **Field-mask functions (`accountIpAccessEnableFieldMask`, etc.) follow a clear lowerCamelCase pattern**, but the leading `acct` in `acct_ip_acl_enable` (wire) does not propagate (TS surface uses `accountIpAclEnable`). Good — but it means the wire-to-TS rename rules are non-obvious. - ---- - -## Domain glossary - -| Acronym / token | Expansion | Mentioned in code? | -|-----------------|-----------|--------------------| -| **CSP** | Compliance Security Profile | Yes, `model.ts:91` (one-time) | -| **ESM** | Enhanced Security Monitoring | Only in method JSDoc `client.ts:338` | -| **ESC** | Enhanced Security Compliance | Yes, `model.ts:12` | -| **DCP** | (Default) Personal Compute policy | No (inferred from wire key `dcp_acct_enable` + neighbouring docs) | -| **LLM** | Large Language Model | No | -| **ACL** | Access Control List | Yes (wire only, `acct_ip_acl_enable`) | -| **IP** | Internet Protocol (network address) | Implicit | -| **AIP** | API Improvement Proposals (Google) | `model.ts:442` ("Added for AIP compliance.") — undocumented | -| **etag** | Entity tag (HTTP cache validator, RFC 7232) | Yes (in field doc) | -| **SHIELD** | Databricks security product line | `model.ts:7` (one-time, undefined) | - ---- - -## File coverage - -| File | Lines read | Coverage | -|------|-----------|----------| -| `src/v1/index.ts` | full | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | -| `src/v1/model.ts` | 1199 (full) | 100% — all 23 types, 2 enums, zod schemas, field-mask helpers audited. | -| `src/v1/client.ts` | 710 (full) | 100% — all 13 client methods, constructor, and private fields audited. | -| `src/v1/utils.ts` | full | 100% — utility functions reviewed; `HttpCallOptions`, `executeCall`, `parseResponse`, `marshalRequest`, `flattenQueryParams` have no naming issues worth flagging (they are infrastructure shared across packages and follow consistent conventions). | - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md index f02a10f3..102560ef 100644 --- a/.agent/naming-audit/alerts.md +++ b/.agent/naming-audit/alerts.md @@ -3,7 +3,7 @@ **Path:** `packages/alerts/src/{v1,v2}/` **Versions audited:** v1, v2 **Inferred domain:** SQL/Databricks alerts: a stored configuration that periodically evaluates a query result against a threshold and notifies subscribers when it triggers. -**Total weird names flagged:** 22 (0 fixed, 22 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 18 (0 fixed, 18 still present after rescan on 2026-05-26 post regen #156) ## Summary table @@ -20,17 +20,13 @@ | 9 | Medium | both | `model.ts` field | `Alert.notifyOnOk` | Acronym casing ambiguity (`Ok` vs `OK`) | | 10 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | | 11 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Boolean-shaped enum | -| 12 | Medium | v2 | `model.ts` field | `Alert.lifecycleState` documented as "Indicates whether the query is trashed" | Misleading (says query, means alert) | -| 13 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | -| 14 | Low | both | `model.ts` field | `pageToken` / `pageSize` / `nextPageToken` | Conventional; flagged only for completeness | -| 15 | Low | both | `model.ts` field | `ListAlertsRequest`/`ListAlertsResponse` plural vs `GetAlertRequest` singular | Consistent with REST norms | -| 16 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | -| 17 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | -| 18 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | -| 19 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | -| 20 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | -| 21 | Low | v2 | `model.ts` field | `Alert.effectiveRunAs` | "Effective" prefix unexplained at first read | -| 22 | Low | both | `client.ts` | comment "Create Alert" / "Update alert" docstrings | Verb-tense / casing inconsistency in JSDoc | +| 12 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | +| 13 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | +| 14 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | +| 15 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | +| 16 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | +| 17 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | +| 18 | Low | v2 | `model.ts` field | `Alert.effectiveRunAs` | "Effective" prefix unexplained at first read | ## v1 vs v2 comparison @@ -204,18 +200,7 @@ export enum SchedulePauseStatus { Two values for a boolean concept; `boolean paused` would be simpler. -### 12. `Alert.lifecycleState` — JSDoc contradicts the field (v2) - -**Location:** `src/v2/model.ts:80-81` - -```ts -/** Indicates whether the query is trashed. */ -lifecycleState?: AlertLifecycleState | undefined; -``` - -JSDoc says "whether the query is trashed," but the field is on `Alert` and the enum is `AlertLifecycleState` with values `ACTIVE`/`DELETED`. The word "query" leaks from the underlying implementation (alerts wrap queries) into an `Alert` field's documentation. - -### 13. `AlertLifecycleState.DELETED` vs v1 `LifecycleState.TRASHED` — vocabulary swap +### 12. `AlertLifecycleState.DELETED` vs v1 `LifecycleState.TRASHED` — vocabulary swap **Location:** v1 `model.ts:24-27`; v2 `model.ts:34-37` @@ -223,26 +208,7 @@ The method is still `trashAlert` (both versions), but in v1 the resulting state ## Low severity -### 14. `pageToken` / `pageSize` / `nextPageToken` (both) - -```ts -export interface ListAlertsRequest { - pageToken?: string | undefined; - pageSize?: number | undefined; -} -export interface ListAlertsResponse { - ... - nextPageToken?: string | undefined; -} -``` - -Conventional Google AIP-158 pagination names. Flagged only because the rule list asks for completeness; no action recommended. - -### 15. `ListAlertsRequest` plural vs `GetAlertRequest` singular (both) - -Consistent with REST norms (`GET /alerts/{id}` singular, `GET /alerts` plural). No action recommended. - -### 16. `Aggregation.STDDEV` — cryptic abbreviation (v2) +### 13. `Aggregation.STDDEV` — cryptic abbreviation (v2) ```ts STDDEV = 'STDDEV', @@ -250,11 +216,11 @@ STDDEV = 'STDDEV', `STANDARD_DEVIATION` or `STDEV` would be clearer; `STDDEV` is a SQL-server-ism. -### 17. `Aggregation.AVG` — cryptic abbreviation (v2) +### 14. `Aggregation.AVG` — cryptic abbreviation (v2) `AVERAGE` would be consistent with `SUM`, `COUNT`, `MEDIAN`, `MIN`, `MAX`. The mix of short and full names inside one enum is the issue. -### 18. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) +### 15. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) ```ts /** Threshold to user for alert evaluation, can be a column or a value. */ @@ -265,15 +231,15 @@ The JSDoc admits the threshold can be a column — i.e., not actually a threshol Also note the typo "Threshold to user" (should be "to use") — content, not naming, but worth fixing. -### 19. `LifecycleState` — missing domain prefix (v1) +### 16. `LifecycleState` — missing domain prefix (v1) v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycleState`. -### 20. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) +### 17. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) Same data, different vocabulary. v1 = email metaphor, v2 = generic content metaphor. Users porting from v1 to v2 need a translation table. -### 21. `effectiveRunAs` (v2) +### 18. `effectiveRunAs` (v2) **Location:** `src/v2/model.ts:94-99` @@ -288,19 +254,6 @@ effectiveRunAs?: AlertRunAs | undefined; The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. (Previously also cited `effectiveParentPath`; that field was removed in regeneration.) -### 22. JSDoc verb/casing inconsistency (both) - -**Location:** v2 `client.ts:68`, `client.ts:198` - -```ts -/** Create Alert */ -async createAlert(...) { ... } -/** Update alert */ -async updateAlert(...) { ... } -``` - -`Create Alert` vs `Update alert` — different capitalization, different sentence shape, neither ends with a period (project rule). v1 uses full sentences (`/** Creates an alert. */`). Naming-adjacent. - ## Observations 1. **Wire-format leakage.** Many names are direct translations of proto wire fields without consideration of how they read in TypeScript: `STDDEV`, `IS_NULL`, `UNKNOWN`. The audit rule "1:1 port" was followed faithfully but the language idioms suffer. diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index d4734a4d..efff12ed 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -9,11 +9,11 @@ with deployments, custom templates, app spaces, and resource bindings. | Severity | Count | | -------- | ----- | -| High | 6 | +| High | 5 | | Medium | 14 | -| Low | 11 | +| Low | 7 | | Observation | 9 | -| **Total** | **40** | +| **Total** | **35** | The audit found one dominant theme: the domain has overlapping vocabularies for the same concept. `App` vs `Application` (`ApplicationStatus`, @@ -107,22 +107,6 @@ cross-product values whose relevance to Apps is unclear. not surface implementation-layer artefacts that a hand-written client would never name this way. -### H6. Singular `permission` field holding a single value but documented as plural permissions -- **File:** `model.ts:838-839, 947-948` -- **Category:** Singular/plural mismatches (9) -- **Issue:** `AppManifest_AppResourceJobSpec.permission?: ...JobPermission` - has doc text `Permissions to grant on the Job. Supported permissions are: - "CAN_MANAGE", "IS_OWNER", "CAN_MANAGE_RUN", "CAN_VIEW".` Same pattern in - `AppResourceJob.permission`. The field name is singular but the doc says - "Permissions" (plural) and lists four. The same hybrid singular/plural - language appears in seven other resource specs. -- **Suggestion:** Either (a) make the field plural and convert it to an array - if multiple values can be granted, or (b) keep singular and reword the doc to - "Permission to grant on the job. One of: ...". Today the singular type - enforces (b) — the doc should match. -- **Rationale:** The doc text contradicts the type signature, so consumers - reading either will be misled. - --- ## Medium-severity findings @@ -278,25 +262,7 @@ cross-product values whose relevance to Apps is unclear. ## Low-severity findings -### L1. `AppDeployment.mode` doc: "The mode of which the deployment will manage the source code." -- **File:** `model.ts:788` -- **Category:** Grammar / clarity (not in numbered categories but flagged) -- **Suggestion:** "of which" should be "in which" or "by which". A nit, not a - rename, but flagged because it appears in the public API docs. - -### L2. `App.creator` doc says "email"; `App.updater` doc agrees — but `creator` field type is just `string` -- **File:** `model.ts:731-736` -- **Category:** Field contradicting type domain (16) -- **Suggestion:** No type change available short of a branded type; document - the format in JSDoc. - -### L3. `AppManifest_AppResourceSpec` documentation typo: "AppResource related fields are copied from app.proto" -- **File:** `model.ts:856` -- **Category:** Doc / clarity -- **Suggestion:** Drop or rephrase the reference to `app.proto`; in TS the - reference is meaningless. - -### L4. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers +### L1. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers - **File:** `model.ts:2939, 3016` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — @@ -305,14 +271,7 @@ cross-product values whose relevance to Apps is unclear. - **Suggestion:** Either expose helpers for every entity with a field-mask schema, or none. -### L5. `App.thumbnailUrl: string` vs `AppThumbnail.thumbnail: Uint8Array` — different mental models -- **File:** `model.ts:771, 994` -- **Category:** Duplicate concepts (12) -- **Suggestion:** Document that `thumbnailUrl` is the display URL and - `AppThumbnail.thumbnail` is the byte content (used in - update/delete-thumbnail requests). - -### L6. `Space` interface — same name as the Genie product `AppResourceGenieSpace` +### L2. `Space` interface — same name as the Genie product `AppResourceGenieSpace` - **File:** `model.ts:938, 1306` - **Category:** Duplicate concepts (12) - **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share @@ -324,18 +283,18 @@ cross-product values whose relevance to Apps is unclear. is the outlier. This realignment also clarifies the wire URLs (`/api/2.0/app-spaces/...`). -### L7. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, +### L3. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, `ListSpacesRequest`, etc., do not mention "App" - **File:** `model.ts:1057, 1103, 1153, 1250`, also `index.ts:78, 84, 91, 100` - **Category:** Vague/generic (1) -- **Suggestion:** Tied to L6 — rename these to `CreateAppSpaceRequest`, etc. +- **Suggestion:** Tied to L2 — rename these to `CreateAppSpaceRequest`, etc. -### L8. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? +### L4. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? - **File:** `model.ts:1232, 1258` -- **Category:** Observation — both follow the same pattern. Tied to L6 again +- **Category:** Observation — both follow the same pattern. Tied to L2 again for the entity rename. -### L9. `Client` class — exported as bare `Client` +### L5. `Client` class — exported as bare `Client` - **File:** `client.ts:95`, also `index.ts:4` - **Category:** Vague/generic (1) - **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the @@ -343,7 +302,7 @@ cross-product values whose relevance to Apps is unclear. `@databricks/sdk-jobs`, they need an alias. - **Suggestion:** Rename to `AppsClient`. Common SDK convention. -### L10. `host` (private field on `Client`) +### L6. `host` (private field on `Client`) - **File:** `client.ts:96` - **Category:** Vague/generic (1) - **Issue:** `private readonly host: string`. The doc on the workspace @@ -351,7 +310,7 @@ cross-product values whose relevance to Apps is unclear. - **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, cosmetic. -### L11. `getSpaceOperation` (method) vs `GetOperationRequest` +### L7. `getSpaceOperation` (method) vs `GetOperationRequest` - **File:** `client.ts:524-546` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells @@ -425,13 +384,13 @@ detail. | `AppDeployment` | A specific deployment (source-code + config snapshot) | Has its own `id`, status, lifecycle. | | `AppManifest` | Schema describing required resources for an app | Used by `CustomTemplate`. | | `AppResource` | A binding from an App to another Databricks resource | Discriminated union of 10 cases. | -| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L6. | -| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L6. | +| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L2. | +| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L2. | | `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | | `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H3. | | `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | | `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M3/M4. | -| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. See L5. | +| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. | | `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M1. | | `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | | `GitSource` | Specific commit/branch/tag + path within a `GitRepository` | Used by deployments. | diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index 11ce4ee4..ef06afc1 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,14 +3,14 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 22 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 7 | -| Low | 7 | +| High | 2 | +| Medium | 4 | +| Low | 5 | | Observation | 5 | ## High severity @@ -21,13 +21,7 @@ - **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). - **Rationale:** A bare `Filter` provides zero discoverability and the package directly forces a collision with `usagepolicy.Filter`. Both packages target the same account-level surface and a consumer will frequently import both. -### 2. `ListBudgetPoliciesRequest.pageToken` JSDoc references `ListServerlessPolicies` — `src/v1/model.ts:116-121` -- **Why weird:** Docstring says: "A page token, received from a previous `ListServerlessPolicies` call ... When paginating, all other parameters provided to `ListServerlessPoliciesRequest` must match the call that provided the page token." — refers to an entirely different RPC name (`ListServerlessPolicies`) that does not exist in this SDK. The actual method is `listBudgetPolicies`. -- **Category:** 6 (misleading — docs describe a different operation), 14 (Go-style internal proto name leaked). -- **Suggested name:** Fix docstring to say `ListBudgetPolicies`/`ListBudgetPoliciesRequest`. -- **Rationale:** Generator bug. Confusing for readers and grep-hostile (searching for `ListBudgetPolicies` won't surface the doc context). - -### 3. Type-name collision with `budgets` package — `src/v1/model.ts:14` vs `packages/budgets/src/v1/model.ts:50` +### 2. Type-name collision with `budgets` package — `src/v1/model.ts:14` vs `packages/budgets/src/v1/model.ts:50` - **Why weird:** This package's central entity is `BudgetPolicy`; the sibling `budgets` package exports `BudgetConfiguration` (the spend-alert budget object). The two are semantically unrelated — `BudgetPolicy` is a tag-attachment policy that influences cost attribution, and `BudgetConfiguration` is a spend threshold + alert. A user importing both packages sees `BudgetPolicy` and `BudgetConfiguration` side by side and may reasonably wonder if `BudgetPolicy` is the policy *for* a `BudgetConfiguration`. The names do not differentiate clearly. - **Category:** 12 (duplicate concepts with confusing names), 1 (the `Budget` prefix overloads two unrelated domain ideas). - **Suggested name:** Consider `CostAttributionPolicy` or `UsageTaggingPolicy` for what `budgetpolicy` actually models (per the JSDoc on `BudgetPolicy`: "Contains the BudgetPolicy details" — tags + workspace bindings, no spend or threshold concept anywhere). @@ -35,43 +29,25 @@ ## Medium severity -### 4. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` +### 3. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. - **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. -### 5. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` +### 4. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 30). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 30 and `Filter.creatorUserId` here. -### 6. `SortSpec` type — `src/v1/model.ts:147` +### 5. `SortSpec` type — `src/v1/model.ts:147` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 7. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:148` -- **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. -- **Category:** Observation (typo). -- **Suggested name:** Fix spelling. -- **Rationale:** Minor; flagging because it surfaces in IntelliSense. - -### 8. `ListBudgetPoliciesResponse.previousPageToken` — `src/v1/model.ts:144` -- **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but `listBudgetPoliciesIter` (client.ts:193) only walks forward. The bidirectional surface area exists but is unused by the iterator helper. -- **Category:** Observation / 12 (duplicate-but-asymmetric concept). -- **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. -- **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. - -### 9. `ListBudgetPoliciesResponse.previousPageToken` doc typo — `src/v1/model.ts:142` -- **Why weird:** Doc reads "In this field is omitted, there are no previous pages." — "In" should be "If". -- **Category:** Observation (typo). -- **Suggested name:** Fix doc. -- **Rationale:** Generated; surfaces in IntelliSense. - -### 10. `SortSpec_Field` enum name — `src/v1/model.ts:6` +### 6. `SortSpec_Field` enum name — `src/v1/model.ts:6` - **Why weird:** Proto-architectural-leak: the underscore-joined `ParentType_NestedType` form is the protobuf/Go-SDK convention for emitting nested enum types into a flat namespace. TS already supports namespaces and modules natively, so the underscore is a wire-protocol artifact bleeding into the public TS API. The eslint-disable comment on the prior line even labels it "Proto-style nested enum name", confirming the generator knows it is non-idiomatic. - **Category:** Proto-architectural leak (proto-style nested-type encoding leaking into TS identifiers). - **Suggested name:** `SortField` (drop the `Spec_` prefix entirely; the enum stands on its own as the set of sortable fields) or `SortSpecField` (camel-join, no underscore). @@ -79,43 +55,31 @@ ## Low severity -### 11. `CreateBudgetPolicyRequest.policy` field with confusing JSDoc — `src/v1/model.ts:44-46` -- **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated. `policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional." — wire-name leak again (`policy_id`, `policy_name`, `custom_tags`) in TS docs. -- **Category:** Observation, 14 (wire-style identifiers in TS docs). -- **Suggested name:** Fix the doc to reference TS field names. -- **Rationale:** Editing UX: hovers should show TS, not proto. - -### 12. `UpdateBudgetPolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:157` -- **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `BudgetPolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. -- **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `BudgetPolicy`, model says otherwise). -- **Suggested name:** Fix doc; likely a Go-SDK paste from a richer struct. -- **Rationale:** Real bug. - -### 13. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 7. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. - **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). - **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. - **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. -### 14. `HttpCallOptions` — `src/v1/utils.ts:15` +### 8. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. - **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). - **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). - **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. -### 15. `readAll` — `src/v1/utils.ts:40` +### 9. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` or `readStreamToEnd`. - **Rationale:** Internal helper. Generator-wide. -### 16. `flattenQueryParams` — `src/v1/utils.ts:123` +### 10. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. - **Category:** Observation / 12 (duplicate utility across packages). - **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. - **Rationale:** Naming is fine; flagging duplication. -### 17. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` +### 11. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` - **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. - **Category:** 1 (vague), 15 (generic name losing meaning). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -123,27 +87,27 @@ ## Observations -### 18. `Client` class plain name — `src/v1/client.ts:46` +### 12. `Client` class plain name — `src/v1/client.ts:46` Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 19. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 13. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. -### 20. Action-verb conventions in `Client` +### 14. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 21. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` +### 15. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. - **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). -### 22. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 16. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 8ab92c88..fdd7b082 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -82,14 +82,7 @@ rename suggestion. Findings are grouped by category. weight here (see also F7). If the type *must* keep the "Config" word, `BudgetAlertActionConfig` is shorter and clearer. -#### F1.2 — `operator` (LOW) -- **Where:** `model.ts:82, 94`. -- **Why flagged:** Generic given there is only one allowed value - (`IN`). Acceptable for forward-compat but worth a JSDoc note. -- **Suggestion:** Keep, but add JSDoc clarifying allowed values and - semantics (currently has none). - -#### F1.3 — `Client` class name (MEDIUM) +#### F1.2 — `Client` class name (MEDIUM) - **Where:** `client.ts:49`, `index.ts:3`. - **Why flagged:** Every package in this SDK exports a `Client`. Re-exported in a barrel like @@ -100,7 +93,7 @@ rename suggestion. Findings are grouped by category. package-qualified import convention, or rename to `BudgetsClient` consistently across packages. Cross-cutting. -#### F1.4 — `req` parameter name on every client method (LOW) +#### F1.3 — `req` parameter name on every client method (LOW) - **Where:** `client.ts:80, 112, 140, 174, 216, 234`. - **Why flagged:** `req` is a Go-ism (see category 14). It is also generic — a reader has to look at the type to know what the @@ -119,30 +112,17 @@ _None._ ### 3. Acronym casing inconsistencies -#### F3.1 — `Id` vs `ID` (acceptable) -- **Where:** `model.ts:28, 37, 52, 54, 100, 102, 135, 137, 145, 147, - 158, 177, 179, 197`; `client.ts:53, 66, 83, 115, 143, 177, 237`. -- **Why flagged:** This SDK uses **lower-camel `Id`** consistently - (`accountId`, `budgetId`, `budgetConfigurationId`, - `actionConfigurationId`, `alertConfigurationId`, `workspaceId`, - `nextPageToken`, `pageToken`). That is internally consistent and - fine. The TS/JS community is split — DOM uses `nodeId`/`HTMLElement`, - TypeScript itself uses `id`/`uuid` — so `Id` is defensible. -- **Suggestion:** Keep `Id`. Add a brief project-level note in - `typescript.mdc` documenting the convention so reviewers stop - re-litigating it. - -#### F3.2 — `URL` / `Url` consistency (acceptable) +#### F3.1 — `URL` / `Url` consistency (acceptable) - `client.ts` consistently uses `url` (lowercase) as a local var name. No casing inconsistency observed. -#### F3.3 — `HTTP` / `Http` (acceptable for this file) +#### F3.2 — `HTTP` / `Http` (acceptable for this file) - `utils.ts` consistently uses `Http` PascalCase (`HttpClient`, `HttpRequest`, `HttpResponse`, `HttpCallOptions`, `executeHttpCall`, `buildHttpRequest`). One file is consistent; flag is cross-package only. -#### F3.4 — `USD` in enum value `LIST_PRICE_DOLLARS_USD` (LOW) +#### F3.3 — `USD` in enum value `LIST_PRICE_DOLLARS_USD` (LOW) - Wire value, leave as-is. But note that `DOLLARS_USD` is doubly redundant — USD already is dollars. See F7.1. @@ -158,7 +138,7 @@ _None._ #### F5.1 — `req` (LOW, Go-ism) - **Where:** `client.ts` every method, `utils.ts:103`. -- Already flagged under F1.4 / F13.1. +- Already flagged under F1.3 / F13.1. #### F5.2 — `resp` (LOW, Go-ism) - **Where:** `client.ts:88, 116, 150, 193, 242`; `utils.ts:73, 75, 81, 84, 88`. @@ -222,28 +202,7 @@ _None._ strictly a naming finding, included because it shows up as a field-domain mismatch. -#### F6.2 — `quantityThreshold` typed as `string` (LOW) -- **Where:** `model.ts:45`, JSDoc: "The threshold for the budget - alert to determine if it is in a triggered state." -- **Why flagged:** A "quantity threshold" sounds numeric, yet it is - a string (probably to preserve precision for currency). The name - does not signal the string-encoded-decimal contract. -- **Suggestion:** Either rename to `quantityThresholdString` (ugly) - or add JSDoc noting "Decimal string (preserves precision)" — the - latter is the standard fix. - -#### F6.3 — `BudgetConfiguration.alertConfigurations: AlertConfiguration[]` - array, but JSDoc says "Budgets must have exactly one alert - configuration." (MEDIUM) -- **Where:** `model.ts:59-60`, `client.ts:78` JSDoc reuses budget docs. -- **Why flagged:** The plural type contradicts the singular semantics. - Misleading at the type level. -- **Suggestion:** This is API-shape, not a TS rename concern. Flag for - the source spec to fix; in TS, document the invariant in JSDoc and - consider a tuple `[AlertConfiguration]` (overkill in practice). - See also F8.1. - -#### F6.4 — `flattenQueryParams` is exported but unused in this +#### F6.2 — `flattenQueryParams` is exported but unused in this package (LOW) - **Where:** `utils.ts:123-150`. - **Why flagged:** The name suggests it is a query-param helper for @@ -254,15 +213,6 @@ _None._ - **Suggestion:** Move shared helpers to `@databricks/sdk-core` or delete from this package's `utils.ts`. -#### F6.5 — JSDoc "previous get all budget configurations call" - (`pageToken` on `ListBudgetConfigurationsRequest`) (LOW) -- **Where:** `model.ts:160-162`. -- **Why flagged:** Documentation, not identifier. The method is - `listBudgetConfigurations`, not "get all". JSDoc text is stale - vs. the method name. -- **Suggestion:** Rewrite JSDoc: "A page token received from a - previous `listBudgetConfigurations` call." - --- ### 7. Overly verbose @@ -320,13 +270,6 @@ _None._ types and have `Create.../Update...` request types embed `BudgetConfiguration` (or `Budget`) directly. See also F10 / F11. -#### F7.4 — `LIST_PRICE_DOLLARS_USD` doubly redundant (LOW) -- **Where:** `model.ts:10`. -- **Why flagged:** `DOLLARS_USD` is tautological — USD *is* dollars. - This is a wire-protocol value, so the SDK cannot change it - unilaterally, but worth noting upstream. See also F17.2. -- **Suggestion:** Wire protocol; leave with a comment. - --- ### 8. Singular / plural mismatches @@ -335,8 +278,7 @@ _None._ semantically singular (HIGH) - **Where:** `model.ts:59-60, 107-108, 184-185`. - **Why flagged:** JSDoc states "Budgets must have exactly one alert - configuration." Field is plural array. Documented earlier (F6.3) as - misleading. + configuration." Field is plural array. - **Suggestion:** API-shape concern; document the invariant or switch to singular `alertConfiguration: AlertConfiguration` when the API allows. diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index cbf49169..8510f733 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -52,13 +52,6 @@ or an ID — they currently contradict each other. See also §5.2. multi-word casing applied elsewhere in the same enum (`MANAGED_ONLINE_CATALOG`). -#### 2.4 "UC Native" in doc comments (no longer present in current model.ts) -Doc comments previously used "UC Native" capitalisation; this phrasing -has been removed in the current generated source. Retained as a low- -priority observation in case the phrasing returns: when the codebase -uses `unity-catalog` in URLs and "Unity Catalog" in prose, the comment -should not shift to "UC Native" without spelling out the abbreviation. - --- ### 3. Cryptic abbreviations @@ -224,24 +217,12 @@ Mirror issue in `UpdateCatalogRequest`. ### 10. Underspecified IDs -#### 10.1 `metastoreId` (model.ts:82, 147, 294) -Documented as "unique identifier of parent metastore". Format opaque -(UUID? slug?). Acceptable but unspecified. - -#### 10.2 `azureTenantId` (model.ts:54) -GUID, implied by Azure context. Doc-less — not specified anywhere. - -#### 10.3 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:55, 56) -Doc-less. Format is an Azure resource ID -(`/subscriptions/…/providers/…`), not signalled by the name or -documentation. - -#### 10.4 `customerManagedKeyId` (model.ts:214) +#### 10.1 `customerManagedKeyId` (model.ts:214) Doc: "the CMK uuid in AWS and GCP, null otherwise." So the field is a UUID on AWS/GCP but `azureCmkAccessConnectorId` is an Azure resource ID elsewhere — same conceptual ID, two formats, no unifying name. -#### 10.5 `azureKeyVaultKeyId` (model.ts:216) +#### 10.2 `azureKeyVaultKeyId` (model.ts:216) Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See §4.2. @@ -412,7 +393,7 @@ passing for the broader review. | `CatalogType.DELTASHARING_CATALOG` | model.ts:13 | 2.3 | | `SecurableType` | model.ts:21 | 11.1 | | `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:39 | — | -| `AzureEncryptionSettings` | model.ts:53 | 2.1, 10.2 | +| `AzureEncryptionSettings` | model.ts:53 | 2.1 | | `CatalogInfo` | model.ts:59 | 6.1 | | `CatalogInfo.options` / `.properties` | model.ts:109, 107 | 4.4, 7.1, 8.1 | | `CatalogInfo.fullName` | model.ts:102 | 4.3, 8.2 | @@ -422,8 +403,8 @@ passing for the broader review. | `EffectivePredictiveOptimizationFlag` | model.ts:199 | 5.1, 6.2 | | `EffectivePredictiveOptimizationFlag.value` | model.ts:201 | 4.1 | | `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:203 | 1.1 | -| `EncryptionSettings.customerManagedKeyId` | model.ts:214 | 2.1, 10.4 | -| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:216 | 2.2, 4.2, 10.5 | +| `EncryptionSettings.customerManagedKeyId` | model.ts:214 | 2.1, 10.1 | +| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:216 | 2.2, 4.2, 10.2 | | `GetCatalogRequest.nameArg` | model.ts:223 | 3.1 | | `ListCatalogsRequest.maxResults` | model.ts:240 | — | | `ListCatalogsRequest.pageToken` | model.ts:242 | — | @@ -453,7 +434,7 @@ passing for the broader review. 2. **Distinguish or merge `options` and `properties`.** (§8.1) 3. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§2.2, §4.2) 4. **Strip read-only fields from `CreateCatalogRequest`/`UpdateCatalogRequest`.** (§9.2) -5. **Decide CMK casing and apply uniformly.** (§2.1, §10.4) +5. **Decide CMK casing and apply uniformly.** (§2.1, §10.1) 6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) --- diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md index 1d2d7896..66a68907 100644 --- a/.agent/naming-audit/cleanroomassets.md +++ b/.agent/naming-audit/cleanroomassets.md @@ -1,136 +1,3 @@ -# Naming Audit: `@databricks/sdk-cleanroomassets` (v1) +# Naming Audit: cleanroomassets -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/cleanroomassets/src/v1/` *(package removed)* -**Files audited (in full):** `model.ts`, `client.ts`, `utils.ts`, `index.ts` -**Scope:** every exported type, interface, enum, enum value, field, method, and -internal helper symbol. - -**Status:** The `cleanroomassets` package was removed from the SDK during -regeneration on 2026-05-13 (commit `28eac80`). Its contents were merged into -the `cleanrooms` package. All cited symbols, file paths, and line numbers -in this audit no longer exist at the cited locations. Surviving symbols -(e.g. `CleanRoomAsset*`, `ColumnInfo`, `PartitionSpecification*`, -`ColumnTypeName`, `ColumnMask`, `NotebookVersionReview`) are now located -in `packages/cleanrooms/src/v1/model.ts` and are covered by the -`cleanrooms` audit instead. - ---- - -## Summary of issue counts (by category) - -| # | Category | Count | -| -- | ----------------------------------------- | ----- | -| 1 | Vague / generic names | 0 | -| 2 | Redundant enum prefixes | 0 | -| 3 | Acronym casing inconsistencies | 0 | -| 4 | Underscores in TS identifiers | 0 | -| 5 | Cryptic abbreviations | 0 | -| 6 | Misleading names | 0 | -| 7 | Overly verbose names | 0 | -| 8 | Redundant suffixes | 0 | -| 9 | Singular / plural mismatches | 0 | -| 10 | Reserved-word / built-in collisions | 0 | -| 11 | Empty / trivial wrapper types | 0 | -| 12 | Duplicate concepts | 0 | -| 13 | Verb-tense inconsistency | 0 | -| 14 | Go / Java-style names | 0 | -| 15 | Generic field names losing meaning | 0 | -| 16 | Field contradicting type domain | 0 | -| 17 | Inconsistent action verbs | 0 | -| 18 | Long enum values | 0 | -| 19 | Underspecified IDs | 0 | -| 20 | Type-suffix tautology | 0 | -| -- | Cross-cutting: `CleanRoom` redundancy | 0 | -| -- | **Total findings** | **0** | - ---- - -## 1. Vague / generic names - -_None._ - -## 2. Redundant enum prefixes - -_None._ - -## 3. Acronym casing inconsistencies - -_None._ - -## 4. Underscores in TS identifiers - -_None._ - -## 5. Cryptic abbreviations - -_None._ - -## 6. Misleading names - -_None._ - -## 7. Overly verbose names - -_None._ - -## 8. Redundant suffixes - -_None._ - -## 9. Singular / plural mismatches - -_None._ - -## 10. Reserved-word / built-in collisions - -_None._ - -## 11. Empty / trivial wrapper types - -_None._ - -## 12. Duplicate concepts - -_None._ - -## 13. Verb-tense inconsistency - -_None._ - -## 14. Go / Java-style names - -_None._ - -## 15. Generic field names losing meaning - -_None._ - -## 16. Field contradicting type domain - -_None._ - -## 17. Inconsistent action verbs - -_None._ - -## 18. Long enum values - -_None._ - -## 19. Underspecified IDs - -_None._ - -## 20. Type-suffix tautology - -_None._ - -## Cross-cutting: `CleanRoom` redundancy across four sibling packages - -_None._ - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md index 17db4cda..f292ae11 100644 --- a/.agent/naming-audit/cleanroomautoapprovalrules.md +++ b/.agent/naming-audit/cleanroomautoapprovalrules.md @@ -1,43 +1,3 @@ -# Naming Audit: `@databricks/sdk-cleanroomautoapprovalrules` (`v1`) +# Naming Audit: cleanroomautoapprovalrules -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -Path: `/home/parth.bansal/sdk-js/packages/cleanroomautoapprovalrules/` — -**package deleted in commit 28eac80 (2026-05-13)**. - -The standalone `cleanroomautoapprovalrules` npm package was removed and its -symbols (the `CleanRoomAutoApprovalRule` enum/interfaces plus -`Create/Get/List/Update/DeleteCleanRoomAutoApprovalRule*` request/response -types and client methods) were folded into -`@databricks/sdk-cleanrooms/v1`. Any remaining naming concerns about those -symbols now live in `.agent/naming-audit/cleanrooms.md`, not here. - -## Summary - -| Severity | Count | -| ------------ | ----- | -| High | 0 | -| Medium | 0 | -| Low | 0 | -| Observation | 0 | -| **Total** | **0** | - -## High - -_None._ - -## Medium - -_None._ - -## Low - -_None._ - -## Observations - -_None._ - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index cad77628..43dd8e98 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -12,11 +12,10 @@ grouped by category, and each finding cites the file/line where it appears. ## Summary -- **Total findings:** 12 +- **Total findings:** 10 - **Highest-impact themes:** 1. Misleading boolean-shaped `accessRestricted` enum. - 2. Acronym casing inconsistencies (`Id` vs `ID`, `Dns` vs `DNS`, - `aws/azure/gcp`, `FEDRAMP`). + 2. Acronym casing inconsistencies (`Id` vs `ID`, `Dns` vs `DNS`). 3. Duplicate `Status` enum types and overlapping collaborator types. 4. Proto-architectural leaks: stray `Handler` suffix on list methods for notebook task runs. @@ -42,16 +41,6 @@ to `ID` across the SDK. **Note:** repo-wide convention should be confirmed. "DNS" is an initialism. Per the style guide, `azureDNSZone`. Currently `azureDnsZone` treats DNS as a word. -### 2.3 `cloudVendor?: string` containing `aws`, `azure`, `gcp` (model.ts:579) -Doc comment uses lowercase `aws,azure,gcp`. These are acronyms — should be -`AWS`, `Azure`, `GCP`. (Doc-only, but inconsistent with the enum members -`AWS_S3`, `AZURE_STORAGE`, `GOOGLE_CLOUD_STORAGE`.) - -### 2.4 `FEDRAMP_MODERATE`, `FEDRAMP_HIGH`, `FEDRAMP_IL5` (model.ts:82, 85, 86) -"FedRAMP" is the official spelling — `FEDRAMP` flattens the casing. -Identifier-level constraint of SCREAMING_SNAKE is fine, but documentation -text should match. - --- ## 3. Misleading Names diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md index 183d57b9..ab5c984b 100644 --- a/.agent/naming-audit/cleanroomtaskruns.md +++ b/.agent/naming-audit/cleanroomtaskruns.md @@ -1,308 +1,3 @@ -# Naming Audit: `cleanroomtaskruns` (v1) +# Naming Audit: cleanroomtaskruns -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `/home/parth.bansal/sdk-js/packages/cleanrooms/` (merged into the -`cleanrooms` package; cleanroomtaskruns symbols are now generated alongside -the other clean-room types). -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` -**Reference:** `databricks/databricks-sdk-go` `service/cleanrooms/{api,impl,model,interface}.go` and sibling TS packages (`cleanrooms`, `cleanroomassets`, `cleanroomautoapprovalrules`, `jobs/v2`). - ---- - -## Inventory - -### Enums -1. `CleanRoomTaskRunLifeCycleState` (model.ts:9) - - Values: `RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, `PENDING`, `RUNNING`, `TERMINATING`, - `TERMINATED`, `SKIPPED`, `INTERNAL_ERROR`, `BLOCKED`, `WAITING_FOR_RETRY`, `QUEUED`. -2. `CleanRoomTaskRunResultState` (model.ts:26) - - Values: `RUN_RESULT_STATE_UNSPECIFIED`, `SUCCESS`, `FAILED`, `TIMEDOUT`, - `CANCELED`, `MAXIMUM_CONCURRENT_RUNS_REACHED`, `UPSTREAM_CANCELED`, - `UPSTREAM_FAILED`, `EXCLUDED`, `EVICTED`, `SUCCESS_WITH_FAILURES`, - `UPSTREAM_EVICTED`, `DISABLED`. - -### Interfaces / Types -1. `CleanRoomNotebookTaskRun` (model.ts:538) - - Fields: `notebookName`, `startTime`, `runDuration`, `notebookJobRunState`, - `collaboratorJobRunInfo`, `outputSchemaName`, `outputSchemaExpirationTime`, - `notebookEtag`, `notebookUpdatedAt`. -2. `CleanRoomTaskRunState` (model.ts:599) - - Fields: `lifeCycleState`, `resultState`. -3. `CollaboratorJobRunInfo` (model.ts:606) - - Fields: `collaboratorJobId`, `collaboratorJobRunId`, `collaboratorTaskRunId`, - `collaboratorWorkspaceId`, `collaboratorAlias`. -4. `ListCleanRoomNotebookTaskRunsRequest` (model.ts:891) - - Fields: `cleanRoomName`, `notebookName`, `pageSize`, `pageToken`. -5. `ListCleanRoomNotebookTaskRunsResponse` (model.ts:902) - - Fields: `runs`, `nextPageToken`. - -### Zod schemas -- `unmarshalCleanRoomNotebookTaskRunSchema` -- `unmarshalCleanRoomTaskRunStateSchema` -- `unmarshalCollaboratorJobRunInfoSchema` -- `unmarshalListCleanRoomNotebookTaskRunsResponseSchema` - -### Client class -- `Client` (client.ts:85) - - Task-runs methods: `listCleanRoomNotebookTaskRunsHandler`, - `listCleanRoomNotebookTaskRunsHandlerIter`. - - Private fields: `host`, `httpClient`, `logger`, `userAgent`. - - Module constant: `PACKAGE_SEGMENT`. - -### Utils -- Types: `HttpCallOptions`. -- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`. - ---- - -## Findings - -### 1. `Handler` suffix on client methods — category 7 (Overly verbose) and category 14 (Go/Java-style names) - -**Symbol:** `Client.listCleanRoomNotebookTaskRunsHandler`, `Client.listCleanRoomNotebookTaskRunsHandlerIter` (client.ts:612, 651). - -**Issue:** The `Handler` suffix is anomalous within the SDK. Every other clean-room -method on the same client (`listCleanRooms`, `listCleanRoomAssets`, -`listCleanRoomAutoApprovalRules`) uses the bare verb form without `Handler`. The -Go reference API (`CleanRoomTaskRunsAPI.List`, `ListByCleanRoomName`) does not -use `Handler` either; "Handler" is an HTTP-server concept, not a client method -idiom. The suffix adds eight characters that convey nothing — the method already -takes a request and returns a response, which is the contract of a "handler" in -API parlance. - -**Suggested:** `listCleanRoomNotebookTaskRuns` and `listCleanRoomNotebookTaskRunsIter`. - -This is the most visible naming defect in the package because it is the only public -surface a TS consumer calls. It is also inconsistent across the SDK; this is a -**P0 fix** for cross-package consistency (audit category 14: every other package uses -camelCase `listX` style without Java/Go-style `Handler` decoration). - -### 2. `LifeCycleState` vs `lifecycle` casing — category 3 (Acronym/compound-word casing) - -**Symbols:** Enum `CleanRoomTaskRunLifeCycleState` and field -`CleanRoomTaskRunState.lifeCycleState` (model.ts:9, 601). - -**Issue:** "Lifecycle" is a single compound word in English (Merriam-Webster lists -it as one closed word). Treating it as two words (`LifeCycle` / `lifeCycle`) -produces an internal capital that doesn't match natural English. Sibling property -in the same struct is `resultState` — natural compound — making the mismatch -visible. Compare to `Date`/`URL` acronym handling: a single word should not have a -midword capital. - -**Suggested:** `CleanRoomTaskRunLifecycleState` and field `lifecycleState`. -Cross-check: the same `LifeCycle` casing exists in `jobs/v2/model.ts` (line 389) -and other "Run" types across the SDK, so a fix must be globally coordinated. - -### 3. `TIMEDOUT` is a non-word — category 6 (Misleading names) and category 13 (Verb tense inconsistency) - -**Symbol:** `CleanRoomTaskRunResultState.TIMEDOUT` (model.ts:30). - -**Issue:** `TIMEDOUT` mashes "timed out" into one token and drops the space without -forming a real word. Adjacent values use correct past-tense English -(`CANCELED`, `EVICTED`, `FAILED`, `SUCCEEDED`-style). The Go reference also uses -`TIMEDOUT`, so this originates upstream; flag for protocol fix. - -### 4. `etag` lowercase abbreviation — category 3 (Acronym casing) - -**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:559) and wire field -`notebook_etag` (line 1306). - -**Issue:** "ETag" is an HTTP standard token defined in RFC 7232 §2.3 ("entity tag") -and is written `ETag` in HTTP headers and most APIs. The TS Style Guide acronym -rule says treat acronyms as one word when 3+ letters (so `XmlHttpRequest`, not -`XMLHTTPRequest`). Two-letter acronyms can keep both letters capitalised. Either -`notebookETag` or `notebookEtag` is defensible; the field uses lowercase, but -elsewhere in the codebase (search `Etag|ETag` in `cleanrooms/v1`) the same -lowercase form is used for the `etag` field on `CleanRoomsNotebookTask`. Mark as -consistent within the codebase but worth re-examining at the SDK level. - -### 5. `notebookEtag` belongs to the notebook, not the task run — category 16 (Field contradicting type domain) - -**Symbol:** `CleanRoomNotebookTaskRun.notebookEtag` (model.ts:559). - -**Issue:** Field doc says "Etag of the notebook executed in this task run". The -field name is fine, but contrast with `notebookUpdatedAt` (line 561) — the -combination `notebookEtag` + `notebookUpdatedAt` implies the entire task-run -struct is mixing notebook metadata with run metadata. Consider whether these -should live under a nested `notebook` sub-object (`notebook.etag`, -`notebook.updatedAt`) in a future revision. Flag only — current shape mirrors Go. - -### 6. `notebookJobRunState` is unclear naming — category 1 (Vague/generic) and 12 (Duplicate concepts) - -**Symbol:** `CleanRoomNotebookTaskRun.notebookJobRunState` (model.ts:546). - -**Issue:** The doc says "State of the task run". The struct is already a *task -run*, and the same idea is also called a *Job run* by the collaborator field -right below. Three names for the same concept appear within one struct: -"task run state" (doc), "notebook job run state" (field name), and "job run info" -(neighbouring field). The naming churn is confusing. - -The field type is `CleanRoomTaskRunState`, so the natural field name is -`taskRunState` or just `state`. The "Job" interjected here mirrors how Jobs -service refers to a run as a "Job Run", but this package is about *task runs* — -the Go SDK source field is also `notebook_job_run_state` (i.e. the messiness is -inherited). - -**Suggested:** `state` or `taskRunState`. Cross-reference with `jobs/v2` -`cleanRoomJobRunState` (jobs/v2/model.ts:1158) which has the same shape with yet -*another* spelling — flag both for coordinated renaming. - -### 7. `runDuration` vs implicit "task run" — category 15 (Generic field names losing meaning) - -**Symbol:** `CleanRoomNotebookTaskRun.runDuration` (model.ts:544). - -**Issue:** The owning struct is already a "Run". Sibling fields drop the "run" -prefix (`startTime`, not `runStartTime`; `notebookEtag`, not `runNotebookEtag`), -yet duration carries it. Inconsistent. - -**Suggested:** `duration` (the doc already says "Duration of the task run, in -milliseconds"). Or rename `startTime` → `runStartTime` for consistency — pick one -side. - -### 8. `outputSchemaExpirationTime` — verbose — category 7 (Overly verbose) - -**Symbol:** `CleanRoomNotebookTaskRun.outputSchemaExpirationTime` (model.ts:557). - -**Issue:** `…Time` suffix is redundant; the value is a number (epoch ms). -Compare to `startTime` which legitimately is "time", and `notebookUpdatedAt` -(line 561) which already uses the more idiomatic `At` suffix for an epoch -millisecond timestamp. Within the *same struct*, three different conventions -coexist: `…Time`, `…At`, and `runDuration` (numeric duration). Pick one. - -**Suggested:** `outputSchemaExpiresAt` and `startedAt` — or normalise all three -to `…Time`. The `Run` pattern in other Databricks APIs leans toward `…At`. - -### 9. `CollaboratorJobRunInfo` repeats "collaborator" in every field — category 8 (Redundant suffixes) and category 2 (Redundant prefixes) - -**Symbol:** `CollaboratorJobRunInfo` (model.ts:606). Fields: `collaboratorJobId`, -`collaboratorJobRunId`, `collaboratorTaskRunId`, `collaboratorWorkspaceId`, -`collaboratorAlias`. - -**Issue:** Every field is prefixed with `collaborator`, but the enclosing struct -is already named `CollaboratorJobRunInfo`. Accessing `info.collaboratorJobId` -reads as "collaborator job-run info → collaborator job id". Drop the prefix: -`jobId`, `jobRunId`, `taskRunId`, `workspaceId`, `alias`. - -The Go SDK keeps the prefix to disambiguate inside the parent struct (`CleanRoomNotebookTaskRun.CollaboratorJobRunInfo.CollaboratorJobId`), -where the prefix is meaningful at the *top* level (`run.collaboratorJobRunInfo.collaboratorJobId`). -TS access lands one level deeper than the natural reading; the prefix is -duplicate. Match the JS idiom: drop the prefix on the nested fields. - -### 10. Type name `CollaboratorJobRunInfo` mixes "Job Run" and the rest of the package speaks "Task Run" — category 12 (Duplicate concepts) and category 9 (Singular/plural mismatch on the broader concept) - -**Symbol:** `CollaboratorJobRunInfo` (model.ts:606). - -**Issue:** Field `collaboratorTaskRunId` lives inside `CollaboratorJobRunInfo` -(model.ts:612). One struct uses both vocabulary domains. From Databricks docs: -a *Task run* is a single task within a *Job run* (a job can have N tasks). The -field doc strings here use "task run" almost exclusively — `Job ID of the task -run`, `Task run ID of the task run`, `triggered the task run`. The "Job Run" in -the struct *name* is therefore misleading; a more accurate name is -`CollaboratorTaskRunRef` or `CollaboratorRunRef`. Flag for coordination with API -team — the Go SDK has the same name. Cross-reference `jobs/v2` to align. - -### 11. `CleanRoomTaskRunState` and the field `notebookJobRunState` of type `CleanRoomTaskRunState` — category 6 (Misleading names) - -**Symbols:** model.ts:599, model.ts:546. - -**Issue:** Three name layers for the same idea. The doc on -`CleanRoomTaskRunState` says "Stores the run state of the clean rooms notebook -task" — i.e. it is the state of a *notebook task run*. The field that holds it is -called `notebookJobRunState`, which is then `CleanRoomTaskRunState`. The Java SDK -calls the same thing `NotebookTaskRunOutput.runState`. Suggest aligning on -`state: CleanRoomTaskRunState` (drop the doubled noun on the field name) and -keep the type name as-is (the wider SDK uses `…State` types throughout, e.g. -`RunState`, `JobState`). - -### 12. `pageSize` doc contradicts behaviour — category 6 (Misleading names) - -**Symbol:** `ListCleanRoomNotebookTaskRunsRequest.pageSize` (model.ts:897). - -**Issue:** Doc reads: "The maximum number of task runs to return. Currently -ignored - all runs will be returned." If the field is currently ignored, the -name `pageSize` is *misleading* — callers will set it expecting it to take -effect. Either remove the field (best), mark it `@deprecated`, or document this -in JSDoc with a `@deprecated` tag so IDEs show strike-through. Naming-wise: -`pageSize` is fine *if* it works; document the no-op via the deprecation tag, -not just a sentence inside the doc. - -### 13. `runs` field in response — category 15 (Generic field names losing meaning) — borderline acceptable - -**Symbol:** `ListCleanRoomNotebookTaskRunsResponse.runs` (model.ts:904). - -**Issue:** Generic given the package context, but defensible: this is the -canonical "list" shape (`{ items, nextPageToken }`). The doc string on it ("Name -of the clean room.") is *wrong* — copy-paste error from the request struct's -`cleanRoomName` doc. Doc-text bug, not a naming bug, but worth flagging during a -naming pass since reviewers will notice the field while reading docs. - -### 14. `nextPageToken` is the canonical name — pass. - -No issue. Matches all other listing responses in the SDK. - -### 15. `Client` class name — category 1 (Vague/generic) — *pass* - -Package convention. Every TS package exports a single `Client` class scoped to its -import path (e.g. `@databricks/sdk-cleanrooms/v1`). - -### 16. `userAgent` and `httpClient` — *pass* - -Standard names; acronym handling is consistent (`Url` would be flagged but -`HttpClient` is acceptable under the project rule and matches the imported type). - -### 17. `flattenQueryParams` — *pass*, but unused (dead code) - -**Symbol:** `flattenQueryParams` (utils.ts:123). - -**Issue:** Imported nowhere within this package's client (the `list` method builds -its querystring inline at client.ts:617–626). The helper is dead code in this -package. Naming itself is fine. Suggest deleting or extracting to a shared utility -in `@databricks/sdk-core/http`. - -### 18. `readAll(body)` — *pass* - -Helper does what its name says. - ---- - -## Cross-package notes (per audit instructions) - -### `TaskRun` field-name divergence between `cleanroomtaskruns` and `jobs/v2` - -The state field that holds a `CleanRoomTaskRunState` is named `notebookJobRunState` -in this package (model.ts:546) and `cleanRoomJobRunState` in `jobs/v2` -(jobs/v2/model.ts:1158). Two names for one wire-level concept across the two -packages that talk about the same run object. Audit category 12 (duplicate -concepts) — coordinate a single field name across both packages. - -### `NotebookTask` concept - -`CleanRoomNotebookTaskRun` (this package) → `CleanRoomsNotebookTask` (jobs/v2, -note plural "Rooms"!) → `CleanRoomNotebookTask` (jobs/v2, deprecated V0). Three -spellings of "clean room(s) notebook task" across two packages. Specifically, -the jobs/v2 package has `CleanRoomsNotebookTask` (plural rooms, -model.ts:1141) explicitly distinguished from the deprecated `CleanRoomNotebookTask` -(singular). This package uses the singular form `CleanRoomNotebookTaskRun`. The -intent is consistent — singular when referring to a specific room, plural for the -service name — but a reader is left to guess. - ---- - -## Summary (counts) - -- **Critical / cross-package consistency:** 1 finding (#1 `Handler` suffix). -- **High (style guide violations):** 2 findings (#2 LifeCycle casing, #9 - collaborator prefix repetition). -- **Medium (naming clarity):** 7 findings (#3, #6, #7, #8, #10, #11, #12). -- **Low / project-wide convention notes:** 4 findings (#4, #5, #13, #17) — - some inherited from generator. -- **Pass / acceptable as-is:** 4 findings (#14, #15, #16, #18). - -**Total flagged findings: 14** distinct items across audit categories (some -findings touch multiple categories). - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index 754d2ce2..f4d86436 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -64,20 +64,13 @@ _None._ per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. - Severity: medium. -### 4.2 `LibraryInstallStatus` value `RESTORED` — `model.ts:35` -- The docstring says "Library installation is restored and can be used." - But `RESTORED` overlaps semantically with `INSTALLED`. Without further - context (cache restore vs. fresh install), consumers cannot distinguish. - Name is technically accurate but underspecified. -- Severity: low. - -### 4.3 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:28` +### 4.2 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:28` - This is the only value that is an action+condition (rather than a state noun). Surrounding values are `PENDING`, `INSTALLED`, `FAILED`. A noun form like `PENDING_UNINSTALL` would line up. See also §10.2. - Severity: medium. -### 4.4 `allClusterStatuses()` — `client.ts:74` +### 4.3 `allClusterStatuses()` — `client.ts:74` - Method is the GET for `all-cluster-statuses`. The TS method name reads like an adjective ("all-cluster statuses") and is not verb-prefixed. Sibling method is `clusterStatus()` (also verb-less). Compare with the @@ -85,7 +78,7 @@ _None._ verb-prefixed). The two GET methods alone are exempt. Should be `listAllClusterStatuses` or `getAllClusterStatuses`, and `getClusterStatus` respectively. -- Severity: medium. See also §11. +- Severity: medium. See also §10. --- @@ -110,13 +103,7 @@ _None._ ## 7. Singular/plural mismatches -### 7.1 `MavenLibrary.exclusions` — `model.ts:156` -- Plural; field is a list. Doc says "List of dependences to exclude" — - consistent. No issue (note: "dependences" is a typo for "dependencies", - inherited from the API doc string). -- Severity (typo): low. - -### 7.2 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:134` +### 7.1 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:134` - Singular method name `allClusterStatuses` (`client.ts:74`) for what is semantically a list operation. The action verb should be `list`. See §11. - Severity: medium. @@ -142,13 +129,13 @@ _None._ - `installLibraries`, `uninstallLibraries` use verb-prefixed forms. - Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: `listAllClusterStatuses` (or `getAllClusterStatuses`) and - `getClusterStatus`. See §4.4 and §11. + `getClusterStatus`. See §4.3 and §11. - Severity: high (consistency of the verb-prefix is a Java/TS SDK convention that consumers rely on). ### 10.2 `LibraryInstallStatus` action vs state values — `model.ts:6` - Values mostly nouns (`PENDING`, `INSTALLED`, `FAILED`) but one verb - imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §4.3. + imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §4.2. - Severity: medium. --- @@ -213,12 +200,11 @@ _None._ - `LibraryFullStatus` with no "non-full" counterpart (§4.1). - `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state - (§4.3, §10.2). + (§4.2, §10.2). ### Low-severity / stylistic -- `LibraryInstallStatus.RESTORED` underspecified vs `INSTALLED` (§4.2). -- "dependences" typo in `MavenLibrary.exclusions` doc (§7.1). +_None._ --- diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index b83c0c28..b229f782 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -159,7 +159,6 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | M-01 | `EditPolicyRequest` (`model.ts:63`) / `editPolicy()` (`client.ts:133`) | High | Standard CRUD verbs in TS/REST are **create / read / update / delete**. The Databricks "Cluster Policies 2.0" API uses `/edit` as the wire path, but the SDK could still expose `updatePolicy` (with `UpdatePolicyRequest` request type) which is the conventional REST verb. Compare with the newer `policies` API surface and most other Databricks SDK resources that expose `update*`. As-is, the SDK exposes `editPolicy` while peer packages (e.g. `clusters`) often expose `editCluster` too — there is precedent — but it remains inconsistent with the broader CRUD vocabulary. Tracked here as a discrepancy worth raising upstream. | -| M-02 | `MavenLibrary.exclusions` JSDoc says "List of dependences to exclude" (`model.ts:196`) | Low | Typo in the JSDoc ("dependences"); not a name issue per se. | ### 2.7 Overly verbose / Redundant suffixes — Medium @@ -286,8 +285,8 @@ architectural-layer words leaking into domain identifiers. | -------- | ----- | | High | 2 | | Medium | 11 | -| Low | 30 | -| **Total**| **43**| +| Low | 29 | +| **Total**| **42**| ### 3.2 Top themes diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index b47e228a..57c73f05 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -29,20 +29,18 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | 6 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | | 7 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | | 8 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to a single form (e.g. `Failed` in place of `Error` so every member is a past/present participle). | -| 9 | medium | 3. Acronym casing inconsistency | `model.ts:133` | `isJsonSchema` | OK (Json compound); contrast with `JsonValue`, `JsonObject` from wkt — confirm casing rule | -| 10 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | -| 11 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 12 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 13 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 14 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 15 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 16 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 17 | low | 1. Vague/generic | `model.ts:142` | `truncated?: boolean` | OK, but document what is truncated | -| 18 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | -| 19 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | -| 20 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | -| 21 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 22 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 9 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | +| 10 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 11 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 12 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 13 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 14 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 15 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 16 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | +| 17 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | +| 18 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | +| 19 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 20 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | --- @@ -177,27 +175,14 @@ should be `FAILED` (past participle) to match the pattern. --- -### Finding 9 — Medium — Cat 3 (Acronym casing) -**Location:** `src/v2/model.ts:133` -```ts -isJsonSchema?: boolean | undefined; -``` -`Json` is treated as a compound (PascalCase). Cross-package -`@databricks/sdk-core/wkt` uses `JsonValue`, `JsonObject` — consistent. -Project convention: treat JSON as `Json`, not `JSON`. Confirm the rule is -recorded in `.agent/rules/typescript.mdc`. -**Proposed:** keep as-is; document the rule. - ---- - -### Finding 10 — Medium — Cat 12 (Duplicate concepts) +### Finding 9 — Medium — Cat 12 (Duplicate concepts) **Location:** `src/v2/client.ts:286-309` **Issue:** `execute()` returns `Promise`. The conflation of "create a context" and "execute returns an id" is artificial. See #2. --- -### Finding 11 — Medium — Cat 14 (Go/Java-style names) +### Finding 10 — Medium — Cat 14 (Go/Java-style names) **Location:** `src/v2/model.ts:74` + `client.ts:256` **Issue:** `destroy` is unusual for a REST SDK. JS conventions favour `delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend @@ -208,15 +193,15 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 12 — Medium — Cat 8 (Redundant suffix) — call-out +### Finding 11 — Medium — Cat 8 (Redundant suffix) — call-out **Location:** `src/v2/client.ts:333, 417, 498` **Issue:** Three classes named `*Waiter`. Acceptable if waiter is a recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #13-#15. +issue is what they wait *for*: see #12-#14. --- -### Finding 13 — Medium — Cat 6 (Misleading name) +### Finding 12 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:417` ```ts export class CreateWaiter { ... } @@ -231,21 +216,21 @@ target endpoint). --- -### Finding 14 — Medium — Cat 6 (Misleading name) +### Finding 13 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:333` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 15 — Medium — Cat 6 (Misleading name) +### Finding 14 — Medium — Cat 6 (Misleading name) **Location:** `src/v2/client.ts:498` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. --- -### Finding 16 — Medium — Cat 17 (Inconsistent action verbs) — call-out +### Finding 15 — Medium — Cat 17 (Inconsistent action verbs) — call-out **Location:** `src/v2/client.ts:86, 256` **Issue:** This package uses three lifecycle verbs: - `cancel()` on a command, @@ -258,18 +243,7 @@ Go-SDK alignment decision. --- -### Finding 17 — Low — Cat 1 (Underspecified) -**Location:** `src/v2/model.ts:141-142` -```ts -/** true if partial results are returned. */ -truncated?: boolean | undefined; -``` -Acceptable but ambiguous: truncated *what*? table rows? text length? -**Proposed:** document the truncation unit. - ---- - -### Finding 18 — Low — Cat 1 (Vague/generic) — call-out +### Finding 16 — Low — Cat 1 (Vague/generic) — call-out **Location:** `src/v2/client.ts:54` ```ts class StillRunningError extends Error {} @@ -278,7 +252,7 @@ Private, OK. Idiomatic for waiter polling patterns. --- -### Finding 19 — Low — Cat 3 (Acronym casing) — non-issue +### Finding 17 — Low — Cat 3 (Acronym casing) — non-issue **Location:** `src/v2/client.ts:49-52` ```ts const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; @@ -289,20 +263,20 @@ correctly cased per the project rules. --- -### Finding 20 — Low — Cat 14 — non-issue +### Finding 18 — Low — Cat 14 — non-issue **Location:** `src/v2/client.ts:54` **Issue:** `StillRunningError` is named in idiomatic TS style (`*Error` suffix on classes extending Error). --- -### Finding 21 — Low — Cat 15 (Generic field) — call-out +### Finding 19 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. --- -### Finding 22 — Low — Cat 3 (Acronym casing in enum string values) +### Finding 20 — Low — Cat 3 (Acronym casing in enum string values) **Location:** `src/v2/model.ts:42-43` ```ts SQL = 'SQL', diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 54e7511a..8158e55c 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -3,13 +3,13 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 23 +**Total weird names flagged:** 21 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 11 | +| High | 5 | +| Medium | 8 | | Low | 6 | | Observation | 2 | @@ -53,55 +53,43 @@ - **Suggested name:** Either drop the field (it's always `CONNECTION`), or rename to `securableKind: SecurableType` and document why a non-`CONNECTION` value would ever appear. - **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. -### 7. `ConnectionInfo.fullName` vs `name` — `src/v1/model.ts:91,101` -- **Why weird:** Two name-like fields (`name` and `fullName`) with no inline doc explaining the difference. The wire pattern in Unity Catalog is "name within a parent" vs "catalog.schema.connection_name", but the type doesn't say that. -- **Category:** 1 (vague — what makes a name "full"?), 17 (inconsistency: `name` is short, `fullName` is fully qualified but doc only says "Full name of connection"). -- **Suggested name:** Keep names; improve doc to clarify `fullName` is the dot-qualified path (`catalog.schema.connection_name`). -- **Rationale:** Naming is fine; documentation is the gap. Flagging because the readability of every field that pairs with `name` depends on knowing that `fullName` is the path-style form. - -### 8. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:97` +### 7. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:97` - **Why weird:** Boolean field name doesn't begin with `is`/`has` as is common for TS booleans. Reads `connection.readOnly` (acceptable adjective form) but sibling enums and types use noun forms. JS naming conventions are split, but inside this SDK most booleans use the adjective form, so this is consistent — flagging at low-medium severity because the rule itself is debatable. - **Category:** 1 (vague form — `readOnly` could be a string of mode flags). - **Suggested name:** Keep as `readOnly` (matches Go SDK and is widely used in JS). Optionally `isReadOnly`. - **Rationale:** No strong convention either way; flagging because audit asked for booleans whose nature isn't obvious from the name. -### 9. `CreateConnectionRequest` / `UpdateConnectionRequest` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:138,230` +### 8. `CreateConnectionRequest` / `UpdateConnectionRequest` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:138,230` - **Why weird:** `CreateConnectionRequest` is `ConnectionInfo` shape. `UpdateConnectionRequest` is `ConnectionInfo + nameArg + newName + name`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnectionRequest` and `UpdateConnectionRequest` even though they're server-only). - **Category:** 12 (duplicate concepts), 6 (misleading — user-settable vs server-set is invisible). - **Suggested name:** Split server-only metadata into a base type and compose. Better still, type create/update inputs as `Pick` or a dedicated `ConnectionInput` interface. - **Rationale:** Today a caller could set `connection.createdAt` on a create request and have no idea it's silently ignored. Type system can prevent this. -### 10. `ListConnectionsRequest.maxResults` semantics — `src/v1/model.ts:201-208` -- **Why weird:** Three different behaviours encoded in the same field: "not set → all results", "0 → server default", ">0 → bound by min(value, server-default)", "<0 → error". Numeric overload that is invisible from the name. -- **Category:** 6 (misleading — `maxResults` implies upper bound, but `0` actually requests server default). -- **Suggested name:** Either two separate fields (`pageSize` and `useServerDefault`), or document inline tersely. Keep name; flag as observation. -- **Rationale:** Name is fine; behaviour overloaded. Easy to call wrong. - -### 11. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:75` +### 9. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:75` - **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. - **Category:** 6 (misleading — value advertised but not actually a securable yet). - **Suggested name:** Hide until promotion or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. -### 12. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:52` +### 10. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:52` - **Why weird:** `SSWS` is cryptic. (Stands for "Single Sign-On Web Services" or Okta SSWS — Secure Single Sign-on. Either way, opaque.) Other tokens are named after their family (OAuth, OIDC, Bearer); SSWS is the only one with a literal product-specific acronym. - **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling values). - **Suggested name:** `OKTA_SSWS_TOKEN` (if it's strictly Okta), or document in doc-comment. - **Rationale:** Future readers cannot guess what SSWS expands to. -### 13. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:53` +### 11. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:53` - **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while sibling values put the vendor first. Inconsistent word order. - **Category:** 17 (inconsistency). - **Suggested name:** `AKAMAI_EDGEGRID`. - **Rationale:** Consistency with vendor-first patterns elsewhere. -### 14. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,272,278` +### 12. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,272,278` - **Why weird:** Proto-architectural-leak naming. Proto-style nested entry types with underscore-joined identifiers leak into the public TS surface. Each `Options` and `Properties` map gets a corresponding `*_OptionsEntry`/`*_PropertiesEntry` interface — six total — that is exported but trivial (`{key?, value?}`). The wire shape is already covered by `Record`. - **Category:** Proto-architectural leak (`_OptionsEntry` / `_PropertiesEntry` proto map-entry message names), 12 (duplicate concept), 5 (cryptic — underscore-joined identifiers). - **Suggested name:** Remove the `*Entry` interfaces from the public API; rely on `Record`. - **Rationale:** These entry types add visual noise and are not used by the surface (the field is `Record`). -### 15. `ProvisioningInfo_State` — `src/v1/model.ts:79` +### 13. `ProvisioningInfo_State` — `src/v1/model.ts:79` - **Why weird:** Proto-architectural-leak naming. Underscore-joined identifier (`ProvisioningInfo_State`) is a proto nested-enum name (`ProvisioningInfo.State`) emitted verbatim into TS. The enum is suppressed via `eslint-disable @typescript-eslint/naming-convention`, confirming it breaks TS conventions. Standalone TS would name this `ProvisioningState` (or merge into `ProvisioningInfo`). - **Category:** Proto-architectural leak (`_State` underscore-joined nested enum name). - **Suggested name:** `ProvisioningState`. @@ -109,19 +97,19 @@ ## Low severity -### 16. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` +### 14. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` - **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. -### 17. `flattenQueryParams` — `src/v1/utils.ts:123` +### 15. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Remove from utils if generator default. - **Rationale:** Generator emits the same helper into every package even when unused. -### 18. `readAll` — `src/v1/utils.ts:40` +### 16. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. - **Category:** 1 (vague). - **Suggested name:** `readStreamToEnd` / `drainStream`. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 467f7466..0cb80601 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -3,13 +3,13 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, and notification routing on failure. -**Total weird names flagged:** 28 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 7 | +| Medium | 4 | | Low | 8 | | Observation | 5 | @@ -65,43 +65,25 @@ ## Medium severity -### 9. `CancelRefreshResponse.refresh` JSDoc says "The refresh to cancel" — `src/v1/model.ts:125` -- **Why weird:** JSDoc on `CancelRefreshResponse.refresh` says "The refresh to cancel" but this is the response (the refresh that *was* cancelled). The doc verb tense contradicts the type name. Listed as naming because the field's contextual meaning is shaped by stale request-side docs. -- **Category:** 13 (verb tense — "to cancel" is forward-looking; "cancelled" / "the cancelled refresh" is past-tense). -- **Suggested name:** Field stays `refresh`; doc should read "The cancelled refresh." -- **Rationale:** Documentation accuracy. The current text implies user intent rather than response state. - -### 10. `DeleteRefreshRequest` doc-block typo "Request to delete a ronitor." — `src/v1/model.ts:270` -- **Why weird:** Doc string typo "ronitor" (should be "monitor" or "refresh"). Affects discoverability via IDE tooltip search. Plus, the doc text says "monitor" but the type's purpose is deleting a refresh — meta-error. -- **Category:** 6 (misleading — typo invites confusion about the type's purpose). -- **Suggested name:** Doc should read "Request to delete a refresh." -- **Rationale:** Generator-emitted typo. Listed because the doc is the first thing IDE users see. - -### 11. `DataProfilingCustomMetric.outputDataType: string` vs `type: DataProfilingCustomMetricType` — `src/v1/model.ts:247` -- **Why weird:** Field name is `outputDataType` and JSDoc says "The output type of the custom metric." — the JSDoc drops `Data`. Field is typed `string`, no enum. Compare with `type: DataProfilingCustomMetricType` which is enum and is the *kind* of metric, not its *data type*. The reader must parse two `type` fields on the same type. -- **Category:** 1 (vague — `outputDataType` vs `type`), 12 (duplicate concept — two `type`s), 17 (inconsistent — one is enum, one is string). -- **Suggested name:** Document the distinction in JSDoc, or strengthen `outputDataType`'s type from `string` to an enum of supported SQL types. -- **Rationale:** Two `type`-like fields on the same struct is a code-smell; the typing should distinguish them. - -### 12. `DataProfilingStatus` has both `ERROR` and `FAILED` members; `DELETE_PENDING` word order — `src/v1/model.ts:57` +### 9. `DataProfilingStatus` has both `ERROR` and `FAILED` members; `DELETE_PENDING` word order — `src/v1/model.ts:57` - **Why weird:** The enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately, with no JSDoc distinguishing them. Separately, `DELETE_PENDING` orders the tokens verb-then-state where most APIs write `PENDING_DELETE` (state-modified-by-action). - **Category:** 12 (duplicate concept — `ERROR` and `FAILED`), 17 (inconsistent word order vs sibling `PENDING`). - **Suggested name:** Either merge `ERROR` and `FAILED` into a single member, or document the difference in JSDoc. Reorder `DELETE_PENDING` to `PENDING_DELETE`. - **Rationale:** The implicit duplicate of `ERROR`/`FAILED` makes this enum harder to reason about than it should be; two synonymous terminal states force callers to handle both. `PENDING_DELETE` mirrors the existing `PENDING` member's modifier-suffix shape. -### 13. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` +### 10. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` - **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #6). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). - **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). - **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. -### 14. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` +### 11. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` - **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. - **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). - **Suggested name:** Type: `Destination` (drop the `Notification` prefix since the type is only used here). Field stays `onFailure`; update doc to clarify timeout semantics. - **Rationale:** Field name and JSDoc should agree on whether timeouts are included; type name should not repeat its parent's noun. -### 15. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` +### 12. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` - **Why weird:** Five sibling types all end in `Config`: `AnomalyDetectionConfig`, `DataProfilingConfig`, `InferenceLogConfig`, `TimeSeriesConfig`, `SnapshotConfig`. The `Config` suffix is a proto-style architectural label — it adds no semantic information once you know the type is a configuration record. The Go reference SDK uses these names because protobuf's `*Config` messages map 1:1 to Go structs, but TS does not need to carry that scaffolding. The leak is most visible at the call site `DataProfilingConfig.analysisConfig` where three `Config`-suffixed arms nest inside a `Config`-suffixed field on a `Config`-suffixed type — triple `Config` nesting in a single access path. - **Category:** proto-architectural-leak (repeated `Config` mid/suffix), 8 (redundant suffix), 12 (duplicate concept). - **Suggested name:** Drop the `Config` suffix on the analysis-arm types: `InferenceLog`, `TimeSeries`, `Snapshot`. Keep `AnomalyDetectionConfig` / `DataProfilingConfig` as the top-level monitor configurations (they are genuinely "the config" of a `Monitor`). Or rename uniformly to `AnomalyDetectionSettings` / `DataProfilingSettings` and use `Analysis` for the arm types. @@ -109,37 +91,37 @@ ## Low severity -### 16. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 13. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Exported helper that is never called from `client.ts`. The package's two list endpoints handle pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. - **Category:** 6 (misleading — looks like it's used; isn't). - **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). - **Rationale:** Same as `dataclassification` finding #19. -### 17. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` +### 14. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Layering not visible from names; identical to `dataclassification` finding #15. - **Category:** 1, 12, 17. - **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). - **Rationale:** Layering should be readable from the names without opening the source. -### 18. `buildHttpRequest` — `src/v1/utils.ts:96` +### 15. `buildHttpRequest` — `src/v1/utils.ts:96` - **Why weird:** Same as `dataclassification` finding #16; "build" suggests builder pattern, the function spreads literals. - **Category:** 1, 6. - **Suggested name:** `makeHttpRequest`. - **Rationale:** "Make" matches the simpler reality. -### 19. `readAll` — `src/v1/utils.ts:40` +### 16. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Identical to `dataclassification` finding #20; "readAll" does not say "drain a stream". - **Category:** 1, 5. - **Suggested name:** `drainStream`. - **Rationale:** Self-describing name for stream draining. -### 20. `HttpCallOptions` — `src/v1/utils.ts:15` +### 17. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same as `dataclassification` finding #21; internal context bag called `Options`. - **Category:** 1, 8. - **Suggested name:** `HttpCallContext`. - **Rationale:** Reserve `Options` for user-tunable knobs. -### 21. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` +### 18. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` - **Why weird:** Same as `dataclassification` finding #22; unspecific noun for a User-Agent identity object. - **Category:** 1. - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md index 7f709e9f..c278c71c 100644 --- a/.agent/naming-audit/endpoints.md +++ b/.agent/naming-audit/endpoints.md @@ -1,1081 +1,3 @@ -# Naming Audit: `endpoints` (v1) +# Naming Audit: endpoints -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Package:** `@databricks/sdk-vectorsearch` (formerly `@databricks/sdk-endpoints`) -**Path:** `/home/parth.bansal/sdk-js/packages/vectorsearch/` -**Version audited:** `v1` -**Files audited:** -- `src/v1/model.ts` -- `src/v1/client.ts` -- `src/v1/utils.ts` -- `src/v1/index.ts` - -This audit applies the 20 numbered concern categories from the audit -checklist plus a special section on the package name itself. The -package was previously named `@databricks/sdk-endpoints`; in the -2026-05-20 regeneration the package was renamed to `@databricks/sdk-vectorsearch` -and absorbed the contents of the former `@databricks/sdk-indexes` -package. Many of the F0 findings about package ambiguity are now -fixed. Findings are grouped by category. - ---- - -## Inventory - -### Package identity - -| Item | Value | -| --------------- | ---------------------------------- | -| Package name | `@databricks/sdk-vectorsearch` | -| Directory | `packages/vectorsearch/` | -| Subpath export | `./v1` | -| REST base path | `/api/2.0/vector-search/endpoints` and `/indexes` | -| Concept | Vector Search endpoints and indexes | - -### Enums (`model.ts`) - -| Name | Members | -| ------------------------------- | ---------------------------------------------------------------------------------------------------------- | -| `EndpointType` | `STORAGE_OPTIMIZED`, `STANDARD` | -| `IndexSubtype` | `VECTOR`, `FULL_TEXT`, `HYBRID` | -| `PipelineType` | `TRIGGERED`, `CONTINUOUS` | -| `ScalingChangeState` | `SCALING_CHANGE_UNSPECIFIED`, `SCALING_CHANGE_APPLIED`, `SCALING_CHANGE_IN_PROGRESS` | -| `UpsertDeleteDataStatus` | `SUCCESS`, `PARTIAL_SUCCESS`, `FAILURE` | -| `VectorIndexType` | `DELTA_SYNC`, `DIRECT_ACCESS` | -| `EndpointStatus_State` | `PROVISIONING`, `ONLINE`, `OFFLINE`, `RED_STATE`, `YELLOW_STATE`, `DELETED` | - -### Interfaces (`model.ts`) - -`ColumnInfo`, `CreateEndpointRequest`, `CreateVectorIndexRequest`, -`CustomTag`, `DeleteDataVectorIndexRequest`, `DeleteDataVectorIndexResponse`, -`DeleteEndpointRequest`, `DeleteEndpointResponse`, `DeleteVectorIndexRequest`, -`DeleteVectorIndexResponse`, `DeltaSyncVectorIndexSpec`, -`DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`, -`EmbeddingSourceColumn`, `EmbeddingVectorColumn`, `Endpoint`, -`EndpointScalingInfo`, `EndpointStatus`, `GetEndpointRequest`, -`GetVectorIndexRequest`, `ListEndpointRequest`, `ListEndpointResponse`, -`ListValue`, `ListVectorIndexRequest`, `ListVectorIndexResponse`, -`MapStringValueEntry`, `MiniVectorIndex`, `PatchEndpointBudgetPolicyRequest`, -`PatchEndpointBudgetPolicyResponse`, `PatchEndpointRequest`, -`QueryVectorIndexNextPageRequest`, `QueryVectorIndexRequest`, -`QueryVectorIndexResponse`, `RerankerConfig`, -`RerankerConfig_RerankerParameters`, `ResultData`, `ResultManifest`, -`ScanVectorIndexRequest`, `ScanVectorIndexResponse`, `Struct`, -`SyncVectorIndexRequest`, `SyncVectorIndexResponse`, -`UpsertDataVectorIndexRequest`, `UpsertDataVectorIndexResponse`, -`UpsertDeleteDataResult`, `Value`, `VectorIndex`, `VectorIndexStatus`. - -### Client methods (`client.ts`) - -`createEndpoint`, `createEndpointWaiter`, `createVectorIndex`, -`deleteDataVectorIndex`, `deleteEndpoint`, `deleteVectorIndex`, -`getEndpoint`, `getVectorIndex`, `listEndpoint`, `listEndpointIter`, -`listVectorIndex`, `listVectorIndexIter`, `patchEndpoint`, -`patchEndpointBudgetPolicy`, `queryVectorIndex`, -`queryVectorIndexNextPage`, `scanVectorIndex`, `syncVectorIndex`, -`upsertDataVectorIndex`. - -### Client classes (`client.ts`) - -`Client`, `CreateEndpointWaiter`, `StillRunningError` (private). - -### Utility functions (`utils.ts`) - -`executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, -`parseResponse`, `marshalRequest`, `flattenQueryParams`. - -### Utility types/interfaces (`utils.ts`) - -`HttpCallOptions`. - ---- - -## F0 — Package-level: "endpoint" is dangerously overloaded - -The package rename to `@databricks/sdk-vectorsearch` resolved much of -the ambiguity called out in the original audit. Some residual concerns -remain about the unqualified `Endpoint` type name. - -### F0.1 — `Endpoint` type still unqualified inside the package (MEDIUM) -- **Where:** `model.ts:274`, `index.ts:31`. -- **Why flagged:** The package rename to `vectorsearch` qualifies the - package identity, but the exported type is still `Endpoint`. A - consumer who imports - `import {Endpoint} from '@databricks/sdk-vectorsearch'` and then - passes it into a function `process(e: Endpoint)` loses the - package-level qualification once the import is destructured. -- **Suggestion:** Rename `Endpoint` → `VectorSearchEndpoint` to mirror - `modelserving.InferenceEndpoint`. Slightly verbose but eliminates - the ambiguity at the type level. - ---- - -## Findings - -### 1. Vague / generic names - -#### F1.1 — `Endpoint` type name (MEDIUM) -- **Where:** `model.ts:274`, `index.ts:31`, return type of - `createEndpoint`, `getEndpoint`, `patchEndpoint`, items of - `listEndpointIter`. -- **Why flagged:** "Endpoint" alone is one of the most generic nouns - in REST APIs (every URL is an endpoint). Combined with F0.1, a user - reading `function process(e: Endpoint)` cannot tell whether this - is a vector-search endpoint, a model-serving endpoint, or a SQL - warehouse endpoint. -- **Suggestion:** Rename to `VectorSearchEndpoint`. Mirrors - `modelserving.InferenceEndpoint` and provides parity - across packages. All sibling type names (`EndpointType`, - `EndpointStatus`, `EndpointScalingInfo`) follow. - -#### F1.2 — `EndpointType` enum, `EndpointStatus` interface (MEDIUM) -- **Where:** `model.ts:18, 314`; `index.ts:6, 33`. -- **Why flagged:** Same generic-noun problem as F1.1. `Endpoint*` - symbols collide across the monorepo (cf. `warehouses.EndpointState`, - `modelserving.InferenceEndpoint`). -- **Suggestion:** Qualify with `VectorSearch` prefix — - `VectorSearchEndpointType`, `VectorSearchEndpointStatus`. Or move - these into a namespace `VectorSearchEndpoint.Status` / - `VectorSearchEndpoint.Type`. - -#### F1.3 — `Client` class name (MEDIUM, cross-cutting) -- **Where:** `client.ts:85`, `index.ts:3`. -- **Why flagged:** Every package in this SDK exports a `Client`. - `import {Client} from '@databricks/sdk-vectorsearch'` is unqualified - and routinely needs `import {Client as VectorSearchClient}` - at the call site. Project-wide pattern. -- **Suggestion:** Keep `Client` and document the per-package - alias convention, or rename to `VectorSearchClient` - consistently across packages. Cross-cutting decision. - -#### F1.4 — `name` field everywhere (MEDIUM) -- **Where:** `model.ts:91, 98, 115, 139, 147, 161, 169, 254, 269, 276, - 323, 328, 339, 378, 403, 416, 427, 436, 512, 534, 542, 574`; - `client.ts` throughout. -- **Why flagged:** `name` is one of the most generic identifiers - possible. JSDoc explains "Name of the AI Search endpoint", but - the field name alone gives no domain hint. Worse, this `name` is - used as the *path-segment identifier* (`/endpoints/${req.name ?? - ''}`) — i.e. it is functionally an ID. Other packages call this - `id`, `pipelineId`, etc. -- **Suggestion:** Either: - - Rename to `endpointName` for self-documentation, or - - Document the dual role in JSDoc on `Endpoint.name`. Note the - `Endpoint` type already has both `name: string` and `id: string` - — see F12.3 / F19.2 for the duplicate-identifier problem. - -#### F1.5 — `req` parameter name on every client method (LOW, Go-ism) -- **Where:** `client.ts:112, 137, 149, 175, 209, 234, 259, 284, 318, - 348, 366, 399, 417, 443, 475, 501, 530, 556, 582`. -- **Why flagged:** `req` is a Go-ism (see category 14). It is also - generic — a reader has to look at the type to know what the - request is. -- **Suggestion:** Use `request` for stylistic consistency with - `options` (which is spelled out). See F14.1. - -#### F1.6 — `state` field on `EndpointScalingInfo` and `EndpointStatus` (LOW) -- **Where:** `model.ts:305, 316`. -- **Why flagged:** `state` is generic. Disambiguated by container - type, but `scalingState` / `endpointState` would be clearer in - isolation. -- **Suggestion:** Acceptable as-is given the containing type; leave. - -#### F1.7 — `message` field on `EndpointStatus` and `VectorIndexStatus` (LOW) -- **Where:** `model.ts:318, 599`. -- **Why flagged:** Generic. Compare `statusMessage`, - `errorMessage`. -- **Suggestion:** Add JSDoc clarifying purpose; rename optional. - -#### F1.8 — `Call`, `Options` (imported, cross-package) (acceptable) -- **Where:** `utils.ts:3-5`, `client.ts:4-5`. -- These come from `@databricks/sdk-core/api`. Generic but - intentional. Out of scope for this package's audit. - ---- - -### 2. Redundant enum prefixes - -#### F2.1 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` (MEDIUM) -- **Where:** `model.ts:79-80`. -- **Why flagged:** `_STATE` is redundant — the enum is already - `EndpointStatus_State`. Reads `EndpointStatus_State.RED_STATE` — - "endpoint status state . red state". Other members in the same - enum (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not - carry the suffix; so this is also inconsistent within the enum. -- **Suggestion:** Wire strings are `RED_STATE` / `YELLOW_STATE`, so - parity needs the suffix. If the wire allows, rename to `RED` / - `YELLOW`. Otherwise, document the asymmetry. Worth fixing at the - spec level. - ---- - -### 3. Acronym casing inconsistencies - -#### F3.1 — `Id` vs `ID` (acceptable, cross-cutting) -- **Where:** `model.ts:102, 104, 188, 220, 288, 294, 296, 405, 409, - 411`. -- **Why flagged:** Field uses `id`, `budgetPolicyId`, - `effectiveBudgetPolicyId`, `usagePolicyId`, `pipelineId` — consistent - lower-camel `Id`. This matches the SDK-wide convention. -- **Suggestion:** No change. - -#### F3.2 — `QPS` rendered as `Qps` (MEDIUM) -- **Where:** - - `CreateEndpointRequest.targetQps` (`model.ts:110`) - - `EndpointScalingInfo.requestedTargetQps` (`model.ts:310`) - - `PatchEndpointRequest.targetQps` (`model.ts:421`) -- **Why flagged:** "QPS" (queries per second) is a TLA. The SDK - applies "first letter cap, rest lower" for camelCase — so `Qps` - here. The JSDoc uses "QPS" (uppercase) and the wire form is - `target_qps`. So `Qps` is consistent with `Http`/`Url` - casing for acronyms; flag is only against the JSDoc/comment mix. -- **Suggestion:** Standardize comments to use `QPS` consistently when - the prose is talking about the term, and `targetQps` for the TS - identifier. Or rename to `targetQueriesPerSecond` (verbose but - self-documenting). - -#### F3.3 — `URL` / `Url` (acceptable for this file) -- `client.ts:115, 152, 178, 184, 212, 237, 262, 287, 296, 321, 327, - 369, 378, 420, 446, 478, 504, 533, 559, 585` uses lowercase - `url` consistently. No casing inconsistency. - -#### F3.4 — `JSON` rendered as `Json` (acceptable) -- **Where:** `model.ts:247, 452, 544`; `inputsJson`, `schemaJson`, - `filtersJson`. -- Matches SDK-wide convention; no change. - ---- - -### 4. Underscores in TS identifiers - -_None._ - ---- - -### 5. Cryptic abbreviations - -#### F5.1 — `req` (LOW, Go-ism) -- **Where:** `client.ts:112, 137, 149, 175, 209, 234, 259, 284, 318, - 348, 366, 399, 417, 443, 475, 501, 530, 556, 582` plus - `client.ts:351, 360, 402, 411`. -- **Why flagged:** Already flagged under F1.5 / F14.1. - -#### F5.2 — `resp` / `respBody` (LOW, Go-ism) -- **Where:** `client.ts:117, 122, 127, 130, 154, 159, 164, 167, 185, - 190, 195, 201, 213, 218, 223, 226, 238, 243, 248, 251, 263, 268, - 273, 276, 297, 302, 307, 310, 328, 333, 338, 341, 353, 379, 384, - 389, 392, 404, 422, 427, 432, 435, 451, 456, 461, 467, 480, 485, - 490, 493, 509, 514, 519, 522, 535, 540, 545, 548, 561, 566, 571, - 574, 587, 592, 597, 603, 625, 666`. -- **Why flagged:** `response` is two extra characters and unambiguous. -- **Suggestion:** `response`, `responseBody`. - -#### F5.3 — `pollResp` (LOW) -- **Where:** `client.ts:625, 632, 642, 666, 673`. -- **Why flagged:** Same `resp` Go-ism inside the waiter. -- **Suggestion:** `pollResponse`. - -#### F5.4 — `httpReq` (LOW) -- **Where:** `client.ts:121, 158, 189, 217, 242, 267, 301, 332, 383, - 426, 455, 484, 513, 539, 565, 591`. -- **Why flagged:** `httpRequest` is clearer and matches the type - `HttpRequest` exactly. -- **Suggestion:** `httpRequest`. - -#### F5.5 — `apiErr` (LOW) -- **Where:** `utils.ts:88-91`. -- **Why flagged:** `apiError` reads better; "err" is a Go-ism. -- **Suggestion:** `apiError`. - -#### F5.6 — `pkgJson` (LOW) -- **Where:** `client.ts:20, 79-80`. -- **Why flagged:** "pkg" abbreviation. `packageJson` is two extra - characters and unambiguous. -- **Suggestion:** `packageJson`. - -#### F5.7 — `msg` (LOW) -- **Where:** `client.ts:642-643`. - ```ts - const msg = pollResp.endpointStatus?.message ?? '(no message)'; - throw new Error(`terminal state ${status}: ${msg}`); - ``` -- **Why flagged:** `message` is the source field name. Inlining - `pollResp.endpointStatus?.message` is also acceptable. -- **Suggestion:** `message` or inline. - -#### F5.8 — `acc`, `val`, `opts`, `e` (LOW) -- **Where:** `utils.ts:55, 137, 30, 65-92, 76`. -- **Why flagged:** Same as in `budgets` audit (F5.7 there). - - `acc` in reduce — conventional. OK. - - `val` in destructure — OK. - - `opts` — Go-ism but widely used in JS libs. - **Inconsistent within the package:** parameter is `options` in - `executeCall` (utils.ts:28), but `opts` inside `executeHttpCall` - (utils.ts:67-92). - - `e` for caught exception — TS guidance permits `e`/`err`/`error`; - inconsistent with `apiErr` (which spells out `err`). -- **Suggestion:** Rename `opts → options` inside `executeHttpCall` - for consistency; leave `acc`, `val`, `e` alone. - -#### F5.9 — `info` in `client.ts:100-105` (LOW) -- **Where:** `client.ts:100-105`. - ```ts - let info = createDefault().with(PACKAGE_SEGMENT); - ``` -- **Why flagged:** Generic; reads as "info about what?". Context tells - the reader it is the User-Agent builder, but the name is content-free. -- **Suggestion:** `userAgentInfo` or `clientInfo` (matches the - imported `createDefault` from `@databricks/sdk-core/clientinfo`). - -#### F5.10 — `qps` (LOW) -- See F3.2. - ---- - -### 6. Misleading names - -#### F6.1 — `Endpoint.name` is functionally the primary key (HIGH) -- **Where:** `model.ts:276`. -- **Why flagged:** The field is described as "Name of the AI Search - endpoint" but used as the path-segment identifier in - `getEndpoint`, `deleteEndpoint`, `patchEndpoint`, etc. - (`client.ts:212, 262, 420, 446`). Also, `Endpoint` has both - `name` and `id` (line 288), with `id` documented as "Unique - identifier of the endpoint" — so the type has *two* identifiers - and only one of them ever shows up in URLs. -- **Suggestion:** Document explicitly: "Used as the primary - identifier in API paths." Or rename `name → endpointName` (still - generic) or `name → key` (more explicit). Also clarify in JSDoc - that `name` is the URL-safe identifier and `id` is the opaque GUID. - See F12.3 / F19.2. - -#### F6.2 — `numIndexes` reads as "number of *array* indexes" (MEDIUM) -- **Where:** `model.ts:292`. -- **Why flagged:** In TS, "index" almost universally means a numeric - position in an array. Here it means "number of vector-search - indexes attached to this endpoint" — a domain term, not the - data-structure term. -- **Suggestion:** Rename `numIndexes → numVectorIndexes` (matches - `MiniVectorIndex` / `VectorIndex` in the same package). Even - better: pluralize naturally, `vectorIndexCount`. - -#### F6.3 — `EndpointStatus_State.OFFLINE` as a *terminal failure* state (HIGH) -- **Where:** `model.ts:72`, `client.ts:641-644, 680-681`. - ```ts - case EndpointStatus_State.OFFLINE: { - const msg = pollResp.endpointStatus?.message ?? '(no message)'; - throw new Error(`terminal state ${status}: ${msg}`); - } - ``` -- **Why flagged:** The waiter treats `OFFLINE` as a *terminal failure* - (throws), but the enum name "OFFLINE" suggests a transient state - ("the endpoint is currently offline"). This is misleading: a - reader sees `OFFLINE` and expects it might come back online; the - client treats it as terminal. -- **Suggestion:** If the wire allows, rename to `FAILED` (semantic - intent) or `TERMINATED`. Otherwise add a prominent JSDoc note on - the enum value explaining the waiter contract. - -#### F6.4 — `Endpoint.creator` is a user *identifier*, not the user (LOW) -- **Where:** `model.ts:278`. JSDoc: "Creator of the endpoint". -- **Why flagged:** "Creator" suggests a `User` object; the field type - is `string`. Compare `lastUpdatedUser` (also `string`). -- **Suggestion:** `creatorUserName` or `creatorEmail`, depending on - what the wire returns. Or `createdBy` (matches REST convention). - -#### F6.5 — `lastUpdatedUser` vs `creator` asymmetry (LOW) -- **Where:** `model.ts:278, 286`. -- **Why flagged:** Two fields, both `string`, both identify a user, - with different naming patterns: `creator` (noun) vs - `lastUpdatedUser` (compound). Inconsistent. -- **Suggestion:** `createdBy` and `updatedBy` (matches REST common - practice) or `creator` and `lastUpdater`. Pick one form. - -#### F6.6 — `flattenQueryParams` is exported but unused in this package (LOW) -- **Where:** `utils.ts:123-150`. -- **Why flagged:** The package's list endpoints use - `URLSearchParams.append` directly (`client.ts:179-182, 322-325, - 370-376`). The helper is dead in this package — same finding as - in the `budgets` audit. -- **Suggestion:** Move shared helpers to `@databricks/sdk-core` or - delete from per-package `utils.ts`. Cross-cutting. - -#### F6.7 — JSDoc `"Update an endpoint"` on `patchEndpoint` lacks the verb match (LOW) -- **Where:** `client.ts:415`. -- **Why flagged:** JSDoc says "Update", the method is `patchEndpoint`. - Inconsistent verb. (See F17.1.) -- **Suggestion:** Either rename the method or rewrite the JSDoc: - "Patch an endpoint to update mutable fields." - ---- - -### 7. Overly verbose - -#### F7.1 — `Endpoint` *would* be fine — but with package qualification - removed, becomes `VectorSearchEndpoint` (MEDIUM) -- **Where:** `model.ts:274`, `index.ts:31`. -- **Why flagged:** Today `Endpoint` is unqualified (F1.1). After the - F0/F1 rename it becomes `VectorSearchEndpoint` — long but - necessary. Worth noting as a deliberate tradeoff, not a bug. -- **Suggestion:** Accept the verbosity; mitigate by aliasing at - import sites where appropriate. - -#### F7.2 — `PatchEndpointBudgetPolicyRequest`, - `PatchEndpointBudgetPolicyResponse` (HIGH) -- **Where:** `model.ts:401, 408`, `index.ts:43-44`. -- **Why flagged:** 32+ characters. Inside a method literally named - `patchEndpointBudgetPolicy(...)`, the request type repeats every - token. Compare typical TS SDK shape: - `endpoint.patchBudgetPolicy(req: PatchBudgetPolicyRequest)`. -- **Suggestion:** With F0/F1 rename, drop the redundant `Endpoint` - token. The method belongs to a vector-search-endpoint client, so - `PatchBudgetPolicyRequest` / `PatchBudgetPolicyResponse` is enough. - -#### F7.3 — Method names: `patchEndpointBudgetPolicy`, - `createEndpoint`, `deleteEndpoint`, - `getEndpoint`, `listEndpoint`, `patchEndpoint` (MEDIUM) -- **Where:** `client.ts:111, 208, 258, 317, 416, 442`. -- **Why flagged:** "Endpoint" repeats in every method name. Compare - typical TS SDK shape: `client.createEndpoint(...)`. Now that - the package contains both endpoints and indexes, the verbose form - is more justified — but the names could be split into nested - resource clients (`client.endpoints.create(...)`, - `client.indexes.create(...)`). -- **Suggestion:** Nested resource clients, or keep as-is given the - multi-resource scope of the package. Cross-package convention. - -#### F7.4 — `createEndpointWaiter` method (MEDIUM) -- **Where:** `client.ts:136-145`. -- **Why flagged:** This method is `createEndpoint` + return-a-waiter. - All sibling SDKs (`warehouses`, `modelserving`) export - the waiter as a separate type and the create method returns it - directly. Reads as `client.createEndpoint(...)` returning an - `Endpoint`, then a second method `createEndpointWaiter(...)` - returning a `CreateEndpointWaiter`. Two methods for one operation. -- **Suggestion:** Either: - - Make `createEndpoint` return the waiter directly (breaking - change), or - - Rename to `createEndpointAndWait` (verbose but explicit), or - - Inline the polling into `createEndpoint` and remove the waiter - type entirely. - See F17.3. - -#### F7.5 — `STILL_RUNNING` / `StillRunningError` (LOW) -- **Where:** `client.ts:83`. -- **Why flagged:** Private error class used as a control-flow signal - for `retryOn`. Three concepts in one name ("still" + "running" + - "error"). It is essentially "not yet done". -- **Suggestion:** Acceptable as-is; alternative - `RetryablePendingError` or `NotYetDoneError`. - -#### F7.6 — `QueryVectorIndexNextPageRequest` (LOW) -- **Where:** `model.ts:425`, `index.ts:46`. -- **Why flagged:** 30+ characters. Could be `QueryVectorIndexPageRequest` - or `QueryNextPageRequest`. -- **Suggestion:** `QueryNextPageRequest` keeps the meaning and drops - the redundant `VectorIndex` token (context: it's a vector-search - package). - ---- - -### 8. Redundant suffixes - -#### F8.1 — `Request` / `Response` suffixes (LOW, conventional) -- **Where:** All request/response types. -- **Why flagged:** Conventional in this SDK. Names are flat - (`CreateEndpointRequest`, `DeleteEndpointResponse`). Good. -- **Suggestion:** No change. - -#### F8.2 — `EndpointType` enum tautology (LOW) -- **Where:** `model.ts:18`, `Endpoint.endpointType: EndpointType` - (`model.ts:284`). -- **Why flagged:** Three layers of "endpoint": `Endpoint` has a - field `endpointType` typed as `EndpointType`. Reads as - `endpoint.endpointType : EndpointType`. -- **Suggestion:** Rename field `endpointType → type` (loses one - redundancy, becomes `endpoint.type : EndpointType`). Wire field - is `endpoint_type` (`model.ts:725, 1028`), so a remap is needed. - See F20.1. - -#### F8.3 — `EndpointStatus` interface + `endpointStatus` field on `Endpoint` (LOW) -- **Where:** `model.ts:290, 314`. -- **Why flagged:** Same pattern as F8.2: - `endpoint.endpointStatus : EndpointStatus`. -- **Suggestion:** Rename field `endpointStatus → status`. Wire field - is `endpoint_status` — generator-level remap. - -#### F8.4 — `EndpointScalingInfo` `Info` suffix (LOW) -- **Where:** `model.ts:303`. -- **Why flagged:** `Info` suffix is a generic filler word. The type - describes scaling state. -- **Suggestion:** `EndpointScaling`. Or align with `EndpointStatus` - (already there, no `Info`). - -#### F8.5 — `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` (LOW) -- **Where:** `model.ts:175, 207`. -- **Why flagged:** Two types with the same prefix differing only by - `Request` suffix; the `Request` variant is the input shape, the - bare variant is the output. Asymmetric: most request-shape - duplicates in the codebase don't carry the suffix. -- **Suggestion:** Document the distinction in JSDoc. Acceptable. - ---- - -### 9. Singular / plural mismatches - -#### F9.1 — `listEndpoint` method singular for a collection (HIGH) -- **Where:** `client.ts:317`. -- **Why flagged:** Method returns `ListEndpointResponse` whose - `endpoints` field is `Endpoint[]`. The method should be - `listEndpoints` (plural). Same applies to its request type: - `ListEndpointRequest` should be `ListEndpointsRequest`, - `ListEndpointResponse` should be `ListEndpointsResponse`. -- **Suggestion:** Pluralize throughout. The wire path is - `/api/2.0/vector-search/endpoints` — plural — so this is also - consistent with the URL. - -#### F9.2 — `ListEndpointRequest` / `ListEndpointResponse` types (HIGH) -- **Where:** `model.ts:338, 343`. -- See F9.1. - -#### F9.3 — `listVectorIndex` method singular for a collection (HIGH) -- **Where:** `client.ts:365`. -- **Why flagged:** Same issue as F9.1 — method returns a list of - indexes. Should be `listVectorIndexes`. -- **Suggestion:** Pluralize throughout: `listVectorIndexes`, - `ListVectorIndexesRequest`, `ListVectorIndexesResponse`. - -#### F9.4 — `ListVectorIndexRequest` / `ListVectorIndexResponse` types (HIGH) -- **Where:** `model.ts:355, 362`. -- See F9.3. - -#### F9.5 — `Endpoint.numIndexes` plural (acceptable) -- **Where:** `model.ts:292`. -- Plural is correct for a count of indexes. - -#### F9.6 — `Endpoint.customTags: CustomTag[]` plural (acceptable) -- **Where:** `model.ts:298`. -- Plural is correct for an array. - ---- - -### 10. Reserved-word / built-in collisions - -#### F10.1 — `delete` method name (LOW) -- **Where:** `client.ts:208` (`deleteEndpoint`). -- **Why flagged:** TS allows `delete` as method name. `deleteEndpoint` - is unambiguous; flag would apply only if renamed to bare `delete`. -- **Suggestion:** Acceptable. - -#### F10.2 — `status` field (LOW) -- **Where:** `model.ts:154, 394, 549, 590`. -- **Why flagged:** `Response.status` collides with `Response.status` - in the Fetch API. Mild shadowing concern in code review. -- **Suggestion:** Acceptable inside the type domain. - -#### F10.3 — `state` field (LOW) -- **Where:** `model.ts:305, 316`. -- **Why flagged:** No reserved-word collision. `state` is a popular - React/Redux concept, but that is library-level not language-level. -- **Suggestion:** Acceptable. - -#### F10.4 — `Headers`, `URLSearchParams`, `TextDecoder`, - `AbortSignal`, `Promise`, `ReadableStream` (acceptable) -- **Where:** `client.ts`, `utils.ts`. -- Used as global classes; no shadowing. - -#### F10.5 — `Error`, `RangeError`, etc. (acceptable) -- `throw new Error(...)` is correct usage. No collision. - ---- - -### 11. Empty / trivial wrapper types - -#### F11.1 — `DeleteEndpointResponse`, `DeleteVectorIndexResponse`, - `SyncVectorIndexResponse` empty (LOW) -- **Where:** `model.ts:165, 173, 538`. -- **Why flagged:** Empty `{}` types. Conventional placeholder for - REST endpoints that return an empty body. Useful for future - evolution. -- **Suggestion:** Acceptable. - ---- - -### 12. Duplicate concepts - -#### F12.1 — `Endpoint.name` vs `Endpoint.id` (HIGH) -- **Where:** `model.ts:276, 288`. -- **Why flagged:** Both fields are documented as identifiers - ("Name of the AI Search endpoint" / "Unique identifier of the - endpoint"). Every URL uses `name`, never `id`. Two identifiers - for the same entity confuse users; see F1.4, F6.1, F19.2. -- **Suggestion:** Document the distinction prominently - (`name` = user-chosen URL-safe key, `id` = opaque GUID). Or - collapse to one identifier at the API level. - -#### F12.2 — `budgetPolicyId` vs `effectiveBudgetPolicyId` (LOW) -- **Where:** `model.ts:294, 296, 405, 409, 411`. -- **Why flagged:** Two fields, same domain, distinguished by the - word "effective". A reader needs JSDoc to know which is the - request and which is the result of policy resolution. -- **Suggestion:** Acceptable convention; JSDoc clarifies. Not a - duplicate, just adjacent. - -#### F12.3 — `usagePolicyId` vs `budgetPolicyId` (LOW) -- **Where:** `model.ts:102, 104`. -- **Why flagged:** Two different policy IDs whose JSDoc says one - will be replaced by the other ("usagePolicyId" — "to be applied - once we've migrated to usage policies"). Transitional API — both - exist today. -- **Suggestion:** Acceptable transition; should be cleaned up post - migration. - -#### F12.4 — `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` - near-duplicate types (LOW) -- **Where:** `model.ts:175, 207`. -- **Why flagged:** The two types have an identical set of fields. - The split is purely for request vs response. -- **Suggestion:** Acceptable convention; document the asymmetry. - -#### F12.5 — `MiniVectorIndex` vs `VectorIndex` near-duplicate types (LOW) -- **Where:** `model.ts:376, 572`. -- **Why flagged:** Both types share identical fields. `MiniVectorIndex` - appears to be used in list responses for lighter weight payloads. -- **Suggestion:** Document the distinction in JSDoc. - -#### F12.6 — Per-method header construction duplicated (LOW, code style) -- **Where:** `client.ts:119-120, 156-157, 187-188, 215-216, 240-241, - 265-266, 299-300, 330-331, 381-382, 424-425, 453-454, 482-483, - 511-512, 537-538, 563-564, 589-590`. -- **Why flagged:** Every method runs: - ```ts - const headers = new Headers(...); - headers.set('User-Agent', this.userAgent); - ``` - Could be a private helper `this.buildHeaders(...)`. Not a naming - issue, but a code-duplication smell. -- **Suggestion:** Out of scope for naming audit. Same finding as in - `budgets`. - ---- - -### 13. Verb-tense inconsistency - -#### F13.1 — Method verbs (acceptable for CRUD) -- `create*`, `delete*`, `get*`, `list*`, `patch*`, `query*`, - `scan*`, `sync*`, `upsert*` — all uniform - imperative present. Good. - -#### F13.2 — `patch*` vs `update*` (MEDIUM) -- **Where:** Method `patchEndpoint` (`client.ts:416`), JSDoc says - "Update an endpoint" (`client.ts:415`). -- **Why flagged:** REST verbs in the SDK are mixed. Most packages - use `update*` (e.g. `updateBudgetConfiguration`); this package - uses `patch*`. Both describe the same HTTP verb (`PATCH`) but - with different SDK ergonomics. -- **Suggestion:** Cross-package decision. If the SDK standardizes - on `update`, rename to `updateEndpoint`, - `updateEndpointBudgetPolicy`. If on `patch`, fix the JSDoc to say - "Patch". See F17.1. - -#### F13.3 — `createEndpoint` / `createEndpointWaiter` overlap (MEDIUM) -- **Where:** `client.ts:111, 136`. -- **Why flagged:** Two methods with the same verb start; only one - actually performs the create — the waiter version *calls* the - create then wraps. Reader might think `createEndpointWaiter` is - a *different* operation. -- **Suggestion:** See F7.4. Acceptable if the verb pattern is - applied consistently across the SDK; flag for cross-cutting - decision. - -#### F13.4 — `creationTimestamp` / `lastUpdatedTimestamp` past-tense - asymmetry (LOW) -- **Where:** `model.ts:280, 282`. -- **Why flagged:** "creation" (noun) vs "lastUpdated" (past - participle). Not parallel. Other SDK packages use - `createTime`/`updateTime` (noun-form) or `createdAt`/`updatedAt` - (past-participle). This package mixes both forms. -- **Suggestion:** Standardize as `createdAt` / `updatedAt` (most - idiomatic in TS) or `createTime` / `updateTime` (matches Google - API). Wire fields are `creation_timestamp` and - `last_updated_timestamp`; remap if needed. - ---- - -### 14. Go / Java-style names - -#### F14.1 — `req`, `resp`, `err`, `httpReq`, `apiErr`, - `pkgJson`, `opts`, `msg` (HIGH, cross-cutting) -- **Where:** - - `req` in every client method - - `resp`, `respBody`, `pollResp` in `client.ts` - - `e` in `utils.ts:76` - - `httpReq` in `client.ts` - - `apiErr` in `utils.ts:88` - - `pkgJson` in `client.ts:20, 79-80` - - `opts` in `utils.ts:30, 65-92` - - `msg` in `client.ts:642` -- **Why flagged:** All classic Go idioms ported verbatim. TS - convention favors spelled-out names: `request`, `response`, - `error`, `httpRequest`, `apiError`, `packageJson`, `options`, - `message`. -- **Suggestion:** Spell them out. Trivial diff, large readability - gain. Generator-level decision; identical to the recommendation - in the `budgets` audit. - -#### F14.2 — `for (;;)` infinite loop (acceptable) -- **Where:** `client.ts:352, 403`, `utils.ts:48`. -- **Why flagged:** Style; this is a `for (;;)` Go-idiom (the Go form - is `for { … }`). TS prefers `while (true)` or `do { … } while (…)`. - But `for (;;)` is also legal and idiomatic in C-derived languages. -- **Suggestion:** Acceptable; consistent within the SDK. - -#### F14.3 — `Waiter` suffix (Go-style) (MEDIUM) -- **Where:** `client.ts:136-145, 610`. Exported as - `CreateEndpointWaiter` (`index.ts:3`). -- **Why flagged:** "Waiter" is an AWS SDK / Go SDK pattern. TS - ecosystems more often expose a `Promise`-returning method (e.g. - `createAndWait`, `pollUntilDone`) or an async iterator. The - `Waiter` object has only two methods (`wait`, `done`); could be - a function. -- **Suggestion:** Rename to `EndpointCreatePoller` (more JS-y) or - inline as `createEndpointAndWait(): Promise`. Or keep - for parity with other Databricks SDKs (Go has Waiters; users - porting may expect them). - -#### F14.4 — `numIndexes`, `numResults` `num` prefix (LOW) -- **Where:** `model.ts:292, 438, 513`. -- **Why flagged:** `num` is shortened from "number of". TS often - uses the bare noun (`indexCount`, `resultCount`) or `count` suffix. -- **Suggestion:** `indexCount`, `resultCount` (more idiomatic). - Wire fields are `num_indexes` / `num_results` — generator-level - remap. - ---- - -### 15. Generic field names losing meaning - -#### F15.1 — `Endpoint.name` (HIGH) -- See F1.4 / F6.1. - -#### F15.2 — `Endpoint.id` (LOW) -- **Where:** `model.ts:288`. -- **Why flagged:** Bare `id` is the most generic identifier name - possible. Acceptable inside the type domain — but only because - the type is `Endpoint`. -- **Suggestion:** Keep; the type context disambiguates. - -#### F15.3 — `state`, `status`, `message` (LOW) -- See F1.6, F1.7. - -#### F15.4 — `key` / `value` on `CustomTag` and - `MapStringValueEntry` (LOW) -- **Where:** `model.ts:139, 141, 371, 373`. -- **Why flagged:** Generic; same finding as `BudgetConfigurationFilter_TagClause.key/value` - in `budgets`. Wrapping type supplies context, but `tagKey` / - `tagValue` would self-document. -- **Suggestion:** Wire fields are `key`/`value`; rename costs a - marshaller mapping. Optional. - -#### F15.5 — `req` parameter on every client method (HIGH) -- See F1.5. - -#### F15.6 — `result` field on `QueryVectorIndexResponse`, - `UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse` - (LOW) -- **Where:** `model.ts:156, 475, 551`. -- **Why flagged:** Generic. Disambiguated by container type. -- **Suggestion:** Acceptable. - -#### F15.7 — `data` field on `ScanVectorIndexResponse` (LOW) -- **Where:** `model.ts:522`. -- **Why flagged:** `data` is generic. -- **Suggestion:** Acceptable in the response domain. - ---- - -### 16. Field contradicting type domain - -#### F16.1 — `state` on `EndpointScalingInfo` is a *change* state, not - a *scaling* state (LOW) -- **Where:** `model.ts:305`. -- **Why flagged:** Field is `state: ScalingChangeState` — the - field-on-type domain is "scaling info", but the field type is - "scaling **change** state". JSDoc says "The current state of the - scaling change request" — so the field name should arguably - match. -- **Suggestion:** Rename field to `changeState` or - `lastChangeState`. - -#### F16.2 — `EndpointStatus_State.RED_STATE`, `YELLOW_STATE` health - semantics (LOW) -- **Where:** `model.ts:79-80`. -- **Why flagged:** These are health-color states, not lifecycle states. - Lumping them with `PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED` - (lifecycle states) in the same enum mixes two orthogonal - dimensions. -- **Suggestion:** API-shape concern. Split into `lifecycleState` - and `healthState`, or rename to be uniformly health-colored - (`GREEN` for `ONLINE`). - ---- - -### 17. Inconsistent action verbs - -#### F17.1 — `patch*` vs `update*` (MEDIUM) -- See F13.2. Cross-cutting. - -#### F17.2 — `Get` vs `List` for read endpoints (acceptable) -- `getEndpoint` for single, `listEndpoint` for collection. Standard - REST verbs. (Plural issue covered in F9.1.) - -#### F17.3 — `createEndpoint` returns `Endpoint`, - `createEndpointWaiter` returns `CreateEndpointWaiter` (MEDIUM) -- **Where:** `client.ts:111, 136`. -- See F7.4 / F13.3. - -#### F17.4 — `wait` vs `done` on `CreateEndpointWaiter` (acceptable) -- **Where:** `client.ts:621, 665`. -- Both verbs are well-chosen. `wait` is blocking-until-terminal; - `done` is a non-blocking check. Symmetric and clear. - -#### F17.5 — `upsert*`, `scan*`, `sync*`, `query*` (acceptable) -- **Where:** `client.ts:529, 555, 474, 500, 581`. -- New action verbs from the index-side of the package (formerly - `indexes`). All are unambiguous and consistent. -- **Suggestion:** No change. - ---- - -### 18. Long enum values - -#### F18.1 — `STORAGE_OPTIMIZED` (LOW) -- 17 chars. Reasonable. - -#### F18.2 — `PROVISIONING` (acceptable) -- 12 chars. Standard. - ---- - -### 19. Underspecified IDs - -#### F19.1 — `Endpoint.id` (LOW) -- See F15.2. Bare `id` inside `Endpoint` is fine. - -#### F19.2 — `Endpoint.name` doubles as ID (HIGH) -- See F1.4 / F6.1 / F12.1. Two identifiers (`name` and `id`) for - the same entity is the underspecification problem. - -#### F19.3 — `budgetPolicyId`, `usagePolicyId`, - `effectiveBudgetPolicyId` (acceptable) -- **Where:** `model.ts:102, 104, 188, 220, 294, 296, 405, 409, 411`. -- Specific enough; matches platform-wide convention. - -#### F19.4 — `MiniVectorIndex.endpointName` (acceptable) -- **Where:** `model.ts:380`. -- Domain-qualified; clear. - ---- - -### 20. Type-suffix tautology - -#### F20.1 — `Endpoint.endpointType: EndpointType` (MEDIUM) -- **Where:** `model.ts:284, 100`. -- **Why flagged:** Three layers of "endpoint": - `endpoint.endpointType : EndpointType`. The container provides - the "endpoint" context. -- **Suggestion:** Rename field `endpointType → type` (similar - pattern in `budgets` F20.1 / F20.2). Wire field is - `endpoint_type`; needs a marshaller remap. - -#### F20.2 — `Endpoint.endpointStatus: EndpointStatus` (MEDIUM) -- **Where:** `model.ts:290, 314`. -- **Why flagged:** Same pattern. -- **Suggestion:** Rename field `endpointStatus → status`. - -#### F20.3 — `EndpointStatus.state: EndpointStatus_State` (LOW) -- **Where:** `model.ts:316`. -- **Why flagged:** Field is `state`, enum is `EndpointStatus_State`. - Not strictly tautological (the field is the bare noun, the type - is the qualified noun). Acceptable. - -#### F20.4 — `EndpointScalingInfo.state: ScalingChangeState` (LOW) -- **Where:** `model.ts:305`. -- **Why flagged:** Same pattern. Field `state` typed against - `ScalingChangeState` reads "scaling info . state : scaling change - state". -- **Suggestion:** Rename field to `changeState` (matches the enum's - domain better). See F16.1. - -#### F20.5 — `MiniVectorIndex.indexType: VectorIndexType`, - `VectorIndex.indexType: VectorIndexType` (LOW) -- **Where:** `model.ts:383, 579`. -- **Why flagged:** Field `indexType` typed against `VectorIndexType`; - reads "vector index . index type : vector index type". -- **Suggestion:** Rename field `indexType → type`. Wire field is - `index_type` — marshaller remap. - -#### F20.6 — `MiniVectorIndex.indexSubtype: IndexSubtype`, - `VectorIndex.indexSubtype: IndexSubtype` (LOW) -- **Where:** `model.ts:398, 594`. -- **Why flagged:** Same pattern. -- **Suggestion:** Rename field `indexSubtype → subtype`. - ---- - -## Package overlap: `vectorsearch` vs `warehouses` vs `modelserving` - -The `endpoints` package was merged into `vectorsearch` in the -2026-05-20 regeneration, resolving the F0.1 / F0.2 / F-OVERLAP.2 -findings about package ambiguity. Some residual concerns remain -about the unqualified `Endpoint` symbol. - -### F-OVERLAP.1 — `Endpoint` symbol exists in three places (MEDIUM) -- **Where:** - - `packages/vectorsearch/src/v1` exports `Endpoint` - - `packages/warehouses/src/v1` exports `EndpointState`, - `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` - - `packages/modelserving/src/v1` exports - `InferenceEndpoint`, etc. -- **Why flagged:** Project-wide `grep -r Endpoint` returns hits across - all three packages. Autocomplete on "Endpoint" collides. Even with - qualified imports, mental load is high. -- **Suggestion:** Rename per F1.1. The model serving package already - qualifies its primary type as `InferenceEndpoint`; this package - should qualify as `VectorSearchEndpoint`; the warehouse package's - legacy `Endpoint*` names are wire-protocol and should be deprecated - but left for compatibility. - -### F-OVERLAP.2 — `EndpointType` exists in this package vs - `WarehouseType` exists in `warehouses` (LOW) -- **Where:** `model.ts:18` here vs - `warehouses/src/v1/index.ts` line for `WarehouseType`. -- **Why flagged:** `WarehouseType` is qualified; `EndpointType` is - bare. After F1.2 rename it becomes `VectorSearchEndpointType` — - symmetric with `WarehouseType`. - ---- - -## Proto-architectural-leak names - -Names that leak the upstream proto/IDL or service architecture into the -TS public surface. These are not standard suffix conventions; they -reflect internal class/file layout that should not be visible to SDK -consumers. - -### 1. `EndpointStatus_State` — model.ts:69, index.ts:12 -- **Why:** Underscore-separated identifier mirrors the proto nested-enum - shape (`EndpointStatus.State` in the IDL). TS has no nested-enum - concept, so the underscore leaks the proto file layout. Also exported - at `index.ts:12`. -- **Category:** Proto-nested type leak (underscore infix). -- **Suggested:** `EndpointState`, or move it under the `EndpointStatus` - namespace via a TS `namespace EndpointStatus { export enum State }`. -- **Rationale:** TS consumers do not see the proto enclosing message. - The underscore is purely a generator artifact; the public type name - should read as a plain TS identifier. - -### 2. `RerankerConfig_RerankerParameters` — model.ts:490, index.ts:50 -- **Why:** Proto-nested message name leaked as an underscore-separated - TS interface. Also repeats the `Reranker` token inside its own parent - type ("reranker config . reranker parameters"). -- **Category:** Proto-nested type leak (underscore infix) + token - repetition. -- **Suggested:** `RerankerParameters` at the top level, or - `RerankerConfig.Parameters` via a TS namespace. Drop the duplicated - `Reranker` token regardless. -- **Rationale:** The wire form `RerankerConfig.RerankerParameters` is - a proto nesting convention; the SDK consumer only sees an interface - reference, so `RerankerParameters` is unambiguous in context. - -### 3. `marshalRerankerConfig_RerankerParametersSchema` — model.ts:1217 -- **Why:** Schema constant name carries the same proto-nested - underscore as finding 2. The Zod schema for the nested message - inherits the leaked name. -- **Category:** Proto-nested type leak (underscore infix) — schema - variant. -- **Suggested:** `marshalRerankerParametersSchema` (consistent with the - renamed interface in finding 2). -- **Rationale:** Same as 2 — internal naming bleeding into the public - module surface. - ---- - -## Summary table - -| # | Category | Findings | -| - | --------------------------------------- | -------- | -| 0 | **Package name (special)** | 1 | -| 1 | Vague / generic | 8 (1 acceptable) | -| 2 | Redundant enum prefixes | 1 | -| 3 | Acronym casing | 4 (3 acceptable) | -| 4 | Underscores in TS identifiers | 0 | -| 5 | Cryptic abbreviations | 10 | -| 6 | Misleading names | 7 | -| 7 | Overly verbose | 6 | -| 8 | Redundant suffixes | 5 (1 acceptable) | -| 9 | Singular / plural mismatch | 6 (2 acceptable) | -| 10 | Reserved-word collisions | 5 (3 acceptable) | -| 11 | Empty / trivial wrappers | 1 | -| 12 | Duplicate concepts | 6 | -| 13 | Verb-tense inconsistency | 4 (1 acceptable) | -| 14 | Go / Java-style names | 4 (1 acceptable) | -| 15 | Generic field names | 7 | -| 16 | Field contradicting type domain | 2 | -| 17 | Inconsistent action verbs | 5 (3 acceptable) | -| 18 | Long enum values | 2 (1 acceptable) | -| 19 | Underspecified IDs | 4 (3 acceptable) | -| 20 | Type-suffix tautology | 6 (2 acceptable) | -| OVERLAP | vectorsearch vs warehouses vs serving | 2 | -| PROTO | Proto-architectural-leak names | 3 | -| **Total** | | **99** | - ---- - -## Top highest-impact renames (recommended order) - -1. **F1.1 / F1.2 / F-OVERLAP.1:** Rename `Endpoint` to - `VectorSearchEndpoint`. The package rename to - `@databricks/sdk-vectorsearch` already happened; aligning the - exported type name closes the loop. -2. **F9.1 / F9.2 / F9.3 / F9.4:** Pluralize the list methods, requests, - and responses: `listEndpoints`, `ListEndpointsRequest`, - `ListEndpointsResponse`, and same for `VectorIndex`. -3. **F12.1 / F1.4 / F6.1 / F19.2:** Resolve the `Endpoint.name` vs - `Endpoint.id` duality — either document the distinction - prominently or unify at the API level. -4. **F8.2 / F20.1 / F20.2:** Drop redundant tokens from - `Endpoint.endpointType` and `Endpoint.endpointStatus` to bare - `type` / `status`. -5. **F14.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ - `pkgJson`/`msg` across the generated code. - ---- - -## Notes / out-of-scope - -- All findings above relate to **generated** code. Code-base rule: - "Code generated from API definition by Databricks SDK Generator. - DO NOT EDIT." The fixes belong upstream in the generator and - spec. This audit is a backlog for that generator. -- The `utils.ts` file contains the same generic helpers - (`executeCall`, `parseResponse`, `marshalRequest`, - `flattenQueryParams`, `executeHttpCall`, `buildHttpRequest`, - `readAll`) that every generated package duplicates. The - duplication itself is not a naming issue and is out of scope for - this audit. -- This package has no `tests/` directory (verified by repo - structure check), so the audit does not cover test naming. -- The `Waiter` pattern (`CreateEndpointWaiter`) is a Go SDK idiom - ported verbatim; whether to keep it for parity or replace with a - JS-idiomatic `Promise`/async-iterator API is a cross-cutting - design decision. -- "Endpoint" appearing across the SDK is a *Databricks-wide* problem - — the term is used by Vector Search, Model Serving, and SQL - Warehouses for three different concepts. Disambiguation at the - SDK level is unavoidable. - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md index 24f2c69a..c1d3a72e 100644 --- a/.agent/naming-audit/indexes.md +++ b/.agent/naming-audit/indexes.md @@ -1,224 +1,3 @@ # Naming Audit: indexes -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/vectorsearch/src/v1/` (formerly `packages/indexes/src/v1/`; merged with the vector-search endpoint API) -**Versions audited:** v1 -**Inferred domain:** Databricks Vector Search index management — CRUD for `VectorIndex` (Delta-Sync or Direct-Access subtypes), data upsert/delete on direct-access indexes, vector/text/hybrid query, scan, pagination, and sync trigger. Routes under `/api/2.0/vector-search/indexes`. -**Total weird names flagged:** 33 - -## Summary -| Severity | Count | -| --- | --- | -| High | 10 | -| Medium | 15 | -| Low | 6 | -| Observation | 2 | - -## High severity - -### 1. `MiniVectorIndex` — `src/v1/model.ts:376` -- **Why weird:** "Mini" is a cryptic informal qualifier. No JSDoc explains what it means. By inspection it is a list-view subset of `VectorIndex` (same fields), used as the element type in `ListVectorIndexResponse.vectorIndexes`. Industry conventions for "the lighter view returned by a list endpoint" include `Summary`, `ListItem`, `Brief`, `Ref`, `Preview` — never `Mini`. -- **Category:** 5 (cryptic abbreviation), 1 (vague qualifier). -- **Suggested name:** `VectorIndexSummary` or `VectorIndexListItem`. Add JSDoc explaining why it differs from `VectorIndex` (in fact, the fields are identical in this version — see #2). -- **Rationale:** `Mini` does not convey "subset of the full type returned by list operations". Naming the type after its role (`Summary`/`ListItem`) makes the relationship to `VectorIndex` discoverable. - -### 2. `MiniVectorIndex` is structurally identical to `VectorIndex` — `src/v1/model.ts:376-399` vs `:572-595` -- **Why weird:** Both types declare exactly the same nine fields (`name`, `endpointName`, `primaryKey`, `indexType`, `indexSpec`, `status`, `creator`, `indexSubtype`) with the same types and (where present) the same JSDoc lines. They are duplicates. The only signal of intent is the prefix "Mini". If they are meant to be the same, one should be an alias; if they differ, the difference must be documented. -- **Category:** 12 (duplicate concept). -- **Suggested name:** Either `export type VectorIndexSummary = VectorIndex;` (with a comment noting wire-format identity), or drop one entirely. If the API intends them to diverge later, document the upcoming difference. -- **Rationale:** Duplicating ~25 lines of type definition with no semantic distinction is a maintenance hazard. - -### 3. `DeltaSyncVectorIndexSpec` vs `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:175-205` vs `model.ts:207-237` -- **Why weird:** Two distinct exported types with the same eight fields (`sourceTable`, `embeddingSourceColumns`, `embeddingVectorColumns`, `pipelineType`, `pipelineId`, `embeddingWritebackTable`, `columnsToSync`, `columnsToIndex`), same JSDoc, same types. Only `...Request` exists for `DeltaSync`; the matching response shape is `DeltaSyncVectorIndexSpec` (sans `Request`). `DirectAccessVectorIndexSpec` does *not* have a separate `...Request` twin. Suggests an upstream quirk that should be flattened in TS. -- **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix). -- **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec`), or document why the request version differs. If the upstream API truly has divergence, list the diverging fields explicitly. -- **Rationale:** The asymmetry with `DirectAccessVectorIndexSpec` (no separate request variant) shows the duplication is gratuitous, not necessary. - -### 4. `UpsertDeleteDataStatus` — single enum shared by both upsert and delete — `src/v1/model.ts:51-55` -- **Why weird:** The enum name is two-verb (`Upsert` AND `Delete`) joined into one noun-prefix. Reads as "the status of an upsert-delete operation" — but there is no such thing as an "upsert-delete". It is the response shape for two separate operations. Conventionally each operation has its own response type or the shared type uses a neutral name. -- **Category:** 13 (verb-tense / verb-coupling), 7 (overly verbose by merging two verbs), 1 (generic "Status"). -- **Suggested name:** `DataModificationStatus` or `OperationStatus`. Or split into `UpsertStatus` and `DeleteStatus` aliases if the back-end is really sharing one. -- **Rationale:** Two-verb compound nouns are unusual and confusing. Same problem exists on `UpsertDeleteDataResult` (model.ts:554). - -### 5. `UpsertDeleteDataResult` — same two-verb compound — `src/v1/model.ts:554` -- **Why weird:** Same dual-verb naming as #4. The JSDoc on the field where it is used ("Result of the upsert or delete operation" — model.ts:155, 550) confirms the verbs are *alternatives*, not a sequence. -- **Category:** 13 (verb-tense), 7 (verbose), 1 (generic). -- **Suggested name:** `DataMutationResult` or split into `UpsertDataResult` / `DeleteDataResult` aliases. -- **Rationale:** Same as #4. - -### 6. Method names follow Go pattern `verbVectorIndex` not idiomatic JS `verbIndex` — `client.ts:148, 174, 233, 283, 365, 398, 474, 500, 529, 555, 581` -- **Why weird:** Eleven methods: `createVectorIndex`, `deleteDataVectorIndex`, `deleteVectorIndex`, `getVectorIndex`, `listVectorIndex`, `listVectorIndexIter`, `queryVectorIndex`, `queryVectorIndexNextPage`, `scanVectorIndex`, `syncVectorIndex`, `upsertDataVectorIndex`. The client now also exposes endpoint methods (`createEndpoint`, etc.) — so the `VectorIndex` suffix does serve a disambiguation role here, but every method name still carries 11+ characters of repetition that the JSDoc and URL already make clear. The Go SDK uses receiver methods so the package prefix is implicit, but in JS we re-add it. -- **Category:** 8 (redundant suffix), 7 (overly verbose), 14 (Go-style). -- **Suggested name:** Group the index methods under a sub-namespace (`client.indexes.create()`, `client.indexes.query()`, ...) instead of repeating `VectorIndex` in every method. Same pattern would split the endpoint methods (`client.endpoints.create()`, etc.). -- **Rationale:** The repetition is mechanical Go-port baggage. Sub-namespacing also separates the two resource families (endpoints, indexes) that now live in one client. - -### 7. `name` is the resource identifier on every Request type — meaning is overloaded — multiple sites -- **Why weird:** Many Request/response types use a bare `name?: string` for what is actually the full index (or endpoint) identifier (typically a Unity Catalog qualified name like `main.schema.index`). Types affected: `CreateVectorIndexRequest.name` (model.ts:115), `DeleteDataVectorIndexRequest.name` (model.ts:147), `DeleteVectorIndexRequest.name` (model.ts:169), `GetVectorIndexRequest.name` (model.ts:328), `MiniVectorIndex.name` (model.ts:378), `QueryVectorIndexNextPageRequest.name` (model.ts:427), `QueryVectorIndexRequest.name` (model.ts:436), `ScanVectorIndexRequest.name` (model.ts:512), `SyncVectorIndexRequest.name` (model.ts:534), `UpsertDataVectorIndexRequest.name` (model.ts:542), `VectorIndex.name` (model.ts:574). JSDoc on every one says "Name of the index" — but a UC three-part name is more than a "name", it's a path/identifier. -- **Category:** 15 (generic field name losing meaning), 19 (underspecified ID). -- **Suggested name:** `indexFullName`, `indexId`, or at least add JSDoc clarifying the expected format ("three-part Unity Catalog identifier `..`"). -- **Rationale:** `name` is too generic when the value is a structured path. Users reading `req.name = "foo"` may send a bare name and get a 404. - -### 8. `endpointName` field for the *index endpoint* — generic name shared across packages — `model.ts:117, 357, 380, 429, 576` -- **Why weird:** Five sites use `endpointName?: string`. There is no JSDoc disambiguation between "vector search endpoint", "model serving endpoint", "external endpoint", "AI gateway endpoint" — all are Databricks concepts. The `EmbeddingSourceColumn.embeddingModelEndpointName` (model.ts:260) shows the SDK *does* qualify endpoint references when ambiguous, but here it does not. -- **Category:** 15 (generic field name), 19 (underspecified ID). -- **Suggested name:** `vectorSearchEndpointName` or add JSDoc clarifying it is "the Vector Search endpoint serving this index". The terse `endpointName` is fine *if* combined with type-level JSDoc. -- **Rationale:** The package owns a `VectorIndex` resource that is hosted on a *vector-search* endpoint — but a reader who jumps to a method signature sees only `endpointName` and may guess wrong. - -### 9. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462` vs `model.ts:491` -- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` (line 462, JSDoc "Column names used to retrieve data to send to the reranker") AND a `reranker.parameters.columnsToRerank: string[]` (line 491) inside the nested reranker parameters type. Two different fields with the same name and same purpose. The JSDoc on `reranker` (model.ts:463-468) does mention "`columns_to_rerank` selects which columns are used for reranking" — but `columns_to_rerank` lives in *both* places. -- **Category:** 12 (duplicate concept), 6 (misleading — which one wins?). -- **Suggested name:** Drop one, or document the precedence. If one is for input and the other for output/echo, name them accordingly. -- **Rationale:** Users will set the wrong field. Worth raising upstream. - -### 10. `usagePolicyId` field has tentative JSDoc — `CreateEndpointRequest.usagePolicyId` — `model.ts:104` -- **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". Exposing a public API field whose JSDoc admits the migration is incomplete invites runtime ambiguity: today the field is silently ignored (or partially handled) and tomorrow it activates. Callers cannot tell which. -- **Category:** 6 (misleading: present but not (yet) honored), 17 (parallel to `budgetPolicyId` which works today, with no behavioural distinction). -- **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behaviour and the rollout date. -- **Rationale:** "Once we've migrated" leaves the contract undefined. - -## Medium severity - -### 11. `IndexSubtype` enum values include `VECTOR` documented as "Not supported" — `src/v1/model.ts:29-33` -- **Why weird:** Enum exposes a sentinel value `VECTOR` whose JSDoc reads "Not supported. Use `HYBRID` instead." Exporting unsupported values inflates the enum and forces every consumer to filter or document them away. -- **Category:** 6 (misleading: present but not supported), 18 (the value `VECTOR` is also a tautology when inside an enum called `IndexSubtype` describing a vector-search index — every value is a kind of "vector"). -- **Suggested name:** Remove `VECTOR` from the enum, or rename the enum to `VectorIndexSubtype` and call the values `FullText | Hybrid`. Either way, eliminate the dead value. -- **Rationale:** Unused enum members are bug magnets. - -### 12. `IndexSubtype` versus `VectorIndexType` — two enums distinguishing two different "type" axes — `model.ts:29, 62` -- **Why weird:** `IndexSubtype` = `{VECTOR, FULL_TEXT, HYBRID}` (search semantics). `VectorIndexType` = `{DELTA_SYNC, DIRECT_ACCESS}` (data residency / sync model). Both are exposed as `index*Type*` fields. Same prefix word, different axes. Beginner users will conflate them. -- **Category:** 6 (misleading: both look like "the type" of the index), 17 (inconsistent naming for two type axes). -- **Suggested name:** Rename to disambiguate: `IndexSearchMode` (for subtype) and `IndexBackingType` / `IndexStorageType` (for the DELTA_SYNC/DIRECT_ACCESS axis). Or `IndexSearchKind` and `IndexSyncMode`. -- **Rationale:** Two parallel `*Type` enums make the API harder to learn. The current names are technically correct but functionally ambiguous. - -### 13. Enum values are SCREAMING_SNAKE_CASE — `PipelineType.TRIGGERED` etc. — `model.ts:40-43` -- **Why weird:** All enums (`EndpointType`, `IndexSubtype`, `PipelineType`, `ScalingChangeState`, `UpsertDeleteDataStatus`, `VectorIndexType`, `EndpointStatus_State`) use `UPPER_SNAKE_CASE` for member names. Google TS Style Guide §9.3 recommends `UpperCamelCase` for enum members. The codebase is mixed (some enums use camelCase elsewhere). The values are also the wire-protocol strings — wire is `UPPER_SNAKE` legitimately, but the TS *identifier* can be `Triggered` mapping to wire `'TRIGGERED'`. -- **Category:** 3 (acronym/casing inconsistency), 14 (Go-style). -- **Suggested name:** `PipelineType.Triggered | Continuous`, with explicit `= 'TRIGGERED'` wire values. Or accept the wire-form names and apply them consistently across all packages. -- **Rationale:** Style consistency across the workspace; preference for camelCase enum members aligns with the Google TS Style Guide. - -### 14. `EmbeddingSourceColumn.modelEndpointNameForQuery` — verb-phrase inside a field name — `model.ts:264` -- **Why weird:** Field name reads as a sentence (`modelEndpointName ForQuery`). JS field-naming convention is noun phrases, not "for"-clauses. Compare with adjacent `embeddingModelEndpointName` (also long, but a noun phrase). -- **Category:** 14 (Java-ish "ForX" suffix), 7 (verbose). -- **Suggested name:** `queryModelEndpointName` or `queryEmbeddingEndpointName`. -- **Rationale:** `for`-clauses in identifiers are uncommon in JS. The renaming aligns it with the adjacent field. - -### 15. `embeddingSourceColumns` vs `embeddingVectorColumns` — same shape, different role — `model.ts:179-181, 211-213, 241, 249` -- **Why weird:** Two parallel array fields on three different types (`DeltaSyncVectorIndexSpec`, `DeltaSyncVectorIndexSpecRequest`, `DirectAccessVectorIndexSpec`). One holds source text columns to be embedded; the other holds pre-computed vector columns. Both arrays use *different* element types (`EmbeddingSourceColumn` vs `EmbeddingVectorColumn`) — good — but the field names look near-identical at a glance. -- **Category:** 6 (visually confusable pair), 15 (the qualifier "Source"/"Vector" is doing all the work). -- **Suggested name:** `textColumns` + `vectorColumns`, or `embeddingTextColumns` + `embeddingVectorColumns`. Anything to widen the gap between the two names. -- **Rationale:** Pairs of similarly named array fields are a known footgun. A user typing `embedding` will autocomplete the wrong one. - -### 16. `columnsToSync` and `columnsToIndex` — overlapping fields with aliasing — `model.ts:197-204, 229-236` -- **Why weird:** Two fields on the same type, JSDoc says they are aliases ("[Optional] Alias for columns_to_sync. Select the columns to include in the vector index. ... Only one of columns_to_sync or columns_to_index may be specified.") Having two fields that mean the same thing in one struct, where the API expects exactly one to be set, is a recipe for runtime errors. -- **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). -- **Suggested name:** Deprecate one in the SDK (mark `columnsToSync` as `@deprecated` if `columnsToIndex` is the new canonical), or merge them with a runtime validation. -- **Rationale:** API-level aliases are upstream policy, but the SDK should clearly mark the deprecated alias. - -### 17. `pipelineId` is an underspecified ID — `model.ts:189, 221` -- **Why weird:** Field type is `string` with JSDoc "The ID of the pipeline that is used to sync the index." No format documented — is it a UUID, a numeric ID, a path? Compare with `effectiveBudgetPolicyId` which uses the same generic `string` but at least the policy ID is a known Databricks pattern. -- **Category:** 19 (underspecified ID), 15 (generic). -- **Suggested name:** Keep the name but improve the JSDoc with the expected ID format and a link to the Pipelines API. -- **Rationale:** Without format hints, users will struggle to construct the value. - -### 18. `inputsJson` instead of `inputs` — pre-stringified JSON in a JSON request — `model.ts:544` -- **Why weird:** `UpsertDataVectorIndexRequest.inputsJson: string` is "JSON string representing the data to be upserted." The TS surface forces the caller to call `JSON.stringify()` themselves, then the marshaling layer wraps the request body in `JSON.stringify(...)` *again*. Double-encoded payloads are a well-known JSON antipattern. -- **Category:** 6 (misleading — the field is JSON-in-JSON), 1 (generic — "inputs" tells you nothing about *what*). -- **Suggested name:** Expose as `inputs: JsonValue[]` (or whatever the row shape is) and let the SDK serialize, OR keep `inputsJson` but rename to `inputsJsonString` and document the double-encoding. -- **Rationale:** Same problem with `filtersJson` (see #19) and `schemaJson` (see #20). All three are wire-protocol leaks that should be normalized at the SDK boundary. - -### 19. `filtersJson` instead of `filters` — pre-stringified JSON in a JSON request — `model.ts:452` -- **Why weird:** Same JSON-in-JSON pattern as #18. The JSDoc even shows the JSON structure in examples (`{"id <": 5}`), which means the SDK knows the type — but it is still typed as `string`. -- **Category:** 6 (misleading), 1 (generic). -- **Suggested name:** Expose as `filters?: Record` and serialize internally. Or rename `filtersJsonString`. -- **Rationale:** Same as #18. - -### 20. `schemaJson` instead of typed schema — `DirectAccessVectorIndexSpec.schemaJson` — `model.ts:247` -- **Why weird:** Same pattern. The field is "The schema of the index in JSON format. Supported types are `integer`, `long`, `float`, `double`, `boolean`, `string`, `date`, `timestamp`." A typed schema descriptor would be far more discoverable. -- **Category:** 6 (misleading), 1 (generic). -- **Suggested name:** Expose as a typed shape, or rename `schemaJsonString` and add JSDoc warning. -- **Rationale:** Same as #18. - -### 21. `embeddingWritebackTable` — compound noun reads as gibberish — `model.ts:191, 223` -- **Why weird:** "Writeback" run together with "embedding" plus "Table" forms a hard-to-parse triple-noun. Pronunciation: "embed-ding-write-back-table". JSDoc clarifies meaning ("[Optional] Name of the Delta table to sync the vector index contents and computed embeddings to") — but the field name is opaque without it. -- **Category:** 7 (overly verbose), 14 (Go-style smushed identifier). -- **Suggested name:** `writebackTableName`, `embeddingsTableName`, or `computedEmbeddingsTable`. -- **Rationale:** Readability of compound nouns degrades fast past 2 words. - -### 22. `ensureRerankerCompatible` boolean — confusing name and confusing semantics — `model.ts:335` -- **Why weird:** JSDoc says: "If true, the URL returned for the index is guaranteed to be compatible with the reranker. Currently this means we return the CP URL regardless of how the index is being accessed. If not set or set to false, the URL may still be compatible with the reranker depending on what URL we return." So the flag toggles *which URL is returned*, not whether the index itself is reranker-compatible. The name suggests the operation *ensures compatibility*, but it actually just changes URL format. -- **Category:** 6 (misleading), 1 (vague boolean). -- **Suggested name:** `useControlPlaneUrl`, `returnControlPlaneUrl`, or `rerankerCompatibleUrl`. -- **Rationale:** Boolean names should describe the side effect, not an aspirational outcome. - -### 23. `numResults` field name in two places — `model.ts:438, 514` -- **Why weird:** Two unrelated requests (`QueryVectorIndexRequest`, `ScanVectorIndexRequest`) both name the result-count field `numResults`. JS convention is `limit` (matching SQL `LIMIT`, REST `?limit=`) or `pageSize`. `numResults` is Python/SQL-ish. -- **Category:** 14 (Python/SQL-style), 17 (cross-package inconsistency — other paged APIs use `pageSize` or `limit`). -- **Suggested name:** `limit` (matches HTTP query param and most JS libs) or `pageSize`. -- **Rationale:** Aligning with `limit`/`pageSize` reduces friction. - -### 24. `queryType` typed as `string` with constrained values — `QueryVectorIndexRequest.queryType` — `model.ts:460` -- **Why weird:** JSDoc says: "The query type to use. Choices are `ANN` and `HYBRID` and `FULL_TEXT`. Defaults to `ANN`." Three known values, but typed as `string` — not an enum. Users get no autocomplete, no compile-time check. -- **Category:** 1 (generic typing), 6 (misleading typing). -- **Suggested name:** Introduce an enum `QueryType.Ann | Hybrid | FullText` (these overlap with `IndexSubtype` values but represent different concepts). -- **Rationale:** `string` for a closed set of values is a known antipattern. - -### 25. `RerankerConfig.model` field — generic name "model" — `model.ts:485` -- **Why weird:** Bare `model?: string` with no JSDoc. In ML SDKs "model" is overloaded (ML model, data model, type model). The field probably holds a model endpoint name or model identifier. -- **Category:** 1 (generic), 15 (generic field losing meaning). -- **Suggested name:** `modelEndpointName`, `modelName`, or `rerankerModel`. -- **Rationale:** Document what kind of identifier this is. - -## Low severity - -### 26. `Struct.fields` returns `MapStringValueEntry[]` instead of a record — `model.ts:529` -- **Why weird:** `Struct` is the SDK's wire-format for a JSON-like map, and `MapStringValueEntry` is `{key: string, value: Value}`. The TS shape is "an array of key-value entries" rather than `Record`. Idiomatic JS would use a plain object or `Map`. -- **Category:** 14 (array-of-entries map encoding leaks to TS). -- **Suggested name:** Flatten to `Record` at the TS boundary; keep the entry-array shape on the wire. -- **Rationale:** Forcing users to map an array of `{key, value}` pairs into a record is friction the SDK could remove. - -### 27. `Value` — single-word generic name for a discriminated union — `model.ts:561-570` -- **Why weird:** A bare type called `Value` is uninformative. It is the SDK's wire-form scalar wrapper (number/string/bool/struct/list). Stronger candidates: `ScalarValue`, `WireValue`, `VectorIndexValue`. -- **Category:** 1 (generic). -- **Suggested name:** `ScalarValue` or move to the core wkt package and rename `wkt.Value`. -- **Rationale:** `Value` collides with too many concepts. - -### 28. `Struct` — generic single-word type name — `model.ts:527` -- **Why weird:** "Struct" is a language keyword in many languages (Go, C, Rust). In JS/TS it is a vague C-style holdover. The type is "a row of a vector index" (per the JSDoc). -- **Category:** 1 (generic), 10 (potential reserved-word collision in TS-flow tools). -- **Suggested name:** `IndexRow` or `VectorIndexRow`. -- **Rationale:** A more domain-specific name is more discoverable. - -### 29. `MapStringValueEntry` — verbose name for a key-value pair — `model.ts:369` -- **Why weird:** Reads as "Map of String to Value Entry". JSDoc says "Key-value pair." Just call it that. -- **Category:** 7 (verbose). -- **Suggested name:** `KeyValue` or `StructField`. -- **Rationale:** Less verbose, more idiomatic. - -### 30. `ResultManifest` — Java/Spring-flavored noun — `model.ts:503-508` -- **Why weird:** "Manifest" in a query-result context is unusual JS phrasing. JSDoc says "Metadata about the result set." More common in JS: `Metadata`, `Schema`, `Info`. -- **Category:** 14 (Java-style), 1 (mildly generic). -- **Suggested name:** `ResultMetadata` or `ResultSchema`. -- **Rationale:** Aligns with idiomatic JS. - -### 31. `ResultData` — generic two-word noun — `model.ts:495-500` -- **Why weird:** Type is "Data returned in the query result." `ResultData` is generic; `QueryResultData` or just `Rows` would be more specific. -- **Category:** 1 (generic). -- **Suggested name:** `QueryResultData` or `ResultRows`. -- **Rationale:** Disambiguate. - -## Observation - -### 32. `Call` type imported from `@databricks/sdk-core/api` — generic name — `client.ts:4` -- **Why weird:** Cross-package import. `Call` is the most generic possible name for "a network operation". -- **Category:** 1 (generic), cross-package observation. -- **Suggested name:** `RetryableCall`, `SdkCall`. Out of scope for this audit. -- **Rationale:** Tracked for cross-package consistency. - -### 33. `MiniVectorIndex` is exported from `index.ts` despite being internal-looking — `index.ts:42` -- **Why weird:** The mini variant (see #1, #2) is re-exported as part of the public API. If the intent is for it to be an internal implementation detail, it should not be in `index.ts`. -- **Category:** Observation on the public surface. -- **Suggested name:** Either rename per #1 or remove from the public surface. -- **Rationale:** Consumers will use whatever is exported; if `MiniVectorIndex` is a name we'd prefer not to commit to publicly, it should be hidden. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/logdeliveryconfigurations.md b/.agent/naming-audit/logdeliveryconfigurations.md index bd248cf4..6c6b7429 100644 --- a/.agent/naming-audit/logdeliveryconfigurations.md +++ b/.agent/naming-audit/logdeliveryconfigurations.md @@ -1,326 +1,3 @@ -# Naming Audit: `logdeliveryconfigurations` (v1) +# Naming Audit: logdeliveryconfigurations -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Package:** `@databricks/sdk-logdelivery` -**Path:** `/home/parth.bansal/sdk-js/packages/logdelivery/` -**Version audited:** `v1` -**Files audited:** -- `src/v1/model.ts` (404 lines) -- `src/v1/client.ts` (245 lines) -- `src/v1/utils.ts` (151 lines) -- `src/v1/index.ts` (25 lines) - -**Inferred domain:** Account-level CRUD for log delivery configurations -(REST: `POST/GET/PATCH /api/2.0/accounts/{account_id}/log-delivery`). -A log delivery configuration ties a `credentialsId` (AWS IAM role) and a -`storageConfigurationId` (S3 bucket) to a log type (`BILLABLE_USAGE` or -`AUDIT_LOGS`), optionally scoped by workspace IDs. There is no delete -endpoint by design — the API only supports disabling via the update -method. - -**Total weird names flagged: 35** - -## Summary - -| Severity | Count | -| --- | --- | -| High | 6 | -| Medium | 13 | -| Low | 10 | -| Observation | 6 | - ---- - -## High severity - -### H1. `LogDeliveryStatusEnum` — type-name carries `Enum` suffix — `model.ts:39` -- **File:** `model.ts:39-50`, exported in `index.ts:8`. -- **Category:** 20 (type-suffix tautology), 12 (duplicate concept — two enums with overlapping prefixes). -- **Why weird:** `LogDeliveryStatusEnum` is the *only* type in the audited package (and one of the few across the workspace) whose name ends in `Enum`. Every other enum here is just `LogDeliveryConfigStatus`, `LogDeliveryType`, `LogDeliveryOutputFormat` — no suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` was already claimed by the wrapper *interface* at `model.ts:208`. -- **Suggested name:** Rename the wrapper interface to `LogDeliveryAttempt` (it actually holds attempt fields: `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, `status`), freeing `LogDeliveryStatus` for the enum. Alternatively, rename the enum to `LogDeliveryAttemptStatus` (drops `Enum`, matches the fields it describes). -- **Rationale:** A field typed `attempt.status: LogDeliveryAttemptStatus` reads better than `logDeliveryStatus.status: LogDeliveryStatusEnum`. The `Enum` suffix is type-suffix tautology and is unique to this one type — a clear smell that the underlying noun is overloaded. - -### H2. `LogDeliveryConfigStatus` vs `LogDeliveryStatusEnum` — two near-identical enum names for unrelated concepts — `model.ts:12,39` -- **File:** `model.ts:12-17`, `model.ts:39-50`. -- **Category:** 12 (duplicate concept), 6 (misleading — both contain "status" + "log delivery"). -- **Why weird:** Both enums describe "status" of "log delivery", but cover orthogonal facets: - - `LogDeliveryConfigStatus`: `ENABLED` / `DISABLED` — whether the configuration is active. - - `LogDeliveryStatusEnum`: `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` — whether the most recent delivery attempt worked. - A reader sees `status?: LogDeliveryConfigStatus` on `LogDeliveryConfiguration.status` (line 199) and `status?: LogDeliveryStatusEnum` on `LogDeliveryStatus.status` (line 217). The two `status` fields live one level apart in the same response payload, with totally different domains. The class-doc on `LogDeliveryConfigStatus` (line 8-10) even mis-describes them: "ENABLED: All dependencies have executed and succeeded. DISABLED: At least one dependency has succeeded." That is nonsense — it appears to be JSDoc copy-pasted from another type. -- **Suggested name:** `LogDeliveryConfigStatus` → `LogDeliveryEnablement` (`ENABLED` / `DISABLED`). `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus` (`CREATED` / `SUCCEEDED` / ...). The differentiated nouns ("enablement" vs "attempt status") make the two enums distinguishable at the call site. -- **Rationale:** Identical noun ("Status") for incompatible domains is a classic source of bugs: a reviewer cannot tell at a glance whether `status === 'CREATED'` is checking the config or the last-delivery state. Renaming forces the distinction. - -### H3. `LogDeliveryConfigStatus` JSDoc is wrong — `model.ts:7-10` -- **File:** `model.ts:5-11`. -- **Category:** 6 (misleading — JSDoc claim contradicts type domain). -- **Why weird:** Class-level JSDoc says: - ``` - Log Delivery Status - `ENABLED`: All dependencies have executed and succeeded - `DISABLED`: At least one dependency has succeeded - ``` - But the enum values are `ENABLED` / `DISABLED` of a *configuration*, with the actual member docs reading "Configuration is enabled" / "Configuration is disabled". The class doc appears imported from a Workflows-domain enum (DLT pipelines have "dependencies"). The leading bare `*` on line 6 is also stray (likely an artefact of the generator emitting `/** * */` blocks). -- **Suggested name:** Rewrite JSDoc to "Whether this log delivery configuration is currently active. Set via the patch-status endpoint." -- **Rationale:** Misleading JSDoc is worse than no JSDoc — IDE tooltips, hover-help, and generated API reference will all display the wrong meaning. Same finding for `LogDeliveryOutputFormat` (line 22) and `LogDeliveryType` (line 56) — all three carry the stray `* ` on the second line. Across the SDK this is a generator artefact worth fixing globally. - -### H4. `LogDeliveryConfiguration.configId` and `.configName` use the cryptic abbreviation `config` — `model.ts:171,173` -- **File:** `model.ts:171,173` (also `model.ts:69,71`, `model.ts:126`, `model.ts:232`, `client.ts:94,126,154,218`). -- **Category:** 5 (cryptic abbreviation), 19 (underspecified ID — `configId` of what?). -- **Why weird:** The field is named `configId`, not `logDeliveryConfigurationId`. Because the surrounding type is `LogDeliveryConfiguration`, the wire field is `config_id`, and the doc says "The unique UUID of log delivery configuration", the truncation is acceptable in context — but on its own, `configId` is generic. A consumer pattern-matching on `configId` across multiple Databricks SDK packages cannot tell which "config" is meant. The wire path `/log-delivery/${req.configId}` in `client.ts:126,218` makes the same identifier look domain-detached. -- **Suggested name:** Either: - 1. Keep `configId` (short, matches wire) and rely on the surrounding type for context — but then JSDoc should say "The UUID of this log delivery configuration" (drop "the"). - 2. Rename to `id` and let `LogDeliveryConfiguration.id` carry meaning by type context — matches `databricks-sdk-go` resource-id idiom. -- **Rationale:** Pattern (2) is what Stripe / GitHub / Google APIs do (`Customer.id`, `Repository.id`). Pattern (1) is what the Databricks Go SDK does. Pick one and apply globally. As written, `configId` is the worst of both — a half-abbreviation that's neither a generic `id` nor a fully qualified `logDeliveryConfigurationId`. - -### H5. `GetLogDeliveryConfigurationRequest` and `UpdateLogDeliveryConfigurationRequest` repeat path/body fields with redundant naming — `model.ts:124-129,230-237` -- **File:** `model.ts:124-129` (`GetLogDeliveryConfigurationRequest`), `model.ts:230-237` (`UpdateLogDeliveryConfigurationRequest`). -- **Category:** 7 (overly verbose), 5 (cryptic — `configId` again), 6 (misleading — both fields are required path params but typed optional). -- **Why weird:** `GetLogDeliveryConfigurationRequest` has exactly two fields, both optional: `configId` and `accountId`. The doc says "The log delivery configuration id of customer" — "of customer" reads like a Hindi/Indian-English idiom and is meaningless in this context (a config has no "of customer" — it belongs to an account). Both fields are part of the URL path (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — see `client.ts:126,218`); marking them `?: undefined` then falling back to `??' '` in the URL template produces silent bad requests (the client will hit `/api/2.0/accounts//log-delivery/` if `accountId` is absent). -- **Suggested name:** Rename "of customer" away (`The unique UUID of the log delivery configuration to fetch`). Drop `| undefined` on `configId` — it is required. `accountId` is fine as optional only if the client falls back to `ClientOptions.accountId` (which it does at `client.ts:126`); document that explicitly. -- **Rationale:** The current design type-checks fine but blows up at runtime with an unintuitive URL. Required path params should be required types. The "of customer" prose is generator-emitted boilerplate worth removing. - -### H6. `*Request_Response` types — proto-architectural-leak `Request_` infix on response DTOs — `model.ts:115,132,158,240` -- **File:** `model.ts:115` (`CreateLogDeliveryConfigurationRequest_Response`), `model.ts:132` (`GetLogDeliveryConfigurationRequest_Response`), `model.ts:158` (`ListLogDeliveryConfigurationRequest_Response`), `model.ts:240` (`UpdateLogDeliveryConfigurationRequest_Response`). Also at `index.ts:15,17,19,23`, and on every marshal/unmarshal schema at `model.ts:243,255,267,332`. -- **Category:** Proto-architectural-leak (mid-position `Request_` infix; underscore from proto-nested-message names). -- **Why weird:** The `Request_` mid-token is a verbatim leak from the proto/gRPC source where the response type is generated as a nested message inside the Request message (`CreateLogDeliveryConfigurationRequest.Response` in proto becomes `CreateLogDeliveryConfigurationRequest_Response` after underscore-flattening). In a TypeScript public API, the *response* type carrying `Request` in its name is a category error: the reader sees `Request` and infers "input DTO" but the type actually models the *output*. The eslint-disable lines (`@typescript-eslint/naming-convention -- Proto-style nested message name.`) at lines 114, 131, 157, 239, 242, 254, 266, 331 acknowledge the leak. The underscore is the disqualified pattern; the `Request` infix on a response DTO is the architectural leak. -- **Suggested name:** Drop the `Request_` infix. Use `CreateLogDeliveryConfigurationResponse`, `GetLogDeliveryConfigurationResponse`, `ListLogDeliveryConfigurationsResponse`, `UpdateLogDeliveryConfigurationResponse`. This removes both the underscore (proto-nested-message smell) and the misleading `Request` infix on response types. -- **Rationale:** The TS public surface should not advertise its proto ancestry. Sibling SDKs (Stripe, GitHub Octokit, AWS SDK v3) emit `Foo` request / `FooResponse` response without nesting. The underscore identifier additionally trips every linter rule for naming-conventions (hence the per-occurrence eslint-disable). Generator-level fix: emit `XxxResponse` instead of `XxxRequest_Response`. - ---- - -## Medium severity - -### M6. `Client` class is unprefixed — `client.ts:46` -- **File:** `client.ts:46`, exported at `index.ts:3`. -- **Category:** 1 (vague), 12 (duplicate concept across packages — every Databricks SDK package exports its own `Client`). -- **Why weird:** A user importing this package writes `import {Client} from '@databricks/sdk-logdelivery/v1'` and immediately must alias (`import {Client as LogDeliveryClient}`) to compose multiple Databricks clients. Consistent across the SDK but worth flagging. -- **Suggested name:** `LogDeliveryClient` or `LogDeliveryConfigurationsClient`. Or expose only a namespace (`import * as logDelivery from '@databricks/sdk-logdelivery/v1'` then `logDelivery.Client`). -- **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. Same finding as `billableusagedownload` audit #8. - -### M7. Client method names embed the noun three times — `client.ts:90,122,150,214` -- **File:** `client.ts:90,122,150,192,214`. -- **Category:** 7 (overly verbose), 17 (inconsistent action verbs vs sibling packages). -- **Why weird:** `client.createLogDeliveryConfiguration(...)` is 27 characters. With the package prefix and the request type, a single call line reads: - ```ts - await client.createLogDeliveryConfiguration({logDeliveryConfiguration: {...}}) - ``` - That is "logDeliveryConfiguration" repeated three times in one expression. The Go SDK uses short method names (`Create`, `Get`, `List`, `PatchStatus`) because the noun comes from the receiver type. The TS port replicates the full noun. Sibling packages like `billableusagedownload.Client.download()` and `accountsettings.Client.disableLegacyFeatures()` use shorter names. -- **Suggested name:** `client.create()`, `client.get()`, `client.list()`, `client.listIter()`, `client.updateStatus()`. The receiver type (`LogDeliveryClient`) already provides the noun. -- **Rationale:** TS method names should not repeat the type they live on. Once `Client` is renamed `LogDeliveryClient` (M6), the shorter forms are unambiguous. Note that the Go SDK uses `PatchStatus` (the actual HTTP verb is `PATCH`) — the TS `updateLogDeliveryConfiguration` is already a paraphrase, so consistency with Go is partly already lost. - -### M8. `updateLogDeliveryConfiguration` does not actually "update" — it only patches status — `client.ts:209-243` -- **File:** `client.ts:209-243`, `UpdateLogDeliveryConfigurationRequest` at `model.ts:230`. -- **Category:** 6 (misleading), 17 (inconsistent verb — Go uses `PatchStatus`, TS uses `update`). -- **Why weird:** The method name `updateLogDeliveryConfiguration` suggests "update arbitrary fields of the config". In reality the request body only contains `configId`, `accountId`, and `status` (see `UpdateLogDeliveryConfigurationRequest` interface at `model.ts:230-237`) — you can only flip ENABLED <-> DISABLED. The JSDoc on the method (`client.ts:209-212`) calls it out: "Enables or disables a log delivery configuration." The Go SDK method is named `PatchStatus`, which is honest. -- **Suggested name:** `patchStatus`, or `setStatus`, or `updateStatus`. The current name oversells the surface. -- **Rationale:** "Update" implies multi-field mutation. If a caller writes `client.updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new-prefix'})` they will be silently surprised — the `deliveryPathPrefix` is not part of the request DTO so it will not type-check (in TS strict mode), but they would have to read the type to learn that. The verb is a footgun. - -### M9. `listLogDeliveryConfiguration` — singular noun on a method returning multiple — `client.ts:150,192` -- **File:** `client.ts:150,192`. -- **Category:** 9 (singular/plural mismatch). -- **Why weird:** `listLogDeliveryConfiguration` is singular ("Configuration") but the method yields multiple configurations (the response body field is `logDeliveryConfigurations` — plural — at `model.ts:160`). Sibling packages use plural — e.g., `listBudgetConfigurations` in `budgets/src/v1/client.ts`. The singular method name fights the plural data shape. -- **Suggested name:** `listLogDeliveryConfigurations` (plural noun). -- **Rationale:** Adjacent package `budgets` uses `listBudgetConfigurations` (plural). Within this package, the response body field is plural while the method name is singular — pluralisation should match the collection it returns. - -### M10. `ListLogDeliveryConfigurationRequest` (request type) is singular — `model.ts:141` -- **File:** `model.ts:141-155`. -- **Category:** 9 (singular/plural mismatch). -- **Why weird:** Same issue as M9 for the request DTO. The interface name says "List one configuration" but the method actually lists many. The class-level JSDoc says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurations` (plural) at `packages/budgets/src/v1/model.ts`. -- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (plural noun preserving the `Request` suffix). -- **Rationale:** Naming should match data shape. Pluralisation is the standard signal that a method returns a collection. Cross-package inconsistency. - -### M11. `logDeliveryStatus` field vs `LogDeliveryStatus` type vs `LogDeliveryStatusEnum` enum — three identifiers conflated — `model.ts:103,205,217` -- **File:** `model.ts:103,205` (field `logDeliveryStatus: LogDeliveryStatus`), `model.ts:208` (interface `LogDeliveryStatus`), `model.ts:217` (`status?: LogDeliveryStatusEnum`). -- **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). -- **Why weird:** A reader looking at `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types: - - `LogDeliveryConfiguration` (the resource). - - `LogDeliveryStatus` (the wrapper holding attempt metadata). - - `LogDeliveryStatusEnum` (the actual ENABLED/CREATED-style enum). - Each layer adds the noun "Status" with different meaning. The field name `logDeliveryStatus` is redundant inside a `LogDeliveryConfiguration` (the prefix is implied) and clashes with the type-level prefix. -- **Suggested name:** Field: `lastAttempt: LogDeliveryAttempt`. Wrapper type: `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message` — drop `last` prefix once nested). Enum: `LogDeliveryAttemptStatus`. Result reads as `config.lastAttempt.status === 'SUCCEEDED'`. -- **Rationale:** "Status" is too generic to triple-stack. Renaming the wrapper to "Attempt" (its actual semantics) breaks the conflation cleanly. - -### M12. `creationTime` / `updateTime` — verb-tense inconsistency, type misleads as ISO timestamp — `model.ts:99-101,201-203` -- **File:** `model.ts:99-101,201-203`. -- **Category:** 13 (verb-tense inconsistency — `creation` is a noun, `update` is a verb), 6 (misleading — `number` type with JSDoc "epoch milliseconds"). -- **Why weird:** `creationTime: number` and `updateTime: number`. The first is noun-form ("creation"), the second is verb-form ("update"). Pair-wise they should match: `createdTime`/`updatedTime` (past participle) or `creationTime`/`updateTime` (noun). Also, both are `number` (epoch ms) but neither type signals "this is a unix timestamp in milliseconds"; the JSDoc carries that information. Across the SDK, audited packages have flagged similar issues. -- **Suggested name:** `createdAt: number` / `updatedAt: number` (canonical SaaS convention — Stripe/GitHub/Salesforce/Atlassian all use *At). Brand the type as `EpochMillis` for compile-time safety. -- **Rationale:** "*At" is the industry standard for timestamps. Same finding in many other audited packages (`budgets`, `apps`, etc.) — fix at generator level. - -### M13. `deliveryStartTime: string` for YYYY-MM — misleading type — `model.ts:95,197` -- **File:** `model.ts:94-95,196-197`. -- **Category:** 6 (misleading — type contradicts domain), 1 (vague — "delivery start time" sounds like a timestamp). -- **Why weird:** The field is `string`, but the JSDoc says "specified in YYYY-MM format". That is a year-month string, not a time. Compare with `creationTime: number` (which is an epoch-ms timestamp). The same word "Time" is used for two different formats. A `string` for "YYYY-MM" should be branded or use a `Temporal.YearMonth` from `@js-temporal/polyfill` (already a dependency at `package.json:23`). -- **Suggested name:** `deliveryStartMonth` (clarifies granularity), typed `Temporal.PlainYearMonth | string`. -- **Rationale:** "Time" implies high-resolution. The domain is monthly billing buckets, so "Month" is the right granularity. Same convention as `Stripe.Invoice.period_start` (epoch) vs `Stripe.UsageRecord.period.start` (date-only). - -### M14. `workspaceIdsFilter` — pluralised collection name mixed with `Filter` suffix — `model.ts:91,193` -- **File:** `model.ts:90-91,192-193`. -- **Category:** 7 (overly verbose), 9 (singular/plural mix), 15 (generic suffix). -- **Why weird:** The field is `workspaceIdsFilter: number[]`. The plural `Ids` says "this is a list of IDs". The `Filter` suffix says "this is a filter". A `number[]` already conveys "list of ints". Calling it `workspaceIdsFilter` adds redundant `Filter` noise; calling it just `workspaceIds` (the actual content) would be clearer. Compare with `ListLogDeliveryConfigurationRequest.credentialsId: string` (singular, no `Filter` suffix at `model.ts:145`) which serves the same conceptual role. -- **Suggested name:** `workspaceIds: number[]` (drop `Filter`). Or `filterByWorkspaceIds` if intent must be made explicit. -- **Rationale:** Type-driven inference: a `number[]` named after the entity is unambiguous. `Filter` is generic ceremony. - -### M15. `workspaceIdsFilter: number[]` — IDs typed as `number` is dangerous — `model.ts:91,193` -- **File:** `model.ts:90-91,192-193`. -- **Category:** 6 (misleading), 19 (underspecified ID). -- **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double precision float — only safe up to 2^53 - 1. Databricks workspace IDs are int64 server-side; sending an ID greater than 2^53 will silently lose precision in the JSON wire. The TS type should be `bigint[]` or `(number | bigint)[]` or branded. -- **Suggested name:** `workspaceIds: bigint[]` (matches the int64 wire). Or `workspaceIds: WorkspaceId[]` with a branded `type WorkspaceId = number & {__brand: 'WorkspaceId'}`. -- **Rationale:** Cross-package issue. Same finding will recur on every `*Id: number` field that maps to an int64 wire. Fix at generator level: emit `bigint` for `int64`. - -### M16. `host` field on `Client` lacks domain context — `client.ts:47` -- **File:** `client.ts:47,62`. -- **Category:** 1 (vague), 15 (generic field name). -- **Why weird:** `private readonly host: string` — without context, `host` could be any URL or hostname. The setter at line 62 trims trailing slash. The semantically correct name is `databricksHost` or `workspaceUrl` or `baseUrl` (the actual content is `https://.../`, not just a hostname like `example.com`). -- **Suggested name:** `baseUrl` (matches the actual content — a URL including scheme). -- **Rationale:** Same pattern across every package's `Client`. Fix at generator. Same finding as `billableusagedownload` audit #?. - -### M17. `marshalRequest` / `parseResponse` and `marshal*Schema` / `unmarshal*Schema` — proto/gRPC verb leak — `utils.ts:113,119`, `model.ts:243,255,267,280,317,332,335,369,379,393` -- **File:** `utils.ts:113` (`parseResponse`), `utils.ts:119` (`marshalRequest`), `model.ts:243,255,267,332` (`unmarshal*Request_ResponseSchema`), `model.ts:280,317` (`unmarshal*Schema`), `model.ts:335,369,379,393` (`marshal*Schema`). -- **Category:** Proto-architectural-leak (mid-position `marshal`/`unmarshal` verbs, gRPC/proto serialization terminology). -- **Why weird:** `marshal` and `unmarshal` are protobuf/gRPC (and Go) terms for binary serialization, not idiomatic JavaScript. The TS ecosystem uses `serialize`/`deserialize` or `encode`/`decode` (e.g., `JSON.stringify`/`JSON.parse`, Zod's `parse`/`safeParse`). Every export-level identifier in `model.ts` is prefixed `marshal*Schema` or `unmarshal*Schema`, advertising the proto backend to consumers. The asymmetry is also odd: input wrapper is `marshalRequest` (verb-noun) but output wrapper is `parseResponse` (different verb entirely — Zod-flavoured "parse" on the unmarshal side and proto-flavoured "marshal" on the marshal side). -- **Suggested name:** Rename `marshalRequest` → `encodeRequest` (or `serializeRequest`); `parseResponse` already uses `parse`, so rename schema vars to match: `*RequestSchema` / `*ResponseSchema` (drop `marshal`/`unmarshal` prefix; the Zod `.parse` and `.transform` direction is encoded in the schema itself, not in its identifier). Or, if direction must be visible, use `encodeXxxSchema` / `decodeXxxSchema`. -- **Rationale:** Cross-package generator concern. `marshal`/`unmarshal` is a proto-ecosystem dialect (Go SDK uses it natively, hence the 1:1 port). TypeScript consumers expect `serialize`/`deserialize` or just schema names. Fix at generator level — none of these symbols are user-facing utility helpers, so renaming has zero blast radius outside the package. - -### M18. `executeHttpCall` parameter struct `HttpCallOptions.request: HttpRequest` reuses `request` for the wire request — `utils.ts:15-19,65` -- **File:** `utils.ts:15-19,65-94`. -- **Category:** 1 (vague mid-position `Call`), proto-architectural-leak (`HttpCall` reads as a gRPC-style "call" abstraction, not an HTTP request). -- **Why weird:** `HttpCallOptions` and `executeHttpCall` use `Call` as a mid-position noun. In gRPC/RPC vocabularies, a "call" is the unit of work (`grpc.Call`, `Twirp.Call`, etc.). In HTTP/REST vocabularies, the unit is a "request". The package already imports `Call` from `@databricks/sdk-core/api` (line 3-4), so the local `HttpCallOptions` doubles up the gRPC terminology. `executeHttpCall` is even more confusing: it doesn't execute a `Call` (the typedef-imported one) — it sends an `HttpRequest` and returns a body. -- **Suggested name:** `HttpRequestOptions` (or drop the type entirely and inline the three fields) and `sendHttpRequest` (or `dispatchHttp`). Reserve `Call` for the retry-wrapped function alias. -- **Rationale:** Within one file, `Call` means two different things: the abstract retry-wrapped function type (imported from `@databricks/sdk-core/api`) and the HTTP request (local `HttpCallOptions`). The overloaded noun is a proto-architectural-leak — HTTP REST clients call them "requests", not "calls". Same finding cross-package. - ---- - -## Low severity - -### L19. `LogDeliveryType` enum values `BILLABLE_USAGE` / `AUDIT_LOGS` — singular/plural mismatch — `model.ts:58-60` -- **File:** `model.ts:56-61`. -- **Category:** 9 (singular/plural mismatch), 18 (long enum values). -- **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered. They should match — either `BILLABLE_USAGE_LOGS` / `AUDIT_LOGS` (both plural) or `BILLABLE_USAGE` / `AUDIT` (both singular). -- **Suggested name:** `BILLABLE_USAGE` / `AUDIT` (drop the `_LOGS` — the enum is `LogDeliveryType` so "logs" is implied). -- **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the type name) is cleaner. - -### L20. `LogDeliveryOutputFormat.CSV` / `.JSON` — acronym casing OK but enum is binary, no need — `model.ts:25-27` -- **File:** `model.ts:23-28`. -- **Category:** 3 (acronym casing — fine here since it matches the wire), Observation. -- **Why weird:** Two-value enum where `log_type === 'BILLABLE_USAGE'` forces `output_format === 'CSV'` and `log_type === 'AUDIT_LOGS'` forces `'JSON'` (see JSDoc on `outputFormat` at `model.ts:79-83`). The field is therefore *always* derivable from `logType` — making it a redundant field, not a redundant enum, but worth flagging. -- **Suggested name:** Drop `outputFormat` from the request DTO (it can be derived server-side). Keep on the response DTO for clarity. -- **Rationale:** Not strictly a naming issue, but reduces API surface area. - -### L21. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` enum-member doc strings are tautological — `model.ts:13-16` -- **File:** `model.ts:13-16`. -- **Category:** 1 (vague). -- **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the doc says exactly what the name says. JSDoc should add information, not echo identifiers. -- **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured S3 bucket." -- **Rationale:** Cross-cutting generator concern. - -### L22. `LogDeliveryStatusEnum.NOT_FOUND` is a confusing terminal state — `model.ts:48-49` -- **File:** `model.ts:48-49`. -- **Category:** 6 (misleading). -- **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc says it actually means "configuration has been disabled since the release of this feature or there are no workspaces in the account". That's not "not found"; it's "no logs to deliver because account state". -- **Suggested name:** `NO_DATA` or `NOT_APPLICABLE` or `DISABLED_AT_RELEASE` — anything that doesn't sound like a 404. -- **Rationale:** API value names should not collide with HTTP semantics that mean something different. A monitoring dashboard surfacing `status === 'NOT_FOUND'` will mislead an operator into thinking the config was deleted. - -### L23. `PACKAGE_SEGMENT` constant — `client.ts:41` -- **File:** `client.ts:41-44`. -- **Category:** 1 (vague), 15 (generic). -- **Why weird:** `Segment` is a generic CS term. The comment "Package identity segment for this client to be used in the User-Agent header" (`client.ts:40`) is the disambiguator; without it the constant name does not communicate what it is. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Cross-package consistency — same finding in every audited package. Worth normalising at generator level. Same as `billableusagedownload` audit #10. - -### L24. `httpClient: HttpClient` field — type-suffix tautology — `client.ts:51` -- **File:** `client.ts:51,72`. -- **Category:** 20 (type-suffix tautology). -- **Why weird:** Field name and type both end in `Client`. Convention is widespread but flagged per rule 20. -- **Suggested name:** `transport: HttpClient` (matches the imported package `@databricks/sdk-databricks/transport`). -- **Rationale:** `transport` is what HTTP layers are usually named in language-agnostic SDK terminology (gRPC, GraphQL clients, etc.). It avoids the `Client/Client` echo. Tolerable as-is. - -### L25. `req` / `resp` / `opts` / `httpReq` abbreviations — `client.ts:91,99,103,127,153,170,193,196,215,223` -- **File:** `client.ts:91,99,103,...` (every method). -- **Category:** 5 (cryptic abbreviation). -- **Why weird:** Three-letter abbreviations for parameter and local names. The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. -- **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. -- **Rationale:** Spelling out costs nothing and improves readability. Same finding across every audit. - -### L26. `pageReq` local in `listLogDeliveryConfigurationIter` — `client.ts:196` -- **File:** `client.ts:196`. -- **Category:** 5 (cryptic), 1 (vague — `pageReq` is shorthand for "request for next page"). -- **Why weird:** Variable holds the *modified* request for each page (with `pageToken` updated). `pageReq` reads as "page request" — a noun describing the page itself. -- **Suggested name:** `currentRequest` or `paginatedRequest`. Or unify with `request` if you adopt option-bag style. -- **Rationale:** Low; loop-local variable. - -### L27. `executeCall` / `executeHttpCall` near-duplicate names — `utils.ts:26,65` -- **File:** `utils.ts:26-38,65-94`. -- **Category:** 1 (vague), 17 (inconsistent layer naming). -- **Why weird:** Two functions named almost identically doing very different things. `executeCall` wraps the call in retry/rate-limit; `executeHttpCall` does the raw HTTP send + decode + ApiError. Within the same file the naming distinction is too subtle. -- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `dispatchHttp`). Or just `wrapRetry` / `sendHttp`. -- **Rationale:** Same finding as `billableusagedownload` audit #13. Cross-package generator concern. - -### L28. `HttpCallOptions` — `utils.ts:15` -- **File:** `utils.ts:15-19`. -- **Category:** 1 (vague suffix `Options`), 12 (duplicate `Options` naming). -- **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` from `@databricks/sdk-core/api` imported at line 3). The local interface shadows the imported one cognitively. The field is not user-facing — it is an internal bag. -- **Suggested name:** `HttpCallContext` (it is not user-tunable options; it is an internal context bag). -- **Rationale:** Distinguish internal context bags from user-tunable option structs. Same finding as `billableusagedownload` audit #14. - ---- - -## Observations - -### O29. `flattenQueryParams` is exported but unused — `utils.ts:123` -`client.ts` does its own query-param construction inline (lines 155-167) using `new URLSearchParams()` and four `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called by this package. This is a generator artefact — every generated package ships this helper. - -### O30. `parseResponse` is unused — `utils.ts:113` -Actually, `parseResponse` *is* used (4 call sites in `client.ts:109,137,180,233`). Not dead. Correction to prior packages' findings: in `logdeliveryconfigurations`, parseResponse is actively in use. - -### O31. `marshalRequest` is used twice — `client.ts:95,219` -Used for `createLogDeliveryConfiguration` and `updateLogDeliveryConfiguration`. Not dead. - -### O32. `accountId` URL fallback — `client.ts:94,126,154,218` -`createLogDeliveryConfiguration` (line 94) reads `req.logDeliveryConfiguration?.accountId ?? ''` (no client fallback!), while the other three methods do `req.accountId ?? this.accountId ?? ''`. The create path silently differs — if `ClientOptions.accountId` is set but the caller forgets to put it inside `logDeliveryConfiguration`, the URL becomes `/api/2.0/accounts//log-delivery`. This is a correctness bug surfaced by a naming/structure inconsistency: the request DTO nests the account ID one level deeper than the others. -- **Category:** 6 (misleading), 16 (field placement contradicts wire-level convention). -- **Suggested fix:** Make `req.accountId ?? this.accountId ?? ''` consistent across all four methods (the create path should reach the top-level `accountId` and the client-options fallback, not just the nested wrapper field). - -### O33. JSDoc artefacts (`* *`, `` template) — `model.ts:6,20,31,53,64,107,121,138,166,227` -Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` on the first line (e.g., line 6: -``` - * * - * Log Delivery Status -``` -). Looks like the generator emits an empty paragraph break that renders as `*`. Also, `` appears in raw form throughout (e.g., `model.ts:84,127,142,186`); it should be a literal "Databricks" or substituted at generation time. Neither is a name issue per se but both pollute the docs. - -### O34. `host: string` vs `accountId: string | undefined` — initialisation imbalance — `client.ts:47-50,58-72` -The constructor throws if `options.host` is undefined (`client.ts:59-61`) but happily accepts `accountId: undefined` (line 63). Then `accountId` is later substituted into URL paths via `??` fallbacks. This is fine for `get`/`list`/`update` (which fall back to the client-level value) but problematic for `create` (which doesn't fall back — see O30). The naming of `accountId` as "optional" in the type lies about the runtime requirement. - ---- - -## Domain glossary - -- **`account`** — Databricks account; the top-level billing/identity boundary. Surfaces as `accountId: string` (uuid-shaped) in every interface and as `ClientOptions.accountId` (`client.ts:50,63`). -- **`workspace`** — A Databricks workspace under an account; `int64` ID on the wire (lossy as `number` in TS — see M15). -- **`credentials`** — Refers to `Credentials.Create` (cross-package) — a stored AWS IAM role with policy/trust relationship. The `credentialsId` field (`model.ts:87,189`) links a log delivery config to a previously-created credentials resource. -- **`storage configuration`** — Refers to `Storage.Create` (cross-package) — a stored S3 bucket descriptor. The `storageConfigurationId` field (`model.ts:89,191`) links a log delivery config to a bucket. -- **`log delivery configuration`** — The resource modelled by this package: a tuple of `(credentialsId, storageConfigurationId, logType, outputFormat, workspaceIdsFilter, status)` that tells Databricks to write certain logs to a bucket. -- **`log type`** — One of `BILLABLE_USAGE` / `AUDIT_LOGS` — what kind of logs to deliver. -- **`output format`** — `CSV` (for billable usage) or `JSON` (for audit logs). Always derivable from `log type`. -- **`delivery path prefix`** — S3 key prefix; defaults to bucket root. Restricted: no leading or trailing slash. -- **`delivery start time`** — `YYYY-MM` string; only applies to billable usage; lower bound is `2019-03`. -- **`config status`** — `ENABLED` / `DISABLED`. The config is never deleted — only disabled (see `client.ts:88,211`). -- **`attempt status`** — `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND`. Reflects the state of the most recent delivery attempt; surfaced as `LogDeliveryStatus.status` (i.e., `LogDeliveryConfiguration.logDeliveryStatus.status`). -- **`E2`** — Databricks deployment architecture (newer multi-region account model). Mentioned in `UpdateLogDeliveryConfigurationRequest.accountId` JSDoc (`model.ts:233`). -- **`int64`** — Wire-level 64-bit signed integer; appears in `workspaceIdsFilter` JSDoc but typed `number` in TS (M15). -- **`PATCH`** — HTTP verb used by the update endpoint (`client.ts:227`); the Go SDK calls this method `PatchStatus`, the TS port renames it `updateLogDeliveryConfiguration` (M9). - ---- - -## File coverage - -- `src/v1/model.ts` (404 lines): read fully. -- `src/v1/client.ts` (245 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (25 lines): read fully. - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md index 17508b76..24e3a475 100644 --- a/.agent/naming-audit/materializedfeatures.md +++ b/.agent/naming-audit/materializedfeatures.md @@ -1,714 +1,3 @@ -# Naming Audit: `materializedfeatures` (v1) +# Naming Audit: materializedfeatures -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `/home/parth.bansal/sdk-js/packages/materializedfeatures/` -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, -`src/v1/index.ts` -**Cross-package references:** `features/v1` (`Feature`, `MaterializedFeature`, -`MaterializedFeature_PipelineScheduleState`, `LineageContext`, `CreateFeatureRequest`, -etc.), `featurestore/v1` (`OnlineStore`, `PublishSpec`, online-store concepts), -`entitytagassignments/v1`, `tagassignments/v1`, `tagpolicies/v1` (other "tag" -domains in the SDK). -**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). - ---- - -## Inventory - -### Enums - -(None — package has no enum types.) - -### Interfaces / Types - -1. `CreateFeatureTagRequest` (model.ts:8) — fields: `tableName`, `featureName`, - `featureTag`. -2. `DeleteFeatureTagRequest` (model.ts:15) — fields: `tableName`, `featureName`, - `key`. -3. `FeatureLineage` (model.ts:24) — fields: `models`, `featureSpecs`, - `onlineFeatures`. -4. `FeatureLineage_FeatureSpec` (model.ts:34) — fields: `name`. -5. `FeatureLineage_Model` (model.ts:40) — fields: `name`, `version`. -6. `FeatureLineage_OnlineFeature` (model.ts:48) — fields: `featureName`, - `tableName`. -7. `FeatureTag` (model.ts:56) — fields: `key`, `value`. -8. `GetFeatureLineageRequest` (model.ts:61) — fields: `featureName`, `tableName`. -9. `GetFeatureTagRequest` (model.ts:69) — fields: `tableName`, `featureName`, - `key`. -10. `ListFeatureTagsRequest` (model.ts:76) — fields: `tableName`, `featureName`, - `pageToken`, `pageSize`. -11. `ListFeatureTagsResponse` (model.ts:86) — fields: `featureTags`, - `nextPageToken`. -12. `UpdateFeatureTagRequest` (model.ts:93) — fields: `tableName`, `featureName`, - `featureTag`, `updateMask`. - -### Zod schemas - -- `unmarshalFeatureLineageSchema` (model.ts:101) -- `unmarshalFeatureLineage_FeatureSpecSchema` (model.ts:120) -- `unmarshalFeatureLineage_ModelSchema` (model.ts:130) -- `unmarshalFeatureLineage_OnlineFeatureSchema` (model.ts:142) -- `unmarshalFeatureTagSchema` (model.ts:153) -- `unmarshalListFeatureTagsResponseSchema` (model.ts:163) -- `marshalFeatureTagSchema` (model.ts:174) - -### Field-mask helpers - -- `featureTagFieldMaskSchema` (model.ts:184, module-internal) -- `featureTagFieldMask()` (model.ts:189, public) - -### Client class - -- `Client` (client.ts:44) - - Methods: `createFeatureTag`, `deleteFeatureTag`, `getFeatureLineage`, - `getFeatureTag`, `listFeatureTags`, `listFeatureTagsIter`, - `updateFeatureTag`. - - Private fields: `host`, `httpClient`, `logger`, `userAgent`. - - Module constant: `PACKAGE_SEGMENT`. - -### Utils (`src/v1/utils.ts`) - -- Type: `HttpCallOptions`. -- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`. - -### `index.ts` - -Re-exports `Client`, every public interface (12 of them, including the four -`FeatureLineage_*` proto-style nested names). - ---- - -## Findings - -### 1. Package name `materializedfeatures` does not match its contents — category 6 (Misleading names) and category 1 (Vague/generic) - -**Symbol:** Package name `@databricks/sdk-materializedfeatures` and directory -`packages/materializedfeatures/`. - -**Issue:** The package is called *materialized features* but exports **zero** -types or operations related to materialized features. Its entire surface is: - -- `FeatureTag` CRUD on regular feature-table columns. -- `FeatureLineage` read of regular feature-table columns. - -The actual `MaterializedFeature` type, `BatchCreateMaterializedFeaturesRequest`, -`CreateMaterializedFeatureRequest`, `DeleteMaterializedFeatureRequest`, -`GetMaterializedFeatureRequest`, `ListMaterializedFeaturesRequest`, -`UpdateMaterializedFeatureRequest`, and `MaterializedFeature_PipelineScheduleState` -all live in the **`features` package** (`packages/features/src/v1/model.ts` -lines 47, 146, 151, 197, 233, 390, 500, 509, 517, 800). The URL paths in this -package's `client.ts` confirm the mismatch: every endpoint targets -`/api/2.0/feature-store/feature-tables/{tableName}/features/{featureName}/...` -— i.e. the *feature table* domain, not "materialized features." - -The package was presumably named after the upstream Go SDK service / proto -package, which itself appears mis-scoped. A TS consumer reading the import path - -```ts -import {FeatureTag} from '@databricks/sdk-materializedfeatures/v1'; -``` - -would reasonably expect a type *about materialized features*, not a tag on a -feature-table column. Symmetrically, `features/v1` contains the actual -materialized-feature types. - -**Suggested:** rename the package — based on what it actually contains: - -- `@databricks/sdk-featuretags` (covers `FeatureTag` and `FeatureLineage`) -- Or merge into `@databricks/sdk-features` (since both deal with the same - underlying `/feature-tables/{tableName}/features/{featureName}/` URL space). - -This is a wire-and-generator-level concern. **Flag SDK-wide / upstream Go.** -**P1 cross-package alignment.** - ---- - -### 2. `FeatureLineage_FeatureSpec` is a reference, not a spec — category 12 (Duplicate concepts) - -**Symbol:** `FeatureLineage_FeatureSpec` (model.ts:34); compare -`featurestore.PublishSpec` and `onlinetables.OnlineTableSpec`. - -**Issue:** Three different SDK packages export a `*Spec` type. In this package, -`FeatureLineage_FeatureSpec` is a *reference* (only field is `name`: "The full -name of the feature spec in Unity Catalog") — not a configuration object. In -`featurestore`, `PublishSpec` is a *configuration object* (multiple fields -describing how publishing should occur). The "Spec" suffix conflates two -different roles: - -- Reference / pointer: `FeatureLineage_FeatureSpec` (this package — single - `name` field). -- Configuration shape: `PublishSpec`, `OnlineTableSpec`. - -A TS reader importing both packages cannot tell from the type name which is -which. - -**Suggested:** clarify that the nested type is a reference (e.g. via JSDoc). -The `FeatureSpec` concept itself (an actual feature-spec configuration) lives -elsewhere in Databricks APIs; this is just a pointer to one. **Flag for -SDK-wide cleanup.** - ---- - -### 3. `FeatureLineage_Model` semantic conflict with `modelregistry`, `modelservingmanagement` — category 6 (Misleading names) and category 12 (Duplicate concepts) - -**Symbol:** `FeatureLineage_Model` (model.ts:40); doc: "List of Unity Catalog -models that were trained on this feature." - -**Issue:** "Model" is one of the most overloaded names in the SDK. The -`modelregistry`, `modelservingmanagement`, and `modelservingquery` packages -all have their own `Model`-shaped types. This local `Model` is yet another: -it is specifically a *reference* (Unity Catalog name + version) to a registered -model — not the model itself. - -The type has two fields: - -```ts -{ - name?: string | undefined; // The full name of the model in Unity Catalog. - version?: number | undefined; // The version of the model. -} -``` - -Naming-wise this is a *model reference*, not a model. - -**Suggested:** strengthen JSDoc to indicate this is a reference (the type -name itself follows the proto-nesting convention and is intentional). This -avoids importing `FeatureLineage_Model` next to `modelregistry.Model` and -confusing the two shapes. - ---- - -### 4. `FeatureLineage_OnlineFeature` is a reference, not a feature — category 6 (Misleading names) - -**Symbol:** `FeatureLineage_OnlineFeature` (model.ts:48); doc on the type-level -JSDoc on the parent says "List of online features that use this feature as -source." - -**Issue:** The type has two fields: - -```ts -{ - featureName?: string | undefined; // The name of the online feature (column name). - tableName?: string | undefined; // The full name of the online table in Unity Catalog. -} -``` - -This is *not* an online feature — it is a `(tableName, featureName)` pair -identifying one. Additionally, the doc-string contradiction: outer JSDoc says -"online features that use this feature as source," but the inner field doc -says "online feature (column name)." The type is a coordinate, not the -feature itself. - -**Suggested:** strengthen JSDoc to indicate this is a reference. Update the -inner field doc to match the outer JSDoc's intent. - ---- - -### 5. `FeatureLineage_OnlineFeature.tableName` is the *online table name*, generic-named — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) - -**Symbol:** `FeatureLineage_OnlineFeature.tableName` (model.ts:52). - -**Issue:** The JSDoc says "The full name of the online table in Unity Catalog." -The field name `tableName` does not specify *online* table — yet the type is -called `FeatureLineage_OnlineFeature` and the field carries an online-table -3-part name (per `featurestore.PublishTableResponse.onlineTableName` and -`onlinetables.OnlineTable.name`). - -Within the same package, `CreateFeatureTagRequest.tableName` (model.ts:9) is -the *source* feature table — a *different* kind of table. Two fields with the -identical name `tableName` carry semantically different values across types -in the same package. - -**Suggested:** `onlineTableName` to match `featurestore.PublishTableResponse.onlineTableName` -and the field's actual content. This is the single most concrete naming bug -in the file. **P1 fix candidate.** - ---- - -### 6. `FeatureTag` is too generic — category 1 (Vague/generic) and category 12 (Duplicate concepts) - -**Symbol:** `FeatureTag` (model.ts:56). JSDoc: "Represents a tag on a feature -in a feature table." - -**Issue:** "Tag" appears in at least four sibling SDK packages, each with -its own type: - -- `entitytagassignments/v1` — `EntityTagAssignment`. -- `tagassignments/v1` — `TagAssignment`. -- `tagpolicies/v1` — `TagPolicy`. -- `materializedfeatures/v1` — `FeatureTag`. - -Each "tag" has its own `{key, value}` shape. A TS reader cannot easily tell -that `FeatureTag` is just a `{key, value}` string-string pair (same shape as -the others, but a distinct type) because the SDK has chosen to keep them -separate. - -The type itself is a perfectly fine 2-field record. The problem is the *name* -plus the *duplicated shape* across packages: - -```ts -export interface FeatureTag { - key?: string | undefined; - value?: string | undefined; -} -``` - -**Suggested:** keep the name (it correctly identifies the tag's owner), but -**flag SDK-wide:** unify the shape (one `Tag` interface) or unify the type -name to `FeatureTag` and put it adjacent to `Feature` in `features/v1`. The -present split between this package and `features/v1` (where `Feature` lives) -duplicates the conceptual boundary. - ---- - -### 7. `FeatureTag.key` and `value` underspecified — category 19 (Underspecified IDs) and category 1 (Vague/generic) - -**Symbols:** `FeatureTag.key`, `FeatureTag.value` (model.ts:57–58). - -**Issue:** Neither field has JSDoc, neither field documents allowed character -sets, length limits, or whether `key` is a free-form string or constrained to -a grammar. `DeleteFeatureTagRequest.key` (model.ts:21) has minimal JSDoc ("The -key of the tag to delete.") but does not link to the grammar. Compare to -`OnlineStore.name` in `featurestore` which at least documents "unique -identifier" — also weak. - -**Suggested:** strengthen JSDoc to specify max length, valid character set, -case sensitivity. The naming itself (`key`/`value`) is the project-wide -convention for tag pairs — pass on name, fix the docs. - ---- - -### 8. `CreateFeatureTagRequest`, `GetFeatureTagRequest`, `ListFeatureTagsRequest`, `UpdateFeatureTagRequest` carry `tableName` and `featureName` undocumented in some — category 6 (Misleading names) and JSDoc drift - -**Symbols:** `CreateFeatureTagRequest.tableName` (model.ts:9), -`GetFeatureTagRequest.tableName` (model.ts:70), -`ListFeatureTagsRequest.tableName` (model.ts:77), -`UpdateFeatureTagRequest.tableName` (model.ts:94) and the parallel -`featureName` fields. - -**Issue:** Of seven types that carry `tableName` / `featureName`: - -- `DeleteFeatureTagRequest` has JSDoc: "The name of the feature table.", "The - name of the feature within the feature table." (model.ts:16–19). -- `GetFeatureLineageRequest` has JSDoc: "The name of the feature.", "The full - name of the feature table in Unity Catalog." (model.ts:62–65). -- `CreateFeatureTagRequest`, `GetFeatureTagRequest`, `ListFeatureTagsRequest`, - `UpdateFeatureTagRequest` have **no JSDoc** at all on those fields (model.ts:9, - 70, 77, 94). - -Within the same package, the *same field* (`tableName`) is documented as both -"The name of the feature table" (delete) and "The full name of the feature -table in Unity Catalog" (lineage get). These are different specificities. The -former does not say whether it is a UC three-part name; the latter does. - -**Suggested:** uniformly document `tableName` as "The full three-part (catalog, -schema, table) name of the feature table in Unity Catalog." and `featureName` -as "The name of the feature (column) within the feature table." Add JSDoc to -the four types currently missing it. **Pass on naming, flag JSDoc drift.** - ---- - -### 9. `ListFeatureTagsResponse` not `ListFeatureTagResponse` — category 9 (Singular/plural mismatch) and JSDoc drift - -**Symbol:** `ListFeatureTagsResponse` (model.ts:86). JSDoc reads "Response -message for ListFeatureTag." (singular!) while the type is plural. - -**Issue:** The JSDoc text uses the singular form ("ListFeatureTag") but the -type, the method, the request, and the response collection are all plural -(`ListFeatureTagsRequest`, `Client.listFeatureTags`, `featureTags: FeatureTag[]`). -Pass on naming, **fix the JSDoc** ("Response message for ListFeatureTags."). - ---- - -### 10. `UpdateFeatureTagRequest.featureTag.key` is also the path key — category 16 (Field contradicting type domain) and category 19 (Underspecified IDs) - -**Symbol:** `UpdateFeatureTagRequest.featureTag` (model.ts:96) + -`client.updateFeatureTag` URL builder (client.ts:220). - -**Issue:** The URL template uses `req.featureTag?.key`: - -```ts -const url = `${this.host}/api/2.0/feature-store/feature-tables/${req.tableName ?? ''}/features/${req.featureName ?? ''}/tags/${req.featureTag?.key ?? ''}`; -``` - -So the *body's* `featureTag.key` *also* identifies the resource. A user who -tries to rename a tag (e.g. change `key` from `env` to `environment`) will -PATCH `/tags/environment` — creating a new tag instead of renaming. The -request shape implicitly forbids changing `key`, but neither the type nor the -JSDoc says so. - -This contrasts with `DeleteFeatureTagRequest` (model.ts:21) which has an -explicit top-level `key`. The split — `key` is a top-level field for delete, -but nested under `featureTag.key` for update — is internally inconsistent. - -**Suggested:** add a top-level `key` field to `UpdateFeatureTagRequest` -(matching delete/get) and either: - -- Document that `featureTag.key` must equal `key`. -- Or remove `key` from the inner `featureTag` payload entirely (it is - redundant with the URL). - -The naming is fine; the structural choice is misleading. **Flag for upstream.** - ---- - -### 11. `GetFeatureLineageRequest` has fields ordered `featureName, tableName` — category 10 (Reserved-word collisions, by association) and JSDoc drift - -**Symbol:** `GetFeatureLineageRequest` (model.ts:61). - -**Issue:** Every other request type orders fields as `tableName, featureName` -(matching the URL: `/feature-tables/{tableName}/features/{featureName}/...`). -`GetFeatureLineageRequest` reverses to `featureName, tableName`. The URL still -goes through tables→features ordering (client.ts:119). This is internally -inconsistent. - -**Suggested:** swap field order to `tableName, featureName` for consistency. -This is a cosmetic but reader-facing inconsistency. - ---- - -### 12. `Client.getFeatureLineage` JSDoc reads "Get Feature Lineage." with title case — JSDoc drift and category 17 (Inconsistent action verbs) - -**Symbol:** `Client.getFeatureLineage` (client.ts:115). - -**Issue:** The JSDoc reads `/** Get Feature Lineage. */` in title case; -elsewhere in the same file: - -- `createFeatureTag` (client.ts:69): "Creates a FeatureTag." — sentence case - with proper noun. -- `deleteFeatureTag` (client.ts:95): "Deletes a FeatureTag." — same. -- `getFeatureTag` (client.ts:139): "Gets a FeatureTag." — same. -- `listFeatureTags` (client.ts:164): "Lists FeatureTags." — same. -- `updateFeatureTag` (client.ts:215): "Updates a FeatureTag." — same. -- `getFeatureLineage` (client.ts:114): "Get Feature Lineage." — **different - pattern** (title case, no plural verb, space between words). - -This is verb-tense / casing inconsistency within the same file. **Pass on -name, fix JSDoc** to read "Gets a FeatureLineage." or "Gets feature lineage." - ---- - -### 13. Method-name verbs `creates`/`deletes`/`gets`/`lists`/`updates` are consistent — category 17 (Inconsistent action verbs) — *pass* - -**Symbols:** `createFeatureTag`, `deleteFeatureTag`, `getFeatureLineage`, -`getFeatureTag`, `listFeatureTags`, `updateFeatureTag` (client.ts). - -The verb-prefix forms a clean CRUD-style vocabulary. No `fetch…`, `retrieve…`, -or `remove…` mixed in. **Pass.** - ---- - -### 14. `Client` class name — category 1 (Vague/generic) — *pass* - -Package convention. Every TS package exports a single `Client` class scoped to -its import path (e.g. `@databricks/sdk-materializedfeatures/v1`). **Pass.** - ---- - -### 15. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) - -**Symbol:** `PACKAGE_SEGMENT` (client.ts:39). - -**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true -constants (primitive literal values like `MAX_LEN = 10`). `PACKAGE_SEGMENT` is -a runtime object literal (`{ key, value }`) constructed from a JSON import. -Value is constant per-process, but the identifier shape violates the project -rule. Used in every package's `client.ts` — a project-wide convention. **Flag -for SDK-wide cleanup, do not fix in isolation.** - -**Suggested:** `packageSegment` or `clientPackageSegment`. - ---- - -### 16. `userAgent` / `httpClient` / `host` / `logger` — *pass* - -Standard private field names. Acronym handling matches the project rule. -**Pass.** - ---- - -### 17. `readAll` — *pass* - -Helper does what its name says (reads a `ReadableStream` to -completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** - ---- - -### 18. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* - -Verb-prefix matches the function's role (constructs an `HttpRequest` object). -Naming is fine. The file mixes `build…`, `execute…`, `marshal…`, `parse…`, -`readAll`, `flatten…` — six verbs for seven functions, but each is correct -for its purpose. **Pass.** - ---- - -### 19. `featureTagFieldMaskSchema` private but exported via `featureTagFieldMask()` — *pass* - -**Symbols:** `featureTagFieldMaskSchema` (model.ts:184, internal) and -`featureTagFieldMask()` (model.ts:189, public). Clean separation: schema is -private, helper is exported, helper name matches the Google AIP-134 -update-mask vocabulary. **Pass.** - ---- - -### 20. `UpdateFeatureTagRequest.updateMask` — category 7 (Overly verbose) — *pass* - -**Symbol:** `UpdateFeatureTagRequest.updateMask: FieldMask` -(model.ts:98). - -`updateMask` is the canonical Google AIP-134 name for partial-update masks; -the type `FieldMask` is from `@databricks/sdk-core/wkt`. The -naming is SDK-wide and idiomatic. **Pass.** - ---- - -### 21. Singular `FeatureTag` ⇔ plural `featureTags` — category 9 (Singular/plural mismatch) — *pass* - -`ListFeatureTagsResponse.featureTags: FeatureTag[]` (model.ts:87) is the -canonical pattern. **Pass.** - ---- - -### 22. `FeatureLineage.models` field name does not describe content — category 6 (Misleading names) and category 15 (Generic field names losing meaning) - -**Symbol:** `FeatureLineage.models?: FeatureLineage_Model[]` (model.ts:26). - -**Issue:** The field is called `models` but contains `FeatureLineage_Model[]` -— each of which is a *reference* to a registered model (name + version), not -the model itself. A reader who sees `lineage.models` reasonably expects -model objects (with fields like `creator`, `description`, etc.). They actually -get bare `{name, version}` pairs. - -**Suggested:** rename to `modelRefs`, `trainedModels`, or `modelReferences`. -Signals that these are references rather than full model records. - ---- - -### 23. `FeatureLineage.featureSpecs` vs `FeatureLineage.onlineFeatures` plural-singular mismatch — category 9 (Singular/plural mismatch) — *partial pass* - -**Symbols:** `FeatureLineage.featureSpecs`, `FeatureLineage.onlineFeatures` -(model.ts:28, 30). - -Both are arrays — plural form is consistent. No issue. **Pass.** - ---- - -### 24. `LineageContext` from `features` package vs `FeatureLineage` from this package — category 12 (Duplicate concepts) - -**Symbol:** `FeatureLineage` (model.ts:24); compare -`features.LineageContext` (`packages/features/src/v1/model.ts:465`). - -**Issue:** Two "lineage"-flavoured types live in two packages: - -- `features.LineageContext`: "Lineage context information for tracking where - an API was invoked. This will allow us to track lineage…" -- `materializedfeatures.FeatureLineage`: per JSDoc-less type, contains models - trained on a feature, feature specs containing the feature, and online - features using the feature as source. - -These are *distinct* concepts ("where this API call came from" vs. "what is -downstream of this feature"). The package split is poor — both concepts -ought to live with `Feature` in one place. A reader importing both packages -sees two different "lineage" shapes and must reason about which is which. - -**Suggested cross-package:** rename `materializedfeatures.FeatureLineage` → -`FeatureUsage` or `FeatureDependents` (it lists *what uses* the feature). The -"lineage" word is being used in two different senses: provenance (Context) -vs. dependents (Lineage). **Flag for upstream Go SDK / generator.** - ---- - -### 25. `GetFeatureLineageRequest` is `GetFeature…`, returns `FeatureLineage` — *pass* - -**Symbol:** `Client.getFeatureLineage` (client.ts:115), return type -`FeatureLineage` (model.ts:24). - -The method name uses verb `get` consistently; the return type name is the -resource. No issue at the method-name layer. (Underlying naming smells of -`FeatureLineage` itself are covered in findings 22, 24.) **Pass.** - ---- - -### 26. `BatchCreateMaterializedFeatures*` types live in `features` not this package — category 12 (Duplicate concepts) — cross-package - -**Symbols (cross-package):** `BatchCreateMaterializedFeaturesRequest`, -`BatchCreateMaterializedFeaturesResponse` live in `features/v1/model.ts:146, -151`. This `materializedfeatures` package has *no* materialized-feature types. - -**Issue:** Compound finding 1. The naming bug is that this package's *name* -implies it owns materialized features, while the actual types live in -`features`. If the rename in finding 1 is rejected, the alternative is to -*move* the materialized-feature types here. **Flag for SDK-wide upstream -coordination.** - ---- - -### 27. `index.ts:5` empty re-export — *pass with note* - -**Symbol:** `export {} from './model';` (index.ts:5). - -This is a generator-emitted no-op (re-export *nothing* from the module). It is -not a naming finding, but it is a code-smell artefact of the generator. **Pass -on naming**, flag for generator cleanup. - ---- - -### 28. URL path constants spread inline in `Client` methods — code-quality (out of scope) — *pass* - -**Symbols:** every method constructs a URL via template literal embedding -`req.tableName ?? ''` and `req.featureName ?? ''` (client.ts:74, 100, 119, -144, 169, 220). - -Naming is fine (no constants to flag); the duplication is a code-quality -concern, not naming. **Pass.** - ---- - -### 29. `req`/`resp`/`pageReq` Go-style short variable names — category 14 (Go/Java-style names) - -**Symbols:** local variables `req` (every method parameter), `resp` (every -method local), `pageReq` (client.ts:202). - -**Issue:** TS ecosystem typically prefers full words: `request`, `response`, -`pageRequest`. Compare with Node/Express conventions. The shortened forms are -Go-style. However, `req`/`res` is also common in TS Express/Node code, so the -convention is mixed. **Pass with note — flag for SDK-wide style decision.** - ---- - -### 30. Generator-comment "DO NOT EDIT." header — *pass* - -Every file begins with `// Code generated from API definition by Databricks -SDK Generator. DO NOT EDIT.` Naming-irrelevant, but informs the scope of any -suggested fix (all naming changes must be implemented at the generator, -not in the file). **Pass.** - ---- - -## Cross-package notes (per audit instructions) - -### Package-name mis-scope (`materializedfeatures` ↔ `features`) - -The most serious finding in this audit. The package called `materializedfeatures` -contains *zero* materialized-feature types; the package called `features` -contains the materialized-feature types (`MaterializedFeature`, -`BatchCreateMaterializedFeaturesRequest`, etc., per `features/v1/model.ts:47, -146, 197, 517`). A reasonable fix: - -- Rename the package directory and `package.json` `name` field to - `@databricks/sdk-featuretags`. -- Or rename to `@databricks/sdk-featuretagsandlineage` (verbose) or move the - contents into `@databricks/sdk-features`. - -The `materializedfeatures` directory exists in `packages/` (per the directory -listing) and the matching markdown doc `materializedfeatures.md` is also -present at `packages/materializedfeatures.md`. Both would need to move. - -**P1 cross-package alignment.** - ---- - -### `tableName` overload across packages - -`materializedfeatures.{Create,Delete,Get,List,Update}FeatureTagRequest.tableName` -is the source feature-table name. `featurestore.PublishTableRequest.sourceTableName` -is also a source table name. `FeatureLineage_OnlineFeature.tableName` is an -*online* table name. `featurestore.DeleteOnlineTableRequest.onlineTableName` -is also an online table name. Four kinds of `tableName` across two packages, -each disambiguated by neighbouring fields and JSDoc — but not by the name -itself. - -**Recommendation:** standardise: - -- Source feature-table name: `featureTableName` (more specific than just - `tableName`). -- Online table name: `onlineTableName` (already in use in `featurestore`). - -The package-local `tableName` (used here) is fine *inside* the request types -because the URL grammar disambiguates, but `FeatureLineage_OnlineFeature.tableName` -should definitely be `onlineTableName` (finding 5). - -**Flag for SDK-wide policy.** - ---- - -### `Tag` concept overlap across packages - -| Package | Type name | Shape | Use | -|---------------------------|------------------------|-------------|-----------------------------| -| `materializedfeatures` | `FeatureTag` | `{key,value}` | Tag on a feature column. | -| `entitytagassignments` | `EntityTagAssignment` | (TBD) | Tag-to-entity assignment. | -| `tagassignments` | `TagAssignment` | (TBD) | Tag-to-resource assignment. | -| `tagpolicies` | `TagPolicy` | (TBD) | Tag policy rules. | - -Four distinct "tag" types in four packages. Each likely justified by its -ownership and lifecycle (a `FeatureTag` is owned by a feature; a -`TagAssignment` connects a tag to a resource; a `TagPolicy` defines tag -governance). But naming-wise the boundary is murky: a reader of -`@databricks/sdk-materializedfeatures/v1` sees `FeatureTag` and may not -realise `TagAssignment` exists separately. - -**Cross-SDK recommendation:** document the relationship in package JSDoc -(`index.ts` should reference the related "tag" packages). **Flag for upstream -Go SDK / docs.** - ---- - -### `FeatureLineage` vs `LineageContext` vs `externallineage` - -Three lineage-related types/packages exist: - -- `materializedfeatures.FeatureLineage` — downstream dependents of a feature. -- `features.LineageContext` — provenance/context for an API call. -- `externallineage` (entire package) — lineage outside Databricks. - -"Lineage" is being used in three different senses. **Flag for upstream -documentation / generator naming**; the SDK exposes consumers to three -distinct lineage concepts with no naming convention to distinguish them. - ---- - -### Field-naming hygiene relative to `features.Feature` - -`features.Feature` (model.ts:279) has its own `lineageContext` field -(model.ts:310), not the `FeatureLineage` defined here. The two "feature -lineage" concepts coexist: - -- `features.Feature.lineageContext: LineageContext` — internal SDK use, set - by the SDK, not the user (per JSDoc: "Users should not manually set this - field…"). -- `materializedfeatures.FeatureLineage` — user-facing read-only object - describing what depends on a feature. - -The two are unrelated, but the words overlap. **Flag for SDK-wide naming -guidance.** - ---- - -## Summary (counts) - -- **Critical / cross-package consistency:** 2 findings (#1 package name - mis-scope `materializedfeatures` does not contain materialized features; - #5 `FeatureLineage_OnlineFeature.tableName` should be `onlineTableName`). -- **High (style guide violations):** 1 finding (#15 `PACKAGE_SEGMENT` - casing). -- **Medium (naming clarity, JSDoc drift):** 11 findings (#2, #3, #4, #6, - #7, #8, #9, #10, #11, #12, #22, #24). -- **Low / project-wide convention notes (generator-level):** 2 findings (#26, - #29). -- **Pass / acceptable as-is:** 11 findings (#13, #14, #16, #17, #18, #19, - #20, #21, #23, #25, #27, #28, #30 — many partial passes with notes). - -**Total flagged findings: 30** distinct items. The dominant themes are -**package mis-naming** (the package does not contain what its name advertises) -and **cross-package mis-allocation** (materialized-feature types live in the -`features` package, not here). Many issues are generator-emitted boilerplate -inherited from the Go SDK; the cleanest local fixes are findings 1 (package -rename), 5 (`onlineTableName` field), 8 (JSDoc on `tableName`/`featureName`), -9 (JSDoc plural form), 10 (top-level `key` for update), 11 (field order in -`GetFeatureLineageRequest`), and 12 (`getFeatureLineage` JSDoc casing). +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md index 598ebf69..f6e7a155 100644 --- a/.agent/naming-audit/modelservingdebug.md +++ b/.agent/naming-audit/modelservingdebug.md @@ -1,316 +1,3 @@ # Naming Audit: modelservingdebug -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/modelservingdebug/` (merged into `packages/modelserving/src/v1/` on 2026-05-20) -**Package name:** `@databricks/sdk-modelservingdebug` (folded into `@databricks/sdk-modelserving`) -**Versions audited:** v1 -**Inferred domain:** Diagnostic / troubleshooting endpoints carved out of the Model Serving API. Three HTTP GETs hanging off `/api/2.0/serving-endpoints/{name}`: `GET /metrics` returns a Prometheus/OpenMetrics text blob (streamed body), `GET /served-models/{servedModelName}/logs` returns the most recent server stdout lines, and `GET /served-models/{servedModelName}/build-logs` returns the served-entity environment build logs. -**Total weird names flagged:** 17 - -## Summary -| Severity | Count | -| --- | --- | -| High | 5 | -| Medium | 6 | -| Low | 6 | -| Observation | 0 | - -## Inventory - -### Package identity -The standalone `modelservingdebug` package no longer exists. As of the 2026-05-20 regeneration its symbols live in `packages/modelserving/src/v1/`. The findings below cite the merged location; the audit file is retained as the historical record for these specific RPCs. - -### Interfaces (`packages/modelserving/src/v1/model.ts`) -- `ExportMetricsResponse` (line 434) -- `GetExportEndpointMetricsRequest` (line 540) -- `GetServedModelBuildLogsRequest` (line 560) -- `GetServedModelBuildLogsRequest_Response` (line 568) -- `GetServedModelLogsRequest` (line 573) -- `GetServedModelLogsRequest_Response` (line 581) - -### Schemas (`packages/modelserving/src/v1/model.ts`) -- `unmarshalGetServedModelBuildLogsRequest_ResponseSchema` (line 1455) -- `unmarshalGetServedModelLogsRequest_ResponseSchema` (line 1465) - -### Enums (`packages/modelserving/src/v1/model.ts`) -None. - -### Client methods (`packages/modelserving/src/v1/client.ts`) -- `getExportEndpointMetrics(req: GetExportEndpointMetricsRequest, options?): Promise` (line 216) -- `getServedModelBuildLogs(req: GetServedModelBuildLogsRequest, options?): Promise` (line 295) -- `getServedModelLogs(req: GetServedModelLogsRequest, options?): Promise` (line 323) - -## High severity - -### 1. `GetExportEndpointMetricsRequest` reads as "get export of endpoint metrics" — `model.ts:540`, `client.ts:216` -- **Why weird:** The grammar is broken. The expected reading is - *"export endpoint metrics" → returns metrics in export format*, but - the word order `Get + Export + Endpoint + Metrics + Request` parses as - five random nouns. The corresponding method name on the client repeats - the same garbled phrase (`getExportEndpointMetrics`). The doc string - on `client.ts:215` confirms the intent: "Retrieves the metrics - associated with the provided serving endpoint in either Prometheus - or OpenMetrics exposition format". The natural English noun phrase - is "export endpoint metrics" → action "export the endpoint's metrics" - → method `exportEndpointMetrics` (verb-first, no `Get`). -- **Category:** 6 (misleading), 7 (overly verbose), 17 (inconsistent - verb — every other method is `getX`, this one is `getExportX`). -- **Suggested name:** Drop `Get` and `Export` from the request, keep - one or the other: - - Method: `exportEndpointMetrics(req: ExportEndpointMetricsRequest)` - returning `EndpointMetrics` (or the existing `ExportMetricsResponse`). - - Or: `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning - `EndpointMetrics`. The "export" framing is a wire-protocol detail - (Prometheus format) that does not belong in the method name. -- **Rationale:** Compare with sibling endpoints in the same merged - package: `getInferenceEndpoint`, `getInferenceEndpointSchema`, - `patchInferenceEndpointTags`. None of them prefix the noun with the - output format. - -### 2. `ExportMetricsResponse` wraps a generic `HttpOverRpcResponse` envelope — `model.ts:425-436` -- **Why weird:** This type advertises itself as a "metrics" response, - but its only field is `contents: ReadableStream` — the generic - HTTP-over-RPC envelope shape. A reader expecting structured metrics - fields gets an opaque stream, and the type name does not warn them. -- **Category:** 6 (misleading — name says "metrics", shape says - "raw body"), 1 (vague — `ExportMetricsResponse` could mean any - metrics export call). -- **Suggested name:** `EndpointMetrics` with a single field `body: - ReadableStream` (or `text: string` after consumption). Document - that the body is Prometheus/OpenMetrics text. -- **Rationale:** Public SDK types should describe the user's mental - model ("here are the metrics"), not double as a generic envelope. - -### 3. `name` field on every request — `model.ts:542,562,575` -- **Why weird:** All three request types have `name?: string` and the - JSDoc has to spell out "The name of the serving endpoint" each time. - Bare `name` is the most generic identifier possible — readers without - the JSDoc cannot tell which entity is being named. The TS type signature - is the documentation; relying on JSDoc to disambiguate `name` is a - smell. Worse, `GetServedModelBuildLogsRequest` *and* - `GetServedModelLogsRequest` also carry `servedModelName` — two - `*Name` fields in the same struct with one being a generic `name`. -- **Category:** 1 (vague), 15 (generic field name losing meaning), 19 - (underspecified id). -- **Suggested name:** `endpointName`. Wire stays `name` (the server - expects it). The method URL templates (`client.ts:220,299,327`) read - `/api/2.0/serving-endpoints/${req.name ?? ''}` which already proves - `name` is the *endpoint name*. -- **Rationale:** Renaming to `endpointName` puts the intent in the - type signature, eliminates the need for JSDoc-as-disambiguator, and - makes the pairing with `servedModelName` parallel (`endpointName` + - `servedModelName`). - -### 4. `name ?? ''` empty-string fallback when the field is "required" — `client.ts:220,299,327` -- **Why weird:** The JSDoc on each request says "This field is - required" yet the type marks `name?: string | undefined` *optional* - and the URL is built with `${req.name ?? ''}` — meaning if the caller - forgets to set it, the SDK silently emits a URL like - `/api/2.0/serving-endpoints//metrics` (note the double slash) which - will 404 server-side. The contradiction between "required per JSDoc" - and "optional per TS type" is a naming/typing inconsistency that - bites consumers. -- **Category:** 6 (misleading — JSDoc contradicts type), 16 (field - contradicting type domain). -- **Suggested name:** Mark `name` as required (`endpointName: string`, - no `?`). Remove the `?? ''` fallback so a missing value throws - earlier. Same applies to `servedModelName`. -- **Rationale:** Optional + "required" JSDoc + empty-string fallback - is a triple-violation. Cf. AIP-122 - (https://google.aip.dev/122) which mandates path parameters be - required. - -### 5. `GetServedModelLogsRequest_Response.logs: string` is a single blob — `model.ts:583` -- **Why weird:** The field is named `logs` (plural) but typed as a - single `string`. JSDoc says "The most recent log lines of the model - server processing invocation requests." So it's many log *lines* - concatenated into one string. The plural/singular conflict with the - type (`string`, not `string[]`) is a category-9 finding. A user - doing `for (const line of response.logs)` will iterate characters, - not lines — silent footgun. -- **Category:** 9 (singular/plural mismatch). -- **Suggested name:** Either `logsText: string` (singular field with - type-disambiguating suffix) or `logs: string[]` (split the lines - server-side). The current shape forces every consumer to write - `response.logs.split('\n')`. -- **Rationale:** Same issue applies to `GetServedModelBuildLogsRequest_Response.logs` - (model.ts:570). When the server can't decide, the SDK should pick a - side and stick with it. - -## Medium severity - -### 6. `servedModelName` doc echoes the field name three times — `model.ts:563-564,576-577` -- **Why weird:** JSDoc on `GetServedModelBuildLogsRequest.servedModelName` - reads "The name of the served model that build logs will be - retrieved for. This field is required." The field name already - contains "servedModel" + "Name" + the type signature already - conveys "this is a name". Pure echo. Same for the logs version. -- **Category:** 7 (overly verbose), 20 (type-suffix tautology — - `name: string` reading as "name of a name"). Plus the bigger - issue: the JSDoc text doesn't tell the user *what format* the - served model name takes (alphanumeric? UUID? UC three-part?). -- **Suggested name:** No name rename; rewrite JSDoc to give the - *format* (e.g., "Slug-style identifier of the served model, e.g. - `myllm-v2`"). If the field were renamed to just `servedModel`, - the JSDoc could disappear entirely. -- **Rationale:** A naming audit should flag the *interaction* of - identifier + JSDoc; the doc carrying no information beyond what - the name says is a footgun for consumers. - -### 7. `GetServedModelBuildLogsRequest.name` clashes with `GetServedModelBuildLogsRequest.servedModelName` — `model.ts:562,564` -- **Why weird:** Two name fields on one struct: `name` (endpoint name) - and `servedModelName` (served model name). The bare `name` looks like - *the* name of the request entity (which a reader would assume is the - served model, since the type is `GetServedModelBuildLogsRequest`). - Wrong: it's the *parent* endpoint. The pairing breaks the principle - of least surprise. -- **Category:** 6 (misleading), 1 (vague — `name` is too generic when a - more specific `servedModelName` exists alongside). -- **Suggested name:** `endpointName` + `servedModelName` together. -- **Rationale:** When two `*Name` fields exist on one struct, neither - should be bare `name`. - -### 8. `ExportMetricsResponse.contents` vs convention `body` — `model.ts:435` -- **Why weird:** The only field is `contents?: ReadableStream | undefined`. - Web Fetch standard - (https://fetch.spec.whatwg.org/#bodyinit-unions) and the SDK's own - `HttpResponse` use `body` for the same concept. "Contents" is rare - in this domain — used by file APIs (file contents) but not HTTP - responses. -- **Category:** 17 (inconsistent naming — `body` everywhere else in - the SDK), 1 (vague — "contents" of what?). -- **Suggested name:** `body: ReadableStream` to match the Fetch - convention and `HttpResponse.body` (utils.ts:81). -- **Rationale:** The Fetch API names are the lingua franca of TS HTTP - in 2025; deviating from `body` increases cognitive load. - -### 9. `getExportEndpointMetrics` returns `ExportMetricsResponse` (no `Endpoint`) — `client.ts:216-219` -- **Why weird:** The method name says `EndpointMetrics`, the response - type says `ExportMetricsResponse` (no `Endpoint`). Inconsistent - qualifier between method and return type. A reader greping for - `EndpointMetrics` won't find the response type. -- **Category:** 17 (inconsistent — method qualifier dropped from - response type), 1 (vague — `ExportMetricsResponse` could be metrics - for anything). -- **Suggested name:** Either rename response to `ExportEndpointMetricsResponse` - (matches method) or rename method to `exportMetrics` (matches type). - Best: kill the `Export` framing (see #1) and pair `getEndpointMetrics()` - → `EndpointMetrics`. -- **Rationale:** Symmetry between method and return type aids - IDE autocomplete and grep-ability. - -### 10. `Get*` prefix on three of three methods — `client.ts:216,295,323` -- **Why weird:** Every method here is a GET. The `Get*` verb prefix on - TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` - or `metrics()` is more idiomatic for read operations - (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, - it's typically on synchronous accessors. -- **Category:** 14 (Go/Java-style names). -- **Suggested name:** Verb-first for actions: `exportMetrics(req)`, - `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or - property-style if the request is trivial: `endpointMetrics(name)`, - `servedModelLogs(name, servedModelName)`. The SDK is consistent on - `get*` across other packages, so this is a *category* issue, not a - local one — flag for project-wide review. -- **Rationale:** Google TS Style Guide § Names of functions - (https://google.github.io/styleguide/tsguide.html#methods) prefers - imperative verbs, but does not mandate `get*` for retrievals. - -### 11. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `client.ts:295,323` -- **Why weird:** Two methods, both retrieve logs, distinguished only - by what *kind* of logs (runtime "service" logs vs container "build" - logs). The build/service axis is a sub-attribute of "logs", not a - separate concept. A more honest API would be one method with a - `kind: 'build' | 'service'` parameter; the SDK could collapse to - `getServedModelLogs(req: {endpointName, servedModelName, kind})`. -- **Category:** 12 (duplicate concept), 6 (misleading — `getServedModelLogs` - alone doesn't tell you it returns *service* (not build) logs). -- **Suggested name:** Rename the existing `getServedModelLogs` to - `getServedModelServiceLogs` (parallel with `getServedModelBuildLogs`). - Or collapse into one method per above. -- **Rationale:** When two siblings differ by a hidden attribute, name - *both* with that attribute. Today `getServedModelLogs` is the default - and `getServedModelBuildLogs` is the special case; the API doesn't - advertise the asymmetry. - -## Low severity - -### 12. `PACKAGE_SEGMENT` const is unsized — `client.ts:75-78` -- **Why weird:** SCREAMING_SNAKE_CASE in TS is a Go/Python carryover. - Google TS Style Guide - (https://google.github.io/styleguide/tsguide.html#identifiers) - permits SCREAMING_SNAKE only for "module-local true constants that - are deeply immutable". This is module-local, but a richer term - like `packageUserAgent` or `userAgentSegment` carries more meaning. -- **Category:** 14 (Go/Python-style name in TS), 1 (vague — - "segment" of what?). -- **Suggested name:** `userAgentSegment` (camelCase). -- **Rationale:** SDK precedent: most other packages have the same - `PACKAGE_SEGMENT` const, so this is a cross-package finding — - fix at the generator. - -### 13. `Call` type aliased to `Promise` in `utils.ts` import — `utils.ts:3` -- **Why weird:** `Call` is one of the most generic names imaginable. - Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` - with no qualifier. Inside the client `const call: Call = async ...` - reads like "a phone call" or "function call". The actual semantic - is "a retriable RPC closure". -- **Category:** 1 (vague). -- **Suggested name:** `RetriableRpc` or `RpcClosure`. Cross-package - decision because `Call` is defined in `@databricks/sdk-core/api`. -- **Rationale:** Type names exported from a "core" package set the - vocabulary for every consumer; bare `Call` is the kind of name - that survives review only because nobody wants to argue with the - framework. - -### 14. `Options` type aliased to internal options shape — `utils.ts:3,30` -- **Why weird:** Same as #13 but for `Options`. `Options` is generic - to the point of meaninglessness. The translation step in - `executeCall` exists *because* the public `CallOptions` and the - internal `Options` are two different "options" types that happen - to have similar fields. -- **Category:** 1 (vague), 12 (duplicate concept — `Options` vs - `CallOptions`). -- **Suggested name:** `ExecuteCallInternalOptions` (verbose but - honest) or `RetrierOptions`. Cross-package decision. -- **Rationale:** Two adjacent "Options" types in 35 lines of code is - the classic accidental-collision pattern. - -### 15. `userAgent` is built once in the constructor and never refreshed — `client.ts:89,103` -- **Why weird:** Not a name bug per se, but the field name `userAgent` - suggests a dynamic property, while the construction reads - `this.userAgent = info.toString();` once at construction time. If - the credentials are mutated post-construction (rare but possible), - the UA goes stale. -- **Category:** Observation / 6 (mildly misleading). -- **Suggested name:** No rename. Document the construction-time - freeze in the JSDoc on the field. -- **Rationale:** Worth a comment; not a rename target. - -### 16. `host` is normalised by trailing-slash strip — `client.ts:95` -- **Why weird:** `this.host = options.host.replace(/\/$/, '');` - silently rewrites the input. The field name `host` doesn't tell - the consumer "we normalise this to no trailing slash". If a debug - log later prints `client.host`, it won't match what was passed in. -- **Category:** Observation, 6 (mildly misleading). -- **Suggested name:** No rename. Add a JSDoc note. -- **Rationale:** Same pattern as #15; cross-package. - -### 17. `info` local var in the constructor — `client.ts:97,99,103` -- **Why weird:** `let info = createDefault().with(PACKAGE_SEGMENT);` - then more `info = info.with(...)` chains. The name `info` is - category-5 (cryptic abbreviation of "information") and category-1 - (vague). A reader who hasn't looked at `createDefault()` does not - know `info` is a `ClientInfo` (or whatever the type is — it's - inferred). -- **Category:** 1, 5. -- **Suggested name:** `clientInfo` (matches the imported - `createDefault` factory and the SDK convention). -- **Rationale:** Local-scope, low-impact rename. Cross-package. - -## Observation - -_None._ +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md index befb0973..5bf37798 100644 --- a/.agent/naming-audit/modelservingmanagement.md +++ b/.agent/naming-audit/modelservingmanagement.md @@ -1,354 +1,3 @@ # Naming Audit: modelservingmanagement -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/modelserving/src/v1/` (renamed from `modelservingmanagement` in regeneration) -**Versions audited:** v1 -**Inferred domain:** "Serving endpoint" management — CRUD over inference (model-serving) endpoints, plus a parallel "PT" (provisioned-throughput) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Sibling packages: `modelservingdebug` (logs/metrics), `modelservingquery` (inference). Three packages share the noun "serving endpoint" with no cross-package alignment of how the noun is rendered (this package: `InferenceEndpoint`; debug: `Endpoint`; query: `Endpoint`). -**Total weird names flagged:** 43 - -## Summary -| Severity | Count | -| --- | --- | -| High | 11 | -| Medium | 17 | -| Low | 11 | -| Observation | 4 | - -## High severity - -### 1. Package noun mismatch: `modelservingmanagement` vs `InferenceEndpoint` vs `ServingEndpoint*` vs `serving-endpoints` URL — entire package -- **Why weird:** The package name says *model-serving management*, the URL path says `/api/2.0/serving-endpoints`, the docs (every JSDoc) say "serving endpoint", but every TypeScript type is named `InferenceEndpoint*` (`InferenceEndpoint`, `InferenceEndpointDetailed`, `InferenceEndpointState`, `CreateInferenceEndpoint`, `DeleteInferenceEndpoint`, etc.). Meanwhile the *permission* enum is `ServingEndpointDetailedPermissionLevel` (model.ts:22) — the only top-level identifier in the file that uses the actual product noun. So the package has *three* names for the same thing: "serving endpoint" (product/doc/URL), "inference endpoint" (TS types), and "serving endpoint detailed" (permission enum). Users importing from this package will see `InferenceEndpoint`, look up docs that say "serving endpoint", and hit URLs labelled `serving-endpoints`. This is the central naming bug of the package. -- **Category:** 6 (misleading), 12 (duplicate concept), 17 (inconsistent terminology). -- **Suggested name:** Pick one product noun. The wire and docs say `serving endpoint`; the Go SDK exposes `ServingEndpoint`/`ServingEndpointsAPI`. Rename all `InferenceEndpoint*` to `ServingEndpoint*` (or vice versa across the docs and URL). The mixed state cannot stand. -- **Rationale:** Cross-language consistency: every Databricks SDK (Python, Java, Go) calls these `ServingEndpoint`. TS being the lone outlier on `InferenceEndpoint` will confuse anyone reading SDK docs side-by-side. - -### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:1004` -- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1007) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1009) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. -- **Category:** 6 (misleading), 15 (generic field name vs specific type name). -- **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. For users, `servedEntities: ServedEntity[]` reads correctly. -- **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. - -### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:376-390, 392-408, 410-415, 856-874, 950-966` -- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]` (the request DTOs now carry a `Request` suffix — e.g. `PutInferenceEndpointConfigRequest` — but the duplication is unchanged). The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. -- **Category:** 12 (duplicate concept), 6 (misleading — deprecated not marked). -- **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely. -- **Rationale:** Five types times two fields equals ten redundant deprecation lookalikes; every one of them is a footgun. - -### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins — `src/v1/model.ts:1032, 1033, 1057-1067` -- **Why weird:** `ServedModel` has both `entityName`/`entityVersion` and `modelName`/`modelVersion`. The JSDoc on `ServedModelLite.modelName` (line 1059) says "Only one of model_name and entity_name should be populated"; same for `modelVersion`/`entityVersion`. So `ServedModel.modelName`/`modelVersion` are legacy fields that mirror `entityName`/`entityVersion`. They are completely undocumented inside `ServedModel` (lines 1032-1033 are bare fields with no comment), so a TS user has no way to know they are deprecated. This is *the same* duplication as #3, but at the field level. -- **Category:** 12 (duplicate concept), 6 (misleading), 19 (underspecified — bare fields with no docs). -- **Suggested name:** Mark `modelName` / `modelVersion` as `@deprecated`. The JSDoc on `ServedModelLite` should be promoted to a real type-level note. Wire keys remain. -- **Rationale:** Public surface area duplicating itself is *the* common source of integration bugs. - -### 5. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` -- **Why weird:** This is the *only* type named `ServingEndpoint*`. Every other type in the file uses `InferenceEndpoint*`. Either this enum should be `InferenceEndpointPermissionLevel` (to match the rest of the package), or the rest of the package should be `ServingEndpoint*` (to match the product and wire). The `Detailed` infix is also suspect — the enum lives on `InferenceEndpointDetailed.permissionLevel`, so the type-name says "this enum belongs to InferenceEndpointDetailed", but a `permissionLevel` of `CAN_VIEW` is *not* detailed any differently from a non-detailed view; the enum applies to the resource, not to the response shape. So `Detailed` is leaking the response-DTO name into the enum name. -- **Category:** 17 (inconsistent terminology), 7 (overly verbose). -- **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. -- **Rationale:** Enum names that include the response-DTO shape (`Detailed`) tangle the message identity into the type identity. In TS, the enum represents a concept, not the message it appears in. - -### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:587` -- **Why weird:** `httpRequest` on a `Client` for *model-serving management* is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. -- **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). -- **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. -- **Rationale:** A method called `httpRequest` on a `ServingEndpointsClient` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. - -### 7. `ExternalFunctionRequest` doc says "Simple Proto message for testing" — `src/v1/model.ts:438` -- **Why weird:** Public type carries the JSDoc comment "Simple Proto message for testing". Either the type is for testing (in which case it should not be exported) or it is production (in which case the doc lies). Given it is wired to a real REST URL and exported via `index.ts`, the doc is a lie. -- **Category:** 6 (misleading — public doc text contradicts the exported reality). -- **Suggested name:** Fix the JSDoc: "Request for `Client.httpRequest`: invoke an external service through a UC Connection." Keep type name `ExternalFunctionRequest` for now (paired with the rename in #6). -- **Rationale:** Doc bugs on exported identifiers are as serious as the identifier itself. - -### 8. Acronym casing storm: `AiGateway` / `AiGuardrails` / `OpenAi` / `PaLm` / `Ai21Labs` / `Pii` / `Pt` / `Uc` / `Llm` / `Ai` everywhere — across the file -- **Why weird:** This single file mixes nearly every imaginable acronym-casing scheme: - - `AiGateway`, `AiGatewayConfig`, `AiGatewayRateLimit`, `AiGuardrails`, `AiGuardrailParameters` — title-cased `Ai`. - - `OpenAiConfig`, `OpenAi` — title-cased `Ai`, lowercase initial. - - `GoogleCloudVertexAiConfig`, `googleCloudVertexAiConfig` — same. - - `PaLmConfig`, `palmConfig` — `PaLm` (the *only* mixed-internal-caps spelling). The product is "PaLM", which is itself a stylized "Pathways Language Model"; the SDK could have rendered it `Palm`, `PaLM`, or `PaLm`. It chose `PaLm`, the worst of three. - - `Ai21Labs`, `Ai21LabsConfig` — the product is "AI21 Labs"; rendered as `Ai21Labs` (lower-case `21`, lower-case `i` mid-word). - - `PiiSettings` — `Pii` is "PII" (personally identifiable information); rendered title-case. - - `Pt`, `PtEndpoint`, `PtServedModel`, `PtEndpointCoreConfig`, `CreatePtEndpoint`, `PutPtEndpointConfig` — `Pt` is "PT" (provisioned throughput). Two-letter acronym title-cased. - - `Uc`, `ucServiceCredentialName` — `Uc` is "UC" (Unity Catalog). - - `HttpMethod` — `Http` title-cased. - - `OpenApi`, `GetOpenApiResponse` — `Api` title-cased mid-word. - - `ApiKey`, `apiKeyAuth` — `Api` title-cased. - - `ARN`-related: `instanceProfileArn`, `Arn` is suffix-cased. - - `Url`, `endpointUrl`, `customProviderUrl` — `Url` title-cased. - - `OpenAi` (line 743) vs `openai` (lines 505, 1399) — `openai` is all lower-case in *some* discriminator keys. -- **Category:** 3 (acronym casing inconsistencies — the audit prompt's exemplar). -- **Suggested name:** Decide a project-wide rule in `typescript.mdc`. The Microsoft .NET capitalization guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) say to title-case two-letter acronyms (`IO`) and PascalCase three-plus-letter acronyms (`Xml`); the Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) says to treat acronyms as whole words. Either is defensible; *none* should be mixed in one file. The current state has at least four different rules co-existing. -- **Rationale:** Twenty-five exported identifiers from one file vary in convention. This is the single biggest *category* of weirdness in the package. - -### 9. `openai` discriminator key lowercase while sibling keys are camelCase — `src/v1/model.ts:505-507, 1399-1401` -- **Why weird:** Inside `ExternalModel.config` discriminated union, the eight `$case` values are: `ai21labsConfig`, `anthropicConfig`, `amazonBedrockConfig`, `cohereConfig`, `googleCloudVertexAiConfig`, `databricksModelServingConfig`, `openaiConfig`, `palmConfig`, `customProviderConfig`. Seven of nine use the standard `Config` camelCase. The two outliers are: - - `ai21labsConfig` (the product is "AI21 Labs"; the discriminator collapses to `ai21labs` — all lower-case middle), and - - `openaiConfig` (the product is "OpenAI"; the discriminator collapses to `openai` — lower-case middle), and - - `palmConfig` (the product is "PaLM"; the discriminator collapses to `palm`). - In each case the JSDoc field name (`Ai21Labs`, `OpenAi`, `PaLm`) does not match the discriminator (`ai21labs`, `openai`, `palm`). -- **Category:** 3 (acronym casing), 17 (inconsistent within the same union). -- **Suggested name:** Either lowercase the camelCase boundary on all keys (`ai21Labs`, `openAi`, `paLm`, `amazonBedrock`, `cohere`, ...) or all-PascalCase the type names to match. As above: pick one rule. -- **Rationale:** The discriminator string is the *runtime* value clients must match against; an inconsistent rule means clients can't programmatically map provider name → discriminator. - -### 10. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` -- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 878). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `BEHAVIOR_UNSPECIFIED | NONE | BLOCK | MASK` — so this is *PII action behavior*. -- **Category:** 1 (vague/generic), 15 (generic name losing meaning). -- **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. -- **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. - -### 11. `Route` field carries `servedModelName` AND `servedEntityName` — `src/v1/model.ts:996-1002` -- **Why weird:** `Route` has three fields: `servedModelName?: string`, `trafficPercentage?: number`, `servedEntityName?: string`. There is no JSDoc on `servedEntityName` — it is silently the modern name; `servedModelName` is the legacy. Two fields point at the same logical thing (the entity to route traffic to), one without docs, one with docs that only mention "served model" (line 997). Same bug class as #3 and #4. -- **Category:** 12 (duplicate concept), 6 (misleading), 19 (undocumented field). -- **Suggested name:** Mark `servedModelName` `@deprecated`; doc `servedEntityName` properly. -- **Rationale:** Triple bug: undocumented field, duplicate concept, no deprecation marker. - -## Medium severity - -### 12. `UNKNOWN` vs `UNSPECIFIED` zero-value naming inconsistent across enums — `src/v1/model.ts:6, 13, 30, 40, 49` -- **Why weird:** Four enums spell the zero-value sentinel `*_UNSPECIFIED` (`Behavior.BEHAVIOR_UNSPECIFIED`, `ExternalFunctionRequest_HttpMethod.HTTP_METHOD_UNSPECIFIED`, `InferenceEndpointState_ConfigUpdateState.CONFIG_UPDATE_STATE_UNSPECIFIED`, `InferenceEndpointState_ReadyState.READY_STATE_UNSPECIFIED`), but `ServedModelDeploymentState.DEPLOYMENT_UNKNOWN` (line 13) uses `UNKNOWN` instead. One file, two conventions for the same concept. -- **Category:** 17 (inconsistent `UNSPECIFIED`/`UNKNOWN`). -- **Suggested name:** Normalize the outlier: rename `DEPLOYMENT_UNKNOWN` → `DEPLOYMENT_STATE_UNSPECIFIED` (per AIP-126: https://google.aip.dev/126). -- **Rationale:** Two spellings for the same sentinel concept across sibling enums in a single file is a pure inconsistency, independent of whether the sentinel itself should exist. - -### 13. `ServedModelDeploymentState` enum name collides with parent `ServedModelState` type — `src/v1/model.ts:12, 1069-1072` -- **Why weird:** The enum type is `ServedModelDeploymentState`, and it lives on the field `ServedModelState.deployment: ServedModelDeploymentState`. Two different types both end in `State`, one wraps the other, and the wrapper field (`deployment`) shares its name with the inner enum's category. The result reads as `served.state.deployment` returning a `ServedModelDeploymentState` — the wrapper and the enum sound like the same thing. -- **Category:** 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). -- **Suggested name:** Rename the type `ServedModelState` → `ServedModelDeployment`, and the enum `ServedModelDeploymentState` → `DeploymentState`. Call site becomes `served.state.deployment === DeploymentState.READY`. The container and the discriminant no longer share a noun. -- **Rationale:** Two `*State` siblings nested inside each other tangle the wrapper identity with the discriminant identity. - -### 14. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:376, 392, 410` -- **Why weird:** Three types describe "the config of a serving endpoint": - - `EndpointCoreConfig`: input shape (`servedEntities: ServedModel[]`, `servedModels: ServedModel[]`, `trafficConfig`, `autoCaptureConfig`). - - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. - - `EndpointCoreConfigSummary`: lite shape (`servedEntities: ServedModelLite[]`, `servedModels: ServedModelLite[]` — no `trafficConfig`, no `autoCaptureConfig`, no `configVersion`). - - Together with `PendingConfig` (which is `EndpointCoreConfigOutput` plus `startTime`) and `PtEndpointCoreConfig` (the PT variant of `EndpointCoreConfig`), there are five overlapping config types. The naming makes the differences invisible: `Output` adds one field; `Summary` removes three. -- **Category:** 12 (duplicate concept), 7 (overly verbose suffixes), 17 (inconsistent suffix semantics). -- **Suggested name:** Either (a) collapse into one type with optional fields, or (b) give the types names that reflect their *purpose*: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). -- **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. - -### 15. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:624, 653` -- **Why weird:** Two near-duplicate types: - - `InferenceEndpoint` (lines 624-651): used in `ListInferenceEndpointsRequest_Response.endpoints`. Has 14 fields. - - `InferenceEndpointDetailed` (lines 653-690): returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. Has 18 fields. - - The "Detailed" version adds `pendingConfig`, `permissionLevel`, `routeOptimized`, `endpointUrl`, `dataPlaneInfo`, `emailNotifications` and changes `config` from `EndpointCoreConfigSummary` to `EndpointCoreConfigOutput`. So `InferenceEndpoint` is really the *list-summary* projection, but its name says "the endpoint". `InferenceEndpointDetailed` is *the* endpoint, but its name says "more detail than usual". -- **Category:** 12 (duplicate concept), 7 (overly verbose suffix), 17 (inconsistent: which one is "the endpoint"?). -- **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. -- **Rationale:** Currently consumers writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. - -### 16. `ServedModelLite` lite-variant — `src/v1/model.ts:1057-1067` -- **Why weird:** Same pattern as #15 at the entity level. `ServedModel` (line 1004) has 23 fields. `ServedModelLite` (lines 1057-1067) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (no Lite suffix, just "Summary" in the name). -- **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). -- **Suggested name:** `ServedEntitySummary` (paired with #2 type rename). -- **Rationale:** Inconsistent suffix convention across the file. "Lite" is also an LLM-era term that clashes with the OpenAI/Anthropic-flavoured product space. - -### 17. `Pt` abbreviation everywhere — `src/v1/client.ts:148, 173, 515, 540` and `src/v1/model.ts:294, 881, 887, 981` -- **Why weird:** `Pt` is short for "provisioned throughput". The full term ("provisioned throughput") *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`), but the request/response *types* use the abbreviation (`CreatePtEndpointRequest`, `PutPtEndpointConfigRequest`, `PtEndpointCoreConfig`, `PtServedModel`). So the public surface has: - - `client.createProvisionedThroughputInferenceEndpoint(req: CreatePtEndpointRequest)` — method-full, type-abbreviated. - - URL: `/api/2.0/serving-endpoints/pt` — wire-abbreviated. - - Three different names for one concept, in one call. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistent abbreviation across method/type/URL). -- **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpointRequest`, `PutProvisionedThroughputEndpointConfigRequest`, etc. — long but searchable) or contract all (`createPtEndpoint`, `putPtEndpointConfig` — short but cryptic). Pick one. The current half-and-half is the worst option. -- **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). - -### 18. `CreatePtEndpointRequest` method-type asymmetry with `CreateInferenceEndpointRequest` — `src/v1/model.ts:271, 294` -- **Why weird:** Sister request types: - - `CreateInferenceEndpointRequest` (full name). - - `CreatePtEndpointRequest` (abbreviated). - - The PT variant is *not* called `CreateProvisionedThroughputInferenceEndpointRequest`; it is `CreatePtEndpointRequest`. The non-PT variant is not called `CreateEndpointRequest`; it is `CreateInferenceEndpointRequest`. So one type carries the qualifier `Inference`, the other carries the qualifier `Pt`. Mixed metaphor. -- **Category:** 17 (inconsistent qualifier choice). -- **Suggested name:** `CreateServingEndpointRequest` and `CreateProvisionedThroughputServingEndpointRequest` (paired with #1). -- **Rationale:** Sibling request types should differ only in the qualifier that actually differs. - -### 19. `PutInferenceEndpointConfigRequest` vs `PutPtEndpointConfigRequest` — request shape divergence — `src/v1/model.ts:950, 981` -- **Why weird:** Two "put endpoint config" requests: - - `PutInferenceEndpointConfigRequest`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). - - `PutPtEndpointConfigRequest`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). - - Same operation conceptually, two different request shapes. The naming makes both look symmetric (`Put*EndpointConfigRequest`), but they are not. -- **Category:** 17 (inconsistent shape with consistent naming — worst case for the reader). -- **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. -- **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. - -### 20. `PatchInferenceEndpointTagsRequest.addTags` / `deleteTags` paired with `EndpointTag` — `src/v1/model.ts:836-843` -- **Why weird:** `addTags?: EndpointTag[]` and `deleteTags?: string[]`. The two fields use different element types — one is the full `EndpointTag` (key+value), the other is bare keys. The naming says "tags" for both, but only one actually holds tags. A user reading `deleteTags: ['env']` will think they are deleting tag `env=*`; in reality they are deleting all tags with key `env`. That semantics is fine, but the field name does not convey it. -- **Category:** 6 (misleading), 15 (generic field name). -- **Suggested name:** `addTags: EndpointTag[]` (keep); `deleteTagKeys: string[]` (rename). -- **Rationale:** When the element type changes, the field name should change too. - -### 21. `endpointUrl` field domain ambiguity — `src/v1/model.ts:679, 331` -- **Why weird:** `endpointUrl` appears twice: - - `InferenceEndpointDetailed.endpointUrl` (line 679): "Endpoint invocation url if route optimization is enabled for endpoint." - - `DataPlaneInfo.endpointUrl` (line 331): "The URL of the endpoint for this operation in the dataplane." - - Same field name, two completely different URLs (one is the public invocation URL; the other is the data-plane endpoint for one specific operation). Compare with #15 in the audit prompt: generic field names lose meaning across structs. -- **Category:** 15 (generic field name across types), 17 (inconsistent usage). -- **Suggested name:** `invocationUrl` (on `InferenceEndpointDetailed`) and `dataPlaneUrl` (on `DataPlaneInfo`). -- **Rationale:** A consumer JOINing the two by `endpointUrl` field name will mismatch them. - -### 22. `id`/`name` dual-identifier on `InferenceEndpoint` — `src/v1/model.ts:625-640, 654-669` -- **Why weird:** `InferenceEndpoint` and `InferenceEndpointDetailed` both have *two* identifiers: - - `name: string` — "The name of the serving endpoint." (Wire `name`. Used in URLs.) - - `id: string` — "System-generated ID of the endpoint, included to be used by the Permissions API." - - The `name` is used in URLs; the `id` is used in the Permissions API. Same resource, two opaque strings. Neither is qualified (`endpointName`/`endpointId` would make grepping work). Compare to the audit prompt's rule 19. -- **Category:** 1 (vague), 19 (underspecified ID), 15 (generic field name). -- **Suggested name:** `name` → `endpointName`; `id` → `endpointId`. Wire stays whatever it is. -- **Rationale:** `endpoint.id` and `endpoint.name` are footguns when joined with other resources (e.g. logs that include a `name` that is something else entirely). - -### 23. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` -- **Why weird:** Four waiter classes: - - `CreateInferenceEndpointWaiter` - - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters — the longest exported class in the file) - - `PutInferenceEndpointConfigWaiter` - - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) - - Two problems: the verb tense varies (`Create*Waiter` is fine; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` (unlike #17 where the type is `Pt`). Sibling request types should differ only in the qualifier that actually differs. -- **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). -- **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. -- **Rationale:** Four exported waiter classes, each 30+ characters long, each containing five+ identical method-name prefixes that grep the same way as the methods themselves. - -### 24. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` -- **Why weird:** Waiter `done()` returns `true` for: - - `NOT_UPDATING` (success) - - `UPDATE_FAILED` (failure) - - `UPDATE_CANCELED` (cancellation) - - All three "terminal" states are treated as `done`. A consumer reading `if (await waiter.done()) { /* it succeeded */ }` will silently get failures and cancellations. The name `done()` does not convey "terminal but possibly failed". -- **Category:** 6 (misleading), 1 (vague). -- **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. -- **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. - -### 25. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` -- **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. -- **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). -- **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). -- **Rationale:** Minor; internal. - -### 26. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:987-994, 93-107` -- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:483 "Deprecated: Please use AI Gateway to manage rate limits instead."). `AiGatewayRateLimit` is the new path. Same pattern as #14: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. -- **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). -- **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimitsRequest*` types `@deprecated` in JSDoc. -- **Rationale:** Same pattern repeated; same fix. - -### 27. `ExportMetricsResponse` JSDoc leaks `Proto` / `Rpc` / `JettyRPC` architecture — `src/v1/model.ts:424-434` -- **Why weird:** The JSDoc on this public exported type reads: "Proto version of com.databricks.rpc.HttpOverRpcResponse. This message can be specially handled in UnaryRpcService with JettyRPC when the advanced feature CustomHandlingForHttpOverRpcProtoResponse is enabled - bypass the RPC serializer and populate HTTP status, response headers and response body from the proto message directly." Five internal architectural concepts (`Proto`, `Rpc`/`RPC`, `UnaryRpcService`, `JettyRPC`, `CustomHandlingForHttpOverRpcProtoResponse`) are dumped into the public docs of a TS type that just carries a `ReadableStream`. The TS consumer has no need to know that `ExportMetricsResponse` is a "Proto version of com.databricks.rpc.HttpOverRpcResponse" — that is a backend impl detail. The type name itself is fine; the doc is the leak. -- **Category:** Proto-architectural leak (in JSDoc), 6 (misleading — public doc surfaces backend internals). -- **Suggested name:** Keep type name `ExportMetricsResponse`. Rewrite the JSDoc to describe the user-facing shape: "Streaming response from `Client.getExportEndpointMetrics`. The body is a Prometheus-format text stream." Strip every `Proto`/`Rpc`/`Jetty*` reference. -- **Rationale:** Public docs that name internal RPC infrastructure leak the implementation strategy into the SDK surface. SDK consumers should never read "JettyRPC" or "UnaryRpcService" in IDE tooltips. - -### 28. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` architectural placeholder — `src/v1/model.ts:737-740` -- **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field (`queryInfo`), so the wrapping is a pure architectural placeholder reserved for future operations. The repeated `Info` suffix is the architectural-leak signal: two `*Info` siblings, one nested in the other, neither carrying real "info" of its own (one is a one-field wrapper, the other is two URL strings). The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. -- **Category:** Proto-architectural leak (`Info`-suffix duplication as structural placeholder), 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). -- **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a second field then. Or rename the wrapper to `ModelDataPlanes` (plural noun) and drop the `Info` suffix on both. -- **Rationale:** `Info`-wrapping-`Info` is the same pattern as `*Spec.spec` or `*Config.config` proto idioms — an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. - -## Low severity - -### 29. `Ai21LabsConfig.ai21labsApiKey` / `ai21labsApiKeyPlaintext` — `src/v1/model.ts:54-69` -- **Why weird:** Field repeats the provider name (`ai21labs`) because the type is named `Ai21LabsConfig`. Reading `config.ai21labsApiKey` inside an `Ai21LabsConfig` is redundant — the only key here is going to be an AI21 Labs API key. Same pattern repeats for every provider config (`anthropicApiKey` inside `AnthropicConfig`, `cohereApiKey` inside `CohereConfig`, etc.). -- **Category:** 7 (overly verbose), 20 (type-suffix tautology). -- **Suggested name:** `apiKey` / `apiKeyPlaintext` inside `Ai21LabsConfig`. Wire stays `ai21labs_api_key`. -- **Rationale:** Compare to `OpenAiConfig.openaiApiKey` (same redundancy), `CohereConfig.cohereApiKey` (same), `AnthropicConfig.anthropicApiKey` (same), `PaLmConfig.palmApiKey` (same), `DatabricksModelServingConfig.databricksApiToken` (same). Six provider configs, six instances of the redundancy. The wire forces the prefix (`anthropic_api_key`); TS does not. - -### 30. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields -- **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. -- **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). -- **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. -- **Rationale:** The "must specify exactly one" constraint is invisible to the type system. - -### 31. `valid_topics` / `invalid_keywords` — `src/v1/model.ts:118, 123` -- **Why weird:** Two list fields on `AiGuardrailParameters`. `validTopics` is the list of *allowed* topics; `invalidKeywords` is the list of *blocked* keywords. So one is a denylist, one is an allowlist. The opposite-polarity naming (`valid*` for allowlist, `invalid*` for denylist) reads correctly *only* if you read both docs. A user skimming the fields will see "valid topics" and "invalid keywords" and not realise the polarity flipped. -- **Category:** 6 (misleading), 17 (inconsistent polarity). -- **Suggested name:** `allowedTopics` / `blockedKeywords`. -- **Rationale:** Allowlist/denylist naming convention is well-established (https://www.ncsc.gov.uk/blog-post/terminology-its-not-black-and-white). - -### 32. `EmailNotifications.onUpdateSuccess` / `onUpdateFailure` — `src/v1/model.ts:371, 373` -- **Why weird:** Field name reads as an event handler (`onUpdateSuccess` is a JS convention for "callback when update succeeds"). But the field is a `string[]` of email addresses. Not a callback. The `on*` prefix is borrowed from JS event-handler-naming and is misleading here. -- **Category:** 6 (misleading — `on*` implies callback). -- **Suggested name:** `notifyOnUpdateSuccess` / `notifyOnUpdateFailure` (verb), or `updateSuccessRecipients` / `updateFailureRecipients` (noun). -- **Rationale:** `on*` in a JS context is a strong signal of "event handler"; using it for email lists violates that signal. - -### 33. `Route.servedModelName` / `servedEntityName` — already flagged in #11 -- **Why weird:** Cross-reference. - -### 34. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` -- **Why weird:** Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added (e.g. `mistralConfig`), the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary (#9). This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. -- **Category:** Observation / 12. -- **Suggested name:** No rename; flag as generator review. -- **Rationale:** Names look clean; runtime is fragile. - -### 35. `ExternalModel.name` — bare `name` on an unbounded type — `src/v1/model.ts:469` -- **Why weird:** "The name of the external model." But `name` on an `ExternalModel` is *different* from `name` on the enclosing `ServedModel` (line 1006). A consumer reading `served.externalModel.name` and `served.name` will see two strings that look related; they are not (the inner is the provider's model name like "gpt-4"; the outer is the route name within the endpoint). -- **Category:** 1 (vague), 15 (generic name across types). -- **Suggested name:** `ExternalModel.modelName` or `ExternalModel.providerModelName`. -- **Rationale:** Disambiguates from `ServedModel.name`. - -### 36. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` -- **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. -- **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). -- **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. -- **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. - -### 37. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` -- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #36: a string field with a documented but unenforced enum. -- **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). -- **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). -- **Rationale:** Type-narrowing fix; minor. - -### 38. `ExternalFunctionRequest` JSDoc literally says "Simple Proto message for testing" — `src/v1/model.ts:438` -- **Why weird:** Cross-references #7 (the doc lying about "for testing"). The proto-architectural angle is sharper here: the word `Proto` itself should not appear in any TS-facing JSDoc. The TS SDK does not transport protobuf, does not use proto codegen at the consumer surface, and the consumer cannot act on the fact that the wire shape originated as a proto. The doc is a verbatim copy from the proto IDL comment that escaped through the generator. -- **Category:** Proto-architectural leak (in JSDoc). -- **Suggested name:** Rewrite the JSDoc (see #7 for proposed user-facing text). Strip the word `Proto`. -- **Rationale:** Same as #27 and #39; proto vocabulary is a backend-team artifact and should be stripped before public docs are emitted. - -### 39. `GetOpenApiResponse` JSDoc says "The top level proto message" — `src/v1/model.ts:555` -- **Why weird:** The JSDoc reads "The top level proto message that represents an OpenAPI 3.0 document." Same pattern as #27 and #38: the doc tells the TS consumer that the type originated as a proto message. The TS type itself is just `{contents?: ReadableStream}` — a stream of OpenAPI 3.0 JSON. The consumer has zero use for the "proto message" framing. The `OpenApi` in the type name is fine (it is the user-facing payload); the word `proto` in the doc is the leak. -- **Category:** Proto-architectural leak (in JSDoc). -- **Suggested name:** Rewrite the JSDoc: "Streaming response from `Client.getInferenceEndpointSchema`. The body is the endpoint's OpenAPI 3.0 schema as JSON." -- **Rationale:** Strip proto vocabulary from public docs. - -## Observations - -### 40. Mixed naming convention for the same product across three sibling packages -The Databricks "Serving Endpoints" product spans three packages in this SDK: -- `modelservingmanagement`: types use `InferenceEndpoint*`. -- `modelservingdebug`: types use `Endpoint` (e.g. `GetExportEndpointMetrics`). -- `modelservingquery`: types use `Endpoint` (e.g. `QueryEndpointInput`, `QueryEndpointResponse`). - -No two packages agree on the noun. The wire uniformly uses `serving-endpoints`. SDK consumers chaining all three packages will see three different names for one concept. -- **Category:** 17 (cross-package inconsistency). - -### 41. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -Same as customllms #28 — every generated package carries this unused export. - -### 42. `PACKAGE_SEGMENT` constant naming — `src/v1/client.ts:75` -Same as customllms #24 — internal user-agent constant. - -### 43. `Headers` constructor used many times in client.ts — `src/v1/client.ts:119, 156, 195, 223, ...` -Each method instantiates a `new Headers({'Content-Type': 'application/json'})` or `new Headers()` then `.set('User-Agent', this.userAgent)`. Naming-wise this is fine (Headers is the standard web API name), but the pattern is duplicated 16+ times in the file. Not a naming bug; observation only. -- **Category:** 12 (duplicate pattern across methods). - - -## Domain glossary -- `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names, abbreviated in type names. -- `ai gateway` — A Databricks-internal proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. -- `ai guardrails` — Input/output content filters applied via AI Gateway (`safety`, `pii`, `validTopics`, `invalidKeywords`). -- `pii` — Personally Identifiable Information. Rendered `Pii` throughout. -- `uc` — Unity Catalog. Rendered `Uc` (in `ucServiceCredentialName`) or written into JSDoc as "UC". -- `pat`/`m2m`/`u2m`/`oidc` — not encountered in this package. -- `iam` — not encountered. -- `arn` — Amazon Resource Name. Rendered `Arn` (suffix `instanceProfileArn`). -- `wkt` — Well-Known Types. Not imported (this package uses raw `number` for timestamps, not `Temporal.Instant`). -- `provider` enum keys (`ai21labs`, `anthropic`, `amazon-bedrock`, `cohere`, `databricks-model-serving`, `google-cloud-vertex-ai`, `openai`, `palm`, `custom`) — kebab-case on the wire, `Config` camelCase in TS. - -## File coverage -- `src/v1/model.ts` (2556 lines): read fully. -- `src/v1/client.ts` (933 lines): read fully. -- `src/v1/utils.ts` (185 lines): read fully. -- `src/v1/index.ts` (92 lines): read fully. -- `src/v1/transport.ts` (75 lines): new file in regeneration; read fully. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md index c5e64bcb..b404887a 100644 --- a/.agent/naming-audit/oauthcustomappintegration.md +++ b/.agent/naming-audit/oauthcustomappintegration.md @@ -1,144 +1,3 @@ # Naming Audit: oauthcustomappintegration -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/oauth/src/v1/` (formerly `packages/oauthcustomappintegration/src/v1/`; consolidated into the `oauth` package) -**Versions audited:** v1 -**Inferred domain:** Account-level CRUD for OAuth App Integrations. Two flavours of integration are managed by the same service: *Custom* (caller-owned OAuth clients with their own redirect URLs and scopes) and *Published* (catalog of Databricks-blessed third-party apps such as Power BI or Tableau Desktop, identified by a stable `appId`). Both share the `TokenAccessPolicy` configuration. The package is the Databricks account-side complement of the `RFC 6749`/`OAuth 2.0` client registration concept. -**Total weird names flagged:** 13 - -## Summary -| Severity | Count | -| --- | --- | -| High | 4 | -| Medium | 3 | -| Low | 4 | -| Observation | 2 | - -## High severity - -### 1. Every domain type re-states `OAuthAppIntegration` and now also carries a `Request` suffix — model.ts:5, 28, 45, 70, 82, 90, 98, 105, 110, 124, 137, 171, 209, 232 -- **Why weird:** Inside the consolidated `oauth` package, every type name still spells "OAuthAppIntegration" in full, and the new regeneration added a `Request` suffix to every request DTO. Imports look like this: - ```ts - import { - CreateCustomOAuthAppIntegrationRequest, - CreatePublishedOAuthAppIntegrationRequest, - CustomOAuthAppIntegration, - CustomOAuthAppIntegrationSecret, - DeleteCustomOAuthAppIntegrationRequest, - DeletePublishedOAuthAppIntegrationRequest, - GetCustomOAuthAppIntegrationRequest, - GetPublishedOAuthAppIntegrationRequest, - ListCustomOAuthAppIntegrationsRequest, - ListPublishedOAuthAppIntegrationsRequest, - PublishedOAuthAppIntegration, - UpdateCustomOAuthAppIntegrationRequest, - UpdatePublishedOAuthAppIntegrationRequest, - } from '@databricks/sdk-oauth/v1'; - ``` - Most request DTO names are now >35 characters; `CreatePublishedOAuthAppIntegrationRequest` is 42. The package name already declares the namespace, so the type names need not re-declare it. Compare what the same code would look like with shorter names: `CreateCustom`, `CreatePublished`, `Custom`, `Published`, `CustomSecret`, `DeleteCustom`, … (still readable when paired with the package import). -- **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology — every type ends with the package domain noun) -- **Suggested name:** Drop the `OAuthAppIntegration` suffix from every type and the `Request` suffix from request DTOs. With a namespace import the call site reads `oauth.CreateCustom`, `oauth.Custom`, `oauth.CustomSecret`, `oauth.ListPublished`. With named imports, alias if needed. -- **Rationale:** TypeScript module imports already qualify the namespace. Repeating it across every type produces walls of identifiers where the eye has to skip redundant characters to find the discriminator (`Create` vs `Update` vs `Delete` vs `List` vs `Get`, and `Custom` vs `Published`). The redundancy is a Go convention port: in Go `oauthcustomappintegration.CreateCustomAppIntegrationRequest` is necessary because Go has no struct-level method namespacing. TS does not have that constraint. - -### 2. Proto-nested `Request_Response` underscore-infix types leak protobuf message-nesting into TS — model.ts:40, 88, 96, 118, 131, 147, 230, 240 (and matching schemas at 243, 297, 301, 305, 319, 333, 400, 404) -- **Why weird:** Eight types follow the pattern `Request_Response` (e.g. `CreatePublishedOAuthAppIntegrationRequest_Response`, `DeleteCustomOAuthAppIntegrationRequest_Response`). The underscore-infix is a literal carry-over of protobuf nested-message naming (`Request.Response` in the proto, rendered as `Request_Response` by code-gen). Each declaration carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.`, which is the generator self-documenting an architectural leak. The names are also tautological in TypeScript: a response type does not need to embed `Request` in its name. -- **Category:** Proto-architectural-leak: `Foo_PublicRequest` pattern (underscore-infix proto-nested message name); also 7, 8, 20 (verbose; redundant `Request` infix; tautology) -- **Suggested name:** Drop the `Request_` prefix and use the response noun: `CreatePublishedResponse`, `DeleteCustomResponse`, `DeletePublishedResponse`, `ListCustomResponse`, `ListPublishedResponse`, `ListPublishedAppsResponse`, `UpdateCustomResponse`, `UpdatePublishedResponse` (or, since several are empty interfaces, replace with `void` / `undefined` returns on the corresponding `Client` methods). Combine with finding #1 to drop the `OAuthAppIntegration` middle as well. -- **Rationale:** TypeScript has no notion of a message nested inside another message; the underscore is a generator-side fix-up that bleeds proto schema topology into the public API surface. The eslint-disable comments are the smoking gun: the project linter rejects these identifiers by default and they only pass because each one carries a per-line escape hatch. Idiomatic TS response types are sibling exports, not underscore-nested children. - -### 3. JSDoc cross-refs point to `CustomAppIntegration` / `PublishedAppIntegration` services that do not exist — client.ts:101, 137, 172, 203, 458, 493 -- **Why weird:** JSDoc on `createCustomOAuthAppIntegration` says: - > You can retrieve the custom OAuth app integration via `:method:CustomAppIntegration/get`. - - Same pattern on `createPublishedOAuthAppIntegration` → `:method:PublishedAppIntegration/get`. But there is no `CustomAppIntegration` or `PublishedAppIntegration` service exposed by this package — the actual method is `getCustomOAuthAppIntegration` on `Client`. The doc references are stale from a previous naming scheme (the Go SDK has separate `CustomAppIntegrations` and `PublishedAppIntegrations` sub-services). Anyone clicking through will hit a broken reference. -- **Category:** 6 (misleading) -- **Suggested name:** Fix the JSDoc cross-references to point to the real method (`Client.getCustomOAuthAppIntegration` / `Client.getPublishedOAuthAppIntegration`). The `:method:Foo/get` proto-doc directive should be processed to TypeScript-link form during generation. -- **Rationale:** Documentation lying to the reader is worse than verbose-but-correct documentation. - -### 4. `appId` on Published refers to a slug, not an ID — model.ts:34, 173 -- **Why weird:** `CreatePublishedOAuthAppIntegrationRequest.appId` and `PublishedOAuthAppIntegration.appId` are documented as `For example power-bi, tableau-deskop` (note also: typo `deskop`). These are human-readable slugs, not opaque IDs. Calling them `appId` and typing as `string` collides with the convention that `xId` is an opaque UUID-like identifier (cf. `accountId`, `integrationId`, `clientId`, `principalId`). The Go reference (`databricks/api/oauth2/published`) calls it `AppID` too, but the value is clearly a published-catalog key like `power-bi`. The typo `tableau-deskop` in the doc comment is also untracked. -- **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) -- **Suggested name:** `appSlug` or `publishedAppKey` with type narrowed to a string literal union or enum: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, fix the `tableau-deskop` typo and document the format ("dash-separated lowercase slug from the Databricks published-app catalog"). -- **Rationale:** "ID" in this codebase otherwise means opaque UUID/integer (`integrationId`, `clientId`, `principalId`, `accountId`). Mixing in a human-readable slug under the same suffix is a teaching trap for callers. - -## Medium severity - -### 5. `createdBy: number` is a user ID hidden as a numeric — model.ts:59, 180 -- **Why weird:** Used in both `CustomOAuthAppIntegration` and `PublishedOAuthAppIntegration`. The field doc is empty, but it pairs with `creatorUsername: string` on `CustomOAuthAppIntegration`, so `createdBy` is the *user ID* of the creator. Calling it `createdBy` and typing it as `number` (rather than `creatorUserId` typed as `number` or `string`) hides the meaning. `principalId: number` next door has the same problem. -- **Category:** 1, 15, 19 (vague; generic field; underspecified ID) -- **Suggested name:** `createdByUserId: number` or just `creatorUserId: number`. Document explicitly that this is the numeric Databricks user ID (note: many other places in the codebase use `string` for user IDs). -- **Rationale:** A bare `createdBy: number` is the worst kind of numeric ID — no type information, no doc, and a name that reads as an activity verb. The asymmetry with `creatorUsername: string` (which sits 2 lines below in `CustomOAuthAppIntegration` but is missing from `PublishedOAuthAppIntegration`) compounds the confusion. - -### 6. `confidential: boolean` — too generic for "requires-secret" flag — model.ts:12, 55 -- **Why weird:** The doc comment is informative ("indicates whether an OAuth client secret is required to authenticate this client"), but the field name `confidential` is ambiguous outside RFC 6749 context. A reader has to know OAuth specifically (RFC 6749 §2.1 distinguishes "confidential" vs "public" clients) to decode this. The field doesn't follow a `requires…` or `is…` convention used elsewhere in the codebase. -- **Category:** 1, 5 (vague/generic; cryptic abbreviation of a spec term) -- **Suggested name:** `isConfidentialClient`, `requiresClientSecret`, or `confidentialClient`. If keeping `confidential`, add the RFC 6749 link in the doc. -- **Rationale:** Half of OAuth API consumers will not recognize "confidential" as the RFC 6749 client-type discriminator. Note that `PublishedOAuthApp.isConfidentialClient` (model.ts:164) uses the longer-form name, so the package itself is inconsistent here. - -### 7. `userAuthorizedScopes` vs `scopes` overlap — model.ts:19, 25, 58, 67, 220, 226 -- **Why weird:** Two scope fields that look unrelated by name but the doc explicitly says `userAuthorizedScopes` "must be a subset of `scopes`". The relationship is invisible from the type — a caller could set `scopes = ["all-apis"]` and `userAuthorizedScopes = ["sql"]` and the type system won't help. `scopes` is the *requested* scope set, `userAuthorizedScopes` is the *user-consent gate* subset. Names do not encode this subset relationship. -- **Category:** 1, 6 (vague; misleading — `scopes` doesn't say "requested") -- **Suggested name:** `requestedScopes` (rename `scopes`) and `consentRequiredScopes` (rename `userAuthorizedScopes`). Or document the subset relationship inline on `scopes` with a backreference. -- **Rationale:** Bug class: caller assumes `userAuthorizedScopes` is "what the user actually consented to" (a state) rather than "what we *will* ask the user to consent to" (a config). The current name reads past-tense and is easily misread. - -## Low severity - -### 8. `OAuth` casing is consistent — model.ts:throughout -- **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants appear. This matches Google TS style guide guidance for trade-mark casing and matches RFC 6749 ("OAuth 2.0"). No action. -- **Category:** 3 (acronym casing — flagged as compliant) -- **Suggested name:** None — confirm the project-wide policy is `OAuth`. -- **Rationale:** Documenting the convention. Other audits should check sibling packages for `OAuth2` vs `Oauth2` vs `OAUTH2`. - -### 9. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix bloat — model.ts:186, 192, 206 -- **Why weird:** Three TTL fields, two named `…InMinutes`, one named `…LifetimeInMinutes`. The "InMinutes" suffix is verbose. Three options to consider: - - Adopt `Temporal.Duration` for the type (no unit in the name needed). - - Keep the unit in the name but standardise on `Minutes` suffix (`accessTokenTtlMinutes`, `refreshTokenTtlMinutes`, `sessionTtlMinutes`). - - Document the unit in JSDoc only and use bare names (`accessTokenTtl`, `refreshTokenTtl`). -- **Category:** 7 (overly verbose) -- **Suggested name:** `accessTokenTtl: Temporal.Duration`, `refreshTokenTtl: Temporal.Duration`, `absoluteSessionLifetime: Temporal.Duration`. -- **Rationale:** Using `Temporal.Duration` removes the need to encode the unit in the field name, and removes the asymmetry between `TtlInMinutes` and `LifetimeInMinutes` (one is "TTL", the other "lifetime" — same concept). - -### 10. `enableSingleUseRefreshTokens` boolean naming inconsistency with `confidential` — model.ts:199 -- **Why weird:** `enableSingleUseRefreshTokens` uses the verb-first `enableX` convention, but `confidential` uses no prefix. Other boolean conventions in the codebase favour `isX`/`hasX`. Three competing patterns on one type. -- **Category:** 13, 17 (verb-tense inconsistency; inconsistent action verbs) -- **Suggested name:** Align to one of `singleUseRefreshTokensEnabled` (state), `useSingleUseRefreshTokens` (config), or `rotateRefreshTokens` (behaviour). -- **Rationale:** "Enable X" reads as an action and slightly suggests a method/mutator. State booleans typically use predicate suffix `isEnabled`/`enabled` or domain noun. - -### 11. `includeCreatorUsername: boolean` query param on List Custom only — model.ts:114 -- **Why weird:** `ListCustomOAuthAppIntegrationsRequest` has `includeCreatorUsername` but `ListPublishedOAuthAppIntegrationsRequest` does not (line 124). The asymmetry is fine for the API (Published integrations don't track creator the same way) but the type-level discoverability is poor. A caller writing both list calls in sequence will not understand why the option is missing from one. The name itself is also a query-flag for *server-side join inclusion*, which is unusual for an SDK to expose verbatim. -- **Category:** 5 (cryptic — the flag's semantics are non-obvious) -- **Suggested name:** Keep the field but document explicitly: "When true, the server resolves `createdBy` to `creatorUsername` in the response (extra database lookup)." -- **Rationale:** The default behaviour (omit username) is a performance optimization; callers should know enabling this is a server-side join. - -## Observations - -### O1. JSDoc literal templating leaks `` and `` markup — model.ts:73, 76, 195 and client.ts:285, 345, 402 -- The literal tokens `` and `` appear in six places in this package. They are proto-doc templating tokens that should have been substituted to "Databricks" / "account" during generation. They render as broken-HTML angle-bracket sequences in TypeScript hover popups. This is a generator bug, not a per-package naming issue, but worth tagging at the project level. - -### O2. `flattenQueryParams` is exported but unused — utils.ts:123 -- This package never builds nested query parameters (`ListCustomOAuthAppIntegrationsRequest` uses three flat scalars), so `flattenQueryParams` is dead in this build. Same as in many sibling packages. Either drop the `export` or move the helper to `@databricks/sdk-core`. - -## Domain glossary -- `accountId` — Databricks account UUID (top-level tenant), distinct from a workspace ID. -- `appId` — Slug key into the Databricks published-app catalog (`power-bi`, `tableau-desktop`, …). Despite the `Id` suffix, this is a human-readable name, not an opaque ID. -- `clientId` — RFC 6749 client identifier (the OAuth "client_id" returned by the server). -- `clientSecret` — RFC 6749 client secret. Only returned at creation time for confidential clients. -- `confidential` — RFC 6749 §2.1 client type: `true` means the client has a secret and can authenticate itself. -- `Custom` integration — Caller-defined OAuth client (their own redirect URLs, scopes, secret). -- `integrationId` — Opaque server-issued ID for an OAuth app integration row. Distinct from `clientId`. -- `OAuth` — IETF OAuth 2.0 (RFC 6749), the authorization framework. Always cased `OAuth` in this package. -- `principalId` — Databricks service-principal ID auto-created alongside the integration. -- `Published` integration — Databricks-blessed third-party app (Power BI, Tableau, …) the account has enabled. -- `scopes` — RFC 6749 scope strings that the integration may request. Documented values: `all-apis`, `sql`, `offline_access`, `openid`, `profile`, `email`. -- `TokenAccessPolicy` — Per-integration token TTL and refresh-rotation policy. -- `userAuthorizedScopes` — Subset of `scopes` requiring end-user consent. Misleading: this is *will-ask*, not *did-grant*. - -## File coverage -- `src/v1/model.ts` (488 lines): read fully — 22 type exports, 13 schema exports. -- `src/v1/client.ts` (526 lines): read fully — 1 class, 11 async methods, 3 async generators. -- `src/v1/utils.ts` (151 lines): read fully — generic across packages. -- `src/v1/index.ts` (33 lines): read fully — re-exports. -- `package.json`: read for context. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md index a5f8bfb4..69bc4be9 100644 --- a/.agent/naming-audit/oauthpublishedapp.md +++ b/.agent/naming-audit/oauthpublishedapp.md @@ -1,115 +1,3 @@ # Naming Audit: oauthpublishedapp -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/oauth/src/v1/` (consolidated package — formerly `packages/oauthpublishedapp/`) -**Versions audited:** v1 -**Inferred domain:** Account-level read-only catalog of Databricks-blessed third-party OAuth applications (e.g. Power BI, Tableau Desktop) that can be enabled for an account. The published-app surface exposes `listPublishedOAuthApps` returning a paginated `PublishedOAuthApp` catalog row. As of the 2026-05-20 regeneration the package was merged into the broader `@databricks/sdk-oauth` package, which now also carries the custom-integration and published-integration surfaces formerly audited under `oauthcustomappintegration`. -**Total weird names flagged:** 10 - -## Summary -| Severity | Count | -| --- | --- | -| High | 1 | -| Medium | 6 | -| Low | 3 | -| Observation | 1 | - -## High severity - -### 1. `appId` on `PublishedOAuthApp` is a slug, not an opaque ID — `model.ts:156` -- **Why weird:** `PublishedOAuthApp.appId` is documented as "Unique ID of the published OAuth app". The sibling `CreatePublishedOAuthAppIntegrationRequest.appId` (line 34, same file) is documented as `For example power-bi, tableau-deskop` (sic — typo carried in original). The appId is therefore a human-readable slug like `power-bi`, not an opaque UUID. Calling it `appId` and typing it as `string` collides with the convention that `xId` is an opaque opaque-ID (cf. `accountId`, `integrationId`, `clientId`, `principalId`). Since both types now live in the same package (`packages/oauth/src/v1/model.ts`), the disagreement is now intra-package. -- **Category:** 6, 19 (misleading; underspecified ID — what kind of ID?) -- **Suggested name:** `appSlug` or `publishedAppKey` with the type narrowed to a literal union: `'power-bi' | 'tableau-desktop' | 'looker' | ...`. At minimum, document the format inline ("dash-separated lowercase slug from the Databricks published-app catalog") and align with `CreatePublishedOAuthAppIntegrationRequest.appId`. -- **Rationale:** Every other `xId` in this codebase (`accountId`, `clientId`) is an opaque identifier. Mixing in a slug under the same suffix is a teaching trap. Two types in the same package disagree by silence on what `appId` is. - -## Medium severity - -### 2. Every domain type re-states `PublishedOAuthApp` in full — `model.ts:137, 147, 154` -- **Why weird:** Inside the consolidated `oauth` package, every published-app type still spells "PublishedOAuthApp" or "PublishedOAuthApps" inside its name: `ListPublishedOAuthAppsRequest`, `ListPublishedOAuthAppsRequest_Response`, `PublishedOAuthApp`. After consolidation the package namespace is now `oauth`, so the qualifier is justified to disambiguate from the custom and published *integration* types in the same module (`PublishedOAuthAppIntegration` lives at line 171). But the qualifier on `Published` vs `PublishedOAuthAppIntegration` does only a small amount of work — both share the `OAuthApp` infix and disambiguate purely via the trailing `Integration`. Reads as 16-character prefix stutter on every type. -- **Category:** 7, 8, 20 (overly verbose; redundant suffix; type-suffix tautology) -- **Suggested name:** With consolidation, distinguish strictly via the `…Integration` suffix and drop `PublishedOAuth` from the catalog row: `App` (the catalog row) vs `PublishedAppIntegration` / `CustomAppIntegration` (the registrations). At minimum drop the redundant `OAuth` infix everywhere — the parent package is already `oauth`. -- **Rationale:** TypeScript module imports already qualify the namespace. The `OAuth` infix is fully redundant once the package is `@databricks/sdk-oauth`. The remaining `Published` qualifier earns its keep only insofar as it distinguishes the catalog row from the published-integration row. - -### 3. `clientId` field lacks the convention-matching closing period — `model.ts:157-158` -- **Why weird:** Doc comment reads `Client ID of the published OAuth app. It is the client_id in the OAuth flow` — missing trailing period (`flow` ends the sentence). Every other doc comment in the file ends with a period. Also, the wire-form `client_id` is hardcoded into the JSDoc text, which leaks generator-side terminology into TS docs that should describe the TS field. Repository CLAUDE.md rule: "Every comment must be a proper sentence ending with a period." -- **Category:** Not strictly a name finding, but a generator-side text issue — included because it sits on a name field and is visible at every hover. -- **Suggested name:** Doc text only; field name `clientId` is correct. Fix to: `Client ID of the published OAuth app. Matches the OAuth 2.0 \`client_id\` parameter (RFC 6749 §2.2).` -- **Rationale:** Comment-style rule on the project. The reference to RFC 6749 §2.2 gives the term a spec anchor instead of leaving "client_id in the OAuth flow" as a vague pointer. - -### 4. `isConfidentialClient` vs `confidential` inconsistent within the same package — `model.ts:164` (vs `model.ts:12, 54`) -- **Why weird:** Consolidation merged the published-app and custom-integration model files. The same RFC 6749 §2.1 client-type flag is now spelled three ways within one model file: `confidential` on `CreateCustomOAuthAppIntegrationRequest` (line 12) and `CustomOAuthAppIntegration` (line 54), versus `isConfidentialClient` on `PublishedOAuthApp` (line 164). What used to be a cross-package inconsistency is now an intra-package one. The boolean-prefix rule (`is…`) plus the `Client` clarifier here are the more descriptive name; the custom-integration side is the side to align. -- **Category:** 12 (duplicate concept across types, inconsistent naming) — now elevated to intra-package -- **Suggested name:** Pick one — `isConfidentialClient` is the clearer name. Rename the three `confidential` occurrences in custom integration types to match. -- **Rationale:** The flag's value space and meaning are identical across the three types; the identifier should be too. Consolidation makes this a single-package fix. - -### 5. `redirectUrls: string[]` field stutter with `URI`/`URL` spec language — `model.ts:165-166` -- **Why weird:** OAuth 2.0 spec (RFC 6749 §3.1.2) calls these *redirection URIs*. The TS field uses `redirectUrls` (lowercase `rl`); the JSDoc reads "Redirect URLs of the published OAuth app." matching the field name. Elsewhere in the same model file the doc uses "redirect urls" (lowercase, lines 7, 50, 212) and "redirect URIs" (line 217) interchangeably — the latter inside `UpdateCustomOAuthAppIntegrationRequest`. The casing `Urls` (lowercase `rl`) follows Google TS style guide. -- **Category:** 3 (acronym casing — `URL` lowercased as `Url` while `OAuth` keeps `Auth` mid-token uppercase, inconsistent acronym treatment within the same identifier set) -- **Suggested name:** Keep `redirectUrls` (matches Google TS style guide https://google.github.io/styleguide/tsguide.html#identifiers), but cross-reference RFC 6749 §3.1.2 in the JSDoc so the spec term is visible: "Redirect URLs of the published OAuth app (RFC 6749 §3.1.2 \"redirection URIs\")." -- **Rationale:** The doc-term mismatch (URI in spec, URL in code, both in JSDoc within the same file) is the real issue; the casing is correct per Google TS. - -### 6. `scopes: string[]` carries no enum/union — `model.ts:167-168` -- **Why weird:** Custom-integration types in the same file document the supported scope set inline: `Supported scopes: all-apis, sql, offline_access, openid, profile, email` (lines 16-18). Here the same field is typed `string[]` with no JSDoc enumeration: just "Required scopes for the published OAuth app." Same vocabulary, asymmetric documentation within one file. -- **Category:** 1, 12 (vague — string[] could be anything; duplicate concept across types, inconsistent treatment) -- **Suggested name:** Keep `scopes`, but type as `Array<'all-apis' | 'sql' | 'offline_access' | 'openid' | 'profile' | 'email'>` to match the custom-integration documented vocabulary. At minimum, JSDoc the supported scopes. -- **Rationale:** Two types in the same package model the same wire field. The custom variant documents the value space; the published variant leaves it open. - -### 7. `pageSize: number` lacks bounds and unit context — `model.ts:142-143` -- **Why weird:** Doc says "The max number of OAuth published apps to return in one page." but does not document the maximum-permitted value, default, or whether `0` means "unset" or "zero results". `pageSize` is the most common cross-API pagination footgun; some Databricks APIs reject `pageSize > 1000`, others treat `0` as "use default", others as "return zero". A consumer doing `req.pageSize = 0` gets undefined behaviour. The name `pageSize` itself is fine and consistent with Databricks API conventions (and Google AIP-158 https://google.aip.dev/158). -- **Category:** 1 (vague — `number` with no bounds reads as "any int", but isn't) -- **Suggested name:** Name is fine; doc should be "The maximum number of published OAuth apps to return in one page. Defaults to server-side default (typically 100). Maximum: 1000." -- **Rationale:** Same field exists in many sibling packages; document once at the source of truth (the generator's pagination template). - -### 8. `pageToken: string` reuses the previous-response `nextPageToken` — implicit cross-field contract — `model.ts:140-141`, `model.ts:150-151` -- **Why weird:** Request `pageToken` and response `nextPageToken` are two halves of one pagination contract. The names use different roots (`page…` vs `nextPage…`), so the connection is invisible. A new reader has to read both shapes and the iterator to understand `req.pageToken = resp.nextPageToken`. This is the Google AIP-158 convention (https://google.aip.dev/158) and shared by every paginated Databricks API, but worth flagging at project level since the naming asymmetry repeats everywhere. -- **Category:** 17 (inconsistent action verbs — `pageToken` is a noun, `nextPageToken` is a noun; the asymmetry is in the prefix `next…`) -- **Suggested name:** Keep names (they match AIP-158); document the relationship in JSDoc: "Pass `nextPageToken` from the previous response as `pageToken` to fetch the next page." -- **Rationale:** Convention-bound, but the doc is silent — every list endpoint in the SDK silently shares this contract. - -## Low severity - -### 9. `OAuth` casing is consistent — `model.ts:throughout` -- **Why weird:** Worth flagging for completeness: this package uses `OAuth` consistently (capital O, capital A, lowercase uth). No `OAUTH`, `Oauth`, or `oAuth` variants. Matches Google TS style guide guidance and matches RFC 6749. No action. -- **Category:** 3 (acronym casing — flagged compliant) -- **Suggested name:** None — confirm the project-wide policy is `OAuth`. -- **Rationale:** Documenting compliance. - -### 10. `Client` class — generic single export, common to all generated packages — `client.ts:69` -- **Why weird:** Same pattern as every other package in this SDK. `import { Client } from '@databricks/sdk-oauth/v1'` produces an unqualified `Client` symbol. Consumers using multiple packages must alias: `import { Client as OAuthClient }`. After consolidation this class now hosts the full custom-integration + published-integration + published-app surface (no longer a one-method client), making the generic name even more of a navigation hazard. -- **Category:** 1 (vague/generic) -- **Suggested name:** `OAuthClient` (still inside `…/v1`). Project-wide change. -- **Rationale:** Defer to the project-wide naming-audit summary. - -### 11. `apps?: PublishedOAuthApp[]` field on response — collection field name matches type — `model.ts:149` -- **Why weird:** The response collection field. Reads naturally enough, but no other indication of plurality at the field name (only the array type adds plurality). After consolidation the response types `ListCustomOAuthAppIntegrationsRequest_Response` (line 118) and `ListPublishedOAuthAppIntegrationsRequest_Response` (line 131) also expose an `apps` field whose values are *integrations*, not apps. So within one package the `apps` field name now collides in meaning across three response types. -- **Category:** 15 (generic field — `apps` is the maximally-generic plural of `app`) — flagged for completeness -- **Suggested name:** Rename to `publishedApps` here (and the two sibling responses to `customIntegrations` / `publishedIntegrations`) to make plural+domain explicit. -- **Rationale:** Now an intra-package collision after consolidation — three response types all expose `apps` with different semantics. - -## Observations - -### O1. JSDoc literal templating: this surface has `` token leak — `client.ts:402` -- The JSDoc on `listPublishedOAuthApps` reads "Get all the available published OAuth apps in ``". Same generator bug appears on the `TokenAccessPolicy.enableSingleUseRefreshTokens` doc (`model.ts:195`) and on `CustomOAuthAppIntegrationSecret.clientId` / `.clientSecret` docs (`model.ts:73, 76`). Five total `` token leaks now visible in this single file after consolidation. - -## Domain glossary -- `accountId` — Databricks account UUID (top-level tenant). Distinct from a workspace ID. -- `appId` — Slug key into the Databricks published-app catalog (e.g. `power-bi`, `tableau-desktop`). Despite the `Id` suffix, this is a human-readable name. Same value space as `CreatePublishedOAuthAppIntegrationRequest.appId` in the same model file. -- `clientId` — RFC 6749 client identifier (OAuth `client_id`). Stable per published app. -- `OAuth` — IETF OAuth 2.0 (RFC 6749). Always cased `OAuth` in this package. -- `Published` app — Databricks-blessed third-party application (Power BI, Tableau Desktop, …) available to be enabled in an account. Distinct from a `Custom` integration (caller-defined OAuth client, now lives in the same consolidated `oauth` package as `CustomOAuthAppIntegration`). -- `redirectUrls` — RFC 6749 §3.1.2 "redirection URIs" registered for the published app. -- `scopes` — RFC 6749 scope strings the published app may request (`all-apis`, `sql`, `offline_access`, `openid`, `profile`, `email`). - -## Cross-package coupling notes -- After the 2026-05-20 regeneration, the `oauthpublishedapp` and `oauthcustomappintegration` packages were merged into `@databricks/sdk-oauth`. What were previously cross-package consistency issues (boolean naming, scope vocabulary, `appId` value space) are now intra-package consistency issues. See findings #1, #4, #6, #11. -- The shared catalog row `PublishedOAuthApp` and the registration row `PublishedOAuthAppIntegration` now coexist in `model.ts`; the previous suggestion to "lift `PublishedOAuthApp` into a shared module" is satisfied by the consolidation. - -## File coverage -- `src/v1/model.ts` (488 lines): read fully — published-app types are `PublishedOAuthApp`, `ListPublishedOAuthAppsRequest`, `ListPublishedOAuthAppsRequest_Response`, plus shared `TokenAccessPolicy` and the custom/published integration types. -- `src/v1/client.ts`: read fully — `Client` class hosts `listPublishedOAuthApps` (line 403) and `listPublishedOAuthAppsIter` (line 439) alongside the custom-integration and published-integration methods. -- `src/v1/utils.ts`: read for context — generic across packages, identical to siblings. -- `src/v1/index.ts`: read for context — re-exports `Client` and model types. -- `package.json`: now `@databricks/sdk-oauth` (consolidated). +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md index ed3dbc7c..6d8251df 100644 --- a/.agent/naming-audit/permissions.md +++ b/.agent/naming-audit/permissions.md @@ -1,235 +1,3 @@ # Naming Audit: permissions -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/accessmanagement/src/v1/` (originally `packages/permissions/`, consolidated into `accessmanagement` during regeneration). -**Versions audited:** v1 -**Inferred domain:** Workspace-object permissions — get, set, update, and inspect ACLs (access control lists) attached to Databricks workspace objects (clusters, jobs, notebooks, dashboards, pipelines, registered models, queries, repos, files, instance pools, etc.). Distinct from `grants` (Unity Catalog privileges on UC securables), though the two surfaces overlap conceptually and lexically. -**Total weird names flagged:** 33 - -## Summary -| Severity | Count | -| --- | --- | -| High | 7 | -| Medium | 18 | -| Low | 5 | -| Observation | 3 | - -The permissions surface contains 9 generated types, 1 enum, and 4 client methods, plus utility helpers. After regeneration, the four request types (`GetObjectPermissions`, `SetObjectPermissions`, `UpdateObjectPermissions`, `GetPermissionLevels`) gained `Request` suffixes — eliminating the worst of the verb-shaped-type problems. What remains on the `PermissionLevel` enum is the redundant `CAN_` action-verb prefix on 19 of 20 values (the lone `IS_OWNER` mixes a different copula), the `_ONLY` qualifier on `CAN_MONITOR_ONLY`, and the object-type-specific values (`CAN_MANAGE_STAGING_VERSIONS`, `CAN_CREATE_APP`) leaking into a universal enum. - -The structural wart from mechanical proto-to-TS porting persists: every request type tags its path-parameter fields with a verbose `requestObjectType` / `requestObjectId` prefix (rather than `objectType`/`objectId` or just `type`/`id`) — the prefix is wire-format leakage. `requestObjectType` and `requestObjectId` are still typed `string` with a documented closed enumeration of valid values listed verbatim in JSDoc (26 different object types in a single doc-comment), surfacing the "stringly-typed closed enum" anti-pattern that TypeScript's type system would otherwise prevent. The package also overlaps heavily with `grants` in vocabulary (`Permission`, `PermissionsResponse`, `permissionLevels`) while modelling a completely different concept. - ---- - -## High severity - -### 1. `PermissionLevel` enum values share a redundant `CAN_` action-verb prefix — `src/v1/model.ts:6–27` -- **Why weird:** Of 20 values, 19 begin with `CAN_` (`CAN_MANAGE`, `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`); the lone exception is `IS_OWNER`, which uses a copula+predicate form. The `CAN_` prefix is implied by membership in `PermissionLevel` — a `PermissionLevel` is, by definition, what the principal can do — and is therefore content-free on every value. This is distinct from the proto-style enum-name prefix (which would be `PERMISSION_LEVEL_*`); here the redundancy is on the action-modal verb shared by 19 of 20 members. Mixing `CAN_*` with `IS_OWNER` also breaks within-enum consistency. -- **Category:** 2 (redundant action-verb prefix on enum members), 17 (inconsistent: 19 `CAN_*` action verbs alongside one `IS_*` copula). -- **Suggested name:** Drop the `CAN_` action-verb prefix: `MANAGE`, `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, `USE`, etc. `IS_OWNER` becomes `OWNER`. -- **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. `PermissionLevel.MANAGE` is shorter and just as unambiguous as `PermissionLevel.CAN_MANAGE` (Google TS Style Guide §5.4 prefers concise enum members; the `CAN_` modal verb does not need to repeat on every member). - -### 2. `CAN_MONITOR` vs `CAN_MONITOR_ONLY` — `src/v1/model.ts:23,25` -- **Why weird:** Two distinct values that differ in name only by the `_ONLY` suffix. The JSDoc (none provided) gives no clue what the difference is. From product context, `CAN_MONITOR` typically grants monitoring AND inherited subset privileges; `CAN_MONITOR_ONLY` strictly limits to monitoring. Cannot infer this from the names — must consult external API docs. -- **Category:** 6 (misleading: pair seems exhaustive but `_ONLY` semantics are non-obvious), 17 (inconsistent: no other value uses `_ONLY` to differentiate). -- **Suggested name:** Document inline what the difference is, OR rename to `MONITOR_FULL` / `MONITOR_READ_ONLY` / similar pair where the contrast is on the *predicate*, not on a vague `_ONLY` qualifier. -- **Rationale:** Whenever an enum exposes "X" and "X_ONLY" with no JSDoc, every caller hits a Stack Overflow question. - -### 3. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` — `src/v1/model.ts:17,18` -- **Why weird:** These values are specific to one object type (`registered-models` in MLflow Model Registry — staging vs production model versions) but live in a universal enum applicable to 25+ object types. Equivalent to having `CAN_MANAGE_DASHBOARD_DRAFTS` or `CAN_MANAGE_NOTEBOOK_REVISIONS` in the same enum: the values are scoped to one domain but visible to all. -- **Category:** 17 (inconsistent — most values are object-type-agnostic, these two leak object-type semantics into the enum). -- **Suggested name:** JSDoc clarifying applicability ("Applies to registered-models only"), or move these MLflow-specific levels into a separate enum. -- **Rationale:** Universal enum + object-specific values is a discoverability hazard; users browsing autocomplete will see these as valid choices for clusters/jobs/dashboards. - -### 4. `CAN_CREATE_APP` — `src/v1/model.ts:26` -- **Why weird:** Same problem as #3 — object-type-specific value in a universal enum. The `App` here refers to Databricks Apps (a specific object kind); other object types have no equivalent. The `_APP` suffix is also inconsistent with how the rest of the enum names the noun being created (most `CAN_CREATE` is unsuffixed; `CAN_CREATE_APP` is the only one with an explicit noun). -- **Category:** 17. -- **Suggested name:** Same pattern as #3 — document scope, or partition. -- **Rationale:** See #3. - -### 5. Concept duplication with `grants` package — cross-package -- **Why weird:** A sibling package `packages/grants/src/v1/` also defines a `Permission*` vocabulary (`PermissionsChange`, `getPermissions`, `updatePermissions`) for a different operation (Unity Catalog privileges on securables). Both packages re-export `Permission`-prefixed types from their `index.ts`. A user reading `import { Permission } from '@databricks/sdk-accessmanagement/v1'` vs `import { PrivilegeAssignment } from '@databricks/sdk-grants/v1'` has no surface-level cue that these belong to disjoint domains. The permissions surface operates on workspace objects (clusters, jobs, notebooks) via `requestObjectType: string` paths; the `grants` package operates on UC securables (catalogs, schemas, tables) via `securableType: string` paths. The vocabulary overlap obscures this distinction. -- This same observation appears in `.agent/naming-audit/grants.md` #10 — flagged from the other side of the mirror. -- **Category:** 12 (duplicate concepts across packages), 1 (vague top-level package naming). -- **Suggested name:** Rename for disambiguation: keep the surface in `accessmanagement` but expose under a `workspace-permissions` or `workspace-acl` subpath; `grants` → `unity-catalog-grants` or `uc-privileges`. At minimum the public exports should be non-overlapping (no `Permission` prefix in both). -- **Rationale:** The two packages cover non-overlapping concrete operations but use heavily overlapping vocabulary — an enormous discoverability hazard. - -### 6. `RequestAuthzIdentity` enum and `REQUEST_AUTHZ_IDENTITY_*` member prefix — `src/v1/model.ts:33–37` -- **Why weird:** The enum-type name starts with `Request` — a wire-format-message prefix (`RequestAuthzIdentity` reads as "the AuthzIdentity field on a request message"). Every member then re-states the entire enum name as a SCREAMING_SNAKE prefix: `REQUEST_AUTHZ_IDENTITY_UNSPECIFIED`, `REQUEST_AUTHZ_IDENTITY_USER_CONTEXT`, `REQUEST_AUTHZ_IDENTITY_SERVICE_IDENTITY`. This is the canonical proto3 enum convention — proto enum members must be globally unique within a file, so the enum name is required as a prefix; TypeScript enums have no such constraint, so the prefix is pure proto-architectural leakage. Also, the `UNSPECIFIED` zero value is a proto convention (every proto enum must have a zero value named `*_UNSPECIFIED`); TS enums have no such requirement. -- **Category:** Proto-architecture leak (enum-name-prefix on members, `Request` infix on type name, `_UNSPECIFIED` zero-value convention). -- **Suggested name:** `AuthzIdentity` enum with members `UNSPECIFIED`, `USER_CONTEXT`, `SERVICE_IDENTITY`. Better: drop `UNSPECIFIED` and make the field optional in the request types (TS-idiomatic absence is `undefined`). -- **Rationale:** Proto3-derived enum naming conventions add 25+ characters of redundant prefix per call site (`RequestAuthzIdentity.REQUEST_AUTHZ_IDENTITY_USER_CONTEXT` vs `AuthzIdentity.USER_CONTEXT`). The `Request` prefix on the type name implies the enum is only valid in request contexts, but it appears as a field on `CheckPolicyRequest` only — the enum itself is a domain concept (who's the actor), not a message-shape concept. - -### 7. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:156,163,340,348` -- **Why weird:** Every request type carries `requestObjectType?: string | undefined`. The JSDoc on line 155 (and identically on 162, 339, 347) lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, clusters, cluster-policies, dashboards, database-projects, dbsql-dashboards, directories, experiments, files, genie, instance-pools, jobs, knowledge-assistants, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, supervisor-agents, vector-search-endpoints, or warehouses"`. The set is closed, well-known to the server, and stable — a perfect fit for a `RequestObjectType` enum or string literal union. The TS SDK ships it as bare `string` with no autocomplete or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) silently 4xx's at runtime. -- **Category:** 19 (underspecified ID), 1 (vague: bare `string`), 15 (generic field name). -- **Suggested name:** Define `type RequestObjectType = 'alerts' | 'alertsv2' | 'authorization' | 'clusters' | 'cluster-policies' | ...` (string literal union, 26 entries), or an `enum RequestObjectType` with kebab-cased values. The JSDoc explicitly enumerates the values; TypeScript should encode that enumeration. -- **Rationale:** This is the single biggest TS-affordance miss in the package. The Go SDK uses `string` because Go enums are second-class; TS has first-class string literal unions that match this exact use case. See also `.agent/naming-audit/grants.md` #19, #28 (same problem with `Privilege` and `SecurableType`). - ---- - -## Medium severity - -### 8. `requestObjectType` / `requestObjectId` prefix — `src/v1/model.ts:156,158,163,164,340,342,348,350` -- **Why weird:** All four request types prefix their two path parameters with `request`: `requestObjectType` and `requestObjectId`. The `request` prefix is wire-format leakage (the Databricks REST path uses `:request_object_type` and `:request_object_id` as URL path placeholders, presumably from an older API spec). On the TypeScript surface, every field is by definition part of a *request* — the `request` prefix carries zero information. -- **Category:** 7 (overly verbose / redundant prefix), 14 (wire-format leak), 15 (generic field name). -- **Suggested name:** `objectType` and `objectId`. The doc-comment on `requestObjectId` already calls it "The id of the request object" — drop the wire-format jargon and just say "object id". -- **Rationale:** Compare `GetObjectPermissionsRequest { requestObjectType, requestObjectId }` to `GetObjectPermissionsRequest { objectType, objectId }`. The latter reads as plain English. The `request` prefix is the same kind of cruft that `requestId` would have if it appeared in a `Request` type. - -### 9. `principalName` discriminated union — `src/v1/model.ts:47–63,68–84` -- **Why weird:** The discriminated union pattern is elegant in TS, but the field name `principalName` is misleading because the values inside are not all "names" — `servicePrincipalName` is documented as "application ID of a service principal" (line 60), which is a UUID, not a name. Calling the carrier field `principalName` and the SP variant `servicePrincipalName` together imply "principal name = service principal name = the SP's name", but the SP variant is the application *ID*, distinct from the SP's display name. -- **Category:** 6 (misleading), 19 (underspecified ID), 15 (overloaded "name"). -- **Suggested name:** Rename outer field to `principal` (per `grants` package convention, see #14) and rename the SP variant to `servicePrincipalApplicationId` or `servicePrincipalId`. Or document explicitly that `servicePrincipalName` is "the SP's application UUID, not its display name". -- **Rationale:** Same field name leaks "name" semantics onto a value that's a UUID. Type system can encode this with proper variant naming. - -### 10. `principalName` vs `principal` cross-package — `src/v1/model.ts:47,68` (this package) vs `grants/src/v1/model.ts:22,33,69` (grants package) -- **Why weird:** This package uses `principalName?: { $case: 'userName' | 'groupName' | 'servicePrincipalName' }` — a typed discriminated union. `grants` uses `principal: string` — a free-form string with a JSDoc-only constraint ("user email address or group name"). Same concept, two utterly different representations across sister packages. A user familiar with one will not be productive in the other. -- **Category:** 12 (duplicate concept), 17 (inconsistent shapes for the same domain object). -- **Suggested name:** Pick one across the SDK. This package's discriminated union is strictly more type-safe and should be the canonical representation. -- **Rationale:** Consistency. Two packages, two ways to spell "who is this for". The audit on `grants` (#12) flagged this from the other side. - -### 11. `displayName` on `AccessControlResponse` — `src/v1/model.ts:86` -- **Why weird:** `displayName?: string | undefined` doc-comment "Display name of the user or service principal." (line 85). But the response also carries `principalName` (line 68) which is the carrier-by-identity. Two name-like fields on the same response and the relationship is JSDoc-only. Worse, the JSDoc *doesn't* say "Display name of the user **or group** or service principal" — it omits groups, possibly because groups don't have display names — but the type allows `principalName.$case === 'groupName'` paired with a `displayName` value, which then has no specified semantics. -- **Category:** 6 (misleading), 1 (vague: groups + displayName combo undocumented). -- **Suggested name:** Keep `displayName` but expand doc-comment to cover all three principal kinds. -- **Rationale:** Cross-checking variant + display-name semantics is an integration footgun. - -### 12. `allPermissions: Permission[]` field — `src/v1/model.ts:88` -- **Why weird:** `allPermissions?: Permission[] | undefined` with JSDoc "All permissions." — minimal information value in the comment. The qualifier "all" suggests there's a "some permissions" variant that doesn't exist. Internally, the type just lists every effective permission (direct + inherited) — so the `all` prefix is the wire-format way of saying "the merged result". Stripping `all` would lose nothing. -- **Category:** 7 (overly verbose), 1 (vague qualifier), 15 (generic field name on a typed array). -- **Suggested name:** `permissions: Permission[]` (matches the type-name plural). The field would read `AccessControlResponse.permissions` — natural English. -- **Rationale:** Field names that re-state the parent type or carry vague qualifiers add noise. The `all` qualifier here implies a `some`/`partial` companion that doesn't exist. - -### 13. `Permission` type — `src/v1/model.ts:244` -- **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance of `Permission` here is really an "effective permission" — a permission level paired with inheritance metadata. The name `Permission` alone is the second-most-overloaded noun in the SDK (after `Client`). -- **Category:** 1 (vague), 12 (cross-package collision: `grants` also exports `Permission`-prefixed types). -- **Suggested name:** `EffectivePermission` (matches the doc semantics) or `PermissionGrant` (clarifies that this is a grant, not the concept of permission abstractly). -- **Rationale:** `Permission` as a standalone PascalCase noun is so common across IAM systems that it's nearly content-free without qualification. - -### 14. `PermissionsDescription` — `src/v1/model.ts:256` -- **Why weird:** Type carries `permissionLevel?: PermissionLevel | undefined` and `description?: string | undefined`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. Should be `PermissionLevelDescription` (singular). Also, the suffix `Description` is generic — the type is effectively a tuple of (level, description-text); it's the "metadata about a single permission level" record. -- **Category:** 9 (singular/plural mismatch — `Permissions` plural for a single-level descriptor), 1 (generic suffix), 15 (vague field `description: string`). -- **Suggested name:** `PermissionLevelDescription` or `PermissionLevelInfo`. -- **Rationale:** Singular/plural matters; one descriptor = one level. - -### 15. `PermissionsResponse` — `src/v1/model.ts:261` -- **Why weird:** Returned from THREE different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, `accessControlList` — i.e. it's "an ACL with metadata", not "a Permissions response". Name is generic; the *content* is the more meaningful concept ("ObjectAcl" or "AccessControlList"). -- **Category:** 1 (vague), 7 (Response suffix tautology), 20 (type-suffix tautology — `Permissions` + `Response` adds no info beyond `AccessControlList`). -- **Suggested name:** `ObjectAcl`, `ObjectPermissions`, or `AccessControlList`. Drop the `Response` suffix per the SDK-wide convention that responses are returned values, not named-as-such types. -- **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental to it being a return value. - -### 16. `accessControlList` field — `src/v1/model.ts:264,343,351` -- **Why weird:** Appears in three types (`PermissionsResponse`, `SetObjectPermissionsRequest`, `UpdateObjectPermissionsRequest`). The field is typed `AccessControlRequest[]` in the two request types and `AccessControlResponse[]` in the response — asymmetric typing under one field name. The conventional shorthand for "access control list" is "ACL" — the field could be `acl` (3 chars vs 18). Or just `entries` since the surrounding type already says "permissions" / "object permissions". -- **Category:** 7 (overly verbose), 20 (type-suffix tautology — field repeats type info), 17 (asymmetric: same field, different element types). -- **Suggested name:** `acl: AccessControlEntry[]` or `entries: AccessControlEntry[]`. -- **Rationale:** "Access control list" is verbose; "ACL" is standard. The asymmetric typing pattern is worth flattening. - -### 17. `inherited` boolean field — `src/v1/model.ts:246` -- **Why weird:** Bare `inherited?: boolean | undefined` on `Permission`. Boolean fields starting with a verb (`is*`, `has*`, `was*`) are easier to read at call sites. The current name reads `if (permission.inherited)` — fine, but `if (permission.isInherited)` is more idiomatic. -- **Category:** 14 (Go/Java-style: Go boolean fields commonly drop the `is`/`has` prefix, TS convention varies). -- **Suggested name:** `isInherited`. -- **Rationale:** Google TS Style Guide §5.3 recommends boolean prefixes for readability. The codebase uses both conventions but `is*`-prefixed booleans are more common in IAM contexts. - -### 18. `inheritedFromObject: string[]` — `src/v1/model.ts:247` -- **Why weird:** Plural field name (`Object`) typed as `string[]` of object identifiers. The "Object" suffix is singular but the type is plural — minor mismatch. More importantly, the JSDoc is missing entirely (line 247 has no comment) so the reader has to infer that this is the chain of inheritance paths from which this permission was derived. Each element is presumably an object path; the typing is bare `string`. -- **Category:** 9 (singular/plural mismatch), 19 (underspecified ID), 1 (vague — no JSDoc). -- **Suggested name:** `inheritedFromObjects: string[]` (plural for plural), or `inheritanceChain: string[]`. Document the element format. -- **Rationale:** Plurality should match the type's plurality; semantics should be JSDoc'd. - -### 19. `Client` — `src/v1/client.ts:69` -- **Why weird:** Top-level class named `Client`. Generic across every generated package. Users importing `Client` from multiple permission-adjacent packages (`@databricks/sdk-accessmanagement`, `@databricks/sdk-grants`, `@databricks/sdk-accountaccesscontrol`) must alias all three. -- **Category:** 1 (vague), 12 (cross-package name clash). -- **Suggested name:** `PermissionsClient` or `AccessManagementClient`. -- **Rationale:** SDK convention in AWS, Azure, GitHub Octokit, etc. is service-prefixed client class names. - -### 20. `requestObjectType` doc-comment duplication — `src/v1/model.ts:155,162,339,347` -- **Why weird:** Four identical 1-line doc-comments listing all 26 valid object types. The list is 280 characters long and is copy-pasted verbatim into every request type. Any change requires four parallel edits. -- **Category:** Observation, 17 (consistency — all four are identical, so this isn't an inconsistency, but it is fragile). -- **Suggested name:** Define `type RequestObjectType` (see #6) and link to it from a single source of truth. -- **Rationale:** DRY for documentation, type-safe for callers. - -### 21. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` -- **Why weird:** Four types use the proto-style nested-message underscore convention: `DeleteWorkspacePermissionAssignmentRequest_Response`, `GetPermissionLevelsRequest_Response`, `GetWorkspacePermissionAssignmentsRequest_Response`, `ListWorkspacePermissionsRequest_Response`. Each is annotated with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` — the comment explicitly admits the leak. In proto, a `Response` message can be declared inside the `Request` message, yielding the path `Foo.Request.Response`; the generator flattens this to `FooRequest_Response`. The underscore is wire-format leakage. The corresponding zod schemas (`unmarshalDeleteWorkspacePermissionAssignmentRequest_ResponseSchema`, etc.) carry the same wart at `model.ts:441,454,466,488`. -- **Category:** Proto-architecture leak (underscore-nested proto-message naming), 17 (inconsistent: most response types in this package are top-level `*Response`, only these four use the nested form). -- **Suggested name:** Top-level `DeleteWorkspacePermissionAssignmentResponse`, `GetPermissionLevelsResponse`, `GetWorkspacePermissionAssignmentsResponse`, `ListWorkspacePermissionsResponse`. Remove the `eslint-disable` annotations once renamed. -- **Rationale:** TypeScript has no concept of nested message types; the underscore separator is a proto-specific path encoding. Every consumer importing these types must hand-type the underscore. Same problem flagged generator-wide in `.agent/naming-audit/_SUMMARY.md` (drop `_Response` underscore suffix). - -### 22. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:250,268,383` -- **Why weird:** Three types ending with `Output`. In proto / gRPC service definitions, message types are commonly named `FooInput` (request) and `FooOutput` (response) — the `Output` suffix is the proto-RPC naming pattern. On the TypeScript surface, `Output` is meaningless: every value is "output" of *something* (a function call, a marshal, a parse). The package uses `Request`/`Response` as the standard envelope suffix and only these three types break the pattern. -- **Category:** Proto-architecture leak (`Output` suffix is proto-RPC convention), 17 (inconsistent: `Request`/`Response` elsewhere, `Output` on these three). -- **Suggested name:** `WorkspacePermission` (already taken by the enum — pick a different domain noun like `WorkspacePermissionDescription`), `Principal`, `WorkspacePermissionAssignment`. Drop the `Output` suffix; the types are concrete domain entities, not RPC payloads. -- **Rationale:** `Output` is wire-format jargon. Compare `principal: PrincipalOutput` to `principal: Principal` — the latter reads as plain English. - -### 23. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` -- **Why weird:** Three methods carry the `Proxy` suffix and are byte-for-byte identical to their non-`Proxy` siblings (lines 218, 292, 366). They issue the same HTTP request to the same URL with the same headers. The `Proxy` suffix communicates an architectural concept — these are the same operation routed through a proxy server in the Databricks control plane — that has zero meaning for a TypeScript SDK caller. From the SDK's perspective, the two methods are indistinguishable. -- **Category:** Proto-architecture leak (`Proxy` suffix mid/end-position is backend-routing jargon, not domain), 12 (duplicate concept: two methods, one operation), 17 (inconsistent: most operations have one method, these have two). -- **Suggested name:** Delete the `*Proxy` variants entirely. If the proxy-routing distinction matters server-side, the server can route the same URL internally; the client should not surface it. If only one variant is the "canonical" one, document that and remove the duplicate. -- **Rationale:** Method-name suffixes should describe what the operation does, not how the server routes it. Two identical methods with a `Proxy` differentiator force every caller to flip a coin. - -### 24. `RuleSetUpdateRequest` — `src/v1/model.ts:322` -- **Why weird:** The verb `Update` appears mid-name; the same package's convention elsewhere is `UpdateRequest` (see `UpdateRuleSetRequest` on line 354, `UpdateWorkspacePermissionAssignmentRequest` on line 362, `UpdateObjectPermissionsRequest` on line 346). `RuleSetUpdateRequest` swaps the verb to a mid-position attributive — likely because in proto, `RuleSetUpdateRequest` is the *body* type carrying the patch payload, while `UpdateRuleSetRequest` is the *RPC* envelope carrying both the routing path and the body. The `Update` mid-position is wire-format leakage from the proto `UpdateRuleSetRequest { string name; RuleSetUpdateRequest rule_set; }` shape. From the TS surface, two `Update`-something types in the same file with different positions of `Update` is jarring. -- **Category:** Proto-architecture leak (mid-position action verb from proto request-envelope/body split), 17 (inconsistent naming with the same-package `Update*Request` types). -- **Suggested name:** `RuleSetUpdate` (a patch object), or fold the fields into `UpdateRuleSetRequest` directly and remove the inner envelope. -- **Rationale:** The proto convention of "outer RPC request + inner body message" doesn't translate to TS — you can just put all fields on one request type. The `*UpdateRequest` mid-position verb only exists because of that envelope split. - -### 25. `flattenQueryParams` (utility) — `src/v1/utils.ts:123` -- **Why weird:** Generic generated helper exported into every package. Now used by `checkPolicy` (`client.ts:536,545,555`), so no longer a dead export here. Still suffers the same problem documented in `.agent/naming-audit/grants.md` #37: the helper is identical across packages and should live in a shared `@databricks/sdk-core` module rather than be re-emitted per package. -- **Category:** 11 (effectively-internal exports), Observation. -- **Suggested name:** Move to a shared `@databricks/sdk-core` util; keep name `flattenQueryParams` (already descriptive). -- **Rationale:** Generator emits the same helper into every package; consolidation reduces surface and tree-shake risk. - ---- - -## Low severity - -### 26. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` -- **Why weird:** `Segment` is a generic word; the constant carries User-Agent identity but the name communicates nothing. Same wart appears in every generated package. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Cross-package consistency. - -### 27. `readAll` (utility) — `src/v1/utils.ts:40` -- **Why weird:** Internal helper name generic to the point of meaninglessness; clashes cognitively with `Array.prototype` methods and Web Streams APIs. Same pattern called out in `.agent/naming-audit/grants.md` #38. The function name is also a direct Go-port of `io.ReadAll`. -- **Category:** 1 (vague), 14 (Go-style). -- **Suggested name:** `readStreamToEnd`, `drainStream`, or `bufferStream`. -- **Rationale:** Cross-package consistency. - -### 28. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Another `Options`-suffixed type; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. -- **Category:** 1 (vague suffix), 17 (inconsistent — internal struct shouldn't share a suffix with the user-facing CallOptions). -- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). -- **Rationale:** Distinguish internal context bags from user-facing option structs. Same finding as `grants.md` #40. - -### 29. `updateObjectPermissions` uses PATCH but the type says "Update" — `src/v1/client.ts:500,513` -- **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 513). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. A user reading both method names side-by-side (`set...` and `update...`) might reasonably assume both perform full replacement. -- **Category:** 17 (inconsistent action verbs), Observation. -- **Suggested name:** `patchObjectPermissions` for the PATCH method, OR explicit JSDoc on `update*` clarifying merge semantics. -- **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. - ---- - -### 30. `kind` discriminated-union field on `Actor` — `src/v1/model.ts:96` -- **Why weird:** `Actor.kind?: { $case: 'actorId'; actorId: number } | undefined` — the `kind` field name is a direct port of the proto `oneof kind { ... }` block convention. In proto, every `oneof` block has a developer-supplied name (commonly `kind`, `value`, or `data`); the convention bleeds straight into the generated TS as a field literally named `kind`. With a single-variant union (only `actorId`), the entire discriminator is dead weight — there's nothing else it could be. -- **Category:** Proto-architecture leak (`oneof` block name `kind` carried verbatim), 1 (vague). -- **Suggested name:** Flatten to `actorId?: number | undefined` directly on `Actor`. If a future variant gets added, then introduce a discriminated union with a meaningful discriminator name (e.g., `principal` per #10 — `userName`, `groupName`, `servicePrincipalName`). -- **Rationale:** A single-variant discriminated union is a proto modeling artifact, not a domain concept. - ---- - -## Observations - -### 31. Three response paths converge on `PermissionsResponse` -`getObjectPermissions`, `setObjectPermissions`, and `updateObjectPermissions` all return the same `PermissionsResponse` type (`client.ts:424,477,503`). This is fine functionally but means callers can't distinguish "the state I just wrote" from "the state I just read" by type — only by which method was called. For an audit log or comparison flow, this loses information. Naming-adjacent because the type carries no read/write/post-update distinction. -- **Category:** Observation. - -### 32. Doc-comment list of object types is potentially stale -The hardcoded list in `requestObjectType` doc-comments includes `database-projects`, `genie`, `knowledge-assistants`, `supervisor-agents` — all relatively new product surfaces. The list will need updating with every new permission-able workspace object. As-is the SDK has 26; if not regularly synced with the server, the JSDoc will drift. -- **Category:** Observation. - -### 33. No pagination — all methods are unpaginated single-call -Unlike `grants` (which has both unpaginated `Get*` and paginated `List*` methods, see `grants.md` #41), the permissions surface has no listing operation over workspace objects. Every method here is by-object-id; there's no "list all permissioned objects" surface. This is correct for the API but worth noting because users coming from `grants` (or `accountaccesscontrol`) might expect parallel list semantics. Naming-adjacent because the absence of `list*` here aligns the method-vocabulary differently than its sibling packages. -- **Category:** Observation. - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md index 92503d44..db816e2f 100644 --- a/.agent/naming-audit/qualitymonitor.md +++ b/.agent/naming-audit/qualitymonitor.md @@ -1,189 +1,3 @@ # Naming Audit: qualitymonitor -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/qualitymonitor/src/v2/` -**Versions audited:** v2 -**Inferred domain:** Quality monitoring on Unity Catalog objects (currently only `schema`). The package defines a single `QualityMonitor` entity that wraps `AnomalyDetectionConfig` (last-run telemetry plus excluded tables) and a list of `ValidityCheckConfiguration` arms (percent-null, range, uniqueness). Every operation is marked `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., this entire package is a deprecated shim that has been superseded by the `dataquality` package. -**Total weird names flagged:** 24 - -## Summary -| Severity | Count | -| --- | --- | -| High | 7 | -| Medium | 6 | -| Low | 8 | -| Observation | 3 | - - -## CRITICAL: Two packages, same domain -This package (`@databricks/sdk-qualitymonitor`, exporting `./v2`) and its sibling `@databricks/sdk-qualitymonitors` (plural, exporting `./v1`) **both exist** in this repo. They model overlapping data-quality concepts but with completely different shapes: -- `qualitymonitor` (singular, v2): schema-level monitor with `AnomalyDetectionConfig` and a list of `ValidityCheckConfiguration` arms. Wire path: `/api/2.0/quality-monitors`. -- `qualitymonitors` (plural, v1): table-level monitor with `DataMonitorInfo`, `Refresh` runs, `MonitorCronSchedule`, etc. Wire path: `/api/2.1/unity-catalog/tables/{full_table_name_arg}/monitor`. - -The singular-vs-plural naming gives the reader no hint that these are different APIs over different UC resource types. Worse, both clients are deprecated in favour of the newer `dataquality` package (`/api/data-quality/v1/monitors`). Three packages, three vocabularies, one underlying business problem. - -**Category:** 9 (singular/plural mismatch in a sibling), 12 (duplicate concept across packages), 6 (misleading — the singular/plural distinction does not communicate the actual API split). - -**Recommendation:** Consolidate or rename. Possible options: (a) collapse both into `dataquality` (which is the deprecation target anyway) and remove the two deprecated packages from the SDK surface; (b) if both must be kept temporarily, rename to `qualitymonitorschema` (singular focuses on schemas) and `qualitymonitortables` (plural focuses on tables) so the directory name encodes the resource type, not a grammatical accident; (c) at minimum, surface a top-level `@deprecated` JSDoc on the `Client` class and on every exported type that points to `@databricks/sdk-dataquality`. None of the three options is done today. - -## High severity - -### 1. Package directory name `qualitymonitor` (singular) vs sibling `qualitymonitors` (plural) — repo layout -- **Why weird:** Two npm packages, two different sub-APIs, distinguished only by an `s`. A user with both installed will tab-complete `@databricks/sdk-qualitymonitor` and `@databricks/sdk-qualitymonitors` and have no obvious way to tell them apart from the import alone. The singular/plural form does not encode anything semantic (the singular package also returns lists of monitors; the plural package also returns single monitors). -- **Category:** 9 (singular/plural mismatch as the only differentiator), 1 (vague — neither name conveys the schema-vs-table split), 12 (duplicate concept). -- **Suggested name:** Rename one or both packages so the difference is on a meaningful dimension. Candidates: `qualitymonitor-schema` + `qualitymonitor-table`, or fold both into `dataquality` and delete these two. -- **Rationale:** Sibling packages must be distinguishable from the import string. Pluralisation alone is not enough. - -### 2. `Client` class — `src/v2/client.ts:41` -- **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing both `@databricks/sdk-qualitymonitor` and `@databricks/sdk-qualitymonitors` (very likely during migration off the deprecated APIs) cannot import both as `Client`. The package name does namespace via the import path, but in IDE go-to-symbol the name appears unqualified — every audited package in this SDK has the same `Client` collision. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). -- **Suggested name:** `QualityMonitorClient`. -- **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but especially acute here because three sibling packages (this, `qualitymonitors`, `dataquality`) all expose `Client`. - -### 3. `ListQualityMonitorRequest` / `ListQualityMonitorResponse` / `listQualityMonitor` — `src/v2/model.ts:44-52`, `src/v2/client.ts:152` -- **Why weird:** Singular noun on a list operation. The response holds `qualityMonitors?: QualityMonitor[]` (plural), and the wire path is `/api/2.0/quality-monitors` (plural) — every concrete signal is plural; only the type/method name uses the singular `QualityMonitor`. Same singular-on-list bug as `dataquality` finding #1. -- **Category:** 9 (singular/plural mismatch). -- **Suggested name:** `ListQualityMonitorsRequest` / `ListQualityMonitorsResponse` / `listQualityMonitors`. -- **Rationale:** REST conventions, the package's own field naming (`qualityMonitors`), and the URL path all use plural. The singular form is generator template noise. - -### 4. `QualityMonitor.objectType` + `QualityMonitor.objectId` — `src/v2/model.ts:62-65` (and copied into 3 request types) -- **Why weird:** `objectType` is a free-form `string` typed as values like `"schema"` (JSDoc says "Can be one of the following: schema." — one option in a one-element set is barely an enumeration). The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("the uuid of the request object. For example, schema id."). This is a stringly-typed sum type with one current arm. Four separate types (`QualityMonitor`, `DeleteQualityMonitorRequest`, `GetQualityMonitorRequest`, `UpdateQualityMonitorRequest`) all duplicate these two fields with copy-pasted JSDoc. -- **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). -- **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string}`. With one arm today, a literal type `objectType: 'schema'` plus `schemaId: string` is enough. -- **Rationale:** TypeScript's strength is exhaustive discriminated unions. Leaving these as `string` defeats the type system and forces every caller to read the JSDoc. The "could be one of: schema" doc text strongly hints that the API team plans to add more arms — the type should be ready for them. - -### 5. `QualityMonitor.objectId` doc text "The uuid of the request object" — `src/v2/model.ts:65` -- **Why weird:** `QualityMonitor` is the response shape too (the GET handler returns it), but the JSDoc says "uuid of the **request** object" — wording that is right only for the request types. Field is also typed `string` with no UUID brand. JSDoc says "For example, schema id" — example-driven docs on a stringly-typed field are a smell. -- **Category:** 6 (misleading — doc refers to request when type is dual-purpose), 19 (underspecified — `Id` says nothing about UUID format). -- **Suggested name:** Doc: "The UUID of the monitored object (e.g. the schema's `schema_id`)." Field: rename to `schemaId` once #4 is applied. -- **Rationale:** Doc-style accuracy and signalling that the value is a UUID. - -### 6. `AnomalyDetectionRunStatus` value `WORKSPACE_MISMATCH_ERROR` overlap with `FAILED` — `src/v2/model.ts:6-15` -- **Why weird:** Both `FAILED` and `WORKSPACE_MISMATCH_ERROR` are error states with no documented distinction — a caller writing exhaustive status handling has to guess whether one is a sub-state of the other. The trailing `_ERROR` suffix on `WORKSPACE_MISMATCH_ERROR` is also dead context: every terminal-failure status here is by definition an error outcome. -- **Category:** 12 (likely duplicate concept — two indistinguishable error states), 18 (redundant suffix on the jargon value `WORKSPACE_MISMATCH_ERROR`). -- **Suggested name:** Rename the member jargon to `WORKSPACE_MISMATCH` (drop the redundant `_ERROR`). Resolve whether `FAILED` and `WORKSPACE_MISMATCH` are siblings or whether the latter is a `FAILED` sub-state. -- **Rationale:** Two members that both mean "the run errored" without documented separation is a real type-modelling gap; the `_ERROR` tail just compounds it. - -### 7. `ValidityCheckConfiguration.name` JSDoc "Can be set by system. Does not need to be user facing." — `src/v2/model.ts:94-95` -- **Why weird:** A field whose own JSDoc admits it "does not need to be user facing" — yet it is part of the public TS type. The doc is also self-contradictory: "Can be set by system" implies output-only, but the field is plain optional (no `@readonly`). A user reading this has no idea whether to set it, what it does, or whether the server will ignore it. -- **Category:** 1 (vague — `name` is generic), 6 (misleading — output-only not typed as such), 15 (generic field name on a non-public-facing concept). -- **Suggested name:** Rename to `internalName` (matches the JSDoc), or mark with `@readonly` and rename to `systemAssignedName`. -- **Rationale:** Public types should not contain "system-set, not user-facing" fields without clear scoping. - -## Medium severity - -### 8. `AnomalyDetectionConfig.lastRunId` and `.latestRunStatus` (`Last` vs `Latest`) — `src/v2/model.ts:19,21` -- **Why weird:** Two adjacent fields use different superlative adjectives for the same concept: `lastRunId` and `latestRunStatus`. Both refer to the most recent run. JSDoc reinforces the mismatch: "Run id of the last run of the workflow" and "The status of the last run of the workflow." — same noun, different field-name modifier. -- **Category:** 17 (inconsistent vocabulary), 12 (duplicate concept across siblings). -- **Suggested name:** Pick one. `lastRunId` + `lastRunStatus`, or `latestRunId` + `latestRunStatus`. -- **Rationale:** Sibling fields describing properties of the same entity should use the same word. - -### 9. `AnomalyDetectionConfig.excludedTableFullNames` — `src/v2/model.ts:23` -- **Why weird:** Same as `dataquality` finding #19. "Full names" is jargon; the JSDoc says "fully qualified table names". The shorter form drops the qualifying word that gives the name its meaning. Other Databricks SDK packages use `fullName` consistently for UC three-part names — here the suffix is `FullNames` (plural of FullName), making this the only field that says "full" then "names". -- **Category:** 1 (vague — "full" alone is generic), 5 (abbreviated jargon). -- **Suggested name:** `excludedTables` (since the values are by definition UC fully-qualified table names), or document the format in JSDoc. -- **Rationale:** Across the SDK, `fullName` is well-known UC vocabulary. The field at minimum should be `excludedTableFullyQualifiedNames` for accuracy, or `excludedTables` for brevity. - -### 10. `PercentNullValidityCheck.upperBound` doc "Optional upper bound; we should use auto determined bounds for now" — `src/v2/model.ts:57` -- **Why weird:** Doc text reads like an internal TODO ("we should use auto determined bounds for now"). The "we" is the API team; "for now" implies the field's semantics are in flux. Public SDK documentation should be definitive, not provisional. Also: field is typed `number` with no unit hint — is this 0-100 or 0-1? -- **Category:** 6 (misleading — provisional doc text in a stable type), 1 (vague — `upperBound` of what units? percentage? fraction?). -- **Suggested name:** Field stays; doc should clarify units ("Optional upper bound on the null-percentage (0-100). If unset, the server auto-determines a bound."). Strip the internal TODO. -- **Rationale:** Doc-style cleanliness and unit precision. - -### 11. `PercentNullValidityCheck.columnNames` (and `RangeValidityCheck.columnNames`, `UniquenessValidityCheck.columnNames`) — `src/v2/model.ts:56,73,82` -- **Why weird:** Three sibling check types each have an independent `columnNames: string[]` field with the same shape and meaning ("the columns to check"). Each carries its own near-identical JSDoc. The three checks could share a base type or a single field, but the wire-driven type model duplicates them. -- **Category:** 12 (duplicate concept across siblings). -- **Suggested name:** Either extract a `BaseValidityCheck { columnNames: string[] }` parent, or accept the duplication (one-line JSDoc each). Generator-emitted. -- **Rationale:** DRY at the type level; per-arm doc cost is small. - -### 12. Method `listQualityMonitor` doc text "(Unimplemented) List quality monitors." — `src/v2/client.ts:150,204` -- **Why weird:** The method is implemented (has a complete body that constructs a URL, paginates, calls the server) — but the JSDoc literally says `(Unimplemented)`. Either (a) the server side is unimplemented and the doc is propagating a server-side TODO, or (b) this is a stale doc from when the method was a stub. Same comment appears on `updateQualityMonitor` (line 204: "(Unimplemented) Update a quality monitor on UC object.") — but the body of `updateQualityMonitor` is a complete `PUT` call. -- **Category:** 6 (misleading — body says implemented, doc says unimplemented). -- **Suggested name:** N/A. Fix the doc — either drop "(Unimplemented)" or move it to a server-side `@throws NotImplemented` annotation. -- **Rationale:** Method docs that lie about implementation status are worse than no docs. - -### 13. `Deprecated:` JSDoc tag style — `src/v2/client.ts:67,99,121,149,203` -- **Why weird:** Every method JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (...)` — but the TS-standard JSDoc tag is `@deprecated`. The text is in the description body, not in the tag, so IDEs that read `@deprecated` (VS Code, TS LSP) will not strike through these methods or warn the user. The deprecation is documented but not enforced. -- **Category:** 14 (Go-style — Go doc comments use a leading word like "Deprecated:" by convention; TS uses `@deprecated`), 6 (misleading — looks deprecated but does not surface as deprecated in tooling). -- **Suggested name:** Use `@deprecated Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` so IDE tooling strikes through call sites. -- **Rationale:** A whole package marked deprecated should advertise the deprecation through TS conventions, not Go conventions. - -## Low severity - -### 14. `flattenQueryParams` exported but unused — `src/v2/utils.ts:123` -- **Why weird:** Exported helper that is never called from `client.ts`. The package's one list endpoint handles pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. Same as `dataquality` finding #35. -- **Category:** 6 (misleading — looks like it's used; isn't). -- **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). -- **Rationale:** Same as other audited packages. - -### 15. `executeCall` vs `executeHttpCall` — `src/v2/utils.ts:26,65` -- **Why weird:** Layering not visible from names; identical to `dataquality` finding #36. -- **Category:** 1, 12, 17. -- **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). -- **Rationale:** Layering should be readable from the names without opening the source. - -### 16. `HttpCallOptions` — `src/v2/utils.ts:15` -- **Why weird:** Same as `dataquality` finding #40; internal context bag called `Options`. -- **Category:** 1, 8. -- **Suggested name:** `HttpCallContext`. -- **Rationale:** Reserve `Options` for user-tunable knobs. - -### 17. `PACKAGE_SEGMENT` — `src/v2/client.ts:36` -- **Why weird:** Same as `dataquality` finding #41; unspecific noun for a User-Agent identity object. -- **Category:** 1. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Add the missing domain word. - -### 18. `Call` type + `call` variable — `src/v2/client.ts:80, 107, 130, 167, 216` -- **Why weird:** Same as `dataquality` finding #42; variable named `call` of type `Call` repeated 5 times across the client. -- **Category:** 1, 12. -- **Suggested name:** `request` (variable) — reserve `Call` for the type. -- **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. - -### 19. `req.objectType ?? ''` / `req.objectId ?? ''` URL composition — `src/v2/client.ts:106, 128, 210` -- **Why weird:** Same as `dataquality` finding #43 — `objectType`/`objectId` typed optional but required in practice for the URL path. Silently substitutes empty string producing malformed URLs like `/api/2.0/quality-monitors//`. Three call sites here. -- **Category:** 6. -- **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. -- **Rationale:** Type shape should match runtime requirement. - -### 20. `respBody` vs `resp` — `src/v2/client.ts:84-95, 134-145, 171-182, 220-231` -- **Why weird:** Same as `dataquality` finding #44; two variables differ by `Body` only. -- **Category:** 5, 17. -- **Suggested name:** `rawBody` + `result`. -- **Rationale:** Distinguish by meaningful nouns. - -### 21. `httpReq` local — `src/v2/client.ts:83, 110, 133, 170, 219` -- **Why weird:** Same as `dataquality` finding #45. -- **Category:** 5, 12. -- **Suggested name:** `httpRequest` (no abbreviation). -- **Rationale:** Avoid two `req`-rooted identifiers in the same scope. - -## Observations - -### 22. Action verbs in `Client` -The client uses `Create` / `Get` / `Update` / `Delete` / `List` for monitor operations. Verbs are consistent within the package. Listed per rule 17 to note the absence of inconsistency (relative to `qualitymonitors` plural, which adds `Cancel` / `Run` / `Regenerate`). - -### 23. `qualitymonitor` lowercase package name vs `quality-monitors` wire path vs `QualityMonitor` types -Same shape as the `dataquality` casing observation: directory is one collapsed word (`qualitymonitor`), wire path is kebab-plural (`/quality-monitors`), TS types are PascalCase singular (`QualityMonitor`). The directory plural-vs-singular question (relative to `qualitymonitors`) is unique to this package family. -- **Category:** 3 (casing inconsistency), 9 (singular/plural mismatch). - -### 24. Entire package is `@deprecated` per JSDoc -Every method's JSDoc starts with `Deprecated: Use Data Quality Monitoring API instead (/api/data-quality/v1/monitors).` — i.e., the package itself should not be used in new code. The TS surface does not surface this with `@deprecated` tags (#13), so IDE tooling does not strike through call sites. This is the single most important fact about this package and it is documented only inside method bodies. - -## Domain glossary -- `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema). -- `quality monitor` — the long-lived configuration entity (one per UC schema) holding anomaly-detection config and validity checks. -- `anomaly detection` — periodic workflow that compares incoming data against historical patterns to flag anomalies. -- `validity check` — an input-data constraint (null %, range, uniqueness) evaluated during anomaly detection. -- `run status` — eight-value lifecycle: `RUNNING`, `PENDING`, `CANCELED`, `SUCCESS`, `FAILED`, `JOB_DELETED`, `WORKSPACE_MISMATCH_ERROR` (+ sentinel `UNKNOWN`). -- `object type` / `object id` — stringly-typed reference to a UC object (currently always a schema). -- `refresh`, `monitor cron schedule`, `dashboard`, `notifications`, `data classification config` — none of these appear in this package; they all live in the sibling `qualitymonitors` (plural, v1) package. - -## File coverage -- `src/v2/model.ts` (317 lines): read fully. -- `src/v2/client.ts` (233 lines): read fully. -- `src/v2/utils.ts` (150 lines): read fully. -- `src/v2/index.ts` (21 lines): read fully. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md index c71bdb2d..7f4373d9 100644 --- a/.agent/naming-audit/qualitymonitors.md +++ b/.agent/naming-audit/qualitymonitors.md @@ -1,352 +1,3 @@ # Naming Audit: qualitymonitors -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/qualitymonitors/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Lakehouse Monitoring on Unity Catalog tables (legacy/deprecated surface). The package models a `Monitor` per UC table with an `analysisConfig` chosen from `InferenceLog` / `TimeSeries` / `Snapshot`, scheduled refreshes (`Cancel` / `Get` / `List` / `Run`), Quartz cron scheduling, custom metric definitions (`Aggregate`/`Derived`/`Drift`), data classification toggles, dashboard regeneration, and notification routing on failure and on new classification tags. **Every** client method JSDoc starts with "Deprecated: Use Data Quality Monitors API instead (/api/data-quality/v1/monitors)" — this entire package is a deprecated wire-compatible facade for the `dataquality` package. -**Total weird names flagged:** 50 - -## CRITICAL: TWO co-existing packages with the same domain - -Three packages in this repository overlap on the same domain at the wire level: - -| Package directory | npm name | Version(s) | Wire path | Resource type | Domain object | -| --- | --- | --- | --- | --- | --- | -| `qualitymonitors` (plural, **this audit**) | `@databricks/sdk-qualitymonitors` | v1 | `/api/2.1/unity-catalog/tables/{name}/monitor` and `/api/2.1/quality-monitoring/...` | `DataMonitorInfo` | `Monitor` (per UC table) | -| `qualitymonitor` (singular) | `@databricks/sdk-qualitymonitor` | v2 | undetermined (anomaly-detection oriented) | `QualityMonitor` | `QualityMonitor` (per UC schema, anomaly detection) | -| `dataquality` | `@databricks/sdk-dataquality` | v1 | `/api/data-quality/v1/monitors` | `Monitor` | `Monitor` (per UC schema or table, both flavours) | - -**Why this matters:** - -1. **Singular/plural mismatch between packages.** Every other package in this repo (e.g. `apps`, `alerts`, `clusters`, `jobs`) uses plural for the package name. The fact that we have *both* `qualitymonitor` and `qualitymonitors` co-existing is a violation of any consistent convention. One of them is wrong. (Audit-rule category 9: singular/plural mismatch at the package level.) -2. **Domain duplication.** `dataquality` is documented in its own client JSDoc as the *replacement* for `qualitymonitors`. Both packages are exported to users today. A consumer of the SDK who installs `@databricks/sdk-qualitymonitors` and `@databricks/sdk-dataquality` gets two `Client` classes for the same domain with subtly different shapes. -3. **Three names for the "monitor" entity in three sibling packages.** `qualitymonitors.DataMonitorInfo`, `qualitymonitor.QualityMonitor`, `dataquality.Monitor`. The same wire concept (a monitor on a UC table) is named three different ways across the SDK. (Audit-rule category 12: duplicate concept, surfaced across packages.) -4. **All client methods in this package carry a "Deprecated" prefix in their JSDoc.** Yet the package is shipped, exported from `index.ts`, and has its own client class — a deprecation marker in the doc string is not a TypeScript-level deprecation. There is no `@deprecated` JSDoc tag, so editors will not flag usage. - -**Recommendation:** Decide on one package name and merge / dual-publish. Rename `qualitymonitors` → either retired (and `dataquality` becomes the sole source of truth) or renamed to `qualitymonitorslegacy`. The current state is the worst of all worlds: two near-identical packages with names that differ by a single letter, neither flagged as deprecated at the TS level. - -## Summary -| Severity | Count | -| --- | --- | -| High | 10 | -| Medium | 24 | -| Low | 10 | -| Observation | 6 | - -## High severity - -### 1. Package name `qualitymonitors` collides with sibling `qualitymonitor` (singular) -- **Why weird:** Two npm packages, `@databricks/sdk-qualitymonitors` and `@databricks/sdk-qualitymonitor`, both ship from this repository, on different versions (v1 vs v2), differing by one trailing `s`. The two packages handle overlapping wire surfaces (this one targets UC tables; the singular targets UC schemas with anomaly detection). A package consumer scanning npm sees two near-identical names with no human-readable cue as to which to pick. -- **Category:** 9 (singular/plural mismatch — at the package boundary), 12 (duplicate concept). -- **Suggested name:** Pick one (`qualitymonitor` or `qualitymonitors`) and consolidate. If both must remain, rename this one to `qualitymonitorslegacy` to make the deprecation visible at the package boundary. -- **Rationale:** Package-level naming is the first cue a user gets. Singular vs plural in two npm names is a UX trap. - -### 2. `DataMonitorInfo` — `src/v1/model.ts:213` -- **Why weird:** The package's central response type is named `DataMonitorInfo`, but no other domain type in the package uses the `Data` prefix. The companion request types are now `CreateMonitorRequest`, `UpdateMonitorRequest`, `DeleteMonitorRequest`, `GetMonitorRequest` — they all carry the `Request` suffix and the `Monitor` noun, but the response alone is `DataMonitorInfo`, with `Data` and `Info` as filler. -- **Category:** 1 (vague — `Data` and `Info` are noise), 8 (redundant suffix — `Info`), 17 (inconsistent — every other monitor type in the package uses the `Monitor` stem; only this one prepends `Data` and appends `Info`), 20 (type-suffix tautology — `Info` adds no semantic content). -- **Suggested name:** `Monitor`. -- **Rationale:** Every API in the client (`createMonitor`, `getMonitor`, `updateMonitor`) returns this type. Naming it `Monitor` aligns with the API verbs and with the sister `dataquality` package which already calls it `Monitor`. The `Data` and `Info` syllables are dead context. - -### 3. `Client` class — `src/v1/client.ts:57` -- **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing two SDK packages (e.g., `@databricks/sdk-qualitymonitors` and `@databricks/sdk-dataquality`) cannot import both as `Client` without aliasing. There is no domain word in the name. The same problem exists across the entire generator and is called out in every audit, but it is especially acute here because two packages with similar names ship the same class name. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). -- **Suggested name:** `QualityMonitorsClient` (or, after consolidation per #1, `QualityMonitorClient`). -- **Rationale:** Cross-package import collisions force users to alias. - -### 4. `fullTableNameArg` field — `src/v1/model.ts:95,107,286,302,307,334,379,399,423` -- **Why weird:** The field name carries the `_Arg` suffix which is a generator artefact — the doc clarifies "This field corresponds to the {full_table_name_arg} arg in the endpoint path." `Arg` is a proto convention for "this is a URL path parameter, not a body field." In TS the body/path distinction is invisible to the caller; the suffix leaks the wire model. The same field appears identically in 9 of the 13 request types in the package, copy-pasted with the same JSDoc. -- **Category:** 5 (cryptic abbreviation — `Arg` for "argument"), 15 (generic naming via `Arg`). -- **Suggested name:** `tableFullName` (matches the rest of the SDK's UC fully-qualified name convention; e.g. `dataquality.AnomalyDetectionConfig.excludedTableFullNames`). -- **Rationale:** The `Arg` suffix advertises a wire artefact that has zero meaning at the TypeScript boundary. `tableFullName` is the established UC vocabulary across the SDK for three-part `catalog.schema.table` references. - -### 5. `ProblemType` enum — `src/v1/model.ts:30-34` -- **Why weird:** `ProblemType` is a generic name for "what kind of ML problem is this table's data about". Without the JSDoc on `InferenceLogAnalysisConfig.problemType` ("Problem type the model aims to solve"), the reader cannot tell that `ProblemType` is ML-specific (vs the more general English meaning of "problem"). Sibling `dataquality` package uses `InferenceProblemType` for the same concept. -- **Category:** 1 (vague — `ProblemType` is generic), 17 (inconsistent across sibling packages). -- **Suggested name:** `InferenceProblemType` (matches `dataquality.InferenceProblemType`). -- **Rationale:** The generic `ProblemType` could mean anything outside ML. Cross-package parity with `dataquality` is the second motivation. - -### 6. `RefreshState` enum + sentinel `UNKNOWN` vs `_UNSPECIFIED` elsewhere — `src/v1/model.ts:37-66` -- **Why weird:** Three flavors of "unset" sentinel coexist in this one file: `_UNSPECIFIED` (3 enums), `UNKNOWN` (1 enum, this one), `UNKNOWN_TRIGGER` (1 enum, `RefreshTrigger`). A user writing `if (refresh.state === RefreshState.UNKNOWN)` and `if (refresh.trigger === RefreshTrigger.UNKNOWN_TRIGGER)` in the same code block has to remember that the second has a suffix and the first does not. -- **Category:** 17 (inconsistent sentinel naming across sibling enums). -- **Suggested name:** Pick one sentinel name and apply uniformly across the file (either `_UNSPECIFIED` everywhere or `UNKNOWN` everywhere). -- **Rationale:** Sentinel-name consistency across sibling enums in the same file. - -### 7. `RefreshTrigger.UNKNOWN_TRIGGER` — `src/v1/model.ts:73` -- **Why weird:** The "unset" sentinel is uniquely named `UNKNOWN_TRIGGER`, while sibling `RefreshState` uses `UNKNOWN` and the proto-prefixed enums use `_UNSPECIFIED`. Three different unset-sentinel conventions in this one file. -- **Category:** 17 (inconsistent sentinels). -- **Suggested name:** Align with the sentinel chosen in #6. -- **Rationale:** Same as #6 — sentinel consistency. - -### 8. `SchedulePauseStatus` — `src/v1/model.ts:84-88` -- **Why weird:** Three-value enum (`UNSPECIFIED`, `UNPAUSED`, `PAUSED`) for a binary on/off concept. Sibling `dataquality.CronSchedulePauseStatus` has the same shape and was flagged there. Boolean would suffice. The `UNSPECIFIED` sentinel also has no clear semantics (is a schedule with `pauseStatus = UNSPECIFIED` running or stopped?). -- **Category:** 11 (trivial enum where boolean would suffice). -- **Suggested name:** Collapse to `paused?: boolean` on `MonitorCronSchedule`. -- **Rationale:** "Paused" is binary. Other packages (`jobs`, `alerts`) already use `paused: boolean`. - -### 9. `analysisConfig` discriminated union with `$case` discriminator — `src/v1/model.ts:122-135,221-234,432-444` -- **Why weird:** Same shape as `dataquality.DataProfilingConfig.analysisConfig` (audit #10 in that package). The field is named `analysisConfig`, but its arms are types named `InferenceLogAnalysisConfig`, `TimeSeriesAnalysisConfig`, `SnapshotAnalysisConfig` — three names ending in `AnalysisConfig`. The discriminator is `$case`, the arm key matches the arm payload type's prefix (e.g., `inferenceLog` for `InferenceLogAnalysisConfig`). Naming the variants `$case` is a ts-proto convention foreign to TypeScript culture; the more idiomatic discriminator is `kind` or `type`. -- **Category:** 1 (vague — `$case` is unusual TS), 12 (duplicate concept — `AnalysisConfig` repeated 3 times), 20 (type-suffix tautology — `AnalysisConfig` on every arm). -- **Suggested name:** Field name: `analysis`. Discriminator: `kind: 'inferenceLog' | 'timeSeries' | 'snapshot'`. Arm payloads: keep `InferenceLogAnalysisConfig` or rename to `InferenceLogAnalysis` / `TimeSeriesAnalysis` / `SnapshotAnalysis`. -- **Rationale:** `$case` is a ts-proto idiom; in idiomatic TS you write `if (config.analysis.kind === 'inferenceLog')`, not `if (config.analysisConfig?.$case === 'inferenceLog')`. - -### 10. `CreateMonitorRequest`, `UpdateMonitorRequest`, `DataMonitorInfo` carry **17 duplicated fields** — `src/v1/model.ts:102-180,213-279,418-489` -- **Why weird:** Three types share a 17-field overlap (outputSchemaName, assetsDir, analysisConfig, slicingExprs, customMetrics, baselineTableName, schedule, notifications, dataClassificationConfig, tableName, status, latestMonitorFailureMsg, profileMetricsTableName, driftMetricsTableName, dashboardId, monitorVersion, fullTableNameArg). Each is copy-pasted with the same JSDoc and the same `[Create:REQ Update:REQ]`-style annotation in the comment. The "annotation in the comment" tells the reader which fields are required at create vs update vs read — but is never enforced by the type system. -- **Category:** 6 (misleading — type says optional, semantics say required-at-create), 7 (overly verbose — three nearly-identical types where one with a generic param could do). -- **Suggested name:** One `Monitor` interface for the read shape; `CreateMonitorRequest` and `UpdateMonitorRequest` carry only their differences (e.g., `CreateMonitorRequest` has the input-only `skipBuiltinDashboard` and `warehouseId`). Or use TypeScript's `Pick`/`Omit`/`Partial` to derive types from a base. Encode `[Create:REQ Update:IGN]` in the type system (not the doc): non-optional in `CreateMonitorRequest`, omitted in `UpdateMonitorRequest`. -- **Rationale:** The current state is a maintenance hazard — adding a field requires editing three places. Worse, the wire-side `[Create:REQ ...]` semantics live only in comments. - -## Medium severity - -### 11. `[Create:REQ Update:REQ]` doc-comment annotations — `src/v1/model.ts:115,118,122,136,145,148,153,155,157,159,161,163,165,167,169,174` (and again for `DataMonitorInfo` and `UpdateMonitorRequest`) -- **Why weird:** Every field on `CreateMonitorRequest` / `UpdateMonitorRequest` / `DataMonitorInfo` has a prefix annotation in its JSDoc — `[Create:REQ Update:REQ]`, `[Create:OPT Update:OPT]`, `[Create:ERR Update:IGN]` — that encodes per-operation requirement semantics in the comment. These are generator markers, not human-friendly. A user opening the JSDoc tooltip sees `[Create:ERR Update:IGN]` and must decode "ERR means errors if you pass this, IGN means it's ignored on update". The TypeScript type does not enforce any of this. -- **Category:** 6 (misleading — comment marker pretends to be authoritative but is not enforced), 18 (long, noisy comment prefix). -- **Suggested name:** Remove the markers from comments. Encode the semantics in the type (separate `CreateMonitorRequest` vs `UpdateMonitorRequest` vs `Monitor` types with the right optionality and field presence). -- **Rationale:** Doc markers are not type-checked. They look like type annotations but are inert. - -### 12. `latestMonitorFailureMsg` — `src/v1/model.ts:164,263,473` -- **Why weird:** Three problems in one field name. (a) `Msg` is an abbreviation for `Message` — sister field on `RefreshInfo` is `message` (full word), and `dataquality.DataProfilingConfig` uses `latestMonitorFailureMessage` (full word). Inconsistency within the SDK. (b) `Monitor` is in the path — `monitor.latestMonitorFailureMsg` repeats "monitor". (c) The field is documented as `[Create:ERR Update:IGN]` (read-only, server-populated), but the type does not mark it. -- **Category:** 5 (cryptic abbreviation — `Msg`), 7 (overly verbose), 8 (redundant `Monitor` in path), 17 (inconsistent with sibling `message` and with `dataquality`). -- **Suggested name:** `latestFailureMessage`. -- **Rationale:** Full word, no redundant prefix; matches `dataquality`. - -### 13. `profileMetricsTableName` and `driftMetricsTableName` — `src/v1/model.ts:166,168,265,267,475,477` -- **Why weird:** Pair of fields with the suffix `TableName`. Sibling Zod field is `profile_metrics_table_name` — six tokens on the wire. JSDoc on both: identical except for the leading noun. The naming pattern is consistent within the pair but verbose. Compare with `dataquality.DataProfilingConfig.{profileMetricsTableName, driftMetricsTableName}` (same names — at least consistent across packages). -- **Category:** 7 (overly verbose). -- **Suggested name:** `profileMetricsTable` / `driftMetricsTable` (drop `Name` — these are reference fields, not column names). -- **Rationale:** "Table" is sufficient context. - -### 14. `outputSchemaName` field — `src/v1/model.ts:116,215,425` -- **Why weird:** JSDoc says "Schema where output tables are created. Needs to be in 2-level format `{catalog}.{schema}`." So `outputSchemaName` is a two-part UC reference, not just a name. Sister field `baselineTableName` is a three-part UC reference; `tableName` is also three-part. The naming gives no cue about which "name" shape applies. -- **Category:** 19 (underspecified — name vs full name vs two-part), 15 (generic name). -- **Suggested name:** `outputSchemaFullName` (matches UC vocabulary; the value is `catalog.schema`). -- **Rationale:** The "Name" suffix is ambiguous in UC contexts where the term `FullName` is reserved for fully qualified references. - -### 15. `assetsDir` — `src/v1/model.ts:121,220,430` -- **Why weird:** Identical to `dataquality.DataProfilingConfig.assetsDir` (audit #12 in that package). `assets` is generic ("which assets?"), and `Dir` is an abbreviation. JSDoc says "absolute path to a custom directory to store data-monitoring assets". -- **Category:** 1 (vague), 5 (cryptic abbreviation — `Dir`). -- **Suggested name:** `assetsDirectory` or `monitoringAssetsPath`. -- **Rationale:** Same as `dataquality` #12. - -### 16. `slicingExprs` — `src/v1/model.ts:144,243,453` -- **Why weird:** Identical to `dataquality.DataProfilingConfig.slicingExprs` (audit #25 in that package). `Exprs` truncates "Expressions". -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `slicingExpressions` (or, for clarity, `columnSlicingExpressions`). -- **Rationale:** Same as `dataquality` #25. - -### 17. `skipBuiltinDashboard` (negative boolean) — `src/v1/model.ts:109` -- **Why weird:** Same pattern as `dataquality.DataProfilingConfig.skipBuiltinDashboard` (audit #11 in that package). Negative boolean field name. Reading `skipBuiltinDashboard: true` requires a mental NOT-flip. -- **Category:** 6 (misleading), 13 (verb-tense — `skip` is action-y, field is state-y). -- **Suggested name:** `disableBuiltinDashboard` or invert to `createBuiltinDashboard: boolean`. -- **Rationale:** Same as `dataquality` #11. - -### 18. `baselineTableName` — `src/v1/model.ts:152,251,461` -- **Why weird:** A three-part UC reference (per JSDoc: "Baseline table name") but the name says only `Name`. Same shape concern as #14. -- **Category:** 19 (underspecified ID — wire-side three-part name, not flagged as such). -- **Suggested name:** `baselineTableFullName`. -- **Rationale:** UC vocabulary uses `FullName` for three-part references. - -### 19. `tableName` — `src/v1/model.ts:160,259,469` -- **Why weird:** Three-part UC reference per JSDoc ("UC table to monitor. Format: `catalog.schema.table_name`"), but the name says only `Name`. Compare with `fullTableNameArg` on the same types — *two* fields representing essentially the same UC table reference, one called `tableName` (`[Create:ERR Update:IGN]`) and one called `fullTableNameArg` (the URL path param). This is the same data appearing under two field names in the same interface. -- **Category:** 12 (duplicate concept — two fields for the same table reference), 19 (underspecified — three-part wire format hidden behind `Name`). -- **Suggested name:** Drop one of the two. If `tableName` (the body field) is truly read-only and copied from the URL path, remove it. Otherwise, rename to `tableFullName`. -- **Rationale:** Having both `tableName` and `fullTableNameArg` in the same type forces a caller to choose which to populate. - -### 20. `dashboardId` is read-only at create, optional at update — `src/v1/model.ts:173,272,482` -- **Why weird:** JSDoc reads `[Create:ERR Update:OPT]`, meaning the field errors if set on create but is optional on update. Type marks both as optional. A caller writing `createMonitor({dashboardId: 'x', ...})` gets a runtime error from the API but no type-time signal. Same pattern as #12 in general; called out separately because `dashboardId` is one of the most likely fields to be mistakenly set. -- **Category:** 6 (misleading optionality). -- **Suggested name:** Move `dashboardId` out of `CreateMonitorRequest` entirely. Keep in `UpdateMonitorRequest` and `DataMonitorInfo`. -- **Rationale:** Type-level enforcement of "ERR" semantics. - -### 21. `monitorVersion: number` — `src/v1/model.ts:179,278,488` -- **Why weird:** Field name says "monitor version" but on a type called `CreateMonitorRequest` / `UpdateMonitorRequest` / `DataMonitorInfo`, the `monitor` part is dead context. JSDoc also notes the field "has flexibility to take on negative values, which can indicate corrupted monitor_version numbers" — using a magic-value (negative) to indicate corruption is a code smell (the type should be `number | 'corrupted'` or split into `version: number` + `corrupted: boolean`). -- **Category:** 7 (overly verbose — `monitor` in path), 6 (misleading — magic-value encoding of corruption state). -- **Suggested name:** `version: number`. -- **Rationale:** Field path already gives Monitor context. - -### 22. `warehouseId` only on `CreateMonitorRequest` and `RegenerateDashboardRequest`, not on `DataMonitorInfo` — `src/v1/model.ts:114,384` -- **Why weird:** `warehouseId` is an input-only field for picking a SQL warehouse to render the dashboard. Not on the response (`DataMonitorInfo`) — so a caller has no way to see which warehouse was actually chosen if they left this blank. Sibling `dataquality.DataProfilingConfig` has both `warehouseId` (input) and `effectiveWarehouseId` (output) — the latter is missing here. Inconsistent across two near-identical packages. -- **Category:** 17 (inconsistent — input-only vs input+output across sibling packages). -- **Suggested name:** Add `effectiveWarehouseId` to `DataMonitorInfo` to match `dataquality`. -- **Rationale:** Cross-package parity. - -### 23. `Notifications` vs `dataquality.NotificationSettings` — `src/v1/model.ts:352` -- **Why weird:** Sister package uses `NotificationSettings`; this package uses just `Notifications`. The plural noun is fine, but the sister naming differs. Also: only one nested type, `Destination` (vs `dataquality.NotificationDestination`) — again one is shorter and one is longer. -- **Category:** 17 (inconsistent — sibling package uses different type names for the same concept). -- **Suggested name:** Pick one: either `Notifications` + `Destination` (this package's form) or `NotificationSettings` + `NotificationDestination` (sibling's form), and apply uniformly across both packages. -- **Rationale:** Consistency across sibling packages. - -### 24. `Destination` — `src/v1/model.ts:292` -- **Why weird:** The `Destination` type holds only `emailAddresses?: string[]`. Naming a type for an email recipient list as `Destination` is generic. Compare with sister `dataquality.NotificationDestination` which has the same shape. The name `Destination` reads as "a place"; the content is "a list of email addresses". -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `EmailDestination` (matches content), or merge with `Notifications` if there's only one channel. -- **Rationale:** Generic noun for a specific data shape. - -### 25. `onNewClassificationTagDetected` field — `src/v1/model.ts:356` -- **Why weird:** Five-word field name (`on` + `New` + `Classification` + `Tag` + `Detected`) — past-tense verb at the end of a noun phrase. The doc says "Destinations to send notifications on new classification tag detected." The grammatical structure is awkward English. Sister `Notifications.onFailure` is concise (two words, no verb tense problem). -- **Category:** 7 (overly verbose), 13 (verb tense — past-participle at the end of a field name). -- **Suggested name:** `onNewClassificationTag` (drop `Detected`; the field is on `Notifications` so the verb is implicit). -- **Rationale:** Length and clarity. The `Detected` adds no information. - -### 26. `Notifications.onFailure: Destination` — `src/v1/model.ts:354` -- **Why weird:** Field name says only "failure"; the comment hints at more ("notifications on failure/timeout") — same caveat as `dataquality.NotificationSettings.onFailure` (audit #33 in that package). Field name and JSDoc disagree on whether timeouts are included. -- **Category:** 1 (vague), 17 (inconsistent doc/name). -- **Suggested name:** `onFailureOrTimeout` (matches doc) or `onFailure` (matches name; update doc). -- **Rationale:** Same as `dataquality` #33. - -### 27. `Notifications` field name uses plural but each value is a single `Destination` — `src/v1/model.ts:352-357` -- **Why weird:** The type is plural (`Notifications`) but each field (`onFailure`, `onNewClassificationTagDetected`) holds a single `Destination`, not an array. The plural-vs-singular doesn't match the content. Compare: `dataquality.NotificationSettings` (singular type, singular fields). -- **Category:** 9 (singular/plural mismatch — type plural, content singular). -- **Suggested name:** `NotificationSettings` (matches `dataquality`). -- **Rationale:** Same as `dataquality` parity. - -### 28. `InferenceLogAnalysisConfig.problemType: ProblemType` — `src/v1/model.ts:314` -- **Why weird:** Field name does not say "ML"; type is the generic `ProblemType` (#5). The reader has no cue from the field name that this is ML-specific. -- **Category:** 1 (vague — `problemType` alone is generic). -- **Suggested name:** `mlProblemType: InferenceProblemType` (relying on rename of the enum per #5). -- **Rationale:** Disambiguate from generic English meaning. - -### 29. `predictionProbaCol` — `src/v1/model.ts:326` -- **Why weird:** `Proba` is a Python ML idiom for "probability" — sklearn `predict_proba` etc. In a TS API, the name leaks the upstream Python convention. JSDoc says "Column for prediction probabilities" — uses the full word. -- **Category:** 5 (cryptic Python-ML abbreviation), 14 (foreign-ecosystem idiom). -- **Suggested name:** `predictionProbabilityCol` (or `predictionProbabilitiesCol`). -- **Rationale:** Python's `predict_proba` is sklearn vocabulary; a TS SDK should not require knowing sklearn to read field names. - -### 30. `timestampCol`, `predictionCol`, `labelCol`, `modelIdCol`, `predictionProbaCol` (Col suffix) — `src/v1/model.ts:316,320,322,324,326` -- **Why weird:** `Col` is an abbreviation for `Column`. Five fields on `InferenceLogAnalysisConfig` use it. Same in `TimeSeriesAnalysisConfig.timestampCol`. TS has no length constraint. -- **Category:** 5 (cryptic abbreviation — `Col`). -- **Suggested name:** `timestampColumn`, `predictionColumn`, `labelColumn`, `modelIdColumn`, `predictionProbabilityColumn`. -- **Rationale:** Full words; matches `dataquality.InferenceLogConfig` if that package has the same pattern (worth cross-checking). - -### 31. `modelIdCol` — `src/v1/model.ts:324` -- **Why weird:** `Id` ambiguity flagged across the SDK. `modelIdCol` — the column in the user's table that holds a model identifier — could be any UC ID or a free-form model version string. JSDoc says only "Column for the model identifier." -- **Category:** 19 (underspecified ID — what *kind* of model ID?). -- **Suggested name:** Document, or rename to `modelVersionColumn` if that is what the wire expects. -- **Rationale:** "Model ID" in Databricks could mean MLflow run ID, MLflow model version, registered model name, or a customer-chosen string. - -### 32. `MonitorCronSchedule` vs `dataquality.CronSchedule` — `src/v1/model.ts:343` -- **Why weird:** Same wire shape, different type names. Sister `dataquality.CronSchedule` drops the `Monitor` prefix. The prefix here is dead context — this type only ever lives on a `Monitor`. -- **Category:** 8 (redundant prefix — `Monitor` is in the access path). -- **Suggested name:** `CronSchedule` (matches `dataquality`). -- **Rationale:** Cross-package consistency. - -### 33. `quartzCronExpression` (leaks library name) — `src/v1/model.ts:345` -- **Why weird:** Same as `dataquality.CronSchedule.quartzCronExpression` (audit #30 in that package). `Quartz` is a Java scheduling library; users do not need to know that. -- **Category:** 14 (implementation-detail leak). -- **Suggested name:** `cronExpression`. -- **Rationale:** Same as `dataquality` #30. - -### 34. `timezoneId` — `src/v1/model.ts:347` -- **Why weird:** Same as `dataquality.CronSchedule.timezoneId` (audit #30 in that package). `Id` for what is in fact an IANA timezone name (e.g., `America/New_York`) — the field is a tz name, not an "ID" in the database sense. -- **Category:** 19 (misnamed — calling a tz name an `Id`), 5 (jargon). -- **Suggested name:** `timezone` (matches JS-standard `Intl.DateTimeFormat.timeZone`). -- **Rationale:** IANA tz names are not IDs in the UUID sense. - -## Low severity - -### 35. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Same as `dataquality` audit #35. Helper exported but never called from `client.ts`. -- **Category:** 6 (misleading — looks used; isn't). -- **Suggested name:** N/A — unexport. -- **Rationale:** Dead exported surface. - -### 36. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Same as `dataquality` audit #36. -- **Category:** 1, 12, 17. -- **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). -- **Rationale:** Layering should be readable from names. - -### 37. `buildHttpRequest` — `src/v1/utils.ts:96` -- **Why weird:** Same as `dataquality` audit #37 — "build" hints at builder pattern, function spreads literals. -- **Category:** 1, 6. -- **Suggested name:** `makeHttpRequest`. -- **Rationale:** "Make" matches the reality. - -### 38. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Same as `dataquality` audit #39. "ReadAll" does not say "drain a stream". -- **Category:** 1, 5. -- **Suggested name:** `drainStream`. -- **Rationale:** Self-describing. - -### 39. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Same as `dataquality` audit #40. Internal context bag named `Options` — collides with the public `CallOptions` / `ClientOptions` semantics. -- **Category:** 1, 8. -- **Suggested name:** `HttpCallContext`. -- **Rationale:** Reserve `Options` for user-tunable knobs. - -### 40. `PACKAGE_SEGMENT` — `src/v1/client.ts:52` -- **Why weird:** Same as `dataquality` audit #41. -- **Category:** 1. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Domain-word missing. - -### 41. `Call` type + `call` variable name collision in every method — `src/v1/client.ts:93,136,177,220,258,296,339,382,424` -- **Why weird:** Same as `dataquality` audit #42. Variable `call: Call` in 9 methods. -- **Category:** 1, 12. -- **Suggested name:** `request` (variable). -- **Rationale:** Type/variable collision. - -### 42. `respBody` vs `resp` — every method in `client.ts` -- **Why weird:** Same as `dataquality` audit #44. Two variables differ only by `Body`. -- **Category:** 5, 17. -- **Suggested name:** `rawBody` + `result`. -- **Rationale:** Distinguish by meaningful nouns. - -### 43. `httpReq` local — every method in `client.ts` -- **Why weird:** Same as `dataquality` audit #45. -- **Category:** 5, 12. -- **Suggested name:** `httpRequest`. -- **Rationale:** No abbreviation. - -### 44. `req.fullTableNameArg ?? ''` URL composition — `src/v1/client.ts:90,133,175,218,256,294,336,379,421` -- **Why weird:** Same as `dataquality` audit #43. `fullTableNameArg` typed optional but required in practice; silent empty-string substitution yields URLs like `/api/2.1/unity-catalog/tables//monitor`. -- **Category:** 6. -- **Suggested name:** Make `fullTableNameArg` non-optional on every request type. -- **Rationale:** Type should match runtime requirement. - -## Observations - -### 45. Every method's first JSDoc line is "Deprecated: Use Data Quality Monitors API instead" -- **Note:** All 9 client methods (`cancelRefresh`, `createMonitor`, `deleteMonitor`, `getMonitor`, `getRefresh`, `listRefreshes`, `regenerateDashboard`, `runRefresh`, `updateMonitor`) start their JSDoc with that sentence. None uses the `@deprecated` JSDoc tag, so editors do not render the deprecation visually. The package is deprecated in spirit, but live in build. - -### 46. Acronym casing -- `Id` (capital-then-lower in `refreshId`, `dashboardId`, `warehouseId`, `monitorVersion`); `Ms` (`startTimeMs`, `endTimeMs`); `Http` (in imported types). No within-package collisions, all generator-emitted. -- **Category:** 3 (acronym casing). - -### 47. URL paths mix `unity-catalog` and `quality-monitoring` -- **Note:** Eight of nine methods use `/api/2.1/unity-catalog/tables/{}/monitor[/...]`; one (`regenerateDashboard`) uses `/api/2.1/quality-monitoring/tables/{}/monitor/dashboard`. The package name does not match either prefix. The sister `dataquality` package uses `/api/data-quality/v1/monitors`. -- **Category:** 17 (inconsistent — package name vs wire path). - -### 48. No `FieldMask` types -- This package does not have any `FieldMask<...>` types (unlike `dataquality`). The deprecated API does not support partial updates via field masks; the entire monitor body is replaced on `PUT`. (Listed as observation to contrast with sibling packages.) - -### 49. Verb consistency -- `Cancel`, `Create`, `Delete`, `Get`, `List`, `Regenerate`, `Run`, `Update` — eight different verbs in nine methods. Within the package the verbs are appropriate and consistent. The unusual one is `Regenerate` (vs `Recreate` or `RebuildDashboard`) — generator-driven choice, fine in context. -- **Category:** 17 (verb inventory, none inconsistent). - -### 50. `Notifications` is a slim type with two channel fields -- Two-channel `Notifications` (`onFailure`, `onNewClassificationTagDetected`) follows the proto shape. A TS-idiomatic shape might be `notifications: Array<{channel: 'failure' | 'newClassificationTag', destination: Destination}>` to allow future expansion. Listed as observation, not a flag. - -## Domain glossary -- `uc` / Unity Catalog — the resource container for the monitored table. -- `inference log` — predictions + labels + (optional) probabilities for a deployed ML model. -- `time series` — analysis configuration where rows have a timestamp column and are bucketed by granularity. -- `snapshot` — analysis configuration with no time dimension; the table is treated as a single snapshot. -- `refresh` — a single run of the monitoring pipeline; produces metric rows in `profileMetricsTableName` / `driftMetricsTableName`. -- `monitor` — the long-lived per-table configuration entity. -- `baseline table` — a separate table whose statistics drift is computed against. -- `profile metrics` / `drift metrics` — two distinct output tables; profile = per-window distribution stats, drift = stats compared against baseline or previous window. -- `quartz` — Apache Quartz Scheduler (Java library); leaks via `quartzCronExpression`. -- `assets dir` — workspace directory holding the dashboard and other monitor assets. -- `slicing exprs` — column expressions to group data by for targeted analysis. -- `data classification` — automated tagging of columns by data type / PII / etc.; controlled by `dataClassificationConfig.enabled` and `Notifications.onNewClassificationTagDetected`. -- `proba` — Python ML idiom for "probability" (sklearn `predict_proba`). -- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered. - -## File coverage -- `src/v1/model.ts` (935 lines): read fully. -- `src/v1/client.ts` (441 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (39 lines): read fully. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/queryexecution.md b/.agent/naming-audit/queryexecution.md index c81e349c..ca1ebced 100644 --- a/.agent/naming-audit/queryexecution.md +++ b/.agent/naming-audit/queryexecution.md @@ -1,52 +1,3 @@ # Naming Audit: queryexecution -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/queryexecution/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Execute, cancel, and poll SQL queries for *published, embedded -Lakeview dashboards*. All three endpoints hit the same URL -(`/api/2.0/lakeview-query/query/published`) and only differ by HTTP verb (POST = execute, -GET = poll, DELETE = cancel). The package name (`queryexecution`) is much broader than -what it actually does (lakeview-dashboard query lifecycle). Confusing overlap with -sibling packages `statementexecution` (general SQL Statement Execution API), -`queryhistory` (history of executed queries), and `queries` (saved query definitions). -**Total weird names flagged:** 0 - -## Summary -| Severity | Count | -| --- | --- | -| High | 0 | -| Medium | 0 | -| Low | 0 | -| Observation | 0 | - -## High severity - -_None._ - -## Medium severity - -_None._ - -## Low severity - -_None._ - -## Observations - -_None._ - -## Domain glossary -- **Lakeview** — Databricks' notebook-style published dashboards product. -- **Published dashboard** — A dashboard configured to run "as the publisher" (publisher's identity, publisher's warehouse) rather than the viewer's. This is the entire reason this package exists. -- **Embedded dashboard** — A dashboard rendered outside the Databricks UI (e.g., in a customer's site). Triggers the "publisher mode". -- **`sql-exec-api`** — Internal service that runs the SQL; referenced in JSDoc but not in TS names. -- **`lakeview-config`** — Internal service that stores the dashboard configuration (warehouse, datasets, embedded credentials); referenced in JSDoc. -- **`dataToken`** / **`statementId`** — Same value on the wire, two field names: `dataToken` is for polling, `statementId` is for audit-logging. -- **`PublishedDatasetDataModel`** — Internal Java class referenced in JSDoc; holds the published-dashboard datasets, warehouse_id, and embedded_credentials. - -## File coverage -- Package removed from the repository — no source files to audit. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md index 9d632b6a..671b25f2 100644 --- a/.agent/naming-audit/serviceprincipalsecrets.md +++ b/.agent/naming-audit/serviceprincipalsecrets.md @@ -1,44 +1,3 @@ # Naming Audit: serviceprincipalsecrets -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/serviceprincipalsecrets/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Account-level CRUD over OAuth client secrets attached to -a service principal. Endpoints sit under -`/api/2.0/accounts//servicePrincipals//credentials/secrets`. -**Total weird names flagged:** 0 - ---- - -## Summary table - -_None._ - ---- - -## High severity (must fix) - -_None._ - ---- - -## Medium severity (worth pushing back on) - -_None._ - ---- - -## Low severity (nits) - -_None._ - ---- - -## Observations (not flags) - -_None._ - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md index 7d4794d2..0d68e152 100644 --- a/.agent/naming-audit/workspace.md +++ b/.agent/naming-audit/workspace.md @@ -1,486 +1,3 @@ # Naming Audit: workspace -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/workspaceobjects/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Databricks workspace filesystem-style operations on notebooks, folders, and files: import, export, delete, list, get-status, and mkdirs against absolute paths under `/Workspace`. -**Total weird names flagged:** 27 - -## Scope note: `workspaceobjects` vs sibling packages - -The Databricks SDK ships several packages whose names begin with "workspace". This audit covers the filesystem-style operations package, now `workspaceobjects`; the others differ in scope: - -| Package | Domain | Wire prefix | -|---------|--------|-------------| -| `workspaceobjects` (this audit) | Workspace filesystem (notebooks/folders/files) | `/api/2.0/workspace/` | -| `workspaceassignment` | Account-level principal-to-workspace permission assignments | account API | -| `workspacebindings` | Securable-to-workspace bindings (catalog/credential/location) | Unity Catalog API | -| `workspaceconf` | Untyped key/value workspace configuration | `/api/2.0/workspace-conf` | -| `workspacesettings` | Strongly-typed workspace settings (compliance security profile, automatic cluster update, etc.) | various `/api/2.0/settings/*` | - -## Summary table - -| # | Severity | Location | Name | Category | -|---|----------|----------|------|----------| -| 1 | High | `model.ts` enum | `ExportFormat` used as the `format` field of `ImportRequest` | Misleading name (an "ExportFormat" governs imports too) | -| 2 | High | `model.ts` enum value | `ExportFormat.AUTO` | Misleading enum value (server inspects content) | -| 3 | High | `model.ts` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | -| 4 | High | `model.ts` field | `ObjectInfo.objectId` and `ObjectInfo.resourceId` | Duplicate concept (two IDs for the same object, undifferentiated names) | -| 5 | High | `model.ts` enum | `Language` | Vague/generic, no domain prefix | -| 6 | Medium | `model.ts` enum value | `ObjectType.LIBRARY` | Misleading (library notebooks are an obsolete concept; deprecated in product) | -| 7 | Medium | `model.ts` field | `ListRequest.notebooksModifiedAfter` | Field contradicts type domain (list of all objects, filter only on notebooks) | -| 8 | Medium | `model.ts` field | `ExportRequest.directDownload` | Verb-as-noun field + boolean named like a noun | -| 9 | Medium | `model.ts` field | `ExportRequest_Response.fileType` | Underspecified (raw extension? MIME type? format enum?) | -| 10 | Medium | `model.ts` field | `ExportRequest_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | -| 11 | Medium | `model.ts` field | `ImportRequest.content` typed `Uint8Array` | Same type/JSDoc mismatch as 10 in the reverse direction | -| 12 | Medium | `model.ts` field | `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` | Underspecified time fields (mtime/ctime? wall clock?) and unit ambiguity (epoch millis as number) | -| 13 | Medium | `model.ts` field | `ObjectInfo.size` | Underspecified (file size in bytes per JSDoc, but no unit in the name) | -| 14 | Medium | `model.ts` field | `MkdirsRequest.path` | Singular/plural mismatch — type name plural (`Mkdirs`), field singular (`path`) | -| 15 | Medium | `model.ts` type | `MkdirsRequest` | Cryptic abbreviation (Unix-ism, "mkdirs" not "createDirectory") | -| 16 | Medium | `model.ts` enum value | `Language.R` | Single-letter identifier (clashes with `package R Markdown`) | -| 17 | Medium | `client.ts` method | `getStatus` | Vague verb (status of what?), inconsistent with `list`/`export` | -| 18 | Medium | `model.ts` field | `DeleteRequest.recursive` | Underspecified boolean (verbatim Unix flag, no domain reading) | -| 19 | Low | `model.ts` enum value | `ExportFormat.R_MARKDOWN` | Underscore inside enum value matches wire, but mixes shape with `JUPYTER`/`HTML` (single tokens) | -| 20 | Low | `model.ts` enum value | `ExportFormat.DBC` | Cryptic abbreviation (Databricks archive) | -| 21 | Low | `model.ts` interface | `ObjectInfo` | Generic name ("info" suffix used inconsistently across SDK) | -| 22 | Low | `model.ts` field | `ListRequest_Response.objects` | Generic field (`objects`) for `ObjectInfo[]` | -| 23 | Low | `client.ts` method | `mkdirs` | Verb-tense / casing inconsistency vs `createDirectory` analog elsewhere in SDK | -| 24 | Low | docstrings | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | -| 25 | High | `model.ts` types | `DeleteRequest_Response`, `ExportRequest_Response`, `ImportRequest_Response`, `ListRequest_Response`, `MkdirsRequest_Response` | Proto-architectural-leak (`_Response` infix encodes proto nested-message name) | -| 26 | High | `model.ts` schema constants | `unmarshalDeleteRequest_ResponseSchema`, `unmarshalExportRequest_ResponseSchema`, `unmarshalImportRequest_ResponseSchema`, `unmarshalListRequest_ResponseSchema`, `unmarshalMkdirsRequest_ResponseSchema` | Proto-architectural-leak (schema const names carry the proto nested-message infix into the public schema identifiers) | -| 27 | Observation | source files | `// Proto-style nested message name.` eslint-disable comments at `model.ts:69,96,146,156,170,202,206,221,225,235` and `index.ts` re-exports | Proto-architectural-leak surfacing: the lint-rule suppressions name "Proto" directly in source, confirming the leak is structural, not incidental | - -## High severity - -### 1. `ExportFormat` reused for `ImportRequest.format` — misleading enum - -**Location:** `model.ts:5-25`; used as `ImportRequest.format` at `:129` - -```ts -export enum ExportFormat { - SOURCE = 'SOURCE', - HTML = 'HTML', - ... -} - -export interface ImportRequest { - ... - format?: ExportFormat | undefined; - ... -} -``` - -The enum is named `ExportFormat` but is used as the format for both `ImportRequest.format` and `ExportRequest.format`. The Go SDK's name (`ExportFormat`) leaks here. A neutral name like `WorkspaceObjectFormat` or `NotebookFormat` would describe both directions. The JSDoc on `ImportRequest.format` even lists the values (SOURCE, HTML, JUPYTER, DBC, R_MARKDOWN) as if they were import-specific, while the enum description says "for workspace import and export." - -There is also a subtle asymmetry: `ImportRequest.format` documents AUTO as "depending on extension," `ExportRequest.format` documents AUTO as "depending on object type." Same enum value, different server behaviour per direction. - -### 2. `ExportFormat.AUTO` — misleading enum value - -**Location:** `model.ts:17-18` - -```ts -/** We will inspect the content of the payload to determine the type */ -AUTO = 'AUTO', -``` - -`AUTO` reads as "automatic file selection," but the value means "server inspects payload bytes to guess the file type." For an export request, "AUTO" means "decide based on the object's type." The single token serves two different inferred behaviors. `DETECT_FROM_CONTENT` / `DETECT_FROM_OBJECT` (split into two enums) would be honest. - -### 3. `ExportFormat.RAW` — vague enum value - -**Location:** `model.ts:19-24` - -```ts -/** - * This is introduced to unblock a DR use case importing .zip file as is. - * If you import .zip file with AUTO format, it will be imported as a folder. - * In workspace 3.0 folder import will be supported via a different API. - */ -RAW = 'RAW', -``` - -`RAW` does not name a format — it names a behavior ("no decoding, store as-is"). The JSDoc is a story about why the value exists, not what it represents. The value's existence is conditional on "workspace 3.0," a server-side roadmap item the SDK user does not see. - -`ZIP_PASSTHROUGH` or `BINARY` would describe the actual data path. Right now a reader sees `ExportFormat.RAW` and has to read three lines of JSDoc to understand it. - -### 4. `ObjectInfo.objectId` and `ObjectInfo.resourceId` — duplicate concept, undifferentiated names - -**Location:** `model.ts:194-199` - -```ts -/** Unique identifier for the object. */ -objectId?: number | undefined; -... -/** A unique identifier for the object that is consistent across all Databricks APIs. */ -resourceId?: string | undefined; -``` - -The same `ObjectInfo` carries two distinct identifiers, both documented as "unique identifier for the object," differing only by JSDoc adjective ("consistent across all Databricks APIs"). The names do not encode the difference: a reader sees `objectId` (number) and `resourceId` (string) and cannot tell which one to pass into another API. - -Likely truth: `objectId` is the legacy 64-bit workspace-local numeric ID; `resourceId` is the new UUID-shaped string ID used by the unified resources API. The names should be `legacyObjectId` (deprecated) and `resourceId`, or `localObjectId` and `globalResourceId`, or one should be dropped. - -Also, `objectId` is typed `number` — JavaScript numbers are 64-bit float; if the server ID exceeds 2^53, precision is lost. Other SDK types use `bigint` or string for similar IDs. - -### 5. `Language` — vague/generic, no domain prefix - -**Location:** `model.ts:27-37` - -```ts -/** The language of notebook. */ -export enum Language { - SCALA = 'SCALA', - PYTHON = 'PYTHON', - SQL = 'SQL', - R = 'R', -} -``` - -A top-level export named `Language` in a domain package. Many other SDK packages reference "language" (`apps` runtimes, `jobs` task language, `clusters` runtime languages, `pipelines` SQL/Python). The package re-exports `Language` without a `Notebook` or `Workspace` qualifier. A user importing two SDK packages can get `Language` from `workspaceobjects` and a different `Language` from `apps` or `jobs` (when those add similar enums). - -`NotebookLanguage` is the natural domain prefix; the wire field is `notebook.language`. - -### 25. `*Request_Response` types — proto nested-message naming leaks into the public surface - -**Location:** `model.ts:70` (`DeleteRequest_Response`), `model.ts:97` (`ExportRequest_Response`), `model.ts:147` (`ImportRequest_Response`), `model.ts:157` (`ListRequest_Response`), `model.ts:171` (`MkdirsRequest_Response`); re-exported from `index.ts:9,11,13,15,17`. - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteRequest_Response {} -... -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface ExportRequest_Response { ... } -``` - -**Why:** the `_Response` infix encodes the protobuf nested-message path (`message DeleteRequest { message Response { ... } }`) directly into a TS identifier. The eslint-disable comment names the leak verbatim ("Proto-style nested message name"). TypeScript consumers do not have proto-nested types; the underscored name reads as "snake_case in PascalCase" — a shape no other TS SDK package uses. - -**Category:** Proto-architectural-leak — proto/IDL implementation detail surfaced in public type names. - -**Suggested:** drop the `_Response` infix and pick a flat name: `DeleteResponse`, `ExportResponse`, `ImportResponse`, `ListResponse`, `MkdirsResponse`. Where the response carries domain content (`ListResponse` → `ObjectInfo[]`), a content-bearing name like `ListObjectsResponse` would also work. - -**Rationale:** TS naming conventions are PascalCase without underscores. The `Request_Response` shape forces every consumer call site (`Promise`, `unmarshalDeleteRequest_ResponseSchema`) to carry the proto path. It also implies a parent-child semantic relationship between `DeleteRequest` and `DeleteRequest_Response` that does not exist on the wire (the response is a sibling message in proto, just nested for namespacing). - -### 26. `unmarshal*Request_ResponseSchema` constants — proto leak into schema identifier names - -**Location:** `model.ts:203` (`unmarshalDeleteRequest_ResponseSchema`), `model.ts:207` (`unmarshalExportRequest_ResponseSchema`), `model.ts:222` (`unmarshalImportRequest_ResponseSchema`), `model.ts:226` (`unmarshalListRequest_ResponseSchema`), `model.ts:236` (`unmarshalMkdirsRequest_ResponseSchema`); imported and used in `client.ts:38-42`. - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export const unmarshalDeleteRequest_ResponseSchema: z.ZodType = - z.object({}); -``` - -**Why:** the proto-nested name from finding 25 propagates into every schema constant. The schema identifier itself (`unmarshalDeleteRequest_ResponseSchema`) is a public export carrying the proto path. The unmarshal verb is also kept (separate, deliberate per project rules), but the `Request_Response` infix on the schema names is the proto leak surfacing twice — once on the type, once on the schema constant. - -**Category:** Proto-architectural-leak — schema-identifier inheritance of the proto nested-message path. - -**Suggested:** rename in lockstep with finding 25: `unmarshalDeleteResponseSchema`, `unmarshalExportResponseSchema`, etc. - -**Rationale:** schema constants are public API (re-exportable, used by downstream code). Carrying the proto path into them locks the proto shape into the SDK's public surface even for consumers who never see the underlying type alias. - -## Medium severity - -### 6. `ObjectType.LIBRARY` — obsolete concept - -**Location:** `model.ts:48` - -```ts -NOTEBOOK = 'NOTEBOOK', -DIRECTORY = 'DIRECTORY', -LIBRARY = 'LIBRARY', -FILE = 'FILE', -REPO = 'REPO', -DASHBOARD = 'DASHBOARD', -``` - -Workspace "libraries" (as a top-level object type) are obsolete — Databricks moved libraries to cluster-level and job-level configurations. The value is exported without a deprecation marker and without JSDoc explanation. Consumers writing `if (obj.objectType === ObjectType.LIBRARY)` are coding against a dead branch. - -### 7. `ListRequest.notebooksModifiedAfter` — field contradicts type domain - -**Location:** `model.ts:149-154` - -```ts -export interface ListRequest { - /** The absolute path of the notebook or directory. */ - path?: string | undefined; - /** UTC timestamp in milliseconds */ - notebooksModifiedAfter?: number | undefined; -} -``` - -`list` returns all object types (notebooks, directories, files, repos, dashboards), but the filter parameter is named `notebooksModifiedAfter` — i.e., the filter only applies to objects of type `NOTEBOOK`. The asymmetry is invisible from the field name. A non-notebook object's last-modified value is silently not filtered, and a user expecting `modifiedAfter` semantics will see directories whose contents post-date the filter. - -`modifiedAfterMillis` (without the `notebooks` prefix) or `notebookModifiedAfterMillis` (with the singular subject matching the filter's actual scope) would describe what the server does. - -The unit (`milliseconds`) is in JSDoc only, not in the field name. Other timestamp fields in the same file are documented in milliseconds but named `createdAt` / `modifiedAt`. Inconsistent — see finding 12. - -### 8. `ExportRequest.directDownload` — verb-as-noun field, weak boolean - -**Location:** `model.ts:88-92` - -```ts -/** - * Flag to enable direct download. If it is `true`, the response is the exported file itself. - * Otherwise, by default, the response contains content in the form of a base64 encoded string. - */ -directDownload?: boolean | undefined; -``` - -`directDownload` reads as a noun phrase ("the direct download"), but it's a boolean flag controlling response shape. Booleans are usually named with `is`/`has`/`should` prefixes or as adjectives. `streamBinary` or `responseAsBinary` would parse as a flag. - -The flag also has a semantic problem: when `true`, the response body is raw bytes; when `false`, the response body is a JSON object with base64. So the field changes the entire response content type, but the generated client (`export` method) parses the response identically in both cases. Setting `directDownload: true` would crash the parser. - -### 9. `ExportRequest_Response.fileType` — underspecified - -**Location:** `model.ts:103-105` - -```ts -/** The file type of the exported file. */ -fileType?: string | undefined; -``` - -The doc says "the file type" but doesn't say in what form. Is it the extension (`.ipynb`)? A MIME type (`application/x-ipynb+json`)? An `ExportFormat` enum value (`JUPYTER`)? An object kind (`NOTEBOOK`)? Typed as `string` so any of the four is possible. The name `fileType` is one of the most overloaded strings in software. - -`mimeType`, `extension`, or `format: ExportFormat` would commit. - -### 10. `ExportRequest_Response.content` typed `Uint8Array` with "base64-encoded" doc - -**Location:** `model.ts:98-102` - -```ts -/** - * The base64-encoded content. - * If the limit (10MB) is exceeded, exception with error code **MAX_NOTEBOOK_SIZE_EXCEEDED** is thrown. - */ -content?: Uint8Array | undefined; -``` - -The JSDoc says the content is base64-encoded; the type is `Uint8Array` (raw bytes). The client decodes base64 before populating this field, so the field actually holds decoded bytes, contradicting the JSDoc. The JSDoc was lifted from the wire format documentation and not updated for the post-decode TS shape. A reader holding the type sees "Uint8Array of base64-encoded data," which is technically meaningless (Uint8Arrays are bytes, not base64). - -### 11. `ImportRequest.content` typed `Uint8Array` with "base64-encoded" doc - -**Location:** `model.ts:132-138` - -```ts -/** - * The base64-encoded content. This has a limit of 10 MB. - * ... - * This parameter might be absent, and instead a posted file is used. - */ -content?: Uint8Array | undefined; -``` - -Mirror of finding 10 in the reverse direction. The client encodes the bytes to base64 before sending; the TS user passes raw bytes despite the JSDoc saying "base64-encoded." Worse: a defensive caller who reads the JSDoc and base64-encodes their bytes will double-encode and corrupt the upload. - -### 12. `ObjectInfo.createdAt` and `ObjectInfo.modifiedAt` — unit ambiguity, `Number` precision - -**Location:** `model.ts:190-193` - -```ts -/** Only applicable to files. The creation UTC timestamp. */ -createdAt?: number | undefined; -/** Only applicable to files, the last modified UTC timestamp. */ -modifiedAt?: number | undefined; -``` - -Two issues: - -1. The names use the `At` suffix (TS-friendly) but the type is `number`. Unit (milliseconds vs seconds) is documented nowhere in this type. The companion `ListRequest.notebooksModifiedAfter` is documented as milliseconds; one infers consistency, but the type does not declare it. Most of the SDK uses `Temporal.Instant` for `At`-suffixed timestamps; here it's `number`. -2. "Only applicable to files" — the field is on `ObjectInfo`, which also describes notebooks, directories, etc. Setting expectations via "only applicable" in JSDoc is a code smell: the field shape doesn't change based on object type. - -### 13. `ObjectInfo.size` — underspecified - -**Location:** `model.ts:196-197` - -```ts -/** Only applicable to files. The file size in bytes can be returned. */ -size?: number | undefined; -``` - -`size` is a unit-less name. JSDoc says "file size in bytes can be returned" (the "can be" is also ambiguous — is it always returned for files?). `sizeBytes` or `sizeInBytes` is the convention used elsewhere in Databricks SDKs (`clusters.clusterMemoryMb`, `pipelines.storageBytes`). At scale-up time (>4GiB) `number` loses precision; `bigint` or `string` would be safer. - -### 14. `MkdirsRequest.path` — singular/plural mismatch with the type name - -**Location:** `model.ts:162-168` - -```ts -export interface MkdirsRequest { - /** - * The absolute path of the directory. If the parent directories do not exist, it will also create them. - * ... - */ - path?: string | undefined; -} -``` - -The type's verb is plural (`Mkdirs` — "make directories"), but it takes one path. The pluralization comes from the Unix `mkdir -p` semantics ("makes the directory and any missing parent directories"), but the input is a single path. A user reading `MkdirsRequest` expects to pass an array. - -### 15. `MkdirsRequest` — Unix-ism - -**Location:** `model.ts:162`; `client.ts:266` - -`mkdirs` is a Unix verb. The convention in TS SDKs is `createDirectory` (matches the Files API's `createDirectory`). The Databricks SDK's own `files` package uses `createDirectory` for a similar operation. Inconsistent verb across packages. - -Also: the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the request body holds one path. So even at the wire level, the name is misleading. - -### 16. `Language.R` — single-letter identifier - -**Location:** `model.ts:36` - -```ts -export enum Language { - SCALA = 'SCALA', - PYTHON = 'PYTHON', - SQL = 'SQL', - R = 'R', -} -``` - -`Language.R` is the only single-character enum value in the package. Auto-import tools, grep, and refactoring tools handle one-letter identifiers poorly. The wire format also uses just `R`, so wire compatibility constrains the value, but the enum key (the TS identifier) can diverge from the wire string. Documenting `R` more thoroughly, or treating it as the lone exception to a single-token convention, would help readers grepping for the symbol. - -### 17. `getStatus` — vague verb on the client - -**Location:** `client.ts:157` - -```ts -async getStatus(req: GetStatusRequest, options?: CallOptions): Promise -``` - -"Status" of what? In TS SDKs, `getStatus` usually returns a status enum or a small status object (e.g., job run status). Here it returns full `ObjectInfo` metadata — a filesystem `stat`, not a status. The Files API uses `getMetadata`. The Go SDK uses `GetStatus` (from `os.Stat` ancestry). Either `getMetadata` or `stat` would describe the actual operation. - -The method also returns `Promise` while `list` returns `Promise` — inconsistent shape (one returns the bare entity, one returns a wrapper). See finding 22. - -### 18. `DeleteRequest.recursive` — Unix flag, no domain reading - -**Location:** `model.ts:61-66` - -```ts -/** - * The flag that specifies whether to delete the object recursively. It is `false` by default. - * Please note this deleting directory is not atomic. If it fails in the middle, some of objects - * under this directory may be deleted and cannot be undone. - */ -recursive?: boolean | undefined; -``` - -`recursive` is a verbatim port of `rm -r`. For a single-object delete, "recursive" only matters when the path is a directory. The flag would read better as `deleteContents` or `force` for the destructive intent. The JSDoc admits the deletion is non-atomic, a meaningful caveat hidden behind a one-word flag. - -## Low severity - -### 19. `ExportFormat.R_MARKDOWN` — shape mismatch within enum - -**Location:** `model.ts:15-16` - -```ts -SOURCE = 'SOURCE', -HTML = 'HTML', -JUPYTER = 'JUPYTER', -DBC = 'DBC', -R_MARKDOWN = 'R_MARKDOWN', -AUTO = 'AUTO', -RAW = 'RAW', -``` - -Five of the seven values are single tokens; one is `R_MARKDOWN` with an underscore. SQL convention would also be `RMARKDOWN` or `RMD`. Inconsistent shape inside the same enum. - -### 20. `ExportFormat.DBC` — cryptic abbreviation - -**Location:** `model.ts:13-14` - -```ts -/** The notebook will be imported/exported as Databricks archive format. */ -DBC = 'DBC', -``` - -DBC = "Databricks Archive." The acronym is product-specific. `DATABRICKS_ARCHIVE` would be readable. Wire-format compatibility (`DBC` is what the server expects) means the rename has to happen in the enum-key layer, not the enum-value layer — which TS supports cleanly. - -### 21. `ObjectInfo` — `Info` suffix used inconsistently across SDK - -**Location:** `model.ts:173-200` - -The `Info` suffix is a Go/Java convention for "POJO that describes a thing." TS SDKs vary: some use bare entity names (`Catalog`, `Cluster`), some use `Info`/`Details`. This package's only entity type is `ObjectInfo`. There is no companion `Object` — so the name reads consistently with itself, but the suffix is purely a hat-tip to Go. - -### 22. `ListRequest_Response.objects` — generic field for `ObjectInfo[]` - -**Location:** `model.ts:157-160` - -```ts -export interface ListRequest_Response { - /** List of objects. */ - objects?: ObjectInfo[] | undefined; -} -``` - -`objects` is the most generic JavaScript noun; it tells the reader nothing. `items`, `entries`, `paths`, or `workspaceObjects` would convey scope. The Go SDK has the same `Objects` field; transferring the name without adaptation gives a TS user a `resp.objects` access that reads like "the objects of the response." - -### 23. `mkdirs` — verb-tense / casing inconsistency - -**Location:** `client.ts:266` - -```ts -async mkdirs(req: MkdirsRequest, options?: CallOptions): Promise -``` - -Other client methods read as verb-noun (`export`, `import`, `list`) or compound verb (`getStatus`). `mkdirs` is the only Unix-style contraction. The class also has a `delete` method (matches HTTP verb) but no `make` or `create` method. `createDirectory` would align with `delete` semantically. - -### 24. First-person and ticket-driven prose in public JSDoc - -**Location:** `model.ts:17`, `:19-23` - -```ts -/** We will inspect the content of the payload to determine the type */ -AUTO = 'AUTO', -/** - * This is introduced to unblock a DR use case importing .zip file as is. - * If you import .zip file with AUTO format, it will be imported as a folder. - * In workspace 3.0 folder import will be supported via a different API. - */ -RAW = 'RAW', -``` - -"We will inspect" and "This is introduced to unblock a DR use case" are not customer-facing language. They read as commit messages or design-doc fragments. JSDoc is rendered into TS IDE tooltips that customers see. Naming-adjacent but flagged. - -## Observations - -1. **Filesystem package without filesystem vocabulary.** The package implements filesystem-style operations (`list`, `delete`, `mkdirs`, `getStatus`) but does not use the canonical filesystem nouns (`File`, `Directory`, `Path`, `Stat`). Instead it uses `ObjectInfo`/`ObjectType`/`path: string`. A user familiar with `fs.stat` or POSIX has to mentally translate. Meanwhile the sibling `files` package (`/api/2.0/fs/`) uses `DirectoryEntry`/`FileInfo` — different vocabulary for the same concept. - -2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) and `ObjectInfo.resourceId` (string, unified-resource) are both returned, both documented as "unique identifier for the object," with no naming clue about which one to pass where. This is the single most user-hostile naming issue in the file. - -3. **`ExportFormat` is the import format.** The single enum services both `ImportRequest` and `ExportRequest` (good — DRY), but the name says only "Export." A neutral name (`NotebookFormat` or `WorkspaceObjectFormat`) would describe what it actually is. - -4. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` on `ImportRequest` means "detect from file extension + header," and `AUTO` on `ExportRequest` means "decide from object type." Same enum value, different server-side algorithm. - -5. **`content: Uint8Array` documented as base64 in both directions.** Two fields hold post-decode bytes but their JSDoc reads as if they still hold base64 strings. A defensive user reading the JSDoc and base64-encoding their bytes will double-encode on the way in. The mismatch is silent and the failure mode is data corruption. - -6. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear elsewhere in the SDK.** The `files` package uses `createDirectory` and `getMetadata`. The `repos` package uses `getRepo`. Picking one verb per concept and applying it across packages would let users transfer knowledge. - -7. **Proto nested-message names surface ten times in the public API (finding 27).** Every response type and its schema constant carries the `Request_Response` infix. The source files mark the leak in eight separate `eslint-disable-next-line ... -- Proto-style nested message name.` comments at `model.ts:69, :96, :146, :156, :170, :202, :206, :221, :225, :235`. The lint rule that would block this shape (`@typescript-eslint/naming-convention`) is suppressed package-wide for these identifiers. The suppression naming the leak ("Proto-style nested message name") confirms the issue is generator-level, not incidental — fixable only in the template that emits these types from the proto schema. - -## Domain glossary - -| Term | Meaning in this package | -|------|------------------------| -| Workspace object | Anything that lives in the workspace filesystem tree: notebooks, directories, files, repos, dashboards, (legacy) libraries. | -| Path | An absolute string starting with `/Workspace/` that names a workspace object. | -| Notebook | A workspace object containing runnable code cells and prose; carries a `Language`. | -| Directory | A workspace folder; can be listed and made via `mkdirs`. | -| File | An arbitrary blob in the workspace (not a notebook). | -| Repo | A Git-linked directory; appears in `ObjectType` but managed by a different package. | -| DBC | Databricks archive format — a `.zip`-like bundle of one or more notebooks. | -| Import | Upload an object (or DBC archive) into the workspace at a path. | -| Export | Download an object (or DBC archive) from the workspace at a path. | -| Mkdirs | Create a directory and any missing parents at a path (single-path operation despite the plural verb). | -| Get-status | Return metadata (path, type, language, ID, size, timestamps) for the object at a path — equivalent to `stat`. | -| Object ID | Legacy numeric workspace-local identifier (typed `number`, vulnerable to JS precision at >2^53). | -| Resource ID | Newer string identifier consistent across Databricks resource APIs. | -| Direct download | An `Export` mode where the response body is raw bytes instead of a base64-wrapped JSON object. | - -## File coverage - -| File | Lines | Read in full | -|------|-------|--------------| -| `src/v1/model.ts` | 299 | yes | -| `src/v1/client.ts` | 291 | yes | -| `src/v1/utils.ts` | 151 | yes | -| `src/v1/index.ts` | 21 | yes | +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md index c598cd6e..b49d36ae 100644 --- a/.agent/naming-audit/workspaceassignment.md +++ b/.agent/naming-audit/workspaceassignment.md @@ -1,178 +1,3 @@ # Naming Audit: workspaceassignment -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `packages/accessmanagement/src/v1/` (source moved here; the -`workspaceassignment` source directory no longer exists, but the -WorkspacePermissionAssignment surface continues to live in the -`accessmanagement` package). -**Versions audited:** v1 -**Inferred domain:** Account-level workspace permission assignments — list/get/update/delete the `USER`/`ADMIN` permissions a principal (user / service principal / group) has on a single workspace, plus list the catalog of workspace-level permission values supported. -**Total weird names flagged:** 23 - -## Summary -| Severity | Count | -| --- | --- | -| High | 7 | -| Medium | 9 | -| Low | 6 | -| Observation | 1 | - - -## High severity - -### 1. Package name `workspaceassignment` (historic) / `accessmanagement` (current) vs API path `/permissionassignments` — package directory / `src/v1/client.ts:103,131,159,187` -- **Why weird:** The npm package is named `@databricks/sdk-workspaceassignment`, but every type in it is about a `PermissionAssignment` (`DeleteWorkspacePermissionAssignmentRequest`, `GetWorkspacePermissionAssignmentsRequest_Response`, `WorkspacePermissionAssignmentOutput`, ...), every URL ends in `permissionassignments`, and the conceptually equivalent type in the `iam` package is `WorkspaceAssignmentDetail`. So the package is called "workspace assignment" (singular, no qualifier) while the contents are uniformly "workspace permission assignment(s)" and the upstream iam port models the same domain object under a third name entirely. The singular package name is also a singular/plural mismatch with the operations it exposes (`getWorkspacePermissionAssignments`, plural). The surface has since been merged into `accessmanagement`, which is broader but still does not match the `/permissionassignments` URL fragment. -- **Category:** 8 (redundant/inconsistent suffix), 9 (singular/plural), 12 (duplicate concept — `iam.WorkspaceAssignmentDetail`). -- **Suggested name:** Rename the package to `workspacepermissions` (matches the listWorkspacePermissions surface and the `permissionassignments` URL fragment), or merge into `iam` since `iam.WorkspaceAssignmentDetail` already covers the same conceptual entity. At minimum align with the route: `workspacepermissionassignments`. -- **Rationale:** Three different names for one concept across the SDK (`workspaceassignment` package, `WorkspacePermissionAssignment*` types, `iam.WorkspaceAssignmentDetail`) is a Discovery footgun — users searching for "workspace assignment" will hit the iam package first and miss this one. - -### 2. `WorkspacePermission.UNKNOWN` sentinel inconsistent with `*_UNSPECIFIED` used elsewhere — `src/v1/model.ts:40` -- **Why weird:** This package uses `UNKNOWN` as the zero-value sentinel, but every other enum in this codebase uses `*_UNSPECIFIED` (e.g., `REQUEST_AUTHZ_IDENTITY_UNSPECIFIED` in this same file at model.ts:34; `WORKSPACE_PERMISSION_UNSPECIFIED`, `PRINCIPAL_TYPE_UNSPECIFIED` in iam). The sentinel form is inconsistent across packages modelling the same concept. -- **Category:** 17 (inconsistent sentinel naming across enums in the same codebase). -- **Suggested name:** Rename `UNKNOWN` to `WORKSPACE_PERMISSION_UNSPECIFIED` to align with the iam mirror and the rest of the SDK. -- **Rationale:** The iam mirror of this same concept uses `WORKSPACE_PERMISSION_UNSPECIFIED`. A consistent sentinel name across packages reduces user confusion when bridging the two. - -### 3. `GetWorkspacePermissionAssignmentsRequest` request type for an HTTP `GET` that returns a *list* — `src/v1/model.ts:203`, `src/v1/client.ts:127` -- **Why weird:** The method `getWorkspacePermissionAssignments` returns a list of `permissionAssignments` (model.ts:213). That is a `list` operation, not a `get`. Compare to `iam.ListWorkspaceAssignmentDetailsRequest` (same domain, different verb). Mislabelling a list as "get" leads users to expect a single object back. -- **Category:** 6 (misleading verb), 13 (verb-tense inconsistency — `Get` for a list result), 17 (verb inconsistency with iam mirror). -- **Suggested name:** `ListWorkspacePermissionAssignmentsRequest` / `…Response`, method `listWorkspacePermissionAssignments`. -- **Rationale:** A plural-result response makes this unambiguously a list. The current name reads as "get the assignments for this workspace" — singular intent, plural body — and is inconsistent with `iam.ListWorkspaceAssignmentDetails`. - -### 4. `ListWorkspacePermissionsRequest` returns a static catalog, not data — `src/v1/model.ts:231`, `src/v1/client.ts:155` -- **Why weird:** `listWorkspacePermissions` returns the (fixed) catalog of `PermissionOutput` values (`USER`, `ADMIN`, ...) that the workspace supports. The Go SDK has identical confusion: every method called `list…` looks like it lists user data, but here it lists the *types of permissions that exist*. Plus the method appears side-by-side with `getWorkspacePermissionAssignments` (which actually lists assignments), so users will wire the wrong one. -- **Category:** 6 (misleading — name implies data, returns metadata), 15 (generic field `permissions` losing meaning). -- **Suggested name:** `ListAssignablePermissionsRequest` / `listAssignablePermissions`, or `GetSupportedWorkspacePermissions` / `getSupportedWorkspacePermissions`. Either makes the metadata nature explicit. -- **Rationale:** `listWorkspacePermissions(req)` vs `getWorkspacePermissionAssignments(req)` are visually similar enough that someone scanning autocomplete will pick the wrong one. The semantic gulf between them (catalog vs assignments) demands distinct verbs. - -### 5. `PermissionOutput` / `PrincipalOutput` / `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` -- **Why weird:** `Output` suffix is a generic noise word that adds zero information — every response shape is "output". The Go SDK uses `Output` because protobuf service definitions use `Output` as a request/response naming convention; in TS this surfaces as `Permission` vs `PermissionOutput`, two near-identical types differing only by the field semantics. The doc comment on `WorkspacePermissionAssignmentOutput` even spells it out: "The output format for existing workspace PermissionAssignment records". A name that needs the doc string to say "this is the output type" is the symptom. -- **Category:** 1 (vague suffix), 8 (redundant type suffix), 14 (proto/Go naming). -- **Suggested name:** Drop the `Output` suffix. `Permission` (the enum) and `PermissionDetail`/`PermissionDescription` (the wrapper carrying `description`) is one option; `WorkspacePermissionAssignment`, `Principal`, `PermissionDescriptor` is another. The iam mirror dropped `Output` already (`WorkspaceAssignmentDetail`, not `WorkspaceAssignmentDetailOutput`). -- **Rationale:** Cf. rule 1 of the audit list ("vague/generic"). `Output` carries no semantics and conflicts with the sibling type in the same package. - -### 6. `WorkspacePermissionAssignmentOutput` vs `iam.WorkspaceAssignmentDetail` duplicate concept — `src/v1/model.ts:383` vs `packages/iam/src/v2/model.ts:983` -- **Why weird:** Two TS types modelling the same conceptual record: - - `WorkspacePermissionAssignmentOutput` (here): `{ principal: PrincipalOutput, permissions: WorkspacePermission[], error: string }`. - - `iam.WorkspaceAssignmentDetail`: `{ principalId, workspaceId, accountId, principalType, entitlements }`. - - Both encode "what permissions does this principal have on this workspace?", but with different field sets and different field names. Users will not know which is canonical. The two packages share zero types. -- **Category:** 12 (duplicate concept), 1 (vague — `…Detail` vs `…Output` vs no suffix). -- **Suggested name:** Reconcile with iam. If the workspaceassignment API is older/account-level and iam is workspace-level, document that explicitly; if they overlap functionally, ship one shape and re-export from both packages. -- **Rationale:** This surface is a tiny 4-method slice within `accessmanagement`; living without a consistent type with iam is sustainable, but every SDK consumer will need to bridge the two by hand. - -### 7. `PrincipalOutput.principalName` discriminated union — `src/v1/model.ts:268-285` -- **Why weird:** The discriminator field is named `principalName` and each variant carries its own typed sub-field (`userName`, `groupName`, `servicePrincipalName`). The variant tag values are also full identifier strings (`'userName' | 'groupName' | 'servicePrincipalName'`). The result is access like `principal.principalName.userName` — three name-words in a row. The actual `displayName` is a *separate* sibling field two lines down, so the structure conflates "what kind of principal is it?" with "what is its identifier?". The iam package handles the same idea more cleanly via a `principalType: PrincipalType` enum + a single `principalId: number` field. -- **Category:** 5 (cryptic / redundant), 11 (wrapper around oneof), 12 (duplicate of `iam.PrincipalType` mechanism), 15 (generic field names lose meaning when nested). -- **Suggested name:** `principalType: PrincipalType` enum + flatten the identifier to a single string field (or per-variant fields at the top level). Match the iam approach. -- **Rationale:** `principal.principalName.userName` is three nested name tokens when the encoding is "this principal is a user named X". A flatter `principalType: 'USER' | 'GROUP' | 'SERVICE_PRINCIPAL', principalName: string, displayName: string` reads far better. - -## Medium severity - -### 8. `accountId` doc comment "The account ID." — `src/v1/model.ts:123,204,232,363` -- **Why weird:** Doc is uniformly terse — "The account ID." Doesn't say whether it's a UUID, an integer, that it falls back to `ClientOptions.accountId` (per `client.ts:71-73,86`), that it's required for the URL path, or that it gets URL-injected and not query-parameterised. The same field appears in four request types with the same too-thin doc. -- **Category:** 19 (underspecified ID). -- **Suggested name:** Keep `accountId`, rewrite doc to `"Databricks account ID (UUID). If omitted on the request, falls back to ClientOptions.accountId. Required at request time — the SDK substitutes an empty string into the URL path if neither is set."` -- **Rationale:** This is the only ID that has a client-side fallback mechanism. Hiding that in a comment three files away is a footgun. - -### 9. `workspaceId?: number` typed as `number` — `src/v1/model.ts:126,207,235,366` -- **Why weird:** Workspace IDs in Databricks are 64-bit integers; JS `number` loses precision above 2^53. Same problem on `principalId` (`number` too — model.ts:128,287,368). The client also unconditionally `String(req.workspaceId ?? '')`s the value into the URL (`client.ts:103,131,159,187`), implying string semantics are sufficient — meaning `number` was the wrong primitive to begin with. -- **Category:** 16 (field type contradicts domain), 19 (underspecified ID). -- **Suggested name:** Keep `workspaceId`, type as `bigint | string` (or `string` to match the URL serialisation). -- **Rationale:** Public Databricks workspace IDs cross 2^53 in account-level deployments; silent rounding bugs are a real risk. Same concern applies to `principalId`. - -### 10. `permissionAssignments` vs `permissions` field names on response types — `src/v1/model.ts:213 vs 241,387` -- **Why weird:** The response for `getWorkspacePermissionAssignments` carries `permissionAssignments` (list of assigned-principal records with role). The response for `listWorkspacePermissions` carries `permissions` (list of *permission types*). `WorkspacePermissionAssignmentOutput.permissions` is the *roles a single principal holds*. Three different things, two of them just called `permissions`. -- **Category:** 1 (vague), 15 (generic field name loses meaning), 17 (inconsistent label across siblings). -- **Suggested name:** On the list-permissions response, rename `permissions` to `supportedPermissions` or `availablePermissions`. On `WorkspacePermissionAssignmentOutput`, rename `permissions` to `permissionLevels` or `grantedPermissions` to match the singular `permissionLevel` in `PermissionOutput`. -- **Rationale:** A user holding the response sees `.permissions` and can't tell whether it's "permissions held" or "permission types defined". - -### 11. `PermissionOutput.permissionLevel` singular vs `WorkspacePermissionAssignmentOutput.permissions` plural — `src/v1/model.ts:251 vs 387` -- **Why weird:** The same `WorkspacePermission` enum is held as singular on one type (`permissionLevel: WorkspacePermission`) and plural on another (`permissions: WorkspacePermission[]`). The lexical difference is significant (`level` vs no suffix) and inconsistent across the package. Internal users won't know whether to think of permissions as a scalar or set. -- **Category:** 9 (singular/plural inconsistency), 17 (inconsistent action verb / field name). -- **Suggested name:** Settle on one shape: if a principal can hold multiple levels, use `permissionLevels: WorkspacePermission[]` everywhere. If `PermissionOutput` is really just describing a single level, name it `permission` (singular, matching the type). -- **Rationale:** `permissionLevel` and `permissions` are both `WorkspacePermission`-typed; the asymmetry has no semantic justification visible in this file. - -### 12. `WorkspacePermissionAssignmentOutput.error?: string` — `src/v1/model.ts:389` -- **Why weird:** Embedding an opaque error string inside the success response body. The pattern is "we succeeded enough to return data, but here's a per-record error message". This is unusual: typical SDK design surfaces errors as exceptions or as a typed error union. A bare `string` carrying potentially structured error content forces the user to parse strings. Also, `error` is a reserved-ish JS identifier (global `Error` class, `try/catch` `error` parameter) and clashes with style. -- **Category:** 1 (vague), 10 (reserved-word-adjacent), 15 (generic field loses meaning), 16 (field contradicting type — a success response carrying error data). -- **Suggested name:** `errorMessage` or `partialFailureReason`, typed as `string | undefined`. Better: model the assignment as `{ ok: true, data: ... } | { ok: false, error: ... }`. -- **Rationale:** The current shape leaks the per-record-error nature of the upstream API. At minimum rename to make the partial-failure semantics explicit. - -### 13. `PermissionOutput.description` doc comment "The results of a permissions query." — `src/v1/model.ts:252-253` -- **Why weird:** Doc string is meaningless — "description" labelled as "results of a permissions query" gives the reader zero signal about what the string contains. Looking at the upstream this likely contains a human-readable description like "Allows full access" or "Read-only access". -- **Category:** 1 (vague — both field and doc). -- **Suggested name:** Keep `description`, rewrite doc to `"Human-readable description of what this permission grants (for example, 'Allows full administrative access to the workspace')."`. -- **Rationale:** The current JSDoc is worse than no doc at all because it suggests the field is a query-result wrapper. - -### 14. `PrincipalOutput.principalName` discriminator tag values use camelCase — `src/v1/model.ts:271,276,281` -- **Why weird:** `$case` values are `'userName' | 'groupName' | 'servicePrincipalName'` — those are *field names*, not discriminator tags. A discriminator value should describe the *type* of the variant (`'user' | 'group' | 'servicePrincipal'`), not duplicate the field name. The current shape forces `principalName.userName` ("user name's user name"). -- **Category:** 5 (cryptic — discriminator tag duplicates the field), 11 (trivial wrapper-around-oneof). -- **Suggested name:** Tag values `'user' | 'group' | 'servicePrincipal'`, payload field `name: string` across all three variants. Or flatten to enum + single string. -- **Rationale:** Discriminator should let `switch (p.principalName.$case)` read as `case 'user':` rather than `case 'userName':`. - -### 15. `PrincipalOutput.principalId: number` opaque ID doc — `src/v1/model.ts:286-287` -- **Why weird:** Doc reads "The unique, opaque id of the principal." with `id` lowercase mid-sentence and no casing on the field. The same field on `DeleteWorkspacePermissionAssignmentRequest` / `UpdateWorkspacePermissionAssignmentRequest` (model.ts:128,368) is documented as `"The ID of the user, service principal, or group."` — same concept, two different docs. Also `number` typing same precision issue as workspaceId. -- **Category:** 16 (field type contradicts domain), 17 (inconsistent doc across sibling types), 19 (underspecified ID). -- **Suggested name:** Keep `principalId`, type as `bigint | string`, and use one consistent doc: `"Unique numeric identifier of the principal (user / service principal / group)."`. -- **Rationale:** Three call sites for the same field, three slightly different definitions, plus a precision risk. - -### 16. `UpdateWorkspacePermissionAssignmentRequest.permissions` doc paragraph — `src/v1/model.ts:369-376` -- **Why weird:** A multi-line JSDoc smuggling validation semantics into a public field comment: "If both 'USER' and 'ADMIN' are provided, 'ADMIN' takes precedence. Other values will be ignored. Note that excluding this field, or providing unsupported values, will have the same effect as providing an empty list, which will result in the deletion of all permissions for the principal." That last clause is a *destructive* behaviour hidden in a paragraph. Field name `permissions` plus this doc gives the field a meaning of "set or delete" depending on contents — too much overloading for one field. -- **Category:** 1 (vague — overloaded semantics), 6 (misleading — looks like an additive update, can be destructive). -- **Suggested name:** Either split into `setPermissions: WorkspacePermission[]` / `clearPermissions: boolean`, or rename to `replacePermissions` with explicit doc "Replaces all permissions on the principal. Pass an empty array (or omit) to revoke all permissions." -- **Rationale:** Hiding a "delete everything" behaviour behind an empty/missing field is a destructive-by-omission API. Type signature should make it visible. - -## Low severity - -### 17. `PrincipalOutput.principalName.servicePrincipalName: string` — `src/v1/model.ts:281-284` -- **Why weird:** A service principal's name is here typed as `string`, but the `iam` package treats service principals as either a `principalType: PrincipalType.SERVICE_PRINCIPAL` enum value or by `applicationId`. The string-only name representation here disagrees with iam's identifier model. -- **Category:** 12 (duplicate concept with iam.PrincipalType.SERVICE_PRINCIPAL), 17 (inconsistent representation across siblings). -- **Suggested name:** Align with iam: principalType enum + a single name/id field. If kept, rename the variant to `name` so it reads `principal.principalName.$case === 'servicePrincipal' && principal.principalName.name`. -- **Rationale:** Two packages, two shapes for "the name of a service principal" — pick one. - -### 18. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` -- **Why weird:** REST path uses `/permissionassignments/` (no separator), while every other Databricks REST resource in this SDK uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). This is a wire-format problem, not a TS naming problem, but it spills into the visual feel of the client URLs. -- **Category:** 3 (casing/separator inconsistency). -- **Suggested name:** N/A for TS, but flag upstream: prefer `permission-assignments`. -- **Rationale:** Cross-API consistency. - -### 19. `accountId?: string | undefined` doc placement — `src/v1/model.ts:123,124` -- **Why weird:** Doc above `accountId` says "The account ID." but the equally important fallback semantics live in `client.ts:71-73` ("Fallback for endpoints whose path contains {account_id}. If the request already carries an accountId, that value wins."). Doc is on the wrong side. -- **Category:** 19 (underspecified ID). -- **Suggested name:** Move/duplicate the fallback semantics into the model.ts JSDoc. -- **Rationale:** Most users read model.ts, not client.ts. - -### 20. `displayName` doc terseness — `src/v1/model.ts:288-289` -- **Why weird:** Doc "The display name of the principal." while the discriminated union variants above carry their own names (`userName`, `groupName`, `servicePrincipalName`). Relationship between `displayName` and the variant names is undocumented (the variant names are the canonical identifier; `displayName` is the human-friendly label — but a reader has to guess). -- **Category:** 1 (vague doc). -- **Suggested name:** Keep field name, expand doc. -- **Rationale:** A two-field name model deserves explicit roles. - -### 21. `WorkspacePermission.USER` doc string — `src/v1/model.ts:41-42` -- **Why weird:** Doc "The most basic workspace permission" on `USER` but no doc on `ADMIN`. Asymmetric annotation; reader concludes `ADMIN` has no doc because it's "obvious", but `USER` does because — what? The same enum in iam (`WorkspacePermission`) also docs `USER_PERMISSION` and nothing else. Pattern is consistent, but still strange. -- **Category:** 17 (inconsistent annotation across enum members). -- **Suggested name:** Document both, or document neither. -- **Rationale:** Hover docs read better with parity. - -### 22. URL path interpolation uses unencoded segments — `src/v1/client.ts:103,131,159,187` -- **Why weird:** Not a naming finding strictly, but worth flagging: paths interpolate `${req.accountId ?? ''}` / `${String(req.workspaceId ?? '')}` directly into URLs without `encodeURIComponent`. If a malicious or weird `accountId` ever lands in here, path injection is possible. Sibling packages use the same pattern, so it's project-wide. -- **Category:** N/A (security/correctness, not naming). -- **Suggested name:** N/A. Flag for hardening. -- **Rationale:** Belongs in a different audit, but caught in passing. - -## Observations - -### 23. Side-by-side `getWorkspacePermissionAssignments` and `listWorkspacePermissions` — `src/v1/client.ts:127,155` -- **Why weird:** Two list-like methods, one named `get*` (returns array of assignments), one named `list*` (returns a static catalog). Naming inverts the more usual REST convention where `list*` is paginated and `get*` is singular. -- **Category:** 17 (inconsistent action verbs), 13 (verb-tense inconsistency). -- **Suggested name:** `getWorkspacePermissionAssignments` → `listWorkspacePermissionAssignments`; `listWorkspacePermissions` → `getSupportedWorkspacePermissions`. Now `list*` always returns assignments, `get*` is a one-shot catalog read. -- **Rationale:** Cf. finding 3 + 4. Worth flagging once more as a pair-level observation. - -## Cross-cutting themes -1. **Non-idiomatic TS shapes.** Findings 5, 7 — `*Output` suffixes and double-wrapped oneof discriminators. Neither is idiomatic TS. -2. **Duplicated domain modelling with `iam` package.** Findings 1, 6, 7, 17 highlight that `iam.WorkspaceAssignmentDetail`, `iam.WorkspacePermission`, and `iam.PrincipalType` already model the same concepts under different names and shapes. The two packages should either share types or one should redirect to the other. -3. **Misleading verb assignment for list vs get.** Findings 3, 4, 23 — the array-returning method is named `get*`, the static-catalog method is named `list*`. This inverts the REST-list convention used elsewhere in the SDK. -4. **Underspecified IDs and weak typing.** Findings 8, 9, 15, 19 — IDs are `number` (precision risk) or thinly typed `string`, with critical fallback / serialisation behaviour hidden in client.ts comments rather than the type. +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspaceconf.md b/.agent/naming-audit/workspaceconf.md index 9ef8bcef..86ac761b 100644 --- a/.agent/naming-audit/workspaceconf.md +++ b/.agent/naming-audit/workspaceconf.md @@ -1,251 +1,3 @@ # Naming Audit: workspaceconf -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `/home/parth.bansal/sdk-js/packages/workspaceconf/` -**Versions audited:** v1 -**Inferred domain:** Reads and writes a workspace's "known configuration" key/value entries — a generic `map[string]string` bag of advanced workspace toggles served from `/api/2.0/workspace-conf`. The legacy Go SDK calls this surface `WorkspaceConf` with methods `GetStatus`/`SetStatus`. -**Total weird names flagged:** 23 - ---- - -## Top themes (read this first) - -1. **The package name `workspaceconf` is the single biggest offense in this audit.** - - `conf` is an undocumented, cryptic abbreviation of `configuration`. Spelling it out costs four characters and removes ambiguity (cf. *config* vs *conference* vs *confidence*). - - The package's *entire surface area* is two types and two methods — yet "conf" is repeated in: package name, every type name, every method name, and the JSDoc on every public symbol. The cost of fixing it is low; the benefit is high. - - Naming-rule literature (Google TS style guide §5.4 "Abbreviations") and Databricks' own JS SDK convention (see `packages/clusters`, `packages/jobs`, `packages/cleanrooms` — all spelled out) say the right name is **`workspaceconfig`** or **`workspaceconfiguration`**. - -2. **`workspaceconf` semantically overlaps with `workspacesettings`, `settings`, and `accountsettings` — and the overlap is hidden by the cryptic name.** - - `workspacesettings` (the sibling package) exposes ~80 typed setting toggles (CSP, ESM, default warehouse, auto-restart, …) — i.e. the *typed* workspace configuration API. - - `workspaceconf` exposes the *legacy untyped* workspace configuration API, where everything is `string`/`string` and toggles are referenced by string key (e.g. `"enableIpAccessLists"`). - - In the legacy Go SDK both APIs live in *the same package* (`service/settings`) and share documentation; in the JS SDK they are split into two packages whose names do not telegraph the typed-vs-untyped distinction. The cryptic abbreviation `conf` makes the relationship invisible. - - A reader landing on `@databricks/sdk-workspaceconf` cannot tell from the name whether to use it or `workspacesettings`. The right answer ("legacy untyped string-bag for advanced toggles") should be in the package name and/or the module JSDoc — currently it is in neither. - -3. **The TS port silently changed `WorkspaceConf` from a `map` to a single `{key, value}` pair.** This is the most consequential single-name finding in the audit. See §6 below — it is not just a naming bug, it is a wire-shape bug that makes the call useless for the standard multi-toggle pattern. - ---- - -## Summary table - -| # | Severity | Category | Identifier | File:line | -|---|----------|----------|------------|-----------| -| 1 | High | Cryptic abbreviation (package-wide) | package name `workspaceconf` / `@databricks/sdk-workspaceconf` | `package.json:2` | -| 2 | High | Cryptic abbreviation, Type-suffix tautology | `WorkspaceConfRequest` (interface) | `model.ts:9-12` | -| 3 | High | Cryptic abbreviation, Overly verbose | `GetWorkspaceConfRequest` | `model.ts:5-7` | -| 4 | High | Misleading / inconsistent action verb | `updateWorkspaceConf` method (PATCH that actually replaces / `SetStatus` upstream) | `client.ts:89` | -| 5 | High | Misleading / generic field name | `keys?: string` (single CSV string, not an array) | `model.ts:6` | -| 6 | High | Misleading / wire-shape regression vs Go SDK | `WorkspaceConfRequest = {key, value}` (Go is `map[string]string`) | `model.ts:9-12` | -| 7 | High | Duplicate concept | `workspaceconf` vs `workspacesettings` | package level | -| 8 | High | Generic field name losing meaning | `key?` / `value?` fields | `model.ts:10-11` | -| 9 | Medium | Method name redundancy | `Client.getWorkspaceConf` / `Client.updateWorkspaceConf` | `client.ts:58, 89` | -| 10 | Medium | Verb-tense inconsistency cross-package | TS `getWorkspaceConf`/`updateWorkspaceConf` vs Go `GetStatus`/`SetStatus` | `client.ts` vs Go SDK | -| 11 | Medium | Singular/plural mismatch | `keys` (plural query arg) on a request that returns *one* `{key, value}` | `model.ts:6` vs `model.ts:9-12` | -| 12 | Medium | Singular/plural mismatch | `WorkspaceConfRequest` (singular type) but the endpoint accepts/returns a *map* | `model.ts:9-12` | -| 13 | Medium | Overly verbose / module JSDoc missing | no `index.ts` module-level JSDoc explaining the package's scope | `index.ts:1-8` | -| 14 | Medium | Reserved-word adjacency | `key` (TS-friendly but shadows builtin `Map.prototype.keys`) | `model.ts:10` | -| 15 | Medium | Misleading suffix | `WorkspaceConfRequest` is also the *response* of `getWorkspaceConf` — the `Request` suffix lies | `client.ts:61, 90` | -| 16 | Medium | Misleading PATCH semantics | "Sets the configuration status … including enabling or disabling it." | `client.ts:88` | -| 17 | Low | Acronym casing inconsistency | `Conf` vs spelled-out `Config` across SDK packages | cross-package | -| 18 | Low | Verbose JSDoc | "Gets the configuration status for a workspace." / "Sets the configuration status …" | `client.ts:57, 88` | -| 19 | Low | Underspecified ID | `keys` accepts comma-separated string of unspecified vocabulary | `model.ts:6` | -| 20 | Low | Type-suffix tautology | `WorkspaceConfRequest` inside package `workspaceconf` → triple stutter | `model.ts:9` | -| 21 | Low | Module-doc location | no top-of-file JSDoc on `index.ts` (per CLAUDE.md §10.6) | `index.ts` | -| 22 | Low | Field contradicting type domain | `WorkspaceConfRequest.value` typed `string`, but actual values are stringified booleans/numbers | `model.ts:11` | -| 23 | Low | Inconsistent action verb | `updateWorkspaceConf` (TS) corresponds to HTTP `PATCH` with **full-bag-replace** server semantics | `client.ts:98` | - ---- - -## High severity - -### 1. Package name `workspaceconf` — cryptic abbreviation -- **File:line:** `package.json:2` (`"name": "@databricks/sdk-workspaceconf"`); directory path; every import site. -- **Category:** Cryptic abbreviation. -- **Suggestion:** **`workspaceconfig`** (or `workspaceconfiguration` if the SDK is verbose-friendly). Equivalently, scoped name `@databricks/sdk-workspaceconfig`. -- **Rationale:** "conf" is not a standard abbreviation of "configuration" in any major TS/JS style guide. The Google TS style guide explicitly forbids non-conventional abbreviations (§5.4 *Abbreviations*: "Treat abbreviations like acronyms in names as whole words … Don't use abbreviations that are not widely accepted within the team or community"). The TS SDK already uses fully spelled-out forms in sibling packages (`workspacesettings`, `workspaceassignment`, `workspacebindings`) so "workspaceconf" stands out as the lone abbreviated package. The legacy Go SDK is *also* fully spelled-out — `WorkspaceConf` is the legacy type name in `service/settings`, but the *package* there is `settings`, not `workspaceconf`. This package name is a JS-SDK invention and could be fixed at the generator level with no Go-SDK churn. - -### 2. `WorkspaceConfRequest` (interface) — cryptic + tautological -- **File:line:** `model.ts:9-12` -- **Category:** Cryptic abbreviation, type-suffix tautology, duplicate-concept. -- **Suggestion:** Rename the interface to `WorkspaceConfigEntry` (because it represents *one* key/value pair — see §6) and rename the package to `workspaceconfig` (§1). Then the type read by the consumer becomes `workspaceconfig.Entry` — semantically clear, no abbreviation. -- **Rationale:** Three problems at once. (a) "Conf" is cryptic (§1). (b) Inside a package literally named `workspaceconf`, the type `WorkspaceConfRequest` stutters when consumed (`workspaceconf.WorkspaceConfRequest`). (c) The name does not describe the shape: in the TS port it is a single key/value pair, *not* the workspace configuration as a whole (see §6 for why this is also wrong). The `Request` suffix added in regeneration also lies about the role — the type is used as both request body and response value (see §15). - -### 3. `GetWorkspaceConfRequest` — cryptic + verbose -- **File:line:** `model.ts:5-7` -- **Category:** Cryptic abbreviation, overly verbose. -- **Suggestion:** Rename to `GetWorkspaceConfigRequest` once the package is spelled out (§1). If the SDK ever moves to short package-scoped names, `GetRequest` within the package context is unambiguous. -- **Rationale:** The full name `GetWorkspaceConfRequest` is 24 characters of which 12 ("WorkspaceConf") are package-redundant and 7 ("Request") are convention noise. The legacy Go SDK calls the same shape `GetStatusRequest` (16 chars, single field `Keys`). The cryptic `Conf` abbreviation (§1) compounds the verbosity — the type appears in every consumer's import list and method signature, so a 4-character savings is real. - -### 4. `updateWorkspaceConf` method name — misleading -- **File:line:** `client.ts:89-106` -- **Category:** Misleading / inconsistent action verb. -- **Suggestion:** Either `setConfig` (matches the upstream `SetStatus` semantics — the body is a full replacement, not a partial update), or `patchConfig` (matches the HTTP verb). The current name lies about both. -- **Rationale:** The JSDoc reads "Sets the configuration status for a workspace, including enabling or disabling it." — i.e. the canonical action is **set**, not **update**. The HTTP verb is PATCH (which conventionally implies partial update) but the body shape is the entire WorkspaceConf payload; the doc and the upstream Go method name (`SetStatus`) confirm full-replace semantics. The TS verb `update` is overloaded in the rest of the SDK to mean "partial mutation by field-mask," so users will reasonably assume this method merges into the existing config — and it does not. - -### 5. `keys?: string` — misleading / generic / singular-plural confusion -- **File:line:** `model.ts:6` -- **Category:** Misleading + generic field name + singular/plural mismatch. -- **Suggestion:** Rename to `configKeys?: readonly string[]` (true array, not a CSV string) and let `flattenQueryParams` / `URLSearchParams` handle list-style query encoding. If the backend genuinely takes a CSV string, document that in a JSDoc on the field; do not make the SDK type lie. -- **Rationale:** Three problems. (a) Generic: "keys" on a request type without context means nothing — *which* keys, of *what*? Compare `configKeys` which immediately answers. (b) Plural form `keys` is a TS-array idiom that the type contradicts (`string`, not `string[]`). (c) The upstream API accepts a comma-separated string, but a strongly-typed SDK should accept `string[]` and serialize the comma-join itself; the current `keys?: string` punts string-encoding to the caller. The Go SDK has the same shape (`Keys string`) — that's a Go-SDK limitation worth fixing in the JS port, not faithfully reproducing. - -### 6. `WorkspaceConfRequest = {key, value}` — wire-shape regression vs Go SDK (CRITICAL) -- **File:line:** `model.ts:9-12` -- **Category:** Misleading / Generic field names losing meaning / wire-shape divergence. -- **Suggestion:** Change the type to match upstream semantics: `WorkspaceConfig = Readonly>` (or `Map`). The endpoint `/api/2.0/workspace-conf` accepts and returns a map of multiple key/value pairs; the current `{key?: string; value?: string}` cannot represent that. -- **Rationale (the single most important finding in this audit):** - - In the legacy Go SDK (`databricks/databricks-sdk-go @ service/settings/model.go`): - ```go - type WorkspaceConf map[string]string - ``` - and the methods are: - ```go - GetStatus(ctx, GetStatusRequest) (*map[string]string, error) - SetStatus(ctx, WorkspaceConf) error - ``` - i.e. the request and response are *both* a map of arbitrary keys to string values. - - The TS port has: - ```ts - export interface WorkspaceConfRequest { - key?: string | undefined; - value?: string | undefined; - } - ``` - i.e. a single optional key/value *pair*. This: - 1. Cannot represent the multi-entry response that the API actually returns (e.g. fetching multiple keys via `keys=k1,k2` returns `{"k1":"v1","k2":"v2"}`, not `{key:"k1",value:"v1"}`). - 2. Cannot update more than one toggle at a time, while the legacy semantics permit a single PATCH to flip many. - 3. Will round-trip through zod and either fail validation or silently drop fields on every realistic payload. - - The bug is *naming-shaped* — the wire format is a string→string map; the type and its fields name a single pair — so it qualifies as a naming audit finding (the type name `WorkspaceConfRequest` promises the whole config and delivers one pair). It is also a correctness bug that should be filed against the generator. This is the *single most important* finding in this audit. - -### 7. `workspaceconf` vs `workspacesettings` — duplicate concept, undisclosed -- **File:line:** package level -- **Category:** Duplicate concept (vs workspacesettings, settings, accountsettings). -- **Suggestion:** Either: - (a) merge `workspaceconf` into `workspacesettings` as a sub-module (`workspacesettings/legacy` or `workspacesettings/raw`), since they target the same physical workspace-configuration surface, or - (b) add an unmissable `index.ts` JSDoc that says: "This package wraps the legacy untyped workspace configuration API (`/api/2.0/workspace-conf`). For typed setting toggles (CSP, ESM, default warehouse, auto-restart, etc.) use `@databricks/sdk-workspacesettings`." -- **Rationale:** A user reading the package list cannot tell what differentiates `workspaceconf` from `workspacesettings` — and the legacy Go SDK confirms they are the same logical domain (both live in `service/settings/`). The cryptic name `conf` actively hides the relationship. The package's `README` / `index.ts` says nothing to disambiguate. In a multi-package SDK this is a usability hazard: a user searching for "set workspace setting" might pick the wrong package and never realize the right typed API exists. - -### 8. `key` / `value` — generic field names losing meaning -- **File:line:** `model.ts:10-11` -- **Category:** Generic field name losing meaning. -- **Suggestion:** Once §6 is fixed (`WorkspaceConfig = Record`), the generic names go away: a map has named keys at runtime. If the wire-shape is genuinely a singleton pair (it is not, per §6), rename to `configKey` / `configValue` to add domain context. -- **Rationale:** Within a single package, every public type/method ends up reading `WorkspaceConfRequest.key` / `WorkspaceConfRequest.value` — but there is no signal of *what* the key is keyed by or *what* the value represents. Domain-bearing field names (e.g. `configKey: string`, `configValue: string`) make IDE hover meaningful. - ---- - -## Medium severity - -### 9. `Client.getWorkspaceConf` / `Client.updateWorkspaceConf` — method-name redundancy -- **File:line:** `client.ts:58, 89` -- **Category:** Method name redundancy / duplicate concept. -- **Suggestion:** `Client.get` / `Client.set` (matches Go `GetStatus`/`SetStatus` shorn of the redundant `Status` suffix), since the `Client` is already package-scoped. So `workspaceconfig.Client.get()` and `workspaceconfig.Client.set()`. -- **Rationale:** `workspaceconf.Client.getWorkspaceConf()` triple-stutters "workspace conf." Compare other SDK packages where the client carries the namespace (`clusters.Client.list()`, not `clusters.Client.listClusters()`). - -### 10. `getWorkspaceConf` / `updateWorkspaceConf` (TS) vs `GetStatus` / `SetStatus` (Go) — cross-package verb inconsistency -- **File:line:** TS `client.ts:58, 89`; Go `service/settings/api.go`. -- **Category:** Verb-tense / cross-SDK inconsistency. -- **Suggestion:** Standardize on one pair across SDKs. The cleanest is `get` / `set` (paired verbs), which matches the Go SDK and accurately describes the PATCH-as-replace semantics (§4). -- **Rationale:** A user reading both SDKs will notice the verb mismatch. "update" in particular is a foreign verb here (no other Get/Update verb pair in the Go SDK for this endpoint). - -### 11. `keys` (plural query arg) → returns *one* `{key, value}` — singular/plural mismatch -- **File:line:** `model.ts:6` vs `model.ts:9-12` -- **Category:** Singular/plural mismatch (intertwined with §6). -- **Suggestion:** Once §6 is fixed (return-type becomes a map), the plural request shape matches the plural response shape and this finding dissolves. -- **Rationale:** This is the surface symptom of §6. The request says "give me values for these keys (plural)" but the response can only carry one key. This is internally contradictory. - -### 12. `WorkspaceConfRequest` (singular type) used for a map endpoint — singular/plural mismatch -- **File:line:** `model.ts:9-12` -- **Category:** Singular/plural mismatch. -- **Suggestion:** See §6. If the type stays a single entry, rename it `WorkspaceConfigEntry` (singular noun matching singular shape). -- **Rationale:** "WorkspaceConf" (or "WorkspaceConfig") names the whole bag; "WorkspaceConfigEntry" names a single pair. The current name promises the bag, delivers the entry. - -### 13. Missing module-level JSDoc on `index.ts` -- **File:line:** `index.ts:1-8` -- **Category:** Documentation absence (relates to "module doc in index" memory rule). -- **Suggestion:** Add a top-of-file JSDoc explaining what this package wraps (legacy untyped workspace configuration), how it relates to `workspacesettings`, and giving an example invocation. -- **Rationale:** Per project rule (typescript.mdc §10.6, also in user memory), module-level JSDoc belongs in `index.ts`. The package's role is unique and easily confused with `workspacesettings`; the lack of a module-level doc maximises that confusion. - -### 14. Field name `key` — adjacent to reserved patterns -- **File:line:** `model.ts:10` -- **Category:** Reserved-word adjacency. -- **Suggestion:** Rename to `configKey` (clearer, no collision risk). -- **Rationale:** `key` is not strictly reserved, but it collides with `Map.prototype.keys`, `Object.keys`, React's `key` prop, etc., so type-narrowing in user code can become ambiguous. A package-specific prefix removes the collision. - -### 15. `WorkspaceConfRequest` named "Request" but also used as response — misleading suffix -- **File:line:** `client.ts:61, 90` (used as both `Promise` return and `req: WorkspaceConfRequest` argument). -- **Category:** Misleading suffix / duplicate concept. -- **Suggestion:** Split into `WorkspaceConfig` (response — the full map) and `UpdateWorkspaceConfigRequest` (request — a `Partial` or `Record` of just the keys to set). The Go SDK gets away with the overload because the type *is* the map, but the TS port's `{key, value}` shape (§6) makes this overload doubly confusing. -- **Rationale:** The regeneration added a `Request` suffix to what used to be `WorkspaceConf`, but the type is still returned by `getWorkspaceConf` as `Promise` (client.ts:61). A type named `…Request` that is also a response value is actively misleading — naming-convention readers expect `…Request` to be input-only. Either drop the suffix (use `WorkspaceConfig`) or split into distinct request and response types. Using the same shape for both works only when the wire shape is symmetric *and* the type name is shape-accurate; here it's neither, and the suffix now compounds the confusion. - -### 16. PATCH but full-replace — misleading HTTP semantics -- **File:line:** `client.ts:88` (JSDoc: "Sets the configuration status …"), `client.ts:98` (HTTP `PATCH`). -- **Category:** Misleading. -- **Suggestion:** Document that PATCH is *full-bag-replace* for unspecified keys (or that absent keys retain their value — whichever is actually true). Currently the user has to inspect the upstream Go SDK to know. -- **Rationale:** HTTP PATCH conventionally merges; this endpoint's verb is `Set`. The semantic difference matters for any caller writing safe code. - ---- - -## Low severity - -### 17. `Conf` vs `Config` — acronym/abbreviation casing inconsistency cross-SDK -- **File:line:** cross-package -- **Category:** Acronym/abbreviation casing inconsistency. -- **Suggestion:** Pick `Config` everywhere (§1). -- **Rationale:** Other SDK packages spell it out; only `workspaceconf` abbreviates. - -### 18. JSDoc redundancy on the two methods -- **File:line:** `client.ts:57` ("Gets the configuration status for a workspace."), `client.ts:88` ("Sets the configuration status for a workspace, including enabling or disabling it."). -- **Category:** Overly verbose / repetitive. -- **Suggestion:** Move "the configuration status for a workspace" into the module-level JSDoc (§13); per-method docs can be one-liners ("Returns the current config." / "Replaces the config."). -- **Rationale:** Both method docs lead with the same phrase; the body of the method already implies it. - -### 19. `keys` parameter accepts an unspecified vocabulary -- **File:line:** `model.ts:6` -- **Category:** Underspecified ID / generic field. -- **Suggestion:** Either link to the Databricks docs that enumerate the valid keys ("enableIpAccessLists", "maxTokenLifetimeDays", "enableProjectTypeInWorkspace", …) or accept a typed union of known string-literal keys. -- **Rationale:** A user can't construct a valid request without finding the key vocabulary somewhere external. Documenting the legal set is a 10-minute fix and dramatically improves usability. - -### 20. Type-suffix tautology `workspaceconf.WorkspaceConfRequest` -- **File:line:** `model.ts:9` (and every consumer importing `workspaceconf.WorkspaceConfRequest`). -- **Category:** Type-suffix tautology. -- **Suggestion:** Drop the package prefix from the type name (per §2 — once §1 is done, `WorkspaceConfig` -> `Entry` or `Config`). -- **Rationale:** Same pattern as `accountsettings.PersonalComputeSetting` flagged in the `accountsettings` audit (severity #12-15 there). TS users access via package; the package prefix on the type name is gratuitous. - -### 21. No module-level JSDoc per project rule -- **File:line:** `index.ts:1-8` -- **Category:** Convention violation. -- **Suggestion:** Add `@module` / file-leading JSDoc summary. -- **Rationale:** Project memory references `feedback_module_doc_in_index.md` and `typescript.mdc` §10.6 — module-level JSDoc must live in `index.ts`. The current `index.ts` is comment-free. - -### 22. `value: string` typing — field contradicts domain -- **File:line:** `model.ts:11` -- **Category:** Field contradicting type domain / underspecified. -- **Suggestion:** Document (in a JSDoc on `value`) that the value is always a *stringified* primitive — even toggles are `"true"`/`"false"` strings, not booleans. Or, in the wrapper layer, deserialize known boolean/integer keys into their TS-native types. -- **Rationale:** The legacy Go SDK preserves the wire-shape `map[string]string`. In TypeScript, presenting a `value: string` field where the value is actually a JSON-encoded bool or number leaks the wire format to the user. Either document or transform. - -### 23. `updateWorkspaceConf` method body uses HTTP `PATCH` — verb mismatch with name -- **File:line:** `client.ts:98` -- **Category:** Inconsistent action verb (relates to §4). -- **Suggestion:** Either rename the method to `patchConfig` (verb matches HTTP) or change the underlying call to `PUT` (semantics match). Since the upstream Go calls this `SetStatus` (i.e. canonically a SET, not a partial update), `setConfig` is closest to truth. -- **Rationale:** Three different names ("update" / "PATCH" / "Set") describe the same operation across the three layers — TS method, HTTP layer, Go SDK. Pick one verb for the user-visible name. - ---- - -## Cross-package observations (informational) - -- The new Go SDK (`databricks/sdk-go`) does **not** have a top-level `workspaceconf` package — the workspace configuration surface in the new SDK lives under `settings/v2`. So the `workspaceconf` JS package's name is a JS-port choice and is *not* directly inherited from the new Go SDK; renaming costs the JS port nothing on the Go-port-correspondence axis. -- The legacy Go SDK (`databricks/databricks-sdk-go @ service/settings/`) is the source for the type names `WorkspaceConf`, `GetStatusRequest`, `SetStatus`, etc. The legacy Go shape `WorkspaceConf = map[string]string` is the **canonical wire shape** — the TS port diverged from it (§6). -- `workspacesettings`, `accountsettings`, `settings`, and `workspaceconf` are four packages with overlapping responsibilities. A single-page comparison doc (in the JS SDK's README) would dramatically reduce confusion. This is out of scope for a naming audit but recommended. - ---- - -## Recommendations (priority order) - -1. **Fix §6** (wire-shape regression). This is a correctness bug, not just a naming bug; file it against the generator. -2. **Rename the package** `workspaceconf` → `workspaceconfig` (§1). Update `package.json`, directory name, every import site, the index doc. -3. **Add module-level JSDoc** to `index.ts` (§7, §13, §21) explaining the package's role and its relationship to `workspacesettings`. -4. **Rename the method pair** to `get` / `set` (or `getConfig` / `setConfig`) for cross-SDK and HTTP-semantic accuracy (§4, §9, §10, §23). -5. **Type `keys` as `string[]`** (§5) and have the client serialize the CSV. - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md index e719aae3..1fd9627e 100644 --- a/.agent/naming-audit/workspacesettings.md +++ b/.agent/naming-audit/workspacesettings.md @@ -1,375 +1,3 @@ # Naming Audit: workspacesettings -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** All findings below pre-date the consolidation and are no longer actionable against active source. Retained as historical record per the audit policy. - -**All findings retired on 2026-05-22.** - -**Path:** `/home/parth.bansal/sdk-js/packages/workspacesettings/` -**Versions audited:** v1 -**Inferred domain:** Workspace-scoped Databricks settings: AI/BI dashboard embedding policy, automatic cluster update, compliance security profile (CSP), dashboard email subscriptions, default namespace, default warehouse ID, legacy access/DBFS disablement, notebook/file export, notebook table clipboard, results download (notebook and SQL), enhanced security monitoring (ESM), LLM proxy partner-powered AI, and restrict-workspace-admins. -**Total weird names flagged:** 45 - -## Summary table - -| # | Severity | Category | Identifier | File:line | -|---|----------|----------|------------|-----------| -| 1 | Critical | Duplicate concept across packages | `workspacesettings` vs `settings` vs `accountsettings` vs `workspaceconf` | package boundary | -| 2 | Critical | Duplicate type | `BooleanMessage`, `StringMessage` (also in `accountsettings`, `settings/v2`) | `model.ts:181, 1029` | -| 3 | Critical | Duplicate type | `ComplianceStandard` (also in `accountsettings`) | `model.ts:8` | -| 4 | Critical | Duplicate concept | `RestrictWorkspaceAdminsSetting`, `AibiDashboardEmbeddingAccessPolicySetting` etc. mirror types in `settings/v2` | `model.ts:986, 99` and `settings/v2` | -| 5 | High | Cryptic abbreviation | `Aibi` (`AI/BI`) family of types/methods | `model.ts:52-155, 99-155`; `client.ts:335,377,752,792,1257,1292` | -| 6 | High | Cryptic abbreviation | `Csp` (Compliance Security Profile) | `model.ts:239-268`; `client.ts:876, 1369`; URL `shield_csp_enablement_ws_db` | -| 7 | High | Cryptic abbreviation | `Esm` (Enhanced Security Monitoring) | `model.ts:697-728`; `client.ts:1104,1560`; URL `shield_esm_enablement_ws_db` | -| 8 | High | Cryptic abbreviation | `Llm` (LLM Proxy Partner-Powered Workspace) | `model.ts:538-565, 934-951, 1137-1144`; `client.ts:624,1140,1588` | -| 9 | High | Cryptic abbreviation | `Dbfs` casing (`disableLegacyDbfs`) | `model.ts:509-536, 646-665, 850-863, 1117-1124`; `client.ts:584,1063,1522` | -| 10 | High | Misleading | `settingName` documented as "will not be respected" on requests | `model.ts:120, 148, 172, 261, 285, 312, 331, 640, 661, 673, 683, 693, 721, 949, 1001, 1025` | -| 11 | High | Misleading | `settingTypeName` query param ignored on Delete/Get (path param wins) | `client.ts:341-346, 383-388, 425-430, 470-475, ...` | -| 12 | High | Underspecified ID | `DefaultWarehouseId` type contains no warehouse-ID field — just an envelope | `model.ts:316-333` | -| 13 | High | Inconsistent action verbs | `patch*` vs `update*` for the same semantic (PATCH HTTP verb) | `client.ts:192 vs 1257, 1292, 1328, ...` | -| 14 | High | Inconsistent action verbs | `delete*` methods actually "revert" / "reset to default" | `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` | -| 15 | High | Triple-stutter against package name | `*Setting` suffix on every type in `workspacesettings` package | `model.ts:105, 246, 706, 986, 1010` and passim | -| 16 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyAccess` (action phrase used as type/state) | `model.ts:625-644` | -| 17 | Medium | Verb-tense / verb-in-noun position | `DisableLegacyDbfs` | `model.ts:646-665` | -| 18 | Medium | Verb-tense / verb-in-noun position | `EnableExportNotebook` | `model.ts:667-675` | -| 19 | Medium | Verb-tense / verb-in-noun position | `EnableNotebookTableClipboard` | `model.ts:677-685` | -| 20 | Medium | Verb-tense / verb-in-noun position | `EnableResultsDownloading` (also: `-ing` mismatch) | `model.ts:687-695` | -| 21 | Medium | Verb-tense / -ing gerund | `EnableResultsDownloading` vs `SqlResultsDownload` (gerund vs noun, same domain) | `model.ts:687, 1010` | -| 22 | Medium | Misleading / parallel naming | `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` (separately) — overlapping concepts | `model.ts:687 vs 1010`; client `patchEnableResultsDownloading` vs `updateSqlResultsDownload` | -| 23 | Medium | Misleading | `LlmProxyPartnerPoweredWorkspace` — "Workspace" suffix on type | `model.ts:934-951` | -| 24 | Medium | Misleading | `automaticClusterUpdateWorkspace` discriminator name | `model.ts:175, 1245` | -| 25 | Medium | Misleading | `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` discriminators | `model.ts:264, 724` | -| 26 | Medium | Misleading | `restartEvenIfNoUpdatesAvailable` — double negative | `model.ts:190` | -| 27 | Medium | Misleading | `canToggle` — boolean field on enablement message | `model.ts:187` | -| 28 | Medium | Misleading | `forcedForComplianceMode` — verb-past-participle as flag | `model.ts:208` | -| 29 | Medium | Misleading | `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — negative phrasing | `model.ts:204, 206` | -| 30 | Medium | Acronym casing | `Dbfs` (should be `DBFS`); `Aibi` (should be `AiBi` or `AIBI`); `Llm` (should be `LLM`); `Csp`/`Esm`/`Sql` | `model.ts` passim | -| 31 | Medium | Acronym casing | `Id` vs `ID` (`DefaultWarehouseId`, `defaultWarehouseId`) | `model.ts:316, 1097` | -| 32 | Medium | Acronym casing | `Url` (`httpReq.url`) vs `URL` casing — minor reference | `utils.ts:70, 98, 103` | -| 33 | Medium | Verb-tense inconsistency | `Enable*` (imperative) vs `Disable*` (imperative) vs `EnableResultsDownloading` (gerund) | `model.ts:667, 677, 687, 625, 646` | -| 34 | Medium | Verb-tense inconsistency | `EnableExportNotebook` vs `EnableNotebookTableClipboard` (verb noun order swap) | `model.ts:667, 677` | -| 35 | Medium | Reserved-word collision | `delete*` method names match JS reserved word adjacency | `client.ts:335, 377, 419, ...` | -| 36 | Medium | Verb-tense / past-participle as field | `disableGovTagCreation` on `RestrictWorkspaceAdminsMessage` (action-as-field) | `model.ts:983` | -| 37 | Low | Cryptic wire-key abbreviation | `aibi_dash_embed_ws_acc_policy`, `aibi_dash_embed_ws_apprvd_domains` | `client.ts:339, 381, 756, 796, 1261, 1296` | -| 38 | Low | Cryptic wire-key abbreviation | `default_namespace_ws`, `shield_csp_enablement_ws_db`, `shield_esm_enablement_ws_db` | `client.ts:468, 876, 956, 1104, 1369, 1439, 1560` | -| 39 | Low | Acronym casing | `eTag` (doc) vs `etag` (field) | `model.ts:107-114, 248-254, 1012-1018` | -| 40 | Low | Singular/plural | `complianceStandards` (array) but inside `ComplianceSecurityProfile` (singular envelope) — consistent but flag for review | `model.ts:243` | -| 41 | Low | Singular/plural | `approvedDomains` (array) on `AibiDashboardEmbeddingApprovedDomains` (plural type / plural field — okay, but mismatched against sibling singular types like `AibiDashboardEmbeddingAccessPolicy`) | `model.ts:130` | -| 42 | Low | Verbose | Setting wire-key length: `automatic_cluster_update`, `dashboard_email_subscriptions`, `restrict_workspace_admins` | `client.ts:836, 423, 673` | -| 43 | High | Proto-architectural-leak (`Message` suffix) | `BooleanMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage` | `model.ts:181, 1029, 185, 977` | -| 44 | High | Proto-architectural-leak (`Message_` nested infix) | `ClusterAutoRestartMessage_EnablementDetails`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:60, 72, 84, 202, 212, 219, 230` | -| 45 | Medium | Proto-architectural-leak (generic `Details` suffix) | `ClusterAutoRestartMessage_EnablementDetails` and field `enablementDetails` | `model.ts:189, 202` | - ---- - -## Critical severity - -### 1. Four overlapping settings packages: `workspacesettings`, `settings`, `accountsettings`, `workspaceconf` -- **Category:** Duplicate concept across packages -- **Suggestion:** Consolidate. The user-facing settings model on Databricks is one thing scoped two ways (account vs workspace). The TS SDK should expose `settings` with sub-namespaces `workspace.*` and `account.*`, and a single discoverable client per scope. The fourth (`workspaceconf`) is a tiny legacy key/value API that should either fold into `workspacesettings` or be marked clearly legacy. -- **Rationale:** A consumer trying to "set a workspace property" today has to know that: - - Default-namespace, AI/BI embedding, automatic-cluster-update, CSP, ESM, LLM-proxy, dashboard-email-subs, default-warehouse, disable-legacy-access, disable-legacy-DBFS, enable-export-notebook, enable-notebook-table-clipboard, enable-results-downloading, restrict-workspace-admins, sql-results-download → `workspacesettings`. - - Generic public-setting CRUD (the umbrella API) → `settings/v2`. - - Account-IP-access, CSP/ESM at account scope, disable-legacy-features, LLM-proxy at account scope, personal compute → `accountsettings`. - - Arbitrary workspace conf KV → `workspaceconf`. - No documentation surfaces this taxonomy; the consumer has to guess. The four packages share types verbatim and the `settings/v2` package already exposes a generic `Setting`/`SettingsMetadata` shape that *can* represent any of these. The split is purely a wire-routing artefact. - -### 2. `BooleanMessage`, `StringMessage` — duplicated in three sibling packages -- **File:line:** `model.ts:181-183, 1029-1032` -- **Category:** Duplicate type -- **Suggestion:** Hoist into `@databricks/sdk-core/wkt` (or similar shared location) alongside `FieldMask`. These are `google.protobuf.BoolValue` and `google.protobuf.StringValue` analogues and belong with `FieldMask`, which the package already imports from `wkt`. -- **Rationale:** Three packages (`workspacesettings`, `accountsettings`, `settings/v2`) all define identical types — same one boolean/string field, same wrapping. Consumers cannot pass a `BooleanMessage` from one package to a sibling method that takes a `BooleanMessage`. The duplication is wire-bookkeeping leaking through the API surface. - -### 3. `ComplianceStandard` enum — duplicated in `accountsettings` -- **File:line:** `model.ts:8-49` (here) and identical in `accountsettings/src/v1/model.ts` -- **Category:** Duplicate type -- **Suggestion:** Hoist into a shared `compliance` module. The enum has 15 values, all canonical regulatory standards (HIPAA, PCI_DSS, FEDRAMP_*, etc.) that do not differ by setting scope. -- **Rationale:** HIPAA at the account level *is* HIPAA at the workspace level. Two enums with identical members means type-incompatible values for the same regulatory concept. - -### 4. Whole types mirrored in `settings/v2` -- **File:line:** `model.ts:99, 133, 239, 246, 686, 706, 977, 986` vs `settings/v2/model.ts` -- **Category:** Duplicate concept -- **Suggestion:** Pick one canonical home. `settings/v2` is clearly the generic surface (it exposes `Setting`, `SettingsMetadata`, `PatchPublicWorkspaceSettingRequest`). The specific-typed methods in `workspacesettings` are a sister API for the same backend data. Either fold the specific methods into `settings/v2` (preferred) or document which one is canonical. -- **Rationale:** `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage`, `BooleanMessage`, `StringMessage` all live in both packages with identical fields. The consumer cannot pass instances across the package boundary, despite naming/structure being byte-identical. - ---- - -## High severity - -### 5. `Aibi*` family — cryptic acronym not expanded in identifier -- **File:line:** `model.ts:52-155`; client.ts six methods -- **Category:** Cryptic abbreviation, acronym casing -- **Suggestion:** Either spell as `AiBiDashboardEmbedding*` (matching Databricks marketing) or `AIBIDashboardEmbedding*` (strict acronym casing). The current `Aibi` parses as one token, hiding the AI + BI = analytics-product structure. -- **Rationale:** "AI/BI dashboards" is the user-facing product name (confirmed in the JSDoc on `client.ts:749`). The wire path even uses `aibi_dash_embed_ws_acc_policy` — itself heavily abbreviated. A new reader cannot guess that `Aibi` means "AI + BI." TS style guide prefers acronym capitalization for known acronyms (`URL`, `HTTP`, `AI`, `BI`). - -### 6. `Csp*` family — undocumented acronym -- **File:line:** `model.ts:239-268`; URL slug `shield_csp_enablement_ws_db` -- **Category:** Cryptic abbreviation -- **Suggestion:** `ComplianceSecurityProfile*` everywhere (it's already spelled out in the JSDoc on line 238). The class methods are already named `ComplianceSecurityProfile`; only the wire slug is `csp`, which is fine on the wire but should not be exposed. -- **Rationale:** Identical issue to `accountsettings`. CSP overloads catastrophically with web "Content Security Policy." Outside this codebase, that is the dominant meaning. The TS-side type name is `ComplianceSecurityProfile` (good!) but the wire and the `_workspace` suffix in `complianceSecurityProfileWorkspace` discriminator is still cryptic-adjacent. - -### 7. `Esm*` family — undocumented acronym -- **File:line:** `model.ts:697-728`; URL slug `shield_esm_enablement_ws_db`; `client.ts:1104, 1560` -- **Category:** Cryptic abbreviation -- **Suggestion:** `EnhancedSecurityMonitoring*` everywhere on TS side. Wire `esm` is fine. -- **Rationale:** Same as CSP. The full name `EnhancedSecurityMonitoring` is used at the type level (good!), but discriminator names like `enhancedSecurityMonitoringWorkspace` add a confusing "Workspace" tail (see #25). - -### 8. `Llm*` family — acronym casing + verb stacking -- **File:line:** `model.ts:538-565, 934-951, 1137-1144`; `client.ts:624, 1140, 1588` -- **Category:** Cryptic abbreviation + Acronym casing -- **Suggestion:** Spell out: `ModelProxyPartnerPoweredWorkspace` or `LargeLanguageModelProxyPartnerPoweredWorkspace` (admittedly long). Better: drop "Workspace" since the package name already scopes it → `LlmProxyPartnerPowered`. Better still: collapse to `PartnerPoweredAi` (the doc on `client.ts:1139` explicitly calls it "partner powered AI features"). -- **Rationale:** `LlmProxyPartnerPoweredWorkspace` is 31 characters parsing as five concepts: LLM-Proxy-Partner-Powered-Workspace. Without context, a reader cannot tell whether "PartnerPowered" modifies "Llm" or modifies "Workspace." `Llm` (one word) violates TS acronym casing. - -### 9. `Dbfs` casing -- **File:line:** `model.ts:509-536, 646-665, 850-863, 1117-1124` -- **Category:** Acronym casing -- **Suggestion:** `DBFS` (it's an acronym — Databricks File System). Apply consistently: `DisableLegacyDBFS`, `disableLegacyDBFS`, `GetDisableLegacyDBFSRequest`. -- **Rationale:** TS style for known acronyms is uppercase. The wire is `disable_legacy_dbfs` (lowercase) which is fine, but the TS surface should be `DBFS`. The codebase is internally consistent in using `Dbfs` everywhere, so this is a global rename. - -### 10. `settingName` documented as not respected on requests -- **File:line:** `model.ts:120, 148, 172, 261, 285, 312, 331, 640, 661, 673, 683, 693, 721, 949, 1001, 1025` -- **Category:** Misleading -- **Suggestion:** Mark `settingName` `readonly` on the response-only path; remove it from request bodies; or split request/response types so it is only present where meaningful. At minimum, the docstring should not say "this field is populated in the response, but it will not be respected even if it's set in the request body." -- **Rationale:** A 16-times-repeated 240-character JSDoc admits that the field is server-ignored on PATCH/UPDATE. The field is forced to `"default"` server-side. Exposing it in the public API surface only invites users to set it, expect it to take effect, and then debug why it didn't. - -### 11. `settingTypeName` query parameter ignored -- **File:line:** `client.ts:341-346, 383-388, 425-430, 470-475, 510-515, 550-555, 590-595, 630-635, 675-680, 715-720, 758-763, 798-803, 838-843, 878-883, 918-923, 958-963, 995-1000, 1032-1037, 1069-1074, 1106-1111, 1146-1151, 1186-1191, 1226-1231` -- **Category:** Misleading -- **Suggestion:** Drop from the request type — the path parameter (`/api/2.0/settings/types/aibi_dash_embed_ws_acc_policy/names/default`) makes the query parameter redundant. The client serializes the path slug for the user; there is no reason to also expose the slug as a `settingTypeName` query param. -- **Rationale:** Every Get/Delete/Update sets the URL path to a hard-coded slug (e.g. `aibi_dash_embed_ws_acc_policy`) and then *also* lets the user populate `settingTypeName` and `settingName` as query params. If a user sets `settingTypeName: 'foo'`, the path still wins; the field is window dressing. - -### 12. `DefaultWarehouseId` envelope holds no warehouse-ID field directly -- **File:line:** `model.ts:316-333` -- **Category:** Underspecified ID, misleading -- **Suggestion:** `interface DefaultWarehouse { id?: string; etag?: string; }` — a flat, non-envelope, no-wrapper type. Or hide the envelope completely and let the client method return `string | undefined`. -- **Rationale:** A reader sees `DefaultWarehouseId` and expects a `string` (or numeric ID). What they get is a four-layer struct: `defaultWarehouseId.value.stringVal.value` is the actual ID. Plus the type lacks any documentation about whether the warehouse ID is numeric (e.g. `1234`) or string-shaped (e.g. `0abc...d`). The Databricks warehouse-ID convention is opaque alphanumeric; this should be documented. - -### 13. `patch*` vs `update*` methods for the same PATCH HTTP verb -- **File:line:** `client.ts:192 (patchEnableExportNotebook), 249 (patchEnableNotebookTableClipboard), 306 (patchEnableResultsDownloading)` vs `client.ts:1257 (updateAibi...), 1292, 1328, 1365, 1397, 1435, 1464, 1493, 1522, 1556, 1588, 1625, 1657 (update*)` -- **Category:** Inconsistent action verbs -- **Suggestion:** Standardize on `update*`. The three `patch*` methods are anomalies — every other PATCH method in the package is named `update*` and every API in the SDK reading from CRUD elsewhere uses `update*`. -- **Rationale:** Three of 26 methods (`patchEnableExportNotebook`, `patchEnableNotebookTableClipboard`, `patchEnableResultsDownloading`) use the verb `patch` instead of `update`, even though all 14 PATCH-method-using siblings use `update`. The HTTP verb is the same (`PATCH`). The naming inconsistency causes consumer discovery problems. - -### 14. `delete*` methods that actually "revert" to default -- **File:line:** `client.ts:335 (deleteAibi...AccessPolicySetting), 377, 419, 464, 504, 544, 584, 624, 669, 709` -- **Category:** Inconsistent action verbs / misleading -- **Suggestion:** `resetToDefault*` or `reset*`. The doc literally reads "Reverts the SQL Results Download setting to its default value" (line 708), "Reverts the Dashboard Email Subscriptions setting to its default value" (line 418), "Reverts the enable partner powered AI features workspace setting to its default value" (line 623), etc. — the semantic is reset, not delete. -- **Rationale:** A `delete` method that doesn't delete is the worst kind of misleading verb. The HTTP verb is `DELETE` but that is the *server's* idiom for "remove the override and fall back to default." The SDK can wrap with `reset*` and hide the wire detail. - -### 15. `*Setting` triple-stutter against the `workspacesettings` package name -- **File:line:** `model.ts:105 (AibiDashboardEmbeddingAccessPolicySetting), 246 (ComplianceSecurityProfileSetting), 706 (EnhancedSecurityMonitoringSetting), 986 (RestrictWorkspaceAdminsSetting), 1010 (SqlResultsDownload — exception)` and ~14 more -- **Category:** Triple-stutter against package name -- **Suggestion:** Drop the `Setting` suffix. The package is already `workspacesettings`, so `workspacesettings.AibiDashboardEmbeddingAccessPolicySetting` reads as "the access-policy setting setting setting." Use `workspacesettings.AibiDashboardEmbeddingAccessPolicy` etc. -- **Rationale:** Every primary type in the package carries a `Setting` suffix despite the package name being `workspacesettings`. The qualified path triple-states "settings." Sibling `SqlResultsDownload` (without `Setting` suffix) shows the cleaner alternative. - -### 43. `Message` suffix on top-level types — proto-architectural-leak -- **File:line:** `model.ts:181 (BooleanMessage), 185 (ClusterAutoRestartMessage), 977 (RestrictWorkspaceAdminsMessage), 1029 (StringMessage)` -- **Why:** Public TS type names should describe the domain object, not the wire-encoding container. `Message` is `proto`'s name for "any encoded record" and carries no semantic value to a TS consumer; it announces that the type was code-generated from a `.proto` definition. -- **Category:** Proto-architectural-leak (suffix) -- **Suggested:** Drop the `Message` suffix everywhere. `BooleanMessage` → `BooleanValue` (or hoist to a shared wkt `BoolValue`); `StringMessage` → `StringValue`; `ClusterAutoRestartMessage` → `ClusterAutoRestart`; `RestrictWorkspaceAdminsMessage` → `RestrictWorkspaceAdmins`. -- **Rationale:** A TS reader has no concept of `proto.Message`. Naming a wrapper around a single boolean `BooleanMessage` exposes the wire transport. Sibling types in the same package (`EnhancedSecurityMonitoring`, `ComplianceSecurityProfile`, `DashboardEmailSubscriptions`, `SqlResultsDownload`, `LlmProxyPartnerPoweredWorkspace`) all drop the `Message` suffix successfully — the four flagged types are outliers carrying through their proto identity. - -### 44. `*Message_*` nested-type underscore infix — proto nested-message naming convention -- **File:line:** `model.ts:60 (ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek), 72 (...WeekDayFrequency), 84 (RestrictWorkspaceAdminsMessage_Status), 202 (ClusterAutoRestartMessage_EnablementDetails), 212 (ClusterAutoRestartMessage_MaintenanceWindow), 219 (...WeekDayBasedSchedule), 230 (...WindowStartTime)` -- **Why:** The `Parent_Nested` and `Parent_Nested_DeepNested` pattern is `protoc`'s mechanical encoding of nested `message`/`enum` blocks (since TS has no nested-type syntax in this codebase). The repeated `Message_` infix doubles down on the proto leak from #43. -- **Category:** Proto-architectural-leak (`Proto`-style nested-type marker) -- **Suggested:** Lift nested types to top-level with clean names. `ClusterAutoRestartMessage_EnablementDetails` → `ClusterAutoRestartEnablement`; `ClusterAutoRestartMessage_MaintenanceWindow` → `ClusterAutoRestartMaintenanceWindow`; `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule` → `WeekDayBasedMaintenanceSchedule`; `..._WindowStartTime` → `MaintenanceWindowStartTime`; `..._DayOfWeek` → `DayOfWeek`; `..._WeekDayFrequency` → `WeekDayFrequency`; `RestrictWorkspaceAdminsMessage_Status` → `WorkspaceAdminRestrictionStatus`. -- **Rationale:** Every occurrence of these identifiers is paired with an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive (lines 51, 59, 71, 83, 201, 211, 218, 229, 1281, 1295, 1310, 1333, 1811, 1825, 1840, 1863, 2552, 2564, 2574, 2586), confirming the codebase itself recognizes this as a proto-style leak that violates the TS naming convention. The double-`Message_` chain (e.g. `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`) is 62 characters of nested-encoding artifact. - ---- - -## Medium severity - -### 16. `DisableLegacyAccess` — verb-phrase as type name -- **File:line:** `model.ts:625-644` -- **Category:** Verb-tense / verb-in-noun position -- **Suggestion:** `LegacyAccessDisablement` or `LegacyAccessToggle`. Types describing settings should be nouns. -- **Rationale:** `DisableLegacyAccess` reads as an imperative ("perform the action of disabling legacy access") rather than a state ("the legacy-access-disabled toggle setting"). The discriminator name `disableLegacyAccess` inside `.value.disableLegacyAccess: BooleanMessage` doubles the verb. - -### 17. `DisableLegacyDbfs` — verb-phrase as type name -- **File:line:** `model.ts:646-665` -- **Category:** Verb-tense / verb-in-noun position -- **Suggestion:** `LegacyDBFSDisablement` or `LegacyDBFSToggle`. -- **Rationale:** Same as #16. - -### 18. `EnableExportNotebook` — verb-phrase as type name -- **File:line:** `model.ts:667-675` -- **Category:** Verb-tense / verb-in-noun position -- **Suggestion:** `NotebookExportToggle` or `NotebookExportEnabled`. -- **Rationale:** Same as #16 plus the ordering is awkward: "enable export notebook" parses as "enable a notebook for exporting" but the doc on `client.ts:166` ("Gets the Notebook and File exporting setting") shows the meaning is the toggle on the export-feature itself. - -### 19. `EnableNotebookTableClipboard` — verb-phrase as type name -- **File:line:** `model.ts:677-685` -- **Category:** Verb-tense / verb-in-noun position -- **Suggestion:** `NotebookTableClipboardToggle`. -- **Rationale:** Same as #16. - -### 20. `EnableResultsDownloading` — verb + gerund mash -- **File:line:** `model.ts:687-695` -- **Category:** Verb-tense / verb-in-noun position + gerund mismatch -- **Suggestion:** `NotebookResultsDownloadToggle` (matches the doc on `client.ts:280` "Notebook results download setting"). -- **Rationale:** `EnableResultsDownloading` mixes imperative `Enable` with gerund `Downloading`. The sibling type `SqlResultsDownload` (no `-ing`, no `Enable`) does the same thing for SQL. The inconsistency is severe — same domain, two different naming conventions. - -### 21. `EnableResultsDownloading` vs `SqlResultsDownload` — inconsistent naming within the same package -- **File:line:** `model.ts:687, 1010` -- **Category:** Verb-tense / -ing gerund inconsistency -- **Suggestion:** Pick one form. Either both as `*Toggle` or both as `Enable*Downloading`. -- **Rationale:** Both control downloading of query results. The notebook variant is `EnableResultsDownloading` (gerund). The SQL variant is `SqlResultsDownload` (noun). The pair was authored at different times by different teams and the inconsistency leaked into the API. - -### 22. `EnableResultsDownloading` (workspace settings) vs `SqlResultsDownload` — semantic overlap -- **File:line:** `model.ts:687, 1010` -- **Category:** Misleading / parallel naming -- **Suggestion:** Unify under one type with a discriminator: `ResultsDownloadToggle { context: 'notebook' | 'sql', enabled: boolean }`. -- **Rationale:** The doc on `client.ts:280` calls one "Notebook results download" and the doc on `client.ts:1219` calls the other "SQL Results Download." They have the same shape and similar semantics — but the methods, types, and wire slugs are all separate. This is duplicated wiring at the API surface. - -### 23. `LlmProxyPartnerPoweredWorkspace` — redundant "Workspace" suffix -- **File:line:** `model.ts:934-951` -- **Category:** Misleading -- **Suggestion:** Drop `Workspace`. The package name is `workspacesettings`, so every type is workspace-scoped. The suffix exists only to mirror `LlmProxyPartnerPoweredAccount` in `accountsettings` — which is symmetrical but ill-justified (both should drop their scope suffix). -- **Rationale:** Compare to siblings: `DefaultNamespaceSetting`, `RestrictWorkspaceAdminsSetting`, `SqlResultsDownload`, `EnableExportNotebook` — none of them carry the "Workspace" suffix despite being workspace-scoped. `LlmProxyPartnerPoweredWorkspace` is the outlier. - -### 24. `automaticClusterUpdateWorkspace` — discriminator/case name with redundant "Workspace" -- **File:line:** `model.ts:175, 1245` -- **Category:** Misleading -- **Suggestion:** `clusterAutoRestart` (matches the actual data type, `ClusterAutoRestartMessage`). -- **Rationale:** Inside `AutomaticClusterUpdateSetting.value.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage` — the discriminator name uses one phrase ("automatic cluster update workspace") while the type uses another ("cluster auto restart"). The reader must mentally bridge "automatic cluster update" with "cluster auto restart." - -### 25. `complianceSecurityProfileWorkspace`, `enhancedSecurityMonitoringWorkspace` — discriminators with redundant "Workspace" -- **File:line:** `model.ts:264, 724` -- **Category:** Misleading -- **Suggestion:** Drop "Workspace" suffix: `complianceSecurityProfile`, `enhancedSecurityMonitoring`. -- **Rationale:** Same as #23. - -### 26. `restartEvenIfNoUpdatesAvailable` — double negative -- **File:line:** `model.ts:190` -- **Category:** Misleading -- **Suggestion:** `restartUnconditionally` (or invert: `skipIfNoUpdates` with opposite default). -- **Rationale:** "Restart even if no updates available" is a triple-conditional that takes effort to parse. The semantics are "restart regardless of update availability." Boolean fields should read as clean predicates. - -### 27. `canToggle` — vague boolean -- **File:line:** `model.ts:187` -- **Category:** Misleading -- **Suggestion:** `isToggleable` or `canBeDisabledByCustomer`. -- **Rationale:** `canToggle` on its own does not specify *what* can be toggled or by *whom*. From context (`ClusterAutoRestartMessage`), this likely means "can the customer toggle the auto-restart setting." The name does not convey that. - -### 28. `forcedForComplianceMode` — past-participle as flag -- **File:line:** `model.ts:208` -- **Category:** Misleading -- **Suggestion:** `isForcedByComplianceMode` or `forcedDueToComplianceMode`. -- **Rationale:** `forcedFor` reads ambiguously — "for the purpose of" or "due to"? The doc on line 207 ("The feature is force enabled if compliance mode is active") confirms the meaning is "due to." - -### 29. `unavailableForNonEnterpriseTier`, `unavailableForDisabledEntitlement` — double negative -- **File:line:** `model.ts:204, 206` -- **Category:** Misleading -- **Suggestion:** Invert: `requiresEnterpriseTier`, `requiresEntitlement` — read more naturally. -- **Rationale:** "Unavailable for non-enterprise" requires reasoning over two negatives. "Requires enterprise" is a positive predicate. - -### 30. Acronym casing across `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql` -- **File:line:** Throughout model.ts and client.ts -- **Category:** Acronym casing -- **Suggestion:** Apply TS-conventional casing — `DBFS`, `AIBI` (or `AiBi`), `LLM`, `CSP`, `ESM`, `SQL` — or, where they are domain acronyms, document expansion. The codebase is internally consistent in using `Pascal-token-case` for all of them, but this contradicts the TS style guide and the JSDoc which uses correct casing (`AI/BI`, `LLM`, `SQL`, etc. in prose). -- **Rationale:** JSDoc has it right; identifiers don't. - -### 31. `Id` vs `ID` casing -- **File:line:** `model.ts:316, 1097` (`DefaultWarehouseId`, `UpdateDefaultWarehouseIdRequest`, `defaultWarehouseId` method) -- **Category:** Acronym casing -- **Suggestion:** `DefaultWarehouseID`, `UpdateDefaultWarehouseIDRequest` — or, if `Id` is house style, document it explicitly. Pick one and apply globally. -- **Rationale:** Established TS code is split — some major SDKs use `Id` (consistent with `Pascal-token-case`), others use `ID` (matches HTTP/spec convention). The Go SDK uses `Id`. The Databricks JS SDK should pick one and apply it everywhere; today, "Id" is used here but "ESM/CSP/LLM" suggests acronym capitalization is house style. - -### 32. `Url` casing -- **File:line:** `utils.ts:70, 98, 103` -- **Category:** Acronym casing -- **Suggestion:** Match the upstream `HttpRequest.url` field; if upstream uses `url`, leave it. Note inconsistency for the audit reviewer. -- **Rationale:** Minor — flagged because the rule applies. - -### 33. Mixed `Enable*` / `Disable*` / `Enable*ing` patterns -- **File:line:** `model.ts:667 (EnableExportNotebook), 677 (EnableNotebookTableClipboard), 687 (EnableResultsDownloading), 625 (DisableLegacyAccess), 646 (DisableLegacyDbfs)` -- **Category:** Verb-tense inconsistency -- **Suggestion:** Pick one verb-tense for "toggle" types: either all imperative (`EnableX` / `DisableX`) or all noun (`XToggle` / `XEnablement`). See severity #16–20. -- **Rationale:** Five types here use three different inflection patterns. - -### 34. `EnableExportNotebook` vs `EnableNotebookTableClipboard` — word-order swap -- **File:line:** `model.ts:667, 677` -- **Category:** Verb-tense inconsistency -- **Suggestion:** Pick word-order convention: noun-verb-noun (`EnableNotebookExport`, `EnableNotebookTableClipboard`) or verb-noun-noun (`EnableExportNotebook`, `EnableClipboardTable`). -- **Rationale:** "Enable Export Notebook" puts the noun ("Notebook") last; "Enable Notebook Table Clipboard" puts it first. The cognitive cost of two siblings in the same package using opposite orders is non-trivial. - -### 35. `delete*` method names — reserved-word adjacency -- **File:line:** `client.ts:335, 377, 419, 464, 504, 544, 584, 624, 669, 709` -- **Category:** Reserved-word collision (soft) -- **Suggestion:** `reset*` (which also fixes #14). -- **Rationale:** `delete` is a JS reserved word (`delete obj.prop`). Using it as a method prefix is technically fine but creates parsing-cost ambiguity in mental models, especially when the operation doesn't *actually* delete. - -### 36. `disableGovTagCreation` — verb-as-field -- **File:line:** `model.ts:983` -- **Category:** Verb-tense inconsistency, cryptic abbreviation -- **Suggestion:** `governanceTagCreationDisabled` or `restrictsGovernanceTagCreation`. `Gov` is also cryptic abbreviation. -- **Rationale:** The field is a boolean predicate that, when `true`, disables tag creation. A noun-phrase reads more naturally. `Gov` short for "governance" is non-standard — "Gov" usually means "government" — and is documented only by the comment on lines 980-982. - -### 45. `EnablementDetails` / `enablementDetails` — generic `Details` suffix -- **File:line:** `model.ts:189 (field), 202 (type ClusterAutoRestartMessage_EnablementDetails)` -- **Why:** `Details` is one of the generic carry-all suffixes that proto-generated types use when the underlying message is "a bag of fields about X." The TS surface inherits this from the proto schema; the type name conveys nothing about *what* the details are (tier eligibility + entitlement + compliance-forcing flags). -- **Category:** Proto-architectural-leak (generic `Details` suffix) -- **Suggested:** `ClusterAutoRestartEligibility` or `AutoRestartAvailability`. The struct holds three booleans about *why* the feature is available/forced — "eligibility" or "availability" is the domain concept, not "details." -- **Rationale:** The JSDoc on lines 193-200 spells out the purpose: "contains an information about the enablement status judging (e.g. whether the enterprise tier is enabled)" — a customer-facing eligibility/availability concept. `Details` is the proto-side mechanical name. Pairs with #44 (nested-type artifact). - ---- - -## Low severity - -### 37. Cryptic wire-key abbreviations in URL slugs -- **File:line:** `client.ts:339 (aibi_dash_embed_ws_acc_policy), 381 (aibi_dash_embed_ws_apprvd_domains), 756, 796, 1261, 1296` -- **Category:** Cryptic abbreviation -- **Suggestion:** Wire keys are server-controlled; the SDK can't unilaterally rename. Worth flagging for the broader Databricks-platform team — these URL paths are exposed in logs and SDK telemetry. `apprvd` for `approved` saves 1 character. -- **Rationale:** Wire keys aren't strictly in scope for naming audits, but they bleed into log lines and error messages. `dash_embed` for "dashboard embedding" is also non-obvious. - -### 38. Cryptic wire-key abbreviations — `_ws` and `_ws_db` suffix -- **File:line:** `client.ts:468 (default_namespace_ws), 876 (shield_csp_enablement_ws_db), 956 (default_namespace_ws), 1104 (shield_esm_enablement_ws_db), 1369 (shield_csp_enablement_ws_db), 1439 (default_namespace_ws), 1560 (shield_esm_enablement_ws_db)` -- **Category:** Cryptic abbreviation -- **Suggestion:** Wire-team concern. `ws` is workspace, `db` is database (?), `ac` is account (in `accountsettings`). These two-letter suffixes are dense. -- **Rationale:** `shield_csp_enablement_ws_db` mixes three abbreviated tokens (`shield` is fine, `csp` and `ws_db` are cryptic). - -### 39. `eTag` (doc) vs `etag` (field) -- **File:line:** `model.ts:107-114, 248-254, 1012-1018` (every `etag` doc block) -- **Category:** Acronym casing -- **Suggestion:** Standardize either `etag` or `eTag`. RFC 7232 spells it "ETag" in HTTP headers; Databricks docs spell it `eTag` in prose and `etag` as the JSON field. -- **Rationale:** Internal-doc inconsistency. The JSDoc on every type says "etag used for versioning. The response is at least as fresh as the eTag provided." — the same paragraph uses two casings. - -### 40. `complianceStandards` array on singular `ComplianceSecurityProfile` envelope -- **File:line:** `model.ts:243` -- **Category:** Singular/plural mismatch (mild — correct in context) -- **Suggestion:** No change. Flagged only because the audit checklist asks for it. The field is correctly plural because it holds an array; the parent type is correctly singular because there is one profile. -- **Rationale:** Consistent. No action needed. - -### 41. `approvedDomains` array — naming consistency with `AibiDashboardEmbeddingAccessPolicy` -- **File:line:** `model.ts:130` -- **Category:** Singular/plural -- **Suggestion:** None needed for this field. Flagging the parent type name — `AibiDashboardEmbeddingApprovedDomains` is plural (because it holds a list) while sibling `AibiDashboardEmbeddingAccessPolicy` is singular. The asymmetry is fine but inconsistent stylistically. -- **Rationale:** Minor; preserved for completeness. - -### 42. Wire-key length in shorter slugs -- **File:line:** `client.ts:836 (automatic_cluster_update), 423 (dashboard_email_subscriptions), 673 (restrict_workspace_admins)` -- **Category:** Verbose / could be shorter -- **Suggestion:** Wire-team concern. -- **Rationale:** These three slugs are 24+ characters but spell every word out (unlike `aibi_dash_embed_ws_acc_policy` which abbreviates aggressively). The inconsistency in wire-side abbreviation conventions is itself a flag. - ---- - -## Cross-cutting themes - -1. **Four overlapping settings packages.** `workspacesettings` + `settings` + `accountsettings` + `workspaceconf` is a confusing taxonomy with literal type duplication. Almost every type in `workspacesettings` has a doppelganger in `settings/v2`. (Severity #1, #2, #3, #4.) - -2. **`*Setting` triple-stutter.** Every primary type carries a `Setting` suffix despite the package name being `workspacesettings`. (Severity #15.) - -3. **Acronym-casing inconsistency.** `Dbfs`, `Aibi`, `Llm`, `Csp`, `Esm`, `Sql`, `Id`, `Url` are all cased as `Pascal-token-case` (treating the acronym as one token). The JSDoc uses correct casing (`AI/BI`, `LLM`, `SQL`, `DBFS`). Pick one and apply globally. (Severities #5, #6, #7, #8, #9, #30, #31, #32.) - -4. **Verb tense as type name.** `EnableExportNotebook`, `DisableLegacyAccess`, `EnableResultsDownloading` — types should be nouns, not imperative verbs or gerunds. (Severities #16-20, #33-34.) - -5. **`delete` and `patch` HTTP verbs leaking into method names with wrong/inconsistent semantics.** `delete*` actually means "reset to default"; `patch*` (three methods) means the same as `update*` (14 methods). (Severities #13, #14, #35.) - -6. **Fields documented as ignored on requests.** `settingName` ignored, `settingTypeName` ignored. The TS surface offers writable fields that the API discards server-side. (Severities #10, #11.) - -7. **Cryptic wire-key abbreviations.** `aibi_dash_embed_ws_acc_policy`, `shield_csp_enablement_ws_db`, `_ws`, `_ws_db` suffixes etc. These leak into logs and error messages even though the SDK hides them behind method names. (Severities #37, #38.) - -8. **Proto-architectural-leak through `Message` suffix and `Parent_Nested` infix.** Top-level types `BooleanMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `RestrictWorkspaceAdminsMessage` and the seven `*_Message_*` nested types expose the proto-generated naming convention directly to consumers. The codebase already acknowledges the leak via `eslint-disable -- Proto-style nested message name.` annotations on every such identifier. Generic `Details` suffix on `EnablementDetails` is the same pattern. (Severities #43, #44, #45.) - ---- +> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. From 74743079e7c0186d64fb2a1bddbacb7b6b54ed86 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 26 May 2026 21:50:37 +0000 Subject: [PATCH 08/12] update --- .agent/naming-audit/accessmanagement.md | 8 +- .agent/naming-audit/accountaccesscontrol.md | 3 - .../naming-audit/accountaccesscontrolproxy.md | 3 - .agent/naming-audit/accountsettings.md | 3 - .agent/naming-audit/budgets.md | 25 +- .agent/naming-audit/cleanroomassets.md | 3 - .../cleanroomautoapprovalrules.md | 3 - .agent/naming-audit/cleanroomtaskruns.md | 3 - .agent/naming-audit/clusters.md | 142 ++++-------- .agent/naming-audit/connections.md | 10 +- .agent/naming-audit/customllms.md | 60 ++--- .agent/naming-audit/database.md | 63 ++--- .agent/naming-audit/dataquality.md | 14 +- .agent/naming-audit/disasterrecovery.md | 32 ++- .agent/naming-audit/endpoints.md | 3 - .agent/naming-audit/environments.md | 58 +---- .agent/naming-audit/experiments.md | 78 ++----- .agent/naming-audit/externallocations.md | 57 ++--- .agent/naming-audit/externalmetadata.md | 42 ++-- .agent/naming-audit/features.md | 128 ++++------- .agent/naming-audit/featurestore.md | 181 ++------------- .agent/naming-audit/files.md | 22 +- .agent/naming-audit/forecasting.md | 24 +- .agent/naming-audit/functions.md | 53 +---- .agent/naming-audit/genie.md | 23 +- .agent/naming-audit/gitcredentials.md | 25 +- .agent/naming-audit/iam.md | 172 ++------------ .agent/naming-audit/indexes.md | 3 - .agent/naming-audit/instancepools.md | 41 ++-- .agent/naming-audit/jobs.md | 215 ++++++------------ .agent/naming-audit/knowledgeassistants.md | 26 +-- .agent/naming-audit/lakeview.md | 69 ++---- .agent/naming-audit/logdelivery.md | 69 ++---- .../naming-audit/logdeliveryconfigurations.md | 3 - .agent/naming-audit/marketplaces.md | 52 +---- .agent/naming-audit/materializedfeatures.md | 3 - .agent/naming-audit/metastores.md | 137 +++-------- .agent/naming-audit/modelregistry.md | 209 ++++------------- .agent/naming-audit/modelserving.md | 114 ++++------ .agent/naming-audit/modelservingdebug.md | 3 - .agent/naming-audit/modelservingmanagement.md | 3 - .agent/naming-audit/modelservingquery.md | 26 +-- .../naming-audit/notificationdestinations.md | 8 +- .agent/naming-audit/oauth.md | 71 +----- .../naming-audit/oauthcustomappintegration.md | 3 - .agent/naming-audit/oauthpublishedapp.md | 3 - .agent/naming-audit/permissions.md | 3 - .agent/naming-audit/pipelines.md | 127 ++--------- .agent/naming-audit/policyfamilies.md | 18 +- .agent/naming-audit/postgres.md | 76 +++---- .agent/naming-audit/qualitymonitor.md | 3 - .agent/naming-audit/qualitymonitors.md | 3 - .agent/naming-audit/queries.md | 24 +- .agent/naming-audit/queryexecution.md | 3 - .agent/naming-audit/resourcequotas.md | 35 +-- .agent/naming-audit/schemas.md | 15 +- .agent/naming-audit/secrets.md | 62 +---- .../naming-audit/serviceprincipalsecrets.md | 3 - .agent/naming-audit/workspace.md | 3 - .agent/naming-audit/workspaceassignment.md | 3 - .agent/naming-audit/workspaceconf.md | 3 - .agent/naming-audit/workspacesettings.md | 3 - 62 files changed, 656 insertions(+), 2024 deletions(-) delete mode 100644 .agent/naming-audit/accountaccesscontrol.md delete mode 100644 .agent/naming-audit/accountaccesscontrolproxy.md delete mode 100644 .agent/naming-audit/accountsettings.md delete mode 100644 .agent/naming-audit/cleanroomassets.md delete mode 100644 .agent/naming-audit/cleanroomautoapprovalrules.md delete mode 100644 .agent/naming-audit/cleanroomtaskruns.md delete mode 100644 .agent/naming-audit/endpoints.md delete mode 100644 .agent/naming-audit/indexes.md delete mode 100644 .agent/naming-audit/logdeliveryconfigurations.md delete mode 100644 .agent/naming-audit/materializedfeatures.md delete mode 100644 .agent/naming-audit/modelservingdebug.md delete mode 100644 .agent/naming-audit/modelservingmanagement.md delete mode 100644 .agent/naming-audit/oauthcustomappintegration.md delete mode 100644 .agent/naming-audit/oauthpublishedapp.md delete mode 100644 .agent/naming-audit/permissions.md delete mode 100644 .agent/naming-audit/qualitymonitor.md delete mode 100644 .agent/naming-audit/qualitymonitors.md delete mode 100644 .agent/naming-audit/queryexecution.md delete mode 100644 .agent/naming-audit/serviceprincipalsecrets.md delete mode 100644 .agent/naming-audit/workspace.md delete mode 100644 .agent/naming-audit/workspaceassignment.md delete mode 100644 .agent/naming-audit/workspaceconf.md delete mode 100644 .agent/naming-audit/workspacesettings.md diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md index 35c27e31..2d31042c 100644 --- a/.agent/naming-audit/accessmanagement.md +++ b/.agent/naming-audit/accessmanagement.md @@ -404,7 +404,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Cross-package consistency. -### 25. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` +### 24. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 513). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the @@ -416,7 +416,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. -### 26. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` +### 25. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` - **Why weird:** REST path uses `/permissionassignments/` (no separator), while every other Databricks REST resource in this SDK uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). @@ -427,7 +427,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum in this package. - **Rationale:** Cross-API consistency. -### 27. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` +### 26. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` - **Why weird:** Method is named with `get*` but returns `permissionAssignments` array (model.ts:213). REST convention is `list*` for array-returning operations; `get*` for singular. @@ -438,7 +438,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Aligns naming with REST list semantics used elsewhere in the SDK. -### 28. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` +### 27. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` - **Why weird:** Method `listWorkspacePermissions` returns the catalog of `PermissionOutput` values supported (USER/ADMIN), not user data. Sits side-by-side with `getWorkspacePermissionAssignments` diff --git a/.agent/naming-audit/accountaccesscontrol.md b/.agent/naming-audit/accountaccesscontrol.md deleted file mode 100644 index f11ed73d..00000000 --- a/.agent/naming-audit/accountaccesscontrol.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: accountaccesscontrol - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/accountaccesscontrolproxy.md b/.agent/naming-audit/accountaccesscontrolproxy.md deleted file mode 100644 index 1e177120..00000000 --- a/.agent/naming-audit/accountaccesscontrolproxy.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: accountaccesscontrolproxy - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/accountsettings.md b/.agent/naming-audit/accountsettings.md deleted file mode 100644 index 3430ebc4..00000000 --- a/.agent/naming-audit/accountsettings.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: accountsettings - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index fdd7b082..cfa037b5 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -124,7 +124,7 @@ _None._ #### F3.3 — `USD` in enum value `LIST_PRICE_DOLLARS_USD` (LOW) - Wire value, leave as-is. But note that `DOLLARS_USD` is doubly - redundant — USD already is dollars. See F7.1. + redundant — USD already is dollars. See F17.2. --- @@ -453,11 +453,8 @@ _None._ ### 14. Generic field names losing meaning -#### F14.1 — `operator` on Clauses (LOW) -- See F1.2. - -#### F14.2 — `req` parameter on every client method (HIGH) -- See F1.4. +#### F14.1 — `req` parameter on every client method (HIGH) +- See F1.3. --- @@ -494,8 +491,8 @@ _None._ #### F17.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) - **Where:** `model.ts:10`. -- **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant - (F7.4). Could be `LIST_PRICE_USD` or `USD`. +- **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant. + Could be `LIST_PRICE_USD` or `USD`. - **Suggestion:** Wire value; report upstream. #### F17.3 — `EMAIL_NOTIFICATION` (LOW) @@ -566,20 +563,20 @@ This SDK exposes two separate packages whose names both start with | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Vague / generic | 4 | +| 1 | Vague / generic | 3 | | 2 | Redundant enum prefixes | 0 | -| 3 | Acronym casing | 4 (4 acceptable) | +| 3 | Acronym casing | 3 (3 acceptable) | | 4 | Underscores in TS identifiers | 0 | | 5 | Cryptic abbreviations | 7 | -| 6 | Misleading names | 5 | -| 7 | Overly verbose | 4 | +| 6 | Misleading names | 2 | +| 7 | Overly verbose | 3 | | 8 | Singular / plural mismatch | 4 (3 acceptable) | | 9 | Reserved-word collisions | 3 (3 acceptable) | | 10 | Empty / trivial wrappers | 0 | | 11 | Duplicate concepts | 5 | -| 12 | Verb-tense inconsistency | 2 (1 acceptable) | +| 12 | Verb-tense inconsistency | 2 (2 acceptable) | | 13 | Go / Java-style names | 2 (1 acceptable) | -| 14 | Generic field names | 2 | +| 14 | Generic field names | 1 | | 15 | Field contradicting type domain | 2 | | 16 | Inconsistent action verbs | 1 (1 acceptable) | | 17 | Long enum values | 3 | diff --git a/.agent/naming-audit/cleanroomassets.md b/.agent/naming-audit/cleanroomassets.md deleted file mode 100644 index 66a68907..00000000 --- a/.agent/naming-audit/cleanroomassets.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: cleanroomassets - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/cleanroomautoapprovalrules.md b/.agent/naming-audit/cleanroomautoapprovalrules.md deleted file mode 100644 index f292ae11..00000000 --- a/.agent/naming-audit/cleanroomautoapprovalrules.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: cleanroomautoapprovalrules - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/cleanroomtaskruns.md b/.agent/naming-audit/cleanroomtaskruns.md deleted file mode 100644 index ab5c984b..00000000 --- a/.agent/naming-audit/cleanroomtaskruns.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: cleanroomtaskruns - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index e98981cc..2f49a100 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -3,15 +3,15 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 **Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 48 +**Total weird names flagged:** 38 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 21 | -| Low | 10 | -| Observation | 8 | +| High | 8 | +| Medium | 17 | +| Low | 6 | +| Observation | 7 | ## High severity @@ -51,19 +51,13 @@ - **Suggested name:** Rename to `NO_PUBLIC_IP_TUNNEL_*` or document `NPIP` in the enum docstring. - **Rationale:** Same as #5; SDK users should not need to know Databricks' internal acronyms. -### 7. `TerminationCode.K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` / `DBR_IMAGE_RESOLUTION_FAILURE` — `src/v2/model.ts:391,726` -- **Why weird:** `DBR` ("Databricks Runtime") and `K8S` ("Kubernetes") used together with no expansion. JSDoc on line 390 says "DBR Cluster launched on K8s (i.e. CMv2)" — three acronyms in one sentence. -- **Category:** 5 (cryptic abbreviation), 8 (jargon). -- **Suggested name:** Expand acronyms in JSDoc minimum; consider renaming to `DATABRICKS_RUNTIME_CLUSTER_LAUNCH_TIMEOUT_KUBERNETES`. -- **Rationale:** Internal SDK people read `DBR` daily; external consumers don't. - -### 8. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` vs `GCP_IP_SPACE_EXHAUSTED` cross-cloud asymmetry — `src/v2/model.ts:379,590` +### 7. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` vs `GCP_IP_SPACE_EXHAUSTED` cross-cloud asymmetry — `src/v2/model.ts:379,590` - **Why weird:** AWS enum value is 52 characters; GCP equivalent is 22 chars — same concept, very different length. JSDoc at line 421 explicitly TODOs consolidating these. - **Category:** 17 (inconsistent across clouds). - **Suggested name:** `AWS_SUBNET_IP_EXHAUSTED` (mirror the GCP form). - **Rationale:** Per-cloud variants should follow the same shape; the AWS/GCP/Azure versions of the same condition should not differ in length by 30 characters. -### 9. `TerminationCode.ALLOCATION_TIMEOUT_*` family — eight near-identical codes — `src/v2/model.ts:661-686` +### 8. `TerminationCode.ALLOCATION_TIMEOUT_*` family — eight near-identical codes — `src/v2/model.ts:661-686` - **Why weird:** Eight `ALLOCATION_TIMEOUT_*` siblings all encode subtle internal scheduler states (e.g., `ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` at line 686). - **Category:** 12 (duplicate concept across eight near-identical codes). - **Suggested name:** Collapse the family into `ALLOCATION_TIMEOUT` with a structured sub-field (`reason: string`) on `TerminationReason.parameters`. @@ -71,127 +65,103 @@ ## Medium severity -### 10. `Adlsgen2Info` casing — `src/v2/model.ts:917` +### 9. `Adlsgen2Info` casing — `src/v2/model.ts:917` - **Why weird:** Type name is `Adlsgen2Info` — should be `AdlsGen2Info` to match acronym-casing rules. ADLS (Azure Data Lake Storage) Gen2 should retain the boundary between `Adls` and `Gen2`. - **Category:** 3 (acronym casing inconsistency), 1 (vague `Info` suffix). - **Suggested name:** `AdlsGen2Storage` (or just `AbfssStorage`, since the wire name is `abfss`). - **Rationale:** Compare to sibling types `DbfsStorageInfo`, `GcsStorageInfo`, `S3StorageInfo` — all use `Info` suffix and capitalize the storage product. `Adlsgen2Info` is the odd one out. -### 11. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:917,2101,2509,2875,3044,3391,3414` +### 10. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:917,2101,2509,2875,3044,3391,3414` - **Why weird:** `Adlsgen2Info` (no `Storage`), `DbfsStorageInfo`, `GcsStorageInfo`, `LocalFileInfo` (no `Storage`), `S3StorageInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. Seven sibling types; five say `StorageInfo`, two say `Info`. - **Category:** 17 (inconsistent suffix across siblings). - **Suggested name:** Standardise on `XStorage` (drop the redundant `Info`) — `AdlsGen2Storage`, `DbfsStorage`, `GcsStorage`, `LocalFileStorage`, `S3Storage`, `VolumesStorage`, `WorkspaceStorage`. - **Rationale:** All seven describe the same kind of thing (a storage destination). Either all of them get `StorageInfo` or none do. -### 12. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:1253,2350,2361,2595,2812` +### 11. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:1253,2350,2361,2595,2812` - **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForClusterRequest` (a request), `GetPolicyComplianceForClusterRequest_Response`, `EnforcePolicyComplianceForClusterRequest` (request), `ListClusterComplianceForPolicyRequest` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. - **Category:** 1 (vague — `For` is the only disambiguator), 6 (misleading — easy to mis-parse). - **Suggested name:** `GetClusterPolicyComplianceRequest`, `EnforceClusterPolicyComplianceRequest`, `ListPolicyCompliantClustersRequest`, `ClusterPolicyCompliance`. - **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. -### 13. `hasChanges` field — `src/v2/model.ts:2366` +### 12. `hasChanges` field — `src/v2/model.ts:2366` - **Why weird:** Boolean on `EnforcePolicyComplianceForClusterRequest_Response` named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. - **Category:** 12 (duplicate signal), 1 (vague). - **Suggested name:** Drop the field, infer from `changes.length`. - **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. -### 14. `useMlRuntime` field — `src/v2/model.ts:1210` +### 13. `useMlRuntime` field — `src/v2/model.ts:1210` - **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. - **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). - **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. - **Rationale:** A boolean and an enum jointly describing one runtime selection is a boolean-shaped-enum smell. -### 15. `isSingleNode` field — `src/v2/model.ts:1216` -- **Why weird:** Boolean field that, when true, automatically sets `custom_tags`, `spark_conf`, and `num_workers`. Doc admits the surprise: "When set to true, Databricks will automatically set single node related custom_tags, spark_conf, and num_workers." A field that secretly mutates three others is a footgun. -- **Category:** 6 (misleading — hidden side effects). -- **Suggested name:** Name is fine, but document the side effects in the type-level JSDoc, not just the field doc. -- **Rationale:** Flag for upstream — the boolean is doing more than the name suggests. - -### 16. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields +### 14. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields - **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. - **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). - **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. - **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. -### 17. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` +### 15. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` - **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. - **Category:** 17 (inconsistent grouping). - **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. - **Rationale:** Within the same type, related fields should sit together. -### 18. `ListAvailableZonesRequest_Response.defaultZone` — `src/v2/model.ts:2809` -- **Why weird:** JSDoc says "The availability zone if no `zone_id` is provided in the cluster creation request." The doc references `zone_id` (the wire name) instead of the TS `zoneId`. Other docstrings in the package also reference `zone_id`, `cluster_id`, `cluster_log_conf`, `init_scripts`, etc. -- **Category:** Observation — generated docs reference wire names rather than TS names. -- **Suggested name:** Update doc-comment generation to use TS names. -- **Rationale:** Inconsistent doc/identifier pairing makes IntelliSense suggestions look out-of-date. - -### 19. `LogAnalyticsInfo` no JSDoc — `src/v2/model.ts:2880` -- **Why weird:** `LogAnalyticsInfo` has two fields (`logAnalyticsWorkspaceId`, `logAnalyticsPrimaryKey`), both un-documented. The type itself has no JSDoc. Used only by `AzureAttributes.logAnalyticsInfo`. -- **Category:** Observation (no naming issue per se, but missing context). -- **Suggested name:** Keep `LogAnalyticsInfo` (Azure Monitor terminology) but add a JSDoc; consider `AzureLogAnalyticsConfig`. -- **Rationale:** Both fields are Azure-specific; naming should signal that. - -### 20. `clusterLogStatus` field — `src/v2/model.ts:1330` +### 16. `clusterLogStatus` field — `src/v2/model.ts:1330` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). - **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. - **Rationale:** Same concept, two different names in 5 lines. -### 21. `jdbcPort` field — `src/v2/model.ts:1358` +### 17. `jdbcPort` field — `src/v2/model.ts:1358` - **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). -- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #22). +- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #18). -### 22. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` +### 18. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` - **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. - **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. -### 23. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` +### 19. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` - **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. - **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). - **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. - **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. -### 24. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` +### 20. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` - **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. - **Category:** 12 (duplicate concepts), 17 (could be a tagged union). - **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). - **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. -### 25. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:3055,3060` +### 21. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:3055,3060` - **Why weird:** JSDoc explicitly says "Either region or endpoint needs to be set. If both are set, endpoint will be used." Mutually-exclusive fields not encoded in the type. - **Category:** 16 (field-pair constraint not in the type). - **Suggested name:** Could be a discriminated union `{kind: 'region', value: string} | {kind: 'endpoint', value: string}`. - **Rationale:** Type-system-encodable constraint; flagged for upstream. -### 26. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` +### 22. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` - **Why weird:** `SparkInfo` is declared as an empty interface (`export interface SparkInfo {}`) whose JSDoc literally says "This is used in both the [[ClusterInfo]] for Cluster APIs and persisted cluster proto." Its only purpose is to namespace `SparkInfo_SparkNode` and `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Empty wrapper types tied to "persisted cluster proto" are pure proto-architectural leak — the TS surface carries a do-nothing type just to mirror proto message nesting. - **Category:** 14 (proto-style namespace anchor), 8 (JSDoc references the proto wire layer). - **Suggested name:** Delete `SparkInfo`; expose `SparkNode` (and `SparkNodeAwsAttributes`) as top-level types. - **Rationale:** TS doesn't need proto-style nesting; the empty parent interface is a generator artefact and a user-facing footgun (auto-completion shows a useless symbol). -### 27. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` -- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #29) is the smoking gun — the parent exists only to host the child. +### 23. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` +- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #24) is the smoking gun — the parent exists only to host the child. - **Category:** 14 (proto-style namespace anchor). - **Suggested name:** Delete `ClusterEventType` (the parent) and flatten the enum to a top-level `ClusterEventType` enum. The empty wrapper adds no value. -- **Rationale:** Same as #26 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. - -### 28. JSDoc text `"Proto defined to model a mapping from string to string."` — `src/v2/model.ts:1266,2615` -- **Why weird:** Two JSDoc strings literally start with "Proto defined to model...". The word "Proto" leaks the wire encoding into the TS user surface; the rest of the sentence (a `Record`) is generic boilerplate that ships as the only documentation for these `*Entry` types. -- **Category:** 14 (proto vocabulary in public-facing docs). -- **Suggested name:** Rewrite the JSDoc to describe the field semantics in TS terms (e.g., "Key-value pairs of policy violations, keyed by field path."). -- **Rationale:** A TS SDK doc should not say "Proto defined to" — that exposes the implementation strategy. Users see "Proto" in IntelliSense and wonder if they need a proto library. +- **Rationale:** Same as #22 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. -### 29. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` -- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#27) is empty, so the doubly-stuttered name carries no information. +### 24. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` +- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#23) is empty, so the doubly-stuttered name carries no information. - **Category:** 14 (proto nesting stutter), 4 (redundant repetition). - **Suggested name:** `ClusterEventType` (single, top-level). -- **Rationale:** After deleting the empty parent (#27), the child can drop the `ClusterEventType_` prefix entirely. +- **Rationale:** After deleting the empty parent (#23), the child can drop the `ClusterEventType_` prefix entirely. -### 30. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` +### 25. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` - **Why weird:** "Data plane" is an internal Databricks infrastructure concept (vs "control plane") — not a customer-facing domain term. Two public types prefix their names with the deployment-plane they originate from. A user creating a cluster does not need to know which plane emitted which event class; the distinction is a Databricks-internal architecture detail. - **Category:** 8 (internal architecture leak in public surface). - **Suggested name:** Either merge into a single `ClusterEventType` enum / `EventDetails` shape, or rename to a non-infrastructure word (e.g., `RuntimeEventDetails`). @@ -199,61 +169,37 @@ ## Low severity -### 31. `dockerImage` field comment `"Custom docker image BYOC"` — `src/v2/model.ts:1177,1468,1663,2012,2271,3314` -- **Why weird:** JSDoc abbreviation `BYOC` (Bring Your Own Container) used without expansion. Appears six times in the model. -- **Category:** 5 (cryptic abbreviation in JSDoc). -- **Suggested name:** N/A — fix the comment, not the identifier. -- **Rationale:** Quick doc fix. - -### 32. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1353` +### 26. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1353` - **Why weird:** Field is named `sparkContextId` but typed as `number`. Other IDs in the model are strings (`clusterId`, `policyId`, `nodeTypeId`). Internal Spark context IDs are 64-bit ints — the type clash hints at potential JS number-precision issues for large IDs. - **Category:** 19 (underspecified ID — different type from sibling IDs). - **Suggested name:** Keep but consider `bigint` typing or document the precision risk. - **Rationale:** JS number safe-integer range is 2^53; if Spark uses 64-bit IDs, this is a latent bug. -### 33. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` +### 27. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` - **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. - **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). - **Suggested name:** `credentials` (singular). - **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. -### 34. `DockerBasicAuth.username` / `password` — `src/v2/model.ts:2116,2118` -- **Why weird:** Doc strings are "Name of the user" and "Password of the user" — generic and add no information beyond the field names. -- **Category:** Observation (low-quality docstrings). -- **Suggested name:** No rename; flag doc-quality. -- **Rationale:** Minor. - -### 35. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:981` +### 28. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:981` - **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:1041`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. - **Category:** 17 (sibling AWS/Azure shapes differ), 1 (`number` without unit suffix). - **Suggested name:** `spotBidPricePercent` is fine; flag for upstream — the AWS/Azure semantics should be more discoverable from the model. - **Rationale:** Cross-cloud asymmetry is a domain concern. -### 36. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:1041` +### 29. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:1041` - **Why weird:** Magic value `-1` overloaded as "do not evict on price basis". Encoded in JSDoc, not in the type. - **Category:** 16 (sentinel value in scalar field), Observation. - **Suggested name:** N/A; flag for upstream to consider a sentinel enum or `null`. - **Rationale:** Sentinels in scalar fields are old-school API design. -### 37. `GcpAttributes.usePreemptibleExecutors` deprecated field — `src/v2/model.ts:2458` -- **Why weird:** JSDoc says "Note: Soon to be deprecated, use the 'availability' field instead." But the field is not actually marked `@deprecated`. -- **Category:** Observation — missing `@deprecated`. -- **Suggested name:** Add `@deprecated` JSDoc tag. -- **Rationale:** Tooling can pick up `@deprecated`; "Note: Soon to be deprecated" is invisible to IDEs. - -### 38. `ChangeClusterOwnerRequest.ownerUsername` field docstring — `src/v2/model.ts:1047` -- **Why weird:** Doc says "New owner of the cluster_id after this RPC." `RPC` jargon leaks. `cluster_id` is the wire name; should be `clusterId`. -- **Category:** Observation (doc quality), 5 (RPC jargon). -- **Suggested name:** Update doc text. -- **Rationale:** Minor doc fix. - -### 39. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2390,2397` +### 30. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2390,2397` - **Why weird:** Both fields typed as `string`. JSDoc says values are "either a number, a boolean, or a string converted to a string." Pre-stringified union encoded as plain string — caller must re-parse. - **Category:** 16 (type contradicts domain — it's actually `number | boolean | string` flattened to string). - **Suggested name:** Type as `string | number | boolean`, or `previousValueRaw`. - **Rationale:** Documents the stringification rather than hiding it. -### 40. `AutoScale` type name — `src/v2/model.ts:922` +### 31. `AutoScale` type name — `src/v2/model.ts:922` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). @@ -261,39 +207,35 @@ ## Observations -### 41. Seven Waiter classes with identical shape — `client.ts:967-1523` +### 32. Seven Waiter classes with identical shape — `client.ts:967-1523` The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. - **Category:** 12 (duplicate concept across seven classes), Observation. - **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. -### 42. `_req` parameter for empty request types — `client.ts:404,486,514` +### 33. `_req` parameter for empty request types — `client.ts:404,486,514` Several methods take a `_req: ListAvailableZonesRequest` / `_req: ListNodeTypesRequest` / `_req: GetSparkVersionsRequest` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. - **Category:** Observation (generator artefact). -### 43. `ResizeClusterRequest` / `RestartClusterRequest` requests are partial overlaps +### 34. `ResizeClusterRequest` / `RestartClusterRequest` requests are partial overlaps `ResizeClusterRequest` carries `clusterId` and `size`; `RestartClusterRequest` carries `clusterId` and `restartUser`; `StartClusterRequest` carries only `clusterId`. Three near-identical types; could be one. - **Category:** 12 (duplicate concept), Observation. -### 44. `_req` unused vs `req` used — inconsistency in method-signature lint +### 35. `_req` unused vs `req` used — inconsistency in method-signature lint Three client methods use `_req` (where the request type is empty), the rest use `req` (where it's not). Pure mechanical. - **Category:** Observation. -### 45. `clusterId?: string | undefined` shape +### 36. `clusterId?: string | undefined` shape Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:258,304,357,641,683,733,817`). - **Category:** 6 (misleading optional — should be required), Observation. -### 46. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) +### 37. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). - **Category:** 1 (vague), 17 (inconsistent), Observation. -### 47. `flattenQueryParams` exported but unused (`utils.ts:123`) +### 38. `flattenQueryParams` exported but unused (`utils.ts:123`) The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. - **Category:** Observation (dead public surface). -### 48. JSDoc placeholder `` — pervasive -Throughout the model, JSDocs say `` (e.g., `model.ts:1128` — "Databricks will tag all cluster resources..."). Looks like an un-substituted templated brand placeholder. Reader sees `` in IntelliSense. -- **Category:** Observation (doc-quality artefact in generator). - ## Domain glossary - `dbfs` — Databricks File System. diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 8158e55c..f990f812 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -115,19 +115,19 @@ - **Suggested name:** `readStreamToEnd` / `drainStream`. - **Rationale:** Trivial; flagged for cross-package consistency. -### 19. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 17. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should encode the layer, not just the protocol. -### 20. `HttpCallOptions` — `src/v1/utils.ts:15` +### 18. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). - **Rationale:** Distinguish internal context bags from user-facing option structs. -### 21. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:167-168` +### 19. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:167-168` - **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. - **Category:** Observation only. - **Suggested name:** None — this is the marshalling boundary by design. @@ -135,14 +135,14 @@ ## Observations -### 22. Casing inconsistency in vendor name decomposition +### 20. Casing inconsistency in vendor name decomposition Within `ConnectionType`: - `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). - `MYSQL` (joined) vs `GA4_RAW_DATA` (split). No discoverable rule. Wire-locked, but worth surfacing. - **Category:** 3 (acronym/casing inconsistency). -### 23. `Client` constructor throws for missing host +### 21. `Client` constructor throws for missing host `if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. - **Category:** Observation. diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index b75faf3d..ab291fe9 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -3,20 +3,20 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 **Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. -**Total weird names flagged:** 22 (0 fixed, 22 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 19 (0 fixed, 19 still present after rescan on 2026-05-26 post regen #156) ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 7 | +| High | 3 | +| Medium | 6 | | Low | 7 | -| Observation | 4 | +| Observation | 3 | ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #21). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #19). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. @@ -27,13 +27,7 @@ - **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). - **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. -### 3. `StartCustomLlmOptimizationRunRequest.id` doc says "Id of the tile" — `src/v1/model.ts:79` -- **Why weird:** Doc comment "The Id of the tile." refers to a "tile" that does not exist anywhere else in the package. This is almost certainly a copy-paste from another generated API (dashboards/tiles). Either the field name or the doc is wrong; reading the surrounding code, the field is the custom-LLM id (same as `CancelCustomLlmOptimizationRunRequest.id` on line 20). Public SDK doc bug. -- **Category:** 6 (misleading — doc contradicts the actual domain). -- **Suggested name:** Field name stays `id`; fix the JSDoc to "The id of the custom LLM whose optimization run to start." (matches `DeleteCustomLlmRequest.id` and `GetCustomLlmRequest.id` docs on lines 69 and 74). -- **Rationale:** A naming audit should flag doc-text bugs on identifiers as well as the identifier itself; consumers learn the semantics from JSDoc and a wrong doc is as harmful as a wrong name. - -### 4. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` +### 3. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` - **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. - **Category:** Observation / 6 (misleading — field-mask implies updatable). - **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. @@ -41,43 +35,37 @@ ## Medium severity -### 5. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` +### 4. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` - **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. - **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). - **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. - **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. -### 6. `creationTime: Temporal.Instant` — `src/v1/model.ts:60` -- **Why weird:** `Temporal.Instant` is correct (good!) but the field name `creationTime` reads as a `Date` and many callers will accidentally `new Date(customLlm.creationTime)`, which throws because `Temporal.Instant` does not coerce. Worth a comment in JSDoc; not a rename. -- **Category:** Observation. -- **Suggested name:** Keep `creationTime`; expand JSDoc to mention `Temporal.Instant`. -- **Rationale:** Friction is from the type more than the name, but the name does not warn the reader of the unusual type. - -### 7. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +### 5. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 8. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair +### 6. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair - **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. - **Rationale:** Names should differ in more than the `Http` infix. -### 9. `HttpCallOptions` — `src/v1/utils.ts:15` +### 7. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. - **Category:** 1 (vague suffix). - **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). - **Rationale:** Distinguish internal context bags from user-tunable option structs. -### 10. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` +### 8. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` - **Why weird:** The `State` enum's first member `STATE_UNSPECIFIED` is a proto-architectural leak. Proto3 requires every enum to declare a zero-value sentinel (typically `FOO_UNSPECIFIED`); that requirement does not exist in TypeScript. Exposing it on the public TS surface forces every consumer to handle a member that semantically means "the server forgot to set this field" — a proto wire-format concern, not a domain concern. The screaming-snake-case casing (`STATE_UNSPECIFIED`) also leaks proto's enum-value convention into a TS type system that conventionally uses PascalCase for enum members (https://google.github.io/styleguide/tsguide.html#enums). - **Category:** Proto-architectural leak (enum sentinel + screaming-snake casing). - **Suggested name:** Drop the `STATE_UNSPECIFIED` member entirely; if a "not yet set" value is needed, use `undefined` (the field is already `State | undefined`). If kept, rename to PascalCase `Unspecified` and document that it is a wire-format sentinel. - **Rationale:** Optional TS fields express "unset" via `undefined`; a redundant enum sentinel doubles the representation of "no value" and forces consumers to write `state !== undefined && state !== State.STATE_UNSPECIFIED`. The all-caps casing further signals that the value is a proto artifact rather than a designed TS API member. -### 11. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` +### 9. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` - **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. @@ -85,43 +73,43 @@ ## Low severity -### 12. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +### 10. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` - **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. - **Category:** Observation / 9 (reversed — correctly singular). - **Suggested name:** No change. - **Rationale:** Note for consistency reviews. -### 13. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 11. `customLlmFieldMask` function name — `src/v1/model.ts:259` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). - **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. -### 14. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` +### 12. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` - **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (if it is an unused generator default), or document why it ships per-package. - **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. -### 15. `readAll` helper — `src/v1/utils.ts:40` +### 13. `readAll` helper — `src/v1/utils.ts:40` - **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToEnd`. - **Rationale:** Internal helper, low cost. Skip if generated. -### 16. `Call` import alias — `src/v1/client.ts:4` +### 14. `Call` import alias — `src/v1/client.ts:4` - **Why weird:** `import type {Call}` — `Call` is a one-word generic noun. Used for the inner async function. Could be `RetryableCall`, `HttpCallback`, etc. Not local to this package (it is from `@databricks/sdk-core/api`), but worth flagging. - **Category:** 1 (vague type name). - **Suggested name:** Imported type; rename upstream if appropriate. - **Rationale:** Generic noun in core API surface. -### 17. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` +### 15. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` - **Why weird:** Three-letter local names. `info` for the client-info builder, `host` for the URL host, `body` for the request body. Conventional and short, but `info` is especially vague. - **Category:** 1 (vague). - **Suggested name:** Keep `host` and `body` (universal); rename `info` to `clientInfo`. - **Rationale:** Localized; cosmetic. -### 18. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` +### 16. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` - **Why weird:** `resp` is the response. Four methods declare `let resp: CustomLlm | undefined;` then assign in a closure and `throw` if undefined. The pattern is repetitive *and* uses the same short name. Consider extracting a helper that returns `T | never`. - **Category:** 12 (duplicate pattern). - **Suggested name:** Refactor away the pattern, not the name. @@ -129,22 +117,18 @@ ## Observations -### 19. Action verbs in `Client` are consistent +### 17. Action verbs in `Client` are consistent The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. - **Category:** 17 (reversed — explicit *consistency* note). -### 20. No `list` operation +### 18. No `list` operation The package exposes singleton CRUD plus optimization start/cancel, but no `listCustomLlms`. Unusual for a Databricks resource SDK. Not a naming issue, but worth flagging because the typical resource SDK has `list` and users will look for it. - **Category:** Observation. -### 21. Mixed acronym casing in core types +### 19. Mixed acronym casing in core types The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `ApiError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `Api` (title), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. - **Category:** 3 (acronym casing). -### 22. `flattenQueryParams` array-of-objects TODO — `src/v1/utils.ts:132` -Comment "// arrays of objects are not yet supported" inside a generated utility. Not a name issue, but the public-export status of this function makes the TODO load-bearing. -- **Category:** Observation. - ## Domain glossary - `llm` — Large Language Model (every type, every field, every method; the canonical token). - `uc` — Unity Catalog (mentioned only in JSDoc on `agentArtifactPath` and `Table.tablePath`: "Full UC table path in catalog.schema.table_name format"). diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index ae0b31b8..f1974a89 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,15 +3,15 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 29 +**Total weird names flagged:** 24 ## Summary | Severity | Count | | --- | --- | | High | 7 | -| Medium | 12 | -| Low | 7 | -| Observation | 3 | +| Medium | 11 | +| Low | 4 | +| Observation | 2 | ## High severity @@ -107,25 +107,19 @@ - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 16. `DeleteDatabaseInstanceRequest.purge` field is documented as deprecated — `src/v1/model.ts:411-415` -- **Why weird:** "Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. Setting a value of false will throw a bad request." Field is exposed in the public TS type but has no `@deprecated` JSDoc tag. -- **Category:** 6 (misleading: deprecated field undocumented as deprecated). -- **Suggested name:** Add `@deprecated` tag; consider removing in next major. -- **Rationale:** TS tooling honours `@deprecated`; the current setup just has prose. - -### 17. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` -- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #18 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. +### 16. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` +- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #17 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. - **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). - **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`; field `inlinePipeline` (paired with `existingPipelineId`). Drop the `New` adjective and the `Spec` suffix. - **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. -### 18. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` -- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #19); `DeltaTableSyncInfo` is a sync checkpoint (see #13); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #17). Each of the four would read more clearly with a domain-specific suffix. +### 17. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` +- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #18); `DeltaTableSyncInfo` is a sync checkpoint (see #13); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #16). Each of the four would read more clearly with a domain-specific suffix. - **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). -- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #17); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #13); `ProvisioningInfo` → drop (per #19). Goal: no two types in the package share a generic suffix. +- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #16); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #13); `ProvisioningInfo` → drop (per #18). Goal: no two types in the package share a generic suffix. - **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. -### 19. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` +### 18. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` - **Why weird:** Type declaration is literally `export interface ProvisioningInfo {}` with a comment "Copied over from managed-catalog/api/messages/common.proto to decouple SDK packages. xref go/unified-api-packages-dd". An empty interface — the type itself carries zero domain meaning. Only its nested `ProvisioningInfo_State` enum is used (referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`); the empty parent is a vestigial proto namespace. The exported type name and its nested enum bleed Managed Catalog internals into the Lakebase SDK. - **Category:** proto-architectural leak (proto message preserved as empty TS interface for namespacing), 6 (misleading — exists but has no fields), 12 (cross-package proto leak). - **Suggested name:** Drop the empty `ProvisioningInfo` interface; rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). The empty interface is a generator artefact that should not surface. @@ -133,43 +127,25 @@ ## Low severity -### 20. `ListDatabaseInstanceRolesRequest.pageToken` doc copy-pasta — `src/v1/model.ts:505` -- **Why weird:** Doc says "Pagination token to go to the next page of Database Instances" — but this is roles, not instances. Doc-copy bug. -- **Category:** 6 (misleading doc). -- **Suggested name:** Fix the doc to say "roles". -- **Rationale:** Naming-adjacent bug worth flagging. - -### 21. `ListDatabaseCatalogsRequest.pageToken` doc says "synced database tables" — `src/v1/model.ts:491` -- **Why weird:** Same bug: catalogs request says "synced database tables" in doc. -- **Category:** 6 (misleading doc). -- **Suggested name:** Fix to "catalogs". -- **Rationale:** Same as #20. - -### 22. `ListDatabaseInstanceRolesResponse.nextPageToken` doc says "next page of instances" — `src/v1/model.ts:514` -- **Why weird:** Doc says "next page of instances" for the roles response. -- **Category:** 6 (misleading doc). -- **Suggested name:** Fix to "roles". -- **Rationale:** Same as #20. - -### 23. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` +### 19. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` - **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:181-184). - **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). - **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. - **Rationale:** Caller has to know the wire-encoding accident to decide which to set. -### 24. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` +### 20. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` - **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. - **Category:** 14 (Google-AIP naming convention leak). - **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. - **Rationale:** Internal-jargon leak; flag for awareness. -### 25. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` +### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` - **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. - **Rationale:** Cross-package consistency. -### 26. `StillRunningError` private error class — `src/v1/client.ts:83` +### 22. `StillRunningError` private error class — `src/v1/client.ts:83` - **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. - **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). - **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). @@ -177,17 +153,12 @@ ## Observations -### 27. `client.ts` has a 5-line block-comment at line 633-638 explaining that the role APIs will never reach Public Preview -The comment ("START OF PG ROLE APIs Section ... These APIs are marked a PUBLIC with stage < PUBLIC_PREVIEW. With more recent Lakebase V2 plans, we don't plan to ever advance these to PUBLIC_PREVIEW.") leaks internal lifecycle. It belongs in JSDoc on each role method as `@experimental` / `@internal`, not as a block-comment in the middle of the client. -- **Category:** 6 (misleading: client exposes APIs that won't stabilise). -- **Action:** Mark `createDatabaseInstanceRole`, `deleteDatabaseInstanceRole`, `getDatabaseInstanceRole`, `listDatabaseInstanceRoles`, `updateDatabaseInstanceRole` as `@experimental`. - -### 28. `findDatabaseInstanceByUid` is the only `findBy*` method +### 23. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 29. Action-verb conventions in `Client` are consistent -`create*` / `delete*` / `get*` / `list*` / `update*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. +### 24. Action-verb conventions in `Client` are consistent +`create*` / `delete*` / `get*` / `list*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. ## Domain glossary - `Lakebase` — Databricks' managed Postgres-as-a-service product (mentioned only in the buried client.ts:634 comment). diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 0cb80601..96e0c2c1 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -127,13 +127,13 @@ - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - **Rationale:** Add the missing domain word. -### 22. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` +### 19. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` - **Why weird:** Same as `dataclassification` finding #24; variable named `call` of type `Call` repeated 11 times across the client. - **Category:** 1, 12. - **Suggested name:** `request` (variable) — reserve `Call` for the type. - **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. -### 23. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +### 20. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` - **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. @@ -141,20 +141,20 @@ ## Observations -### 24. Heavy boilerplate dominates the file +### 21. Heavy boilerplate dominates the file `model.ts` is 1030 lines for ~16 user-facing types; ~520 lines (~50%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. -### 25. Action verbs in `Client` +### 22. Action verbs in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) -### 26. Acronym casing +### 23. Acronym casing Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. - **Category:** 3 (acronym casing). -### 27. Tense / nominalisation drift in enum naming +### 24. Tense / nominalisation drift in enum naming `AnomalyDetection` (gerund), `DataProfiling` (gerund), `DataClassification` (noun) — at the package boundary the gerund/noun choice tracks the API team's preference. Within `dataquality` the choice is consistent (both gerunds), good. -### 28. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types +### 25. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types Same shape as the `dataclassification` casing observation (#32 in that package): directory is one collapsed word, types are PascalCase compounded, wire path is kebab. SDK-wide convention question, not local. - **Category:** 3 (casing inconsistency). diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index c0ffd224..8b01e25e 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -3,13 +3,13 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 14 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 3 | -| Medium | 4 | +| Medium | 3 | | Low | 5 | | Observation | 2 | @@ -25,7 +25,7 @@ - **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #13 — same issue applies in `utils.ts` field `url` on `StableUrl`.) +- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #12 — same issue applies in `utils.ts` field `url` on `StableUrl`.) ### 3. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` - **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: @@ -48,16 +48,10 @@ ### 5. `UcReplicationConfig` — `src/v1/model.ts:284` - **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). -- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #9). +- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #8). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. -### 6. `etag` field on multiple types — `src/v1/model.ts:78,106,138` -- **Why weird:** `etag` lowercased. Web/HTTP convention is `ETag` (capital E-Tag, RFC 9110 §8.8.3). The wire format here is `etag` (lowercase, per the Zod schema line 332). Mixed casing across the ecosystem; the lowercase here at least mirrors the wire, but a TS reader might expect `eTag` or `ETag`. -- **Category:** 3 (acronym casing). -- **Suggested name:** Keep `etag` for wire fidelity; document the choice in a top-level comment. (Or use `eTag` if the SDK style guide prefers JS-camelCase for acronyms.) -- **Rationale:** Low-impact but flagged because the audit asks for casing inconsistencies. The Google TS style guide (loaded skill `google-ts-styleguide:ts-style-guide`) generally prefers camelCase for acronyms (so `etag` is actually fine). - -### 7. `Client` class name — `src/v1/client.ts:52` +### 6. `Client` class name — `src/v1/client.ts:52` - **Why weird:** Plain `Client` is the maximally-generic name. Once imported, callers see `import { Client } from '@databricks/sdk-disasterrecovery/v1'` — fine if used qualified, but `new Client()` floating in user code is meaningless. Sibling packages all do the same per generator convention; flagging this once at the package level. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `DisasterRecoveryClient`. (Or rely on import aliases.) @@ -65,31 +59,31 @@ ## Low severity -### 8. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +### 7. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. -### 9. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` +### 8. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` - **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Same as other packages in the audit. Flag once per package. -### 10. `flattenQueryParams` — `src/v1/utils.ts:123` +### 9. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. - **Category:** Observation / 11 (unused public helper). - **Suggested name:** Either remove the export (generator default) or document why it ships per-package. - **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. -### 11. `readAll` — `src/v1/utils.ts:40` +### 10. `readAll` — `src/v1/utils.ts:40` - **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. - **Category:** 1 (vague). - **Suggested name:** `drainStream` / `readStreamToBuffer`. - **Rationale:** Internal helper. Skip if generated identically across all packages. -### 12. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` +### 11. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` - **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + ApiError lift). - **Category:** 1 (vague), 17 (inconsistent). - **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). @@ -97,10 +91,10 @@ ## Observations -### 13. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#8), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. +### 12. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#7), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. -### 14. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +### 13. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` Within this package: - `stableUrl`/`StableUrl` (PascalCase capital-then-lower). - `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). diff --git a/.agent/naming-audit/endpoints.md b/.agent/naming-audit/endpoints.md deleted file mode 100644 index c278c71c..00000000 --- a/.agent/naming-audit/endpoints.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: endpoints - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index 8f7b1761..3ee2878d 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -5,15 +5,15 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 19 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 4 | -| Low | 5 | -| Observation | 2 | +| High | 7 | +| Medium | 3 | +| Low | 2 | +| Observation | 1 | --- @@ -67,35 +67,23 @@ - **Suggested name:** `ServiceErrorDetails`, `DatabricksError`, or `RpcError`. Drop the `WithDetails`, `Proto`, and `Exception` suffix all at once. - **Rationale:** The name has the worst of every world: Java verb + Proto codegen tag + length. No piece of the name helps a TS consumer. -### 8. `refreshWorkspaceBaseEnvironment` doc comment refers to "Refresh*Workspace*BaseEnvironment**s**" plural and the request type docstring says "to delete" — `model.ts:680, 683` -- **Why weird:** The request type is `RefreshWorkspaceBaseEnvironmentRequest` (singular), but its JSDoc says: "Request message for RefreshWorkspaceBaseEnviro**ments**" (plural). The same type's `name` field doc says: "Required. The resource name of the workspace base environment **to delete**" — i.e. copy-pasted from the delete request and never edited. -- **Category:** 9 (singular/plural mismatch — type vs doc), 6 (misleading doc — says delete). -- **Suggested name:** Fix the docstrings — say "Refresh a workspace base environment. The resource name of the environment to refresh." Either keep the type singular (matches the client method `refreshWorkspaceBaseEnvironment`) or move to plural everywhere. -- **Rationale:** Wrong action verb in a doc that an IDE will display when the user hovers a parameter. The package was generated from a proto where the message-name was singular but the doc-string copied from elsewhere — the SDK is propagating the bug. - --- ## Medium severity -### 9. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` +### 8. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` - **Why weird:** The `ErrorCode` enum has roughly 100 members. The doc comments mark a large fraction as deprecated ("kept to maintain backwards compatibility"). Many members are domain-specific (e.g. `IPYNB_FILE_IN_REPO`, `GIT_URL_NOT_ON_ALLOW_LIST`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `DAC_ALREADY_EXISTS`) and have nothing to do with environments. The enum is a kitchen-sink import of every Databricks-platform error code, exported from a *workspace-base-environment* package. - **Category:** 1 (overly broad — exposed in the wrong scope), 7 (overly verbose surface), 12 (duplicate concept — `ErrorCode` likely lives in many packages). - **Suggested name:** Move to a shared `@databricks/sdk-databricks/apierror` (where `apierr/codes/` already lives, per AGENTS.md) and import it. The environments package should export at most the subset of codes it actually returns. - **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `ApiError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. -### 10. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` +### 9. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` - **Why weird:** Enum values are SCREAMING_SNAKE wire strings (e.g. `MAX_CHILD_NODE_SIZE_EXCEEDED`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). 100+ values × ~30 chars each = a large surface that consumers must spell exactly. TS pattern is `PascalCase` enum members. - **Category:** 14 (Java/Go-style names), 18 (long enum values). - **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. - **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. -### 11. `UpdateWorkspaceBaseEnvironmentRequest.name` is undocumented — `model.ts:706` -- **Why weird:** Most `*Request` types document their `name` field as "The resource name of the workspace base environment to ..." but `UpdateWorkspaceBaseEnvironmentRequest.name` (model.ts:706) is the only one with no JSDoc. The very next field (`workspaceBaseEnvironment`, line 711) is documented and even references `name`: "The name field is used to identify the environment to update." -- **Category:** 19 (underspecified ID), 6 (misleading by omission). -- **Suggested name:** Add JSDoc. The field is the resource name to update; say so. Or drop the field entirely if it duplicates `workspaceBaseEnvironment.name`. -- **Rationale:** Inconsistent doc coverage in a generated file is a tell that the source proto field has no comment — should be fixed upstream. - -### 12. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` +### 10. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` - **Why weird:** The mid-position word `Service` in `DatabricksServiceExceptionWithDetailsProto` describes a server-side architectural layer ("a service threw this exception"), not anything about the data the type carries. The type is a plain error payload with `errorCode`/`message`/`stackTrace`/`details`; no field references a "service". `Service` here mirrors the Java `*ServiceException` superclass pattern and the proto message name `DatabricksServiceExceptionWithDetails` — both server-internal concepts that have no meaning for a TS SDK consumer. Combined with the trailing `Proto` (codegen origin) the name is a stack of three architectural tags: `Service` (layer) + `Exception` (Java throwable) + `Proto` (wire format). - **Category:** proto-architectural-leak (mid-position `Service` is not the domain), 14 (Java-style naming), 20 (`Proto` suffix tautology). - **Suggested name:** `DatabricksErrorDetails`, `ServiceErrorPayload` is still leaky; prefer `ApiErrorDetails` or `RpcErrorDetails` if the gRPC framing is part of the public contract, otherwise just `ErrorDetails`/`DatabricksError`. Drop `Service`, `Exception`, and `Proto` together. @@ -105,50 +93,26 @@ ## Low severity -### 13. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` +### 11. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` - **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:741). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:564) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. - **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). - **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. - **Rationale:** Two representations of "is this the default" invite drift. -### 14. `ListWorkspaceBaseEnvironmentsRequest.pageSize` doc says "Default is 1000" with no min/max — `model.ts:619` -- **Why weird:** Page-size doc says only "Default is 1000". No documented min/max, no behavior on `0`, no behavior on values exceeding server cap. -- **Category:** 19 (underspecified). -- **Suggested name:** Add doc bounds. -- **Rationale:** Doc-only nit; not a name issue per se but worth flagging in a naming audit because `pageSize` is a known naming convention with known semantics that this doc partially undermines. - -### 15. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:545` +### 12. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:545` - **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. - **Category:** 19 (underspecified), 6 (slightly misleading). - **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. - **Rationale:** Doc-implied invariants that aren't in the type. -### 16. `WorkspaceBaseEnvironment.displayName` — generic, lacks "human-readable" or constraints — `model.ts:725` -- **Why weird:** Doc says "Human-readable display name". No documented uniqueness, max length, allowed characters. Compare `workspaceBaseEnvironmentId` (model.ts:543) which is constrained: "4-63 characters, valid characters /[a-z][0-9]-/". `displayName` deserves similar treatment in the doc. -- **Category:** 19 (underspecified), 1 (slightly generic). -- **Suggested name:** Keep but document constraints. -- **Rationale:** Minor. - -### 17. `WorkspaceBaseEnvironment.filepath` — points at a YAML file but type is `string` — `model.ts:727` -- **Why weird:** Doc says "The WSFS or UC Volumes path to the environment YAML file." But the field is `string`. WSFS paths and UC Volume paths have different syntaxes (`/Workspace/...` vs `/Volumes/...`). The type permits any string. A union of the two path types would be more precise but probably not worth the porting effort. -- **Category:** 19 (underspecified — the doc lists two valid path types but the type doesn't distinguish). -- **Suggested name:** Keep `filepath`, but document the allowed prefixes. -- **Rationale:** Minor. - --- ## Observation -### 18. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` +### 13. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` - **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. - **Category:** 12 (duplicate concept), 6 (misleading lineage signal). - **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. - **Rationale:** Generator-level; not actionable in TS alone, but worth recording. -### 19. JSDoc comment "If changed, also update estore/namespaces/defaultbaseenvironments/latest.proto" leaks internal-only path — `model.ts:8` -- **Why noteworthy:** The comment on `BaseEnvironmentType` references an internal proto path that public SDK consumers cannot see, cannot navigate to, and have no use for. It's a generator-cycle reminder to Databricks engineers that shouldn't have made it through the porting/codegen scrub. -- **Category:** 6 (misleading — refers to a non-public artefact in a doc comment public users see). -- **Suggested action:** Strip internal references from generated comments at codegen time. -- **Rationale:** SDK hygiene; not a name issue but worth flagging in the audit since the comment is on a *public* type. - --- diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index a24538c5..1b8b6886 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -3,15 +3,15 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 **Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 40 +**Total weird names flagged:** 34 ## Summary | Severity | Count | | --- | --- | | High | 12 | -| Medium | 15 | -| Low | 9 | -| Observation | 4 | +| Medium | 11 | +| Low | 8 | +| Observation | 3 | ## High severity @@ -95,68 +95,52 @@ - **Suggested name:** `GetMetricValuesRequest` / `getMetricValues`, or `ListMetricHistoryRequest` / `listMetricHistory` (since it paginates). - **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. -### 14. `LogModel` is deprecated and method docs say so — `src/v1/client.ts:973-979` -- **Why weird:** The docstring literally starts with "**Note:** the [Create a logged model](...) API replaces this endpoint." But `logModel` is still exported with no `@deprecated` JSDoc tag. Same for `LogModelRequest` and `LogModelRequest_Response`. The method `createLoggedModel` is the replacement. -- **Category:** 6 (misleading — exported as if it were current). -- **Suggested name:** Add `@deprecated Use createLoggedModel instead.` JSDoc to `logModel`, `LogModelRequest`, `LogModelRequest_Response`. -- **Rationale:** A linter or IDE that reads `@deprecated` will warn users; a plaintext note in the markdown JSDoc body will not. - -### 15. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` +### 14. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` - **Why weird:** Multiple types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. - **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). - **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. - **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. -### 16. `userId` deprecated — `src/v1/model.ts:101, 738` -- **Why weird:** Same problem as #15 but for `userId` on `CreateRunRequest.userId` and `RunInfo.userId`. JSDoc: "This field is deprecated as of MLflow 1.0, and will be removed in a future MLflow release. Use 'mlflow.user' tag instead." No `@deprecated` tag. -- **Category:** 6. -- **Suggested name:** Add `@deprecated`. Same as #15. - -### 17. `creatorId: number` (not string) — `src/v1/model.ts:584` +### 15. `creatorId: number` (not string) — `src/v1/model.ts:584` - **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." - **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). - **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. - **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). -### 18. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` +### 16. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` - **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. - **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). - **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). - **Rationale:** Heterogeneous string ID fields are debugging traps. -### 19. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` +### 17. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` - **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#10) buries the ID one level deep. - **Category:** 15 (generic field name losing meaning), 7 (verbose access). - **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). - **Rationale:** Awkward access pattern. -### 20. `RunInfo.experimentId` is bare while `LoggedModelInfo.experimentId` doc says "The ID of the experiment that owns the model" — `src/v1/model.ts:730, 572` -- **Why weird:** Two fields named `experimentId`, two completely different relationships. On `RunInfo` the field connects the run to its parent experiment. On `LoggedModelInfo` it connects the model to its owning experiment. JSDoc only on one of them. -- **Category:** 15 (generic name losing meaning across contexts). -- **Suggested name:** Both are fine as `experimentId` if doc consistently says "parent experiment". The issue is uneven JSDoc. - -### 21. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` +### 18. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` - **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:916`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). - **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParamsRequest`. - **Rationale:** The double-Log is jarring on read. -### 22. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` +### 19. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` - **Why weird:** `setExperimentTag(req: SetExperimentTagRequest)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTagsRequest)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 23. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` +### 20. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` - **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. - **Category:** Observation (URL design upstream). -### 24. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` +### 21. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 25. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 22. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -170,67 +154,55 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 26. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` +### 23. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` - **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. - **Category:** 15 (generic field name losing structure). -### 27. `LogModelRequest.modelJson` — bare json string field — `src/v1/model.ts:508-513` -- **Why weird:** `LogModelRequest.modelJson` is "MLmodel file in json format." Field name OK but content is a serialized MLmodel YAML/JSON file — the user must construct an MLmodel doc. The SDK does no parsing or validation. -- **Category:** Observation (an opaque blob field could carry doc). - ## Low severity -### 28. `RunInfo.lifecycleStage` doc says "the experiment" but field is on a Run — `src/v1/model.ts:753` -- **Why weird:** `RunInfo.lifecycleStage` JSDoc says: "Current life cycle stage of the experiment : OneOf("active", "deleted")". But this is a `Run`'s `lifecycleStage`, not the experiment's. Same field on `Experiment.lifecycleStage` (model.ts:230) is correctly described. -- **Category:** 6 (misleading doc — wrong entity name in description). -- **Suggested name:** Fix doc to say "Current life cycle stage of the run". - -### 29. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` +### 24. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` - **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #8. The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 30. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 25. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 31. `FileInfo` itself is a generic name — `src/v1/model.ts:248` +### 26. `FileInfo` itself is a generic name — `src/v1/model.ts:248` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. -### 32. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` +### 27. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` - **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. - **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). - **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). -### 33. `HttpCallOptions` — `src/v1/utils.ts:15` +### 28. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). - **Category:** 17 (collision risk with `CallOptions`). -### 34. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` +### 29. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` - **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) - **Category:** Observation (dead export). -### 35. `PACKAGE_SEGMENT` constant in `client.ts:161` — `src/v1/client.ts:161` +### 30. `PACKAGE_SEGMENT` constant in `client.ts:161` — `src/v1/client.ts:161` - **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. - **Category:** 17 (inconsistency in identifier case across the file). - **Suggested name:** `packageSegment` per TS conventions. -### 36. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:162` +### 31. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:162` - **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. - **Category:** 1 (generic name leaking into observability). ## Observations (non-actionable but noted) -### 37. `Dataset.name` examples include emoji "fantastic-elk-3" — `src/v1/model.ts:121, 494, 622` -- **Note:** JSDoc on `Dataset.name`, `LogMetricRequest.datasetName`, `Metric.datasetName` includes the literal example `"fantastic-elk-3"` (with smart quotes) — a generated mlflow run-name example. Looks like documentation noise that survived the port. - -### 38. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-130` +### 32. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-130` - **Note:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. -### 39. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +### 33. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` - **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. -### 40. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` +### 34. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` - **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index 0c568a05..ec67f0f6 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -11,7 +11,7 @@ update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting sub-structure is `FileEventQueue` — an oneof-of-oneofs across three cloud providers (Azure AQS, AWS SQS, GCP Pub/Sub) with a parallel "provided" vs "managed" axis (6 cases total). -**Total weird names flagged:** 13 +**Total weird names flagged:** 12 --- @@ -23,15 +23,14 @@ providers (Azure AQS, AWS SQS, GCP Pub/Sub) with a parallel "provided" vs | 2 | `Client` | client.ts:44 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client`. Every package in the SDK exports a class literally named `Client`; importers must alias on collision. `ExternalLocationsClient` would self-identify. | | 3 | `SseEncryptionAlgorithm.AWS_SSE_S3` / `AWS_SSE_KMS` | model.ts:13-14 | enum values | Medium | 3 Acronym casing | The two non-sentinel members redundantly carry an `AWS_` prefix (the enclosing type name already says SSE which is AWS terminology). The wrapping `Sse*` already implies S3-server-side, so the leading `AWS_` is duplicative. | | 4 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type | model.ts:17, 27, 183 | type set | Medium | (none individually, taken as set: inconsistent) | The three queue-config types use three different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`. | -| 5 | `AwsSqsQueue.queueUrl` JSDoc says "AQS queue url" | model.ts:19 | doc | Medium | 6 Misleading names | The type is **AWS SQS**, but the JSDoc says "The AQS queue url" — AQS is *Azure* Queue Storage (the next type over). Copy-paste error from `AzureQueueStorage.queueUrl`. Misleading for any AWS user reading docs. | -| 6 | `GcpPubsub` (lowercase "ubsub") | model.ts:183 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | -| 7 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | -| 8 | `nameArg` field | model.ts:102, 195, 244 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocationRequest`, `GetExternalLocationRequest`, `UpdateExternalLocationRequest`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | -| 9 | `DeleteExternalLocationRequest_Response` | model.ts:108 | type | High | 16 Proto-architectural-leak names | Underscore-delimited proto-nested message name leaked through to the TS public surface. The `_Response` suffix is a Go/Protobuf RPC convention; idiomatic TS would name this `DeleteExternalLocationResponse` (or omit it entirely when the body is empty). | -| 10 | `ListExternalLocationsRequest_Response` | model.ts:221 | type | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern. Should be `ListExternalLocationsResponse`. The leading `Request_` infix is meaningless to a TS caller — the response is not "the response of a request type", it is the list response. | -| 11 | `unmarshalDeleteExternalLocationRequest_ResponseSchema` | model.ts:324 | const | High | 16 Proto-architectural-leak names | Schema constant inherits the proto-nested `Request_Response` identifier. Should track whatever the renamed type becomes (e.g., `unmarshalDeleteExternalLocationResponseSchema`). | -| 12 | `unmarshalListExternalLocationsRequest_ResponseSchema` | model.ts:436 | const | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern carried into schema constant naming. | -| 13 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | +| 5 | `GcpPubsub` (lowercase "ubsub") | model.ts:183 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | +| 6 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | +| 7 | `nameArg` field | model.ts:102, 195, 244 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocationRequest`, `GetExternalLocationRequest`, `UpdateExternalLocationRequest`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | +| 8 | `DeleteExternalLocationRequest_Response` | model.ts:108 | type | High | 16 Proto-architectural-leak names | Underscore-delimited proto-nested message name leaked through to the TS public surface. The `_Response` suffix is a Go/Protobuf RPC convention; idiomatic TS would name this `DeleteExternalLocationResponse` (or omit it entirely when the body is empty). | +| 9 | `ListExternalLocationsRequest_Response` | model.ts:221 | type | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern. Should be `ListExternalLocationsResponse`. The leading `Request_` infix is meaningless to a TS caller — the response is not "the response of a request type", it is the list response. | +| 10 | `unmarshalDeleteExternalLocationRequest_ResponseSchema` | model.ts:324 | const | High | 16 Proto-architectural-leak names | Schema constant inherits the proto-nested `Request_Response` identifier. Should track whatever the renamed type becomes (e.g., `unmarshalDeleteExternalLocationResponseSchema`). | +| 11 | `unmarshalListExternalLocationsRequest_ResponseSchema` | model.ts:436 | const | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern carried into schema constant naming. | +| 12 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | --- @@ -120,25 +119,7 @@ are AWS-only concepts. Within the proto-style identifier convention these could read as plain `SSE_S3` / `SSE_KMS`, or even `S3` / `KMS` since the wrapping type already says SSE. -### M2. `AwsSqsQueue.queueUrl` JSDoc says "AQS" - -```ts -export interface AwsSqsQueue { - /** - * The AQS queue url in the format https://sqs.{region}.amazonaws.com/{account id}/{queue name}. - * Only required for provided_sqs. - */ - queueUrl?: string | undefined; - // ... -} -``` - -The type is **AWS SQS**, but the doc string starts "The AQS queue url" — AQS -is Azure Queue Storage. Copy-paste error from the sibling `AzureQueueStorage.queueUrl` -JSDoc (lines 28-31). Wire-format example string is correct (AWS SQS); only the -prose is wrong. Confusing for any AWS user. - -### M3. The three cloud-provider queue types use three different naming conventions +### M2. The three cloud-provider queue types use three different naming conventions ```ts interface AwsSqsQueue { ... } // cloud + service + Queue @@ -152,7 +133,7 @@ Three naming patterns for three parallel types. Pick one: - All without: `AwsSqs`, `AzureQueueStorage`, `GcpPubsub`. - All as `Config`: `AwsSqsConfig`, `AzureAqsConfig`, `GcpPubsubConfig`. -### M4. `AzureQueueStorage` vs `Aqs` abbreviation +### M3. `AzureQueueStorage` vs `Aqs` abbreviation The interface name is `AzureQueueStorage`, but two of its consumers (the discriminator case keys `providedAqs`/`managedAqs` and the wire-format string @@ -160,13 +141,13 @@ discriminator case keys `providedAqs`/`managedAqs` and the wire-format string not standard Microsoft terminology — Microsoft's docs call this "Azure Queue Storage" or "Azure Storage Queues". `AQS` is Databricks-internal shorthand. -### M5. `Pubsub` casing +### M4. `Pubsub` casing GCP's product is "Pub/Sub" (with slash and two capitals). The TS type is `GcpPubsub` (one capital). Internally consistent (the discriminator cases `providedPubsub`/`managedPubsub` match), but not the canonical GCP spelling. -### M6. `ExternalLocationInfo` — `Info` suffix carries no semantic value +### M5. `ExternalLocationInfo` — `Info` suffix carries no semantic value ```ts export interface ExternalLocationInfo { ... } @@ -233,15 +214,14 @@ The following acronyms appear: ## Summary -13 findings: +12 findings: - **5 High severity** — `nameArg` artifact, two `Request_Response` proto-nested type names, two matching schema-constant names. -- **7 Medium severity** — `Client` collision, redundant `AWS_` prefix on +- **6 Medium severity** — `Client` collision, redundant `AWS_` prefix on `SseEncryptionAlgorithm` members, queue-type naming-pattern inconsistency, - `AQS` JSDoc copy-paste, `AzureQueueStorage`/`Aqs` long-vs-short - inconsistency, `Pubsub` casing, `ExternalLocationInfo` redundant `Info` - suffix. + `AzureQueueStorage`/`Aqs` long-vs-short inconsistency, `Pubsub` casing, + `ExternalLocationInfo` redundant `Info` suffix. - **1 Low severity** — `externallocations` package folder verbosity. Primary themes: @@ -253,7 +233,6 @@ Primary themes: model.ts:107 / 220 / 323 / 435 are themselves the giveaway. 2. **Cloud-provider naming is internally inconsistent**: three queue-config types with three different naming conventions, AQS abbreviation that isn't - Microsoft canonical, copy-paste error mixing AWS SQS and Azure AQS in one - JSDoc. + Microsoft canonical. --- diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index d039371c..2c949c45 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -3,13 +3,13 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 26 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 5 | +| Medium | 4 | | Low | 9 | | Observation | 4 | @@ -71,25 +71,19 @@ - **Suggested name:** Keep `url` (TS convention), but acknowledge the JS-ecosystem split. - **Rationale:** The JS world is split here — Node, browsers, and the URL spec all use `URL` for the class and `url` for member fields. Internal consistency within this file is preserved (`url` everywhere); the rule is conventional, not broken. -### 10. `ExternalMetadata.owner` — `src/v1/model.ts:59` -- **Why weird:** Field `owner: string | undefined` with no hint of format. JSDoc says "Owner of the external metadata object" — owner is a Unity Catalog principal (user, group, or service principal). Common sister-package convention names this `owner` consistently, but a user has no idea what string format to put (`alice@example.com`? `users/alice`? a UUID?). Same problem applies to `createdBy` (line 65) and `updatedBy` (line 69). -- **Category:** 1 (vague), 19 (underspecified ID — what format is the principal?). -- **Suggested name:** Keep `owner` but document format. Or `ownerPrincipal`, matching other UC packages. -- **Rationale:** Bare `owner: string` is the canonical UC principal-as-string pattern across the SDK, but the type does not communicate format. Minor — sister-package convention is the same. Listed for visibility. - -### 11. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` +### 10. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` - **Why weird:** Bare `metastoreId: string | undefined` — a UUID identifier on a UC metastore, but the type does not hint at the format. Idiomatic across the SDK; here mentioned only for rule-19 completeness. Also note: this field is "Unique identifier of parent metastore" but `parent` is not named — the metastore relationship is communicated via the `metastoreId` field alone, not a `parent` field per AIP-160. - **Category:** 19 (underspecified ID — `string` doesn't tell you it's a UUID). - **Suggested name:** Keep `metastoreId` (canonical across SDK). - **Rationale:** SDK-wide pattern; field name is fine. Listed for completeness. -### 12. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` +### 11. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` - **Why weird:** Field name `updateMask` doesn't say what kind of mask. In context the mask describes "which fields to patch". The Google AIP-134 convention names this `updateMask`; the TS-idiomatic name would describe contents (`fieldsToUpdate`, `patchedFields`, `paths`). - **Category:** 1 (vague), 14 (Google-AIP-style name). - **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. - **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. -### 13. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` +### 12. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` - **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. - **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). - **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. @@ -97,55 +91,55 @@ ## Low severity -### 14. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` +### 13. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` - **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. - **Category:** 1 (vague — `Segment` of what?). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. - **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. -### 15. `Call` type and `call` variable — `src/v1/client.ts:85,115,141,183,245` +### 14. `Call` type and `call` variable — `src/v1/client.ts:85,115,141,183,245` - **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). - **Category:** 1 (vague), 12 (duplicate concept). - **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. - **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. -### 16. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:75-104, 110-129, etc.` +### 15. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:75-104, 110-129, etc.` - **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). - **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). - **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. -### 17. `pageReq` — `src/v1/client.ts:211` +### 16. `pageReq` — `src/v1/client.ts:211` - **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). - **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). - **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. -### 18. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` +### 17. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` - **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. - **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). - **Suggested name:** `requestBody: string | ReadableStream`. - **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. -### 19. `flattenQueryParams` — `src/v1/utils.ts:123` +### 18. `flattenQueryParams` — `src/v1/utils.ts:123` - **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. - **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). - **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. - **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. -### 20. `readAll(body)` — `src/v1/utils.ts:40` +### 19. `readAll(body)` — `src/v1/utils.ts:40` - **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". - **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). - **Suggested name:** `drainStream` or `readStreamToUint8Array`. - **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. -### 21. `HttpCallOptions` — `src/v1/utils.ts:15` +### 20. `HttpCallOptions` — `src/v1/utils.ts:15` - **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. - **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). - **Suggested name:** `HttpCallContext` or `HttpCallArgs`. - **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. -### 22. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` +### 21. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` - **Why weird:** The Zod schema constant carries the `V2` mid-position infix just like the type it parses (#6) and the client methods (#7). The directory is `v1/`, so `V2` here is wire-RPC-name leakage embedded inside a TS identifier that has no business advertising the upstream RPC version. Architectural leak — the generator copied the proto `ResponseV2` name straight through into the parser symbol. - **Category:** 14 (Go/proto-style name leak — wire `V2` infix on a TS identifier), 8 (redundant suffix — version is in the path), 20 (type-version suffix tautology between version-in-path and version-in-name). - **Suggested name:** `unmarshalListExternalMetadataResponseSchema` (drop `V2`). @@ -153,17 +147,17 @@ ## Observations -### 23. Identifier doubling for path + UUID +### 22. Identifier doubling for path + UUID The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5. -### 24. Action-verb conventions in `Client` +### 23. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. -### 25. Acronym casing +### 24. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 26. `externalmetadata` lowercase package name +### 25. `externalmetadata` lowercase package name The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). - **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index b89c39ee..ab78a16a 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -15,7 +15,7 @@ computes a feature on a schedule and writes results to an offline or online store). Feature transformations are a discriminated union over 13 aggregation functions and 3 data sources (Delta, Kafka, request-time), composed under three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 45 (0 fixed, 45 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 38 (0 fixed, 38 still present after rescan on 2026-05-26 post regen #156) --- @@ -28,46 +28,39 @@ three flavors of time window (continuous, tumbling, sliding). | 3 | `Feature` interface | model.ts:280 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | | 4 | `Client` | client.ts:65 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `FeaturesClient` or `FeatureEngineeringClient` would self-identify and disambiguate from `featurestore.Client` and `materializedfeatures.Client`. | | 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-635 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 636 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | -| 6 | `Function_FunctionType` (whole enum) — *deprecated per JSDoc* | model.ts:27-44 | enum | High | 12 Duplicate concepts | JSDoc says "Deprecated: Use the function-specific messages in AggregationFunction.function_type oneof instead." So this enum *and* the 13 sibling `*Function` interfaces (`AvgFunction`, `CountFunction`, etc.) coexist as parallel ways to express the same thing. Mark `@deprecated` in TS-side JSDoc; currently the import re-exports it without warning (index.ts:7). | -| 7 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 179, 758, 572, 566, 344, 467, 84, 92, 716, 727, 819, 825 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | -| 8 | `TimeWindow.windowType` field | model.ts:769 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | -| 9 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:288, 317, 319 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | -| 10 | `Feature.inputs` (deprecated `string[]`) vs `Feature.entities: EntityColumn[]` | model.ts:293, 317 | field pair | Medium | 12 Duplicate concepts | `inputs` is deprecated (JSDoc says use `AggregationFunction.inputs` — but that field doesn't exist either; see #33). It's a `string[]`, while the modern `entities` is `EntityColumn[]`. The two fields coexist on the same interface; the deprecation tag is not surfaced in TS JSDoc as `@deprecated`. | -| 11 | `Feature.filterCondition` (deprecated) vs `DeltaTableSource.filterCondition` vs `KafkaSource.filterCondition` | model.ts:307, 253, 463 | field set | Medium | 12 Duplicate concepts | Same field name on three types with the same meaning ("SQL WHERE clause"). The one on `Feature` is deprecated in favor of the per-source ones (per JSDoc). The other two are duplicates of each other across data-source flavors — fine. Just mark the deprecated copy `@deprecated`. | -| 12 | `Feature.timeWindow` (deprecated, top-level) vs `AggregationFunction.timeWindow` (canonical, nested) | model.ts:300, 80 | field pair | Medium | 12 Duplicate concepts | Two `timeWindow` fields at different positions in the same record. The Feature-level one is deprecated. JSDoc says so, no `@deprecated` tag. | -| 13 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:246, 317 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | -| 14 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:251, 319 | field pair | Medium | 12 Duplicate concepts | Same pattern as #13. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | -| 15 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:456, 317, 246 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | -| 16 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:461, 319, 251 | field set | High | 12 Duplicate concepts | Same as #15 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | -| 17 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 268, 777 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | -| 18 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | -| 19 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:376 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | -| 20 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:535 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts) — verbose. | -| 21 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:226, 236, 231 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | -| 22 | `KafkaConfig.bootstrapServers` | model.ts:424 | field | Low | (none) | Standard Kafka term. Fine. | -| 23 | `SubscriptionMode.$case === 'assign'` | model.ts:737 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | -| 24 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:750 | field | Low | (none) | Fine, matches Kafka SDK. | -| 25 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:623 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | -| 26 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:598, 604, 612 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | -| 27 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:562, 538 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | -| 28 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:315 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | -| 29 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | -| 30 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | -| 31 | `JobContext.jobId` JSDoc typo | model.ts:411 | field | Low | (none) | JSDoc reads "The job ID where this API invoked." (missing "was"). Pure typo; flag for completeness. | -| 32 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | -| 33 | `AggregationFunction.inputs` field referenced in JSDoc but not present | model.ts:290-293 | (missing) | High | 6 Misleading names | The JSDoc on `Feature.inputs` says "Deprecated: Use AggregationFunction.inputs instead." But `AggregationFunction` has no `inputs` field. The intended successor is per-function `input?` (singular, on each of `AvgFunction`, `SumFunction`, etc.). Doc is stale. | -| 34 | `Feature.entities` JSDoc references missing `Feature.entity` | model.ts:242-246 | (missing) | High | 6 Misleading names | `DeltaTableSource.entityColumns` JSDoc says "Use Feature.entity instead." The actual field is `Feature.entities` (plural). Stale or pluralized inconsistently. | -| 35 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | -| 36 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | -| 37 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 38 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | -| 39 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | -| 40 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely per #6). | -| 41 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #40. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | -| 42 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | -| 43 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | -| 44 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #42. | -| 45 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#40-44) clears this automatically. | +| 6 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 179, 758, 572, 566, 344, 467, 84, 92, 716, 727, 819, 825 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | +| 7 | `TimeWindow.windowType` field | model.ts:769 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | +| 8 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:288, 317, 319 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | +| 9 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:246, 317 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | +| 10 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:251, 319 | field pair | Medium | 12 Duplicate concepts | Same pattern as #9. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | +| 11 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:456, 317, 246 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | +| 12 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:461, 319, 251 | field set | High | 12 Duplicate concepts | Same as #11 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | +| 13 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 268, 777 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | +| 14 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 15 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:376 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | +| 16 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:535 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts) — verbose. | +| 17 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:226, 236, 231 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | +| 18 | `KafkaConfig.bootstrapServers` | model.ts:424 | field | Low | (none) | Standard Kafka term. Fine. | +| 19 | `SubscriptionMode.$case === 'assign'` | model.ts:737 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | +| 20 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:750 | field | Low | (none) | Fine, matches Kafka SDK. | +| 21 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:623 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | +| 22 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:598, 604, 612 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | +| 23 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:562, 538 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | +| 24 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:315 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | +| 25 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | +| 26 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | +| 27 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | +| 28 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | +| 29 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | +| 30 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 31 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 32 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 33 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | +| 34 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #33. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | +| 35 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | +| 36 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | +| 37 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #35. | +| 38 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#33-37) clears this automatically. | --- @@ -159,27 +152,7 @@ field, two with different field names (`variantExprPath` vs `name`). The simplest fix is one shared `ColumnRef { path: string }` plus a tag on the parent context (e.g., `entities: ColumnRef[]`, `timeseries: ColumnRef`). -### H6. Deprecated fields/types not marked with `@deprecated` - -The deprecation note ("Deprecated: Use the function-specific messages in -AggregationFunction.function_type oneof instead") lives in the JSDoc *text* -but neither the type, nor the field, nor the enum carries a `@deprecated` tag. -TS callers' IDEs will not flag use. The full list: - -- `Function.functionType` — model.ts:363 -- `Function.extraParameters` — model.ts:368 -- `Feature.inputs` — model.ts:293 -- `Feature.timeWindow` — model.ts:300 -- `Feature.filterCondition` — model.ts:307 -- `BackfillSource.$case === 'deltaTableSource'` — model.ts:130 -- `DeltaTableSource.entityColumns` — model.ts:246 -- `DeltaTableSource.timeseriesColumn` — model.ts:251 -- `KafkaSource.entityColumnIdentifiers` — model.ts:456 -- `KafkaSource.timeseriesColumnIdentifier` — model.ts:461 - -Ten deprecated fields with no `@deprecated` tag. Add the tag. - -### H7. `Feature.lineageContext` is internal but exposed as public +### H6. `Feature.lineageContext` is internal but exposed as public JSDoc explicitly says: "WARNING: This field is primarily intended for internal use by systems and is automatically populated... Users should not @@ -194,7 +167,7 @@ consumer constructing a `Feature` literal can fill in any value. Fix: mark `@internal` (or remove from public type and have the server inject it). -### H8. `isOnline` redundancy with `destination` +### H7. `isOnline` redundancy with `destination` `MaterializedFeature.isOnline` is `true` iff `destination.$case === 'onlineStoreConfig'`. Two booleans for one fact. A consumer who reads one and not the other can @@ -205,14 +178,14 @@ misinterpret the record's state. Either: create/update (it appears in the field-mask schema — model.ts:2510 — and the JSDoc doesn't say it's read-only). -### H9. Path-parameter IDs typed as `number` +### H8. Path-parameter IDs typed as `number` `LineageContext.notebookId` and `JobContext.jobId`, `JobContext.jobRunId` are typed as `number`. Databricks IDs are 64-bit. The other ID field on the same file (`MaterializedFeature.materializedFeatureId`) is `string`. Inconsistent within the file *and* potentially unsafe at the `2^53` boundary. -### H10. `Function` interface shadows the JS built-in +### H9. `Function` interface shadows the JS built-in `export interface Function` (model.ts:343) shadows the TypeScript global `Function` type (the constructor signature `Function`). Inside any module @@ -222,7 +195,7 @@ via `globalThis.Function`. Most ESLint configs (including this repo's, see Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. -### H11. Proto-architectural leak: `Outer_Inner` nested names +### H10. Proto-architectural leak: `Outer_Inner` nested names Four public identifiers carry the proto-nested `_` underscore convention straight from the `.proto` IDL into the TS public API: @@ -331,16 +304,7 @@ entity over a lifetime ContinuousWindow". The name gives no domain hint. `LatestColumnValue` would name the behavior. (Same critique as `Credential` in the credentials audit.) -### M6. JSDoc references stale field names - -- "Use Feature.entity instead" (model.ts:243) — actual field is `entities`. -- "Use Feature.entity instead" (model.ts:453) — same typo. -- "Use AggregationFunction.inputs instead" (model.ts:290) — field doesn't - exist; modern shape is per-function `input?`. -- "Use Function.aggregation_function.time_window" (model.ts:297) — references - snake_case wire name in TS-facing JSDoc. - -### M7. `executeCall` vs `executeHttpCall` +### M6. `executeCall` vs `executeHttpCall` Same as sibling packages. Two `execute*` verbs. @@ -384,23 +348,19 @@ constraint; not enforced. Same critique as `SlidingWindow.slideDuration` A `string` containing potentially many KB of source text. Naming is fine; the data shape is the design choice. Listing for completeness. -### L8. JSDoc typo on `JobContext.jobId` - -"The job ID where this API invoked." → "where this API was invoked." Minor. - -### L9. `SecretScopeReference { scope, key }` +### L8. `SecretScopeReference { scope, key }` Two-field reference to a Databricks secret. Standard. Fine. -### L10. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` +### L9. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` Four Spark Structured Streaming idioms. Standard. Fine. -### L11. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` +### L10. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` Three field-mask builders. Standard generator pattern. Fine. -### L12. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` +### L11. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` The list endpoint filters by feature name (full UC name). Field is `featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index 2875057a..2e73e727 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -171,34 +171,7 @@ divergence. --- -### 4. `OnlineStore.name` is the *unique identifier*, not a display name — category 19 (Underspecified IDs) — *Still* - -**Symbol:** `OnlineStore.name` (model.ts:84). JSDoc: "The name of the online -store. This is the unique identifier for the online store." - -**Issue:** Two distinct concepts are conflated in a field called `name`: - -- "Name" (human-readable label). -- "Unique identifier" (what URL paths key on). - -The Go SDK and the wire format choose `name` to mean *identifier*, but -neighbouring SDK fields (`OnlineStore.creator` — email; `OnlineTable.name` — -three-part identifier; `Feature.name` — composite "table.column") all use -`name` for *different* shapes. A reader cannot tell from the type whether -`name` is a UC three-part name, a single token, or a free-text label. - -This package: `OnlineStore.name` is a **single token** (the URL embeds it as -`/online-stores/{name}` per client.ts:102, 140, 242). That is fine — but -documenting "this is also the unique identifier" inside the JSDoc is a -naming smell: if the doc has to say "this is the ID", the field name should -be `id` or the JSDoc should at minimum link to the URL grammar. **Suggest** -strengthening JSDoc to specify the lexical grammar -(`/^[a-zA-Z][a-zA-Z0-9_-]*$/` or similar) so consumers don't pass -arbitrary strings. - ---- - -### 5. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) — *Still* +### 4. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) — *Still* **Symbol:** `OnlineStore.capacity?: string` (model.ts:92). JSDoc: "The capacity of the online store. Valid values are "CU_1", "CU_2", "CU_4", @@ -220,52 +193,9 @@ model an *open* enum with `'CU_1' | 'CU_2' | (string & {})` if needed. The current shape — bare `string` with a JSDoc note — provides no compile-time help. **Flag for SDK-wide policy on open enums** (categories 1 + 6). -Also: "CU" is unexplained (probably "Compute Unit"). Audit category 5 -(cryptic abbreviation) — see finding 6. - ---- - -### 6. `"CU_1"` is a cryptic literal — category 5 (Cryptic abbreviations) — *Still* - -**Symbol:** `OnlineStore.capacity` valid values `"CU_1"`–`"CU_8"` -(model.ts:91). - -**Issue:** `CU` is unexpanded in the file. Industry-wide it can mean -"Compute Unit", "Capacity Unit", or "Container Unit". The JSDoc should -either spell out the acronym or link to the public docs page that defines -it. Naming-side fix is at the wire level (rename to e.g. `compute-units-1`) -which is impractical; the practical fix is to expand the JSDoc. - -**Suggested JSDoc:** "The capacity of the online store (CU = Compute Unit). -Valid values: …". - ---- - -### 7. `OnlineStore.readReplicaCount` defaults documented in JSDoc only — category 6 (Misleading names) — *partial pass* — *Still* - -**Symbol:** `OnlineStore.readReplicaCount?: number` (model.ts:94). JSDoc: -"The number of read replicas for the online store. Defaults to 0." - -**Issue:** The field is optional with a documented server-side default of 0. -Optionality alone leaves the default unclear at the call site. This is not a -naming bug per se — flag JSDoc. - --- -### 8. `OnlineStore.usagePolicyId` underspecified — category 19 (Underspecified IDs) — *Still* - -**Symbol:** `OnlineStore.usagePolicyId?: string` (model.ts:96). - -**Issue:** `*Id` fields in the SDK refer to several different ID schemes -(UUID, ULID, account-scoped numeric, opaque tokens). The JSDoc says "The -usage policy applied to the online store to track billing." — it does not -specify the format. Cross-reference `budgetpolicy/v1` which defines such IDs -as UUIDs. **Suggest** JSDoc enrichment to say "Account-scoped UUID -referring to a usage policy defined in the budget-policy service." - ---- - -### 9. `PublishSpec` is vague — category 1 (Vague/generic) — *Still* +### 5. `PublishSpec` is vague — category 1 (Vague/generic) — *Still* **Symbol:** `PublishSpec` (model.ts:99). @@ -283,38 +213,14 @@ which has more room because it lives in the `featurestore` Go package. --- -### 10. `PublishTableRequest`/`Response.onlineTableName` underspecified — category 19 (Underspecified IDs) — *Still* - -**Symbols:** `PublishTableRequest.publishSpec.onlineTableName`, -`PublishTableResponse.onlineTableName` (model.ts:103, 117). - -**Issue:** The JSDoc on both reads "The full three-part (catalog, schema, -table) name of the online table." — same finding as #3: the field is a -specific structured string. Currently typed `string`. No compile-time -safety. Cross-SDK pattern is to leave as `string` with JSDoc — accept that -trade-off, but the JSDoc spelling should be canonical and consistent. The -field appears in *three* places (model.ts:59, 103, 117) with three slightly -different doc strings: - -- model.ts:58: "The full three-part (catalog, schema, table) name of the - online table." -- model.ts:102: "The full three-part (catalog, schema, table) name of the - online table." -- model.ts:116: "The full three-part (catalog, schema, table) name of the - online table." - -(Actually identical here — pass on consistency.) **Pass with note.** - ---- - -### 11. `PublishTableResponse.pipelineId` — *pass* — *Still* +### 6. `PublishTableResponse.pipelineId` — *pass* — *Still* Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. No issue. --- -### 12. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* — *Still* +### 7. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* — *Still* **Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` (model.ts:126). @@ -325,30 +231,7 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 13. `Client.publishTable` semantically publishes *features*, not a table — category 6 (Misleading names) and category 17 (Inconsistent action verbs) — *Still* - -**Symbol:** `Client.publishTable` (client.ts:212). JSDoc: "Publish features." - -**Issue:** The method name claims to publish a *table*, but the JSDoc says -"Publish features." The request body's content (`sourceTableName`, -`publishSpec.onlineTableName`) is *about* tables, but the API operation — -per the JSDoc — is "publish features." Naming-wise the method matches the -URL grammar (`/feature-store/tables/{sourceTableName}/publish`) and the Go -SDK method name, but the JSDoc is misleading. - -Actually re-reading: the operation **publishes a source table's data to an -online store as an online table**. So "publishTable" is roughly correct -("publish a table"), the JSDoc "Publish features." is a stale one-liner. -**Fix the JSDoc**, not the method name. - -**Suggested JSDoc:** "Publish a feature table to an online store, creating -an online table that syncs from the source." Alternative method name -candidate: `publishFeatureTable` — more descriptive, ports `publish` from -the URL — but diverges from Go. **Pass on the name, flag the JSDoc.** - ---- - -### 14. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) — *Still* +### 8. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) — *Still* **Symbols:** `Client.deleteOnlineTable` (client.ts:117, featurestore) vs. `Client.deleteOnlineTable` (client.ts:108, onlinetables). @@ -373,7 +256,7 @@ the *request types* are also identically named but field-incompatible. --- -### 15. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* — *Still* +### 9. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* — *Still* **Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and `onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the @@ -382,14 +265,14 @@ Google AIP-134 update-mask vocabulary. **Pass.** --- -### 16. `Client` class name — category 1 (Vague/generic) — *pass* — *Still* +### 10. `Client` class name — category 1 (Vague/generic) — *pass* — *Still* Package convention. Every TS package exports a single `Client` class scoped to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** --- -### 17. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) — *Still* +### 11. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) — *Still* **Symbol:** `PACKAGE_SEGMENT` (client.ts:41). @@ -405,7 +288,7 @@ do not fix in isolation.** --- -### 18. `userAgent` / `httpClient` / `host` / `logger` — *pass* — *Still* +### 12. `userAgent` / `httpClient` / `host` / `logger` — *pass* — *Still* Standard private field names. Acronym handling matches the project rule (`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported @@ -413,14 +296,14 @@ type `HttpClient`). **Pass.** --- -### 19. `readAll` — *pass* — *Still* +### 13. `readAll` — *pass* — *Still* Helper does what its name says (reads a `ReadableStream` to completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** --- -### 20. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* — *Still* +### 14. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* — *Still* Verb-prefix matches the function's role (constructs an `HttpRequest` object). Naming is fine. Note however the *file* mixes `build…`, @@ -429,7 +312,7 @@ seven functions. Not unique to this package. **Pass.** --- -### 21. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* +### 15. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -441,49 +324,21 @@ package qualifies. **Pass on package consistency.** --- -### 22. `Client.listOnlineStores` doc says "List Online Feature Stores" — category 6 (Misleading names) — *Still* - -**Symbol:** `Client.listOnlineStores` (client.ts:160). - -**Issue:** Method JSDoc reads "List Online Feature Stores." — the result -type is `ListOnlineStoresResponse` of `OnlineStore[]`, *not* -`OnlineFeatureStore[]`. The type is called `OnlineStore`, the method is -`listOnlineStores`, and only the JSDoc says "Feature Stores". Two -spellings of the same concept. The wire path is `/feature-store/online-stores`. -**Fix the JSDoc** to align with the type names. - -**Suggested JSDoc:** "List online stores." (matches type and method). - -Similar inconsistency at `createOnlineStore` ("Create an Online Feature -Store.", client.ts:71), `deleteOnlineStore` ("Delete an Online Feature -Store.", client.ts:97), `getOnlineStore` ("Get an Online Feature Store.", -client.ts:135), `updateOnlineStore` ("Update an Online Feature Store.", -client.ts:237). All five method docstrings call them "Online Feature -Stores" while every type and field calls them "Online Stores." - -This is a **package-wide doc-text drift**, not a code-naming bug, but -worth flagging: pick one — "online store" or "online feature store" — and -make it consistent. Recommended: keep the type as `OnlineStore` (concise) -and update JSDocs to drop "Feature" (already redundant since the package is -`@databricks/sdk-featurestore`). - ---- - -### 23. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* +### 16. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 24. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* — *Still* +### 17. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* — *Still* `pipelineId` correctly camelCases the two-letter "ID"; `creator` is a plain word. **Pass.** --- -### 25. `OnlineStore_State` — model.ts:9 — *Still* +### 18. `OnlineStore_State` — model.ts:9 — *Still* **Why:** `Parent_Nested` underscore-joined identifier is a literal translation of a proto nested-type path into the TS symbol name. The @@ -505,9 +360,9 @@ namespace. --- -### 26. `PublishSpec_PublishMode` — model.ts:27 — *Still* +### 19. `PublishSpec_PublishMode` — model.ts:27 — *Still* -**Why:** Same `Parent_Nested` proto-namespace leak as finding 25. The +**Why:** Same `Parent_Nested` proto-namespace leak as finding 18. The identifier reads as "PublishSpec's PublishMode" — the enclosing-type prefix is a verbatim port of the proto nested-type name, and the file acknowledges this with the same eslint-disable comment. @@ -544,7 +399,7 @@ Friction-heavy. **Strong recommendation:** rename `DeletePublishedOnlineTableRequest` (it deletes a table created by `publishTable`) — or rename `featurestore.deleteOnlineTable` method to `deletePublishedOnlineTable` and follow with the request type. Aligns with -finding 14. +finding 8. --- diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index f900c483..4b6fd0c1 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -4,14 +4,14 @@ **Versions audited:** v2 **Inferred domain:** File operations on Databricks storage. v2 is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 16 +**Total weird names flagged:** 15 ## Summary | Severity | Count | | --- | --- | | High | 6 | | Medium | 4 | -| Low | 4 | +| Low | 3 | | Observation | 2 | ## High severity @@ -180,21 +180,11 @@ overwrite?: boolean | undefined; Appears in `CreateRequest`, `PutRequest`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `CreateRequest` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. -### 12. `nextPageToken` is camelCase but `next_page_token` appears in JSDoc — `src/v2/model.ts:208,210,183,194,200` - -```ts -contents?: DirectoryEntry[] | undefined; -nextPageToken?: string | undefined; // OK -// JSDoc: "the `next_page_token` in the response..." (line 194) -``` - -JSDoc strings reference the wire name (`next_page_token`), but the TS field is `nextPageToken`. The doc accurately reflects the wire — flagged because cross-referencing a wire name in user-facing JSDoc is confusing. Should reference the TS field name (`nextPageToken`). - -### 13. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` +### 12. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. -### 14. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` +### 13. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` ```ts const PACKAGE_SEGMENT = { @@ -207,10 +197,10 @@ SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. Thi ## Observations -### 15. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` +### 14. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) -### 16. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` +### 15. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index 64ec5b08..eb2804ae 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -268,19 +268,6 @@ _None._ proto's `Foo.Bar`. The flat camel/Pascal form removes the IDL artifact and the eslint-disable. -#### F11.2 — "Public RPC" in JSDoc — `client.ts:112` -- **Why flagged:** The JSDoc `/** Public RPC to get forecasting - experiment */` exposes the server-side classification - (`Public` vs `Internal` RPC) and the transport term `RPC` to SDK - consumers. Users of an HTTP SDK do not need to know the call - is dispatched as a "public RPC" inside the backend. -- **Category:** Proto/RPC architectural leak (`Public` mid-position - classifier + `RPC` transport noun in user-facing doc). -- **Suggested:** Replace with a behavioural description, e.g. - `/** Gets a forecasting experiment by ID. */`. -- **Rationale:** Public-API JSDoc should describe what the method - does for the caller, not how the backend routes it. - --- ## Package overlap: `forecasting` vs `experiments` @@ -301,13 +288,6 @@ generic experiment but uses the same term and the same ID name. disambiguation. Or, namespace this package's types under `forecasting.Experiment` if the package adopts nested exports. -### F-OVERLAP.2 — `experimentId` naming collision (LOW) -- Same field name used in both APIs but the IDs are not - interchangeable. Users should not pass an MLflow experiment ID to - forecasting or vice versa. -- **Suggestion:** Document explicitly in JSDoc that the ID is the - forecasting/AutoML experiment ID, not an MLflow experiment ID. - --- ## Summary table @@ -324,8 +304,8 @@ generic experiment but uses the same term and the same ID name. | 8 | Generic field names | 1 | | 9 | Untyped string for closed enum | 1 | | 10 | `*Path` fields contradicting domain | 0 | -| 11 | Proto / architectural leaks | 2 | -| OVERLAP | forecasting vs experiments | 2 | +| 11 | Proto / architectural leaks | 1 | +| OVERLAP | forecasting vs experiments | 1 | --- diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index 1ccf6896..d7c241f9 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -3,7 +3,7 @@ **Package path:** `/home/parth.bansal/sdk-js/packages/functions/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog Functions (SQL / Python UDFs and UDTFs). -**Total weird names flagged:** 49 (0 fixed, 49 still present after rescan on 2026-05-26 post regen #156). +**Total weird names flagged:** 43 (0 fixed, 43 still present after rescan on 2026-05-26 post regen #156). --- @@ -94,12 +94,7 @@ TS rules. Field name `typeJson`. JSON is treated as `Json` per Google TS rules. Consistent. -#### 4.4 `typeText` field (model.ts:252) -Field name `typeText`. Doc says "Full data type spec, SQL/catalogString -text." OK as a name but ambiguous: is it SQL-formatted, JSON-formatted, -or arbitrary? - -#### 4.5 "UDF" / "UDTF" never appear in identifiers +#### 4.4 "UDF" / "UDTF" never appear in identifiers The package is *Unity Catalog Functions* — it covers both UDFs and UDTFs (table-valued functions). Neither acronym appears in any identifier or doc comment. The distinction is encoded in the @@ -111,20 +106,7 @@ flagging. ### 5. Misleading names -#### 5.1 `routineDependencies` doc comment lowercases "function" (model.ts:119, 228, 367) -JSDoc reads "function dependencies." (lowercase, mid-sentence). The -field name is `routineDependencies` and the doc says "function". The -package toggles between "routine" and "function" terminology -indiscriminately — a Go-port artifact of the SQL standard's vocabulary -(`CREATE PROCEDURE … LANGUAGE SQL ROUTINE_BODY …`). Doc inconsistency -worth flagging. - -#### 5.2 `DeleteFunctionRequest.force` doc has typo "notempty" (model.ts:153) -"Force deletion even if the function is notempty." Should be "not -empty". Doc bug, not a naming bug, but signals the field hasn't been -read recently. - -#### 5.3 `specificName` reserved-for-future-use (model.ts:104, 213, 352) +#### 5.1 `specificName` reserved-for-future-use (model.ts:104, 213, 352) Doc: "Specific name of the function; Reserved for future use." A field whose name promises specificity and whose docs admit it's unused is a future trap. Better to omit until it does something. @@ -266,16 +248,7 @@ outliers. No issues found. ### 13. Underspecified IDs -#### 13.1 `metastoreId` (model.ts:122, 231, 370) -Documented as "Unique identifier of parent metastore." Format -opaque (UUID? slug?). Acceptable but unspecified. - -#### 13.2 `functionId` (model.ts:134, 243, 382) -Doc: "Id of Function, relative to parent schema." Format unspecified -— is this a UUID, an autoincrement integer, an opaque token? Type is -`string` so opaque, but the docs should say so. - -#### 13.3 `metastoreId` & `functionId` — distinct domains, same shape +#### 13.1 `metastoreId` & `functionId` — distinct domains, same shape Both `string`, both undocumented for format, both server-assigned. A consumer cannot tell them apart from the types. @@ -321,12 +294,7 @@ shadows nothing, but the combination of the package name and the `Dependency.value.$case === 'function'` pattern creates a vocabulary where "function" is overloaded. -### F. `FunctionInfo.routineDependencies` is described as "function dependencies." -(model.ts:119, 228, 367) Comment text starts with lowercase and uses -"function" instead of "routine"; field name uses "routine". See -§5.1. - -### G. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` +### F. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` The most extreme case of a single-purpose API surface: a long enum type holding a one-letter variant, only ever set to `S`, marshaled as the JSON string `"S"`. Three layers of indirection for a constant. @@ -433,19 +401,18 @@ envelope visibly reflect proto oneof semantics. Already noted in | `FunctionInfo_SecurityType.DEFINER` | model.ts:59-61 | 2.2 | | `FunctionInfo_SqlDataAccess` | model.ts:64 | 4.1 | | `CreateFunction` | model.ts:76 | 7.1, 11.2 | -| `CreateFunction.specificName` | model.ts:104 | 5.3 | +| `CreateFunction.specificName` | model.ts:104 | 5.1 | | `CreateFunction.fullName` | model.ts:124 | 7.2, 11.4 | -| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:122-136 | 11.2, 13.1, 13.2 | +| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:122-136 | 11.2, 13.1 | | `DeleteFunctionRequest.fullNameArg` | model.ts:152 | 3.3, 9.2, 11.3 | -| `DeleteFunctionRequest.force` | model.ts:154 | 5.2 | | `Dependency.value.$case` | model.ts:165 | 9.3 | | `FunctionInfo` | model.ts:185 | 7.1 | -| `FunctionInfo.specificName` | model.ts:213 | 5.3 | +| `FunctionInfo.specificName` | model.ts:213 | 5.1 | | `FunctionInfo.properties` | model.ts:227 | 10.2 | | `FunctionInfo.fullName` | model.ts:233 | 7.2, 11.4 | -| `FunctionInfo.functionId` | model.ts:243 | 13.2, 13.3 | +| `FunctionInfo.functionId` | model.ts:243 | 13.1 | | `FunctionParameterInfo.name` | model.ts:250 | 10.1 | -| `FunctionParameterInfo.typeText / typeJson / typeName` | model.ts:252-256 | 4.3, 4.4 | +| `FunctionParameterInfo.typeJson` | model.ts:254 | 4.3 | | `GetFunctionRequest.fullNameArg` | model.ts:281 | 3.3, 9.2 | | `UpdateFunctionRequest` | model.ts:322 | 7.1, 7.4, 11.1, 11.2 | | `UpdateFunctionRequest.fullNameArg / name` | model.ts:324, 326 | 3.3, 7.4, 11.1 | diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index 214b2e7d..c5931f45 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -3,15 +3,15 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 37 +**Total weird names flagged:** 35 ## Summary | Severity | Count | | --- | --- | | High | 14 | | Medium | 9 | -| Low | 10 | -| Observation | 4 | +| Low | 9 | +| Observation | 3 | ## High severity @@ -205,13 +205,7 @@ - **Suggested name:** `ArrowStream` (in a Pascal-case enum). - **Rationale:** Low priority — enum-value style is widely-debated. -### 32. `GenieMessage.queryResult: Result | undefined` deprecated field — `src/v1/model.ts:1392` -- **Why weird:** Field is marked deprecated in JSDoc ("Use `query_result_metadata` in `GenieQueryAttachment` instead"). Still exported. Type is `Result` (the bare `Result` type — see #24). -- **Category:** 12 (duplicate concept — kept-for-compat), 1 (vague — `Result`). -- **Suggested name:** Mark with `/** @deprecated */` JSDoc (current text just says "Deprecated" — TS tooling won't strike-through). -- **Rationale:** Tooling support — modern TS understands `@deprecated`. - -### 33. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +### 32. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. @@ -219,20 +213,17 @@ ## Observations -### 34. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` +### 33. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` - **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. - **Suggested name:** N/A. - **Rationale:** Confirms the package's pagination naming is consistent. -### 35. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` +### 34. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` - **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. - **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. - **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. -### 36. Inconsistent `request field X required for polling is missing` error messages — `src/v1/client.ts:195,200,204,999,1008` -- **Observation:** All six error strings phrased identically, but `response field` vs `request field` distinction is correct. No naming bug; documentation only. - -### 37. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` +### 35. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` - **Observation:** `export interface MessageStatus {}` is an empty placeholder. The actual status enum is `MessageStatus_MessageStatus`. The empty type adds noise to the surface. - **Suggested name:** Remove the empty interface; refer to the enum directly. - **Rationale:** Empty interfaces in TS satisfy any object type and become bug magnets. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index 2c878a62..f7f00dad 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -13,7 +13,7 @@ creation and returns it everywhere else. Five operations: `create/get/list/update/delete`. No enums, no discriminated unions, no pagination, no list filtering beyond an optional `principalId` query parameter, no version negotiation. -**Total weird names flagged:** 15 (0 fixed, 15 still open) +**Total weird names flagged:** 12 (0 fixed, 12 still open) **Last rescan:** 2026-05-26 (post regen #156) --- @@ -31,12 +31,9 @@ parameter, no version negotiation. | 7 | `ListCredentialsRequest_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | | 8 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | | 9 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | -| 10 | `gitLabEnterpriseEdition` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. The TS-side will outlive the rename. | -| 11 | `bitbucketServer` wire value | model.ts:10, 75, 165 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Same problem as #10 — wire value is the legacy name. | -| 12 | `awsCodeCommit` wire value | model.ts:10-11, 75-76, 165-166 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Caller has no programmatic way to detect deprecation. | -| 13 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | -| 14 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 141, 175, 209, 107 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | -| 15 | `*Request_Response` underscore-nested response types (5 of them) | model.ts:43, 106, 116, 147, 192 | interface set | High | Proto-architectural-leak | All five response types use the proto-style `ParentRequest_Response` underscore-nested form: `CreateCredentialsRequest_Response`, `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. The underscore is a protobuf-nested-message encoding bleeding into the public TS API — the generator even acknowledges it with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` above every one. The matching zod schema constants (`unmarshalCreateCredentialsRequest_ResponseSchema`, etc.) inherit the same underscore. | +| 10 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | +| 11 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 141, 175, 209, 107 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 12 | `*Request_Response` underscore-nested response types (5 of them) | model.ts:43, 106, 116, 147, 192 | interface set | High | Proto-architectural-leak | All five response types use the proto-style `ParentRequest_Response` underscore-nested form: `CreateCredentialsRequest_Response`, `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. The underscore is a protobuf-nested-message encoding bleeding into the public TS API — the generator even acknowledges it with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` above every one. The matching zod schema constants (`unmarshalCreateCredentialsRequest_ResponseSchema`, etc.) inherit the same underscore. | --- @@ -86,7 +83,7 @@ await client.createCredential({gitProvider: 'gitHub', ...}); Recommendation: keep `listCredentials` (plural — list returns many) but rename the four single-resource methods and their request types to -singular. See #5, #6, #14. +singular. See #5, #6, #11. ### H3. Three field-for-field-identical "Credential" shapes @@ -205,13 +202,7 @@ URL `/credentials`), singular for resource ops (`getCredential`, ## Low severity (style polish) -### L1. `awsCodeCommit` is documented as deprecated but not tagged - -The JSDoc on `gitProvider` says "`awsCodeCommit` (deprecated by AWS, not -accepting new customers)". But the model has no `@deprecated` tag on -either the field's documentation or on a typed enum value (which doesn't -exist — see H4). Callers cannot programmatically detect deprecated values. -See #12. +_None._ --- @@ -237,8 +228,8 @@ them for awareness — fixing requires an API-server change. | Issue | This package | `credentials` audit | `oauthcustomappintegration` (typical) | |---|---|---|---| -| Bare `Client` class | Yes (#13) | Yes (#10) | Yes | -| Plural request envelopes on single-resource ops | Yes (#5, #6, #14) | No (uses `nameArg`/singular shapes) | Mixed | +| Bare `Client` class | Yes (#10) | Yes (#10) | Yes | +| Plural request envelopes on single-resource ops | Yes (#5, #6, #11) | No (uses `nameArg`/singular shapes) | Mixed | | `string`-typed enum-domain field | Yes (#8) | No (uses real enums) | Rare | The `string`-typed `gitProvider` despite a documented closed set (#8, H4) diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md index 6d5f2b1c..e61293a5 100644 --- a/.agent/naming-audit/iam.md +++ b/.agent/naming-audit/iam.md @@ -11,10 +11,10 @@ resolve-by-external-id flows that bridge the customer IdP to Databricks. | Severity | Count | | -------- | ----- | | High | 6 | -| Medium | 10 | -| Low | 10 | +| Medium | 5 | +| Low | 3 | | Observation | 3 | -| **Total** | **29** | +| **Total** | **17** | Three dominant themes remain. **First, the package still ships methods, requests, and a handful of variants in parallel `*` and `*Proxy` forms** that @@ -185,60 +185,7 @@ beyond Java-RPC habit. - **Rationale:** Two suffixes for the same routing-variant idea is the worst possible outcome. -### M3. `applicationId` on `ServicePrincipal` — third ID on the same type -- **File:** `model.ts:251-252` -- **Category:** 19 (underspecified ID) -- **Issue:** `ServicePrincipal` already has `accountId`, `internalId`, - `externalId`, and now `applicationId`. The doc says "Application ID of the - service principal." but does not say where this comes from (AAD app - registration? Databricks-issued?). It is a string and the doc gives no - format. -- **Suggestion:** Document the source: "Azure AD application ID (UUID) - identifying the service principal at the identity provider." Plus add a - format hint if not arbitrary string. -- **Rationale:** Four IDs on one struct is a lot; each one needs to be - obviously distinct in purpose. - -### M4. `Group.accountId` doc — "The parent account ID for group in " (missing article) -- **File:** `model.ts:131-132` -- **Category:** 6 (misleading via grammar) -- **Issue:** Doc reads "The parent account ID for group in " — - missing "the" before "group". Same pattern on `User.accountId` ("The - accountId parent of the user in .") and `ServicePrincipal.accountId` - ("The parent account ID for the service principal in ."). Three - siblings with three different phrasings of the same thing, two with grammar - issues. -- **Suggestion:** Standardize to "Databricks account ID of the parent - account." or just "Parent Databricks account ID." -- **Rationale:** Consistency + grammar; the `` template marker - also needs to go (see M5). - -### M5. `` proto template markup throughout JSDoc blocks -- **File:** `model.ts` everywhere, e.g. `25, 29, 31, 63, 73, 79, 89, 131, 133`; `client.ts:286, 287, 323` -- **Category:** 14 (Go/proto-style markup leak) -- **Issue:** The literal string `` appears 25+ times across the - JSDoc comments. It is upstream template syntax meant to be replaced by - the brand at doc-generation time; in TS it renders as stray angle brackets - in IDE hover popups and TypeDoc. Examples: - - "Required. Workspace assignment detail to be created in " - - "Internal service principal ID of the service principal in ." - - "Required. ID of the principal in ." -- **Suggestion:** Strip the template markup in the generator, leaving just - "Databricks". -- **Rationale:** Public docs leaking template syntax is the most visible - proto-leak across the SDK. - -### M6. `UpdateWorkspaceAssignmentDetailRequest` doc body says `TBD since the only updatable field is permissions` -- **File:** `model.ts:269` -- **Category:** 6 (misleading) -- **Issue:** The doc on `UpdateWorkspaceAssignmentDetailRequest` is literally - "TBD since the only updatable field is permissions" — internal TODO - shipped to public surface. Also factually wrong (entitlements, not - permissions, per the type). -- **Suggestion:** Replace with the real description. -- **Rationale:** Placeholder docs degrade developer trust. - -### M7. `resolveByExternalId` URL segment uses camelCase +### M3. `resolveByExternalId` URL segment uses camelCase - **File:** `client.ts:105, 134, 163, 198, 233, 262` - **Category:** 14, 3 (Go-style; casing) - **Issue:** The URL paths use `/resolveByExternalId` in camelCase. The URLs @@ -248,7 +195,7 @@ beyond Java-RPC habit. - **Suggestion:** Server-side fix (out of scope), but flag to the API team. - **Rationale:** Not the SDK's bug, but reflects an upstream inconsistency. -### M8. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields +### M4. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields - **File:** `model.ts:317, 329` - **Category:** 12, 6 (duplicate concepts; misleading) - **Issue:** `WorkspaceAccessDetail.permissions` (USER_PERMISSION / @@ -262,7 +209,7 @@ beyond Java-RPC habit. both JSDoc blocks. If they are the same, merge. - **Rationale:** This is the kind of overlap that produces support tickets. -### M9. `resolveByExternalId` method naming +### M5. `resolveByExternalId` method naming - **File:** `client.ts:101, 159, 229` - **Category:** 17 (verb inconsistency) - **Issue:** `resolveGroup`, `resolveUser`, `resolveServicePrincipal`. These @@ -275,42 +222,11 @@ beyond Java-RPC habit. semantic prominently. - **Rationale:** Method names should not hide write side-effects. -### M10. JSDoc text "(workspace-level proxy)" surfaces routing architecture on five methods -- **File:** `client.ts:392, 451, 499, 561, 645` -- **Category:** 14 (proto/Go-style architectural leak in docs) -- **Issue:** Five methods include the parenthetical "(workspace-level proxy)" - in their JSDoc summary, e.g. `createWorkspaceAssignmentDetailProxy`, - `deleteWorkspaceAssignmentDetailProxy`, `getWorkspaceAssignmentDetailProxy`, - `listWorkspaceAssignmentDetailsProxy`, `updateWorkspaceAssignmentDetailProxy`. - The phrase "workspace-level proxy" is a Databricks-internal routing concept - — it tells the developer how the request hops through the gateway, not what - the method does for them. In IDE hover popups and TypeDoc this is the - first thing a consumer reads. -- **Suggestion:** Replace with consumer-facing semantics, e.g. "Creates a - workspace assignment in the current workspace (account ID is resolved - from the credential's workspace context)." If H1 collapses the variants, - this finding disappears with them. -- **Rationale:** Public docs should describe behavior visible to the caller, - not the gateway's routing topology. - --- ## Low-severity findings -### L1. `accountId` field documented inconsistently across types -- **File:** `model.ts:69, 85, 103, 121, 131, 151, 182, 207, 232, 245, 271, 285` -- **Category:** Observation, 6 (misleading) -- **Issue:** Multiple different phrasings of the same `accountId` field's JSDoc: - - "Required. The account ID for which the workspace assignment detail is being created." - - "Required. The parent account ID for which the workspace access details are being requested." - - "The parent account ID for group in ." - - "The accountId parent of the user in ." -- **Suggestion:** One canonical phrasing for the request-level field - ("Databricks account ID. Falls back to ClientOptions.accountId if omitted.") - and one for the resource-level field ("Parent Databricks account ID."). -- **Rationale:** Same field, many different doc strings. - -### L2. `principalId` is `number` (Databricks internal) but `accountId` is `string` (UUID) — type-inconsistency for IDs +### L1. `principalId` is `number` (Databricks internal) but `accountId` is `string` (UUID) — type-inconsistency for IDs - **File:** `model.ts:70, 80, 90, 96, 104, 108, 122, 126, 132, 134, 152, 246, 248, 286, 288, 307, 311, 323, 327` - **Category:** 19 (underspecified ID) - **Issue:** Databricks-internal IDs are `number`, account IDs are `string` @@ -321,7 +237,7 @@ beyond Java-RPC habit. - **Rationale:** Type-system disambiguation; out-of-scope for a 1:1 port but worth noting for any future hardening. -### L3. `ResolveGroupRequest` vs `ResolveGroupProxyRequest` symmetry +### L2. `ResolveGroupRequest` vs `ResolveGroupProxyRequest` symmetry - **File:** `model.ts:172-186` - **Category:** Observation - **Issue:** `ResolveGroupRequest` carries `accountId` + `externalId`, but @@ -331,36 +247,7 @@ beyond Java-RPC habit. - **Suggestion:** Collapse per H1. - **Rationale:** Pattern, not a new finding. -### L4. `Group.externalId` field name vs `Group.accountId` field name — neither match wire snake_case nor the legacy SCIM camelCase -- **File:** `model.ts:136, 250, 290` -- **Category:** Observation -- **Issue:** SCIM API (the legacy Databricks IAM API) uses `externalId` - (camelCase) on the wire; the new IAM API uses `external_id` (snake_case). - This SDK uses `externalId` in TS and `external_id` on the wire. The - pattern is correct and consistent — flagging only because anyone migrating - from SCIM may be confused. -- **Suggestion:** None; documentation for migrators if not already present. -- **Rationale:** Migration-friendly note. - -### L5. `pageSize` JSDoc could document the default -- **File:** `model.ts:143, 155` -- **Category:** 6, Observation (misleading) -- **Issue:** `pageSize` docstrings do not specify the default ("If not - provided, defaults to N"). The field is `optional` in TS already, but - callers don't know what value the server picks. -- **Suggestion:** Document the default if known. -- **Rationale:** Trivial cleanup. - -### L6. `User.username` doc — "Username/email of the user" -- **File:** `model.ts:291` -- **Category:** 6 (misleading) -- **Issue:** Doc says "Username/email" — which is it? Slashes in JSDoc - signal ambiguity. -- **Suggestion:** Be specific: "Email address used as the user's login - identifier." -- **Rationale:** Surface the format. - -### L7. `Group.groupName` doc — "Display name of the group" +### L3. `Group.groupName` doc — "Display name of the group" - **File:** `model.ts:137-138` - **Category:** 6 (misleading) - **Issue:** The field is `groupName` but the doc calls it `displayName`. @@ -370,37 +257,6 @@ beyond Java-RPC habit. say "Group name displayed in the UI". - **Rationale:** Consistency between the doc and the field name. -### L8. `ServicePrincipal` JSDoc — "The details of a ServicePrincipal resource." -- **File:** `model.ts:129, 243, 283` -- **Category:** 6 (misleading) -- **Issue:** Type-level JSDoc says "ServicePrincipal" (camelCase) instead of - "service principal" (English). Same on `Group` ("The details of a Group - resource.") and `User` ("The details of a User resource."). Three - identical placeholder docs. -- **Suggestion:** Replace with prose. -- **Rationale:** Type-level docs should be in English. - -### L9. `applicationId` doc could disclose source -- **File:** `model.ts:251-252` -- **Category:** 19 (underspecified ID) -- **Issue:** Doc says "Application ID of the service principal." with no - format hint (UUID? AAD app ID? Databricks-internal?). -- **Suggestion:** "Application ID of the service principal at the customer's - identity provider (typically the Azure AD app registration UUID)." -- **Rationale:** Surface the format. - -### L10. `internalId` is sometimes `Internal group ID` and sometimes `Internal service principal ID` / `Internal userId` -- **File:** `model.ts:133, 247, 287` -- **Category:** 6, Observation (misleading; documentation rot) -- **Issue:** `internalId` is documented three different ways across types: - "Internal group ID of the group in .", "Internal service - principal ID of the service principal in .", "Internal userId - of the user in ." (typo on the last — `userId` should be two - words). The self-referential ("group ID of the group") phrasing is also - awkward. -- **Suggestion:** Standardize to "Databricks-internal numeric ID of the X." -- **Rationale:** Documentation consistency. - --- ## Observations (not findings, but worth noting) @@ -432,14 +288,12 @@ beyond Java-RPC habit. ## Cross-cutting recommendations (priority order) -1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L3, O2, O3).** This +1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L2, O2, O3).** This is the largest single improvement and ~halves the public type surface. -2. **Replace `` template markup (M5).** Generator-side fix. -3. **Standardize ID field doc strings (L1, L10) and the `State` enum name (H3).** +2. **Standardize the `State` enum name (H3).** One name per concept. -4. **Remove type-suffix tautology on the `PrincipalType` enum (H6).** Drop +3. **Remove type-suffix tautology on the `PrincipalType` enum (H6).** Drop the type suffix from the enum name. -5. **Drop the `Detail` suffix from the Workspace* types (H4).** -6. **Rewrite the placeholder JSDocs (M6).** Generator + spec fix. +4. **Drop the `Detail` suffix from the Workspace* types (H4).** --- diff --git a/.agent/naming-audit/indexes.md b/.agent/naming-audit/indexes.md deleted file mode 100644 index c1d3a72e..00000000 --- a/.agent/naming-audit/indexes.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: indexes - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index efcbf102..095d081a 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -22,10 +22,10 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | | High | 8 | -| Medium | 2 | -| Low | 12 | -| Observation | 7 | -| **Total** | **29**| +| Medium | 1 | +| Low | 8 | +| Observation | 5 | +| **Total** | **22**| ### Top themes @@ -128,12 +128,10 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | C-01 | `DockerImage.credsOneof` | High (also V-01) | `creds` and `Oneof` are both opaque outside Go/proto context. | -| C-02 | `BYOC` in JSDoc `"Custom Docker Image BYOC"` (`model.ts:141, 323, 445, 574`) | Medium | "Bring Your Own Container" not expanded. External readers will not know. | -| C-03 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | -| C-04 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | -| C-05 | `req`, `resp`, `httpReq`, `respBody` locals in `client.ts` | Low | Method-local; OK. | -| C-06 | `opts` (`utils.ts:66`) | Low | Inside function scope; OK. | -| C-07 | `Mb/s` in JSDoc `"configurable throughput (in Mb/s)"` (`model.ts:161, 343, 465, 594`) | Low | Likely intended `MB/s` (megabytes per second) given the cloud-disk-throughput context; `Mb/s` (megabits) is unusual for disk throughput. Possible casing typo upstream. | +| C-02 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | +| C-03 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | +| C-04 | `req`, `resp`, `httpReq`, `respBody` locals in `client.ts` | Low | Method-local; OK. | +| C-05 | `opts` (`utils.ts:66`) | Low | Inside function scope; OK. | ### 2.4 Misleading names — High @@ -142,10 +140,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | M-01 | `editInstancePool()` / `EditInstancePoolRequest` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | | M-02 | `InstancePoolStatus` | High | The type carries *only* `pendingInstanceErrors`. The name promises a general "status" but the shape exposes only errors. `InstancePoolPendingErrors` or `InstancePoolFailures` would be more truthful. (`InstancePoolState` is the actual lifecycle state, on the entity itself.) | | M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 28 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | -| M-04 | `DiskSpec.diskIops` (no JSDoc) and `diskSpec.diskThroughput` (no JSDoc) — `model.ts:239-240` | Low | Two fields with no JSDoc. Hard to know the unit without context. (Compare neighbouring `diskSize` which documents "GiB".) | -| M-05 | `preloadedDockerImages` is plural but JSDoc says "Custom Docker Image BYOC" (singular) — `model.ts:141, 323, 445, 574` | Low | Field is `DockerImage[]`. Plural correctly matches type, but the JSDoc is misleading. | -| M-06 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | -| M-07 | `InstancePoolStats.usedCount` / `idleCount` / `pendingUsedCount` / `pendingIdleCount` | Low | Adequate, but `usedCount` is ambiguous about what "used" means. JSDoc clarifies ("part of a cluster") — without it, readers might think "used = ever used". | +| M-04 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | ### 2.5 Overly verbose / Redundant suffixes — Low @@ -157,7 +152,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| P-01 | `preloadedSparkVersions: string[]` | High (also M-06) | Plural array type but the JSDoc constrains it to at most one element. | +| P-01 | `preloadedSparkVersions: string[]` | High (also M-04) | Plural array type but the JSDoc constrains it to at most one element. | | P-02 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | | P-03 | `ListInstancePoolsRequest` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | | P-04 | `ListInstancePoolsRequest_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | @@ -250,11 +245,9 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | JSDoc placeholder `` appears many times in this file (e.g., `" will tag all pool resources"` `model.ts:117`) | Observation | Un-substituted template placeholder leaking into the generated TS docstrings. Reader sees `` in IntelliSense. Same finding as `clusters.md` #92. | -| X-02 | `enableElasticDisk` JSDoc: "Autoscaling Local Storage: when enabled, **this instances** in this pool ..." (`model.ts:133, 315, 437, 566`) | Observation | Grammar typo in JSDoc ("this instances" → "the instances"). Same string repeated four times. | -| X-03 | `client.ts:167-170` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | -| X-04 | `client.ts:197` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | -| X-05 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | +| X-01 | `client.ts:167-170` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | +| X-02 | `client.ts:197` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | +| X-03 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | ### 2.18 Proto-architectural leaks @@ -399,10 +392,10 @@ artefact and the leading underscore at the same time. | Severity | Count | | ------------ | ----- | | High | 8 | -| Medium | 2 | -| Low | 12 | -| Observation | 7 | -| **Total** | **29**| +| Medium | 1 | +| Low | 8 | +| Observation | 5 | +| **Total** | **22**| ## 4. Cross-package consistency notes diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index 4971e5dc..321d993f 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -8,11 +8,11 @@ the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------ | -| High | 26 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | -| Medium | 50 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | -| Low | 25 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 14 | Patterns spanning the entire file (oneof wrappers, ID typing, etc.). | -| **Total** | **115** | | +| High | 24 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | +| Medium | 41 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | +| Low | 21 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| Observations | 11 | Patterns spanning the entire file (oneof wrappers, ID typing, etc.). | +| **Total** | **97** | | Issues are catalogued below by severity, then by file/line. @@ -86,98 +86,85 @@ Issues are catalogued below by severity, then by file/line. - **Suggestion:** Same as H10 — remove or rename to `runIdAlias`. - **Rationale:** Same dead duplication on the response. -### H12. `Format` enum value `SINGLE_TASK` is semantically dead -- **Location:** `model.ts:151-154`. -- **Category:** Misleading names (#6). -- **Suggestion:** Mark `SINGLE_TASK` with `@deprecated` (the JSDoc on `CreateJobRequest.format` says it's always `MULTI_TASK`). -- **Rationale:** Exposing a value the server will never return is a footgun. - -### H13. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition +### H12. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition - **Location:** `model.ts:282`. - **Category:** Misleading names (#6). - **Suggestion:** Document inline, or rename to `NO_FAILURES_AT_LEAST_ONE_RAN`. Alternatively, `AT_LEAST_ONE_SUCCESS_NONE_FAILED`. - **Rationale:** The enum-level JSDoc clarifies "none failed AND at least one was executed" — this is non-obvious from the name. -### H14. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion +### H13. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion - **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2556`, `model.ts:2564`. - **Category:** Singular/plural mismatch (#9), redundant suffixes (#8). - **Suggestion:** `JobsHealthRule` and `JobsHealthRules` differ only by `s` and the inner wraps a `rules?: JobsHealthRule[]`. Flatten — make the array the public shape (call it `HealthRules` or just `HealthRule[]`). - **Rationale:** Hairsplitting wrappers around arrays force consumers to write `{rules: [...]}` instead of `[...]`. Plural type names alongside singular ones are the most error-prone pattern in this file. -### H15. `JobsHealth*` prefix is inconsistent — `Jobs` is plural +### H14. `JobsHealth*` prefix is inconsistent — `Jobs` is plural - **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2556`, `model.ts:2564`. - **Category:** Singular/plural mismatch (#9), Go/Java-style names (#14). - **Suggestion:** Use the singular product noun: `JobHealthMetric`, `JobHealthRule`. Or just `HealthMetric` if global. - **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). -### H16. `RunNowRequest_Response.runId` field is the "newly triggered run" — confusingly typed `number` +### H15. `RunNowRequest_Response.runId` field is the "newly triggered run" — confusingly typed `number` - **Location:** `model.ts:3742`. - **Category:** Underspecified IDs (#19). - **Suggestion:** Add a branded type alias `RunId = number & {readonly __brand: 'RunId'}` or use `string` to match `bigint`-safe APIs. - **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId` (string!). -### H17. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` +### H16. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` - **Location:** `model.ts:1605`, `model.ts:1637`. - **Category:** Field contradicting type domain (#16), misleading names (#6). - **Suggestion:** Standardize on `string` for upstream IDs; note in JSDoc. - **Rationale:** Same semantic field encoded as two different TS types in adjacent interfaces is a bug magnet. -### H18. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous +### H17. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous - **Location:** `model.ts:3500`. - **Category:** Misleading names (#6). - **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3976). - **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? -### H19. `BaseJob` and `GetJobRequest_Response` and `Run` duplicate ~10 identical fields +### H18. `BaseJob` and `GetJobRequest_Response` and `Run` duplicate ~10 identical fields - **Location:** `model.ts:874`, `model.ts:1973`, `model.ts:3399`, `model.ts:908`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Extract a shared `JobIdentity` / `JobCoreFields` interface or use TS `Pick`/`Omit` on a base shape. - **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId` are repeated verbatim in `BaseJob` and `GetJobRequest_Response`. Diverges silently. -### H20. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums +### H19. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums - **Location:** `model.ts:3852`, `model.ts:3866`. - **Category:** Duplicate concepts (#12), versioned API leakage (#11). - **Suggestion:** Pick `RunStatus` as the canonical shape, deprecate `RunState`, and document the deprecation in the rule. - **Rationale:** The JSDoc on `Run.state` already says "Deprecated. Please use the `status` field instead." but the type is still exported and still shows up in the union. -### H21. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) +### H20. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) - **Location:** `model.ts:390`, `model.ts:478`, `model.ts:542`, `model.ts:662`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Normalize to one form. The `MAX_` form is more common; reach-vs-exceed should pick one verb. - **Rationale:** Three enums describe the same overflow scenario with three different names. Consumers cannot write a generic handler. -### H22. `client.exportRun` returns `ExportRunRequest_Response` which contains a `views` array of `ViewItem` +### H21. `client.exportRun` returns `ExportRunRequest_Response` which contains a `views` array of `ViewItem` - **Location:** `client.ts:449`, `model.ts:1830`, `model.ts:4920`. - **Category:** Vague/generic (#1). - **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. - **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. -### H23. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint +### H22. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint - **Location:** `model.ts:327`, `model.ts:337`. - **Category:** Duplicate concepts (#12). - **Suggestion:** Merge or namespace: `View.Type` (NOTEBOOK | DASHBOARD) and `View.ExportSelector` (CODE | DASHBOARDS | ALL). - **Rationale:** Two enums about "views" with different value sets and intent. Users will pick the wrong one. -### H24. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` +### H23. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` - **Location:** `client.ts:971-1048`. - **Category:** Versioned API leakage. - **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. - **Rationale:** Future deprecation of V1 will silently break all four waiters. -### H25. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers +### H24. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers - **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3615` (`RunLifecycleStateV2` wrapper interface), `model.ts:3867` (`RunStatus.state: RunLifecycleStateV2_State`). - **Why:** `V2` mid-token in a type name records that the upstream schema versioned this enum, not anything a JS consumer needs. The V1 type already lives at `RunLifeCycleState` / `RunLifeCycleState_RunLifeCycleState`; the V2 variant should adopt a domain-meaningful name rather than a version-stamped one. - **Category:** Proto-architectural-leak (`V2` mid-position). - **Suggested:** Rename the wrapper to `RunLifecycleState` (singular, modern) and the enum to `RunLifecycleState_State` — then mark the legacy `RunLifeCycleState` family `@deprecated`. If the V1 type must keep its current name for back-compat, rename the V2 family to `RunPhase` or `RunLifecycleStatus` (anything that says "this is the new shape" without encoding the version number). - **Rationale:** `V2` as part of a type name is the textbook proto-architectural leak this audit category targets; it bakes upstream-version churn into every consumer's import list. The casing difference (`LifeCycle` vs `Lifecycle`) between V1 and V2 names also makes the pair harder to grep. -### H26. `ProjectCheckoutInternalRepo` RPC name leaked into public JSDoc on `TerminationCode_Code` -- **Location:** `model.ts:619` (comment on `REPOSITORY_CHECKOUT_FAILED`). -- **Why:** The JSDoc reads "Returned if [[ProjectCheckoutInternalRepo]] RPC fails" — `ProjectCheckoutInternalRepo` is an internal service RPC, and the `Internal` token plus `RPC` mention exposes a backend implementation detail to public API consumers. -- **Category:** Proto-architectural-leak (`Internal` infix, `RPC` reference in public doc). -- **Suggested:** Rewrite the JSDoc to describe the user-visible failure ("Returned if checking out the project's source repository failed") without naming the internal RPC. -- **Rationale:** Internal service/RPC names should not surface in JSDoc; they leak the server topology and become stale references when the backend reorganizes. - --- ## Medium @@ -260,154 +247,110 @@ Issues are catalogued below by severity, then by file/line. - **Category:** Long enum values (#18). - **Suggestion:** Acceptable; consider grouping into a nested enum if the four become five. -### M15. `WaitAfterLastChangeSeconds` — appears identically in three triggers -- **Location:** `model.ts:1846`, `model.ts:2833`, `model.ts:4658`. -- **Category:** Verbose, repetitive (#7). -- **Suggestion:** OK, document once. - -### M16. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) +### M15. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) - **Location:** `model.ts:1041`, `model.ts:1026`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Pick one. `CleanRoom*` (singular) is consistent with the standalone product "Clean Rooms" being treated as a singular feature. -### M17. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL +### M16. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL - **Location:** `model.ts:1043`. - **Category:** Acronym casing (#3). - **Suggestion:** Acceptable; brand inconsistency is upstream's responsibility. -### M18. `DbtCloudJobRunStep` (deprecated) and `DbtPlatformJobRunStep` (new) -- **Location:** `model.ts:1583`, `model.ts:1613`. -- **Category:** Versioned API leakage. -- **Suggestion:** OK while transition is documented; reconsider after dbt Cloud is dropped. - -### M19. `SparkJarTask.jarUri` (deprecated) — already deprecated -- **Location:** `model.ts:4311`. -- **Category:** OK as docstring; ensure `@deprecated` JSDoc tag added. - -### M20. `SparkJarTask.runAsRepl` — deprecated; values restricted -- **Location:** `model.ts:4325`. -- **Category:** Vague/misleading (#6). -- **Suggestion:** `@deprecated`. Comment says "A value of `false` is no longer supported." - -### M21. `Repair.type` (RepairType) is a reserved-ish word +### M17. `Repair.type` (RepairType) is a reserved-ish word - **Location:** `model.ts:3084`, `model.ts:4926`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. -### M22. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK +### M18. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK - **Location:** `model.ts:3634`, `model.ts:4570`. - **Category:** Verbose but precise. -### M23. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern +### M19. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern - **Location:** `model.ts:3111-3117`. - **Category:** Consistent prefix; OK. -### M24. `RepairRunRequest.latestRepairId` vs `RepairRunRequest_Response.repairId` (no `latest`) -- **Location:** `model.ts:3109`, `model.ts:3221`. -- **Category:** Inconsistent naming (#17). -- **Suggestion:** Document the semantic: request takes "the previous latest", response returns "the new latest". - -### M25. `DockerImage.credsOneof` — exposes proto oneof name to TS +### M20. `DockerImage.credsOneof` — exposes proto oneof name to TS - **Location:** `model.ts:1715`. - **Category:** Go/Java-style names (#14). - **Suggestion:** Rename to `credentials` or `auth`. -### M26. `JobRunAs.identity` — OK +### M21. `JobRunAs.identity` — OK - **Location:** `model.ts:2398`. -### M27. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix +### M22. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix - **Location:** `model.ts:2340`. - **Category:** Acceptable; key is the lookup pattern. -### M28. `JobEnvironment.environmentKey` — same pattern, OK. +### M23. `JobEnvironment.environmentKey` — same pattern, OK. - **Location:** `model.ts:2381`. -### M29. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy +### M24. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy - **Location:** `model.ts:4682`, `model.ts:3902`, `model.ts:4091`, `model.ts:4671`. - **Category:** Verbose but precise. -### M30. `ResolvedValues` interface has 11 single-purpose sub-types +### M25. `ResolvedValues` interface has 11 single-purpose sub-types - **Location:** `model.ts:3247-3397`. - **Category:** Verbose; many shapes for one purpose. - **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. -### M31. `BaseRun.numberInJob` — meaningless field (see H10) +### M26. `BaseRun.numberInJob` — meaningless field (see H10) - **Location:** `model.ts:916`. -### M32. `BaseRun.originalAttemptRunId` — verbose, but precise. +### M27. `BaseRun.originalAttemptRunId` — verbose, but precise. -### M33. `Run.runId` (inside `Run`) — tautological +### M28. `Run.runId` (inside `Run`) — tautological - **Location:** `model.ts:3403`, `model.ts:912`, `model.ts:2140`, `model.ts:3877`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. -### M34. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRunRequest_Response` — could be deduped +### M29. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRunRequest_Response` — could be deduped - **Location:** `model.ts:942`, `model.ts:3433`, `model.ts:2170`. -### M35. `RunNowRequest_Response.numberInJob` (see H11). +### M30. `RunNowRequest_Response.numberInJob` (see H11). -### M36. `ListJobsRequest.limit` vs `ListRunsRequest.limit` documentation discrepancy -- **Location:** `model.ts:2692`, `model.ts:2751`. -- **Category:** Inconsistent docs (not naming, but worth flagging). -- **Suggestion:** Document max values explicitly; `ListJobsRequest` says ≤100, `ListRunsRequest` says <25. - -### M37. `ListJobsRequest.offset` deprecated by `pageToken` — but both still typed -- **Location:** `model.ts:2690`. -- **Category:** Deprecation hygiene. -- **Suggestion:** Add `@deprecated` JSDoc to `offset`. - -### M38. `Adlsgen2Info` field `destination` — vague (could be `path`, `url`) -- **Location:** `model.ts:708`, similar in `DbfsStorageInfo`, `S3StorageInfo`, `GcsStorageInfo`, `LocalFileInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. -- **Category:** Generic field names (#15). -- **Suggestion:** Each storage type has different URI semantics; `destination` is fine since it's polymorphic, but document the form. - -### M39. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type +### M31. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type - **Location:** `model.ts:257`. - **Category:** Type design. - **Suggestion:** Could be `type CodeSource = 'WORKSPACE' | 'GIT'`. Same for `Format`, `ViewType`, etc. -### M40. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead +### M32. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead - **Location:** `model.ts:151-154`. - **Category:** Dead enum value. -### M41. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` +### M33. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` - **Location:** `model.ts:355`. - **Category:** Generic enum value (#1). - **Suggestion:** `UNKNOWN` is universally vague; consider `NOT_EVALUATED`. -### M42. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) +### M34. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) - **Location:** `model.ts:570`, `model.ts:541`, `model.ts:137`. - **Category:** Inconsistent naming (#17). - **Suggestion:** Pick one spelling; "canceled" (single-L) is the American spelling, "cancelled" is the British. Cross-checking with go SDK keeps wire compat. -### M43. `TerminationCode_Code.USER_CANCELED` vs `TerminationCode_Code.CANCELED` (no `USER_`) -- **Location:** `model.ts:670`, `model.ts:611`. -- **Category:** Overlapping enum values (#12). -- **Suggestion:** Document distinction (one is user-initiated, the other is platform-initiated). - -### M44. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +### M35. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized - **Location:** `model.ts:4967`, `model.ts:4971`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Rename to `ClientTypes`. -### M45. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) +### M36. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) - **Location:** `model.ts:3075`. - **Category:** Acronym casing (#3). - **Suggestion:** Cran is an acronym (CRAN = Comprehensive R Archive Network). `RLibrary` works too. The `R` prefix is from the Go SDK. -### M46. `PythonPyPiLibrary` — duplicate "Py" prefix +### M37. `PythonPyPiLibrary` — duplicate "Py" prefix - **Location:** `model.ts:3026`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). -### M47. `MavenLibrary.coordinates` — common, accept. +### M38. `MavenLibrary.coordinates` — common, accept. - **Location:** `model.ts:2797`. -### M48. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. +### M39. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. -### M49. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. +### M40. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. -### M50. `ListRunsRequest.runType` shouldn't be optional when the API permits a default +### M41. `ListRunsRequest.runType` shouldn't be optional when the API permits a default - **Location:** `model.ts:2753`. - **Category:** Default semantics. @@ -416,7 +359,7 @@ Issues are catalogued below by severity, then by file/line. ## Low ### L1. `Adlsgen2Info` — see M1. -### L2. `WorkloadType_ClientsTypes` — see M44. +### L2. `WorkloadType_ClientsTypes` — see M35. ### L3. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). @@ -429,51 +372,40 @@ Issues are catalogued below by severity, then by file/line. ### L7. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. -### L8. `JobEmailNotifications.noAlertForSkippedRuns` (deprecated) — `@deprecated` recommended. - -### L9. `WebhookNotifications.onStreamingBacklogExceeded` — accept. +### L8. `WebhookNotifications.onStreamingBacklogExceeded` — accept. -### L10. `ContinuousSettings.taskRetryMode` (enum) — OK. +### L9. `ContinuousSettings.taskRetryMode` (enum) — OK. -### L11. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. +### L10. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. -### L12. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. +### L11. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. -### L13. `CronSchedule.quartzCronExpression` — long but precise. +### L12. `CronSchedule.quartzCronExpression` — long but precise. -### L14. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. +### L13. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. -### L15. `JobDeployment.metadataFilePath` +### L14. `JobDeployment.metadataFilePath` - **Location:** `model.ts:2354`. - **Category:** Verbose. -### L16. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. +### L15. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. - **Location:** `model.ts:3477-3479`. - **Category:** Field contradicting type domain (#16). - **Suggestion:** Move to `RunTask` only, mark deprecated on `Run`. -### L17. `RepairRunRequest.dbtCommands` — present on `RunNowRequest`, `RunJobTask`, `RepairRunRequest`, `RunParameters`. +### L16. `RepairRunRequest.dbtCommands` — present on `RunNowRequest`, `RunJobTask`, `RepairRunRequest`, `RunParameters`. - **Location:** `model.ts:3190`, `model.ts:3570`, `model.ts:3711`, `model.ts:3821`. - **Category:** Repeated identical fields — argues for shared `RunOverrideParameters` base. -### L18. `SparkPythonTask.parameters` (string[]) — OK. - -### L19. `SparkJarTask.runAsRepl` (deprecated) — see M20. +### L17. `SparkPythonTask.parameters` (string[]) — OK. -### L20. `Library.egg` (deprecated) — see top JSDoc. -- **Location:** `model.ts:2582`. +### L18. `Library.cran: RCranLibrary` — see M36. -### L21. `Library.cran: RCranLibrary` — see M45. +### L19. `Library.requirements: string` (a requirements.txt URI) — OK. -### L22. `Library.requirements: string` (a requirements.txt URI) — OK. +### L20. `AwsAttributes.spotBidPricePercent` — long but precise. -### L23. `AwsAttributes.spotBidPricePercent` — long but precise. - -### L24. `GcpAttributes.usePreemptibleExecutors` — deprecated per JSDoc (use `availability`). -- **Location:** `model.ts:1876`. -- **Category:** Deprecation hygiene. - -### L25. `ClusterSpec_NewCluster.useMlRuntime` — `Ml` casing (vs `ML`); follows style. +### L21. `ClusterSpec_NewCluster.useMlRuntime` — `Ml` casing (vs `ML`); follows style. --- @@ -488,46 +420,35 @@ Issues are catalogued below by severity, then by file/line. - The base "what's a task here" question requires reading `RunTask.task` oneof to discover. ### O3. ID fields are stringly typed throughout -- All run/job/repair IDs are `number`; `dbtPlatformJobRunId` is `string` (see H17). Standardizing as branded types would prevent silent ID swaps. +- All run/job/repair IDs are `number`; `dbtPlatformJobRunId` is `string` (see H16). Standardizing as branded types would prevent silent ID swaps. ### O4. ID disambiguation is heavy - `runId`, `jobId`, `taskRunIds`, `originalAttemptRunId`, `jobRunId`, `repairId`, `latestRepairId`, `clusterId`, `sparkContextId`, `cleanRoomName`, `notebookName`, `policyId`, `instancePoolId`, `warehouseId`, `widgetId`, `agentId`, `subscriberId`, `destinationId`, `pipelineId`, `dashboardId`, `dbtCloudJobId`, `dbtPlatformJobId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId`, `idempotencyToken`, `endpointId`, `gpuNodePoolId`. - All over the place; many would benefit from branded types. -### O5. `WorkflowRun` is mentioned in `RunType` but no `Workflow*` type exists -- `RunType.WORKFLOW_RUN` is "from `dbutils.notebook.run`". The lack of a corresponding `WorkflowTask` is intentional but worth a doc note. - -### O6. JSDoc references `` template-token in many places +### O5. JSDoc references `` template-token in many places - The literal `` string appears in JSDoc throughout (e.g., `model.ts:1880`, `model.ts:824`). This is the placeholder for env-specific brand. Acceptable. -### O7. Deprecated fields are not consistently marked -- Many fields are described as "Deprecated. Please use the X field instead." in prose but lack `@deprecated` JSDoc tag. -- TS LSP will not flag uses; consumers must read prose. Add `@deprecated`. - -### O8. Method-vs-type verb-tense pairing +### O6. Method-vs-type verb-tense pairing - `client.cancelRun(CancelRunRequest) → CancelRunRequest_Response`: verb-noun matches. - `client.runNow(RunNowRequest)`: verb-now matches. - `client.repair(RepairRunRequest) → RepairRunRequest_Response`: verb-noun matches now that the request type has the explicit `Request` suffix; the method/type pairing is consistent. - `client.submitRun(SubmitRunRequest)`: verb-noun matches. -### O9. The waiters duplicate ~80 lines of code each +### O7. The waiters duplicate ~80 lines of code each - `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. - Suggestion: `RepairRunWaiter` for consistency. -### O10. `client.ts:781` declares `repair()` method (not `repairRun()`) +### O8. `client.ts:781` declares `repair()` method (not `repairRun()`) - The method name remains `repair` even though the request type is `RepairRunRequest`. Consider `repairRun` for consistency with `submitRun`, `cancelRun`, `runNow`, etc. -### O11. `index.ts` re-exports both the value classes and types in two blocks +### O9. `index.ts` re-exports both the value classes and types in two blocks - Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. -### O12. `Format` and `Source` are top-level public enums named with single English words +### O10. `Format` and `Source` are top-level public enums named with single English words - These specific names collide with global and tooling identifiers — see H3, H4. -### O13. Acronym-casing rule should be documented -- `Sql`, `Dbt`, `Jvm`, `Adls`, `Aws`, `Azure`, `Gcp`, `Gcs`, `Powerbi` (mixed), `Ml`, `Mlflow`, `Gpu`, `Lakeview`, `Dbfs`, `Ebs`, `Vm`. -- The pattern is mostly "first letter of acronym capitalized only", with a few exceptions. Codify. - -### O14. Inconsistent abbreviations: `Params` vs `Parameters` +### O11. Inconsistent abbreviations: `Params` vs `Parameters` - Within the same parent type (e.g., `RunNowRequest`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. - Standardize on `Parameters`. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 6e0ede8a..6d53097d 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -9,15 +9,15 @@ volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and `KnowledgeSource` each carry their own proto-style nested lifecycle enum (`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). -**Total weird names flagged:** 20 +**Total weird names flagged:** 18 ## Summary | Severity | Count | | --- | --- | | High | 4 | | Medium | 2 | -| Low | 8 | -| Observation | 6 | +| Low | 7 | +| Observation | 5 | ## High severity @@ -105,37 +105,27 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and - **Suggested name:** `pageRequest` or `nextPageReq`. - **Rationale:** Local clarity for readability. -### 14. `KnowledgeSource.spec` field-mask child wiring inconsistent with `$case` — `src/v1/model.ts:734-737` -- **Why weird:** `knowledgeSourceFieldMaskSchema` carries top-level entries `fileTable`, `files`, `index` — matching the `$case` keys, but the wire serialization uses `file_table`/`files`/`index`. Reading the schema, a consumer might write `knowledgeSourceFieldMask('spec.files')` expecting the variant-aware path; the field-mask schema has no `spec` key at all. The discriminated union variants are flattened to top-level field-mask paths, which is correct AIP-161 (https://google.aip.dev/161) behavior — but jarring if you've read the TS type. -- **Category:** 17 (inconsistency between TS shape and field-mask schema). -- **Suggested name:** Not a rename; flag for documentation. -- **Rationale:** Field-mask path lookup is non-obvious; deserves a JSDoc note. - ## Observations -### 15. `KnowledgeAssistant.description` "user-facing" annotation — `src/v1/model.ts:172-178` -- **Why weird:** Doc says "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Either every `description` should carry this annotation, or none should. Flagged for cross-package style review. -- **Category:** Observation. - -### 16. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` +### 14. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` - **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. - **Category:** 17 (reversed — consistency note). -### 17. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +### 15. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` - **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id. The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. -### 18. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` +### 16. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` - **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `ApiError` usage. Cross-cutting observation from `customllms.md` #36. - **Category:** 3 (acronym casing — SDK-wide). - **Suggested name:** SDK-wide policy decision. -### 19. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +### 17. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` - **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. - **Category:** Observation. -### 20. `Example` lacks `state` field — `src/v1/model.ts:79-98` +### 18. `Example` lacks `state` field — `src/v1/model.ts:79-98` - **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. - **Category:** Observation. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index a7e81087..73c973c7 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,7 +3,7 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 19 +**Total weird names flagged:** 16 ## Summary @@ -11,8 +11,8 @@ | ----------- | ----- | | High | 6 | | Medium | 5 | -| Low | 4 | -| Observation | 4 | +| Low | 2 | +| Observation | 3 | ## Summary table @@ -30,13 +30,10 @@ | 10 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | | 11 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | | 12 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | -| 13 | Low | `model.ts` field | `Dashboard.warehouseId` | 19 | -| 14 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | -| 15 | Low | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | -| 16 | Observation | `model.ts` field | `CreateDashboardRequest.datasetCatalog`/`datasetSchema` | 15 | -| 17 | Observation | `model.ts` field | `ListSchedulesRequest.dashboardId` doc typo | 9 | -| 18 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | -| 19 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | +| 13 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | +| 14 | Observation | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | +| 15 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | +| 16 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | --- @@ -258,17 +255,7 @@ Also, the doc string is past-tense verb plus present-tense ("adds") — inconsis **Rationale:** Silent overflow is the worst kind of bug. -### 13. `Dashboard.warehouseId` — underspecified ID - -**Location:** `src/v1/model.ts:112` - -`warehouseId` is a SQL Warehouse ID. The field doc says "warehouse ID used to run the dashboard". Format isn't specified — it's an alphanumeric like `1abc2d3456e789f`. Common across the SDK. - -**Category:** 19. - -**Suggested name:** Keep `warehouseId`, but JSDoc should specify "SQL Warehouse ID (alphanumeric, found at `/sql/warehouses/{id}` in the UI)". - -### 14. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing +### 13. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing **Location:** `src/v1/model.ts:118`, `src/v1/model.ts:341`, `src/v1/model.ts:365` @@ -278,7 +265,11 @@ Consistent within the package, but the HTTP spec spells it `ETag`. Most TS SDKs **Suggested name:** Keep `etag`. Note the project convention. -### 15. `Dashboard.path` vs `Dashboard.parentPath` — overlap +--- + +## Observations + +### 14. `Dashboard.path` vs `Dashboard.parentPath` — overlap **Location:** `src/v1/model.ts:103`, `src/v1/model.ts:135` @@ -293,37 +284,7 @@ parentPath?: string | undefined; // workspace path of the folder containing t **Suggested name:** Keep both. Either rename `path → fullPath` for symmetry, or document the relationship in JSDoc on both fields. ---- - -## Observations - -### 16. `CreateDashboardRequest.datasetCatalog`/`datasetSchema` — generic prefix - -**Location:** `src/v1/model.ts:61,67` - -```ts -datasetCatalog?: string | undefined; -datasetSchema?: string | undefined; -``` - -`Catalog` and `Schema` are Unity Catalog concepts. The prefix `dataset` is what scopes them (apply only to datasets in this dashboard). Without the prefix the fields would be ambiguous with workspace-level catalog/schema. The current names are accurate but a developer reading the field for the first time might think `datasetSchema` is a structural/JSON schema for the dataset — *Schema* is overloaded. - -**Suggested name:** Keep. Add JSDoc clarifying "this is the Unity Catalog *catalog* / *schema* applied to dataset queries". Done already in the JSDoc, but worth flagging. - -### 17. `ListSchedulesRequest.dashboardId` doc typo - -**Location:** `src/v1/model.ts:242` - -```ts -/** UUID identifying the dashboard to which the schedules belongs. */ -dashboardId?: string | undefined; -``` - -"schedules belongs" — verb agreement error. Same on `ListSubscriptionsRequest.dashboardId` line 263 ("subscriptions belongs") and 265 ("subscriptions belongs"). Generated-code artifact; fix at template level. - -**Category:** 9 (plural verb agreement). - -### 18. `index.ts` — mixed `export {...}` and `export type {...}` +### 15. `index.ts` — mixed `export {...}` and `export type {...}` **Location:** `src/v1/index.ts:5,7-43` @@ -334,7 +295,7 @@ export type {AuthorizationDetails, ...} from './model'; Enums are exported as values (correct — they have runtime representation); interfaces are exported as types (correct — type-only). The pattern is right; flagging only because a reader scanning the index file might miss the distinction. Consistent with other SDK packages. -### 19. URL paths still use `lakeview` +### 16. URL paths still use `lakeview` **Location:** Every method's URL constant in `client.ts`, e.g. line 105: `/api/2.0/lakeview/dashboards` diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md index 606d521b..5b525f91 100644 --- a/.agent/naming-audit/logdelivery.md +++ b/.agent/naming-audit/logdelivery.md @@ -9,15 +9,15 @@ delivery configuration ties a `credentialsId` (AWS IAM role) and a `AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no delete endpoint by design — the API only supports disabling via the update (`PATCH`) method. -**Total weird names flagged:** 22 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 4 | | Medium | 7 | -| Low | 7 | -| Observation | 3 | +| Low | 6 | +| Observation | 2 | ## High severity @@ -37,28 +37,13 @@ update (`PATCH`) method. - **Suggested name:** Rename to expose the distinction: `LogDeliveryConfigStatus` → `LogDeliveryEnablement` (`ENABLED` / `DISABLED`) and `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus` (`CREATED` / `SUCCEEDED` / ...). - **Rationale:** Identical nouns for incompatible domains are a classic bug source. Differentiated nouns ("enablement" vs "attempt status") make the two enums distinguishable at the call site. -### 3. `LogDeliveryConfigStatus` JSDoc describes a different concept than the values — `src/v1/model.ts:5-11` -- **Why weird:** The class-level JSDoc reads: - - ``` - Log Delivery Status - - `ENABLED`: All dependencies have executed and succeeded - `DISABLED`: At least one dependency has succeeded - ``` - - The values are `ENABLED` / `DISABLED` of a *configuration* (the per-member docs say "Configuration is enabled" / "Configuration is disabled"). The class doc appears to have been copy-pasted from a Workflows-domain enum (DLT pipelines have "dependencies"). The stray leading `*` on line 6 is a generator artefact that recurs on every multi-line block in this file (`model.ts:6,20,31,53,64,107,121,138,166,227`). -- **Category:** 6 (misleading — JSDoc claim contradicts type domain). -- **Suggested name:** Rewrite JSDoc to "Whether this log delivery configuration is active. Modified via the patch-status endpoint." -- **Rationale:** Wrong JSDoc is worse than missing JSDoc — IDE tooltips, hover-help, and generated reference docs will all display the unrelated "dependencies" prose. The stray `* *` opening line is generator-level and worth fixing globally. - -### 4. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` +### 3. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` - **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:126,218`). The client substitutes them via `?? ''` (`client.ts:126,218`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). - **Category:** 6 (misleading — type signature says optional, runtime requires non-empty), 7 (overly verbose / boilerplate JSDoc). - **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create`). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." - **Rationale:** Required path params should have required types. The current shape silently produces malformed URLs at runtime. The "of customer" prose is generator-emitted boilerplate worth removing globally. -### 5. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` +### 4. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` - **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:209-213`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus`, which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. - **Category:** 6 (misleading), 17 (verb inconsistency — Go uses `PatchStatus`, TS paraphrases as `update`). - **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:227`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. @@ -66,25 +51,25 @@ update (`PATCH`) method. ## Medium severity -### 6. `Client` class is unprefixed — `src/v1/client.ts:46`, exported at `src/v1/index.ts:3` +### 5. `Client` class is unprefixed — `src/v1/client.ts:46`, exported at `src/v1/index.ts:3` - **Why weird:** A user importing the package writes `import {Client} from '@databricks/sdk-logdelivery/v1'` and must alias (`import {Client as LogDeliveryClient}`) to compose with any other Databricks SDK client. Consistent across the SDK; flagged once per package. - **Category:** 1 (vague), 12 (duplicate concept — every Databricks SDK package exports its own `Client`). - **Suggested name:** `LogDeliveryClient` (or expose a namespace and let `logDelivery.Client` be the qualified name). - **Rationale:** Every audited package has this finding. Worth normalising at generator level. -### 7. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` +### 6. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` - **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:160`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `listLogDeliveryConfigurations` (plural). The `*Iter` pagination helper should match: `listLogDeliveryConfigurationsIter`. - **Rationale:** Method-name pluralisation should match the data shape it yields. -### 8. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` -- **Why weird:** Same shape mismatch as finding 7, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. +### 7. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` +- **Why weird:** Same shape mismatch as finding 6, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and the `_Response` partner correspondingly). - **Rationale:** Pluralisation is the standard signal for a collection-returning method/type pair. -### 9. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` +### 8. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` - **Why weird:** Reading `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types whose names all carry "Status": - `LogDeliveryConfiguration` (the resource). - `LogDeliveryStatus` (wrapper for the last-attempt fields). @@ -95,19 +80,19 @@ update (`PATCH`) method. - **Suggested name:** Rename field `logDeliveryStatus` → `lastAttempt`. Rename wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`). Rename enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The call site becomes `config.lastAttempt.status === 'SUCCEEDED'` — three concrete nouns instead of three "Status" repetitions. - **Rationale:** "Status" is too generic to triple-stack. Aligns with findings 1 and 2. -### 10. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` +### 9. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` - **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double-precision float — only safe up to 2^53 − 1. Databricks workspace IDs are int64 server-side; transmitting an ID above the safe range silently loses precision in the JSON wire round-trip. - **Category:** 6 (misleading — TS type cannot represent the wire's int64 safely), 19 (under-specified id type). - **Suggested name:** `workspaceIds: bigint[]` (matches int64 wire). Alternative: brand the IDs as `WorkspaceId` via `type WorkspaceId = bigint & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package finding — every `*Id: number` typed against an int64 wire has the same hazard. Generator-level fix: emit `bigint` for `int64` fields. -### 11. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` +### 10. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` - **Why weird:** `private readonly host: string` — without context, `host` could be just a hostname (`example.com`). The setter at line 62 trims a trailing slash, hinting that the field actually carries a full URL with scheme. A user wiring up `ClientOptions.host` cannot tell from the type whether to pass `databricks.com` or `https://databricks.com/`. - **Category:** 1 (vague), 15 (generic field name). - **Suggested name:** `baseUrl: string` (or `databricksHost`). Matches the actual content (a URL including scheme). - **Rationale:** Generator-level concern — every package's `Client` has this field. Same finding as `disasterrecovery` and others. -### 12. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` +### 11. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` - **Why weird:** Two functions both prefixed `execute` doing very different jobs. `executeCall` wraps a call in retry/rate-limit (`utils.ts:26-38`); `executeHttpCall` does the raw HTTP send plus error lift (`utils.ts:65-94`). Inside each client method, `executeHttpCall` is wrapped in a `Call` (the function alias), and `executeCall(call, options)` runs it — the reader has to trace both bodies to learn who calls whom. - **Category:** 1 (vague), 12 (duplicate prefix), 17 (inconsistent layering nomenclature). - **Suggested name:** `runWithRetry(call, options)` (outer) + `sendHttp(opts)` or `dispatchHttp(opts)` (inner). The verb pair "run" vs "send" makes the layering obvious. @@ -115,43 +100,37 @@ update (`PATCH`) method. ## Low severity -### 13. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` +### 12. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered by this configuration. Pair-wise consistency would be either `BILLABLE_USAGE_LOGS` + `AUDIT_LOGS` (both plural with `_LOGS`) or `BILLABLE_USAGE` + `AUDIT` (both singular without). - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Suggested name:** `BILLABLE_USAGE` + `AUDIT` (drop `_LOGS` — the enum is `LogDeliveryType` so "logs" is implicit). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the enclosing type) is shorter. -### 14. `LogDeliveryConfigStatus.ENABLED` / `.DISABLED` JSDoc is tautological — `src/v1/model.ts:13-16` -- **Why weird:** `/** Configuration is enabled */ ENABLED = 'ENABLED'` — the per-member doc echoes the identifier verbatim. JSDoc should add information. -- **Category:** 1 (vague — doc carries no new signal). -- **Suggested name:** Either delete the JSDoc, or describe behavior: "Logs are actively delivered to the configured bucket." -- **Rationale:** Generator-wide concern. Same in many audited packages. - -### 15. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` +### 13. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc on line 37 says it means "the log delivery status as the configuration has been disabled since the release of this feature or there are no workspaces in the account". That is "no data to report", not "resource missing". - **Category:** 6 (misleading — value name suggests an HTTP error state, semantics are operational). - **Suggested name:** `NO_DATA`, `NOT_APPLICABLE`, or `DISABLED_AT_RELEASE` — anything that does not read as 404. - **Rationale:** A monitoring dashboard surfacing `status === 'NOT_FOUND'` would mislead an operator into thinking the configuration was deleted. -### 16. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` +### 14. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` - **Why weird:** `Segment` is a generic CS term. The leading comment ("Package identity segment for this client to be used in the User-Agent header.", line 40) does the documentation work the name should do. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. - **Rationale:** Generator-wide concern. Same finding in every audited package. -### 17. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` +### 15. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` - **Why weird:** Field name and type both end in `Client`. The shorter form would be `client: HttpClient`, but that would collide with the enclosing `Client` class. So the disambiguation is mechanical, not informative. - **Category:** 20 (type-suffix tautology). - **Suggested name:** `transport: HttpClient` (matches the imported `./transport` module) — avoids the `Client/Client` echo and reads as "the transport layer". - **Rationale:** Generator-wide concern. Tolerable as-is but flagged per rule 20. -### 18. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` +### 16. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` - **Why weird:** Three-letter abbreviations on parameter and local names across every method. The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. -### 19. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` +### 17. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` - **Why weird:** Holds the request shape mutated with `pageToken` between pages. The name reads as "the page's request" rather than "the request iterated across pages". - **Category:** 5 (cryptic), 1 (vague). - **Suggested name:** `currentRequest`, `paginatedRequest`, or just `request` (the per-iteration redefinition is clear from context). @@ -159,14 +138,10 @@ update (`PATCH`) method. ## Observations -### 20. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` +### 18. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` `client.ts` constructs query params inline (lines 155-167) with `new URLSearchParams()` and `params.append(...)`. The exported `flattenQueryParams` helper is never called from this package. Every generated package ships this helper unconditionally — it is generator scaffolding. - **Category:** 11 (unused public helper). - **Suggested fix:** Generator-level — only emit `flattenQueryParams` when the client actually needs it. -### 21. JSDoc artefacts: stray ` * *` opening lines and unresolved `` templates — `src/v1/model.ts:6,20,31,53,64,107,121,138,166,227` and `model.ts:84,127,142,186,233` -Every multi-line JSDoc block in `model.ts` starts with a stray ` * *` line (e.g., line 5-7: `/**\n * *\n * Log Delivery Status`). Looks like the generator emits an empty paragraph break that renders as a literal `*`. Separately, the placeholder `` appears unsubstituted throughout (e.g., `model.ts:84,127,142,186,233` — "`` account ID"). Neither is a naming issue per se but both pollute the rendered docs. -- **Category:** Observation (generator template hygiene). - -### 22. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` +### 19. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. diff --git a/.agent/naming-audit/logdeliveryconfigurations.md b/.agent/naming-audit/logdeliveryconfigurations.md deleted file mode 100644 index 6c6b7429..00000000 --- a/.agent/naming-audit/logdeliveryconfigurations.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: logdeliveryconfigurations - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index ab2575eb..c6a9b97f 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,14 +3,14 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 38 (38 still present, 0 newly fixed, 0 superseded). +**Total weird names flagged:** 36 (36 still present, 0 newly fixed, 0 superseded). ## Summary | Severity | Count | | --- | --- | | High | 8 | | Medium | 18 | -| Low | 7 | +| Low | 5 | | Observation | 5 | The marketplaces package remains one of the more naming-distressed surfaces in the SDK, though the dominant pre-existing problem — **inconsistent request-type naming** across the package — has been resolved by uniformly applying the `*Request`/`*Response` suffix to every operation type. Notable issues remaining include the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListingsRequest` and its proto-nested `_Response` payload field both use `listings`, while `CreateListingRequest` and `DeleteListingRequest` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type. @@ -593,64 +593,26 @@ Two adjective values. Fine. Flagged because the package also has `Personalizatio - **Suggested name:** No rename. - **Rationale:** Internal consistency check. -### 32. `ProviderInfo.iconFilePath` vs `iconFileId` — id and path co-located - -**Location:** `src/v1/model.ts:776, 784` - -```ts -iconFilePath?: string | undefined; -... -iconFileId?: string | undefined; -``` - -Same icon represented two ways — `iconFilePath` (a URL or storage path) and `iconFileId` (a Marketplace file id). The pairing repeats with `darkModeIconFileId` and `darkModeIconFilePath` (lines 787-788). No doc explains when to use which or whether one is derived from the other. -- **Category:** 12 (duplicate concept), 17 (inconsistent — the relationship is implicit). -- **Suggested name:** No rename; flag for doc clarification. -- **Rationale:** Observation. - -### 33. Method docstring inconsistency — `client.ts` - -**Location:** `src/v1/client.ts:235, 266, 297, 326, 380, 437, 491, 542, 600, 628, 656, 735, 763, 789, 849, 927, 952, 986, 1015, 1041, 1070, 1096, 1125, 1154, 1186, 1211, 1239, 1264, 1292, 1320, 1345, 1370, 1400, 1425, 1479, 1539, 1567, 1624, 1675, 1732, 1790, 1847, 1875, 1929, 1957, 1983, 2012, 2041, 2073, 2102` - -```ts -/** Associate an exchange with a listing */ -/** Create an exchange */ -/** Add an exchange filter. */ -/** Create a file. Currently, only provider icons and attached notebooks are supported. */ -/** Create a new listing */ -/** This removes a listing from marketplace. */ -/** Get provider analytics dashboard. */ -``` - -Inconsistent docstring style: -- Mix of trailing period ("Add an exchange filter.", "Create a file. ...") and no period ("Create an exchange", "Create a new listing"). -- Mix of imperative verbs ("Create", "Get", "Delete") and full sentences ("This removes a listing from marketplace."). -- "Get provider analytics dashboard" appears on `listProviderAnalyticsDashboard` (line 1847) — verb mismatch (it's a list method but the doc says "Get"). -- "This removes a listing from marketplace" appears on `deleteExchange` (line 1186) — text describes the wrong concept (says "listing", method is `deleteExchange`). -- **Category:** 17 (inconsistent action verbs / doc style), 6 (misleading: docstring text contradicts method name). -- **Suggested name:** No rename; flag for doc consistency. -- **Rationale:** Observation. - --- ## Observations -### 34. v1-only audit +### 32. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 35. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` +### 33. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. - **Category:** 1 (vague), 15 (generic name). -### 36. `flattenQueryParams` — `src/v1/utils.ts:123` +### 34. `flattenQueryParams` — `src/v1/utils.ts:123` The helper is used by `client.ts` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. - **Category:** Observation. -### 37. `readAll` — `src/v1/utils.ts:40` +### 35. `readAll` — `src/v1/utils.ts:40` Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. - **Category:** 1 (vague), 14 (Go-style name). -### 38. `HttpCallOptions` — `src/v1/utils.ts:15` +### 36. `HttpCallOptions` — `src/v1/utils.ts:15` Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. - **Category:** 1 (vague suffix), 17 (inconsistent). diff --git a/.agent/naming-audit/materializedfeatures.md b/.agent/naming-audit/materializedfeatures.md deleted file mode 100644 index 24e3a475..00000000 --- a/.agent/naming-audit/materializedfeatures.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: materializedfeatures - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index e410bdfd..1279d49c 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -40,17 +40,6 @@ A bare `cloud: string` with a single example list in the doc (`aws`, `azure`, `gcp`). Should probably be typed as a `CloudProvider` enum (see §5.2) — but at minimum the field is generic when read alone. -#### 1.3 `owner` field (model.ts:177, 234, 389, 430, 491) -"The owner of the metastore." — generic. Owner of what kind? Username? -Email? Group? Service principal? Documented as a free-form string with -no format hint. See §13.4. - -#### 1.4 `region` (model.ts:181, 238, 393, 434, 495) -Bare `region: string` with examples (`us-west-2`, `westus`). Acceptable -as cloud-vendor-specific opaque strings, but the same field carries -different vocabularies across `aws` / `azure` / `gcp` — that -heterogeneity isn't reflected in the name or doc. - --- ### 2. Redundant enum prefixes @@ -61,23 +50,7 @@ _None._ ### 3. Acronym casing inconsistencies -#### 3.1 `DBR` in doc strings (model.ts:198, 255, 410, 451, 512) -Doc says "Whether to allow non-DBR clients to directly access entities -under the metastore." DBR (Databricks Runtime) is an internal acronym -not introduced anywhere in the package. Doc-only, not a code-naming -issue per se, but it's a documentation acronym that won't mean anything -to external SDK consumers. - -#### 3.2 `UUID` casing in docs (model.ts:168, 225, 380, 421, 482) -"UUID of storage credential" — UUID is in the doc only. The field is -named `storageRootCredentialId` (lowercase `Id`). Consistent with -ECMAScript identifier convention; flagged in passing. - -#### 3.3 `` placeholder tokens in docs (model.ts:22, 37, 49, 63, 77, 91, 105, 118, 132, 147, 362, 463) -Literal `` strings appear in doc comments — these are -unsubstituted templating placeholders. Not a naming issue, but -surfaces as a publication bug for SDK consumers reading the generated -TypeDoc. +_None._ --- @@ -93,24 +66,12 @@ _None._ "Info" suggests metadata about a metastore separate from the entity itself; the type is in fact the entity. See also §7.1. -#### 5.2 `defaultDataAccessConfigId` (model.ts:167, 223, 379, 419, 480) -Doc says "Unique identifier of the metastore's (Default) Data Access -Configuration." The parenthetical "Default" duplicates the `default` -prefix in the name, but the field is described as both the default -data-access-config and as a unique identifier. Slightly self-referential -and unclear whether this is mutable or static. See also §13.3. - -#### 5.3 `cloud: string` (model.ts:195, 252, 407, 448, 509) +#### 5.2 `cloud: string` (model.ts:195, 252, 407, 448, 509) Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as `string`. The name is fine; the *type* misleads about the value space. See §1.2. -#### 5.4 `region: string` carries cloud-specific formats (model.ts:181, 238, 393, 434, 495) -"e.g., `us-west-2`, `westus`" — same field carries AWS-style and -Azure-style region names. Name is fine; doc just shows the -heterogeneity. See §1.4. - -#### 5.5 `GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` (model.ts:294-333 vs 373-412) +#### 5.3 `GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` (model.ts:294-333 vs 373-412) Both types have the *same* 18 fields with the *same* docs in the *same* order. The "summary" type doesn't actually summarise — it returns the full metastore record. The name lies about the content. The Go SDK @@ -118,13 +79,13 @@ inherits this from the API definition, but the TS port could collapse the two: either alias the summary response to `MetastoreInfo` or expose the genuinely-summarised subset. -#### 5.6 `getMetastoreSummary` is presented as info-about (client.ts:616-619) +#### 5.4 `getMetastoreSummary` is presented as info-about (client.ts:616-619) JSDoc says "Gets information about a metastore. This summary includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" omits the "current-workspace" semantics. Cf. `getCurrentMetastoreAssignment`, which spells out "current". See also -§11.1. +§10.1. --- @@ -133,7 +94,7 @@ omits the "current-workspace" semantics. Cf. #### 6.1 `getCurrentMetastoreAssignment` (client.ts:567) 28-character method name. Acceptable — describes the semantics — but combined with `getMetastoreSummary` (which is also "current-workspace" -in practice, §5.6) one of them carries redundant prefixing. +in practice, §5.4) one of them carries redundant prefixing. --- @@ -173,7 +134,7 @@ fixable in isolation. See also §10.1. ### 10. Duplicate concepts #### 10.1 `MetastoreInfo` vs `GetMetastoreSummaryRequest_Response` (model.ts:294, 373) -Same 18 fields, same docs, different names. See §5.5. +Same 18 fields, same docs, different names. See §5.3. #### 10.2 `CreateMetastoreRequest` vs `MetastoreInfo` vs `UpdateMetastoreRequest` (model.ts:218, 373, 471) Massive structural duplication — `CreateMetastoreRequest` has 19 fields, @@ -190,14 +151,7 @@ request shape (§11.3). Three structurally identical types with three workspace-id / metastore-id / default-catalog-name fields. Could be unified. -#### 10.4 `name` (CreateMetastoreRequest body) vs metastore identity -`CreateMetastoreRequest.name` is "the user-specified name of the -metastore" — but `MetastoreInfo` also exposes `metastoreId` as the -canonical unique identifier. The naming pretends `name` is unique but -in fact the server creates `metastoreId` as the immutable key and -`name` is mutable. The doc could disclose this; the name doesn't. - -#### 10.5 `name` vs `newName` on `UpdateMetastoreRequest` (model.ts:475, 477) +#### 10.4 `name` vs `newName` on `UpdateMetastoreRequest` (model.ts:475, 477) Two name-like fields on the update request: - `newName` — "New name for the metastore." (model.ts:475). - `name` — "The user-specified name of the metastore." (model.ts:477). @@ -237,7 +191,7 @@ The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of catalogs §16.2. -#### 11.4 `GetMetastoreSummaryRequest_Response` returns the full metastore (model.ts:294) — see §5.5. The type name promises a summary; the value is the entity. +#### 11.4 `GetMetastoreSummaryRequest_Response` returns the full metastore (model.ts:294) — see §5.3. The type name promises a summary; the value is the entity. --- @@ -253,7 +207,7 @@ Three "get"-style methods, each with a different qualifier: The first explicitly takes an id, the second implicitly uses the current workspace, the third explicitly says "Current". Inconsistent qualifier vocabulary. Either rename `getMetastoreSummary` to -`getCurrentMetastore` (which would also fix §5.6) or drop "Current" +`getCurrentMetastore` (which would also fix §5.4) or drop "Current" from `getCurrentMetastoreAssignment`. #### 12.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. @@ -262,30 +216,10 @@ from `getCurrentMetastoreAssignment`. ### 13. Underspecified IDs -#### 13.1 `metastoreId` (model.ts:27, 54, 66, 94, 121, 137, 150, 183, 206, 240, 263, 296, 365, 395, 436, 459, 497) -Documented as "Unique identifier of metastore" / "The unique ID of the -metastore." Format is opaque — likely a UUID, but never specified in -the doc. - -#### 13.2 `workspaceId` (model.ts:25, 52, 80, 135, 203, 260, 363, 457) -`number` — that's specified by the type, but the doc just says "A -workspace ID." with no range or stability guarantee. Acceptable for a -numeric id; flagged because the format isn't documented in the field. - -#### 13.3 `defaultDataAccessConfigId` (model.ts:167, 223, 300, 379, 419, 480) -"Unique identifier of the metastore's (Default) Data Access -Configuration." No format hint (UUID? slug?). See §5.2. - -#### 13.4 `storageRootCredentialId` (model.ts:169, 225, 302, 381, 421, 482) -Doc says "UUID of storage credential" — at least the doc says UUID -here, but the field name doesn't carry the type. Counter-example to -§13.1: when the doc *does* specify UUID, the field still doesn't carry -it. - -#### 13.5 `owner`, `createdBy`, `updatedBy` (model.ts:177, 187, 191, 234, 244, 248, 322, 326, 330, 389, 399, 403, 430, 440, 444, 491, 501, 505) -Documented as "username", "Username of metastore creator", etc. -Format (email? user id? group?) is unspecified. The names imply -identity; the doc only narrows to "username". +#### 13.1 `storageRootCredentialId` (model.ts:169, 225, 302, 381, 421, 482) +Doc says "UUID of storage credential" — the doc says UUID here, but the +field name doesn't carry the type. The field name should communicate +the identifier shape that the doc already specifies. --- @@ -356,57 +290,50 @@ flagged in passing. | Identifier | Location | Finding | | ------------------------------------------------------- | ------------------ | ------- | | `CreateMetastoreRequest` | model.ts:218 | 10.2, 11.3 | -| `CreateMetastoreRequest.name` | model.ts:220 | 9.1, 10.4 | -| `CreateMetastoreRequest.defaultDataAccessConfigId` | model.ts:224 | 5.2, 13.3 | -| `CreateMetastoreRequest.storageRootCredentialId` | model.ts:226 | 13.4 | -| `CreateMetastoreRequest.owner` | model.ts:234 | 1.3, 13.5 | -| `CreateMetastoreRequest.region` | model.ts:238 | 1.4, 5.4 | -| `CreateMetastoreRequest.metastoreId` (read-only) | model.ts:240 | 11.3, 13.1, 15.1 | +| `CreateMetastoreRequest.name` | model.ts:220 | 9.1 | +| `CreateMetastoreRequest.storageRootCredentialId` | model.ts:226 | 13.1 | +| `CreateMetastoreRequest.cloud` | model.ts:252 | 1.2, 5.2 | +| `CreateMetastoreRequest.metastoreId` (read-only) | model.ts:240 | 11.3, 15.1 | | `CreateMetastoreRequest.createdAt` (read-only) | model.ts:242 | 11.3 | -| `CreateMetastoreRequest.createdBy` (read-only) | model.ts:244 | 11.3, 13.5 | +| `CreateMetastoreRequest.createdBy` (read-only) | model.ts:244 | 11.3 | | `CreateMetastoreRequest.updatedAt` (read-only) | model.ts:246 | 11.3 | -| `CreateMetastoreRequest.updatedBy` (read-only) | model.ts:248 | 11.3, 13.5 | +| `CreateMetastoreRequest.updatedBy` (read-only) | model.ts:248 | 11.3 | | `CreateMetastoreRequest.storageRootCredentialName` | model.ts:250 | 11.3 | -| `CreateMetastoreRequest.cloud` | model.ts:252 | 1.2, 5.3 | | `CreateMetastoreRequest.globalMetastoreId` (read-only) | model.ts:254 | 11.3 | -| `CreateMetastoreRequest.externalAccessEnabled` | model.ts:256 | 3.1 (doc) | | `CreateMetastoreAssignmentRequest` | model.ts:202 | 10.3 | -| `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | 13.2, F | -| `CreateMetastoreAssignmentRequest.metastoreId` | model.ts:206 | 13.1 | +| `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | F | | `CreateMetastoreAssignmentRequest.defaultCatalogName` | model.ts:212 | — | | `DeleteMetastoreRequest` | model.ts:269 | — | | `DeleteMetastoreAssignmentRequest` | model.ts:259 | 10.3 | -| `DeleteMetastoreAssignmentRequest.workspaceId` | model.ts:260 | 13.2 | -| `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | 13.1, D | +| `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | D | | `GetCurrentMetastoreAssignmentRequest` | model.ts:283 | — | | `GetMetastoreRequest` | model.ts:285 | — | | `GetMetastoreSummaryRequest` | model.ts:291 | — | -| `GetMetastoreSummaryRequest_Response` | model.ts:294 | 5.5, 10.1, 11.4 | +| `GetMetastoreSummaryRequest_Response` | model.ts:294 | 5.3, 10.1, 11.4 | | `ListMetastoresRequest` | model.ts:335 | — | | `ListMetastoresRequest.maxResults` | model.ts:345 | — | | `ListMetastoresRequest.pageToken` | model.ts:347 | — | | `ListMetastoresRequest_Response.metastores` | model.ts:353 | 8.1 (positive) | | `ListMetastoresRequest_Response.nextPageToken` | model.ts:358 | — | | `MetastoreAssignment` | model.ts:361 | 1.1, 7.2, 10.3 | -| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.1, 13.2, F | -| `MetastoreAssignment.metastoreId` | model.ts:365 | 13.1, 15.2 | +| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.1, F | +| `MetastoreAssignment.metastoreId` | model.ts:365 | 15.2 | | `MetastoreAssignment.defaultCatalogName` | model.ts:370 | — | | `MetastoreInfo` | model.ts:373 | 5.1, 7.1, 10.2 | -| `MetastoreInfo.metastoreId` | model.ts:395 | 13.1, 15.1 | +| `MetastoreInfo.metastoreId` | model.ts:395 | 15.1 | | `UpdateMetastoreRequest` | model.ts:471 | 10.2, 11.1, 11.3 | | `UpdateMetastoreRequest.id` | model.ts:473 | 11.1, 11.2 | -| `UpdateMetastoreRequest.newName` | model.ts:475 | 10.5, 11.1 | -| `UpdateMetastoreRequest.name` | model.ts:477 | 10.5, 11.1 | +| `UpdateMetastoreRequest.newName` | model.ts:475 | 10.4, 11.1 | +| `UpdateMetastoreRequest.name` | model.ts:477 | 10.4, 11.1 | | `UpdateMetastoreRequest.metastoreId` | model.ts:497 | 11.1, 11.2 | | `UpdateMetastoreAssignmentRequest` | model.ts:455 | 10.3 | -| `UpdateMetastoreAssignmentRequest.workspaceId` | model.ts:457 | 13.2 | | `Client.createMetastore` | client.ts:437 | — | | `Client.createMetastoreAssignment` | client.ts:467 | — | | `Client.deleteMetastore` | client.ts:499 | C | | `Client.deleteMetastoreAssignment` | client.ts:533 | B, D | | `Client.getCurrentMetastoreAssignment` | client.ts:567 | 12.1 | | `Client.getMetastore` | client.ts:592 | 12.1, C | -| `Client.getMetastoreSummary` | client.ts:620 | 5.6, 12.1 | +| `Client.getMetastoreSummary` | client.ts:620 | 5.4, 12.1 | | `Client.listMetastores` | client.ts:656 | — | | `Client.updateMetastore` | client.ts:714 | C | | `Client.updateMetastoreAssignment` | client.ts:744 | B | @@ -419,10 +346,10 @@ flagged in passing. ## Recommended priority order -1. **Disambiguate the four name/id-like fields on `UpdateMetastoreRequest`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.5) +1. **Disambiguate the four name/id-like fields on `UpdateMetastoreRequest`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.4) 2. **Strip read-only fields from `CreateMetastoreRequest` / `UpdateMetastoreRequest`.** (§11.3, §10.2) -3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.5, §10.1) -4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.6, §12.1) +3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.3, §10.1) +4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.4, §12.1) 5. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) 6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index 806dccf7..00b309c2 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,14 +8,14 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 42 +**Total weird names flagged:** 31 ## Summary | Severity | Count | | --- | --- | -| High | 21 | -| Medium | 12 | -| Low | 6 | +| High | 20 | +| Medium | 6 | +| Low | 2 | | Observation | 3 | ## High severity @@ -76,23 +76,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Mixed tense and grammatical category in one enum makes it hard to remember which value to use without looking it up. -### 4. `PermissionLevel` enum values — `model.ts:82-95` -- **Why weird:** Values include `CAN_MANAGE_STAGING_VERSIONS`, - `CAN_MANAGE_PRODUCTION_VERSIONS`, `CAN_CREATE_REGISTERED_MODEL`. These - hard-code two MLflow stages (Staging, Production) into the permission - enum, but the stage list itself is open-ended (None, Staging, - Production, Archived). There is no `CAN_MANAGE_ARCHIVED_VERSIONS`. - Also, the doc-comment for `CAN_EDIT` says it is `reserved 1; // - IS_OWNER = 1; was DEPRECATED` — that is a Protobuf reservation comment - leaking into TypeScript public docs. -- **Category:** 6 (misleading: implies parallel constants exist), 14 - (proto-style leakage in JSDoc). -- **Suggested name:** Leave values as-is for wire compatibility, but - strip the protobuf "reserved 1" comment from the public doc. -- **Rationale:** The proto comment serves no purpose to TS users and - hints that the enum will break if reused. - -### 5. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` +### 4. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` - **Why weird:** Enum name says `Type` but values are *states* (`ALL_EVENTS`, `DEFAULT`, `SUBSCRIBED`, `UNSUBSCRIBED`). `DEFAULT` and `ALL_EVENTS` overlap in meaning. The class doc-comment marks it @@ -104,7 +88,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The field consuming the enum is already called `emailSubscriptionStatus`; the enum should match. -### 6. `RegistryWebhookEvent` enum — `model.ts:113-126` +### 5. `RegistryWebhookEvent` enum — `model.ts:113-126` - **Why weird:** Contains both generic `MODEL_VERSION_TRANSITIONED_STAGE` *and* three specific `MODEL_VERSION_TRANSITIONED_TO_{STAGING,PRODUCTION,ARCHIVED}`. The @@ -119,7 +103,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Overlap creates "two ways to express one intent" — a classic source of bugs. -### 7. `Activity` vs `CommentObject` vs `TransitionRequest` — `model.ts:150, 227, 1015` +### 6. `Activity` vs `CommentObject` vs `TransitionRequest` — `model.ts:150, 227, 1015` - **Why weird:** Three interfaces have *identical* shape and *identical* doc-comment ("For activities, this contains the activity recorded for the action. For comments, this contains the comment details. For @@ -134,15 +118,15 @@ is the Unity-Catalog-scoped successor. the `activityType` discriminator. The "type per usage site" anti-pattern forces consumers to choose between identical shapes. -### 8. `CommentObject` — `model.ts:227` +### 7. `CommentObject` — `model.ts:227` - **Why weird:** `Object` is the most generic suffix possible in TS (everything is an object). Combined with the duplicate-shape problem - (#7), this is a textbook bad name. + (#6), this is a textbook bad name. - **Category:** 1 (vague `Object` suffix), 20 (type-suffix tautology). -- **Suggested name:** `Comment` — or fold into `Activity` per #7. +- **Suggested name:** `Comment` — or fold into `Activity` per #6. - **Rationale:** `Object` adds nothing; the type is already a TS object. -### 9. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, +### 8. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, `TransitionModelVersionStageDatabricksRequest`, `ModelVersionDatabricks` — `model.ts:542, 549, 690, 758, 981, 1005` - **Why weird:** `Databricks` as a type suffix. The whole SDK is the @@ -160,7 +144,7 @@ is the Unity-Catalog-scoped successor. (then split by capability). The current "shadow type per extension" is a generator artefact, not a user-friendly API. -### 10. `TransitionModelVersionStageDatabricksRequest` — `model.ts:981` +### 9. `TransitionModelVersionStageDatabricksRequest` — `model.ts:981` - **Why weird:** Six-word PascalCase identifier with awkward word order. Reads as "transition[verb] model-version-stage[object]-databricks[suffix]-request[suffix]". For a @@ -176,7 +160,7 @@ is the Unity-Catalog-scoped successor. performing similar workspace operations; the asymmetric names obscure this. -### 11. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:542` +### 10. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:542` - **Why weird:** Verb-phrase request type name (`GetX`) is OK if used consistently, but `GetRegisteredModelDatabricksRequest` is the only method the SDK exposes to fetch a registered model — there is no plain @@ -188,7 +172,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** No need for the disambiguation suffix when there's no sibling. -### 12. `client.listTransitionsRequest` method vs `ListTransitionRequest` +### 11. `client.listTransitionsRequest` method vs `ListTransitionRequest` request type — `client.ts:513, model.ts:645` - **Why weird:** The method is `listTransitionsRequest` (plural "Transitions") but the request type is `ListTransitionRequest` @@ -209,7 +193,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The method name in JS conventions describes the collection being listed; here that's "transition requests", plural. -### 13. `RegistryWebhook` vs `Webhook` — `model.ts:787` +### 12. `RegistryWebhook` vs `Webhook` — `model.ts:787` - **Why weird:** Type is `RegistryWebhook` but client methods, paths, and request types alternate: `CreateRegistryWebhookRequest`, `ListRegistryWebhooksRequest`, `UpdateRegistryWebhookRequest`, @@ -222,7 +206,7 @@ is the Unity-Catalog-scoped successor. `TestWebhookRequest`. - **Rationale:** Package name already establishes the registry context. -### 14. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` +### 13. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` - **Why weird:** `Spec` is a vague suffix shared by every config-bag in the SDK. Two sibling types in the same package, only the `Spec` suffix distinguishing them. `HttpUrlSpec` is the *target* of a webhook @@ -235,7 +219,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The two together discriminate the webhook destination kind; the naming should make that obvious. -### 15. `LinkedFeature` — `model.ts:573` +### 14. `LinkedFeature` — `model.ts:573` - **Why weird:** Doc comment says "Feature for model version. ([ML-57150] Renamed from Feature to LinkedFeature)". The ticket number leaks into the public docstring. Type name was changed for internal reasons @@ -248,7 +232,7 @@ is the Unity-Catalog-scoped successor. type; the fields are just identifiers pointing at a feature in the feature store. -### 16. `stage: string` field on `ApproveTransitionRequest`, +### 15. `stage: string` field on `ApproveTransitionRequest`, `CreateTransitionRequest`, `DeleteTransitionRequest`, `RejectTransitionRequest`, `TransitionModelVersionStageDatabricksRequest` — `model.ts:209, 396, 483, 847, 997` @@ -264,9 +248,9 @@ is the Unity-Catalog-scoped successor. to a type. Currently every transition method takes `stage: string` with no type-level validation. -### 17. `currentStage: string` field on `ModelVersion`, +### 16. `currentStage: string` field on `ModelVersion`, `ModelVersionDatabricks` — `model.ts:670, 701` -- **Why weird:** Same as #16 — typed as `string`, valid values +- **Why weird:** Same as #15 — typed as `string`, valid values enumerated only in docs. Also called `currentStage` here but `stage` on request DTOs (no prefix). Inconsistent. - **Category:** 6 (misleading), 16 (type contradicts domain), 17 @@ -275,7 +259,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** "Current" is implicit (it's the *current* stage of this version). -### 18. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` +### 17. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` - **Why weird:** Three different `Activity`-shaped types each duplicate `fromStage: string | undefined`, `toStage: string | undefined`, again stringly typed. Identical doc-comments paste the same four-value @@ -283,10 +267,10 @@ is the Unity-Catalog-scoped successor. - **Category:** 16 (type contradicts domain), 12 (duplicate concept), 7 (overly verbose docs). - **Suggested name:** `fromStage: Stage`, `toStage: Stage`. -- **Rationale:** Same as #16. +- **Rationale:** Same as #15. -### 19. `Databricks` as a suffix is overused -- **Why weird:** Distinct type names still end in `Databricks` (see #9): +### 18. `Databricks` as a suffix is overused +- **Why weird:** Distinct type names still end in `Databricks` (see #8): `RegisteredModelDatabricks`, `ModelVersionDatabricks`. Two more retain `Databricks` as an infix inside the new `Request` suffix (`GetRegisteredModelDatabricksRequest`, @@ -294,10 +278,10 @@ is the Unity-Catalog-scoped successor. workspace-specific extension. The `Databricks` token appearing inside the *Databricks SDK* is tautological. - **Category:** 8 (redundant suffix), 20 (type-suffix tautology). -- **Suggested name:** See #9. -- **Rationale:** See #9. +- **Suggested name:** See #8. +- **Rationale:** See #8. -### 20. `getRegisteredModelDatabricks` client method — `client.ts:416` +### 19. `getRegisteredModelDatabricks` client method — `client.ts:416` - **Why weird:** Method name carries `Databricks` mid-position (between the noun `RegisteredModel` and any conceptual suffix). The whole SDK is the Databricks SDK; embedding `Databricks` inside a method name is @@ -317,9 +301,9 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The infix encodes a proto-level distinction that has no analogue in this TS surface; remove it. -### 21. `transitionModelVersionStageDatabricks` client method — +### 20. `transitionModelVersionStageDatabricks` client method — `client.ts:615` -- **Why weird:** Same `Databricks` mid-position leak as #20. The token +- **Why weird:** Same `Databricks` mid-position leak as #19. The token sits between `Stage` and the implicit method suffix, marking the method as the workspace-extension variant of an upstream MLflow RPC. Method-name length (six words, 38 chars) is also a symptom: the verb @@ -330,45 +314,13 @@ is the Unity-Catalog-scoped successor. (overly verbose), 14 (proto-style leakage into surface API). - **Suggested name:** `transitionModelVersionStage` (drop the infix) or fold into `approveTransitionRequest`-style verbs since the operations - overlap (see #10). -- **Rationale:** Same as #20 — the infix encodes a generator-side + overlap (see #9). +- **Rationale:** Same as #19 — the infix encodes a generator-side distinction that callers do not need. ## Medium severity -### 22. `jobId: string` on `JobSpec` — `model.ts:565` -- **Why weird:** Doc says "ID of the job that the webhook runs." This is - a Databricks Jobs job ID. `jobId` is fine but lives in a model that - duplicates the documentation in the comment for - `CreateRegistryWebhookRequest.jobSpec` (model.ts:371 says "ID of the - job that the webhook runs.") even though `jobSpec` is a *struct* not - an ID. -- **Category:** 6 (misleading docstring). -- **Suggested name:** Field name OK; fix doc-comment on - `CreateRegistryWebhookRequest.jobSpec`. -- **Rationale:** Doc-comment mismatch is a generator bug. - -### 23. `enableSslVerification: boolean` — `model.ts:556` -- **Why weird:** Doc-comment is 4 lines describing why you should never - disable this. The boolean has a default (true) per the docs but the - field is `boolean | undefined`. So `undefined` and `true` mean the - same thing — confusing. -- **Category:** 16 (semantics not captured in type). -- **Suggested name:** Field name OK; add `@default true` JSDoc tag. -- **Rationale:** Make default-truthy fields clearer. - -### 24. `events: RegistryWebhookEvent[]` doc paste — `model.ts:331-355, - 602-630, 791-815, 1102-1127` -- **Why weird:** The 25-line "Events that can trigger a registry - webhook" doc block is copy-pasted at least 4 times across types - that all expose `events: RegistryWebhookEvent[]`. Pure generator - noise polluting the public docs. -- **Category:** 7 (overly verbose), Observation. -- **Suggested name:** Doc generation should DRY this; only the field - signature plus a one-line description should remain. -- **Rationale:** Quality-of-life for consumers reading JSDoc. - -### 25. `tags?: ModelVersionTag[] | undefined` and +### 21. `tags?: ModelVersionTag[] | undefined` and `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, 719, 755, 776` - **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, @@ -379,52 +331,42 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Single `Tag` type with `{ key, value }`. - **Rationale:** Identical structure should have identical type. -### 26. `systemComment: string | undefined` — `model.ts:185, 262, 1050` -- **Why weird:** The same paragraph-long doc-comment is pasted on three - identical fields across three identical types. "Comment made by - system, for example explaining an activity of type - `SYSTEM_TRANSITION`." -- **Category:** 12 (duplicate concept across types), 7 (verbose). -- **Suggested name:** Field name OK; field is also a candidate for - consolidation via #7. -- **Rationale:** Same as #7. - -### 27. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` +### 22. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` - **Why weird:** Typed as `Activity[]` but the field is documented as "Open requests for this `model_versions`" — they are transition *requests* (not arbitrary activities). The reason is the - identical-shape problem (#7). + identical-shape problem (#6). - **Category:** 6 (misleading type), 16 (type contradicts domain). - **Suggested name:** `openTransitionRequests: TransitionRequest[]` - (post-rename per #7). + (post-rename per #6). - **Rationale:** Restores the intent. -### 28. `requests: Activity[]` on list-transition-requests response — +### 23. `requests: Activity[]` on list-transition-requests response — `model.ts:655` - **Why weird:** Stored as `Activity[]` but the response is documented as "Array of open transition requests." - **Category:** 6 (misleading type), 15 (generic field name). - **Suggested name:** `transitionRequests: TransitionRequest[]`. -- **Rationale:** Same as #27 — type contradicts domain because of the - identical-shape problem (#7). +- **Rationale:** Same as #22 — type contradicts domain because of the + identical-shape problem (#6). -### 29. `registeredModelDatabricks: RegisteredModelDatabricks` — +### 24. `registeredModelDatabricks: RegisteredModelDatabricks` — `model.ts:549` - **Why weird:** Field name *is* the type name verbatim. The `Databricks` - suffix problem (#9) cascades into the field name. + suffix problem (#8) cascades into the field name. - **Category:** 20 (type-suffix tautology). - **Suggested name:** After dropping the `Databricks` suffix from the type: `registeredModel: RegisteredModel`. Or just return the type directly without a wrapper. - **Rationale:** Reduces verbosity by removing the wrapper. -### 30. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` -- **Why weird:** Same as #29 for `ModelVersionDatabricks`. +### 25. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` +- **Why weird:** Same as #24 for `ModelVersionDatabricks`. - **Category:** 20. - **Suggested name:** `modelVersion: ModelVersion`. - **Rationale:** Same. -### 31. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, +### 26. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, `model.ts:501` - **Why weird:** The method returns *one* version per stage, not "the latest version" globally. The name reads as "give me the latest @@ -437,39 +379,9 @@ is the Unity-Catalog-scoped successor. `getLatestVersionsByStage`. - **Rationale:** Conveys the per-stage semantics. -### 32. `featureTableId`, `featureTableName`, `featureName` on - `LinkedFeature` — `model.ts:575, 577, 579` -- **Why weird:** Both `featureTableId` and `featureTableName` are - exposed — primary key duplication. Doc-comments are bare ("Feature - table id" / "Feature table name") and don't explain why both are - present. -- **Category:** 12 (duplicate concept), 19 (underspecified ID). -- **Suggested name:** Field names OK; add JSDoc explaining the - relationship. -- **Rationale:** Without docs, callers won't know which to populate. - -### 33. `description: string` overloaded — `model.ts:303, 318, 358, 672, - 703, 748, 768, 822, 1077, 1090, 1130` -- **Why weird:** Same field on 11 types, each meaning slightly different - things (registered-model description, model-version description, - webhook description, registered-model-databricks description). Same - field name everywhere. -- **Category:** 15 (generic field name). -- **Suggested name:** Acceptable as `description` if doc-comments are - clear; flag for consistency. -- **Rationale:** Common across SDK; low cost to leave alone. - ## Low severity -### 34. `statusMessage: string` — `model.ts:683, 710` -- **Why weird:** Field name fine but doc says it's only set "if it is - pending or failed", so the field is conditionally meaningful — not in - the type signature. -- **Category:** 6 (misleading: optional semantics not in type). -- **Suggested name:** Field name OK; document the conditional. -- **Rationale:** Low priority. - -### 35. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, +### 27. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, 593, 633, 634, 642, 877, 886, 894, 905, 913, 921` - **Why weird:** Consistent across the package — good. Noted for completeness. @@ -477,23 +389,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** No change. - **Rationale:** Observation. -### 36. `orderBy: string[]` on `SearchModelVersionsRequest`, - `SearchRegisteredModelsRequest` — `model.ts:884, 911` -- **Why weird:** Stringly-typed sort spec; doc says values are like - `"name DESC"` or `"version ASC"`. Could be a typed `Sort` struct, but - string is the standard SQL-like sort spec. -- **Category:** 16 (type contradicts domain). -- **Suggested name:** Field name OK; flag the stringly-typed pattern. -- **Rationale:** Matches REST API conventions; low cost. - -### 37. `filter: string` on `SearchModelVersionsRequest`, - `SearchRegisteredModelsRequest` — `model.ts:875, 903` -- **Why weird:** Stringly-typed search filter (SQL-like). Same as #36. -- **Category:** 16. -- **Suggested name:** No change; could be `filterExpression`. -- **Rationale:** REST convention. - -### 38. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` +### 28. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` - **Why weird:** Field doc says "If provided, updates the name for this `registered_model`." Slightly confusing because `RenameRegisteredModelRequest` is *the* rename operation — "if @@ -504,18 +400,9 @@ is the Unity-Catalog-scoped successor. omission is a no-op. - **Rationale:** Optional-but-required-in-practice fields confuse users. -### 39. `httpUrlSpec` / `jobSpec` doc on `CreateRegistryWebhookRequest` — - `model.ts:369-371` -- **Why weird:** Doc-comment on `jobSpec` (line 371) is literally just - "ID of the job that the webhook runs." — wrong, since `jobSpec` is a - struct holding multiple fields, not an ID. -- **Category:** 6 (misleading docstring). -- **Suggested name:** Field name OK; fix doc-comment. -- **Rationale:** Generator bug; users will read the doc. - ## Observations -### 40. Both `modelregistry` and `registeredmodels` exist as packages +### 29. Both `modelregistry` and `registeredmodels` exist as packages The user instruction calls out this duplication. Cross-package overlap: - `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` (registeredmodels) — same concept, different names. @@ -533,7 +420,7 @@ The user instruction calls out this duplication. Cross-package overlap: Documentation does not direct users to one or the other. - **Category:** 12 (duplicate concepts — across packages). -### 41. Action-verb conventions in `Client` +### 30. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -542,7 +429,7 @@ reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). -### 42. Acronym casing inside doc-comments +### 31. Acronym casing inside doc-comments `MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` (`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md index 02758a62..e4e41574 100644 --- a/.agent/naming-audit/modelserving.md +++ b/.agent/naming-audit/modelserving.md @@ -3,14 +3,14 @@ **Path:** `packages/modelserving/src/v1/` **Versions audited:** v1 **Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Created by the 2026-05-22 regeneration which consolidated the prior `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. -**Total weird names flagged:** 38 +**Total weird names flagged:** 33 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 13 | -| Low | 10 | +| High | 8 | +| Medium | 12 | +| Low | 9 | | Observation | 4 | ## High severity @@ -27,63 +27,45 @@ - **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. - **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. -### 3. `EndpointCoreConfig*.servedEntities` + `servedModels` duplicate field — `src/v1/model.ts:376-390, 392-408, 410-415, 856-874, 950-966` -- **Why weird:** Five different request/response types each carry *both* `servedEntities?: ServedModel[]` and `servedModels?: ServedModel[]`. The JSDoc admits the duplication: "(Deprecated, use served_entities instead) The list of served models under the serving endpoint config." For a TS SDK user typing into IntelliSense both fields appear and both look valid. Idiomatic TS uses `@deprecated` on the field, which the JSDoc does not. -- **Category:** 12 (duplicate concept), 6 (misleading — deprecated not marked). -- **Suggested name:** Mark `servedModels` with `@deprecated` JSDoc tag (so IDEs strike through it). Better: drop `servedModels` from the TS surface entirely. -- **Rationale:** Five types times two fields equals ten redundant deprecation lookalikes; every one of them is a footgun. - -### 4. `ServedModel.modelName` / `ServedModel.modelVersion` deprecated cousins of `entityName` / `entityVersion` — `src/v1/model.ts:1032, 1033, 1057-1067` -- **Why weird:** `ServedModel` has both `entityName`/`entityVersion` and `modelName`/`modelVersion`. The JSDoc on `ServedModelLite.modelName` (line 1059) says "Only one of model_name and entity_name should be populated"; same for `modelVersion`/`entityVersion`. So `ServedModel.modelName`/`modelVersion` are legacy fields that mirror `entityName`/`entityVersion`. They are completely undocumented inside `ServedModel` (lines 1032-1033 are bare fields with no comment), so a TS user has no way to know they are deprecated. Same bug class as #3 at the field level. -- **Category:** 12 (duplicate concept), 6 (misleading), 19 (underspecified — bare fields with no docs). -- **Suggested name:** Mark `modelName` / `modelVersion` as `@deprecated`. The JSDoc on `ServedModelLite` should be promoted to a real type-level note. Wire keys remain. -- **Rationale:** Public surface area duplicating itself is *the* common source of integration bugs. - -### 5. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` +### 3. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` - **Why weird:** This is the *only* type named `ServingEndpoint*`. Every other type in the file uses `InferenceEndpoint*`. Either this enum should be `InferenceEndpointPermissionLevel` (to match the rest of the package), or the rest of the package should be `ServingEndpoint*` (to match the product and wire). The `Detailed` infix is also suspect — the enum lives on `InferenceEndpointDetailed.permissionLevel`, so the type-name says "this enum belongs to InferenceEndpointDetailed", but a `permissionLevel` of `CAN_VIEW` is *not* detailed any differently from a non-detailed view; the enum applies to the resource, not to the response shape. So `Detailed` is leaking the response-DTO name into the enum name. - **Category:** 17 (inconsistent terminology), 7 (overly verbose). - **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. - **Rationale:** Enum names that include the response-DTO shape (`Detailed`) tangle the message identity into the type identity. In TS, the enum represents a concept, not the message it appears in. -### 6. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:587` +### 4. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:587` - **Why weird:** `httpRequest` on a model-serving `Client` is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. - **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). - **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. - **Rationale:** A method called `httpRequest` on a model-serving `Client` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. -### 7. Acronym casing storm: `Ai` / `OpenAi` / `PaLm` / `Ai21Labs` / `Pii` / `Pt` / `Llm` across the file +### 5. Acronym casing storm: `Ai` / `OpenAi` / `PaLm` / `Ai21Labs` / `Pii` / `Pt` / `Llm` across the file - **Why weird:** Mixed acronym-casing schemes on user-visible names: - `AiGateway`, `AiGatewayConfig`, `AiGatewayRateLimit`, `AiGuardrails`, `AiGuardrailParameters` — title-cased `Ai`. - `OpenAiConfig`, `googleCloudVertexAiConfig` — title-cased `Ai` mid-word. - `PaLmConfig`, `palmConfig` — `PaLm` (mixed-internal-caps). The product is "PaLM" (stylized "Pathways Language Model"); the SDK chose `PaLm`, the worst rendering option. - `Ai21Labs`, `Ai21LabsConfig` — the product is "AI21 Labs"; rendered as `Ai21Labs` (lower-case `21`, lower-case `i` mid-word). - `PiiSettings` — `Pii` (PII = personally identifiable information); rendered title-case. - - `Pt`, `PtEndpoint`, `PtServedModel`, `PtEndpointCoreConfig`, `CreatePtEndpointRequest`, `PutPtEndpointConfigRequest` — `Pt` is "PT" (provisioned throughput). Two-letter acronym title-cased while the method names spell it out (#8). + - `Pt`, `PtEndpoint`, `PtServedModel`, `PtEndpointCoreConfig`, `CreatePtEndpointRequest`, `PutPtEndpointConfigRequest` — `Pt` is "PT" (provisioned throughput). Two-letter acronym title-cased while the method names spell it out (#6). Excludes JS-built-in acronyms (`Http`, `Json`) and wire-format strings. - **Category:** 3 (acronym casing inconsistencies). - **Suggested name:** Decide a project-wide rule in `typescript.mdc`. Either follow Microsoft's .NET capitalization (title-case two-letter acronyms, PascalCase three-plus) or the Google TypeScript Style Guide (treat acronyms as whole words). Either is defensible; *none* should be mixed in one file. - **Rationale:** Twenty-plus exported identifiers from one file vary in convention. This is the single biggest *category* of weirdness in the package surface. -### 8. `Pt` abbreviation in types vs `ProvisionedThroughput` in methods/waiters — `src/v1/client.ts:148, 173, 515, 540, 695, 855`, `src/v1/model.ts:294, 881, 887, 981` +### 6. `Pt` abbreviation in types vs `ProvisionedThroughput` in methods/waiters — `src/v1/client.ts:148, 173, 515, 540, 695, 855`, `src/v1/model.ts:294, 881, 887, 981` - **Why weird:** `Pt` is short for "provisioned throughput". The full term *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`) and two waiter class names (`CreateProvisionedThroughputInferenceEndpointWaiter`, `PutProvisionedThroughputInferenceEndpointConfigWaiter`), but the request/response *types* use the abbreviation (`CreatePtEndpointRequest`, `PutPtEndpointConfigRequest`, `PtEndpointCoreConfig`, `PtServedModel`). The URL says `/api/2.0/serving-endpoints/pt`. Three different names for one concept in one call. - **Category:** 5 (cryptic abbreviation), 17 (inconsistent abbreviation across method/type/URL). - **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpointRequest`, `PutProvisionedThroughputEndpointConfigRequest`) or contract all (`createPtEndpoint`, `putPtEndpointConfig`). Pick one. The current half-and-half is the worst option. - **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). -### 9. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` +### 7. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` - **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 878). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `NONE | BLOCK | MASK` — so this is *PII action behavior*. - **Category:** 1 (vague/generic), 15 (generic name losing meaning). - **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. - **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. -### 10. `Route` carries both `servedModelName` and `servedEntityName` — `src/v1/model.ts:996-1002` -- **Why weird:** `Route` has three fields: `servedModelName?: string`, `trafficPercentage?: number`, `servedEntityName?: string`. There is no JSDoc on `servedEntityName` — it is silently the modern name; `servedModelName` is the legacy. Two fields point at the same logical thing (the entity to route traffic to), one without docs, one with docs that only mention "served model" (line 997). Same bug class as #3 and #4. -- **Category:** 12 (duplicate concept), 6 (misleading), 19 (undocumented field). -- **Suggested name:** Mark `servedModelName` `@deprecated`; doc `servedEntityName` properly. -- **Rationale:** Triple bug: undocumented field, duplicate concept, no deprecation marker. - -### 11. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:540`, `src/v1/client.ts:216` +### 8. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:540`, `src/v1/client.ts:216` - **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but `Get + Export + Endpoint + Metrics + Request` parses as five nouns in a row. The doc string (`client.ts:215`) confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English phrase is "export the endpoint's metrics" → method `exportEndpointMetrics`. Compare with sibling methods on the same client: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags` — none prefix the noun with an output format. - **Category:** 6 (misleading), 7 (overly verbose), 17 (inconsistent verb — every other method is `getX`, this one is `getExportX`). - **Suggested name:** `exportEndpointMetrics(req: ExportEndpointMetricsRequest)` returning `EndpointMetrics`. Or `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning `EndpointMetrics`. The "export" framing is a wire-protocol detail (Prometheus format) that does not belong in the method name. @@ -91,13 +73,13 @@ ## Medium severity -### 12. `ServedModelDeploymentState` enum name collides with parent `ServedModelState` type — `src/v1/model.ts:12, 1069-1072` +### 9. `ServedModelDeploymentState` enum name collides with parent `ServedModelState` type — `src/v1/model.ts:12, 1069-1072` - **Why weird:** The enum type is `ServedModelDeploymentState`, and it lives on the field `ServedModelState.deployment: ServedModelDeploymentState`. Two different types both end in `State`, one wraps the other, and the wrapper field (`deployment`) shares its name with the inner enum's category. The result reads as `served.state.deployment` returning a `ServedModelDeploymentState` — the wrapper and the enum sound like the same thing. - **Category:** 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). - **Suggested name:** Rename the type `ServedModelState` → `ServedModelDeployment`, and the enum `ServedModelDeploymentState` → `DeploymentState`. Call site becomes `served.state.deployment === DeploymentState.READY`. The container and the discriminant no longer share a noun. - **Rationale:** Two `*State` siblings nested inside each other tangle the wrapper identity with the discriminant identity. -### 13. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:376, 392, 410` +### 10. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:376, 392, 410` - **Why weird:** Three types describe "the config of a serving endpoint": - `EndpointCoreConfig`: input shape (`servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig`). - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. @@ -108,7 +90,7 @@ - **Suggested name:** Either collapse into one type with optional fields, or give the types names that reflect their purpose: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). - **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. -### 14. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:624, 653` +### 11. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:624, 653` - **Why weird:** Two near-duplicate types: - `InferenceEndpoint` (lines 624-651): 14 fields, used in `ListInferenceEndpointsRequest_Response.endpoints`. - `InferenceEndpointDetailed` (lines 653-690): 18 fields, returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. @@ -118,13 +100,13 @@ - **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. - **Rationale:** A consumer writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. -### 15. `ServedModelLite` lite-variant — `src/v1/model.ts:1057-1067` -- **Why weird:** Same pattern as #14 at the entity level. `ServedModel` (line 1004) has 23 fields. `ServedModelLite` (lines 1057-1067) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (uses "Summary" in the name). +### 12. `ServedModelLite` lite-variant — `src/v1/model.ts:1057-1067` +- **Why weird:** Same pattern as #11 at the entity level. `ServedModel` (line 1004) has 23 fields. `ServedModelLite` (lines 1057-1067) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (uses "Summary" in the name). - **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). - **Suggested name:** `ServedEntitySummary` (paired with #2 rename). - **Rationale:** Inconsistent suffix convention across the file. -### 16. `CreatePtEndpointRequest` method-type asymmetry with `CreateInferenceEndpointRequest` — `src/v1/model.ts:271, 294` +### 13. `CreatePtEndpointRequest` method-type asymmetry with `CreateInferenceEndpointRequest` — `src/v1/model.ts:271, 294` - **Why weird:** Sister request types: - `CreateInferenceEndpointRequest` (full name). - `CreatePtEndpointRequest` (abbreviated). @@ -134,7 +116,7 @@ - **Suggested name:** `CreateServingEndpointRequest` and `CreateProvisionedThroughputServingEndpointRequest` (paired with #1). - **Rationale:** Sibling request types should differ only in the qualifier that actually differs. -### 17. `PutInferenceEndpointConfigRequest` vs `PutPtEndpointConfigRequest` — request shape divergence — `src/v1/model.ts:950, 981` +### 14. `PutInferenceEndpointConfigRequest` vs `PutPtEndpointConfigRequest` — request shape divergence — `src/v1/model.ts:950, 981` - **Why weird:** Two "put endpoint config" requests: - `PutInferenceEndpointConfigRequest`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). - `PutPtEndpointConfigRequest`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). @@ -144,25 +126,25 @@ - **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. - **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. -### 18. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:192, 220, 247, 272, 299, 327, 383, 415, 447, 487, 519, 559` +### 15. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:192, 220, 247, 272, 299, 327, 383, 415, 447, 487, 519, 559` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — if the caller forgets to set it, the SDK silently emits a URL like `/api/2.0/serving-endpoints//metrics` (double slash) which will 404 server-side. The contradiction between "required per JSDoc" and "optional per TS type" is a typing inconsistency that bites consumers. - **Category:** 6 (misleading — JSDoc contradicts type), 16 (field contradicting type domain). - **Suggested name:** Mark `name` as required (`endpointName: string`). Remove the `?? ''` fallback so a missing value throws earlier. Same applies to `servedModelName`. - **Rationale:** Optional + "required" JSDoc + empty-string fallback is a triple-violation. Cf. AIP-122 (https://google.aip.dev/122) which mandates path parameters be required. -### 19. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` +### 16. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` - **Why weird:** Four waiter classes: - `CreateInferenceEndpointWaiter` - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters) - `PutInferenceEndpointConfigWaiter` - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) - Two issues: the verb tense varies (`Create*Waiter` describes the resource lifecycle; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` while the request/response types use `Pt` (#8). + Two issues: the verb tense varies (`Create*Waiter` describes the resource lifecycle; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` while the request/response types use `Pt` (#6). - **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). - **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. - **Rationale:** Four exported waiter classes, each 30+ characters long, with five+ identical prefixes that grep the same way as the methods themselves. -### 20. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` +### 17. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -173,25 +155,19 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 21. `RateLimit` vs `AiGatewayRateLimit` — two near-duplicate types — `src/v1/model.ts:987-994, 93-107` -- **Why weird:** `RateLimit` (3 fields: calls, key, renewalPeriod) and `AiGatewayRateLimit` (5 fields: calls, key, renewalPeriod, principal, tokens). The `AiGateway` variant is a strict superset. Why two types? `RateLimit` is used by the deprecated `putInferenceEndpointRateLimits` (client.ts:483 "Deprecated: Please use AI Gateway to manage rate limits instead."). Same pattern as #13: legacy + new lives side-by-side, with no `@deprecated` tag on the legacy type. -- **Category:** 12 (duplicate concept), 6 (misleading — deprecation not in tag). -- **Suggested name:** Mark `RateLimit` and `PutInferenceEndpointRateLimitsRequest*` types `@deprecated` in JSDoc. -- **Rationale:** Same pattern repeated; same fix. - -### 22. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:737-740` +### 18. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:737-740` - **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field, so the wrapping is a pure architectural placeholder reserved for future operations. The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. - **Category:** 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). - **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a field then. - **Rationale:** `Info`-wrapping-`Info` is an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. -### 23. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `src/v1/client.ts:295, 323` +### 19. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `src/v1/client.ts:295, 323` - **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a separate concept. The naming makes the unqualified one (`getServedModelLogs`) sound canonical, but it is actually the service-logs special case. - **Category:** 12 (duplicate concept), 6 (misleading — `getServedModelLogs` alone doesn't tell you it returns *service* (not build) logs). - **Suggested name:** Rename the existing `getServedModelLogs` to `getServedModelServiceLogs` (parallel with `getServedModelBuildLogs`). Or collapse into one method with a `kind: 'build' | 'service'` parameter. - **Rationale:** When two siblings differ by a hidden attribute, name *both* with that attribute. Today the default and the special case look asymmetric. -### 24. `GetServedModelLogsRequest_Response.logs: string` is a single blob, name is plural — `src/v1/model.ts:570, 583` +### 20. `GetServedModelLogsRequest_Response.logs: string` is a single blob, name is plural — `src/v1/model.ts:570, 583` - **Why weird:** Both `GetServedModelBuildLogsRequest_Response` and `GetServedModelLogsRequest_Response` have `logs?: string`. The field name is plural but the type is a single string — many log *lines* concatenated. A user doing `for (const line of response.logs)` will iterate characters, not lines. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Either `logsText: string` (singular field with type-disambiguating suffix) or `logs: string[]` (split lines server-side). @@ -199,69 +175,63 @@ ## Low severity -### 25. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields across provider configs +### 21. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields across provider configs - **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. - **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). - **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. - **Rationale:** The "must specify exactly one" constraint is invisible to the type system. -### 26. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` +### 22. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` - **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. - **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). - **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. - **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. -### 27. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` -- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #34: a string field with a documented but unenforced enum. +### 23. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` +- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #22: a string field with a documented but unenforced enum. - **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). - **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). - **Rationale:** Type-narrowing fix; minor. -### 28. `ExternalModel.task` freeform string — `src/v1/model.ts:471` +### 24. `ExternalModel.task` freeform string — `src/v1/model.ts:471` - **Why weird:** "The task type of the external model." Bare `string` with no JSDoc enumeration of accepted values. `task` is also used on `InferenceEndpoint.task` (line 642) and `InferenceEndpointDetailed.task` (line 675) with the same minimalist doc ("The task type of the serving endpoint."). Three uses of `task: string`, none telling the user what strings are legal (e.g., `chat`, `completion`, `embeddings`). - **Category:** 1 (vague), 19 (underspecified domain). - **Suggested name:** Type as a string-literal union or, at minimum, document the accepted values in JSDoc. -- **Rationale:** Same class as #34/#35. +- **Rationale:** Same class as #22/#23. -### 29. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` +### 25. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` - **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. - **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). - **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). - **Rationale:** Minor; internal. -### 30. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` +### 26. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` - **Why weird:** The method `getExportEndpointMetrics` returns `ExportMetricsResponse` — the type name dropped the `Endpoint` qualifier present in the method name. A reader greping for `EndpointMetrics` won't find the response type. Same shape (`contents?: ReadableStream`) as `ExternalFunctionResponse` and `GetOpenApiResponse`; the *content* is the only thing that says "metrics". - **Category:** 17 (inconsistent — method qualifier dropped from response type), 1 (vague — `ExportMetricsResponse` could be metrics for anything). -- **Suggested name:** Pair the method rename in #11 with a response rename: `getEndpointMetrics()` → `EndpointMetrics`. Or `exportEndpointMetrics()` → `ExportEndpointMetricsResponse`. +- **Suggested name:** Pair the method rename in #8 with a response rename: `getEndpointMetrics()` → `EndpointMetrics`. Or `exportEndpointMetrics()` → `ExportEndpointMetricsResponse`. - **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. -### 31. `servedModelName` doc echoes the field name three times — `src/v1/model.ts:563-564, 576-577` -- **Why weird:** JSDoc on `GetServedModelBuildLogsRequest.servedModelName` reads "The name of the served model that build logs will be retrieved for. This field is required." The field name already contains "servedModel" + "Name" + the type signature already conveys "this is a name". Pure echo. The doc also doesn't tell the user *what format* the served model name takes (alphanumeric? UUID? UC three-part?). -- **Category:** 7 (overly verbose), 20 (type-suffix tautology — `name: string` reading as "name of a name"). -- **Suggested name:** No name rename; rewrite JSDoc to give the *format* (e.g., "Slug-style identifier of the served model, e.g. `myllm-v2`"). -- **Rationale:** The doc carries no information beyond what the name already says. - -### 32. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` +### 27. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` - **Why weird:** Every read method here is prefixed `get*`. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, it's typically on synchronous accessors. - **Category:** 14 (Go/Java-style names). - **Suggested name:** Verb-first for actions: `exportMetrics(req)`, `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or property-style if the request is trivial. - **Rationale:** Google TS Style Guide § Names of functions (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. SDK-wide call, flag for project review. -### 33. `Call` type aliased to `Promise` in `utils.ts` import — `src/v1/utils.ts:3` +### 28. `Call` type aliased to `Promise` in `utils.ts` import — `src/v1/utils.ts:3` - **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` reads like "a phone call" or "function call". The actual semantic is "a retriable RPC closure". - **Category:** 1 (vague). - **Suggested name:** `RetriableRpc` or `RpcClosure`. Cross-package decision because `Call` is defined in `@databricks/sdk-core/api`. - **Rationale:** Type names exported from a "core" package set the vocabulary for every consumer; bare `Call` is the kind of name that survives review only because nobody wants to argue with the framework. -### 34. `Options` type aliased to internal options shape — `src/v1/utils.ts:3, 30` -- **Why weird:** Same as #41 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen to have similar fields. +### 29. `Options` type aliased to internal options shape — `src/v1/utils.ts:3, 30` +- **Why weird:** Same as #28 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen to have similar fields. - **Category:** 1 (vague), 12 (duplicate concept — `Options` vs `CallOptions`). - **Suggested name:** `ExecuteCallInternalOptions` (verbose but honest) or `RetrierOptions`. Cross-package decision. - **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. ## Observation -### 35. Mixed naming convention for the same product across sibling packages +### 30. Mixed naming convention for the same product across sibling packages The Databricks "Serving Endpoints" product spans two packages in this SDK after the 2026-05-22 consolidation: - `modelserving`: types use `InferenceEndpoint*` (control plane). - `modelservingquery`: types use `Endpoint` (data plane — e.g., `QueryEndpointInput`, `QueryEndpointResponse`). @@ -269,15 +239,15 @@ The Databricks "Serving Endpoints" product spans two packages in this SDK after The wire uniformly uses `serving-endpoints`. SDK consumers chaining both packages will see different names for one concept. - **Category:** 17 (cross-package inconsistency). -### 36. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +### 31. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. - **Category:** 12 (duplicate concept). -### 37. `userAgent` is built once in the constructor and never refreshed — `src/v1/client.ts:89, 103` +### 32. `userAgent` is built once in the constructor and never refreshed — `src/v1/client.ts:89, 103` Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If the credentials are mutated post-construction (rare but possible), the UA goes stale. Cross-package observation. - **Category:** 6 (mildly misleading). -### 38. `info` local var in the constructor — `src/v1/client.ts:97, 99, 103` +### 33. `info` local var in the constructor — `src/v1/client.ts:97, 99, 103` `let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 (vague). A reader who hasn't looked at `createDefault()` does not know `info` is a `ClientInfo`. Cross-package observation. - **Category:** 1, 5. diff --git a/.agent/naming-audit/modelservingdebug.md b/.agent/naming-audit/modelservingdebug.md deleted file mode 100644 index f6e7a155..00000000 --- a/.agent/naming-audit/modelservingdebug.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: modelservingdebug - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/modelservingmanagement.md b/.agent/naming-audit/modelservingmanagement.md deleted file mode 100644 index 5bf37798..00000000 --- a/.agent/naming-audit/modelservingmanagement.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: modelservingmanagement - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index d4b8edc1..5ce54ff0 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -11,9 +11,9 @@ **Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. -**Total weird names flagged:** 18 (0 fixed, 18 still, 0 superseded) +**Total weird names flagged:** 17 (0 fixed, 17 still, 0 superseded) -Rescanned on 2026-05-26 after regeneration #156. All 18 findings remain +Rescanned on 2026-05-26 after regeneration #156. All 17 findings remain unchanged in the regenerated output; no items have moved to `## Fixed`. --- @@ -37,9 +37,8 @@ unchanged in the regenerated output; no items have moved to `## Fixed`. | 13 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | | 14 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | | 15 | Medium | `model.ts` field | `QueryEndpointInputRequest.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | -| 16 | Low | `client.ts` JSDoc | `/** Query a serving endpoint */` | Verb-tense / missing period (project rule) | -| 17 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | -| 18 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | +| 16 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 17 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | --- @@ -304,20 +303,7 @@ extraParams?: Record | undefined; ## Low severity -### 16. JSDoc `/** Query a serving endpoint */` — verb tense / no period - -**Location:** `src/v1/client.ts:57` - -**Categories:** 13 (verb-tense inconsistency), project rule (sentences end with period) - -```ts -/** Query a serving endpoint */ -async query(...) { ... } -``` - -Imperative verb, no terminal punctuation. Project rule (`CLAUDE.md`) requires comments to be sentences ending with a period. `/** Queries a serving endpoint. */` would match the v2-style JSDoc in other packages (`alerts/src/v2/client.ts` uses third-person singular present). - -### 17. `ChatMessageRole.ASSISTANT` — incomplete enum +### 16. `ChatMessageRole.ASSISTANT` — incomplete enum **Location:** `src/v1/model.ts:17-23` @@ -334,7 +320,7 @@ export enum ChatMessageRole { Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. -### 18. `flattenQueryParams` — orphaned export with conflicting "Query" +### 17. `flattenQueryParams` — orphaned export with conflicting "Query" **Location:** `src/v1/utils.ts:123-150` diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 99e2c09d..6d4cd66d 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,7 +3,7 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 13 +**Total weird names flagged:** 12 ## Summary @@ -12,7 +12,7 @@ | High | 4 | | Medium | 1 | | Low | 5 | -| Observation | 3 | +| Observation | 2 | ## Summary table @@ -30,7 +30,6 @@ | 10 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | | 11 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | | 12 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | -| 13 | Obs | `model.ts:47`, `:51` | `[Input-Only][Optional]` doc marker inconsistency | — | ## High severity @@ -172,9 +171,6 @@ JSDoc bracket prefixes mark every secret-bearing field as either input-only or o ### 12. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. -### 13. JSDoc inconsistency in `[Input-Only][Optional]` markers -The `GenericWebhookConfig.username` (line 47) and `.password` (line 51) use the marker `[Input-Only][Optional]` — concatenating two brackets — while every other field uses single-bracket markers. The `[Optional]` is also redundant because the TS type already shows `?: undefined`. Minor doc inconsistency. - ## Domain glossary - `notification destination` — the persistent record being managed. Always paired with a `displayName` and one `Config`. - `channel` — implicit term-of-art for the kind of destination (Slack, Email, etc.). Not used in any identifier here; encoded as `DestinationType`. diff --git a/.agent/naming-audit/oauth.md b/.agent/naming-audit/oauth.md index 935ec39b..de5c3cb3 100644 --- a/.agent/naming-audit/oauth.md +++ b/.agent/naming-audit/oauth.md @@ -22,17 +22,17 @@ covers three resources in one client: All three share the `TokenAccessPolicy` type for access/refresh-token TTL and session-rotation configuration. The package is the Databricks account-side complement to RFC 6749 client registration. -**Total weird names flagged:** 5 +**Total weird names flagged:** 3 ## Summary table | Severity | Count | | --- | --- | -| High | 2 | +| High | 1 | | Medium | 0 | -| Low | 3 | -| Observation | 2 | -| **Total** | **5 (+ 2 observations)** | +| Low | 2 | +| Observation | 1 | +| **Total** | **3 (+ 1 observation)** | The audit excludes the `OAuth*` brand-name spelling (RFC 6749 platform-name exception), `*_UNSPECIFIED` proto sentinels, `*_Response` proto-nested @@ -49,28 +49,7 @@ template tokens, dead helper exports). ## High severity (must fix) -### 1. Stale JSDoc cross-references to non-existent services — `client.ts:101, 137, 172, 203, 458, 493` -- **Why:** Six method docs say "You can retrieve the … OAuth app - integration via `:method:CustomAppIntegration/get`" or - "`:method:PublishedAppIntegration/get`". Neither `CustomAppIntegration` - nor `PublishedAppIntegration` is exported by this package — the - consolidated `Client` exposes `getCustomOAuthAppIntegration` and - `getPublishedOAuthAppIntegration`. The `:method:Foo/bar` directive - is proto-doc cross-reference syntax that should have been rewritten - during generation. Anyone clicking through hits a broken reference, - and the doc text reads as if there is a separate sub-service that - doesn't exist. -- **Category:** 6 (misleading documentation) -- **Suggested:** Rewrite during generation to TS-link form, e.g. - `Client.getCustomOAuthAppIntegration` / `Client.getPublishedOAuthAppIntegration`, - rendered as a JSDoc `{@link}` tag. At minimum, drop the - proto-cross-reference syntax and inline the method name as plain - prose. -- **Rationale:** Documentation that names APIs that do not exist is - worse than no documentation. The leak is a generator template - failing to rewrite proto-cross-reference syntax for TS output. - -### 2. `confidential` vs `isConfidentialClient` — same flag spelled two ways in one file — `model.ts:12, 55, 164` +### 1. `confidential` vs `isConfidentialClient` — same flag spelled two ways in one file — `model.ts:12, 55, 164` - **Why:** The RFC 6749 §2.1 "confidential client" boolean flag appears three times in `model.ts`. On `CreateCustomOAuthAppIntegrationRequest.confidential` (line 12) and @@ -124,28 +103,7 @@ _None._ `Lifetime` is gratuitous — the JSDoc itself uses both interchangeably for one concept. -### 2. `includeCreatorUsername` is a server-side join flag, cryptic without context — `model.ts:114` -- **Why:** `ListCustomOAuthAppIntegrationsRequest.includeCreatorUsername` - is a boolean opt-in that does not appear on the sibling - `ListPublishedOAuthAppIntegrationsRequest` (line 124). The JSDoc - is empty. A caller writing both list calls in sequence cannot tell - why one has the option and the other does not. The flag's - semantics — "perform a server-side join to resolve the creator user - ID to their username" — are not visible from the name. -- **Category:** 5 (cryptic — the flag's semantics are non-obvious - without external context) -- **Suggested:** Keep the name (matches Go SDK convention) but - document the flag inline: "When `true`, the server resolves - `createdBy` to `creatorUsername` in each response row (extra - server-side lookup)." Decide whether the same option belongs on - the published-integration list endpoint, and add it for parity - if so. -- **Rationale:** The default behaviour (omit username) is a - performance optimisation; callers should know enabling this is a - server-side join, and the asymmetry with the published-integration - list should be deliberate or removed. - -### 3. `Client` is a single generic export on a multi-resource package — `client.ts:69` +### 2. `Client` is a single generic export on a multi-resource package — `client.ts:69` - **Why:** The package exports a single `Client` class whose responsibilities now span three resources (custom integrations, published integrations, published apps) and ten methods. A @@ -166,16 +124,7 @@ _None._ ## Observations (not flags) -### O1. `` and `` template tokens leak into JSDoc — `model.ts:73, 76, 195`, `client.ts:285, 345, 402` -- Six call sites in this package leave literal `` / - `` angle-bracket tokens in their JSDoc — they were meant - to be substituted with "Databricks" / "account" by the generator's - template engine. They render as broken-HTML angle-bracket sequences - in TypeScript hover popups and IDE doc views. Not a per-package - naming issue, but the leak is visible at every IDE hover. Tracked - at the project level. - -### O2. `flattenQueryParams` exported but unused — `utils.ts:123` +### O1. `flattenQueryParams` exported but unused — `utils.ts:123` - The helper is exported from `utils.ts` but the three list endpoints in this package (`listCustomOAuthAppIntegrations`, `listPublishedOAuthAppIntegrations`, `listPublishedOAuthApps`) all @@ -201,7 +150,7 @@ _None._ - `confidential` / `isConfidentialClient` — RFC 6749 §2.1 client type. `true` means the client has a secret and authenticates itself; `false` means it is a public client and relies on PKCE. - Currently spelled two ways in this file (finding H2). + Currently spelled two ways in this file (finding H1). - `Custom` integration — Caller-defined OAuth client (caller-owned redirect URLs, scopes, secret). - `createdBy` — Numeric Databricks user ID of the registration @@ -236,7 +185,7 @@ _None._ `oauthcustomappintegration` and `oauthpublishedapp` packages into this single `@databricks/sdk-oauth` package. Former cross-package inconsistencies are now intra-package issues: - `confidential` vs `isConfidentialClient` (H2) and the shape of the + `confidential` vs `isConfidentialClient` (H1) and the shape of the `scopes` documented value space across the published and custom surfaces. The consolidation is reflected in the import list at `index.ts:7-31`, which now re-exports 25 types from one model file. diff --git a/.agent/naming-audit/oauthcustomappintegration.md b/.agent/naming-audit/oauthcustomappintegration.md deleted file mode 100644 index b404887a..00000000 --- a/.agent/naming-audit/oauthcustomappintegration.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: oauthcustomappintegration - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/oauthpublishedapp.md b/.agent/naming-audit/oauthpublishedapp.md deleted file mode 100644 index 69bc4be9..00000000 --- a/.agent/naming-audit/oauthpublishedapp.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: oauthpublishedapp - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/permissions.md b/.agent/naming-audit/permissions.md deleted file mode 100644 index 6d8251df..00000000 --- a/.agent/naming-audit/permissions.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: permissions - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index d0e2c53b..fe2e9dba 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -14,11 +14,11 @@ | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------------------- | -| High | 14 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | -| Medium | 16 | Vague names, acronym casing, generic IDs, misleading enum values. | -| Low | 15 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 7 | Patterns spanning the whole file (branding history, proto-architectural leakage). | -| **Total** | **52** | | +| High | 12 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | +| Medium | 13 | Vague names, acronym casing, generic IDs, misleading enum values. | +| Low | 8 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| Observations | 3 | Patterns spanning the whole file (branding history, proto-architectural leakage). | +| **Total** | **36** | | Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. @@ -80,31 +80,19 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). - **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). -### H10. `PipelineState_PipelineState.IDLE` is the terminal state — but the JSDoc says "Pipeline is stopped and is not processing data. Can be resumed by calling `run`" -- **Location:** `model.ts:262`. -- **Category:** 6 (misleading — references method `run` that does not exist; the method is `start`). -- **Suggestion:** Fix JSDoc to reference `start()`. After H3, both will line up at `run()`. -- **Rationale:** Currently the user reads "call `run`" and finds no `run()` method on `Client`. - -### H11. `client.delete()` collides with JS `delete` keyword +### H10. `client.delete()` collides with JS `delete` keyword - **Location:** `client.ts:220`. - **Category:** 10 (reserved-word collision). - **Suggestion:** Rename to `deletePipeline()`. Alternatively, `remove()`. - **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. -### H12. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +### H11. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity - **Location:** `model.ts:56`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. -### H13. `UpdateState.QUEUED` description references the wrong noun ("update") instead of "run" -- **Location:** `model.ts:187` ("Update is waiting for previous update to finish."). -- **Category:** 6 (misleading). -- **Suggestion:** Doc rewrite (English) after H1: "Run is waiting for previous run to finish." -- **Rationale:** Same as H1 — once `Update` is renamed to `Run`, every JSDoc that mentions "update" in this enum needs to follow. - -### H14. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +### H12. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural - **Locations:** `model.ts:1464`, plus all `notifications?: Notifications[]` field declarations. - **Category:** 9 (singular/plural mismatch). - **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. @@ -154,49 +142,34 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu - **Suggestion:** Move to `NetsuiteOptions` connector-specific type. - **Rationale:** A generic ingestion-definition type carrying a `netsuiteJarPath` field implies every other connector is incomplete. JSDoc literally says "Netsuite only configuration." Belongs in a per-connector options struct. -### M8. `IngestionSourceType.WORKDAY_RAAS` — undefined acronym -- **Location:** `model.ts:67`. -- **Category:** 5 (cryptic abbreviation). -- **Suggestion:** Document inline that RaaS = "Reports as a Service" (Workday terminology). The acronym is non-obvious. - -### M9. `IngestionSourceType.GA4_RAW_DATA` — vendor-numbered identifier -- **Location:** `model.ts:68`. -- **Category:** 5. -- **Suggestion:** Document inline that GA4 = "Google Analytics 4." - -### M10. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator +### M8. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator - **Location:** `model.ts:80`. - **Category:** 1 (vague). - **Suggestion:** `UC_FOREIGN_CATALOG` or document inline. - **Rationale:** "Foreign Catalog" is a Unity Catalog concept; without context this looks like a country-of-origin enum value. -### M11. `Origin.ucResourceId` mixes acronym casing +### M9. `Origin.ucResourceId` mixes acronym casing - **Location:** `model.ts:1528`. - **Category:** 3 (acronym casing inconsistency). - **Suggestion:** Either `ucResourceId` (current) or `UCResourceId` — the Google TS style guide says treat acronyms as words, so `ucResourceId` is correct. But sibling fields use the same lowercase pattern (`workspaceId`, `pipelineId`), so this one is internally consistent. Flagged because it could be `unityCatalogResourceId` for clarity. -### M12. `eventType?: string` on `PipelineEvent` — string-typed enum +### M10. `eventType?: string` on `PipelineEvent` — string-typed enum - **Location:** `model.ts:1765`. - **Category:** 16 (field contradicts type domain). - **Suggestion:** Define an `EventType` enum (or union of string literals) and type the field with it. Right now consumers have no IDE help. - **Rationale:** JSDoc says "The event type. Should always correspond to the details." The Go SDK has the same field as string (porting fidelity), but TS could improve. -### M13. `PipelineEvent.timestamp: string` — typed string but holds an ISO date -- **Location:** `model.ts:1757`. -- **Category:** 16. -- **Suggestion:** Document the format in JSDoc, or use a `Date | string` union. - -### M14. `Sequencing` — singular noun for a 2-field record describing one event's position +### M11. `Sequencing` — singular noun for a 2-field record describing one event's position - **Location:** `model.ts:2323`. - **Category:** 1 (vague). - **Suggestion:** `EventSequence` or `EventPosition`. "Sequencing" is the action of putting in order, not the position itself. -### M15. `EditPipelineRequest.expectedLastModified: number` — wire is millis since epoch, but no JSDoc +### M12. `EditPipelineRequest.expectedLastModified: number` — wire is millis since epoch, but no JSDoc - **Location:** `model.ts:643`. - **Category:** 16 (field contradicts type domain), 19 (underspecified ID). - **Suggestion:** Either type as `Date | number` or document "milliseconds since Unix epoch" in JSDoc. -### M16. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` +### M13. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` - **Location:** `model.ts:593`. - **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). - **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. @@ -206,74 +179,42 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## Low -### L1. `client.start()` JSDoc mentions "If there is already an active update" — should say "active run" -- **Location:** `client.ts:519`. -- **Category:** 6. - -### L2. `client.stop()` JSDoc mentions "Stops the pipeline by canceling the active update" — same -- **Location:** `client.ts:551`. - -### L3. `client.list()` JSDoc says "Lists pipelines defined in the Spark Declarative Pipelines system" -- **Location:** `client.ts:413`. -- **Category:** 6 (misleading), branding inconsistency. -- **Rationale:** The product is "Lakeflow Declarative Pipelines" per the IngestionPipelineDefinition JSDoc (`model.ts:965`). Internal naming: "Spark Declarative Pipelines" (SDP). Public marketing name: "Lakeflow Declarative Pipelines." The SDK uses both, sometimes in adjacent JSDoc. - -### L4. JSDoc references to "SDP" appear in four fields, undefined -- **Locations:** `model.ts:379` (`ClonePipelineRequest.channel` — "SDP Release Channel"), `model.ts:521` (`CreatePipelineRequest.channel`), `model.ts:682` (`EditPipelineRequest.channel`), `model.ts:1849` (`PipelineSpec.channel`), `model.ts:2085` (`PipelinesEnvironment` — "SDP's environment"). -- **Category:** 5 (cryptic abbreviation), 6 (misleading). -- **Suggestion:** Expand SDP → "Spark Declarative Pipelines" on first mention, with parenthetical "(internal name for Lakeflow Declarative Pipelines)". - -### L5. `PipelinesS3StorageInfo.cannedAcl` — undocumented S3 jargon -- **Location:** `model.ts:2248`. -- **Category:** 5. -- **Suggestion:** Document inline: "canned ACL = a predefined S3 access-control list, e.g., `bucket-owner-full-control`." Currently the field name is fine since it matches the S3 API; only the casing (`cannedAcl` not `cannedAcl` — should be `cannedACL` per Google TS style? actually `cannedAcl` is correct). - -### L6. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent +### L1. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent - **Location:** `model.ts:2238`. - **Category:** 3. - **Suggestion:** `kmsKey` is the correct casing per Google TS style. Just flagging for cross-check with other AWS fields in the file. -### L7. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system +### L2. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system - **Locations:** `model.ts:2231`, `model.ts:2236`. - **Category:** 16. - **Suggestion:** Use a discriminated union: `encryption?: {kind: 'none'} | {kind: 'sse-s3'} | {kind: 'sse-kms'; key: string}`. -### L8. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" +### L3. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" - **Location:** `model.ts:1608`. - **Category:** 16. - **Suggestion:** Make this an enum `ClusterLabel.{Default, Maintenance}`. -### L9. `PipelineCluster.applyPolicyDefaultValues` JSDoc says "won't be persisted" — should be marked deprecated or transient -- **Location:** `model.ts:1610`. -- **Category:** 6. -- **Suggestion:** Add `@deprecated` JSDoc tag. - -### L10. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc +### L4. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc - **Location:** `model.ts:333`. - **Category:** Generator artifact leakage. - **Suggestion:** Express via TS optionality (`?:`) instead of repeating "Optional" in JSDoc. -### L11. `(Required, Immutable)` / `(Optional, Mutable)` proto tags appear in many JSDoc blocks -- **Locations:** searches: `(Required`, `(Optional` throughout `model.ts` (currently ~53 occurrences). -- **Category:** Generator artifact leakage. -- **Suggestion:** Remove or move to a structured `@required` / `@mutable` tag. - -### L12. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link +### L5. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link - **Locations:** `model.ts:2299` (`cascade`), `model.ts:2301` (`resetCheckpoints`). - **Category:** 16. - **Suggestion:** Group into an `options` substruct or document interactions in JSDoc. -### L13. `KafkaOptions.startingOffset: string` — typed string but documented as enum +### L6. `KafkaOptions.startingOffset: string` — typed string but documented as enum - **Location:** `model.ts:1294`. - **Category:** 16. - **Suggestion:** Define `KafkaStartingOffset.{Latest, Earliest}` enum. -### L14. `MetaMarketingOptions.level: string` — typed string but documented as enum +### L7. `MetaMarketingOptions.level: string` — typed string but documented as enum - **Location:** `model.ts:1436`. - **Category:** 16. - **Suggestion:** Define `MetaAggregationLevel.{Account, Ad, AdSet, Campaign}` enum. -### L15. `MetaMarketingOptions.actionReportTime: string` — string enum +### L8. `MetaMarketingOptions.actionReportTime: string` — string enum - **Location:** `model.ts:1442`. - **Category:** 16. - **Suggestion:** Define enum. @@ -282,37 +223,19 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## Observations -### O1. Branding history (DLT → Lakeflow Declarative Pipelines → Spark Declarative Pipelines) leaks into several abbreviations across the public API -- **Search:** `DLT`, `SDP`, `LDP`, `Lakeflow`, `Spark Declarative Pipelines`, `Delta Live Tables`, `DAB`. -- **Locations:** `model.ts:47` (`DAB` in DeploymentKind comment), `model.ts:379` (`SDP` in `channel` JSDoc), `model.ts:956` (`Spark Declarative Pipelines` in JSDoc), `model.ts:965` (`Lakeflow Connect`), `model.ts:2085` (`SDP's environment`), `client.ts:413` (`Spark Declarative Pipelines`). -- **Suggestion:** Settle on one product name in JSDoc. The TS types should be backwards-compatible (no rename) but the docstrings should agree. - -### O2. There are FIVE separate `connectorOptions` / `sourceOptions` discriminators in the ingestion pipeline definition — connector wiring is too nested -- **Locations:** `IngestionPipelineDefinition.connectorType`, `IngestionPipelineDefinition.sourceConfigurations[].catalog.options`, `IngestionPipelineDefinition_SchemaSpec.connectorOptions`, `IngestionPipelineDefinition_TableSpec.connectorOptions`. -- **Suggestion:** Document the resolution order between schema-level and table-level options. JSDoc currently fragments the rules across multiple types. - -### O3. JSDoc uses `` placeholder — leak from the Go SDK's template substitution -- **Search:** `` appears 18 times in `model.ts`. -- **Suggestion:** Replace with literal "Databricks" before TS compilation. - -### O4. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` +### O1. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` - **Location:** `model.ts:1476`. - **Category:** 16. - **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. -### O5. `OutlookOptions` carries three `*Filter` fields marked deprecated (`folderFilter`, `senderFilter`, `subjectFilter`) plus the new `include*` versions side-by-side -- **Locations:** `model.ts:1546-1599`. -- **Category:** Generator artifact / Go-SDK fidelity issue. -- **Suggestion:** Mark deprecated fields with `@deprecated` JSDoc tag (currently only mentioned in plain text). - -### O6. `ConnectorOptions` JSDoc opens with "Wrapper message for source-specific options" — proto-architectural terminology leak +### O2. `ConnectorOptions` JSDoc opens with "Wrapper message for source-specific options" — proto-architectural terminology leak - **Location:** `model.ts:456`. - **Why:** "Wrapper message" is a protobuf concept (the proto2/proto3 well-known wrapper types: `BoolValue`, `StringValue`, etc., plus the generic "wrapper message" pattern used to box discriminated unions). It is visible in user-facing JSDoc on a public interface. - **Category:** Generator artifact leakage / proto-architectural leak. - **Suggested:** Rewrite JSDoc as "Source-specific options for ingestion connectors. Exactly one option must be specified for the connector type." Drop "Wrapper message". - **Rationale:** TypeScript developers do not know what a "wrapper message" is — the term reveals the proto IDL underneath. The shape is just a discriminated union over connector option types; describe it in TS terms. -### O7. `Internal` proto-field tag leaks into JSDoc on two public fields +### O3. `Internal` proto-field tag leaks into JSDoc on two public fields - **Locations:** `model.ts:959` (`IngestionGatewayPipelineDefinition.connectionParameters` — "Optional, Internal. Parameters required to establish an initial connection with the source."), `model.ts:1295` (`KafkaOptions.maxOffsetsPerTrigger` — "Internal option to control the maximum number of offsets to process per trigger."). - **Why:** `Internal` is a proto-level annotation (`google.api.field_visibility = INTERNAL` or similar) indicating the field is not part of the public API surface. If these fields are truly internal, they should be stripped from the public SDK at generation time; if they are public, the "Internal" label should not appear in user-visible documentation. - **Category:** Generator artifact leakage / proto-architectural leak. diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index 5eb2583e..f95f6de7 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -118,11 +118,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| M-01 | `getPolicyFamily()` JSDoc (`client.ts:61`): "an policy family" | Low | Typo in the JSDoc ("an" should be "a"). Not a naming issue but a generator artifact worth fixing upstream. | -| M-02 | `listPolicyFamilies()` JSDoc (`client.ts:92`): "list of policy definition types" | Medium | The method returns *policy families*, but the JSDoc paraphrases them as "policy definition types". Mismatched terminology between the method name (`PolicyFamily`) and its docstring will confuse readers. Method/type/route all say "family"; doc should too. | -| M-03 | `GetPolicyFamilyRequest` JSDoc (`model.ts:5`): "Returns the details of a policy family at a specific version" | Low | The JSDoc describes the *operation*, not the request body. The type is a request shape, not a response. Convention across the SDK, OK but slightly misleading on first read. | -| M-04 | `ListPolicyFamiliesRequest` JSDoc (`model.ts:13`): "Returns the list of policy families…" | Low | Same as M-03 — the JSDoc describes the operation rather than the request shape. | -| M-05 | `Client` (`client.ts:36`) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | +| M-01 | `Client` (`client.ts:36`) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | ### 2.7 Overly verbose / Redundant suffixes — Medium @@ -158,7 +154,6 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | D-01 | `PolicyFamily.policyFamilyId` (here) and `Policy.policyFamilyId` (in `clusterpolicies`) | Low | The field name is consistent across packages — good. No duplication concern. | -| D-02 | `PolicyFamily` vs `Policy` (cross-package) | Low | Distinct concepts: a `PolicyFamily` is a template, a `Policy` is an instance. Cross-package linking (JSDoc `{@link}`) would help readers understand the relationship. Out of scope for naming. | ### 2.12 Verb-tense inconsistency — Low @@ -239,7 +234,7 @@ _None._ | X-09 | `pageReq` (local in `client.ts:133`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | | X-10 | `index.ts:5` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | | X-11 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | -| X-12 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-05. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | +| X-12 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-01. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | --- @@ -250,9 +245,9 @@ _None._ | Severity | Count | | -------- | ----- | | High | 2 | -| Medium | 6 | -| Low | 28 | -| **Total**| **36**| +| Medium | 5 | +| Low | 24 | +| **Total**| **31**| ### 3.2 Top themes @@ -273,9 +268,6 @@ _None._ (non-breaking renames are not possible — this section is advisory for the codegen owners) -- Fix the JSDoc on `getPolicyFamily()` ("an policy family" → "a policy - family") and on `listPolicyFamilies()` ("policy definition types" → - "policy families"). - Rename `Client` → `PolicyFamiliesClient` for cross-package disambiguation. (Repo-wide pattern; flag at codegen layer.) - Flatten `ListPolicyFamiliesRequest_Response` → `ListPolicyFamiliesResponse` diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index 2e9150c4..f4a67d70 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -3,15 +3,15 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Catalog`s (Unity Catalog mirrors of logical PG databases), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Operation` waiter-style classes. -**Total weird names flagged:** 33 +**Total weird names flagged:** 29 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 16 | -| Low | 6 | -| Observation | 2 | +| Medium | 15 | +| Low | 4 | +| Observation | 1 | ## High severity @@ -91,88 +91,82 @@ - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 12. `CreateBranchRequest.branch` vs `CreateBranchRequest.branchId` — duplicate identifier semantics — `src/v1/model.ts:907, 909` -- **Why weird:** `CreateBranchRequest` has `parent`, `branchId`, `branch`, `replaceExisting`. `branchId` is the path-component id; `branch.name` (inside `Branch`) is the full resource path; `branch` is the body. Three fields all involved in identifying the branch. -- **Category:** 17 (inconsistency — same operation, three id-like fields), 19 (underspecified id semantics). -- **Suggested name:** Document the relationship clearly in JSDoc; or accept just `branch: Branch` and derive the id from `branch.name`. -- **Rationale:** Same shape repeats on `CreateCatalogRequest`, `CreateDatabaseRequest`, `CreateEndpointRequest`, `CreateProjectRequest`, `CreateRoleRequest`, `CreateSyncedTableRequest`. Caller must read multiple field docs to know which ID to set. - -### 13. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` +### 12. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` - **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. - **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). - **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). - **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. -### 14. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` +### 13. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` - **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. - **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). - **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. - **Rationale:** Three identifier slots is too many. -### 15. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` +### 14. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` - **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. - **Category:** 5 (cryptic abbreviation), 1 (vague suffix). - **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. - **Rationale:** "CU" is Lakebase-internal slang. -### 16. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` +### 15. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` - **Why weird:** Same pattern as #11 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. - **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #11). - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. - **Rationale:** Same as #11. -### 17. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #25 +### 16. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #24 _Reserved._ -### 18. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` +### 17. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` - **Why weird:** Plain `Record`. The 21 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1524-1533` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. - **Category:** 15 (generic), 16 (loose typing). - **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. - **Rationale:** Same root cause as #7 — opaque records on the public surface. -### 19. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` +### 18. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` - **Why weird:** Variant `response` carries `Record` (line 1597). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) - **Category:** 16 (asymmetric typing), 15 (generic on success arm). -- **Suggested name:** Same as #18 — generic `Operation` with both arms typed. -- **Rationale:** Same as #7, #18. +- **Suggested name:** Same as #17 — generic `Operation` with both arms typed. +- **Rationale:** Same as #7, #17. -### 20. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` +### 19. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` - **Why weird:** `Project` carries an `initialEndpointSpec` field that is a create-time-only input but exposed on the response type too — a read-flow consumer sees a field that is typically empty after project creation. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). - **Suggested name:** Hoist the `initialEndpointSpec` onto `CreateProjectRequest` only (where it belongs); leave `Project` to spec/status. - **Rationale:** Same as `database` audit #12 — input/output shape confusion. -### 21. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` +### 20. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` - **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. - **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). - **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. - **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. -### 22. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` +### 21. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` - **Why weird:** Doc says "The major Postgres version number. The set of supported versions may vary; consult the API documentation for currently accepted values." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. - **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). - **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. - **Rationale:** Aligns documented constraints with the type system. -### 23. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` +### 22. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` - **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. - **Category:** 17 (inconsistent with sister package). - **Suggested name:** Pick one convention across the two packages. - **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. -### 24. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` +### 23. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` - **Why weird:** Same as `database` audit #36: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Same as `database` audit #36. -### 25. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` +### 24. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` - **Why weird:** Identical to `database` audit findings on synced-table-spec naming. Won't re-state at length; flag that the duplication exists across both packages with identical naming. Other related fields (`acceleratedSync`, `extraIndexDefinitions`, `extraColumnDefinitions`, `typeOverrides`) were removed during regeneration; only the `createDatabaseObjectsIfMissing` "If Missing" pattern remains here, matching `database` package's similar wording. - **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). - **Suggested name:** Same suggestions as `database` audit. - **Rationale:** Two SDKs, same problems. -### 26. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` +### 25. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` - **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. - **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). - **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. @@ -180,52 +174,34 @@ _Reserved._ ## Low severity -### 27. `BranchSpec.expireTime` (inside union variant) vs `BranchStatus.expireTime` (top-level) — `src/v1/model.ts:743, 788` -- **Why weird:** Field name `expireTime` appears twice: once as a discriminated-union variant on `BranchSpec` (input), once as a top-level field on `BranchStatus` (output). Reader has to track that the input shape collapses `expireTime`/`ttl`/`noExpiry` to a single output value `expireTime`. -- **Category:** 17 (input/output shape mismatch). -- **Suggested name:** Document the asymmetry in JSDoc; or expose the same union shape on output. -- **Rationale:** Generator-driven asymmetry. - -### 28. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` +### 26. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` - **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete now uses `purge: boolean` only (`allowMissing` field removed in regeneration). Mismatched conventions for "if it does/doesn't exist" remain. - **Category:** 17 (inconsistent action verbs across CRUD). - **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. - **Rationale:** Inconsistent options across CRUD operations is a small papercut. -### 29. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` +### 27. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` - **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete." Same `purge` field on `DeleteProjectRequest` (line 1142). - **Category:** 16 (boolean modeling a future 3-state field), 6 (misleading — purge implies cleanup, not the *only* delete mode). - **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. - **Rationale:** Boolean toggle for a future-3-state field. -### 30. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` +### 28. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` - **Why weird:** Same as `database` audit #54 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Same as `database` audit #54 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. - **Rationale:** Same as `database` audit #54. -### 31. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` +### 29. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` - **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1552`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. - **Rationale:** Tri-state booleans always confuse callers. -### 32. `Branch.spec.expiration` JSDoc mentions `update_mask` (snake_case) — `src/v1/model.ts:734, 741, 749, 758, 1291, 1299, 1308, 1656, 1665` -- **Why weird:** JSDoc references update mask in snake_case (e.g. "When updating this field, use `spec.expiration` in the update_mask"). Update mask field on the request is `updateMask: FieldMask<...>` (camelCase) but docs reference the wire-format name. Consumer reading the JSDoc and writing TS code has to translate. -- **Category:** 17 (inconsistent — JSDoc snake_case, TS camelCase). -- **Suggested name:** Use TS field name in JSDoc. -- **Rationale:** Doc/code drift. - ## Observation -### 33. Method JSDoc inconsistency — `src/v1/client.ts` throughout -- **Why weird:** Some methods have rich JSDoc ("Creates a new database branch in the project.", "Register a Postgres database in the Unity Catalog."). Others are terse ("Create a Database.", "Get a Database.", "List Databases."). Inconsistency in doc depth across CRUD methods of the same resource. -- **Category:** Observation (doc quality, not naming). -- **Suggested name:** Standardise to the richer template. -- **Rationale:** Naming-adjacent. - -### 34. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` +### 30. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` - **Why weird:** All 21 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#8) or reads `Operation.result.response` (untyped `Record`). - **Category:** Observation (architecture, not naming per se). - **Suggested name:** `Operation` generic. -- **Rationale:** Connects #7, #8, #18, #19. +- **Rationale:** Connects #7, #8, #17, #18. diff --git a/.agent/naming-audit/qualitymonitor.md b/.agent/naming-audit/qualitymonitor.md deleted file mode 100644 index db816e2f..00000000 --- a/.agent/naming-audit/qualitymonitor.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: qualitymonitor - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/qualitymonitors.md b/.agent/naming-audit/qualitymonitors.md deleted file mode 100644 index 7f4373d9..00000000 --- a/.agent/naming-audit/qualitymonitors.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: qualitymonitors - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index 46de97ba..b97cffc5 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 21 (last rescanned 2026-05-26) +**Total weird names flagged:** 20 (last rescanned 2026-05-26) ## Summary table @@ -29,7 +29,6 @@ | 18 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | | 19 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | | 20 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | -| 21 | Low | `model.ts` JSDoc | snake_case identifiers in JSDoc (e.g. "`dynamic_date_value` or `date_value`") | Wire-format leakage into TS docstrings | ## High severity @@ -308,19 +307,6 @@ startDayOfWeek?: number | undefined; Standard Google AIP-158 names. Flagged for completeness; no action recommended. -### 21. snake_case in JSDoc — `dynamic_date_value`, `date_value`, etc. - -**Location:** `src/v1/model.ts:292`, `297` - -```ts -/** Date query parameter value. Can only specify one of `dynamic_date_value` or `date_value`. */ -dateValue: DateValue; -/** Date-range query parameter value. Can only specify one of `dynamic_date_range_value` or `date_range_value`. */ -dateRangeValue: DateRangeValue; -``` - -The JSDoc references wire-format field names (snake_case) but the user is writing TS code that uses camelCase (`dynamicDateValue`, `dateValue`). Wire-format leakage; doc should reference the TS oneof discriminator names. - ## Cross-package overlap The four query-flavoured packages share concept space without sharing types: @@ -342,13 +328,11 @@ Observations: 1. **`Query` overload.** `Query` is one of the broadest words in any SQL SDK. This package's `Query` is a *saved* configuration; `queryexecution`'s implicit "query" is a *running statement*; `queryhistory`'s `QueryInfo` is a *historical record*. None reference each other. A future cleanup might rename this package's `Query` → `SavedQuery` or `WorkspaceQuery`. -2. **Wire-format leakage in JSDoc.** snake_case identifiers appear in JSDoc (e.g. `dynamic_date_value`, `date_value`) — the docs reference protobuf field names while the user is writing camelCase TS. - -3. **Soft-delete verb is `trash`, not `delete`.** `trashQuery` and `LifecycleState.TRASHED` are the only places in the SDK using "trash." This will diverge from the rest of the resource lifecycle vocabulary as the SDK grows. +2. **Soft-delete verb is `trash`, not `delete`.** `trashQuery` and `LifecycleState.TRASHED` are the only places in the SDK using "trash." This will diverge from the rest of the resource lifecycle vocabulary as the SDK grows. -4. **Top-level type pollution.** `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRange`, `DateRangeValue`, `MultiValuesOptions`, `Visualization` are all unprefixed and exported. A user importing `import { TextValue } from '@databricks/sdk-queries'` gets a generically-named type that competes with their own code. +3. **Top-level type pollution.** `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRange`, `DateRangeValue`, `MultiValuesOptions`, `Visualization` are all unprefixed and exported. A user importing `import { TextValue } from '@databricks/sdk-queries'` gets a generically-named type that competes with their own code. -5. **`utils.ts` is well-named and unchanged.** Exports (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are domain-neutral and not flagged. `flattenQueryParams` is exported but unused in `client.ts` (orphaned export) — not a naming issue, but worth noting. +4. **`utils.ts` is well-named and unchanged.** Exports (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are domain-neutral and not flagged. `flattenQueryParams` is exported but unused in `client.ts` (orphaned export) — not a naming issue, but worth noting. ## Domain glossary diff --git a/.agent/naming-audit/queryexecution.md b/.agent/naming-audit/queryexecution.md deleted file mode 100644 index ca1ebced..00000000 --- a/.agent/naming-audit/queryexecution.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: queryexecution - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 73fe213f..8fecb192 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -13,10 +13,10 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 2 | -| Medium | 3 | +| Medium | 1 | | Low | 5 | | Observation | 4 | -| **Total** | **14** | +| **Total** | **12** | Headline themes: @@ -56,22 +56,6 @@ Headline themes: - **Suggestion:** `Quota`. - **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O2. -### M2. `quotaCount` and `quotaLimit` carry no unit / type signal — counts of *what*? - -- **File / line:** `src/v1/model.ts:68, 70`. -- **Category:** #1 vague/generic; #19 underspecified. -- **Current:** `quotaCount?: number`, `quotaLimit?: number`. -- **Suggestion:** Inline-doc the unit and reference what is being counted (number of *child securables*). -- **Rationale:** From the field names alone, a reader doesn't know whether these are counts of children, megabytes, requests, etc. The package-level JSDoc on `client.ts:62` clarifies that quotas count child entities (e.g. tables under a schema), but the field-level doc says only "current usage of the resource quota" and "current limit of the resource quota." Names like `currentUsage` / `currentLimit` or doc-strings citing "number of child securables" would close the gap. - -### M3. `nextPageToken` doc references `__page_token__` with double underscores - -- **File / line:** `src/v1/model.ts:55` (JSDoc on `ListQuotasRequest_Response.nextPageToken`). -- **Category:** #5 cryptic abbreviation; documentation defect more than naming defect, but mentions identifier syntax that doesn't exist. -- **Current:** `"__page_token__ should be set to this value for the next request."` -- **Suggestion:** Reference the actual TS field name `pageToken` (camelCase) in prose. -- **Rationale:** The double-underscore markdown bolding for `page_token` (the wire form) leaks the snake_case wire field into the public TS docs. Callers don't see `page_token`; they see `pageToken`. The doc misleads. - --- ## Low Severity @@ -175,18 +159,18 @@ Type & symbol checklist: - [x] `GetQuotaRequest.quotaName` → no defect. - [x] `GetQuotaRequest_Response` interface (1 field) → Wrapper preserved for forward compatibility. - [x] `GetQuotaRequest_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). -- [x] `ListQuotasRequest` interface (2 fields) → no per-field defects beyond M3. +- [x] `ListQuotasRequest` interface (2 fields) → no defect. - [x] `ListQuotasRequest.maxResults` → no defect. - [x] `ListQuotasRequest.pageToken` → no defect. -- [x] `ListQuotasRequest_Response` interface (2 fields) → M3. +- [x] `ListQuotasRequest_Response` interface (2 fields) → no defect. - [x] `ListQuotasRequest_Response.quotas` → no defect; correctly plural. -- [x] `ListQuotasRequest_Response.nextPageToken` → M3. +- [x] `ListQuotasRequest_Response.nextPageToken` → no defect. - [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix), O1; per-field below. - [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H2. - [x] `QuotaInfo.parentFullName` → no defect. - [x] `QuotaInfo.quotaName` → no defect. -- [x] `QuotaInfo.quotaCount` → M2. -- [x] `QuotaInfo.quotaLimit` → M2. +- [x] `QuotaInfo.quotaCount` → no defect. +- [x] `QuotaInfo.quotaLimit` → no defect. - [x] `QuotaInfo.lastRefreshedAt` → no defect. - [x] `Client` class → L2. - [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. @@ -213,13 +197,12 @@ Type & symbol checklist: | `ListQuotasRequest` | model.ts:42 | — | | `ListQuotasRequest.maxResults` | model.ts:44 | — | | `ListQuotasRequest.pageToken` | model.ts:46 | — | -| `ListQuotasRequest_Response.nextPageToken` (doc) | model.ts:55-57 | M3 | | `QuotaInfo` | model.ts:60 | M1, O1 | | `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H2 | | `QuotaInfo.parentFullName` | model.ts:64 | — | | `QuotaInfo.quotaName` | model.ts:66 | — | -| `QuotaInfo.quotaCount` | model.ts:68 | M2 | -| `QuotaInfo.quotaLimit` | model.ts:70 | M2 | +| `QuotaInfo.quotaCount` | model.ts:68 | — | +| `QuotaInfo.quotaLimit` | model.ts:70 | — | | `QuotaInfo.lastRefreshedAt` | model.ts:72 | — | | `Client` (bare name) | client.ts:37 | L2 | | `PACKAGE_SEGMENT` | client.ts:32 | O3 | diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index b2a1142f..3e0ef80c 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -34,12 +34,7 @@ _None._ ### 2. Acronym casing inconsistencies -#### 2.1 "UC" / "Unity Catalog" inconsistency in URLs and doc text -The endpoint path is `/api/2.1/unity-catalog/schemas` (client.ts:77, -106, etc.) and the package docs spell out "Unity Catalog" / "the -Metastore" (client.ts:71). No identifier in the package uses `UC` — -only doc comments. Minor inconsistency, but flagged for cross-package -review. +_None._ --- @@ -262,16 +257,12 @@ No `fetch…` / `retrieve…` / `read…` outliers. No issues found. ### 13. Underspecified IDs -#### 13.1 `metastoreId` (model.ts:29, 138, 196) -Documented as "unique identifier of parent metastore". Format opaque -(UUID? slug?). Acceptable but unspecified. - -#### 13.2 `schemaId` (model.ts:48, 157, 215) +#### 13.1 `schemaId` (model.ts:48, 157, 215) "The unique identifier of the schema." No format hint (UUID?). The field exists alongside `fullName` (which is also a unique identifier in a different sense). Two simultaneous IDs without disambiguation. -#### 13.3 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) +#### 13.2 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) Both `string`. `inheritedFromType` could be one of the UC securable types, but the field is not enum-typed. `inheritedFromName` is opaque text. diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index 51e4d946..80b46007 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -21,9 +21,9 @@ Notation: file paths are relative to the package root. Findings reference | ----------- | ----- | | High | 3 | | Medium | 5 | -| Low | 8 | -| Observation | 5 | -| **Total** | **21** | +| Low | 4 | +| Observation | 4 | +| **Total** | **16** | Headline themes: @@ -225,57 +225,7 @@ Headline themes: enum (`'READ' | 'WRITE' | 'MANAGE'`). If the server adds a new permission level, zod will throw at decode. Not a name issue, just notable. -### L2. `PutSecretRequest.value` `stringValue` JSDoc references "UTF-8 (MB4)" - -- **File / line:** `src/v1/model.ts:166`. -- **Category:** #5 cryptic abbreviations. -- **Current JSDoc:** "If specified, note that the value will be stored in - UTF-8 (MB4) form." -- **Issue:** "MB4" likely means "MySQL utf8mb4" (4-byte UTF-8); an opaque - abbreviation outside the MySQL ecosystem. A TS API consumer has no - reason to know MySQL trivia. -- **Suggestion:** clarify or drop. "UTF-8 with full BMP support" or just - "UTF-8". This is a doc issue, not a name issue per se, but a naming - audit notices it. - -### L3. `principal` is a single field used for both users and groups - -- **Files / lines:** `model.ts:38, 69, 97, 150`. -- **Category:** #1 vague/generic. -- **Current:** `principal?: string | undefined` — JSDoc says "The principal - in which the permission is applied." `client.ts:562-594` clarifies: - "user or group name". -- **Suggestion:** acceptable as-is, as "principal" is the Databricks - platform-wide term for user-or-group; consistent with other packages. - Flagging only because a casual reader sees `principal` and may not - realize they should pass either a username or group name. JSDoc on the - request types could explicitly say "(user or group name)". - -### L4. `req.scope` is documented inconsistently across types - -- **Files / lines:** `model.ts:52, 67, 77, 85, 95, 102, 117, 137, 148, 160`. -- **Category:** observation; documentation only. -- **Current:** various JSDoc: - - `CreateScopeRequest.scope`: "Scope name requested by the user. Scope - names are unique." - - `DeleteAclRequest.scope`: "The name of the scope to remove permissions - from." - - `DeleteScopeRequest.scope`: "Name of the scope to delete." (no "the") - - `DeleteSecretRequest.scope`: "The name of the scope that contains the - secret to delete." -- **Suggestion:** the JSDocs are written by hand per-operation, with minor - grammar variation. Not a naming defect; flagging because it makes - cross-reference annoying. - -### L5. `ScopeBackendType` values include only two cases despite the JSDoc - -- **File / line:** `src/v1/model.ts:16-30`. -- **Category:** observation. -- **JSDoc:** "Azure KeyVault backed secret scopes will be supported in a - later release." The release shipped; the doc string is stale. Not a - naming issue but indicates the file is not maintained tightly. - -### L6. `flattenQueryParams` is dead code in this package +### L2. `flattenQueryParams` is dead code in this package - **File / line:** `src/v1/utils.ts:123`. - **Category:** #21 dead code. @@ -285,7 +235,7 @@ Headline themes: generator-wide. - **Suggestion:** drop dead code, or move it to a shared utils package. -### L7. `executeCall` vs `executeHttpCall` name collision +### L3. `executeCall` vs `executeHttpCall` name collision - **Files / lines:** `src/v1/utils.ts:26, 65`. - **Category:** #17 inconsistent action verbs. @@ -293,7 +243,7 @@ Headline themes: `executeCall` (sets options + dispatches retries) and `executeHttpCall` (one HTTP roundtrip). Same defect cataloged in other audits. -### L8. `PACKAGE_SEGMENT` constant is vague +### L4. `PACKAGE_SEGMENT` constant is vague - **File / line:** `src/v1/client.ts:65`. - **Category:** #1 vague/generic. diff --git a/.agent/naming-audit/serviceprincipalsecrets.md b/.agent/naming-audit/serviceprincipalsecrets.md deleted file mode 100644 index 671b25f2..00000000 --- a/.agent/naming-audit/serviceprincipalsecrets.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: serviceprincipalsecrets - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspace.md b/.agent/naming-audit/workspace.md deleted file mode 100644 index 0d68e152..00000000 --- a/.agent/naming-audit/workspace.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: workspace - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspaceassignment.md b/.agent/naming-audit/workspaceassignment.md deleted file mode 100644 index b49d36ae..00000000 --- a/.agent/naming-audit/workspaceassignment.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: workspaceassignment - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspaceconf.md b/.agent/naming-audit/workspaceconf.md deleted file mode 100644 index 86ac761b..00000000 --- a/.agent/naming-audit/workspaceconf.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: workspaceconf - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. diff --git a/.agent/naming-audit/workspacesettings.md b/.agent/naming-audit/workspacesettings.md deleted file mode 100644 index 1fd9627e..00000000 --- a/.agent/naming-audit/workspacesettings.md +++ /dev/null @@ -1,3 +0,0 @@ -# Naming Audit: workspacesettings - -> **Status: Package source removed/consolidated in regeneration on 2026-05-22.** Package consolidated into a successor or dropped. All findings retired. From d9ac41e72619c4dcb3090b808c2762ab277ead63 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 26 May 2026 22:18:50 +0000 Subject: [PATCH 09/12] update --- .agent/naming-audit/_SUMMARY.md | 157 ++++++--- .agent/naming-audit/abacpolicies.md | 43 +-- .agent/naming-audit/accessmanagement.md | 76 +---- .agent/naming-audit/apps.md | 58 +--- .agent/naming-audit/artifactallowlists.md | 122 +------ .agent/naming-audit/billableusagedownload.md | 67 +--- .agent/naming-audit/budgetpolicy.md | 68 +--- .agent/naming-audit/budgets.md | 252 ++------------- .agent/naming-audit/bundle.md | 33 +- .agent/naming-audit/catalogs.md | 45 +-- .agent/naming-audit/cleanrooms.md | 14 +- .agent/naming-audit/clusterlibraries.md | 12 +- .agent/naming-audit/clusterpolicies.md | 63 +--- .agent/naming-audit/clusters.md | 153 ++------- .agent/naming-audit/commandexecution.md | 38 +-- .agent/naming-audit/connections.md | 48 +-- .agent/naming-audit/credentials.md | 50 +-- .agent/naming-audit/customllms.md | 72 +---- .agent/naming-audit/database.md | 80 ++--- .agent/naming-audit/dataclassification.md | 68 +--- .agent/naming-audit/dataquality.md | 64 +--- .agent/naming-audit/disasterrecovery.md | 40 +-- .agent/naming-audit/entitytagassignments.md | 83 +---- .agent/naming-audit/environments.md | 48 +-- .agent/naming-audit/experiments.md | 114 +++---- .agent/naming-audit/externallineage.md | 64 +--- .agent/naming-audit/externallocations.md | 43 ++- .agent/naming-audit/externalmetadata.md | 80 +---- .agent/naming-audit/features.md | 54 ++-- .agent/naming-audit/featurestore.md | 63 +--- .agent/naming-audit/files.md | 45 +-- .agent/naming-audit/forecasting.md | 10 - .agent/naming-audit/functions.md | 35 +- .agent/naming-audit/gitcredentials.md | 2 +- .agent/naming-audit/globalinitscripts.md | 33 +- .agent/naming-audit/grants.md | 22 +- .agent/naming-audit/iam.md | 41 +-- .agent/naming-audit/instancepools.md | 33 +- .agent/naming-audit/instanceprofiles.md | 29 +- .agent/naming-audit/knowledgeassistants.md | 56 +--- .agent/naming-audit/lakeview.md | 25 +- .agent/naming-audit/logdelivery.md | 51 +-- .agent/naming-audit/marketplaces.md | 20 +- .agent/naming-audit/metastores.md | 45 +-- .agent/naming-audit/modelregistry.md | 113 +++---- .agent/naming-audit/modelserving.md | 40 +-- .agent/naming-audit/modelservingquery.md | 32 +- .../naming-audit/notificationdestinations.md | 54 +--- .agent/naming-audit/oauth.md | 14 +- .agent/naming-audit/onlinetables.md | 43 ++- .agent/naming-audit/policyfamilies.md | 45 +-- .agent/naming-audit/postgres.md | 84 +++-- .agent/naming-audit/queries.md | 2 - .agent/naming-audit/queryhistory.md | 92 +----- .agent/naming-audit/registeredmodels.md | 40 +-- .agent/naming-audit/repos.md | 69 +--- .agent/naming-audit/resourcequotas.md | 63 +--- .agent/naming-audit/rfa.md | 116 ++----- .agent/naming-audit/schemas.md | 181 ++++------- .agent/naming-audit/scim.md | 36 +-- .agent/naming-audit/secrets.md | 66 +--- .agent/naming-audit/secretsuc.md | 18 +- .agent/naming-audit/settings.md | 168 +++------- .agent/naming-audit/statementexecution.md | 101 ++---- .agent/naming-audit/supervisoragents.md | 121 +------ .agent/naming-audit/systemschemas.md | 26 +- .agent/naming-audit/tables.md | 299 +++--------------- .agent/naming-audit/tagassignments.md | 100 +----- .agent/naming-audit/tagpolicies.md | 54 +--- .agent/naming-audit/tokenmanagement.md | 30 +- .agent/naming-audit/tokens.md | 80 +---- .agent/naming-audit/usagedashboards.md | 50 +-- .agent/naming-audit/usagepolicy.md | 114 ++----- .agent/naming-audit/vectorsearch.md | 66 ++-- .agent/naming-audit/volumes.md | 134 +------- .agent/naming-audit/warehouses.md | 137 +------- .agent/naming-audit/workspacebindings.md | 74 +---- .agent/naming-audit/workspaceobjects.md | 88 +----- .agent/naming-audit/workspaces.md | 13 - AGENTS.md | 4 +- 80 files changed, 1094 insertions(+), 4292 deletions(-) diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index 74ce6092..2ab3adf5 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,9 +1,9 @@ # Cross-Package Naming Audit — Executive Summary -**Packages audited:** 87 active API packages (every package under `packages//src//` after the 2026-05-22 generator regen consolidation). An additional 24 audit files exist for packages that were removed or consolidated in the regen; those audits are retired and their finding counts are excluded from the active total. See "Retired audits" at the bottom of §6. -**Total active findings across all 87 active audits:** **2,891** (down from 2,926 before the 2026-05-22 Theme 2 prune; 3,572 before the 2026-05-22 regen + rescan; previously 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep). The 2026-05-22 Theme 2 prune removed ~35 active findings across 20 packages whose `Foo*` package-prefix issues were the sole concern; the remaining 32 candidate audits had no matching findings. +**Packages audited:** 87 active API packages (every package under `packages//src//`). The 24 orphan audit files that previously existed for packages retired in the 2026-05-22 regen were deleted on 2026-05-26 (see Prune note 8); per-package audits are now strictly limited to packages with live source. +**Total active findings across all 87 active audits:** **1,598** (down from 2,891 before the 2026-05-26 cleanup pass — a 45% reduction. Earlier waypoints: 2,926 before the 2026-05-22 Theme 2 prune; 3,572 before the 2026-05-22 regen + rescan; 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep.) The 2026-05-26 cleanup pass removed ~1,500 findings via five Workflow B prune passes (AIP `name`, sibling-state-enum, field-rename, doc-change, SDK-internal + non-TS), the deletion of 23 orphan audit files, and the removal of `## Fixed` sections from every audit (a small note in this summary now captures the historical "fixed" delta). **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` -**Last source state:** Rescan against generator state 2026-05-22, upstream API version `0555d6a59265799ed8ea12f355eee662e739430d`. +**Last source state:** Rebase onto main + rescan on 2026-05-26 against generator regen #156 + acronym renames (PR #148). Upstream API version `0555d6a59265799ed8ea12f355eee662e739430d`. > **Prune note 1.** The original audit included a cross-cutting theme > "Empty / trivial wrapper interfaces" (empty `*_Response` interfaces, @@ -99,6 +99,78 @@ > (marked retired in place), generator recommendations (§8.6 > removed), Top-50, and by-the-numbers table below. +> **Prune pass 8 (2026-05-26) — corpus cleanup.** Combined rebase + +> rescan + orphan deletion + five Workflow B prune passes. Combined +> removals ~1,500 findings (2,891 → 1,598). Components, in +> chronological order: +> +> 1. **Rebase + rescan against regen #156 + acronym renames +> (PR #148).** All 87 active audits rescanned. `logdelivery` +> moved one finding to `Fixed`; remaining audits had minor line +> drift only. +> 2. **`## Fixed` sections removed from every audit** per user +> direction ("remove the entries which are fixed... I think it's +> good to just have a small note in the summary.md which we +> already have"). Audit files now only carry active findings; the +> historical "fixed" delta is summarised in this document. +> 3. **23 orphan / retired audit files deleted** per user direction +> ("Please remove the complete file if there is no issue in +> it... do it for every packages like this"). The 23 deleted: +> `accountaccesscontrol`, `accountaccesscontrolproxy`, +> `accountsettings`, `cleanroomassets`, +> `cleanroomautoapprovalrules`, `cleanroomtaskruns`, `endpoints`, +> `indexes`, `logdeliveryconfigurations`, `materializedfeatures`, +> `modelservingdebug`, `modelservingmanagement`, +> `oauthcustomappintegration`, `oauthpublishedapp`, +> `permissions`, `qualitymonitor`, `qualitymonitors`, +> `queryexecution`, `serviceprincipalsecrets`, +> `serviceprincipalsecretsproxy`, `workspace`, +> `workspaceassignment`, `workspaceconf`, `workspacesettings`. +> (Note: `serviceprincipalsecretsproxy` had already been deleted +> earlier; the active count of deleted files in this pass is +> 23.) The "Retired audits" table at the bottom of §6 is now +> historical reference only. +> 4. **AIP `name` pattern prune** — ~20 findings removed across the +> 31-package scope per user direction ("the name pattern is well +> established in the AIP"). Findings citing the AIP-mandated +> `name` field on Get/Update/Delete requests are no longer +> flagged. +> 5. **Sibling-state-enum prune** — ~5 findings removed across the +> 6-package scope per user direction ("not possible to fix +> without changing the api"). Cross-package state-enum +> duplicates that would require an API change to fix are no +> longer flagged. +> 6. **Field-rename prune** — ~773 findings removed across all 87 +> audits per user direction ("if i change the field name it +> would make the sdk quite different from the api itself"). +> Field-level rename findings (the single largest category by +> incidence) are no longer in scope. Field-name vocabulary drift +> and underspecified-ID findings that boil down to a rename are +> out. +> 7. **Doc-change prune** — ~300 findings removed across all 87 +> audits per user direction ("those can be anytime"). JSDoc +> text, banner-comment, and prose-deprecation findings are no +> longer flagged: the doc surface is a follow-up sweep, not part +> of the structural naming corpus. +> 8. **SDK-internal prune** — ~400 findings removed for +> identifiers that are never re-exported. Coverage: `utils.ts` +> helpers (`executeCall`, `executeHttpCall`, `flattenQueryParams`, +> `readAll`, `HttpCallOptions`, `buildHttpRequest`, +> `PACKAGE_SEGMENT`, `Call`, `pkgJson`), local variables in +> `client.ts` (`req`, `resp`, `opts`), and other internal +> plumbing. Per user direction ("they don't get reexported"). +> 9. **Non-TS prune** — ~70 findings removed for `CHANGELOG.md`, +> `NEXT_CHANGELOG.md`, `package.json`, build / lint workflows, +> and other non-source files. Per user direction ("make sure for +> all packages that recommendations are strictly for the ts +> code"). +> +> The combined pass shrunk every category. The dominant remaining +> findings are now structural type-level issues: +> reserved-word collisions, brand drift, post-merge friction in +> the consolidated packages, cross-package duplicate concepts, and +> proto-architectural leaks that survived the regen. + > **Rescan note (2026-05-20).** The generator was re-run and the > per-package audits were rescanned against the new source state. The > rescan dropped **710 findings net** and closed out several structural @@ -231,31 +303,35 @@ formats; the Databricks JS SDK currently does not. Ranked by approximate package incidence. Each theme is a generator-level defect — one template change fixes ~87 packages. -### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~70/87 packages +### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~30/87 packages (shrunk by the 2026-05-26 field-rename prune) The Go SDK uses `Info` to name "details of an X" because Go does not have package-qualified imports for types. TS does, and `` alone -suffices. Examples: +suffices. The 2026-05-26 field-rename prune removed the field-side +incidence of this theme (e.g. `repo?: RepoInfo` is no longer flagged as a +field-name issue) but the type-name incidence survives. Examples that +remain flagged at the type level: -- `RepoInfo` → `Repo` / `GitFolder` (and the field `repo?: RepoInfo` becomes `repo?: Repo`). +- `RepoInfo` → `Repo` / `GitFolder` (brand drift — see Theme 3). - `PolicyInfo` → `Policy`. -- `EndpointInfo` → `Endpoint` (in `warehouses`, which has a brand mismatch — see Theme 3). +- `EndpointInfo` → `Endpoint` (in `warehouses`, brand mismatch — see Theme 3). - `SchemaInfo` → `Schema`. - `CredentialInfo` → `Credential`. - `MetastoreInfo` → `Metastore`. - `CatalogInfo` → `Catalog`. -- `RunInfo`, `JobInfo`, `TableInfo`, `FunctionInfo`, `ConnectionInfo`, - `VolumeInfo`, `ServicePrincipalInfo`, `UserInfo`, `WorkspaceInfo`, - `OnlineTableInfo`, `ExperimentInfo`. +- `RegisteredModelInfo`, `ModelVersionInfo`, `RegisteredModelAliasInfo`, + `TableInfo`, `FunctionInfo`, `ConnectionInfo`, `VolumeInfo`, + `OnlineTableInfo`. -Same problem with other vague suffixes: -- `*Options` on tagged-union arms (`RowFilterOptions`, `ColumnMaskOptions`, `DenyOptions`, `GrantOptions`) — when the `$case` discriminator already says "this is the X options". -- `*Spec` / `*Details` / `*Config` / `*Status` / `*Data` / `*Metadata` used inconsistently — sometimes for the entity, sometimes for a sub-property, sometimes for both. `apps.ApplicationStatus` and `App.appStatus` mismatch on the same product noun. +Same problem with other vague suffixes (type-side only after the prune): +- `*Spec` / `*Details` / `*Config` / `*Status` / `*Data` / `*Metadata` used inconsistently — sometimes for the entity, sometimes for a sub-property, sometimes for both. `apps.ApplicationStatus` and `App.appStatus` (the field is no longer flagged but the type-name divergence remains). **Generator fix:** Strip the `Info` suffix when the type is the canonical domain entity. (Heuristic: if `Info` is the only `*` type that isn't a request/response, drop `Info`.) Same for redundant `Options`/`Spec` -suffixes on tagged-union arms when the parent has a discriminator. +suffixes on tagged-union arms when the parent has a discriminator. Field +renames are out of scope per user direction (would deviate the SDK from +the underlying API). ### Theme 2. Inconsistent acronym casing across the SDK — 87/87 packages @@ -342,7 +418,7 @@ constants) were: > the platform-name exception. `SCREAMING_SNAKE_CASE` constants > unaffected. -### Theme 3. Brand drift / rebrand leakage — ~10/87 packages +### Theme 3. Brand drift / rebrand leakage — ~6/87 packages (stable across the 2026-05-26 prune) Several products were rebranded but the TS surface still carries the old codename: @@ -357,53 +433,40 @@ codename: **Generator fix:** Per-product spec needs updates; the rename can land via a generator alias map (`Endpoint` → `Warehouse` in `warehouses` only, etc.). -### Theme 4. Proto-architectural-leak infixes — ~10/87 packages, ~50 findings (substantially shrunk) +### Theme 4. Proto-architectural-leak infixes — ~8/87 packages (further shrunk by the 2026-05-26 doc + SDK-internal prunes) Internal proto / service-tier identifiers leak through the codegen and show up as mid-position infix tokens that have no meaning to a TS SDK consumer. The 2026-05-22 generator regen retroactively validated generator rule §8.2 -and renamed the dominant `*Public*Request` sub-pattern across every -account-tier package — ~81 findings moved to per-package `Fixed` sections. - -**Status after the 2026-05-22 regen:** - -- The `*Public*` mid-position infix sub-pattern is largely fixed. Account-tier - packages that previously carried 14-21 such findings each - (`networking` 21 → 0, `workspaces` 21 → 0, - `metastores` 20 → 0, `credentials` 12 → 0, - `storageconfigurations` 14 → 0, `keyconfigurations` 3 → 0) now have zero - active `*Public*Request` findings. The residual active findings on these - packages are unrelated singular/plural and category-1 issues that the - rescan surfaced once the proto-leak noise cleared. +and renamed the dominant `*Public*Request` sub-pattern. The 2026-05-26 prune +further removed the JSDoc-banner sub-cases (out of scope per the doc-change +prune) and SDK-internal `utils.ts` plumbing (out of scope per the +SDK-internal prune). What remains is the type-name surface only. + +**Status after the 2026-05-26 prune:** + +- The `*Public*Request` sub-pattern is fixed (2026-05-22 regen). - **`*CustomerFacing*` qualifier still survives in `networking`** — 40+ identifiers (`CustomerFacingIngressNetworkPolicy`, `CustomerFacingVpcEndpointUseCase`, etc.) in active source. Not yet - scanned as findings because the regen left them untouched; they are the - same proto-tier qualifier and should be flagged in a follow-up pass. + scanned as findings because the regen left them untouched. - **`*Proto` suffix** still active in a handful of identifiers: - `DatabricksServiceExceptionProto`, - `DatabricksServiceExceptionWithDetailsProto`, `TriggerStateProto` (jobs - `model.ts`). The companion JSDoc usually says "Proto defined to model …" — - that is the right place for the word; in the identifier it leaks the wire - format. + `TriggerStateProto` (`jobs`), `DatabricksServiceExceptionProto`, + `DatabricksServiceExceptionWithDetailsProto` (`apps`). - **`*Service*` mid-position infix.** `ServiceErrorCode` / `ServiceError` - in `statementexecution`. The `Service` token is a proto/gRPC - architectural-layer noun and not a domain concept. -- **`*V2*` mid-position.** `RunLifecycleStateV2` (jobs), - `unmarshalListExternalMetadataResponseV2Schema` (externalmetadata). - Version goes in the import path / subpath export, not the identifier. -- **JSDoc proto-layer banners.** `forecasting` and `pipelines` both ship - JSDoc with "Public RPC" / "Wrapper message" / "Public facing RPC requests - and responses *****" verbatim — banner comments that exist solely for the - proto file structure. + in `statementexecution`. +- **`*Handler` suffix.** `listCleanRoomNotebookTaskRunsHandler` / + `listCleanRoomNotebookTaskRunsHandlerIter` in `cleanrooms/client.ts`. +- **`*V2*` mid-position.** `RunLifecycleStateV2` (jobs). +- **JSDoc banners pruned.** "Public RPC", "Wrapper message", and "Public + facing RPC requests and responses *****" comments no longer flagged + (doc-change prune, 2026-05-26). **Generator fix:** Strip proto-architectural-tier markers from the public TS surface emit. The set is small and closed: `Public`, `Internal`, `Proto`, `Service` (when mid-position and not the domain word), `Backend`, `Manager`, `Handler`, `Impl`, `Rpc`, `Grpc`, `Wrapper`, `CustomerFacing`, mid-position `V`. Carried as a single generator-only rule in §8.2 below. -The `*Public*Request` sub-pattern has now shipped via the 2026-05-22 regen, -which is a retroactive validation of the rule but does not close it out. --- diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index 90ab1a7d..f92f5654 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -3,15 +3,15 @@ **Path:** `packages/abacpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter and column-mask policies. -**Total weird names flagged:** 13 +**Total weird names flagged:** 7 ## Summary | Severity | Count | | --- | --- | | High | 3 | | Medium | 2 | -| Low | 4 | -| Observation | 4 | +| Low | 0 | +| Observation | 2 | ## High severity @@ -49,46 +49,17 @@ ## Low severity -### 6. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` -- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Minor; only one place in the file but flagged for consistency review across the SDK. - -### 7. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Either remove the export (if it's an unused generator default), or document why it ships per-package. -- **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. - -### 8. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` / `readStreamToEnd`. -- **Rationale:** Internal helper, low cost. Skip if generated. - -### 9. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions with nearly identical names handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call site. -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). -- **Rationale:** Names should differ in more than the `Http` infix. +_None._ ## Observations -### 10. Wire/TS divergence is heavy -The model file is ~497 lines for ~9 user-facing types; >half is marshal/unmarshal/FieldMaskSchema scaffolding. Not a naming problem, but the audit surfaces just how much generator boilerplate dominates each package — worth raising at the SDK-design level. - -### 11. Action-verb conventions in `Client` +### 6. Action-verb conventions in `Client` The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) -### 12. Acronym casing for `Http` / `Url` / `Id` in `utils.ts` / `client.ts` -The codebase uses `Http` (`HttpClient`, `HttpRequest`, `executeHttpCall`) and `URLSearchParams` (Web standard) and `url` (lowercase) and `userAgent`. Mixing `Http` (PascalCase capital-then-lower) with the imported `URLSearchParams` (ALLCAPS) is inconsistent — common across JS ecosystem and probably not worth changing, but worth noting. +### 7. Acronym casing for `Http` / `Url` / `Id` across the SDK +The codebase uses `Http` (PascalCase capital-then-lower, e.g. `HttpClient`, `HttpRequest`) alongside the imported `URLSearchParams` (ALLCAPS, Web standard) and lowercase `url` / `userAgent`. Mixing `Http`-style with `URL`-style acronym casing is inconsistent across the SDK surface — common across JS ecosystem and probably not worth changing, but worth noting as a cross-package consistency question. - **Category:** 3 (acronym casing). -### 13. `abac` abbreviation only appears in package name -The package directory is `abacpolicies` but neither type, field, comment, nor enum mentions `abac`. The package name acts as a domain keyword the SDK is otherwise silent about. May confuse users searching by acronym. -- **Category:** 5 (cryptic abbreviation in package name). - ## Domain glossary - `abac` — Attribute-Based Access Control (package name only; not referenced in current model code). - `uc` — Unity Catalog (referenced in comment at model.ts:32 as "UC-2980", and implicitly across all types since policies live on Unity Catalog securables). diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md index 2d31042c..c90c5a90 100644 --- a/.agent/naming-audit/accessmanagement.md +++ b/.agent/naming-audit/accessmanagement.md @@ -16,15 +16,15 @@ the `USER`/`ADMIN` role a principal holds on a workspace (d) the `checkPolicy` resource-access policy decision endpoint. Originated from `permissions`, `workspaceassignment`, `accountaccesscontrol`, and `accountaccesscontrolproxy` during the 2026-05-22 regeneration. -**Total weird names flagged:** 31 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | | High | 7 | | Medium | 11 | -| Low | 9 | -| Observation | 4 | +| Low | 4 | +| Observation | 3 | The consolidation has eliminated several prior warts (top-level verb-shaped request types from `permissions` now carry `Request` suffixes; the @@ -364,47 +364,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum most likely correct per Google TS rules. - **Rationale:** Defer to global policy. -### 20. `flattenQueryParams` exported but rarely consumed — `src/v1/utils.ts:123` -- **Why weird:** Used only by `checkPolicy` (`client.ts:536,545,555`). - The helper is identical across packages and should live in a shared - `@databricks/sdk-core` module rather than be re-emitted per package. - Generator-wide concern. -- **Category:** Effectively internal/redundant export. -- **Suggested name:** Move to shared core utility module; keep current - name. -- **Rationale:** Generator emits the same helper into every package; - consolidation reduces surface. - -### 21. `HttpCallOptions` shadows `CallOptions` — `src/v1/utils.ts:15` -- **Why weird:** The package imports `CallOptions` from - `@databricks/sdk-options/call` (line 12) and defines its own - `HttpCallOptions` here. The names suggest the latter is a - subtype/extension of the former, but they describe different concerns - — `CallOptions` is retry/signal/timeout policy; `HttpCallOptions` is - request + client + logger bundle. -- **Category:** Vague suffix; naming-overlap with the public type. -- **Suggested name:** `HttpCallContext` (it's a context bag, not - user-tunable options). -- **Rationale:** Distinguish internal context bags from user-facing - option structs. - -### 22. `readAll` is a Go-port utility name — `src/v1/utils.ts:40` -- **Why weird:** Direct Go-port of `io.ReadAll`; clashes cognitively - with `Array.prototype` methods and Web Streams APIs. Generator-wide. -- **Category:** Vague; Go-port style. -- **Suggested name:** `readStreamToEnd`, `drainStream`, or - `bufferStream`. -- **Rationale:** Cross-package consistency. - -### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:64` -- **Why weird:** `Segment` is a generic word; the constant carries - User-Agent identity but the name communicates nothing. Same wart - appears in every generated package. -- **Category:** Vague; generic name. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Cross-package consistency. - -### 24. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` +### 20. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` (line 513). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the @@ -416,18 +376,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. -### 25. `permissionassignments` URL fragment is one word — `src/v1/client.ts:103,131,159,187` -- **Why weird:** REST path uses `/permissionassignments/` (no - separator), while every other Databricks REST resource in this SDK - uses hyphenated paths (`/clean-rooms`, `/external-locations`, etc.). - Wire-format problem, not TS naming, but spills into the visual feel - of the client URLs. -- **Category:** Casing/separator inconsistency (wire side). -- **Suggested name:** Upstream: `permission-assignments`. Not actionable - in this package. -- **Rationale:** Cross-API consistency. - -### 26. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` +### 21. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` - **Why weird:** Method is named with `get*` but returns `permissionAssignments` array (model.ts:213). REST convention is `list*` for array-returning operations; `get*` for singular. @@ -438,7 +387,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Aligns naming with REST list semantics used elsewhere in the SDK. -### 27. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` +### 22. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` - **Why weird:** Method `listWorkspacePermissions` returns the catalog of `PermissionOutput` values supported (USER/ADMIN), not user data. Sits side-by-side with `getWorkspacePermissionAssignments` @@ -453,28 +402,21 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum ## Observations -### O1. URL path interpolation is unencoded — `src/v1/client.ts:103,131,159,187,222,259,296,333,370,399,425,450,478,504` -- All URL path placeholders interpolate `${req.accountId ?? ''}`, - `${String(req.workspaceId ?? '')}`, etc. directly into URLs without - `encodeURIComponent`. A malicious or weird `accountId` allows path - injection. Sibling packages use the same pattern, so it's - project-wide. Not a naming finding strictly, caught in passing. - -### O2. `workspaceId` and `principalId` typed as `number` — `src/v1/model.ts:126,128,207,235,287,366,368` +### O1. `workspaceId` and `principalId` typed as `number` — `src/v1/model.ts:126,128,207,235,287,366,368` - Workspace IDs and principal IDs are 64-bit integers in Databricks; JS `number` loses precision above 2^53. The client also unconditionally `String()`s these into URL paths, so string semantics are sufficient throughout. Worth flagging cross-package: bigint or string would be safer. -### O3. `error?: string` on `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:389` +### O2. `error?: string` on `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:389` - Embedding an opaque error string inside the success response body is unusual; typical SDK design surfaces errors as exceptions or as a typed error union. The field is named `error` (clashing with the global `Error` class and the `catch(error)` parameter name). `errorMessage` or `partialFailureReason` would be clearer. -### O4. Single class composes four formerly-distinct services — `src/v1/client.ts:69` +### O3. Single class composes four formerly-distinct services — `src/v1/client.ts:69` - The `Client` class composes 12 methods that previously lived across four packages. Three operational clusters (workspace-object-permissions, account-level rule sets, diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index efff12ed..861d3dcd 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -10,10 +10,10 @@ with deployments, custom templates, app spaces, and resource bindings. | Severity | Count | | -------- | ----- | | High | 5 | -| Medium | 14 | -| Low | 7 | +| Medium | 10 | +| Low | 6 | | Observation | 9 | -| **Total** | **35** | +| **Total** | **30** | The audit found one dominant theme: the domain has overlapping vocabularies for the same concept. `App` vs `Application` (`ApplicationStatus`, @@ -190,43 +190,7 @@ cross-product values whose relevance to Apps is unclear. `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name promises nothing. -### M8. `flattenQueryParams` — what does it flatten? -- **File:** `utils.ts:123` -- **Category:** Vague/generic (1) -- **Issue:** `flattenQueryParams(prefix, value, params)` — the function - flattens *nested object structures* into dotted query keys - (`a.b.c=value`). The verb "flatten" doesn't communicate the target format. -- **Suggestion:** Rename to `encodeNestedQueryParams` or - `appendObjectAsQueryParams`. - -### M9. `readAll` — local helper exported as `readAll` -- **File:** `utils.ts:40` -- **Category:** Vague/generic (1) -- **Issue:** `readAll(body: ReadableStream | null)` — reads-all of - what? The function reads a stream to completion. -- **Suggestion:** Rename to `readStreamToBytes` or `consumeStream`. (It's not - exported, so impact is local.) - -### M10. `executeCall` vs `executeHttpCall` — pair drifts in meaning -- **File:** `utils.ts:26, 65` -- **Category:** Inconsistent action verbs (17) -- **Issue:** `executeCall` is the *outer* retry/rate-limit wrapper; - `executeHttpCall` is the *inner* one-shot HTTP send. The function names - suggest the former is just a generic "execute" and the latter adds HTTP, but - in practice every concrete call goes through both. Disambiguating names - would help. -- **Suggestion:** Rename to `runWithRetries`/`sendHttp`, or `runCall`/`sendOne`. - -### M11. `StillRunningError` — internal sentinel class, named ambiguously -- **File:** `client.ts:93` -- **Category:** Misleading names (6) -- **Issue:** `class StillRunningError extends Error {}` — used as a sentinel - to drive retries. Reads like a real domain error but has no message and is - caught locally. Could be confused with a public error type. -- **Suggestion:** Rename to `pollAgainSentinel` (as a typed Error subclass) or - `RetryablePollError`, and add a comment that it never escapes the file. - -### M12. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +### M8. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too - **File:** `client.ts:121, 902` - **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) - **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, @@ -237,7 +201,7 @@ cross-product values whose relevance to Apps is unclear. - **Suggestion:** Drop the `async` prefix from `asyncUpdateApp` to match `updateSpace`, or add `asyncUpdateSpace` for symmetry. -### M13. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +### M9. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type - **File:** `client.ts:297, 396, 939` - **Category:** Type-suffix tautology (20) - **Issue:** Methods named `createSpaceOperation()` return a @@ -248,7 +212,7 @@ cross-product values whose relevance to Apps is unclear. `createSpaceAndWait()` or `createSpaceLongRunning()`. The `*Operation` class could be `*LongRunning` (mirroring the `Operation` type's role). -### M14. `gitProvider?: string` — should be enum/union +### M10. `gitProvider?: string` — should be enum/union - **File:** `model.ts:1075-1076, 1163-1166` - **Category:** Vague/generic (1) - **Issue:** `CustomTemplate.gitProvider` and `GitRepository.provider` are @@ -302,15 +266,7 @@ cross-product values whose relevance to Apps is unclear. `@databricks/sdk-jobs`, they need an alias. - **Suggestion:** Rename to `AppsClient`. Common SDK convention. -### L6. `host` (private field on `Client`) -- **File:** `client.ts:96` -- **Category:** Vague/generic (1) -- **Issue:** `private readonly host: string`. The doc on the workspace - parameter usually calls this the "workspace host" or "workspace URL". -- **Suggestion:** Rename to `workspaceUrl` or `workspaceHost`. Internal-only, - cosmetic. - -### L7. `getSpaceOperation` (method) vs `GetOperationRequest` +### L6. `getSpaceOperation` (method) vs `GetOperationRequest` - **File:** `client.ts:524-546` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index 2ed7cec4..a39903cf 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -11,10 +11,10 @@ Notation: file paths are absolute. Findings reference `file:line`. | Severity | Count | | ----------- | ----- | | High | 1 | -| Medium | 4 | -| Low | 5 | -| Observation | 3 | -| **Total** | **13** | +| Medium | 3 | +| Low | 0 | +| Observation | 2 | +| **Total** | **6** | Headline themes: @@ -81,21 +81,7 @@ verbs vs. UC sibling APIs `update…`. If the API spec dictates `Set`, this is correct; the audit flags it because the verb is unique within UC. -### M3. `req` parameter name on `Client.getArtifactAllowlist` / -`setArtifactAllowlist` - -- **File / line:** `src/v1/client.ts:67, 97`. -- **Category:** #5 cryptic abbreviation; #14 Go-style name. -- **Current:** `req: GetArtifactAllowlistRequest`. -- **Suggestion:** `request` (matches Go-port readability without saving - characters that matter in TypeScript). -- **Rationale:** Throughout the JS/TS ecosystem, function parameters tend - to be spelled out (`request`, `response`) rather than abbreviated. The Go - `req`/`resp` idiom is fine in Go where short names are encouraged; in TS - it reads as Go-translated code. (Note: `resp` shows up locally in the - same file at lines 71, 84, 102, 115 — a separate, lower-priority issue.) - -### M4. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak +### M3. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak - **File / line:** `src/v1/model.ts:15`. - **Category:** proto-architectural-leak — `Proto` infix / nested-enum @@ -116,80 +102,7 @@ verbs vs. UC sibling APIs ## Low Severity -### L1. `executeCall` vs. `executeHttpCall` — overlapping verbs - -- **File / line:** `src/v1/utils.ts:26, 65`. -- **Category:** #6 misleading name; #12 duplicate concepts. -- **Current:** Both functions live in the same file with very similar - names. `executeCall` is the public-options translator that delegates to - `execute` from `@databricks/sdk-core/api`. `executeHttpCall` is the low- - level HTTP send + parse helper. -- **Suggestion:** Rename `executeCall` to `runCallWithOptions` / - `dispatchCall` (or fold into `executeHttpCall` if the indirection is - trivial). At minimum, the JSDoc already calls this out as a *translator* - — the name should match. -- **Rationale:** Two functions named `execute*Call` in 70 lines of code, - with different return shapes (`Promise` vs. - `Promise`), is a readability hazard. The JSDoc on line 21–25 - explicitly says "Translates public CallOptions to the internal Options - shape," which is a better name. - -### L2. `Call` (imported, not local) and `call` local variable share names - -- **File / line:** `src/v1/client.ts:72` (`const call: Call = …`). -- **Category:** #1 vague/generic. -- **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. -- **Suggestion:** `httpCall` or `doRequest`. -- **Rationale:** `call` is a built-in word in JS (`.call()` on functions), - so a variable named `call` inside a method that is itself a call is - ambiguous. Caveat: this is a 1:1 port of Go SDK convention. - -### L3. `body` shadowed across helpers in `executeHttpCall` - -- **File / line:** `src/v1/utils.ts:81`, `buildHttpRequest` (line 96), - `parseResponse` (line 113). -- **Category:** #1 vague generic name. -- **Current:** `body: Uint8Array` (response body) vs. `body: string | - ReadableStream` (request body, in `buildHttpRequest`). -- **Suggestion:** `responseBody` / `requestBody`. -- **Rationale:** Within `client.ts` line 101 a request body flows into a - function that internally also reasons about response bodies. - Differentiating with `requestBody` / `responseBody` would help readers. - -### L4. `AuthHttpClient` — architectural-layer wrapper class name - -- **File / line:** `src/v1/transport.ts:43`. -- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` pattern - exposed; architectural mid-token `Http`. -- **Current:** `class AuthHttpClient implements HttpClient` — the JSDoc - on line 42 reads "Wraps an HttpClient and adds authentication headers - to requests," explicitly admitting wrapper semantics. -- **Suggestion:** Internalize the wrapper (e.g., a `withAuth(client, - credentials)` factory that returns an `HttpClient`), or name the class - after what it produces (`AuthenticatedTransport`) rather than the - architectural layering. If kept, drop `Http` and align with the - domain — `AuthenticatingClient` reads as the role. -- **Rationale:** `AuthHttpClient` reads as `Auth` + `Http` + `Client`, - three architectural tokens stacked. The `Http` infix in particular adds - no information beyond what `HttpClient` (the implemented interface) - already conveys. Wrapper class names that stack adjective + transport - layer + role are a known leak of internal layering into identifiers. - -### L5. `TimeoutHttpClient` — second instance of the same wrapper-naming pattern - -- **File / line:** `src/v1/transport.ts:61`. -- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` pattern; - architectural mid-token `Http`. -- **Current:** `class TimeoutHttpClient implements HttpClient` (JSDoc: - "Wraps an HttpClient and applies a default timeout to requests"). -- **Suggestion:** Same treatment as L4 — a `withTimeout(client, ms)` - factory, or rename to `TimeoutTransport` / `TimeoutClient` to drop the - architectural `Http` infix. -- **Rationale:** Same naming anti-pattern as L4 repeated. Together, - `AuthHttpClient` + `TimeoutHttpClient` form a small decorator chain - whose class names advertise the chain layout rather than the behaviour - delivered. The cluster suggests a generator template rather than a - package-local choice. +_None._ --- @@ -209,13 +122,6 @@ URL paths (`/artifact-allowlists/`), and the package name `@databricks/sdk-artifactallowlists`. No `AllowList`, `Allow_list`, or `Whitelist` anywhere. **Passes** the audit on this criterion. -### O3. URL path constant is inlined - -The string `/api/2.1/unity-catalog/artifact-allowlists/${artifactType}` -appears twice (`client.ts:70` and `client.ts:100`) without a named -constant. Not a naming defect, but typical naming-audit findings include -"unnamed magic strings." Worth a note. - --- ## Domain glossary @@ -245,24 +151,14 @@ constant. Not a naming defect, but typical naming-audit findings include Type & symbol checklist: - [x] `ArtifactType` enum (4 members) → no defect. -- [x] `ArtifactMatcher_MatchType` enum (2 members) → M4. +- [x] `ArtifactMatcher_MatchType` enum (2 members) → M3. - [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O1. - [x] `ArtifactMatcher` interface (2 fields) → no defect. - [x] `GetArtifactAllowlistRequest` interface (1 field) → no defect. - [x] `SetArtifactAllowlistRequest` interface (5 fields) → H1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → no defect. -- [x] `getArtifactAllowlist(req, options)` method → M2, M3. -- [x] `setArtifactAllowlist(req, options)` method → M2, M3. -- [x] `HttpCallOptions` interface → no defect. -- [x] `executeCall` function → L1. -- [x] `readAll` private function → no defect (name fits idiom). -- [x] `executeHttpCall` function → L1, L3. -- [x] `buildHttpRequest` function → L3. -- [x] `flattenQueryParams` function → no defect. -- [x] `newHttpClient` factory (`transport.ts`) → no defect. -- [x] `AuthHttpClient` class (`transport.ts`) → L4. -- [x] `TimeoutHttpClient` class (`transport.ts`) → L5. +- [x] `getArtifactAllowlist(req, options)` method → M2. +- [x] `setArtifactAllowlist(req, options)` method → M2. - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). --- diff --git a/.agent/naming-audit/billableusagedownload.md b/.agent/naming-audit/billableusagedownload.md index a180c8c1..b8a21971 100644 --- a/.agent/naming-audit/billableusagedownload.md +++ b/.agent/naming-audit/billableusagedownload.md @@ -3,15 +3,15 @@ **Path:** `packages/billableusagedownload/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CSV export of billable Databricks usage logs for a given month range. Single endpoint: `GET /api/2.0/accounts/{account_id}/usage/download`. No CRUD surface, no enums, no list/page semantics — just one streaming download method. -**Total weird names flagged:** 19 +**Total weird names flagged:** 8 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 6 | -| Low | 5 | -| Observation | 4 | +| Medium | 3 | +| Low | 0 | +| Observation | 1 | ## High severity @@ -59,72 +59,17 @@ - **Suggested name:** `downloadBillableUsage` (matches the request-type rename) or, if the package gets folded into `billing`, `downloadUsage`. - **Rationale:** Domain-qualified method names read better when imported into application code. Even within the package, `billableUsageDownloadClient.download()` has a pleasing redundancy that a single naked `download()` does not. -### 8. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:17` -- **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. -- **Category:** 1 (vague), 15 (generic field name losing meaning). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Cross-package consistency — same finding appears in every audited package. Worth normalising at generator level. - -### 9. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` -- **Why weird:** `client.ts` does its own query-param construction inline (lines 70-79) using `new URLSearchParams()` and three `params.append(...)` calls. The exported `flattenQueryParams` helper in `utils.ts` is never called. -- **Category:** 11 (unused public helper — dead surface area). -- **Suggested name:** Remove the export, or drop the function entirely if no caller in this package needs it. -- **Rationale:** Every generated package ships this helper; in `billableusagedownload` (which has zero list/page operations and only three query params), the inline approach is clearly what the generator chose. The unused export is a generator artefact that should be pruned. - -### 10. `executeHttpCall` is exported but unused — `src/v1/utils.ts:65` -- **Why weird:** `utils.ts` exports both `executeHttpCall` and `sendAndCheckError`; only the latter is used in `client.ts:96`. `executeHttpCall` is dead surface area. -- **Category:** 11 (unused public helper — dead surface area). -- **Suggested name:** Remove `executeHttpCall`; the package only needs `sendAndCheckError`. -- **Rationale:** Two HTTP-send variants with subtly different return types (`Uint8Array` vs `HttpResponse`) is confusing. The unused export should be pruned. - ## Low severity -### 11. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** The word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, ...). Within this file the imported `Options` from `@databricks/sdk-core/api` (line 3) collides with this local interface name. -- **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). -- **Suggested name:** `HttpCallContext` (it is not user-facing options; it is an internal bag of args). -- **Rationale:** Distinguish internal context bags from user-tunable option structs. Same finding as `abacpolicies` audit #37. - -### 12. `readAll` helper — `src/v1/utils.ts:40` -- **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. Also reads the body twice in `sendAndCheckError` (lines 176-181) — once for body content, once for error parsing — though this is fine because non-2xx is handled separately. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` / `readStreamToEnd`. -- **Rationale:** Internal helper, low cost. Skip if generated. - -### 13. `buildHttpRequest` parameter order — `src/v1/utils.ts:96-102` -- **Why weird:** `(method, url, headers, signal?, body?)` — positional 5-arg function with two optional trailing params. Calling site (`client.ts:86`) passes `('GET', fullUrl, headers, callSignal)` — fine — but a caller adding a body has to remember the order. An options object would be clearer. -- **Category:** 1 (no name issue per se), Observation. -- **Suggested name:** Take `{method, url, headers, signal?, body?}` as an options object. -- **Rationale:** Less of a naming issue, more of an API shape concern. Not a blocker. - -### 14. `req` / `resp` / `opts` / `httpReq` / `httpResp` abbreviations — `src/v1/client.ts:66,68,86,87,...` -- **Why weird:** Three-letter abbreviations for local variables (`req`, `resp`, `opts`). The codebase guideline (typescript.mdc) discourages cryptic short abbreviations. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. -- **Rationale:** Spelling out four-letter names costs nothing and improves readability. - -### 15. `httpClient: HttpClient` field — `src/v1/client.ts:27` / `src/v1/utils.ts:17` -- **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention is widespread in this SDK. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the (different) outer `Client` class in the same file. -- **Rationale:** Tolerable given the disambiguation, but flagged per rule 20. +_None._ ## Observations -### 16. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` +### 8. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` The field is typed `ReadableStream` (no type parameter) rather than `ReadableStream`. Every other use in the codebase (`packages/files/src/v1/model.ts`, `utils.ts:42`, `utils.ts:101`) uses `ReadableStream` explicitly. The unparameterised version is the global lib type which is structurally `ReadableStream`, weakening type safety for callers. - **Category:** 6 (misleading — type appears typed but is in fact `any`-typed), 17 (inconsistent across the SDK). - **Suggested name:** `contents?: ReadableStream | undefined`. -### 17. Wire/TS mapping is correct -The TS field `personalData` maps to wire `personal_data`, `startMonth` -> `start_month`, etc. The query-param construction in `client.ts:70-79` does it manually and correctly. Good — no naming bug here, just noting that no schema/codec layer is needed because this is a query-string-only request. - -### 18. No enums, no list-types, no FieldMask -This package is one of the simplest in the SDK: zero enums, zero list/paginated types. Audit-rule categories 2 (redundant enum prefix), 18 (long enum values), and 13 (verb tense inconsistency) do not apply here. That's why the finding count is comparatively low. - -### 19. CSV body is undocumented in types -`DownloadResponse.contents` is `ReadableStream` (untyped) but the JSDoc on `Client.download` (`client.ts:51-64`) makes clear the body is CSV. There is no type-level hint or branded type to mark this — a caller might treat the stream as JSON. Worth considering a documented branded type (`type CsvStream = ReadableStream & {readonly _csvBrand: unique symbol}`) or, more practically, a Content-Type assertion. Not a name problem; flagged because the response shape is uninformative. - ## Domain glossary - `DBU` — Databricks Unit; standard billing unit for Databricks compute. Notably absent from this package's types and JSDoc — no DBU-related fields surface here despite the package being about billable usage. (User-mentioned in the task; verified via grep that the literal "DBU" never appears.) - `PII` — Personally Identifiable Information. Surfaced indirectly as the `personalData` field flag. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index ef06afc1..ab6918ce 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -3,15 +3,15 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 16 +**Total weird names flagged:** 7 ## Summary | Severity | Count | | --- | --- | | High | 2 | -| Medium | 4 | -| Low | 5 | -| Observation | 5 | +| Medium | 3 | +| Low | 0 | +| Observation | 2 | ## High severity @@ -29,25 +29,19 @@ ## Medium severity -### 3. `CustomPolicyTag` reserved-key documentation — `src/v1/model.ts:55-56` -- **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling. They aren't surfaced as constants or an enum. -- **Category:** 6 (misleading: hard-coded magic strings that callers must memorise), 18 (long magic string sentinels). -- **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant, or validate in marshal step and throw a typed error. -- **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Worth flagging because the names are stable wire-level identifiers. - -### 4. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` +### 3. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 30). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). - **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 30 and `Filter.creatorUserId` here. -### 5. `SortSpec` type — `src/v1/model.ts:147` +### 4. `SortSpec` type — `src/v1/model.ts:147` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 6. `SortSpec_Field` enum name — `src/v1/model.ts:6` +### 5. `SortSpec_Field` enum name — `src/v1/model.ts:6` - **Why weird:** Proto-architectural-leak: the underscore-joined `ParentType_NestedType` form is the protobuf/Go-SDK convention for emitting nested enum types into a flat namespace. TS already supports namespaces and modules natively, so the underscore is a wire-protocol artifact bleeding into the public TS API. The eslint-disable comment on the prior line even labels it "Proto-style nested enum name", confirming the generator knows it is non-idiomatic. - **Category:** Proto-architectural leak (proto-style nested-type encoding leaking into TS identifiers). - **Suggested name:** `SortField` (drop the `Spec_` prefix entirely; the enum stands on its own as the set of sortable fields) or `SortSpecField` (camel-join, no underscore). @@ -55,59 +49,17 @@ ## Low severity -### 7. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. -- **Category:** 1 (vague), 17 (inconsistent — names differ only by `Http` infix). -- **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. -- **Rationale:** Same pair flagged in the `abacpolicies` audit. Generator-wide. - -### 8. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. -- **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). -- **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). -- **Rationale:** Generator-wide concern; same as `abacpolicies` finding #37. - -### 9. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` or `readStreamToEnd`. -- **Rationale:** Internal helper. Generator-wide. - -### 10. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Used by `client.ts:158,165,221` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package. -- **Category:** Observation / 12 (duplicate utility across packages). -- **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. -- **Rationale:** Naming is fine; flagging duplication. - -### 11. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` -- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. -- **Category:** 1 (vague), 15 (generic name losing meaning). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Same as `abacpolicies` finding #32; generator-wide. +_None._ ## Observations -### 12. `Client` class plain name — `src/v1/client.ts:46` +### 6. `Client` class plain name — `src/v1/client.ts:46` Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). - **Suggested name:** `BudgetPolicyClient`. - **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. -### 13. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` -Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. -- **Category:** 5 (cryptic abbreviation when the long form fits comfortably). -- **Suggested name:** `request`. -- **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. - -### 14. Action-verb conventions in `Client` -The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs (matching the JSDoc method documentation). No mixed `fetch`/`retrieve`/`read`. (`abacpolicies` audit noted the same.) -- **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). - -### 15. Wire-form vs TS-form casing of `policyId` (path interpolation) — `src/v1/client.ts:80,106,125,150,215` -The URL path uses `accounts/${req.accountId ?? this.accountId ?? ''}/budget-policies` and the policy id is substituted via `req.policyId ?? ''`. The kebab-case URL segment `budget-policies` is fine; flagging that the SDK uses three different casings (`budget_policies` wire-form for query params, `budget-policies` for the URL, `budgetPolicies` for TS) — readers must mentally translate. -- **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). - -### 16. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` +### 7. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` Three sibling packages exist with related-sounding names: - `budgetpolicy` — tag attribution policy (this package). - `budgets` — spend-alert budget configurations. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index cfa037b5..4b68f768 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -6,7 +6,6 @@ **Files audited:** - `src/v1/model.ts` - `src/v1/client.ts` -- `src/v1/utils.ts` - `src/v1/index.ts` This audit applies the 20 numbered concern categories from the audit @@ -52,15 +51,6 @@ rename suggestion. Findings are grouped by category. `getBudgetConfiguration`, `listBudgetConfigurations`, `listBudgetConfigurationsIter`, `updateBudgetConfiguration`. -### Utility functions (`utils.ts`) - -`executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, -`parseResponse`, `marshalRequest`, `flattenQueryParams`. - -### Utility types/interfaces (`utils.ts`) - -`HttpCallOptions`. - --- ## Findings @@ -112,19 +102,7 @@ _None._ ### 3. Acronym casing inconsistencies -#### F3.1 — `URL` / `Url` consistency (acceptable) -- `client.ts` consistently uses `url` (lowercase) as a local var - name. No casing inconsistency observed. - -#### F3.2 — `HTTP` / `Http` (acceptable for this file) -- `utils.ts` consistently uses `Http` PascalCase (`HttpClient`, - `HttpRequest`, `HttpResponse`, `HttpCallOptions`, - `executeHttpCall`, `buildHttpRequest`). One file is consistent; - flag is cross-package only. - -#### F3.3 — `USD` in enum value `LIST_PRICE_DOLLARS_USD` (LOW) -- Wire value, leave as-is. But note that `DOLLARS_USD` is doubly - redundant — USD already is dollars. See F17.2. +_None._ --- @@ -137,81 +115,14 @@ _None._ ### 5. Cryptic abbreviations #### F5.1 — `req` (LOW, Go-ism) -- **Where:** `client.ts` every method, `utils.ts:103`. -- Already flagged under F1.3 / F13.1. - -#### F5.2 — `resp` (LOW, Go-ism) -- **Where:** `client.ts:88, 116, 150, 193, 242`; `utils.ts:73, 75, 81, 84, 88`. -- See F13.1. - -#### F5.3 — `respBody` (LOW) -- **Where:** `client.ts:93, 121, 155, 198, 247`. -- **Why flagged:** "resp" abbreviation. Spell out `responseBody` - for clarity in TS where verbosity is cheap. -- **Suggestion:** `responseBody`. - -#### F5.4 — `httpReq` (LOW) -- **Where:** `client.ts:92, 120, 154, 197, 246`. -- **Why flagged:** `httpRequest` is clearer and matches the type - `HttpRequest` exactly. -- **Suggestion:** `httpRequest`. - -#### F5.5 — `apiErr` (LOW) -- **Where:** `utils.ts:88`. -- **Why flagged:** `apiError` reads better; "err" is a Go-ism. -- **Suggestion:** `apiError`. - -#### F5.6 — `pkgJson` (LOW) -- **Where:** `client.ts:19`. -- **Why flagged:** "pkg" abbreviation. `packageJson` is two extra - characters and unambiguous. -- **Suggestion:** `packageJson`. - -#### F5.7 — `acc`, `val`, `opts`, `e` (LOW) -- **Where:** `utils.ts:55, 137, 30, 66-92, 76`. -- **Why flagged:** - - `acc` (utils.ts:55) — reduce accumulator, conventional. OK. - - `val` (utils.ts:137) — local destructure, OK. - - `opts` (utils.ts:30, 37, 66, 68, 69, 70, 75, 77, 83) — Go-ism; - `options` is preferred but `opts` is also widely used in JS - libraries. **Inconsistent with itself:** the public parameter - is `options` (utils.ts:28) but the internal one is `opts`. Pick - one. - - `e` for the caught exception (utils.ts:76) — TS guidance is - `err`/`error`/`e` are all acceptable. Match the file's other - usages (`apiErr`). -- **Suggestion:** rename `opts → options` inside `executeHttpCall` - for consistency; leave `acc`, `val`, `e` alone. +- **Where:** `client.ts` every method. +- Already flagged under F1.3. --- ### 6. Misleading names -#### F6.1 — `BudgetConfigurationFilter_WorkspaceIdClause.values: - number[]` (MEDIUM) -- **Where:** `model.ts:95`. -- **Why flagged:** Workspace IDs are 64-bit integers on Databricks. - TypeScript `number` cannot safely represent values > 2^53. Other - packages in this SDK use `string` for IDs that overflow. This is a - *type* issue, not a *naming* issue — but the field name `values: - number[]` does not signal that it is the wrong width. Worth a - cross-reference (the v1 spec presumably uses int64). -- **Suggestion:** Confirm with the Go reference; if it is `int64`, - the TS port should be `string[]` or `bigint[]`. If `number` is - intentional (sometimes IDs fit in 53 bits), document it. Not - strictly a naming finding, included because it shows up as a - field-domain mismatch. - -#### F6.2 — `flattenQueryParams` is exported but unused in this - package (LOW) -- **Where:** `utils.ts:123-150`. -- **Why flagged:** The name suggests it is a query-param helper for - this client; the client does not call it (lines 144-148, 178-190 - use `URLSearchParams.append` directly). The function is dead code - inside this package. Either there is an intended caller that has - not landed, or the helper should not be in this package. -- **Suggestion:** Move shared helpers to `@databricks/sdk-core` or - delete from this package's `utils.ts`. +_None._ --- @@ -283,37 +194,11 @@ _None._ switch to singular `alertConfiguration: AlertConfiguration` when the API allows. -#### F8.2 — `actionConfigurations: ActionConfiguration[]` (acceptable) -- **Where:** `model.ts:47`. -- **Why flagged:** No mismatch — multiple actions per alert are - allowed. Plural is correct. - -#### F8.3 — `tags: BudgetConfigurationFilter_TagClause[]` (acceptable) -- Plural-array, no mismatch. - -#### F8.4 — `budgets` field in `ListBudgetConfigurationsRequest_Response` - (acceptable) -- Plural, correct. - --- ### 9. Reserved-word / built-in collisions -#### F9.1 — `filter` field (LOW) -- **Where:** `model.ts:65, 113, 190`. -- **Why flagged:** `filter` is `Array.prototype.filter` — not a - reserved word, but shadowing a built-in causes mental hiccups - during code review. Acceptable here because the field is on - `BudgetConfiguration`, not on an array. -- **Suggestion:** Keep; not worth churn. - -#### F9.2 — `Headers` constructor use vs DOM `Headers` (acceptable) -- **Where:** `client.ts:90, 118, 152, 195, 244`. -- The code intentionally uses the global `Headers`. No new identifier - shadows it. Fine. - -#### F9.3 — `URLSearchParams`, `TextDecoder` (acceptable) -- Used as global classes, no shadowing. +_None._ --- @@ -348,19 +233,7 @@ _None._ collapse to a generic clause type — but only if the generator supports it. -#### F11.3 — Per-method header construction duplicated (LOW, code style) -- **Where:** `client.ts:90, 118, 152, 195, 244`. -- **Why flagged:** Every method runs: - ```ts - const headers = new Headers(...); - headers.set('User-Agent', this.userAgent); - ``` - Could be a private helper `this.buildHeaders(...)`. Not a naming - issue, but a code-duplication smell. -- **Suggestion:** Out of scope for naming audit. Mentioned for - completeness. - -#### F11.4 — `accountId` declared on both the request envelope and +#### F11.3 — `accountId` declared on both the request envelope and the inner `Budget` (LOW) - **Where:** - `CreateBudgetConfigurationBudget.accountId` (model.ts:102) @@ -381,7 +254,7 @@ _None._ request envelope for *all* methods. The Go/proto layer can keep nesting; the TS client should flatten. -#### F11.5 — `budgetId` on +#### F11.4 — `budgetId` on `Delete/Get/UpdateBudgetConfigurationRequest` vs `budgetConfigurationId` on `BudgetConfiguration` and `Create/UpdateBudgetConfigurationBudget` (HIGH) @@ -408,46 +281,13 @@ _None._ ### 12. Verb-tense inconsistency -#### F12.1 — Method verbs (acceptable) -- `create*`, `delete*`, `get*`, `list*`, `update*` — uniform - imperative present. Good. - -#### F12.2 — `createTime`, `updateTime` vs `created_at`/`updated_at` - conventions (LOW) -- **Where:** `model.ts:56-58, 104-106, 181-183`. -- **Why flagged:** Past-tense `createdTime` / `updatedTime` (or - `createdAt`/`updatedAt`) is more idiomatic; current form reads - as imperative ("create the time"). This is a noun form ("the - time of creation"), which is fine but ambiguous on first read. - This matches Google API conventions, so it is defensible. -- **Suggestion:** Keep for parity with Go/proto and Google API - convention. Just note that `createdTime`/`updatedTime` would read - more naturally in TS. +_None._ --- ### 13. Go / Java-style names -#### F13.1 — `req`, `resp`, `err`, `httpReq`, `apiErr`, - `pkgJson`, `opts` (HIGH, but cross-cutting) -- **Where:** - - `req` everywhere in `client.ts` - - `resp` everywhere in `client.ts` and `utils.ts:73, 75, 81, 84, 88` - - `e` in `utils.ts:76` (with rethrow) - - `httpReq` in client.ts - - `apiErr` in utils.ts:88 - - `pkgJson` in client.ts:19 - - `opts` in utils.ts:30, 66 -- **Why flagged:** These are all classic Go idioms ported verbatim. - TS convention favors spelled-out names (`request`, `response`, - `error`, `httpRequest`, `apiError`, `packageJson`, `options`). -- **Suggestion:** Spell them out. Trivial diff, large readability - gain. This is a porting-convention decision and should be made - globally at the generator level. - -#### F13.2 — Comment style (acceptable) -- Comments are sentences. Good — but the file-top comment is the - generator banner. +_None._ --- @@ -460,43 +300,19 @@ _None._ ### 15. Field contradicting type domain -#### F15.1 — `BudgetConfigurationFilter_WorkspaceIdClause` typed - as `number[]` (MEDIUM) -- **Where:** `model.ts:95`. See F6.1. - -#### F15.2 — `LIST_PRICE_DOLLARS_USD` member on - `AlertConfigurationQuantityType` (LOW) -- **Where:** `model.ts:10`. -- **Why flagged:** Name implies *currency*, type is "quantity type". - The "quantity" in the API is a dollar amount. Minor domain - mismatch — could be `Currency`, `Cost`, or `Price` enum. -- **Suggestion:** Out of scope for TS rename; wire value. +_None._ --- ### 16. Inconsistent action verbs -#### F16.1 — `Get` vs `List` for read endpoints (acceptable) -- `get` for single, `list` for collection. Standard REST verbs. +_None._ --- ### 17. Long enum values -#### F17.1 — `CUMULATIVE_SPENDING_EXCEEDED` (MEDIUM) -- **Where:** `model.ts:18`. -- **Why flagged:** 28 characters. Long but informative. -- **Suggestion:** Wire value; cannot rename in TS without losing - parity. Acceptable. - -#### F17.2 — `LIST_PRICE_DOLLARS_USD` (MEDIUM) -- **Where:** `model.ts:10`. -- **Why flagged:** 22 characters; `DOLLARS_USD` is doubly redundant. - Could be `LIST_PRICE_USD` or `USD`. -- **Suggestion:** Wire value; report upstream. - -#### F17.3 — `EMAIL_NOTIFICATION` (LOW) -- **Where:** `model.ts:6`. 18 characters; reasonable. +_None._ --- @@ -504,14 +320,11 @@ _None._ #### F18.1 — `budgetId` vs `budgetConfigurationId` for the same thing (HIGH) -- See F11.5. The `budgetId` form is *less* underspecified than +- See F11.4. The `budgetId` form is *less* underspecified than `budgetConfigurationId` if the package name carries "budgets" context — both are unambiguous in this package; the issue is inconsistency. -#### F18.2 — `accountId` (acceptable) -- Specific enough; matches platform-wide convention. - --- ## Package overlap: `budgets` vs `budgetpolicy` @@ -550,13 +363,6 @@ This SDK exposes two separate packages whose names both start with inconsistency. - **Suggestion:** When (if) renaming, align the two field shapes. -### F-OVERLAP.3 — Package directory name `budgets` (plural) vs - `budgetpolicy` (singular) (LOW) -- Cross-package naming pluralization inconsistency. Other examples - in the repo: `clusters` vs `clusterpolicies` vs `budgetpolicy`. - Mixed. -- **Suggestion:** Cross-cutting style decision. Pick one. - --- ## Summary table @@ -565,29 +371,29 @@ This SDK exposes two separate packages whose names both start with | - | --------------------------------------- | -------- | | 1 | Vague / generic | 3 | | 2 | Redundant enum prefixes | 0 | -| 3 | Acronym casing | 3 (3 acceptable) | +| 3 | Acronym casing | 0 | | 4 | Underscores in TS identifiers | 0 | -| 5 | Cryptic abbreviations | 7 | -| 6 | Misleading names | 2 | +| 5 | Cryptic abbreviations | 1 | +| 6 | Misleading names | 0 | | 7 | Overly verbose | 3 | -| 8 | Singular / plural mismatch | 4 (3 acceptable) | -| 9 | Reserved-word collisions | 3 (3 acceptable) | +| 8 | Singular / plural mismatch | 1 | +| 9 | Reserved-word collisions | 0 | | 10 | Empty / trivial wrappers | 0 | -| 11 | Duplicate concepts | 5 | -| 12 | Verb-tense inconsistency | 2 (2 acceptable) | -| 13 | Go / Java-style names | 2 (1 acceptable) | +| 11 | Duplicate concepts | 4 | +| 12 | Verb-tense inconsistency | 0 | +| 13 | Go / Java-style names | 0 | | 14 | Generic field names | 1 | -| 15 | Field contradicting type domain | 2 | -| 16 | Inconsistent action verbs | 1 (1 acceptable) | -| 17 | Long enum values | 3 | -| 18 | Underspecified IDs | 2 (1 acceptable) | -| OVERLAP | budgets vs budgetpolicy | 3 | +| 15 | Field contradicting type domain | 0 | +| 16 | Inconsistent action verbs | 0 | +| 17 | Long enum values | 0 | +| 18 | Underspecified IDs | 1 | +| OVERLAP | budgets vs budgetpolicy | 2 | --- ## Top highest-impact renames (recommended order) -1. **F11.5:** `budgetConfigurationId` → `budgetId` (or pick one +1. **F11.4:** `budgetConfigurationId` → `budgetId` (or pick one universally). Same concept under two names is the worst smell here. 2. **F7.1 / F7.3 / F11.1:** Collapse `BudgetConfiguration`, `CreateBudgetConfigurationBudget`, @@ -595,10 +401,8 @@ This SDK exposes two separate packages whose names both start with 3. **F1.1:** Rename `ActionConfiguration` to `BudgetAlertAction`. 4. **F7.2:** Drop "Configuration" from request type names (`CreateBudgetRequest`). -5. **F11.4:** Lift `accountId` to top-level on all request types +5. **F11.3:** Lift `accountId` to top-level on all request types (currently nested under `budget` for create/update only). -6. **F13.1 / F5.x:** Spell out `req`/`resp`/`err`/`opts`/ - `pkgJson` etc. across all generated code. --- diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md index d9f488d0..ac1af952 100644 --- a/.agent/naming-audit/bundle.md +++ b/.agent/naming-audit/bundle.md @@ -1,7 +1,7 @@ # Naming Audit — `@databricks/sdk-bundle` (v1) **Package path:** `/home/parth.bansal/sdk-js/packages/bundle/` -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/index.ts` **Domain:** Databricks Asset Bundles (DAB) — control-plane registry for `databricks bundle deploy`/`destroy` runs. --- @@ -12,9 +12,9 @@ | ------------ | ----- | | High | 3 | | Medium | 6 | -| Low | 6 | -| Observation | 5 | -| **Total** | **20** | +| Low | 5 | +| Observation | 4 | +| **Total** | **18** | Dominant themes: 1. **`VersionComplete` is a misleading type name.** It is a noun that reads like a boolean predicate, but it actually carries a completion *reason* enum; the type, the field that holds it (`completionReason`), and the values disagree on terminology. @@ -171,33 +171,21 @@ This is correct re-use — both reference the same bundle config path. No issue. --- -### L6. `deployments` request method names vs URL path consistency - -**Location:** `Client.listDeployments` → `/api/2.0/bundle/deployments` (`client.ts:428`). - -The URL is `/api/2.0/bundle/deployments` (`/api/2.0/{service}/{resource}`). The method `listDeployments` matches. No issue, just noting the package's external resource is named "deployment" and the package is named "bundle", reinforcing the H2 observation that "Bundle" is in the URL but absent from type names. - ---- - ## Observations (Non-Defects) ### O1. JSDoc on the `state` fields is good `Resource.state` and `Operation.state` both clearly say "Serialized local config state". Doc-level disambiguation is solid. -### O2. Pagination wire shape is uniform and correct - -`pageSize`, `pageToken`, `nextPageToken` — all four `List*Request`/`List*Response` pairs are mechanically identical on the wire. - -### O3. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing +### O2. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is correct. -### O4. Method `getResource` returns `Resource`, no naming collision +### O3. Method `getResource` returns `Resource`, no naming collision `client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level. -### O5. Comment on the `name`-vs-`destroy` divergence is appreciated +### O4. Comment on the `name`-vs-`destroy` divergence is appreciated `Deployment.destroyTime` has an in-code justification (`model.ts:256-257`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on other overloaded fields. @@ -226,11 +214,10 @@ The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is | File | Lines | Findings | | ----------------- | ----- | --------------------------------------------------------------------------------- | -| `src/v1/model.ts` | 842 | H1, H2, H3, M1-M4, M6, L1, L2, L4, L5, O1, O3, O5 | -| `src/v1/client.ts`| 629 | H3 (method name), M5, L6, O4 | -| `src/v1/utils.ts` | 150 | (no findings — internal helpers, all well-named: `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, `HttpCallOptions`) | +| `src/v1/model.ts` | 842 | H1, H2, H3, M1-M4, M6, L1, L2, L4, L5, O1, O2, O4 | +| `src/v1/client.ts`| 629 | H3 (method name), M5, O3 | | `src/v1/index.ts` | 39 | Re-exports — inherits findings from `model.ts` and `client.ts`. | -Every exported identifier in `model.ts` and `client.ts` was inspected. `utils.ts` and `index.ts` produced no incremental findings beyond what the model/client files surface. +Every exported identifier in `model.ts` and `client.ts` was inspected. `index.ts` produced no incremental findings beyond what the model/client files surface. --- diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index 8510f733..16374f9f 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -70,10 +70,6 @@ symmetry). Today, `UpdateCatalogRequest` has *both* `nameArg` (path) and #### 3.3 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:216) — see §2.2. -#### 3.4 `pkgJson` (client.ts:19) -Variable name `pkgJson` for `package.json`. Mostly internal — minor — but -worth noting for consistency. - --- ### 4. Misleading names @@ -342,45 +338,11 @@ for consistency with the broader review. - **Suggested:** Remove from the public surface. - **Rationale:** See 13.4. -#### 13.10 `unmarshalDeleteCatalogRequest_ResponseSchema` — model.ts:409 -- **Why:** Schema identifier inherits the underscore-paired proto name - from 13.6, propagating the leak into the marshal/unmarshal surface. -- **Category:** Proto suffix/infix. -- **Suggested:** Rename in lockstep with 13.6 to - `unmarshalDeleteCatalogResponseSchema`. -- **Rationale:** The schema's identity is derived from the type it - decodes; fixing 13.6 dictates this rename. - -#### 13.11 `unmarshalListCatalogsRequest_ResponseSchema` — model.ts:441 -- **Why:** Same as 13.10 — schema name inherits the proto-paired - underscore. -- **Category:** Proto suffix/infix. -- **Suggested:** Rename in lockstep with 13.7 to - `unmarshalListCatalogsResponseSchema`. -- **Rationale:** See 13.10. - --- ## Additional / cross-cutting observations -### A. `flattenQueryParams` is defined but unused (utils.ts:123) -Each `listCatalogs` / `getCatalog` / `deleteCatalog` handler builds query -strings inline with `URLSearchParams.append` (client.ts:101-105, -138-141, 179-191). The exported helper `flattenQueryParams` is never -referenced by `client.ts`. Either it's intentionally exported for -consumer use (then it should be documented and reside in `utils` proper) -or it's dead code. - -### B. `nameArg` URL substitution silently allows empty string (client.ts:100, 137, 241) -`${req.nameArg ?? ''}` — if `nameArg` is undefined, the URL silently -becomes `/api/2.1/unity-catalog/catalogs/` and the request will fail on -the server. The naming (`nameArg`) and the substitution behaviour -together hide what should be a required parameter. Worth surfacing via -a non-optional type or a typed assertion. - -### C. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) -"Host is required." — bare `Error`. Not a naming issue, flagged in -passing for the broader review. +_None._ --- @@ -420,11 +382,7 @@ passing for the broader review. | `ListCatalogsRequest_Response` | model.ts:251 | 13.7 | | `UpdateCatalogRequest_OptionsEntry` | model.ts:325 | 13.8 | | `UpdateCatalogRequest_PropertiesEntry` | model.ts:331 | 13.9 | -| `unmarshalDeleteCatalogRequest_ResponseSchema` | model.ts:409 | 13.10 | -| `unmarshalListCatalogsRequest_ResponseSchema` | model.ts:441 | 13.11 | | `Client` (bare name) | client.ts:44 | 12 | -| `${req.nameArg ?? ''}` URL substitution | client.ts:100,137,241 | B | -| `flattenQueryParams` (unused export) | utils.ts:123 | A | --- @@ -435,6 +393,5 @@ passing for the broader review. 3. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§2.2, §4.2) 4. **Strip read-only fields from `CreateCatalogRequest`/`UpdateCatalogRequest`.** (§9.2) 5. **Decide CMK casing and apply uniformly.** (§2.1, §10.1) -6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) --- diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index 43dd8e98..ad24a1b0 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -1,7 +1,7 @@ # Naming Audit: `cleanrooms` (v1) **Path:** `/home/parth.bansal/sdk-js/packages/cleanrooms/` -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/index.ts` **Auditor:** Naming audit pass — TypeScript port of Databricks Go SDK. This audit catalogs every type, field, enum value, and method name in the @@ -12,7 +12,7 @@ grouped by category, and each finding cites the file/line where it appears. ## Summary -- **Total findings:** 10 +- **Total findings:** 9 - **Highest-impact themes:** 1. Misleading boolean-shaped `accessRestricted` enum. 2. Acronym casing inconsistencies (`Id` vs `ID`, `Dns` vs `DNS`). @@ -53,12 +53,6 @@ yes/no. The shape itself is boolean-like (two values, one of which is the absence sentinel) — a `boolean` field would model the domain more honestly. -### 3.2 `CreateCleanRoomWaiter` class (client.ts:881) -The waiter polls `getCleanRoom` and resolves when status reaches `ACTIVE`. -Naming it `CreateCleanRoomWaiter` ties it to `createCleanRoom`, but the -waiter is operationally generic (any clean room name can be polled). A -better name is `CleanRoomActivationWaiter` or `CleanRoomStatusWaiter`. - --- ## 4. Singular / Plural Mismatches @@ -150,9 +144,5 @@ _None._ use correct plurality. - JSDoc is generally comprehensive — references to UC naming rules and external compliance documents are well-linked. -- The `StillRunningError` class (client.ts:83) is concise and - self-documenting. -- The package-level segment naming (`PACKAGE_SEGMENT` in client.ts:78) - is appropriately namespaced. --- diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index f4d86436..9ecdbee0 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -1,7 +1,7 @@ # Naming Audit: `clusterlibraries` (v2) Path: `/home/parth.bansal/sdk-js/packages/clusterlibraries/` -Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/utils.ts`, `src/v2/index.ts` +Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` Scope: every type, field, enum value, method, and exported identifier. Findings are grouped by category. Severity reflects the impact on TS consumers @@ -234,14 +234,4 @@ Methods audited (`client.ts`): - `installLibraries` (144). - `uninstallLibraries` (176). -Utilities audited (`utils.ts`): -- `HttpCallOptions` (15). -- `executeCall` (26). -- `readAll` (40). -- `executeHttpCall` (65). -- `buildHttpRequest` (96). -- `parseResponse` (113). -- `marshalRequest` (119). -- `flattenQueryParams` (123). - --- diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index b229f782..f87e8370 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -7,7 +7,6 @@ - `src/v2/model.ts` - `src/v2/client.ts` -- `src/v2/utils.ts` - `src/v2/index.ts` This audit catalogues every identifier (type, field, enum value, method, @@ -100,21 +99,7 @@ rubric. Issues are graded: ### 1.5 Other identifiers -- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields - `host`, `httpClient`, `logger`, `userAgent`. -- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`. -- Marshal / unmarshal schemas: `unmarshalCreatePolicyRequest_ResponseSchema`, - `unmarshalDeletePolicyRequest_ResponseSchema`, - `unmarshalEditPolicyRequest_ResponseSchema`, `unmarshalLibrarySchema`, - `unmarshalListPoliciesRequest_ResponseSchema`, - `unmarshalMavenLibrarySchema`, `unmarshalPolicySchema`, - `unmarshalPythonPyPiLibrarySchema`, `unmarshalRCranLibrarySchema`, - `marshalCreatePolicyRequestSchema`, `marshalDeletePolicyRequestSchema`, - `marshalEditPolicyRequestSchema`, `marshalLibrarySchema`, - `marshalMavenLibrarySchema`, `marshalPythonPyPiLibrarySchema`, - `marshalRCranLibrarySchema`. +- `client.ts`: `Client` class (public, top-level export). --- @@ -125,7 +110,6 @@ rubric. Issues are graded: | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `Policy.description` (`model.ts:228`), `CreatePolicyRequest.description` (`model.ts:26`), `EditPolicyRequest.description` (`model.ts:74`) | Low | Generic but standard across the SDK; acceptable. | -| V-02 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | ### 2.2 Redundant enum prefixes @@ -137,8 +121,6 @@ _None._ | ----- | --------------------- | -------- | ----- | | A-01 | `PythonPyPiLibrary` (`model.ts:251`) | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. | | A-02 | `RCranLibrary` (`model.ts:264`) | Medium | "CRAN" is an acronym ("Comprehensive R Archive Network"). The type uses `Cran` (PascalCase) which is acceptable under Google TS style (acronyms ≥3 chars → only first letter capitalised). However, the JSDoc and surrounding usage refers to "CRAN library". Consistent with the rule but worth noting — peer types like `PolicySortColumn` keep full uppercase in member names. Leave as-is for Google style compliance. | -| A-03 | `RCranLibrary` — prefix `R` (`model.ts:264`) | Low | The leading lone `R` (the language) is awkward; the Go SDK uses the same name so this is a porting constraint. | -| A-04 | `pypi` discriminator case (`Library.lib.$case === 'pypi'`, `model.ts:124`) | Low | Lowercased, matching API wire format; consistent with `jar`, `egg`, `cran`, `maven`. Acceptable. | ### 2.4 Underscores in TS identifiers @@ -148,25 +130,17 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------- | -------- | ----- | -| C-01 | `Library.lib.$case === 'whl'` (`model.ts:145`) | Medium | `whl` (wheel) is a Python packaging file extension; readers unfamiliar with Python will not know it. Documented in JSDoc but the discriminator value itself is opaque. | -| C-02 | `Library.lib.$case === 'egg'` (`model.ts:119`) | Medium | Same as C-01 for Python "egg" files. The JSDoc even notes it is "Deprecated". | -| C-03 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Maven term, OK in context. | -| C-04 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`, throughout) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | -| C-05 | `opts` (`utils.ts:66`, `executeHttpCall` parameter) | Low | Inside fn scope; minor. | +| C-01 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Maven term, OK in context. | ### 2.6 Misleading names — High -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| M-01 | `EditPolicyRequest` (`model.ts:63`) / `editPolicy()` (`client.ts:133`) | High | Standard CRUD verbs in TS/REST are **create / read / update / delete**. The Databricks "Cluster Policies 2.0" API uses `/edit` as the wire path, but the SDK could still expose `updatePolicy` (with `UpdatePolicyRequest` request type) which is the conventional REST verb. Compare with the newer `policies` API surface and most other Databricks SDK resources that expose `update*`. As-is, the SDK exposes `editPolicy` while peer packages (e.g. `clusters`) often expose `editCluster` too — there is precedent — but it remains inconsistent with the broader CRUD vocabulary. Tracked here as a discrepancy worth raising upstream. | +_None._ ### 2.7 Overly verbose / Redundant suffixes — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| O-01 | `policyFamilyDefinitionOverrides` (`model.ts:42`, `model.ts:90`, `model.ts:244`) | Medium | Five-word camel-case identifier. Inherited from the API; very long but no shorter form is unambiguous. Accept as upstream constraint. | -| O-02 | `PACKAGE_SEGMENT` (`client.ts:44`) | Low | OK in context. | -| O-03 | `Policy.maxClustersPerUser` (`model.ts:246`) | Low | Long but precise. | +| O-01 | `Policy.maxClustersPerUser` (`model.ts:246`) | Low | Long but precise. | ### 2.8 Singular / plural mismatches — Low @@ -207,7 +181,6 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `MavenLibrary` (`model.ts:187`), `PythonPyPiLibrary` (`model.ts:251`), `RCranLibrary` (`model.ts:264`) (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | -| G-02 | `httpClient` / `HttpClient` (vs `HTTPClient`) (`client.ts:51`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | ### 2.14 Generic field names losing meaning — Medium @@ -215,7 +188,6 @@ _None._ | ----- | ----------------------------------- | -------- | ----- | | F-01 | `Policy.name` (`model.ts:224`), `Policy.description` (`model.ts:228`) | Low | Standard entity fields; meaning preserved in context. | | F-02 | `MavenLibrary.coordinates` (`model.ts:189`) | Low | Maven-specific; precise. | -| F-03 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | ### 2.15 Field contradicting type domain — Low @@ -227,8 +199,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| AV-01 | `editPolicy()` (`client.ts:133`) vs ecosystem-standard `update` | Medium | Most modern Databricks APIs (and broader REST APIs) use **update**. This package uses **edit** to match the API path `/api/2.0/policies/clusters/edit`. The verb mismatch within the Databricks SDK as a whole (e.g. `Clusters.editCluster` exists, but newer surfaces use `update*`) is upstream. Flagged for awareness. | -| AV-02 | `getPolicy()` (`client.ts:159`, singular) vs `listPolicies()` (`client.ts:190`, plural) | Low | Correct convention (singular get, plural list). Consistent. | +| AV-01 | `getPolicy()` (`client.ts:159`, singular) vs `listPolicies()` (`client.ts:190`, plural) | Low | Correct convention (singular get, plural list). Consistent. | ### 2.17 Long enum values @@ -256,15 +227,10 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | X-01 | `Policy.createdAtTimestamp` (`model.ts:214`, epoch ms, `number`) | Medium | JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | -| X-02 | `Library.lib.$case` literal `'requirements'` (`model.ts:156`) | Low | The discriminator value `'requirements'` is the longest in the union (12 chars) and contrasts with three-letter peers (`jar`, `egg`, `whl`). Consistent with wire format, OK. | -| X-03 | `HttpCallOptions` (`utils.ts:15`) | Low | Local interface; precise. | -| X-04 | `executeHttpCall` (`utils.ts:65`), `executeCall` (`utils.ts:26`) | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | -| X-05 | `readAll` (`utils.ts:40`, private) | Low | Reads a `ReadableStream` to a `Uint8Array`. Standard name. | -| X-06 | `flattenQueryParams` (`utils.ts:123`, exported but unused in this package?) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | ### 2.21 Proto / architectural-leak naming -_None._ Scanned all identifiers in `model.ts`, `client.ts`, `utils.ts`, and +_None._ Scanned all identifiers in `model.ts`, `client.ts`, and `index.ts` for mid-position `Public`/`Internal`/`External` (non-domain), `Proto` suffix/infix, `Service`/`Server`/`Backend`/`Frontend`, `Rpc`/`Grpc`, `Manager`/`Handler`/`Controller`/`Processor`/`Daemon`/`Worker` (non-domain), @@ -283,21 +249,17 @@ architectural-layer words leaking into domain identifiers. | Severity | Count | | -------- | ----- | -| High | 2 | -| Medium | 11 | -| Low | 29 | -| **Total**| **42**| +| High | 1 | +| Medium | 7 | +| Low | 16 | +| **Total**| **24**| ### 3.2 Top themes 1. **`PyPi` casing should be `PyPI`** (acronym); the type name `PythonPyPiLibrary` should be `PythonPyPILibrary`. -2. **`editPolicy` vs ecosystem-standard `update`** — the SDK exposes - `editPolicy` to match the wire path `/edit`, but most modern Databricks - surfaces use `update*`. Flag for upstream alignment. - -3. **Type-suffix tautology in the `Library` union**: `MavenLibrary`, +2. **Type-suffix tautology in the `Library` union**: `MavenLibrary`, `PythonPyPiLibrary`, `RCranLibrary` all repeat the `Library` suffix even though their *position* in the discriminated union already identifies them as library variants. @@ -309,5 +271,4 @@ section is advisory for the codegen owners) ### 3.4 Cross-package consistency notes -- `editPolicy` (vs `updatePolicy`) is a per-API decision driven by the - upstream REST verb; flag for upstream alignment but no per-package fix. +_None._ diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index 2f49a100..cf001f62 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -3,15 +3,15 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 **Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 38 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 17 | -| Low | 6 | -| Observation | 7 | +| High | 2 | +| Medium | 16 | +| Low | 2 | +| Observation | 0 | ## High severity @@ -27,179 +27,113 @@ - **Suggested name:** Pick one of each aliased pair and document deprecation on the other. - **Rationale:** Public SDK enums should not ship two members for one concept; one of each pair should be `@deprecated`. -### 3. `CloudProviderNodeStatus` enum uses non-SCREAMING_SNAKE wire values — `src/v2/model.ts:40-43` -- **Why weird:** `NOT_ENABLED_ON_SUBSCRIPTION = 'NotEnabledOnSubscription'` and `NOT_AVAILABLE_IN_REGION = 'NotAvailableInRegion'`. The TS identifier is `SCREAMING_SNAKE` (every other enum in this file follows that), but the wire value is `PascalCase`. Every other enum's wire value matches the TS identifier exactly. -- **Category:** 17 (inconsistent wire-value casing). -- **Suggested name:** Keep the SCREAMING_SNAKE TS identifier; this is an upstream wire-value inconsistency that the generator faithfully reproduces. -- **Rationale:** Highlight to upstream — the API surface should be uniform. Flagged here so downstream consumers know to expect PascalCase strings for this one enum. - -### 4. `TerminationCode.*` — 150+ enum values, internal jargon and duplicated concepts — `src/v2/model.ts:175-734` -- **Why weird:** The enum has ~150 values; many encode the same concept three or four times. Examples: `BOOTSTRAP_TIMEOUT` vs `BOOTSTRAP_TIMEOUT_DUE_TO_MISCONFIG` vs `BOOTSTRAP_TIMEOUT_CLOUD_PROVIDER_EXCEPTION`; `INSTANCE_UNREACHABLE` vs `INSTANCE_UNREACHABLE_DUE_TO_MISCONFIG`; `CONTROL_PLANE_REQUEST_FAILURE` vs `CONTROL_PLANE_REQUEST_FAILURE_DUE_TO_MISCONFIG` (whose JSDoc just says "CPRF, but due to misconfiguration on the customer's side"). Several values reference internal Databricks jargon: `NEPHOS_RESOURCE_MANAGEMENT`, `CHAUFFEUR`, `NPIP_TUNNEL`, `IN_PENALTY_BOX`, `CMv2`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT`, `GKE_BASED_CLUSTER_TERMINATION`. -- **Category:** 5 (cryptic abbreviations — Nephos, CPRF, CPLF, CMv2, DBR, NPIP, CMK, K8s, IMv2), 8 (internal jargon in public surface), 12 (duplicate concepts — many `_DUE_TO_MISCONFIG` siblings duplicate the base reason), 18 (150-value enum size). -- **Suggested name:** Out of scope for a rename, but flag upstream: collapse `_DUE_TO_MISCONFIG` siblings into a structured field (`misconfig: boolean` on `TerminationReason`) instead of doubling every code; document internal-jargon codes for external consumers. -- **Rationale:** This is a public SDK; values like `IN_PENALTY_BOX` and `NEPHOS_RESOURCE_MANAGEMENT` leak internal-process names to customers and are unfit for external naming. Comments on `GCP_QUOTA_EXCEEDED` (`model.ts:426`) literally include a TODO about consolidating per-cloud reasons — the SDK is shipping the unconsolidated state. The enum size alone (150 values) is a domain concern. - -### 5. `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` — `src/v2/model.ts:432` -- **Why weird:** `BYOK` is "Bring Your Own Key". Abbreviation used without expansion in either the enum value or the JSDoc. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** Expand to `AZURE_CUSTOMER_KEY_PERMISSION_FAILURE` or document `BYOK` inline. -- **Rationale:** External SDK users will not all know `BYOK` is a cloud-key acronym. - -### 6. `TerminationCode.NPIP_TUNNEL_TOKEN_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE` — `src/v2/model.ts:320,361` -- **Why weird:** `NPIP` ("No Public IP") is internal Databricks networking terminology. Not expanded in JSDoc. -- **Category:** 5 (cryptic abbreviation), 8 (internal jargon in public surface). -- **Suggested name:** Rename to `NO_PUBLIC_IP_TUNNEL_*` or document `NPIP` in the enum docstring. -- **Rationale:** Same as #5; SDK users should not need to know Databricks' internal acronyms. - -### 7. `TerminationCode.AWS_INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET_FAILURE` vs `GCP_IP_SPACE_EXHAUSTED` cross-cloud asymmetry — `src/v2/model.ts:379,590` -- **Why weird:** AWS enum value is 52 characters; GCP equivalent is 22 chars — same concept, very different length. JSDoc at line 421 explicitly TODOs consolidating these. -- **Category:** 17 (inconsistent across clouds). -- **Suggested name:** `AWS_SUBNET_IP_EXHAUSTED` (mirror the GCP form). -- **Rationale:** Per-cloud variants should follow the same shape; the AWS/GCP/Azure versions of the same condition should not differ in length by 30 characters. - -### 8. `TerminationCode.ALLOCATION_TIMEOUT_*` family — eight near-identical codes — `src/v2/model.ts:661-686` -- **Why weird:** Eight `ALLOCATION_TIMEOUT_*` siblings all encode subtle internal scheduler states (e.g., `ALLOCATION_TIMEOUT_NO_HEALTHY_AND_WARMED_UP_CLUSTERS` at line 686). -- **Category:** 12 (duplicate concept across eight near-identical codes). -- **Suggested name:** Collapse the family into `ALLOCATION_TIMEOUT` with a structured sub-field (`reason: string`) on `TerminationReason.parameters`. -- **Rationale:** Eight `ALLOCATION_TIMEOUT_*` codes look like the inverse of "values should be discriminator-friendly". External callers will hardly distinguish `NO_HEALTHY_CLUSTERS` from `NO_HEALTHY_AND_WARMED_UP_CLUSTERS`. - ## Medium severity -### 9. `Adlsgen2Info` casing — `src/v2/model.ts:917` +### 3. `Adlsgen2Info` casing — `src/v2/model.ts:917` - **Why weird:** Type name is `Adlsgen2Info` — should be `AdlsGen2Info` to match acronym-casing rules. ADLS (Azure Data Lake Storage) Gen2 should retain the boundary between `Adls` and `Gen2`. - **Category:** 3 (acronym casing inconsistency), 1 (vague `Info` suffix). - **Suggested name:** `AdlsGen2Storage` (or just `AbfssStorage`, since the wire name is `abfss`). - **Rationale:** Compare to sibling types `DbfsStorageInfo`, `GcsStorageInfo`, `S3StorageInfo` — all use `Info` suffix and capitalize the storage product. `Adlsgen2Info` is the odd one out. -### 10. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:917,2101,2509,2875,3044,3391,3414` +### 4. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:917,2101,2509,2875,3044,3391,3414` - **Why weird:** `Adlsgen2Info` (no `Storage`), `DbfsStorageInfo`, `GcsStorageInfo`, `LocalFileInfo` (no `Storage`), `S3StorageInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. Seven sibling types; five say `StorageInfo`, two say `Info`. - **Category:** 17 (inconsistent suffix across siblings). - **Suggested name:** Standardise on `XStorage` (drop the redundant `Info`) — `AdlsGen2Storage`, `DbfsStorage`, `GcsStorage`, `LocalFileStorage`, `S3Storage`, `VolumesStorage`, `WorkspaceStorage`. - **Rationale:** All seven describe the same kind of thing (a storage destination). Either all of them get `StorageInfo` or none do. -### 11. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:1253,2350,2361,2595,2812` +### 5. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:1253,2350,2361,2595,2812` - **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForClusterRequest` (a request), `GetPolicyComplianceForClusterRequest_Response`, `EnforcePolicyComplianceForClusterRequest` (request), `ListClusterComplianceForPolicyRequest` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. - **Category:** 1 (vague — `For` is the only disambiguator), 6 (misleading — easy to mis-parse). - **Suggested name:** `GetClusterPolicyComplianceRequest`, `EnforceClusterPolicyComplianceRequest`, `ListPolicyCompliantClustersRequest`, `ClusterPolicyCompliance`. - **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. -### 12. `hasChanges` field — `src/v2/model.ts:2366` +### 6. `hasChanges` field — `src/v2/model.ts:2366` - **Why weird:** Boolean on `EnforcePolicyComplianceForClusterRequest_Response` named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. - **Category:** 12 (duplicate signal), 1 (vague). - **Suggested name:** Drop the field, infer from `changes.length`. - **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. -### 13. `useMlRuntime` field — `src/v2/model.ts:1210` +### 7. `useMlRuntime` field — `src/v2/model.ts:1210` - **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. - **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). - **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. - **Rationale:** A boolean and an enum jointly describing one runtime selection is a boolean-shaped-enum smell. -### 14. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields +### 8. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields - **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. - **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). - **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. - **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. -### 15. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` +### 9. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` - **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. - **Category:** 17 (inconsistent grouping). - **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. - **Rationale:** Within the same type, related fields should sit together. -### 16. `clusterLogStatus` field — `src/v2/model.ts:1330` +### 10. `clusterLogStatus` field — `src/v2/model.ts:1330` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). - **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. - **Rationale:** Same concept, two different names in 5 lines. -### 17. `jdbcPort` field — `src/v2/model.ts:1358` +### 11. `jdbcPort` field — `src/v2/model.ts:1358` - **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). -- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #18). +- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #12). -### 18. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` +### 12. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` - **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. - **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. -### 19. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` +### 13. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` - **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. - **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). - **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. - **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. -### 20. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` +### 14. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` - **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. - **Category:** 12 (duplicate concepts), 17 (could be a tagged union). - **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). - **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. -### 21. `S3StorageInfo.region` / `endpoint` mutually-exclusive pair — `src/v2/model.ts:3055,3060` -- **Why weird:** JSDoc explicitly says "Either region or endpoint needs to be set. If both are set, endpoint will be used." Mutually-exclusive fields not encoded in the type. -- **Category:** 16 (field-pair constraint not in the type). -- **Suggested name:** Could be a discriminated union `{kind: 'region', value: string} | {kind: 'endpoint', value: string}`. -- **Rationale:** Type-system-encodable constraint; flagged for upstream. - -### 22. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` +### 15. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` - **Why weird:** `SparkInfo` is declared as an empty interface (`export interface SparkInfo {}`) whose JSDoc literally says "This is used in both the [[ClusterInfo]] for Cluster APIs and persisted cluster proto." Its only purpose is to namespace `SparkInfo_SparkNode` and `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Empty wrapper types tied to "persisted cluster proto" are pure proto-architectural leak — the TS surface carries a do-nothing type just to mirror proto message nesting. - **Category:** 14 (proto-style namespace anchor), 8 (JSDoc references the proto wire layer). - **Suggested name:** Delete `SparkInfo`; expose `SparkNode` (and `SparkNodeAwsAttributes`) as top-level types. - **Rationale:** TS doesn't need proto-style nesting; the empty parent interface is a generator artefact and a user-facing footgun (auto-completion shows a useless symbol). -### 23. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` -- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #24) is the smoking gun — the parent exists only to host the child. +### 16. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` +- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #17) is the smoking gun — the parent exists only to host the child. - **Category:** 14 (proto-style namespace anchor). - **Suggested name:** Delete `ClusterEventType` (the parent) and flatten the enum to a top-level `ClusterEventType` enum. The empty wrapper adds no value. -- **Rationale:** Same as #22 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. +- **Rationale:** Same as #15 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. -### 24. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` -- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#23) is empty, so the doubly-stuttered name carries no information. +### 17. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` +- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#16) is empty, so the doubly-stuttered name carries no information. - **Category:** 14 (proto nesting stutter), 4 (redundant repetition). - **Suggested name:** `ClusterEventType` (single, top-level). -- **Rationale:** After deleting the empty parent (#23), the child can drop the `ClusterEventType_` prefix entirely. +- **Rationale:** After deleting the empty parent (#16), the child can drop the `ClusterEventType_` prefix entirely. -### 25. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` +### 18. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` - **Why weird:** "Data plane" is an internal Databricks infrastructure concept (vs "control plane") — not a customer-facing domain term. Two public types prefix their names with the deployment-plane they originate from. A user creating a cluster does not need to know which plane emitted which event class; the distinction is a Databricks-internal architecture detail. - **Category:** 8 (internal architecture leak in public surface). - **Suggested name:** Either merge into a single `ClusterEventType` enum / `EventDetails` shape, or rename to a non-infrastructure word (e.g., `RuntimeEventDetails`). -- **Rationale:** Customer SDK consumers should not be expected to map "data plane" onto their mental model of Databricks. Flagged for upstream — same class as `NEPHOS_RESOURCE_MANAGEMENT` (item #4) and `CMv2` (internal scheduler names leaking into public API). +- **Rationale:** Customer SDK consumers should not be expected to map "data plane" onto their mental model of Databricks. Flagged for upstream — same class as internal scheduler names leaking into public API. ## Low severity -### 26. `ClusterInfo.sparkContextId: number` — `src/v2/model.ts:1353` -- **Why weird:** Field is named `sparkContextId` but typed as `number`. Other IDs in the model are strings (`clusterId`, `policyId`, `nodeTypeId`). Internal Spark context IDs are 64-bit ints — the type clash hints at potential JS number-precision issues for large IDs. -- **Category:** 19 (underspecified ID — different type from sibling IDs). -- **Suggested name:** Keep but consider `bigint` typing or document the precision risk. -- **Rationale:** JS number safe-integer range is 2^53; if Spark uses 64-bit IDs, this is a latent bug. - -### 27. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` +### 19. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` - **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. - **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). - **Suggested name:** `credentials` (singular). - **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. -### 28. `AwsAttributes.spotBidPricePercent: number` — `src/v2/model.ts:981` -- **Why weird:** Field is a percentage but typed as `number` (no unit hint). Compare `AzureAttributes.spotBidMaxPrice: number` (`model.ts:1041`) — Azure version uses a raw price, AWS uses a percentage. Different semantics, same `number` type. -- **Category:** 17 (sibling AWS/Azure shapes differ), 1 (`number` without unit suffix). -- **Suggested name:** `spotBidPricePercent` is fine; flag for upstream — the AWS/Azure semantics should be more discoverable from the model. -- **Rationale:** Cross-cloud asymmetry is a domain concern. - -### 29. `AzureAttributes.spotBidMaxPrice` JSDoc reference to `>0 or -1` magic numbers — `src/v2/model.ts:1041` -- **Why weird:** Magic value `-1` overloaded as "do not evict on price basis". Encoded in JSDoc, not in the type. -- **Category:** 16 (sentinel value in scalar field), Observation. -- **Suggested name:** N/A; flag for upstream to consider a sentinel enum or `null`. -- **Rationale:** Sentinels in scalar fields are old-school API design. - -### 30. `EnforcePolicyComplianceForClusterRequest_Response_ClusterSettingsChange.previousValue` / `newValue` — `src/v2/model.ts:2390,2397` -- **Why weird:** Both fields typed as `string`. JSDoc says values are "either a number, a boolean, or a string converted to a string." Pre-stringified union encoded as plain string — caller must re-parse. -- **Category:** 16 (type contradicts domain — it's actually `number | boolean | string` flattened to string). -- **Suggested name:** Type as `string | number | boolean`, or `previousValueRaw`. -- **Rationale:** Documents the stringification rather than hiding it. - -### 31. `AutoScale` type name — `src/v2/model.ts:922` +### 20. `AutoScale` type name — `src/v2/model.ts:922` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). @@ -207,34 +141,7 @@ ## Observations -### 32. Seven Waiter classes with identical shape — `client.ts:967-1523` -The file declares `CreateClusterWaiter`, `DeleteClusterWaiter`, `EditClusterWaiter`, `ResizeClusterWaiter`, `RestartClusterWaiter`, `StartClusterWaiter`, `UpdateClusterWaiter` — 557 lines. The only variation between them is the set of terminal `ClusterState` values they accept (e.g., `CreateClusterWaiter` treats `RUNNING` as success and `TERMINATED` as failure; `DeleteClusterWaiter` does the opposite). The rest is copy-pasted. -- **Category:** 12 (duplicate concept across seven classes), Observation. -- **Suggested:** A generic `ClusterStateWaiter` parameterised by the success/failure state sets would shrink this to ~80 lines. - -### 33. `_req` parameter for empty request types — `client.ts:404,486,514` -Several methods take a `_req: ListAvailableZonesRequest` / `_req: ListNodeTypesRequest` / `_req: GetSparkVersionsRequest` parameter even though the request types are empty (`{}`). The underscore prefix avoids the unused-arg lint warning. Indicates the generator does not collapse empty requests. -- **Category:** Observation (generator artefact). - -### 34. `ResizeClusterRequest` / `RestartClusterRequest` requests are partial overlaps -`ResizeClusterRequest` carries `clusterId` and `size`; `RestartClusterRequest` carries `clusterId` and `restartUser`; `StartClusterRequest` carries only `clusterId`. Three near-identical types; could be one. -- **Category:** 12 (duplicate concept), Observation. - -### 35. `_req` unused vs `req` used — inconsistency in method-signature lint -Three client methods use `_req` (where the request type is empty), the rest use `req` (where it's not). Pure mechanical. -- **Category:** Observation. - -### 36. `clusterId?: string | undefined` shape -Every request type that targets a cluster has `clusterId?: string | undefined`. `?` (optional) plus `undefined` is the explicit-undefined style used throughout. But `clusterId` is semantically required for many operations (delete, edit, restart, etc.). Marking it optional means the runtime check `if (req.clusterId === undefined) throw new Error(...)` appears in every waiter constructor (`client.ts:258,304,357,641,683,733,817`). -- **Category:** 6 (misleading optional — should be required), Observation. - -### 37. `executeCall` / `executeHttpCall` (`utils.ts:26,65`) -Two functions whose names differ only by `Http`. Same pair-naming concern flagged in `abacpolicies.md` audit (item #36 there). -- **Category:** 1 (vague), 17 (inconsistent), Observation. - -### 38. `flattenQueryParams` exported but unused (`utils.ts:123`) -The function is exported but `client.ts` never calls it. (Cluster v2 endpoints with query params do it inline.) Same observation as in `abacpolicies.md`. -- **Category:** Observation (dead public surface). +_None._ ## Domain glossary diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index 57c73f05..97b6fa02 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -36,11 +36,8 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | 13 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | | 14 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | | 15 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 16 | low | 1. Vague/generic | `client.ts:54` | `StillRunningError` | Acceptable; private | -| 17 | low | 3. Acronym casing | `client.ts:50,77` | `userAgent` (good) but the package-segment key is `'sdk-auth'` and `'auth'` — distinct from camelCase API conventions | Hyphenated identifier-like keys are intentional (HTTP User-Agent tokens) — leave | -| 18 | low | 14. Go/Java-style | `client.ts:54` | `StillRunningError` | Idiomatic JS uses suffix `Error`; this is fine | -| 19 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 20 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 16 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 17 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | --- @@ -243,40 +240,13 @@ Go-SDK alignment decision. --- -### Finding 16 — Low — Cat 1 (Vague/generic) — call-out -**Location:** `src/v2/client.ts:54` -```ts -class StillRunningError extends Error {} -``` -Private, OK. Idiomatic for waiter polling patterns. - ---- - -### Finding 17 — Low — Cat 3 (Acronym casing) — non-issue -**Location:** `src/v2/client.ts:49-52` -```ts -const PACKAGE_SEGMENT = { key: pkgJson.name.replace(...), value: pkgJson.version }; -``` -`PACKAGE_SEGMENT` is a true constant (SCREAMING_SNAKE_CASE is correct). -Mixed with `userAgent` (camelCase method-scope variable). Both are -correctly cased per the project rules. - ---- - -### Finding 18 — Low — Cat 14 — non-issue -**Location:** `src/v2/client.ts:54` -**Issue:** `StillRunningError` is named in idiomatic TS style -(`*Error` suffix on classes extending Error). - ---- - -### Finding 19 — Low — Cat 15 (Generic field) — call-out +### Finding 16 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. --- -### Finding 20 — Low — Cat 3 (Acronym casing in enum string values) +### Finding 17 — Low — Cat 3 (Acronym casing in enum string values) **Location:** `src/v2/model.ts:42-43` ```ts SQL = 'SQL', diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index f990f812..5784a746 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -3,15 +3,15 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 21 +**Total weird names flagged:** 14 ## Summary | Severity | Count | | --- | --- | | High | 5 | | Medium | 8 | -| Low | 6 | -| Observation | 2 | +| Low | 0 | +| Observation | 1 | ## High severity @@ -97,55 +97,17 @@ ## Low severity -### 14. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:39` -- **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Same finding as in `abacpolicies` audit; consistent across generated packages. - -### 15. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Remove from utils if generator default. -- **Rationale:** Generator emits the same helper into every package even when unused. - -### 16. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Internal helper name is generic and clashes cognitively with `Array.prototype` / stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `readStreamToEnd` / `drainStream`. -- **Rationale:** Trivial; flagged for cross-package consistency. - -### 17. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. -- **Rationale:** Names should encode the layer, not just the protocol. - -### 18. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). -- **Rationale:** Distinguish internal context bags from user-facing option structs. - -### 19. Inconsistent option name: `req.maxResults` vs wire `max_results` — `src/v1/client.ts:167-168` -- **Why weird:** TS uses camelCase (`maxResults`); wire is snake_case (`max_results`). Conversion is buried in the client method. Fine in isolation but two near-identical strings live three lines apart. -- **Category:** Observation only. -- **Suggested name:** None — this is the marshalling boundary by design. -- **Rationale:** Just noting it for reviewer awareness. +_None._ ## Observations -### 20. Casing inconsistency in vendor name decomposition +### 14. Casing inconsistency in vendor name decomposition Within `ConnectionType`: - `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). - `MYSQL` (joined) vs `GA4_RAW_DATA` (split). No discoverable rule. Wire-locked, but worth surfacing. - **Category:** 3 (acronym/casing inconsistency). -### 21. `Client` constructor throws for missing host -`if (options.host === undefined) { throw new Error('Host is required.'); }` — error message is fine, naming is fine, but `Host is required.` doesn't tell the user which constructor failed. Flagged for cross-SDK consistency review. -- **Category:** Observation. - ## Domain glossary - `uc` — Unity Catalog (referenced in `model.ts` doc comments). - `raas` — Reporting as a Service (e.g. `WORKDAY_RAAS`). Doc-less. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index 29f82b22..09a0b353 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -13,7 +13,7 @@ cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure Managed Identity, GCP Service Account Key, Databricks-managed GCP Service Account, Cloudflare API token) and yields one of six temporary-credential shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). -**Total weird names flagged:** 24 (24 still applicable, 0 newly fixed in regeneration on 2026-05-26) +**Total weird names flagged:** 22 (22 still applicable, 0 newly fixed in regeneration on 2026-05-26) --- @@ -41,10 +41,8 @@ shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). | 18 | `R2Credentials` type | model.ts:861 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | | 19 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:619, 690, 723, 654 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | | 20 | `TemporaryCredentials` | model.ts:961 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | -| 21 | `purpose` field (referenced in JSDoc but absent from interface) | model.ts:264-266 (etc.) | (missing) | High | 6 Misleading names | The JSDoc text on `readOnly` and `usedForManagedStorage` (and elsewhere) says "Only applicable when purpose is **STORAGE**" / "**SERVICE**". But there is no `purpose` field on `CreateCredentialRequest`/`CredentialInfo`/`UpdateCredentialRequest`. Either the field is missing from the generated TS, or the doc is stale. Either way the contract is broken. | -| 22 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Cf. accountaccesscontrolproxy audit M5. | -| 23 | `ListCredentialsPublicRequest` | model.ts:776 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | -| 24 | `Client.createCredentialsPublic` / `Client.deleteCredentialsPublic` / `Client.getCredentialsPublic` / `Client.listCredentialsPublic` | client.ts:927, 953, 978, 1003 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `Client` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | +| 21 | `ListCredentialsPublicRequest` | model.ts:776 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | +| 22 | `Client.createCredentialsPublic` / `Client.deleteCredentialsPublic` / `Client.getCredentialsPublic` / `Client.listCredentialsPublic` | client.ts:927, 953, 978, 1003 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `Client` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | --- @@ -123,26 +121,9 @@ Three name-related fields on one envelope, no clear precedence. Recommend: drop the body-level `name` so only `nameArg` (path, identifying the existing credential) and `newName` (rename) remain. -### H5. `purpose` field is referenced in JSDoc but does not exist on the type +### H5. `Public` infix proto-architectural leak (1 type + 4 methods) -The JSDoc on `readOnly` (model.ts:264-266, etc.) and `usedForManagedStorage` -(model.ts:282-285) and `force` (model.ts:567-571) says "Only applicable when -purpose is **STORAGE**" or "**SERVICE**". But there is no `purpose` field -anywhere on `CreateCredentialRequest`/`UpdateCredentialRequest`/ -`CredentialInfo`/`StorageCredentialInfo`. Either: - -- The generator dropped the field, or -- The doc is stale (the API uses a different mechanism to decide purpose, e.g. - inferring from which discriminator case is set, or routing by endpoint), or -- The field is intentionally on the `Credential` side only and missing from - the model. - -In all cases the contract documented in JSDoc cannot be honored by a TS -caller. See #21. - -### H6. `Public` infix proto-architectural leak (1 type + 4 methods) - -Findings #23-#24. The package exposes **1 generated type** and **4 `Client` +Findings #21-#22. The package exposes **1 generated type** and **4 `Client` methods** whose identifiers carry `Public` as a mid-position or trailing word. The infix originates from the internal proto/service definition where `Public` distinguishes externally-routable account-API endpoints from @@ -236,27 +217,13 @@ for the type. Acronym handling within one chain should match. RFC 6749 (OAuth 2.0) titles the term as "OAuth". The code uses "Oauth". Minor. -### L3. `PACKAGE_SEGMENT` is undescriptive - -Used only for the User-Agent header. `USER_AGENT_PACKAGE_SEGMENT` is -self-documenting. - -### L4. `HttpCallOptions` - -Generic name, internal-only. Same pattern as in sibling packages. Fine inside -the file; would warrant a better name if it leaked out. - -### L5. `req` parameter naming in client methods - -Standard across the SDK. Go-idiomatic, but consistent. - -### L6. `Generate*CredentialRequest` method names are 30+ chars +### L3. `Generate*CredentialRequest` method names are 30+ chars `generateTemporaryServiceCredential` is 35 chars. Combined with `await client.generateTemporaryServiceCredential(req)` the call site is 60+ chars before the args. Cannot shorten without breaking the resource hierarchy. -### L7. Acronym casing review +### L4. Acronym casing review - `Aws` (PascalCase first letter) — `AwsCredentials`, `AwsIamRole`, `awsIamRole`. Internally consistent. @@ -347,7 +314,7 @@ Class re-exported with `export {Client}`; types and enums re-exported with |------|-------------------------| | **Credential** (new) | The consolidated UC credential record covering both Storage and Service purposes. Reached via `/api/2.1/unity-catalog/credentials`. | | **Storage Credential** (legacy) | The older Storage-only credential record. Reached via `/api/2.1/unity-catalog/storage-credentials`. Per in-tree TODO, being deprecated. | -| **Service Credential** | A `Credential` whose purpose is **SERVICE** — used by Databricks to access cloud APIs on behalf of the user (e.g., for foundation models, external functions). Note: there is no `purpose` field on the TS model — see H5. | +| **Service Credential** | A `Credential` whose purpose is **SERVICE** — used by Databricks to access cloud APIs on behalf of the user (e.g., for foundation models, external functions). | | **Purpose** | One of `SERVICE` / `STORAGE`. Distinguishes the two flavors of a `Credential`. Referenced in JSDoc but absent from the TS type. | | **Long-lived credential** | The customer-supplied cloud-provider auth material (IAM role, service principal, etc.) stored in the metastore. Six discriminated cases. | | **Temporary credential** | Short-lived tokens vended by Databricks for direct cloud access. Six discriminated cases. | @@ -368,7 +335,6 @@ Class re-exported with `export {Client}`; types and enums re-exported with |------|-------|-----------------|---------| | `src/v1/model.ts` | 2877 | 7 enums, 39 interfaces | yes | | `src/v1/client.ts` | 1031 | 1 class, 22 public methods (20 RPC + 2 async generators) | yes | -| `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | | `src/v1/index.ts` | 80 | 1 class re-export, 7 enum re-exports, 51 type re-exports | yes | Every type, field, enum value, and method enumerated above is accounted for. diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index ab291fe9..4b8f2575 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -3,20 +3,20 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 **Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. -**Total weird names flagged:** 19 (0 fixed, 19 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 10 (0 fixed, 10 still present after rescan on 2026-05-26 post regen #156) ## Summary | Severity | Count | | --- | --- | | High | 3 | -| Medium | 6 | -| Low | 7 | -| Observation | 3 | +| Medium | 3 | +| Low | 2 | +| Observation | 2 | ## High severity ### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #19). +- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #10). - **Category:** 3 (acronym casing — the audit prompt singles this out). - **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. - **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. @@ -47,85 +47,33 @@ - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 6. `executeCall` / `executeHttpCall` in `utils.ts:26,65` — naming pair -- **Why weird:** Two functions with nearly identical names handling different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at the call site. -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. -- **Rationale:** Names should differ in more than the `Http` infix. - -### 7. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Same word `Options` is reused for many unrelated concepts (`ClientOptions`, `CallOptions`, this one). The file also imports `Options` from `@databricks/sdk-core/api` (line 3) — three things named `Options` in the same file. -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` or `HttpCallParams` (it is not user-facing options; it is an internal arg bag). -- **Rationale:** Distinguish internal context bags from user-tunable option structs. - -### 8. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` +### 6. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` - **Why weird:** The `State` enum's first member `STATE_UNSPECIFIED` is a proto-architectural leak. Proto3 requires every enum to declare a zero-value sentinel (typically `FOO_UNSPECIFIED`); that requirement does not exist in TypeScript. Exposing it on the public TS surface forces every consumer to handle a member that semantically means "the server forgot to set this field" — a proto wire-format concern, not a domain concern. The screaming-snake-case casing (`STATE_UNSPECIFIED`) also leaks proto's enum-value convention into a TS type system that conventionally uses PascalCase for enum members (https://google.github.io/styleguide/tsguide.html#enums). - **Category:** Proto-architectural leak (enum sentinel + screaming-snake casing). - **Suggested name:** Drop the `STATE_UNSPECIFIED` member entirely; if a "not yet set" value is needed, use `undefined` (the field is already `State | undefined`). If kept, rename to PascalCase `Unspecified` and document that it is a wire-format sentinel. - **Rationale:** Optional TS fields express "unset" via `undefined`; a redundant enum sentinel doubles the representation of "no value" and forces consumers to write `state !== undefined && state !== State.STATE_UNSPECIFIED`. The all-caps casing further signals that the value is a proto artifact rather than a designed TS API member. -### 9. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` -- **Why weird:** `Segment` is a generic CS term. Comment explains it is the User-Agent identity segment; without the comment the constant name does not communicate that. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Minor; only one place in the file but flagged for SDK-wide consistency review. - ## Low severity -### 10. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +### 7. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` - **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. - **Category:** Observation / 9 (reversed — correctly singular). - **Suggested name:** No change. - **Rationale:** Note for consistency reviews. -### 11. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 8. `customLlmFieldMask` function name — `src/v1/model.ts:259` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). - **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. -### 12. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Function is exported but not used in this package (no caller in `client.ts`). Dead-looking surface area. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Either remove the export (if it is an unused generator default), or document why it ships per-package. -- **Rationale:** Not a name-quality issue per se, but flagged because each generated package will carry this and grep for unused exports across all packages will turn it up. - -### 13. `readAll` helper — `src/v1/utils.ts:40` -- **Why weird:** Function reads an entire response body stream into a buffer. Name is fine but generic; collides cognitively with `Array.prototype` or stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` / `readStreamToEnd`. -- **Rationale:** Internal helper, low cost. Skip if generated. - -### 14. `Call` import alias — `src/v1/client.ts:4` -- **Why weird:** `import type {Call}` — `Call` is a one-word generic noun. Used for the inner async function. Could be `RetryableCall`, `HttpCallback`, etc. Not local to this package (it is from `@databricks/sdk-core/api`), but worth flagging. -- **Category:** 1 (vague type name). -- **Suggested name:** Imported type; rename upstream if appropriate. -- **Rationale:** Generic noun in core API surface. - -### 15. `info` / `host` / `body` short locals — `src/v1/client.ts:58,73,74` -- **Why weird:** Three-letter local names. `info` for the client-info builder, `host` for the URL host, `body` for the request body. Conventional and short, but `info` is especially vague. -- **Category:** 1 (vague). -- **Suggested name:** Keep `host` and `body` (universal); rename `info` to `clientInfo`. -- **Rationale:** Localized; cosmetic. - -### 16. `resp` local variable in every method — `src/v1/client.ts:98,142,171,197` -- **Why weird:** `resp` is the response. Four methods declare `let resp: CustomLlm | undefined;` then assign in a closure and `throw` if undefined. The pattern is repetitive *and* uses the same short name. Consider extracting a helper that returns `T | never`. -- **Category:** 12 (duplicate pattern). -- **Suggested name:** Refactor away the pattern, not the name. -- **Rationale:** Refactor opportunity surfaced by naming-audit. - ## Observations -### 17. Action verbs in `Client` are consistent +### 9. Action verbs in `Client` are consistent The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. - **Category:** 17 (reversed — explicit *consistency* note). -### 18. No `list` operation -The package exposes singleton CRUD plus optimization start/cancel, but no `listCustomLlms`. Unusual for a Databricks resource SDK. Not a naming issue, but worth flagging because the typical resource SDK has `list` and users will look for it. -- **Category:** Observation. - -### 19. Mixed acronym casing in core types +### 10. Mixed acronym casing in core types The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `ApiError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `Api` (title), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. - **Category:** 3 (acronym casing). diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index f1974a89..305657c5 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -3,55 +3,43 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 24 +**Total weird names flagged:** 19 ## Summary | Severity | Count | | --- | --- | -| High | 7 | +| High | 5 | | Medium | 11 | -| Low | 4 | +| Low | 1 | | Observation | 2 | ## High severity -### 1. Package name `database` is generic — does not say Lakebase / OLTP / Postgres — `packages/database/` -- **Why weird:** `database` is the most generic possible word for a Databricks SDK package. The actual domain is "Lakebase" / Databricks-managed Postgres (every type either wraps a Postgres concept or is a UC mirror of one), but neither the package name, the README, nor any top-level JSDoc says "Lakebase" or "Postgres". A user scanning the workspace sees `database`, `postgres`, `sql`, `catalog` (Unity Catalog), `dbsql` etc. and cannot distinguish them. -- **Category:** 1 (vague/generic), 12 (duplicate concept: `database` vs `postgres` packages — see #2). -- **Suggested name:** `lakebase`, `lakebase-instances`, or `oltp` — whichever marketing name is canonical. At minimum, add a JSDoc on `index.ts` saying "Lakebase Postgres instance management". -- **Rationale:** Package names are the first-line filter a user uses; "database" tells them nothing. The sister package `postgres` is more specific despite sitting at a lower level. - -### 2. `database` and `postgres` packages overlap and confuse — `packages/database/` vs `packages/postgres/` -- **Why weird:** Two sibling packages model what is almost the same physical thing. `database` exposes `DatabaseInstance` / `SyncedDatabaseTable` / `DatabaseCatalog`; `postgres` exposes `ComputeInstance` / `SyncedTable` / `Catalog` / `Project` / `Branch` / `Endpoint`. Several types are textually duplicated (`DeltaTableSyncInfo`, `SyncedTablePosition`, `SyncedTablePipelineProgress`, `NewPipelineSpec`, `DatabaseCredential`, `GenerateDatabaseCredentialRequest`, `RequestedClaims`, `RequestedResource`, `ProvisioningInfo`, `ProvisioningPhase`, `SyncedTableState`). Multiple enums share names (`ProvisioningPhase`, `SyncedTableState`). -- **Category:** 12 (duplicate concept across packages), 6 (misleading: user cannot infer which package owns what). -- **Suggested name:** Either (a) merge into one `lakebase` package with versioning, (b) declare one package the public surface and mark the other internal, or (c) cross-reference each shared type and make the docstrings explicitly say "see postgres/v1 for the V2 API". -- **Rationale:** Comment at `client.ts:634-638` says "Lakebase V2 plans" — i.e. `database` is V1 and `postgres` is V2 OLTP. The naming does not reflect that lineage; users picking a dependency have no breadcrumb. - -### 3. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:373-375` +### 1. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:373-375` - **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:365-370) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; keep `createdb`/`createrole`/`bypassrls` on the wire (marshal/unmarshal handles the mapping). - **Rationale:** Every other field in the package is `camelCase`. Three boolean fields breaking the convention to honour Postgres SQL keywords is a leak. Postgres SDK at `postgres/v1/model.ts` solves this differently — worth aligning. -### 4. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:70` +### 2. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:70` - **Why weird:** Should be `SYNCED_TABLE_OFFLINE`. Spelled as `SYNCED_TABLED_OFFLINE` (`TABLED` past tense). - **Category:** 6 (misleading: typo). - **Suggested name:** Fix the wire-string to `SYNCED_TABLE_OFFLINE`. - **Rationale:** This is a protocol-level typo that the SDK is propagating. If fixed upstream this becomes a breaking change unless aliased — flag now. -### 5. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) +### 3. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) - **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+1 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. - **Category:** 7 (overly verbose), 12 (duplicate concept), 15 (generic prefix). - **Suggested name:** Hoist effective values onto a sub-struct or use a discriminated `{input, effective}` shape; or drop the `effective` fields and explain in docs that the same field is read-mostly on responses. - **Rationale:** This is a Lakebase API protocol pattern, not a naming bug per se, but the resulting TS surface is twice as wide as it needs to be. Worth pushing back upstream. -### 6. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:395` +### 4. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:395` - **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 447 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:471): "Name of the **cluster** to get". - **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). - **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. - **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. -### 7. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:924`, `index.ts:3` +### 5. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:924`, `index.ts:3` - **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. @@ -59,67 +47,67 @@ ## Medium severity -### 8. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` +### 6. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` - **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. - **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). - **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". - **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. -### 9. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` +### 7. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` - **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? - **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). - **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. - **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. -### 10. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` +### 8. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` - **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". - **Category:** 12 (duplicate concept), 1 (generic `Database`). - **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. - **Rationale:** Reader has to read both JSDocs to understand the partitioning. -### 11. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` +### 9. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` - **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`) split words at capital boundaries. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Trivia, but `time series` is two words in English. -### 12. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` +### 10. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 13. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` +### 11. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` - **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. - **Category:** 20 (type-suffix tautology in field names), 7 (verbose). - **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. - **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. -### 14. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` +### 12. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 15. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` +### 13. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 16. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` -- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #17 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. +### 14. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` +- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #15 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. - **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). - **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`; field `inlinePipeline` (paired with `existingPipelineId`). Drop the `New` adjective and the `Spec` suffix. - **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. -### 17. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` -- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #18); `DeltaTableSyncInfo` is a sync checkpoint (see #13); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #16). Each of the four would read more clearly with a domain-specific suffix. +### 15. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` +- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #16); `DeltaTableSyncInfo` is a sync checkpoint (see #11); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #14). Each of the four would read more clearly with a domain-specific suffix. - **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). -- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #16); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #13); `ProvisioningInfo` → drop (per #18). Goal: no two types in the package share a generic suffix. +- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #14); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #11); `ProvisioningInfo` → drop (per #16). Goal: no two types in the package share a generic suffix. - **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. -### 18. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` +### 16. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` - **Why weird:** Type declaration is literally `export interface ProvisioningInfo {}` with a comment "Copied over from managed-catalog/api/messages/common.proto to decouple SDK packages. xref go/unified-api-packages-dd". An empty interface — the type itself carries zero domain meaning. Only its nested `ProvisioningInfo_State` enum is used (referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`); the empty parent is a vestigial proto namespace. The exported type name and its nested enum bleed Managed Catalog internals into the Lakebase SDK. - **Category:** proto-architectural leak (proto message preserved as empty TS interface for namespacing), 6 (misleading — exists but has no fields), 12 (cross-package proto leak). - **Suggested name:** Drop the empty `ProvisioningInfo` interface; rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). The empty interface is a generator artefact that should not surface. @@ -127,37 +115,19 @@ ## Low severity -### 19. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` +### 17. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` - **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:181-184). - **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). - **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. - **Rationale:** Caller has to know the wire-encoding accident to decide which to set. -### 20. `DeleteDatabaseInstanceRoleRequest.allowMissing` doc — `src/v1/model.ts:422-423` -- **Why weird:** Doc says "This is the AIP standard name for the equivalent of Postgres' `IF EXISTS` option". Two abstractions documented in the comment; the field name reads neither. -- **Category:** 14 (Google-AIP naming convention leak). -- **Suggested name:** `ignoreIfMissing` (mild). The current name comes from `google.aip.dev/135`, which is fine to keep — but acknowledge the convention. -- **Rationale:** Internal-jargon leak; flag for awareness. - -### 21. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:78` -- **Why weird:** Same as abacpolicies finding #32. `Segment` is generic; comment makes the meaning clear but the name doesn't. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Cross-package consistency. - -### 22. `StillRunningError` private error class — `src/v1/client.ts:83` -- **Why weird:** Class extends `Error` and is used only as a sentinel for retry detection (`err instanceof StillRunningError`). The name suggests it represents an operation state, not an error. Sentinel-as-error is OK in Go (`errors.Is`) but in JS the convention is a state enum or a custom Result. -- **Category:** 14 (Go-style sentinel error), 6 (misleading — it's a control-flow signal, not an error). -- **Suggested name:** `PollAgainSignal` / `OperationStillRunning` (still a class, but reads as state). -- **Rationale:** Throwing for control flow is fine; the *name* shouldn't pretend it's a real error. - ## Observations -### 23. `findDatabaseInstanceByUid` is the only `findBy*` method +### 18. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 24. Action-verb conventions in `Client` are consistent +### 19. Action-verb conventions in `Client` are consistent `create*` / `delete*` / `get*` / `list*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. ## Domain glossary diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md index 791924be..7e69d891 100644 --- a/.agent/naming-audit/dataclassification.md +++ b/.agent/naming-audit/dataclassification.md @@ -3,15 +3,15 @@ **Path:** `packages/dataclassification/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 13 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | | High | 0 | -| Medium | 3 | -| Low | 6 | -| Observation | 4 | +| Medium | 1 | +| Low | 0 | +| Observation | 1 | ## High severity @@ -25,72 +25,16 @@ _None._ - **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. -### 2. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` -- **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. -- **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). -- **Suggested name:** `makeHttpRequest` or inline at the call sites (the function is 16 lines and used 4 times). -- **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just a shorthand. Using `make` or inlining would scan more clearly. - -### 3. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** The function is exported but unused in `client.ts` (this package has no list endpoint with query params). Dead-code-shaped helper sitting in shared scaffolding. -- **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). -- **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. -- **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. - ## Low severity -### 4. `PACKAGE_SEGMENT` — `src/v1/client.ts:33` -- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. -- **Category:** 1 (vague — `Segment` of what?). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. -- **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. - -### 5. `userAgent` field — `src/v1/client.ts:45` -- **Why weird:** `userAgent` is the canonical name for the header value, so this is fine. The field is `private readonly` — no problem with naming itself. -- **Category:** N/A (verification, no issue). -- **Suggested name:** unchanged. -- **Rationale:** Listed only to confirm canonical naming is preserved. - -### 6. `Call` type and `call` variable — `src/v1/client.ts:77-87, 101-110, 121-131, 157-173` -- **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). -- **Category:** 1 (vague), 12 (duplicate concept). -- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. -- **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. - -### 7. `req.parent ?? ''` / `req.name ?? ''` / `req.catalogConfig?.name ?? ''` URL composition — `src/v1/client.ts:74,100,119,148` -- **Why weird:** The client silently substitutes empty string for missing required path components, producing malformed URLs (e.g., `/api/data-classification/v1//config`). The naming is fine; the *handling* leaks via the optional types. Listed because `req.parent` and `req.name` are typed `string | undefined` while functionally required. -- **Category:** 6 (misleading — optional in type but required in practice). -- **Suggested name:** Make `parent` and `name` required (non-optional) on the request types. -- **Rationale:** This is a type-shape issue more than a naming one, but it surfaces because the field names promise less than the API requires. - -### 8. `respBody` vs `resp` variables — `src/v1/client.ts:81-86, 125-130, 167-172` -- **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: CatalogConfig`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. Abbreviating `response` to `resp` is fine but inconsistent with `req` (also abbreviated) which is also a parameter name. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). -- **Suggested name:** `rawBody` + `result` (or `parsedResponse`). -- **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. - -### 9. `httpReq` local variable — `src/v1/client.ts:80,104,124,160` -- **Why weird:** Inside a method that already has `req: CreateCatalogConfigRequest`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. -- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). -- **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. -- **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest` solves it. +_None._ ## Observations -### 10. Wire/TS divergence is heavy -The model file is 206 lines for ~5 user-facing types; >half is wire-conversion and field-mask scaffolding. Same pattern as other audited packages. Not a naming problem, but the audit consistently surfaces how much generator boilerplate dominates each package. - -### 11. Action-verb conventions in `Client` -The client uses `Create`/`Get`/`Update`/`Delete` consistently — no `Fetch`/`Retrieve`/`Read`. No `List` endpoint in this package (the entity is a singleton per catalog, by design). Verb consistency is good. (Listed per rule 17 to note the absence of inconsistency.) - -### 12. Acronym casing +### 2. Acronym casing The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. - **Category:** 3 (acronym casing). -### 13. `dataclassification` lowercase package name -The package directory is `dataclassification` (one word, no separator), but every type/field uses `DataClassification` or `data-classification`. The HTTP path uses kebab-case `/api/data-classification/v1/`. The directory name's collapsed spelling looks like an abbreviation but isn't — it's just unsegmented. Worth flagging for SDK-wide convention (compare: should be `data-classification` to match other multi-word packages, but npm package names allow hyphens only via scopes). -- **Category:** 3 (casing inconsistency: directory `dataclassification` vs. wire `data-classification` vs. types `DataClassification`). - ## Domain glossary - `uc` / Unity Catalog — implicit across all types (the configured resource is a UC catalog). - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 96e0c2c1..1e07d093 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -3,15 +3,15 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 **Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, and notification routing on failure. -**Total weird names flagged:** 25 +**Total weird names flagged:** 15 ## Summary | Severity | Count | | --- | --- | | High | 8 | | Medium | 4 | -| Low | 8 | -| Observation | 5 | +| Low | 1 | +| Observation | 2 | ## High severity @@ -91,49 +91,7 @@ ## Low severity -### 13. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Exported helper that is never called from `client.ts`. The package's two list endpoints handle pagination params (`pageToken`, `pageSize`) inline rather than via `flattenQueryParams`. Dead exported surface. -- **Category:** 6 (misleading — looks like it's used; isn't). -- **Suggested name:** N/A — should be unexported (or moved to a shared utils package — generator-wide concern). -- **Rationale:** Same as `dataclassification` finding #19. - -### 14. `executeCall` vs `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Layering not visible from names; identical to `dataclassification` finding #15. -- **Category:** 1, 12, 17. -- **Suggested name:** `runWithRetry` (outer) + `sendHttpRequest` (inner). -- **Rationale:** Layering should be readable from the names without opening the source. - -### 15. `buildHttpRequest` — `src/v1/utils.ts:96` -- **Why weird:** Same as `dataclassification` finding #16; "build" suggests builder pattern, the function spreads literals. -- **Category:** 1, 6. -- **Suggested name:** `makeHttpRequest`. -- **Rationale:** "Make" matches the simpler reality. - -### 16. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Identical to `dataclassification` finding #20; "readAll" does not say "drain a stream". -- **Category:** 1, 5. -- **Suggested name:** `drainStream`. -- **Rationale:** Self-describing name for stream draining. - -### 17. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Same as `dataclassification` finding #21; internal context bag called `Options`. -- **Category:** 1, 8. -- **Suggested name:** `HttpCallContext`. -- **Rationale:** Reserve `Options` for user-tunable knobs. - -### 18. `PACKAGE_SEGMENT` — `src/v1/client.ts:50` -- **Why weird:** Same as `dataclassification` finding #22; unspecific noun for a User-Agent identity object. -- **Category:** 1. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Add the missing domain word. - -### 19. `Call` type + `call` variable — `src/v1/client.ts:96, 135, 169, 207, 226, 261, 297, 331, 393, 453, 491` -- **Why weird:** Same as `dataclassification` finding #24; variable named `call` of type `Call` repeated 11 times across the client. -- **Category:** 1, 12. -- **Suggested name:** `request` (variable) — reserve `Call` for the type. -- **Rationale:** Type/variable collision is common in Go idioms; TS prefers distinct names. - -### 20. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +### 13. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` - **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. @@ -141,23 +99,13 @@ ## Observations -### 21. Heavy boilerplate dominates the file -`model.ts` is 1030 lines for ~16 user-facing types; ~520 lines (~50%) are `marshal*` / `unmarshal*` / `*FieldMaskSchema` scaffolding. Same shape as every audited package. - -### 22. Action verbs in `Client` +### 14. Action verbs in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) -### 23. Acronym casing +### 15. Acronym casing Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. - **Category:** 3 (acronym casing). -### 24. Tense / nominalisation drift in enum naming -`AnomalyDetection` (gerund), `DataProfiling` (gerund), `DataClassification` (noun) — at the package boundary the gerund/noun choice tracks the API team's preference. Within `dataquality` the choice is consistent (both gerunds), good. - -### 25. `dataquality` lowercase package name vs `data-quality` wire path vs `DataQuality` types -Same shape as the `dataclassification` casing observation (#32 in that package): directory is one collapsed word, types are PascalCase compounded, wire path is kebab. SDK-wide convention question, not local. -- **Category:** 3 (casing inconsistency). - ## Domain glossary - `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema or UC table). - `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask` and `FieldMask`). diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index 8b01e25e..edb7510e 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -3,14 +3,14 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 13 +**Total weird names flagged:** 9 ## Summary | Severity | Count | | --- | --- | | High | 3 | | Medium | 3 | -| Low | 5 | +| Low | 1 | | Observation | 2 | ## High severity @@ -25,7 +25,7 @@ - **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. - **Category:** 3 (acronym casing inconsistency). - **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** Within `client.ts` line 8 we import `CallOptions` and the file uses `URLSearchParams` (line 83) right beside `stableUrlId` (line 128), giving us `URLSearchParams` and `stableUrlId` on adjacent lines. The mixed casing is jarring. (Note: this is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. See observation #12 — same issue applies in `utils.ts` field `url` on `StableUrl`.) +- **Rationale:** The mixed casing is jarring against the surrounding Web platform conventions (e.g., `URLSearchParams`). This is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. ### 3. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` - **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: @@ -48,7 +48,7 @@ ### 5. `UcReplicationConfig` — `src/v1/model.ts:284` - **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). -- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #8). +- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #4). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. ### 6. `Client` class name — `src/v1/client.ts:52` @@ -65,41 +65,16 @@ - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. -### 8. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:47` -- **Why weird:** Generic CS-term constant; the comment (line 46) explains it as "Package identity segment for this client to be used in the User-Agent header." Without the comment the name doesn't communicate that it's a User-Agent payload. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. -- **Rationale:** Same as other packages in the audit. Flag once per package. - -### 9. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Exported helper but no caller in `client.ts` (the client builds URLSearchParams inline). Dead-looking surface area. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Either remove the export (generator default) or document why it ships per-package. -- **Rationale:** Carried by every generated package. Surfaces as `import { flattenQueryParams } from './utils'` no-op. - -### 10. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Generic name for "read a `ReadableStream` to a single Uint8Array". Could collide cognitively with `Array.prototype` ergonomics. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` / `readStreamToBuffer`. -- **Rationale:** Internal helper. Skip if generated identically across all packages. - -### 11. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions whose names differ only by `Http` infix but operate on very different layers (retry/rate-limit wrapper vs raw HTTP send + ApiError lift). -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `runCallWithOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). -- **Rationale:** At the call site (`client.ts:104,111`), the two are visually similar; the more descriptive name disambiguates. - ## Observations -### 12. Action-verb consistency on `Client` (mostly good) +### 8. Action-verb consistency on `Client` (mostly good) Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#7), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. -### 13. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` +### 9. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` Within this package: - `stableUrl`/`StableUrl` (PascalCase capital-then-lower). - `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). -- `URLSearchParams` (Web global, ALLCAPS in code, `client.ts:83`). -Three different casings for two acronyms (URL/URI). The Web platform uses `URL` (ALLCAPS) globally; the TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) +Two different casings for two related acronyms (URL/URI), and both differ from the Web platform's ALLCAPS `URL`/`URLSearchParams`. The TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) - **Category:** 3 (acronym casing). ## Domain glossary @@ -119,5 +94,4 @@ Three different casings for two acronyms (URL/URI). The Web platform uses `URL` ## File coverage - `src/v1/model.ts` (620 lines): read fully. - `src/v1/client.ts` (418 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. - `src/v1/index.ts` (30 lines): read fully. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index b6b56e24..23d31430 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -3,15 +3,15 @@ **Path:** `packages/entitytagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). -**Total weird names flagged:** 20 +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | | High | 5 | -| Medium | 9 | -| Low | 2 | -| Observation | 4 | +| Medium | 2 | +| Low | 0 | +| Observation | 3 | ## High severity @@ -53,91 +53,26 @@ - **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. - **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. -### 7. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions named "execute" — `executeCall` runs the retry/rate-limit shell, `executeHttpCall` does the actual HTTP send. They appear together in every client method: - ```ts - const call: Call = async (callSignal?: AbortSignal): Promise => { - ... - const respBody = await executeHttpCall({...}); - ... - }; - await executeCall(call, options); - ``` - Reading just the names, a developer cannot tell which wraps which. -- **Category:** 1 (vague), 12 (duplicate concept — both "execute"), 17 (inconsistent layering name). -- **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. -- **Rationale:** Names should reveal the layering, not require code-diving. Generator-wide concern. - -### 8. `Call` type and `call` variable — `src/v1/client.ts:86,119,139,178,242` and `src/v1/utils.ts:27` -- **Why weird:** Variable `call` of type `Call`, called inside `executeCall(call, options)`. The same word is the variable, the type, and the verb. Inside one method scope we have `req`, `call`, `httpReq` — three layered names where one of them collides with its type. -- **Category:** 1 (vague), 12 (duplicate concept). -- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. -- **Rationale:** Type-name collisions are tolerable but obscure prose-style code. - -### 9. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` +### 7. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. -### 10. `respBody` (raw bytes) vs. `resp` (parsed object) — `src/v1/client.ts:90-95, 143-148, 182-187, 252-257` -- **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: EntityTagAssignment`. The names differ only by `Body`. Both are short for "response". The reader has to track which is bytes, which is parsed. Compare `req` (parameter, request) — also abbreviated, but no `reqBody` sibling. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, `resp` drops the implied `Parsed`). -- **Suggested name:** `rawBody` + `result`, or `responseBytes` + `response`. -- **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. - -### 11. `httpReq` local variable — `src/v1/client.ts:89,122,142,181,245` -- **Why weird:** Inside a method that already has `req: CreateEntityTagAssignmentRequest`, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. -- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). -- **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. -- **Rationale:** Avoid forking the same identifier across two layers in one scope. - -### 12. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. -- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). -- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. -- **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. - -### 13. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` -- **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. -- **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern, is just an object literal). -- **Suggested name:** `makeHttpRequest` or inline at call sites. -- **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is just shorthand. - -### 14. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** The function is exported but unused in `client.ts` (this package's list endpoint uses individual `params.append(...)` calls instead). Dead-code-shaped helper in shared scaffolding. -- **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). -- **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. -- **Rationale:** Generator-wide concern: every package duplicates this helper. - ## Low severity -### 15. `readAll(body)` — `src/v1/utils.ts:40` -- **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". -- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). -- **Suggested name:** `drainStream` or `readStreamToUint8Array`. -- **Rationale:** A name like `readAll` reads as if it took a file path or array. - -### 16. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` -- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. Casing is appropriate for a module constant; the noun is weak. -- **Category:** 1 (vague — `Segment` of what?). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. -- **Rationale:** Single word "segment" gives no domain; the comment above it does the work the name should. +_None._ ## Observations -### 17. Action verb consistency +### 8. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 18. Acronym casing +### 9. Acronym casing The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 19. `entitytagassignments` lowercase package name -The package directory is `entitytagassignments` (single token, no separator), but every type uses `EntityTagAssignment` and the HTTP path uses `entity-tag-assignments`. Same problem as `dataclassification`. SDK-wide convention issue. -- **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). - -### 20. Domain leakage from sister packages +### 10. Domain leakage from sister packages Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index 3ee2878d..7228332d 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -5,27 +5,21 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 13 +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | -| High | 7 | +| High | 6 | | Medium | 3 | -| Low | 2 | -| Observation | 1 | +| Low | 1 | +| Observation | 0 | --- ## High severity -### 1. Package name `environments` is generic — does not say "base environment", "serverless", or "Python dependencies" — `packages/environments/` -- **Why weird:** The package name `environments` is the most generic word possible. The actual scope is narrow: workspace-level Python *base environments* (YAML dependency manifests) used by serverless notebooks and jobs. A reader scanning the workspace sees `environments` alongside `connections`, `catalogs`, `credentials` etc. and has no idea this is about Python dependency manifests, not deployment environments / staging / prod / runtime environments. -- **Category:** 1 (vague/generic). -- **Suggested name:** `workspacebaseenvironments`, `baseenvironments`, `serverlessenvironments`, or `pythondependencies`. At minimum, add a JSDoc on `index.ts` saying "Workspace base environment (Python dependency manifest) management for serverless compute". -- **Rationale:** "Environment" is overloaded across infrastructure (prod/staging/dev), runtime (Python/Node), workspace, deployment, and platform meanings. The package is the user's first filter and gives them zero signal. - -### 2. `Environment` concept fragmented across `environments` and `clusterlibraries` packages — `packages/environments/` vs `packages/clusterlibraries/` +### 1. `Environment` concept fragmented across `environments` and `clusterlibraries` packages — `packages/environments/` vs `packages/clusterlibraries/` - **Why weird:** Two sibling packages model overlapping pieces of the same domain: - `clusterlibraries/v2` exposes `DefaultBaseEnvironment`, `BaseEnvironmentType`, `DefaultBaseEnvironmentCache`, `DefaultBaseEnvironmentCache_Status`, `Environment`, `MaterializedEnvironment`, and full CRUD on `DefaultBaseEnvironment`s. - `environments/v1` exposes `WorkspaceBaseEnvironment`, the same `BaseEnvironmentType` enum (redefined, not imported), `WorkspaceBaseEnvironmentCache`, `WorkspaceBaseEnvironmentCache_Status` (same shape as `DefaultBaseEnvironmentCache_Status`), and `DefaultWorkspaceBaseEnvironment`. @@ -34,31 +28,31 @@ - **Suggested name:** Either (a) consolidate into a single `baseenvironments` package and have `clusterlibraries` import from it, (b) explicitly cross-reference each shared type in docstrings, or (c) version one of them (`clusterlibraries` `DefaultBaseEnvironment` is presumably v1, `environments` `WorkspaceBaseEnvironment` is v2 — say so). - **Rationale:** Same shape, redefined in two packages, with subtly different naming (`DefaultBaseEnvironment` vs `WorkspaceBaseEnvironment`). Consumers will hit type-incompatibility errors when passing a value from one package into the other. -### 3. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:718` +### 2. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:718` - **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. The 26 characters are baked into the *type prefix*, not the enum-member prefix; this is a TS-surface concern, not a proto-codegen concern. - **Category:** 7 (overly verbose type prefix), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). - **Suggested name:** Drop one of the adjectives in the *type* name. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. - **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. -### 4. `WorkspaceBaseEnvironment.status` field name and type's domain do not align — `model.ts:737` +### 3. `WorkspaceBaseEnvironment.status` field name and type's domain do not align — `model.ts:737` - **Why weird:** `WorkspaceBaseEnvironment.status` is typed `WorkspaceBaseEnvironmentCache_Status` — i.e. the *status of a Cache*. But the field documents itself as "The status of the materialized workspace base environment", not the status of a cache. The user reads `env.status` and the type's name implies a different concept (cache) than the doc and the data (materialization state of the environment). - **Category:** 16 (field type contradicts type domain), 6 (misleading). - **Suggested name:** Either (a) rename the enum to `MaterializationStatus` (the doc's own words) and drop the `Cache` qualifier, or (b) rename the field to `cacheStatus` to match the type. - **Rationale:** Field name and type name should describe the same thing. The mismatch is a tell that the enum was named for an internal proto nesting that the public API doesn't surface. -### 5. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:641, index.ts:26` +### 4. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:641, index.ts:26` - **Why weird:** The type name `Operation` is one of the most generic words in software (matches OS-level, math, audit-log, business, telemetry, async-task… meanings). It is exported alongside two related types (`GetOperationRequest`, `WorkspaceBaseEnvironmentOperationMetadata`) and three classes (`CreateWorkspaceBaseEnvironmentOperation`, etc.). It is also a `google.longrunning.Operation`-shaped envelope (the docstring at model.ts:638 even says so), but the name doesn't say that. - **Category:** 1 (vague/generic), 15 (generic type name losing meaning). - **Suggested name:** `LongRunningOperation`, `LROperation`, `AsyncOperation`, or namespace it under the package name (`EnvironmentOperation`). Whichever wins, the request type should match: `GetLongRunningOperationRequest` etc. - **Rationale:** A consumer importing `{Operation}` into a file that also has Slack `Operation`, audit `Operation`, or domain-specific `Operation` is in for a renaming party. The name signals nothing about being a polling envelope. -### 6. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:666-677` +### 5. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:666-677` - **Why weird:** The union's discriminator field is `$case` (the `$` prefix is a wire/codegen artifact, not idiomatic TS — see `clusterlibraries` and `database` audits where the same pattern surfaces). The `'response'` variant's payload field is also called `response`, so consumers write `op.result.response.response` is *not* the access path but `op.result.$case === 'response'` then `op.result.response` is. Conflating the discriminator literal `'response'` with a payload field also named `response` is confusing. Same for `'error'` / `error`. - **Category:** 6 (misleading — `$case`/`response`/`error` triple-overloading), 17 (inconsistency with idiomatic TS discriminated unions which use `kind` or `type`), 14 (Go/proto codegen artefact). - **Suggested name:** Use `kind` (or `type`) instead of `$case`, and use distinct names like `kind: 'error' | 'success'` with payload fields `error: DatabricksServiceException` / `value: Record<...>` (or similar). See database audit #14 for an analogous critique. - **Rationale:** `$` in identifiers in TS implies "internal/synthetic". This is a leak of the ts-proto codegen convention. Consumers writing `op.result?.$case` see synthetic noise. -### 7. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:552, index.ts:18` +### 6. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:552, index.ts:18` - **Why weird:** Three problems in one name: 1. **`Proto` suffix** on a TypeScript identifier — leaks the proto origin into the type name (`Proto` means nothing to a TS consumer). 2. **`Exception`** is Java/Python terminology; TS/JS uses `Error`. The type is a *data* representation of an error (it's a plain interface with `errorCode`/`message`/`stackTrace`), not an actual thrown exception class. Naming a data structure `Exception` suggests it can be thrown. @@ -71,48 +65,38 @@ ## Medium severity -### 8. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` +### 7. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` - **Why weird:** The `ErrorCode` enum has roughly 100 members. The doc comments mark a large fraction as deprecated ("kept to maintain backwards compatibility"). Many members are domain-specific (e.g. `IPYNB_FILE_IN_REPO`, `GIT_URL_NOT_ON_ALLOW_LIST`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `DAC_ALREADY_EXISTS`) and have nothing to do with environments. The enum is a kitchen-sink import of every Databricks-platform error code, exported from a *workspace-base-environment* package. - **Category:** 1 (overly broad — exposed in the wrong scope), 7 (overly verbose surface), 12 (duplicate concept — `ErrorCode` likely lives in many packages). - **Suggested name:** Move to a shared `@databricks/sdk-databricks/apierror` (where `apierr/codes/` already lives, per AGENTS.md) and import it. The environments package should export at most the subset of codes it actually returns. - **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `ApiError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. -### 9. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` +### 8. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` - **Why weird:** Enum values are SCREAMING_SNAKE wire strings (e.g. `MAX_CHILD_NODE_SIZE_EXCEEDED`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). 100+ values × ~30 chars each = a large surface that consumers must spell exactly. TS pattern is `PascalCase` enum members. - **Category:** 14 (Java/Go-style names), 18 (long enum values). - **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. - **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. -### 10. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` +### 9. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` - **Why weird:** The mid-position word `Service` in `DatabricksServiceExceptionWithDetailsProto` describes a server-side architectural layer ("a service threw this exception"), not anything about the data the type carries. The type is a plain error payload with `errorCode`/`message`/`stackTrace`/`details`; no field references a "service". `Service` here mirrors the Java `*ServiceException` superclass pattern and the proto message name `DatabricksServiceExceptionWithDetails` — both server-internal concepts that have no meaning for a TS SDK consumer. Combined with the trailing `Proto` (codegen origin) the name is a stack of three architectural tags: `Service` (layer) + `Exception` (Java throwable) + `Proto` (wire format). - **Category:** proto-architectural-leak (mid-position `Service` is not the domain), 14 (Java-style naming), 20 (`Proto` suffix tautology). - **Suggested name:** `DatabricksErrorDetails`, `ServiceErrorPayload` is still leaky; prefer `ApiErrorDetails` or `RpcErrorDetails` if the gRPC framing is part of the public contract, otherwise just `ErrorDetails`/`DatabricksError`. Drop `Service`, `Exception`, and `Proto` together. -- **Rationale:** The proto-architectural-leak audit treats mid-position `Service` as a server-implementation tell that leaks into TS surfaces. Even setting aside the existing `Proto`/`Exception` complaints (#7), the `Service` infix on a *data* type tells the consumer nothing useful and reinforces the impression that the SDK exposes server internals. The unmarshal schema (`model.ts:757`) propagates the same name; renaming the type renames its schema. +- **Rationale:** The proto-architectural-leak audit treats mid-position `Service` as a server-implementation tell that leaks into TS surfaces. Even setting aside the existing `Proto`/`Exception` complaints (#6), the `Service` infix on a *data* type tells the consumer nothing useful and reinforces the impression that the SDK exposes server internals. The unmarshal schema (`model.ts:757`) propagates the same name; renaming the type renames its schema. --- ## Low severity -### 11. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` +### 10. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` - **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:741). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:564) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. - **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). - **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. - **Rationale:** Two representations of "is this the default" invite drift. -### 12. `requestId` doc says "A random UUID is recommended" but field is `string`, not UUID — `model.ts:545` -- **Why weird:** Doc strongly suggests UUID, but the type is `string`. If UUID is required for idempotency to work, that's a constraint the type doesn't capture. -- **Category:** 19 (underspecified), 6 (slightly misleading). -- **Suggested name:** Keep `requestId: string` but document constraints, or use a branded type `RequestId = string & {__brand: 'RequestId'}`. -- **Rationale:** Doc-implied invariants that aren't in the type. - --- ## Observation -### 13. Package version is hard-coded `v1` while sibling `clusterlibraries` is `v2` for the same concept — `packages/environments/src/v1/`, `packages/clusterlibraries/src/v2/` -- **Why noteworthy:** The two packages model the same `BaseEnvironment` concept at different version numbers. `clusterlibraries/v2` has `DefaultBaseEnvironment`; `environments/v1` has `DefaultWorkspaceBaseEnvironment`. Likely `environments` is the newer, narrower carve-out (workspace-scoped), but the version numbers misleadingly suggest `clusterlibraries` is newer. -- **Category:** 12 (duplicate concept), 6 (misleading lineage signal). -- **Suggested action:** Document the relationship in `index.ts` of each package (e.g. "This supersedes / is superseded by / is independent of `clusterlibraries/v2`"). Or align versions. -- **Rationale:** Generator-level; not actionable in TS alone, but worth recording. +_None._ --- diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index 1b8b6886..79ebc771 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -3,85 +3,79 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 **Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 34 +**Total weird names flagged:** 25 ## Summary | Severity | Count | | --- | --- | -| High | 12 | -| Medium | 11 | -| Low | 8 | -| Observation | 3 | +| High | 11 | +| Medium | 10 | +| Low | 3 | +| Observation | 1 | ## High severity -### 1. Package name `experiments` is too generic — `packages/experiments/` -- **Why weird:** The package is the MLflow Experiment Tracking API surface, but the package name says only "experiments". Other Databricks SDK packages own equally fuzzy nouns (`apps`, `catalogs`, `database`, `cleanrooms`) — so a reader cannot tell from `@databricks/sdk-experiments` that this is MLflow. The folder contains MLflow `Run`, `Metric`, `Param`, `Tag`, `LoggedModel` — none of which a typical Databricks user thinks of as "experiments" first. Every URL the client builds is `/api/2.0/mlflow/…`. -- **Category:** 1 (generic), 6 (misleading: name does not say MLflow). -- **Suggested name:** `mlflow`, `mlflow-tracking`, or `mlflow-experiments`. At minimum, add a JSDoc on `index.ts` saying "MLflow tracking — experiments, runs, logged models". -- **Rationale:** Every other identifier inside the package treats MLflow as the controlling brand (`mlflowParam`, `mlflowMetric`, `mlflowRunTag` appear in docstrings). The package name buries that. - -### 2. `Run` — `src/v1/model.ts:701` +### 1. `Run` — `src/v1/model.ts:701` - **Why weird:** The central noun is named `Run`. `Run` is a reserved-feeling word in any JS context: `Promise.all().run()`, test framework "runs", workflow "runs". The user has zero context that this is an MLflow Run (a tracked execution of a training/eval script with metrics/params/artifacts). Compare with `jobs.Run` (already a different concept in this SDK) and `pipelines.Run`. - **Category:** 1 (vague/generic), 12 (duplicate concept across packages — `jobs.Run`, `pipelines.Run`), 15 (generic field/type name losing meaning). - **Suggested name:** `MlflowRun` or `ExperimentRun`. Re-export the alias and deprecate `Run`. - **Rationale:** When a consumer writes `import {Run} from '@databricks/sdk-experiments/v1'` they may already have `Run` in scope from `@databricks/sdk-jobs/v2`. The two have unrelated schemas. Disambiguating the type name removes a foot-gun. -### 3. `Experiment` — `src/v1/model.ts:219` -- **Why weird:** Same generic-noun problem as #2. `Experiment` is a generic English word; this is specifically an MLflow Experiment (named container of MLflow Runs with a UUID and a UC artifact-location). Multiple Databricks teams may legitimately have "experiment" types in the future (notebooks?, lakehouse-experiments?). +### 2. `Experiment` — `src/v1/model.ts:219` +- **Why weird:** Same generic-noun problem as #1. `Experiment` is a generic English word; this is specifically an MLflow Experiment (named container of MLflow Runs with a UUID and a UC artifact-location). Multiple Databricks teams may legitimately have "experiment" types in the future (notebooks?, lakehouse-experiments?). - **Category:** 1 (generic), 15 (generic name). - **Suggested name:** `MlflowExperiment`. -- **Rationale:** Same as #2 — disambiguating the package's central noun against future Databricks "experiments" features prevents conflicts. +- **Rationale:** Same as #1 — disambiguating the package's central noun against future Databricks "experiments" features prevents conflicts. -### 4. `Metric` / `Param` / `Run` / `Experiment` — all single-word top-level types — `src/v1/model.ts:219,612,656,701` +### 3. `Metric` / `Param` / `Run` / `Experiment` — all single-word top-level types — `src/v1/model.ts:219,612,656,701` - **Why weird:** Four central types are bare nouns (`Metric`, `Param`, `Run`, `Experiment`). All four will collide with names in scope at the user's call site. None says "MLflow". `Param` in particular collides with React Router `Params`, Express `Params`, Node `URLSearchParams`, etc. - **Category:** 1 (vague), 10 (reserved-word adjacent), 12 (duplicate concept against React/Node `Params`). - **Suggested name:** `MlflowMetric`, `MlflowParam`, `MlflowRun`, `MlflowExperiment` — or namespace under `Mlflow.{Metric, Param, Run, Experiment}`. - **Rationale:** Even MLflow's own protobuf calls these `mlflow.Run`, `mlflow.Experiment`, `mlflow.Metric` — they assume a namespace. Flattening them into TS without one loses that disambiguation. -### 5. `LoggedModel` — `src/v1/model.ts:549` +### 4. `LoggedModel` — `src/v1/model.ts:549` - **Why weird:** `LoggedModel` is a noun-phrase made of past-participle adjective + noun. The "logged" prefix is doing the disambiguation against `RegisteredModel`, `ServingModel`, `MlflowModel` etc. But (a) past-tense adjectives in type names read awkwardly (`LoggedModel`, `DeletedExperiment`, `FinishedRun` would all be similarly weird), and (b) `Logged` does not describe what the type *is* — it describes the verb history that produced it. - **Category:** 6 (misleading: "Logged" describes history, not identity), 13 (verb-tense in noun-phrase). - **Suggested name:** `MlflowModel`, `TrackedModel`, or `RunModel` (since every `LoggedModel` belongs to a Run via `sourceRunId`). -- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #6). +- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #5). -### 6. `LoggedModel` family — many separate types — `src/v1/model.ts:549, 557, 568, 596, 604` + request/response — `model.ts:72, 161, 169, 257, 303, 464, 803, 921` +### 5. `LoggedModel` family — many separate types — `src/v1/model.ts:549, 557, 568, 596, 604` + request/response — `model.ts:72, 161, 169, 257, 303, 464, 803, 921` - **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModelRequest`, `DeleteLoggedModelRequest`, `DeleteLoggedModelTagRequest`, `FinalizeLoggedModelRequest`, `GetLoggedModelRequest`, `LogLoggedModelParamsRequest`, `SearchLoggedModelsRequest`, `SetLoggedModelTagsRequest`. The `LoggedModel` prefix is repeated 13 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. - **Category:** 7 (overly verbose), 12 (duplicate concept against `Model*` family that may exist in `modelregistry` package). - **Suggested name:** Either drop the `Logged` and call the family `MlflowModel` / `MlflowModelData` / `MlflowModelInfo` / `MlflowModelParameter` / `MlflowModelTag` / `MlflowModelStatus`, or nest under a namespace. - **Rationale:** 13 occurrences of "LoggedModel" in identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. -### 7. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:596` vs `model.ts:656` +### 6. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:596` vs `model.ts:656` - **Why weird:** Two distinct types both model `{key: string, value: string}` parameter pairs: `LoggedModelParameter` (for a `LoggedModel`) and `Param` (for a `Run`). JSDoc at line 595 says "Parameter associated with a `LoggedModel`" and at 655 "Param associated with a run". Why one type is spelled out (`Parameter`) and the other abbreviated (`Param`) is unexplained. - **Category:** 12 (duplicate concept), 17 (inconsistent abbreviation: `Parameter` vs `Param`). - **Suggested name:** Align the abbreviation: either both `Parameter` or both `Param`. - **Rationale:** The difference between `Run.params: Param[]` and `LoggedModel.data.params: LoggedModelParameter[]` is cosmetic — the underlying shape is identical. -### 8. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 364, 604, 765` +### 7. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 364, 604, 765` - **Why weird:** Four `{key: string, value: string}` types, one per parent entity. All four have identical shapes. The only differentiator is the parent entity — but the type itself is indistinguishable. - **Category:** 12 (duplicate concept × 4). - **Suggested name:** Adopt a single parent prefix convention so `MlflowTag` (or `Mlflow.Tag`) carries the shared shape, with parent-specific variants only when fields actually diverge. - **Rationale:** An end-user picking the wrong tag type (`InputTag` vs `RunTag` etc.) will not get a compile error because they have the same shape. -### 9. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:701, 711, 721, 757` +### 8. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:701, 711, 721, 757` - **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:710-718`), `RunInfo` is "id, name, status, times, user" (`model.ts:720-754`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:756-762`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. - **Category:** 1 (vague: `Data`/`Info`/`Inputs`), 15 (generic field name). - **Suggested name:** Flatten into `Run` (one object). If they must stay split, name them by content: `RunMetadata` (instead of `RunInfo`), `RunMeasurements` (instead of `RunData`), `RunDatasetsAndModels` (instead of `RunInputs`). - **Rationale:** `RunInfo` vs `RunData` requires the reader to look up the schema to know which fields go where. Naming by content removes that lookup. -### 10. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:568, 557` -- **Why weird:** Same `Info`/`Data` split as `Run` (#9). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. +### 9. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:568, 557` +- **Why weird:** Same `Info`/`Data` split as `Run` (#8). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. -- **Rationale:** Same as #9. +- **Rationale:** Same as #8. -### 11. `KILLED` enum value — `src/v1/model.ts:36` +### 10. `KILLED` enum value — `src/v1/model.ts:36` - **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." - **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). - **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. - **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). -### 12. `ViewType` enum — generic name + inconsistent field names for the same enum — `src/v1/model.ts:40-47` +### 11. `ViewType` enum — generic name + inconsistent field names for the same enum — `src/v1/model.ts:40-47` - **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). The same enum is used as `viewType` on `ListExperimentsRequest` (model.ts:405), `runViewType` on `SearchRunsRequest` (model.ts:886), and `viewType` on `SearchExperimentsRequest` (model.ts:789) — two fields named `viewType` and one named `runViewType` for the same enum. - **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). - **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Field name: pick one (`viewType` everywhere, or rename uniformly). @@ -89,58 +83,54 @@ ## Medium severity -### 13. `getMetricHistory` / `GetMetricHistoryRequest` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:314, client.ts:594` +### 12. `getMetricHistory` / `GetMetricHistoryRequest` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:314, client.ts:594` - **Why weird:** Type name `GetMetricHistoryRequest` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRunRequest`, `DeleteExperimentRequest`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". - **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). - **Suggested name:** `GetMetricValuesRequest` / `getMetricValues`, or `ListMetricHistoryRequest` / `listMetricHistory` (since it paginates). - **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. -### 14. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` +### 13. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` - **Why weird:** Multiple types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. - **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). - **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. - **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. -### 15. `creatorId: number` (not string) — `src/v1/model.ts:584` +### 14. `creatorId: number` (not string) — `src/v1/model.ts:584` - **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." - **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). - **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. - **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). -### 16. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` +### 15. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` - **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. - **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). - **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). - **Rationale:** Heterogeneous string ID fields are debugging traps. -### 17. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` -- **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#10) buries the ID one level deep. +### 16. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` +- **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#9) buries the ID one level deep. - **Category:** 15 (generic field name losing meaning), 7 (verbose access). - **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). - **Rationale:** Awkward access pattern. -### 18. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` +### 17. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` - **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:916`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). -- **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #6 is applied: `LogMlflowModelParamsRequest`. +- **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #5 is applied: `LogMlflowModelParamsRequest`. - **Rationale:** The double-Log is jarring on read. -### 19. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` +### 18. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` - **Why weird:** `setExperimentTag(req: SetExperimentTagRequest)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTagsRequest)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 20. `setExperimentTag` URL has double "set-experiment-tag" — `src/v1/client.ts:1280` -- **Why weird:** URL is `/api/2.0/mlflow/experiments/set-experiment-tag`. The path already says `experiments/` so the segment `set-experiment-tag` repeats "experiment". Other methods use `experiments/set` / `experiments/create` style. Not a TS naming issue per se but caller-visible if someone logs the URL. -- **Category:** Observation (URL design upstream). - -### 21. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` +### 19. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 22. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 20. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -154,55 +144,27 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 23. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` +### 21. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` - **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. - **Category:** 15 (generic field name losing structure). ## Low severity -### 24. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` -- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #8. The field is consistently `tags`, but the element type is not unifiable in TS without changes. +### 22. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` +- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #7. The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 25. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 23. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 26. `FileInfo` itself is a generic name — `src/v1/model.ts:248` +### 24. `FileInfo` itself is a generic name — `src/v1/model.ts:248` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. -### 27. `executeCall` / `executeHttpCall` — two execute verbs in `utils.ts` — `src/v1/utils.ts:26, 65` -- **Why weird:** `executeCall` is the public retrier+rate-limit wrapper; `executeHttpCall` is the inner HTTP send. The names differ by one word and roles are not obvious from the name. -- **Category:** 17 (inconsistency), 6 (misleading: both look like the entry point). -- **Suggested name:** `executeWithRetry` and `sendHttpRequest` (or `dispatch`). - -### 28. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** `HttpCallOptions` is the parameter bag for `executeHttpCall`; it carries a `request`, `httpClient`, `logger`. Name is fine but `Options` is a common suffix that may collide with `CallOptions` from `@databricks/sdk-options/call` imported on the same file (line 12). -- **Category:** 17 (collision risk with `CallOptions`). - -### 29. `flattenQueryParams` — only used internally — `src/v1/utils.ts:123` -- **Why weird:** Exported `flattenQueryParams` is dead code in `experiments` — no method in `client.ts` calls it. (Searched the file; query string assembly is done inline in `getMetricHistory`, `listArtifacts`, etc.) -- **Category:** Observation (dead export). - -### 30. `PACKAGE_SEGMENT` constant in `client.ts:161` — `src/v1/client.ts:161` -- **Why weird:** Top-level constant `PACKAGE_SEGMENT` is SCREAMING_SNAKE_CASE — the only TS identifier in `client.ts` using that style. Comment on the line says it's used for the User-Agent header. -- **Category:** 17 (inconsistency in identifier case across the file). -- **Suggested name:** `packageSegment` per TS conventions. - -### 31. `PACKAGE_SEGMENT.key` derived by regex from `pkgJson.name` — `src/v1/client.ts:162` -- **Why weird:** The expression `pkgJson.name.replace(/^@[^/]+\//, '')` extracts `sdk-experiments` from `@databricks/sdk-experiments`. The resulting User-Agent segment is `sdk-experiments/0.0.0`. The literal `sdk-experiments` is then user-visible in HTTP traces. The same generic-name problem as #1. -- **Category:** 1 (generic name leaking into observability). - ## Observations (non-actionable but noted) -### 32. `Dataset.source` doc — "Note that the source may not exactly reproduce..." — `src/v1/model.ts:127-130` -- **Note:** The field name `source` is generic; JSDoc says it may not actually be reproducible. The name does not warn the user that the field is best-effort. - -### 33. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` +### 25. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` - **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. - -### 34. `RUNNING` / `SCHEDULED` / `FINISHED` / `FAILED` / `KILLED` — wire-stable enum values — `src/v1/model.ts:28-36` -- **Note:** Wire values match the server's MLflow contract — they cannot be renamed without a wire-protocol break. Any rename would need to be TS-side only (with a marshaller mapping). diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index b1ef5abc..db01b5e2 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -3,14 +3,14 @@ **Path:** `packages/externallineage/src/v1/` **Versions audited:** v1 **Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 17 +**Total weird names flagged:** 9 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 5 | -| Low | 7 | +| Medium | 1 | +| Low | 3 | | Observation | 1 | ## High severity @@ -47,77 +47,29 @@ - **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). - **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. -### 6. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26, 65` -- **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. Inside each client method, `executeHttpCall` is wrapped in `call`, then `executeCall(call, options)` runs it. The reader has to read the bodies to figure out who calls whom. -- **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). -- **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. -- **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. - -### 7. `buildHttpRequest` returns `HttpRequest` — `src/v1/utils.ts:96` -- **Why weird:** A pure object-literal-with-optional-fields helper named "build" suggests something more elaborate (e.g., builder pattern). The function just spreads optional fields into a struct. -- **Category:** 1 (vague), 6 (misleading — implies builder pattern, is just an object literal). -- **Suggested name:** `makeHttpRequest` or inline at the call sites. -- **Rationale:** "Build" carries connotations from Java/JS Builder patterns; this is a one-liner. - -### 8. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. -- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). -- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. -- **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. - -### 9. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Function recurses into objects and arrays to flatten them into URL-search-parameter dot-notation form. The "arrays of objects are not yet supported" comment shows the implementation is partial. The name says "flatten" but the function in fact *recurses* and *appends* to a `URLSearchParams` instance — it does not return a flat structure. -- **Category:** 1 (vague — "flatten" doesn't say "append to URLSearchParams"), 6 (misleading — looks pure, mutates a parameter), 17 (verb inconsistency — name says "flatten" but action is "append"). -- **Suggested name:** `appendDotPathParams` or `serializeQueryDotPath`. -- **Rationale:** A function that mutates its third argument should not be named after the value it returns (`flatten` reads as a pure transform). Generator-wide concern (every package duplicates this helper). - ## Low severity -### 10. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` +### 6. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` - **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. - **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). - **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) - **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. -### 11. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 7. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). - **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. - **Rationale:** Type name should reflect the dominant content; current name is misleading. -### 12. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` +### 8. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` - **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. - **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). - **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. - **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. -### 13. `req` parameter and `respBody` / `resp` locals — `src/v1/client.ts:72, 80-92, 104, 134-178, 202-235` -- **Why weird:** Two stages produce `respBody: Uint8Array` then `resp: ExternalLineageRelationship`. The names differ only by `Body`; the reader has to track that one is bytes, one is parsed. -- **Category:** 5 (cryptic abbreviation), 17 (`respBody` keeps `Body`, `resp` drops the implied `Parsed`). -- **Suggested name:** `rawBody` + `result` (or `parsedResponse`). -- **Rationale:** Distinguish stages by meaningful nouns, not by suffix differences on the same root. - -### 14. `httpReq` local variable — `src/v1/client.ts:84, 123, 162, 220` -- **Why weird:** Inside a method that already has `req: …Request`, a second variable `httpReq: HttpRequest` shares the same `req` root with a different prefix. Easy to grab the wrong one. -- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s in the same scope). -- **Suggested name:** `httpRequest` (no abbreviation) or `wireRequest`. -- **Rationale:** Avoid forking the same identifier across two layers in the same scope. - -### 15. `Call` type and `call` variable — `src/v1/client.ts:81, 120, 159, 217` -- **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring. -- **Category:** 1 (vague), 12 (duplicate concept). -- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. -- **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. - -### 16. `PACKAGE_SEGMENT` — `src/v1/client.ts:40` -- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The comment above does the documentation work the name should. -- **Category:** 1 (vague — `Segment` of what?). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. -- **Rationale:** Single word "segment" gives no domain. Pair with the comment. - ## Observations -### 17. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name +### 9. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #3. - **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). @@ -125,7 +77,7 @@ The response wraps an array under the field `externalLineageRelationships` (35 c - `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. - `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). - `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #10. +- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #6. - `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). - `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). - `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index ec67f0f6..cb50fe1c 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -11,7 +11,7 @@ update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting sub-structure is `FileEventQueue` — an oneof-of-oneofs across three cloud providers (Azure AQS, AWS SQS, GCP Pub/Sub) with a parallel "provided" vs "managed" axis (6 cases total). -**Total weird names flagged:** 12 +**Total weird names flagged:** 9 --- @@ -19,18 +19,15 @@ providers (Azure AQS, AWS SQS, GCP Pub/Sub) with a parallel "provided" vs | # | Name | File | Kind | Severity | Category | Issue (one-liner) | | --- | ----------------------------------------------------------------------------- | ----------------- | ------------------ | -------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | package folder `externallocations` | (package) | package | Low | 7 Overly verbose | Compound noun jammed together with no separator. Sibling packages with the same pattern: `accountaccesscontrol`, `cleanroomtaskruns`. The `npm` package is `@databricks/sdk-externallocations`. `external-locations` would be more readable but the rest of the SDK uses the same one-word convention. | -| 2 | `Client` | client.ts:44 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client`. Every package in the SDK exports a class literally named `Client`; importers must alias on collision. `ExternalLocationsClient` would self-identify. | -| 3 | `SseEncryptionAlgorithm.AWS_SSE_S3` / `AWS_SSE_KMS` | model.ts:13-14 | enum values | Medium | 3 Acronym casing | The two non-sentinel members redundantly carry an `AWS_` prefix (the enclosing type name already says SSE which is AWS terminology). The wrapping `Sse*` already implies S3-server-side, so the leading `AWS_` is duplicative. | -| 4 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type | model.ts:17, 27, 183 | type set | Medium | (none individually, taken as set: inconsistent) | The three queue-config types use three different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`. | -| 5 | `GcpPubsub` (lowercase "ubsub") | model.ts:183 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | -| 6 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | -| 7 | `nameArg` field | model.ts:102, 195, 244 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocationRequest`, `GetExternalLocationRequest`, `UpdateExternalLocationRequest`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | -| 8 | `DeleteExternalLocationRequest_Response` | model.ts:108 | type | High | 16 Proto-architectural-leak names | Underscore-delimited proto-nested message name leaked through to the TS public surface. The `_Response` suffix is a Go/Protobuf RPC convention; idiomatic TS would name this `DeleteExternalLocationResponse` (or omit it entirely when the body is empty). | -| 9 | `ListExternalLocationsRequest_Response` | model.ts:221 | type | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern. Should be `ListExternalLocationsResponse`. The leading `Request_` infix is meaningless to a TS caller — the response is not "the response of a request type", it is the list response. | -| 10 | `unmarshalDeleteExternalLocationRequest_ResponseSchema` | model.ts:324 | const | High | 16 Proto-architectural-leak names | Schema constant inherits the proto-nested `Request_Response` identifier. Should track whatever the renamed type becomes (e.g., `unmarshalDeleteExternalLocationResponseSchema`). | -| 11 | `unmarshalListExternalLocationsRequest_ResponseSchema` | model.ts:436 | const | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern carried into schema constant naming. | -| 12 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | +| 1 | `Client` | client.ts:44 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client`. Every package in the SDK exports a class literally named `Client`; importers must alias on collision. `ExternalLocationsClient` would self-identify. | +| 2 | `SseEncryptionAlgorithm.AWS_SSE_S3` / `AWS_SSE_KMS` | model.ts:13-14 | enum values | Medium | 3 Acronym casing | The two non-sentinel members redundantly carry an `AWS_` prefix (the enclosing type name already says SSE which is AWS terminology). The wrapping `Sse*` already implies S3-server-side, so the leading `AWS_` is duplicative. | +| 3 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type | model.ts:17, 27, 183 | type set | Medium | (none individually, taken as set: inconsistent) | The three queue-config types use three different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`. | +| 4 | `GcpPubsub` (lowercase "ubsub") | model.ts:183 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | +| 5 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | +| 6 | `nameArg` field | model.ts:102, 195, 244 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocationRequest`, `GetExternalLocationRequest`, `UpdateExternalLocationRequest`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | +| 7 | `DeleteExternalLocationRequest_Response` | model.ts:108 | type | High | 16 Proto-architectural-leak names | Underscore-delimited proto-nested message name leaked through to the TS public surface. The `_Response` suffix is a Go/Protobuf RPC convention; idiomatic TS would name this `DeleteExternalLocationResponse` (or omit it entirely when the body is empty). | +| 8 | `ListExternalLocationsRequest_Response` | model.ts:221 | type | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern. Should be `ListExternalLocationsResponse`. The leading `Request_` infix is meaningless to a TS caller — the response is not "the response of a request type", it is the list response. | +| 9 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | --- @@ -75,9 +72,8 @@ disable comment is itself a tell. Idiomatic TS would either: - collapse the empty-body response into `Promise` since the wire envelope carries no fields. -The schema constant `unmarshalDeleteExternalLocationRequest_ResponseSchema` -(model.ts:324) and the client return type at client.ts:105 inherit the same -name and need to move together. +The client return type at client.ts:105 inherits the same name and needs +to move together. ### H3. `ListExternalLocationsRequest_Response` — same proto-nested pattern @@ -91,9 +87,8 @@ export interface ListExternalLocationsRequest_Response { ``` Same shape as H2: an underscore-delimited proto-nested identifier in the -public surface. Should be `ListExternalLocationsResponse`. The schema constant -`unmarshalListExternalLocationsRequest_ResponseSchema` (model.ts:436) and the -client return type at client.ts:182 share the rename. +public surface. Should be `ListExternalLocationsResponse`. The client return +type at client.ts:182 shares the rename. This is the only paginated response shape in the package, so the type is materially load-bearing — callers iterating manually have to read @@ -164,7 +159,6 @@ The suffix shows up in every signature touching the resource: - `Promise` (4 client method return types). - `ExternalLocationInfo[]` in `ListExternalLocationsRequest_Response`. - `AsyncGenerator` in the iter method. -- The schema constant `unmarshalExternalLocationInfoSchema`. Renaming to `ExternalLocation` removes ~6 occurrences of dead-weight suffix across the public surface. @@ -214,15 +208,14 @@ The following acronyms appear: ## Summary -12 findings: +9 findings: -- **5 High severity** — `nameArg` artifact, two `Request_Response` - proto-nested type names, two matching schema-constant names. +- **3 High severity** — `nameArg` artifact, two `Request_Response` + proto-nested type names. - **6 Medium severity** — `Client` collision, redundant `AWS_` prefix on `SseEncryptionAlgorithm` members, queue-type naming-pattern inconsistency, `AzureQueueStorage`/`Aqs` long-vs-short inconsistency, `Pubsub` casing, `ExternalLocationInfo` redundant `Info` suffix. -- **1 Low severity** — `externallocations` package folder verbosity. Primary themes: @@ -230,7 +223,7 @@ Primary themes: identifiers, the `Info` suffix on the resource type, and the `nameArg` path-vs-body disambiguation are all Go-/Protobuf-shaped idioms that idiomatic TS would express differently. The ESLint disable comments on - model.ts:107 / 220 / 323 / 435 are themselves the giveaway. + model.ts:107 / 220 are themselves the giveaway. 2. **Cloud-provider naming is internally inconsistent**: three queue-config types with three different naming conventions, AQS abbreviation that isn't Microsoft canonical. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index 2c949c45..a88c7532 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -3,15 +3,15 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 25 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 8 | -| Medium | 4 | -| Low | 9 | -| Observation | 4 | +| Medium | 3 | +| Low | 0 | +| Observation | 2 | ## High severity @@ -83,84 +83,18 @@ - **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. - **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. -### 12. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions named "execute" — one runs the retry/rate-limit shell, the other does the actual HTTP request. The names do not communicate the layering. A reader sees both `executeCall` and `executeHttpCall` called inside the same client method (the inner `call` wraps `executeHttpCall`, then `executeCall(call, options)` runs it) and must read the bodies to figure out who calls whom. -- **Category:** 1 (vague), 12 (duplicate concept — both are "execute"), 17 (inconsistent layering name). -- **Suggested name:** `runWithRetry(call, options)` (outer) and `sendHttpRequest(opts)` (inner). Or `executeWithPolicies` + `executeHttpRequest`. -- **Rationale:** The current names hide the fact that one wraps the other. Layer names should make the call graph obvious. Same pattern across sister packages — generator-wide concern. - ## Low severity -### 13. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` -- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. Constant is `UPPER_SNAKE_CASE` in a TS file otherwise dominated by camelCase. The casing is appropriate for a top-level constant, but the noun is weak. -- **Category:** 1 (vague — `Segment` of what?). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. -- **Rationale:** Single word "segment" gives no domain. The comment above does the work the name should. - -### 14. `Call` type and `call` variable — `src/v1/client.ts:85,115,141,183,245` -- **Why weird:** Variable named `call` of type `Call` — same word for the variable, type, and the API method semantics. Inside `executeCall(call, options)` the verb-noun collision is jarring (`execute the call`). -- **Category:** 1 (vague), 12 (duplicate concept). -- **Suggested name:** `runRequest` / `sendRequest` for the variable; reserve `Call` for the type. -- **Rationale:** Type-name collisions read fine in IDE but obscure prose-style reads. - -### 15. `req` / `resp` / `respBody` / `httpReq` variables — `src/v1/client.ts:75-104, 110-129, etc.` -- **Why weird:** Three abbreviations of `request`/`response` in the same scope. `req: CreateExternalMetadataRequest` is the user input; `httpReq: HttpRequest` is the wire object; `resp: ExternalMetadata` is the parsed result; `respBody: Uint8Array` is the wire body. Easy to grab the wrong one. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `respBody` keeps `Body`, but `resp` drops the implied `Parsed`). -- **Suggested name:** `request`, `response`, `rawBody`, `httpRequest` (no abbreviations) or distinguish stages by meaningful nouns (e.g., `input`, `result`). -- **Rationale:** Avoid forking the same identifier across two layers in the same scope. Spelling out `httpRequest`/`response` solves it. - -### 16. `pageReq` — `src/v1/client.ts:211` -- **Why weird:** Yet another `req` abbreviation (`pageReq: ListExternalMetadataRequest`). Inside `listExternalMetadataV2Iter`, the loop variable `pageReq` shares the `req` root with the outer parameter `req`. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency with `req`). -- **Suggested name:** `nextPageRequest` or unwrap the variable entirely (just mutate `req.pageToken`). -- **Rationale:** Sibling-scope variables with shared roots are easy to mis-grab. Spell out one or the other. - -### 17. `body` parameter on `buildHttpRequest` — `src/v1/utils.ts:101` -- **Why weird:** Parameter `body?: string | ReadableStream` is bare-typed `string | ReadableStream` — no hint that this is JSON-string-or-streamed-bytes. Compare: callers pass the result of `marshalRequest` (always JSON string), so the stream variant is theoretical. -- **Category:** 1 (vague — `body` is the most generic field name), 15 (generic field name losing meaning). -- **Suggested name:** `requestBody: string | ReadableStream`. -- **Rationale:** Inside a function building HTTP requests, `body` is fine because the type is `HttpRequest['body']`. Listed for completeness; not actionable on its own. - -### 18. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Function is exported but unused in `client.ts` — `listExternalMetadataV2` uses ad-hoc `params.append(...)` calls inline (`page_size`, `page_token`) rather than the flatten helper. Dead-code-shaped helper sitting in shared scaffolding. -- **Category:** 6 (misleading — implies the package uses it), 18 (carry-over from a different template). -- **Suggested name:** N/A — the function should not live in this package at all. Belongs in a shared utils package. -- **Rationale:** Generator-wide concern: every package duplicates this helper. The naming is fine but the location is not. - -### 19. `readAll(body)` — `src/v1/utils.ts:40` -- **Why weird:** `readAll` is generic enough to read anything; here it specifically drains a `ReadableStream`. The name does not say "drain a stream into a single buffer". -- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). -- **Suggested name:** `drainStream` or `readStreamToUint8Array`. -- **Rationale:** A name like `readAll` reads as if it took a file path. The function signature does the documentation work; the name does not. - -### 20. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not user-tunable options. The user-facing options type is `CallOptions` (different file). Mixing "options" for two different concepts is confusing. -- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal context bags should not be called `Options`). -- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. -- **Rationale:** Reserve `Options` for things callers tune; use `Context`/`Args` for the internal bag. - -### 21. `unmarshalListExternalMetadataResponseV2Schema` — `src/v1/model.ts:144` -- **Why weird:** The Zod schema constant carries the `V2` mid-position infix just like the type it parses (#6) and the client methods (#7). The directory is `v1/`, so `V2` here is wire-RPC-name leakage embedded inside a TS identifier that has no business advertising the upstream RPC version. Architectural leak — the generator copied the proto `ResponseV2` name straight through into the parser symbol. -- **Category:** 14 (Go/proto-style name leak — wire `V2` infix on a TS identifier), 8 (redundant suffix — version is in the path), 20 (type-version suffix tautology between version-in-path and version-in-name). -- **Suggested name:** `unmarshalListExternalMetadataResponseSchema` (drop `V2`). -- **Rationale:** The schema is local to `v1/model.ts`; nothing in this file disambiguates a `V2` schema from a `V1` schema because no `V1` schema exists. Same generator-wide concern as #6 and #7 — propagating the wire RPC version into TS identifiers leaks an architectural detail of the upstream service. +_None._ ## Observations -### 22. Identifier doubling for path + UUID +### 12. Identifier doubling for path + UUID The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5. -### 23. Action-verb conventions in `Client` +### 13. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. -### 24. Acronym casing -The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `url` lowercase. No `Id`/`URL`/`UC` clashes encountered in the user-facing types of this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. -- **Category:** 3 (acronym casing). - -### 25. `externalmetadata` lowercase package name -The package directory is `externalmetadata` (one word, no separator), but every type/field uses `ExternalMetadata` (two words) and the HTTP path uses kebab-case `/api/2.0/lineage-tracking/external-metadata` (note the *outer* `lineage-tracking` — not `external-metadata`-rooted). The directory name's collapsed spelling is unsegmented across word boundaries. Worth flagging for SDK-wide convention (compare: should be `external-metadata` to match other multi-word packages, but npm package names allow hyphens only via scopes). -- **Category:** 3 (casing inconsistency: directory `externalmetadata` vs. wire `external-metadata` vs. types `ExternalMetadata`). - ## Domain glossary - `uc` / Unity Catalog — implicit across all types (the registered entities live in a UC metastore). - `metastore` / `metastoreId` — UC metastore (the top-level UC namespace); the `metastoreId` is a UUID. diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index ab78a16a..194ddb2a 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -15,7 +15,7 @@ computes a feature on a schedule and writes results to an offline or online store). Feature transformations are a discriminated union over 13 aggregation functions and 3 data sources (Delta, Kafka, request-time), composed under three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 38 (0 fixed, 38 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 36 (0 fixed, 36 still present after rescan on 2026-05-26 post regen #156) --- @@ -50,17 +50,15 @@ three flavors of time window (continuous, tumbling, sliding). | 25 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | | 26 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | | 27 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | -| 28 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs | Two `execute*` functions with overlapping vocabulary. One translates options + dispatches retries, the other does one HTTP roundtrip. Same pattern as sibling-package audits. | -| 29 | `PACKAGE_SEGMENT` | client.ts:60 | const | Low | 1 Vague/generic | Could be `USER_AGENT_PACKAGE_SEGMENT`. Sibling-package pattern. | -| 30 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 31 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | -| 32 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | -| 33 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | -| 34 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #33. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | -| 35 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | -| 36 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | -| 37 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #35. | -| 38 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#33-37) clears this automatically. | +| 28 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | +| 29 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 30 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 31 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | +| 32 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #31. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | +| 33 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | +| 34 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | +| 35 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #33. | +| 36 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#31-35) clears this automatically. | --- @@ -195,7 +193,7 @@ via `globalThis.Function`. Most ESLint configs (including this repo's, see Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. -### H10. Proto-architectural leak: `Outer_Inner` nested names +### H10. Proto-architectural leak: `Outer_Inner` nested names (#31-36) Four public identifiers carry the proto-nested `_` underscore convention straight from the `.proto` IDL into the TS public API: @@ -304,63 +302,51 @@ entity over a lifetime ContinuousWindow". The name gives no domain hint. `LatestColumnValue` would name the behavior. (Same critique as `Credential` in the credentials audit.) -### M6. `executeCall` vs `executeHttpCall` - -Same as sibling packages. Two `execute*` verbs. - --- ## Low severity (nits) -### L1. `PACKAGE_SEGMENT` undescriptive - -Sibling-package pattern. - -### L2. `MtlsConfig.disableHostnameVerification` reasonable +### L1. `MtlsConfig.disableHostnameVerification` reasonable Boolean named in negative ("disable") to match the underlying Kafka option (`kafka.ssl.endpoint.identification.algorithm`). JSDoc warns about security implications. Fine. -### L3. `bootstrapServers` is conventional Kafka +### L2. `bootstrapServers` is conventional Kafka Fine. -### L4. `cronSchedule` field on `MaterializedFeature` +### L3. `cronSchedule` field on `MaterializedFeature` `MaterializedFeature.cronSchedule: string` is a Quartz cron expression. The field name is fine; the type could be a branded `CronExpression` for stronger typing, but flagging only for completeness. -### L5. `req` parameter naming in client methods - -Standard SDK-wide convention. Fine. - -### L6. `ContinuousWindow.offset` allows non-positive +### L4. `ContinuousWindow.offset` allows non-positive Note in JSDoc: "must be non-positive" — i.e., 0 or negative duration. The type is `Temporal.Duration` which doesn't constrain sign. Documentation-only constraint; not enforced. Same critique as `SlidingWindow.slideDuration` ("must be positive and less than duration"). -### L7. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text +### L5. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text A `string` containing potentially many KB of source text. Naming is fine; the data shape is the design choice. Listing for completeness. -### L8. `SecretScopeReference { scope, key }` +### L6. `SecretScopeReference { scope, key }` Two-field reference to a Databricks secret. Standard. Fine. -### L9. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` +### L7. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` Four Spark Structured Streaming idioms. Standard. Fine. -### L10. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` +### L8. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` Three field-mask builders. Standard generator pattern. Fine. -### L11. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` +### L9. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` The list endpoint filters by feature name (full UC name). Field is `featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index 2e73e727..1d0e232c 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -1,8 +1,7 @@ # Naming Audit: `featurestore` (v1) **Path:** `/home/parth.bansal/sdk-js/packages/featurestore/` -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, -`src/v1/index.ts` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/index.ts` **Cross-package references:** `features/v1` (`OnlineStoreConfig`, `onlineStoreName`), `materializedfeatures/v1`, `onlinetables/v1` (`DeleteOnlineTableRequest`, `OnlineTable`, `OnlineTableState`, @@ -61,14 +60,6 @@ - Methods: `createOnlineStore`, `deleteOnlineStore`, `deleteOnlineTable`, `getOnlineStore`, `listOnlineStores`, `listOnlineStoresIter`, `publishTable`, `updateOnlineStore`. - - Private fields: `host`, `httpClient`, `logger`, `userAgent`. - - Module constant: `PACKAGE_SEGMENT`. - -### Utils (`src/v1/utils.ts`) - -- Type: `HttpCallOptions`. -- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`. --- @@ -272,47 +263,7 @@ to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** --- -### 11. `PACKAGE_SEGMENT` constant — category 4 (Underscores in TS identifiers) — *Still* - -**Symbol:** `PACKAGE_SEGMENT` (client.ts:41). - -**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true -constants (primitive literal values like `MAX_LEN = 10`). `PACKAGE_SEGMENT` -is a runtime object literal (`{ key, value }`) constructed from a JSON -import. The value *is* constant per-process, but the identifier shape -violates the project rule. The same name is used in every package's -`client.ts` — it is a project-wide convention. **Flag for SDK-wide cleanup, -do not fix in isolation.** - -**Suggested:** `packageSegment` or `clientPackageSegment`. - ---- - -### 12. `userAgent` / `httpClient` / `host` / `logger` — *pass* — *Still* - -Standard private field names. Acronym handling matches the project rule -(`HttpClient`, `Url` would be flagged, but `HttpClient` matches the imported -type `HttpClient`). **Pass.** - ---- - -### 13. `readAll` — *pass* — *Still* - -Helper does what its name says (reads a `ReadableStream` to -completion). Conventional in the Node `stream/promises` ecosystem. **Pass.** - ---- - -### 14. `buildHttpRequest` — category 17 (Inconsistent action verbs) — *pass* — *Still* - -Verb-prefix matches the function's role (constructs an `HttpRequest` -object). Naming is fine. Note however the *file* mixes `build…`, -`execute…`, `marshal…`, `parse…`, `readAll`, `flatten…` — six verbs for -seven functions. Not unique to this package. **Pass.** - ---- - -### 15. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* +### 11. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -324,21 +275,21 @@ package qualifies. **Pass on package consistency.** --- -### 16. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* +### 12. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 17. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* — *Still* +### 13. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* — *Still* `pipelineId` correctly camelCases the two-letter "ID"; `creator` is a plain word. **Pass.** --- -### 18. `OnlineStore_State` — model.ts:9 — *Still* +### 14. `OnlineStore_State` — model.ts:9 — *Still* **Why:** `Parent_Nested` underscore-joined identifier is a literal translation of a proto nested-type path into the TS symbol name. The @@ -360,9 +311,9 @@ namespace. --- -### 19. `PublishSpec_PublishMode` — model.ts:27 — *Still* +### 15. `PublishSpec_PublishMode` — model.ts:27 — *Still* -**Why:** Same `Parent_Nested` proto-namespace leak as finding 18. The +**Why:** Same `Parent_Nested` proto-namespace leak as finding 14. The identifier reads as "PublishSpec's PublishMode" — the enclosing-type prefix is a verbatim port of the proto nested-type name, and the file acknowledges this with the same eslint-disable comment. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index 4b6fd0c1..b6ac7ae3 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -4,14 +4,14 @@ **Versions audited:** v2 **Inferred domain:** File operations on Databricks storage. v2 is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 15 +**Total weird names flagged:** 12 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 4 | -| Low | 3 | +| Medium | 3 | +| Low | 1 | | Observation | 2 | ## High severity @@ -127,21 +127,7 @@ export interface ListDirectoryResponse { ... } // not ListDirectoryContentsRes - **Suggested name:** `ListDirectoryContentsResponse` to mirror the request. Or trim both to `ListDirectoryRequest` / `ListDirectoryResponse`. - **Rationale:** Same endpoint, same operation — names should mirror. -### 8. `executeCall` / `executeHttpCall` / `sendAndCheckError` / `buildHttpRequest` — `src/v2/utils.ts:26,65,168,96` - -```ts -export async function executeCall(call: Call, options?: CallOptions): Promise -export async function executeHttpCall(opts: HttpCallOptions): Promise -export async function sendAndCheckError(opts: HttpCallOptions): Promise -export function buildHttpRequest(method, url, headers, signal?, body?): HttpRequest -``` - -- **Why weird:** Four nearly-identical-sounding helpers in one file. `executeCall` wraps a `Call` (whatever a `Call` is — it's an opaque `(signal?) => Promise` function reference). `executeHttpCall` takes the actual HTTP request. `sendAndCheckError` is what `executeHttpCall` is but with a different return type (raw `HttpResponse` vs buffered `Uint8Array`). All four start with a verb but use different verbs (`execute`, `send`, `build`) for what amounts to "send this HTTP request and return something". The lowercase `'head'` HTTP method in two callers (`client.ts:621,658`) is an unrelated bug. -- **Category:** 17 (inconsistent verb cluster — execute/send/build), 6 (misleading — `executeCall` and `executeHttpCall` are different despite the matching prefix), 12 (duplicate concept — `executeHttpCall` and `sendAndCheckError` do almost the same thing). -- **Suggested name:** Collapse to one helper (`sendRequest`), let it return the raw `HttpResponse`, and have the caller buffer/stream as needed. Or, if both must exist: `sendAndBuffer` (returns buffered body) and `sendAndStream` (returns raw response). -- **Rationale:** Three functions doing nearly the same thing with names that differ in verb is a recipe for mis-imports. - -### 9. `MoveRequest.sourcePath` / `MoveRequest.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` +### 8. `MoveRequest.sourcePath` / `MoveRequest.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` ```ts export const marshalMoveRequestSchema: z.ZodType = z @@ -160,7 +146,7 @@ export const marshalMoveRequestSchema: z.ZodType = z - **Suggested name:** Acceptable as-is (these are clearer than `path1`/`path2`). Flag only the inconsistency with the rest of the DBFS surface. - **Rationale:** The inconsistency is upstream; the TS port should match. -### 10. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-274` +### 9. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-274` ```ts // ReadRequest_Response: @@ -172,7 +158,7 @@ export const marshalMoveRequestSchema: z.ZodType = z ## Low severity -### 11. `overwrite` — same — `src/v2/model.ts:36,248,283` +### 10. `overwrite` — same — `src/v2/model.ts:36,248,283` ```ts overwrite?: boolean | undefined; @@ -180,27 +166,12 @@ overwrite?: boolean | undefined; Appears in `CreateRequest`, `PutRequest`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `CreateRequest` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. -### 12. `flattenQueryParams` — unused in this file — `src/v2/utils.ts:123` - -Exported helper. Search shows it's never called by `client.ts` here. Name is generic and could collide with workspace-flattening utilities. Either dead code or genuine helper waiting for use. - -### 13. `PACKAGE_SEGMENT` — SCREAMING_SNAKE constant — `src/v2/client.ts:89` - -```ts -const PACKAGE_SEGMENT = { - key: pkgJson.name.replace(/^@[^/]+\//, ''), - value: pkgJson.version, -}; -``` - -SCREAMING_SNAKE is only conventional for true compile-time primitives in TS. This is a plain object; `packageSegment` is fine. - ## Observations -### 14. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` +### 11. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) -### 15. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` +### 12. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index eb2804ae..ad790aa0 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -6,7 +6,6 @@ **Files audited:** - `src/v1/model.ts` - `src/v1/client.ts` -- `src/v1/utils.ts` - `src/v1/index.ts` This audit applies the audit checklist categories. Each finding lists @@ -42,15 +41,6 @@ Findings are grouped by category. - Method `done` - Local helper class `StillRunningError` -### Utility functions (`utils.ts`) - -`executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, -`parseResponse`, `marshalRequest`, `flattenQueryParams`. - -### Utility types/interfaces (`utils.ts`) - -`HttpCallOptions`. - --- ## Findings diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index d7c241f9..bc092130 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -3,7 +3,7 @@ **Package path:** `/home/parth.bansal/sdk-js/packages/functions/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog Functions (SQL / Python UDFs and UDTFs). -**Total weird names flagged:** 43 (0 fixed, 43 still present after rescan on 2026-05-26 post regen #156). +**Total weird names flagged:** 38 (0 fixed, 38 still present after rescan on 2026-05-26 post regen #156). --- @@ -68,12 +68,6 @@ request-body fields with the same key. TypeScript callers have no need for this distinction — the field is the function's fully-qualified name. See also §8.1 and §7.3. -#### 3.4 `pkgJson` (client.ts:19) -Internal variable name for `package.json`. Mild — flagged for -consistency with other audits. - -#### 3.5 `respBody` (client.ts:97, 137, 181, 237, 293) — internal-only; mild. - --- ### 4. Acronym casing inconsistencies (SQL, UDF, UDTF, JSON) @@ -161,8 +155,6 @@ desired name of the function, used in the body). See §9.1. #### 8.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`. No tense issues. -#### 8.2 `executeCall`, `executeHttpCall` (utils.ts:26, 65), `buildHttpRequest`, `flattenQueryParams` (utils.ts:96, 123) — all imperative present, consistent. - No verb-tense inconsistencies found across the package. --- @@ -256,16 +248,7 @@ A consumer cannot tell them apart from the types. ## Additional / cross-cutting observations -### A. `flattenQueryParams` is defined but unused (utils.ts:123) -Each `listFunctions` / `getFunction` / `deleteFunction` handler -builds query strings inline with `URLSearchParams.append` -(client.ts:115-118, 156-159, 197-212). The exported helper -`flattenQueryParams` is never referenced by `client.ts`. Either it's -intentionally exported for consumer use (then it should be -documented) or it's dead code. Same finding as catalogs audit -(cross-cutting A). - -### B. `fullNameArg` URL substitution silently allows empty string +### A. `fullNameArg` URL substitution silently allows empty string (client.ts:122, 166, 283) — `${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL silently becomes `/api/2.1/unity-catalog/functions/` and the request will fail on the @@ -273,17 +256,13 @@ server. The naming (`fullNameArg`) and the substitution behaviour together hide what should be a required parameter. Worth surfacing via a non-optional type or a typed assertion. -### C. `marshalUpdateFunctionRequestSchema` serialises `fullNameArg` into the body +### B. `marshalUpdateFunctionRequestSchema` serialises `fullNameArg` into the body (model.ts:799) `fullNameArg` is a path parameter — but the marshal schema produces a JSON field `full_name_arg`. Either the server tolerates the extra field or this is a bug. The `Arg` suffix lets the bug hide. -### D. `Client` constructor throws bare `Error` for missing `host` (client.ts:59) -"Host is required." — bare `Error`. Not a naming issue, flagged for -consistency with the catalogs audit. - -### E. Package-name collision with JavaScript reserved word +### C. Package-name collision with JavaScript reserved word The package is named `@databricks/sdk-functions` and the npm workspace path is `packages/functions/`. `function` is a JS reserved word; `functions` is not, but the proximity is jarring. Importers @@ -294,7 +273,7 @@ shadows nothing, but the combination of the package name and the `Dependency.value.$case === 'function'` pattern creates a vocabulary where "function" is overloaded. -### F. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` +### D. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` The most extreme case of a single-purpose API surface: a long enum type holding a one-letter variant, only ever set to `S`, marshaled as the JSON string `"S"`. Three layers of indirection for a constant. @@ -418,8 +397,7 @@ envelope visibly reflect proto oneof semantics. Already noted in | `UpdateFunctionRequest.fullNameArg / name` | model.ts:324, 326 | 3.3, 7.4, 11.1 | | `UpdateFunctionRequest.fullName` | model.ts:372 | 7.2, 11.4 | | `Client` (bare name) | client.ts:44 | 9.1 | -| `${req.fullNameArg ?? ''}` URL substitution | client.ts:122, 166, 283 | B | -| `flattenQueryParams` (unused export) | utils.ts:123 | A | +| `${req.fullNameArg ?? ''}` URL substitution | client.ts:122, 166, 283 | A | --- @@ -428,6 +406,5 @@ envelope visibly reflect proto oneof semantics. Already noted in 1. **Fix `fullNameArg` / `name` confusion on `UpdateFunctionRequest`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §3.3) 2. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.1, §2.2, §3.1, §3.2) 3. **Strip read-only fields from `CreateFunction` / `UpdateFunctionRequest`.** (§11.2) -4. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) --- diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index f7f00dad..44f7db63 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -14,7 +14,7 @@ creation and returns it everywhere else. Five operations: pagination, no list filtering beyond an optional `principalId` query parameter, no version negotiation. **Total weird names flagged:** 12 (0 fixed, 12 still open) -**Last rescan:** 2026-05-26 (post regen #156) +**Last rescan:** 2026-05-26 (post regen #156, post Workflow B prune) --- diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index 57c25ef6..c3ae32b1 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -79,11 +79,7 @@ None. This package defines no enums. ### 1.5 Other identifiers -- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields - `host`, `httpClient`, `logger`, `userAgent`. -- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`. +- `client.ts`: `Client` class. --- @@ -103,9 +99,8 @@ No enums are declared in this package; this rubric category does not apply. | ID | Symbol | Severity | Issue | | ----- | --------------------- | -------- | ----- | -| A-01 | `HttpClient`, `httpClient` (imported from core) | Low | Google TS style uses `Http` (initial-only capitalisation for acronyms > 2 chars — https://google.github.io/styleguide/tsguide.html#identifiers). Consistent. | -| A-02 | `Uint8Array` | Low | Standard Web/TC39 typed-array name; OK. | -| A-03 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScriptRequest.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | +| A-01 | `Uint8Array` | Low | Standard Web/TC39 typed-array name; OK. | +| A-02 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScriptRequest.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | ### 2.4 Underscores in TS identifiers — Low @@ -113,13 +108,9 @@ No enums are declared in this package; this rubric category does not apply. | ----- | ------------------------------------------ | -------- | ----- | | U-01 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | -### 2.5 Cryptic abbreviations — Low +### 2.5 Cryptic abbreviations — None -| ID | Symbol | Severity | Issue | -| ----- | ----------------------- | -------- | ----- | -| C-01 | `req`, `resp`, `httpReq`, `respBody` (`client.ts`) | Low | Short-lived local identifiers; OK for short scope but `request` / `response` would be clearer at no cost. | -| C-02 | `opts` (`utils.ts` parameter) | Low | Inside fn scope; minor. | -| C-03 | `pkgJson` (`client.ts:19`) | Low | Abbreviation of "packageJson". Local import alias; OK. | +_None._ ### 2.6 Misleading names — High @@ -173,14 +164,12 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix, `model.ts:41`) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | -| G-02 | `req: CreateGlobalInitScriptRequest` (parameter named `req`, `client.ts:75`) | Low | Go-style parameter abbreviation. JS/TS convention is `request` for a parameter; `req` is also common in Express but uncommon as an SDK method parameter. | ### 2.14 Generic field names losing meaning — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | F-01 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Standard entity field; meaning preserved in context. | -| F-02 | `httpReq`, `respBody`, `body`, `headers`, `text`, `parsed`, `info` (locals in `client.ts` / `utils.ts`) | Low | Local-scope identifiers only. | ### 2.15 Field contradicting type domain — Low @@ -208,8 +197,6 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | TS-01 | `GlobalInitScriptDetails` (`model.ts:41`) | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | -| TS-02 | `HttpCallOptions` (utils) | Low | "Options" is conventional for option-bag types; not tautological. | -| TS-03 | `CallOptions` (imported) | Low | Same. | ### 2.20 Proto-architectural leaks — High @@ -229,11 +216,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | X-01 | `GlobalInitScriptDetails.createdAt` / `updatedAt` (`number`, epoch ms) | Low | Acceptable for ms timestamps; the SDK exposes these as plain numbers. JS `Date` safe-integer range covers epoch-ms beyond year 285,000. Flagged for parity with other audits. | -| X-02 | `PACKAGE_SEGMENT` constant (`client.ts:43`) | Low | `SCREAMING_SNAKE_CASE` for a module-level constant — Google TS style permits this for "module-level constants … that are deeply immutable and used like enum constants" (https://google.github.io/styleguide/tsguide.html#constants). OK. | -| X-03 | `Client` (class name, `client.ts:48`) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | -| X-04 | `VERSION as AUTH_VERSION` (imported alias, `client.ts:3`) | Low | Aliasing on import is fine; communicates which version is being referenced. OK. | -| X-05 | `HttpClient`, `HttpRequest`, `HttpResponse` (imported) | Low | Consistent Google-style acronym casing. OK. | -| X-06 | `NoOpLogger` (imported) | Low | `NoOp` casing is correct for "no-op" (the term `no-op` is itself a contracted form). OK. | +| X-02 | `Client` (class name, `client.ts:48`) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | --- @@ -245,8 +228,8 @@ _None._ | -------- | ----- | | High | 10 | | Medium | 5 | -| Low | 28 | -| **Total**| **43**| +| Low | 16 | +| **Total**| **31**| ### 3.2 Top themes diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md index 51f39937..8f41fac0 100644 --- a/.agent/naming-audit/grants.md +++ b/.agent/naming-audit/grants.md @@ -3,15 +3,15 @@ **Path:** `packages/grants/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. -**Total weird names flagged:** 12 +**Total weird names flagged:** 9 ## Summary | Severity | Count | | --- | --- | | High | 5 | | Medium | 3 | -| Low | 3 | -| Observation | 1 | +| Low | 1 | +| Observation | 0 | The grants package contains 9 generated types and 3 client methods covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive remaining issues are (1) the conceptual overlap with the separate `permissions` package which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation, and (2) the lack of enum types for the closed sets of `securableType` and `privilege` strings. @@ -84,24 +84,10 @@ The grants package contains 9 generated types and 3 client methods covering one - **Suggested name:** `GrantsClient` (or whatever the package-specific name is). - **Rationale:** Convention in `@aws-sdk/*`, `@google-cloud/*`, `@azure/*` is service-prefixed client class names for exactly this reason. -### 10. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` -- **Why weird:** `Segment` is a generic word; without the doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Cross-package consistency. - -### 11. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Yet another `Options` suffix; the file also imports `Options` (line 3) and `CallOptions` (line 12), so three `Options` types are in scope at once. The `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. -- **Category:** 1 (vague suffix), 17 (inconsistent). -- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). -- **Rationale:** Distinguish internal context bags from user-facing option structs. - --- ## Observations -### 12. `Client` constructor: `Host is required.` — `src/v1/client.ts:52` -Error message thrown but no client name in the message. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. -- **Category:** Observation. +_None._ --- diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md index e61293a5..90cb75bb 100644 --- a/.agent/naming-audit/iam.md +++ b/.agent/naming-audit/iam.md @@ -11,10 +11,10 @@ resolve-by-external-id flows that bridge the customer IdP to Databricks. | Severity | Count | | -------- | ----- | | High | 6 | -| Medium | 5 | +| Medium | 4 | | Low | 3 | -| Observation | 3 | -| **Total** | **17** | +| Observation | 1 | +| **Total** | **14** | Three dominant themes remain. **First, the package still ships methods, requests, and a handful of variants in parallel `*` and `*Proxy` forms** that @@ -185,17 +185,7 @@ beyond Java-RPC habit. - **Rationale:** Two suffixes for the same routing-variant idea is the worst possible outcome. -### M3. `resolveByExternalId` URL segment uses camelCase -- **File:** `client.ts:105, 134, 163, 198, 233, 262` -- **Category:** 14, 3 (Go-style; casing) -- **Issue:** The URL paths use `/resolveByExternalId` in camelCase. The URLs - are server-defined, so this is not a naming issue the SDK can fix, but it - is worth noting because the inconsistency is visible in the SDK's debug - logs. -- **Suggestion:** Server-side fix (out of scope), but flag to the API team. -- **Rationale:** Not the SDK's bug, but reflects an upstream inconsistency. - -### M4. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields +### M3. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields - **File:** `model.ts:317, 329` - **Category:** 12, 6 (duplicate concepts; misleading) - **Issue:** `WorkspaceAccessDetail.permissions` (USER_PERMISSION / @@ -209,7 +199,7 @@ beyond Java-RPC habit. both JSDoc blocks. If they are the same, merge. - **Rationale:** This is the kind of overlap that produces support tickets. -### M5. `resolveByExternalId` method naming +### M4. `resolveByExternalId` method naming - **File:** `client.ts:101, 159, 229` - **Category:** 17 (verb inconsistency) - **Issue:** `resolveGroup`, `resolveUser`, `resolveServicePrincipal`. These @@ -261,34 +251,17 @@ beyond Java-RPC habit. ## Observations (not findings, but worth noting) -### O1. The `Detail` suffix is wired through the URL path -- **File:** `client.ts:294, 331, 367, 402, 436, 460, 479, 504, 529, 566, 608, 654` -- **Issue:** The server URL paths use `workspaceAccessDetails` and - `workspaceAssignmentDetails` — proto/Go RPC pattern. The SDK reflects the - server names. Renaming the TS types per H4 does not change the wire; the - SDK can have nicer TS names while still hitting `workspaceAccessDetails` - URLs. - -### O2. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) +### O1. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) - **File:** `model.ts:94`, `client.ts:327` - **Issue:** Only `WorkspaceAccessDetail` has a `Local` variant; the parallel `WorkspaceAssignmentDetail` uses `Proxy` instead. Inconsistent presence of the Local/Proxy variants across sibling Detail types. -### O3. The `accountId` fallback comment in `client.ts:70-72` only applies to non-proxy methods -- **File:** `client.ts:70-72` -- **Issue:** "Fallback for endpoints whose path contains {account_id}. If - the request already carries an accountId, that value wins." This is true - for the non-proxy methods only — `*Proxy` methods don't have `accountId` - in the URL. Worth noting because if H1 collapses the variants, the - fallback semantic becomes "use the workspace context if accountId is - absent". - --- ## Cross-cutting recommendations (priority order) -1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L2, O2, O3).** This +1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L2, O1).** This is the largest single improvement and ~halves the public type surface. 2. **Standardize the `State` enum name (H3).** One name per concept. diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 095d081a..380c252d 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -21,11 +21,11 @@ configuration, idle / used statistics, and pending-instance failure reporting. | Severity | Count | | ------------ | ----- | -| High | 8 | -| Medium | 1 | -| Low | 8 | -| Observation | 5 | -| **Total** | **22**| +| High | 30 | +| Medium | 3 | +| Low | 28 | +| Observation | 3 | +| **Total** | **64**| ### Top themes @@ -111,9 +111,8 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `DockerImage.credsOneof` | High | `credsOneof` is a Go/proto-codegen leak — TS readers do not know what "Oneof" means in this context (the wire field uses a protobuf `oneof`). The "creds" abbreviation is also generic. Should be `credentials` (and the union shape itself satisfies the discriminator). | -| V-02 | `readAll` (`utils.ts:40`) | Low | Standard name for a read-to-end helper. | -| V-03 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | -| V-04 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | +| V-02 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | +| V-03 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | ### 2.2 Acronym casing inconsistencies — High @@ -130,8 +129,6 @@ configuration, idle / used statistics, and pending-instance failure reporting. | C-01 | `DockerImage.credsOneof` | High (also V-01) | `creds` and `Oneof` are both opaque outside Go/proto context. | | C-02 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | | C-03 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | -| C-04 | `req`, `resp`, `httpReq`, `respBody` locals in `client.ts` | Low | Method-local; OK. | -| C-05 | `opts` (`utils.ts:66`) | Low | Inside function scope; OK. | ### 2.4 Misleading names — High @@ -188,7 +185,6 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ----- | ----------------------------------- | -------- | ----- | | G-01 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | | G-02 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | -| G-03 | `httpClient`, `HttpClient` (vs `HTTPClient`) | Low | Google TS style uses `Http` (lowercased acronym) — consistent. | ### 2.11 Generic field names losing meaning — Low @@ -198,7 +194,6 @@ configuration, idle / used statistics, and pending-instance failure reporting. | F-02 | `DockerBasicAuth.username` / `password` | Low | Standard. OK. | | F-03 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | | F-04 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | -| F-05 | `httpReq`, `respBody`, `params` (locals in `client.ts`) | Low | Locals only. | ### 2.12 Field contradicting type domain — Low @@ -245,9 +240,7 @@ configuration, idle / used statistics, and pending-instance failure reporting. | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | `client.ts:167-170` builds query manually inside `getInstancePool`. `utils.ts:123` exports `flattenQueryParams` but it is unused. | Observation | Dead exported helper. Same observation as in `abacpolicies.md` and other audits. | -| X-02 | `client.ts:197` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | -| X-03 | `executeCall` / `executeHttpCall` pair (`utils.ts:26, 65`) | Observation | Same name-pair concern as in other audits (`abacpolicies.md` #36, `clusters.md` #90). One function name differs from the other only by `Http`. | +| X-01 | `client.ts:197` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | ### 2.18 Proto-architectural leaks @@ -391,11 +384,11 @@ artefact and the leading underscore at the same time. | Severity | Count | | ------------ | ----- | -| High | 8 | -| Medium | 1 | -| Low | 8 | -| Observation | 5 | -| **Total** | **22**| +| High | 30 | +| Medium | 3 | +| Low | 28 | +| Observation | 3 | +| **Total** | **64**| ## 4. Cross-package consistency notes diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index 5e7a5fd4..5b4ef4d9 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -74,14 +74,6 @@ are graded: | `listInstanceProfiles` | GET | `/api/2.0/instance-profiles/list` | `ListInstanceProfilesRequest_Response` | | `removeInstanceProfile` | POST | `/api/2.0/instance-profiles/remove` | `RemoveInstanceProfileRequest_Response` | -### 1.5 Other identifiers - -- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields - `host`, `httpClient`, `logger`, `userAgent`. -- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`. - --- ## 2. Findings by Category @@ -91,8 +83,6 @@ are graded: | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `InstanceProfile` (interface, `model.ts:64`) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | -| V-02 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | -| V-03 | `readAll` (`utils.ts:40`, private) | Low | Standard name for "read all bytes from a stream". OK. | ### 2.2 Redundant enum prefixes — N/A @@ -121,9 +111,6 @@ are graded: | ----- | ----------------------------------- | -------- | ----- | | C-01 | `arn` (within `instanceProfileArn`, `iamRoleArn`) | Low | "ARN" is a well-known AWS acronym; not cryptic in the AWS context. Acceptable. | | C-02 | `iam` (within `iamRoleArn`) | Low | "IAM" = AWS Identity & Access Management. Well-known AWS acronym. Acceptable. | -| C-03 | `req`, `resp`, `httpReq`, `respBody` (`client.ts` locals) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. | -| C-04 | `opts` (`utils.ts` parameter, `executeHttpCall`) | Low | Inside fn scope; minor. | -| C-05 | `pkgJson` (`client.ts:19`) | Low | Standard short name for `package.json` import. OK. | ### 2.6 Misleading names — High @@ -136,9 +123,7 @@ are graded: ### 2.7 Overly verbose / Redundant suffixes — Low -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| O-01 | `PACKAGE_SEGMENT` (`client.ts:41`) | Low | OK in context. | +_None._ ### 2.8 Singular / plural mismatches — Low @@ -189,7 +174,6 @@ revisions can add fields without breaking the type signature. Not flagged. | ----- | ----------------------------------- | -------- | ----- | | F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | | F-02 | `instanceProfiles` (in `ListInstanceProfilesRequest_Response`) | Low | Self-describing. Good. | -| F-03 | `httpReq`, `respBody`, `body` (locals in `client.ts`) | Low | Locals only. | ### 2.15 Field contradicting type domain — Medium @@ -234,12 +218,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | `HttpCallOptions` (`utils.ts:15`) | Low | Local interface; precise. | -| X-02 | `executeHttpCall`, `executeCall` | Low | Both exist, one wraps the other. The naming difference (`HttpCall` vs `Call`) communicates layering: HTTP-aware vs. transport-agnostic. OK. | -| X-03 | `flattenQueryParams` (`utils.ts:123`, exported but unused in this package) | Low | The package has no GET endpoints with query params (the list endpoint takes none). Either remove or use it. Not strictly a naming issue. | -| X-04 | `Client` (the class name itself, `client.ts:46`) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | -| X-05 | `pkgJson` (import alias) | Low | Standard short alias for `package.json`. OK. | -| X-06 | `PACKAGE_SEGMENT.key` derives from `pkgJson.name.replace(/^@[^/]+\//, '')` (string transform on a constant) | Low | Identifier semantics OK; observation only. | +| X-01 | `Client` (the class name itself, `client.ts:46`) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | --- @@ -251,8 +230,8 @@ _None._ | -------- | ----- | | High | 9 | | Medium | 5 | -| Low | 35 | -| **Total**| **49**| +| Low | 23 | +| **Total**| **37**| ### 3.2 Top themes diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 6d53097d..389541b7 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -9,14 +9,14 @@ volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and `KnowledgeSource` each carry their own proto-style nested lifecycle enum (`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). -**Total weird names flagged:** 18 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | | High | 4 | | Medium | 2 | -| Low | 7 | +| Low | 0 | | Observation | 5 | ## High severity @@ -63,69 +63,29 @@ re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and ## Low severity -### 7. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21. -- **Category:** 1 (vague), 17 (inconsistency). -- **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. -- **Rationale:** Names should differ in more than one infix. - -### 8. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` -- **Why weird:** Same as `customllms.md` #23: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in the same file. Three things named `Options`. -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` or `HttpCallParams`. -- **Rationale:** Distinguish internal context bags from user-facing options. - -### 9. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Same as `customllms.md` #28: exported but not used by `client.ts`. -- **Category:** Observation / 11 (unused export). -- **Suggested name:** Either remove the export or document why it ships per-package. -- **Rationale:** Generated artifact; flag for cross-package cleanup. - -### 10. `readAll` helper generic name — `src/v1/utils.ts:40` -- **Why weird:** Same as `customllms.md` #29: helper reads an entire response body stream; name is generic. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` or `readStreamToEnd`. -- **Rationale:** Internal helper, low cost. Skip if generated. - -### 11. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:58` -- **Why weird:** Same as `customllms.md` #24: `Segment` is a generic CS term. -- **Category:** 1 (vague). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** SDK-wide consistency review. - -### 12. `resp` local variable in every method — `src/v1/client.ts:95,124,153,235,260,285,319,370,424,496,537,578` -- **Why weird:** Same as `customllms.md` #33: `resp` is the response. 12 methods repeat the same pattern. -- **Category:** 12 (duplicate pattern). -- **Suggested name:** Refactor away the pattern, not the name. -- **Rationale:** Refactor opportunity surfaced by audit. - -### 13. `pageReq` local in iterator methods — `src/v1/client.ts:342,396,450` -- **Why weird:** Three async generator methods each declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. Minor abbreviation inconsistency: `request` would be clearer in the iterator context, where the variable's purpose ("the request used to fetch each page") differs from the input `req`. -- **Category:** 5 (abbreviation). -- **Suggested name:** `pageRequest` or `nextPageReq`. -- **Rationale:** Local clarity for readability. +_None._ ## Observations -### 14. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` +### 7. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` - **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. - **Category:** 17 (reversed — consistency note). -### 15. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +### 8. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` - **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id. The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. -### 16. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` +### 9. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` - **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `ApiError` usage. Cross-cutting observation from `customllms.md` #36. - **Category:** 3 (acronym casing — SDK-wide). - **Suggested name:** SDK-wide policy decision. -### 17. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +### 10. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` - **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. - **Category:** Observation. -### 18. `Example` lacks `state` field — `src/v1/model.ts:79-98` +### 11. `Example` lacks `state` field — `src/v1/model.ts:79-98` - **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. - **Category:** Observation. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index 73c973c7..13a34602 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,7 +3,7 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 16 +**Total weird names flagged:** 14 ## Summary @@ -12,7 +12,7 @@ | High | 6 | | Medium | 5 | | Low | 2 | -| Observation | 3 | +| Observation | 1 | ## Summary table @@ -32,8 +32,6 @@ | 12 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | | 13 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | | 14 | Observation | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | -| 15 | Observation | `index.ts` | Mixed `export {...}` for enums and `export type {...}` for interfaces | n/a | -| 16 | Observation | URL paths | `/api/2.0/lakeview/...` URL prefix still uses old name | 6 | --- @@ -284,25 +282,6 @@ parentPath?: string | undefined; // workspace path of the folder containing t **Suggested name:** Keep both. Either rename `path → fullPath` for symmetry, or document the relationship in JSDoc on both fields. -### 15. `index.ts` — mixed `export {...}` and `export type {...}` - -**Location:** `src/v1/index.ts:5,7-43` - -```ts -export {DashboardView, LifecycleState, SchedulePauseStatus} from './model'; -export type {AuthorizationDetails, ...} from './model'; -``` - -Enums are exported as values (correct — they have runtime representation); interfaces are exported as types (correct — type-only). The pattern is right; flagging only because a reader scanning the index file might miss the distinction. Consistent with other SDK packages. - -### 16. URL paths still use `lakeview` - -**Location:** Every method's URL constant in `client.ts`, e.g. line 105: `/api/2.0/lakeview/dashboards` - -Wire-format. The SDK cannot rename the URL without server cooperation. Flagged so that the rebrand mismatch noted in #1 is understood as partial (TS name is the lever; URLs are not). - -**Category:** 6. - --- ## Net assessment diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md index 5b525f91..39535650 100644 --- a/.agent/naming-audit/logdelivery.md +++ b/.agent/naming-audit/logdelivery.md @@ -9,15 +9,15 @@ delivery configuration ties a `credentialsId` (AWS IAM role) and a `AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no delete endpoint by design — the API only supports disabling via the update (`PATCH`) method. -**Total weird names flagged:** 19 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 7 | -| Low | 6 | -| Observation | 2 | +| Medium | 5 | +| Low | 3 | +| Observation | 1 | ## High severity @@ -86,62 +86,27 @@ update (`PATCH`) method. - **Suggested name:** `workspaceIds: bigint[]` (matches int64 wire). Alternative: brand the IDs as `WorkspaceId` via `type WorkspaceId = bigint & {__brand: 'WorkspaceId'}`. - **Rationale:** Cross-package finding — every `*Id: number` typed against an int64 wire has the same hazard. Generator-level fix: emit `bigint` for `int64` fields. -### 10. `host: string` field on `Client` is under-described — `src/v1/client.ts:47,62` -- **Why weird:** `private readonly host: string` — without context, `host` could be just a hostname (`example.com`). The setter at line 62 trims a trailing slash, hinting that the field actually carries a full URL with scheme. A user wiring up `ClientOptions.host` cannot tell from the type whether to pass `databricks.com` or `https://databricks.com/`. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `baseUrl: string` (or `databricksHost`). Matches the actual content (a URL including scheme). -- **Rationale:** Generator-level concern — every package's `Client` has this field. Same finding as `disasterrecovery` and others. - -### 11. `executeCall` / `executeHttpCall` — two layers named "execute" — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions both prefixed `execute` doing very different jobs. `executeCall` wraps a call in retry/rate-limit (`utils.ts:26-38`); `executeHttpCall` does the raw HTTP send plus error lift (`utils.ts:65-94`). Inside each client method, `executeHttpCall` is wrapped in a `Call` (the function alias), and `executeCall(call, options)` runs it — the reader has to trace both bodies to learn who calls whom. -- **Category:** 1 (vague), 12 (duplicate prefix), 17 (inconsistent layering nomenclature). -- **Suggested name:** `runWithRetry(call, options)` (outer) + `sendHttp(opts)` or `dispatchHttp(opts)` (inner). The verb pair "run" vs "send" makes the layering obvious. -- **Rationale:** Layer names should make the call graph readable. Same finding cross-package; generator-level concern. - ## Low severity -### 12. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` +### 10. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` - **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered by this configuration. Pair-wise consistency would be either `BILLABLE_USAGE_LOGS` + `AUDIT_LOGS` (both plural with `_LOGS`) or `BILLABLE_USAGE` + `AUDIT` (both singular without). - **Category:** 9 (singular/plural mismatch), 18 (long enum values). - **Suggested name:** `BILLABLE_USAGE` + `AUDIT` (drop `_LOGS` — the enum is `LogDeliveryType` so "logs" is implicit). - **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the enclosing type) is shorter. -### 13. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` +### 11. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` - **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc on line 37 says it means "the log delivery status as the configuration has been disabled since the release of this feature or there are no workspaces in the account". That is "no data to report", not "resource missing". - **Category:** 6 (misleading — value name suggests an HTTP error state, semantics are operational). - **Suggested name:** `NO_DATA`, `NOT_APPLICABLE`, or `DISABLED_AT_RELEASE` — anything that does not read as 404. - **Rationale:** A monitoring dashboard surfacing `status === 'NOT_FOUND'` would mislead an operator into thinking the configuration was deleted. -### 14. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41-44` -- **Why weird:** `Segment` is a generic CS term. The leading comment ("Package identity segment for this client to be used in the User-Agent header.", line 40) does the documentation work the name should do. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PKG_UA_SEGMENT`. -- **Rationale:** Generator-wide concern. Same finding in every audited package. - -### 15. `httpClient: HttpClient` field — type-suffix tautology — `src/v1/client.ts:51,72` -- **Why weird:** Field name and type both end in `Client`. The shorter form would be `client: HttpClient`, but that would collide with the enclosing `Client` class. So the disambiguation is mechanical, not informative. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `transport: HttpClient` (matches the imported `./transport` module) — avoids the `Client/Client` echo and reads as "the transport layer". -- **Rationale:** Generator-wide concern. Tolerable as-is but flagged per rule 20. - -### 16. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` +### 12. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` - **Why weird:** Three-letter abbreviations on parameter and local names across every method. The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. - **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. -### 17. `pageReq` local in `listLogDeliveryConfigurationIter` — `src/v1/client.ts:196` -- **Why weird:** Holds the request shape mutated with `pageToken` between pages. The name reads as "the page's request" rather than "the request iterated across pages". -- **Category:** 5 (cryptic), 1 (vague). -- **Suggested name:** `currentRequest`, `paginatedRequest`, or just `request` (the per-iteration redefinition is clear from context). -- **Rationale:** Loop-local; low impact. - ## Observations -### 18. `flattenQueryParams` is exported but unused — `src/v1/utils.ts:123` -`client.ts` constructs query params inline (lines 155-167) with `new URLSearchParams()` and `params.append(...)`. The exported `flattenQueryParams` helper is never called from this package. Every generated package ships this helper unconditionally — it is generator scaffolding. -- **Category:** 11 (unused public helper). -- **Suggested fix:** Generator-level — only emit `flattenQueryParams` when the client actually needs it. - -### 19. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` +### 13. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index c6a9b97f..355f44bf 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,7 +3,7 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 36 (36 still present, 0 newly fixed, 0 superseded). +**Total weird names flagged:** 32 (32 still present, 0 newly fixed, 0 superseded). ## Summary | Severity | Count | @@ -11,7 +11,7 @@ | High | 8 | | Medium | 18 | | Low | 5 | -| Observation | 5 | +| Observation | 1 | The marketplaces package remains one of the more naming-distressed surfaces in the SDK, though the dominant pre-existing problem — **inconsistent request-type naming** across the package — has been resolved by uniformly applying the `*Request`/`*Response` suffix to every operation type. Notable issues remaining include the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListingsRequest` and its proto-nested `_Response` payload field both use `listings`, while `CreateListingRequest` and `DeleteListingRequest` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type. @@ -600,20 +600,4 @@ Two adjective values. Fine. Flagged because the package also has `Personalizatio ### 32. v1-only audit The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. -### 33. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:205` -Same generic-name issue flagged in other audits — every package emits a `PACKAGE_SEGMENT` constant for User-Agent assembly. Cross-package consistency observation only. -- **Category:** 1 (vague), 15 (generic name). - -### 34. `flattenQueryParams` — `src/v1/utils.ts:123` -The helper is used by `client.ts` to flatten the `file_parent` nested query object in `listFiles`. Most other packages emit this helper unused; here it's actually used. Cross-package consistency observation. -- **Category:** Observation. - -### 35. `readAll` — `src/v1/utils.ts:40` -Internal helper, same as in other packages. Generic name (`io.ReadAll` Go idiom). Could be `readStreamToEnd` or `bufferStream`. -- **Category:** 1 (vague), 14 (Go-style name). - -### 36. `HttpCallOptions` — `src/v1/utils.ts:15` -Yet another `Options` suffix; `Options` (from `@databricks/sdk-core/api`) and `CallOptions` are also in scope. Could be `HttpCallContext`. Cross-package consistency observation. -- **Category:** 1 (vague suffix), 17 (inconsistent). - --- diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index 1279d49c..6e4e526c 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -243,16 +243,7 @@ Same pattern as 15.1 — entity name in field. ## Additional / cross-cutting observations -### A. `flattenQueryParams` is defined but unused (utils.ts:123) -Each `deleteMetastore` / `deleteMetastoreAssignment` / `listMetastores` -handler builds query strings inline with `URLSearchParams.append` -(client.ts:504-507, 538-541, 661-667). The exported helper -`flattenQueryParams` is never referenced by `client.ts`. Either it's -intentionally exported for consumer use (then it should be documented -and reside in `utils` proper) or it's dead code. Same as catalogs -cross-cutting A. - -### B. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:471, 537, 748) +### A. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:471, 537, 748) If `workspaceId` is undefined, the URL silently becomes `/api/2.1/unity-catalog/workspaces//metastore` (note the double slash) and the request will fail on the server. The optional typing of @@ -260,12 +251,12 @@ and the request will fail on the server. The optional typing of `DeleteMetastoreAssignmentRequest`, and `UpdateMetastoreAssignmentRequest` (each field is `number | undefined`) lets the bug hide. -### C. `req.id` is similarly optional but interpolated into URLs (client.ts:503, 596, 718) +### B. `req.id` is similarly optional but interpolated into URLs (client.ts:503, 596, 718) `${req.id ?? ''}` — same pattern: undefined id silently produces a malformed URL. Combined with the generic `id` name the type contract is too loose for a required path parameter. -### D. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:538-543) +### C. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:538-543) On `DELETE /api/2.1/unity-catalog/workspaces/{workspaceId}/metastore`, the request appends `?metastore_id=…`. That contradicts the doc on `DeleteMetastoreAssignmentRequest.metastoreId` ("Query for the ID of @@ -273,11 +264,11 @@ the metastore to delete.") only via the leading word "Query" — the field name itself does not signal that the value is a query parameter, not a path one. -### E. `Client` constructor throws bare `Error` for missing `host` (client.ts:109) +### D. `Client` constructor throws bare `Error` for missing `host` (client.ts:109) "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. -### F. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies +### E. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies This package's `workspaceId` is `number`. Some peer packages model workspace IDs as strings (e.g. when forwarded through URL params). The type inconsistency is across packages, not within this one; @@ -301,11 +292,11 @@ flagged in passing. | `CreateMetastoreRequest.storageRootCredentialName` | model.ts:250 | 11.3 | | `CreateMetastoreRequest.globalMetastoreId` (read-only) | model.ts:254 | 11.3 | | `CreateMetastoreAssignmentRequest` | model.ts:202 | 10.3 | -| `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | F | +| `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | E | | `CreateMetastoreAssignmentRequest.defaultCatalogName` | model.ts:212 | — | | `DeleteMetastoreRequest` | model.ts:269 | — | | `DeleteMetastoreAssignmentRequest` | model.ts:259 | 10.3 | -| `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | D | +| `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | C | | `GetCurrentMetastoreAssignmentRequest` | model.ts:283 | — | | `GetMetastoreRequest` | model.ts:285 | — | | `GetMetastoreSummaryRequest` | model.ts:291 | — | @@ -316,7 +307,7 @@ flagged in passing. | `ListMetastoresRequest_Response.metastores` | model.ts:353 | 8.1 (positive) | | `ListMetastoresRequest_Response.nextPageToken` | model.ts:358 | — | | `MetastoreAssignment` | model.ts:361 | 1.1, 7.2, 10.3 | -| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.1, F | +| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.1, E | | `MetastoreAssignment.metastoreId` | model.ts:365 | 15.2 | | `MetastoreAssignment.defaultCatalogName` | model.ts:370 | — | | `MetastoreInfo` | model.ts:373 | 5.1, 7.1, 10.2 | @@ -329,18 +320,17 @@ flagged in passing. | `UpdateMetastoreAssignmentRequest` | model.ts:455 | 10.3 | | `Client.createMetastore` | client.ts:437 | — | | `Client.createMetastoreAssignment` | client.ts:467 | — | -| `Client.deleteMetastore` | client.ts:499 | C | -| `Client.deleteMetastoreAssignment` | client.ts:533 | B, D | +| `Client.deleteMetastore` | client.ts:499 | B | +| `Client.deleteMetastoreAssignment` | client.ts:533 | A, C | | `Client.getCurrentMetastoreAssignment` | client.ts:567 | 12.1 | -| `Client.getMetastore` | client.ts:592 | 12.1, C | +| `Client.getMetastore` | client.ts:592 | 12.1, B | | `Client.getMetastoreSummary` | client.ts:620 | 5.4, 12.1 | | `Client.listMetastores` | client.ts:656 | — | -| `Client.updateMetastore` | client.ts:714 | C | -| `Client.updateMetastoreAssignment` | client.ts:744 | B | -| `${req.id ?? ''}` URL substitution | client.ts:503, 596, 718 | C | -| `${req.workspaceId ?? ''}` URL substitution | client.ts:471, 537, 748 | B | -| `Host is required.` bare Error | client.ts:109 | E | -| `flattenQueryParams` (unused export) | utils.ts:123 | A | +| `Client.updateMetastore` | client.ts:714 | B | +| `Client.updateMetastoreAssignment` | client.ts:744 | A | +| `${req.id ?? ''}` URL substitution | client.ts:503, 596, 718 | B | +| `${req.workspaceId ?? ''}` URL substitution | client.ts:471, 537, 748 | A | +| `Host is required.` bare Error | client.ts:109 | D | --- @@ -350,7 +340,6 @@ flagged in passing. 2. **Strip read-only fields from `CreateMetastoreRequest` / `UpdateMetastoreRequest`.** (§11.3, §10.2) 3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.3, §10.1) 4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.4, §12.1) -5. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting B, C) -6. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) +5. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting A, B) --- diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index 00b309c2..fa7cfac4 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,36 +8,19 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 31 +**Total weird names flagged:** 30 ## Summary | Severity | Count | | --- | --- | -| High | 20 | +| High | 19 | | Medium | 6 | | Low | 2 | | Observation | 3 | ## High severity -### 1. Package name `modelregistry` — `package.json`, `src/v1/` -- **Why weird:** The directory/package name collapses "model registry" - into one word with no separator, while every other multi-word package - in the SDK keeps the same convention (`registeredmodels`, - `cleanrooms`). The deeper issue is that two packages now exist for the - same product area: `modelregistry` (workspace MLflow) and - `registeredmodels` (Unity Catalog). A user reading the package list - cannot tell which one is which. -- **Category:** 1 (vague), 6 (misleading vs sibling package), 12 - (duplicate concept). -- **Suggested name:** `mlflowmodels` or `workspacemlflow` for this - package, leaving `registeredmodels` as the UC equivalent. Even better: - prefix both with their scope (`mlflowregistry` and `ucmodelregistry`). -- **Rationale:** "modelregistry" reads as the canonical name but is - actually the legacy workspace-scoped surface; UC's `registeredmodels` - is the strategic future. Today's name suggests the opposite. - -### 2. `ActivityAction` enum and `availableActions` field — `model.ts:20-31, 187` +### 1. `ActivityAction` enum and `availableActions` field — `model.ts:20-31, 187` - **Why weird:** `ActivityAction` enum values are full verbs like `APPROVE_TRANSITION_REQUEST`, `CANCEL_TRANSITION_REQUEST`, `EDIT_COMMENT`, `DELETE_COMMENT`. The field on `Activity` is named @@ -56,7 +39,7 @@ is the Unity-Catalog-scoped successor. bag-of-strings. Users typing `ActivityAction.` get suggested values that may be illegal for their actual context. -### 3. `ActivityType` enum — `model.ts:47-62` +### 2. `ActivityType` enum — `model.ts:47-62` - **Why weird:** Values use past-tense verbs (`APPLIED_TRANSITION`, `REQUESTED_TRANSITION`, `CANCELLED_REQUEST`, `APPROVED_REQUEST`, `REJECTED_REQUEST`, `NEW_COMMENT`, `SYSTEM_TRANSITION`). The "_REQUEST" @@ -76,7 +59,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Mixed tense and grammatical category in one enum makes it hard to remember which value to use without looking it up. -### 4. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` +### 3. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` - **Why weird:** Enum name says `Type` but values are *states* (`ALL_EVENTS`, `DEFAULT`, `SUBSCRIBED`, `UNSUBSCRIBED`). `DEFAULT` and `ALL_EVENTS` overlap in meaning. The class doc-comment marks it @@ -88,7 +71,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The field consuming the enum is already called `emailSubscriptionStatus`; the enum should match. -### 5. `RegistryWebhookEvent` enum — `model.ts:113-126` +### 4. `RegistryWebhookEvent` enum — `model.ts:113-126` - **Why weird:** Contains both generic `MODEL_VERSION_TRANSITIONED_STAGE` *and* three specific `MODEL_VERSION_TRANSITIONED_TO_{STAGING,PRODUCTION,ARCHIVED}`. The @@ -103,7 +86,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** Overlap creates "two ways to express one intent" — a classic source of bugs. -### 6. `Activity` vs `CommentObject` vs `TransitionRequest` — `model.ts:150, 227, 1015` +### 5. `Activity` vs `CommentObject` vs `TransitionRequest` — `model.ts:150, 227, 1015` - **Why weird:** Three interfaces have *identical* shape and *identical* doc-comment ("For activities, this contains the activity recorded for the action. For comments, this contains the comment details. For @@ -118,15 +101,15 @@ is the Unity-Catalog-scoped successor. the `activityType` discriminator. The "type per usage site" anti-pattern forces consumers to choose between identical shapes. -### 7. `CommentObject` — `model.ts:227` +### 6. `CommentObject` — `model.ts:227` - **Why weird:** `Object` is the most generic suffix possible in TS (everything is an object). Combined with the duplicate-shape problem - (#6), this is a textbook bad name. + (#5), this is a textbook bad name. - **Category:** 1 (vague `Object` suffix), 20 (type-suffix tautology). -- **Suggested name:** `Comment` — or fold into `Activity` per #6. +- **Suggested name:** `Comment` — or fold into `Activity` per #5. - **Rationale:** `Object` adds nothing; the type is already a TS object. -### 8. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, +### 7. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, `TransitionModelVersionStageDatabricksRequest`, `ModelVersionDatabricks` — `model.ts:542, 549, 690, 758, 981, 1005` - **Why weird:** `Databricks` as a type suffix. The whole SDK is the @@ -144,7 +127,7 @@ is the Unity-Catalog-scoped successor. (then split by capability). The current "shadow type per extension" is a generator artefact, not a user-friendly API. -### 9. `TransitionModelVersionStageDatabricksRequest` — `model.ts:981` +### 8. `TransitionModelVersionStageDatabricksRequest` — `model.ts:981` - **Why weird:** Six-word PascalCase identifier with awkward word order. Reads as "transition[verb] model-version-stage[object]-databricks[suffix]-request[suffix]". For a @@ -160,7 +143,7 @@ is the Unity-Catalog-scoped successor. performing similar workspace operations; the asymmetric names obscure this. -### 10. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:542` +### 9. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:542` - **Why weird:** Verb-phrase request type name (`GetX`) is OK if used consistently, but `GetRegisteredModelDatabricksRequest` is the only method the SDK exposes to fetch a registered model — there is no plain @@ -172,7 +155,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** No need for the disambiguation suffix when there's no sibling. -### 11. `client.listTransitionsRequest` method vs `ListTransitionRequest` +### 10. `client.listTransitionsRequest` method vs `ListTransitionRequest` request type — `client.ts:513, model.ts:645` - **Why weird:** The method is `listTransitionsRequest` (plural "Transitions") but the request type is `ListTransitionRequest` @@ -193,7 +176,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The method name in JS conventions describes the collection being listed; here that's "transition requests", plural. -### 12. `RegistryWebhook` vs `Webhook` — `model.ts:787` +### 11. `RegistryWebhook` vs `Webhook` — `model.ts:787` - **Why weird:** Type is `RegistryWebhook` but client methods, paths, and request types alternate: `CreateRegistryWebhookRequest`, `ListRegistryWebhooksRequest`, `UpdateRegistryWebhookRequest`, @@ -206,7 +189,7 @@ is the Unity-Catalog-scoped successor. `TestWebhookRequest`. - **Rationale:** Package name already establishes the registry context. -### 13. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` +### 12. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` - **Why weird:** `Spec` is a vague suffix shared by every config-bag in the SDK. Two sibling types in the same package, only the `Spec` suffix distinguishing them. `HttpUrlSpec` is the *target* of a webhook @@ -219,7 +202,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The two together discriminate the webhook destination kind; the naming should make that obvious. -### 14. `LinkedFeature` — `model.ts:573` +### 13. `LinkedFeature` — `model.ts:573` - **Why weird:** Doc comment says "Feature for model version. ([ML-57150] Renamed from Feature to LinkedFeature)". The ticket number leaks into the public docstring. Type name was changed for internal reasons @@ -232,7 +215,7 @@ is the Unity-Catalog-scoped successor. type; the fields are just identifiers pointing at a feature in the feature store. -### 15. `stage: string` field on `ApproveTransitionRequest`, +### 14. `stage: string` field on `ApproveTransitionRequest`, `CreateTransitionRequest`, `DeleteTransitionRequest`, `RejectTransitionRequest`, `TransitionModelVersionStageDatabricksRequest` — `model.ts:209, 396, 483, 847, 997` @@ -248,9 +231,9 @@ is the Unity-Catalog-scoped successor. to a type. Currently every transition method takes `stage: string` with no type-level validation. -### 16. `currentStage: string` field on `ModelVersion`, +### 15. `currentStage: string` field on `ModelVersion`, `ModelVersionDatabricks` — `model.ts:670, 701` -- **Why weird:** Same as #15 — typed as `string`, valid values +- **Why weird:** Same as #14 — typed as `string`, valid values enumerated only in docs. Also called `currentStage` here but `stage` on request DTOs (no prefix). Inconsistent. - **Category:** 6 (misleading), 16 (type contradicts domain), 17 @@ -259,7 +242,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** "Current" is implicit (it's the *current* stage of this version). -### 17. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` +### 16. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` - **Why weird:** Three different `Activity`-shaped types each duplicate `fromStage: string | undefined`, `toStage: string | undefined`, again stringly typed. Identical doc-comments paste the same four-value @@ -267,10 +250,10 @@ is the Unity-Catalog-scoped successor. - **Category:** 16 (type contradicts domain), 12 (duplicate concept), 7 (overly verbose docs). - **Suggested name:** `fromStage: Stage`, `toStage: Stage`. -- **Rationale:** Same as #15. +- **Rationale:** Same as #14. -### 18. `Databricks` as a suffix is overused -- **Why weird:** Distinct type names still end in `Databricks` (see #8): +### 17. `Databricks` as a suffix is overused +- **Why weird:** Distinct type names still end in `Databricks` (see #7): `RegisteredModelDatabricks`, `ModelVersionDatabricks`. Two more retain `Databricks` as an infix inside the new `Request` suffix (`GetRegisteredModelDatabricksRequest`, @@ -278,10 +261,10 @@ is the Unity-Catalog-scoped successor. workspace-specific extension. The `Databricks` token appearing inside the *Databricks SDK* is tautological. - **Category:** 8 (redundant suffix), 20 (type-suffix tautology). -- **Suggested name:** See #8. -- **Rationale:** See #8. +- **Suggested name:** See #7. +- **Rationale:** See #7. -### 19. `getRegisteredModelDatabricks` client method — `client.ts:416` +### 18. `getRegisteredModelDatabricks` client method — `client.ts:416` - **Why weird:** Method name carries `Databricks` mid-position (between the noun `RegisteredModel` and any conceptual suffix). The whole SDK is the Databricks SDK; embedding `Databricks` inside a method name is @@ -301,9 +284,9 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The infix encodes a proto-level distinction that has no analogue in this TS surface; remove it. -### 20. `transitionModelVersionStageDatabricks` client method — +### 19. `transitionModelVersionStageDatabricks` client method — `client.ts:615` -- **Why weird:** Same `Databricks` mid-position leak as #19. The token +- **Why weird:** Same `Databricks` mid-position leak as #18. The token sits between `Stage` and the implicit method suffix, marking the method as the workspace-extension variant of an upstream MLflow RPC. Method-name length (six words, 38 chars) is also a symptom: the verb @@ -314,13 +297,13 @@ is the Unity-Catalog-scoped successor. (overly verbose), 14 (proto-style leakage into surface API). - **Suggested name:** `transitionModelVersionStage` (drop the infix) or fold into `approveTransitionRequest`-style verbs since the operations - overlap (see #9). -- **Rationale:** Same as #19 — the infix encodes a generator-side + overlap (see #8). +- **Rationale:** Same as #18 — the infix encodes a generator-side distinction that callers do not need. ## Medium severity -### 21. `tags?: ModelVersionTag[] | undefined` and +### 20. `tags?: ModelVersionTag[] | undefined` and `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, 719, 755, 776` - **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, @@ -331,42 +314,42 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Single `Tag` type with `{ key, value }`. - **Rationale:** Identical structure should have identical type. -### 22. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` +### 21. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` - **Why weird:** Typed as `Activity[]` but the field is documented as "Open requests for this `model_versions`" — they are transition *requests* (not arbitrary activities). The reason is the - identical-shape problem (#6). + identical-shape problem (#5). - **Category:** 6 (misleading type), 16 (type contradicts domain). - **Suggested name:** `openTransitionRequests: TransitionRequest[]` - (post-rename per #6). + (post-rename per #5). - **Rationale:** Restores the intent. -### 23. `requests: Activity[]` on list-transition-requests response — +### 22. `requests: Activity[]` on list-transition-requests response — `model.ts:655` - **Why weird:** Stored as `Activity[]` but the response is documented as "Array of open transition requests." - **Category:** 6 (misleading type), 15 (generic field name). - **Suggested name:** `transitionRequests: TransitionRequest[]`. -- **Rationale:** Same as #22 — type contradicts domain because of the - identical-shape problem (#6). +- **Rationale:** Same as #21 — type contradicts domain because of the + identical-shape problem (#5). -### 24. `registeredModelDatabricks: RegisteredModelDatabricks` — +### 23. `registeredModelDatabricks: RegisteredModelDatabricks` — `model.ts:549` - **Why weird:** Field name *is* the type name verbatim. The `Databricks` - suffix problem (#8) cascades into the field name. + suffix problem (#7) cascades into the field name. - **Category:** 20 (type-suffix tautology). - **Suggested name:** After dropping the `Databricks` suffix from the type: `registeredModel: RegisteredModel`. Or just return the type directly without a wrapper. - **Rationale:** Reduces verbosity by removing the wrapper. -### 25. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` -- **Why weird:** Same as #24 for `ModelVersionDatabricks`. +### 24. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` +- **Why weird:** Same as #23 for `ModelVersionDatabricks`. - **Category:** 20. - **Suggested name:** `modelVersion: ModelVersion`. - **Rationale:** Same. -### 26. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, +### 25. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, `model.ts:501` - **Why weird:** The method returns *one* version per stage, not "the latest version" globally. The name reads as "give me the latest @@ -381,7 +364,7 @@ is the Unity-Catalog-scoped successor. ## Low severity -### 27. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, +### 26. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, 593, 633, 634, 642, 877, 886, 894, 905, 913, 921` - **Why weird:** Consistent across the package — good. Noted for completeness. @@ -389,7 +372,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** No change. - **Rationale:** Observation. -### 28. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` +### 27. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` - **Why weird:** Field doc says "If provided, updates the name for this `registered_model`." Slightly confusing because `RenameRegisteredModelRequest` is *the* rename operation — "if @@ -402,7 +385,7 @@ is the Unity-Catalog-scoped successor. ## Observations -### 29. Both `modelregistry` and `registeredmodels` exist as packages +### 28. Both `modelregistry` and `registeredmodels` exist as packages The user instruction calls out this duplication. Cross-package overlap: - `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` (registeredmodels) — same concept, different names. @@ -420,7 +403,7 @@ The user instruction calls out this duplication. Cross-package overlap: Documentation does not direct users to one or the other. - **Category:** 12 (duplicate concepts — across packages). -### 30. Action-verb conventions in `Client` +### 29. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -429,7 +412,7 @@ reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). -### 31. Acronym casing inside doc-comments +### 30. Acronym casing inside doc-comments `MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` (`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md index e4e41574..1fb64502 100644 --- a/.agent/naming-audit/modelserving.md +++ b/.agent/naming-audit/modelserving.md @@ -3,15 +3,15 @@ **Path:** `packages/modelserving/src/v1/` **Versions audited:** v1 **Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Created by the 2026-05-22 regeneration which consolidated the prior `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. -**Total weird names flagged:** 33 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | | High | 8 | | Medium | 12 | -| Low | 9 | -| Observation | 4 | +| Low | 6 | +| Observation | 2 | ## High severity @@ -199,39 +199,21 @@ - **Suggested name:** Type as a string-literal union or, at minimum, document the accepted values in JSDoc. - **Rationale:** Same class as #22/#23. -### 25. `StillRunningError extends Error` private throw-away — `src/v1/client.ts:80` -- **Why weird:** Internal marker error class. Name is fine (`StillRunningError` reads as "operation still running, not done yet"), but the class is never exported, never caught outside the four waiters, and is used purely as a retry signal. Compare to other packages where this is named `RetryableError` or `PollAgainError`. The name "StillRunning" implies a polling lifecycle rather than a retry signal. -- **Category:** 1 (vague), 17 (inconsistent with sibling SDK packages). -- **Suggested name:** `RetrySignal` (it is an internal control-flow signal, not a real error). -- **Rationale:** Minor; internal. - -### 26. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` +### 25. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` - **Why weird:** The method `getExportEndpointMetrics` returns `ExportMetricsResponse` — the type name dropped the `Endpoint` qualifier present in the method name. A reader greping for `EndpointMetrics` won't find the response type. Same shape (`contents?: ReadableStream`) as `ExternalFunctionResponse` and `GetOpenApiResponse`; the *content* is the only thing that says "metrics". - **Category:** 17 (inconsistent — method qualifier dropped from response type), 1 (vague — `ExportMetricsResponse` could be metrics for anything). - **Suggested name:** Pair the method rename in #8 with a response rename: `getEndpointMetrics()` → `EndpointMetrics`. Or `exportEndpointMetrics()` → `ExportEndpointMetricsResponse`. - **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. -### 27. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` +### 26. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` - **Why weird:** Every read method here is prefixed `get*`. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, it's typically on synchronous accessors. - **Category:** 14 (Go/Java-style names). - **Suggested name:** Verb-first for actions: `exportMetrics(req)`, `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or property-style if the request is trivial. - **Rationale:** Google TS Style Guide § Names of functions (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. SDK-wide call, flag for project review. -### 28. `Call` type aliased to `Promise` in `utils.ts` import — `src/v1/utils.ts:3` -- **Why weird:** `Call` is one of the most generic names imaginable. Imported as `import type {Call, Options} from '@databricks/sdk-core/api'` with no qualifier. Inside the client `const call: Call = async ...` reads like "a phone call" or "function call". The actual semantic is "a retriable RPC closure". -- **Category:** 1 (vague). -- **Suggested name:** `RetriableRpc` or `RpcClosure`. Cross-package decision because `Call` is defined in `@databricks/sdk-core/api`. -- **Rationale:** Type names exported from a "core" package set the vocabulary for every consumer; bare `Call` is the kind of name that survives review only because nobody wants to argue with the framework. - -### 29. `Options` type aliased to internal options shape — `src/v1/utils.ts:3, 30` -- **Why weird:** Same as #28 but for `Options`. `Options` is generic to the point of meaninglessness. The translation step in `executeCall` exists *because* the public `CallOptions` and the internal `Options` are two different "options" types that happen to have similar fields. -- **Category:** 1 (vague), 12 (duplicate concept — `Options` vs `CallOptions`). -- **Suggested name:** `ExecuteCallInternalOptions` (verbose but honest) or `RetrierOptions`. Cross-package decision. -- **Rationale:** Two adjacent "Options" types in 35 lines of code is the classic accidental-collision pattern. - ## Observation -### 30. Mixed naming convention for the same product across sibling packages +### 27. Mixed naming convention for the same product across sibling packages The Databricks "Serving Endpoints" product spans two packages in this SDK after the 2026-05-22 consolidation: - `modelserving`: types use `InferenceEndpoint*` (control plane). - `modelservingquery`: types use `Endpoint` (data plane — e.g., `QueryEndpointInput`, `QueryEndpointResponse`). @@ -239,18 +221,10 @@ The Databricks "Serving Endpoints" product spans two packages in this SDK after The wire uniformly uses `serving-endpoints`. SDK consumers chaining both packages will see different names for one concept. - **Category:** 17 (cross-package inconsistency). -### 31. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` +### 28. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. - **Category:** 12 (duplicate concept). -### 32. `userAgent` is built once in the constructor and never refreshed — `src/v1/client.ts:89, 103` -Not a name bug per se, but the field name `userAgent` suggests a dynamic property, while the construction reads `this.userAgent = info.toString();` once at construction time. If the credentials are mutated post-construction (rare but possible), the UA goes stale. Cross-package observation. -- **Category:** 6 (mildly misleading). - -### 33. `info` local var in the constructor — `src/v1/client.ts:97, 99, 103` -`let info = createDefault().with(PACKAGE_SEGMENT);` then more `info = info.with(...)` chains. The name `info` is category-5 (cryptic abbreviation of "information") and category-1 (vague). A reader who hasn't looked at `createDefault()` does not know `info` is a `ClientInfo`. Cross-package observation. -- **Category:** 1, 5. - ## Domain glossary - `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names and waiter class names, abbreviated in type names. - `ai gateway` — A Databricks proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index 5ce54ff0..debd0b3a 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -6,14 +6,13 @@ **Files audited:** - `src/v1/model.ts` - `src/v1/client.ts` -- `src/v1/utils.ts` - `src/v1/index.ts` **Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. -**Total weird names flagged:** 17 (0 fixed, 17 still, 0 superseded) +**Total weird names flagged:** 16 (0 fixed, 16 still, 0 superseded) -Rescanned on 2026-05-26 after regeneration #156. All 17 findings remain +Rescanned on 2026-05-26 after regeneration #156. All 16 findings remain unchanged in the regenerated output; no items have moved to `## Fixed`. --- @@ -38,7 +37,6 @@ unchanged in the regenerated output; no items have moved to `## Fixed`. | 14 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | | 15 | Medium | `model.ts` field | `QueryEndpointInputRequest.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | | 16 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | -| 17 | Low | `utils.ts` function | `flattenQueryParams` | Orphaned export — not used in client; "Query" here means URL query, conflicting with the package's "Query" | --- @@ -320,25 +318,6 @@ export enum ChatMessageRole { Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. -### 17. `flattenQueryParams` — orphaned export with conflicting "Query" - -**Location:** `src/v1/utils.ts:123-150` - -**Categories:** 1 (vague), 12 (duplicate concept), 17 (orphan) - -```ts -export function flattenQueryParams( - prefix: string, - value: unknown, - params: URLSearchParams -): void { ... } -``` - -Two issues: - -1. **Not used by the client** — `client.ts` only POSTs a body, never sets URL query parameters. The function is dead code at the package level (generator artefact). -2. **"Query" is conflated.** Inside this package the word "query" refers to *inference*, but here it means *URL query string parameters*. A reader who has just internalised "query = inference" will misread the function's purpose. `flattenUrlSearchParams` would dodge the collision. - --- ## Observations @@ -353,11 +332,9 @@ Two issues: 5. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInputRequest` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. -6. **`utils.ts` is identical across packages.** The file is byte-for-byte the same as in `alerts/src/v1/utils.ts`, `endpoints/src/v1/utils.ts`, etc. The single domain-specific export, `flattenQueryParams`, is dead in this package. - -7. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInputRequest, options?: CallOptions)` would catch the missing path parameter at the type level. +6. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInputRequest, options?: CallOptions)` would catch the missing path parameter at the type level. -8. **No streaming support despite `stream: boolean`.** `QueryEndpointInputRequest.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. +7. **No streaming support despite `stream: boolean`.** `QueryEndpointInputRequest.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. --- @@ -394,5 +371,4 @@ This package has only `v1`. There is no v2 to diff against. Several names visibl |-------------------|-------|--------------| | `src/v1/model.ts` | 342 | yes | | `src/v1/client.ts`| 82 | yes | -| `src/v1/utils.ts` | 150 | yes | | `src/v1/index.ts` | 21 | yes | diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 6d4cd66d..e5c2b4e0 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,7 +3,7 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 12 +**Total weird names flagged:** 8 ## Summary @@ -11,8 +11,8 @@ | --- | --- | | High | 4 | | Medium | 1 | -| Low | 5 | -| Observation | 2 | +| Low | 2 | +| Observation | 1 | ## Summary table @@ -24,12 +24,8 @@ | 4 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | | 5 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | | 6 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | -| 7 | Low | `client.ts:40-43` | `PACKAGE_SEGMENT` | 1 (vague), 15 (generic) | -| 8 | Low | `utils.ts:15-19` | `HttpCallOptions` | 1 (vague), 12 (duplicate `Options`) | -| 9 | Low | `utils.ts:26` / `:65` | `executeCall` / `executeHttpCall` near-duplicate | 1 (vague), 17 (inconsistent layer naming) | -| 10 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 11 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | -| 12 | Obs | — | `NEXT_CHANGELOG.md` and pre-existing build/lint workflows | — | +| 7 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 8 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | ## High severity @@ -121,40 +117,7 @@ - **Category:** 9 (qualifier mismatch). - **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #2 for the rationale. -### 7. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:40-43` -- **Code:** - ```ts - // Package identity segment for this client to be used in the User-Agent header. - const PACKAGE_SEGMENT = { - key: pkgJson.name.replace(/^@[^/]+\//, ''), - value: pkgJson.version, - }; - ``` -- **Why weird:** "Segment" is a generic computer-science term. The comment disambiguates ("for this client to be used in the User-Agent header"), but the constant name does not. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `USER_AGENT_PACKAGE_INFO` or `PACKAGE_USER_AGENT`. -- **Rationale:** Cross-package — same finding appears in every audited file. - -### 8. `HttpCallOptions` — `src/v1/utils.ts:15-19` -- **Code:** - ```ts - export interface HttpCallOptions { - readonly request: HttpRequest; - readonly httpClient: HttpClient; - readonly logger: Logger; - } - ``` -- **Why weird:** Word `Options` is reused throughout the SDK for unrelated concepts (`ClientOptions`, `CallOptions`, `Options` imported from `@databricks/sdk-core/api`). Within `utils.ts` this local interface name collides with the imported `Options` symbol on line 3. -- **Category:** 1 (vague suffix), 12 (duplicate `Options` naming). -- **Suggested name:** `HttpCallContext` (it is an internal context bag, not user-tunable options). - -### 9. `executeCall` vs `executeHttpCall` — near-duplicate function names — `src/v1/utils.ts:26`, `:65` -- **Code:** lines 26-38 and 65-94. -- **Why weird:** Two functions named almost identically, doing very different things: `executeCall` wraps in retry/rate-limit/timeout semantics, `executeHttpCall` does the raw HTTP send + decode + ApiError check. -- **Category:** 1 (vague), 17 (inconsistent layer naming). -- **Suggested name:** `runWithCallOptions` (the wrapper) and `sendHttpRequest` (the executor). - -### 10. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` +### 7. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -162,15 +125,12 @@ ## Observations -### 11. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +### 8. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). - **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. -### 12. `NEXT_CHANGELOG.md` and pre-existing build/lint workflows -Out of scope for naming but worth noting: the package has both a `CHANGELOG.md` and `NEXT_CHANGELOG.md` — the duplicate-file convention is a project-wide pattern, not a naming bug. - ## Domain glossary - `notification destination` — the persistent record being managed. Always paired with a `displayName` and one `Config`. - `channel` — implicit term-of-art for the kind of destination (Slack, Email, etc.). Not used in any identifier here; encoded as `DestinationType`. diff --git a/.agent/naming-audit/oauth.md b/.agent/naming-audit/oauth.md index de5c3cb3..bf6eec07 100644 --- a/.agent/naming-audit/oauth.md +++ b/.agent/naming-audit/oauth.md @@ -31,8 +31,8 @@ account-side complement to RFC 6749 client registration. | High | 1 | | Medium | 0 | | Low | 2 | -| Observation | 1 | -| **Total** | **3 (+ 1 observation)** | +| Observation | 0 | +| **Total** | **3** | The audit excludes the `OAuth*` brand-name spelling (RFC 6749 platform-name exception), `*_UNSPECIFIED` proto sentinels, `*_Response` proto-nested @@ -124,15 +124,7 @@ _None._ ## Observations (not flags) -### O1. `flattenQueryParams` exported but unused — `utils.ts:123` -- The helper is exported from `utils.ts` but the three list endpoints - in this package (`listCustomOAuthAppIntegrations`, - `listPublishedOAuthAppIntegrations`, `listPublishedOAuthApps`) all - use flat scalar query parameters (`pageToken`, `pageSize`, - `includeCreatorUsername`), so the helper is dead code in this - build. Same pattern in many sibling packages — either drop the - `export` here or lift the helper into `@databricks/sdk-core` so it - is not duplicated 93 times. +_None._ --- diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md index 9e697740..8ad2d907 100644 --- a/.agent/naming-audit/onlinetables.md +++ b/.agent/naming-audit/onlinetables.md @@ -75,12 +75,6 @@ - Private fields: `host`, `httpClient`, `logger`, `userAgent`. - Module constant: `PACKAGE_SEGMENT` (client.ts:34). -### Utils (utils.ts) - -- Interface: `HttpCallOptions`. -- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`. - ### Index (index.ts) - Re-exports `Client`, `CreateOnlineTableWaiter`, enum values, and 14 @@ -92,18 +86,39 @@ | Severity | Count | | --------------------- | ----- | -| High | 4 | -| Medium | 10 | -| Low / SDK-wide note | 9 | -| Pass / acceptable | 9 | +| High | 0 | +| Medium | 0 | +| Low / SDK-wide note | 0 | +| Pass / acceptable | 0 | | Fixed (post-regen) | 0 | -| **Total findings** | **31** | - -(Several findings touch multiple audit categories; counts above are unique -findings.) +| **Total findings** | **0** | Rescanned against the 2026-05-26 regeneration (#156): no findings were addressed by the regeneration — every previously open finding is still present in the current source. --- + +## High severity (must fix) + +_None._ + +--- + +## Medium severity (worth pushing back on) + +_None._ + +--- + +## Low severity (nits) + +_None._ + +--- + +## Observations (not flags) + +_None._ + +--- diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index f95f6de7..761608e1 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -83,7 +83,6 @@ The package defines no enums. | ----- | ---------------------------------------------------- | -------- | ----- | | V-01 | `PolicyFamily.name` (`model.ts:33`) | Low | Generic but standard for entity types; meaning is preserved by the parent type. | | V-02 | `PolicyFamily.description` (`model.ts:35`) | Low | Generic but standard across the SDK; acceptable. | -| V-03 | `flattenQueryParams` (`utils.ts:123`) | Low | Reasonable. | ### 2.2 Redundant enum prefixes — High @@ -93,10 +92,7 @@ The package defines no enums. ### 2.3 Acronym casing inconsistencies — High -| ID | Symbol | Severity | Issue | -| ----- | --------------------- | -------- | ----- | -| A-01 | `httpClient`, `HttpClient`, `HttpCallOptions`, `HttpRequest`, `HttpResponse`, `httpReq` | Low | `Http` (lowercased) follows Google TS style for acronyms ≥3 chars. Consistent with the rest of the SDK. | -| A-02 | `URLSearchParams` (local in `client.ts`) | Low | DOM API; uses uppercase `URL` because that is the platform-defined identifier. Acceptable. | +_None._ ### 2.4 Underscores in TS identifiers — High @@ -104,15 +100,7 @@ _None._ ### 2.5 Cryptic abbreviations — Medium -| ID | Symbol | Severity | Issue | -| ----- | ------------------------------------------------- | -------- | ----- | -| C-01 | `req`, `resp` (locals in `client.ts`) | Low | Inside method scope; OK for short-lived locals but `request` / `response` would be clearer at no cost. Used in every CRUD method. | -| C-02 | `httpReq` (local in `client.ts`) | Low | Short for "HTTP request". OK in local scope. | -| C-03 | `respBody` (local in `client.ts`) | Low | Short for "response body". OK in local scope. | -| C-04 | `pageReq` (local in `client.ts:133`) | Low | Short for "page request". OK. | -| C-05 | `opts` (`utils.ts` parameter, `executeHttpCall` and `executeCall`) | Low | Inside fn scope; minor. | -| C-06 | `pkgJson` (import in `client.ts:18`) | Low | Short for `packageJson`. Consistent with peer packages' codegen output. | -| C-07 | `acc` (local in `utils.ts:55` reduce callback) | Low | Standard reduce-accumulator name. OK. | +_None._ ### 2.6 Misleading names — High @@ -125,8 +113,7 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | O-01 | `policyFamilyId` (every occurrence) | Low | 14 chars but precise. Two `policyFamily*` fields would collapse to one once the type name (`PolicyFamily`) is in scope, but it remains unambiguous across the SDK and matches the upstream API field name. Accept. | -| O-02 | `PACKAGE_SEGMENT` (`client.ts:31`) | Low | OK in context. | -| O-03 | `ListPolicyFamiliesRequest_Response` (`model.ts:22`) | Medium | The `Request_Response` compound suffix is verbose — the proto-nested style yields a name where `Request` is carried into the response type even though the response is not a request. A flatter `ListPolicyFamiliesResponse` would self-describe. (Generator-level.) | +| O-02 | `ListPolicyFamiliesRequest_Response` (`model.ts:22`) | Medium | The `Request_Response` compound suffix is verbose — the proto-nested style yields a name where `Request` is carried into the response type even though the response is not a request. A flatter `ListPolicyFamiliesResponse` would self-describe. (Generator-level.) | ### 2.8 Singular / plural mismatches — Low @@ -160,15 +147,10 @@ _None._ | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | T-01 | `getPolicyFamily`, `listPolicyFamilies` | Low | Both imperative present-tense — consistent. | -| T-02 | `executeCall`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`, `readAll` | Low | All imperative present-tense — consistent. | ### 2.13 Go / Java-style names — Medium -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| G-01 | `HttpClient`, `HttpRequest`, `HttpResponse` | Low | Google TS style uses `Http` (lowercased acronym) — consistent. Not a Go-style violation. | -| G-02 | `executeCall`, `executeHttpCall` | Medium | The dual-naming (`Call` vs `HttpCall`) communicates the wrapping relationship in a Go-style "the inner one is HTTP-specific, the outer one is a generic retry/timeout decorator" idiom. Acceptable; common pattern in the Go SDK at `databricks/sdk-go/transport/`. | -| G-03 | `buildHttpRequest` | Low | "Build" is fine in TS; the naming is broadly used. | +_None._ ### 2.14 Generic field names losing meaning — Medium @@ -176,7 +158,6 @@ _None._ | ----- | ---------------------------------------------------- | -------- | ----- | | F-01 | `name` (on `PolicyFamily`) | Low | Universal noun; meaning is preserved through type context. OK. | | F-02 | `description` (on `PolicyFamily`) | Low | Same as F-01. | -| F-03 | `url`, `params`, `query`, `fullUrl`, `headers`, `body` (locals in `client.ts`) | Low | Locals only; standard naming. OK. | ### 2.15 Field contradicting type domain — Low @@ -210,7 +191,6 @@ _None._ | ----- | ---------------------------------------------------- | -------- | ----- | | TS-01 | `PolicyFamily` — does the `Family` suffix double up with `Policy`? | Low | `PolicyFamily` is the domain term used in the Databricks docs (cf. https://docs.databricks.com/en/admin/clusters/policy-families.html). The "Family" here means *grouping/template*, not a `*Family` type-suffix tautology. OK. | | TS-02 | `GetPolicyFamilyRequest`, `ListPolicyFamiliesRequest` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | -| TS-03 | `HttpCallOptions` (`utils.ts:15`) | Low | The `Options` suffix is a standard TS pattern (`fetch` accepts `RequestInit`, but `Options` is widespread). OK. | ### 2.20 Proto / architectural-leak naming — High @@ -226,15 +206,8 @@ _None._ | X-01 | `version` typed as `number` (`GetPolicyFamilyRequest.version`) | Low | The API contract uses an integer version. `number` is fine; flagged for completeness. No `bigint` is needed (versions won't exceed `Number.MAX_SAFE_INTEGER`). | | X-02 | `pageToken` / `nextPageToken` (cross-pagination field naming) | Low | Standard Databricks SDK pagination shape. The request-side cursor is `pageToken`, the response-side cursor is `nextPageToken` — consistent with `clusterpolicies`, `instancepools`, etc. OK. | | X-03 | `maxResults` (`ListPolicyFamiliesRequest.maxResults`) | Low | Standard pagination field name. OK. | -| X-04 | `Client.host` is mutated post-construction via `replace(/\/$/, '')` only at constructor entry | Low | Naming-wise neutral; not strictly a naming issue. The field name `host` (rather than `baseUrl` or `endpoint`) is consistent with peer packages. | -| X-05 | `Client.userAgent` (private) | Low | Standard naming; HTTP `User-Agent` is the wire-format identifier. OK. | -| X-06 | `executeCall` parameter `call: Call` | Low | The type `Call` is generic from `@databricks/sdk-core/api` and overloads the verb; readers may briefly wonder which "call" is meant (function callback vs. RPC call). Imported from the core package; flagged once. | -| X-07 | `callSignal` (local in `client.ts`) | Low | Distinct from `req.signal` / `options?.signal` — the qualifier `call` disambiguates. Good. | -| X-08 | `flattenQueryParams` (utils, exported) | Low | Exported but `client.ts` builds query strings manually with `URLSearchParams.append`. Either remove or use it. Not strictly a naming issue. | -| X-09 | `pageReq` (local in `client.ts:133`) | Low | Mutated per iteration. Naming reasonable; an alternative `nextRequest` reads slightly clearer. | -| X-10 | `index.ts:5` has `export {} from './model';` (empty re-export) | Low | The empty `export {}` is dead code emitted by codegen. Naming-neutral. Should be removed by codegen, not a per-package fix. | -| X-11 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | -| X-12 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-01. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | +| X-04 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | +| X-05 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-01. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | --- @@ -245,9 +218,9 @@ _None._ | Severity | Count | | -------- | ----- | | High | 2 | -| Medium | 5 | -| Low | 24 | -| **Total**| **31**| +| Medium | 3 | +| Low | 22 | +| **Total**| **27**| ### 3.2 Top themes diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index f4a67d70..2ea674cf 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -3,37 +3,31 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Catalog`s (Unity Catalog mirrors of logical PG databases), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Operation` waiter-style classes. -**Total weird names flagged:** 29 +**Total weird names flagged:** 28 ## Summary | Severity | Count | | --- | --- | -| High | 9 | +| High | 8 | | Medium | 15 | | Low | 4 | | Observation | 1 | ## High severity -### 1. Package name `postgres` does not say "Lakebase" / "autoscaling" / "managed-PG" — `packages/postgres/` -- **Why weird:** Generic single-word name for a Databricks-specific service. The actual product is "Lakebase Autoscaling Postgres" (see JSDoc `createProject`, `client.ts:339`). Sibling package `database` covers earlier-generation Lakebase (`DatabaseInstance` / V1), and `postgres` is V2 — see `database/naming-audit/database.md` finding #2. Neither package name says "Lakebase" or makes the V1/V2 lineage discoverable. -- **Category:** 1 (vague/generic), 12 (duplicate concept across packages). -- **Suggested name:** `lakebase` (and merge with `database`), or `lakebase-autoscaling`, or `lakebase-v2`. At minimum, add an `index.ts` JSDoc declaring "Lakebase Autoscaling Postgres (V2 OLTP)". -- **Rationale:** `postgres` is too broad — Databricks also has Postgres-backed services elsewhere (DBSQL, query history, etc.). Naming should encode the product. - -### 2. `postgres` and `database` packages overlap heavily — `packages/postgres/` vs `packages/database/` +### 1. `postgres` and `database` packages overlap heavily — `packages/postgres/` vs `packages/database/` - **Why weird:** Many duplicate type names remain across the two packages: `DeltaTableSyncInfo` (`model.ts:1169`), `SyncedTablePosition` (`model.ts:2012`), `SyncedTablePipelineProgress` (`model.ts:1996`), `NewPipelineSpec` (`model.ts:1544`), `DatabaseCredential` (`model.ts:1079`), `GenerateDatabaseCredentialRequest` (`model.ts:1361`), `RequestedClaims` (`model.ts:1750`), `RequestedResource` (`model.ts:1755`), `ProvisioningInfo` (`model.ts:1748`), `ProvisioningInfo_State`/`SyncedTableState`/`RequestedClaims_PermissionSet`. Identical signatures but exported from two packages — a TS user importing both gets noisy alias-juggling. - **Category:** 12 (duplicate concept across packages), 6 (misleading: same name, two definitions). - **Suggested name:** Pick one as canonical; the other re-exports from the canonical or marks itself deprecated. Cross-reference each shared type with a JSDoc note like "Equivalent to `database/v1.DeltaTableSyncInfo`; see go/lakebase-v2 for the migration." - **Rationale:** Same as `database` finding #2 — `postgres` is V2 and `database` is V1; nothing in the names says so. -### 3. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` +### 2. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` - **Why weird:** Huge enum (~100 entries) referenced exactly once via `DatabricksServiceExceptionWithDetailsProto.errorCode` (1091). Most entries are explicitly marked "NOTE: Deprecated and kept to maintain backwards compatibility for public APIs that use it, avoid using it in the new APIs" (e.g. `IO_ERROR`, `INVALID_STATE`, `UNPARSEABLE_HTTP_ERROR`, `QUOTA_EXCEEDED`, `MAX_BLOCK_SIZE_EXCEEDED`, `DRY_RUN_FAILED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, all the `GIT_*`, `IPYNB_FILE_IN_REPO`, `INSECURE_PARTNER_RESPONSE`, `METASTORE_*_EXISTS`, `CATALOG_NOT_EMPTY`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, etc. — at least 40 entries). The enum re-exports the entire Databricks-platform error vocabulary into a Postgres-specific SDK package. - **Category:** 7 (overly verbose), 11 (empty/trivial wrappers for deprecated values), 14 (Go/proto leak — all deprecated values exist only "for public APIs that use it"), 18 (long enum values). - **Suggested name:** Move `ErrorCode` to a shared `core/apierror` package (already exists per CLAUDE.md), drop deprecated values from the public TS surface (or mark them `@deprecated` so TS tooling can warn). - **Rationale:** Every consumer of this package gets a 100-entry deprecated-warning bundle. The fact that it's exported from `postgres/v1/index.ts` (line 30) means it's part of the public surface. -### 4. Three "State" enums share value vocabulary but use two different qualifier patterns — `src/v1/model.ts:581, 600, 610` +### 3. Three "State" enums share value vocabulary but use two different qualifier patterns — `src/v1/model.ts:581, 600, 610` - **Why weird:** Three state enums use two different qualifier patterns: - Branch state and endpoint state qualify by the status struct (`BranchStatus`-scoped, `EndpointStatus`-scoped). - Provisioning state lives under the unrelated `ProvisioningInfo` wrapper. @@ -42,31 +36,31 @@ - **Suggested name:** Standardise to `State`: `BranchState`, `EndpointState`, `ProvisioningState`. - **Rationale:** Three state enums with two naming conventions across one package. -### 5. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:1793-1795` +### 4. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:1793-1795` - **Why weird:** Three lowercase run-together field names. Doc comment (lines 1786-1789) acknowledges the choice ("The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words"). That's a wire-format justification (Postgres keywords). The TypeScript identifier should still be camelCase. `createrole` is especially confusing — could read as `createRole` (verb) or `creator_ole`. - **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS), 17 (inconsistent — every other field in the package is camelCase). - **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; wire stays `createdb`/`createrole`/`bypassrls`. - **Rationale:** Same finding as `database` audit #5 — both packages share this bug. -### 6. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:633, 638` +### 5. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:633, 638` - **Why weird:** Implementation details (SCRAM-SHA-256 mechanism, OAuth `_V1`) leak into the public enum. The `_V1` suffix begs the question: what happens at V2? Should the SDK consumer have to migrate from `LAKEBASE_OAUTH_V1` to `LAKEBASE_OAUTH_V2` when the wire format changes? Worse, the `SCRAM_SHA_256` qualifier is a specific hash function — consumers picking an auth method shouldn't have to know about hash schemes. - **Category:** 1 (vague at the wrong level — too specific), 6 (misleading: `LAKEBASE_OAUTH_V1` versioning leaks), 14 (Postgres/auth-spec internal naming), 18 (long enum values). - **Suggested name:** `Password` (replacing `PG_PASSWORD_SCRAM_SHA_256`) and `OAuth` (replacing `LAKEBASE_OAUTH_V1`). Keep `NoLogin`. Push the wire-protocol-specific names into the marshal layer. - **Rationale:** Public enums should describe the *concept* (password vs OAuth vs no-login), not the wire-protocol mechanism. -### 7. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1094` +### 6. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1094` - **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The type is reached via `Operation.result` (line 1588), making it the SDK's primary error surface. Every error consumer must cast. - **Category:** 1 (vague), 15 (generic), 16 (type contradicts domain — details have structure, just unmodelled). - **Suggested name:** Add typed discriminator: `details: ErrorDetail[]` with `ErrorDetail = ResourceInfo | RetryInfo | …` aligned to `google.rpc.Status`. - **Rationale:** Errors are the most-handled values in any SDK; opaque `unknown` arrays force every caller to write defensive code. -### 8. 21 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1512-3345` +### 7. 21 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1512-3345` - **Why weird:** The package exports 21 boilerplate poller classes (each ~80 lines, near-identical): `CreateBranchOperation`, `CreateCatalogOperation`, `CreateDatabaseOperation`, `CreateEndpointOperation`, `CreateProjectOperation`, `CreateRoleOperation`, `CreateSyncedTableOperation`, `DeleteBranchOperation`, `DeleteCatalogOperation`, `DeleteDatabaseOperation`, `DeleteEndpointOperation`, `DeleteProjectOperation`, `DeleteRoleOperation`, `DeleteSyncedTableOperation`, `UndeleteBranchOperation`, `UndeleteProjectOperation`, `UpdateBranchOperation`, `UpdateDatabaseOperation`, `UpdateEndpointOperation`, `UpdateProjectOperation`, `UpdateRoleOperation`. Each has identical `name()` / `metadata()` / `wait()` / `done()` methods, differing only in return type (`Branch` vs `Catalog` vs `Database` etc.). All 21 are exported from `index.ts:5-26`. - **Category:** 7 (overly verbose), 11 (trivial wrappers), 14 (Go-style poll-helper pattern), 17 (21-way redundancy). - **Suggested name:** Single generic `Operation` class with `wait(): Promise` and `metadata(): Promise`. Drop all 21 named exports; expose factory methods on `Client` like `createBranchOperation()` that return `Operation`. - **Rationale:** Comparable to `database/v1/client.ts`'s `CreateDatabaseInstanceWaiter` — but here the pattern is repeated 21 times. This bloats the bundle, the public surface, and the autocomplete list. -### 9. `DatabricksServiceExceptionWithDetailsProto` — proto-architectural-leak type name — `src/v1/model.ts:1090`, `index.ts:64` +### 8. `DatabricksServiceExceptionWithDetailsProto` — proto-architectural-leak type name — `src/v1/model.ts:1090`, `index.ts:64` - **Why weird:** The type name carries two architectural leaks in one identifier: mid-position `Service` (the server-side concept the message originates from) and a trailing `Proto` suffix (the wire-format origin). Neither term is part of the domain. The same name surfaces on `Operation.result.error` (line 1592), so every SDK consumer who inspects an `Operation` error encounters "ServiceException...Proto" jargon. `WithDetails` is also a hand-rolled qualifier that mirrors how proto messages get suffixed when extended; an idiomatic TS API would just call this `DatabricksError` and treat the detail array as part of the error itself. - **Category:** 14 (proto-architectural-leak — both `Service` mid and `Proto` suffix), 7 (overly verbose), 5 (5 stacked qualifiers — `Databricks` + `Service` + `Exception` + `WithDetails` + `Proto`). - **Suggested name:** `DatabricksApiError` (or `DatabricksError`, matching `@databricks/sdk-databricks/apierror` conventions in CLAUDE.md). Drop `Service`, `Proto`, and the `WithDetails` distinguisher; the type already carries `details` as a first-class field. @@ -74,7 +68,7 @@ ## Medium severity -### 10. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` — 7 generic top-level resource names — `src/v1/model.ts` (multiple) +### 9. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` — 7 generic top-level resource names — `src/v1/model.ts` (multiple) - **Why weird:** Most of these names are single-word generic English (`Branch`, `Catalog`, `Database`, `Endpoint`, `Project`, `Role`). Multiple are *already-taken* concepts in Databricks-land: - `Catalog` collides with Unity Catalog `Catalog` (in `catalogs` package) - `Database` collides with the `database` package's `DatabaseInstance` / `DatabaseCatalog` @@ -85,88 +79,88 @@ - **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). - **Rationale:** With 100+ packages in the workspace, single-word resource names guarantee collisions. -### 11. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:736-762` +### 10. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:736-762` - **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. - **Category:** 16 (type allows `false` but spec rejects it). - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 12. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` +### 11. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` - **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. - **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). - **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). - **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. -### 13. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` +### 12. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` - **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. - **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). - **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. - **Rationale:** Three identifier slots is too many. -### 14. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` +### 13. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` - **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. - **Category:** 5 (cryptic abbreviation), 1 (vague suffix). - **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. - **Rationale:** "CU" is Lakebase-internal slang. -### 15. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` -- **Why weird:** Same pattern as #11 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. -- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #11). +### 14. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` +- **Why weird:** Same pattern as #10 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. +- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #10). - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. -- **Rationale:** Same as #11. +- **Rationale:** Same as #10. -### 16. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #24 +### 15. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #23 _Reserved._ -### 17. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` +### 16. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` - **Why weird:** Plain `Record`. The 21 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1524-1533` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. - **Category:** 15 (generic), 16 (loose typing). - **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. -- **Rationale:** Same root cause as #7 — opaque records on the public surface. +- **Rationale:** Same root cause as #6 — opaque records on the public surface. -### 18. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` +### 17. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` - **Why weird:** Variant `response` carries `Record` (line 1597). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) - **Category:** 16 (asymmetric typing), 15 (generic on success arm). -- **Suggested name:** Same as #17 — generic `Operation` with both arms typed. -- **Rationale:** Same as #7, #17. +- **Suggested name:** Same as #16 — generic `Operation` with both arms typed. +- **Rationale:** Same as #6, #16. -### 19. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` +### 18. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` - **Why weird:** `Project` carries an `initialEndpointSpec` field that is a create-time-only input but exposed on the response type too — a read-flow consumer sees a field that is typically empty after project creation. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). - **Suggested name:** Hoist the `initialEndpointSpec` onto `CreateProjectRequest` only (where it belongs); leave `Project` to spec/status. - **Rationale:** Same as `database` audit #12 — input/output shape confusion. -### 20. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` +### 19. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` - **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. - **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). - **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. - **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. -### 21. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` +### 20. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` - **Why weird:** Doc says "The major Postgres version number. The set of supported versions may vary; consult the API documentation for currently accepted values." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. - **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). - **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. - **Rationale:** Aligns documented constraints with the type system. -### 22. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` +### 21. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` - **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. - **Category:** 17 (inconsistent with sister package). - **Suggested name:** Pick one convention across the two packages. - **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. -### 23. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` +### 22. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` - **Why weird:** Same as `database` audit #36: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. - **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). - **Suggested name:** `timeSeriesKey`. - **Rationale:** Same as `database` audit #36. -### 24. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` +### 23. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` - **Why weird:** Identical to `database` audit findings on synced-table-spec naming. Won't re-state at length; flag that the duplication exists across both packages with identical naming. Other related fields (`acceleratedSync`, `extraIndexDefinitions`, `extraColumnDefinitions`, `typeOverrides`) were removed during regeneration; only the `createDatabaseObjectsIfMissing` "If Missing" pattern remains here, matching `database` package's similar wording. - **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). - **Suggested name:** Same suggestions as `database` audit. - **Rationale:** Two SDKs, same problems. -### 25. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` +### 24. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` - **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. - **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). - **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. @@ -174,25 +168,25 @@ _Reserved._ ## Low severity -### 26. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` +### 25. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` - **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete now uses `purge: boolean` only (`allowMissing` field removed in regeneration). Mismatched conventions for "if it does/doesn't exist" remain. - **Category:** 17 (inconsistent action verbs across CRUD). - **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. - **Rationale:** Inconsistent options across CRUD operations is a small papercut. -### 27. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` +### 26. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` - **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete." Same `purge` field on `DeleteProjectRequest` (line 1142). - **Category:** 16 (boolean modeling a future 3-state field), 6 (misleading — purge implies cleanup, not the *only* delete mode). - **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. - **Rationale:** Boolean toggle for a future-3-state field. -### 28. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` +### 27. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` - **Why weird:** Same as `database` audit #54 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Same as `database` audit #54 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. - **Rationale:** Same as `database` audit #54. -### 29. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` +### 28. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` - **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1552`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. @@ -200,8 +194,8 @@ _Reserved._ ## Observation -### 30. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` -- **Why weird:** All 21 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#8) or reads `Operation.result.response` (untyped `Record`). +### 29. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` +- **Why weird:** All 21 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#7) or reads `Operation.result.response` (untyped `Record`). - **Category:** Observation (architecture, not naming per se). - **Suggested name:** `Operation` generic. -- **Rationale:** Connects #7, #8, #17, #18. +- **Rationale:** Connects #6, #7, #16, #17. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index b97cffc5..8cfbe3aa 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -332,8 +332,6 @@ Observations: 3. **Top-level type pollution.** `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRange`, `DateRangeValue`, `MultiValuesOptions`, `Visualization` are all unprefixed and exported. A user importing `import { TextValue } from '@databricks/sdk-queries'` gets a generically-named type that competes with their own code. -4. **`utils.ts` is well-named and unchanged.** Exports (`executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`) are domain-neutral and not flagged. `flattenQueryParams` is exported but unused in `client.ts` (orphaned export) — not a naming issue, but worth noting. - ## Domain glossary | Term | Meaning in this package | diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index 6daca860..5f55cedb 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,15 +3,15 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 25 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 2 | -| Medium | 12 | -| Low | 11 | -| Observation | 3 | +| Medium | 8 | +| Low | 5 | +| Observation | 1 | ## High severity @@ -59,42 +59,18 @@ - **Suggested name:** Pick one convention across the package and apply it uniformly. - **Rationale:** Cross-enum consistency. The proto3 zero-value member must exist on every enum, but the spelling of that member (`UNKNOWN` vs `UNSPECIFIED`) should be consistent across the package. -### 8. `QueryStatementType.OTHER` — vague catch-all — `src/v1/model.ts:30` -- **Why weird:** `OTHER` is a vague catch-all value within an otherwise specific enum of SQL statement keywords (`SELECT`, `INSERT`, ...). A caller seeing `statementType === 'OTHER'` has no way to recover what the statement actually was. -- **Category:** 1 (vague) -- **Suggested name:** Keep `OTHER` (no good alternative) but document the value to explain when the runtime emits it. -- **Rationale:** Without documentation the value is opaque; documenting it removes most of the surprise. - -### 9. `QueryStatus.CANCELED` — spelling and verb-tense — `src/v1/model.ts:82` -- **Why weird:** `CANCELED` (single-l, US) where most JavaScript ecosystems use `cancelled` (double-l) and at minimum should be consistent with the rest of the codebase. More importantly: every other `QueryStatus` value is a past participle (`QUEUED`, `STARTED`, `COMPILED`, `FAILED`, `FINISHED`) or `-ING` (`COMPILING`, `RUNNING`). `CANCELED` fits the past-participle pattern — flag only for spelling. -- **Category:** 13 (verb-tense — minor) plus orthographic -- **Suggested name:** Keep `CANCELED` if that matches the wire (and project-wide policy); flag for cross-package consistency. -- **Rationale:** The W3C HTML spec uses `cancelled`; Node.js, the DOM, and most npm packages use `canceled`. The wire form here is `"CANCELED"`, so the TS surface should match. Just record the choice. - -### 10. `QueryStatus.STARTED` and `COMPILED` — deprecated but exported — `src/v1/model.ts:65,75` -- **Why weird:** Both enum values are documented as `DEPRECATED: to be removed once runtime side change is picked up.` Yet they're exported in `index.ts` (since `QueryStatus` is) and have no JSDoc `@deprecated` tag. IDE autocomplete will offer them indistinguishably from current values. -- **Category:** 11 (effectively dead) plus tooling concern -- **Suggested name:** No rename. Add `@deprecated` JSDoc on each so IDEs show the strikethrough and the doc surfaces in tooltips. -- **Rationale:** TypeScript honors `@deprecated` in completions; the current comment is informational only. - -### 11. `QueryInfo.executionEndTimeMs` vs `queryEndTimeMs` — domain confusion — `src/v1/model.ts:195,197` -- **Why weird:** Two `*End*Ms` fields next to each other. The doc comments are: `The time execution of the query ended.` (executionEndTimeMs) and `The time the query ended.` (queryEndTimeMs). Are these different? When? The metrics type later splits time into `compilationTimeMs`, `executionTimeMs`, `resultFetchTimeMs` — so plausibly "execution end" is after spark execution but before fetch, while "query end" is after fetch. The TS types do not encode this. A reader has to guess. -- **Category:** 1, 6, 19 (vague; misleading; underspecified time field) -- **Suggested name:** Keep both names but rewrite the docs to spell out the relationship and the relative ordering (`queryStartTimeMs ≤ executionEndTimeMs ≤ queryEndTimeMs`). Optionally rename to `executionEndTimeMs` / `resultsDeliveredTimeMs`. -- **Rationale:** This is the kind of field that turns into a billing/SLA bug if confused. The audit is naming-only, but the names *here* are the source of the confusion. - -### 12. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` +### 8. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` - **Why weird:** Cross-reference of #2: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). - **Category:** 19, 16 (underspecified ID; field contradicting type domain) - **Suggested name:** See #2. -### 13. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` +### 9. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` - **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. - **Category:** 15, 19 (generic field; underspecified ID) - **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. - **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. -### 14. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` +### 10. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` - **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. - **Category:** 12, 1 (duplicate concepts; vague) - **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. @@ -102,70 +78,34 @@ ## Low severity -### 15. `ExternalQuerySource.dashboardId` vs `legacyDashboardId` — `src/v1/model.ts:99,101` -- **Why weird:** Two dashboard-related ID fields on the same type. `legacyDashboardId` implies pre-Lakeview dashboards (the JSDoc on `dashboardId` is "this Lakeview dashboard"). Both can be set simultaneously? The semantics are not encoded — should be a discriminated union (`{ kind: 'lakeview', id } | { kind: 'legacy', id }`). -- **Category:** 12, 19 (duplicate concept; underspecified) -- **Suggested name:** Keep the names; consider a `kind` discriminator. At minimum, document the mutual exclusivity. -- **Rationale:** Documentation fix more than naming. - -### 16. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` +### 11. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` - **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. - **Category:** 19 (underspecified) - **Suggested name:** As above — convert to discriminated union. - **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. -### 17. `ExternalQuerySource_JobInfo.jobTaskRunId` — — `src/v1/model.ts:120` -- **Why weird:** Three IDs on one type: `jobId`, `jobRunId`, `jobTaskRunId`. The naming is consistent and self-documenting. `jobTaskRunId` (one identifier for "task run within a job run") could be ambiguous: is it the run-ID of a *task* (with `jobRunId` being the run-ID of the whole job), or vice versa? The doc says `The canonical identifier of the task run.` — confirms the former. -- **Category:** 19 (underspecified) -- **Suggested name:** Acceptable; if confusion arises, rename to `taskRunIdWithinJobRun`. -- **Rationale:** Documentation is sufficient. - -### 18. `QueryMetrics.totalTimeMs` vs `executionTimeMs` vs `taskTotalTimeMs` vs `photonTotalTimeMs` — — `src/v1/model.ts:261,269,279,285` -- **Why weird:** Four time fields; the relationship is `totalTime ≥ compilationTime + executionTime + resultFetchTime` (roughly), and `executionTime` aggregates `taskTotalTime` and `photonTotalTime`. The names don't encode the hierarchy; a developer must read all four docs to understand. Individually each name is OK. -- **Category:** 1 (vague — collectively) -- **Suggested name:** Keep, but add a JSDoc on `QueryMetrics` summarizing the hierarchy. -- **Rationale:** Documentation > rename. - -### 19. `QueryMetrics.workToBeDone` — phrase as field name — `src/v1/model.ts:319` -- **Why weird:** Phrase rather than a noun. Doc says "remaining work to be done... deprecated: using projected_remaining_task_total_time_ms instead". So this is a deprecated field with a name that reads like English prose ("work to be done") rather than a TS identifier. Reads awkwardly: `metrics.workToBeDone`. -- **Category:** 7, 14 (verbose; Go/Java-style phrase) -- **Suggested name:** Already deprecated. If kept for back-compat, that's fine. New consumers should use `projectedRemainingTaskTotalTimeMs`. -- **Rationale:** Will be removed; flag for awareness only. - -### 20. `QueryMetrics.runnableTasks` — — `src/v1/model.ts:324` -- **Why weird:** Doc says `number of remaining tasks to complete, calculated by autoscaler StatementAnalysis.scala. deprecated: use remaining_task_count instead`. So `runnableTasks` actually means "remaining tasks" — name and meaning don't align. Also deprecated. -- **Category:** 6, 1 (misleading; vague) -- **Suggested name:** Deprecated. Use `remainingTaskCount`. Flag for awareness. -- **Rationale:** Same as #19. - -### 21. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` +### 12. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` - **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. - **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) - **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. - **Rationale:** Same value reachable through two paths is a maintenance hazard. -### 22. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` +### 13. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` - **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. - **Category:** 1 (vague — `Entry`) - **Suggested name:** Optional rename to domain names. - **Rationale:** Marginal. -### 23. `QueryFilter.statuses` doc — recommends against using it — `src/v1/model.ts:170` -- **Why weird:** Doc says `Filtering for multiple statuses is not recommended. Instead, opt to filter by a single status multiple times and then combine the results.` This is a behaviour quirk; field name is fine. Flag for documentation polish. -- **Category:** observation -- **Suggested name:** Keep `statuses`; document why multi-filter is discouraged on the type, not just on the field. -- **Rationale:** Surfaces the constraint. - -### 24. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` +### 14. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` - **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. - **Category:** 1 (vague) - **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. - **Rationale:** Minor. -### 25. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` +### 15. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` - **Why weird:** `Legacy` is a temporal/architectural modifier mid-name — it tags the identifier as belonging to the *old* product (pre-Lakeview dashboards). The "legacy" label only has meaning inside Databricks' product roadmap; SDK consumers who don't know that Databricks shipped a new dashboard product see "legacy" as architectural noise. Names like `Legacy`/`Modern`/`Old`/`New` mid-position bake a release-timeline distinction into the public type surface; once a third dashboard product ships, the name becomes a lie. - **Category:** proto-architectural-leak (`Legacy` mid-position temporal modifier) -- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #15. +- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #11. - **Rationale:** Replace the temporal modifier with the actual product name. The Go SDK keeps `legacy_dashboard_id` because of wire-format back-compat; the TS surface can rename without breaking the wire transform. ## Observations @@ -173,12 +113,6 @@ ### O1. `Client` is the only exported class — `src/v1/client.ts:32` - The class is just `Client`. Consistent across the SDK (so a project-level concern), but worth noting that `import { Client } from '@databricks/sdk-queryhistory/v1'` produces a bare name that collides with every other package's `Client`. Consumers must rename on import. -### O2. `flattenQueryParams` exported but only used internally — `src/v1/utils.ts:123` -- `flattenQueryParams` is `export`ed from `utils.ts`, used in `client.ts`, and not re-exported from `index.ts`. Module-private would suffice, but the helper has to be cross-file. This is a generated-code pattern; flag at the generator level. (Identical to #15 in the `accountaccesscontrol` audit, suggesting this is package-wide.) - -### O3. `executeCall` and `executeHttpCall` — overlapping verb pair — `src/v1/utils.ts:26,65` -- Two functions, similar names, different purposes. `executeCall` is the public-`CallOptions` adapter; `executeHttpCall` is the wire-level executor. Names don't signal that one wraps the other. Could be `applyCallOptions` + `sendHttpRequest`. Generated-code concern. (See also the `accountaccesscontrol` audit O2.) - ## Cross-cutting themes 1. **The `Info` / `State` suffix habit.** `QueryInfo`, `ChannelInfo`, `PlansState` — bare-noun renames (`Query`, `Channel`, `PlanStorageStatus`) would be cleaner. `Info` is a category-1 vague suffix doing no work. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index fa731fa4..a517b60f 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -59,17 +59,6 @@ standalone), but for `runWorkspaceId` it lowercases `Id` correctly. The issue is that `metastoreId`, `id`, and `runId` are all lowercase, while `URI` appears nowhere as a field name. -#### 3.2 `MLflow` in doc comments (model.ts:222-223, 335-336) -Doc comments spell it `MLflow` (correct trademark casing). No identifier -exists for MLflow here, but if one were added, follow the trademark -casing (`Mlflow*` would be wrong). - -#### 3.3 `` placeholder leakage (model.ts:227, 340) -JSDoc contains the literal token `` — clearly an -unresolved template marker from the upstream generator. It will render -poorly in IDE tooltips. Not a naming issue per se, but visible in the -audit surface; documentation hygiene. - --- ### 4. Cryptic abbreviations @@ -173,11 +162,7 @@ collision worse. ### 11. Verb tense / parallel inconsistency -#### 11.1 `nextPageToken` versus `pageToken` (model.ts:152, 164, 197, 207) -Request types use `pageToken`; response types use `nextPageToken`. This -asymmetry is conventional for cursored pagination, but the convention -should be documented somewhere (it isn't, here). Not a defect, but -flagged because it is a common reader stumbling block. +_None._ --- @@ -198,12 +183,7 @@ SDK pattern leaking into TS. ### 13. Underspecified IDs -#### 13.1 `RegisteredModelInfo.metastoreId` (model.ts:287) and `ModelVersionInfo.metastoreId` (model.ts:245) -"The unique identifier of the metastore". Acceptable name but worth -flagging that the format (UUID? slug?) is not specified anywhere in -the doc. - -#### 13.2 `ModelVersionInfo.runWorkspaceId` (model.ts:230) +#### 13.1 `ModelVersionInfo.runWorkspaceId` (model.ts:230) `number` typed. The doc says "ID of the Databricks workspace". Workspace IDs in Databricks are 64-bit integers — TS `number` is only safe up to 2^53. This is a *type* concern, but the name `runWorkspaceId` does not @@ -313,14 +293,7 @@ parallel `modelregistry` package which uses bare `RegisteredModel` / ## Cross-cutting observations -### A. Doc-comment typos - -Two instances of `recieve` (sic) in `client.ts:356` and `client.ts:429`, -both in `listModelVersions` and `listRegisteredModels` JSDoc. Not a -naming issue but visible in IDE tooltips alongside every flagged -identifier. - -### B. Parallel package collision risk +### A. Parallel package collision risk A consumer that imports both `modelregistry` and `registeredmodels` will encounter colliding identifiers for: `ModelVersionStatus`, @@ -330,7 +303,7 @@ encounter colliding identifiers for: `ModelVersionStatus`, Importing both *requires* aliasing on every single one of those names. This is the biggest practical naming defect of the package. -### C. Request shapes leak response/server fields +### B. Request shapes leak response/server fields `CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, and especially `UpdateModelVersionRequest` carry the entire response shape @@ -345,13 +318,12 @@ meaningless). See §15. 1. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, `RegisteredModelAliasInfo`. (§7.1, §16.1) 2. **Disambiguate parallel-package collisions** with `modelregistry` — - either re-namespace or rename types. (§10, §B) + either re-namespace or rename types. (§10, §A) 3. **Strip server-populated fields** from `CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, `UpdateModelVersionRequest` request - shapes. (§15, §C) + shapes. (§15, §B) 4. **Rename `MODEL_VERSION_STATUS_UNKNOWN`** to `MODEL_VERSION_STATUS_UNSPECIFIED` for consistency with the rest of the SDK's zero-value enum members. (§2.1) -5. **Fix `recieve` typos** in client.ts JSDoc. (§A) --- diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index 34faff5a..2b707968 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -14,7 +14,7 @@ even though the product was rebranded to "Git folders". One resource type (`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, `SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set `provider` values appearing in JSDoc on five fields. -**Total weird names flagged:** 21 (21 still applicable, 0 newly fixed in regeneration on 2026-05-26) +**Total weird names flagged:** 15 (15 still applicable, 0 newly fixed in regeneration on 2026-05-26) --- @@ -32,17 +32,11 @@ even though the product was rebranded to "Git folders". One resource type | 8 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` wire values (in JSDoc) | model.ts:9-13, 37-39, 72-75, 119-121 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Same as `gitcredentials` audit #13. Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (lower-case G at the boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" TS field-name convention. Values dictated by the API server. | | 9 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | | 10 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | -| 11 | `awsCodeCommit` wire value (deprecated, untagged) | model.ts:13, 40, 76, 122 | enum-like wire value | Low | 6 Misleading names | JSDoc says "deprecated by AWS, not accepting new customers" — but the value is still exported and accepted by the API. No `@deprecated` JSDoc tag on the values or the model. Same as `gitcredentials` audit #16. | -| 12 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | -| 13 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:253-259 vs 287-293 — duplicated marshal logic). One is used in `CreateRepoRequest`/responses; the other only in `UpdateRepoRequest`. The shapes have no semantic difference. Should be one type. | -| 14 | `SparseCheckout.patterns` doc verbiage | model.ts:132, 142 | comment | Low | (none) | "Sparse checkout configuration, it contains options like cone patterns." reads awkwardly (comma splice; "it contains options like cone patterns" reads as natural-language but the `patterns` field is *the only* field — there are no "options like cone patterns", there is *exactly* the cone patterns). Should be "Sparse checkout configuration." or "Sparse checkout configuration. The `patterns` array specifies cone-mode patterns." | -| 15 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | -| 16 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 133, 161, 215, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | -| 17 | `executeCall` vs `executeHttpCall` | utils.ts:26, 65 | function pair | Medium | 17 Inconsistent action verbs, 1 Vague/generic | Two `execute*` functions with overlapping vocabulary. `executeCall` translates options and dispatches via the retry/rate-limit executor; `executeHttpCall` does one HTTP round-trip. Same complaint as the `credentials`, `gitcredentials`, and `accountaccesscontrolproxy` audits — repeated boilerplate. | -| 18 | `buildHttpRequest` action verb mixed with `executeHttpCall` | utils.ts:96, 65 | function pair | Low | 17 Inconsistent action verbs | The `*HttpRequest`/`*HttpCall` vocabulary is mixed: `buildHttpRequest` builds a *request* object; `executeHttpCall` makes the *call*. "Call" and "Request" are used interchangeably. | -| 19 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 137, 219 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | -| 20 | `RepoInfo.path` doc says "Root path" but `CreateRepoRequest.path` and other `path` docs say "Path" | model.ts:115 vs 20, 33, 68 | field | Low | 6 Misleading names | `RepoInfo.path` doc: "Root path of the git folder (repo) in the Workspace." The same field on `CreateRepoRequest` / `GetRepoRequest` says just "Path of the Git folder (repo) in the workspace." Different qualifiers ("root path" vs "path"), different casing ("Workspace" vs "workspace"). Inconsistency within the same model file. | -| 21 | `RepoInfo` doc casing inconsistency: "git folder" vs "Git folder" | model.ts:110, 112, 114, 116, 118, 124, 126, 128 | doc | Low | (none) | Within `RepoInfo` alone, the JSDoc uses both "Git folder" (sentence-start, capitalized) and "git folder" (mid-sentence, lowercase). Same for "Workspace" vs "workspace". The other types consistently say "Git folder (repo)" with capital G. Generator-introduced text inconsistency. | +| 11 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 12 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:253-259 vs 287-293 — duplicated marshal logic). One is used in `CreateRepoRequest`/responses; the other only in `UpdateRepoRequest`. The shapes have no semantic difference. Should be one type. | +| 13 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | +| 14 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 133, 161, 215, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | +| 15 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 137, 219 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | --- @@ -245,21 +239,7 @@ interface UpdateRepoRequest { This is a wire-compatible rename; the zod transform can flatten back to `{branch, tag}` on the way out. -### M3. `executeCall` / `executeHttpCall` (overlapping vocabulary) - -`utils.ts` exposes: - -- `executeCall(call, options)` -- `executeHttpCall(opts)` -- `buildHttpRequest(method, url, headers, signal?, body?)` - -The `execute*` pair (`executeCall` wraps the retry/rate-limit executor; -`executeHttpCall` is a single HTTP round-trip) has been flagged in every -audit so far. The `*HttpRequest`/`*HttpCall` vocabulary is also mixed — -"Call" and "Request" used interchangeably across `buildHttpRequest` and -`executeHttpCall`. - -### M4. `req.id ?? ''` URL-builder bug-shape +### M3. `req.id ?? ''` URL-builder bug-shape ```ts const url = `${this.host}/api/2.0/repos/${String(req.id ?? '')}`; @@ -275,39 +255,7 @@ throw before issuing the call. The pattern repeats in ## Low severity (style polish) -### L1. `awsCodeCommit` is documented as deprecated but not tagged - -The JSDoc on `provider` says "`awsCodeCommit` (deprecated by AWS, not -accepting new customers)". But the model has no `@deprecated` tag on -either the field's documentation or on a typed enum value (which doesn't -exist — see H4). Callers cannot programmatically detect deprecated values. -See #11. - -### L2. `SparseCheckout` doc has a comma splice - -```ts -/** Sparse checkout configuration, it contains options like cone patterns. */ -``` - -"Sparse checkout configuration, it contains options like cone patterns." -— "configuration, it contains" is a comma splice (independent clauses -joined by a comma). Should be "Sparse checkout configuration." or -"Sparse checkout configuration. The `patterns` array specifies cone-mode -patterns." See #14. - -### L3. `RepoInfo` doc text inconsistencies - -"Git folder" vs "git folder" within `RepoInfo` (model.ts:110, 112, 114, -116, 118, 124, 126, 128). "Workspace" vs "workspace". Generator-introduced -text inconsistency. See #21. - -### L4. `RepoInfo.path` doc says "Root path"; the other `path` docs say "Path" - -The `RepoInfo` interface describes `path` as "Root path of the git folder -(repo) in the Workspace." The same field on `CreateRepoRequest` / -`GetRepoRequest` says "Path of the Git folder (repo) in the workspace." -Different qualifier ("root path" vs "path"), different casing -("Workspace" vs "workspace"). Generator-introduced. See #20. +_None._ --- @@ -343,7 +291,6 @@ method name (`deleteProject`) and the *TS-side* request type | Bare `Client` class | Yes (H7) | Yes (H7) | Yes (#10) | | Three identical resource/response shapes | Yes (H3: `RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | | `string`-typed enum-domain field (`provider`) | Yes (H4) | Yes (H6 — same field!) | No (uses real enums) | -| `executeCall` / `executeHttpCall` vocabulary clash | Yes (M3) | Yes (#31) | Yes (#55) | | `host` field stores a URL | Removed | Yes (#36) | Common | | Plural/singular mismatch | Removed | Severe (H2 — plural request type for singular op) | Mixed | | Legacy-name leak | **Yes (H2 — `DeleteProjectRequest*` on a "repos" client)** | No | No | diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 8fecb192..469dfae7 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -14,9 +14,9 @@ Notation: file paths are absolute. Findings reference `file:line`. | ----------- | ----- | | High | 2 | | Medium | 1 | -| Low | 5 | -| Observation | 4 | -| **Total** | **12** | +| Low | 2 | +| Observation | 1 | +| **Total** | **6** | Headline themes: @@ -54,7 +54,7 @@ Headline themes: - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `interface QuotaInfo`. - **Suggestion:** `Quota`. -- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O2. +- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O1. --- @@ -76,30 +76,6 @@ Headline themes: - **Suggestion:** `ResourceQuotasClient` (or a re-export of `Client as ResourceQuotasClient`). - **Rationale:** TS imports often need disambiguation: `import {Client} from '@databricks/sdk-resourcequotas/v1'` forces aliasing on any consumer that uses multiple packages. Repo-wide convention, see `catalogs.md` §14.2. -### L3. `call` local variable shadows the imported `Call` type - -- **File / line:** `src/v1/client.ts:73` (`const call: Call = …`); `client.ts:113` (same). -- **Category:** #1 vague/generic; #10 type/identifier shadowing. -- **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. -- **Suggestion:** `httpCall` or `doRequest`. -- **Rationale:** `call` collides with `Function.prototype.call` and with the imported `Call` type from `@databricks/sdk-core/api`. The expression `await executeCall(call, options)` reads as "execute call call options" — three uses of the verb in one line. Repo-wide port-style convention. - -### L4. `resp` local variable + `respBody` shadowed concept - -- **File / line:** `src/v1/client.ts:72, 77, 82, 112, 117, 122`. -- **Category:** #1 vague/generic. -- **Current:** `let resp: GetQuotaRequest_Response | undefined`, `const respBody = …`. -- **Suggestion:** `response`, `responseBytes` / `responseBody`. -- **Rationale:** Same JS-vs-Go shorthand issue as L1. `respBody` is a `Uint8Array` (bytes), not a parsed body — the name promises the parsed thing. - -### L5. `pkgJson` constant name - -- **File / line:** `src/v1/client.ts:18`. -- **Category:** #5 cryptic abbreviation. -- **Current:** `import pkgJson from '../../package.json' …`. -- **Suggestion:** `packageJson` or `manifest`. -- **Rationale:** Minor and internal; the `Json` part is obvious from the import target. Listed because the file is small enough to track every identifier. Repo-wide. - --- ## Observations (repo-wide conventions, not local defects) @@ -108,21 +84,6 @@ Headline themes: `QuotaInfo` mirrors `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo`. If the codebase decides to drop the `Info` suffix, this is one of many. -### O2. `URL` constants are inlined - -- **File / line:** `src/v1/client.ts:71, 102`. -- **Observation:** `${this.host}/api/2.1/unity-catalog/resource-quotas/...` appears in both methods without a named constant. Not a naming defect, but typical audits flag unnamed magic strings. - -### O3. `PACKAGE_SEGMENT.key` computed via regex from `pkgJson.name` - -- **File / line:** `src/v1/client.ts:32-35`. -- **Observation:** `key: pkgJson.name.replace(/^@[^/]+\//, '')` strips the `@databricks/` org prefix. The constant name `PACKAGE_SEGMENT` is OK but the `key`/`value` shape is generic — readers don't immediately know `key="resourcequotas"` and `value=version`. Cosmetic. Identical to `artifactallowlists.md` O7. - -### O4. `flattenQueryParams` is exported but unused in this package - -- **File / line:** `src/v1/utils.ts:123`. -- **Observation:** Both `getQuota` (`client.ts:71`) and `listQuota` (`client.ts:102-111`) build URLs/query strings inline. The `flattenQueryParams` helper is dead code from the package's standpoint. Same finding as `catalogs.md` cross-cutting §A and `artifactallowlists.md` L5 — repo-wide template artifact. - --- ## Domain glossary @@ -174,12 +135,10 @@ Type & symbol checklist: - [x] `QuotaInfo.lastRefreshedAt` → no defect. - [x] `Client` class → L2. - [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O3. - [x] `getQuota(req, options)` method → L1. -- [x] `listQuota(req, options)` method → H1, L1, L3, L4. +- [x] `listQuota(req, options)` method → H1, L1. - [x] `listQuotaIter(req, options)` paginator method → H1, L1. - [x] `HttpCallOptions` interface → no defect. -- [x] `flattenQueryParams` function → O4 (unused). - [x] `index.ts` re-exports → no defects; mirrors model exports faithfully. --- @@ -205,15 +164,9 @@ Type & symbol checklist: | `QuotaInfo.quotaLimit` | model.ts:70 | — | | `QuotaInfo.lastRefreshedAt` | model.ts:72 | — | | `Client` (bare name) | client.ts:37 | L2 | -| `PACKAGE_SEGMENT` | client.ts:32 | O3 | -| `pkgJson` import alias | client.ts:18 | L5 | | `Client.getQuota` parameter `req` | client.ts:68 | L1 | | `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | | `Client.listQuotaIter` (singular paginator method) | client.ts:131-146 | H1, L1 | -| `const call: Call` | client.ts:73, 113 | L3 | -| `let resp: …_Response` | client.ts:72, 112 | L4 | -| `const respBody` | client.ts:77, 117 | L4 | -| `flattenQueryParams` | utils.ts:123 | O4 | --- @@ -221,9 +174,7 @@ Type & symbol checklist: 1. **Rename `listQuota` → `listQuotas`** — single-character defect, highest user impact. (H1) 2. **Reconcile `parentSecurableType` type — make `GetQuotaRequest.parentSecurableType: SecurableType`.** (H2) -3. **Document counts on `quotaCount`/`quotaLimit`.** (M2) -4. **Fix the `__page_token__` reference in `nextPageToken` doc to use the camelCase TS field.** (M3) -5. **Drop `Info` suffix on `QuotaInfo`.** (M1, O2) -6. **Spell out `req` → `request` (repo-wide policy).** (L1) +3. **Drop `Info` suffix on `QuotaInfo`.** (M1, O1) +4. **Spell out `req` → `request` (repo-wide policy).** (L1) --- diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index 18e60b12..070eed42 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -3,15 +3,15 @@ **Path:** `packages/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 29 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 11 | -| Low | 8 | -| Observation | 5 | +| High | 4 | +| Medium | 9 | +| Low | 1 | +| Observation | 2 | ## High severity @@ -27,13 +27,7 @@ - **Suggested name:** Rename `URL` to `URL_NOTIFICATION` or `PLAIN_URL`, or rename `GENERIC_WEBHOOK` to clarify what makes it "generic" relative to `URL`. Document the wire-level difference between the two. - **Rationale:** Two enum members for "send to a URL" is a discoverability bug. Future callers will guess one and silently get the wrong webhook semantics. -### 3. `Securable.fullName` doc says "catalog/schema/table" but reality is broader — `model.ts:162-165` -- **Why weird:** The doc comment for `fullName` reads "The full name of the catalog/schema/table". But the `type` field's enum `SecurableType` supports 17 different securables: CATALOG, SCHEMA, TABLE, STORAGE_CREDENTIAL, EXTERNAL_LOCATION, FUNCTION, SHARE, PROVIDER, RECIPIENT, CLEAN_ROOM, METASTORE, PIPELINE, VOLUME, CONNECTION, CREDENTIAL, EXTERNAL_METADATA, STAGING_TABLE. The doc is misleading by selective enumeration — implies the field is only for three securable types. -- **Category:** 6 (misleading doc on a name-bearing field). -- **Suggested name:** Keep field name; fix doc to say "The full name of the securable, e.g. `catalog.schema.table` for a table, `catalog.schema.view` for a view, etc." -- **Rationale:** Name itself is fine; the documentation undermines the field's apparent applicability. - -### 4. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` +### 3. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` - **Why weird:** `AccessRequestDestinations` has both: - `securable?: Securable` (which has `type` and `fullName`), and - top-level `securableType?: string` and `fullName?: string`. @@ -45,7 +39,7 @@ - **Suggested name:** Drop `securableType` and `fullName` from `AccessRequestDestinations` for non-Terraform callers; expose them under a `terraformShim` namespace if needed, or model with `Pick`/conditional types. Wire stays unchanged. - **Rationale:** Two-field duplication invites bugs (a caller might set one and not the other). The "necessary for Terraform integration" rationale is exactly the kind of generator artefact that should not surface here. -### 5. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` +### 4. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` - **Why weird:** The request type for `getAccessRequestDestinations` has `securableType?: string`, but the response type `AccessRequestDestinations` has `securable?: { type?: SecurableType }` — a typed enum. So the request is untyped string, while the response is enum. A caller writing `req.securableType = 'catalogue'` (typo or wrong case) gets no compile-time error. - **Category:** 16 (field type contradicts domain — should be `SecurableType`), 6 (misleading — looks like free text but server demands an enum value). - **Suggested name:** Keep name, change type to `SecurableType`. @@ -53,67 +47,55 @@ ## Medium severity -### 6. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` +### 5. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` - **Why weird:** The type is plural (`Destinations`) but each instance describes the destinations *for one securable* (`securable?: Securable`, singular). The plural belongs only to the inner `destinations?: NotificationDestination[]` array. Compare: `AccessRequestDestination` (singular) would describe one route; `AccessRequestDestinations` (plural) implies multiple route configs. The current name is the latter but holds the former. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `AccessRequestRouting` or `AccessRequestDestinationConfig` (singular) — captures "the routing configuration for one securable". - **Rationale:** The pluralization is for the inner array, not the outer concept. Today the type-name reader gets the wrong mental model. -### 7. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` +### 6. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` - **Why weird:** Verbose type names (32 / 33 chars). `Batch` + `Create` + `AccessRequests` + `Request`/`Response`. Also: `Batch` prefix is the *only* signal that the endpoint accepts an array — but the client method is just `batchCreateAccessRequests`, and the field inside is `requests?: CreateAccessRequest[]`. Three levels of "batchness". - **Category:** 7 (overly verbose), 8 (redundant suffix `Request`). - **Suggested name:** `CreateAccessRequestsRequest` (drop `Batch`; the plural already implies batching). Or even better: `CreateAccessRequestsInput` / `CreateAccessRequestsOutput`. Pair with method `createAccessRequests`. - **Rationale:** `Batch` doubles as marketing copy ("look, batched!") rather than naming. TS plural-`s` already says "multiple". -### 8. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` +### 7. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` - **Why weird:** `CreateAccessRequest` has `securablePermissions?: SecurablePermissions[]` (plural array, type `SecurablePermissions` itself plural). `SecurablePermissions` holds `securable: Securable` (singular) and `permissions: string[]` (plural). So `request.securablePermissions[0].securable` reads as "the singular securable inside the plural securable-permissions". The type name `SecurablePermissions` doesn't say "pairs of securable + permissions list". - **Category:** 9 (singular/plural mismatch), 1 (vague — what does `SecurablePermissions` model?). - **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). Field becomes `securablePermissionRequests?: SecurablePermissionRequest[]` — long but readable. - **Rationale:** The type-name pluralization is hiding what the type actually models (one securable + a permissions list). -### 9. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` +### 8. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` - **Why weird:** A single `NotificationDestination` has both `destinationType?: DestinationType` and `specialDestination?: SpecialDestination`. The doc says `specialDestination`'s `destination_type` is "always EMAIL". So we have two enums that *cannot both be expressive at once* — if `specialDestination` is set, `destinationType` is constrained to `EMAIL`. The type system doesn't enforce this. - **Category:** 12 (duplicate concept — two enums encode overlapping info), 6 (misleading — looks like independent fields). - **Suggested name:** Either (a) collapse: extend `DestinationType` with new members and drop `SpecialDestination`; or (b) model as a discriminated union: `{ kind: 'normal'; destinationType, destinationId } | { kind: 'special'; specialDestination }`. - **Rationale:** Two parallel enums for a constrained relationship is exactly the kind of latent-bug field name pair that a strict type system can prevent. -### 10. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` +### 9. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` - **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape is fine, but the bare `id` doesn't communicate "the meaning depends on `principalType`". - **Category:** 19 (underspecified ID), 1 (vague). - **Suggested name:** Keep `id` paired with `principalType`, OR (more aggressive) make the type a discriminated union: `{ kind: 'user'; userId: string } | { kind: 'group'; groupId: string } | { kind: 'service'; servicePrincipalId: string }`. - **Rationale:** Tagged unions express the constraint at the type level. The current shape is a Go-port idiom. -### 11. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` +### 10. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` - **Why weird:** Enum value pinned by inline TODO: `/** TODO: [UC-2980] Staging tables aren't full-fleged securables yet. */`. The TODO leaks an internal JIRA ticket (`UC-2980`) and the typo "full-fleged" into the public SDK surface. The presence of the value tells callers it works; the comment tells them it doesn't. - **Category:** 18 (questionable enum value). - **Suggested name:** Either hide until promotion (`@experimental`), or remove the inline TODO and document the constraint in the doc-comment proper. - **Rationale:** Public SDK enums shouldn't carry internal JIRA references. Same pattern as `connections#29` and `dataclassification`. -### 12. `SecurableType.EXTERNAL_METADATA` lacks doc — `model.ts:40` -- **Why weird:** `EXTERNAL_METADATA` is undocumented. Neighbouring `STAGING_TABLE` carries a TODO/comment, but `EXTERNAL_METADATA` doesn't even say what it is. Unity Catalog has `externalmetadata` as its own package (`packages/externalmetadata/`), but this RFA enum member exists in isolation. -- **Category:** 1 (vague; no doc disambiguating). -- **Suggested name:** Keep name; add doc comment. -- **Rationale:** Naming OK, but undocumented enum members in a 17-element enum mean readers must cross-reference to other packages. - -### 13. `Principal` is exported but `principalType` field has no doc — `model.ts:148` -- **Why weird:** `principalType?: PrincipalType | undefined` has no JSDoc. Sibling `id` has a doc. The PrincipalType enum has only an `_UNSPECIFIED` sentinel + three values, none of which clarify when each applies. Caller has to guess by inspecting the IAM service. -- **Category:** 1 (vague). -- **Suggested name:** Keep name; add doc. -- **Rationale:** Mechanical. - -### 14. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` +### 11. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` - **Why weird:** `permissions` is `string[]` rather than an enum. Doc says "List of requested Unity Catalog permissions" — UC permissions are a known closed set (`SELECT`, `MODIFY`, `USAGE`, `READ_VOLUME`, etc.), so this should be a typed enum or branded string. Bare `string[]` loses any compile-time guard against typos. - **Category:** 16 (field type contradicts domain — should be enum or branded string). - **Suggested name:** Keep name; type as `UnityCatalogPermission[]` (new enum). Or document the closed set inline. -- **Rationale:** Same problem as #5. The wire is string, but TS could narrow it. +- **Rationale:** Same problem as #4. The wire is string, but TS could narrow it. -### 15. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` +### 12. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` - **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. - **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). - **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). - **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. -### 16. Three Client methods, three different domain entity names — `client.ts:74,113,147` +### 13. Three Client methods, three different domain entity names — `client.ts:74,113,147` - **Why weird:** `Client.batchCreateAccessRequests` works on `requests`. `Client.getAccessRequestDestinations` works on `destinations`. `Client.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. - **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). - **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). @@ -121,74 +103,20 @@ ## Low severity -### 17. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` -- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site. -- **Category:** 1 (vague), 17. -- **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. -- **Rationale:** Same as `connections#40`. - -### 18. `HttpCallOptions` — `utils.ts:15` -- **Why weird:** Yet another `Options` suffix; the file imports `Options` from `@databricks/sdk-core/api` and `CallOptions` from `@databricks/sdk-options/call`. Three `Options` types in scope. `HttpCallOptions` is internal — purely a context bag for `executeHttpCall`. -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). -- **Rationale:** Same as `connections#41`. - -### 19. `readAll` — `utils.ts:40` -- **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `readStreamToEnd` / `drainStream`. -- **Rationale:** Same as `connections#38`. - -### 20. `flattenQueryParams` — `utils.ts:123` -- **Why weird:** Exported but unused in this package (`client.ts` builds query strings inline with `URLSearchParams.append`). Dead-looking export. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Remove from utils if it's a generator default. -- **Rationale:** Generator emits the same helper into every package even when unused. Same as `connections#37`. - -### 21. `PACKAGE_SEGMENT` constant — `client.ts:35` -- **Why weird:** `Segment` is a generic word; without the comment the constant doesn't communicate User-Agent identity. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Same as `connections#36`. - -### 22. `Client` class — `client.ts:40` +### 14. `Client` class — `client.ts:40` - **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). - **Category:** 1 (vague). - **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). - **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. -### 23. `buildHttpRequest` parameter list — `utils.ts:96-102` -- **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. The function name `buildHttpRequest` doesn't communicate the parameter order; callers in `client.ts:87,122,166` pass them positionally. Easy to confuse `signal` and `body` (both optional, both at the end). -- **Category:** 1 (vague — five-positional builder). -- **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. -- **Rationale:** Five-positional builders without object syntax are an anti-pattern in modern TS. - -### 24. Loose typing for `executeCall(call, options)` `Options` field copying — `utils.ts:30-37` -- **Why weird:** The `Options` shape is built with a series of `...(options?.foo !== undefined && {foo: options.foo})` spreads. The pattern is a TS-idiom for conditional spread of optional fields. Naming-wise: the local `opts` variable is intentionally one letter shorter than `options` to disambiguate — but the shadowing convention isn't documented. -- **Category:** Observation. -- **Suggested name:** Rename inner `opts` → `internalOptions` (or the outer parameter to `callOptions`). -- **Rationale:** Mechanical. - ## Observations -### 25. `index.ts` is exhaustive but doesn't re-export schemas — `index.ts:1-24` -The index file exports the `Client`, all four enums, and all nine model interfaces (`AccessRequestDestinations`, `BatchCreateAccessRequestsRequest`, `BatchCreateAccessRequestsResponse`, `CreateAccessRequest`, `CreateAccessRequestResponse`, `GetAccessRequestDestinationsRequest`, `NotificationDestination`, `Principal`, `Securable`, `SecurablePermissions`, `UpdateAccessRequestDestinationsRequest`). It does *not* export the `marshal*`/`unmarshal*` schemas or the `accessRequestDestinationsFieldMask` helper. Consistent with the other packages but means the field-mask helper isn't available to consumers. -- **Category:** Observation. - -### 26. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +### 15. Comment-tag inconsistency — `client.ts:78,117,151` vs URL The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. - **Category:** Observation. -### 27. No tests in the package -`package.json` line 24-25: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. The package ships untested. Not a naming issue, but cross-package noise — same as several other newly generated packages. -- **Category:** Observation. - -### 28. Action-verb conventions on `Client` -`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #16). -- **Category:** Observation. - -### 29. `package.json` description is empty string — `package.json:4` -`"description": ""`. The npm package has no public description string. Combined with the cryptic `rfa` name (see #1), this leaves users with no metadata to identify the package's purpose when browsing npm. +### 16. Action-verb conventions on `Client` +`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #13). - **Category:** Observation. ## Domain glossary @@ -202,7 +130,7 @@ The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the pac - **`Principal`** — Unity Catalog/IAM term for "an entity that can hold permissions": a user, a group, or a service principal. The `PrincipalType` enum disambiguates which kind. Used here as the "on behalf of" actor in `CreateAccessRequest`. - **`SpecialDestination`** — five enum members denoting "the owner of the metastore/catalog/external-location/connection/credential" as an implicit email destination. These cannot be assigned; they're a default fallback. - **`FieldMask`** — Google protobuf convention (re-used in Databricks API) for sparse-field updates in PATCH semantics. `accessRequestDestinationsFieldMask(...)` builds the wire-format paths. -- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #4). +- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #3). ## File coverage - `src/v1/model.ts` (385 lines): read fully. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index 3e0ef80c..46b05ac4 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -48,15 +48,7 @@ key. TypeScript callers have no need for this distinction — the field *is* the schema identifier and should just be `fullName` (or `name`). Even worse: `UpdateSchemaRequest` has *both* `fullNameArg` (path) and `fullName` (body) on the same type, with no obvious difference in -semantics. See §11.1. - -#### 3.2 `pkgJson` (client.ts:19) -Variable name `pkgJson` for `package.json` import. Mostly internal — -minor — but worth noting for consistency. - -#### 3.3 `req`, `resp`, `opts` (client.ts and utils.ts throughout) -Internal abbreviations. Conventional, but worth flagging for the -broader audit. +semantics. See §10.1. --- @@ -113,7 +105,7 @@ collision before landing. #### 6.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) The whole type *is* the flag; the suffix is redundant. See §5.1. -#### 6.3 `Arg` suffix on `fullNameArg` — see §3.1 and §11.1. +#### 6.3 `Arg` suffix on `fullNameArg` — see §3.1 and §10.1. --- @@ -155,7 +147,7 @@ Mirror issue in `CreateSchemaRequest` (model.ts:17, 31) and The `UpdateSchemaRequest` has **both** `fullNameArg` (the existing schema identifier, path param) and `fullName` (the same field name on the body) — plus `newName` for renaming. Three fields all touching -the schema's identity. See §11.1. +the schema's identity. See §10.1. #### 8.4 `CatalogType` is re-implemented across packages The exact `CatalogType` enum is defined here @@ -192,33 +184,13 @@ will be surprised to find that system schemas live elsewhere. #### 9.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. -#### 9.2 `executeCall`, `executeHttpCall`, `buildHttpRequest`, `readAll`, `flattenQueryParams` (utils.ts) — all imperative present, consistent. - No verb-tense inconsistencies found across the package. --- -### 10. Go / Java-style names - -#### 10.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) -Java/Go style. TS convention is to drop it. See §6.1. - -#### 10.2 `Client` class name (client.ts:44) -Bare `Client` (rather than `SchemasClient`) is a Go-idiom: package -qualifies the type. JS consumers commonly import as -`import {Client} from '@databricks/sdk-schemas/v1'` and have to alias. -Package-wide convention; flagged for the broader review. - -#### 10.3 `fullNameArg` — Go-generator naming. See §3.1. - -#### 10.4 `package_segment` / `PACKAGE_SEGMENT` (client.ts:39) -Constant naming is fine; flagged for completeness. - ---- - -### 11. Field contradicting type domain +### 10. Field contradicting type domain -#### 11.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 198, 182) +#### 10.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 198, 182) Four name-bearing fields on a single update request: - `fullNameArg` — existing schema identifier (path param). @@ -232,7 +204,7 @@ identifying the existing schema; the others are vestigial in the update context.) This is the single most user-hostile naming pattern in the package — and it sits on the most-used mutation method. -#### 11.2 `CreateSchemaRequest` contains read-only output fields (model.ts:32-50) +#### 10.2 `CreateSchemaRequest` contains read-only output fields (model.ts:32-50) `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `catalogType`, `effectivePredictiveOptimizationFlag`, `schemaId`, `browseOnly`. These are server-populated; a creator @@ -240,14 +212,14 @@ setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Same mirror issue in `UpdateSchemaRequest` (model.ts:199-217). -#### 11.3 `DeleteSchemaRequest.fullNameArg` — see §3.1. +#### 10.3 `DeleteSchemaRequest.fullNameArg` — see §3.1. -#### 11.4 `GetSchemaRequest.fullNameArg` (model.ts:90) -Same as 11.3. +#### 10.4 `GetSchemaRequest.fullNameArg` (model.ts:90) +Same as 10.3. --- -### 12. Inconsistent action verbs +### 11. Inconsistent action verbs Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`. Verbs are consistent — standard CRUD. @@ -255,42 +227,57 @@ No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- -### 13. Underspecified IDs +### 12. Underspecified IDs -#### 13.1 `schemaId` (model.ts:48, 157, 215) +#### 12.1 `schemaId` (model.ts:48, 157, 215) "The unique identifier of the schema." No format hint (UUID?). The field exists alongside `fullName` (which is also a unique identifier in a different sense). Two simultaneous IDs without disambiguation. -#### 13.2 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) +#### 12.2 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) Both `string`. `inheritedFromType` could be one of the UC securable types, but the field is not enum-typed. `inheritedFromName` is opaque text. --- -### 14. Type-suffix tautology +### 13. Type-suffix tautology -#### 14.1 `CatalogType` enum with field `catalogType: CatalogType` +#### 13.1 `CatalogType` enum with field `catalogType: CatalogType` (model.ts:6, 41, 150, 208) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 14.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. +#### 13.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. --- -### 15. Generic field names losing meaning +### 14. Generic field names losing meaning -#### 15.1 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §4.3, §8.1. +#### 14.1 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §4.3, §8.1. --- -### 16. Singular / plural mismatches +### 15. Singular / plural mismatches _None._ --- +### 16. Go / Java-style names + +#### 16.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +Java/Go style. TS convention is to drop it. See §6.1. + +#### 16.2 `Client` class name (client.ts:44) +Bare `Client` (rather than `SchemasClient`) is a Go-idiom: package +qualifies the type. JS consumers commonly import as +`import {Client} from '@databricks/sdk-schemas/v1'` and have to alias. +Package-wide convention; flagged for the broader review. + +#### 16.3 `fullNameArg` — Go-generator naming. See §3.1. + +--- + ### 17. Proto-architectural-leak naming #### 17.1 `EffectivePredictiveOptimizationFlag` — `Flag` wrapper suffix (model.ts:79) @@ -322,27 +309,7 @@ _None._ ## Additional / cross-cutting observations -### A. `flattenQueryParams` is defined but unused (utils.ts:123) -Each `listSchemas` / `getSchema` / `deleteSchema` handler builds query -strings inline with `URLSearchParams.append` (client.ts:107-110, -144-147, 185-197). The exported helper `flattenQueryParams` is never -referenced by `client.ts`. Either it's intentionally exported for -consumer use (then it should be documented and reside in `utils` -proper) or it's dead code. Same pattern as `catalogs` package. - -### B. `fullNameArg` URL substitution silently allows empty string (client.ts:106, 143, 248) -`${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL -silently becomes `/api/2.1/unity-catalog/schemas/` and the request -will fail on the server. The naming (`fullNameArg`) and the -substitution behaviour together hide what should be a required -parameter. The type marks it `string | undefined` even though it is -operationally required. - -### C. `Client` constructor throws bare `Error` for missing `host` (client.ts:55) -"Host is required." — bare `Error`. Not a naming issue, flagged in -passing for the broader review. - -### D. The package name is plural; the entity types are singular +### A. The package name is plural; the entity types are singular The package is `schemas` (plural); the model types are `Schema` (well, `SchemaInfo` — singular). The five client methods mix: `createSchema`/`deleteSchema`/`getSchema`/`updateSchema` (singular — @@ -350,21 +317,13 @@ they act on one) and `listSchemas` (plural — returns many). This is the same pattern as `catalogs`, `tables`, etc. — consistent across the SDK. -### E. `SchemaInfo`'s "Next ID: 45" comment (model.ts:123) -The doc comment is a leftover proto field-number management note. It -has no consumer-facing meaning. Should be stripped on the way to TS. - -### F. Doc comment for `effectivePredictiveOptimizationFlag` is missing (model.ts:44-46, 153-155, 211-213) -The field has no JSDoc, even though the type has a doc. Three -occurrences. Consistency: every other field has a doc comment. - -### G. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) +### B. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) The field name says "enable" — suggesting boolean — but the type is `string`. The actual value is presumably `'ENABLE' | 'DISABLE' | 'INHERIT'` or similar. The name lies about the type. See also §4.1 for the related `EffectivePredictiveOptimizationFlag.value`. -### H. Overlap with `systemschemas` package — see §8.7 +### C. Overlap with `systemschemas` package — see §8.7 A consumer reading "schemas" reasonably expects to find all schema operations here. They will not find `disableSystemSchema`, `enableSystemSchema`, or `listSystemSchemas` — those live in @@ -377,54 +336,50 @@ upstream API surface, but the seam is non-obvious to discover. | Identifier | Location | Finding | | ----------------------------------------------------------- | --------------------- | -------------------- | -| `CatalogType` | model.ts:6 | 8.4, 14.1 | -| `CreateSchemaRequest` | model.ts:15 | 8.6, 11.2 | +| `CatalogType` | model.ts:6 | 8.4, 13.1 | +| `CreateSchemaRequest` | model.ts:15 | 8.6, 10.2 | | `CreateSchemaRequest.name` | model.ts:17 | 8.2 | -| `CreateSchemaRequest.catalogType` | model.ts:41 | 14.1 | -| `CreateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:44 | 5.1, 17.2, F | -| `CreateSchemaRequest.properties` / `.options` | model.ts:52, 54 | 4.3, 7.1, 8.1, 15.1 | -| `DeleteSchemaRequest` | model.ts:69 | 11.3 | -| `DeleteSchemaRequest.fullNameArg` | model.ts:71 | 3.1, 10.3, 11.3, B | -| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 5.1, 6.2, 10.1, 17.1 | +| `CreateSchemaRequest.catalogType` | model.ts:41 | 13.1 | +| `CreateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:44 | 5.1, 17.2 | +| `CreateSchemaRequest.properties` / `.options` | model.ts:52, 54 | 4.3, 7.1, 8.1, 14.1 | +| `DeleteSchemaRequest` | model.ts:69 | 10.3 | +| `DeleteSchemaRequest.fullNameArg` | model.ts:71 | 3.1, 10.3, 16.3 | +| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 5.1, 6.2, 16.1, 17.1 | | `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 4.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 13.3 | -| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 13.3 | -| `GetSchemaRequest.fullNameArg` | model.ts:90 | 3.1, 10.3, 11.4, B | +| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 12.2 | +| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 12.2 | +| `GetSchemaRequest.fullNameArg` | model.ts:90 | 3.1, 10.4, 16.3 | | `ListSchemasRequest` | model.ts:95 | — | | `ListSchemasRequest.maxResults` | model.ts:105 | — | | `ListSchemasRequest.pageToken` | model.ts:107 | — | | `ListSchemasRequest.includeBrowse` | model.ts:109 | — | -| `SchemaInfo` | model.ts:124 | 6.1, 8.6, 10.1, E | +| `SchemaInfo` | model.ts:124 | 6.1, 8.6, 16.1 | | `SchemaInfo.name` | model.ts:126 | 8.2 | | `SchemaInfo.fullName` | model.ts:140 | 4.2, 8.2 | -| `SchemaInfo.catalogType` | model.ts:150 | 14.1 | -| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 5.1, 17.2, F | -| `SchemaInfo.schemaId` | model.ts:157 | 13.2 | -| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 4.3, 7.1, 8.1, 15.1 | -| `UpdateSchemaRequest` | model.ts:178 | 8.3, 8.6, 11.1, 11.2 | -| `UpdateSchemaRequest.fullNameArg` | model.ts:180 | 3.1, 8.3, 10.3, 11.1, B | -| `UpdateSchemaRequest.newName` | model.ts:182 | 11.1 | -| `UpdateSchemaRequest.name` | model.ts:184 | 8.2, 11.1 | -| `UpdateSchemaRequest.fullName` | model.ts:198 | 8.2, 8.3, 11.1 | -| `UpdateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:211 | 5.1, 17.2, F | -| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | G | -| `Client` (bare name) | client.ts:44 | 10.2 | -| `${req.fullNameArg ?? ''}` URL substitution | client.ts:106, 143, 248 | B | -| `flattenQueryParams` (unused export) | utils.ts:123 | A | -| Cross-package overlap with `systemschemas` | (package boundary) | 8.7, H | +| `SchemaInfo.catalogType` | model.ts:150 | 13.1 | +| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 5.1, 17.2 | +| `SchemaInfo.schemaId` | model.ts:157 | 12.1 | +| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 4.3, 7.1, 8.1, 14.1 | +| `UpdateSchemaRequest` | model.ts:178 | 8.3, 8.6, 10.1, 10.2 | +| `UpdateSchemaRequest.fullNameArg` | model.ts:180 | 3.1, 8.3, 10.1, 16.3 | +| `UpdateSchemaRequest.newName` | model.ts:182 | 10.1 | +| `UpdateSchemaRequest.name` | model.ts:184 | 8.2, 10.1 | +| `UpdateSchemaRequest.fullName` | model.ts:198 | 8.2, 8.3, 10.1 | +| `UpdateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:211 | 5.1, 17.2 | +| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | B | +| `Client` (bare name) | client.ts:44 | 16.2 | +| Cross-package overlap with `systemschemas` | (package boundary) | 8.7, C | --- ## Recommended priority order -1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchemaRequest`** — four name-like fields on the same request, the worst user-facing trap in the package. (§11.1, §3.1, §8.3) +1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchemaRequest`** — four name-like fields on the same request, the worst user-facing trap in the package. (§10.1, §3.1, §8.3) 2. **Distinguish or merge `options` and `properties`.** (§8.1, §4.3) -3. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§4.1, G) -4. **Strip read-only fields from `CreateSchemaRequest`/`UpdateSchemaRequest`.** (§11.2) -5. **Either document or remove the unused `flattenQueryParams` export.** (Cross-cutting A) -6. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§13.2, §8.2) -7. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§6.1) -8. **Strip the `Next ID: 45` leftover from `SchemaInfo` JSDoc.** (E) -9. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§8.7, H) +3. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§4.1, B) +4. **Strip read-only fields from `CreateSchemaRequest`/`UpdateSchemaRequest`.** (§10.2) +5. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§12.1, §8.2) +6. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§6.1) +7. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§8.7, C) --- diff --git a/.agent/naming-audit/scim.md b/.agent/naming-audit/scim.md index c7d54b87..45f9a0fd 100644 --- a/.agent/naming-audit/scim.md +++ b/.agent/naming-audit/scim.md @@ -3,14 +3,14 @@ **Path:** `packages/scim/src/v1/` **Versions audited:** v1 **Inferred domain:** SCIM (System for Cross-domain Identity Management, RFC 7644) — workspace and account user, service principal, and group provisioning, plus password permissions. `SCIM` itself is an industry-standard protocol acronym and is treated as a domain word. -**Total weird names flagged:** 13 +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 4 | -| Low | 2 | +| High | 4 | +| Medium | 3 | +| Low | 1 | | Observation | 2 | ## High severity @@ -39,33 +39,21 @@ - **Suggested name:** Drop the per-type `Schema` enums; type the field as a const string union (`type GroupSchema = "urn:ietf:params:scim:schemas:core:2.0:Group"`) or hide it entirely behind the marshaller (the client knows which URNs to send). The `_UNSPECIFIED` zero values should disappear. - **Rationale:** The enum wraps a single literal URN per type — a `const` is simpler and matches what the spec actually says. The `_UNSPECIFIED` zero is a proto3 default-value artifact with no SCIM meaning. -### 5. `Resources` PascalCase wire field surfaces in unmarshaller — `src/v1/model.ts:1096,1111,1128,1143,1160,1178` -- **Why weird:** Every list-response unmarshaller declares the wire field as `Resources` (capital R), e.g. `Resources: z.array(...)`, then transforms to `resources` (camelCase) in the output. The capital-`R` form is the proto-generated JSON name for a field whose proto name was `resources` and whose `json_name` annotation was set to `Resources`. It then leaks into the Zod schema as the literal wire key. While not a public-facing type name, it documents a proto-convention divergence (proto `lower_snake` → JSON `Resources`) baked into the generator that has no SCIM-spec justification. -- **Category:** Proto-architecture leak -- **Suggested name:** The wire field name is fixed by SCIM (which uses `Resources` with capital R, per RFC 7644 §3.4.2); this one is technically correct. Flag for verification rather than rename: ensure the JSDoc on `*Response.resources` says "SCIM lists this as `Resources` on the wire (RFC 7644 §3.4.2)" so the casing is not assumed to be a bug. -- **Rationale:** Distinguishes spec-mandated quirk from proto artifact; the visual similarity to a generator leak warrants a comment. - ## Medium severity -### 6. `Operations` PascalCase wire key in marshal output — `src/v1/model.ts:1576,1591,1604,1617,1629,1641` -- **Why weird:** Every patch-request marshaller transforms `operations` (camelCase TS) to `Operations` (PascalCase wire). Same shape as finding 5, but on the outbound side. Per RFC 7644 §3.5.2, the SCIM patch wire field is `Operations` (capital O), so this is spec-mandated. Flag for the same reason: it looks like a proto-RPC leak but is actually SCIM. -- **Category:** Proto-architecture leak -- **Suggested name:** No rename. Add a comment in the marshallers explaining the capital `Operations` is from RFC 7644 §3.5.2. -- **Rationale:** Audit-trail clarity. Without the comment, a reader cleaning up "obvious" proto leftovers might lowercase this and break the wire. - -### 7. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:583` +### 5. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:583` - **Why weird:** The list-response type is `ListServicePrincipalResponse` (singular `ServicePrincipal`) while the request type is `ListServicePrincipalsRequest` (plural). Compare to `ListAccountServicePrincipalsResponse` (plural) on line 510. The singular form on a list response reads as a proto message-name copy where the inner message is `ServicePrincipal` and the outer wraps it — i.e., proto's habit of letting the inner singular name dominate. - **Category:** Proto-architecture leak - **Suggested name:** `ListServicePrincipalsResponse`. - **Rationale:** Symmetry with sibling types and with the request name; the current singular is a generator artifact. -### 8. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:34,143,715` +### 6. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:34,143,715` - **Why weird:** `PatchOp` is the enum of patch operation kinds (`ADD`/`REMOVE`/`REPLACE`); `Patch.op` is the field that holds one. The TS field is `op` of type `PatchOp` (or `AccountPatchOp_PatchOp` for the account variant), so the enum has `Op` baked into its own name *and* the field is `op` — `Patch.op: PatchOp` is a type-suffix tautology and `AccountPatchOp_PatchOp` is the worst-case version of finding 1. - **Category:** Proto-architecture leak - **Suggested name:** Rename the enum to `PatchOperation` (or just inline as a string literal union `"ADD" | "REMOVE" | "REPLACE"`); keep the field `op`. - **Rationale:** `Op` is a proto shorthand for "operation"; the TS type name should spell it out, and the `_PatchOp` re-suffix should vanish. -### 9. Sentinel `*_UNSPECIFIED` enum values — `src/v1/model.ts:18,24,29,35,42,47,52,59,66,74,82,88,96` +### 7. Sentinel `*_UNSPECIFIED` enum values — `src/v1/model.ts:18,24,29,35,42,47,52,59,66,74,82,88,96` - **Why weird:** Every enum carries an `_UNSPECIFIED` zero value: `GET_SORT_ORDER_UNSPECIFIED`, `GROUP_SCHEMA_UNSPECIFIED`, `LIST_RESPONSE_SCHEMA_UNSPECIFIED`, `PATCH_OP_UNSPECIFIED`, `PATCH_SCHEMA_UNSPECIFIED`, `SERVICE_PRINCIPAL_SCHEMA_UNSPECIFIED`, `USER_SCHEMA_UNSPECIFIED`, `ORDER_UNSPECIFIED`, `LEVEL_UNSPECIFIED`, and copies under each `Account*` variant. The `*_UNSPECIFIED` zero is a proto3 default-value convention with no semantic meaning in TS, where an enum field can simply be optional. - **Category:** Proto-architecture leak - **Suggested name:** Drop the `_UNSPECIFIED` variants. Express absence as `undefined` (the fields are already optional). @@ -73,22 +61,16 @@ ## Low severity -### 10. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:652` +### 8. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:652` - **Why weird:** Not a proto leak per se, but the `Me` segment in `MeRequest` is a proto-style shorthand: SCIM defines `GET /Users/me` as the "current user" endpoint, and the proto generator turned `Me` into a type prefix instead of using a verb. `MeRequest` reads as "a Me-shaped request" — the request *to* the `me` endpoint would be `GetCurrentUserRequest` or `GetMeRequest`. - **Category:** Proto-architecture leak - **Suggested name:** `GetCurrentUserRequest` (and rename `client.me()` to `getCurrentUser()`); or `GetMeRequest` if the URL slug is preserved. - **Rationale:** Pronouns are not normally type prefixes in TS; this is the proto RPC name leaking through. -### 11. `unmarshal*Schema` / `marshal*Schema` exported helpers — `src/v1/model.ts:934-1791` -- **Why weird:** Each (un)marshaller is exported as `unmarshalSchema` / `marshalSchema`. The `Schema` suffix here refers to the *Zod schema* used to parse, but in a SCIM package the word `Schema` already means a SCIM resource schema URN (see findings 4 and the `GroupSchema`/`UserSchema` enums). Two unrelated meanings of `Schema` in the same module are easy to confuse on read. -- **Category:** Proto-architecture leak -- **Suggested name:** Either drop the `Schema` suffix (e.g. `unmarshalUser`/`marshalUser`) or rename to `unmarshalUserCodec`/`marshalUserCodec`. The conflict is a generator-template choice that ignored the domain vocabulary. -- **Rationale:** Disambiguate the two `Schema` namespaces in one file. - ## Observations ### O1. `eslint-disable` density as a signal — `src/v1/model.ts:57,64,72,80,86,94,108,131,150,153,403,411,618` -- The file carries 13 inline `eslint-disable-next-line` comments, all for `@typescript-eslint/naming-convention` (proto-nested enum names) or `@typescript-eslint/no-empty-object-type` (empty proto messages). Every disable corresponds to a proto-architecture artifact — taken together, they form a precise list of the proto-shaped pieces the linter wanted to flag and the generator decided to suppress. Removing the underlying patterns (findings 1, 2, 8) would also remove every disable in this file. +- The file carries 13 inline `eslint-disable-next-line` comments, all for `@typescript-eslint/naming-convention` (proto-nested enum names) or `@typescript-eslint/no-empty-object-type` (empty proto messages). Every disable corresponds to a proto-architecture artifact — taken together, they form a precise list of the proto-shaped pieces the linter wanted to flag and the generator decided to suppress. Removing the underlying patterns (findings 1, 2, 6) would also remove every disable in this file. ### O2. Workspace and account API split at type level, not namespace — package vs siblings - Sibling packages `accountusers`, `accountgroups`, etc. exist for account-scope IAM at higher levels of the SDK; this package interleaves both scopes (`createUser` vs `createAccountUser`, `listGroups` vs `listAccountGroups`) on a single `Client`. The naming convention is mid-position `Account` (finding 3), which is a proto-package-name leak. A consumer who only wants workspace SCIM still sees every account method in IDE autocomplete. diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index 80b46007..4eb62c9f 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -21,9 +21,9 @@ Notation: file paths are relative to the package root. Findings reference | ----------- | ----- | | High | 3 | | Medium | 5 | -| Low | 4 | -| Observation | 4 | -| **Total** | **16** | +| Low | 0 | +| Observation | 3 | +| **Total** | **11** | Headline themes: @@ -217,41 +217,7 @@ Headline themes: ## Low Severity -### L1. `unmarshalAclItemSchema` parses `permission: z.enum(AclPermission)` without strictness - -- **File / line:** `src/v1/model.ts:208`. -- **Category:** observation; not a naming defect strictly, but worth noting. -- **Issue:** `z.enum(AclPermission)` accepts the *string values* of the - enum (`'READ' | 'WRITE' | 'MANAGE'`). If the server adds a new permission - level, zod will throw at decode. Not a name issue, just notable. - -### L2. `flattenQueryParams` is dead code in this package - -- **File / line:** `src/v1/utils.ts:123`. -- **Category:** #21 dead code. -- **Issue:** function defined but not imported in `client.ts`. The client - builds query strings inline (`client.ts:316-323, :379-386, :434-438, - :534-538`). Same defect noted in `credentials.md` #57 — appears - generator-wide. -- **Suggestion:** drop dead code, or move it to a shared utils package. - -### L3. `executeCall` vs `executeHttpCall` name collision - -- **Files / lines:** `src/v1/utils.ts:26, 65`. -- **Category:** #17 inconsistent action verbs. -- **Current:** two `execute*` functions with overlapping vocabulary: - `executeCall` (sets options + dispatches retries) and `executeHttpCall` - (one HTTP roundtrip). Same defect cataloged in other audits. - -### L4. `PACKAGE_SEGMENT` constant is vague - -- **File / line:** `src/v1/client.ts:65`. -- **Category:** #1 vague/generic. -- **Current:** `const PACKAGE_SEGMENT = {key, value}` — used to compose - the User-Agent header. -- **Suggestion:** `USER_AGENT_PACKAGE_SEGMENT`. The JSDoc on the line - above already says "Package identity segment for this client to be used - in the User-Agent header" — fold the comment into the name. +_None._ --- @@ -264,19 +230,7 @@ Headline themes: requires `scope` for ten of eleven operations. Not a naming defect but worth noting: the type is wider than the API allows. -### O2. `CreateScopeRequest` fields are out of order vs. domain intuition - -- **File / line:** `src/v1/model.ts:51-60`. -- The order is `scope`, `initialManagePrincipal`, `scopeBackendType`, - `backendAzureKeyvault`. The example in `client.ts:104-115` orders them - differently (`scope`, `initial_manage_principal`, `scope_backend_type`, - `backend_azure_keyvault` — same order, but the JSON example also has - `tenant_id` which the type doesn't have). -- The JSDoc example references `tenant_id` (`client.ts:112`) but the - type `AzureKeyVaultSecretScopeMetadata` has no `tenantId` field. The - example is out of sync with the type. - -### O3. `AclPermission.MANAGE` is owner-equivalent but not named that way +### O2. `AclPermission.MANAGE` is owner-equivalent but not named that way - **File / line:** `src/v1/model.ts:11-12`. - The JSDoc says "Allowed to read/write ACLs, and read/write secrets to @@ -284,15 +238,7 @@ Headline themes: Databricks platform, this level is often called OWNER. Naming inconsistency with the wider platform; the wire format is fixed. -### O4. `marshalPutSecretRequestSchema` does a `btoa` on the bytes value - -- **File / line:** `src/v1/model.ts:393-397`. -- The `bytesValue` field is encoded via `btoa(Array.from(d, b => - String.fromCharCode(b)).join(''))`. This is the legacy Web base64 path - (not name-related). Modern code would use `Buffer.from(d).toString( - 'base64')` (Node) or a polyfill. Not a naming defect. - -### O5. The `Secret` noun is absent from this package's exports +### O3. The `Secret` noun is absent from this package's exports - **Files / lines:** `src/v1/index.ts`, `model.ts`. - The package is called `secrets` but exports `SecretScope`, diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index 5c841c4d..362c1e7d 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -3,14 +3,14 @@ **Path:** `packages/secretsuc/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. -**Total weird names flagged:** 14 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 4 | | Medium | 5 | -| Low | 1 | +| Low | 0 | | Observation | 4 | ## High severity @@ -73,26 +73,22 @@ ## Low severity -### 10. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:36` -- **Why weird:** Same constant repeated in every generated package. `Segment` is generic; reader needs the comment to learn it's the User-Agent identity segment. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `USER_AGENT_PACKAGE_ID` or `PACKAGE_USER_AGENT_SEGMENT`. -- **Rationale:** Same flag as in other generated packages; flagged for consistency. +_None._ ## Observations -### 11. Action-verb convention in `Client` +### 10. Action-verb convention in `Client` `createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) -### 12. Acronym casing for `Http` / `Url` +### 11. Acronym casing for `Http` / `Url` Same as other audited packages: `Http` (PascalCase capital-then-lower) coexists with `URLSearchParams` (ALLCAPS from Web standard). Convention inherited from broader JS ecosystem; not worth changing. - **Category:** 3. -### 13. `Uc` abbreviation never expanded in code +### 12. `Uc` abbreviation never expanded in code Tracked thoroughly. The string "Uc" (in any case) does not appear in any identifier, type name, field name, constant, or enum value. "Unity Catalog" appears only in (a) JSDoc on `Secret` (`model.ts:85`), (b) JSDoc on `createSecret` / `listSecrets` / `updateSecret` (`client.ts:67,163,232`), and (c) the URL path string `/api/2.1/unity-catalog/secrets` (`client.ts:79,109,136,176,244`). The package name `secretsuc` is the **only** carrier of the disambiguator at the import level, and it's silent everywhere else. A consumer importing `Client` and `Secret` from this package, then opening their editor's symbol view, will see no hint that this is Unity-Catalog-scoped. See finding #1. - **Category:** 5. -### 14. No enums in this package +### 13. No enums in this package No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; `secretsuc` exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. ## Domain glossary diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index e4ce411d..a3c960f9 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 **Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). -**Total weird names flagged:** 46 +**Total weird names flagged:** 34 --- @@ -36,44 +36,32 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | 6 | High | Vague/generic type | `UserPreference` | `model.ts:452` | | 7 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:102, 106, 175, 292, 296, 442` | | 8 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | -| 9 | High | Underspecified ID | `accountId` (no format documented on most uses) | `model.ts:157, 162, 181, 209, 272, 279` | -| 10 | High | Underspecified ID | `userId` | `model.ts:165, 211, 281, 456` | -| 11 | High | Misleading | `effectiveValue` vs `value` distinction undocumented at top-level | `model.ts:311, 313, 369, 370` | -| 12 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:296` | -| 13 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:106` | -| 14 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` | -| 15 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:98, 497, 928` | -| 16 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | -| 17 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` | -| 18 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | -| 19 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | -| 20 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | -| 21 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:229` | -| 22 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:208` | -| 23 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:277` | -| 24 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | -| 25 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | -| 26 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:302` | -| 27 | Medium | Generic field name | `hours?: number`, `minutes?: number` on `WindowStartTime` (no timezone documented) | `model.ts:152-153` | -| 28 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #17 as a proto-leak category) | `model.ts:156, 161, 170, 270, 277, 286` | -| 29 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | -| 30 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | -| 31 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | -| 32 | Low | Cryptic abbreviation | `OBO` (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | `model.ts:78` | -| 33 | Low | Cryptic abbreviation | `WS` (in same doc) | `model.ts:78` | -| 34 | Low | Cryptic abbreviation | `SP`/`SPs` ("service principal") in same doc | `model.ts:78, 83` | -| 35 | Low | Cryptic abbreviation | `OBO` undocumented | `model.ts:78` | -| 36 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:157, 165, ...` | -| 37 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | -| 38 | Low | Misleading | "Setting" doc on `UserPreference.setting` field (it's actually a UserPreference, not a Setting) | `model.ts:283` | -| 39 | Low | Wire-vs-TS abbreviation | `disable_gov_tag_creation` wire key | `model.ts:670, 1059` | -| 40 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | -| 41 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:176` | -| 42 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | -| 43 | Low | Misleading | doc on `userId` on `GetPublicAccountUserPreferenceRequest` says "user whose setting is being retrieved" (says "setting" not "preference") | `model.ts:164-165` | -| 44 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | -| 45 | Low | Generic name | `host` (on `Client` private field) | `client.ts:54` | -| 46 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | +| 9 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:296` | +| 10 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:106` | +| 11 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` | +| 12 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:98, 497, 928` | +| 13 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | +| 14 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` | +| 15 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | +| 16 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | +| 17 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | +| 18 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:229` | +| 19 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:208` | +| 20 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:277` | +| 21 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | +| 22 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | +| 23 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:302` | +| 24 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #14 as a proto-leak category) | `model.ts:156, 161, 170, 270, 277, 286` | +| 25 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | +| 26 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | +| 27 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | +| 28 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:157, 165, ...` | +| 29 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | +| 30 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | +| 31 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:176` | +| 32 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | +| 33 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | +| 34 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | --- @@ -141,28 +129,14 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** `AIBI` (acronym casing) or spell out `AiBi` for the AI/BI Genie embedding feature. Add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." - **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. -### 9–10. `accountId`, `userId` — underspecified IDs - -- **File:line:** `model.ts:157, 162, 165, 181, 209, 211, 272, 279, 281, 456` -- **Category:** Underspecified ID -- **Suggestion:** Document the ID format (UUID, opaque-string, numeric, ...) in JSDoc consistently. Currently only some occurrences have a doc (" account ID of the account being managed"), and the format isn't specified anywhere. -- **Rationale:** Users have no way to know whether the SDK accepts `"acct-12345"`, `"abc...uuid"`, or an integer-as-string. The Go SDK's pattern of relying on type-level documentation isn't carried over. - -### 11. `effectiveValue` vs `value` — undocumented distinction - -- **File:line:** `model.ts:311-363 (value) vs 369-421 (effectiveValue)` -- **Category:** Misleading -- **Suggestion:** Add a JSDoc explaining the relationship at the `Setting` type level. Currently the distinction is only documented as "The user-set value that goes into storage" (311) vs "The final effective value from server as per the policy evaluation" (369) — a reader has to read both blocks to understand they're a get/set asymmetry. -- **Rationale:** This is a non-obvious feature where the user sets `value` but the server might return a different `effectiveValue` after applying policy. Worth a top-level doc, not just per-block. - -### 12–13. Verb-tense action-as-noun naming +### 9–10. Verb-tense action-as-noun naming - **File:line:** `model.ts:296 (RestrictWorkspaceAdminsMessage), 106 (ClusterAutoRestartMessage)` - **Category:** Verb-tense inconsistency - **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`). - **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. -### 14. Proto-nested underscore type naming — proto-architectural leak +### 11. Proto-nested underscore type naming — proto-architectural leak - **File:line:** `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` (and the corresponding marshal/unmarshal schema declarations) - **Category:** Proto-architectural leak (nested-message naming) @@ -179,7 +153,7 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Promote nested message/enum types to top-level TS interfaces with descriptive names: `AccessPolicyType`, `MaintenanceWindow`, `DayOfWeek`, `WeekDayFrequency`, `MaintenanceSchedule`, `WindowStartTime`, `EnablementDetails`, `PersonalComputeMode`, `WorkspaceAdminRestrictionStatus`. Where two top-level names would collide across packages, prefix with the owning concept (e.g., `MaintenanceWindowDayOfWeek`) but never use `_`. - **Rationale:** Underscore-separated multi-word TS identifiers are non-idiomatic (Google TS style mandates `PascalCase` for types; Microsoft TS handbook agrees). The `*Foo_Bar_Baz` chain is purely a transliteration of proto's nested-message scoping — TS has module namespaces (`Foo.Bar.Baz`) and lexical scoping for that, neither of which is used here. The eslint-disable comments are the smoking gun. -### 15. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak +### 12. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak - **File:line:** `model.ts:98, 497 (unmarshal), 928 (marshal)` - **Category:** Proto-architectural leak (`Api` mid-position) + `*Message` suffix (covered in #7) @@ -191,40 +165,40 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ## Medium severity -### 16. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use +### 13. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use - **File:line:** `model.ts:94-96` - **Category:** Singular/plural mismatch - **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. -### 17. `*Public*` qualifier — redundant +### 14. `*Public*` qualifier — redundant - **File:line:** `model.ts:156, 161, 170, 270, 277, 286` - **Category:** Redundant qualifier -- **Suggestion:** Drop `Public` from request type names (and method names — #18). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Suggestion:** Drop `Public` from request type names (and method names — #15). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. - **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. -### 18. Method names: `getPublic*`, `patchPublic*` — redundant `Public` +### 15. Method names: `getPublic*`, `patchPublic*` — redundant `Public` - **File:line:** `client.ts:83, 112, 137, 346, 378, 409` - **Category:** Redundant qualifier + verbose - **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. -### 19. `patch*` vs `update*` — inconsistent action verb across SDK +### 16. `patch*` vs `update*` — inconsistent action verb across SDK - **File:line:** `client.ts:346, 378, 409` (use `patch`) - **Category:** Inconsistent action verbs - **Suggestion:** Pick one verb. `update` is the verb in `accountsettings/v1/client.ts` and `workspacesettings/v1/client.ts` for the equivalent operation; `patch` is used here. Cross-package consistency matters. - **Rationale:** Same operation (PATCH HTTP verb against a settings endpoint) named `update*` in the v1 packages and `patch*` in this v2 package. Users will look for `update*` first based on muscle memory. -### 20. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action +### 17. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action - **File:line:** `client.ts:378` - **Category:** Inconsistent + verbose - **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. - **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. -### 21–23. Long type names +### 18–20. Long type names - **File:line:** `model.ts:229, 208, 277` - **Category:** Overly verbose @@ -234,7 +208,7 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - `PatchPublicAccountUserPreferenceRequest` (39 chars) - **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. -### 24. `PreviewPhase` enum — mixed temporal/qualitative members +### 21. `PreviewPhase` enum — mixed temporal/qualitative members - **File:line:** `model.ts:11-27` - **Category:** Verb-tense / categorisation inconsistency @@ -242,102 +216,63 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. - **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. -### 25–26. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` +### 22–23. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` - **File:line:** `model.ts:30, 88, 94, 302` - **Category:** Acronym casing - **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. -### 27. `hours`, `minutes` with no timezone - -- **File:line:** `model.ts:152-153` -- **Category:** Generic field name, missing constraint -- **Suggestion:** Add doc specifying the time-zone interpretation, or add a `timezone?: string` field. -- **Rationale:** A "maintenance window start time" without timezone is ambiguous (workspace TZ? customer TZ? UTC?). - -### 28. `*Public*` qualifier as proto-architectural leak (reframe of #17) +### 24. `*Public*` qualifier as proto-architectural leak (reframe of #14) - **File:line:** `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` - **Category:** Proto-architectural leak (`Public` mid-position) - **Why:** `Public` in `GetPublic*Request`, `PatchPublic*Request`, and method names `getPublic*`/`patchPublic*` is a direct echo of the proto service-name `PublicSettingsService` — i.e., the *server-side* internal-vs-public service split. The TS SDK only ships the public surface, so the qualifier signals nothing the user can act on. - **Suggestion:** Drop `Public` from every request type and every method name. `GetAccountSettingRequest`/`getAccountSetting`, `PatchAccountSettingRequest`/`patchAccountSetting`, etc. -- **Rationale:** This duplicates #17 and #18 but reframes them as a *proto-architectural leak* per the scan brief. `Public`/`Internal` are explicitly on the flag list. The two earlier findings catalogued the names; this one names the cause. +- **Rationale:** This duplicates #14 and #15 but reframes them as a *proto-architectural leak* per the scan brief. `Public`/`Internal` are explicitly on the flag list. The two earlier findings catalogued the names; this one names the cause. --- ## Low severity -### 29–31. Long enum values +### 25–27. Long enum values - **File:line:** `model.ts:85, 56, 57` - **Category:** Long enum value - **Identifiers:** `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) - **Suggestion:** For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. -### 32–35. Undocumented abbreviations in JSDoc - -- **File:line:** `model.ts:78, 83` -- **Category:** Cryptic abbreviation -- **Tokens:** "WS" (workspace), "OBO" (on-behalf-of token), "SPs" (service principals) -- **Suggestion:** Spell out in the JSDoc. -- **Rationale:** Users reading the IDE tooltip will see "WS admins to create OBO tokens for all SPs" without expansions. - -### 36–37. Acronym casing notes +### 28–29. Acronym casing notes - **File:line:** `model.ts:157, 78` - **Category:** Acronym casing - **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). -### 38. `setting?: UserPreference` doc mismatch - -- **File:line:** `model.ts:283` -- **Category:** Misleading -- **Suggestion:** Update the JSDoc to refer to "user preference" rather than "setting" so the doc matches the type. - -### 39. `disable_gov_tag_creation` wire key - -- **File:line:** `model.ts:670, 1059` -- **Category:** Cryptic abbreviation (server-controlled) -- **Suggestion:** N/A — wire format is fixed. Note for documentation. - -### 40. `restrict_tokens_and_job_run_as` enum string value +### 30. `restrict_tokens_and_job_run_as` enum string value - **File:line:** `model.ts:85` - **Category:** Wire value - **Suggestion:** N/A — wire-fixed. -### 41. `IntegerMessage` misleading in JS +### 31. `IntegerMessage` misleading in JS - **File:line:** `model.ts:175-177` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 42. `patch*` vs `update*` +### 32. `patch*` vs `update*` -- See #19. +- See #16. -### 43. JSDoc on `userId` says "user whose setting is being retrieved" instead of "preference" - -- **File:line:** `model.ts:164-165` -- **Category:** Misleading -- **Suggestion:** Use the same vocabulary as the type — "preference" for user-preference endpoints. - -### 44. Cross-package `Dbfs` casing +### 33. Cross-package `Dbfs` casing - **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) - **Category:** Cross-package acronym casing - **Suggestion:** Note for the cross-package audit, not actionable here. -### 45. `host` — generic class field - -- **File:line:** `client.ts:54` -- **Category:** Generic -- **Suggestion:** `baseUrl` (consistent with `fetch` API conventions). "Host" can mean DNS host, host machine, etc. - -### 46. `BETA` member adjacent to `PUBLIC_PREVIEW` +### 34. `BETA` member adjacent to `PUBLIC_PREVIEW` -- See #24. +- See #21. --- @@ -387,7 +322,6 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess |------|-----------|----------| | `src/v2/index.ts` | 44 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | | `src/v2/model.ts` | 1300 (full) | 100% — 6 enums, 23 interfaces (incl. all nested message types), 15 unmarshal-zod schemas, 15 marshal-zod schemas audited. | -| `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor and 9 client methods audited (paginated page-returning and iterator-returning variants both reviewed). Private fields (`host`, `accountId`, `httpClient`, `logger`, `userAgent`) audited. | -| `src/v2/utils.ts` | 150 (full) | 100% — `HttpCallOptions`, `executeCall`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll` audited. Shared utility code; no naming issues unique to this package (the same scaffolding appears in every package). | +| `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor and 9 client methods audited (paginated page-returning and iterator-returning variants both reviewed). | --- diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index 16fcf3e4..807bc875 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -28,20 +28,20 @@ The package name `statementexecution` is reasonable in isolation, but the SDK opening the marketplace sees four packages whose names overlap heavily and has to read every one to pick the right tool. See finding #1. -**Total weird names flagged:** 43 +**Total weird names flagged:** 37 ## Summary | Severity | Count | | --- | --- | | High | 9 | -| Medium | 24 | -| Low | 7 | +| Medium | 20 | +| Low | 5 | | Observation | 3 | ## High severity -### 1. Package name `statementexecution` overlaps three sibling packages — `package.json`, directory name +### 1. Package name `statementexecution` overlaps three sibling packages — directory name, public import specifier - **Why weird:** The SDK ships `statementexecution`, `queryexecution`, `commandexecution`, and `queries`. The English words "query", "statement", and "command" are near-synonyms in casual usage, so a user installing the SDK can't pick the right one without reading docs. Concretely: this package is the *only* one that runs ad-hoc SQL on a SQL Warehouse, yet its name doesn't reveal that. The Databricks SQL Statement Execution API itself is documented at `docs.databricks.com/api/workspace/statementexecution`, so the wire-level name is "statement execution" — but the *user-facing* TS-import surface should distinguish itself from `queryexecution`. - **Category:** 1 (vague — "statement" overlaps "query"/"command"), 12 (duplicate concept — three execution packages). - **Suggested name:** `sqlstatements`, `sqlexec`, or `warehouseexec` — anything that signals "SQL on a SQL Warehouse". If staying with `statementexecution`, every type name should keep its `Statement*` prefix and the package docstring should call out the contrast with `queryexecution` and `commandexecution`. @@ -102,7 +102,7 @@ to read every one to pick the right tool. See finding #1. ## Medium severity ### 10. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` -- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #17 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. +- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #16 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. - **Category:** 13 (verb-tense inconsistency), 17 (US/UK spelling inconsistency for "cancel"). - **Suggested name:** Pick one cancel spelling. The wire is `CANCELED` (single-l) per this enum and `CANCELLED` per `ServiceErrorCode`. Resolve at wire level. - **Rationale:** Twin spellings of the same English word in adjacent enums in the same file is a maintenance hazard. Compare `StatementStatus_State.CANCELED` to `ServiceErrorCode.CANCELLED`. @@ -114,131 +114,108 @@ to read every one to pick the right tool. See finding #1. - **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. ### 12. `warehouseId` field — `src/v1/model.ts:158` -- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #27. +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #24. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. -### 13. `rowLimit` vs `byteLimit` — both optional, asymmetric defaults — `src/v1/model.ts:176, 184` -- **Why weird:** Two parallel "limit" fields; `rowLimit` has no default mentioned; `byteLimit` mentions a "100 GiB default if not explicitly set" for `EXTERNAL_LINKS` disposition. The asymmetric defaults aren't captured by the types. JSDoc encodes them; users have to read both. -- **Category:** 16 (field-vs-domain — domain has implicit defaults the type doesn't show), 17 (asymmetric defaults). -- **Suggested name:** Names are fine; consolidate JSDoc so both fields document defaults symmetrically. -- **Rationale:** Pair-fields should have parallel JSDoc structure. - -### 14. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` +### 13. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` - **Why weird:** Field name is `parameters`. Element type is `StatementParameter`. The element name is more specific (statement parameter) than the field (parameters). At the JSDoc level, the field describes "parameter markers" — which is yet a third name for the same concept. So users see: `parameters` (field) vs `StatementParameter` (element type) vs "parameter markers" (docs). Pick one vocabulary. - **Category:** 12 (duplicate concept — three names for one idea), 17 (inconsistent vocabulary). - **Suggested name:** Either rename the element type to `Parameter` (less qualified than field) or rename the field to `statementParameters`. The wire shape probably matters; pick the less verbose option. - **Rationale:** Multiple synonyms for one concept burns reader attention. -### 15. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` +### 14. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` - **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `ApiError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `ApiError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. - **Category:** 12 (duplicate concept — overlaps `ApiError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). - **Suggested name:** `StatementError` (or fold into `ApiError` extensions). The errorCode should reuse the canonical apierror codes per #2. - **Rationale:** Multiple error type shapes per SDK is a cognitive tax. -### 16. `StatementStatus.sqlState` field — `src/v1/model.ts:522` +### 15. `StatementStatus.sqlState` field — `src/v1/model.ts:522` - **Why weird:** Field name `sqlState`. The JSDoc says "SQLSTATE error code returned when the statement execution fails." The all-caps acronym SQLSTATE is the SQL-standard 5-character status code (e.g. `42S22`). The TS field uses camelCase `sqlState`. Compare to elsewhere in the SDK where SQL is also lowercased (`sqlExpression`, `sqlText`). This is consistent SDK-wide. - **Category:** 3 (acronym casing — `SQL` becoming `sql` is debatable; SDK has settled on lowercase, so this matches). - **Suggested name:** Keep `sqlState`. Flagged for completeness. - **Rationale:** TS convention varies on multi-letter acronyms; google-ts-style says lowercase initial; SDK follows the convention. -### 17. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` +### 16. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` - **Why weird:** Same English word, two spellings, in two enums in the same file. `CANCELLED` is British; `CANCELED` is American. The wire chose differently for the two enums; the SDK mirrors the wire. End users have to remember "cancel with one or two Ls". - **Category:** 13 (spelling/tense inconsistency — see #10), 17 (asymmetric pair). - **Suggested name:** Normalise upstream. If kept, document the spelling difference in `@databricks/sdk-databricks` README. - **Rationale:** The spelling difference is invisible in casual scanning but breaks copy/paste. -### 18. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` +### 17. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` - **Why weird:** `waitTimeout?: string` with JSDoc explaining it must be formatted as `"Ns"` where N is 0 or 5-50. So a *typed string* with a private DSL inside. Users will write `"5s"` and hope, or worse: `5` (number, won't compile). The wire format is a proto Duration, but the TS surface could parse `number` (seconds) or `Duration` (ms) and emit `Ns`. - **Category:** 1 (vague — `string`-typed numeric), 6 (misleading — a "timeout" with arbitrary string content), 14 (proto/Go-style — Duration carry-over). - **Suggested name:** Keep `waitTimeout` but change the type to `number` (seconds) and let the marshaller produce `Ns`. Or `Duration` from `@databricks/sdk-core/wkt`. - **Rationale:** Letting users pass arbitrary strings into a numeric field is a contract violation waiting to happen. -### 19. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` +### 18. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` - **Why weird:** Field is `onWaitTimeout`, type is `TimeoutAction`. The two names don't share the prefix `Wait*` even though they're tightly coupled. A reader sees `onWaitTimeout?: TimeoutAction` and has to chase the docs to learn the enum members are about wait-timeouts. - **Category:** 17 (asymmetric field/type naming), 12 (duplicate concept — `Wait`/`Timeout` overloaded). - **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #5, `OnTimeout`. - **Rationale:** Field/type symmetry is a strong signal. -### 20. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` +### 19. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` - **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. - **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). - **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. - **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. -### 21. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +### 20. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` - **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. - **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). - **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). - **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. -### 22. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` +### 21. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` - **Why weird:** `ResultManifest.chunks` is an array of `ChunkInfo`; `totalChunkCount` is `chunks.length`. The two carry the same information; on the wire there is a sender-receiver invariant, but TS users can compute one from the other. The naming gives no hint of the redundancy. - **Category:** 12 (duplicate concept), 1 (vague — both fields are about the same property). - **Suggested name:** Drop `totalChunkCount`; users compute via `chunks?.length`. - **Rationale:** Two fields that mean the same thing should not both be public. -### 23. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` +### 22. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` - **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. - **Category:** 16 (field-vs-format contradicts domain when format differs). - **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. - **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. -### 24. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` -- **Why weird:** Companion to #23. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. +### 23. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +- **Why weird:** Companion to #22. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. - **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. - **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. -### 25. `executeCall` and `executeHttpCall` in utils — `src/v1/utils.ts:26, 65` -- **Why weird:** Two `execute*` functions in the same file, one wraps retry/rate-limit policy and one does the actual HTTP. Same as `queryexecution.md` Finding #21. -- **Category:** 1, 12, 17. -- **Suggested name:** `runWithPolicies` + `sendHttpRequest`. -- **Rationale:** Generator-wide. - -### 26. `buildHttpRequest` helper — `src/v1/utils.ts:96` -- **Why weird:** "Build" implies builder pattern; this is a 16-line object literal. Same as `queryexecution.md` Finding #22. -- **Category:** 1, 6. -- **Suggested name:** `makeHttpRequest` or inline. - -### 27. Every field on every request type is optional — `src/v1/model.ts` (every interface) +### 24. Every field on every request type is optional — `src/v1/model.ts` (every interface) - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). - **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. -### 28. `StatementResponse` is the response of *two* methods — `src/v1/model.ts:493`, `src/v1/client.ts:151, 222` -- **Why weird:** Both `executeStatement()` and `getStatementResult()` return `StatementResponse`. The name `StatementResponse` is generic enough to cover both — but a reader can't tell from the type which method produced it. The contents differ subtly: `executeStatement` may return `PENDING`; `getStatementResult` returns terminal states only. Two operations with one response type is fine if the response is genuinely one shape, but the JSDoc on the response should disambiguate, and the audit-only `statementId` collision (per #11) suggests this is the wrong abstraction. -- **Category:** 6 (misleading — type is overloaded), 12 (duplicate concept — two operations). -- **Suggested name:** Keep `StatementResponse` but document that it's polymorphic. Or split into `StatementSubmissionResponse` + `StatementStateResponse`. -- **Rationale:** Shared response types are acceptable but should be flagged for documentation. - -### 29. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` -- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). #15 already flags the type for overlap with `ApiError`; this finding flags the `Service` mid-position as a proto/Java-RPC architectural leak. +### 25. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` +- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). #14 already flags the type for overlap with `ApiError`; this finding flags the `Service` mid-position as a proto/Java-RPC architectural leak. - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementError` — domain-named, mirrors the surrounding `Statement*` vocabulary. - **Rationale:** Architectural-layer words ("Service", "Server", "Backend") in user-facing type names are proto/RPC framework carry-overs. Domain-named alternatives compose better with the rest of the package surface. -### 30. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` -- **Why weird:** Same `Service` mid-position architectural leak as #29, applied to the code enum. #2 already flags the enum for duplicating `google.rpc.Code`; this finding flags the `Service` qualifier specifically as a proto-RPC architectural noun. +### 26. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` +- **Why weird:** Same `Service` mid-position architectural leak as #25, applied to the code enum. #2 already flags the enum for duplicating `google.rpc.Code`; this finding flags the `Service` qualifier specifically as a proto-RPC architectural noun. - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementErrorCode` if the enum is retained; ideally fold into canonical `apierror/codes` per #2. -- **Rationale:** Pair with #29 — the `Service` qualifier carries no domain meaning at the use site. +- **Rationale:** Pair with #25 — the `Service` qualifier carries no domain meaning at the use site. -### 31. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` +### 27. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` - **Why weird:** Underscore-joined identifier `StatementStatus_State` directly transcribes the proto nested-message name into TS. The source file even carries an `eslint-disable` for `@typescript-eslint/naming-convention` with the comment "Proto-style nested enum name." That comment confirms it: the name is a verbatim proto leak, not a TS-idiomatic choice. As a top-level export from `index.ts`, every consumer sees the underscore. - **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). - **Suggested name:** `StatementState` (the `Status` parent is itself a thin wrapper; the state is the meaningful enum) or `StatementStatusState` (no underscore) if both halves matter. - **Rationale:** Proto nested-type underscores are an artefact of code generation from `.proto`. TS has no nested-type concept; flattening to a single CamelCase name removes the leak. -### 32. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` +### 28. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` - **Why weird:** Another underscore-joined name with the same `eslint-disable` and an explicit "Proto-style nested message name" comment. The type exists because proto3 represents `map` as a synthetic nested `*Entry` message; gRPC generators surface this as a nested type. In TS the wire shape is just `Record` (see `httpHeaders` on `ExternalLink`). Re-exporting `ExternalLink_HttpHeadersEntry` from `index.ts` exposes proto machinery the JS user never needs. - **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape), 12 (duplicate concept — `httpHeaders` is already typed `Record`). - **Suggested name:** Delete the type. The `httpHeaders` field is already `Record | undefined`; no consumer needs the synthetic map-entry pair. - **Rationale:** Proto `map` synthetic `*Entry` messages should not surface in user-facing TS types. The information is fully captured by `Record`. -### 33. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` +### 29. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` - **Why weird:** Four enums (`Disposition`, `Format`, `TimeoutAction`, `StatementStatus_State`) carry a `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, `STATE_UNSPECIFIED` first variant. These are proto3 enum convention: every enum must have a `_UNSPECIFIED = 0` member because the default scalar value is required to be valid. JS/TS has no such constraint — `undefined` already encodes "not specified". So the enums carry a value that exists *only* to satisfy proto3 codegen requirements. End users have to filter out the unspecified variant manually when narrowing. - **Category:** 14 (proto/protobuf convention leak), 6 (misleading — the variant has no domain meaning), 1 (vague — `UNSPECIFIED` is the literal default state). - **Suggested name:** Drop the `*_UNSPECIFIED` variants. TS uses `Disposition | undefined` for "not set". @@ -246,43 +223,33 @@ to read every one to pick the right tool. See finding #1. ## Low severity -### 34. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +### 30. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` - **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. - **Category:** 17 (acceptable asymmetry). - **Suggested name:** Keep. -### 35. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:109, 111, 116` +### 31. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:109, 111, 116` - **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. - **Category:** 12 (duplicate concept — three types carry the same fields). - **Suggested name:** Extract `ChunkMetrics` shared interface. - **Rationale:** Trio-replicated types are a tell. -### 36. `ColumnInfo.typeText` vs `typeName` — `src/v1/model.ts:135, 137` -- **Why weird:** `typeText` is "the full SQL type specification" (e.g. `DECIMAL(10,2)`). `typeName` is the base type name (`DECIMAL`). The pair is intentional but the names don't make the relationship obvious — `typeText` and `typeName` sound interchangeable. -- **Category:** 17 (asymmetric pair — `Text` vs `Name`), 1 (vague — `Text` of what?). -- **Suggested name:** `typeSql` (the wire SQL text) + `typeBase` (the base type) — but the wire is canonical, so keep names. Document the relationship. - -### 37. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +### 32. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` - **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. - **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). - **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 38. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +### 33. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` - **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. - **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). - **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. -### 39. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` -- **Why weird:** Generic key-value pair. Same as #36 but for tags. `tagKey` + `tagValue` are common alternatives. +### 34. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` +- **Why weird:** Generic key-value pair. `tagKey` + `tagValue` are common alternatives. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** Acceptable in context. -### 40. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:38` -- **Why weird:** Generic name. Same as `queryexecution.md` Finding #25. -- **Category:** 1. -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. - ## Observations (non-fixable here) ### O-1. URL string concatenation handles `undefined` silently — `src/v1/client.ts:76, 187, 223` @@ -326,7 +293,7 @@ The two packages model semantically distinct operations (general SQL Statement Execution vs Lakeview-dashboard query lifecycle) but share enough vocabulary (`Statement`, `Query`, `Cancel`, `Execute`, `Status`) that a user importing both will be confused. The fix is at the naming/package level (see #1) and -the cross-package vocabulary alignment (#11, #17). +the cross-package vocabulary alignment (#11, #16). --- diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md index e1363b2c..7c9c09bd 100644 --- a/.agent/naming-audit/supervisoragents.md +++ b/.agent/naming-audit/supervisoragents.md @@ -11,15 +11,15 @@ resource types: `SupervisorAgent` (top-level), `Tool` (child of in-context steering). Every list endpoint paginates via `pageSize`/`pageToken`. No state enums exist in this package; the entire surface is data plus references to other Databricks resources. -**Total weird names flagged:** 29 +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | -| High | 7 | -| Medium | 10 | -| Low | 6 | -| Observation | 6 | +| High | 5 | +| Medium | 4 | +| Low | 1 | +| Observation | 3 | ## High severity @@ -41,25 +41,13 @@ surface is data plus references to other Databricks resources. - **Suggested name:** Either (a) convert `toolType` to a string-literal union matching the enumerated wire values, or (b) drop `toolType` entirely because `spec.$case` already encodes the variants the SDK supports (recommended). - **Rationale:** Stringly-typed enums in TypeScript are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals). The duplicate declaration in two casings is a generator artifact from the proto definition and a tax on every consumer. -### 4. `Tool.toolType` casing disagrees with every other discriminator value on the wire — `src/v1/model.ts:227` -- **Why weird:** The 14 enumerated values inside the doc string are snake_case: `"genie_space"`, `"knowledge_assistant"`, `"uc_function"`, `"uc_connection"`, `"serving_endpoint"`, `"vector_search_index"`, `"supervisor_agent"`, `"web_search"`, `"dashboard"`, `"table"` (singletons `"app"`, `"volume"`, `"catalog"`, `"schema"` work in both). But the TypeScript `spec.$case` field uses camelCase variants of its 6-element subset: `'genieSpace'`, `'knowledgeAssistant'`, etc. The wire format for `toolType` is snake_case — but the consumer must know to write `toolType: 'genie_space'` while paying attention to camelCase `spec.$case`. A TypeScript-only consumer who never reads JSDoc will think the values are camelCase to match `$case` and get HTTP 400 on the first request. -- **Category:** 17 (casing inconsistency within the same struct), 4 (snake_case in a string-literal value, even though the value is on the wire). -- **Suggested name:** If `toolType` survives (see #3), document inline that values are snake_case wire-side, or normalize to camelCase to match `spec.$case`. -- **Rationale:** The mismatch is exactly what causes the most painful bugs in generated SDKs — the type checker says it is fine, the runtime fails. A naming audit must call this out even though it is a *value* mismatch rather than an *identifier* mismatch. - -### 5. `KnowledgeAssistant` package name collision — `src/v1/model.ts:120` +### 4. `KnowledgeAssistant` package name collision — `src/v1/model.ts:120` - **Why weird:** The package `@databricks/sdk-supervisoragents` exports a type `KnowledgeAssistant` that represents *one variant of a Tool.spec discriminated union*, not the actual knowledge assistant resource. The actual `KnowledgeAssistant` resource lives in `@databricks/sdk-knowledgeassistants/v1`. A consumer importing both packages will collide on the same identifier in TS source — and the supervisor-agents type only has two fields (`servingEndpointName`, `knowledgeAssistantId`) while the real one has 12+. This is the same problem as #1/#2 but at the cross-package level. The same applies to `GenieSpace` (a single deprecated `id` field) vs the canonical Genie space resource elsewhere in the SDK. - **Category:** 12 (duplicate concept across packages), 6 (misleading — same name, different shape). - **Suggested name:** `KnowledgeAssistantToolSpec`, `KnowledgeAssistantRef`, or `ToolKnowledgeAssistant`. Apply the suffix uniformly to all 6 variants (`GenieSpaceRef`, `UcFunctionRef`, etc.). - **Rationale:** Cross-package name collisions are the worst kind of naming bug because the import path lies about the type's identity. A `Ref`/`ToolSpec` suffix on every variant solves this uniformly. -### 6. `SupervisorAgent.id` is deprecated but still in the public TS surface — `src/v1/model.ts:205-206` -- **Why weird:** `id?: string` carries the JSDoc "Deprecated: Use supervisor_agent_id instead." (mind the wire-format leaking into the doc — `supervisor_agent_id` is the snake_case version, but the actual TS field is `supervisorAgentId`). The field is *not* marked `@deprecated` for the IDE, so consumers using IntelliSense will not see the strikethrough. The same issue applies to `Tool.id` (model.ts:225-226, same wording "Deprecated: Use tool_id instead."), `GenieSpace.id` (model.ts:88-92, "Deprecated: use space_id instead."), and `KnowledgeAssistant.servingEndpointName` (model.ts:121-122, "Deprecated: use knowledge_assistant_id instead."). -- **Category:** 6 (misleading — deprecation is documented but not annotated), 8 (redundant suffix: keeping deprecated `id` *and* `supervisorAgentId` causes name clutter), 14 (the doc references the snake_case wire name rather than the TS name). -- **Suggested name:** Add `@deprecated` JSDoc tag so IDEs render it; doc should reference `supervisorAgentId` (the TS name) not `supervisor_agent_id` (the wire name); long-term plan for removal. Same fix on `Tool.id`, `GenieSpace.id`, and `KnowledgeAssistant.servingEndpointName`. -- **Rationale:** Public-API deprecation has a standard JSDoc tag (https://jsdoc.app/tags-deprecated.html) that triggers IDE warnings. Free-text comment does not. - -### 7. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:121-122` +### 5. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:121-122` - **Why weird:** The `KnowledgeAssistant` variant type (one of 6 tool kinds) has two fields: - `servingEndpointName?: string` — doc "Deprecated: use knowledge_assistant_id instead." - `knowledgeAssistantId?: string` — doc "The ID of the knowledge assistant." @@ -70,58 +58,25 @@ surface is data plus references to other Databricks resources. ## Medium severity -### 8. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:211-212` +### 6. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:211-212` - **Why weird:** `Temporal.Instant` is correct (good!) but the field name `createTime` follows AIP-142 (https://google.aip.dev/142). Compare with `customllms.CustomLlm.creationTime: Temporal.Instant` (audited as inconsistent) — the supervisor-agents package uses the AIP form, the customllms package does not. This is positive consistency on supervisor-agents and negative on customllms. Flagging here because the audit covers SDK-wide consistency. - **Category:** Observation / 17 (cross-package inconsistency). - **Suggested name:** Keep `createTime`; flag `customllms` to align. - **Rationale:** Note positive precedent; pair with the audit on `customllms` to align it. -### 9. `SupervisorAgent.description` "user-facing" annotation — `src/v1/model.ts:201-202` -- **Why weird:** Doc reads "Description of what this agent can do (user-facing)." The parenthetical "(user-facing)" is unusual — every other `description` field in the Databricks SDK is implicitly user-facing. Same observation flagged in `knowledgeassistants.md` #42. The same parenthetical appears on `Tool.description` (model.ts:238-239). -- **Category:** Observation / 17 (inconsistent JSDoc style across SDK). -- **Suggested name:** Drop "(user-facing)" from the two sites; flag for cross-package style review. -- **Rationale:** Minor; cosmetic but worth aligning. - -### 10. `Tool.description` "user-facing" repeated annotation — `src/v1/model.ts:238-239` -- **Why weird:** Same as #9; the `Tool.description` has the same "(user-facing)" parenthetical. The doc reads "Description of what this tool does (user-facing)." If the audit prompt cares about consistency, both descriptions should match. -- **Category:** Observation / 17. -- **Suggested name:** Same as #9. - -### 11. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:240-241` +### 7. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:240-241` - **Why weird:** Doc reads "User specified id of the Tool." Comparing with `CreateToolRequest.toolId` (model.ts:37-41, "The ID to use for the tool, which will become the final component of the tool's resource name."), the two `toolId` fields are *the same wire concept* — but on `Tool` it is the persisted id, while on `CreateToolRequest` it is the request-time supplied id. The same field name is doing two semantic jobs depending on context. Plus, comparing with `Example.exampleId` (model.ts:83-84, "The universally unique identifier (UUID) of the example."), the format claim differs: `Tool.toolId` is *user-specified*, `Example.exampleId` is a *UUID*. The two id formats are not aligned across sibling types in the same package. - **Category:** 17 (inconsistency across sibling types), 6 (misleading — different format claims). - **Suggested name:** Keep `toolId` and `exampleId` but expand the JSDoc on each to disambiguate the id-format contract. Or rename `Tool.toolId` → `toolKey` to mirror that it is a user-supplied identifier (as opposed to a server-generated UUID). - **Rationale:** A naming audit must flag fields whose format contract is silent in the type signature. -### 12. `SupervisorAgent.supervisorAgentId` vs `SupervisorAgent.id` (deprecated) — both UUIDs — `src/v1/model.ts:205-208` -- **Why weird:** Two id fields on `SupervisorAgent`: the deprecated `id` and the canonical `supervisorAgentId`. Both are `string`, both UUIDs per the doc on line 207 ("The universally unique identifier (UUID) of the Supervisor Agent."). The deprecation is in JSDoc only (no `@deprecated` tag — see #6). Same situation on `Tool.id` vs `Tool.toolId` (model.ts:225-226, 240-241). Carrying the deprecated alias on the type forces consumers to handle both; the SDK should pick one. -- **Category:** 8 (redundant alias suffix), 12 (duplicate concept within the same type). -- **Suggested name:** Mark `id` `@deprecated`; document that `supervisorAgentId` is canonical. Future major version removes `id` entirely. -- **Rationale:** Carrying a deprecated alias on a TS type is a tax on every reader. Mark it loudly. - -### 13. `SupervisorAgent.supervisorAgentId` type-suffix tautology — `src/v1/model.ts:207-208` -- **Why weird:** `SupervisorAgent.supervisorAgentId` repeats `SupervisorAgent` in the type name and field. The pattern is correct AIP-style (every entity has `*Id` matching its type) but extremely verbose. Once `SupervisorAgent` is renamed to `RouterAgent` (per #1), the field becomes `routerAgentId` — slightly shorter, still type-tautological. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** Keep current (tradeoff with cross-type disambiguation), but document the convention in `typescript.mdc`. -- **Rationale:** This is a convention question, not a bug. The verbose form *does* disambiguate from `Tool.toolId` and `Example.exampleId` when passed to a generic function. Flagged for awareness. - -### 14. `Example.exampleId` type-suffix tautology — `src/v1/model.ts:83-84` -- **Why weird:** Same shape as #13, but the field is `exampleId` and the type is `Example`. The redundancy is identical. Note: every sibling SDK package follows the same convention (`knowledgeassistants.Example.exampleId` is the same pattern). -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** Keep current; document the convention. - -### 15. `Tool.toolId` type-suffix tautology — `src/v1/model.ts:240-241` -- **Why weird:** Same pattern as #13, #14. -- **Category:** 20. -- **Suggested name:** Keep current; document the convention. - -### 16. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:37-41` +### 8. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:37-41` - **Why weird:** The create request takes both `tool: Tool` (the body) *and* `toolId: string` (the URL/query param). The wire form is `POST /supervisor-agents/{id}/tools?tool_id={user-supplied}`. So `req.toolId` flows into the query string and `req.tool.toolId` is *not used* on creation — but TypeScript does not enforce this. A consumer who writes `{tool: {toolId: 'foo'}}` and leaves `req.toolId` undefined gets unexpected behavior. The two-fields-for-one-concept pattern is also documented in `customllms.md` #20. - **Category:** 12 (duplicate concept on the same request), 6 (misleading — `tool.toolId` looks usable on creation but isn't), 17. - **Suggested name:** Either remove `tool.toolId` from the body shape (TypeScript can enforce this via a discriminated `Omit` type for create), or document the precedence rule on the JSDoc. - **Rationale:** Generated request types with duplicate fields are a well-known footgun. -### 17. `Client` class name — bare, no scoping — `src/v1/client.ts:61` +### 9. `Client` class name — bare, no scoping — `src/v1/client.ts:61` - **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-supervisoragents/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as SAClient} from '@databricks/sdk-supervisoragents/v1'`. Same SDK-wide issue flagged in `knowledgeassistants.md` #30. - **Category:** 1 (vague), 17 (SDK-wide inconsistency). - **Suggested name:** `SupervisorAgentsClient` (matches the Go SDK's `WorkspaceClient.SupervisorAgents` and AWS SDK's `S3Client`, `IAMClient` pattern). @@ -129,69 +84,23 @@ surface is data plus references to other Databricks resources. ## Low severity -### 18. `Volume`/`UcFunction`/`UcConnection` — `Uc` prefix on some, bare on others — `src/v1/model.ts:245,249,286` +### 10. `Volume`/`UcFunction`/`UcConnection` — `Uc` prefix on some, bare on others — `src/v1/model.ts:245,249,286` - **Why weird:** Of the variant types, three are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`. The `Uc` prefix is applied to two but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). - **Category:** 3 (acronym casing — `Uc` vs `UC`), 17 (inconsistent prefix application — `Volume` should be `UcVolume`). - **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection` (with the acronym-casing question decided once SDK-wide). - **Rationale:** Consistency wins; the audit prompt rule 3 (acronym casing) and rule 17 (consistent action verbs / family naming) both flag this. -### 19. `executeCall` / `executeHttpCall` differ in name by `Http` only — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions with nearly identical names handling different layers — same anti-pattern as `customllms.md` #21 and `knowledgeassistants.md` #34. Each generated package carries the same pair. -- **Category:** 1 (vague), 17 (inconsistency). -- **Suggested name:** `runWithCallOptions` / `sendHttp` or `wrapCall` / `dispatchHttp`. -- **Rationale:** Names should differ in more than one infix. - -### 20. `HttpCallOptions` reuses `Options` — `src/v1/utils.ts:15` -- **Why weird:** Same as `customllms.md` #23 and `knowledgeassistants.md` #35: `ClientOptions`, `CallOptions`, and `HttpCallOptions` all live in scope simultaneously. Three things named `Options`. -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` or `HttpCallParams`. -- **Rationale:** Distinguish internal context bags from user-facing options. - -### 21. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Same as `customllms.md` #28 and `knowledgeassistants.md` #36: exported but not used by `client.ts`. Generator-mechanical surface area. -- **Category:** Observation / (unused export). -- **Suggested name:** Either remove the export or document why it ships per-package. -- **Rationale:** Generated artifact; flag for cross-package cleanup. - -### 22. `readAll` helper generic name — `src/v1/utils.ts:40` -- **Why weird:** Same as `customllms.md` #29 and `knowledgeassistants.md` #37: helper reads an entire response body stream; name is generic. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` or `readStreamToEnd`. -- **Rationale:** Internal helper, low cost. Skip if generated. - -### 23. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:56` -- **Why weird:** Same as `customllms.md` #24 and `knowledgeassistants.md` #38: `Segment` is a generic CS term. -- **Category:** 1 (vague). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** SDK-wide consistency review. - ## Observations -### 24. `resp` local variable in every method — `src/v1/client.ts:98,130,165,265,293,318,355,409,466,518,565,609` -- **Why weird:** Same as `customllms.md` #33 and `knowledgeassistants.md` #39: `resp` is the response. Twelve methods repeat the same pattern. -- **Category:** 12 (duplicate pattern). -- **Suggested name:** Refactor away the pattern, not the name. -- **Rationale:** Refactor opportunity surfaced by audit. - -### 25. `pageReq` local in iterator methods — `src/v1/client.ts:381,438,492` -- **Why weird:** Same as `knowledgeassistants.md` #40: three async generator methods declare `const pageReq: ... = {...req};`. Reuses the abbreviation `Req` while elsewhere in the file the parameter is named `req`. -- **Category:** 5 (abbreviation). -- **Suggested name:** `pageRequest` or `nextPageReq`. - -### 26. `tool.spec` field-mask handling — discriminated union flattened — `src/v1/model.ts:656-674` -- **Why weird:** The field-mask carries top-level entries for each variant of the `spec` union — `app`, `genieSpace`, `knowledgeAssistant`, `ucConnection`, `ucFunction`, `volume`. The field-mask flattens the union variants to top-level field-mask paths (AIP-161, https://google.aip.dev/161 behavior) but does not include a `spec` path. A consumer writing `toolFieldMask('spec.genieSpace')` will get an invalid mask. Same pattern flagged in `knowledgeassistants.md` #41. -- **Category:** 17 (inconsistency between TS shape and field-mask). -- **Suggested name:** No rename; document on the JSDoc. - -### 27. `Tool.toolType` doc lists 14 kinds but `Tool.spec` union covers only 6 — `src/v1/model.ts:227,230-237` +### 11. `Tool.toolType` doc lists 14 kinds but `Tool.spec` union covers only 6 — `src/v1/model.ts:227,230-237` - **Why weird:** The JSDoc on `Tool.toolType` enumerates 14 wire values (`"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "dashboard", "serving_endpoint", "table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`), but the `Tool.spec` discriminated union only encodes 6 of them (`genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `ucConnection`). The other 8 wire kinds — dashboard, serving_endpoint, table, vector_search_index, catalog, schema, supervisor_agent, web_search — can be set via `toolType` but have no corresponding `spec` variant. A consumer who writes `{toolType: 'dashboard'}` gets no type-system support for the dashboard payload because the variant doesn't exist. Either the backend has dropped those kinds (and the doc should be updated) or the TS surface is missing variants. - **Category:** 16 (field contradicts type domain), 17 (doc vs type-shape mismatch), 6 (misleading). - **Suggested name:** Reconcile the two declarations: either add the missing variants to `Tool.spec` or shrink the `toolType` enumeration to the supported subset. -### 28. Action verbs in `Client` are consistent — `src/v1/client.ts` +### 12. Action verbs in `Client` are consistent — `src/v1/client.ts` - **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. - **Category:** 17 (reversed — consistency note). -### 29. Method-name verb conventions match resource targets — `src/v1/client.ts:92,121,153,194,216,238,260,288,316,341,395,452,506,550,597` +### 13. Method-name verb conventions match resource targets — `src/v1/client.ts:92,121,153,194,216,238,260,288,316,341,395,452,506,550,597` - **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. - **Category:** 17 (positive observation). diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index 8c4c52e0..eb3676cf 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -3,14 +3,14 @@ **Path:** `packages/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 10 +**Total weird names flagged:** 8 ## Summary | Severity | Count | | --- | --- | | High | 3 | -| Medium | 3 | -| Low | 2 | +| Medium | 2 | +| Low | 1 | | Observation | 2 | ## High severity @@ -41,13 +41,7 @@ - **Suggested name:** Keep names; change type to non-optional. (Out of scope for a *naming* audit, but the optionality leaks into how the names should be interpreted.) - **Rationale:** Path-required fields must be required. Treating them as optional weakens the contract; the name `metastoreId` reads as "the metastore id" but the type says "you can omit this". -### 5. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:37` -- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate intent. -- **Category:** 1 (vague), 15 (generic field name). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Minor; flagged for cross-SDK consistency since the same constant appears in every generated client. - -### 6. `Client` — `src/v1/client.ts:42` +### 5. `Client` — `src/v1/client.ts:42` - **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. - **Category:** 1 (vague), 15 (generic). - **Suggested name:** `SystemSchemasClient`. @@ -55,24 +49,18 @@ ## Low severity -### 7. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:185` +### 6. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:185` - **Why weird:** `listSystemSchemasIter` (client.ts:185) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). - **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. - **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. -### 8. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions whose names differ by a single `Http` infix, handling very different layers (retry/rate-limit wrapper vs raw HTTP send + logging). -- **Category:** 1 (vague), 17 (inconsistent). -- **Suggested name:** `runWithCallOptions` / `sendHttp` (or `wrapCall` / `dispatchHttp`). -- **Rationale:** Same pattern across the SDK; collected for the cross-package sweep. - ## Observations -### 9. Action-verb consistency in `Client` +### 7. Action-verb consistency in `Client` Methods are `disable`, `enable`, `list` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. -### 10. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod +### 8. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), the package name (`systemschemas`), and a library term (zod's `Schema`). Multiple overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. - **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index d3f1fd0b..908c2dcc 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -91,7 +91,7 @@ 17. `EncryptionDetails` (model.ts:437) — discriminated union (one variant: `sseEncryptionDetails`). 18. `ForeignKeyConstraint` (model.ts:447) — 5 fields (`name`, `childColumns`, - `parentTable`, `parentColumns`, `rely`). + `parentTable`, `parentColumns`, `rely`). 19. `FunctionDependency` (model.ts:461) — 1 field. 20. `GetTableRequest` (model.ts:466) — 4 fields. 21. `ListTableSummariesRequest` (model.ts:477) — 6 fields. @@ -152,11 +152,11 @@ | Severity | Count | | --------------------- | ----- | -| High | 13 | -| Medium | 11 | -| Low / SDK-wide note | 7 | -| Pass / acceptable | 9 | -| **Total findings** | **40** | +| High | 11 | +| Medium | 6 | +| Low / SDK-wide note | 3 | +| Pass / acceptable | 8 | +| **Total findings** | **28** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -283,26 +283,12 @@ holds a table"), the other is about UC table classifications. **Suggested:** - Rename `TABLE_TYPE` → `TABLE` (matches the pattern: `ARRAY`, `STRUCT`, `MAP` are the same kind of compound type). -- Or document the relationship in JSDoc. **Coordinate with protocol.** --- -### 6. `ColumnTypeName.TIMESTAMP_NTZ` cryptic abbreviation — category 5 (Cryptic abbreviations) - -**Symbol:** `ColumnTypeName.TIMESTAMP_NTZ` (model.ts:25). - -**Issue:** "NTZ" is "no time zone" (a Spark/Delta abbreviation). Has no -JSDoc. A reader who has not seen the Spark dialect cannot tell what `NTZ` -means from the symbol alone. - -**Suggested:** add JSDoc to `TIMESTAMP_NTZ` clarifying `NTZ = "no time -zone"`. - ---- - -### 7. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) +### 6. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) **Symbols:** `DataSourceFormat` values (model.ts:33–75). @@ -331,7 +317,7 @@ if (format === 'MYSQL_FORMAT' || format === 'POSTGRESQL_FORMAT') {} // suffix --- -### 8. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) +### 7. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) **Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:43), `DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:70). @@ -350,46 +336,7 @@ consistent. **Not a per-package fix.** --- -### 9. `SecurableKind` values like `TABLE_DELTASHARING_OPEN_DIR_BASED` — category 5 (Cryptic abbreviations) and category 18 (Long enum values) - -**Symbol:** `SecurableKind.TABLE_DELTASHARING_OPEN_DIR_BASED` (model.ts:93). - -**Issue:** "OPEN DIR BASED" abbreviates "open-directory-based" — i.e. a -delta-sharing table backed by an open directory listing. The acronym is -unique to delta-sharing internals. No JSDoc. - -The value sits among 70+ others, most also opaque without internal -knowledge (e.g. `TABLE_DELTA_UNIFORM_ICEBERG_EXTERNAL_DELTASHARING` has -JSDoc, `TABLE_DELTASHARING_OPEN_DIR_BASED` does not). - -**Suggested:** add JSDoc to clarify. **Pass on naming** (wire-string -constraint), **flag for documentation cleanup.** - ---- - -### 10. `SecurableKind` deprecated values mixed with current — category 6 (Misleading names) and category 17 (Inconsistent action verbs) - -**Symbols:** -- `SecurableKind.TABLE_FEATURE_STORE` (model.ts:95) and - `TABLE_FEATURE_STORE_EXTERNAL` (model.ts:96) — both marked "deprecated" - in JSDoc (model.ts:94). -- `SecurableKind.TABLE_FOREIGN_HIVE_METASTORE` (model.ts:119) — also - marked deprecated. - -**Issue:** Five+ deprecated values left in the enum without `@deprecated` -JSDoc tags (only inline comments). Consumers code-completing on -`SecurableKind` see all values equally — no syntactic signal of deprecation. - -**Suggested:** -- Add `@deprecated` JSDoc tags so IDEs strike through the symbol. -- Or, more aggressively, drop the deprecated values when the next breaking - release happens. - -**Flag for SDK-wide deprecation policy.** - ---- - -### 11. `CreateTableRequest` and `TableInfo` and `UpdateTableRequest` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) +### 8. `CreateTableRequest` and `TableInfo` and `UpdateTableRequest` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) **Symbols:** `CreateTableRequest` (model.ts:287, 38 fields), `TableInfo` (model.ts:710, 36 fields), `UpdateTableRequest` (model.ts:795, 37 fields). @@ -428,51 +375,7 @@ messages map 1:1). --- -### 12. `CreateTableRequest.fullName` is server-generated — category 6 (Misleading names) - -**Symbol:** `CreateTableRequest.fullName?: string | undefined` -(model.ts:325). JSDoc: "Full name of table, in form of -__catalog_name__.__schema_name__.__table_name__". - -**Issue:** The field appears in the request *input* type but is server-output -(derived from `catalogName`, `schemaName`, `name`). A caller writing -`createTable({ fullName: 'foo.bar.baz' })` would believe they are setting -the full name; the server ignores it. No JSDoc marks the field as -output-only. - -Same applies to `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, -`tableId`, `metastoreId`, `deletedAt`, `pipelineId`, `dataAccessConfigurationId`, -`deltaRuntimePropertiesKvpairs`, `effectivePredictiveOptimizationFlag` — -all server-output but exposed on the input type. Same critique applies to -`UpdateTableRequest`. - -**Suggested:** mark with JSDoc `@readonly` and add a sentence "Output only; -ignored on input." Or restructure types (finding 11). **Coordinate with -generator.** - ---- - -### 13. `CreateTableRequest.tableConstraints` not used on input — category 6 (Misleading names) and category 7 (Overly verbose) - -**Symbol:** `CreateTableRequest.tableConstraints?: TableConstraint[] | undefined` -(model.ts:317). JSDoc: "List of table constraints. Note: this field is not -set in the output of the __listTables__ API." - -**Issue:** The JSDoc note is structured oddly: it explains the field's -*output* behaviour, but the field appears in the *input* type. Combined -with the existence of a separate `createTableConstraint` method -(client.ts:147), the typical workflow is: -1. Call `createTable` (without constraints). -2. Call `createTableConstraint` (one per constraint). - -So `CreateTableRequest.tableConstraints` is also an unusual input — the -server might or might not honour it depending on the deployment. - -**Suggested:** clarify JSDoc on input behaviour; possibly mark deprecated. - ---- - -### 14. `CreateTableRequest.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) +### 9. `CreateTableRequest.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) **Symbol:** `CreateTableRequest.enablePredictiveOptimization?: string | undefined` (model.ts:321). Same field on `TableInfo` (model.ts:744) and @@ -489,14 +392,13 @@ also a `string` with the same domain. **Suggested:** - Type as an enum (e.g. `PredictiveOptimizationFlag = 'ENABLE' | 'DISABLE' | 'INHERIT'`). -- Or document the accepted values in JSDoc. **Coordinate with protocol.** Cross-reference `catalogs/v1` which has the same field. --- -### 15. `CreateTableRequest.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) +### 10. `CreateTableRequest.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) **Symbol:** `CreateTableRequest.dataAccessConfigurationId?: string | undefined` (model.ts:327). 28 chars. Same field on `TableInfo` (model.ts:750) and @@ -515,24 +417,7 @@ choice. **Pass with note.** --- -### 16. `CreateTableRequest.browseOnly` is server-output but appears in request — category 6 (Misleading names) - -**Symbol:** `CreateTableRequest.browseOnly?: boolean | undefined` -(model.ts:348). JSDoc: "Indicates whether the principal is limited to -retrieving metadata for the associated object through the BROWSE privilege -when include_browse is enabled in the request." - -**Issue:** Server-output field on an input type, again. The JSDoc is also -describing the server's behaviour ("when include_browse is enabled in the -request") which is a different request entirely. Confusing because the -field's *meaning* depends on context. - -**Suggested:** mark `@readonly` and add a one-line "Output only." Or move -to `TableInfo` only. - ---- - -### 17. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* +### 11. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* **Symbol:** `ListTablesRequest.maxResults?: number | undefined` (model.ts:527), JSDoc: "Maximum number of tables to return. If not set, all @@ -545,7 +430,7 @@ deprecated. The naming is fine; the API behaviour is the issue. --- -### 18. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` defined in three packages — category 12 (Duplicate concepts) +### 12. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` defined in three packages — category 12 (Duplicate concepts) **Symbols:** - This file: `Dependency` (model.ts:412), `DependencyList` (model.ts:422), @@ -565,7 +450,7 @@ from each service package. **Strong SDK-wide cleanup.** --- -### 19. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) +### 13. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) **Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:240). JSDoc: "Ordinal position of column (starting at position 0)." @@ -577,27 +462,7 @@ field name that it's 0-indexed. The JSDoc clarifies. --- -### 20. `RowFilter.functionName` vs `RowFilter.inputColumnNames` vs `RowFilter.inputArguments` plural mismatch — category 9 (Singular/plural mismatch) and category 17 (Inconsistent action verbs) - -**Symbols:** `RowFilter.functionName?: string` (model.ts:633), -`RowFilter.inputColumnNames?: string[]` (model.ts:638), -`RowFilter.inputArguments?: PolicyFunctionArgument[]` (model.ts:644). - -**Issue:** Naming is consistent for arrays (`columnNames`, `arguments` — -both plural). But: -- `inputColumnNames` is **deprecated** per JSDoc ("This is the replacement - of the deprecated input_column_names field" — model.ts:641); the - replacement is `inputArguments`. -- The deprecated field name still exists in the TS surface and is - generated/marshalled. - -**Suggested:** mark `inputColumnNames` with `@deprecated`. Cross-reference -`ColumnMask.usingColumnNames` (model.ts:266) which has the same -deprecation note. - ---- - -### 21. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* +### 14. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `OptionSpec.isRequired` (model.ts:584), `OptionSpec.isSecret` (model.ts:586), `OptionSpec.isHidden` (model.ts:588), @@ -615,7 +480,7 @@ correctly may want a richer type. **Note for upstream.**) --- -### 22. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 15. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` (model.ts:429). JSDoc: "Whether predictive optimization should be enabled @@ -623,14 +488,14 @@ for this object and objects under it." **Issue:** The type's *purpose* is to indicate whether PO is enabled. The field name `value` says nothing about that. The type is also a `string` -(not a `boolean`) — same problem as finding 14. +(not a `boolean`) — same problem as finding 9. **Suggested:** type the field as a boolean (or a constrained enum matching the JSDoc's "enabled" sense). **Coordinate with protocol team.** --- -### 23. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) +### 16. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) **Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` (model.ts:431), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` @@ -645,13 +510,13 @@ three fields. --- -### 24. `Client` class name — category 1 (Vague/generic) — *pass* +### 17. `Client` class name — category 1 (Vague/generic) — *pass* Package convention. **Pass.** --- -### 25. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* +### 18. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* Standard `{verb}{Resource}` shape. Convention. **Pass.** @@ -662,72 +527,19 @@ level.**) --- -### 26. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* +### 19. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* Same `{verb}{Resource}` pattern. **Pass.** --- -### 27. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* +### 20. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* Standard. **Pass.** --- -### 28. `PACKAGE_SEGMENT` SCREAMING_SNAKE — category 4 (Underscores in TS identifiers) - -**Symbol:** `PACKAGE_SEGMENT` (client.ts:55). - -**Issue:** Google TS Style Guide § 5.1 reserves `UPPER_SNAKE_CASE` for true -primitive constants (`MAX_LEN = 10`). `PACKAGE_SEGMENT` is a runtime -object literal `{ key, value }` constructed from a JSON import. The same -identifier is used in every package's `client.ts`. - -**Suggested:** `packageSegment` or `clientPackageSegment`. **Flag for -SDK-wide cleanup.** - ---- - -### 29. `HttpCallOptions` interface — category 1 (Vague/generic) and category 20 (Type-suffix tautology) - -**Symbol:** `HttpCallOptions` (utils.ts:15). - -**Issue:** "HttpCall" is not a concept that exists elsewhere in the SDK; -the file also imports `CallOptions` from `@databricks/sdk-options/call` -(utils.ts:12). Two `…CallOptions` types side by side, with one being the -HTTP-layer context and the other the public retry/rate-limit options. - -**Suggested:** `HttpRequestContext` or `ExecuteHttpArgs`. **Flag for -SDK-wide cleanup** — generated boilerplate. - ---- - -### 30. `executeCall` vs `executeHttpCall` verb collision — category 17 (Inconsistent action verbs) - -**Symbols:** `executeCall` (utils.ts:26), `executeHttpCall` (utils.ts:65). - -**Issue:** Two functions named `execute…Call` that operate at different -layers. The names imply a hierarchical relationship that does not exist. - -**Suggested:** rename `executeHttpCall` to `sendAndDecode` or -`doHttpRequest`. **Flag for SDK-wide cleanup.** - ---- - -### 31. `buildHttpRequest`, `readAll`, `flattenQueryParams` — *pass* - -Verb-prefixed. Naming is fine. `flattenQueryParams` is used by the -multi-query-param list methods (client.ts:357, 444). - -(Cross-check: this package *does* use `flattenQueryParams` indirectly via -the manual `URLSearchParams` construction in `listTables`/`listTableSummaries` -client.ts:311/393. Hmm, actually it doesn't import the helper. Manual -construction with `params.append(...)` is duplicated 14 times across the -file.) - ---- - -### 32. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* +### 21. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, `TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide @@ -735,7 +547,7 @@ pattern. **Pass.** --- -### 33. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* +### 22. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* **Symbols:** `Dependency.value.$case` literals (model.ts:414–417). @@ -756,18 +568,7 @@ their $case literals. --- -### 34. `parseResponse` ignores `Content-Type` — category 6 (Misleading names) — *pass with note* - -**Symbol:** `parseResponse` (utils.ts:113) does `JSON.parse(text)` -unconditionally. The name implies it can handle any response shape; in -practice it only handles JSON. - -**Suggested:** rename `parseJsonResponse` to set caller expectations. -**Pass — generated boilerplate.** - ---- - -### 35. `_PropertiesEntry` / `_Response` underscore-suffixed proto-nested type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) +### 23. `_PropertiesEntry` / `_Response` underscore-suffixed proto-nested type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) **Symbols:** `CreateTableRequest_PropertiesEntry` (model.ts:359), `DeleteTableConstraintRequest_Response` (model.ts:383), @@ -800,7 +601,7 @@ the proto definition. --- -### 36. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:209, 222 +### 24. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:209, 222 **Why:** Underscore-separated `OuterMessage_InnerEnum` naming is a literal transcription of proto nested-enum scoping. The infix `_` and the @@ -820,7 +621,7 @@ non-idiomatic shape. --- -### 37. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:563 +### 25. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:563 **Why:** `Spec` is a generic config-style suffix that re-appears across the file (`SecurableKindManifest`, `EffectivePredictiveOptimizationFlag`, @@ -837,7 +638,7 @@ struct describing X" — a proto convention, not a TS one. --- -### 38. `SecurableKindManifest` type name — file:line model.ts:648 +### 26. `SecurableKindManifest` type name — file:line model.ts:648 **Why:** `Manifest` is a config-style suffix (analogous to `Spec`/`Config`). It tags the type as a descriptor message rather than a domain concept. @@ -853,7 +654,7 @@ adds no information beyond "this is the descriptor". --- -### 39. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:233, 710, 787 +### 27. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:233, 710, 787 **Why:** `Info` and `Summary` are generic descriptor-suffixes used to distinguish the wire/RPC message from the domain noun (`Column`, `Table`). @@ -863,7 +664,7 @@ repeated config-suffix pattern. **Category:** proto-architectural-leak (repeated `Info` config-suffix). **Suggested:** `Column`, `Table`, `TableOverview` (or collapse all three -into `Table` per finding #11). +into `Table` per finding #8). **Rationale:** in a TS surface the noun *is* the type; the `Info`/`Summary` tag exists only to disambiguate from the proto request/response messages @@ -871,7 +672,7 @@ and from server-internal representations — a generator/architectural leak. --- -### 40. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:437, 662 +### 28. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:437, 662 **Why:** Two `…Details` types in the same file. `Details` is a generic "descriptor" suffix with no domain meaning — same family as `Info`/`Spec`. @@ -947,34 +748,14 @@ and naming. --- -### G. Three-tier table-type confusion - -This package, `onlinetables`, `database`, `postgres`, and `featurestore` -all model "table" concepts at different layers: -- `tables.TableType` (model.ts:189) — 9 values for UC table classifications. -- `tables.SecurableKind` (model.ts:78) — 70+ values, mostly `TABLE_*` - prefixes for finer-grained UC kinds. -- `onlinetables.OnlineTableState` — the lifecycle/sync state of an - online table (overlaps with `TableType.MATERIALIZED_VIEW`, - `STREAMING_TABLE`). -- `database.SyncedTableState`, `postgres.SyncedTableState` — same as - `OnlineTableState`, renamed. - -The relationships between `TableType.MATERIALIZED_VIEW`, -`SecurableKind.TABLE_MATERIALIZED_VIEW`, `OnlineTableState.ONLINE`, etc., -are non-obvious without reading the JSDoc on each enum. **SDK-wide -documentation pass needed.** - ---- - ## Counts by severity | Severity | Count | Findings | | -------- | ----- | -------- | -| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics, proto-architectural leaks) | 13 | #1, #4, #11, #12, #14, #18, #22, #28, #36, #37, #38, #39, #40 | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 11 | #2, #5, #6, #7, #8, #9, #10, #13, #15, #20, #35 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 7 | #3, #16, #23, #29, #30, #33, #34 | -| **Pass / acceptable** | 9 | #17, #19, #21, #24, #25, #26, #27, #31, #32 | +| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics, proto-architectural leaks) | 11 | #1, #4, #8, #9, #12, #15, #24, #25, #26, #27, #28 | +| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 6 | #2, #5, #6, #7, #10, #23 | +| **Low / SDK-wide note** (generator boilerplate, not local fix) | 3 | #3, #16, #22 | +| **Pass / acceptable** | 8 | #11, #13, #14, #17, #18, #19, #20, #21 | --- @@ -983,12 +764,12 @@ documentation pass needed.** 1. **#1** — fix `DeltaRuntimePropertiesKvpairs` (field) / `DeltaRuntimePropertiesKvPairs` (type) casing mismatch. Local, mechanical rename. -2. **#14** — type `enablePredictiveOptimization` as a real enum instead of +2. **#9** — type `enablePredictiveOptimization` as a real enum instead of a free-form string. Improves type safety. -3. **#22** — type `EffectivePredictiveOptimizationFlag.value` as a real - boolean/enum instead of a free-form string. Same family as #14. -4. **#35** — eliminate `_Response` empty bodies and `_PropertiesEntry` +3. **#15** — type `EffectivePredictiveOptimizationFlag.value` as a real + boolean/enum instead of a free-form string. Same family as #9. +4. **#23** — eliminate `_Response` empty bodies and `_PropertiesEntry` map-entry shells. Local type-level cleanup. -5. **#36 / #37 / #38 / #39 / #40** — drop proto-architectural type-name +5. **#24 / #25 / #26 / #27 / #28** — drop proto-architectural type-name suffixes (`_OauthStage`, `Spec`, `Manifest`, `Info`/`Summary`, `Details`) in favour of bare domain nouns. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 6e31c541..6a0561bc 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -3,14 +3,14 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 **Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. -**Total weird names flagged:** 24 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 11 | -| Low | 4 | +| Medium | 2 | +| Low | 0 | | Observation | 3 | ## High severity @@ -59,110 +59,26 @@ - **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. - **Rationale:** Rule 9 demands the flag even when intentional. -### 8. `executeCall` vs. `executeHttpCall` — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions named "execute". `executeCall` wraps retry/rate-limit policy; `executeHttpCall` does the actual HTTP send. In every client method both appear: - ```ts - const call: Call = async (callSignal?: AbortSignal): Promise => { - ... - const respBody = await executeHttpCall({...}); - }; - await executeCall(call, options); - ``` - Names do not reveal the layering. -- **Category:** 1 (vague), 12 (duplicate concept — both "execute"), 17 (inconsistent layering name). -- **Suggested name:** `runWithPolicies(call, options)` for outer, `sendHttpRequest(opts)` for inner. -- **Rationale:** Layering should be readable from names. Generator-wide concern. - -### 9. `Call` type and `call` variable — `src/v1/client.ts:74,98,118,152,201` and `src/v1/utils.ts:27` -- **Why weird:** Variable `call` of type `Call`, passed to `executeCall`. Same word as variable, type, and verb. Inside one method scope we have `req`, `call`, `httpReq`, `resp` — four roles, three of which abbreviate. -- **Category:** 1 (vague), 12 (duplicate concept). -- **Suggested name:** `runRequest`/`sendRequest` for the variable; keep `Call` as the type. -- **Rationale:** Variable-type collisions are tolerable but obscure prose. - -### 10. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` +### 8. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` - **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. - **Category:** 6 (misleading — silent malformed URLs). - **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. - **Rationale:** See #6. Generator-wide concern. -### 11. `respBody` (bytes) vs. `resp` (parsed) — `src/v1/client.ts:78-83,122-128,156-161,211-216` -- **Why weird:** `respBody: Uint8Array` and `resp: TagAssignment` differ only by suffix. Both abbreviate "response"; the reader must remember which is bytes and which is parsed. There is no `reqBody` sibling for symmetry. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistency — only response abbreviates with `Body`). -- **Suggested name:** `rawBody`/`result`, or `responseBytes`/`response`. -- **Rationale:** Stage differences should be communicated by meaningful nouns, not suffix variations. - -### 12. `httpReq` local variable — `src/v1/client.ts:77,101,121,155,204` -- **Why weird:** Inside methods that already have `req: `, a second variable `httpReq: HttpRequest` shares the `req` root. Two `req`s in the same scope. -- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept — two `req`s). -- **Suggested name:** `httpRequest` (no abbreviation), or `wireRequest`. -- **Rationale:** Forking the same identifier across layers is hard to read. - -### 13. `pageReq` clone variable in paginated list — `src/v1/client.ts:174` -- **Why weird:** A clone of `req` is named `pageReq`. The `Req` abbreviation gets re-applied with a `page` modifier; outer `req` is the parameter. -- **Category:** 5 (cryptic), 8 (redundant prefix — `page` in a pagination loop is implicit). -- **Suggested name:** `current` or `cursor` (describes its role as iterator state). -- **Rationale:** A variable that mutates a clone of the input should describe its role. - -### 14. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** Type called `Options` but it is an internal context bag (request + http client + logger), not a user-tunable options struct. The user-facing options type is `CallOptions` (different file). Two different `Options` types for two different concepts. -- **Category:** 1 (vague suffix `Options`), 8 (redundant suffix — internal bags should not be called `Options`). -- **Suggested name:** `HttpCallContext` or `HttpCallArgs`. -- **Rationale:** Reserve `Options` for caller-tunable knobs; use `Context`/`Args` for internal bags. - -### 15. `buildHttpRequest` is just object-spread — `src/v1/utils.ts:96` -- **Why weird:** Pure object-literal-with-optional-fields helper named "build". "Build" suggests builder-pattern construction; the function just spreads fields into a struct. -- **Category:** 1 (vague — "build" suggests heavyweight construction), 6 (misleading — implies builder pattern). -- **Suggested name:** `makeHttpRequest` or inline at call sites. -- **Rationale:** "Build" carries Java/JS Builder-pattern connotations. - -### 16. `AuthHttpClient` — `src/v1/transport.ts:43` -- **Why weird:** Class name encodes its implementation pattern: it is an `HttpClient` whose role is "wraps another HttpClient and injects auth headers". The JSDoc on line 42 literally reads "Wraps an HttpClient and adds authentication headers to requests." That is the Decorator/Wrapper architectural pattern leaking into the type name. The name describes the *how* (HTTP client decorator), not the *what* (authenticated transport). -- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` style class whose name advertises a decorator implementation rather than the domain role. -- **Suggested name:** `AuthenticatingTransport`, `AuthenticatedTransport`, or `AuthInjector`. Drops the `HttpClient` infix that just restates the base interface it decorates. -- **Rationale:** A class whose only job is to add auth headers should be named for that job, not the wrapping mechanism. Sister packages all duplicate this class verbatim — generator-wide concern. - -### 17. `TimeoutHttpClient` — `src/v1/transport.ts:61` -- **Why weird:** Same wrapper-name pattern as #16. JSDoc line 60: "Wraps an HttpClient and applies a default timeout to requests." Name encodes the wrapping mechanism (`HttpClient` suffix) plus the cross-cutting concern (`Timeout` prefix). Reads as `` — a classic Decorator naming tell. -- **Category:** proto-architectural-leak — `Wrapper`/`Adapter` class whose name advertises a decorator-of-HttpClient implementation rather than the domain role. -- **Suggested name:** `TimeoutTransport`, `RequestTimeout`, or merge the timeout behavior into the base `newFetchHttpClient` so a separate type is unneeded. -- **Rationale:** `TimeoutHttpClient` is two architectural words concatenated: the concern (`Timeout`) and the wrapped interface (`HttpClient`). Domain names should describe behavior, not the OO pattern. Generator-wide concern — every package repeats this. - ## Low severity -### 18. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Exported but unused in `client.ts`. This package's `listTagAssignments` uses individual `params.append(...)` calls (line 142-148) instead. Dead-shaped helper in shared scaffolding. -- **Category:** 6 (misleading — implies the package uses it). -- **Suggested name:** N/A — should not live here at all. Belongs in a shared utils package. -- **Rationale:** Generator-wide concern: every package duplicates this helper. - -### 19. `readAll(body)` — `src/v1/utils.ts:40` -- **Why weird:** `readAll` is too generic; the function specifically drains a `ReadableStream` into a single buffer. The name does not say "drain a stream into a buffer". -- **Category:** 1 (vague), 5 (cryptic — `readAll` is JS-conventional but not self-describing). -- **Suggested name:** `drainStream` or `readStreamToUint8Array`. -- **Rationale:** Reads like it might take a file path or array. - -### 20. `PACKAGE_SEGMENT` — `src/v1/client.ts:36` -- **Why weird:** `SEGMENT` is unspecific; the value is `{key, value}` for the User-Agent identity. The single word "segment" provides no domain context. -- **Category:** 1 (vague — `Segment` of what?). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `PACKAGE_USER_AGENT_ID`. -- **Rationale:** Comment above the constant does the work the name should. - -### 21. `tagValue` field doc empty — `src/v1/model.ts:53,54` -- **Why weird:** `tagValue?: string | undefined` is documented as "The value of the tag" — a tautology. Compare the rich docs on `entityType`/`entityId`/`tagKey` (with character-class rules). The doc is doing zero work. -- **Category:** 1 (vague — doc says nothing the field name does not), 15 (generic field doc). -- **Suggested name:** Document what makes a `tagValue` valid (max length? character set? same restrictions as `tagKey`?). -- **Rationale:** Asymmetric documentation: three fields have rules, one is silent. +_None._ ## Observations -### 22. Action verb consistency +### 9. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 23. `tagassignments` lowercase package name vs. types and HTTP path +### 10. `tagassignments` lowercase package name vs. types and HTTP path The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). -### 24. Domain leakage between sister packages +### 11. Domain leakage between sister packages Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md index 762e64e6..8d3337c3 100644 --- a/.agent/naming-audit/tagpolicies.md +++ b/.agent/naming-audit/tagpolicies.md @@ -3,14 +3,14 @@ **Path:** `packages/tagpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and an optional `id`/timestamps so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. -**Total weird names flagged:** 16 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 4 | -| Low | 3 | +| High | 4 | +| Medium | 2 | +| Low | 1 | | Observation | 4 | ## High severity @@ -33,13 +33,7 @@ - **Suggested name:** `TagPoliciesClient` (matches the package name) or `GovernedTagsClient` (matches domain language). - **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing on every co-use (`import {Client as TagPoliciesClient} from '@databricks/sdk-tagpolicies'`). Generator-level concern. -### 4. `tagKey` is both the resource identifier and a field on `TagPolicy` — `src/v1/model.ts:37` and `model.ts:13,17` -- **Why weird:** The thing that uniquely identifies a `TagPolicy` is its `tagKey` (string), but the same type *also* has an `id: string` field (`model.ts:38`). The wire URL is `/api/2.1/tag-policies/{tagKey}` — i.e., the path key is `tagKey`, not `id`. Two identifiers, no JSDoc saying which one is authoritative. Compare to `BudgetPolicy` (`policyId`, `policyName`) which has the same split — same problem. -- **Category:** 1 (vague — which field actually identifies the resource?), 6 (misleading — `id` looks like a primary key, but the URL uses `tagKey`), 19 (underspecified ID — what does `id` mean if the path uses `tagKey`?), 16 (field contradicts type domain). -- **Suggested name:** Document both fields explicitly. `tagKey` is the user-chosen primary key (the tag name itself); `id` is presumably an opaque server-generated handle. Suggest: keep both but JSDoc each, OR collapse to just `tagKey` if `id` is dead. -- **Rationale:** Two unlabeled IDs in a type is a recipe for caller confusion. The SDK should make plain which is the resource key. - -### 5. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:13,17` +### 4. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:13,17` - **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${this.host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:97,116`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). - **Category:** 6 (misleading — type says optional, semantics says required), 19 (underspecified ID — what should `tagKey` look like? Constraints? Encoding?). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) on get/delete/update. Add JSDoc describing valid keys. @@ -47,64 +41,40 @@ ## Medium severity -### 6. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:20` vs. `model.ts:36` +### 5. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:20` vs. `model.ts:36` - **Why weird:** Plural only on list endpoint; singular elsewhere. The list response is `ListTagPoliciesResponse` (plural). The wire path is `/tag-policies` (plural). The convention is consistent with the Go SDK, but worth flagging that the resource name on the wire is plural while the item type is singular. - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary within one type family). - **Suggested name:** Keep as is (cross-SDK convention). Listed for completeness under rule 9. - **Rationale:** Same as in `entitytagassignments` audit — flagged because rule 9 demands it. -### 7. Create/update wrap the subject in a body field while the list response also wraps in an array field — `src/v1/model.ts:9,32,48` +### 6. Create/update wrap the subject in a body field while the list response also wraps in an array field — `src/v1/model.ts:9,32,48` - **Why weird:** `CreateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) and `UpdateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) both put the subject inside a one-field body. `ListTagPoliciesResponse.tagPolicies: TagPolicy[]` does the analogous thing for the response. Each wrapper is a single-field envelope around the actual payload, which means every caller writes `client.create({tagPolicy: {...}})` instead of `client.create({...})`. The envelope is consistent in cardinality (singular/plural matches the type), but it adds a level of indirection on every call. - **Category:** 17 (inconsistency — request and response both wrap, but callers must remember the wrapper field name on each side). - **Suggested name:** N/A — the wrapper envelopes are dictated by wire-side proto shape. Flagged as a generator-level consideration. - **Rationale:** Single-field body envelopes show up across the generated SDK; this package is one instance. -### 8. `executeCall` vs. `executeHttpCall` confusion — `src/v1/utils.ts:26,65` -- **Why weird:** Two near-identical names with different purposes. `executeCall(call, options)` runs a `Call` through the retrier/rate-limiter; `executeHttpCall(opts)` issues a single HTTP request and reads the body. The names differ by one word (`Http`) but the responsibilities are radically different (orchestrator vs. transport). A user grepping for "execute" can't tell which one to use. -- **Category:** 1 (vague — the disambiguator is too thin), 17 (inconsistent verb scoping). -- **Suggested name:** `executeCall` (orchestrator) and `sendHttpRequest` (single-request transport). -- **Rationale:** Distinct responsibilities should have distinct verb roots, not a same-verb-different-noun split. - -### 9. `flattenQueryParams` exported but unused — `src/v1/utils.ts:123` -- **Why weird:** Exported helper that this client does not invoke (the list endpoint uses individual `params.append(...)` calls instead — see `client.ts:143,146`). Dead-code-shaped helper. -- **Category:** 6 (misleading — implies the package uses it), 1 (vague — `flatten` is generic; this specific one only handles a subset of types). -- **Suggested name:** N/A — should live in a shared utils package, not be copied into every package. -- **Rationale:** Generator-wide concern: every package duplicates this helper, often without using it. - ## Low severity -### 10. `Temporal.Instant` for timestamps — `src/v1/model.ts:42,44` -- **Why weird:** Uses `Temporal.Instant` (from `@js-temporal/polyfill`), which is a great future-proof choice — but `Instant` is unfamiliar to most JS devs (who expect `Date` or string). The doc says "Timestamp when the tag policy was created" without explaining why it's an `Instant`. -- **Category:** 1 (slightly vague choice without doc support), 5 (cryptic to readers unfamiliar with Temporal proposal). -- **Suggested name:** Keep `Temporal.Instant`; add JSDoc explaining the type choice. -- **Rationale:** Generator-wide; flagged once. - -### 11. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:22-25` +### 7. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:22-25` - **Why weird:** JSDoc says "The maximum value is 1000; values above 1000 will be coerced down to 1000." but the field is typed `number | undefined`. A caller passing `pageSize: 100000` silently gets clipped to 1000. The constraint travels only via the docstring. - **Category:** 6 (misleading — type does not match contract). - **Suggested name:** Keep `pageSize`; consider a branded type or a runtime validator. At minimum, restate the limit clearly. - **Rationale:** Generator-wide; flagged because docs lie about wire behaviour. -### 12. `updateMask` field type `FieldMask` — `src/v1/model.ts:49` -- **Why weird:** `FieldMask` is a generic type carrying the masked-shape as a type parameter. The name `updateMask` is wire-standard (proto FieldMask) but cryptic to TS users — "mask" usually means a bitmask. The JSDoc is missing. -- **Category:** 5 (cryptic — `mask` for TS users means bitmask), 14 (proto-style — FieldMask is a proto concept). -- **Suggested name:** Keep `updateMask`; add JSDoc explaining it's a path-based selector for partial updates. -- **Rationale:** Generator-wide name; flag once. - ## Observations -### 13. Action verb consistency +### 8. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 14. Acronym casing +### 9. Acronym casing File uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri` casing clashes encountered within the file. - **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). -### 15. `tagpolicies` lowercase package name +### 10. `tagpolicies` lowercase package name Package directory is `tagpolicies` (single token, no separator), but every type uses `TagPolicy*` and the HTTP path uses `tag-policies`. Same problem as `dataclassification`, `tagassignments`, `entitytagassignments` — SDK-wide convention issue. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). -### 16. Domain leakage from sister packages +### 11. Domain leakage from sister packages Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — all collide on the noun "tag". Each ships its own `Client`, its own `tag*` types, and its own `tagKey`. Co-import requires extensive aliasing. `tagpolicies` differs in that it defines the *policy* over the tag, while the assignment packages attach a `tagKey` + `tagValue` to entities — but a user can't tell from the name; "tag policies" sounds like it could be policies *for* tag assignments. - **Category:** 12 (duplicate concept across siblings). diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index 9e854454..0a5ad6dc 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -3,14 +3,14 @@ **Path:** `packages/tokenmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/create-on-behalf-of/delete arbitrary user tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. -**Total weird names flagged:** 11 +**Total weird names flagged:** 8 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 4 | -| Low | 3 | +| Medium | 2 | +| Low | 2 | | Observation | 0 | ## High severity @@ -47,19 +47,7 @@ - **Suggested name:** Either expose a single `filter` string or document mutual exclusivity. At minimum, JSDoc the AND/OR semantics. - **Rationale:** Consumer-facing API ambiguity. -### 6. `ownerId` vs `createdById` — both are user IDs, on the same struct, no docs distinguishing semantics beyond JSDoc -- **Why weird:** `AdminTokenInfo` has `createdById` ("User ID of the user that created the token", `model.ts:15`) and `ownerId` ("User ID of the user that owns the token", `model.ts:19`). What's the difference? In the sibling `tokens` package, the type has no `ownerId`. This appears to be admin-only metadata where ownership can transfer (e.g., on-behalf-of tokens). A reader has no way to know without external docs whether the two are usually equal. -- **Category:** 1 (vague — relationship unstated), 19 (underspecified IDs in same struct). -- **Suggested name:** Keep names but add JSDoc clarifying when they diverge (e.g., on-behalf-of tokens: creator is the principal who called the API, owner is the service principal). -- **Rationale:** Discoverability. - -### 7. `workspaceId` on `AdminTokenInfo` — only meaningful for account-level scope -- **Why weird:** `workspaceId?: number | undefined` (`model.ts:21`) is documented "If applicable, the ID of the workspace that the token was created in." So it's optional and only meaningful at the account level. But the package and the URL path `/api/2.0/token-management/...` is a workspace endpoint. The field thus carries no useful signal at this endpoint, yet it's exposed. -- **Category:** 6 (misleading — looks pertinent, often vestigial). -- **Suggested name:** Keep; document under what circumstances it is populated (e.g., when the same model is reused at the account API). -- **Rationale:** Generator artefact from sharing models across workspace/account scopes. Flag for upstream cleanup. - -### 8. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name +### 6. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name - **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:27`. Industry shorthand is "OBO" but the SDK avoids the acronym. - **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). - **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. @@ -67,19 +55,13 @@ ## Low severity -### 9. `Client` class is named `Client` (no namespacing) +### 7. `Client` class is named `Client` (no namespacing) - **Why weird:** `export class Client` (`client.ts:44`). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. - **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). - **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). - **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. -### 10. `PACKAGE_SEGMENT` constant — vague label -- **Why weird:** `const PACKAGE_SEGMENT = {...}` (`client.ts:39`). "Segment" is CS jargon; the comment one line up explains it's "the User-Agent identity segment". Without the comment, the constant name doesn't communicate that. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT` or `USER_AGENT_PKG`. -- **Rationale:** Minor; identical issue in every generated package. - -### 11. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory +### 8. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory - **Why:** The package's directory and npm name `tokenmanagement` ends in `management`, which sits in the `Manager`/`Handler`/`Controller`/`Processor` family of architectural-tier suffixes. The package does not contain a "management" concept; it contains operations on tokens (list, get, create-on-behalf-of, delete). The `-management` suffix is service-side scaffolding language (cf. proto `TokenManagementService`) that leaks out via the URL path `/api/2.0/token-management/...` and into the SDK package name. Compare to peers in the SDK where the action package is named after the domain noun (`tokens`, `clusters`, `secrets`), not the service tier. - **Category:** Proto-architectural-leak — `Manager`/`Handler`/`Controller`/`Processor`/`-management` family (architectural label not in the domain). - **Suggested:** `tokenadmin` — keeps the audience-disambiguation from sibling `tokens` but uses an audience noun rather than an architectural verb. See finding #1 which proposes the same package rename for the collision-avoidance reason. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index e793a81e..34e9ec88 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -3,15 +3,15 @@ **Path:** `packages/tokens/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share a near-identical "token info" record, but the auth/audience boundary makes them distinct services. -**Total weird names flagged:** 20 +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | | High | 5 | -| Medium | 5 | -| Low | 6 | -| Observation | 4 | +| Medium | 2 | +| Low | 1 | +| Observation | 2 | ## High severity @@ -54,23 +54,13 @@ ## Medium severity -### 6. `UpdateTokenRequest.tokenId` doc says "SHA-256 hash" but other types say "ID" — `model.ts:57` -- **Why weird:** Doc on `UpdateTokenRequest.tokenId`: "The SHA-256 hash of the token to be updated." But every other `tokenId` doc in the package (and in `tokenmanagement`) says variants of "The ID of the token". So readers comparing the types see: - - `CreateTokenRequest_Response.tokenInfo.tokenId` (line 25 → `PublicTokenInfo.tokenId` line 39) — "The ID of this token." - - `PublicTokenInfo.tokenId` (line 39) — "The ID of this token." - - `RevokeTokenRequest.tokenId` (line 50) — "The ID of the token to be revoked." - - `UpdateTokenRequest.tokenId` (line 57) — "The SHA-256 hash of the token to be updated." -- **Category:** 6 (misleading doc — same field, different meaning), 13 (inconsistency), 19 (underspecified ID — what is it actually?). -- **Suggested name:** Either (a) reconcile the docs — if `tokenId` is the SHA-256 hash everywhere, say so consistently; or (b) if `UpdateTokenRequest.tokenId` actually expects a different format than the others, rename or document the divergence loudly. -- **Rationale:** The doc disagreement implies either a stale comment or a real wire-protocol quirk. Either way, a caller can't tell which. - -### 7. `UpdateTokenRequest` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:56-62` +### 6. `UpdateTokenRequest` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:56-62` - **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:171`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenRequestSchema` on `model.ts:146-159`). - **Category:** 12 (duplicate concept), 6 (misleading — which one is authoritative?), 11 (the inner one is dead-ish data). - **Suggested name:** Drop one. Either: (a) make `token` exclude `tokenId` (`Omit`) and keep the top-level; or (b) drop the top-level and use `req.token.tokenId` in the client. - **Rationale:** Two fields for the same identifier invite subtle bugs (server may pick the inner one if the top-level is empty). -### 8. `Client` class name — colliding namespace — `client.ts:46` +### 7. `Client` class name — colliding namespace — `client.ts:46` - **Why weird:** Top-level class literally named `Client`. Re-exported in `index.ts` as just `Client`. A consumer importing from both `@databricks/sdk-tokens/v1` and `@databricks/sdk-tokenmanagement/v1` faces an identical name clash: ``` import {Client} from '@databricks/sdk-tokens/v1'; @@ -81,68 +71,20 @@ - **Suggested name:** `TokensClient`, `UserTokensClient`, or `MyTokensClient`. Mirror with `TokenManagementClient`/`AdminTokensClient`. - **Rationale:** Same finding as `rfa#37`, recurs across all packages — but particularly painful here given the `tokens`/`tokenmanagement` overlap. -### 9. `executeCall` / `executeHttpCall` naming pair — `utils.ts:26,65` -- **Why weird:** Two functions distinguished only by an `Http` infix. `executeCall` wraps retry/rate-limit/timeout; `executeHttpCall` does the actual fetch + logging + error throw. Easy to confuse at call site (`client.ts:87,115` use them within four lines of each other). -- **Category:** 1 (vague), 17 (inconsistent action verbs). -- **Suggested name:** `runWithCallOptions` / `sendHttp`, or `wrapCall` / `dispatchHttp`. -- **Rationale:** Cross-package: same as `rfa#32`, recurs everywhere. - -### 10. `HttpCallOptions` shadows package's other `Options` types — `utils.ts:15` -- **Why weird:** The file imports `Options` from `@databricks/sdk-core/api` (line 3) and `CallOptions` from `@databricks/sdk-options/call` (line 12). Three `Options`-suffixed types in scope. `HttpCallOptions` is internal — purely a context bag passed to `executeHttpCall`. -- **Category:** 1 (vague suffix). -- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). -- **Rationale:** Same as `rfa#33`. - ## Low severity -### 11. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:168` +### 8. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:168` - **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateTokenRequest` payloads must learn this helper. -- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #17 re-export gap). +- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #9 re-export gap). - **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. - **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. -### 12. `readAll` — generic helper name — `utils.ts:40` -- **Why weird:** Internal helper name is generic; clashes cognitively with `Array.prototype` / stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `readStreamToEnd` / `drainStream`. -- **Rationale:** Same as `rfa#34`. - -### 13. `flattenQueryParams` — `utils.ts:123` -- **Why weird:** Exported but unused in this package (`client.ts` only ever builds JSON bodies). Dead-looking export. -- **Category:** Observation / 11 (unused public helper). -- **Suggested name:** Remove from utils if it's a generator default; or keep, but stop emitting it for body-only services. -- **Rationale:** Same as `rfa#35`. - -### 14. `PACKAGE_SEGMENT` constant — `client.ts:41` -- **Why weird:** `Segment` is a generic word; without the inline comment the constant doesn't communicate User-Agent identity. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Same as `rfa#36`. - -### 15. `buildHttpRequest` parameter list — five positional args — `utils.ts:96-102` -- **Why weird:** Five positional parameters (`method`, `url`, `headers`, `signal`, `body`) with the optional ones at the end. Callers in `client.ts:86,114,144,177` pass them positionally; the order is non-obvious from the name. Easy to confuse `signal` and `body` (both optional, both at the end). -- **Category:** 1 (vague — five-positional builder). -- **Suggested name:** Keep name; accept a single options object `{ method, url, headers, signal?, body? }`. -- **Rationale:** Same as `rfa#38`. - -### 16. `executeCall` `opts` local shadows `options` parameter — `utils.ts:30-37` -- **Why weird:** Local `opts` variable is one letter shorter than the parameter `options` to disambiguate. The shadowing convention isn't documented. -- **Category:** Observation. -- **Suggested name:** Rename inner `opts` → `internalOptions`. -- **Rationale:** Same as `rfa#41`. - ## Observations -### 17. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper +### 9. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper The index file exports the `Client` and eight model interfaces (`CreateTokenRequest`, `CreateTokenRequest_Response`, `ListTokensRequest`, `ListTokensRequest_Response`, `PublicTokenInfo`, `RevokeTokenRequest`, `RevokeTokenRequest_Response`, `UpdateTokenRequest`, `UpdateTokenResponse`). It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. -### 18. `package.json` description is empty string — `package.json:4` -`"description": ""`. The npm package has no public description string. Combined with the ambiguous `tokens` name (see #1) and the parallel `tokenmanagement` package, this leaves users without any registry-level metadata to disambiguate the two packages. - -### 19. No tests in the package -`package.json` line 25-26: `"test": "echo 'no tests'"`, `"test:browser": "echo 'no tests'"`. Same as `tokenmanagement` and most newly-generated packages. Not a naming issue, but the wire-format guarantees deserve a contract test. - -### 20. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:171` +### 10. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:171` `const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:58`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. ## Domain glossary @@ -158,4 +100,4 @@ The index file exports the `Client` and eight model interfaces (`CreateTokenRequ - `src/v1/client.ts` (192 lines): read fully. - `src/v1/utils.ts` (151 lines): read fully. - `src/v1/index.ts` (18 lines): read fully. -- Cross-referenced `packages/tokenmanagement/src/v1/` for overlap analysis (see findings #1, #3, #4, #7). +- Cross-referenced `packages/tokenmanagement/src/v1/` for overlap analysis (see findings #1, #3, #4, #6). diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 41607af0..7fbf3a4f 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -3,15 +3,15 @@ **Path:** `packages/usagedashboards/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). -**Total weird names flagged:** 19 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | | High | 4 | -| Medium | 6 | -| Low | 5 | -| Observation | 4 | +| Medium | 5 | +| Low | 0 | +| Observation | 2 | ## High severity @@ -71,49 +71,13 @@ - **Suggested name:** Keep the field name; consider a branded type (`type Url = string & {readonly _urlBrand: unique symbol}`) or `URL` (the WHATWG class). At minimum, make it non-optional on a 2xx response. - **Rationale:** SDK-wide concern (every URL field in every package is `string`); flag once per audit. Branded URLs are a TS idiom precisely for this case. -### 10. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:33` -- **Why weird:** `Segment` is a generic CS term. The comment ("Package identity segment for this client to be used in the User-Agent header") is the disambiguator; without it the constant name does not communicate what it is. -- **Category:** 1 (vague), 15 (generic field name losing meaning). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Cross-package consistency — same finding appears in every audited package. Worth normalising at the generator level. - ## Low severity -### 11. JSDoc on `dashboardType` is duplicated verbatim — `src/v1/model.ts:22, 39` -- **Why weird:** The exact same multi-sentence JSDoc ("Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account.") appears on `CreateBillingUsageDashboardRequest.dashboardType` (line 22) and `GetBillingUsageDashboardRequest.dashboardType` (line 39). The duplication suggests the underlying enum (`UsageDashboardType`) should carry the doc, not each field. -- **Category:** Observation — not strictly a name issue but flagged because it implies fragmentation. JSDoc duplication is a generator artefact. -- **Suggested name:** Move the doc to the `UsageDashboardType` enum (or its members). - -### 12. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:69, 74, 77, 81, 101, 114, 118` -- **Why weird:** Local variables use three-letter abbreviations (`req`, `resp`, `opts`, `httpReq`). The codebase guideline (typescript.mdc § 5) discourages cryptic short abbreviations. Compare with `httpClient` (full word) in the same file. -- **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `request`, `response`, `options`, `httpRequest`. -- **Rationale:** Inexpensive readability win. - -### 13. `params` shadowed across files — `src/v1/client.ts:105` -- **Why weird:** Local `params: URLSearchParams` — fine in isolation, but `flattenQueryParams(prefix, value, params)` in `utils.ts:126` exposes the same `params` name in public API. The repeated use of `params` for both `URLSearchParams` and "named function parameters" is mildly confusing in audit traces. -- **Category:** 1 (vague). -- **Suggested name:** `queryParams` / `urlSearchParams`. - -### 14. `query` local in `getBillingUsageDashboard` — `src/v1/client.ts:112` -- **Why weird:** `const query = params.toString();` — the variable is the serialized query *string*, but `query` reads as a query expression/object. Compare with `fullUrl` on the next line (which is clear about what it is). -- **Category:** 1 (vague), 6 (misleading — name implies a query, value is a string). -- **Suggested name:** `queryString`. - -### 15. `httpClient: HttpClient` field — `src/v1/client.ts:43` -- **Why weird:** Type-suffix tautology (`httpClient` field of type `HttpClient`). Minor — convention widespread in this SDK. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** `client: HttpClient` — though arguably the longer name disambiguates from the outer `Client` class in the same file. +_None._ ## Observations -### 16. `flattenQueryParams` exported but unused in this package — `src/v1/utils.ts:123` -The exported `flattenQueryParams` helper is never called from `client.ts` — the GET method does its own `params.append()` (lines 106-111) inline because there are only two query params. The helper is dead surface area in this package; same finding as `billableusagedownload` audit #11. Worth pruning at the generator level when the consuming methods don't need it. - -### 17. `executeHttpCall` and `executeCall` near-duplicate exported names — `src/v1/utils.ts:26, 65` -Two functions named almost identically, doing very different things: `executeCall` wraps the call in retry/rate-limit semantics, `executeHttpCall` does the raw HTTP send + decode + ApiError check. Both are used in `client.ts:82, 92, 119, 129`. The verb-pair is fine, but the cognitive distance between "wrap with retry options" and "send an HTTP request and check for API errors" is large enough that one name should be different (e.g., `runWithCallOptions` / `sendHttp`). Same finding appears in every audited package's `utils.ts`. - -### 18. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency +### 10. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency - The enum names are `UsageDashboardMajorVersion`, `UsageDashboardType` — `Usage` first, no "Billing". - The request types are `CreateBillingUsageDashboardRequest` — `Billing` first, with `Usage`. - The package is `usagedashboards` — `usage` only, no "billing". @@ -121,7 +85,7 @@ Two functions named almost identically, doing very different things: `executeCal Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #5. -### 19. The package has no list/page operations +### 11. The package has no list/page operations There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. ## Domain glossary diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md index d0be2fab..a0c2f216 100644 --- a/.agent/naming-audit/usagepolicy.md +++ b/.agent/naming-audit/usagepolicy.md @@ -3,14 +3,14 @@ **Path:** `packages/usagepolicy/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). -**Total weird names flagged:** 28 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 9 | -| Low | 10 | +| High | 3 | +| Medium | 5 | +| Low | 3 | | Observation | 5 | ## High severity @@ -27,13 +27,7 @@ - **Suggested name:** `UsagePolicyFilter` (and rename the sibling to `BudgetPolicyFilter`). - **Rationale:** A bare `Filter` provides zero discoverability and forces a collision with `budgetpolicy.Filter`. Both packages target the same account-level API; consumers will frequently import both. This finding is doubly bad because the two `Filter` types have identical structure but are not type-compatible from TS's structural-typing perspective at the import boundary if a consumer aliases one (`import {Filter as BudgetFilter}`). -### 3. `UpdateUsagePolicyRequest.limitConfig` field doc references a non-existent successor — `src/v1/model.ts:117` -- **Why weird:** JSDoc reads: "DEPRECATED. This is redundant field as LimitConfig is part of the UsagePolicy". But `UsagePolicy` itself (line 121–130) does **not** have a `limitConfig` member, so the JSDoc claim ("LimitConfig is part of the UsagePolicy") is wrong about its successor — the field has nowhere to migrate to within this package. -- **Category:** 6 (misleading — doc points to a non-existent replacement). -- **Suggested name:** Fix the JSDoc to either point at the real successor or drop the migration hint. -- **Rationale:** A new-language SDK should not inherit other-language migration warts on day one, and the warning is broken because the documented successor doesn't exist in this package's `UsagePolicy`. - -### 4. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` +### 3. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` - **Why weird:** Workspace IDs are typed as `number[]`. Databricks workspace IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so workspace IDs `>2^53` will silently lose precision. Same problem on `Filter.creatorUserId: number` (line 57). - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). - **Suggested name:** `bindingWorkspaceIds: bigint[]` or `string[]` (matches Databricks REST API serialisation of large IDs). @@ -41,55 +35,31 @@ ## Medium severity -### 5. `CustomPolicyTag` type name — `src/v1/model.ts:23` +### 4. `CustomPolicyTag` type name — `src/v1/model.ts:23` - **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. Also colliding with the same `CustomPolicyTag` exported from `budgetpolicy/src/v1/model.ts:53`. - **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location), 12 (duplicate concept across siblings with identical name). - **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. - **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". -### 6. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` +### 5. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` - **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling **from the budget-policy domain** — copy-pasted verbatim from the `budgetpolicy` package without renaming to the usage-policy equivalents (one would expect `usage-policy-name` etc.). Either (a) the wire really *does* use the `budget-policy-*` prefix (which is a Databricks API design issue worth surfacing), or (b) the JSDoc was lazily duplicated and the actual reserved keys are different. - **Category:** 6 (misleading: cross-domain magic strings that callers must memorise), 12 (duplicate across siblings — but here it's a *bug*, because the reserved keys are not surfaced as constants and may differ from `budgetpolicy`), 18 (long magic string sentinels). - **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate the wire payload and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. - **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Either way the verbatim duplication smells. -### 7. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` +### 6. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` - **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. - **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). - **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Same as finding #4 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. +- **Rationale:** Same as finding #3 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. -### 8. `SortSpec` type — `src/v1/model.ts:103` +### 7. `SortSpec` type — `src/v1/model.ts:103` - **Why weird:** `SortSpec` (specification) and `Field` together build the "what to sort by" structure. `Spec` is generic — every type is a spec of something. The wrapping type holds two fields (`field` + `descending`); a one-or-two-field pair could be inlined into the request. - **Category:** 1 (vague suffix `Spec`), 11 (trivial wrapper holding two fields). - **Suggested name:** `SortOptions`, or inline as `sortField?: SortField; sortDescending?: boolean` on the request. - **Rationale:** `Spec` adds no information. `sortBy: SortField` plus a boolean is more direct. Mirrors `budgetpolicy` finding #17. -### 9. `SortSpec.field` JSDoc typo "The filed to sort by" — `src/v1/model.ts:104` -- **Why weird:** `filed` typo for `field`. Generated comment text is permanent unless the API spec is fixed. -- **Category:** Observation (typo). -- **Suggested name:** Fix spelling. -- **Rationale:** Surfaces in IntelliSense. Same typo as `budgetpolicy/src/v1/model.ts:150` — the two packages even share generator typos. - -### 10. `ListUsagePoliciesResponse.previousPageToken` — `src/v1/model.ts:100` -- **Why weird:** Response supports both forward (`nextPageToken`) and backward (`previousPageToken`) pagination — but the iterator helper only walks forward. The bidirectional surface area exists but is unused by the iterator helper. -- **Category:** Observation / 12 (duplicate-but-asymmetric concept). -- **Suggested name:** Keep name; consider documenting that the iterator does not honor `previousPageToken`. -- **Rationale:** Field name is fine on its own; flagging because it hints at unsupported reverse pagination. Mirrors `budgetpolicy` finding #20. - -### 11. `CreateUsagePolicyRequest.policy` field with wire-name leak in JSDoc — `src/v1/model.ts:19-20` -- **Why weird:** Doc: "The policy to create. `policy_id` needs to be empty as it will be generated" — wire-name leak (`policy_id`) in the docs of a TS field. Also: the doc is *shorter* than the sibling `budgetpolicy.CreateBudgetPolicyRequest.policy` doc (which adds: "`policy_name` must be provided, custom_tags may need to be provided depending on the cloud provider. All other fields are optional."). So the usage-policy version silently drops the "policyName must be provided" and the cloud-provider-conditional tag note. -- **Category:** 14 (wire-style identifiers in TS docs), 17 (inconsistent docs across sibling packages for the same conceptual request). -- **Suggested name:** Fix the doc to reference TS field names; align with sibling-package doc content. -- **Rationale:** Editing UX: hovers should show TS, not proto. The sibling-divergence also matters: a developer reading both packages should see consistent requirements unless they actually differ. - -### 12. `UpdateUsagePolicyRequest.policy` doc mentions `creator_user_id` — `src/v1/model.ts:112` -- **Why weird:** Doc: "`creator_user_id` cannot be specified in the request" — but `UsagePolicy` (the type of `policy` here) doesn't have a `creatorUserId` field! It has `policyId`, `policyName`, `customTags`, `bindingWorkspaceIds`. The doc refers to a field that doesn't exist on the model. Exact same bug as `budgetpolicy.UpdateBudgetPolicyRequest.policy` JSDoc. -- **Category:** 6 (misleading documentation — refers to non-existent field), 17 (inconsistency: doc says creator is part of `UsagePolicy`, model says otherwise), 14 (Go-SDK paste from a richer struct). -- **Suggested name:** Fix doc; remove the spurious reference or add the missing field to the model. -- **Rationale:** Real bug, twice (once here, once in `budgetpolicy`). - -### 13. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` +### 8. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` - **Why weird:** `budgetpolicy.UpdateBudgetPolicyRequest` (`packages/budgetpolicy/src/v1/model.ts:165`) carries an `updateMask?: FieldMask` plus a `budgetPolicyFieldMask(...paths)` builder. `usagepolicy.UpdateUsagePolicyRequest` does not. Either (a) the usage-policy API genuinely uses replace-on-PATCH semantics (no partial updates) — in which case the JSDoc should say so — or (b) the SDK is missing field-mask support that the API offers. Without inspection of the OpenAPI source, either is plausible, and the absence of a doc note is itself a finding. - **Category:** 17 (inconsistency across near-clone sibling packages), Observation (potential missing surface). - **Suggested name:** If full-replace: document on `UpdateUsagePolicyRequest`. If partial-update: add `updateMask?: FieldMask` and a `usagePolicyFieldMask(...paths)` helper to match the sibling. @@ -97,85 +67,43 @@ ## Low severity -### 14. `executeCall` / `executeHttpCall` naming pair — `src/v1/utils.ts:26,65` -- **Why weird:** Two functions with nearly identical names handle different layers (retry/rate-limit wrapper vs raw HTTP send + logging). Easy to confuse at call sites in `client.ts`. -- **Category:** 1 (vague), 17 (names differ only by `Http` infix). -- **Suggested name:** `runWithCallOptions` / `sendHttpRequest`. -- **Rationale:** Same pair flagged in `abacpolicies` and `budgetpolicy` audits. Generator-wide. - -### 15. `HttpCallOptions` — `src/v1/utils.ts:15` -- **Why weird:** `Options` is reused across the SDK for many unrelated concepts (`ClientOptions`, `CallOptions`, and the imported `Options` type from `@databricks/sdk-core/api` on line 3). Within `utils.ts` alone, two `Options`-named types collide cognitively. -- **Category:** 1 (vague suffix), 17 (collides with the imported `Options`). -- **Suggested name:** `HttpCallContext` (it's not user-facing options; it's an internal bag of arguments). -- **Rationale:** Generator-wide; same as `budgetpolicy` finding #29. - -### 16. `readAll` — `src/v1/utils.ts:40` -- **Why weird:** Function reads an entire response body stream into a buffer. Generic name; collides cognitively with `Array.prototype` or stream utilities. -- **Category:** 1 (vague). -- **Suggested name:** `drainStream` or `readStreamToEnd`. -- **Rationale:** Internal helper. Generator-wide. - -### 17. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Used by `client.ts:158,165,217` for nested query-param flattening; OK in this package but exported per package which makes it a duplicated utility across every generated package (12+ identical copies in this monorepo). -- **Category:** Observation / 12 (duplicate utility across packages). -- **Suggested name:** Keep name; consider hoisting to `@databricks/sdk-core`. -- **Rationale:** Naming is fine; flagging duplication. - -### 18. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` -- **Why weird:** `Segment` is a generic CS term. Comment explains it's the User-Agent identity segment; without the comment the constant name doesn't communicate that. -- **Category:** 1 (vague), 15 (generic name losing meaning). -- **Suggested name:** `USER_AGENT_PACKAGE` or `PKG_USER_AGENT_SEGMENT`. -- **Rationale:** Same as `budgetpolicy` finding #33; generator-wide. - -### 19. `Client` class plain name — `src/v1/client.ts:46` +### 9. `Client` class plain name — `src/v1/client.ts:46` - **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-usagepolicy/v1`, they will almost certainly alias it (`import {Client as UsagePolicyClient}`) to avoid collision with `Client` from every other package — including the byte-identical class from `@databricks/sdk-budgetpolicy/v1`. - **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages, *especially* this one and `budgetpolicy`). - **Suggested name:** `UsagePolicyClient`. - **Rationale:** Each generated package emits a `Client`. With `usagepolicy`/`budgetpolicy` being near-clones, the importer who needs both will be forced into double-aliasing. -### 20. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` +### 10. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` - **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. - **Category:** 5 (cryptic abbreviation when the long form fits comfortably). - **Suggested name:** `request`. - **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. Same as `budgetpolicy` finding #35. -### 21. JSDoc on `getUsagePolicy` reads "Retrieves a usage policy by it's ID." — `src/v1/client.ts:120` -- **Why weird:** "it's" should be "its" (possessive). Same grammatical mistake appears in `budgetpolicy/src/v1/client.ts:120` ("Retrieves a policy by it's ID.") — copy-pasted across the clones. -- **Category:** Observation (grammar). -- **Suggested name:** Fix to "its". -- **Rationale:** Surfaces in editor hovers; small but persistent. - -### 22. `SortSpec_Field` proto-style underscore-nested enum name — `src/v1/model.ts:6` +### 11. `SortSpec_Field` proto-style underscore-nested enum name — `src/v1/model.ts:6` - **Why weird:** Underscored identifier `SortSpec_Field` mirrors protobuf's "ParentMessage_NestedEnum" wire convention and is unidiomatic in TypeScript. The file even carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.` on line 5, confirming the proto-architectural leak. Re-exported from `index.ts:5` so the leak reaches consumers verbatim. - **Category:** Proto-architectural leak — proto-nested-type naming convention surfaced into the TS public API. - **Suggested name:** `SortField` (or namespace it under `SortSpec` as `SortSpec.Field` if the nesting relationship matters). - **Rationale:** TS has no `Parent_Nested` convention; the underscore is a direct proto leak. Mirrors the same finding in `budgetpolicy` (`SortSpec_Field` at `budgetpolicy/src/v1/model.ts:8`). -### 23. `buildHttpRequest` — `Http` mid-position infix — `src/v1/utils.ts:96` -- **Why weird:** `Http` appears as a mid-position infix between the verb `build` and the noun `Request`. The function's role is "construct an `HttpRequest` value", but the `Http` infix in the function name redundantly leaks the transport layer into the verb. Same pattern in the imported `HttpRequest` type is fine (end suffix), but on the function it duplicates information already in the return type. -- **Category:** Proto-architectural leak — transport-layer noun appearing mid-name. -- **Suggested name:** `buildRequest` (return type `HttpRequest` already conveys the transport). -- **Rationale:** Standard naming guidance: don't repeat the return-type noun's qualifier in the verb. Mirrors the same pattern in `budgetpolicy/src/v1/utils.ts:96`. - ## Observations -### 24. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference +### 12. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. - **Category:** 12 (duplicate concept), 1 (vague package boundary). -### 25. No `FieldMask` import in `usagepolicy/src/v1/model.ts` -Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #13 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. +### 13. No `FieldMask` import in `usagepolicy/src/v1/model.ts` +Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #8 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. - **Category:** Observation / 17 (cross-package inconsistency). -### 26. Action-verb conventions in `Client` +### 14. Action-verb conventions in `Client` The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. - **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). -### 27. Acronym casing `Id` consistently used as `Id`, not `ID` +### 15. Acronym casing `Id` consistently used as `Id`, not `ID` `policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). - **Category:** 3 (observation — internal acronym style is consistent). -### 28. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) +### 16. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) The same identifier appears in three forms in the same client file: - `usage_policies` — wire form (in the Zod schemas via snake_case keys). - `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). @@ -187,7 +115,7 @@ Readers must mentally translate. Worth flagging because the kebab-case form does ## Domain glossary - `usage policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. Same structure as `budgetpolicy.BudgetPolicy` per the JSDoc on `UsagePolicy` (line 120). Despite "usage" in the name, no usage-data concept (rows/metrics/period) lives on the model — only tags and workspace bindings. - `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `UsagePolicy.bindingWorkspaceIds: number[]`. -- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #6). +- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #5). - `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.1/accounts/{accountId}/usage-policies`). - `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md index 8b450995..85c18ab7 100644 --- a/.agent/naming-audit/vectorsearch.md +++ b/.agent/naming-audit/vectorsearch.md @@ -4,17 +4,17 @@ **Versions audited:** v1 **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` **Inferred domain:** Databricks AI/Vector Search — endpoint management (create, get, list, patch, delete, budget-policy patch) and vector-index management (create, get, list, query, query-next-page, scan, sync, upsert-data, delete-data, delete). Routes under `/api/2.0/vector-search/endpoints` and `/api/2.0/vector-search/indexes`. Hosts a single `Client` with mixed endpoint and index methods plus a single `CreateEndpointWaiter`. -**Total weird names flagged:** 19 +**Total weird names flagged:** 14 ## Summary | Severity | Count | | ------------ | ----- | -| High | 6 | +| High | 5 | | Medium | 6 | -| Low | 4 | -| Observation | 3 | -| **Total** | **19** | +| Low | 2 | +| Observation | 1 | +| **Total** | **14** | Dominant themes: 1. **Two resource families share one flat `Client`.** Endpoint methods (`createEndpoint`, `getEndpoint`, …) and index methods (`createVectorIndex`, `queryVectorIndex`, …) sit side by side on the same class. The result is long method names that re-encode the resource family (`createVectorIndex` instead of `client.indexes.create()`), plus a single waiter that only covers endpoints. @@ -31,31 +31,25 @@ Dominant themes: - **Suggested name:** `VectorSearchEndpoint` (mirrors `modelserving.InferenceEndpoint`). Sibling types (`EndpointType`, `EndpointStatus`, `EndpointScalingInfo`) follow. - **Rationale:** "Endpoint" alone is the most generic REST noun. Disambiguation at the type level is needed once the type leaves the import statement. -### 2. `Endpoint.name` is the URL identifier but coexists with `Endpoint.id` — `src/v1/model.ts:276, 288` -- **Why weird:** `Endpoint` declares both `name?: string` ("Name of the AI Search endpoint") and `id?: string` ("Unique identifier of the endpoint"). Every URL in the client uses `name` as the path segment (`/endpoints/${req.name}` — `client.ts:212, 262, 420, 446`); `id` is never used as a key. Two identifiers for the same entity is confusing: which one is the canonical reference for the rest of the SDK? JSDoc does not say. -- **Category:** 12 (duplicate concepts), 19 (underspecified IDs), 6 (misleading — `name` reads like a label but acts like a primary key). -- **Suggested name:** Document the distinction prominently in JSDoc — `name` is the user-chosen URL-safe key, `id` is the opaque server-generated GUID — and pick one as the canonical handle. Alternatively, collapse to one identifier at the API level. -- **Rationale:** Users who fetch an endpoint and try to use `.id` to delete it will hit a 404. The dual identifier needs to be either eliminated or surfaced explicitly. - -### 3. `listEndpoint` / `listVectorIndex` method names are singular for collection operations — `src/v1/client.ts:317, 365` +### 2. `listEndpoint` / `listVectorIndex` method names are singular for collection operations — `src/v1/client.ts:317, 365` - **Why weird:** Both methods return a collection (`ListEndpointResponse.endpoints: Endpoint[]`, `ListVectorIndexResponse.vectorIndexes: MiniVectorIndex[]`) yet the method names are singular. The corresponding URLs are plural (`/endpoints`, `/indexes`) and the body field names are plural. The request/response types (`ListEndpointRequest`, `ListEndpointResponse`, `ListVectorIndexRequest`, `ListVectorIndexResponse`) inherit the singular form. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verbs). - **Suggested name:** `listEndpoints`, `listVectorIndexes`, `ListEndpointsRequest`, `ListEndpointsResponse`, `ListVectorIndexesRequest`, `ListVectorIndexesResponse`. The iterator pair (`listEndpointIter`, `listVectorIndexIter`) follows: `listEndpointsIter`, `listVectorIndexesIter`. - **Rationale:** A collection method should be plural to match its return type, the wire URL, and the response field shape. -### 4. `MiniVectorIndex` and `VectorIndex` are structurally identical duplicates — `src/v1/model.ts:376-399` vs `:572-595` +### 3. `MiniVectorIndex` and `VectorIndex` are structurally identical duplicates — `src/v1/model.ts:376-399` vs `:572-595` - **Why weird:** Both types declare exactly the same nine fields (`name`, `endpointName`, `primaryKey`, `indexType`, `indexSpec`, `status`, `creator`, `indexSubtype`) with identical JSDoc on the fields they share. `MiniVectorIndex` is used in `ListVectorIndexResponse.vectorIndexes` (the list-view element type); `VectorIndex` is used everywhere else. With no field-level difference, the type split is gratuitous — and the "Mini" qualifier is cryptic (industry convention is `Summary`, `ListItem`, `Brief`, `Ref`). - **Category:** 12 (duplicate concept), 5 (cryptic abbreviation), 1 (vague qualifier). - **Suggested name:** Either `export type VectorIndexSummary = VectorIndex` (with a JSDoc note that the wire form is currently identical), or drop `MiniVectorIndex` entirely and use `VectorIndex` in list responses. If the API intends them to diverge later, document the upcoming difference. - **Rationale:** Two ~25-line type definitions with no semantic distinction is a maintenance hazard. The "Mini" prefix tells the reader nothing about what is omitted (because nothing is). -### 5. `DeltaSyncVectorIndexSpec` and `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:175-205` vs `:207-237` +### 4. `DeltaSyncVectorIndexSpec` and `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:175-205` vs `:207-237` - **Why weird:** Two exported types with identical field sets (`sourceTable`, `embeddingSourceColumns`, `embeddingVectorColumns`, `pipelineType`, `pipelineId`, `embeddingWritebackTable`, `columnsToSync`, `columnsToIndex`) and identical JSDoc on every shared field. The `Request` twin exists only for `DeltaSync` — `DirectAccessVectorIndexSpec` has no `Request` variant. The asymmetry is unexplained and the structural identity makes the split feel arbitrary. - **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix when the type has no distinguishing fields). - **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec` used in both request and response positions, mirroring `DirectAccessVectorIndexSpec`), or document the planned divergence prominently. - **Rationale:** The mismatch with `DirectAccessVectorIndexSpec` (no `Request` twin) shows the duplication is gratuitous. Users serializing a `DeltaSyncVectorIndexSpec` for a create call have to discover that `*Request` is the right one only by reading the function signature. -### 6. `EndpointStatus_State.OFFLINE` is a terminal-failure state but reads as transient — `model.ts:72`, `client.ts:641-644, 680-681` +### 5. `EndpointStatus_State.OFFLINE` is a terminal-failure state but reads as transient — `model.ts:72`, `client.ts:641-644, 680-681` - **Why weird:** The waiter's terminal-state switch (`client.ts:637-647`) treats `EndpointStatus_State.OFFLINE` as a *failure* and throws. The enum identifier "OFFLINE" however reads as a transient lifecycle state ("the endpoint is currently offline"), implying it might come back online. JSDoc on the enum value is absent; the only hint is in the comment block above `RED_STATE`/`YELLOW_STATE`. A reader inspecting the enum would not predict that the waiter throws on OFFLINE. - **Category:** 6 (misleading), 16 (field type contradicts domain — lifecycle name implies transient, runtime semantics are terminal). - **Suggested name:** If the wire allows, rename to `FAILED` or `TERMINATED` to match the runtime semantics. Otherwise, add JSDoc on `OFFLINE` clarifying that it is a terminal failure state, distinct from "temporarily not serving traffic". @@ -65,37 +59,37 @@ Dominant themes: ## Medium severity -### 7. `IndexSubtype` vs `VectorIndexType` — two enums on different "type" axes — `model.ts:29, 62` +### 6. `IndexSubtype` vs `VectorIndexType` — two enums on different "type" axes — `model.ts:29, 62` - **Why weird:** Two enums both describing a "type" axis of a vector index. `IndexSubtype = {VECTOR, FULL_TEXT, HYBRID}` is the search-semantics axis (what kind of similarity is computed). `VectorIndexType = {DELTA_SYNC, DIRECT_ACCESS}` is the data-residency axis (how data flows in). Both surface as `index*Type*` fields on `VectorIndex`. A first-time reader cannot tell which axis is which without reading both JSDocs. - **Category:** 6 (misleading — both look like "the type" of the index), 17 (inconsistent naming for two type axes). - **Suggested name:** Disambiguate: `IndexSearchMode` for the search-semantics axis, `IndexBackingMode` (or `IndexStorageType`) for the data-residency axis. Or `IndexSearchKind` / `IndexSyncMode`. - **Rationale:** Two parallel `*Type` enums on the same type make the API harder to learn. Naming each by its axis would self-document. -### 8. `IndexSubtype` exposes an unsupported value `VECTOR` — `model.ts:29-33` +### 7. `IndexSubtype` exposes an unsupported value `VECTOR` — `model.ts:29-33` - **Why weird:** The enum's first member is `VECTOR`, and its JSDoc says "Not supported. Use `HYBRID` instead." A public-API enum that exposes a value whose only documented behavior is "do not use" inflates the surface area and forces every switch statement to handle it. Also, "VECTOR" inside an enum on a vector-search index is tautological — every value is some kind of vector behavior. - **Category:** 6 (misleading: present but explicitly unsupported), 18 (the value itself is content-free against the enum name). - **Suggested name:** Remove `VECTOR` from the enum, or document the deprecation path in JSDoc and timeline for removal. - **Rationale:** Dead enum members are bug magnets. -### 9. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:51-55, 554` +### 8. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:51-55, 554` - **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:155, 550` — "Result of the upsert or delete operation"). - **Category:** 13 (verb-coupling), 7 (verbose), 1 (generic `Status`/`Result`). - **Suggested name:** Split into `UpsertDataStatus` / `DeleteDataStatus` (aliases of the same wire enum), or use a neutral name `DataMutationStatus` / `DataMutationResult`. - **Rationale:** Two-verb compound nouns are unusual and confusing. Most APIs use a single neutral noun for shared response types. -### 10. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` +### 9. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` - **Why weird:** Two methods with the same verb start (`createEndpoint` / `createEndpointWaiter`). The waiter version *calls* `createEndpoint` then wraps the result in a `CreateEndpointWaiter`. A reader sees two `create*` methods and may think they are different operations. The Java/Go SDK convention surfaces a waiter via a side return; TS would more naturally inline the wait (`createEndpointAndWait`). - **Category:** 7 (verbose), 13 (verb overlap), 17 (inconsistent action verbs). - **Suggested name:** Either fold the wait into `createEndpoint` (return a `CreateEndpointWaiter` that is both an awaitable and the resource shape), or rename to `createEndpointAndWait`, or expose a single `waitForEndpoint(name)` that any caller can use after `createEndpoint`. - **Rationale:** Two `create*` methods for one logical "create" operation force every caller to learn which one to use. There is also no analogous waiter for the index create flow, so the pattern is inconsistent within the package. -### 11. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` +### 10. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` - **Why weird:** The enum is already `EndpointStatus_State` and the other members (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not carry the suffix — only the health-colored values do. Reads `EndpointStatus_State.RED_STATE` — "endpoint status state . red state". Inconsistent within the enum. - **Category:** 16 (field/value contradicting type domain), 8 (redundant suffix). - **Suggested name:** If wire allows, `RED` / `YELLOW` (matches `PROVISIONING` / `ONLINE` shape). Otherwise, document the asymmetry. - **Rationale:** Inconsistency within a single enum is a generator-spec issue worth surfacing. -### 12. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` +### 11. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` - **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 73-83 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. - **Category:** 16 (field contradicting domain — two orthogonal axes squeezed into one enum), 6 (misleading). - **Suggested name:** Split into `EndpointLifecycleState` and `EndpointHealth`. Reflect both on `EndpointStatus` as two fields. @@ -105,25 +99,13 @@ Dominant themes: ## Low severity -### 13. `req`, `resp`, `respBody`, `httpReq`, `pollResp`, `apiErr`, `pkgJson`, `opts`, `msg` — Go-idiom shorthand in TS — `client.ts:20, 79-80, 112, 117, 121, 122, 130, 137, 149, 154, 158, 159, 167, 175, 185, 189, 190, 201, 209, 213, 217, 218, 226, 234, 238, 242, 243, 251, 259, 263, 267, 268, 276, 284, 297, 301, 302, 310, 318, 328, 332, 333, 341, 348, 351, 353, 360, 366, 379, 383, 384, 392, 399, 402, 404, 411, 417, 422, 426, 427, 435, 443, 451, 455, 456, 467, 475, 480, 484, 485, 493, 501, 509, 513, 514, 522, 530, 535, 539, 540, 548, 556, 561, 565, 566, 574, 582, 587, 591, 592, 603, 625, 632, 642, 666, 673`; `utils.ts:30, 65-92, 76, 88-91` -- **Why weird:** Ubiquitous Go-style shorthand identifiers ported verbatim. `req`/`resp`/`err`/`opts`/`msg` are conventional in Go, where the receiver supplies enough context; in TS the convention favors spelled-out names (`request`, `response`, `error`, `options`, `message`). Internal inconsistency too: `executeCall` accepts `options` (utils.ts:28) but `executeHttpCall` uses `opts` (utils.ts:67). -- **Category:** 14 (Go/Java-style names), 5 (cryptic abbreviation). -- **Suggested name:** Spell them out throughout: `request`, `response`, `responseBody`, `pollResponse`, `httpRequest`, `apiError`, `packageJson`, `options`, `message`. Generator-level change. -- **Rationale:** Trivial diff, large readability gain. The TS ecosystem standard is the spelled-out form. - -### 14. `flattenQueryParams` is exported but unused inside the package — `utils.ts:123-150` -- **Why weird:** The function is exported from `utils.ts` but every client method assembles `URLSearchParams` directly via `params.append(...)`. The helper is dead code for this package. -- **Category:** Observation (dead export), 6 (misleading — exported as if needed). -- **Suggested name:** Either delete from `utils.ts` here or move to `@databricks/sdk-core` so the per-package `utils.ts` files stop duplicating it. -- **Rationale:** Same finding as in other per-package audits. Generator-level cleanup. - -### 15. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` +### 12. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` - **Why weird:** Two array fields on the same type, JSDoc on `columnsToIndex` says: "Alias for columns_to_sync. ... Only one of columns_to_sync or columns_to_index may be specified." Two fields that mean the same thing, where the API rejects both being set, is an API-level footgun. The SDK exposes both without runtime validation. - **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). - **Suggested name:** Mark `columnsToSync` `@deprecated` if `columnsToIndex` is the canonical form (or vice versa), and add runtime validation in `marshalDeltaSyncVectorIndexSpecRequestSchema`. - **Rationale:** API-level aliases are upstream policy, but the SDK should mark the deprecated alias to steer callers. -### 16. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` +### 13. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` - **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` at the top level (line 462) AND a `reranker.parameters.columnsToRerank: string[]` nested inside `RerankerConfig_RerankerParameters` (line 491). Same field name, same purpose, two places. The JSDoc on `reranker` references "`columns_to_rerank`" without saying which copy wins. - **Category:** 12 (duplicate concept), 6 (misleading — precedence unclear). - **Suggested name:** Drop one, or document the precedence in JSDoc. If one is for input and the other for echoed-back output, name them accordingly. @@ -133,20 +115,8 @@ Dominant themes: ## Observation -### 17. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` +### 14. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` - **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". A field whose JSDoc admits the rollout is incomplete leaves callers guessing whether setting it has any effect today. - **Category:** 6 (misleading — present but possibly inactive). - **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behavior and rollout timeline. - **Rationale:** Documentation-only TODOs leak generator/spec-side state into the public API. Worth surfacing. - -### 18. `EmbeddingSourceColumn.embeddingConfig` JSDoc says "TODO: clean up ai gateway related code" — `model.ts:255` -- **Why weird:** JSDoc on a public-API field contains a developer TODO: "TODO: clean up ai gateway related code. It's deprecated on ModelServing side." This is internal generator/spec-side debt leaking into IntelliSense for every SDK user. -- **Category:** Observation (generator-side leak in JSDoc). -- **Suggested name:** Rewrite the JSDoc to describe the public contract; track the cleanup in the spec, not in the user-facing docs. -- **Rationale:** Internal TODOs in JSDoc are a long-known generator hygiene issue. Worth flagging. - -### 19. `Endpoint.creator` and `lastUpdatedUser` JSDoc gives no format — `model.ts:278, 286` -- **Why weird:** Both fields are typed `string` with JSDocs "Creator of the endpoint" / "User who last updated the endpoint". The reader has no way to tell if the value is a user ID, a display name, an email, or a UC identifier. Same observation applies to `MiniVectorIndex.creator` (`model.ts:396`) and `VectorIndex.creator` (`model.ts:592`). -- **Category:** Observation (underspecified format on user-reference fields), 19 (underspecified IDs). -- **Suggested name:** Keep the field names but extend JSDoc with the expected format (e.g. "the email of the user who created this endpoint"). -- **Rationale:** Documentation-only nit; worth tracking because the format is stable wire behavior and is not surfaced today. diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index 4432d08d..212d6300 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -12,9 +12,9 @@ Notation: file paths are absolute. Findings reference `file:line`. | ----------- | ----- | | High | 2 | | Medium | 4 | -| Low | 6 | -| Observation | 4 | -| **Total** | **16** | +| Low | 0 | +| Observation | 2 | +| **Total** | **8** | Headline themes: @@ -154,90 +154,7 @@ Headline themes: ## Low Severity -### L1. `executeCall` vs. `executeHttpCall` — overlapping verbs - -- **File / line:** `src/v1/utils.ts:26, 65`. -- **Category:** #6 misleading name; #12 duplicate concepts. -- **Current:** Two functions in the same file with very similar names. - `executeCall` is the public-options translator delegating to `execute` - from `@databricks/sdk-core/api`. `executeHttpCall` is the low-level - HTTP send + parse helper. -- **Suggestion:** Rename `executeCall` to `runCallWithOptions` / - `dispatchCall` (or to match the JSDoc, `translateAndExecute`). The - JSDoc on line 22 already calls this a *translator* — the name should - match. -- **Rationale:** Two functions named `execute*Call` in 100 lines of - code, with different return shapes (`Promise` vs. - `Promise`), is a readability hazard. - -### L2. `Call` (imported, not local) and `call` local variable share names - -- **File / line:** `src/v1/client.ts:96, 127, 168, 226, 280`. -- **Category:** #1 vague/generic. -- **Current:** `const call: Call = async (callSignal?: AbortSignal) => …`. -- **Suggestion:** `httpCall` or `doRequest`. -- **Rationale:** `call` is a built-in word in JS (`.call()` on - functions), so a variable named `call` inside a method that is itself - a call is ambiguous. Caveat: this is a 1:1 port of Go SDK convention. - -### L3. `body` shadowed across `executeHttpCall` / `buildHttpRequest` / -`parseResponse` - -- **File / line:** `src/v1/utils.ts:81` (`body`, response bytes), `101` - (`body`, request body parameter), `113` (`body`, response bytes - again). -- **Category:** #1 vague generic name. -- **Current:** Single name `body` used for both request body and - response body, with different types - (`Uint8Array`, `string | ReadableStream`). -- **Suggestion:** `responseBody` / `requestBody`. -- **Rationale:** The same identifier `body` flows through helpers as a - request payload in one place and a response payload in another. - Differentiating helps readers track direction. - -### L4. `flattenQueryParams` is dead code in this package - -- **File / line:** `src/v1/utils.ts:123`. -- **Category:** dead code. -- **Current:** Exported but not used by `client.ts` (the list / get - methods build params inline via `URLSearchParams.append` calls at - `client.ts:161–222`). -- **Suggestion:** Drop the export or move to a shared util package. -- **Rationale:** Unused exports become accidental public API. Out of - scope for pure naming but flagged because the name promises a feature - that no method exercises. - -### L5. `fullName` (on `VolumeInfo`) vs. `fullNameArg` (on path-param -requests) - -- **File / line:** `model.ts:36, 148, 186` (`fullName` on - `CreateVolumeRequest`, `UpdateVolumeRequest.fullName` in payload, - `VolumeInfo.fullName`), `model.ts:56, 75, 126` (`fullNameArg` as path - param). -- **Category:** #6 misleading name; #19 underspecified IDs. -- **Current:** Two different fields naming the same logical concept - (the three-level volume identifier) differently depending on - request/response position. -- **Suggestion:** Resolve in concert with H1 — use `fullName` everywhere. - If proto generation requires the `_Arg` discriminator, then bury it - internally and surface only `fullName` to callers. -- **Rationale:** A user reading the API sees `fullName` on - `VolumeInfo` and `fullNameArg` on `DeleteVolumeRequest` and has to - ask: why are they different? The answer ("one is a request path - parameter") is generator-internal and should not bleed onto the - public surface. - -### L6. `pageReq` and `pageReq.pageToken` mutation in `listVolumesIter` - -- **File / line:** `src/v1/client.ts:251–260`. -- **Category:** #1 vague/generic. -- **Current:** `const pageReq: ListVolumesRequest = {...req};` then - mutates `pageReq.pageToken = resp.nextPageToken;` on each loop - iteration. -- **Suggestion:** `currentPageRequest` or `nextPageRequest`. -- **Rationale:** `pageReq` is fine as a Go-ism, but the variable is - reassigned across iterations — `pageRequest` makes the mutation site - more legible. Minor. +_None._ --- @@ -258,22 +175,6 @@ URL path parameter. Search: `grep -rE "fullNameArg|nameArg|idArg" packages/*/src/`. Documented here because the fix has cross-package implications. -### O3. URL path string repeated across methods without a named constant - -The base path `/api/2.1/unity-catalog/volumes` (and the suffixed -variant with `${req.fullNameArg ?? ''}`) appears five times in -`client.ts:93, 125, 160, 206, 277`. Not a naming defect, but typical -naming-audit findings include "unnamed magic strings." Worth a note. - -### O4. `PACKAGE_SEGMENT.key` / `.value` carry no descriptive name - -`client.ts:39–42`: `{key: pkgJson.name.replace(/^@[^/]+\//, ''), value: -pkgJson.version}`. The variable name `PACKAGE_SEGMENT` reads fine but -the `key`/`value` shape is generic — readers may not know `key` is -"package name" and `value` is "package version" without inspecting -`createDefault().with(...)`. No action required; cosmetic. Pattern is -identical across every generated client in the workspace. - --- ## Domain glossary @@ -309,27 +210,20 @@ Type & symbol checklist: - [x] `SseEncryptionAlgorithm` enum (3 members) → no defect. - [x] `VolumeType` enum (2 members) → no defect. - [x] `CreateVolumeRequest` interface (17 fields) → H2, M2. -- [x] `DeleteVolumeRequest` interface (1 field) → H1, L5. +- [x] `DeleteVolumeRequest` interface (1 field) → H1. - [x] `EncryptionDetails` interface → M4. -- [x] `GetVolumeRequest` interface (2 fields) → H1, L5. +- [x] `GetVolumeRequest` interface (2 fields) → H1. - [x] `ListVolumesRequest` interface (5 fields) → no additional defect. - [x] `SseEncryptionDetails` interface (2 fields) → M4. -- [x] `UpdateVolumeRequest` interface (18 fields) → H1, H2, M2, L5. -- [x] `VolumeInfo` interface (16 fields) → M1, M2, L5, O1. +- [x] `UpdateVolumeRequest` interface (18 fields) → H1, H2, M2. +- [x] `VolumeInfo` interface (16 fields) → M1, M2, O1. - [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `PACKAGE_SEGMENT` constant → O4. -- [x] `createVolume(req, options)` method → H2, M3, L2. -- [x] `deleteVolume(req, options)` method → H1, M3, L2. -- [x] `getVolume(req, options)` method → H1, M3, L2. -- [x] `listVolumes(req, options)` method → M3, L2. -- [x] `listVolumesIter(req, options)` async generator → M3, L6. -- [x] `updateVolume(req, options)` method → H1, H2, M3, L2. -- [x] `HttpCallOptions` interface → no defect. -- [x] `executeCall` function → L1. -- [x] `readAll` private function → no defect (name fits idiom). -- [x] `executeHttpCall` function → L1, L3. -- [x] `buildHttpRequest` function → L3. -- [x] `flattenQueryParams` function → L4 (unused). +- [x] `createVolume(req, options)` method → H2, M3. +- [x] `deleteVolume(req, options)` method → H1, M3. +- [x] `getVolume(req, options)` method → H1, M3. +- [x] `listVolumes(req, options)` method → M3. +- [x] `listVolumesIter(req, options)` async generator → M3. +- [x] `updateVolume(req, options)` method → H1, H2, M3. - [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). --- diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index c7de05f0..a6debb62 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -6,7 +6,6 @@ **Files audited:** - `src/v1/model.ts` - `src/v1/client.ts` -- `src/v1/utils.ts` - `src/v1/index.ts` This audit applies the 20 numbered concern categories from the audit @@ -29,10 +28,10 @@ This is the dominant theme of the audit (see F0). | Severity | Count | | ----------- | ----- | | High | 21 | -| Medium | 10 | -| Low | 40 | -| Observation | 17 | -| **Total** | **88** | +| Medium | 9 | +| Low | 29 | +| Observation | 16 | +| **Total** | **75** | --- @@ -83,33 +82,6 @@ This is the dominant theme of the audit (see F0). `StartRequest`, `StartRequest_Response`, `StopRequest`, `StopRequest_Response`. -### Schemas (`model.ts`) - -`unmarshalChannelSchema`, `unmarshalCreateWarehouseRequest_ResponseSchema`, -`unmarshalDefaultWarehouseOverrideSchema`, -`unmarshalEditWarehouseRequest_ResponseSchema`, -`unmarshalEndpointConfPairSchema`, `unmarshalEndpointHealthSchema`, -`unmarshalEndpointInfoSchema`, `unmarshalEndpointTagPairSchema`, -`unmarshalEndpointTagsSchema`, `unmarshalGetWarehouseRequest_ResponseSchema`, -`unmarshalGetWorkspaceWarehouseConfigRequest_ResponseSchema`, -`unmarshalListDefaultWarehouseOverridesResponseSchema`, -`unmarshalOdbcParamsSchema`, `unmarshalRepeatedEndpointConfPairsSchema`, -`unmarshalSetWorkspaceWarehouseConfigRequest_ResponseSchema`, -`unmarshalTerminationReasonSchema`, `unmarshalWarehouseTypePairSchema`, -`unmarshalDeleteWarehouseRequest_ResponseSchema`, -`unmarshalListWarehousesRequest_ResponseSchema`, -`unmarshalStartRequest_ResponseSchema`, -`unmarshalStopRequest_ResponseSchema`, `marshalChannelSchema`, -`marshalCreateWarehouseRequestSchema`, `marshalDefaultWarehouseOverrideSchema`, -`marshalEditWarehouseRequestSchema`, `marshalEndpointConfPairSchema`, -`marshalEndpointTagPairSchema`, `marshalEndpointTagsSchema`, -`marshalRepeatedEndpointConfPairsSchema`, -`marshalSetWorkspaceWarehouseConfigRequestSchema`, -`marshalWarehouseTypePairSchema`, `marshalStartRequestSchema`, -`marshalStopRequestSchema`. Also exports -`defaultWarehouseOverrideFieldMask` helper and -`defaultWarehouseOverrideFieldMaskSchema` (private). - ### Client methods (`client.ts`) `createDefaultWarehouseOverride`, `createWarehouse`, @@ -125,18 +97,7 @@ This is the dominant theme of the audit (see F0). ### Client classes (`client.ts`) `Client`, `CreateWarehouseWaiter`, `EditWarehouseWaiter`, -`StartWarehouseWaiter`, `StopWarehouseWaiter`, -`StillRunningError` (private). - -### Utility functions (`utils.ts`) - -`executeCall`, `readAll` (private), `executeHttpCall`, -`buildHttpRequest`, `parseResponse`, `marshalRequest`, -`flattenQueryParams`. - -### Utility types/interfaces (`utils.ts`) - -`HttpCallOptions`. +`StartWarehouseWaiter`, `StopWarehouseWaiter`. --- @@ -320,11 +281,6 @@ compatibility while updating the customer-visible type names. Already typed against the `TerminationCode` enum, so renaming introduces redundancy. Leave. -#### F1.12 — `Call`, `Options` (imported, cross-package) (acceptable) -- **Where:** `utils.ts:3`, `client.ts:4`. -- These come from `@databricks/sdk-core/api`. Generic but - intentional. Out of scope for this package's audit. - --- ### 2. Redundant enum prefixes @@ -477,22 +433,7 @@ _None._ accurate. - **Suggestion:** Rename to `ChannelType` or `WarehouseChannel`. -#### F6.7 — `Channel.dbsqlVersion` as the override mechanism (LOW) -- **Where:** `model.ts:703`. -- **Why flagged:** Field is required only when `name` is - `CHANNEL_NAME_CUSTOM`. JSDoc on the parent says so. Name - itself does not convey the conditional contract. -- **Suggestion:** Add JSDoc; field name is fine. - -#### F6.8 — `instanceProfileArn` JSDoc says "Deprecated" but field remains (LOW) -- **Where:** `model.ts:786, 930, 1048, 1183`. -- **Why flagged:** Identifier carries no `_DEPRECATED` marker; - only JSDoc. Customer code completion shows it as a normal - field. -- **Suggestion:** Add `@deprecated` JSDoc tag (separate from - prose) so IDEs strike it through. - -#### F6.9 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) +#### F6.7 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) - **Where:** `model.ts:784, 928, 1046, 1181`. - **Why flagged:** The field is settable on `CreateWarehouseRequest`/`EditWarehouseRequest`, but its meaning @@ -501,11 +442,7 @@ _None._ - **Suggestion:** Spec-level. Mark read-only on response types only. -#### F6.10 — `EndpointHealth.message` is "Deprecated" prose but no marker (LOW) -- **Where:** `model.ts:970`. -- Same pattern as F6.8. - -#### F6.11 — Waiter `done` returns true on terminal failure states (MEDIUM) +#### F6.8 — Waiter `done` returns true on terminal failure states (MEDIUM) - **Where:** `client.ts:690, 770, 850, 925` (the `done()` of each Waiter). - **Why flagged:** `done()` returns `true` for `RUNNING`, @@ -534,11 +471,6 @@ _None._ - **Suggestion:** Acceptable; AIP-compliant. Aliasing at the call site is the typical workaround. -#### F7.2 — `defaultWarehouseOverrideFieldMask` (LOW) -- **Where:** `model.ts:1995`. -- **Why flagged:** Long, but consistent with the AIP-style - resource name. Acceptable. - --- ### 8. Redundant suffixes @@ -684,38 +616,6 @@ _None. Wrappers are retained for forward compatibility._ category 12: the entire `Endpoint*` family is historical baggage from the rename of "SQL Endpoints" to "SQL Warehouses". -#### F12.5 — `numActiveSessions` deprecated field still on response types (LOW) -- **Where:** `model.ts:1077, 1212`. -- **Why flagged:** JSDoc says "Deprecated. current number of - active sessions for the warehouse". Carries no `@deprecated` - tag. -- **Suggestion:** Add `@deprecated`. Schedule for removal. - -#### F12.6 — `EndpointHealth.message` deprecated (LOW) -- **Where:** `model.ts:970`. Same pattern. - -#### F12.7 — `instanceProfileArn` deprecated (LOW) -- **Where:** `model.ts:786, 930, 1048, 1183`. Same. - -#### F12.8 — `globalParam`, `configParam` deprecated in favor of -`sqlConfigurationParameters` (LOW) -- **Where:** `model.ts:1250, 1252, 1339, 1341`. Same. - -#### F12.9 — `ListWarehousesRequest.runAsUserId` deprecated and ignored (LOW) -- **Where:** `model.ts:1438`. JSDoc says "Deprecated: this field - is ignored by the server." -- **Suggestion:** Add `@deprecated` and consider removal. - -#### F12.10 — Workspace config endpoint duplicates per-warehouse fields (MEDIUM) -- **Where:** `instanceProfileArn`, `channel`, - `enableServerlessCompute` all appear in both per-warehouse - (`CreateWarehouseRequest`) and workspace - (`SetWorkspaceWarehouseConfigRequest`) types. -- **Why flagged:** The same field name maps to two different - conceptual levels (per-warehouse override vs. workspace - default). A reader can't tell from the field name alone. -- **Suggestion:** Document the dual presence in JSDoc. - --- ### 13. Verb-tense inconsistency @@ -738,7 +638,7 @@ _None. Wrappers are retained for forward compatibility._ ### 14. Go/Java-style names #### F14.1 — `req`, `resp`, `opts` Go abbreviations (LOW) -- **Where:** `client.ts` throughout; `utils.ts:30, 47, 60, 66`. +- **Where:** `client.ts` throughout. - **Why flagged:** Go convention is `req`, `resp`, `opts`; TS convention is `request`, `response`, `options`. SDK already uses `options` (full word) so the abbreviation is inconsistent @@ -746,7 +646,7 @@ _None. Wrappers are retained for forward compatibility._ - **Suggestion:** Generator-level. #### F14.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) -- **Where:** `client.ts:411, 468`, `utils.ts:48`. +- **Where:** `client.ts:411, 468`. - **Why flagged:** `for (;;)` is C/Go idiom; TS prefers `while (true)` for readability. Minor. - **Suggestion:** Generator-level. @@ -830,14 +730,6 @@ _None. Wrappers are retained for forward compatibility._ resource is being created either. - **Suggestion:** Acceptable. -#### F16.3 — `EndpointSpotInstancePolicy.RELIABILITY_OPTIMIZED` is misnamed (LOW) -- **Where:** `model.ts:80`. -- **Why flagged:** Per JSDoc, on Azure it makes no difference - (both On Demand) — only AWS distinguishes. The name implies - reliability is universally improved, but on Azure it is a - no-op. -- **Suggestion:** Document; rename optional. - --- ### 17. Inconsistent action verbs @@ -863,16 +755,7 @@ _None. Wrappers are retained for forward compatibility._ machines. Good. - **Suggestion:** No change. -#### F17.3 — `Set` (`setWorkspaceWarehouseConfig`) vs. `Update` (LOW) -- **Where:** `client.ts:481`. -- **Why flagged:** `set` semantically means "replace entire - resource"; `update` means "patch fields". Both apply here. - `setWorkspaceWarehouseConfig` uses PUT (full replace) — - `set` is correct. -- **Suggestion:** No change. But document the PUT semantics in - JSDoc. - -#### F17.4 — `Create` and `Delete` (acceptable) +#### F17.3 — `Create` and `Delete` (acceptable) - Standard CRUD. No issue. --- diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index 0d30beb7..2650d03d 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -3,15 +3,15 @@ **Path:** `packages/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 18 +**Total weird names flagged:** 7 ## Summary | Severity | Count | | --- | --- | | High | 3 | -| Medium | 10 | -| Low | 2 | -| Observation | 3 | +| Medium | 3 | +| Low | 0 | +| Observation | 1 | The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **stringly-typed `securableType`** that should be a closed enum; (2) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (3) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction, and the verbs "bind"/"assign" are mixed inside a single request type (`UpdateCatalogWorkspaceBindingsRequest.assignWorkspaces`). @@ -57,84 +57,24 @@ The package contains 9 generated types (1 enum + 8 message/response shapes) and - **Suggested name:** Keep the name `workspaceId` but consider `bigint` or `string` for the type. This is a project-wide concern. - **Rationale:** Cross-cutting JS interop issue; not unique to this package, but flagged for completeness. -### 6. `pageToken?: string` doc — `src/v1/model.ts:36-37` -- **Why weird:** Doc-comment "Opaque pagination token to go to next page based on previous query" is OK, but in the response side `nextPageToken` (line 45-48) the doc refers to "__page_token__" with double-underscores — a documentation hangover from a wire-format spec. Inconsistent with the TS field name `pageToken`. -- **Category:** 6 (misleading docs), Observation. -- **Suggested name:** Field name is fine; fix the doc to use TS field name `pageToken`. -- **Rationale:** Doc-comment consistency. - -### 7. `nextPageToken?: string` — `src/v1/model.ts:48` -- **Why weird:** The doc-comment includes `__page_token__` (double-underscore) referring to the request field. The actual TS field is named `pageToken` — the doc is documenting wire format, not TS. -- **Category:** 6 (misleading docs). -- **Suggested name:** Field name is fine; fix the doc text. -- **Rationale:** See #6. - -### 8. `getCatalogWorkspaceBindings` method — `src/v1/client.ts:80` -- **Why weird:** Catalog-specific variant of the generic `getWorkspaceBindings` (see #2). The method is undocumented as deprecated even though the generic endpoint subsumes it. The JSDoc on lines 76-79 makes no mention of the generic alternative. -- **Category:** 12 (duplicate concept), Observation. -- **Suggested name:** Mark with `@deprecated` JSDoc and reference `getWorkspaceBindings`. -- **Rationale:** IDE strike-through requires the `@deprecated` tag. - -### 9. `updateCatalogWorkspaceBindings` method — `src/v1/client.ts:179` -- **Why weird:** Same as #8. The catalog-specific update is strictly less expressive than the generic update (cannot set `bindingType`) — should not be the recommended path. -- **Category:** 12, Observation. -- **Suggested name:** Mark with `@deprecated`. -- **Rationale:** See #8. - -### 10. `Client` — `src/v1/client.ts:46` +### 6. `Client` — `src/v1/client.ts:46` - **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). - **Category:** 1 (vague), 12 (duplicate across packages). - **Suggested name:** `WorkspaceBindingsClient`. - **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. -### 11. `executeCall` — `src/v1/utils.ts:26` -- **Why weird:** Generic verb-noun name. Two `execute` functions in scope (`execute` imported on line 4, `executeCall` defined on line 26, `executeHttpCall` defined on line 65). The discriminator between them is just "Call" vs "HttpCall" — and both ultimately wrap the imported `execute()`. -- **Category:** 1 (vague), 17 (inconsistent action verbs). -- **Suggested name:** `executeRetryableCall` (since this one applies the retrier/rateLimiter/timeout options) or `executeWithOptions`. -- **Rationale:** Distinguishes the two wrappers semantically. - -### 12. `executeHttpCall` — `src/v1/utils.ts:65` -- **Why weird:** Generic name for what is actually "send an HTTP request, drain the body, surface API errors as exceptions, and return the raw body bytes". The function name does not communicate that it throws `ApiError` on 4xx/5xx (line 88-91) — a non-obvious side effect. -- **Category:** 1 (vague), 6 (misleading: "execute" sounds neutral but throws). -- **Suggested name:** `sendAndParseResponse` or `sendOrThrow`. -- **Rationale:** Naming should hint at error semantics. - -### 13. `HttpCallOptions` (interface) — `src/v1/utils.ts:15` -- **Why weird:** Yet another `*Options` suffix in a file that already imports `Options` (line 3) and `CallOptions` (line 12) — three `Options` types in scope. `HttpCallOptions` is purely an internal context bag for `executeHttpCall` (request + httpClient + logger) — it isn't user-tunable, so `Options` is misleading. -- **Category:** 1 (vague suffix), 8 (redundant suffix), 17 (inconsistency). -- **Suggested name:** `HttpCallContext` (it's a context bag, not user-tunable options). -- **Rationale:** Distinguish internal context bags from user-facing option structs. - --- ## Low severity -### 14. `flattenQueryParams` — `src/v1/utils.ts:123` -- **Why weird:** Exported but unused in this package (the client builds query strings inline with `URLSearchParams.append` on `client.ts:117-122`). Dead-looking export from the standard generator template. -- **Category:** Observation, 11 (unused public helper). -- **Suggested name:** Remove if generator default; or move to a shared utility package and not emit per-package. -- **Rationale:** Cross-package consistency. - -### 15. `PACKAGE_SEGMENT` constant — `src/v1/client.ts:41` -- **Why weird:** `Segment` is a generic word; without the inline doc-comment the constant doesn't communicate User-Agent identity. Same issue exists in every generated package. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `USER_AGENT_PACKAGE_SEGMENT`. -- **Rationale:** Cross-package consistency. +_None._ --- ## Observations -### 16. Client `Host is required.` error message — `src/v1/client.ts:61` +### 7. Client `Host is required.` error message — `src/v1/client.ts:61` The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. - **Category:** Observation. -### 17. `marshalRequest` / `parseResponse` schemas not re-exported from `index.ts` -The marshal/unmarshal helpers are exported from `model.ts` (via `export const`) but `index.ts` (lines 7-17) only re-exports types and `Client`. So the schemas are part of the package's effective import surface (`import {...} from '@databricks/sdk-workspacebindings/v1/model'`) but not advertised. Dead surface or intentional? If the latter, the `export const` should be `const` (module-local). -- **Category:** Observation, 11 (effectively-internal exports). - -### 18. `WorkspaceBindingInfo.workspaceId` doc-comment "Required" — `src/v1/model.ts:89` -The single word "Required" appears as a doc-comment on `workspaceId?: number`. But the field is *optional* in the TypeScript type (`workspaceId?: number | undefined`). The annotation contradicts the type modifier. Either: (a) the field is genuinely required by the server and the optional TS type is generator-wide policy (proto3 fields are all optional in TS); or (b) the doc is stale. Either way, readers can't tell. -- **Category:** Observation, 6 (misleading docs). - --- diff --git a/.agent/naming-audit/workspaceobjects.md b/.agent/naming-audit/workspaceobjects.md index 8bbca710..cec13dea 100644 --- a/.agent/naming-audit/workspaceobjects.md +++ b/.agent/naming-audit/workspaceobjects.md @@ -6,7 +6,7 @@ notebooks, folders, and files — import, export, delete, list, get-status, and mkdirs against absolute paths under `/Workspace`. Wire prefix: `/api/2.0/workspace/`. -**Total weird names flagged:** 14 +**Total weird names flagged:** 10 ## Scope note: `workspaceobjects` vs sibling packages @@ -27,9 +27,9 @@ others differ in scope: | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 6 | -| Low | 5 | +| High | 4 | +| Medium | 2 | +| Low | 4 | | Observation | 6 | ## Summary table @@ -40,16 +40,12 @@ others differ in scope: | 2 | High | `model.ts:18` enum value | `ExportFormat.AUTO` | Ambiguous enum value (different behaviour for import vs. export) | | 3 | High | `model.ts:24` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | | 4 | High | `model.ts:28` enum | `Language` | Vague/generic, no domain prefix | -| 5 | Medium | `model.ts:48` enum value | `ObjectType.LIBRARY` | Misleading (workspace libraries are an obsolete concept) | -| 6 | Medium | `model.ts:102` field | `ExportRequest_Response.content` typed `Uint8Array` | Type contradicts JSDoc ("base64-encoded content") | -| 7 | Medium | `model.ts:138` field | `ImportRequest.content` typed `Uint8Array` | Same type/JSDoc mismatch as 6 in reverse direction | -| 8 | Medium | `model.ts:162` type | `MkdirsRequest` | Unix-ism (`mkdir -p`); sibling `files` package uses `createDirectory` | -| 9 | Medium | `client.ts:157` method | `getStatus` | Vague verb; returns full `ObjectInfo` metadata (a `stat`, not a status) | -| 10 | Low | `model.ts:16` enum value | `ExportFormat.R_MARKDOWN` | Shape mismatch — single underscored value among single-token values | -| 11 | Low | `model.ts:14` enum value | `ExportFormat.DBC` | Cryptic product-specific abbreviation (Databricks archive) | -| 12 | Low | `model.ts:174` interface | `ObjectInfo` | `Info` suffix carries no information; central entity is just an "Object" | -| 13 | Low | `client.ts:266` method | `mkdirs` | Lower-case Unix contraction next to other `verbNoun` methods (`getStatus`, `import`, `export`) | -| 14 | Low | `model.ts:17-23` JSDoc | "We will inspect…" / "This is introduced to unblock a DR use case" | First-person and ticket-driven prose in public JSDoc | +| 5 | Medium | `model.ts:162` type | `MkdirsRequest` | Unix-ism (`mkdir -p`); sibling `files` package uses `createDirectory` | +| 6 | Medium | `client.ts:157` method | `getStatus` | Vague verb; returns full `ObjectInfo` metadata (a `stat`, not a status) | +| 7 | Low | `model.ts:16` enum value | `ExportFormat.R_MARKDOWN` | Shape mismatch — single underscored value among single-token values | +| 8 | Low | `model.ts:14` enum value | `ExportFormat.DBC` | Cryptic product-specific abbreviation (Databricks archive) | +| 9 | Low | `model.ts:174` interface | `ObjectInfo` | `Info` suffix carries no information; central entity is just an "Object" | +| 10 | Low | `client.ts:266` method | `mkdirs` | Lower-case Unix contraction next to other `verbNoun` methods (`getStatus`, `import`, `export`) | ## High severity @@ -102,44 +98,7 @@ others differ in scope: ## Medium severity -### 5. `ObjectType.LIBRARY` — obsolete enum value -- **Location:** `model.ts:48` -- **Category:** Misleading enum value (encoded concept is obsolete). -- **Suggested name:** Keep the name but mark `@deprecated` in JSDoc with a - pointer to the cluster-libraries / job-libraries APIs. -- **Rationale:** Workspace "libraries" as a top-level object type were - superseded years ago by cluster-level and job-level library - configurations. The value is exported in `ObjectType` without a - deprecation marker. Consumers writing `if (obj.objectType === - ObjectType.LIBRARY)` are coding against a branch the server almost never - returns; that is a discoverability hazard. - -### 6. `ExportRequest_Response.content` — type contradicts "base64-encoded" JSDoc -- **Location:** `model.ts:98-102`; decoded via `marshalSchema` transform at - `model.ts:211-213`. -- **Category:** Type/JSDoc mismatch. -- **Suggested name:** Keep the field name, fix the JSDoc to say "Raw bytes - decoded from the server's base64 encoding," or rename to `bytes`. -- **Rationale:** The JSDoc says the content is base64-encoded; the type is - `Uint8Array` (raw bytes). The transform schema does `atob(s).charCodeAt` - before populating the field, so the field already holds decoded bytes. - The JSDoc was lifted from the wire-format documentation and never - updated for the post-decode shape. "Uint8Array of base64-encoded data" - is technically meaningless. - -### 7. `ImportRequest.content` — type contradicts "base64-encoded" JSDoc -- **Location:** `model.ts:132-138`; encoded via `marshalSchema` transform - at `model.ts:276-281`. -- **Category:** Type/JSDoc mismatch (mirror of 6). -- **Suggested name:** Keep the name; fix the JSDoc to say "Raw bytes; the - client base64-encodes before sending." -- **Rationale:** The mirror of finding 6 in the reverse direction. The - client encodes the bytes to base64 before sending. A defensive caller - who reads the JSDoc and base64-encodes their bytes will double-encode - and corrupt the upload. The mismatch is silent and the failure mode is - data corruption. - -### 8. `MkdirsRequest` — Unix-ism +### 5. `MkdirsRequest` — Unix-ism - **Location:** `model.ts:162` (type), `client.ts:266` (method). - **Category:** Cryptic Unix abbreviation, cross-package inconsistency. - **Suggested name:** `CreateDirectoryRequest`. @@ -150,7 +109,7 @@ others differ in scope: the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the request body holds one path, so even the wire name is misleading. -### 9. `getStatus` — vague verb on the client +### 6. `getStatus` — vague verb on the client - **Location:** `client.ts:157` - **Category:** Vague verb; misleading category (returns metadata, not a status enum); inconsistent return shape vs. peer methods. @@ -167,7 +126,7 @@ others differ in scope: ## Low severity -### 10. `ExportFormat.R_MARKDOWN` — shape mismatch within the enum +### 7. `ExportFormat.R_MARKDOWN` — shape mismatch within the enum - **Location:** `model.ts:15-16` - **Category:** Inconsistent shape inside an enum (most values single token, one with an underscore). @@ -178,7 +137,7 @@ others differ in scope: `R_MARKDOWN` with an underscore. Inconsistent shape inside the same enum. -### 11. `ExportFormat.DBC` — cryptic abbreviation +### 8. `ExportFormat.DBC` — cryptic abbreviation - **Location:** `model.ts:13-14` - **Category:** Cryptic product-specific abbreviation. - **Suggested name:** `DATABRICKS_ARCHIVE` on the TS identifier; the wire @@ -188,7 +147,7 @@ others differ in scope: expects) means the rename must happen on the enum-key layer, not the enum-value layer — TypeScript supports that cleanly. -### 12. `ObjectInfo` — `Info` suffix +### 9. `ObjectInfo` — `Info` suffix - **Location:** `model.ts:174-200` - **Category:** Vague suffix; Go/Java convention carried into TS without reason. @@ -201,7 +160,7 @@ others differ in scope: a hat-tip to the Go SDK. A name like `WorkspaceObject` would also avoid the JS `Object` collision. -### 13. `mkdirs` client method — Unix contraction next to verb-noun siblings +### 10. `mkdirs` client method — Unix contraction next to verb-noun siblings - **Location:** `client.ts:266` - **Category:** Verb-tense / shape inconsistency among sibling methods. - **Suggested name:** `createDirectory`. @@ -210,21 +169,6 @@ others differ in scope: `mkdirs` is the only Unix-style contraction. `createDirectory` would align with `getStatus` and with the `files` package convention. -### 14. First-person and ticket-driven prose in JSDoc -- **Location:** `model.ts:17` ("We will inspect the content of the payload - to determine the type"); `model.ts:19-23` ("This is introduced to - unblock a DR use case importing .zip file as is. … In workspace 3.0 - folder import will be supported via a different API."). -- **Category:** JSDoc voice / customer-facing prose. -- **Suggested name:** Rewrite as third-person product documentation — - e.g. "The server inspects the payload header to determine the type." for - `AUTO`, and "Use to import a `.zip` file without unwrapping it." for - `RAW`. -- **Rationale:** "We will inspect" and "This is introduced to unblock a - DR use case" read as commit-message or design-doc fragments, not - customer-facing documentation. JSDoc renders into IDE tooltips that - consumers see. Naming-adjacent but flagged. - ## Observations 1. **Filesystem package without filesystem vocabulary.** The package diff --git a/.agent/naming-audit/workspaces.md b/.agent/naming-audit/workspaces.md index 2c61092f..d48a0296 100644 --- a/.agent/naming-audit/workspaces.md +++ b/.agent/naming-audit/workspaces.md @@ -95,8 +95,6 @@ _None._ | --------------------- | ----- | ------------------------------------------------------------------------ | | `src/v1/model.ts` | 829 | All 5 enums, all 13 interfaces, every field, all 11 marshal/unmarshal schemas, field-mask schemas. | | `src/v1/client.ts` | 423 | `Client` class, constructor, 5 RPC methods + 2 waiter factories, 2 waiter classes, import list. | -| `src/v1/utils.ts` | 151 | All exported / private helpers. No proto-leak hits. | -| `src/v1/transport.ts` | 75 | `newHttpClient` factory + auth wrapper. No proto-leak hits. | | `src/v1/index.ts` | 35 | All re-exports — names mirror `model.ts` and `client.ts` (covered above).| Type & symbol checklist: @@ -172,15 +170,4 @@ Type & symbol checklist: `updateWorkspacePublicWaiter` — flagged (#2). - [x] `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter` classes — flagged (#3). -- [x] `StillRunningError` private sentinel class — clean (cross-package - pattern; not a domain identifier). - [x] `client.ts` import list / `index.ts` re-exports — flagged (#4). -- [x] `utils.ts` (`executeCall`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`, `readAll`, - `HttpCallOptions`) — no proto-architectural-leak names. (The - `executeCall` / `executeHttpCall` verb overlap is a common - cross-package pattern; out of scope here.) -- [x] `transport.ts` (`newHttpClient`, auth-wrapping class) — no - `Public`/`Internal`/`Proto`/`Service`/`Manager` leak in domain - identifiers. (The auth wrapper class itself is a cross-package - pattern, not flagged here.) diff --git a/AGENTS.md b/AGENTS.md index 9d6f2060..a4bb6def 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -149,9 +149,7 @@ synthesis step that updates `_SUMMARY.md` or similar). ### Active TODOs -- 2026-05-26 — rebase + rerun audit on updated branch — rescan done (87/87 pkgs: 1 fix in logdelivery, rest still); `_SUMMARY.md` synthesis pending, will roll into the next cleanup synthesis. -- 2026-05-26 — collapse retired/orphan audit bodies to just the title + status block (example given: `qualitymonitors`) — in progress. -- 2026-05-26 — prune findings whose primary recommendation is a JSDoc/doc change (example: `apps.md` H9 `noCompute` doc clarification). Reason: "those can be anytime." — in progress. +- 2026-05-26 — regenerate `_SUMMARY.md` to reflect all the 2026-05-26 pruning passes (rebase+rescan, AIP-name, sibling-enum, field-rename, doc-change, SDK-internal, non-TS) and the orphan deletions. — in progress. (When populated, each line is one TODO in the form: `- YYYY-MM-DD — `.) From 6e09df950e5978e2393717291c733d4651485427 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Thu, 28 May 2026 22:04:10 +0000 Subject: [PATCH 10/12] update --- .agent/naming-audit/_SUMMARY.md | 449 ++++++++++++++++---------------- AGENTS.md | 2 +- 2 files changed, 224 insertions(+), 227 deletions(-) diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index 2ab3adf5..6b8c2654 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -790,74 +790,66 @@ this rule on 2026-05-21. Document the choice in --- -## 5. Top-48 highest-impact individual findings - -Picked one per package where possible, prioritising ones with broad reuse. -Findings ranked High severity in their audit. Entries whose package was -deleted/merged in the 2026-05-20 or 2026-05-22 regeneration have been -removed; entries about the now-pruned enum-name-prefix theme and -`*_UNSPECIFIED` sentinel existence have been removed; entries whose -underlying finding has moved to `Fixed` after the 2026-05-22 regen (the -`*Public*Request` proto-leak across `networking`, `workspaces`, -`metastores`, etc.) have been removed. In the 2026-05-22 Theme 2 prune -the former `pipelines` "Pipelines\* prefix on 15 types" row and the -`genie` "40 of ~70 types prefixed Genie\*" row were removed. Entries -for `oauth` (`OAuthAppIntegration*`) and `cleanrooms` (`CleanRoom*`) -are retained because their `Foo*` prefixes were flagged for the -secondary consolidation/merge symptom — see prune note 7 — not the -type-name-prefix-only finding. Each entry: file + symbol + the -generator pattern it exemplifies. +## 5. Top highest-impact surviving findings + +Picked from the post-2026-05-26-prune corpus. Entries that depended on +field-rename, doc-change, SDK-internal, or non-TS findings (now all +out-of-scope) have been removed. The retained entries are +structural type-level issues — type names, reserved-word collisions, +brand drift, cross-package duplicate concepts, and the surviving +proto-architectural leaks. Each entry: file + symbol + the generator +pattern it exemplifies. | # | Package | File:Line | Symbol / Issue | Pattern | |---|---|---|---|---| -| 1 | `jobs` | `model.ts:3414, 3890` | `Run` overloaded across 7 shapes (`Run`, `BaseRun`, `RunTask`, `Run_JobLevelParameters`, `RunState`, `RunStatus`, `RunTriggerInfo`). | Vague/duplicate concepts | +| 1 | `jobs` | `model.ts:3399, 3491, 3852, 3866, 4261, 908, 3875` | `Run` overloaded across 7 shapes (`Run`, `BaseRun`, `RunTask`, `Run_JobLevelParameters`, `RunState`, `RunStatus`, `RunTriggerInfo`). | Vague/duplicate concepts | | 2 | `jobs` | `model.ts:150, 280, 1464, 1835` | `Format`, `Source`, `Compute`, `Environment` — top-level types collide with JS/TS built-ins and DOM globals. | Reserved-word collision | -| 3 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | -| 4 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | -| 5 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in type names | -| 6 | `abacpolicies` | `model.ts:190` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | -| 7 | `tables` | `model.ts:passim` | `fullNameArg` path-param field name (5+ UC packages share this). | Cryptic `Arg` suffix | -| 8 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | -| 9 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | -| 10 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission.CAN_USE` — `App` token thrice; package-name re-prefix throughout. | Redundant prefix | -| 11 | `genie` | `client.ts:131, 1019, 1038` | Method naming: 28 of 30 prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | -| 12 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | -| 13 | `commandexecution` | `model.ts:71, 100, 112` | Three different `id?: string` fields — should be `contextId`/`commandId`. | Underspecified IDs | -| 14 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | -| 15 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | -| 16 | `secrets` | `model.ts:passim` | `ListAcls_Response.items` should be `acls` (parallel to `ListScopes_Response.scopes` / `ListSecrets_Response.secrets`). | Field-name vocabulary drift | -| 17 | `dataquality` | model + types | `ListMonitorRequest` singular for list of monitors; `qualitymonitor`/`qualitymonitors` deprecated and retired in 2026-05-22 regen. | Singular/plural mismatch | -| 18 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | -| 19 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | -| 20 | `oauth` | `model.ts:passim` | After the merge, `OAuthAppIntegration*` types still re-state the package name on every shape. The finding survives prune-pass 7 because its primary citation is the post-merge `Custom`/`Published` consolidation friction, not the bare package-prefix pattern. | Post-merge prefix friction (Theme 2 retained) | -| 21 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, the type-name overlap with `iam` and `grants` is still present. | Cross-package fragmentation | -| 22 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | -| 23 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`, `ListTokens`, `RevokeToken`. | Cross-package collisions | -| 24 | `tagassignments` + `entitytagassignments` | model.ts | Same conceptual object has `entityId` here, `entityName` there. | Cross-package field drift | -| 25 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | -| 26 | `customllms` | every file | `Llm` casing throughout — SDK has no acronym-casing policy. | Acronym casing | -| 27 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | -| 28 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds; `toolType: string`. | Stringly-typed sum | -| 29 | `cleanrooms` | `model.ts:passim` | After absorbing 3 sibling packages, `CleanRoom*` re-prefix still pervades. Retained post-prune-pass 7 because the finding is cited for the post-consolidation friction, not the bare package-prefix pattern. | Post-merge prefix friction (Theme 2 retained) | -| 30 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | -| 31 | `iam` | `model.ts:41-48` | `State` (top-level enum named `STATE`) — collides with React `setState`/dozens of state-machine libs. | Generic top-level enum | -| 32 | `iam` | `model.ts:13-21` | `Entitlement` — vague name for workspace-only entitlement enum; mixes presence and permission semantics. | Vague enum | -| 33 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types, all collide with common JS terms. | Generic naming | -| 34 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | -| 35 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | -| 36 | `notificationdestinations` | `model.ts:17, 13` | `Config` interface + `config` field — vague top-level name + self-referential field; `DestinationType` vague enum. | Self-referential field + generic naming | -| 37 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | -| 38 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | -| 39 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum has 22 values with inconsistent casing (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Acronym/brand-value casing | -| 40 | `clusters` | `model.ts:175-734` | `TerminationCode` enum has 150+ values with inconsistent casing (`AZURE_BYOK_*`, `NPIP_*`, `K8S_DBR_*`, `AWS_*`). | Acronym/brand-value casing | -| 41 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | -| 42 | `bundle` | package + types | Bare "bundle" word collides with Webpack/Vite/Rollup; verb-as-noun residue in request types. | Generic naming | -| 43 | `instancepools` | `model.ts:passim` | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | -| 44 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection`; `tpe` typo (likely intended `type`). | Generator stutter + typo | -| 45 | `settings` | `model.ts:passim` | After the regen consolidation, the v2 surface still carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrapper sprawl. | Generic + cryptic | -| 46 | `jobs` | `model.ts:passim` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | -| 47 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun, not a domain concept. | Proto-architectural leak (`Service` infix) | -| 48 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | +| 3 | `jobs` | `model.ts` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | +| 4 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | +| 5 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | +| 6 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in method names | +| 7 | `iam` | `model.ts:41-48` | `State` (top-level enum) — collides with React `setState`/state-machine libraries. | Generic top-level enum | +| 8 | `iam` | `model.ts:13-21` | `Entitlement` — vague enum mixing presence and permission semantics. | Vague enum | +| 9 | `abacpolicies` | `model.ts:137` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | +| 10 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | +| 11 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | +| 12 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission` — `App` token thrice on the type path. | Redundant prefix | +| 13 | `apps` | `model.ts` | `DatabricksServiceExceptionProto`, `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix. | Proto-architectural leak (`Proto` suffix) | +| 14 | `genie` | `client.ts:131, 1019, 1038` | 28 of 30 methods prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | +| 15 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | +| 16 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | +| 17 | `commandexecution` | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` — too short to convey what they wait for. | Waiter-class genericity | +| 18 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | +| 19 | `dataquality` | model.ts | `ListMonitorRequest` singular for a list-of-monitors request. | Singular/plural mismatch | +| 20 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | +| 21 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | +| 22 | `oauth` | `model.ts:passim` | After the merge, `OAuthAppIntegration*` vs `CustomOAuthAppIntegration*` consolidation friction. | Post-merge consolidation friction | +| 23 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, type-name overlap with `iam` and `grants` is still present. | Cross-package fragmentation | +| 24 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 25 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`. | Cross-package collisions | +| 26 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | +| 27 | `customllms` | every file | `CustomLlm` — generic name with cryptic-acronym body. | Generic naming + cryptic abbreviation | +| 28 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 29 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds. | Stringly-typed sum | +| 30 | `cleanrooms` | `client.ts:662, 704` | `listCleanRoomNotebookTaskRunsHandler` / `listCleanRoomNotebookTaskRunsHandlerIter` — `Handler` suffix proto-leak. | Proto-architectural leak (`Handler` suffix) | +| 31 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | +| 32 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types. | Generic naming | +| 33 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | +| 34 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 35 | `notificationdestinations` | `model.ts:17, 13` | `Config` top-level interface; `DestinationType` vague enum. | Generic top-level name | +| 36 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 37 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | +| 38 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum with 22 values mixing case styles (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Brand-value casing | +| 39 | `clusters` | `model.ts:175-734` | `TerminationCode` enum with 150+ values mixing case styles. | Brand-value casing | +| 40 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | +| 41 | `bundle` | package + types | Bare "bundle" word collides with Webpack/Vite/Rollup. | Generic package name | +| 42 | `instancepools` | `model.ts:passim` | Structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | +| 43 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection` stutter. | Generator stutter | +| 44 | `settings` | `model.ts:passim` | Post-consolidation v2 surface carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrappers. | Generic + cryptic | +| 45 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun. | Proto-architectural leak (`Service` infix) | +| 46 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | +| 47 | `marketplaces` | `model.ts:passim` | `Exchange` vs `Listing` vocabulary tension within a single package. | Vocabulary drift | +| 48 | `forecasting` | `client.ts` | `CreateForecastingExperimentWaiter` + Go-style `Waiter.done()` predicate. | Go-style waiter pattern | --- @@ -865,104 +857,104 @@ generator pattern it exemplifies. | # | Package | Findings | Top theme | |---|---|---|---| -| 1 | jobs | 169 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | -| 2 | warehouses | 100 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | -| 3 | settings | 84 | Cross-package consolidation residue; cryptic acronyms (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | -| 4 | clusters | 78 | Per-cloud-enum-prefix inconsistency; 150-member `TerminationCode` | -| 5 | modelregistry | 66 | Workspace vs UC duplicate (`registeredmodels`); `MLflow` vocabulary | -| 6 | apps | 63 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology | -| 7 | pipelines | 62 | `Update` noun = pipeline run; JSDoc "Public RPC" banners (Theme 2 `Pipelines*` prefix pruned 2026-05-22) | -| 8 | genie | 61 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term (Theme 2 `Genie*` prefix pruned 2026-05-22) | -| 9 | instanceprofiles | 61 | Bare verb request types; vague identifiers | -| 10 | tables | 58 | `fullNameArg`; `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 11 | database | 54 | Package name overlaps `postgres`; deep proto nesting; proto-architectural infixes | -| 12 | postgres | 54 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | -| 13 | statementexecution | 52 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | -| 14 | features | 51 | Three sibling feature packages with blurry boundaries (now reduced to 2 after `materializedfeatures` retirement) | -| 15 | marketplaces | 51 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | -| 16 | experiments | 48 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | -| 17 | globalinitscripts | 48 | Verb-as-noun requests; brittle `script_id` path-parameter handling; proto suffix | -| 18 | modelserving (was modelservingmanagement + modelservingdebug) | 47 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | -| 19 | queryhistory | 46 | Vague `Query` types; cross-package overlap with `queries` | -| 20 | clusterpolicies | 41 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | -| 21 | dataquality | 41 | `ListMonitorRequest` singular for list of monitors | -| 22 | policyfamilies | 41 | "Family" + "Policy Family" mixed; underscored enums | -| 23 | instancepools | 39 | Massive structural duplication of `Create*`/`Edit*`/`*AndStats`; proto-suffix (Theme 2 prefix pruned 2026-05-22) | -| 24 | accessmanagement (was permissions + workspaceassignment + accountaccesscontrol(+proxy)) | 38 | Permissions/grants/rule-sets fragmentation; absorbed account access control | -| 25 | knowledgeassistants | 37 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | -| 26 | supervisoragents | 37 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | -| 27 | commandexecution | 36 | Three resources (Command/Context/Cluster) mixed; `id?: string` underspecified | -| 28 | rfa | 36 | 3-letter cryptic package name | -| 29 | alerts | 35 | Mixed v1/v2 | -| 30 | credentials | 35 | UC vs auth duplicate; `Accounts*` family (the `Public*` infix has been removed in the 2026-05-22 regen) | -| 31 | externalmetadata | 35 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | -| 32 | lakeview | 35 | Old codename (rebrand to "AI/BI Dashboards") | -| 33 | usagepolicy | 35 | 1:1 clone of `budgetpolicy` | -| 34 | bundle | 34 | Generic package name (`bundle`); verb-as-noun requests | -| 35 | iam | 33 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | -| 36 | onlinetables | 33 | Underspecified IDs; deprecation drift | -| 37 | queries | 33 | Three-package overlap with `queryhistory`/`statementexecution` | -| 38 | customllms | 30 | `Llm` casing throughout (Theme 2 `CustomLlm*` prefix pruned 2026-05-22) | -| 39 | modelservingquery | 30 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | -| 40 | secrets | 30 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | -| 41 | connections | 29 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 42 | featurestore | 29 | Cross-package duplicates in feature trio | -| 43 | workspaceobjects (was workspace) | 29 | Filesystem scope clarified by rename; `fullNameArg` residue | -| 44 | budgetpolicy | 28 | Sibling clone in `usagepolicy` | -| 45 | cleanrooms (absorbed cleanroomassets + cleanroomautoapprovalrules + cleanroomtaskruns) | 28 | Post-consolidation `CleanRoom*` re-prefix friction (the bare-prefix instance was pruned; the post-merge consolidation symptom is retained) | -| 46 | clusterlibraries | 28 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 47 | environments | 28 | `Environment` generic name | -| 48 | logdelivery (was logdeliveryconfigurations) | 27 | Renamed; legacy long name fixed | -| 49 | repos | 27 | "Repos" legacy term; product is "Git folders" | -| 50 | tagassignments | 27 | Three-package tag split; sibling field-name drift | -| 51 | vectorsearch (was endpoints + indexes) | 27 | `Endpoint*` and `VectorIndex*` overlap; vector search renamed in place | -| 52 | abacpolicies | 26 | `PolicyInfo`; verb-as-noun requests | -| 53 | workspacebindings | 26 | Bare verb requests | -| 54 | budgets | 24 | Budget vs `budgetpolicy` duplication | -| 55 | entitytagassignments | 24 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 56 | files | 24 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | -| 57 | disasterrecovery | 23 | `FailoverFailoverGroupRequest` stutter | -| 58 | functions | 23 | `function` reserved-word; `fullNameArg`; cryptic single-letter enum variants | -| 59 | secretsuc | 23 | `uc` cryptic suffix; collides with `secrets` | -| 60 | externallineage | 22 | `Direction_LineageDirection`; `tpe` typo | -| 61 | tokens | 22 | Cross-package duplicate of `tokenmanagement` | -| 62 | gitcredentials | 21 | Three "Credentials" packages with different meanings | -| 63 | grants | 21 | Verb-phrase request types | -| 64 | billableusagedownload | 20 | Verb in package name (`download`) | -| 65 | notificationdestinations | 20 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 66 | tokenmanagement | 19 | Overlap with `tokens`; duplicate `AutoscopeState` enum | -| 67 | usagedashboards | 19 | Vague type names | -| 68 | resourcequotas | 18 | Vague type names | -| 69 | tagpolicies | 18 | Three sibling tag packages with overlapping vocab | -| 70 | volumes | 18 | `fullNameArg`; verb-as-noun requests | -| 71 | dataclassification | 17 | Tag-domain overlap | -| 72 | schemas | 17 | `_OptionsEntry`/`_PropertiesEntry`; `fullNameArg`; vs `systemschemas` package | -| 73 | artifactallowlists | 15 | Vague type names | -| 74 | metastores | 15 | Structural duplicate of `MetastoreInfo` — 20 `Accounts*MetastorePublic*` findings moved to Fixed in 2026-05-22 regen | -| 75 | registeredmodels | 15 | `fullNameArg`/`versionArg`/`aliasArg`; cross-package overlap with `modelregistry` | -| 76 | catalogs | 13 | `*_OptionsEntry`/`*_PropertiesEntry`; `nameArg`; Create-with-read-only-fields | -| 77 | externallocations | 13 | `nameArg` cryptic suffix; cross-cloud queue type naming inconsistency (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | -| 78 | scim | 13 | Account-tier SCIM 2.0 user/group provisioning; proto-architectural surface | -| 79 | systemschemas | 13 | Sibling-package collision with `schemas` | -| 80 | forecasting | 11 | Generic-named `Waiter` API; cross-package overlap with `experiments`; "Wrapper message" JSDoc | -| 81 | oauth (was oauthcustomappintegration + oauthpublishedapp) | 11 | OAuth Custom + Published app integrations consolidated; `OAuthAppIntegration*` retained per prune-pass 7 (post-merge consolidation friction) | -| 82 | sharing | 5 | Account-tier Delta Sharing provider config | -| 83 | workspaces | 5 | Singular/plural residue after 16 `*Public*Request` findings moved to Fixed | -| 84 | authentication | 4 | Account-tier token federation policies | -| 85 | networking | 4 | Singular/plural residue after 17 `*Public*Request` findings moved to Fixed; ~40 active `CustomerFacing*` identifiers not yet flagged | -| 86 | storageconfigurations | 4 | Sparse account-tier residue after `*Public*Request` findings moved to Fixed | -| 87 | keyconfigurations | 1 | Singular `ListCustomerManagedKeyRequest` residue after `*Public*Request` findings moved to Fixed | -| — | **Total** | **2,891** | Across all 87 active audits | - -### Retired audits (24 — excluded from the active total) - -These audit files exist as historical record. Their source packages were -removed or consolidated in the 2026-05-20 or 2026-05-22 regen; their -findings have been migrated to the successor packages where applicable. -The retired audits each carry a status banner at the top indicating the -consolidation date. - -| Retired audit | Successor (where applicable) | +| 1 | jobs | 97 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | +| 2 | warehouses | 75 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 3 | instancepools | 64 | Structural duplication of `Create*`/`Edit*`/`*AndStats` | +| 4 | catalogs | 41 | `*_OptionsEntry`/`*_PropertiesEntry`; Create-with-read-only-fields; cross-package SecurableType collisions | +| 5 | functions | 38 | `function` reserved-word; cryptic single-letter enum variants | +| 6 | statementexecution | 37 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | +| 7 | instanceprofiles | 37 | Bare verb request types; vague identifiers | +| 8 | pipelines | 36 | `Update` noun = pipeline run (DLT → Lakeflow rebrand) | +| 9 | features | 36 | Sibling-package fragmentation (now 2 after `materializedfeatures` retirement) | +| 10 | genie | 35 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 11 | settings | 34 | Post-consolidation v2 surface; acronym soup (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | +| 12 | schemas | 33 | `_OptionsEntry`/`_PropertiesEntry`; cross-package SecurableType collisions; vs `systemschemas` | +| 13 | marketplaces | 32 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | +| 14 | globalinitscripts | 31 | Verb-as-noun requests; proto suffix | +| 15 | modelregistry | 30 | Workspace vs UC duplicate (`registeredmodels`); MLflow vocabulary | +| 16 | apps | 30 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology; `*Proto` suffix | +| 17 | tables | 28 | `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 18 | postgres | 28 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | +| 19 | modelserving | 28 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | +| 20 | policyfamilies | 27 | "Family" + "Policy Family" mixed; underscored enums | +| 21 | metastores | 25 | Structural duplicate of `MetastoreInfo`; `UpdateMetastoreRequest` four name-like fields | +| 22 | experiments | 25 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 23 | accessmanagement | 25 | Permissions/grants/rule-sets fragmentation; absorbed account access control | +| 24 | clusterpolicies | 24 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | +| 25 | registeredmodels | 23 | Cross-package overlap with `modelregistry`; `Info`-suffix entities | +| 26 | credentials | 22 | UC vs auth duplicate; `Accounts*` family | +| 27 | queries | 20 | Three-package overlap with `queryhistory`/`statementexecution` | +| 28 | clusters | 20 | 150-member `TerminationCode` brand-value casing | +| 29 | database | 19 | Package name overlaps `postgres`; deep proto nesting | +| 30 | bundle | 18 | Generic package name (`bundle`) | +| 31 | alerts | 18 | Mixed v1/v2 | +| 32 | commandexecution | 17 | Three resources (Command/Context/Cluster) mixed; verb collision (`destroy`/`delete`) | +| 33 | usagepolicy | 16 | 1:1 clone of `budgetpolicy` | +| 34 | rfa | 16 | 3-letter cryptic package name | +| 35 | modelservingquery | 16 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 36 | forecasting | 16 | Generic-named `Waiter` API; cross-package overlap with `experiments` | +| 37 | budgets | 16 | Budget vs `budgetpolicy` duplication | +| 38 | repos | 15 | "Repos" legacy term; product is "Git folders" | +| 39 | featurestore | 15 | Cross-package duplicates with `onlinetables` (`DeleteOnlineTableRequest`) | +| 40 | dataquality | 15 | `ListMonitorRequest` singular for list of monitors | +| 41 | clusterlibraries | 15 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 42 | vectorsearch | 14 | `Endpoint*` and `VectorIndex*` overlap | +| 43 | lakeview | 14 | Old codename (rebrand to "AI/BI Dashboards") | +| 44 | iam | 14 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | +| 45 | connections | 14 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 46 | supervisoragents | 13 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 47 | secretsuc | 13 | `uc` cryptic suffix; collides with `secrets` | +| 48 | queryhistory | 13 | Vague `Query` types; cross-package overlap with `queries` | +| 49 | logdelivery | 13 | Renamed; legacy long name fixed | +| 50 | externalmetadata | 13 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | +| 51 | gitcredentials | 12 | Three "Credentials" packages with different meanings | +| 52 | files | 12 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | +| 53 | usagedashboards | 11 | Vague type names | +| 54 | tagpolicies | 11 | Three sibling tag packages with overlapping vocab | +| 55 | tagassignments | 11 | Three-package tag split | +| 56 | secrets | 11 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | +| 57 | knowledgeassistants | 11 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | +| 58 | workspaceobjects | 10 | Filesystem scope clarified by rename | +| 59 | tokens | 10 | Cross-package duplicate of `tokenmanagement` | +| 60 | scim | 10 | Account-tier SCIM 2.0 user/group provisioning | +| 61 | environments | 10 | `Environment` generic name | +| 62 | entitytagassignments | 10 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 63 | customllms | 10 | `Llm` cryptic-acronym usage throughout | +| 64 | grants | 9 | Verb-phrase request types | +| 65 | externallocations | 9 | Cross-cloud queue type naming (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | +| 66 | externallineage | 9 | `Direction_LineageDirection`; `tpe` typo | +| 67 | disasterrecovery | 9 | `FailoverFailoverGroupRequest` stutter | +| 68 | cleanrooms | 9 | `*Handler` suffix proto-leak; misleading `accessRestricted` enum | +| 69 | volumes | 8 | Verb-as-noun requests | +| 70 | tokenmanagement | 8 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 71 | systemschemas | 8 | Sibling-package collision with `schemas` | +| 72 | notificationdestinations | 8 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 73 | billableusagedownload | 8 | Verb in package name (`download`) | +| 74 | workspacebindings | 7 | Bare verb requests | +| 75 | budgetpolicy | 7 | Sibling clone in `usagepolicy` | +| 76 | abacpolicies | 7 | `PolicyInfo`; `MatchColumn` verb-as-noun | +| 77 | resourcequotas | 6 | Vague type names | +| 78 | artifactallowlists | 6 | Vague type names | +| 79 | sharing | 5 | Account-tier Delta Sharing provider config | +| 80 | workspaces | 4 | Residue after `*Public*Request` regen fixes | +| 81 | storageconfigurations | 4 | Sparse account-tier residue | +| 82 | networking | 4 | Residue; ~40 active `CustomerFacing*` identifiers not yet flagged | +| 83 | authentication | 4 | Account-tier token federation policies | +| 84 | oauth | 3 | OAuth Custom + Published app integrations consolidated | +| 85 | dataclassification | 2 | Tag-domain overlap | +| 86 | keyconfigurations | 1 | `ListCustomerManagedKeyRequest` singular residue | +| 87 | onlinetables | 0 | No active findings after the 2026-05-26 prune | +| — | **Total** | **1,598** | Across all 87 active audits | + +### Retired audits — historical reference + +The 24 audit files for packages retired in the 2026-05-20 or 2026-05-22 +regen were **deleted on 2026-05-26** (see Prune note 8, step 3). The +audit directory now contains exactly 87 per-package files plus this +summary. The table below is preserved as a historical reference of which +packages were retired and where their findings went. + +| Retired audit (file deleted) | Successor (where applicable) | |---|---| | `accountaccesscontrol` | merged into `accessmanagement` | | `accountaccesscontrolproxy` | removed (proxy package retired) | @@ -983,7 +975,7 @@ consolidation date. | `qualitymonitors` | deprecated; replaced by `dataquality` | | `queryexecution` | removed outright | | `serviceprincipalsecrets` | removed outright | -| `serviceprincipalsecretsproxy` | removed outright | +| `serviceprincipalsecretsproxy` | removed outright (deleted before 2026-05-26) | | `workspace` | renamed to `workspaceobjects` | | `workspaceassignment` | merged into `accessmanagement` | | `workspaceconf` | merged into `settings` | @@ -998,7 +990,9 @@ The previous §§8.1–8.6 recommendations have all been retired: - The enum-name-prefix recommendation (former §8.1) is withdrawn — see prune note 5 (TS member names mirror the wire identifier intentionally). - The `Info`/`Spec`/`Details` suffix recommendation (former §8.2) is an - API-team decision, not a generator template change. + API-team decision, not a generator template change. Field-side instances + are out of scope per the 2026-05-26 field-rename prune; type-side + instances remain cataloged in Theme 1 above. - The acronym-casing policy recommendation (former §8.3) is dropped at the generator level; the inconsistencies are still cataloged in §4 as an observational reference. @@ -1010,15 +1004,13 @@ The previous §§8.1–8.6 recommendations have all been retired: per prune-pass 7 (2026-05-22): the package-name prefix is now considered intentional. Neither a generator change nor an API-team rename is planned. -### 7.1 Surface deprecations as `@deprecated` JSDoc tags +### 7.1 Surface deprecations as `@deprecated` JSDoc tags (deferred) -Today the audits found dozens of fields whose JSDoc text says "deprecated" -in prose but does not carry the `@deprecated` tag, so IDEs do not strike -them through. Examples: `Environment.client`, `Run.numberInJob`, -`ServedModel.modelName`, `EndpointCoreConfig.servedModels`, every method -in `qualitymonitor`/`qualitymonitors` (both retired). A simple template -change — when the proto description starts with "Deprecated", emit -`@deprecated` — catches all of them. +Fields whose JSDoc text says "deprecated" in prose but does not carry the +`@deprecated` tag (so IDEs do not strike them through). This is a +doc-only template change; it is out of the current naming-audit corpus +per the 2026-05-26 doc-change prune ("those can be anytime"). Retained +here as a follow-up note rather than an open finding. --- @@ -1050,15 +1042,18 @@ packages (every package that has a paginating list endpoint). ### 8.2 Strip proto-architectural-tier markers from the public TS surface -**Rule:** When emitting a public TS identifier, strip any mid-position -or suffix token whose only purpose is to disambiguate proto/service -tiers on the server. The closed set is: `Public`, `Internal`, `Proto`, -`Service` (when mid-position and not the domain word), `Backend`, -`Manager`, `Handler`, `Impl`, `Rpc`, `Grpc`, `Wrapper`, -`CustomerFacing`, and mid-position version markers like `V2`/`V3`. -Also strip JSDoc banner comments that exist only for proto file -structure (`"Public RPC requests and responses"`, -`"Wrapper message ..."`, `"Public facing ..."` headers). +**Rule:** When emitting a public TS identifier on the exported surface, +strip any mid-position or suffix token whose only purpose is to +disambiguate proto/service tiers on the server. The closed set is: +`Public`, `Internal`, `Proto`, `Service` (when mid-position and not the +domain word), `Backend`, `Manager`, `Handler`, `Impl`, `Rpc`, `Grpc`, +`Wrapper`, `CustomerFacing`, and mid-position version markers like +`V2`/`V3`. + +JSDoc banner comments are out of scope per the 2026-05-26 doc-change +prune; SDK-internal identifiers (`utils.ts` schema helpers, etc.) are +out of scope per the 2026-05-26 SDK-internal prune. The rule covers +the public exported surface only. **Why it's generator-only:** The TS SDK exports exactly one tier (the public one); these qualifiers exist solely to navigate the @@ -1066,44 +1061,32 @@ proto definition and have no caller-side meaning. The same template emits them across every account-tier package, so a single template fix replaces hundreds of per-package findings. -**Status (2026-05-22):** The `*Public*Request` sub-pattern has shipped +**Status (2026-05-26):** The `*Public*Request` sub-pattern has shipped across every account-tier package via the 2026-05-22 generator regen. -~81 findings moved from active to `Fixed` in this pass: -- `metastores`: 20 fixed -- `networking`: 17 fixed -- `workspaces`: 16 fixed -- `credentials`: ~10 fixed -- `storageconfigurations`: ~10 fixed -- `cleanrooms`: 4 fixed -- `keyconfigurations`: 2 fixed -- `jobs`: 2 fixed (`TriggerState` related) - This is a retroactive validation of the rule. The rule remains open -because: +because the following public-surface instances survive: + - `CustomerFacing*` qualifier is **still emitted** in `networking` (40+ active identifiers in `model.ts`, e.g. `CustomerFacingIngressNetworkPolicy`, `CustomerFacingVpcEndpointUseCase`). Not yet flagged in the rescan — should land in a follow-up pass. -- `*Proto` suffix survives on a handful of types: `TriggerStateProto` - (`jobs`), `DatabricksServiceExceptionProto` (`apps`), - `DatabricksServiceExceptionWithDetailsProto` (`apps`). +- `*Proto` suffix survives on a handful of public types: + `TriggerStateProto` (`jobs`), `DatabricksServiceExceptionProto` + (`apps`), `DatabricksServiceExceptionWithDetailsProto` (`apps`). - `*Service*` mid-position infix in `statementexecution` (`ServiceErrorCode` / `ServiceError`). -- Mid-position `V` in `jobs` (`RunLifecycleStateV2`) and - `externalmetadata` (`unmarshalListExternalMetadataResponseV2Schema`). -- JSDoc banners ("Public RPC", "Wrapper message", "Public facing RPC - requests and responses *****") still emit verbatim in `forecasting` - and `pipelines`. +- `*Handler` suffix in `cleanrooms/client.ts` on + `listCleanRoomNotebookTaskRunsHandler` and its `*Iter` companion. +- Mid-position `V` in `jobs` (`RunLifecycleStateV2`). -**Approximate package count where it appeared before pruning:** ~25/87 -packages (the account-tier cluster of 11 plus a single-digit tail -across the rest of the SDK). +**Approximate package count where it appears today:** ~8/87 packages +on the exported surface. **Illustrative example (pre-regen):** `CreateNetworkConnectivityConfigPublicRequest` → `CreateNetworkConnectivityConfigRequest`. The 2026-05-22 regen shipped this rename; the remaining gap is the `CustomerFacing*` -qualifier and the `*Proto`/`*Service*`/`V` tails. +qualifier and the `*Proto`/`*Service*`/`*Handler`/`V` tails. --- @@ -1116,25 +1099,39 @@ enum prefix" (prune note 5), Category 11 "Empty / trivial wrapper types" note 4). A new category was added in the 2026-05-20 proto-architectural-leak scan (audit-pass note 7): "Proto-architectural leak" — mid-position proto/service-tier infixes; the 2026-05-22 regen moved most of its -`*Public*Request` cases to `Fixed`. The most-cited remaining categories -across all 87 active audits: - -| # | Category | Audits citing it | +`*Public*Request` cases to `Fixed`. + +The 2026-05-26 prune pass narrowed the rubric significantly: + +- **Category 15 "Generic field names losing meaning"** and **Category 19 + "Underspecified IDs"** are now out of scope — both boil down to field + renames (field-rename prune). +- **Category 14 "Go / Java-style names"** field-name instances (`req`, + `resp`, local var names) are out of scope — they are SDK-internal + identifiers (SDK-internal prune). +- **Category 16 "Field contradicting type domain"** is significantly + reduced — field-side instances are out (field-rename prune); only + type-name-vs-content contradictions remain (e.g. + `ServedModel.servedEntities`). +- JSDoc-only findings (banner comments, "deprecated in prose without + @deprecated tag") are out of scope across all categories + (doc-change prune). + +The most-cited remaining categories on the type-level surface across +all 87 active audits: + +| # | Category | Surviving on type level | |---|---|---| -| 1 | Vague / generic names | 87 | -| 6 | Misleading names | 87 | -| 3 | Acronym casing inconsistencies | 87 | -| 12 | Duplicate concepts | 85 | -| 15 | Generic field names losing meaning | 84 | -| 20 | Type-suffix tautology | 84 | -| 19 | Underspecified IDs | 83 | -| 17 | Inconsistent action verbs | 83 | -| 7 | Overly verbose names | 80 | -| 14 | Go / Java-style names | 79 | -| 5 | Cryptic abbreviations | 77 | -| 8 | Redundant suffix | 70 | -| 9 | Singular/plural mismatches | 70 | -| 16 | Field contradicting type domain | 69 | -| 18 | Long enum values | 66 | -| 13 | Verb-tense inconsistency | 60 | -| Proto | Proto-architectural leak (most `*Public*Request` cases shipped in 2026-05-22 regen) | ~10 | +| 1 | Vague / generic names (type level) | ~80 | +| 6 | Misleading names (type level) | ~75 | +| 12 | Duplicate concepts (cross-package, type-level) | ~70 | +| 20 | Type-suffix tautology | ~60 | +| 17 | Inconsistent action verbs (method names) | ~50 | +| 7 | Overly verbose type names | ~50 | +| 8 | Redundant suffix (`Info`, `Spec`, `Details`) | ~45 | +| 9 | Singular/plural mismatches (type level) | ~40 | +| 5 | Cryptic abbreviations (in type names) | ~35 | +| 3 | Acronym casing (type level, post-2026-05-21 acronym renames) | ~30 | +| 13 | Verb-tense inconsistency | ~25 | +| 18 | Long enum values | ~25 | +| Proto | Proto-architectural leak (`*Proto`/`*Handler`/`*Service*`/`*CustomerFacing*`) | ~8 | diff --git a/AGENTS.md b/AGENTS.md index a4bb6def..2216dbe2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -149,7 +149,7 @@ synthesis step that updates `_SUMMARY.md` or similar). ### Active TODOs -- 2026-05-26 — regenerate `_SUMMARY.md` to reflect all the 2026-05-26 pruning passes (rebase+rescan, AIP-name, sibling-enum, field-rename, doc-change, SDK-internal, non-TS) and the orphan deletions. — in progress. +_None._ (When populated, each line is one TODO in the form: `- YYYY-MM-DD — `.) From ab517f7fb6724cff20195be930780c72db1f0787 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 2 Jun 2026 16:44:44 +0000 Subject: [PATCH 11/12] update --- .agent/naming-audit/_SUMMARY.md | 817 +++++++++++------- .agent/naming-audit/abacpolicies.md | 61 +- .agent/naming-audit/accessmanagement.md | 352 +------- .agent/naming-audit/alerts.md | 227 +---- .agent/naming-audit/apps.md | 284 +----- .agent/naming-audit/artifactallowlists.md | 98 +-- .agent/naming-audit/authentication.md | 111 +-- .agent/naming-audit/billableusagedownload.md | 85 -- .agent/naming-audit/budgetpolicy.md | 69 +- .agent/naming-audit/budgets.md | 410 +-------- .agent/naming-audit/bundle.md | 223 ----- .agent/naming-audit/catalogs.md | 339 +------- .agent/naming-audit/cleanrooms.md | 120 +-- .agent/naming-audit/clusterlibraries.md | 196 +---- .agent/naming-audit/clusterpolicies.md | 269 +----- .agent/naming-audit/clusters.md | 179 +--- .agent/naming-audit/commandexecution.md | 180 +--- .agent/naming-audit/connections.md | 104 +-- .agent/naming-audit/credentials.md | 305 +------ .agent/naming-audit/customllms.md | 56 +- .agent/naming-audit/database.md | 125 +-- .agent/naming-audit/dataclassification.md | 49 -- .agent/naming-audit/dataquality.md | 89 +- .agent/naming-audit/disasterrecovery.md | 71 +- .agent/naming-audit/entitytagassignments.md | 72 +- .agent/naming-audit/environments.md | 84 +- .agent/naming-audit/experiments.md | 133 +-- .agent/naming-audit/externallineage.md | 83 +- .agent/naming-audit/externallocations.md | 198 +---- .agent/naming-audit/externalmetadata.md | 96 +- .agent/naming-audit/features.md | 333 ++----- .agent/naming-audit/featurestore.md | 226 +---- .agent/naming-audit/files.md | 146 +--- .agent/naming-audit/forecasting.md | 235 +---- .agent/naming-audit/functions.md | 382 ++------ .agent/naming-audit/genie.md | 159 +--- .agent/naming-audit/gitcredentials.md | 182 +--- .agent/naming-audit/globalinitscripts.md | 244 +----- .agent/naming-audit/grants.md | 79 +- .agent/naming-audit/iam.md | 272 ------ .agent/naming-audit/instancepools.md | 306 ++----- .agent/naming-audit/instanceprofiles.md | 216 +---- .agent/naming-audit/jobs.md | 455 +++------- .agent/naming-audit/keyconfigurations.md | 46 +- .agent/naming-audit/knowledgeassistants.md | 85 +- .agent/naming-audit/lakeview.md | 226 +---- .agent/naming-audit/logdelivery.md | 81 +- .agent/naming-audit/marketplaces.md | 450 ++-------- .agent/naming-audit/metastores.md | 289 +------ .agent/naming-audit/modelregistry.md | 287 ++---- .agent/naming-audit/modelserving.md | 201 +---- .agent/naming-audit/modelservingquery.md | 279 +----- .agent/naming-audit/networking.md | 36 +- .../naming-audit/notificationdestinations.md | 85 +- .agent/naming-audit/oauth.md | 204 ----- .agent/naming-audit/onlinetables.md | 124 --- .agent/naming-audit/pipelines.md | 198 ++--- .agent/naming-audit/policyfamilies.md | 221 +---- .agent/naming-audit/postgres.md | 179 +--- .agent/naming-audit/queries.md | 224 +---- .agent/naming-audit/queryhistory.md | 122 +-- .agent/naming-audit/registeredmodels.md | 267 +----- .agent/naming-audit/repos.md | 198 +---- .agent/naming-audit/resourcequotas.md | 136 +-- .agent/naming-audit/rfa.md | 112 +-- .agent/naming-audit/schemas.md | 309 +------ .agent/naming-audit/scim.md | 62 +- .agent/naming-audit/secrets.md | 201 +---- .agent/naming-audit/secretsuc.md | 90 +- .agent/naming-audit/settings.md | 278 ++---- .agent/naming-audit/sharing.md | 149 +--- .agent/naming-audit/statementexecution.md | 250 +----- .agent/naming-audit/storageconfigurations.md | 50 +- .agent/naming-audit/supervisoragents.md | 72 +- .agent/naming-audit/systemschemas.md | 62 +- .agent/naming-audit/tables.md | 630 ++------------ .agent/naming-audit/tagassignments.md | 74 +- .agent/naming-audit/tagpolicies.md | 77 +- .agent/naming-audit/tokenmanagement.md | 80 +- .agent/naming-audit/tokens.md | 86 +- .agent/naming-audit/usagedashboards.md | 78 +- .agent/naming-audit/usagepolicy.md | 127 --- .agent/naming-audit/vectorsearch.md | 96 +- .agent/naming-audit/volumes.md | 156 +--- .agent/naming-audit/warehouses.md | 663 ++++---------- .agent/naming-audit/workspacebindings.md | 59 +- .agent/naming-audit/workspaceobjects.md | 237 ----- .agent/naming-audit/workspaces.md | 132 +-- 88 files changed, 2386 insertions(+), 14402 deletions(-) delete mode 100644 .agent/naming-audit/billableusagedownload.md delete mode 100644 .agent/naming-audit/bundle.md delete mode 100644 .agent/naming-audit/dataclassification.md delete mode 100644 .agent/naming-audit/iam.md delete mode 100644 .agent/naming-audit/oauth.md delete mode 100644 .agent/naming-audit/onlinetables.md delete mode 100644 .agent/naming-audit/usagepolicy.md delete mode 100644 .agent/naming-audit/workspaceobjects.md diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index 6b8c2654..2d0b421d 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,9 +1,9 @@ # Cross-Package Naming Audit — Executive Summary -**Packages audited:** 87 active API packages (every package under `packages//src//`). The 24 orphan audit files that previously existed for packages retired in the 2026-05-22 regen were deleted on 2026-05-26 (see Prune note 8); per-package audits are now strictly limited to packages with live source. -**Total active findings across all 87 active audits:** **1,598** (down from 2,891 before the 2026-05-26 cleanup pass — a 45% reduction. Earlier waypoints: 2,926 before the 2026-05-22 Theme 2 prune; 3,572 before the 2026-05-22 regen + rescan; 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep.) The 2026-05-26 cleanup pass removed ~1,500 findings via five Workflow B prune passes (AIP `name`, sibling-state-enum, field-rename, doc-change, SDK-internal + non-TS), the deletion of 23 orphan audit files, and the removal of `## Fixed` sections from every audit (a small note in this summary now captures the historical "fixed" delta). +**Packages audited:** 79 active API packages (every package under `packages//src//`). The 2026-06-02 prune pass deleted one more audit file (`oauth` — its sole remaining finding was a wire-field rename, leaving zero findings; see Prune pass 12), down from 80. Per-package audits are strictly limited to packages with live source. +**Total active findings across all 79 active audits:** **712** (down from 791 reported before the 2026-06-02 category-prune pass. Earlier waypoints: 1,372 before the 2026-06-02 combined prune pass; 1,376 before the 2026-06-01 single-variant-union prune; 1,420 before the 2026-06-01 regen rescan; 1,598 before the 2026-05-28 rescan-and-prune pass; 2,891 before the 2026-05-26 cleanup pass; 2,926 before the 2026-05-22 Theme 2 prune; 3,572 before the 2026-05-22 regen + rescan; 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep.) The latest pass (Prune pass 13) applied three Workflow-B category prunes (field-ordering / grouping findings, data-type-retype findings, and empty / do-nothing wrapper-deletion findings). Net effect: 791 / 79 → 712 / 79. **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` -**Last source state:** Rebase onto main + rescan on 2026-05-26 against generator regen #156 + acronym renames (PR #148). Upstream API version `0555d6a59265799ed8ea12f355eee662e739430d`. +**Last source state:** Rescan on 2026-06-02 against the regenerated generated client (proto-nested `*Request_Response` collapsed to clean `*Response`, the `ApiError` swap, many `number` → `bigint` ID-precision conversions, and package-prefixed client class names; the `bundle`, `usagepolicy`, and `billableusagedownload` packages were removed). Prior baseline: rescan on 2026-06-01 against generator regen #167 ("Update SDK API…") + #168 ("Update SDK to latest State of Generator"). > **Prune note 1.** The original audit included a cross-cutting theme > "Empty / trivial wrapper interfaces" (empty `*_Response` interfaces, @@ -171,6 +171,202 @@ > the consolidated packages, cross-package duplicate concepts, and > proto-architectural leaks that survived the regen. +> **Prune pass 9 (2026-05-28) — rescan + two prunes + four deletions.** +> Combined removals ~180 findings (1,598 → 1,420). Components, in order: +> +> 1. **Full Workflow-A rescan.** Every source-backed audit was +> re-validated against the current generated source. Findings whose +> symbol is gone, was already renamed to the suggested name, or whose +> concern no longer applies were **deleted outright** (no `## Fixed` +> sections were created or kept). Many resolved findings were +> `number` → `bigint` ID-precision conversions that the generator now +> emits correctly. Line numbers were refreshed in place for findings +> that are still present. +> 2. **Prune A — generic top-level `Client` class name (DEFERRED).** The +> "the exported `Client` class is too generic / collides across every +> package / rename to `Client`" finding was removed from +> every package that carried it (~45 packages). The user is deferring +> this fix (verbatim: "i will fix this later") — it is most likely a +> single generator-level rename rather than per-package work. It is +> **not** lost: it is tracked in the "Deferred (user will fix later)" +> note below so the user can act on it in one place. Example: the +> now-deleted `dataclassification` package's `Client` would become +> `DataClassificationClient`. +> 3. **Prune B — acronym casing (category 3) RESOLVED.** Every +> acronym-casing finding (the "treat acronyms as whole words" rule: +> `Http`/`HTTP`, `Url`/`URL`, `Id`/`ID`, `Uc`/`UC`, `Api`/`API`, +> `Sql`/`SQL`, `PyPi`/`PyPI`, etc.) was removed from every package +> that carried it (~47 packages). The user has resolved acronym +> casing on the public interface (verbatim: "i have already resolved +> this from the public interface"), so this theme is closed/retired — +> see the "Resolved / retired themes" note below. +> 4. **Four audit files deleted.** Each was removed from the corpus: +> - `iam` — orphan; `packages/iam/` source no longer exists (its +> domain moved to `accessmanagement`). +> - `workspaceobjects` — orphan; the `/api/2.0/workspace/` filesystem +> service was dropped from the public-filtered descriptor. +> - `dataclassification` — emptied by the two prunes (its only two +> findings were a `Client`-class item and an acronym-casing item), +> then deleted as an empty audit. +> - `onlinetables` — already had zero findings, deleted as an empty +> audit. +> +> **Deferred → RESOLVED upstream (see Prune pass 10):** the generic +> top-level `Client` class-name rename was deferred here on 2026-05-28 +> (user: "i will fix this later"). It has since shipped at the generator +> level — the 2026-06-01 regen (#167/#168) emits package-prefixed client +> classes (`AccessManagementClient`, `FeaturesClient`, `CredentialsClient`, +> `JobsClient`, `WarehousesClient`, …) instead of a bare `Client`. The +> fix is no longer pending; it is recorded as resolved under Prune pass 10. +> +> **Resolved / retired themes:** acronym casing (former Theme 2 / §4 / +> Appendix category 3) is **resolved** — pruned from every package this +> pass after the user fixed acronym casing on the public interface. It is +> retained below only as a historical reference, marked resolved in place. + +> **Prune pass 10 (2026-06-01) — regen rescan + three orphan deletions.** +> Net removal 44 findings (1,420 → 1,376). Components, in order: +> +> 1. **Generator regen (#167/#168).** The generated client was regenerated +> upstream — commit #167 ("Update SDK API…") and commit #168 ("Update +> SDK to latest State of Generator"). A full Workflow-A rescan ran +> across every source-backed package. +> 2. **Full Workflow-A rescan.** Every finding was re-validated against the +> current generated source. Resolved findings were **deleted outright** +> (no `## Fixed` sections were created or kept), line numbers were +> refreshed in place, and a few findings were superseded-rewritten. +> Most packages had line-number corrections only. The rescan dropped +> **8 findings** inside surviving audits, all where the regen fixed the +> underlying issue: several `number` → `bigint` 64-bit ID-precision +> conversions (`jobs`, `metastores`, `registeredmodels`, and +> experiments-adjacent types), `getMetricHistory` → `listMetricHistory` +> (`experiments`), `get*` → `list*WorkspacePermissionAssignments` / +> `listAssignableRoles*` (`accessmanagement`), `getLatestVersions` → +> `listLatestVersions` (`modelregistry`, superseded-rewritten in place, +> no net change), and a stale `Call` import (`instancepools`). The +> per-package net deltas: `jobs` 83 → 79, `experiments` 24 → 23, +> `accessmanagement` 22 → 21, `instancepools` 61 → 60, +> `registeredmodels` 21 → 20. +> 3. **Three orphan audit files deleted** (source removed by the regen) — +> 36 findings excluded from the total: +> - `bundle` — `packages/bundle/` no longer exists. +> - `usagepolicy` — `packages/usagepolicy/` no longer exists. +> - `billableusagedownload` — `packages/billableusagedownload/` has no +> TypeScript source anymore. +> No surviving audit was emptied this pass, so no additional empty-file +> deletions were needed. +> 4. **Generic `Client` rename — RESOLVED upstream.** The generic +> top-level `Client` class-name rename that the 2026-05-28 pass pruned +> and **deferred** ("i will fix this later", likely generator-level) has +> now shipped: the regen emits package-prefixed client classes +> (`AccessManagementClient`, `FeaturesClient`, `CredentialsClient`, +> `JobsClient`, `WarehousesClient`, …) instead of a bare `Client`. The +> per-package audits already carry no such finding; the deferred note +> under Prune pass 9 is updated to mark the fix resolved at the +> generator level. + +> **Prune pass 11 (2026-06-01) — single-variant union flatten retired.** +> Workflow B prune. Pruned the single-variant discriminated-union flatten +> recommendation (flatten `{ $case: 'x'; ... } | undefined` to a bare +> field). Rejected by the user as not forward-compatible — re-introducing +> the union when a second variant is added is a breaking type change. +> Removed from 2 packages (`accessmanagement` `Actor.kind`, `volumes` +> `EncryptionDetails`). Both findings had been filed under the +> proto-architectural-leak / unnecessary-structure category. All other +> `$case`/`oneof` findings were kept: they are multi-variant unions, +> discriminator-name concerns, proto-leak `_Response`/`_Entry`/`_State` +> types, or recommendations to *introduce* a union — none matched the +> rejected "flatten single-variant union" class. No audit was emptied, so +> no files were deleted this pass. Net −2 findings (1,374 → 1,372); the +> headline figure moves from the previously reported 1,376 because +> re-summing the corpus also corrected a stale `featurestore` tally +> (13 in-file, 15 in the old summary). + +> **Prune pass 12 (2026-06-02) — regen rescan + six category prunes + +> scaffolding cleanup.** Combined removals 581 findings net (1,372 → 791). +> Components, in order: +> +> 1. **Workflow-A rescan after generator regen.** Every source-backed audit +> was re-validated against the regenerated client. The regen collapsed +> the proto-nested `*Request_Response` types into clean `*Response` +> types, swapped the error type to `ApiError`, converted many `number` +> fields to `bigint` for 64-bit ID precision, and emitted +> package-prefixed client class names. The packages `bundle`, +> `usagepolicy`, and `billableusagedownload` were removed (their audit +> files had already been deleted in Prune pass 10). +> 2. **Pruned the `ErrorCode`-centralization recommendation class.** Removed +> every finding recommending that a package stop shipping the large +> global `ErrorCode` enum locally / move it to a shared core +> `apierror/codes` package (candidates: `apps`, `credentials`, +> `environments`, `genie`, `postgres`, `statementexecution`). +> 3. **Pruned the generic-`Operation`-LRO-type recommendation class.** +> Removed every finding recommending that the top-level `Operation` +> long-running-operation type be renamed to `Operation` or moved +> to shared core, including the `GetOperationRequest` generic-name angle +> (candidates: `apps`, `environments`, `forecasting`, `postgres`). +> 4. **Pruned the boolean-shaped-two-value-enum recommendation class.** +> Removed every finding recommending that a two-value enum whose other +> value is an absence/`NO_*` sentinel be modeled as a `boolean` (e.g. +> `accessRestricted?: CleanRoom_AccessRestricted`). +> 5. **Pruned the duplicate-concept / naming-consistency recommendation +> class.** Removed every finding recommending that generated +> types/enums/fields modeling the same or a related concept be +> renamed, consolidated, or disambiguated (e.g. two `Status` enums, +> `creator` vs `collaborators`, `CleanRoomCollaborator` vs +> `CollaboratorJobRunInfo`). +> 6. **Stripped non-finding scaffolding sections.** Removed the +> `## Inventory`, `## File coverage`, `## Domain glossary`, +> `## Comparison` / cross-audit tables, priority-order lists, file +> indexes, and scope-note preambles from every audit, keeping only the +> metadata, the summary table, and the findings. +> 7. **Pruned documentation-only findings.** Removed every finding whose +> fix is JSDoc/comment content, a soft-deprecation note needing the +> `@deprecated` tag, or a doc-markup leak — anything that can be changed +> at any time without a backward-incompatible change (e.g. +> `agentArtifactPath` doc wording). +> 8. **Removed empty `_None._` section stubs throughout.** Where a prior +> prune had emptied a section, the leftover header + `_None._` line was +> deleted and any index/summary table that referenced it was reconciled. +> 9. **Pruned wire-identifier-rename findings.** Removed every finding whose +> core fix renames a JSON field/property name or an enum member value. +> KEPT type/interface/class renames, method-name fixes, and `string` → +> enum retyping. +> +> **Net effect: 1,372 / 80 → 791 / 79.** The `oauth.md` audit was deleted +> because its sole remaining finding was a wire-field rename, which the +> wire-identifier-rename prune removed, leaving the file with zero findings. + +> **Prune pass 13 (2026-06-02) — three category prunes.** Combined removals +> 79 findings net (791 → 712). Three Workflow-B category prunes were applied, +> in order: +> +> 1. **Pruned the field-ordering / grouping recommendation class** (category +> 17 "reorder fields so related fields sit adjacent"). Removed every +> finding whose only fix is cosmetic source-order — reordering fields in +> a type so related fields sit next to each other. Source-order has no +> effect on the public contract or the wire format. +> 2. **Pruned the data-type-retype recommendation class.** Removed every +> finding whose fix retypes a field's primitive type: a `string` that +> should be an enum/union, a `number` that should be a `Date` or +> `bigint`, or a `string` that should be a branded/opaque type. This +> **reverses the earlier keep-`string` → enum stance** recorded in +> Prune pass 12 (the wire-identifier-rename prune had explicitly KEPT +> `string` → enum retyping). KEPT all structural findings — optionality, +> cardinality, discriminated unions, and non-empty wrapper reshape — and +> all renames. +> 3. **Pruned the empty / do-nothing wrapper-deletion recommendation class.** +> Removed every finding recommending that an EMPTY interface or a +> proto-namespace-anchor wrapper be deleted. Empty messages are kept for +> forward-compatibility: adding a field later is a non-breaking change for +> a wrapper type but a breaking change if the response was previously +> `void`. Note: proto MAP-ENTRY types (`*_Entry` = `{ key, value }` for +> `map` fields) are KEPT — they are non-empty wrappers, not +> do-nothing anchors. The `catalogs` (6) and `features` (1) map-entry +> findings were briefly over-removed in this pass and then restored. +> +> **Net effect: 791 / 79 → 712 / 79.** No audit was emptied, so no files +> were deleted this pass; the package count holds at 79. + > **Rescan note (2026-05-20).** The generator was re-run and the > per-package audits were rescanned against the new source state. The > rescan dropped **710 findings net** and closed out several structural @@ -291,7 +487,7 @@ to deliver an idiomatic TypeScript SDK. The vast majority of the findings are template-driven — fix the template once and the symptoms disappear from every package. -The 87 active packages are a 1:1 port of `databricks/sdk-go`, so most defects +The 79 active packages are a 1:1 port of `databricks/sdk-go`, so most defects flow from Go/protobuf idioms that do not translate to TypeScript. Idiomatic TS SDKs (AWS, Azure, Stripe, Octokit) deliberately diverge from their wire formats; the Databricks JS SDK currently does not. @@ -301,9 +497,26 @@ formats; the Databricks JS SDK currently does not. ## 1. Top cross-cutting themes Ranked by approximate package incidence. Each theme is a generator-level -defect — one template change fixes ~87 packages. +defect — one template change fixes most of the 79 active packages. + +The table below tallies the theme tags carried by the 79 per-package audits, +counting the number of packages each tag appears in (a package is counted +once per tag regardless of how many findings carry it). The curated narrative +themes (Theme 1–4) follow. -### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~30/87 packages (shrunk by the 2026-05-26 field-rename prune) +| Theme | Packages | +|---|---| +| Type-shape / cardinality (unions, optionality, wrappers) | 48 | +| Method / operation naming | 47 | +| Vague / generic type name | 38 | +| Redundant `*Info`/`*Details`/`*Spec` type suffix | 36 | +| Misleading type name | 32 | +| Proto `Foo_Bar` type-name leak (incl. map-entry types) | 21 | +| Architectural leak (`Public`/`Proxy`/`Handler`) | 18 | +| `*Request`/`*Response` envelope rename | 18 | +| Package name | 11 | + +### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~30/79 packages (shrunk by the 2026-05-26 field-rename prune) The Go SDK uses `Info` to name "details of an X" because Go does not have package-qualified imports for types. TS does, and `` alone @@ -320,8 +533,7 @@ remain flagged at the type level: - `MetastoreInfo` → `Metastore`. - `CatalogInfo` → `Catalog`. - `RegisteredModelInfo`, `ModelVersionInfo`, `RegisteredModelAliasInfo`, - `TableInfo`, `FunctionInfo`, `ConnectionInfo`, `VolumeInfo`, - `OnlineTableInfo`. + `TableInfo`, `FunctionInfo`, `ConnectionInfo`, `VolumeInfo`. Same problem with other vague suffixes (type-side only after the prune): - `*Spec` / `*Details` / `*Config` / `*Status` / `*Data` / `*Metadata` used inconsistently — sometimes for the entity, sometimes for a sub-property, sometimes for both. `apps.ApplicationStatus` and `App.appStatus` (the field is no longer flagged but the type-name divergence remains). @@ -333,92 +545,30 @@ suffixes on tagged-union arms when the parent has a discriminator. Field renames are out of scope per user direction (would deviate the SDK from the underlying API). -### Theme 2. Inconsistent acronym casing across the SDK — 87/87 packages - -> **Status (2026-05-21):** Policy adopted (Google TS Style Guide: -> "treat acronyms as whole words"). The rule was already at -> `.agent/rules/typescript.mdc:184`. All hand-written-package renames -> listed in 2b have been applied. Theme 2a generated-code outliers -> remain — `OAuth*` is documented as a platform-name exception per -> RFC 6749 (kept). - -The SDK has no project-wide acronym-casing policy. The inconsistencies -appear on two distinct surfaces, each with a different cause and fix path. - -#### 2a. Generated code — 87/87 packages - -The generator already uses **`Pascal-then-lower`** very consistently for -TS identifiers (`Url`, `Id`, `Json`, `Sql`, `Http`, `Oauth`, `Aws`, -`Gcp`, `Llm`, `Dbfs`, `Iam`, `Sse`, `Pii`, `Aibi`, `Dbr`, `Uri`). A scan -of all generated packages found: - -| Acronym | TS identifiers (Pascal-then-lower) | `ALL_CAPS` form — where it appears | -|---|---|---| -| URL | `Url` — 445 hits / 63 pkgs | `URLSearchParams` (JS built-in, every `client.ts`); `'URL'` enum value in `rfa` | -| ID | `Id` — 3303 hits / 71 pkgs | `'ID'` enum value in ~10 pkgs (e.g. `IpAccessListType.ID`, `GenieAttachment.ID`); `ACCOUNT_ID` (`SCREAMING_SNAKE` constant — different style class) | -| JSON | `Json` — 208 hits / 65 pkgs | `JSON.parse`/`JSON.stringify` (JS built-in, every `utils.ts`); occasional `'JSON'` enum value | -| SQL | `Sql` — 132 hits / 7 pkgs | `'SQL'` enum values; `DATABRICKS_SQL_ACCESS` (`SCREAMING_SNAKE` constant) | -| HTTP | `Http` — 2156 hits / 65 pkgs | `'HTTP request'` log strings in `utils.ts`; `HTTPS URL` in JSDoc | -| OAuth | `Oauth` — 29 hits in `oauth` pkg | **`OAuthAppIntegration`/`CustomOAuthAppIntegration` identifiers also in `oauth` pkg** — real mixed-form inconsistency in the same package | -| AWS | `Aws` — 120 hits / 7 pkgs | `AWS_SSE_S3` and friends (`SCREAMING_SNAKE` enum values) | -| GCP | `Gcp` — 198 hits / 7 pkgs | `'GCP'` JSDoc / enum string | -| IAM | (no `Iam*` TS identifiers — only `Iam`-prefixed model types in 2 pkgs) | `IAM role`, `IAM` in JSDoc comments in 4 pkgs — comment text only, not identifiers | -| URI | `Uri` — 27 hits / 6 pkgs | `URI` in JSDoc comments in 4 pkgs — comment text only | -| LLM | `Llm` — 147 hits / 4 pkgs | `LLM` in JSDoc / occasional enum string | -| DBFS | `Dbfs` — 76 hits / 3 pkgs | `DBFS` in JSDoc comments | -| ETag | `etag` field name | RFC 7232 §2.3 says `ETag` — minor canonical-form mismatch | -| RPC | `Rpc` — 5 hits / 3 pkgs | `RPC` in JSDoc comments — comment text only | - -**The apparent `ALL_CAPS` leaks in identifiers across the generated -packages are almost entirely:** - -- **JS built-ins** (`URLSearchParams`, `JSON.parse`/`JSON.stringify`, - `encodeURIComponent`) — part of the JavaScript standard library; the - SDK cannot rename them. -- **JSDoc comment text** copied from upstream proto comments (`IAM role`, - `S3 URI`, `HTTPS URL`, `OAuth scopes`, `DBFS`) — not identifiers. -- **Wire-format enum string values** (`'URL' = 'URL'`, `'SQL' = 'SQL'`, - `'ID' = 'ID'`) — preserved as-is from the upstream proto; the JSON - wire shape requires the literal uppercase strings. -- **`SCREAMING_SNAKE_CASE` constants** (`AWS_SSE_S3`, - `DATABRICKS_SQL_ACCESS`) — a different style class (SCREAMING_SNAKE - constants), not "ALL_CAPS acronym" leaks. - -**The one real generated-code identifier inconsistency** is `OAuth` -vs `Oauth` mixed within the `oauth` package itself -(`OAuthAppIntegration`, `CustomOAuthAppIntegration` vs `Oauth` field -positions). - -**Generator fix:** Adopt one policy in `typescript.mdc` and converge the -small number of `OAuth*` identifiers. The two consistent options: -1. **Google TS style guide (`Pascal-then-lower`):** `Url`, `Id`, `Sql`, `Json`, `Oauth`. Pro: matches what the generator already emits for ~99% of identifiers; lowest-churn path. Con: `Oauth` deviates slightly from the brand spelling `OAuth`. -2. **.NET / Microsoft (`ALL_CAPS` for ≤2-letter, `Pascal-then-lower` for ≥3):** `URL`, `ID`, `Sql`, `Json`, `OAuth`. Pro: matches HTTP/RFC casing and the brand. Con: requires renaming ~3300 `*Id` identifiers and ~445 `*Url` identifiers across the whole corpus — major generator+spec change. - -#### 2b. Hand-written code — 5/5 packages (`auth`, `core`, `databricks`, `sdk`, `options`) - -**Status: Fixed (2026-05-21).** The renames listed below were applied. -The historical table and prose are retained as a record of the BEFORE -state. - -The hand-written packages mixed the two styles within the same file. -The real inconsistencies (excluding JS built-ins and `SCREAMING_SNAKE` -constants) were: - -- **`core/apierror/`** mixed `HttpClient`/`HttpRequest`/`HttpResponse` (Pascal) with `HTTPBody`/`HTTPHeader`/`HTTPStatusCode` (ALL_CAPS) within the same module. -- **`auth/credentials/`** used `IDToken`/`IDTokenProvider` (ALL_CAPS) alongside `clientId`/`fetchCliToken` (Pascal) for short acronyms. -- **`core/apierror/APIError`** used ALL_CAPS for `API` while the rest of the codebase used Pascal-then-lower. - -> **Resolved:** all real identifier renames listed above were applied -> (105 files: 11 hand-written + 94 generated `utils.ts`). -> `APIError` → `ApiError` rename touched 105 files. -> `IDToken`/`IDTokenProvider` → `IdToken`/`IdTokenProvider`. -> `HTTPStatusCode`/`HTTPHeader`/`HTTPBody` → `httpStatusCode`/`httpHeader`/`httpBody`. -> `OAuthAuthorizationServer`, `OIDC*` and JS built-ins -> (`URLSearchParams`, `JSON.parse`, `encodeURIComponent`) kept under -> the platform-name exception. `SCREAMING_SNAKE_CASE` constants -> unaffected. - -### Theme 3. Brand drift / rebrand leakage — ~6/87 packages (stable across the 2026-05-26 prune) +### Theme 2. Inconsistent acronym casing across the SDK — RETIRED (RESOLVED 2026-05-28) + +> **Status (2026-05-28): RESOLVED — theme retired.** The user has +> resolved acronym casing on the public interface (verbatim: "i have +> already resolved this from the public interface"). Every +> acronym-casing finding (the "treat acronyms as whole words" rule: +> `Http`/`HTTP`, `Url`/`URL`, `Id`/`ID`, `Uc`/`UC`, `Api`/`API`, +> `Sql`/`SQL`, `PyPi`/`PyPI`, etc.) was pruned from every per-package +> audit in the 2026-05-28 Prune B pass (~47 packages). This theme is no +> longer an active cross-cutting concern; it is retained here only as a +> historical pointer. +> +> Earlier history: the Google TS Style Guide rule +> (`.agent/rules/typescript.mdc:184`) was adopted on 2026-05-21, the +> hand-written-package renames (105 files: `APIError` → `ApiError`, +> `IDToken` → `IdToken`, `HTTPStatusCode`/`HTTPHeader`/`HTTPBody` → +> `httpStatusCode`/`httpHeader`/`httpBody`, etc.) were applied then, and +> `OAuth*`/`OIDC*` plus JS built-ins (`URLSearchParams`, `JSON.parse`, +> `encodeURIComponent`) were kept under the platform-name exception. The +> 2026-05-28 pass closed out the remaining generated-code surface. The +> observational casing inventory that used to live here is preserved in +> §4 below, marked resolved in place. + +### Theme 3. Brand drift / rebrand leakage — ~6/79 packages (stable across the 2026-05-26 prune) Several products were rebranded but the TS surface still carries the old codename: @@ -433,7 +583,7 @@ codename: **Generator fix:** Per-product spec needs updates; the rename can land via a generator alias map (`Endpoint` → `Warehouse` in `warehouses` only, etc.). -### Theme 4. Proto-architectural-leak infixes — ~8/87 packages (further shrunk by the 2026-05-26 doc + SDK-internal prunes) +### Theme 4. Proto-architectural-leak infixes — ~8/79 packages (further shrunk by the 2026-05-26 doc + SDK-internal prunes; single-variant `oneof`-wrapper sub-case pruned 2026-06-01) Internal proto / service-tier identifiers leak through the codegen and show up as mid-position infix tokens that have no meaning to a TS SDK consumer. @@ -461,6 +611,18 @@ SDK-internal prune). What remains is the type-name surface only. - **JSDoc banners pruned.** "Public RPC", "Wrapper message", and "Public facing RPC requests and responses *****" comments no longer flagged (doc-change prune, 2026-05-26). +- **Single-variant `oneof`-wrapper sub-case pruned (2026-06-01).** A + structural proto-leak variant — a `oneof` rendered as a single-variant + discriminated union (`{ $case: 'x'; ... } | undefined`) or a one-field + wrapper message kept only to carry that union — was previously flagged + with a recommendation to flatten it to a bare field. The user rejected + flattening as not forward-compatible (re-introducing the union when a + second variant is added is a breaking type change), so the two findings + (`accessmanagement` `Actor.kind`, `volumes` `EncryptionDetails`) were + removed in Prune pass 11. This sub-case never contributed to the ~8/80 + infix-token incidence above — it is structural, not one of the + `*Proto`/`*Service*`/`*Handler`/`*CustomerFacing*`/`V` tokens — so the + package count is unchanged; only the global finding total drops by 2. **Generator fix:** Strip proto-architectural-tier markers from the public TS surface emit. The set is small and closed: `Public`, `Internal`, @@ -487,7 +649,7 @@ into: | `settings` (v2) | Generic polymorphic value | Account- and workspace-scoped settings under the unified v2 surface | | Retired | — | `accountsettings`, `workspacesettings`, `workspaceconf` were retired in the regen; their findings are in the orphan audits | -`settings/v2/model.ts` now carries 84 active findings — the cross-package +`settings/v2/model.ts` now carries 30 active findings — the cross-package duplicates (`BooleanMessage`, `StringMessage`, `RestrictWorkspaceAdminsMessage`, `PersonalComputeMessage`) are now collapsed into a single surface but the type-naming friction remains. @@ -517,15 +679,16 @@ no longer exists. The bare type name `Credential` exists in two of these and `Credentials` exists in the third. -### 2.4 Identity / IAM (shrunk further by the 2026-05-22 regen) +### 2.4 Identity / IAM (consolidated; `iam` audit deleted 2026-05-28) -- `iam` still exposes `*` + `*Proxy` versions of every method (e.g. - `createGroup` + `createGroupProxy`, etc.) — 17 endpoint pairs. -- `accessmanagement` (NEW in the 2026-05-22 regen) is the consolidated - umbrella for what used to be `permissions`, `accountaccesscontrol`, - `accountaccesscontrolproxy`, and `workspaceassignment`. Covers object - permissions, permission levels, rule sets, and workspace assignments - in a single import path. +- The `iam` package source no longer exists; its domain moved to + `accessmanagement`, so the `iam` audit file was deleted on 2026-05-28. + (The former `iam` pain points — `*` + `*Proxy` method pairs, the + generic top-level `State`/`Entitlement` enums — are no longer tracked.) +- `accessmanagement` is the consolidated umbrella for what used to be + `permissions`, `accountaccesscontrol`, `accountaccesscontrolproxy`, and + `workspaceassignment`. Covers object permissions, permission levels, + rule sets, and workspace assignments in a single import path. ### 2.5 Tokens @@ -550,12 +713,6 @@ Three packages, three `Client` classes, three near-identical `entityId: string`, the UC variant has `entityName: string` — same logical field, different name, both string. -### 2.7 Quality / Data monitoring (consolidated to one) - -The 2026-05-22 regen retired `qualitymonitor` and `qualitymonitors` (both -deprecated). The only active surface is `dataquality`. Two former orphans -no longer contribute to the active total. - ### 2.8 Model Registry | Package | What it really is | @@ -566,20 +723,6 @@ no longer contribute to the active total. The legacy package has the canonical-sounding name; the UC replacement is hidden behind a plural noun. -### 2.9 Model Serving (consolidated) - -The three-way fragmentation -(`modelservingmanagement` + `modelservingquery` + `modelservingdebug`) -collapsed to two packages in the 2026-05-22 regen: - -| Package | What it really is | -|---|---| -| `modelserving` | CRUD over serving endpoints (was `modelservingmanagement`); absorbed the former `modelservingdebug` | -| `modelservingquery` | Inference / `POST /invocations` | - -The type-naming friction remains: `InferenceEndpoint` (in `modelserving`) -vs `Endpoint` (in `modelservingquery`) vs the URL `serving-endpoints`. - ### 2.10 Cluster compute (overlapping warehouses) - `warehouses` exposes SQL Warehouses (formerly "SQL Endpoints"); the @@ -611,32 +754,36 @@ The third sibling (`materializedfeatures`) was retired in the 2026-05-22 regen; its surface is folded into `features` (`MaterializedFeature` types already live there). -### 2.13 Budget / Usage policy +### 2.13 Budget policy (was a Budget / Usage-policy 2-way overlap) | Package | What it really is | |---|---| | `budgetpolicy` | `/api/2.0/accounts/{accountId}/budget-policies` | -| `usagepolicy` | `/api/2.1/accounts/{accountId}/usage-policies` | -`usagepolicy/v1/model.ts` is `budgetpolicy/v1/model.ts` with the word -"Budget" substituted for "Usage". The JSDoc on `UsagePolicy.policyId` even -admits it: "(same structure as BudgetPolicy)". Reserved tag keys still say -`"budget-policy-name"` in the usage-policy clone. +The 2026-06-01 regen (#167/#168) removed the `usagepolicy` package source, +so its audit was deleted as an orphan (Prune pass 10) and the overlap is +gone. For the record, `usagepolicy/v1/model.ts` had been a 1:1 clone of +`budgetpolicy/v1/model.ts` with the word "Budget" substituted for "Usage" — +the JSDoc on `UsagePolicy.policyId` even admitted it ("same structure as +BudgetPolicy"). The remaining `budgetpolicy` package stands alone. -### 2.14 Workspace (2-package fanout, was 5) +### 2.14 Workspace (now a single package, was 5) The 2026-05-22 regen retired three of the previous five (`workspace` → `workspaceobjects` rename, `workspaceassignment` → `accessmanagement`, and both `workspaceconf` and `workspacesettings` -retired). The remaining set: +retired). The 2026-05-28 pass then deleted the `workspaceobjects` audit +as an orphan: the `/api/2.0/workspace/` filesystem service was dropped +from the public-filtered descriptor, so that source no longer exists. The +remaining audited package in this space is: | Package | What it really is | |---|---| -| `workspaceobjects` | Workspace filesystem (notebooks/folders/files) | | `workspacebindings` | Securable-to-workspace bindings | -The bare name `workspace` was the most-overloaded; renaming to -`workspaceobjects` resolves the principal-vs-filesystem confusion. +The bare name `workspace` was the most-overloaded; the workspace +filesystem surface (notebooks/folders/files) is no longer part of the +public-filtered SDK. ### 2.15 Schemas (UC overlap) @@ -695,9 +842,6 @@ are not yet flagged but match generator rule §8.2. ### 2.19 Other notable overlaps -- `lakeview` (the rebranded "AI/BI Dashboards" — name uses old codename). -- `cleanrooms` absorbed `cleanroomassets` + `cleanroomautoapprovalrules` + - `cleanroomtaskruns`; the four-package fanout is now a single package. - `supervisoragents` + `knowledgeassistants` + `customllms` — three packages in the LLM-orchestration space with bare-generic top-level type names (`SupervisorAgent`, `KnowledgeAssistant`, `CustomLlm`). @@ -725,12 +869,12 @@ expansion in code or JSDoc. A first-time user has to guess. | `llm` | Large Language Model | `CustomLlm`, `LlmProxyPartnerPoweredAccount`, `Llm*` family | `Llm` casing is uniform across SDK. | | `sdp` | Serverless Declarative Pipelines | Comments | Internal acronym. | | `ldp` | Lakeflow Declarative Pipelines | Comments | Internal acronym. | -| `dab` | Databricks Asset Bundles | `bundle` package only | Spelled out in package. | +| `dab` | Databricks Asset Bundles | formerly the `bundle` package (removed by the 2026-06-01 regen) | Was spelled out in the package name. | | `m2m` | Machine-to-Machine | `auth/credentials/m2m.ts` | OAuth grant type. | | `u2m` | User-to-Machine | `auth/credentials/u2m.ts` | OAuth grant type. | | `pat` | Personal Access Token | `auth/credentials/pat.ts`, `tokens` package | OAuth-adjacent. | | `abac` | Attribute-Based Access Control | Package name `abacpolicies` only | Never appears in code or types. | -| `iam` | Identity and Access Management | Package name | Conventional. | +| `iam` | Identity and Access Management | Former package name (audit deleted 2026-05-28); still appears in JSDoc/identifiers elsewhere | Conventional. | | `wkt` | Well-Known Types | `@databricks/sdk-core/wkt` import | Proto term, not exposed to users. | | `aibi` | AI/BI Dashboards | `AibiDashboard*` family | Internal codename for the "AI/BI" product brand. | | `byok` | Bring Your Own Key | `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` | Not expanded. | @@ -748,9 +892,16 @@ expansion in code or JSDoc. A first-time user has to guess. --- -## 4. Acronym-casing inconsistencies +## 4. Acronym-casing inconsistencies — RESOLVED (2026-05-28) -The SDK currently has no enforced casing policy. The same acronym appears in +> **Resolved / retired.** The user has fixed acronym casing on the public +> interface (verbatim: "i have already resolved this from the public +> interface"). The corresponding per-package findings (category 3) were +> pruned everywhere in the 2026-05-28 Prune B pass. The table below is +> retained as a historical inventory of the BEFORE state only; it is no +> longer an active set of findings. + +The SDK previously had no enforced casing policy. The same acronym appeared in multiple casings across packages — sometimes within the same file. | Acronym | Found casings | Sample sites | @@ -782,23 +933,27 @@ multiple casings across packages — sometimes within the same file. | **TLS** | `Tls`, `TLS` | Rare; `Tls` in field names. | | **OAuth2** | varied | `oauth2` (path), `OAuth` (types). | -**Recommendation:** Pick one rule. The Google TypeScript Style Guide -specifies `Pascal-then-lower` (`Url`, `Id`, `Json`, `Sql`) — this is the -current majority in the SDK. The hand-written packages were converged on -this rule on 2026-05-21. Document the choice in -`.agent/rules/typescript.mdc` § 3 and enforce in CI. Wire format unchanged. +**Outcome (resolved).** The chosen rule is the Google TypeScript Style +Guide `Pascal-then-lower` form (`Url`, `Id`, `Json`, `Sql`), already +documented at `.agent/rules/typescript.mdc`. The hand-written packages +were converged on 2026-05-21 and the user has since resolved the +remaining public-interface casing; the per-package acronym-casing +findings were pruned on 2026-05-28. Wire format unchanged. --- ## 5. Top highest-impact surviving findings -Picked from the post-2026-05-26-prune corpus. Entries that depended on -field-rename, doc-change, SDK-internal, or non-TS findings (now all -out-of-scope) have been removed. The retained entries are -structural type-level issues — type names, reserved-word collisions, -brand drift, cross-package duplicate concepts, and the surviving -proto-architectural leaks. Each entry: file + symbol + the generator -pattern it exemplifies. +Picked from the post-2026-06-01-rescan corpus. Entries that depended on +field-rename, doc-change, SDK-internal, non-TS, generic-`Client`-class, +or acronym-casing findings (all now out-of-scope or resolved) have been +removed. The generic-`Client`-class issue is now resolved upstream (the +regen emits `Client` names), and the `bundle` and `usagepolicy` +entries are dropped because the 2026-06-01 regen removed those packages. +The retained entries are structural type-level issues — type names, +reserved-word collisions, brand drift, cross-package duplicate concepts, +and the surviving proto-architectural leaks. Each entry: file + symbol + +the generator pattern it exemplifies. | # | Package | File:Line | Symbol / Issue | Pattern | |---|---|---|---|---| @@ -807,150 +962,166 @@ pattern it exemplifies. | 3 | `jobs` | `model.ts` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | | 4 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | | 5 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | -| 6 | `iam` | `client.ts:309-2150` | Every method exists as `*` + `*Proxy` pair (17 endpoint duplicates). | Proxy routing in method names | -| 7 | `iam` | `model.ts:41-48` | `State` (top-level enum) — collides with React `setState`/state-machine libraries. | Generic top-level enum | -| 8 | `iam` | `model.ts:13-21` | `Entitlement` — vague enum mixing presence and permission semantics. | Vague enum | -| 9 | `abacpolicies` | `model.ts:137` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | -| 10 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | -| 11 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | -| 12 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission` — `App` token thrice on the type path. | Redundant prefix | -| 13 | `apps` | `model.ts` | `DatabricksServiceExceptionProto`, `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix. | Proto-architectural leak (`Proto` suffix) | -| 14 | `genie` | `client.ts:131, 1019, 1038` | 28 of 30 methods prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | -| 15 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | -| 16 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | -| 17 | `commandexecution` | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` — too short to convey what they wait for. | Waiter-class genericity | -| 18 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | -| 19 | `dataquality` | model.ts | `ListMonitorRequest` singular for a list-of-monitors request. | Singular/plural mismatch | -| 20 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | -| 21 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | -| 22 | `oauth` | `model.ts:passim` | After the merge, `OAuthAppIntegration*` vs `CustomOAuthAppIntegration*` consolidation friction. | Post-merge consolidation friction | -| 23 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, type-name overlap with `iam` and `grants` is still present. | Cross-package fragmentation | -| 24 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | -| 25 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource; both export `Client`. | Cross-package collisions | -| 26 | `usagepolicy` | model.ts | 1:1 clone of `budgetpolicy` with `Budget` → `Usage`. | Whole-package duplicate | -| 27 | `customllms` | every file | `CustomLlm` — generic name with cryptic-acronym body. | Generic naming + cryptic abbreviation | -| 28 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | -| 29 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds. | Stringly-typed sum | -| 30 | `cleanrooms` | `client.ts:662, 704` | `listCleanRoomNotebookTaskRunsHandler` / `listCleanRoomNotebookTaskRunsHandlerIter` — `Handler` suffix proto-leak. | Proto-architectural leak (`Handler` suffix) | -| 31 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | -| 32 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types. | Generic naming | -| 33 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | -| 34 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | -| 35 | `notificationdestinations` | `model.ts:17, 13` | `Config` top-level interface; `DestinationType` vague enum. | Generic top-level name | -| 36 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | -| 37 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | -| 38 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum with 22 values mixing case styles (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Brand-value casing | -| 39 | `clusters` | `model.ts:175-734` | `TerminationCode` enum with 150+ values mixing case styles. | Brand-value casing | -| 40 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | -| 41 | `bundle` | package + types | Bare "bundle" word collides with Webpack/Vite/Rollup. | Generic package name | -| 42 | `instancepools` | `model.ts:passim` | Structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | -| 43 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection` stutter. | Generator stutter | -| 44 | `settings` | `model.ts:passim` | Post-consolidation v2 surface carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrappers. | Generic + cryptic | -| 45 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun. | Proto-architectural leak (`Service` infix) | -| 46 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | -| 47 | `marketplaces` | `model.ts:passim` | `Exchange` vs `Listing` vocabulary tension within a single package. | Vocabulary drift | -| 48 | `forecasting` | `client.ts` | `CreateForecastingExperimentWaiter` + Go-style `Waiter.done()` predicate. | Go-style waiter pattern | +| 6 | `abacpolicies` | `model.ts:137` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | +| 7 | `tables` | `model.ts:849` | `TableSummary` vs `TableInfo` — two near-identical shapes. | Duplicate concept | +| 8 | `apps` | `model.ts:693, 1054` | `ApplicationStatus` on `App` — two vocabularies for one product. | Vocabulary drift | +| 9 | `apps` | `model.ts:606, 962` | `AppResourceApp.AppPermission` — `App` token thrice on the type path. | Redundant prefix | +| 10 | `apps` | `model.ts` | `DatabricksServiceExceptionProto`, `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix. | Proto-architectural leak (`Proto` suffix) | +| 11 | `genie` | `client.ts:131, 1019, 1038` | 28 of 30 methods prefixed `genie*`, 2 not; one `Trash*` instead of `Delete*`. | Inconsistent action verbs | +| 12 | `commandexecution` | model.ts vs client.ts | `CreateResponse` reused for both `create()` (context id) and `execute()` (command queued). | Type repurposing | +| 13 | `commandexecution` | `client.ts:256` | `client.destroy()` — verb collision; Go SDK uses `delete`. | Verb inconsistency | +| 14 | `commandexecution` | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` — too short to convey what they wait for. | Waiter-class genericity | +| 15 | `secrets` | `client.ts:passim` | `Put` for ACLs/secrets, `Create` for scopes, `Delete` for both — inconsistent mutation verbs. | Inconsistent action verbs | +| 16 | `dataquality` | model.ts | `ListMonitorRequest` singular for a list-of-monitors request. | Singular/plural mismatch | +| 17 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | +| 18 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | +| 19 | — | — | _Removed 2026-06-02: the `oauth` audit was deleted (its sole remaining finding was a wire-field rename, pruned in Prune pass 12)._ | Post-merge consolidation friction (retired) | +| 20 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, type-name overlap with `grants` is still present. | Cross-package fragmentation | +| 21 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 22 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource, with duplicated request/enum shapes. (The shared bare-`Client` export was resolved upstream — the regen now emits `TokensClient` / `TokenManagementClient`.) | Cross-package collisions | +| 23 | — | — | _Removed 2026-06-01: the `usagepolicy` 1:1 clone of `budgetpolicy` is gone — the regen removed the `usagepolicy` package source._ | Whole-package duplicate (retired) | +| 24 | `customllms` | every file | `CustomLlm` — generic name with cryptic-acronym body. | Generic naming + cryptic abbreviation | +| 25 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 26 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds. | Stringly-typed sum | +| 27 | `cleanrooms` | `client.ts:662, 704` | `listCleanRoomNotebookTaskRunsHandler` / `listCleanRoomNotebookTaskRunsHandlerIter` — `Handler` suffix proto-leak. | Proto-architectural leak (`Handler` suffix) | +| 28 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | +| 29 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types. | Generic naming | +| 30 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | +| 31 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 32 | `notificationdestinations` | `model.ts:17, 13` | `Config` top-level interface; `DestinationType` vague enum. | Generic top-level name | +| 33 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 34 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | +| 35 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum with 22 values mixing case styles (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Brand-value casing | +| 36 | `clusters` | `model.ts:175-734` | `TerminationCode` enum with 150+ values mixing case styles. | Brand-value casing | +| 37 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | +| 38 | — | — | _Removed 2026-06-01: the bare-`bundle` package-name collision is gone — the regen removed the `bundle` package source._ | Generic package name (retired) | +| 39 | `instancepools` | `model.ts:passim` | Structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | +| 40 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection` stutter. | Generator stutter | +| 41 | `settings` | `model.ts:passim` | Post-consolidation v2 surface carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrappers. | Generic + cryptic | +| 42 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun. | Proto-architectural leak (`Service` infix) | +| 43 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | +| 44 | `marketplaces` | `model.ts:passim` | `Exchange` vs `Listing` vocabulary tension within a single package. | Vocabulary drift | +| 45 | `forecasting` | `client.ts` | `CreateForecastingExperimentWaiter` + Go-style `Waiter.done()` predicate. | Go-style waiter pattern | --- -## 6. By-the-numbers (all 87 active packages, sorted by total findings) +## 6. By-the-numbers (all 79 active packages, sorted by total findings) + +Counts reflect each per-package audit's current declared total (or, for +the audits that use category-numbered sections instead of an H/M/L/Obs +table, that file's own consistent finding count) after the 2026-06-02 +category-prune pass (Prune pass 13). The column sums to **712** +(verified: the 79 per-package totals add up to 712 exactly — see the +arithmetic check below the table). | # | Package | Findings | Top theme | |---|---|---|---| -| 1 | jobs | 97 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | -| 2 | warehouses | 75 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | -| 3 | instancepools | 64 | Structural duplication of `Create*`/`Edit*`/`*AndStats` | -| 4 | catalogs | 41 | `*_OptionsEntry`/`*_PropertiesEntry`; Create-with-read-only-fields; cross-package SecurableType collisions | -| 5 | functions | 38 | `function` reserved-word; cryptic single-letter enum variants | -| 6 | statementexecution | 37 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | -| 7 | instanceprofiles | 37 | Bare verb request types; vague identifiers | -| 8 | pipelines | 36 | `Update` noun = pipeline run (DLT → Lakeflow rebrand) | -| 9 | features | 36 | Sibling-package fragmentation (now 2 after `materializedfeatures` retirement) | -| 10 | genie | 35 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | -| 11 | settings | 34 | Post-consolidation v2 surface; acronym soup (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | -| 12 | schemas | 33 | `_OptionsEntry`/`_PropertiesEntry`; cross-package SecurableType collisions; vs `systemschemas` | -| 13 | marketplaces | 32 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | -| 14 | globalinitscripts | 31 | Verb-as-noun requests; proto suffix | -| 15 | modelregistry | 30 | Workspace vs UC duplicate (`registeredmodels`); MLflow vocabulary | -| 16 | apps | 30 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology; `*Proto` suffix | -| 17 | tables | 28 | `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 18 | postgres | 28 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | -| 19 | modelserving | 28 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | -| 20 | policyfamilies | 27 | "Family" + "Policy Family" mixed; underscored enums | -| 21 | metastores | 25 | Structural duplicate of `MetastoreInfo`; `UpdateMetastoreRequest` four name-like fields | -| 22 | experiments | 25 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | -| 23 | accessmanagement | 25 | Permissions/grants/rule-sets fragmentation; absorbed account access control | -| 24 | clusterpolicies | 24 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | -| 25 | registeredmodels | 23 | Cross-package overlap with `modelregistry`; `Info`-suffix entities | -| 26 | credentials | 22 | UC vs auth duplicate; `Accounts*` family | -| 27 | queries | 20 | Three-package overlap with `queryhistory`/`statementexecution` | -| 28 | clusters | 20 | 150-member `TerminationCode` brand-value casing | -| 29 | database | 19 | Package name overlaps `postgres`; deep proto nesting | -| 30 | bundle | 18 | Generic package name (`bundle`) | -| 31 | alerts | 18 | Mixed v1/v2 | -| 32 | commandexecution | 17 | Three resources (Command/Context/Cluster) mixed; verb collision (`destroy`/`delete`) | -| 33 | usagepolicy | 16 | 1:1 clone of `budgetpolicy` | -| 34 | rfa | 16 | 3-letter cryptic package name | -| 35 | modelservingquery | 16 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | -| 36 | forecasting | 16 | Generic-named `Waiter` API; cross-package overlap with `experiments` | -| 37 | budgets | 16 | Budget vs `budgetpolicy` duplication | -| 38 | repos | 15 | "Repos" legacy term; product is "Git folders" | -| 39 | featurestore | 15 | Cross-package duplicates with `onlinetables` (`DeleteOnlineTableRequest`) | -| 40 | dataquality | 15 | `ListMonitorRequest` singular for list of monitors | -| 41 | clusterlibraries | 15 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 42 | vectorsearch | 14 | `Endpoint*` and `VectorIndex*` overlap | -| 43 | lakeview | 14 | Old codename (rebrand to "AI/BI Dashboards") | -| 44 | iam | 14 | `*Proxy` method duplicates; `State`/`Entitlement` generic enums | -| 45 | connections | 14 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 46 | supervisoragents | 13 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | -| 47 | secretsuc | 13 | `uc` cryptic suffix; collides with `secrets` | -| 48 | queryhistory | 13 | Vague `Query` types; cross-package overlap with `queries` | -| 49 | logdelivery | 13 | Renamed; legacy long name fixed | -| 50 | externalmetadata | 13 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | -| 51 | gitcredentials | 12 | Three "Credentials" packages with different meanings | -| 52 | files | 12 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | -| 53 | usagedashboards | 11 | Vague type names | -| 54 | tagpolicies | 11 | Three sibling tag packages with overlapping vocab | -| 55 | tagassignments | 11 | Three-package tag split | -| 56 | secrets | 11 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | -| 57 | knowledgeassistants | 11 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | -| 58 | workspaceobjects | 10 | Filesystem scope clarified by rename | -| 59 | tokens | 10 | Cross-package duplicate of `tokenmanagement` | -| 60 | scim | 10 | Account-tier SCIM 2.0 user/group provisioning | -| 61 | environments | 10 | `Environment` generic name | -| 62 | entitytagassignments | 10 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 63 | customllms | 10 | `Llm` cryptic-acronym usage throughout | -| 64 | grants | 9 | Verb-phrase request types | -| 65 | externallocations | 9 | Cross-cloud queue type naming (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | -| 66 | externallineage | 9 | `Direction_LineageDirection`; `tpe` typo | -| 67 | disasterrecovery | 9 | `FailoverFailoverGroupRequest` stutter | -| 68 | cleanrooms | 9 | `*Handler` suffix proto-leak; misleading `accessRestricted` enum | -| 69 | volumes | 8 | Verb-as-noun requests | -| 70 | tokenmanagement | 8 | Overlap with `tokens`; duplicate `AutoscopeState` enum | -| 71 | systemschemas | 8 | Sibling-package collision with `schemas` | -| 72 | notificationdestinations | 8 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 73 | billableusagedownload | 8 | Verb in package name (`download`) | -| 74 | workspacebindings | 7 | Bare verb requests | -| 75 | budgetpolicy | 7 | Sibling clone in `usagepolicy` | -| 76 | abacpolicies | 7 | `PolicyInfo`; `MatchColumn` verb-as-noun | -| 77 | resourcequotas | 6 | Vague type names | -| 78 | artifactallowlists | 6 | Vague type names | -| 79 | sharing | 5 | Account-tier Delta Sharing provider config | -| 80 | workspaces | 4 | Residue after `*Public*Request` regen fixes | -| 81 | storageconfigurations | 4 | Sparse account-tier residue | -| 82 | networking | 4 | Residue; ~40 active `CustomerFacing*` identifiers not yet flagged | -| 83 | authentication | 4 | Account-tier token federation policies | -| 84 | oauth | 3 | OAuth Custom + Published app integrations consolidated | -| 85 | dataclassification | 2 | Tag-domain overlap | -| 86 | keyconfigurations | 1 | `ListCustomerManagedKeyRequest` singular residue | -| 87 | onlinetables | 0 | No active findings after the 2026-05-26 prune | -| — | **Total** | **1,598** | Across all 87 active audits | +| 1 | jobs | 55 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | +| 2 | warehouses | 50 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 3 | instancepools | 33 | Structural duplication of `Create*`/`Edit*`/`*AndStats` | +| 4 | instanceprofiles | 28 | Bare verb request types; vague identifiers | +| 5 | features | 24 | Sibling-package fragmentation (now 2 after `materializedfeatures` retirement) | +| 6 | pipelines | 20 | `Update` noun = pipeline run (DLT → Lakeflow rebrand) | +| 7 | settings | 20 | Post-consolidation v2 surface; acronym soup (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | +| 8 | statementexecution | 20 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | +| 9 | genie | 18 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 10 | modelregistry | 17 | Workspace vs UC duplicate (`registeredmodels`); MLflow vocabulary | +| 11 | tables | 16 | `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 12 | functions | 14 | `function` reserved-word; cryptic single-letter enum variants | +| 13 | marketplaces | 14 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | +| 14 | apps | 13 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology; `*Proto` suffix | +| 15 | budgets | 13 | Budget vs `budgetpolicy` duplication | +| 16 | catalogs | 13 | `*_OptionsEntry`/`*_PropertiesEntry`; Create-with-read-only-fields; cross-package SecurableType collisions | +| 17 | accessmanagement | 12 | Permissions/grants/rule-sets fragmentation; absorbed account access control | +| 18 | commandexecution | 12 | Three resources (Command/Context/Cluster) mixed; verb collision (`destroy`/`delete`) | +| 19 | experiments | 12 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 20 | queries | 12 | Three-package overlap with `queryhistory`/`statementexecution` | +| 21 | database | 11 | Package name overlaps `postgres`; deep proto nesting | +| 22 | forecasting | 11 | Generic-named `Waiter` API; cross-package overlap with `experiments` | +| 23 | policyfamilies | 11 | "Family" + "Policy Family" mixed; underscored enums | +| 24 | modelserving | 10 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | +| 25 | featurestore | 9 | Cross-package duplicate of `database`/online-store surface | +| 26 | rfa | 9 | 3-letter cryptic package name | +| 27 | clusterlibraries | 8 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 28 | dataquality | 8 | `ListMonitorRequest` singular for list of monitors | +| 29 | modelservingquery | 8 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 30 | schemas | 8 | `_OptionsEntry`/`_PropertiesEntry`; cross-package SecurableType collisions; vs `systemschemas` | +| 31 | alerts | 7 | Mixed v1/v2 | +| 32 | logdelivery | 7 | Renamed; legacy long name fixed | +| 33 | metastores | 7 | Structural duplicate of `MetastoreInfo`; `UpdateMetastoreRequest` four name-like fields | +| 34 | usagedashboards | 7 | Vague type names | +| 35 | customllms | 6 | `Llm` cryptic-acronym usage throughout | +| 36 | disasterrecovery | 6 | `FailoverFailoverGroupRequest` stutter | +| 37 | knowledgeassistants | 6 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | +| 38 | lakeview | 6 | Old codename (rebrand to "AI/BI Dashboards") | +| 39 | registeredmodels | 6 | Cross-package overlap with `modelregistry`; `Info`-suffix entities | +| 40 | repos | 6 | "Repos" legacy term; product is "Git folders" | +| 41 | secretsuc | 6 | `uc` cryptic suffix; collides with `secrets` | +| 42 | connections | 5 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 43 | entitytagassignments | 5 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 44 | notificationdestinations | 5 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 45 | postgres | 5 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | +| 46 | scim | 5 | Account-tier SCIM 2.0 user/group provisioning | +| 47 | secrets | 5 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | +| 48 | tagassignments | 5 | Three-package tag split | +| 49 | volumes | 5 | Verb-as-noun requests | +| 50 | artifactallowlists | 4 | Vague type names | +| 51 | clusters | 4 | 150-member `TerminationCode` brand-value casing | +| 52 | credentials | 4 | UC vs auth duplicate; `Accounts*` family | +| 53 | externalmetadata | 4 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | +| 54 | gitcredentials | 4 | Three "Credentials" packages with different meanings | +| 55 | globalinitscripts | 4 | Verb-as-noun requests; proto suffix | +| 56 | networking | 4 | Residue; ~40 active `CustomerFacing*` identifiers not yet flagged | +| 57 | queryhistory | 4 | Vague `Query` types; cross-package overlap with `queries` | +| 58 | resourcequotas | 4 | Vague type names | +| 59 | storageconfigurations | 4 | Sparse account-tier residue | +| 60 | supervisoragents | 4 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 61 | systemschemas | 4 | Sibling-package collision with `schemas` | +| 62 | tokenmanagement | 4 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 63 | vectorsearch | 4 | `Endpoint*` and `VectorIndex*` overlap | +| 64 | workspaces | 4 | Residue after `*Public*Request` regen fixes | +| 65 | budgetpolicy | 3 | Account budget-policy CRUD (its `usagepolicy` clone was removed by the regen) | +| 66 | cleanrooms | 3 | `*Handler` suffix proto-leak; misleading `accessRestricted` enum | +| 67 | clusterpolicies | 3 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | +| 68 | sharing | 3 | Account-tier Delta Sharing provider config | +| 69 | tagpolicies | 3 | Three sibling tag packages with overlapping vocab | +| 70 | tokens | 3 | Cross-package duplicate of `tokenmanagement` | +| 71 | abacpolicies | 2 | `PolicyInfo`; `MatchColumn` verb-as-noun | +| 72 | environments | 2 | `Environment` generic name | +| 73 | externallineage | 2 | `Direction_LineageDirection`; `tpe` typo | +| 74 | externallocations | 2 | Cross-cloud queue type naming (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | +| 75 | files | 2 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | +| 76 | workspacebindings | 2 | Bare verb requests | +| 77 | authentication | 1 | Account-tier token federation policies | +| 78 | grants | 1 | Verb-phrase request types | +| 79 | keyconfigurations | 1 | `ListCustomerManagedKeyRequest` singular residue | +| — | **Total** | **712** | Across all 79 active audits | + +**Arithmetic check.** Summing the 79 per-package totals gives exactly +**712**, matching the grand total. (Spot check: the top 11 packages +55 + 50 + 33 + 28 + 24 + 20 + 20 + 20 + 18 + 17 + 16 = 301; the remaining +68 packages sum to 411; 301 + 411 = 712.) The 79-finding drop from the +previously reported 791 is the 2026-06-02 category-prune pass (Prune +pass 13): three Workflow-B category prunes (field-ordering / grouping +findings, data-type-retype findings — a `string` that should be an +enum/union, a `number` that should be a `Date`/`bigint`, a `string` that +should be branded/opaque — and empty / do-nothing wrapper-deletion +findings). No audit was emptied, so the package count holds at 79. ### Retired audits — historical reference The 24 audit files for packages retired in the 2026-05-20 or 2026-05-22 -regen were **deleted on 2026-05-26** (see Prune note 8, step 3). The -audit directory now contains exactly 87 per-package files plus this +regen were **deleted on 2026-05-26** (see Prune note 8, step 3). A further +four audit files were **deleted on 2026-05-28** (see Prune pass 9): `iam` +and `workspaceobjects` (orphaned — source no longer exists), +`dataclassification` (emptied by the two prunes), and `onlinetables` +(already empty). The 2026-06-01 regen then orphaned three more, **deleted +on 2026-06-01** (see Prune pass 10): `bundle`, `usagepolicy`, and +`billableusagedownload` — each lost its source package. The 2026-06-02 +combined prune pass (see Prune pass 12) then deleted one more: `oauth`, +whose sole remaining finding was a wire-field rename that the +wire-identifier-rename prune removed, leaving it with zero findings. The +audit directory now contains exactly 79 per-package files plus this summary. The table below is preserved as a historical reference of which packages were retired and where their findings went. @@ -976,10 +1147,18 @@ packages were retired and where their findings went. | `queryexecution` | removed outright | | `serviceprincipalsecrets` | removed outright | | `serviceprincipalsecretsproxy` | removed outright (deleted before 2026-05-26) | -| `workspace` | renamed to `workspaceobjects` | +| `workspace` | renamed to `workspaceobjects` (audit later deleted 2026-05-28 — see below) | | `workspaceassignment` | merged into `accessmanagement` | | `workspaceconf` | merged into `settings` | | `workspacesettings` | merged into `settings` | +| `iam` | deleted 2026-05-28 (orphan; domain moved to `accessmanagement`) | +| `workspaceobjects` | deleted 2026-05-28 (orphan; `/api/2.0/workspace/` filesystem service dropped from the public-filtered descriptor) | +| `dataclassification` | deleted 2026-05-28 (emptied by the `Client`-class + acronym-casing prunes) | +| `onlinetables` | deleted 2026-05-28 (already empty after the 2026-05-26 prune) | +| `bundle` | deleted 2026-06-01 (orphan; `packages/bundle/` removed by the regen) | +| `usagepolicy` | deleted 2026-06-01 (orphan; `packages/usagepolicy/` removed by the regen) | +| `billableusagedownload` | deleted 2026-06-01 (orphan; no TypeScript source after the regen) | +| `oauth` | deleted 2026-06-02 (emptied — its sole wire-field-rename finding was pruned) | --- @@ -993,11 +1172,17 @@ The previous §§8.1–8.6 recommendations have all been retired: API-team decision, not a generator template change. Field-side instances are out of scope per the 2026-05-26 field-rename prune; type-side instances remain cataloged in Theme 1 above. -- The acronym-casing policy recommendation (former §8.3) is dropped at the - generator level; the inconsistencies are still cataloged in §4 as an - observational reference. -- The `Client` rename recommendation (former §8.4) is a product decision, - not a generator concern. +- The acronym-casing policy recommendation (former §8.3) is **resolved** + (2026-05-28): the user fixed acronym casing on the public interface, the + per-package acronym-casing findings were pruned everywhere, and §4 below + is retained only as a historical reference. +- The `Client` rename recommendation (former §8.4) is **resolved** + (2026-06-01): deferred on 2026-05-28 (verbatim: "i will fix this + later"), it shipped at the generator level in the 2026-06-01 regen + (#167/#168), which now emits package-prefixed client classes + (`AccessManagementClient`, `FeaturesClient`, `CredentialsClient`, + `JobsClient`, `WarehousesClient`, …) instead of a bare `Client`. See + Prune pass 10 above. - The `Request` suffix recommendation (former §8.5) is **Done**: every request DTO is now emitted with a `Request` suffix. - The strip-package-name-prefix recommendation (former §8.6) is **withdrawn** @@ -1018,7 +1203,7 @@ here as a follow-up note rather than an open finding. The following recommendations are template-level fixes that the generator emits identically across every package. Rather than carry the -same finding in 87 per-package audits, each rule is recorded once here. +same finding in 79 per-package audits, each rule is recorded once here. Each item names the rule, why it is generator-only, the approximate package count it appeared in before promotion, and an illustrative example. @@ -1079,7 +1264,7 @@ because the following public-surface instances survive: `listCleanRoomNotebookTaskRunsHandler` and its `*Iter` companion. - Mid-position `V` in `jobs` (`RunLifecycleStateV2`). -**Approximate package count where it appears today:** ~8/87 packages +**Approximate package count where it appears today:** ~8/79 packages on the exported surface. **Illustrative example (pre-regen):** @@ -1095,8 +1280,9 @@ qualifier and the `*Proto`/`*Service*`/`*Handler`/`V` tails. The audits used a shared 20-category rubric. Several categories have been retired as cross-cutting themes via prune passes: Category 2 "Redundant enum prefix" (prune note 5), Category 11 "Empty / trivial wrapper types" -(prune note 1), and Category 4 "Underscores in TS identifiers" (prune -note 4). A new category was added in the 2026-05-20 proto-architectural-leak +(prune note 1), Category 4 "Underscores in TS identifiers" (prune note +4), and Category 3 "Acronym casing" (resolved 2026-05-28 — Prune pass 9). +A new category was added in the 2026-05-20 proto-architectural-leak scan (audit-pass note 7): "Proto-architectural leak" — mid-position proto/service-tier infixes; the 2026-05-22 regen moved most of its `*Public*Request` cases to `Fixed`. @@ -1117,21 +1303,30 @@ The 2026-05-26 prune pass narrowed the rubric significantly: @deprecated tag") are out of scope across all categories (doc-change prune). +The 2026-05-28 prune pass narrowed the rubric further: + +- **Category 3 "Acronym casing"** is **resolved / retired** — the user + fixed acronym casing on the public interface and the findings were + pruned from every package. +- The **generic top-level `Client` class-name** finding (a Category 1 / + 12 sub-case) was pruned from every package and deferred by the user on + 2026-05-28; it is now **resolved** upstream — the 2026-06-01 regen + (#167/#168) emits `Client` names. See Prune pass 10. + The most-cited remaining categories on the type-level surface across -all 87 active audits: +all 79 active audits: | # | Category | Surviving on type level | |---|---|---| -| 1 | Vague / generic names (type level) | ~80 | -| 6 | Misleading names (type level) | ~75 | -| 12 | Duplicate concepts (cross-package, type-level) | ~70 | -| 20 | Type-suffix tautology | ~60 | -| 17 | Inconsistent action verbs (method names) | ~50 | -| 7 | Overly verbose type names | ~50 | -| 8 | Redundant suffix (`Info`, `Spec`, `Details`) | ~45 | -| 9 | Singular/plural mismatches (type level) | ~40 | -| 5 | Cryptic abbreviations (in type names) | ~35 | -| 3 | Acronym casing (type level, post-2026-05-21 acronym renames) | ~30 | -| 13 | Verb-tense inconsistency | ~25 | -| 18 | Long enum values | ~25 | +| 1 | Vague / generic names (type level) | ~78 | +| 6 | Misleading names (type level) | ~73 | +| 12 | Duplicate concepts (cross-package, type-level) | ~68 | +| 20 | Type-suffix tautology | ~58 | +| 17 | Inconsistent action verbs (method names) | ~48 | +| 7 | Overly verbose type names | ~48 | +| 8 | Redundant suffix (`Info`, `Spec`, `Details`) | ~44 | +| 9 | Singular/plural mismatches (type level) | ~38 | +| 5 | Cryptic abbreviations (in type names) | ~34 | +| 13 | Verb-tense inconsistency | ~24 | +| 18 | Long enum values | ~24 | | Proto | Proto-architectural leak (`*Proto`/`*Handler`/`*Service*`/`*CustomerFacing*`) | ~8 | diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index f92f5654..22c28a9f 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -1,75 +1,24 @@ # Naming Audit: abacpolicies -**Path:** `packages/abacpolicies/src/v1/` +**Path:** `packages/uc/abacpolicies/src/v1/` **Versions audited:** v1 -**Inferred domain:** Attribute-Based Access Control (ABAC) policies on Unity Catalog securables — create/get/list/update/delete row-filter and column-mask policies. -**Total weird names flagged:** 7 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 2 | -| Low | 0 | -| Observation | 2 | +| High | 2 | ## High severity -### 1. `PolicyInfo` — `src/v1/model.ts:137` +### 1. `PolicyInfo` — `src/v1/model.ts:136` - **Why weird:** `Info` is a generic suffix that adds nothing — every type is "info about something". This is the central domain entity; it should just be called `Policy`. (See rule 1: `Info` is on the vague-suffix list.) - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix). - **Suggested name:** `Policy`. - **Rationale:** `Policy` is the noun the user actually thinks about. The `Info` suffix is a tic carried over from Go SDK naming conventions that does not apply in TS, where the namespace and import path already disambiguate. -### 2. `onSecurableType: string` on `DeletePolicyRequest` / `GetPolicyRequest` / `ListPoliciesRequest` / `UpdatePolicyRequest` — `src/v1/model.ts:64,92,101,232` -- **Why weird:** Typed as `string` everywhere on these request DTOs while the same field on `PolicyInfo` (`model.ts:145`) is typed as `SecurableType` enum. The values are the same domain (`CATALOG`, `SCHEMA`, ...) — the inconsistency is a bug. -- **Category:** 6 (misleading — name implies enum, actual type is `string`), 16 (field type contradicts domain). -- **Suggested name:** Keep the name but type it `SecurableType`. -- **Rationale:** Same field name with two different types across four request DTOs forces callers to remember which one is loose. This is almost certainly a generator bug worth flagging upstream. - -### 3. `MatchColumn` — `src/v1/model.ts:130` +### 2. `MatchColumn` — `src/v1/model.ts:129` - **Why weird:** Reads as a verb (`MatchColumn`) — could be a method or a type. The field that uses it is plural (`matchColumns: MatchColumn[]`), which then reads as "match columns are an array of `MatchColumn`", and a `MatchColumn` is actually a "column matcher / condition + alias pair". - **Category:** 6 (misleading verb-as-noun), 9 (singular noun whose meaning is unclear). - **Suggested name:** `ColumnMatcher` or `ColumnMatchCondition`. - **Rationale:** Type names should be nouns; the verb form misleads. `ColumnMatcher` makes `matchColumns: ColumnMatcher[]` clearly read as "the matchers". - -## Medium severity - -### 4. `SecurableType.STAGING_TABLE` — `src/v1/model.ts:33` -- **Why weird:** Enum value pinned by a comment that says it isn't a real securable yet: "TODO: [UC-2980] Staging tables aren't full-fleged securables yet." Internal TODOs in generated SDK enums leak abstraction. -- **Category:** 18 (questionable enum value). -- **Suggested name:** Remove until it actually is a securable, or mark `@experimental`. -- **Rationale:** Public SDK enums shouldn't contain TODO-tagged speculative values. - -### 5. Inconsistent rename style for `*Options` types — `src/v1/model.ts:36,215` -- **Why weird:** `ColumnMaskOptions` and `RowFilterOptions` — two near-identical types describing variants of policy options. Each is a discriminator member; the `Options` suffix is redundant given the discriminator already says "this is the X options". -- **Category:** 8 (redundant suffix), 12 (duplicate concept across similar types). -- **Suggested name:** Either keep current names but acknowledge as boilerplate, or rename to `RowFilter`, `ColumnMask` (the `$case` discriminator already disambiguates). -- **Rationale:** Generator artefact; flagging because near-identical types is the moment to ask whether the API surface should collapse. - -## Low severity - -_None._ - -## Observations - -### 6. Action-verb conventions in `Client` -The client uses `Create`/`Get`/`List`/`Update`/`Delete` consistently. No mixed `Fetch`/`Retrieve`/`Read`. This is good. (Listed as observation per rule 17 since the audit asked us to flag inconsistencies; here we explicitly note consistency.) - -### 7. Acronym casing for `Http` / `Url` / `Id` across the SDK -The codebase uses `Http` (PascalCase capital-then-lower, e.g. `HttpClient`, `HttpRequest`) alongside the imported `URLSearchParams` (ALLCAPS, Web standard) and lowercase `url` / `userAgent`. Mixing `Http`-style with `URL`-style acronym casing is inconsistent across the SDK surface — common across JS ecosystem and probably not worth changing, but worth noting as a cross-package consistency question. -- **Category:** 3 (acronym casing). - -## Domain glossary -- `abac` — Attribute-Based Access Control (package name only; not referenced in current model code). -- `uc` — Unity Catalog (referenced in comment at model.ts:32 as "UC-2980", and implicitly across all types since policies live on Unity Catalog securables). -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). -- `oss` — not encountered in this package. -- `m2m`/`u2m`/`pat` — not encountered in this package. -- `iam` — not encountered, but conceptually overlaps with `Principal` references. - -## File coverage -- `src/v1/model.ts` (497 lines): read fully. -- `src/v1/client.ts` (250 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (20 lines): read fully. diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md index c90c5a90..9c012c1d 100644 --- a/.agent/naming-audit/accessmanagement.md +++ b/.agent/naming-audit/accessmanagement.md @@ -2,81 +2,21 @@ **Path:** `packages/accessmanagement/src/v1/` **Versions audited:** v1 -**Inferred domain:** Consolidated IAM / authorization surface for Databricks. -Combines four formerly-separate packages into one v1: (a) workspace-object -permissions (the `getObjectPermissions` / `setObjectPermissions` / -`updateObjectPermissions` / `getPermissionLevels` cluster — ACLs on clusters, -jobs, notebooks, dashboards, pipelines, registered models, etc.); (b) -account-level rule sets that bind roles to principals on accounts, groups, -service principals, and tag policies (`getRuleSet` / `updateRuleSet` / -`getAssignableRolesForResource`); (c) workspace-permission assignments — -the `USER`/`ADMIN` role a principal holds on a workspace -(`getWorkspacePermissionAssignments` / `updateWorkspacePermissionAssignment` -/ `deleteWorkspacePermissionAssignment` / `listWorkspacePermissions`); and -(d) the `checkPolicy` resource-access policy decision endpoint. Originated -from `permissions`, `workspaceassignment`, `accountaccesscontrol`, and -`accountaccesscontrolproxy` during the 2026-05-22 regeneration. -**Total weird names flagged:** 25 +**Total weird names flagged:** 12 ## Summary | Severity | Count | | --- | --- | -| High | 7 | -| Medium | 11 | -| Low | 4 | -| Observation | 3 | - -The consolidation has eliminated several prior warts (top-level verb-shaped -request types from `permissions` now carry `Request` suffixes; the -`accountaccesscontrolproxy` package surface no longer exists as a separate -package). What persists is the entire load of the prior four audits stacked -together: a 20-member `PermissionLevel` enum with `CAN_*` redundancy and -object-type-specific values leaking into a universal namespace; four -proto-style `*Request_Response` nested message types; three `*Output` -suffix types; `requestObjectType` / `requestObjectId` stringly-typed closed -enum prefixes; a `Proxy`-suffixed duplicate-method cluster around -`getAssignableRolesForResource` / `getRuleSet` / `updateRuleSet`; an -`UNKNOWN` zero-value sentinel that contradicts the `*_UNSPECIFIED` form used -on the same file's `RequestAuthzIdentity` enum; and a half-dozen -duplicate-shape concerns (`PermissionsResponse` vs `WorkspacePermissionAssignmentOutput` -vs the iam `WorkspaceAssignmentDetail`). - -The merger also introduces new collisions: `permissions` now means three -different things in three different response shapes -(`PermissionsResponse.accessControlList` vs -`ListWorkspacePermissionsRequest_Response.permissions` vs -`WorkspacePermissionAssignmentOutput.permissions`), and the `PermissionLevel` -enum (per-object permissions) sits alongside the `WorkspacePermission` enum -(per-workspace USER/ADMIN) with overlapping vocabulary but disjoint scope. +| High | 3 | +| Medium | 5 | +| Low | 2 | +| Observation | 2 | --- ## High severity -### 1. `PermissionLevel` enum values share a redundant `CAN_` action-verb prefix — `src/v1/model.ts:6-27` -- **Why weird:** Of 20 values, 19 begin with `CAN_` (`CAN_MANAGE`, - `CAN_RESTART`, `CAN_ATTACH_TO`, `CAN_MANAGE_RUN`, `CAN_VIEW`, `CAN_READ`, - `CAN_RUN`, `CAN_EDIT`, `CAN_USE`, `CAN_BIND`, `CAN_QUERY`, `CAN_MONITOR`, - `CAN_CREATE`, `CAN_MONITOR_ONLY`, `CAN_CREATE_APP`, `CAN_EDIT_METADATA`, - `CAN_VIEW_METADATA`, `CAN_MANAGE_STAGING_VERSIONS`, - `CAN_MANAGE_PRODUCTION_VERSIONS`); the lone exception is `IS_OWNER`, - which uses a copula+predicate form. The `CAN_` modal verb is implied by - membership in `PermissionLevel` — a `PermissionLevel` is, by definition, - what the principal can do — so it is content-free on every value. This is - distinct from the proto-style enum-name prefix; here the redundancy is on - the action verb shared by 19 of 20 members. Mixing `CAN_*` with - `IS_OWNER` also breaks within-enum consistency. -- **Category:** Redundant action-verb prefix on enum members; within-enum - inconsistency. -- **Suggested name:** Drop the `CAN_` action-verb prefix: `MANAGE`, - `RESTART`, `ATTACH_TO`, `MANAGE_RUN`, `VIEW`, `READ`, `RUN`, `EDIT`, - `USE`, etc. `IS_OWNER` becomes `OWNER`. -- **Rationale:** Compare `Visibility { PUBLIC, PRIVATE }` vs - `Visibility { IS_PUBLIC, IS_PRIVATE }`. The latter is comically redundant. - `PermissionLevel.MANAGE` is shorter and just as unambiguous as - `PermissionLevel.CAN_MANAGE`. - -### 2. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:17,18,26` +### 1. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:17,18,26` - **Why weird:** Three values are specific to one object type each (`registered-models` in MLflow Model Registry, and Databricks Apps), but live in a universal `PermissionLevel` enum applicable to 25+ object @@ -94,51 +34,26 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum discoverability hazard; users browsing autocomplete will see these as valid choices for clusters, jobs, and dashboards. -### 3. `RequestAuthzIdentity` enum and `REQUEST_AUTHZ_IDENTITY_*` member prefix; `Authz` truncation — `src/v1/model.ts:33-37` +### 2. `RequestAuthzIdentity` enum name — `Request` prefix and `Authz` truncation — `src/v1/model.ts:33-37` - **Why weird:** The type name starts with `Request` — a wire-format message prefix (`RequestAuthzIdentity` reads as "the AuthzIdentity field on a request message"). The mid-name truncation `Authz` (instead of `Authorization`) is a Go-style abbreviation that does not match the rest of the package, which spells out `permission` and `permissionLevel` in - full. The members re-state the entire enum name as a SCREAMING_SNAKE - prefix: `REQUEST_AUTHZ_IDENTITY_USER_CONTEXT`, - `REQUEST_AUTHZ_IDENTITY_SERVICE_IDENTITY` — wasted call-site characters. + full. - **Category:** Proto-architectural leak (`Request` prefix on a domain enum), cryptic abbreviation (`Authz`). - **Suggested name:** `AuthorizationIdentity` (or simply - `AuthIdentity`/`CallerIdentity`) with members `USER_CONTEXT`, - `SERVICE_IDENTITY`. + `AuthIdentity`/`CallerIdentity`). - **Rationale:** The `Request` prefix on a type that names a domain concept (who the policy check is on behalf of) is wire-shape leakage from the containing `CheckPolicyRequest`. The `Authz` truncation is fine in code comments but jars on a public, exported enum. -### 4. `requestObjectType: string` is a stringly-typed closed enum — `src/v1/model.ts:156,163,340,348` -- **Why weird:** Every request type carries - `requestObjectType?: string | undefined`. The JSDoc on each occurrence - lists 26 valid string values verbatim: `"alerts, alertsv2, authorization, - clusters, cluster-policies, dashboards, database-projects, - dbsql-dashboards, directories, experiments, files, genie, instance-pools, - jobs, knowledge-assistants, notebooks, pipelines, queries, - registered-models, repos, serving-endpoints, supervisor-agents, - vector-search-endpoints, or warehouses"`. The set is closed, - well-known to the server, and stable — a perfect fit for a string - literal union. The TS SDK ships it as bare `string` with no autocomplete - or compile-time validation. A typo (`"cluster"` instead of `"clusters"`) - silently 4xxs at runtime. -- **Category:** Underspecified ID; cryptic/loose typing; generic field - name (`requestObjectType`). -- **Suggested name:** Define - `type RequestObjectType = 'alerts' | 'alertsv2' | 'authorization' | 'clusters' | 'cluster-policies' | ... | 'warehouses'` - (string literal union, 26 entries). -- **Rationale:** This is the single biggest TS-affordance miss in the - package. The Go SDK uses `string` because Go enums are second-class; TS - has first-class string literal unions that match this exact use case. - -### 5. `getAssignableRolesForResourceProxy`, `getRuleSetProxy`, `updateRuleSetProxy` — `src/v1/client.ts:255,329,395` +### 3. `getRuleSetProxy`, `listAssignableRolesForResourceProxy`, `updateRuleSetProxy` — `src/v1/client.ts:257,331,397` - **Why weird:** Three methods carry the `Proxy` suffix and are - byte-for-byte identical to their non-`Proxy` siblings (lines 218, 292, - 366). They issue the same HTTP request to the same URL with the same + byte-for-byte identical to their non-`Proxy` siblings (lines 220, 294, + 368). They issue the same HTTP request to the same URL with the same headers. The `Proxy` suffix communicates an architectural concept — these are the same operation routed through a proxy server in the Databricks control plane — that has zero meaning for a TypeScript SDK @@ -154,133 +69,26 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum does, not how the server routes it. Two identical methods with a `Proxy` differentiator force every caller to flip a coin. -### 6. `WorkspacePermission.UNKNOWN` zero-value sentinel — `src/v1/model.ts:40` -- **Why weird:** `WorkspacePermission` uses `UNKNOWN` as its zero-value - sentinel, but the sibling enum `RequestAuthzIdentity` in the same file - uses the `*_UNSPECIFIED` form (`REQUEST_AUTHZ_IDENTITY_UNSPECIFIED`, - line 34), and every other enum across this SDK uses `*_UNSPECIFIED` as - well (e.g., `WORKSPACE_PERMISSION_UNSPECIFIED` in the now-removed iam - mirror). One enum, one file, two sentinel conventions. -- **Category:** Within-package inconsistency (same file, two sentinel - conventions). -- **Suggested name:** `WORKSPACE_PERMISSION_UNSPECIFIED`. -- **Rationale:** Same-file inconsistency is the worst kind. Aligning with - the rest of the file (and the rest of the SDK) costs nothing. - -### 7. `Client` — `src/v1/client.ts:69` -- **Why weird:** Top-level class named `Client`. Generic across every - generated package. The merger makes this worse: this class now exposes - the *combined* surface of four formerly-distinct services - (permissions, workspaceassignment, accountaccesscontrol, - accountaccesscontrolproxy). A consumer importing `Client` from this - package has no surface-level cue what it does. Users importing - `Client` from multiple permission-adjacent packages still have to - alias. -- **Category:** Vague top-level identifier; cross-package collision. -- **Suggested name:** `AccessManagementClient` (matches the package name) - or, given the breadth of the surface, split the class along its four - composed services. -- **Rationale:** SDK convention in AWS, Azure, and GitHub Octokit is - service-prefixed client class names. Project-wide pattern — flag here as - highest-leverage location. - --- ## Medium severity -### 8. `RuleSet` vs `RuleSetUpdateRequest` (duplicate body shape) — `src/v1/model.ts:306,322` -- **Why weird:** `RuleSet` and `RuleSetUpdateRequest` are structurally - identical (`name`, `etag`, `grantRules`). They model the same resource — - one as a response body, one as the update body — but expose it under two - top-level names. `UpdateRuleSetRequest` then wraps `RuleSetUpdateRequest` - under a `ruleSet` field, so the developer sees three overlapping shapes - (`RuleSet`, `RuleSetUpdateRequest`, `UpdateRuleSetRequest`) for one - concept. The wire payload is keyed `rule_set`, not - `rule_set_update_request`. -- **Category:** Duplicate concepts; redundant wrapper. -- **Suggested name:** Collapse to `RuleSet` only. The update endpoint body - should be `{ name, ruleSet: RuleSet }`. Remove `RuleSetUpdateRequest` - entirely. -- **Rationale:** A single canonical `RuleSet` shape avoids the read/write - divergence. Proto generates separate types because Go does not have - structural typing; in TypeScript the duplication is wasteful. - -### 9. `UpdateRuleSetRequest.ruleSet` vs `UpdateRuleSetRequest.name` overlap — `src/v1/model.ts:354-360` -- **Why weird:** `UpdateRuleSetRequest` has both a top-level `name` and - `ruleSet.name` (because `RuleSetUpdateRequest` also carries `name`). Two - `name` fields on the same request that conceptually identify the same - thing is a footgun — which one wins? Nothing in the TS type encodes - that. -- **Category:** Misleading; field name overlapping itself. -- **Suggested name:** Drop the outer `name` (use it from `ruleSet.name`), - or rename the outer to `pathName`/`resourceName` to make the routing - role explicit. -- **Rationale:** Both fields share an identical doc comment ("Name of the - rule set."). Developers will set one and not the other and silently - 4xx. - -### 10. `GrantRule.role` is a string, not a `Role` — `src/v1/model.ts:227,302` -- **Why weird:** The package exports a `Role` type and then immediately - ignores it: `GrantRule.role` is `string`. So `Role` is the response - shape from `getAssignableRolesForResource`, but `GrantRule.role` is the - same identifier path serialized inline. Two representations of the - same concept. -- **Category:** Duplicate concept; field type mismatch with sibling type. -- **Suggested name:** Type `GrantRule.role` as `Role['name']` or a - branded `RoleName` string so the two surfaces stay aligned. -- **Rationale:** Developers will write `grantRule.role = role.name` - constantly because the types don't line up. - -### 11. `GetAssignableRolesForResource*` verbosity and verb shape — `src/v1/model.ts:134,150`, `src/v1/client.ts:218` -- **Why weird:** 41-character type names. The "ForResource" suffix is - implied — every assignable-roles query is for a resource. The pair - reads like a Java RPC service name (`GetForRequest`). - The method `getAssignableRolesForResource` returns an array, so it is - semantically a list, not a get. -- **Category:** Overly verbose; verb mismatch (`Get` for a list result). +### 4. `ListAssignableRolesForResource*` "ForResource" verbosity — `src/v1/model.ts:194,210`, `src/v1/client.ts:294` +- **Why weird:** 38-character type names + (`ListAssignableRolesForResourceRequest` / + `ListAssignableRolesForResourceResponse`). The "ForResource" suffix is + implied — every assignable-roles query is for a resource (the request + carries a single `resource` field). The pair reads like a Java RPC + service name (`ListForRequest`). +- **Category:** Overly verbose; redundant qualifier. - **Suggested name:** `ListAssignableRolesRequest` / - `ListAssignableRolesResponse`, method `listAssignableRoles`. Reflects - that the operation returns a list and aligns with REST conventions. -- **Rationale:** Symmetry with `GetRuleSet`/`UpdateRuleSet` might suggest - `Get...`, but the operation returns an array and is closer to a list - semantically. + `ListAssignableRolesResponse`, method `listAssignableRoles`. Drops the + implied "ForResource" tail. +- **Rationale:** The `List`/`list` verb already matches the array-returning + REST semantics; only the redundant "ForResource" qualifier remains. A + shorter name is just as unambiguous. -### 12. `GrantRule.principals: string[]` is an untyped principal-format list — `src/v1/model.ts:225` -- **Why weird:** Generic `string[]` for principals, where each entry is - one of three formats (`users/`, `groups/`, - `servicePrincipals/`). The shape is - documented in the JSDoc but not in the type. -- **Category:** Generic field losing meaning; underspecified ID. -- **Suggested name:** Type with a template-literal union — e.g. - `principals: PrincipalRef[]` where - `type PrincipalRef = \`users/${string}\` | \`groups/${string}\` | \`servicePrincipals/${string}\``. -- **Rationale:** TypeScript can encode this; the Go SDK cannot. The 1:1 - port leaves type information on the floor. - -### 13. `*Request_Response` underscore-nested proto-message types — `src/v1/model.ts:132,168,211,239` -- **Why weird:** Four types use the proto-style nested-message underscore - convention: `DeleteWorkspacePermissionAssignmentRequest_Response`, - `GetPermissionLevelsRequest_Response`, - `GetWorkspacePermissionAssignmentsRequest_Response`, - `ListWorkspacePermissionsRequest_Response`. Each is annotated with - `// eslint-disable-next-line @typescript-eslint/naming-convention -- - Proto-style nested message name.` — the comment explicitly admits the - leak. The corresponding zod schemas - (`unmarshalDeleteWorkspacePermissionAssignmentRequest_ResponseSchema`, - etc.) carry the same wart at `model.ts:441,454,466,488`. Most response - types in this package are top-level `*Response`; only these four use - the nested form. (NOTE: `_Response` underscore suffix is a - generator-only recommendation in `_SUMMARY.md`; here we flag the - within-file inconsistency it creates.) -- **Category:** Within-package inconsistency — some responses top-level - `*Response`, others nested `*Request_Response`. -- **Suggested name:** Generator-side fix. For this package, the - inconsistency would resolve once the underscore-suffix recommendation - applies SDK-wide. -- **Rationale:** TypeScript has no concept of nested message types; the - underscore separator is a proto-specific path encoding. - -### 14. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:250,268,383` +### 5. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:247,265,380` - **Why weird:** Three types ending with `Output`. In proto / gRPC service definitions, message types are commonly named `FooInput` (request) and `FooOutput` (response) — the `Output` suffix is the @@ -296,7 +104,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Compare `principal: PrincipalOutput` to `principal: Principal` — the latter reads as plain English. -### 15. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:244` +### 6. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:241` - **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance is really an "effective permission" — a permission level paired with @@ -313,7 +121,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum common across IAM systems that it's nearly content-free without qualification. -### 16. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:256` +### 7. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:253` - **Why weird:** Type carries `permissionLevel?: PermissionLevel` (singular) and `description?: string`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. @@ -322,7 +130,7 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum `PermissionLevelInfo`. - **Rationale:** One descriptor = one level; the type name should match. -### 17. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:261` +### 8. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:258` - **Why weird:** Returned from three different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, @@ -335,38 +143,13 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** The type's payload (`objectId`, `objectType`, `accessControlList`) is the concept; `Response` is incidental. -### 18. `Actor.kind` discriminated-union with a single variant — `src/v1/model.ts:95-97` -- **Why weird:** `Actor.kind?: { $case: 'actorId'; actorId: number } | - undefined` — the `kind` field name is a direct port of the proto - `oneof kind { ... }` block convention. With a single-variant union - (only `actorId`), the entire discriminator is dead weight — there's - nothing else it could be. -- **Category:** Proto-architectural leak (`oneof` block name `kind` - carried verbatim); single-variant union is unnecessary structure. -- **Suggested name:** Flatten to `actorId?: number | undefined` directly - on `Actor`. If a future variant is added, introduce the discriminated - union then with a meaningful discriminator name. -- **Rationale:** A single-variant discriminated union is a proto - modeling artifact, not a domain concept. - --- ## Low severity -### 19. `etag` casing — `src/v1/model.ts:199,318,334` -- **Why weird:** Lowercase `etag` (rather than `eTag`/`ETag`). HTTP spec - uses `ETag`. Per the project-wide acronym policy (Google TS - `Pascal-then-lower`), the form would be `etag`/`Etag` depending on - position. Mixed-case `eTag` would be wrong. Flag for cross-package - consistency review only. -- **Category:** Acronym casing. -- **Suggested name:** Confirm against project-wide policy. Current form is - most likely correct per Google TS rules. -- **Rationale:** Defer to global policy. - -### 20. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:500,513` +### 9. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:511,527` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` - (line 513). The request type `UpdateObjectPermissionsRequest` is + (line 527). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. @@ -376,21 +159,10 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum - **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. -### 21. `getWorkspacePermissionAssignments` returns a list — `src/v1/client.ts:127` -- **Why weird:** Method is named with `get*` but returns - `permissionAssignments` array (model.ts:213). REST convention is - `list*` for array-returning operations; `get*` for singular. -- **Category:** Verb-tense inconsistency. -- **Suggested name:** `listWorkspacePermissionAssignments` and - `ListWorkspacePermissionAssignmentsRequest` / - `…Response`. -- **Rationale:** Aligns naming with REST list semantics used elsewhere - in the SDK. - -### 22. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:155` +### 10. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:157` - **Why weird:** Method `listWorkspacePermissions` returns the catalog of `PermissionOutput` values supported (USER/ADMIN), not - user data. Sits side-by-side with `getWorkspacePermissionAssignments` + user data. Sits side-by-side with `listWorkspacePermissionAssignments` (which actually lists data). The two are visually similar and easy to mix up. - **Category:** Misleading verb (catalog vs data). @@ -402,63 +174,21 @@ enum (per-object permissions) sits alongside the `WorkspacePermission` enum ## Observations -### O1. `workspaceId` and `principalId` typed as `number` — `src/v1/model.ts:126,128,207,235,287,366,368` -- Workspace IDs and principal IDs are 64-bit integers in - Databricks; JS `number` loses precision above 2^53. The client also - unconditionally `String()`s these into URL paths, so string semantics - are sufficient throughout. Worth flagging cross-package: bigint or - string would be safer. - -### O2. `error?: string` on `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:389` +### O1. `error?: string` on `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:386` - Embedding an opaque error string inside the success response body is unusual; typical SDK design surfaces errors as exceptions or as a - typed error union. The field is named `error` (clashing with the - global `Error` class and the `catch(error)` parameter name). - `errorMessage` or `partialFailureReason` would be clearer. + typed error union. A caller has to inspect a per-row `error` field to + discover that an otherwise-successful response carries a partial + failure. -### O3. Single class composes four formerly-distinct services — `src/v1/client.ts:69` -- The `Client` class composes 12 methods that previously lived across - four packages. Three operational clusters +### O2. Single class composes four formerly-distinct services — `src/v1/client.ts:68` +- The `AccessManagementClient` class composes 15 methods that previously + lived across four packages. Three operational clusters (workspace-object-permissions, account-level rule sets, workspace-permission-assignments) plus one orphan (`checkPolicy`) share a class with no internal structure or grouping. Naming-adjacent: - a single flat `Client` interface flattens the conceptual boundaries + a single flat client class flattens the conceptual boundaries that gave the four original packages their identity. Consider exposing sub-namespaces (`client.objectPermissions.get(...)`, `client.ruleSets.update(...)`, etc.) to reflect the cluster boundaries, even though the merger argues against re-split. - ---- - -## Domain glossary -- `accountId` — Databricks account UUID (top-level tenant container, - distinct from a workspace). -- `etag` — HTTP entity tag, used here as a freshness floor on GET and as - an optimistic concurrency token on PUT. -- `principal` — User, service principal, or group; the subject of an - access rule or a permission assignment. -- `Role` — Reference to a grantable account-level role (e.g. - `roles/account.admin`). -- `RuleSet` — A versioned collection of `GrantRule`s attached to a - resource. -- `GrantRule` — A binding of N principals to 1 role within a `RuleSet`. -- `PermissionLevel` — A per-object-type access-grant level (`CAN_MANAGE`, - `CAN_VIEW`, `IS_OWNER`, etc.). Distinct from `WorkspacePermission`. -- `WorkspacePermission` — A workspace-membership role for a principal - (`USER`, `ADMIN`). Distinct from `PermissionLevel`. -- `PermissionAssignment` — A binding of a principal to one or more - `WorkspacePermission` values on a single workspace. -- `requestObjectType` / `requestObjectId` — Wire-name pair identifying - the object on which a permissions ACL is read or written. -- `resource` — Hierarchical name identifying what the rule set or roles - list applies to (account, group, service principal, or tag policy). -- `policy` (in `CheckPolicyRequest`) — A server-side authorization - rule; `checkPolicy` asks the server whether a given actor may perform - a given permission on a given resource. - -## File coverage -- `src/v1/model.ts` (738 lines): read fully. -- `src/v1/client.ts` (581 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (45 lines): read fully. -- `src/v1/transport.ts` (75 lines): read for context. diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md index 102560ef..0a76ad22 100644 --- a/.agent/naming-audit/alerts.md +++ b/.agent/naming-audit/alerts.md @@ -2,62 +2,19 @@ **Path:** `packages/alerts/src/{v1,v2}/` **Versions audited:** v1, v2 -**Inferred domain:** SQL/Databricks alerts: a stored configuration that periodically evaluates a query result against a threshold and notifies subscribers when it triggers. -**Total weird names flagged:** 18 (0 fixed, 18 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 7 (rescan on 2026-05-28; wire-identifier renames pruned on 2026-06-02) ## Summary table | # | Severity | Version | Location | Name | Category | |---|----------|---------|----------|------|----------| | 1 | High | v2 | `model.ts` enum | `Aggregation` | Vague/generic, no domain prefix | -| 2 | High | v2 | `model.ts` enum value | `AlertEvaluationState.UNKNOWN` | Inconsistent sentinel naming (`UNKNOWN` vs `UNSPECIFIED`) | -| 3 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | -| 4 | High | v2 | `model.ts` field | `Alert.runAsUserName` vs `Alert.runAs.userName` | Duplicate concept | -| 5 | High | v2 | `model.ts` field | `Alert.queryText` | Field contradicts type domain (alert holds raw SQL) | -| 6 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | -| 7 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | -| 8 | Medium | both | `model.ts` enum value | `AlertOperator.IS_NULL` / v2 `IS_NOT_NULL` | Long enum values inconsistent with binary ops | -| 9 | Medium | both | `model.ts` field | `Alert.notifyOnOk` | Acronym casing ambiguity (`Ok` vs `OK`) | -| 10 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | -| 11 | Medium | v2 | `model.ts` enum | `SchedulePauseStatus` | Boolean-shaped enum | -| 12 | Medium | v2 | `model.ts` enum value | `AlertLifecycleState.DELETED` vs v1 `TRASHED` | v1→v2 rename break | -| 13 | Low | v2 | `model.ts` enum value | `Aggregation.STDDEV` | Cryptic abbreviation | -| 14 | Low | v2 | `model.ts` enum value | `Aggregation.AVG` | Cryptic abbreviation | -| 15 | Low | v2 | `model.ts` field | `AlertEvaluation.threshold` typed as `AlertOperand` | Misleading type (threshold can be a column) | -| 16 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | -| 17 | Low | both | `model.ts` field | `Alert.customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) | v1→v2 rename — different email/text vocabulary | -| 18 | Low | v2 | `model.ts` field | `Alert.effectiveRunAs` | "Effective" prefix unexplained at first read | - -## v1 vs v2 comparison - -### Major renames - -| v1 name | v2 name | Notes | -|---------|---------|-------| -| `AlertOperator` (enum) | `ComparisonOperator` (enum) | **Regression** — `AlertOperator` was self-describing within the alerts package; `ComparisonOperator` is generic and re-uses a name already common across SDK packages. The new enum also adds `IS_NOT_NULL` (good), but the rename obscures the domain. | -| `AlertOperator.IS_NULL` only | `ComparisonOperator.IS_NULL` + `IS_NOT_NULL` | Expansion (good) but introduces a unary/binary asymmetry inside an enum named "Comparison". | -| `LifecycleState` (enum) | `AlertLifecycleState` (enum) | **Improvement** — domain prefix added. | -| `LifecycleState.TRASHED` | `AlertLifecycleState.DELETED` | **Break** — `trashAlert` method (still named "trash") now yields a state called `DELETED`. The verb on the wire and the state vocabulary diverge, even though the docstring still says "soft deleted". | -| `AlertCondition` (type) | `AlertEvaluation` (type) | **Major rename** — shifts from "condition shape" to "evaluation snapshot." The new type co-mingles configuration (`comparisonOperator`, `threshold`, `notification`) with runtime telemetry (`state`, `lastEvaluatedAt`), which is a meaningful design regression for naming. | - -### New in v2 (no v1 counterpart) - -- `Aggregation` (enum) — top-level, no domain prefix. -- `SchedulePauseStatus` (enum) — partial domain prefix. -- `AlertNotification` (type) -- `AlertRunAs` (type) — verb-as-noun. -- `AlertSubscription` (type) -- `CronSchedule` (type) — generic name in a single-domain package. -- `Alert.queryText`, `Alert.runAsUserName`, `Alert.runAs`, `Alert.effectiveRunAs`, `Alert.schedule`, `Alert.customSummary`, `Alert.customDescription`. -- `TrashAlertRequest.purge` — new flag. - -### Dropped in v2 - -- `Alert.queryId` (v1) — alert no longer references a Query by ID; v2 embeds raw `queryText` + `warehouseId`. **Regression** in normalization, **improvement** in name specificity. - -### Net assessment - -v2 has clear wins (`AlertLifecycleState` prefix; spelling out `comparisonOperator`) but also introduces several regressions (`AlertOperator` → `ComparisonOperator`, `condition` → `evaluation`, `LifecycleState.TRASHED` → `AlertLifecycleState.DELETED` while keeping the method `trashAlert`). +| 2 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | +| 3 | High | v2 | `model.ts` field | `Alert.queryText` | Field contradicts type domain (alert holds raw SQL) | +| 4 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | +| 5 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | +| 6 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | +| 7 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | ## High severity @@ -80,28 +37,7 @@ export enum Aggregation { Exported at the package root without an `Alert` or `Column` prefix. The same word is overloaded across SQL, stats, monitoring, and ML domains. `AlertOperandAggregation` or `ColumnAggregation` would be unambiguous. -### 2. `AlertEvaluationState.UNKNOWN` — inconsistent sentinel naming and deprecated value (v2) - -**Location:** `src/v2/model.ts:26-32` - -```ts -/** - * UNSPECIFIED - default unspecify value for proto enum, do not use it in the code - * UNKNOWN - alert not yet evaluated - * ... - */ -export enum AlertEvaluationState { - /** Deprecated. Please avoid using `UNKNOWN` as empty_result_state. */ - UNKNOWN = 'UNKNOWN', - TRIGGERED = 'TRIGGERED', - OK = 'OK', - ERROR = 'ERROR', -} -``` - -This enum exposes a value (`UNKNOWN`) that the inline JSDoc tells the user to avoid: "Deprecated. Please avoid using `UNKNOWN` as empty_result_state." Shipping a deprecated value as part of the public enum surface is a naming/API smell — consumers reading the type cannot tell which values are valid without the JSDoc. Additionally, this enum's zero-value sentinel is named `UNSPECIFIED` while other enums in the package use `UNKNOWN` for the same role; the package-wide sentinel convention is inconsistent. - -### 3. `AlertRunAs` — verb-as-noun (v2) +### 2. `AlertRunAs` — verb-as-noun (v2) **Location:** `src/v2/model.ts:155-168` @@ -116,21 +52,7 @@ export interface AlertRunAs { `RunAs` is an imperative verb phrase used as a type name. `AlertIdentity`, `AlertRunner`, or `RunAsIdentity` would parse as nouns. Also note: the *field* inside is named `identity` — a clearer type name would let the field name be more specific (or vice versa). -### 4. Duplicate concept — `runAsUserName` vs `runAs.userName` (v2) - -**Location:** `src/v2/model.ts:77-99` - -```ts -// Deprecated: Use `run_as` field instead. ... -runAsUserName?: string | undefined; -... -runAs?: AlertRunAs | undefined; -effectiveRunAs?: AlertRunAs | undefined; -``` - -The same data is expressible as either `runAsUserName` (legacy scalar) or `runAs.identity.userName` (new structured). The Alert type carries both. The deprecation is noted in JSDoc only — a TS user reading the type sees three "run as"-prefixed fields without IDE help. - -### 5. `Alert.queryText` — field contradicts type domain (v2) +### 3. `Alert.queryText` — field contradicts type domain (v2) **Location:** `src/v2/model.ts:68-69` @@ -143,9 +65,9 @@ A type named `Alert` carrying a raw SQL string makes the alert object responsibl ## Medium severity -### 6. `trashAlert` — inconsistent action verb (both) +### 4. `trashAlert` — inconsistent action verb (both) -**Location:** `src/v1/client.ts:170-192`; `src/v2/client.ts:168-196` +**Location:** `src/v1/client.ts:180-206`; `src/v2/client.ts:178-210` ```ts /** Moves an alert to the trash. ... A trashed alert is permanently deleted after 30 days. */ @@ -154,141 +76,22 @@ async trashAlert(...) { ... DELETE ... } The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashAlert`. Across the SDK this is the only place where soft-delete uses `trash`-prefix. Most resources use `deleteX` (and the v2 enum value is `AlertLifecycleState.DELETED`, not `TRASHED`). -### 7. `TrashAlertRequest` — same as 6, in the type layer (both) +### 5. `TrashAlertRequest` — same as 4, in the type layer (both) **Location:** `src/v1/model.ts:187-189`; `src/v2/model.ts:218-222` Same verb inconsistency at the type layer. -### 8. Long enum values with `_OR_` connectors - -**Location:** `src/v1/model.ts:8-16`; `src/v2/model.ts:39-48` - -```ts -GREATER_THAN_OR_EQUAL = 'GREATER_THAN_OR_EQUAL', -LESS_THAN_OR_EQUAL = 'LESS_THAN_OR_EQUAL', -``` - -The wire format uses long, English-prose enum values where most SDKs use `GT`, `GTE`, `LT`, `LTE`. They are long and verbose, and v2 adds `IS_NOT_NULL` alongside `IS_NULL` — unary operators sharing an enum named `ComparisonOperator`. - -### 9. `Alert.notifyOnOk` — acronym/initialism case ambiguity (both) - -**Location:** `src/v1/model.ts:59`; `src/v2/model.ts:128` - -```ts -notifyOnOk?: boolean | undefined; -``` - -`OK` is conventionally upper-case, so `notifyOnOK` would match the enum value `AlertEvaluationState.OK`. The field uses title-case `Ok`, mismatching the enum value casing in the same file. - -### 10. `CronSchedule` — generic name in a single-domain package (v2) +### 6. `CronSchedule` — generic name in a single-domain package (v2) **Location:** `src/v2/model.ts:181-195` A top-level type called `CronSchedule` in a package whose only consumer is alerts. If/when another package wants its own cron schedule shape, the user has two `CronSchedule`s. `AlertSchedule` would domain-prefix consistently with the rest of v2. -### 11. `SchedulePauseStatus` — boolean-shaped enum (v2) - -**Location:** `src/v2/model.ts:50-53` - -```ts -export enum SchedulePauseStatus { - UNPAUSED = 'UNPAUSED', - PAUSED = 'PAUSED', -} -``` - -Two values for a boolean concept; `boolean paused` would be simpler. - -### 12. `AlertLifecycleState.DELETED` vs v1 `LifecycleState.TRASHED` — vocabulary swap - -**Location:** v1 `model.ts:24-27`; v2 `model.ts:34-37` - -The method is still `trashAlert` (both versions), but in v1 the resulting state is `TRASHED` and in v2 it is `DELETED`. So in v2 you "trash" something and it becomes "deleted." The wire/JSDoc still references "trashed." - ## Low severity -### 13. `Aggregation.STDDEV` — cryptic abbreviation (v2) - -```ts -STDDEV = 'STDDEV', -``` - -`STANDARD_DEVIATION` or `STDEV` would be clearer; `STDDEV` is a SQL-server-ism. - -### 14. `Aggregation.AVG` — cryptic abbreviation (v2) - -`AVERAGE` would be consistent with `SUM`, `COUNT`, `MEDIAN`, `MIN`, `MAX`. The mix of short and full names inside one enum is the issue. - -### 15. `AlertEvaluation.threshold` typed as `AlertOperand` — misleading (v2) - -```ts -/** Threshold to user for alert evaluation, can be a column or a value. */ -threshold?: AlertOperand | undefined; -``` - -The JSDoc admits the threshold can be a column — i.e., not actually a threshold value but another operand. The field name implies "fixed comparison number," the type allows "another column." The field name lies. - -Also note the typo "Threshold to user" (should be "to use") — content, not naming, but worth fixing. +### 7. `LifecycleState` — missing domain prefix (v1) -### 16. `LifecycleState` — missing domain prefix (v1) +**Location:** `src/v1/model.ts:24-27` v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycleState`. - -### 17. `customBody` / `customSubject` (v1) vs `customSummary` / `customDescription` (v2) - -Same data, different vocabulary. v1 = email metaphor, v2 = generic content metaphor. Users porting from v1 to v2 need a translation table. - -### 18. `effectiveRunAs` (v2) - -**Location:** `src/v2/model.ts:94-99` - -```ts -/** - * The actual identity that will be used to execute the alert. - * This is an output-only field that shows the resolved run-as identity after applying - * permissions and defaults. - */ -effectiveRunAs?: AlertRunAs | undefined; -``` - -The "effective" prefix is a Databricks convention for "value after applying inheritance/permissions." First-time readers will not know what `effectiveX` means without docs. Established convention, but flagged. (Previously also cited `effectiveParentPath`; that field was removed in regeneration.) - -## Observations - -1. **Wire-format leakage.** Many names are direct translations of proto wire fields without consideration of how they read in TypeScript: `STDDEV`, `IS_NULL`, `UNKNOWN`. The audit rule "1:1 port" was followed faithfully but the language idioms suffer. - -2. **v1→v2 vocabulary churn.** The package introduces multiple renames between versions (`AlertOperator` → `ComparisonOperator`, `LifecycleState` → `AlertLifecycleState`, `TRASHED` → `DELETED`, `AlertCondition` → `AlertEvaluation`, `customBody/Subject` → `customSummary/Description`). Some are improvements, some are lateral, some are regressions. Combined with `trashAlert` keeping its name while `TRASHED` becomes `DELETED`, the message-vs-method vocabulary is inconsistent. - -3. **Verb-as-noun proliferation in v2.** `AlertRunAs`, `effectiveRunAs`, `runAs.identity`, `runAsUserName` — a single concept ("which identity executes this alert") spreads across four names with overlapping semantics. - -4. **`Alert.evaluation` mixes config and telemetry.** `AlertEvaluation` carries both inputs (`comparisonOperator`, `threshold`, `notification`) and outputs (`state`, `lastEvaluatedAt`). The name suggests "a run/event," but the type is really "evaluation configuration + last-run snapshot." Splitting into `AlertEvaluationConfig` + `AlertEvaluationStatus` (or moving `state`/`lastEvaluatedAt` onto `Alert` directly, where they used to live in v1) would make the naming honest. - -5. **Top-level type pollution in v2.** v2 exports `Aggregation`, `ComparisonOperator`, `CronSchedule`, `SchedulePauseStatus`, `AlertEvaluationState`, `AlertLifecycleState` plus 9 message types from a single package. Several have no `Alert` prefix and read as if they belong to a shared domain library. Prefixing them all uniformly (`AlertAggregation`, `AlertScheduleCron`, `AlertSchedulePauseStatus`) would isolate the package. - -## Domain glossary - -| Term | Meaning in this package | -|------|------------------------| -| Alert | A stored configuration that runs a SQL query on a schedule and notifies subscribers when the result satisfies a comparison against a threshold. | -| Trigger | The state transition from "not satisfying the condition" to "satisfying the condition." | -| Re-trigger | Re-firing of notifications after the alert has already triggered (gated by a cooldown). | -| Evaluation | A single run of the alert's query + comparison; produces a state. | -| Operand | One side of the comparison; can be a column reference or a literal value. | -| Threshold | The value (or column) the source column is compared against. v2 misuses the word — it's really the second operand. | -| Lifecycle state | `ACTIVE` (visible to user) or trashed/`DELETED` (soft-deleted; auto-purged after 30 days). | -| Run-as | The identity (user or service principal) under which the query executes. | -| Effective X | The value of X after applying permission inheritance / server defaults. | - -## File coverage - -| File | Lines | Read in full | -|------|-------|--------------| -| `src/v1/model.ts` | 620 | yes | -| `src/v1/client.ts` | 219 | yes | -| `src/v1/utils.ts` | 150 | yes | -| `src/v1/index.ts` | 23 | yes | -| `src/v2/model.ts` | 669 | yes | -| `src/v2/client.ts` | 235 | yes | -| `src/v2/utils.ts` | 150 | yes | -| `src/v2/index.ts` | 30 | yes | diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index 861d3dcd..878b781d 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -1,118 +1,23 @@ # Naming Audit: `@databricks/sdk-apps` (v1) **Package:** `apps` (`packages/apps/src/v1/`) -**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts` -**Domain:** Databricks Apps — interactive applications hosted in a workspace, -with deployments, custom templates, app spaces, and resource bindings. +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts`, `transport.ts` ## Summary | Severity | Count | | -------- | ----- | -| High | 5 | -| Medium | 10 | -| Low | 6 | -| Observation | 9 | -| **Total** | **30** | - -The audit found one dominant theme: the domain has overlapping vocabularies for -the same concept. `App` vs `Application` (`ApplicationStatus`, -`ApplicationStatus_ApplicationState`) collide on the same entity, and three -overlapping "space" vocabularies (`Space`, `AppResourceGenieSpace`, `space` as -a string field on `App`/`ListAppsRequest`) produce outright ambiguity (`Space` -versus Genie Space). The package also re-exports an `ErrorCode` enum with 76 -cross-product values whose relevance to Apps is unclear. - ---- - -## High-severity findings - -### H1. `ApplicationStatus` vs `App` — duplicate top-level "application" concept -- **File:** `model.ts:681, 1014`, also `index.ts:40, 72` -- **Category:** Duplicate concepts (12), Misleading names (6) -- **Issue:** The package's primary entity is `App`, but the runtime state of an - App is modelled by a struct called `ApplicationStatus` (with enum - `ApplicationStatus_ApplicationState`). On `App`, the field is - `appStatus?: ApplicationStatus`, so the type name disagrees with the field - name. There are two parallel vocabularies for the same idea. -- **Suggestion:** Rename `ApplicationStatus` -> `AppStatus`, the nested enum to - `AppStatus.State` (TS namespace) or `AppState`. Aligns with the `App` entity - and with the `appStatus` field. -- **Rationale:** A consumer reading `app.appStatus: ApplicationStatus` has to - prove to themselves that "application" and "app" refer to the same thing. - -### H2. `ErrorCode` (76 values) shipped from a package whose surface is Apps -- **File:** `model.ts:14-512`, also `index.ts:17` -- **Category:** Vague/generic without domain context (1), Duplicate concepts (12) -- **Issue:** The `ErrorCode` enum has 76 values, the majority of which are - Unity Catalog, Repos, Files API, and Workspaces error codes - (`METASTORE_DOES_NOT_EXIST`, `SHARE_DOES_NOT_EXIST`, `IPYNB_FILE_IN_REPO`, - `GIT_SENSITIVE_TOKEN_DETECTED`, `MAX_BLOCK_SIZE_EXCEEDED`, etc.). The vast - majority of values are documented as "Deprecated and kept to maintain - backwards compatibility". The only place this enum is consumed inside the - apps package is `DatabricksServiceExceptionWithDetailsProto.errorCode`, - which is itself only used as the `error` arm of `Operation.result`. -- **Suggestion:** Move `ErrorCode` to a shared core package - (`@databricks/sdk-databricks/apierror/codes`) and re-export it. Each - service-level package should not duplicate the canonical error-code list. -- **Rationale:** The enum is huge, mostly deprecated, semantically global, and - is being inlined into a service-specific package. This is the canonical case - the project's own `apierr/codes` directory was created to avoid. - -### H3. `Operation` — generic name with no domain prefix -- **File:** `model.ts:1267`, also `index.ts:102`, `client.ts:275, 375, 527, 905` -- **Category:** Vague/generic without domain context (1) -- **Issue:** `Operation` is exported as a top-level type. There is no Apps - context in the name; a user importing `Operation` from `@databricks/sdk-apps` - has no way to know what it operates on. The accompanying request type - `GetOperationRequest` is even more generic. From the client, the method that - consumes it is `getSpaceOperation`, which is the only thing it can actually - be used for in this package. -- **Suggestion:** Rename `Operation` -> `SpaceOperation` and - `GetOperationRequest` -> `GetSpaceOperationRequest`. Alternatively, move - both to a shared core package (Google's standard - `google.longrunning.Operation`) so all packages share the type rather than - each redefining it locally. -- **Rationale:** Today every API package will have its own `Operation` type - and they will collide on import. Either a shared canonical type or a - domain-specific rename is required. - -### H4. `oauth2AppIntegrationId` / `oauth2AppClientId` — digit-embedded acronym -- **File:** `model.ts:759-760` -- **Category:** Acronym casing inconsistencies (3) -- **Issue:** The fields use `oauth2` (all-lowercase) embedded with PascalCase. - Google's TS style guide treats this as an acronym; the canonical case is - `oAuth2` for camelCase (or `OAuth2` for PascalCase). The actual specification - capitalises it as "OAuth 2.0". -- **Suggestion:** Rename to `oauth2AppIntegrationId` -> `oAuth2AppIntegrationId` - (or accept the eslint exception for compatibility with the wire field - `oauth2_app_integration_id`). -- **Rationale:** Inconsistent with how the SDK treats other acronyms (e.g. - `Url` in `thumbnailUrl`, `Id` in many fields). - -### H5. `DatabricksServiceExceptionWithDetailsProto` — `Proto` suffix is a wire-format architectural leak -- **File:** `model.ts:1081`, also `index.ts:80`, used at `model.ts:1296` and serialised at `model.ts:1955, 2072`. -- **Category:** Proto-architectural-leak (Proto suffix), Overly verbose (7) -- **Issue:** The public type carries a `Proto` suffix, exposing the - underlying protobuf serialization format in the TS public surface. The - suffix has no meaning to a JS/TS consumer and is purely a leak from the - upstream `.proto` definition. The name is also overly long for what is - effectively the API error envelope. -- **Suggestion:** Rename to `DatabricksServiceException` or, better, drop - this local copy entirely and reuse the canonical error envelope from - `@databricks/sdk-databricks/apierror` (parallels H2, which makes the same - case for `ErrorCode`). -- **Rationale:** Wire-format tokens (`Proto`, `Rpc`, `Grpc`) in public - type names violate the proto-architectural-leak rule. The TS SDK should - not surface implementation-layer artefacts that a hand-written client - would never name this way. +| Medium | 6 | +| Low | 2 | +| Observation | 5 | +| **Total** | **13** | --- ## Medium-severity findings ### M1. `EnvVar` — too short -- **File:** `model.ts:1108`, also `index.ts:85` +- **File:** `model.ts:1116`, also `index.ts:85` - **Category:** Cryptic abbreviations (5) - **Issue:** `EnvVar` reads as Go-style. Full TS conventions prefer `EnvironmentVariable` or, since it carries both name and source, more @@ -124,51 +29,19 @@ cross-product values whose relevance to Apps is unclear. strict 1:1 with Go names, leave as-is. ### M2. `AsyncUpdateAppRequest.appName` carrying a redundant nesting -- **File:** `model.ts:1021-1025` +- **File:** `model.ts:1037-1041` - **Category:** Redundant suffixes (8) - **Issue:** `AsyncUpdateAppRequest` already contains an `app: App` field, and separately an `appName: string` field that's just `req.app.name`. This is - visible at `client.ts:125`: `${this.host}/api/2.0/apps/${req.appName ?? ''}` + visible at `client.ts:127`: `${this.host}/api/2.0/apps/${req.appName ?? ''}` with no consultation of `req.app?.name`. - **Suggestion:** Drop `appName` from `AsyncUpdateAppRequest` and read - `req.app?.name` (as `updateApp` already does at `client.ts:828`). This is a + `req.app?.name` (as `updateApp` already does at `client.ts:902`). This is a semantic change; flag for discussion. Alternative: keep both and document which wins on conflict. -### M3. `UcSecurableType` duplicated across manifest spec and runtime resource -- **File:** `model.ts:586-591, 664-669` -- **Category:** Duplicate concepts (12) -- **Issue:** Two identical enums (`VOLUME`, `TABLE`, `FUNCTION`, `CONNECTION`) - — one for the manifest spec, one for the runtime resource. Same value set, - different declaration. -- **Suggestion:** Consolidate to a single `UcSecurableType` enum and reference - it from both the manifest UC securable spec and the runtime UC securable - resource. - -### M4. UC securable permission enum on the runtime resource is a strict subset of the manifest-spec enum -- **File:** `model.ts:576-583, 654-661` -- **Category:** Duplicate concepts (12) -- **Issue:** Spec enum has 7 values (`READ_VOLUME`, `WRITE_VOLUME`, `MANAGE`, - `SELECT`, `EXECUTE`, `USE_CONNECTION`, `MODIFY`). Resource enum has 6 — same - list minus `MANAGE`. The relationship is undocumented; the duplication is - fragile. -- **Suggestion:** Define one shared `UcSecurablePermission` and, if `MANAGE` - isn't actually grantable at runtime, document that. Or define two related - enums where one is a subset reference (not duplicated). - -### M5. `AppResourceSqlWarehouse.id` vs `App.id`, `Space.id` — `id` overloaded across types -- **File:** `model.ts:756, 946, 975, 1316` -- **Category:** Underspecified IDs (19) -- **Issue:** `AppResourceSqlWarehouse.id` is a SQL warehouse ID, `App.id` is an - App ID, `AppResourceJob.id` is a Job ID, `Space.id` is a Space ID. All are - bare `id`. JSON output serializes the same key for very different - identifiers. -- **Suggestion:** Either accept the convention (`id` always means "the entity - this object describes") or be explicit (`sqlWarehouseId`, `jobId`, - `experimentId`). The package is currently inconsistent in this regard. - -### M6. `UnityCatalog` interface — generic name, no role suffix -- **File:** `model.ts:1383-1390`, also `index.ts:110` +### M3. `UnityCatalog` interface — generic name, no role suffix +- **File:** `model.ts:1391-1398`, also `index.ts:110` - **Category:** Vague/generic (1) - **Issue:** `UnityCatalog` is exported as a public type. The interface has three table-name fields (`logsTable`, `metricsTable`, `tracesTable`) and is @@ -178,11 +51,11 @@ cross-product values whose relevance to Apps is unclear. - **Suggestion:** Rename to `UnityCatalogTelemetryDestination` or `UnityCatalogTables`. Inline if not reused. -### M7. `Operation.result` carries `error` and `response` arms -- **File:** `model.ts:1292-1303` +### M4. `Operation.result` carries `error` and `response` arms +- **File:** `model.ts:1300-1311` - **Category:** Vague/generic (1) - **Issue:** The `response` arm holds `Record` — a totally - untyped payload. The consumer at `client.ts:1010` immediately re-parses it + untyped payload. The consumer at `client.ts:1095` immediately re-parses it through `unmarshalSpaceSchema`. The name `response` and the unknown type conceal what's actually inside. - **Suggestion:** Use generics: `Operation` with `result: ... | @@ -190,8 +63,8 @@ cross-product values whose relevance to Apps is unclear. `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name promises nothing. -### M8. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too -- **File:** `client.ts:121, 902` +### M5. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +- **File:** `client.ts:123, 985` - **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) - **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, long-running operations that return an `AppUpdate`/`Operation` and have a @@ -201,8 +74,8 @@ cross-product values whose relevance to Apps is unclear. - **Suggestion:** Drop the `async` prefix from `asyncUpdateApp` to match `updateSpace`, or add `asyncUpdateSpace` for symmetry. -### M9. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type -- **File:** `client.ts:297, 396, 939` +### M6. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +- **File:** `client.ts:317, 428, 1025` - **Category:** Type-suffix tautology (20) - **Issue:** Methods named `createSpaceOperation()` return a `CreateSpaceOperation` wrapper (not an `Operation` directly). A reader @@ -212,22 +85,12 @@ cross-product values whose relevance to Apps is unclear. `createSpaceAndWait()` or `createSpaceLongRunning()`. The `*Operation` class could be `*LongRunning` (mirroring the `Operation` type's role). -### M10. `gitProvider?: string` — should be enum/union -- **File:** `model.ts:1075-1076, 1163-1166` -- **Category:** Vague/generic (1) -- **Issue:** `CustomTemplate.gitProvider` and `GitRepository.provider` are - free-form strings, but the doc on `GitRepository.provider` enumerates eight - legal values (gitHub, gitHubEnterprise, bitbucketCloud, etc.). The type - should be a string-literal union or enum. -- **Suggestion:** Define `enum GitProvider { GIT_HUB, GIT_HUB_ENTERPRISE, ... }` - or a string-literal union of the documented values. - --- ## Low-severity findings ### L1. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers -- **File:** `model.ts:2939, 3016` +- **File:** `model.ts:2964, 3041` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — no `appDeploymentFieldMask`, despite the `AppDeployment` having an internal @@ -235,39 +98,8 @@ cross-product values whose relevance to Apps is unclear. - **Suggestion:** Either expose helpers for every entity with a field-mask schema, or none. -### L2. `Space` interface — same name as the Genie product `AppResourceGenieSpace` -- **File:** `model.ts:938, 1306` -- **Category:** Duplicate concepts (12) -- **Issue:** `Space` (an Apps Space) and `GenieSpace` (the Genie product) share - the "space" noun and both have a `spaceId` field. They are unrelated - domains. -- **Suggestion:** Rename `Space` -> `AppSpace` everywhere (`AppSpace`, - `CreateAppSpaceRequest`, `UpdateAppSpaceRequest`, `AppSpaceStatus`, etc.). - Many of the comments in this file already say "app space" — the type name - is the outlier. This realignment also clarifies the wire URLs - (`/api/2.0/app-spaces/...`). - -### L3. `CreateSpaceRequest`, `DeleteSpaceRequest`, `GetSpaceRequest`, - `ListSpacesRequest`, etc., do not mention "App" -- **File:** `model.ts:1057, 1103, 1153, 1250`, also `index.ts:78, 84, 91, 100` -- **Category:** Vague/generic (1) -- **Suggestion:** Tied to L2 — rename these to `CreateAppSpaceRequest`, etc. - -### L4. `ListSpacesResponse.spaces` plural is fine, but consistent with `ListAppsResponse.apps`? -- **File:** `model.ts:1232, 1258` -- **Category:** Observation — both follow the same pattern. Tied to L2 again - for the entity rename. - -### L5. `Client` class — exported as bare `Client` -- **File:** `client.ts:95`, also `index.ts:4` -- **Category:** Vague/generic (1) -- **Issue:** `import {Client} from '@databricks/sdk-apps/v1'`. Reads as "the - Client" with no domain. If a consumer also imports `Client` from - `@databricks/sdk-jobs`, they need an alias. -- **Suggestion:** Rename to `AppsClient`. Common SDK convention. - -### L6. `getSpaceOperation` (method) vs `GetOperationRequest` -- **File:** `client.ts:524-546` +### L2. `getSpaceOperation` (method) vs `GetOperationRequest` +- **File:** `client.ts:571-596` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells you it's a space operation, but the request type doesn't. Mismatch. @@ -279,12 +111,7 @@ cross-product values whose relevance to Apps is unclear. ## Observations (not necessarily problems) -### O1. `App` is the primary noun; `Application*` only appears where state is concerned -This is the cleanest distinction in the package: the entity is `App` (URL, -field name `app`), and the runtime metadata is `Application*`. Resolving H1 -fixes the inconsistency. - -### O2. `Operation` lifecycle wrappers come in two flavours: `*Operation` and `*Waiter` +### O1. `Operation` lifecycle wrappers come in two flavours: `*Operation` and `*Waiter` - `CreateSpaceOperation`, `DeleteSpaceOperation`, `UpdateSpaceOperation` — driven by `google.longrunning.Operation` (poll a separate endpoint). - `AsyncUpdateAppWaiter`, `CreateAppDeploymentWaiter`, `CreateAppWaiter`, @@ -294,74 +121,25 @@ The two flavours are confusing as named. Consider renaming `*Operation` -> `*LongRunning` so the difference (LRO vs status-poll) is visible. -### O3. Field-mask helpers exist for `App` and `Space` only +### O2. Field-mask helpers exist for `App` and `Space` only `appFieldMask()` and `spaceFieldMask()` are exported; equivalents for `AppDeployment` etc. are not. Probably intentional (only `App` and `Space` have an update endpoint that takes a mask), but worth confirming. -### O4. Discriminated unions use `$case` — borrowed from `ts-proto` oneof -The `$case` discriminator is non-idiomatic in hand-written TS (most consumers -use plain `kind: 'X'`). Documenting this in the package README would help. - -### O5. `CustomTemplate` doesn't carry "App" in its name, but it's an app template +### O3. `CustomTemplate` doesn't carry "App" in its name, but it's an app template The doc and methods make this clear (`createCustomTemplate` -> `/api/2.0/apps-settings/templates`), but the type name is ambiguous. Consider `AppTemplate` or `CustomAppTemplate`. -### O6. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter +### O4. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter Asymmetry but probably intentional. -### O7. `ListAppsRequest.space` filters by space name (string), not by -`Space` object — observation tied to the ambiguity between the bare `space` -field type and the `Space` interface. - -### O8. The package re-exports the `apierr` enum locally -Per H2, this enum should live in `@databricks/sdk-databricks/apierror/codes`. -The project memory note already calls this out -(`packages/databricks/src/apierror/codes/`). +### O5. `index.ts` exports +- 27 enums +- 69 type aliases +- 9 named exports from `./client` (1 class + 8 wrapper classes) -### O9. `index.ts` exports -- 26 enums -- 71 type aliases -- 8 named exports from `./client` (1 class + 7 wrapper classes) - -That's 105 top-level exports. Worth checking whether the wrapper classes +That's 105 top-level exports, plus the two field-mask helper functions +(`appFieldMask`, `spaceFieldMask`). Worth checking whether the wrapper classes (`*Operation`, `*Waiter`) need to be public or if they're implementation detail. - ---- - -## Domain glossary - -| Term in code | What it actually means | Notes | -| ------------ | ---------------------- | ----- | -| `App` | A Databricks App (interactive application instance) | Primary entity. | -| `Application` | Runtime view of an App's process/server | Only used in `ApplicationStatus*`. See H1. | -| `AppDeployment` | A specific deployment (source-code + config snapshot) | Has its own `id`, status, lifecycle. | -| `AppManifest` | Schema describing required resources for an app | Used by `CustomTemplate`. | -| `AppResource` | A binding from an App to another Databricks resource | Discriminated union of 10 cases. | -| `Space` (`AppSpace`) | A workspace-scoped grouping of Apps | Recommended rename: `AppSpace`. See L2. | -| `GenieSpace` | Databricks Genie product — *unrelated* to App Spaces | Confusion source; see L2. | -| `CustomTemplate` | An installable app template stored in Git | Lives under `/api/2.0/apps-settings/`. | -| `Operation` | google.longrunning.Operation for Space CRUD | Only used by Space operations. See H3. | -| `Waiter` | Locally-driven status poller for App/Deployment lifecycle | Distinct from `Operation`. See O2. | -| `UcSecurable` | A Unity Catalog securable (table/volume/function/connection) | Two duplicate enums. See M3/M4. | -| `Thumbnail` | An app's display image (bytes) plus its URL | Two fields, two concepts. | -| `EnvVar` | Environment variable for the deployed app process | Short for "EnvironmentVariable". See M1. | -| `GitRepository` | Repository configuration (URL + provider + credentials) | Top-level Git config on App. | -| `GitSource` | Specific commit/branch/tag + path within a `GitRepository` | Used by deployments. | - ---- - -## File coverage - -| File | Lines read | Coverage | -| ---- | ---------- | -------- | -| `src/v1/index.ts` | 116 / 116 | 100% | -| `src/v1/utils.ts` | 151 / 151 | 100% | -| `src/v1/model.ts` | 3023 / 3023 | 100% | -| `src/v1/client.ts` | 1602 / 1602 | 100% | - -All types, fields, enum values, and methods reviewed. - ---- diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index a39903cf..fe0a34ea 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -4,29 +4,14 @@ Package path: `/home/parth.bansal/sdk-js/packages/artifactallowlists/` Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/transport.ts`, `src/v1/index.ts`. -Notation: file paths are absolute. Findings reference `file:line`. - ## Summary | Severity | Count | | ----------- | ----- | | High | 1 | -| Medium | 3 | -| Low | 0 | -| Observation | 2 | -| **Total** | **6** | - -Headline themes: - -1. **Redundant `Info` suffix on `ArtifactAllowlistInfo`** is the canonical - payload type for both `Get` and `Set` responses; the suffix adds no - information beyond "this is a struct." -2. **Server-derived fields leak onto a request type** — - `SetArtifactAllowlistRequest` exposes `createdBy` / `createdAt`, which are - response-only metadata. - -Allowlist casing is **consistent** throughout the package (always -`Allowlist`, never `AllowList` or `Whitelist`). +| Medium | 2 | +| Observation | 1 | +| **Total** | **4** | --- @@ -34,9 +19,10 @@ Allowlist casing is **consistent** throughout the package (always ### H1. `SetArtifactAllowlistRequest` carries server-derived fields on a request type -- **File / line:** `src/v1/model.ts:44–55`. +- **File / line:** `src/v1/model.ts:44–55` (`createdBy` at 52, `createdAt` + at 54). - **Category:** #16 field contradicting type domain. -- **Current:** Fields `createdBy?: string` and `createdAt?: number` are +- **Current:** Fields `createdBy?: string` and `createdAt?: bigint` are present on what is documented as the SET payload — these are server-set timestamps/identities and are also present on `ArtifactAllowlistInfo`. - **Suggestion:** Remove `createdBy` / `createdAt` from @@ -66,22 +52,7 @@ Allowlist casing is **consistent** throughout the package (always (today, the package has no type with that bare name, even though it is literally the "artifact allowlists" package). -### M2. `GetArtifactAllowlistRequest` / `SetArtifactAllowlistRequest` use inconsistent -verbs vs. UC sibling APIs - -- **File / line:** `src/v1/model.ts:39, 44`; `client.ts:66, 96`. -- **Category:** #17 inconsistent action verbs. -- **Current:** `Get…` + `Set…`. -- **Suggestion:** Confirm whether `Set` is intentional vs. `Update`. The Unity - Catalog REST API frequently uses `PUT` semantics with `Update…` verbs (see - `catalogs`, `connections`, `externallocations`, `storagecredentials`). -- **Rationale:** The HTTP method here is `PUT` (`client.ts:106`) and the - docstring says "The whole artifact allowlist is replaced with the new - allowlist" — a replace semantic. UC peers typically expose this as - `update…`. If the API spec dictates `Set`, this is correct; the audit - flags it because the verb is unique within UC. - -### M3. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak +### M2. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak - **File / line:** `src/v1/model.ts:15`. - **Category:** proto-architectural-leak — `Proto` infix / nested-enum @@ -100,12 +71,6 @@ verbs vs. UC sibling APIs --- -## Low Severity - -_None._ - ---- - ## Observations (Repo-wide conventions, not local defects) ### O1. `…Info` suffix repeated across UC types @@ -113,52 +78,3 @@ _None._ `ArtifactAllowlistInfo` follows the `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the codebase decides to drop the `Info` suffix, this is one of many to fix. - -### O2. Allowlist terminology / casing is consistent - -`Allowlist` (single uppercase A, then lowercase `llowlist`) is used in -every position in this package: type names, methods, schemas, comments, -URL paths (`/artifact-allowlists/`), and the package name -`@databricks/sdk-artifactallowlists`. No `AllowList`, `Allow_list`, or -`Whitelist` anywhere. **Passes** the audit on this criterion. - ---- - -## Domain glossary - -| Term | Meaning in this package | -| -------------------------- | ---------------------------------------------------------- | -| Artifact | A user-supplied resource (init script / jar / maven coord) installed onto a cluster. | -| Artifact type | One of `INIT_SCRIPT`, `LIBRARY_JAR`, `LIBRARY_MAVEN` — the kind of artifact being allowed. | -| Allowlist | Per-metastore list of artifacts permitted to run. Replaces the older "whitelist" terminology. | -| ArtifactMatcher | One rule entry on the allowlist: an `(artifact, matchType)` pair. | -| MatchType / MATCH_TYPE | How the matcher compares the candidate artifact to the stored pattern. Today only `PREFIX_MATCH`; spec reserves room for `EXACT_MATCH`, `WILDCARDS`. | -| Metastore | Unity Catalog top-level container the allowlist is scoped to. | -| Set / PUT | Replace-the-whole-allowlist semantic. Not an additive update. | - ---- - -## File coverage - -| File | Lines | Audited | -| -------------- | ----- | ------------------------------------------------ | -| `src/v1/model.ts` | 111 | All 4 types + 2 enums + 3 schemas + every field. | -| `src/v1/client.ts` | 121 | Class, constructor, 2 methods, all locals. | -| `src/v1/utils.ts` | 151 | All 7 exported / private functions and types. | -| `src/v1/transport.ts` | 76 | `newHttpClient` factory + 2 wrapper classes. | -| `src/v1/index.ts` | 13 | All re-exports. | - -Type & symbol checklist: - -- [x] `ArtifactType` enum (4 members) → no defect. -- [x] `ArtifactMatcher_MatchType` enum (2 members) → M3. -- [x] `ArtifactAllowlistInfo` interface (4 fields) → M1, O1. -- [x] `ArtifactMatcher` interface (2 fields) → no defect. -- [x] `GetArtifactAllowlistRequest` interface (1 field) → no defect. -- [x] `SetArtifactAllowlistRequest` interface (5 fields) → H1. -- [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `getArtifactAllowlist(req, options)` method → M2. -- [x] `setArtifactAllowlist(req, options)` method → M2. -- [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). - ---- diff --git a/.agent/naming-audit/authentication.md b/.agent/naming-audit/authentication.md index c3aeb7ce..ce802d87 100644 --- a/.agent/naming-audit/authentication.md +++ b/.agent/naming-audit/authentication.md @@ -3,36 +3,20 @@ **Path:** `packages/authentication/src/v1/` **Versions audited:** v1 **Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` -**Inferred domain:** Account-level CRUD over OAuth client secrets attached to -a service principal (create, list, delete). The previous -`serviceprincipalsecretsproxy` package was merged in, so both the -non-proxy and proxy RPC variants now live under one client. -**Total weird names flagged:** 4 +**Total weird names flagged:** 1 ## Summary table | Severity | Count | | --- | --- | | High | 1 | -| Medium | 3 | -| Low | 0 | -| Observation | 0 | -| **Total** | **4** | - -The audit is narrowly scoped to proto/architectural leaks. The -package exposes only one resource (`ServicePrincipalSecret`), so the -findings cluster around two themes: (1) a duplicate -`` / `Proxy` API surface that mirrors the proto's -proxy-vs-non-proxy RPC routing distinction, and (2) the proto -`Request_Response` underscore-nested message name leaking into TS as -the empty `DeleteServicePrincipalSecretRequest_Response` and the -populated `ListServicePrincipalSecretsRequest_Response`. +| **Total** | **1** | --- ## High severity (must fix) -### 1. `*Proxy` method variants duplicate the entire API surface — `client.ts:491, 551, 633, 669` +### 1. `*Proxy` method variants duplicate the entire API surface — `client.ts:488, 548, 630, 666` - **Why:** The class exposes three real operations (`createServicePrincipalSecret`, `deleteServicePrincipalSecret`, `listServicePrincipalSecrets`) and, for every one of them, a @@ -55,92 +39,3 @@ populated `ListServicePrincipalSecretsRequest_Response`. the duplicate on the public client doubles autocomplete clutter for a three-operation surface and forces every consumer to pick between two methods that do the same thing. - ---- - -## Medium severity (worth pushing back on) - -### 1. `DeleteServicePrincipalSecretRequest_Response` — proto-style `Request_Response` nesting on the public type — `model.ts:90` -- **Why:** The empty interface - `DeleteServicePrincipalSecretRequest_Response` is exported (and - re-exported from `index.ts:15`) using the proto-nested - `_` underscore convention. It is the only place in - the TS surface where a delete operation returns a nested empty - message; the underscore identifier exists purely because the proto - schema modelled the response as a nested message inside the request - type. -- **Category:** Proto-architecture leak (`Request_Response` infix - underscore from proto nesting) -- **Suggested:** Either drop the empty response type and have - `deleteServicePrincipalSecret` return `Promise`, or expose - the type as `DeleteServicePrincipalSecretResponse` (sibling-cased, - no underscore) for symmetry with - `CreateServicePrincipalSecretResponse`. -- **Rationale:** No consumer writes a value of this type — the body - is empty. The underscored identifier requires an eslint disable - comment to compile and forces callers reading types to learn proto - message-nesting rules. - -### 2. `ListServicePrincipalSecretsRequest_Response` — proto-style `Request_Response` nesting on the public type — `model.ts:173` -- **Why:** Same shape as finding M1: the response is exported through - `index.ts:23` as `ListServicePrincipalSecretsRequest_Response` - because the proto schema modelled it as a nested message inside the - request. Unlike M1, this one carries fields (`secrets`, - `nextPageToken`) and is actually consumed, so the underscore name - is visible at every call site. -- **Category:** Proto-architecture leak (`Request_Response` infix - underscore from proto nesting) -- **Suggested:** Rename to `ListServicePrincipalSecretsResponse` to - match the existing `CreateServicePrincipalSecretResponse` - convention used in the same file. -- **Rationale:** The sibling `CreateServicePrincipalSecretResponse` - is already named with the unnested form, so the package is - internally inconsistent: of three operations, only `create` gets a - clean response name. Aligning the two list/delete responses - removes the eslint disable and makes the type discoverable without - understanding the proto layout. - -### 3. `Client` methods returning the underscored response types — `client.ts:526, 554, 582, 636` -- **Why:** Four public method signatures bake the proto-nested - `*Request_Response` identifier into their return types - (`Promise`, - `Promise`). The - underscore identifier propagates from `model.ts` into the client - contract and surfaces in hover tooltips and generated docs for - every method. -- **Category:** Proto-architecture leak (`Request_Response` infix - underscore from proto nesting) -- **Suggested:** Resolves automatically once the underlying types - are renamed per medium findings M1 and M2. -- **Rationale:** The leak is observable on the most public surface - (method signatures), not just an internal type alias. - ---- - -## Low severity (nits) - -_None._ - ---- - -## Observations (not flags) - -_None._ - ---- - -## File coverage - -| File | Lines read | Coverage | -| ---- | ---------- | -------- | -| `src/v1/index.ts` | 28 / 28 | 100% | -| `src/v1/transport.ts` | 75 / 75 | 100% | -| `src/v1/utils.ts` | 150 / 150 | 100% | -| `src/v1/model.ts` | 502 / 502 | 100% | -| `src/v1/client.ts` | 688 / 688 | 100% | - -All types, fields, and methods reviewed for proto-architectural leaks -(`Proxy` suffix; `Request_Response` proto-nested underscore -identifiers). Standard suffixes at end (e.g. `*Request`, `*Response`, -`*Schema`), real-domain prefixes (e.g. `ServicePrincipal*`), and -`OAuth*` lexicon are not flagged. diff --git a/.agent/naming-audit/billableusagedownload.md b/.agent/naming-audit/billableusagedownload.md deleted file mode 100644 index b8a21971..00000000 --- a/.agent/naming-audit/billableusagedownload.md +++ /dev/null @@ -1,85 +0,0 @@ -# Naming Audit: billableusagedownload - -**Path:** `packages/billableusagedownload/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Account-level CSV export of billable Databricks usage logs for a given month range. Single endpoint: `GET /api/2.0/accounts/{account_id}/usage/download`. No CRUD surface, no enums, no list/page semantics — just one streaming download method. -**Total weird names flagged:** 8 - -## Summary -| Severity | Count | -| --- | --- | -| High | 4 | -| Medium | 3 | -| Low | 0 | -| Observation | 1 | - -## High severity - -### 1. Package name `billableusagedownload` embeds an action verb — `packages/billableusagedownload/` -- **Why weird:** Package names should be domain nouns (`billing`, `usage`, `accounts`). `billableusagedownload` is `noun+noun+verb` — the only verb-suffixed package in the workspace (compare `usagedashboards`, `usagepolicy`, `budgets`, `accountsettings`). The `download` verb belongs on the method, not the package. Users discovering the SDK would naturally search for "billing" or "usage", not for "billableusagedownload". -- **Category:** 7 (overly verbose), 14 (Go/proto-style names — this is almost certainly the protobuf package), 17 (inconsistent action-verb conventions vs sibling packages). -- **Suggested name:** Fold into a `billing` package alongside `usagedashboards` (most idiomatic), or rename to `billableusage` (drop the verb). The single method `Client.download()` then carries the action. -- **Rationale:** The Databricks REST API path is `/usage/download`, but the SDK shouldn't reproduce URL path segments as package names. The sibling `usagedashboards` package handles a closely related concern; the two should likely co-exist as one `billing` namespace. Worth raising at SDK-generator level. - -### 2. `DownloadRequest` — `src/v1/model.ts:3` -- **Why weird:** Type name is action-shaped (verb-prefixed), and the verb is generic. "Download" alone says nothing about what is being downloaded. Collides with `DownloadRequest` in `packages/files/src/v1/model.ts:?` — a user importing both packages must alias one (`import type {DownloadRequest as BillingDownloadRequest}`). Same collision applies to `DownloadResponse` (finding #3). -- **Category:** 1 (vague without domain context), 12 (duplicate concept across packages — `files` has the same names for unrelated payloads). -- **Suggested name:** `DownloadBillableUsageRequest` (matches the Go SDK message-name convention) or `DownloadUsageRequest`. -- **Rationale:** The collision with `files.DownloadRequest` is the killer here — they have completely different fields (`accountId`/`startMonth`/`endMonth`/`personalData` vs `filePath`) and one is `application/octet-stream` CSV while the other is binary file bytes. A user re-exporting both packages from an app barrel file gets a TS error or silently shadowed types. Renaming makes both imports safe. - -### 3. `DownloadResponse` — `src/v1/model.ts:30` -- **Why weird:** Same problems as #2: vague verb-shaped name, collides with `files.DownloadResponse`. Both packages use `contents: ReadableStream` as the sole field — the type shape is structurally identical but semantically distinct (CSV blob vs file bytes), which means TS structural typing will *not* catch a mix-up. -- **Category:** 1, 12, 6 (structurally identical to unrelated `files.DownloadResponse`, creates misleading shape match). -- **Suggested name:** `DownloadBillableUsageResponse`. -- **Rationale:** A `Promise` collides directly with the file-download response of the same name. Renaming disambiguates the two unrelated payloads and prevents the structural-typing trap. - -### 4. `DownloadRequest.startMonth` / `endMonth` are misleadingly optional — `src/v1/model.ts:15,20` -- **Why weird:** Both fields are typed `string | undefined`, but the JSDoc explicitly says `endMonth` "This field is required." — and `startMonth` is required in practice (the API would fail without it). The optionality contradicts the doc. -- **Category:** 6 (misleading — TS type says optional, doc says required), 16 (field type contradicts domain reality). -- **Suggested name:** Keep the field names; change the types to `string` (required) on both. Worth also renaming `startMonth`/`endMonth` to something more self-documenting like `fromMonth`/`toMonth` or `startMonth`/`untilMonth` — current names are fine. -- **Rationale:** TS strict mode rewards required fields with non-optional types; the doc and the type should agree. The Go SDK probably models these as `string` (empty-string defaults), which is a Go-ism; in TS, required strings should not carry `| undefined`. - -## Medium severity - -### 5. `DownloadRequest.accountId` field — `src/v1/model.ts:8` -- **Why weird:** The `accountId` lives on the request DTO *and* on `ClientOptions` (see `client.ts:39`). The client falls back from `req.accountId` to `this.accountId` (`client.ts:69`). Having the same identifier in two places, with one-overrides-the-other semantics, is a footgun: callers may set it once on the client and forget that a stale request value silently shadows it. -- **Category:** 12 (duplicate concept across types), 19 (underspecified id — same `accountId` means different things at different layers). -- **Suggested name:** Drop `accountId` from `DownloadRequest`. Make it a client-level concern only (it's a path parameter, not a body field). If per-call override is needed, document it explicitly. -- **Rationale:** The JSDoc on the field is a verbose explanation about getting your account ID from the console — content that belongs in `ClientOptions.accountId`, not duplicated per request. Removing it simplifies the API surface and eliminates the fallback chain in `client.ts`. - -### 6. `Client` class is unprefixed — `src/v1/client.ts:22` -- **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-billableusagedownload/v1'`, then has to rename it (`import {Client as BillableUsageClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Consistent across the SDK but worth flagging. -- **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). -- **Suggested name:** `BillableUsageDownloadClient` or `BillableUsageClient`. Or expose a namespace export instead of a bare class. -- **Rationale:** Cross-SDK consistency may justify keeping `Client`, but in practice every user re-aliases. The SDK could expose `import * as billableUsage from '@databricks/sdk-billableusagedownload/v1'` and remove the `Client` symbol entirely, letting `billableUsage.Client` be the qualified name. - -### 7. `Client.download` method name — `src/v1/client.ts:65` -- **Why weird:** A bare `download` verb on the client. Outside the package context, `client.download(...)` reads as "download something" — the package name is the disambiguator. If a user composes multiple SDK clients (`billing.download()`, `files.download()`), the method names collide cognitively. Compare with `usagedashboards.Client` which probably exposes `createBillingUsageDashboard()` / `getBillingUsageDashboard()` — verb + domain noun. -- **Category:** 1 (vague), 17 (inconsistent verb-pattern across sibling packages). -- **Suggested name:** `downloadBillableUsage` (matches the request-type rename) or, if the package gets folded into `billing`, `downloadUsage`. -- **Rationale:** Domain-qualified method names read better when imported into application code. Even within the package, `billableUsageDownloadClient.download()` has a pleasing redundancy that a single naked `download()` does not. - -## Low severity - -_None._ - -## Observations - -### 8. Field type `ReadableStream` is un-parameterised — `src/v1/model.ts:31` -The field is typed `ReadableStream` (no type parameter) rather than `ReadableStream`. Every other use in the codebase (`packages/files/src/v1/model.ts`, `utils.ts:42`, `utils.ts:101`) uses `ReadableStream` explicitly. The unparameterised version is the global lib type which is structurally `ReadableStream`, weakening type safety for callers. -- **Category:** 6 (misleading — type appears typed but is in fact `any`-typed), 17 (inconsistent across the SDK). -- **Suggested name:** `contents?: ReadableStream | undefined`. - -## Domain glossary -- `DBU` — Databricks Unit; standard billing unit for Databricks compute. Notably absent from this package's types and JSDoc — no DBU-related fields surface here despite the package being about billable usage. (User-mentioned in the task; verified via grep that the literal "DBU" never appears.) -- `PII` — Personally Identifiable Information. Surfaced indirectly as the `personalData` field flag. -- `E2` — Databricks deployment architecture. Mentioned in the JSDoc for `accountId` ("For non-E2 account types, get your account ID from the Accounts Console..."). -- `account ID` — Databricks account identifier. Surfaces as both `ClientOptions.accountId` and `DownloadRequest.accountId` (with fallback semantics — see finding #5). -- `CSV` — Comma-Separated Values, the wire format of the download body. Documented in JSDoc, not in types. -- `usage logs` — The actual data being downloaded (billable usage records). Not a type/field; only appears in JSDoc. - -## File coverage -- `src/v1/model.ts` (33 lines): read fully. -- `src/v1/client.ts` (103 lines): read fully. -- `src/v1/utils.ts` (186 lines): read fully. -- `src/v1/index.ts` (8 lines): read fully. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index ab6918ce..7cd3bd19 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -2,85 +2,32 @@ **Path:** `packages/budgetpolicy/src/v1/` **Versions audited:** v1 -**Inferred domain:** Account-level "Budget Policy" management — create/get/list/update/delete cost-control policies that attach custom tags to billing usage and can be bound to specific workspaces. Distinct from the sibling `budgets` package, which manages spend-alert configurations. -**Total weird names flagged:** 7 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | -| High | 2 | -| Medium | 3 | -| Low | 0 | -| Observation | 2 | +| High | 1 | +| Medium | 2 | ## High severity ### 1. `Filter` (bare top-level type) — `src/v1/model.ts:75` -- **Why weird:** Re-exported from `index.ts` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (Array#filter, RxJS filter, content filters, etc.) and the type is package-scoped — but the re-export under this name collides with the same bare `Filter` in `packages/usagepolicy/src/v1/model.ts:81` and any user who imports both with `Filter` will hit a name clash. -- **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). +- **Why weird:** Re-exported from `index.ts` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (Array#filter, RxJS filter, content filters, etc.) and the type is package-scoped, so the name carries no hint of what it filters. +- **Category:** 1 (vague/generic). - **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). -- **Rationale:** A bare `Filter` provides zero discoverability and the package directly forces a collision with `usagepolicy.Filter`. Both packages target the same account-level surface and a consumer will frequently import both. - -### 2. Type-name collision with `budgets` package — `src/v1/model.ts:14` vs `packages/budgets/src/v1/model.ts:50` -- **Why weird:** This package's central entity is `BudgetPolicy`; the sibling `budgets` package exports `BudgetConfiguration` (the spend-alert budget object). The two are semantically unrelated — `BudgetPolicy` is a tag-attachment policy that influences cost attribution, and `BudgetConfiguration` is a spend threshold + alert. A user importing both packages sees `BudgetPolicy` and `BudgetConfiguration` side by side and may reasonably wonder if `BudgetPolicy` is the policy *for* a `BudgetConfiguration`. The names do not differentiate clearly. -- **Category:** 12 (duplicate concepts with confusing names), 1 (the `Budget` prefix overloads two unrelated domain ideas). -- **Suggested name:** Consider `CostAttributionPolicy` or `UsageTaggingPolicy` for what `budgetpolicy` actually models (per the JSDoc on `BudgetPolicy`: "Contains the BudgetPolicy details" — tags + workspace bindings, no spend or threshold concept anywhere). -- **Rationale:** The package name is misleading: there is no "budget" (numeric monetary threshold) anywhere in the `budgetpolicy` model. The closest concept is `customTags`. Naming convergence with `budgets` (real spend budgets) drives the confusion. Worth raising with API designers, since the SDK name follows the API name. +- **Rationale:** A bare `Filter` provides zero discoverability. The sibling `budgets` package solves the same problem by exporting `BudgetConfigurationFilter`; this package should follow the same convention so the import surface is self-describing. ## Medium severity -### 3. `Filter.creatorUserId: number` representation — `src/v1/model.ts:85` -- **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers (this SDK uses `number` for `bindingWorkspaceIds` too — line 30). JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. -- **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified id). -- **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Worth flagging as a generator/policy issue. Same problem for `BudgetPolicy.bindingWorkspaceIds: number[]` on line 30 and `Filter.creatorUserId` here. - -### 4. `SortSpec` type — `src/v1/model.ts:147` +### 1. `SortSpec` type — `src/v1/model.ts:147` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. - **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. -### 5. `SortSpec_Field` enum name — `src/v1/model.ts:6` +### 2. `SortSpec_Field` enum name — `src/v1/model.ts:6` - **Why weird:** Proto-architectural-leak: the underscore-joined `ParentType_NestedType` form is the protobuf/Go-SDK convention for emitting nested enum types into a flat namespace. TS already supports namespaces and modules natively, so the underscore is a wire-protocol artifact bleeding into the public TS API. The eslint-disable comment on the prior line even labels it "Proto-style nested enum name", confirming the generator knows it is non-idiomatic. - **Category:** Proto-architectural leak (proto-style nested-type encoding leaking into TS identifiers). - **Suggested name:** `SortField` (drop the `Spec_` prefix entirely; the enum stands on its own as the set of sortable fields) or `SortSpecField` (camel-join, no underscore). - **Rationale:** TS consumers should not need to learn that `SortSpec.field`'s enum lives under a underscored sibling type. The proto nesting is invisible at the wire level — only the generator emits the `_`. - -## Low severity - -_None._ - -## Observations - -### 6. `Client` class plain name — `src/v1/client.ts:46` -Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-budgetpolicy/v1`, they will likely alias it (`import {Client as BudgetPolicyClient}`) to avoid collision with `Client` from every other package. -- **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages). -- **Suggested name:** `BudgetPolicyClient`. -- **Rationale:** Each generated package emits a `Client`. Forcing aliasing on every import is a usability cost. Generator-wide; not specific to this package. - -### 7. Package name `budgetpolicy` overlaps with `budgets` and `usagepolicy` -Three sibling packages exist with related-sounding names: -- `budgetpolicy` — tag attribution policy (this package). -- `budgets` — spend-alert budget configurations. -- `usagepolicy` — has the identical model shape (`UsagePolicy`, `CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`) — i.e. it's a duplicate API surface with a different entity name. - -The three together blur the boundary between "policy that classifies usage" (budgetpolicy/usagepolicy) and "budget with alert thresholds" (budgets). The names themselves do not disambiguate which is which. -- **Category:** 12 (duplicate concept), 1 (vague package names). -- **Rationale:** Worth raising at the SDK / API design level. From the TS-user perspective, three near-clones makes the import surface confusing. - -## Domain glossary -- `budget policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. **Despite the name, it has no monetary "budget" semantics.** Compare with `budgets` package (real spend alerts). -- `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `BudgetPolicy.bindingWorkspaceIds: number[]`. -- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result`. -- `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.0/accounts/{accountId}/budget-policies`). -- `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. -- `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`); only used for `FieldMask` here. -- `ListServerlessPolicies` — Phantom name appearing only in `ListBudgetPoliciesRequest.pageToken` JSDoc; no such RPC exists. Likely a Go-SDK copy/paste. - -## File coverage -- `src/v1/model.ts` (266 lines): read fully. -- `src/v1/client.ts` (252 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (20 lines): read fully. -- Cross-referenced: `packages/budgets/src/v1/model.ts`, `packages/budgets/src/v1/index.ts`, `packages/usagepolicy/src/v1/index.ts` for sibling-package overlap. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 4b68f768..3008744d 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -8,49 +8,6 @@ - `src/v1/client.ts` - `src/v1/index.ts` -This audit applies the 20 numbered concern categories from the audit -checklist. Each finding lists the offending identifier(s), the -category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete -rename suggestion. Findings are grouped by category. - ---- - -## Inventory - -### Enums (`model.ts`) - -| Name | Members | -| --------------------------------------- | ------- | -| `ActionConfigurationType` | `EMAIL_NOTIFICATION` | -| `AlertConfigurationQuantityType` | `LIST_PRICE_DOLLARS_USD` | -| `AlertConfigurationTimePeriod` | `MONTH` | -| `AlertConfigurationTriggerType` | `CUMULATIVE_SPENDING_EXCEEDED` | -| `BudgetConfigurationFilter_Operator` | `IN` | - -### Interfaces (`model.ts`) - -`ActionConfiguration`, `AlertConfiguration`, `BudgetConfiguration`, -`BudgetConfigurationFilter`, `BudgetConfigurationFilter_Clause`, -`BudgetConfigurationFilter_TagClause`, -`BudgetConfigurationFilter_WorkspaceIdClause`, -`CreateBudgetConfigurationBudget`, `CreateBudgetConfigurationRequest`, -`CreateBudgetConfigurationRequest_Response`, -`DeleteBudgetConfigurationRequest`, -`DeleteBudgetConfigurationRequest_Response`, -`GetBudgetConfigurationRequest`, -`GetBudgetConfigurationRequest_Response`, -`ListBudgetConfigurationsRequest`, -`ListBudgetConfigurationsRequest_Response`, -`UpdateBudgetConfigurationBudget`, -`UpdateBudgetConfigurationRequest`, -`UpdateBudgetConfigurationRequest_Response`. - -### Client methods (`client.ts`) - -`createBudgetConfiguration`, `deleteBudgetConfiguration`, -`getBudgetConfiguration`, `listBudgetConfigurations`, -`listBudgetConfigurationsIter`, `updateBudgetConfiguration`. - --- ## Findings @@ -58,7 +15,7 @@ rename suggestion. Findings are grouped by category. ### 1. Vague / generic names #### F1.1 — `ActionConfiguration` / `actionConfigurationId` / `actionType` (HIGH) -- **Where:** `model.ts:26-33`, `index.ts:14`. +- **Where:** `model.ts:27-34`, `index.ts:14`. - **Why flagged:** "Action" is one of the most generic nouns in software. Combined with "Configuration", it gives almost no clue about what the user is configuring. In context this type is @@ -69,23 +26,12 @@ rename suggestion. Findings are grouped by category. delivery method. - **Suggestion:** Rename to `BudgetAlertAction` (or `BudgetNotificationAction`). The `Configuration` suffix is dead - weight here (see also F7). If the type *must* keep the "Config" + weight here (see also F3). If the type *must* keep the "Config" word, `BudgetAlertActionConfig` is shorter and clearer. -#### F1.2 — `Client` class name (MEDIUM) -- **Where:** `client.ts:49`, `index.ts:3`. -- **Why flagged:** Every package in this SDK exports a `Client`. - Re-exported in a barrel like - `import {Client as BudgetsClient} from '@databricks/sdk-budgets'` - it is fine, but unqualified `Client` symbol-shadows aggressively. - This is a project-wide pattern, not a budgets-specific issue. -- **Suggestion:** Either keep `Client` and document the - package-qualified import convention, or rename to - `BudgetsClient` consistently across packages. Cross-cutting. - -#### F1.3 — `req` parameter name on every client method (LOW) -- **Where:** `client.ts:80, 112, 140, 174, 216, 234`. -- **Why flagged:** `req` is a Go-ism (see category 14). It is also +#### F1.2 — `req` parameter name on every client method (LOW) +- **Where:** `client.ts:77, 109, 137, 171, 213, 231`. +- **Why flagged:** `req` is a Go-ism (see category 4). It is also generic — a reader has to look at the type to know what the request is. - **Suggestion:** Use a domain-meaningful parameter name: @@ -94,57 +40,33 @@ rename suggestion. Findings are grouped by category. --- -### 2. Redundant enum prefixes - -_None._ - ---- - -### 3. Acronym casing inconsistencies +### 2. Cryptic abbreviations -_None._ - ---- - -### 4. Underscores in TS identifiers - -_None._ - ---- - -### 5. Cryptic abbreviations - -#### F5.1 — `req` (LOW, Go-ism) +#### F2.1 — `req` (LOW, Go-ism) - **Where:** `client.ts` every method. -- Already flagged under F1.3. +- Already flagged under F1.2. --- -### 6. Misleading names - -_None._ - ---- +### 3. Overly verbose -### 7. Overly verbose - -#### F7.1 — `BudgetConfiguration` (HIGH) -- **Where:** `model.ts:50`. +#### F3.1 — `BudgetConfiguration` (HIGH) +- **Where:** `model.ts:51`. - **Why flagged:** Within a package literally named `budgets`, every type is about budgets. The "Configuration" suffix doesn't add signal — a budget IS a configuration on the account. Compare Go's `budgets.Budget` (typical Go SDK convention). - **Suggestion:** Rename to `Budget`. Users would write `import {Budget} from '@databricks/sdk-budgets'`. The - package name carries the qualifier. Combined with F7.2 / F7.3 - this collapses naming significantly. + package name carries the qualifier. Combined with F3.2 this + collapses naming significantly. -#### F7.2 — `CreateBudgetConfigurationRequest`, +#### F3.2 — `CreateBudgetConfigurationRequest`, `GetBudgetConfigurationRequest`, `UpdateBudgetConfigurationRequest`, `DeleteBudgetConfigurationRequest`, `ListBudgetConfigurationsRequest` (HIGH) -- **Where:** `model.ts:118, 133, 143, 156, 195`; `index.ts:22-31`. +- **Where:** `model.ts:119, 143, 193, 133, 155`; `index.ts:22-31`. - **Why flagged:** Long request type names. Combined with method names that already say `createBudgetConfiguration(...)`, the argument type is highly redundant. Compare typical TS SDK @@ -153,215 +75,12 @@ _None._ `CreateBudgetRequest`, `GetBudgetRequest`, `UpdateBudgetRequest`, `DeleteBudgetRequest`, `ListBudgetsRequest`. -#### F7.3 — `CreateBudgetConfigurationBudget` and - `UpdateBudgetConfigurationBudget` (HIGH) -- **Where:** `model.ts:98, 175`; `index.ts:21, 30`. -- **Why flagged:** These types are literally `BudgetConfiguration` + - the noun `Budget`. The name is `Budget` repeated twice plus - `Configuration`. Reads as - "Create-Budget-Configuration-Budget". -- **Suggestion:** Replace with the existing `BudgetConfiguration` - (or renamed `Budget`) directly. Inspection shows these types are - byte-for-byte identical to `BudgetConfiguration`: - - ```ts - // BudgetConfiguration - budgetConfigurationId, accountId, createTime, updateTime, - alertConfigurations, filter, displayName - - // CreateBudgetConfigurationBudget — identical - budgetConfigurationId, accountId, createTime, updateTime, - alertConfigurations, filter, displayName - - // UpdateBudgetConfigurationBudget — identical - budgetConfigurationId, accountId, createTime, updateTime, - alertConfigurations, filter, displayName - ``` - The duplication serves no schema purpose. Delete both wrapper - types and have `Create.../Update...` request types embed - `BudgetConfiguration` (or `Budget`) directly. See also F10 / F11. - ---- - -### 8. Singular / plural mismatches - -#### F8.1 — `alertConfigurations: AlertConfiguration[]` plural but - semantically singular (HIGH) -- **Where:** `model.ts:59-60, 107-108, 184-185`. -- **Why flagged:** JSDoc states "Budgets must have exactly one alert - configuration." Field is plural array. -- **Suggestion:** API-shape concern; document the invariant or - switch to singular `alertConfiguration: AlertConfiguration` when - the API allows. - ---- - -### 9. Reserved-word / built-in collisions - -_None._ - ---- - -### 10. Empty / trivial wrapper types - -_None._ - ---- - -### 11. Duplicate concepts - -#### F11.1 — `BudgetConfiguration` vs `CreateBudgetConfigurationBudget` - vs `UpdateBudgetConfigurationBudget` (HIGH) -- **Where:** `model.ts:50, 98, 175`. -- **Why flagged:** Three types with byte-for-byte identical fields. - Already noted in F7.3. They exist because the API contract - *might* diverge later (e.g. `Update` strips server-managed fields), - but today they are duplicates. -- **Suggestion:** Collapse to a single `BudgetConfiguration` (or - `Budget`) where the spec allows. If the spec mandates separate - shapes, document *why* each is distinct in JSDoc. - -#### F11.2 — `BudgetConfigurationFilter_Clause` and - `BudgetConfigurationFilter_WorkspaceIdClause` are the same shape - with `values` typed differently (MEDIUM) -- **Where:** `model.ts:81, 93`. -- **Why flagged:** Two near-identical types differ only in - `values: string[]` vs `values: number[]`. In TS this is a perfect - case for a generic: `Clause { operator?: Operator; values?: T[] }`. - The proto duplication is preserved verbatim. -- **Suggestion:** If parity with proto matters, leave alone. If not, - collapse to a generic clause type — but only if the generator - supports it. - -#### F11.3 — `accountId` declared on both the request envelope and - the inner `Budget` (LOW) -- **Where:** - - `CreateBudgetConfigurationBudget.accountId` (model.ts:102) - - `UpdateBudgetConfigurationBudget.accountId` (model.ts:179) - - `DeleteBudgetConfigurationRequest.accountId` (model.ts:137) - - `GetBudgetConfigurationRequest.accountId` (model.ts:147) - - `ListBudgetConfigurationsRequest.accountId` (model.ts:158) - - `UpdateBudgetConfigurationRequest` has no top-level `accountId`; it - pulls from `req.budget?.accountId` (`client.ts:237`) - - `CreateBudgetConfigurationRequest` likewise uses - `req.budget?.accountId` (`client.ts:83`) -- **Why flagged:** Inconsistent location of `accountId` between - request types. Some have it at the top level, some require it - nested under `budget`. Reader can't tell from the type which to - set. The fallback `this.accountId ?? ''` in - `delete/get/list` masks the inconsistency. -- **Suggestion:** Standardize: lift `accountId` to the top-level - request envelope for *all* methods. The Go/proto layer can keep - nesting; the TS client should flatten. - -#### F11.4 — `budgetId` on - `Delete/Get/UpdateBudgetConfigurationRequest` vs - `budgetConfigurationId` on `BudgetConfiguration` and - `Create/UpdateBudgetConfigurationBudget` (HIGH) -- **Where:** - - `DeleteBudgetConfigurationRequest.budgetId` (model.ts:135) - - `GetBudgetConfigurationRequest.budgetId` (model.ts:145) - - `UpdateBudgetConfigurationRequest.budgetId` (model.ts:197) - - `BudgetConfiguration.budgetConfigurationId` (model.ts:52) - - `CreateBudgetConfigurationBudget.budgetConfigurationId` - (model.ts:100) - - `UpdateBudgetConfigurationBudget.budgetConfigurationId` - (model.ts:177) -- **Why flagged:** Same conceptual ID, two different names. This is - the prototypical "same thing, two names" duplicate concept. Most - egregious example: `UpdateBudgetConfigurationRequest` has both - `budgetId` (top-level) *and* the nested - `budget.budgetConfigurationId`. -- **Suggestion:** Pick one. `budgetId` is shorter and matches the - REST path segment (`/budgets/{budgetId}`). Rename - `budgetConfigurationId → budgetId` everywhere. Combined with - the F7.1 rename `BudgetConfiguration → Budget`, this is consistent. - ---- - -### 12. Verb-tense inconsistency - -_None._ - ---- - -### 13. Go / Java-style names - -_None._ - ---- - -### 14. Generic field names losing meaning - -#### F14.1 — `req` parameter on every client method (HIGH) -- See F1.3. - ---- - -### 15. Field contradicting type domain - -_None._ - ---- - -### 16. Inconsistent action verbs - -_None._ - --- -### 17. Long enum values +### 4. Generic field names losing meaning -_None._ - ---- - -### 18. Underspecified IDs - -#### F18.1 — `budgetId` vs `budgetConfigurationId` for the same thing - (HIGH) -- See F11.4. The `budgetId` form is *less* underspecified than - `budgetConfigurationId` if the package name carries "budgets" - context — both are unambiguous in this package; the issue is - inconsistency. - ---- - -## Package overlap: `budgets` vs `budgetpolicy` - -This SDK exposes two separate packages whose names both start with -"budget": - -- `@databricks/sdk-budgets` (this package) -- `@databricks/sdk-budgetpolicy` (sibling) - -### F-OVERLAP.1 — `BudgetPolicy` vs `BudgetConfiguration` collision (HIGH) -- **Where:** `budgetpolicy/src/v1/model.ts:16` declares - `BudgetPolicy` with fields `policyId`, `policyName`, `customTags`, - `bindingWorkspaceIds`. This package's `BudgetConfiguration` - declares `budgetConfigurationId`, `accountId`, - `alertConfigurations`, `filter`, `displayName`. They are - *different* concepts (one defines spend-limit alerts, the other - defines workspace-binding policy tags) but a casual reader - searching for "budget" in autocomplete will see both and likely - conflate them. -- **Suggestion:** - - Add a short JSDoc on `BudgetConfiguration` clarifying it is the - spend-alert/notification budget. Cross-link to `BudgetPolicy`. - - Consider naming this package's primary type `SpendBudget` or - `UsageBudget` to disambiguate from `BudgetPolicy`. (`Budget` - alone is ambiguous with `BudgetPolicy`.) - - If staying with `Budget`, add a top-level index.ts JSDoc that - explicitly contrasts the two packages. - -### F-OVERLAP.2 — Both packages key off `accountId` and use similar - filter/binding semantics (MEDIUM) -- `BudgetPolicy.bindingWorkspaceIds: number[]` (direct array). -- `BudgetConfigurationFilter_WorkspaceIdClause.values: number[]` - (wrapped in a clause). -- Same data shape, different ergonomics. Cross-package - inconsistency. -- **Suggestion:** When (if) renaming, align the two field shapes. +#### F4.1 — `req` parameter on every client method (HIGH) +- See F1.2. --- @@ -369,57 +88,16 @@ This SDK exposes two separate packages whose names both start with | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Vague / generic | 3 | -| 2 | Redundant enum prefixes | 0 | -| 3 | Acronym casing | 0 | -| 4 | Underscores in TS identifiers | 0 | -| 5 | Cryptic abbreviations | 1 | -| 6 | Misleading names | 0 | -| 7 | Overly verbose | 3 | -| 8 | Singular / plural mismatch | 1 | -| 9 | Reserved-word collisions | 0 | -| 10 | Empty / trivial wrappers | 0 | -| 11 | Duplicate concepts | 4 | -| 12 | Verb-tense inconsistency | 0 | -| 13 | Go / Java-style names | 0 | -| 14 | Generic field names | 1 | -| 15 | Field contradicting type domain | 0 | -| 16 | Inconsistent action verbs | 0 | -| 17 | Long enum values | 0 | -| 18 | Underspecified IDs | 1 | -| OVERLAP | budgets vs budgetpolicy | 2 | - ---- - -## Top highest-impact renames (recommended order) - -1. **F11.4:** `budgetConfigurationId` → `budgetId` (or pick one - universally). Same concept under two names is the worst smell here. -2. **F7.1 / F7.3 / F11.1:** Collapse `BudgetConfiguration`, - `CreateBudgetConfigurationBudget`, - `UpdateBudgetConfigurationBudget` into a single `Budget` type. -3. **F1.1:** Rename `ActionConfiguration` to `BudgetAlertAction`. -4. **F7.2:** Drop "Configuration" from request type names - (`CreateBudgetRequest`). -5. **F11.3:** Lift `accountId` to top-level on all request types - (currently nested under `budget` for create/update only). - ---- - -## Notes / out-of-scope - -- All findings above relate to **generated** code. Code-base rule: - "Code generated from API definition by Databricks SDK Generator. - DO NOT EDIT." The fixes belong upstream in the generator and - spec. This audit is a backlog for that generator. -- This package has no `tests/` directory (verified by repo - structure check), so the audit does not cover test naming. +| 1 | Vague / generic | 2 | +| 2 | Cryptic abbreviations | 1 | +| 3 | Overly verbose | 2 | +| 4 | Generic field names | 1 | --- ## Proto / Architectural Leaks -### 1. `BudgetConfiguration` — model.ts:50 +### 1. `BudgetConfiguration` — model.ts:51 - **Why:** Repeated `Configuration` token threaded through nearly every type in the package (`BudgetConfiguration`, `BudgetConfigurationFilter`, @@ -437,7 +115,7 @@ This SDK exposes two separate packages whose names both start with ### 2. `AlertConfiguration` / `AlertConfigurationType` / `AlertConfigurationQuantityType` / `AlertConfigurationTimePeriod` / - `AlertConfigurationTriggerType` — model.ts:9, 13, 17, 35 + `AlertConfigurationTriggerType` — model.ts:10, 14, 18, 36 - **Why:** Same `Configuration` proto suffix repeated on the alert domain (and on every alert-related enum). The alert *is* a @@ -448,21 +126,18 @@ This SDK exposes two separate packages whose names both start with - **Rationale:** Drop `Configuration` — it's a proto-message-name artifact. -### 3. `ActionConfiguration` / `ActionConfigurationType` / - `actionConfigurationId` / `actionType` — model.ts:5, 26 +### 3. `ActionConfiguration` / `ActionConfigurationType` — model.ts:6, 27 - **Why:** Repeated `Configuration` proto suffix on the action domain. - `actionConfigurationId` is `ConfigurationId` — - three nouns where one would do. - **Category:** Proto leak — repeated `Config`/`Configuration` suffix. -- **Suggested:** `Action`, `ActionType`, `actionId`. +- **Suggested:** `Action`, `ActionType`. - **Rationale:** `Configuration` adds no semantic value here. ### 4. `BudgetConfigurationFilter` / `BudgetConfigurationFilter_Clause` / `BudgetConfigurationFilter_TagClause` / `BudgetConfigurationFilter_WorkspaceIdClause` / - `BudgetConfigurationFilter_Operator` — model.ts:22, 70, 81, 87, 93 + `BudgetConfigurationFilter_Operator` — model.ts:23, 71, 82, 88, 94 - **Why:** The `BudgetConfiguration` proto-message prefix is dragged into the filter family even though every reader is already inside @@ -479,15 +154,15 @@ This SDK exposes two separate packages whose names both start with drop both `Configuration` and the underscore-nesting convention. ### 5. `CreateBudgetConfigurationBudget` / - `UpdateBudgetConfigurationBudget` — model.ts:98, 175 + `UpdateBudgetConfigurationBudget` — model.ts:99, 173 - **Why:** Reads as `-Budget-Configuration-Budget`. The `Configuration` proto token is wedged between the verb prefix and the domain noun it already qualifies. Pure proto-message-naming artifact. - **Category:** Proto leak — `Configuration` infix duplicating domain. -- **Suggested:** Inline `Budget` (drop the wrapper entirely; see F7.3), - or rename to `CreateBudget` / `UpdateBudget`. +- **Suggested:** Inline `Budget` (drop the wrapper entirely), or + rename to `CreateBudget` / `UpdateBudget`. - **Rationale:** The mid-position `Configuration` adds nothing the package name and outer type don't already convey. @@ -495,8 +170,8 @@ This SDK exposes two separate packages whose names both start with `DeleteBudgetConfigurationRequest` / `GetBudgetConfigurationRequest` / `ListBudgetConfigurationsRequest` / - `UpdateBudgetConfigurationRequest` — model.ts:118, 133, 143, - 156, 195 + `UpdateBudgetConfigurationRequest` — model.ts:119, 133, 143, + 155, 193 - **Why:** `Configuration` infix between verb and `Request`/`Response` is a proto/gRPC service-method naming artifact. TS request types @@ -506,24 +181,3 @@ This SDK exposes two separate packages whose names both start with `GetBudgetRequest`, `ListBudgetsRequest`, `UpdateBudgetRequest`. - **Rationale:** Drop the proto inner-message qualifier — the verb + domain noun is sufficient. - -### 7. `CreateBudgetConfigurationRequest_Response` / - `DeleteBudgetConfigurationRequest_Response` / - `GetBudgetConfigurationRequest_Response` / - `ListBudgetConfigurationsRequest_Response` / - `UpdateBudgetConfigurationRequest_Response` — model.ts:124, 141, - 152, 169, 203 - -- **Why:** Two proto leaks stacked: (a) `Configuration` infix - duplicating domain, (b) `Request_Response` nested-message pattern - where the underscore segregates a proto inner type. The - `_Response` suffix in particular is the canonical proto-nested-type - artifact (`.Request.Response` in proto IDL). -- **Category:** Proto leak — proto-nested `_Response` + `Configuration` - infix. -- **Suggested:** `CreateBudgetResponse`, `DeleteBudgetResponse`, - `GetBudgetResponse`, `ListBudgetsResponse`, `UpdateBudgetResponse`. -- **Rationale:** Drop both the `Configuration` token and the - `Request_Response` proto nesting; use flat `Response`. - ---- diff --git a/.agent/naming-audit/bundle.md b/.agent/naming-audit/bundle.md deleted file mode 100644 index ac1af952..00000000 --- a/.agent/naming-audit/bundle.md +++ /dev/null @@ -1,223 +0,0 @@ -# Naming Audit — `@databricks/sdk-bundle` (v1) - -**Package path:** `/home/parth.bansal/sdk-js/packages/bundle/` -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/index.ts` -**Domain:** Databricks Asset Bundles (DAB) — control-plane registry for `databricks bundle deploy`/`destroy` runs. - ---- - -## Summary - -| Severity | Count | -| ------------ | ----- | -| High | 3 | -| Medium | 6 | -| Low | 5 | -| Observation | 4 | -| **Total** | **18** | - -Dominant themes: -1. **`VersionComplete` is a misleading type name.** It is a noun that reads like a boolean predicate, but it actually carries a completion *reason* enum; the type, the field that holds it (`completionReason`), and the values disagree on terminology. -2. **"Bundle" is in the URL but absent from type names**, while `DeploymentResourceType` (the domain catalog) is unrelated to the `Resource` interface (the per-deployment tracked item) — two distinct concepts share a confusable root. - ---- - -## High-Severity Findings - -### H1. `VersionComplete` enum name is misleading (Category: 6 — misleading; 13 — verb-tense) - -**Location:** `model.ts:127-137`, exported `index.ts:10`. - -```ts -export enum VersionComplete { - VERSION_COMPLETE_UNSPECIFIED = ..., - VERSION_COMPLETE_SUCCESS = ..., - VERSION_COMPLETE_FAILURE = ..., - VERSION_COMPLETE_FORCE_ABORT = ..., - VERSION_COMPLETE_LEASE_EXPIRED = ..., -} -``` - -The type *describes the reason a version finished*, but the identifier `VersionComplete` reads either as an adjective ("the version [is] complete") or an imperative verb ("complete the version"). The corresponding field is `completionReason: VersionComplete` (`Version.completionReason`, `CompleteVersionRequest.completionReason`), and the docstring says "Reason why a version was completed", so the type itself should be `VersionCompletionReason` (or `CompletionReason`). The current name forces the reader to inspect each call site to discover the type's role. - -Compounding the issue: the `complete` action lives on a *method* called `completeVersion()` (`client.ts:102`), so `VersionComplete` and `completeVersion` look related but mean different things — one is an enum of post-hoc reasons, the other is the imperative action. - -**Suggested rename:** `VersionCompletionReason` or `CompletionReason`, which matches the field name (`completionReason`) verbatim. - ---- - -### H2. "Bundle" is missing from every type name despite being the package name (Category: 14 — Go/Java-style; 15 — generic names losing meaning) - -**Location:** all exported types in `model.ts`, `index.ts:5-39`. - -The package is `@databricks/sdk-bundle` and every URL has `/api/2.0/bundle/`, yet not one type is `Bundle*`. Instead, the top-level entity is `Deployment` — extremely generic in TypeScript, where "deployment" appears in dozens of unrelated packages (jobs, model serving, apps, etc.). Outside the namespace, `Deployment` says nothing. - -Worse: `Deployment` also unrelatedly resembles `DeploymentResourceType` (see M2), and `DeploymentStatus` is used both on the top-level deployment *and* describes one of the lifecycle terms `DELETED` that does not match the more recent `destroyTime` lifecycle. From outside this package, the type `Deployment` is non-self-describing. - -Note: the user-supplied glossary explicitly flags "Bundle" as overloaded. The package solves the overload by *avoiding the word*, but this swap is not free — it just moves the ambiguity from "Bundle" to "Deployment". - -**Suggested rename:** `BundleDeployment` (or keep `Deployment` if internal consistency is preferred — but then export an aliased `BundleDeployment` for downstream consumers). At minimum, `Deployment` should be in the package-level JSDoc as "a bundle deployment", which the docstring on the interface already says. - ---- - -### H3. `HeartbeatRequest` / `HeartbeatResponse` and `heartbeat()` use a bare noun where the verb is `renew` (Category: 6 — misleading; 17 — inconsistent action verbs) - -**Location:** `model.ts:304-316`, `client.ts:398-421`. - -The semantics described in the docstring (`client.ts:391-397`) are *renew the lock on a version*. The method name `heartbeat` is a bare noun, not a verb. The other RPCs use action verbs: `createX`, `getX`, `deleteX`, `listX`, `completeX`. Only `heartbeat` is a noun. Worse, the return type `HeartbeatResponse` only carries `expireTime` — the new lock expiry — which is the *result of renewal*, not a "heartbeat response". - -**Suggested renames:** -- Method `heartbeat()` → `renewLock()` or `renewVersionLock()`. -- Type `HeartbeatRequest` → `RenewLockRequest`. -- Type `HeartbeatResponse` → `RenewLockResponse`. - ---- - -## Medium-Severity Findings - -### M1. `OperationActionType` enum name has the "action type" tautology (Category: 20 — type-suffix tautology) - -**Location:** `model.ts:83`. - -Reads as "the type of action type of operation". One of "action" or "type" is redundant. Pick `OperationAction` (the kind/category of an operation) or even `BundleAction`. - ---- - -### M2. `DeploymentResourceType` is also tautological in compound form (Category: 20 — type-suffix tautology) - -**Location:** `model.ts:19`. - -Reads as "deployment resource type", but the enum is the *catalog of resource kinds*, not a property of deployment. Just `ResourceKind` (or `BundleResourceKind` if you want to disambiguate from the `Resource` interface) would suffice. - ---- - -### M3. `completionReason` vs. enum `VersionComplete` mismatch (Category: 17 — inconsistent action verbs) - -**Location:** `Version.completionReason` (`model.ts:544`), `CompleteVersionRequest.completionReason` (`model.ts:169`). - -The field is `completionReason` (noun "reason" with "completion" adjective). The type is `VersionComplete` (no "Reason" suffix). Wire JSON is `completion_reason`. If the type is renamed per H1 to `VersionCompletionReason`, everything aligns. - ---- - -### M4. `VersionComplete` enum values use inconsistent grammatical forms (Category: 13 — verb-tense) - -**Location:** `model.ts:128-136`. - -The completion-reason values mix grammatical structures: -- `Success` — noun. -- `Failure` — noun. -- `ForceAbort` — verb phrase ("force abort"). -- `LeaseExpired` — past-participle phrase. - -Three different grammatical structures for what should be parallel completion reasons. The docstring on the force-abort value says "was force-aborted by another user" — so `ForceAborted` (past participle) would parallel `LeaseExpired`, and noun forms (`Success`, `Failure`, `ForcedAbort`, `LeaseExpiration`) would be even more parallel. - ---- - -### M5. Method `heartbeat()` collides with idiomatic "is-alive" connotation (Category: 6 — misleading; 7 — overly verbose interactions) - -**Location:** `client.ts:398`. - -In most APIs, `heartbeat()` is a *liveness check* (e.g. "is server up?"). Here it actively *mutates server state* (renews a lock). The verb suggests a read but it's a write. See H3 for suggested rename to `renewLock`. - ---- - -### M6. `VersionType` enum is generic (Category: 1 — vague) - -**Location:** `model.ts:149`. - -`VersionType` could be anything (semantic version? major/minor?). What it actually means is "deploy or destroy". `VersionKind` (or `BundleCommand`/`CliCommand`) is clearer. Values would shrink to `Deploy`/`Destroy`. - ---- - -## Low-Severity Findings - -### L1. `destroyTime` / `destroyedBy` naming carry over from the destroy-vs-delete distinction (Category: 6 — misleading) - -**Location:** `Deployment.destroyTime` (`model.ts:259`), `Deployment.destroyedBy` (`model.ts:264`). - -The comment on `destroyTime` explicitly justifies the divergence from `deleteTime` ("Named destroy_time (not delete_time) because this tracks the `databricks bundle destroy` command, not the API-level deletion"). That is a sensible choice, but worth noting that a reader scanning the field list sees `createTime`, `updateTime`, `destroyTime` and may mistakenly think it equals "delete time" (since the `Deleted` lifecycle value on `DeploymentStatus` exists). Could keep `destroyTime` but rename the enum value to `Destroyed` for consistency. Currently the enum value is `Deleted` while the lifecycle event is `destroy`. - ---- - -### L2. `cliVersion` — abbreviation acceptable but flag for awareness (Category: 5 — cryptic abbreviation; 3 — acronym casing) - -**Location:** `Version.cliVersion` (`model.ts:535`). - -`cli` is a well-known acronym (Command-Line Interface) so the abbreviation is fine, but the casing `cliVersion` (lowercase `cli`) is inconsistent with Google's TS rule that acronyms are PascalCase as a word (i.e. `cliVersion` is correct camelCase, but `Cli` rather than `CLI` is the convention — check the rest of the SDK for consistency). Wire form is `cli_version` which is fine. - ---- - -### L3. `pageSize` / `pageToken` / `nextPageToken` are consistent with Google AIP — fine - -**Location:** all `List*Request`/`List*Response` types. - -No issue, just noting these names are uniform and correct. - ---- - -### L4. `Operation` interface name collides with `Operation` from `@databricks/sdk-databricks` long-running-ops (Category: 12 — duplicate concepts) - -**Location:** `Operation` (`model.ts:441-481`). - -In many Databricks/Google APIs, `Operation` is the LRO (Long-Running Operation) pattern from `google.longrunning.Operation`. Here, `Operation` is a *resource operation row in a deployment version*. Same name, totally different concept. Importing both into the same file would collide. `ResourceOperation` would disambiguate. Check across other packages (`packages/databricks`, etc.) for an existing `Operation` type. - ---- - -### L5. `Resource.resourceKey` vs `Operation.resourceKey` — same name, same role (good) - -**Location:** `model.ts:497`, `model.ts:458`. - -This is correct re-use — both reference the same bundle config path. No issue. Noted for completeness. - ---- - -## Observations (Non-Defects) - -### O1. JSDoc on the `state` fields is good - -`Resource.state` and `Operation.state` both clearly say "Serialized local config state". Doc-level disambiguation is solid. - -### O2. `Resource.state` is `JsonValue` from `@databricks/sdk-core/wkt` — correct typing - -The `jsonValueSchema` (recursive Zod) is a clean port pattern. The field type is correct. - -### O3. Method `getResource` returns `Resource`, no naming collision - -`client.ts:341` returns `Resource` (the per-deployment tracked resource). No confusion with `DeploymentResourceType` here at the *method* level. - -### O4. Comment on the `name`-vs-`destroy` divergence is appreciated - -`Deployment.destroyTime` has an in-code justification (`model.ts:256-257`) explaining why it's not `deleteTime`. This kind of inline rationale is exactly what's missing on other overloaded fields. - ---- - -## Domain Glossary - -| Domain term | Meaning | Naming concerns? | -| ------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------ | -| Bundle | Databricks Asset Bundle — a config-driven project deployed via `databricks bundle deploy`. | Absent from all type names (H2). | -| Deployment | A registered bundle in the control plane. One per bundle target. Top-level entity in this API. | Overloaded with "deploy time" sense; generic outside the package. | -| Version | A single deploy or destroy *run* of a bundle. Acquires an exclusive lock on the deployment. | OK; `Version` is clear within the package. | -| Operation | One resource action (create/update/delete/bind/...) recorded under a version. Append-only. | Collides with LRO `Operation` (L4). | -| Resource | A per-deployment record of one Databricks object the bundle manages (a job, a pipeline, etc.). | Confusable with `DeploymentResourceType`. | -| `resource_key` | A dotted config path inside the bundle YAML (e.g. `"jobs.foo"`). | — | -| `resource_id` | The workspace-scoped ID of the underlying Databricks object (e.g. a job ID, pipeline ID). | — | -| Heartbeat | Lock renewal RPC sent by the active CLI while a version is in progress. | Misleading name; should be "renew lock" (H3). | -| Target | A named profile within a bundle (e.g. `dev`, `staging`, `prod`). | — | -| Destroy | The `databricks bundle destroy` command — undeploys a bundle. Distinct from API-level delete. | Named `destroyTime` (not `deleteTime`) intentionally (L1). | -| Force-abort | A user other than the version creator forcibly completes the version. | The `ForceAbort` completion value uses a verb phrase while siblings are nouns (M4). | -| Lease | The lock held by a version; renewed by Heartbeat; expires after timeout. | Surfaces only in the `LeaseExpired` completion value. | - ---- - -## File Coverage - -| File | Lines | Findings | -| ----------------- | ----- | --------------------------------------------------------------------------------- | -| `src/v1/model.ts` | 842 | H1, H2, H3, M1-M4, M6, L1, L2, L4, L5, O1, O2, O4 | -| `src/v1/client.ts`| 629 | H3 (method name), M5, O3 | -| `src/v1/index.ts` | 39 | Re-exports — inherits findings from `model.ts` and `client.ts`. | - -Every exported identifier in `model.ts` and `client.ts` was inspected. `index.ts` produced no incremental findings beyond what the model/client files surface. - ---- diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index 16374f9f..62220a5e 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -1,205 +1,49 @@ # Naming Audit: `catalogs` package (v1) -**Package path:** `/home/parth.bansal/sdk-js/packages/catalogs/` -**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` -**Domain:** Unity Catalog (UC) — top-level securable container. - ---- - -## Summary - -The `catalogs` package surfaces five UC catalog operations -(`createCatalog`, `deleteCatalog`, `getCatalog`, `listCatalogs`, -`updateCatalog`) plus a paginated iterator. The model layer mostly mirrors -the Go SDK 1:1, so most issues are inherited from the upstream definitions. -The most pervasive problems are (1) the cryptic `nameArg` path-parameter -field, and (2) massive `Create*Request`/`Update*Request` shapes that include -read-only output fields (`createdAt`, `createdBy`, `provisioningInfo`, -`securableType`, `fullName`, etc.) that have no business in a write request. +**Package path:** `/home/parth.bansal/sdk-js/packages/uc/catalogs/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` --- ## Findings -### 1. Vague / generic names - -#### 1.1 `inheritedFromType` / `inheritedFromName` (model.ts:203, 205) -`Type` here is a free-form `string`, not the `SecurableType` enum that -governs the rest of the package. The name `inheritedFromType` suggests an -enum/typed handle but is in fact human-readable text. Misleading — see -also §5. - ---- - -### 2. Acronym casing inconsistencies (UC, CMK, AKV) - -#### 2.1 `azureCmkAccessConnectorId`, `azureCmkManagedIdentityId` (model.ts:55, 56) -CMK ("Customer Managed Key") is consistently cased `Cmk` here. The same -concept is spelled out elsewhere as `customerManagedKeyId` -(EncryptionSettings.customerManagedKeyId — model.ts:214). Pick one: -either use the acronym everywhere (`azureCmkAccessConnectorId`, -`cmkId`) or expand it everywhere -(`azureCustomerManagedKeyAccessConnectorId`, `customerManagedKeyId`). - -#### 2.2 `azureKeyVaultKeyId` vs comment "AKV URL" (model.ts:216) -Field is `azureKeyVaultKeyId` but the doc comment says "the AKV URL in -Azure". The field name and doc must agree on whether the value is a URL -or an ID — they currently contradict each other. See also §5.2. - -#### 2.3 `DELTASHARING_CATALOG` enum variant (model.ts:13) -"Delta Sharing" is two words. Variant runs them together as -`DELTASHARING_CATALOG`. Should be `DELTA_SHARING_CATALOG` to match the -multi-word casing applied elsewhere in the same enum -(`MANAGED_ONLINE_CATALOG`). - ---- - -### 3. Cryptic abbreviations - -#### 3.1 `nameArg` (model.ts:191, 223, 269) -Used as the catalog name path-parameter on `DeleteCatalogRequest`, -`GetCatalogRequest`, and `UpdateCatalogRequest`. The `Arg` suffix is jargon -from the Go generator distinguishing path arguments from request-body -fields with the same key. TypeScript callers have no need for this -distinction — the field is the catalog name and should be named `name` -(or `catalogName` if a sibling `name` field is required for body -symmetry). Today, `UpdateCatalogRequest` has *both* `nameArg` (path) and -`name` (body) — virtually guaranteeing user confusion. See also §8.1. - -#### 3.2 `Cmk` prefix — see §2.1. - -#### 3.3 `Akv` (in `azureKeyVaultKeyId` doc comment, model.ts:216) — see §2.2. - ---- +### 1. Overly verbose -### 4. Misleading names - -#### 4.1 `EffectivePredictiveOptimizationFlag.value` "string" carries enum-like semantics -The field is typed `string | undefined` but the comment ("Whether predictive -optimization should be enabled…") implies a tri-state (enabled / disabled / -inherit). Either the type should be an enum (`PredictiveOptimizationFlag`) -or the field should be named explicitly (`enabled: string`). - -#### 4.2 `azureKeyVaultKeyId` is described as a URL (model.ts:215-216) -Field is named `…Id` but doc says "the AKV URL in Azure". Either rename to -`azureKeyVaultKeyUri` or fix the doc to match. Today the name lies about -what the field holds. - -#### 4.3 `CatalogInfo.fullName` "Corresponds with the name field" (model.ts:101-102) -The doc explicitly states that `fullName` equals `name` for catalogs. -The field exists only to satisfy the parent `Securable` contract. This is -arguably acceptable (UC is column-uniform across securables) but the name -misleads — it promises richer information than `name` provides. - -#### 4.4 `CatalogInfo.options` vs `CatalogInfo.properties` (model.ts:106-109) -Both are `Record` with identical doc comments ("A map of -key-value properties attached to the securable."). There is no way for a -caller to know what distinguishes them. The doc duplication is verbatim -in `CreateCatalogRequest` (171-174) and `UpdateCatalogRequest` (318-321). -Either is underspecified or one of them is misnamed. - ---- - -### 5. Overly verbose - -#### 5.1 `EffectivePredictiveOptimizationFlag` (model.ts:199) -Identifier is 39 characters. Compounded by the field name -`effectivePredictiveOptimizationFlag` (model.ts:95, 160, 307) used on -three different request/response types. `EffectivePOFlag` or +#### 1.1 `EffectivePredictiveOptimizationFlag` (model.ts:199) +Type identifier is 39 characters. `EffectivePOFlag` or `EffectivePredictiveOptFlag` is overkill the other way; consider `EffectivePredictiveOptimization` (no `Flag` since the type already wraps the flag). -#### 5.2 `enablePredictiveOptimization: string` (model.ts:69, 134, 281) -Long field name for a single flag value. Acceptable, but tracked because -it pairs with §5.1 to make every `CatalogInfo`-style object verbose. - --- -### 6. Redundant suffixes +### 2. Redundant suffixes -#### 6.1 `…Info` types (`CatalogInfo`, `ProvisioningInfo`) +#### 2.1 `…Info` types (`CatalogInfo`, `ProvisioningInfo`) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from the resource handle; in JS/TS the convention is to drop it (`Catalog`, `Provisioning`). -#### 6.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` -The whole type *is* the flag; the suffix is redundant. See §5.1. - -#### 6.3 `…Arg` suffix on `nameArg` — see §3.1 and §8.1. +#### 2.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` +The whole type *is* the flag; the suffix is redundant. See §1.1. --- -### 7. Reserved-word collisions +### 3. Reserved-word collisions -#### 7.1 `options` field on `CatalogInfo`, `CreateCatalogRequest`, `UpdateCatalogRequest` (model.ts:109, 174, 321) +#### 3.1 `options` field on `CatalogInfo`, `CreateCatalogRequest`, `UpdateCatalogRequest` (model.ts:109, 174, 320) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (e.g. `createCatalog(req, options)`). The collision is not a compile error but creates cognitive load — inside `updateCatalog(req, options)` the reader sees both `req.options` (catalog metadata) and `options` (call options). Rename one. The least invasive -fix is renaming the second client parameter to `callOptions`. See also -§8.1 for the duplicate-with-`properties` concern. - -#### 7.2 `name` keyword-ish field -`name` is used as a non-path-param body field on `Create*Request` / -`Update*Request` / `CatalogInfo`, and also as a path arg via `nameArg`. -This isn't a reserved word but it routinely shadows -`Function.prototype.name` and is a common source of confusion when -callers spread request objects. See also §3.1. - ---- - -### 8. Duplicate concepts - -#### 8.1 `properties` and `options` (model.ts:106-109, 171-174, 318-321) -Both `Record` on every catalog shape, with identical doc -comments ("A map of key-value properties attached to the securable."). -There is no way for a caller to know which to use for what. Either the -docs need to differentiate them or one is redundant. See also §4.4. - -#### 8.2 `name` vs `fullName` on `CatalogInfo` -`fullName` is documented as "the full name of the catalog. Corresponds -with the name field" (model.ts:101-102). The same data lives in `name` -for catalogs because catalogs are top-level. The duplicate field exists -to satisfy a polymorphic Securable shape — but for the catalog-specific -type, it's redundant. See also §4.3. - -#### 8.3 `name` vs `nameArg` on `UpdateCatalogRequest` -The `UpdateCatalogRequest` has *both* `nameArg` (the existing catalog -identifier, used in the URL path) and `name` (the new desired name, -used in the body). It also has `newName` for the same concept. See -§9.1 below — three name-like fields on one request shape. - -#### 8.4 `securableType` on `CatalogInfo` (model.ts:103) duplicates the type identity -`CatalogInfo` represents a catalog; its `securableType` field will -always be `SecurableType.CATALOG`. The field exists for polymorphism -across UC types but is meaningless when the surrounding type already -identifies the securable. Not a renaming issue — but worth flagging -as a duplicated concept. - -#### 8.5 `CreateCatalogRequest`, `UpdateCatalogRequest`, and `CatalogInfo` share ~25 fields verbatim -The three types are 95% identical and have largely identical doc strings. -This is a generator artifact, but it bleeds into naming: any rename of -`storageRoot` must happen in three places. Recommend basing -`CreateCatalogRequest`/`UpdateCatalogRequest` on `Partial` -or a shared `CatalogProperties` mixin. +fix is renaming the second client parameter to `callOptions`. --- -### 9. Field contradicting type domain - -#### 9.1 `UpdateCatalogRequest` has `nameArg`, `name`, and `newName` (model.ts:269, 271, 273) -Three name-bearing fields on a single update request: -- `nameArg` — existing catalog (path param). -- `newName` — new desired name (body). -- `name` — also "name of catalog" per the inherited doc (model.ts:272). - -A caller staring at this struct cannot intuit which to set. This is the -single most user-hostile naming pattern in the package — and it sits on -the most-used method. +### 4. Field contradicting type domain -#### 9.2 `CreateCatalogRequest` contains read-only output fields +#### 4.1 `CreateCatalogRequest` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `provisioningInfo`, `fullName`, `securableType`, `effectivePredictiveOptimizationFlag`, `browseOnly` (model.ts:147-168). @@ -207,58 +51,11 @@ These are server-populated; a creator setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Mirror issue in `UpdateCatalogRequest`. -#### 9.3 `DeleteCatalogRequest.nameArg` — see §3.1. - ---- - -### 10. Underspecified IDs - -#### 10.1 `customerManagedKeyId` (model.ts:214) -Doc: "the CMK uuid in AWS and GCP, null otherwise." So the field is a -UUID on AWS/GCP but `azureCmkAccessConnectorId` is an Azure resource ID -elsewhere — same conceptual ID, two formats, no unifying name. - -#### 10.2 `azureKeyVaultKeyId` (model.ts:216) -Doc says "the AKV URL in Azure" — so it's actually a URL, not an ID. See -§4.2. - --- -### 11. Type-suffix tautology - -#### 11.1 `SecurableType` enum with field `securableType: SecurableType` -(model.ts:21, 103, 168, 315) — field name tautological with type name. -Defensible (field carries the dynamic value) but worth flagging. - -#### 11.2 `CatalogType` enum with field `catalogType: CatalogType` -(model.ts:11, 70, 135, 282) — same pattern. - -#### 11.3 `CatalogIsolationMode` enum with field `isolationMode: CatalogIsolationMode` -(model.ts:5, 94, 159, 306) — field-name shortened, type-name keeps the -prefix. Reasonable. - -#### 11.4 `…Info` types with `…info` fields -- `provisioningInfo: ProvisioningInfo` -- `effectivePredictiveOptimizationFlag: EffectivePredictiveOptimizationFlag` -- `managedEncryptionSettings: EncryptionSettings` (oddly *not* tautological) - -The first two are tautological. Acceptable convention; flagged for -completeness. - ---- - -### 12. Bare `Client` class name (client.ts:44) -`Client` (rather than `CatalogsClient`) is a Go-idiom: package qualifies -the type. JS consumers commonly import as -`import {Client} from '@databricks/sdk-catalogs/v1'` and have to alias. -This is a package-wide convention, but worth flagging in this audit -for consistency with the broader review. - ---- +### 5. Proto-architectural leaks -### 13. Proto-architectural leaks - -#### 13.1 `ProvisioningInfo_State` — model.ts:43 +#### 5.1 `ProvisioningInfo_State` — model.ts:43 - **Why:** Underscore-separated identifier signals a nested protobuf enum (`message ProvisioningInfo { enum State { ... } }`). The transport encoding has bled into the public type name and the `eslint-disable` @@ -269,7 +66,7 @@ for consistency with the broader review. `State` produces a flat, idiomatic identifier without leaking the proto-nested origin. -#### 13.2 `CatalogInfo_OptionsEntry` — model.ts:113 +#### 5.2 `CatalogInfo_OptionsEntry` — model.ts:113 - **Why:** Auto-generated proto map-entry message exposed as a public type. `_OptionsEntry` is the canonical protobuf shape for `map options` and has no semantic meaning at the @@ -281,15 +78,15 @@ for consistency with the broader review. - **Rationale:** Map-entry types are a proto serialization artifact, not a domain concept. -#### 13.3 `CatalogInfo_PropertiesEntry` — model.ts:119 -- **Why:** Same as 13.2 — proto map-entry leak for the `properties` +#### 5.3 `CatalogInfo_PropertiesEntry` — model.ts:119 +- **Why:** Same as 5.2 — proto map-entry leak for the `properties` field. - **Category:** Proto suffix/infix. - **Suggested:** Remove from the public surface, or rename to `CatalogProperty`. -- **Rationale:** Identical reasoning to 13.2. +- **Rationale:** Identical reasoning to 5.2. -#### 13.4 `CreateCatalogRequest_OptionsEntry` — model.ts:178 +#### 5.4 `CreateCatalogRequest_OptionsEntry` — model.ts:178 - **Why:** Proto map-entry type duplicated per parent message. - **Category:** Proto suffix/infix. - **Suggested:** Remove from the public surface; the inline @@ -298,100 +95,20 @@ for consistency with the broader review. `CatalogInfo`, `CreateCatalogRequest`, and `UpdateCatalogRequest` is a smoking gun for proto codegen, not an SDK design. -#### 13.5 `CreateCatalogRequest_PropertiesEntry` — model.ts:184 -- **Why:** Same as 13.4 — proto map-entry leak. +#### 5.5 `CreateCatalogRequest_PropertiesEntry` — model.ts:184 +- **Why:** Same as 5.4 — proto map-entry leak. - **Category:** Proto suffix/infix. - **Suggested:** Remove from the public surface. -- **Rationale:** See 13.4. - -#### 13.6 `DeleteCatalogRequest_Response` — model.ts:197 -- **Why:** Empty interface whose name literally encodes the proto - request/response coupling (`_Response`). It exists only - because protobuf RPC defines a paired response message; the TS SDK - could return `void` or a plain `{}`/`Record`. -- **Category:** Proto suffix/infix; also `Foo_PublicRequest`-style - paired-name leak. -- **Suggested:** Drop the type and return `void` from `deleteCatalog`, - or rename to `DeleteCatalogResponse` (no underscore). -- **Rationale:** The underscore-paired name is the protobuf service - convention; nothing in the JS SDK contract demands it. +- **Rationale:** See 5.4. -#### 13.7 `ListCatalogsRequest_Response` — model.ts:251 -- **Why:** Same proto-paired naming as 13.6. The response carries - `catalogs` and `nextPageToken` and deserves a name describing its - domain, not its request-pair lineage. -- **Category:** Proto suffix/infix. -- **Suggested:** `ListCatalogsResponse` (drop the underscore) or - `CatalogPage`. -- **Rationale:** The `Request_Response` underscored pairing is a proto - artifact and is exported on the public surface (`index.ts:27`). - -#### 13.8 `UpdateCatalogRequest_OptionsEntry` — model.ts:325 +#### 5.6 `UpdateCatalogRequest_OptionsEntry` — model.ts:324 - **Why:** Proto map-entry leak (third copy of the same shape). - **Category:** Proto suffix/infix. - **Suggested:** Remove from the public surface. -- **Rationale:** See 13.4. +- **Rationale:** See 5.4. -#### 13.9 `UpdateCatalogRequest_PropertiesEntry` — model.ts:331 +#### 5.7 `UpdateCatalogRequest_PropertiesEntry` — model.ts:330 - **Why:** Proto map-entry leak. - **Category:** Proto suffix/infix. - **Suggested:** Remove from the public surface. -- **Rationale:** See 13.4. - ---- - -## Additional / cross-cutting observations - -_None._ - ---- - -## File / line index for fast lookup - -| Identifier | Location | Finding | -| ------------------------------------------------------- | ------------------ | ------- | -| `CatalogIsolationMode` | model.ts:5 | 11.3 | -| `CatalogType` | model.ts:11 | 11.2 | -| `CatalogType.DELTASHARING_CATALOG` | model.ts:13 | 2.3 | -| `SecurableType` | model.ts:21 | 11.1 | -| `SecurableType.STAGING_TABLE` (with TODO comment) | model.ts:39 | — | -| `AzureEncryptionSettings` | model.ts:53 | 2.1 | -| `CatalogInfo` | model.ts:59 | 6.1 | -| `CatalogInfo.options` / `.properties` | model.ts:109, 107 | 4.4, 7.1, 8.1 | -| `CatalogInfo.fullName` | model.ts:102 | 4.3, 8.2 | -| `CatalogInfo.securableType` | model.ts:103 | 8.4, 11.1 | -| `CreateCatalogRequest` | model.ts:124 | 8.5, 9.2 | -| `DeleteCatalogRequest.nameArg` | model.ts:191 | 3.1, 9.3 | -| `EffectivePredictiveOptimizationFlag` | model.ts:199 | 5.1, 6.2 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:201 | 4.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:203 | 1.1 | -| `EncryptionSettings.customerManagedKeyId` | model.ts:214 | 2.1, 10.1 | -| `EncryptionSettings.azureKeyVaultKeyId` | model.ts:216 | 2.2, 4.2, 10.2 | -| `GetCatalogRequest.nameArg` | model.ts:223 | 3.1 | -| `ListCatalogsRequest.maxResults` | model.ts:240 | — | -| `ListCatalogsRequest.pageToken` | model.ts:242 | — | -| `ListCatalogsRequest.includeUnbound` | model.ts:247 | — | -| `ProvisioningInfo` | model.ts:262 | 6.1 | -| `UpdateCatalogRequest.nameArg/newName/name` | model.ts:269-273 | 3.1, 8.3, 9.1 | -| `ProvisioningInfo_State` (proto-nested enum) | model.ts:43 | 13.1 | -| `CatalogInfo_OptionsEntry` | model.ts:113 | 13.2 | -| `CatalogInfo_PropertiesEntry` | model.ts:119 | 13.3 | -| `CreateCatalogRequest_OptionsEntry` | model.ts:178 | 13.4 | -| `CreateCatalogRequest_PropertiesEntry` | model.ts:184 | 13.5 | -| `DeleteCatalogRequest_Response` | model.ts:197 | 13.6 | -| `ListCatalogsRequest_Response` | model.ts:251 | 13.7 | -| `UpdateCatalogRequest_OptionsEntry` | model.ts:325 | 13.8 | -| `UpdateCatalogRequest_PropertiesEntry` | model.ts:331 | 13.9 | -| `Client` (bare name) | client.ts:44 | 12 | - ---- - -## Recommended priority order - -1. **Fix `nameArg` / `name` / `newName` triple on `UpdateCatalogRequest`** — biggest user-facing trap. (§9.1, §3.1) -2. **Distinguish or merge `options` and `properties`.** (§8.1) -3. **Disambiguate `azureKeyVaultKeyId` (URL vs ID).** (§2.2, §4.2) -4. **Strip read-only fields from `CreateCatalogRequest`/`UpdateCatalogRequest`.** (§9.2) -5. **Decide CMK casing and apply uniformly.** (§2.1, §10.1) - ---- +- **Rationale:** See 5.4. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index ad24a1b0..b57c1164 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -4,117 +4,29 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/index.ts` **Auditor:** Naming audit pass — TypeScript port of Databricks Go SDK. -This audit catalogs every type, field, enum value, and method name in the -`cleanrooms` v1 package against the 20 criteria provided. Findings are -grouped by category, and each finding cites the file/line where it appears. - --- ## Summary -- **Total findings:** 9 -- **Highest-impact themes:** - 1. Misleading boolean-shaped `accessRestricted` enum. - 2. Acronym casing inconsistencies (`Id` vs `ID`, `Dns` vs `DNS`). - 3. Duplicate `Status` enum types and overlapping collaborator types. - 4. Proto-architectural leaks: stray `Handler` suffix on list methods - for notebook task runs. - ---- - -## 1. Vague / Generic Names - -_None._ - ---- - -## 2. Acronym Casing Inconsistencies - -### 2.1 `centralCleanRoomId` (model.ts:577) -Uses `Id` (lowercase `d`). Elsewhere `globalMetastoreId`, -`inviteRecipientWorkspaceId` — consistent within this file as `Id`. But -Google TypeScript Style Guide § 5.3 recommends `ID` (treat as acronym). The -package is internally consistent (all `Id`); the issue is whether to upgrade -to `ID` across the SDK. **Note:** repo-wide convention should be confirmed. - -### 2.2 `azureDnsZone` (model.ts:806) -"DNS" is an initialism. Per the style guide, `azureDNSZone`. Currently -`azureDnsZone` treats DNS as a word. +- **Total findings:** 3 --- -## 3. Misleading Names - -### 3.1 `accessRestricted?: CleanRoom_AccessRestricted` (model.ts:271) -Reads as a boolean ("is access restricted?"). It is actually an enum with -values `NO_RESTRICTION` and `CSP_MISMATCH`. The JSDoc reinforces the -miscommunication: "Whether clean room access is restricted…" — implying a -yes/no. The shape itself is boolean-like (two values, one of which is the -absence sentinel) — a `boolean` field would model the domain more -honestly. - ---- - -## 4. Singular / Plural Mismatches - -_None._ - ---- - -## 5. Duplicate Concepts - -### 5.1 Two `Status` enums -- `CleanRoom.status: CleanRoom_Status_Enum` (model.ts:262) -- `CleanRoomOutputCatalog.status: CleanRoomOutputCatalog_OutputCatalogStatus` - (model.ts:565) - -Two distinct, non-overlapping `Status` enums. The two enum types should -consider naming themselves unambiguously: `CleanRoomStatus`, -`OutputCatalogStatus`. +## 1. Inconsistent Action Verbs -### 5.2 `creator?: CleanRoomCollaborator` (model.ts:592) vs. -`collaborators?: CleanRoomCollaborator[]` (model.ts:590) -Per the JSDoc, `creator` is also **one of the collaborators in the -collaborators list**. So we have the same logical entity reachable through -two paths. Mild — not a renamed-target, but flagged as a shape concern. - -### 5.3 `CleanRoomCollaborator` (model.ts:490) vs. -`CollaboratorJobRunInfo` (model.ts:606) -Both types now live in `cleanrooms` (the `cleanroomtaskruns` package was -consolidated into `cleanrooms`). Within the package, two "Collaborator- -prefixed" surfaces model different aspects of collaborators with different -prefixes. Consistency would suggest renaming `CollaboratorJobRunInfo` to -`CleanRoomCollaboratorJobRunInfo`. - ---- - -## 6. Inconsistent Action Verbs - -### 6.1 `createCleanRoom` returns the new clean room (client.ts:125); +### 1.1 `createCleanRoomAsset` returns the new asset (client.ts:168); `createCleanRoomOutputCatalog` returns a **response wrapper** -(`CreateCleanRoomOutputCatalogResponse`) (client.ts:267). +(`CreateCleanRoomOutputCatalogResponse`) (client.ts:264). Inconsistent return shapes for two `create*` methods. The Go SDK has the same wart, but it surfaces here as inconsistent ergonomics: -`(await c.createCleanRoom(...)).name` vs. +`(await c.createCleanRoomAsset(...)).name` vs. `(await c.createCleanRoomOutputCatalog(...)).outputCatalog?.catalogName`. --- -## 7. Cloud Asymmetry / Cross-Cloud Field Naming - -_None._ - ---- - -## 8. Cross-Package Overlap - -_None._ +## 2. Proto / Architectural Leaks ---- - -## 9. Proto / Architectural Leaks - -### 9.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:662 +### 2.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:659 - **Why:** Mid/end-position `Handler` on a public method (not a domain term). All sibling list methods (`listCleanRooms`, `listCleanRoomAssets`, `listCleanRoomAutoApprovalRules`) omit the `Handler` suffix. The stray @@ -125,24 +37,12 @@ _None._ like `Handler` in client-method names; consistency with the other `list*` methods is the principal benefit. -### 9.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:704 +### 2.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:701 - **Why:** Same stray `Handler` infix in the async-iterator companion to - §9.1. Sibling iterators (`listCleanRoomsIter`, + §2.1. Sibling iterators (`listCleanRoomsIter`, `listCleanRoomAssetsIter`, `listCleanRoomAutoApprovalRulesIter`) follow the `Iter` pattern without `Handler`. - **Category:** Architectural leak (server-side terminology). - **Suggested:** `listCleanRoomNotebookTaskRunsIter`. -- **Rationale:** Must rename in lock-step with §9.1 so the iterator name +- **Rationale:** Must rename in lock-step with §2.1 so the iterator name derives cleanly from the base method. - ---- - -## Positive Examples (no action required) - -- Method names follow standard CRUD verbs (create/get/list/update/delete). -- `cleanRooms` / `cleanRoomName` / `collaborators` / `complianceStandards` - use correct plurality. -- JSDoc is generally comprehensive — references to UC naming rules and - external compliance documents are well-linked. - ---- diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index 9ecdbee0..9e7ab889 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -2,75 +2,18 @@ Path: `/home/parth.bansal/sdk-js/packages/clusterlibraries/` Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` -Scope: every type, field, enum value, method, and exported identifier. - -Findings are grouped by category. Severity reflects the impact on TS consumers -of the SDK; "high" means a name will mislead, surprise, or conflict; "medium" -means it is awkward or inconsistent; "low" means a minor blemish. - ---- - -## 1. Vague / generic names - -_None._ - ---- - -## 2. Acronym casing inconsistencies - -### 2.1 `PythonPyPiLibrary` — `model.ts:159` -- Mixed casing for the PyPI acronym. The canonical brand name is **PyPI** - (Python Package Index, https://pypi.org). The TS identifier uses `PyPi` - which is neither pure brand casing nor TS acronym convention. Should be - either `PythonPyPiLibrary` -> `PythonPyPILibrary` (brand) or — and this - is the larger issue — the type itself is double-prefixed: it already - belongs to a category of Python ecosystem things, so the prefix `Python` - is also a tautology since "PyPI" is exclusively Python. `PypiLibrary` or - `PyPILibrary` would be cleaner. -- The `$case: 'pypi'` literal further uses lowercase `pypi`, which is fine - for a wire tag but inconsistent with the type name regardless of which - casing wins. -- Severity: high (a brand-name spelling error visible in every consumer - using PyPI packages). - -### 2.2 `RCranLibrary` — `model.ts:172` -- "CRAN" (Comprehensive R Archive Network) is an all-caps acronym. The TS - identifier renders it `Cran`. By TS/Google style guidance acronyms longer - than two letters are typically PascalCased ("Cran"), but the resulting - `RCranLibrary` mixes a one-letter prefix `R` (uppercase) with the lowercase - acronym, which reads oddly (is it "R-Cran" or "RC-Ran"?). `CranLibrary` - alone would be unambiguous (CRAN is R-specific); the `R` prefix is the - same tautology as `Python` on `PythonPyPiLibrary`. -- The discriminator `$case: 'cran'` is consistent with the type tag. -- Severity: medium. - ---- - -## 3. Cryptic abbreviations - -### 3.1 `Library.pypi`, `Library.cran` — `model.ts:79, 95` -- Lower-cased acronyms as field tags. Acceptable for wire compatibility, - but the inconsistency with the (camelCased) type names (`PythonPyPiLibrary`, - `RCranLibrary`) is jarring. See §2. -- Severity: low. --- -## 4. Misleading names +## 1. Misleading names -### 4.1 `LibraryFullStatus` — `model.ts:122` +### 1.1 `LibraryFullStatus` — `model.ts:122` - "Full" implies there is a "Partial" or "Short" counterpart, but there is none in this package. The type is "the status of a library on a cluster" per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. - Severity: medium. -### 4.2 `LibraryInstallStatus` value `UNINSTALL_ON_RESTART` — `model.ts:28` -- This is the only value that is an action+condition (rather than a state - noun). Surrounding values are `PENDING`, `INSTALLED`, `FAILED`. A noun - form like `PENDING_UNINSTALL` would line up. See also §10.2. -- Severity: medium. - -### 4.3 `allClusterStatuses()` — `client.ts:74` +### 1.2 `allClusterStatuses()` — `client.ts:76` - Method is the GET for `all-cluster-statuses`. The TS method name reads like an adjective ("all-cluster statuses") and is not verb-prefixed. Sibling method is `clusterStatus()` (also verb-less). Compare with the @@ -78,13 +21,13 @@ _None._ verb-prefixed). The two GET methods alone are exempt. Should be `listAllClusterStatuses` or `getAllClusterStatuses`, and `getClusterStatus` respectively. -- Severity: medium. See also §10. +- Severity: medium. See also §5. --- -## 5. Overly verbose names +## 2. Overly verbose names -### 5.1 `ListAllClusterLibraryStatusesRequest` — `model.ts:134` +### 2.1 `ListAllClusterLibraryStatusesRequest` — `model.ts:134` - The type name embeds "All" (which is also encoded in the URL `/api/2.0/libraries/all-cluster-statuses`). The type name `ListAllClusterLibraryStatusesRequest` is itself verbose — `ListLibraryStatusesRequest` @@ -93,145 +36,50 @@ _None._ --- -## 6. Redundant suffixes +## 3. Redundant suffixes -### 6.1 `LibraryFullStatus` — `model.ts:122` -- "Full" is a vestigial qualifier with no counterpart. See §4.1. +### 3.1 `LibraryFullStatus` — `model.ts:122` +- "Full" is a vestigial qualifier with no counterpart. See §1.1. - Severity: medium. --- -## 7. Singular/plural mismatches +## 4. Singular/plural mismatches -### 7.1 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:134` -- Singular method name `allClusterStatuses` (`client.ts:74`) for what is - semantically a list operation. The action verb should be `list`. See §11. +### 4.1 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:134` +- Singular method name `allClusterStatuses` (`client.ts:76`) for what is + semantically a list operation. The action verb should be `list`. See §6. - Severity: medium. --- -## 8. Reserved-word collisions - -_None._ - ---- - -## 9. Duplicate concepts - -_None._ +## 5. Verb-tense inconsistency ---- - -## 10. Verb-tense inconsistency - -### 10.1 Method verbs across the client — `client.ts:74, 110, 144, 176` +### 5.1 Method verbs across the client — `client.ts:76, 115, 152, 184` - `allClusterStatuses` and `clusterStatus` are verb-less (noun-only). - `installLibraries`, `uninstallLibraries` use verb-prefixed forms. - Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: `listAllClusterStatuses` (or `getAllClusterStatuses`) and - `getClusterStatus`. See §4.3 and §11. + `getClusterStatus`. See §1.2 and §6. - Severity: high (consistency of the verb-prefix is a Java/TS SDK convention that consumers rely on). -### 10.2 `LibraryInstallStatus` action vs state values — `model.ts:6` -- Values mostly nouns (`PENDING`, `INSTALLED`, `FAILED`) but one verb - imperative `UNINSTALL_ON_RESTART` and one passive `SKIPPED`. See §4.2. -- Severity: medium. - --- -## 11. Inconsistent action verbs +## 6. Inconsistent action verbs -### 11.1 GET vs `list` vs `all` — `client.ts:74` +### 6.1 GET vs `list` vs `all` — `client.ts:76` - `allClusterStatuses()` (verb `all`) reads as a noun-phrase, not a verb. The Go SDK uses the same naming, but the TS port has the opportunity to normalize to `list` (or `get`). -- Severity: medium (see §10.1). - -### 11.2 `installLibraries` / `uninstallLibraries` — `client.ts:144, 176` -- Symmetric pair, good. Mirror request types `InstallLibrariesRequest` / - `UninstallLibrariesRequest` (named after the operation, not the resource). - Consistent. +- Severity: medium (see §5.1). --- -## 12. Field contradicting type domain +## 7. Type-suffix tautology -_None._ - ---- - -## 13. Long enum values - -_None._ - ---- - -## 14. Underspecified IDs - -### 14.1 `ClusterLibraryStatuses.clusterId`, `ClusterStatusRequest.clusterId`, - `InstallLibrariesRequest.clusterId`, `UninstallLibrariesRequest.clusterId` - — `model.ts:40, 47, 52, 181` -- Bare `clusterId` everywhere. Good consistency. No issue. - ---- - -## 15. Type-suffix tautology - -### 15.1 `LibraryFullStatus` — `model.ts:122` +### 7.1 `LibraryFullStatus` — `model.ts:122` - "Status" appears in the type name and the field `status: LibraryInstallStatus` contains the noun again. Not a tautology per se, but the parent - `LibraryFullStatus` could be `LibraryReport` or just `LibraryStatus` (with - the inner field becoming `state` to avoid the duplicate). + `LibraryFullStatus` could be `LibraryReport` or just `LibraryStatus`. - Severity: low. - ---- - -## Cross-cutting summary - -### High-severity (consumer-facing surprises) - -- `PythonPyPiLibrary` brand-casing inconsistency (§2.1): "PyPi" misspells - the PyPI brand. -- Verb-tense gap: `allClusterStatuses()` and `clusterStatus()` break the - client's prevailing verb-prefix convention (§10.1, §11.1). - -### Medium-severity - -- `LibraryFullStatus` with no "non-full" counterpart (§4.1). -- `LibraryInstallStatus.UNINSTALL_ON_RESTART` mixes action and state - (§4.2, §10.2). - -### Low-severity / stylistic - -_None._ - ---- - -## Inventory (for completeness) - -Enums audited: -- `LibraryInstallStatus` (model.ts:6). - -Interfaces audited: -- `ClusterLibraryStatuses` (38). -- `ClusterStatusRequest` (45). -- `InstallLibrariesRequest` (50). -- `InstallLibrariesRequest_Response` (58). -- `Library` (60). -- `LibraryFullStatus` (122). -- `ListAllClusterLibraryStatusesRequest` (134). -- `ListAllClusterLibraryStatusesRequest_Response` (137). -- `MavenLibrary` (142). -- `PythonPyPiLibrary` (159). -- `RCranLibrary` (172). -- `UninstallLibrariesRequest` (179). -- `UninstallLibrariesRequest_Response` (187). - -Methods audited (`client.ts`): -- `allClusterStatuses` (74). -- `clusterStatus` (110). -- `installLibraries` (144). -- `uninstallLibraries` (176). - ---- diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index f87e8370..5746c925 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -9,266 +9,35 @@ - `src/v2/client.ts` - `src/v2/index.ts` -This audit catalogues every identifier (type, field, enum value, method, -constant) in the package and flags naming concerns against the 20-category -rubric. Issues are graded: - -- **High** — actively misleading, ambiguous, or violates a TS rule. -- **Medium** — friction; verbose, redundant, or stylistically off. -- **Low** — nit / consistency observation; safe to ignore. - --- -## 1. Inventory - -### 1.1 Enums (`model.ts`) - -| Name | Members | -| ----------------- | ------------------------------------------------ | -| `ListOrder` | `DESC`, `ASC` | -| `PolicySortColumn`| `POLICY_CREATION_TIME`, `POLICY_NAME` | - -### 1.2 Interfaces (`model.ts`) - -| Name | Purpose | -| ------------------------------- | --------------------------------------------- | -| `CreatePolicyRequest` | Request body for create. | -| `CreatePolicyRequest_Response` | Response from create (proto-style suffix). | -| `DeletePolicyRequest` | Request body for delete. | -| `DeletePolicyRequest_Response` | Empty response from delete. | -| `EditPolicyRequest` | Request body for update/edit. | -| `EditPolicyRequest_Response` | Empty response from edit. | -| `GetPolicyRequest` | Request body for get. | -| `Library` | Discriminated-union wrapper around `lib`. | -| `ListPoliciesRequest` | Request body for list. | -| `ListPoliciesRequest_Response` | Response from list. | -| `MavenLibrary` | Maven coordinates payload. | -| `Policy` | The cluster-policy entity. | -| `PythonPyPiLibrary` | PyPI package payload. | -| `RCranLibrary` | CRAN R package payload. | - -### 1.3 Fields (entity / request / response — combined catalog) - -| Type | Field | Type / Notes | -| --------------------------------- | ---------------------------------- | ----------------------------- | -| `CreatePolicyRequest` | `name` | `string?` | -| `CreatePolicyRequest` | `definition` | `string?` | -| `CreatePolicyRequest` | `description` | `string?` | -| `CreatePolicyRequest` | `policyFamilyId` | `string?` | -| `CreatePolicyRequest` | `policyFamilyDefinitionOverrides` | `string?` | -| `CreatePolicyRequest` | `maxClustersPerUser` | `number?` | -| `CreatePolicyRequest` | `libraries` | `Library[]?` | -| `CreatePolicyRequest_Response` | `policyId` | `string?` | -| `DeletePolicyRequest` | `policyId` | `string?` | -| `EditPolicyRequest` | `policyId` | `string?` | -| `EditPolicyRequest` | `name` … `libraries` | (same shape as `CreatePolicyRequest`) | -| `GetPolicyRequest` | `policyId` | `string?` | -| `Library` | `lib` | discriminated union | -| `Library.lib.$case` | `jar`/`egg`/`pypi`/`maven`/`cran`/`whl`/`requirements` | union tag | -| `ListPoliciesRequest` | `sortOrder` | `ListOrder?` | -| `ListPoliciesRequest` | `sortColumn` | `PolicySortColumn?` | -| `ListPoliciesRequest_Response` | `policies` | `Policy[]?` | -| `MavenLibrary` | `coordinates` | `string?` | -| `MavenLibrary` | `repo` | `string?` | -| `MavenLibrary` | `exclusions` | `string[]?` | -| `Policy` | `policyId` | `string?` | -| `Policy` | `creatorUserName` | `string?` | -| `Policy` | `createdAtTimestamp` | `number?` | -| `Policy` | `isDefault` | `boolean?` | -| `Policy` | `name` | `string?` | -| `Policy` | `definition` | `string?` | -| `Policy` | `description` | `string?` | -| `Policy` | `policyFamilyId` | `string?` | -| `Policy` | `policyFamilyDefinitionOverrides` | `string?` | -| `Policy` | `maxClustersPerUser` | `number?` | -| `Policy` | `libraries` | `Library[]?` | -| `PythonPyPiLibrary` | `package` | `string?` (reserved word) | -| `PythonPyPiLibrary` | `repo` | `string?` | -| `RCranLibrary` | `package` | `string?` (reserved word) | -| `RCranLibrary` | `repo` | `string?` | +## Summary -### 1.4 Methods (`client.ts`) +| Severity | Count | +| --------- | ----- | +| High | 0 | +| Medium | 3 | +| Low | 0 | +| **Total** | **3** | -| Method | Verb | Returns | -| --------------- | ---- | ------------------------------- | -| `createPolicy` | POST | `CreatePolicyRequest_Response` | -| `deletePolicy` | POST | `DeletePolicyRequest_Response` | -| `editPolicy` | POST | `EditPolicyRequest_Response` | -| `getPolicy` | GET | `Policy` | -| `listPolicies` | GET | `ListPoliciesRequest_Response` | - -### 1.5 Other identifiers - -- `client.ts`: `Client` class (public, top-level export). +Total weird names flagged: 3. --- -## 2. Findings by Category - -### 2.1 Vague / generic names — High & Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| V-01 | `Policy.description` (`model.ts:228`), `CreatePolicyRequest.description` (`model.ts:26`), `EditPolicyRequest.description` (`model.ts:74`) | Low | Generic but standard across the SDK; acceptable. | - -### 2.2 Redundant enum prefixes - -_None._ - -### 2.3 Acronym casing inconsistencies — High - -| ID | Symbol | Severity | Issue | -| ----- | --------------------- | -------- | ----- | -| A-01 | `PythonPyPiLibrary` (`model.ts:251`) | High | "PyPI" is a proper acronym (Python Package Index). The chosen casing `PyPi` is non-standard — official sources write **PyPI** (see https://pypi.org/ and PEP 541). Should be `PythonPyPILibrary`. | -| A-02 | `RCranLibrary` (`model.ts:264`) | Medium | "CRAN" is an acronym ("Comprehensive R Archive Network"). The type uses `Cran` (PascalCase) which is acceptable under Google TS style (acronyms ≥3 chars → only first letter capitalised). However, the JSDoc and surrounding usage refers to "CRAN library". Consistent with the rule but worth noting — peer types like `PolicySortColumn` keep full uppercase in member names. Leave as-is for Google style compliance. | - -### 2.4 Underscores in TS identifiers - -_None._ - -### 2.5 Cryptic abbreviations — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------- | -------- | ----- | -| C-01 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Maven term, OK in context. | - -### 2.6 Misleading names — High - -_None._ - -### 2.7 Overly verbose / Redundant suffixes — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| O-01 | `Policy.maxClustersPerUser` (`model.ts:246`) | Low | Long but precise. | - -### 2.8 Singular / plural mismatches — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| P-01 | `ListPoliciesRequest` (`model.ts:166`) vs `listPolicies()` (`client.ts:190`) | Low | The request type is plural to match the API verb; the method matches. Consistent. | -| P-02 | `ListPoliciesRequest_Response.policies` (`model.ts:183`) | Low | Plural field for an array — correct. | -| P-03 | `MavenLibrary.exclusions` (`model.ts:201`) | Low | Plural for array — correct. | - -### 2.9 Reserved-word collisions — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| R-01 | None of the type names collide. | — | OK. | - -### 2.10 Empty / trivial wrapper types — Medium - -_None._ - -### 2.11 Duplicate concepts — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| D-01 | `CreatePolicyRequest` (`model.ts:17`) vs `EditPolicyRequest` (`model.ts:63`) | Medium | The two request types are byte-identical except `EditPolicyRequest` adds `policyId`. Could share a base type. Codegen constraint, but readers see two near-duplicate 7-field interfaces. | -| D-02 | `Policy` (`model.ts:205`) vs `CreatePolicyRequest` (`model.ts:17`) vs `EditPolicyRequest` (`model.ts:63`) | Medium | Same body fields duplicated three times (with the entity adding `creatorUserName`, `createdAtTimestamp`, `isDefault`). Tooling could share a base. | -| D-03 | `definition` and `policyFamilyDefinitionOverrides` (`model.ts:24, 42`, `model.ts:72, 90`, `model.ts:226, 244`) | Low | Distinct concepts (full definition vs. override deltas), but the names alone don't communicate "two mutually exclusive ways of supplying a definition". The JSDoc explains the relationship; OK. | - -### 2.12 Verb-tense inconsistency — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| T-01 | `createPolicy`, `deletePolicy`, `editPolicy`, `getPolicy`, `listPolicies` (`client.ts`) | Low | All imperative present-tense — consistent. | -| T-02 | `createdAtTimestamp` (`model.ts:214`) | Low | Past participle, correct for a timestamp field. | -| T-03 | `isDefault` (`model.ts:219`) | Low | Standard `is*` boolean prefix. Consistent with the rest of the SDK. | - -### 2.13 Go / Java-style names — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| G-01 | `MavenLibrary` (`model.ts:187`), `PythonPyPiLibrary` (`model.ts:251`), `RCranLibrary` (`model.ts:264`) (suffix `Library` repeated) | Low | Java-style "TypeNameTypeSuffix" pattern. See § 2.19 for the type-suffix tautology angle. | - -### 2.14 Generic field names losing meaning — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| F-01 | `Policy.name` (`model.ts:224`), `Policy.description` (`model.ts:228`) | Low | Standard entity fields; meaning preserved in context. | -| F-02 | `MavenLibrary.coordinates` (`model.ts:189`) | Low | Maven-specific; precise. | - -### 2.15 Field contradicting type domain — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| C-01 | None observed. | — | All fields are domain-appropriate for the cluster-policy context. | - -### 2.16 Inconsistent action verbs — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| AV-01 | `getPolicy()` (`client.ts:159`, singular) vs `listPolicies()` (`client.ts:190`, plural) | Low | Correct convention (singular get, plural list). Consistent. | - -### 2.17 Long enum values - -_None._ - -### 2.18 Underspecified IDs — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| I-01 | `policyId` (`model.ts:52, 57, 65, 102, 207`) | Low | Well-specified: scope = policy. No collision with workspace / account / cluster IDs in this package. Good. | -| I-02 | `policyFamilyId` (`model.ts:34, 82, 236`) | Low | Scoped correctly. Good. | - -(Section retained for parity with the rubric; no high findings in this package.) - -### 2.19 Type-suffix tautology — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `MavenLibrary` (`model.ts:187`) | Medium | The type already lives in a `Library` discriminated union; the `Library` suffix is redundant when accessed as `library.lib.$case === 'maven' ? library.lib.maven : ...` — the value's *position* in the union already identifies it as a library variant. `MavenSpec` or just `Maven` would suffice. | -| TS-02 | `PythonPyPiLibrary` (`model.ts:251`) | Medium | Same as TS-01. Could be `PyPISpec`. | -| TS-03 | `RCranLibrary` (`model.ts:264`) | Medium | Same as TS-01. Could be `CRANSpec`. | - -### 2.20 Other observations - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| X-01 | `Policy.createdAtTimestamp` (`model.ts:214`, epoch ms, `number`) | Medium | JS `Date` has a 53-bit safe-integer range that covers epoch-ms until year 285,000+, but a TS SDK conventionally exposes either `Date`, `string` (ISO-8601), or `bigint`. `number` is acceptable for ms timestamps; flagged. | - -### 2.21 Proto / architectural-leak naming - -_None._ Scanned all identifiers in `model.ts`, `client.ts`, and -`index.ts` for mid-position `Public`/`Internal`/`External` (non-domain), -`Proto` suffix/infix, `Service`/`Server`/`Backend`/`Frontend`, `Rpc`/`Grpc`, -`Manager`/`Handler`/`Controller`/`Processor`/`Daemon`/`Worker` (non-domain), -`Impl`, `Proxy` (non-real), `Action`/`Op` mid duplicating a verb, -`Wrapper`/`Adapter`, `Old`/`New`/`Legacy`/`Modern`, `V1`/`V2` mid, -`Api`/`Sdk`/`Client` mid, repeated `Spec`/`Config`/`Details`/`Info`, and -`Foo_PublicRequest` shapes. No matches: the only `Client` is the top-level -exported class (terminal position, standard SDK convention), and there are no -architectural-layer words leaking into domain identifiers. - ---- - -## 3. Summary - -### 3.1 Findings by severity - -| Severity | Count | -| -------- | ----- | -| High | 1 | -| Medium | 7 | -| Low | 16 | -| **Total**| **24**| - -### 3.2 Top themes +## Medium -1. **`PyPi` casing should be `PyPI`** (acronym); the type name - `PythonPyPiLibrary` should be `PythonPyPILibrary`. +### 1. `MavenLibrary` (`model.ts:185`) -2. **Type-suffix tautology in the `Library` union**: `MavenLibrary`, - `PythonPyPiLibrary`, `RCranLibrary` all repeat the `Library` suffix even - though their *position* in the discriminated union already identifies - them as library variants. +Type-suffix tautology. The type already lives in a `Library` discriminated +union; the `Library` suffix is redundant when accessed as +`library.lib.$case === 'maven' ? library.lib.maven : ...` — the value's +*position* in the union already identifies it as a library variant. +`MavenSpec` or just `Maven` would suffice. -### 3.3 Suggested quick wins (non-breaking renames are not possible — this -section is advisory for the codegen owners) +### 2. `PythonPyPiLibrary` (`model.ts:249`) -- `PythonPyPiLibrary` -> `PythonPyPILibrary`. +Type-suffix tautology. Same as finding 1. Could be `PyPISpec`. -### 3.4 Cross-package consistency notes +### 3. `RCranLibrary` (`model.ts:262`) -_None._ +Type-suffix tautology. Same as finding 1. Could be `CRANSpec`. diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index cf001f62..6e68b728 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -2,124 +2,29 @@ **Path:** `packages/clusters/src/v2/` **Versions audited:** v2 -**Inferred domain:** Databricks Spark cluster lifecycle (create/edit/start/restart/resize/delete/permanent-delete/pin/unpin/update/get/list), node-type catalogue, Spark-version catalogue, availability zones, and cluster-policy compliance. -**Total weird names flagged:** 20 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | -| High | 2 | -| Medium | 16 | -| Low | 2 | -| Observation | 0 | - -## High severity - -### 1. `AzureAvailability.SPOT_AZURE` / `ON_DEMAND_AZURE` / `SPOT_WITH_FALLBACK_AZURE` — `src/v2/model.ts:28-37` -- **Why weird:** Every enum value redundantly re-states the enum's cloud (`_AZURE`). Same for `GcpAvailability.PREEMPTIBLE_GCP` / `ON_DEMAND_GCP` / `PREEMPTIBLE_WITH_FALLBACK_GCP` (`model.ts:151-154`). Compare with `AwsAvailability` (`model.ts:12-22`) where AWS-specific values are unprefixed (`SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK`). Three sibling enums, three different conventions — the `_AZURE`/`_GCP` suffix is a cloud tag, not a proto-style enum-name prefix, and it makes cross-cloud asymmetry visible at the call site. -- **Category:** 17 (inconsistent across the AWS/Azure/GCP triplet). -- **Suggested name:** Either drop `_AZURE`/`_GCP` from Azure/GCP to match AWS, or add the cloud suffix back to AWS (`SPOT_AWS`, `ON_DEMAND_AWS`, `SPOT_WITH_FALLBACK_AWS`). Pick one. -- **Rationale:** Cross-cloud asymmetry — the AWS triplet says one thing, Azure/GCP triplets say another. Either all three carry the cloud tag or none do. - -### 2. `DataSecurityMode` duplicate-concept aliases — `src/v2/model.ts:99-134` -- **Why weird:** The enum's JSDoc itself notes some values are aliases: "`DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`" and "`DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`". So the enum has duplicate values for the same concept under different names. -- **Category:** 12 (duplicate concepts: STANDARD alias for USER_ISOLATION; DEDICATED alias for SINGLE_USER). -- **Suggested name:** Pick one of each aliased pair and document deprecation on the other. -- **Rationale:** Public SDK enums should not ship two members for one concept; one of each pair should be `@deprecated`. +| Medium | 3 | +| Low | 1 | ## Medium severity -### 3. `Adlsgen2Info` casing — `src/v2/model.ts:917` -- **Why weird:** Type name is `Adlsgen2Info` — should be `AdlsGen2Info` to match acronym-casing rules. ADLS (Azure Data Lake Storage) Gen2 should retain the boundary between `Adls` and `Gen2`. -- **Category:** 3 (acronym casing inconsistency), 1 (vague `Info` suffix). -- **Suggested name:** `AdlsGen2Storage` (or just `AbfssStorage`, since the wire name is `abfss`). -- **Rationale:** Compare to sibling types `DbfsStorageInfo`, `GcsStorageInfo`, `S3StorageInfo` — all use `Info` suffix and capitalize the storage product. `Adlsgen2Info` is the odd one out. - -### 4. `*StorageInfo` family naming inconsistency — `src/v2/model.ts:917,2101,2509,2875,3044,3391,3414` -- **Why weird:** `Adlsgen2Info` (no `Storage`), `DbfsStorageInfo`, `GcsStorageInfo`, `LocalFileInfo` (no `Storage`), `S3StorageInfo`, `VolumesStorageInfo`, `WorkspaceStorageInfo`. Seven sibling types; five say `StorageInfo`, two say `Info`. -- **Category:** 17 (inconsistent suffix across siblings). -- **Suggested name:** Standardise on `XStorage` (drop the redundant `Info`) — `AdlsGen2Storage`, `DbfsStorage`, `GcsStorage`, `LocalFileStorage`, `S3Storage`, `VolumesStorage`, `WorkspaceStorage`. -- **Rationale:** All seven describe the same kind of thing (a storage destination). Either all of them get `StorageInfo` or none do. - -### 5. `ClusterCompliance` vs `*PolicyCompliance*` naming — `src/v2/model.ts:1253,2350,2361,2595,2812` -- **Why weird:** The package has `ClusterCompliance` (a result type), `GetPolicyComplianceForClusterRequest` (a request), `GetPolicyComplianceForClusterRequest_Response`, `EnforcePolicyComplianceForClusterRequest` (request), `ListClusterComplianceForPolicyRequest` (request — opposite direction). Each combines `Policy`/`Cluster`/`Compliance` in a different order. Reading them, it's not obvious which is "policies compliant with cluster" vs "clusters compliant with policy". The verb `For` is the disambiguator — fragile. -- **Category:** 1 (vague — `For` is the only disambiguator), 6 (misleading — easy to mis-parse). -- **Suggested name:** `GetClusterPolicyComplianceRequest`, `EnforceClusterPolicyComplianceRequest`, `ListPolicyCompliantClustersRequest`, `ClusterPolicyCompliance`. -- **Rationale:** Put the noun before the preposition; the `For` framing reads like SQL and is order-sensitive. - -### 6. `hasChanges` field — `src/v2/model.ts:2366` -- **Why weird:** Boolean on `EnforcePolicyComplianceForClusterRequest_Response` named `has*` next to `changes: ClusterSettingsChange[]`. `hasChanges` is true iff `changes.length > 0` — redundant signal. -- **Category:** 12 (duplicate signal), 1 (vague). -- **Suggested name:** Drop the field, infer from `changes.length`. -- **Rationale:** Two ways to express the same predicate is one too many. Worth flagging upstream. - -### 7. `useMlRuntime` field — `src/v2/model.ts:1210` -- **Why weird:** Boolean prefixed `use*`. Doc says "This field can only be used when kind = CLASSIC_PREVIEW". Mixed with the broader `runtimeEngine` enum field; two fields combine to determine the runtime. `useMlRuntime: boolean` next to `runtimeEngine: RuntimeEngine` — incongruent shape. -- **Category:** 1 (vague — `use` prefix); 6 (misleading — looks like a generic feature toggle but is conditional on `kind`); 17 (boolean + enum for the same concept). -- **Suggested name:** Either fold into `runtimeEngine` (add `ML` value) or rename `useMlRuntime` to `mlRuntimeEnabled` for consistency. -- **Rationale:** A boolean and an enum jointly describing one runtime selection is a boolean-shaped-enum smell. - -### 8. `WorkloadType` vs `runtimeEngine` vs `kind` vs `dataSecurityMode` — overlap of "cluster mode"-ish fields -- **Why weird:** Four fields all describe some aspect of "what kind of cluster this is": `workloadType` (notebooks/jobs), `runtimeEngine` (STANDARD/PHOTON), `kind` (CLASSIC_PREVIEW or unset), `dataSecurityMode` (NONE/SINGLE_USER/USER_ISOLATION/…). Each is a separate optional enum/object. The names don't cluster well. -- **Category:** 12 (duplicate concept across fields), 1 (vague — `kind` and `workloadType` both could mean either thing). -- **Suggested name:** Consider grouping under a `clusterMode` substructure, or at least documenting the relationships. -- **Rationale:** Domain-level — flag to upstream that four overlapping enum/struct fields make the API hard to learn. - -### 9. `NodeInstanceType.localDiskSizeGb` / `localNvmeDiskSizeGb` ordering — `src/v2/model.ts:2910,2912` -- **Why weird:** `localDisks`, then `localDiskSizeGb`, then `localNvmeDiskSizeGb`, then `localNvmeDisks` — the size of the nvme disks comes before the count of nvme disks, and the size of the regular disks comes between regular and nvme. Pairings are scrambled. -- **Category:** 17 (inconsistent grouping). -- **Suggested name:** Reorder fields, or rename to make the pairs clear: `localDiskCount`/`localDiskSizeGb`, then `localNvmeDiskCount`/`localNvmeDiskSizeGb`. -- **Rationale:** Within the same type, related fields should sit together. - -### 10. `clusterLogStatus` field — `src/v2/model.ts:1330` +### 1. `clusterLogStatus` field typed `LogSyncStatus` — `src/v2/model.ts:1330` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). -- **Suggested name:** Either rename the type to `ClusterLogStatus` or the field to `logSyncStatus`. +- **Suggested name:** Rename the type to `ClusterLogStatus` to match the field. - **Rationale:** Same concept, two different names in 5 lines. -### 11. `jdbcPort` field — `src/v2/model.ts:1358` -- **Why weird:** All-lowercase acronym fragment. The package consistently uses Pascal-form for acronyms in identifiers elsewhere (`awsAttributes`, `gcpAttributes`, `ebsVolumeType`, `kmsKey`). `JdbcPort` would match. -- **Category:** 3 (acronym casing inconsistency). -- **Suggested name:** `JdbcPort` (TS: `jdbcPort` is conventional in camelCase; flagged because the doc-text says "Spark JDBC server" — capitalisation in JSDoc says JDBC, identifier says jdbc). -- **Rationale:** Per the package conventions (`Aws`, `Gcp`, `Ebs`, `Kms`), `Jdbc` is actually consistent — but `Dns`, `Ip`, `Url`, `Iam`, `Vm` are inconsistent across the model (see #12). - -### 12. Pervasive acronym-casing inconsistency (`Aws`, `Gcp`, `Ebs`, `Kms` vs `IP`, `DNS`, `URL`, `IAM`, `VM`) — across `model.ts` -- **Why weird:** The TS code uses PascalCase initial-capital for some acronyms (`Aws`, `Azure`, `Gcp`, `Ebs`, `Kms`, `Adls`, `Gcs`, `Dbfs`, `Acl`, `Arn`) but JSDoc and string constants use all-caps (`AWS`, `Azure`, `GCP`, `EBS`, `KMS`). Within enum values, all-caps wins (`AWS_AUTHORIZATION_FAILURE`). Type names mix: `AwsAttributes` but `S3StorageInfo` (S3 is all-caps). Field names mix: `privateIp` (lowercase ip), `publicDns` (lowercase dns), `kmsKey` (lowercase kms). -- **Category:** 3 (acronym casing inconsistency). -- **Suggested name:** Pick one rule. Google TS style guide allows either `httpRequest` or `HTTPRequest` but requires consistency. -- **Rationale:** This is the single highest-friction naming issue across the package — every reader stumbles on it. - -### 13. `S3StorageInfo.cannedAcl: string` — `src/v2/model.ts:3079` -- **Why weird:** `Acl` is AWS terminology; field is typed `string` rather than a `CannedAcl` enum despite AWS having a fixed canned-ACL list. JSDoc says "Set canned access control list for the logs, e.g. `bucket-owner-full-control`". Also note `cannedCal` typo in the doc body — likely meant `cannedAcl`. -- **Category:** 5 (cryptic abbreviation — `acl`), 16 (typed as string but values are enum-like), 3 (acronym casing — should it be `cannedACL`?). -- **Suggested name:** Type as an enum (`CannedS3Acl`); field `cannedAcl` is fine. -- **Rationale:** Typing as string surfaces every user's typo as a runtime failure when an enum would catch at compile time. - -### 14. `S3StorageInfo.enableEncryption` + `encryptionType` + `kmsKey` — `src/v2/model.ts:3062,3067,3069` -- **Why weird:** Three independent fields encoding what could be one discriminated union: `enableEncryption=false` → no encryption; `enableEncryption=true, encryptionType='sse-s3'` → SSE-S3; `enableEncryption=true, encryptionType='sse-kms', kmsKey='...'` → SSE-KMS. Cross-field invariants encoded by convention. -- **Category:** 12 (duplicate concepts), 17 (could be a tagged union). -- **Suggested name:** Either nest these as a `S3Encryption` discriminated union, or rename to make the dependency explicit (`encryption: 'none' | 'sse-s3' | 'sse-kms'`). -- **Rationale:** Three booleans/strings tangled — easier API would be one discriminated field. - -### 15. `SparkInfo` empty interface as proto namespace anchor — `src/v2/model.ts:3087` -- **Why weird:** `SparkInfo` is declared as an empty interface (`export interface SparkInfo {}`) whose JSDoc literally says "This is used in both the [[ClusterInfo]] for Cluster APIs and persisted cluster proto." Its only purpose is to namespace `SparkInfo_SparkNode` and `SparkInfo_SparkNode_SparkNodeAwsAttributes`. Empty wrapper types tied to "persisted cluster proto" are pure proto-architectural leak — the TS surface carries a do-nothing type just to mirror proto message nesting. -- **Category:** 14 (proto-style namespace anchor), 8 (JSDoc references the proto wire layer). -- **Suggested name:** Delete `SparkInfo`; expose `SparkNode` (and `SparkNodeAwsAttributes`) as top-level types. -- **Rationale:** TS doesn't need proto-style nesting; the empty parent interface is a generator artefact and a user-facing footgun (auto-completion shows a useless symbol). - -### 16. `ClusterEventType` empty interface as proto namespace anchor — `src/v2/model.ts:1286` -- **Why weird:** `export interface ClusterEventType {}` is declared empty solely so the generator can nest the enum `ClusterEventType_ClusterEventType` under it. The doubly-nested `ClusterEventType_ClusterEventType` name (see #17) is the smoking gun — the parent exists only to host the child. -- **Category:** 14 (proto-style namespace anchor). -- **Suggested name:** Delete `ClusterEventType` (the parent) and flatten the enum to a top-level `ClusterEventType` enum. The empty wrapper adds no value. -- **Rationale:** Same as #15 — TS does not have proto's "message that contains an enum" pattern; the wrapper is a generator artefact. - -### 17. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` -- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. In TS, the parent message (#16) is empty, so the doubly-stuttered name carries no information. +### 2. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` +- **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. The repeated identifier carries no information. - **Category:** 14 (proto nesting stutter), 4 (redundant repetition). - **Suggested name:** `ClusterEventType` (single, top-level). -- **Rationale:** After deleting the empty parent (#16), the child can drop the `ClusterEventType_` prefix entirely. +- **Rationale:** Drop the redundant `ClusterEventType_` prefix; the doubly-stuttered name repeats the same word with no added meaning. -### 18. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2093` +### 3. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2092` - **Why weird:** "Data plane" is an internal Databricks infrastructure concept (vs "control plane") — not a customer-facing domain term. Two public types prefix their names with the deployment-plane they originate from. A user creating a cluster does not need to know which plane emitted which event class; the distinction is a Databricks-internal architecture detail. - **Category:** 8 (internal architecture leak in public surface). - **Suggested name:** Either merge into a single `ClusterEventType` enum / `EventDetails` shape, or rename to a non-infrastructure word (e.g., `RuntimeEventDetails`). @@ -127,72 +32,8 @@ ## Low severity -### 19. `DockerImage.credsOneof` field name — `src/v2/model.ts:2124` -- **Why weird:** `credsOneof` is a discriminated-union container with a single `$case: 'basicAuth'` variant. The `Oneof` suffix leaks proto terminology; `Creds` is an abbreviation of `Credentials`. -- **Category:** 5 (cryptic abbreviation), 14 (proto-style `Oneof`). -- **Suggested name:** `credentials` (singular). -- **Rationale:** TS doesn't need to keep the `Oneof` suffix from proto. - -### 20. `AutoScale` type name — `src/v2/model.ts:922` +### 4. `AutoScale` type name — `src/v2/model.ts:922` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). - **Rationale:** Matches sibling naming (`autoscale: Autoscale`). - -## Observations - -_None._ - -## Domain glossary - -- `dbfs` — Databricks File System. -- `dbr` — Databricks Runtime (cluster runtime image). -- `dbu` — not encountered. -- `adls` — Azure Data Lake Storage (used as `Adlsgen2Info`, wire `abfss`). -- `abfss` — Azure Blob File System Secure (wire-side name for ADLS Gen2 destinations). -- `gcs` — Google Cloud Storage. -- `s3` — Amazon S3. -- `wsfs` — Workspace File System (per `WorkspaceStorageInfo` JSDoc). -- `ebs` — Elastic Block Store (AWS). -- `kms` — Key Management Service (AWS/GCP). -- `iam` — Identity and Access Management (AWS). -- `cmk` — Customer-Managed Key (`AZURE_BYOK_*`, `GCP_INACCESSIBLE_KMS_KEY_FAILURE` JSDoc). -- `byok` — Bring Your Own Key (cloud-key terminology, used in `AZURE_BYOK_KEY_PERMISSION_FAILURE`). -- `byoc` — Bring Your Own Container (used in JSDoc `"Custom docker image BYOC"`). -- `byo-vpc`, `byo-vnet` — Bring Your Own VPC/VNet (mentioned in JSDoc for `SLOW_IMAGE_DOWNLOAD`). -- `acl` — Access Control List. -- `arn` — Amazon Resource Name. -- `vpc` — Virtual Private Cloud (AWS). -- `vnet` — Virtual Network (Azure). -- `vm` — Virtual Machine. -- `gpu` — Graphics Processing Unit. -- `nvme` — Non-Volatile Memory Express (storage). -- `sse-s3` / `sse-kms` — Server-Side Encryption (S3 algorithms). -- `gke` — Google Kubernetes Engine (`GKE_BASED_CLUSTER_TERMINATION`). -- `k8s` — Kubernetes (used throughout `TerminationCode`). -- `repl` — Read-Eval-Print Loop (Spark REPL, per `model.ts:1343`). -- `jdbc` — Java Database Connectivity. -- `dns` — Domain Name System. -- `nic` — Network Interface Card (per `NETWORK_CHECK_NIC_FAILURE`). -- `nfs` — Network File System (per `NFS_MOUNT_FAILURE`). -- `npip` — No Public IP (Databricks networking jargon). -- `pat` — Personal Access Token (per `model.ts:603`). -- `sdp` — implied by client.ts:834 ("Databricks Jobs, SDP, or Models services"). Likely "Serverless Data Platform" or "Streaming Data Pipelines". -- `cmv1` / `cmv2` — Cluster Manager v1/v2 (Databricks internal scheduler generations). -- `imv2` — Instance Manager v2 (Databricks internal infra, per `INVALID_WORKER_IMAGE_FAILURE`). -- `nephos` — Internal serverless infra name (per `NEPHOS_RESOURCE_MANAGEMENT`). -- `cmk` — Customer-Managed Key. -- `chauffeur` — Internal Databricks driver-orchestration daemon (per `DRIVER_UNREACHABLE`). -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). -- `sts` — AWS Security Token Service (per `STS_CLIENT_SETUP_FAILURE`). -- `cprf` / `cplf` — Control Plane Request Failure / Cloud Provider Launch Failure (per `model.ts:629-631`). -- `sev_snp` — AMD Secure Encrypted Virtualization — Secure Nested Paging (GCP confidential VM, per `model.ts:70`). -- `csp` — Cloud Service Provider (per `is_csp_unified` in `model.ts:682`). -- `luks` — Linux Unified Key Setup (disk encryption, per `enableLocalDiskEncryption` JSDoc). -- `uc` — Unity Catalog (referenced in `VolumesStorageInfo`). -- `aip` — API Improvement Proposal (`https://google.aip.dev/161` referenced in `updateMask` field doc). - -## File coverage -- `src/v2/model.ts` (5315 lines): read fully (in 800-line chunks). -- `src/v2/client.ts` (1523 lines): read fully. -- `src/v2/utils.ts` (150 lines): read fully. diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index 97b6fa02..588057e0 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -6,15 +6,6 @@ **Files audited:** `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/utils.ts`, `src/v2/index.ts`. -This audit flags naming issues using the 20-category framework. Each finding -has: ID, location, current name, category, severity, problem, and proposed -name. Severity scale: **high** (public API confusing, blocks readability), **medium** -(inconsistency, minor cognitive load), **low** (polish). - -The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a -`Context` (REPL session) on a `Cluster`. Three resources mix freely in names — -**this is the dominant source of naming pain.** - --- ## Summary of Findings @@ -22,29 +13,24 @@ The domain centres on a `Command` (Python/SQL/Scala/R code), executed inside a | # | Severity | Category | Location | Current | Proposed | | -- | -------- | -------- | -------- | ------- | -------- | | 1 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | -| 2 | high | 12. Duplicate concepts | `model.ts:70` vs `client.ts:286-309` | `CreateResponse` reused for `execute()` | Split: `CreateContextResponse`, `ExecuteCommandResponse` | -| 3 | high | 17. Inconsistent action verbs | `client.ts:256` vs URL `contexts/destroy` | `destroy()` vs Go SDK convention `delete` | Pick one; SDK-wide rule should drive choice | -| 4 | high | 17. Inconsistent action verbs | `client.ts:139,176` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | -| 5 | high | 16. Field contradicts type domain | `model.ts:117-143` | `Results` (plural) for single-command result | `Result` | -| 6 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | -| 7 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | -| 8 | medium | 13. Verb-tense inconsistency | `model.ts:23-28` | `CANCELLED`, `CANCELLING`, `ERROR`, `FINISHED`, `QUEUED`, `RUNNING` | Mix of past, present, and noun. Normalise to a single form (e.g. `Failed` in place of `Error` so every member is a past/present participle). | -| 9 | medium | 12. Duplicate concepts | `client.ts:286,289` | `execute()` returns `CreateResponse` | Type repurpose conflates "context created" vs "command queued" | -| 10 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:256` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 11 | medium | 8. Redundant suffix — call-out | `client.ts:333, 417, 498` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 12 | medium | 6. Misleading name | `client.ts:417` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 13 | medium | 6. Misleading name | `client.ts:333` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 14 | medium | 6. Misleading name | `client.ts:498` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 15 | medium | 17. Inconsistent action verbs | `client.ts:86,256` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 16 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | -| 17 | low | 3. Acronym casing | `model.ts:42-43` | `SQL`, `R` enum values | Mixed-length acronym/single-letter values; `Sql` and `R` if camelCased — keep all-caps consistently | +| 2 | high | 17. Inconsistent action verbs | `client.ts:144,184` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | +| 3 | high | 16. Field contradicts type domain | `model.ts:116-143` | `Results` (plural) for single-command result | `Result` | +| 4 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | +| 5 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | +| 6 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:270` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 7 | medium | 8. Redundant suffix — call-out | `client.ts:353, 430, 504` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | +| 8 | medium | 6. Misleading name | `client.ts:430` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 9 | medium | 6. Misleading name | `client.ts:353` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 10 | medium | 6. Misleading name | `client.ts:504` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | +| 11 | medium | 17. Inconsistent action verbs | `client.ts:88,270` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | +| 12 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | --- ## Detailed Findings ### Finding 1 — High — Cat 4 (Underscores in TS identifiers) -**Location:** every enum member in `model.ts:22-53`. +**Location:** every enum member in `model.ts:22-52`. **Issue:** TS identifier convention is PascalCase for type-namespace members. `COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`, `SCALA` are all SHOUTY_SNAKE_CASE, which violates the Google TypeScript style guide @@ -66,42 +52,8 @@ export enum CommandStatus { --- -### Finding 2 — High — Cat 12 (Duplicate concepts) -**Location:** `src/v2/model.ts:70` and `src/v2/client.ts:289` -```ts -export interface CreateResponse { - id?: string | undefined; -} -... -async execute(req: ExecuteCommandRequest, ...): Promise -``` -`CreateResponse` is used for *both* `create()` (returns a context id) and -`execute()` (returns a command id). The type's name implies "creation", -but `execute()` is not a creation operation in the public-API sense — the -shared shape is incidental, not semantic. Reusing the type forces a -caller reading `response.id` to know the operation to interpret it. -**Proposed:** split into `CreateContextResponse` and -`ExecuteCommandResponse`. - ---- - -### Finding 3 — High — Cat 17 (Inconsistent action verbs) -**Location:** `src/v2/client.ts:256` -```ts -/** Deletes an execution context. */ -async destroy(req: DestroyContextRequest, ...) -``` -The JSDoc says "Deletes" while the method is named `destroy`. The URL is -`/api/1.2/contexts/destroy`. Three different verbs (`destroy`, `delete`, plus -`cancel` for commands) live in the same domain. -**Proposed:** keep `destroy` if the backend route is canonical; otherwise -align with the Go SDK convention. At minimum, edit the JSDoc to say -"Destroys" so name and doc agree. - ---- - -### Finding 4 — High — Cat 17 (Inconsistent action verbs) -**Location:** `src/v2/client.ts:139, 176` +### Finding 2 — High — Cat 17 (Inconsistent action verbs) +**Location:** `src/v2/client.ts:144, 184` ```ts async commandStatus(req: GetCommandStatusRequest, ...) async contextStatus(req: GetContextStatusRequest, ...) @@ -115,8 +67,8 @@ the request-type name and is verb-led like the other methods. --- -### Finding 5 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) -**Location:** `src/v2/model.ts:117-143` +### Finding 3 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +**Location:** `src/v2/model.ts:116-143` ```ts export interface Results { ... } ``` @@ -128,7 +80,7 @@ inside it, not from multiple results. --- -### Finding 6 — Medium — Cat 7 (Overly verbose) +### Finding 4 — Medium — Cat 7 (Overly verbose) **Location:** `src/v2/model.ts:99, 111` ```ts export interface GetCommandStatusResponse { ... } @@ -142,7 +94,7 @@ returned", not "the response to a GET". --- -### Finding 7 — Medium — Cat 20 (Type-suffix tautology) — call-out only +### Finding 5 — Medium — Cat 20 (Type-suffix tautology) — call-out only **Location:** `src/v2/model.ts:55, 64, 74, 82, 93, 106` ```ts CancelCommandRequest, CreateContextRequest, DestroyContextRequest, @@ -155,32 +107,8 @@ convention is widely accepted across REST SDKs. --- -### Finding 8 — Medium — Cat 13 (Verb-tense inconsistency) -**Location:** `src/v2/model.ts:23-28` -The `CommandStatus` members mix forms: -- `CANCELLED` — past participle -- `CANCELLING` — present participle (transitional) -- `ERROR` — noun -- `FINISHED` — past participle -- `QUEUED` — past participle -- `RUNNING` — present participle - -`ERROR` is a noun; everything else is a verbal form. The odd-one-out -should be `FAILED` (past participle) to match the pattern. -**Proposed:** rename the `ERROR` member to `FAILED`. (Same applies to -`CONTEXT_ERROR` in `ContextStatus`.) - ---- - -### Finding 9 — Medium — Cat 12 (Duplicate concepts) -**Location:** `src/v2/client.ts:286-309` -**Issue:** `execute()` returns `Promise`. The conflation -of "create a context" and "execute returns an id" is artificial. See #2. - ---- - -### Finding 10 — Medium — Cat 14 (Go/Java-style names) -**Location:** `src/v2/model.ts:74` + `client.ts:256` +### Finding 6 — Medium — Cat 14 (Go/Java-style names) +**Location:** `src/v2/model.ts:74` + `client.ts:270` **Issue:** `destroy` is unusual for a REST SDK. JS conventions favour `delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend path is `/contexts/destroy`, so renaming the *method* would diverge. @@ -190,16 +118,16 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 11 — Medium — Cat 8 (Redundant suffix) — call-out -**Location:** `src/v2/client.ts:333, 417, 498` +### Finding 7 — Medium — Cat 8 (Redundant suffix) — call-out +**Location:** `src/v2/client.ts:353, 430, 504` **Issue:** Three classes named `*Waiter`. Acceptable if waiter is a recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #12-#14. +issue is what they wait *for*: see #8-#10. --- -### Finding 12 — Medium — Cat 6 (Misleading name) -**Location:** `src/v2/client.ts:417` +### Finding 8 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:430` ```ts export class CreateWaiter { ... } ``` @@ -213,26 +141,26 @@ target endpoint). --- -### Finding 13 — Medium — Cat 6 (Misleading name) -**Location:** `src/v2/client.ts:333` +### Finding 9 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:353` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 14 — Medium — Cat 6 (Misleading name) -**Location:** `src/v2/client.ts:498` +### Finding 10 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:504` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. --- -### Finding 15 — Medium — Cat 17 (Inconsistent action verbs) — call-out -**Location:** `src/v2/client.ts:86, 256` +### Finding 11 — Medium — Cat 17 (Inconsistent action verbs) — call-out +**Location:** `src/v2/client.ts:88, 270` **Issue:** This package uses three lifecycle verbs: - `cancel()` on a command, - `destroy()` on a context, -- `delete` (in JSDoc) on a context. +- `delete` on a context. Three verbs for two lifecycle actions reads awkward. **Proposed:** keep `cancel` (correct for commands — cancel is the right verb for in-flight async work). Reconcile `destroy`/`delete` per the @@ -240,48 +168,6 @@ Go-SDK alignment decision. --- -### Finding 16 — Low — Cat 15 (Generic field) — call-out +### Finding 12 — Low — Cat 15 (Generic field) — call-out **Location:** `src/v2/model.ts:67, 87` `language?: Language` is correct. - ---- - -### Finding 17 — Low — Cat 3 (Acronym casing in enum string values) -**Location:** `src/v2/model.ts:42-43` -```ts -SQL = 'SQL', -R = 'R', -``` -Identifier `SQL` is all-caps (3 letters → standard "≤3 letter acronym -all caps") in the language enum. `R` is single-letter — naturally all -caps. Apply the casing rule (#1) and these become `Sql` (if the rule is -"acronyms PascalCase") or remain `SQL`/`R` (if "≤3 letters all caps"). -**Proposed:** consult `typescript.mdc`; pick a rule and apply globally. - ---- - -## Top Themes - -1. **Enum identifier casing** — SHOUTY_SNAKE_CASE enum identifiers - (`COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`) violate the - TypeScript convention that reserves `SCREAMING_SNAKE_CASE` for - constants. PascalCase identifiers with the wire string preserved as - the value restore idiomatic TS while keeping serialisation intact. - -2. **Verb inconsistency** — `cancel` (command), `destroy` (context), - `commandStatus` (no verb), `contextStatus` (no verb), `execute` (vs - `run`), `create`/`delete`/`destroy` mixing. Add `getCommandStatus` / - `getContextStatus` and pick one of `destroy`/`delete` to settle this. - -3. **Waiter-class names** — `CancelWaiter`, `CreateWaiter`, - `ExecuteWaiter` are too short to convey what they wait for and are - genericised against the resource axis. Renaming with the resource - (`CancelCommandWaiter`, `CreateContextWaiter`, `ExecuteCommandWaiter`) - removes a recurring source of confusion. - -4. **Type reuse across operations** — `CreateResponse` is reused for both - context creation and command execution. Splitting into - `CreateContextResponse` and `ExecuteCommandResponse` clarifies the - public surface. - ---- diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 5784a746..4f31735e 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -2,126 +2,44 @@ **Path:** `packages/connections/src/v1/` **Versions audited:** v1 -**Inferred domain:** Unity Catalog Foreign Connections — create/get/list/update/delete connections to external data sources (MySQL, Snowflake, Salesforce, BigQuery, ServiceNow, GitHub, etc.) for federated query and ingestion. -**Total weird names flagged:** 14 +**Total weird names flagged:** 5 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 8 | -| Low | 0 | -| Observation | 1 | +| High | 1 | +| Medium | 4 | ## High severity -### 1. `ConnectionType` value casing — `BIGQUERY`, `POSTGRESQL`, `MYSQL`, `SQLSERVER`, `SQLDW`, `WORKDAY_RAAS`, `GA4_RAW_DATA` — `src/v1/model.ts:6-34` -- **Why weird:** Wire constants are flat SCREAMING_SNAKE but the domain has well-known camelCased product names (BigQuery, PostgreSQL, MySQL, SQL Server, Workday RaaS, GA4). Wire `BIGQUERY` is fine; TS-facing string literals lose the canonical brand casing. Some vendors collapse `POSTGRESQL` (one word, no underscore) but split `META_MARKETING`, `POWER_BI` — no consistent rule for which compound vendor names get an underscore. -- **Category:** 3 (acronym casing inconsistency across vendor names). -- **Suggested name:** Either keep wire SCREAMING_SNAKE (current) and document, or move to a `Vendor` enum with PascalCase members (`Vendor.BigQuery`, `Vendor.Postgres`, `Vendor.MySql`). -- **Rationale:** Vendor names are proper nouns. Generator emits the proto enum verbatim; TS consumers will see `ConnectionType.POSTGRESQL` rather than the canonical `PostgreSQL`. Worth raising with API-design before the surface grows further. - -### 2. `ConnectionType.SQLDW` and `SQLSERVER` (no underscore) vs `WORKDAY_RAAS`, `META_MARKETING` — `src/v1/model.ts:12-13,17,28` -- **Why weird:** Compound product names — sometimes joined (`SQLDW` = "SQL Data Warehouse", `SQLSERVER` = "SQL Server"), sometimes split with underscore (`WORKDAY_RAAS`). No rule. Comparable to `POWER_BI` (underscore) vs `BIGQUERY` (joined). -- **Category:** 3 (casing inconsistency). -- **Suggested name:** Pick one convention. If splitting on word boundaries: `SQL_DW`, `SQL_SERVER`, `BIG_QUERY`, `POWER_BI`. If joining: `WORKDAYRAAS`. Most ergonomic is to consolidate on word-split + underscores. -- **Rationale:** Internal inconsistency makes the type non-discoverable — a user typing `ConnectionType.SQL_` will autocomplete to nothing if the value is `SQLSERVER`. Probably wire-locked, but worth flagging upstream. - -### 3. `ConnectionInfo` — `src/v1/model.ts:89` +### 1. `ConnectionInfo` — `src/v1/model.ts:89` - **Why weird:** `Info` is the central domain entity — every type holds info about something. The Go SDK uses `XxxInfo` widely as a Go-style noun, but in TS the type would simply be `Connection`. `typescript.mdc` lists `Info` as a vague suffix. - **Category:** 1 (vague suffix), 8 (redundant type suffix). - **Suggested name:** `Connection`. - **Rationale:** The domain noun is "connection". Stripping `Info` improves every reference (`connection.connectionType` → `Connection.connectionType`). -### 4. `UpdateConnectionRequest.name` field — `src/v1/model.ts:236` -- **Why weird:** `UpdateConnectionRequest` has THREE name-like fields: `nameArg` (path param, identifies which), `newName` (new name), AND `name` (also documented as "Name of the connection"). Both `nameArg` and `name` are documented identically and both refer to the existing connection. Easily mis-set; ambiguous which the server uses. -- **Category:** 12 (duplicate concept), 6 (misleading — three fields mean "the name"). -- **Suggested name:** Remove `name` from `UpdateConnectionRequest` (it duplicates `nameArg`). -- **Rationale:** Three fields for one concept is a bug surface. Worth pushing to API design. - -### 5. `DeleteConnectionRequest_Response` / `ListConnectionsRequest_Response` — `src/v1/model.ts:193,214` -- **Why weird:** Proto-architectural-leak naming. The `_Response` infix on an underscore-joined identifier is a verbatim proto nested-message name (`DeleteConnectionRequest.Response`), exported into the public TS surface. `DeleteConnectionRequest_Response` is even empty (`{}`). The TS-idiomatic shape is `DeleteConnectionResponse` / `ListConnectionsResponse` (or `void` for the empty case), not a nested type tied to its sibling request. -- **Category:** Proto-architectural leak (`_Response` underscore-joined nested message name), 12 (empty type duplicates `void`). -- **Suggested name:** `DeleteConnectionResponse` / `ListConnectionsResponse` (or drop the empty one entirely; method returns `void`). -- **Rationale:** The underscore-joined `Foo_Response` pattern is a generator artefact from proto's nested-message resolution. Users see `unmarshalDeleteConnectionRequest_ResponseSchema` and `DeleteConnectionRequest_Response` in autocomplete — both leak the proto namespacing into the SDK surface. - ## Medium severity -### 6. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:118` -- **Why weird:** Type-suffix tautology. Also: the value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. -- **Category:** 20 (tautology), 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). -- **Suggested name:** Either drop the field (it's always `CONNECTION`), or rename to `securableKind: SecurableType` and document why a non-`CONNECTION` value would ever appear. +### 2. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:118` +- **Why weird:** The value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. +- **Category:** 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). +- **Suggested name:** Drop the field (it's always `CONNECTION`), or document why a non-`CONNECTION` value would ever appear. - **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. -### 7. `ConnectionInfo.readOnly: boolean` — `src/v1/model.ts:97` -- **Why weird:** Boolean field name doesn't begin with `is`/`has` as is common for TS booleans. Reads `connection.readOnly` (acceptable adjective form) but sibling enums and types use noun forms. JS naming conventions are split, but inside this SDK most booleans use the adjective form, so this is consistent — flagging at low-medium severity because the rule itself is debatable. -- **Category:** 1 (vague form — `readOnly` could be a string of mode flags). -- **Suggested name:** Keep as `readOnly` (matches Go SDK and is widely used in JS). Optionally `isReadOnly`. -- **Rationale:** No strong convention either way; flagging because audit asked for booleans whose nature isn't obvious from the name. - -### 8. `CreateConnectionRequest` / `UpdateConnectionRequest` / `ConnectionInfo` share ~18 identical fields — `src/v1/model.ts:138,230` -- **Why weird:** `CreateConnectionRequest` is `ConnectionInfo` shape. `UpdateConnectionRequest` is `ConnectionInfo + nameArg + newName + name`. Almost all fields are duplicated three times. From the type signature, you cannot tell which fields are user-settable on create vs server-set; everything is optional and present everywhere (e.g. `createdAt`, `createdBy`, `updatedBy` show up on `CreateConnectionRequest` and `UpdateConnectionRequest` even though they're server-only). -- **Category:** 12 (duplicate concepts), 6 (misleading — user-settable vs server-set is invisible). -- **Suggested name:** Split server-only metadata into a base type and compose. Better still, type create/update inputs as `Pick` or a dedicated `ConnectionInput` interface. -- **Rationale:** Today a caller could set `connection.createdAt` on a create request and have no idea it's silently ignored. Type system can prevent this. - -### 9. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:75` +### 3. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:74-75` - **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. - **Category:** 6 (misleading — value advertised but not actually a securable yet). - **Suggested name:** Hide until promotion or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. -### 10. `CredentialType.SSWS_TOKEN` — `src/v1/model.ts:52` -- **Why weird:** `SSWS` is cryptic. (Stands for "Single Sign-On Web Services" or Okta SSWS — Secure Single Sign-on. Either way, opaque.) Other tokens are named after their family (OAuth, OIDC, Bearer); SSWS is the only one with a literal product-specific acronym. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistent with sibling values). -- **Suggested name:** `OKTA_SSWS_TOKEN` (if it's strictly Okta), or document in doc-comment. -- **Rationale:** Future readers cannot guess what SSWS expands to. - -### 11. `CredentialType.EDGEGRID_AKAMAI` — `src/v1/model.ts:53` -- **Why weird:** Vendor name (`AKAMAI`) appears at the end of the enum value while sibling values put the vendor first. Inconsistent word order. -- **Category:** 17 (inconsistency). -- **Suggested name:** `AKAMAI_EDGEGRID`. -- **Rationale:** Consistency with vendor-first patterns elsewhere. - -### 12. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,272,278` +### 4. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,271,277` - **Why weird:** Proto-architectural-leak naming. Proto-style nested entry types with underscore-joined identifiers leak into the public TS surface. Each `Options` and `Properties` map gets a corresponding `*_OptionsEntry`/`*_PropertiesEntry` interface — six total — that is exported but trivial (`{key?, value?}`). The wire shape is already covered by `Record`. - **Category:** Proto-architectural leak (`_OptionsEntry` / `_PropertiesEntry` proto map-entry message names), 12 (duplicate concept), 5 (cryptic — underscore-joined identifiers). - **Suggested name:** Remove the `*Entry` interfaces from the public API; rely on `Record`. - **Rationale:** These entry types add visual noise and are not used by the surface (the field is `Record`). -### 13. `ProvisioningInfo_State` — `src/v1/model.ts:79` +### 5. `ProvisioningInfo_State` — `src/v1/model.ts:79` - **Why weird:** Proto-architectural-leak naming. Underscore-joined identifier (`ProvisioningInfo_State`) is a proto nested-enum name (`ProvisioningInfo.State`) emitted verbatim into TS. The enum is suppressed via `eslint-disable @typescript-eslint/naming-convention`, confirming it breaks TS conventions. Standalone TS would name this `ProvisioningState` (or merge into `ProvisioningInfo`). - **Category:** Proto-architectural leak (`_State` underscore-joined nested enum name). - **Suggested name:** `ProvisioningState`. - **Rationale:** Proto nesting has no analogue in TS modules; the underscore is a wire-name artefact. Same generator pattern produces `*_Response`, `*_OptionsEntry`, `*_PropertiesEntry`. - -## Low severity - -_None._ - -## Observations - -### 14. Casing inconsistency in vendor name decomposition -Within `ConnectionType`: -- `BIGQUERY`, `POSTGRESQL`, `SQLSERVER` (joined) vs `POWER_BI`, `WORKDAY_RAAS`, `META_MARKETING` (split). -- `MYSQL` (joined) vs `GA4_RAW_DATA` (split). -No discoverable rule. Wire-locked, but worth surfacing. -- **Category:** 3 (acronym/casing inconsistency). - -## Domain glossary -- `uc` — Unity Catalog (referenced in `model.ts` doc comments). -- `raas` — Reporting as a Service (e.g. `WORKDAY_RAAS`). Doc-less. -- `ga4` — Google Analytics 4 (in `GA4_RAW_DATA`). -- `m2m`/`u2m` — Machine-to-machine / User-to-machine OAuth flows (in `CredentialType`). -- `mtls` — Mutual TLS (in `OAUTH_MTLS`). -- `pem` — Privacy-Enhanced Mail format (in `PEM_PRIVATE_KEY`). -- `ssws` — Secure Single Sign-on Web Services (Okta) (in `SSWS_TOKEN`). Undocumented. -- `oidc` — OpenID Connect (in `OIDC_TOKEN`). -- `oss` — not encountered. -- `iam` — not encountered. - -## File coverage -- `src/v1/model.ts` (446 lines): read fully. -- `src/v1/client.ts` (240 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (29 lines): read fully. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index 09a0b353..dc1d35ce 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -1,19 +1,11 @@ # Naming Audit: credentials -**Path:** `packages/credentials/src/v1/` +**Path:** `packages/uc/credentials/src/v1/` **Versions audited:** v1 **Package name:** `@databricks/sdk-credentials` (top-level module name collides semantically with the hand-written `@databricks/sdk-auth/credentials` sub-module). -**Inferred domain:** Unity Catalog "Credentials" API — manages two parallel -shapes (the newer consolidated `Credential` and the older `StorageCredential`) -plus four `GenerateTemporary*Credential` token-vending endpoints (path, table, -volume, service). Each credential is a discriminated union over six -cloud-provider configurations (AWS IAM role, Azure Service Principal, Azure -Managed Identity, GCP Service Account Key, Databricks-managed GCP Service -Account, Cloudflare API token) and yields one of six temporary-credential -shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). -**Total weird names flagged:** 22 (22 still applicable, 0 newly fixed in regeneration on 2026-05-26) +**Total weird names flagged:** 4 --- @@ -21,125 +13,35 @@ shapes (AWS, Azure SAS, GCP OAuth, Azure AAD, R2, UC encrypted token). | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| -| 1 | package `credentials` / module `@databricks/sdk-credentials` | (package) | package | High | 1 Vague/generic, 12 Duplicate concepts | Cross-package naming collision with `@databricks/sdk-auth`'s hand-written `credentials/` sub-module. Importers will routinely ask "which `credentials` did I want?" — one is SDK authentication (PAT, U2M, M2M); this is Unity Catalog cloud-storage credentials. | -| 2 | `CredentialInfo` vs `CreateCredentialRequest` vs `UpdateCredentialRequest` vs `StorageCredentialInfo` | model.ts:463, 300, 1055, 870 | interface set | High | 12 Duplicate concepts | Four near-identical record shapes (~20 fields each) differ only in two flag fields (`skipValidation`, `force`, `newName`, `nameArg`). The "Info" suffix vs "Request" suffix is meaningless. Real shape is one resource + a small action delta. | -| 3 | `CreateCredentialRequest` vs `CreateStorageCredentialRequest` | model.ts:300, 388 | interface pair | High | 12 Duplicate concepts | Field-for-field identical. The wire endpoints differ (`/credentials` vs `/storage-credentials`) but the request bodies are the same. One should be a re-export of the other or both should share a common base. | -| 4 | `UpdateCredentialRequest` vs `UpdateStorageCredentialRequest` | model.ts:1055, 1140 | interface pair | High | 12 Duplicate concepts | Same as #3 — body fields identical. | -| 5 | `CredentialInfo` vs `StorageCredentialInfo` | model.ts:463, 870 | interface pair | High | 12 Duplicate concepts | Same fields, same types, same optionality. The only thing distinguishing them is which list endpoint emits which. Generator-produced. | -| 6 | `DeleteCredentialRequest` vs `DeleteStorageCredentialRequest` | model.ts:564, 584 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg, force}`; identical shape. | -| 7 | `GetCredentialRequest` vs `GetStorageCredentialRequest` | model.ts:755, 771 | interface pair | High | 12 Duplicate concepts | Both expose `{nameArg}`. Same shape. | -| 8 | `ListCredentialsRequest` vs `ListStorageCredentialsRequest` | model.ts:788, 825 | interface pair | High | 12 Duplicate concepts | Both expose `{includeUnbound, maxResults, pageToken}`. Same shape, different doc string. | -| 9 | `ValidateCredentialRequest` vs `ValidateStorageCredentialRequest` | model.ts:1225, 1283 | interface pair | High | 12 Duplicate concepts | The `credential` discriminator differs (`credentialName` vs `storageCredentialName`; storage variant adds `azureServicePrincipal` and `cloudflareApiToken`). Otherwise overlapping. | -| 10 | `Client` | client.ts:106 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `CredentialsClient` would self-identify. | -| 11 | `Client.createCredential` vs `Client.createStorageCredential` (plus delete/get/list/update/validate pairs) | client.ts:309, 339, 368, 402, 445, 480, 514, 551, 586, 614, 648, 715, 777, 808, 850, 889 | method set | High | 12 Duplicate concepts | The class exposes parallel `*Credential` and `*StorageCredential` operations (16 methods, 8 pairs). Per the in-tree TODO note (model.ts:766-770) the storage-credentials API is being deprecated, but both are surfaced equally — no `@deprecated` JSDoc, no log warning. | -| 12 | `UpdateCredentialRequest.nameArg` and `UpdateCredentialRequest.name` coexist | model.ts:1057, 1072 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same envelope carries both `nameArg` (path) and `name` (body). The JSDoc doesn't say what to do when they differ; the JSDoc on `name` repeats `CreateCredentialRequest.name`'s text. Caller will pick wrong. | -| 13 | `UpdateStorageCredentialRequest.nameArg` and `UpdateStorageCredentialRequest.name` coexist | model.ts:1142, 1156 | field pair | High | 12 Duplicate concepts, 15 Generic field names | Same as #12 for the storage variant. | -| 14 | `TableOperation` vs `VolumeOperation` enums | model.ts:17, 22 | enum pair | Low | 12 Duplicate concepts | `TableOperation = READ \| READ_WRITE`, `VolumeOperation = READ_VOLUME \| WRITE_VOLUME`. Same semantic (read-or-write a cloud-storage thing) expressed two different ways across sibling enums in the same file. | -| 15 | `AwsIamRole`, `AzureServicePrincipal`, `AzureManagedIdentity`, `GcpServiceAccountKey`, `DatabricksGcpServiceAccount`, `CloudflareApiToken` | model.ts:151, 192, 174, 610, 555, 214 | interface set | Low | 3 Acronym casing | Acronym handling differs: `Aws`, `Azure`, `Gcp`, `Iam` are all PascalCase-first-letter-only. Field names use the same (`awsIamRole`, `gcpServiceAccountKey`). Internally consistent, but `IAM`, `GCP`, `AWS` are all-caps acronyms; per the Google TS Style Guide (which the repo references) initialisms-as-words is the right choice — flag only because the JSDoc text uses ALL-CAPS forms ("AWS IAM role", "GCP", "AAD"). Pick one. | -| 16 | `aadToken` field, `AzureActiveDirectoryToken` type, `azureAad` discriminator case | model.ts:170, 168, 642 | name set | Low | 3 Acronym casing | The type is spelled out (`AzureActiveDirectoryToken`); the wire/discriminator/field name uses the acronym `Aad`. Inconsistent within the same chain (long name in type, short name in field/case). | -| 17 | `GcpOauthToken` type, `gcpOauthToken` field | model.ts:602, 603 | type/field | Low | 3 Acronym casing | "OAuth" is conventionally `OAuth` (RFC 6749 title casing). The code spells it `Oauth`. Sibling spec types in the auth package use `Oauth` too — internally consistent, but not RFC-conventional. | -| 18 | `R2Credentials` type | model.ts:861 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | -| 19 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:619, 690, 723, 654 | interface set | Medium | 7 Overly verbose, 12 Duplicate concepts | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | -| 20 | `TemporaryCredentials` | model.ts:961 | interface | Medium | 12 Duplicate concepts | The three `Generate*` response shapes carry the same field set (`credentials` union + `expirationTime` + `url`) as `TemporaryCredentials`. Only one canonical shape is needed; the others should re-export it. | -| 21 | `ListCredentialsPublicRequest` | model.ts:776 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | -| 22 | `Client.createCredentialsPublic` / `Client.deleteCredentialsPublic` / `Client.getCredentialsPublic` / `Client.listCredentialsPublic` | client.ts:927, 953, 978, 1003 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `Client` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | +| 1 | `R2Credentials` type | model.ts:853 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | +| 2 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:615, 685, 717, 649 | interface set | Medium | 7 Overly verbose | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | +| 3 | `ListCredentialsPublicRequest` | model.ts:769 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | +| 4 | `CredentialsClient.createCredentialsPublic` / `CredentialsClient.deleteCredentialsPublic` / `CredentialsClient.getCredentialsPublic` / `CredentialsClient.listCredentialsPublic` | client.ts:971, 997, 1022, 1047 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `CredentialsClient` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | --- ## High severity (must fix) -### H1. Cross-package collision: `credentials` vs `auth/credentials` +### H1. `Public` infix proto-architectural leak (1 type + 4 methods) -The repository has **two** "credentials" concepts: - -- `@databricks/sdk-credentials` (this package) — Unity Catalog cloud storage - credentials (AWS IAM roles, Azure SPs, GCP service accounts). -- `@databricks/sdk-auth/credentials/` (hand-written sub-module) — SDK *user* - authentication credentials (PAT, OAuth U2M, OAuth M2M); see - `packages/auth/src/credentials/{m2m,pat,u2m}.ts`. Their public surface uses - the literal name `Credentials` (`M2mCredentials`, `U2mCredentials`, - `PatCredentials`). - -A consumer writing `import {Credentials} from '@databricks/sdk-...'` cannot -tell which package they want. Both legitimately call their primary concept -"credentials". Possible fixes (pick one): - -- Rename this package to `@databricks/sdk-unity-catalog-credentials`, - `@databricks/sdk-uc-credentials`, or `@databricks/sdk-storage-credentials`. -- Rename the auth-side to `@databricks/sdk-auth/identity` or `/providers` - (followed by `IdentityProvider`, not `Credentials`). -- At minimum, document the disambiguation in both packages' README/JSDoc. - -### H2. Whole-package internal duplication: `Credential` vs `StorageCredential` - -Eight method pairs and eight interface pairs are field-for-field identical -between the "Credential" (new consolidated) surface and the "StorageCredential" -(legacy) surface. See findings #2-#9. The in-tree TODO note -(model.ts:766-770) confirms the storage variant is being deprecated. But: - -- No `@deprecated` JSDoc tag on any of the `*StorageCredential*` types or - methods. -- No log warning when a caller invokes them. -- They are equally promoted in `index.ts`. - -Recommendation: mark every `*StorageCredential*` type and method `@deprecated`, -or hide them behind a `/legacy` sub-export, until they are removed. - -### H3. Identical request envelopes (`Credential` and `StorageCredential` pairs) - -`CreateCredentialRequest` and `CreateStorageCredentialRequest` (model.ts:300, 388) -have identical fields. Same for the Update, Delete, Get, List pairs (#3, #4, #6, -#7, #8). The discriminated unions on the `credential` field are subsets/supersets -of each other: - -- `CreateStorageCredentialRequest` accepts: awsIamRole, azureServicePrincipal, - gcpServiceAccountKey, azureManagedIdentity, databricksGcpServiceAccount, - cloudflareApiToken (6 cases). -- `CreateCredentialRequest` accepts: the same 6 cases. - -There is no behavioral difference. One should be a type alias. - -### H4. Body-level `name` collides with path-level `nameArg` - -`UpdateCredentialRequest` and `UpdateStorageCredentialRequest` carry both -`nameArg` (path parameter) and `name` (body field), plus a `newName` field. The -JSDoc on `name` says "The credential name. The name must be unique among -storage and service credentials within the metastore." — i.e., the *new* -canonical name. So `nameArg`, `name`, and `newName` all reference the same -conceptual "credential name" with no clear precedence. See #12, #13. - -```ts -interface UpdateCredentialRequest { - nameArg?: string; // URL path parameter — which credential to update - newName?: string; // new credential name - name?: string; // body-level "credential name" — what does this even do? - // ... -} -``` - -Three name-related fields on one envelope, no clear precedence. Recommend: -drop the body-level `name` so only `nameArg` (path, identifying the existing -credential) and `newName` (rename) remain. - -### H5. `Public` infix proto-architectural leak (1 type + 4 methods) - -Findings #21-#22. The package exposes **1 generated type** and **4 `Client` -methods** whose identifiers carry `Public` as a mid-position or trailing -word. The infix originates from the internal proto/service definition where +Findings #3-#4. The package exposes **1 generated type** and **4 +`CredentialsClient` methods** whose identifiers carry `Public` as a +mid-position or trailing word. The infix originates from the internal +proto/service definition where `Public` distinguishes externally-routable account-API endpoints from internal RPCs; it has no meaning at the TS SDK boundary, where every exported symbol is by definition public. Types (model.ts): -- `ListCredentialsPublicRequest` (776). +- `ListCredentialsPublicRequest` (769). Methods (client.ts): -- `createCredentialsPublic` (927). -- `deleteCredentialsPublic` (953). -- `getCredentialsPublic` (978). -- `listCredentialsPublic` (1003). +- `createCredentialsPublic` (971). +- `deleteCredentialsPublic` (997). +- `getCredentialsPublic` (1022). +- `listCredentialsPublic` (1047). Note also: the sibling consolidated UC endpoints (`CreateCredentialRequest`, `CreateStorageCredentialRequest`, etc.) do *not* carry `Public` even though @@ -147,14 +49,17 @@ they are equally externally-routable. This inconsistency confirms `Public` is not a deliberate domain term but a wire-layer artifact whose presence depends on which generation pass produced the type. +(The `CreateCredentialRequest` family is named only as a contrasting example +here; those types are not themselves flagged.) + Recommendation: drop the `Public` token from every identifier at the generator level. Suggested renames: | Current | Suggested | |---------|-----------| | `ListCredentialsPublicRequest` | `AccountsListCredentialsRequest` | -| `Client.createCredentialsPublic` | `Client.createAccountsCredentials` | -| `Client.listCredentialsPublic` | `Client.listAccountsCredentials` | +| `CredentialsClient.createCredentialsPublic` | `CredentialsClient.createAccountsCredentials` | +| `CredentialsClient.listCredentialsPublic` | `CredentialsClient.listAccountsCredentials` | This is a generator-only fix — there is no way to rename these consistently without touching the generator/spec. @@ -163,180 +68,20 @@ without touching the generator/spec. ## Medium severity (worth pushing back on) -### M1. `Credential` is a vague, generic noun - -The interface `Credential` (and `Credentials`, `CredentialInfo`, -`CredentialName`) does not, in isolation, tell a TS reader anything about the -domain. The Databricks SDK has at least four distinct "credential" concepts: - -1. SDK authentication (auth package). -2. Unity Catalog Storage Credentials (legacy this package). -3. Unity Catalog Service Credentials (new this package). -4. Cloud-provider credentials (vended via `TemporaryCredentials`). - -A type named just `Credential` could be any of them. Domain-prefixing -(`StorageCredentialInfo`, `ServiceCredentialInfo`) at least narrows it. - -### M2. `Client` is unqualified - -`export class Client` (client.ts:106). Importing `{Client}` from `@databricks/sdk-credentials/v1` -and from any sibling package collides. Either: - -- Export as `CredentialsClient`, or -- Rely on namespace imports. - -### M3. Eight `client.ts` method pairs duplicate work - -Sixteen methods, eight pairs. Each pair differs only in the URL it hits. -Cf. #11. The class is over 1000 lines, with ~30 lines of boilerplate per -method. Half of that is generated for the legacy storage-credentials path. - -### M4. `TemporaryCredentials` shape duplicated across responses - -`TemporaryCredentials` and the three `Generate*` response types carry the -same field set. The wire endpoints might differ (so each method returns its -own named type), but at the TS level there is no need to create multiple -declarations. - -### M5. `R2Credentials` requires Cloudflare product knowledge +### M1. `R2Credentials` requires Cloudflare product knowledge A type named `R2` is identifiable only to readers who know Cloudflare's -product line. The JSDoc gives no expansion. Use `CloudflareR2Credentials` or -add a JSDoc anchor. +product line. Use `CloudflareR2Credentials` to make the cloud provider +explicit in the type name. --- ## Low severity (nits) -### L1. `aadToken` field vs `AzureActiveDirectoryToken` type - -Short form (`aadToken`) for the field, long form (`AzureActiveDirectoryToken`) -for the type. Acronym handling within one chain should match. - -### L2. `GcpOauthToken` casing - -RFC 6749 (OAuth 2.0) titles the term as "OAuth". The code uses "Oauth". Minor. - -### L3. `Generate*CredentialRequest` method names are 30+ chars +### L1. `Generate*CredentialRequest` method names are 30+ chars `generateTemporaryServiceCredential` is 35 chars. Combined with `await client.generateTemporaryServiceCredential(req)` the call site is 60+ chars before the args. Cannot shorten without breaking the resource hierarchy. -### L4. Acronym casing review - -- `Aws` (PascalCase first letter) — `AwsCredentials`, `AwsIamRole`, - `awsIamRole`. Internally consistent. -- `Azure` (not an acronym) — fine. -- `Gcp` (PascalCase first letter) — `GcpOauthToken`, `gcpServiceAccountKey`. - Internally consistent. -- `Aad` (mixed) — `aadToken` (field, short), `AzureActiveDirectoryToken` - (type, long). Inconsistent. See #16. -- `Iam` — consistent with `Aws`/`Gcp` style. -- `R2` — special-cased product name. See M5/#18. -- `Sas` (PascalCase first letter) — `AzureUserDelegationSas`, `sasToken`. - Consistent. -- `Oauth` — see L2/#17. - -The JSDoc *text* in the same file uses ALL-CAPS forms ("AWS", "GCP", "IAM", -"AAD") because that is how the cloud providers write them. The Google TS -Style Guide prefers initialism-as-word (`Aws`, `Gcp`, `Iam`) for identifiers. -This is fine; just don't claim the spec uses the same casing. - ---- - -## Cross-cutting observations (not flags) - -### Confusion with `@databricks/sdk-auth/credentials/` - -The hand-written auth/credentials sub-module exports: - -- `M2mCredentialsError`, `U2mCredentialsError` (error classes). -- `M2mCredentialsErrorCode`, `U2mCredentialsErrorCode` (type aliases). -- `newM2mCredentials`, `newPatCredentials`, `newU2mCredentials` (factories). -- `M2mCredentialsOptions`, `U2mCredentialsOptions` (option types). - -It does *not* export a type literally called `Credentials`; the closest is -the factory return type pattern (`*Credentials` named instances). Still, a -search-and-replace consumer who types "import {Credentials}" will hit both -packages. The simplest fix is package-level renaming (H1). For now, callers -must keep the import paths straight (`@databricks/sdk-credentials/v1` for UC -storage credentials, `@databricks/sdk-auth` for SDK auth credentials). - -### Generator marker - -Every file is prefixed with `// Code generated from API definition by -Databricks SDK Generator. DO NOT EDIT.` All naming issues here must be fixed -upstream in the generator/spec. - -### Optionality model - -Every field is `T | undefined`. Matches `exactOptionalPropertyTypes` and the -rest of the SDK. - -### No reserved-word collisions - -No `delete`, `class`, `new`, `default` (as field names). - -### No singular/plural mismatches in interface names - -`Credentials` vs `Credential` is used consistently: - -- `TemporaryCredentials` (plural) — wraps a single credential value (a - discriminated union); reads as "this is a temporary credentials *bundle*". - Marginal. -- `R2Credentials`, `AwsCredentials` (plural) — wraps a single set of - credential values (key + secret + session); fine as the convention is - "credentials" for the bundle. -- `CredentialInfo` (singular) — one credential record. Consistent with - Databricks API "Info" suffix. - -### Versioning - -Only `v1` exists; nothing to compare across versions. - -### Tests - -No `tests/` directory for this package. - -### `index.ts` re-export style - -Class re-exported with `export {Client}`; types and enums re-exported with -`export {IsolationMode, ...}` (for enums, which are runtime values) and -`export type {AwsCredentials, ...}` (for type-only interfaces). Correct for -`verbatimModuleSyntax`. - ---- - -## Domain glossary (as inferred from this code) - -| Term | Meaning in this package | -|------|-------------------------| -| **Credential** (new) | The consolidated UC credential record covering both Storage and Service purposes. Reached via `/api/2.1/unity-catalog/credentials`. | -| **Storage Credential** (legacy) | The older Storage-only credential record. Reached via `/api/2.1/unity-catalog/storage-credentials`. Per in-tree TODO, being deprecated. | -| **Service Credential** | A `Credential` whose purpose is **SERVICE** — used by Databricks to access cloud APIs on behalf of the user (e.g., for foundation models, external functions). | -| **Purpose** | One of `SERVICE` / `STORAGE`. Distinguishes the two flavors of a `Credential`. Referenced in JSDoc but absent from the TS type. | -| **Long-lived credential** | The customer-supplied cloud-provider auth material (IAM role, service principal, etc.) stored in the metastore. Six discriminated cases. | -| **Temporary credential** | Short-lived tokens vended by Databricks for direct cloud access. Six discriminated cases. | -| **External location** | A cloud-storage URL registered in UC and authorized via a Storage Credential. Validated by `validateCredential` / `validateStorageCredential`. | -| **Isolation mode** | Workspace-binding policy for the credential securable. One of `Unspecified`, `Open`, `Isolated`. | -| **Unbound credential** | A credential not bound to any workspace. Listable via `includeUnbound=true`. | -| **`nameArg`** | URL-path positional argument for the credential's name. Exists because the request envelope also carries body-level `name` and `newName` — see H4. | -| **Access connector ID** (Azure) | The Azure resource ID of the Databricks Access Connector. | -| **AAD token** | Azure Active Directory access token (Oauth bearer for Azure cloud services). | -| **R2** | Cloudflare's S3-compatible object storage product (named after the SF-Bay-Area meme). | -| **External ID** | AWS confused-deputy mitigation token in role assumption. | - ---- - -## File coverage - -| File | Lines | Exports counted | Audited | -|------|-------|-----------------|---------| -| `src/v1/model.ts` | 2877 | 7 enums, 39 interfaces | yes | -| `src/v1/client.ts` | 1031 | 1 class, 22 public methods (20 RPC + 2 async generators) | yes | -| `src/v1/index.ts` | 80 | 1 class re-export, 7 enum re-exports, 51 type re-exports | yes | - -Every type, field, enum value, and method enumerated above is accounted for. - --- diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 4b8f2575..96ad07b6 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -2,32 +2,25 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 -**Inferred domain:** "Custom LLM" CRUD plus an optimization run lifecycle — create/get/update/delete a `CustomLlm` resource (instructions, guidelines, datasets, optional UC artifact path), then start/cancel an optimization run that flips `optimizationState` through `CREATED → PENDING → RUNNING → COMPLETED|FAILED|CANCELLED`. -**Total weird names flagged:** 10 (0 fixed, 10 still present after rescan on 2026-05-26 post regen #156) +**Total weird names flagged:** 6 (0 fixed, 6 still present after rescan on 2026-06-02) ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 3 | +| High | 2 | +| Medium | 1 | | Low | 2 | -| Observation | 2 | +| Observation | 1 | ## High severity -### 1. `Llm` casing throughout — every file -- **Why weird:** Every public type, field, method, and schema collapses the acronym `LLM` to title-case `Llm` (`CustomLlm`, `customLlm`, `createCustomLlm`, `customLlmFieldMask`, etc.). `LLM` is a well-known three-letter initialism, not a word. The Google TypeScript Style Guide (https://google.github.io/styleguide/tsguide.html#identifiers) explicitly says "treat abbreviations like acronyms in names as whole words" — that produces `LLM` if you choose the all-caps convention, or `Llm` if you choose the title-case convention. The package is internally consistent on `Llm` (and so are the sibling packages `accountsettings.LlmProxyPartnerPoweredAccount` and `workspacesettings.LlmProxyPartnerPoweredWorkspace`), so this is a *category* finding for the SDK rather than a local fix: `Llm` is harder to read than `LLM` because the human eye expects `Ll` to be a digraph rather than the start of an initialism. Microsoft's .NET guidelines (https://learn.microsoft.com/dotnet/standard/design-guidelines/capitalization-conventions) flip the other direction: capitalize all letters of two-letter acronyms (`IO`) and pascal-case three-or-more-letter acronyms (`Xml`, `Html`) — by that rule `Llm` *is* the consistent choice. There is no globally correct answer, but the SDK should pick *one* convention and apply it across all packages (`http` vs `Http`, `url` vs `Url`, `id` vs `Id` are already mixed — see Observation #10). -- **Category:** 3 (acronym casing — the audit prompt singles this out). -- **Suggested name:** Pick a project-wide policy in `typescript.mdc` and apply globally. If the SDK keeps `Llm`, document the choice; if it switches to `LLM`, every type and field in this package and the two sibling packages needs the rename. -- **Rationale:** This is the highest-impact naming question in the package because it touches every single exported identifier. Currently the only consumer-facing precedent in the codebase is `Llm`, so flipping to `LLM` is a breaking change across at least three packages. - -### 2. `State` enum (top-level, ungrouped) — `src/v1/model.ts:9-17` +### 1. `State` enum (top-level, ungrouped) — `src/v1/model.ts:9-17` - **Why weird:** The enum is named `State` — the most generic noun in any API. There is no qualifier to tell the reader *which* state (optimization run? custom LLM? endpoint?). The doc comment ("States of Custom LLM optimization lifecycle.") clarifies, but the name alone does not. Every other Databricks package has its own `State` (jobs, clusters, queries) and a user importing two of them will be forced to alias. - **Category:** 1 (vague/generic), 15 (generic field name). - **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). - **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. -### 3. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` +### 2. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` - **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. - **Category:** Observation / 6 (misleading — field-mask implies updatable). - **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. @@ -35,33 +28,21 @@ ## Medium severity -### 4. `agentArtifactPath` field with explicit "soon be deprecated!!" comment — `src/v1/model.ts:36-40,61` -- **Why weird:** Field carries a self-deprecated marker in its doc ("This will soon be deprecated!!") but is not tagged `@deprecated` and lives on both `CreateCustomLlmRequest` and `CustomLlm`. SDK consumers will not see "soon to be deprecated" from IDE hover unless they read the body of the comment. Also the name conflates two ideas: it is an *output* artifact destination for the agent, framed as if it were an input — but actually the doc says "If you are using a dataset that you only have read permissions, please provide a destination path where you have write permissions." So this is a "destination" path, not an artifact-locating path. -- **Category:** 6 (misleading), 1 (vague — "agent artifact" is a generic term). -- **Suggested name:** Mark `@deprecated` and consider renaming to `outputDestinationPath` or `artifactWritePath`. -- **Rationale:** The public surface should not silently carry a soft-deprecation note. Tag it properly. - -### 5. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:69,162` +### 3. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:71,176` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). - **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. -### 6. `STATE_UNSPECIFIED` enum sentinel — `src/v1/model.ts:10` -- **Why weird:** The `State` enum's first member `STATE_UNSPECIFIED` is a proto-architectural leak. Proto3 requires every enum to declare a zero-value sentinel (typically `FOO_UNSPECIFIED`); that requirement does not exist in TypeScript. Exposing it on the public TS surface forces every consumer to handle a member that semantically means "the server forgot to set this field" — a proto wire-format concern, not a domain concern. The screaming-snake-case casing (`STATE_UNSPECIFIED`) also leaks proto's enum-value convention into a TS type system that conventionally uses PascalCase for enum members (https://google.github.io/styleguide/tsguide.html#enums). -- **Category:** Proto-architectural leak (enum sentinel + screaming-snake casing). -- **Suggested name:** Drop the `STATE_UNSPECIFIED` member entirely; if a "not yet set" value is needed, use `undefined` (the field is already `State | undefined`). If kept, rename to PascalCase `Unspecified` and document that it is a wire-format sentinel. -- **Rationale:** Optional TS fields express "unset" via `undefined`; a redundant enum sentinel doubles the representation of "no value" and forces consumers to write `state !== undefined && state !== State.STATE_UNSPECIFIED`. The all-caps casing further signals that the value is a proto artifact rather than a designed TS API member. - ## Low severity -### 7. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` +### 4. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` - **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. - **Category:** Observation / 9 (reversed — correctly singular). - **Suggested name:** No change. - **Rationale:** Note for consistency reviews. -### 8. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 5. `customLlmFieldMask` function name — `src/v1/model.ts:259` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). @@ -69,23 +50,6 @@ ## Observations -### 9. Action verbs in `Client` are consistent +### 6. Action verbs in `Client` are consistent The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. - **Category:** 17 (reversed — explicit *consistency* note). - -### 10. Mixed acronym casing in core types -The codebase imports `HttpClient`, `HttpRequest`, `HttpResponse`, `ApiError`, `URLSearchParams`, `userAgent`. The acronyms are cased every which way: `Http` (title), `Api` (title), `URL` (all-caps), `userAgent` (camel). This is consistent with the broader JS ecosystem (`fetch` returns a `Response`, `XMLHttpRequest` is its own caps, `URL` is all-caps in `URLSearchParams`), but it explains why `Llm` vs `LLM` feels arbitrary — the SDK has no single policy. -- **Category:** 3 (acronym casing). - -## Domain glossary -- `llm` — Large Language Model (every type, every field, every method; the canonical token). -- `uc` — Unity Catalog (mentioned only in JSDoc on `agentArtifactPath` and `Table.tablePath`: "Full UC table path in catalog.schema.table_name format"). -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). -- `pat`/`m2m`/`u2m`/`oidc` — not encountered in this package. -- `iam` — not encountered. - -## File coverage -- `src/v1/model.ts` (262 lines): read fully. -- `src/v1/client.ts` (216 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (18 lines): read fully. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index 305657c5..da01ec73 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -2,44 +2,24 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 -**Inferred domain:** Databricks Lakebase OLTP layer — manage Postgres `DatabaseInstance`s, `DatabaseCatalog`s (Unity Catalog mirrors of logical Postgres databases), `DatabaseTable`s (UC-registered PG tables), `SyncedDatabaseTable`s (UC-managed Delta-to-PG continuous/triggered/snapshot sync pipelines), instance roles, and short-lived credentials. -**Total weird names flagged:** 19 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 11 | -| Low | 1 | +| High | 2 | +| Medium | 7 | | Observation | 2 | ## High severity -### 1. `DatabaseInstanceRole_Attributes.createdb` / `createrole` / `bypassrls` — `src/v1/model.ts:373-375` -- **Why weird:** Three lowercase, run-together field names. The doc comment (model.ts:365-370) explicitly says "The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words." That justifies the wire format (Postgres keywords are case-insensitive identifiers) but the *TypeScript* field should use `camelCase` (`createDb`, `createRole`, `bypassRls`) — the wire stays `createdb`/`createrole`/`bypassrls`. `createrole` is particularly confusing because it could read as `create_role` (a verb-phrase) or `creator_ole`. -- **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS). -- **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; keep `createdb`/`createrole`/`bypassrls` on the wire (marshal/unmarshal handles the mapping). -- **Rationale:** Every other field in the package is `camelCase`. Three boolean fields breaking the convention to honour Postgres SQL keywords is a leak. Postgres SDK at `postgres/v1/model.ts` solves this differently — worth aligning. - -### 2. `SYNCED_TABLED_OFFLINE` typo — `src/v1/model.ts:70` -- **Why weird:** Should be `SYNCED_TABLE_OFFLINE`. Spelled as `SYNCED_TABLED_OFFLINE` (`TABLED` past tense). -- **Category:** 6 (misleading: typo). -- **Suggested name:** Fix the wire-string to `SYNCED_TABLE_OFFLINE`. -- **Rationale:** This is a protocol-level typo that the SDK is propagating. If fixed upstream this becomes a breaking change unless aliased — flag now. - -### 3. `effective*` field-prefix pattern duplicates every input field — `src/v1/model.ts` (~24 effective_ fields across DatabaseInstance, DatabaseInstanceRef, DatabaseInstanceRole, SyncedDatabaseTable) -- **Why weird:** `DatabaseInstance` has 15 input/output pairs: `capacity`/`effectiveCapacity`, `stopped`/`effectiveStopped`, `nodeCount`/`effectiveNodeCount`, `enableReadableSecondaries`/`effectiveEnableReadableSecondaries`, `retentionWindowInDays`/`effectiveRetentionWindowInDays`, `enablePgNativeLogin`/`effectiveEnablePgNativeLogin`, `usagePolicyId`/`effectiveUsagePolicyId`, `customTags`/`effectiveCustomTags`, plus `lsn`/`effectiveLsn` on `DatabaseInstanceRef`, `attributes`/`effectiveAttributes` on `DatabaseInstanceRole`, and `databaseInstanceName`/`effectiveDatabaseInstanceName` (+1 more) on `SyncedDatabaseTable`. JSDoc on every effective field is the same boilerplate sentence. Doubles the surface area of every type. -- **Category:** 7 (overly verbose), 12 (duplicate concept), 15 (generic prefix). -- **Suggested name:** Hoist effective values onto a sub-struct or use a discriminated `{input, effective}` shape; or drop the `effective` fields and explain in docs that the same field is read-mostly on responses. -- **Rationale:** This is a Lakebase API protocol pattern, not a naming bug per se, but the resulting TS surface is twice as wide as it needs to be. Worth pushing back upstream. - -### 4. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:395` +### 1. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:427` - **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 447 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:471): "Name of the **cluster** to get". - **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). - **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. - **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. -### 5. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:924`, `index.ts:3` +### 2. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:998`, `index.ts:3` - **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. @@ -47,106 +27,53 @@ ## Medium severity -### 6. `DatabaseInstance.capacity: string` typed as a free-form string but doc constrains it — `src/v1/model.ts:211` -- **Why weird:** Field doc says 'Valid values are "CU_1", "CU_2", "CU_4", "CU_8".' That is an enum encoded as a string. Should be an enum. -- **Category:** 16 (field type contradicts domain), 1 (vague — `capacity` for an opaque size class). -- **Suggested name:** Introduce `Capacity` enum (`Cu1 | Cu2 | Cu4 | Cu8`); rename field to `sku` if Lakebase docs prefer that term, since the doc itself says "The sku of the instance". -- **Rationale:** Generator artefact: protobuf string-typed scalars often hide enums. Worth pushing back. - -### 7. `DatabaseInstance.stopped` / `effectiveStopped` as a boolean toggle for state — `src/v1/model.ts:219,225` -- **Why weird:** Already-state-bearing struct has `state?: DatabaseInstance_State` (which includes `STOPPED`). Adding an orthogonal `stopped: boolean` is redundant and confusing — what happens if `state = AVAILABLE` and `stopped = true`? -- **Category:** 17 (two fields encoding the same concept), 12 (duplicate concept within the same struct). -- **Suggested name:** Either drop `stopped` and use `state === STOPPED`, or make it write-only and exclude from the read shape. -- **Rationale:** The doc says "An input only param" but the type makes it look like both. Worth a `@deprecated`-style marker. - -### 8. `SyncedDatabaseTable` vs `DatabaseTable` — overlapping concepts — `src/v1/model.ts:378,590` -- **Why weird:** Two near-identical struct types: `DatabaseTable` registers an existing PG table in UC; `SyncedDatabaseTable` is a UC-side spec for a Delta-to-PG sync. They share `name`, `databaseInstanceName`, `logicalDatabaseName`. Naming does not signal that `SyncedDatabaseTable` is more like a "managed table" while `DatabaseTable` is a "foreign-table registration". -- **Category:** 12 (duplicate concept), 1 (generic `Database`). -- **Suggested name:** `PgTableRegistration` and `DeltaSyncedPgTable` (or similar). At minimum, doc each type with a sentence about how they differ. -- **Rationale:** Reader has to read both JSDocs to understand the partitioning. - -### 9. `SyncedTableSpec.timeseriesKey` casing — `src/v1/model.ts:731` -- **Why weird:** `timeseries` is one run-together word; could be `timeSeriesKey` (two words). Same field appears on the wire as `timeseries_key` — wire uses snake_case run-together, TS preserves it. Other compound words in this file (e.g. `pageToken`, `nextPageToken`) split words at capital boundaries. -- **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). -- **Suggested name:** `timeSeriesKey`. -- **Rationale:** Trivia, but `time series` is two words in English. - -### 10. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` +### 3. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 11. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` -- **Why weird:** Type holds two fields (`deltaCommitVersion`, `deltaCommitTimestamp`). The `Delta` prefix appears once at the type level and twice at the field level (`deltaCommitVersion`, `deltaCommitTimestamp`). Type-prefix duplication. -- **Category:** 20 (type-suffix tautology in field names), 7 (verbose). -- **Suggested name:** Type `DeltaSyncCheckpoint`, fields `commitVersion` / `commitTimestamp`. -- **Rationale:** Inside `DeltaTableSyncInfo` the `delta` prefix is implied. +### 4. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` +- **Why weird:** Type holds two fields and is the lone `*SyncInfo` / `Delta*` type in the package. `SyncInfo` is a generic stand-in suffix; the type is really a sync checkpoint. +- **Category:** 15 (generic `*Info` suffix). +- **Suggested name:** Type `DeltaSyncCheckpoint`. +- **Rationale:** `DeltaTableSyncInfo` reads as a generic bag of fields; a domain-specific name conveys that it captures a sync checkpoint. -### 12. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` +### 5. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 13. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` +### 6. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 14. `NewPipelineSpec` type and `newPipelineSpec` field — `src/v1/model.ts:551,753` -- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (here, paired with `existingPipelineId`). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #15 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. +### 7. `NewPipelineSpec` type — `src/v1/model.ts:551` +- **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (the type is paired with a sibling `existingPipelineId` field). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #8 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. - **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). -- **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`; field `inlinePipeline` (paired with `existingPipelineId`). Drop the `New` adjective and the `Spec` suffix. +- **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`. Drop the `New` adjective and the `Spec` suffix. - **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. -### 15. Repeated generic suffixes `*Spec` and `*Info` across the package — `src/v1/model.ts:436,551,575,723` -- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) and two `*Info` types (`DeltaTableSyncInfo`, `ProvisioningInfo`) coexist with no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `ProvisioningInfo` is empty (see #16); `DeltaTableSyncInfo` is a sync checkpoint (see #11); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #14). Each of the four would read more clearly with a domain-specific suffix. +### 8. Repeated generic suffix `*Spec` across the package — `src/v1/model.ts:436,551,723` +- **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) coexist with the `*Info` type `DeltaTableSyncInfo` and no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `DeltaTableSyncInfo` is a sync checkpoint (see #4); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #7). Each of these would read more clearly with a domain-specific suffix. - **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). -- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #14); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #11); `ProvisioningInfo` → drop (per #16). Goal: no two types in the package share a generic suffix. +- **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #7); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #4). Goal: no two types in the package share a generic suffix. - **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. -### 16. `ProvisioningInfo` empty interface copied verbatim from another proto file — `src/v1/model.ts:570-575` -- **Why weird:** Type declaration is literally `export interface ProvisioningInfo {}` with a comment "Copied over from managed-catalog/api/messages/common.proto to decouple SDK packages. xref go/unified-api-packages-dd". An empty interface — the type itself carries zero domain meaning. Only its nested `ProvisioningInfo_State` enum is used (referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`); the empty parent is a vestigial proto namespace. The exported type name and its nested enum bleed Managed Catalog internals into the Lakebase SDK. -- **Category:** proto-architectural leak (proto message preserved as empty TS interface for namespacing), 6 (misleading — exists but has no fields), 12 (cross-package proto leak). -- **Suggested name:** Drop the empty `ProvisioningInfo` interface; rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). The empty interface is a generator artefact that should not surface. -- **Rationale:** An empty exported interface is dead surface area. The xref comment (`go/unified-api-packages-dd`) tells the reader this is a cross-package proto coordination workaround — that workaround belongs in the generator, not in the public TS types. - -## Low severity - -### 17. `CreateDatabaseInstanceRoleRequest.databaseInstanceName` (field) vs `instanceName` (also field) on same request — `src/v1/model.ts:158-160` -- **Why weird:** Same struct exposes `instanceName` and `databaseInstanceName` — both strings, both presumably name an instance. Doc-less. Wire format makes `instanceName` the path parameter and `databaseInstanceName` a query parameter (visible in client.ts:181-184). -- **Category:** 12 (duplicate concept), 17 (inconsistent naming for the same thing), 19 (underspecified ids). -- **Suggested name:** One field. If protocol genuinely needs both, name them `instanceNamePath` / `instanceNameQuery` and add docs. -- **Rationale:** Caller has to know the wire-encoding accident to decide which to set. +### 9. `ProvisioningInfo_State` proto-underscore type name — `src/v1/model.ts:570-575` +- **Why weird:** The enum `ProvisioningInfo_State` carries a proto-style underscore-nested name (`Parent_Nested`). It is referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`. The underscore-joined name bleeds the proto nesting structure into the public TS surface. +- **Category:** proto-architectural leak (proto-underscore nested type name `Foo_Bar`), 12 (cross-package proto leak). +- **Suggested name:** Rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). +- **Rationale:** A `Parent_Nested` underscore name is a generator artefact that should not surface in idiomatic TS; the flattened `ProvisioningState` reads as a native enum. ## Observations -### 18. `findDatabaseInstanceByUid` is the only `findBy*` method +### 10. `findDatabaseInstanceByUid` is the only `findBy*` method Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. - **Category:** 17 (inconsistency with peer methods). -### 19. Action-verb conventions in `Client` are consistent +### 11. Action-verb conventions in `Client` are consistent `create*` / `delete*` / `get*` / `list*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. - -## Domain glossary -- `Lakebase` — Databricks' managed Postgres-as-a-service product (mentioned only in the buried client.ts:634 comment). -- `PG` / `pg` / `Postgres` / `PostgreSQL` — Postgres database; appears as `pgVersion`, `enablePgNativeLogin`, `PG_ONLY`, and as `PostgreSQL` in JSDoc. -- `UC` — Unity Catalog (referenced in `claims` doc and in JSDoc of `DatabaseCatalog`). -- `DNS` — Domain Name System (used as `Dns` suffix on `readWriteDns`/`readOnlyDns`). -- `LSN` — Postgres Log Sequence Number (`lsn`, `effectiveLsn`). -- `WAL` — Postgres Write-Ahead Log (referenced in `lsn` doc). -- `CU` — Capacity Unit (e.g. `CU_1`, `CU_2` — only in `capacity` doc string). -- `CDF` — Change Data Feed (Delta Lake feature; referenced in `SyncedTableSchedulingPolicy` docs). -- `PITR` — Point-in-Time Recovery (referenced in `DeleteDatabaseInstanceRequest.force` doc). -- `RLS` — Row-Level Security (`bypassrls` field). -- `AIP` — Google API Improvement Proposals (referenced in `allowMissing` doc). -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`). -- `oss`/`m2m`/`u2m`/`pat`/`iam`/`abac` — not encountered in this package. - -## File coverage -- `src/v1/model.ts` (1,904 lines): read fully. -- `src/v1/client.ts` (995 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (67 lines): read fully. diff --git a/.agent/naming-audit/dataclassification.md b/.agent/naming-audit/dataclassification.md deleted file mode 100644 index 7e69d891..00000000 --- a/.agent/naming-audit/dataclassification.md +++ /dev/null @@ -1,49 +0,0 @@ -# Naming Audit: dataclassification - -**Path:** `packages/dataclassification/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Data Classification configuration on Unity Catalog catalogs — enable/disable scanning, scope schemas, and configure auto-tagging of classified columns with governance/system tags. -**Total weird names flagged:** 2 - -## Summary -| Severity | Count | -| --- | --- | -| High | 0 | -| Medium | 1 | -| Low | 0 | -| Observation | 1 | - -## High severity - -_None._ - -## Medium severity - -### 1. `Client` class — `src/v1/client.ts:38` -- **Why weird:** A class literally named `Client` at the top level of the package's API surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). -- **Suggested name:** `DataClassificationClient` (matches the package name and avoids collisions on combined imports). -- **Rationale:** A user doing `import {Client} from '@databricks/sdk-dataclassification'` and `import {Client} from '@databricks/sdk-abacpolicies'` cannot, and must rename. Sister packages all share the same problem, suggesting a generator-level rename. Worth flagging upstream. - -## Low severity - -_None._ - -## Observations - -### 2. Acronym casing -The codebase mixes `Http` (PascalCase capital-then-lower) with `URLSearchParams` (Web standard ALLCAPS imported by name). Field uses `userAgent` (camelCase). No `Id`/`URL`/`UC` clashes encountered in this small package. The `Http`/`URL` split mirrors the JS ecosystem and is hard to fix locally. -- **Category:** 3 (acronym casing). - -## Domain glossary -- `uc` / Unity Catalog — implicit across all types (the configured resource is a UC catalog). -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `auto-tagging` / `auto-tag` — automatic application of governance tags to columns classified by the scanner (used both as gerund `AutoTagging` in types and as noun `AutoTag` in field names). -- `system tag` / `governance tag` — terminology in JSDoc for `classificationTag` (built-in vs. custom class tag keys). -- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. - -## File coverage -- `src/v1/model.ts` (206 lines): read fully. -- `src/v1/client.ts` (181 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 1e07d093..1c16359d 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -2,88 +2,51 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 -**Inferred domain:** Data Quality monitoring on Unity Catalog schemas and tables. The package models two flavours of "Monitor" (Anomaly Detection for schemas, Data Profiling for tables), Refresh runs of the underlying monitoring pipeline, cron-style scheduling, baseline-vs-monitored drift metrics, custom metric definitions, and notification routing on failure. -**Total weird names flagged:** 15 +**Total weird names flagged:** 8 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 4 | +| High | 3 | +| Medium | 3 | | Low | 1 | -| Observation | 2 | +| Observation | 1 | ## High severity -### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:345,351`, `src/v1/client.ts:316` +### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:345,351`, `src/v1/client.ts:339` - **Why weird:** Singular noun on a list operation. A list returns many monitors but the type and method names use the singular `Monitor`. The wire path is `/api/data-quality/v1/monitors` (plural), the response holds `monitors?: Monitor[]`, and the paginator yields a single `Monitor` — every concrete signal says plural; only the type/method name disagrees. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListMonitorsRequest` / `ListMonitorsResponse` / `listMonitors`. - **Rationale:** REST conventions, the package's own field naming (`monitors`, `refreshes`), and the URL path all use plural. The singular form here is generator template noise, not intent. Same fix applies to refreshes (#2). -### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:357,377`, `src/v1/client.ts:378` +### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:357,377`, `src/v1/client.ts:404` - **Why weird:** Same singular-on-list problem as #1. The wire path is `/refreshes` and the response holds `refreshes?: Refresh[]`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListRefreshesRequest` / `ListRefreshesResponse` / `listRefreshes`. - **Rationale:** Internal consistency: every other place in this file uses the plural `refreshes`. Only the type and method name break the pattern. -### 3. `RefreshState` uses `_UNKNOWN` sentinel instead of `_UNSPECIFIED` — `src/v1/model.ts:72-84` -- **Why weird:** `RefreshState` includes `MONITOR_REFRESH_STATE_UNKNOWN` while every other enum in this file uses `_UNSPECIFIED` (e.g. `DataProfilingStatus.DATA_PROFILING_STATUS_UNSPECIFIED`). Inconsistent sentinel naming across sibling enums on the same type. -- **Category:** 17 (inconsistent sentinel — `UNKNOWN` vs `UNSPECIFIED` in sibling enums). -- **Suggested name:** Normalise the unset member to `_UNSPECIFIED`. -- **Rationale:** The `UNKNOWN`/`UNSPECIFIED` inconsistency with `RefreshTrigger.MONITOR_REFRESH_TRIGGER_UNKNOWN` vs `DataProfilingStatus.DATA_PROFILING_STATUS_UNSPECIFIED` will trip API users who write `===` checks against the sentinel. - -### 4. `RefreshTrigger` uses `_UNKNOWN` sentinel instead of `_UNSPECIFIED` — `src/v1/model.ts:87-95` -- **Why weird:** Same sentinel inconsistency as #3. `RefreshTrigger` uses `_UNKNOWN` for the unset value while sibling enums use `_UNSPECIFIED`. -- **Category:** 17 (sentinel inconsistency). -- **Suggested name:** Normalise the unset member to `_UNSPECIFIED`. -- **Rationale:** Same as #3. - -### 5. `CronSchedulePauseStatus` enum + `pauseStatus` field — `src/v1/model.ts:33-39,152` -- **Why weird:** A two-state on/off concept (`UNPAUSED` vs `PAUSED`) modelled as an enum. The `pauseStatus` field on `CronSchedule` is read-only (per JSDoc), but nothing in the type marks it as such. A boolean `paused: boolean` would model the same thing in one byte of cognitive load. -- **Category:** 11 (trivially-enum where boolean suffices), 6 (misleading: field is read-only but typing does not enforce). -- **Suggested name:** Collapse to `paused?: boolean` (output-only). -- **Rationale:** "Paused" is binary. The `CRON_SCHEDULE_PAUSE_STATUS_*` enum adds no information over a boolean. Sister packages (`jobs`, `alerts`) already use boolean `paused` fields. - -### 6. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:383-405,385,397` and 6 other request types +### 3. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:383-405,385,397` and 6 other request types - **Why weird:** `objectType` is a free-form `string` typed as the values `"schema"` or `"table"`. The discriminator is implicit in a `string`. The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("It is `schema_id` for `schema`, and `table_id` for `table`"). This is a stringly-typed sum type. Every single request and response in the package copies these two fields verbatim with copy-pasted JSDoc (43 lines of the same boilerplate per type, 6+ types). - **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). -- **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string} | {kind: 'table', tableId: string}`. Or at minimum, type `objectType: 'schema' | 'table'`. +- **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string} | {kind: 'table', tableId: string}`. - **Rationale:** TypeScript's strength is exhaustive discriminated unions. Leaving these as `string` defeats the type system and forces every caller to read the JSDoc. The current copy-paste of the same 40-line doc across `CancelRefreshRequest`, `DeleteMonitorRequest`, `DeleteRefreshRequest`, `GetMonitorRequest`, `GetRefreshRequest`, `ListRefreshRequest`, `Refresh`, `UpdateMonitorRequest`, `UpdateRefreshRequest` is a smoking gun for missing abstraction. -### 7. `Client` class — `src/v1/client.ts:55` -- **Why weird:** A class literally named `Client` at the top of the package's public surface. A user importing two SDK packages (e.g., `@databricks/sdk-dataquality` and `@databricks/sdk-dataclassification`) cannot import both as `Client`. The package name is already in the import path, but in IDE go-to-symbol the name appears unqualified. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name). -- **Suggested name:** `DataQualityClient`. -- **Rationale:** Cross-package import collisions force users to alias. Generator-wide concern but worth flagging. - -### 8. `Refresh.startTimeMs` / `Refresh.endTimeMs` — `src/v1/model.ts:442,444` -- **Why weird:** `Ms` suffix to indicate "milliseconds since epoch", but it ignores the local convention of `Date` and `bigint` for UTC timestamps in modern TS. The field is `number` — JavaScript numbers lose precision beyond 2^53, but milliseconds-since-epoch fits, so the type itself is fine. The `Ms` suffix tells the reader to do arithmetic with `new Date(x)`; meanwhile `creation_time` / `last_updated` elsewhere in the SDK uses `bigint` with explicit precision. Inconsistent unit handling across the SDK. -- **Category:** 5 (cryptic abbreviation — `Ms`), 14 (Go-style suffix — Go SDK uses `int64` with `Ms` everywhere; TS would use `Date`). -- **Suggested name:** Leave on the wire as `start_time_ms` but on the TS side use `startedAt: Date` / `endedAt: Date` (transformed in unmarshal). -- **Rationale:** Idiomatic TS uses `Date` for UTC instants. Forcing every caller to write `new Date(refresh.startTimeMs)` to display a timestamp is a paper cut. Other Databricks SDK packages have moved to this. (Generator-wide concern.) - ## Medium severity -### 9. `DataProfilingStatus` has both `ERROR` and `FAILED` members; `DELETE_PENDING` word order — `src/v1/model.ts:57` -- **Why weird:** The enum has six values (`UNSPECIFIED`, `ACTIVE`, `PENDING`, `DELETE_PENDING`, `ERROR`, `FAILED`) — `ERROR` and `FAILED` likely mean the same thing in practice but are modelled separately, with no JSDoc distinguishing them. Separately, `DELETE_PENDING` orders the tokens verb-then-state where most APIs write `PENDING_DELETE` (state-modified-by-action). -- **Category:** 12 (duplicate concept — `ERROR` and `FAILED`), 17 (inconsistent word order vs sibling `PENDING`). -- **Suggested name:** Either merge `ERROR` and `FAILED` into a single member, or document the difference in JSDoc. Reorder `DELETE_PENDING` to `PENDING_DELETE`. -- **Rationale:** The implicit duplicate of `ERROR`/`FAILED` makes this enum harder to reason about than it should be; two synonymous terminal states force callers to handle both. `PENDING_DELETE` mirrors the existing `PENDING` member's modifier-suffix shape. - -### 10. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` -- **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #6). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). +### 4. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` +- **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #3). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). - **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). - **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. -### 11. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` +### 5. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` - **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. - **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). - **Suggested name:** Type: `Destination` (drop the `Notification` prefix since the type is only used here). Field stays `onFailure`; update doc to clarify timeout semantics. - **Rationale:** Field name and JSDoc should agree on whether timeouts are included; type name should not repeat its parent's noun. -### 12. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` +### 6. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` - **Why weird:** Five sibling types all end in `Config`: `AnomalyDetectionConfig`, `DataProfilingConfig`, `InferenceLogConfig`, `TimeSeriesConfig`, `SnapshotConfig`. The `Config` suffix is a proto-style architectural label — it adds no semantic information once you know the type is a configuration record. The Go reference SDK uses these names because protobuf's `*Config` messages map 1:1 to Go structs, but TS does not need to carry that scaffolding. The leak is most visible at the call site `DataProfilingConfig.analysisConfig` where three `Config`-suffixed arms nest inside a `Config`-suffixed field on a `Config`-suffixed type — triple `Config` nesting in a single access path. - **Category:** proto-architectural-leak (repeated `Config` mid/suffix), 8 (redundant suffix), 12 (duplicate concept). - **Suggested name:** Drop the `Config` suffix on the analysis-arm types: `InferenceLog`, `TimeSeries`, `Snapshot`. Keep `AnomalyDetectionConfig` / `DataProfilingConfig` as the top-level monitor configurations (they are genuinely "the config" of a `Monitor`). Or rename uniformly to `AnomalyDetectionSettings` / `DataProfilingSettings` and use `Analysis` for the arm types. @@ -91,7 +54,7 @@ ## Low severity -### 13. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:93, 166, 206, 225, 259, 295, 382, 444, 482` +### 7. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:95, 174, 217, 239, 276, 315, 408, 473, 514` - **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. @@ -99,29 +62,5 @@ ## Observations -### 14. Action verbs in `Client` +### 8. Action verbs in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) - -### 15. Acronym casing -Mixed conventions, all generator-emitted: `Id` (PascalCase-capital-then-lower in `objectId`, `refreshId`), `Ms` (capital-then-lower in `startTimeMs`), `Http` (capital-then-lower in `HttpClient`, `HttpRequest`), `URL`-style ALLCAPS only via the imported web standard `URLSearchParams`. No within-package collisions. -- **Category:** 3 (acronym casing). - -## Domain glossary -- `uc` / Unity Catalog — implicit across the package (the monitored resource is a UC schema or UC table). -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask` and `FieldMask`). -- `quartz` — Apache Quartz Scheduler (Java library) — the cron expression dialect used server-side; surfaces as `quartzCronExpression`. -- `inference log` — predictions + labels + (optional) probabilities for a deployed ML model, used to compute drift on inputs and accuracy on outputs. -- `time series` — analysis configuration where rows have a timestamp column and are bucketed by `AggregationGranularity`. -- `snapshot` — analysis configuration with no time dimension; the table is treated as a single snapshot. -- `refresh` — a single run of the data-monitoring pipeline; produces metric rows in `profileMetricsTableName` / `driftMetricsTableName`. -- `monitor` — the long-lived configuration entity (one per UC schema or table); contains either an `anomalyDetectionConfig` or a `dataProfilingConfig`. -- `baseline table` — a separate table whose statistics drift is computed against (per `baselineTableName`). -- `profile metrics` / `drift metrics` — two distinct output tables; profile = per-window distribution stats, drift = same stats compared against baseline or the previous window. -- `effective` — server-resolved value of an input field (e.g. `effectiveWarehouseId` is the warehouse chosen when the user left `warehouseId` blank). -- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. - -## File coverage -- `src/v1/model.ts` (1030 lines): read fully. -- `src/v1/client.ts` (515 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (42 lines): read fully. diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index edb7510e..b2f8f5b0 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -2,16 +2,15 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 -**Inferred domain:** Account-level Disaster Recovery — manage `FailoverGroup` resources (regions, workspace sets, UC replication config) and `StableUrl` resources (failover-aware endpoints for workspaces), including a `failover` action to swing the primary region. -**Total weird names flagged:** 9 +**Total weird names flagged:** 6 ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 3 | +| High | 2 | +| Medium | 2 | | Low | 1 | -| Observation | 2 | +| Observation | 1 | ## High severity @@ -21,45 +20,33 @@ - **Suggested name:** `FailoverRequest` (the resource is unambiguous in this package) or `TriggerFailoverRequest` (more explicit verb). - **Rationale:** No other request in the package re-states the resource word inside its verb. The wire path is `…/failover`, so a single `Failover` in the type name is sufficient. -### 2. `StableUrl` (and all references: `CreateStableUrlRequest`, `stableUrl`, `stableUrlId`, `stableUrlNames`, `ListStableUrlsResponse`, etc.) — `src/v1/model.ts:53,57,64,82,87,162,167,198,211,213,247,326` -- **Why weird:** Acronym casing for `URL` is inconsistent with the wider JS/TS ecosystem, which treats `URL` as ALLCAPS (Web `URL` global, `URLSearchParams`, `urlencoded`). This package uses `Url` (PascalCase capital-then-lower) for one of the two top-level resources. `client.ts` mirrors the inconsistency: `createStableUrl`, `getStableUrl`, `deleteStableUrl`, `listStableUrls`. -- **Category:** 3 (acronym casing inconsistency). -- **Suggested name:** `StableURL` / `CreateStableURLRequest` / `stableURLId` (matches Web `URL` global) **or** keep `Stable` + `Url` consistently across both type and wire (current) but explicitly document the choice. -- **Rationale:** The mixed casing is jarring against the surrounding Web platform conventions (e.g., `URLSearchParams`). This is a package-wide rename; the cheaper compromise is to keep `Url` but document the convention. - -### 3. `effectivePrimaryRegion` vs `initialPrimaryRegion` vs `targetPrimaryRegion` field triplet — `src/v1/model.ts:125,149,101` -- **Why weird:** Three subtly-different "primary region" fields whose semantics depend entirely on a JSDoc paragraph: +### 2. Write-only "primary region" fields are not distinguished in the type shape — `src/v1/model.ts:125,149,101` +- **Why weird:** Two of the three "primary region" fields are write-only, but the type signature gives no hint: - `effectivePrimaryRegion` — current truth; mutated by failover. - `initialPrimaryRegion` — create-only input; never returned. - `targetPrimaryRegion` — request-only on `failover` action. - A reader scanning the type sees three identical-looking string fields. Two of them (`initial`, `target`) are write-only — that critical fact is hidden in JSDoc. -- **Category:** 1 (vague — adjectives `effective`/`initial`/`target` carry the entire weight), 15 (generic field name across three different lifecycles), 6 (misleading — type signature gives no hint that `initialPrimaryRegion` is response-stripped). -- **Suggested name:** Consider splitting: keep `primaryRegion` (effective) on `FailoverGroup`; lift `initialPrimaryRegion` into `CreateFailoverGroupRequest` as a sibling of `failoverGroup`; keep `targetPrimaryRegion` on `FailoverFailoverGroupRequest`. If the generator cannot split (since this mirrors a proto with output_only annotations), at minimum mark `initialPrimaryRegion` `@deprecated`-style write-only in JSDoc with a `WRITE-ONLY` tag. -- **Rationale:** The current shape forces the user to read three different paragraphs to learn that the same-typed fields obey three different rules. This is the most user-hostile naming pattern in the file. + A reader scanning the type sees three identical-looking, always-present string fields. The fact that `initial` and `target` are write-only (response-stripped) is hidden in JSDoc rather than expressed in the type. +- **Category:** type-shape (optionality / write-only semantics not reflected in the field's declared shape). +- **Suggested fix:** Reflect the write-only semantics in the type shape — split the write-only inputs onto the request types where they actually apply (`initialPrimaryRegion` on `CreateFailoverGroupRequest`, `targetPrimaryRegion` on the failover request) rather than declaring all three on the resource. This is a shape change, not a rename; the field names stay the same. +- **Rationale:** The current shape forces the user to read JSDoc to learn that same-typed, always-present fields obey three different read/write rules. A shape that separates write-only inputs from the returned resource makes the contract self-evident. ## Medium severity -### 4. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:278` +### 3. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:289` - **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 131) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. - **Category:** 5 (cryptic abbreviation `Uc`), 8 (redundant `Uc` prefix inside Uc context), 17 (inconsistency — `unityCatalog` vs `Uc`). - **Suggested name:** `Catalog` (or `ReplicatedCatalog`), and field type `catalogs: Catalog[]`. - **Rationale:** `UcReplicationConfig.catalogs: UcCatalog[]` reads as "UC replication config's UC catalogs" — redundant. The full `unityCatalog` spelling is used adjacent in the file; either propagate that or drop the prefix entirely inside the UC-scoped type. -### 5. `UcReplicationConfig` — `src/v1/model.ts:284` +### 4. `UcReplicationConfig` — `src/v1/model.ts:295` - **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). -- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). Field stays `unityCatalogAssets` -> `unityCatalogConfig` (see #4). +- **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. -### 6. `Client` class name — `src/v1/client.ts:52` -- **Why weird:** Plain `Client` is the maximally-generic name. Once imported, callers see `import { Client } from '@databricks/sdk-disasterrecovery/v1'` — fine if used qualified, but `new Client()` floating in user code is meaningless. Sibling packages all do the same per generator convention; flagging this once at the package level. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `DisasterRecoveryClient`. (Or rely on import aliases.) -- **Rationale:** Most SDK conventions name the client after the service. The bare `Client` is a generator default and inherits whatever the import alias is. - ## Low severity -### 7. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:204` +### 5. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:218` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). @@ -67,31 +54,5 @@ ## Observations -### 8. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#7), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. - -### 9. Acronym casing inconsistency: `URL` vs `Uri` vs `Url` -Within this package: -- `stableUrl`/`StableUrl` (PascalCase capital-then-lower). -- `uriByRegion`/`LocationMappingEntry.uri` (`Uri` capital-then-lower). -Two different casings for two related acronyms (URL/URI), and both differ from the Web platform's ALLCAPS `URL`/`URLSearchParams`. The TS code uses `Url`/`Uri` to follow Go-style camelCase. Pick one. (Listed at observation since this is a package-wide policy question, not a single-line fix.) -- **Category:** 3 (acronym casing). - -## Domain glossary -- **DR** — Disaster Recovery. Encoded in the package name `disasterrecovery`. Mentioned once in a JSDoc on `replicateWorkspaceAssets` ("control plane DR"). -- **UCDR** — Unity Catalog Disaster Recovery (UC data plane replication). Mentioned in JSDoc at `model.ts:113`. Not present as an identifier. -- **CPDR** — Control Plane Disaster Recovery (notebooks, jobs, clusters, etc.). Mentioned in JSDoc at `model.ts:113,308`. Not present as an identifier — encoded only via `replicateWorkspaceAssets: boolean`. -- **UC** — Unity Catalog. Appears as the `Uc` prefix on `UcCatalog`, `UcReplicationConfig`, and as `unityCatalog…` in field names (inconsistency, see #4). -- **EA** — Early Access / Early Adoption? Mentioned in JSDoc on `WorkspaceSet.workspaceIds` (line 305) as "EA: exactly 2 workspaces (one per region)". Not decoded anywhere in the package. -- **RPO** — Recovery Point Objective. Not explicitly named; `replicationPoint` (line 144) is effectively the RPO marker. -- **RTO** — Recovery Time Objective. Not present in this package. -- **spog** — Single Pane of Glass (Databricks-internal term for the account-level UI host). Referenced once in a comment on `StableUrl.url` (line 256) as ``. No identifier carries the term. -- **etag** — Entity Tag (RFC 9110). Used for optimistic concurrency. Lowercase per wire. -- **FQ** (used in this audit) — Fully-qualified resource name (e.g., `accounts/{account_id}/failover-groups/{failover_group_id}`). -- **wkt** — Well-Known Types (import path `@databricks/sdk-core/wkt`). -- **m2m** / **u2m** / **pat** / **oidc** / **iam** — not encountered in this package. - -## File coverage -- `src/v1/model.ts` (620 lines): read fully. -- `src/v1/client.ts` (418 lines): read fully. -- `src/v1/index.ts` (30 lines): read fully. +### 6. Action-verb consistency on `Client` (mostly good) +Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#5), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index 23d31430..fb085176 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -1,93 +1,45 @@ # Naming Audit: entitytagassignments -**Path:** `packages/entitytagassignments/src/v1/` +**Path:** `packages/uc/entitytagassignments/src/v1/` **Versions audited:** v1 -**Inferred domain:** Unity Catalog entity tag assignments — create/get/list/update/delete key/value tags on UC entities (tables, schemas, columns, volumes, etc.), with provenance (`sourceType`) metadata. Sister of `tagassignments` (non-UC entities: apps, dashboards, geniespaces, notebooks) and `tagpolicies` (governed tag definitions). -**Total weird names flagged:** 10 +**Total weird names flagged:** 5 ## Summary | Severity | Count | | --- | --- | -| High | 5 | +| High | 2 | | Medium | 2 | -| Low | 0 | -| Observation | 3 | +| Observation | 1 | ## High severity -### 1. Package name `entitytagassignments` vs. sister `tagassignments` — `package directory name` -- **Why weird:** Two packages exist whose names differ only by the prefix `entity`: `entitytagassignments` (Unity Catalog tables/schemas/columns) and `tagassignments` (apps, dashboards, geniespaces, notebooks). Both model "a tag assigned to a thing", both expose the same five operations (Create/Get/List/Update/Delete), and both have a primary type called `(Entity)TagAssignment`. The split mirrors a backend HTTP-path split (`/api/2.1/unity-catalog/entity-tag-assignments` vs. `/api/2.0/tag-assignments`) that is invisible to TS users. -- **Category:** 12 (duplicate concept across two packages — overlapping responsibility), 1 (vague: what is a non-entity tag assignment?), 16 (the field `entityType` in `tagassignments` carries the *exact same* notion that the prefix `entity` carries here, so the disambiguating prefix is doubly redundant). -- **Suggested name:** Merge into a single package `tagassignments` keyed by `entityKind` ("uc" vs. "platform"), or rename to `uctagassignments` so the surface marker is "uc", not "entity". The non-UC sibling can drop its own `entityType` field discrimination and become `platformtagassignments`. As a smaller fix: `unitycatalogtags` here, `platformtags` there. -- **Rationale:** Two `Client` classes called `Client`, with two `TagAssignment` / `EntityTagAssignment` types, both shipping `tagKey`/`tagValue`/`entityType`, will collide in user imports and force aliasing on every co-use. The split exists for backend reasons but leaks raw into the SDK. Worth flagging upstream as a generator-level concern. - -### 2. `TagAssignmentSourceType` — `src/v1/model.ts:9` -- **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. Combined with the surrounding type `EntityTagAssignment`, the relevant field is `sourceType: TagAssignmentSourceType` — five words to say "where did this come from". +### 1. `TagAssignmentSourceType` — `src/v1/model.ts:9` +- **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. - **Category:** 20 (type-suffix tautology — `Type` on an enum), 7 (overly verbose). -- **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). Field becomes `source: TagSource`. -- **Rationale:** The shorter name is unambiguous in context (`EntityTagAssignment.source` reads better than `EntityTagAssignment.sourceType`). Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. - -### 3. `entityType: string` everywhere — `src/v1/model.ts:28,40,56,68` -- **Why weird:** Four occurrences of `entityType?: string | undefined` with no enum or string-literal union to constrain values. The JSDoc says "The type of the entity to which the tag is assigned" but never lists which values are valid (compare sister `tagassignments`: doc explicitly lists `apps, dashboards, geniespaces, notebooks`). For Unity Catalog entities, the actual valid set is something like `table`, `schema`, `catalog`, `column`, `volume`, `function`, `model` — none of which is documented or constrained in the type. -- **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what type strings are valid?), 6 (misleading — looks free-form, is actually constrained). -- **Suggested name:** `EntityKind` (string-literal union or enum) typed as the field. E.g. `entityKind?: 'table' | 'schema' | 'catalog' | 'column' | 'volume' | 'function' | 'model'`. The field name `Type` also collides with the JS reserved-ish word — `Kind` reads more cleanly. -- **Rationale:** Stringly-typed enum fields are a generator anti-pattern. The valid set is closed; the type should say so. `Type` as a noun is also overused — `Kind` is the convention in TS standard library (`SyntaxKind`, `NodeKind`). +- **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). +- **Rationale:** The shorter name is unambiguous in context. Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. -### 4. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` +### 2. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` - **Why weird:** `DeleteEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag to delete". `GetEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag". But `EntityTagAssignment.tagKey` (on the actual returned/created object) and `CreateEntityTagAssignmentRequest.tagAssignment.tagKey` are documented as just "The key of the tag" with no required marker — yet you cannot create or get a tag without a key. The `?: string | undefined` typing makes all of them optional in TS. Type and doc disagree. - **Category:** 6 (misleading — type says optional, semantics says required), 17 (inconsistent — some docs say "Required.", others don't, for what is the same logical field). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) and remove the "Required." doc preamble since the type enforces it. Apply uniformly across all four request types and the assignment type itself. - **Rationale:** "Required." in a docstring while the type is optional is a generator smell. Honest required-ness should travel through the type. -### 5. `Client` class — `src/v1/client.ts:41` -- **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The other tag packages (`tagassignments`, `tagpolicies`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages). -- **Suggested name:** `EntityTagAssignmentsClient` (or `UnityCatalogTagsClient`). -- **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing. Generator-level concern. - ## Medium severity -### 6. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` +### 3. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` - **Why weird:** The plural appears only on the list endpoint; the rest of the surface is singular. Singular/plural mix is consistent with the Go SDK and other packages, but worth flagging that the resource name on the wire is `/entity-tag-assignments` (plural) while the type name is singular `EntityTagAssignment`. The list response is `ListEntityTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. - **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. -### 7. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:118,137,167,230` +### 4. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:123,145,178,244` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. -## Low severity - -_None._ - ## Observations -### 8. Action verb consistency +### 5. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. - -### 9. Acronym casing -The file uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri`/`UC` casing clashes encountered. -- **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). - -### 10. Domain leakage from sister packages -Three packages — `entitytagassignments`, `tagassignments`, `tagpolicies` — all collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment` (or `TagPolicy`) type, and its own `tagKey`/`tagValue`. Co-import requires extensive aliasing. The split aligns to wire-side API groupings, not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. -- **Category:** 12 (duplicate concept across siblings). - -## Domain glossary -- `uc` / Unity Catalog — implicit across the package; the HTTP path includes `/unity-catalog/entity-tag-assignments`. -- `entity` — generic UC resource: catalog, schema, table, column, volume, function, model (never enumerated in this package's types). -- `entity name` — wire docs say "fully qualified name" — i.e., dotted form like `catalog.schema.table` (or column ref). -- `entity type` — string discriminator for the kind of entity (no enum in this package). -- `tag key` / `tag value` — string key/value pair attached to an entity (the "tag" itself). -- `tag policy` — governed tag definition with constraints/values (a separate sister package). -- `governed tag` — a tag whose key matches an active `TagPolicy`. JSDoc mentions ASSIGN/MANAGE permissions on the tag policy. -- `source type` — provenance of the assignment: user vs. data-classification (today, only `SYSTEM_DATA_CLASSIFICATION` is enumerated). - -## File coverage -- `src/v1/model.ts` (161 lines): read fully. -- `src/v1/client.ts` (265 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (15 lines): read fully. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index 7228332d..0aa3542b 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -3,100 +3,28 @@ **Path:** `packages/environments/src/v1/` **Versions audited:** v1 **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` -**Inferred domain:** Workspace-level Python "base environment" management for serverless notebooks and jobs. A `WorkspaceBaseEnvironment` points at a YAML dependency manifest (on WSFS or UC Volumes) for either CPU or GPU compute; the workspace also has a singleton `DefaultWorkspaceBaseEnvironment` that names one CPU default and one GPU default. The package exposes CRUD plus a `refresh` action and three long-running-operation helper classes. -**Total weird names flagged:** 10 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 3 | -| Low | 1 | -| Observation | 0 | +| High | 2 | --- ## High severity -### 1. `Environment` concept fragmented across `environments` and `clusterlibraries` packages — `packages/environments/` vs `packages/clusterlibraries/` -- **Why weird:** Two sibling packages model overlapping pieces of the same domain: - - `clusterlibraries/v2` exposes `DefaultBaseEnvironment`, `BaseEnvironmentType`, `DefaultBaseEnvironmentCache`, `DefaultBaseEnvironmentCache_Status`, `Environment`, `MaterializedEnvironment`, and full CRUD on `DefaultBaseEnvironment`s. - - `environments/v1` exposes `WorkspaceBaseEnvironment`, the same `BaseEnvironmentType` enum (redefined, not imported), `WorkspaceBaseEnvironmentCache`, `WorkspaceBaseEnvironmentCache_Status` (same shape as `DefaultBaseEnvironmentCache_Status`), and `DefaultWorkspaceBaseEnvironment`. -- The relationship between `DefaultBaseEnvironment` (cluster-libraries package) and `WorkspaceBaseEnvironment` / `DefaultWorkspaceBaseEnvironment` (this package) is undocumented. They share enum *values* (`BASE_ENVIRONMENT_TYPE_UNSPECIFIED | CPU | GPU`) and status enum members but are textually duplicated rather than reused. -- **Category:** 12 (duplicate concept across packages), 6 (misleading — user can't infer which package owns what). -- **Suggested name:** Either (a) consolidate into a single `baseenvironments` package and have `clusterlibraries` import from it, (b) explicitly cross-reference each shared type in docstrings, or (c) version one of them (`clusterlibraries` `DefaultBaseEnvironment` is presumably v1, `environments` `WorkspaceBaseEnvironment` is v2 — say so). -- **Rationale:** Same shape, redefined in two packages, with subtly different naming (`DefaultBaseEnvironment` vs `WorkspaceBaseEnvironment`). Consumers will hit type-incompatibility errors when passing a value from one package into the other. - -### 2. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:718` +### 1. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:718` - **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. The 26 characters are baked into the *type prefix*, not the enum-member prefix; this is a TS-surface concern, not a proto-codegen concern. - **Category:** 7 (overly verbose type prefix), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). - **Suggested name:** Drop one of the adjectives in the *type* name. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. - **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. -### 3. `WorkspaceBaseEnvironment.status` field name and type's domain do not align — `model.ts:737` +### 2. `WorkspaceBaseEnvironment.status` field type's name and the type's domain do not align — `model.ts:737` - **Why weird:** `WorkspaceBaseEnvironment.status` is typed `WorkspaceBaseEnvironmentCache_Status` — i.e. the *status of a Cache*. But the field documents itself as "The status of the materialized workspace base environment", not the status of a cache. The user reads `env.status` and the type's name implies a different concept (cache) than the doc and the data (materialization state of the environment). - **Category:** 16 (field type contradicts type domain), 6 (misleading). -- **Suggested name:** Either (a) rename the enum to `MaterializationStatus` (the doc's own words) and drop the `Cache` qualifier, or (b) rename the field to `cacheStatus` to match the type. -- **Rationale:** Field name and type name should describe the same thing. The mismatch is a tell that the enum was named for an internal proto nesting that the public API doesn't surface. - -### 4. `Operation` exported with no namespace prefix — collides on a single-import surface — `model.ts:641, index.ts:26` -- **Why weird:** The type name `Operation` is one of the most generic words in software (matches OS-level, math, audit-log, business, telemetry, async-task… meanings). It is exported alongside two related types (`GetOperationRequest`, `WorkspaceBaseEnvironmentOperationMetadata`) and three classes (`CreateWorkspaceBaseEnvironmentOperation`, etc.). It is also a `google.longrunning.Operation`-shaped envelope (the docstring at model.ts:638 even says so), but the name doesn't say that. -- **Category:** 1 (vague/generic), 15 (generic type name losing meaning). -- **Suggested name:** `LongRunningOperation`, `LROperation`, `AsyncOperation`, or namespace it under the package name (`EnvironmentOperation`). Whichever wins, the request type should match: `GetLongRunningOperationRequest` etc. -- **Rationale:** A consumer importing `{Operation}` into a file that also has Slack `Operation`, audit `Operation`, or domain-specific `Operation` is in for a renaming party. The name signals nothing about being a polling envelope. - -### 5. `Operation.result` discriminated union uses `$case: 'error' | 'response'` — naming verbose & inconsistent — `model.ts:666-677` -- **Why weird:** The union's discriminator field is `$case` (the `$` prefix is a wire/codegen artifact, not idiomatic TS — see `clusterlibraries` and `database` audits where the same pattern surfaces). The `'response'` variant's payload field is also called `response`, so consumers write `op.result.response.response` is *not* the access path but `op.result.$case === 'response'` then `op.result.response` is. Conflating the discriminator literal `'response'` with a payload field also named `response` is confusing. Same for `'error'` / `error`. -- **Category:** 6 (misleading — `$case`/`response`/`error` triple-overloading), 17 (inconsistency with idiomatic TS discriminated unions which use `kind` or `type`), 14 (Go/proto codegen artefact). -- **Suggested name:** Use `kind` (or `type`) instead of `$case`, and use distinct names like `kind: 'error' | 'success'` with payload fields `error: DatabricksServiceException` / `value: Record<...>` (or similar). See database audit #14 for an analogous critique. -- **Rationale:** `$` in identifiers in TS implies "internal/synthetic". This is a leak of the ts-proto codegen convention. Consumers writing `op.result?.$case` see synthetic noise. - -### 6. `DatabricksServiceExceptionWithDetailsProto` — Proto suffix on a TS type, "Exception" implies an Error class — `model.ts:552, index.ts:18` -- **Why weird:** Three problems in one name: - 1. **`Proto` suffix** on a TypeScript identifier — leaks the proto origin into the type name (`Proto` means nothing to a TS consumer). - 2. **`Exception`** is Java/Python terminology; TS/JS uses `Error`. The type is a *data* representation of an error (it's a plain interface with `errorCode`/`message`/`stackTrace`), not an actual thrown exception class. Naming a data structure `Exception` suggests it can be thrown. - 3. **Verbose** — 41 characters. The shape is `{ errorCode, message, stackTrace, details }` — i.e. a typical Google-RPC error. -- **Category:** 20 (type-suffix tautology — `Proto`), 14 (Java-style name — `Exception`), 7 (overly verbose), 6 (misleading — looks throwable). -- **Suggested name:** `ServiceErrorDetails`, `DatabricksError`, or `RpcError`. Drop the `WithDetails`, `Proto`, and `Exception` suffix all at once. -- **Rationale:** The name has the worst of every world: Java verb + Proto codegen tag + length. No piece of the name helps a TS consumer. - ---- - -## Medium severity - -### 7. `ErrorCode` enum exports ~100 values and is mostly deprecated — `model.ts:16-514, index.ts:12` -- **Why weird:** The `ErrorCode` enum has roughly 100 members. The doc comments mark a large fraction as deprecated ("kept to maintain backwards compatibility"). Many members are domain-specific (e.g. `IPYNB_FILE_IN_REPO`, `GIT_URL_NOT_ON_ALLOW_LIST`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `DAC_ALREADY_EXISTS`) and have nothing to do with environments. The enum is a kitchen-sink import of every Databricks-platform error code, exported from a *workspace-base-environment* package. -- **Category:** 1 (overly broad — exposed in the wrong scope), 7 (overly verbose surface), 12 (duplicate concept — `ErrorCode` likely lives in many packages). -- **Suggested name:** Move to a shared `@databricks/sdk-databricks/apierror` (where `apierr/codes/` already lives, per AGENTS.md) and import it. The environments package should export at most the subset of codes it actually returns. -- **Rationale:** Each package re-declaring all 100 error codes makes them non-comparable across imports and bloats the bundle. The package's `client.ts` imports `ApiError` from `@databricks/sdk-core/apierror` (utils.ts:5) — there is already a canonical location. - -### 8. `ErrorCode` values are SCREAMING_SNAKE strings, e.g. `'PROVIDER_SHARE_NOT_ACCESSIBLE'` — `model.ts:513` -- **Why weird:** Enum values are SCREAMING_SNAKE wire strings (e.g. `MAX_CHILD_NODE_SIZE_EXCEEDED`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). 100+ values × ~30 chars each = a large surface that consumers must spell exactly. TS pattern is `PascalCase` enum members. -- **Category:** 14 (Java/Go-style names), 18 (long enum values). -- **Suggested name:** `MaxChildNodeSizeExceeded`, `StorageCredentialAlreadyExists`, etc. -- **Rationale:** TS conventions favour `PascalCase`. Wire format can keep SCREAMING_SNAKE via marshal/unmarshal. - -### 9. `DatabricksServiceExceptionWithDetailsProto` — `Service` mid-position is an architectural-layer leak, not domain — `model.ts:552, index.ts:18` -- **Why weird:** The mid-position word `Service` in `DatabricksServiceExceptionWithDetailsProto` describes a server-side architectural layer ("a service threw this exception"), not anything about the data the type carries. The type is a plain error payload with `errorCode`/`message`/`stackTrace`/`details`; no field references a "service". `Service` here mirrors the Java `*ServiceException` superclass pattern and the proto message name `DatabricksServiceExceptionWithDetails` — both server-internal concepts that have no meaning for a TS SDK consumer. Combined with the trailing `Proto` (codegen origin) the name is a stack of three architectural tags: `Service` (layer) + `Exception` (Java throwable) + `Proto` (wire format). -- **Category:** proto-architectural-leak (mid-position `Service` is not the domain), 14 (Java-style naming), 20 (`Proto` suffix tautology). -- **Suggested name:** `DatabricksErrorDetails`, `ServiceErrorPayload` is still leaky; prefer `ApiErrorDetails` or `RpcErrorDetails` if the gRPC framing is part of the public contract, otherwise just `ErrorDetails`/`DatabricksError`. Drop `Service`, `Exception`, and `Proto` together. -- **Rationale:** The proto-architectural-leak audit treats mid-position `Service` as a server-implementation tell that leaks into TS surfaces. Even setting aside the existing `Proto`/`Exception` complaints (#6), the `Service` infix on a *data* type tells the consumer nothing useful and reinforces the impression that the SDK exposes server internals. The unmarshal schema (`model.ts:757`) propagates the same name; renaming the type renames its schema. - ---- - -## Low severity - -### 10. `WorkspaceBaseEnvironment.isDefault` — boolean field on the resource, but `DefaultWorkspaceBaseEnvironment` is a separate type — `model.ts:741` -- **Why weird:** A `WorkspaceBaseEnvironment` has an `isDefault` boolean (model.ts:741). The same package also has a separate `DefaultWorkspaceBaseEnvironment` type (model.ts:564) that represents the workspace's default. Two encodings of the same fact: a boolean on each environment, and a separate "default" type listing CPU/GPU defaults. A consumer can't tell from the type whether `isDefault` is computed from `DefaultWorkspaceBaseEnvironment` or vice versa. -- **Category:** 12 (duplicate concept), 6 (misleading — which one is the source of truth?). -- **Suggested name:** Document the relationship explicitly; or drop one. If `isDefault` is server-computed, it could be a `default: 'cpu' | 'gpu' | null` enum so a reader can tell which kind of default at a glance. -- **Rationale:** Two representations of "is this the default" invite drift. - ---- - -## Observation - -_None._ +- **Suggested name:** Rename the enum type to `MaterializationStatus` (the doc's own words) and drop the `Cache` qualifier. +- **Rationale:** Field name and type name should describe the same thing. The mismatch is a tell that the enum type was named for an internal proto nesting that the public API doesn't surface. --- diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index 79ebc771..d014845b 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -2,135 +2,67 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 -**Inferred domain:** MLflow Experiments — track Experiments (named containers), Runs (single executions, with metrics/params/tags/artifacts/datasets/model inputs/outputs), LoggedModels (versioned model artifacts attached to a Run), and the surrounding CRUD (create/get/list/search/restore/delete/update/log). -**Total weird names flagged:** 25 +**Total weird names flagged:** 12 ## Summary | Severity | Count | | --- | --- | -| High | 11 | -| Medium | 10 | +| High | 5 | +| Medium | 4 | | Low | 3 | -| Observation | 1 | ## High severity -### 1. `Run` — `src/v1/model.ts:701` -- **Why weird:** The central noun is named `Run`. `Run` is a reserved-feeling word in any JS context: `Promise.all().run()`, test framework "runs", workflow "runs". The user has zero context that this is an MLflow Run (a tracked execution of a training/eval script with metrics/params/artifacts). Compare with `jobs.Run` (already a different concept in this SDK) and `pipelines.Run`. -- **Category:** 1 (vague/generic), 12 (duplicate concept across packages — `jobs.Run`, `pipelines.Run`), 15 (generic field/type name losing meaning). -- **Suggested name:** `MlflowRun` or `ExperimentRun`. Re-export the alias and deprecate `Run`. -- **Rationale:** When a consumer writes `import {Run} from '@databricks/sdk-experiments/v1'` they may already have `Run` in scope from `@databricks/sdk-jobs/v2`. The two have unrelated schemas. Disambiguating the type name removes a foot-gun. - -### 2. `Experiment` — `src/v1/model.ts:219` -- **Why weird:** Same generic-noun problem as #1. `Experiment` is a generic English word; this is specifically an MLflow Experiment (named container of MLflow Runs with a UUID and a UC artifact-location). Multiple Databricks teams may legitimately have "experiment" types in the future (notebooks?, lakehouse-experiments?). -- **Category:** 1 (generic), 15 (generic name). -- **Suggested name:** `MlflowExperiment`. -- **Rationale:** Same as #1 — disambiguating the package's central noun against future Databricks "experiments" features prevents conflicts. - -### 3. `Metric` / `Param` / `Run` / `Experiment` — all single-word top-level types — `src/v1/model.ts:219,612,656,701` -- **Why weird:** Four central types are bare nouns (`Metric`, `Param`, `Run`, `Experiment`). All four will collide with names in scope at the user's call site. None says "MLflow". `Param` in particular collides with React Router `Params`, Express `Params`, Node `URLSearchParams`, etc. -- **Category:** 1 (vague), 10 (reserved-word adjacent), 12 (duplicate concept against React/Node `Params`). -- **Suggested name:** `MlflowMetric`, `MlflowParam`, `MlflowRun`, `MlflowExperiment` — or namespace under `Mlflow.{Metric, Param, Run, Experiment}`. -- **Rationale:** Even MLflow's own protobuf calls these `mlflow.Run`, `mlflow.Experiment`, `mlflow.Metric` — they assume a namespace. Flattening them into TS without one loses that disambiguation. - -### 4. `LoggedModel` — `src/v1/model.ts:549` +### 1. `LoggedModel` — `src/v1/model.ts:537` - **Why weird:** `LoggedModel` is a noun-phrase made of past-participle adjective + noun. The "logged" prefix is doing the disambiguation against `RegisteredModel`, `ServingModel`, `MlflowModel` etc. But (a) past-tense adjectives in type names read awkwardly (`LoggedModel`, `DeletedExperiment`, `FinishedRun` would all be similarly weird), and (b) `Logged` does not describe what the type *is* — it describes the verb history that produced it. - **Category:** 6 (misleading: "Logged" describes history, not identity), 13 (verb-tense in noun-phrase). - **Suggested name:** `MlflowModel`, `TrackedModel`, or `RunModel` (since every `LoggedModel` belongs to a Run via `sourceRunId`). -- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #5). +- **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #2). -### 5. `LoggedModel` family — many separate types — `src/v1/model.ts:549, 557, 568, 596, 604` + request/response — `model.ts:72, 161, 169, 257, 303, 464, 803, 921` +### 2. `LoggedModel` family — many separate types — `src/v1/model.ts:537, 545, 556, 584, 592` + request/response — `model.ts:71, 158, 166, 253, 296, 452, 789, 905` - **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModelRequest`, `DeleteLoggedModelRequest`, `DeleteLoggedModelTagRequest`, `FinalizeLoggedModelRequest`, `GetLoggedModelRequest`, `LogLoggedModelParamsRequest`, `SearchLoggedModelsRequest`, `SetLoggedModelTagsRequest`. The `LoggedModel` prefix is repeated 13 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. - **Category:** 7 (overly verbose), 12 (duplicate concept against `Model*` family that may exist in `modelregistry` package). - **Suggested name:** Either drop the `Logged` and call the family `MlflowModel` / `MlflowModelData` / `MlflowModelInfo` / `MlflowModelParameter` / `MlflowModelTag` / `MlflowModelStatus`, or nest under a namespace. - **Rationale:** 13 occurrences of "LoggedModel" in identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. -### 6. `LoggedModelParameter` vs `Param` — inconsistent abbreviation for the same concept — `src/v1/model.ts:596` vs `model.ts:656` -- **Why weird:** Two distinct types both model `{key: string, value: string}` parameter pairs: `LoggedModelParameter` (for a `LoggedModel`) and `Param` (for a `Run`). JSDoc at line 595 says "Parameter associated with a `LoggedModel`" and at 655 "Param associated with a run". Why one type is spelled out (`Parameter`) and the other abbreviated (`Param`) is unexplained. -- **Category:** 12 (duplicate concept), 17 (inconsistent abbreviation: `Parameter` vs `Param`). -- **Suggested name:** Align the abbreviation: either both `Parameter` or both `Param`. -- **Rationale:** The difference between `Run.params: Param[]` and `LoggedModel.data.params: LoggedModelParameter[]` is cosmetic — the underlying shape is identical. - -### 7. `ExperimentTag` / `RunTag` / `InputTag` / `LoggedModelTag` — four tag types for the same shape — `src/v1/model.ts:240, 364, 604, 765` -- **Why weird:** Four `{key: string, value: string}` types, one per parent entity. All four have identical shapes. The only differentiator is the parent entity — but the type itself is indistinguishable. -- **Category:** 12 (duplicate concept × 4). -- **Suggested name:** Adopt a single parent prefix convention so `MlflowTag` (or `Mlflow.Tag`) carries the shared shape, with parent-specific variants only when fields actually diverge. -- **Rationale:** An end-user picking the wrong tag type (`InputTag` vs `RunTag` etc.) will not get a compile error because they have the same shape. - -### 8. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:701, 711, 721, 757` -- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:710-718`), `RunInfo` is "id, name, status, times, user" (`model.ts:720-754`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:756-762`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. -- **Category:** 1 (vague: `Data`/`Info`/`Inputs`), 15 (generic field name). +### 3. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:688, 698, 708, 744` +- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:697-705`), `RunInfo` is "id, name, status, times, user" (`model.ts:707-741`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:743-749`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. +- **Category:** 1 (vague: `Data`/`Info`/`Inputs` type names). - **Suggested name:** Flatten into `Run` (one object). If they must stay split, name them by content: `RunMetadata` (instead of `RunInfo`), `RunMeasurements` (instead of `RunData`), `RunDatasetsAndModels` (instead of `RunInputs`). - **Rationale:** `RunInfo` vs `RunData` requires the reader to look up the schema to know which fields go where. Naming by content removes that lookup. -### 9. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:568, 557` -- **Why weird:** Same `Info`/`Data` split as `Run` (#8). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem. -- **Category:** 1 (vague), 15 (generic). +### 4. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:556, 545` +- **Why weird:** Same `Info`/`Data` split as `Run` (#3). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem on the type names. +- **Category:** 1 (vague). - **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. -- **Rationale:** Same as #8. +- **Rationale:** Same as #3. -### 10. `KILLED` enum value — `src/v1/model.ts:36` -- **Why weird:** `RunStatus.KILLED` reads aggressively. MLflow's own term is `KILLED` (preserved here from the wire format), but "killed" is uncommon in API-design vocabulary outside of Unix signals. `Cancelled`, `Aborted`, `Stopped` are typical English equivalents. The JSDoc says "Run killed by user." -- **Category:** 6 (misleading — sounds like an error, but it is a user-initiated state), 18 (uncommon enum value), 17 (inconsistent verb tense with `RUNNING` / `SCHEDULED` — `KILLED` is past tense of an active verb). -- **Suggested name:** `RunStatus.Cancelled` (TS) with wire-value remaining `KILLED`. Match the rest: `Running`, `Scheduled`, `Finished`, `Failed`, `Cancelled`. -- **Rationale:** `Cancelled` is the dominant industry term for user-initiated termination (HTTP `499 Client Closed Request`, GRPC `CANCELLED`, etc.). - -### 11. `ViewType` enum — generic name + inconsistent field names for the same enum — `src/v1/model.ts:40-47` -- **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). The same enum is used as `viewType` on `ListExperimentsRequest` (model.ts:405), `runViewType` on `SearchRunsRequest` (model.ts:886), and `viewType` on `SearchExperimentsRequest` (model.ts:789) — two fields named `viewType` and one named `runViewType` for the same enum. -- **Category:** 1 (generic name), 17 (inconsistent field names — `viewType` vs `runViewType` for the same enum). -- **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. Field name: pick one (`viewType` everywhere, or rename uniformly). -- **Rationale:** A field that means "filter experiments/runs by deleted state" is more searchable as `lifecycleFilter`. +### 5. `ViewType` enum — generic type name — `src/v1/model.ts:40-47` +- **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). It is the enum used to filter experiments/runs by deleted state. +- **Category:** 1 (generic type name). +- **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. +- **Rationale:** `ViewType` gives no hint that it selects experiments/runs by lifecycle/deleted state; a domain type name like `LifecycleFilter` is more searchable. ## Medium severity -### 12. `getMetricHistory` / `GetMetricHistoryRequest` — request type uses verb-noun, response is paginated metrics — `src/v1/model.ts:314, client.ts:594` -- **Why weird:** Type name `GetMetricHistoryRequest` reads as a verb phrase, not a noun. All other request types use verb-phrase names (`GetRunRequest`, `DeleteExperimentRequest`) so this is internally consistent, but it does conflict with the convention `Verb + EntityName` (because "history" is not the entity — `Metric` is). The response field is `metrics: Metric[]` — so "metric history" really means "page of historical metric values for a single metric_key". -- **Category:** 1 (vague: "history" is non-specific), 6 (misleading: "metric history" sounds like an aggregate, returns a page of `Metric` rows). -- **Suggested name:** `GetMetricValuesRequest` / `getMetricValues`, or `ListMetricHistoryRequest` / `listMetricHistory` (since it paginates). -- **Rationale:** The verb `get` paired with a paginated response is misleading — all other paginated endpoints use `list` or `search` (e.g. `listExperiments`, `searchRuns`). This one is the odd one out. - -### 13. `runUuid` deprecated field appears on many types — `src/v1/model.ts:321, 354, 378, 481, 535, 728, 938, 965` -- **Why weird:** Multiple types/methods carry a `runUuid?: string` field with the comment `[Deprecated, use 'run_id' instead] ID of the run ...`. There is no `@deprecated` JSDoc tag — the deprecation is buried in prose. The TS port translated `run_uuid` (snake_case wire) into `runUuid` (camelCase) so the deprecation comment's `run_id` reference does not match the TS field name (`runId`) the user would actually use. -- **Category:** 6 (misleading prose), 19 (underspecified ID: `runUuid` vs `runId` for the same thing), 17 (inconsistent ID style). -- **Suggested name:** Either remove the deprecated field from the TS surface (since the Go SDK keeps it for wire-compat, TS could omit) or add `@deprecated` JSDoc. -- **Rationale:** If a user passes both `runId` and `runUuid` the API picks `runId`; the TS surface should make `runUuid` impossible to autocomplete. - -### 14. `creatorId: number` (not string) — `src/v1/model.ts:584` -- **Why weird:** `LoggedModelInfo.creatorId` is typed as `number | undefined` — every other ID in the package is `string` (`experimentId`, `runId`, `modelId`, `sourceRunId`). The JSDoc says "The ID of the user or principal that created the model." -- **Category:** 16 (field contradicting type domain), 17 (inconsistent ID type), 19 (underspecified ID). -- **Suggested name:** Either align as `string` (most likely the wire really is a numeric user-id but TS-side string is safer for large ints) or rename to `creatorIdNumeric` to flag the divergence. -- **Rationale:** If the user-id ever exceeds `Number.MAX_SAFE_INTEGER`, this field silently corrupts. All other Databricks SDK packages use `string` for IDs (e.g. `databricks/sdk-iam` uses `id: string`). - -### 15. `modelId` ambiguity in `Metric` — `src/v1/model.ts:632-636` -- **Why weird:** `Metric.modelId` doc: "The ID of the **logged model or registered model version** associated with the metric, if applicable." So one field carries IDs from two different domains (LoggedModel from this package + RegisteredModelVersion from `mlmodels`/`modelregistry` package). The type cannot tell them apart. -- **Category:** 6 (misleading — same string field holds two ID kinds), 19 (underspecified ID). -- **Suggested name:** Split into `loggedModelId?: string` and `registeredModelVersionId?: string`, or carry a discriminator (`{kind: 'logged' | 'registered', id: string}`). -- **Rationale:** Heterogeneous string ID fields are debugging traps. - -### 16. `LoggedModelInfo.modelId` doc vs `LoggedModel.info.modelId` access pattern — `src/v1/model.ts:549-554, 568-573` -- **Why weird:** To get a model's own ID, you have to write `loggedModel.info?.modelId`. The natural place would be `loggedModel.id` or `loggedModel.modelId`. The split between `info` and `data` (#9) buries the ID one level deep. -- **Category:** 15 (generic field name losing meaning), 7 (verbose access). -- **Suggested name:** Hoist `modelId` to `LoggedModel.id` (typescript can keep `info` for the rest). -- **Rationale:** Awkward access pattern. - -### 17. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:464` -- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:916`). +### 6. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:452` +- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:948`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). -- **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #5 is applied: `LogMlflowModelParamsRequest`. +- **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #2 is applied: `LogMlflowModelParamsRequest`. - **Rationale:** The double-Log is jarring on read. -### 18. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1280, 1309` +### 7. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1362, 1333` - **Why weird:** `setExperimentTag(req: SetExperimentTagRequest)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTagsRequest)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 19. `logBatch` does not say "log run batch" — `src/v1/client.ts:860` +### 8. `logBatch` does not say "log run batch" — `src/v1/client.ts:886` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. -### 20. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` +### 9. `logInputs` vs `logOutputs` vs `logParam` vs `logMetric` vs `logBatch` vs `logModel` vs `logLoggedModelParams` — 7 different `log*` verbs — `src/v1/client.ts` - **Why weird:** Seven log* methods with no consistent grammar: - `logBatch` (multiple of {metric, param, tag} on a run) - `logInputs` (datasets + models for a run) @@ -144,27 +76,18 @@ - **Suggested name:** Adopt a `log[ToRun|ToModel]` pattern uniformly. e.g. `logMetricToRun`, `logParamToRun`, `logBatchToRun`, `logInputsToRun`, `logOutputsFromRun`, `logParamsToModel`. Verbose, but unambiguous. - **Rationale:** The current set is internally inconsistent. The Go SDK has the same problem; TS can normalize. -### 21. `LogInputsRequest.datasets` vs `LogInputsRequest.models` field names — `src/v1/model.ts:452-459` -- **Why weird:** Two parallel fields with different abstraction levels: `datasets` is `DatasetInput[]` (carries tags + dataset), `models` is `ModelInput[]` (only model id). The names don't hint at this asymmetry. -- **Category:** 15 (generic field name losing structure). - ## Low severity -### 22. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:236, 592, 717` -- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`) — see #7. The field is consistently `tags`, but the element type is not unifiable in TS without changes. +### 10. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:232, 580, 704` +- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`). The field is consistently `tags`, but the element type is not unifiable in TS without changes. - **Category:** 17 (inconsistency at the element-type level). -### 23. Boolean field `FileInfo.isDir` — `src/v1/model.ts:252` +### 11. Boolean field `FileInfo.isDir` — `src/v1/model.ts:248` - **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). - **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. -### 24. `FileInfo` itself is a generic name — `src/v1/model.ts:248` +### 12. `FileInfo` itself is a generic name — `src/v1/model.ts:244` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. - -## Observations (non-actionable but noted) - -### 25. `Experiment.lifecycleStage` is typed as `string` not `enum` — `src/v1/model.ts:230` -- **Note:** Doc says: `Current life cycle stage of the experiment: "active" or "deleted"`. Wire returns a closed set. TS type is `string | undefined` — no enum. Suggested: `lifecycleStage?: 'active' | 'deleted'` or `LifecycleStage` enum. diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index db01b5e2..8ef4678a 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -1,90 +1,27 @@ # Naming Audit: externallineage -**Path:** `packages/externallineage/src/v1/` +**Path:** `packages/uc/externallineage/src/v1/` **Versions audited:** v1 -**Inferred domain:** External Lineage relationships on Unity Catalog — create / update / delete / list typed relationships between Databricks objects (tables, paths, model versions) and external metadata objects (e.g., Tableau dashboards, Looker views), plus optional per-column relationships. -**Total weird names flagged:** 9 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 1 | -| Low | 3 | -| Observation | 1 | +| High | 1 | +| Low | 1 | ## High severity -### 1. `CreateRequestExternalLineage` / `DeleteRequestExternalLineage` / `UpdateRequestExternalLineage` — `src/v1/model.ts:51, 74, 238` -- **Why weird:** Word-order inversion `Request` + entity instead of entity + `Request`. Every other request type in this package (`CreateExternalLineageRelationshipRequest`, `DeleteExternalLineageRelationshipRequest`) and across the SDK uses entity-then-`Request`. These three types are the nested *payload* shapes for create/delete/update (wrapped inside `*Request` outer types). All three types are structurally identical to each other AND to `ExternalLineageRelationship` (same five fields: `id`, `source`, `target`, `columns`, `properties`). -- **Category:** 12 (duplicate concept — 4 types with the same shape), 17 (verb-position inconsistency with rest of SDK). -- **Suggested name:** Rename to entity-first form: `CreateExternalLineagePayload` / `DeleteExternalLineagePayload` / `UpdateExternalLineagePayload`, or align with the outer `*Request` naming. -- **Rationale:** The inversion serves no purpose except to differentiate them by name from the outer request types. Entity-first matches the rest of the SDK. - -### 2. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` -- **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:563-570` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. +### 1. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` +- **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:566-573` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. - **Category:** 5 (cryptic abbreviation), 10 (reserved-word collision-avoidance). - **Suggested name:** Use a TS discriminated union with `$case` directly (no outer `tpe` field): `ExternalLineageRelationshipObject = {$case: 'table', table: ...} | {$case: 'path', path: ...} | ...`. If the wrapper must stay, name the field `kind` or `objectType`. - **Rationale:** TS allows `type` as a property name, so the cryptic `tpe` solves a problem TS does not have. -### 3. `ExternalLineageInfo` vs. `ExternalLineageRelationship` — `src/v1/model.ts:98, 111` -- **Why weird:** Two top-level types share the prefix `ExternalLineage` but mean different things: `ExternalLineageInfo` is a union-of-info "row" that may describe a table, a file, a model version, or an external metadata object plus the edge metadata; `ExternalLineageRelationship` is the edge itself (id, source, target, columns, properties). The JSDoc on `ExternalLineageInfo` says "Lineage response containing lineage information of a data asset" while one of its fields is `externalLineageInfo?: ExternalLineageRelationship` — i.e., an "info" type that *contains* an "info" field whose type ends in `Relationship`. Five fields ending in `Info` (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`, `externalLineageInfo`) on a type also ending in `Info`. This is the heart of the naming muddle. -- **Category:** 1 (vague `Info` everywhere), 6 (misleading — `externalLineageInfo` is the edge metadata, not "info about external lineage"), 8 (redundant suffix), 12 (duplicate concept — `ExternalLineageInfo.externalLineageInfo` of type `ExternalLineageRelationship`). -- **Suggested name:** `ExternalLineageInfo` → `LineageNode` or `LineageEntry`. `externalLineageInfo` field → `relationship: ExternalLineageRelationship`. The four neighbour fields (`tableInfo`, `fileInfo`, `modelInfo`, `externalMetadataInfo`) become `table`, `file`, `model`, `externalMetadata`. -- **Rationale:** "Info" is the generator's escape hatch for "I don't know what to call this". The current shape forces a reader to deduce that one of the `Info` fields is structurally different from the others (it's the edge, not a node). Concrete names break the muddle. - -### 4. Mixed `Info` / `Relationship` / `Object` suffix vocabulary — across `src/v1/model.ts` -- **Why weird:** The package mixes three competing nouns for related concepts: `*Info` (LineageTableInfo, LineageFileInfo, LineageModelVersionInfo, LineageExternalMetadataInfo, ExternalLineageInfo), `*Relationship` (ColumnRelationship, ExternalLineageRelationship, plus six `ExternalLineageRelationship*` sub-types), and `*Object` (ExternalLineageRelationshipObject). All three trade off in the same conceptual space. A reader cannot predict which suffix a new sibling type will get. -- **Category:** 8 (redundant suffix), 12 (duplicate concept), 17 (inconsistent action-vocabulary). -- **Suggested name:** Pick one: prefer no suffix where the noun is concrete (`Table`, `Path`, `ModelVersion`, `ExternalMetadata`), `Relationship` for edges, and drop `Info`/`Object` entirely. -- **Rationale:** Three suffixes for related types make the vocabulary feel arbitrary. The Google TypeScript style guide encourages "names should reflect what something is, not its scaffolding". - -## Medium severity - -### 5. `Client` class — `src/v1/client.ts:45` -- **Why weird:** Class literally named `Client` at the top level of the package's API surface, re-exported through `index.ts` as just `Client`. Two packages co-existing in user code would clash on import. Same problem as every other audited package. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `ExternalLineageClient` (matches the package name and avoids collisions). -- **Rationale:** A user doing `import {Client} from '@databricks/sdk-externallineage'` and `import {Client} from '@databricks/sdk-externalmetadata'` cannot, and must rename. Sister packages share the problem; treat as generator-wide. - ## Low severity -### 6. `LineageModelVersionInfo.modelName` vs `version` — `src/v1/model.ts:191, 193` -- **Why weird:** Type carries `modelName` (string) and `version` (number). The `version` is described as "Version number of the model" — but the related type `ExternalLineageRelationshipModelVersion` uses `version: string`. Same concept, two types: `number` in the response, `string` on the relationship side. -- **Category:** 16 (field contradicting type domain — `version` is `number` here, `string` elsewhere), 17 (inconsistent type for the same concept). -- **Suggested name:** Pick one type and stick to it. (Likely `string` because UC model versions can be e.g. `"1"`, `"prod"`, `"latest"`.) -- **Rationale:** Type drift on the same field across types implies one of them is wrong on the wire. - -### 7. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` -- **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. The fourth field is `path: string` ("URL of the path"); reread: URL of the path. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. -- **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"), 15 (generic `path` field doing structured work). -- **Suggested name:** `LineageFileSecurableInfo`, or rename the fields to drop `securable` if the file aspect is meant to dominate. Also expand the `path` JSDoc — "URL of the path" is circular. +### 2. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +- **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. +- **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"). +- **Suggested name:** `LineageFileSecurableInfo`, to reflect that the type is mostly about the securable rather than the file. - **Rationale:** Type name should reflect the dominant content; current name is misleading. - -### 8. `eventTime` repeated on four sibling types — `src/v1/model.ts:171, 185, 195, 207` -- **Why weird:** Every `Lineage*Info` type carries `eventTime?: Temporal.Instant` with identical JSDoc "Timestamp of the lineage event." This is fine for parallelism, but the field is *also* not present on `ExternalLineageRelationship` (the actual edge metadata) — only on the node-side `Info` types. A reader expects the edge to carry the event time. -- **Category:** 12 (duplicate concept — four identical fields), 6 (misleading — the edge type *lacks* the event time, an asymmetry the names hide). -- **Suggested name:** Lift `eventTime` into a shared `LineageNode` base interface if duplication bothers; or document why the edge lacks one. -- **Rationale:** Four-fold repetition is a generator artefact. The asymmetry against the edge is the hidden bit. - -## Observations - -### 9. `ListExternalLineageRelationshipsResponse.externalLineageRelationships` field name -The response wraps an array under the field `externalLineageRelationships` (35 characters). The type of that array is `ExternalLineageInfo[]` — *not* `ExternalLineageRelationship[]`. So a field named `externalLineageRelationships` is actually a list of `ExternalLineageInfo`. This is the same Info/Relationship muddle from #3. -- **Category:** 6 (misleading — field name promises one type, returns another), 12 (duplicate concept). - -## Domain glossary -- `External Lineage` — relationships connecting Databricks (UC) data assets to non-Databricks systems (Tableau dashboards, Looker views, Power BI reports, BigQuery tables, etc.). The "edge" is `ExternalLineageRelationship`. -- `UC` / Unity Catalog — the governance layer that owns the source/target objects on the Databricks side (tables, paths, model versions). -- `Securable` — UC concept for any governed object; see `LineageFileInfo.securableType`/`securableName`. Not surfaced as its own type in this package. -- `Model Version` — MLflow registered-model version, identified by `(modelName, version)` pair. Note the type-drift between `number` (in `LineageModelVersionInfo`) and `string` (in `ExternalLineageRelationshipModelVersion`) — see #6. -- `External Metadata` — sister package `externalmetadata`. The edge type here references it by name only (`ExternalLineageRelationshipExternalMetadata.name`). -- `wkt` — Well-Known Types (import `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `wire` — JSON-on-the-wire representation; `marshal`/`unmarshal` schemas translate between TS camelCase and wire snake_case. -- `oneof` / `$case` — protobuf tagged-union encoding, preserved in TS as discriminated unions keyed on `$case`. - -## File coverage -- `src/v1/model.ts` (668 lines): read fully. -- `src/v1/client.ts` (243 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (33 lines): read fully. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index cb50fe1c..32e54c52 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -4,131 +4,22 @@ **Versions audited:** v1 **Package name:** `@databricks/sdk-externallocations` (workspace package; the folder is one word `externallocations`, no hyphen, no underscore). -**Inferred domain:** Unity Catalog External Locations — manages a single -resource type "external location" (a named pointer at cloud-storage URI plus -storage credential) with five operations (create / get / list / list-iter / -update / delete) at `/api/2.1/unity-catalog/external-locations`. The interesting -sub-structure is `FileEventQueue` — an oneof-of-oneofs across three cloud -providers (Azure AQS, AWS SQS, GCP Pub/Sub) with a parallel "provided" vs -"managed" axis (6 cases total). -**Total weird names flagged:** 9 +**Total weird names flagged:** 2 --- ## Summary table -| # | Name | File | Kind | Severity | Category | Issue (one-liner) | -| --- | ----------------------------------------------------------------------------- | ----------------- | ------------------ | -------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `Client` | client.ts:44 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client`. Every package in the SDK exports a class literally named `Client`; importers must alias on collision. `ExternalLocationsClient` would self-identify. | -| 2 | `SseEncryptionAlgorithm.AWS_SSE_S3` / `AWS_SSE_KMS` | model.ts:13-14 | enum values | Medium | 3 Acronym casing | The two non-sentinel members redundantly carry an `AWS_` prefix (the enclosing type name already says SSE which is AWS terminology). The wrapping `Sse*` already implies S3-server-side, so the leading `AWS_` is duplicative. | -| 3 | `AwsSqsQueue` type vs `AzureQueueStorage` type vs `GcpPubsub` type | model.ts:17, 27, 183 | type set | Medium | (none individually, taken as set: inconsistent) | The three queue-config types use three different naming conventions: `AwsSqsQueue` (cloud + service + Queue), `AzureQueueStorage` (cloud + AzureProduct, no Queue suffix), `GcpPubsub` (cloud + product, no Queue suffix). Pick one. E.g., `AwsSqsConfig`/`AzureAqsConfig`/`GcpPubsubConfig`. | -| 4 | `GcpPubsub` (lowercase "ubsub") | model.ts:183 | type | Low | 3 Acronym casing | Pub/Sub is conventionally written with a slash and two capitals. The code uses `Pubsub` (one capital). Sibling discriminators use `providedPubsub`/`managedPubsub`. Consistent internally, but non-canonical. | -| 5 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | -| 6 | `nameArg` field | model.ts:102, 195, 244 | field | High | 5 Cryptic abbreviations, 14 Go/Java-style names | Three request types (`DeleteExternalLocationRequest`, `GetExternalLocationRequest`, `UpdateExternalLocationRequest`) carry a field named `nameArg`. The `Arg` suffix is a generator artifact (it exists because some envelopes also carry a body-level `name`). TS callers reading `req.nameArg = 'my-loc'` get no hint of why it isn't `name`. | -| 7 | `DeleteExternalLocationRequest_Response` | model.ts:108 | type | High | 16 Proto-architectural-leak names | Underscore-delimited proto-nested message name leaked through to the TS public surface. The `_Response` suffix is a Go/Protobuf RPC convention; idiomatic TS would name this `DeleteExternalLocationResponse` (or omit it entirely when the body is empty). | -| 8 | `ListExternalLocationsRequest_Response` | model.ts:221 | type | High | 16 Proto-architectural-leak names | Same proto-nested underscore pattern. Should be `ListExternalLocationsResponse`. The leading `Request_` infix is meaningless to a TS caller — the response is not "the response of a request type", it is the list response. | -| 9 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | - ---- - -## High severity (must fix) - -### H1. `nameArg` is a generator artifact - -Three request types carry a field called `nameArg`: - -- `DeleteExternalLocationRequest.nameArg` (model.ts:102) -- `GetExternalLocationRequest.nameArg` (model.ts:195) -- `UpdateExternalLocationRequest.nameArg` (model.ts:244) - -The `Arg` suffix is meaningless to a TS caller. It exists only because the -generator needs to disambiguate the path-parameter `name` from the body-field -`name` on `UpdateExternalLocationRequest`. Renaming it to `externalLocationName` -or just `name` (and dropping the body-level `name` on Update) would clarify. - -```ts -// Today: -await client.deleteExternalLocation({nameArg: 'my-loc', force: true}); - -// Cleaner: -await client.deleteExternalLocation({name: 'my-loc', force: true}); -``` - -This finding mirrors `credentials.md` H4 and applies generator-wide. - -### H2. `DeleteExternalLocationRequest_Response` — proto-nested underscore in public type - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteExternalLocationRequest_Response {} -``` - -The `Request_Response` underscore identifier is a Protobuf nested-message -convention leaked verbatim into the TS public API. The escape-hatch ESLint -disable comment is itself a tell. Idiomatic TS would either: - -- name the response `DeleteExternalLocationResponse` (drop the `Request_` - infix; the response is a sibling of the request, not nested under it), or -- collapse the empty-body response into `Promise` since the wire - envelope carries no fields. - -The client return type at client.ts:105 inherits the same name and needs -to move together. - -### H3. `ListExternalLocationsRequest_Response` — same proto-nested pattern - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface ListExternalLocationsRequest_Response { - /** An array of external locations. */ - externalLocations?: ExternalLocationInfo[] | undefined; - // ... -} -``` - -Same shape as H2: an underscore-delimited proto-nested identifier in the -public surface. Should be `ListExternalLocationsResponse`. The client return -type at client.ts:182 shares the rename. - -This is the only paginated response shape in the package, so the type is -materially load-bearing — callers iterating manually have to read -`resp.nextPageToken` against this type. +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +| --- | ------------------- | -------------- | ---- | -------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | +| 2 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | --- ## Medium severity (worth pushing back on) -### M1. `SseEncryptionAlgorithm` members carry redundant `AWS_` prefix - -```ts -enum SseEncryptionAlgorithm { - SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED = 'SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED', - AWS_SSE_S3 = 'AWS_SSE_S3', - AWS_SSE_KMS = 'AWS_SSE_KMS', -} -``` - -The two non-sentinel members duplicate the AWS context that is already -implicit in the enclosing `SseEncryptionAlgorithm` type — SSE-S3 and SSE-KMS -are AWS-only concepts. Within the proto-style identifier convention these -could read as plain `SSE_S3` / `SSE_KMS`, or even `S3` / `KMS` since the -wrapping type already says SSE. - -### M2. The three cloud-provider queue types use three different naming conventions - -```ts -interface AwsSqsQueue { ... } // cloud + service + Queue -interface AzureQueueStorage { ... } // cloud + product, no suffix -interface GcpPubsub { ... } // cloud + product, no suffix -``` - -Three naming patterns for three parallel types. Pick one: - -- All with `Queue` suffix: `AwsSqsQueue`, `AzureAqsQueue`, `GcpPubsubQueue`. -- All without: `AwsSqs`, `AzureQueueStorage`, `GcpPubsub`. -- All as `Config`: `AwsSqsConfig`, `AzureAqsConfig`, `GcpPubsubConfig`. - -### M3. `AzureQueueStorage` vs `Aqs` abbreviation +### M1. `AzureQueueStorage` vs `Aqs` abbreviation The interface name is `AzureQueueStorage`, but two of its consumers (the discriminator case keys `providedAqs`/`managedAqs` and the wire-format string @@ -136,13 +27,7 @@ discriminator case keys `providedAqs`/`managedAqs` and the wire-format string not standard Microsoft terminology — Microsoft's docs call this "Azure Queue Storage" or "Azure Storage Queues". `AQS` is Databricks-internal shorthand. -### M4. `Pubsub` casing - -GCP's product is "Pub/Sub" (with slash and two capitals). The TS type is -`GcpPubsub` (one capital). Internally consistent (the discriminator cases -`providedPubsub`/`managedPubsub` match), but not the canonical GCP spelling. - -### M5. `ExternalLocationInfo` — `Info` suffix carries no semantic value +### M2. `ExternalLocationInfo` — `Info` suffix carries no semantic value ```ts export interface ExternalLocationInfo { ... } @@ -157,75 +42,8 @@ idiomatic TS this would just be `ExternalLocation`. The suffix shows up in every signature touching the resource: - `Promise` (4 client method return types). -- `ExternalLocationInfo[]` in `ListExternalLocationsRequest_Response`. +- `ExternalLocationInfo[]` in `ListExternalLocationsResponse`. - `AsyncGenerator` in the iter method. Renaming to `ExternalLocation` removes ~6 occurrences of dead-weight suffix across the public surface. - ---- - -## Low severity (nits) - -_None._ - ---- - -## Cross-cutting observations (not flags) - -### Generator marker - -Every file is prefixed with `// Code generated from API definition by -Databricks SDK Generator. DO NOT EDIT.` All naming issues here must be fixed -upstream in the generator/spec. - -### Optionality model - -Every field is `T | undefined`. Matches the repo's `exactOptionalPropertyTypes` -setting. Consistent across the SDK. - -### Acronym inventory - -The following acronyms appear: - -| Acronym | Casing in code | Notes | -| -------- | ---------------- | ----------------------------------------------------------- | -| AWS | `Aws` | Initialism-as-word per Google TS Style Guide. | -| S3 | `S3` (in `AWS_SSE_S3`); `s3` (JSDoc on line 230) | Mixed. | -| SQS | `Sqs` | Initialism-as-word. | -| SSE | `Sse` | Initialism-as-word. | -| KMS | `Kms` | Initialism-as-word. | -| ARN | `Arn` | Initialism-as-word. | -| IAM | not in this pkg | Used in sibling packages with `Iam` initialism-as-word. | -| Azure | `Azure` | Not an acronym. | -| AQS | `Aqs` | Databricks-internal abbreviation, not Microsoft canonical. | -| GCP | `Gcp` | Initialism-as-word. | -| Pub/Sub | `Pubsub` | Non-canonical (Google spells `Pub/Sub`). | -| URL | `url` (lower; field name); `Url` (in `queueUrl`) | Standard. | -| ID | `Id` (in `metastoreId`, `credentialId`, `managedResourceId`, `subscriptionId`) | Initialism-as-word. | - ---- - -## Summary - -9 findings: - -- **3 High severity** — `nameArg` artifact, two `Request_Response` - proto-nested type names. -- **6 Medium severity** — `Client` collision, redundant `AWS_` prefix on - `SseEncryptionAlgorithm` members, queue-type naming-pattern inconsistency, - `AzureQueueStorage`/`Aqs` long-vs-short inconsistency, `Pubsub` casing, - `ExternalLocationInfo` redundant `Info` suffix. - -Primary themes: - -1. **Proto-architectural-leak names**: the `Request_Response` underscore - identifiers, the `Info` suffix on the resource type, and the `nameArg` - path-vs-body disambiguation are all Go-/Protobuf-shaped idioms that - idiomatic TS would express differently. The ESLint disable comments on - model.ts:107 / 220 are themselves the giveaway. -2. **Cloud-provider naming is internally inconsistent**: three queue-config - types with three different naming conventions, AQS abbreviation that isn't - Microsoft canonical. - ---- diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index a88c7532..15e26f42 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -2,113 +2,35 @@ **Path:** `packages/externalmetadata/src/v1/` **Versions audited:** v1 -**Inferred domain:** Unity Catalog External Metadata — register, list, update, and delete metadata objects that describe data assets living outside Databricks (Tableau dashboards, Power BI reports, Kafka topics, ServiceNow tables, Snowflake tables, etc.), enabling cross-system lineage in the Databricks lineage-tracking subsystem. -**Total weird names flagged:** 13 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 3 | -| Low | 0 | -| Observation | 2 | +| High | 3 | +| Observation | 1 | ## High severity -### 1. `SystemType.OTHER` — `src/v1/model.ts:10` -- **Why weird:** Generic catch-all value with no semantic indicator that it is a fallback. A user encountering `SystemType.OTHER` cannot tell if it means "data not yet classified", "vendor we don't support", or "user-provided custom system". Compare to `SystemType.SYSTEM_TYPE_UNSPECIFIED` which at least signals it is a sentinel. -- **Category:** 1 (vague — `OTHER` is the most generic possible name), 15 (generic field/value name losing meaning). -- **Suggested name:** `SystemType.Custom` or `SystemType.UserDefined` (whichever matches the API semantics). -- **Rationale:** `OTHER` as an enum value is the value-side equivalent of naming a field `data`. JSDoc on the enum, or a more specific value name, would tell readers when to reach for it. - -### 2. `SystemType` value casing — `POWER_BI`, `MICROSOFT_SQL_SERVER`, `AMAZON_REDSHIFT`, `AZURE_SYNAPSE`, `GOOGLE_BIGQUERY`, `MICROSOFT_FABRIC`, `STREAM_NATIVE`, `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE`, `WORKDAY`, `TABLEAU`, `LOOKER`, `KAFKA`, `MYSQL`, `ORACLE`, `SAP`, `SNOWFLAKE`, `TERADATA`, `CONFLUENT`, `DATABRICKS` — `src/v1/model.ts:10-32` -- **Why weird:** Vendor names are proper nouns with canonical brand casing (Power BI, Microsoft SQL Server, Amazon Redshift, BigQuery, PostgreSQL, MongoDB, ServiceNow, Tableau). Wire SCREAMING_SNAKE collapses every brand to a flat shout. Also: split rules are inconsistent — `POWER_BI` and `MICROSOFT_SQL_SERVER` split on word boundary, but `POSTGRESQL`, `MONGODB`, `SERVICENOW`, `SALESFORCE` join compounds without underscore. -- **Category:** 3 (acronym casing inconsistency across vendor names). -- **Suggested name:** Pick one split convention: word-bound (`POSTGRE_SQL`, `MONGO_DB`, `SERVICE_NOW`, `SALES_FORCE`) or joined (`POWERBI`, `MICROSOFTSQLSERVER`). Alternatively move TS-side to PascalCase brand casing (`SystemType.PowerBI`, `SystemType.MicrosoftSqlServer`, `SystemType.Postgres`, `SystemType.MongoDb`). -- **Rationale:** Vendor names are proper nouns. Within the set there is no reproducible rule (compare `POWER_BI` split vs `POSTGRESQL` joined). A user typing `SystemType.MongoDB` won't autocomplete to `MONGODB`. Probably wire-locked, but worth flagging upstream. - -### 3. `SystemType.STREAM_NATIVE` — `src/v1/model.ts:32` -- **Why weird:** The vendor is "StreamNative" (one camelCased brand name), but the wire splits it as `STREAM_NATIVE`. Compare: `SERVICENOW` (joined, brand is "ServiceNow") vs `STREAM_NATIVE` (split, brand is "StreamNative"). The split rule is unprincipled. -- **Category:** 3 (acronym/brand casing inconsistency). -- **Suggested name:** `STREAMNATIVE` (matches `SERVICENOW`) or fix `SERVICENOW` -> `SERVICE_NOW`. Pick one. -- **Rationale:** Sibling brand names with the same shape (one-word camelCased) should encode identically. The current internal inconsistency makes the type non-discoverable. - -### 4. `ExternalMetadata` — `src/v1/model.ts:43` +### 1. `ExternalMetadata` — `src/v1/model.ts:43` - **Why weird:** The central domain entity is named after the package, which is a noun phrase but not a noun ("External Metadata" is more an adjective+noun phrase than a thing). Compare: `Catalog`, `Connection`, `Schema` are crisp nouns; `ExternalMetadata` reads like a category, not an instance. Also: every field has the doc-string suffix "external metadata object" — the type is essentially `XxxObject` without the suffix, but the docs need it because the bare type name lacks objecthood. - **Category:** 1 (vague — what is "an External Metadata"?), 6 (misleading: name reads as a kind, not an instance). - **Suggested name:** `ExternalAsset` or `ExternalEntity` (the type already has a `entityType` field describing what shape of external thing it is). Alternatively, embrace the proto-canonical name with `ExternalMetadataObject`. - **Rationale:** Reading `const x: ExternalMetadata = ...` does not communicate that `x` is a single named external asset. The JSDoc fix ("external metadata object") betrays that the type name needs help to read as a noun. Worth raising upstream. -### 5. `ExternalMetadata.name` vs. `ExternalMetadata.id` — `src/v1/model.ts:45,71` -- **Why weird:** The entity has both `name` AND `id` — two different identifier-shaped fields with no doc differentiation beyond "Unique identifier of the external metadata object" on `id` and "Name of the external metadata object" on `name`. The URL routing uses `name` as the path segment (`/api/2.0/lineage-tracking/external-metadata/${req.name}`), suggesting `name` is the canonical key; `id` is the implementation-detail UUID. -- **Category:** 12 (duplicate concept — `name` and `id` both feel identity-shaped), 19 (underspecified ID). -- **Suggested name:** Drop `id` if `name` is the canonical key, or document in JSDoc when callers use `name` vs `id`. -- **Rationale:** Co-existence of `name?: string` and `id?: string` with no semantic separation in docs is a recipe for caller confusion. The type does not communicate which is canonical. - -### 6. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` +### 2. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` - **Why weird:** Type name carries the API version suffix `V2`, but the enclosing file is already `v1/model.ts` and the package is mounted at `./v1`. Version is encoded twice — once in the directory, once in the type. If the user later imports a hypothetical `v2/`, they would get `V3`? Versioning the entity name within the version namespace creates an off-by-one collision risk. - **Category:** 8 (redundant suffix — version is in the path), 20 (type-suffix tautology between version-in-path and version-in-name), 14 (Go/proto-style — Go SDK carries the `V2` per RPC name; TS doesn't need it). - **Suggested name:** `ListExternalMetadataResponse` (drop `V2`). - **Rationale:** The directory is the namespace. Embedding the wire RPC version into the TS type name leaks an internal detail of the generator. If the package later gets a `v2/` directory, every type there ends up `V3` (one ahead of the dir), which is worse than the original problem. -### 7. `Client.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:75,110,135,168,207,229` -- **Why weird:** Every public method on `Client` ends with `V2`, but the directory is `v1/`. The version suffix is wire-RPC-name leakage (the upstream API is `ExternalMetadataServiceV2.Create`, hence `createExternalMetadataV2`). User code reads `client.createExternalMetadataV2(...)` for a method on a `v1/` import — confusing on first read. +### 3. `ExternalMetadataClient.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:72,107,132,165,204,226` +- **Why weird:** Every public method on `ExternalMetadataClient` ends with `V2`, but the directory is `v1/`. The version suffix is wire-RPC-name leakage (the upstream API is `ExternalMetadataServiceV2.Create`, hence `createExternalMetadataV2`). User code reads `client.createExternalMetadataV2(...)` for a method on a `v1/` import — confusing on first read. - **Category:** 8 (redundant suffix), 14 (Go/proto-style name leak), 20 (type/version suffix tautology). - **Suggested name:** `createExternalMetadata`, `deleteExternalMetadata`, etc. (drop `V2`). -- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #6; generator-wide concern. - -### 8. `Client` — `src/v1/client.ts:41` -- **Why weird:** Class literally named `Client` at the top level of the package's surface. Re-exported through `index.ts` as just `Client`. Two packages co-existing in user code collide on import: `import {Client} from '@databricks/sdk-externalmetadata'` and `import {Client} from '@databricks/sdk-catalogs'` both fight for the same identifier. -- **Category:** 1 (vague — `Client` is the most generic name), 15 (generic name). -- **Suggested name:** `ExternalMetadataClient` (matches the package name and avoids collisions on combined imports). -- **Rationale:** A user combining packages must alias on every import (`import {Client as ExternalMetadataClient}`). Sister packages all share this problem — generator-wide rename worth raising upstream. - -## Medium severity - -### 9. `ExternalMetadata.url` — `src/v1/model.ts:51` -- **Why weird:** Casing of acronym. The codebase uses `url` (lowercase) consistently for the property, but the Web platform/standards canonical is `URL` (uppercase). Compare to `userAgent` (camelCase) and `URLSearchParams` (Web standard SCREAMING). Internal inconsistency between `url` (field) and `URLSearchParams` (function/class). -- **Category:** 3 (acronym casing). -- **Suggested name:** Keep `url` (TS convention), but acknowledge the JS-ecosystem split. -- **Rationale:** The JS world is split here — Node, browsers, and the URL spec all use `URL` for the class and `url` for member fields. Internal consistency within this file is preserved (`url` everywhere); the rule is conventional, not broken. - -### 10. `ExternalMetadata.metastoreId` — `src/v1/model.ts:61` -- **Why weird:** Bare `metastoreId: string | undefined` — a UUID identifier on a UC metastore, but the type does not hint at the format. Idiomatic across the SDK; here mentioned only for rule-19 completeness. Also note: this field is "Unique identifier of parent metastore" but `parent` is not named — the metastore relationship is communicated via the `metastoreId` field alone, not a `parent` field per AIP-160. -- **Category:** 19 (underspecified ID — `string` doesn't tell you it's a UUID). -- **Suggested name:** Keep `metastoreId` (canonical across SDK). -- **Rationale:** SDK-wide pattern; field name is fine. Listed for completeness. - -### 11. `UpdateExternalMetadataRequest.updateMask: FieldMask` — `src/v1/model.ts:101` -- **Why weird:** Field name `updateMask` doesn't say what kind of mask. In context the mask describes "which fields to patch". The Google AIP-134 convention names this `updateMask`; the TS-idiomatic name would describe contents (`fieldsToUpdate`, `patchedFields`, `paths`). -- **Category:** 1 (vague), 14 (Google-AIP-style name). -- **Suggested name:** Keep `updateMask` (AIP-134 canon) or rename to `fieldsToUpdate`. -- **Rationale:** Sticking to AIP-134 is fine; SDK-wide pattern. Listed for awareness. - -## Low severity - -_None._ +- **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #2; generator-wide concern. ## Observations -### 12. Identifier doubling for path + UUID -The `ExternalMetadata` type has both `name` (the URL-path key) and `id` (the system UUID). Sister packages handle this differently — some collapse to `name` only, some collapse to `id` only, some keep both with explicit `nameOrId` semantics in JSDoc. The lack of a single SDK-wide convention is the underlying problem; per-package, this manifests as #5. - -### 13. Action-verb conventions in `Client` +### 4. Action-verb conventions in `Client` The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. - -## Domain glossary -- `uc` / Unity Catalog — implicit across all types (the registered entities live in a UC metastore). -- `metastore` / `metastoreId` — UC metastore (the top-level UC namespace); the `metastoreId` is a UUID. -- `external-metadata` — the wire name for the resource registered in the lineage-tracking subsystem; refers to metadata about an entity living *outside* Databricks (a Tableau dashboard, a Kafka topic, etc.). -- `lineage-tracking` — the URL path prefix `/api/2.0/lineage-tracking/...`; the broader subsystem this package belongs to. -- `system` / `SystemType` — the external vendor system (Tableau, Snowflake, Kafka, ...). Closed enum. -- `entity` / `entityType` — the kind of object *within* the external system (a Tableau workbook vs. a dashboard; a Kafka topic vs. a partition). Open string, not enumerated. -- `BROWSE`, `MANAGE`, `MODIFY`, `CREATE_EXTERNAL_METADATA` — UC privileges referenced in method JSDoc but not modeled as types. -- `wkt` — Well-Known Types (import path `@databricks/sdk-core/wkt`, used for `FieldMask`). -- `properties` — user-defined `Record`. -- `oss`, `m2m`/`u2m`/`pat`, `iam`, `abac` — not encountered in this package. - -## File coverage -- `src/v1/model.ts` (221 lines): read fully. -- `src/v1/client.ts` (271 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index 194ddb2a..53e005cb 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -2,20 +2,8 @@ **Path:** `packages/features/src/v1/` **Versions audited:** v1 -**Package name:** `@databricks/sdk-features` — collides semantically with two -sibling packages (`@databricks/sdk-featurestore` and -`@databricks/sdk-materializedfeatures`), all three of which are part of the -Feature Engineering surface. The bare word "feature" is also overloaded with -the unrelated common-English sense ("product feature" / "preview feature") -that appears throughout the SDK in flags, settings, and previews. -**Inferred domain:** Databricks Feature Engineering — defines **Feature** -(the abstract definition: source + transformation + aggregation), Kafka -streaming config, and **MaterializedFeature** (a concrete pipeline that -computes a feature on a schedule and writes results to an offline or online -store). Feature transformations are a discriminated union over 13 aggregation -functions and 3 data sources (Delta, Kafka, request-time), composed under -three flavors of time window (continuous, tumbling, sliding). -**Total weird names flagged:** 36 (0 fixed, 36 still present after rescan on 2026-05-26 post regen #156) +**Package name:** `@databricks/sdk-features` +**Total weird names flagged:** 24 (rescan on 2026-06-02) --- @@ -23,81 +11,36 @@ three flavors of time window (continuous, tumbling, sliding). | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| -| 1 | package `features` / module `@databricks/sdk-features` | (package) | package | High | 1 Vague/generic, 12 Duplicate concepts | The bare term "features" is ambiguous: (a) ML features (this package), (b) Databricks product features / feature flags (settings/previews), (c) "features" of a billing plan (billing). A reader cannot disambiguate from the import path. Rename to `@databricks/sdk-feature-engineering`, `@databricks/sdk-ml-features`, or `@databricks/sdk-feature-definitions`. | -| 2 | three sibling packages: `features` / `featurestore` / `materializedfeatures` | (across packages) | package set | High | 12 Duplicate concepts | The Feature Engineering surface is split across three top-level packages whose names overlap at the prefix. Boundaries: `features` defines feature *definitions* (this package); `materializedfeatures` is **misnamed** — it actually owns feature **lineage and tags** (`FeatureLineage`, `FeatureTag`), not materialized features (which live here); `featurestore` owns **online stores**. The names do not align with their contents. Either rename `materializedfeatures` to `featuremetadata` / `featurelineage`, or move `MaterializedFeature` and its client methods out of this package into the (misnamed) `materializedfeatures` package. | -| 3 | `Feature` interface | model.ts:280 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | -| 4 | `Client` | client.ts:65 | class | Medium | 1 Vague/generic, 12 Duplicate concepts | Unqualified `Client` — once imported it shadows every other package's `Client`. `FeaturesClient` or `FeatureEngineeringClient` would self-identify and disambiguate from `featurestore.Client` and `materializedfeatures.Client`. | -| 5 | `Client.*Feature*` plus `Client.*KafkaConfig*` plus `Client.*MaterializedFeature*` (3 resource families on one client) | client.ts:91-635 | method set | Medium | 12 Duplicate concepts | One `Client` class owns three distinct resource families: `Feature`, `KafkaConfig`, and `MaterializedFeature`. The class is 636 lines and reads as three sub-clients merged. A `FeaturesClient` (feature defs only) + `KafkaConfigsClient` + `MaterializedFeaturesClient` split would let each Client be ≤ 250 lines and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../kafka-configs`, `/.../materialized-features`). | -| 6 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:117, 179, 758, 572, 566, 344, 467, 84, 92, 716, 727, 819, 825 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that already encode "this is the average operation" — `avg` (not `avgFunction`). The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | -| 7 | `TimeWindow.windowType` field | model.ts:769 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | -| 8 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:288, 317, 319 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | -| 9 | `DeltaTableSource.entityColumns` (deprecated `string[]`) vs `Feature.entities` (`EntityColumn[]`) | model.ts:246, 317 | field pair | Medium | 12 Duplicate concepts | Same data ("which columns are entities for this feature") expressed two ways: a `string[]` on the source (deprecated) and an `EntityColumn[]` on the parent. Pick one. The deprecation note ("Use Feature.entity instead") refers to a non-existent field name (`entity` singular vs `entities` plural — typo in the spec). | -| 10 | `DeltaTableSource.timeseriesColumn` (deprecated `string`) vs `Feature.timeseriesColumn` (canonical `TimeseriesColumn`) | model.ts:251, 319 | field pair | Medium | 12 Duplicate concepts | Same pattern as #9. Two `timeseriesColumn` fields, one deprecated string, one canonical object. | -| 11 | `KafkaSource.entityColumnIdentifiers` vs `Feature.entities` vs `DeltaTableSource.entityColumns` (three names for one concept) | model.ts:456, 317, 246 | field set | High | 12 Duplicate concepts, 17 Inconsistent action verbs | Three names for the same domain notion ("entity columns of a source"): `entityColumnIdentifiers` (Kafka source, `ColumnIdentifier[]`), `entityColumns` (Delta source, `string[]`), `entities` (Feature top-level, `EntityColumn[]`). The element types are even three different shapes. | -| 12 | `KafkaSource.timeseriesColumnIdentifier` vs `Feature.timeseriesColumn` vs `DeltaTableSource.timeseriesColumn` | model.ts:461, 319, 251 | field set | High | 12 Duplicate concepts | Same as #11 but for the timeseries column. Three names, three types (`ColumnIdentifier`, `TimeseriesColumn`, `string`) for one concept. | -| 13 | `ColumnIdentifier` vs `EntityColumn` vs `TimeseriesColumn` (three "column reference" types) | model.ts:156, 268, 777 | interface set | High | 12 Duplicate concepts, 1 Vague/generic | Three interfaces that all describe "a reference to a column" (each carries a string name field). `ColumnIdentifier.variantExprPath`, `EntityColumn.name`, `TimeseriesColumn.name`. The field names also differ (`variantExprPath` vs `name`). One `ColumnRef` type with a `path` field would consolidate. | -| 14 | `ColumnSelection` interface | model.ts:165 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | -| 15 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:376 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | -| 16 | `MaterializedFeature.materializedFeatureId` field (stutter) | model.ts:535 | field | High | 12 Duplicate concepts, 15 Generic field names, 19 Underspecified IDs | Reads `mf.materializedFeatureId` — the type prefix duplicates. TS idiom: just `id`. Path interpolations elsewhere look like `${req.materializedFeatureId ?? ''}` (client.ts) — verbose. | -| 17 | `DeleteFeatureRequest.fullName` vs `DeleteMaterializedFeatureRequest.materializedFeatureId` vs `DeleteKafkaConfigRequest.name` | model.ts:226, 236, 231 | field set | Medium | 17 Inconsistent action verbs, 19 Underspecified IDs | Three sibling delete requests use three different name conventions for "which thing to delete": `fullName`, `materializedFeatureId`, `name`. Three patterns in one file. Caller has to remember which name field each resource uses. | -| 18 | `KafkaConfig.bootstrapServers` | model.ts:424 | field | Low | (none) | Standard Kafka term. Fine. | -| 19 | `SubscriptionMode.$case === 'assign'` | model.ts:737 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | -| 20 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:750 | field | Low | (none) | Fine, matches Kafka SDK. | -| 21 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:623 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | -| 22 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:598, 604, 612 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | -| 23 | `MaterializedFeature.isOnline` vs `MaterializedFeature.destination` (redundant) | model.ts:562, 538 | field pair | High | 12 Duplicate concepts | `isOnline = true` ⟺ `destination.$case === 'onlineStoreConfig'`. Two ways to ask the same question. The JSDoc on `isOnline` confirms: "True if this is an online materialized feature. False if it is an offline materialized feature." But `destination` already discriminates the two. Drop `isOnline` or make it a server-side derived flag with an `@readonly` note. | -| 24 | `Feature.lineageContext` field (per JSDoc "internal use") | model.ts:315 | field | High | 6 Misleading names | The field is documented as "primarily intended for internal use by systems and is automatically populated... Users should not manually set this field as incorrect values may lead to inaccurate lineage tracking or unexpected behavior." Yet it is `lineageContext?: LineageContext \| undefined` on a public type with no `@internal` JSDoc tag. A consumer can construct it and shoot themselves in the foot. Mark `@internal` or remove from the public type. | -| 25 | `LineageContext.notebookId` (number) vs `JobContext.jobId` (number) — both "id"s typed as `number` | model.ts:475, 412 | field pair | Medium | 19 Underspecified IDs, 16 Field contradicting type domain | Databricks resource IDs are 64-bit integers that exceed JS `Number.MAX_SAFE_INTEGER` (~2^53). Typing them as `number` is unsafe; the rest of the SDK uses `bigint` or `string` for IDs. Compare to e.g. `MaterializedFeature.materializedFeatureId: string`. | -| 26 | `LineageContext` interface name | model.ts:473 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | -| 27 | `JobContext.jobRunId` | model.ts:414 | field | Low | (none) | Fine. | -| 28 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:2432, 2482, 2525 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources. Listing for completeness. | -| 29 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:171, 708, 789 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | -| 30 | `Function` interface shadows JS built-in `Function` | model.ts:358 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | -| 31 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | -| 32 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #31. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | -| 33 | `Function_ExtraParameter` interface | model.ts:388 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | -| 34 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:444 | interface | High | Proto architectural leak | Synthetic proto map-entry type. `protoc` auto-generates `Entry` messages for `map` fields and the TS generator copies the name verbatim. The corresponding TS field is already `extraOptions: Record` (model.ts:434), so this auxiliary interface has no consumer in idiomatic TS code yet leaks into the public surface via `index.ts:44`. Drop it. | -| 35 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1163, 1935 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #33. | -| 36 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 38, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#31-35) clears this automatically. | +| 1 | package `features` / module `@databricks/sdk-features` | (package) | package | High | 1 Vague/generic | The bare term "features" is ambiguous: (a) ML features (this package), (b) Databricks product features / feature flags (settings/previews), (c) "features" of a billing plan (billing). A reader cannot disambiguate from the import path. Rename to `@databricks/sdk-feature-engineering`, `@databricks/sdk-ml-features`, or `@databricks/sdk-feature-definitions`. | +| 2 | `Feature` interface | model.ts:343 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | +| 3 | `FeaturesClient.*Feature*` plus `*KafkaConfig*` plus `*MaterializedFeature*` plus `*Stream*` (4 resource families on one client) | client.ts:102-872 | method set | Medium | 12 Duplicate concepts | One `FeaturesClient` class owns four distinct resource families: `Feature`, `KafkaConfig`, `MaterializedFeature`, and `Stream`. The class is 873 lines and reads as four sub-clients merged. A split into per-resource clients would let each be a focused surface and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../features/kafka-configs`, `/.../materialized-features`, `/.../streams`). | +| 4 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:134, 196, 1043, 769, 763, 407, 624, 101, 109, 913, 924, 1116, 1122 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that mostly already encode "this is the average operation" — `avg` (not `avgFunction`); only `countFunction` keeps the suffix. The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | +| 5 | `TimeWindow.windowType` field | model.ts:1058 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding`/`rolling` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | +| 6 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:351, 380, 382 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | +| 7 | `ColumnSelection` interface | model.ts:182 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 8 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:439 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | +| 9 | `KafkaConfig.bootstrapServers` | model.ts:538 | field | Low | (none) | Standard Kafka term. Fine. | +| 10 | `SubscriptionMode.$case === 'assign'` | model.ts:1022 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | +| 11 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:1035 | field | Low | (none) | Fine, matches Kafka SDK. | +| 12 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:820 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | +| 13 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:795, 801, 809 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | +| 14 | `LineageContext` interface name | model.ts:630 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | +| 15 | `JobContext.jobRunId` | model.ts:528 | field | Low | (none) | Fine. | +| 16 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:3221, 3290, 3359 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources (a fourth, `streamFieldMask`, follows the same shape). Listing for completeness. | +| 17 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:188, 905, 1078 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | +| 18 | `Function` interface shadows JS built-in `Function` | model.ts:421 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 19 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | +| 20 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #19. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | +| 21 | `Function_ExtraParameter` interface | model.ts:451 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | +| 22 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:558 | interface | High | Proto architectural leak | Proto-architectural-leak naming. The generator emits a synthetic `{key?, value?}` map-entry interface for the `extraOptions` field of `KafkaConfig`, copying the proto `Entry` message name verbatim. The wire shape is already covered by `Record` (model.ts:548), so this entry type adds noise and is not used by the surface. Remove the `*Entry` interface from the public API. | +| 23 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1491, 2504 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #21. | +| 24 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 44, 53 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#19-23) clears this automatically. | --- ## High severity (must fix) -### H1. Three sibling packages, blurry boundaries - -The Feature Engineering surface is split across three top-level packages: - -- `features` (this package) — owns `Feature`, `KafkaConfig`, - `MaterializedFeature`, and 21 client methods spanning all three. -- `materializedfeatures` — **does not** own `MaterializedFeature`. It owns - `FeatureLineage` and `FeatureTag` (see - `packages/materializedfeatures/src/v1/index.ts`). -- `featurestore` — owns `OnlineStore` and `PublishTable` (see - `packages/featurestore/src/v1/index.ts`). - -The boundaries do not match the package names. A new reader walking the -package list will assume `MaterializedFeature` lives in `materializedfeatures` -— it doesn't. They will assume `KafkaConfig` lives in `featurestore` (the -"store" for features) — it doesn't. - -Recommendations (pick one): - -- **Rename to match contents:** - - this package → `feature-definitions` or `feature-engineering` (it owns - definitions + materialization + Kafka). - - `materializedfeatures` → `feature-lineage` or `feature-metadata`. - - `featurestore` → `feature-online-stores`. -- **Move types to match names:** - - Move `MaterializedFeature` + `materializedFeatures*` client methods out of - `features` and into `materializedfeatures`. - - Move `KafkaConfig` + `kafkaConfigs*` client methods out of `features` into - a new `feature-streaming-sources` package or keep in `features` if it - becomes "feature definitions only". - -Either way, the current state misleads consumers. - -### H2. Package name `features` is vague +### H1. Package name `features` is vague Bare "features" overlaps with at least three unrelated Databricks concepts: @@ -110,10 +53,10 @@ has no signal that this is the ML kind. Recommend `@databricks/sdk-feature-engineering` to match the URL path (`/api/2.0/feature-engineering/...`). -### H3. The `Feature` type name is overloaded +### H2. The `Feature` type name is overloaded The unqualified noun `Feature` is the central type of this package -(model.ts:280) and is re-exported from `index.ts`. Once it lands in a +(model.ts:343) and is re-exported from `index.ts`. Once it lands in a consumer's namespace it shadows the common-English sense of the word. ```ts @@ -125,67 +68,9 @@ Rename `MLFeature`, `FeatureDefinition`, or `FeatureEngineeringFeature` (the latter is verbose but unambiguous and matches the URL). -### H4. `MaterializedFeature` is misplaced - -The package `materializedfeatures/` exists at `packages/materializedfeatures/` -but does not contain `MaterializedFeature` (it contains `FeatureLineage` / -`FeatureTag` instead). `MaterializedFeature` lives in this package. The -package naming and module organization are out of sync. - -This is the most surprising thing in this audit. A reader who searches the -codebase for `MaterializedFeature` will find it in `features/`, not -`materializedfeatures/`. Moving it (or renaming the empty-shelled package) -should be a P1 fix. - -### H5. Three names for "column reference of a source" - -- `ColumnIdentifier { variantExprPath?: string }` — used by `KafkaSource`. -- `EntityColumn { name?: string }` — used by `Feature`. -- `TimeseriesColumn { name?: string }` — used by `Feature`. -- `string` — used by deprecated `DeltaTableSource.entityColumns`, - `DeltaTableSource.timeseriesColumn`. - -Four representations for the same domain notion. Three of them carry a single -field, two with different field names (`variantExprPath` vs `name`). The -simplest fix is one shared `ColumnRef { path: string }` plus a tag on the -parent context (e.g., `entities: ColumnRef[]`, `timeseries: ColumnRef`). - -### H6. `Feature.lineageContext` is internal but exposed as public - -JSDoc explicitly says: "WARNING: This field is primarily intended for internal -use by systems and is automatically populated... Users should not -manually set this field as incorrect values may lead to inaccurate lineage -tracking or unexpected behavior. This field will be set by feature-engineering -client and should be left unset by SDK and terraform users." - -Yet it sits on the public `Feature` interface, with no `@internal` JSDoc tag, -no runtime guardrail, no separate "internal feature creation" path. A TS -consumer constructing a `Feature` literal can fill in any value. +### H3. `Function` interface shadows the JS built-in -Fix: mark `@internal` (or remove from public type and have the server inject -it). - -### H7. `isOnline` redundancy with `destination` - -`MaterializedFeature.isOnline` is `true` iff `destination.$case === 'onlineStoreConfig'`. -Two booleans for one fact. A consumer who reads one and not the other can -misinterpret the record's state. Either: - -- Drop `isOnline` and require consumers to inspect `destination`. -- Make `isOnline` a server-derived read-only flag and forbid setting it on - create/update (it appears in the field-mask schema — model.ts:2510 — and - the JSDoc doesn't say it's read-only). - -### H8. Path-parameter IDs typed as `number` - -`LineageContext.notebookId` and `JobContext.jobId`, `JobContext.jobRunId` are -typed as `number`. Databricks IDs are 64-bit. The other ID field on the same -file (`MaterializedFeature.materializedFeatureId`) is `string`. Inconsistent -within the file *and* potentially unsafe at the `2^53` boundary. - -### H9. `Function` interface shadows the JS built-in - -`export interface Function` (model.ts:343) shadows the TypeScript global +`export interface Function` (model.ts:421) shadows the TypeScript global `Function` type (the constructor signature `Function`). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Most ESLint configs (including this repo's, see @@ -193,57 +78,57 @@ via `globalThis.Function`. Most ESLint configs (including this repo's, see Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. -### H10. Proto-architectural leak: `Outer_Inner` nested names (#31-36) +### H4. Proto-architectural leak: `Outer_Inner` nested names (#19-24) Four public identifiers carry the proto-nested `_` underscore convention straight from the `.proto` IDL into the TS public API: - `Function_FunctionType` (enum, model.ts:29) - `MaterializedFeature_PipelineScheduleState` (enum, model.ts:47) -- `Function_ExtraParameter` (interface, model.ts:388) -- `KafkaConfig_ExtraOptionsEntry` (interface, model.ts:444) +- `Function_ExtraParameter` (interface, model.ts:451) +- `KafkaConfig_ExtraOptionsEntry` (interface, model.ts:558) Each requires an `eslint-disable @typescript-eslint/naming-convention` line to compile, with the disable comment self-identifying as "Proto-style nested enum name" or "Proto-style nested message name". The corresponding zod-schema constants inherit the underscore (`unmarshalFunction_ExtraParameterSchema`, -`marshalFunction_ExtraParameterSchema` — model.ts:1163, 1935). +`marshalFunction_ExtraParameterSchema` — model.ts:1491, 2504). -`KafkaConfig_ExtraOptionsEntry` is a particularly clear leak: it is the -auto-generated proto map-entry type for the `map` field on -`KafkaConfig`. The user-facing TS field is already `extraOptions: -Record` — no consumer can or should reference the entry -type. +`KafkaConfig_ExtraOptionsEntry` is the synthetic map-entry interface the +generator emits for the `extraOptions: map` field; the +user-facing TS field is already `extraOptions: Record` +(model.ts:548), so the `*Entry` type has no consumer in idiomatic TS code. -All four are re-exported from `index.ts` (lines 7-8, 38, 44), so the +All four are re-exported from `index.ts` (lines 7-8, 44, 53), so the underscore-shaped names cross the package boundary into every importer's namespace. Fix at the generator: emit the inner type at the file top level without the outer prefix (`FunctionType`, `PipelineScheduleState`, -`ExtraFunctionParameter`) and drop the synthetic map-entry interface -entirely. +`ExtraFunctionParameter`) and drop the synthetic map-entry interface. --- ## Medium severity (worth pushing back on) -### M1. One `Client` owning three resource families +### M1. One `FeaturesClient` owning four resource families -The `Client` class is 631 lines and exposes methods over three resource +The `FeaturesClient` class is 873 lines and exposes methods over four resource families: - `Feature`: create, get, list, update, delete. - `KafkaConfig`: create, get, list, update, delete. - `MaterializedFeature`: batchCreate, create, get, list, update, delete. +- `Stream`: create, get, list, update, delete. The URL groupings hint that they are distinct sub-resources: - `/api/2.0/feature-engineering/features` - `/api/2.0/feature-engineering/features/kafka-configs` - `/api/2.0/feature-engineering/materialized-features` +- `/api/2.0/feature-engineering/streams` -Splitting to three sub-clients (or three packages) would let each Client read +Splitting to per-resource sub-clients (or packages) would let each Client read as a single focused surface. ### M2. `*Function` interface proliferation @@ -290,12 +175,7 @@ without affecting `AvgFunction`. Worth pushing back on.) - `DeltaTableSource.entityColumns: string[]` — plural field, primitive element. Deprecated. Three plural conventions for the same notion. -### M4. Three names for one notion (`entities` / `entityColumns` / `entityColumnIdentifiers`) - -See H5. The three names also differ in element type (`EntityColumn`, `string`, -`ColumnIdentifier`). Cf. T3 in cross-cutting observations below. - -### M5. `ColumnSelection` interface is too generic +### M4. `ColumnSelection` interface is too generic JSDoc says `ColumnSelection` represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow". The name gives no domain hint. @@ -316,136 +196,27 @@ implications. Fine. Fine. -### L3. `cronSchedule` field on `MaterializedFeature` - -`MaterializedFeature.cronSchedule: string` is a Quartz cron expression. The -field name is fine; the type could be a branded `CronExpression` for stronger -typing, but flagging only for completeness. - -### L4. `ContinuousWindow.offset` allows non-positive +### L3. `ContinuousWindow.offset` allows non-positive Note in JSDoc: "must be non-positive" — i.e., 0 or negative duration. The type is `Temporal.Duration` which doesn't constrain sign. Documentation-only constraint; not enforced. Same critique as `SlidingWindow.slideDuration` ("must be positive and less than duration"). -### L5. `ProtoSchemaSpec.schemaText` carries the entire `.proto` file text - -A `string` containing potentially many KB of source text. Naming is fine; the -data shape is the design choice. Listing for completeness. - -### L6. `SecretScopeReference { scope, key }` +### L4. `SecretScopeReference { scope, key }` Two-field reference to a Databricks secret. Standard. Fine. -### L7. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` +### L5. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` Four Spark Structured Streaming idioms. Standard. Fine. -### L8. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` +### L6. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` Three field-mask builders. Standard generator pattern. Fine. -### L9. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` +### L7. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` The list endpoint filters by feature name (full UC name). Field is `featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` in the response, which is the same value. - ---- - -## Cross-cutting observations (not flags) - -### T1. Generator marker - -Every file begins with `// Code generated from API definition by Databricks -SDK Generator. DO NOT EDIT.` All issues here must be fixed upstream. - -### T2. Three packages, three different concepts of "what is a feature" - -| Package | What it owns | Where it lives | -|---------|--------------|----------------| -| `features` | `Feature` definitions, `KafkaConfig`, `MaterializedFeature` | this audit | -| `materializedfeatures` | `FeatureLineage`, `FeatureTag` (mismatched name) | `packages/materializedfeatures/` | -| `featurestore` | `OnlineStore`, `PublishTable` | `packages/featurestore/` | - -Domain-wise these are all *one product* (Databricks Feature Engineering / -Feature Store). They are split across three packages whose names suggest a -different breakdown than the contents. - -### T3. Optionality model - -Every field is `T | undefined`. Matches the rest of the SDK -(`exactOptionalPropertyTypes`). - -### T4. `index.ts` re-export style - -Class re-exported with `export {Client}`; enums (runtime values) re-exported -with `export {ScalarDataType, Function_FunctionType, MaterializedFeature_PipelineScheduleState}`; -interfaces (type-only) re-exported with `export type {...}`. Correct for -`verbatimModuleSyntax`. - -### T5. No tests - -No `tests/` directory for this package (matches sibling Feature Engineering -packages). - -### T6. Versioning - -Only `v1` exists; nothing to compare. - -### T7. Acronym casing - -| Acronym | Code form | JSDoc text | Consistent? | -|---------|-----------|-----------|-------------| -| UC (Unity Catalog) | `unityCatalog*` (e.g., `ucServiceCredentialName`) — *not used here*; appears in `AuthConfig.$case === 'ucServiceCredentialName'` (model.ts:104) | "Unity Catalog" spelled out | Mixed (cf. credentials audit M7) | - -| SQL | `transformationSql` field, `sql` lowercase | "SQL" all-caps | Field uses `Sql` (PascalCase-first-letter). Fine. | -| TLS / mTLS | `MtlsConfig`, `mtlsConfig` | "Mutual-TLS (mTLS)" mixed | Code `Mtls` (PascalCase-first-letter). Diverges from RFC convention "mTLS". | -| TLS / SSL | `disableHostnameVerification` (no acronym) | "SSL" / "TLS" all-caps | N/A | -| IETF | `jsonSchema`, "IETF JSON schema" in JSDoc | N/A | N/A | -| JKS | "JKS files" in JSDoc | N/A | N/A | - -### T8. Streaming-specific vocabulary - -`SubscriptionMode.assign` / `subscribe` / `subscribePattern` directly mirror -Spark Structured Streaming Kafka options. Documented inline. Fine for users -who know the upstream API; opaque otherwise. - ---- - -## Domain glossary (as inferred from this code) - -| Term | Meaning in this package | -|------|-------------------------| -| **Feature** | A UC-registered feature definition: full three-part name + data source + aggregation function + time window. Reached via `/api/2.0/feature-engineering/features`. | -| **Materialized Feature** | A scheduled pipeline that computes a feature's values and writes them to an offline UC Delta table or an online Lakebase table. Reached via `/api/2.0/feature-engineering/materialized-features`. | -| **Kafka Config** | A reusable Kafka cluster + topic-subscription + schema bundle. Referenced by `KafkaSource.name` from `Feature.source`. | -| **Pipeline Schedule State** | The state of the underlying DLT pipeline driving the materialization. One of `SNAPSHOT` (one-shot), `ACTIVE` (running), `PAUSED`. | -| **Aggregation Function** | One of 13 SQL aggregations (`avg`, `count`, `sum`, `min`, `max`, `first`, `last`, `approxCountDistinct`, `approxPercentile`, `stddevPop`, `stddevSamp`, `varPop`, `varSamp`) applied over a time window. | -| **Column Selection** | The non-aggregation alternative to `AggregationFunction` — picks the latest value of a single column over a lifetime continuous window. Semantic equivalent of SQL `LAST()`. | -| **Data Source** | One of three: Delta table (batch), Kafka stream (streaming), Request-time (inference-time scoring). | -| **Backfill Source** | A user-provided historical-data table used when constructing training sets from streaming features. | -| **Time Window** | One of three Spark windowing variants: continuous, tumbling (non-overlapping fixed-duration), sliding (overlapping). | -| **Subscription Mode** | Kafka topic-selection mode: explicit topic-partition `assign`, comma-separated `subscribe`, regex `subscribePattern`. | -| **Auth Config** | One of two Kafka auth flavors: Unity-Catalog service credential, or mTLS keystores/truststores. | -| **Lineage Context** | Internal-only field linking a feature to the notebook/job that created it. Auto-populated by the feature-engineering client. | -| **Entity Column** | Column(s) used as the lookup key for the feature at query time. Aggregation keys. | -| **Timeseries Column** | The event-time column on the source data. Used for point-in-time joins, backfills, and aggregation windowing. | -| **Online Store** | A Lakebase logical database + schema serving low-latency feature lookups. | -| **Offline Store** | A Delta table serving batch-scoring/training feature lookups. | - ---- - -## File coverage - -| File | Lines | Exports counted | Audited | -|------|-------|-----------------|---------| -| `src/v1/model.ts` | 2638 | 3 enums, 50 interfaces, 60 zod consts (30 unmarshal + 30 marshal), 3 field-mask helpers | yes | -| `src/v1/client.ts` | 636 | 1 class, public methods covering 3 resource families (Feature, KafkaConfig, MaterializedFeature) | yes | -| `src/v1/utils.ts` | 150 | 1 interface, 5 functions | yes | -| `src/v1/index.ts` | 77 | 1 class re-export, 3 enum re-exports, 60 type re-exports | yes | - -Every type, field, enum value, and method enumerated above is accounted for. - ---- diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index 1d0e232c..7d642370 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -10,59 +10,6 @@ --- -## Inventory - -### Enums - -1. `OnlineStore_State` (model.ts:9) - - Values: `STATE_UNSPECIFIED`, `STARTING`, `AVAILABLE`, `DELETING`, - `STOPPED`, `UPDATING`, `FAILING_OVER`. -2. `PublishSpec_PublishMode` (model.ts:27) - - Values: `PUBLISH_MODE_UNSPECIFIED`, `CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`. - -### Interfaces / Types - -1. `CreateOnlineStoreRequest` (model.ts:47) — fields: `onlineStore`. -2. `DeleteOnlineStoreRequest` (model.ts:52) — fields: `name`. -3. `DeleteOnlineTableRequest` (model.ts:57) — fields: `onlineTableName`. -4. `GetOnlineStoreRequest` (model.ts:62) — fields: `name`. -5. `ListOnlineStoresRequest` (model.ts:67) — fields: `pageToken`, `pageSize`. -6. `ListOnlineStoresResponse` (model.ts:74) — fields: `onlineStores`, - `nextPageToken`. -7. `OnlineStore` (model.ts:82) — fields: `name`, `creator`, `creationTime`, - `state`, `capacity`, `readReplicaCount`, `usagePolicyId`. -8. `PublishSpec` (model.ts:99) — fields: `onlineStore`, `onlineTableName`, - `publishMode`. -9. `PublishTableRequest` (model.ts:108) — fields: `sourceTableName`, - `publishSpec`. -10. `PublishTableResponse` (model.ts:115) — fields: `onlineTableName`, - `pipelineId`. -11. `UpdateOnlineStoreRequest` (model.ts:122) — fields: `onlineStore`, - `updateMask`. - -### Zod schemas - -- `unmarshalListOnlineStoresResponseSchema` (model.ts:129) -- `unmarshalOnlineStoreSchema` (model.ts:142) -- `unmarshalPublishTableResponseSchema` (model.ts:165) -- `marshalOnlineStoreSchema` (model.ts:176) -- `marshalPublishSpecSchema` (model.ts:199) -- `marshalPublishTableRequestSchema` (model.ts:211) - -### Field-mask helpers - -- `onlineStoreFieldMaskSchema` (model.ts:221, module-internal) -- `onlineStoreFieldMask()` (model.ts:231, public) - -### Client class - -- `Client` (client.ts:46) - - Methods: `createOnlineStore`, `deleteOnlineStore`, `deleteOnlineTable`, - `getOnlineStore`, `listOnlineStores`, `listOnlineStoresIter`, - `publishTable`, `updateOnlineStore`. - ---- - ## Findings ### 1. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) — *Still* @@ -108,85 +55,7 @@ unilateral change here would diverge from sibling packages. --- -### 2. `FAILING_OVER` present-tense vs. `STOPPED`/`UPDATING` mixed — category 13 (Verb-tense inconsistency) — *Still* - -**Symbols:** `OnlineStore_State.FAILING_OVER` (model.ts:23), `STARTING`, -`DELETING`, `UPDATING` (model.ts:13, 17, 21) vs. `STOPPED`, `AVAILABLE` -(model.ts:19, 15). - -**Issue:** Six of the seven values are either progressive (`-ING`) or -adjectival/perfect (`STOPPED`, `AVAILABLE`, `UNSPECIFIED`). `FAILING_OVER` -mixes a participle with a particle preposition; the canonical -network/database term is `FAILOVER` (noun) or `FAILING_OVER` (verb-phrase). -Compare: AWS RDS uses `failing-over` as a state, Postgres uses -`failover`. Mark as a wire-level concern — TS identifier `FailingOver` is -fine under finding 1. **Pass at the TS level**, flag at the wire level. - ---- - -### 3. `DeleteOnlineTableRequest.onlineTableName` diverges from sibling package — category 12 (Duplicate concepts) and category 19 (Underspecified IDs) — *Still* - -**Symbol:** `DeleteOnlineTableRequest.onlineTableName` (model.ts:59), wire -field `online_table_name` (the field appears in the URL path, not JSON). - -**Issue:** The neighbouring `onlinetables/v1` package defines an *identical* -operation with a *different* field name: - -```ts -// onlinetables/v1/model.ts:93 -export interface DeleteOnlineTableRequest { - name?: string | undefined; // Full three-part name of the table. -} -``` - -Both packages name the type `DeleteOnlineTableRequest` (identical type names -in two packages — namespace-distinguished, but confusing). The field is -called `name` in `onlinetables`, `onlineTableName` in `featurestore`. A -caller switching packages would have to translate the field. The URL paths -also differ: `/api/2.0/online-tables/{name}` in `onlinetables` vs. -`/api/2.0/feature-store/online-tables/{onlineTableName}` here. - -`featurestore`'s field name is *more* descriptive (since the context is -"feature-store deletes an online table that wraps a 3-part Unity name"), -which is defensible — but the divergence is jarring. **Cross-package -alignment recommendation:** harmonise on `name` (shorter, idiomatic for -URL-path resource identifiers; matches HTTP REST conventions and the Go SDK's -`name` field for resources). - -This finding *also* hits category 19: the field is documented as "The full -three-part (catalog, schema, table) name of the online table." which is a -**very specific format** — neither the name nor the JSDoc enforces it. A -typed wrapper (e.g. `ThreePartName`) is an option, but cross-SDK convention -keeps it as a string. **Pass on the wrapper**, flag the field-name -divergence. - ---- - -### 4. `OnlineStore.capacity: string` with comment specifying valid values — category 1 (Vague/generic) and category 6 (Misleading names) — *Still* - -**Symbol:** `OnlineStore.capacity?: string` (model.ts:92). JSDoc: "The -capacity of the online store. Valid values are "CU_1", "CU_2", "CU_4", -"CU_8"." - -**Issue:** A field with four valid enum-like string values is typed as -`string`. This is a **missing enum** — the appropriate shape is a string -literal union or a TS enum: - -```ts -// Either: -capacity?: 'CU_1' | 'CU_2' | 'CU_4' | 'CU_8' | undefined; -// or: -export enum OnlineStoreCapacity { CU1 = 'CU_1', CU2 = 'CU_2', ... } -``` - -The Go SDK uses a string for forward-compatibility (open enum), but TS can -model an *open* enum with `'CU_1' | 'CU_2' | (string & {})` if needed. The -current shape — bare `string` with a JSDoc note — provides no compile-time -help. **Flag for SDK-wide policy on open enums** (categories 1 + 6). - ---- - -### 5. `PublishSpec` is vague — category 1 (Vague/generic) — *Still* +### 2. `PublishSpec` is vague — category 1 (Vague/generic) — *Still* **Symbol:** `PublishSpec` (model.ts:99). @@ -204,14 +73,14 @@ which has more room because it lives in the `featurestore` Go package. --- -### 6. `PublishTableResponse.pipelineId` — *pass* — *Still* +### 3. `PublishTableResponse.pipelineId` — *pass* — *Still* Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. No issue. --- -### 7. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* — *Still* +### 4. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* — *Still* **Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` (model.ts:126). @@ -222,32 +91,7 @@ naming is SDK-wide and idiomatic. **Pass.** --- -### 8. `Client.deleteOnlineTable` is in `featurestore` but `onlinetables` has its own — category 12 (Duplicate concepts) — *Still* - -**Symbols:** `Client.deleteOnlineTable` (client.ts:117, featurestore) vs. -`Client.deleteOnlineTable` (client.ts:108, onlinetables). - -**Issue:** Two SDK packages expose a method with the same name that hits -*different* HTTP endpoints: - -- `featurestore.deleteOnlineTable` → `/api/2.0/feature-store/online-tables/{onlineTableName}` -- `onlinetables.deleteOnlineTable` → `/api/2.0/online-tables/{name}` - -The semantic is "delete an online table" in both cases, but the endpoints -are separate. This is a *backend* concern, but at the SDK level a TS user -will import both `@databricks/sdk-featurestore/v1.Client` and -`@databricks/sdk-onlinetables/v1.Client` and find two identically-named -methods that do related but distinct things. Compounded by finding 3 where -the *request types* are also identically named but field-incompatible. - -**Suggested at the SDK level:** in `featurestore`, rename the method to -`deletePublishedOnlineTable` (since the table only exists because of -`publishTable`). This is a soft fix; the bigger issue is the duplicated -*surface* across packages. **Flag for the SDK platform team.** - ---- - -### 9. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* — *Still* +### 5. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* — *Still* **Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and `onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the @@ -256,14 +100,7 @@ Google AIP-134 update-mask vocabulary. **Pass.** --- -### 10. `Client` class name — category 1 (Vague/generic) — *pass* — *Still* - -Package convention. Every TS package exports a single `Client` class scoped -to its import path (e.g. `@databricks/sdk-featurestore/v1`). **Pass.** - ---- - -### 11. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* +### 6. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* **Symbols:** `ListOnlineStoresRequest` (model.ts:67), `ListOnlineStoresResponse` (model.ts:74). @@ -275,21 +112,14 @@ package qualifies. **Pass on package consistency.** --- -### 12. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* +### 7. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* `ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the canonical pattern. **Pass.** --- -### 13. `creator` vs `pipelineId` casing — category 3 (Acronym/compound-word casing) — *pass* — *Still* - -`pipelineId` correctly camelCases the two-letter "ID"; `creator` is a -plain word. **Pass.** - ---- - -### 14. `OnlineStore_State` — model.ts:9 — *Still* +### 8. `OnlineStore_State` — model.ts:9 — *Still* **Why:** `Parent_Nested` underscore-joined identifier is a literal translation of a proto nested-type path into the TS symbol name. The @@ -311,9 +141,9 @@ namespace. --- -### 15. `PublishSpec_PublishMode` — model.ts:27 — *Still* +### 9. `PublishSpec_PublishMode` — model.ts:27 — *Still* -**Why:** Same `Parent_Nested` proto-namespace leak as finding 14. The +**Why:** Same `Parent_Nested` proto-namespace leak as finding 8. The identifier reads as "PublishSpec's PublishMode" — the enclosing-type prefix is a verbatim port of the proto nested-type name, and the file acknowledges this with the same eslint-disable comment. @@ -327,41 +157,3 @@ prefix duplicates the enclosing type and adds no information (the only field that uses it is `PublishSpec.publishMode`). Dropping the proto nesting yields a clean `PublishMode` symbol that matches how the field already reads (`publishMode: PublishMode`). No wire change. - ---- - -## Cross-package notes (per audit instructions) - -### `DeleteOnlineTableRequest` name collision with `onlinetables/v1` - -Already covered in finding 3. Two distinct request types share the same -type name across packages, with different field names. A consumer who -imports both packages (likely — they are complementary) writes: - -```ts -import {DeleteOnlineTableRequest as FsDeleteOnlineTableRequest} - from '@databricks/sdk-featurestore/v1'; -import {DeleteOnlineTableRequest as OtDeleteOnlineTableRequest} - from '@databricks/sdk-onlinetables/v1'; -``` - -Friction-heavy. **Strong recommendation:** rename -`featurestore.DeleteOnlineTableRequest` to e.g. -`DeletePublishedOnlineTableRequest` (it deletes a table created by -`publishTable`) — or rename `featurestore.deleteOnlineTable` method to -`deletePublishedOnlineTable` and follow with the request type. Aligns with -finding 8. - ---- - -### `publishMode` cross-package overlap - -`PublishSpec_PublishMode` (this package, model.ts:27) has values -`CONTINUOUS`, `TRIGGERED`, `SNAPSHOT`. The `onlinetables` package has -`OnlineTableSpec.schedulingPolicy` with discriminated `runContinuously` / -`runTriggered` cases (onlinetables/v1/model.ts:145–153). Same underlying -concept (continuous vs. triggered pipeline), two different modelling -approaches (string enum vs. discriminated union). Plus there is no -`SNAPSHOT` case in `onlinetables`. **Flag for upstream protocol alignment.** - ---- diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index b6ac7ae3..bada1598 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -2,89 +2,18 @@ **Path:** `packages/files/src/v2/` **Versions audited:** v2 -**Inferred domain:** File operations on Databricks storage. v2 is the generated 1:1 port of the upstream API surface and is the union of TWO distinct underlying services: (a) the legacy DBFS API (`/api/2.0/dbfs/...`) — `addBlock`, `close`, `create`, `delete`, `getStatus`, `list`, `mkdirs`, `move`, `put`, `read`; and (b) the modern Files API (`/api/2.0/fs/...`) — `createDirectory`, `deleteDirectory`, `deleteFile`, `downloadFile`, `getDirectoryMetadata`, `getFileMetadata`, `listDirectoryContents`, `uploadFile`. Both surfaces are presented through a single `Client` class with no naming distinction between the two services. -**Total weird names flagged:** 12 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | -| High | 6 | -| Medium | 3 | +| High | 1 | | Low | 1 | -| Observation | 2 | ## High severity -### 1. `DBFS` vs `Dbfs` casing — never appears in TS identifier, only in JSDoc — model & client - -- **Why weird:** "DBFS" appears 11 times in JSDoc strings (e.g. "The path should be the absolute DBFS path.", `model.ts:33,64,161,214,225,233,235,243,255`) and once in client docstrings ("DBFS REST API"). But NONE of the TS type or method names carry the prefix. The class is just `Client`, the methods are `read`/`write`/`put`/`delete`/`move`/`mkdirs` — DBFS is invisible at the TS surface. Compare with `databricks-sdk-go` upstream where these are split into `dbfs.API` and `files.API` as separate services. The TS port merges them and removes the namespace. -- **Category:** 3 (acronym casing — should be `Dbfs` if it were ever used), 16 (field-contradicting-domain), 17 (inconsistency — JSDoc says DBFS, identifier doesn't). -- **Suggested name:** Carry the surface name in identifiers: `DbfsClient` for the legacy methods, or split into two packages / sub-modules: `@databricks/sdk-files/v2/dbfs` and `@databricks/sdk-files/v2/files`. If kept as one client, prefix the methods (`client.dbfsRead`, `client.dbfsMove`, ...). -- **Rationale:** Two REST APIs in one class with no naming signal mixes a deprecated surface (DBFS, max 1 MB per call, deprecated by Databricks) with the modern surface (Files API, 5 GiB streaming). Users can't tell which to use from the method list. Surface name in identifier resolves this. - -### 2. Package name `files` and class name `Client` are both contextless — `client.ts:94` - -```ts -export class Client { ... } // src/v2/client.ts:94 -``` - -- **Why weird:** Exports `Client` without qualification. Consuming code that imports from multiple packages ends up with `import {Client as FilesClient} from '@databricks/sdk-files/v2';` in every file. The package name `files` is also generic — DBFS files? UC volume files? Workspace files (already a separate `@databricks/sdk-workspace`)? Workspace assets called "files"? The package scopes ALL of: DBFS API, Files API for UC volumes, generic file storage. -- **Category:** 1 (vague — "files" overloaded across at least DBFS, UC Volumes, Workspace files), 6 (misleading — name does not signal which file surface). -- **Suggested name:** Export `FilesClient` (or split — `DbfsClient` + `FilesClient`). The package itself could be `@databricks/sdk-dbfs-and-files` (ugly but honest) or split into two packages. -- **Rationale:** Already a problem in the wider SDK; `Client` is opaque in error messages and stack traces. - -### 3. `DirectoryEntry` vs `FileInfo` — duplicate concept inside v2 — `src/v2/model.ts:73,114` - -```ts -export interface DirectoryEntry { - fileSize?: number | undefined; - isDirectory?: boolean | undefined; - lastModified?: number | undefined; - name?: string | undefined; - path?: string | undefined; -} - -export interface FileInfo { - path?: string | undefined; - isDir?: boolean | undefined; - fileSize?: number | undefined; - modificationTime?: number | undefined; -} -``` - -- **Why weird:** Both types describe a file-or-directory metadata snapshot, with overlapping fields: - - Both have `path`, `fileSize`. - - `DirectoryEntry.isDirectory` vs `FileInfo.isDir` (same field, two casings). - - `DirectoryEntry.lastModified` vs `FileInfo.modificationTime` (same wire concept, two names). - - `DirectoryEntry.name` (component name) — exists only in `DirectoryEntry`. - Two distinct types because they come from two distinct REST APIs (modern listDirectoryContents vs legacy listStatus / getStatus). The client exposes both, side-by-side, with no docstring telling callers which to use. -- **Category:** 12 (duplicate concepts), 17 (cross-API naming clash), 6 (misleading — `DirectoryEntry` may be a file). -- **Suggested name:** Pick one. `FileInfo` is the existing standard (also used in `experiments`, `marketplaces` packages — see #4). Re-shape `DirectoryEntry` to extend `FileInfo` with `name`. -- **Rationale:** Two identical-shape types with different field names are a maintenance hazard. - -### 4. `FileInfo` collides with at least two other packages — `src/v2/model.ts:114` - -```ts -// files/v2: file/directory metadata snapshot -export interface FileInfo { - path?: string | undefined; - isDir?: boolean | undefined; - fileSize?: number | undefined; - modificationTime?: number | undefined; -} -// experiments/v1/model.ts:248 — MLflow file artifact -export interface FileInfo { ... } -// marketplaces/v1/model.ts:288 — listing file attachment -export interface FileInfo { ... } -``` - -- **Why weird:** Three different packages all export `FileInfo` with three different shapes. The names are flat-spaced inside the package, but downstream consumers who do `import * as files from '@databricks/sdk-files/v2'; import * as exp from '@databricks/sdk-experiments/v1';` get two unrelated `FileInfo` types and `files.FileInfo !== exp.FileInfo` is a confusing source of bugs. -- **Category:** 1 (vague/generic top-level name), 12 (duplicate concept across packages), 15 (generic name loses meaning). -- **Suggested name:** `DbfsFileInfo` (or merge with `DirectoryEntry` per #3 — `FileEntry`). -- **Rationale:** `FileInfo` is so generic three different domains felt entitled to use it. - -### 5. `CreateRequest` returns a `handle` (not the created file) — `src/v2/model.ts:32-43` +### 1. `CreateRequest` returns a `handle` (not the created file) — `src/v2/model.ts:32-42` ```ts export interface CreateRequest { @@ -92,7 +21,7 @@ export interface CreateRequest { overwrite?: boolean | undefined; } // Response shape: -// handle?: number | undefined; +// handle?: bigint | undefined; // "Handle which should subsequently be passed into the AddBlock and Close calls when writing to a file through a stream." ``` @@ -101,77 +30,12 @@ export interface CreateRequest { - **Suggested name:** `OpenWriteStreamRequest` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). - **Rationale:** Method name should reflect action; right now `create` and `createDirectory` look like sibling actions when they are entirely different (create-handle vs create-resource). -### 6. `listDirectoryContents` vs `list` — same action, two methods — `src/v2/client.ts:321,730` - -```ts -async list(req: ListStatusRequest, ...): Promise // legacy DBFS -async listDirectoryContents(req: ListDirectoryContentsRequest, ...): Promise // modern Files -``` - -- **Why weird:** Two list methods on the same client. `list` is the legacy DBFS list (no paging), `listDirectoryContents` is the modern Files API (paginated). The names give no signal which is which; the JSDoc on `list` calls out a 60 s timeout and a 10 K file limit. A naive caller will pick the shorter name and hit production limits. -- **Category:** 1 (vague — `list` is generic), 12 (duplicate concept), 17 (inconsistent — `list` is short, `listDirectoryContents` is long; both list a directory). -- **Suggested name:** `dbfsListStatus` (legacy) and `listDirectoryContents` (modern). Or `list` (modern, paged, recommended) and `dbfsList` (legacy, deprecated). -- **Rationale:** Method-name length should not be the only discriminator between a recommended modern API and a deprecated legacy one. - -## Medium severity - -### 7. `ListDirectoryContentsRequest` paired with `ListDirectoryResponse` — request/response noun mismatch — `src/v2/model.ts:178,206` - -```ts -export interface ListDirectoryContentsRequest { ... } -export interface ListDirectoryResponse { ... } // not ListDirectoryContentsResponse -``` - -- **Why weird:** The request has 4 words (`List Directory Contents Request`); the response has 3 (`List Directory Response`). Same wire endpoint. The asymmetry forces every caller to remember which name has the `Contents` word and which doesn't. Other request/response pairs in this file are matched (`CreateDirectoryRequest` / `CreateDirectoryResponse`; `DownloadFileRequest` / `DownloadFileResponse`). -- **Category:** 7 (overly verbose), 9 (singular/plural mismatch — also: "contents" pluralised on request, dropped on response), 17 (inconsistent with the rest of the file). -- **Suggested name:** `ListDirectoryContentsResponse` to mirror the request. Or trim both to `ListDirectoryRequest` / `ListDirectoryResponse`. -- **Rationale:** Same endpoint, same operation — names should mirror. - -### 8. `MoveRequest.sourcePath` / `MoveRequest.destinationPath` use snake_case on the wire — `src/v2/model.ts:484-492` - -```ts -export const marshalMoveRequestSchema: z.ZodType = z - .object({ - sourcePath: z.string().optional(), - destinationPath: z.string().optional(), - }) - .transform(d => ({ - source_path: d.sourcePath, - destination_path: d.destinationPath, - })); -``` - -- **Why weird:** The wire keys are `source_path` / `destination_path` — but ALL other DBFS methods use a single `path` field. This is an entirely separate field-naming convention used in one method. Compare: `DeleteRequest.path` (not `target_path`), `GetStatusRequest.path` (not `target_path`), but `MoveRequest.sourcePath` / `MoveRequest.destinationPath`. -- **Category:** 17 (inconsistent — single endpoint convention). -- **Suggested name:** Acceptable as-is (these are clearer than `path1`/`path2`). Flag only the inconsistency with the rest of the DBFS surface. -- **Rationale:** The inconsistency is upstream; the TS port should match. - -### 9. `bytesRead` vs `data` in the read response — singular/plural and naming mismatch — `src/v2/model.ts:267-274` - -```ts -// ReadRequest_Response: -// bytesRead?: number // count -// data?: Uint8Array // bytes -``` - -`bytesRead` (count) and `data` (the bytes) refer to the same byte slice. `bytesRead` is the LENGTH; `data` is the BUFFER. Cleaner: `bytes: Uint8Array` and `bytesRead: number` (count); even better, drop `bytesRead` since `data.byteLength` is the same value. - ## Low severity -### 10. `overwrite` — same — `src/v2/model.ts:36,248,283` +### 2. `overwrite` — same — `src/v2/model.ts:36,245,279` ```ts overwrite?: boolean | undefined; ``` Appears in `CreateRequest`, `PutRequest`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `CreateRequest` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. - -## Observations - -### 11. `pageSize: number` — should mention coercion — `src/v2/model.ts:192` - -JSDoc says "The maximum value is 1000. Values above 1000 will be coerced to 1000." Type does not encode the constraint. (TS branded types could; not a naming issue.) - -### 12. `pageToken` — opaque token, marked `string | undefined` — `src/v2/model.ts:203` - -Best practice is to brand the type (`PageToken = string & {readonly __brand: unique symbol}`) to prevent passing an arbitrary string. Not a naming issue per se. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index ad790aa0..1f1f264e 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -7,96 +7,19 @@ - `src/v1/model.ts` - `src/v1/client.ts` - `src/v1/index.ts` - -This audit applies the audit checklist categories. Each finding lists -the offending identifier(s), the category, severity -(`HIGH` / `MEDIUM` / `LOW`), and a concrete rename suggestion. -Findings are grouped by category. - ---- - -## Inventory - -### Enums (`model.ts`) - -| Name | Members | -| ----------------------------- | ------- | -| `ForecastingExperiment_State` | `PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`, `CANCELLED` | - -### Interfaces (`model.ts`) - -`CreateForecastingExperimentRequest`, -`CreateForecastingExperimentResponse`, `ForecastingExperiment`, -`GetForecastingExperimentRequest`. - -### Client classes and methods (`client.ts`) - -- Class `Client` - - Method `createForecastingExperiment` - - Method `createForecastingExperimentWaiter` - - Method `getForecastingExperiment` -- Class `CreateForecastingExperimentWaiter` - - Field `experimentId` - - Method `wait` - - Method `done` -- Local helper class `StillRunningError` +- `src/v1/transport.ts` +- `src/v1/utils.ts` --- ## Findings -### 1. Vague / generic names - -#### F1.1 — `Client` class name (MEDIUM) -- **Where:** `client.ts:42`, `index.ts:3`. -- **Why flagged:** Every package in this SDK exports a `Client`. - Re-exported in a barrel like - `import {Client as ForecastingClient} from '@databricks/sdk-forecasting'` - it is fine, but unqualified `Client` symbol-shadows aggressively. - This is a project-wide pattern, not a forecasting-specific issue. -- **Suggestion:** Either keep `Client` and document the - package-qualified import convention, or rename to - `ForecastingClient` consistently across packages. Cross-cutting. - -#### F1.2 — `primaryMetric: string` (MEDIUM) -- **Where:** `model.ts:34`. -- **Why flagged:** "Primary metric" without enumeration is vague. - JSDoc says only "The evaluation metric used to optimize the - forecasting model" with no enumeration of permitted values. By - contrast, `forecastGranularity` JSDoc lists allowed values inline. - The user has no way to know what to pass. -- **Suggestion:** Document allowed values in JSDoc (e.g. `mae`, `mse`, - `rmse`, `mape`, `mdape`, `smape`), or introduce a string-literal - union type `PrimaryMetric = 'mae' | 'mse' | …`. Naming itself is - fine; signal loss happens at the field level. - -#### F1.3 — `target` is *not* present here (note) -- Unlike many sibling packages, this package's request payload uses - domain-specific column names (`targetColumn`, `splitColumn`, - `timeColumn`, `customWeightsColumn`) which is *good* and is the - pattern other packages should follow. Worth noting as a positive - example. +### 1. Misleading names ---- - -### 2. Redundant enum prefixes - -_None._ - ---- - -### 3. Acronym casing inconsistencies - -_None._ - ---- - -### 4. Misleading names - -#### F4.1 — `done` method on the waiter does not return a boolean of +#### F1.1 — `done` method on the waiter does not return a boolean of "I'm done waiting" but "operation has reached a terminal state" (LOW) -- **Where:** `client.ts:194-215`. +- **Where:** `client.ts:194-216`. - **Why flagged:** Method `done()` returns `Promise` and performs a poll. A naive reader might assume `done()` reflects internal waiter state (similar to `Promise.resolve(done)` or @@ -106,9 +29,9 @@ _None._ ("Checks whether the operation has reached a terminal state.") does clarify this, but the name does not. -#### F4.2 — `createForecastingExperimentWaiter` returns the waiter, +#### F1.2 — `createForecastingExperimentWaiter` returns the waiter, not the response (LOW) -- **Where:** `client.ts:99-110`. +- **Where:** `client.ts:104-115`. - **Why flagged:** The method name suggests "create a waiter," but it actually performs the *create* call first and then wraps the result. The return type @@ -124,9 +47,9 @@ _None._ --- -### 5. Overly verbose +### 2. Overly verbose -#### F5.1 — `ForecastingExperiment` (MEDIUM) +#### F2.1 — `ForecastingExperiment` (MEDIUM) - **Where:** `model.ts:72`. - **Why flagged:** Inside a package literally named `forecasting`, every type is about forecasting. The `Forecasting` prefix doesn't @@ -134,13 +57,13 @@ _None._ `import {ForecastingExperiment} from '@databricks/sdk-forecasting'` — the `Forecasting` is said twice. - **Suggestion:** Rename to `Experiment`. The package name carries - the qualifier. Combined with F5.2 / F5.3 this collapses naming + the qualifier. Combined with F2.2 / F2.3 this collapses naming significantly. **Caveat:** `Experiment` is the same name used by the MLflow `experiments` API. If both packages are likely to be imported together, the qualification helps. Worth a cross-package review. -#### F5.2 — `CreateForecastingExperimentRequest`, +#### F2.2 — `CreateForecastingExperimentRequest`, `CreateForecastingExperimentResponse`, `GetForecastingExperimentRequest` (MEDIUM) - **Where:** `model.ts:19, 66, 81`; `index.ts:8-12`. @@ -154,31 +77,31 @@ _None._ `GetExperimentRequest`. Or, if collapsed to a single client method per verb, just `CreateRequest`/`CreateResponse`/`GetRequest`. -#### F5.3 — `CreateForecastingExperimentWaiter` (HIGH) -- **Where:** `client.ts:138`, `index.ts:3`. +#### F2.3 — `CreateForecastingExperimentWaiter` (HIGH) +- **Where:** `client.ts:146`, `index.ts:3`. - **Why flagged:** 34 characters. Reads as "Create-Forecasting-Experiment-Waiter". With `Forecasting` removed - (F5.1), it becomes `CreateExperimentWaiter` — still long but + (F2.1), it becomes `CreateExperimentWaiter` — still long but workable. The `Waiter` suffix itself is a Go SDK pattern; in TS/JS the more common terms are `Operation`, `Poller`, `Run`, or `Tracker`. Alternative: drop `Create` since the waiter exists only for create-style long-running operations, and name it `ExperimentRun` or `Operation`. - **Suggestion:** Rename to `ExperimentRun` (analogous to - `LongRunningOperation` in other SDKs). Combined with F4.2, the + `LongRunningOperation` in other SDKs). Combined with F1.2, the flow becomes `const run = await client.forecasting.startExperiment(req); await run.wait();`. -#### F5.4 — `createForecastingExperimentWaiter` method (HIGH) -- **Where:** `client.ts:99`. -- **Why flagged:** 35 character method name. Same issue as F5.3. +#### F2.4 — `createForecastingExperimentWaiter` method (HIGH) +- **Where:** `client.ts:104`. +- **Why flagged:** 35 character method name. Same issue as F2.3. - **Suggestion:** Rename to `startExperiment` (or `createAndWait`) to match a renamed waiter. -#### F5.5 — `getForecastingExperiment` / `createForecastingExperiment` +#### F2.5 — `getForecastingExperiment` / `createForecastingExperiment` methods (MEDIUM) -- **Where:** `client.ts:68, 113`. +- **Where:** `client.ts:70, 118`. - **Why flagged:** Inside a `Forecasting` client, the `Forecasting` suffix is repetitive. Compare typical TS SDK shape: `forecasting.experiments.create(...)`, @@ -190,62 +113,36 @@ _None._ --- -### 6. Go-style `Waiter` pattern +### 3. Go-style `Waiter` pattern -#### F6.1 — `Waiter` suffix on `CreateForecastingExperimentWaiter` +#### F3.1 — `Waiter` suffix on `CreateForecastingExperimentWaiter` (LOW) -- **Where:** `client.ts:138`. +- **Where:** `client.ts:146`. - **Why flagged:** `Waiter` is a Go SDK pattern for long-running operations. In TS/JS the more common terms are `Operation`, `Poller`, `Run`, or `Tracker`. `Waiter` isn't wrong but it is Go-flavored. - **Suggestion:** Rename suffix to `Operation` or `Run` (e.g. - `ExperimentRun`). See F5.3. + `ExperimentRun`). See F2.3. --- -### 7. Reserved-word / built-in collisions +### 4. Reserved-word / built-in collisions -#### F7.1 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) -- **Where:** `client.ts:194`. +#### F4.1 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) +- **Where:** `client.ts:195`. - **Why flagged:** `done` shadows `IteratorResult.done` (the boolean property returned by iterator `next()`). Defining a `done()` *method* on a non-iterator class is mildly misleading. A reader encountering `waiter.done` might first think of iteration. - **Suggestion:** Rename to `isTerminal()` / `isFinished()` (see - F4.1). + F1.1). --- -### 8. Generic field names losing meaning - -#### F8.1 — `primaryMetric: string` (MEDIUM) -- **Where:** `model.ts:34`. See F1.2. +### 5. Proto / architectural leaks ---- - -### 9. Untyped string for closed enum - -#### F9.1 — `forecastGranularity: string` (LOW) -- **Where:** `model.ts:30`. -- **Why flagged:** Type is `string` but JSDoc enumerates discrete - values like `'1 second'`, `'Hourly'`, `'Yearly'`. This is a - string-typed enum. Compare F1.2. -- **Suggestion:** Introduce a string-literal union type - `ForecastGranularity = '1 second' | '1 minute' | … | 'Yearly'`, - or document acceptable strings in JSDoc more rigorously. - ---- - -### 10. `*Path` fields contradicting type domain - -_None._ - ---- - -### 11. Proto / architectural leaks - -#### F11.1 — `ForecastingExperiment_State` — `model.ts:6` +#### F5.1 — `ForecastingExperiment_State` — `model.ts:6` - **Why flagged:** The `Foo_Bar` underscore identifier is a verbatim proto-generated nested-enum form (`ForecastingExperiment.State` in the original proto). The underscore form leaks the proto IDL @@ -253,79 +150,19 @@ _None._ comment "Proto-style nested enum name" makes the leak explicit. - **Category:** Proto architectural leak (nested-enum underscore form). - **Suggested:** `ExperimentState` (or `ForecastingExperimentState` - if the qualifier is kept per F-OVERLAP.1). + if the qualifier is kept). - **Rationale:** TS has no first-class nested-enum syntax matching proto's `Foo.Bar`. The flat camel/Pascal form removes the IDL artifact and the eslint-disable. --- -## Package overlap: `forecasting` vs `experiments` - -This SDK ships both `@databricks/sdk-forecasting` and an MLflow-style -`experiments` API in `@databricks/sdk-experiments` (verify path). -The forecasting concept of an "experiment" is distinct from MLflow's -generic experiment but uses the same term and the same ID name. - -### F-OVERLAP.1 — `ForecastingExperiment` vs MLflow `Experiment` - (MEDIUM) -- **Why flagged:** Naive autocomplete on "Experiment" surfaces both - types. The forecasting experiment is a - *long-running training job* tracked by AutoML; the MLflow - experiment is a *grouping* of runs. Semantically very different. -- **Suggestion:** Keep `ForecastingExperiment` (do not drop the - qualifier from the type, despite F5.1 above) to maintain - disambiguation. Or, namespace this package's types under - `forecasting.Experiment` if the package adopts nested exports. - ---- - ## Summary table | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Vague / generic | 3 (1 acceptable note) | -| 2 | Redundant enum prefixes | 0 | -| 3 | Acronym casing | 0 | -| 4 | Misleading names | 2 | -| 5 | Overly verbose | 5 | -| 6 | Go-style `Waiter` pattern | 1 | -| 7 | Reserved-word collisions | 1 | -| 8 | Generic field names | 1 | -| 9 | Untyped string for closed enum | 1 | -| 10 | `*Path` fields contradicting domain | 0 | -| 11 | Proto / architectural leaks | 1 | -| OVERLAP | forecasting vs experiments | 1 | - ---- - -## Top renames (recommended order) - -1. **F4.2 / F5.4:** Rename - `createForecastingExperimentWaiter` to - `startForecastingExperiment` (or `createAndWait…`) to remove the - "create" verb overload. Rename `CreateForecastingExperimentWaiter` - class to `ForecastingExperimentRun` or `…Operation` (F5.3 / F6.1). -2. **F4.1 / F7.1:** Rename waiter `done()` method to - `isTerminal()` (or `isDone()`) to signal that it is a - server-poll predicate, not iterator state. -3. **F1.2 / F9.1:** Introduce string-literal union types for - `primaryMetric` and `forecastGranularity`. Improves - discoverability and type safety. -4. **F5.1 / F5.2:** Drop the redundant `Forecasting` token from - type names where the package qualifier already conveys domain - (`ForecastingExperiment` → `Experiment`, - `CreateForecastingExperimentRequest` → `CreateExperimentRequest`, - etc.) — subject to the cross-package conflict noted in - F-OVERLAP.1. - ---- - -## Notes / out-of-scope - -- All findings above relate to **generated** code. Code-base rule: - "Code generated from API definition by Databricks SDK Generator. - DO NOT EDIT." The fixes belong upstream in the generator and - spec. This audit is a backlog for that generator. -- This package has no `tests/` directory (verified by repo - structure check), so the audit does not cover test naming. +| 1 | Misleading names | 2 | +| 2 | Overly verbose | 5 | +| 3 | Go-style `Waiter` pattern | 1 | +| 4 | Reserved-word collisions | 1 | +| 5 | Proto / architectural leaks | 1 | diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index bc092130..6e9244f6 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -1,175 +1,45 @@ # Naming Audit: `functions` package (v1) -**Package path:** `/home/parth.bansal/sdk-js/packages/functions/` -**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` +**Package path:** `/home/parth.bansal/sdk-js/packages/uc/functions/` +**Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` **Domain:** Unity Catalog Functions (SQL / Python UDFs and UDTFs). -**Total weird names flagged:** 38 (0 fixed, 38 still present after rescan on 2026-05-26 post regen #156). - ---- - -## Summary - -The `functions` package surfaces five UC function operations -(`createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, -`updateFunction`) plus a paginated iterator. The model layer mirrors -the Go SDK 1:1, so most issues are inherited from the upstream -definitions. The most pervasive problems are: (1) cryptic -single-letter enum variants (`S`, `IN`, `DEFINER`); (2) the cryptic -`fullNameArg` path-parameter field (a generator artifact whose `Arg` -suffix has no meaning on the TS surface); and (3) proto-architectural -leaks such as `Parent_Child` underscore-typed enums and the -`$case`/`value` ts-proto oneof envelope. +**Total weird names flagged:** 14 (rescanned 2026-06-02 after the API +regeneration and LRO/waiter refactor). --- ## Findings -### 1. Vague / generic names - -_None._ - ---- - -### 2. Cryptic single-letter / two-letter enum variants - -#### 2.1 `FunctionInfo_ParameterStyle.S` (model.ts:42-44) -Single-variant enum with the variant `S`. The doc on the type-using -field says `**S** is the value for SQL.` So `S` is *the* SQL -parameter style. The single-letter variant is cryptic; even if it -preserves wire compatibility, the TypeScript surface should expose -`SQL` (and let the marshal layer translate to `S` on the wire). -See also §3.1. +### 1. Single-variant enums surfaced as full enum types -#### 2.2 `FunctionInfo_SecurityType.DEFINER` (model.ts:59-61) +#### 1.1 `FunctionInfo_SecurityType.DEFINER` (model.ts:59-61) Single-variant enum with `DEFINER`. The single-valued switch is surfaced as a full enum type; the variant itself is meaningful (SQL `SECURITY DEFINER` clause) but the TS-side ergonomics suffer. --- -### 3. Cryptic abbreviations - -#### 3.1 `FunctionInfo_ParameterStyle.S` (model.ts:43) -A bare letter `S` whose only documented purpose is "the value for -SQL". Cryptic — preserve wire compatibility in the marshal layer and -expose `SQL` as the TS variant. See also §2.1. - -#### 3.2 `FunctionParameterMode.IN` (model.ts:32-34) -Bare two-letter variant `IN`. Comes from SQL's `IN`/`OUT`/`INOUT` -parameter modes; without that context, the variant is cryptic. A -consumer reading `parameterMode === FunctionParameterMode.IN` cannot -intuit "input parameter" without prior SQL exposure. - -#### 3.3 `fullNameArg` (model.ts:152, 281, 324) -Used as the function name path-parameter on `DeleteFunctionRequest`, -`GetFunctionRequest`, and `UpdateFunctionRequest`. The `Arg` suffix -is jargon from the Go generator distinguishing path arguments from -request-body fields with the same key. TypeScript callers have no -need for this distinction — the field is the function's -fully-qualified name. See also §8.1 and §7.3. - ---- - -### 4. Acronym casing inconsistencies (SQL, UDF, UDTF, JSON) - -#### 4.1 `FunctionInfo_SqlDataAccess` (model.ts:64) vs field `sqlDataAccess` (model.ts:98, 207, 346) -`SqlDataAccess` (PascalCase for the type) uses `Sql` as a word; -`sqlDataAccess` (camelCase field) uses `sql` lowercase. Both are -internally consistent for camelCase/PascalCase rules, but the -Databricks codebase elsewhere uses uppercase `SQL` (e.g. `sqlPath` -field, comments saying "SQL"). Google TS style guide treats SQL as a -three-letter acronym → `Sql`/`sql` is valid. Flagged for awareness. - -#### 4.2 `sqlPath` field (model.ts:112, 221, 360) -Consistent with §4.1: `sqlPath` rather than `sQLPath`. OK by Google -TS rules. - -#### 4.3 `typeJson` field (model.ts:254) -Field name `typeJson`. JSON is treated as `Json` per Google TS rules. -Consistent. - -#### 4.4 "UDF" / "UDTF" never appear in identifiers -The package is *Unity Catalog Functions* — it covers both UDFs and -UDTFs (table-valued functions). Neither acronym appears in any -identifier or doc comment. The distinction is encoded in the -`routineBody` + `returnParams` combination, which is non-obvious. -Not a renaming issue per se, but a discoverability problem worth -flagging. - ---- - -### 5. Misleading names +### 2. Misleading names -#### 5.1 `specificName` reserved-for-future-use (model.ts:104, 213, 352) +#### 2.1 `specificName` reserved-for-future-use (model.ts:104, 213, 351) Doc: "Specific name of the function; Reserved for future use." A field whose name promises specificity and whose docs admit it's unused is a future trap. Better to omit until it does something. --- -### 6. Reserved-word collisions +### 3. Reserved-word collisions -#### 6.1 `options` parameter on every client method -(client.ts:85, 120, 164, 208, 256, 281) — the second parameter is +#### 3.1 `options` parameter on every client method +(client.ts:82, 117, 158, 202, 247, 272) — the second parameter is named `options` and shadows the marshal schema's `options`-style -metadata patterns. Not a collision in this package specifically but -consistent with the catalogs audit (§10.1). - ---- - -### 7. Duplicate concepts - -#### 7.1 `CreateFunction`, `UpdateFunctionRequest`, and `FunctionInfo` share ~28 fields verbatim -(model.ts:76-137, 185-246, 322-385) -Three types with almost-identical shapes and identical doc strings. -Generator artifact, but means any rename of, say, `routineBody`, -must happen three times — and the divergences between Create / Update -/ Info are easy to miss. Recommend basing `CreateFunction` and -`UpdateFunctionRequest` on `Partial` (or a shared base -interface). - -#### 7.2 `fullName` vs `catalogName` + `schemaName` + `name` (model.ts:78-82, 124, 187-191, 233, 326-330, 372) -A `FunctionInfo` has all four: a top-level `name` (relative to -schema), parent `catalogName` and `schemaName`, and `fullName` -(the concatenation). Three pieces of data; four fields. A caller -setting one and not the others leaves the type in an inconsistent -state, and there's no documentation on which is authoritative on -`Create*` / `Update*`. See also §9.4. - -#### 7.3 `dataType` vs `fullDataType` (model.ts:86-88, 195-197, 334-336) -- `dataType: ColumnTypeName` — the enum form. -- `fullDataType: string` — "Pretty printed function data type." - -The pretty-printed form is presumably a function of the enum plus -any precision/scale/interval. Two fields encoding the same datum in -two representations. - -#### 7.4 `name` vs `fullNameArg` on `UpdateFunctionRequest` -`UpdateFunctionRequest` has *both* `fullNameArg` (the existing -function identifier, used in the URL path) and `name` (the new -desired name of the function, used in the body). See §9.1. - ---- - -### 8. Verb-tense inconsistency - -#### 8.1 Client methods are well-aligned: `createFunction`, `deleteFunction`, `getFunction`, `listFunctions`, `updateFunction`. No tense issues. - -No verb-tense inconsistencies found across the package. +metadata patterns. --- -### 9. Go / Java-style names +### 4. Go / Java-style names -#### 9.1 `Client` class name (client.ts:44) -Bare `Client` (rather than `FunctionsClient`) is a Go idiom: package -qualifies the type. JS consumers commonly import as -`import {Client} from '@databricks/sdk-functions/v1'` and have to -alias. Package-wide convention; flagged for consistency. - -#### 9.2 `fullNameArg` (model.ts:152, 281, 324) — Go generator naming. See §3.3. - -#### 9.3 `Dependency.value.$case` discriminated union encoding (model.ts:165-170) +#### 4.1 `Dependency.value.$case` discriminated union encoding (model.ts:165-170) The `$case` discriminator with `value`-keyed payload is a ts-proto serialiser idiom. TS-native discriminated unions usually keep the discriminator at the top level (`{type: 'function', function: {…}}`) @@ -177,113 +47,20 @@ rather than wrapping in `value`. Functional, but visibly Go/proto. --- -### 10. Generic field names losing meaning - -#### 10.1 `name` is used twelve+ times across the model -(model.ts:78, 81, 83 within docs, 187, 190, 250, 326, 329, etc.) -The semantics shift: function name, parameter name, catalog name, -schema name, etc. — but the field is consistently `name`. Combined -with `fullName`, `fullNameArg`, `functionFullName`, `tableFullName`, -`externalName`, `specificName`, the surface area of "name" fields is -huge. See also §7.2. - -#### 10.2 `properties` (model.ts:118, 227, 366) -"JSON-serialized key-value pair map, encoded (escaped) as a string." -The field is `string`, despite the name promising a structured map. -A consumer reading the type sees `properties?: string` and has to -manually `JSON.parse`. Either name it `propertiesJson` or type it -as `Record` with marshal-layer translation. - ---- - -### 11. Field contradicting type domain +### 5. Field contradicting type domain -#### 11.1 `UpdateFunctionRequest` has `fullNameArg` *and* `name` (model.ts:324, 326) -- `fullNameArg` — the existing function's fully-qualified identifier - (path param). -- `name` — the function name, body field (the new desired name?). - -A caller staring at this struct cannot intuit which to set, in what -combination, or whether `name` is the *new* name or the *current* -name (the catalogs package answers this question differently with -`newName` — but `functions` lacks `newName` entirely, leaving the -caller without a renaming primitive at all, or with an ambiguous -`name` field). See also §7.4. - -#### 11.2 `CreateFunction` contains read-only output fields +#### 5.1 `CreateFunction` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `functionId`, `browseOnly` (model.ts:126-136). These are server-populated; a creator setting them is at best ignored. The type's domain is "create request body" but its shape contradicts -that. Mirror issue in `UpdateFunctionRequest` (model.ts:374-384). - -#### 11.3 `DeleteFunctionRequest.fullNameArg` — see §3.3. - -#### 11.4 `FunctionInfo.fullName` vs `name` / `catalogName` / `schemaName` -(model.ts:187-191, 233) -On `FunctionInfo`, all four are present; for *catalogs* a `fullName` -is redundant with `name`, but for *functions* `fullName` is -`catalog_name.schema_name.function_name`. The doc comment -underscores them as if they're literal placeholders. The naming is -acceptable but the redundancy invites inconsistent state. - ---- - -### 12. Inconsistent action verbs - -Method verbs in `Client`: `createFunction`, `deleteFunction`, -`getFunction`, `listFunctions`, `updateFunction`. Verbs are -consistent: standard CRUD. No `fetch…` / `retrieve…` / `read…` -outliers. No issues found. +that. Mirror issue in `UpdateFunctionRequest` (model.ts:373-383). --- -### 13. Underspecified IDs - -#### 13.1 `metastoreId` & `functionId` — distinct domains, same shape -Both `string`, both undocumented for format, both server-assigned. -A consumer cannot tell them apart from the types. - ---- +### 6. Proto-architectural-leak naming -## Additional / cross-cutting observations - -### A. `fullNameArg` URL substitution silently allows empty string -(client.ts:122, 166, 283) — `${req.fullNameArg ?? ''}` — if -`fullNameArg` is undefined, the URL silently becomes -`/api/2.1/unity-catalog/functions/` and the request will fail on the -server. The naming (`fullNameArg`) and the substitution behaviour -together hide what should be a required parameter. Worth surfacing -via a non-optional type or a typed assertion. - -### B. `marshalUpdateFunctionRequestSchema` serialises `fullNameArg` into the body -(model.ts:799) `fullNameArg` is a path parameter — but the marshal -schema produces a JSON field `full_name_arg`. Either the server -tolerates the extra field or this is a bug. The `Arg` suffix lets -the bug hide. - -### C. Package-name collision with JavaScript reserved word -The package is named `@databricks/sdk-functions` and the npm -workspace path is `packages/functions/`. `function` is a JS reserved -word; `functions` is not, but the proximity is jarring. Importers -will often write -`import * as functions from '@databricks/sdk-functions/v1'` which -sets up `functions.createFunction(…)` — the local binding `functions` -shadows nothing, but the combination of the package name and the -`Dependency.value.$case === 'function'` pattern creates a vocabulary -where "function" is overloaded. - -### D. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` -The most extreme case of a single-purpose API surface: a long enum -type holding a one-letter variant, only ever set to `S`, marshaled -as the JSON string `"S"`. Three layers of indirection for a constant. -See §2.1, §3.1. - ---- - -## 14. Proto-architectural-leak naming - -### 14.1 `FunctionInfo_ParameterStyle` — model.ts:42 +#### 6.1 `FunctionInfo_ParameterStyle` — model.ts:42 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. @@ -293,71 +70,28 @@ Rationale: TypeScript enums do not need parent-qualifying via underscore. The leak exposes the upstream proto schema's nested-type layout to TS consumers. -### 14.2 `FunctionInfo_RoutineBody` — model.ts:47 +#### 6.2 `FunctionInfo_RoutineBody` — model.ts:47 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. Suggested: `RoutineBody`. -Rationale: Same as 14.1. +Rationale: Same as 6.1. -### 14.3 `FunctionInfo_SecurityType` — model.ts:59 +#### 6.3 `FunctionInfo_SecurityType` — model.ts:59 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. Suggested: `SecurityType`. -Rationale: Same as 14.1. +Rationale: Same as 6.1. -### 14.4 `FunctionInfo_SqlDataAccess` — model.ts:64 +#### 6.4 `FunctionInfo_SqlDataAccess` — model.ts:64 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. Suggested: `SqlDataAccess`. -Rationale: Same as 14.1. +Rationale: Same as 6.1. -### 14.5 `DeleteFunctionRequest_Response` — model.ts:158 -Why: `Request_Response` underscore-paired identifier mirrors proto -nested-response-message convention (`Foo_Response`). The lint comment -explicitly notes "Proto-style nested message name." -Category: Proto suffix/infix + `Foo_PublicRequest`-style paired naming. -Suggested: `DeleteFunctionResponse` (or omit entirely — it is an -empty object). -Rationale: TS has no nested-message concept; the underscore-paired -naming surfaces the upstream proto schema to consumers. - -### 14.6 `ListFunctionsRequest_Response` — model.ts:306 -Why: `Request_Response` underscore-paired identifier mirrors proto -nested-response-message convention. -Category: Proto suffix/infix + `Foo_PublicRequest`-style paired naming. -Suggested: `ListFunctionsResponse`. -Rationale: Same as 14.5. - -### 14.7 `unmarshalDeleteFunctionRequest_ResponseSchema` — model.ts:406 -Why: Schema constant inherits the `Request_Response` proto-nested -underscore identifier; verb-prefixed schema name (`unmarshal*Schema`) -on top further surfaces serialisation-layer concerns at the package -surface. -Category: Proto suffix/infix. -Suggested: `unmarshalDeleteFunctionResponseSchema`. -Rationale: Same as 14.5. - -### 14.8 `unmarshalListFunctionsRequest_ResponseSchema` — model.ts:561 -Why: Schema constant inherits the `Request_Response` proto-nested -underscore identifier. -Category: Proto suffix/infix. -Suggested: `unmarshalListFunctionsResponseSchema`. -Rationale: Same as 14.5. - -### 14.9 `fullNameArg` — model.ts:152, 281, 324 -Why: The `Arg` suffix is a Go SDK generator artifact distinguishing -path-parameter fields from same-keyed body fields; it has no meaning -on the TS surface. -Category: Generator/codegen artifact (proto-adjacent). -Suggested: `fullName` (drop `Arg`). -Rationale: TS consumers do not see the path/body split; the suffix -exposes a generator implementation detail. Already cross-referenced -in §3.3, §9.2; re-flagged here as a proto-architectural leak. - -### 14.10 `Dependency.value.$case` discriminated-union shape — model.ts:165-170 +#### 6.5 `Dependency.value.$case` discriminated-union shape — model.ts:165-170 Why: `{$case: 'foo'; foo: T}` is the ts-proto serialiser's encoding for oneof fields; native TS discriminated unions normally use a top-level discriminator key, not a `value`-wrapped `$case` envelope. @@ -366,45 +100,39 @@ Suggested: Flatten to `{type: 'function'; function: FunctionDependency} | ...` at the top level. Rationale: The `$case` discriminator key and the `value`-wrapped envelope visibly reflect proto oneof semantics. Already noted in -§9.3; re-flagged here as a proto-architectural leak. +§4.1; re-flagged here as a proto-architectural leak. --- -## File / line index for fast lookup +## Observations -| Identifier | Location | Finding | -| -------------------------------------------------------- | --------------------- | ------- | -| `FunctionParameterMode` | model.ts:32 | 3.2 | -| `FunctionParameterMode.IN` | model.ts:32-34 | 3.2 | -| `FunctionInfo_ParameterStyle.S` | model.ts:43 | 2.1, 3.1 | -| `FunctionInfo_SecurityType.DEFINER` | model.ts:59-61 | 2.2 | -| `FunctionInfo_SqlDataAccess` | model.ts:64 | 4.1 | -| `CreateFunction` | model.ts:76 | 7.1, 11.2 | -| `CreateFunction.specificName` | model.ts:104 | 5.1 | -| `CreateFunction.fullName` | model.ts:124 | 7.2, 11.4 | -| `CreateFunction.functionId / metastoreId / createdAt / etc.` | model.ts:122-136 | 11.2, 13.1 | -| `DeleteFunctionRequest.fullNameArg` | model.ts:152 | 3.3, 9.2, 11.3 | -| `Dependency.value.$case` | model.ts:165 | 9.3 | -| `FunctionInfo` | model.ts:185 | 7.1 | -| `FunctionInfo.specificName` | model.ts:213 | 5.1 | -| `FunctionInfo.properties` | model.ts:227 | 10.2 | -| `FunctionInfo.fullName` | model.ts:233 | 7.2, 11.4 | -| `FunctionInfo.functionId` | model.ts:243 | 13.1 | -| `FunctionParameterInfo.name` | model.ts:250 | 10.1 | -| `FunctionParameterInfo.typeJson` | model.ts:254 | 4.3 | -| `GetFunctionRequest.fullNameArg` | model.ts:281 | 3.3, 9.2 | -| `UpdateFunctionRequest` | model.ts:322 | 7.1, 7.4, 11.1, 11.2 | -| `UpdateFunctionRequest.fullNameArg / name` | model.ts:324, 326 | 3.3, 7.4, 11.1 | -| `UpdateFunctionRequest.fullName` | model.ts:372 | 7.2, 11.4 | -| `Client` (bare name) | client.ts:44 | 9.1 | -| `${req.fullNameArg ?? ''}` URL substitution | client.ts:122, 166, 283 | A | - ---- +### A. `fullNameArg` URL substitution silently allows empty string +(client.ts:119, 160, 274) — `${req.fullNameArg ?? ''}` — if +`fullNameArg` is undefined, the URL silently becomes +`/api/2.1/unity-catalog/functions/` and the request will fail on the +server. The naming (`fullNameArg`) and the substitution behaviour +together hide what should be a required parameter. Worth surfacing +via a non-optional type or a typed assertion. -## Recommended priority order +### B. `marshalUpdateFunctionRequestSchema` serialises `fullNameArg` into the body +(model.ts:802) `fullNameArg` is a path parameter — but the marshal +schema produces a JSON field `full_name_arg`. Either the server +tolerates the extra field or this is a bug. The `Arg` suffix lets +the bug hide. -1. **Fix `fullNameArg` / `name` confusion on `UpdateFunctionRequest`** — there is no `newName` field, so `name`'s role (current vs new) is undocumented. (§11.1, §3.3) -2. **Expose `SQL` / spell-out variants for cryptic single-letter enums** (`FunctionInfo_ParameterStyle.S`, `FunctionParameterMode.IN`, `FunctionInfo_SecurityType.DEFINER`). (§2.1, §2.2, §3.1, §3.2) -3. **Strip read-only fields from `CreateFunction` / `UpdateFunctionRequest`.** (§11.2) +### C. Package-name proximity to JavaScript reserved word +The package is named `@databricks/sdk-uc-functions` and the npm +workspace path is `packages/uc/functions/`. `function` is a JS reserved +word; `functions` is not, but the proximity is jarring. Importers +will often write +`import * as functions from '@databricks/sdk-uc-functions/v1'` which +sets up `functions.createFunction(…)` — the local binding `functions` +shadows nothing, but the combination of the package name and the +`Dependency.value.$case === 'function'` pattern creates a vocabulary +where "function" is overloaded. ---- +### D. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` +The most extreme case of a single-purpose API surface: a long enum +type holding a one-letter variant, only ever set to `S`, marshaled +as the JSON string `"S"`. Three layers of indirection for a constant. +See §6.1. diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index c5931f45..3aeb1e09 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -2,32 +2,31 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 -**Inferred domain:** Databricks "Genie" — natural-language data interface. The unit of organisation is a `GenieSpace` (a workspace scoped to a warehouse + a set of dataset/instructions); inside a space, users `startConversation` and exchange `Message`s; messages produce `GenieAttachment`s (text / SQL query / suggested follow-up questions); SQL attachments execute against the warehouse and yield `Result`s (`StatementResponse` shapes copied from the statement-execution API). The package also exposes "Eval" — a benchmarking flow (`EvalRun` → `EvalResult` → `EvalResultDetails` with LLM-judge scoring). -**Total weird names flagged:** 35 +**Total weird names flagged:** 18 ## Summary | Severity | Count | | --- | --- | -| High | 14 | -| Medium | 9 | -| Low | 9 | -| Observation | 3 | +| High | 6 | +| Medium | 5 | +| Low | 6 | +| Observation | 1 | ## High severity -### 1. Method naming wildly inconsistent: 28 of 30 methods are `genieXxx`, 2 are bare — `src/v1/client.ts:131,1038` -- **Why weird:** `client.ts` exposes 30 public methods. 28 are prefixed `genie` (e.g. `genieCreateConversationMessage`, `genieGetSpace`, `genieListSpaces`, `genieTrashSpace`). Two are not: `createSpace` (line 131) and `updateSpace` (line 1038). Reader calling `client.createSpace(...)` then trying `client.deleteSpace(...)` discovers the delete equivalent is named `genieTrashSpace(...)`. The "trash" method name is also inconsistent (see #2). +### 1. Method naming wildly inconsistent: 28 of 30 methods are `genieXxx`, 2 are bare — `src/v1/client.ts:133,1121` +- **Why weird:** `client.ts` exposes 30 public methods. 28 are prefixed `genie` (e.g. `genieGetSpace`, `genieListSpaces`, `genieTrashSpace`). Two are not: `createSpace` (line 133) and `updateSpace` (line 1121). Reader calling `client.createSpace(...)` then trying `client.deleteSpace(...)` discovers the delete equivalent is named `genieTrashSpace(...)`. The "trash" method name is also inconsistent (see #2). - **Category:** 17 (inconsistent action verbs / prefix), 6 (misleading — autocomplete shows two naming families). - **Suggested name:** Pick one and apply uniformly. Either drop the `genie` prefix everywhere (the package is already `@databricks/sdk-genie` — the prefix is tautological) or keep it everywhere (`genieCreateSpace`, `genieUpdateSpace`). Strongly prefer the former. - **Rationale:** Every method in the client is on a Genie `Client` imported from `@databricks/sdk-genie`. Prefixing every method with `genie` is type-suffix tautology — `client.genieListSpaces()` is no clearer than `client.listSpaces()`. The current half-prefixed surface is the worst of both options. -### 2. `genieTrashSpace` is the only delete-style method named `Trash` — `src/v1/client.ts:1019` +### 2. `genieTrashSpace` is the only delete-style method named `Trash` — `src/v1/client.ts:1099` - **Why weird:** All other delete methods are `genieDeleteX` (`genieDeleteConversation`, `genieDeleteConversationMessage`). The space delete is `genieTrashSpace` and the request type is `GenieTrashSpaceRequest`. JSDoc says "Move a Genie Space to the trash" — i.e. it is a soft delete, not a destructive one — but the name still breaks the `delete*` pattern. - **Category:** 17 (inconsistent action verb), 14 (Go/Java-style "trash" verb is uncommon in JS SDKs). - **Suggested name:** `genieDeleteSpace` (matches the other deletes; document the soft-delete semantics in JSDoc) or, if soft-delete needs to be explicit, mirror it on the messages too (`genieTrashConversationMessage`). - **Rationale:** Inconsistency forces every reader to learn the exception. The "soft delete" semantic can be conveyed by docs without leaking into the verb. -### 3. `genieExecuteMessageAttachmentQuery` vs `genieGetMessageAttachmentQueryResult` vs `genieGenerateDownloadFullQueryResult` — three different verbs for retrieving the same data — `src/v1/client.ts:308,564,396` +### 3. `genieExecuteMessageAttachmentQuery` vs `genieGetMessageAttachmentQueryResult` vs `genieGenerateDownloadFullQueryResult` — three different verbs for retrieving the same data — `src/v1/client.ts:328,605,422` - **Why weird:** The package has at least four "get the SQL result" entry points (`Execute`, `Get`, `Generate`, plus `genieGetQueryResultByAttachment`/`genieGetMessageQueryResult` deprecated aliases). Each uses a different verb stem. `Execute` re-runs the query; `Get` reads the result; `Generate` initiates a download — but the user has to read each docstring to learn that. - **Category:** 17 (inconsistent action verbs), 7 (overly verbose). - **Suggested name:** Group with verb pairs: `runMessageAttachmentQuery` (re-execute) / `getMessageAttachmentQueryResult` (read) / `startMessageAttachmentDownload` + `getMessageAttachmentDownload` (download flow). @@ -39,173 +38,83 @@ - **Suggested name:** `GenieRoom`, `GenieAgent`, `GenieDeployment`, or at minimum a JSDoc on the type explaining what a "space" *is* (warehouse + datasets + instructions). If "Space" is the Databricks product-marketing term, document it inline. - **Rationale:** This is the package's central concept. Letting it stand on a single word that means "container" is a documentation gap as much as a naming bug. -### 5. Statement-execution types duplicated wholesale into genie — `src/v1/model.ts:5-30,33-531,543-548,754-884,1589-1694` -- **Why weird:** 15+ types are byte-for-byte copies of types in the `statementexecution`, `sql` and `apierror` packages: `ColumnTypeName` (enum, 28 values), `ErrorCode` (enum, 80 values, with line-for-line JSDoc), `Format` (enum), `ChunkInfo`, `ColumnInfo`, `ColumnMask`, `DatabricksServiceExceptionProto`, `ExternalLink`, `ExternalLink_HttpHeadersEntry`, `PolicyFunctionArgument`, `Result`, `ResultData`, `ResultManifest`, `Schema`, `StatementResponse`, `StatementStatus`, `StatementStatus_State`. The file even copies the Google-Well-Known-Types (`Struct`, `Value`, `ListValue`, `MapStringValueEntry`). -- **Category:** 12 (duplicate concept across packages). -- **Suggested name:** Import from `@databricks/sdk-databricks/statementexecution` (or wherever the originals live). If the generator can't yet cross-link, mark each duplicate `@internal` or move them to a shared internal module. -- **Rationale:** A consumer who imports both `@databricks/sdk-genie` and `@databricks/sdk-sql` ends up with two structurally-identical-but-nominally-distinct `StatementResponse` types — runtime values are not assignable to each other in strict mode. This is the biggest correctness footgun in the package. - -### 6. `ErrorCode` enum (80 values, ~60% deprecated) duplicated from apierror — `src/v1/model.ts:33-531` -- **Why weird:** ErrorCode is copied verbatim from the SDK's apierror codes package. Of the 80 values, comments explicitly mark ~50 as deprecated. The enum is only referenced via the copied `DatabricksServiceExceptionProto` type, which is itself unused by any Genie method (the SDK uses `ApiError.fromHttpError` in `utils.ts:88`). -- **Category:** 12 (duplicate concept), 18 (long enum values — `MAX_NOTEBOOK_SIZE_EXCEEDED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, `RESOURCE_DOES_NOT_EXIST`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`). -- **Suggested name:** Import from `@databricks/sdk-databricks/apierror/codes`. Remove the local copy. -- **Rationale:** 500 lines of code duplicate a separate package. Maintenance hazard: deprecation removals or additions to the canonical enum will diverge silently. - -### 7. `ScoreReason` enum mixes three prefix families and keeps six deprecated values inline — `src/v1/model.ts:584-613` -- **Why weird:** 22 values fall into three groups: (a) bare (`EMPTY_RESULT`, `SINGLE_CELL_DIFFERENCE`, `EMPTY_GOOD_SQL`, `COLUMN_TYPE_DIFFERENCE`); (b) `RESULT_*` (`RESULT_MISSING_ROWS`, `RESULT_EXTRA_ROWS`, `RESULT_MISSING_COLUMNS`, `RESULT_EXTRA_COLUMNS`); (c) `LLM_JUDGE_*` (16 values). `EMPTY_RESULT` and `EMPTY_GOOD_SQL` are semantically `RESULT_*` reasons but lack the prefix family. Six `LLM_JUDGE_*` values are deprecated and live beside the new ones with no visual separation. -- **Category:** 17 (inconsistent grouping — same family, different prefixes), 12 (deprecated values inline with active ones). -- **Suggested name:** Move `EMPTY_RESULT` / `EMPTY_GOOD_SQL` into the `RESULT_*` family for internal consistency. Separate deprecated values into a dedicated comment block (or split into two enums) so autocomplete groups them. -- **Rationale:** The current ordering makes it hard for a reader to tell which values are deterministic vs LLM-judge and which are still active vs deprecated. - -### 8. `MessageError_Type` enum — 60 values, all suffixed `_EXCEPTION` — `src/v1/model.ts:648-713` -- **Why weird:** 60 values, almost every one ends in `_EXCEPTION` (`UNEXPECTED_REPLY_PROCESS_EXCEPTION`, `GENERIC_CHAT_COMPLETION_EXCEPTION`, `CONTEXT_EXCEEDED_EXCEPTION`, …). The few that don't are inconsistent: `STOP_PROCESS_DUE_TO_AUTO_REGENERATE`, `UNKNOWN_AI_MODEL`, `NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE`, plus `MESSAGE_ATTACHMENT_TOO_LONG_ERROR` (suffix `_ERROR` not `_EXCEPTION`), `DESCRIBE_QUERY_UNEXPECTED_FAILURE` / `DESCRIBE_QUERY_TIMEOUT` / `DESCRIBE_QUERY_INVALID_SQL_ERROR` (different verbs). The `_EXCEPTION` suffix is also Java vocabulary, not TS. -- **Category:** 2 (redundant suffix — every value already lives under `MessageError_Type`), 14 (Java-style `Exception` vocabulary in TS), 18 (long values — `INTERNAL_CATALOG_ASSET_CREATION_UNSPECIFIED_EXCEPTION` is 52 chars), 17 (inconsistent suffix). -- **Suggested name:** Drop `_EXCEPTION` from every value: `UnexpectedReplyProcess | GenericChatCompletion | ContextExceeded | …`. Pick one of `_ERROR` / `_EXCEPTION` / nothing. -- **Rationale:** This enum is 67 lines long; cleaning the suffix removes 600+ characters and makes the values readable in autocomplete. - -### 9. Multiple `*_UNSPECIFIED` enum sentinels prefixed by the enum's own name — `src/v1/model.ts:534,544,551,558,565,581,585,617,634,649,745` -- **Why weird:** 11 enums use a `XXX_UNSPECIFIED` sentinel where `XXX` is the enum's name: `EVALUATION_STATUS_TYPE_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `GENIE_FEEDBACK_RATING_UNSPECIFIED`, `NULL_VALUE`, `SCORE_REASON_UNSPECIFIED`, `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED`, `THOUGHT_TYPE_UNSPECIFIED`, `TYPE_UNSPECIFIED` (inside `MessageError_Type`), `STATE_UNSPECIFIED` (inside `StatementStatus_State`). Proto2 forces this; TS does not need it because the enum's type acts as the namespace. -- **Category:** 2 (redundant enum prefix), 18 (long enum values). -- **Suggested name:** `Unspecified` (drop the prefix). Or omit entirely if TS-undefined can stand in for proto-unspecified. -- **Rationale:** The package will get cleaner immediately; the wire string can stay the same. - -### 10. `TextAttachmentPurpose` enum has only 2 values — collapse to boolean — `src/v1/model.ts:616-619` -- **Why weird:** Two values: `TEXT_ATTACHMENT_PURPOSE_UNSPECIFIED` and `FOLLOW_UP_QUESTION`. A two-member enum where one member is the sentinel adds nothing over a boolean. -- **Category:** 12 (overspecified — enum used where a boolean would do). -- **Suggested name:** Drop the enum; replace with `isFollowUp?: boolean`. -- **Rationale:** Two-member enums where one is `_UNSPECIFIED` are often better collapsed to an optional boolean. - -### 11. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:533` +### 5. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:533` - **Why weird:** The type is named `EvaluationStatusType`. Every enum is by definition a "type", so the suffix adds nothing. Peer enums in the same file use bare-noun names (`ScoreReason`, `ThoughtType` — though `ThoughtType` is itself debatable, `Format`, `MessageStatus_MessageStatus`). - **Category:** 8 (redundant `Type` suffix on enum name). - **Suggested name:** `EvaluationStatus`. - **Rationale:** This enum is exposed on `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus`; trimming the suffix shortens both call sites without losing information. -### 12. `GenieGetQueryResultByAttachment` / `GenieGetMessageQueryResult` / `GenieGetMessageAttachmentQueryResult` — 3 names for the same operation — `src/v1/client.ts:564,592,620` -- **Why weird:** Three deprecated/active methods all return `GenieGetMessageQueryResultResponse` and all read the SQL result for a message. The naming hierarchy is `Message.QueryResult` vs `MessageAttachment.QueryResult` vs `QueryResult.byAttachment` — three different mental models. Two are deprecated but still exported and named in the surface. -- **Category:** 17 (inconsistent action verb / structure), 7 (overly verbose), 12 (duplicate concept). -- **Suggested name:** Keep the single canonical method (`getMessageAttachmentQueryResult` → `getMessageAttachmentResult`), mark the others `@deprecated` and consider hiding them from the typed surface (re-export only from `/legacy`). -- **Rationale:** Three names with overlapping suffixes is the classic generator-emitting-everything problem. - -### 13. `GenieEvalAssessment` / `GenieEvalResponseType` — only the sentinel carries the long prefix — `src/v1/model.ts:550,557` -- **Why weird:** `GenieEvalAssessment` has values `GENIE_EVAL_ASSESSMENT_UNSPECIFIED`, `GOOD`, `BAD`, `NEEDS_REVIEW`. Only the sentinel carries the prefix. `GenieEvalResponseType` likewise: `GENIE_EVAL_RESPONSE_TYPE_UNSPECIFIED`, `TEXT`, `SQL`. Within one enum two naming conventions are present. -- **Category:** 17 (inconsistent prefix within one enum). -- **Suggested name:** Drop the prefix on the sentinel; align with the bare-name convention used by the rest of the values. -- **Rationale:** Inconsistency inside a single enum is more jarring than a uniform convention either way; this is the proto-style "only the sentinel is prefixed" pattern. - -### 14. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:828` -- **Why weird:** The type name stacks three architectural-layer words: `Service` (server-side tier), `Exception` (Java vocabulary), and `Proto` (wire-format suffix). None of these belong in a public TS SDK surface — the SDK exposes errors, not Java exceptions, and not proto messages. JSDoc reinforces the leak: "Serialization format for DatabricksServiceException. Note the definition of this message should be in sync with DatabricksServiceExceptionWithDetailsProto defined in /api-base/proto/exception_with_details.proto". The companion schema is `unmarshalDatabricksServiceExceptionProtoSchema` (line 1843), propagating the leak. +### 6. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:828` +- **Why weird:** The type name stacks three architectural-layer words: `Service` (server-side tier), `Exception` (Java vocabulary), and `Proto` (wire-format suffix). None of these belong in a public TS SDK surface — the SDK exposes errors, not Java exceptions, and not proto messages. JSDoc reinforces the leak: "Serialization format for DatabricksServiceException. Note the definition of this message should be in sync with DatabricksServiceExceptionWithDetailsProto defined in /api-base/proto/exception_with_details.proto". The companion schema is `unmarshalDatabricksServiceExceptionProtoSchema` (line 1854), propagating the leak. - **Category:** Proto-architectural-leak (`Proto` suffix, `Service` mid), 14 (Java-style `Exception` vocabulary in TS), 12 (duplicate concept — the SDK already has `ApiError`). - **Suggested name:** Delete the type and reuse `ApiError` from `@databricks/sdk-databricks/apierror`. If the wire-format shape must be kept locally, name it `ApiErrorPayload` or `WireError` and treat it as an internal marshal-time type, not a public export. -- **Rationale:** `Service`, `Exception`, and `Proto` are all backend implementation vocabulary that should never reach the user-facing SDK surface. The type is unused by any public method body (per finding #6), making the leak gratuitous. +- **Rationale:** `Service`, `Exception`, and `Proto` are all backend implementation vocabulary that should never reach the user-facing SDK surface. The type is unused by any public method body, making the leak gratuitous. ## Medium severity -### 15. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1483` +### 7. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1483` - **Why weird:** Request type for `genieStartConversation`. Name contains *both* `Conversation` and `Message`, but the body has only `spaceId` and `content` (`{ spaceId?: string; content?: string; }`). It is not a request to start a "conversation message" — it is a request to start a conversation by sending an initial message. Compare with `GenieStartConversationResponse` (no `Message` in the name). - **Category:** 6 (misleading — name suggests a compound entity that doesn't exist), 7 (overly verbose). - **Suggested name:** `StartConversationRequest` (matches the response). - **Rationale:** Reader has to parse the doc to learn what "ConversationMessage" means here. The companion response name (`GenieStartConversationResponse`) silently drops `Message` — internal inconsistency. -### 16. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:888` +### 8. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:888` - **Why weird:** `GenieAttachment.attachment` is a `{ $case: 'text' | 'query' | 'suggestedQuestions', … } | undefined` field. Reading `myAttachment.attachment.text` reads as "the attachment of the attachment", and the parent `GenieAttachment` also has a peer field `attachmentId`. The shape mixes the discriminator field with a flat id field. - **Category:** 15 (generic field name losing meaning). -- **Suggested name:** Hoist to top-level discriminated union: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. Or rename the field to `payload` / `body` / `content`. +- **Suggested name:** Hoist to a top-level discriminated union so the variant lives at the type level rather than under a nested same-named field: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. - **Rationale:** Same struct, single name; the parent-name-shaped field name confuses readers traversing nested attachments. -### 17. `GenieConversation.id` *and* `GenieConversation.conversationId` — both identifiers — `src/v1/model.ts:917,929` -- **Why weird:** The struct has two id fields. JSDoc on `id` says "Legacy identifier, use conversation_id instead". Both are emitted, both are typed `string | undefined`, both are read from the wire. The struct also has no doc explaining the precedence rule when both are present (server normally fills both with the same value). -- **Category:** 19 (underspecified id), 12 (duplicate concept within one struct), 8 (redundant suffix). -- **Suggested name:** Either drop `id` (breaking-change risk) or mark with `@deprecated` and only emit one in the surface. Same pattern in `GenieMessage` (#18). -- **Rationale:** Caller cannot tell which to read without consulting the doc; autocomplete shows both at the same priority. - -### 18. `GenieMessage.id` *and* `GenieMessage.messageId` — both identifiers — `src/v1/model.ts:1372,1395` -- **Why weird:** Same pattern as #17. `id` is the "legacy identifier" and `messageId` the canonical one. Both fields appear in autocomplete. The waiter code (`client.ts:193`) reads `resp.messageId`, but a less-careful caller might read `resp.id`. -- **Category:** 19, 12, 8 (same as #17). -- **Suggested name:** Same as #17. -- **Rationale:** Same as #17. - -### 19. `GenieConversation.userId: number` typed as a number — `src/v1/model.ts:921` -- **Why weird:** User identifiers across the Databricks SDK are usually strings (workspace IDs are decimal-stringified longs; SCIM user IDs are strings; AAD ids are strings). `userId: number` truncates IDs above 2^53 silently. Also appears on `GenieMessage.userId` (line 1378), `GenieMessageComment.userId` (line 1412), `GenieEvalResult.createdByUser` (line 1025), `GenieEvalRunResponse.runByUser` (line 1091). -- **Category:** 16 (field type contradicts domain), 14 (proto-int64 leaked to JS `number`). -- **Suggested name:** Keep field name, change type to `string` (matches the rest of the SDK), or use `bigint`. Or `userId: string` with stronger JSDoc. -- **Rationale:** Postgres-ID / long-id semantics are universal here. The `userId: number` typing is a generator bug that bites at runtime. - -### 20. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` +### 9. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` - **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). - **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). - **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. - **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. -### 21. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` +### 10. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` - **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. - **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). - **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. - **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. -### 22. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` -- **Why weird:** Same as #21 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +### 11. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` +- **Why weird:** Same as #10 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). - **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). - **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. - **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. -### 23. `etag` field lowercase but `ETag` is a standard acronym — `src/v1/model.ts:1480,1529` -- **Why weird:** HTTP `ETag` is the canonical capitalisation. The field is `etag: string`. Across the SDK other types use `etag` lowercase too — but it is an acronym (`Entity Tag`). -- **Category:** 3 (acronym casing). -- **Suggested name:** `eTag` (camelCase per TS style) or `etag` (current — chosen for consistency). -- **Rationale:** Low priority; flag for awareness. - ## Low severity -### 24. `Result` type name — too generic — `src/v1/model.ts:1589` +### 12. `Result` type name — too generic — `src/v1/model.ts:1589` - **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. - **Category:** 1 (vague/generic). - **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. - **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. -### 25. `GenieResultMetadata` duplicates `ResultManifest` semantics — `src/v1/model.ts:1438` -- **Why weird:** A type whose two fields (`rowCount`, `isTruncated`) are both already on `ResultManifest`. JSDoc says "Metadata associated with the query result", but `ResultManifest` is also "result manifest" metadata. -- **Category:** 12 (duplicate concept). -- **Suggested name:** Replace with `ResultManifest` (or a sub-projection of it); delete `GenieResultMetadata`. -- **Rationale:** Two structs covering the same semantic territory cause readers to wonder which one is authoritative. - -### 26. `GenieAttachment.attachment.$case === 'suggestedQuestions'` — variant name redundant with type name — `src/v1/model.ts:903` -- **Why weird:** Discriminator value is `'suggestedQuestions'` and the payload type is `GenieSuggestedQuestionsAttachment`. The word `Attachment` is in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". +### 13. `GenieSuggestedQuestionsAttachment` — payload type name redundant with parent — `src/v1/model.ts:903` +- **Why weird:** The payload type is `GenieSuggestedQuestionsAttachment` for the discriminator value `'suggestedQuestions'` on `GenieAttachment`. The word `Attachment` is already in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology). -- **Suggested name:** Variant `'followUps'`, payload `SuggestedQuestions { questions: string[] }`. +- **Suggested name:** Payload type `SuggestedQuestions { questions: string[] }`. - **Rationale:** Reduce noise per attachment. -### 27. `GenieAttachment.attachmentId` — bare id alongside variant-specific ids — `src/v1/model.ts:909` -- **Why weird:** `attachmentId` on the parent; `TextAttachment.id` (line 1714) and `GenieQueryAttachment.id` (line 1429) inside variants. Three different id fields for the same logical entity (the attachment). -- **Category:** 19 (underspecified id), 12 (duplicate concept). -- **Suggested name:** Single `id` on `GenieAttachment`, remove inner ids. -- **Rationale:** Eliminate redundant inner id fields. - -### 28. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:188,992` +### 14. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:196,1072` - **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). - **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. - **Rationale:** Class names should be noun phrases; current name reads as a verb. -### 29. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:160` +### 15. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:165` - **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. - **Category:** 7 (overly verbose). - **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. - **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. -### 30. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:682, model.ts:1255` +### 16. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:735, model.ts:1255` - **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. - **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). - **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. - **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. -### 31. `Format.ARROW_STREAM` — `Arrow` is Apache Arrow (acronym), `STREAM` is uppercased — `src/v1/model.ts:546` -- **Why weird:** Value `ARROW_STREAM` casing. The product name is `Apache Arrow` — `Arrow` is title-case in TS naming. As an enum value `ARROW_STREAM` is conventional (SCREAMING_SNAKE) but mixed with `JSON_ARRAY` and `CSV` where one is fully-cap acronym and one is mixed. -- **Category:** 3 (acronym casing), 17 (mixed conventions within the enum). -- **Suggested name:** `ArrowStream` (in a Pascal-case enum). -- **Rationale:** Low priority — enum-value style is widely-debated. - -### 32. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:620` +### 17. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:667` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. @@ -213,17 +122,7 @@ ## Observations -### 33. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` +### 18. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` - **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. - **Suggested name:** N/A. - **Rationale:** Confirms the package's pagination naming is consistent. - -### 34. `Value` Well-Known-Type — empty in JS, hand-rolled — `src/v1/model.ts:1747` -- **Observation:** `Value` is the proto WKT for arbitrary JSON values. The TS shape is `{ kind: { $case: 'nullValue' | 'numberValue' | 'stringValue' | 'boolValue' | 'structValue' | 'listValue', ... } | undefined }` — 24 lines of TS for what JS represents as `unknown`. Same for `Struct`, `ListValue`, `MapStringValueEntry`. -- **Suggested name:** Replace `Value | Struct | ListValue` with `unknown` (or `JsonValue`) at marshal boundary. -- **Rationale:** Genie doesn't actually use these in any public method body; they exist only as transitive types referenced by `Result.* → ResultData.dataArray` (whose elements are `ListValue` of `Value`). The proto-WKT shape is buying nothing. - -### 35. Stub `MessageStatus` empty interface — `src/v1/model.ts:1562` -- **Observation:** `export interface MessageStatus {}` is an empty placeholder. The actual status enum is `MessageStatus_MessageStatus`. The empty type adds noise to the surface. -- **Suggested name:** Remove the empty interface; refer to the enum directly. -- **Rationale:** Empty interfaces in TS satisfy any object type and become bug magnets. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index 44f7db63..22bc7986 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -5,16 +5,8 @@ **Package name:** `@databricks/sdk-gitcredentials` (lowercased compound — the camel-case domain term is "Git credentials", so the package directory and module name both drop the obvious word boundary). -**Inferred domain:** A small CRUD surface over a workspace-level Git provider -credential store. Each credential is a record holding `(gitProvider, -gitUsername, gitEmail, name, isDefaultForProvider)` plus a write-only -`personalAccessToken`. The API mints an opaque numeric `credentialId` on -creation and returns it everywhere else. Five operations: -`create/get/list/update/delete`. No enums, no discriminated unions, no -pagination, no list filtering beyond an optional `principalId` query -parameter, no version negotiation. -**Total weird names flagged:** 12 (0 fixed, 12 still open) -**Last rescan:** 2026-05-26 (post regen #156, post Workflow B prune) +**Total weird names flagged:** 4 +**Last rescan:** 2026-06-02 (post regen, re-validated against current source) --- @@ -22,49 +14,16 @@ parameter, no version negotiation. | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| -| 1 | package `gitcredentials` / module `@databricks/sdk-gitcredentials` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 12 Duplicate concepts | Lowercased compound noun runs `git` and `credentials` together with no separator. The npm registry has packages literally called `git-credentials`/`@gitcredentials` (different ecosystem). Also collides conceptually with `@databricks/sdk-credentials` (Unity Catalog cloud-storage credentials) and `@databricks/sdk-auth/credentials` (SDK auth credentials). Three packages with "Credentials" in the name, three different meanings. | -| 2 | `Credential` (interface) | model.ts:68 | interface | High | 1 Vague/generic, 12 Duplicate concepts | Bare `Credential` clashes with `@databricks/sdk-credentials`'s `Credential` (UC credentials) and with the auth package's `Credentials` interface. None of them say "Git" or "auth" or "UC" on the type name. Should be `GitCredential`. | -| 3 | `Credential` vs `CreateCredentialsRequest_Response` vs `GetCredentialsRequest_Response` (3 identical shapes) | model.ts:68, 43, 116 | interface set | High | 12 Duplicate concepts | The three types have field-for-field identical structure: `{credentialId, gitProvider, gitUsername, name, isDefaultForProvider, gitEmail}`. The two response types should be type aliases of `Credential`, or `Credential` should be the response type directly. | -| 4 | `CreateCredentialsRequest` vs `UpdateCredentialsRequest` (request envelopes) | model.ts:5, 152 | interface pair | High | 12 Duplicate concepts | The two request envelopes differ by exactly one field: `UpdateCredentialsRequest` adds `id` (path parameter). Otherwise field-for-field identical: `gitProvider`, `gitUsername`, `personalAccessToken`, `principalId`, `name`, `isDefaultForProvider`, `gitEmail`. The JSDoc text on every shared field is duplicated verbatim across both. Should share a base type (`GitCredentialMutation`) and only differ on the path key. | -| 5 | `CreateCredentialsRequest` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredentialRequest`. (Compare `Credential` itself — the resource singular is already chosen.) | -| 6 | `UpdateCredentialsRequest`, `DeleteCredentialsRequest`, `GetCredentialsRequest` named with plural | model.ts:152, 98, 108 | interface set | High | 9 Singular/plural mismatches | Same as #5 — three more cases. `UpdateCredentialsRequest` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentialsRequest` deletes one. `GetCredentialsRequest` gets one. All three should be singular. | -| 7 | `ListCredentialsRequest_Response.credentials` field | model.ts:149 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | -| 8 | `gitProvider` field typed as `string` (should be enum) | model.ts:13, 47, 77, 120, 168 | field | High | 6 Misleading names, 15 Generic field names | The JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. | -| 9 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` (wire values inside JSDoc) | model.ts:8-11, 73-75, 163-165 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (small-G at boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" convention TS field names use. The values are dictated by the API server, but they will confuse readers ("is it `GitHub` or `gitHub`?"). | -| 10 | `Client` (unqualified class name) | client.ts:48 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `GitCredentialsClient` (matching the package name). | -| 11 | `Client.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:78, 141, 175, 209, 107 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | -| 12 | `*Request_Response` underscore-nested response types (5 of them) | model.ts:43, 106, 116, 147, 192 | interface set | High | Proto-architectural-leak | All five response types use the proto-style `ParentRequest_Response` underscore-nested form: `CreateCredentialsRequest_Response`, `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. The underscore is a protobuf-nested-message encoding bleeding into the public TS API — the generator even acknowledges it with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` above every one. The matching zod schema constants (`unmarshalCreateCredentialsRequest_ResponseSchema`, etc.) inherit the same underscore. | +| 1 | `CreateCredentialsRequest` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredentialRequest`. (Compare `Credential` itself — the resource singular is already chosen.) | +| 2 | `UpdateCredentialsRequest`, `DeleteCredentialsRequest`, `GetCredentialsRequest` named with plural | model.ts:149, 97, 107 | interface set | High | 9 Singular/plural mismatches | Same as #1 — three more cases. `UpdateCredentialsRequest` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentialsRequest` deletes one. `GetCredentialsRequest` gets one. All three should be singular. | +| 3 | `ListCredentialsResponse.credentials` field | model.ts:146 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | +| 4 | `GitCredentialsClient.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:80, 143, 177, 211, 109 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | --- ## High severity (must fix) -### H1. Three "Credentials" packages, three meanings - -The repository now has three packages with "Credentials" in the name, each -meaning something different: - -| Package | What it really is | -|---|---| -| `@databricks/sdk-auth/credentials/` (hand-written sub-module) | SDK *user* authentication credentials (PAT, OAuth U2M, OAuth M2M). | -| `@databricks/sdk-credentials` | Unity Catalog cloud-storage / service credentials (AWS IAM roles, Azure SPs, GCP service accounts). | -| `@databricks/sdk-gitcredentials` (this package) | Per-workspace Git provider credentials (PATs for GitHub, GitLab, etc.). | - -A consumer reading `import {Credential} from '@databricks/sdk-...'` cannot -tell which one is meant. The three packages even use the same `Credential` -type name. Recommend: - -- Either keep the domain prefix in the type names (`GitCredential` here, - `StorageCredential`/`ServiceCredential` in the UC package), or -- Disambiguate the package names (`@databricks/sdk-git-credentials` — - spelled with the hyphen — would at least visually separate it). - -Also flagged: directory and module name use `gitcredentials`, not -`git-credentials` or `git_credentials`. The npm registry already has -unrelated packages with the literal name `git-credentials` and -`git-credentials-node`. Pick a hyphenated form to disambiguate from those. - -### H2. Plural request-type names +### H1. Plural request-type names Four request envelopes act on a single resource but use the plural noun: `CreateCredentialsRequest`, `GetCredentialsRequest`, `UpdateCredentialsRequest`, @@ -83,91 +42,7 @@ await client.createCredential({gitProvider: 'gitHub', ...}); Recommendation: keep `listCredentials` (plural — list returns many) but rename the four single-resource methods and their request types to -singular. See #5, #6, #11. - -### H3. Three field-for-field-identical "Credential" shapes - -`Credential`, `CreateCredentialsRequest_Response`, and `GetCredentialsRequest_Response` -all have the same six fields with the same types, the same optionality, and -the same JSDoc text. Two of the three are redundant. - -Recommendation: - -```ts -// Before -export interface CreateCredentialsRequest_Response { /* 6 fields */ } -export interface GetCredentialsRequest_Response { /* same 6 fields */ } -export interface Credential { /* same 6 fields */ } - -// After -export interface GitCredential { /* 6 fields */ } -// Return GitCredential directly from create() and get(). -``` - -### H4. `gitProvider` is typed `string` but is closed-set - -```ts -gitProvider?: string | undefined; -``` - -JSDoc enumerates eight values: `gitHub`, `bitbucketCloud`, `gitLab`, -`azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, -`gitLabEnterpriseEdition`, `awsCodeCommit`. The set is closed; the API -server rejects other values. But the TS-side surfaces it as `string`, so: - -- No autocomplete on the value list. -- No compile-time check for typos (`gitub` will type-check). -- The JSDoc casing inconsistencies (`gitHub` vs `gitLabEnterpriseEdition`) - cannot be fixed at the call site, only by the API server. - -Recommendation: emit a string-literal union or enum. The casing problem -(#9) gets handled there. - -### H5. `Client` is unqualified - -`export class Client` (client.ts:48). Every package in this SDK exports its -own `Client`. Once imported in user code: - -```ts -import {Client as GitCredentialsClient} from '@databricks/sdk-gitcredentials/v1'; -``` - -— the consumer has to do the renaming. The generator should produce -`GitCredentialsClient` directly (matching the package noun). This is a -pattern-wide issue and was flagged in every audit so far. - -### H6. `*Request_Response` underscore-nested response types — `model.ts:43, 106, 116, 147, 192` - -- **Why:** All five response types are emitted as proto-style nested - messages joined by a literal underscore — `CreateCredentialsRequest_Response`, - `DeleteCredentialsRequest_Response`, `GetCredentialsRequest_Response`, - `ListCredentialsRequest_Response`, `UpdateCredentialsRequest_Response`. - The underscore-joined `ParentRequest_Response` form is the - protobuf/Go-SDK convention for flattening a nested-message namespace - (`message CreateCredentialsRequest { message Response { ... } }`) into a - single identifier. TS has native namespaces and modules, so the - underscore is a wire-protocol artifact bleeding into the public TS - surface. The generator already labels every one of them - "Proto-style nested message name" via an `eslint-disable-next-line` - comment, which is an explicit confession that the form is non-idiomatic. - The matching zod schemas (`unmarshalCreateCredentialsRequest_ResponseSchema`, - etc.) inherit the same underscore at `model.ts:195, 233, 237, 257, 267`, - and every import site in `client.ts:22-30, 35-39, 81, 84, 96, 110, 118, - 130, 144, 152, 164, 178, 186, 198, 212, 215, 227` carries it forward. -- **Category:** Proto-architectural leak (proto-style nested-message - encoding leaking into TS identifiers). -- **Suggested name:** Drop the underscore and the `Request_` prefix. - `CreateCredentialResponse`, `DeleteCredentialResponse`, - `GetCredentialResponse`, `ListCredentialsResponse`, - `UpdateCredentialResponse`. Even better, collapse all three - identical-shape response types into `GitCredential` directly (see H3) so - three of the five disappear entirely. -- **Rationale:** TS consumers should never have to learn that a response - type is "nested inside" its request message — that nesting is a proto - detail the wire never sees (the JSON body has no `Request_Response` - envelope; it just has the response fields directly). The underscore is - the single clearest piece of evidence that the generator is emitting Go - shapes verbatim rather than rendering an idiomatic TS surface. +singular. See #1, #2, #4. --- @@ -175,7 +50,7 @@ pattern-wide issue and was flagged in every audit so far. ### M1. Plural `*Credentials` envelopes for single-resource operations -See H2. Repeating because the request-type and method names compound the +See H1. Repeating because the request-type and method names compound the plural problem. ### M2. `Credential` (singular) and `*Credentials` (plural) coexist as the same domain term @@ -197,42 +72,3 @@ concept toggles plural/singular at almost every boundary: Pick a rule. Conventional CRUD: plural for collection ops (`listCredentials`, URL `/credentials`), singular for resource ops (`getCredential`, `createCredential`, URL `/credentials/{id}`). - ---- - -## Low severity (style polish) - -_None._ - ---- - -## Notes - -### Wire-protocol values that the audit cannot fix - -The `gitProvider` wire values (`gitHub`, `bitbucketCloud`, etc.) are -dictated by the API server. The casing inconsistencies (#9) are baked in. -The TS-side cannot change them without breaking the wire. The audit flags -them for awareness — fixing requires an API-server change. - -### Identifier zoo summary - -| Identifier kind | Count | -|---|---| -| Total exported interfaces | 10 | -| Plural request envelopes for single-resource ops | 4 | -| Identical-shape interface trios | 1 (`Credential` ≡ `CreateCredentialsRequest_Response` ≡ `GetCredentialsRequest_Response`) | -| Enums | 0 (despite an 8-value closed set on `gitProvider`) | - -### Comparison to other audits - -| Issue | This package | `credentials` audit | `oauthcustomappintegration` (typical) | -|---|---|---|---| -| Bare `Client` class | Yes (#10) | Yes (#10) | Yes | -| Plural request envelopes on single-resource ops | Yes (#5, #6, #11) | No (uses `nameArg`/singular shapes) | Mixed | -| `string`-typed enum-domain field | Yes (#8) | No (uses real enums) | Rare | - -The `string`-typed `gitProvider` despite a documented closed set (#8, H4) -is the standout finding unique to this package. The plural request-type -naming (#5, #6, H2) is also pronounced here — the `credentials` audit -gets it right (`CreateCredential`, `UpdateCredential`). diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index c3ae32b1..292bb073 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -10,252 +10,36 @@ - `src/v2/utils.ts` - `src/v2/index.ts` -This audit catalogues every identifier (type, field, enum value, method, -constant) in the package and flags naming concerns against the 20-category -rubric. Issues are graded: - -- **High** — actively misleading, ambiguous, or violates a TS rule. -- **Medium** — friction; verbose, redundant, or stylistically off. -- **Low** — nit / consistency observation; safe to ignore. - --- -## 1. Inventory - -### 1.1 Enums (`model.ts`) - -None. This package defines no enums. - -### 1.2 Interfaces (`model.ts`) - -| Name | Purpose | -| -------------------------------------------- | --------------------------------------------- | -| `CreateGlobalInitScriptRequest` | Request body for create. | -| `CreateGlobalInitScriptRequest_Response` | Response from create. | -| `DeleteGlobalInitScriptRequest` | Request body (path param wrapper) for delete. | -| `DeleteGlobalInitScriptRequest_Response` | Empty response from delete. | -| `GetGlobalInitScriptRequest` | Request body (path param wrapper) for get. | -| `GlobalInitScriptDetails` | Entity describing a global init script. | -| `ListGlobalInitScriptsRequest` | Empty request body for list. | -| `ListGlobalInitScriptsRequest_Response` | Response from list. | -| `UpdateGlobalInitScriptRequest` | Request body for update. | -| `UpdateGlobalInitScriptRequest_Response` | Empty response from update. | - -### 1.3 Fields (entity / request / response — combined catalog) - -| Type | Field | Type / Notes | -| ---------------------------------------- | ------------ | ----------------------------------------- | -| `CreateGlobalInitScriptRequest` | `name` | `string?` — script display name. | -| `CreateGlobalInitScriptRequest` | `script` | `Uint8Array?` — Base64-encoded content. | -| `CreateGlobalInitScriptRequest` | `position` | `number?` — execution order index. | -| `CreateGlobalInitScriptRequest` | `enabled` | `boolean?` | -| `CreateGlobalInitScriptRequest_Response` | `scriptId` | `string?` | -| `DeleteGlobalInitScriptRequest` | `scriptId` | `string?` — path parameter. | -| `GetGlobalInitScriptRequest` | `scriptId` | `string?` — path parameter. | -| `GlobalInitScriptDetails` | `scriptId` | `string?` | -| `GlobalInitScriptDetails` | `name` | `string?` | -| `GlobalInitScriptDetails` | `position` | `number?` | -| `GlobalInitScriptDetails` | `enabled` | `boolean?` | -| `GlobalInitScriptDetails` | `createdBy` | `string?` — username. | -| `GlobalInitScriptDetails` | `createdAt` | `number?` — Unix timestamp in ms. | -| `GlobalInitScriptDetails` | `updatedBy` | `string?` — username. | -| `GlobalInitScriptDetails` | `updatedAt` | `number?` — Unix timestamp in ms. | -| `ListGlobalInitScriptsRequest_Response` | `scripts` | `GlobalInitScriptDetails[]?` | -| `UpdateGlobalInitScriptRequest` | `scriptId` | `string?` — path parameter. | -| `UpdateGlobalInitScriptRequest` | `name` | `string?` | -| `UpdateGlobalInitScriptRequest` | `script` | `Uint8Array?` — Base64-encoded content. | -| `UpdateGlobalInitScriptRequest` | `position` | `number?` | -| `UpdateGlobalInitScriptRequest` | `enabled` | `boolean?` | - -### 1.4 Methods (`client.ts`) - -| Method | HTTP | Returns | -| ------------------------- | ------ | ------------------------------------------- | -| `createGlobalInitScript` | POST | `CreateGlobalInitScriptRequest_Response` | -| `deleteGlobalInitScript` | DELETE | `DeleteGlobalInitScriptRequest_Response` | -| `getGlobalInitScript` | GET | `GlobalInitScriptDetails` | -| `listGlobalInitScripts` | GET | `ListGlobalInitScriptsRequest_Response` | -| `updateGlobalInitScript` | PATCH | `UpdateGlobalInitScriptRequest_Response` | - -### 1.5 Other identifiers +## 1. Summary -- `client.ts`: `Client` class. +| Severity | Count | +| -------- | ----- | +| High | 1 | +| Medium | 3 | +| Low | 0 | +| **Total**| **4** | --- ## 2. Findings by Category -### 2.1 Vague / generic names — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| V-01 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Generic but standard across the SDK; acceptable in entity context. | - -### 2.2 Redundant enum prefixes — None - -No enums are declared in this package; this rubric category does not apply. - -### 2.3 Acronym casing inconsistencies — Low - -| ID | Symbol | Severity | Issue | -| ----- | --------------------- | -------- | ----- | -| A-01 | `Uint8Array` | Low | Standard Web/TC39 typed-array name; OK. | -| A-02 | "Base64" in JSDoc | Low | The JSDoc on `CreateGlobalInitScriptRequest.script` writes "Base64" with mixed case — this is correct (the format name is `Base64`, not `BASE64`). Acceptable. | - -### 2.4 Underscores in TS identifiers — Low - -| ID | Symbol | Severity | Issue | -| ----- | ------------------------------------------ | -------- | ----- | -| U-01 | Wire-format keys (`script_id`, `created_by`, `created_at`, `updated_by`, `updated_at`) inside Zod schemas | Low | These are string literals inside `z.object({...})` — they are JSON keys on the wire, not TS identifiers. Not a naming-convention violation; correctly mapped to camelCase via `.transform`. | - -### 2.5 Cryptic abbreviations — None - -_None._ - -### 2.6 Misleading names — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| M-01 | `GlobalInitScriptDetails` (returned by `getGlobalInitScript`, `client.ts:133`) — JSDoc says "including its Base64-encoded contents" | High | The entity type defines no `script` / `content` field at all, despite the method JSDoc claiming the contents are returned. Either the JSDoc is wrong, or the entity is missing a `script` field. This is a high-severity inconsistency between method docs and the entity shape — readers will look for content in the response and not find it. | - -### 2.7 Overly verbose / Redundant suffixes — Medium +### 2.1 Overly verbose / Redundant suffixes | ID | Symbol | Severity | Issue | | ----- | ----------------------------------------------- | -------- | ----- | -| O-01 | `CreateGlobalInitScriptRequest` / `DeleteGlobalInitScriptRequest` / `GetGlobalInitScriptRequest` / `UpdateGlobalInitScriptRequest` / `ListGlobalInitScriptsRequest` (`model.ts:5`, `28`, `36`, `61`, `68`) | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full plus the `Request` suffix, producing ~28-32-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `CreateRequest`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | -| O-02 | `GlobalInitScriptDetails` (entity name, `model.ts:41`) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | - -### 2.8 Singular / plural mismatches — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| P-01 | `ListGlobalInitScriptsRequest` (request, plural) vs `listGlobalInitScripts()` (method, plural) | Low | Consistent. | -| P-02 | `ListGlobalInitScriptsRequest_Response.scripts` | Low | Plural field for array — correct. | -| P-03 | `GlobalInitScriptDetails` (singular entity) vs `getGlobalInitScript()` (singular get) | Low | Consistent. | -| P-04 | `createGlobalInitScript`, `deleteGlobalInitScript`, `updateGlobalInitScript` | Low | Singular for per-resource ops — correct. | +| O-01 | `CreateGlobalInitScriptRequest` / `DeleteGlobalInitScriptRequest` / `GetGlobalInitScriptRequest` / `UpdateGlobalInitScriptRequest` / `ListGlobalInitScriptsRequest` (`model.ts:5`, `27`, `35`, `66`, `60`) | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full plus the `Request` suffix, producing ~28-32-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `CreateRequest`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | +| O-02 | `GlobalInitScriptDetails` (entity name, `model.ts:40`) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | -### 2.9 Reserved-word collisions — None +### 2.2 Go / Java-style names | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| R-01 | None observed. | — | None of the field names (`name`, `script`, `position`, `enabled`, `scriptId`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`) collide with JavaScript reserved words. Note that `name` is a reserved property on `Function.prototype` but not a reserved identifier, so it is fine as a field name. | +| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix, `model.ts:40`) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | -### 2.10 Empty / trivial wrapper types — None - -_None._ - -### 2.11 Duplicate concepts — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| D-01 | `CreateGlobalInitScriptRequest` vs `UpdateGlobalInitScriptRequest` (`model.ts:5`, `model.ts:68`) | Medium | Update adds only one field (`scriptId`); otherwise identical to create. Two near-duplicate 4-field interfaces. Codegen constraint, but readers see them side by side. | -| D-02 | `GlobalInitScriptDetails` vs `CreateGlobalInitScriptRequest` / `UpdateGlobalInitScriptRequest` | Medium | Same `name`, `position`, `enabled` fields appear in three types. The entity adds audit fields (`createdBy`, `createdAt`, etc.) but omits `script`. A shared base / fragment would reduce duplication. | - -### 2.12 Verb-tense inconsistency — Low +### 2.3 Type-suffix tautology | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| T-01 | `createGlobalInitScript`, `deleteGlobalInitScript`, `getGlobalInitScript`, `listGlobalInitScripts`, `updateGlobalInitScript` | Low | All imperative present-tense — consistent. | -| T-02 | `createdBy`, `createdAt`, `updatedBy`, `updatedAt` | Low | Past participles for audit fields — correct convention. | -| T-03 | `enabled` (past participle / adjective) | Low | Consistent with the rest of the SDK (`enabled` boolean state). | - -### 2.13 Go / Java-style names — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix, `model.ts:41`) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | - -### 2.14 Generic field names losing meaning — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| F-01 | `GlobalInitScriptDetails.name` (`model.ts:45`) | Low | Standard entity field; meaning preserved in context. | - -### 2.15 Field contradicting type domain — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| FD-01 | None observed. | — | All fields are domain-appropriate for the global-init-script context. | - -### 2.16 Inconsistent action verbs — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| AV-01 | `createGlobalInitScript`, `deleteGlobalInitScript`, `getGlobalInitScript`, `listGlobalInitScripts`, `updateGlobalInitScript` | Low | Clean CRUD verb set — `create`, `delete`, `get`, `list`, `update`. Matches the broader Databricks SDK style. No `edit` / `patch` / `modify` inconsistencies. | -| AV-02 | `getGlobalInitScript()` (singular) vs `listGlobalInitScripts()` (plural) | Low | Correct convention (singular get, plural list). Consistent. | - -### 2.17 Long enum values — None - -No enums declared; not applicable. - -### 2.18 Underspecified IDs — Medium - -_None._ - -### 2.19 Type-suffix tautology — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `GlobalInitScriptDetails` (`model.ts:41`) | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | - -### 2.20 Proto-architectural leaks — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| PL-01 | `CreateGlobalInitScriptRequest_Response` (`model.ts:23`) | High | The `Request_Response` infix is a verbatim leak of the proto nested-message naming (`CreateRequest.Response`). The source comment on line 22 explicitly says "Proto-style nested message name". A TS-idiomatic response type would be `CreateGlobalInitScriptResponse` (or just `CreateResponse` since the package scope already implies the entity). | -| PL-02 | `DeleteGlobalInitScriptRequest_Response` (`model.ts:34`) | High | Same proto-nested leak. Suggested: `DeleteGlobalInitScriptResponse`. | -| PL-03 | `ListGlobalInitScriptsRequest_Response` (`model.ts:64`) | High | Same proto-nested leak. Suggested: `ListGlobalInitScriptsResponse`. | -| PL-04 | `UpdateGlobalInitScriptRequest_Response` (`model.ts:95`) | High | Same proto-nested leak. Suggested: `UpdateGlobalInitScriptResponse`. | -| PL-05 | `unmarshalCreateGlobalInitScriptRequest_ResponseSchema` (`model.ts:98`) | High | Schema identifier carries the proto nested-message infix. Suggested: `unmarshalCreateGlobalInitScriptResponseSchema`. | -| PL-06 | `unmarshalDeleteGlobalInitScriptRequest_ResponseSchema` (`model.ts:108`) | High | Same. Suggested: `unmarshalDeleteGlobalInitScriptResponseSchema`. | -| PL-07 | `unmarshalListGlobalInitScriptsRequest_ResponseSchema` (`model.ts:135`) | High | Same. Suggested: `unmarshalListGlobalInitScriptsResponseSchema`. | -| PL-08 | `unmarshalUpdateGlobalInitScriptRequest_ResponseSchema` (`model.ts:147`) | High | Same. Suggested: `unmarshalUpdateGlobalInitScriptResponseSchema`. | - -### 2.21 Other observations - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| X-01 | `GlobalInitScriptDetails.createdAt` / `updatedAt` (`number`, epoch ms) | Low | Acceptable for ms timestamps; the SDK exposes these as plain numbers. JS `Date` safe-integer range covers epoch-ms beyond year 285,000. Flagged for parity with other audits. | -| X-02 | `Client` (class name, `client.ts:48`) | Low | The class is named `Client` (not `GlobalInitScriptsClient`) within the per-package namespace. Consistent with peer packages. The import alias at call sites disambiguates (`import {Client as GlobalInitScriptsClient}` or similar). OK. | - ---- - -## 3. Summary - -### 3.1 Findings by severity - -| Severity | Count | -| -------- | ----- | -| High | 10 | -| Medium | 5 | -| Low | 16 | -| **Total**| **31**| - -### 3.2 Top themes - -1. **`GlobalInitScriptDetails` should just be `GlobalInitScript`.** - The `Details` suffix is a Java-style hangover with no peer type to - disambiguate from. The method JSDoc also claims to return Base64 - content while the entity has no content field — a documentation / - shape inconsistency. - -2. **`createdAt`/`updatedAt` naming is good** — unlike sibling packages - that use `createdAtTimestamp`, this package uses the cleaner - `createdAt` / `updatedAt`. Worth keeping as the cross-package - reference. - -### 3.3 Suggested quick wins (advisory — codegen-level) - -- Rename entity `GlobalInitScriptDetails` -> `GlobalInitScript`. -- Add the missing content field on the entity (or fix the JSDoc on - `getGlobalInitScript` that claims contents are returned). - -### 3.4 Cross-package consistency notes - -- `position` field semantics are unique to this resource; no other - package collides on the name with a different meaning. -- The clean `createdAt` / `updatedAt` naming here contrasts with - `createdAtTimestamp` in `clusterpolicies` — this package is the - preferred reference for timestamp naming. - ---- +| TS-01 | `GlobalInitScriptDetails` (`model.ts:40`) | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md index 8f41fac0..7dfa82c5 100644 --- a/.agent/naming-audit/grants.md +++ b/.agent/naming-audit/grants.md @@ -1,93 +1,22 @@ # Naming Audit: grants -**Path:** `packages/grants/src/v1/` +**Path:** `packages/uc/grants/src/v1/` **Versions audited:** v1 -**Inferred domain:** Unity Catalog Grants — get, list, and update privileges (e.g. `SELECT`, `MODIFY`, `USE_CATALOG`) on UC securables (catalogs, schemas, tables, etc.) for principals (users, groups, service principals). Also exposes "effective" variants that traverse parent-securable inheritance. -**Total weird names flagged:** 9 +**Total weird names flagged:** 1 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 3 | -| Low | 1 | -| Observation | 0 | - -The grants package contains 9 generated types and 3 client methods covering one of the most overlapping surfaces in the SDK: UC privilege management. The most pervasive remaining issues are (1) the conceptual overlap with the separate `permissions` package which uses entirely different vocabulary (`PermissionLevel`, `AccessControlRequest`, `PermissionsResponse`) for a similar operation, and (2) the lack of enum types for the closed sets of `securableType` and `privilege` strings. - ---- - -## High severity - -### 1. Concept duplication with `permissions` package — cross-package -- **Why weird:** A sibling package `packages/permissions/src/v1/` (also generated, also exposed) uses an entirely different vocabulary for similar-sounding operations: - - `permissions` package: `PermissionLevel` enum (e.g. `CAN_MANAGE`, `IS_OWNER`), `AccessControlRequest` (uses discriminated union over `userName` / `groupName` / `servicePrincipalName`), `PermissionsResponse` with `accessControlList`, `setObjectPermissions`, `getObjectPermissions`, `updateObjectPermissions`, `getPermissionLevels`. - - `grants` package: free-form `privileges: string[]` (no enum), `principal: string` (single field, doesn't distinguish user vs group vs SP), `PrivilegeAssignment`, `getPermissions`, `updatePermissions`. -- Both packages claim the `Permissions` and `Permission*` keywords. A user navigating the SDK will see `permissions` and `grants` and reasonably wonder which to use. There is no surface-level disambiguation. -- **Category:** 12 (duplicate concepts across packages), 1 (vague top-level naming — neither package name is self-disambiguating). -- **Suggested name:** Rename one of the packages to make the disambiguation clear, e.g. `grants` → `unity-catalog-grants` or `uc-privileges`; `permissions` → `workspace-permissions` or `workspace-acl`. Or — at minimum — keep their public types non-overlapping (currently both export "Permission..."-prefixed types). -- **Rationale:** The two packages cover non-overlapping concrete operations (UC grants vs workspace-object ACLs) but use heavily overlapping vocabulary. This is an enormous discoverability hazard. - -### 2. `PermissionsChange` (type) — `src/v1/model.ts:99` -- **Why weird:** Inconsistent vocabulary with the rest of the file. The package mostly uses `Privilege*` (`PrivilegeAssignment`, `EffectivePrivilege`, `EffectivePrivilegeAssignment`) but the change-payload is named `PermissionsChange` (plural "Permissions", not "Privilege"). The change describes adding/removing entries to `add: string[]` / `remove: string[]` where the strings are privileges. So the type is really a `PrivilegeChange` or `PrivilegeAssignmentChange`. -- **Category:** 17 (inconsistent vocabulary), 12 (concept overlap with `permissions` package). -- **Suggested name:** `PrivilegeChange` or `PermissionsChange` (and pick one across the file). -- **Rationale:** Internal vocabulary consistency. - -### 3. `GetEffectivePermissionsRequest_Response` — `src/v1/model.ts:53,163` -- **Why weird:** Proto-architectural leak. The `Request_Response` underscore-separated name encodes the proto-style nested-message hierarchy (a `Response` message nested inside the `GetEffectivePermissionsRequest` enclosing message). TypeScript readers see a foreign tooling artifact, not an idiomatic type name. The companion `unmarshalGetEffectivePermissionsRequest_ResponseSchema` constant and the inline ESLint-disable comments (`Proto-style nested message name.`) confirm the leak is intentional but unidiomatic. -- **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). -- **Suggested name:** `GetEffectivePermissionsResponse`. -- **Rationale:** TypeScript has no notion of nested-message scoping; the underscore exists solely to mirror `message Foo { message Response { ... } }` in the source proto. Flattening to `GetEffectivePermissionsResponse` matches the rest of the SDK's response-type convention. - -### 4. `GetPermissionsRequest_Response` — `src/v1/model.ts:89,177` -- **Why weird:** Same proto-architectural leak as #3. The `Request_Response` underscore-separated form is a direct port of a proto-nested message name; the accompanying schema constant (`unmarshalGetPermissionsRequest_ResponseSchema`) and the `Proto-style nested message name.` ESLint-disable comment make the proto origin explicit. -- **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). -- **Suggested name:** `GetPermissionsResponse`. -- **Rationale:** See #3. - -### 5. `UpdatePermissionsRequest_Response` — `src/v1/model.ts:131,202` -- **Why weird:** Same proto-architectural leak as #3 and #4. The `Request_Response` naming and the `unmarshalUpdatePermissionsRequest_ResponseSchema` schema constant both carry the proto nested-message marker. -- **Category:** Proto-architectural leak (mid-position underscore separator from `.proto` nesting). -- **Suggested name:** `UpdatePermissionsResponse`. -- **Rationale:** See #3. +| Medium | 1 | --- ## Medium severity -### 6. `privileges: string[]` and `privilege: string` — model-wide (e.g. `src/v1/model.ts:7,24,106,108,118`) -- **Why weird:** Every privilege is typed as a free-form `string`. The Go SDK and Databricks UC API have a fixed enum of privilege names (`SELECT`, `MODIFY`, `USE_CATALOG`, `USE_SCHEMA`, `EXECUTE`, `CREATE_*`, `READ_VOLUME`, `WRITE_VOLUME`, etc.). The TS SDK exposes them as bare strings with no autocomplete, no type-checking, no documentation. A typo like `"SELCT"` will silently round-trip to the server. -- **Category:** 19 (underspecified), 1 (vague: `string` doesn't constrain meaning). -- **Suggested name:** Define a `Privilege` enum (or string literal union). At minimum document the valid values inline. -- **Rationale:** Type-safety is the entire point of TypeScript. The audit task explicitly flags "long enum values (many privilege values)" — the irony is that grants HAS the most privilege values of any UC operation and exposes ZERO of them as types. - -### 7. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` +### 1. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` - **Why weird:** Three-word PascalCase name (`Effective` + `Privilege` + `Assignment`) that on first read parses as "Effective Privilege" / "Assignment" but on second read could parse as "Effective" / "Privilege Assignment". The conceptual model is "the privilege assignment that effectively applies (because of inheritance)", which the doc-comment confirms — but the name doesn't disambiguate. - **Category:** 7 (overly verbose). - **Suggested name:** Possibly leave as-is; alternative is `EffectiveAssignment` (drop `Privilege` since `Assignment` is privilege-specific in this file). - **Rationale:** Marginal; flagged for symmetry with `EffectivePrivilege` (line 5). -### 8. `securableType: string` — model-wide (3 occurrences at `src/v1/model.ts:29,65,123`) -- **Why weird:** Free-form string for what should be an enum. UC defines a closed set of securable types (`CATALOG`, `SCHEMA`, `TABLE`, `VIEW`, `FUNCTION`, `VOLUME`, `EXTERNAL_LOCATION`, `STORAGE_CREDENTIAL`, `CONNECTION`, `METASTORE`, ...). The TS SDK exposes none of them. -- **Category:** 19 (underspecified), 1 (vague). -- **Suggested name:** Define a `SecurableType` enum. -- **Rationale:** Type-safety; closed sets should be enums. - ---- - -## Low severity - -### 9. `Client` — `src/v1/client.ts:41` -- **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts` re-exports `Client` (line 3), so users write `import { Client } from '@databricks/sdk-grants/v1'`. Same name appears in every generated package — you can't have multiple grants/catalogs/etc. clients in one import without aliasing. -- **Category:** 1 (vague), 12 (duplicate across packages). -- **Suggested name:** `GrantsClient` (or whatever the package-specific name is). -- **Rationale:** Convention in `@aws-sdk/*`, `@google-cloud/*`, `@azure/*` is service-prefixed client class names for exactly this reason. - ---- - -## Observations - -_None._ - --- diff --git a/.agent/naming-audit/iam.md b/.agent/naming-audit/iam.md deleted file mode 100644 index 90cb75bb..00000000 --- a/.agent/naming-audit/iam.md +++ /dev/null @@ -1,272 +0,0 @@ -# Naming Audit: `@databricks/sdk-iam` (v2) - -**Package:** `iam` (`packages/iam/src/v2/`) -**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts` - -**Domain:** Databricks IAM — workspace assignment / access details and -resolve-by-external-id flows that bridge the customer IdP to Databricks. - -## Summary - -| Severity | Count | -| -------- | ----- | -| High | 6 | -| Medium | 4 | -| Low | 3 | -| Observation | 1 | -| **Total** | **14** | - -Three dominant themes remain. **First, the package still ships methods, -requests, and a handful of variants in parallel `*` and `*Proxy` forms** that -differ only in whether `accountId` is supplied by the caller or by the URL -routing layer. **Second, the package still leaks proto conventions into JSDoc:** -the literal `` markup appears throughout. **Third, naming is -inconsistent across status fields and parent-account fields** — -`accountUserStatus`, `accountSpStatus`, and `status` all describe the same -`State` enum across types, and the `Detail` suffix on -`WorkspaceAssignmentDetail` / `WorkspaceAccessDetail` adds no information -beyond Java-RPC habit. - ---- - -## High-severity findings - -### H1. Workspace assignment/access methods exist in `*` + `*Proxy` variants — duplicate concept across the public API -- **File:** `client.ts:101-153, 159-223, 229-281, 290-355, 363-424, 432-472, 475-522, 525-596, 604-688` -- **Category:** 12, 7, 14 (duplicate concepts; verbose; Go/Java-style RPC pairs) -- **Issue:** The remaining endpoints are duplicated as `X` + `XProxy` - pairs: `resolveGroup` + `resolveGroupProxy`, `resolveUser` + - `resolveUserProxy`, `resolveServicePrincipal` + - `resolveServicePrincipalProxy`, plus - `createWorkspaceAssignmentDetail`/`Proxy`, - `deleteWorkspaceAssignmentDetail`/`Proxy`, - `getWorkspaceAssignmentDetail`/`Proxy`, - `listWorkspaceAssignmentDetails`/`Proxy`, - `updateWorkspaceAssignmentDetail`/`Proxy`. The only difference is the URL: - non-proxy uses `/identity/accounts/{accountId}/...`, proxy uses - `/identity/...` (workspace-rooted, accountId resolved server-side). The - request types are the same minus the `accountId` field. A consumer must - decide between two methods for every operation, doubling the API surface - and the request-type count. -- **Suggestion:** Collapse to one method per operation. Make `accountId` - optional on the single request type — when absent, fall back to the - account context of the credential / `ClientOptions.accountId` (the client - already does this on line 105, 163, 233, 294, 367, etc.). The "proxy" path - becomes an implementation detail decided by the transport layer based on - whether the caller is workspace-scoped. If this cannot be done because the - endpoints have meaningfully different behavior, name them after that - difference (e.g. `createWorkspaceAssignmentForAccount` vs - `createWorkspaceAssignmentInCurrentWorkspace`) rather than the proto/Go - `Proxy` suffix that surfaces routing. -- **Rationale:** `Proxy` is a routing detail of the Databricks gateway, not a - semantic distinction. It is the strongest source of confusion in the - package. Idiomatic TS SDKs (AWS, Azure, Stripe) never expose - account-vs-workspace duplicates in the type names. - -### H2. `Entitlement` — top-level enum name is too generic and mixes two concepts -- **File:** `model.ts:7-15` -- **Category:** 1 (vague/generic) -- **Issue:** The exported enum `Entitlement` carries values like - `WORKSPACE_ACCESS`, `WORKSPACE_CONSUME`, `DATABRICKS_SQL_ACCESS`, - `WORKSPACE_ADMIN`, `ALLOW_CLUSTER_CREATE`, `ALLOW_INSTANCE_POOL_CREATE`. - These are workspace-scoped entitlements, not generic "entitlements", and - the enum has no JSDoc. The name does not disclose scope; a developer - reading `entitlements?: Entitlement[]` on a workspace assignment cannot - tell whether these are workspace entitlements, account entitlements, or - something more abstract. The values mix permission verbs - (`ALLOW_CLUSTER_CREATE`) with abstract access markers (`WORKSPACE_ACCESS`) - on the same enum. -- **Suggestion:** `WorkspaceEntitlement`. Add a JSDoc that distinguishes - "presence" entitlements (`WORKSPACE_ACCESS`, `WORKSPACE_ADMIN`) from - "create" entitlements (`ALLOW_CLUSTER_CREATE`, `ALLOW_INSTANCE_POOL_CREATE`). - Consider splitting into `WorkspaceRole` (admin/user/SQL access) and - `WorkspaceCreatePermission` (cluster/instance pool create) — they are - conceptually different and gated differently in the platform. -- **Rationale:** `Entitlement` is used on exactly one field - (`WorkspaceAssignmentDetail.entitlements`) and never elsewhere, so it is - effectively a workspace entitlement enum already. - -### H3. `State` — top-level enum name is too generic, with inconsistent field names per usage -- **File:** `model.ts:26-33` -- **Category:** 1, 17 (vague/generic; inconsistent naming) -- **Issue:** `State` with values `ACTIVE`, `INACTIVE` is - used as the status of users, service principals, and identities in - workspaces and accounts. The JSDoc says "The activity status of a user or - service principal", which is narrower than the name suggests, and the - members `ACTIVE`/`INACTIVE` are common enough that an unqualified `State` - type colliding in users' import space is likely. The field name also - varies per usage: `accountUserStatus`, `accountSpStatus`, plain `status` — - three different field names for the same enum domain across three types. -- **Suggestion:** Rename the enum to `ActivityStatus` (or `PrincipalStatus`). -- **Rationale:** A 3-letter enum with 2 values and the name `State` is a - textbook example of a name that says nothing about the domain. JSDoc-only - context is not enough. - -### H4. `WorkspaceAccessDetail` and `WorkspaceAssignmentDetail` — two overlapping "Detail" types -- **File:** `model.ts:305-318, 321-330`, plus the methods they appear in -- **Category:** 1, 12, 7 (vague generic suffix; duplicate concept; verbose) -- **Issue:** Two top-level types with the `Detail` suffix model overlapping - shapes of "what a principal has in a workspace": - - `WorkspaceAccessDetail`: principal, workspace, account, principalType, accessType, status, permissions. - - `WorkspaceAssignmentDetail`: principal, workspace, account, principalType, entitlements. - - Both identify the same triple `(accountId, workspaceId, principalId)`. - `Detail` is a meaningless suffix — every type in a data model is a "detail". - The differences are: permissions (Access), entitlements (Assignment). A new - reader cannot tell from the names which type carries which fields. -- **Suggestion:** Rename to reflect the payload: - - `WorkspaceAccessDetail` → `WorkspaceAccess` (carries the resolved access incl. permissions). - - `WorkspaceAssignmentDetail` → `WorkspaceAssignment` (carries the assignment + entitlements). - Or merge into one type with a discriminator if the platform allows it. -- **Rationale:** `Detail` is fluff. The methods named after these types - (`getWorkspaceAccessDetail`, `listWorkspaceAssignmentDetails`, - `updateWorkspaceAssignmentDetail`, …) inherit the noise. - -### H5. `WorkspaceAccessDetailView` is a Google-style "view" enum but named oddly -- **File:** `model.ts:36-40` -- **Category:** 1, 14 (vague; Google/proto-style) -- **Issue:** Values are `BASIC`, `FULL`. The type is a [Google AIP-157 - view-mask](https://google.aip.dev/157), but the name doesn't surface that - and the values look generic. It's used as `view?: - WorkspaceAccessDetailView` on `GetWorkspaceAccessDetailRequest` / `Local` - variants, but a developer cannot guess from the field name `view` that it - controls response shape. -- **Suggestion:** `enum FieldView { BASIC = 'BASIC', FULL = 'FULL' }`, - reusable across the SDK. Or rename to `WorkspaceAccessView` and document - what each enum value includes/excludes. -- **Rationale:** `Detail` in the name is the same `Detail` flagged in H4 and - carries no extra meaning. - -### H6. `principalType: PrincipalType` — type-suffix tautology pattern -- **File:** `model.ts:312, 328` -- **Category:** 20 (type-suffix tautology) -- **Issue:** The field `principalType: PrincipalType | undefined` appears on - `WorkspaceAccessDetail` and `WorkspaceAssignmentDetail`. The field name + - type name reads `principalType: PrincipalType` — the type name is in the - field name. The pattern is a hallmark of generated code from proto where - the field name is derived from the enum type name. -- **Suggestion:** Drop the type suffix from the enum (`PrincipalKind` - with field `principalType` reading `principal.type = "USER"` works, but - `principal: PrincipalKind` is even cleaner). -- **Rationale:** Tautology adds visual noise without adding meaning. - ---- - -## Medium-severity findings - -### M1. `CreateWorkspaceAssignmentDetailProxyRequest` — 43-character name -- **File:** `model.ts:62`, similarly `DeleteWorkspaceAssignmentDetailProxyRequest`, `UpdateWorkspaceAssignmentDetailProxyRequest`, `ListWorkspaceAssignmentDetailsProxyRequest`, `GetWorkspaceAssignmentDetailProxyRequest` -- **Category:** 7 (overly verbose) -- **Issue:** Five of the request type names are 40+ characters: - `CreateWorkspaceAssignmentDetailProxyRequest` (43 chars), - `DeleteWorkspaceAssignmentDetailProxyRequest` (43), - `UpdateWorkspaceAssignmentDetailProxyRequest` (43), - `ListWorkspaceAssignmentDetailsProxyRequest` (42), - `GetWorkspaceAssignmentDetailProxyRequest` (40). Plus the imports list in - `client.ts` repeats them, doubling the noise. -- **Suggestion:** Once H1 collapses the proxy duplication and H4 drops - `Detail`, these become `CreateWorkspaceAssignmentRequest` etc. — about 30 - chars each. -- **Rationale:** Length itself is not a sin, but `43 chars × 2 × - every-occurrence` is friction. - -### M2. `Local` suffix on `GetWorkspaceAccessDetailLocalRequest` -- **File:** `model.ts:94`, `client.ts:327`, `index.ts:19` -- **Category:** 1, 14 (vague; Java/Go-style) -- **Issue:** `GetWorkspaceAccessDetailLocalRequest` uses a `Local` suffix - that is not defined anywhere in the public types. From `client.ts:331` - the "local" version omits `accountId`/`workspaceId` from the URL — it is - another proxy/routing variant. Why is this one called `Local` while the - others use `Proxy`? -- **Suggestion:** Make it consistent. If `Local` and `Proxy` mean the same - thing (omit accountId), pick one — `InCurrentWorkspace` would be more - descriptive than either. If they differ semantically, document the - difference. -- **Rationale:** Two suffixes for the same routing-variant idea is the - worst possible outcome. - -### M3. `permissions: WorkspacePermission[]` vs `entitlements: Entitlement[]` — conceptually overlapping fields -- **File:** `model.ts:317, 329` -- **Category:** 12, 6 (duplicate concepts; misleading) -- **Issue:** `WorkspaceAccessDetail.permissions` (USER_PERMISSION / - ADMIN_PERMISSION) and `WorkspaceAssignmentDetail.entitlements` - (WORKSPACE_ACCESS, WORKSPACE_ADMIN, …) both encode workspace-level - capabilities of the same principal. Yet they appear on two different - types using two different enum types. Is `WORKSPACE_ADMIN` an - `Entitlement` or a `WorkspacePermission`? -- **Suggestion:** Reconcile the two. If they are different concepts (e.g., - "access scope" vs "assignable capability"), document the distinction in - both JSDoc blocks. If they are the same, merge. -- **Rationale:** This is the kind of overlap that produces support tickets. - -### M4. `resolveByExternalId` method naming -- **File:** `client.ts:101, 159, 229` -- **Category:** 17 (verb inconsistency) -- **Issue:** `resolveGroup`, `resolveUser`, `resolveServicePrincipal`. These - read like "resolve a group" (e.g. resolve a reference), but the actual - semantics is "resolve-or-create using external ID". The method name does - not surface the "or-create" side-effect. The URL hints at it - (`resolveByExternalId`) but the TS method doesn't. -- **Suggestion:** Rename to `resolveByExternalId(req)` taking a discriminated - request type, or `getOrCreateByExternalId`. Document the create-on-miss - semantic prominently. -- **Rationale:** Method names should not hide write side-effects. - ---- - -## Low-severity findings - -### L1. `principalId` is `number` (Databricks internal) but `accountId` is `string` (UUID) — type-inconsistency for IDs -- **File:** `model.ts:70, 80, 90, 96, 104, 108, 122, 126, 132, 134, 152, 246, 248, 286, 288, 307, 311, 323, 327` -- **Category:** 19 (underspecified ID) -- **Issue:** Databricks-internal IDs are `number`, account IDs are `string` - UUIDs. The convention is consistent across the file, but a developer - reading just one type cannot tell which to expect. -- **Suggestion:** Brand the types: `type AccountId = string & { readonly __brand: 'AccountId' }`, - `type PrincipalInternalId = number & { readonly __brand: 'PrincipalInternalId' }`. -- **Rationale:** Type-system disambiguation; out-of-scope for a 1:1 port but - worth noting for any future hardening. - -### L2. `ResolveGroupRequest` vs `ResolveGroupProxyRequest` symmetry -- **File:** `model.ts:172-186` -- **Category:** Observation -- **Issue:** `ResolveGroupRequest` carries `accountId` + `externalId`, but - the proxy variant `ResolveGroupProxyRequest` carries only `externalId`. - The `Response` is the same. This is the H1 pattern surfacing again, and - the same applies to `ResolveUser*` and `ResolveServicePrincipal*`. -- **Suggestion:** Collapse per H1. -- **Rationale:** Pattern, not a new finding. - -### L3. `Group.groupName` doc — "Display name of the group" -- **File:** `model.ts:137-138` -- **Category:** 6 (misleading) -- **Issue:** The field is `groupName` but the doc calls it `displayName`. - Inconsistent naming. -- **Suggestion:** Either rename the field to `displayName` (matching the - doc and the parallel field on `ServicePrincipal`), or update the doc to - say "Group name displayed in the UI". -- **Rationale:** Consistency between the doc and the field name. - ---- - -## Observations (not findings, but worth noting) - -### O1. `Local` only applies to `WorkspaceAccessDetail` (not `WorkspaceAssignmentDetail`) -- **File:** `model.ts:94`, `client.ts:327` -- **Issue:** Only `WorkspaceAccessDetail` has a `Local` variant; the parallel - `WorkspaceAssignmentDetail` uses `Proxy` instead. Inconsistent presence of - the Local/Proxy variants across sibling Detail types. - ---- - -## Cross-cutting recommendations (priority order) - -1. **Collapse `*Proxy` and `*Local` variants (H1, M2, L2, O1).** This - is the largest single improvement and ~halves the public type surface. -2. **Standardize the `State` enum name (H3).** - One name per concept. -3. **Remove type-suffix tautology on the `PrincipalType` enum (H6).** Drop - the type suffix from the enum name. -4. **Drop the `Detail` suffix from the Workspace* types (H4).** - ---- diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index 380c252d..ab8eebd9 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -5,188 +5,77 @@ **Version audited:** `v2` **Files audited:** -- `src/v2/model.ts` (1259 lines, read in full) -- `src/v2/client.ts` (223 lines, read in full) -- `src/v2/utils.ts` (150 lines, read in full) +- `src/v2/model.ts` (1250 lines, read in full) +- `src/v2/client.ts` (224 lines, read in full) +- `src/v2/utils.ts` (156 lines, read in full) - `src/v2/index.ts` (43 lines, read in full) -**Inferred domain:** Databricks instance-pool lifecycle (create / edit / get / -delete / list) of pre-warmed cloud VMs that clusters can draw from. Carries -per-cloud (AWS / Azure / GCP) attributes, disk specifications, Docker preload -configuration, idle / used statistics, and pending-instance failure reporting. - --- ## Summary | Severity | Count | | ------------ | ----- | -| High | 30 | +| High | 3 | | Medium | 3 | -| Low | 28 | -| Observation | 3 | -| **Total** | **64**| - -### Top themes - -1. **Massive structural duplication.** `CreateInstancePoolRequest` (28 fields), - `EditInstancePoolRequest` (29 fields), `GetInstancePoolRequest_Response` - (30 fields), and `InstancePoolAndStats` (30 fields) are byte-identical - apart from one or two fields. They could share a single base type. -2. **Cross-package shape duplication** — eleven types/enums are duplicated - verbatim between this package and `clusters`. A shared `compute` module - would eliminate the dual maintenance burden. - ---- - -## 1. Inventory - -### 1.1 Enums (`model.ts`) - -| Name | Members | Lines | -| --------------------- | -------------------------------------------------- | ---------- | -| `AwsAvailability` | `SPOT`, `ON_DEMAND`, `SPOT_WITH_FALLBACK` | 10-20 | -| `AzureAvailability` | `SPOT_AZURE`, `ON_DEMAND_AZURE`, `SPOT_WITH_FALLBACK_AZURE` | 26-36 | -| `AzureDiskVolumeType` | `PREMIUM_LRS`, `STANDARD_LRS` | 42-47 | -| `EbsVolumeType` | `GENERAL_PURPOSE_SSD`, `THROUGHPUT_OPTIMIZED_HDD` | 53-58 | -| `GcpAvailability` | `PREEMPTIBLE_GCP`, `ON_DEMAND_GCP`, `PREEMPTIBLE_WITH_FALLBACK_GCP` | 64-68 | -| `InstancePoolState` | `ACTIVE`, `STOPPED`, `DELETED` | 78-88 | - -### 1.2 Interfaces (`model.ts`) - -| Name | Lines | Purpose | -| --------------------------------------------------- | -------- | -------------------------------------------------- | -| `CreateInstancePoolRequest` | 90-165 | Request body for create — 28 fields. | -| `CreateInstancePoolRequest_CustomTagsEntry` | 168-181 | Proto-nested tag entry, dead in TS. | -| `CreateInstancePoolRequest_Response` | 184-187 | Response with single `instancePoolId`. | -| `DeleteInstancePoolRequest` | 189-192 | `{ instancePoolId?: string }`. | -| `DeleteInstancePoolRequest_Response` | 195 | Empty `{}`. | -| `DiskSpec` | 203-241 | Disk-attachment spec. | -| `DiskType` | 244-249 | Disc-union wrapper for EBS or Azure disk types. | -| `DockerBasicAuth` | 251-256 | `{ username, password }`. | -| `DockerImage` | 258-268 | `{ url, credsOneof }`. | -| `EditInstancePoolRequest` | 270-347 | Request body for edit — 29 fields. | -| `EditInstancePoolRequest_CustomTagsEntry` | 350-363 | Same as the Create variant — duplicate. | -| `EditInstancePoolRequest_Response` | 366 | Empty `{}`. | -| `GetInstancePoolRequest` | 368-371 | `{ instancePoolId?: string }`. | -| `GetInstancePoolRequest_Response` | 374-469 | 30 fields — superset of `CreateInstancePoolRequest` plus statistics. | -| `GetInstancePoolRequest_Response_CustomTagsEntry` | 472-485 | Third duplicate of the tag-entry shape. | -| `GetInstancePoolRequest_Response_DefaultTagsEntry` | 488-501 | Fourth duplicate of the tag-entry shape. | -| `InstancePoolAndStats` | 503-598 | 30 fields — duplicate of `GetInstancePoolRequest_Response`. | -| `InstancePoolAndStats_CustomTagsEntry` | 601-614 | Fifth duplicate of the tag-entry shape. | -| `InstancePoolAndStats_DefaultTagsEntry` | 617-630 | Sixth duplicate of the tag-entry shape. | -| `InstancePoolAwsAttributes` | 633-668 | AWS-specific config. | -| `InstancePoolAzureAttributes` | 671-682 | Azure-specific config. | -| `InstancePoolGcpAttributes` | 685-707 | GCP-specific config. | -| `InstancePoolStats` | 709-718 | Idle/used counters. | -| `InstancePoolStatus` | 720-728 | Wraps `pendingInstanceErrors`. | -| `ListInstancePoolsRequest` | 731 | Empty `{}`. | -| `ListInstancePoolsRequest_Response` | 734-736 | Wraps `instancePools` array. | -| `NodeTypeFlexibility` | 739-742 | Wraps `alternateNodeTypeIds`. | -| `PendingInstanceError` | 745-748 | `{ instanceId, message }`. | - -### 1.3 Methods (`client.ts`) - -| Method | HTTP | URL path | Returns | -| -------------------- | ------ | --------------------------------- | ------------------------------------ | -| `createInstancePool` | POST | `/api/2.0/instance-pools/create` | `CreateInstancePoolRequest_Response` | -| `deleteInstancePool` | POST | `/api/2.0/instance-pools/delete` | `DeleteInstancePoolRequest_Response` | -| `editInstancePool` | POST | `/api/2.0/instance-pools/edit` | `EditInstancePoolRequest_Response` | -| `getInstancePool` | GET | `/api/2.0/instance-pools/get` | `GetInstancePoolRequest_Response` | -| `listInstancePools` | GET | `/api/2.0/instance-pools/list` | `ListInstancePoolsRequest_Response` | - -### 1.4 Other identifiers - -- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private fields - `host`, `httpClient`, `logger`, `userAgent`. -- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `flattenQueryParams`. +| Low | 25 | +| Observation | 2 | +| **Total** | **33**| --- -## 2. Findings - -### 2.1 Vague / generic names - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| V-01 | `DockerImage.credsOneof` | High | `credsOneof` is a Go/proto-codegen leak — TS readers do not know what "Oneof" means in this context (the wire field uses a protobuf `oneof`). The "creds" abbreviation is also generic. Should be `credentials` (and the union shape itself satisfies the discriminator). | -| V-02 | `Call` type imported from core | Observation | Single-letter capitalized name; comes from `@databricks/sdk-core/api`. Out of scope. | -| V-03 | `DockerImage.url` JSDoc only says "URL of the docker image" — but the field name `url` is already generic at the value-level when destructured outside `DockerImage`. | Low | Acceptable inside the type. | - -### 2.2 Acronym casing inconsistencies — High +## 1. Findings -| ID | Symbol | Severity | Issue | -| ----- | ------------------------------------- | -------- | ----- | -| A-01 | `InstancePoolAwsAttributes` | High | Google TS style says acronyms ≥3 chars get only-first-letter capitalised ("AWS" → "Aws"). The repo follows this (Aws/Azure/Gcp). Acceptable, but contrasts with `EbsVolumeType` where `Ebs` is only 3 chars (same rule, applied consistently). No defect — listed for parity with related audits. | -| A-02 | `InstancePoolAwsAttributes.instanceProfileArn` | Low | "Arn" applies Google TS style for ≥3-char acronyms. Compare with `EbsVolumeType` (same package) and consistent. OK. | -| A-03 | `InstancePoolGcpAttributes.localSsdCount` | Low | "Ssd" is 3 letters; same casing rule. OK. | - -### 2.3 Cryptic abbreviations — Medium +### 1.1 Cryptic abbreviations — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| C-01 | `DockerImage.credsOneof` | High (also V-01) | `creds` and `Oneof` are both opaque outside Go/proto context. | -| C-02 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | -| C-03 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | +| C-01 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | +| C-02 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | -### 2.4 Misleading names — High +### 1.2 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | M-01 | `editInstancePool()` / `EditInstancePoolRequest` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | | M-02 | `InstancePoolStatus` | High | The type carries *only* `pendingInstanceErrors`. The name promises a general "status" but the shape exposes only errors. `InstancePoolPendingErrors` or `InstancePoolFailures` would be more truthful. (`InstancePoolState` is the actual lifecycle state, on the entity itself.) | | M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 28 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | -| M-04 | `preloadedSparkVersions: string[]` with JSDoc "A list containing at most one preloaded Spark image version" | High | Type is `string[]` but the JSDoc enforces a max length of 1. If only one value is allowed, the field should be `preloadedSparkVersion?: string` (singular). The array shape misleads callers into thinking they can pass several. | -### 2.5 Overly verbose / Redundant suffixes — Low +### 1.3 Overly verbose / Redundant suffixes — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | O-01 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | -### 2.6 Singular / plural mismatches — Low / High +### 1.4 Singular / plural mismatches — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| P-01 | `preloadedSparkVersions: string[]` | High (also M-04) | Plural array type but the JSDoc constrains it to at most one element. | -| P-02 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | -| P-03 | `ListInstancePoolsRequest` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | -| P-04 | `ListInstancePoolsRequest_Response.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | +| P-01 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | +| P-02 | `ListInstancePoolsRequest` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | +| P-03 | `ListInstancePoolsResponse.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | -### 2.7 Reserved-word collisions — Medium +### 1.5 Reserved-word collisions — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | R-01 | `DockerImage.credsOneof.$case === 'basicAuth'.basicAuth: DockerBasicAuth` | Low | `basicAuth` is not a reserved word but is duplicated across the `$case` discriminator and the embedded field — `library.lib.basicAuth.basicAuth` style access. | | R-02 | None of the type names collide with TS reserved words. | — | OK. | -### 2.8 Duplicate concepts — Highest in repo - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| D-01 | `CreateInstancePoolRequest` (28 fields, lines 90-165) vs `EditInstancePoolRequest` (29 fields, lines 270-347) | High | Identical except `EditInstancePoolRequest` adds `instancePoolId`. Could share a base type. | -| D-02 | `GetInstancePoolRequest_Response` (30 fields, lines 374-469) vs `InstancePoolAndStats` (30 fields, lines 503-598) | High | **Byte-identical** apart from the type name. Compare line-by-line: identical field set, identical order, identical JSDoc. Two names for the same shape. | -| D-03 | `CreateInstancePoolRequest` vs the `Pool` body inside `InstancePoolAndStats` | High | All 28 config fields appear three times: once on Create, once on Edit (29), once on the entity. Codegen could project from a shared base. | -| D-04 | `InstancePoolAwsAttributes` (this package) vs `AwsAttributes` (`clusters` package) | High | Same domain (AWS attributes for a compute pool / cluster). `clusters` calls them `AwsAttributes`; this package calls them `InstancePoolAwsAttributes`. Both share many fields (availability, zoneId, instanceProfileArn, spotBid…) but `clusters` has additional fields (`ebsVolumeCount`, etc.). Cross-package duplication; a shared `compute` module would fix both. | -| D-05 | `InstancePoolAzureAttributes` / `InstancePoolGcpAttributes` vs `clusters.AzureAttributes` / `clusters.GcpAttributes` | High | Same as D-04 for Azure / GCP. | -| D-06 | `EbsVolumeType`, `AzureDiskVolumeType`, `AwsAvailability`, `AzureAvailability`, `GcpAvailability`, `DockerImage`, `DockerBasicAuth`, `DiskSpec`, `DiskType`, `NodeTypeFlexibility`, `PendingInstanceError` | High | All eleven types/enums are duplicated verbatim in `clusters/src/v2/model.ts` (verified via `grep`). Two packages ship eleven identical shapes. | - -### 2.9 Verb-tense inconsistency — Low +### 1.6 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | T-01 | `createInstancePool`, `deleteInstancePool`, `editInstancePool`, `getInstancePool`, `listInstancePools` | Low | All present-tense imperative — consistent. | | T-02 | `preloadedDockerImages`, `preloadedSparkVersions` (past participle) | Low | Standard for fields that describe a pre-applied state. OK. | -### 2.10 Go / Java-style names — High +### 1.7 Go / Java-style names — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `DockerImage.credsOneof` | High | `Oneof` is a literal proto-keyword leak. No TS reader expects this. See V-01. | -| G-02 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | +| G-01 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | -### 2.11 Generic field names losing meaning — Low +### 1.8 Generic field names losing meaning — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -195,13 +84,13 @@ configuration, idle / used statistics, and pending-instance failure reporting. | F-03 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | | F-04 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | -### 2.12 Field contradicting type domain — Low +### 1.9 Field contradicting type domain — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | K-01 | None observed. All fields are within their type's domain. | — | OK. | -### 2.13 Inconsistent action verbs — Medium +### 1.10 Inconsistent action verbs — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -209,14 +98,14 @@ configuration, idle / used statistics, and pending-instance failure reporting. | AV-02 | `getInstancePool()` (singular) vs `listInstancePools()` (plural) | Low | Correct REST convention. OK. | | AV-03 | `createInstancePool()` / `deleteInstancePool()` / `editInstancePool()` / `getInstancePool()` / `listInstancePools()` — only five verbs | Low | No `start`, `stop`, `pin`, etc. — instance pools are stateless from the API standpoint; the lifecycle is implicit via fewer endpoints than `clusters`. Consistent. | -### 2.14 Long enum values — Low +### 1.11 Long enum values — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | L-01 | `EbsVolumeType.THROUGHPUT_OPTIMIZED_HDD` (24 chars) | Low | Standard AWS terminology; OK. | | L-02 | `AzureDiskVolumeType.STANDARD_LRS` (12 chars) | Low | Short. OK. | -### 2.15 Underspecified IDs — Medium +### 1.12 Underspecified IDs — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -227,86 +116,24 @@ configuration, idle / used statistics, and pending-instance failure reporting. | I-05 | `NodeTypeFlexibility.alternateNodeTypeIds: string[]` | Low | Plural array of node-type IDs; scoped. OK. | | I-06 | `InstancePoolAwsAttributes.zoneId` / `InstancePoolGcpAttributes.zoneId` | Low | Both reuse `zoneId` for the AWS availability zone ("us-west-2a") and GCP availability zone ("us-west1-a"). Same name, two slightly different value formats. Acceptable cross-cloud abstraction. | -### 2.16 Type-suffix tautology — Medium +### 1.13 Type-suffix tautology — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-02). Doubly off. | +| TS-01 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-01). Doubly off. | | TS-02 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | | TS-03 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix the type-name still echoes. | | TS-04 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | -### 2.17 Other observations +### 1.14 Other observations | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| X-01 | `client.ts:197` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | - -### 2.18 Proto-architectural leaks +| X-01 | `client.ts:199` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | -### 1. `DockerImage.credsOneof` — model.ts:261 - -**Why:** `Oneof` is a literal protobuf-keyword suffix. The wire field uses -a proto `oneof`; the TS reader has no business knowing this. TypeScript -already encodes the union shape via the `$case` discriminator pattern, -making the suffix doubly redundant. -**Category:** Proto suffix/infix. -**Suggested:** `credentials`. -**Rationale:** Drop the proto-codegen idiom; the union type expresses the -mutual-exclusion semantics on its own. - -### 2. `DockerImage.credsOneof.$case` / `DiskType.remoteVolumeType.$case` — model.ts:246, 247, 263 - -**Why:** The `$case` discriminator key is a `ts-proto` codegen artefact -(see `ts-proto`'s "oneof=unions" mode). Native TypeScript discriminated -unions use a domain-named tag (e.g., `kind`, `type`). -**Category:** Proto suffix/infix. -**Suggested:** Replace `$case` with a domain tag such as `kind` or `type` -(e.g., `{ kind: 'basicAuth'; basicAuth: DockerBasicAuth }`). -**Rationale:** `$case` is unique to one TS-from-proto codegen tool; it -leaks the generator into the public API. +### 1.15 Proto-architectural leaks -### 3. `CreateInstancePoolRequest_Response` — model.ts:184 - -**Why:** The `_Response` underscore-nested name mirrors the proto-codegen -convention `Outer.NestedMessage`, flattened to `Outer_Nested`. TypeScript -has no nested-message concept; the underscore is purely an architectural -leak from the protobuf compiler. -**Category:** Proto suffix/infix. -**Suggested:** `CreateInstancePoolResponse`. -**Rationale:** Use a top-level response type that pairs with the request -without echoing proto nesting. - -### 4. `DeleteInstancePoolRequest_Response` — model.ts:195 - -**Why:** Same proto-nested underscore as finding #3. -**Category:** Proto suffix/infix. -**Suggested:** `DeleteInstancePoolResponse`. -**Rationale:** Same as #3. - -### 5. `EditInstancePoolRequest_Response` — model.ts:366 - -**Why:** Same proto-nested underscore as finding #3. -**Category:** Proto suffix/infix. -**Suggested:** `EditInstancePoolResponse`. -**Rationale:** Same as #3. - -### 6. `GetInstancePoolRequest_Response` — model.ts:374 - -**Why:** Same proto-nested underscore as finding #3. -**Category:** Proto suffix/infix. -**Suggested:** `GetInstancePoolResponse` (or fold into the entity type -`InstancePool` since the shape is identical to `InstancePoolAndStats`). -**Rationale:** Same as #3. - -### 7. `ListInstancePoolsRequest_Response` — model.ts:734 - -**Why:** Same proto-nested underscore as finding #3. -**Category:** Proto suffix/infix. -**Suggested:** `ListInstancePoolsResponse`. -**Rationale:** Same as #3. - -### 8. `CreateInstancePoolRequest_CustomTagsEntry` — model.ts:168 +### 1. `CreateInstancePoolRequest_CustomTagsEntry` — model.ts:168 **Why:** Proto-nested map-entry type. Protobuf compiles `map` fields into a synthetic `*_Entry` message; TypeScript expresses maps as @@ -317,44 +144,44 @@ unused by the request, which uses `Record` directly **Suggested:** Delete the type. **Rationale:** Dead proto-codegen artefact with no consumer in TS. -### 9. `EditInstancePoolRequest_CustomTagsEntry` — model.ts:350 +### 2. `EditInstancePoolRequest_CustomTagsEntry` — model.ts:349 -**Why:** Same proto-map-entry artefact as #8. +**Why:** Same proto-map-entry artefact as #1. **Category:** Proto suffix/infix. **Suggested:** Delete. -**Rationale:** Same as #8. +**Rationale:** Same as #1. -### 10. `GetInstancePoolRequest_Response_CustomTagsEntry` — model.ts:472 +### 3. `GetInstancePoolResponse_CustomTagsEntry` — model.ts:470 -**Why:** Doubly-nested proto map-entry: `Get…Request → Response → -CustomTagsEntry`. Two underscores in one identifier. +**Why:** Same proto-map-entry artefact as #1 — Protobuf's synthetic +`*_Entry` message for a `map` field, which TypeScript expresses as +`Record`. The type is exported but has no TS consumer. **Category:** Proto suffix/infix. **Suggested:** Delete. -**Rationale:** Same as #8; the double underscore makes the leak even more -visible. +**Rationale:** Same as #1. -### 11. `GetInstancePoolRequest_Response_DefaultTagsEntry` — model.ts:488 +### 4. `GetInstancePoolResponse_DefaultTagsEntry` — model.ts:486 -**Why:** Same doubly-nested proto-map artefact as #10. +**Why:** Same proto-map-entry artefact as #1. **Category:** Proto suffix/infix. **Suggested:** Delete. -**Rationale:** Same as #10. +**Rationale:** Same as #1. -### 12. `InstancePoolAndStats_CustomTagsEntry` — model.ts:601 +### 5. `InstancePoolAndStats_CustomTagsEntry` — model.ts:599 -**Why:** Same proto-map-entry artefact as #8. +**Why:** Same proto-map-entry artefact as #1. **Category:** Proto suffix/infix. **Suggested:** Delete. -**Rationale:** Same as #8. +**Rationale:** Same as #1. -### 13. `InstancePoolAndStats_DefaultTagsEntry` — model.ts:617 +### 6. `InstancePoolAndStats_DefaultTagsEntry` — model.ts:615 -**Why:** Same proto-map-entry artefact as #8. +**Why:** Same proto-map-entry artefact as #1. **Category:** Proto suffix/infix. **Suggested:** Delete. -**Rationale:** Same as #8. +**Rationale:** Same as #1. -### 14. `unmarshalCreateInstancePoolRequest_ResponseSchema` / `marshalCreateInstancePoolRequestSchema` (and 14 sibling marshal/unmarshal exports) — model.ts:751, 761, 764, 780, 797, 807, 821, 825, 885, 945, 960, 971, 984, 998, 1010, 1021, 1030, 1041, 1089, 1097, 1113, 1137, 1147, 1166, 1216, 1230, 1240, 1252 +### 7. `marshalCreateInstancePoolRequestSchema` / `unmarshalCreateInstancePoolResponseSchema` (and 26 sibling marshal/unmarshal exports) — model.ts:747, 756, 759, 775, 792, 802, 815, 818, 878, 938, 953, 964, 977, 991, 1002, 1013, 1022, 1033, 1081, 1089, 1105, 1129, 1139, 1158, 1208, 1222, 1232, 1244 **Why:** `marshal` / `unmarshal` are proto/Go-codegen verbs (cf. Go's `proto.Marshal` / `proto.Unmarshal`, `encoding/json.Marshal`). TypeScript @@ -366,7 +193,7 @@ convention is `encode` / `decode`, `serialize` / `deserialize`, or **Rationale:** The verb pair betrays the Go-SDK ancestry; TS consumers will not recognise it as the standard name for JSON shape transformation. -### 15. `_req: ListInstancePoolsRequest` parameter on `listInstancePools` — client.ts:197 +### 8. `_req: ListInstancePoolsRequest` parameter on `listInstancePools` — client.ts:199 **Why:** Empty request type generated from a proto with no fields, threaded into the public method signature and leading-underscored to @@ -380,33 +207,12 @@ artefact and the leading underscore at the same time. --- -## 3. Severity totals (recap) +## 2. Severity totals (recap) | Severity | Count | | ------------ | ----- | -| High | 30 | +| High | 3 | | Medium | 3 | -| Low | 28 | -| Observation | 3 | -| **Total** | **64**| - -## 4. Cross-package consistency notes - -- **The eleven shared shapes** (`AwsAvailability`, `AzureAvailability`, - `GcpAvailability`, `AzureDiskVolumeType`, `EbsVolumeType`, `DiskSpec`, - `DiskType`, `DockerImage`, `DockerBasicAuth`, `NodeTypeFlexibility`, - `PendingInstanceError`) are duplicated verbatim between this package and - `clusters`. A shared `@databricks/sdk-compute-common` package — or codegen - emitting from a shared schema — would eliminate the dual maintenance burden. -- The `*Attributes` types (`InstancePoolAwsAttributes` etc.) overlap heavily - with `clusters` `AwsAttributes` etc., but the field sets differ. A common - base + extension would still help. - -## 5. File coverage - -- `src/v2/model.ts` (1259 lines): read fully. -- `src/v2/client.ts` (223 lines): read fully. -- `src/v2/utils.ts` (150 lines): read fully. -- `src/v2/index.ts` (43 lines): read fully. - ---- +| Low | 25 | +| Observation | 2 | +| **Total** | **33**| diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index 5b4ef4d9..da9d48a7 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -10,151 +10,47 @@ - `src/v2/utils.ts` - `src/v2/index.ts` -`InstanceProfile` is a specific AWS concept (an AWS IAM Instance Profile -encapsulates an IAM role that an EC2 instance can assume). This audit -catalogues every identifier (type, field, enum value, method, constant) in -the package and flags naming concerns against the 20-category rubric. Issues -are graded: - -- **High** — actively misleading, ambiguous, or violates a TS rule. -- **Medium** — friction; verbose, redundant, or stylistically off. -- **Low** — nit / consistency observation; safe to ignore. - ---- - -## 1. Inventory - -### 1.1 Enums (`model.ts`) - -| Name | Members | -| ---- | ------- | -| _(none)_ | _(no enums declared in this package)_ | - -### 1.2 Interfaces (`model.ts`) - -| Name | Purpose | -| ------------------------------------------ | -------------------------------------------------------- | -| `AddInstanceProfileRequest` | Request body for register/add. | -| `AddInstanceProfileRequest_Response` | Empty response from add. | -| `EditInstanceProfileRequest` | Request body for edit/update. | -| `EditInstanceProfileRequest_Response` | Empty response from edit. | -| `InstanceProfile` | The instance-profile entity (AWS-scoped). | -| `ListInstanceProfilesRequest` | Empty request body for list. | -| `ListInstanceProfilesRequest_Response` | Response from list. | -| `RemoveInstanceProfileRequest` | Request body for unregister/remove. | -| `RemoveInstanceProfileRequest_Response` | Empty response from remove. | - -### 1.3 Fields (entity / request / response — combined catalog) - -| Type | Field | Type / Notes | -| ------------------------------------------ | ------------------------ | ------------------------------------- | -| `AddInstanceProfileRequest` | `skipValidation` | `boolean?` | -| `AddInstanceProfileRequest` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | -| `AddInstanceProfileRequest` | `isMetaInstanceProfile` | `boolean?` | -| `AddInstanceProfileRequest` | `iamRoleArn` | `string?` (AWS IAM role ARN) | -| `AddInstanceProfileRequest_Response` | _(no fields)_ | _(empty body)_ | -| `EditInstanceProfileRequest` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | -| `EditInstanceProfileRequest` | `isMetaInstanceProfile` | `boolean?` | -| `EditInstanceProfileRequest` | `iamRoleArn` | `string?` | -| `EditInstanceProfileRequest_Response` | _(no fields)_ | _(empty body)_ | -| `InstanceProfile` | `instanceProfileArn` | `string?` (AWS ARN, marked required) | -| `InstanceProfile` | `isMetaInstanceProfile` | `boolean?` | -| `InstanceProfile` | `iamRoleArn` | `string?` | -| `ListInstanceProfilesRequest` | _(no fields)_ | _(empty request)_ | -| `ListInstanceProfilesRequest_Response` | `instanceProfiles` | `InstanceProfile[]?` | -| `RemoveInstanceProfileRequest` | `instanceProfileArn` | `string?` (ARN, marked required) | -| `RemoveInstanceProfileRequest_Response` | _(no fields)_ | _(empty body)_ | - -### 1.4 Methods (`client.ts`) - -| Method | Verb | URL path | Returns | -| ----------------------- | ---- | --------------------------------- | --------------------------------------------- | -| `addInstanceProfile` | POST | `/api/2.0/instance-profiles/add` | `AddInstanceProfileRequest_Response` | -| `editInstanceProfile` | POST | `/api/2.0/instance-profiles/edit` | `EditInstanceProfileRequest_Response` | -| `listInstanceProfiles` | GET | `/api/2.0/instance-profiles/list` | `ListInstanceProfilesRequest_Response` | -| `removeInstanceProfile` | POST | `/api/2.0/instance-profiles/remove` | `RemoveInstanceProfileRequest_Response` | - --- -## 2. Findings by Category +## 1. Findings by Category -### 2.1 Vague / generic names — High +### 1.1 Vague / generic names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | V-01 | `InstanceProfile` (interface, `model.ts:64`) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | -### 2.2 Redundant enum prefixes — N/A - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------- | -------- | ----- | -| E-01 | _(no enums in package)_ | — | Nothing to flag. | - -### 2.3 Acronym casing inconsistencies — High - -| ID | Symbol | Severity | Issue | -| ----- | --------------------------------- | -------- | ----- | -| A-01 | `instanceProfileArn` (field) | High | "ARN" is the AWS acronym for Amazon Resource Name (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html). Google TypeScript style says acronyms ≥3 chars take only the first letter capitalised (https://google.github.io/styleguide/tsguide.html#naming-style). `Arn` (capital A, lowercase r/n) is correct under Google style. Flagged only because the field uses the Google convention rather than uppercase `ARN`; both are defensible — keep as-is for Google style compliance. | -| A-02 | `iamRoleArn` (field) | High | Same as A-01. "IAM" (AWS Identity & Access Management) and "ARN" are acronyms; Google TS style lowercases all but the first letter. Currently `iamRoleArn` lowercases the entire `iam` prefix because it is the *first* word in the camel-cased identifier; that is consistent with the rule (the first letter would be lowercase even if the rule said full uppercase, since camelCase always starts lowercased). Defensible. | -| A-03 | `isMetaInstanceProfile` | Low | No acronym issues. | -| A-04 | `Aws` / `Iam` / `Arn` not appearing as type prefixes | Low | The package doesn't have a type-name acronym to test (e.g. no `AWSInstanceProfile`). If the type were renamed per V-01, the chosen casing should be `AwsInstanceProfile` to match Google TS style. | - -### 2.4 Underscores in TS identifiers — Low +### 1.2 Underscores in TS identifiers — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------------------- | -------- | ----- | | U-01 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | -### 2.5 Cryptic abbreviations — Low +### 1.3 Cryptic abbreviations — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | C-01 | `arn` (within `instanceProfileArn`, `iamRoleArn`) | Low | "ARN" is a well-known AWS acronym; not cryptic in the AWS context. Acceptable. | | C-02 | `iam` (within `iamRoleArn`) | Low | "IAM" = AWS Identity & Access Management. Well-known AWS acronym. Acceptable. | -### 2.6 Misleading names — High +### 1.4 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| M-01 | `AddInstanceProfileRequest` / `addInstanceProfile()` (`model.ts:5`, `client.ts:77`) | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | -| M-02 | `RemoveInstanceProfileRequest` / `removeInstanceProfile()` (`model.ts:95`, `client.ts:185`) | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | -| M-03 | `EditInstanceProfileRequest` / `editInstanceProfile()` (`model.ts:39`, `client.ts:119`) | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | -| M-04 | `InstanceProfile.instanceProfileArn` (marked required, but `?: string \| undefined`, `model.ts:66`) | High | The JSDoc says "This field is required" but the TS type is `string \| undefined`. Across the SDK, every field is optional in the generated type; the doc note is informational. Not a name issue per se, but the type contradicts the documented contract. Flagged because the *name* implies it should always be populated, yet the type doesn't enforce it. | +| M-01 | `AddInstanceProfileRequest` / `addInstanceProfile()` (`model.ts:5`, `client.ts:79`) | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | +| M-02 | `RemoveInstanceProfileRequest` / `removeInstanceProfile()` (`model.ts:94`, `client.ts:193`) | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | +| M-03 | `EditInstanceProfileRequest` / `editInstanceProfile()` (`model.ts:39`, `client.ts:121`) | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | -### 2.7 Overly verbose / Redundant suffixes — Low - -_None._ - -### 2.8 Singular / plural mismatches — Low +### 1.5 Singular / plural mismatches — Low | ID | Symbol | Severity | Issue | | ----- | --------------------------------------------------- | -------- | ----- | | P-01 | `ListInstanceProfilesRequest` (plural) vs `listInstanceProfiles()` (plural) | Low | Consistent. | -| P-02 | `ListInstanceProfilesRequest_Response.instanceProfiles` | Low | Plural field for an array — correct. | +| P-02 | `ListInstanceProfilesResponse.instanceProfiles` | Low | Plural field for an array — correct. | | P-03 | `InstanceProfile` (singular entity) vs `instanceProfiles` (plural array) | Low | Correct pluralisation throughout. | | P-04 | `AddInstanceProfileRequest` / `EditInstanceProfileRequest` / `RemoveInstanceProfileRequest` (all singular) | Low | Correct — single-entity operations. | -### 2.9 Reserved-word collisions — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| R-01 | _(no collisions observed)_ | — | No fields use reserved words (e.g. `package`, `class`, `enum`, `delete`). | - -### 2.10 Empty / trivial wrapper types — N/A - -_None._ Wrapper types (empty response interfaces, empty request structs, -and single-field wrappers) exist for forward compatibility: future API -revisions can add fields without breaking the type signature. Not flagged. - -### 2.11 Duplicate concepts — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| D-01 | `InstanceProfile` vs `EditInstanceProfileRequest` vs `AddInstanceProfileRequest` (`model.ts:5`, `model.ts:39`, `model.ts:64`) | Medium | Three types with substantially overlapping field sets (`instanceProfileArn`, `isMetaInstanceProfile`, `iamRoleArn`). `EditInstanceProfileRequest` and `InstanceProfile` are byte-identical; `AddInstanceProfileRequest` adds only `skipValidation`. Could be expressed as a base type with extension. Codegen constraint; flagged for visibility. | -| D-02 | `instanceProfileArn` across all 4 request/entity types | Low | Same field, same semantics — duplication is expected for codegen output. OK. | -| D-03 | `iamRoleArn` across `InstanceProfile`, `AddInstanceProfileRequest`, `EditInstanceProfileRequest` | Low | Same observation as D-02. OK. | - -### 2.12 Verb-tense inconsistency — Low +### 1.6 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -162,20 +58,20 @@ revisions can add fields without breaking the type signature. Not flagged. | T-02 | `isMetaInstanceProfile` (boolean) | Low | Standard `is*` boolean prefix. | | T-03 | `skipValidation` (boolean) | Low | Imperative — consistent boolean style. | -### 2.13 Go / Java-style names — Low +### 1.7 Go / Java-style names — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `RemoveInstanceProfileRequest` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | -### 2.14 Generic field names losing meaning — Low +### 1.8 Generic field names losing meaning — Low | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | -| F-02 | `instanceProfiles` (in `ListInstanceProfilesRequest_Response`) | Low | Self-describing. Good. | +| F-02 | `instanceProfiles` (in `ListInstanceProfilesResponse`) | Low | Self-describing. Good. | -### 2.15 Field contradicting type domain — Medium +### 1.9 Field contradicting type domain — Medium | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -183,7 +79,7 @@ revisions can add fields without breaking the type signature. Not flagged. | FD-02 | `AddInstanceProfileRequest.skipValidation` | Low | A request-only behaviour flag in a "domain entity"-shaped request. Acceptable for an "add"/"create" request type. | | FD-03 | `RemoveInstanceProfileRequest.instanceProfileArn` | Low | Identifier-only payload for delete — appropriate. | -### 2.16 Inconsistent action verbs — High +### 1.10 Inconsistent action verbs — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -193,13 +89,7 @@ revisions can add fields without breaking the type signature. Not flagged. | AV-04 | `removeInstanceProfile` (vs `deleteInstanceProfile` / `unregisterInstanceProfile`) | High | Same observation as AV-03. The method un-registers, not deletes. `unregisterInstanceProfile` would be most precise. See M-02. | | AV-05 | `listInstanceProfiles` (vs `getInstanceProfiles`) | Low | Correct: `list*` for plural retrieval, `get*` for singular. Consistent. | -### 2.17 Long enum values — N/A - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------- | -------- | ----- | -| L-01 | _(no enums in package)_ | — | Nothing to flag. | - -### 2.18 Underspecified IDs — High +### 1.11 Underspecified IDs — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | @@ -207,74 +97,16 @@ revisions can add fields without breaking the type signature. Not flagged. | I-02 | `iamRoleArn` | Low | Well-specified: scope (IAM role), type (ARN). Good. | | I-03 | Absence of `instanceProfileId` | Low | The package uses ARN as the sole identifier — there is no separate "ID" concept. Good (no ambiguity between `id` and `arn`). | -(Section retained for parity with the rubric; no high findings — the -package is exemplary in using ARNs as identifiers.) - -### 2.19 Type-suffix tautology — N/A - -_None._ - -### 2.20 Other observations - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| X-01 | `Client` (the class name itself, `client.ts:46`) | Medium | The class is just `Client`. The package exports it as the top-level symbol, but a reader importing it as `import {Client} from '@databricks/sdk-instanceprofiles/v2'` may collide with other packages' `Client`. Most consumers will alias it (`InstanceProfilesClient`); flagging that the bare name doesn't carry scope. This is a repo-wide pattern (every package exports `Client`); not a per-package fix. | - --- -## 3. Summary +## 2. Summary -### 3.1 Findings by severity +### 2.1 Findings by severity | Severity | Count | | -------- | ----- | -| High | 9 | -| Medium | 5 | -| Low | 23 | -| **Total**| **37**| - -### 3.2 Top themes - -1. **`add` / `remove` verbs mislead about scope.** The methods **register** / - **unregister** an existing AWS instance profile with Databricks — neither - creates nor deletes the underlying AWS resource. `register*` / `unregister*` - would be more accurate. Compounded by `edit*` (instead of `update*`) breaking - the CRUD verb consistency. - -2. **`InstanceProfile` is AWS-specific but not cloud-prefixed.** In a - multi-cloud SDK, an unqualified name implies a cross-cloud concept it - doesn't represent. `AwsInstanceProfile` (matching `AzureServicePrincipal`, - `GcpAttributes`) would prevent future ambiguity. - -### 3.3 Suggested quick wins (non-breaking renames are not possible — this section is advisory for the codegen owners) - -- Rename `InstanceProfile` → `AwsInstanceProfile` to scope to the cloud. -- Rename `addInstanceProfile` → `registerInstanceProfile` and - `removeInstanceProfile` → `unregisterInstanceProfile` to match actual - semantics. -- Rename `editInstanceProfile` → `updateInstanceProfile` for CRUD consistency. - -### 3.4 Cross-package consistency notes - -- `editInstanceProfile` (vs `updateInstanceProfile`) is a per-API decision - driven by the upstream REST verb; flag for upstream alignment but no - per-package fix. -- `Client` as the exported class name is repo-wide; aliasing on import is - the de-facto solution. - ---- - -## Proto-Architectural Leaks - -_None._ Scanned every identifier (interfaces, fields, methods, locals, -constants) in `model.ts`, `client.ts`, `utils.ts`, and `index.ts` for the -flagged patterns: `Public`/`Internal`/`External` mid-position, `Proto` -suffix/infix, `Service`/`Server`/`Backend`/`Frontend`, `Rpc`/`Grpc`, -`Manager`/`Handler`/`Controller`/`Processor`/`Daemon`/`Worker`, `Impl`, -non-real `Proxy`, mid-position `Action`/`Op` duplicating a verb, -`Wrapper`/`Adapter`, `Old`/`New`/`Legacy`/`Modern`, mid-position -`V1`/`V2`, mid-position `Api`/`Sdk`/`Client`, repeated -`Spec`/`Config`/`Details`/`Info`, and `Foo_PublicRequest`-style -visibility infixes. No matches. The package is exemplary on this rubric. - ---- +| High | 6 | +| Medium | 3 | +| Low | 19 | +| Observation | 0 | +| **Total**| **28**| diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index 321d993f..41f3813e 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -1,165 +1,106 @@ # Naming Audit: `@databricks/sdk-jobs` (v2) -Scope: `packages/jobs/src/v2/` — `model.ts` (10030 lines), `client.ts` (1289 lines), -`utils.ts` (150 lines), `index.ts` (284 lines). This is the largest API surface in -the SDK and exposes ~140 interfaces, 47 enums, and 19 client methods. +Path: `packages/jobs/src/v2/` +Versions: v2 +Files: `model.ts` (10210 lines), `client.ts` (1249 lines), `utils.ts` (180 lines), +`transport.ts` (73 lines), `index.ts` (284 lines). +Total findings: 55 +Last rescanned: 2026-06-02 ## Summary Table | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------ | -| High | 24 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | -| Medium | 41 | Redundant prefixes/suffixes, vague names, acronym casing, pluralization. | -| Low | 21 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 11 | Patterns spanning the entire file (oneof wrappers, ID typing, etc.). | -| **Total** | **97** | | - -Issues are catalogued below by severity, then by file/line. +| High | 14 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | +| Medium | 22 | Redundant prefixes/suffixes, vague names, pluralization. | +| Low | 15 | Mild verbosity, plural mismatches, stylistic inconsistencies. | +| Observations | 4 | Patterns spanning the entire file (oneof wrappers, type design, etc.). | +| **Total** | **55** | | --- ## High -### H1. `Run` is overloaded across at least seven shapes -- **Location:** `model.ts:3399` (`Run`), `model.ts:908` (`BaseRun`), `model.ts:3875` (`RunTask`), `model.ts:3491` (`Run_JobLevelParameters`), `model.ts:3852` (`RunState`), `model.ts:3866` (`RunStatus`), `model.ts:4261` (`RunTriggerInfo`). -- **Category:** Vague/generic + duplicate concepts (#1, #12). -- **Suggestion:** Treat `Run` as a domain concept and only use the bare token on the canonical job run. Rename `RunTask` -> `TaskRun` (it represents a task **run**, not a run-task), and rename `Run` -> `JobRun` for symmetry with `JobRunId`, `numberInJob`, `runType: JOB_RUN`. -- **Rationale:** Currently `BaseRun`, `Run`, `RunTask`, and the `RunStatus.state` field all describe overlapping shapes. Authors must read JSDoc to know which is which. `RunTask` reading order "task that is a run" is opposite to its actual meaning ("the run of a task"). - -### H2. `RunTask` and `TaskSettings` are nearly identical but named asymmetrically -- **Location:** `model.ts:3875` (`RunTask`), `model.ts:4676` (`TaskSettings`), `model.ts:4085` (`RunTaskSettings`). -- **Category:** Duplicate concepts (#12), misleading names (#6). -- **Suggestion:** Use `TaskRun` (the runtime/output form) and `Task` (the design-time form). Drop `RunTaskSettings` in favour of `SubmitTask` if it is submit-specific. -- **Rationale:** A reader sees three shapes (`RunTask`, `TaskSettings`, `RunTaskSettings`) carrying the same union of task types and cannot tell which to use without grepping. The naming pattern (`RunX` for "X on a run", `XSettings` for "X on a job") is undocumented. - -### H3. `Format` (top-level public enum) is a reserved-word collision +### H1. `Format` (top-level public enum) is a reserved-word collision - **Location:** `model.ts:151`. - **Category:** Reserved-word collisions (#10), vague/generic (#1). - **Suggestion:** Rename to `JobFormat`. - **Rationale:** `Format` is a well-known global (the `Intl.NumberFormat`/`Intl.DateTimeFormat` family, `console.format` in some runtimes, and a built-in name in many code-generators). Importing `Format` from a Jobs SDK forces consumers to alias it. -### H4. `Source` (top-level public enum) clashes with global Web/TS names +### H2. `Source` (top-level public enum) clashes with global Web/TS names - **Location:** `model.ts:257`. - **Category:** Reserved-word collisions (#10), vague/generic (#1). - **Suggestion:** Rename to `TaskSource`, `CodeSource`, or `FileSource` (only two values: `WORKSPACE`, `GIT`). - **Rationale:** `Source` is the name of the DOM `EventSource` shorthand, Web Audio `AudioBufferSourceNode`, RxJS `Source`, several stream libraries, and lint rules around it. With only two values describing where SQL/Notebook/dbt code lives, a domain prefix is essential. -### H5. `Compute` interface clashes with the larger Databricks Compute API +### H3. `Compute` interface clashes with the larger Databricks Compute API - **Location:** `model.ts:1362`. - **Category:** Vague/generic (#1), misleading names (#6). - **Suggestion:** Rename to `TaskComputeOverride` or `TaskCompute` — the type wraps only `hardwareAccelerator` for serverless GPU. - **Rationale:** A consumer would expect `Compute` to describe an entire compute target (cluster spec, node type, runtime, etc.). It actually has one field. This is the worst "field contradicting type domain" case in the file (#16). -### H6. `Environment` overload — minimal interface, generic word -- **Location:** `model.ts:1787`. +### H4. `Environment` overload — minimal interface, generic word +- **Location:** `model.ts:1785`. - **Category:** Vague/generic (#1), reserved-word collision (#10). - **Suggestion:** Rename to `TaskEnvironment` (matching the per-task `environment_key` reference) or `EnvironmentSpec`. - **Rationale:** `Environment` is a host-level concept in Node (`process.env`) and a common UI/test-framework type. Inside this file it is a tiny dep-list + base-env reference; it is referenced as `JobEnvironment.spec: Environment`, so a `Spec` suffix matches its role. -### H7. `Repair` lacks a noun and is mistaken for a verb -- **Location:** `model.ts:3082`. +### H5. `Repair` lacks a noun and is mistaken for a verb +- **Location:** `model.ts:3084`. - **Category:** Verb-tense inconsistency (#13), vague/generic (#1). - **Suggestion:** Rename to `RepairHistoryEntry` (or `RepairAttempt`) — it represents a single past repair. -- **Rationale:** The verb `repair()` exists on the client (`client.ts:781`), and `RepairRunRequest`/`RepairRunRequest_Response` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. +- **Rationale:** The verb `repair()` exists on the client (`client.ts:769`), and `RepairRunRequest`/`RepairRunResponse` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. -### H8. `Webhook` is a generic top-level name that collides with the platform `Webhook` concept +### H6. `Webhook` is a generic top-level name that collides with the platform `Webhook` concept - **Location:** `model.ts:4938`. - **Category:** Vague/generic (#1), reserved-word/global collision (#10). - **Suggestion:** Rename to `WebhookRef` (or `JobWebhook`) — readers grep `Webhook` expecting the request/payload shape, but the actual Webhook _payload_ is `WebhookNotifications`. The bare `Webhook` token is the wrong claimant for that name. - **Rationale:** "Webhook" is a broad industry term and the actual delivery payload lives under a different identifier; the unqualified type-name should belong to the canonical shape, not to a Jobs-specific reference. -### H9. `Subscription` and `AlertTaskSubscriber` / `SqlTaskSubscription` are three near-identical shapes -- **Location:** `model.ts:4607` (`Subscription`), `model.ts:741` (`AlertTaskSubscriber`), `model.ts:4531` (`SqlTaskSubscription`), `model.ts:4620` (`Subscription_Subscriber`). -- **Category:** Duplicate concepts (#12), inconsistent naming (#17). -- **Suggestion:** Standardize on `Subscriber` for the leaf type and `SubscriptionList` (or just `Subscription`) for the container. Avoid mixing `Subscriber` (alert), `Subscription` (sql), and `Subscription_Subscriber` (dashboard). -- **Rationale:** Each task type re-invents the same `userName | destinationId` oneof under a different name. This is a porting artifact, not a domain distinction. - -### H10. `Run.numberInJob` always equals `Run.runId` — meaningless field -- **Location:** `model.ts:3407`, `model.ts:916`, `model.ts:3744`. +### H7. `Run.numberInJob` always equals `Run.runId` — meaningless field +- **Location:** `model.ts:3408`, `model.ts:916`, `model.ts:2137`. - **Category:** Misleading names (#6), generic field names losing meaning (#15). - **Suggestion:** Drop or alias; if it must stay for back-compat, document the duplication on the field rather than the type. - **Rationale:** The comment "This is set to the same value as `run_id`" makes the field a no-op. New TS users will assume it's distinct. -### H11. `RunNowRequest_Response.numberInJob` reused -- **Location:** `model.ts:3744`. +### H8. `RunNowResponse.numberInJob` reused +- **Location:** `model.ts:3752`. - **Category:** Misleading names (#6). -- **Suggestion:** Same as H10 — remove or rename to `runIdAlias`. +- **Suggestion:** Same as H7 — remove the field, or document the duplication on the field if it must stay for back-compat. - **Rationale:** Same dead duplication on the response. -### H12. `TaskDependencyType.NONE_FAILED` reads as a negation, not a condition -- **Location:** `model.ts:282`. -- **Category:** Misleading names (#6). -- **Suggestion:** Document inline, or rename to `NO_FAILURES_AT_LEAST_ONE_RAN`. Alternatively, `AT_LEAST_ONE_SUCCESS_NONE_FAILED`. -- **Rationale:** The enum-level JSDoc clarifies "none failed AND at least one was executed" — this is non-obvious from the name. - -### H13. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion -- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2556`, `model.ts:2564`. +### H9. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion +- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2561`, `model.ts:2569`. - **Category:** Singular/plural mismatch (#9), redundant suffixes (#8). - **Suggestion:** `JobsHealthRule` and `JobsHealthRules` differ only by `s` and the inner wraps a `rules?: JobsHealthRule[]`. Flatten — make the array the public shape (call it `HealthRules` or just `HealthRule[]`). - **Rationale:** Hairsplitting wrappers around arrays force consumers to write `{rules: [...]}` instead of `[...]`. Plural type names alongside singular ones are the most error-prone pattern in this file. -### H14. `JobsHealth*` prefix is inconsistent — `Jobs` is plural -- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2556`, `model.ts:2564`. +### H10. `JobsHealth*` prefix is inconsistent — `Jobs` is plural +- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2561`, `model.ts:2569`. - **Category:** Singular/plural mismatch (#9), Go/Java-style names (#14). - **Suggestion:** Use the singular product noun: `JobHealthMetric`, `JobHealthRule`. Or just `HealthMetric` if global. - **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). -### H15. `RunNowRequest_Response.runId` field is the "newly triggered run" — confusingly typed `number` -- **Location:** `model.ts:3742`. -- **Category:** Underspecified IDs (#19). -- **Suggestion:** Add a branded type alias `RunId = number & {readonly __brand: 'RunId'}` or use `string` to match `bigint`-safe APIs. -- **Rationale:** Run IDs exceed Number.MAX_SAFE_INTEGER (~9e15) for long-lived workspaces. The current `number` typing silently lossy-truncates; consumers cannot distinguish `runId`, `jobId`, `taskRunId`, `repairId`, `originalAttemptRunId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId` (string!). - -### H16. `DbtCloudTaskOutput.dbtCloudJobRunId: number` but `DbtPlatformTaskOutput.dbtPlatformJobRunId: string` -- **Location:** `model.ts:1605`, `model.ts:1637`. -- **Category:** Field contradicting type domain (#16), misleading names (#6). -- **Suggestion:** Standardize on `string` for upstream IDs; note in JSDoc. -- **Rationale:** Same semantic field encoded as two different TS types in adjacent interfaces is a bug magnet. - -### H17. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous -- **Location:** `model.ts:3500`. +### H11. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous +- **Location:** `model.ts:3501`. - **Category:** Misleading names (#6). -- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per JSDoc on line 3976). +- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per the oneof JSDoc on line 3976). - **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? -### H18. `BaseJob` and `GetJobRequest_Response` and `Run` duplicate ~10 identical fields -- **Location:** `model.ts:874`, `model.ts:1973`, `model.ts:3399`, `model.ts:908`. -- **Category:** Duplicate concepts (#12). -- **Suggestion:** Extract a shared `JobIdentity` / `JobCoreFields` interface or use TS `Pick`/`Omit` on a base shape. -- **Rationale:** Fields like `jobId`, `creatorUserName`, `runAsUserName`, `settings`, `createdTime`, `triggerState`, `hasMore`, `effectiveBudgetPolicyId`, `effectiveUsagePolicyId` are repeated verbatim in `BaseJob` and `GetJobRequest_Response`. Diverges silently. - -### H19. `RunStatus.state` (V2) vs `RunState.lifeCycleState` (V1) — same concept, different field names + different enums -- **Location:** `model.ts:3852`, `model.ts:3866`. -- **Category:** Duplicate concepts (#12), versioned API leakage (#11). -- **Suggestion:** Pick `RunStatus` as the canonical shape, deprecate `RunState`, and document the deprecation in the rule. -- **Rationale:** The JSDoc on `Run.state` already says "Deprecated. Please use the `status` field instead." but the type is still exported and still shows up in the union. - -### H20. `MAXIMUM_CONCURRENT_RUNS_REACHED` (CleanRoom) vs `MAX_CONCURRENT_RUNS_REACHED` (queue) vs `MAX_CONCURRENT_RUNS_EXCEEDED` (termination) -- **Location:** `model.ts:390`, `model.ts:478`, `model.ts:542`, `model.ts:662`. -- **Category:** Inconsistent naming (#17). -- **Suggestion:** Normalize to one form. The `MAX_` form is more common; reach-vs-exceed should pick one verb. -- **Rationale:** Three enums describe the same overflow scenario with three different names. Consumers cannot write a generic handler. - -### H21. `client.exportRun` returns `ExportRunRequest_Response` which contains a `views` array of `ViewItem` -- **Location:** `client.ts:449`, `model.ts:1830`, `model.ts:4920`. +### H12. `client.exportRun` returns `ExportRunResponse` which contains a `views` array of `ViewItem` +- **Location:** `client.ts:440`, `model.ts:1825`, `model.ts:4920`. - **Category:** Vague/generic (#1). - **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. - **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. -### H22. `ViewType` enum vs `ViewsToExport` enum — overlapping but disjoint -- **Location:** `model.ts:327`, `model.ts:337`. -- **Category:** Duplicate concepts (#12). -- **Suggestion:** Merge or namespace: `View.Type` (NOTEBOOK | DASHBOARD) and `View.ExportSelector` (CODE | DASHBOARDS | ALL). -- **Rationale:** Two enums about "views" with different value sets and intent. Users will pick the wrong one. - -### H23. `cancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` -- **Location:** `client.ts:971-1048`. +### H13. `CancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` +- **Location:** `client.ts:986-997` (and the identical blocks in `RepairWaiter` at `client.ts:1059-1070`, `RunNowWaiter` at `client.ts:1132-1143`, `SubmitRunWaiter` at `client.ts:1205-1216`). - **Category:** Versioned API leakage. - **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. -- **Rationale:** Future deprecation of V1 will silently break all four waiters. +- **Rationale:** Every waiter's `wait()` reads `pollResp.state?.lifeCycleState` against `RunLifeCycleState_RunLifeCycleState`; future deprecation of V1 will silently break all four waiters. -### H24. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers -- **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3615` (`RunLifecycleStateV2` wrapper interface), `model.ts:3867` (`RunStatus.state: RunLifecycleStateV2_State`). +### H14. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers +- **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3616` (`RunLifecycleStateV2` wrapper interface), `model.ts:3867` (`RunStatus.state: RunLifecycleStateV2_State`). - **Why:** `V2` mid-token in a type name records that the upstream schema versioned this enum, not anything a JS consumer needs. The V1 type already lives at `RunLifeCycleState` / `RunLifeCycleState_RunLifeCycleState`; the V2 variant should adopt a domain-meaningful name rather than a version-stamped one. - **Category:** Proto-architectural-leak (`V2` mid-position). - **Suggested:** Rename the wrapper to `RunLifecycleState` (singular, modern) and the enum to `RunLifecycleState_State` — then mark the legacy `RunLifeCycleState` family `@deprecated`. If the V1 type must keep its current name for back-compat, rename the V2 family to `RunPhase` or `RunLifecycleStatus` (anything that says "this is the new shape" without encoding the version number). @@ -169,243 +110,130 @@ Issues are catalogued below by severity, then by file/line. ## Medium -### M1. `Adlsgen2Info` casing — should be `ADLSGen2Info` or `AdlsGen2Info` -- **Location:** `model.ts:706`, `index.ts:60`. -- **Category:** Acronym/word casing (#3). -- **Suggestion:** Use `AdlsGen2Info` (acronym + version + "Info"). ADLS stays uppercase only when alone. -- **Rationale:** The Google TS style guide treats acronyms longer than two letters as words (e.g. `Adls`), but `gen2` should be `Gen2`. - -### M2. `AwsAttributes` / `AzureAttributes` / `GcpAttributes` — accept casing -- **Location:** `model.ts:766`, `model.ts:846`, `model.ts:1870`. -- **Category:** Acronym casing (#3). -- **Suggestion:** OK as `Aws/Azure/Gcp`, consistent with style guide. -- **Rationale:** All three already follow "first letter only" — good baseline. - -### M3. `DbtTask` / `DbtCloudTask` / `DbtPlatformTask` / `DbtPlatformJobRunStep` — acronym casing -- **Location:** `model.ts:1646`, `model.ts:1595`, `model.ts:1628`, `model.ts:1613`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Already follows "Dbt"; OK. -- **Rationale:** Three-letter ID treated as a word — consistent. - -### M4. `EbsVolume*` and `Ebs*` — keep -- **Location:** `model.ts:813`, `model.ts:832`, `model.ts:838`, `model.ts:144`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Keep as `Ebs*`. Consistent with TS style guide. -- **Rationale:** — - -### M5. `GcsStorageInfo` — `Gcs` casing -- **Location:** `model.ts:1927`. -- **Category:** Acronym casing (#3). -- **Suggestion:** OK; consistent with file. - -### M6. `S3StorageInfo` — `S3` (number) keeps caps -- **Location:** `model.ts:4267`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Keep — `S3` is a brand name, kept as-is. - -### M7. `Dbfs*` types — keep -- **Location:** `model.ts:1574`, `model.ts:106`. -- **Category:** Acronym casing (#3). -- **Suggestion:** OK; consistent. - -### M8. `PowerBi*` casing (vs `PowerBI`) -- **Location:** `model.ts:2970`, `model.ts:2983`, `model.ts:2994`, `model.ts:173-175`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Brand-style "BI" is industry-standard caps; consider `PowerBI*`. The Microsoft brand is "Power BI". Currently mixed: type uses `PowerBi`, JSDoc uses `Power BI`. -- **Rationale:** Per the TS style guide, "BI" is an acronym (Business Intelligence), so `PowerBI` is correct. Going with `PowerBi` is inconsistent with `SqlTask` (3 letters). - -### M9. `SqlTask` / `SqlAlertState` / etc. — `Sql` lower or upper? -- **Location:** `model.ts:4365`, `model.ts:4363`, `model.ts:558`, `model.ts:565`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Either `Sql` everywhere (current) or `SQL` everywhere. Pick one. -- **Rationale:** The TS style guide allows acronyms of 3+ letters to be word-cased (`Sql`); this is consistent in this file. Note however the JSDoc still writes "SQL" — fine for prose. - -### M10. `HardwareAcceleratorType` enum values `GPU_1xA10`, `GPU_8xH100` (lowercase `x`) -- **Location:** `model.ts:171-176`. +### M1. `HardwareAcceleratorType` enum values `GPU_1xA10`, `GPU_8xH100` (lowercase `x`) +- **Location:** `model.ts:173-175`. - **Category:** Naming convention violation in enum value strings. - **Suggestion:** The TS enum keys are properly `GPU_1X_A10`, but the values keep the wire form. This is OK since the wire is contract — but flag the asymmetry inline. - **Rationale:** Wire compatibility forces lowercase `x`; the enum key uppercase is fine. -### M11. `TriggerType.RUN_JOB_TASK` is named after a task type, not a trigger -- **Location:** `model.ts:316`. -- **Category:** Misleading names (#6). -- **Suggestion:** Rename to `RUN_JOB`. -- **Rationale:** "Run Job Task" duplicates the task-type tag inside an enum about triggers. - -### M12. `RuntimeEngine.NULL` (versus `STANDARD`, `PHOTON`) -- **Location:** `model.ts:237`. -- **Category:** Reserved-word collision (#10), vague/generic (#1). -- **Suggestion:** Rename to `DEFAULT` or `UNSPECIFIED`. `NULL` is a TS/JS keyword (lowercase `null`) and reserved word in other languages. - -### M13. `JobsHealthMetric.RUN_DURATION_SECONDS` — long but OK +### M2. `JobsHealthMetric.RUN_DURATION_SECONDS` — long but OK - **Location:** `model.ts:199`. - **Category:** Long enum values (#18). - **Suggestion:** Acceptable. -### M14. `JobsHealthMetric.STREAMING_BACKLOG_*` (4 values) +### M3. `JobsHealthMetric.STREAMING_BACKLOG_*` (4 values) - **Location:** `model.ts:200-203`. - **Category:** Long enum values (#18). - **Suggestion:** Acceptable; consider grouping into a nested enum if the four become five. -### M15. `CleanRoomsNotebookTask` (plural "Rooms") vs `CleanRoomTaskRunState` (singular) -- **Location:** `model.ts:1041`, `model.ts:1026`. -- **Category:** Singular/plural mismatch (#9). -- **Suggestion:** Pick one. `CleanRoom*` (singular) is consistent with the standalone product "Clean Rooms" being treated as a singular feature. - -### M16. `clean_room_name` (snake_case in wire) → `cleanRoomName` (good); but JSDoc switches to `cleanrooms` in URL -- **Location:** `model.ts:1043`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Acceptable; brand inconsistency is upstream's responsibility. - -### M17. `Repair.type` (RepairType) is a reserved-ish word -- **Location:** `model.ts:3084`, `model.ts:4926`. +### M4. `Repair.type` (RepairType) is a reserved-ish word +- **Location:** `model.ts:3086`, `model.ts:215`. - **Category:** Reserved-word collision (#10). - **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. -### M18. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK -- **Location:** `model.ts:3634`, `model.ts:4570`. +### M5. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK +- **Location:** `model.ts:3635`, `model.ts:4570`. - **Category:** Verbose but precise. -### M19. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern -- **Location:** `model.ts:3111-3117`. +### M6. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern +- **Location:** `model.ts:3113-3119`. - **Category:** Consistent prefix; OK. -### M20. `DockerImage.credsOneof` — exposes proto oneof name to TS -- **Location:** `model.ts:1715`. -- **Category:** Go/Java-style names (#14). -- **Suggestion:** Rename to `credentials` or `auth`. - -### M21. `JobRunAs.identity` — OK -- **Location:** `model.ts:2398`. +### M7. `JobRunAs.identity` — OK +- **Location:** `model.ts:2403`. -### M22. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix -- **Location:** `model.ts:2340`. +### M8. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix +- **Location:** `model.ts:2333`. - **Category:** Acceptable; key is the lookup pattern. -### M23. `JobEnvironment.environmentKey` — same pattern, OK. -- **Location:** `model.ts:2381`. +### M9. `JobEnvironment.environmentKey` — same pattern, OK. +- **Location:** `model.ts:2386`. -### M24. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy -- **Location:** `model.ts:4682`, `model.ts:3902`, `model.ts:4091`, `model.ts:4671`. +### M10. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy +- **Location:** `model.ts:4681`, `model.ts:3902`, `model.ts:4091`, `model.ts:4670`. - **Category:** Verbose but precise. -### M25. `ResolvedValues` interface has 11 single-purpose sub-types -- **Location:** `model.ts:3247-3397`. +### M11. `ResolvedValues` interface has 11 single-purpose sub-types +- **Location:** `model.ts:3248-3398`. - **Category:** Verbose; many shapes for one purpose. - **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. -### M26. `BaseRun.numberInJob` — meaningless field (see H10) +### M12. `BaseRun.numberInJob` — meaningless field (see H7) - **Location:** `model.ts:916`. -### M27. `BaseRun.originalAttemptRunId` — verbose, but precise. +### M13. `BaseRun.originalAttemptRunId` — verbose, but precise. -### M28. `Run.runId` (inside `Run`) — tautological -- **Location:** `model.ts:3403`, `model.ts:912`, `model.ts:2140`, `model.ts:3877`. +### M14. `Run.runId` (inside `Run`) — tautological +- **Location:** `model.ts:3404`, `model.ts:912`, `model.ts:2133`, `model.ts:3877`. - **Category:** Type-suffix tautology (#20). - **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. -### M29. `Run.tasks: RunTask[]` — same `tasks` field also exists on `BaseRun`, `Run`, `GetRunRequest_Response` — could be deduped -- **Location:** `model.ts:942`, `model.ts:3433`, `model.ts:2170`. - -### M30. `RunNowRequest_Response.numberInJob` (see H11). +### M15. `RunNowResponse.numberInJob` (see H8). -### M31. `Source` enum — only `WORKSPACE`/`GIT` — could be a literal type -- **Location:** `model.ts:257`. -- **Category:** Type design. -- **Suggestion:** Could be `type CodeSource = 'WORKSPACE' | 'GIT'`. Same for `Format`, `ViewType`, etc. - -### M32. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead +### M16. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead - **Location:** `model.ts:151-154`. - **Category:** Dead enum value. -### M33. `AlertEvaluationState_AlertEvaluationState.UNKNOWN` -- **Location:** `model.ts:355`. -- **Category:** Generic enum value (#1). -- **Suggestion:** `UNKNOWN` is universally vague; consider `NOT_EVALUATED`. - -### M34. `SqlTask_SqlTaskQueryStatus.CANCELLED` (double-L) vs `RunResultState_RunResultState.CANCELED` (single-L) vs `DbtPlatformRunStatus.CANCELLED` (double-L) -- **Location:** `model.ts:570`, `model.ts:541`, `model.ts:137`. -- **Category:** Inconsistent naming (#17). -- **Suggestion:** Pick one spelling; "canceled" (single-L) is the American spelling, "cancelled" is the British. Cross-checking with go SDK keeps wire compat. - -### M35. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +### M17. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized - **Location:** `model.ts:4967`, `model.ts:4971`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Rename to `ClientTypes`. -### M36. `RCranLibrary` capitalization — should be `CranLibrary` (R is a language; doesn't need to lead) -- **Location:** `model.ts:3075`. -- **Category:** Acronym casing (#3). -- **Suggestion:** Cran is an acronym (CRAN = Comprehensive R Archive Network). `RLibrary` works too. The `R` prefix is from the Go SDK. - -### M37. `PythonPyPiLibrary` — duplicate "Py" prefix -- **Location:** `model.ts:3026`. +### M18. `PythonPyPiLibrary` — duplicate "Py" prefix +- **Location:** `model.ts:3028`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). -### M38. `MavenLibrary.coordinates` — common, accept. -- **Location:** `model.ts:2797`. +### M19. `MavenLibrary.coordinates` — common, accept. +- **Location:** `model.ts:2800`. -### M39. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. +### M20. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. -### M40. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. +### M21. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. -### M41. `ListRunsRequest.runType` shouldn't be optional when the API permits a default -- **Location:** `model.ts:2753`. +### M22. `ListRunsRequest.runType` shouldn't be optional when the API permits a default +- **Location:** `model.ts:2756`. - **Category:** Default semantics. --- ## Low -### L1. `Adlsgen2Info` — see M1. -### L2. `WorkloadType_ClientsTypes` — see M35. +### L1. `WorkloadType_ClientsTypes` — see M17. -### L3. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). +### L2. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). +- **Location:** `model.ts:2987-2991`. -### L4. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. +### L3. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. -### L5. `QueueDetails.message` and `QueueDetails.code` — OK. +### L4. `QueueDetails.message` and `QueueDetails.code` — OK. +- **Location:** `model.ts:3060-3066`. -### L6. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. -- **Location:** `model.ts:2909`. +### L5. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. +- **Location:** `model.ts:2911`. -### L7. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. +### L6. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. -### L8. `WebhookNotifications.onStreamingBacklogExceeded` — accept. +### L7. `WebhookNotifications.onStreamingBacklogExceeded` — accept. -### L9. `ContinuousSettings.taskRetryMode` (enum) — OK. +### L8. `ContinuousSettings.taskRetryMode` (enum) — OK. -### L10. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. +### L9. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. -### L11. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. +### L10. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. -### L12. `CronSchedule.quartzCronExpression` — long but precise. +### L11. `CronSchedule.quartzCronExpression` — long but precise. -### L13. `JobSource.jobConfigPath` — `jobConfig` prefix inside `JobSource` is mild tautology. - -### L14. `JobDeployment.metadataFilePath` -- **Location:** `model.ts:2354`. -- **Category:** Verbose. - -### L15. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. -- **Location:** `model.ts:3477-3479`. +### L12. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. +- **Location:** `model.ts:3478-3480`. - **Category:** Field contradicting type domain (#16). - **Suggestion:** Move to `RunTask` only, mark deprecated on `Run`. -### L16. `RepairRunRequest.dbtCommands` — present on `RunNowRequest`, `RunJobTask`, `RepairRunRequest`, `RunParameters`. -- **Location:** `model.ts:3190`, `model.ts:3570`, `model.ts:3711`, `model.ts:3821`. -- **Category:** Repeated identical fields — argues for shared `RunOverrideParameters` base. - -### L17. `SparkPythonTask.parameters` (string[]) — OK. +### L13. `SparkPythonTask.parameters` (string[]) — OK. -### L18. `Library.cran: RCranLibrary` — see M36. +### L14. `Library.requirements: string` (a requirements.txt URI) — OK. -### L19. `Library.requirements: string` (a requirements.txt URI) — OK. - -### L20. `AwsAttributes.spotBidPricePercent` — long but precise. - -### L21. `ClusterSpec_NewCluster.useMlRuntime` — `Ml` casing (vs `ML`); follows style. +### L15. `AwsAttributes.spotBidPricePercent` — long but precise. --- @@ -415,95 +243,14 @@ Issues are catalogued below by severity, then by file/line. - Every oneof in the file uses `{$case: 'tag'; tag: T} | undefined`. - This is a porting convention from `protobuf-ts`/`@bufbuild/protobuf-es`; it's noisy but consistent, and consumers can pattern-match cleanly. Keep. -### O2. "Task" prefix vs suffix is wildly inconsistent -- 19 task subtypes exist; some use `XTask` (NotebookTask, SqlTask, DbtTask, PowerBiTask) and some use `XCloudTask` / `XPlatformTask` (DbtCloudTask, DbtPlatformTask). Yet `CleanRoomsNotebookTask` is pluralized. -- The base "what's a task here" question requires reading `RunTask.task` oneof to discover. - -### O3. ID fields are stringly typed throughout -- All run/job/repair IDs are `number`; `dbtPlatformJobRunId` is `string` (see H16). Standardizing as branded types would prevent silent ID swaps. - -### O4. ID disambiguation is heavy -- `runId`, `jobId`, `taskRunIds`, `originalAttemptRunId`, `jobRunId`, `repairId`, `latestRepairId`, `clusterId`, `sparkContextId`, `cleanRoomName`, `notebookName`, `policyId`, `instancePoolId`, `warehouseId`, `widgetId`, `agentId`, `subscriberId`, `destinationId`, `pipelineId`, `dashboardId`, `dbtCloudJobId`, `dbtPlatformJobId`, `dbtCloudJobRunId`, `dbtPlatformJobRunId`, `idempotencyToken`, `endpointId`, `gpuNodePoolId`. -- All over the place; many would benefit from branded types. - -### O5. JSDoc references `` template-token in many places -- The literal `` string appears in JSDoc throughout (e.g., `model.ts:1880`, `model.ts:824`). This is the placeholder for env-specific brand. Acceptable. - -### O6. Method-vs-type verb-tense pairing -- `client.cancelRun(CancelRunRequest) → CancelRunRequest_Response`: verb-noun matches. -- `client.runNow(RunNowRequest)`: verb-now matches. -- `client.repair(RepairRunRequest) → RepairRunRequest_Response`: verb-noun matches now that the request type has the explicit `Request` suffix; the method/type pairing is consistent. -- `client.submitRun(SubmitRunRequest)`: verb-noun matches. - -### O7. The waiters duplicate ~80 lines of code each -- `CancelRunWaiter`, `RepairWaiter`, `RunNowWaiter`, `SubmitRunWaiter` (~80 lines each, mostly identical). Naming: `RepairWaiter` is unique in dropping the `Run` suffix. -- Suggestion: `RepairRunWaiter` for consistency. - -### O8. `client.ts:781` declares `repair()` method (not `repairRun()`) -- The method name remains `repair` even though the request type is `RepairRunRequest`. Consider `repairRun` for consistency with `submitRun`, `cancelRun`, `runNow`, etc. +### O2. Method-vs-type verb-tense pairing +- `client.cancelRun(CancelRunRequest) → CancelRunResponse`: verb-noun matches. +- `client.runNow(RunNowRequest) → RunNowResponse`: verb-now matches. +- `client.repair(RepairRunRequest) → RepairRunResponse`: verb-noun matches now that request and response types carry explicit `Request`/`Response` suffixes; the method/type pairing is consistent. +- `client.submitRun(SubmitRunRequest) → SubmitRunResponse`: verb-noun matches. -### O9. `index.ts` re-exports both the value classes and types in two blocks +### O3. `index.ts` re-exports both the value classes and types in two blocks - Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. -### O10. `Format` and `Source` are top-level public enums named with single English words -- These specific names collide with global and tooling identifiers — see H3, H4. - -### O11. Inconsistent abbreviations: `Params` vs `Parameters` -- Within the same parent type (e.g., `RunNowRequest`): `jobParameters`, `notebookParams`, `pythonParams`, `pipelineParams`, `pythonNamedParams`, `sqlParams`, `sparkSubmitParams`, `jarParams`, `dbtCommands`. -- Standardize on `Parameters`. - ---- - -## Domain Glossary - -| Term | Meaning in this SDK | -| -------------------- | ------------------------------------------------------------------------------------ | -| **Job** | A persistent, named workflow definition. Created via `createJob`. Has `jobId`. | -| **Run** | A single execution of a job. Has `runId`. Triggered via `runNow`/`submitRun`/schedule.| -| **Job Run** | The top-level run of a job (parent of per-task runs). | -| **Task** | A unit of work within a job's DAG. Identified by `taskKey`. | -| **Task Run** | The execution of a single task within a run. Has its own `runId`. | -| **Repair** | A re-run of failed tasks within a previously failed job run. Each repair has its own `repairId`. | -| **Trigger** | The event that initiates a run (cron, file arrival, table, model, etc.). | -| **Trigger Type** | The taxonomy of triggers (`PERIODIC`, `ONE_TIME`, `RETRY`, `FILE_ARRIVAL`, ...). | -| **Lifecycle State** | Where a run is in its execution (QUEUED → PENDING → RUNNING → TERMINATING → TERMINATED). | -| **Result State** | The outcome of a terminated run (SUCCESS / FAILED / TIMEDOUT / CANCELED / ...). | -| **Termination Code** | A fine-grained code attached to a terminated run, with a parent `TerminationType`. | -| **Idempotency Token**| Client-supplied dedup key. If a run with the same token exists, the existing `runId` is returned. | -| **Job Cluster** | A cluster definition reusable across tasks within one job, keyed by `jobClusterKey`. | -| **Environment** | A pip+java dependency spec for serverless tasks, keyed by `environmentKey`. | -| **Task Type** | A variant of work: NotebookTask, SparkJarTask, SparkPythonTask, SparkSubmitTask, PipelineTask, PythonWheelTask, DbtTask, SqlTask, RunJobTask, ConditionTask, ForEachTask, CleanRoomsNotebookTask, GenAiComputeTask, AlertTask, PowerBiTask, DashboardTask, DbtCloudTask, DbtPlatformTask, PythonOperatorTask (19 in total). | -| **Source** | Where source code/assets live: `WORKSPACE` or `GIT`. | -| **Format** | Wire compatibility tag for the Jobs API; effectively always `MULTI_TASK`. | -| **Edit Mode** | UI lock state: `UI_LOCKED` or `EDITABLE`. | -| **Performance Target**| Serverless execution mode: `STANDARD` (cost-optimized) or `PERFORMANCE_OPTIMIZED`. | -| **Budget Policy / Usage Policy** | Cost attribution policies. `budget_policy_id` is user-specified; `effective_budget_policy_id` is what actually applied. | -| **Health Rule** | A per-job alerting rule on a metric (e.g. `RUN_DURATION_SECONDS > 3600`). | -| **Clean Room** | A Databricks Clean Rooms feature; notebook-tasks scoped to a clean room. | -| **dbt Cloud / dbt Platform** | External dbt orchestration; `Cloud` is legacy/deprecated, `Platform` is the new name. | -| **GenAI Compute Task** | Custom GPU training-script task with model parameters. | -| **Power BI Task** | Refresh of a Power BI semantic model from Databricks. | -| **Dashboard Task** | Lakeview dashboard refresh + email subscription. | -| **Alert Task** | Evaluates an alert and notifies subscribers. | -| **Pipeline Task** | Triggers a DLT/Spark Declarative Pipeline update. | -| **RunJob Task** | Triggers another job from a task. | -| **Condition Task** | Branches the DAG based on an evaluation; no cluster required. | -| **ForEach Task** | Fan-out: runs a nested task for each input element. | -| **Python Operator Task** | Runs a Python operator (entry point or class) with structured parameters. | - ---- - -## File Coverage - -| File | Lines | Read In Full? | Notes | -| ----------------- | ----- | ------------- | ------------------------------------------- | -| `v2/index.ts` | 284 | Yes | Re-exports; lists every public identifier. | -| `v2/utils.ts` | 150 | Yes | Marshalling and request helpers. | -| `v2/client.ts` | 1289 | Yes | 19 methods + 4 waiter classes. | -| `v2/model.ts` | 10030 | Yes (chunks) | 47 enums, ~140 interfaces, ~5000 lines of marshalling code (4984+).| - -All public identifiers exported from `index.ts` were considered. Interfaces below -the `unmarshalAdlsgen2InfoSchema` line (4984+) are runtime marshalling code, -not naming surface; they are not in scope. - ---- +### O4. `Format` and `Source` are top-level public enums named with single English words +- These specific names collide with global and tooling identifiers — see H1, H2. diff --git a/.agent/naming-audit/keyconfigurations.md b/.agent/naming-audit/keyconfigurations.md index e2ac6385..63ea16c2 100644 --- a/.agent/naming-audit/keyconfigurations.md +++ b/.agent/naming-audit/keyconfigurations.md @@ -3,45 +3,25 @@ **Path:** `packages/keyconfigurations/src/v1/` **Versions audited:** v1 **Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` -**Inferred domain:** Account-level CRUD over customer-managed key (CMK) -configurations used to encrypt Databricks-managed resources. Endpoints sit -under `/api/2.0/accounts//customer-managed-keys`. Supports AWS -KMS, Azure Key Vault, and GCP KMS key info variants. **Total weird names flagged:** 1 ## Summary table | Severity | Count | | --- | --- | -| High | 0 | | Medium | 1 | -| Low | 0 | -| Observation | 0 | | **Total** | **1** | -The audit is narrowly scoped to proto/architectural leaks. The remaining -finding is a `Public` suffix on every public method of `Client`, mirroring -the proto-side distinction between a `Public` (customer-facing, account -API) RPC and an internal/private variant. From the TS surface this -carries no observable semantic difference — every method here is already -public by virtue of being exported. - ---- - -## High severity (must fix) - -_None._ - --- ## Medium severity (worth pushing back on) -### 1. `Public` suffix on every `Client` method — `client.ts:92, 121, 159, 184` +### 1. `Public` suffix on every `Client` method — `client.ts:89, 118, 156, 181` - **Why:** Every method on `Client` carries the `Public` suffix: - `createCustomerManagedKeyPublic` (client.ts:92), - `deleteCustomerManagedKeyPublic` (client.ts:121), - `getCustomerManagedKeyPublic` (client.ts:159), and - `listCustomerManagedKeyPublic` (client.ts:184). This is a proto-audience + `createCustomerManagedKeyPublic` (client.ts:89), + `deleteCustomerManagedKeyPublic` (client.ts:118), + `getCustomerManagedKeyPublic` (client.ts:156), and + `listCustomerManagedKeyPublic` (client.ts:181). This is a proto-audience leak surfaced on the most caller-visible symbols in the package. A consumer writing `client.createCustomerManagedKeyPublic(...)` sees no contrast to a hypothetical non-public form, because none is exported. @@ -52,22 +32,8 @@ _None._ `listCustomerManagedKey` (or `listCustomerManagedKeys`, matching the return shape). - **Rationale:** The underlying request/response types have already - dropped the `Public` infix (see Fixed); the methods are the last + dropped the `Public` infix; the methods are the last callers still exposing the proto routing detail. The current names are also longer than every comparable method in sibling configuration packages (`networkconfigurations`, `storageconfigurations`, `credentialconfigurations`). - ---- - -## Low severity (nits) - -_None._ - ---- - -## Observations (not flags) - -_None._ - ---- diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 389541b7..274cc3f2 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -2,104 +2,43 @@ **Path:** `packages/knowledgeassistants/src/v1/` **Versions audited:** v1 -**Inferred domain:** "Knowledge Assistant" CRUD plus three child sub-resources: -(a) `Example` (question + guidelines pairs that steer the assistant), -(b) `KnowledgeSource` (a typed pointer into UC — vector-search `IndexSpec`, -volume `FilesSpec`, or table `FileTableSpec`), and (c) a `sync` action that -re-ingests all non-index sources for one assistant. `KnowledgeAssistant` and -`KnowledgeSource` each carry their own proto-style nested lifecycle enum -(`CREATING/ACTIVE/FAILED` and `UPDATING/UPDATED/FAILED_UPDATE`). -**Total weird names flagged:** 11 +**Total weird names flagged:** 6 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 2 | -| Low | 0 | -| Observation | 5 | +| High | 2 | +| Observation | 4 | ## High severity -### 1. `KnowledgeSource_State.UPDATED` reads as past-participle, not lifecycle terminal — `src/v1/model.ts:20` -- **Why weird:** The "successfully ingested / ready" terminal state is named `UPDATED` — past tense of the in-flight `UPDATING`. A reader scanning `UPDATING/UPDATED/FAILED_UPDATE` will see "the source has been updated" which sounds transient (it was just updated, then something else might happen). The sibling assistant enum uses `ACTIVE` for the same concept (the resource is ready and operational), which is much clearer. -- **Category:** 6 (misleading), 13 (verb tense), 17 (inconsistency: assistant has `ACTIVE`, source has `UPDATED`). -- **Suggested name:** `READY` (or `ACTIVE`, matching the assistant) for the ready/operational state. `UPDATING` stays for in-flight. -- **Rationale:** `UPDATED` implies "the action happened" rather than "the resource is in a ready state." A state enum should describe the resource's condition, not the last operation that touched it. - -### 2. `KnowledgeSource.sourceType: string` — stringly-typed when it should be an enum — `src/v1/model.ts:227` -- **Why weird:** The doc literally enumerates the allowed values: `'The type of the source: "index", "files", or "file_table"'`. A `string` typing means callers can write `sourceType: 'INDEX'` (wrong case) or `sourceType: 'vector_search'` (typo) and the compiler accepts both. Same package already uses Zod-discriminated unions for `spec` (model.ts:229-233), so the type info exists; `sourceType` is the redundant string mirror. -- **Category:** 16 (field contradicts type domain — declared as `string` when it is closed-set), 6 (misleading), 12 (duplicate of `spec.$case`). -- **Suggested name:** Convert to an enum `KnowledgeSourceType` with values `Index | Files | FileTable`; or drop `sourceType` entirely because `spec.$case` already carries the discriminant. -- **Rationale:** Stringly-typed enums are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals — TS supports closed string literal unions specifically to avoid this). The fact that `spec.$case` already discriminates makes `sourceType` pure noise on both reads and writes. - -### 3. `KnowledgeAssistant_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:9` +### 1. `KnowledgeAssistant_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:9` - **Why weird:** The enum is named `KnowledgeAssistant_State` with a literal `_State` infix, and the file even carries an eslint-disable comment declaring "Proto-style nested enum name" (model.ts:8). The underscore is a direct architectural leak from the upstream `.proto` definition where the enum was nested inside the `KnowledgeAssistant` message (proto generates `OuterMessage_InnerEnum` for nested enums). TypeScript has no nested-enum-inside-class concept, so the underscore conveys nothing to a TS consumer and just signals "this code was generated from proto." - **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). - **Suggested name:** `KnowledgeAssistantState` (drop the underscore — already the convention in non-leaky TS APIs). The generator can flatten nested-enum names without changing the wire format. - **Rationale:** The proto wire format and the TS identifier shape are decoupled. Carrying the `Outer_Inner` separator into TS leaks the generator's source format and conflicts with the SDK-wide naming-convention lint rule (the file disables `@typescript-eslint/naming-convention` for exactly this reason). -### 4. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:17` -- **Why weird:** Same proto-nested-enum architectural leak as #3. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:16). Two sibling enums in the same file repeat the same proto-leak pattern. +### 2. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:17` +- **Why weird:** Same proto-nested-enum architectural leak as #1. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:16). Two sibling enums in the same file repeat the same proto-leak pattern. - **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). - **Suggested name:** `KnowledgeSourceState` (drop the underscore). -- **Rationale:** Same as #3. Generator-level fix. - -## Medium severity - -### 5. `KnowledgeAssistant.errorInfo: string` — `src/v1/model.ts:195` -- **Why weird:** Two issues: - - Suffix `Info` is generic CS noise (rule 8: redundant suffix). `error` alone or `errorMessage` is more specific. - - Type is `string` but the field is reserved for "Error details when the Knowledge Assistant is in FAILED state." Other Databricks APIs (jobs, clusters) use structured `ErrorInfo` objects with `code`, `message`, `details`. A bare string forces consumers to parse free text — and a future structured upgrade would be a breaking change. -- **Category:** 8 (redundant suffix), 1 (vague), 16 (field contradicts type domain). -- **Suggested name:** `errorMessage` (if the field stays a string) or convert to an `ApiError` object (if the field upgrades). Drop the `Info` suffix either way. -- **Rationale:** The `Info` suffix is a Go/Java carryover (`*Info` types are common in proto messages); TS gets clearer names without it. - -### 6. `Client` class name — bare, no scoping — `src/v1/client.ts:63` -- **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-knowledgeassistants/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as KAClient} from '@databricks/sdk-knowledgeassistants/v1'`. Other SDKs in the Databricks ecosystem name the class `KnowledgeAssistantsClient` (or `KnowledgeAssistantsApi`), avoiding the alias dance. -- **Category:** 1 (vague), 17 (SDK-wide inconsistency). -- **Suggested name:** `KnowledgeAssistantsClient`. Sibling SDK packages (Go SDK reference uses `WorkspaceClient.KnowledgeAssistants`; AWS JS SDK uses `S3Client`, `IAMClient`) follow this pattern. -- **Rationale:** Bare `Client` is convenient until you import two SDK packages; then it's a tax. - -## Low severity - -_None._ +- **Rationale:** Same as #1. Generator-level fix. ## Observations -### 7. No `list` for `Example` siblings outside of `listExamples` — `src/v1/client.ts:305-336` -- **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource`. Naming consistent. Flagging as a *positive* observation — the verbs are uniform. +### 3. `list` verbs are uniform across all three resources — `src/v1/client.ts:334,388,445` +- **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource` (`listExamples`, `listKnowledgeAssistants`, `listKnowledgeSources`). Naming consistent. Flagging as a *positive* observation — the verbs are uniform. - **Category:** 17 (reversed — consistency note). -### 8. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:464` +### 4. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:502` - **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id. The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. - **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. - **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. -### 9. Acronym casing: `URI`, `UUID`, `MLflow`, `UC` — `src/v1/model.ts:92,142,144,146,165,192,261,310` -- **Why weird:** This package follows the SDK convention of *not* using acronym casing in TS identifiers (none of `UUID`, `URI`, `MLflow`, `UC` appear as identifier components in source — they only appear in JSDoc as documentation). When they do appear in TS identifiers (`docUriCol`), they are title-cased (`Uri`) — matching Microsoft's three-letter-acronym rule but contradicting the SDK's own `ApiError` usage. Cross-cutting observation from `customllms.md` #36. -- **Category:** 3 (acronym casing — SDK-wide). -- **Suggested name:** SDK-wide policy decision. - -### 10. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` +### 5. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` - **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. - **Category:** Observation. -### 11. `Example` lacks `state` field — `src/v1/model.ts:79-98` +### 6. `Example` lacks `state` field — `src/v1/model.ts:79-98` - **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. - **Category:** Observation. - -## Domain glossary -- `knowledge assistant` — the top-level resource: an LLM-powered assistant scoped to a corpus of knowledge. -- `knowledge source` — a typed pointer into UC (vector index, volume of files, or file table) that feeds the assistant. -- `example` — a question + guidelines pair used to steer the assistant's responses. -- `uc` — Unity Catalog (referenced in JSDoc on `FileTableSpec.tableName`, `IndexSpec.indexName`, `FilesSpec.path`). -- `mlflow` — Machine-learning lifecycle platform (referenced only in `KnowledgeAssistant.experimentId` JSDoc). -- `field mask` — Google AIP-161 partial-update mechanism (FieldMask from `@databricks/sdk-core/wkt`). -- `uuid` — referenced in JSDoc on `Example.exampleId` and `KnowledgeAssistant.id`. - -## File coverage -- `src/v1/model.ts` (752 lines): read fully. -- `src/v1/client.ts` (603 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (34 lines): read fully. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index 13a34602..3740b41e 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -3,35 +3,25 @@ **Path:** `packages/lakeview/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks AI/BI Dashboards (formerly named "Lakeview"). CRUD of draft dashboards, publish/unpublish, schedule periodic refresh, and email subscriptions tied to schedules. Also includes a one-way migration entry point from the older "classic SQL" dashboards. -**Total weird names flagged:** 14 +**Total weird names flagged:** 6 ## Summary | Severity | Count | | ----------- | ----- | -| High | 6 | -| Medium | 5 | -| Low | 2 | -| Observation | 1 | +| High | 3 | +| Medium | 3 | ## Summary table | # | Severity | Location | Name | Category | | -- | ----------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------- | | 1 | High | package name | `lakeview` | 6 | -| 2 | High | `model.ts` enum | `DashboardView` | 1, 7 | -| 3 | High | `model.ts` enum | `LifecycleState` | 1, 12 | -| 4 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashDashboard` | 17 | -| 5 | High | `model.ts` interface | `Dashboard` | 1, 15 | -| 6 | High | `model.ts` interface | `PublishedDashboard` | 12 | -| 7 | Medium | `model.ts` interface | `CronSchedule` | 1 | -| 8 | Medium | `model.ts` enum | `SchedulePauseStatus` | 1, 7 | -| 9 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | -| 10 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | -| 11 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | -| 12 | Low | `model.ts` field | `Subscription.createdByUserId` typed `number` | 19, 16 | -| 13 | Low | `model.ts` field | `Dashboard.etag` / `Schedule.etag` / `Subscription.etag` | 3 | -| 14 | Observation | `model.ts` field | `Dashboard.path` and `Dashboard.parentPath` | 15, 6 | +| 2 | High | `model.ts` enum | `DashboardView` | 1 | +| 3 | High | `client.ts` method / `model.ts` type | `trashDashboard` / `TrashDashboardRequest` vs everywhere else `delete...` | 17 | +| 4 | Medium | `model.ts` interface | `MigrateDashboardRequest` | 17 | +| 5 | Medium | `client.ts` method | `trashDashboard` vs everywhere else `delete...` | 17 | +| 6 | Medium | `model.ts` interface | `PublishDashboardRequest` & `PublishedDashboard` | 6, 12 | --- @@ -65,138 +55,37 @@ export enum DashboardView { } ``` -The enum has only one member. It exists because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.) — but until those exist the enum is a confusing single-value gate. +The enum has only one member. It exists because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.). `View` is also a generic name in a Dashboards package (it overloads the HTML/UI sense of "view" with the "field mask" sense — e.g. `proto3` partial-response style). -**Category:** 1 (vague), 7 (overengineering for binary). +**Category:** 1 (vague). -**Suggested name:** Either rename to `DashboardFieldMask` / `DashboardResponseMode` (closer to its actual role: a partial-response selector), or, until there is a second value, replace `view?: DashboardView` with `summaryOnly?: boolean` and delete the enum. +**Suggested name:** Rename to `DashboardFieldMask` / `DashboardResponseMode` (closer to its actual role: a partial-response selector). **Rationale:** Without the doc comment on `ListDashboardsRequest.view`, the type name does not communicate that this is a "give me only summary fields" selector. -### 3. `LifecycleState` — domain-detached enum that overlaps with other packages +### 3. `trashDashboard()` / `TrashDashboardRequest` — verb diverges from the SDK-wide `delete` -**Location:** `src/v1/model.ts:11-16` +**Location:** `src/v1/client.ts:672` (`trashDashboard`), `src/v1/model.ts:421` (`TrashDashboardRequest`) -```ts -export enum LifecycleState { - /** The dashboard is in an active state (not-trashed). */ - ACTIVE = 'ACTIVE', - /** The dashboard is in a trashed state. */ - TRASHED = 'TRASHED', -} -``` - -`LifecycleState` is a top-level export with no domain prefix. Other Databricks SDK packages also use the name (e.g. `alerts.LifecycleState`, `queries.LifecycleState`) — same name, different sets of values. Cross-package imports clash: - -```ts -import {LifecycleState as DashLifecycle} from '@databricks/sdk-lakeview'; -import {LifecycleState as AlertLifecycle} from '@databricks/sdk-alerts'; -``` - -**Category:** 1 (vague), 12 (duplicate concepts across packages). - -**Suggested name:** `DashboardLifecycleState` (matches the v2 alerts pattern `AlertLifecycleState`). - -**Rationale:** Eliminates the import-rename ritual. Consistent with the rest of the SDK after the alerts v2 refactor. - -### 4. `LifecycleState.TRASHED` vs `trashDashboard()` — split vocabulary inherited from pre-v2 alerts +The method uses `trash` and the type uses `Trash`, while every other CRUD-style endpoint in the Databricks SDK uses `Delete`/`delete`. Alerts had the *exact* same `trash` method/type vocabulary (flagged in `alerts.md` #11 and #12); it was renamed in alerts v2 — leaving Lakeview as an outlier. -**Location:** `src/v1/model.ts:15`, `src/v1/client.ts:592` (`trashDashboard`), `src/v1/model.ts:403` (`TrashDashboardRequest`) - -The enum uses `TRASHED`, the method uses `trash`, the type uses `Trash`. **Same package, same operation, three forms**. Meanwhile every other CRUD-style endpoint in the Databricks SDK uses `Delete`/`delete`. Alerts has the *exact* same issue (flagged in `alerts.md` #11 and #12); it was kept in v1 and renamed to `DELETED` in alerts v2 — leaving Lakeview as an outlier. - -The `LifecycleState.TRASHED` value is paired with a method called `trashDashboard()` (verb `trash`) and a method `getDashboard()` that returns `lifecycleState: TRASHED` after a soft-delete. So the lifecycle word, the method verb, and the type-name suffix all share a vocabulary that none of the rest of the SDK uses. +The `trashDashboard()` method (verb `trash`) soft-deletes a dashboard. So the method verb and the type-name suffix share a vocabulary that none of the rest of the SDK uses. **Category:** 17 (inconsistent action verb). -**Suggested name:** Either keep `trashDashboard` and rename `TRASHED → DELETED` (mirrors alerts v2 — but then the method verb mismatches its own state) or rename both to `deleteDashboard` + `DELETED`. The cleanest is to rename method + type + state value to `delete`/`Delete`/`DELETED` together. - -**Rationale:** A single coherent verb. The Trash → Delete migration is partially complete in other packages and lakeview is behind. - -### 5. `Dashboard` — overloaded top-level type - -**Location:** `src/v1/model.ts:93-136` - -`Dashboard` is the top-level type for the *draft* dashboard. The package then exposes `PublishedDashboard` as a *different* shape for the published-state mirror. A user reading the API thinks `Dashboard` means "any dashboard"; in fact it means "draft dashboard". The `lifecycleState` field on `Dashboard` is `ACTIVE`/`TRASHED` — and never `PUBLISHED`, because a published dashboard is the wholly separate `PublishedDashboard` type. Nothing in the type name conveys "draft". - -This is compounded by Databricks having (1) classic SQL dashboards (a separate API), (2) AI/BI dashboards / lakeview dashboards (this API), (3) genie dashboards, (4) usage dashboards. The bare name `Dashboard` is therefore severely overloaded both within the company and within the SDK. - -**Category:** 1 (vague/generic), 15 (generic type losing meaning at site). - -**Suggested name:** `DraftDashboard` (paired with `PublishedDashboard`). Both are draft and published views of the same underlying resource, so the symmetry is desirable. - -**Rationale:** Without the rename the API is asymmetric: `getDashboard()` returns "the draft view", `getPublishedDashboard()` returns "the published view", but only one of those calls makes the draft/published nature explicit. - -### 6. `PublishedDashboard` — projection sibling of `Dashboard`, missing structural identity +**Suggested name:** Rename the method and type to `deleteDashboard` / `DeleteDashboardRequest` so the verb matches the rest of the SDK. The cleanest is to rename method + type together. -**Location:** `src/v1/model.ts:315-324` - -```ts -export interface PublishedDashboard { - displayName?: string | undefined; - warehouseId?: string | undefined; - embedCredentials?: boolean | undefined; - revisionCreateTime?: Temporal.Instant | undefined; -} -``` - -No `dashboardId`. No `etag`. No `serializedDashboard`. No reference back to the parent `Dashboard`. So `PublishedDashboard` is a *partial mirror* of the draft `Dashboard` resource, but the only thing tying them together is the URL path the user used to fetch it. The name `PublishedDashboard` implies "a full dashboard in the published state", but the type is in practice "the metadata of the latest publish action". - -**Category:** 12 (duplicate concept relative to `Dashboard`). - -**Suggested name:** `PublishedDashboardSnapshot` or `PublishMetadata`. If the long-term intent is for the type to contain the full published content, the type name is fine but it should at least carry the `dashboardId` of its parent. - -**Rationale:** Today every caller of `getPublishedDashboard()` has to remember the `dashboardId` they passed in to use the response. The type should round-trip. +**Rationale:** A single coherent verb. The trash → delete method/type migration is partially complete in other packages and lakeview is behind. --- ## Medium severity -### 7. `CronSchedule` — generic type name in a single-domain package - -**Location:** `src/v1/model.ts:80-91` - -```ts -export interface CronSchedule { - quartzCronExpression?: string | undefined; - timezoneId?: string | undefined; -} -``` - -The package exports a top-level `CronSchedule`. The same name appears in `alerts/v2`, `jobs` (similar concept), `pipelines` (similar concept). Each defines its own. Across the SDK there is no shared "this is a cron expression with a timezone" type — every team duplicates the two-field interface. - -**Category:** 1 (generic name in domain package). - -**Suggested name:** Either accept the duplication (matches Go SDK's package-local types) and rename to `DashboardCronSchedule`, or extract a shared core type. The audit recommends `DashboardCronSchedule` since the user-facing concept is "a cron schedule that the dashboards service understands". - -**Rationale:** Future-proofing: the field set may diverge from other services' cron-schedule types (some add a `pauseStatus`, some add a `nextFireTime`). A domain-prefixed name prevents `import { CronSchedule } from '@databricks/sdk-lakeview'` from being a confusing rename. - -### 8. `SchedulePauseStatus` — domain prefix only partially applied - -**Location:** `src/v1/model.ts:18-21` - -```ts -export enum SchedulePauseStatus { - UNPAUSED = 'UNPAUSED', - PAUSED = 'PAUSED', -} -``` - -Same enum-name shape as `alerts/v2.SchedulePauseStatus` — i.e. the prefix is `Schedule`, not `Dashboard` or `Lakeview`. So we have a `Schedule`-prefixed enum inside the lakeview package and an identical-looking enum inside the alerts package. The two are not interchangeable but they look identical at the type level — a developer copying code between packages might think they are. - -Also: a two-value enum named `*Status` for two paused-or-not states is overengineering. A boolean (`paused: boolean`) reads more naturally and prevents the case where a future `SUSPENDED` value silently changes paused-checks. - -**Category:** 1 (overly generic prefix), 7 (overly verbose for binary). - -**Suggested name:** Either rename to `DashboardSchedulePauseStatus` (preserves enum), or collapse to `Schedule.paused?: boolean`. The former retains the option for a third state; the latter is what most users will expect. - -**Rationale:** Binary status enums are an anti-pattern in TS where booleans are first-class. The Go SDK is constrained to enums (no booleans for proto), but the TS SDK is not. +### 4. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb -### 9. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb - -**Location:** `src/v1/model.ts:285`, `src/v1/client.ts:540` +**Location:** `src/v1/model.ts:285`, `src/v1/client.ts:585` "Migrate" can mean (a) copy and convert, (b) move-and-delete-source, (c) rewrite-in-place. The JSDoc on the method ("Migrates a classic SQL dashboard to Lakeview.") suggests (a): the source dashboard remains, a new AI/BI dashboard is created. The verb does not encode this. @@ -206,19 +95,19 @@ Also: a two-value enum named `*Status` for two paused-or-not states is overengin **Rationale:** The other Databricks "migrate" endpoints (e.g. `tables.migrate`, `permissions.migrate`) actually move state. This one creates a new asset. Same verb, two operations. -### 10. `trashDashboard` — soft-delete method without a paired restore (see also #4) +### 5. `trashDashboard` — soft-delete method without a paired restore (see also #3) -**Location:** `src/v1/client.ts:592` +**Location:** `src/v1/client.ts:672` -Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` method is paired with no `restoreDashboard` or `untrashDashboard`. The method moves the dashboard into `TRASHED` lifecycle state, but the API doesn't expose how to undo it via the SDK — a caller has to use `updateDashboard({ dashboard: { lifecycleState: ACTIVE } })`. Discovery from method names alone gives no hint that "restore" exists. +Beyond the verb-mismatch flagged in #3, the `trashDashboard` method is paired with no `restoreDashboard` or `untrashDashboard`. The method soft-deletes the dashboard, but the API doesn't expose how to undo it via the SDK — a caller has to use `updateDashboard(...)` to reactivate it. Discovery from method names alone gives no hint that "restore" exists. -**Category:** 17 (inconsistent action verb), see #4. +**Category:** 17 (inconsistent action verb), see #3. **Suggested name:** `deleteDashboard` (semantics-clear). Add `restoreDashboard` (or document `updateDashboard` as the restoration path in the `trashDashboard` JSDoc). **Rationale:** Symmetry. `deletePermanently` is also unavailable here — soft-delete is the only delete. -### 11. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles +### 6. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles **Location:** `src/v1/model.ts:299`, `src/v1/model.ts:315` @@ -229,70 +118,3 @@ Beyond the verb-mismatch with `LifecycleState.TRASHED`, the `trashDashboard` met **Suggested name:** `PublishDashboardRequest` → `PublishDashboardOptions` or `PublishDashboardInput`. The "Request" suffix doesn't distinguish on the auto-complete; an `Input`/`Options` suffix does. **Rationale:** Reduce typo bugs. The Databricks SDK already uses `*Options` in `ClientOptions`, `CallOptions`, so the pattern is precedented. - ---- - -## Low severity - -### 12. `Subscription.createdByUserId` typed as `number` - -**Location:** `src/v1/model.ts:360` - -```ts -/** UserId of the user who adds subscribers (users or notification destinations) to the dashboard's schedule. */ -createdByUserId?: number | undefined; -``` - -User IDs in Databricks are 64-bit integers; storing them as JS `number` overflows above 2^53. The Databricks JS SDK has the same problem elsewhere, but it surfaces visibly here because the field is part of every Subscription response. - -Also, the doc string is past-tense verb plus present-tense ("adds") — inconsistent. - -**Category:** 19 (underspecified ID — `number` is wrong storage), 16 (field contradicts wire format which is int64). - -**Suggested name:** Keep `createdByUserId`, change type to `string` (matching the SCIM API's `users/` convention) or `bigint`. JSDoc should clarify the format. - -**Rationale:** Silent overflow is the worst kind of bug. - -### 13. `Dashboard.etag`, `Schedule.etag`, `Subscription.etag` — `etag` lowercase casing - -**Location:** `src/v1/model.ts:118`, `src/v1/model.ts:341`, `src/v1/model.ts:365` - -Consistent within the package, but the HTTP spec spells it `ETag`. Most TS SDKs use lowercase, so it's defensible. Flagged for whole-codebase consistency (compare `alerts.md` #14 on `notifyOnOk` for similar acronym-casing concerns). - -**Category:** 3. - -**Suggested name:** Keep `etag`. Note the project convention. - ---- - -## Observations - -### 14. `Dashboard.path` vs `Dashboard.parentPath` — overlap - -**Location:** `src/v1/model.ts:103`, `src/v1/model.ts:135` - -```ts -path?: string | undefined; // workspace path of the dashboard asset, including the file name -parentPath?: string | undefined; // workspace path of the folder containing the dashboard -``` - -`path = parentPath + '/' + filename`. The two fields are derivable from each other (given a known filename rule). Maintaining both is convenient for clients but means clients must keep them in sync on writes. Field names give no hint about the relationship. - -**Category:** 15 (generic), 6 (silently redundant). - -**Suggested name:** Keep both. Either rename `path → fullPath` for symmetry, or document the relationship in JSDoc on both fields. - ---- - -## Net assessment - -Lakeview / AI/BI Dashboards is a relatively small surface (5 enums-and-resources, 19 client methods) but the naming smells cluster around: - -1. **The rebrand from "Lakeview" to "AI/BI Dashboards"** is incomplete — the package name and URLs preserve the old codename, while the JSDoc mixes the two. -2. **The trash/delete vocabulary split** (#4, #10) is inherited from the alerts package's pre-v2 design — already fixed in alerts v2 but not in lakeview. -3. **Generic top-level type names** (`Dashboard`, `LifecycleState`, `CronSchedule`, `SchedulePauseStatus`) overlap with other packages in the SDK monorepo and force consumers to import-rename. -4. **64-bit user IDs typed as `number`** (#12) silently truncate above 2^53. Same issue exists in other packages but is unsurfaced here. - -If only one change were possible, completing the trash/delete vocabulary unification (renaming `trashDashboard` + `TRASHED` to the `delete`/`DELETED` family used by alerts v2) would remove the most visible inconsistency. - ---- diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md index 39535650..7522a6a7 100644 --- a/.agent/naming-audit/logdelivery.md +++ b/.agent/naming-audit/logdelivery.md @@ -9,104 +9,59 @@ delivery configuration ties a `credentialsId` (AWS IAM role) and a `AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no delete endpoint by design — the API only supports disabling via the update (`PATCH`) method. -**Total weird names flagged:** 13 +**Total weird names flagged:** 7 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 5 | -| Low | 3 | +| High | 3 | +| Medium | 2 | +| Low | 1 | | Observation | 1 | ## High severity ### 1. `LogDeliveryStatusEnum` — type name carries `Enum` suffix — `src/v1/model.ts:39` -- **Why weird:** `LogDeliveryStatusEnum` is the only type in the package whose name ends in `Enum`. The three sibling enums (`LogDeliveryConfigStatus` at line 12, `LogDeliveryOutputFormat` at line 23, `LogDeliveryType` at line 56) carry no such suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` is already claimed by the wrapper *interface* at `model.ts:208` (which holds `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, and `status`). +- **Why weird:** `LogDeliveryStatusEnum` is the only type in the package whose name ends in `Enum`. The three sibling enums (`LogDeliveryConfigStatus` at line 12, `LogDeliveryOutputFormat` at line 23, `LogDeliveryType` at line 56) carry no such suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` is already claimed by the wrapper *interface* at `model.ts:205` (which holds `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, and `status`). - **Category:** 20 (type-suffix tautology), 12 (duplicate concept — `LogDeliveryStatus` interface and `LogDeliveryStatusEnum` enum coexist). - **Suggested name:** Rename the wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (it models the most-recent attempt, not the status per se), and rename the enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The field site then reads `attempt.status: LogDeliveryAttemptStatus` instead of `logDeliveryStatus.status: LogDeliveryStatusEnum`. - **Rationale:** The `Enum` suffix is unique to this one type and signals that the underlying noun is overloaded. Splitting the noun ("attempt" for the wrapper, "attempt status" for the values) removes the suffix and the conflation in one rename. -### 2. `LogDeliveryConfigStatus` vs `LogDeliveryStatusEnum` — two enums named "status" of "log delivery" for orthogonal facets — `src/v1/model.ts:12,39` -- **Why weird:** Both enums describe "status" of "log delivery", but their domains are unrelated: - - `LogDeliveryConfigStatus`: `ENABLED` / `DISABLED` — whether the configuration is active. - - `LogDeliveryStatusEnum`: `CREATED` / `SUCCEEDED` / `USER_FAILURE` / `SYSTEM_FAILURE` / `NOT_FOUND` — whether the most recent delivery attempt worked. - - Inside `LogDeliveryConfiguration` both surface as `status` fields one level apart: `LogDeliveryConfiguration.status: LogDeliveryConfigStatus` (line 199) and `LogDeliveryConfiguration.logDeliveryStatus.status: LogDeliveryStatusEnum` (line 217). A reviewer cannot tell at a glance which `status` is meant. -- **Category:** 12 (duplicate concept), 6 (misleading — same noun for incompatible domains). -- **Suggested name:** Rename to expose the distinction: `LogDeliveryConfigStatus` → `LogDeliveryEnablement` (`ENABLED` / `DISABLED`) and `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus` (`CREATED` / `SUCCEEDED` / ...). -- **Rationale:** Identical nouns for incompatible domains are a classic bug source. Differentiated nouns ("enablement" vs "attempt status") make the two enums distinguishable at the call site. - -### 3. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:124-129,230-237` -- **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:126,218`). The client substitutes them via `?? ''` (`client.ts:126,218`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). +### 2. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:123-128,227-234` +- **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:123,215`). The client substitutes them via `?? ''` (`client.ts:123,215`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:227-234`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). - **Category:** 6 (misleading — type signature says optional, runtime requires non-empty), 7 (overly verbose / boilerplate JSDoc). - **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create`). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." - **Rationale:** Required path params should have required types. The current shape silently produces malformed URLs at runtime. The "of customer" prose is generator-emitted boilerplate worth removing globally. -### 4. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214,230-237` -- **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:230-237`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:209-213`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus`, which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. +### 3. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:211`, `src/v1/model.ts:227-234` +- **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:227-234`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:206-210`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus`, which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. - **Category:** 6 (misleading), 17 (verb inconsistency — Go uses `PatchStatus`, TS paraphrases as `update`). -- **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:227`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. +- **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:224`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. - **Rationale:** "Update" implies multi-field mutation. A caller writing `updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new'})` will be surprised — `deliveryPathPrefix` is not on the DTO so TS will type-error, but only after the user reads the type. The verb is a footgun and the existing JSDoc admits it. Naming should match capability. ## Medium severity -### 5. `Client` class is unprefixed — `src/v1/client.ts:46`, exported at `src/v1/index.ts:3` -- **Why weird:** A user importing the package writes `import {Client} from '@databricks/sdk-logdelivery/v1'` and must alias (`import {Client as LogDeliveryClient}`) to compose with any other Databricks SDK client. Consistent across the SDK; flagged once per package. -- **Category:** 1 (vague), 12 (duplicate concept — every Databricks SDK package exports its own `Client`). -- **Suggested name:** `LogDeliveryClient` (or expose a namespace and let `logDelivery.Client` be the qualified name). -- **Rationale:** Every audited package has this finding. Worth normalising at generator level. - -### 6. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:150,192` -- **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:160`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). +### 4. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:147,189` +- **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:157`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `listLogDeliveryConfigurations` (plural). The `*Iter` pagination helper should match: `listLogDeliveryConfigurationsIter`. - **Rationale:** Method-name pluralisation should match the data shape it yields. -### 7. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:141` -- **Why weird:** Same shape mismatch as finding 6, applied to the request DTO. The class-level JSDoc on line 138 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. +### 5. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:139` +- **Why weird:** Same shape mismatch as finding 4, applied to the request DTO. The class-level JSDoc on line 137 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and the `_Response` partner correspondingly). - **Rationale:** Pluralisation is the standard signal for a collection-returning method/type pair. -### 8. `logDeliveryStatus` field, `LogDeliveryStatus` type, `LogDeliveryStatusEnum` enum — triple-conflation of one noun — `src/v1/model.ts:103,205,208,217` -- **Why weird:** Reading `LogDeliveryConfiguration.logDeliveryStatus.status` traverses three types whose names all carry "Status": - - `LogDeliveryConfiguration` (the resource). - - `LogDeliveryStatus` (wrapper for the last-attempt fields). - - `LogDeliveryStatusEnum` (the actual enum values). - - Each layer adds the same noun with different meaning. The field name `logDeliveryStatus` is also redundant inside a `LogDeliveryConfiguration` — the `LogDelivery` prefix is implied by the parent type. -- **Category:** 12 (duplicate concept), 15 (generic field name losing meaning). -- **Suggested name:** Rename field `logDeliveryStatus` → `lastAttempt`. Rename wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (with fields `status`, `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`). Rename enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The call site becomes `config.lastAttempt.status === 'SUCCEEDED'` — three concrete nouns instead of three "Status" repetitions. -- **Rationale:** "Status" is too generic to triple-stack. Aligns with findings 1 and 2. - -### 9. `workspaceIdsFilter: number[]` — int64 wire field stored as JS `number` — `src/v1/model.ts:91,193` -- **Why weird:** The JSDoc explicitly says "each one is an `int64`". JavaScript `number` is a double-precision float — only safe up to 2^53 − 1. Databricks workspace IDs are int64 server-side; transmitting an ID above the safe range silently loses precision in the JSON wire round-trip. -- **Category:** 6 (misleading — TS type cannot represent the wire's int64 safely), 19 (under-specified id type). -- **Suggested name:** `workspaceIds: bigint[]` (matches int64 wire). Alternative: brand the IDs as `WorkspaceId` via `type WorkspaceId = bigint & {__brand: 'WorkspaceId'}`. -- **Rationale:** Cross-package finding — every `*Id: number` typed against an int64 wire has the same hazard. Generator-level fix: emit `bigint` for `int64` fields. - ## Low severity -### 10. `LogDeliveryType` values `BILLABLE_USAGE` vs `AUDIT_LOGS` — singular/plural mismatch — `src/v1/model.ts:58-60` -- **Why weird:** `BILLABLE_USAGE` is singular; `AUDIT_LOGS` is plural. Both are types of logs delivered by this configuration. Pair-wise consistency would be either `BILLABLE_USAGE_LOGS` + `AUDIT_LOGS` (both plural with `_LOGS`) or `BILLABLE_USAGE` + `AUDIT` (both singular without). -- **Category:** 9 (singular/plural mismatch), 18 (long enum values). -- **Suggested name:** `BILLABLE_USAGE` + `AUDIT` (drop `_LOGS` — the enum is `LogDeliveryType` so "logs" is implicit). -- **Rationale:** Pair-wise consistency. The implicit-noun pattern (rely on the enclosing type) is shorter. - -### 11. `LogDeliveryStatusEnum.NOT_FOUND` collides with HTTP 404 semantics — `src/v1/model.ts:48-49` -- **Why weird:** `NOT_FOUND` reads as "this resource does not exist" — a 404-style state — but the JSDoc on line 37 says it means "the log delivery status as the configuration has been disabled since the release of this feature or there are no workspaces in the account". That is "no data to report", not "resource missing". -- **Category:** 6 (misleading — value name suggests an HTTP error state, semantics are operational). -- **Suggested name:** `NO_DATA`, `NOT_APPLICABLE`, or `DISABLED_AT_RELEASE` — anything that does not read as 404. -- **Rationale:** A monitoring dashboard surfacing `status === 'NOT_FOUND'` would mislead an operator into thinking the configuration was deleted. - -### 12. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:90,99,103,127,153,170,193,196,215,223` -- **Why weird:** Three-letter abbreviations on parameter and local names across every method. The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. +### 6. `req` / `resp` / `httpReq` / `pageReq` abbreviations — `src/v1/client.ts:88,96,100,120,128,148,167,171,190,193,212,224` +- **Why weird:** Short abbreviations on parameter and local names across every method (`req` for the request parameter, `resp` for the response local, `httpReq` for the built HTTP request, `pageReq` for the pagination request). The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `request`, `response`, `options`, `httpRequest`, `httpResponse`. +- **Suggested name:** `request`, `response`, `httpRequest`, `pageRequest`. - **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. ## Observations -### 13. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:79-83,181-185` +### 7. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:78-83,177-182` The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index 355f44bf..f1f5af4e 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,68 +3,22 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 32 (32 still present, 0 newly fixed, 0 superseded). +**Total weird names flagged:** 14 (14 still present, 0 newly fixed, 0 superseded). ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 18 | -| Low | 5 | -| Observation | 1 | - -The marketplaces package remains one of the more naming-distressed surfaces in the SDK, though the dominant pre-existing problem — **inconsistent request-type naming** across the package — has been resolved by uniformly applying the `*Request`/`*Response` suffix to every operation type. Notable issues remaining include the overloaded vocabulary triad **Listing / Exchange / Provider** without disambiguation (an exchange filter is a metastore-id allowlist, an exchange listing is a join row between an exchange and a listing, a listing detail is the body of a listing, and a personalization request is a consumer-side action targeting a listing), the cryptic plural irregularities around the noun `Listings` (the `GetListingsRequest` and its proto-nested `_Response` payload field both use `listings`, while `CreateListingRequest` and `DeleteListingRequest` use the singular and `ListListingsForExchange` re-introduces the plural with a different field name `exchangeListings`), and the field `isFromLighthouse` referencing the internal-codename "Lighthouse" service in a public type. +| High | 3 | +| Medium | 10 | +| Low | 1 | --- ## High severity -### 1. `Listing` — ambiguous central type - -**Location:** `src/v1/model.ts:652` - -```ts -export interface Listing { - id?: string | undefined; - summary?: ListingSummary | undefined; - detail?: ListingDetail | undefined; -} -``` - -`Listing` is the central noun of the package, but the name has two unrelated English meanings: a *marketplace listing* (a storefront entry) and a *list operation* (the verb "to list", noun "a listing of items"). The package frequently uses both meanings within a single line: -- `getListings(req: GetListingsRequest)` — method name uses the verb sense ("get the listings"), the type name uses the noun sense (a "GetListings" request that returns marketplace listings). -- `ListListingsForExchangeRequest` reads as "list the listings for exchange" — the first `List` is the verb, the second `Listings` is the noun. -- `ExchangeListing` (line 320) is a join-row type — neither a storefront listing nor a list-operation but a third concept ("a listing in an exchange"). - -The triple overload is unavoidable given the domain word but the SDK does not disambiguate (e.g. by renaming join rows to `ExchangeListingLink` or `ExchangeMembership`). -- **Category:** 1 (vague), 12 (duplicate concepts), 15 (overloaded vocabulary). -- **Suggested name:** Keep `Listing` for the noun; rename `ExchangeListing` → `ExchangeListingLink` / `ListingExchangeMembership`. -- **Rationale:** "Listing" has multiple senses; the SDK uses all three; the API can mitigate this by giving the *join row* a less ambiguous name. - -### 2. `ExchangeListing` — overloaded "listing" inside the type name - -**Location:** `src/v1/model.ts:320` - -```ts -export interface ExchangeListing { - id?: string | undefined; - exchangeId?: string | undefined; - exchangeName?: string | undefined; - listingId?: string | undefined; - listingName?: string | undefined; - createdAt?: number | undefined; - createdBy?: string | undefined; -} -``` - -The type is a join row connecting an exchange to a listing (with denormalized names). Named `ExchangeListing` it parses as either "a listing of type Exchange" (no — exchanges and listings are distinct) or "the exchange-side view of a listing" (no — both sides are denormalized into the same row) or "a listing exposed in the exchange" (closer, but the type is really the *link*, not the listing itself). The `Exchange.linkedListings: ExchangeListing[]` field at line 305 makes the relationship visible but does not clarify the name. -- **Category:** 1 (vague), 6 (misleading: looks like an inheritance from `Listing`), 12 (overloaded with `Listing`). -- **Suggested name:** `ExchangeListingLink`, `ExchangeMembership`, `ListingExchangeAssociation`. -- **Rationale:** See #1. - -### 3. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order +### 1. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order -**Location:** `src/v1/model.ts:142, 796` +**Location:** `src/v1/model.ts:142, 774` ```ts export interface AddExchangeForListingRequest { @@ -82,46 +36,9 @@ The operations are symmetric (associate / disassociate an exchange with a listin - **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`). - **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. -### 4. `PersonalizationRequest.isFromLighthouse` — internal codename leak +### 2. `ListingSummary` — 20-field "summary" -**Location:** `src/v1/model.ts:767` - -```ts -export interface PersonalizationRequest { - ... - isFromLighthouse?: boolean | undefined; - ... -} -``` - -`Lighthouse` is an internal Databricks service codename, not a product term — there is no `Lighthouse` mention anywhere else in the package, no JSDoc clarifying what the flag means, no enum, and no type-safety on what it controls. The flag's purpose is opaque to anyone outside the marketplace team. -- **Category:** 5 (cryptic abbreviation / codename), 1 (vague), 6 (misleading: implies a known concept). -- **Suggested name:** Either document inline (the doc-comment should explain Lighthouse) or rename to a feature-describing name. If Lighthouse is a request-origin tag, `originatingService` (with an enum) would be clearer. -- **Rationale:** Public APIs should not leak internal-system codenames. - -### 5. `ListingSummary` vs `ListingDetail` — Summary / Detail as separate types - -**Location:** `src/v1/model.ts:719, 658` - -```ts -export interface Listing { - id?: string | undefined; - summary?: ListingSummary | undefined; - detail?: ListingDetail | undefined; -} - -export interface ListingSummary { /* 20 fields */ } -export interface ListingDetail { /* 18 fields */ } -``` - -The split into `Summary` and `Detail` looks like a "list view vs. detail view" distinction (where `Summary` is what gets returned in list endpoints and `Detail` is the full payload). But both are bundled into a single `Listing` and both come back from `getListing` and `listListings`. The convention is meaningful in REST APIs that ship two read-shapes (e.g. GitHub's `Repository` vs `MinimalRepository`), but here both types are always present on the same `Listing`. The naming implies a contract the API doesn't honor. -- **Category:** 6 (misleading — names imply contract that isn't enforced), 12 (duplicate concept of "the listing"), 11 (could be merged). -- **Suggested name:** `ListingMetadata` (for what is currently `ListingSummary`) and `ListingContent` (for `ListingDetail`); or merge into a single `Listing` type. -- **Rationale:** The "Summary / Detail" lexicon promises a slim/fat split that the API doesn't actually provide. - -### 6. `ListingSummary` — 20-field "summary" - -**Location:** `src/v1/model.ts:719-740` +**Location:** `src/v1/model.ts:697-718` ```ts export interface ListingSummary { @@ -139,8 +56,8 @@ export interface ListingSummary { publishedBy?: string | undefined; categories?: Category[] | undefined; listingType?: ListingType | undefined; - createdById?: number | undefined; - updatedById?: number | undefined; + createdById?: bigint | undefined; + updatedById?: bigint | undefined; providerId?: string | undefined; exchangeIds?: string[] | undefined; gitRepo?: RepoInfo | undefined; @@ -150,11 +67,11 @@ export interface ListingSummary { A 20-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. - **Category:** 6 (misleading). - **Suggested name:** `ListingMetadata` or `ListingHeader`. -- **Rationale:** See #5. +- **Rationale:** A "summary" with 20 fields, including nested objects and full audit metadata, promises a slim shape the type does not deliver. -### 7. `FileParent` — abstract container with weak typing +### 3. `FileParent` — abstract container with weak typing -**Location:** `src/v1/model.ts:345-349` +**Location:** `src/v1/model.ts:347-351` ```ts export interface FileParent { @@ -165,102 +82,15 @@ export interface FileParent { ``` The type ships with a `TODO` in the JSDoc — the API contract is incomplete by the generator's own admission. `parentId` is a free-form string with no statement of which `FileParentType` corresponds to which kind of id. `fileParentType` is a 3-value enum (`PROVIDER`, `LISTING`, `LISTING_RESOURCE`), but `LISTING_RESOURCE` has no separate `ListingResource` type in the package — it's an opaque concept. The pair is effectively a discriminated union that isn't discriminated. -- **Category:** 19 (underspecified ID), 6 (misleading: looks like a polymorphic parent but isn't typed), Observation (incomplete API). -- **Suggested name:** Either model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`) or rename `parentId` → `providerId | listingId | listingResourceId` per case. +- **Category:** 6 (misleading: looks like a polymorphic parent but isn't typed), Observation (incomplete API). +- **Suggested name:** Model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`). - **Rationale:** The `TODO` says the team knows; the type is shipped publicly anyway. -### 8. `*Request_Response` — proto-nested-message pattern leaked into public types - -**Location:** `src/v1/model.ts:203, 214, 243, 252, 280, 287, 294, 386, 410, 444, 454, 474, 484, 602, 622, 635, 926, 939, 954, 968` - -```ts -// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name. -export interface CreateFileRequest_Response { - fileInfo?: FileInfo | undefined; -} - -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type -- Proto-style nested message name. -export interface DeleteFileRequest_Response {} - -// ...and 18 others with the same shape. -``` - -Twenty response types follow the proto-IDL convention `message Request { message Response { ... } }`, which generates `Request_Response` in flat code-gen. The full list: `CreateFileRequest_Response`, `CreateListingRequest_Response`, `CreateProviderAnalyticsDashboardRequest_Response`, `CreateProviderRequest_Response`, `DeleteFileRequest_Response`, `DeleteListingRequest_Response`, `DeleteProviderRequest_Response`, `GetFileRequest_Response`, `GetLatestVersionProviderAnalyticsDashboardRequest_Response`, `GetListingRequest_Response`, `GetListingsRequest_Response`, `GetPersonalizationRequestsForProviderRequest_Response`, `GetProviderRequest_Response`, `ListFilesRequest_Response`, `ListProviderAnalyticsDashboardRequest_Response`, `ListProvidersRequest_Response`, `UpdateListingRequest_Response`, `UpdatePersonalizationRequestStatusRequest_Response`, `UpdateProviderAnalyticsDashboardRequest_Response`, `UpdateProviderRequest_Response`. - -Every one carries an `eslint-disable @typescript-eslint/naming-convention -- Proto-style nested message name.` comment, which is the codegen explicitly acknowledging that the underscore identifier exists only because of the proto serialization shape. The same package uses the underscore-free `*Response` form (`CreateExchangeResponse`, `GetExchangeResponse`, `UpdateExchangeFilterResponse`, etc.) for operations whose proto definition declares a sibling response message rather than a nested one — so the package ships **both** conventions side-by-side, and the choice between them is dictated by the proto IDL, not by anything visible at the TS surface. -- **Category:** Proto suffix/infix — `Foo_PublicRequest`-style paired-name leak (`Request_Response` underscore identifier). -- **Suggested name:** Drop the underscore: `CreateFileResponse`, `DeleteFileResponse`, `GetListingResponse`, `ListProvidersResponse`, etc.; for empty-body cases (`Delete*Request_Response`, `Update*Request_Response` where the body is `{}`), have the corresponding client method return `void` and drop the type entirely. -- **Rationale:** The underscore in `Request_Response` is the protobuf service convention (`.Request.Response` in proto IDL); nothing in the JS SDK contract demands it. TS callers see two unrelated naming styles for the same concept (the "Response" payload), with the choice driven by an upstream proto definition they cannot see. - --- ## Medium severity -### 9. `Client` — generic top-level class name - -**Location:** `src/v1/client.ts:210` - -```ts -export class Client { ... } -``` - -Top-level export named just `Client`. Every generated package exports a `Client` class with the same name; importing two requires aliasing (`import { Client as MarketplacesClient } from '@databricks/sdk-marketplaces/v1'`). -- **Category:** 1 (vague), 12 (duplicate across packages). -- **Suggested name:** `MarketplacesClient`. -- **Rationale:** Service-prefixed client class names are standard across `@aws-sdk/*`, `@google-cloud/*`, `@azure/*`. - -### 10. `ExchangeFilterType.GLOBAL_METASTORE_ID` — single-value enum - -**Location:** `src/v1/model.ts:68-70` - -```ts -export enum ExchangeFilterType { - GLOBAL_METASTORE_ID = 'GLOBAL_METASTORE_ID', -} -``` - -An enum with a single member. Typically a sign that the API anticipates future filter types but only has one today — but in TypeScript a single-value enum is just `'GLOBAL_METASTORE_ID'`. The naming is fine; the type's existence is the smell. -- **Category:** 11 (trivially small enum), 1 (over-engineered for one value). -- **Suggested name:** Could be a string literal type until a second value lands. -- **Rationale:** TS allows narrowing without enums (`type ExchangeFilterType = 'GLOBAL_METASTORE_ID'`). - -### 11. `MarketplaceFileType.APP` — three-letter generic value - -**Location:** `src/v1/model.ts:126` - -```ts -export enum MarketplaceFileType { - PROVIDER_ICON = 'PROVIDER_ICON', - EMBEDDED_NOTEBOOK = 'EMBEDDED_NOTEBOOK', - APP = 'APP', -} -``` - -`APP` is the only member without a qualifier. Compare with `EMBEDDED_NOTEBOOK` — prefixed with "embedded" to indicate it's attached to a listing. Is `APP` similarly embedded? Is it a Databricks App package file? A general application archive? Without a qualifier or doc-comment the value is ambiguous. -- **Category:** 1 (vague), 17 (inconsistent qualifier convention with peers). -- **Suggested name:** `EMBEDDED_APP` or `APP_PACKAGE`. -- **Rationale:** Match the qualifier convention of `EMBEDDED_*` peers. - -### 12. `PersonalizationRequestStatus.REQUEST_PENDING` — preposition-padded value with a workaround comment - -**Location:** `src/v1/model.ts:129-135` - -```ts -export enum PersonalizationRequestStatus { - NEW = 'NEW', - /** Pending already defined for ListingStatus */ - REQUEST_PENDING = 'REQUEST_PENDING', - FULFILLED = 'FULFILLED', - DENIED = 'DENIED', -} -``` - -The JSDoc explicitly says the value is named `REQUEST_PENDING` because `PENDING` is already defined for `ListingStatus`. But these are separate TS enum types; there is no collision (TypeScript enums are scoped). The renaming reveals a server-side or proto-side collision concern, leaked into the SDK as an awkward enum value. A user reading `PersonalizationRequestStatus.REQUEST_PENDING` and `ListingStatus.PENDING` will reasonably expect them to mean different things — they don't. -- **Category:** 18 (long enum values), 6 (misleading: name implies a different concept than `Pending`), 17 (inconsistent value patterns within file). -- **Suggested name:** `PENDING` (cross-enum collisions don't exist in TS). -- **Rationale:** Proto-side collision avoidance has no purpose in the TS surface. - -### 13. `Cost` — single-word, ambiguous enum +### 4. `Cost` — single-word, ambiguous enum **Location:** `src/v1/model.ts:46-49` @@ -271,12 +101,12 @@ export enum Cost { } ``` -`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 669) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". +`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 647) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". - **Category:** 1 (vague), 6 (misleading: implies price, means tier). - **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. - **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. -### 14. `DataRefresh` — enum named after the noun, not the property +### 5. `DataRefresh` — enum named after the noun, not the property **Location:** `src/v1/model.ts:51-61` @@ -294,28 +124,12 @@ export enum DataRefresh { } ``` -The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 258) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. Also note: values mix nouns (`SECOND`, `MINUTE`) with adjectives (`HOURLY`, `DAILY`, `WEEKLY`) within the same enum — `SECONDLY` and `MINUTELY` are not used. -- **Category:** 1 (vague: name is the noun, not the unit), 17 (inconsistent value form: nouns vs adverbs). +The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 257) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. +- **Category:** 1 (vague: name is the noun, not the unit). - **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. -- **Rationale:** Self-documenting enum name; consistent value form. - -### 15. `DataRefresh.NONE` vs `SECOND`/`MINUTE`/`HOURLY` — second is special - -**Location:** `src/v1/model.ts:52-55` - -```ts -NONE = 'NONE', -SECOND = 'SECOND', -MINUTE = 'MINUTE', -HOURLY = 'HOURLY', -``` - -`NONE` reads as "no refresh"; `SECOND` reads as "every second"; `HOURLY` reads as "every hour". The first two follow noun-naming; the third follows adverb-naming. Mixing the two within the same enum produces inconsistency. -- **Category:** 17 (inconsistent value form). -- **Suggested name:** Pick one convention. If "every X" adverbs are used, change `SECOND` → `SECONDLY`, `MINUTE` → `MINUTELY`, `NONE` → unchanged. -- **Rationale:** See #14. +- **Rationale:** Self-documenting enum name. -### 16. `Category` — generic enum name with 22 values +### 6. `Category` — generic enum name with 22 values **Location:** `src/v1/model.ts:21-44` @@ -329,73 +143,10 @@ export enum Category { `Category` is generic without a domain qualifier (compare with `AssetType`, `ListingType`, `MarketplaceFileType`). The other enums use a domain prefix; `Category` does not. Also, it's exported at the package root and a user importing `Category` doesn't know it's marketplace-scoped. - **Category:** 1 (vague), 17 (inconsistent qualifier convention). -- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 732). +- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 710). - **Rationale:** Cross-package collision avoidance and self-documentation. -### 17. `ListingDetail.cost` typed as `Cost` (enum), but doc says price - -**Location:** `src/v1/model.ts:668-669, 673-674` - -```ts -/** Whether the dataset is free or paid */ -cost?: Cost | undefined; -/** - * What the pricing model is (e.g. paid, subscription, paid upfront); should only be present if cost is paid - * TODO: Not used yet, should deprecate if we will never use it - */ -pricingModel?: string | undefined; -``` - -Two related fields: `cost: Cost (= 'FREE' | 'PAID')` and `pricingModel: string` (free-form). The first is the boolean-like cost tier, the second is the model. The second carries an inline `TODO` admitting it might never be used. The pair encodes "is it free?" and "if not, how is it priced?" but the relationship isn't enforced and the JSDoc says it "should only be present if cost is paid" — relationship in prose, not in types. -- **Category:** 1 (vague), 16 (field contradicts type domain — `cost` is a category, `pricingModel` is a string). -- **Suggested name:** Combine into one discriminated union: `pricing?: { $case: 'free' } | { $case: 'paid', model: string }`. -- **Rationale:** Type-system can encode the relationship the prose tries to. - -### 18. `ListingDetail.updateFrequency` vs `collectionGranularity` — same type, different naming - -**Location:** `src/v1/model.ts:675-678` - -```ts -/** How often data is updated */ -updateFrequency?: DataRefreshInfo | undefined; -/** Smallest unit of time in the dataset */ -collectionGranularity?: DataRefreshInfo | undefined; -``` - -Both are `DataRefreshInfo` (an interval), but one is named "frequency" and the other "granularity". A reader unfamiliar with the domain has to read both doc-comments to disambiguate. Also note that `DataRefreshInfo` is named after only one of its uses (`update_frequency`, which the wire calls "data_refresh") — the type is reused for collection granularity, which has nothing to do with refresh. -- **Category:** 6 (misleading: type name `DataRefresh` doesn't fit "collection granularity"), 17 (inconsistent vocabulary for the same concept). -- **Suggested name:** Rename type → `TimeInterval`; keep the field-level distinction. -- **Rationale:** Reuse a generic type name for a reusable type. - -### 19. `ListingDetail.tags: ListingTag[]` — typed-but-not-typed tags - -**Location:** `src/v1/model.ts:689-704` - -```ts -export interface ListingDetail { - ... - /** - * Listing tags - Simple key value pair to annotate listings. - * When should I use tags vs dedicated fields? - * ... - */ - tags?: ListingTag[] | undefined; -} - -export interface ListingTag { - /** Tag name (enum) */ - tagName?: ListingTagType | undefined; - /** String representation of the tag value. Values should be string literals (no complex types) */ - tagValues?: string[] | undefined; -} -``` - -The enum constrains tag *names* to a small set. Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. -- **Category:** 6 (misleading: name implies free-form labels, structure is constrained), 7 (`tagName` / `tagValues` add `tag` prefix repeated from type name). -- **Suggested name:** Rename type to clarify (e.g. `ListingAttribute`). -- **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. - -### 20. `ContactInfo` — generic suffix on a single-purpose type +### 7. `ContactInfo` — generic suffix on a single-purpose type **Location:** `src/v1/model.ts:171-177` @@ -409,14 +160,14 @@ export interface ContactInfo { } ``` -`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 752). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. +`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 730). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. - **Category:** 8 (redundant `Info` suffix), 1 (vague). - **Suggested name:** `Contact` or `ConsumerContact`. - **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. -### 21. `RegionInfo` — `Info` suffix on a single-purpose type +### 8. `RegionInfo` — `Info` suffix on a single-purpose type -**Location:** `src/v1/model.ts:791-794` +**Location:** `src/v1/model.ts:769-772` ```ts export interface RegionInfo { @@ -425,14 +176,15 @@ export interface RegionInfo { } ``` -Same problem as #20. Also note: both fields are `string` — there's no enum of cloud providers or regions. The type name suggests rich info; the shape is two strings. -- **Category:** 8 (redundant `Info` suffix), 19 (underspecified — no enum constraints). +Same problem as #7. The `*Info` suffix is generic and the type is reused only as +a region descriptor. +- **Category:** 8 (redundant `Info` suffix). - **Suggested name:** `Region` (the cloud is implicitly part of the region in many SDKs) or `CloudRegion`. -- **Rationale:** Avoid `*Info` suffix; consider richer typing. +- **Rationale:** Avoid the `*Info` suffix; name the type for the concept it represents. -### 22. `ShareInfo` — `Info` suffix on a sharing concept +### 9. `ShareInfo` — `Info` suffix on a sharing concept -**Location:** `src/v1/model.ts:839-842` +**Location:** `src/v1/model.ts:816-819` ```ts export interface ShareInfo { @@ -441,14 +193,14 @@ export interface ShareInfo { } ``` -Same problem as #20 and #21. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". +Same problem as #7 and #8. Additionally, `ShareInfo.type: ListingShareType` reads as "the listing-share-type of the share" — three nouns to communicate "is this a sample or full share". - **Category:** 8 (redundant `Info` suffix). - **Suggested name:** `Share`, `ListingShare`. -- **Rationale:** See #20. +- **Rationale:** See #7. -### 23. `ProviderInfo` — `Info` suffix on the canonical provider type +### 10. `ProviderInfo` — `Info` suffix on the canonical provider type -**Location:** `src/v1/model.ts:772-789` +**Location:** `src/v1/model.ts:750-767` ```ts export interface ProviderInfo { @@ -460,30 +212,30 @@ export interface ProviderInfo { } ``` -Same problem as #20. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. +Same problem as #7. The package also has `CreateProviderRequest`, `GetProviderRequest`, `UpdateProviderRequest`, `DeleteProviderRequest`, `ListProvidersRequest` — all referencing the noun `Provider`. The canonical full type is named `ProviderInfo`, but consumers would expect `Provider`. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent: the rest of the package uses `Provider` alone). - **Suggested name:** `Provider`. - **Rationale:** Consistency with method/request type names. -### 24. `DataRefreshInfo` — `Info` suffix on an interval type +### 11. `DataRefreshInfo` — `Info` suffix on an interval type -**Location:** `src/v1/model.ts:256-259` +**Location:** `src/v1/model.ts:255-258` ```ts export interface DataRefreshInfo { - interval?: number | undefined; + interval?: bigint | undefined; unit?: DataRefresh | undefined; } ``` -Same problem as #20. Also note: the type is reused for `collectionGranularity` (#18), so the name `DataRefreshInfo` is wrong for half of its uses. -- **Category:** 8 (redundant `Info` suffix), 6 (misleading: name doesn't fit `collectionGranularity` use). -- **Suggested name:** `TimeInterval` (matches #18). -- **Rationale:** See #18. +Same problem as #7. Also note: the type models a generic time interval, so the `DataRefresh` stem reads as too narrow for the concept. +- **Category:** 8 (redundant `Info` suffix), 6 (misleading: name implies a refresh event, not an interval). +- **Suggested name:** `TimeInterval`. +- **Rationale:** Avoid the `*Info` suffix and name the type for the generic interval concept it represents. -### 25. `FileInfo` — `Info` suffix on the canonical file type +### 12. `FileInfo` — `Info` suffix on the canonical file type -**Location:** `src/v1/model.ts:330-343` +**Location:** `src/v1/model.ts:332-345` ```ts export interface FileInfo { @@ -493,91 +245,44 @@ export interface FileInfo { } ``` -Same problem as #20. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. +Same problem as #7. The package also has `CreateFileRequest`, `GetFileRequest`, `DeleteFileRequest`, `ListFilesRequest` — all referencing the noun `File`. The canonical full type is named `FileInfo`, breaking the pattern. - **Category:** 8 (redundant `Info` suffix), 17 (inconsistent with siblings). - **Suggested name:** `File`. -- **Rationale:** See #23. +- **Rationale:** See #10. -### 26. `ListingSummary.providerRegion` — region of what? +### 13. `ListingTag` — typed-but-not-typed tags -**Location:** `src/v1/model.ts:724` +**Location:** `src/v1/model.ts:682, 720-725` ```ts -providerRegion?: RegionInfo | undefined; -``` - -`PersonalizationRequest.consumerRegion` (line 751) uses the same `RegionInfo` type with the `consumer` qualifier. So the package has `providerRegion` and `consumerRegion` — two different qualifiers for the same `RegionInfo` type. Fine; flagged because the *type* name (`RegionInfo`) is unqualified, while every *use* requires a qualifier. -- **Category:** 1 (vague type, qualified field), 17 (qualifier convention not encoded in the type). -- **Suggested name:** No rename; this is the price of reusing `RegionInfo`. -- **Rationale:** Observation. - ---- - -## Low severity - -### 27. `Listing.id` vs `ListingDetail.fileIds: string[]` vs `ListingSummary.exchangeIds: string[]` — id pluralization - -**Location:** `src/v1/model.ts:653, 663, 737` - -Mixed singular/plural id fields: -- `Listing.id` — single id of the listing. -- `ListingDetail.fileIds: string[]` — many file ids. -- `ListingSummary.exchangeIds: string[]` — many exchange ids. -- `ListingSummary.providerId: string` — single provider id. -- `ListingSummary.createdById: number` — single id, type `number` (not `string` like other ids — see #28). - -Within one transitive type (`Listing → ListingSummary | ListingDetail`), id fields use 4 different patterns: `id`, `*Id` (number), `*Id` (string), `*Ids` (string[]). Internal consistency check fails. -- **Category:** 9 (singular/plural mismatch), 17 (inconsistent suffix convention), 19 (underspecified — see #28). -- **Suggested name:** Pick one — `*Id`/`*Ids` is standard. -- **Rationale:** Observation; flagged for completeness. - -### 28. `ListingSummary.createdById: number` and `updatedById: number` — id typed as number - -**Location:** `src/v1/model.ts:734-735` - -```ts -createdById?: number | undefined; -updatedById?: number | undefined; -``` - -User ids are typed as `number`. JS `number` only safely represents integers up to 2^53; Databricks user ids are 64-bit (int64). Same issue flagged in `grants` audit #13. -- **Category:** 19 (underspecified ID), 16 (field contradicts JS type domain). -- **Suggested name:** `createdById: string` or `bigint`. -- **Rationale:** Lossy representation; consistency with other id fields (all `string`). - -### 29. `Visibility.PUBLIC` / `Visibility.PRIVATE` — binary enum named `Visibility` - -**Location:** `src/v1/model.ts:137-140` +export interface ListingDetail { + ... + /** + * Listing tags - Simple key value pair to annotate listings. + * When should I use tags vs dedicated fields? + * ... + */ + tags?: ListingTag[] | undefined; +} -```ts -export enum Visibility { - PUBLIC = 'PUBLIC', - PRIVATE = 'PRIVATE', +export interface ListingTag { + /** Tag name (enum) */ + tagName?: ListingTagType | undefined; + /** String representation of the tag value. Values should be string literals (no complex types) */ + tagValues?: string[] | undefined; } ``` -Two-value enum. Could be a boolean (`isPublic?: boolean`) or a string literal type. The enum is fine; flagged for completeness. -- **Category:** 11 (trivially small enum). -- **Suggested name:** Could be `'public' | 'private'` literal union. -- **Rationale:** Observation. - -### 30. `ListingShareType.SAMPLE` / `ListingShareType.FULL` — adjective vs noun - -**Location:** `src/v1/model.ts:99-102` +The enum constrains tag *names* to a small set. Values are free-form strings. So a "tag" is really a `(name: enum, values: string[])` pair — that's not a tag in the colloquial sense (tag = single label). Compare with how `kubernetes` or `aws` model tags: `{ key: string, value: string }`. The marketplace model is `{ tagName: enum, tagValues: string[] }` — many-to-many. +- **Category:** 6 (misleading: name implies free-form labels, structure is constrained). +- **Suggested name:** Rename type to clarify (e.g. `ListingAttribute`). +- **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. -```ts -export enum ListingShareType { - SAMPLE = 'SAMPLE', - FULL = 'FULL', -} -``` +--- -`SAMPLE` is a noun (a small portion of something); `FULL` is an adjective (complete). The convention is mixed. -- **Category:** 17 (inconsistent value form). -- **Suggested name:** `SAMPLE` / `COMPLETE` (both nouns) or `PARTIAL` / `FULL` (both adjectives). -- **Rationale:** Internal consistency. +## Low severity -### 31. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values +### 14. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values **Location:** `src/v1/model.ts:118-121` @@ -588,16 +293,7 @@ export enum ListingType { } ``` -Two adjective values. Fine. Flagged because the package also has `PersonalizationRequest` (line 749) — the noun for `PERSONALIZED` mode. Cross-reference unclear. +Two adjective values. Fine. Flagged because the package also has `PersonalizationRequest` (line 727) — the noun for `PERSONALIZED` mode. Cross-reference unclear. - **Category:** Observation. - **Suggested name:** No rename. - **Rationale:** Internal consistency check. - ---- - -## Observations - -### 32. v1-only audit -The marketplaces package has only v1 today (`packages/marketplaces/src/v1/`), so no v1↔v2 comparison to make. - ---- diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index 6e4e526c..33c71b9e 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -1,110 +1,55 @@ # Naming Audit: `metastores` package (v1) -**Package path:** `/home/parth.bansal/sdk-js/packages/metastores/` +**Package path:** `/home/parth.bansal/sdk-js/packages/uc/metastores/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog (UC) metastore — the top-level container that holds catalogs, schemas, and tables, and is assigned to workspaces. --- -## Summary - -The `metastores` package exposes nine Unity Catalog metastore operations -(`createMetastore`, `createMetastoreAssignment`, `deleteMetastore`, -`deleteMetastoreAssignment`, `getCurrentMetastoreAssignment`, -`getMetastore`, `getMetastoreSummary`, `listMetastores`, -`updateMetastore`, `updateMetastoreAssignment`). -The dominant naming problems are structural: `CreateMetastoreRequest`, -`UpdateMetastoreRequest`, and `MetastoreInfo` share 18 fields verbatim, -including read-only output fields (`createdAt`, `createdBy`, `updatedAt`, -`updatedBy`, `metastoreId`, `globalMetastoreId`) that have no business in -a write request. `UpdateMetastoreRequest` further conflates a path-parameter -`id`, a body `name`, and a "rename target" `newName`. -`GetMetastoreSummaryRequest_Response` is structurally identical to -`MetastoreInfo` despite the "summary" name promising a smaller shape. - ---- - ## Findings ### 1. Vague / generic names -#### 1.1 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:363, 365) +#### 1.1 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:355, 357) Acceptable in isolation — but the *type* `MetastoreAssignment` is just a `(workspaceId, metastoreId, defaultCatalogName)` triple. The name "MetastoreAssignment" promises richer semantics than the three-field struct delivers. Consider `WorkspaceMetastoreLink` or making the relationship directional in the name. -#### 1.2 `cloud` field (model.ts:195, 252, 407, 448, 509) -A bare `cloud: string` with a single example list in the doc (`aws`, -`azure`, `gcp`). Should probably be typed as a `CloudProvider` enum -(see §5.2) — but at minimum the field is generic when read alone. - ---- - -### 2. Redundant enum prefixes - -_None._ - --- -### 3. Acronym casing inconsistencies - -_None._ - ---- +### 2. Misleading names -### 4. Cryptic abbreviations - -_None._ - ---- - -### 5. Misleading names - -#### 5.1 `MetastoreInfo` (model.ts:373) +#### 2.1 `MetastoreInfo` (model.ts:365) "Info" suggests metadata about a metastore separate from the entity -itself; the type is in fact the entity. See also §7.1. - -#### 5.2 `cloud: string` (model.ts:195, 252, 407, 448, 509) -Holds an enum-like vocabulary (`aws`, `azure`, `gcp`) but is typed as -`string`. The name is fine; the *type* misleads about the value -space. See §1.2. - -#### 5.3 `GetMetastoreSummaryRequest_Response` is structurally identical to `MetastoreInfo` (model.ts:294-333 vs 373-412) -Both types have the *same* 18 fields with the *same* docs in the *same* -order. The "summary" type doesn't actually summarise — it returns the -full metastore record. The name lies about the content. The Go SDK -inherits this from the API definition, but the TS port could collapse -the two: either alias the summary response to `MetastoreInfo` or -expose the genuinely-summarised subset. - -#### 5.4 `getMetastoreSummary` is presented as info-about (client.ts:616-619) +itself; the type is in fact the entity. See also §4.1. + +#### 2.2 `getMetastoreSummary` is presented as info-about (client.ts:637) JSDoc says "Gets information about a metastore. This summary includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" omits the "current-workspace" semantics. Cf. -`getCurrentMetastoreAssignment`, which spells out "current". See also -§10.1. +`getCurrentMetastoreAssignment`, which spells out "current". --- -### 6. Overly verbose +### 3. Overly verbose -#### 6.1 `getCurrentMetastoreAssignment` (client.ts:567) +#### 3.1 `getCurrentMetastoreAssignment` (client.ts:578) 28-character method name. Acceptable — describes the semantics — but combined with `getMetastoreSummary` (which is also "current-workspace" -in practice, §5.4) one of them carries redundant prefixing. +in practice, §2.2) one of them carries redundant prefixing. --- -### 7. Redundant suffixes +### 4. Redundant suffixes -#### 7.1 `…Info` suffix on `MetastoreInfo` (model.ts:373) +#### 4.1 `…Info` suffix on `MetastoreInfo` (model.ts:365) "Info" carries no semantic content. Go-SDK convention; TS would just -say `Metastore`. See §9.2. +say `Metastore`. See §6.2. -#### 7.2 `…Assignment` suffix on `MetastoreAssignment` and four request types +#### 4.2 `…Assignment` suffix on `MetastoreAssignment` and four request types `CreateMetastoreAssignmentRequest`, `DeleteMetastoreAssignmentRequest`, `UpdateMetastoreAssignmentRequest`, `GetCurrentMetastoreAssignmentRequest`, `MetastoreAssignment`. The suffix is justified because "metastore @@ -113,77 +58,27 @@ completeness. --- -### 8. Singular / plural mismatches +### 5. Singular / plural mismatches -#### 8.1 `ListMetastoresRequest_Response.metastores` (model.ts:353) +#### 5.1 `ListMetastoresResponse.metastores` (model.ts:345) Field is plural and correctly typed `MetastoreInfo[]` — no mismatch. Flagged as a counter-example. --- -### 9. Reserved-word collisions +### 6. Reserved-word collisions -#### 9.1 `name` field on `CreateMetastoreRequest`, `MetastoreInfo`, `UpdateMetastoreRequest`, `GetMetastoreSummaryRequest_Response` response (model.ts:220, 298, 375, 477) +#### 6.1 `name` field on `CreateMetastoreRequest`, `MetastoreInfo`, `UpdateMetastoreRequest`, `GetMetastoreSummaryResponse` (model.ts:214, 291, 367, 469) Routinely shadows `Function.prototype.name`. Common SDK convention; not -fixable in isolation. See also §10.1. +fixable in isolation. -#### 9.2 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. +#### 6.2 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. --- -### 10. Duplicate concepts - -#### 10.1 `MetastoreInfo` vs `GetMetastoreSummaryRequest_Response` (model.ts:294, 373) -Same 18 fields, same docs, different names. See §5.3. - -#### 10.2 `CreateMetastoreRequest` vs `MetastoreInfo` vs `UpdateMetastoreRequest` (model.ts:218, 373, 471) -Massive structural duplication — `CreateMetastoreRequest` has 19 fields, -`MetastoreInfo` has 19 fields, `UpdateMetastoreRequest` has 20 fields. -The extra fields on `UpdateMetastoreRequest` are `id` (path param) and -`newName`. Every other field is replicated verbatim with the same doc -string. A shared `MetastoreCommon` (or `Partial`) would -let renames happen in one place. Note that all three contain the same -read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, -`metastoreId`, `globalMetastoreId`) — these have no business on a -request shape (§11.3). - -#### 10.3 `CreateMetastoreAssignmentRequest` vs `MetastoreAssignment` vs `UpdateMetastoreAssignmentRequest` (model.ts:202, 361, 455) -Three structurally identical types with three workspace-id / -metastore-id / default-catalog-name fields. Could be unified. - -#### 10.4 `name` vs `newName` on `UpdateMetastoreRequest` (model.ts:475, 477) -Two name-like fields on the update request: -- `newName` — "New name for the metastore." (model.ts:475). -- `name` — "The user-specified name of the metastore." (model.ts:477). - -Per the doc, both fields can hold a name. The intent is presumably -that `newName` is the rename target and `name` is left over from the -shared shape; in practice, callers cannot tell. See §11.1. - ---- - -### 11. Field contradicting type domain - -#### 11.1 `UpdateMetastoreRequest` has `id`, `name`, `newName`, and `metastoreId` (model.ts:473, 475, 477, 497) -Four name/id-like fields on a single update request: -- `id` — path parameter; the existing metastore to update. -- `metastoreId` — leftover from the shared shape; not used by the - client method (`req.id` is what is interpolated into the URL at - client.ts:718). -- `name` — "The user-specified name of the metastore." Ambiguous - whether this is the current or new name. -- `newName` — "New name for the metastore." Presumably the rename - target. - -A caller staring at this struct cannot intuit which field controls -what. This is the package's single most user-hostile naming pattern, -mirroring the `UpdateCatalog` issue (catalogs §16.1). +### 7. Field contradicting type domain -#### 11.2 `UpdateMetastoreRequest.metastoreId` shadows `UpdateMetastoreRequest.id` (model.ts:473, 497) -Same as 11.1 — two id-like fields whose roles are not differentiated -by name. - -#### 11.3 `CreateMetastoreRequest` and `UpdateMetastoreRequest` carry read-only output fields (model.ts:240-256, 497-513) +#### 7.1 `CreateMetastoreRequest` and `UpdateMetastoreRequest` carry read-only output fields (model.ts:234-248, 489-503) `metastoreId`, `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `globalMetastoreId`, `cloud`, `storageRootCredentialName`. These are server-populated; a creator/updater setting them is at best ignored. @@ -191,72 +86,34 @@ The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of catalogs §16.2. -#### 11.4 `GetMetastoreSummaryRequest_Response` returns the full metastore (model.ts:294) — see §5.3. The type name promises a summary; the value is the entity. - ---- - -### 12. Inconsistent action verbs - -#### 12.1 `getMetastore` vs `getMetastoreSummary` vs `getCurrentMetastoreAssignment` (client.ts:592, 620, 567) -Three "get"-style methods, each with a different qualifier: -- `getMetastore(req)` — get by id. -- `getMetastoreSummary()` — get the current metastore (no id). -- `getCurrentMetastoreAssignment()` — get the current - workspace/metastore assignment. - -The first explicitly takes an id, the second implicitly uses the -current workspace, the third explicitly says "Current". Inconsistent -qualifier vocabulary. Either rename `getMetastoreSummary` to -`getCurrentMetastore` (which would also fix §5.4) or drop "Current" -from `getCurrentMetastoreAssignment`. - -#### 12.2 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. +#### 7.2 `GetMetastoreSummaryResponse` returns the full metastore (model.ts:287) +The type name promises a summary; the value is the full metastore +entity, with the same 19 fields and docs as `MetastoreInfo`. --- -### 13. Underspecified IDs +### 8. Inconsistent action verbs -#### 13.1 `storageRootCredentialId` (model.ts:169, 225, 302, 381, 421, 482) -Doc says "UUID of storage credential" — the doc says UUID here, but the -field name doesn't carry the type. The field name should communicate -the identifier shape that the doc already specifies. - ---- - -### 14. Proto / architectural-leak naming - -_None._ - ---- - -### 15. Type-suffix tautology - -#### 15.1 `MetastoreInfo` exposes `metastoreId` (model.ts:373, 395) -The type's domain is the metastore; the field redundantly carries the -entity name in its identifier. Acceptable convention; flagged for -completeness. - -#### 15.2 `MetastoreAssignment` carries `metastoreId` (model.ts:361, 365) -Same pattern as 15.1 — entity name in field. +#### 8.1 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. --- ## Additional / cross-cutting observations -### A. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:471, 537, 748) +### A. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:476, 545, 771) If `workspaceId` is undefined, the URL silently becomes `/api/2.1/unity-catalog/workspaces//metastore` (note the double slash) and the request will fail on the server. The optional typing of `workspaceId` on `CreateMetastoreAssignmentRequest`, `DeleteMetastoreAssignmentRequest`, and `UpdateMetastoreAssignmentRequest` -(each field is `number | undefined`) lets the bug hide. +(each field is `bigint | undefined`) lets the bug hide. -### B. `req.id` is similarly optional but interpolated into URLs (client.ts:503, 596, 718) +### B. `req.id` is similarly optional but interpolated into URLs (client.ts:511, 610, 738) `${req.id ?? ''}` — same pattern: undefined id silently produces a -malformed URL. Combined with the generic `id` name the type -contract is too loose for a required path parameter. +malformed URL. The optional typing leaves the contract too loose for a +required path parameter. -### C. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:538-543) +### C. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:545-549) On `DELETE /api/2.1/unity-catalog/workspaces/{workspaceId}/metastore`, the request appends `?metastore_id=…`. That contradicts the doc on `DeleteMetastoreAssignmentRequest.metastoreId` ("Query for the ID of @@ -264,82 +121,6 @@ the metastore to delete.") only via the leading word "Query" — the field name itself does not signal that the value is a query parameter, not a path one. -### D. `Client` constructor throws bare `Error` for missing `host` (client.ts:109) +### D. `MetastoresClient` constructor throws bare `Error` for missing `host` (client.ts:112) "Host is required." — bare `Error`. Not a naming issue, flagged in passing for the broader review. - -### E. `MetastoreAssignment.workspaceId` is `number` while everything else `workspaceId` is also `number` — but the rest of the SDK varies -This package's `workspaceId` is `number`. Some peer packages model -workspace IDs as strings (e.g. when forwarded through URL params). -The type inconsistency is across packages, not within this one; -flagged in passing. - ---- - -## File / line index for fast lookup - -| Identifier | Location | Finding | -| ------------------------------------------------------- | ------------------ | ------- | -| `CreateMetastoreRequest` | model.ts:218 | 10.2, 11.3 | -| `CreateMetastoreRequest.name` | model.ts:220 | 9.1 | -| `CreateMetastoreRequest.storageRootCredentialId` | model.ts:226 | 13.1 | -| `CreateMetastoreRequest.cloud` | model.ts:252 | 1.2, 5.2 | -| `CreateMetastoreRequest.metastoreId` (read-only) | model.ts:240 | 11.3, 15.1 | -| `CreateMetastoreRequest.createdAt` (read-only) | model.ts:242 | 11.3 | -| `CreateMetastoreRequest.createdBy` (read-only) | model.ts:244 | 11.3 | -| `CreateMetastoreRequest.updatedAt` (read-only) | model.ts:246 | 11.3 | -| `CreateMetastoreRequest.updatedBy` (read-only) | model.ts:248 | 11.3 | -| `CreateMetastoreRequest.storageRootCredentialName` | model.ts:250 | 11.3 | -| `CreateMetastoreRequest.globalMetastoreId` (read-only) | model.ts:254 | 11.3 | -| `CreateMetastoreAssignmentRequest` | model.ts:202 | 10.3 | -| `CreateMetastoreAssignmentRequest.workspaceId` | model.ts:203 | E | -| `CreateMetastoreAssignmentRequest.defaultCatalogName` | model.ts:212 | — | -| `DeleteMetastoreRequest` | model.ts:269 | — | -| `DeleteMetastoreAssignmentRequest` | model.ts:259 | 10.3 | -| `DeleteMetastoreAssignmentRequest.metastoreId` | model.ts:263 | C | -| `GetCurrentMetastoreAssignmentRequest` | model.ts:283 | — | -| `GetMetastoreRequest` | model.ts:285 | — | -| `GetMetastoreSummaryRequest` | model.ts:291 | — | -| `GetMetastoreSummaryRequest_Response` | model.ts:294 | 5.3, 10.1, 11.4 | -| `ListMetastoresRequest` | model.ts:335 | — | -| `ListMetastoresRequest.maxResults` | model.ts:345 | — | -| `ListMetastoresRequest.pageToken` | model.ts:347 | — | -| `ListMetastoresRequest_Response.metastores` | model.ts:353 | 8.1 (positive) | -| `ListMetastoresRequest_Response.nextPageToken` | model.ts:358 | — | -| `MetastoreAssignment` | model.ts:361 | 1.1, 7.2, 10.3 | -| `MetastoreAssignment.workspaceId` | model.ts:363 | 1.1, E | -| `MetastoreAssignment.metastoreId` | model.ts:365 | 15.2 | -| `MetastoreAssignment.defaultCatalogName` | model.ts:370 | — | -| `MetastoreInfo` | model.ts:373 | 5.1, 7.1, 10.2 | -| `MetastoreInfo.metastoreId` | model.ts:395 | 15.1 | -| `UpdateMetastoreRequest` | model.ts:471 | 10.2, 11.1, 11.3 | -| `UpdateMetastoreRequest.id` | model.ts:473 | 11.1, 11.2 | -| `UpdateMetastoreRequest.newName` | model.ts:475 | 10.4, 11.1 | -| `UpdateMetastoreRequest.name` | model.ts:477 | 10.4, 11.1 | -| `UpdateMetastoreRequest.metastoreId` | model.ts:497 | 11.1, 11.2 | -| `UpdateMetastoreAssignmentRequest` | model.ts:455 | 10.3 | -| `Client.createMetastore` | client.ts:437 | — | -| `Client.createMetastoreAssignment` | client.ts:467 | — | -| `Client.deleteMetastore` | client.ts:499 | B | -| `Client.deleteMetastoreAssignment` | client.ts:533 | A, C | -| `Client.getCurrentMetastoreAssignment` | client.ts:567 | 12.1 | -| `Client.getMetastore` | client.ts:592 | 12.1, B | -| `Client.getMetastoreSummary` | client.ts:620 | 5.4, 12.1 | -| `Client.listMetastores` | client.ts:656 | — | -| `Client.updateMetastore` | client.ts:714 | B | -| `Client.updateMetastoreAssignment` | client.ts:744 | A | -| `${req.id ?? ''}` URL substitution | client.ts:503, 596, 718 | B | -| `${req.workspaceId ?? ''}` URL substitution | client.ts:471, 537, 748 | A | -| `Host is required.` bare Error | client.ts:109 | D | - ---- - -## Recommended priority order - -1. **Disambiguate the four name/id-like fields on `UpdateMetastoreRequest`** (`id`, `metastoreId`, `name`, `newName`) — biggest user-facing trap. (§11.1, §10.4) -2. **Strip read-only fields from `CreateMetastoreRequest` / `UpdateMetastoreRequest`.** (§11.3, §10.2) -3. **Decide whether the `GetMetastoreSummaryRequest_Response` should alias `MetastoreInfo` or expose a genuine subset.** (§5.3, §10.1) -4. **Rename `getMetastoreSummary` to `getCurrentMetastore`** to match `getCurrentMetastoreAssignment` and accurately describe the call. (§5.4, §12.1) -5. **Tighten optional-typing on URL-bound parameters** (`id`, `workspaceId`) so undefined values are caught at compile time, not by malformed URLs. (Cross-cutting A, B) - ---- diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index fa7cfac4..227a8ae8 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,58 +8,32 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 30 +**Total weird names flagged:** 17 ## Summary | Severity | Count | | --- | --- | -| High | 19 | -| Medium | 6 | +| High | 13 | +| Medium | 1 | | Low | 2 | -| Observation | 3 | +| Observation | 1 | ## High severity ### 1. `ActivityAction` enum and `availableActions` field — `model.ts:20-31, 187` -- **Why weird:** `ActivityAction` enum values are full verbs like - `APPROVE_TRANSITION_REQUEST`, `CANCEL_TRANSITION_REQUEST`, - `EDIT_COMMENT`, `DELETE_COMMENT`. The field on `Activity` is named - `availableActions: ActivityAction[]`. So the *type* is "actions" but - the values look like RPC method names. Worse, the enum mixes two - unrelated domains (transition-request lifecycle + comment editing) into - one type, and the docstring says so explicitly ("For activities…For - comments…"). -- **Category:** 6 (misleading: enum members are RPC verbs not actions), - 17 (mixed-domain enum). -- **Suggested name:** Split into two enums: `TransitionRequestAction` ( - `Approve | Reject | Cancel`) and `CommentAction` (`Edit | Delete`). Or - shorten to verbs only: `ActivityAction.Approve | Reject | Cancel | Edit - | Delete`. +- **Why weird:** The field on `Activity` is named + `availableActions: ActivityAction[]`, so the *type* is "actions". The + enum mixes two unrelated domains (transition-request lifecycle + comment + editing) into one type, and the docstring says so explicitly ("For + activities…For comments…"). +- **Category:** 17 (mixed-domain enum). +- **Suggested name:** Split into two enums: `TransitionRequestAction` and + `CommentAction`. - **Rationale:** A single enum forced to cover two domains becomes a bag-of-strings. Users typing `ActivityAction.` get suggested values that may be illegal for their actual context. -### 2. `ActivityType` enum — `model.ts:47-62` -- **Why weird:** Values use past-tense verbs (`APPLIED_TRANSITION`, - `REQUESTED_TRANSITION`, `CANCELLED_REQUEST`, `APPROVED_REQUEST`, - `REJECTED_REQUEST`, `NEW_COMMENT`, `SYSTEM_TRANSITION`). The "_REQUEST" - suffix is inconsistent with the "_TRANSITION" suffix — `APPROVED_REQUEST` - is past-tense ("a request was approved"), while - `APPLIED_TRANSITION` is past-tense ("a transition was applied"). What is - `NEW_COMMENT`? It is a noun, not a past-tense verb like its peers. And - `SYSTEM_TRANSITION` is a transition performed by the system, mixing - actor + action where every other value is just an action. -- **Category:** 13 (verb-tense inconsistency), 17 (inconsistent action - verbs). -- **Suggested name:** Pick one pattern. Either all past-tense - (`TransitionApplied`, `TransitionRequested`, `RequestCancelled`, - `RequestApproved`, `RequestRejected`, `CommentPosted`, - `SystemTransitionApplied`), or simple nouns (`Apply`, `Request`, - `Cancel`, `Approve`, `Reject`, `Comment`, `SystemTransition`). -- **Rationale:** Mixed tense and grammatical category in one enum makes - it hard to remember which value to use without looking it up. - -### 3. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` +### 2. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` - **Why weird:** Enum name says `Type` but values are *states* (`ALL_EVENTS`, `DEFAULT`, `SUBSCRIBED`, `UNSUBSCRIBED`). `DEFAULT` and `ALL_EVENTS` overlap in meaning. The class doc-comment marks it @@ -71,47 +45,17 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The field consuming the enum is already called `emailSubscriptionStatus`; the enum should match. -### 4. `RegistryWebhookEvent` enum — `model.ts:113-126` -- **Why weird:** Contains both generic - `MODEL_VERSION_TRANSITIONED_STAGE` *and* three specific - `MODEL_VERSION_TRANSITIONED_TO_{STAGING,PRODUCTION,ARCHIVED}`. The - values describe the same event at two levels of granularity, so users - must pick one and the docs do not say which. Same pattern for - `TRANSITION_REQUEST_CREATED` vs three - `TRANSITION_REQUEST_TO_{STAGING,PRODUCTION,ARCHIVED}_CREATED`. -- **Category:** 17 (inconsistent action verbs), 12 (duplicate concepts - within one enum). -- **Suggested name:** Either keep the granular ones and drop the - generic, or document the relationship. -- **Rationale:** Overlap creates "two ways to express one intent" — a - classic source of bugs. - -### 5. `Activity` vs `CommentObject` vs `TransitionRequest` — `model.ts:150, 227, 1015` -- **Why weird:** Three interfaces have *identical* shape and *identical* - doc-comment ("For activities, this contains the activity recorded for - the action. For comments, this contains the comment details. For - transition requests, this contains the transition request details."). - They differ only in name. This is a Java/Go habit (one class per - context) where TS would use one type or a discriminated union. -- **Category:** 12 (duplicate concepts), 14 (Go/Java-style naming). -- **Suggested name:** Single `Activity` type used in all three slots, - with the `activityType` enum already discriminating which flavour it - is. Drop `CommentObject` and `TransitionRequest`. -- **Rationale:** All three already have the same field set including - the `activityType` discriminator. The "type per usage site" anti-pattern - forces consumers to choose between identical shapes. - -### 6. `CommentObject` — `model.ts:227` +### 3. `CommentObject` — `model.ts:226` - **Why weird:** `Object` is the most generic suffix possible in TS - (everything is an object). Combined with the duplicate-shape problem - (#5), this is a textbook bad name. + (everything is an object). The type is already a TS object, so the + suffix conveys nothing. - **Category:** 1 (vague `Object` suffix), 20 (type-suffix tautology). -- **Suggested name:** `Comment` — or fold into `Activity` per #5. +- **Suggested name:** `Comment`. - **Rationale:** `Object` adds nothing; the type is already a TS object. -### 7. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, +### 4. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, `TransitionModelVersionStageDatabricksRequest`, `ModelVersionDatabricks` — - `model.ts:542, 549, 690, 758, 981, 1005` + `model.ts:525, 676, 744, 962` - **Why weird:** `Databricks` as a type suffix. The whole SDK is the Databricks SDK; everything is "Databricks". The suffix is used to distinguish workspace-Databricks extensions from upstream MLflow @@ -127,7 +71,7 @@ is the Unity-Catalog-scoped successor. (then split by capability). The current "shadow type per extension" is a generator artefact, not a user-friendly API. -### 8. `TransitionModelVersionStageDatabricksRequest` — `model.ts:981` +### 5. `TransitionModelVersionStageDatabricksRequest` — `model.ts:962` - **Why weird:** Six-word PascalCase identifier with awkward word order. Reads as "transition[verb] model-version-stage[object]-databricks[suffix]-request[suffix]". For a @@ -143,7 +87,7 @@ is the Unity-Catalog-scoped successor. performing similar workspace operations; the asymmetric names obscure this. -### 9. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:542` +### 6. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:525` - **Why weird:** Verb-phrase request type name (`GetX`) is OK if used consistently, but `GetRegisteredModelDatabricksRequest` is the only method the SDK exposes to fetch a registered model — there is no plain @@ -155,8 +99,8 @@ is the Unity-Catalog-scoped successor. - **Rationale:** No need for the disambiguation suffix when there's no sibling. -### 10. `client.listTransitionsRequest` method vs `ListTransitionRequest` - request type — `client.ts:513, model.ts:645` +### 7. `client.listTransitionsRequest` method vs `ListTransitionRequest` + request type — `client.ts:527, model.ts:632` - **Why weird:** The method is `listTransitionsRequest` (plural "Transitions") but the request type is `ListTransitionRequest` (singular). The doc comment says "Gets a list of all open stage @@ -176,7 +120,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The method name in JS conventions describes the collection being listed; here that's "transition requests", plural. -### 11. `RegistryWebhook` vs `Webhook` — `model.ts:787` +### 8. `RegistryWebhook` vs `Webhook` — `model.ts:773` - **Why weird:** Type is `RegistryWebhook` but client methods, paths, and request types alternate: `CreateRegistryWebhookRequest`, `ListRegistryWebhooksRequest`, `UpdateRegistryWebhookRequest`, @@ -189,7 +133,7 @@ is the Unity-Catalog-scoped successor. `TestWebhookRequest`. - **Rationale:** Package name already establishes the registry context. -### 12. `HttpUrlSpec` / `JobSpec` — `model.ts:552, 563` +### 9. `HttpUrlSpec` / `JobSpec` — `model.ts:534, 545` - **Why weird:** `Spec` is a vague suffix shared by every config-bag in the SDK. Two sibling types in the same package, only the `Spec` suffix distinguishing them. `HttpUrlSpec` is the *target* of a webhook @@ -202,7 +146,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The two together discriminate the webhook destination kind; the naming should make that obvious. -### 13. `LinkedFeature` — `model.ts:573` +### 10. `LinkedFeature` — `model.ts:555` - **Why weird:** Doc comment says "Feature for model version. ([ML-57150] Renamed from Feature to LinkedFeature)". The ticket number leaks into the public docstring. Type name was changed for internal reasons @@ -215,45 +159,8 @@ is the Unity-Catalog-scoped successor. type; the fields are just identifiers pointing at a feature in the feature store. -### 14. `stage: string` field on `ApproveTransitionRequest`, - `CreateTransitionRequest`, `DeleteTransitionRequest`, - `RejectTransitionRequest`, `TransitionModelVersionStageDatabricksRequest` - — `model.ts:209, 396, 483, 847, 997` -- **Why weird:** Field is `stage: string` but valid values are - enumerated in the docstring: `None`, `Staging`, `Production`, - `Archived`. There is no `Stage` enum exported anywhere in the model, - so callers have to memorise stringly-typed magic values. Compare to - `status: ModelVersionStatus` (typed) — inconsistent treatment. -- **Category:** 6 (misleading), 16 (field-type contradicts domain). -- **Suggested name:** Introduce `Stage` enum (`None | Staging | - Production | Archived`) and type these fields accordingly. -- **Rationale:** The docstring already lists the four values; promote - to a type. Currently every transition method takes `stage: string` - with no type-level validation. - -### 15. `currentStage: string` field on `ModelVersion`, - `ModelVersionDatabricks` — `model.ts:670, 701` -- **Why weird:** Same as #14 — typed as `string`, valid values - enumerated only in docs. Also called `currentStage` here but `stage` - on request DTOs (no prefix). Inconsistent. -- **Category:** 6 (misleading), 16 (type contradicts domain), 17 - (inconsistent prefix). -- **Suggested name:** `stage: Stage` (enum) for both. -- **Rationale:** "Current" is implicit (it's the *current* stage of - this version). - -### 16. `fromStage`, `toStage` fields — `model.ts:171, 183, 248, 260, 1036, 1048` -- **Why weird:** Three different `Activity`-shaped types each duplicate - `fromStage: string | undefined`, `toStage: string | undefined`, - again stringly typed. Identical doc-comments paste the same four-value - list six times. -- **Category:** 16 (type contradicts domain), 12 (duplicate concept), 7 - (overly verbose docs). -- **Suggested name:** `fromStage: Stage`, `toStage: Stage`. -- **Rationale:** Same as #14. - -### 17. `Databricks` as a suffix is overused -- **Why weird:** Distinct type names still end in `Databricks` (see #7): +### 11. `Databricks` as a suffix is overused +- **Why weird:** Distinct type names still end in `Databricks` (see #4): `RegisteredModelDatabricks`, `ModelVersionDatabricks`. Two more retain `Databricks` as an infix inside the new `Request` suffix (`GetRegisteredModelDatabricksRequest`, @@ -261,10 +168,10 @@ is the Unity-Catalog-scoped successor. workspace-specific extension. The `Databricks` token appearing inside the *Databricks SDK* is tautological. - **Category:** 8 (redundant suffix), 20 (type-suffix tautology). -- **Suggested name:** See #7. -- **Rationale:** See #7. +- **Suggested name:** See #4. +- **Rationale:** See #4. -### 18. `getRegisteredModelDatabricks` client method — `client.ts:416` +### 12. `getRegisteredModelDatabricks` client method — `client.ts:424` - **Why weird:** Method name carries `Databricks` mid-position (between the noun `RegisteredModel` and any conceptual suffix). The whole SDK is the Databricks SDK; embedding `Databricks` inside a method name is @@ -284,9 +191,9 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The infix encodes a proto-level distinction that has no analogue in this TS surface; remove it. -### 19. `transitionModelVersionStageDatabricks` client method — - `client.ts:615` -- **Why weird:** Same `Databricks` mid-position leak as #18. The token +### 13. `transitionModelVersionStageDatabricks` client method — + `client.ts:632` +- **Why weird:** Same `Databricks` mid-position leak as #12. The token sits between `Stage` and the implicit method suffix, marking the method as the workspace-extension variant of an upstream MLflow RPC. Method-name length (six words, 38 chars) is also a symptom: the verb @@ -297,82 +204,36 @@ is the Unity-Catalog-scoped successor. (overly verbose), 14 (proto-style leakage into surface API). - **Suggested name:** `transitionModelVersionStage` (drop the infix) or fold into `approveTransitionRequest`-style verbs since the operations - overlap (see #8). -- **Rationale:** Same as #18 — the infix encodes a generator-side + overlap (see #5). +- **Rationale:** Same as #12 — the infix encodes a generator-side distinction that callers do not need. ## Medium severity -### 20. `tags?: ModelVersionTag[] | undefined` and - `tags?: RegisteredModelTag[] | undefined` — `model.ts:296, 316, 685, - 719, 755, 776` -- **Why weird:** Two parallel `*Tag` types (`ModelVersionTag`, - `RegisteredModelTag`) that both have `{ key: string; value: string }`. - Identical shape, two names. (Compare with Unity Catalog tags in - `entitytagassignments` which use one type.) -- **Category:** 12 (duplicate concepts). -- **Suggested name:** Single `Tag` type with `{ key, value }`. -- **Rationale:** Identical structure should have identical type. - -### 21. `openRequests: Activity[]` on `ModelVersionDatabricks` — `model.ts:716` -- **Why weird:** Typed as `Activity[]` but the field is documented as - "Open requests for this `model_versions`" — they are transition - *requests* (not arbitrary activities). The reason is the - identical-shape problem (#5). -- **Category:** 6 (misleading type), 16 (type contradicts domain). -- **Suggested name:** `openTransitionRequests: TransitionRequest[]` - (post-rename per #5). -- **Rationale:** Restores the intent. - -### 22. `requests: Activity[]` on list-transition-requests response — - `model.ts:655` -- **Why weird:** Stored as `Activity[]` but the response is documented - as "Array of open transition requests." -- **Category:** 6 (misleading type), 15 (generic field name). -- **Suggested name:** `transitionRequests: TransitionRequest[]`. -- **Rationale:** Same as #21 — type contradicts domain because of the - identical-shape problem (#5). - -### 23. `registeredModelDatabricks: RegisteredModelDatabricks` — - `model.ts:549` -- **Why weird:** Field name *is* the type name verbatim. The `Databricks` - suffix problem (#7) cascades into the field name. -- **Category:** 20 (type-suffix tautology). -- **Suggested name:** After dropping the `Databricks` suffix from the - type: `registeredModel: RegisteredModel`. Or just return the type - directly without a wrapper. -- **Rationale:** Reduces verbosity by removing the wrapper. - -### 24. `modelVersionDatabricks: ModelVersionDatabricks` — `model.ts:1007` -- **Why weird:** Same as #23 for `ModelVersionDatabricks`. -- **Category:** 20. -- **Suggested name:** `modelVersion: ModelVersion`. -- **Rationale:** Same. - -### 25. `getLatestVersions` / `GetLatestVersionsRequest` — `client.ts:917`, - `model.ts:501` +### 14. `listLatestVersions` / `ListLatestVersionsRequest` — `client.ts:1029`, + `model.ts:564` - **Why weird:** The method returns *one* version per stage, not "the - latest version" globally. The name reads as "give me the latest - versions" (plural overall) but the meaning is "give me the latest one - for each stage". The docstring on the method (`client.ts:916`) says - "Gets the latest version of a registered model" (singular) — that's - *wrong*; the actual response returns a list keyed by stage. + latest version" globally. The name reads as "list the latest versions" + (plural overall) but the meaning is "give me the latest one for each + stage". The docstring on the method (`client.ts:1028`) says "Gets the + latest version of a registered model" (singular) — that's *wrong*; the + actual response returns a list keyed by stage. - **Category:** 6 (misleading), 9 (singular/plural confusion). -- **Suggested name:** `getLatestVersionPerStage` or - `getLatestVersionsByStage`. +- **Suggested name:** `listLatestVersionPerStage` or + `listLatestVersionsByStage`. - **Rationale:** Conveys the per-stage semantics. ## Low severity -### 26. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:584, 586, - 593, 633, 634, 642, 877, 886, 894, 905, 913, 921` +### 15. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:573, 575, + 581, 621, 622, 629, 861, 870, 877, 888, 896, 903` - **Why weird:** Consistent across the package — good. Noted for completeness. - **Category:** N/A (consistent). - **Suggested name:** No change. - **Rationale:** Observation. -### 27. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:862` +### 16. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:847` - **Why weird:** Field doc says "If provided, updates the name for this `registered_model`." Slightly confusing because `RenameRegisteredModelRequest` is *the* rename operation — "if @@ -385,25 +246,7 @@ is the Unity-Catalog-scoped successor. ## Observations -### 28. Both `modelregistry` and `registeredmodels` exist as packages -The user instruction calls out this duplication. Cross-package overlap: -- `RegisteredModel` (modelregistry) vs `RegisteredModelInfo` - (registeredmodels) — same concept, different names. -- `ModelVersion` (modelregistry) vs `ModelVersionInfo` - (registeredmodels) — same concept. -- `CreateRegisteredModelRequest` exists in both packages, with different - fields. -- `DeleteRegisteredModelRequest` exists in both. -- `ModelVersionStatus` enum exists in both, with different values - (modelregistry has `PENDING_REGISTRATION | FAILED_REGISTRATION | - READY`; verify against registeredmodels). -- Modelregistry uses tags as `RegisteredModelTag` / `ModelVersionTag`; - registeredmodels uses different tag types (verify). -- The two registries cover overlapping but not identical operations. - Documentation does not direct users to one or the other. -- **Category:** 12 (duplicate concepts — across packages). - -### 29. Action-verb conventions in `Client` +### 17. Action-verb conventions in `Client` The client mixes `Approve` / `Reject` (active verbs for transition- request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for webhook health) and `Transition` (verb-as-method-name for state @@ -411,35 +254,3 @@ machine). Consistency-wise the surface is jagged but each verb is reasonably motivated by the underlying state model. Not a defect, but worth noting. - **Category:** 17 (mixed but justified). - -### 30. Acronym casing inside doc-comments -`MLflow` is consistent throughout (good). `HTTP` appears as `HTTPS` -(`HttpUrlSpec` doc, model.ts:553) and `HTTPS` (doc, model.ts:368). Type -names use `Http` (Pascal). Standard JS-ecosystem split between Pascal-Http -and SCREAMING-HTTPS. -- **Category:** 3 (acronym casing — minor). - -## Domain glossary -- `MLflow` — Used throughout. Refers to the open-source MLflow tracking - + registry product that this package wraps. Always written `MLflow`, - never `mlflow` or `Mlflow` (good consistency). -- `Workspace` — Implicit; the entire package is workspace-scoped (vs - Unity Catalog). -- `Stage` — The MLflow stage enum: `None`, `Staging`, `Production`, - `Archived`. Never typed; only documented in field comments. -- `Activity` / `TransitionRequest` / `CommentObject` — Three names for - one shape. -- `Webhook` / `Registry Webhook` — Used interchangeably. -- `Databricks` (as a suffix) — Marker for workspace-extension types - carrying Databricks-specific fields (permissions, ACL paths, etc.). -- `Tag` — Two distinct types (`ModelVersionTag`, `RegisteredModelTag`) - with identical shape. -- `Run` — MLflow tracking run (not Databricks job run). -- `RunLink` — URL pointing back to the MLflow tracking-server run. -- `userId` — Username (not numeric ID) per doc-comments. - -## File coverage -- `src/v1/model.ts` (2001 lines): read fully. -- `src/v1/client.ts` (1337 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (94 lines): read fully. diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md index 1fb64502..0fbc8a59 100644 --- a/.agent/naming-audit/modelserving.md +++ b/.agent/naming-audit/modelserving.md @@ -3,148 +3,51 @@ **Path:** `packages/modelserving/src/v1/` **Versions audited:** v1 **Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Created by the 2026-05-22 regeneration which consolidated the prior `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. -**Total weird names flagged:** 28 +**Total weird names flagged:** 10 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 12 | -| Low | 6 | -| Observation | 2 | +| High | 4 | +| Medium | 4 | +| Low | 1 | +| Observation | 1 | ## High severity -### 1. Package noun mismatch: `modelserving` vs `InferenceEndpoint*` vs `ServingEndpoint*` vs `serving-endpoints` URL — entire package -- **Why weird:** The package directory says *model serving*, every URL path says `/api/2.0/serving-endpoints`, every JSDoc on every method says "serving endpoint", but every TS type is named `InferenceEndpoint*` (`InferenceEndpoint`, `InferenceEndpointDetailed`, `InferenceEndpointState`, `CreateInferenceEndpointRequest`, `DeleteInferenceEndpointRequest`, `GetInferenceEndpointRequest`, `GetInferenceEndpointSchemaRequest`, `ListInferenceEndpointsRequest`, `PatchInferenceEndpointTagsRequest`, `PutInferenceEndpointAiGatewayRequest`, `PutInferenceEndpointConfigRequest`, `PutInferenceEndpointRateLimitsRequest`, `UpdateInferenceEndpointNotificationsRequest`). The lone exception is `ServingEndpointDetailedPermissionLevel` (model.ts:22) — the only top-level identifier in the file that uses the actual product noun. So the package has three names for one thing: "serving endpoint" (product/doc/URL), "inference endpoint" (TS types), "serving endpoint detailed" (permission enum). -- **Category:** 6 (misleading), 12 (duplicate concept), 17 (inconsistent terminology). -- **Suggested name:** Pick one product noun. The wire and docs say `serving endpoint`; sibling Databricks SDKs (Python, Java, Go) all expose `ServingEndpoint`. Rename all `InferenceEndpoint*` to `ServingEndpoint*`, or rename the URL/docs to `inference-endpoints`. The mixed state cannot stand. -- **Rationale:** Cross-language consistency: every other Databricks SDK calls these `ServingEndpoint`. TS being the lone outlier on `InferenceEndpoint` will confuse anyone reading SDK docs side-by-side. - -### 2. `ServedModel` type now also holds non-models — `src/v1/model.ts:1004` -- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1007) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1009) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. +### 1. `ServedModel` type now also holds non-models — `src/v1/model.ts:998` +- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1001) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1003) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. - **Category:** 6 (misleading), 15 (generic field name vs specific type name). - **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. - **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. -### 3. `ServingEndpointDetailedPermissionLevel` enum — only one identifier in the package using `ServingEndpoint*` — `src/v1/model.ts:22-26` -- **Why weird:** This is the *only* type named `ServingEndpoint*`. Every other type in the file uses `InferenceEndpoint*`. Either this enum should be `InferenceEndpointPermissionLevel` (to match the rest of the package), or the rest of the package should be `ServingEndpoint*` (to match the product and wire). The `Detailed` infix is also suspect — the enum lives on `InferenceEndpointDetailed.permissionLevel`, so the type-name says "this enum belongs to InferenceEndpointDetailed", but a `permissionLevel` of `CAN_VIEW` is *not* detailed any differently from a non-detailed view; the enum applies to the resource, not to the response shape. So `Detailed` is leaking the response-DTO name into the enum name. -- **Category:** 17 (inconsistent terminology), 7 (overly verbose). -- **Suggested name:** `ServingEndpointPermissionLevel` (and rename the rest of the package — see #1). Drop `Detailed`. -- **Rationale:** Enum names that include the response-DTO shape (`Detailed`) tangle the message identity into the type identity. In TS, the enum represents a concept, not the message it appears in. - -### 4. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:587` +### 2. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:631` - **Why weird:** `httpRequest` on a model-serving `Client` is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. - **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). - **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. - **Rationale:** A method called `httpRequest` on a model-serving `Client` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. -### 5. Acronym casing storm: `Ai` / `OpenAi` / `PaLm` / `Ai21Labs` / `Pii` / `Pt` / `Llm` across the file -- **Why weird:** Mixed acronym-casing schemes on user-visible names: - - `AiGateway`, `AiGatewayConfig`, `AiGatewayRateLimit`, `AiGuardrails`, `AiGuardrailParameters` — title-cased `Ai`. - - `OpenAiConfig`, `googleCloudVertexAiConfig` — title-cased `Ai` mid-word. - - `PaLmConfig`, `palmConfig` — `PaLm` (mixed-internal-caps). The product is "PaLM" (stylized "Pathways Language Model"); the SDK chose `PaLm`, the worst rendering option. - - `Ai21Labs`, `Ai21LabsConfig` — the product is "AI21 Labs"; rendered as `Ai21Labs` (lower-case `21`, lower-case `i` mid-word). - - `PiiSettings` — `Pii` (PII = personally identifiable information); rendered title-case. - - `Pt`, `PtEndpoint`, `PtServedModel`, `PtEndpointCoreConfig`, `CreatePtEndpointRequest`, `PutPtEndpointConfigRequest` — `Pt` is "PT" (provisioned throughput). Two-letter acronym title-cased while the method names spell it out (#6). - - Excludes JS-built-in acronyms (`Http`, `Json`) and wire-format strings. -- **Category:** 3 (acronym casing inconsistencies). -- **Suggested name:** Decide a project-wide rule in `typescript.mdc`. Either follow Microsoft's .NET capitalization (title-case two-letter acronyms, PascalCase three-plus) or the Google TypeScript Style Guide (treat acronyms as whole words). Either is defensible; *none* should be mixed in one file. -- **Rationale:** Twenty-plus exported identifiers from one file vary in convention. This is the single biggest *category* of weirdness in the package surface. - -### 6. `Pt` abbreviation in types vs `ProvisionedThroughput` in methods/waiters — `src/v1/client.ts:148, 173, 515, 540, 695, 855`, `src/v1/model.ts:294, 881, 887, 981` -- **Why weird:** `Pt` is short for "provisioned throughput". The full term *is* used in two method names (`createProvisionedThroughputInferenceEndpoint`, `putProvisionedThroughputInferenceEndpointConfig`) and two waiter class names (`CreateProvisionedThroughputInferenceEndpointWaiter`, `PutProvisionedThroughputInferenceEndpointConfigWaiter`), but the request/response *types* use the abbreviation (`CreatePtEndpointRequest`, `PutPtEndpointConfigRequest`, `PtEndpointCoreConfig`, `PtServedModel`). The URL says `/api/2.0/serving-endpoints/pt`. Three different names for one concept in one call. -- **Category:** 5 (cryptic abbreviation), 17 (inconsistent abbreviation across method/type/URL). -- **Suggested name:** Either expand all (`CreateProvisionedThroughputEndpointRequest`, `PutProvisionedThroughputEndpointConfigRequest`) or contract all (`createPtEndpoint`, `putPtEndpointConfig`). Pick one. The current half-and-half is the worst option. -- **Rationale:** A user searching the codebase for `provisionedThroughput` will find the methods but not the types; searching for `pt` will find the types but produce massive false positives (`Pattern`, `Path`, `Patch`, etc.). - -### 7. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` -- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 878). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `NONE | BLOCK | MASK` — so this is *PII action behavior*. +### 3. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` +- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 874). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `NONE | BLOCK | MASK` — so this is *PII action behavior*. - **Category:** 1 (vague/generic), 15 (generic name losing meaning). - **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. - **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. -### 8. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:540`, `src/v1/client.ts:216` -- **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but `Get + Export + Endpoint + Metrics + Request` parses as five nouns in a row. The doc string (`client.ts:215`) confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English phrase is "export the endpoint's metrics" → method `exportEndpointMetrics`. Compare with sibling methods on the same client: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags` — none prefix the noun with an output format. +### 4. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:540`, `src/v1/client.ts:227` +- **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but `Get + Export + Endpoint + Metrics + Request` parses as five nouns in a row. The doc string (`client.ts:226`) confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English phrase is "export the endpoint's metrics" → method `exportEndpointMetrics`. Compare with sibling methods on the same client: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags` — none prefix the noun with an output format. - **Category:** 6 (misleading), 7 (overly verbose), 17 (inconsistent verb — every other method is `getX`, this one is `getExportX`). - **Suggested name:** `exportEndpointMetrics(req: ExportEndpointMetricsRequest)` returning `EndpointMetrics`. Or `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning `EndpointMetrics`. The "export" framing is a wire-protocol detail (Prometheus format) that does not belong in the method name. - **Rationale:** Method naming consistency across siblings; English grammar. ## Medium severity -### 9. `ServedModelDeploymentState` enum name collides with parent `ServedModelState` type — `src/v1/model.ts:12, 1069-1072` -- **Why weird:** The enum type is `ServedModelDeploymentState`, and it lives on the field `ServedModelState.deployment: ServedModelDeploymentState`. Two different types both end in `State`, one wraps the other, and the wrapper field (`deployment`) shares its name with the inner enum's category. The result reads as `served.state.deployment` returning a `ServedModelDeploymentState` — the wrapper and the enum sound like the same thing. -- **Category:** 20 (type-suffix tautology on `deployment: ServedModelDeploymentState`). -- **Suggested name:** Rename the type `ServedModelState` → `ServedModelDeployment`, and the enum `ServedModelDeploymentState` → `DeploymentState`. Call site becomes `served.state.deployment === DeploymentState.READY`. The container and the discriminant no longer share a noun. -- **Rationale:** Two `*State` siblings nested inside each other tangle the wrapper identity with the discriminant identity. - -### 10. `EndpointCoreConfig` vs `EndpointCoreConfigOutput` vs `EndpointCoreConfigSummary` — three near-duplicates — `src/v1/model.ts:376, 392, 410` -- **Why weird:** Three types describe "the config of a serving endpoint": - - `EndpointCoreConfig`: input shape (`servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig`). - - `EndpointCoreConfigOutput`: input shape + `configVersion: number`. - - `EndpointCoreConfigSummary`: lite shape (`servedEntities: ServedModelLite[]`, `servedModels: ServedModelLite[]` — no `trafficConfig`, no `autoCaptureConfig`, no `configVersion`). - - Together with `PendingConfig` (= `EndpointCoreConfigOutput` plus `startTime`) and `PtEndpointCoreConfig` (the PT variant of `EndpointCoreConfig`), there are five overlapping config types. The naming makes the differences invisible: `Output` adds one field; `Summary` removes three. -- **Category:** 12 (duplicate concept), 7 (overly verbose suffixes), 17 (inconsistent suffix semantics). -- **Suggested name:** Either collapse into one type with optional fields, or give the types names that reflect their purpose: `EndpointConfigInput` (write), `EndpointConfig` (read with version), `EndpointConfigPreview` (lite/list-view). -- **Rationale:** "Output" and "Summary" and "Detailed" are three different ways to say "the shape on the wire". The trio invites bugs where the wrong type is passed. - -### 11. `InferenceEndpoint` vs `InferenceEndpointDetailed` near-duplicate — `src/v1/model.ts:624, 653` -- **Why weird:** Two near-duplicate types: - - `InferenceEndpoint` (lines 624-651): 14 fields, used in `ListInferenceEndpointsRequest_Response.endpoints`. - - `InferenceEndpointDetailed` (lines 653-690): 18 fields, returned by `getInferenceEndpoint`, `createInferenceEndpoint`, `putInferenceEndpointConfig`. - - The "Detailed" version adds `pendingConfig`, `permissionLevel`, `routeOptimized`, `endpointUrl`, `dataPlaneInfo`, `emailNotifications` and changes `config` from `EndpointCoreConfigSummary` to `EndpointCoreConfigOutput`. So `InferenceEndpoint` is really the *list-summary* projection but its name says "the endpoint"; `InferenceEndpointDetailed` is *the* endpoint but its name says "more detail than usual". -- **Category:** 12 (duplicate concept), 7 (overly verbose suffix), 17 (inconsistent — which one is "the endpoint"?). -- **Suggested name:** `InferenceEndpointSummary` (list projection) and `InferenceEndpoint` (single-resource projection). Drop the `Detailed` suffix — the unqualified name should be the canonical resource. -- **Rationale:** A consumer writing `function show(endpoint: InferenceEndpoint)` will get the list-projection type and miss fields like `endpointUrl`. The name lies about which is canonical. - -### 12. `ServedModelLite` lite-variant — `src/v1/model.ts:1057-1067` -- **Why weird:** Same pattern as #11 at the entity level. `ServedModel` (line 1004) has 23 fields. `ServedModelLite` (lines 1057-1067) has 7 fields. The "Lite" suffix says nothing about *which* fields it kept; only by reading both types side-by-side can you see what is dropped. Compare to the JSDoc convention used in `EndpointCoreConfigSummary` (uses "Summary" in the name). -- **Category:** 12 (duplicate concept), 1 (vague suffix — `Lite` is non-standard), 17 (inconsistent: `Summary` for the parent, `Lite` for the child). -- **Suggested name:** `ServedEntitySummary` (paired with #2 rename). -- **Rationale:** Inconsistent suffix convention across the file. - -### 13. `CreatePtEndpointRequest` method-type asymmetry with `CreateInferenceEndpointRequest` — `src/v1/model.ts:271, 294` -- **Why weird:** Sister request types: - - `CreateInferenceEndpointRequest` (full name). - - `CreatePtEndpointRequest` (abbreviated). - - The PT variant is *not* called `CreateProvisionedThroughputInferenceEndpointRequest`; it is `CreatePtEndpointRequest`. The non-PT variant is not called `CreateEndpointRequest`; it is `CreateInferenceEndpointRequest`. So one type carries the qualifier `Inference`, the other carries the qualifier `Pt`. Mixed metaphor. -- **Category:** 17 (inconsistent qualifier choice). -- **Suggested name:** `CreateServingEndpointRequest` and `CreateProvisionedThroughputServingEndpointRequest` (paired with #1). -- **Rationale:** Sibling request types should differ only in the qualifier that actually differs. - -### 14. `PutInferenceEndpointConfigRequest` vs `PutPtEndpointConfigRequest` — request shape divergence — `src/v1/model.ts:950, 981` -- **Why weird:** Two "put endpoint config" requests: - - `PutInferenceEndpointConfigRequest`: flat — `name`, `servedEntities`, `servedModels`, `trafficConfig`, `autoCaptureConfig` (5 fields). - - `PutPtEndpointConfigRequest`: nested — `name`, `config: PtEndpointCoreConfig` (2 fields, with the config under a sub-object). - - Same operation conceptually, two different request shapes. The naming makes both look symmetric (`Put*EndpointConfigRequest`), but they are not. -- **Category:** 17 (inconsistent shape with consistent naming — worst case for the reader). -- **Suggested name:** Pick one shape. Either flatten both (drop the inner `PtEndpointCoreConfig`) or nest both. -- **Rationale:** API surface asymmetry hidden by consistent naming is the most surprising kind. - -### 15. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:192, 220, 247, 272, 299, 327, 383, 415, 447, 487, 519, 559` +### 5. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:200, 231, 261, 289, 319, 350, 409, 444, 479, 522, 557, 600` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — if the caller forgets to set it, the SDK silently emits a URL like `/api/2.0/serving-endpoints//metrics` (double slash) which will 404 server-side. The contradiction between "required per JSDoc" and "optional per TS type" is a typing inconsistency that bites consumers. - **Category:** 6 (misleading — JSDoc contradicts type), 16 (field contradicting type domain). -- **Suggested name:** Mark `name` as required (`endpointName: string`). Remove the `?? ''` fallback so a missing value throws earlier. Same applies to `servedModelName`. +- **Suggested fix:** Mark `name` as required (drop `?: ... | undefined`). Remove the `?? ''` fallback so a missing value throws earlier. Same applies to `servedModelName`. - **Rationale:** Optional + "required" JSDoc + empty-string fallback is a triple-violation. Cf. AIP-122 (https://google.aip.dev/122) which mandates path parameters be required. -### 16. Waiter classes have asymmetric naming — `src/v1/client.ts:615, 695, 775, 855` -- **Why weird:** Four waiter classes: - - `CreateInferenceEndpointWaiter` - - `CreateProvisionedThroughputInferenceEndpointWaiter` (53 characters) - - `PutInferenceEndpointConfigWaiter` - - `PutProvisionedThroughputInferenceEndpointConfigWaiter` (54 characters) - - Two issues: the verb tense varies (`Create*Waiter` describes the resource lifecycle; `Put*ConfigWaiter` describes the *config* operation, not the *endpoint* lifecycle); the two PT waiters spell out `ProvisionedThroughput` while the request/response types use `Pt` (#6). -- **Category:** 17 (inconsistent abbreviation: `Pt` in types, `ProvisionedThroughput` in waiter classes), 13 (verb-tense inconsistency: `Create*` vs `Put*Config*`). -- **Suggested name:** Either drop the waiter classes entirely and expose `Client.createInferenceEndpoint(...).wait(options)` directly, or shorten with a consistent rule: `CreateEndpointWaiter`, `CreatePtEndpointWaiter`, `PutEndpointConfigWaiter`, `PutPtEndpointConfigWaiter`. -- **Rationale:** Four exported waiter classes, each 30+ characters long, with five+ identical prefixes that grep the same way as the methods themselves. - -### 17. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:671-692, 751-772, 831-852, 911-932` +### 6. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:711-732, 784-805, 857-878, 930-951` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -155,57 +58,21 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 18. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:737-740` +### 7. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:733-737` - **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field, so the wrapping is a pure architectural placeholder reserved for future operations. The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. - **Category:** 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). - **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a field then. - **Rationale:** `Info`-wrapping-`Info` is an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. -### 19. `getServedModelLogs` vs `getServedModelBuildLogs` — duplicate concept "logs" — `src/v1/client.ts:295, 323` -- **Why weird:** Two methods, both retrieve logs, distinguished only by what *kind* of logs (runtime "service" logs vs container "build" logs). The build/service axis is a sub-attribute of "logs", not a separate concept. The naming makes the unqualified one (`getServedModelLogs`) sound canonical, but it is actually the service-logs special case. -- **Category:** 12 (duplicate concept), 6 (misleading — `getServedModelLogs` alone doesn't tell you it returns *service* (not build) logs). -- **Suggested name:** Rename the existing `getServedModelLogs` to `getServedModelServiceLogs` (parallel with `getServedModelBuildLogs`). Or collapse into one method with a `kind: 'build' | 'service'` parameter. -- **Rationale:** When two siblings differ by a hidden attribute, name *both* with that attribute. Today the default and the special case look asymmetric. - -### 20. `GetServedModelLogsRequest_Response.logs: string` is a single blob, name is plural — `src/v1/model.ts:570, 583` -- **Why weird:** Both `GetServedModelBuildLogsRequest_Response` and `GetServedModelLogsRequest_Response` have `logs?: string`. The field name is plural but the type is a single string — many log *lines* concatenated. A user doing `for (const line of response.logs)` will iterate characters, not lines. +### 8. `GetServedModelLogsResponse.logs: string` is a single blob, name is plural — `src/v1/model.ts:569, 581` +- **Why weird:** Both `GetServedModelBuildLogsResponse` and `GetServedModelLogsResponse` have `logs?: string`. The field name is plural but the type is a single string — many log *lines* concatenated. A user doing `for (const line of response.logs)` will iterate characters, not lines. - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** Either `logsText: string` (singular field with type-disambiguating suffix) or `logs: string[]` (split lines server-side). +- **Suggested fix:** Re-shape to `logs: string[]` (split lines server-side) so the plural name matches an iterable of lines. - **Rationale:** The current shape forces every consumer to write `response.logs.split('\n')`. ## Low severity -### 21. `*ApiKeyPlaintext` / `*Plaintext` paired-field pattern — many fields across provider configs -- **Why weird:** Every provider config has a `*ApiKey` (secret reference) and `*ApiKeyPlaintext` (literal value). Six configs, twelve pairs. The "plaintext" suffix is necessary on the wire, but in TS could be modelled as a discriminated union (`{kind: 'secret'; secretRef: string} | {kind: 'plaintext'; value: string}`). Today the user must read JSDoc to understand "exactly one of these two" semantics. -- **Category:** 6 (misleading — two optional fields modelled instead of a union), 12 (duplicate concept). -- **Suggested name:** Model as discriminated union; or at minimum mark the JSDoc with `@oneOf`. -- **Rationale:** The "must specify exactly one" constraint is invisible to the type system. - -### 22. `ExternalModel.provider` is a freeform string — `src/v1/model.ts:467` -- **Why weird:** "The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', 'palm', and 'custom'." This is a `string` that is *actually* an enum (9 known values). The discriminator union below (`config.$case`) repeats the same set with different casing. So the `provider` field and the `$case` field both encode the same fact, in two different formats. -- **Category:** 6 (misleading — string-typed enum), 12 (duplicate of `$case`). -- **Suggested name:** Type as a string-literal union: `provider?: 'ai21labs' | 'anthropic' | ... | 'custom' | undefined`. Or remove entirely and derive from `config.$case`. -- **Rationale:** A `string` field with a finite set of legal values should be a union; this is one of TS's strongest features and the codebase is bypassing it. - -### 23. `ServedModel.workloadSize` is a freeform `string` — `src/v1/model.ts:1021` -- **Why weird:** "Valid workload sizes are 'Small' (4 - 4 provisioned concurrency), 'Medium' (8 - 16 provisioned concurrency), and 'Large' (16 - 64 provisioned concurrency). Additional custom workload sizes can also be used when available in the workspace." Same pattern as #22: a string field with a documented but unenforced enum. -- **Category:** 6 (misleading), 1 (vague — `workloadSize` could mean memory, cpu, instance type, etc.). -- **Suggested name:** Keep `workloadSize`; type as `'Small' | 'Medium' | 'Large' | (string & {})` (the `& {}` trick keeps custom values acceptable while suggesting the canonical three in IDEs). -- **Rationale:** Type-narrowing fix; minor. - -### 24. `ExternalModel.task` freeform string — `src/v1/model.ts:471` -- **Why weird:** "The task type of the external model." Bare `string` with no JSDoc enumeration of accepted values. `task` is also used on `InferenceEndpoint.task` (line 642) and `InferenceEndpointDetailed.task` (line 675) with the same minimalist doc ("The task type of the serving endpoint."). Three uses of `task: string`, none telling the user what strings are legal (e.g., `chat`, `completion`, `embeddings`). -- **Category:** 1 (vague), 19 (underspecified domain). -- **Suggested name:** Type as a string-literal union or, at minimum, document the accepted values in JSDoc. -- **Rationale:** Same class as #22/#23. - -### 25. `ExportMetricsResponse` is generic "metrics" not "endpoint metrics" — `src/v1/model.ts:425-436`, `src/v1/client.ts:216-219` -- **Why weird:** The method `getExportEndpointMetrics` returns `ExportMetricsResponse` — the type name dropped the `Endpoint` qualifier present in the method name. A reader greping for `EndpointMetrics` won't find the response type. Same shape (`contents?: ReadableStream`) as `ExternalFunctionResponse` and `GetOpenApiResponse`; the *content* is the only thing that says "metrics". -- **Category:** 17 (inconsistent — method qualifier dropped from response type), 1 (vague — `ExportMetricsResponse` could be metrics for anything). -- **Suggested name:** Pair the method rename in #8 with a response rename: `getEndpointMetrics()` → `EndpointMetrics`. Or `exportEndpointMetrics()` → `ExportEndpointMetricsResponse`. -- **Rationale:** Symmetry between method and return type aids IDE autocomplete and grep-ability. - -### 26. `Get*` prefix on every read method — `src/v1/client.ts:216, 243, 268, 295, 323` +### 9. `Get*` prefix on every read method — `src/v1/client.ts:227, 257, 285, 315, 346` - **Why weird:** Every read method here is prefixed `get*`. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, it's typically on synchronous accessors. - **Category:** 14 (Go/Java-style names). - **Suggested name:** Verb-first for actions: `exportMetrics(req)`, `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or property-style if the request is trivial. @@ -213,30 +80,6 @@ ## Observation -### 27. Mixed naming convention for the same product across sibling packages -The Databricks "Serving Endpoints" product spans two packages in this SDK after the 2026-05-22 consolidation: -- `modelserving`: types use `InferenceEndpoint*` (control plane). -- `modelservingquery`: types use `Endpoint` (data plane — e.g., `QueryEndpointInput`, `QueryEndpointResponse`). - -The wire uniformly uses `serving-endpoints`. SDK consumers chaining both packages will see different names for one concept. -- **Category:** 17 (cross-package inconsistency). - -### 28. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:460-506` -Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1346-1387) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. +### 10. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:473-519` +Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1389-1430) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. - **Category:** 12 (duplicate concept). - -## Domain glossary -- `pt` — Provisioned Throughput (a billing/serving model where capacity is pre-allocated). Mixed: spelled out in method names and waiter class names, abbreviated in type names. -- `ai gateway` — A Databricks proxy layer that sits in front of model-serving endpoints to apply guardrails, rate limits, usage tracking, payload logging, and fallback. Rendered `AiGateway` throughout. -- `ai guardrails` — Input/output content filters applied via AI Gateway (`safety`, `pii`, `validTopics`, `invalidKeywords`). -- `pii` — Personally Identifiable Information. Rendered `Pii` throughout. -- `uc` — Unity Catalog. Referenced in JSDoc as "UC" and in field docs ("the credentials stored in UC Connection"). -- `arn` — Amazon Resource Name. Rendered `Arn` (suffix `instanceProfileArn`). -- `provider` values (`ai21labs`, `anthropic`, `amazon-bedrock`, `cohere`, `databricks-model-serving`, `google-cloud-vertex-ai`, `openai`, `palm`, `custom`) — kebab-case on the wire, `Config` camelCase in TS. - -## File coverage -- `src/v1/model.ts` (2557 lines): read fully. -- `src/v1/client.ts` (934 lines): read fully. -- `src/v1/utils.ts` (185 lines): read fully. -- `src/v1/index.ts` (93 lines): read fully. -- `src/v1/transport.ts`: present (not a naming source). diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index debd0b3a..b880e4a6 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -3,17 +3,11 @@ **Package:** `@databricks/sdk-modelservingquery` **Path:** `/home/parth.bansal/sdk-js/packages/modelservingquery/` **Version audited:** `v1` -**Files audited:** -- `src/v1/model.ts` -- `src/v1/client.ts` -- `src/v1/index.ts` -**Inferred domain:** Model-serving *inference path*. The single client method `query()` POSTs an inference request body to `/api/serving-endpoints/{name}/invocations`. Supports four payload shapes simultaneously: chat (LLM), completions (LLM), embeddings (LLM), and traditional MLflow models (dataframes / tensors). The package is a *sibling* of `servingendpoints` (which owns CRUD on the endpoint resource itself) — this package only owns the **query/invoke** verb. The package name and its types share vocabulary with the unrelated SQL packages `queries`, `queryexecution`, `queryhistory` — none of which have anything to do with model serving. +**Total weird names flagged:** 8 -**Total weird names flagged:** 16 (0 fixed, 16 still, 0 superseded) - -Rescanned on 2026-05-26 after regeneration #156. All 16 findings remain -unchanged in the regenerated output; no items have moved to `## Fixed`. +Rescanned on 2026-06-02 against the current generated output. Line numbers were +refreshed to the current source. --- @@ -21,100 +15,20 @@ unchanged in the regenerated output; no items have moved to `## Fixed`. | # | Severity | Location | Name | Category | |----|----------|-----------------------------------|--------------------------------------------------------------|----------------------------------------------| -| 1 | High | package + dir | `modelservingquery` / `@databricks/sdk-modelservingquery` | Duplicate concept; "query" overloaded SDK-wide | -| 2 | High | `model.ts` interface | `QueryEndpointInputRequest` / `QueryEndpointResponse` | Four unrelated payload shapes packed into one type; double-suffix `Input` + `Request` | -| 3 | High | `model.ts` field | `QueryEndpointInputRequest.input` / `inputs` / `instances` / `prompt` / `messages` / `dataframeRecords` / `dataframeSplit` | 7 mutually-exclusive "input" fields, no oneof | -| 4 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name; empty `Element` suffix | -| 5 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked into type name; empty `Element` suffix | -| 6 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | -| 7 | High | `model.ts` interface | `QueryEndpointInputRequest_ExtraParamsEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | -| 8 | High | `model.ts` interface | `QueryEndpointInputRequest_UsageContextEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | -| 9 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | -| 10 | Medium | `model.ts` field | `QueryEndpointResponse.choices` vs `.data` vs `.predictions` vs `.outputs` | 4 mutually-exclusive output fields, no oneof | -| 11 | Medium | `model.ts` field | `V1ResponseChoiceElement.text` / `.message` | Singular/plural mismatch with `messages` request field | -| 12 | Medium | `model.ts` enum | `ChatMessageRole` | Singular/plural — type is `ChatMessage`, but role values are `SYSTEM`/`USER`/`ASSISTANT` — none of which are *types of message* | -| 13 | Medium | `model.ts` field | `V1ResponseChoiceElement.logprobs` | Cryptic abbreviation; typed as `number` (the OpenAI spec returns an object) | -| 14 | Medium | `model.ts` field | `V1ResponseChoiceElement.finishReason` | Underspecified — typed `string`, but in practice an enum (`stop`, `length`, …) | -| 15 | Medium | `model.ts` field | `QueryEndpointInputRequest.extraParams` | Vague — what counts as "extra"? Also typed `Record` though OpenAI passes arbitrary JSON | -| 16 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 1 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name; empty `Element` suffix | +| 2 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked into type name; empty `Element` suffix | +| 3 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | +| 4 | High | `model.ts` interface | `QueryEndpointInputRequest_ExtraParamsEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | +| 5 | High | `model.ts` interface | `QueryEndpointInputRequest_UsageContextEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | +| 6 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | +| 7 | Medium | `model.ts` enum | `ChatMessageRole` | Redundant `Message` segment — values are roles of the speaker, not types of message | +| 8 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | --- ## High severity -### 1. `modelservingquery` / `@databricks/sdk-modelservingquery` — duplicate concept - -**Location:** `package.json`, directory `packages/modelservingquery/` - -**Categories:** 1 (vague), 12 (duplicate concept across packages), 7 (overly verbose) - -``` -packages/modelservingquery/ ← model inference path -packages/queries/ ← SQL alert queries -packages/queryexecution/ ← published-dashboard SQL execution -packages/queryhistory/ ← SQL query history -packages/servingendpoints/ ← CRUD for serving endpoints -``` - -The word **query** is reused across four unrelated SDK packages. In SQL-land (`queries`, `queryexecution`, `queryhistory`) a "query" is a SQL statement. In this package a "query" is *inference against an LLM/MLflow model* — i.e., a single HTTP POST to `/invocations`. The two meanings have nothing in common, but `import { Client } from '@databricks/sdk-modelservingquery/v1'` and `import { Client } from '@databricks/sdk-queryexecution/v1'` will appear side-by-side in user code. - -The Go SDK calls the corresponding service `serving.QueryEndpoint` (a verb-prefixed call inside the `serving` package, not a standalone package). The TS port hoists `QueryEndpoint` to a top-level package and concatenates the prefix `modelserving` + the verb `query`, producing a name that reads as a noun ("model serving query") but is actually verb-phrase. A clearer split would be either: - -- Fold into `servingendpoints` as a method (matches Go). -- Rename the package to `inference`, `invocations`, or `modelservinginvoke` — names that nobody else in the SDK uses. - -The package name is the most consequential naming choice in the audit; every type below inherits its ambiguity. - -### 2. `QueryEndpointInputRequest` / `QueryEndpointResponse` — four payload shapes packed into one type + double suffix - -**Location:** `src/v1/model.ts:76-139`, `153-183` - -**Categories:** 1 (vague), 8 (redundant suffixes), 14 (Go/Java-style) - -```ts -export interface QueryEndpointInputRequest { - name?: string | undefined; - prompt?: JsonValue | undefined; - input?: JsonValue | undefined; - messages?: ChatMessage[] | undefined; - // ... 14 more fields, mutually exclusive across 4 payload shapes -} -``` - -The single request type encodes **four** different request shapes: - -- **Chat:** `messages`, `temperature`, `stop`, `maxTokens`, `n`, `stream`, `extraParams`. -- **Completions:** `prompt`, same modifiers. -- **Embeddings:** `input`, `extraParams`. -- **Traditional ML:** `dataframeRecords` / `dataframeSplit` / `instances` / `inputs`. - -`QueryEndpointInputRequest` carries **two** request-shaped suffixes back to back: `Input` and `Request`. Both are noise. The name says "input" but the field `input` also exists, and `inputs` exists, and `instances` exists. The user constructing this type has to know which combination is valid — TS gives no help. The fresh `Request` suffix (added in regeneration) doesn't disambiguate the four shapes; it just makes the type name longer. - -Better: split into `ChatQueryRequest`, `CompletionsQueryRequest`, `EmbeddingsQueryRequest`, `TraditionalModelQueryRequest`, and have the client expose four methods (or a discriminated union). - -`QueryEndpointResponse` has the same problem in mirror image: `choices` (chat/completions), `data` (embeddings), `predictions` (traditional), `outputs` (feature serving). The Go SDK has the same union, so the smell is inherited from the wire protocol. - -### 3. Seven mutually-exclusive "input" fields with no discriminator - -**Location:** `src/v1/model.ts:79-134` - -**Categories:** 4 (singular/plural confusion), 15 (generic field name), 17 (inconsistent verbs/nouns) - -| Field | Used by | Type | -|-------------------|--------------|---------------------------| -| `prompt` | completions | `JsonValue` | -| `input` | embeddings | `JsonValue` | -| `messages` | chat | `ChatMessage[]` | -| `dataframeRecords`| traditional | `JsonValue[]` | -| `dataframeSplit` | traditional | `DataframeSplitInput` | -| `instances` | traditional | `JsonValue[]` | -| `inputs` | traditional | `JsonValue` | - -Note the singular/plural near-collision `input` (embeddings) vs `inputs` (tensor columnar) — the *plural* refers to a single object (columnar map), and the *singular* refers to potentially a list of strings. This is the textbook trap the audit checklist calls out as "Singular/plural mismatches." - -A user writing TS sees seven optional fields and has to read four JSDoc paragraphs to figure out which one to set. A discriminated union (`payload: { kind: 'chat'; messages: ... } | { kind: 'completions'; prompt: ... } | ...`) would make invalid combinations impossible. - -### 4. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix +### 1. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix **Location:** `src/v1/model.ts:185-196` @@ -126,7 +40,7 @@ export interface V1ResponseChoiceElement { ... } The `V1` prefix duplicates the directory it lives in (`src/v1/`). When a hypothetical v2 ships, the type will be either `V2ResponseChoiceElement` (now-impossible name collision with whatever the new shape is called) or renamed (breaking change). The `Element` suffix is also empty — the type is the choice itself, not an "element of a choice." `Choice` (no prefix, no suffix) would suffice — `QueryEndpointResponse.choices: Choice[]` reads cleanly. v2-style versioning should live exclusively in the import path, not in identifiers. -### 5. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix +### 2. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix **Location:** `src/v1/model.ts:58-65` @@ -140,9 +54,9 @@ export interface EmbeddingsV1ResponseEmbeddingElement { } ``` -Same `V1` leak as finding #4. The `Element` suffix is empty — the type is the single embedding, not an "element of an embedding." `Embedding` (with `vector` for the numeric field) would convey the same data cleanly. +Same `V1` leak as finding #1. The `Element` suffix is empty — the type is the single embedding, not an "element of an embedding." `Embedding` (no prefix, no suffix) would convey the same data cleanly. -### 6. `ExternalModelUsageElement` — misleading scope + meaningless suffix +### 3. `ExternalModelUsageElement` — misleading scope + meaningless suffix **Location:** `src/v1/model.ts:67-74` @@ -164,7 +78,7 @@ Two problems: 1. **"External" is misleading.** This type is the OpenAI-spec `usage` block, returned by Databricks Foundation Model and Databricks Provisioned Throughput endpoints — both of which are **internal** Databricks-managed models. JSDoc in `QueryEndpointResponse.usage` even says "external/foundation model", but Databricks Foundation Models are explicitly *first-party*. The "External" prefix mislabels its scope. 2. **"Element" is meaningless.** The type is the single usage block, not "an element of a list." `TokenUsage`, `Usage`, or `ModelUsage` would suffice. -### 7. `QueryEndpointInputRequest_ExtraParamsEntry` — proto map-entry leak +### 4. `QueryEndpointInputRequest_ExtraParamsEntry` — proto map-entry leak **Location:** `src/v1/model.ts:142-145` @@ -176,25 +90,25 @@ Two problems: **Rationale:** `_Entry` types are a proto-generator implementation detail (`map` lowers to a hidden nested message named `Entry`). Re-exporting them through a TS SDK forces language-specific generator scaffolding into the public API. The file's own ESLint disable comment is direct evidence that the name violates the project's naming convention — it is suppressed rather than fixed. -### 8. `QueryEndpointInputRequest_UsageContextEntry` — proto map-entry leak +### 5. `QueryEndpointInputRequest_UsageContextEntry` — proto map-entry leak **Location:** `src/v1/model.ts:148-151` -**Why:** Same proto-architectural leak as finding #7, applied to the `usage_context` map field. The interface is exported, never used in the schema (which uses `z.record(z.string(), z.string())`), and the file's own ESLint directive on line 147 labels it "Proto-style nested message name." Duplicate leak from the same generator template. +**Why:** Same proto-architectural leak as finding #4, applied to the `usage_context` map field. The interface is exported, never used in the schema (which uses `z.record(z.string(), z.string())`), and the file's own ESLint directive on line 147 labels it "Proto-style nested message name." Duplicate leak from the same generator template. **Category:** proto-architectural-leak (Protobuf generator artefact: `_Entry` map-entry message) **Suggested:** Delete the exported type entirely; `Record` is the natural TS surface. -**Rationale:** Mirror of #7. Two `_Entry` exports inflate the package surface area with proto-internal types that have no meaningful TS use case. They are a recurring pattern across packages with map fields, suitable for generator-level suppression. +**Rationale:** Mirror of #4. Two `_Entry` exports inflate the package surface area with proto-internal types that have no meaningful TS use case. They are a recurring pattern across packages with map fields, suitable for generator-level suppression. --- ## Medium severity -### 9. `query()` — verb-tense / reserved-word feel +### 6. `query()` — verb-tense / reserved-word feel -**Location:** `src/v1/client.ts:58-81` +**Location:** `src/v1/client.ts:59-86` **Categories:** 13 (verb-tense), 10 (reserved-word collision), 17 (inconsistent action verb) @@ -205,170 +119,41 @@ async query(req: QueryEndpointInputRequest, options?: CallOptions): Promise | undefined; -``` - -"Extra" relative to what? The 8 other fields already on `QueryEndpointInputRequest` are the "main" params; everything else falls through to here. `passthroughParams`, `modelParams`, or `externalParamsOverride` would be clearer. Also: typed `Record` — but OpenAI's "extra params" semantically include `top_p` (number), `presence_penalty` (number), and `tools` (array). The string-only typing forces stringification of values that should be passed through as JSON. - --- ## Low severity -### 16. `ChatMessageRole.ASSISTANT` — incomplete enum +### 8. `ChatMessageRole.ASSISTANT` — incomplete enum **Location:** `src/v1/model.ts:17-23` -**Category:** 6 (misleading names), 9 (singular/plural) +**Category:** 6 (misleading names) ```ts export enum ChatMessageRole { CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', - SYSTEM = 'SYSTEM', - USER = 'USER', - ASSISTANT = 'ASSISTANT', + SYSTEM = 'system', + USER = 'user', + ASSISTANT = 'assistant', } ``` -Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. Either the enum should be open (string union) or it should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. - ---- - -## Observations - -1. **The whole package is a thin wrapper around one POST.** `client.ts` has a single method (`query`) that does a single POST against `/api/serving-endpoints/{name}/invocations`. The entire surface area is the request and response *shape*, which is the union of four different OpenAI-like APIs plus traditional MLflow models. The naming difficulty is therefore concentrated in `model.ts`, which crams four request shapes and four response shapes into one type apiece. A discriminated union would solve roughly half the findings (3, 10). - -2. **Wire-format leakage is severe.** Wire-format names show up almost verbatim in TS: `n`, `stop`, `stream`, `logprobs`, `object`, `data`, `extra_params`, `served-model-name`, `EmbeddingsV1ResponseEmbeddingElement`. The Go SDK shares the smell, but Go's `query_endpoint` request becomes `QueryEndpointInputRequest` in TS, where TS users have no way to distinguish the four valid combinations. - -3. **Version-segment leak.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, and `EmbeddingsV1ResponseEmbeddingElementObject` all carry the literal string `V1` in the *type* name. The directory is already `src/v1/`. Other packages in the SDK (e.g., `alerts`) do not carry `V1`/`V2` segments in type names — those have explicit `v1` / `v2` directories instead, with the version expressed at the package-import path level. This package is inconsistent with that convention. - -4. **"Element" is the canonical empty suffix.** `V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`, `ExternalModelUsageElement` all carry the suffix `Element`. None of them are array elements in any structural sense — they are first-class types. The suffix is a Go convention for "value type inside a repeated field"; it adds noise in TS. - -5. **Package-level confusion.** Putting "query" in a model-serving package's name produces type names like `QueryEndpointInputRequest` (inference request to a serving endpoint, but reads as "an input to a Query endpoint" in a SQL context) and a client method called `query` (which is *not* a SQL query). The `queries` / `queryexecution` / `queryhistory` packages would all be on the same import autocomplete page as `modelservingquery` in any IDE. - -6. **The `query()` method has no `endpointName` parameter.** The endpoint name is buried in `req.name`, which is typed optional. If the caller forgets, the URL silently becomes `/api/serving-endpoints//invocations` (double slash). A signature like `query(endpointName: string, req: QueryEndpointInputRequest, options?: CallOptions)` would catch the missing path parameter at the type level. - -7. **No streaming support despite `stream: boolean`.** `QueryEndpointInputRequest.stream` is a passthrough to the wire format, but `client.query()` always reads the full response body via `readAll`. Setting `stream: true` will either produce a malformed response or a parse failure. The field name promises a capability the SDK doesn't deliver. - ---- - -## v1-only - -This package has only `v1`. There is no v2 to diff against. Several names visibly anticipate a v2 (`V1ResponseChoiceElement`, `EmbeddingsV1ResponseEmbeddingElement`), but the version is also baked into the directory and package export path. If/when v2 ships, those leaked version segments will have to be renamed *and* moved. - ---- - -## Domain glossary - -| Term | Meaning in this package | -|--------------------------------|--------------------------------------------------------------------------------------------| -| Serving endpoint | A deployed Databricks model serving resource (an "/endpoints/{name}/invocations" URL). | -| Query (verb) | A single inference call (POST). **Not** a SQL query. | -| Query endpoint | The "/invocations" REST resource; the only method in the package. | -| External model | Confusingly, this includes Databricks Foundation Models (which are first-party). Used to distinguish from user-deployed MLflow models. | -| Foundation model | A first-party (typically open-source, hosted by Databricks) LLM. | -| Choice | One generated response in a chat or completions reply (mirrors OpenAI). | -| Embedding | A vector of floats representing the input text (mirrors OpenAI). | -| Logprobs | Log probabilities of generated tokens. Mistyped as `number` in this package. | -| `n` (in `QueryEndpointInputRequest`) | "Number of candidates" (mirrors OpenAI's `n`). | -| Usage context | Free-form metadata recorded in the model-serving usage tracking table. | -| Extra params | Free-form parameters passed through to the underlying model API. | -| Served model | One model behind a serving endpoint (an endpoint can host several with traffic split). | -| Dataframe split / records | Two of `pandas.DataFrame.to_dict`'s orientations, used for traditional MLflow models. | -| Instances / inputs | Tensor-input shapes — `instances` is row-major, `inputs` is column-major. | - ---- - -## File coverage - -| File | Lines | Read in full | -|-------------------|-------|--------------| -| `src/v1/model.ts` | 342 | yes | -| `src/v1/client.ts`| 82 | yes | -| `src/v1/index.ts` | 21 | yes | +Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. The enum should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. diff --git a/.agent/naming-audit/networking.md b/.agent/naming-audit/networking.md index 0a6bd224..059771f9 100644 --- a/.agent/naming-audit/networking.md +++ b/.agent/naming-audit/networking.md @@ -8,28 +8,14 @@ ## Summary | Severity | Count | | --- | --- | -| High | 0 | | Medium | 4 | -| Low | 0 | -| Observation | 0 | - -## File coverage -- `src/v1/model.ts` — 4449 lines; interface, enum, and marshal/unmarshal schema definitions. -- `src/v1/client.ts` — 1675 lines; `Client` class with the public RPC methods. -- `src/v1/transport.ts` — 75 lines; HTTP transport wrapper. -- `src/v1/utils.ts` — 150 lines; helpers. -- `src/v1/index.ts` — 153 lines; barrel exports. - -## High severity - -_None._ ## Medium severity -### 1. `ListNetworkRequest` — `src/v1/model.ts:1442` +### 1. `ListNetworkRequest` — `src/v1/model.ts:1440` - **Why weird:** The noun is singular (`Network`) where the sibling list request types in the package pluralise (`ListNetworkPoliciesRequest` - at line 1428, `ListNetworkConnectivityConfigsRequest` at line 1414). + at line 1426, `ListNetworkConnectivityConfigsRequest` at line 1412). The proto-tier `Public` infix was dropped in the 2026-05-22 regeneration, leaving the residual singular/plural inconsistency. - **Category:** Singular/plural inconsistency. @@ -37,17 +23,17 @@ _None._ - **Rationale:** A list operation returns multiple items; pluralise the noun to align with the rest of the package's `List*Request` naming. -### 2. `ListNetworkResponse` — `src/v1/model.ts:1446` +### 2. `ListNetworkResponse` — `src/v1/model.ts:1444` - **Why weird:** Same singular/plural mismatch as #1. Sibling list - response types pluralise (`ListNetworkPoliciesResponse` at line 1435, - `ListNetworkConnectivityConfigsResponse` at line 1422). The proto-tier + response types pluralise (`ListNetworkPoliciesResponse` at line 1433, + `ListNetworkConnectivityConfigsResponse` at line 1420). The proto-tier `Public` infix was dropped in the 2026-05-22 regeneration, leaving the residual singular/plural inconsistency. - **Category:** Singular/plural inconsistency. - **Suggested name:** `ListNetworksResponse`. - **Rationale:** Same as #1. -### 3. `ListVpcEndpointRequest` — `src/v1/model.ts:1458` +### 3. `ListVpcEndpointRequest` — `src/v1/model.ts:1456` - **Why weird:** Same singular/plural mismatch as #1. The list request for VPC endpoints uses a singular noun. The proto-tier `Public` infix was dropped in the 2026-05-22 regeneration, leaving the residual @@ -57,7 +43,7 @@ _None._ - **Rationale:** Same as #1; pluralise the noun the way other list request types in the package do. -### 4. `ListVpcEndpointResponse` — `src/v1/model.ts:1462` +### 4. `ListVpcEndpointResponse` — `src/v1/model.ts:1460` - **Why weird:** Same singular/plural mismatch as #1. The list response for VPC endpoints uses a singular noun. The proto-tier `Public` infix was dropped in the 2026-05-22 regeneration, leaving the residual @@ -65,11 +51,3 @@ _None._ - **Category:** Singular/plural inconsistency. - **Suggested name:** `ListVpcEndpointsResponse`. - **Rationale:** Same as #1. - -## Low severity - -_None._ - -## Observations - -_None._ diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index e5c2b4e0..4c5aa11e 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -3,15 +3,14 @@ **Path:** `packages/notificationdestinations/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-level CRUD over "notification destinations" — named, persisted records that pair a `displayName` with one config out of five wire-format channels (Slack, Email, GenericWebhook, PagerDuty, MicrosoftTeams). The REST surface is `/api/2.0/notification-destinations`, with the usual `create` / `get` / `list` / `update` / `delete` plus a paged async iterator. Every channel-config carries the same `*Set: boolean` companion shape: secret fields are write-only on input and the server echoes only a "is it set?" mirror on output. There are zero typed timestamps, zero enum sub-types beyond `DestinationType`, and the only oneof is the discriminated `Config` union. -**Total weird names flagged:** 8 +**Total weird names flagged:** 5 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 1 | -| Low | 2 | +| High | 3 | +| Low | 1 | | Observation | 1 | ## Summary table @@ -19,13 +18,10 @@ | # | Severity | Location | Name | Category | |---|----------|----------|------|----------| | 1 | High | `model.ts:5-11` | `DestinationType` | 1 (vague) | -| 2 | High | `model.ts:8` | `DestinationType.WEBHOOK` (vs `GenericWebhookConfig`) | 6 (misleading), 12 (duplicate concept name mismatch) | -| 3 | High | `model.ts:13-21` | `Config` (type) and `Config.config` (field) | 1 (vague), 9 (self-referential) | -| 4 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | -| 5 | Medium | `client.ts:45` | `Client` (unprefixed class) | 1 (vague), 12 (duplicate across SDK) | -| 6 | Low | `model.ts:8` | `WEBHOOK` enum singular while wire-config implies "generic" | 9 (singular/plural / qualifier mismatch with `GenericWebhookConfig`) | -| 7 | Low | `client.ts:80`, `:105`, etc. | `req` / `resp` / `opts` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 8 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 2 | High | `model.ts:13-21` | `Config` (type) | 1 (vague) | +| 3 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | +| 4 | Low | `client.ts:74`, `:82`, etc. | `req` / `resp` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 5 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | ## High severity @@ -45,22 +41,7 @@ - **Suggested name:** `NotificationChannel` or, less invasive, `NotificationDestinationType`. - **Rationale:** Domain-anchored enum names protect users from cross-package collisions and read better in IDE autocomplete (`NotificationChannel.SLACK` vs `DestinationType.SLACK`). -### 2. `DestinationType.WEBHOOK` corresponds to `GenericWebhookConfig` — misleading enum vs config asymmetry — `src/v1/model.ts:8`, `:42-55`, `:17` -- **Code:** - ```ts - // enum value - WEBHOOK = 'WEBHOOK', - // config type - export interface GenericWebhookConfig { ... } - // discriminator - | {$case: 'genericWebhook'; genericWebhook: GenericWebhookConfig} - ``` -- **Why weird:** Of the five channels, four have an enum value that matches their config name in lowercase (`SLACK`/`SlackConfig`, `EMAIL`/`EmailConfig`, `PAGERDUTY`/`PagerdutyConfig`, `MICROSOFT_TEAMS`/`MicrosoftTeamsConfig`). Only the webhook case introduces an unexplained qualifier: the enum says `WEBHOOK`, the config type says `GenericWebhookConfig`. A user is left wondering whether "generic" means "the default kind of webhook" or whether there's a future non-generic webhook config coming. The `$case` discriminant uses `'genericWebhook'`, the wire uses `'generic_webhook'`, but the enum value drops the qualifier entirely. Either the enum should be `GENERIC_WEBHOOK` (matching the config name) or the config should be `WebhookConfig` (matching the enum). -- **Category:** 6 (misleading — name asymmetry across the same channel), 12 (the same conceptual channel has two different names in the same file). -- **Suggested name:** Pick one: rename the enum value to `GENERIC_WEBHOOK` (preferred, preserves the qualifier that distinguishes from MS-Teams' webhook URL), or rename `GenericWebhookConfig` → `WebhookConfig`. -- **Rationale:** The `MicrosoftTeamsConfig` and `GenericWebhookConfig` both have a `url` field that is "a webhook URL" (lines 44, 85), so the qualifier "generic" is genuinely meaningful — it distinguishes the channel-agnostic incoming-webhook target from the Teams-branded webhook. Keep the qualifier, but propagate it to the enum. - -### 3. `Config` (interface) and its `config` field — vague top-level name + self-referential field — `src/v1/model.ts:13-21` +### 2. `Config` (interface) — vague top-level type name — `src/v1/model.ts:13-21` - **Code:** ```ts export interface Config { @@ -73,12 +54,12 @@ | undefined; } ``` -- **Why weird:** The type name `Config` is one of the most generic identifiers in software. A package-root `Config` export means an app barrel re-exporting `@databricks/sdk-notificationdestinations/v1` collides instantly with any other `Config` (web framework configs, app configs, build configs, …). The user must alias it. Compounding the vagueness, the field inside `Config` is also named `config`, so you read `notificationDestination.config.config.email.addresses` — the same identifier appears twice along the path. -- **Category:** 1 (vague/generic top-level name), 9 (self-referential field name). +- **Why weird:** The type name `Config` is one of the most generic identifiers in software. A package-root `Config` export means an app barrel re-exporting `@databricks/sdk-notificationdestinations/v1` collides instantly with any other `Config` (web framework configs, app configs, build configs, …). The user must alias it. +- **Category:** 1 (vague/generic top-level name). - **Suggested name:** Rename the type to `NotificationDestinationConfig` (matches the package's domain prefix). -- **Rationale:** A domain-anchored type name eliminates the cross-package collision risk and the `config.config` repetition along the property path. +- **Rationale:** A domain-anchored type name eliminates the cross-package collision risk. -### 4. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:42-55` +### 3. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:42-55` - **Code:** ```ts export interface GenericWebhookConfig { @@ -93,55 +74,21 @@ ``` - **Why weird:** The qualifier "generic" tells the user nothing concrete. It means "this is the webhook config that is *not* the Microsoft Teams webhook config" — a knowledge that requires reading the whole file. A user looking at IDE autocomplete sees `GenericWebhookConfig` and `MicrosoftTeamsConfig` side-by-side and has to guess that MS-Teams is also a webhook channel that just has more fields. - **Category:** 1 (vague — "generic" carries no positive information). -- **Suggested name:** `WebhookConfig` (and rename the enum value to `GENERIC_WEBHOOK` per #2 if you want to preserve the disambiguation from the MS-Teams-webhook). Or be honest and call it `IncomingWebhookConfig` (the actual term-of-art used by Slack/Teams/Discord for this shape). +- **Suggested name:** `WebhookConfig`. Or be honest and call it `IncomingWebhookConfig` (the actual term-of-art used by Slack/Teams/Discord for this shape). - **Rationale:** "Generic" is a code smell whenever it appears in a public type name. It usually means "this is the default, but there might be variants" — and TypeScript already has `extends`, intersections, and unions for variants. If the shape is the default, drop the qualifier; if there are real variants, name them after what makes them different (`AuthenticatedWebhookConfig`, etc.). -## Medium severity - -### 5. `Client` — unprefixed class — `src/v1/client.ts:45` -- **Code:** `export class Client { ... }` -- **Why weird:** Every package in the SDK exports a class named `Client`. A user wiring up two packages (`notificationdestinations` + `alerts`, say) writes: - ```ts - import { Client as NotificationDestinationsClient } from '@databricks/sdk-notificationdestinations/v1'; - import { Client as AlertsClient } from '@databricks/sdk-alerts/v1'; - ``` - every time. The aliasing is universal — every audit raises this finding. -- **Category:** 1 (vague), 12 (cross-package duplication). -- **Suggested name:** `NotificationDestinationsClient`, or expose only the namespace import (`import * as notificationDestinations from '@databricks/sdk-notificationdestinations/v1'`). -- **Rationale:** Cross-SDK consistency, but every consumer pays the rename cost. Worth a generator-level fix. - ## Low severity -### 6. `WEBHOOK` enum value drops the qualifier "generic" — `src/v1/model.ts:8` -- See #2 (high). Listed separately as a low-severity naming-only issue: even if the enum name stays, the value `WEBHOOK` is **singular** while the config name `GenericWebhookConfig` is **qualifier-prefixed**. The qualifier is lost in transit between enum and config. -- **Category:** 9 (qualifier mismatch). -- **Suggested name:** `GENERIC_WEBHOOK = 'GENERIC_WEBHOOK'`. See #2 for the rationale. - -### 7. `req` / `resp` / `opts` / `httpReq` abbreviations — `src/v1/client.ts:72, 80, 84, 101, 105, 126, 130, 151, 164, 187, 192, 205, 213` +### 4. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:74, 82, 89, 106, 109, 134, 137, 162, 182, 201, 219, 234` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). -- **Suggested name:** `request`, `response`, `options`, `httpRequest`. Cost is trivial. +- **Suggested name:** `request`, `response`, `httpRequest`. Cost is trivial. ## Observations -### 8. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-99`, `:117-136` +### 5. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-103`, `:117-136` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). - **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. - -## Domain glossary -- `notification destination` — the persistent record being managed. Always paired with a `displayName` and one `Config`. -- `channel` — implicit term-of-art for the kind of destination (Slack, Email, etc.). Not used in any identifier here; encoded as `DestinationType`. -- `integration key` — PagerDuty term for the API key used to post events. -- `webhook` — incoming HTTPS endpoint that receives a POST when the notification fires. -- `oauth token` — Slack Bot user OAuth token. -- `app id` / `tenant id` / `channel url` / `auth secret` — Microsoft Teams app-registration fields. -- `pageToken` / `pageSize` / `nextPageToken` — standard SDK pagination triplet; not specific to this package. - -## File coverage -- `src/v1/model.ts` (447 lines): read fully. -- `src/v1/client.ts` (231 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (23 lines): read fully. diff --git a/.agent/naming-audit/oauth.md b/.agent/naming-audit/oauth.md deleted file mode 100644 index bf6eec07..00000000 --- a/.agent/naming-audit/oauth.md +++ /dev/null @@ -1,204 +0,0 @@ -# Naming Audit: oauth - -**Path:** `packages/oauth/src/v1/` -**Versions audited:** v1 -**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` -**Inferred domain:** Account-level CRUD over OAuth 2.0 application -registrations. After the 2026-05-22 regeneration the former -`oauthcustomappintegration` and `oauthpublishedapp` packages were -consolidated into a single `@databricks/sdk-oauth` package. The surface -covers three resources in one client: - -- *Custom* OAuth app integrations — caller-defined OAuth clients with - their own `redirectUrls`, `scopes`, and (optionally) a confidential - client secret (`CustomOAuthAppIntegration`, - `CustomOAuthAppIntegrationSecret`). -- *Published* OAuth app integrations — registrations of - Databricks-blessed third-party apps such as Power BI or Tableau - Desktop, identified by a slug `appId` (`PublishedOAuthAppIntegration`). -- *Published* OAuth apps — read-only catalog rows describing the - available third-party apps (`PublishedOAuthApp`). - -All three share the `TokenAccessPolicy` type for access/refresh-token -TTL and session-rotation configuration. The package is the Databricks -account-side complement to RFC 6749 client registration. -**Total weird names flagged:** 3 - -## Summary table - -| Severity | Count | -| --- | --- | -| High | 1 | -| Medium | 0 | -| Low | 2 | -| Observation | 0 | -| **Total** | **3** | - -The audit excludes the `OAuth*` brand-name spelling (RFC 6749 platform-name -exception), `*_UNSPECIFIED` proto sentinels, `*_Response` proto-nested -underscored identifiers, `marshal*` / `unmarshalSchema` Zod helper names, -empty wrapper types, `*Iter` pagination duplicates, redundant enum prefixes, -JS-built-in acronym casing (`URLSearchParams`, `JSON.parse`), and -wire-format strings preserved in JSDoc. The remaining findings cluster -around (1) the consolidated package surfacing intra-package -inconsistencies that used to be cross-package and (2) leftover -generator/template artefacts (stale `:method:` cross-refs, `` -template tokens, dead helper exports). - ---- - -## High severity (must fix) - -### 1. `confidential` vs `isConfidentialClient` — same flag spelled two ways in one file — `model.ts:12, 55, 164` -- **Why:** The RFC 6749 §2.1 "confidential client" boolean flag appears - three times in `model.ts`. On - `CreateCustomOAuthAppIntegrationRequest.confidential` (line 12) and - `CustomOAuthAppIntegration.confidential` (line 55) it is named - `confidential`. On `PublishedOAuthApp.isConfidentialClient` (line 164) - it is named `isConfidentialClient`. Both forms describe the same - RFC 6749 client-type discriminator. Before the package consolidation - this was a cross-package inconsistency; consolidation has now - promoted it to a single-file inconsistency. The `isConfidentialClient` - form is the clearer of the two (boolean predicate prefix, explicit - `Client` noun) and matches the codebase convention for boolean - state flags (`isEnabled`, `isPrimary`, …). -- **Category:** 12 (duplicate concept, inconsistent naming within one - file) -- **Suggested:** Pick `isConfidentialClient` for all three sites and - rename the two custom-integration usages. -- **Rationale:** The flag's value space and meaning are identical - across the three types; the identifier should be too. Consolidation - makes this a clean single-package fix that no longer requires - cross-package coordination. - ---- - -## Medium severity (worth pushing back on) - -_None._ - ---- - -## Low severity (nits) - -### 1. `accessTokenTtlInMinutes`, `refreshTokenTtlInMinutes`, `absoluteSessionLifetimeInMinutes` — unit suffix + vocabulary drift in one type — `model.ts:186, 192, 206` -- **Why:** Three TTL fields on `TokenAccessPolicy`. Two are named - `…TtlInMinutes`; the third uses `…LifetimeInMinutes`. The "InMinutes" - suffix is encoded into the field name three times in one type — a - doc-able invariant that lives in the identifier. The `Ttl` vs - `Lifetime` drift is the second issue: the JSDoc on line 201 calls - the third field "Absolute OAuth session TTL in minutes", so even - the doc inconsistently swaps "TTL" and "Lifetime" for the same - concept. -- **Category:** 7, 17 (overly verbose; inconsistent vocabulary — - TTL/Lifetime) -- **Suggested:** Either (a) adopt a `Temporal.Duration`-typed field - and drop the unit suffix entirely (`accessTokenTtl`, - `refreshTokenTtl`, `absoluteSessionLifetime`), or (b) standardise - on one suffix and one root: `accessTokenTtlMinutes`, - `refreshTokenTtlMinutes`, `sessionTtlMinutes`. The `Lifetime` / - `Ttl` mismatch should be resolved either way. -- **Rationale:** Encoding units into field names dates the API to - before `Temporal` shipped. The asymmetry between `Ttl` and - `Lifetime` is gratuitous — the JSDoc itself uses both - interchangeably for one concept. - -### 2. `Client` is a single generic export on a multi-resource package — `client.ts:69` -- **Why:** The package exports a single `Client` class whose - responsibilities now span three resources (custom integrations, - published integrations, published apps) and ten methods. A - consumer doing `import { Client } from '@databricks/sdk-oauth/v1'` - gets an unqualified symbol that must be aliased to coexist with any - other package's `Client`. The post-consolidation surface is wider - than it was pre-merge, which makes the generic name more of a - navigation hazard than before. -- **Category:** 1 (vague / generic) -- **Suggested:** `OAuthClient` (still inside `…/v1`). Project-wide - change — every generated package shares this pattern, so the fix - belongs at the generator template level, not per-package. -- **Rationale:** Defer to the project-wide naming-audit summary - recommendation. Flagged here for completeness, with the - caveat that this is shared across all 93 packages. - ---- - -## Observations (not flags) - -_None._ - ---- - -## Domain glossary - -- `accountId` — Databricks account UUID (top-level tenant), distinct - from a workspace ID. -- `appId` — Slug into the Databricks published-app catalog - (`power-bi`, `tableau-desktop`, …). Despite the `Id` suffix, this - is a human-readable name, not an opaque server-issued ID. -- `clientId` — RFC 6749 client identifier (the OAuth `client_id` - returned by the server). Opaque. -- `clientSecret` — RFC 6749 client secret. Returned only at creation - time for confidential clients. -- `confidential` / `isConfidentialClient` — RFC 6749 §2.1 client - type. `true` means the client has a secret and authenticates - itself; `false` means it is a public client and relies on PKCE. - Currently spelled two ways in this file (finding H1). -- `Custom` integration — Caller-defined OAuth client (caller-owned - redirect URLs, scopes, secret). -- `createdBy` — Numeric Databricks user ID of the registration - creator. -- `creatorUsername` — Username string of the registration creator. - Server-side joined when `includeCreatorUsername` is set on the - list request. -- `integrationId` — Opaque server-issued ID for an OAuth app - integration row. Distinct from `clientId`. -- `OAuth` — IETF OAuth 2.0 (RFC 6749). Brand-name capitalisation - (`OAuth`, not `Oauth`) is intentional per the project's RFC 6749 - platform-name exception. -- `Published` app — Databricks-blessed third-party application - (catalog row). -- `Published` integration — Account-level registration of a - published app (enables the app for the account). -- `scopes` — RFC 6749 scope strings the integration may request. - Documented set: `all-apis`, `sql`, `offline_access`, `openid`, - `profile`, `email`. -- `TokenAccessPolicy` — Per-integration token TTL and - refresh-rotation policy. -- `userAuthorizedScopes` — Subset of `scopes` requiring explicit - end-user consent. Despite the past-tense name, this is the - *configuration* of which scopes will require consent, not a - record of past consent. - ---- - -## Cross-package coupling notes - -- The 2026-05-22 regeneration consolidated the prior - `oauthcustomappintegration` and `oauthpublishedapp` packages into - this single `@databricks/sdk-oauth` package. Former - cross-package inconsistencies are now intra-package issues: - `confidential` vs `isConfidentialClient` (H1) and the shape of the - `scopes` documented value space across the published and custom - surfaces. The consolidation is reflected in the import list at - `index.ts:7-31`, which now re-exports 25 types from one model file. - ---- - -## File coverage - -| File | Lines read | Coverage | -| ---- | ---------- | -------- | -| `src/v1/index.ts` | 32 / 32 | 100% | -| `src/v1/transport.ts` | 75 / 75 | 100% | -| `src/v1/utils.ts` | 150 / 150 | 100% | -| `src/v1/model.ts` | 487 / 487 | 100% | -| `src/v1/client.ts` | 525 / 525 | 100% | - -All types, fields, and methods reviewed. Out-of-scope per the audit -constraints: `OAuth*` brand-name spelling (RFC 6749 platform-name -exception), `*_UNSPECIFIED` enum sentinels, `*_Response` proto-nested -underscored identifiers, `marshal*` / `unmarshalSchema` Zod helpers, -empty wrapper interfaces, `*Iter` pagination duplicates, redundant -enum prefixes, JS-built-in acronym casing (`URLSearchParams`, -`JSON.parse`, `TextDecoder`), and wire-format strings preserved -verbatim in JSDoc. diff --git a/.agent/naming-audit/onlinetables.md b/.agent/naming-audit/onlinetables.md deleted file mode 100644 index 8ad2d907..00000000 --- a/.agent/naming-audit/onlinetables.md +++ /dev/null @@ -1,124 +0,0 @@ -# Naming Audit: `onlinetables` (v1) - -**Path:** `/home/parth.bansal/sdk-js/packages/onlinetables/` -**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, -`src/v1/index.ts` -**Package import path:** `@databricks/sdk-onlinetables/v1` -**Cross-package references:** - -- `featurestore/v1` — also defines `DeleteOnlineTableRequest`, also references - `OnlineTable` semantics via `PublishSpec.onlineTableName` / - `PublishTableResponse`. -- `database/v1` — defines `SyncedTableState`, `SyncedTablePipelineProgress`, - `SyncedTableSchedulingPolicy`, `ProvisioningInfo_State`, `ProvisioningInfo`, - `SyncedTableContinuousUpdateStatus`, `SyncedTableFailedStatus`, - `SyncedTableTriggeredUpdateStatus`, `SyncedTableProvisioningStatus`, - `SyncedTableStatus` — all of which are *renames of identical concepts* with - a `SyncedTable` prefix. -- `postgres/v1` — same shape as `database`, also forks the type set. -- `catalogs/v1`, `connections/v1` — re-export `ProvisioningInfo_State` and - `ProvisioningInfo` from their own modules. - -**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). - ---- - -## Inventory - -### Enums (model.ts) - -1. `OnlineTableState` (model.ts:7) — 12 values: `ONLINE_TABLE_STATE_UNSPECIFIED`, - `PROVISIONING`, `PROVISIONING_PIPELINE_RESOURCES`, - `PROVISIONING_INITIAL_SNAPSHOT`, `ONLINE`, `ONLINE_CONTINUOUS_UPDATE`, - `ONLINE_TRIGGERED_UPDATE`, `ONLINE_NO_PENDING_UPDATE`, `OFFLINE`, - `OFFLINE_FAILED`, `ONLINE_PIPELINE_FAILED`, - `ONLINE_UPDATING_PIPELINE_RESOURCES`. -2. `ProvisioningInfo_State` (model.ts:57) — 7 values: `STATE_UNSPECIFIED`, - `PROVISIONING`, `ACTIVE`, `FAILED`, `DELETING`, `UPDATING`, `DEGRADED`. - -### Interfaces / Types (model.ts) - -1. `ContinuousUpdateStatus` (model.ts:71) — fields: - `lastProcessedCommitVersion`, `timestamp`, `initialPipelineSyncProgress`. -2. `CreateOnlineTableRequest` (model.ts:87) — fields: `table`. -3. `DeleteOnlineTableRequest` (model.ts:93) — fields: `name`. -4. `FailedStatus` (model.ts:102) — fields: `lastProcessedCommitVersion`, - `timestamp`. -5. `GetOnlineTableRequest` (model.ts:117) — fields: `name`. -6. `OnlineTable` (model.ts:123) — fields: `name`, `spec`, `status`, - `tableServingUrl`, `unityCatalogProvisioningState`. -7. `OnlineTableSpec` (model.ts:141) — fields: `schedulingPolicy` (discriminated - union with `runContinuously` / `runTriggered`), `sourceTableFullName`, - `primaryKeyColumns`, `timeseriesKey`, `performFullCopy`, `pipelineId`. -8. `OnlineTableSpec_ContinuousSchedulingPolicy` (model.ts:175) — empty - interface. -9. `OnlineTableSpec_TriggeredSchedulingPolicy` (model.ts:178) — empty - interface. -10. `OnlineTableStatus` (model.ts:181) — fields: `detailedState`, `message`, - `detailedStatus` (discriminated union). -11. `PipelineProgress` (model.ts:202) — fields: - `latestVersionCurrentlyProcessing`, `syncedRowCount`, `totalRowCount`, - `syncProgressCompletion`, `estimatedCompletionTimeSeconds`. -12. `ProvisioningInfo` (model.ts:220) — empty interface. -13. `ProvisioningStatus` (model.ts:226) — fields: - `initialPipelineSyncProgress`. -14. `TriggeredUpdateStatus` (model.ts:238) — fields: - `lastProcessedCommitVersion`, `timestamp`, `triggeredUpdateProgress`. - -### Client (client.ts) - -- Class `Client` (client.ts:41). -- Methods: `createOnlineTable`, `createOnlineTableWaiter`, `deleteOnlineTable`, - `getOnlineTable`. -- Class `CreateOnlineTableWaiter` (client.ts:152) — methods: `wait`, `done`. -- Internal `class StillRunningError extends Error` (client.ts:39). -- Private fields: `host`, `httpClient`, `logger`, `userAgent`. -- Module constant: `PACKAGE_SEGMENT` (client.ts:34). - -### Index (index.ts) - -- Re-exports `Client`, `CreateOnlineTableWaiter`, enum values, and 14 - interfaces. - ---- - -## Summary (counts) - -| Severity | Count | -| --------------------- | ----- | -| High | 0 | -| Medium | 0 | -| Low / SDK-wide note | 0 | -| Pass / acceptable | 0 | -| Fixed (post-regen) | 0 | -| **Total findings** | **0** | - -Rescanned against the 2026-05-26 regeneration (#156): no findings were -addressed by the regeneration — every previously open finding is still -present in the current source. - ---- - -## High severity (must fix) - -_None._ - ---- - -## Medium severity (worth pushing back on) - -_None._ - ---- - -## Low severity (nits) - -_None._ - ---- - -## Observations (not flags) - -_None._ - ---- diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index fe2e9dba..393c035d 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -6,171 +6,128 @@ **Files audited:** - `src/v2/model.ts` (~5,500 lines) — 26 enums, ~116 interfaces, marshal/unmarshal schemas. -- `src/v2/client.ts` (673 lines) — 12 RPC methods + 2 paginators + `StopWaiter`. -- `src/v2/utils.ts` (150 lines) — generic HTTP/marshal helpers (no domain names). -- `src/v2/index.ts` (154 lines) — re-exports. +- `src/v2/client.ts` (631 lines) — 12 RPC methods + 2 paginators + `StopWaiter`. +- `src/v2/utils.ts` (181 lines) — generic HTTP/marshal helpers (no domain names). +- `src/v2/index.ts` (155 lines) — re-exports. ## Summary | Severity | Count | Notes | | ------------ | ----- | ------------------------------------------------------------------------------------------- | -| High | 12 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | -| Medium | 13 | Vague names, acronym casing, generic IDs, misleading enum values. | -| Low | 8 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 3 | Patterns spanning the whole file (branding history, proto-architectural leakage). | -| **Total** | **36** | | - -Issues are catalogued below by severity, then by file/line. Throughout this document I use **"Update" (proper noun)** to refer to the DLT/Lakeflow concept of a pipeline run, since that overload is the most pervasive and most confusing naming choice in the package. +| High | 10 | Verb/noun overloading (`Update`), DLT-era rebrand leakage, identifier collisions. | +| Medium | 8 | Vague/misleading names, redundant suffix, generic types, misplaced field. | +| Low | 2 | Coupled fields modelled as loose flags. | +| **Total** | **20** | | --- ## High ### H1. `Update` is a verb in every other Databricks SDK but the noun "pipeline run" here — pervasive overloading -- **Locations:** `model.ts:168` (`UpdateCause`), `model.ts:186` (`UpdateState`), `model.ts:888` (`GetUpdateRequest`), `model.ts:896` (`GetUpdateRequest_Response`), `model.ts:1407` (`ListUpdatesRequest`), `model.ts:1419` (`ListUpdatesRequest_Response`), `model.ts:2400` (`StartUpdateRequest`), `model.ts:2445` (`StartUpdateRequest_Response`), `model.ts:2533` (`UpdateInfo`), `model.ts:2577` (`UpdateStateInfo`), `client.ts:386` (`getUpdate`), `client.ts:477` (`listUpdates`), `client.ts:520` (`start`), plus every `updateId` field. +- **Locations:** `model.ts:168` (`UpdateCause`), `model.ts:186` (`UpdateState`), `model.ts:885` (`GetUpdateRequest`), `model.ts:1401` (`ListUpdatesRequest`), `model.ts:2405` (`StartUpdateRequest`), `model.ts:2537` (`UpdateInfo`), `model.ts:2581` (`UpdateStateInfo`), `client.ts:362` (`getUpdate`), `client.ts:450` (`listUpdates`), `client.ts:490` (`start`). - **Category:** 1 (vague), 6 (misleading — rebrand history), 13 (verb/noun inconsistency), 17 (inconsistent action verbs). -- **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdateRequest` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdateRequest` → `GetRunRequest`, `ListUpdatesRequest` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateStateInfo` → `RunSummary`, `updateId` → `runId`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. +- **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdateRequest` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdateRequest` → `GetRunRequest`, `ListUpdatesRequest` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateStateInfo` → `RunSummary`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. - **Rationale:** "Update" is the standard verb for `PUT`/`PATCH` (and `EditPipelineRequest` already takes that slot — the client method is `edit()`, but the HTTP verb is `PUT`). Every JS/TS developer expects `update()` to mean "mutate". The DLT product feature historically named the unit-of-execution "Update" but Databricks itself renamed the concept to **"Pipeline run"** when the product became Lakeflow Declarative Pipelines. The SDK is on the wrong side of the rebrand. The same problem ripples through `start()` (the method that "starts an update"), `getUpdate()`, and `listUpdates()`. This is the single most confusing name in the package. -### H2. `client.edit()` returns `EditPipelineRequest_Response` instead of `UpdatePipelineRequest_Response` — verb collision avoidance is leaking through -- **Locations:** `client.ts:260` (`edit`), `model.ts:633` (`EditPipelineRequest`), `model.ts:730` (`EditPipelineRequest_Response`). -- **Category:** 13 (verb-tense inconsistency: `Edit` vs `Update` vs `Modify`), 6 (misleading: HTTP verb is `PUT`). -- **Suggestion:** Rename `EditPipelineRequest` → `UpdatePipelineRequest` and the client method `edit()` → `update()`. Then rename the "pipeline run" concept per H1 to free up the `Update` token. -- **Rationale:** The package uses `Edit` only because the `Update` noun was burned by DLT history. Once H1 is applied, `edit()` should follow the standard `create()`/`update()`/`delete()` REST pattern used by every other SDK (`jobs`, `clusters`, `instancepools`, etc., all use `update()`). - -### H3. `client.start()` is "start a pipeline update" — but it reads as "start a pipeline" -- **Location:** `client.ts:520`. +### H2. `client.start()` is "start a pipeline update" — but it reads as "start a pipeline" +- **Location:** `client.ts:490`. - **Category:** 6 (misleading), 17 (inconsistent action verbs). - **Suggestion:** Rename `start(req: StartUpdateRequest)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. - **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipelineRequest)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. -### H4. `PipelinesJobRunAs` references `Job` from a `Pipelines` package -- **Location:** `model.ts:2180`. +### H3. `PipelinesJobRunAs` references `Job` from a `Pipelines` package +- **Location:** `model.ts:2185`. - **Category:** 6 (misleading — `Job` is a separate Databricks product), 14 (Go-style). - **Suggestion:** Rename to `RunAs` or `PipelineRunAs`. Drop the `Job` token entirely — this type is not used by `@databricks/sdk-jobs`. - **Rationale:** `Job` belongs to the `jobs` API. A user reading `runAs: PipelinesJobRunAs` cannot tell whether the pipeline is associated with a job or just borrows the shape. The proto comment ("Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as.") confirms this is a pipeline-only concept. -### H5. `Pipeline` is never used as a type name — the central domain entity is missing -- **Locations:** N/A — the package has `PipelineSpec`, `PipelineStateInfo`, `GetPipelineRequest_Response`, `BaseJob`-style scattering, but no plain `Pipeline` type. +### H4. `Pipeline` is never used as a type name — the central domain entity is missing +- **Locations:** N/A — the package has `PipelineSpec`, `PipelineStateInfo`, `GetPipelineResponse`, `BaseJob`-style scattering, but no plain `Pipeline` type. - **Category:** 1 (vague/generic alternative missing), 6 (misleading). -- **Suggestion:** Add an exported `Pipeline` type that consolidates the runtime view (`GetPipelineRequest_Response` is the closest). Alternatively rename `GetPipelineRequest_Response` → `Pipeline`. Keep `PipelineSpec` as the write-form (the "settings" sub-object). -- **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipelineRequest_Response`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. - -### H6. `EditPipelineRequest` / `CreatePipelineRequest` / `ClonePipelineRequest` / `PipelineSpec` all duplicate 25 of the same fields -- **Locations:** `model.ts:336` (`ClonePipelineRequest`), `model.ts:479` (`CreatePipelineRequest`), `model.ts:633` (`EditPipelineRequest`), `model.ts:1816` (`PipelineSpec`). -- **Category:** 12 (duplicate concepts). -- **Suggestion:** Extract `PipelineSpec` as the shared base and have `CreatePipelineRequest`, `EditPipelineRequest`, `ClonePipelineRequest` use TS intersection: `type CreatePipelineRequest = PipelineSpec & {allowDuplicateNames?: boolean; dryRun?: boolean; ...}`. -- **Rationale:** Each of the four interfaces redeclares `id`, `name`, `storage`, `configuration`, `clusters`, `libraries`, `ingestionDefinition`, `gatewayDefinition`, `trigger`, `target`, `schema`, `filters`, `continuous`, `development`, `photon`, `edition`, `channel`, `catalog`, `notifications`, `serverless`, `deployment`, `restartWindow`, `budgetPolicyId`, `tags`, `eventLog`, `rootPath`, `environment`, `usagePolicyId`. Drift between the four is silent. +- **Suggestion:** Add an exported `Pipeline` type that consolidates the runtime view (`GetPipelineResponse` is the closest). Alternatively rename `GetPipelineResponse` → `Pipeline`. Keep `PipelineSpec` as the write-form (the "settings" sub-object). +- **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipelineResponse`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. -### H7. `client.events()` method name is too generic -- **Location:** `client.ts:292`. +### H5. `client.events()` method name is too generic +- **Location:** `client.ts:274`. - **Category:** 1 (vague), 17 (inconsistent action verbs — should be `listEvents`). - **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. - **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). -### H8. `client.list()` — too generic for the package's bare-`list` slot -- **Location:** `client.ts:414`. +### H6. `client.list()` — too generic for the package's bare-`list` slot +- **Location:** `client.ts:390`. - **Category:** 1 (vague), 17 (inconsistent verbs). - **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelinesRequest` and to disambiguate from `listUpdates`/`listEvents`. - **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelinesRequest`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. -### H9. `ScdType_ScdType` enum uses the cryptic acronym SCD +### H7. `ScdType_ScdType` enum uses the cryptic acronym SCD - **Locations:** `model.ts:268` (`ScdType_ScdType`), `index.ts:27`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). - **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). -### H10. `client.delete()` collides with JS `delete` keyword -- **Location:** `client.ts:220`. +### H8. `client.delete()` collides with JS `delete` keyword +- **Location:** `client.ts:208`. - **Category:** 10 (reserved-word collision). - **Suggestion:** Rename to `deletePipeline()`. Alternatively, `remove()`. - **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. -### H11. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity +### H9. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity - **Location:** `model.ts:56`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. -### H12. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural -- **Locations:** `model.ts:1464`, plus all `notifications?: Notifications[]` field declarations. +### H10. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural +- **Locations:** `model.ts:1457`, plus all `notifications?: Notifications[]` field declarations. - **Category:** 9 (singular/plural mismatch). -- **Suggestion:** Rename to `NotificationRule` (singular). The field becomes `notificationRules?: NotificationRule[]`. +- **Suggestion:** Rename the type to `NotificationRule` (singular). - **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. --- ## Medium -### M1. `TikTokAdsOptions_TikTokDataLevel` enum values split `TikTok` across an underscore (`TIK_TOK_*`) -- **Location:** `model.ts:291`. -- **Category:** 3 (acronym/word casing inconsistency). -- **Suggestion:** Use `TIKTOK_*` (single token) in enum values to match the brand spelling and the parent type name (`TikTok`). -- **Rationale:** The brand is "TikTok" (one word). Splitting to `TIK_TOK` in `SCREAMING_SNAKE_CASE` reads as two separate tokens and diverges from the parent type's CamelCase. - -### M2. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level +### M1. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level - **Location:** `model.ts:84-88`. - **Category:** 6 (misleading). -- **Suggestion:** Rename enum to `EventStability` or rename value `DEPRECATED` → `LEGACY`. +- **Suggestion:** Rename the enum to `EventStability`. - **Rationale:** `DEPRECATED` is widely used as a TS/JSDoc tag for "do not use." Reading `maturityLevel: DEPRECATED` mis-suggests the EVENT is deprecated, not the schema field. -### M3. `EventLogSpec` — `Spec` suffix on a small config object -- **Location:** `model.ts:752`. +### M2. `EventLogSpec` — `Spec` suffix on a small config object +- **Location:** `model.ts:750`. - **Category:** 8 (redundant suffix). - **Suggestion:** `EventLogConfig` or just `EventLog`. The `Spec` suffix is overused (`PipelineSpec`, `RewindSpec`, `RewindDatasetSpec`, `EventLogSpec`, `IngestionPipelineDefinition_SchemaSpec`, `_TableSpec`, `_ReportSpec`). - **Rationale:** TS doesn't need `Spec` as a discriminator; the type's role is clear from its field name. -### M4. `Filters` — pluralized name for a 2-field struct -- **Location:** `model.ts:830-835`. +### M3. `Filters` — pluralized name for a 2-field struct +- **Location:** `model.ts:828-833`. - **Category:** 9 (singular/plural mismatch), 1 (vague). - **Suggestion:** Rename to `PathFilter` (singular). The shape is `{include?: string[]; exclude?: string[]}`. -### M5. `PathPattern` field is `include: string` (singular, no array) but it represents a glob -- **Location:** `model.ts:1601-1604`. -- **Category:** 15 (generic field names), 6 (misleading). -- **Suggestion:** Rename type to `GlobPattern` and field to `pattern`. JSDoc says "The source code to include for pipelines" — `pattern` describes the *what*, `include` describes the *intent*. +### M4. `PathPattern` — generic type name for a single-glob struct +- **Location:** `model.ts:1594-1597`. +- **Category:** 6 (misleading). +- **Suggestion:** Rename the type to `GlobPattern`. The type wraps a single glob string, and `PathPattern` is easily confused with the broader path-filter shapes in the package. -### M6. `Origin` — too generic for "event source metadata" -- **Location:** `model.ts:1495`. +### M5. `Origin` — too generic for "event source metadata" +- **Location:** `model.ts:1488`. - **Category:** 1 (vague). - **Suggestion:** Rename to `EventOrigin` or `EventSource`. - **Rationale:** "Origin" is also a DOM type (`Window.origin`) and a CORS concept. Type contains many fields covering everything from cloud region to flow IDs. -### M7. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type -- **Location:** `model.ts:1021`. +### M6. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type +- **Location:** `model.ts:1017`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Move to `NetsuiteOptions` connector-specific type. - **Rationale:** A generic ingestion-definition type carrying a `netsuiteJarPath` field implies every other connector is incomplete. JSDoc literally says "Netsuite only configuration." Belongs in a per-connector options struct. -### M8. `IngestionSourceType.FOREIGN_CATALOG` — too generic, no source indicator -- **Location:** `model.ts:80`. -- **Category:** 1 (vague). -- **Suggestion:** `UC_FOREIGN_CATALOG` or document inline. -- **Rationale:** "Foreign Catalog" is a Unity Catalog concept; without context this looks like a country-of-origin enum value. - -### M9. `Origin.ucResourceId` mixes acronym casing -- **Location:** `model.ts:1528`. -- **Category:** 3 (acronym casing inconsistency). -- **Suggestion:** Either `ucResourceId` (current) or `UCResourceId` — the Google TS style guide says treat acronyms as words, so `ucResourceId` is correct. But sibling fields use the same lowercase pattern (`workspaceId`, `pipelineId`), so this one is internally consistent. Flagged because it could be `unityCatalogResourceId` for clarity. - -### M10. `eventType?: string` on `PipelineEvent` — string-typed enum -- **Location:** `model.ts:1765`. -- **Category:** 16 (field contradicts type domain). -- **Suggestion:** Define an `EventType` enum (or union of string literals) and type the field with it. Right now consumers have no IDE help. -- **Rationale:** JSDoc says "The event type. Should always correspond to the details." The Go SDK has the same field as string (porting fidelity), but TS could improve. - -### M11. `Sequencing` — singular noun for a 2-field record describing one event's position -- **Location:** `model.ts:2323`. +### M7. `Sequencing` — singular noun for a 2-field record describing one event's position +- **Location:** `model.ts:2328`. - **Category:** 1 (vague). - **Suggestion:** `EventSequence` or `EventPosition`. "Sequencing" is the action of putting in order, not the position itself. -### M12. `EditPipelineRequest.expectedLastModified: number` — wire is millis since epoch, but no JSDoc -- **Location:** `model.ts:643`. -- **Category:** 16 (field contradicts type domain), 19 (underspecified ID). -- **Suggestion:** Either type as `Date | number` or document "milliseconds since Unix epoch" in JSDoc. - -### M13. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` -- **Location:** `model.ts:593`. +### M8. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` +- **Location:** `model.ts:591`. - **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). - **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. - **Rationale:** Every other `*Id` type in the SDK is a string. Reading `dataPlaneId: DataPlaneId` then accessing `dataPlaneId.seqNo` is jarring. @@ -179,67 +136,12 @@ Issues are catalogued below by severity, then by file/line. Throughout this docu ## Low -### L1. `PipelinesS3StorageInfo.kmsKey` — uppercase acronym treatment is inconsistent -- **Location:** `model.ts:2238`. -- **Category:** 3. -- **Suggestion:** `kmsKey` is the correct casing per Google TS style. Just flagging for cross-check with other AWS fields in the file. - -### L2. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system -- **Locations:** `model.ts:2231`, `model.ts:2236`. +### L1. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system +- **Locations:** `model.ts:2236`, `model.ts:2241`. - **Category:** 16. - **Suggestion:** Use a discriminated union: `encryption?: {kind: 'none'} | {kind: 'sse-s3'} | {kind: 'sse-kms'; key: string}`. -### L3. `PipelineCluster.label` — string typed, expected values "default" / "maintenance" -- **Location:** `model.ts:1608`. -- **Category:** 16. -- **Suggestion:** Make this an enum `ClusterLabel.{Default, Maintenance}`. - -### L4. `AutoFullRefreshPolicy.minIntervalHours` JSDoc says "(Optional, Mutable)" — proto-style modifier tag in user-visible JSDoc -- **Location:** `model.ts:333`. -- **Category:** Generator artifact leakage. -- **Suggestion:** Express via TS optionality (`?:`) instead of repeating "Optional" in JSDoc. - -### L5. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link -- **Locations:** `model.ts:2299` (`cascade`), `model.ts:2301` (`resetCheckpoints`). +### L2. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link +- **Locations:** `model.ts:2304` (`cascade`), `model.ts:2306` (`resetCheckpoints`). - **Category:** 16. - **Suggestion:** Group into an `options` substruct or document interactions in JSDoc. - -### L6. `KafkaOptions.startingOffset: string` — typed string but documented as enum -- **Location:** `model.ts:1294`. -- **Category:** 16. -- **Suggestion:** Define `KafkaStartingOffset.{Latest, Earliest}` enum. - -### L7. `MetaMarketingOptions.level: string` — typed string but documented as enum -- **Location:** `model.ts:1436`. -- **Category:** 16. -- **Suggestion:** Define `MetaAggregationLevel.{Account, Ad, AdSet, Campaign}` enum. - -### L8. `MetaMarketingOptions.actionReportTime: string` — string enum -- **Location:** `model.ts:1442`. -- **Category:** 16. -- **Suggestion:** Define enum. - ---- - -## Observations - -### O1. `Notifications.alerts: string[]` is a hand-rolled enum of `on-update-success`, `on-update-failure`, `on-update-fatal-failure`, `on-flow-failure` -- **Location:** `model.ts:1476`. -- **Category:** 16. -- **Suggestion:** Define `AlertCondition` enum. Currently typed `string[]` with values listed only in JSDoc. - -### O2. `ConnectorOptions` JSDoc opens with "Wrapper message for source-specific options" — proto-architectural terminology leak -- **Location:** `model.ts:456`. -- **Why:** "Wrapper message" is a protobuf concept (the proto2/proto3 well-known wrapper types: `BoolValue`, `StringValue`, etc., plus the generic "wrapper message" pattern used to box discriminated unions). It is visible in user-facing JSDoc on a public interface. -- **Category:** Generator artifact leakage / proto-architectural leak. -- **Suggested:** Rewrite JSDoc as "Source-specific options for ingestion connectors. Exactly one option must be specified for the connector type." Drop "Wrapper message". -- **Rationale:** TypeScript developers do not know what a "wrapper message" is — the term reveals the proto IDL underneath. The shape is just a discriminated union over connector option types; describe it in TS terms. - -### O3. `Internal` proto-field tag leaks into JSDoc on two public fields -- **Locations:** `model.ts:959` (`IngestionGatewayPipelineDefinition.connectionParameters` — "Optional, Internal. Parameters required to establish an initial connection with the source."), `model.ts:1295` (`KafkaOptions.maxOffsetsPerTrigger` — "Internal option to control the maximum number of offsets to process per trigger."). -- **Why:** `Internal` is a proto-level annotation (`google.api.field_visibility = INTERNAL` or similar) indicating the field is not part of the public API surface. If these fields are truly internal, they should be stripped from the public SDK at generation time; if they are public, the "Internal" label should not appear in user-visible documentation. -- **Category:** Generator artifact leakage / proto-architectural leak. -- **Suggested:** Either remove these fields from the public SDK (preferred — they are marked internal) or drop the "Internal" qualifier from JSDoc and document the actual user-facing semantics. -- **Rationale:** Users reading JSDoc see `Internal option to control...` and reasonably wonder why an internal field is in the public SDK. This is a generator-template concern (same pattern likely shows up in other packages) — surface in the cross-package summary. - ---- diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md index 761608e1..79e08e4e 100644 --- a/.agent/naming-audit/policyfamilies.md +++ b/.agent/naming-audit/policyfamilies.md @@ -10,247 +10,66 @@ - `src/v2/utils.ts` - `src/v2/index.ts` -This audit catalogues every identifier (type, field, enum value, method, -constant) in the package and flags naming concerns against the 20-category -rubric. Issues are graded: - -- **High** — actively misleading, ambiguous, or violates a TS rule. -- **Medium** — friction; verbose, redundant, or stylistically off. -- **Low** — nit / consistency observation; safe to ignore. - --- -## 1. Inventory - -### 1.1 Enums (`model.ts`) - -| Name | Members | -| ----------- | ------- | -| (none) | — | - -The package defines no enums. - -### 1.2 Interfaces (`model.ts`) - -| Name | Purpose | -| -------------------------------------- | -------------------------------------------------- | -| `GetPolicyFamilyRequest` | Request body for the single-resource GET endpoint. | -| `ListPolicyFamiliesRequest` | Request body for the list endpoint. | -| `ListPolicyFamiliesRequest_Response` | Response from list (proto-style nested name). | -| `PolicyFamily` | The policy-family entity itself. | - -### 1.3 Fields (entity / request / response — combined catalog) - -| Type | Field | Type / Notes | -| -------------------------------------- | ----------------- | ----------------------------------------------------- | -| `GetPolicyFamilyRequest` | `policyFamilyId` | `string?` — path parameter (the resource identifier). | -| `GetPolicyFamilyRequest` | `version` | `number?` — version number to fetch (defaults to latest). | -| `ListPolicyFamiliesRequest` | `maxResults` | `number?` — page size. | -| `ListPolicyFamiliesRequest` | `pageToken` | `string?` — pagination cursor. | -| `ListPolicyFamiliesRequest_Response` | `policyFamilies` | `PolicyFamily[]?` — page of results. | -| `ListPolicyFamiliesRequest_Response` | `nextPageToken` | `string?` — pagination cursor for next page. | -| `PolicyFamily` | `policyFamilyId` | `string?` — unique identifier. | -| `PolicyFamily` | `name` | `string?` — display name. | -| `PolicyFamily` | `description` | `string?` — human-readable description. | -| `PolicyFamily` | `definition` | `string?` — Databricks Cluster Policy Definition Language JSON. | +## 1. Findings by Category -### 1.4 Methods (`client.ts`) - -| Method | Verb | Returns | -| ----------------------- | ---- | ------------------------------------ | -| `getPolicyFamily` | GET | `PolicyFamily` | -| `listPolicyFamilies` | GET | `ListPolicyFamiliesRequest_Response` | -| `listPolicyFamiliesIter`| GET | `AsyncGenerator` (paginated) | - -### 1.5 Other identifiers - -- `client.ts`: `PACKAGE_SEGMENT` constant; `Client` class with private - fields `host`, `httpClient`, `logger`, `userAgent`. -- `client.ts` local variables in methods: `url`, `params`, `query`, - `fullUrl`, `resp`, `call`, `callSignal`, `headers`, `httpReq`, `respBody`, - `pageReq`, `item`, `info`. -- `utils.ts`: `HttpCallOptions` interface; functions `executeCall`, - `readAll`, `executeHttpCall`, `buildHttpRequest`, `parseResponse`, - `marshalRequest`, `flattenQueryParams`. - ---- - -## 2. Findings by Category - -### 2.1 Vague / generic names — High & Medium - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| V-01 | `PolicyFamily.name` (`model.ts:33`) | Low | Generic but standard for entity types; meaning is preserved by the parent type. | -| V-02 | `PolicyFamily.description` (`model.ts:35`) | Low | Generic but standard across the SDK; acceptable. | - -### 2.2 Redundant enum prefixes — High - -| ID | Symbol | Severity | Issue | -| ---- | ------- | -------- | ----- | -| E-01 | (none) | — | The package defines no enums. | - -### 2.3 Acronym casing inconsistencies — High - -_None._ - -### 2.4 Underscores in TS identifiers — High - -_None._ - -### 2.5 Cryptic abbreviations — Medium - -_None._ - -### 2.6 Misleading names — High - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| M-01 | `Client` (`client.ts:36`) | Medium | Bare `Client` (with no domain qualifier) is ambiguous when imported into application code that uses multiple SDK packages — e.g. `import {Client as PolicyFamiliesClient} from '@databricks/sdk-policyfamilies/v2'` requires an alias to disambiguate from `Client` exported from `clusterpolicies`, `clusters`, etc. `PolicyFamiliesClient` would self-disambiguate. (Repo-wide pattern; flagged for consistency review at the codegen layer.) | - -### 2.7 Overly verbose / Redundant suffixes — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| O-01 | `policyFamilyId` (every occurrence) | Low | 14 chars but precise. Two `policyFamily*` fields would collapse to one once the type name (`PolicyFamily`) is in scope, but it remains unambiguous across the SDK and matches the upstream API field name. Accept. | -| O-02 | `ListPolicyFamiliesRequest_Response` (`model.ts:22`) | Medium | The `Request_Response` compound suffix is verbose — the proto-nested style yields a name where `Request` is carried into the response type even though the response is not a request. A flatter `ListPolicyFamiliesResponse` would self-describe. (Generator-level.) | - -### 2.8 Singular / plural mismatches — Low +### 1.1 Singular / plural mismatches — Low | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | P-01 | `getPolicyFamily()` (singular) | Low | Singular for a single-resource GET. Correct. | | P-02 | `listPolicyFamilies()` (plural method) | Low | Plural for a collection endpoint. Correct. | | P-03 | `ListPolicyFamiliesRequest` request type vs `listPolicyFamilies` method | Low | Both plural and matched. Correct. | -| P-04 | `ListPolicyFamiliesRequest_Response.policyFamilies` | Low | Plural field for an array of `PolicyFamily`. Correct. | -| P-05 | Package directory `policyfamilies` (lowercase) | Low | The npm package is `@databricks/sdk-policyfamilies` (lowercase, no separator). Compare with `clusterpolicies`, `clusterlibraries`, `instancepools`. Convention is consistent across this codebase — squashed lowercase. The directory and package name use plural ("families") which matches the dominant resource the package exposes. Acceptable but visually awkward (`policyfamilies` is hard to parse versus `policy-families`); a hyphenated path / scoped suffix would be more readable. (Pattern is repo-wide; flagged once.) | -| P-06 | `PolicyFamily` (entity, singular) vs `policyfamilies` (package directory, plural) | Low | Standard pattern — the package is plural, the entity it contains is singular. OK. | - -### 2.9 Reserved-word collisions — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ------- | -------- | ----- | -| R-01 | (none observed) | — | None of the field, type, or method names in this package collide with JS reserved or future-reserved words. | - -### 2.10 Empty / trivial wrapper types — Medium - -_None._ - -### 2.11 Duplicate concepts (vs `clusterpolicies`) — Medium +| P-04 | Package directory `policyfamilies` (lowercase) | Low | The npm package is `@databricks/sdk-policyfamilies` (lowercase, no separator). Compare with `clusterpolicies`, `clusterlibraries`, `instancepools`. Convention is consistent across this codebase — squashed lowercase. The directory and package name use plural ("families") which matches the dominant resource the package exposes. Acceptable but visually awkward (`policyfamilies` is hard to parse versus `policy-families`); a hyphenated path / scoped suffix would be more readable. (Pattern is repo-wide; flagged once.) | +| P-05 | `PolicyFamily` (entity, singular) vs `policyfamilies` (package directory, plural) | Low | Standard pattern — the package is plural, the entity it contains is singular. OK. | -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| D-01 | `PolicyFamily.policyFamilyId` (here) and `Policy.policyFamilyId` (in `clusterpolicies`) | Low | The field name is consistent across packages — good. No duplication concern. | - -### 2.12 Verb-tense inconsistency — Low +### 1.2 Verb-tense inconsistency — Low | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | T-01 | `getPolicyFamily`, `listPolicyFamilies` | Low | Both imperative present-tense — consistent. | -### 2.13 Go / Java-style names — Medium - -_None._ - -### 2.14 Generic field names losing meaning — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| F-01 | `name` (on `PolicyFamily`) | Low | Universal noun; meaning is preserved through type context. OK. | -| F-02 | `description` (on `PolicyFamily`) | Low | Same as F-01. | - -### 2.15 Field contradicting type domain — Low - -| ID | Symbol | Severity | Issue | -| ----- | ------- | -------- | ----- | -| FC-01 | (none observed) | — | All fields are domain-appropriate for the policy-family context. | - -### 2.16 Inconsistent action verbs — Medium +### 1.3 Inconsistent action verbs — Low | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | AV-01 | `getPolicyFamily()` (singular get) vs `listPolicyFamilies()` (plural list) | Low | Correct convention: singular `get` for one-resource, plural `list` for many. Consistent. | | AV-02 | The package exposes only **read** verbs — `get`, `list`. There are no `create` / `update` / `delete` methods (the API is read-only). The verb set is consistent with the API's read-only nature. | Low | OK. | -### 2.17 Long enum values — Medium - -| ID | Symbol | Severity | Issue | -| ---- | ------- | -------- | ----- | -| L-01 | (none) | — | The package defines no enums. | - -### 2.18 Underspecified IDs — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------- | -------- | ----- | -| I-01 | `policyFamilyId` | Low | Well-specified: scope = policy family. No collision with workspace / account / cluster / policy IDs in this package or in cross-package usage. Good. | -| I-02 | No bare `id` field anywhere. | — | The package consistently uses the scoped form `policyFamilyId`. Compliant with the "no bare `id`" guideline. | - -### 2.19 Type-suffix tautology — Medium +### 1.4 Type-suffix tautology — Low | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | | TS-01 | `PolicyFamily` — does the `Family` suffix double up with `Policy`? | Low | `PolicyFamily` is the domain term used in the Databricks docs (cf. https://docs.databricks.com/en/admin/clusters/policy-families.html). The "Family" here means *grouping/template*, not a `*Family` type-suffix tautology. OK. | | TS-02 | `GetPolicyFamilyRequest`, `ListPolicyFamiliesRequest` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | -### 2.20 Proto / architectural-leak naming — High - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| PL-01 | `ListPolicyFamiliesRequest_Response` (`model.ts:22`, `model.ts:41`, `client.ts:22`, `client.ts:26`, `client.ts:96`, `client.ts:107`, `client.ts:119`, `index.ts:10`) | High | The mid-position `Request_` token leaks proto's nested-message convention (`ListPolicyFamiliesRequest.Response` flattened with `_`). `Request` is meaningless mid-name on a response type and forces an `eslint-disable` for `@typescript-eslint/naming-convention`. **Suggested:** `ListPolicyFamiliesResponse`. **Rationale:** drops the proto-architectural leak; aligns with idiomatic TS `Response`. (Generator-level.) | -| PL-02 | `unmarshalListPolicyFamiliesRequest_ResponseSchema` (`model.ts:41`, `client.ts:26`, `client.ts:119`) | High | Same proto-nested leak carried into the schema constant. **Suggested:** `unmarshalListPolicyFamiliesResponseSchema`. **Rationale:** removes the `Request_` infix; matches PL-01. (Generator-level.) | - -### 2.21 Other observations +### 1.5 Other observations | ID | Symbol | Severity | Issue | | ----- | ---------------------------------------------------- | -------- | ----- | -| X-01 | `version` typed as `number` (`GetPolicyFamilyRequest.version`) | Low | The API contract uses an integer version. `number` is fine; flagged for completeness. No `bigint` is needed (versions won't exceed `Number.MAX_SAFE_INTEGER`). | -| X-02 | `pageToken` / `nextPageToken` (cross-pagination field naming) | Low | Standard Databricks SDK pagination shape. The request-side cursor is `pageToken`, the response-side cursor is `nextPageToken` — consistent with `clusterpolicies`, `instancepools`, etc. OK. | -| X-03 | `maxResults` (`ListPolicyFamiliesRequest.maxResults`) | Low | Standard pagination field name. OK. | -| X-04 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-05. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | -| X-05 | The class is exported simply as `Client` from `client.ts` and re-exported from `index.ts` | Medium | See M-01. Consumers must import `{Client as PolicyFamiliesClient}` to disambiguate. Codegen could emit `export class PolicyFamiliesClient` to relieve the alias burden. | +| X-01 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-04. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | --- -## 3. Summary +## 2. Summary -### 3.1 Findings by severity +### 2.1 Findings by severity | Severity | Count | | -------- | ----- | -| High | 2 | -| Medium | 3 | -| Low | 22 | -| **Total**| **27**| +| High | 0 | +| Medium | 0 | +| Low | 11 | +| **Total**| **11**| -### 3.2 Top themes +### 2.2 Top themes 1. **Read-only API ⇒ minimal naming surface.** With only two endpoints (`getPolicyFamily`, `listPolicyFamilies`) and one entity (`PolicyFamily`), - the package introduces almost no domain-specific naming. The majority of - issues are repo-wide patterns (the bare `Client` class name) rather than - per-package mistakes. - -2. **Proto-architectural leak in response type name.** - `ListPolicyFamiliesRequest_Response` (and the matching - `unmarshalListPolicyFamiliesRequest_ResponseSchema`) carry the - proto-nested `Request_Response` compound suffix into idiomatic TS. The - `Request` token mid-name is meaningless on a response type and forces an - `eslint-disable` for the naming-convention rule. + the package introduces almost no domain-specific naming. After the + regeneration flattened the response type, only Low-severity nits remain. -### 3.3 Suggested quick wins -(non-breaking renames are not possible — this section is advisory for the -codegen owners) +### 2.3 Suggested quick wins -- Rename `Client` → `PolicyFamiliesClient` for cross-package - disambiguation. (Repo-wide pattern; flag at codegen layer.) -- Flatten `ListPolicyFamiliesRequest_Response` → `ListPolicyFamiliesResponse` - to drop the proto-nested `Request_Response` compound suffix. - -### 3.4 Cross-package consistency notes - -- The bare `Client` class name is consistent with peers; a codegen-level - rename to `Client` would help all packages. -- `PolicyFamily.policyFamilyId` matches `Policy.policyFamilyId` in the - `clusterpolicies` package — cross-package field naming is consistent. - ---- +_None. All remaining findings are Low-severity observations._ diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index 2ea674cf..9eaf2aac 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -3,199 +3,44 @@ **Path:** `packages/postgres/src/v1/` **Versions audited:** v1 **Inferred domain:** Lakebase Autoscaling Postgres — manages Lakebase `Project`s, `Branch`es (Postgres-style branching for PITR / dev forks), `Endpoint`s (autoscaling read-write or read-only compute endpoints), `Database`s (logical Postgres databases inside a branch), `Role`s (Postgres roles bound to Databricks identities or plain Postgres roles), `SyncedTable`s (UC-managed Delta→Postgres sync pipelines), `Catalog`s (Unity Catalog mirrors of logical PG databases), short-lived `DatabaseCredential`s, and long-running `Operation`s with per-resource `*Operation` waiter-style classes. -**Total weird names flagged:** 28 +**Total weird names flagged:** 5 ## Summary | Severity | Count | | --- | --- | -| High | 8 | -| Medium | 15 | -| Low | 4 | -| Observation | 1 | - -## High severity - -### 1. `postgres` and `database` packages overlap heavily — `packages/postgres/` vs `packages/database/` -- **Why weird:** Many duplicate type names remain across the two packages: `DeltaTableSyncInfo` (`model.ts:1169`), `SyncedTablePosition` (`model.ts:2012`), `SyncedTablePipelineProgress` (`model.ts:1996`), `NewPipelineSpec` (`model.ts:1544`), `DatabaseCredential` (`model.ts:1079`), `GenerateDatabaseCredentialRequest` (`model.ts:1361`), `RequestedClaims` (`model.ts:1750`), `RequestedResource` (`model.ts:1755`), `ProvisioningInfo` (`model.ts:1748`), `ProvisioningInfo_State`/`SyncedTableState`/`RequestedClaims_PermissionSet`. Identical signatures but exported from two packages — a TS user importing both gets noisy alias-juggling. -- **Category:** 12 (duplicate concept across packages), 6 (misleading: same name, two definitions). -- **Suggested name:** Pick one as canonical; the other re-exports from the canonical or marks itself deprecated. Cross-reference each shared type with a JSDoc note like "Equivalent to `database/v1.DeltaTableSyncInfo`; see go/lakebase-v2 for the migration." -- **Rationale:** Same as `database` finding #2 — `postgres` is V2 and `database` is V1; nothing in the names says so. - -### 2. `ErrorCode` enum — 102 long, mostly-deprecated values — `src/v1/model.ts:17-515` -- **Why weird:** Huge enum (~100 entries) referenced exactly once via `DatabricksServiceExceptionWithDetailsProto.errorCode` (1091). Most entries are explicitly marked "NOTE: Deprecated and kept to maintain backwards compatibility for public APIs that use it, avoid using it in the new APIs" (e.g. `IO_ERROR`, `INVALID_STATE`, `UNPARSEABLE_HTTP_ERROR`, `QUOTA_EXCEEDED`, `MAX_BLOCK_SIZE_EXCEEDED`, `DRY_RUN_FAILED`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, all the `GIT_*`, `IPYNB_FILE_IN_REPO`, `INSECURE_PARTNER_RESPONSE`, `METASTORE_*_EXISTS`, `CATALOG_NOT_EMPTY`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, etc. — at least 40 entries). The enum re-exports the entire Databricks-platform error vocabulary into a Postgres-specific SDK package. -- **Category:** 7 (overly verbose), 11 (empty/trivial wrappers for deprecated values), 14 (Go/proto leak — all deprecated values exist only "for public APIs that use it"), 18 (long enum values). -- **Suggested name:** Move `ErrorCode` to a shared `core/apierror` package (already exists per CLAUDE.md), drop deprecated values from the public TS surface (or mark them `@deprecated` so TS tooling can warn). -- **Rationale:** Every consumer of this package gets a 100-entry deprecated-warning bundle. The fact that it's exported from `postgres/v1/index.ts` (line 30) means it's part of the public surface. - -### 3. Three "State" enums share value vocabulary but use two different qualifier patterns — `src/v1/model.ts:581, 600, 610` -- **Why weird:** Three state enums use two different qualifier patterns: - - Branch state and endpoint state qualify by the status struct (`BranchStatus`-scoped, `EndpointStatus`-scoped). - - Provisioning state lives under the unrelated `ProvisioningInfo` wrapper. - - All three enums share values like `INIT`, `ACTIVE`, etc. The TypeScript user can't tell which enum to use for which resource without reading the JSDoc. -- **Category:** 17 (inconsistent naming pattern). -- **Suggested name:** Standardise to `State`: `BranchState`, `EndpointState`, `ProvisioningState`. -- **Rationale:** Three state enums with two naming conventions across one package. - -### 4. `Role_Attributes.createdb` / `createrole` / `bypassrls` — Postgres-keyword-style lowercase fields — `src/v1/model.ts:1793-1795` -- **Why weird:** Three lowercase run-together field names. Doc comment (lines 1786-1789) acknowledges the choice ("The values follow Postgres keyword naming e.g. CREATEDB, BYPASSRLS, etc. which is why they don't include typical underscores between words"). That's a wire-format justification (Postgres keywords). The TypeScript identifier should still be camelCase. `createrole` is especially confusing — could read as `createRole` (verb) or `creator_ole`. -- **Category:** 3 (acronym/casing inconsistency), 14 (Postgres-keyword names not idiomatic in TS), 17 (inconsistent — every other field in the package is camelCase). -- **Suggested name:** `createDb`, `createRole`, `bypassRls` in the TS type; wire stays `createdb`/`createrole`/`bypassrls`. -- **Rationale:** Same finding as `database` audit #5 — both packages share this bug. - -### 5. `Role_AuthMethod.PG_PASSWORD_SCRAM_SHA_256` and `LAKEBASE_OAUTH_V1` enum values — `src/v1/model.ts:633, 638` -- **Why weird:** Implementation details (SCRAM-SHA-256 mechanism, OAuth `_V1`) leak into the public enum. The `_V1` suffix begs the question: what happens at V2? Should the SDK consumer have to migrate from `LAKEBASE_OAUTH_V1` to `LAKEBASE_OAUTH_V2` when the wire format changes? Worse, the `SCRAM_SHA_256` qualifier is a specific hash function — consumers picking an auth method shouldn't have to know about hash schemes. -- **Category:** 1 (vague at the wrong level — too specific), 6 (misleading: `LAKEBASE_OAUTH_V1` versioning leaks), 14 (Postgres/auth-spec internal naming), 18 (long enum values). -- **Suggested name:** `Password` (replacing `PG_PASSWORD_SCRAM_SHA_256`) and `OAuth` (replacing `LAKEBASE_OAUTH_V1`). Keep `NoLogin`. Push the wire-protocol-specific names into the marshal layer. -- **Rationale:** Public enums should describe the *concept* (password vs OAuth vs no-login), not the wire-protocol mechanism. - -### 6. `DatabricksServiceExceptionWithDetailsProto.details: Record[]` — array of opaque records — `src/v1/model.ts:1094` -- **Why weird:** `details` is `Record[]` — an array of unknown bags. Consumers get no type help. The type is reached via `Operation.result` (line 1588), making it the SDK's primary error surface. Every error consumer must cast. -- **Category:** 1 (vague), 15 (generic), 16 (type contradicts domain — details have structure, just unmodelled). -- **Suggested name:** Add typed discriminator: `details: ErrorDetail[]` with `ErrorDetail = ResourceInfo | RetryInfo | …` aligned to `google.rpc.Status`. -- **Rationale:** Errors are the most-handled values in any SDK; opaque `unknown` arrays force every caller to write defensive code. - -### 7. 21 separate `*Operation` classes — one per CRUD verb per resource — `src/v1/client.ts:1512-3345` -- **Why weird:** The package exports 21 boilerplate poller classes (each ~80 lines, near-identical): `CreateBranchOperation`, `CreateCatalogOperation`, `CreateDatabaseOperation`, `CreateEndpointOperation`, `CreateProjectOperation`, `CreateRoleOperation`, `CreateSyncedTableOperation`, `DeleteBranchOperation`, `DeleteCatalogOperation`, `DeleteDatabaseOperation`, `DeleteEndpointOperation`, `DeleteProjectOperation`, `DeleteRoleOperation`, `DeleteSyncedTableOperation`, `UndeleteBranchOperation`, `UndeleteProjectOperation`, `UpdateBranchOperation`, `UpdateDatabaseOperation`, `UpdateEndpointOperation`, `UpdateProjectOperation`, `UpdateRoleOperation`. Each has identical `name()` / `metadata()` / `wait()` / `done()` methods, differing only in return type (`Branch` vs `Catalog` vs `Database` etc.). All 21 are exported from `index.ts:5-26`. -- **Category:** 7 (overly verbose), 11 (trivial wrappers), 14 (Go-style poll-helper pattern), 17 (21-way redundancy). -- **Suggested name:** Single generic `Operation` class with `wait(): Promise` and `metadata(): Promise`. Drop all 21 named exports; expose factory methods on `Client` like `createBranchOperation()` that return `Operation`. -- **Rationale:** Comparable to `database/v1/client.ts`'s `CreateDatabaseInstanceWaiter` — but here the pattern is repeated 21 times. This bloats the bundle, the public surface, and the autocomplete list. - -### 8. `DatabricksServiceExceptionWithDetailsProto` — proto-architectural-leak type name — `src/v1/model.ts:1090`, `index.ts:64` -- **Why weird:** The type name carries two architectural leaks in one identifier: mid-position `Service` (the server-side concept the message originates from) and a trailing `Proto` suffix (the wire-format origin). Neither term is part of the domain. The same name surfaces on `Operation.result.error` (line 1592), so every SDK consumer who inspects an `Operation` error encounters "ServiceException...Proto" jargon. `WithDetails` is also a hand-rolled qualifier that mirrors how proto messages get suffixed when extended; an idiomatic TS API would just call this `DatabricksError` and treat the detail array as part of the error itself. -- **Category:** 14 (proto-architectural-leak — both `Service` mid and `Proto` suffix), 7 (overly verbose), 5 (5 stacked qualifiers — `Databricks` + `Service` + `Exception` + `WithDetails` + `Proto`). -- **Suggested name:** `DatabricksApiError` (or `DatabricksError`, matching `@databricks/sdk-databricks/apierror` conventions in CLAUDE.md). Drop `Service`, `Proto`, and the `WithDetails` distinguisher; the type already carries `details` as a first-class field. -- **Rationale:** The user explicitly flags `Service` mid-position and `Proto` suffix as architectural leaks; both appear in this one type name. The type is also a public, error-carrying surface, so the leak is highly visible. +| Medium | 3 | +| Low | 2 | ## Medium severity -### 9. `Branch` / `Catalog` / `Database` / `Endpoint` / `Project` / `Role` / `SyncedTable` — 7 generic top-level resource names — `src/v1/model.ts` (multiple) -- **Why weird:** Most of these names are single-word generic English (`Branch`, `Catalog`, `Database`, `Endpoint`, `Project`, `Role`). Multiple are *already-taken* concepts in Databricks-land: - - `Catalog` collides with Unity Catalog `Catalog` (in `catalogs` package) - - `Database` collides with the `database` package's `DatabaseInstance` / `DatabaseCatalog` - - `Endpoint` collides with `endpoints` package (Model Serving endpoints) and `vector-search endpoints` - - `Project` is a generic word — Lakebase Projects are not the same as Bundle projects or Genie projects. - - `Role` collides with workspace IAM roles and instance-profile roles. -- **Category:** 1 (vague/generic), 12 (duplicate concept across packages). -- **Suggested name:** Namespace-qualify (e.g. `LakebaseBranch`, `LakebaseCatalog`, `LakebaseEndpoint`, `LakebaseProject`, `LakebaseRole`) or rely on TS module import (`import * as lakebase from '@databricks/sdk-postgres/v1'; lakebase.Branch`). -- **Rationale:** With 100+ packages in the workspace, single-word resource names guarantee collisions. - -### 10. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:736-762` +### 1. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:744-770` - **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. - **Category:** 16 (type allows `false` but spec rejects it). - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 11. `Database` (SDK resource) vs `postgresDatabase` field (Postgres-side identifier) — same thing, two names — `src/v1/model.ts:1013, 1054` -- **Why weird:** Class `Database` represents the SDK resource; field `postgresDatabase` is the underlying PG name. So `Database` is an SDK noun and `postgresDatabase` is the actual PG-server-side identifier. The field name is what the Postgres-savvy reader expects; the type name is the SDK abstraction. Reading `db.spec.postgresDatabase` requires you to track two abstraction layers. -- **Category:** 1 (vague — `Database` could be either layer), 6 (misleading — both names describe the same physical thing). -- **Suggested name:** Rename either the type (to `DatabaseResource` or `LakebaseDatabase`) or the field (to `pgName`). -- **Rationale:** Disambiguate the SDK resource from the Postgres server-side concept. - -### 12. `Database` and `databaseId` query parameter for `createDatabase` — `src/v1/client.ts:245-289`, `model.ts:939` -- **Why weird:** Operation is "Create a Database" — but `CreateDatabaseRequest` has `parent`, `databaseId`, and `database`. The body is `database`; the query param is `databaseId`. The path is `/postgres/${req.parent}/databases`. Three places carry the name. JSDoc on `databaseId` says "If database_id is not specified in the request, it is generated automatically." But the JSDoc on `database` (the body) says nothing about how it relates to `databaseId`. -- **Category:** 17 (inconsistency — three identifier slots), 6 (misleading — caller doesn't know which to use). -- **Suggested name:** Move identifier into `database.name`; flatten the request to `{database, parent, replaceExisting}`. -- **Rationale:** Three identifier slots is too many. - -### 13. `EndpointSpec.autoscalingLimitMinCu` / `autoscalingLimitMaxCu` — `Cu` suffix is opaque — `src/v1/model.ts:1274, 1279` -- **Why weird:** `Cu` stands for "Compute Unit" (referenced in JSDoc on `EndpointSpec`). Field name doesn't expand the acronym. `MinCu` / `MaxCu` reads as `min cu` / `max cu` — `cu` could be currency unit, control unit, or anything. -- **Category:** 5 (cryptic abbreviation), 1 (vague suffix). -- **Suggested name:** `minComputeUnits` / `maxComputeUnits`, or `autoscalingMinComputeUnits` / `autoscalingMaxComputeUnits`. -- **Rationale:** "CU" is Lakebase-internal slang. - -### 14. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1293-1312` -- **Why weird:** Same pattern as #10 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. -- **Category:** 16 (type allows `false` but spec rejects), 27 (echo of #10). +### 2. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1268-1287` +- **Why weird:** Same pattern as #1 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. +- **Category:** 16 (type allows `false` but spec rejects), echo of #1. - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. -- **Rationale:** Same as #10. +- **Rationale:** Same as #1. -### 15. `GenerateDatabaseCredentialRequest.expiration` discriminated union — _removed in regeneration_; only the simpler `claims` + `endpoint` shape remains — see #23 -_Reserved._ - -### 16. `Operation.metadata: Record` — opaque metadata field — `src/v1/model.ts:1575` -- **Why weird:** Plain `Record`. The 21 `*Operation` classes each parse this metadata into a specific `*OperationMetadata` type at runtime (`client.ts:1524-1533` etc.). But the public `Operation` type doesn't carry the metadata type as a generic parameter, so a consumer reading `op.metadata` directly has no help. -- **Category:** 15 (generic), 16 (loose typing). -- **Suggested name:** `Operation` with `metadata?: T` (generic); each `*Operation` class returns `Operation` etc. -- **Rationale:** Same root cause as #6 — opaque records on the public surface. - -### 17. `Operation.result` discriminated union with `error` / `response` — `src/v1/model.ts:1588-1599` -- **Why weird:** Variant `response` carries `Record` (line 1597). Variant `error` carries the typed `DatabricksServiceExceptionWithDetailsProto`. Asymmetric: error is typed, response isn't. (The `*Operation.wait()` methods cast via Zod, but the public type stays opaque.) -- **Category:** 16 (asymmetric typing), 15 (generic on success arm). -- **Suggested name:** Same as #16 — generic `Operation` with both arms typed. -- **Rationale:** Same as #6, #16. - -### 18. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1624` +### 3. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1590` - **Why weird:** `Project` carries an `initialEndpointSpec` field that is a create-time-only input but exposed on the response type too — a read-flow consumer sees a field that is typically empty after project creation. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). - **Suggested name:** Hoist the `initialEndpointSpec` onto `CreateProjectRequest` only (where it belongs); leave `Project` to spec/status. - **Rationale:** Same as `database` audit #12 — input/output shape confusion. -### 19. `ProjectCustomTag` vs the `database` package's `CustomTag` — `src/v1/model.ts:1637`, `database:206` -- **Why weird:** `ProjectCustomTag` and `CustomTag` (in `database`) are textually identical (`{key, value}`). The `Project` prefix is package-scope tautology. Catalogs SDK and others use `CustomTag` too. -- **Category:** 12 (duplicate concept across packages), 20 (type-prefix tautology — `ProjectCustomTag` on `ProjectSpec.customTags`). -- **Suggested name:** `CustomTag` (drop the `Project` prefix). Or share a single `CustomTag` across SDK packages. -- **Rationale:** 13 duplicated `{key, value}` shapes in the workspace would be a useful audit. - -### 20. `ProjectSpec.pgVersion: number` vs `ProjectStatus.pgVersion: number` — Postgres version as integer — `src/v1/model.ts:1687, 1716` -- **Why weird:** Doc says "The major Postgres version number. The set of supported versions may vary; consult the API documentation for currently accepted values." Type is `number` (integer). Better to be an enum (`Pg16 | Pg17`) or `'16' | '17'` to encode "supported values". Also note `pgVersion: string` on `database/v1.DatabaseInstance` (the V1 package uses string) — inconsistent across the two packages. -- **Category:** 16 (type contradicts domain — open `number`), 17 (inconsistent with `database.DatabaseInstance.pgVersion` which is `string`). -- **Suggested name:** `pgMajorVersion: 16 | 17` or an enum. -- **Rationale:** Aligns documented constraints with the type system. - -### 21. `ProjectSpec.historyRetentionDuration` vs `ProjectStatus.historyRetentionDuration` — copy of input on output — `src/v1/model.ts:1689, 1718` -- **Why weird:** Same field appears on `ProjectSpec` (input) and `ProjectStatus` (output, doc'd as "effective"). The output doesn't add an "effective" prefix as `database/v1` does, but the JSDoc on `ProjectStatus` does say "The effective number of seconds…". Inconsistency: `database` uses `effective_` prefix on output, `postgres` (this package) drops it. Could be progress, could be a regression — flag for clarity. -- **Category:** 17 (inconsistent with sister package). -- **Suggested name:** Pick one convention across the two packages. -- **Rationale:** Mixed conventions encourage bugs when bridging between SDKs. - -### 22. `timeseriesKey` field casing on the synced-table spec — `src/v1/model.ts:1936` -- **Why weird:** Same as `database` audit #36: `timeseries` is one run-together word but English has `timeSeries` (two words). Wire is `timeseries_key`. -- **Category:** 3 (acronym/casing inconsistency), 17 (inconsistent with neighbours). -- **Suggested name:** `timeSeriesKey`. -- **Rationale:** Same as `database` audit #36. - -### 23. Synced-table spec fields `createDatabaseObjectsIfMissing` — same fields, same issues as `database` package — `src/v1/model.ts:1951` -- **Why weird:** Identical to `database` audit findings on synced-table-spec naming. Won't re-state at length; flag that the duplication exists across both packages with identical naming. Other related fields (`acceleratedSync`, `extraIndexDefinitions`, `extraColumnDefinitions`, `typeOverrides`) were removed during regeneration; only the `createDatabaseObjectsIfMissing` "If Missing" pattern remains here, matching `database` package's similar wording. -- **Category:** 12 (duplicate concept), 17 (inherited inconsistencies). -- **Suggested name:** Same suggestions as `database` audit. -- **Rationale:** Two SDKs, same problems. - -### 24. `UpdateBranchRequest.updateMask: FieldMask` — Google API protocol leak — `src/v1/model.ts:2057` -- **Why weird:** Generic `FieldMask` is a Google-API-protocol-buffers thing for partial updates. The naming is correct for an AIP-conformant API; less correct for an idiomatic TS SDK. Same on `UpdateDatabaseRequest`, `UpdateEndpointRequest`, `UpdateProjectRequest`, `UpdateRoleRequest`. -- **Category:** 14 (Google AIP/proto leak), 1 (vague — `updateMask` is jargon). -- **Suggested name:** `fields?: (keyof Branch)[]` or `patch?: Partial` (and derive the field-mask). The `FieldMask` import already comes from `@databricks/sdk-core/wkt` (well-known types) — the SDK already lifts the type. -- **Rationale:** AIP `FieldMask` is an industry pattern, but it should not be the only update affordance. - ## Low severity -### 25. `CreateBranchRequest.replaceExisting` (Create) — no symmetrical `allowMissing` on Delete (Delete uses `purge`) — `src/v1/model.ts:911, 1104, 1142` -- **Why weird:** Create uses `replaceExisting: boolean` (proactive). Delete now uses `purge: boolean` only (`allowMissing` field removed in regeneration). Mismatched conventions for "if it does/doesn't exist" remain. -- **Category:** 17 (inconsistent action verbs across CRUD). -- **Suggested name:** Pick one: `ifExists: 'update' | 'error'` and `ifMissing: 'ignore' | 'error'`, or just both `upsert` and `ignoreIfMissing`. -- **Rationale:** Inconsistent options across CRUD operations is a small papercut. - -### 26. `DeleteBranchRequest.purge` — boolean for hard delete — `src/v1/model.ts:1104` -- **Why weird:** `purge: boolean` distinguishes hard vs soft delete. Doc: "If true, permanently delete the branch; if false, soft delete." Same `purge` field on `DeleteProjectRequest` (line 1142). -- **Category:** 16 (boolean modeling a future 3-state field), 6 (misleading — purge implies cleanup, not the *only* delete mode). -- **Suggested name:** `deleteMode: 'hard' | 'soft'` or `permanent: boolean`. -- **Rationale:** Boolean toggle for a future-3-state field. - -### 27. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1363` +### 4. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1329` - **Why weird:** Same as `database` audit #54 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Same as `database` audit #54 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. - **Rationale:** Same as `database` audit #54. -### 28. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1581` -- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1552`). +### 5. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1547` +- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1660`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. - **Rationale:** Tri-state booleans always confuse callers. - -## Observation - -### 29. `Operation` is a separate type, not a generic — `src/v1/model.ts:1563` -- **Why weird:** All 21 mutation methods return `Promise`. The `Operation` type is monomorphic — no generic parameter for result/metadata. Consumer either uses the per-resource `*Operation` waiter classes (#7) or reads `Operation.result.response` (untyped `Record`). -- **Category:** Observation (architecture, not naming per se). -- **Suggested name:** `Operation` generic. -- **Rationale:** Connects #6, #7, #16, #17. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index 8cfbe3aa..e8517018 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,32 +3,24 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 20 (last rescanned 2026-05-26) +**Total weird names flagged:** 12 (last rescanned 2026-06-01) ## Summary table | # | Severity | Location | Name | Category | |---|----------|----------|------|----------| | 1 | High | `model.ts` interface | `Query` | Vague/generic — top-level name for what is really a "workspace SQL query" | -| 2 | High | `model.ts` interfaces | `CreateQueryRequestQuery`, `UpdateQueryRequestQuery`, `ListQueryObjectsResponseQuery` | Go/Java-style nested-message names | -| 3 | High | `model.ts` interface | `ListQueryObjectsResponseQuery` | Cryptic/Go-style: leaking proto inner-message + `Objects` filler word | -| 4 | High | package vs siblings | `queries` package vs `queryexecution`, `queryhistory`, `modelservingquery` | Duplicate concept across 4 packages, no shared prefix | -| 5 | High | `model.ts` enum value | `LifecycleState.TRASHED` vs method `trashQuery` | Inconsistent verb — most of the SDK uses `delete`; only the SQL surface uses `trash` | -| 6 | High | `model.ts` enum names | `LifecycleState`, `RunAsMode`, `DatePrecision` | Missing domain prefix (no `Query*`) — collide with identical enums in `alerts` package | -| 7 | High | `model.ts` field | `Query.parameters` of type `QueryParameter[]` | Inconsistent action verb: `QueryParameter` re-uses `Query` prefix while sibling types (`TextValue`, `NumericValue`, `EnumValue`) don't | -| 8 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | -| 9 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | -| 10 | High | `model.ts` interface | `Empty` | Proto architectural leak — `google.protobuf.Empty` surfaced as a TS export | -| 11 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | -| 12 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | -| 13 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | -| 14 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 15 | Medium | `model.ts` enum value | `LifecycleState.TRASHED` | Verb-tense inconsistency vs imperative method `trashQuery` | -| 16 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | -| 17 | Medium | `model.ts` enum values | `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, `LAST_30_DAYS`, etc. | Long enum values — numeric suffix per-bucket forms an open-ended discrete enum | -| 18 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | -| 19 | Medium | `model.ts` field | `DateRangeValue.startDayOfWeek` | Underspecified type (int 0–6? string? Mon-first or Sun-first?) | -| 20 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | +| 2 | High | `model.ts` interface | `ListQueryObjectsResponseQuery` | Cryptic/Go-style: leaking proto inner-message + `Objects` filler word | +| 3 | High | `client.ts` method | `trashQuery` | Inconsistent verb — most of the SDK uses `delete`; only the SQL surface uses `trash` | +| 4 | High | `model.ts` interface | `QueryBackedValue` | Misleading — name says "backed by a query" but it's a dropdown parameter source | +| 5 | High | `model.ts` interface | `EnumValue` | Vague/generic top-level name — generic word `enum` reused as identifier | +| 6 | Medium | `client.ts` method | `trashQuery` | Inconsistent action verb (HTTP `DELETE`, docs say "permanently deleted after 30 days", but method named `trash`) | +| 7 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | +| 8 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | +| 9 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | +| 10 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 11 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | +| 12 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | ## High severity @@ -50,17 +42,7 @@ export interface Query { A domain-anchored name like `WorkspaceQuery` or `SavedQuery` (this is, in fact, a *saved/stored* SQL query, not a runtime query execution) would distinguish it from the runtime `Query` concept in `queryexecution`. -### 2. Go/Java-style nested-message types - -**Location:** `src/v1/model.ts:57-91`, `163-197`, `324-358` - -- `CreateQueryRequestQuery` -- `UpdateQueryRequestQuery` -- `ListQueryObjectsResponseQuery` - -These three interfaces share the bulk of `Query`'s fields and originate from protobuf's `MessageA_MessageB` flattening. The naming forces the user to choose which `Query`-like type to construct depending on which call they want to make. This is the exact problem `alerts` v2 solved by collapsing back to `Alert`. - -### 3. `ListQueryObjectsResponseQuery` — Go-style + filler word +### 2. `ListQueryObjectsResponseQuery` — Go-style + filler word **Location:** `src/v1/model.ts:163-197` @@ -70,66 +52,20 @@ export interface ListQueryObjectsResponseQuery { ... } The "Objects" infix between `Query` and `Response` is filler — the RPC is `ListQueries`, the response wraps a list of queries; there is no separate "QueryObject" concept. Combined with the trailing `Query` repeat, this is one of the most verbose generated names in the package (29 chars, four query-related morphemes). -### 4. Duplicate concept across 4 packages — `queries`, `queryexecution`, `queryhistory`, `modelservingquery` - -**Location:** package boundaries - -The Databricks SDK ships four query-flavoured packages with no shared prefix: - -- `queries` — *saved* SQL queries (this package). -- `queryexecution` — running a query against a published dashboard. -- `queryhistory` — past query executions (with metrics, timing). -- `modelservingquery` — querying a served ML model. - -There is no obvious entry point for "I want to run a SQL query" — the user has to guess which package owns which verb. A namespace like `sql.queries`, `sql.executions`, `sql.history` (and `ml.servingQueries`) would group them. Inside this package, `Query` returned by `getQuery` is *not* the same `Query`-prefixed type that `queryhistory.ListQueries` returns (which is named `ListQueries` — see below). +### 3. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) -### 5. `LifecycleState.TRASHED` vs method `trashQuery` — verb/state inconsistency - -**Location:** `src/v1/model.ts:14-17`, `src/v1/client.ts:228-250` +**Location:** `src/v1/client.ts:242-267` ```ts -export enum LifecycleState { - ACTIVE = 'ACTIVE', - TRASHED = 'TRASHED', -} - /** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, ... A trashed query is permanently deleted after 30 days. */ async trashQuery(req: TrashQueryRequest, options?: CallOptions): Promise { ... } ``` -The HTTP verb is `DELETE`, the docstring talks about "permanently deleted after 30 days," but the method is `trashQuery` and the resulting enum value is `TRASHED`. Across the SDK, `trash` is unique to the SQL surface (queries, alerts); every other resource uses `deleteX`. A v2 of `alerts` already broke this consistency (it renamed `TRASHED` → `DELETED` but kept `trashAlert`); `queries` v1 may face the same trap. - -### 6. Missing domain prefix on enums - -**Location:** `src/v1/model.ts:8-22` - -```ts -export enum DatePrecision { ... } -export enum LifecycleState { ... } -export enum RunAsMode { ... } -``` - -Three top-level enums in a domain-specific package, none prefixed with `Query*`. The same package also indirectly uses an identical `LifecycleState` concept that exists with the same values (`ACTIVE`/`TRASHED`) in `alerts` v1; when a user imports both they collide by name. `QueryLifecycleState`, `QueryRunAsMode`, `QueryDatePrecision` (or simply re-using shared `LifecycleState` from a common package) would address this; the current state is the worst of both worlds. - -### 7. `QueryParameter` vs sibling value types — inconsistent prefixing - -**Location:** `src/v1/model.ts:268-306`, `308-310`, `219-221`, `140-147` - -```ts -export interface QueryParameter { ... } // prefixed -export interface TextValue { ... } // unprefixed -export interface NumericValue { ... } // unprefixed -export interface EnumValue { ... } // unprefixed -export interface DateValue { ... } // unprefixed -export interface DateRangeValue { ... } // unprefixed -export interface QueryBackedValue { ... } // prefixed -``` - -Some value-type wrappers are prefixed (`Query*`), others are not. The choice appears to be based on whether the type "feels generic" — but `EnumValue`, `DateValue`, `DateRange` are arguably even more generic than `QueryParameter`. The package picks `QueryParameter` and `QueryBackedValue` for prefixing, while leaving `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRangeValue` unprefixed. Result: importing this package brings ambient types like `EnumValue` and `TextValue` into the user's scope. +The HTTP verb is `DELETE`, the docstring talks about "permanently deleted after 30 days," but the method is `trashQuery`. Across the SDK, `trash` is unique to the SQL surface (queries, alerts); every other resource uses `deleteX`. A v2 of `alerts` already broke this verb consistency (it kept `trashAlert` even as the rest of the SDK standardised on `delete`); `queries` v1 may face the same trap. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 8. `QueryBackedValue` — misleading +### 4. `QueryBackedValue` — misleading **Location:** `src/v1/model.ts:259-266` @@ -146,7 +82,7 @@ export interface QueryBackedValue { The name reads as "a value that is backed by a query" — implying the value itself comes from query state. The actual semantics, per JSDoc, is: a dropdown widget whose options are populated by running another saved query. `QuerySourcedDropdownParameter`, `QueryBackedDropdown`, or `DropdownFromQuery` would describe the actual concept. As written, the name is at the same abstraction level as `QueryBackedView` or `QueryBackedTable` — neither of which describes what this is. -### 9. `EnumValue` — vague/generic top-level name +### 5. `EnumValue` — vague/generic top-level name **Location:** `src/v1/model.ts:140-147` @@ -163,32 +99,11 @@ export interface EnumValue { `EnumValue` exported at the package root. `enum` is a TypeScript keyword and a generic concept; the type is in fact a *dropdown* parameter source (a list of valid options + the selected subset). `DropdownParameter`, `EnumParameter`, or `QueryEnumParameter` would name the actual concept. -### 10. `Empty` — proto architectural leak - -**Location:** `src/v1/model.ts:133-138` - -```ts -/** - * Represents an empty message, similar to google.protobuf.Empty, which is not available in the firm - * right now. - */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface Empty {} -``` - -**Why:** Proto/RPC architectural leak — `google.protobuf.Empty` is a wire-format construct used by code generators to express "no body." The JSDoc explicitly admits this ("similar to google.protobuf.Empty"). Exporting it as a public TS interface forces every `Promise` return type (e.g. `trashQuery`, see #11) to surface the proto abstraction to callers. - -**Category:** Proto architectural leak. - -**Suggested:** Drop the type entirely; have methods return `Promise`. If a placeholder is needed, do not export it — TS already has `void` and `undefined` as native equivalents. - -**Rationale:** `Empty` exists only because protobuf has no native "no return value" concept. TypeScript does. Surfacing the proto workaround as a named export pollutes the package's public API with a wire-format artefact that has no domain meaning. Users see `Promise` and reasonably ask "what's in `Empty`?" — the answer is "nothing, it's a proto thing." That answer should never be visible. - ## Medium severity -### 11. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) +### 6. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) -**Location:** `src/v1/client.ts:228-250` +**Location:** `src/v1/client.ts:242-267` ```ts /** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, and cannot be used for alerts. You can restore a trashed query through the UI. A trashed query is permanently deleted after 30 days. */ @@ -200,7 +115,7 @@ async trashQuery( The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashQuery`. Across the SDK this is the only place where soft-delete uses `trash`-prefix outside `alerts`. The standard SDK shape is `deleteX` with a flag for `permanent: true/false` or two endpoints (`deleteX` + `purgeX`). -### 12. `TrashQueryRequest` — same as #11, in the type layer +### 7. `TrashQueryRequest` — same as #6, in the type layer **Location:** `src/v1/model.ts:312-314` @@ -212,9 +127,9 @@ export interface TrashQueryRequest { Same verb inconsistency at the type layer. Carries only `id`. -### 13. `listVisualizationsForQuery` — overly verbose +### 8. `listVisualizationsForQuery` — overly verbose -**Location:** `src/v1/client.ts:174-208` +**Location:** `src/v1/client.ts:185-222` ```ts async listVisualizationsForQuery( @@ -225,7 +140,7 @@ async listVisualizationsForQuery( `For` infixed between the resource and its parent is a Go-style nested-resource pattern. REST endpoint is `/api/2.0/sql/queries/{id}/visualizations` — TypeScript naming would more naturally be `listVisualizations(req: ListVisualizationsRequest)` where the request shape has `queryId` (or the method lives on a sub-client `client.queries(id).visualizations.list()`). The current name is 28 characters. -### 14. `Visualization` — vague/generic top-level name +### 9. `Visualization` — vague/generic top-level name **Location:** `src/v1/model.ts:360-377` @@ -235,13 +150,7 @@ export interface Visualization { ... } `Visualization` is a top-level export in a package about *query* visualizations. The sibling type `QueryParameter` has a domain prefix; `Visualization` does not. `QueryVisualization` would mirror `QueryParameter` and avoid collisions with the visualizations exposed by Lakeview, Dashboards, MLflow, etc. -### 15. `LifecycleState.TRASHED` — verb-tense inconsistency - -**Location:** `src/v1/model.ts:14-17` - -The enum value is past-participle (`TRASHED`), the method is imperative (`trashQuery`). When the SDK adds future lifecycle values like `ARCHIVED`, the new value will match this pattern, but the lifecycle vocabulary will diverge further from the verb vocabulary (`trash`/`archive`/`restore`). - -### 16. `RunAsMode` — verb-as-noun, filler `Mode` +### 10. `RunAsMode` — verb-as-noun, filler `Mode` **Location:** `src/v1/model.ts:19-22` @@ -252,27 +161,9 @@ export enum RunAsMode { } ``` -`RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity`, `Authority`, or even `runAs: 'OWNER' | 'VIEWER'` (a string literal union) would be cleaner. - -### 17. Open-ended discrete enum — `LAST_8_HOURS`, `LAST_24_HOURS`, `LAST_14_DAYS`, ... +`RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity` or `Authority` would be cleaner. -**Location:** `src/v1/model.ts:25-42` - -```ts -LAST_HOUR = 'LAST_HOUR', -LAST_8_HOURS = 'LAST_8_HOURS', -LAST_24_HOURS = 'LAST_24_HOURS', -LAST_7_DAYS = 'LAST_7_DAYS', -LAST_14_DAYS = 'LAST_14_DAYS', -LAST_30_DAYS = 'LAST_30_DAYS', -LAST_60_DAYS = 'LAST_60_DAYS', -LAST_90_DAYS = 'LAST_90_DAYS', -LAST_12_MONTHS = 'LAST_12_MONTHS', -``` - -The user gets 16 hard-coded time windows. If they want "last 45 days," there is no value. A `{ unit: 'DAY' | 'HOUR' | ...; n: number }` shape would express the same thing without the enum-value explosion. (Acknowledged that the underlying API likely accepts only these buckets — but the API design itself is the smell.) - -### 18. `MultiValuesOptions` — singular/plural mismatch +### 11. `MultiValuesOptions` — singular/plural mismatch **Location:** `src/v1/model.ts:210-217` @@ -289,69 +180,10 @@ export interface MultiValuesOptions { `MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). -### 19. `DateRangeValue.startDayOfWeek` — underspecified type - -**Location:** `src/v1/model.ts:113` - -```ts -startDayOfWeek?: number | undefined; -``` - -`number` with no JSDoc — is this 0-indexed or 1-indexed? Monday-first (ISO) or Sunday-first (US)? A `DayOfWeek` enum (`MONDAY`, `TUESDAY`, ...) or a typed alias would be self-documenting. - ## Low severity -### 20. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination +### 12. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination **Location:** `src/v1/model.ts:153-156`, `158-161` Standard Google AIP-158 names. Flagged for completeness; no action recommended. - -## Cross-package overlap - -The four query-flavoured packages share concept space without sharing types: - -| Package | Top-level `Query`-prefixed types | -|---------|----------------------------------| -| `queries` (this) | `Query`, `QueryParameter`, `QueryBackedValue`, `CreateQueryRequest`, `UpdateQueryRequest`, `ListQueriesRequest`, `GetQueryRequest`, `TrashQueryRequest`, `ListQueriesResponse`, `ListQueryObjectsResponseQuery`, `ListVisualizationsForQueryRequest`, `ListVisualizationsForQueryResponse` | -| `queryexecution` | `CancelQueryExecutionResponse`, `CancelQueryExecutionResponseStatus`, `ExecuteQueryResponse`, `PollQueryStatusResponse`, `PollQueryStatusResponseData`, `QueryResponseStatus`, `ExecutePublishedDashboardQueryRequest`, `PollPublishedQueryStatusRequest`, `CancelPublishedQueryExecutionRequest` | -| `queryhistory` | `QueryStatementType`, `QueryStatus`, `ListQueries`, `ListQueries_Response`, `QueryFilter`, `QueryInfo`, `QueryMetrics`, `QueryTag`, `ExternalQuerySource`, `ExternalQuerySource_JobInfo` | -| `modelservingquery` | `QueryEndpointInput`, `QueryEndpointInput_ExtraParamsEntry`, `QueryEndpointInput_UsageContextEntry`, `QueryEndpointResponse`, `QueryEndpointResponseObject` | - -Observations: - -- **`Query` is overloaded.** This package's `Query` is a saved SQL artefact. `queryhistory.QueryInfo` is a runtime execution record. `queryexecution`'s nameless concept (no `Query` type) is a dashboard parameterised query run. The four packages do not cross-reference each other's types. -- **`ListQueries` collides cross-package.** `queries.ListQueriesRequest` and `queryhistory.ListQueries` are entirely different shapes returning entirely different data, both with the same human-readable name. -- **No shared enums.** `queries.LifecycleState`, `queryhistory.QueryStatus`, `queryexecution.PendingStatus` / `SuccessStatus` are unrelated. A consumer building a query dashboard would have to manually correlate them. - -## Observations - -1. **`Query` overload.** `Query` is one of the broadest words in any SQL SDK. This package's `Query` is a *saved* configuration; `queryexecution`'s implicit "query" is a *running statement*; `queryhistory`'s `QueryInfo` is a *historical record*. None reference each other. A future cleanup might rename this package's `Query` → `SavedQuery` or `WorkspaceQuery`. - -2. **Soft-delete verb is `trash`, not `delete`.** `trashQuery` and `LifecycleState.TRASHED` are the only places in the SDK using "trash." This will diverge from the rest of the resource lifecycle vocabulary as the SDK grows. - -3. **Top-level type pollution.** `TextValue`, `NumericValue`, `EnumValue`, `DateValue`, `DateRange`, `DateRangeValue`, `MultiValuesOptions`, `Visualization` are all unprefixed and exported. A user importing `import { TextValue } from '@databricks/sdk-queries'` gets a generically-named type that competes with their own code. - -## Domain glossary - -| Term | Meaning in this package | -|------|------------------------| -| Query | A stored, named SQL statement saved in the workspace (not a running execution). | -| Query text | The raw SQL of the saved query. | -| Parameter | A placeholder in the SQL text (between `{{ }}` markers) that gets substituted at run time; has a typed value (text / numeric / enum / date / date-range / query-backed). | -| Query-backed value | A dropdown parameter whose options come from running another saved query. | -| Visualization | A view definition (counter, table, funnel, etc.) attached to a query. | -| Run-as | The identity (`OWNER` of the query or current `VIEWER`) under which the SQL executes. | -| Lifecycle state | `ACTIVE` (visible) or `TRASHED` (soft-deleted; permanently deleted after 30 days). | -| Auto-limit | A 1000-row cap automatically applied to query results when `applyAutoLimit=true`. | -| Parent path | The workspace folder path containing the saved query. | -| Catalog / schema | Unity-Catalog three-part-name prefix (`catalog.schema.table`) used as the default for unqualified table references in the SQL. | - -## File coverage - -| File | Lines | Read in full | -|------|-------|--------------| -| `src/v1/model.ts` | 996 | yes | -| `src/v1/client.ts` | 278 | yes | -| `src/v1/utils.ts` | 151 | yes | -| `src/v1/index.ts` | 38 | yes | diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index 5f55cedb..1398e3bc 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,139 +3,41 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 13 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | -| High | 2 | -| Medium | 8 | -| Low | 5 | -| Observation | 1 | +| High | 1 | +| Medium | 1 | +| Low | 2 | ## High severity -### 1. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:177` +### 1. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:176` - **Why weird:** The most central type in the package — the value returned from `listQueries` — is named `QueryInfo`. "Info" is a category-1 vague suffix; almost every field on it is a first-class property of a *query* (`queryId`, `queryText`, `status`, `userId`, `queryStartTimeMs`, ...). The type *is* the query — there is no other `Query` type for `QueryInfo` to disambiguate from. Compare with Go SDK convention where `*Info` types are common, but in TS the suffix is non-idiomatic; e.g. `alerts.Alert`, `jobs.Job`, `clusters.ClusterInfo` (this last one is the exception, also flagged in another audit). The endpoint URL is `/api/2.0/sql/history/queries` — the resource is "queries", so the response item should be `Query`. - **Category:** 8, 14, 1 (redundant `Info` suffix; Go/Java-style; vague suffix) - **Suggested name:** `Query`. -- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` (see #2) — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. - -### 2. `QueryInfo.endpointId` aliased to `warehouse_id` — `src/v1/model.ts:205` -- **Why weird:** `QueryInfo` has both `endpointId` (line 205) and `warehouseId` (line 232) and the doc on `endpointId` reads `Alias for warehouse_id.` Two fields, one underlying ID, both present on every response. Callers will pick one and silently miss the other if the server only fills one. The wire form has the same problem: `endpoint_id` and `warehouse_id` are independent JSON properties on the response. "Endpoint" is also outdated SQL Warehouse vocabulary (Databricks renamed SQL endpoints to SQL warehouses years ago); keeping it for backwards compatibility belongs in the wire layer, not the public TS type. -- **Category:** 12, 6 (duplicate concepts; misleading) -- **Suggested name:** Drop `endpointId`. If the server still returns it, alias inside the unmarshal: `warehouseId: d.warehouse_id ?? d.endpoint_id`. -- **Rationale:** Two fields with identical meaning is a perpetual source of `if (q.warehouseId !== undefined) ... else if (q.endpointId !== undefined) ...` chains in consumer code. The Go SDK already exposes both because it cannot collapse them without API breakage; TS can collapse and document the legacy wire name. +- **Rationale:** A list of queries should be `Query[]`, not `QueryInfo[]`. The field is even called `res?: QueryInfo[]` — `res?: Query[]` reads better. The Go SDK uses `QueryInfo` because Go does not have a `Query` type collision in this package; TS does not have that constraint and should pick the cleaner name. ## Medium severity -### 3. `PlansState` — vague type name — `src/v1/model.ts:14` +### 2. `PlansState` — vague type name — `src/v1/model.ts:14` - **Why weird:** "Plans state" — state of what? The JSDoc clarifies: "Possible Reasons for which we have not saved plans in the database." So the enum is really an "outcome" or "save status" — not a runtime state of a plan. The values include `EXISTS`, `EMPTY`, `IGNORED_*`, `UNKNOWN` — these are storage outcomes, not lifecycle states. Calling them a "state" is misleading. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `PlanStorageStatus` or `QueryPlansAvailability`. - **Rationale:** Reflects what the value actually represents. Also fixes the singular/plural smell: `PlansState` (plural noun + singular state) reads oddly; `PlanStorageStatus` is uniformly singular. -### 4. `PlansState.EXISTS` vs `EMPTY` — verb-tense inconsistency — `src/v1/model.ts:20,24` -- **Why weird:** Within the same enum: `EXISTS` is a verb (present tense), `EMPTY` is an adjective, `IGNORED_*` is a past participle, `UNKNOWN` is an adjective. Four grammatical categories for the same set of states. A consumer using one value learns the wrong pattern for the next. -- **Category:** 13 (verb-tense inconsistency) -- **Suggested name:** Normalize on adjectives/past participles: `AVAILABLE`, `EMPTY`, `IGNORED_SMALL_DURATION`, `IGNORED_LARGE_SIZE`, `IGNORED_SPARK_PLAN_TYPE`, `UNKNOWN`. -- **Rationale:** Internal consistency. `AVAILABLE` is also more accurate than `EXISTS` (the plans exist *somewhere*; the value means they exist *in storage*). - -### 5. `PlansState.IGNORED_LARGE_PLANS_SIZE` — grammatically awkward — `src/v1/model.ts:18` -- **Why weird:** `LARGE_PLANS_SIZE` is awkward English: "large plans size" reads as a noun pile. "Large plan size" or simply "too large" would scan naturally. -- **Category:** 18 (awkward grammar) -- **Suggested name:** `IGNORED_LARGE_PLAN_SIZE` or `IGNORED_TOO_LARGE`. -- **Rationale:** Fixes the singular/plural shape so the value reads as English. - -### 6. `PlansState.IGNORED_SPARK_PLAN_TYPE` — domain-leaky enum value — `src/v1/model.ts:26` -- **Why weird:** The value mentions "Spark plan type" — Spark is a Databricks implementation detail and the doc comment references three internal flags: `isIgnoredSparkPlanType`, `isIgnoredSparkPlanName`, `isDeltaLogScan`. SDK consumers shouldn't need to know about Spark's plan taxonomy. Also, the value name only references one of the three reasons — what if it's `isDeltaLogScan` or `isIgnoredSparkPlanName`? The value is one enum entry for three distinct causes. -- **Category:** 1, 6 (vague; misleading) -- **Suggested name:** `IGNORED_FILTERED_TYPE` (broader, doesn't leak Spark vocabulary), or split into three values matching the three internal flags. -- **Rationale:** Either generalize or specialize — but not both. - -### 7. `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — UNKNOWN-vs-UNSPECIFIED inconsistency — `src/v1/model.ts:22,6` -- **Why weird:** Two enums in the same file use two different conventions for the "default/unrecognized" sentinel: `PlansState.UNKNOWN` and `ChannelName.CHANNEL_NAME_UNSPECIFIED`. A consumer who learns one pattern won't reach for the other. The values are conceptually adjacent (both denote "no real value here") but spelled differently in the same package. -- **Category:** 13 (cross-enum convention inconsistency) -- **Suggested name:** Pick one convention across the package and apply it uniformly. -- **Rationale:** Cross-enum consistency. The proto3 zero-value member must exist on every enum, but the spelling of that member (`UNKNOWN` vs `UNSPECIFIED`) should be consistent across the package. - -### 8. `QueryInfo.warehouseId` and `endpointId` co-existing — `src/v1/model.ts:205,232` -- **Why weird:** Cross-reference of #2: these two fields both exist on `QueryInfo`. The audit calls out the *duplication*; the names *individually* are also weak — `warehouseId` is fine; `endpointId` is misleading (the wire form keeps it for back-compat with the old SQL Endpoint API). -- **Category:** 19, 16 (underspecified ID; field contradicting type domain) -- **Suggested name:** See #2. - -### 9. `QueryInfo.sessionId` — overloaded identifier — `src/v1/model.ts:222` -- **Why weird:** Doc reads `The spark session UUID that query ran on. This is either the Spark Connect, DBSQL, or SDP session ID.` Three distinct session-ID namespaces collapsed into one field with no discriminator. Caller cannot tell, from the field alone, which session type the ID refers to. -- **Category:** 15, 19 (generic field; underspecified ID) -- **Suggested name:** Keep `sessionId` but add a sibling `sessionType?: 'SPARK_CONNECT' | 'DBSQL' | 'SDP'` or split into three optional fields. -- **Rationale:** A naked UUID with three possible namespaces is a debugging hazard. - -### 10. `QueryInfo.metrics: QueryMetrics` vs `QueryInfo.duration: number` — `src/v1/model.ts:213,237` -- **Why weird:** A `metrics` sub-object exists, and *also* a top-level `duration` field on `QueryInfo`. Inside `QueryMetrics` there is `totalTimeMs` (`Total execution time of the query from the client's point of view, in milliseconds.`). What's the difference between `QueryInfo.duration` and `QueryInfo.metrics.totalTimeMs`? The doc on `duration` says `Total time of the statement execution. This value does not include the time taken to retrieve the results...` — so `duration` excludes result fetch, while `totalTimeMs` doesn't. Two near-synonym fields, in two places. -- **Category:** 12, 1 (duplicate concepts; vague) -- **Suggested name:** Move `duration` into `QueryMetrics` as `executionTimeExcludingFetchMs` (or use the existing `executionTimeMs`), and remove the top-level `duration`. -- **Rationale:** Two times on one type, both unitless in the name (`duration` doesn't say ms), invites confusion. - ## Low severity -### 11. `ExternalQuerySource.alertId` and `sqlQueryId` and `genieSpaceId` — — `src/v1/model.ts:103,107,110` -- **Why weird:** Several optional IDs co-exist on `ExternalQuerySource` with no rule about which is set when. Discriminated-union opportunity not taken. Field names are individually fine; together they encode "exactly one of N" weakly. -- **Category:** 19 (underspecified) -- **Suggested name:** As above — convert to discriminated union. -- **Rationale:** TS can encode this; Go cannot. Lost in 1:1 port. - -### 12. `QueryMetrics.rowsProducedCount` vs `QueryInfo.rowsProduced` — — `src/v1/model.ts:265,207` -- **Why weird:** `QueryInfo.rowsProduced` (no `Count` suffix) and `QueryMetrics.rowsProducedCount` (with `Count` suffix). Same concept, two field names. The `QueryInfo` doc says "The number of results returned by the query"; the `QueryMetrics` doc says "Total number of rows returned by the query." Are these always equal? Probably. Different names = different fields. -- **Category:** 12, 9 (duplicate concepts; plural/singular mismatch) -- **Suggested name:** Drop one. Keep `QueryMetrics.rowsProducedCount` if metrics is the right home; or rename one to match the other. -- **Rationale:** Same value reachable through two paths is a maintenance hazard. - -### 13. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:349,358` +### 3. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:348,357` - **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. - **Category:** 1 (vague — `Entry`) - **Suggested name:** Optional rename to domain names. - **Rationale:** Marginal. -### 14. `QueryTag.key` / `QueryTag.value` — both optional — `src/v1/model.ts:344,345` -- **Why weird:** Both fields are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional), but the names are also weak — `key` and `value` are the *most* generic names possible. -- **Category:** 1 (vague) -- **Suggested name:** Acceptable as proto-mirror; ideal would be `name: string; value?: string`. +### 4. `QueryTag.key` — required field marked optional — `src/v1/model.ts:343` +- **Why weird:** Both `key` and `value` are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional). +- **Category:** optionality (required field marked optional) +- **Suggested name:** Tighten `key` to `key: string` (non-optional). - **Rationale:** Minor. - -### 15. `ExternalQuerySource.legacyDashboardId` — `Legacy` mid-position architectural-leak modifier — `src/v1/model.ts:101` -- **Why weird:** `Legacy` is a temporal/architectural modifier mid-name — it tags the identifier as belonging to the *old* product (pre-Lakeview dashboards). The "legacy" label only has meaning inside Databricks' product roadmap; SDK consumers who don't know that Databricks shipped a new dashboard product see "legacy" as architectural noise. Names like `Legacy`/`Modern`/`Old`/`New` mid-position bake a release-timeline distinction into the public type surface; once a third dashboard product ships, the name becomes a lie. -- **Category:** proto-architectural-leak (`Legacy` mid-position temporal modifier) -- **Suggested name:** `redashDashboardId` (or whatever the underlying product is actually called), or fold into a discriminated union as suggested in #11. -- **Rationale:** Replace the temporal modifier with the actual product name. The Go SDK keeps `legacy_dashboard_id` because of wire-format back-compat; the TS surface can rename without breaking the wire transform. - -## Observations - -### O1. `Client` is the only exported class — `src/v1/client.ts:32` -- The class is just `Client`. Consistent across the SDK (so a project-level concern), but worth noting that `import { Client } from '@databricks/sdk-queryhistory/v1'` produces a bare name that collides with every other package's `Client`. Consumers must rename on import. - -## Cross-cutting themes - -1. **The `Info` / `State` suffix habit.** `QueryInfo`, `ChannelInfo`, `PlansState` — bare-noun renames (`Query`, `Channel`, `PlanStorageStatus`) would be cleaner. `Info` is a category-1 vague suffix doing no work. - -2. **Sentinel-naming convention inconsistency.** `PlansState.UNKNOWN` vs `ChannelName.CHANNEL_NAME_UNSPECIFIED` — two enums in the same file use different spellings for the proto3 zero-value member. The zero-value itself is required by proto3 and intentional; the inconsistent spelling is not. - -3. **Multiple ways to identify one thing.** `endpointId` / `warehouseId`, `sessionId` (Spark Connect or DBSQL or SDP). Each is a "two-fields-one-concept" or "one-field-multiple-concepts" smell. - -## Domain glossary -- **DBSQL** — Databricks SQL, the serverless warehouse engine. The SDK package targets `/api/2.0/sql/history/...`. -- **SDP** — Streaming/Serverless Data Pipelines (per the `sessionId` doc) — internal Databricks runtime. -- **Spark Connect** — Apache Spark's gRPC-based client/server protocol, distinct from DBSQL. -- **Channel** — A versioned SQL warehouse runtime track (Preview/Current/Previous/Custom). `ChannelInfo.dbsqlVersion` is the underlying version string. -- **Photon** — Databricks' native vectorized query engine; `photonTotalTimeMs` measures time spent in Photon-native execution. -- **Plans** — Query execution plans (logical/physical/spark). `PlansState` reports whether and why plans are stored. -- **Statement** — A SQL statement (one query). Aliased with "query" throughout this package; the `statementType` field captures `SELECT`/`INSERT`/etc. -- **Warehouse / Endpoint** — Same concept, two legacy names. SQL Warehouses (current) were originally called SQL Endpoints (legacy); the wire format keeps both fields. -- **Lakeview** — Databricks' newer dashboard product; `ExternalQuerySource.dashboardId` references it. `legacyDashboardId` references the older dashboards. -- **Genie space** — Databricks AI/BI assistant workspace; identified by `genieSpaceId`. -- **Provisioning queue / Overloading queue** — Two queue states a query passes through: waiting for a warehouse to spin up; waiting because the warehouse is overloaded. - -## File coverage -- `src/v1/model.ts` (613 lines): read fully. -- `src/v1/client.ts` (109 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (26 lines): read fully. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index a517b60f..01a2ffae 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -1,6 +1,6 @@ # Naming Audit: `registeredmodels` package (v1) -**Package path:** `/home/parth.bansal/sdk-js/packages/registeredmodels/` +**Package path:** `/home/parth.bansal/sdk-js/packages/uc/registeredmodels/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog (UC) Model Registry — the UC-resident successor to the legacy workspace-level `modelregistry` (MLflow-style) Model Registry. @@ -17,184 +17,47 @@ The `registeredmodels` package exposes ten UC model-registry operations The model layer is a verbatim 1:1 port of the Go SDK, and most defects derive from upstream definitions. -The dominant naming issues are (1) extremely heavy +The dominant naming issue is extremely heavy `Create*Request`/`Update*Request` shapes that include server-populated read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, -`fullName`, `metastoreId`, `storageLocation`, `browseOnly`), and (2) -collision-prone parallel concept naming versus the legacy -`modelregistry` package. +`fullName`, `metastoreId`, `storageLocation`, `browseOnly`). --- ## Findings -### 1. Vague / generic names +### 1. Redundant suffixes -_None._ - ---- - -### 2. Sentinel enum naming inconsistency - -#### 2.1 `ModelVersionStatus.MODEL_VERSION_STATUS_UNKNOWN` (model.ts:6) -The zero-value sentinel on this enum is named `MODEL_VERSION_STATUS_UNKNOWN` -while every other enum in the codebase uses `*_UNSPECIFIED` for the proto3 -zero-value member. The inconsistency is internal: `UNKNOWN` reads as a -discoverable lifecycle state alongside the three real states -(`PENDING_REGISTRATION`, `FAILED_REGISTRATION`, `READY`), whereas -`UNSPECIFIED` carries the standard "value-not-set" semantics used -elsewhere. Rename to `MODEL_VERSION_STATUS_UNSPECIFIED` for consistency -with the rest of the SDK and to clarify that the value is a default -rather than an observable status. - ---- - -### 3. Acronym casing inconsistencies (URI, UC, MLflow, ID) - -#### 3.1 `runId` versus `Id` (model.ts:225, 253, 366) -"ID" is a two-letter initialism. Google TS style guide states that -identifiers should follow `camelCase` and treat acronyms as words. The -package uses both `runId` (one-letter run + Id, fine) and `id` (lowercase -standalone), but for `runWorkspaceId` it lowercases `Id` correctly. The -issue is that `metastoreId`, `id`, and `runId` are all lowercase, while -`URI` appears nowhere as a field name. - ---- - -### 4. Cryptic abbreviations - -_None._ - ---- - -### 5. Misleading names - -_None._ - ---- - -### 6. Overly verbose names - -_None._ - ---- - -### 7. Redundant suffixes - -#### 7.1 `RegisteredModelInfo` (model.ts:273), `ModelVersionInfo` (model.ts:210), `RegisteredModelAliasInfo` (model.ts:258) +#### 1.1 `RegisteredModelInfo` (model.ts:271), `ModelVersionInfo` (model.ts:208), `RegisteredModelAliasInfo` (model.ts:256) The `*Info` suffix is a verbatim Go-ism. In TS the suffix adds nothing — `RegisteredModel`, `ModelVersion`, and `RegisteredModelAlias` would be the natural names. `*Info` is leftover from the proto/Go convention of distinguishing a wire DTO from an in-memory entity in the same file. -TypeScript does not need the distinction. Compare with the legacy -`modelregistry` package, which uses bare names (`RegisteredModel`, -`ModelVersion`) — see §10.1. +TypeScript does not need the distinction. --- -### 8. Singular / plural mismatches +### 2. Singular / plural mismatches -#### 8.1 `ListModelVersionsRequest`, `ListModelVersionsRequest_Response.modelVersions` (model.ts:140, 159) +#### 2.1 `ListModelVersionsRequest`, `ListModelVersionsResponse.modelVersions` (model.ts:140, 158) The request type is *plural* (`ListModelVersionsRequest`), the response collection field is *plural* (`modelVersions`). Internally consistent. -#### 8.2 `ListRegisteredModelsRequest` paginates registered models; field is `registeredModels` (model.ts:202) -Same as 8.1; flagged for completeness. - ---- - -### 9. Reserved-word collisions - -#### 9.1 `Dependency.value.$case: 'function'` (model.ts:91-93) -`function` is a TS reserved keyword. The discriminant value happens to -be a string literal so it parses, but the projected `function` field -inside the union arm (`{$case: 'function'; function: FunctionDependency}`) -shadows the keyword. Valid TS, but it forces consumers to write -`if (dep.value.$case === 'function') { dep.value.function ... }` — -syntactically legal, ergonomically poor. The Go SDK uses -`Function FunctionDependency` (capitalized), avoiding the collision. - -#### 9.2 No other reserved words observed. -`name`, `version`, `comment`, `owner`, `aliases`, `dependencies`, etc. -are all safe. +#### 2.2 `ListRegisteredModelsRequest` paginates registered models; field is `registeredModels` (model.ts:200) +Same as 2.1; flagged for completeness. --- -### 10. Duplicate concepts versus modelregistry / MLflow - -#### 10.1 `RegisteredModel` (modelregistry) versus `RegisteredModelInfo` (registeredmodels) -The legacy workspace-level package `modelregistry` already exports a -`RegisteredModel` type and a `ModelVersion` type (verified in -`/home/parth.bansal/sdk-js/packages/modelregistry/src/v1/model.ts`). -The UC-resident package re-uses the same domain noun with an `Info` -suffix (`RegisteredModelInfo`, `ModelVersionInfo`). A consumer -importing both packages will hold both `RegisteredModel` (from -modelregistry) and `RegisteredModelInfo` (from registeredmodels) for -fundamentally different APIs that nonetheless model the same concept. - -This is the single most confusing parallel-concept issue. Mitigations: -- Drop the `Info` suffix here so the types collide visibly and force - an import alias (`import {RegisteredModel as UcRegisteredModel}`), or -- Adopt distinct domain nouns (`UcRegisteredModel`, `CatalogModel`). - -#### 10.2 `CreateRegisteredModelRequest` (registeredmodels) versus `CreateRegisteredModelRequest` (modelregistry) -Same exact type name in both packages. Path-disambiguated only. -`grep -rn "CreateRegisteredModelRequest" packages/` returns two -identical identifiers in two different namespaces; both are documented -as "Create a registered model" but mean different things. The collision -risk is identical for `DeleteRegisteredModelRequest`, -`DeleteModelVersionRequest`, `GetModelVersionRequest`, -`ListRegisteredModelsRequest`, and `ModelVersionStatus` (all share names -with the legacy `modelregistry` exports). - -#### 10.3 `ModelVersionStatus` collision (model.ts:5) -Identical enum name in `modelregistry/src/v1/model.ts`. The three real -*variants* match (`PENDING_REGISTRATION`, `FAILED_REGISTRATION`, -`READY`), but `registeredmodels` adds a `MODEL_VERSION_STATUS_UNKNOWN` -zero-value sentinel that the legacy package lacks. A consumer who -imports both will see two enums of the same name describing -nearly-the-same lifecycle on two different APIs. This is high-risk for -runtime bugs (passing one package's enum value into the other compiles -but does not match), and the divergent zero-value handling makes the -collision worse. +### 3. Go / Java-style names ---- - -### 11. Verb tense / parallel inconsistency - -_None._ +#### 3.1 `Info` suffix everywhere +Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §1.1. --- -### 12. Go / Java-style names +### 4. Generic field names losing meaning -#### 12.1 `Info` suffix everywhere -Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §7.1. - -#### 12.2 PascalCase exported `Client` (client.ts:63) -The exported `Client` class is named bare-`Client`. Most TS SDKs export -a context-qualified name like `RegisteredModelsClient` or -`UcRegisteredModelsClient`. The bare `Client` works with the -`registeredmodels/v1` import path but causes name clashes if a consumer -imports from multiple SDK packages without aliases. Conventional Go -SDK pattern leaking into TS. - ---- - -### 13. Underspecified IDs - -#### 13.1 `ModelVersionInfo.runWorkspaceId` (model.ts:230) -`number` typed. The doc says "ID of the Databricks workspace". Workspace -IDs in Databricks are 64-bit integers — TS `number` is only safe up to -2^53. This is a *type* concern, but the name `runWorkspaceId` does not -flag the underlying integer-width risk; consider `string` per Go's -`json:",string"` tag treatment. - ---- - -### 14. Generic field names losing meaning - -#### 14.1 `CreateRegisteredModelRequest.aliases` (model.ts:47), `UpdateRegisteredModelRequest.aliases` (model.ts:401) +#### 4.1 `CreateRegisteredModelRequest.aliases` (model.ts:47), `UpdateRegisteredModelRequest.aliases` (model.ts:399) A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. Aliases are normally set on already-existing models, not at create time. The field is also marked optional. The name `aliases` is @@ -203,9 +66,9 @@ shape is semantically odd. Flagged for shape, not just naming. --- -### 15. Field contradicting type domain +### 5. Field contradicting type domain -#### 15.1 `CreateRegisteredModelRequest.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId, storageLocation, browseOnly}` (model.ts:33-49) +#### 5.1 `CreateRegisteredModelRequest.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId, storageLocation, browseOnly}` (model.ts:33-49) `CreateRegisteredModelRequest` is a *request* shape, yet it includes server-populated fields that the client cannot meaningfully set: - `fullName` (computed from `catalogName.schemaName.name`) @@ -216,21 +79,19 @@ server-populated fields that the client cannot meaningfully set: These fields belong on `RegisteredModelInfo` (the response). Their presence on the create request misleads users into thinking they can set creation timestamps or override the metastore. Same defect on -`UpdateRegisteredModelRequest` (model.ts:371-404): all six are present +`UpdateRegisteredModelRequest` (model.ts:371-401): all six are present plus `name`, `catalogName`, `schemaName`, `storageLocation`, `aliases`, -and `browseOnly` — most of which are not actually updatable per the -JSDoc which says "only the name, the owner or the comment of the -registered model can be updated". +and `browseOnly` — most of which are not actually updatable. -#### 15.2 `UpdateModelVersionRequest.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:319-369) +#### 5.2 `UpdateModelVersionRequest.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:319-366) `UpdateModelVersionRequest` carries *every* field from `ModelVersionInfo`. -The JSDoc says "Currently only the comment of the model version can be -updated". The shape is therefore deeply misleading: it presents 17 -optional fields where 16 are silently no-ops on the server. A user -setting `updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` +Only the comment of the model version can be updated. The shape is +therefore deeply misleading: it presents 17 optional fields where 16 are +silently no-ops on the server. A user setting +`updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` will see no effect from `status` but no error either. -#### 15.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:266-270) +#### 5.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:264-268) Three parent-locator fields on an alias type. The alias is already nested inside `RegisteredModelInfo.aliases`, so the parent is known from context. Embedding these makes the alias serialisable in @@ -238,92 +99,32 @@ isolation but pollutes the shape. --- -### 16. Type-suffix tautology +### 6. Type-suffix tautology -#### 16.1 `RegisteredModelInfo` (model.ts:273), `ModelVersionInfo` (model.ts:210), `RegisteredModelAliasInfo` (model.ts:258) -See §7.1. The `Info` suffix is tautological because the type already -*is* the info; it does not need to be marked as such. Compare with the -parallel `modelregistry` package which uses bare `RegisteredModel` / -`ModelVersion`. - ---- - -### 17. Proto-architectural leaks - -#### 17.1 `DeleteModelVersionRequest_Response` — model.ts:66 -- **Why:** Underscore-separated identifier signals a nested protobuf - message (`message DeleteModelVersionRequest { message Response { ... } }`). - The transport encoding has bled into the public type name and the - `eslint-disable` comment on the same line acknowledges it explicitly - as "Proto-style nested message name". -- **Category:** Proto suffix/infix. -- **Suggested:** `DeleteModelVersionResponse` (or `void` since the body - is empty). -- **Rationale:** TS callers have no nesting; a flat name keeps the - public surface free of proto-nested origin markers. - -#### 17.2 `DeleteRegisteredModelAliasRequest_Response` — model.ts:76 -- **Why:** Same proto-nested-message pattern as 17.1; empty body, only - the type name carries the leak. -- **Category:** Proto suffix/infix. -- **Suggested:** `DeleteRegisteredModelAliasResponse` (or `void`). -- **Rationale:** See 17.1. - -#### 17.3 `DeleteRegisteredModelRequest_Response` — model.ts:84 -- **Why:** Same proto-nested-message pattern as 17.1; empty body. -- **Category:** Proto suffix/infix. -- **Suggested:** `DeleteRegisteredModelResponse` (or `void`). -- **Rationale:** See 17.1. - -#### 17.4 `ListModelVersionsRequest_Response` — model.ts:158 -- **Why:** Underscore-separated identifier signals a nested protobuf - response message embedded under the request. The `eslint-disable` - comment on the same line acknowledges it explicitly. -- **Category:** Proto suffix/infix. -- **Suggested:** `ListModelVersionsResponse`. -- **Rationale:** See 17.1. - -#### 17.5 `ListRegisteredModelsRequest_Response` — model.ts:201 -- **Why:** Same proto-nested-message pattern as 17.4. -- **Category:** Proto suffix/infix. -- **Suggested:** `ListRegisteredModelsResponse`. -- **Rationale:** See 17.1. +#### 6.1 `RegisteredModelInfo` (model.ts:271), `ModelVersionInfo` (model.ts:208), `RegisteredModelAliasInfo` (model.ts:256) +See §1.1. The `Info` suffix is tautological because the type already +*is* the info; it does not need to be marked as such. --- ## Cross-cutting observations -### A. Parallel package collision risk - -A consumer that imports both `modelregistry` and `registeredmodels` will -encounter colliding identifiers for: `ModelVersionStatus`, -`CreateRegisteredModelRequest`, `DeleteModelVersionRequest`, -`DeleteRegisteredModelRequest`, `GetModelVersionRequest`, -`ListRegisteredModelsRequest`, and the `Client` class. -Importing both *requires* aliasing on every single one of those names. -This is the biggest practical naming defect of the package. - -### B. Request shapes leak response/server fields +### A. Request shapes leak response/server fields `CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, and especially `UpdateModelVersionRequest` carry the entire response shape on the request side. This is a *type-design* defect surfaced via *naming* (a field called `createdAt` on a "create" request is -meaningless). See §15. +meaningless). See §5. --- ## Recommendations (priority-ordered) 1. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, - `RegisteredModelAliasInfo`. (§7.1, §16.1) -2. **Disambiguate parallel-package collisions** with `modelregistry` — - either re-namespace or rename types. (§10, §A) -3. **Strip server-populated fields** from `CreateRegisteredModelRequest`, + `RegisteredModelAliasInfo`. (§1.1, §6.1) +2. **Strip server-populated fields** from `CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, `UpdateModelVersionRequest` request - shapes. (§15, §B) -4. **Rename `MODEL_VERSION_STATUS_UNKNOWN`** to - `MODEL_VERSION_STATUS_UNSPECIFIED` for consistency with the rest of - the SDK's zero-value enum members. (§2.1) + shapes. (§5, §A) --- diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index 2b707968..ec8a886d 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -2,19 +2,8 @@ **Path:** `packages/repos/src/v1/` **Versions audited:** v1 -**Package name:** `@databricks/sdk-repos` (the `repos` directory + module name -use the abbreviation, while the JSDoc throughout the file consistently spells -the resource as "Git folder (repo)"). -**Inferred domain:** Databricks "Repos" API — a workspace-level CRUD surface -for "Git folders" (formerly "Repos"): linkable workspace mount points that -track a remote Git repository at a given branch/tag/commit, optionally with -sparse-checkout configuration. Five operations: -`create/get/list/update/delete`. The API endpoint stays `POST /api/2.0/repos` -even though the product was rebranded to "Git folders". One resource type -(`RepoInfo`), two sparse-checkout config types (`SparseCheckout`, -`SparseCheckoutUpdate`), and no enums anywhere despite eight closed-set -`provider` values appearing in JSDoc on five fields. -**Total weird names flagged:** 15 (15 still applicable, 0 newly fixed in regeneration on 2026-05-26) +**Package name:** `@databricks/sdk-repos` +**Total weird names flagged:** 6 --- @@ -22,21 +11,12 @@ even though the product was rebranded to "Git folders". One resource type | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| -| 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". Every JSDoc string in the package uses the form "Git folder (repo)". The package, type, method, and field names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | +| 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". Every JSDoc string in the package uses the form "Git folder (repo)". The package, type, and method names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | | 2 | `Repo` as the resource noun | model.ts (throughout) | concept | High | 1 Vague/generic, 5 Cryptic abbreviations | The TS resource type is `RepoInfo`. The JSDoc clarifies: "Git folder (repo) information". The product UI calls it "Git folder". The Go SDK source uses `Repo`. JS-side could use the rebranded name (`GitFolder`/`GitFolderInfo`) or at least spell out the abbreviation (`Repository`). The wire URL still says `repos` so URL renaming is not possible, but the TS types are free. | -| 3 | `RepoInfo` interface | model.ts:111 | interface | Medium | 20 Type-suffix tautology, 1 Vague/generic | The `Info` suffix is a Java/proto idiom that does not match TS norms. The interface *is* the repo — there is no `Repo` type that `RepoInfo` is "info about". `Repo` (or `GitFolder` per H1) without `Info` would be cleaner. (See also `CredentialInfo` in the `credentials` audit, M-pattern.) | -| 4 | `RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response` (three identical shapes) | model.ts:111, 29, 64 | interface trio | High | 12 Duplicate concepts | All three have the same seven fields (`id`, `path`, `url`, `provider`, `branch`, `headCommitId`, `sparseCheckout`) with the same types and the same optionality. The three zod transforms are three copies of the same body (model.ts:174-193, 200-218, 233-251 — sixty lines of duplicated logic). The two response shapes should be type aliases of `RepoInfo`. | -| 5 | `DeleteProjectRequest` (request type) | model.ts:50 | interface | High | 6 Misleading names, 12 Duplicate concepts | The type is named `DeleteProjectRequest` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project*` name in the entire package — every other operation uses `*Repo*`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | -| 6 | `Client.deleteProject` (method name on a `repos` client) | client.ts:105 | method | High | 6 Misleading names, 17 Inconsistent action verbs | The client method is `deleteProject` even though the package is `repos`, the URL is `/repos/{id}`, the JSDoc says "Deletes the specified repo", and the four sibling methods are `createRepo`, `getRepo`, `listRepos`, `updateRepo`. Should be `deleteRepo`. Reads as: `client.createRepo(...)`, `client.getRepo(...)`, `client.deleteProject(...)`, `client.updateRepo(...)` — the inconsistency is loud. | -| 7 | `provider` field typed as `string` (should be enum) | model.ts:15, 41, 76, 123 | field | High | 6 Misleading names, 15 Generic field names | JSDoc enumerates eight discrete provider values: `gitHub`, `bitbucketCloud`, `gitLab`, `azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, `gitLabEnterpriseEdition`, `awsCodeCommit`. There is no enum in the model — the field is `string`. Callers cannot get autocomplete and cannot type-check against the closed set. The JSDoc also says "case-insensitive" — but TS string comparison is case-sensitive. Should be a string-literal union or enum. Mirrors `gitProvider` in the `gitcredentials` audit (H6, #12). | -| 8 | `gitHub`, `bitbucketCloud`, `gitLab`, `gitHubEnterprise`, `gitLabEnterpriseEdition` wire values (in JSDoc) | model.ts:9-13, 37-39, 72-75, 119-121 | enum-like wire values | High | 3 Acronym casing inconsistencies, 5 Cryptic abbreviations | Same as `gitcredentials` audit #13. Casing is inconsistent across the same enumeration:
- "GitHub" → `gitHub` (lower-case G at the boundary)
- "GitLab" → `gitLab`
- "Bitbucket Cloud" → `bitbucketCloud`
- "Bitbucket Server" → `bitbucketServer`
- "Azure DevOps" → `azureDevOpsServices`
- "AWS CodeCommit" → `awsCodeCommit`
The "Hub"/"Lab"/"Cloud"/"Commit" portions are capitalized; the leading provider name uses lowercase initial. This breaks both the "Title Case" convention these brands actually use ("GitHub", "GitLab", "Bitbucket") and the "lower camel" TS field-name convention. Values dictated by the API server. | -| 9 | `gitLabEnterpriseEdition` wire value | model.ts:12, 39, 74, 121 | enum-like wire value | Medium | 7 Overly verbose, 6 Misleading names | 25-char value. JSDoc clarifies that `gitLabEnterpriseEdition` is "GitLab Self-Managed". The product name was renamed from "GitLab Enterprise Edition" to "GitLab Self-Managed" — the wire value preserves the legacy name. Same as `gitcredentials` audit #14. | -| 10 | `bitbucketServer` wire value | model.ts:11, 39, 74, 121 | enum-like wire value | Medium | 6 Misleading names | JSDoc clarifies "Bitbucket Data Center". Atlassian renamed "Bitbucket Server" to "Bitbucket Data Center" in 2024. Wire value is the legacy name. Same as `gitcredentials` audit #15. | -| 11 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:156, 162 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | -| 12 | `SparseCheckout` vs `SparseCheckoutUpdate` | model.ts:133, 143 | interface pair | High | 12 Duplicate concepts | Field-for-field identical:
```
interface SparseCheckout { patterns?: string[] }
interface SparseCheckoutUpdate { patterns?: string[] }
```
Same doc string ("Sparse checkout configuration, it contains options like cone patterns."). Same zod transform body (model.ts:253-259 vs 287-293 — duplicated marshal logic). One is used in `CreateRepoRequest`/responses; the other only in `UpdateRepoRequest`. The shapes have no semantic difference. Should be one type. | -| 13 | `Client` (unqualified class name) | client.ts:49 | class | Medium | 1 Vague/generic | `export class Client` — once imported it shadows every other package's `Client` (every package in this SDK exports its own `Client`). Should be `ReposClient` or, per H1, `GitFoldersClient`. Same flag as every prior audit. | -| 14 | `Client.createRepo` / `getRepo` / `listRepos` / `updateRepo` (singular) vs `deleteProject` | client.ts:79, 133, 161, 215, 105 | method set | High | 17 Inconsistent action verbs, 12 Duplicate concepts, 6 Misleading names | Four methods carry the `Repo` suffix; one carries `Project`. Per #5/#6, the `Project` form is a legacy name that leaked into this one operation only. Method naming should be uniform: `createRepo`, `getRepo`, `listRepos`, `updateRepo`, `deleteRepo` (or — per H1 — `createGitFolder`/`getGitFolder`/etc.). | -| 15 | `req.id ?? ''` String coercion in URL builders | client.ts:109, 137, 219 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `number | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 3 | `RepoInfo` interface | model.ts:108 | interface | Medium | 20 Type-suffix tautology, 1 Vague/generic | The `Info` suffix is a Java/proto idiom that does not match TS norms. The interface *is* the repo — there is no `Repo` type that `RepoInfo` is "info about". `Repo` (or `GitFolder` per H1) without `Info` would be cleaner. (See also `CredentialInfo` in the `credentials` audit, M-pattern.) | +| 4 | `DeleteProjectRequest` (request type) | model.ts:49 | interface | High | 6 Misleading names | The type is named `DeleteProjectRequest` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project*` name in the entire package — every other operation uses `*Repo*`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | +| 5 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:153, 159 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 6 | `req.id ?? ''` String coercion in URL builders | client.ts:114, 142, 230 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `bigint | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | --- @@ -44,11 +24,11 @@ even though the product was rebranded to "Git folders". One resource type ### H1. "Repos" is the legacy term; the product is "Git folders" -The package name (`repos`), the resource type (`RepoInfo`), the five client -methods (`createRepo`, `getRepo`, `listRepos`, `updateRepo`, -`deleteProject` (!)), and the response field (`repos`) all use the legacy -term "Repos". The Databricks product UI, marketing, and docs have rebranded -this resource to "Git folders". +The package name (`repos`), the resource type (`RepoInfo`), and the five +client methods (`createRepo`, `getRepo`, `listRepos`, `updateRepo`, +`deleteProject` (!)) all use the legacy term "Repos". The Databricks +product UI, marketing, and docs have rebranded this resource to +"Git folders". The JSDoc *throughout the file* uses the form "Git folder (repo)" — i.e., the generator already knows the rebrand happened. Twenty-three doc strings @@ -73,12 +53,12 @@ The package can also adopt the gitcredentials-style hyphenation: rename to ```ts export interface DeleteProjectRequest { /** The ID for the corresponding repo to delete. */ - id?: number | undefined; + id?: bigint | undefined; } ``` ```ts -async deleteProject(req: DeleteProjectRequest, options?: CallOptions): Promise +async deleteProject(req: DeleteProjectRequest, options?: CallOptions): Promise ``` The Databricks API endpoint is `DELETE /api/2.0/repos/{id}`. The doc says @@ -106,93 +86,6 @@ Recommendation: rename `DeleteProjectRequest` → `DeleteRepoRequest`, method pure TS-side rename that fixes a readability footgun. If the Go SDK keeps the legacy name (likely it does), file an upstream cleanup request. -### H3. Three field-for-field-identical "Repo" shapes - -`RepoInfo`, `CreateRepoRequest_Response`, and `GetRepoRequest_Response` -all have the same seven fields with the same types, the same optionality, -the same JSDoc text, and three copies of the same zod transform body -(model.ts:174-193 vs 200-218 vs 233-251). Two of the three are redundant. - -Recommendation: - -```ts -// Before -export interface CreateRepoRequest_Response { /* 7 fields */ } -export interface GetRepoRequest_Response { /* same 7 fields */ } -export interface RepoInfo { /* same 7 fields */ } - -// After -export interface Repo { /* 7 fields */ } -// Return Repo directly from create() and get(). -``` - -### H4. `provider` is typed `string` but is closed-set - -```ts -provider?: string | undefined; -``` - -JSDoc enumerates eight values: `gitHub`, `bitbucketCloud`, `gitLab`, -`azureDevOpsServices`, `gitHubEnterprise`, `bitbucketServer`, -`gitLabEnterpriseEdition`, `awsCodeCommit`. The set is closed; the API -server rejects other values. But the TS-side surfaces it as `string`, so: - -- No autocomplete on the value list. -- No compile-time check for typos (`gitub` will type-check). -- The JSDoc casing inconsistencies (`gitHub` vs `gitLabEnterpriseEdition`) - cannot be fixed at the call site, only by the API server. - -Recommendation: emit a string-literal union or enum. The casing problem -(#8) gets handled there. This is identical to the `gitcredentials` audit -H6 — the same field appears in both packages, neither has an enum, both -duplicate the eight-value enumeration inline. - -### H5. `Client.deleteProject` mid-CRUD-set - -The package's `Client` class exposes: - -```ts -client.createRepo(req) // ✓ -client.getRepo(req) // ✓ -client.listRepos(req) // ✓ -client.deleteProject(req) // 🚨 different noun -client.updateRepo(req) // ✓ -``` - -Four methods read uniformly; one does not. Renaming `deleteProject` → -`deleteRepo` is a one-line fix on the TS side that materially improves -readability. See H2 for the full discussion. - -### H6. `SparseCheckout` vs `SparseCheckoutUpdate` (identical shapes) - -```ts -interface SparseCheckout { patterns?: string[] | undefined } -interface SparseCheckoutUpdate { patterns?: string[] | undefined } -``` - -Both have the same doc string ("Sparse checkout configuration, it contains -options like cone patterns."), both zod transforms are identical -(model.ts:253-259 vs 287-293). The only difference is which top-level -request type holds them — `CreateRepoRequest` holds `SparseCheckout`; -`UpdateRepoRequest` holds `SparseCheckoutUpdate`. - -Recommendation: one type, used by both. The Go-SDK likely keeps the two -separate because the proto generator emits them; the TS-side is free to -collapse. - -### H7. `Client` is unqualified - -`export class Client` (client.ts:49). Every package in this SDK exports -its own `Client`. Once imported in user code: - -```ts -import {Client as ReposClient} from '@databricks/sdk-repos/v1'; -``` - -— the consumer has to do the renaming. The generator should produce -`ReposClient` directly (or `GitFoldersClient` per H1, matching the package -noun). This is a pattern-wide issue and was flagged in every audit so far. - --- ## Medium severity (worth pushing back on) @@ -209,7 +102,7 @@ proto/Go-SDK ancestry; TS canonical naming would just be `Repo` (or ```ts interface UpdateRepoRequest { - id?: number; + id?: bigint; branch?: string; tag?: string; sparseCheckout?: SparseCheckoutUpdate; @@ -230,7 +123,7 @@ type GitRef = | {kind: 'commit'; sha: string}; interface UpdateRepoRequest { - id?: number; + id?: bigint; ref?: GitRef; sparseCheckout?: SparseCheckoutUpdate; } @@ -245,63 +138,8 @@ This is a wire-compatible rename; the zod transform can flatten back to const url = `${this.host}/api/2.0/repos/${String(req.id ?? '')}`; ``` -When `req.id` is `undefined` (the type allows it — `id?: number`), this +When `req.id` is `undefined` (the type allows it — `id?: bigint`), this produces `/api/2.0/repos/` (trailing slash, no ID). The server responds 404. Idiomatic TS would mark `id` as required for paths that need it, or throw before issuing the call. The pattern repeats in -`client.ts:109, 137, 219`. - ---- - -## Low severity (style polish) - -_None._ - ---- - -## Notes - -### Wire-protocol values that the audit cannot fix - -The `provider` wire values (`gitHub`, `bitbucketCloud`, etc.) are dictated -by the API server. The casing inconsistencies (#8) and legacy renames -(#9, #10) are baked in. The TS-side cannot change them without breaking -the wire. The audit flags them for awareness — fixing requires an -API-server change. - -The `DELETE /api/2.0/repos/{id}` URL also cannot change. But the *TS-side* -method name (`deleteProject`) and the *TS-side* request type -(`DeleteProjectRequest`) can both rename freely (see H2). - -### Identifier zoo summary - -| Identifier kind | Count | -|---|---| -| Total exported interfaces | 10 | -| Identical-shape interface trios | 1 (`RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response`) | -| Identical-shape interface pairs | 1 (`SparseCheckout` ≡ `SparseCheckoutUpdate`) | -| Enums | 0 (despite an 8-value closed set on `provider`) | -| Legacy-name leaks | 1 (`DeleteProjectRequest*` on a "repos" client) | -| Rebranding leaks | All identifiers (the resource is now "Git folder" everywhere in JSDoc and product UI, but the type/method names still say "Repo") | - -### Comparison to other audits - -| Issue | This package | `gitcredentials` audit | `credentials` audit | -|---|---|---|---| -| Bare `Client` class | Yes (H7) | Yes (H7) | Yes (#10) | -| Three identical resource/response shapes | Yes (H3: `RepoInfo` ≡ `CreateRepoRequest_Response` ≡ `GetRepoRequest_Response`) | Yes (H4: `Credential` ≡ `CreateCredentials_Response` ≡ `GetCredentials_Response`) | Yes (#2, #3, #5) | -| `string`-typed enum-domain field (`provider`) | Yes (H4) | Yes (H6 — same field!) | No (uses real enums) | -| `host` field stores a URL | Removed | Yes (#36) | Common | -| Plural/singular mismatch | Removed | Severe (H2 — plural request type for singular op) | Mixed | -| Legacy-name leak | **Yes (H2 — `DeleteProjectRequest*` on a "repos" client)** | No | No | -| Product-rebrand leak | **Yes (H1 — TS surface says "Repo", product/doc says "Git folder")** | Partial (Bitbucket Data Center rename, GitLab Self-Managed rename — wire values only) | No | - -The `DeleteProjectRequest` legacy leak (H2) is unique to this package — no -other audited package has a single mismatched-noun operation in an -otherwise-uniform CRUD client. The product-rebrand-vs-API-name divergence -(H1) is also pronounced: every JSDoc string in the file uses "Git folder -(repo)", while every type and method name uses only "Repo". The generator -already has the new terminology in the doc strings; only the names have -not followed. - ---- +`client.ts:114, 142, 230`. diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 469dfae7..59d132f4 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -1,28 +1,25 @@ # Naming Audit: `resourcequotas` package (v1) -**Package path:** `/home/parth.bansal/sdk-js/packages/resourcequotas/` +**Package path:** `/home/parth.bansal/sdk-js/packages/uc/resourcequotas/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog — resource quota inspection (count vs. limit for child securables under a parent). -Notation: file paths are absolute. Findings reference `file:line`. - --- ## Summary | Severity | Count | | ----------- | ----- | -| High | 2 | +| High | 1 | | Medium | 1 | -| Low | 2 | +| Low | 1 | | Observation | 1 | -| **Total** | **6** | +| **Total** | **4** | Headline themes: -1. **Singular/plural mismatch on the `listQuota` / `listQuotaIter` methods.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotasRequest`, `ListQuotasRequest_Response`) are all plural, but the client methods are `listQuota` / `listQuotaIter` (singular). This is the most user-visible naming defect. -2. **`SecurableType` is duplicated as a `string` on `GetQuotaRequest` but a typed enum on `QuotaInfo`.** The two views of the same field are inconsistent — see H2 below. +1. **Singular/plural mismatch on the `listQuota` / `listQuotaIter` methods.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotasRequest`, `ListQuotasResponse`) are all plural, but the client methods are `listQuota` / `listQuotaIter` (singular). This is the most user-visible naming defect. --- @@ -30,19 +27,11 @@ Headline themes: ### H1. Method names `listQuota` / `listQuotaIter` are singular but return / paginate a list -- **File / line:** `src/v1/client.ts:98` (`async listQuota(...)`); `src/v1/client.ts:131` (`async *listQuotaIter(...)`). +- **File / line:** `src/v1/client.ts:103` (`async listQuota(...)`); `src/v1/client.ts:139` (`async *listQuotaIter(...)`). - **Category:** #9 singular/plural mismatch; #15 generic-name losing meaning. -- **Current:** `async listQuota(req: ListQuotasRequest, options?): Promise`; `async *listQuotaIter(req: ListQuotasRequest, options?): AsyncGenerator`. +- **Current:** `async listQuota(req: ListQuotasRequest, options?): Promise`; `async *listQuotaIter(req: ListQuotasRequest, options?): AsyncGenerator`. - **Suggestion:** `listQuotas` / `listQuotasIter`. -- **Rationale:** The request type is `ListQuotasRequest` (plural noun), the response is `ListQuotasRequest_Response` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:92`). Every neighbouring signal is plural except the method names. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact, and now duplicated on the generator-added `listQuotaIter` paginator. - -### H2. `GetQuotaRequest.parentSecurableType: string` vs. `QuotaInfo.parentSecurableType: SecurableType` - -- **File / line:** `src/v1/model.ts:29` (request, `string`); `src/v1/model.ts:62` (response, `SecurableType`). -- **Category:** #6 misleading name; #16 field contradicting type domain. -- **Current:** The same logical field is typed as a free-form `string` on the request and as the typed `SecurableType` enum on the response. -- **Suggestion:** Type both as `SecurableType`. If the API genuinely accepts arbitrary strings on input, document that explicitly in the field-level JSDoc. -- **Rationale:** A caller cannot intuit that the `parentSecurableType` they pass into `getQuota` must match a `SecurableType` enum value — the type system promises nothing. The URL substitution (`client.ts:71`) drops the string straight into the path, so a typo like `CATELOG` produces a 404 the user has to debug. Either the enum is the source of truth and the request should reuse it, or the enum is wrong. Today they disagree, which is the worst of both worlds. +- **Rationale:** The request type is `ListQuotasRequest` (plural noun), the response is `ListQuotasResponse` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:97`). Every neighbouring signal is plural except the method names. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact, and now duplicated on the generator-added `listQuotaIter` paginator. --- @@ -50,7 +39,7 @@ Headline themes: ### M1. `QuotaInfo` carries the redundant `Info` suffix -- **File / line:** `src/v1/model.ts:60`. +- **File / line:** `src/v1/model.ts:58`. - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `interface QuotaInfo`. - **Suggestion:** `Quota`. @@ -62,19 +51,11 @@ Headline themes: ### L1. `req` parameter name on every client method -- **File / line:** `src/v1/client.ts:68, 99, 132`. +- **File / line:** `src/v1/client.ts:70, 104, 140`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. - **Current:** `req: GetQuotaRequest`, `req: ListQuotasRequest` (twice, once on `listQuota` and once on `listQuotaIter`). - **Suggestion:** `request`. -- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:72, 77, 82, 112, 117, 122` — same shorthand, lower priority. - -### L2. `Client` is the bare type name (no `ResourceQuotasClient`) - -- **File / line:** `src/v1/client.ts:37`. -- **Category:** #14 Go-style name. -- **Current:** `export class Client`. -- **Suggestion:** `ResourceQuotasClient` (or a re-export of `Client as ResourceQuotasClient`). -- **Rationale:** TS imports often need disambiguation: `import {Client} from '@databricks/sdk-resourcequotas/v1'` forces aliasing on any consumer that uses multiple packages. Repo-wide convention, see `catalogs.md` §14.2. +- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:74, 87, 90, 93, 117, 130, 133, 136` — same shorthand, lower priority. --- @@ -83,98 +64,3 @@ Headline themes: ### O1. `…Info` suffix repeated across UC types `QuotaInfo` mirrors `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo`. If the codebase decides to drop the `Info` suffix, this is one of many. - ---- - -## Domain glossary - -| Term | Meaning in this package | -| -------------------- | ------------------------------------------------------------------------------------ | -| Quota | A `(count, limit)` pair tracking how many child securables exist under a parent. | -| Parent securable | The container whose children are being counted (e.g. metastore → catalog, catalog → schema). | -| `parentFullName` | The dotted full name of the parent securable; or the metastore ID when parent is a metastore. | -| `quotaName` | A slug built from the quota kind plus the `-quota` suffix (e.g. `schemas-quota`). Format under-documented. | -| `quotaCount` | Current number of child securables. | -| `quotaLimit` | Maximum allowed before further creation is rejected. | -| `lastRefreshedAt` | Epoch-ms timestamp of last server-side count refresh; refreshes are asynchronous. | -| SecurableType | One of 17 Unity Catalog securable kinds (CATALOG, SCHEMA, TABLE, …). | - ---- - -## File coverage - -| File | Lines | Audited | -| -------------- | ----- | ---------------------------------------------------------------------- | -| `src/v1/model.ts` | 113 | 1 enum (17 members), 4 interfaces (12 fields total). | -| `src/v1/client.ts` | 148 | `Client` class + constructor + `getQuota` + `listQuota` + `listQuotaIter` + all locals + `PACKAGE_SEGMENT`. | -| `src/v1/utils.ts` | 151 | All exported / private functions, the `HttpCallOptions` interface, `readAll`. | -| `src/v1/index.ts` | 14 | All 7 re-exports. | - -Type & symbol checklist: - -- [x] `SecurableType` enum (17 members) → no defect. -- [x] `SecurableType.STAGING_TABLE` (with TODO comment) → no defect (already flagged in source). -- [x] `GetQuotaRequest` interface (3 fields) → H2; per-field below. Wrapper preserved for forward compatibility. -- [x] `GetQuotaRequest.parentSecurableType` (`string`) → H2 (type mismatch with response). -- [x] `GetQuotaRequest.parentFullName` → no defect. -- [x] `GetQuotaRequest.quotaName` → no defect. -- [x] `GetQuotaRequest_Response` interface (1 field) → Wrapper preserved for forward compatibility. -- [x] `GetQuotaRequest_Response.quotaInfo` → no defect beyond M1 (`Info` suffix). -- [x] `ListQuotasRequest` interface (2 fields) → no defect. -- [x] `ListQuotasRequest.maxResults` → no defect. -- [x] `ListQuotasRequest.pageToken` → no defect. -- [x] `ListQuotasRequest_Response` interface (2 fields) → no defect. -- [x] `ListQuotasRequest_Response.quotas` → no defect; correctly plural. -- [x] `ListQuotasRequest_Response.nextPageToken` → no defect. -- [x] `QuotaInfo` interface (6 fields) → M1 (`Info` suffix), O1; per-field below. -- [x] `QuotaInfo.parentSecurableType` (`SecurableType`) → H2. -- [x] `QuotaInfo.parentFullName` → no defect. -- [x] `QuotaInfo.quotaName` → no defect. -- [x] `QuotaInfo.quotaCount` → no defect. -- [x] `QuotaInfo.quotaLimit` → no defect. -- [x] `QuotaInfo.lastRefreshedAt` → no defect. -- [x] `Client` class → L2. -- [x] `Client.host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `getQuota(req, options)` method → L1. -- [x] `listQuota(req, options)` method → H1, L1. -- [x] `listQuotaIter(req, options)` paginator method → H1, L1. -- [x] `HttpCallOptions` interface → no defect. -- [x] `index.ts` re-exports → no defects; mirrors model exports faithfully. - ---- - -## File / line index for fast lookup - -| Identifier | Location | Finding | -| -------------------------------------------------------- | ----------------- | ------------------------ | -| `SecurableType` | model.ts:6 | — | -| `SecurableType.STAGING_TABLE` | model.ts:24 | — (annotated TODO) | -| `GetQuotaRequest` | model.ts:27 | — | -| `GetQuotaRequest.parentSecurableType` (`string`) | model.ts:29 | H2 | -| `GetQuotaRequest.parentFullName` | model.ts:31 | — | -| `GetQuotaRequest.quotaName` | model.ts:33 | — | -| `ListQuotasRequest` | model.ts:42 | — | -| `ListQuotasRequest.maxResults` | model.ts:44 | — | -| `ListQuotasRequest.pageToken` | model.ts:46 | — | -| `QuotaInfo` | model.ts:60 | M1, O1 | -| `QuotaInfo.parentSecurableType` (`SecurableType`) | model.ts:62 | H2 | -| `QuotaInfo.parentFullName` | model.ts:64 | — | -| `QuotaInfo.quotaName` | model.ts:66 | — | -| `QuotaInfo.quotaCount` | model.ts:68 | — | -| `QuotaInfo.quotaLimit` | model.ts:70 | — | -| `QuotaInfo.lastRefreshedAt` | model.ts:72 | — | -| `Client` (bare name) | client.ts:37 | L2 | -| `Client.getQuota` parameter `req` | client.ts:68 | L1 | -| `Client.listQuota` (singular method) | client.ts:98 | H1, L1 | -| `Client.listQuotaIter` (singular paginator method) | client.ts:131-146 | H1, L1 | - ---- - -## Recommended priority order - -1. **Rename `listQuota` → `listQuotas`** — single-character defect, highest user impact. (H1) -2. **Reconcile `parentSecurableType` type — make `GetQuotaRequest.parentSecurableType: SecurableType`.** (H2) -3. **Drop `Info` suffix on `QuotaInfo`.** (M1, O1) -4. **Spell out `req` → `request` (repo-wide policy).** (L1) - ---- diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index 070eed42..5db2e990 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -1,139 +1,69 @@ # Naming Audit: rfa -**Path:** `packages/rfa/src/v1/` +**Path:** `packages/uc/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 16 +**Total weird names flagged:** 9 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 9 | -| Low | 1 | +| High | 1 | +| Medium | 6 | | Observation | 2 | ## High severity -### 1. Package name `rfa` — `packages/rfa/`, `.package.json:2`, `client.ts:78,117,151` -- **Why weird:** Three-letter cryptic acronym used as the npm package name (`@databricks/sdk-rfa`), the package directory, the import path (`packages/rfa/src/v1/`), and the URL segment (`/api/3.0/rfa/...`). Nothing in the source files spells out what `rfa` stands for — no doc comment, no README description (`package.json` description is empty string), no module-level JSDoc in `index.ts`. From the model alone, the user has to reverse-engineer that `rfa` means "Request For Access" by reading the type names (`CreateAccessRequest`, `AccessRequestDestinations`). The Databricks Go SDK (`databricks/sdk-go`) does not yet contain this code path either — there's no upstream reference. +### 1. Package name `rfa` — `packages/uc/rfa/`, `package.json:2`, `client.ts:80,122,159` +- **Why weird:** Three-letter cryptic acronym used as the npm package name (`@databricks/sdk-uc-rfa`), the package directory, the import path (`packages/uc/rfa/src/v1/`), and the URL segment (`/api/3.0/rfa/...`). Nothing in the source files spells out what `rfa` stands for — no doc comment, no README description (`package.json` description is empty string), no module-level JSDoc in `index.ts`. From the model alone, the user has to reverse-engineer that `rfa` means "Request For Access" by reading the type names (`CreateAccessRequest`, `AccessRequestDestinations`). The Databricks Go SDK (`databricks/sdk-go`) does not yet contain this code path either — there's no upstream reference. - **Category:** 5 (cryptic abbreviation), 1 (vague). -- **Suggested name:** `accessrequests` or `accessrequestdestinations`. The npm package would be `@databricks/sdk-accessrequests`. The wire URL `/api/3.0/rfa/...` can stay locked while the SDK surface uses the spelled-out name. -- **Rationale:** TS SDK names are user-typed in import statements (`import {Client} from '@databricks/sdk-rfa/v1';`). A user reading that import line has no way to guess the package's purpose. Compare to neighbour packages — `abacpolicies`, `accountaccesscontrol`, `alerts`, `cleanrooms`, `gitcredentials` — all spell out the domain. `rfa` is the only opaque acronym among ~70 packages. - -### 2. `DestinationType.URL` — `model.ts:13` -- **Why weird:** `URL` collides with the JavaScript built-in global `URL` (the WHATWG URL class). The enum member is therefore syntactically `DestinationType.URL` which is fine, but importing/destructuring is error-prone (`const {URL} = DestinationType` would shadow the global). Worse, the value `'URL'` is a misleading category — `DestinationType.URL` is documented as a webhook delivery to an arbitrary URL, but `DestinationType.GENERIC_WEBHOOK` is *also* a delivery to a URL. The semantic difference between `URL` and `GENERIC_WEBHOOK` is invisible from the names. -- **Category:** 10 (reserved-word/global collision), 6 (misleading — two members both denote webhook-URL deliveries). -- **Suggested name:** Rename `URL` to `URL_NOTIFICATION` or `PLAIN_URL`, or rename `GENERIC_WEBHOOK` to clarify what makes it "generic" relative to `URL`. Document the wire-level difference between the two. -- **Rationale:** Two enum members for "send to a URL" is a discoverability bug. Future callers will guess one and silently get the wrong webhook semantics. - -### 3. `AccessRequestDestinations.securableType` and `fullName` duplicate `securable.type` and `securable.fullName` — `model.ts:54-73` -- **Why weird:** `AccessRequestDestinations` has both: - - `securable?: Securable` (which has `type` and `fullName`), and - - top-level `securableType?: string` and `fullName?: string`. - The inline JSDoc says "Redundant with the type in the securable object, but necessary for Terraform integration" and "Redundant with the name in the securable object, but necessary for Terraform integration". Three problems: - 1. Two fields hold the same data — easy to set inconsistently (`securable.type === 'CATALOG'` while `securableType === 'TABLE'`). - 2. The redundant `securableType` is typed `string` while `securable.type` is typed `SecurableType` — *different types* for the same data. - 3. The reason ("Terraform integration") is implementation detail leaking onto the public SDK surface for every non-Terraform caller. -- **Category:** 12 (duplicate concepts), 6 (misleading — which one is authoritative?), 16 (type contradiction: `string` vs enum `SecurableType`). -- **Suggested name:** Drop `securableType` and `fullName` from `AccessRequestDestinations` for non-Terraform callers; expose them under a `terraformShim` namespace if needed, or model with `Pick`/conditional types. Wire stays unchanged. -- **Rationale:** Two-field duplication invites bugs (a caller might set one and not the other). The "necessary for Terraform integration" rationale is exactly the kind of generator artefact that should not surface here. - -### 4. `GetAccessRequestDestinationsRequest.securableType` typed as `string` — `model.ts:121-126` -- **Why weird:** The request type for `getAccessRequestDestinations` has `securableType?: string`, but the response type `AccessRequestDestinations` has `securable?: { type?: SecurableType }` — a typed enum. So the request is untyped string, while the response is enum. A caller writing `req.securableType = 'catalogue'` (typo or wrong case) gets no compile-time error. -- **Category:** 16 (field type contradicts domain — should be `SecurableType`), 6 (misleading — looks like free text but server demands an enum value). -- **Suggested name:** Keep name, change type to `SecurableType`. -- **Rationale:** Same data model, two field types. Type narrowing is the whole point of TS — losing it on the request side is a regression. +- **Suggested name:** `accessrequests` or `accessrequestdestinations`. The npm package would be `@databricks/sdk-uc-accessrequests`. The wire URL `/api/3.0/rfa/...` can stay locked while the SDK surface uses the spelled-out name. +- **Rationale:** TS SDK names are user-typed in import statements (`import {RfaClient} from '@databricks/sdk-uc-rfa/v1';`). A user reading that import line has no way to guess the package's purpose. Compare to neighbour packages — `abacpolicies`, `accountaccesscontrol`, `alerts`, `cleanrooms`, `gitcredentials` — all spell out the domain. `rfa` is the only opaque acronym among ~70 packages. ## Medium severity -### 5. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` +### 2. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` - **Why weird:** The type is plural (`Destinations`) but each instance describes the destinations *for one securable* (`securable?: Securable`, singular). The plural belongs only to the inner `destinations?: NotificationDestination[]` array. Compare: `AccessRequestDestination` (singular) would describe one route; `AccessRequestDestinations` (plural) implies multiple route configs. The current name is the latter but holds the former. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `AccessRequestRouting` or `AccessRequestDestinationConfig` (singular) — captures "the routing configuration for one securable". - **Rationale:** The pluralization is for the inner array, not the outer concept. Today the type-name reader gets the wrong mental model. -### 6. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` +### 3. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` - **Why weird:** Verbose type names (32 / 33 chars). `Batch` + `Create` + `AccessRequests` + `Request`/`Response`. Also: `Batch` prefix is the *only* signal that the endpoint accepts an array — but the client method is just `batchCreateAccessRequests`, and the field inside is `requests?: CreateAccessRequest[]`. Three levels of "batchness". - **Category:** 7 (overly verbose), 8 (redundant suffix `Request`). - **Suggested name:** `CreateAccessRequestsRequest` (drop `Batch`; the plural already implies batching). Or even better: `CreateAccessRequestsInput` / `CreateAccessRequestsOutput`. Pair with method `createAccessRequests`. - **Rationale:** `Batch` doubles as marketing copy ("look, batched!") rather than naming. TS plural-`s` already says "multiple". -### 7. `CreateAccessRequest.securablePermissions` is array but bare `securable` siblings are singular — `model.ts:111` +### 4. Type name `SecurablePermissions` is plural but models ONE securable + its permissions — `model.ts:173-178` - **Why weird:** `CreateAccessRequest` has `securablePermissions?: SecurablePermissions[]` (plural array, type `SecurablePermissions` itself plural). `SecurablePermissions` holds `securable: Securable` (singular) and `permissions: string[]` (plural). So `request.securablePermissions[0].securable` reads as "the singular securable inside the plural securable-permissions". The type name `SecurablePermissions` doesn't say "pairs of securable + permissions list". - **Category:** 9 (singular/plural mismatch), 1 (vague — what does `SecurablePermissions` model?). -- **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). Field becomes `securablePermissionRequests?: SecurablePermissionRequest[]` — long but readable. +- **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). - **Rationale:** The type-name pluralization is hiding what the type actually models (one securable + a permissions list). -### 8. `NotificationDestination.specialDestination` overloads with `destinationType` — `model.ts:136-142` -- **Why weird:** A single `NotificationDestination` has both `destinationType?: DestinationType` and `specialDestination?: SpecialDestination`. The doc says `specialDestination`'s `destination_type` is "always EMAIL". So we have two enums that *cannot both be expressive at once* — if `specialDestination` is set, `destinationType` is constrained to `EMAIL`. The type system doesn't enforce this. -- **Category:** 12 (duplicate concept — two enums encode overlapping info), 6 (misleading — looks like independent fields). -- **Suggested name:** Either (a) collapse: extend `DestinationType` with new members and drop `SpecialDestination`; or (b) model as a discriminated union: `{ kind: 'normal'; destinationType, destinationId } | { kind: 'special'; specialDestination }`. -- **Rationale:** Two parallel enums for a constrained relationship is exactly the kind of latent-bug field name pair that a strict type system can prevent. - -### 9. `Principal.id` is bare `id` — but holds either user, group, or service principal ID — `model.ts:145-149` -- **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape is fine, but the bare `id` doesn't communicate "the meaning depends on `principalType`". +### 5. `Principal` shape — bare `id` whose meaning depends on a sibling `principalType` — `model.ts:145-149` +- **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape couples two fields that the type system leaves independent. - **Category:** 19 (underspecified ID), 1 (vague). -- **Suggested name:** Keep `id` paired with `principalType`, OR (more aggressive) make the type a discriminated union: `{ kind: 'user'; userId: string } | { kind: 'group'; groupId: string } | { kind: 'service'; servicePrincipalId: string }`. +- **Suggested name:** Reshape `Principal` into a discriminated union keyed on the principal kind so the type system enforces "this ID belongs to this principal type", rather than two loosely-coupled optional fields. - **Rationale:** Tagged unions express the constraint at the type level. The current shape is a Go-port idiom. -### 10. `SecurableType.STAGING_TABLE` and inline TODO — `model.ts:41-42` -- **Why weird:** Enum value pinned by inline TODO: `/** TODO: [UC-2980] Staging tables aren't full-fleged securables yet. */`. The TODO leaks an internal JIRA ticket (`UC-2980`) and the typo "full-fleged" into the public SDK surface. The presence of the value tells callers it works; the comment tells them it doesn't. -- **Category:** 18 (questionable enum value). -- **Suggested name:** Either hide until promotion (`@experimental`), or remove the inline TODO and document the constraint in the doc-comment proper. -- **Rationale:** Public SDK enums shouldn't carry internal JIRA references. Same pattern as `connections#29` and `dataclassification`. - -### 11. `SecurablePermissions.permissions: string[]` — `model.ts:173-178` -- **Why weird:** `permissions` is `string[]` rather than an enum. Doc says "List of requested Unity Catalog permissions" — UC permissions are a known closed set (`SELECT`, `MODIFY`, `USAGE`, `READ_VOLUME`, etc.), so this should be a typed enum or branded string. Bare `string[]` loses any compile-time guard against typos. -- **Category:** 16 (field type contradicts domain — should be enum or branded string). -- **Suggested name:** Keep name; type as `UnityCatalogPermission[]` (new enum). Or document the closed set inline. -- **Rationale:** Same problem as #4. The wire is string, but TS could narrow it. - -### 12. Method `batchCreateAccessRequests` on `Client` — `client.ts:74` +### 6. Method `batchCreateAccessRequests` on `RfaClient` — `client.ts:76` - **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. - **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). - **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). - **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. -### 13. Three Client methods, three different domain entity names — `client.ts:74,113,147` -- **Why weird:** `Client.batchCreateAccessRequests` works on `requests`. `Client.getAccessRequestDestinations` works on `destinations`. `Client.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. +### 7. Three RfaClient methods, three different domain entity names — `client.ts:76,118,155` +- **Why weird:** `RfaClient.batchCreateAccessRequests` works on `requests`. `RfaClient.getAccessRequestDestinations` works on `destinations`. `RfaClient.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. - **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). - **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). - **Rationale:** A class with three methods that cover two disjoint resources is hiding the resource boundary. -## Low severity - -### 14. `Client` class — `client.ts:40` -- **Why weird:** Top-level class literally named `Client`. Re-exported through `index.ts` as just `Client`. Two RFA packages co-existing in user code would clash on import (`import {Client} from '@databricks/sdk-rfa/v1'` vs `import {Client} from '@databricks/sdk-accounts/v1'`). -- **Category:** 1 (vague). -- **Suggested name:** `RfaClient` or `AccessRequestClient` (better — see #1). -- **Rationale:** Same finding as `dataclassification`. Recurs across all generated packages. - ## Observations -### 15. Comment-tag inconsistency — `client.ts:78,117,151` vs URL +### 8. Comment-tag inconsistency — `client.ts:80,122,159` vs URL The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. - **Category:** Observation. -### 16. Action-verb conventions on `Client` -`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #13). +### 9. Action-verb conventions on `RfaClient` +`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #7). - **Category:** Observation. - -## Domain glossary -- **`rfa`** — **R**equest **F**or **A**ccess. The Databricks Unity Catalog API for managing access-request notifications to UC securables. There are two distinct concerns: - 1. **Access Requests** (`POST /api/3.0/rfa/requests`) — a *user* (or principal on whose behalf) is requesting permissions (`SELECT`, `MODIFY`, etc.) on a list of Unity Catalog securables (catalogs, schemas, tables, etc.). The response tells the caller *where* the request was routed (which destinations). - 2. **Access Request Destinations** (`GET`/`PATCH /api/3.0/rfa/destinations/...`) — administrative configuration of *which* destinations (email addresses, Slack channels, MS Teams webhooks, generic webhooks, URLs) receive notifications when end-users file an access request against a given securable. -- **`uc`** — Unity Catalog. Referenced indirectly in `CreateAccessRequest` doc comments ("requested UC privileges"). Not in field names. -- **`d2d`** — Delta-to-Delta (Delta Sharing peer-to-peer). Appears in `Securable.providerShare` doc comment ("D2D Delta Sharing"). Not expanded inline. -- **`UC-2980`** — internal JIRA ticket referenced in `SecurableType.STAGING_TABLE` TODO comment. Should not appear on public SDK surface. -- **`Securable`** — Unity Catalog term-of-art for any object that can be granted permissions: catalog, schema, table, view, volume, function, model, connection, credential, external location, share, recipient, clean-room, metastore, pipeline, external-metadata, staging-table. The full taxonomy lives in `SecurableType` (17 values incl. sentinel). -- **`Principal`** — Unity Catalog/IAM term for "an entity that can hold permissions": a user, a group, or a service principal. The `PrincipalType` enum disambiguates which kind. Used here as the "on behalf of" actor in `CreateAccessRequest`. -- **`SpecialDestination`** — five enum members denoting "the owner of the metastore/catalog/external-location/connection/credential" as an implicit email destination. These cannot be assigned; they're a default fallback. -- **`FieldMask`** — Google protobuf convention (re-used in Databricks API) for sparse-field updates in PATCH semantics. `accessRequestDestinationsFieldMask(...)` builds the wire-format paths. -- Inferred but not in source: **`Terraform integration`** — appears in `AccessRequestDestinations.securableType` doc, suggests the redundant string fields exist because the Terraform provider can't read nested struct field types (see finding #3). - -## File coverage -- `src/v1/model.ts` (385 lines): read fully. -- `src/v1/client.ts` (187 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (24 lines): read fully. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index 46b05ac4..694e9270 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -1,99 +1,25 @@ # Naming Audit: `schemas` package (v1) -**Package path:** `/home/parth.bansal/sdk-js/packages/schemas/` +**Package path:** `/home/parth.bansal/sdk-js/packages/uc/schemas/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` **Domain:** Unity Catalog (UC) — schemas (the level beneath catalogs, parents of tables/views/functions). --- -## Summary - -The `schemas` package exposes the standard five UC schema operations -(`createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, -`updateSchema`). The package is small (one -enum, one nested-flag type, the schema info type, five request types, -two response types). Because it is a 1:1 -port of the Go SDK, most issues are inherited from upstream proto -definitions: the most pervasive problems are (1) `fullNameArg` as a -cryptic path parameter that coexists with `fullName` on the same type -and (2) `CreateSchemaRequest`/`UpdateSchemaRequest` carrying read-only -server-populated fields. There is also significant -duplicate-concept overlap with the sibling `systemschemas` package -(separate types `SchemaInfo` vs `SystemSchemaInfo`, separate clients, -separate methods) that the audit calls out at the package boundary. - ---- - ## Findings -### 1. Vague / generic names - -_None._ - ---- - -### 2. Acronym casing inconsistencies - -_None._ - ---- - -### 3. Cryptic abbreviations - -#### 3.1 `fullNameArg` (model.ts:71, 90, 180) -Path-parameter field on `DeleteSchemaRequest`, `GetSchemaRequest`, and -`UpdateSchemaRequest`. The `Arg` suffix is Go-generator jargon -distinguishing path arguments from request-body fields with the same -key. TypeScript callers have no need for this distinction — the field -*is* the schema identifier and should just be `fullName` (or `name`). -Even worse: `UpdateSchemaRequest` has *both* `fullNameArg` (path) and -`fullName` (body) on the same type, with no obvious difference in -semantics. See §10.1. - ---- - -### 4. Misleading names - -#### 4.1 `EffectivePredictiveOptimizationFlag.value` is a tri-state encoded as `string` (model.ts:81) -Field is typed `string | undefined` but the doc comment ("Whether -predictive optimization should be enabled…") implies a small discrete -set of values (enable / disable / inherit). The type should be an -enum rather than `string`. - -#### 4.2 `SchemaInfo.fullName` corresponds with `name` + `catalogName` (model.ts:140) -The doc is honest: "Full name of schema, in form of -__catalog_name__.__schema_name__". But the field name `fullName` -suggests it might carry additional information not available from -`name`+`catalogName`. It doesn't. See also §8.2. - -#### 4.3 `SchemaInfo.options` vs `SchemaInfo.properties` (model.ts:161-163) -Both are `Record` with identical doc comments ("A map -of key-value properties attached to the securable."). There is no way -for a caller to know which to use for what. The doc duplication recurs -verbatim in `CreateSchemaRequest` (model.ts:51-54) and -`UpdateSchemaRequest` (model.ts:218-221). Either is underspecified or -one of them is redundant. See §8.1. - ---- +### 1. Overly verbose -### 5. Overly verbose - -#### 5.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) -39 characters. Compounded by `effectivePredictiveOptimizationFlag` as -a field name on three different request/response shapes (model.ts:44, -153, 211). Consider `EffectivePredictiveOptimization` (drop the +#### 1.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) +39 characters. Consider `EffectivePredictiveOptimization` (drop the `Flag` suffix — the type already wraps the flag) or -`EffectivePOSetting` if shortening is acceptable. See also §6.2. - -#### 5.2 `enablePredictiveOptimization: string` (model.ts:27, 136, 194) -Long field name for what is effectively a flag value. Acceptable, but -pairs with §5.1 to make every schema shape verbose. +`EffectivePOSetting` if shortening is acceptable. See also §2.2. --- -### 6. Redundant suffixes +### 2. Redundant suffixes -#### 6.1 `SchemaInfo` type name (model.ts:124) +#### 2.1 `SchemaInfo` type name (model.ts:123) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from a resource handle; in TS the convention is to drop it (`Schema`). Compare with `Catalog`, `Table`, @@ -102,95 +28,39 @@ collides with the zod artifact `Schema` (a runtime validator type in common use across the JS ecosystem) — the rename must consider that collision before landing. -#### 6.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) -The whole type *is* the flag; the suffix is redundant. See §5.1. - -#### 6.3 `Arg` suffix on `fullNameArg` — see §3.1 and §10.1. +#### 2.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) +The whole type *is* the flag; the suffix is redundant. See §1.1. --- -### 7. Reserved-word collisions +### 3. Reserved-word collisions -#### 7.1 `options` field on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` (model.ts:54, 163, 221) +#### 3.1 `options` field on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` (model.ts:54, 162, 220) `options` collides with the SDK's own `CallOptions` parameter name -used throughout the client (`createSchema(req, options)`, client.ts:74, +used throughout the client (`createSchema(req, options)`, client.ts:77, etc.). Not a compile error but creates cognitive load — inside `createSchema(req, options)` the reader sees both `req.options` (schema metadata) and `options` (call options). The cleanest fix is to -rename the client parameter to `callOptions`. See also §8.1 for the -duplicate-with-`properties` concern. +rename the client parameter to `callOptions`. -#### 7.2 `properties` is not reserved but conflicts with `Object` semantics -`SchemaInfo.properties` (model.ts:161) is fine but worth noting that +#### 3.2 `properties` is not reserved but conflicts with `Object` semantics +`SchemaInfo.properties` (model.ts:160) is fine but worth noting that `properties` is a heavily-overloaded term in JS (object properties, -descriptor properties, etc.). Combined with the duplicate-with-`options` -problem in §8.1, the name is doubly overloaded. - ---- - -### 8. Duplicate concepts - -#### 8.1 `properties` vs `options` (model.ts:51-54, 161-163, 218-221) -Both `Record` on every schema shape, with identical -doc comments ("A map of key-value properties attached to the -securable."). Either the documentation needs to differentiate them or -one is redundant. See also §4.3. - -#### 8.2 `name` vs `fullName` on `SchemaInfo` (model.ts:126, 140) -`name` is the schema name "relative to parent catalog"; `fullName` is -"in form of __catalog_name__.__schema_name__". These two fields are -deterministically derivable from each other (given `catalogName`). -Mirror issue in `CreateSchemaRequest` (model.ts:17, 31) and -`UpdateSchemaRequest` (model.ts:184, 198). See also §4.2. - -#### 8.3 `fullName` vs `fullNameArg` on `UpdateSchemaRequest` (model.ts:180, 198) -The `UpdateSchemaRequest` has **both** `fullNameArg` (the existing -schema identifier, path param) and `fullName` (the same field name on -the body) — plus `newName` for renaming. Three fields all touching -the schema's identity. See §10.1. - -#### 8.4 `CatalogType` is re-implemented across packages -The exact `CatalogType` enum is defined here -(model.ts:6-13) and also in `catalogs` (and likely in several other UC -packages). A consumer touching both packages gets two unrelated TS -types named `CatalogType`. Cross-package duplication — flagged in -this audit for the broader review. - -#### 8.5 `EffectivePredictiveOptimizationFlag` may be duplicated -This type is identical to the one in `catalogs` (and probably in any -UC securable package). Cross-package duplication. - -#### 8.6 `CreateSchemaRequest`, `UpdateSchemaRequest`, and `SchemaInfo` share ~21 fields verbatim -All three types are 95% identical with identical doc strings. This is -a generator artefact, but any rename of `storageRoot` must happen in -three places. Recommend basing `CreateSchemaRequest`/`UpdateSchemaRequest` -on `Partial` or a shared `SchemaProperties` mixin. - -#### 8.7 Overlap with `systemschemas` package -The sibling `systemschemas` package operates on a completely different -shape (`SystemSchemaInfo` has only `schema` and `state` — no overlap -with `SchemaInfo`). Same noun, different types, different clients, -different methods. A consumer might reasonably expect one client to -handle both kinds of schemas; instead they must import two packages. -At minimum, the type names should be sufficiently distinguishable — -`SchemaInfo` vs `SystemSchemaInfo` is fine, but the *package* names -(`@databricks/sdk-schemas` vs `@databricks/sdk-systemschemas`) are -trap-shaped: a consumer who imports the first expecting "all schemas" -will be surprised to find that system schemas live elsewhere. +descriptor properties, etc.), making the name overloaded. --- -### 9. Verb-tense inconsistency +### 4. Verb-tense inconsistency -#### 9.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. +#### 4.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. No verb-tense inconsistencies found across the package. --- -### 10. Field contradicting type domain +### 5. Field contradicting type domain -#### 10.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:180, 184, 198, 182) +#### 5.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:179, 183, 197, 181) Four name-bearing fields on a single update request: - `fullNameArg` — existing schema identifier (path param). @@ -204,22 +74,17 @@ identifying the existing schema; the others are vestigial in the update context.) This is the single most user-hostile naming pattern in the package — and it sits on the most-used mutation method. -#### 10.2 `CreateSchemaRequest` contains read-only output fields (model.ts:32-50) +#### 5.2 `CreateSchemaRequest` contains read-only output fields (model.ts:32-50) `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `catalogType`, `effectivePredictiveOptimizationFlag`, `schemaId`, `browseOnly`. These are server-populated; a creator setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Same mirror issue in -`UpdateSchemaRequest` (model.ts:199-217). - -#### 10.3 `DeleteSchemaRequest.fullNameArg` — see §3.1. - -#### 10.4 `GetSchemaRequest.fullNameArg` (model.ts:90) -Same as 10.3. +`UpdateSchemaRequest` (model.ts:198-216). --- -### 11. Inconsistent action verbs +### 6. Inconsistent action verbs Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`. Verbs are consistent — standard CRUD. @@ -227,60 +92,35 @@ No `fetch…` / `retrieve…` / `read…` outliers. No issues found. --- -### 12. Underspecified IDs +### 7. Underspecified IDs -#### 12.1 `schemaId` (model.ts:48, 157, 215) +#### 7.1 `schemaId` (model.ts:48, 156, 214) "The unique identifier of the schema." No format hint (UUID?). The field exists alongside `fullName` (which is also a unique identifier in a different sense). Two simultaneous IDs without disambiguation. -#### 12.2 `inheritedFromType` / `inheritedFromName` on `EffectivePredictiveOptimizationFlag` (model.ts:83, 85) -Both `string`. `inheritedFromType` could be one of the UC securable -types, but the field is not enum-typed. `inheritedFromName` is opaque -text. - --- -### 13. Type-suffix tautology +### 8. Type-suffix tautology -#### 13.1 `CatalogType` enum with field `catalogType: CatalogType` -(model.ts:6, 41, 150, 208) — field name tautological with type name. +#### 8.1 `CatalogType` enum with field `catalogType: CatalogType` +(model.ts:6, 41, 149, 207) — field name tautological with type name. Defensible (field carries the dynamic value) but worth flagging. -#### 13.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. - ---- - -### 14. Generic field names losing meaning - -#### 14.1 `properties`, `options` (model.ts:51, 53, 161, 163, 218, 220) — see §4.3, §8.1. +#### 8.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. --- -### 15. Singular / plural mismatches - -_None._ - ---- - -### 16. Go / Java-style names - -#### 16.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) -Java/Go style. TS convention is to drop it. See §6.1. - -#### 16.2 `Client` class name (client.ts:44) -Bare `Client` (rather than `SchemasClient`) is a Go-idiom: package -qualifies the type. JS consumers commonly import as -`import {Client} from '@databricks/sdk-schemas/v1'` and have to alias. -Package-wide convention; flagged for the broader review. +### 9. Go / Java-style names -#### 16.3 `fullNameArg` — Go-generator naming. See §3.1. +#### 9.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +Java/Go style. TS convention is to drop it. See §2.1. --- -### 17. Proto-architectural-leak naming +### 10. Proto-architectural-leak naming -#### 17.1 `EffectivePredictiveOptimizationFlag` — `Flag` wrapper suffix (model.ts:79) +#### 10.1 `EffectivePredictiveOptimizationFlag` — `Flag` wrapper suffix (model.ts:79) - **Why:** The type is a proto-style wrapper around a tri-state value (`value`, `inheritedFromType`, `inheritedFromName`). `Flag` is a proto-wrapper marker that leaks the upstream message-modeling pattern @@ -288,23 +128,11 @@ Package-wide convention; flagged for the broader review. setting; `Flag` adds no semantic content. - **Category:** `Wrapper`/`Adapter` suffix (proto wrapper pattern). - **Suggested:** `EffectivePredictiveOptimization` (or, combined with - §5.1, `PredictiveOptimization`). + §1.1, `PredictiveOptimization`). - **Rationale:** TS callers care about the value and its inheritance source; the wrapper-ness is an implementation detail of the proto schema, not part of the domain vocabulary. -#### 17.2 `effectivePredictiveOptimizationFlag` field — `Flag` wrapper infix (model.ts:44, 153, 211) -- **Why:** Same proto-wrapper leak repeated as a field name on three - shapes (`CreateSchemaRequest`, `SchemaInfo`, `UpdateSchemaRequest`). - 35-character field name whose `Flag` segment exists only to mirror - the wrapper type. -- **Category:** `Wrapper`/`Adapter` infix (proto wrapper pattern). -- **Suggested:** `effectivePredictiveOptimization` (or - `predictiveOptimization`). -- **Rationale:** Field name should describe the domain concept - (predictive-optimization setting), not the proto modelling choice - (wrapping the setting in a `*Flag` message). - --- ## Additional / cross-cutting observations @@ -316,70 +144,3 @@ The package is `schemas` (plural); the model types are `Schema` (well, they act on one) and `listSchemas` (plural — returns many). This is the same pattern as `catalogs`, `tables`, etc. — consistent across the SDK. - -### B. `enablePredictiveOptimization` is typed `string` not `boolean` (model.ts:27, 136, 194) -The field name says "enable" — suggesting boolean — but the type is -`string`. The actual value is presumably `'ENABLE' | 'DISABLE' | -'INHERIT'` or similar. The name lies about the type. See also §4.1 -for the related `EffectivePredictiveOptimizationFlag.value`. - -### C. Overlap with `systemschemas` package — see §8.7 -A consumer reading "schemas" reasonably expects to find all schema -operations here. They will not find `disableSystemSchema`, -`enableSystemSchema`, or `listSystemSchemas` — those live in -`@databricks/sdk-systemschemas`. Package boundaries follow the -upstream API surface, but the seam is non-obvious to discover. - ---- - -## File / line index for fast lookup - -| Identifier | Location | Finding | -| ----------------------------------------------------------- | --------------------- | -------------------- | -| `CatalogType` | model.ts:6 | 8.4, 13.1 | -| `CreateSchemaRequest` | model.ts:15 | 8.6, 10.2 | -| `CreateSchemaRequest.name` | model.ts:17 | 8.2 | -| `CreateSchemaRequest.catalogType` | model.ts:41 | 13.1 | -| `CreateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:44 | 5.1, 17.2 | -| `CreateSchemaRequest.properties` / `.options` | model.ts:52, 54 | 4.3, 7.1, 8.1, 14.1 | -| `DeleteSchemaRequest` | model.ts:69 | 10.3 | -| `DeleteSchemaRequest.fullNameArg` | model.ts:71 | 3.1, 10.3, 16.3 | -| `EffectivePredictiveOptimizationFlag` | model.ts:79 | 5.1, 6.2, 16.1, 17.1 | -| `EffectivePredictiveOptimizationFlag.value` | model.ts:81 | 4.1 | -| `EffectivePredictiveOptimizationFlag.inheritedFromType` | model.ts:83 | 12.2 | -| `EffectivePredictiveOptimizationFlag.inheritedFromName` | model.ts:85 | 12.2 | -| `GetSchemaRequest.fullNameArg` | model.ts:90 | 3.1, 10.4, 16.3 | -| `ListSchemasRequest` | model.ts:95 | — | -| `ListSchemasRequest.maxResults` | model.ts:105 | — | -| `ListSchemasRequest.pageToken` | model.ts:107 | — | -| `ListSchemasRequest.includeBrowse` | model.ts:109 | — | -| `SchemaInfo` | model.ts:124 | 6.1, 8.6, 16.1 | -| `SchemaInfo.name` | model.ts:126 | 8.2 | -| `SchemaInfo.fullName` | model.ts:140 | 4.2, 8.2 | -| `SchemaInfo.catalogType` | model.ts:150 | 13.1 | -| `SchemaInfo.effectivePredictiveOptimizationFlag` | model.ts:153 | 5.1, 17.2 | -| `SchemaInfo.schemaId` | model.ts:157 | 12.1 | -| `SchemaInfo.properties` / `.options` | model.ts:161, 163 | 4.3, 7.1, 8.1, 14.1 | -| `UpdateSchemaRequest` | model.ts:178 | 8.3, 8.6, 10.1, 10.2 | -| `UpdateSchemaRequest.fullNameArg` | model.ts:180 | 3.1, 8.3, 10.1, 16.3 | -| `UpdateSchemaRequest.newName` | model.ts:182 | 10.1 | -| `UpdateSchemaRequest.name` | model.ts:184 | 8.2, 10.1 | -| `UpdateSchemaRequest.fullName` | model.ts:198 | 8.2, 8.3, 10.1 | -| `UpdateSchemaRequest.effectivePredictiveOptimizationFlag` | model.ts:211 | 5.1, 17.2 | -| `enablePredictiveOptimization` (string-typed bool) | model.ts:27, 136, 194 | B | -| `Client` (bare name) | client.ts:44 | 16.2 | -| Cross-package overlap with `systemschemas` | (package boundary) | 8.7, C | - ---- - -## Recommended priority order - -1. **Fix `fullNameArg` / `fullName` / `name` / `newName` on `UpdateSchemaRequest`** — four name-like fields on the same request, the worst user-facing trap in the package. (§10.1, §3.1, §8.3) -2. **Distinguish or merge `options` and `properties`.** (§8.1, §4.3) -3. **Type `enablePredictiveOptimization` and `EffectivePredictiveOptimizationFlag.value` honestly** — either enum or boolean, not `string`. (§4.1, B) -4. **Strip read-only fields from `CreateSchemaRequest`/`UpdateSchemaRequest`.** (§10.2) -5. **Disambiguate `schemaId` vs `fullName` as identifiers** — document which is canonical. (§12.1, §8.2) -6. **Resolve the `Schema` vs zod `Schema` collision before renaming `SchemaInfo` to `Schema`.** (§6.1) -7. **Decide cross-package strategy with `systemschemas`** — at minimum document the seam. (§8.7, C) - ---- diff --git a/.agent/naming-audit/scim.md b/.agent/naming-audit/scim.md index 45f9a0fd..461437f5 100644 --- a/.agent/naming-audit/scim.md +++ b/.agent/naming-audit/scim.md @@ -3,15 +3,15 @@ **Path:** `packages/scim/src/v1/` **Versions audited:** v1 **Inferred domain:** SCIM (System for Cross-domain Identity Management, RFC 7644) — workspace and account user, service principal, and group provisioning, plus password permissions. `SCIM` itself is an industry-standard protocol acronym and is treated as a domain word. -**Total weird names flagged:** 10 +**Total weird names flagged:** 5 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 3 | +| High | 1 | +| Medium | 2 | | Low | 1 | -| Observation | 2 | +| Observation | 1 | ## High severity @@ -21,47 +21,23 @@ - **Suggested name:** Collapse to a single `SortOrder` enum (shared across get/list and account/workspace variants); rename `PasswordPermission_Level` to `PasswordPermissionLevel`. The whole `_` shape is a proto artifact that should not survive code generation. - **Rationale:** TypeScript has structural typing and module-scoped names; there is no value collision to resolve. The disable comment is a clue that the generator is fighting the language. -### 2. Empty placeholder interfaces for proto-nesting parents — `src/v1/model.ts:109,132,151,154,404,412,619` -- **Why weird:** Seven `export interface`s are wholly empty (`{}`), each suppressed by `// eslint-disable-next-line @typescript-eslint/no-empty-object-type`: `AccountGetSortOrder`, `AccountListSort`, `AccountPatchOp`, `AccountPatchSchema`, `GetPasswordPermissionLevelsRequest`, `GetPasswordPermissionsRequest`, and `ListSort`. The first four and `ListSort` exist only because the enum was nested inside a proto message — the message itself has no fields, so the TypeScript type carries no information. The two `Get…Request` empties are RPC-shape placeholders for an HTTP GET that takes no body and no path params; they survive as exports despite carrying zero schema. A leading JSDoc on `AccountListSort` and `ListSort` explicitly says "ListSortOrder and GetSortOrder share enum values, which is not supported. We use nesting as a workaround." — i.e. the comment names the proto restriction it works around. -- **Category:** Proto-architecture leak -- **Suggested name:** Delete all seven exports. The empty-body `Get…PermissionLevelsRequest` / `Get…PermissionsRequest` methods should take no argument (or take `CallOptions` only). The five enum-parent interfaces should disappear once the enums are flattened (see finding 1). -- **Rationale:** Public empty interfaces are pure proto/RPC plumbing; they expose generator structure as API surface and force consumers to either pass `{}` or define a variable they cannot meaningfully populate. - -### 3. `Account*` mid-position duplicate type families — `src/v1/model.ts:100,111,134,141,156,161,177,205,220,236,317,325,333,359,367,375,460,479,491,510,522,541,722,732,742,800,815,831` -- **Why weird:** The package exports two parallel families of identical-shape types distinguished only by an `Account` prefix: `ComplexValue` vs `AccountComplexValue`, `Name` vs `AccountName`, `ResourceMeta` vs `AccountResourceMeta`, `Patch` vs `AccountPatch`, `Group` vs `AccountGroup`, `User` vs `AccountUser`, `ServicePrincipal` vs `AccountServicePrincipal`, and the corresponding `Create/Update/Patch/Delete/Get/List…Request`/`…Response` quartets. The shapes are almost identical (compare `User` lines 911-932 to `AccountUser` lines 177-195 — same fields, plus `accountId`); the divergence is one extra optional `accountId` and the absence of a few workspace-only entitlements. The `Account` prefix is mid-position in the larger compound names (`CreateAccountUserRequest`, `PatchAccountGroupRequest`, `ListAccountServicePrincipalsResponse`) — a classic proto package-namespace leak where the same message was redefined under `databricks.scim.account.v1` and `databricks.scim.workspace.v1`. -- **Category:** Proto-architecture leak -- **Suggested name:** Either (a) unify into one type with an optional `accountId` field and one method surface that switches on whether `accountId` is present, or (b) split into two sub-namespaces (`scim.account.User`, `scim.workspace.User`) so the prefix is not embedded in the name. The current shape doubles the type-export count without doubling the information. -- **Rationale:** This is the package's single biggest source of surface bloat — ~30 duplicated types — and reads as "the proto compiler emitted two packages and we re-exported both". - -### 4. `Schema` field as proto-discriminator array — `src/v1/model.ts:271,290,311,456,576,589,645,757,773` and enums on lines 23,28,46,51 -- **Why weird:** Every `Group`, `User`, `ServicePrincipal`, list-response, and patch-request type carries a `schemas?: <…>Schema[]` field whose contents are URN strings like `URN_IETF_PARAMS_SCIM_SCHEMAS_CORE_2_0_GROUP`. The schemas are part of the SCIM spec on the wire, but their *enum* representation in TS is awkward: the values are SHOUTY_SNAKE constants embedding the entire URN, and there are separate `GroupSchema`, `ListResponseSchema`, `PatchSchema`, `ServicePrincipalSchema`, `UserSchema` enums each with one or two values plus an `_UNSPECIFIED` zero. This is the proto convention of "every enum needs an UNSPECIFIED variant for backwards-compat" applied to a constant set that is fully determined by RFC 7644 and never grows. Note: `SCIM` itself is a domain word, but the per-type `Schema` enum-wrapper is a generator artifact. -- **Category:** Proto-architecture leak -- **Suggested name:** Drop the per-type `Schema` enums; type the field as a const string union (`type GroupSchema = "urn:ietf:params:scim:schemas:core:2.0:Group"`) or hide it entirely behind the marshaller (the client knows which URNs to send). The `_UNSPECIFIED` zero values should disappear. -- **Rationale:** The enum wraps a single literal URN per type — a `const` is simpler and matches what the spec actually says. The `_UNSPECIFIED` zero is a proto3 default-value artifact with no SCIM meaning. - ## Medium severity -### 5. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:583` +### 2. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:583` - **Why weird:** The list-response type is `ListServicePrincipalResponse` (singular `ServicePrincipal`) while the request type is `ListServicePrincipalsRequest` (plural). Compare to `ListAccountServicePrincipalsResponse` (plural) on line 510. The singular form on a list response reads as a proto message-name copy where the inner message is `ServicePrincipal` and the outer wraps it — i.e., proto's habit of letting the inner singular name dominate. - **Category:** Proto-architecture leak - **Suggested name:** `ListServicePrincipalsResponse`. - **Rationale:** Symmetry with sibling types and with the request name; the current singular is a generator artifact. -### 6. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:34,143,715` +### 3. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:34,143,715` - **Why weird:** `PatchOp` is the enum of patch operation kinds (`ADD`/`REMOVE`/`REPLACE`); `Patch.op` is the field that holds one. The TS field is `op` of type `PatchOp` (or `AccountPatchOp_PatchOp` for the account variant), so the enum has `Op` baked into its own name *and* the field is `op` — `Patch.op: PatchOp` is a type-suffix tautology and `AccountPatchOp_PatchOp` is the worst-case version of finding 1. - **Category:** Proto-architecture leak -- **Suggested name:** Rename the enum to `PatchOperation` (or just inline as a string literal union `"ADD" | "REMOVE" | "REPLACE"`); keep the field `op`. +- **Suggested name:** Rename the enum to `PatchOperation`; keep the field `op`. - **Rationale:** `Op` is a proto shorthand for "operation"; the TS type name should spell it out, and the `_PatchOp` re-suffix should vanish. -### 7. Sentinel `*_UNSPECIFIED` enum values — `src/v1/model.ts:18,24,29,35,42,47,52,59,66,74,82,88,96` -- **Why weird:** Every enum carries an `_UNSPECIFIED` zero value: `GET_SORT_ORDER_UNSPECIFIED`, `GROUP_SCHEMA_UNSPECIFIED`, `LIST_RESPONSE_SCHEMA_UNSPECIFIED`, `PATCH_OP_UNSPECIFIED`, `PATCH_SCHEMA_UNSPECIFIED`, `SERVICE_PRINCIPAL_SCHEMA_UNSPECIFIED`, `USER_SCHEMA_UNSPECIFIED`, `ORDER_UNSPECIFIED`, `LEVEL_UNSPECIFIED`, and copies under each `Account*` variant. The `*_UNSPECIFIED` zero is a proto3 default-value convention with no semantic meaning in TS, where an enum field can simply be optional. -- **Category:** Proto-architecture leak -- **Suggested name:** Drop the `_UNSPECIFIED` variants. Express absence as `undefined` (the fields are already optional). -- **Rationale:** TS has `undefined`; proto3 does not. The sentinel is dead weight. - ## Low severity -### 8. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:652` +### 4. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:652` - **Why weird:** Not a proto leak per se, but the `Me` segment in `MeRequest` is a proto-style shorthand: SCIM defines `GET /Users/me` as the "current user" endpoint, and the proto generator turned `Me` into a type prefix instead of using a verb. `MeRequest` reads as "a Me-shaped request" — the request *to* the `me` endpoint would be `GetCurrentUserRequest` or `GetMeRequest`. - **Category:** Proto-architecture leak - **Suggested name:** `GetCurrentUserRequest` (and rename `client.me()` to `getCurrentUser()`); or `GetMeRequest` if the URL slug is preserved. @@ -70,24 +46,4 @@ ## Observations ### O1. `eslint-disable` density as a signal — `src/v1/model.ts:57,64,72,80,86,94,108,131,150,153,403,411,618` -- The file carries 13 inline `eslint-disable-next-line` comments, all for `@typescript-eslint/naming-convention` (proto-nested enum names) or `@typescript-eslint/no-empty-object-type` (empty proto messages). Every disable corresponds to a proto-architecture artifact — taken together, they form a precise list of the proto-shaped pieces the linter wanted to flag and the generator decided to suppress. Removing the underlying patterns (findings 1, 2, 6) would also remove every disable in this file. - -### O2. Workspace and account API split at type level, not namespace — package vs siblings -- Sibling packages `accountusers`, `accountgroups`, etc. exist for account-scope IAM at higher levels of the SDK; this package interleaves both scopes (`createUser` vs `createAccountUser`, `listGroups` vs `listAccountGroups`) on a single `Client`. The naming convention is mid-position `Account` (finding 3), which is a proto-package-name leak. A consumer who only wants workspace SCIM still sees every account method in IDE autocomplete. - -## Domain glossary -- `SCIM` — System for Cross-domain Identity Management; RFC 7643/7644. Industry-standard, treated as domain word. -- `ServicePrincipal` — Machine identity (UUID + display name) that can authenticate independently of any user. -- `entitlements` — Account/workspace-level capability flags assigned to a user, group, or SP (e.g. `allow-cluster-create`). -- `Patch` — JSON Patch-style partial update body per RFC 7644 §3.5.2. -- `Resources` — Wire-level list payload key in SCIM list responses (capital R per spec). -- `Operations` — Wire-level list of patch ops in SCIM patch requests (capital O per spec). -- `Schema` (URN) — SCIM resource type discriminator, e.g. `urn:ietf:params:scim:schemas:core:2.0:User`. -- `me` — SCIM convention for "the authenticated identity"; `GET /Users/me` returns the calling user. - -## File coverage -- `src/v1/model.ts` (1791 lines): read fully. -- `src/v1/client.ts` (1417 lines): read for method-name patterns and class shape. -- `src/v1/transport.ts` (75 lines): read fully. -- `src/v1/utils.ts` (150 lines): read for helper-name patterns. -- `src/v1/index.ts` (93 lines): read fully. +- The file carries 13 inline `eslint-disable-next-line` comments, all for `@typescript-eslint/naming-convention` (proto-nested enum names) or `@typescript-eslint/no-empty-object-type` (empty proto messages). Every disable corresponds to a proto-architecture artifact — taken together, they form a precise list of the proto-shaped pieces the linter wanted to flag and the generator decided to suppress. Removing the underlying naming patterns (findings 1 and 3) would clear every `naming-convention` disable in this file. diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index 4eb62c9f..12fc0ae8 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -4,14 +4,6 @@ **Module name:** `@databricks/sdk-secrets` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts` -**Inferred domain:** Workspace-level "Secret Manager" (Databricks Secrets API, -`/api/2.0/secrets/...`). Provides three resources: secret scopes (containers, -either Databricks-managed or Azure KeyVault-backed), secrets (key/value -entries inside a scope, value stored as bytes), and ACLs (per-principal -read/write/manage permissions on a scope). - -Notation: file paths are relative to the package root. Findings reference -`file:line`. --- @@ -19,22 +11,14 @@ Notation: file paths are relative to the package root. Findings reference | Severity | Count | | ----------- | ----- | -| High | 3 | -| Medium | 5 | -| Low | 0 | -| Observation | 3 | -| **Total** | **11** | +| High | 1 | +| Medium | 3 | +| Observation | 1 | +| **Total** | **5** | Headline themes: -1. **Cross-package namespace collision with three sibling "secret" packages.** - The repo ships four `*secret*` packages — `secrets` (this one, workspace - Secret Manager), `secretsuc` (Unity Catalog secrets, three-level - namespace), `serviceprincipalsecrets` (account-level OAuth client secrets), - and `serviceprincipalsecretsproxy` (workspace-level proxy for the same). - All four export a class literally named `Client` and types with the noun - `Secret`. Cross-package usage is opaque without aliasing. -2. **Inconsistent action verb across mutating operations.** `Put` for +1. **Inconsistent action verb across mutating operations.** `Put` for creating/updating ACLs and secrets, `Create` for scopes, `Delete` for all three. There is no `Update`. Go's REST SDK adopts the same shape, but `Put` reads as Go/HTTP-method jargon rather than a TS-side action verb. @@ -43,61 +27,18 @@ Headline themes: ## High Severity -### H1. Package collision: four "secret" packages, opaque imports - -- **Affected:** `package.json:2` (`@databricks/sdk-secrets`); compare - `@databricks/sdk-secretsuc`, `@databricks/sdk-serviceprincipalsecrets`, - `@databricks/sdk-serviceprincipalsecretsproxy`. -- **Category:** #1 vague/generic, #12 duplicate concepts. -- **Issue:** All four packages legitimately deal with "secrets" but at very - different layers: - - `secrets` (this package) — workspace-level Secret Manager. Key/value - secrets inside named scopes, with per-scope ACLs. - Endpoint: `/api/2.0/secrets/...`. Domain noun: `SecretScope`. - - `secretsuc` — Unity Catalog secrets. Three-level namespace - (catalog.schema.secret). Domain noun: `Secret` (UC-style). - - `serviceprincipalsecrets` — account-level OAuth M2M client secrets for - service principals. - - `serviceprincipalsecretsproxy` — the same API exposed at the workspace - level via a proxy endpoint. -- The literal symbol `Client` is exported by all four (`index.ts:3`). An - importer writing `import {Client} from '@databricks/sdk-secrets'` cannot - visually distinguish from the other three without aliasing - (`import {Client as SecretsClient}`). Compare to the sibling - `serviceprincipalsecrets` vs `serviceprincipalsecretsproxy` collision - flagged in the `credentials` audit H1. -- **Suggestion:** rename the exported class to `SecretsClient` (and the - three siblings to `SecretsUCClient`, `ServicePrincipalSecretsClient`, - `ServicePrincipalSecretsProxyClient`), so the `Client` symbol does not - appear bare in any of them. Document the four-package matrix in each - package's README. - -### H2. `Client` is unqualified; overlaps with `Secret*` types in the same package +### H1. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` -- **File / line:** `src/v1/client.ts:70` (`export class Client`); re-exported - from `src/v1/index.ts:3`. -- **Category:** #1 vague/generic. -- **Current:** `export class Client`. -- **Suggestion:** `export class SecretsClient`. -- **Rationale:** The package exports `SecretScope`, `SecretMetadata`, and - numerous `Secret*` operation types alongside the bare `Client`. A consumer - importing several symbols from this package gets a mix of self-identifying - `Secret*` names plus an undifferentiated `Client`. Self-identifying the - class name (`SecretsClient`) aligns it with the rest of the package's - exports and also eliminates the cross-package alias dance flagged in H1. - -### H3. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` - -- **Files / lines:** `src/v1/client.ts:596` (`putAcl`), `:653` (`putSecret`); - contrast `:137` (`createScope`), `:268` (`deleteSecret`), `:223` - (`deleteScope`), `:183` (`deleteAcl`). +- **Files / lines:** `src/v1/client.ts:613` (`putAcl`), `:673` (`putSecret`); + contrast `:139` (`createScope`), `:273` (`deleteSecret`), `:228` + (`deleteScope`), `:185` (`deleteAcl`). - **Category:** #17 inconsistent action verbs. - **Current:** `Put` for ACLs and secrets, `Create` for scopes, `Delete` for all three. No `Update`. - **Issue:** A consumer who learned `createScope` will not guess that the way to create or update a secret is `putSecret`, not `createSecret` or - `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:622) and - "Creates or overwrites the ACL" (client.ts:563) — three different verbs + `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:642) and + "Creates or overwrites the ACL" (client.ts:580) — three different verbs for the same upsert semantic. - **Suggestion:** unify on one verb pair: either (a) `Create*` for new + `Update*` for existing, or @@ -111,53 +52,22 @@ Headline themes: ## Medium Severity -### M1. `KeyVault` / `KeyvaultMetadata` / `keyvault` casing inconsistency - -- **Files / lines:** - - `model.ts:29` `AZURE_KEYVAULT` (one word, upper). - - `model.ts:44` `AzureKeyVaultSecretScopeMetadata` (two words, "Vault"). - - `model.ts:59` `backendAzureKeyvault` (one word, lower-camel). - - `model.ts:202` `keyvaultMetadata` (one word, lower-camel). - - `model.ts:215` `unmarshalAzureKeyVaultSecretScopeMetadataSchema` (two - words, "Vault"). - - `model.ts:309` `keyvault_metadata` (the *wire* form). - - `model.ts:319` `marshalAzureKeyVaultSecretScopeMetadataSchema`. -- **Category:** #3 acronym casing inconsistency, #4 underscores (in wire - names — acceptable, but interacts). -- **Current:** simultaneously `KeyVault`, `Keyvault`, `keyvault`, - `KEYVAULT`. -- **Suggestion:** pick one. Microsoft's official product name is - "Azure Key Vault" (two words; see - `https://azure.microsoft.com/en-us/products/key-vault`). Standardize on - `KeyVault` in types and `keyVault` in fields: - - Type: `AzureKeyVaultSecretScopeMetadata` (already correct). - - Field: `keyVaultMetadata` (currently `keyvaultMetadata`), - `backendAzureKeyVault` (currently `backendAzureKeyvault`). -- **Rationale:** the type name is already two-word and follows the - Microsoft-canonical spelling. The fields just need to match the type - names they describe. - -### M2. `AclItem` is generic-suffix tautology +### M1. `AclItem` is generic-suffix tautology - **File / line:** `src/v1/model.ts:36`. -- **Category:** #20 type-suffix tautology, #15 generic field names. +- **Category:** #20 type-suffix tautology. - **Current:** `AclItem` describes "an ACL rule". The `Item` suffix is meaningless. -- **Suggestion:** rename to `Acl` or `AclEntry` or `AclRule`. The - enclosing `ListAclsRequest_Response.items: AclItem[]` is then - `ListAclsRequest_Response.acls: Acl[]`. The Go SDK uses `AclItem`, but in - TS the suffix doesn't carry weight: `AclItem` and `AclRule` carry exactly - the same information. -- **Rationale:** Look at the surrounding code: - - `ListAclsRequest_Response.items` (`model.ts:123`) — the field is - `items`, not `acls`. Generic name lost the domain. - - JSDoc on `:122` says "The associated ACLs rule applied to principals" - — so the type is conceptually "an ACL rule", but it's spelled - "AclItem". The doc disagrees with the name. +- **Suggestion:** rename to `Acl` or `AclEntry` or `AclRule`. The Go SDK + uses `AclItem`, but in TS the suffix doesn't carry weight: `AclItem` and + `AclRule` carry exactly the same information. +- **Rationale:** JSDoc on `model.ts:120` says "The associated ACLs rule + applied to principals" — so the type is conceptually "an ACL rule", but + it's spelled "AclItem". The doc disagrees with the name. -### M3. `SecretMetadata` describes a list-item, not metadata +### M2. `SecretMetadata` describes a list-item, not metadata -- **File / line:** `src/v1/model.ts:184`. +- **File / line:** `src/v1/model.ts:180`. - **Category:** #1 vague/generic, #20 type-suffix tautology. - **Current:** `SecretMetadata { key, lastUpdatedTimestamp }`. The JSDoc says "The metadata about a secret. Returned when listing secrets. Does @@ -171,13 +81,9 @@ Headline themes: (tags, schema, labels). Here the type *is* the secret as exposed by list — it lacks only the value. `SecretSummary` reads correctly. -### M4. `Backend` mid-position is an architectural leak +### M3. `ScopeBackendType` enum name is an architectural leak -- **Files / lines:** `src/v1/model.ts:19` (`ScopeBackendType` enum), - `:57` (`CreateScopeRequest.scopeBackendType`), `:59` - (`CreateScopeRequest.backendAzureKeyvault`), `:200` - (`SecretScope.backendType`), `:308, :315, :333, :341` (marshal/unmarshal - schema field names). +- **File / line:** `src/v1/model.ts:19` (`ScopeBackendType` enum). - **Category:** proto-architectural-leak (`Backend` mid-position, not a domain noun). - **Issue:** the public surface uses `Backend` to mean "where the secret @@ -185,40 +91,16 @@ Headline themes: `Backend` is an implementation/architecture term (frontend/backend layering), not a user-facing domain concept. A consumer sees `ScopeBackendType` and reads it as a deployment/architecture flag, - rather than what the field actually denotes: the *storage provider* or + rather than what the type actually denotes: the *storage provider* or *vault provider* of the scope. - **Suggestion:** rename to a domain term. Options: - `ScopeBackendType` → `ScopeStorageType` or `SecretStorageProvider`. -- **Rationale:** every other field in the package uses domain nouns +- **Rationale:** every other type in the package uses domain nouns (`scope`, `key`, `principal`, `permission`). `Backend` is the one outlier that smuggles in implementation jargon. Same defect appears in several other audits where "backend" describes an integration/provider layer (e.g., `connections.md` flags `ConnectionType` analogues). -### M5. `GetSecretRequest_Response` returned by `getSecret` carries `key` redundantly - -- **File / line:** `src/v1/model.ts:108-113`. -- **Category:** #12 duplicate concepts (request → response). -- **Current:** `GetSecretRequest_Response { key?: string; value?: Uint8Array }`. - The caller has just passed `key` in via `GetSecretRequest.key`, so they - have it. -- **Issue:** the response echoes the key. Two interpretations: - - The server is *confirming* which key was returned, useful for any - callers using multi-stage pipelines. - - The server's response may rewrite the key in some way (e.g. - normalization), but the JSDoc gives no such hint. -- **Suggestion:** consider whether `key` is load-bearing on the response. - If not, drop it; if so, document why. As a TS shape, `Promise` - for `getSecret` would be simpler than a `{key, value}` envelope. As-is, - callers writing `(await client.getSecret({scope, key: 'foo'})).value` - spell `foo` twice. - ---- - -## Low Severity - -_None._ - --- ## Observations @@ -230,37 +112,4 @@ _None._ requires `scope` for ten of eleven operations. Not a naming defect but worth noting: the type is wider than the API allows. -### O2. `AclPermission.MANAGE` is owner-equivalent but not named that way - -- **File / line:** `src/v1/model.ts:11-12`. -- The JSDoc says "Allowed to read/write ACLs, and read/write secrets to - this secret scope" — i.e., MANAGE is full control. In the rest of the - Databricks platform, this level is often called OWNER. Naming - inconsistency with the wider platform; the wire format is fixed. - -### O3. The `Secret` noun is absent from this package's exports - -- **Files / lines:** `src/v1/index.ts`, `model.ts`. -- The package is called `secrets` but exports `SecretScope`, - `SecretMetadata`, and various `Secret*` operations. There is no bare - `Secret` type. The closest is `GetSecretRequest_Response { key, value }` - — the actual full secret. Compare to the sibling `secretsuc` package - which exports a top-level `Secret` type (`secretsuc/model.ts:89`). -- Naming the type would help: e.g., `Secret { key, value }`. As-is, the - package's primary domain entity has no named type. - ---- - -## Recommended renames (high-confidence, in priority order) - -1. `Client` → `SecretsClient` (H1, H2). -2. Verb harmonization: pick `Create`/`Update` *or* `Put` and apply - consistently across all mutating methods (H3). -3. `AclItem` → `Acl` or `AclEntry` (M2). -4. `SecretMetadata` → `SecretSummary` or `SecretInfo` (M3). -5. Casing standardization: `KeyVault` everywhere (`keyVaultMetadata`, - `backendAzureKeyVault`) (M1). -6. `ScopeBackendType` → `ScopeStorageType`; drop `Backend` mid-position - (M4). - --- diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index 362c1e7d..2efd9226 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -1,111 +1,49 @@ # Naming Audit: secretsuc -**Path:** `packages/secretsuc/src/v1/` +**Path:** `packages/uc/secrets/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. -**Total weird names flagged:** 13 +**Total weird names flagged:** 6 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 5 | -| Low | 0 | -| Observation | 4 | +| High | 1 | +| Medium | 3 | +| Observation | 2 | ## High severity -### 1. Package name `secretsuc` — `packages/secretsuc/`, `package.json:2` -- **Why weird:** Two words mashed together with no separator: `secrets` + `uc`. The result reads as "secret-suc" or a single nonsense word. `uc` is a two-letter cryptic abbreviation that is never expanded anywhere in the public TypeScript surface — neither the `Client` class, the `Secret` interface, nor any field or constant mentions "UnityCatalog" or "Uc". The only places "Unity Catalog" appears at all are (a) JSDoc prose, (b) the URL path `/api/2.1/unity-catalog/secrets`, and (c) the `Secret` interface JSDoc. The package directory is the only carrier of the disambiguator, and it's silent in code. -- **Category:** 5 (cryptic abbreviation), 12 (duplicate concept against `packages/secrets/`), 6 (misleading — `secretsuc` looks like a typo or a verb suffix). -- **Suggested name:** `secrets-unity-catalog`, `unitycatalogsecrets`, or `ucsecrets` (all worse than expanding fully). Best: rename package to `unitycatalogsecrets` (matching pattern of `unitycatalogvolumes` etc. used elsewhere) or move the secrets type into a sub-namespace of a unified `unitycatalog` package. At a minimum, separate the words: `secrets-uc` or `secretsUc` is still wrong; the actual readable form is **`secrets-unitycatalog`** or **`unitycatalog-secrets`**. -- **Rationale:** A package name is the most user-facing identifier in any SDK — it appears in every `import` line and every `package.json` dependency entry. `secretsuc` fails three tests at once: (a) it is unreadable on first sight (where does the word boundary fall?); (b) it hides the disambiguator that separates it from `secrets`; (c) it embeds an undefined two-letter token. Compare with workspace-level peer `secrets`: a user installing both gets `@databricks/sdk-secrets` and `@databricks/sdk-secretsuc`, with no hint from the names which one targets workspaces and which targets Unity Catalog. The `uc` suffix is the entire semantic load and it's mute. - -### 2. `Client` class collides with `secrets` package at the import level — `src/v1/client.ts:41` -- **Why weird:** Bare `Client` for the secret-management API. After `import {Client} from '@databricks/sdk-secretsuc/v1'` the caller has a symbol named `Client` with no domain hint. If the caller also imports from `@databricks/sdk-secrets/v1`, they get two identifiers both called `Client` — they must alias both at import. The collision is sharpest for `secrets` vs `secretsuc`: both export `Client` from the same overall scope, so a user with both deps has to write `import {Client as UcSecretsClient} from '@databricks/sdk-secretsuc/v1'`. -- **Category:** 1 (vague), 12 (duplicate concept — every package exports `Client`), 6 (misleading — no hint of which domain it serves). -- **Suggested name:** `SecretsClient`, or better, `UnityCatalogSecretsClient`. -- **Rationale:** Every generated package in this SDK exports `Client`; auditing one package can't fix the convention. But the pain is sharpest for `secrets` vs `secretsuc`, which is why this finding is scoped to that import-level collision. - -### 3. `Secret` interface is overloaded as create-input, update-input, and read-output — `src/v1/model.ts:89` -- **Why weird:** Same word used by the sibling `@databricks/sdk-secrets` package's `SecretMetadata`/`PutSecret` types. A consumer with both packages cannot import `Secret` from either without aliasing. The type also doubles as the entity returned from `getSecret`, the input shape embedded in `CreateSecretRequest.secret`, and the update payload embedded in `UpdateSecretRequest.secret`. Its fields mix read-only (`createTime`, `metastoreId`, `effectiveOwner`) with write-only (`value`) with read-write (`comment`, `owner`). -- **Category:** 12 (duplicate concept — different `Secret` exists at workspace level), 6 (misleading — single type for create-input + read-output + update-input means many fields are conditionally valid). -- **Suggested name:** `UnityCatalogSecret` for the type. Splitting into `CreateSecretInput` / `Secret` / `UpdateSecretInput` is the structural fix that would surface the read/write asymmetry in the type system. -- **Rationale:** Even if the package rename happens, the type name `Secret` carries no UC-specific signal. Users wiring up both APIs will collide. Beyond the collision, one type for three lifecycle stages means callers cannot tell from the type which fields are writable on input and which are server-populated on output. - -### 4. `fullName` is the routing key but marked optional — `src/v1/model.ts:23,32,115,152` -- **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:109,136,244`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. +### 1. `fullName` is the routing key but marked optional — `src/v1/model.ts:23,32,115,152` +- **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:114,144,258`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. - **Category:** 6 (misleading — looks optional, isn't), 16 (field type contradicts domain — required key marked optional). - **Suggested name:** Keep the name, drop `| undefined` on the three request DTOs (or split: `Secret.fullName?` for responses, `SecretRef.fullName` required for requests). - **Rationale:** This is a routing identifier; the TS type system can prevent a whole class of "I forgot the name" bugs and the SDK can stop substituting empty strings. ## Medium severity -### 5. `Secret` mixes effective (server-resolved) and direct (caller-set) fields — `src/v1/model.ts:126` -- **Why weird:** The single `Secret` type carries write-only `value` alongside read-only `effectiveValue`, `effectiveOwner`, `createTime`, `createdBy`, `updateTime`, `updatedBy`, `metastoreId`, `browseOnly`. The shared type is used on both create (`client.ts:80`) and update (`client.ts:251`) paths. Callers cannot tell from the type which fields are writable on input and which are server-populated on output, and the `effective*` pairs (owner/effectiveOwner, value/effectiveValue) put the resolved and directly-set values next to each other without a structural distinction. -- **Category:** 11 (single type wearing two hats), 6 (misleading). -- **Suggested name:** Split into `WritableSecret` / `Secret`, or `SecretCreateInput` / `SecretUpdateInput` / `Secret`. -- **Rationale:** The single-type approach forces every consumer to know which fields are write-permitted. The field-mask on update (`updateMask` — `model.ts:162`) partially mitigates but doesn't substitute for type-level intent. - -### 6. `UpdateSecretRequest.secret` is the *update payload* with `fullName` as routing key — `src/v1/model.ts:147-163` -- **Why weird:** `UpdateSecretRequest` has both `fullName` (routing) and `secret` (payload). The nested `secret.fullName` is meaningless — what if it differs from the outer `fullName`? The whole `secret`, including its own optional `fullName`, is serialised into the PATCH body even though the path is keyed by the outer `req.fullName`. -- **Category:** 6 (misleading — two `fullName`s can disagree), 17 (inconsistency — same field appearing twice in one logical operation). -- **Suggested name:** Either define `SecretUpdate` (omits `fullName`, `createTime`, etc.) or rely on the field-mask to ignore non-listed fields. Naming-wise: rename the outer to `name`/`secretFullName` to emphasise it's the routing key, not part of the payload. -- **Rationale:** This is a real bug surface: callers will write `{fullName: 'a.b.c', secret: {fullName: 'x.y.z', ...}}` and wonder why renames don't work. - -### 7. `ListSecretsRequest.catalogName` + `schemaName` as filters but documented as required-when-paired — `src/v1/model.ts:46,51` +### 2. `ListSecretsRequest.catalogName` + `schemaName` as filters but documented as required-when-paired — `src/v1/model.ts:46,51` - **Why weird:** JSDoc says "Both **catalog_name** and **schema_name** must be specified together". TS type marks both optional. The "must be specified together" constraint is enforced at the server, not in the type. A more honest shape would be `{ scope?: {catalogName: string; schemaName: string} | undefined }` so the pair must be set atomically. - **Category:** 16 (field type contradicts domain — "must be together" not expressible). - **Suggested name:** Keep names, group into a `scope` sub-object so paired-ness is type-enforced. - **Rationale:** Internal grouping fix; not strictly a naming finding. Listed because the field names alone don't communicate the constraint, and the type system isn't carrying the weight. -### 8. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` -- **Why weird:** Request uses `pageToken`, response uses `nextPageToken`. Internally consistent with conventions across the SDK, but the asymmetry between "what I send" and "what I receive next time" is something the type system can't help with. The pagination iterator (`client.ts:227`) bridges them via `pageReq.pageToken = resp.nextPageToken`. +### 3. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` +- **Why weird:** Request uses `pageToken`, response uses `nextPageToken`. Internally consistent with conventions across the SDK, but the asymmetry between "what I send" and "what I receive next time" is something the type system can't help with. The pagination iterator (`client.ts:241`) bridges them via `pageReq.pageToken = resp.nextPageToken`. - **Category:** 17 (action-verb / qualifier asymmetry between request and response). - **Suggested name:** Accept the convention (`nextPageToken` is the next page; you copy it to `pageToken` on the next request). Listed for completeness. - **Rationale:** Generator convention; this isn't really a naming defect — flagged because rules 14 and 17 both ask about cross-DTO consistency. -### 9. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` +### 4. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` - **Why weird:** JSDoc enumerates four meanings of `pageSize`: unset = 10000, positive = min(value, 10000), zero = 10000, negative = error. The field type is `number | undefined` which expresses none of those. A reader of the type signature alone would believe any number works. - **Category:** 16 (type contradicts domain — should be `positive integer | undefined`), 6 (misleading — zero has special meaning). - **Suggested name:** Keep the name; consider a Zod refinement (`z.number().int().nonnegative()`) and document the zero-means-default specially. - **Rationale:** API-level concern (the upstream API conflates "use default" and "0"); flagging at the SDK level because the type system is silent. -## Low severity - -_None._ - ## Observations -### 10. Action-verb convention in `Client` +### 5. Action-verb convention in `Client` `createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) -### 11. Acronym casing for `Http` / `Url` -Same as other audited packages: `Http` (PascalCase capital-then-lower) coexists with `URLSearchParams` (ALLCAPS from Web standard). Convention inherited from broader JS ecosystem; not worth changing. -- **Category:** 3. - -### 12. `Uc` abbreviation never expanded in code -Tracked thoroughly. The string "Uc" (in any case) does not appear in any identifier, type name, field name, constant, or enum value. "Unity Catalog" appears only in (a) JSDoc on `Secret` (`model.ts:85`), (b) JSDoc on `createSecret` / `listSecrets` / `updateSecret` (`client.ts:67,163,232`), and (c) the URL path string `/api/2.1/unity-catalog/secrets` (`client.ts:79,109,136,176,244`). The package name `secretsuc` is the **only** carrier of the disambiguator at the import level, and it's silent everywhere else. A consumer importing `Client` and `Secret` from this package, then opening their editor's symbol view, will see no hint that this is Unity-Catalog-scoped. See finding #1. -- **Category:** 5. - -### 13. No enums in this package -No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; `secretsuc` exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. - -## Domain glossary -- `uc` — Unity Catalog. Used in the **package name only**. Never expanded in any TS identifier. Spelled out in JSDoc prose ("Unity Catalog") and the URL path (`unity-catalog`). -- `BROWSE` / `MANAGE` / `READ_SECRET` / `CREATE_SECRET` / `USE SCHEMA` / `USE CATALOG` — Unity Catalog privilege names, referenced in JSDoc only (`client.ts:69,127,165`). -- `metastore` — Unity Catalog metastore (top of the catalog hierarchy). Referenced via `metastoreId` field. -- `securable` — Not used in this package, despite being core to UC. The hierarchy here (`catalog.schema.secret`) does not surface the term. -- `wkt` — Well-Known Types (`@databricks/sdk-core/wkt`), used for `FieldMask`. -- `oss`, `m2m`, `u2m`, `pat`, `iam`, `abac` — not encountered. - -## File coverage -- `src/v1/model.ts` (296 lines): read fully. -- `src/v1/client.ts` (276 lines): read fully. -- `src/v1/utils.ts` (150 lines): read fully. -- `src/v1/index.ts` (15 lines): read fully. -- `package.json`: spot-checked for package metadata. - -## Cross-package notes -- `packages/secrets/` (workspace-level Secrets API): exports `AclPermission`, `AclItem`, `CreateScope`, `DeleteAcl`, `DeleteSecret`, `GetSecret`, `ListAcls`, `ListScopes`, `ListSecrets`, `PutAcl`, `PutSecret`, `SecretMetadata`, `SecretScope`, `ScopeBackendType`. **Same concept noun (`Secret`) exists in both packages with incompatible shapes.** A consumer with both deps faces name collisions on `Client`, `DeleteSecret`/`DeleteSecretRequest`, `GetSecret`/`GetSecretRequest`, `ListSecrets`/`ListSecretsRequest`, and the workspace-side `PutSecret` vs UC-side `Secret`. -- The workspace-level `secrets` package has its own naming problems (`PutSecret`, the `key` / `value` flat shape vs UC's three-level `Secret` shape). Out of scope for this audit; flagged because the SDK design choice to have two separate packages multiplies the surface area. +### 6. No enums in this package +No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; this package exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index a3c960f9..c06a45c0 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -2,25 +2,8 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 -**Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with seven typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — replacing the per-feature `get*`/`update*`/`delete*` endpoints that live in `accountsettings` (v1) and `workspacesettings` (v1). -**Total weird names flagged:** 34 - ---- - -## CRITICAL: Cross-package collision - -Within the JS SDK there are now **four** packages with overlapping responsibilities: - -| Package | Versions | Style | Surface | -|---------|----------|-------|---------| -| `settings` (this) | v2 | Generic key/value | `Setting` with polymorphic `value`/`effectiveValue` | -| `accountsettings` | v1 | Per-feature endpoints | `CspEnablementAccountSetting`, `PersonalComputeSetting`, etc. | -| `workspacesettings` | v1 | Per-feature endpoints | `DefaultNamespaceSetting`, `AutomaticClusterUpdateSetting`, etc. | -| `workspaceconf` | v1 | Free-form key/value | `WorkspaceConf {key,value}` (single string-string map) | - -The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `PersonalComputeMessage`, `BooleanMessage`, `StringMessage`, `IntegerMessage` — appears verbatim in both `settings/v2/model.ts` and `workspacesettings/v1/model.ts` (and is referenced from `accountsettings/v1`). Same TS identifier, defined twice, in two packages, with two `unmarshal*Schema`s. Consumers using both packages will get two distinct types named the same thing. - -> Flag the entire package layout for re-design (or, at minimum, hoist shared message types into a single `@databricks/sdk-settings-shared` package). The "settings vs workspacesettings vs accountsettings vs workspaceconf" naming gives the reader no way to predict which one to import. +**Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with multiple typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — via a single set of generic `get*`/`patch*`/`list*Metadata` endpoints. +**Total weird names flagged:** 20 --- @@ -29,39 +12,25 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess | # | Severity | Category | Identifier | File:line | |---|----------|----------|------------|-----------| | 1 | Critical | Vague package name | `settings` (package) | package level | -| 2 | Critical | Duplicate concept (4-package overlap) | `settings` vs `accountsettings` vs `workspacesettings` vs `workspaceconf` | package level | -| 3 | Critical | Duplicated TS identifier across packages | `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage` | `model.ts:88-100,102,288,294,98,171,414,284` (and the workspacesettings dup) | -| 4 | High | Vague/generic type | `Setting` | `model.ts:305` | -| 5 | High | Vague/generic type | `SettingsMetadata` | `model.ts:424` | -| 6 | High | Vague/generic type | `UserPreference` | `model.ts:452` | -| 7 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:102, 106, 175, 292, 296, 442` | -| 8 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 88, 94` | -| 9 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:296` | -| 10 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:106` | -| 11 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` | -| 12 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:98, 497, 928` | -| 13 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:94-96` | -| 14 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` | -| 15 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:83, 112, 137, 346, 378, 409` | -| 16 | Medium | Inconsistent action verbs | `patch` for mutation (vs `update` in `accountsettings`/`workspacesettings` for the same operation) | `client.ts:346, 378, 409` | -| 17 | Medium | Inconsistent action verbs | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:378` | -| 18 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:229` | -| 19 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:208` | -| 20 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:277` | -| 21 | Medium | Verb-tense inconsistency | `PreviewPhase` vs `GA_SOON` (mixed adverb/timeline forms) | `model.ts:11-27` | -| 22 | Medium | Acronym casing | `Aibi` should be `AIBI` or `AiBi` per TS rules | `model.ts:30` | -| 23 | Medium | Acronym casing | `Gov` (short for "Government") undocumented short | `model.ts:302` | -| 24 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #14 as a proto-leak category) | `model.ts:156, 161, 170, 270, 277, 286` | -| 25 | Low | Long enum value | `RESTRICT_TOKENS_AND_JOB_RUN_AS` | `model.ts:85` | -| 26 | Low | Long enum value | `FIRST_AND_THIRD_OF_MONTH` | `model.ts:56` | -| 27 | Low | Long enum value | `SECOND_AND_FOURTH_OF_MONTH` | `model.ts:57` | -| 28 | Low | Acronym casing | `Id` vs `ID` (TS chooses `Id`, package consistent) | `model.ts:157, 165, ...` | -| 29 | Low | Acronym casing | `Ws` (in JSDoc, not identifier) | `model.ts:78, 83` | -| 30 | Low | Wire-vs-TS abbreviation | `restrict_tokens_and_job_run_as` enum value | `model.ts:85` | -| 31 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:176` | -| 32 | Low | Inconsistent verb | "patch" (HTTP idiom) vs "update" (SDK idiom in sibling packages) | `client.ts:346, 378, 409` | -| 33 | Low | Acronym casing | `Dbfs` doc — appears in workspacesettings as `Dbfs` (cross-package) | `workspacesettings/model.ts`; `settings` doesn't have it but consumers will collide | -| 34 | Low | Misleading | `PreviewPhase` enum lists `BETA` as separate from `PUBLIC_PREVIEW` even though common usage merges them | `model.ts:21-25` | +| 2 | High | Vague/generic type | `Setting` | `model.ts:324` | +| 3 | High | Vague/generic type | `SettingsMetadata` | `model.ts:453` | +| 4 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:111, 194, 471, 115, 311, 315` | +| 5 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 97, 103` | +| 6 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:315` | +| 7 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:115` | +| 8 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 142, 38, 50, 149, 160, 132, 75, 82` | +| 9 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:107, 526, 989` | +| 10 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:103-104` | +| 11 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:175, 289, 189, 305, 180, 296`; `client.ts:85, 354, 139, 417, 114, 386` | +| 12 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:85, 354, 139, 417, 114, 386` | +| 13 | Medium | HTTP-verb leak | `patch` for mutation where the SDK convention is `update`/`set` | `client.ts:354, 386, 417` | +| 14 | Medium | Inconsistent action verb | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:386` | +| 15 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:248` | +| 16 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:227` | +| 17 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:296` | +| 18 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #11 as a proto-leak category) | `model.ts:175, 180, 189, 289, 296, 305` | +| 19 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:195` | +| 20 | Low | HTTP-verb leak | `patch` (HTTP idiom) vs `update`/`set` (SDK idiom) | `client.ts:354, 386, 417` | --- @@ -72,73 +41,51 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **File:line:** package level - **Category:** Vague/generic — extreme risk - **Suggestion:** `settingsv2` (or `unified-settings`, or `settingskv`). A user-facing package name of literally `"settings"` collides with most "settings" concepts in any application. -- **Rationale:** The wire path is `/api/2.1/settings/{name}` and `/api/2.1/accounts/{accountId}/settings/{name}`. The Go SDK uses `settingsv2`. The TS package elides the `v2` suffix from the package name (it only appears in the subpath import `@databricks/sdk-settings/v2`), which gives the impression of a generic catch-all when in fact this is the new key/value flavor that supersedes `accountsettings`/`workspacesettings` per-feature endpoints. - -### 2. Four-package overlap: `settings` vs `accountsettings` vs `workspacesettings` vs `workspaceconf` - -- **File:line:** repo-wide -- **Category:** Duplicate concept -- **Suggestion:** Either (a) merge into one `@databricks/sdk-settings` package with sub-paths `/v1` (legacy per-feature) and `/v2` (unified KV), or (b) rename to make the distinction explicit: `legacy-account-settings`, `legacy-workspace-settings`, `unified-settings`, `legacy-workspace-conf`. Today, a user wanting to read/write the `automatic_cluster_update_workspace` setting must guess which package: `workspacesettings/v1` (specific endpoint), `settings/v2` (generic endpoint), or `workspaceconf/v1` (free-form). The packages give no signal of preference. -- **Rationale:** A naming audit cannot fix the underlying API design but must surface it. The collision is the dominant naming issue in this package. - -### 3. Duplicated TS identifiers across packages: `*Message` family - -- **File:line:** `model.ts` (this) vs `workspacesettings/v1/model.ts` -- **Category:** Duplicate concept — same TS identifier defined twice -- **Identifiers:** `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMessage`, `AibiDashboardEmbeddingAccessPolicy`, `AibiDashboardEmbeddingApprovedDomains`, `BooleanMessage`, `StringMessage`, `IntegerMessage`, `PersonalComputeMessage`. -- **Suggestion:** Hoist these into a shared `@databricks/sdk-settings-shared` package (or just `@databricks/sdk-common` if the messages stabilize). A consumer who imports `{ClusterAutoRestartMessage}` from both `settings` and `workspacesettings` gets two structurally-identical-but-nominally-distinct types and any function expecting one rejects the other. -- **Rationale:** Verified by grepping both packages — the type declarations are byte-for-byte the same. The Go SDK upstream uses the same proto definition for both, so the duplication is faithful to the source, but in TypeScript it manifests as a real collision. +- **Rationale:** The wire path is `/api/2.1/settings/{name}` and `/api/2.1/accounts/{accountId}/settings/{name}`. The Go SDK uses `settingsv2`. The TS package elides the `v2` suffix from the package name (it only appears in the subpath import `@databricks/sdk-settings/v2`), which gives the impression of a generic catch-all when in fact this is the new key/value flavor of the settings surface. --- ## High severity -### 4. `Setting` — extreme generic risk +### 2. `Setting` — extreme generic risk -- **File:line:** `model.ts:305-422` +- **File:line:** `model.ts:324-451` - **Category:** Vague/generic, reserved-word risk - **Suggestion:** `UnifiedSetting`, `SettingValue`, or `KeyedSetting`. The Setting concept here is "a name plus a polymorphic value plus a polymorphic effective value" — none of those properties match the bare word "Setting" without context. -- **Rationale:** `Setting` is one of the most overloaded single words in software (UI settings, settings menu, settings file, configuration setting, etc.). Inside a "settings" package, the type `Setting` reads like "the thing this package is about" — but the package has three other top-level types (`UserPreference`, `SettingsMetadata`, and the wrapper messages). The bare name encourages a `import {Setting}` that competes with React UI `Setting` types, Node `process.config` settings, etc. +- **Rationale:** `Setting` is one of the most overloaded single words in software (UI settings, settings menu, settings file, configuration setting, etc.). Inside a "settings" package, the type `Setting` reads like "the thing this package is about" — but the package has other top-level types (`UserPreference`, `SettingsMetadata`, and the wrapper messages). The bare name encourages a `import {Setting}` that competes with React UI `Setting` types, Node `process.config` settings, etc. -### 5. `SettingsMetadata` — plural type, singular use +### 3. `SettingsMetadata` — plural type, singular use -- **File:line:** `model.ts:424-440` +- **File:line:** `model.ts:453-469` - **Category:** Vague + singular/plural mismatch - **Suggestion:** `SettingMetadata` (singular). The type describes metadata about *one* setting; lists are `SettingMetadata[]`. The current `SettingsMetadata` reads as "all metadata about all settings" which is what the *array* of these things represents — not the element. -- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:200`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). - -### 6. `UserPreference` — vague + collides with `Setting` - -- **File:line:** `model.ts:452-475` -- **Category:** Vague/generic -- **Suggestion:** Either fold into `Setting` (since the structure differs only in which `$case` payloads are allowed) or rename to `UserSetting` for parallelism with the package theme. The doc comment at `model.ts:447-451` already says "user-specific setting scoped to an individual user" — the word "preference" then competes with "setting" for the same concept. -- **Rationale:** Three top-level structural types — `Setting`, `UserPreference`, `SettingsMetadata` — that all model "name + value(s)" with slightly different shapes. A user reading just type names cannot predict which to use. +- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:219, 250, 277`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). -### 7. `*Message` suffix — Go/proto-style +### 4. `*Message` suffix — Go/proto-style -- **File:line:** `model.ts:102, 106, 175, 292, 296, 442` +- **File:line:** `model.ts:111, 194, 471, 115, 311, 315` - **Category:** Suffix tautology / Go-style -- **Identifiers:** `BooleanMessage`, `ClusterAutoRestartMessage`, `IntegerMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`, `StringMessage`, and the workspacesettings duplicates. +- **Identifiers:** `BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage` (and `AllowedAppsUserApiScopesMessage`, `CollaborationPlatformConnectivityMessage`, `OperationalEmailCustomRecipientMessage`). - **Suggestion:** Drop `Message`. Rename `ClusterAutoRestartMessage → ClusterAutoRestart`, `RestrictWorkspaceAdminsMessage → RestrictWorkspaceAdmins`, etc. The "Message" suffix is the protobuf convention for "everything is a Message"; in TS where "everything is an interface", the suffix is noise. -- **Rationale:** No other TS-idiomatic SDK uses `*Message` as a suffix. The classes are not messages in any TS-visible sense (they don't extend a `Message` base, they have no serialization methods — the marshal/unmarshal functions are external). +- **Rationale:** No other TS-idiomatic SDK uses `*Message` as a suffix. The interfaces are not messages in any TS-visible sense (they don't extend a `Message` base, they have no serialization methods — the marshal/unmarshal functions are external). -### 8. `Aibi` — undefined cryptic abbreviation (AI/BI) +### 5. `Aibi` — undefined cryptic abbreviation (AI/BI) -- **File:line:** `model.ts:30, 88, 94, 335-337, 392` and method-name appearances in `client.ts` -- **Category:** Cryptic abbreviation, acronym casing -- **Suggestion:** `AIBI` (acronym casing) or spell out `AiBi` for the AI/BI Genie embedding feature. Add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." +- **File:line:** `model.ts:30, 97, 103` +- **Category:** Cryptic abbreviation +- **Suggestion:** Spell out as `AiBi` for the AI/BI Genie embedding feature, and add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." - **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. -### 9–10. Verb-tense action-as-noun naming +### 6–7. Verb-tense action-as-noun naming -- **File:line:** `model.ts:296 (RestrictWorkspaceAdminsMessage), 106 (ClusterAutoRestartMessage)` +- **File:line:** `model.ts:315 (RestrictWorkspaceAdminsMessage), 115 (ClusterAutoRestartMessage)` - **Category:** Verb-tense inconsistency - **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`). - **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. -### 11. Proto-nested underscore type naming — proto-architectural leak +### 8. Proto-nested underscore type naming — proto-architectural leak -- **File:line:** `model.ts:30, 38, 50, 66, 73, 123, 133, 140, 151` (and the corresponding marshal/unmarshal schema declarations) +- **File:line:** `model.ts:30, 142, 38, 50, 149, 160, 132, 75, 82` (and the corresponding marshal/unmarshal schema declarations) - **Category:** Proto-architectural leak (nested-message naming) - **Why:** Every nested type carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested ... name.` comment — an explicit admission that the TS surface is wearing proto-generated shape. Examples: - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` @@ -153,10 +100,10 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess - **Suggestion:** Promote nested message/enum types to top-level TS interfaces with descriptive names: `AccessPolicyType`, `MaintenanceWindow`, `DayOfWeek`, `WeekDayFrequency`, `MaintenanceSchedule`, `WindowStartTime`, `EnablementDetails`, `PersonalComputeMode`, `WorkspaceAdminRestrictionStatus`. Where two top-level names would collide across packages, prefix with the owning concept (e.g., `MaintenanceWindowDayOfWeek`) but never use `_`. - **Rationale:** Underscore-separated multi-word TS identifiers are non-idiomatic (Google TS style mandates `PascalCase` for types; Microsoft TS handbook agrees). The `*Foo_Bar_Baz` chain is purely a transliteration of proto's nested-message scoping — TS has module namespaces (`Foo.Bar.Baz`) and lexical scoping for that, neither of which is used here. The eslint-disable comments are the smoking gun. -### 12. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak +### 9. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak -- **File:line:** `model.ts:98, 497 (unmarshal), 928 (marshal)` -- **Category:** Proto-architectural leak (`Api` mid-position) + `*Message` suffix (covered in #7) +- **File:line:** `model.ts:107, 526 (unmarshal), 989 (marshal)` +- **Category:** Proto-architectural leak (`Api` mid-position) + `*Message` suffix (covered in #4) - **Why:** `Api` appears mid-name in a domain type that models *what user-OAuth scopes apps may be granted*. The "Api" half describes the **wire/proto** medium ("user-API scopes") rather than the domain concept (OAuth scopes). - **Suggestion:** `AllowedAppsUserScopes` (drop `Api`, drop `Message`). The discriminator value `allowedAppsUserApiScopes` and wire key `allowed_apps_user_api_scopes` would remain wire-side; the TS surface should not carry the proto-medium descriptor. - **Rationale:** The combined `Api` + `Message` pair carries two architectural-leak tokens in a single identifier (60 chars including `Schema` in the marshal/unmarshal forms). `Api` mid-position falls squarely in the prompt's flag list. @@ -165,163 +112,80 @@ The same data type — `RestrictWorkspaceAdminsMessage`, `ClusterAutoRestartMess ## Medium severity -### 13. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use +### 10. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use -- **File:line:** `model.ts:94-96` +- **File:line:** `model.ts:103-104` - **Category:** Singular/plural mismatch - **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. -### 14. `*Public*` qualifier — redundant +### 11. `*Public*` qualifier — redundant -- **File:line:** `model.ts:156, 161, 170, 270, 277, 286` +- **File:line:** `model.ts:175, 289, 189, 305, 180, 296` - **Category:** Redundant qualifier -- **Suggestion:** Drop `Public` from request type names (and method names — #15). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Suggestion:** Drop `Public` from request type names (and method names — #12). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. - **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. -### 15. Method names: `getPublic*`, `patchPublic*` — redundant `Public` +### 12. Method names: `getPublic*`, `patchPublic*` — redundant `Public` -- **File:line:** `client.ts:83, 112, 137, 346, 378, 409` +- **File:line:** `client.ts:85, 354, 139, 417, 114, 386` - **Category:** Redundant qualifier + verbose - **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. -### 16. `patch*` vs `update*` — inconsistent action verb across SDK +### 13. `patch*` — HTTP-verb leak where the SDK convention is `update`/`set` -- **File:line:** `client.ts:346, 378, 409` (use `patch`) -- **Category:** Inconsistent action verbs -- **Suggestion:** Pick one verb. `update` is the verb in `accountsettings/v1/client.ts` and `workspacesettings/v1/client.ts` for the equivalent operation; `patch` is used here. Cross-package consistency matters. -- **Rationale:** Same operation (PATCH HTTP verb against a settings endpoint) named `update*` in the v1 packages and `patch*` in this v2 package. Users will look for `update*` first based on muscle memory. +- **File:line:** `client.ts:354, 386, 417` (use `patch`) +- **Category:** HTTP-verb leak / inconsistent action verb +- **Suggestion:** Pick an SDK-domain verb. `update` (for the setting mutations) or `set`/`put` (for the user-preference replacement) reads more like an SDK operation than the raw HTTP method `patch`. +- **Rationale:** The method name echoes the HTTP verb (`PATCH`) rather than the domain action. Mutation methods elsewhere in the SDK favor `update`/`set`; `patch` leaks the transport idiom onto the public surface and breaks muscle memory for users scanning for an `update*` method. -### 17. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action +### 14. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action -- **File:line:** `client.ts:378` +- **File:line:** `client.ts:386` - **Category:** Inconsistent + verbose - **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. - **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. -### 18–20. Long type names +### 15–17. Long type names -- **File:line:** `model.ts:229, 208, 277` +- **File:line:** `model.ts:248, 227, 296` - **Category:** Overly verbose - **Identifiers:** - `ListAccountUserPreferencesMetadataResponse` (42 chars) - `ListAccountUserPreferencesMetadataRequest` (41 chars) - `PatchPublicAccountUserPreferenceRequest` (39 chars) -- **Suggestion:** After applying the suggested simplifications (drop `Public`, drop `Message`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. - -### 21. `PreviewPhase` enum — mixed temporal/qualitative members - -- **File:line:** `model.ts:11-27` -- **Category:** Verb-tense / categorisation inconsistency -- **Members:** `PRIVATE_PREVIEW`, `PUBLIC_PREVIEW`, `BETA`, `GA_SOON`, `GA` -- **Suggestion:** Standardise. The current set has `*_PREVIEW` (qualifier-style) alongside `BETA` (single word), `GA_SOON` (temporal hedge), and `GA` (acronym). `PUBLIC_PREVIEW` vs `BETA` are essentially the same launch phase in many product lifecycles — picking one would tighten the model. -- **Rationale:** Tension visible even in the JSDoc: "The feature is in public preview, available to all customers. Also used for gated public preview (available to customers who request access) since the distinction is internal." So `PUBLIC_PREVIEW` already covers two cases. Adding `BETA` on top is a third overlapping concept. +- **Suggestion:** After applying the suggested simplifications (drop `Public`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. -### 22–23. Acronym casing: `Aibi` vs `AIBI`; `Gov` vs `Governance` +### 18. `*Public*` qualifier as proto-architectural leak (reframe of #11) -- **File:line:** `model.ts:30, 88, 94, 302` -- **Category:** Acronym casing -- **Suggestion:** Google TS style says 2-3 letter acronyms can be TitleCase (`Aibi` ok) but longer acronyms or non-acronyms (like `Gov` for `Governance`) should be spelt out. - -### 24. `*Public*` qualifier as proto-architectural leak (reframe of #14) - -- **File:line:** `model.ts:156, 161, 170, 270, 277, 286`; `client.ts:83, 112, 137, 346, 378, 409` +- **File:line:** `model.ts:175, 180, 189, 289, 296, 305`; `client.ts:85, 114, 139, 354, 386, 417` - **Category:** Proto-architectural leak (`Public` mid-position) - **Why:** `Public` in `GetPublic*Request`, `PatchPublic*Request`, and method names `getPublic*`/`patchPublic*` is a direct echo of the proto service-name `PublicSettingsService` — i.e., the *server-side* internal-vs-public service split. The TS SDK only ships the public surface, so the qualifier signals nothing the user can act on. - **Suggestion:** Drop `Public` from every request type and every method name. `GetAccountSettingRequest`/`getAccountSetting`, `PatchAccountSettingRequest`/`patchAccountSetting`, etc. -- **Rationale:** This duplicates #14 and #15 but reframes them as a *proto-architectural leak* per the scan brief. `Public`/`Internal` are explicitly on the flag list. The two earlier findings catalogued the names; this one names the cause. +- **Rationale:** This duplicates #11 and #12 but reframes them as a *proto-architectural leak* per the scan brief. The two earlier findings catalogued the names; this one names the cause. --- ## Low severity -### 25–27. Long enum values - -- **File:line:** `model.ts:85, 56, 57` -- **Category:** Long enum value -- **Identifiers:** `RESTRICT_TOKENS_AND_JOB_RUN_AS` (28c), `FIRST_AND_THIRD_OF_MONTH` (24c), `SECOND_AND_FOURTH_OF_MONTH` (26c) -- **Suggestion:** For `RESTRICT_TOKENS_AND_JOB_RUN_AS`, the wire string is fixed (`'RESTRICT_TOKENS_AND_JOB_RUN_AS'`), so the TS-side rename would only affect the enum-key access. - -### 28–29. Acronym casing notes +### 19. `IntegerMessage` misleading in JS -- **File:line:** `model.ts:157, 78` -- **Category:** Acronym casing -- **Notes:** `Id` (consistent), `Ws` (only in JSDoc, not identifiers — safe). - -### 30. `restrict_tokens_and_job_run_as` enum string value - -- **File:line:** `model.ts:85` -- **Category:** Wire value -- **Suggestion:** N/A — wire-fixed. - -### 31. `IntegerMessage` misleading in JS - -- **File:line:** `model.ts:175-177` +- **File:line:** `model.ts:194-196` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 32. `patch*` vs `update*` - -- See #16. +### 20. `patch*` vs `update*`/`set*` -### 33. Cross-package `Dbfs` casing - -- **File:line:** `workspacesettings/v1/model.ts` (consumer-collision risk noted; not present in this package directly) -- **Category:** Cross-package acronym casing -- **Suggestion:** Note for the cross-package audit, not actionable here. - -### 34. `BETA` member adjacent to `PUBLIC_PREVIEW` - -- See #21. +- See #13. --- ## Observations -1. **`settings` v2 is the latest in a sprawl of overlapping packages.** The same user functionality (e.g. configure cluster auto-restart, restrict workspace admins) is reachable via at least three packages with three different shapes: - - `workspacesettings/v1`: per-feature endpoints, typed payloads (`AutomaticClusterUpdateSetting.automaticClusterUpdateWorkspace: ClusterAutoRestartMessage`). - - `settings/v2`: unified `Setting` with polymorphic `value` field (`Setting.value.$case === 'automaticClusterUpdateWorkspace'`). - - `workspaceconf/v1`: untyped `{key: string, value: string}` map. - The package naming gives the user zero guidance on which to use. A user-facing index / migration guide is critical. - -2. **`Setting`, `SettingsMetadata`, `UserPreference` are all underspecific.** The package theme is "settings v2", but the central types use the bare word "Setting" without qualification. This is the single biggest naming risk in the package — a user importing `Setting` from `@databricks/sdk-settings/v2` will clash with any application-level `Setting` type in seconds. - -3. **Cross-package duplication of `*Message` types is a real type-system hazard.** `RestrictWorkspaceAdminsMessage` declared in both `settings/v2/model.ts` and `workspacesettings/v1/model.ts` is the most concrete example. A function in user code typed as `(m: RestrictWorkspaceAdminsMessage) => void` will accept one import but not the other — and the TS error message will say "Type 'RestrictWorkspaceAdminsMessage' is not assignable to type 'RestrictWorkspaceAdminsMessage'" with no further hint. Hoisting these to a shared module is the highest-ROI fix. +1. **`Setting`, `SettingsMetadata`, `UserPreference` are all underspecific.** The package theme is "settings v2", but the central types use the bare word "Setting" without qualification. This is the single biggest naming risk in the package — a user importing `Setting` from `@databricks/sdk-settings/v2` will clash with any application-level `Setting` type in seconds. -4. **`patch` vs `update` cross-package inconsistency.** The v1 SDKs use `update*`; the v2 SDK uses `patch*`. Same wire verb (PATCH HTTP). The verb mismatch will trip muscle-memory across the surface. +2. **`patch` leaks the HTTP verb onto the public surface.** The mutation methods are named `patch*`, echoing the `PATCH` HTTP method rather than a domain action like `update`/`set`. Same wire verb (PATCH HTTP); the SDK-domain name would read more naturally and is easier to discover. -5. **`Aibi`, `Gov`, `Dbfs`, `Csp`, `Esm`, `Dcp`, `Llm`, `Sql` etc.** form an acronym soup across all four packages. None of them are defined in any one place. A glossary at the repo level (or per package) would be high-ROI and zero-risk. +3. **`Aibi` is an undefined abbreviation.** It is not expanded anywhere in the package — `Aibi` (AI/BI) only appears inside type names. A package-level glossary (or spelling it out in the type identifiers) would be high-ROI and zero-risk. -6. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. - ---- - -## Domain glossary - -| Acronym / token | Expansion | Mentioned in code? | -|-----------------|-----------|--------------------| -| **Aibi / AIBI** | AI/BI (Databricks's AI- and BI-powered Genie dashboards) | No (only as part of type names) | -| **Gov** | Governance (in `disableGovTagCreation`) | Inferred from field doc | -| **OBO** | On-behalf-of (in `RESTRICT_TOKENS_AND_JOB_RUN_AS` doc) | Yes (one-time, undefined) | -| **WS** | Workspace (in same doc) | Inferred | -| **SP / SPs** | Service Principal(s) (in same doc) | Inferred | -| **GA / GA_SOON** | Generally Available | Implicit via doc | -| **DCP / Dcp** | Default Personal Compute policy (only in `accountsettings`, not here) | N/A | -| **CSP** | Compliance Security Profile (cross-package) | N/A here | -| **ESM** | Enhanced Security Monitoring (cross-package) | N/A here | -| **DBFS** | Databricks File System (cross-package) | N/A here | -| **LLM** | Large Language Model (cross-package) | N/A here | -| **Id** | Identifier | Implicit | -| **etag** | Entity tag (HTTP cache validator, RFC 7232) | Not in this package | - ---- - -## File coverage - -| File | Lines read | Coverage | -|------|-----------|----------| -| `src/v2/index.ts` | 44 (full) | 100% — exports inventory only, no naming surprises beyond the type names already audited from `model.ts`. | -| `src/v2/model.ts` | 1300 (full) | 100% — 6 enums, 23 interfaces (incl. all nested message types), 15 unmarshal-zod schemas, 15 marshal-zod schemas audited. | -| `src/v2/client.ts` | 433 (full) | 100% — `Client` constructor and 9 client methods audited (paginated page-returning and iterator-returning variants both reviewed). | - ---- +4. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. diff --git a/.agent/naming-audit/sharing.md b/.agent/naming-audit/sharing.md index 3574c2f9..b72d6af4 100644 --- a/.agent/naming-audit/sharing.md +++ b/.agent/naming-audit/sharing.md @@ -3,48 +3,32 @@ **Path:** `packages/sharing/src/v1/` **Versions audited:** v1 **Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` -**Inferred domain:** Delta Sharing — providers, recipients, shares, share -permissions, federation policies, and provider-share asset listing. Models -the cross-metastore Delta Sharing flow: a Databricks data provider exposes -shares (collections of tables/views/volumes/notebooks/functions/models) -to one or more recipients (other Databricks metastores or external OIDC / -token-authenticated clients). -**Total weird names flagged:** 5 +**Total weird names flagged:** 3 -**Last rescanned:** 2026-05-26 (post regeneration #156). All five findings -re-verified against the regenerated source; none addressed upstream. -`client.ts` line numbers drifted with the regen (the `getActivationUrlInfo` -method moved from line 369 to line 398), but the underlying naming pattern -is unchanged. +**Last rescanned:** 2026-06-02. All findings re-verified against the +current source; none addressed upstream. The regeneration shifted most +line numbers and renamed the proto-nested `GetActivationUrlInfoRequest_Response` +to the clean `GetActivationUrlInfoResponse`; every citation was corrected +in place, and finding L1 was rewritten to reference the new response name. ## Summary | Severity | Count | | --- | --- | -| High | 2 | -| Medium | 2 | +| High | 1 | +| Medium | 1 | | Low | 1 | -| Observation | 0 | -| **Total** | **5** | - -The audit is narrowly scoped to proto/architectural leaks. The package's -main pattern is a `*Info` "metadata-message" suffix that proto uses to -distinguish a slim identifier message from the populated entity message; -in TS it collapses to redundant type-naming for what is just *the entity*. -The remaining flag is on `PartitionSpecification`, an empty top-level -interface that exists only to namespace its nested proto types. -`DeltaSharing*` (a real product name) and standard `*Request` / `*Response` -end suffixes are not flagged. +| **Total** | **3** | --- ## High severity (must fix) -### 1. `*Info` suffix repeated across the core entity surface — `model.ts:739, 774, 845, 902, 331, 358` +### 1. `*Info` suffix repeated across the core entity surface — `model.ts:733, 768, 839, 895, 331, 358` - **Why:** Five entity types use the proto-style `*Info` "metadata - message" suffix: `ProviderInfo` (model.ts:739), `RecipientInfo` - (model.ts:774), `RecipientTokenInfo` (model.ts:845), `ShareInfo` - (model.ts:902), and `FunctionParameterInfo` (model.ts:331) plus the + message" suffix: `ProviderInfo` (model.ts:733), `RecipientInfo` + (model.ts:768), `RecipientTokenInfo` (model.ts:839), `ShareInfo` + (model.ts:895), and `FunctionParameterInfo` (model.ts:331) plus the pluralised wrapper `FunctionParameterInfos` (model.ts:358). In every case the type IS the entity, not metadata *about* the entity — there is no `Provider` / `Recipient` / `RecipientToken` / `FunctionParameter` @@ -58,11 +42,10 @@ end suffixes are not flagged. sibling entity types) - **Suggested:** Drop the `Info` suffix on the entity types: `ProviderInfo` → `Provider`, `RecipientInfo` → `Recipient`, - `RecipientTokenInfo` → `RecipientToken`, `ShareInfo` → `Share` (see - finding H2 — collides with the existing slim `Share` type, which is - the actual rename target), `FunctionParameterInfo` → - `FunctionParameter`, `FunctionParameterInfos` → `FunctionParameters` - (or drop the wrapper and inline the array; see finding M2). + `RecipientTokenInfo` → `RecipientToken`, `ShareInfo` → `Share`, + `FunctionParameterInfo` → `FunctionParameter`, `FunctionParameterInfos` + → `FunctionParameters` (or drop the wrapper and inline the array; see + finding M1). - **Rationale:** Sibling packages in this SDK already follow the unsuffixed convention for the entity (`catalogs.Catalog`, `schemas.Schema`, `volumes.Volume`, `connections.Connection`, @@ -71,61 +54,11 @@ end suffixes are not flagged. `RecipientInfo` is the recipient itself, a sidecar metadata object, or a server-side projection. It is just the recipient. -### 2. `Share` (slim stub) coexists with `ShareInfo` (full record) — `model.ts:897` vs `model.ts:902` -- **Why:** Two parallel "the share" types live in the same file: - `Share { name?, id? }` (model.ts:897) is a 2-field identifier stub - used as the `share` slot on `ListProviderShareAssetsResponse` - (model.ts:495), while `ShareInfo` (model.ts:902) is the full record - used by `createShare`, `getShare`, and `listShares`. This is the - proto pattern of having both a slim `Share` "reference" message and - a fat `ShareInfo` "metadata" message for the same logical entity; - in the TS surface a consumer cannot tell from the names which one - to expect at which call site. -- **Category:** Proto-architecture leak (slim-vs-fat duplicate-message - pair for the same entity) -- **Suggested:** Collapse the pair: rename `ShareInfo` → `Share` and - rename the existing 2-field `Share` to `ShareReference` (or drop the - stub entirely and use `{name?: string; id?: string}` inline on - `ListProviderShareAssetsResponse`). After the collapse, the full - record is the canonical `Share` and the surface matches the - `Provider` / `Recipient` rename in finding H1. -- **Rationale:** Two types named after the same noun, sharing two - fields (`name`, `id`), is the most direct form of proto-message - leak. The slim form exists in the wire schema for size optimisation; - in TS the optional fields handle that, and a caller has no use for - a stand-alone two-field stub when the populated form is already a - superset. - --- ## Medium severity (worth pushing back on) -### 1. `PartitionSpecification` empty top-level + nested-only payload — `model.ts:677, 680, 686` -- **Why:** `PartitionSpecification` (model.ts:677) is declared as an - empty interface (`{}` with an eslint-disable for the empty-object - type) whose only role is to host the nested `PartitionSpecification_Partition` - (model.ts:680) and `PartitionSpecification_Partition_PartitionValue` - (model.ts:686) types. The actual array of partitions lives on - `SharedDataObject.partitions: PartitionSpecification_Partition[]` - (model.ts:1023), never on a `PartitionSpecification` value. The - empty top-level + nested-tree shape is a verbatim transcription of - the proto message tree (`PartitionSpecification { repeated Partition - partitions; }`) where the outer message is the namespacing container. -- **Category:** Proto-architecture leak (`Specification`/`Spec` infix - on a namespacing-only type whose root has no payload) -- **Suggested:** Either drop the empty top-level `PartitionSpecification` - and surface `Partition` / `PartitionValue` as flat siblings (with - the `partitions` field on `SharedDataObject` typed as - `Partition[]`), or, if a top-level container is desired, give it - the missing `partitions: Partition[]` field so the name carries - some payload. -- **Rationale:** An empty interface that exists only to namespace its - nested types is a TS-hostile pattern (TS has no nested-namespace - semantics for interfaces — the underscore-flattened names live at - the top level anyway). Removing the empty container exposes the - partition tree at the level it is actually used. - -### 2. `FunctionParameterInfos` single-field array wrapper — `model.ts:358` +### 1. `FunctionParameterInfos` single-field array wrapper — `model.ts:358` - **Why:** `FunctionParameterInfos { parameters?: FunctionParameterInfo[] }` is a wrapper interface whose only field is the array. It is consumed exactly once, as the `inputParams: FunctionParameterInfos | undefined` @@ -151,11 +84,11 @@ end suffixes are not flagged. ## Low severity (nits) -### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:363, 369, client.ts:398` -- **Why:** The method `getActivationUrlInfo` (client.ts:398) returns - `GetActivationUrlInfoRequest_Response`, an empty interface - (model.ts:369). The mid-position `Info` in both the method and the - request type adds nothing semantic: the method just gets the +### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:363, 369, client.ts:386` +- **Why:** The method `getActivationUrlInfo` (client.ts:386) returns + `GetActivationUrlInfoResponse`, an empty interface (model.ts:369). + The mid-position `Info` in the method and the `GetActivationUrlInfoRequest` + type (model.ts:363) adds nothing semantic: the method just gets the activation URL data (and currently returns nothing). The naming inherits the proto RPC name (`GetActivationUrlInfo`) where `Info` was the message-type variant suffix. @@ -170,39 +103,3 @@ end suffixes are not flagged. where it is provably defunct (no response fields). Removing it matches the bare `getActivationUrl` shape a reader would write from first principles. - ---- - -## Observations (not flags) - -_None._ - ---- - -## File coverage - -| File | Lines read | Coverage | -| ---- | ---------- | -------- | -| `src/v1/index.ts` | 93 / 93 | 100% | -| `src/v1/transport.ts` | 75 / 75 | 100% | -| `src/v1/utils.ts` | 150 / 150 | 100% | -| `src/v1/model.ts` | 2354 / 2354 | 100% | -| `src/v1/client.ts` | 1133 / 1133 | 100% | - -All types, fields, enums, methods, and locals reviewed for the -proto/architectural-leak patterns: `Public`/`Internal`/`External` -mid-position, `Proto` suffix/infix, `Service`/`Server`/`Backend`/ -`Frontend`, `Rpc`/`Grpc`, `Manager`/`Handler`/`Controller`/ -`Processor`/`Daemon`/`Worker`, `Impl`, non-real `Proxy`, -mid-position `Action`/`Op` duplicating verbs, `Wrapper`/`Adapter`, -`Old`/`New`/`Legacy`/`Modern`, mid-position `V1`/`V2`, mid-position -`Api`/`Sdk`/`Client`, and repeated `Spec`/`Config`/`Details`/`Info` -suffixes. No `Proxy`, `Impl`, `Manager`, `Handler`, `Controller`, -`Service`, `Server`, `Backend`, `Frontend`, `Rpc`, `Grpc`, -`Processor`, `Daemon`, `Worker`, `Wrapper`, `Adapter`, `Old`, `New`, -`Legacy`, `Modern`, mid-position `V1`/`V2`, mid-position `Api`/`Sdk`/ -`Client`, `Public`/`Internal`/`External` mid-position, or -`Foo_PublicRequest` visibility-infix patterns observed. The -`DeltaSharing*` lexicon (real product name), domain `External*` (in -context-appropriate places), `OAuth*`, `Webhook*`, and standard -`*Request`/`*Response`/`*Schema` end suffixes are not flagged. diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index 807bc875..e569b5e1 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -6,216 +6,112 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`. -**Inferred domain.** The Databricks SQL Statement Execution API. Submit a SQL -`statement`, await a `status`, then fetch result `data` either inline or via -`external_links` chunked from cloud storage. Four methods: -`executeStatement`, `cancelStatement`, `getStatementResult` (poll a submitted -statement), and `getResultData` (fetch a single result chunk by index). HTTP -prefix `/api/2.0/sql/statements/`. - -**Direct overlap with sibling packages.** - -| Package | What it is | Overlap source | -| --- | --- | --- | -| `statementexecution` (this) | Run arbitrary SQL on a SQL Warehouse. Public general-purpose SQL execution API. | — | -| `queryexecution` | Re-run *saved* queries inside *published Lakeview dashboards*. Hits `/api/2.0/lakeview-query/query/published`. | Vocabulary collides (`statementId` exists in both; `truncated` field in both; both have a `cancel` method). | -| `queryhistory` | List historical query executions. | Shares `Channel`, `Status`, `Warehouse`, `WarehouseId`. | -| `commandexecution` | Run Python/SQL via REPL on a cluster. | Both call themselves "execution". | -| `queries` | Saved query definitions. | Naming collision: `queries` vs `statements`. | - -The package name `statementexecution` is reasonable in isolation, but the SDK -*already* has `queryexecution`, `commandexecution`, and `queries`. A user -opening the marketplace sees four packages whose names overlap heavily and has -to read every one to pick the right tool. See finding #1. - -**Total weird names flagged:** 37 +**Total weird names flagged:** 20 ## Summary | Severity | Count | | --- | --- | -| High | 9 | -| Medium | 20 | -| Low | 5 | -| Observation | 3 | +| High | 5 | +| Medium | 11 | +| Low | 3 | +| Observation | 1 | ## High severity -### 1. Package name `statementexecution` overlaps three sibling packages — directory name, public import specifier -- **Why weird:** The SDK ships `statementexecution`, `queryexecution`, `commandexecution`, and `queries`. The English words "query", "statement", and "command" are near-synonyms in casual usage, so a user installing the SDK can't pick the right one without reading docs. Concretely: this package is the *only* one that runs ad-hoc SQL on a SQL Warehouse, yet its name doesn't reveal that. The Databricks SQL Statement Execution API itself is documented at `docs.databricks.com/api/workspace/statementexecution`, so the wire-level name is "statement execution" — but the *user-facing* TS-import surface should distinguish itself from `queryexecution`. -- **Category:** 1 (vague — "statement" overlaps "query"/"command"), 12 (duplicate concept — three execution packages). -- **Suggested name:** `sqlstatements`, `sqlexec`, or `warehouseexec` — anything that signals "SQL on a SQL Warehouse". If staying with `statementexecution`, every type name should keep its `Statement*` prefix and the package docstring should call out the contrast with `queryexecution` and `commandexecution`. -- **Rationale:** Naming should disambiguate. Today the four packages are differentiable only by URL prefix and resource. Compare to e.g. `clusterlibraries` vs `clusterpolicies`: both clearly cluster-scoped but each names its sub-resource. - -### 2. `ServiceErrorCode` enum members duplicate generic HTTP/gRPC vocabulary — `src/v1/model.ts:53` -- **Why weird:** The enum lists 14 generic codes: `UNKNOWN`, `INTERNAL_ERROR`, `TEMPORARILY_UNAVAILABLE`, `IO_ERROR`, `BAD_REQUEST`, `SERVICE_UNDER_MAINTENANCE`, `WORKSPACE_TEMPORARILY_UNAVAILABLE`, `DEADLINE_EXCEEDED`, `CANCELLED`, `RESOURCE_EXHAUSTED`, `ABORTED`, `NOT_FOUND`, `ALREADY_EXISTS`, `UNAUTHENTICATED`. These are direct gRPC `google.rpc.Code` carry-overs. The SDK already has a canonical apierror codes module (`packages/databricks/src/apierror/codes/`); duplicating them inside one package's enum is wrong on three axes: it's redundant, it pulls gRPC vocabulary into a HTTP/JSON SDK, and it pollutes per-package type surfaces. -- **Category:** 1 (vague — `IO_ERROR`, `ABORTED` give no context), 2 (redundant: `ServiceErrorCode.ABORTED` reads `ServiceErrorCode = ABORTED` twice), 12 (duplicate concept — apierror module owns these codes), 14 (gRPC-style names). -- **Suggested name:** Eliminate the enum. Map the wire code into the canonical `apierror/codes` enum; expose `ServiceError.errorCode` as that type. -- **Rationale:** Per-package error-code enums diverge over time. The SDK already commits to canonical codes elsewhere; this package should use them. - -### 3. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` +### 1. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` - **Why weird:** Enum name is `Disposition` — a generic noun (`Content-Disposition` header? business "disposition"?). The enum members `INLINE` and `EXTERNAL_LINKS` are recognisable, but the type name doesn't say "fetch" or "result". A reader who skims `disposition?: Disposition` in `ExecuteStatementRequest` won't know it means "where the result data goes". As a top-level export, `Disposition` collides with any other "disposition" concept a consumer might pull in. - **Category:** 1 (vague — "Disposition" of what?), 15 (generic top-level export). -- **Suggested name:** `ResultDisposition` or `FetchDisposition`. Matching field rename: `resultDisposition?: ResultDisposition`. +- **Suggested name:** `ResultDisposition` or `FetchDisposition`. - **Rationale:** Top-level enum names should self-describe at use sites. `request.disposition: Disposition` reads as "disposition disposition"; `request.disposition: ResultDisposition` reads correctly. -### 4. `Format` enum is dangerously generic — `src/v1/model.ts:46` -- **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #3: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). +### 2. `Format` enum is dangerously generic — `src/v1/model.ts:46` +- **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #1: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). - **Category:** 1 (vague — `Format` is the most generic possible name), 10 (reserved-word-ish — `format` is a builtin function name in many ecosystems), 15 (generic name losing meaning at use sites). -- **Suggested name:** `ResultFormat`. Same pattern as #3. +- **Suggested name:** `ResultFormat`. Same pattern as #1. - **Rationale:** Top-level enum names should self-describe at use sites. `result.format: Format` reads as "format format"; `result.format: ResultFormat` reads correctly. The collision risk for a single-word `Format` import is high. -### 5. `TimeoutAction` enum members `CONTINUE`/`CANCEL` are too generic — `src/v1/model.ts:77` -- **Why weird:** Two of the enum values are bare English verbs that don't say *what* they continue or cancel. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously (`CONTINUE`) or is cancelled (`CANCEL`). The relationship between the verbs and the timeout is invisible at the type level. -- **Category:** 1 (vague — `CONTINUE` what?), 14 (gRPC/proto-style upper-case verbs), 15 (generic verb-only names). -- **Suggested name:** `OnTimeout.ContinueAsync` and `OnTimeout.CancelExecution` (or rename the enum to `OnTimeout` to match the field `onWaitTimeout`). -- **Rationale:** Enum members should self-document; bare verbs require the reader to chase the field's JSDoc. - -### 6. `GetResultDataRequest` vs. `GetStatementResultRequest` — `src/v1/model.ts:381,390` -- **Why weird:** Two near-identical request types, one with `chunkIndex` and one without. Their names break apart suspiciously: - - `GetResultDataRequest` fetches *one chunk* of the result data. - - `GetStatementResultRequest` polls the entire statement (`statementId` only). - - Read aloud, they look like they swap word order arbitrarily (`Result Data` vs `Statement Result`). A user can't tell from the type names which one fetches what. The method names amplify the issue: `getResultData` (fetches a chunk) and `getStatementResult` (polls status + first chunk). -- **Category:** 1 (vague — "ResultData" vs "StatementResult"), 6 (misleading — names suggest interchangeable concepts), 17 (inconsistent ordering of qualifiers). -- **Suggested name:** `GetResultChunkRequest` (carries `chunkIndex`) + `GetStatementRequest` (polls by `statementId`). Methods: `getResultChunk` + `getStatement`. This matches the URL paths `/result/chunks/{chunkIndex}` and `/{statementId}`. -- **Rationale:** Type names should mirror the resource being addressed. The wire makes the distinction explicit; the TS surface obscures it. +### 3. `TimeoutAction` enum name doesn't tie to the timeout field — `src/v1/model.ts:77` +- **Why weird:** The top-level enum `TimeoutAction` is generic — it doesn't tie back to the field it governs. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously or is cancelled. The relationship between the enum and the timeout is invisible at the type level. +- **Category:** 1 (vague — action on what?), 15 (generic top-level export). +- **Suggested name:** Rename the enum to `OnTimeout` to match the field `onWaitTimeout`. +- **Rationale:** Top-level enum names should self-describe at use sites and tie to the field they govern. -### 7. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:219` -- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. Combine with #6: there are now two `getResult*` methods, one of which doesn't actually fetch results (it polls), and one of which does (`getResultData`). -- **Category:** 6 (misleading — name implies result-fetch, primary purpose is poll), 12 (duplicate concept — both methods carry "Result" but mean different things), 17 (inconsistent verb usage — `cancel`, `execute`, `getStatementResult`, `getResultData`). +### 4. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:230` +- **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. The companion chunk-fetch method `getResultData` (#5) does the actual result fetch, so a reader sees two `getResult*`-shaped methods, one of which only polls. +- **Category:** 6 (misleading — name implies result-fetch, primary purpose is poll), 17 (inconsistent verb usage — `cancel`, `execute`, `getStatementResult`, `getResultData`). - **Suggested name:** `getStatement` (matches the URL path `/{statementId}`). The Go SDK calls this `GetStatement`. The result is *part* of the response; foregrounding it in the method name misleads. - **Rationale:** The Databricks API docs name the operation "Get statement" (https://docs.databricks.com/api/workspace/statementexecution/getstatement). The TS SDK should match. -### 8. `getResultData` method asymmetric with `getStatementResult` — `src/v1/client.ts:183` -- **Why weird:** Companion to #7. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. +### 5. `getResultData` method drops resource and chunk-index semantics — `src/v1/client.ts:191` +- **Why weird:** Companion to #4. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. - **Category:** 1 (vague — "result data" is too generic), 6 (misleading — drops the chunk-indexing semantic), 17 (asymmetric with sibling method). - **Suggested name:** `getResultChunk` (or `getStatementResultChunk` to match Go). Field rename: `chunkIndex` stays. - **Rationale:** Names should match the official API where possible. Compare to `getStatementResultChunkN` in the Go SDK. -### 9. `Client` class name — `src/v1/client.ts:43` -- **Why weird:** A class literally named `Client`, re-exported as `Client` from `index.ts:3`. A user importing this from `@databricks/sdk-statementexecution` and another `Client` from `@databricks/sdk-queryexecution` will collide on the namespace. Identical to `queryexecution.md` Finding #9. -- **Category:** 1 (vague), 15 (generic name). -- **Suggested name:** `StatementExecutionClient`. -- **Rationale:** Repeated SDK-wide pattern. - ## Medium severity -### 10. `SUCCEEDED` vs `FAILED` vs `CANCELED` vs `CLOSED` tense mix — `src/v1/model.ts:86-91` -- **Why weird:** Enum values: `PENDING` (gerund), `RUNNING` (gerund), `SUCCEEDED` (past), `FAILED` (past), `CANCELED` (past, single-l), `CLOSED` (past). One spelling is `CANCELED` (US, single-l) — see #16 for the inconsistency with the same word `CANCELLED` in `ServiceErrorCode` (which the `ServiceErrorCode` enum spells with double-l). The tense mix is fine across the SDK, but the cancel spelling inconsistency is a real bug. -- **Category:** 13 (verb-tense inconsistency), 17 (US/UK spelling inconsistency for "cancel"). -- **Suggested name:** Pick one cancel spelling. The wire is `CANCELED` (single-l) per this enum and `CANCELLED` per `ServiceErrorCode`. Resolve at wire level. -- **Rationale:** Twin spellings of the same English word in adjacent enums in the same file is a maintenance hazard. Compare `StatementStatus_State.CANCELED` to `ServiceErrorCode.CANCELLED`. - -### 11. `StatementResponse.statementId` collides with `QueryResponseStatus.statementId` (sibling package) — `src/v1/model.ts:498`, `queryexecution model.ts:102` -- **Why weird:** A user importing from both `statementexecution` and `queryexecution` finds a `statementId` field on responses from both packages. In `statementexecution` it identifies the SQL Statement Execution submission. In `queryexecution` (a published-dashboard query) the JSDoc explicitly says "The statement_id should be identical to data_token in SuccessStatus and PendingStatus" — i.e. it's an audit copy, not a primary key. The same name means different things in two adjacent packages. -- **Category:** 12 (duplicate concept — same name, different meaning), 19 (underspecified ID — what kind of statement?). -- **Suggested name:** Keep `statementId` here (primary identifier); rename the audit-only copy in `queryexecution` (see `queryexecution.md` Finding #14). -- **Rationale:** Cross-package consistency; this package is the canonical home of `statementId`. - -### 12. `warehouseId` field — `src/v1/model.ts:158` -- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #24. +### 6. `warehouseId` field — `src/v1/model.ts:158` +- **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #11. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. -### 13. `parameters` field carries `StatementParameter[]` — `src/v1/model.ts:308` -- **Why weird:** Field name is `parameters`. Element type is `StatementParameter`. The element name is more specific (statement parameter) than the field (parameters). At the JSDoc level, the field describes "parameter markers" — which is yet a third name for the same concept. So users see: `parameters` (field) vs `StatementParameter` (element type) vs "parameter markers" (docs). Pick one vocabulary. -- **Category:** 12 (duplicate concept — three names for one idea), 17 (inconsistent vocabulary). -- **Suggested name:** Either rename the element type to `Parameter` (less qualified than field) or rename the field to `statementParameters`. The wire shape probably matters; pick the less verbose option. -- **Rationale:** Multiple synonyms for one concept burns reader attention. - -### 14. `ServiceError` carries an open-ended `errorCode` and `message` — `src/v1/model.ts:473` -- **Why weird:** Type is named `ServiceError`. SDK already has canonical error types in `@databricks/sdk-databricks/apierror` — `ApiError` and friends. A `ServiceError` type that lives inside one API package and exposes its own enum is parallel to the SDK's canonical error type but doesn't interop. So a user catching errors might encounter both `ApiError` (from the transport layer) and a `StatementStatus.error: ServiceError` (from a 200-OK statement-failed response). Two error shapes for one user-facing problem. -- **Category:** 12 (duplicate concept — overlaps `ApiError`), 6 (misleading — "Service" qualifier doesn't say which service), 14 (Java/Go-style `ServiceError`). -- **Suggested name:** `StatementError` (or fold into `ApiError` extensions). The errorCode should reuse the canonical apierror codes per #2. -- **Rationale:** Multiple error type shapes per SDK is a cognitive tax. - -### 15. `StatementStatus.sqlState` field — `src/v1/model.ts:522` -- **Why weird:** Field name `sqlState`. The JSDoc says "SQLSTATE error code returned when the statement execution fails." The all-caps acronym SQLSTATE is the SQL-standard 5-character status code (e.g. `42S22`). The TS field uses camelCase `sqlState`. Compare to elsewhere in the SDK where SQL is also lowercased (`sqlExpression`, `sqlText`). This is consistent SDK-wide. -- **Category:** 3 (acronym casing — `SQL` becoming `sql` is debatable; SDK has settled on lowercase, so this matches). -- **Suggested name:** Keep `sqlState`. Flagged for completeness. -- **Rationale:** TS convention varies on multi-letter acronyms; google-ts-style says lowercase initial; SDK follows the convention. - -### 16. `ServiceErrorCode.CANCELLED` (double-l) vs `StatementStatus_State.CANCELED` (single-l) — `src/v1/model.ts:62, 90` -- **Why weird:** Same English word, two spellings, in two enums in the same file. `CANCELLED` is British; `CANCELED` is American. The wire chose differently for the two enums; the SDK mirrors the wire. End users have to remember "cancel with one or two Ls". -- **Category:** 13 (spelling/tense inconsistency — see #10), 17 (asymmetric pair). -- **Suggested name:** Normalise upstream. If kept, document the spelling difference in `@databricks/sdk-databricks` README. -- **Rationale:** The spelling difference is invisible in casual scanning but breaks copy/paste. - -### 17. `waitTimeout` is a string-encoded duration — `src/v1/model.ts:264` -- **Why weird:** `waitTimeout?: string` with JSDoc explaining it must be formatted as `"Ns"` where N is 0 or 5-50. So a *typed string* with a private DSL inside. Users will write `"5s"` and hope, or worse: `5` (number, won't compile). The wire format is a proto Duration, but the TS surface could parse `number` (seconds) or `Duration` (ms) and emit `Ns`. -- **Category:** 1 (vague — `string`-typed numeric), 6 (misleading — a "timeout" with arbitrary string content), 14 (proto/Go-style — Duration carry-over). -- **Suggested name:** Keep `waitTimeout` but change the type to `number` (seconds) and let the marshaller produce `Ns`. Or `Duration` from `@databricks/sdk-core/wkt`. -- **Rationale:** Letting users pass arbitrary strings into a numeric field is a contract violation waiting to happen. - -### 18. `onWaitTimeout` field with `TimeoutAction` enum — `src/v1/model.ts:272` -- **Why weird:** Field is `onWaitTimeout`, type is `TimeoutAction`. The two names don't share the prefix `Wait*` even though they're tightly coupled. A reader sees `onWaitTimeout?: TimeoutAction` and has to chase the docs to learn the enum members are about wait-timeouts. -- **Category:** 17 (asymmetric field/type naming), 12 (duplicate concept — `Wait`/`Timeout` overloaded). -- **Suggested name:** Rename the enum to `OnWaitTimeoutAction` or, per #5, `OnTimeout`. -- **Rationale:** Field/type symmetry is a strong signal. - -### 19. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:187` +### 7. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:195` - **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. - **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). - **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. - **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. -### 20. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +### 8. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` - **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. - **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). - **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). - **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. -### 21. `chunks` array + `totalChunkCount` redundancy — `src/v1/model.ts:453-462` -- **Why weird:** `ResultManifest.chunks` is an array of `ChunkInfo`; `totalChunkCount` is `chunks.length`. The two carry the same information; on the wire there is a sender-receiver invariant, but TS users can compute one from the other. The naming gives no hint of the redundancy. -- **Category:** 12 (duplicate concept), 1 (vague — both fields are about the same property). -- **Suggested name:** Drop `totalChunkCount`; users compute via `chunks?.length`. -- **Rationale:** Two fields that mean the same thing should not both be public. - -### 22. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:418` +### 9. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:422` - **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. - **Category:** 16 (field-vs-format contradicts domain when format differs). - **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. - **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. -### 23. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` -- **Why weird:** Companion to #22. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. +### 10. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +- **Why weird:** Companion to #9. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. - **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. - **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. -### 24. Every field on every request type is optional — `src/v1/model.ts` (every interface) +### 11. Every field on every request type is optional — `src/v1/model.ts` (every interface) - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). - **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. -### 25. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` -- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). #14 already flags the type for overlap with `ApiError`; this finding flags the `Service` mid-position as a proto/Java-RPC architectural leak. +### 12. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` +- **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementError` — domain-named, mirrors the surrounding `Statement*` vocabulary. - **Rationale:** Architectural-layer words ("Service", "Server", "Backend") in user-facing type names are proto/RPC framework carry-overs. Domain-named alternatives compose better with the rest of the package surface. -### 26. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` -- **Why weird:** Same `Service` mid-position architectural leak as #25, applied to the code enum. #2 already flags the enum for duplicating `google.rpc.Code`; this finding flags the `Service` qualifier specifically as a proto-RPC architectural noun. +### 13. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` +- **Why weird:** Same `Service` mid-position architectural leak as #12, applied to the code enum. A TS consumer reads `ServiceErrorCode` and sees an architectural noun rather than the domain concept. - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). -- **Suggested name:** `StatementErrorCode` if the enum is retained; ideally fold into canonical `apierror/codes` per #2. -- **Rationale:** Pair with #25 — the `Service` qualifier carries no domain meaning at the use site. +- **Suggested name:** `StatementErrorCode`. +- **Rationale:** Pair with #12 — the `Service` qualifier carries no domain meaning at the use site. -### 27. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` +### 14. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` - **Why weird:** Underscore-joined identifier `StatementStatus_State` directly transcribes the proto nested-message name into TS. The source file even carries an `eslint-disable` for `@typescript-eslint/naming-convention` with the comment "Proto-style nested enum name." That comment confirms it: the name is a verbatim proto leak, not a TS-idiomatic choice. As a top-level export from `index.ts`, every consumer sees the underscore. - **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). - **Suggested name:** `StatementState` (the `Status` parent is itself a thin wrapper; the state is the meaningful enum) or `StatementStatusState` (no underscore) if both halves matter. - **Rationale:** Proto nested-type underscores are an artefact of code generation from `.proto`. TS has no nested-type concept; flattening to a single CamelCase name removes the leak. -### 28. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` +### 15. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` - **Why weird:** Another underscore-joined name with the same `eslint-disable` and an explicit "Proto-style nested message name" comment. The type exists because proto3 represents `map` as a synthetic nested `*Entry` message; gRPC generators surface this as a nested type. In TS the wire shape is just `Record` (see `httpHeaders` on `ExternalLink`). Re-exporting `ExternalLink_HttpHeadersEntry` from `index.ts` exposes proto machinery the JS user never needs. -- **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape), 12 (duplicate concept — `httpHeaders` is already typed `Record`). +- **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). - **Suggested name:** Delete the type. The `httpHeaders` field is already `Record | undefined`; no consumer needs the synthetic map-entry pair. - **Rationale:** Proto `map` synthetic `*Entry` messages should not surface in user-facing TS types. The information is fully captured by `Record`. -### 29. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` +### 16. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` - **Why weird:** Four enums (`Disposition`, `Format`, `TimeoutAction`, `StatementStatus_State`) carry a `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, `STATE_UNSPECIFIED` first variant. These are proto3 enum convention: every enum must have a `_UNSPECIFIED = 0` member because the default scalar value is required to be valid. JS/TS has no such constraint — `undefined` already encodes "not specified". So the enums carry a value that exists *only* to satisfy proto3 codegen requirements. End users have to filter out the unspecified variant manually when narrowing. - **Category:** 14 (proto/protobuf convention leak), 6 (misleading — the variant has no domain meaning), 1 (vague — `UNSPECIFIED` is the literal default state). - **Suggested name:** Drop the `*_UNSPECIFIED` variants. TS uses `Disposition | undefined` for "not set". @@ -223,84 +119,28 @@ to read every one to pick the right tool. See finding #1. ## Low severity -### 30. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` +### 17. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` - **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. - **Category:** 17 (acceptable asymmetry). - **Suggested name:** Keep. -### 31. `rowOffset`, `rowCount`, `byteCount` triple — `src/v1/model.ts:109, 111, 116` -- **Why weird:** Three integer fields on `ChunkInfo` (and parallel on `ExternalLink` and `ResultData`) that record per-chunk metrics. The pattern is the same across types; consider extracting to a shared `ChunkMetrics` mixin. The names are fine. -- **Category:** 12 (duplicate concept — three types carry the same fields). -- **Suggested name:** Extract `ChunkMetrics` shared interface. -- **Rationale:** Trio-replicated types are a tell. - -### 32. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` -- **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The TS type doesn't signal this. Names like `secretHeaders` or wrapper types like `SensitiveString` would surface the constraint. -- **Category:** 16 (field-vs-domain contradiction — sensitive content with normal-string type). -- **Suggested name:** Keep `httpHeaders` but tag the type or document at the type level. +### 18. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +- **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The field name doesn't signal this. A name like `secretHeaders` would surface the constraint at the use site. +- **Category:** 16 (field-vs-domain contradiction — sensitive content, neutral field name). +- **Suggested name:** `secretHeaders`, or document the sensitivity at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 33. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +### 19. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` - **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. - **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). - **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. -### 34. `QueryTag.key` and `QueryTag.value` — `src/v1/model.ts:404-405` -- **Why weird:** Generic key-value pair. `tagKey` + `tagValue` are common alternatives. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** Acceptable in context. - ## Observations (non-fixable here) -### O-1. URL string concatenation handles `undefined` silently — `src/v1/client.ts:76, 187, 223` +### O-1. URL string concatenation handles `undefined` silently — `src/v1/client.ts:78, 195, 234` - The URL is built via template literals like ``${this.host}/api/2.0/sql/statements/${req.statementId ?? ''}/cancel``. If `statementId` is `undefined`, the URL becomes `.../sql/statements//cancel`, which the server will return 404 for. The fallback to empty string is a silent-failure pattern. Names are fine; the fallback semantics are wrong. - -### O-2. Statement IDs share a vocabulary with `queryexecution` and `queryhistory`. -- All three packages emit some flavour of `statementId`. The naming should be - unified at the apierror / statement-vocabulary layer if it matters. - -### O-3. Module-level JSDoc lives in leaf files instead of `index.ts`. -- `index.ts` has no module-level JSDoc; `model.ts` has none either. Other - packages document scope and the API at `index.ts`. The naming choices flagged - above (e.g. `Format`, `Disposition`, `Client`) would be less confusing if - `index.ts` explained the package scope and contrasts with sibling packages. - ---- - -## Overlap with `queryexecution` — explicit comparison - -The audit prompt asked specifically to flag the overlap. Here's the explicit -mapping of vocabulary shared between the two packages: - -| Concept | statementexecution | queryexecution | -| --- | --- | --- | -| Primary identifier | `statementId` (primary) | `statementId` (audit-only copy of `dataToken`) | -| "Truncated" boolean | `ResultManifest.truncated` (truncation of result set) | `SuccessStatus.truncated` (truncation of dashboard query result) | -| Cancel operation | `cancelStatement()` | `cancelPublishedQueryExecution()` | -| Execute operation | `executeStatement()` | `executePublishedDashboardQuery()` | -| Poll operation | `getStatementResult()` (also returns first chunk) | `pollPublishedQueryStatus()` | -| State terminology | `StatementStatus_State.{PENDING, RUNNING, SUCCEEDED, FAILED, CANCELED, CLOSED}` | `QueryResponseStatus.{success, pending, canceled, closed}` (discriminated union) | -| Cancellation spelling | `CANCELED` (single-l) | `canceled` (single-l, lowercase) | -| Generic `Client` name | yes | yes | -| Verb-tense | `cancelStatement` | `cancelPublishedQueryExecution` | - -The two packages model semantically distinct operations (general SQL Statement -Execution vs Lakeview-dashboard query lifecycle) but share enough vocabulary -(`Statement`, `Query`, `Cancel`, `Execute`, `Status`) that a user importing -both will be confused. The fix is at the naming/package level (see #1) and -the cross-package vocabulary alignment (#11, #16). - ---- - -## Themes - -1. **Per-package error-code enum.** `ServiceErrorCode` mimics `google.rpc.Code` inside a single API package, parallel to the canonical `apierror/codes` module. Generator-wide; the fix is to map wire codes through the canonical apierror layer. -2. **Generic top-level names.** `Format`, `Disposition`, `Schema`, `Client`, `ServiceError`. Each one is fine in isolation but collides with the surrounding ecosystem (other SDKs, zod, language builtins). -3. **Package-name competition.** `statementexecution` lives alongside `queryexecution`, `commandexecution`, and `queries` — four near-synonymous names for related-but-distinct execution surfaces. -4. **Polymorphic types pretending to be flat.** `ResultData` (inline vs external links), `StatementResponse` (executeStatement vs getStatementResult), `ChunkInfo` (manifest entry vs response chunk). Discriminated unions would surface the variants. -5. **Proto/RPC architectural leaks.** `Service` mid-position on `ServiceError` / `ServiceErrorCode` (architectural-layer noun); `StatementStatus_State` and `ExternalLink_HttpHeadersEntry` proto-style underscored nested names; `*_UNSPECIFIED` enum zero values across four enums. Each is a verbatim transcription of proto/gRPC machinery into TS where the equivalent concept (`undefined`, `Record`, flat enums) is already idiomatic. diff --git a/.agent/naming-audit/storageconfigurations.md b/.agent/naming-audit/storageconfigurations.md index 4515d0be..f9ed20cd 100644 --- a/.agent/naming-audit/storageconfigurations.md +++ b/.agent/naming-audit/storageconfigurations.md @@ -7,31 +7,15 @@ workspaces in an account). **Total weird names flagged:** 4 -This audit is scoped to proto-architectural-leak naming (mid-position -`Public`/`Internal`/`External`, `Proto` suffix/infix, architectural-layer -words such as `Service`/`Manager`/`Wrapper`, `Impl`, `Rpc`/`Grpc`, -`Foo_PublicRequest`-style paired naming, etc.). Domain words like -`External*`/`Online*` and standard end-position suffixes (`Request`, -`Response`, `Info`) are not flagged here. - ## Summary -| Severity | Count | -| ------------ | ----- | -| High | 4 | -| Medium | 0 | -| Low | 0 | -| Observation | 0 | - -All 4 remaining findings are the same category: `Public` suffix on -`Client` methods leaking from the upstream proto/service layout into the -TS surface. The request/response interfaces and marshal schema were -renamed in regeneration; the `Client` method names are the last -surviving carriers of the leak. +| Severity | Count | +| -------- | ----- | +| High | 4 | ## High severity -### 1. `Client.createStorageConfigurationPublic` — `src/v1/client.ts:70` +### 1. `Client.createStorageConfigurationPublic` — `src/v1/client.ts:67` - **Why weird:** A method on the `Client` class whose name ends in `Public`. Reads as "the method on the public class that calls the public endpoint" — the suffix only exists because the underlying @@ -41,41 +25,29 @@ surviving carriers of the leak. - **Suggested:** `createStorageConfiguration`. - **Rationale:** Methods on `Client` are inherently public; the suffix is meaningless to a TS caller. -- **Status:** Still present after regeneration on 2026-05-26. +- **Status:** Still present after regeneration on 2026-06-01. -### 2. `Client.deleteStorageConfigurationPublic` — `src/v1/client.ts:99` +### 2. `Client.deleteStorageConfigurationPublic` — `src/v1/client.ts:96` - **Why weird:** Same `Public` suffix on `Client` method as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `deleteStorageConfiguration`. - **Rationale:** Same as #1. -- **Status:** Still present after regeneration on 2026-05-26. +- **Status:** Still present after regeneration on 2026-06-01. -### 3. `Client.getStorageConfigurationPublic` — `src/v1/client.ts:124` +### 3. `Client.getStorageConfigurationPublic` — `src/v1/client.ts:121` - **Why weird:** Same `Public` suffix on `Client` method as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `getStorageConfiguration`. - **Rationale:** Same as #1. -- **Status:** Still present after regeneration on 2026-05-26. +- **Status:** Still present after regeneration on 2026-06-01. -### 4. `Client.listStorageConfigurationPublic` — `src/v1/client.ts:149` +### 4. `Client.listStorageConfigurationPublic` — `src/v1/client.ts:146` - **Why weird:** Same `Public` suffix on `Client` method as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `listStorageConfigurations` (drop `Public`; pluralise while renaming). - **Rationale:** Same as #1. -- **Status:** Still present after regeneration on 2026-05-26. - -## Medium severity - -_None._ - -## Low severity - -_None._ - -## Observation - -_None._ +- **Status:** Still present after regeneration on 2026-06-01. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md index 7c9c09bd..4bd74047 100644 --- a/.agent/naming-audit/supervisoragents.md +++ b/.agent/naming-audit/supervisoragents.md @@ -11,15 +11,13 @@ resource types: `SupervisorAgent` (top-level), `Tool` (child of in-context steering). Every list endpoint paginates via `pageSize`/`pageToken`. No state enums exist in this package; the entire surface is data plus references to other Databricks resources. -**Total weird names flagged:** 13 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 4 | -| Low | 1 | -| Observation | 3 | +| High | 2 | +| Observation | 2 | ## High severity @@ -35,72 +33,12 @@ surface is data plus references to other Databricks resources. - **Suggested name:** `AgentTool`, `SupervisorTool`, or `RegisteredTool`. The qualifier disambiguates against generic `Tool` collisions in a multi-package import set. - **Rationale:** Same reasoning as #1; specificity in type names prevents alias collisions and makes import lists self-documenting. -### 3. `Tool.toolType: string` — stringly-typed when it is a closed set — `src/v1/model.ts:227-228` -- **Why weird:** The JSDoc enumerates the allowed values: `"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "dashboard", "serving_endpoint", "table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`. The type is `string`, so a caller writing `toolType: 'GENIE_SPACE'` (wrong case), `'genieSpace'` (camelCase), or `'web-search'` (kebab) gets no compiler help. The same struct *already* carries the discriminant in the `spec` discriminated union: `spec.$case` ranges over `'genieSpace' | 'knowledgeAssistant' | ...`. So the SDK declares the type domain twice, in two incompatible casings (snake on `toolType`, camel on `spec.$case`). Worse: the `toolType` enumeration in the doc includes 14 values while the `spec` discriminated union only covers 6 — the two declarations are not even aligned in cardinality. -- **Category:** 16 (field contradicts type domain — `string` for a closed set), 6 (misleading — two declarations of the same enum), 12 (duplicate of `spec.$case`), 17 (snake vs camel for the same enum). -- **Suggested name:** Either (a) convert `toolType` to a string-literal union matching the enumerated wire values, or (b) drop `toolType` entirely because `spec.$case` already encodes the variants the SDK supports (recommended). -- **Rationale:** Stringly-typed enums in TypeScript are a well-documented anti-pattern (https://google.github.io/styleguide/tsguide.html#enums-vs-string-literals). The duplicate declaration in two casings is a generator artifact from the proto definition and a tax on every consumer. - -### 4. `KnowledgeAssistant` package name collision — `src/v1/model.ts:120` -- **Why weird:** The package `@databricks/sdk-supervisoragents` exports a type `KnowledgeAssistant` that represents *one variant of a Tool.spec discriminated union*, not the actual knowledge assistant resource. The actual `KnowledgeAssistant` resource lives in `@databricks/sdk-knowledgeassistants/v1`. A consumer importing both packages will collide on the same identifier in TS source — and the supervisor-agents type only has two fields (`servingEndpointName`, `knowledgeAssistantId`) while the real one has 12+. This is the same problem as #1/#2 but at the cross-package level. The same applies to `GenieSpace` (a single deprecated `id` field) vs the canonical Genie space resource elsewhere in the SDK. -- **Category:** 12 (duplicate concept across packages), 6 (misleading — same name, different shape). -- **Suggested name:** `KnowledgeAssistantToolSpec`, `KnowledgeAssistantRef`, or `ToolKnowledgeAssistant`. Apply the suffix uniformly to all 6 variants (`GenieSpaceRef`, `UcFunctionRef`, etc.). -- **Rationale:** Cross-package name collisions are the worst kind of naming bug because the import path lies about the type's identity. A `Ref`/`ToolSpec` suffix on every variant solves this uniformly. - -### 5. `KnowledgeAssistant.servingEndpointName` is a deprecated alias inside a variant type — `src/v1/model.ts:121-122` -- **Why weird:** The `KnowledgeAssistant` variant type (one of 6 tool kinds) has two fields: - - `servingEndpointName?: string` — doc "Deprecated: use knowledge_assistant_id instead." - - `knowledgeAssistantId?: string` — doc "The ID of the knowledge assistant." - Both fields are optional. A consumer setting both gets an ambiguous wire payload (the backend has to pick one). Plus, the field name `servingEndpointName` does not even *imply* "knowledge assistant" — it implies a model-serving endpoint. The naming of the deprecation target is also misleading: a knowledge assistant *id* is not necessarily the same wire value as a serving-endpoint *name*. The doc-comment claim that one replaces the other is suspect. -- **Category:** 6 (misleading — name and replacement don't obviously equate), 16 (field name from wrong domain — "serving endpoint" applies to a different resource). -- **Suggested name:** Apply `@deprecated`; consider dropping the field entirely if `knowledgeAssistantId` fully supplants it. Document the migration mapping precisely. -- **Rationale:** This is a deprecation transition mid-flight; the public TS surface should signal it correctly. - -## Medium severity - -### 6. `SupervisorAgent.createTime: Temporal.Instant` — `src/v1/model.ts:211-212` -- **Why weird:** `Temporal.Instant` is correct (good!) but the field name `createTime` follows AIP-142 (https://google.aip.dev/142). Compare with `customllms.CustomLlm.creationTime: Temporal.Instant` (audited as inconsistent) — the supervisor-agents package uses the AIP form, the customllms package does not. This is positive consistency on supervisor-agents and negative on customllms. Flagging here because the audit covers SDK-wide consistency. -- **Category:** Observation / 17 (cross-package inconsistency). -- **Suggested name:** Keep `createTime`; flag `customllms` to align. -- **Rationale:** Note positive precedent; pair with the audit on `customllms` to align it. - -### 7. `Tool.toolId` is "user-specified ID" while wire name is camelCased — `src/v1/model.ts:240-241` -- **Why weird:** Doc reads "User specified id of the Tool." Comparing with `CreateToolRequest.toolId` (model.ts:37-41, "The ID to use for the tool, which will become the final component of the tool's resource name."), the two `toolId` fields are *the same wire concept* — but on `Tool` it is the persisted id, while on `CreateToolRequest` it is the request-time supplied id. The same field name is doing two semantic jobs depending on context. Plus, comparing with `Example.exampleId` (model.ts:83-84, "The universally unique identifier (UUID) of the example."), the format claim differs: `Tool.toolId` is *user-specified*, `Example.exampleId` is a *UUID*. The two id formats are not aligned across sibling types in the same package. -- **Category:** 17 (inconsistency across sibling types), 6 (misleading — different format claims). -- **Suggested name:** Keep `toolId` and `exampleId` but expand the JSDoc on each to disambiguate the id-format contract. Or rename `Tool.toolId` → `toolKey` to mirror that it is a user-supplied identifier (as opposed to a server-generated UUID). -- **Rationale:** A naming audit must flag fields whose format contract is silent in the type signature. - -### 8. `CreateToolRequest.toolId` separately on the request — `src/v1/model.ts:37-41` -- **Why weird:** The create request takes both `tool: Tool` (the body) *and* `toolId: string` (the URL/query param). The wire form is `POST /supervisor-agents/{id}/tools?tool_id={user-supplied}`. So `req.toolId` flows into the query string and `req.tool.toolId` is *not used* on creation — but TypeScript does not enforce this. A consumer who writes `{tool: {toolId: 'foo'}}` and leaves `req.toolId` undefined gets unexpected behavior. The two-fields-for-one-concept pattern is also documented in `customllms.md` #20. -- **Category:** 12 (duplicate concept on the same request), 6 (misleading — `tool.toolId` looks usable on creation but isn't), 17. -- **Suggested name:** Either remove `tool.toolId` from the body shape (TypeScript can enforce this via a discriminated `Omit` type for create), or document the precedence rule on the JSDoc. -- **Rationale:** Generated request types with duplicate fields are a well-known footgun. - -### 9. `Client` class name — bare, no scoping — `src/v1/client.ts:61` -- **Why weird:** The class is named `Client`. After `import {Client} from '@databricks/sdk-supervisoragents/v1'`, the type is unambiguous in isolation — but consumers importing multiple packages routinely write `import {Client as SAClient} from '@databricks/sdk-supervisoragents/v1'`. Same SDK-wide issue flagged in `knowledgeassistants.md` #30. -- **Category:** 1 (vague), 17 (SDK-wide inconsistency). -- **Suggested name:** `SupervisorAgentsClient` (matches the Go SDK's `WorkspaceClient.SupervisorAgents` and AWS SDK's `S3Client`, `IAMClient` pattern). -- **Rationale:** Bare `Client` is convenient until you import two SDK packages; then it's a tax. - -## Low severity - -### 10. `Volume`/`UcFunction`/`UcConnection` — `Uc` prefix on some, bare on others — `src/v1/model.ts:245,249,286` -- **Why weird:** Of the variant types, three are Unity Catalog resources: `Volume`, `UcFunction`, `UcConnection`. The `Uc` prefix is applied to two but not to `Volume` — even though a Databricks volume is *always* a UC volume. The `Uc` prefix is also inconsistent acronym casing: `Uc` (title-case) instead of `UC` (all-caps), and the Google TypeScript style guide could go either way (https://google.github.io/styleguide/tsguide.html#identifiers). Same acronym-casing question as flagged in `customllms.md` #1 (`Llm` vs `LLM`). -- **Category:** 3 (acronym casing — `Uc` vs `UC`), 17 (inconsistent prefix application — `Volume` should be `UcVolume`). -- **Suggested name:** Either drop the `Uc` prefix everywhere (the package context makes it clear) or apply it uniformly: `UcVolume`, `UcFunction`, `UcConnection` (with the acronym-casing question decided once SDK-wide). -- **Rationale:** Consistency wins; the audit prompt rule 3 (acronym casing) and rule 17 (consistent action verbs / family naming) both flag this. - ## Observations -### 11. `Tool.toolType` doc lists 14 kinds but `Tool.spec` union covers only 6 — `src/v1/model.ts:227,230-237` -- **Why weird:** The JSDoc on `Tool.toolType` enumerates 14 wire values (`"genie_space", "knowledge_assistant", "uc_function", "uc_connection", "app", "volume", "dashboard", "serving_endpoint", "table", "vector_search_index", "catalog", "schema", "supervisor_agent", "web_search"`), but the `Tool.spec` discriminated union only encodes 6 of them (`genieSpace`, `knowledgeAssistant`, `ucFunction`, `app`, `volume`, `ucConnection`). The other 8 wire kinds — dashboard, serving_endpoint, table, vector_search_index, catalog, schema, supervisor_agent, web_search — can be set via `toolType` but have no corresponding `spec` variant. A consumer who writes `{toolType: 'dashboard'}` gets no type-system support for the dashboard payload because the variant doesn't exist. Either the backend has dropped those kinds (and the doc should be updated) or the TS surface is missing variants. -- **Category:** 16 (field contradicts type domain), 17 (doc vs type-shape mismatch), 6 (misleading). -- **Suggested name:** Reconcile the two declarations: either add the missing variants to `Tool.spec` or shrink the `toolType` enumeration to the supported subset. - -### 12. Action verbs in `Client` are consistent — `src/v1/client.ts` +### 3. Action verbs in `Client` are consistent — `src/v1/client.ts` - **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. - **Category:** 17 (reversed — consistency note). -### 13. Method-name verb conventions match resource targets — `src/v1/client.ts:92,121,153,194,216,238,260,288,316,341,395,452,506,550,597` +### 4. Method-name verb conventions match resource targets — `src/v1/client.ts:89,118,150,191,213,235,257,285,313,338,392,449,503,547,594` - **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. - **Category:** 17 (positive observation). diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index eb3676cf..074241d2 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -1,79 +1,43 @@ # Naming Audit: systemschemas -**Path:** `packages/systemschemas/src/v1/` +**Path:** `packages/uc/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 8 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 2 | +| High | 1 | +| Medium | 1 | | Low | 1 | -| Observation | 2 | +| Observation | 1 | ## High severity -### 1. Package name `systemschemas` collides with the sibling `schemas` package — `packages/systemschemas/` vs `packages/schemas/` -- **Why weird:** Two top-level packages for closely related Unity Catalog concepts: `schemas` (user-defined schemas: full CRUD with `CreateSchema`, `DeleteSchema`, etc.) and `systemschemas` (server-managed schemas: only enable/disable/list). A consumer searching `npm ls @databricks/sdk-*` sees two near-identical names; an import alias of `schemas` from either package shadows the other. -- **Category:** 12 (duplicate concept across packages). -- **Suggested name:** Either fold `systemschemas` into `schemas` as a `system` sub-namespace (`@databricks/sdk-schemas/system`), or rename to something less collision-prone such as `unityCatalogSystemSchemas` / `metastoreSystemSchemas`. -- **Rationale:** The two packages export different `Client` classes; the domain word `Schema` appears in both with overlapping vocabulary. Anything that lessens that overlap — even just keeping them under one package — would reduce caller confusion. - -### 2. `SystemSchemaInfo` — `src/v1/model.ts:53` +### 1. `SystemSchemaInfo` — `src/v1/model.ts:52` - **Why weird:** `Info` is a generic, content-free suffix on the package's central domain entity. This is *the* system schema — it should just be `SystemSchema`. The `Info` suffix is on the vague-suffix list in `typescript.mdc`. It also infects the field name (`schemas: SystemSchemaInfo[]`) which awkwardly reads as "an array of info". - **Category:** 1 (vague `Info`), 8 (redundant type suffix). - **Suggested name:** `SystemSchema`. - **Rationale:** `SystemSchema` is the noun consumers think about. `schemas: SystemSchema[]` reads cleanly; `schemas: SystemSchemaInfo[]` does not. -### 3. `SystemSchemaInfo.state: string` — `src/v1/model.ts:60` -- **Why weird:** Typed as `string` despite the doc enumerating six concrete values (`AVAILABLE | ENABLE_INITIALIZED | ENABLE_COMPLETED | DISABLE_INITIALIZED | UNAVAILABLE | MANAGED`). This is the package's only enum-shaped field and the only piece of state the consumer reads back, yet it ships as a stringly-typed value. Every other package in the SDK exposes such fields as TS enums. The comment "An empty string means the system schema is available and ready for opt-in" further muddles things — it contradicts `AVAILABLE` being one of the listed values. -- **Category:** 16 (field type contradicts the documented domain), 6 (misleading — doc says enum, type says `string`). -- **Suggested name:** Introduce `SystemSchemaState` enum with members `Available | EnableInitialized | EnableCompleted | DisableInitialized | Unavailable | Managed` and type the field `state: SystemSchemaState`. -- **Rationale:** Almost certainly a generator/upstream-API miss; the wire surface is enum-shaped and should round-trip through a TS enum. Worth raising upstream. - ## Medium severity -### 4. `DisableSystemSchemaRequest.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` -- **Why weird:** Marked optional, but `client.ts:75` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchemaRequest.metastoreId`, `DisableSystemSchemaRequest.schema`, `EnableSystemSchemaRequest.schema`, `ListSystemSchemasRequest.metastoreId`. +### 2. `DisableSystemSchemaRequest.metastoreId: string | undefined` is in fact required — `src/v1/model.ts:9` +- **Why weird:** Marked optional, but `client.ts:77` template-interpolates `${req.metastoreId ?? ''}` straight into the URL path `metastores/.../systemschemas/...`. An empty path segment yields a malformed URL (or a 404). The "optional" annotation is misleading. Same pattern on `EnableSystemSchemaRequest.metastoreId`, `DisableSystemSchemaRequest.schema`, `EnableSystemSchemaRequest.schema`, `ListSystemSchemasRequest.metastoreId`. - **Category:** 6 (misleading optionality), 16 (field type contradicts domain — these are mandatory path params). - **Suggested name:** Keep names; change type to non-optional. (Out of scope for a *naming* audit, but the optionality leaks into how the names should be interpreted.) - **Rationale:** Path-required fields must be required. Treating them as optional weakens the contract; the name `metastoreId` reads as "the metastore id" but the type says "you can omit this". -### 5. `Client` — `src/v1/client.ts:42` -- **Why weird:** Class is just `Client` (no domain qualifier). Once a consumer imports `import {Client} from '@databricks/sdk-systemschemas/v1'`, the bare name carries no clue about which API surface it talks to. The other generated packages have the same problem, so they all clash on import. -- **Category:** 1 (vague), 15 (generic). -- **Suggested name:** `SystemSchemasClient`. -- **Rationale:** Forces consumers to alias on import (`import {Client as SystemSchemasClient}`) if they ever combine clients. Every generated package has this issue; flagged for consistency. - ## Low severity -### 6. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:50`, `client.ts:185` -- **Why weird:** `listSystemSchemasIter` (client.ts:185) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. +### 3. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:49`, `client.ts:190` +- **Why weird:** `listSystemSchemasIter` (client.ts:190) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). -- **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:78-83) so callers see a consistent sentinel. +- **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:76-79) so callers see a consistent sentinel. - **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. ## Observations -### 7. Action-verb consistency in `Client` -Methods are `disable`, `enable`, `list` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. - -### 8. Domain noun overlap: `Schema`, `SystemSchema`, `schemas:` field, `Schema` zod -The word "schema" appears in this single package as a wire field, a domain noun (`SystemSchema`), the package name (`systemschemas`), and a library term (zod's `Schema`). Multiple overlapping uses of the same word in a 106-line model file. Worth raising as a package-design issue rather than a per-name fix. -- **Category:** 12 (duplicate concept), 17 (inconsistent meaning of same word within one module). - -## Domain glossary -- `metastore` — Unity Catalog metastore (container that owns catalogs/schemas). -- `system schema` — curated, Databricks-managed schema (e.g. `access`, `billing`, `lineage`) attached to a metastore via opt-in enablement. -- `catalog` — Unity Catalog catalog; the namespace that the enabled system schema appears under. -- `state` (enum-shaped string field): `AVAILABLE`, `ENABLE_INITIALIZED`, `ENABLE_COMPLETED`, `DISABLE_INITIALIZED`, `UNAVAILABLE`, `MANAGED` — undocumented externally; the source comment in `model.ts:57-58` is the only place these values are listed. -- `uc` — Unity Catalog (appears in URL paths only: `/api/2.1/unity-catalog/...`). -- `abac` / `oss` / `m2m` / `u2m` / `pat` / `wkt` — not encountered in this package. - -## File coverage -- `src/v1/model.ts` (106 lines): read fully. -- `src/v1/client.ts` (191 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (16 lines): read fully. +### 4. Action-verb consistency in `SystemSchemasClient` +Methods are `disableSystemSchema`, `enableSystemSchema`, `listSystemSchemas` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index 908c2dcc..c597e888 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -1,162 +1,24 @@ # Naming Audit: `tables` (v1) -**Path:** `/home/parth.bansal/sdk-js/packages/tables/` +**Path:** `/home/parth.bansal/sdk-js/packages/uc/tables/` **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, -`src/v1/index.ts` +`src/v1/index.ts`, `src/v1/transport.ts` **Package import path:** `@databricks/sdk-tables/v1` **Domain:** Unity Catalog tables (`/api/2.1/unity-catalog/tables`, `/api/2.1/unity-catalog/constraints`, `/api/2.1/unity-catalog/table-summaries`). -**Cross-package references:** - -- `catalogs/v1`, `connections/v1` — also export `SecurableType`. -- `volumes/v1`, `externallocations/v1` — also export `EncryptionDetails`, - `SseEncryptionAlgorithm`, `SseEncryptionDetails`. -- `catalogs/v1` — also defines `EffectivePredictiveOptimizationFlag`. -- `functions/v1`, `registeredmodels/v1` — also define the entire - `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / - `ConnectionDependency` / `CredentialDependency` family. -- `functions/v1` — also exports `ColumnTypeName`. -- `abacpolicies/v1` — defines `RowFilterOptions` / `ColumnMaskOptions` which - duplicate the role of this package's `RowFilter` / `ColumnMask`. -- `schemas/v1`, `functions/v1`, `registeredmodels/v1` — also use the - `fullNameArg` request-field pattern. -- `onlinetables/v1`, `database/v1`, `postgres/v1`, `featurestore/v1` — also - use the table-name modelling and the `MATERIALIZED_VIEW` / - `STREAMING_TABLE` / `MANAGED` lifecycle vocabulary. - **Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). --- -## Inventory - -### Enums (model.ts) - -1. `ColumnTypeName` (model.ts:5) — 24 values: `BOOLEAN`, `BYTE`, `SHORT`, - `INT`, `LONG`, `FLOAT`, `DOUBLE`, `DATE`, `TIMESTAMP`, `STRING`, `BINARY`, - `DECIMAL`, `INTERVAL`, `ARRAY`, `STRUCT`, `MAP`, `CHAR`, `NULL`, - `USER_DEFINED_TYPE`, `TIMESTAMP_NTZ`, `VARIANT`, `GEOMETRY`, `GEOGRAPHY`, - `TABLE_TYPE`. -2. `DataSourceFormat` (model.ts:33) — 26 values, most suffixed `_FORMAT`: - `DELTA`, `CSV`, `JSON`, `AVRO`, `PARQUET`, `ORC`, `TEXT`, `UNITY_CATALOG`, - `DELTASHARING`, `DATABRICKS_FORMAT`, `MYSQL_FORMAT`, `ORACLE_FORMAT`, - `POSTGRESQL_FORMAT`, `REDSHIFT_FORMAT`, `SNOWFLAKE_FORMAT`, `SQLDW_FORMAT`, - `SQLSERVER_FORMAT`, `SALESFORCE_FORMAT`, `SALESFORCE_DATA_CLOUD_FORMAT`, - `TERADATA_FORMAT`, `BIGQUERY_FORMAT`, `NETSUITE_FORMAT`, - `WORKDAY_RAAS_FORMAT`, `MONGODB_FORMAT`, `HIVE`, `VECTOR_INDEX_FORMAT`, - `DATABRICKS_ROW_STORE_FORMAT`, `DELTA_UNIFORM_HUDI`, - `DELTA_UNIFORM_ICEBERG`, `ICEBERG`. -3. `SecurableKind` (model.ts:78) — 70+ values, all prefixed with one of - `TABLE_`, `RECIPIENT_`, `CONNECTION_`, `CATALOG_`, `SCHEMA_`. -4. `SecurableType` (model.ts:162) — 17 values: `CATALOG`, `SCHEMA`, `TABLE`, - `STORAGE_CREDENTIAL`, `EXTERNAL_LOCATION`, `FUNCTION`, `SHARE`, `PROVIDER`, - `RECIPIENT`, `CLEAN_ROOM`, `METASTORE`, `PIPELINE`, `VOLUME`, `CONNECTION`, - `CREDENTIAL`, `EXTERNAL_METADATA`, `STAGING_TABLE`. -5. `SseEncryptionAlgorithm` (model.ts:183) — 3 values: - `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED`, `AWS_SSE_S3`, `AWS_SSE_KMS`. -6. `TableType` (model.ts:189) — 9 values: `MANAGED`, `EXTERNAL`, `VIEW`, - `MATERIALIZED_VIEW`, `STREAMING_TABLE`, `MANAGED_SHALLOW_CLONE`, `FOREIGN`, - `EXTERNAL_SHALLOW_CLONE`, `METRIC_VIEW`. -7. `OptionSpec_OauthStage` (model.ts:209) — 3 values: - `OAUTH_STAGE_UNSPECIFIED`, `BEFORE_AUTHORIZATION_CODE`, - `BEFORE_ACCESS_TOKEN`. -8. `OptionSpec_OptionType` (model.ts:222) — 8 values: - `OPTION_TYPE_UNSPECIFIED`, `OPTION_BOOLEAN`, `OPTION_NUMBER`, - `OPTION_BIGINT`, `OPTION_STRING`, `OPTION_ENUM`, - `OPTION_SERVICE_CREDENTIAL`, `OPTION_MULTILINE_STRING`. - -### Interfaces (model.ts) - -1. `ColumnInfo` (model.ts:233) — 12 fields (`name`, `typeText`, `typeName`, - `position`, `typePrecision`, `typeScale`, `typeIntervalType`, `typeJson`, - `comment`, `nullable`, `partitionIndex`, `mask`). -2. `ColumnMask` (model.ts:258) — 3 fields. -3. `ConnectionDependency` (model.ts:276) — 1 field. -4. `CreateTableConstraintRequest` (model.ts:281) — 2 fields. -5. `CreateTableRequest` (model.ts:287) — 38 fields. -6. `CreateTableRequest_PropertiesEntry` (model.ts:359) — 2 fields. -7. `CredentialDependency` (model.ts:365) — 1 field. -8. `DeleteTableConstraintRequest` (model.ts:370) — 3 fields. -9. `DeleteTableConstraintRequest_Response` (model.ts:383) — empty body. -10. `DeleteTableRequest` (model.ts:385) — 1 field. -11. `DeleteTableRequest_Response` (model.ts:391) — empty body. -12. `DeltaRuntimePropertiesKvPairs` (model.ts:397) — 1 field. -13. `DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` - (model.ts:403) — 2 fields. -14. `Dependency` (model.ts:412) — discriminated union (table / function / - connection / credential). -15. `DependencyList` (model.ts:422) — 1 field. -16. `EffectivePredictiveOptimizationFlag` (model.ts:427) — 3 fields. -17. `EncryptionDetails` (model.ts:437) — discriminated union (one variant: - `sseEncryptionDetails`). -18. `ForeignKeyConstraint` (model.ts:447) — 5 fields (`name`, `childColumns`, - `parentTable`, `parentColumns`, `rely`). -19. `FunctionDependency` (model.ts:461) — 1 field. -20. `GetTableRequest` (model.ts:466) — 4 fields. -21. `ListTableSummariesRequest` (model.ts:477) — 6 fields. -22. `ListTableSummariesRequest_Response` (model.ts:505) — 2 fields. -23. `ListTablesRequest` (model.ts:515) — 9 fields. -24. `ListTablesRequest_Response` (model.ts:543) — 2 fields. -25. `NamedTableConstraint` (model.ts:553) — 1 field. -26. `OptionSpec` (model.ts:563) — 14 fields. -27. `PolicyFunctionArgument` (model.ts:605) — discriminated union (column / - constant). -28. `PrimaryKeyConstraint` (model.ts:620) — 4 fields. -29. `RowFilter` (model.ts:631) — 3 fields. -30. `SecurableKindManifest` (model.ts:648) — 5 fields. -31. `SseEncryptionDetails` (model.ts:662) — 2 fields. -32. `TableConstraint` (model.ts:676) — discriminated union (primary key / - foreign key / named). -33. `TableDependency` (model.ts:694) — 1 field. -34. `TableExistsRequest` (model.ts:699) — 1 field. -35. `TableExistsRequest_Response` (model.ts:705) — 1 field (`tableExists`). -36. `TableInfo` (model.ts:710) — 36 fields (duplicates `CreateTableRequest` / - `UpdateTableRequest` field-by-field). -37. `TableInfo_PropertiesEntry` (model.ts:782) — 2 fields. -38. `TableSummary` (model.ts:787) — 3 fields. -39. `UpdateTableRequest` (model.ts:795) — 37 fields (`fullNameArg` + the same - set as `CreateTableRequest`). -40. `UpdateTableRequest_PropertiesEntry` (model.ts:869) — 2 fields. -41. `UpdateTableRequest_Response` (model.ts:875) — empty body. - -### Zod schemas (model.ts) - -- Unmarshal: schemas for the response and structural types. -- Marshal: a near-parallel set of `marshal…Schema` symbols (no - `marshal…Schema` for path-only requests with no body). - -### Client (client.ts) - -- Class `Client` (client.ts:60). -- Public methods: `createTable`, `createTableConstraint`, `deleteTable`, - `deleteTableConstraint`, `getTable`, `listTableSummaries`, - `listTableSummariesIter`, `listTables`, `listTablesIter`, `tableExists`, - `updateTable`. -- Private fields: `host`, `httpClient`, `logger`, `userAgent`. -- Module constant: `PACKAGE_SEGMENT` (client.ts:55). - -### Utils (utils.ts) - -- Interface: `HttpCallOptions`. -- Functions: `executeCall`, `readAll`, `executeHttpCall`, `buildHttpRequest`, - `parseResponse`, `marshalRequest`, `flattenQueryParams`. - -### Index (index.ts) - -- Re-exports `Client`, 8 enums, and 38 interfaces. - ---- - ## Summary (counts) | Severity | Count | | --------------------- | ----- | -| High | 11 | +| High | 4 | | Medium | 6 | -| Low / SDK-wide note | 3 | -| Pass / acceptable | 8 | -| **Total findings** | **28** | +| Pass / acceptable | 6 | +| **Total findings** | **16** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -165,50 +27,9 @@ findings.) ## Findings -### 1. `DeltaRuntimePropertiesKvPairs` type name vs. `deltaRuntimePropertiesKvpairs` field name acronym-casing mismatch — category 3 (Acronym casing inconsistencies) - -**Symbols:** -- Type: `DeltaRuntimePropertiesKvPairs` (model.ts:397) — `KvPairs` (capital - `P`). -- Field: `deltaRuntimePropertiesKvpairs` (model.ts:339, 762, 849) — `Kvpairs` - (lowercase `p`). - -**Issue:** The same word ("KvPairs") is cased differently across type and -field names *within the same generated package*: - -```ts -// type name -export interface DeltaRuntimePropertiesKvPairs { ... } // KvPairs - -// field name on TableInfo / CreateTableRequest / UpdateTableRequest -deltaRuntimePropertiesKvpairs?: DeltaRuntimePropertiesKvPairs | undefined; -// ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ -// Kvpairs (field) KvPairs (type) -``` - -The wire form is `delta_runtime_properties_kvpairs` — snake_case with two -underscores around `kvpairs` (not three). The field-name camelCase -conversion turns `kvpairs` into one camelCase token; the type-name -PascalCase keeps `KvPairs` as two tokens. The mismatch is purely a -generator quirk: it tokenizes the wire string differently for struct names -vs. field names. - -**Suggested:** unify casing. -- Either `DeltaRuntimePropertiesKvpairs` (field-consistent — but breaks the - acronym-rule from the Google style guide which keeps multi-letter - acronyms readable, e.g. `xmlHttpRequest`). -- Or `deltaRuntimePropertiesKvPairs` (type-consistent — and "Kv" / "Pairs" - read naturally as two words). - -**Prefer the type-consistent form.** Apply on the field. Cross-reference -the proto-source field naming convention. **Flag for SDK-wide generator -cleanup.** +### 1. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) ---- - -### 2. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) - -**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:397). +**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:401). **Issue:** `Kv` (key-value) is borderline cryptic for a TypeScript API; the "Pairs" suffix is redundant if `Kv` already means key-value. The type holds @@ -221,206 +42,10 @@ self-describing). --- -### 3. SSE acronym casing in `SseEncryptionAlgorithm` / `SseEncryptionDetails` — category 3 (Acronym casing inconsistencies) - -**Symbols:** `SseEncryptionAlgorithm` (model.ts:183), -`SseEncryptionDetails` (model.ts:662), `sseEncryptionDetails` (field name in -`EncryptionDetails` discriminator at model.ts:440). - -**Issue:** "SSE" is a three-letter acronym (Server-Side Encryption). Google -TS Style Guide § 5.1 says multi-letter acronyms should be cased like -ordinary words (e.g. `xmlHttpRequest`, not `XMLHTTPRequest`). The current -form `Sse…` is *correct* under that rule. However, all enum members use -`AWS_SSE_S3` / `AWS_SSE_KMS` / `SSE_ENCRYPTION_ALGORITHM_UNSPECIFIED` — -keeping the full upper-case acronym in the wire values. The split makes the -TS identifier rule and the wire value rule diverge: `Sse` in code, -`SSE` on the wire. - -This is consistent with the rest of the SDK (`HttpClient`, `JsonStringify` -etc.) but is worth flagging for anyone reviewing this file fresh. - -**Pass** under Google's rule; **note** the inconsistency for SDK-wide review. - ---- - -### 4. `SecurableType` is a generic identifier name shared with `catalogs` / `connections` — category 12 (Duplicate concepts) and category 1 (Vague/generic) - -**Symbol:** `SecurableType` (model.ts:162). - -**Issue:** `SecurableType` is also exported from `catalogs/v1/model.ts:28`, -`connections/v1/model.ts:109`, and at least two other audited packages. -Each definition is the same enum with the same 17 values. Five copies of -the same enum across the SDK. The values overlap with `SecurableKind` -(model.ts:78) but are at a different level of granularity (a `TABLE` of -`SecurableType` maps to ~50 `TABLE_*` `SecurableKind` values). - -Within the `tables` package, `SecurableType` only appears on -`SecurableKindManifest.securableType` (model.ts:650) — a single field on a -single type. The enum's *value* to this package is marginal: a consumer -who already has a `TableInfo` knows it's a `TABLE`. - -**Suggested:** hoist to `@databricks/sdk-core/securable` or similar. -**SDK-wide cleanup.** - ---- - -### 5. `ColumnTypeName.TABLE_TYPE` collides with the `TableType` enum domain — category 6 (Misleading names) and category 16 (Field contradicting type domain) - -**Symbol:** `ColumnTypeName.TABLE_TYPE` (model.ts:29). - -**Issue:** A value in `ColumnTypeName` is named the same as the -*type-name* of another enum in this file: - -- `ColumnTypeName.TABLE_TYPE` — a column-data-type value of "table". -- `TableType` (model.ts:189) — the *enum* describing kinds of UC tables - (`MANAGED`, `EXTERNAL`, `VIEW`, …). - -A reader scanning the file sees `TABLE_TYPE` as a `ColumnTypeName` value -and `TableType` as a separate enum — but the names overlap, suggesting they -are related. They are not: one is about Spark column SQL types ("the column -holds a table"), the other is about UC table classifications. - -**Suggested:** -- Rename `TABLE_TYPE` → `TABLE` (matches the pattern: `ARRAY`, `STRUCT`, - `MAP` are the same kind of compound type). - -**Coordinate with protocol.** - ---- - -### 6. `DataSourceFormat` enum values split between `_FORMAT` suffix and bare forms — category 17 (Inconsistent action verbs) - -**Symbols:** `DataSourceFormat` values (model.ts:33–75). - -**Issue:** 18 of the 26 values carry a `_FORMAT` suffix -(`DATABRICKS_FORMAT`, `MYSQL_FORMAT`, etc.), but 8 are bare (`DELTA`, `CSV`, -`JSON`, `AVRO`, `PARQUET`, `ORC`, `TEXT`, `UNITY_CATALOG`, `HIVE`, -`DELTASHARING`, `DELTA_UNIFORM_HUDI`, `DELTA_UNIFORM_ICEBERG`, `ICEBERG`). -The split is along provenance: the bare values are the "native" Databricks -formats; the `_FORMAT` suffix marks query-federation source formats (added -later, per the `BEGIN`/`END` comments at model.ts:44, 63). - -So the suffix carries semantic information (source-federation vs. native). -But that distinction should be expressed *outside* the wire string — e.g. a -boolean `isFederationSource` on a richer type, or two enums. The current -form has the suffix as a soft tag inside one enum. - -For consumers, this means writing: -```ts -if (format === 'DELTA' || format === 'PARQUET') {} // bare -if (format === 'MYSQL_FORMAT' || format === 'POSTGRESQL_FORMAT') {} // suffix -``` - -**Suggested:** drop `_FORMAT` suffixes on the TS identifiers -(`MYSQL = 'MYSQL_FORMAT'`); the wire string remains. Cross-reference -`connections.ConnectionType` for the same domain. - ---- - -### 7. `DataSourceFormat.DELTASHARING` (no underscore) vs. `DELTA_UNIFORM_HUDI` (underscore-split) — category 17 (Inconsistent action verbs) - -**Symbols:** `DataSourceFormat.DELTASHARING` (model.ts:43), -`DataSourceFormat.DELTA_UNIFORM_HUDI` (model.ts:70). - -**Issue:** Inconsistent tokenisation within the same enum: -- `DELTASHARING` — single token ("delta sharing" without separator). -- `DELTA_UNIFORM_HUDI` — three tokens. - -The wire form for "delta sharing" *should* be `DELTA_SHARING` to follow the -pattern, but the protocol team chose `DELTASHARING`. Same problem exists -across `SecurableKind` (`TABLE_DELTASHARING`, `TABLE_DELTA_ICEBERG_DELTASHARING`, -etc.). - -**Suggested:** push back upstream — `DELTA_SHARING` would be more -consistent. **Not a per-package fix.** - ---- - -### 8. `CreateTableRequest` and `TableInfo` and `UpdateTableRequest` share 36+ identical fields — category 12 (Duplicate concepts) and category 7 (Overly verbose) - -**Symbols:** `CreateTableRequest` (model.ts:287, 38 fields), `TableInfo` -(model.ts:710, 36 fields), `UpdateTableRequest` (model.ts:795, 37 fields). - -**Issue:** Three types describe essentially the same shape: -- `CreateTableRequest` — fields a caller sets when creating a table. -- `TableInfo` — fields the server returns about a table. -- `UpdateTableRequest` — fields a caller sets when updating a table (the - only delta is `fullNameArg` added at the top). - -Comparing field lists: -- `CreateTableRequest.fullName` vs `UpdateTableRequest.fullName`: both - fields exist in both types. `UpdateTableRequest` *also* has - `fullNameArg`. The `fullName` field on `CreateTableRequest` is - server-output (the server fills it). The same field on - `UpdateTableRequest` is also server-output. -- `CreateTableRequest.createdAt`, `createdBy`, `updatedAt`, `updatedBy`, - `tableId`, `deletedAt`, `metastoreId` — all server-populated. They appear - in `CreateTableRequest` *because* the type is also used as the response - shape of `createTable()`. The client.ts code confirms — the response is - parsed as `TableInfo`, but `CreateTableRequest` carries the same fields - anyway as part of the "fields you *could* set" surface. - -So `CreateTableRequest` is *both* an input and an output type, with the -same set of fields. Same for `UpdateTableRequest`. `TableInfo` is the -response shape but shares the field set. Three types that are *almost* -identical. - -**Suggested:** collapse to one `Table` type, with optional fields for the -output-only segments (or use `Pick`/`Omit` types if input-only / output-only -need to be distinct). The current shape is generator-driven (proto-source -messages map 1:1). - -**Strong flag for generator cleanup.** Cross-reference the same problem in -`featurestore`, `database`, `postgres`. - ---- - -### 9. `CreateTableRequest.enablePredictiveOptimization` is a `string`, not a boolean — category 6 (Misleading names) and category 16 (Field contradicting type domain) - -**Symbol:** `CreateTableRequest.enablePredictiveOptimization?: string | undefined` -(model.ts:321). Same field on `TableInfo` (model.ts:744) and -`UpdateTableRequest` (model.ts:831). No JSDoc. - -**Issue:** The `enable…` prefix strongly suggests a boolean. The type is -`string`. A caller writing -`createTable({ enablePredictiveOptimization: true })` gets a TS error and -must look up the JSDoc to learn the field accepts string enum values -(typically `'ENABLE'`, `'DISABLE'`, `'INHERIT'` per UC). The -companion `effectivePredictiveOptimizationFlag.value` (model.ts:429) is -also a `string` with the same domain. - -**Suggested:** -- Type as an enum (e.g. `PredictiveOptimizationFlag = 'ENABLE' | 'DISABLE' - | 'INHERIT'`). - -**Coordinate with protocol.** Cross-reference `catalogs/v1` which has the -same field. - ---- - -### 10. `CreateTableRequest.dataAccessConfigurationId` underspecified ID — category 19 (Underspecified IDs) and category 7 (Overly verbose) - -**Symbol:** `CreateTableRequest.dataAccessConfigurationId?: string | undefined` -(model.ts:327). 28 chars. Same field on `TableInfo` (model.ts:750) and -`UpdateTableRequest` (model.ts:837). - -**Issue:** A `string` field with no type discrimination. The JSDoc says -"Unique ID of the Data Access Configuration to use with the table data." -A consumer cannot know the ID's format (UUID? snowflake? human-readable?). -Same applies to: -- `metastoreId` (model.ts:323) — UC metastore identifier. -- `pipelineId` (model.ts:320) — DLT pipeline identifier. -- `tableId` (model.ts:337) — UC table identifier. - -All are bare strings. The TS SDK has no typed IDs; that is an SDK-wide -choice. **Pass with note.** - ---- - -### 11. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* +### 2. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* **Symbol:** `ListTablesRequest.maxResults?: number | undefined` -(model.ts:527), JSDoc: "Maximum number of tables to return. If not set, all +(model.ts:530), JSDoc: "Maximum number of tables to return. If not set, all the tables are returned (not recommended)." The pagination docstring is long and warns that unpaginated calls will be @@ -430,29 +55,9 @@ deprecated. The naming is fine; the API behaviour is the issue. --- -### 12. `Dependency` / `DependencyList` / `TableDependency` / `FunctionDependency` / `ConnectionDependency` / `CredentialDependency` defined in three packages — category 12 (Duplicate concepts) - -**Symbols:** -- This file: `Dependency` (model.ts:412), `DependencyList` (model.ts:422), - and the four leaf-types (model.ts:276, 365, 461, 694). -- `functions/v1/model.ts` — full duplicate. -- `registeredmodels/v1/model.ts` — full duplicate. - -**Issue:** Three packages export the same six types. Each defines its own -`Dependency` discriminated union with the same four cases. The field shapes -are identical (e.g. `TableDependency.tableFullName` is `tableFullName` in -all three). A consumer who uses `tables.TableDependency` and -`functions.TableDependency` will get two different (but structurally -identical) types from the type checker. - -**Suggested:** hoist to `@databricks/sdk-core/dependency` and re-export -from each service package. **Strong SDK-wide cleanup.** - ---- +### 3. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) -### 13. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) - -**Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:240). +**Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:244). JSDoc: "Ordinal position of column (starting at position 0)." **Issue:** Bare `position` (number) — a consumer cannot tell from the @@ -462,13 +67,13 @@ field name that it's 0-indexed. The JSDoc clarifies. --- -### 14. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* +### 4. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* -**Symbols:** `OptionSpec.isRequired` (model.ts:584), -`OptionSpec.isSecret` (model.ts:586), `OptionSpec.isHidden` (model.ts:588), -`OptionSpec.isUpdatable` (model.ts:590), `OptionSpec.isLoggable` -(model.ts:594), `OptionSpec.isCreatable` (model.ts:596), -`OptionSpec.isCopiable` (model.ts:598). +**Symbols:** `OptionSpec.isRequired` (model.ts:586), +`OptionSpec.isSecret` (model.ts:588), `OptionSpec.isHidden` (model.ts:590), +`OptionSpec.isUpdatable` (model.ts:592), `OptionSpec.isLoggable` +(model.ts:596), `OptionSpec.isCreatable` (model.ts:598), +`OptionSpec.isCopiable` (model.ts:600). The boolean fields all use the `is…` prefix, which is the right convention for booleans. **Pass on naming.** @@ -480,26 +85,26 @@ correctly may want a richer type. **Note for upstream.**) --- -### 15. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) +### 5. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) **Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` -(model.ts:429). JSDoc: "Whether predictive optimization should be enabled +(model.ts:433). JSDoc: "Whether predictive optimization should be enabled for this object and objects under it." **Issue:** The type's *purpose* is to indicate whether PO is enabled. The -field name `value` says nothing about that. The type is also a `string` -(not a `boolean`) — same problem as finding 9. +field name `value` says nothing about that — the generic `value` token +loses the domain meaning the type name carries. -**Suggested:** type the field as a boolean (or a constrained enum matching -the JSDoc's "enabled" sense). **Coordinate with protocol team.** +**Suggested:** rename the field to reflect its meaning (e.g. +`predictiveOptimization`, matching the type's "enabled" sense). --- -### 16. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) +### 6. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) **Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` -(model.ts:431), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` -(model.ts:433). +(model.ts:435), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` +(model.ts:437). **Issue:** Two fields describing the source of inheritance — the object type ("CATALOG"|"SCHEMA"|…) and the object's name. Naming is OK, but the @@ -510,36 +115,30 @@ three fields. --- -### 17. `Client` class name — category 1 (Vague/generic) — *pass* - -Package convention. **Pass.** - ---- - -### 18. `Client.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* +### 7. `TablesClient.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* Standard `{verb}{Resource}` shape. Convention. **Pass.** -(Note: `Client.tableExists` (client.ts:478) breaks the verb-first pattern — -it reads `noun-verb` instead of `verb-noun`. The corresponding shape in -other SDKs is `existsTable` or `checkTableExists`. **Flag at SDK-wide -level.**) +(Note: `TablesClient.tableExists` (client.ts:495) breaks the verb-first +pattern — it reads `noun-verb` instead of `verb-noun`. The corresponding +shape in other SDKs is `existsTable` or `checkTableExists`. **Flag at +SDK-wide level.**) --- -### 19. `Client.createTableConstraint` / `deleteTableConstraint` — *pass* +### 8. `TablesClient.createTableConstraint` / `deleteTableConstraint` — *pass* Same `{verb}{Resource}` pattern. **Pass.** --- -### 20. `Client` private fields `host`, `httpClient`, `logger`, `userAgent` — *pass* +### 9. `TablesClient` private fields `host`, `workspaceId`, `httpClient`, `logger`, `userAgent` — *pass* Standard. **Pass.** --- -### 21. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* +### 10. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, `TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide @@ -547,61 +146,30 @@ pattern. **Pass.** --- -### 22. `Dependency.value` $case literals (`'table'`, `'function'`, `'connection'`, `'credential'`) all lowercase, no prefix — category 17 (Inconsistent action verbs) — *pass with note* - -**Symbols:** `Dependency.value.$case` literals (model.ts:414–417). - -**Issue:** The four `$case` literals are plain nouns. Within the file: -- `TableConstraint.constraint.$case` literals (model.ts:679, 683, 687) are - `'primaryKeyConstraint'` / `'foreignKeyConstraint'` / `'namedTableConstraint'` — - i.e. *suffixed* with `Constraint`. -- `EncryptionDetails.encryptionDetailsType.$case` literal (model.ts:440) is - `'sseEncryptionDetails'` — suffixed with `Details`. -- `PolicyFunctionArgument.arg.$case` literals (model.ts:608, 613) are - `'column'` / `'constant'` — plain nouns, like `Dependency.value`. +### 11. `_PropertiesEntry` / `_DeltaRuntimePropertiesEntry` underscore-suffixed proto map-entry type names — category 4 (Underscores in TS identifiers) -So **four discriminated unions, two different naming conventions** for -their $case literals. - -**Suggested:** unify on one form. `Dependency`'s short-form literals -(plain nouns) are the cleanest — apply elsewhere. **Flag at port time.** - ---- - -### 23. `_PropertiesEntry` / `_Response` underscore-suffixed proto-nested type names — category 4 (Underscores in TS identifiers) and category 14 (Go/Java-style names) - -**Symbols:** `CreateTableRequest_PropertiesEntry` (model.ts:359), -`DeleteTableConstraintRequest_Response` (model.ts:383), -`DeleteTableRequest_Response` (model.ts:391), -`DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` (model.ts:403), -`ListTableSummariesRequest_Response` (model.ts:505), -`ListTablesRequest_Response` (model.ts:543), -`TableExistsRequest_Response` (model.ts:705), -`TableInfo_PropertiesEntry` (model.ts:782), -`UpdateTableRequest_PropertiesEntry` (model.ts:869), -`UpdateTableRequest_Response` (model.ts:875). +**Symbols:** `CreateTableRequest_PropertiesEntry` (model.ts:363), +`DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` (model.ts:407), +`TableInfo_PropertiesEntry` (model.ts:783), +`UpdateTableRequest_PropertiesEntry` (model.ts:870). **Issue:** Underscores in PascalCase identifiers are not idiomatic TS (Google style guide § 5.1 disallows them; the generated code carries an `eslint-disable-next-line @typescript-eslint/naming-convention` comment -above each). The underscores survive from the proto's nested-message -naming. Several `…_Response` types are *empty* bodies kept only to mirror -the proto definition. - -**Suggested:** -- For `_Response` empty bodies: drop the type entirely; the method can - return `void`. -- For `_PropertiesEntry` / `_DeltaRuntimePropertiesEntry` map-entry types: - drop or inline — `Record` is sufficient. -- For non-empty responses (`ListTablesRequest_Response`, - `TableExistsRequest_Response`): rename to `ListTablesResponse`, - `TableExistsResponse` (PascalCase, no underscore). +above each, at model.ts:362, 406, 782, 869). The underscores survive from +the proto's nested map-entry message naming. None of these four types is +referenced anywhere — the actual map fields use `Record` +(e.g. `CreateTableRequest.properties`, model.ts:359) — yet they are still +declared and re-exported from `index.ts`. + +**Suggested:** drop the map-entry types entirely; `Record` +is sufficient and is already what the fields use. **Flag for SDK-wide generator cleanup.** --- -### 24. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:209, 222 +### 12. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:213, 226 **Why:** Underscore-separated `OuterMessage_InnerEnum` naming is a literal transcription of proto nested-enum scoping. The infix `_` and the @@ -616,12 +184,12 @@ prefix) — or, if collision risk exists, `OptionOauthStage` / `OptionTypeKind`. **Rationale:** the `OptionSpec_` prefix exists solely to mirror the proto -nesting; the eslint-disable comments on lines 208, 221 acknowledge the +nesting; the eslint-disable comments on lines 212, 225 acknowledge the non-idiomatic shape. --- -### 25. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:563 +### 13. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:565 **Why:** `Spec` is a generic config-style suffix that re-appears across the file (`SecurableKindManifest`, `EffectivePredictiveOptimizationFlag`, @@ -638,7 +206,7 @@ struct describing X" — a proto convention, not a TS one. --- -### 26. `SecurableKindManifest` type name — file:line model.ts:648 +### 14. `SecurableKindManifest` type name — file:line model.ts:650 **Why:** `Manifest` is a config-style suffix (analogous to `Spec`/`Config`). It tags the type as a descriptor message rather than a domain concept. @@ -654,7 +222,7 @@ adds no information beyond "this is the descriptor". --- -### 27. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:233, 710, 787 +### 15. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:237, 711, 788 **Why:** `Info` and `Summary` are generic descriptor-suffixes used to distinguish the wire/RPC message from the domain noun (`Column`, `Table`). @@ -663,8 +231,7 @@ repeated config-suffix pattern. **Category:** proto-architectural-leak (repeated `Info` config-suffix). -**Suggested:** `Column`, `Table`, `TableOverview` (or collapse all three -into `Table` per finding #8). +**Suggested:** `Column`, `Table`, `TableOverview`. **Rationale:** in a TS surface the noun *is* the type; the `Info`/`Summary` tag exists only to disambiguate from the proto request/response messages @@ -672,7 +239,7 @@ and from server-internal representations — a generator/architectural leak. --- -### 28. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:437, 662 +### 16. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:441, 664 **Why:** Two `…Details` types in the same file. `Details` is a generic "descriptor" suffix with no domain meaning — same family as `Info`/`Spec`. @@ -684,92 +251,3 @@ if disambiguation is needed). **Rationale:** `Details` is generator boilerplate for proto messages wrapping `oneof`s or option blobs; idiomatic TS uses the bare domain noun. - ---- - -## Cross-package alignment recommendations - -### A. `Dependency` family duplicated in three packages - -`tables`, `functions`, and `registeredmodels` each export the same six -types: `Dependency`, `DependencyList`, `TableDependency`, `FunctionDependency`, -`ConnectionDependency`, `CredentialDependency`. Same shape, same fields, -three copies. Strong P0 candidate for hoisting to -`@databricks/sdk-core/dependency`. - ---- - -### B. `EncryptionDetails` / `SseEncryptionAlgorithm` / `SseEncryptionDetails` duplicated in three packages - -`tables`, `volumes`, and `externallocations` each define the same encryption -types with the same fields and the same enum values. Three copies. - -**Suggested:** hoist to `@databricks/sdk-core/encryption` or -`@databricks/sdk-core/storage`. - ---- - -### C. `SecurableType` defined in 5+ packages - -`tables`, `catalogs`, `connections`, plus the unaudited -`grants`/`abacpolicies`/etc. Same 17 values, same names. - -**Suggested:** hoist to `@databricks/sdk-core/securable`. - ---- - -### D. `EffectivePredictiveOptimizationFlag` defined in `tables` and `catalogs` - -`catalogs/v1/model.ts` defines the same type as -`tables/v1/model.ts:427`. Three fields (`value`, `inheritedFromType`, -`inheritedFromName`). - -**Suggested:** hoist or pick a canonical home. - ---- - -### E. `ColumnTypeName` defined in `tables` and `functions` - -`functions/v1/model.ts:5` defines the same enum. The shared SQL/Spark -data-type values overlap heavily. - -**Suggested:** hoist to `@databricks/sdk-core/sql-types`. - ---- - -### F. `RowFilter` / `ColumnMask` vs. `abacpolicies.RowFilterOptions` / `abacpolicies.ColumnMaskOptions` shape divergence - -`tables/v1/model.ts:631` defines `RowFilter` and `tables/v1/model.ts:258` -defines `ColumnMask`. `abacpolicies/v1/model.ts` defines -`ColumnMaskOptions` / `RowFilterOptions`. Same domain, different shapes -and naming. - -**Suggested:** harmonise. - ---- - -## Counts by severity - -| Severity | Count | Findings | -| -------- | ----- | -------- | -| **High** (style guide violations, dead/empty types, cross-package collisions, misleading semantics, proto-architectural leaks) | 11 | #1, #4, #8, #9, #12, #15, #24, #25, #26, #27, #28 | -| **Medium** (naming clarity, verbose, redundant suffixes, JSDoc drift) | 6 | #2, #5, #6, #7, #10, #23 | -| **Low / SDK-wide note** (generator boilerplate, not local fix) | 3 | #3, #16, #22 | -| **Pass / acceptable** | 8 | #11, #13, #14, #17, #18, #19, #20, #21 | - ---- - -## Top fixes (highest local return) - -1. **#1** — fix `DeltaRuntimePropertiesKvpairs` (field) / - `DeltaRuntimePropertiesKvPairs` (type) casing mismatch. Local, mechanical - rename. -2. **#9** — type `enablePredictiveOptimization` as a real enum instead of - a free-form string. Improves type safety. -3. **#15** — type `EffectivePredictiveOptimizationFlag.value` as a real - boolean/enum instead of a free-form string. Same family as #9. -4. **#23** — eliminate `_Response` empty bodies and `_PropertiesEntry` - map-entry shells. Local type-level cleanup. -5. **#24 / #25 / #26 / #27 / #28** — drop proto-architectural type-name - suffixes (`_OauthStage`, `Spec`, `Manifest`, `Info`/`Summary`, `Details`) - in favour of bare domain nouns. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 6a0561bc..17aac381 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -2,50 +2,18 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 -**Inferred domain:** Tag assignment management for non-Unity-Catalog Databricks platform entities — specifically `apps`, `dashboards`, `geniespaces`, `notebooks`. Provides CRUD over (entityType, entityId, tagKey) -> tagValue triples through `/api/2.0/entity-tag-assignments`. Sister of `entitytagassignments` (Unity Catalog entities) and `tagpolicies` (governed tag definitions). Despite the package name and the URL path both being `entity-tag-assignments`-flavored, the primary type here is `TagAssignment` (no `Entity` prefix), unlike sister package `entitytagassignments`. -**Total weird names flagged:** 11 +**Total weird names flagged:** 5 ## Summary | Severity | Count | | --- | --- | -| High | 6 | +| High | 1 | | Medium | 2 | -| Low | 0 | -| Observation | 3 | +| Observation | 2 | ## High severity -### 1. Package directory `tagassignments` vs. sister `entitytagassignments` and wire path `/entity-tag-assignments` — `package directory name` -- **Why weird:** This package is called `tagassignments` (no `entity` prefix). Its sister `entitytagassignments` shares the same wire path *prefix* and the same five operations. But its own HTTP path (line `client.ts:71`) is `/api/2.0/entity-tag-assignments` — so this package is named *without* `entity` even though the URL is *with* `entity`. The sister package is named *with* `entity` and its URL is `/api/2.1/unity-catalog/entity-tag-assignments`. The directory tokens do not predict the wire shape. Worse, both packages have a `Client` and the resource shape `(entityType, entityId-or-name, tagKey, tagValue)` is conceptually identical — only the entity universe (UC vs. apps/dashboards/etc.) differs. -- **Category:** 12 (duplicate concept across two packages), 1 (vague — what does `tagassignments` mean without `entity`?), 6 (misleading — name suggests "any tag assignment" but the package only covers four platform entity kinds). -- **Suggested name:** Rename to `platformtagassignments` or `appdashtags` to mark the scope, while renaming the sister `entitytagassignments` to `uctagassignments`. Alternatively, merge both into a unified `tagassignments` package with a discriminating `entityKind` field. -- **Rationale:** Two sister packages whose names diverge from their wire paths force users to memorize a name-to-API mapping. Without `entity` in this directory, the type `TagAssignment` here and `EntityTagAssignment` there look like different kinds of objects when they are not. Generator-level concern. - -### 2. `TagAssignment` — `src/v1/model.ts:46` -- **Why weird:** The primary type `TagAssignment` is a tag assigned to an *entity* — every field on it (`entityType`, `entityId`, `tagKey`, `tagValue`) presupposes an entity. The name says "tag assignment" but the type really is "entity tag assignment". Yet sister package `entitytagassignments` does include the `Entity` prefix on its type. So the SDK has both `TagAssignment` and `EntityTagAssignment` for the same conceptual shape. -- **Category:** 1 (vague — assignment to what?), 12 (duplicate concept naming across siblings), 16 (no `Entity` prefix when sister package has it for the same concept). -- **Suggested name:** Either pick `EntityTagAssignment` here too (and rename type-collisions out at re-export), or rename the sister to drop `Entity` and use package-scoped imports. Pick one. -- **Rationale:** The naming asymmetry between sister types is the actual bug. Both should be the same name, with disambiguation via import. - -### 3. `entityType: string` — `src/v1/model.ts:13,22,31,48` -- **Why weird:** Four occurrences of `entityType?: string | undefined`. The JSDoc lists allowed values inline: "apps, dashboards, geniespaces, notebooks". A closed set of four values lives in plain prose, not in the type. Users will pass typos with no compile-time check. -- **Category:** 1 (vague — `string` for what is really an enum), 19 (underspecified ID — what values are valid?), 6 (misleading — looks free-form, is actually constrained), 16 (field contradicts type — closed set typed as open string). -- **Suggested name:** Introduce `EntityKind = 'apps' | 'dashboards' | 'geniespaces' | 'notebooks'` and type the field as `entityKind?: EntityKind`. `Kind` reads cleaner than `Type` in TS (cf. `SyntaxKind` in TS compiler API). -- **Rationale:** The valid set is closed and documented; the type should reflect that. Generator anti-pattern: stringly-typed enums. - -### 4. `Client` class — `src/v1/client.ts:41` -- **Why weird:** A class literally named `Client` re-exported through `index.ts:3` as plain `Client`. Sister packages `entitytagassignments` and `tagpolicies` ship `Client` classes of the same name. Three `Client`s across the tag-related sibling packages. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name losing meaning), 12 (duplicate concept across sister packages). -- **Suggested name:** `TagAssignmentsClient`. Forces aliasing only when co-imported, but reads as "the client for the tag-assignments surface". -- **Rationale:** Three `Client`s in three sister packages will collide on combined imports. - -### 5. `pageSize` here vs. `maxResults` in sister `entitytagassignments` — `src/v1/model.ts:35` vs. `entitytagassignments/src/v1/model.ts:68` -- **Why weird:** Same concept, two different field names across sister packages. This package: `pageSize?: number`. Sister: `maxResults?: number`. The wire-side names also diverge (`page_size` here, `max_results` there). Within a single SDK, the page-size parameter has two names depending on which tag flavor you use. -- **Category:** 12 (duplicate concept named differently across siblings), 17 (inconsistency between sibling fields). -- **Suggested name:** Pick one. `pageSize` is the more conventional name (matches `nextPageToken` here). `maxResults` is older. -- **Rationale:** Cross-SDK pagination naming consistency. Worth flagging upstream — generator-wide concern. - -### 6. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:141` +### 1. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:152` - **Why weird:** The list URL is `/api/2.0/entity-tag-assignments/${entityType ?? ''}/${entityId ?? ''}/tags`. When either is undefined, the URL becomes `.../entity-tag-assignments///tags`. Both fields are typed `string | undefined`, but `entityType` and `entityId` are clearly required to address an entity. Same issue on `Get`/`Delete`/`Update`. The SDK silently produces malformed URLs. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. @@ -53,47 +21,23 @@ ## Medium severity -### 7. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` +### 2. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` - **Why weird:** The plural appears only on list types. The HTTP resource on the wire is `/entity-tag-assignments` (plural) while the item type is singular `TagAssignment`. List response is `ListTagAssignmentsResponse` (plural). - **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). - **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. - **Rationale:** Rule 9 demands the flag even when intentional. -### 8. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:97,116,141,192` +### 3. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:102,124,152,206` - **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. - **Category:** 6 (misleading — silent malformed URLs). - **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. -- **Rationale:** See #6. Generator-wide concern. - -## Low severity - -_None._ +- **Rationale:** See #1. Generator-wide concern. ## Observations -### 9. Action verb consistency +### 4. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. -### 10. `tagassignments` lowercase package name vs. types and HTTP path +### 5. `tagassignments` lowercase package name vs. types and HTTP path The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. - **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). - -### 11. Domain leakage between sister packages -Three packages — `tagassignments`, `entitytagassignments`, `tagpolicies` — collide on the noun "tag". Each ships its own `Client`, its own `*TagAssignment`/`TagPolicy` type, and its own `tagKey`/`tagValue`. Co-import requires aliasing. The split aligns to wire-side API groupings (different HTTP paths and product surfaces), not to a user mental model of "tag tools". Worth flagging upstream as a structure-level concern, not just naming. -- **Category:** 12 (duplicate concept across siblings). - -## Domain glossary -- `entity` — a Databricks platform resource being tagged. In this package, restricted to `apps`, `dashboards`, `geniespaces`, `notebooks` (per the JSDoc). -- `entity type` — string discriminator naming the kind of entity (closed set of 4 values, typed as open string). -- `entity id` — identifier of the entity. For apps, this is the app name. For the other three kinds, not documented in this package. -- `tag key` — string with character-class restrictions (no `,` `.` `:` `/` `-` `=` and no leading/trailing spaces). -- `tag value` — string with no documented constraints in this file. -- `tag assignment` — the (entityType, entityId, tagKey) -> tagValue triple. -- `tag policy` — a separate governed-tag concept; see sister package `tagpolicies`. -- `unity catalog entity tag assignment` — a separate but conceptually identical assignment over UC entities; see sister package `entitytagassignments`. - -## File coverage -- `src/v1/model.ts` (115 lines): read fully. -- `src/v1/client.ts` (224 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (16 lines): read fully. diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md index 8d3337c3..6cc51668 100644 --- a/.agent/naming-audit/tagpolicies.md +++ b/.agent/naming-audit/tagpolicies.md @@ -3,90 +3,29 @@ **Path:** `packages/tagpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and an optional `id`/timestamps so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. -**Total weird names flagged:** 11 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 2 | -| Low | 1 | -| Observation | 4 | +| High | 2 | +| Observation | 1 | ## High severity -### 1. Three sister packages (`tagpolicies`, `tagassignments`, `entitytagassignments`) split the noun "tag" — package directory name -- **Why weird:** Three sibling packages each carry one slice of the "tag" domain — definitions (this package), assignments to platform entities (`tagassignments`), assignments to Unity Catalog entities (`entitytagassignments`) — and each ships its own `Client` class, its own primary type, and its own `tagKey` field. A user who wants to "manage tags" must import three packages and alias three `Client`s. The split mirrors backend RPC groupings, not a user mental model. -- **Category:** 12 (duplicate concept split across three packages), 1 (`tag*` as a package-name fragment is vague — which slice of tags?). -- **Suggested name:** Merge into a single `tags` (or `taxonomy`) package with sub-namespaces `tags.policies`, `tags.assignments.platform`, `tags.assignments.uc`. As a smaller fix, rename to `governedtags` (this package) and `governedtagvalues` (or similar) to make the role explicit. -- **Rationale:** Three `Client`s in three packages collide on combined imports. The user-facing surface should follow the user mental model ("I want to manage tags"), not the wire-side `/api/2.1/tag-policies` vs. `/api/2.0/tag-assignments` vs. `/api/2.1/unity-catalog/entity-tag-assignments` partition. Worth flagging as a generator-level structural concern. - -### 2. `TagPolicy` exposes the wire-side term instead of the domain term — `src/v1/model.ts:36` -- **Why weird:** The primary type is named `TagPolicy`, but the JSDoc on every client method talks about "governed tags" (`client.ts:66,92,111,136,187`). "Governed tag" is the canonical domain term; "tag policy" is the wire/proto-side term that mirrors the `/api/2.1/tag-policies` path. The SDK should expose the domain term, not the wire-side noun. +### 1. `TagPolicy` exposes the wire-side term instead of the domain term — `src/v1/model.ts:36` +- **Why weird:** The primary type is named `TagPolicy`, but the JSDoc on every client method talks about "governed tags" (`client.ts:68,97,119,147,201`). "Governed tag" is the canonical domain term; "tag policy" is the wire/proto-side term that mirrors the `/api/2.1/tag-policies` path. The SDK should expose the domain term, not the wire-side noun. - **Category:** 14 (Go-style — Go SDK keeps the wire-side noun; TS users would benefit from the domain term). - **Suggested name:** `GovernedTag` (matches domain language used throughout the JSDoc). - **Rationale:** The user-facing concept is "this tag is governed", not "this tag has a policy attached". Cross-SDK consistency vs. domain readability trade-off. -### 3. `Client` class — `src/v1/client.ts:41` -- **Why weird:** A class literally named `Client` at the top level of the package's public API, re-exported through `index.ts:3` as just `Client`. The sister packages (`tagassignments`, `entitytagassignments`) ship their own `Client` class with the same name. Three `Client` classes in three sister packages, plus this `Client` in the rest of the SDK's ~70 other packages. -- **Category:** 1 (vague — `Client` is the most generic possible name), 15 (generic name), 12 (duplicate concept across sister packages and the entire SDK). -- **Suggested name:** `TagPoliciesClient` (matches the package name) or `GovernedTagsClient` (matches domain language). -- **Rationale:** Three sister packages with three `Client`s will collide on combined imports and force aliasing on every co-use (`import {Client as TagPoliciesClient} from '@databricks/sdk-tagpolicies'`). Generator-level concern. - -### 4. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:13,17` -- **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${this.host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:97,116`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). +### 2. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:13,17` +- **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${this.host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:102,124`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). - **Category:** 6 (misleading — type says optional, semantics says required), 19 (underspecified ID — what should `tagKey` look like? Constraints? Encoding?). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) on get/delete/update. Add JSDoc describing valid keys. - **Rationale:** Optional path parameters in REST clients are a generator anti-pattern. Honest required-ness should travel through the type, not through a `?? ''` fallback that produces a malformed URL. -## Medium severity - -### 5. `ListTagPoliciesRequest` (plural) vs. `TagPolicy` (singular) — `src/v1/model.ts:20` vs. `model.ts:36` -- **Why weird:** Plural only on list endpoint; singular elsewhere. The list response is `ListTagPoliciesResponse` (plural). The wire path is `/tag-policies` (plural). The convention is consistent with the Go SDK, but worth flagging that the resource name on the wire is plural while the item type is singular. -- **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary within one type family). -- **Suggested name:** Keep as is (cross-SDK convention). Listed for completeness under rule 9. -- **Rationale:** Same as in `entitytagassignments` audit — flagged because rule 9 demands it. - -### 6. Create/update wrap the subject in a body field while the list response also wraps in an array field — `src/v1/model.ts:9,32,48` -- **Why weird:** `CreateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) and `UpdateTagPolicyRequest.tagPolicy: TagPolicy` (singular wrapper) both put the subject inside a one-field body. `ListTagPoliciesResponse.tagPolicies: TagPolicy[]` does the analogous thing for the response. Each wrapper is a single-field envelope around the actual payload, which means every caller writes `client.create({tagPolicy: {...}})` instead of `client.create({...})`. The envelope is consistent in cardinality (singular/plural matches the type), but it adds a level of indirection on every call. -- **Category:** 17 (inconsistency — request and response both wrap, but callers must remember the wrapper field name on each side). -- **Suggested name:** N/A — the wrapper envelopes are dictated by wire-side proto shape. Flagged as a generator-level consideration. -- **Rationale:** Single-field body envelopes show up across the generated SDK; this package is one instance. - -## Low severity - -### 7. `pageSize` upper-bound documented in doc, not enforced in type — `src/v1/model.ts:22-25` -- **Why weird:** JSDoc says "The maximum value is 1000; values above 1000 will be coerced down to 1000." but the field is typed `number | undefined`. A caller passing `pageSize: 100000` silently gets clipped to 1000. The constraint travels only via the docstring. -- **Category:** 6 (misleading — type does not match contract). -- **Suggested name:** Keep `pageSize`; consider a branded type or a runtime validator. At minimum, restate the limit clearly. -- **Rationale:** Generator-wide; flagged because docs lie about wire behaviour. - ## Observations -### 8. Action verb consistency +### 3. Action verb consistency The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. - -### 9. Acronym casing -File uses `HttpRequest`, `HttpResponse`, `HttpCallOptions` (Pascal `Http`), `URLSearchParams` (web standard `URL`), `userAgent` (camelCase). The `Http` vs. `URL` split is the JS-ecosystem norm. No `Id`/`Uri` casing clashes encountered within the file. -- **Category:** 3 (acronym casing — consistent within the file, ecosystem-divergent overall). - -### 10. `tagpolicies` lowercase package name -Package directory is `tagpolicies` (single token, no separator), but every type uses `TagPolicy*` and the HTTP path uses `tag-policies`. Same problem as `dataclassification`, `tagassignments`, `entitytagassignments` — SDK-wide convention issue. -- **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types). - -### 11. Domain leakage from sister packages -Three packages — `tagpolicies`, `tagassignments`, `entitytagassignments` — all collide on the noun "tag". Each ships its own `Client`, its own `tag*` types, and its own `tagKey`. Co-import requires extensive aliasing. `tagpolicies` differs in that it defines the *policy* over the tag, while the assignment packages attach a `tagKey` + `tagValue` to entities — but a user can't tell from the name; "tag policies" sounds like it could be policies *for* tag assignments. -- **Category:** 12 (duplicate concept across siblings). - -## Domain glossary -- `tag policy` — a governed-tag definition with allowed values. -- `governed tag` — a tag whose key has an active `TagPolicy` (JSDoc on every method mentions this). -- `tag key` — the user-chosen identifier of a tag (e.g., `"environment"`). Doubles as the path-key for the resource (`/tag-policies/{tagKey}`). -- `tag value` — one of the allowed strings for a tag (e.g., `"prod"`, `"dev"`) — wrapped in a `Value` type that has a single `name` field. -- `Terraform documentation` — JSDoc on every method links to the matching `terraform-provider-databricks` page. - -## File coverage -- `src/v1/model.ts` (143 lines): read fully. -- `src/v1/client.ts` (224 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (17 lines): read fully. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index 0a5ad6dc..a5010297 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -3,95 +3,41 @@ **Path:** `packages/tokenmanagement/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace-admin API for managing personal access tokens (PATs) belonging to any user in the workspace — list/get/create-on-behalf-of/delete arbitrary user tokens. Distinct from the per-user `tokens` API which only manages the calling user's own tokens. -**Total weird names flagged:** 8 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 2 | -| Low | 2 | -| Observation | 0 | +| High | 2 | +| Medium | 1 | +| Low | 1 | ## High severity -### 1. Package name `tokenmanagement` duplicates `tokens` — overlap with sibling package -- **Why weird:** Two packages, `tokens` and `tokenmanagement`, both manage Databricks personal access tokens (PATs). Both expose `ListTokens*`, `RevokeToken*`, and list response/request types, and both publish a `Client` class with `listTokens` methods. The only structural differences are (a) the admin variant adds `getToken`, `createOnBehalfOfToken`, and admin-only fields on its token info, (b) the per-user variant has `createToken` (no on-behalf-of), and (c) the entity type is named `AdminTokenInfo` here vs. `PublicTokenInfo` in `tokens`. URL paths also differ: `/api/2.0/token-management/...` vs `/api/2.0/token/...`. From a TS user's perspective the namespaces collide: `import {Client, ListTokensRequest} from '@databricks/sdk-tokenmanagement/v1'` and `import {Client, ListTokensRequest} from '@databricks/sdk-tokens/v1'` clash on every public name. -- **Category:** 12 (duplicate concepts across `tokens` vs `tokenmanagement` packages). -- **Suggested name:** Keep the directory split (the API is split upstream) but in the public exports prefix admin types: `AdminListTokensRequest`, `AdminRevokeTokenRequest`, etc., or alternatively rename the package to `tokenadmin` so the call-site distinction is unmistakable (`@databricks/sdk-tokenadmin`). -- **Rationale:** Today consumers who import both packages cannot do so by named import without aliasing every type. - -### 2. `AdminTokenInfo` — `Info` is a vague suffix, package-specific prefix is misleading -- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. `src/v1/model.ts:5`. +### 1. `AdminTokenInfo` — `Info` is a vague suffix, package-specific prefix is misleading +- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. `src/v1/model.ts:23`. - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix), 15 (generic suffix that loses meaning). -- **Suggested name:** `Token` (or `ManagedToken` if `Token` would clash with a class on the consumer side; given this is exported from `@databricks/sdk-tokenmanagement/v1`, `Token` is fine — see also finding #1 about cross-package name collisions). +- **Suggested name:** `Token` (or `ManagedToken` if `Token` would clash with a class on the consumer side; given this is exported from `@databricks/sdk-tokenmanagement/v1`, `Token` is fine). - **Rationale:** `Token` is the noun the user thinks about. `Info` is a Go-SDK tic; TS does not need it. -### 3. Client method `deleteToken` wraps request type `RevokeTokenRequest` — verb-tense inconsistency -- **Why weird:** `client.deleteToken(req: RevokeTokenRequest)` at `client.ts:99-100` with the type defined at `model.ts:85`. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently. +### 2. Client method `deleteToken` wraps request type `RevokeTokenRequest` — verb-tense inconsistency +- **Why weird:** `client.deleteToken(req: RevokeTokenRequest)` at `client.ts:108-133` with the type defined at `model.ts:110`. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently. - **Category:** 13 (verb-tense inconsistency between method and request type), 17 (inconsistent action verbs across the two packages: `tokenmanagement.deleteToken` vs `tokens.revokeToken` for the same kind of operation). - **Suggested name:** Either rename method to `revokeToken` (matches type and matches sibling package) or rename type to `DeleteTokenRequest` (matches HTTP verb). Recommend the former so both packages share a verb. - **Rationale:** "Revoke" carries a security/lifecycle meaning that "delete" loses; tokens aren't deleted from history, they're invalidated. -### 4. `AdminTokenInfo` — `Admin` mid-position prefix is an architectural-tier leak (not domain) — `src/v1/model.ts:5` -- **Why:** `Admin` mid-position on the entity type names a service-tier / audience-of-callers (admin vs. non-admin caller), not a domain concept. The sibling package uses `PublicTokenInfo` for the same kind of leak (`Public` mid-position). Tokens are not "admin tokens"; they are personal access tokens that this admin-scoped endpoint can list/manage. The `Admin`/`Public` distinction is purely about which RBAC tier of the backend service exposes the model. -- **Category:** Proto-architectural-leak — `Public`/`Internal`/`External` family of mid-position service-tier qualifiers used as a noun prefix. -- **Suggested:** `Token` (or `ManagedToken` to disambiguate from the sibling package's entity; see also finding #2 which already proposes `Token`). -- **Rationale:** The `Admin` qualifier survives from the proto's two-tier service split (`token-management` admin-scoped service vs. `token` user-scoped service). End users of the SDK only see one type per import; the architectural-tier label adds no domain meaning at the call site (e.g., `token.tokenId` is clearer than `adminTokenInfo.tokenId`). - ## Medium severity -### 5. `ListTokensRequest` fields `createdById` and `createdByUsername` — duplicate filter slots -- **Why weird:** `ListTokensRequest { createdById?, createdByUsername? }` (`model.ts:71-76`). Two fields that filter on the same logical concept (the creator), with no semantics about whether they're AND/OR. The doc string above the type says "string filter parameter instead of hard-coded filters" — i.e., this is a temporary shape. The client builds `params` from both unconditionally (`client.ts:158-163`) which means callers can submit both at once and get undefined server behavior. -- **Category:** 1 (vague — relationship unspecified), 6 (misleading — looks like two filters, possibly redundant). -- **Suggested name:** Either expose a single `filter` string or document mutual exclusivity. At minimum, JSDoc the AND/OR semantics. -- **Rationale:** Consumer-facing API ambiguity. - -### 6. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name -- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:27`. Industry shorthand is "OBO" but the SDK avoids the acronym. +### 3. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name +- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:53`. Industry shorthand is "OBO" but the SDK avoids the acronym. - **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). - **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. - **Rationale:** This is the only operation in the package whose name relies on the preposition; surfacing the intent (mint a token for someone else) helps. Defensible as-is. ## Low severity -### 7. `Client` class is named `Client` (no namespacing) -- **Why weird:** `export class Client` (`client.ts:44`). With both `tokens` and `tokenmanagement` packages exporting a `Client`, and many other packages too, code that imports several SDK clients has to alias each one. The class name itself is the most generic possible. -- **Category:** 1 (vague), 12 (duplicate concept across all SDK packages — every package has its own `Client`). -- **Suggested name:** `TokenManagementClient` (or `TokenAdminClient`). -- **Rationale:** This is a cross-package convention concern; mass-renaming would be a breaking change, but flag because users will hit it. - -### 8. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory +### 4. Package name `tokenmanagement` — `Management` suffix is an architectural label, not a domain noun — package directory - **Why:** The package's directory and npm name `tokenmanagement` ends in `management`, which sits in the `Manager`/`Handler`/`Controller`/`Processor` family of architectural-tier suffixes. The package does not contain a "management" concept; it contains operations on tokens (list, get, create-on-behalf-of, delete). The `-management` suffix is service-side scaffolding language (cf. proto `TokenManagementService`) that leaks out via the URL path `/api/2.0/token-management/...` and into the SDK package name. Compare to peers in the SDK where the action package is named after the domain noun (`tokens`, `clusters`, `secrets`), not the service tier. - **Category:** Proto-architectural-leak — `Manager`/`Handler`/`Controller`/`Processor`/`-management` family (architectural label not in the domain). -- **Suggested:** `tokenadmin` — keeps the audience-disambiguation from sibling `tokens` but uses an audience noun rather than an architectural verb. See finding #1 which proposes the same package rename for the collision-avoidance reason. +- **Suggested:** `tokenadmin` — keeps the audience-disambiguation from sibling `tokens` but uses an audience noun rather than an architectural verb. - **Rationale:** "Management" is meaningless to an SDK consumer (everything an SDK does is, in some sense, "managing"). `tokenadmin` names *who* the API is for (admins-of-others) and disambiguates from `tokens` (self) without leaking the proto service tier. - -## Observations - -_None._ - -## Domain glossary -- `PAT` — Personal Access Token (the term the package is about but never names directly). -- `OBO` — On-Behalf-Of (spelled out in `CreateOnBehalfOfTokenRequest`). -- `service principal` — Non-human identity that a token can be minted for via on-behalf-of. -- `workspace` — Mentioned in `workspaceId` and in proto comments; the scope of this admin API. -- `m2m`/`u2m` — not encountered. -- `iam` — not encountered. -- `wkt` — not encountered in current source. - -## Cross-package overlap with `tokens` -- **Shared request types:** `ListTokensRequest`, `RevokeTokenRequest` exist in both packages with different fields. `ListTokensRequest` in `tokenmanagement` has `createdById`/`createdByUsername`; in `tokens` it differs. -- **Shared response shapes:** List and revoke responses exist in both packages. Both pull from a `*TokenInfo[]` array (`AdminTokenInfo[]` vs `PublicTokenInfo[]`). -- **Different entity name:** `AdminTokenInfo` (this package) vs `PublicTokenInfo` (`tokens` package). -- **Different create operation:** `createOnBehalfOfToken` (admin) vs `createToken` (per-user). -- **Different revoke method name:** `deleteToken` (admin) vs `revokeToken` (per-user) — flagged in finding #3. -- **Different URL prefix:** `/api/2.0/token-management/...` vs `/api/2.0/token/...`. - -The two packages are conceptual siblings (PAT lifecycle) split by audience (admin-of-others vs self), but the SDK surface is split inconsistently — naming, return types, and method verbs diverge for no obvious reason. Worth raising at the SDK-design level. - -## File coverage -- `src/v1/model.ts` (169 lines): read fully. -- `src/v1/client.ts` (185 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (18 lines): read fully. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index 34e9ec88..2f673a9f 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -2,102 +2,32 @@ **Path:** `packages/tokens/src/v1/` **Versions audited:** v1 -**Inferred domain:** Databricks workspace Personal Access Token (PAT) management — the *end-user-facing* surface for a workspace user to create/list/revoke/update their own tokens. Endpoints live under `/api/2.0/token/...`. Pairs with the *admin-facing* `tokenmanagement` package at `/api/2.0/token-management/...` which lets workspace administrators inspect and revoke tokens owned by *other* users (including on-behalf-of service principal tokens). The two packages share a near-identical "token info" record, but the auth/audience boundary makes them distinct services. -**Total weird names flagged:** 10 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | -| High | 5 | -| Medium | 2 | +| High | 1 | | Low | 1 | -| Observation | 2 | +| Observation | 1 | ## High severity -### 1. Package name `tokens` overlaps with sibling `tokenmanagement` and is sub-domain-vague — `packages/tokens/`, `package.json:2`, `client.ts:80,109,138,171` -- **Why weird:** Two npm packages co-exist in `sdk-js/packages/`: `@databricks/sdk-tokens` (this package) and `@databricks/sdk-tokenmanagement` (admin surface). Both manage *the same kind of resource* (Databricks PATs) and both expose a `Client` class with a `listTokens(req, options)` and a `revokeToken(req, options)` method. From the npm name alone, a caller cannot tell which package is the end-user surface and which is the admin surface — `tokens` reads as "the token API" while `tokenmanagement` reads as "manage tokens". Both are accurate descriptions of the other. Compounding: the `package.json` `description` field is empty (line 4) for both packages, so npm registry browsers see only the name. -- **Category:** 12 (duplicate concepts across packages), 1 (vague), 6 (misleading — neither name expresses which audience it serves). -- **Suggested name:** Rename `tokens` → `usertokens` (or `mytokens`, `selftokens`) to mark the end-user surface; keep `tokenmanagement` for the admin surface. Or invert: rename `tokenmanagement` → `admintokens`. The wire URL `/api/2.0/token/...` can stay locked while npm/import paths use the disambiguated names. Worst case, document the audience boundary in each `package.json` description string. -- **Rationale:** A caller writing `import {Client} from '@databricks/sdk-tokens/v1'` has no signal that they're getting the workspace-self surface, not the admin surface. The same problem applies to `import {Client} from '@databricks/sdk-tokenmanagement/v1'`. Two distinct OpenAPI services with overlapping resource models and overlapping method names should not be named with this much ambiguity. - -### 2. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:37-46` +### 1. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:56-73` - **Why weird:** Type is named `PublicTokenInfo` but the surrounding context contains no `PrivateTokenInfo`, `InternalTokenInfo`, or any other counterpart. The "Public" qualifier therefore communicates nothing to a TS reader. From the wire perspective, the Go SDK presumably has a parallel internal type that *isn't* exposed; in TS, that distinction is invisible. Compare to `tokenmanagement.AdminTokenInfo` (also "TokenInfo"-flavoured) — the package uses `Admin` to clarify the audience, but `Public` here doesn't. - **Category:** 1 (vague qualifier), 6 (misleading — "Public" implies a public-vs-private dichotomy that doesn't surface in the SDK). - **Suggested name:** `TokenInfo` (drop the `Public` prefix) or `UserTokenInfo` (parallel to `AdminTokenInfo` in `tokenmanagement`). The wire field `token_info` is bare anyway — the qualifier is purely cosmetic. - **Rationale:** "Public" reads as a security qualifier (public-key, public-API) when the value is just "token metadata visible to the token owner". `UserTokenInfo` makes the audience explicit. -### 3. `PublicTokenInfo` vs `AdminTokenInfo` divergence — same conceptual resource, different shapes — `tokens/model.ts:37-46`, `tokenmanagement/model.ts` -- **Why weird:** Two parallel "token info" records describe the *same wire resource* (a Databricks PAT) with overlapping but non-identical field sets: - - `PublicTokenInfo`: `tokenId, creationTime, expiryTime, comment` (4 fields). - - `AdminTokenInfo`: 11 fields including `createdById, createdByUsername, ownerId, workspaceId, lastUsedDay, scopes, autoscopeState` (verify in `tokenmanagement/model.ts`). - - The two records describe the same wire-side resource (a PAT) but expose dramatically different views. The Public form lacks every attribution field (no creator, no owner, no workspace) and lacks any usage signal (no `lastAccessedTime` / `lastUsedDay`). The Admin form lacks nothing the Public form exposes. -- **Category:** 12 (duplicate concepts), 1 (vague qualifier on both type names). -- **Suggested name:** Two options: - 1. Document the public-vs-admin partition inline so readers know which fields appear where. - 2. Merge to a single `TokenInfo` with all fields optional, and document which subset the server populates for each endpoint. -- **Rationale:** A caller doing token introspection on the workspace needs to pick a package; the type-name doesn't tell them which fields they'll get. - -### 4. `Client.revokeToken` method paired with URL `/api/2.0/token/delete` — `client.ts:134,138` -- **Why weird:** Method on `Client` is `revokeToken`, but the wire URL it hits is `/api/2.0/token/delete`. Sibling `tokenmanagement.Client.deleteToken` maps `RevokeTokenRequest`/`RevokeTokenRequest_Response` to URL `/api/2.0/token-management/tokens/{id}` via HTTP `DELETE`. So: - - `tokens.revokeToken` → request type `RevokeTokenRequest` → URL ends in `/delete` → HTTP `POST` (revoke = delete on wire, named "revoke" in SDK). - - `tokenmanagement.deleteToken` → request type `RevokeToken*` → URL ends in `/tokens/{id}` → HTTP `DELETE` (delete on wire, named "delete" in SDK, request type still `Revoke*`). -- **Category:** 17 (inconsistent action verbs for the same conceptual operation), 13 (inconsistency between packages), 6 (misleading — the request type doesn't match the method verb). -- **Suggested name:** Pick one verb (`revoke` or `delete`) and use it for the method, the request type, and ideally the URL. The Go SDK uses `Delete` consistently, so the TS port should too. Or pick `revoke` consistently. Today, `RevokeTokenRequest` is the *request type* in both packages but only the `tokens` package method is called `revokeToken`. -- **Rationale:** Calling the same operation `revokeToken` in one package and `deleteToken` in another (with the *same request type* `RevokeTokenRequest`) is a recipe for confusion. A user code-completing on a client typed as "either of the two" cannot rely on method names. - -### 5. Proto-architectural-leak: `Foo_Response` underscored nested response types — `model.ts:21, 32, 54` -- **Why weird:** The package defines `CreateTokenRequest_Response`, `ListTokensRequest_Response`, and `RevokeTokenRequest_Response` — names that bake the Protobuf nested-message convention (`OuterMessage_InnerMessage`) directly into the public TypeScript surface. The underscore is a transport-format artefact (a Go/proto idiom for nested message types), not a TypeScript naming convention. Each declaration is even guarded with `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` — the codebase already knows these names violate TS conventions. The pattern matches the user's `Foo_PublicRequest` rule: a transport-layer naming structure leaking into the SDK's published types. Also propagates through `index.ts:9,11,14`, `client.ts:22,24,26,34,35,36,79,108,137,152`, and the schema names `unmarshal*Request_ResponseSchema` (`model.ts:68, 80, 106`). -- **Category:** Proto-architectural leak (transport-format identifier shape in public TS surface). -- **Suggested name:** Drop the underscore-nested form and use idiomatic TS response-type names: `CreateTokenResponse`, `ListTokensResponse`, `RevokeTokenResponse` (the existing `UpdateTokenResponse` on `model.ts:65` already follows this pattern, so the package is internally inconsistent). -- **Rationale:** Public TS APIs should not advertise the wire/proto provenance of a type. Mixing `UpdateTokenResponse` (clean) with `CreateTokenRequest_Response` (proto-style underscore) in the same module signals that the generator is mechanically translating proto nested-message names rather than producing idiomatic TS. The `eslint-disable` annotation in source is direct evidence that the names break the project's own lint rules. - -## Medium severity - -### 6. `UpdateTokenRequest` has BOTH `tokenId` and `token.tokenId` — duplicate IDs — `model.ts:56-62` -- **Why weird:** The request carries `tokenId?: string` (top-level) *and* `token?: PublicTokenInfo` which itself has `tokenId?: string`. Two fields for the same logical ID, easy to set inconsistently. The Client method uses `req.tokenId ?? ''` (`client.ts:171`) — so the top-level wins. But the `PublicTokenInfo.tokenId` inside `token` is still serialised on the wire (per `marshalUpdateTokenRequestSchema` on `model.ts:146-159`). -- **Category:** 12 (duplicate concept), 6 (misleading — which one is authoritative?), 11 (the inner one is dead-ish data). -- **Suggested name:** Drop one. Either: (a) make `token` exclude `tokenId` (`Omit`) and keep the top-level; or (b) drop the top-level and use `req.token.tokenId` in the client. -- **Rationale:** Two fields for the same identifier invite subtle bugs (server may pick the inner one if the top-level is empty). - -### 7. `Client` class name — colliding namespace — `client.ts:46` -- **Why weird:** Top-level class literally named `Client`. Re-exported in `index.ts` as just `Client`. A consumer importing from both `@databricks/sdk-tokens/v1` and `@databricks/sdk-tokenmanagement/v1` faces an identical name clash: - ``` - import {Client} from '@databricks/sdk-tokens/v1'; - import {Client as AdminTokensClient} from '@databricks/sdk-tokenmanagement/v1'; - ``` - Worse, both packages export a class with method `listTokens(req, options)` where `req` is a *different* `ListTokensRequest` type. Strong TS types catch the assignment error, but the duplication forces an alias at every dual import. -- **Category:** 1 (vague), 12 (duplicate name across packages). -- **Suggested name:** `TokensClient`, `UserTokensClient`, or `MyTokensClient`. Mirror with `TokenManagementClient`/`AdminTokensClient`. -- **Rationale:** Same finding as `rfa#37`, recurs across all packages — but particularly painful here given the `tokens`/`tokenmanagement` overlap. - ## Low severity -### 8. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:168` +### 2. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:224` - **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateTokenRequest` payloads must learn this helper. -- **Category:** 8 (helper-as-public-API), 13 (intra-package inconsistency — see #9 re-export gap). +- **Category:** 8 (helper-as-public-API). - **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. - **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. ## Observations -### 9. `index.ts` re-exports interfaces but not the `publicTokenInfoFieldMask` helper -The index file exports the `Client` and eight model interfaces (`CreateTokenRequest`, `CreateTokenRequest_Response`, `ListTokensRequest`, `ListTokensRequest_Response`, `PublicTokenInfo`, `RevokeTokenRequest`, `RevokeTokenRequest_Response`, `UpdateTokenRequest`, `UpdateTokenResponse`). It does *not* export the `publicTokenInfoFieldMask` helper. Consistent with sibling packages but means a downstream consumer cannot build field masks without reaching into `./model` directly. Same finding as `rfa#43`. - -### 10. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:171` -`const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:58`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. - -## Domain glossary -- **`tokens`** — npm package name; represents the *workspace user* PAT surface (create / list / revoke / update one's own tokens). Wire: `/api/2.0/token/...`. -- **`tokenmanagement`** — sibling npm package; represents the *workspace admin* PAT surface (inspect / revoke any user's tokens, create service-principal on-behalf-of tokens). Wire: `/api/2.0/token-management/...`. -- **`PAT`** — Personal Access Token. Databricks workspace bearer tokens issued to users or service principals. -- **`PublicTokenInfo`** — The token-metadata record visible to the *owner* of the token (no `createdBy*`, no `ownerId`, no `workspaceId`). Now a 4-field record after the regeneration removed `scopes`, `lastAccessedTime`, `autoscopeState`, `inferredScopes`, `backfillScopes`. -- **`AdminTokenInfo`** — (`tokenmanagement` package) the token-metadata record visible to a *workspace admin* (carries `createdById`, `createdByUsername`, `ownerId`, `workspaceId`, `lastUsedDay`). -- **`FieldMask`** — Google protobuf convention for sparse-field updates in PATCH semantics. `publicTokenInfoFieldMask(...)` builds the wire-format paths for `UpdateTokenRequest.updateMask`. - -## File coverage -- `src/v1/model.ts` (176 lines): read fully. -- `src/v1/client.ts` (192 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (18 lines): read fully. -- Cross-referenced `packages/tokenmanagement/src/v1/` for overlap analysis (see findings #1, #3, #4, #6). +### 3. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:176` +`const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:89`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 7fbf3a4f..5cd1a29e 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -3,15 +3,14 @@ **Path:** `packages/usagedashboards/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). -**Total weird names flagged:** 11 +**Total weird names flagged:** 7 ## Summary | Severity | Count | | --- | --- | -| High | 4 | -| Medium | 5 | -| Low | 0 | -| Observation | 2 | +| High | 3 | +| Medium | 3 | +| Observation | 1 | ## High severity @@ -21,84 +20,39 @@ - **Suggested name:** `usagedashboard` (singular) — or, better, fold into a `billing` package alongside `billableusagedownload` (which has the same parent `/api/2.0/accounts/{account_id}` namespace). - **Rationale:** A user discovering the SDK would expect a "list" operation from a plural package name and be surprised by the lack of one. The singular form also matches the REST path `/dashboard`. The fold-into-`billing` move is a generator-level concern but worth flagging: both `usagedashboards` and `billableusagedownload` are about account-level billing data and live under the same URL prefix. -### 2. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 40` / `src/v1/client.ts:109-110` -- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:109-110`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. +### 2. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 39` / `src/v1/client.ts:106-107` +- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:106-107`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. - **Category:** 6 (misleading — TS type says optional, API likely requires it), 16 (field type contradicts domain reality), 17 (inconsistent transport: same field is body on POST, query on GET). - **Suggested name:** Keep the name but type as `UsageDashboardType` (required). Or split the DTO into `CreateBillingUsageDashboardRequest` (body) and `GetBillingUsageDashboardRequest` (query params), since the GET endpoint conceptually has different parameter semantics from the POST. - **Rationale:** `dashboardType` is the field that distinguishes Workspace from Global dashboards — it is *the* selector for the resource. Treating it as optional with no default is type-level dishonesty. -### 3. `workspaceId: number` typed as JS `number` will silently truncate large IDs — `src/v1/model.ts:19, 36` -- **Why weird:** Databricks workspace IDs are 64-bit integers (the Go SDK uses `int64`); JavaScript's `number` type is IEEE-754 double which loses precision above 2^53. The TS field is typed `number | undefined`. Same finding applies to `metastores` and most workspace-scoped packages in the SDK, but worth flagging because every audit cycle compounds the risk. Compare with `accountId: string` (line 21) which correctly uses `string` for an account UUID. -- **Category:** 16 (field type contradicts domain — `number` cannot represent a 64-bit ID), 6 (misleading — type appears safe but is lossy). -- **Suggested name:** Keep the field name, change type to `string`. -- **Rationale:** Most workspace IDs are below 2^53 in practice, so this rarely bites. But the type contract claims something the runtime can't honour for the high end of the ID space. This is a systemic SDK-level issue worth raising at the generator. - -### 4. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:72, 104` -- **Why weird:** `accountId` lives on `CreateBillingUsageDashboardRequest` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:72, 104` — `${req.accountId ?? this.accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. +### 3. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:69, 101` +- **Why weird:** `accountId` lives on `CreateBillingUsageDashboardRequest` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:69, 101` — `${req.accountId ?? this.accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. - **Category:** 6 (misleading — body shape implies body field, but it's a path param), 12 (duplicate concept — also lives on `ClientOptions`), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree? what happens if both sources are missing?). - **Suggested name:** Remove `accountId` from the request DTOs entirely. Make it a client-level concern only; throw a clear error if it is missing. Or segregate path params into a separate type and document the dual role. - **Rationale:** Same as `billableusagedownload` finding. The current shape misleads callers about the wire format, the duplicated-with-fallback pattern is a footgun, and the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. ## Medium severity -### 5. `CreateBillingUsageDashboardRequest` / `GetBillingUsageDashboardRequest` include `Billing` but the package is `usagedashboards` — `src/v1/model.ts:17, 34` -- **Why weird:** The package is `@databricks/sdk-usagedashboards` (no "billing"); the types prefix `Billing` (no "Usage" alone). A user who imported the package by its `usage`-themed name then sees `Billing`-prefixed types and `Client.createBillingUsageDashboard()` method must mentally bridge `usage` ↔ `billing`. The package name and type names disagree on which noun is primary. -- **Category:** 17 (inconsistent action verbs / nouns across naming layers), 7 (overly verbose — `BillingUsage` is two synonyms for the same concept). -- **Suggested name:** Pick one noun. Either rename the package to `billingusagedashboards` (matches types) or drop `Billing` from the type names (`CreateUsageDashboardRequest` / `GetUsageDashboardRequest`). The Go SDK calls this domain "Billing → UsageDashboards" so types match Go; the TS package name is the outlier. -- **Rationale:** Cross-layer consistency. The simplest fix is `CreateUsageDashboardRequest` / `GetUsageDashboardRequest` since the package name is already `usagedashboards`. "Billing" is implied by the account-level endpoint path. - -### 6. `Client` class is unprefixed — `src/v1/client.ts:38` -- **Why weird:** Exported as `Client` (the only class). A user importing this package writes `import {Client} from '@databricks/sdk-usagedashboards/v1'`, then has to rename it (`import {Client as UsageDashboardsClient}`) to avoid collision with every other Databricks SDK package's `Client` export. Cross-SDK consistency — but worth flagging. -- **Category:** 1 (vague — `Client` of what?), 12 (every package defines its own `Client`). -- **Suggested name:** `UsageDashboardsClient` or `BillingUsageDashboardClient`. -- **Rationale:** Same finding as `billableusagedownload` audit #8. The SDK could expose a namespace export pattern (`import * as usageDashboards from '@databricks/sdk-usagedashboards/v1'`) and remove the `Client` symbol entirely, letting `usageDashboards.Client` be the qualified name. Not a blocker. - -### 7. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:68, 100` +### 4. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:65, 97` - **Why weird:** Method name and request-type name are textually identical (modulo case and the new `Request` suffix): `createBillingUsageDashboard(req: CreateBillingUsageDashboardRequest)`. The repetition is so close that the type name reads like a misnamed method import. Compare with `lakeview` where `Client.createDashboard(req: CreateDashboardRequest)` keeps the type-noun separate from the method-verb. - **Category:** 7 (overly verbose), 8 (redundant — method verb is already implicit in the type's verb prefix). - **Suggested name:** `createDashboard` / `getDashboard` (drop `BillingUsage` since the package name disambiguates) or `create` / `get` (since there are only two methods). Type stays as `CreateBillingUsageDashboardRequest`. - **Rationale:** A method on `usageDashboardsClient` is already in the usage-dashboards namespace; restating `BillingUsageDashboard` in the method name is pure stutter. The Go SDK does this because Go has package-flat method tables; TS classes provide their own namespace. -### 8. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:31, 46` +### 5. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:30, 44` - **Why weird:** Both response types include `dashboardId?: string` (always optional). But there is no `GetByDashboardId` method, and the request types use `(workspaceId, accountId, dashboardType)` to identify the dashboard, not the `dashboardId`. So `dashboardId` is a returned-but-never-accepted identifier — informational only. The field is also typed optional, but a successful 2xx response should always have an ID; the `?` is again type-level dishonesty. - **Category:** 6 (misleading optionality), 19 (underspecified id — present in responses but not accepted as a request key). - **Suggested name:** Keep the name; make it required (`dashboardId: string`). Or document that it is a read-only side-channel identifier (not a primary key from the API's POV). Or expose a `getByDashboardId` method that round-trips the value. - **Rationale:** If the API returns an ID, the SDK should either let you use it or document why you can't. The current state — return-only, never-accepted — is API-design noise that the SDK faithfully echoes. -### 9. `dashboardUrl` field is a `string` — should be `URL` or branded — `src/v1/model.ts:48` -- **Why weird:** `dashboardUrl?: string | undefined` — a URL is typed as a bare string. Callers must `new URL(resp.dashboardUrl)` defensively. Compare with `accountId`/`dashboardId` which are also strings but represent IDs, not URLs. No branded type distinguishes them. Also optional on a success response (same dishonesty as #8). -- **Category:** 15 (generic field name losing meaning), 6 (misleading optionality), 1 (vague — `string` for a URL). -- **Suggested name:** Keep the field name; consider a branded type (`type Url = string & {readonly _urlBrand: unique symbol}`) or `URL` (the WHATWG class). At minimum, make it non-optional on a 2xx response. -- **Rationale:** SDK-wide concern (every URL field in every package is `string`); flag once per audit. Branded URLs are a TS idiom precisely for this case. - -## Low severity - -_None._ +### 6. `dashboardUrl` is optional on a success response — `src/v1/model.ts:46` +- **Why weird:** `dashboardUrl?: string | undefined` is optional on a success response (same dishonesty as #5). A successful 2xx read should always carry the dashboard URL, so the `?` overstates the genuine variability of the field. +- **Category:** 6 (misleading optionality). +- **Suggested name:** Keep the field name; make it non-optional on a 2xx response. +- **Rationale:** If a successful read always returns a URL, the SDK should type it as required rather than forcing every caller to guard against an absence that never occurs. ## Observations -### 10. `BillingUsage` vs `UsageDashboard` noun ordering inconsistency -- The enum names are `UsageDashboardMajorVersion`, `UsageDashboardType` — `Usage` first, no "Billing". -- The request types are `CreateBillingUsageDashboardRequest` — `Billing` first, with `Usage`. -- The package is `usagedashboards` — `usage` only, no "billing". -- The Go SDK service is "Billing → UsageDashboards" — both nouns in two layers. - -Three different name compositions for one domain. A user trying to autocomplete `Billing` will find the request types but not the enums; trying `Usage` finds the enums but the type names appear under `Create...` / `Get...`. The SDK should pick one noun order (e.g., `BillingUsageDashboard*` everywhere, or `UsageDashboard*` everywhere) and stick to it. See also #5. - -### 11. The package has no list/page operations +### 7. The package has no list/page operations There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. - -## Domain glossary -- `usage dashboard` — A Databricks-managed dashboard (DBSQL or AI/BI Lakeview) that visualises account-level billing/usage data. Two flavours: **Workspace** (per-workspace) and **Global** (all workspaces in an account). -- `DBU` — Databricks Unit; the standard unit of compute consumption. Notably absent from this package's types and JSDoc — verified via grep that the literal "DBU" never appears, even though DBUs are the unit the dashboard would visualise. -- `account ID` — Databricks account identifier (UUID); surfaces as `accountId: string` on both request types and on `ClientOptions.accountId`. -- `workspace ID` — Databricks workspace identifier (64-bit int); surfaces as `workspaceId: number` — see finding #3 about the precision issue. -- `major version` — Template version of the dashboard (1 or 2). Per the JSDoc, defaults to `VERSION_1` if unspecified at create time. -- `dashboard ID` — Identifier of the created dashboard (returned, not accepted as input). See finding #8. -- `E2` — Databricks deployment architecture; not mentioned in this package but implicit (account-level endpoints are E2-only). - -## File coverage -- `src/v1/model.ts` (86 lines): read fully. -- `src/v1/client.ts` (136 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. -- `src/v1/index.ts` (13 lines): read fully. diff --git a/.agent/naming-audit/usagepolicy.md b/.agent/naming-audit/usagepolicy.md deleted file mode 100644 index a0c2f216..00000000 --- a/.agent/naming-audit/usagepolicy.md +++ /dev/null @@ -1,127 +0,0 @@ -# Naming Audit: usagepolicy - -**Path:** `packages/usagepolicy/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Account-level "Usage Policy" management — create/get/list/update/delete cost-attribution policies that attach custom tags to billing usage and can be bound to specific workspaces. Hits `POST/GET/PATCH/DELETE /api/2.1/accounts/{accountId}/usage-policies`. The JSDoc on `UsagePolicy` reads "Contains the UsagePolicy details (same structure as BudgetPolicy)" — i.e. this package is an explicit clone of the sibling `budgetpolicy` package with a renamed entity and a bumped API version (`/api/2.1` vs `/api/2.0`). -**Total weird names flagged:** 16 - -## Summary -| Severity | Count | -| --- | --- | -| High | 3 | -| Medium | 5 | -| Low | 3 | -| Observation | 5 | - -## High severity - -### 1. Whole package duplicates `budgetpolicy` with a renamed entity — `src/v1/model.ts` (entire file) vs `packages/budgetpolicy/src/v1/model.ts` -- **Why weird:** `UsagePolicy` is `BudgetPolicy` with `Usage` substituted for `Budget`. The shared types (`CustomPolicyTag`, `Filter`, `LimitConfig`, `SortSpec`, `SortSpec_Field`) are textually identical between the two packages. The `UsagePolicy.policyId` JSDoc even confirms: "(same structure as BudgetPolicy)" (line 120). Same `/accounts/{accountId}/{verb}-policies` URL shape, same wire fields. The only material difference is the API version (`/api/2.1` vs `/api/2.0`) and the URL segment (`usage-policies` vs `budget-policies`). -- **Category:** 12 (duplicate concept — two sibling packages with the same shape and overlapping name), 1 (vague — `usage` and `budget` both modify the same underlying tag-policy concept). -- **Suggested name:** Either (a) collapse `usagepolicy` and `budgetpolicy` into a single package with a versioned entity, or (b) ensure both publish under distinct, non-overlapping type names. As shipped, a consumer importing both packages cannot disambiguate `Filter`, `LimitConfig`, `SortSpec`, `CustomPolicyTag`, or `Client` without aliasing. -- **Rationale:** This is the headline finding for the package. The duplication is a 1:1 clone, and the API team did not even bother to rename the reserved custom-tag keys: `CustomPolicyTag.key` JSDoc in `usagepolicy` still says `"budget-policy-name"`, `"budget-policy-id"`, `"budget-policy-resolution-result"` (line 27, copied from `budgetpolicy`). Two clones in one SDK with collidable names is a real usability problem. - -### 2. `Filter` (bare top-level type) — `src/v1/model.ts:47` -- **Why weird:** Re-exported from `index.ts:11` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (`Array#filter`, RxJS `filter`, content filters, etc.) and the type is package-scoped — but the re-export under this name *directly collides* with the same bare `Filter` in `packages/budgetpolicy/src/v1/model.ts:77`. Any user importing both packages will hit a name clash. -- **Category:** 1 (vague/generic), 12 (duplicate concept across two sibling packages with the same name). -- **Suggested name:** `UsagePolicyFilter` (and rename the sibling to `BudgetPolicyFilter`). -- **Rationale:** A bare `Filter` provides zero discoverability and forces a collision with `budgetpolicy.Filter`. Both packages target the same account-level API; consumers will frequently import both. This finding is doubly bad because the two `Filter` types have identical structure but are not type-compatible from TS's structural-typing perspective at the import boundary if a consumer aliases one (`import {Filter as BudgetFilter}`). - -### 3. `UsagePolicy.bindingWorkspaceIds: number[]` representation — `src/v1/model.ts:129` -- **Why weird:** Workspace IDs are typed as `number[]`. Databricks workspace IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so workspace IDs `>2^53` will silently lose precision. Same problem on `Filter.creatorUserId: number` (line 57). -- **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). -- **Suggested name:** `bindingWorkspaceIds: bigint[]` or `string[]` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Generator/policy issue across the SDK. Worth flagging at every usage site. - -## Medium severity - -### 4. `CustomPolicyTag` type name — `src/v1/model.ts:23` -- **Why weird:** Type is just `{key, value}` — i.e. a plain tag. `CustomPolicyTag` is a triple-loaded name: "custom" (versus what? a built-in tag?), "policy" (which policy? the only one in scope), "tag" (the actual semantic noun). Two of the three words are redundant in context. Also colliding with the same `CustomPolicyTag` exported from `budgetpolicy/src/v1/model.ts:53`. -- **Category:** 7 (overly verbose), 8 (redundant prefix `CustomPolicy*` already implied by location), 12 (duplicate concept across siblings with identical name). -- **Suggested name:** `Tag` (in this package it's unambiguous) or `PolicyTag`. -- **Rationale:** `customTags: CustomPolicyTag[]` reads as type-suffix tautology + redundant `Custom`. The doc on `CustomPolicyTag.key` even calls them "custom tags". - -### 5. `CustomPolicyTag` reserved-key documentation refers to `budget-policy-*` keys — `src/v1/model.ts:27-29` -- **Why weird:** Doc says key cannot be `"budget-policy-name"`, `"budget-policy-id"` or `"budget-policy-resolution-result"`. These reserved keys are the wire-form spelling **from the budget-policy domain** — copy-pasted verbatim from the `budgetpolicy` package without renaming to the usage-policy equivalents (one would expect `usage-policy-name` etc.). Either (a) the wire really *does* use the `budget-policy-*` prefix (which is a Databricks API design issue worth surfacing), or (b) the JSDoc was lazily duplicated and the actual reserved keys are different. -- **Category:** 6 (misleading: cross-domain magic strings that callers must memorise), 12 (duplicate across siblings — but here it's a *bug*, because the reserved keys are not surfaced as constants and may differ from `budgetpolicy`), 18 (long magic string sentinels). -- **Suggested name:** Either expose a `RESERVED_TAG_KEYS` constant per package, or validate the wire payload and throw a typed error. If the wire truly shares the budget-policy reserved keys, the JSDoc should say "(shared with budget-policy)" to remove the ambiguity. -- **Rationale:** Documentation-only constraints are easy to violate and produce server-side 400s. Either way the verbatim duplication smells. - -### 6. `Filter.creatorUserId: number` representation — `src/v1/model.ts:57` -- **Why weird:** User IDs are typed as `number`. Databricks user IDs are 64-bit integers. JS `number` only has 53-bit safe integer precision, so user IDs `>2^53` will silently lose precision. -- **Category:** 16 (field type contradicts domain — int64 in a 53-bit number type), 19 (underspecified ID — no encoding documented). -- **Suggested name:** `creatorUserId: bigint` or `string` (matches Databricks REST API serialisation of large IDs). -- **Rationale:** Same as finding #3 but for the filter field. Generator-wide concern; same problem on `bindingWorkspaceIds: number[]`. - -### 7. `SortSpec` type — `src/v1/model.ts:103` -- **Why weird:** `SortSpec` (specification) and `Field` together build the "what to sort by" structure. `Spec` is generic — every type is a spec of something. The wrapping type holds two fields (`field` + `descending`); a one-or-two-field pair could be inlined into the request. -- **Category:** 1 (vague suffix `Spec`), 11 (trivial wrapper holding two fields). -- **Suggested name:** `SortOptions`, or inline as `sortField?: SortField; sortDescending?: boolean` on the request. -- **Rationale:** `Spec` adds no information. `sortBy: SortField` plus a boolean is more direct. Mirrors `budgetpolicy` finding #17. - -### 8. `UpdateUsagePolicyRequest` has **no** `updateMask` field — `src/v1/model.ts:111-118` -- **Why weird:** `budgetpolicy.UpdateBudgetPolicyRequest` (`packages/budgetpolicy/src/v1/model.ts:165`) carries an `updateMask?: FieldMask` plus a `budgetPolicyFieldMask(...paths)` builder. `usagepolicy.UpdateUsagePolicyRequest` does not. Either (a) the usage-policy API genuinely uses replace-on-PATCH semantics (no partial updates) — in which case the JSDoc should say so — or (b) the SDK is missing field-mask support that the API offers. Without inspection of the OpenAPI source, either is plausible, and the absence of a doc note is itself a finding. -- **Category:** 17 (inconsistency across near-clone sibling packages), Observation (potential missing surface). -- **Suggested name:** If full-replace: document on `UpdateUsagePolicyRequest`. If partial-update: add `updateMask?: FieldMask` and a `usagePolicyFieldMask(...paths)` helper to match the sibling. -- **Rationale:** A user toggling between the two clones will expect parity. The divergence is silent and unjustified by either docstring. - -## Low severity - -### 9. `Client` class plain name — `src/v1/client.ts:46` -- **Why weird:** Top-level export `Client`. When a consumer imports `Client` from `@databricks/sdk-usagepolicy/v1`, they will almost certainly alias it (`import {Client as UsagePolicyClient}`) to avoid collision with `Client` from every other package — including the byte-identical class from `@databricks/sdk-budgetpolicy/v1`. -- **Category:** 1 (vague — `Client` is the most generic name in the SDK ecosystem), 12 (duplicate across all packages, *especially* this one and `budgetpolicy`). -- **Suggested name:** `UsagePolicyClient`. -- **Rationale:** Each generated package emits a `Client`. With `usagepolicy`/`budgetpolicy` being near-clones, the importer who needs both will be forced into double-aliasing. - -### 10. `req` parameter name on client methods — `src/v1/client.ts:77,103,122,147,194,212` -- **Why weird:** Abbreviation `req` instead of `request`. Six occurrences in `client.ts`. -- **Category:** 5 (cryptic abbreviation when the long form fits comfortably). -- **Suggested name:** `request`. -- **Rationale:** Style. Comments on `client.ts` already use the full word. Same convention should apply to params for hovers. Same as `budgetpolicy` finding #35. - -### 11. `SortSpec_Field` proto-style underscore-nested enum name — `src/v1/model.ts:6` -- **Why weird:** Underscored identifier `SortSpec_Field` mirrors protobuf's "ParentMessage_NestedEnum" wire convention and is unidiomatic in TypeScript. The file even carries `// eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.` on line 5, confirming the proto-architectural leak. Re-exported from `index.ts:5` so the leak reaches consumers verbatim. -- **Category:** Proto-architectural leak — proto-nested-type naming convention surfaced into the TS public API. -- **Suggested name:** `SortField` (or namespace it under `SortSpec` as `SortSpec.Field` if the nesting relationship matters). -- **Rationale:** TS has no `Parent_Nested` convention; the underscore is a direct proto leak. Mirrors the same finding in `budgetpolicy` (`SortSpec_Field` at `budgetpolicy/src/v1/model.ts:8`). - -## Observations - -### 12. URL-path version split (`/api/2.1` vs `/api/2.0`) is the only meaningful API surface difference -The only on-the-wire distinction between this package and `budgetpolicy` is the URL: `/api/2.1/accounts/{accountId}/usage-policies` (`client.ts:80,106,125,150,215`) vs `/api/2.0/accounts/{accountId}/budget-policies`. Same HTTP verbs, same query parameter names (`page_size`, `page_token`, `filter_by`, `sort_spec`, `limit_config`), same request and response shapes. If the two endpoints are intended to converge under the `2.1` URL, `budgetpolicy` is likely v1 of the same surface and this package supersedes it. If they are intended to coexist, the type names should not collide. -- **Category:** 12 (duplicate concept), 1 (vague package boundary). - -### 13. No `FieldMask` import in `usagepolicy/src/v1/model.ts` -Unlike `budgetpolicy/src/v1/model.ts:3-4` which imports `FieldMask` from `@databricks/sdk-core/wkt` and emits a `budgetPolicyFieldMask(...paths)` helper (lines 271-282), `usagepolicy` has no `FieldMask` machinery at all. This is linked to finding #8 (no `updateMask` on the update request). Either the API genuinely doesn't support field masks (the SDK is correct), or it does and the SDK is missing the support. -- **Category:** Observation / 17 (cross-package inconsistency). - -### 14. Action-verb conventions in `Client` -The client consistently uses `create`/`delete`/`get`/`list`/`update` verbs. No mixed `fetch`/`retrieve`/`read`. -- **Category:** 17 (observation of consistency, per rule that we flag inconsistencies — this is the inverse). - -### 15. Acronym casing `Id` consistently used as `Id`, not `ID` -`policyId`, `accountId`, `creatorUserId`, `bindingWorkspaceIds`, `requestId`, `pageSize`/`pageToken`. Internal consistency holds. Inconsistent only with external `URLSearchParams` (Web API; out of our control). -- **Category:** 3 (observation — internal acronym style is consistent). - -### 16. Wire-form vs kebab-case vs TS casings (`usage_policies` / `usage-policies` / `usagePolicies`) -The same identifier appears in three forms in the same client file: -- `usage_policies` — wire form (in the Zod schemas via snake_case keys). -- `usage-policies` — URL path segment (`client.ts:80,106,125,150,215`). -- `usagePolicies` — TS type/method names. - -Readers must mentally translate. Worth flagging because the kebab-case form does not appear in the audit findings unless one inspects the URL building code. -- **Category:** 3 (acronym/casing inconsistency — three forms of the same identifier). - -## Domain glossary -- `usage policy` — A named policy that attaches custom tags to billing usage and optionally restricts which workspaces apply it. Same structure as `budgetpolicy.BudgetPolicy` per the JSDoc on `UsagePolicy` (line 120). Despite "usage" in the name, no usage-data concept (rows/metrics/period) lives on the model — only tags and workspace bindings. -- `binding workspace` — A workspace that the policy is exclusively applied to (subset of account workspaces). Implementation: `UsagePolicy.bindingWorkspaceIds: number[]`. -- `custom tag` — A `{key, value}` pair attached to billing usage. Reserved keys per JSDoc: `budget-policy-name`, `budget-policy-id`, `budget-policy-resolution-result` (note: keys retain the `budget-policy-` prefix even though this is the *usage* policy package — see finding #5). -- `account id` — The Databricks account-level identifier (path segment in URL: `/api/2.1/accounts/{accountId}/usage-policies`). -- `policy id` — Generated server-side; globally unique. Used as the resource id in get/update/delete paths. - -## File coverage -- `src/v1/model.ts` (230 lines): read fully. -- `src/v1/client.ts` (252 lines): read fully. -- `src/v1/utils.ts` (151 lines): read fully. Byte-identical to `budgetpolicy/src/v1/utils.ts` (same 4012-byte file size). -- `src/v1/index.ts` (20 lines): read fully. -- Cross-referenced: `packages/budgetpolicy/src/v1/model.ts`, `packages/budgetpolicy/src/v1/client.ts`, `packages/budgetpolicy/src/v1/index.ts` (the near-clone sibling), and previously-audited `.agent/naming-audit/budgetpolicy.md` for consistency. diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md index 85c18ab7..515944b2 100644 --- a/.agent/naming-audit/vectorsearch.md +++ b/.agent/naming-audit/vectorsearch.md @@ -3,120 +3,44 @@ **Path:** `packages/vectorsearch/src/v1/` (consolidation of the prior `endpoints` and `indexes` packages from the 2026-05-22 regen) **Versions audited:** v1 **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` -**Inferred domain:** Databricks AI/Vector Search — endpoint management (create, get, list, patch, delete, budget-policy patch) and vector-index management (create, get, list, query, query-next-page, scan, sync, upsert-data, delete-data, delete). Routes under `/api/2.0/vector-search/endpoints` and `/api/2.0/vector-search/indexes`. Hosts a single `Client` with mixed endpoint and index methods plus a single `CreateEndpointWaiter`. -**Total weird names flagged:** 14 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | ------------ | ----- | -| High | 5 | -| Medium | 6 | -| Low | 2 | -| Observation | 1 | -| **Total** | **14** | - -Dominant themes: -1. **Two resource families share one flat `Client`.** Endpoint methods (`createEndpoint`, `getEndpoint`, …) and index methods (`createVectorIndex`, `queryVectorIndex`, …) sit side by side on the same class. The result is long method names that re-encode the resource family (`createVectorIndex` instead of `client.indexes.create()`), plus a single waiter that only covers endpoints. -2. **`Endpoint` is a Databricks-wide overloaded noun.** Bare `Endpoint`, `EndpointType`, `EndpointStatus`, `EndpointScalingInfo` collide with `modelserving.InferenceEndpoint`, `warehouses.EndpointState`, and other "endpoint" concepts. The package name `vectorsearch` qualifies the import, but destructured types lose that context. -3. **Near-duplicate types.** `VectorIndex` ≡ `MiniVectorIndex` (identical field set), `DeltaSyncVectorIndexSpec` ≡ `DeltaSyncVectorIndexSpecRequest` (identical field set). The duplication is gratuitous given that `DirectAccessVectorIndexSpec` has no `Request` twin. +| High | 1 | +| Medium | 3 | +| **Total** | **4** | --- ## High severity -### 1. `Endpoint` bare top-level type collides with sibling packages — `src/v1/model.ts:274`, `src/v1/index.ts:31` -- **Why weird:** `Endpoint` is exported unqualified. The sibling `modelserving` package exports `InferenceEndpoint` (qualified); the sibling `warehouses` package exports `EndpointState`, `EndpointSecurityPolicy`, etc. A consumer who imports `{Endpoint}` from this package and writes `function process(e: Endpoint)` has no way to tell from the local signature whether `e` is a vector-search endpoint, an inference endpoint, or a SQL warehouse endpoint. The package-level rename to `vectorsearch` qualifies the import path but is destructured away at the use site. -- **Category:** 1 (vague/generic), 15 (generic field name losing meaning across packages). -- **Suggested name:** `VectorSearchEndpoint` (mirrors `modelserving.InferenceEndpoint`). Sibling types (`EndpointType`, `EndpointStatus`, `EndpointScalingInfo`) follow. -- **Rationale:** "Endpoint" alone is the most generic REST noun. Disambiguation at the type level is needed once the type leaves the import statement. - -### 2. `listEndpoint` / `listVectorIndex` method names are singular for collection operations — `src/v1/client.ts:317, 365` +### 1. `listEndpoint` / `listVectorIndex` method names are singular for collection operations — `src/v1/client.ts:348, 399` - **Why weird:** Both methods return a collection (`ListEndpointResponse.endpoints: Endpoint[]`, `ListVectorIndexResponse.vectorIndexes: MiniVectorIndex[]`) yet the method names are singular. The corresponding URLs are plural (`/endpoints`, `/indexes`) and the body field names are plural. The request/response types (`ListEndpointRequest`, `ListEndpointResponse`, `ListVectorIndexRequest`, `ListVectorIndexResponse`) inherit the singular form. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verbs). - **Suggested name:** `listEndpoints`, `listVectorIndexes`, `ListEndpointsRequest`, `ListEndpointsResponse`, `ListVectorIndexesRequest`, `ListVectorIndexesResponse`. The iterator pair (`listEndpointIter`, `listVectorIndexIter`) follows: `listEndpointsIter`, `listVectorIndexesIter`. - **Rationale:** A collection method should be plural to match its return type, the wire URL, and the response field shape. -### 3. `MiniVectorIndex` and `VectorIndex` are structurally identical duplicates — `src/v1/model.ts:376-399` vs `:572-595` -- **Why weird:** Both types declare exactly the same nine fields (`name`, `endpointName`, `primaryKey`, `indexType`, `indexSpec`, `status`, `creator`, `indexSubtype`) with identical JSDoc on the fields they share. `MiniVectorIndex` is used in `ListVectorIndexResponse.vectorIndexes` (the list-view element type); `VectorIndex` is used everywhere else. With no field-level difference, the type split is gratuitous — and the "Mini" qualifier is cryptic (industry convention is `Summary`, `ListItem`, `Brief`, `Ref`). -- **Category:** 12 (duplicate concept), 5 (cryptic abbreviation), 1 (vague qualifier). -- **Suggested name:** Either `export type VectorIndexSummary = VectorIndex` (with a JSDoc note that the wire form is currently identical), or drop `MiniVectorIndex` entirely and use `VectorIndex` in list responses. If the API intends them to diverge later, document the upcoming difference. -- **Rationale:** Two ~25-line type definitions with no semantic distinction is a maintenance hazard. The "Mini" prefix tells the reader nothing about what is omitted (because nothing is). - -### 4. `DeltaSyncVectorIndexSpec` and `DeltaSyncVectorIndexSpecRequest` are structurally identical — `model.ts:175-205` vs `:207-237` -- **Why weird:** Two exported types with identical field sets (`sourceTable`, `embeddingSourceColumns`, `embeddingVectorColumns`, `pipelineType`, `pipelineId`, `embeddingWritebackTable`, `columnsToSync`, `columnsToIndex`) and identical JSDoc on every shared field. The `Request` twin exists only for `DeltaSync` — `DirectAccessVectorIndexSpec` has no `Request` variant. The asymmetry is unexplained and the structural identity makes the split feel arbitrary. -- **Category:** 12 (duplicate concept), 8 (redundant `Request` suffix when the type has no distinguishing fields). -- **Suggested name:** Collapse to one type (`DeltaSyncVectorIndexSpec` used in both request and response positions, mirroring `DirectAccessVectorIndexSpec`), or document the planned divergence prominently. -- **Rationale:** The mismatch with `DirectAccessVectorIndexSpec` (no `Request` twin) shows the duplication is gratuitous. Users serializing a `DeltaSyncVectorIndexSpec` for a create call have to discover that `*Request` is the right one only by reading the function signature. - -### 5. `EndpointStatus_State.OFFLINE` is a terminal-failure state but reads as transient — `model.ts:72`, `client.ts:641-644, 680-681` -- **Why weird:** The waiter's terminal-state switch (`client.ts:637-647`) treats `EndpointStatus_State.OFFLINE` as a *failure* and throws. The enum identifier "OFFLINE" however reads as a transient lifecycle state ("the endpoint is currently offline"), implying it might come back online. JSDoc on the enum value is absent; the only hint is in the comment block above `RED_STATE`/`YELLOW_STATE`. A reader inspecting the enum would not predict that the waiter throws on OFFLINE. -- **Category:** 6 (misleading), 16 (field type contradicts domain — lifecycle name implies transient, runtime semantics are terminal). -- **Suggested name:** If the wire allows, rename to `FAILED` or `TERMINATED` to match the runtime semantics. Otherwise, add JSDoc on `OFFLINE` clarifying that it is a terminal failure state, distinct from "temporarily not serving traffic". -- **Rationale:** A user inspecting the enum to write their own polling logic will conclude that `OFFLINE` is recoverable and miss the failure path entirely. - --- ## Medium severity -### 6. `IndexSubtype` vs `VectorIndexType` — two enums on different "type" axes — `model.ts:29, 62` -- **Why weird:** Two enums both describing a "type" axis of a vector index. `IndexSubtype = {VECTOR, FULL_TEXT, HYBRID}` is the search-semantics axis (what kind of similarity is computed). `VectorIndexType = {DELTA_SYNC, DIRECT_ACCESS}` is the data-residency axis (how data flows in). Both surface as `index*Type*` fields on `VectorIndex`. A first-time reader cannot tell which axis is which without reading both JSDocs. -- **Category:** 6 (misleading — both look like "the type" of the index), 17 (inconsistent naming for two type axes). -- **Suggested name:** Disambiguate: `IndexSearchMode` for the search-semantics axis, `IndexBackingMode` (or `IndexStorageType`) for the data-residency axis. Or `IndexSearchKind` / `IndexSyncMode`. -- **Rationale:** Two parallel `*Type` enums on the same type make the API harder to learn. Naming each by its axis would self-document. - -### 7. `IndexSubtype` exposes an unsupported value `VECTOR` — `model.ts:29-33` -- **Why weird:** The enum's first member is `VECTOR`, and its JSDoc says "Not supported. Use `HYBRID` instead." A public-API enum that exposes a value whose only documented behavior is "do not use" inflates the surface area and forces every switch statement to handle it. Also, "VECTOR" inside an enum on a vector-search index is tautological — every value is some kind of vector behavior. -- **Category:** 6 (misleading: present but explicitly unsupported), 18 (the value itself is content-free against the enum name). -- **Suggested name:** Remove `VECTOR` from the enum, or document the deprecation path in JSDoc and timeline for removal. -- **Rationale:** Dead enum members are bug magnets. - -### 8. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:51-55, 554` -- **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:155, 550` — "Result of the upsert or delete operation"). +### 2. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:52-56, 633` +- **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:156, 629` — "Result of the upsert or delete operation"). - **Category:** 13 (verb-coupling), 7 (verbose), 1 (generic `Status`/`Result`). - **Suggested name:** Split into `UpsertDataStatus` / `DeleteDataStatus` (aliases of the same wire enum), or use a neutral name `DataMutationStatus` / `DataMutationResult`. - **Rationale:** Two-verb compound nouns are unusual and confusing. Most APIs use a single neutral noun for shared response types. -### 9. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:136-145` +### 3. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:149-158` - **Why weird:** Two methods with the same verb start (`createEndpoint` / `createEndpointWaiter`). The waiter version *calls* `createEndpoint` then wraps the result in a `CreateEndpointWaiter`. A reader sees two `create*` methods and may think they are different operations. The Java/Go SDK convention surfaces a waiter via a side return; TS would more naturally inline the wait (`createEndpointAndWait`). - **Category:** 7 (verbose), 13 (verb overlap), 17 (inconsistent action verbs). - **Suggested name:** Either fold the wait into `createEndpoint` (return a `CreateEndpointWaiter` that is both an awaitable and the resource shape), or rename to `createEndpointAndWait`, or expose a single `waitForEndpoint(name)` that any caller can use after `createEndpoint`. - **Rationale:** Two `create*` methods for one logical "create" operation force every caller to learn which one to use. There is also no analogous waiter for the index create flow, so the pattern is inconsistent within the package. -### 10. `EndpointStatus_State.RED_STATE` / `YELLOW_STATE` carry redundant `_STATE` suffix — `model.ts:79-80` -- **Why weird:** The enum is already `EndpointStatus_State` and the other members (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) do not carry the suffix — only the health-colored values do. Reads `EndpointStatus_State.RED_STATE` — "endpoint status state . red state". Inconsistent within the enum. -- **Category:** 16 (field/value contradicting type domain), 8 (redundant suffix). -- **Suggested name:** If wire allows, `RED` / `YELLOW` (matches `PROVISIONING` / `ONLINE` shape). Otherwise, document the asymmetry. -- **Rationale:** Inconsistency within a single enum is a generator-spec issue worth surfacing. - -### 11. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:69-87` -- **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 73-83 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. +### 4. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:70-88` +- **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 74-79 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. - **Category:** 16 (field contradicting domain — two orthogonal axes squeezed into one enum), 6 (misleading). - **Suggested name:** Split into `EndpointLifecycleState` and `EndpointHealth`. Reflect both on `EndpointStatus` as two fields. - **Rationale:** Single-enum mixing of orthogonal dimensions is an API-design smell. - ---- - -## Low severity - -### 12. `columnsToSync` and `columnsToIndex` are documented as aliases — `model.ts:197-204, 229-236` -- **Why weird:** Two array fields on the same type, JSDoc on `columnsToIndex` says: "Alias for columns_to_sync. ... Only one of columns_to_sync or columns_to_index may be specified." Two fields that mean the same thing, where the API rejects both being set, is an API-level footgun. The SDK exposes both without runtime validation. -- **Category:** 12 (duplicate concept by design), 6 (misleading — both look valid). -- **Suggested name:** Mark `columnsToSync` `@deprecated` if `columnsToIndex` is the canonical form (or vice versa), and add runtime validation in `marshalDeltaSyncVectorIndexSpecRequestSchema`. -- **Rationale:** API-level aliases are upstream policy, but the SDK should mark the deprecated alias to steer callers. - -### 13. `RerankerConfig.parameters.columnsToRerank` duplicates `QueryVectorIndexRequest.columnsToRerank` — `model.ts:462, 491` -- **Why weird:** `QueryVectorIndexRequest` has both `columnsToRerank: string[]` at the top level (line 462) AND a `reranker.parameters.columnsToRerank: string[]` nested inside `RerankerConfig_RerankerParameters` (line 491). Same field name, same purpose, two places. The JSDoc on `reranker` references "`columns_to_rerank`" without saying which copy wins. -- **Category:** 12 (duplicate concept), 6 (misleading — precedence unclear). -- **Suggested name:** Drop one, or document the precedence in JSDoc. If one is for input and the other for echoed-back output, name them accordingly. -- **Rationale:** Users will set the wrong field, or both, and silently get the wrong rerank behavior. - ---- - -## Observation - -### 14. `usagePolicyId` JSDoc admits incomplete rollout — `model.ts:104` -- **Why weird:** JSDoc reads "The usage policy id to be applied once we've migrated to usage policies". A field whose JSDoc admits the rollout is incomplete leaves callers guessing whether setting it has any effect today. -- **Category:** 6 (misleading — present but possibly inactive). -- **Suggested name:** Either remove the field until usage policies ship, or rewrite the JSDoc to spell out the current behavior and rollout timeline. -- **Rationale:** Documentation-only TODOs leak generator/spec-side state into the public API. Worth surfacing. diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index 212d6300..fcef2486 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -1,64 +1,26 @@ # Naming Audit: `volumes` (v1) -Package path: `/home/parth.bansal/sdk-js/packages/volumes/` +Package path: `/home/parth.bansal/sdk-js/packages/uc/volumes/` Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`. -Notation: file paths are absolute. Findings reference `file:line`. - ## Summary | Severity | Count | | ----------- | ----- | -| High | 2 | -| Medium | 4 | -| Low | 0 | -| Observation | 2 | -| **Total** | **8** | - -Headline themes: - -1. **`fullNameArg` is a cryptic, Go/proto-generator-driven name** that leaks - internal path-parameter terminology into the public TypeScript API. The - `Arg` suffix is meaningless to TS users and inconsistent with the - `fullName` field on the response/info shapes. Appears on - `GetVolumeRequest`, `DeleteVolumeRequest`, and `UpdateVolumeRequest` - (model.ts:56, 75, 126). -2. **`Create*` / `Update*` request types include read-only output fields** - (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, - `volumeId`, `fullName`, `browseOnly`). These belong only on - `VolumeInfo`. They appear on the request shapes because the upstream - proto reuses the same message — but on the TypeScript surface they - misleadingly invite users to "set" server-managed values. +| High | 1 | +| Medium | 3 | +| Observation | 1 | +| **Total** | **5** | --- ## High Severity -### H1. `fullNameArg` — cryptic `Arg` suffix on path-parameter fields - -- **File / line:** `src/v1/model.ts:56` (`DeleteVolumeRequest.fullNameArg`), - `src/v1/model.ts:75` (`GetVolumeRequest.fullNameArg`), - `src/v1/model.ts:126` (`UpdateVolumeRequest.fullNameArg`); cross-ref - `src/v1/client.ts:125, 160, 277`. -- **Category:** #5 cryptic abbreviation; #6 misleading name; #20 type- - suffix tautology (inverse — `Arg` is a non-domain suffix). -- **Current:** `fullNameArg?: string`. -- **Suggestion:** `fullName: string` (drop both the `Arg` suffix and the - unnecessary `?:` — this is a required path parameter). -- **Rationale:** `Arg` is a proto/grpc-generator artifact that signals "this - field maps to a URL path argument." TypeScript callers have no concept - of "Arg" — they just see two fields named `fullNameArg` and (on the - related `VolumeInfo` / `UpdateVolumeRequest` payload) `fullName`, with no - way to know they refer to the same volume identifier. The URL templating - in `client.ts:125, 160, 277` interpolates it into the path directly. The - `?: | undefined` is also a semantic lie — without this value the path - becomes `/api/2.1/unity-catalog/volumes/` and the call cannot succeed. - -### H2. `Create*` / `Update*` request types include server-only fields +### H1. `Create*` / `Update*` request types include server-only fields - **File / line:** `src/v1/model.ts:16–52` (`CreateVolumeRequest`), - `src/v1/model.ts:124–164` (`UpdateVolumeRequest`). + `src/v1/model.ts:123–163` (`UpdateVolumeRequest`). - **Category:** #6 misleading name; #16 field contradicting type domain; #12 duplicate concepts. - **Current:** `CreateVolumeRequest` and `UpdateVolumeRequest` both carry @@ -69,11 +31,11 @@ Headline themes: `name`, `catalogName`, `schemaName`, `volumeType`, `storageLocation`, `comment`. For `UpdateVolumeRequest`: `fullNameArg` (the path identifier), `newName`, `owner`, `comment` (per the method docstring at - `client.ts:271`). + `client.ts:279`). - **Rationale:** A request type named `CreateVolumeRequest` whose fields include `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, and `volumeId` invites users to populate them — but the server ignores or - rejects them. The `client.ts:271` doc itself says "Currently only the + rejects them. The `client.ts:279` doc itself says "Currently only the name, the owner or the comment of the volume could be updated." Compare with the Go SDK `databricks/sdk-go/databricks/api/volumes/v1/` to confirm the upstream split. @@ -84,7 +46,7 @@ Headline themes: ### M1. `VolumeInfo` — redundant `Info` suffix -- **File / line:** `src/v1/model.ts:166`. +- **File / line:** `src/v1/model.ts:165`. - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `VolumeInfo`. - **Suggestion:** `Volume`. @@ -98,7 +60,7 @@ Headline themes: ### M2. `browseOnly` is a server-derived flag on request types - **File / line:** `src/v1/model.ts:51` (`CreateVolumeRequest.browseOnly`), - `163` (`UpdateVolumeRequest.browseOnly`), `201` + `162` (`UpdateVolumeRequest.browseOnly`), `200` (`VolumeInfo.browseOnly`). - **Category:** #6 misleading name; #16 field contradicting type domain. - **Current:** `browseOnly?: boolean | undefined` — present on the @@ -106,17 +68,17 @@ Headline themes: principal is limited to retrieving metadata for the associated object through the BROWSE privilege when include_browse is enabled in the request." -- **Suggestion:** Remove from request types (see H2). On the response +- **Suggestion:** Remove from request types (see H1). On the response type, the name itself is fine but the JSDoc should say "Read-only. Set by the server when include_browse is true." -- **Rationale:** Sub-issue of H2; called out separately because the name +- **Rationale:** Sub-issue of H1; called out separately because the name also reads ambiguously — `browseOnly: true` could be misread as "I want browse-only access" rather than "the server has limited me to browse-only." ### M3. `req` parameter name on all client methods -- **File / line:** `src/v1/client.ts:90, 122, 157, 203, 248, 274`. +- **File / line:** `src/v1/client.ts:92, 127, 162, 211, 256, 282`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. - **Current:** `req: CreateVolumeRequest`, `req: DeleteVolumeRequest`, etc. - **Suggestion:** `request` (matches Go-port readability without @@ -127,35 +89,6 @@ Headline themes: encouraged; in TS this reads as Go-translated code. Pervasive in this package (every method uses `req`) and across the repo. -### M4. Repeated `Details` suffix — `EncryptionDetails` wraps -`SseEncryptionDetails` - -- **File / line:** `src/v1/model.ts:63` (`EncryptionDetails`), - `src/v1/model.ts:114` (`SseEncryptionDetails`); cross-ref - `model.ts:49, 161, 199` (field `encryptionDetails`). -- **Category:** proto-architectural-leak — repeated `Details` suffix - across a parent/child pair carrying the same wrapper word. -- **Current:** `EncryptionDetails` is a one-field discriminated-union - wrapper whose only payload variant is `SseEncryptionDetails`. Both - types end in `Details`, and the field on the request/info types is - `encryptionDetails` (which itself only contains - `sseEncryptionDetails`). -- **Suggestion:** Either drop the outer wrapper entirely (inline the - union on `VolumeInfo`) or rename the inner type so `Details` is not - doubled — e.g. `EncryptionConfig` / `SseEncryption`. -- **Rationale:** The doubled `Details` is a proto-message-shape leak: - proto requires a wrapper message for each `oneof`, so the generator - emits `EncryptionDetails` purely to carry one `sse_encryption_details` - field. In TypeScript a discriminated union does not need that wrapper, - and the repeated `Details` reads as the generator name-pattern, not - domain vocabulary. - ---- - -## Low Severity - -_None._ - --- ## Observations (repo-wide conventions, not local defects) @@ -166,64 +99,3 @@ _None._ `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the codebase decides to drop the `Info` suffix, this is one of many to fix (M1 above flags it locally). - -### O2. `_Arg` suffix on path parameter fields is a generator-wide artifact - -`fullNameArg` (H1) is not unique to volumes — the workspace contains -fields like `nameArg`, `idArg`, `fullNameArg` across packages that take a -URL path parameter. Search: -`grep -rE "fullNameArg|nameArg|idArg" packages/*/src/`. Documented here -because the fix has cross-package implications. - ---- - -## Domain glossary - -| Term | Meaning in this package | -| -------------------------- | ---------------------------------------------------------- | -| Volume | A Unity Catalog securable representing a directory of files in cloud object storage. | -| Managed volume | Volume located in the default storage location specified by the parent schema, catalog, or metastore. | -| External volume | Volume located in a user-specified external location (S3 / ADLS / GCS path). | -| Catalog / Schema | Two outer levels of the UC three-level namespace; a volume's full name is `catalog.schema.volume`. | -| Full name (`fullName`) | The three-level (fully qualified) identifier `catalog.schema.volume`. | -| `fullNameArg` | Generator-internal name for the same three-level identifier when bound as a URL path parameter. | -| SSE | Server-Side Encryption (AWS S3). One of `AWS_SSE_S3` or `AWS_SSE_KMS`. | -| KMS ARN | AWS KMS Key ARN used by `AWS_SSE_KMS`. Sent via the `x-amz-server-side-encryption-aws-kms-key-id` S3 header. | -| Access point | AWS S3 access point used when accessing S3 for an external volume location. | -| Browse-only | A retrieval mode where the caller has only the `BROWSE` privilege on the volume and sees only metadata. | -| Metastore | Unity Catalog top-level container that owns the volume's catalog and schema. | -| Page token | Opaque pagination cursor. `nextPageToken` is server-emitted; absence signals end of results. | - ---- - -## File coverage - -| File | Lines | Audited | -| -------------- | ----- | ------------------------------------------------ | -| `src/v1/model.ts` | 399 | All 2 enums + 9 interfaces + 9 schemas + every field. | -| `src/v1/client.ts` | 298 | Class, constructor, 5 public methods + 1 iterator, all locals. | -| `src/v1/utils.ts` | 151 | All exported / private functions and types. | -| `src/v1/index.ts` | 19 | All re-exports. | - -Type & symbol checklist: - -- [x] `SseEncryptionAlgorithm` enum (3 members) → no defect. -- [x] `VolumeType` enum (2 members) → no defect. -- [x] `CreateVolumeRequest` interface (17 fields) → H2, M2. -- [x] `DeleteVolumeRequest` interface (1 field) → H1. -- [x] `EncryptionDetails` interface → M4. -- [x] `GetVolumeRequest` interface (2 fields) → H1. -- [x] `ListVolumesRequest` interface (5 fields) → no additional defect. -- [x] `SseEncryptionDetails` interface (2 fields) → M4. -- [x] `UpdateVolumeRequest` interface (18 fields) → H1, H2, M2. -- [x] `VolumeInfo` interface (16 fields) → M1, M2, O1. -- [x] `Client` class + `host` / `httpClient` / `logger` / `userAgent` fields → no defect. -- [x] `createVolume(req, options)` method → H2, M3. -- [x] `deleteVolume(req, options)` method → H1, M3. -- [x] `getVolume(req, options)` method → H1, M3. -- [x] `listVolumes(req, options)` method → M3. -- [x] `listVolumesIter(req, options)` async generator → M3. -- [x] `updateVolume(req, options)` method → H1, H2, M3. -- [x] `index.ts` re-exports → no defect (mirrors model exports faithfully). - ---- diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index a6debb62..b13fb76c 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -7,118 +7,23 @@ - `src/v1/model.ts` - `src/v1/client.ts` - `src/v1/index.ts` - -This audit applies the 20 numbered concern categories from the audit -checklist. Each finding lists the offending identifier(s), the -category number, severity (`HIGH` / `MEDIUM` / `LOW`), and a concrete -rename suggestion. Findings are grouped by category. Generator-driven -items are flagged as `LOW` because they are codified across the entire -generated SDK surface — they should be fixed at the generator, not by -hand-editing this package. - -**Special historical context:** SQL Warehouses were renamed from -"SQL Endpoints" (legacy term). The proto definitions still use -`Endpoint`/`endpoint` extensively (state, health, security policy, -tags, conf pairs, info). The current customer-facing brand is -"warehouse", so leftover `Endpoint*` identifiers are misleading. -This is the dominant theme of the audit (see F0). +- `src/v1/utils.ts` +- `src/v1/transport.ts` ## Summary | Severity | Count | | ----------- | ----- | -| High | 21 | -| Medium | 9 | -| Low | 29 | -| Observation | 16 | -| **Total** | **75** | - ---- - -## Inventory - -### Package identity - -| Item | Value | -| --------------- | ------------------------------------------- | -| Package name | `@databricks/sdk-warehouses` | -| Directory | `packages/warehouses/` | -| Subpath export | `./v1` | -| REST base paths | `/api/2.0/sql/warehouses`, `/api/2.0/sql/config/warehouses`, `/api/warehouses/v1/default-warehouse-overrides` | -| Concept | SQL Warehouses (formerly SQL Endpoints) and default warehouse overrides | - -### Enums (`model.ts`) - -| Name | Members | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| `ChannelName` | `CHANNEL_NAME_UNSPECIFIED`, `CHANNEL_NAME_PREVIEW`, `CHANNEL_NAME_CURRENT`, `CHANNEL_NAME_PREVIOUS`, `CHANNEL_NAME_CUSTOM` | -| `DefaultWarehouseOverrideType` | `DEFAULT_WAREHOUSE_OVERRIDE_TYPE_UNSPECIFIED`, `LAST_SELECTED`, `CUSTOM` | -| `EndpointSecurityPolicy` | `NONE`, `DATA_ACCESS_CONTROL`, `PASSTHROUGH` | -| `EndpointSpotInstancePolicy` | `POLICY_UNSPECIFIED`, `COST_OPTIMIZED`, `RELIABILITY_OPTIMIZED` | -| `EndpointState` | `STARTING`, `RUNNING`, `STOPPING`, `STOPPED`, `DELETING`, `DELETED` | -| `TerminationCode` | ~150 values (`UNKNOWN`, `USER_REQUEST`, `JOB_FINISHED`, `INACTIVITY`, ... `HIVEMETASTORE_CONNECTIVITY_FAILURE`) | -| `TerminationType` | `SUCCESS`, `CLIENT_ERROR`, `SERVICE_FAULT`, `CLOUD_FAILURE` | -| `WarehouseType` | `TYPE_UNSPECIFIED`, `CLASSIC`, `PRO` | -| `EndpointHealth_Status` | `STATUS_UNSPECIFIED`, `HEALTHY`, `DEGRADED`, `FAILED` | - -### Interfaces (`model.ts`) - -`Channel`, `CreateDefaultWarehouseOverrideRequest`, `CreateWarehouseRequest`, -`CreateWarehouseRequest_Response`, `DefaultWarehouseOverride`, -`DeleteDefaultWarehouseOverrideRequest`, `EditWarehouseRequest`, -`EditWarehouseRequest_Response`, `EndpointConfPair`, `EndpointHealth`, -`EndpointInfo`, `EndpointTagPair`, `EndpointTags`, -`GetDefaultWarehouseOverrideRequest`, `GetWarehouseRequest`, -`GetWarehouseRequest_Response`, `GetWorkspaceWarehouseConfigRequest`, -`GetWorkspaceWarehouseConfigRequest_Response`, -`ListDefaultWarehouseOverridesRequest`, -`ListDefaultWarehouseOverridesResponse`, `OdbcParams`, -`RepeatedEndpointConfPairs`, `SetWorkspaceWarehouseConfigRequest`, -`SetWorkspaceWarehouseConfigRequest_Response`, `TerminationReason`, -`TerminationReason_ParametersEntry`, -`UpdateDefaultWarehouseOverrideRequest`, `WarehouseTypePair`, -`DeleteWarehouseRequest`, `DeleteWarehouseRequest_Response`, -`ListWarehousesRequest`, `ListWarehousesRequest_Response`, -`StartRequest`, `StartRequest_Response`, `StopRequest`, -`StopRequest_Response`. - -### Client methods (`client.ts`) - -`createDefaultWarehouseOverride`, `createWarehouse`, -`createWarehouseWaiter`, `deleteDefaultWarehouseOverride`, -`deleteWarehouse`, `editWarehouse`, `editWarehouseWaiter`, -`getDefaultWarehouseOverride`, `getWarehouse`, -`getWorkspaceWarehouseConfig`, `listDefaultWarehouseOverrides`, -`listDefaultWarehouseOverridesIter`, `listWarehouses`, -`listWarehousesIter`, `setWorkspaceWarehouseConfig`, `startWarehouse`, -`startWarehouseWaiter`, `stopWarehouse`, `stopWarehouseWaiter`, -`updateDefaultWarehouseOverride`. - -### Client classes (`client.ts`) - -`Client`, `CreateWarehouseWaiter`, `EditWarehouseWaiter`, -`StartWarehouseWaiter`, `StopWarehouseWaiter`. +| High | 17 | +| Medium | 7 | +| Low | 15 | +| Observation | 11 | +| **Total** | **50** | --- ## F0 — Package-level: legacy "Endpoint" terminology leaks through the warehouse package -This is the dominant finding for this package and should be read -before the categorized findings below. The package brand is -"warehouse" — every URL is `/sql/warehouses` and customer JSDoc uses -"SQL warehouse" — yet the proto types still use `Endpoint*` as a -prefix for state, health, tags, conf pairs, security policy, spot -instance policy, and the row record (`EndpointInfo`). The result is -a public surface in which `listWarehouses` returns -`EndpointInfo[]`, `getWarehouse` returns a value with an `endpoint`- -flavored health type, and the per-warehouse state machine is -`EndpointState`. This is historical baggage: SQL Warehouses were -formerly called SQL Endpoints, and the legacy names persist in the -proto. Every `Endpoint*` identifier in this package is flagged -below (F1.1, F1.2, F1.3, F1.4, F1.5, F12.x, F15.x). Renames should -happen at the proto / spec level to preserve wire-format -compatibility while updating the customer-visible type names. - ### F0.1 — Two product surfaces conflated under one package (HIGH) - **Where:** `client.ts` exposes both `*Warehouse(s)` methods on `/api/2.0/sql/warehouses` and `*DefaultWarehouseOverride(s)` @@ -151,7 +56,7 @@ compatibility while updating the customer-visible type names. name says "warehouses". A reader cannot grep for "endpoint" and know which subsystem matches. - **Suggestion:** Rename all `Endpoint*` types in this package to - `Warehouse*` (see F1.x, F12.x). Reconcile with the package brand. + `Warehouse*` (see F1.x, F8.1). Reconcile with the package brand. --- @@ -160,62 +65,63 @@ compatibility while updating the customer-visible type names. ### 1. Vague / generic names #### F1.1 — `EndpointInfo` type name (HIGH) -- **Where:** `model.ts:979`, `index.ts:34`, return field - `warehouses?: EndpointInfo[]` on `ListWarehousesRequest_Response` - (`model.ts:1455`), yield type of `listWarehousesIter` - (`client.ts:466`). +- **Where:** `model.ts:981`, `index.ts:35`, return field + `warehouses?: EndpointInfo[]` on `ListWarehousesResponse` + (`model.ts:1304`), yield type of `listWarehousesIter` + (`client.ts:483`). - **Why flagged:** Misleading legacy name. The type represents a SQL warehouse (it has `clusterSize`, `warehouseType`, `jdbcUrl`, `numClusters`, etc.), but the type is named - `EndpointInfo`. Same root concept as `GetWarehouseRequest_Response`, + `EndpointInfo`. Same root concept as `GetWarehouseResponse`, which has identical field set — so the type name should match. - **Suggestion:** Rename to `Warehouse` (the resource itself) or `WarehouseInfo` if backward parity matters. Mirror - `GetWarehouseRequest_Response` shape into a single canonical type - (see F12.1). + `GetWarehouseResponse` shape into a single canonical type. #### F1.2 — `EndpointState` enum name (HIGH) - **Where:** `model.ts:87`, `index.ts:16`. Used in - `EndpointInfo.state`, `GetWarehouseRequest_Response.state`, and as - the poll-target inside every Waiter (`client.ts:662, 665, 666, - 704, ...`). + `EndpointInfo.state` (`model.ts:1081`), + `GetWarehouseResponse.state` (`model.ts:1215`), and as + the poll-target inside every Waiter (`client.ts:691, 694, 695, + 764, ...`). - **Why flagged:** The states themselves (`RUNNING`, `STOPPING`, `STOPPED`, `DELETING`, `DELETED`, `STARTING`) are warehouse states. JSDoc on the enum says "State of a warehouse." but the type is named `EndpointState`. The mismatch forces every customer-facing waiter to import `EndpointState` then check - `EndpointState.RUNNING` on a value whose type is warehouse. + `EndpointState.RUNNING` (`client.ts:691`) on a value whose type + is warehouse. - **Suggestion:** Rename to `WarehouseState`. The wire string can remain identical (server expects `"RUNNING"`, etc., not `"ENDPOINT_RUNNING"`), so this is a zero-cost rename at the spec level. #### F1.3 — `EndpointHealth` interface and `EndpointHealth_Status` enum (HIGH) -- **Where:** `model.ts:966`, `model.ts:686`, `index.ts:20`. - Field on `EndpointInfo.health` and - `GetWarehouseRequest_Response.health`. JSDoc says "Health status of - the endpoint" (`model.ts:967`). +- **Where:** `model.ts:968`, `model.ts:686`, `index.ts:34, 20`. + Field on `EndpointInfo.health` (`model.ts:1087`) and + `GetWarehouseResponse.health` (`model.ts:1221`). JSDoc says + "Health status of the endpoint" (`model.ts:969`). - **Why flagged:** Same root issue as F1.1/F1.2. The health is of a warehouse, not an endpoint. The waiters use - `pollResp.health?.summary` (`client.ts:667`) — a warehouse + `pollResp.health?.summary` (`client.ts:696`) — a warehouse health message. - **Suggestion:** Rename to `WarehouseHealth` / `WarehouseHealth_Status`. #### F1.4 — `EndpointTags`, `EndpointTagPair` interface names (HIGH) -- **Where:** `model.ts:1093, 1088`, `index.ts:35, 36`. Field - `tags?: EndpointTags` on `CreateWarehouseRequest`, - `EditWarehouseRequest`, `EndpointInfo`, - `GetWarehouseRequest_Response`. +- **Where:** `model.ts:1095, 1090`, `index.ts:37, 36`. Field + `tags?: EndpointTags` on `CreateWarehouseRequest` (`model.ts:794`), + `EditWarehouseRequest` (`model.ts:940`), `EndpointInfo` + (`model.ts:1058`), `GetWarehouseResponse` (`model.ts:1192`). - **Why flagged:** Same legacy naming. Tags are on warehouses, not endpoints. JSDoc says "key-value pairs that will be tagged on all resources … associated with this SQL warehouse" - (`model.ts:789, 933, 1051, 1186`). + (`model.ts:788, 933, 1051, 1185`). - **Suggestion:** Rename to `WarehouseTags` / `WarehouseTagPair`. #### F1.5 — `EndpointConfPair`, `RepeatedEndpointConfPairs` (HIGH) -- **Where:** `model.ts:961, 1309`, `index.ts:32, 45`. +- **Where:** `model.ts:963, 1319`, `index.ts:33, 47`. - **Why flagged:** Workspace-level SQL configuration parameters (`globalParam`, `sqlConfigurationParameters`, etc.) are not per-endpoint. They are workspace-scoped. The current name @@ -226,9 +132,11 @@ compatibility while updating the customer-visible type names. #### F1.6 — `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` (HIGH) - **Where:** `model.ts:26, 55`, `index.ts:14, 15`. Field on - `SetWorkspaceWarehouseConfigRequest.securityPolicy`, - `GetWorkspaceWarehouseConfigRequest_Response.securityPolicy`, - and `spotInstancePolicy` on each warehouse. + `SetWorkspaceWarehouseConfigRequest.securityPolicy` + (`model.ts:1332`), + `GetWorkspaceWarehouseConfigResponse.securityPolicy` + (`model.ts:1233`), and `spotInstancePolicy` on each warehouse + (`model.ts:796, 942, 1060, 1194`). - **Why flagged:** Same legacy term. JSDoc on `EndpointSecurityPolicy` reads "Security policy to be used for warehouses". JSDoc on `EndpointSpotInstancePolicy` extensively @@ -245,187 +153,72 @@ compatibility while updating the customer-visible type names. `CHANNEL_NAME_CUSTOM`. The JSDoc says "Configures the channel name and DBSQL version of the warehouse" but the type name itself does not signal this. -- **Suggestion:** Rename to `WarehouseChannel` / - `WarehouseChannelName` (or `DbsqlChannel` / +- **Suggestion:** Rename the type to `WarehouseChannel` and the + enum to `WarehouseChannelName` (or `DbsqlChannel` / `DbsqlChannelName`). Note: the enum name `ChannelName` - duplicates "name" — see F8.2. + duplicates "name" — see F5.2. #### F1.8 — `req` parameter name on every client method (LOW, Go-ism) -- **Where:** `client.ts:108, 152, 180, 196, 215, 243, 271, 287, - 312, 340, 371, 407, 425, 464, 482, 514, 539, 551, 576, 591`. -- **Why flagged:** `req` is a Go-ism (see category 14). It is +- **Where:** `client.ts:110, 157, 185, 201, 223, 251, 279, 295, + 323, 385, 424, 442, 481, 499, 534, 562, 574, 617` (and `_req` at + `client.ts:351`). +- **Why flagged:** `req` is a Go-ism (see category 10). It is also generic. - **Suggestion:** Use `request` for stylistic consistency with `options` (which is spelled out). Cross-package decision. #### F1.9 — `resp` local variable everywhere (LOW) - **Where:** `client.ts` throughout (e.g. `resp: - CreateWarehouseRequest_Response | undefined`). -- **Why flagged:** Same Go abbreviation as `req`. See F14.1. + CreateWarehouseResponse | undefined`, `client.ts:162`). +- **Why flagged:** Same Go abbreviation as `req`. See F10.1. - **Suggestion:** `response` for consistency. Generator-level. -#### F1.10 — `Client` class name (MEDIUM, cross-cutting) -- **Where:** `client.ts:78`, `index.ts:4`. -- **Why flagged:** Every package in this SDK exports a `Client`. - `import {Client} from '@databricks/sdk-warehouses'` is - unqualified and routinely needs aliasing at the call site. -- **Suggestion:** Either keep `Client` and document the alias - convention, or rename to `WarehousesClient` consistently - across packages. Cross-cutting decision. - -#### F1.11 — `code` field on `TerminationReason` (LOW) -- **Where:** `model.ts:1366`. -- **Why flagged:** `code` is generic; disambiguated by container - type, but `terminationCode` would be clearer in isolation. -- **Suggestion:** Acceptable as-is given the containing type. - Already typed against the `TerminationCode` enum, so renaming - introduces redundancy. Leave. - ---- - -### 2. Redundant enum prefixes - -_None._ - ---- - -### 3. Acronym casing inconsistencies - -#### F3.1 — `Id` vs `ID` (acceptable, SDK-wide) -- **Where:** `id`, `defaultWarehouseOverrideId`, `warehouseId`, - `runAsUserId`. Consistent lower-camel `Id`. -- **Suggestion:** No change. - -#### F3.2 — `SQL` rendered as `Sql` in `sqlConfigurationParameters` (LOW) -- **Where:** `model.ts:1254, 1343`. -- **Why flagged:** `sqlConfigurationParameters` uses lowercase - `sql`. The SDK applies "first letter cap, rest lower" for - TLAs in camelCase — but the field starts the identifier and - is rendered all lowercase. This is internally consistent with - the rest of the SDK (`url`, `http`, `id` all lowercase when - leading). Flag because the JSDoc and prose use uppercase - "SQL" throughout — only the identifier deviates. -- **Suggestion:** No change to identifier. SDK-wide pattern. - -#### F3.3 — `DBSQL` rendered as `Dbsql` in `dbsqlVersion` (LOW) -- **Where:** `model.ts:703`, `Channel.dbsqlVersion`. -- **Why flagged:** `DBSQL` is a Databricks-internal product - name. Wire form is `dbsql_version` (all lowercase). TS form - `dbsqlVersion` lowercases the whole acronym. Consistent with - `sql`, `jdbc`, `odbc` elsewhere in this package. -- **Suggestion:** Acceptable; consistent with adjacent fields. - -#### F3.4 — `JDBC` rendered as `jdbc` in `jdbcUrl` (acceptable) -- **Where:** `model.ts:1081, 1216`. Field `jdbcUrl`. -- **Why flagged:** Consistent with `http`, `url`. Lowercase - acronyms in lower-camel. Note `Url` not `URL` (also lowercase - TLA). Internally consistent. -- **Suggestion:** No change. - -#### F3.5 — `ODBC` rendered in mixed forms (LOW) -- **Where:** `model.ts:1083, 1218, 1302`. Type `OdbcParams` - (Pascal case, "Odbc" mixed); field `odbcParams` (lower-camel - "odbc"). -- **Why flagged:** Type uses `Odbc` (first letter cap, rest - lowercase); field uses `odbc` (all lowercase, leading - position). This is consistent with the SDK convention for - TLAs in identifier-leading vs. middle positions, but a careful - reader will notice the asymmetry. -- **Suggestion:** Acceptable; consistent with `HttpClient` vs. - `httpClient` pattern. Leave. - -#### F3.6 — `IAM` casing (acceptable, JSDoc only) -- **Where:** `model.ts:785, 929, 1047, 1182, 1240, 1329`. -- **Why flagged:** "IAM role" appears in JSDoc only; no - identifier rendering. -- **Suggestion:** No change. - -#### F3.7 — `URL` / `Url` (acceptable) -- **Where:** `client.ts` uses `url` consistently (leading - position). Type `jdbcUrl` uses `Url`. Internally consistent. -- **Suggestion:** No change. - --- -### 4. Underscores in TS identifiers - -_None._ +### 2. Cryptic abbreviations ---- - -### 5. Cryptic abbreviations - -#### F5.1 — `Conf` for configuration (`EndpointConfPair`, `configPair`, `dataAccessConfig`) (MEDIUM) -- **Where:** `model.ts:961, 1238, 1311, 1327`. -- **Why flagged:** "Conf" is an abbreviation. Inconsistent - within the package: `RepeatedEndpointConfPairs` has both - `configPair` and `configurationPairs` (the latter is - spelled out). The package alternates between `Conf`, - `Config`, `Configuration`. -- **Suggestion:** Standardize on `Config` (already in - `dataAccessConfig`). Rename `EndpointConfPair` → `ConfigPair`. - -#### F5.2 — `Num` for number (`numClusters`, `numActiveSessions`, `maxNumClusters`, `minNumClusters`) (LOW) -- **Where:** `model.ts:760, 771, 1022, 1033, 1075, 1077, 1157, 1168, 1210, 1212`. -- **Why flagged:** "Num" is a programmer-ism. SDK and other - packages occasionally spell it out as `count` or `number`. -- **Suggestion:** Acceptable; widely used across the API. Note - that `numActiveSessions` is deprecated. Consider - `clusterCount`, `activeSessionCount`, `maxClusterCount`, - `minClusterCount` for clarity, but consistency with wire - takes priority. Leave. - -#### F5.3 — `Arn` for AWS Resource Name (`instanceProfileArn`) (acceptable) -- **Where:** `model.ts:786, 930, 1048, 1183, 1244, 1333`. -- **Why flagged:** `ARN` is a well-known AWS acronym. Casing - matches `instanceProfileArn` (first letter cap, rest lower). - No issue. -- **Suggestion:** No change. +#### F2.1 — `Conf` for configuration (`EndpointConfPair`) (MEDIUM) +- **Where:** `model.ts:963, 1321`. +- **Why flagged:** "Conf" is an abbreviation. It is also + inconsistent with the spelled-out `Config` / + `Configuration` forms used elsewhere in the package. +- **Suggestion:** Standardize on `Config`. Rename the type + `EndpointConfPair` → `ConfigPair`. -#### F5.4 — `Conf` vs. `Config` vs. `Configuration` (MEDIUM, internal inconsistency) -- **Where:** Repeated across `EndpointConfPair`, - `dataAccessConfig`, `sqlConfigurationParameters`, - `configPair`, `configurationPairs`, `globalParam`, - `configParam`. -- **Why flagged:** Three different ways to write the same word - in the same file. Confusing. -- **Suggestion:** Pick one. Suggest `Config` for short field - names, `Configuration` for spelled-out prose. Or fully - spell out everywhere. - -#### F5.5 — `req`, `resp` Go-ism abbreviations (LOW) +#### F2.2 — `req`, `resp` Go-ism abbreviations (LOW) - **Where:** `client.ts` throughout. - Already covered in F1.8 and F1.9. --- -### 6. Misleading names +### 3. Misleading names -#### F6.1 — `EndpointInfo` for a warehouse record (HIGH) -- **Where:** `model.ts:979`. +#### F3.1 — `EndpointInfo` for a warehouse record (HIGH) +- **Where:** `model.ts:981`. - Covered in F1.1 / F0. The most glaring example: a value of type `EndpointInfo` is a warehouse, not an endpoint. - **Suggestion:** Rename to `Warehouse` or `WarehouseInfo`. -#### F6.2 — `EndpointState` for warehouse states (HIGH) +#### F3.2 — `EndpointState` for warehouse states (HIGH) - Covered in F1.2 / F0. -#### F6.3 — `EndpointHealth` for warehouse health (HIGH) +#### F3.3 — `EndpointHealth` for warehouse health (HIGH) - Covered in F1.3 / F0. -#### F6.4 — `EndpointTags` / `EndpointTagPair` for warehouse tags (HIGH) +#### F3.4 — `EndpointTags` / `EndpointTagPair` for warehouse tags (HIGH) - Covered in F1.4 / F0. -#### F6.5 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) -- **Where:** `model.ts:961, 1309`. Used inside - `GetWorkspaceWarehouseConfigRequest_Response.dataAccessConfig` - (workspace-scoped) and `globalParam` (also workspace-scoped). -- **Why flagged:** Field name says "endpoint conf" but the +#### F3.5 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) +- **Where:** `model.ts:963, 1319`. Used inside + `GetWorkspaceWarehouseConfigResponse.dataAccessConfig` + (`model.ts:1238`, workspace-scoped) and `globalParam` + (`model.ts:1250`, also workspace-scoped). +- **Why flagged:** The type name says "endpoint conf" but the scope is workspace. - **Suggestion:** Rename to `WorkspaceConfigPair` or `ConfigPair`. -#### F6.6 — `ChannelName` enum used for the channel's "version selector" (LOW) +#### F3.6 — `ChannelName` enum used for the channel's "version selector" (LOW) - **Where:** `model.ts:7`. - **Why flagged:** Enum is named `ChannelName` (suggesting just the "name"), but the values include `CUSTOM` and a @@ -433,8 +226,8 @@ _None._ accurate. - **Suggestion:** Rename to `ChannelType` or `WarehouseChannel`. -#### F6.7 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) -- **Where:** `model.ts:784, 928, 1046, 1181`. +#### F3.7 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) +- **Where:** `model.ts:784, 930, 1048, 1182`. - **Why flagged:** The field is settable on `CreateWarehouseRequest`/`EditWarehouseRequest`, but its meaning is read-only on the server side ("creator" never changes after @@ -442,15 +235,15 @@ _None._ - **Suggestion:** Spec-level. Mark read-only on response types only. -#### F6.8 — Waiter `done` returns true on terminal failure states (MEDIUM) -- **Where:** `client.ts:690, 770, 850, 925` (the `done()` of +#### F3.8 — Waiter `done` returns true on terminal failure states (MEDIUM) +- **Where:** `client.ts:712, 785, 858, 926` (the `done()` of each Waiter). - **Why flagged:** `done()` returns `true` for `RUNNING`, - `STOPPED`, `DELETED` indiscriminately. A caller who reads - "done()" expects success, but `DELETED` is a failure for - `CreateWarehouseWaiter`/`StartWarehouseWaiter`. The wait() - method correctly distinguishes (throws on - STOPPED/DELETED), but done() does not. + `STOPPED`, `DELETED` indiscriminately (`client.ts:726-728`). A + caller who reads "done()" expects success, but `DELETED` is a + failure for `CreateWarehouseWaiter`/`StartWarehouseWaiter`. The + wait() method correctly distinguishes (throws on + STOPPED/DELETED at `client.ts:694-697`), but done() does not. - **Suggestion:** Either rename `done()` to `terminal()` / `settled()` (clearly signals "stopped progressing", not "succeeded"), or split into `done()` (succeeded) and @@ -459,10 +252,10 @@ _None._ --- -### 7. Overly verbose +### 4. Overly verbose -#### F7.1 — `CreateDefaultWarehouseOverrideRequest`, `GetDefaultWarehouseOverrideRequest`, `UpdateDefaultWarehouseOverrideRequest`, `DeleteDefaultWarehouseOverrideRequest`, `ListDefaultWarehouseOverridesRequest`, `ListDefaultWarehouseOverridesResponse` (MEDIUM) -- **Where:** `model.ts:707, 1098, 1380, 847, 1273, 1292`. +#### F4.1 — `CreateDefaultWarehouseOverrideRequest`, `GetDefaultWarehouseOverrideRequest`, `UpdateDefaultWarehouseOverrideRequest`, `DeleteDefaultWarehouseOverrideRequest`, `ListDefaultWarehouseOverridesRequest`, `ListDefaultWarehouseOverridesResponse` (MEDIUM) +- **Where:** `model.ts:707, 1100, 1396, 846, 1273, 1292`. - **Why flagged:** All AIP-style "DefaultWarehouseOverride" resources. The names are accurate but very long (39-48 characters). The matching client methods @@ -473,9 +266,9 @@ _None._ --- -### 8. Redundant suffixes +### 5. Redundant suffixes -#### F8.1 — `Request` suffix on every request interface (HIGH, generator-driven) +#### F5.1 — `Request` suffix on every request interface (HIGH, generator-driven) - **Where:** `CreateDefaultWarehouseOverrideRequest`, `CreateWarehouseRequest`, `DeleteDefaultWarehouseOverrideRequest`, @@ -496,29 +289,28 @@ _None._ - **Suggestion:** Drop the `Request` suffix across the SDK at the generator level. Generator-level. -#### F8.2 — `Name` suffix on `ChannelName` enum (MEDIUM) +#### F5.2 — `Name` suffix on `ChannelName` enum (MEDIUM) - **Where:** `model.ts:7`. - **Why flagged:** Both `ChannelName.CHANNEL_NAME_PREVIEW` (the enum) and the `name` field on `Channel` of type `ChannelName` — three layers of "name". The enum is more accurately a "Channel Type". -- **Suggestion:** Rename enum to `ChannelType`. Field - `Channel.name` → `Channel.type` (this also clarifies - intent — Custom vs. Preview is the *type* of channel). +- **Suggestion:** Rename the enum to `ChannelType` (this also + clarifies intent — Custom vs. Preview is the *type* of channel). -#### F8.3 — `Pair` suffix on `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair` (MEDIUM) -- **Where:** `model.ts:1088, 961, 1407`. +#### F5.3 — `Pair` suffix on `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair` (MEDIUM) +- **Where:** `model.ts:1090, 963, 1423`. - **Why flagged:** "Pair" is a generic suffix that adds little information when the type's two fields are obvious. For `EndpointTagPair` (`key`, `value`), the suffix duplicates the shape already evident from the fields. - **Suggestion:** Rename `EndpointTagPair` → `Tag`, `EndpointConfPair` → `Config`, `WarehouseTypePair` → - `WarehouseTypeAvailability` (or similar) — wire-aligned but - semantically clearer than the `Pair` suffix. + `WarehouseTypeAvailability` (or similar) — semantically clearer + than the `Pair` suffix. -#### F8.4 — `Params` suffix on `OdbcParams` (LOW) -- **Where:** `model.ts:1302`. +#### F5.4 — `Params` suffix on `OdbcParams` (LOW) +- **Where:** `model.ts:1312`. - **Why flagged:** Mild noise. Type has `hostname`, `path`, `protocol`, `port` — `OdbcConnectionInfo` would be more accurate. @@ -527,100 +319,68 @@ _None._ --- -### 9. Singular / plural mismatches +### 6. Singular / plural mismatches -#### F9.1 — `TerminationReason.parameters` is a map, not a list (LOW) -- **Where:** `model.ts:1370`. Type `Record`. +#### F6.1 — `TerminationReason.parameters` is a map, not a list (LOW) +- **Where:** `model.ts:1386`. Type `Record`. - **Why flagged:** `parameters` is plural but typed as a map. Plural maps are fine but inconsistent — compare to `globalParam` / `configParam` which are singular. - **Suggestion:** Acceptable; map semantics are clear from the type. Plural is correct. -#### F9.2 — `enabledWarehouseTypes` plural array (acceptable) -- **Where:** `model.ts:1269, 1358`. +#### F6.2 — `enabledWarehouseTypes` plural array (acceptable) +- **Where:** `model.ts:1269, 1368`. - **Why flagged:** Plural name + array type. Correct. - **Suggestion:** No change. -#### F9.3 — `defaultWarehouseOverrides` plural array (acceptable) +#### F6.3 — `defaultWarehouseOverrides` plural array (acceptable) - **Where:** `model.ts:1294`. - **Why flagged:** Correct. - **Suggestion:** No change. -#### F9.4 — `warehouses` plural array (acceptable) -- **Where:** `model.ts:1455`. Correct. +#### F6.4 — `warehouses` plural array (acceptable) +- **Where:** `model.ts:1304`. Correct. -#### F9.5 — `customTags` plural array (acceptable) -- **Where:** `model.ts:1094`. Correct. +#### F6.5 — `customTags` plural array (acceptable) +- **Where:** `model.ts:1096`. Correct. --- -### 10. Reserved-word collisions +### 7. Reserved-word collisions -#### F10.1 — `type` field (LOW) -- **Where:** `DefaultWarehouseOverride.type` (`model.ts:838`), - `TerminationReason.type` (`model.ts:1368`). +#### F7.1 — `type` field (LOW) +- **Where:** `DefaultWarehouseOverride.type` (`model.ts:837`), + `TerminationReason.type` (`model.ts:1384`). - **Why flagged:** `type` is a TS keyword in certain positions (the `type` modifier in type imports), but valid as a property name. No actual collision. Some linters warn. - **Suggestion:** Acceptable; common pattern in TS APIs. -#### F10.2 — `name`, `id` (acceptable) +#### F7.2 — `name`, `id` (acceptable) - Common property names; not reserved. -#### F10.3 — `delete` not used as identifier (acceptable) +#### F7.3 — `delete` not used as identifier (acceptable) - Used only as method name `deleteWarehouse`, `deleteDefaultWarehouseOverride` — fine in TS (verb prefix). -#### F10.4 — `default-warehouse-overrides` URL segment vs. `default` TS keyword (acceptable) +#### F7.4 — `default-warehouse-overrides` URL segment vs. `default` TS keyword (acceptable) - **Where:** Path string only. Not an identifier. --- -### 11. Empty / trivial wrapper types - -_None. Wrappers are retained for forward compatibility._ - ---- +### 8. Duplicate concepts / historical baggage -### 12. Duplicate concepts / historical baggage - -#### F12.1 — `EndpointInfo` and `GetWarehouseRequest_Response` are the same record (HIGH) -- **Where:** `model.ts:979` and `model.ts:1114`. -- **Why flagged:** Both types have identical field sets (~20 - identical fields). One is the per-warehouse record in - `listWarehouses`, the other is the result of `getWarehouse`. - Duplicating the shape across two types means every change has - to happen in two places. -- **Suggestion:** Collapse into one type (call it `Warehouse`). - `GetWarehouseRequest_Response = Warehouse`. `EndpointInfo` removed. - Generator-level. - -#### F12.2 — `CreateWarehouseRequest` and `EditWarehouseRequest` are nearly identical (HIGH) -- **Where:** `model.ts:719` and `model.ts:861`. -- **Why flagged:** `EditWarehouseRequest` is `CreateWarehouseRequest - + id`. All other fields identical. Duplicating the shape. -- **Suggestion:** Have `EditWarehouseRequest` extend - `CreateWarehouseRequest` with `id` added. Reduces drift. - -#### F12.3 — `SetWorkspaceWarehouseConfigRequest` and -`GetWorkspaceWarehouseConfigRequest_Response` are identical (HIGH) -- **Where:** `model.ts:1320` and `model.ts:1231`. -- **Why flagged:** Same field set on both. Same legacy - `globalParam`, `configParam` deprecated pair on both. -- **Suggestion:** Generate as `WorkspaceWarehouseConfig` type - used by both methods. Generator-level. - -#### F12.4 — Legacy `Endpoint*` naming for a `Warehouse*` concept (HIGH) +#### F8.1 — Legacy `Endpoint*` naming for a `Warehouse*` concept (HIGH) - Covered in F0 and F1.x. Listed here for completeness in - category 12: the entire `Endpoint*` family is historical + category 8: the entire `Endpoint*` family is historical baggage from the rename of "SQL Endpoints" to "SQL Warehouses". --- -### 13. Verb-tense inconsistency +### 9. Verb-tense inconsistency -#### F13.1 — `Create*`, `Delete*`, `Edit*`, `Update*`, `Get*`, `Set*`, +#### F9.1 — `Create*`, `Delete*`, `Edit*`, `Update*`, `Get*`, `Set*`, `List*`, `Start*`, `Stop*` (acceptable + inconsistency) - **Where:** Method names across `client.ts`. - **Why flagged:** All imperatives, present tense. Consistent @@ -631,13 +391,13 @@ _None. Wrappers are retained for forward compatibility._ - Default overrides: `createDefaultWarehouseOverride`, `updateDefaultWarehouseOverride`, `deleteDefaultWarehouseOverride`. Standard CRUD verbs. -- **Suggestion:** See F17 below — same root cause. +- **Suggestion:** See F11.1 below — same root cause. --- -### 14. Go/Java-style names +### 10. Go/Java-style names -#### F14.1 — `req`, `resp`, `opts` Go abbreviations (LOW) +#### F10.1 — `req`, `resp`, `opts` Go abbreviations (LOW) - **Where:** `client.ts` throughout. - **Why flagged:** Go convention is `req`, `resp`, `opts`; TS convention is `request`, `response`, `options`. SDK already @@ -645,151 +405,57 @@ _None. Wrappers are retained for forward compatibility._ within the same method signature. - **Suggestion:** Generator-level. -#### F14.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) -- **Where:** `client.ts:411, 468`. +#### F10.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) +- **Where:** `client.ts:428, 485`. - **Why flagged:** `for (;;)` is C/Go idiom; TS prefers `while (true)` for readability. Minor. - **Suggestion:** Generator-level. --- -### 15. Generic field names losing meaning - -#### F15.1 — `state` field on `EndpointInfo` / `GetWarehouseRequest_Response` (LOW) -- **Where:** `model.ts:1079, 1214`. -- **Why flagged:** Disambiguated by type - (`EndpointState`), but `warehouseState` would be clearer in - isolation. -- **Suggestion:** Leave. - -#### F15.2 — `status` field on `EndpointHealth` (LOW) -- **Where:** `model.ts:968`. Type `EndpointHealth_Status`. -- **Why flagged:** Reads "endpoint health . status . - endpoint health status". Three layers of "status". -- **Suggestion:** Acceptable given typing. - -#### F15.3 — `enabled` field on `WarehouseTypePair` (LOW) -- **Where:** `model.ts:1413`. -- **Why flagged:** Generic, but disambiguated by container. -- **Suggestion:** Leave. - -#### F15.4 — `summary` field on `EndpointHealth` (LOW) -- **Where:** `model.ts:974`. -- **Why flagged:** Generic. JSDoc says "short summary of the - health status". Could be `summaryMessage` or - `healthSummary`, but field is rarely used in isolation. -- **Suggestion:** Leave. - -#### F15.5 — `key`, `value` on every `*Pair` type (LOW) -- **Where:** `EndpointConfPair`, `EndpointTagPair`, - `TerminationReason_ParametersEntry`. -- **Why flagged:** Maximally generic. Domain is in the - container type name. -- **Suggestion:** Acceptable; conventional for key-value pair - types. - -#### F15.6 — `code`, `type`, `parameters` on `TerminationReason` (LOW) -- **Where:** `model.ts:1366, 1368, 1370`. -- **Why flagged:** All three are generic words. Disambiguated - by container. -- **Suggestion:** Leave. - -#### F15.7 — `host`, `path`, `protocol`, `port` on `OdbcParams` (LOW) -- **Where:** `model.ts:1303-1306`. -- **Why flagged:** Generic connection-string fields. Standard. -- **Suggestion:** Leave. - ---- - -### 16. Field contradicting type domain - -#### F16.1 — `cluster*` fields on warehouse types (HIGH) -- **Where:** `CreateWarehouseRequest.clusterSize` (`model.ts:746`), - `minNumClusters` (`model.ts:760`), `maxNumClusters` - (`model.ts:771`), `numClusters` (`model.ts:1075`); same on - `EditWarehouseRequest`, `EndpointInfo`, - `GetWarehouseRequest_Response`. JSDoc: "Logical name for the - cluster" (`model.ts:721`). -- **Why flagged:** A SQL Warehouse exposes "cluster" terminology - internally because the warehouse is implemented atop Spark - clusters. To the customer, this is "warehouse size", - "warehouse cluster count", etc. The names leak - implementation. -- **Suggestion:** Rename for clarity: - - `clusterSize` → `warehouseSize` (the literal customer doc - term). - - `minNumClusters` → `minWarehouseInstances`? - - This is a wire-level rename. Considered intentional — - cluster terminology is documented externally. Leave with - a JSDoc note. Flag for future spec consideration. - -#### F16.2 — `creatorName` references the cluster (LOW) -- **Where:** `model.ts:784, 928, 1046, 1181`. -- **Why flagged:** JSDoc says "warehouse creator name"; field - name `creatorName` doesn't conflict but doesn't say what - resource is being created either. -- **Suggestion:** Acceptable. - ---- - -### 17. Inconsistent action verbs +### 11. Inconsistent action verbs -#### F17.1 — `Edit` vs. `Update` (HIGH) -- **Where:** `editWarehouse` (`client.ts:242`) vs. - `updateDefaultWarehouseOverride` (`client.ts:590`). Same +#### F11.1 — `Edit` vs. `Update` (HIGH) +- **Where:** `editWarehouse` (`client.ts:250`) vs. + `updateDefaultWarehouseOverride` (`client.ts:616`). Same package, two different "modify resource" verbs. - **Why flagged:** Warehouses use `edit`; default warehouse overrides use `update`. CRUD-style APIs across the SDK use "update"; the warehouse `edit` is a legacy form. Compounded by `Editor`-ish naming on types: `EditWarehouseRequest`, - `EditWarehouseRequest_Response`, `EditWarehouseWaiter`. + `EditWarehouseResponse`, `EditWarehouseWaiter`. - **Suggestion:** Standardize on `update` across the SDK. Rename `editWarehouse` → `updateWarehouse`, `EditWarehouseRequest` → `UpdateWarehouseRequest`, `EditWarehouseWaiter` → `UpdateWarehouseWaiter`. Note: this is - a wire/API-level rename — coordinate with backend. + a method/operation rename — coordinate with backend. -#### F17.2 — `Start` and `Stop` as method names (acceptable) +#### F11.2 — `Start` and `Stop` as method names (acceptable) - **Where:** `startWarehouse`, `stopWarehouse`. - **Why flagged:** Pair of opposites; standard for state machines. Good. - **Suggestion:** No change. -#### F17.3 — `Create` and `Delete` (acceptable) +#### F11.3 — `Create` and `Delete` (acceptable) - Standard CRUD. No issue. --- -### 18. Long enum values - -_None._ - ---- - -### 19. Underspecified IDs - -#### F19.1 — `defaultWarehouseOverrideId` vs. `warehouseId` on -`DefaultWarehouseOverride` (LOW) -- **Where:** `model.ts:836, 843`. -- **Why flagged:** Two ID fields on one type: - `defaultWarehouseOverrideId` (the override's own ID) and - `warehouseId` (the warehouse referenced *by* the override). - Both are clearly named, but a reader has to look carefully. -- **Suggestion:** Acceptable; both names are explicit. +### 12. Underspecified IDs -#### F19.2 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) -- **Where:** `model.ts:1438`. Already deprecated. Numeric (`number`), +#### F12.1 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) +- **Where:** `model.ts:1451`. Already deprecated. Numeric (`bigint`), not string — unusual; most IDs in the SDK are string. - **Suggestion:** Already deprecated. Leave. -#### F19.3 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) +#### F12.2 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) - **Where:** `model.ts:1299`. Standard pagination identifier. --- -### 20. Type-suffix tautology +### 13. Type-suffix tautology -#### F20.1 — `Channel.name: ChannelName` (HIGH) +#### F13.1 — `Channel.name: ChannelName` (HIGH) - **Where:** `model.ts:701-704`. ```ts export interface Channel { @@ -801,18 +467,19 @@ _None._ field is `channel.name: ChannelName`. Trying to read `channel.name.toString()` returns `'CHANNEL_NAME_PREVIEW'` — three layers of "name". -- **Suggestion:** Rename enum to `ChannelType`; rename field - to `type`. See F6.6 / F8.2. +- **Suggestion:** Rename the enum to `ChannelType`, which breaks + the tautology between the field and its enum type. See F3.6 / + F5.2. -#### F20.2 — `EndpointHealth.status: EndpointHealth_Status` (LOW) -- **Where:** `model.ts:968`. +#### F13.2 — `EndpointHealth.status: EndpointHealth_Status` (LOW) +- **Where:** `model.ts:970`. - **Why flagged:** Field name `status` + enum suffix `Status` + interface "Health Status" namespace. Disambiguated by typing. - **Suggestion:** Acceptable; standard pattern. -#### F20.3 — `WarehouseTypePair.warehouseType: WarehouseType` (HIGH) -- **Where:** `model.ts:1407-1413`. +#### F13.3 — `WarehouseTypePair.warehouseType: WarehouseType` (HIGH) +- **Where:** `model.ts:1423-1429`. ```ts export interface WarehouseTypePair { warehouseType?: WarehouseType | undefined; @@ -822,53 +489,21 @@ _None._ - **Why flagged:** Field name and type name are nearly identical. Reads "warehouse-type pair . warehouse type = WarehouseType.PRO". Two layers of "warehouse type". -- **Suggestion:** Rename field to `type` (or rename type to - `Type`). E.g. `WarehouseTypeAvailability { type, enabled }`. +- **Suggestion:** Rename the enum type `WarehouseType` → `Type` + (or rename the container to `WarehouseTypeAvailability`) to + break the duplication. -#### F20.4 — `TerminationReason.code: TerminationCode` (LOW) -- **Where:** `model.ts:1366`. Field `code` + enum suffix `Code` - on `TerminationCode`. Generic field name with specific enum - — acceptable per F1.11. +#### F13.4 — `TerminationReason.code: TerminationCode` (LOW) +- **Where:** `model.ts:1382`. Field `code` + enum suffix `Code` + on `TerminationCode`. Generic field name with specific enum — + acceptable. -#### F20.5 — `TerminationReason.type: TerminationType` (LOW) -- **Where:** `model.ts:1368`. Same pattern. Acceptable. +#### F13.5 — `TerminationReason.type: TerminationType` (LOW) +- **Where:** `model.ts:1384`. Same pattern. Acceptable. -#### F20.6 — `DefaultWarehouseOverride.type: DefaultWarehouseOverrideType` (LOW) -- **Where:** `model.ts:838`. +#### F13.6 — `DefaultWarehouseOverride.type: DefaultWarehouseOverrideType` (LOW) +- **Where:** `model.ts:837`. - **Why flagged:** Field `type` typed as `DefaultWarehouseOverrideType`. Container type already says "DefaultWarehouseOverride", so the field's type duplicates the container's name + adds "Type". Acceptable in practice. - ---- - -## Cross-cutting summary - -### Highest-leverage fixes - -1. **Resolve the `Endpoint*` legacy naming (F0, F1.1-F1.6, - F6.1-F6.5, F12.4)** — rename every `Endpoint*` type to - `Warehouse*` to align with the customer brand. Single biggest - fix; cleans up ~10 type names across the package. -2. **Resolve `Edit` vs. `Update` (F17.1)** — pick one verb for - "modify resource" across the SDK; standardize wire and TS. -3. **Collapse duplicate types (F12.1, F12.2, F12.3)** — - `EndpointInfo` + `GetWarehouseRequest_Response`, - `CreateWarehouseRequest` + `EditWarehouseRequest`, - `Set*Config` + `Get*Config_Response`. - -### Recurring themes - -- **Generator-driven Go/proto idioms** (`req`/`resp`, - `for(;;)`) are LOW because they are consistent across the - entire SDK; fix at the generator. -- **Legacy `Endpoint*` naming** is the package-specific issue. - It causes the most readability harm because the package - brand is "warehouse" while half the types still say - "endpoint". HIGH severity; spec-level rename. -- **Two unrelated resource families** (warehouses + - default-warehouse-overrides) coexist in one package, with - different REST base paths and different API conventions. - Splitting could simplify. - ---- diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index 2650d03d..f6c8e08d 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -3,78 +3,31 @@ **Path:** `packages/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 7 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | -| High | 3 | -| Medium | 3 | -| Low | 0 | +| Medium | 1 | | Observation | 1 | -The package contains 9 generated types (1 enum + 8 message/response shapes) and 4 client methods (plus 1 paginated iterator). The pervasive issues are (1) **stringly-typed `securableType`** that should be a closed enum; (2) **dual catalog-specific and generic-securable APIs** that overlap functionally — `getCatalogWorkspaceBindings` is a deprecated specialisation of `getWorkspaceBindings(securableType: 'catalog', ...)` but both ship in v1 with different request/response shapes; and (3) **conceptual neighbour confusion** with the separate `workspaceassignment` package, which assigns *principals* to workspaces while this package binds *securables* to workspaces — same noun "workspace", opposite direction, and the verbs "bind"/"assign" are mixed inside a single request type (`UpdateCatalogWorkspaceBindingsRequest.assignWorkspaces`). - ---- - -## High severity - -### 1. `securableType: string` (field, multiple) — `src/v1/model.ts:25,68` -- **Why weird:** Free-form `string` for what is a closed set of values. The doc-comment explicitly lists them: "(catalog, storage_credential, credential, or external_location)" — meaning the API author *knows* the set is closed but chose not to type it. A typo like `"caatalog"` will silently 4xx at the server. Also, the path is constructed via `${req.securableType ?? ''}` (`client.ts:123`, `client.ts:221`) which means an undefined value will produce a URL like `/api/2.1/unity-catalog/bindings//...` — a routing-incidental 404. -- **Category:** 19 (underspecified ID/discriminator), 1 (vague), 16 (field contradicts type domain). -- **Suggested name:** Define a `SecurableType` enum (`CATALOG`, `STORAGE_CREDENTIAL`, `CREDENTIAL`, `EXTERNAL_LOCATION`) and type both fields accordingly. -- **Rationale:** Type-safety is the entire point of TypeScript. Other UC packages in the SDK also use bare `string` for securable types — same fix should apply across all of them. - -### 2. Concept duplication: catalog-specific vs generic securable APIs — entire file -- **Why weird:** The package ships two parallel surfaces: - - `Get/UpdateCatalogWorkspaceBindingsRequest` operate on `/workspace-bindings/catalogs/{name}` (catalog-only legacy). - - `Get/UpdateWorkspaceBindingsRequest` operate on `/bindings/{securable_type}/{full_name}` (generic). -- For a catalog, both paths exist; the legacy path is functionally a special case of the generic path with `securable_type=catalog`. The TS SDK exposes both, with different request shapes, different response shapes (number[] vs WorkspaceBindingInfo[]), and different update semantics (`assign_workspaces`/`unassign_workspaces` IDs vs `add`/`remove` of `WorkspaceBindingInfo` records). -- The legacy methods cannot express `READ_ONLY` bindings (they only return/accept workspace IDs, no `BindingType`) — meaning the catalog-specific API is strictly less expressive than the generic one. Yet both are shipped. -- **Category:** 12 (duplicate concept within one package), 17 (inconsistency), Observation. -- **Suggested name:** Either deprecate the catalog-specific surface (mark with `@deprecated`) and direct users to `getWorkspaceBindings({securableType: 'catalog', securableFullName: name})`, or rename the catalog-specific variant to make its legacy status explicit (e.g. `getCatalogWorkspaceBindingsLegacy`). -- **Rationale:** Two surfaces for one operation, where one is strictly weaker, is a footgun. - -### 3. Concept overlap with sibling package `workspaceassignment` — cross-package -- **Why weird:** A sibling package `packages/workspaceassignment/src/v1/` covers `WorkspacePermissionAssignment` — assigning **principals** (users, groups, service principals) to **workspaces**. The current package `workspacebindings` covers `WorkspaceBindingInfo` — assigning **securables** (catalogs, credentials, etc.) to **workspaces**. Both use the noun "workspace" and an "assign"/"bind" verb. A user searching the SDK for "how do I associate X with a workspace" will find both packages and must read both READMEs to disambiguate. There is no surface-level disambiguation in the type or method names. `workspaceassignment` even has an `assign_workspaces` / `unassign_workspaces` field in `UpdateCatalogWorkspaceBindingsRequest` (line 55, 57) — using the verb "assign" inside the *bindings* package. -- **Category:** 12 (duplicate concept across packages), 17 (inconsistent verbs: "bind" vs "assign" used for adjacent operations). -- **Suggested name:** Either align the verbs (both as "assign" or both as "bind") or rename one package to disambiguate directionally — e.g. `workspacebindings` → `securableworkspacebindings` or `ucbindings`; `workspaceassignment` → `workspaceprincipalassignment`. At minimum, pick one verb across the two packages. -- **Rationale:** Two packages with overlapping vocabulary and adjacent semantics is a discoverability hazard. The verb mix ("bind"/"assign") within a single request type (`UpdateCatalogWorkspaceBindingsRequest.assignWorkspaces`) actively misleads. +A redundant Go-style `Info` suffix and a context-free client error message make up +the remaining findings. --- ## Medium severity -### 4. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` +### 1. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:84` - **Why weird:** `Info` suffix is a Go-style convention (`*Info` types in `databricks/sdk-go` are pervasive: `CatalogInfo`, `TableInfo`, `SchemaInfo`...). In TS the suffix carries no information — the type *is* the binding, not a separate "info-about-the-binding" record. Just two fields: `workspaceId` and `bindingType`. - **Category:** 14 (Go-style name), 8 (redundant suffix). - **Suggested name:** `WorkspaceBinding`. - **Rationale:** Drop Go suffixes when porting; sibling packages have already done this for some types but not consistently. -### 5. `workspaceId?: number` — `src/v1/model.ts:90` -- **Why weird:** Databricks workspace IDs are 64-bit integers. JS `number` can only represent integers safely up to 2^53. While today's workspace IDs are far below that, the type is a JS-platform-specific overflow risk. The Go SDK uses `int64`, which TS cannot losslessly represent as `number`. The same field appears as `workspaces?: number[]` and `assignWorkspaces?: number[]` — all three would need to migrate together. -- **Category:** 16 (field contradicts type domain: 64-bit IDs typed as JS number), 19 (underspecified). -- **Suggested name:** Keep the name `workspaceId` but consider `bigint` or `string` for the type. This is a project-wide concern. -- **Rationale:** Cross-cutting JS interop issue; not unique to this package, but flagged for completeness. - -### 6. `Client` — `src/v1/client.ts:46` -- **Why weird:** Top-level export named just `Client`. Generic, ambiguous. The package-level `index.ts:3` re-exports it as `Client`. Users importing from multiple `@databricks/sdk-*` packages must alias every Client (`import {Client as WorkspaceBindingsClient} from '@databricks/sdk-workspacebindings/v1'`). -- **Category:** 1 (vague), 12 (duplicate across packages). -- **Suggested name:** `WorkspaceBindingsClient`. -- **Rationale:** Convention in AWS, Google Cloud, Azure SDKs is service-prefixed client class names for exactly this reason. Same fix should apply across all `@databricks/sdk-*` packages. - ---- - -## Low severity - -_None._ - --- ## Observations -### 7. Client `Host is required.` error message — `src/v1/client.ts:61` +### 2. Client `Host is required.` error message — `src/v1/client.ts:60` The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. - **Category:** Observation. - ---- diff --git a/.agent/naming-audit/workspaceobjects.md b/.agent/naming-audit/workspaceobjects.md deleted file mode 100644 index cec13dea..00000000 --- a/.agent/naming-audit/workspaceobjects.md +++ /dev/null @@ -1,237 +0,0 @@ -# Naming Audit: workspaceobjects - -**Path:** `packages/workspaceobjects/src/v1/` -**Versions audited:** v1 -**Inferred domain:** Databricks workspace filesystem-style operations on -notebooks, folders, and files — import, export, delete, list, get-status, -and mkdirs against absolute paths under `/Workspace`. Wire prefix: -`/api/2.0/workspace/`. -**Total weird names flagged:** 10 - -## Scope note: `workspaceobjects` vs sibling packages - -The Databricks SDK ships several packages whose names begin with "workspace". -This audit covers the filesystem-objects package, `workspaceobjects`; the -others differ in scope: - -| Package | Domain | Wire prefix | -|---------|--------|-------------| -| `workspaceobjects` (this audit) | Workspace filesystem (notebooks/folders/files) | `/api/2.0/workspace/` | -| `workspaceassignment` | Account-level principal-to-workspace permission assignments | account API | -| `workspacebindings` | Securable-to-workspace bindings (catalog/credential/location) | Unity Catalog API | -| `workspaceconf` | Untyped key/value workspace configuration | `/api/2.0/workspace-conf` | -| `workspacesettings` | Strongly-typed workspace settings (compliance security profile, automatic cluster update, etc.) | various `/api/2.0/settings/*` | -| `workspaces` | Account-level workspace lifecycle (create/list/delete workspaces) | accounts API | - -## Summary - -| Severity | Count | -| --- | --- | -| High | 4 | -| Medium | 2 | -| Low | 4 | -| Observation | 6 | - -## Summary table - -| # | Severity | Location | Name | Category | -|---|----------|----------|------|----------| -| 1 | High | `model.ts:6` enum | `ExportFormat` used as `format` field of `ImportRequest` | Misleading name (an "ExportFormat" governs imports too) | -| 2 | High | `model.ts:18` enum value | `ExportFormat.AUTO` | Ambiguous enum value (different behaviour for import vs. export) | -| 3 | High | `model.ts:24` enum value | `ExportFormat.RAW` | Vague enum value (no documented format, only a use-case story) | -| 4 | High | `model.ts:28` enum | `Language` | Vague/generic, no domain prefix | -| 5 | Medium | `model.ts:162` type | `MkdirsRequest` | Unix-ism (`mkdir -p`); sibling `files` package uses `createDirectory` | -| 6 | Medium | `client.ts:157` method | `getStatus` | Vague verb; returns full `ObjectInfo` metadata (a `stat`, not a status) | -| 7 | Low | `model.ts:16` enum value | `ExportFormat.R_MARKDOWN` | Shape mismatch — single underscored value among single-token values | -| 8 | Low | `model.ts:14` enum value | `ExportFormat.DBC` | Cryptic product-specific abbreviation (Databricks archive) | -| 9 | Low | `model.ts:174` interface | `ObjectInfo` | `Info` suffix carries no information; central entity is just an "Object" | -| 10 | Low | `client.ts:266` method | `mkdirs` | Lower-case Unix contraction next to other `verbNoun` methods (`getStatus`, `import`, `export`) | - -## High severity - -### 1. `ExportFormat` reused for `ImportRequest.format` — misleading enum -- **Location:** `model.ts:6` (declaration); used as `ImportRequest.format` at `model.ts:129` and `ExportRequest.format` at `model.ts:87`. -- **Category:** Misleading name — the enum name encodes a single direction - (export) but the type is used both ways. -- **Suggested name:** `WorkspaceObjectFormat` or `NotebookFormat`. The wire - string values stay the same; the TS identifier becomes direction-neutral. -- **Rationale:** The JSDoc on the enum already says "for workspace import and - export." The asymmetry is more than cosmetic: `ImportRequest.format`'s - JSDoc documents `AUTO` as "depending on extension," while - `ExportRequest.format`'s JSDoc documents `AUTO` as "depending on object - type." Same enum value, different server-side algorithm — see finding 2. - A neutral name removes the "for export" implication. - -### 2. `ExportFormat.AUTO` — ambiguous enum value -- **Location:** `model.ts:17-18` -- **Category:** Ambiguous / context-sensitive enum value. -- **Suggested name:** Split into two distinct enums per direction, or - rename to `DETECT_FROM_CONTENT` (import meaning) and document the export - meaning separately, or drop entirely and pick a default server-side. -- **Rationale:** `AUTO` reads as "let the server pick a format," but the - picking algorithm differs per direction. For imports, the server inspects - payload extension and content header. For exports, the server picks - based on the object's type. One name, two algorithms is exactly the - failure mode of overloaded enum values. - -### 3. `ExportFormat.RAW` — vague enum value -- **Location:** `model.ts:19-24` -- **Category:** Vague enum value — names a behaviour, not a format. -- **Suggested name:** `ZIP_PASSTHROUGH` or `BINARY` (or `BYTES_AS_IS`). -- **Rationale:** `RAW` does not name a format — it names a behaviour ("no - decoding, store as-is"). The JSDoc is a story about why the value exists - ("This is introduced to unblock a DR use case importing .zip file as is") - rather than what it represents. The value's existence is also gated on a - server-side roadmap ("In workspace 3.0 folder import will be supported via - a different API") that the SDK user does not see. - -### 4. `Language` — vague / generic, no domain prefix -- **Location:** `model.ts:28-37` -- **Category:** Vague/generic top-level name. -- **Suggested name:** `NotebookLanguage`. -- **Rationale:** A top-level export called `Language` in a domain package - is an attractive nuisance. Several other Databricks SDK domains touch - "language" (`apps` runtimes, `jobs` task language, `clusters` runtime - languages, `pipelines` SQL/Python). A user importing two SDK packages can - end up with two clashing `Language` symbols. The wire field is - `notebook.language`; `NotebookLanguage` is the natural domain prefix. - -## Medium severity - -### 5. `MkdirsRequest` — Unix-ism -- **Location:** `model.ts:162` (type), `client.ts:266` (method). -- **Category:** Cryptic Unix abbreviation, cross-package inconsistency. -- **Suggested name:** `CreateDirectoryRequest`. -- **Rationale:** `mkdirs` is a Unix-derived verb. The convention in TS - SDKs is to spell verbs out. The Databricks SDK's own `files` package - uses `createDirectory` for the analogous operation — so the same - conceptual action has two names across packages in the same SDK. Also: - the wire path is `/api/2.0/workspace/mkdirs` (plural verb), but the - request body holds one path, so even the wire name is misleading. - -### 6. `getStatus` — vague verb on the client -- **Location:** `client.ts:157` -- **Category:** Vague verb; misleading category (returns metadata, not a - status enum); inconsistent return shape vs. peer methods. -- **Suggested name:** `getMetadata` or `stat`. -- **Rationale:** "Status" of what? Across TS SDKs `getStatus` typically - returns a status enum or a small status object (e.g. job run status). - Here it returns full `ObjectInfo` metadata — a filesystem `stat`, not a - status. The Files API in the same SDK uses `getMetadata`. The Go SDK - uses `GetStatus` from `os.Stat` ancestry. Also: this method returns - `Promise` while `list` returns - `Promise` (wrapper). One returns the bare entity, - the other returns a wrapper — inconsistent shape across the same - client. - -## Low severity - -### 7. `ExportFormat.R_MARKDOWN` — shape mismatch within the enum -- **Location:** `model.ts:15-16` -- **Category:** Inconsistent shape inside an enum (most values single - token, one with an underscore). -- **Suggested name:** `RMARKDOWN` or `RMD` (with wire string still - `R_MARKDOWN`). Or accept it as the exception and document. -- **Rationale:** Five of the seven `ExportFormat` values are single tokens - (`SOURCE`, `HTML`, `JUPYTER`, `DBC`, `AUTO`, `RAW`); one is - `R_MARKDOWN` with an underscore. Inconsistent shape inside the same - enum. - -### 8. `ExportFormat.DBC` — cryptic abbreviation -- **Location:** `model.ts:13-14` -- **Category:** Cryptic product-specific abbreviation. -- **Suggested name:** `DATABRICKS_ARCHIVE` on the TS identifier; the wire - string stays `DBC`. -- **Rationale:** "DBC" = "Databricks Archive." The acronym is internal - product jargon. Wire-format compatibility (`DBC` is what the server - expects) means the rename must happen on the enum-key layer, not the - enum-value layer — TypeScript supports that cleanly. - -### 9. `ObjectInfo` — `Info` suffix -- **Location:** `model.ts:174-200` -- **Category:** Vague suffix; Go/Java convention carried into TS without - reason. -- **Suggested name:** `WorkspaceObject` (or simply `Object` if not for the - global-name collision with `Object`). -- **Rationale:** `Info` is a generic "POJO that describes a thing" suffix - imported from Go/Java conventions. TS SDKs vary on this — some packages - use bare entity names (`Catalog`, `Cluster`). This package's only entity - type is `ObjectInfo` with no companion `Object`, so the suffix is purely - a hat-tip to the Go SDK. A name like `WorkspaceObject` would also avoid - the JS `Object` collision. - -### 10. `mkdirs` client method — Unix contraction next to verb-noun siblings -- **Location:** `client.ts:266` -- **Category:** Verb-tense / shape inconsistency among sibling methods. -- **Suggested name:** `createDirectory`. -- **Rationale:** Sibling methods on `Client` read as bare HTTP verbs - (`export`, `import`, `list`, `delete`) or verb-noun (`getStatus`). - `mkdirs` is the only Unix-style contraction. `createDirectory` would - align with `getStatus` and with the `files` package convention. - -## Observations - -1. **Filesystem package without filesystem vocabulary.** The package - implements filesystem-style operations (`list`, `delete`, `mkdirs`, - `getStatus`) but does not use the canonical filesystem nouns (`File`, - `Directory`, `Path`, `Stat`). Instead it uses - `ObjectInfo` / `ObjectType` / `path: string`. A user familiar with - `fs.stat` or POSIX has to mentally translate. The sibling `files` - package (`/api/2.0/fs/`) uses `DirectoryEntry` / `FileInfo` — - different vocabulary for the same concept across SDK packages. - -2. **Two ID fields, one entity.** `ObjectInfo.objectId` (numeric, legacy) - and `ObjectInfo.resourceId` (string, unified-resource) are both - returned, both documented as "unique identifier for the object," with - no naming clue about which one to pass where. - -3. **`ExportFormat` is the import format.** The single enum services both - `ImportRequest` and `ExportRequest` (good — DRY), but the name says - only "Export." A neutral name (`WorkspaceObjectFormat` or - `NotebookFormat`) would describe what it actually is. - -4. **`AUTO` means two different things.** Inside `ExportFormat`, `AUTO` - on `ImportRequest` means "detect from file extension + header," and - `AUTO` on `ExportRequest` means "decide from object type." Same enum - value, different server-side algorithm. - -5. **`content: Uint8Array` documented as base64 in both directions.** Two - fields hold post-decode bytes but their JSDoc reads as if they still - hold base64 strings. A defensive user reading the JSDoc and - base64-encoding their bytes will double-encode on the way in. The - mismatch is silent and the failure mode is data corruption. - -6. **`mkdirs` and `getStatus` are Unix/POSIX verbs that don't appear - elsewhere in the SDK.** The `files` package uses `createDirectory` - and `getMetadata`. The `repos` package uses `getRepo`. Picking one - verb per concept and applying it across packages would let users - transfer knowledge. - -## Domain glossary - -| Term | Meaning in this package | -|------|------------------------| -| Workspace object | Anything that lives in the workspace filesystem tree: notebooks, directories, files, repos, dashboards, (legacy) libraries. | -| Path | An absolute string starting with `/Workspace/` that names a workspace object. | -| Notebook | A workspace object containing runnable code cells and prose; carries a `Language`. | -| Directory | A workspace folder; can be listed and made via `mkdirs`. | -| File | An arbitrary blob in the workspace (not a notebook). | -| Repo | A Git-linked directory; appears in `ObjectType` but managed by a different package. | -| DBC | Databricks archive format — a `.zip`-like bundle of one or more notebooks. | -| Import | Upload an object (or DBC archive) into the workspace at a path. | -| Export | Download an object (or DBC archive) from the workspace at a path. | -| Mkdirs | Create a directory and any missing parents at a path (single-path operation despite the plural verb). | -| Get-status | Return metadata (path, type, language, ID, size, timestamps) for the object at a path — equivalent to `stat`. | -| Object ID | Legacy numeric workspace-local identifier (typed `number`, vulnerable to JS precision at >2^53). | -| Resource ID | Newer string identifier consistent across Databricks resource APIs. | -| Direct download | An `Export` mode where the response body is raw bytes instead of a base64-wrapped JSON object. | - -## File coverage - -| File | Lines | Read in full | -|------|-------|--------------| -| `src/v1/model.ts` | 298 | yes | -| `src/v1/client.ts` | 290 | yes | -| `src/v1/utils.ts` | 150 | yes | -| `src/v1/transport.ts` | 75 | yes | -| `src/v1/index.ts` | 20 | yes | diff --git a/.agent/naming-audit/workspaces.md b/.agent/naming-audit/workspaces.md index d48a0296..9b72c3ff 100644 --- a/.agent/naming-audit/workspaces.md +++ b/.agent/naming-audit/workspaces.md @@ -7,33 +7,15 @@ its cloud, network, storage, and encryption configuration). **Total weird names flagged:** 4 -This audit is scoped to proto-architectural-leak naming (mid-position -`Public`/`Internal`/`External`, `Proto` suffix/infix, architectural-layer -words such as `Service`/`Manager`/`Wrapper`, `Impl`, `Rpc`/`Grpc`, -`Foo_PublicRequest`-style paired naming, etc.). Domain words like -`External*`/`Online*` and standard end-position suffixes (`Request`, -`Response`, `Info`) are not flagged here. - ## Summary | Severity | Count | | ------------ | ----- | | High | 4 | -| Medium | 0 | -| Low | 0 | -| Observation | 0 | - -The remaining findings all cluster around the `Public` mid-position -infix on the client surface — the upstream proto/service "Public" vs -internal-route split still leaks into the `Client` methods, the two -waiter classes, and the corresponding imports / re-exports. -The model-side `Public` / `CustomerFacing` infixes on the request, -response, container, and enum types have all been removed; see the -`Fixed` section below. ## High severity -### 1. `Client.createWorkspacePublic` / `createWorkspacePublicWaiter` — `src/v1/client.ts:88,113` +### 1. `Client.createWorkspacePublic` / `createWorkspacePublicWaiter` — `src/v1/client.ts:85,110` - **Why weird:** `Client` method names end in `Public`. Reads as "the method on the public class that calls the public endpoint" — the suffix only exists because the underlying proto/spec uses `Public` @@ -45,7 +27,7 @@ response, container, and enum types have all been removed; see the - **Rationale:** Methods on `Client` are inherently public; the suffix is meaningless to a TS caller. -### 2. `Client.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` / `updateWorkspacePublicWaiter` — `src/v1/client.ts:127,155,180,210,250` +### 2. `Client.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` / `updateWorkspacePublicWaiter` — `src/v1/client.ts:124,152,177,207,247` - **Why weird:** Same `Public` suffix on every other `Client` method (and the update waiter factory) as #1. - **Category:** Proto-architectural leak — `Public` suffix on client @@ -54,7 +36,7 @@ response, container, and enum types have all been removed; see the `updateWorkspace`, `updateWorkspaceWaiter`. - **Rationale:** Same as #1. -### 3. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:264,344` +### 3. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:261,334` - **Why weird:** Two exported waiter classes carry the `Public` infix between the verb (`Create`/`Update`) and the noun (`Workspace`) plus the `Waiter` role suffix. The class names are wholly SDK-side @@ -66,108 +48,12 @@ response, container, and enum types have all been removed; see the - **Rationale:** Waiter classes are TS-only constructs; they have no business carrying the upstream proto's public/internal qualifier. -### 4. `Public` imports in `client.ts` and the `index.ts` re-export list — `src/v1/client.ts:31-36`, `src/v1/index.ts:5-7` -- **Why weird:** Both files mirror the leaked `Public` names from the - waiter classes in their import / re-export lists: +### 4. `Public` waiter names in the `index.ts` re-export list — `src/v1/index.ts:5-6` +- **Why weird:** `index.ts` mirrors the leaked `Public` names from the + waiter classes in its re-export list: `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter`. - **Category:** Proto-architectural leak — `Public` mid-position - (import & re-export mirror). + (re-export mirror). - **Suggested:** Track the renames of #1–#3. -- **Rationale:** Re-export and import statements inherit the leaked - names verbatim; nothing to do here independent of the upstream - renames. - -## Medium severity - -_None._ - -## Low severity - -_None._ - -## Observation - -_None._ - -## File coverage - -| File | Lines | Audited | -| --------------------- | ----- | ------------------------------------------------------------------------ | -| `src/v1/model.ts` | 829 | All 5 enums, all 13 interfaces, every field, all 11 marshal/unmarshal schemas, field-mask schemas. | -| `src/v1/client.ts` | 423 | `Client` class, constructor, 5 RPC methods + 2 waiter factories, 2 waiter classes, import list. | -| `src/v1/index.ts` | 35 | All re-exports — names mirror `model.ts` and `client.ts` (covered above).| - -Type & symbol checklist: - -- [x] `ComputeMode` enum — clean (renamed from `CustomerFacingComputeMode`). -- [x] `GkeConnectivityType` enum — clean (`Gke` is a domain acronym; - no proto qualifier). -- [x] `PricingTier` enum — clean (renamed from `PublicPricingTier`). -- [x] `StorageMode` enum — clean (renamed from `CustomerFacingStorageMode`). -- [x] `WorkspaceStatus` enum — clean. -- [x] `AzureWorkspaceInfo` interface — clean (`Info` is a standard - end-position suffix; `Azure` is a domain qualifier). -- [x] `CloudResourceContainer` interface — clean (renamed from - `CustomerFacingCloudResourceContainer`). -- [x] `CreateWorkspaceRequest` interface — clean (renamed from - `CreateWorkspacePublicRequest`). -- [x] `CreateWorkspaceRequest_CustomTagsEntry` interface — clean (renamed - from `CreateWorkspacePublicRequest_CustomTagsEntry`). -- [x] `DeleteWorkspaceRequest` interface — clean (renamed from - `DeleteWorkspacePublicRequest`). -- [x] `GcpCloudResourceContainer` interface — clean (renamed from - `CustomerFacingGcpCloudResourceContainer`). -- [x] `GcpCommonNetworkConfig` interface — clean (domain abbreviation - `Gcp` + descriptive suffix). -- [x] `GcpManagedNetworkConfig` interface — clean. -- [x] `GetWorkspaceRequest` interface — clean (renamed from - `GetWorkspacePublicRequest`). -- [x] `GkeConfig` interface — clean. -- [x] `ListWorkspacesRequest` interface — clean (renamed from - `ListWorkspacesPublicRequest`). -- [x] `ListWorkspacesResponse` interface — clean (renamed from - `ListWorkspacesPublicResponse`). -- [x] `UpdateWorkspaceRequest` interface — clean as a type name (renamed - from `UpdateWorkspacePublicRequest`). -- [x] `Workspace` interface — clean (renamed from `CustomerFacingWorkspace`). -- [x] `Workspace_CustomTagsEntry` interface — clean (renamed from - `CustomerFacingWorkspace_CustomTagsEntry`). -- [x] `WorkspaceNetwork` interface — clean. -- [x] `marshalCreateWorkspaceRequestSchema` — clean (renamed from - `marshalCreateWorkspacePublicRequestSchema`). -- [x] `unmarshalCloudResourceContainerSchema`, - `unmarshalGcpCloudResourceContainerSchema`, - `unmarshalWorkspaceSchema`, - `marshalCloudResourceContainerSchema`, - `marshalGcpCloudResourceContainerSchema`, - `marshalWorkspaceSchema` — clean (renamed from their - `CustomerFacing*` versions). -- [x] `unmarshalAzureWorkspaceInfoSchema`, - `unmarshalGcpCommonNetworkConfigSchema`, - `unmarshalGcpManagedNetworkConfigSchema`, - `unmarshalGkeConfigSchema`, `unmarshalWorkspaceNetworkSchema`, - `marshalAzureWorkspaceInfoSchema`, - `marshalGcpCommonNetworkConfigSchema`, - `marshalGcpManagedNetworkConfigSchema`, `marshalGkeConfigSchema`, - `marshalWorkspaceNetworkSchema` — clean (no `Public`/`CustomerFacing` - qualifier). -- [x] Field-mask schemas - (`azureWorkspaceInfoFieldMaskSchema`, - `cloudResourceContainerFieldMaskSchema`, - `gcpCloudResourceContainerFieldMaskSchema`, - `workspaceFieldMaskSchema`, - `gcpCommonNetworkConfigFieldMaskSchema`, - `gcpManagedNetworkConfigFieldMaskSchema`, - `gkeConfigFieldMaskSchema`, `workspaceNetworkFieldMaskSchema`) and - the exported `workspaceFieldMask()` factory — clean (renamed along - with the underlying types). -- [x] `Client` class itself — clean (terminal-position `Client` is the - standard SDK convention). -- [x] `Client.createWorkspacePublic` + `createWorkspacePublicWaiter` — - flagged (#1). -- [x] `Client.deleteWorkspacePublic`, `getWorkspacePublic`, - `listWorkspacesPublic`, `updateWorkspacePublic`, - `updateWorkspacePublicWaiter` — flagged (#2). -- [x] `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter` - classes — flagged (#3). -- [x] `client.ts` import list / `index.ts` re-exports — flagged (#4). +- **Rationale:** The re-export statement inherits the leaked names + verbatim; nothing to do here independent of the upstream renames. From ac9c3ae3ecf111168940fa10dd265c6f6f96e79d Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Fri, 12 Jun 2026 12:18:10 +0000 Subject: [PATCH 12/12] update --- .agent/naming-audit/_SUMMARY.md | 1151 ++++------------- .agent/naming-audit/abacpolicies.md | 4 +- .agent/naming-audit/accessmanagement.md | 45 +- .agent/naming-audit/alerts.md | 62 +- .agent/naming-audit/apps.md | 44 +- .agent/naming-audit/artifactallowlists.md | 31 +- .agent/naming-audit/authentication.md | 2 +- .agent/naming-audit/budgetpolicy.md | 4 +- .agent/naming-audit/budgets.md | 69 +- .agent/naming-audit/catalogs.md | 55 +- .agent/naming-audit/cleanrooms.md | 24 +- .agent/naming-audit/clusterlibraries.md | 18 +- .agent/naming-audit/clusterpolicies.md | 6 +- .agent/naming-audit/clusters.md | 8 +- .agent/naming-audit/commandexecution.md | 129 +- .agent/naming-audit/connections.md | 22 +- .agent/naming-audit/credentials.md | 33 +- .agent/naming-audit/customllms.md | 31 +- .agent/naming-audit/database.md | 34 +- .agent/naming-audit/dataquality.md | 24 +- .agent/naming-audit/disasterrecovery.md | 22 +- .agent/naming-audit/entitytagassignments.md | 22 +- .agent/naming-audit/environments.md | 4 +- .agent/naming-audit/experiments.md | 36 +- .agent/naming-audit/externallineage.md | 6 +- .agent/naming-audit/externallocations.md | 10 +- .agent/naming-audit/externalmetadata.md | 16 +- .agent/naming-audit/features.md | 113 +- .agent/naming-audit/featurestore.md | 99 +- .agent/naming-audit/files.md | 13 +- .agent/naming-audit/forecasting.md | 47 +- .agent/naming-audit/functions.md | 82 +- .agent/naming-audit/genie.md | 58 +- .agent/naming-audit/gitcredentials.md | 8 +- .agent/naming-audit/globalinitscripts.md | 11 +- .agent/naming-audit/grants.md | 22 - .agent/naming-audit/instancepools.md | 161 +-- .agent/naming-audit/instanceprofiles.md | 83 +- .agent/naming-audit/jobs.md | 190 +-- .agent/naming-audit/keyconfigurations.md | 8 +- .agent/naming-audit/knowledgeassistants.md | 28 +- .agent/naming-audit/lakeview.md | 25 +- .agent/naming-audit/logdelivery.md | 36 +- .agent/naming-audit/marketplaces.md | 119 +- .agent/naming-audit/metastores.md | 84 +- .agent/naming-audit/modelregistry.md | 101 +- .agent/naming-audit/modelserving.md | 35 +- .agent/naming-audit/modelservingquery.md | 86 +- .agent/naming-audit/networking.md | 26 +- .../naming-audit/notificationdestinations.md | 37 +- .agent/naming-audit/pipelines.md | 44 +- .agent/naming-audit/policyfamilies.md | 75 -- .agent/naming-audit/postgres.md | 20 +- .agent/naming-audit/queries.md | 48 +- .agent/naming-audit/queryhistory.md | 16 +- .agent/naming-audit/registeredmodels.md | 43 +- .agent/naming-audit/repos.md | 71 +- .agent/naming-audit/resourcequotas.md | 41 +- .agent/naming-audit/rfa.md | 27 +- .agent/naming-audit/schemas.md | 79 +- .agent/naming-audit/scim.md | 20 +- .agent/naming-audit/secrets.md | 32 +- .agent/naming-audit/secretsuc.md | 23 +- .agent/naming-audit/settings.md | 109 +- .agent/naming-audit/sharing.md | 30 +- .agent/naming-audit/statementexecution.md | 62 +- .agent/naming-audit/storageconfigurations.md | 10 +- .agent/naming-audit/supervisoragents.md | 13 +- .agent/naming-audit/systemschemas.md | 12 +- .agent/naming-audit/tables.md | 146 +-- .agent/naming-audit/tagassignments.md | 24 +- .agent/naming-audit/tagpolicies.md | 12 +- .agent/naming-audit/tokenmanagement.md | 6 +- .agent/naming-audit/tokens.md | 8 +- .agent/naming-audit/usagedashboards.md | 26 +- .agent/naming-audit/vectorsearch.md | 28 +- .agent/naming-audit/volumes.md | 38 +- .agent/naming-audit/warehouses.md | 317 ++--- .agent/naming-audit/workspacebindings.md | 18 +- .agent/naming-audit/workspaces.md | 35 +- AGENTS.md | 24 +- 81 files changed, 1254 insertions(+), 3587 deletions(-) delete mode 100644 .agent/naming-audit/grants.md delete mode 100644 .agent/naming-audit/policyfamilies.md diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md index 2d0b421d..b8d2065f 100644 --- a/.agent/naming-audit/_SUMMARY.md +++ b/.agent/naming-audit/_SUMMARY.md @@ -1,485 +1,9 @@ # Cross-Package Naming Audit — Executive Summary -**Packages audited:** 79 active API packages (every package under `packages//src//`). The 2026-06-02 prune pass deleted one more audit file (`oauth` — its sole remaining finding was a wire-field rename, leaving zero findings; see Prune pass 12), down from 80. Per-package audits are strictly limited to packages with live source. -**Total active findings across all 79 active audits:** **712** (down from 791 reported before the 2026-06-02 category-prune pass. Earlier waypoints: 1,372 before the 2026-06-02 combined prune pass; 1,376 before the 2026-06-01 single-variant-union prune; 1,420 before the 2026-06-01 regen rescan; 1,598 before the 2026-05-28 rescan-and-prune pass; 2,891 before the 2026-05-26 cleanup pass; 2,926 before the 2026-05-22 Theme 2 prune; 3,572 before the 2026-05-22 regen + rescan; 3,273 before the 2026-05-20 proto-architectural-leak pass; 5,322 in the original sweep.) The latest pass (Prune pass 13) applied three Workflow-B category prunes (field-ordering / grouping findings, data-type-retype findings, and empty / do-nothing wrapper-deletion findings). Net effect: 791 / 79 → 712 / 79. +**Packages audited:** 77 active API packages (every package under `packages//src//`). Per-package audits are strictly limited to packages with live source. +**Total active findings across all 77 active audits:** **479** **Source files:** `/home/parth.bansal/sdk-js/.agent/naming-audit/.md` -**Last source state:** Rescan on 2026-06-02 against the regenerated generated client (proto-nested `*Request_Response` collapsed to clean `*Response`, the `ApiError` swap, many `number` → `bigint` ID-precision conversions, and package-prefixed client class names; the `bundle`, `usagepolicy`, and `billableusagedownload` packages were removed). Prior baseline: rescan on 2026-06-01 against generator regen #167 ("Update SDK API…") + #168 ("Update SDK to latest State of Generator"). - -> **Prune note 1.** The original audit included a cross-cutting theme -> "Empty / trivial wrapper interfaces" (empty `*_Response` interfaces, -> single-field-primitive wrapper types, and proto outer-message wrappers -> retained only to anchor a nested enum). Per user direction these have -> been removed from every per-package audit: the wrapper types are kept -> on the public surface deliberately, for forward compatibility — adding -> a field later is a non-breaking change for a wrapper type but a -> breaking change if the response was previously `void` or a bare -> primitive. The 321 pruned findings are reflected in the totals, -> theme list, and Top-50 below. - -> **Prune note 2.** A second cross-cutting theme, -> "`marshal` / `unmarshal` / `Schema` suffix vocabulary is Go-isms" -> (`marshalCreatePolicySchema`, `unmarshalGetMetastoreSummary_ResponseSchema`, -> etc.), has now also been pruned per user direction. These Zod -> encoder/decoder helpers are SDK-internal — they are emitted into -> per-package `utils.ts` and `model.ts` but are not part of the public -> contract that callers import against. Renaming them carries zero -> external risk and is therefore not a public-surface naming concern. -> The 457 pruned findings from this pass are reflected in the totals, -> theme list (Theme 8 removed), generator recommendations (§8.7 -> removed), and by-the-numbers table below. - -> **Prune note 3.** A third cross-cutting theme, -> "Pagination `Iter` suffix on every paginating method" -> (`listPoliciesIter`, `listCatalogsIter`, `listWarehousesIter`, etc.), -> has now been promoted to a generator-only recommendation per user -> direction. The duplicate-method pattern is emitted by every generated -> package; the fix is one template change, not per-package work. Rather -> than carry the same finding in 98 per-package audits, the rule is -> recorded once in the new `## Generator-only recommendations` section -> below. The 42 pruned findings from this pass are reflected in the -> totals, theme list (the former Theme 8 removed), generator -> recommendations (§8.10 removed), and by-the-numbers table below. - -> **Prune note 4.** A fourth cross-cutting theme, -> "Underscore-in-identifier (proto `Outer_Inner` / `Foo_Response`)" — -> e.g. `ClusterState_ClusterState`, `PipelineState_PipelineState`, -> `DeletePolicy_Response`, `EgressNetworkPolicy_InternetAccessPolicy_InternetDestination_InternetDestinationFilteringProtocol` — -> has now been pruned per user direction. The proto-style underscored -> identifier convention is intentional and correct: it preserves the -> mapping between TS identifiers and protobuf nested-message paths, -> keeps codegen deterministic, and the `// eslint-disable` line that -> each identifier carries is acceptable cost. Renaming would break the -> wire ↔ TS correspondence that downstream tooling relies on. The 584 -> pruned findings from this pass are reflected in the totals, theme -> list (the former Theme 1 removed), generator recommendations (§8.2 -> removed), and by-the-numbers table below. This was the single -> largest category by package incidence (~85/98). - -> **Prune note 5.** A fifth cross-cutting theme, -> "Redundant enum-name prefix on every member" — e.g. -> `PolicyType.POLICY_TYPE_ROW_FILTER`, -> `DestinationType.DESTINATION_TYPE_EMAIL`, -> `CommandStatus.COMMAND_CANCELLED`, `IsolationMode.ISOLATION_MODE_OPEN_IN_ACCOUNT` — -> has been pruned per user direction. The proto-style `Foo.FOO_BAR_BAZ` -> shape is intentional: TS enum member names mirror the protobuf wire -> identifier exactly, which keeps codegen deterministic and preserves -> the wire ↔ TS correspondence. Stripping the prefix on the TS side -> would force a per-enum translation table and break the symmetry that -> generators and downstream tooling rely on. The pruned findings are -> reflected in the totals, theme list (the former Theme 1 removed), -> generator recommendations (§8.1 removed), and by-the-numbers table -> below. - -> **Prune note 6.** A sixth cross-cutting theme, -> "`*_UNSPECIFIED` proto sentinel values in every enum" — e.g. -> `STATE_UNSPECIFIED`, `POLICY_TYPE_UNSPECIFIED`, -> `COMPUTE_KIND_UNSPECIFIED`, `RUN_LIFE_CYCLE_STATE_UNSPECIFIED`, -> `DAY_OF_WEEK_UNSPECIFIED` — has been pruned per user direction. -> proto3 mandates that every enum carry a zero value, and the -> `*_UNSPECIFIED` member is semantically distinct from `undefined`: -> it means "explicitly set to absent/default" on the wire, whereas -> field-optional `?:` `undefined` means "not present in this message". -> Dropping the sentinel would conflate those two states and silently -> break round-tripping. The pruned findings are reflected in the -> totals, theme list (the former Theme 2 removed), and by-the-numbers -> table below. - -> **Prune pass 7 (2026-05-22) — Theme 2 retired.** Workflow B prune -> of "Type-name prefix repeats the package" per user direction -> ("Many type names re-state the package's domain noun. I don't fix -> it, it is fine as it is."). ~34 findings removed across 20 -> packages. Biggest removals: instancepools (5), -> notificationdestinations (4), entitytagassignments (3), -> customllms/externallineage/pipelines/queries/registeredmodels/tagassignments -> (2 each). The remaining 32 candidate audits had no matching -> findings — `Foo*`-prefixed types in those audits were flagged for -> OTHER primary issues (`Info` suffix, proto-architectural leak, -> vague names, cross-package duplicates) and retained. The pruned -> findings are reflected in the totals, theme 2 description below -> (marked retired in place), generator recommendations (§8.6 -> removed), Top-50, and by-the-numbers table below. - -> **Prune pass 8 (2026-05-26) — corpus cleanup.** Combined rebase + -> rescan + orphan deletion + five Workflow B prune passes. Combined -> removals ~1,500 findings (2,891 → 1,598). Components, in -> chronological order: -> -> 1. **Rebase + rescan against regen #156 + acronym renames -> (PR #148).** All 87 active audits rescanned. `logdelivery` -> moved one finding to `Fixed`; remaining audits had minor line -> drift only. -> 2. **`## Fixed` sections removed from every audit** per user -> direction ("remove the entries which are fixed... I think it's -> good to just have a small note in the summary.md which we -> already have"). Audit files now only carry active findings; the -> historical "fixed" delta is summarised in this document. -> 3. **23 orphan / retired audit files deleted** per user direction -> ("Please remove the complete file if there is no issue in -> it... do it for every packages like this"). The 23 deleted: -> `accountaccesscontrol`, `accountaccesscontrolproxy`, -> `accountsettings`, `cleanroomassets`, -> `cleanroomautoapprovalrules`, `cleanroomtaskruns`, `endpoints`, -> `indexes`, `logdeliveryconfigurations`, `materializedfeatures`, -> `modelservingdebug`, `modelservingmanagement`, -> `oauthcustomappintegration`, `oauthpublishedapp`, -> `permissions`, `qualitymonitor`, `qualitymonitors`, -> `queryexecution`, `serviceprincipalsecrets`, -> `serviceprincipalsecretsproxy`, `workspace`, -> `workspaceassignment`, `workspaceconf`, `workspacesettings`. -> (Note: `serviceprincipalsecretsproxy` had already been deleted -> earlier; the active count of deleted files in this pass is -> 23.) The "Retired audits" table at the bottom of §6 is now -> historical reference only. -> 4. **AIP `name` pattern prune** — ~20 findings removed across the -> 31-package scope per user direction ("the name pattern is well -> established in the AIP"). Findings citing the AIP-mandated -> `name` field on Get/Update/Delete requests are no longer -> flagged. -> 5. **Sibling-state-enum prune** — ~5 findings removed across the -> 6-package scope per user direction ("not possible to fix -> without changing the api"). Cross-package state-enum -> duplicates that would require an API change to fix are no -> longer flagged. -> 6. **Field-rename prune** — ~773 findings removed across all 87 -> audits per user direction ("if i change the field name it -> would make the sdk quite different from the api itself"). -> Field-level rename findings (the single largest category by -> incidence) are no longer in scope. Field-name vocabulary drift -> and underspecified-ID findings that boil down to a rename are -> out. -> 7. **Doc-change prune** — ~300 findings removed across all 87 -> audits per user direction ("those can be anytime"). JSDoc -> text, banner-comment, and prose-deprecation findings are no -> longer flagged: the doc surface is a follow-up sweep, not part -> of the structural naming corpus. -> 8. **SDK-internal prune** — ~400 findings removed for -> identifiers that are never re-exported. Coverage: `utils.ts` -> helpers (`executeCall`, `executeHttpCall`, `flattenQueryParams`, -> `readAll`, `HttpCallOptions`, `buildHttpRequest`, -> `PACKAGE_SEGMENT`, `Call`, `pkgJson`), local variables in -> `client.ts` (`req`, `resp`, `opts`), and other internal -> plumbing. Per user direction ("they don't get reexported"). -> 9. **Non-TS prune** — ~70 findings removed for `CHANGELOG.md`, -> `NEXT_CHANGELOG.md`, `package.json`, build / lint workflows, -> and other non-source files. Per user direction ("make sure for -> all packages that recommendations are strictly for the ts -> code"). -> -> The combined pass shrunk every category. The dominant remaining -> findings are now structural type-level issues: -> reserved-word collisions, brand drift, post-merge friction in -> the consolidated packages, cross-package duplicate concepts, and -> proto-architectural leaks that survived the regen. - -> **Prune pass 9 (2026-05-28) — rescan + two prunes + four deletions.** -> Combined removals ~180 findings (1,598 → 1,420). Components, in order: -> -> 1. **Full Workflow-A rescan.** Every source-backed audit was -> re-validated against the current generated source. Findings whose -> symbol is gone, was already renamed to the suggested name, or whose -> concern no longer applies were **deleted outright** (no `## Fixed` -> sections were created or kept). Many resolved findings were -> `number` → `bigint` ID-precision conversions that the generator now -> emits correctly. Line numbers were refreshed in place for findings -> that are still present. -> 2. **Prune A — generic top-level `Client` class name (DEFERRED).** The -> "the exported `Client` class is too generic / collides across every -> package / rename to `Client`" finding was removed from -> every package that carried it (~45 packages). The user is deferring -> this fix (verbatim: "i will fix this later") — it is most likely a -> single generator-level rename rather than per-package work. It is -> **not** lost: it is tracked in the "Deferred (user will fix later)" -> note below so the user can act on it in one place. Example: the -> now-deleted `dataclassification` package's `Client` would become -> `DataClassificationClient`. -> 3. **Prune B — acronym casing (category 3) RESOLVED.** Every -> acronym-casing finding (the "treat acronyms as whole words" rule: -> `Http`/`HTTP`, `Url`/`URL`, `Id`/`ID`, `Uc`/`UC`, `Api`/`API`, -> `Sql`/`SQL`, `PyPi`/`PyPI`, etc.) was removed from every package -> that carried it (~47 packages). The user has resolved acronym -> casing on the public interface (verbatim: "i have already resolved -> this from the public interface"), so this theme is closed/retired — -> see the "Resolved / retired themes" note below. -> 4. **Four audit files deleted.** Each was removed from the corpus: -> - `iam` — orphan; `packages/iam/` source no longer exists (its -> domain moved to `accessmanagement`). -> - `workspaceobjects` — orphan; the `/api/2.0/workspace/` filesystem -> service was dropped from the public-filtered descriptor. -> - `dataclassification` — emptied by the two prunes (its only two -> findings were a `Client`-class item and an acronym-casing item), -> then deleted as an empty audit. -> - `onlinetables` — already had zero findings, deleted as an empty -> audit. -> -> **Deferred → RESOLVED upstream (see Prune pass 10):** the generic -> top-level `Client` class-name rename was deferred here on 2026-05-28 -> (user: "i will fix this later"). It has since shipped at the generator -> level — the 2026-06-01 regen (#167/#168) emits package-prefixed client -> classes (`AccessManagementClient`, `FeaturesClient`, `CredentialsClient`, -> `JobsClient`, `WarehousesClient`, …) instead of a bare `Client`. The -> fix is no longer pending; it is recorded as resolved under Prune pass 10. -> -> **Resolved / retired themes:** acronym casing (former Theme 2 / §4 / -> Appendix category 3) is **resolved** — pruned from every package this -> pass after the user fixed acronym casing on the public interface. It is -> retained below only as a historical reference, marked resolved in place. - -> **Prune pass 10 (2026-06-01) — regen rescan + three orphan deletions.** -> Net removal 44 findings (1,420 → 1,376). Components, in order: -> -> 1. **Generator regen (#167/#168).** The generated client was regenerated -> upstream — commit #167 ("Update SDK API…") and commit #168 ("Update -> SDK to latest State of Generator"). A full Workflow-A rescan ran -> across every source-backed package. -> 2. **Full Workflow-A rescan.** Every finding was re-validated against the -> current generated source. Resolved findings were **deleted outright** -> (no `## Fixed` sections were created or kept), line numbers were -> refreshed in place, and a few findings were superseded-rewritten. -> Most packages had line-number corrections only. The rescan dropped -> **8 findings** inside surviving audits, all where the regen fixed the -> underlying issue: several `number` → `bigint` 64-bit ID-precision -> conversions (`jobs`, `metastores`, `registeredmodels`, and -> experiments-adjacent types), `getMetricHistory` → `listMetricHistory` -> (`experiments`), `get*` → `list*WorkspacePermissionAssignments` / -> `listAssignableRoles*` (`accessmanagement`), `getLatestVersions` → -> `listLatestVersions` (`modelregistry`, superseded-rewritten in place, -> no net change), and a stale `Call` import (`instancepools`). The -> per-package net deltas: `jobs` 83 → 79, `experiments` 24 → 23, -> `accessmanagement` 22 → 21, `instancepools` 61 → 60, -> `registeredmodels` 21 → 20. -> 3. **Three orphan audit files deleted** (source removed by the regen) — -> 36 findings excluded from the total: -> - `bundle` — `packages/bundle/` no longer exists. -> - `usagepolicy` — `packages/usagepolicy/` no longer exists. -> - `billableusagedownload` — `packages/billableusagedownload/` has no -> TypeScript source anymore. -> No surviving audit was emptied this pass, so no additional empty-file -> deletions were needed. -> 4. **Generic `Client` rename — RESOLVED upstream.** The generic -> top-level `Client` class-name rename that the 2026-05-28 pass pruned -> and **deferred** ("i will fix this later", likely generator-level) has -> now shipped: the regen emits package-prefixed client classes -> (`AccessManagementClient`, `FeaturesClient`, `CredentialsClient`, -> `JobsClient`, `WarehousesClient`, …) instead of a bare `Client`. The -> per-package audits already carry no such finding; the deferred note -> under Prune pass 9 is updated to mark the fix resolved at the -> generator level. - -> **Prune pass 11 (2026-06-01) — single-variant union flatten retired.** -> Workflow B prune. Pruned the single-variant discriminated-union flatten -> recommendation (flatten `{ $case: 'x'; ... } | undefined` to a bare -> field). Rejected by the user as not forward-compatible — re-introducing -> the union when a second variant is added is a breaking type change. -> Removed from 2 packages (`accessmanagement` `Actor.kind`, `volumes` -> `EncryptionDetails`). Both findings had been filed under the -> proto-architectural-leak / unnecessary-structure category. All other -> `$case`/`oneof` findings were kept: they are multi-variant unions, -> discriminator-name concerns, proto-leak `_Response`/`_Entry`/`_State` -> types, or recommendations to *introduce* a union — none matched the -> rejected "flatten single-variant union" class. No audit was emptied, so -> no files were deleted this pass. Net −2 findings (1,374 → 1,372); the -> headline figure moves from the previously reported 1,376 because -> re-summing the corpus also corrected a stale `featurestore` tally -> (13 in-file, 15 in the old summary). - -> **Prune pass 12 (2026-06-02) — regen rescan + six category prunes + -> scaffolding cleanup.** Combined removals 581 findings net (1,372 → 791). -> Components, in order: -> -> 1. **Workflow-A rescan after generator regen.** Every source-backed audit -> was re-validated against the regenerated client. The regen collapsed -> the proto-nested `*Request_Response` types into clean `*Response` -> types, swapped the error type to `ApiError`, converted many `number` -> fields to `bigint` for 64-bit ID precision, and emitted -> package-prefixed client class names. The packages `bundle`, -> `usagepolicy`, and `billableusagedownload` were removed (their audit -> files had already been deleted in Prune pass 10). -> 2. **Pruned the `ErrorCode`-centralization recommendation class.** Removed -> every finding recommending that a package stop shipping the large -> global `ErrorCode` enum locally / move it to a shared core -> `apierror/codes` package (candidates: `apps`, `credentials`, -> `environments`, `genie`, `postgres`, `statementexecution`). -> 3. **Pruned the generic-`Operation`-LRO-type recommendation class.** -> Removed every finding recommending that the top-level `Operation` -> long-running-operation type be renamed to `Operation` or moved -> to shared core, including the `GetOperationRequest` generic-name angle -> (candidates: `apps`, `environments`, `forecasting`, `postgres`). -> 4. **Pruned the boolean-shaped-two-value-enum recommendation class.** -> Removed every finding recommending that a two-value enum whose other -> value is an absence/`NO_*` sentinel be modeled as a `boolean` (e.g. -> `accessRestricted?: CleanRoom_AccessRestricted`). -> 5. **Pruned the duplicate-concept / naming-consistency recommendation -> class.** Removed every finding recommending that generated -> types/enums/fields modeling the same or a related concept be -> renamed, consolidated, or disambiguated (e.g. two `Status` enums, -> `creator` vs `collaborators`, `CleanRoomCollaborator` vs -> `CollaboratorJobRunInfo`). -> 6. **Stripped non-finding scaffolding sections.** Removed the -> `## Inventory`, `## File coverage`, `## Domain glossary`, -> `## Comparison` / cross-audit tables, priority-order lists, file -> indexes, and scope-note preambles from every audit, keeping only the -> metadata, the summary table, and the findings. -> 7. **Pruned documentation-only findings.** Removed every finding whose -> fix is JSDoc/comment content, a soft-deprecation note needing the -> `@deprecated` tag, or a doc-markup leak — anything that can be changed -> at any time without a backward-incompatible change (e.g. -> `agentArtifactPath` doc wording). -> 8. **Removed empty `_None._` section stubs throughout.** Where a prior -> prune had emptied a section, the leftover header + `_None._` line was -> deleted and any index/summary table that referenced it was reconciled. -> 9. **Pruned wire-identifier-rename findings.** Removed every finding whose -> core fix renames a JSON field/property name or an enum member value. -> KEPT type/interface/class renames, method-name fixes, and `string` → -> enum retyping. -> -> **Net effect: 1,372 / 80 → 791 / 79.** The `oauth.md` audit was deleted -> because its sole remaining finding was a wire-field rename, which the -> wire-identifier-rename prune removed, leaving the file with zero findings. - -> **Prune pass 13 (2026-06-02) — three category prunes.** Combined removals -> 79 findings net (791 → 712). Three Workflow-B category prunes were applied, -> in order: -> -> 1. **Pruned the field-ordering / grouping recommendation class** (category -> 17 "reorder fields so related fields sit adjacent"). Removed every -> finding whose only fix is cosmetic source-order — reordering fields in -> a type so related fields sit next to each other. Source-order has no -> effect on the public contract or the wire format. -> 2. **Pruned the data-type-retype recommendation class.** Removed every -> finding whose fix retypes a field's primitive type: a `string` that -> should be an enum/union, a `number` that should be a `Date` or -> `bigint`, or a `string` that should be a branded/opaque type. This -> **reverses the earlier keep-`string` → enum stance** recorded in -> Prune pass 12 (the wire-identifier-rename prune had explicitly KEPT -> `string` → enum retyping). KEPT all structural findings — optionality, -> cardinality, discriminated unions, and non-empty wrapper reshape — and -> all renames. -> 3. **Pruned the empty / do-nothing wrapper-deletion recommendation class.** -> Removed every finding recommending that an EMPTY interface or a -> proto-namespace-anchor wrapper be deleted. Empty messages are kept for -> forward-compatibility: adding a field later is a non-breaking change for -> a wrapper type but a breaking change if the response was previously -> `void`. Note: proto MAP-ENTRY types (`*_Entry` = `{ key, value }` for -> `map` fields) are KEPT — they are non-empty wrappers, not -> do-nothing anchors. The `catalogs` (6) and `features` (1) map-entry -> findings were briefly over-removed in this pass and then restored. -> -> **Net effect: 791 / 79 → 712 / 79.** No audit was emptied, so no files -> were deleted this pass; the package count holds at 79. - -> **Rescan note (2026-05-20).** The generator was re-run and the -> per-package audits were rescanned against the new source state. The -> rescan dropped **710 findings net** and closed out several structural -> pain points in the wire ↔ TS mapping: -> -> - **`Request` suffix wave (Theme 3, former).** The generator now -> emits every request DTO with a `Request` suffix -> (`DeletePolicyRequest`, `ListSecretsRequest`, `ExportRequest`, -> etc.). Verb-phrase request types — the previous Theme 3, cited in -> ~80/98 packages — are no longer the dominant concern. Residual -> instances in `bundle`, `files`, `marketplaces`, and a few others -> are tracked per-package. The former §8.5 generator rule has been retired -> as **Done** in §7 below. -> - **14 packages deleted, merged, or renamed.** Five removed outright -> (`accountaccesscontrol`, `accountaccesscontrolproxy`, -> `serviceprincipalsecrets`, `serviceprincipalsecretsproxy`, -> `queryexecution`). Nine consolidated: -> `cleanroomassets` + `cleanroomautoapprovalrules` + -> `cleanroomtaskruns` → `cleanrooms`; `endpoints` + `indexes` → -> `vectorsearch`; `oauthcustomappintegration` + `oauthpublishedapp` -> → `oauth`; `modelservingdebug` + `modelservingmanagement` → -> `modelserving`; `workspaceassignment` → `accessmanagement`. -> Three packages renamed in place: `permissions` → -> `accessmanagement`, `workspace` → `workspaceobjects`, -> `logdeliveryconfigurations` → `logdelivery`. -> - **Themes that shrank materially.** The "verb-phrase request types" -> theme has been retired and is now footnote-level. The "Package-name -> prefix repeats package" (e.g. `OAuthAppIntegration*`, -> `CleanRoom*`, `Pipelines*`, `Genie*`) theme shrank ~30% because -> several offending packages were merged or renamed. The -> "byte-identical `*proxy` packages" pain point is gone (both -> `*Proxy` packages were deleted). -> - **Carried-over findings.** Findings that were *still present* after -> the regeneration kept their position in `High`/`Medium`/`Low`. Line -> numbers were updated in place. Audits whose package was deleted -> have all findings under `## Fixed` and zero active total. - -> **Audit-pass note 7 (proto-architectural-leak scan).** A ~93-agent -> pass scanned every API package for mid-position infix tokens that -> betray internal proto/service-tier ownership: `*Public*Request`, -> `*Proto` suffix, `*Service*` / `*Manager*` / `*Backend*` / `*Handler*` -> mid-position, `*Internal*`, `*Wrapper*`, `*CustomerFacing*` qualifier, -> mid-position `*V2*` (e.g. `RunLifecycleStateV2`), and JSDoc leaks of -> "Public RPC" / "Wrapper message" / "Public facing RPC requests and -> responses" verbatim banners. Findings were appended to each per-package -> audit under a new "Proto-architectural leak" category and added ~300 -> findings net (3,273 → 3,572). The pass also created seven -> previously-missing audits for packages absorbed from the account-API -> split during the 2026-05-20 regen: `authentication`, `keyconfigurations`, -> `networking`, `scim`, `sharing`, `storageconfigurations`, `workspaces`. - -> **Audit-pass note 8 (2026-05-21 — Google TS acronym renames applied).** -> Adopted the Google TS Style Guide acronym-as-whole-word rule (already -> documented at `.agent/rules/typescript.mdc:184`). Renamed 105 files: -> 11 hand-written (`auth`, `core`, `examples`) + 94 generated `utils.ts` -> import updates. `OAuth*`, `OIDC*`, and JS built-ins kept under the -> platform-name exception. - -> **Audit-pass note 9 (2026-05-22 — Generator regen + rescan).** The -> generator was re-run against upstream API version -> `0555d6a59265799ed8ea12f355eee662e739430d`. All 81 active audits -> were rescanned and 6 newly-created audits cover packages that the -> regen consolidated from smaller siblings: -> -> - `accessmanagement` (NEW, 38 findings) — supersedes `permissions`, -> `accountaccesscontrol`, `accountaccesscontrolproxy`, and -> `workspaceassignment`. Single umbrella for object permissions, -> permission levels, rule sets, and workspace assignments. -> - `logdelivery` (NEW, 28 findings) — renamed from -> `logdeliveryconfigurations`. The legacy long name was a clean -> rename target. -> - `modelserving` (NEW, 47 findings) — supersedes -> `modelservingmanagement` and absorbed the former `modelservingdebug`. -> `modelservingquery` remains separate. -> - `oauth` (NEW, 11 findings) — supersedes -> `oauthcustomappintegration` and `oauthpublishedapp`. Single -> package for both Custom and Published app integrations plus -> the published-app catalog. -> - `vectorsearch` (NEW, 28 findings) — supersedes `endpoints` and -> `indexes`. Single endpoint+index surface for Vector Search. -> - `workspaceobjects` (NEW, 29 findings) — renamed from -> `workspace`. The bare name was the most-overloaded in the SDK; -> the rename clarifies the package scope as the workspace -> filesystem (notebooks/folders/files). -> -> **24 audit files marked as removed/consolidated.** Their findings -> are excluded from the active total. Source packages no longer -> exist: -> `accountaccesscontrol`, `accountaccesscontrolproxy`, -> `accountsettings`, `cleanroomassets`, `cleanroomautoapprovalrules`, -> `cleanroomtaskruns`, `endpoints`, `indexes`, -> `logdeliveryconfigurations`, `materializedfeatures`, -> `modelservingdebug`, `modelservingmanagement`, -> `oauthcustomappintegration`, `oauthpublishedapp`, `permissions`, -> `qualitymonitor`, `qualitymonitors`, `queryexecution`, -> `serviceprincipalsecrets`, `serviceprincipalsecretsproxy`, -> `workspace`, `workspaceassignment`, `workspaceconf`, -> `workspacesettings`. Each retired audit carries a status banner at -> the top of the file noting the 2026-05-22 consolidation date and -> retains the original findings as historical record. -> -> **~81 findings moved to Fixed in this regen** — overwhelmingly -> proto-architectural-leak `*Public*Request` and `*PublicRequest_Response` -> patterns that the regen renamed across the account-tier packages. -> The largest per-package shifts: -> `metastores` (20 fixed), `networking` (17 fixed), `workspaces` (16 -> fixed), `credentials` (~10 fixed), `storageconfigurations` (~10 -> fixed), `cleanrooms` (4 fixed), `jobs` (2 fixed), `keyconfigurations` -> (2 fixed). These renames retroactively validate generator rule -> §8.2 ("Strip proto-architectural-tier markers"). The rule is **not** -> marked Done — `*CustomerFacing*` qualifiers in `networking` and a -> handful of `Proto` suffixes (e.g. `TriggerStateProto`, -> `DatabricksServiceExceptionProto`) still survive in active audits. +**Last source state:** The per-package audits are validated against the current generated client source. This document synthesises the per-package audits into the patterns that the upstream generator (and a smaller number of API team decisions) should fix @@ -487,7 +11,7 @@ to deliver an idiomatic TypeScript SDK. The vast majority of the findings are template-driven — fix the template once and the symptoms disappear from every package. -The 79 active packages are a 1:1 port of `databricks/sdk-go`, so most defects +The 77 active packages are a 1:1 port of `databricks/sdk-go`, so most defects flow from Go/protobuf idioms that do not translate to TypeScript. Idiomatic TS SDKs (AWS, Azure, Stripe, Octokit) deliberately diverge from their wire formats; the Databricks JS SDK currently does not. @@ -497,33 +21,32 @@ formats; the Databricks JS SDK currently does not. ## 1. Top cross-cutting themes Ranked by approximate package incidence. Each theme is a generator-level -defect — one template change fixes most of the 79 active packages. +defect — one template change fixes most of the 77 active packages. -The table below tallies the theme tags carried by the 79 per-package audits, +The table below tallies the theme tags carried by the 77 per-package audits, counting the number of packages each tag appears in (a package is counted once per tag regardless of how many findings carry it). The curated narrative themes (Theme 1–4) follow. | Theme | Packages | |---|---| -| Type-shape / cardinality (unions, optionality, wrappers) | 48 | -| Method / operation naming | 47 | -| Vague / generic type name | 38 | -| Redundant `*Info`/`*Details`/`*Spec` type suffix | 36 | -| Misleading type name | 32 | -| Proto `Foo_Bar` type-name leak (incl. map-entry types) | 21 | -| Architectural leak (`Public`/`Proxy`/`Handler`) | 18 | -| `*Request`/`*Response` envelope rename | 18 | -| Package name | 11 | - -### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~30/79 packages (shrunk by the 2026-05-26 field-rename prune) +| Type-shape / cardinality (unions, optionality, wrappers) | 43 | +| Method / operation naming | 34 | +| Misleading type name | 33 | +| Vague / generic type name | 32 | +| Architectural leak (`Public`/`Proxy`/`Handler`) | 30 | +| Redundant `*Info`/`*Details`/`*Spec` type suffix | 29 | +| Proto `Foo_Bar` type-name leak (incl. map-entry types) | 23 | +| `*Request`/`*Response` envelope rename | 14 | +| Package name | 9 | + +### Theme 1. `Info` (and other vague) suffix on the canonical entity — ~29/77 packages The Go SDK uses `Info` to name "details of an X" because Go does not have package-qualified imports for types. TS does, and `` alone -suffices. The 2026-05-26 field-rename prune removed the field-side -incidence of this theme (e.g. `repo?: RepoInfo` is no longer flagged as a -field-name issue) but the type-name incidence survives. Examples that -remain flagged at the type level: +suffices. Field-side instances of this theme are out of scope (field +renames would deviate the SDK from the underlying API), but the type-name +incidence is flagged. Examples that are flagged at the type level: - `RepoInfo` → `Repo` / `GitFolder` (brand drift — see Theme 3). - `PolicyInfo` → `Policy`. @@ -535,8 +58,8 @@ remain flagged at the type level: - `RegisteredModelInfo`, `ModelVersionInfo`, `RegisteredModelAliasInfo`, `TableInfo`, `FunctionInfo`, `ConnectionInfo`, `VolumeInfo`. -Same problem with other vague suffixes (type-side only after the prune): -- `*Spec` / `*Details` / `*Config` / `*Status` / `*Data` / `*Metadata` used inconsistently — sometimes for the entity, sometimes for a sub-property, sometimes for both. `apps.ApplicationStatus` and `App.appStatus` (the field is no longer flagged but the type-name divergence remains). +Same problem with other vague suffixes (type-side only): +- `*Spec` / `*Details` / `*Config` / `*Status` / `*Data` / `*Metadata` used inconsistently — sometimes for the entity, sometimes for a sub-property, sometimes for both. `apps.ApplicationStatus` and `App.appStatus` (the type-name divergence is flagged; the field name is out of scope). **Generator fix:** Strip the `Info` suffix when the type is the canonical domain entity. (Heuristic: if `Info` is the only `*` type that @@ -545,30 +68,17 @@ suffixes on tagged-union arms when the parent has a discriminator. Field renames are out of scope per user direction (would deviate the SDK from the underlying API). -### Theme 2. Inconsistent acronym casing across the SDK — RETIRED (RESOLVED 2026-05-28) - -> **Status (2026-05-28): RESOLVED — theme retired.** The user has -> resolved acronym casing on the public interface (verbatim: "i have -> already resolved this from the public interface"). Every -> acronym-casing finding (the "treat acronyms as whole words" rule: -> `Http`/`HTTP`, `Url`/`URL`, `Id`/`ID`, `Uc`/`UC`, `Api`/`API`, -> `Sql`/`SQL`, `PyPi`/`PyPI`, etc.) was pruned from every per-package -> audit in the 2026-05-28 Prune B pass (~47 packages). This theme is no -> longer an active cross-cutting concern; it is retained here only as a -> historical pointer. -> -> Earlier history: the Google TS Style Guide rule -> (`.agent/rules/typescript.mdc:184`) was adopted on 2026-05-21, the -> hand-written-package renames (105 files: `APIError` → `ApiError`, -> `IDToken` → `IdToken`, `HTTPStatusCode`/`HTTPHeader`/`HTTPBody` → -> `httpStatusCode`/`httpHeader`/`httpBody`, etc.) were applied then, and -> `OAuth*`/`OIDC*` plus JS built-ins (`URLSearchParams`, `JSON.parse`, -> `encodeURIComponent`) were kept under the platform-name exception. The -> 2026-05-28 pass closed out the remaining generated-code surface. The -> observational casing inventory that used to live here is preserved in -> §4 below, marked resolved in place. - -### Theme 3. Brand drift / rebrand leakage — ~6/79 packages (stable across the 2026-05-26 prune) +### Theme 2. Inconsistent acronym casing across the SDK — resolved (not a current finding) + +Acronym casing on the public interface follows the Google TypeScript Style +Guide `Pascal-then-lower` form (`Url`, `Id`, `Json`, `Sql`), documented at +`.agent/rules/typescript.mdc`. `OAuth*`/`OIDC*` plus JS built-ins +(`URLSearchParams`, `JSON.parse`, `encodeURIComponent`) are kept under the +platform-name exception. This is resolved and is no longer flagged as a +per-package finding; the casing inventory in §4 below is retained for +reference. + +### Theme 3. Brand drift / rebrand leakage — ~6/77 packages Several products were rebranded but the TS surface still carries the old codename: @@ -583,24 +93,19 @@ codename: **Generator fix:** Per-product spec needs updates; the rename can land via a generator alias map (`Endpoint` → `Warehouse` in `warehouses` only, etc.). -### Theme 4. Proto-architectural-leak infixes — ~8/79 packages (further shrunk by the 2026-05-26 doc + SDK-internal prunes; single-variant `oneof`-wrapper sub-case pruned 2026-06-01) +### Theme 4. Proto-architectural-leak infixes — ~8/77 packages Internal proto / service-tier identifiers leak through the codegen and show up as mid-position infix tokens that have no meaning to a TS SDK consumer. -The 2026-05-22 generator regen retroactively validated generator rule §8.2 -and renamed the dominant `*Public*Request` sub-pattern. The 2026-05-26 prune -further removed the JSDoc-banner sub-cases (out of scope per the doc-change -prune) and SDK-internal `utils.ts` plumbing (out of scope per the -SDK-internal prune). What remains is the type-name surface only. - -**Status after the 2026-05-26 prune:** +The `*Public*Request` sub-pattern has been renamed and is no longer a +concern; JSDoc-banner sub-cases and SDK-internal `utils.ts` plumbing are out +of scope. What remains is the type-name surface only: -- The `*Public*Request` sub-pattern is fixed (2026-05-22 regen). -- **`*CustomerFacing*` qualifier still survives in `networking`** — 40+ +- **`*CustomerFacing*` qualifier survives in `networking`** — 40+ identifiers (`CustomerFacingIngressNetworkPolicy`, `CustomerFacingVpcEndpointUseCase`, etc.) in active source. Not yet - scanned as findings because the regen left them untouched. -- **`*Proto` suffix** still active in a handful of identifiers: + scanned as findings. +- **`*Proto` suffix** active in a handful of identifiers: `TriggerStateProto` (`jobs`), `DatabricksServiceExceptionProto`, `DatabricksServiceExceptionWithDetailsProto` (`apps`). - **`*Service*` mid-position infix.** `ServiceErrorCode` / `ServiceError` @@ -608,21 +113,6 @@ SDK-internal prune). What remains is the type-name surface only. - **`*Handler` suffix.** `listCleanRoomNotebookTaskRunsHandler` / `listCleanRoomNotebookTaskRunsHandlerIter` in `cleanrooms/client.ts`. - **`*V2*` mid-position.** `RunLifecycleStateV2` (jobs). -- **JSDoc banners pruned.** "Public RPC", "Wrapper message", and "Public - facing RPC requests and responses *****" comments no longer flagged - (doc-change prune, 2026-05-26). -- **Single-variant `oneof`-wrapper sub-case pruned (2026-06-01).** A - structural proto-leak variant — a `oneof` rendered as a single-variant - discriminated union (`{ $case: 'x'; ... } | undefined`) or a one-field - wrapper message kept only to carry that union — was previously flagged - with a recommendation to flatten it to a bare field. The user rejected - flattening as not forward-compatible (re-introducing the union when a - second variant is added is a breaking type change), so the two findings - (`accessmanagement` `Actor.kind`, `volumes` `EncryptionDetails`) were - removed in Prune pass 11. This sub-case never contributed to the ~8/80 - infix-token incidence above — it is structural, not one of the - `*Proto`/`*Service*`/`*Handler`/`*CustomerFacing*`/`V` tokens — so the - package count is unchanged; only the global finding total drops by 2. **Generator fix:** Strip proto-architectural-tier markers from the public TS surface emit. The set is small and closed: `Public`, `Internal`, @@ -638,35 +128,31 @@ The audits surfaced ~20 pairs/triplets/quartets of packages that overlap on a single underlying concept. Each row is a real user-facing pain point: "I want to do X — which of these N packages do I import?" -### 2.1 Settings (2-way overlap — was a 4-way) +### 2.1 Settings -The 2026-05-22 regen consolidated the previous 4-way fanout -(`settings` + `accountsettings` + `workspacesettings` + `workspaceconf`) -into: +Account- and workspace-scoped settings live under a single unified v2 +surface: | Package | Style | What it really is | |---|---|---| | `settings` (v2) | Generic polymorphic value | Account- and workspace-scoped settings under the unified v2 surface | -| Retired | — | `accountsettings`, `workspacesettings`, `workspaceconf` were retired in the regen; their findings are in the orphan audits | -`settings/v2/model.ts` now carries 30 active findings — the cross-package -duplicates (`BooleanMessage`, `StringMessage`, `RestrictWorkspaceAdminsMessage`, -`PersonalComputeMessage`) are now collapsed into a single surface but the +`settings/v2/model.ts` carries the cross-package duplicates +(`BooleanMessage`, `StringMessage`, `RestrictWorkspaceAdminsMessage`, +`PersonalComputeMessage`) collapsed into a single surface, but the type-naming friction remains. -### 2.2 Secrets (2-way overlap, was 4-way) +### 2.2 Secrets (2-way overlap) -The 2026-05-20 regeneration deleted both `serviceprincipalsecrets` and -`serviceprincipalsecretsproxy`. The remaining secrets surface is: +The secrets surface is: | Package | What it really is | |---|---| | `secrets` | Workspace-level Secret Manager (scopes + key/value) | | `secretsuc` | Unity Catalog three-level-namespaced secrets | -Both packages still export a class literally named `Client` and a type -literally named `Secret`. The previous byte-identical `*proxy` duplicate -no longer exists. +Both packages export a class literally named `Client` and a type literally +named `Secret`. ### 2.3 Credentials (3-way overlap) @@ -679,16 +165,11 @@ no longer exists. The bare type name `Credential` exists in two of these and `Credentials` exists in the third. -### 2.4 Identity / IAM (consolidated; `iam` audit deleted 2026-05-28) +### 2.4 Identity / IAM (consolidated) -- The `iam` package source no longer exists; its domain moved to - `accessmanagement`, so the `iam` audit file was deleted on 2026-05-28. - (The former `iam` pain points — `*` + `*Proxy` method pairs, the - generic top-level `State`/`Entitlement` enums — are no longer tracked.) -- `accessmanagement` is the consolidated umbrella for what used to be - `permissions`, `accountaccesscontrol`, `accountaccesscontrolproxy`, and - `workspaceassignment`. Covers object permissions, permission levels, - rule sets, and workspace assignments in a single import path. +`accessmanagement` is the consolidated umbrella for object permissions, +permission levels, rule sets, and workspace assignments in a single import +path. ### 2.5 Tokens @@ -727,9 +208,8 @@ hidden behind a plural noun. - `warehouses` exposes SQL Warehouses (formerly "SQL Endpoints"); the TS types still spell `Endpoint*` (e.g. `EndpointInfo`, `EndpointState`). -- `vectorsearch` (consolidated from `endpoints` + `indexes`) exposes - Vector Search endpoints with type names like `Endpoint`, `EndpointType`, - `EndpointStatus`. +- `vectorsearch` exposes Vector Search endpoints with type names like + `Endpoint`, `EndpointType`, `EndpointStatus`. Two packages, two `Endpoint*` type families, different products. @@ -750,40 +230,27 @@ types covering the same wire object. | `features` | Feature definitions | | `featurestore` | Online stores / publishing | -The third sibling (`materializedfeatures`) was retired in the 2026-05-22 -regen; its surface is folded into `features` (`MaterializedFeature` types -already live there). +The materialized-features surface is folded into `features` +(`MaterializedFeature` types live there). -### 2.13 Budget policy (was a Budget / Usage-policy 2-way overlap) +### 2.13 Budget policy | Package | What it really is | |---|---| | `budgetpolicy` | `/api/2.0/accounts/{accountId}/budget-policies` | -The 2026-06-01 regen (#167/#168) removed the `usagepolicy` package source, -so its audit was deleted as an orphan (Prune pass 10) and the overlap is -gone. For the record, `usagepolicy/v1/model.ts` had been a 1:1 clone of -`budgetpolicy/v1/model.ts` with the word "Budget" substituted for "Usage" — -the JSDoc on `UsagePolicy.policyId` even admitted it ("same structure as -BudgetPolicy"). The remaining `budgetpolicy` package stands alone. +The `budgetpolicy` package stands alone. -### 2.14 Workspace (now a single package, was 5) +### 2.14 Workspace -The 2026-05-22 regen retired three of the previous five -(`workspace` → `workspaceobjects` rename, `workspaceassignment` → -`accessmanagement`, and both `workspaceconf` and `workspacesettings` -retired). The 2026-05-28 pass then deleted the `workspaceobjects` audit -as an orphan: the `/api/2.0/workspace/` filesystem service was dropped -from the public-filtered descriptor, so that source no longer exists. The -remaining audited package in this space is: +The remaining audited package in this space is: | Package | What it really is | |---|---| | `workspacebindings` | Securable-to-workspace bindings | -The bare name `workspace` was the most-overloaded; the workspace -filesystem surface (notebooks/folders/files) is no longer part of the -public-filtered SDK. +The workspace filesystem surface (notebooks/folders/files) is not part of +the public-filtered SDK. ### 2.15 Schemas (UC overlap) @@ -794,16 +261,12 @@ public-filtered SDK. ### 2.16 OAuth (consolidated) -The 2026-05-22 regen merged `oauthcustomappintegration` and -`oauthpublishedapp` into a single `oauth` package, ending the -singular-plural split and the misleading "custom" name. The new package -covers both Custom and Published app integrations as well as the -published-app catalog. +A single `oauth` package covers both Custom and Published app integrations +as well as the published-app catalog. ### 2.17 Statement / Query / Command execution -`queryexecution` was deleted in the 2026-05-20 regeneration. The -remaining surfaces: +The execution surfaces are: | Package | What it really is | |---|---| @@ -815,12 +278,9 @@ remaining surfaces: Four packages, three near-synonyms in the names (query/statement/command), disjoint scopes that the names do not telegraph. -### 2.18 Account API cluster (consolidated in the 2026-05-22 regen) +### 2.18 Account API cluster (consolidated) -The 2026-05-20 regen first absorbed account-tier APIs into seven -previously-unaudited packages. The 2026-05-22 regen then renamed the -`*Public*Request` family across every one of them — ~81 findings moved to -`Fixed`. The remaining surface is the consolidated set: +The account-tier surface is the consolidated set: | Package | Account-tier surface | |---|---| @@ -834,11 +294,10 @@ previously-unaudited packages. The 2026-05-22 regen then renamed the | `scim` | Account-level SCIM 2.0 user/group provisioning | | `sharing` | Account-level Delta Sharing provider config | | `accessmanagement` | Object permissions, permission levels, rule sets, workspace assignments (consolidated) | -| `logdelivery` | Account-level log delivery configs (was `logdeliveryconfigurations`) | +| `logdelivery` | Account-level log delivery configs | -The `*Public*Request` proto-leak that previously dominated this cluster is -no longer a concern. Residual `*CustomerFacing*` qualifiers in `networking` -are not yet flagged but match generator rule §8.2. +Residual `*CustomerFacing*` qualifiers in `networking` are not yet flagged +but match generator rule §8.2. ### 2.19 Other notable overlaps @@ -858,7 +317,7 @@ expansion in code or JSDoc. A first-time user has to guess. | `rfa` | Request For Access | Package name only | `packages/rfa/` — no expansion in any TS identifier or JSDoc. The wire URL `/api/3.0/rfa/...` is the only other carrier. | | `uc` | Unity Catalog | Package suffix (`secretsuc`), URL `/unity-catalog/`, comment references | Never appears as a type prefix. | | `sp` | Service Principal | Field prefixes (`accountSpStatus`, `spId`) | Inconsistent — sometimes spelled out (`servicePrincipal`), sometimes `sp`. | -| `conf` | Configuration | `EndpointConfPair` (type) (legacy `workspaceconf` package retired in 2026-05-22 regen) | One four-letter abbreviation that the rest of the SDK consistently spells out. | +| `conf` | Configuration | `EndpointConfPair` (type) | One four-letter abbreviation that the rest of the SDK consistently spells out. | | `dbu` | Databricks Unit | Cluster docs only | Not in type names. | | `dbr` | Databricks Runtime | `TerminationCode.DBR_IMAGE_RESOLUTION_FAILURE`, `K8S_DBR_CLUSTER_LAUNCH_TIMEOUT` | Acronym not expanded. | | `dbfs` | Databricks File System | `DbfsStorageInfo`, `disableLegacyDbfs` | Casing varies (`Dbfs` vs `DBFS` in JSDoc). | @@ -869,12 +328,12 @@ expansion in code or JSDoc. A first-time user has to guess. | `llm` | Large Language Model | `CustomLlm`, `LlmProxyPartnerPoweredAccount`, `Llm*` family | `Llm` casing is uniform across SDK. | | `sdp` | Serverless Declarative Pipelines | Comments | Internal acronym. | | `ldp` | Lakeflow Declarative Pipelines | Comments | Internal acronym. | -| `dab` | Databricks Asset Bundles | formerly the `bundle` package (removed by the 2026-06-01 regen) | Was spelled out in the package name. | +| `dab` | Databricks Asset Bundles | Not a current package | Conventional Databricks acronym. | | `m2m` | Machine-to-Machine | `auth/credentials/m2m.ts` | OAuth grant type. | | `u2m` | User-to-Machine | `auth/credentials/u2m.ts` | OAuth grant type. | | `pat` | Personal Access Token | `auth/credentials/pat.ts`, `tokens` package | OAuth-adjacent. | | `abac` | Attribute-Based Access Control | Package name `abacpolicies` only | Never appears in code or types. | -| `iam` | Identity and Access Management | Former package name (audit deleted 2026-05-28); still appears in JSDoc/identifiers elsewhere | Conventional. | +| `iam` | Identity and Access Management | Appears in JSDoc/identifiers | Conventional. | | `wkt` | Well-Known Types | `@databricks/sdk-core/wkt` import | Proto term, not exposed to users. | | `aibi` | AI/BI Dashboards | `AibiDashboard*` family | Internal codename for the "AI/BI" product brand. | | `byok` | Bring Your Own Key | `TerminationCode.AZURE_BYOK_KEY_PERMISSION_FAILURE` | Not expanded. | @@ -892,17 +351,12 @@ expansion in code or JSDoc. A first-time user has to guess. --- -## 4. Acronym-casing inconsistencies — RESOLVED (2026-05-28) +## 4. Acronym-casing inventory — resolved (reference only) -> **Resolved / retired.** The user has fixed acronym casing on the public -> interface (verbatim: "i have already resolved this from the public -> interface"). The corresponding per-package findings (category 3) were -> pruned everywhere in the 2026-05-28 Prune B pass. The table below is -> retained as a historical inventory of the BEFORE state only; it is no -> longer an active set of findings. - -The SDK previously had no enforced casing policy. The same acronym appeared in -multiple casings across packages — sometimes within the same file. +Acronym casing on the public interface is resolved and is no longer an +active set of findings. The table below is retained as a reference +inventory of the acronyms that appear across the SDK and the casings each +takes. | Acronym | Found casings | Sample sites | |---|---|---| @@ -917,7 +371,7 @@ multiple casings across packages — sometimes within the same file. | **GCP** | `Gcp`, `GCP` | `GcpAvailability` (type), `GCP_QUOTA_EXCEEDED` (enum). | | **Azure** | `Azure` | Consistent. | | **LLM** | `Llm`, `LLM` | `CustomLlm` (type, field), JSDoc says `LLM`. | -| **HTTP** | `Http`, `HTTP` | `HttpClient` (type) vs JSDoc and headers. Hand-written packages converged on Pascal-then-lower (`httpStatusCode`, `httpHeader`, `httpBody`) on 2026-05-21. | +| **HTTP** | `Http`, `HTTP` | `HttpClient` (type) vs JSDoc and headers. Hand-written packages use Pascal-then-lower (`httpStatusCode`, `httpHeader`, `httpBody`). | | **HTTPS** | `Https` | Consistent. | | **DBFS** | `Dbfs`, `DBFS` | `DbfsStorageInfo` vs `disableLegacyDbfs` vs JSDoc "DBFS". | | **DBR** | `Dbr`, `DBR` | Enum members all-caps. | @@ -925,7 +379,7 @@ multiple casings across packages — sometimes within the same file. | **CSP** | `Csp`, `CSP` | Type `Csp*`, JSDoc "CSP". | | **ESM** | `Esm`, `ESM` | Type `Esm*`, JSDoc "ESM". | | **IdP** | `Idp`, `IdP` | `idp*` fields, JSDoc "IdP". | -| **ETag** | `etag`, `eTag`, `ETag` | Three casings within one JSDoc comment block (formerly `accountaccesscontrolproxy`, now in `accessmanagement`). | +| **ETag** | `etag`, `eTag`, `ETag` | Three casings within one JSDoc comment block in `accessmanagement`. | | **ODBC** | `Odbc` | `OdbcParams`. | | **JDBC** | `Jdbc`, `JDBC` | Doc references only. | | **AI/BI** | `Aibi`, `AI/BI` | `AibiDashboard*` types, JSDoc says "AI/BI". | @@ -933,33 +387,24 @@ multiple casings across packages — sometimes within the same file. | **TLS** | `Tls`, `TLS` | Rare; `Tls` in field names. | | **OAuth2** | varied | `oauth2` (path), `OAuth` (types). | -**Outcome (resolved).** The chosen rule is the Google TypeScript Style -Guide `Pascal-then-lower` form (`Url`, `Id`, `Json`, `Sql`), already -documented at `.agent/rules/typescript.mdc`. The hand-written packages -were converged on 2026-05-21 and the user has since resolved the -remaining public-interface casing; the per-package acronym-casing -findings were pruned on 2026-05-28. Wire format unchanged. +**Policy.** The rule is the Google TypeScript Style Guide +`Pascal-then-lower` form (`Url`, `Id`, `Json`, `Sql`), documented at +`.agent/rules/typescript.mdc`. Wire format unchanged. --- -## 5. Top highest-impact surviving findings +## 5. Top highest-impact findings -Picked from the post-2026-06-01-rescan corpus. Entries that depended on -field-rename, doc-change, SDK-internal, non-TS, generic-`Client`-class, -or acronym-casing findings (all now out-of-scope or resolved) have been -removed. The generic-`Client`-class issue is now resolved upstream (the -regen emits `Client` names), and the `bundle` and `usagepolicy` -entries are dropped because the 2026-06-01 regen removed those packages. -The retained entries are structural type-level issues — type names, -reserved-word collisions, brand drift, cross-package duplicate concepts, -and the surviving proto-architectural leaks. Each entry: file + symbol + -the generator pattern it exemplifies. +The entries are structural type-level issues — type names, reserved-word +collisions, brand drift, cross-package duplicate concepts, and +proto-architectural leaks. Each entry: file + symbol + the generator +pattern it exemplifies. | # | Package | File:Line | Symbol / Issue | Pattern | |---|---|---|---|---| | 1 | `jobs` | `model.ts:3399, 3491, 3852, 3866, 4261, 908, 3875` | `Run` overloaded across 7 shapes (`Run`, `BaseRun`, `RunTask`, `Run_JobLevelParameters`, `RunState`, `RunStatus`, `RunTriggerInfo`). | Vague/duplicate concepts | | 2 | `jobs` | `model.ts:150, 280, 1464, 1835` | `Format`, `Source`, `Compute`, `Environment` — top-level types collide with JS/TS built-ins and DOM globals. | Reserved-word collision | -| 3 | `jobs` | `model.ts` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak that survived the 2026-05-22 regen. | Proto-architectural leak (`Proto` suffix) | +| 3 | `jobs` | `model.ts` | `TriggerStateProto` — `Proto` suffix is a wire-format architectural leak. | Proto-architectural leak (`Proto` suffix) | | 4 | `warehouses` | `model.ts:passim` | Every `Endpoint*` type leaks the legacy "SQL Endpoints" brand into the modern "SQL Warehouses" surface. | Brand drift / rebrand leakage | | 5 | `pipelines` | `model.ts:283, 1091, 1689, 2738, 2879` | `Update` is the noun "pipeline run" — collides with HTTP `update()` verb across 9 types/methods. | Rebrand leakage (DLT → Lakeflow) | | 6 | `abacpolicies` | `model.ts:137` | `PolicyInfo` — `Info` suffix on the canonical entity. | `Info` suffix | @@ -975,227 +420,154 @@ the generator pattern it exemplifies. | 16 | `dataquality` | model.ts | `ListMonitorRequest` singular for a list-of-monitors request. | Singular/plural mismatch | | 17 | `modelserving` | `model.ts:passim` | Package says "model serving"; types say `InferenceEndpoint*`; URL says `serving-endpoints`. | Three names for one noun | | 18 | `modelserving` | `model.ts:960` | `ServedModel` actually holds non-model entities (`servedEntities: ServedModel[]`). | Type-name contradicts content | -| 19 | — | — | _Removed 2026-06-02: the `oauth` audit was deleted (its sole remaining finding was a wire-field rename, pruned in Prune pass 12)._ | Post-merge consolidation friction (retired) | -| 20 | `accessmanagement` | model.ts | After the `permissions` rename + `workspaceassignment` absorption, type-name overlap with `grants` is still present. | Cross-package fragmentation | -| 21 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | -| 22 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource, with duplicated request/enum shapes. (The shared bare-`Client` export was resolved upstream — the regen now emits `TokensClient` / `TokenManagementClient`.) | Cross-package collisions | -| 23 | — | — | _Removed 2026-06-01: the `usagepolicy` 1:1 clone of `budgetpolicy` is gone — the regen removed the `usagepolicy` package source._ | Whole-package duplicate (retired) | -| 24 | `customllms` | every file | `CustomLlm` — generic name with cryptic-acronym body. | Generic naming + cryptic abbreviation | -| 25 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | -| 26 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds. | Stringly-typed sum | -| 27 | `cleanrooms` | `client.ts:662, 704` | `listCleanRoomNotebookTaskRunsHandler` / `listCleanRoomNotebookTaskRunsHandlerIter` — `Handler` suffix proto-leak. | Proto-architectural leak (`Handler` suffix) | -| 28 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | -| 29 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types. | Generic naming | -| 30 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | -| 31 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | -| 32 | `notificationdestinations` | `model.ts:17, 13` | `Config` top-level interface; `DestinationType` vague enum. | Generic top-level name | -| 33 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | -| 34 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | -| 35 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum with 22 values mixing case styles (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Brand-value casing | -| 36 | `clusters` | `model.ts:175-734` | `TerminationCode` enum with 150+ values mixing case styles. | Brand-value casing | -| 37 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | -| 38 | — | — | _Removed 2026-06-01: the bare-`bundle` package-name collision is gone — the regen removed the `bundle` package source._ | Generic package name (retired) | -| 39 | `instancepools` | `model.ts:passim` | Structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | -| 40 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection` stutter. | Generator stutter | -| 41 | `settings` | `model.ts:passim` | Post-consolidation v2 surface carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrappers. | Generic + cryptic | -| 42 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun. | Proto-architectural leak (`Service` infix) | -| 43 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers remain in active source. Not flagged in the rescan but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | -| 44 | `marketplaces` | `model.ts:passim` | `Exchange` vs `Listing` vocabulary tension within a single package. | Vocabulary drift | -| 45 | `forecasting` | `client.ts` | `CreateForecastingExperimentWaiter` + Go-style `Waiter.done()` predicate. | Go-style waiter pattern | +| 19 | `accessmanagement` | model.ts | Type-name overlap with `grants`. | Cross-package fragmentation | +| 20 | `tokens` | `model.ts:13-21` | `AutoscopeState` duplicated verbatim in `tokenmanagement`. | Cross-package duplicate type | +| 21 | `tokens` + `tokenmanagement` | package | Two packages for one PAT resource, with duplicated request/enum shapes. | Cross-package collisions | +| 22 | `customllms` | every file | `CustomLlm` — generic name with cryptic-acronym body. | Generic naming + cryptic abbreviation | +| 23 | `supervisoragents` | `model.ts:219` | `SupervisorAgent` — two extremely generic nouns combined. | Generic naming | +| 24 | `supervisoragents` | `model.ts:251` | `Tool` — bare generic for discriminated union over 14 resource kinds. | Stringly-typed sum | +| 25 | `cleanrooms` | `client.ts:662, 704` | `listCleanRoomNotebookTaskRunsHandler` / `listCleanRoomNotebookTaskRunsHandlerIter` — `Handler` suffix proto-leak. | Proto-architectural leak (`Handler` suffix) | +| 26 | `database` + `postgres` | model.ts | Two packages, one product (Lakebase managed Postgres); `SyncedTable`/`DatabaseInstance` duplicated across both. | Duplicate package | +| 27 | `experiments` | `model.ts:219, 712` | `Run`, `Experiment`, `Metric`, `Param`, `LoggedModel` — single-word top-level types. | Generic naming | +| 28 | `repos` | `model.ts:111` | `RepoInfo` — `Info` suffix on the canonical entity; product re-branded to "Git folders". | `Info` suffix + brand drift | +| 29 | `repos` | package + types | "Repos" is legacy; product is "Git folders". | Brand drift | +| 30 | `notificationdestinations` | `model.ts:17, 13` | `Config` top-level interface; `DestinationType` vague enum. | Generic top-level name | +| 31 | `disasterrecovery` | `model.ts:91, 10` | `FailoverFailoverGroupRequest` — token "Failover" twice. | Generator stutter | +| 32 | `marketplaces` | `model.ts:passim` | `Listing` vs `ExchangeListing` vs `ListingSummary` vs `ListingDetail` — four overlapping "listing" shapes. | Duplicate concept | +| 33 | `externalmetadata` | `model.ts:10-32` | `SystemType` enum with 22 values mixing case styles (`POWER_BI`, `STREAM_NATIVE`, `POSTGRESQL`, `MICROSOFT_SQL_SERVER`). | Brand-value casing | +| 34 | `clusters` | `model.ts:175-734` | `TerminationCode` enum with 150+ values mixing case styles. | Brand-value casing | +| 35 | `lakeview` | package | Old codename; product is now "AI/BI Dashboards". | Brand drift | +| 36 | `instancepools` | `model.ts:passim` | Structural duplication of `Create*`/`Edit*`/`*AndStats`. | Duplicate concept | +| 37 | `externallineage` | `model.ts:passim` | `Direction_LineageDirection` stutter. | Generator stutter | +| 38 | `settings` | `model.ts:passim` | The v2 surface carries acronym soup (`Csp*`, `Esm*`, `Llm*`, `Dcp*`) and `BooleanMessage`/`StringMessage` wrappers. | Generic + cryptic | +| 39 | `statementexecution` | `model.ts:passim` | `ServiceErrorCode` / `ServiceError` — `Service` mid-position is a proto/gRPC architectural-layer noun. | Proto-architectural leak (`Service` infix) | +| 40 | `networking` | `model.ts:passim` | 40+ `CustomerFacing*` identifiers in active source. Not flagged but match generator rule §8.2. | Proto-architectural leak (`CustomerFacing` qualifier) | +| 41 | `marketplaces` | `model.ts:passim` | `Exchange` vs `Listing` vocabulary tension within a single package. | Vocabulary drift | +| 42 | `forecasting` | `client.ts` | Go-style `Waiter.done()` predicate on the waiter returned by the create call. | Go-style waiter pattern | --- -## 6. By-the-numbers (all 79 active packages, sorted by total findings) +## 6. By-the-numbers (all 77 active packages, sorted by total findings) Counts reflect each per-package audit's current declared total (or, for the audits that use category-numbered sections instead of an H/M/L/Obs -table, that file's own consistent finding count) after the 2026-06-02 -category-prune pass (Prune pass 13). The column sums to **712** -(verified: the 79 per-package totals add up to 712 exactly — see the -arithmetic check below the table). +table, that file's own consistent finding count). The column sums to +**479** (the 77 per-package totals add up to 479 exactly). | # | Package | Findings | Top theme | |---|---|---|---| -| 1 | jobs | 55 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | -| 2 | warehouses | 50 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | -| 3 | instancepools | 33 | Structural duplication of `Create*`/`Edit*`/`*AndStats` | -| 4 | instanceprofiles | 28 | Bare verb request types; vague identifiers | -| 5 | features | 24 | Sibling-package fragmentation (now 2 after `materializedfeatures` retirement) | -| 6 | pipelines | 20 | `Update` noun = pipeline run (DLT → Lakeflow rebrand) | -| 7 | settings | 20 | Post-consolidation v2 surface; acronym soup (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | -| 8 | statementexecution | 20 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | -| 9 | genie | 18 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | -| 10 | modelregistry | 17 | Workspace vs UC duplicate (`registeredmodels`); MLflow vocabulary | -| 11 | tables | 16 | `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | -| 12 | functions | 14 | `function` reserved-word; cryptic single-letter enum variants | -| 13 | marketplaces | 14 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | -| 14 | apps | 13 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology; `*Proto` suffix | -| 15 | budgets | 13 | Budget vs `budgetpolicy` duplication | -| 16 | catalogs | 13 | `*_OptionsEntry`/`*_PropertiesEntry`; Create-with-read-only-fields; cross-package SecurableType collisions | -| 17 | accessmanagement | 12 | Permissions/grants/rule-sets fragmentation; absorbed account access control | -| 18 | commandexecution | 12 | Three resources (Command/Context/Cluster) mixed; verb collision (`destroy`/`delete`) | -| 19 | experiments | 12 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | -| 20 | queries | 12 | Three-package overlap with `queryhistory`/`statementexecution` | -| 21 | database | 11 | Package name overlaps `postgres`; deep proto nesting | -| 22 | forecasting | 11 | Generic-named `Waiter` API; cross-package overlap with `experiments` | -| 23 | policyfamilies | 11 | "Family" + "Policy Family" mixed; underscored enums | -| 24 | modelserving | 10 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | -| 25 | featurestore | 9 | Cross-package duplicate of `database`/online-store surface | -| 26 | rfa | 9 | 3-letter cryptic package name | -| 27 | clusterlibraries | 8 | `Library.lib` field; "Full" suffix without "Partial" counterpart | -| 28 | dataquality | 8 | `ListMonitorRequest` singular for list of monitors | -| 29 | modelservingquery | 8 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | -| 30 | schemas | 8 | `_OptionsEntry`/`_PropertiesEntry`; cross-package SecurableType collisions; vs `systemschemas` | -| 31 | alerts | 7 | Mixed v1/v2 | -| 32 | logdelivery | 7 | Renamed; legacy long name fixed | -| 33 | metastores | 7 | Structural duplicate of `MetastoreInfo`; `UpdateMetastoreRequest` four name-like fields | -| 34 | usagedashboards | 7 | Vague type names | -| 35 | customllms | 6 | `Llm` cryptic-acronym usage throughout | -| 36 | disasterrecovery | 6 | `FailoverFailoverGroupRequest` stutter | -| 37 | knowledgeassistants | 6 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | -| 38 | lakeview | 6 | Old codename (rebrand to "AI/BI Dashboards") | -| 39 | registeredmodels | 6 | Cross-package overlap with `modelregistry`; `Info`-suffix entities | -| 40 | repos | 6 | "Repos" legacy term; product is "Git folders" | -| 41 | secretsuc | 6 | `uc` cryptic suffix; collides with `secrets` | -| 42 | connections | 5 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | -| 43 | entitytagassignments | 5 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | -| 44 | notificationdestinations | 5 | `Config`/`config` self-reference; `DestinationType` vague enum | -| 45 | postgres | 5 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | -| 46 | scim | 5 | Account-tier SCIM 2.0 user/group provisioning | -| 47 | secrets | 5 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | -| 48 | tagassignments | 5 | Three-package tag split | -| 49 | volumes | 5 | Verb-as-noun requests | -| 50 | artifactallowlists | 4 | Vague type names | -| 51 | clusters | 4 | 150-member `TerminationCode` brand-value casing | -| 52 | credentials | 4 | UC vs auth duplicate; `Accounts*` family | -| 53 | externalmetadata | 4 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | -| 54 | gitcredentials | 4 | Three "Credentials" packages with different meanings | -| 55 | globalinitscripts | 4 | Verb-as-noun requests; proto suffix | -| 56 | networking | 4 | Residue; ~40 active `CustomerFacing*` identifiers not yet flagged | -| 57 | queryhistory | 4 | Vague `Query` types; cross-package overlap with `queries` | -| 58 | resourcequotas | 4 | Vague type names | -| 59 | storageconfigurations | 4 | Sparse account-tier residue | -| 60 | supervisoragents | 4 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | -| 61 | systemschemas | 4 | Sibling-package collision with `schemas` | -| 62 | tokenmanagement | 4 | Overlap with `tokens`; duplicate `AutoscopeState` enum | -| 63 | vectorsearch | 4 | `Endpoint*` and `VectorIndex*` overlap | -| 64 | workspaces | 4 | Residue after `*Public*Request` regen fixes | -| 65 | budgetpolicy | 3 | Account budget-policy CRUD (its `usagepolicy` clone was removed by the regen) | -| 66 | cleanrooms | 3 | `*Handler` suffix proto-leak; misleading `accessRestricted` enum | -| 67 | clusterpolicies | 3 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | -| 68 | sharing | 3 | Account-tier Delta Sharing provider config | -| 69 | tagpolicies | 3 | Three sibling tag packages with overlapping vocab | -| 70 | tokens | 3 | Cross-package duplicate of `tokenmanagement` | -| 71 | abacpolicies | 2 | `PolicyInfo`; `MatchColumn` verb-as-noun | -| 72 | environments | 2 | `Environment` generic name | -| 73 | externallineage | 2 | `Direction_LineageDirection`; `tpe` typo | -| 74 | externallocations | 2 | Cross-cloud queue type naming (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | -| 75 | files | 2 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | -| 76 | workspacebindings | 2 | Bare verb requests | -| 77 | authentication | 1 | Account-tier token federation policies | -| 78 | grants | 1 | Verb-phrase request types | -| 79 | keyconfigurations | 1 | `ListCustomerManagedKeyRequest` singular residue | -| — | **Total** | **712** | Across all 79 active audits | - -**Arithmetic check.** Summing the 79 per-package totals gives exactly -**712**, matching the grand total. (Spot check: the top 11 packages -55 + 50 + 33 + 28 + 24 + 20 + 20 + 20 + 18 + 17 + 16 = 301; the remaining -68 packages sum to 411; 301 + 411 = 712.) The 79-finding drop from the -previously reported 791 is the 2026-06-02 category-prune pass (Prune -pass 13): three Workflow-B category prunes (field-ordering / grouping -findings, data-type-retype findings — a `string` that should be an -enum/union, a `number` that should be a `Date`/`bigint`, a `string` that -should be branded/opaque — and empty / do-nothing wrapper-deletion -findings). No audit was emptied, so the package count holds at 79. - -### Retired audits — historical reference - -The 24 audit files for packages retired in the 2026-05-20 or 2026-05-22 -regen were **deleted on 2026-05-26** (see Prune note 8, step 3). A further -four audit files were **deleted on 2026-05-28** (see Prune pass 9): `iam` -and `workspaceobjects` (orphaned — source no longer exists), -`dataclassification` (emptied by the two prunes), and `onlinetables` -(already empty). The 2026-06-01 regen then orphaned three more, **deleted -on 2026-06-01** (see Prune pass 10): `bundle`, `usagepolicy`, and -`billableusagedownload` — each lost its source package. The 2026-06-02 -combined prune pass (see Prune pass 12) then deleted one more: `oauth`, -whose sole remaining finding was a wire-field rename that the -wire-identifier-rename prune removed, leaving it with zero findings. The -audit directory now contains exactly 79 per-package files plus this -summary. The table below is preserved as a historical reference of which -packages were retired and where their findings went. - -| Retired audit (file deleted) | Successor (where applicable) | -|---|---| -| `accountaccesscontrol` | merged into `accessmanagement` | -| `accountaccesscontrolproxy` | removed (proxy package retired) | -| `accountsettings` | merged into `settings` | -| `cleanroomassets` | merged into `cleanrooms` | -| `cleanroomautoapprovalrules` | merged into `cleanrooms` | -| `cleanroomtaskruns` | merged into `cleanrooms` | -| `endpoints` | merged into `vectorsearch` | -| `indexes` | merged into `vectorsearch` | -| `logdeliveryconfigurations` | renamed to `logdelivery` | -| `materializedfeatures` | merged into `features` | -| `modelservingdebug` | merged into `modelserving` | -| `modelservingmanagement` | merged into `modelserving` | -| `oauthcustomappintegration` | merged into `oauth` | -| `oauthpublishedapp` | merged into `oauth` | -| `permissions` | renamed to `accessmanagement` | -| `qualitymonitor` | deprecated; replaced by `dataquality` | -| `qualitymonitors` | deprecated; replaced by `dataquality` | -| `queryexecution` | removed outright | -| `serviceprincipalsecrets` | removed outright | -| `serviceprincipalsecretsproxy` | removed outright (deleted before 2026-05-26) | -| `workspace` | renamed to `workspaceobjects` (audit later deleted 2026-05-28 — see below) | -| `workspaceassignment` | merged into `accessmanagement` | -| `workspaceconf` | merged into `settings` | -| `workspacesettings` | merged into `settings` | -| `iam` | deleted 2026-05-28 (orphan; domain moved to `accessmanagement`) | -| `workspaceobjects` | deleted 2026-05-28 (orphan; `/api/2.0/workspace/` filesystem service dropped from the public-filtered descriptor) | -| `dataclassification` | deleted 2026-05-28 (emptied by the `Client`-class + acronym-casing prunes) | -| `onlinetables` | deleted 2026-05-28 (already empty after the 2026-05-26 prune) | -| `bundle` | deleted 2026-06-01 (orphan; `packages/bundle/` removed by the regen) | -| `usagepolicy` | deleted 2026-06-01 (orphan; `packages/usagepolicy/` removed by the regen) | -| `billableusagedownload` | deleted 2026-06-01 (orphan; no TypeScript source after the regen) | -| `oauth` | deleted 2026-06-02 (emptied — its sole wire-field-rename finding was pruned) | +| 1 | warehouses | 25 | Legacy `Endpoint*` brand surviving the SQL-Warehouse rebrand | +| 2 | jobs | 22 | Generic enum/interface names (`Run`, `Format`, `Source`, `Compute`); `Run` overload across 7 shapes; `TriggerStateProto` proto-suffix | +| 3 | pipelines | 20 | `Update` noun = pipeline run (DLT → Lakeflow rebrand) | +| 4 | settings | 19 | Unified v2 surface; acronym soup (`Csp`/`Esm`/`Llm`/`Dcp`); `*Message` wrapper sprawl | +| 5 | statementexecution | 17 | `ServiceErrorCode` infix; package name overlaps `commandexecution`/`queries` | +| 6 | genie | 16 | Inconsistent method prefixing (28/30 with `genie*`); `GenieSpace` opaque term | +| 7 | modelregistry | 15 | Workspace vs UC duplicate (`registeredmodels`); MLflow vocabulary | +| 8 | instancepools | 8 | Structural duplication of `Create*`/`Edit*`/`*AndStats` | +| 9 | marketplaces | 13 | `Listing`/`ExchangeListing`/`ListingSummary`/`ListingDetail` overlap | +| 10 | catalogs | 6 | Create-with-read-only-fields; cross-package SecurableType collisions | +| 11 | features | 11 | Sibling-package fragmentation with `featurestore` | +| 12 | accessmanagement | 11 | Permissions/grants/rule-sets fragmentation; covers account access control | +| 13 | experiments | 11 | Single-word top-level types (`Run`, `Metric`, `Experiment`) | +| 14 | queries | 11 | Three-package overlap with `queryhistory`/`statementexecution` | +| 15 | apps | 10 | `App` vs `Application` vocabularies; `AppResourceApp_AppPermission` triple-tautology; `*Proto` suffix | +| 16 | budgets | 9 | Budget vs `budgetpolicy` duplication | +| 17 | database | 9 | Package name overlaps `postgres`; deep proto nesting | +| 18 | forecasting | 8 | `ForecastingExperiment` type-name family; Go-style `done()` waiter semantics | +| 19 | functions | 9 | `function` reserved-word; cryptic single-letter enum variants | +| 20 | modelserving | 9 | `InferenceEndpoint` vs `Endpoint` vs `serving-endpoints` terminology | +| 21 | clusterlibraries | 8 | `Library.lib` field; "Full" suffix without "Partial" counterpart | +| 22 | commandexecution | 7 | Three resources (Command/Context/Cluster) mixed; verb collision (`destroy`/`delete`) | +| 23 | metastores | 8 | Structural duplicate of `MetastoreInfo`; `UpdateMetastoreRequest` four name-like fields | +| 24 | modelservingquery | 5 | `QueryEndpointInput` has 7 mutually-exclusive input fields, no oneof | +| 25 | registeredmodels | 8 | Cross-package overlap with `modelregistry`; `Info`-suffix entities | +| 26 | schemas | 8 | `_OptionsEntry`/`_PropertiesEntry`; cross-package SecurableType collisions; vs `systemschemas` | +| 27 | tables | 6 | `TableInfo` vs `TableSummary`; cross-package `Dependency` family duplication | +| 28 | dataquality | 7 | `ListMonitorRequest` singular for list of monitors | +| 29 | rfa | 7 | 3-letter cryptic package name | +| 30 | alerts | 6 | Mixed v1/v2 | +| 31 | lakeview | 6 | Old codename (rebrand to "AI/BI Dashboards") | +| 32 | logdelivery | 6 | Account-level log delivery configs | +| 33 | repos | 5 | "Repos" legacy term; product is "Git folders" | +| 34 | usagedashboards | 6 | Vague type names | +| 35 | connections | 4 | `UNKNOWN_*` sentinels; `ConnectionType` value casing inconsistencies | +| 36 | disasterrecovery | 5 | `FailoverFailoverGroupRequest` stutter | +| 37 | instanceprofiles | 5 | Bare verb request types; vague identifiers | +| 38 | notificationdestinations | 5 | `Config`/`config` self-reference; `DestinationType` vague enum | +| 39 | postgres | 5 | Quad-nested `SyncedTable_*` shapes; cross-package duplicate of `database` | +| 40 | clusters | 4 | 150-member `TerminationCode` brand-value casing | +| 41 | featurestore | 3 | Cross-package duplicate of `database`/online-store surface | +| 42 | networking | 4 | ~40 active `CustomerFacing*` identifiers not yet flagged | +| 43 | scim | 4 | Account-tier SCIM 2.0 user/group provisioning | +| 44 | secrets | 4 | Mutation-verb inconsistency (`Put`/`Create`/`Delete`) | +| 45 | storageconfigurations | 4 | Sparse account-tier residue | +| 46 | tokenmanagement | 4 | Overlap with `tokens`; duplicate `AutoscopeState` enum | +| 47 | vectorsearch | 3 | `Endpoint*` and `VectorIndex*` overlap | +| 48 | volumes | 4 | Verb-as-noun requests | +| 49 | artifactallowlists | 3 | Vague type names | +| 50 | budgetpolicy | 3 | Account budget-policy CRUD | +| 51 | clusterpolicies | 3 | Verb-as-noun requests; `Family` vocabulary mismatch with `policyfamilies` | +| 52 | credentials | 3 | UC vs auth duplicate; `Accounts*` family | +| 53 | customllms | 3 | `Llm` cryptic-acronym usage throughout | +| 54 | entitytagassignments | 3 | `EntityTagAssignment` vs `TagAssignment` cross-package collision | +| 55 | externalmetadata | 3 | `SystemType` casing; brand-value casing (`POWER_BI`, `STREAM_NATIVE`); `V2` mid-position | +| 56 | gitcredentials | 3 | Three "Credentials" packages with different meanings | +| 57 | globalinitscripts | 3 | Verb-as-noun requests; proto suffix | +| 58 | queryhistory | 3 | Vague `Query` types; cross-package overlap with `queries` | +| 59 | resourcequotas | 2 | Vague type names | +| 60 | secretsuc | 3 | `uc` cryptic suffix; collides with `secrets` | +| 61 | sharing | 3 | Account-tier Delta Sharing provider config | +| 62 | systemschemas | 3 | Sibling-package collision with `schemas` | +| 63 | tokens | 3 | Cross-package duplicate of `tokenmanagement` | +| 64 | workspaces | 3 | Account-managed workspace CRUD | +| 65 | abacpolicies | 2 | `PolicyInfo`; `MatchColumn` verb-as-noun | +| 66 | cleanrooms | 2 | `*Handler` suffix proto-leak; misleading `accessRestricted` enum | +| 67 | environments | 2 | `Environment` generic name | +| 68 | externallineage | 2 | `Direction_LineageDirection`; `tpe` typo | +| 69 | externallocations | 2 | Cross-cloud queue type naming (`AwsSqsQueue`/`AzureQueueStorage`/`GcpPubsub`) | +| 70 | knowledgeassistants | 2 | Generic `KnowledgeAssistant`; bare `Tool`/`Resource` type names | +| 71 | supervisoragents | 2 | Generic `SupervisorAgent`; `Tool` bare type for 14-arm union | +| 72 | tagassignments | 2 | Three-package tag split | +| 73 | tagpolicies | 2 | Three sibling tag packages with overlapping vocab | +| 74 | authentication | 1 | Account-tier token federation policies | +| 75 | files | 1 | `Read`/`Move`/`Put`/`Delete` legacy DBFS verb-as-noun residue | +| 76 | keyconfigurations | 1 | `ListCustomerManagedKeyRequest` singular residue | +| 77 | workspacebindings | 1 | Bare verb requests | +| — | **Total** | **479** | Across all 77 active audits | + +**Arithmetic check.** Summing the 77 per-package totals gives exactly +**479**, matching the grand total. (Spot check: the top 11 packages +25 + 22 + 20 + 19 + 17 + 16 + 15 + 8 + 13 + 6 + 11 = 172; the remaining +66 packages sum to 307; 172 + 307 = 479.) --- ## 7. Generator-level recommendations -The previous §§8.1–8.6 recommendations have all been retired: - -- The enum-name-prefix recommendation (former §8.1) is withdrawn — see prune - note 5 (TS member names mirror the wire identifier intentionally). -- The `Info`/`Spec`/`Details` suffix recommendation (former §8.2) is an - API-team decision, not a generator template change. Field-side instances - are out of scope per the 2026-05-26 field-rename prune; type-side - instances remain cataloged in Theme 1 above. -- The acronym-casing policy recommendation (former §8.3) is **resolved** - (2026-05-28): the user fixed acronym casing on the public interface, the - per-package acronym-casing findings were pruned everywhere, and §4 below - is retained only as a historical reference. -- The `Client` rename recommendation (former §8.4) is **resolved** - (2026-06-01): deferred on 2026-05-28 (verbatim: "i will fix this - later"), it shipped at the generator level in the 2026-06-01 regen - (#167/#168), which now emits package-prefixed client classes - (`AccessManagementClient`, `FeaturesClient`, `CredentialsClient`, - `JobsClient`, `WarehousesClient`, …) instead of a bare `Client`. See - Prune pass 10 above. -- The `Request` suffix recommendation (former §8.5) is **Done**: every - request DTO is now emitted with a `Request` suffix. -- The strip-package-name-prefix recommendation (former §8.6) is **withdrawn** - per prune-pass 7 (2026-05-22): the package-name prefix is now considered - intentional. Neither a generator change nor an API-team rename is planned. +Several earlier recommendations are no longer active: + +- The enum-name-prefix recommendation is withdrawn — TS member names mirror + the wire identifier intentionally. +- The `Info`/`Spec`/`Details` suffix recommendation is an API-team + decision, not a generator template change. Field-side instances are out + of scope; type-side instances are cataloged in Theme 1 above. +- The acronym-casing policy recommendation is resolved; §4 below is + retained for reference. +- The `Client` rename recommendation is resolved — the generator emits + package-prefixed client classes (`AccessManagementClient`, + `FeaturesClient`, `CredentialsClient`, `JobsClient`, `WarehousesClient`, + …) instead of a bare `Client`. +- The `Request` suffix recommendation is done — every request DTO is + emitted with a `Request` suffix. +- The strip-package-name-prefix recommendation is withdrawn — the + package-name prefix is considered intentional. ### 7.1 Surface deprecations as `@deprecated` JSDoc tags (deferred) Fields whose JSDoc text says "deprecated" in prose but does not carry the `@deprecated` tag (so IDEs do not strike them through). This is a -doc-only template change; it is out of the current naming-audit corpus -per the 2026-05-26 doc-change prune ("those can be anytime"). Retained -here as a follow-up note rather than an open finding. +doc-only template change and is out of the current naming-audit corpus. +Retained here as a follow-up note rather than an open finding. --- @@ -1203,9 +575,8 @@ here as a follow-up note rather than an open finding. The following recommendations are template-level fixes that the generator emits identically across every package. Rather than carry the -same finding in 79 per-package audits, each rule is recorded once here. -Each item names the rule, why it is generator-only, the approximate -package count it appeared in before promotion, and an illustrative +same finding in 77 per-package audits, each rule is recorded once here. +Each item names the rule, why it is generator-only, and an illustrative example. ### 8.1 Drop the duplicate `list*Iter()` paginator method @@ -1219,9 +590,6 @@ Octokit, Azure SDK, AWS SDK v3. every generated package; the fix is one template change, not per-package work. -**Approximate package count where it appeared before pruning:** ~57/87 -packages (every package that has a paginating list endpoint). - **Illustrative example:** `listCatalogsIter` in `catalogs/v1/client.ts` (and parallel methods in `vectorsearch`, `warehouses`, `jobs`, etc.). @@ -1235,9 +603,8 @@ domain word), `Backend`, `Manager`, `Handler`, `Impl`, `Rpc`, `Grpc`, `Wrapper`, `CustomerFacing`, and mid-position version markers like `V2`/`V3`. -JSDoc banner comments are out of scope per the 2026-05-26 doc-change -prune; SDK-internal identifiers (`utils.ts` schema helpers, etc.) are -out of scope per the 2026-05-26 SDK-internal prune. The rule covers +JSDoc banner comments are out of scope; SDK-internal identifiers +(`utils.ts` schema helpers, etc.) are out of scope. The rule covers the public exported surface only. **Why it's generator-only:** The TS SDK exports exactly one tier @@ -1246,16 +613,12 @@ proto definition and have no caller-side meaning. The same template emits them across every account-tier package, so a single template fix replaces hundreds of per-package findings. -**Status (2026-05-26):** The `*Public*Request` sub-pattern has shipped -across every account-tier package via the 2026-05-22 generator regen. -This is a retroactive validation of the rule. The rule remains open -because the following public-surface instances survive: +**Remaining instances on the public surface (~8/77 packages):** -- `CustomerFacing*` qualifier is **still emitted** in `networking` - (40+ active identifiers in `model.ts`, e.g. - `CustomerFacingIngressNetworkPolicy`, `CustomerFacingVpcEndpointUseCase`). - Not yet flagged in the rescan — should land in a follow-up pass. -- `*Proto` suffix survives on a handful of public types: +- `CustomerFacing*` qualifier in `networking` (40+ active identifiers + in `model.ts`, e.g. `CustomerFacingIngressNetworkPolicy`, + `CustomerFacingVpcEndpointUseCase`). Not yet flagged. +- `*Proto` suffix on a handful of public types: `TriggerStateProto` (`jobs`), `DatabricksServiceExceptionProto` (`apps`), `DatabricksServiceExceptionWithDetailsProto` (`apps`). - `*Service*` mid-position infix in `statementexecution` @@ -1264,57 +627,39 @@ because the following public-surface instances survive: `listCleanRoomNotebookTaskRunsHandler` and its `*Iter` companion. - Mid-position `V` in `jobs` (`RunLifecycleStateV2`). -**Approximate package count where it appears today:** ~8/79 packages -on the exported surface. - -**Illustrative example (pre-regen):** +**Illustrative example:** `CreateNetworkConnectivityConfigPublicRequest` → -`CreateNetworkConnectivityConfigRequest`. The 2026-05-22 regen -shipped this rename; the remaining gap is the `CustomerFacing*` -qualifier and the `*Proto`/`*Service*`/`*Handler`/`V` tails. +`CreateNetworkConnectivityConfigRequest`. --- ## Appendix: Categories (from the per-package audits) -The audits used a shared 20-category rubric. Several categories have been -retired as cross-cutting themes via prune passes: Category 2 "Redundant -enum prefix" (prune note 5), Category 11 "Empty / trivial wrapper types" -(prune note 1), Category 4 "Underscores in TS identifiers" (prune note -4), and Category 3 "Acronym casing" (resolved 2026-05-28 — Prune pass 9). -A new category was added in the 2026-05-20 proto-architectural-leak -scan (audit-pass note 7): "Proto-architectural leak" — mid-position -proto/service-tier infixes; the 2026-05-22 regen moved most of its -`*Public*Request` cases to `Fixed`. +The audits use a shared 20-category rubric. Several categories are not +active as cross-cutting themes: Category 2 "Redundant enum prefix", +Category 11 "Empty / trivial wrapper types", Category 4 "Underscores in TS +identifiers", and Category 3 "Acronym casing". A "Proto-architectural +leak" category covers mid-position proto/service-tier infixes. -The 2026-05-26 prune pass narrowed the rubric significantly: +The rubric is scoped as follows: - **Category 15 "Generic field names losing meaning"** and **Category 19 - "Underspecified IDs"** are now out of scope — both boil down to field - renames (field-rename prune). + "Underspecified IDs"** are out of scope — both boil down to field + renames. - **Category 14 "Go / Java-style names"** field-name instances (`req`, `resp`, local var names) are out of scope — they are SDK-internal - identifiers (SDK-internal prune). -- **Category 16 "Field contradicting type domain"** is significantly - reduced — field-side instances are out (field-rename prune); only - type-name-vs-content contradictions remain (e.g. - `ServedModel.servedEntities`). + identifiers. +- **Category 16 "Field contradicting type domain"** is reduced — + field-side instances are out of scope; only type-name-vs-content + contradictions are flagged (e.g. `ServedModel.servedEntities`). - JSDoc-only findings (banner comments, "deprecated in prose without - @deprecated tag") are out of scope across all categories - (doc-change prune). - -The 2026-05-28 prune pass narrowed the rubric further: - -- **Category 3 "Acronym casing"** is **resolved / retired** — the user - fixed acronym casing on the public interface and the findings were - pruned from every package. + @deprecated tag") are out of scope across all categories. +- **Category 3 "Acronym casing"** is resolved. - The **generic top-level `Client` class-name** finding (a Category 1 / - 12 sub-case) was pruned from every package and deferred by the user on - 2026-05-28; it is now **resolved** upstream — the 2026-06-01 regen - (#167/#168) emits `Client` names. See Prune pass 10. + 12 sub-case) is resolved — the generator emits `Client` names. -The most-cited remaining categories on the type-level surface across -all 79 active audits: +The most-cited categories on the type-level surface across all 77 active +audits: | # | Category | Surviving on type level | |---|---|---| diff --git a/.agent/naming-audit/abacpolicies.md b/.agent/naming-audit/abacpolicies.md index 22c28a9f..d7046520 100644 --- a/.agent/naming-audit/abacpolicies.md +++ b/.agent/naming-audit/abacpolicies.md @@ -11,13 +11,13 @@ ## High severity -### 1. `PolicyInfo` — `src/v1/model.ts:136` +### 1. `PolicyInfo` — `src/v1/model.ts:144` - **Why weird:** `Info` is a generic suffix that adds nothing — every type is "info about something". This is the central domain entity; it should just be called `Policy`. (See rule 1: `Info` is on the vague-suffix list.) - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix). - **Suggested name:** `Policy`. - **Rationale:** `Policy` is the noun the user actually thinks about. The `Info` suffix is a tic carried over from Go SDK naming conventions that does not apply in TS, where the namespace and import path already disambiguate. -### 2. `MatchColumn` — `src/v1/model.ts:129` +### 2. `MatchColumn` — `src/v1/model.ts:137` - **Why weird:** Reads as a verb (`MatchColumn`) — could be a method or a type. The field that uses it is plural (`matchColumns: MatchColumn[]`), which then reads as "match columns are an array of `MatchColumn`", and a `MatchColumn` is actually a "column matcher / condition + alias pair". - **Category:** 6 (misleading verb-as-noun), 9 (singular noun whose meaning is unclear). - **Suggested name:** `ColumnMatcher` or `ColumnMatchCondition`. diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md index 9c012c1d..5651725d 100644 --- a/.agent/naming-audit/accessmanagement.md +++ b/.agent/naming-audit/accessmanagement.md @@ -2,7 +2,7 @@ **Path:** `packages/accessmanagement/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 12 +**Total weird names flagged:** 11 ## Summary | Severity | Count | @@ -10,13 +10,13 @@ | High | 3 | | Medium | 5 | | Low | 2 | -| Observation | 2 | +| Observation | 1 | --- ## High severity -### 1. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:17,18,26` +### 1. `CAN_MANAGE_STAGING_VERSIONS` / `CAN_MANAGE_PRODUCTION_VERSIONS` / `CAN_CREATE_APP` — `src/v1/model.ts:18,19,27` - **Why weird:** Three values are specific to one object type each (`registered-models` in MLflow Model Registry, and Databricks Apps), but live in a universal `PermissionLevel` enum applicable to 25+ object @@ -34,7 +34,7 @@ discoverability hazard; users browsing autocomplete will see these as valid choices for clusters, jobs, and dashboards. -### 2. `RequestAuthzIdentity` enum name — `Request` prefix and `Authz` truncation — `src/v1/model.ts:33-37` +### 2. `RequestAuthzIdentity` enum name — `Request` prefix and `Authz` truncation — `src/v1/model.ts:38-46` - **Why weird:** The type name starts with `Request` — a wire-format message prefix (`RequestAuthzIdentity` reads as "the AuthzIdentity field on a request message"). The mid-name truncation `Authz` (instead of @@ -50,16 +50,16 @@ containing `CheckPolicyRequest`. The `Authz` truncation is fine in code comments but jars on a public, exported enum. -### 3. `getRuleSetProxy`, `listAssignableRolesForResourceProxy`, `updateRuleSetProxy` — `src/v1/client.ts:257,331,397` +### 3. `getRuleSetProxy`, `listAssignableRolesForResourceProxy`, `updateRuleSetProxy` — `src/v1/client.ts:257,333,401` - **Why weird:** Three methods carry the `Proxy` suffix and are - byte-for-byte identical to their non-`Proxy` siblings (lines 220, 294, - 368). They issue the same HTTP request to the same URL with the same + byte-for-byte identical to their non-`Proxy` siblings (lines 219, 295, + 371). They issue the same HTTP request to the same URL with the same headers. The `Proxy` suffix communicates an architectural concept — these are the same operation routed through a proxy server in the Databricks control plane — that has zero meaning for a TypeScript SDK - caller. The same finding triggered the prior - `accountaccesscontrolproxy` package removal; the duplicate-method - echo of it now lives inside this package. + caller. The `Proxy` variants are the operations of the formerly + separate `accountaccesscontrolproxy` service, folded into this + package as duplicate methods. - **Category:** Proto-architectural / backend-routing leak; duplicate concept exposed twice. - **Suggested name:** Delete the `*Proxy` variants entirely. If the @@ -73,7 +73,7 @@ ## Medium severity -### 4. `ListAssignableRolesForResource*` "ForResource" verbosity — `src/v1/model.ts:194,210`, `src/v1/client.ts:294` +### 4. `ListAssignableRolesForResource*` "ForResource" verbosity — `src/v1/model.ts:207,223`, `src/v1/client.ts:295` - **Why weird:** 38-character type names (`ListAssignableRolesForResourceRequest` / `ListAssignableRolesForResourceResponse`). The "ForResource" suffix is @@ -88,7 +88,7 @@ REST semantics; only the redundant "ForResource" qualifier remains. A shorter name is just as unambiguous. -### 5. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:247,265,380` +### 5. `PermissionOutput`, `PrincipalOutput`, `WorkspacePermissionAssignmentOutput` `Output` suffix — `src/v1/model.ts:260,278,393` - **Why weird:** Three types ending with `Output`. In proto / gRPC service definitions, message types are commonly named `FooInput` (request) and `FooOutput` (response) — the `Output` suffix is the @@ -104,7 +104,7 @@ - **Rationale:** Compare `principal: PrincipalOutput` to `principal: Principal` — the latter reads as plain English. -### 6. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:241` +### 6. `Permission` type collides with the broader vocabulary — `src/v1/model.ts:254` - **Why weird:** Top-level type called `Permission` with three fields: `permissionLevel`, `inherited`, `inheritedFromObject`. Every instance is really an "effective permission" — a permission level paired with @@ -121,7 +121,7 @@ common across IAM systems that it's nearly content-free without qualification. -### 7. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:253` +### 7. `PermissionsDescription` plural for a single-level descriptor — `src/v1/model.ts:266` - **Why weird:** Type carries `permissionLevel?: PermissionLevel` (singular) and `description?: string`. The plural `Permissions` in the type name is wrong: each instance describes ONE level. @@ -130,7 +130,7 @@ `PermissionLevelInfo`. - **Rationale:** One descriptor = one level; the type name should match. -### 8. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:258` +### 8. `PermissionsResponse` is a returned ACL, not a "Response" type — `src/v1/model.ts:271` - **Why weird:** Returned from three different operations (`getObjectPermissions`, `setObjectPermissions`, `updateObjectPermissions`). The type carries `objectId`, `objectType`, @@ -147,9 +147,9 @@ ## Low severity -### 9. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:511,527` +### 9. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:519,536` - **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` - (line 527). The request type `UpdateObjectPermissionsRequest` is + (line 536). The request type `UpdateObjectPermissionsRequest` is symmetric in name to `SetObjectPermissionsRequest` (PUT) — but the semantics differ: PUT replaces, PATCH merges. The naming gives no hint of this. @@ -159,7 +159,7 @@ - **Rationale:** Method verbs should hint at HTTP semantics; `set` vs `update` is ambiguous when both exist on the same resource. -### 10. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:157` +### 10. `listWorkspacePermissions` returns a static catalog — `src/v1/client.ts:154` - **Why weird:** Method `listWorkspacePermissions` returns the catalog of `PermissionOutput` values supported (USER/ADMIN), not user data. Sits side-by-side with `listWorkspacePermissionAssignments` @@ -174,14 +174,7 @@ ## Observations -### O1. `error?: string` on `WorkspacePermissionAssignmentOutput` — `src/v1/model.ts:386` -- Embedding an opaque error string inside the success response body is - unusual; typical SDK design surfaces errors as exceptions or as a - typed error union. A caller has to inspect a per-row `error` field to - discover that an otherwise-successful response carries a partial - failure. - -### O2. Single class composes four formerly-distinct services — `src/v1/client.ts:68` +### O1. Single class composes four formerly-distinct services — `src/v1/client.ts:68` - The `AccessManagementClient` class composes 15 methods that previously lived across four packages. Three operational clusters (workspace-object-permissions, account-level rule sets, diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md index 0a76ad22..b11acb9c 100644 --- a/.agent/naming-audit/alerts.md +++ b/.agent/naming-audit/alerts.md @@ -2,7 +2,7 @@ **Path:** `packages/alerts/src/{v1,v2}/` **Versions audited:** v1, v2 -**Total weird names flagged:** 7 (rescan on 2026-05-28; wire-identifier renames pruned on 2026-06-02) +**Total weird names flagged:** 6 ## Summary table @@ -10,36 +10,35 @@ |---|----------|---------|----------|------|----------| | 1 | High | v2 | `model.ts` enum | `Aggregation` | Vague/generic, no domain prefix | | 2 | High | v2 | `model.ts` interface | `AlertRunAs` | Verb-as-noun, reserved-word-feel | -| 3 | High | v2 | `model.ts` field | `Alert.queryText` | Field contradicts type domain (alert holds raw SQL) | -| 4 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | -| 5 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | -| 6 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | -| 7 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | +| 3 | Medium | both | `client.ts` method | `trashAlert` | Inconsistent action verb (mixes with `delete`) | +| 4 | Medium | both | `model.ts` type | `TrashAlertRequest` | Inconsistent verb (rest of SDK uses `Delete`) | +| 5 | Medium | v2 | `model.ts` interface | `CronSchedule` | Generic/global name in domain package | +| 6 | Low | v1 | `model.ts` enum | `LifecycleState` | Missing domain prefix (v2 fixes to `AlertLifecycleState`) | ## High severity ### 1. `Aggregation` — vague/generic top-level name (v2) -**Location:** `src/v2/model.ts:8-17` +**Location:** `src/v2/model.ts:9-21` ```ts -export enum Aggregation { - SUM = 'SUM', - COUNT = 'COUNT', - COUNT_DISTINCT = 'COUNT_DISTINCT', - AVG = 'AVG', - MEDIAN = 'MEDIAN', - MIN = 'MIN', - MAX = 'MAX', - STDDEV = 'STDDEV', -} +export const Aggregation = { + SUM: 'SUM', + COUNT: 'COUNT', + COUNT_DISTINCT: 'COUNT_DISTINCT', + AVG: 'AVG', + MEDIAN: 'MEDIAN', + MIN: 'MIN', + MAX: 'MAX', + STDDEV: 'STDDEV', +} as const; ``` Exported at the package root without an `Alert` or `Column` prefix. The same word is overloaded across SQL, stats, monitoring, and ML domains. `AlertOperandAggregation` or `ColumnAggregation` would be unambiguous. ### 2. `AlertRunAs` — verb-as-noun (v2) -**Location:** `src/v2/model.ts:155-168` +**Location:** `src/v2/model.ts:175-188` ```ts export interface AlertRunAs { @@ -52,22 +51,11 @@ export interface AlertRunAs { `RunAs` is an imperative verb phrase used as a type name. `AlertIdentity`, `AlertRunner`, or `RunAsIdentity` would parse as nouns. Also note: the *field* inside is named `identity` — a clearer type name would let the field name be more specific (or vice versa). -### 3. `Alert.queryText` — field contradicts type domain (v2) - -**Location:** `src/v2/model.ts:68-69` - -```ts -/** Text of the query to be run. */ -queryText?: string | undefined; -``` - -A type named `Alert` carrying a raw SQL string makes the alert object responsible for storage of its query — a v1→v2 change that conflates the alert configuration with the query content. v1 cleanly held `queryId` (FK to a Query resource). The name itself is fine; the placement on `Alert` is the smell. - ## Medium severity -### 4. `trashAlert` — inconsistent action verb (both) +### 3. `trashAlert` — inconsistent action verb (both) -**Location:** `src/v1/client.ts:180-206`; `src/v2/client.ts:178-210` +**Location:** `src/v1/client.ts:183-209`; `src/v2/client.ts:181-213` ```ts /** Moves an alert to the trash. ... A trashed alert is permanently deleted after 30 days. */ @@ -76,22 +64,22 @@ async trashAlert(...) { ... DELETE ... } The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but the method is `trashAlert`. Across the SDK this is the only place where soft-delete uses `trash`-prefix. Most resources use `deleteX` (and the v2 enum value is `AlertLifecycleState.DELETED`, not `TRASHED`). -### 5. `TrashAlertRequest` — same as 4, in the type layer (both) +### 4. `TrashAlertRequest` — same as 3, in the type layer (both) -**Location:** `src/v1/model.ts:187-189`; `src/v2/model.ts:218-222` +**Location:** `src/v1/model.ts:199-201`; `src/v2/model.ts:238-242` Same verb inconsistency at the type layer. -### 6. `CronSchedule` — generic name in a single-domain package (v2) +### 5. `CronSchedule` — generic name in a single-domain package (v2) -**Location:** `src/v2/model.ts:181-195` +**Location:** `src/v2/model.ts:201-215` A top-level type called `CronSchedule` in a package whose only consumer is alerts. If/when another package wants its own cron schedule shape, the user has two `CronSchedule`s. `AlertSchedule` would domain-prefix consistently with the rest of v2. ## Low severity -### 7. `LifecycleState` — missing domain prefix (v1) +### 6. `LifecycleState` — missing domain prefix (v1) -**Location:** `src/v1/model.ts:24-27` +**Location:** `src/v1/model.ts:33-39` v1 exports a global-looking `LifecycleState`. v2 corrects this to `AlertLifecycleState`. diff --git a/.agent/naming-audit/apps.md b/.agent/naming-audit/apps.md index 878b781d..c25cc5cd 100644 --- a/.agent/naming-audit/apps.md +++ b/.agent/naming-audit/apps.md @@ -9,15 +9,15 @@ | -------- | ----- | | Medium | 6 | | Low | 2 | -| Observation | 5 | -| **Total** | **13** | +| Observation | 2 | +| **Total** | **10** | --- ## Medium-severity findings ### M1. `EnvVar` — too short -- **File:** `model.ts:1116`, also `index.ts:85` +- **File:** `model.ts:1229`, also `index.ts:85` - **Category:** Cryptic abbreviations (5) - **Issue:** `EnvVar` reads as Go-style. Full TS conventions prefer `EnvironmentVariable` or, since it carries both name and source, more @@ -29,19 +29,19 @@ strict 1:1 with Go names, leave as-is. ### M2. `AsyncUpdateAppRequest.appName` carrying a redundant nesting -- **File:** `model.ts:1037-1041` +- **File:** `model.ts:1150-1154` - **Category:** Redundant suffixes (8) - **Issue:** `AsyncUpdateAppRequest` already contains an `app: App` field, and separately an `appName: string` field that's just `req.app.name`. This is visible at `client.ts:127`: `${this.host}/api/2.0/apps/${req.appName ?? ''}` with no consultation of `req.app?.name`. - **Suggestion:** Drop `appName` from `AsyncUpdateAppRequest` and read - `req.app?.name` (as `updateApp` already does at `client.ts:902`). This is a + `req.app?.name` (as `updateApp` already does at `client.ts:927`). This is a semantic change; flag for discussion. Alternative: keep both and document which wins on conflict. ### M3. `UnityCatalog` interface — generic name, no role suffix -- **File:** `model.ts:1391-1398`, also `index.ts:110` +- **File:** `model.ts:1504-1511`, also `index.ts:110` - **Category:** Vague/generic (1) - **Issue:** `UnityCatalog` is exported as a public type. The interface has three table-name fields (`logsTable`, `metricsTable`, `tracesTable`) and is @@ -52,10 +52,10 @@ `UnityCatalogTables`. Inline if not reused. ### M4. `Operation.result` carries `error` and `response` arms -- **File:** `model.ts:1300-1311` +- **File:** `model.ts:1413-1424` - **Category:** Vague/generic (1) - **Issue:** The `response` arm holds `Record` — a totally - untyped payload. The consumer at `client.ts:1095` immediately re-parses it + untyped payload. The consumer at `client.ts:1128` immediately re-parses it through `unmarshalSpaceSchema`. The name `response` and the unknown type conceal what's actually inside. - **Suggestion:** Use generics: `Operation` with `result: ... | @@ -64,7 +64,7 @@ promises nothing. ### M5. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too -- **File:** `client.ts:123, 985` +- **File:** `client.ts:122, 1012` - **Category:** Inconsistent action verbs (17), Verb-tense inconsistency (13) - **Issue:** Both `asyncUpdateApp` and `updateSpace` are asynchronous, long-running operations that return an `AppUpdate`/`Operation` and have a @@ -75,7 +75,7 @@ `updateSpace`, or add `asyncUpdateSpace` for symmetry. ### M6. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type -- **File:** `client.ts:317, 428, 1025` +- **File:** `client.ts:321, 438, 1053` - **Category:** Type-suffix tautology (20) - **Issue:** Methods named `createSpaceOperation()` return a `CreateSpaceOperation` wrapper (not an `Operation` directly). A reader @@ -90,7 +90,7 @@ ## Low-severity findings ### L1. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers -- **File:** `model.ts:2964, 3041` +- **File:** `model.ts:3041, 3119` - **Category:** Vague/generic (1) — qualified by entity, but - **Issue:** Inconsistent that only `App` and `Space` get an exported helper — no `appDeploymentFieldMask`, despite the `AppDeployment` having an internal @@ -99,7 +99,7 @@ schema, or none. ### L2. `getSpaceOperation` (method) vs `GetOperationRequest` -- **File:** `client.ts:571-596` +- **File:** `client.ts:588-614` - **Category:** Type-suffix tautology (20) - **Issue:** `getSpaceOperation(req: GetOperationRequest)` — the method tells you it's a space operation, but the request type doesn't. Mismatch. @@ -121,25 +121,7 @@ The two flavours are confusing as named. Consider renaming `*Operation` -> `*LongRunning` so the difference (LRO vs status-poll) is visible. -### O2. Field-mask helpers exist for `App` and `Space` only -`appFieldMask()` and `spaceFieldMask()` are exported; equivalents for -`AppDeployment` etc. are not. Probably intentional (only `App` and `Space` -have an update endpoint that takes a mask), but worth confirming. - -### O3. `CustomTemplate` doesn't carry "App" in its name, but it's an app template +### O2. `CustomTemplate` doesn't carry "App" in its name, but it's an app template The doc and methods make this clear (`createCustomTemplate` -> `/api/2.0/apps-settings/templates`), but the type name is ambiguous. Consider `AppTemplate` or `CustomAppTemplate`. - -### O4. `ListSpacesRequest` doesn't take a `space` filter the way `ListAppsRequest` takes a `space` filter -Asymmetry but probably intentional. - -### O5. `index.ts` exports -- 27 enums -- 69 type aliases -- 9 named exports from `./client` (1 class + 8 wrapper classes) - -That's 105 top-level exports, plus the two field-mask helper functions -(`appFieldMask`, `spaceFieldMask`). Worth checking whether the wrapper classes -(`*Operation`, `*Waiter`) need to be public or if they're implementation -detail. diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md index fe0a34ea..70b68808 100644 --- a/.agent/naming-audit/artifactallowlists.md +++ b/.agent/naming-audit/artifactallowlists.md @@ -1,17 +1,16 @@ # Naming Audit: `artifactallowlists` (v1) -Package path: `/home/parth.bansal/sdk-js/packages/artifactallowlists/` +Package path: `/home/parth.bansal/sdk-js/packages/uc/artifactallowlists/` Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/transport.ts`, `src/v1/index.ts`. ## Summary -| Severity | Count | -| ----------- | ----- | -| High | 1 | -| Medium | 2 | -| Observation | 1 | -| **Total** | **4** | +| Severity | Count | +| --------- | ----- | +| High | 1 | +| Medium | 2 | +| **Total** | **3** | --- @@ -19,8 +18,8 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### H1. `SetArtifactAllowlistRequest` carries server-derived fields on a request type -- **File / line:** `src/v1/model.ts:44–55` (`createdBy` at 52, `createdAt` - at 54). +- **File / line:** `src/v1/model.ts:52–63` (`createdBy` at 60, `createdAt` + at 62). - **Category:** #16 field contradicting type domain. - **Current:** Fields `createdBy?: string` and `createdAt?: bigint` are present on what is documented as the SET payload — these are server-set @@ -39,7 +38,7 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### M1. `ArtifactAllowlistInfo` — redundant `Info` suffix -- **File / line:** `src/v1/model.ts:21`. +- **File / line:** `src/v1/model.ts:29`. - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `ArtifactAllowlistInfo`. - **Suggestion:** `ArtifactAllowlist`. @@ -54,7 +53,7 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### M2. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak -- **File / line:** `src/v1/model.ts:15`. +- **File / line:** `src/v1/model.ts:19` (const), `model.ts:25` (type). - **Category:** proto-architectural-leak — `Proto` infix / nested-enum underscore. - **Current:** `ArtifactMatcher_MatchType` (with an inline @@ -68,13 +67,3 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, the codebase already disables its own naming-convention lint rule to let this through. The identifier leaks the proto/IDL layer into the public surface of the package. - ---- - -## Observations (Repo-wide conventions, not local defects) - -### O1. `…Info` suffix repeated across UC types - -`ArtifactAllowlistInfo` follows the `CatalogInfo`, `ConnectionInfo`, -`FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the -codebase decides to drop the `Info` suffix, this is one of many to fix. diff --git a/.agent/naming-audit/authentication.md b/.agent/naming-audit/authentication.md index ce802d87..ac3a0c6e 100644 --- a/.agent/naming-audit/authentication.md +++ b/.agent/naming-audit/authentication.md @@ -16,7 +16,7 @@ ## High severity (must fix) -### 1. `*Proxy` method variants duplicate the entire API surface — `client.ts:488, 548, 630, 666` +### 1. `*Proxy` method variants duplicate the entire API surface — `client.ts:499, 561, 645, 682` - **Why:** The class exposes three real operations (`createServicePrincipalSecret`, `deleteServicePrincipalSecret`, `listServicePrincipalSecrets`) and, for every one of them, a diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md index 7cd3bd19..9cab4ddd 100644 --- a/.agent/naming-audit/budgetpolicy.md +++ b/.agent/naming-audit/budgetpolicy.md @@ -12,7 +12,7 @@ ## High severity -### 1. `Filter` (bare top-level type) — `src/v1/model.ts:75` +### 1. `Filter` (bare top-level type) — `src/v1/model.ts:79` - **Why weird:** Re-exported from `index.ts` as a bare top-level type. `Filter` is one of the most overloaded words in JS/TS (Array#filter, RxJS filter, content filters, etc.) and the type is package-scoped, so the name carries no hint of what it filters. - **Category:** 1 (vague/generic). - **Suggested name:** `BudgetPolicyFilter` (mirror `BudgetConfigurationFilter` in the `budgets` package). @@ -20,7 +20,7 @@ ## Medium severity -### 1. `SortSpec` type — `src/v1/model.ts:147` +### 1. `SortSpec` type — `src/v1/model.ts:151` - **Why weird:** `Spec` is a generic suffix — every type is a spec of something. The suffix communicates nothing about what kind of specification this is or how it differs from a plain options bag. - **Category:** 1 (vague suffix `Spec`). - **Suggested name:** `SortOptions` or `SortOrder`. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md index 3008744d..606a85f3 100644 --- a/.agent/naming-audit/budgets.md +++ b/.agent/naming-audit/budgets.md @@ -15,7 +15,7 @@ ### 1. Vague / generic names #### F1.1 — `ActionConfiguration` / `actionConfigurationId` / `actionType` (HIGH) -- **Where:** `model.ts:27-34`, `index.ts:14`. +- **Where:** `model.ts:47-54`, `index.ts:14`. - **Why flagged:** "Action" is one of the most generic nouns in software. Combined with "Configuration", it gives almost no clue about what the user is configuring. In context this type is @@ -26,47 +26,30 @@ delivery method. - **Suggestion:** Rename to `BudgetAlertAction` (or `BudgetNotificationAction`). The `Configuration` suffix is dead - weight here (see also F3). If the type *must* keep the "Config" - word, `BudgetAlertActionConfig` is shorter and clearer. - -#### F1.2 — `req` parameter name on every client method (LOW) -- **Where:** `client.ts:77, 109, 137, 171, 213, 231`. -- **Why flagged:** `req` is a Go-ism (see category 4). It is also - generic — a reader has to look at the type to know what the - request is. -- **Suggestion:** Use a domain-meaningful parameter name: - `createBudgetConfiguration(budgetToCreate)` or simply `request` - for stylistic consistency with `options`. + weight here (see also F2.1 and F2.2). If the type *must* keep the + "Config" word, `BudgetAlertActionConfig` is shorter and clearer. --- -### 2. Cryptic abbreviations +### 2. Overly verbose -#### F2.1 — `req` (LOW, Go-ism) -- **Where:** `client.ts` every method. -- Already flagged under F1.2. - ---- - -### 3. Overly verbose - -#### F3.1 — `BudgetConfiguration` (HIGH) -- **Where:** `model.ts:51`. +#### F2.1 — `BudgetConfiguration` (HIGH) +- **Where:** `model.ts:71`. - **Why flagged:** Within a package literally named `budgets`, every type is about budgets. The "Configuration" suffix doesn't add signal — a budget IS a configuration on the account. Compare Go's `budgets.Budget` (typical Go SDK convention). - **Suggestion:** Rename to `Budget`. Users would write `import {Budget} from '@databricks/sdk-budgets'`. The - package name carries the qualifier. Combined with F3.2 this + package name carries the qualifier. Combined with F2.2 this collapses naming significantly. -#### F3.2 — `CreateBudgetConfigurationRequest`, +#### F2.2 — `CreateBudgetConfigurationRequest`, `GetBudgetConfigurationRequest`, `UpdateBudgetConfigurationRequest`, `DeleteBudgetConfigurationRequest`, `ListBudgetConfigurationsRequest` (HIGH) -- **Where:** `model.ts:119, 143, 193, 133, 155`; `index.ts:22-31`. +- **Where:** `model.ts:139, 163, 213, 153, 175`; `index.ts:22-31`. - **Why flagged:** Long request type names. Combined with method names that already say `createBudgetConfiguration(...)`, the argument type is highly redundant. Compare typical TS SDK @@ -77,27 +60,19 @@ --- -### 4. Generic field names losing meaning - -#### F4.1 — `req` parameter on every client method (HIGH) -- See F1.2. - ---- - ## Summary table | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Vague / generic | 2 | -| 2 | Cryptic abbreviations | 1 | -| 3 | Overly verbose | 2 | -| 4 | Generic field names | 1 | +| 1 | Vague / generic | 1 | +| 2 | Overly verbose | 2 | +| — | Proto / architectural leaks | 6 | --- ## Proto / Architectural Leaks -### 1. `BudgetConfiguration` — model.ts:51 +### 1. `BudgetConfiguration` — model.ts:71 - **Why:** Repeated `Configuration` token threaded through nearly every type in the package (`BudgetConfiguration`, `BudgetConfigurationFilter`, @@ -113,20 +88,20 @@ - **Rationale:** A budget is the domain noun; "configuration" is a proto naming convention bleeding through. -### 2. `AlertConfiguration` / `AlertConfigurationType` / - `AlertConfigurationQuantityType` / `AlertConfigurationTimePeriod` / - `AlertConfigurationTriggerType` — model.ts:10, 14, 18, 36 +### 2. `AlertConfiguration` / `AlertConfigurationQuantityType` / + `AlertConfigurationTimePeriod` / `AlertConfigurationTriggerType` + — model.ts:56, 15, 23, 31 - **Why:** Same `Configuration` proto suffix repeated on the alert domain (and on every alert-related enum). The alert *is* a configuration, so the suffix is redundant. - **Category:** Proto leak — repeated `Config`/`Configuration` suffix. -- **Suggested:** `Alert`, `AlertType`, `AlertQuantityType`, +- **Suggested:** `Alert`, `AlertQuantityType`, `AlertTimePeriod`, `AlertTriggerType`. - **Rationale:** Drop `Configuration` — it's a proto-message-name artifact. -### 3. `ActionConfiguration` / `ActionConfigurationType` — model.ts:6, 27 +### 3. `ActionConfiguration` / `ActionConfigurationType` — model.ts:47, 7 - **Why:** Repeated `Configuration` proto suffix on the action domain. - **Category:** Proto leak — repeated `Config`/`Configuration` suffix. @@ -137,7 +112,7 @@ `BudgetConfigurationFilter_Clause` / `BudgetConfigurationFilter_TagClause` / `BudgetConfigurationFilter_WorkspaceIdClause` / - `BudgetConfigurationFilter_Operator` — model.ts:23, 71, 82, 88, 94 + `BudgetConfigurationFilter_Operator` — model.ts:91, 102, 108, 114, 39 - **Why:** The `BudgetConfiguration` proto-message prefix is dragged into the filter family even though every reader is already inside @@ -154,7 +129,7 @@ drop both `Configuration` and the underscore-nesting convention. ### 5. `CreateBudgetConfigurationBudget` / - `UpdateBudgetConfigurationBudget` — model.ts:99, 173 + `UpdateBudgetConfigurationBudget` — model.ts:119, 193 - **Why:** Reads as `-Budget-Configuration-Budget`. The `Configuration` proto token is wedged between the verb prefix and @@ -170,8 +145,8 @@ `DeleteBudgetConfigurationRequest` / `GetBudgetConfigurationRequest` / `ListBudgetConfigurationsRequest` / - `UpdateBudgetConfigurationRequest` — model.ts:119, 133, 143, - 155, 193 + `UpdateBudgetConfigurationRequest` — model.ts:139, 153, 163, + 175, 213 - **Why:** `Configuration` infix between verb and `Request`/`Response` is a proto/gRPC service-method naming artifact. TS request types diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md index 62220a5e..4dcfe8c9 100644 --- a/.agent/naming-audit/catalogs.md +++ b/.agent/naming-audit/catalogs.md @@ -9,7 +9,7 @@ ### 1. Overly verbose -#### 1.1 `EffectivePredictiveOptimizationFlag` (model.ts:199) +#### 1.1 `EffectivePredictiveOptimizationFlag` (model.ts:195) Type identifier is 39 characters. `EffectivePOFlag` or `EffectivePredictiveOptFlag` is overkill the other way; consider `EffectivePredictiveOptimization` (no `Flag` since the type already wraps @@ -31,7 +31,7 @@ The whole type *is* the flag; the suffix is redundant. See §1.1. ### 3. Reserved-word collisions -#### 3.1 `options` field on `CatalogInfo`, `CreateCatalogRequest`, `UpdateCatalogRequest` (model.ts:109, 174, 320) +#### 3.1 `options` field on `CatalogInfo`, `CreateCatalogRequest`, `UpdateCatalogRequest` (model.ts:127, 182, 318) `options` collides with the SDK's own `CallOptions` parameter name used throughout the client (e.g. `createCatalog(req, options)`). The collision is not a compile error but creates cognitive load — inside @@ -46,7 +46,7 @@ fix is renaming the second client parameter to `callOptions`. #### 4.1 `CreateCatalogRequest` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `provisioningInfo`, `fullName`, `securableType`, -`effectivePredictiveOptimizationFlag`, `browseOnly` (model.ts:147-168). +`effectivePredictiveOptimizationFlag`, `browseOnly` (model.ts:153-174). These are server-populated; a creator setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Mirror issue in `UpdateCatalogRequest`. @@ -55,7 +55,7 @@ Mirror issue in `UpdateCatalogRequest`. ### 5. Proto-architectural leaks -#### 5.1 `ProvisioningInfo_State` — model.ts:43 +#### 5.1 `ProvisioningInfo_State` — model.ts:55 - **Why:** Underscore-separated identifier signals a nested protobuf enum (`message ProvisioningInfo { enum State { ... } }`). The transport encoding has bled into the public type name and the `eslint-disable` @@ -65,50 +65,3 @@ Mirror issue in `UpdateCatalogRequest`. - **Rationale:** TS callers have no nesting; the parent prefix plus `State` produces a flat, idiomatic identifier without leaking the proto-nested origin. - -#### 5.2 `CatalogInfo_OptionsEntry` — model.ts:113 -- **Why:** Auto-generated proto map-entry message exposed as a public - type. `_OptionsEntry` is the canonical protobuf shape for - `map options` and has no semantic meaning at the - TypeScript SDK boundary. -- **Category:** Proto suffix/infix. -- **Suggested:** Remove from the public surface (the `options` field is - already typed as `Record`); if a named shape is - required, use `CatalogOption` or inline `{key, value}`. -- **Rationale:** Map-entry types are a proto serialization artifact, not - a domain concept. - -#### 5.3 `CatalogInfo_PropertiesEntry` — model.ts:119 -- **Why:** Same as 5.2 — proto map-entry leak for the `properties` - field. -- **Category:** Proto suffix/infix. -- **Suggested:** Remove from the public surface, or rename to - `CatalogProperty`. -- **Rationale:** Identical reasoning to 5.2. - -#### 5.4 `CreateCatalogRequest_OptionsEntry` — model.ts:178 -- **Why:** Proto map-entry type duplicated per parent message. -- **Category:** Proto suffix/infix. -- **Suggested:** Remove from the public surface; the inline - `Record` already covers the use case. -- **Rationale:** The fact that the same `_OptionsEntry` shape recurs on - `CatalogInfo`, `CreateCatalogRequest`, and `UpdateCatalogRequest` is a - smoking gun for proto codegen, not an SDK design. - -#### 5.5 `CreateCatalogRequest_PropertiesEntry` — model.ts:184 -- **Why:** Same as 5.4 — proto map-entry leak. -- **Category:** Proto suffix/infix. -- **Suggested:** Remove from the public surface. -- **Rationale:** See 5.4. - -#### 5.6 `UpdateCatalogRequest_OptionsEntry` — model.ts:324 -- **Why:** Proto map-entry leak (third copy of the same shape). -- **Category:** Proto suffix/infix. -- **Suggested:** Remove from the public surface. -- **Rationale:** See 5.4. - -#### 5.7 `UpdateCatalogRequest_PropertiesEntry` — model.ts:330 -- **Why:** Proto map-entry leak. -- **Category:** Proto suffix/infix. -- **Suggested:** Remove from the public surface. -- **Rationale:** See 5.4. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md index b57c1164..f868fcea 100644 --- a/.agent/naming-audit/cleanrooms.md +++ b/.agent/naming-audit/cleanrooms.md @@ -8,25 +8,13 @@ ## Summary -- **Total findings:** 3 +- **Total findings:** 2 --- -## 1. Inconsistent Action Verbs +## 1. Proto / Architectural Leaks -### 1.1 `createCleanRoomAsset` returns the new asset (client.ts:168); -`createCleanRoomOutputCatalog` returns a **response wrapper** -(`CreateCleanRoomOutputCatalogResponse`) (client.ts:264). -Inconsistent return shapes for two `create*` methods. The Go SDK has the -same wart, but it surfaces here as inconsistent ergonomics: -`(await c.createCleanRoomAsset(...)).name` vs. -`(await c.createCleanRoomOutputCatalog(...)).outputCatalog?.catalogName`. - ---- - -## 2. Proto / Architectural Leaks - -### 2.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:659 +### 1.1 `listCleanRoomNotebookTaskRunsHandler` — client.ts:673 - **Why:** Mid/end-position `Handler` on a public method (not a domain term). All sibling list methods (`listCleanRooms`, `listCleanRoomAssets`, `listCleanRoomAutoApprovalRules`) omit the `Handler` suffix. The stray @@ -37,12 +25,12 @@ same wart, but it surfaces here as inconsistent ergonomics: like `Handler` in client-method names; consistency with the other `list*` methods is the principal benefit. -### 2.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:701 +### 1.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:716 - **Why:** Same stray `Handler` infix in the async-iterator companion to - §2.1. Sibling iterators (`listCleanRoomsIter`, + §1.1. Sibling iterators (`listCleanRoomsIter`, `listCleanRoomAssetsIter`, `listCleanRoomAutoApprovalRulesIter`) follow the `Iter` pattern without `Handler`. - **Category:** Architectural leak (server-side terminology). - **Suggested:** `listCleanRoomNotebookTaskRunsIter`. -- **Rationale:** Must rename in lock-step with §2.1 so the iterator name +- **Rationale:** Must rename in lock-step with §1.1 so the iterator name derives cleanly from the base method. diff --git a/.agent/naming-audit/clusterlibraries.md b/.agent/naming-audit/clusterlibraries.md index 9e7ab889..a56a5abb 100644 --- a/.agent/naming-audit/clusterlibraries.md +++ b/.agent/naming-audit/clusterlibraries.md @@ -7,13 +7,13 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 1. Misleading names -### 1.1 `LibraryFullStatus` — `model.ts:122` +### 1.1 `LibraryFullStatus` — `model.ts:126` - "Full" implies there is a "Partial" or "Short" counterpart, but there is none in this package. The type is "the status of a library on a cluster" per the JSDoc — `LibraryStatus` would suffice. `Full` is meaningless. - Severity: medium. -### 1.2 `allClusterStatuses()` — `client.ts:76` +### 1.2 `allClusterStatuses()` — `client.ts:75` - Method is the GET for `all-cluster-statuses`. The TS method name reads like an adjective ("all-cluster statuses") and is not verb-prefixed. Sibling method is `clusterStatus()` (also verb-less). Compare with the @@ -27,7 +27,7 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 2. Overly verbose names -### 2.1 `ListAllClusterLibraryStatusesRequest` — `model.ts:134` +### 2.1 `ListAllClusterLibraryStatusesRequest` — `model.ts:138` - The type name embeds "All" (which is also encoded in the URL `/api/2.0/libraries/all-cluster-statuses`). The type name `ListAllClusterLibraryStatusesRequest` is itself verbose — `ListLibraryStatusesRequest` @@ -38,7 +38,7 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 3. Redundant suffixes -### 3.1 `LibraryFullStatus` — `model.ts:122` +### 3.1 `LibraryFullStatus` — `model.ts:126` - "Full" is a vestigial qualifier with no counterpart. See §1.1. - Severity: medium. @@ -46,8 +46,8 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 4. Singular/plural mismatches -### 4.1 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:134` -- Singular method name `allClusterStatuses` (`client.ts:76`) for what is +### 4.1 `ListAllClusterLibraryStatusesRequest` (request) — `model.ts:138` +- Singular method name `allClusterStatuses` (`client.ts:75`) for what is semantically a list operation. The action verb should be `list`. See §6. - Severity: medium. @@ -55,7 +55,7 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 5. Verb-tense inconsistency -### 5.1 Method verbs across the client — `client.ts:76, 115, 152, 184` +### 5.1 Method verbs across the client — `client.ts:75, 115, 153, 186` - `allClusterStatuses` and `clusterStatus` are verb-less (noun-only). - `installLibraries`, `uninstallLibraries` use verb-prefixed forms. - Two stragglers (`allClusterStatuses`, `clusterStatus`) should be aligned: @@ -68,7 +68,7 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 6. Inconsistent action verbs -### 6.1 GET vs `list` vs `all` — `client.ts:76` +### 6.1 GET vs `list` vs `all` — `client.ts:75` - `allClusterStatuses()` (verb `all`) reads as a noun-phrase, not a verb. The Go SDK uses the same naming, but the TS port has the opportunity to normalize to `list` (or `get`). @@ -78,7 +78,7 @@ Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` ## 7. Type-suffix tautology -### 7.1 `LibraryFullStatus` — `model.ts:122` +### 7.1 `LibraryFullStatus` — `model.ts:126` - "Status" appears in the type name and the field `status: LibraryInstallStatus` contains the noun again. Not a tautology per se, but the parent `LibraryFullStatus` could be `LibraryReport` or just `LibraryStatus`. diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md index 5746c925..bb1d8147 100644 --- a/.agent/naming-audit/clusterpolicies.md +++ b/.agent/naming-audit/clusterpolicies.md @@ -26,7 +26,7 @@ Total weird names flagged: 3. ## Medium -### 1. `MavenLibrary` (`model.ts:185`) +### 1. `MavenLibrary` (`model.ts:193`) Type-suffix tautology. The type already lives in a `Library` discriminated union; the `Library` suffix is redundant when accessed as @@ -34,10 +34,10 @@ union; the `Library` suffix is redundant when accessed as *position* in the union already identifies it as a library variant. `MavenSpec` or just `Maven` would suffice. -### 2. `PythonPyPiLibrary` (`model.ts:249`) +### 2. `PythonPyPiLibrary` (`model.ts:257`) Type-suffix tautology. Same as finding 1. Could be `PyPISpec`. -### 3. `RCranLibrary` (`model.ts:262`) +### 3. `RCranLibrary` (`model.ts:270`) Type-suffix tautology. Same as finding 1. Could be `CRANSpec`. diff --git a/.agent/naming-audit/clusters.md b/.agent/naming-audit/clusters.md index 6e68b728..8ddad309 100644 --- a/.agent/naming-audit/clusters.md +++ b/.agent/naming-audit/clusters.md @@ -12,19 +12,19 @@ ## Medium severity -### 1. `clusterLogStatus` field typed `LogSyncStatus` — `src/v2/model.ts:1330` +### 1. `clusterLogStatus` field typed `LogSyncStatus` — `src/v2/model.ts:1392` - **Why weird:** Type is `LogSyncStatus` but field is `clusterLogStatus`. Type and field have different mental models (`LogSync` vs `ClusterLog`). - **Category:** 6 (misleading — type and field name don't match the same concept). - **Suggested name:** Rename the type to `ClusterLogStatus` to match the field. - **Rationale:** Same concept, two different names in 5 lines. -### 2. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:749` +### 2. `ClusterEventType_ClusterEventType` doubly-nested enum name — `src/v2/model.ts:832` - **Why weird:** Enum named `ClusterEventType_ClusterEventType` — the same identifier repeated on both sides of the proto-nesting separator. This is a generator artefact when a proto message named `ClusterEventType` contains a nested enum also named `ClusterEventType`. The repeated identifier carries no information. - **Category:** 14 (proto nesting stutter), 4 (redundant repetition). - **Suggested name:** `ClusterEventType` (single, top-level). - **Rationale:** Drop the redundant `ClusterEventType_` prefix; the doubly-stuttered name repeats the same word with no added meaning. -### 3. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:73,2092` +### 3. `DataPlaneEventDetails` / `DataPlaneClusterEventType` — control-plane vs data-plane infrastructure naming — `src/v2/model.ts:2048,95` - **Why weird:** "Data plane" is an internal Databricks infrastructure concept (vs "control plane") — not a customer-facing domain term. Two public types prefix their names with the deployment-plane they originate from. A user creating a cluster does not need to know which plane emitted which event class; the distinction is a Databricks-internal architecture detail. - **Category:** 8 (internal architecture leak in public surface). - **Suggested name:** Either merge into a single `ClusterEventType` enum / `EventDetails` shape, or rename to a non-infrastructure word (e.g., `RuntimeEventDetails`). @@ -32,7 +32,7 @@ ## Low severity -### 4. `AutoScale` type name — `src/v2/model.ts:922` +### 4. `AutoScale` type name — `src/v2/model.ts:1021` - **Why weird:** PascalCase `AutoScale` is two words. Compare to `autoscale` field (lowercase, one word) and `autoterminationMinutes` (lowercase, one word). The type name is the outlier. - **Category:** 3 (casing inconsistency), 17 (within-package inconsistency). - **Suggested name:** `Autoscale` (one word, matching the field). diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md index 588057e0..42c3806a 100644 --- a/.agent/naming-audit/commandexecution.md +++ b/.agent/naming-audit/commandexecution.md @@ -13,62 +13,43 @@ | # | Severity | Category | Location | Current | Proposed | | -- | -------- | -------- | -------- | ------- | -------- | | 1 | high | 4. Underscores in TS identifiers | every enum member | `COMMAND_CANCELLED`, `PYTHON`, `IMAGES_RESULT` | `Cancelled`, `Python`, `Images` | -| 2 | high | 17. Inconsistent action verbs | `client.ts:144,184` | `commandStatus()`, `contextStatus()` | `getCommandStatus()`, `getContextStatus()` (matches request-type prefix) | -| 3 | high | 16. Field contradicts type domain | `model.ts:116-143` | `Results` (plural) for single-command result | `Result` | -| 4 | medium | 7. Overly verbose | `model.ts:99,111` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | -| 5 | medium | 20. Type-suffix tautology | `model.ts:55,82,93,106` | `CancelCommandRequest`, `ExecuteCommandRequest`, etc. | Acceptable here (request DTOs); flagged for review only | -| 6 | medium | 14. Go/Java-style names | `model.ts:74` + `client.ts:270` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | -| 7 | medium | 8. Redundant suffix — call-out | `client.ts:353, 430, 504` | `CancelWaiter`, `CreateWaiter`, `ExecuteWaiter` | OK if intentional waiter pattern, but `CreateWaiter` is for *context* creation not command creation; ambiguous | -| 8 | medium | 6. Misleading name | `client.ts:430` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | -| 9 | medium | 6. Misleading name | `client.ts:353` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | -| 10 | medium | 6. Misleading name | `client.ts:504` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | -| 11 | medium | 17. Inconsistent action verbs | `client.ts:88,270` | `cancel()` vs `destroy()` | Two destroy-like verbs for different resources (cancel command, destroy context). Acceptable but tone-deaf for JS users. | -| 12 | low | 15. Generic field losing meaning | `model.ts:67,87` | `language?: Language` | OK, but pair the values `R`, `SQL` (single-letter / acronym) — call out below | +| 2 | high | 16. Field contradicts type domain | `model.ts:130-157` | `Results` (plural) for single-command result | `Result` | +| 3 | medium | 7. Overly verbose | `model.ts:113,125` | `GetCommandStatusResponse`, `GetContextStatusResponse` | `CommandStatusResponse`, `ContextStatusResponse` (HTTP verb shouldn't leak into type) | +| 4 | medium | 14. Go/Java-style names | `model.ts:88` + `client.ts:200` | `DestroyContextRequest` / `destroy()` | "Destroy" is unusual in JS/TS REST clients; `delete` is more idiomatic — but match Go SDK | +| 5 | medium | 6. Misleading name | `client.ts:450` | `CreateWaiter` | Waits for **context** to become RUNNING; not for "create" success. Rename `CreateContextWaiter`. | +| 6 | medium | 6. Misleading name | `client.ts:373` | `CancelWaiter` | Waits for **command** cancellation. Rename `CancelCommandWaiter`. | +| 7 | medium | 6. Misleading name | `client.ts:524` | `ExecuteWaiter` | Waits for **command** completion. Rename `ExecuteCommandWaiter`. | --- ## Detailed Findings ### Finding 1 — High — Cat 4 (Underscores in TS identifiers) -**Location:** every enum member in `model.ts:22-52`. +**Location:** every enum-style member key in `model.ts:22-67`. **Issue:** TS identifier convention is PascalCase for type-namespace -members. `COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`, `SCALA` are all +members. The enums are emitted as `const` objects whose keys — +`COMMAND_CANCELLED`, `IMAGES_RESULT`, `PYTHON`, `SCALA` — are all SHOUTY_SNAKE_CASE, which violates the Google TypeScript style guide (`SCREAMING_SNAKE_CASE` only for *constants*, not enum members). -**Proposed:** convert every enum identifier to PascalCase. The string value -may retain the wire format (`COMMAND_CANCELLED`) to preserve serialisation, -but the *identifier* should be `Cancelled`. Example: +**Proposed:** convert every member key to PascalCase. The string value +may retain the wire format (`Cancelled`) to preserve serialisation, but +the *key* should be `Cancelled`. Example: ```ts -export enum CommandStatus { - CommandStatusUnspecified = 'COMMAND_STATUS_UNSPECIFIED', - CommandCancelled = 'COMMAND_CANCELLED', - CommandCancelling = 'COMMAND_CANCELLING', - CommandError = 'COMMAND_ERROR', - CommandFinished = 'COMMAND_FINISHED', - CommandQueued = 'COMMAND_QUEUED', - CommandRunning = 'COMMAND_RUNNING', -} +export const CommandStatus = { + CommandStatusUnspecified: 'COMMAND_STATUS_UNSPECIFIED', + Cancelled: 'Cancelled', + Cancelling: 'Cancelling', + Error: 'Error', + Finished: 'Finished', + Queued: 'Queued', + Running: 'Running', +} as const; ``` --- -### Finding 2 — High — Cat 17 (Inconsistent action verbs) -**Location:** `src/v2/client.ts:144, 184` -```ts -async commandStatus(req: GetCommandStatusRequest, ...) -async contextStatus(req: GetContextStatusRequest, ...) -``` -The *request types* are `GetCommandStatusRequest` / `GetContextStatusRequest` -(with `Get` prefix), but the methods drop the verb. Now `commandStatus` and -`contextStatus` read like getters/properties, not methods. Inconsistent with -`cancel`, `create`, `destroy`, `execute` which all start with a verb. -**Proposed:** rename `getCommandStatus()` and `getContextStatus()`. Matches -the request-type name and is verb-led like the other methods. - ---- - -### Finding 3 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) -**Location:** `src/v2/model.ts:116-143` +### Finding 2 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +**Location:** `src/v2/model.ts:130-157` ```ts export interface Results { ... } ``` @@ -80,8 +61,8 @@ inside it, not from multiple results. --- -### Finding 4 — Medium — Cat 7 (Overly verbose) -**Location:** `src/v2/model.ts:99, 111` +### Finding 3 — Medium — Cat 7 (Overly verbose) +**Location:** `src/v2/model.ts:113, 125` ```ts export interface GetCommandStatusResponse { ... } export interface GetContextStatusResponse { ... } @@ -94,21 +75,8 @@ returned", not "the response to a GET". --- -### Finding 5 — Medium — Cat 20 (Type-suffix tautology) — call-out only -**Location:** `src/v2/model.ts:55, 64, 74, 82, 93, 106` -```ts -CancelCommandRequest, CreateContextRequest, DestroyContextRequest, -ExecuteCommandRequest, GetCommandStatusRequest, GetContextStatusRequest -``` -**Issue:** `*Request` is a request type — the suffix repeats what the type -class already says. However, for *request DTOs* (named arguments) the -convention is widely accepted across REST SDKs. -**Proposed:** leave as-is; flagged only for SDK-wide consistency review. - ---- - -### Finding 6 — Medium — Cat 14 (Go/Java-style names) -**Location:** `src/v2/model.ts:74` + `client.ts:270` +### Finding 4 — Medium — Cat 14 (Go/Java-style names) +**Location:** `src/v2/model.ts:88` + `client.ts:200` **Issue:** `destroy` is unusual for a REST SDK. JS conventions favour `delete` (e.g. `clusters.delete`, `jobs.delete`). However the backend path is `/contexts/destroy`, so renaming the *method* would diverge. @@ -118,56 +86,29 @@ reserved word in expressions — typically requires bracket access). --- -### Finding 7 — Medium — Cat 8 (Redundant suffix) — call-out -**Location:** `src/v2/client.ts:353, 430, 504` -**Issue:** Three classes named `*Waiter`. Acceptable if waiter is a -recognised pattern in this SDK (it is, see Go SDK `awaitable.go`). The -issue is what they wait *for*: see #8-#10. - ---- - -### Finding 8 — Medium — Cat 6 (Misleading name) -**Location:** `src/v2/client.ts:430` +### Finding 5 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:450` ```ts export class CreateWaiter { ... } ``` The class waits for a *context* to reach `CONTEXT_RUNNING`. The name "CreateWaiter" implies it waits for "create" to finish, but the -operation it's bound to (`createWaiter()`) returns immediately after +operation it's bound to (`create()`) returns immediately after the context create call; the *waiter* polls a different endpoint -(`contextStatus`) for terminal state. +(`getContextStatus`) for terminal state. **Proposed:** `CreateContextWaiter` or `ContextWaiter` (parallel to the target endpoint). --- -### Finding 9 — Medium — Cat 6 (Misleading name) -**Location:** `src/v2/client.ts:353` +### Finding 6 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:373` **Issue:** `CancelWaiter` waits for *command* cancellation. **Proposed:** `CancelCommandWaiter`. --- -### Finding 10 — Medium — Cat 6 (Misleading name) -**Location:** `src/v2/client.ts:504` +### Finding 7 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:524` **Issue:** `ExecuteWaiter` waits for *command* completion. **Proposed:** `ExecuteCommandWaiter`. - ---- - -### Finding 11 — Medium — Cat 17 (Inconsistent action verbs) — call-out -**Location:** `src/v2/client.ts:88, 270` -**Issue:** This package uses three lifecycle verbs: -- `cancel()` on a command, -- `destroy()` on a context, -- `delete` on a context. -Three verbs for two lifecycle actions reads awkward. -**Proposed:** keep `cancel` (correct for commands — cancel is the right -verb for in-flight async work). Reconcile `destroy`/`delete` per the -Go-SDK alignment decision. - ---- - -### Finding 12 — Low — Cat 15 (Generic field) — call-out -**Location:** `src/v2/model.ts:67, 87` -`language?: Language` is correct. diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md index 4f31735e..8a96f66c 100644 --- a/.agent/naming-audit/connections.md +++ b/.agent/naming-audit/connections.md @@ -1,18 +1,18 @@ # Naming Audit: connections -**Path:** `packages/connections/src/v1/` +**Path:** `packages/uc/connections/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 5 +**Total weird names flagged:** 4 ## Summary | Severity | Count | | --- | --- | | High | 1 | -| Medium | 4 | +| Medium | 3 | ## High severity -### 1. `ConnectionInfo` — `src/v1/model.ts:89` +### 1. `ConnectionInfo` — `src/v1/model.ts:105` - **Why weird:** `Info` is the central domain entity — every type holds info about something. The Go SDK uses `XxxInfo` widely as a Go-style noun, but in TS the type would simply be `Connection`. `typescript.mdc` lists `Info` as a vague suffix. - **Category:** 1 (vague suffix), 8 (redundant type suffix). - **Suggested name:** `Connection`. @@ -20,26 +20,20 @@ ## Medium severity -### 2. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:118` +### 2. `ConnectionInfo.securableType: SecurableType` — `src/v1/model.ts:136` - **Why weird:** The value is *always* `SecurableType.CONNECTION` since this is a Connection, so the field is essentially constant. - **Category:** 16 (field type contradicts domain — a connection's securable_type can only be CONNECTION). - **Suggested name:** Drop the field (it's always `CONNECTION`), or document why a non-`CONNECTION` value would ever appear. - **Rationale:** Constant fields on response shapes are usually generator leaks. Worth pushing back upstream. -### 3. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:74-75` +### 3. `SecurableType.STAGING_TABLE` and TODO comment — `src/v1/model.ts:83-84` - **Why weird:** Enum value pinned by inline TODO: "Staging tables aren't full-fleged securables yet." Internal SDK TODOs in user-facing enum values. - **Category:** 6 (misleading — value advertised but not actually a securable yet). - **Suggested name:** Hide until promotion or mark `@experimental`. - **Rationale:** Public SDK enums shouldn't carry "not really a thing yet" entries. -### 4. `ConnectionInfo_OptionsEntry` / `ConnectionInfo_PropertiesEntry` / `CreateConnectionRequest_OptionsEntry` / `UpdateConnectionRequest_PropertiesEntry` — `src/v1/model.ts:127,133,176,182,271,277` -- **Why weird:** Proto-architectural-leak naming. Proto-style nested entry types with underscore-joined identifiers leak into the public TS surface. Each `Options` and `Properties` map gets a corresponding `*_OptionsEntry`/`*_PropertiesEntry` interface — six total — that is exported but trivial (`{key?, value?}`). The wire shape is already covered by `Record`. -- **Category:** Proto-architectural leak (`_OptionsEntry` / `_PropertiesEntry` proto map-entry message names), 12 (duplicate concept), 5 (cryptic — underscore-joined identifiers). -- **Suggested name:** Remove the `*Entry` interfaces from the public API; rely on `Record`. -- **Rationale:** These entry types add visual noise and are not used by the surface (the field is `Record`). - -### 5. `ProvisioningInfo_State` — `src/v1/model.ts:79` +### 4. `ProvisioningInfo_State` — `src/v1/model.ts:91` - **Why weird:** Proto-architectural-leak naming. Underscore-joined identifier (`ProvisioningInfo_State`) is a proto nested-enum name (`ProvisioningInfo.State`) emitted verbatim into TS. The enum is suppressed via `eslint-disable @typescript-eslint/naming-convention`, confirming it breaks TS conventions. Standalone TS would name this `ProvisioningState` (or merge into `ProvisioningInfo`). - **Category:** Proto-architectural leak (`_State` underscore-joined nested enum name). - **Suggested name:** `ProvisioningState`. -- **Rationale:** Proto nesting has no analogue in TS modules; the underscore is a wire-name artefact. Same generator pattern produces `*_Response`, `*_OptionsEntry`, `*_PropertiesEntry`. +- **Rationale:** Proto nesting has no analogue in TS modules; the underscore is a wire-name artefact. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md index dc1d35ce..589a9dea 100644 --- a/.agent/naming-audit/credentials.md +++ b/.agent/naming-audit/credentials.md @@ -5,7 +5,7 @@ **Package name:** `@databricks/sdk-credentials` (top-level module name collides semantically with the hand-written `@databricks/sdk-auth/credentials` sub-module). -**Total weird names flagged:** 4 +**Total weird names flagged:** 3 --- @@ -13,10 +13,9 @@ sub-module). | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| -| 1 | `R2Credentials` type | model.ts:853 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | -| 2 | `GenerateTemporaryPathCredentialRequest` / `GenerateTemporaryTableCredentialRequest` / `GenerateTemporaryVolumeCredentialRequest` / `GenerateTemporaryServiceCredentialRequest` | model.ts:615, 685, 717, 649 | interface set | Medium | 7 Overly verbose | Four request types whose names are 38-41 characters long. They differ in the *operand* (path/table/volume/service). A `TemporaryPathRequest` / etc. shape, parameterized by operand, would shorten. | -| 3 | `ListCredentialsPublicRequest` | model.ts:769 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | -| 4 | `CredentialsClient.createCredentialsPublic` / `CredentialsClient.deleteCredentialsPublic` / `CredentialsClient.getCredentialsPublic` / `CredentialsClient.listCredentialsPublic` | client.ts:971, 997, 1022, 1047 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `CredentialsClient` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | +| 1 | `R2Credentials` type | model.ts:881 | interface | Medium | 1 Vague/generic, 5 Cryptic abbreviations | "R2" is Cloudflare's object-storage service name. A reader who doesn't know Cloudflare's product line will be lost. Consider `CloudflareR2Credentials`. | +| 2 | `ListCredentialsPublicRequest` | model.ts:797 | interface | High | 20 Proto-architectural leak | `Public` mid-position is an internal Databricks service-layout artifact (proto/RPC public-vs-internal route distinction). No TS caller cares; the package itself is the public surface. Sibling consolidated UC endpoints have no such infix — confirms `Public` is a wire/service-layer disambiguator that should not leak into the TS surface. | +| 3 | `CredentialsClient.createCredentialsPublic` / `CredentialsClient.deleteCredentialsPublic` / `CredentialsClient.getCredentialsPublic` / `CredentialsClient.listCredentialsPublic` | client.ts:987, 1014, 1040, 1066 | method set | High | 20 Proto-architectural leak | Four public methods on the SDK `CredentialsClient` whose names carry the `Public` suffix. Reads as "the method on the public class that calls the public endpoint" — the suffix is meaningless to a TS caller and only exists because the underlying proto/spec uses `Public` to distinguish account-API routes. | --- @@ -24,7 +23,7 @@ sub-module). ### H1. `Public` infix proto-architectural leak (1 type + 4 methods) -Findings #3-#4. The package exposes **1 generated type** and **4 +Findings #2-#3. The package exposes **1 generated type** and **4 `CredentialsClient` methods** whose identifiers carry `Public` as a mid-position or trailing word. The infix originates from the internal proto/service definition where @@ -34,14 +33,14 @@ exported symbol is by definition public. Types (model.ts): -- `ListCredentialsPublicRequest` (769). +- `ListCredentialsPublicRequest` (797). Methods (client.ts): -- `createCredentialsPublic` (971). -- `deleteCredentialsPublic` (997). -- `getCredentialsPublic` (1022). -- `listCredentialsPublic` (1047). +- `createCredentialsPublic` (987). +- `deleteCredentialsPublic` (1014). +- `getCredentialsPublic` (1040). +- `listCredentialsPublic` (1066). Note also: the sibling consolidated UC endpoints (`CreateCredentialRequest`, `CreateStorageCredentialRequest`, etc.) do *not* carry `Public` even though @@ -73,15 +72,3 @@ without touching the generator/spec. A type named `R2` is identifiable only to readers who know Cloudflare's product line. Use `CloudflareR2Credentials` to make the cloud provider explicit in the type name. - ---- - -## Low severity (nits) - -### L1. `Generate*CredentialRequest` method names are 30+ chars - -`generateTemporaryServiceCredential` is 35 chars. Combined with `await -client.generateTemporaryServiceCredential(req)` the call site is 60+ chars -before the args. Cannot shorten without breaking the resource hierarchy. - ---- diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md index 96ad07b6..309c4562 100644 --- a/.agent/naming-audit/customllms.md +++ b/.agent/naming-audit/customllms.md @@ -2,33 +2,26 @@ **Path:** `packages/customllms/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 6 (0 fixed, 6 still present after rescan on 2026-06-02) +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | -| High | 2 | +| High | 1 | | Medium | 1 | -| Low | 2 | -| Observation | 1 | +| Low | 1 | ## High severity -### 1. `State` enum (top-level, ungrouped) — `src/v1/model.ts:9-17` +### 1. `State` enum (top-level, ungrouped) — `src/v1/model.ts:10-19` - **Why weird:** The enum is named `State` — the most generic noun in any API. There is no qualifier to tell the reader *which* state (optimization run? custom LLM? endpoint?). The doc comment ("States of Custom LLM optimization lifecycle.") clarifies, but the name alone does not. Every other Databricks package has its own `State` (jobs, clusters, queries) and a user importing two of them will be forced to alias. - **Category:** 1 (vague/generic), 15 (generic field name). - **Suggested name:** `OptimizationRunState` (matches the `optimizationState` field on `CustomLlm` and the request types `StartCustomLlmOptimizationRunRequest`/`CancelCustomLlmOptimizationRunRequest`). - **Rationale:** Specific enum names make import lists self-documenting and avoid alias collisions when consumers combine multiple SDK packages. -### 2. `CustomLlmFieldMask` only has 10 keys, missing 1 — `src/v1/model.ts:246-257` -- **Why weird:** The `FieldMask` for `CustomLlm` enumerates 10 fields, but `CustomLlm` declares 10 fields too (`id`, `name`, `endpointName`, `instructions`, `datasets`, `guidelines`, `optimizationState`, `creator`, `creationTime`, `agentArtifactPath`). On a strict read this is exactly aligned, *but* `endpointName` is documented as a server-populated read-only field ("Name of the endpoint that will be used to serve the custom LLM"). Exposing it in the field-mask suggests it is updatable, which would be a server bug — but consistent with the field-mask being machine-generated rather than designed. Worth a sanity check with the upstream API team. -- **Category:** Observation / 6 (misleading — field-mask implies updatable). -- **Suggested name:** No rename; flag the entry `endpointName: {wire: 'endpoint_name'}` for review. -- **Rationale:** This is the kind of thing a careful TS API designer would notice; a generator running over the proto schema will not. - ## Medium severity -### 3. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:71,176` +### 2. `cancelCustomLlmOptimizationRun` vs `startCustomLlmOptimizationRun` plural noun — `src/v1/client.ts:70,179` - **Why weird:** Both methods refer to "Optimization Run" (singular) — but a custom LLM has multiple optimization runs over its lifetime. The current API is `POST .../custom-llms/{id}/optimize/cancel` and `POST .../custom-llms/{id}/optimize` — so the URL has no run-id; the API operates on "the current run" implicitly. The method name `startOptimizationRun` is therefore not quite right; it should be `startOptimization` (the verb that starts a run) or `startCurrentOptimizationRun` (explicit). Same for `cancel`. As-is, the names imply a `runId` is being passed; it is not. - **Category:** 6 (misleading — name implies run-level addressing). - **Suggested name:** `startOptimization` / `cancelOptimization` (the singular "run" is implicit). @@ -36,20 +29,8 @@ ## Low severity -### 4. `Dataset[]` plural-singular consistency — `src/v1/model.ts:32,52` -- **Why weird:** Field `datasets: Dataset[]` — type is singular `Dataset`, field is plural `datasets`. This is correct! Flagging as an *observation* of best practice (rule 9 reversed). Counter-examples appear in other packages where a `Datasets` type holds `dataset: Dataset[]`. This package gets it right. -- **Category:** Observation / 9 (reversed — correctly singular). -- **Suggested name:** No change. -- **Rationale:** Note for consistency reviews. - -### 5. `customLlmFieldMask` function name — `src/v1/model.ts:259` +### 3. `customLlmFieldMask` function name — `src/v1/model.ts:261` - **Why weird:** Function that builds a `FieldMask`. The name `customLlmFieldMask` reads as a field-mask *value* rather than a builder; sibling files in other packages name this `*FieldMaskBuilder` or expose it as a static method `FieldMask.forCustomLlm`. - **Category:** 17 (inconsistent verb convention in the SDK). - **Suggested name:** `buildCustomLlmFieldMask` or `customLlmFieldMaskFor` (with a static-method-like signature). - **Rationale:** Minor; the function is clearly a builder by its signature `(...paths: string[]): FieldMask`. - -## Observations - -### 6. Action verbs in `Client` are consistent -The client uses `cancel`/`create`/`delete`/`get`/`start`/`update` — no `fetch`/`retrieve`/`read`. This is good. -- **Category:** 17 (reversed — explicit *consistency* note). diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md index da01ec73..d622cef0 100644 --- a/.agent/naming-audit/database.md +++ b/.agent/naming-audit/database.md @@ -2,24 +2,23 @@ **Path:** `packages/database/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 11 +**Total weird names flagged:** 9 ## Summary | Severity | Count | | --- | --- | | High | 2 | | Medium | 7 | -| Observation | 2 | ## High severity -### 1. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:446`, `client.ts:427` -- **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 447 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:471): "Name of the **cluster** to get". +### 1. `FindDatabaseInstanceByUidRequest` / `findDatabaseInstanceByUid` — `src/v1/model.ts:497`, `client.ts:437` +- **Why weird:** Verb tense (`Find ... By ...`) is Java/Spring-style. Other clients use `getXById` / `getX` style. The doc on the field at line 498 also says "UID of the **cluster** to get" — referring to a *cluster*, not an instance, contradicting the type name. Same JSDoc bug appears on `GetDatabaseInstanceRequest.name` (model.ts:522): "Name of the **cluster** to get". - **Category:** 14 (Java-style name), 6 (misleading doc — says cluster, type says instance), 17 (verb-tense inconsistency with `getDatabaseInstance`). - **Suggested name:** `LookupDatabaseInstanceRequest` + `lookupDatabaseInstance`, or fold into `getDatabaseInstance` with a uid alternative. Fix the doc strings. - **Rationale:** `findXByY` is uncommon in JS SDKs; `getX` is the idiomatic verb. The misleading "cluster" comments are an additional bug. -### 2. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:998`, `index.ts:3` +### 2. `CreateDatabaseInstanceWaiter` exports separately and the wait class is a noun-phrase — `src/v1/client.ts:1022`, `index.ts:3` - **Why weird:** Class name reads as "the *create instance waiter*" — i.e. a waiter for a create-instance operation. JS convention for poll-helpers tends to be `Poller`, `Waiter`, or a verb (e.g. `waitForX`). Calling it `CreateDatabaseInstanceWaiter` mixes a verb (`Create`) with a noun-suffix (`Waiter`) — reads as "a waiter that creates"; the meaning is "a waiter for a creation result". - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll helper naming). - **Suggested name:** `DatabaseInstanceCreationWaiter`, or eliminate the class entirely and expose `createDatabaseInstance({wait: true})` / `createDatabaseInstanceAndWait()` returning the final instance. @@ -27,53 +26,44 @@ ## Medium severity -### 3. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:795` +### 3. `SyncedTableStatus.lastSync: SyncedTablePosition` — `src/v1/model.ts:871` - **Why weird:** `SyncedTablePosition` is a curious type name — it represents a "position" but holds two timestamps and a source-sync-info union. "Position" reads as an offset/cursor; here it's a snapshot of sync progress. - **Category:** 1 (vague — `Position` is generic), 6 (misleading — not a positional cursor). - **Suggested name:** `LastSyncSummary` or `SyncCheckpoint`. - **Rationale:** Reader sees `lastSync: SyncedTablePosition` and thinks "the position of the last sync" — but the type holds start/end timestamps, not an offset. -### 4. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:436` +### 4. `DeltaTableSyncInfo` is the only `*SyncInfo` type and the only `Delta*` type — `src/v1/model.ts:487` - **Why weird:** Type holds two fields and is the lone `*SyncInfo` / `Delta*` type in the package. `SyncInfo` is a generic stand-in suffix; the type is really a sync checkpoint. - **Category:** 15 (generic `*Info` suffix). - **Suggested name:** Type `DeltaSyncCheckpoint`. - **Rationale:** `DeltaTableSyncInfo` reads as a generic bag of fields; a domain-specific name conveys that it captures a sync checkpoint. -### 5. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:463,577` +### 5. `GenerateDatabaseCredentialRequest.claims` (plural `RequestedClaims[]`) but `RequestedClaims` is itself plural — `src/v1/model.ts:514,628` - **Why weird:** `RequestedClaims` is already plural. Field `claims: RequestedClaims[]` is "an array of plural-claims-objects". JWT-claims convention is that "claims" is a noun-collective; one `RequestedClaims` object holds many claims and is itself one entity. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** Singular type `RequestedClaim` (or `ClaimRequest`) used in plural field `claims: ClaimRequest[]`; or scalar wrapper `claims: RequestedClaimsBundle`. - **Rationale:** Plural-of-plural confuses iteration code. -### 6. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:454-455` +### 6. `GenerateDatabaseCredentialRequest.instanceNames` is "instance_names or claims" — `src/v1/model.ts:505-506` - **Why weird:** Doc says "At least one of instance_names or claims must be specified" — that's a one-of-required constraint expressed only in prose. Type system allows both empty/both set. - **Category:** 16 (type contradicts domain constraint), 1 (loose contract). - **Suggested name:** Discriminated union of `{instanceNames: string[]}` vs `{claims: ClaimRequest[]}`. - **Rationale:** Generator artefact; flag for upstream tightening. -### 7. `NewPipelineSpec` type — `src/v1/model.ts:551` +### 7. `NewPipelineSpec` type — `src/v1/model.ts:602` - **Why weird:** Proto-architectural leak on two axes. (1) `New` is a mid-position relativistic adjective (`Old`/`New`/`Legacy`/`Modern`) — type names should describe what a value *is*, not its temporal status relative to a peer (the type is paired with a sibling `existingPipelineId` field). The "newness" is only meaningful at the moment of creation; the same struct shape would describe an old pipeline equally well. (2) `Spec` is a generic suffix that appears twice in the package (also `SyncedTableSpec`) — see also finding #8 on repeated `Spec`/`Info` suffixes. The `New` prefix mirrors a proto oneof discriminator (existing-vs-new), not a TS-native concept. - **Category:** proto-architectural leak (forbidden mid adjective `New`), 15 (generic suffix `Spec`). - **Suggested name:** Type `PipelineCreationOptions` / `InlinePipelineConfig`. Drop the `New` adjective and the `Spec` suffix. - **Rationale:** The presence of `New` in a type name implies a corresponding `Old`/`Existing` type — which doesn't exist as a struct, only as a sibling string field. The asymmetry betrays the proto oneof. -### 8. Repeated generic suffix `*Spec` across the package — `src/v1/model.ts:436,551,723` +### 8. Repeated generic suffix `*Spec` across the package — `src/v1/model.ts:487,602,774` - **Why weird:** Two `*Spec` types (`NewPipelineSpec`, `SyncedTableSpec`) coexist with the `*Info` type `DeltaTableSyncInfo` and no shared interface or contract. `Spec` and `Info` are generic stand-in nouns that proto / gRPC schemas overuse; they convey "this is a bag of fields" rather than the domain concept. `DeltaTableSyncInfo` is a sync checkpoint (see #4); `SyncedTableSpec` is a sync pipeline configuration; `NewPipelineSpec` is creation-time pipeline options (see #7). Each of these would read more clearly with a domain-specific suffix. - **Category:** proto-architectural leak (repeated `Spec`/`Info` suffixes), 15 (generic nouns), 1 (vague). - **Suggested name:** `SyncedTableSpec` → `SyncedTableConfig` (still generic) or better `SyncPipelineDefinition`; `NewPipelineSpec` → `InlinePipelineConfig` (see #7); `DeltaTableSyncInfo` → `DeltaSyncCheckpoint` (per #4). Goal: no two types in the package share a generic suffix. - **Rationale:** When `Spec` and `Info` appear repeatedly, the reader has to look up each one to know what it actually holds. Suffix-disambiguation is a proto smell that the TS surface inherits. -### 9. `ProvisioningInfo_State` proto-underscore type name — `src/v1/model.ts:570-575` -- **Why weird:** The enum `ProvisioningInfo_State` carries a proto-style underscore-nested name (`Parent_Nested`). It is referenced by `SyncedDatabaseTable.unityCatalogProvisioningState`. The underscore-joined name bleeds the proto nesting structure into the public TS surface. +### 9. `ProvisioningInfo_State` proto-underscore type name — `src/v1/model.ts:161` +- **Why weird:** The enum `ProvisioningInfo_State` carries a proto-style underscore-nested name (`Parent_Nested`). It is referenced by `SyncedDatabaseTable.unityCatalogProvisioningState` (model.ts:683). The underscore-joined name bleeds the proto nesting structure into the public TS surface. - **Category:** proto-architectural leak (proto-underscore nested type name `Foo_Bar`), 12 (cross-package proto leak). - **Suggested name:** Rename `ProvisioningInfo_State` to `ProvisioningState` (or `UnityCatalogProvisioningState`, matching its sole use site). - **Rationale:** A `Parent_Nested` underscore name is a generator artefact that should not surface in idiomatic TS; the flattened `ProvisioningState` reads as a native enum. - -## Observations - -### 10. `findDatabaseInstanceByUid` is the only `findBy*` method -Every other lookup is `getX(req)`. This method exists because the API has a distinct route (`/instances:findByUid`) for UID-lookup vs `/instances/{name}`. The TS surface reflects the URL shape rather than the user's mental model. -- **Category:** 17 (inconsistency with peer methods). - -### 11. Action-verb conventions in `Client` are consistent -`create*` / `delete*` / `get*` / `list*` / `findBy*` — verb prefixes are consistent. Lookup is `get` (good). No `fetch`/`retrieve`/`read` mixing. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md index 1c16359d..b9d370e2 100644 --- a/.agent/naming-audit/dataquality.md +++ b/.agent/naming-audit/dataquality.md @@ -2,7 +2,7 @@ **Path:** `packages/dataquality/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 8 +**Total weird names flagged:** 7 ## Summary | Severity | Count | @@ -10,23 +10,22 @@ | High | 3 | | Medium | 3 | | Low | 1 | -| Observation | 1 | ## High severity -### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:345,351`, `src/v1/client.ts:339` +### 1. `ListMonitorRequest` / `ListMonitorResponse` / `listMonitor` — `src/v1/model.ts:379,385`, `src/v1/client.ts:345` - **Why weird:** Singular noun on a list operation. A list returns many monitors but the type and method names use the singular `Monitor`. The wire path is `/api/data-quality/v1/monitors` (plural), the response holds `monitors?: Monitor[]`, and the paginator yields a single `Monitor` — every concrete signal says plural; only the type/method name disagrees. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListMonitorsRequest` / `ListMonitorsResponse` / `listMonitors`. - **Rationale:** REST conventions, the package's own field naming (`monitors`, `refreshes`), and the URL path all use plural. The singular form here is generator template noise, not intent. Same fix applies to refreshes (#2). -### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:357,377`, `src/v1/client.ts:404` +### 2. `ListRefreshRequest` / `ListRefreshResponse` / `listRefresh` — `src/v1/model.ts:391,411`, `src/v1/client.ts:411` - **Why weird:** Same singular-on-list problem as #1. The wire path is `/refreshes` and the response holds `refreshes?: Refresh[]`. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `ListRefreshesRequest` / `ListRefreshesResponse` / `listRefreshes`. - **Rationale:** Internal consistency: every other place in this file uses the plural `refreshes`. Only the type and method name break the pattern. -### 3. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:383-405,385,397` and 6 other request types +### 3. `Monitor.objectType` + `Monitor.objectId` (and every request type that copies them) — `src/v1/model.ts:417-439,419,431` and 6 other request types - **Why weird:** `objectType` is a free-form `string` typed as the values `"schema"` or `"table"`. The discriminator is implicit in a `string`. The companion `objectId` is a `string` whose actual content depends on what `objectType` says ("It is `schema_id` for `schema`, and `table_id` for `table`"). This is a stringly-typed sum type. Every single request and response in the package copies these two fields verbatim with copy-pasted JSDoc (43 lines of the same boilerplate per type, 6+ types). - **Category:** 1 (vague — `objectType` could be anything), 6 (misleading — stringly-typed sum), 15 (generic field name losing meaning), 19 (underspecified ID — `objectId` shape depends on a sibling field's value). - **Suggested name:** Model as a discriminated union: `target: {kind: 'schema', schemaId: string} | {kind: 'table', tableId: string}`. @@ -34,19 +33,19 @@ ## Medium severity -### 4. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:399,404` +### 4. `Monitor.anomalyDetectionConfig` and `Monitor.dataProfilingConfig` — `src/v1/model.ts:433,438` - **Why weird:** Two top-level fields, exactly one of which must be populated based on `objectType`. The relationship is documented in JSDoc but not in the type. This is the second un-modelled discriminated union in the package (the first being `objectType` itself, #3). A user reading the type sees two optional fields and has no idea both could be set at once (or neither). - **Category:** 6 (misleading — type says both optional, semantics say exactly one), 11 (missing union — should be discriminated). - **Suggested name:** Model as: `configuration: {kind: 'schema', anomalyDetection: AnomalyDetectionConfig} | {kind: 'table', dataProfiling: DataProfilingConfig}`. Then drop `objectType` (the discriminator becomes implicit). - **Rationale:** This is the same anti-pattern as `objectType` — using the type system to model business rules instead of relying on doc strings. -### 5. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:416` +### 5. `NotificationSettings.onFailure: NotificationDestination` — `src/v1/model.ts:450` - **Why weird:** Field name `onFailure` with type `NotificationDestination` — `Notification` repeated in both parent type and the destination type. The JSDoc says "Destinations to send notifications on failure/timeout." — failure *and* timeout, but the field name only says failure. - **Category:** 1 (vague — name says `failure`, doc says `failure/timeout`), 8 (redundant prefix in the type). - **Suggested name:** Type: `Destination` (drop the `Notification` prefix since the type is only used here). Field stays `onFailure`; update doc to clarify timeout semantics. - **Rationale:** Field name and JSDoc should agree on whether timeouts are included; type name should not repeat its parent's noun. -### 6. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:98,156,329,451,454` +### 6. Pervasive `Config` suffix on sibling domain types — `src/v1/model.ts:132,190,363,488,485` - **Why weird:** Five sibling types all end in `Config`: `AnomalyDetectionConfig`, `DataProfilingConfig`, `InferenceLogConfig`, `TimeSeriesConfig`, `SnapshotConfig`. The `Config` suffix is a proto-style architectural label — it adds no semantic information once you know the type is a configuration record. The Go reference SDK uses these names because protobuf's `*Config` messages map 1:1 to Go structs, but TS does not need to carry that scaffolding. The leak is most visible at the call site `DataProfilingConfig.analysisConfig` where three `Config`-suffixed arms nest inside a `Config`-suffixed field on a `Config`-suffixed type — triple `Config` nesting in a single access path. - **Category:** proto-architectural-leak (repeated `Config` mid/suffix), 8 (redundant suffix), 12 (duplicate concept). - **Suggested name:** Drop the `Config` suffix on the analysis-arm types: `InferenceLog`, `TimeSeries`, `Snapshot`. Keep `AnomalyDetectionConfig` / `DataProfilingConfig` as the top-level monitor configurations (they are genuinely "the config" of a `Monitor`). Or rename uniformly to `AnomalyDetectionSettings` / `DataProfilingSettings` and use `Analysis` for the arm types. @@ -54,13 +53,8 @@ ## Low severity -### 7. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:95, 174, 217, 239, 276, 315, 408, 473, 514` -- **Why weird:** Same as `dataclassification` finding #25 — `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. +### 7. `req.objectId ?? ''` / `req.objectType ?? ''` URL composition — `src/v1/client.ts:95, 176, 220, 243, 281, 321, 416, 482, 524` +- **Why weird:** `objectType`/`objectId` typed optional but required in practice. Silently substitutes empty string producing malformed URLs like `/api/data-quality/v1/monitors//`. - **Category:** 6. - **Suggested name:** Make `objectType` and `objectId` non-optional on every request type that constructs a URL from them. - **Rationale:** Type shape should match runtime requirement. - -## Observations - -### 8. Action verbs in `Client` -The client uses `Create`/`Get`/`Update`/`Delete`/`List`/`Cancel` for monitor and refresh operations. Verbs are consistent within the package. (Listed per rule 17 to note the absence of inconsistency.) diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md index b2f8f5b0..caaa6b40 100644 --- a/.agent/naming-audit/disasterrecovery.md +++ b/.agent/naming-audit/disasterrecovery.md @@ -2,7 +2,7 @@ **Path:** `packages/disasterrecovery/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 6 +**Total weird names flagged:** 5 ## Summary | Severity | Count | @@ -10,17 +10,16 @@ | High | 2 | | Medium | 2 | | Low | 1 | -| Observation | 1 | ## High severity -### 1. `FailoverFailoverGroupRequest` — `src/v1/model.ts:91` +### 1. `FailoverFailoverGroupRequest` — `src/v1/model.ts:99` - **Why weird:** Stutter: the word `Failover` appears twice in a single type name. Mechanically this is `Request` (`Failover` verb + `FailoverGroup` noun + `Request`), but the result reads as a typo. - **Category:** 7 (overly verbose), 17 (inconsistency in action-verb naming — every other action type spells out the verb only once since the resource has only one `failover` action). - **Suggested name:** `FailoverRequest` (the resource is unambiguous in this package) or `TriggerFailoverRequest` (more explicit verb). - **Rationale:** No other request in the package re-states the resource word inside its verb. The wire path is `…/failover`, so a single `Failover` in the type name is sufficient. -### 2. Write-only "primary region" fields are not distinguished in the type shape — `src/v1/model.ts:125,149,101` +### 2. Write-only "primary region" fields are not distinguished in the type shape — `src/v1/model.ts:133,157,109` - **Why weird:** Two of the three "primary region" fields are write-only, but the type signature gives no hint: - `effectivePrimaryRegion` — current truth; mutated by failover. - `initialPrimaryRegion` — create-only input; never returned. @@ -32,27 +31,22 @@ ## Medium severity -### 3. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:289` -- **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 131) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. +### 3. `UcCatalog` (and field `catalogs: UcCatalog[]`) — `src/v1/model.ts:295` +- **Why weird:** Field name on `UcReplicationConfig` is `catalogs`, a plain plural — the leading `Uc` prefix is redundant inside a type that already lives in `UcReplicationConfig`. Adjacent identifiers (e.g., `unityCatalogAssets` at line 139) spell the domain out as `unityCatalog`, so the `Uc` abbreviation is also locally inconsistent. - **Category:** 5 (cryptic abbreviation `Uc`), 8 (redundant `Uc` prefix inside Uc context), 17 (inconsistency — `unityCatalog` vs `Uc`). - **Suggested name:** `Catalog` (or `ReplicatedCatalog`), and field type `catalogs: Catalog[]`. - **Rationale:** `UcReplicationConfig.catalogs: UcCatalog[]` reads as "UC replication config's UC catalogs" — redundant. The full `unityCatalog` spelling is used adjacent in the file; either propagate that or drop the prefix entirely inside the UC-scoped type. -### 4. `UcReplicationConfig` — `src/v1/model.ts:295` -- **Why weird:** `Uc` is a two-letter abbreviation in a type name. Comments in the same file (line 113) spell it out as "UCDR" with `Unity Catalog` in `unityCatalogAssets` (line 131). Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. +### 4. `UcReplicationConfig` — `src/v1/model.ts:301` +- **Why weird:** `Uc` is a two-letter abbreviation in a type name. The same file spells the domain out: the `FailoverGroup` JSDoc (line 121) says "Unity Catalog" and the field `unityCatalogAssets` (line 139) uses the full spelling. Single SDK uses both `unityCatalog` (full) and `Uc` (abbreviated) for the same concept across adjacent fields/types. - **Category:** 5 (cryptic abbreviation), 17 (inconsistency — `unityCatalogAssets: UcReplicationConfig`). - **Suggested name:** `UnityCatalogReplicationConfig` (or `UnityCatalogConfig`). - **Rationale:** Within a five-line span the same domain is spelled `unityCatalog` and `Uc`. Pick one. The full spelling is unambiguous and the field name already votes for it. ## Low severity -### 5. `failoverFailoverGroup` method name on `Client` — `src/v1/client.ts:218` +### 5. `failoverFailoverGroup` method name on `DisasterRecoveryClient` — `src/v1/client.ts:221` - **Why weird:** Stutter (same as #1). Methods elsewhere are `createFailoverGroup`, `getFailoverGroup`, `listFailoverGroups`, `updateFailoverGroup`, `deleteFailoverGroup` — all use ``. This one collides because `failover` is both the verb and (lower-cased) part of the resource. - **Category:** 7 (overly verbose), 17 (inconsistency — verb visually merges with resource). - **Suggested name:** `triggerFailover` (verb `trigger`, since `failover` is the object) or just `failover` (single-word, since the package is already "disasterrecovery"). - **Rationale:** `client.failoverFailoverGroup({...})` reads like a typo. `client.failover({...})` or `client.triggerFailover({...})` are unambiguous. - -## Observations - -### 6. Action-verb consistency on `Client` (mostly good) -Methods are `create*`/`get*`/`list*`/`update*`/`delete*` plus one bespoke action (`failoverFailoverGroup`). Aside from the stutter (#5), this is consistent. Listed as observation per rule 17 since the audit asks to flag inconsistencies — here only the one method breaks the pattern. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md index fb085176..39bde47d 100644 --- a/.agent/naming-audit/entitytagassignments.md +++ b/.agent/naming-audit/entitytagassignments.md @@ -2,24 +2,23 @@ **Path:** `packages/uc/entitytagassignments/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 5 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | | High | 2 | -| Medium | 2 | -| Observation | 1 | +| Medium | 1 | ## High severity -### 1. `TagAssignmentSourceType` — `src/v1/model.ts:9` +### 1. `TagAssignmentSourceType` — `src/v1/model.ts:10` - **Why weird:** Three-word enum name `TagAssignmentSourceType`. "Source" + "Type" is a tautology — an enum *is* a type, so `*Type` suffix is filler. - **Category:** 20 (type-suffix tautology — `Type` on an enum), 7 (overly verbose). - **Suggested name:** `TagSource` (drop both `Assignment` and `Type`). - **Rationale:** The shorter name is unambiguous in context. Sister Unity Catalog packages have analogous enums like `Privilege`, `SchemaType` — `Type` suffix is used inconsistently across the SDK. -### 2. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:26,36,54` +### 2. `tagKey` field doc inconsistency: required marker on get/delete, not on `EntityTagAssignment` — `src/v1/model.ts:32,42,60` - **Why weird:** `DeleteEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag to delete". `GetEntityTagAssignmentRequest.tagKey` says "Required. The key of the tag". But `EntityTagAssignment.tagKey` (on the actual returned/created object) and `CreateEntityTagAssignmentRequest.tagAssignment.tagKey` are documented as just "The key of the tag" with no required marker — yet you cannot create or get a tag without a key. The `?: string | undefined` typing makes all of them optional in TS. Type and doc disagree. - **Category:** 6 (misleading — type says optional, semantics says required), 17 (inconsistent — some docs say "Required.", others don't, for what is the same logical field). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) and remove the "Required." doc preamble since the type enforces it. Apply uniformly across all four request types and the assignment type itself. @@ -27,19 +26,8 @@ ## Medium severity -### 3. `ListEntityTagAssignmentsRequest` (plural) vs. `EntityTagAssignment` (singular) — `src/v1/model.ts:60` vs. `src/v1/model.ts:32` -- **Why weird:** The plural appears only on the list endpoint; the rest of the surface is singular. Singular/plural mix is consistent with the Go SDK and other packages, but worth flagging that the resource name on the wire is `/entity-tag-assignments` (plural) while the type name is singular `EntityTagAssignment`. The list response is `ListEntityTagAssignmentsResponse` (plural). -- **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). -- **Suggested name:** Keep as is (this is the cross-SDK convention). Listed for completeness. -- **Rationale:** Listed only to confirm: List endpoints use plural, item type is singular. No fix needed; flagged because rule 9 demands the audit. - -### 4. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:123,145,178,244` +### 3. `req.entityType ?? ''` / `req.entityName ?? ''` / `req.tagKey ?? ''` URL composition — `src/v1/client.ts:124,147,181,248` - **Why weird:** Four endpoints silently substitute empty string for missing path components. `req.entityType` and `req.entityName` and `req.tagKey` are typed `string | undefined` but functionally required (URL is broken without them). When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-name/tags/key`. Same problem flagged in `dataclassification` audit. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. - **Rationale:** Field name promises less than the API requires; the SDK silently produces malformed URLs. - -## Observations - -### 5. Action verb consistency -The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md index 0aa3542b..90fb7295 100644 --- a/.agent/naming-audit/environments.md +++ b/.agent/naming-audit/environments.md @@ -15,13 +15,13 @@ ## High severity -### 1. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:718` +### 1. `WorkspaceBaseEnvironment` — type name is a 26-character three-adjective noun phrase — `model.ts:731` - **Why weird:** The central type's name is the prefix every other identifier in the package inherits, so its length cascades: `CreateWorkspaceBaseEnvironmentRequest`, `RefreshWorkspaceBaseEnvironmentOperation`, `ListWorkspaceBaseEnvironmentsResponse`, etc. Three of the four words (`Workspace`, `Base`, `Environment`) are present in every export. The 26 characters are baked into the *type prefix*, not the enum-member prefix; this is a TS-surface concern, not a proto-codegen concern. - **Category:** 7 (overly verbose type prefix), 1 (generic — "base" and "environment" together still don't say what the resource *is*: a YAML dependency manifest pointer). - **Suggested name:** Drop one of the adjectives in the *type* name. The package being named already implies "environment", and the URL is `/api/environments/v1/workspace-base-environments` — at most one of `Workspace` or `Base` is informationally necessary in TS. Options: `BaseEnvironment`, `WorkspaceEnvironment`, or rename the whole package and call the type `BaseEnvironment`. - **Rationale:** Length compounds: every method, request, response, schema function, and operation class repeats `WorkspaceBaseEnvironment` once or twice. A user typing `client.crea[Tab]` faces a wall of nearly identical 36+ character names. -### 2. `WorkspaceBaseEnvironment.status` field type's name and the type's domain do not align — `model.ts:737` +### 2. `WorkspaceBaseEnvironment.status` field type's name and the type's domain do not align — `model.ts:750` - **Why weird:** `WorkspaceBaseEnvironment.status` is typed `WorkspaceBaseEnvironmentCache_Status` — i.e. the *status of a Cache*. But the field documents itself as "The status of the materialized workspace base environment", not the status of a cache. The user reads `env.status` and the type's name implies a different concept (cache) than the doc and the data (materialization state of the environment). - **Category:** 16 (field type contradicts type domain), 6 (misleading). - **Suggested name:** Rename the enum type to `MaterializationStatus` (the doc's own words) and drop the `Cache` qualifier. diff --git a/.agent/naming-audit/experiments.md b/.agent/naming-audit/experiments.md index d014845b..19ee2c69 100644 --- a/.agent/naming-audit/experiments.md +++ b/.agent/naming-audit/experiments.md @@ -2,42 +2,42 @@ **Path:** `packages/experiments/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 12 +**Total weird names flagged:** 11 ## Summary | Severity | Count | | --- | --- | | High | 5 | | Medium | 4 | -| Low | 3 | +| Low | 2 | ## High severity -### 1. `LoggedModel` — `src/v1/model.ts:537` +### 1. `LoggedModel` — `src/v1/model.ts:547` - **Why weird:** `LoggedModel` is a noun-phrase made of past-participle adjective + noun. The "logged" prefix is doing the disambiguation against `RegisteredModel`, `ServingModel`, `MlflowModel` etc. But (a) past-tense adjectives in type names read awkwardly (`LoggedModel`, `DeletedExperiment`, `FinishedRun` would all be similarly weird), and (b) `Logged` does not describe what the type *is* — it describes the verb history that produced it. - **Category:** 6 (misleading: "Logged" describes history, not identity), 13 (verb-tense in noun-phrase). - **Suggested name:** `MlflowModel`, `TrackedModel`, or `RunModel` (since every `LoggedModel` belongs to a Run via `sourceRunId`). - **Rationale:** `LoggedModel` is a leaky verb. Type names should be present-tense nouns describing identity ("what it is"). Lots of `Logged*` derivatives compound the problem (see #2). -### 2. `LoggedModel` family — many separate types — `src/v1/model.ts:537, 545, 556, 584, 592` + request/response — `model.ts:71, 158, 166, 253, 296, 452, 789, 905` +### 2. `LoggedModel` family — many separate types — `src/v1/model.ts:547, 555, 566, 594, 602` + request/response — `model.ts:81, 168, 176, 263, 306, 462, 799, 915` - **Why weird:** `LoggedModel`, `LoggedModelData`, `LoggedModelInfo`, `LoggedModelParameter`, `LoggedModelTag`, `LoggedModelStatus`, plus request types `CreateLoggedModelRequest`, `DeleteLoggedModelRequest`, `DeleteLoggedModelTagRequest`, `FinalizeLoggedModelRequest`, `GetLoggedModelRequest`, `LogLoggedModelParamsRequest`, `SearchLoggedModelsRequest`, `SetLoggedModelTagsRequest`. The `LoggedModel` prefix is repeated 13 times across types that all live in the same package. Compare to `Run` family — `Run`, `RunInfo`, `RunData`, `RunInputs`, `RunTag`, `RunStatus` — which uses the shorter prefix. - **Category:** 7 (overly verbose), 12 (duplicate concept against `Model*` family that may exist in `modelregistry` package). - **Suggested name:** Either drop the `Logged` and call the family `MlflowModel` / `MlflowModelData` / `MlflowModelInfo` / `MlflowModelParameter` / `MlflowModelTag` / `MlflowModelStatus`, or nest under a namespace. - **Rationale:** 13 occurrences of "LoggedModel" in identifiers — almost every `LoggedModel` request type repeats the verb prefix unnecessarily. -### 3. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:688, 698, 708, 744` -- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:697-705`), `RunInfo` is "id, name, status, times, user" (`model.ts:707-741`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:743-749`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. +### 3. `RunData`, `RunInfo`, `RunInputs` triplet — `src/v1/model.ts:698, 708, 718, 754` +- **Why weird:** `Run` contains three sub-types: `RunInfo`, `RunData`, `RunInputs`. None of the names tells the user what each one carries: `RunData` is "metrics, params, tags" (`model.ts:707-715`), `RunInfo` is "id, name, status, times, user" (`model.ts:717-751`), `RunInputs` is "datasetInputs, modelInputs" (`model.ts:753-759`). All three names are interchangeably vague. The Go SDK splits the same way — but in TS we can flatten. - **Category:** 1 (vague: `Data`/`Info`/`Inputs` type names). - **Suggested name:** Flatten into `Run` (one object). If they must stay split, name them by content: `RunMetadata` (instead of `RunInfo`), `RunMeasurements` (instead of `RunData`), `RunDatasetsAndModels` (instead of `RunInputs`). - **Rationale:** `RunInfo` vs `RunData` requires the reader to look up the schema to know which fields go where. Naming by content removes that lookup. -### 4. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:556, 545` +### 4. `LoggedModelInfo` vs `LoggedModelData` — `src/v1/model.ts:566, 555` - **Why weird:** Same `Info`/`Data` split as `Run` (#3). `LoggedModelInfo` is "attributes, tags, registration info"; `LoggedModelData` is "params and metrics". Same generic-suffix problem on the type names. - **Category:** 1 (vague). - **Suggested name:** `MlflowModelMetadata` and `MlflowModelMeasurements`, or fold both into one `MlflowModel`. - **Rationale:** Same as #3. -### 5. `ViewType` enum — generic type name — `src/v1/model.ts:40-47` +### 5. `ViewType` enum — generic type name — `src/v1/model.ts:47-57` - **Why weird:** Type name `ViewType` is meaningless on its own ("a type of view"). It is the enum used to filter experiments/runs by deleted state. - **Category:** 1 (generic type name). - **Suggested name:** Type: `ExperimentVisibility` or `LifecycleFilter`. @@ -45,19 +45,19 @@ ## Medium severity -### 6. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:452` -- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:948`). +### 6. `LogLoggedModelParamsRequest` — verb-noun-verb compound — `src/v1/model.ts:462` +- **Why weird:** Parses as: Log (verb) + LoggedModel (noun) + Params (noun) + Request (suffix). Read aloud as "Log Logged Model Params Request". Three nouns/verbs strung together. The verb `Log` collides with the participle adjective `Logged` (they have the same root) inside the same identifier. Method is `logLoggedModelParams` (`client.ts:966`). - **Category:** 7 (overly verbose), 17 (verb collision), 6 (reads awkwardly). - **Suggested name:** `AddMlflowModelParamsRequest` + `addMlflowModelParams`, or `LogParamsForModelRequest` + `logParamsForModel`, or drop `Logged` once the rename in #2 is applied: `LogMlflowModelParamsRequest`. - **Rationale:** The double-Log is jarring on read. -### 7. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1362, 1333` +### 7. `setLoggedModelTags` is plural but `setExperimentTag` is singular — `src/v1/client.ts:1392, 1362` - **Why weird:** `setExperimentTag(req: SetExperimentTagRequest)` sets **one** tag. `setLoggedModelTags(req: SetLoggedModelTagsRequest)` sets a batch. Same verb, different cardinality. Method `setTag` (run tag) is also singular. No `setExperimentTags` or `setRunTags` exists. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verb cardinality). - **Suggested name:** Either add bulk variants for experiment/run, or rename to be explicit: `setLoggedModelTagsBatch`, or pluralise all (`setExperimentTags`, `setRunTags`, `setLoggedModelTags`). - **Rationale:** Cardinality should be predictable from the method name. -### 8. `logBatch` does not say "log run batch" — `src/v1/client.ts:886` +### 8. `logBatch` does not say "log run batch" — `src/v1/client.ts:902` - **Why weird:** `logBatch` is a batch-write of metrics/params/tags **to a run**. Name says "batch" but not "what gets batched" or "what scope". From the method name alone, a user might think this is "batch-log many experiments" or "batch-log many metrics across many runs". JSDoc clarifies. - **Category:** 1 (vague), 15 (generic name). - **Suggested name:** `logRunBatch`, `logRunMetadata`, or `logRunMeasurements`. @@ -78,16 +78,12 @@ ## Low severity -### 10. `Experiment.tags` / `LoggedModelInfo.tags` / `RunData.tags` / `RunInputs` no tags — `src/v1/model.ts:232, 580, 704` -- **Why weird:** Three top-level types have a `tags` field but each uses a different element type (`ExperimentTag` / `LoggedModelTag` / `RunTag`). The field is consistently `tags`, but the element type is not unifiable in TS without changes. -- **Category:** 17 (inconsistency at the element-type level). - -### 11. Boolean field `FileInfo.isDir` — `src/v1/model.ts:248` -- **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: number | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. +### 10. Boolean field `FileInfo.isDir` — `src/v1/model.ts:258` +- **Why weird:** Naming-wise `isDir` is fine, but the boolean is paired with `fileSize?: bigint | undefined` where the JSDoc says "Unset for directories" — i.e. `fileSize` is a discriminator partner that should be excluded when `isDir === true`. No discriminated union enforces this. - **Category:** 6 (misleading optionality), 16 (field contradicts domain in the file-vs-directory case). -- **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: number })`. +- **Suggested name:** Model as `type FileInfo = { path: string } & ({ isDir: true } | { isDir: false; fileSize: bigint })`. -### 12. `FileInfo` itself is a generic name — `src/v1/model.ts:244` +### 11. `FileInfo` itself is a generic name — `src/v1/model.ts:254` - **Why weird:** `FileInfo` is generic — many SDKs have a `FileInfo` type. This one is specifically an MLflow Run artifact entry. - **Category:** 1 (generic), 12 (likely duplicate of `dbsql/v1` or `workspace/v1` FileInfo). - **Suggested name:** `RunArtifact` or `ArtifactFileInfo`. diff --git a/.agent/naming-audit/externallineage.md b/.agent/naming-audit/externallineage.md index 8ef4678a..279f0095 100644 --- a/.agent/naming-audit/externallineage.md +++ b/.agent/naming-audit/externallineage.md @@ -12,15 +12,15 @@ ## High severity -### 1. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:140` -- **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:566-573` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. +### 1. `ExternalLineageRelationshipObject.tpe` discriminator — `src/v1/model.ts:130` +- **Why weird:** Field literally spelled `tpe` (three letters, missing the `y`). `type` is a reserved-ish word in TS but is allowed as a property name; this is a workaround for something that doesn't need a workaround. The marshalling code at `model.ts:550-557` confirms this is the *only* discriminator field — wire payload has no `tpe` key, it's spread into `table`/`path`/`model_version`/`external_metadata` directly. - **Category:** 5 (cryptic abbreviation), 10 (reserved-word collision-avoidance). - **Suggested name:** Use a TS discriminated union with `$case` directly (no outer `tpe` field): `ExternalLineageRelationshipObject = {$case: 'table', table: ...} | {$case: 'path', path: ...} | ...`. If the wrapper must stay, name the field `kind` or `objectType`. - **Rationale:** TS allows `type` as a property name, so the cryptic `tpe` solves a problem TS does not have. ## Low severity -### 2. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:179-183` +### 2. `LineageFileInfo.securableName`, `securableType`, `storageLocation` — `src/v1/model.ts:169-173` - **Why weird:** Type is `LineageFileInfo` but three of its four data-bearing fields are about a *securable* (which the JSDoc says lives "on the path"). The type is mostly about the securable, not the file. Three fields named with `securable*` on a type called `*FileInfo` looks like the type name was chosen too early. - **Category:** 6 (misleading type name — `FileInfo` advertises "info about a file" but it's "info about a securable on a file"). - **Suggested name:** `LineageFileSecurableInfo`, to reflect that the type is mostly about the securable rather than the file. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md index 32e54c52..245bf736 100644 --- a/.agent/naming-audit/externallocations.md +++ b/.agent/naming-audit/externallocations.md @@ -1,8 +1,8 @@ # Naming Audit: externallocations -**Path:** `packages/externallocations/src/v1/` +**Path:** `packages/uc/externallocations/src/v1/` **Versions audited:** v1 -**Package name:** `@databricks/sdk-externallocations` (workspace package; the +**Package name:** `@databricks/sdk-uc-externallocations` (workspace package; the folder is one word `externallocations`, no hyphen, no underscore). **Total weird names flagged:** 2 @@ -12,8 +12,8 @@ folder is one word `externallocations`, no hyphen, no underscore). | # | Name | File | Kind | Severity | Category | Issue (one-liner) | | --- | ------------------- | -------------- | ---- | -------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `AzureQueueStorage` | model.ts:27 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | -| 2 | `ExternalLocationInfo` | model.ts:121 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | +| 1 | `AzureQueueStorage` | model.ts:35 | type | Medium | 6 Misleading names | The Azure product is "Azure Queue Storage", which the wire/`provided_aqs`/`managed_aqs` shortens to AQS. So `AzureQueueStorage` is the long name, but two of its callers (`providedAqs`/`managedAqs` fields and case literals) use the AQS abbreviation. Pick one canonical form. | +| 2 | `ExternalLocationInfo` | model.ts:129 | type | Medium | 16 Proto-architectural-leak names, 7 Overly verbose | The `Info` suffix is a Go/proto convention for the resource-representation message; in idiomatic TS the type for "an external location" is just `ExternalLocation`. The suffix carries no semantic value (there is no `ExternalLocation` vs `ExternalLocationInfo` distinction) and adds noise to every reference (`Promise`, `ExternalLocationInfo[]`). | --- @@ -41,7 +41,7 @@ idiomatic TS this would just be `ExternalLocation`. The suffix shows up in every signature touching the resource: -- `Promise` (4 client method return types). +- `Promise` (3 client method return types). - `ExternalLocationInfo[]` in `ListExternalLocationsResponse`. - `AsyncGenerator` in the iter method. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md index 15e26f42..bd74e1a9 100644 --- a/.agent/naming-audit/externalmetadata.md +++ b/.agent/naming-audit/externalmetadata.md @@ -1,36 +1,30 @@ # Naming Audit: externalmetadata -**Path:** `packages/externalmetadata/src/v1/` +**Path:** `packages/uc/externalmetadata/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 4 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | | High | 3 | -| Observation | 1 | ## High severity -### 1. `ExternalMetadata` — `src/v1/model.ts:43` +### 1. `ExternalMetadata` — `src/v1/model.ts:47` - **Why weird:** The central domain entity is named after the package, which is a noun phrase but not a noun ("External Metadata" is more an adjective+noun phrase than a thing). Compare: `Catalog`, `Connection`, `Schema` are crisp nouns; `ExternalMetadata` reads like a category, not an instance. Also: every field has the doc-string suffix "external metadata object" — the type is essentially `XxxObject` without the suffix, but the docs need it because the bare type name lacks objecthood. - **Category:** 1 (vague — what is "an External Metadata"?), 6 (misleading: name reads as a kind, not an instance). - **Suggested name:** `ExternalAsset` or `ExternalEntity` (the type already has a `entityType` field describing what shape of external thing it is). Alternatively, embrace the proto-canonical name with `ExternalMetadataObject`. - **Rationale:** Reading `const x: ExternalMetadata = ...` does not communicate that `x` is a single named external asset. The JSDoc fix ("external metadata object") betrays that the type name needs help to read as a noun. Worth raising upstream. -### 2. `ListExternalMetadataResponseV2` — `src/v1/model.ts:94` +### 2. `ListExternalMetadataResponseV2` — `src/v1/model.ts:92` - **Why weird:** Type name carries the API version suffix `V2`, but the enclosing file is already `v1/model.ts` and the package is mounted at `./v1`. Version is encoded twice — once in the directory, once in the type. If the user later imports a hypothetical `v2/`, they would get `V3`? Versioning the entity name within the version namespace creates an off-by-one collision risk. - **Category:** 8 (redundant suffix — version is in the path), 20 (type-suffix tautology between version-in-path and version-in-name), 14 (Go/proto-style — Go SDK carries the `V2` per RPC name; TS doesn't need it). - **Suggested name:** `ListExternalMetadataResponse` (drop `V2`). - **Rationale:** The directory is the namespace. Embedding the wire RPC version into the TS type name leaks an internal detail of the generator. If the package later gets a `v2/` directory, every type there ends up `V3` (one ahead of the dir), which is worse than the original problem. -### 3. `ExternalMetadataClient.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:72,107,132,165,204,226` +### 3. `ExternalMetadataClient.createExternalMetadataV2` / `deleteExternalMetadataV2` / `getExternalMetadataV2` / `listExternalMetadataV2` / `updateExternalMetadataV2` / `listExternalMetadataV2Iter` — `src/v1/client.ts:71,107,133,167,229,207` - **Why weird:** Every public method on `ExternalMetadataClient` ends with `V2`, but the directory is `v1/`. The version suffix is wire-RPC-name leakage (the upstream API is `ExternalMetadataServiceV2.Create`, hence `createExternalMetadataV2`). User code reads `client.createExternalMetadataV2(...)` for a method on a `v1/` import — confusing on first read. - **Category:** 8 (redundant suffix), 14 (Go/proto-style name leak), 20 (type/version suffix tautology). - **Suggested name:** `createExternalMetadata`, `deleteExternalMetadata`, etc. (drop `V2`). - **Rationale:** The user's call site is `import {Client} from '@databricks/sdk-externalmetadata/v1'; client.createExternalMetadataV2(...)` — `V2` is wire-RPC noise. Version belongs in the import path, not the method name. Same problem as #2; generator-wide concern. - -## Observations - -### 4. Action-verb conventions in `Client` -The client uses `Create`/`Get`/`Update`/`Delete`/`List` consistently — no `Fetch`/`Retrieve`/`Read`/`Remove`. Verb consistency is good. diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md index 53e005cb..811659b5 100644 --- a/.agent/naming-audit/features.md +++ b/.agent/naming-audit/features.md @@ -3,7 +3,7 @@ **Path:** `packages/features/src/v1/` **Versions audited:** v1 **Package name:** `@databricks/sdk-features` -**Total weird names flagged:** 24 (rescan on 2026-06-02) +**Total weird names flagged:** 11 --- @@ -12,29 +12,16 @@ | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| | 1 | package `features` / module `@databricks/sdk-features` | (package) | package | High | 1 Vague/generic | The bare term "features" is ambiguous: (a) ML features (this package), (b) Databricks product features / feature flags (settings/previews), (c) "features" of a billing plan (billing). A reader cannot disambiguate from the import path. Rename to `@databricks/sdk-feature-engineering`, `@databricks/sdk-ml-features`, or `@databricks/sdk-feature-definitions`. | -| 2 | `Feature` interface | model.ts:343 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | -| 3 | `FeaturesClient.*Feature*` plus `*KafkaConfig*` plus `*MaterializedFeature*` plus `*Stream*` (4 resource families on one client) | client.ts:102-872 | method set | Medium | 12 Duplicate concepts | One `FeaturesClient` class owns four distinct resource families: `Feature`, `KafkaConfig`, `MaterializedFeature`, and `Stream`. The class is 873 lines and reads as four sub-clients merged. A split into per-resource clients would let each be a focused surface and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../features/kafka-configs`, `/.../materialized-features`, `/.../streams`). | -| 4 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:134, 196, 1043, 769, 763, 407, 624, 101, 109, 913, 924, 1116, 1122 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that mostly already encode "this is the average operation" — `avg` (not `avgFunction`); only `countFunction` keeps the suffix. The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | -| 5 | `TimeWindow.windowType` field | model.ts:1058 | field | Low | (none) | Not stuttery; the union variants are `continuous`/`tumbling`/`sliding`/`rolling` so `windowType` is a reasonable discriminator label. (Listing for completeness.) | -| 6 | `Feature.source` vs `Feature.entities` vs `Feature.timeseriesColumn` (singular column vs plural columns) | model.ts:351, 380, 382 | field set | Low | 9 Singular/plural mismatches | `entities: EntityColumn[]` (plural, list of columns acting as keys) and `timeseriesColumn: TimeseriesColumn` (singular, one time column). Naming difference is intentional and matches the underlying types — fine. | -| 7 | `ColumnSelection` interface | model.ts:182 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | -| 8 | `Function.function.$case === 'columnSelection'` discriminator | model.ts:439 | field | Low | (none) | Within the `function` union, `columnSelection` sits next to `aggregationFunction`. Consistent. | -| 9 | `KafkaConfig.bootstrapServers` | model.ts:538 | field | Low | (none) | Standard Kafka term. Fine. | -| 10 | `SubscriptionMode.$case === 'assign'` | model.ts:1022 | field | Low | 1 Vague/generic | "assign" is the Kafka idiom for "specifically assign these topic-partitions". Fine for Kafka users; opaque otherwise. | -| 11 | `SubscriptionMode.$case === 'subscribePattern'` | model.ts:1035 | field | Low | (none) | Fine, matches Kafka SDK. | -| 12 | `disableHostnameVerification` flag on `MtlsConfig` | model.ts:820 | field | Low | (none) | Boolean named in the affirmative-by-disabling style. Documented carefully in JSDoc. Fine. | -| 13 | `MtlsConfig.keystorePasswordRef` / `keyPasswordRef` / `truststorePasswordRef` (`Ref` suffix) | model.ts:795, 801, 809 | field set | Low | 5 Cryptic abbreviations | "Ref" abbreviates "Reference". The element type is `SecretScopeReference` so the suffix is informative — fine, consistent across three fields. | -| 14 | `LineageContext` interface name | model.ts:630 | interface | Low | 1 Vague/generic | "LineageContext" is reasonable in a lineage-tracking context. Fine. | -| 15 | `JobContext.jobRunId` | model.ts:528 | field | Low | (none) | Fine. | -| 16 | `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` | model.ts:3221, 3290, 3359 | function set | Low | (none) | Three helper builders. Standard generator pattern. Consistent across resources (a fourth, `streamFieldMask`, follows the same shape). Listing for completeness. | -| 17 | `ContinuousWindow` / `SlidingWindow` / `TumblingWindow` (Spark windowing) | model.ts:188, 905, 1078 | interface set | Low | (none) | Standard Spark Structured Streaming idioms. Fine. | -| 18 | `Function` interface shadows JS built-in `Function` | model.ts:421 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | -| 19 | `Function_FunctionType` enum | model.ts:29 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | -| 20 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:47 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #19. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | -| 21 | `Function_ExtraParameter` interface | model.ts:451 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | -| 22 | `KafkaConfig_ExtraOptionsEntry` interface | model.ts:558 | interface | High | Proto architectural leak | Proto-architectural-leak naming. The generator emits a synthetic `{key?, value?}` map-entry interface for the `extraOptions` field of `KafkaConfig`, copying the proto `Entry` message name verbatim. The wire shape is already covered by `Record` (model.ts:548), so this entry type adds noise and is not used by the surface. Remove the `*Entry` interface from the public API. | -| 23 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1491, 2504 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #21. | -| 24 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState`, `KafkaConfig_ExtraOptionsEntry` | index.ts:7-8, 44, 53 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports four `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#19-23) clears this automatically. | +| 2 | `Feature` interface | model.ts:364 | interface | High | 1 Vague/generic | The unqualified noun `Feature` is the single most overloaded word in Databricks vocabulary. As a TS-imported type, `import {Feature}` from `@databricks/sdk-features/v1` collides conceptually with: (a) feature flags, (b) preview features, (c) workspace "feature settings". Rename to `FeatureDefinition`, `MLFeature`, or `FeatureEngineeringFeature` to scope the noun. | +| 3 | `FeaturesClient.*Feature*` plus `*KafkaConfig*` plus `*MaterializedFeature*` plus `*Stream*` (4 resource families on one client) | client.ts:74-893 | method set | Medium | 12 Duplicate concepts | One `FeaturesClient` class owns four distinct resource families: `Feature`, `KafkaConfig`, `MaterializedFeature`, and `Stream`. The class is 893 lines and reads as four sub-clients merged. A split into per-resource clients would let each be a focused surface and would clarify the URL groupings (`/api/2.0/feature-engineering/features`, `/.../features/kafka-configs`, `/.../materialized-features`, `/.../streams`). | +| 4 | 13 `*Function` interfaces (`AvgFunction`, `CountFunction`, `SumFunction`, `MinFunction`, `MaxFunction`, `FirstFunction`, `LastFunction`, `ApproxCountDistinctFunction`, `ApproxPercentileFunction`, `StddevPopFunction`, `StddevSampFunction`, `VarPopFunction`, `VarSampFunction`) | model.ts:150, 212, 1091, 809, 803, 428, 638, 117, 125, 953, 964, 1164, 1170 | interface set | High | 8 Redundant suffixes, 12 Duplicate concepts, 20 Type-suffix tautology | 13 interfaces named `Function` where only `` would suffice. The `AggregationFunction.operation` discriminated union groups them with `$case` values that mostly already encode "this is the average operation" — `avg` (not `avgFunction`); only `countFunction` keeps the suffix. The `Function` suffix on the type name is redundant. Worse: 11 of 13 of these interfaces are **identical** — `{input?: string \| undefined}`. They could be one shared `SingleColumnFunction` type or a parametric alias. The two that differ are `ApproxCountDistinctFunction` (adds `relativeSd`) and `ApproxPercentileFunction` (adds `percentile`, `accuracy`). | +| 5 | `ColumnSelection` interface | model.ts:198 | interface | Medium | 1 Vague/generic | The name `ColumnSelection` is generic enough to read as "the selection of a column" in any context, but the JSDoc says it represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow" — i.e., a very specific semantic. `LatestColumnValue` or `LifetimeLastValue` would fit the semantic. | +| 6 | `Function` interface shadows JS built-in `Function` | model.ts:442 | interface | High | 1 Vague/generic, 6 Misleading names | `export interface Function` shadows the TypeScript global `Function` type (the constructor signature). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Rename to `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. | +| 7 | `Function_FunctionType` enum | model.ts:33 | enum | High | Proto architectural leak | Underscore-separated proto-nested enum name (`Outer_Inner`) leaks `.proto` IDL nesting into the public TS API. Requires an eslint-disable for `@typescript-eslint/naming-convention`. Flatten to `FunctionType` (or, since deprecated, retire entirely). | +| 8 | `MaterializedFeature_PipelineScheduleState` enum | model.ts:55 | enum | High | Proto architectural leak | Same proto-nested-enum leak as #7. The TS-facing name encodes the proto outer message (`MaterializedFeature`) as a prefix segment. Flatten to `PipelineScheduleState` (the values are already `PIPELINE_SCHEDULE_STATE_*` so the outer prefix is redundant). | +| 9 | `Function_ExtraParameter` interface | model.ts:472 | interface | High | Proto architectural leak | Proto-nested message name with underscore separator; carries an explicit eslint-disable. The pattern `Outer_Inner` is a `.proto` nested-message convention and is not how TS interfaces are named. Flatten to `ExtraFunctionParameter` or move to a discriminated union member. | +| 10 | `unmarshalFunction_ExtraParameterSchema` / `marshalFunction_ExtraParameterSchema` | model.ts:1542, 2572 | const set | Medium | Proto architectural leak | Zod schema constants inherit the proto-nested `Outer_Inner` underscore from the interface. Both carry an explicit eslint-disable. Rename together with #9. | +| 11 | Public re-exports of `Function_FunctionType`, `Function_ExtraParameter`, `MaterializedFeature_PipelineScheduleState` | index.ts:7-8, 44 | re-export set | High | Proto architectural leak | The package's public API barrel re-exports three `Outer_Inner` proto-nested identifiers. A TS consumer importing from `@databricks/sdk-features/v1` cannot avoid the proto-shaped names. Removing the proto leak at the model layer (#7-10) clears this automatically. | --- @@ -56,7 +43,7 @@ has no signal that this is the ML kind. Recommend ### H2. The `Feature` type name is overloaded The unqualified noun `Feature` is the central type of this package -(model.ts:343) and is re-exported from `index.ts`. Once it lands in a +(model.ts:364) and is re-exported from `index.ts`. Once it lands in a consumer's namespace it shadows the common-English sense of the word. ```ts @@ -70,7 +57,7 @@ the URL). ### H3. `Function` interface shadows the JS built-in -`export interface Function` (model.ts:421) shadows the TypeScript global +`export interface Function` (model.ts:442) shadows the TypeScript global `Function` type (the constructor signature `Function`). Inside any module that imports `Function` from this package, the global is unreachable except via `globalThis.Function`. Most ESLint configs (including this repo's, see @@ -78,34 +65,28 @@ via `globalThis.Function`. Most ESLint configs (including this repo's, see Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. -### H4. Proto-architectural leak: `Outer_Inner` nested names (#19-24) +### H4. Proto-architectural leak: `Outer_Inner` nested names (#7-11) -Four public identifiers carry the proto-nested `_` underscore +Three public identifiers carry the proto-nested `_` underscore convention straight from the `.proto` IDL into the TS public API: -- `Function_FunctionType` (enum, model.ts:29) -- `MaterializedFeature_PipelineScheduleState` (enum, model.ts:47) -- `Function_ExtraParameter` (interface, model.ts:451) -- `KafkaConfig_ExtraOptionsEntry` (interface, model.ts:558) +- `Function_FunctionType` (enum, model.ts:33) +- `MaterializedFeature_PipelineScheduleState` (enum, model.ts:55) +- `Function_ExtraParameter` (interface, model.ts:472) Each requires an `eslint-disable @typescript-eslint/naming-convention` line to compile, with the disable comment self-identifying as "Proto-style nested enum name" or "Proto-style nested message name". The corresponding zod-schema constants inherit the underscore (`unmarshalFunction_ExtraParameterSchema`, -`marshalFunction_ExtraParameterSchema` — model.ts:1491, 2504). +`marshalFunction_ExtraParameterSchema` — model.ts:1542, 2572). -`KafkaConfig_ExtraOptionsEntry` is the synthetic map-entry interface the -generator emits for the `extraOptions: map` field; the -user-facing TS field is already `extraOptions: Record` -(model.ts:548), so the `*Entry` type has no consumer in idiomatic TS code. - -All four are re-exported from `index.ts` (lines 7-8, 44, 53), so the +All three are re-exported from `index.ts` (lines 7-8, 44), so the underscore-shaped names cross the package boundary into every importer's namespace. Fix at the generator: emit the inner type at the file top level without the outer prefix (`FunctionType`, `PipelineScheduleState`, -`ExtraFunctionParameter`) and drop the synthetic map-entry interface. +`ExtraFunctionParameter`). --- @@ -113,7 +94,7 @@ the outer prefix (`FunctionType`, `PipelineScheduleState`, ### M1. One `FeaturesClient` owning four resource families -The `FeaturesClient` class is 873 lines and exposes methods over four resource +The `FeaturesClient` class is 893 lines and exposes methods over four resource families: - `Feature`: create, get, list, update, delete. @@ -166,57 +147,9 @@ redundant. preserve forward extensibility — e.g., to let `SumFunction` later add fields without affecting `AvgFunction`. Worth pushing back on.) -### M3. Field-name pluralization mismatches the type - -- `Feature.entities: EntityColumn[]` — plural field, singular element. Fine. -- `KafkaSource.entityColumnIdentifiers: ColumnIdentifier[]` — plural field, - singular element. Fine in isolation but `entities` (the modern version on - Feature) is much shorter. -- `DeltaTableSource.entityColumns: string[]` — plural field, primitive - element. Deprecated. Three plural conventions for the same notion. - -### M4. `ColumnSelection` interface is too generic +### M3. `ColumnSelection` interface is too generic JSDoc says `ColumnSelection` represents "equivalent to the LAST() record of an entity over a lifetime ContinuousWindow". The name gives no domain hint. `LatestColumnValue` would name the behavior. (Same critique as `Credential` in the credentials audit.) - ---- - -## Low severity (nits) - -### L1. `MtlsConfig.disableHostnameVerification` reasonable - -Boolean named in negative ("disable") to match the underlying Kafka option -(`kafka.ssl.endpoint.identification.algorithm`). JSDoc warns about security -implications. Fine. - -### L2. `bootstrapServers` is conventional Kafka - -Fine. - -### L3. `ContinuousWindow.offset` allows non-positive - -Note in JSDoc: "must be non-positive" — i.e., 0 or negative duration. The -type is `Temporal.Duration` which doesn't constrain sign. Documentation-only -constraint; not enforced. Same critique as `SlidingWindow.slideDuration` -("must be positive and less than duration"). - -### L4. `SecretScopeReference { scope, key }` - -Two-field reference to a Databricks secret. Standard. Fine. - -### L5. `TimeWindow`, `ContinuousWindow`, `TumblingWindow`, `SlidingWindow` - -Four Spark Structured Streaming idioms. Standard. Fine. - -### L6. `featureFieldMask` / `kafkaConfigFieldMask` / `materializedFeatureFieldMask` - -Three field-mask builders. Standard generator pattern. Fine. - -### L7. `req.featureName` query parameter on `ListMaterializedFeaturesRequest` - -The list endpoint filters by feature name (full UC name). Field is -`featureName?: string` — fine. Distinguishes from `MaterializedFeature.featureName` -in the response, which is the same value. diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md index 7d642370..37732ac6 100644 --- a/.agent/naming-audit/featurestore.md +++ b/.agent/naming-audit/featurestore.md @@ -12,52 +12,9 @@ ## Findings -### 1. SCREAMING_SNAKE_CASE enum values — category 4 (Underscores in TS identifiers) — *Still* - -**Symbols:** Every value in both enums (model.ts:11–23, 28–44). - -**Issue:** The project's `.agent/skills/google-ts-styleguide` (and the Google -TS Style Guide § 5.3) mandates `UpperCamelCase` for enum members, not -`SCREAMING_SNAKE_CASE`. The project's own `typescript.mdc` enforces no -underscores in TS identifiers. Enum members like `FAILING_OVER` contain -underscores and are SCREAMING-cased. - -Note: enum string *values* double as the on-the-wire representation here (the -Zod schemas parse raw API strings into these identifiers, e.g. `z.enum( -OnlineStore_State)` at model.ts:150). The TS-side identifier can be split -from the wire literal — e.g. `FailingOver = 'FAILING_OVER'` — which is the -canonical TS fix while preserving wire compatibility. - -**Suggested (TS side only, no wire change):** - -```ts -export enum OnlineStoreState { - Unspecified = 'STATE_UNSPECIFIED', - Starting = 'STARTING', - Available = 'AVAILABLE', - Deleting = 'DELETING', - Stopped = 'STOPPED', - Updating = 'UPDATING', - FailingOver = 'FAILING_OVER', -} - -export enum PublishMode { - Unspecified = 'PUBLISH_MODE_UNSPECIFIED', - Continuous = 'CONTINUOUS', - Triggered = 'TRIGGERED', - Snapshot = 'SNAPSHOT', -} -``` - -This is consistent with how the project's `typescript.mdc` treats other enums -and matches the project skill's mandate. **Flag as SDK-wide cleanup** — -unilateral change here would diverge from sibling packages. +### 1. `PublishSpec` is vague — category 1 (Vague/generic) ---- - -### 2. `PublishSpec` is vague — category 1 (Vague/generic) — *Still* - -**Symbol:** `PublishSpec` (model.ts:99). +**Symbol:** `PublishSpec` (model.ts:107). **Issue:** `…Spec` is acceptable when paired with a clear noun (`OnlineTableSpec`, `JobSpec`). "Publish" alone reads as a verb; the @@ -73,53 +30,7 @@ which has more room because it lives in the `featurestore` Go package. --- -### 3. `PublishTableResponse.pipelineId` — *pass* — *Still* - -Format is documented as a pipeline ID; aligns with `pipelines/v2` naming. -No issue. - ---- - -### 4. `UpdateOnlineStoreRequest.updateMask` — category 7 (Overly verbose) — *pass* — *Still* - -**Symbol:** `UpdateOnlineStoreRequest.updateMask: FieldMask` -(model.ts:126). - -`updateMask` is the canonical Google AIP-134 name for partial-update masks; -the type `FieldMask` is from `@databricks/sdk-core/wkt`. The -naming is SDK-wide and idiomatic. **Pass.** - ---- - -### 5. `onlineStoreFieldMaskSchema` private but exported via `onlineStoreFieldMask()` — *pass* — *Still* - -**Symbols:** `onlineStoreFieldMaskSchema` (model.ts:221, internal) and -`onlineStoreFieldMask()` (model.ts:231, public). Clean separation: the -schema is private, the helper is exported, and the helper name matches the -Google AIP-134 update-mask vocabulary. **Pass.** - ---- - -### 6. `ListOnlineStoresRequest`/`Response` — category 7 (Overly verbose) — *pass with note* — *Still* - -**Symbols:** `ListOnlineStoresRequest` (model.ts:67), -`ListOnlineStoresResponse` (model.ts:74). - -Names are long (24/25 chars) but match the SDK-wide pattern for paginated -list endpoints. Within the package scope `ListRequest` / `ListResponse` -would suffice — only `online-store` listing exists — but every other TS -package qualifies. **Pass on package consistency.** - ---- - -### 7. Singular `OnlineStore` ⇔ plural `onlineStores` consistency — category 9 (Singular/plural mismatch) — *pass* — *Still* - -`ListOnlineStoresResponse.onlineStores: OnlineStore[]` (model.ts:76) is the -canonical pattern. **Pass.** - ---- - -### 8. `OnlineStore_State` — model.ts:9 — *Still* +### 2. `OnlineStore_State` — model.ts:9 **Why:** `Parent_Nested` underscore-joined identifier is a literal translation of a proto nested-type path into the TS symbol name. The @@ -141,9 +52,9 @@ namespace. --- -### 9. `PublishSpec_PublishMode` — model.ts:27 — *Still* +### 3. `PublishSpec_PublishMode` — model.ts:31 -**Why:** Same `Parent_Nested` proto-namespace leak as finding 8. The +**Why:** Same `Parent_Nested` proto-namespace leak as finding 2. The identifier reads as "PublishSpec's PublishMode" — the enclosing-type prefix is a verbatim port of the proto nested-type name, and the file acknowledges this with the same eslint-disable comment. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md index bada1598..5df1a85e 100644 --- a/.agent/naming-audit/files.md +++ b/.agent/naming-audit/files.md @@ -3,13 +3,12 @@ **Path:** `packages/files/src/v2/` **Versions audited:** v2 -**Total weird names flagged:** 2 +**Total weird names flagged:** 1 ## Summary | Severity | Count | | --- | --- | | High | 1 | -| Low | 1 | ## High severity @@ -29,13 +28,3 @@ export interface CreateRequest { - **Category:** 6 (misleading — name says "create" but action is "open"). - **Suggested name:** `OpenWriteStreamRequest` / `DbfsOpenWriteRequest` (response: `DbfsWriteHandle`). - **Rationale:** Method name should reflect action; right now `create` and `createDirectory` look like sibling actions when they are entirely different (create-handle vs create-resource). - -## Low severity - -### 2. `overwrite` — same — `src/v2/model.ts:36,245,279` - -```ts -overwrite?: boolean | undefined; -``` - -Appears in `CreateRequest`, `PutRequest`, `UploadFileRequest` with subtly different defaults. `UploadFileRequest`'s docstring says "If true or unspecified, an existing file will be overwritten" (default-true), while `CreateRequest` says "specifies whether to overwrite existing file/files" (default not specified, but in fact false on the wire). Same field name, opposite defaults — a footgun. diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md index 1f1f264e..8402505b 100644 --- a/.agent/naming-audit/forecasting.md +++ b/.agent/naming-audit/forecasting.md @@ -19,7 +19,7 @@ #### F1.1 — `done` method on the waiter does not return a boolean of "I'm done waiting" but "operation has reached a terminal state" (LOW) -- **Where:** `client.ts:194-216`. +- **Where:** `client.ts:197-218`. - **Why flagged:** Method `done()` returns `Promise` and performs a poll. A naive reader might assume `done()` reflects internal waiter state (similar to `Promise.resolve(done)` or @@ -29,28 +29,12 @@ ("Checks whether the operation has reached a terminal state.") does clarify this, but the name does not. -#### F1.2 — `createForecastingExperimentWaiter` returns the waiter, - not the response (LOW) -- **Where:** `client.ts:104-115`. -- **Why flagged:** The method name suggests "create a waiter," but - it actually performs the *create* call first and then wraps the - result. The return type - (`CreateForecastingExperimentWaiter`) suggests the second - interpretation correctly, but the verb `create` is overloaded: - the same word is used for the API call and the waiter - instantiation. -- **Suggestion:** Rename to - `createForecastingExperimentAndWait` (mirroring "AndWait" - patterns) or `startForecastingExperiment` (and have the waiter - type be `ForecastingExperimentRun` or similar). The current name - reads as if it merely *constructs* a waiter without side effects. - --- ### 2. Overly verbose #### F2.1 — `ForecastingExperiment` (MEDIUM) -- **Where:** `model.ts:72`. +- **Where:** `model.ts:76`. - **Why flagged:** Inside a package literally named `forecasting`, every type is about forecasting. The `Forecasting` prefix doesn't add signal. Users will write @@ -66,7 +50,7 @@ #### F2.2 — `CreateForecastingExperimentRequest`, `CreateForecastingExperimentResponse`, `GetForecastingExperimentRequest` (MEDIUM) -- **Where:** `model.ts:19, 66, 81`; `index.ts:8-12`. +- **Where:** `model.ts:23, 70, 85`; `index.ts:8-12`. - **Why flagged:** 33-34 character type names. Combined with method names that already say `createForecastingExperiment(...)`, the argument type is highly redundant. Compare typical TS SDK patterns: @@ -78,7 +62,7 @@ per verb, just `CreateRequest`/`CreateResponse`/`GetRequest`. #### F2.3 — `CreateForecastingExperimentWaiter` (HIGH) -- **Where:** `client.ts:146`, `index.ts:3`. +- **Where:** `client.ts:148`, `index.ts:3`. - **Why flagged:** 34 characters. Reads as "Create-Forecasting-Experiment-Waiter". With `Forecasting` removed (F2.1), it becomes `CreateExperimentWaiter` — still long but @@ -88,20 +72,13 @@ for create-style long-running operations, and name it `ExperimentRun` or `Operation`. - **Suggestion:** Rename to `ExperimentRun` (analogous to - `LongRunningOperation` in other SDKs). Combined with F1.2, the - flow becomes - `const run = await client.forecasting.startExperiment(req); + `LongRunningOperation` in other SDKs), so the flow reads + `const run = await client.createForecastingExperiment(req); await run.wait();`. -#### F2.4 — `createForecastingExperimentWaiter` method (HIGH) -- **Where:** `client.ts:104`. -- **Why flagged:** 35 character method name. Same issue as F2.3. -- **Suggestion:** Rename to `startExperiment` (or `createAndWait`) - to match a renamed waiter. - -#### F2.5 — `getForecastingExperiment` / `createForecastingExperiment` +#### F2.4 — `getForecastingExperiment` / `createForecastingExperiment` methods (MEDIUM) -- **Where:** `client.ts:70, 118`. +- **Where:** `client.ts:105, 119`. - **Why flagged:** Inside a `Forecasting` client, the `Forecasting` suffix is repetitive. Compare typical TS SDK shape: `forecasting.experiments.create(...)`, @@ -117,7 +94,7 @@ #### F3.1 — `Waiter` suffix on `CreateForecastingExperimentWaiter` (LOW) -- **Where:** `client.ts:146`. +- **Where:** `client.ts:148`. - **Why flagged:** `Waiter` is a Go SDK pattern for long-running operations. In TS/JS the more common terms are `Operation`, `Poller`, `Run`, or `Tracker`. `Waiter` isn't wrong but it is @@ -130,7 +107,7 @@ ### 4. Reserved-word / built-in collisions #### F4.1 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) -- **Where:** `client.ts:195`. +- **Where:** `client.ts:197`. - **Why flagged:** `done` shadows `IteratorResult.done` (the boolean property returned by iterator `next()`). Defining a `done()` *method* on a non-iterator class is mildly misleading. A reader @@ -161,8 +138,8 @@ | # | Category | Findings | | - | --------------------------------------- | -------- | -| 1 | Misleading names | 2 | -| 2 | Overly verbose | 5 | +| 1 | Misleading names | 1 | +| 2 | Overly verbose | 4 | | 3 | Go-style `Waiter` pattern | 1 | | 4 | Reserved-word collisions | 1 | | 5 | Proto / architectural leaks | 1 | diff --git a/.agent/naming-audit/functions.md b/.agent/naming-audit/functions.md index 6e9244f6..4dfb2e56 100644 --- a/.agent/naming-audit/functions.md +++ b/.agent/naming-audit/functions.md @@ -3,43 +3,24 @@ **Package path:** `/home/parth.bansal/sdk-js/packages/uc/functions/` **Audited files:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` **Domain:** Unity Catalog Functions (SQL / Python UDFs and UDTFs). -**Total weird names flagged:** 14 (rescanned 2026-06-02 after the API -regeneration and LRO/waiter refactor). +**Total weird names flagged:** 9 --- ## Findings -### 1. Single-variant enums surfaced as full enum types +### 1. Misleading names -#### 1.1 `FunctionInfo_SecurityType.DEFINER` (model.ts:59-61) -Single-variant enum with `DEFINER`. The single-valued switch is -surfaced as a full enum type; the variant itself is meaningful (SQL -`SECURITY DEFINER` clause) but the TS-side ergonomics suffer. - ---- - -### 2. Misleading names - -#### 2.1 `specificName` reserved-for-future-use (model.ts:104, 213, 351) +#### 1.1 `specificName` reserved-for-future-use (model.ts:132, 241, 379) Doc: "Specific name of the function; Reserved for future use." A field whose name promises specificity and whose docs admit it's unused is a future trap. Better to omit until it does something. --- -### 3. Reserved-word collisions - -#### 3.1 `options` parameter on every client method -(client.ts:82, 117, 158, 202, 247, 272) — the second parameter is -named `options` and shadows the marshal schema's `options`-style -metadata patterns. +### 2. Go / Java-style names ---- - -### 4. Go / Java-style names - -#### 4.1 `Dependency.value.$case` discriminated union encoding (model.ts:165-170) +#### 2.1 `Dependency.value.$case` discriminated union encoding (model.ts:192-199) The `$case` discriminator with `value`-keyed payload is a ts-proto serialiser idiom. TS-native discriminated unions usually keep the discriminator at the top level (`{type: 'function', function: {…}}`) @@ -47,20 +28,20 @@ rather than wrapping in `value`. Functional, but visibly Go/proto. --- -### 5. Field contradicting type domain +### 3. Field contradicting type domain -#### 5.1 `CreateFunction` contains read-only output fields +#### 3.1 `CreateFunction` contains read-only output fields `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, -`fullName`, `functionId`, `browseOnly` (model.ts:126-136). These are +`fullName`, `functionId`, `browseOnly` (model.ts:149-164). These are server-populated; a creator setting them is at best ignored. The type's domain is "create request body" but its shape contradicts -that. Mirror issue in `UpdateFunctionRequest` (model.ts:373-383). +that. Mirror issue in `UpdateFunctionRequest` (model.ts:396-411). --- -### 6. Proto-architectural-leak naming +### 4. Proto-architectural-leak naming -#### 6.1 `FunctionInfo_ParameterStyle` — model.ts:42 +#### 4.1 `FunctionInfo_ParameterStyle` — model.ts:54 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. @@ -70,28 +51,28 @@ Rationale: TypeScript enums do not need parent-qualifying via underscore. The leak exposes the upstream proto schema's nested-type layout to TS consumers. -#### 6.2 `FunctionInfo_RoutineBody` — model.ts:47 +#### 4.2 `FunctionInfo_RoutineBody` — model.ts:63 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. Suggested: `RoutineBody`. -Rationale: Same as 6.1. +Rationale: Same as 4.1. -#### 6.3 `FunctionInfo_SecurityType` — model.ts:59 +#### 4.3 `FunctionInfo_SecurityType` — model.ts:79 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. Suggested: `SecurityType`. -Rationale: Same as 6.1. +Rationale: Same as 4.1. -#### 6.4 `FunctionInfo_SqlDataAccess` — model.ts:64 +#### 4.4 `FunctionInfo_SqlDataAccess` — model.ts:88 Why: `Parent_Child` underscore identifier is a proto/ts-proto serialiser idiom for nested message/enum types. Category: Proto suffix/infix. Suggested: `SqlDataAccess`. -Rationale: Same as 6.1. +Rationale: Same as 4.1. -#### 6.5 `Dependency.value.$case` discriminated-union shape — model.ts:165-170 +#### 4.5 `Dependency.value.$case` discriminated-union shape — model.ts:192-199 Why: `{$case: 'foo'; foo: T}` is the ts-proto serialiser's encoding for oneof fields; native TS discriminated unions normally use a top-level discriminator key, not a `value`-wrapped `$case` envelope. @@ -100,39 +81,16 @@ Suggested: Flatten to `{type: 'function'; function: FunctionDependency} | ...` at the top level. Rationale: The `$case` discriminator key and the `value`-wrapped envelope visibly reflect proto oneof semantics. Already noted in -§4.1; re-flagged here as a proto-architectural leak. +§2.1; re-flagged here as a proto-architectural leak. --- ## Observations ### A. `fullNameArg` URL substitution silently allows empty string -(client.ts:119, 160, 274) — `${req.fullNameArg ?? ''}` — if +(client.ts:120, 162, 278) — `${req.fullNameArg ?? ''}` — if `fullNameArg` is undefined, the URL silently becomes `/api/2.1/unity-catalog/functions/` and the request will fail on the server. The naming (`fullNameArg`) and the substitution behaviour together hide what should be a required parameter. Worth surfacing via a non-optional type or a typed assertion. - -### B. `marshalUpdateFunctionRequestSchema` serialises `fullNameArg` into the body -(model.ts:802) `fullNameArg` is a path parameter — but the marshal -schema produces a JSON field `full_name_arg`. Either the server -tolerates the extra field or this is a bug. The `Arg` suffix lets -the bug hide. - -### C. Package-name proximity to JavaScript reserved word -The package is named `@databricks/sdk-uc-functions` and the npm -workspace path is `packages/uc/functions/`. `function` is a JS reserved -word; `functions` is not, but the proximity is jarring. Importers -will often write -`import * as functions from '@databricks/sdk-uc-functions/v1'` which -sets up `functions.createFunction(…)` — the local binding `functions` -shadows nothing, but the combination of the package name and the -`Dependency.value.$case === 'function'` pattern creates a vocabulary -where "function" is overloaded. - -### D. `parameterStyle: FunctionInfo_ParameterStyle` with one variant `S` -The most extreme case of a single-purpose API surface: a long enum -type holding a one-letter variant, only ever set to `S`, marshaled -as the JSON string `"S"`. Three layers of indirection for a constant. -See §6.1. diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md index 3aeb1e09..040523bf 100644 --- a/.agent/naming-audit/genie.md +++ b/.agent/naming-audit/genie.md @@ -2,127 +2,113 @@ **Path:** `packages/genie/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 18 +**Total weird names flagged:** 16 ## Summary | Severity | Count | | --- | --- | | High | 6 | -| Medium | 5 | +| Medium | 4 | | Low | 6 | -| Observation | 1 | ## High severity -### 1. Method naming wildly inconsistent: 28 of 30 methods are `genieXxx`, 2 are bare — `src/v1/client.ts:133,1121` -- **Why weird:** `client.ts` exposes 30 public methods. 28 are prefixed `genie` (e.g. `genieGetSpace`, `genieListSpaces`, `genieTrashSpace`). Two are not: `createSpace` (line 133) and `updateSpace` (line 1121). Reader calling `client.createSpace(...)` then trying `client.deleteSpace(...)` discovers the delete equivalent is named `genieTrashSpace(...)`. The "trash" method name is also inconsistent (see #2). +### 1. Method naming wildly inconsistent: 26 of 28 public methods are `genieXxx`, 2 are bare — `src/v1/client.ts:132,1152` +- **Why weird:** `client.ts` exposes 28 public methods. 26 are prefixed `genie` (e.g. `genieGetSpace`, `genieListSpaces`, `genieTrashSpace`). Two are not: `createSpace` (line 132) and `updateSpace` (line 1152). Reader calling `client.createSpace(...)` then trying `client.deleteSpace(...)` discovers the delete equivalent is named `genieTrashSpace(...)`. The "trash" method name is also inconsistent (see #2). - **Category:** 17 (inconsistent action verbs / prefix), 6 (misleading — autocomplete shows two naming families). - **Suggested name:** Pick one and apply uniformly. Either drop the `genie` prefix everywhere (the package is already `@databricks/sdk-genie` — the prefix is tautological) or keep it everywhere (`genieCreateSpace`, `genieUpdateSpace`). Strongly prefer the former. - **Rationale:** Every method in the client is on a Genie `Client` imported from `@databricks/sdk-genie`. Prefixing every method with `genie` is type-suffix tautology — `client.genieListSpaces()` is no clearer than `client.listSpaces()`. The current half-prefixed surface is the worst of both options. -### 2. `genieTrashSpace` is the only delete-style method named `Trash` — `src/v1/client.ts:1099` +### 2. `genieTrashSpace` is the only delete-style method named `Trash` — `src/v1/client.ts:1129` - **Why weird:** All other delete methods are `genieDeleteX` (`genieDeleteConversation`, `genieDeleteConversationMessage`). The space delete is `genieTrashSpace` and the request type is `GenieTrashSpaceRequest`. JSDoc says "Move a Genie Space to the trash" — i.e. it is a soft delete, not a destructive one — but the name still breaks the `delete*` pattern. - **Category:** 17 (inconsistent action verb), 14 (Go/Java-style "trash" verb is uncommon in JS SDKs). - **Suggested name:** `genieDeleteSpace` (matches the other deletes; document the soft-delete semantics in JSDoc) or, if soft-delete needs to be explicit, mirror it on the messages too (`genieTrashConversationMessage`). - **Rationale:** Inconsistency forces every reader to learn the exception. The "soft delete" semantic can be conveyed by docs without leaking into the verb. -### 3. `genieExecuteMessageAttachmentQuery` vs `genieGetMessageAttachmentQueryResult` vs `genieGenerateDownloadFullQueryResult` — three different verbs for retrieving the same data — `src/v1/client.ts:328,605,422` +### 3. `genieExecuteMessageAttachmentQuery` vs `genieGetMessageAttachmentQueryResult` vs `genieGenerateDownloadFullQueryResult` — three different verbs for retrieving the same data — `src/v1/client.ts:337,621,433` - **Why weird:** The package has at least four "get the SQL result" entry points (`Execute`, `Get`, `Generate`, plus `genieGetQueryResultByAttachment`/`genieGetMessageQueryResult` deprecated aliases). Each uses a different verb stem. `Execute` re-runs the query; `Get` reads the result; `Generate` initiates a download — but the user has to read each docstring to learn that. - **Category:** 17 (inconsistent action verbs), 7 (overly verbose). - **Suggested name:** Group with verb pairs: `runMessageAttachmentQuery` (re-execute) / `getMessageAttachmentQueryResult` (read) / `startMessageAttachmentDownload` + `getMessageAttachmentDownload` (download flow). - **Rationale:** The verbs `Execute` / `Get` / `Generate` overlap in everyday English; the type system gives no hint which one to call first. The current names are generator-faithful but unhelpful for users. -### 4. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1458` +### 4. `GenieSpace` — domain meaning of "Space" is opaque without docs — `src/v1/model.ts:1540` - **Why weird:** The central noun. A `GenieSpace` is a "workspace scoped to a Genie deployment", but the word `Space` is one of the most overloaded terms in the Databricks SDK (it also appears in workspace, mlflow registered model, dashboards, etc.). Type doc on the class itself is one line ("Genie space ID"). Reader sees `GenieSpace` and has to consult external docs to learn whether it's a folder, a user-permission boundary, a model-deployment, or something else. - **Category:** 1 (vague/generic), 15 (generic field name losing meaning — `Space`). - **Suggested name:** `GenieRoom`, `GenieAgent`, `GenieDeployment`, or at minimum a JSDoc on the type explaining what a "space" *is* (warehouse + datasets + instructions). If "Space" is the Databricks product-marketing term, document it inline. - **Rationale:** This is the package's central concept. Letting it stand on a single word that means "container" is a documentation gap as much as a naming bug. -### 5. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:533` +### 5. `EvaluationStatusType` — type name has redundant `Type` suffix — `src/v1/model.ts:543` - **Why weird:** The type is named `EvaluationStatusType`. Every enum is by definition a "type", so the suffix adds nothing. Peer enums in the same file use bare-noun names (`ScoreReason`, `ThoughtType` — though `ThoughtType` is itself debatable, `Format`, `MessageStatus_MessageStatus`). - **Category:** 8 (redundant `Type` suffix on enum name). - **Suggested name:** `EvaluationStatus`. - **Rationale:** This enum is exposed on `GenieEvalResult.status` and `GenieEvalResultDetails.evalRunStatus`; trimming the suffix shortens both call sites without losing information. -### 6. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:828` -- **Why weird:** The type name stacks three architectural-layer words: `Service` (server-side tier), `Exception` (Java vocabulary), and `Proto` (wire-format suffix). None of these belong in a public TS SDK surface — the SDK exposes errors, not Java exceptions, and not proto messages. JSDoc reinforces the leak: "Serialization format for DatabricksServiceException. Note the definition of this message should be in sync with DatabricksServiceExceptionWithDetailsProto defined in /api-base/proto/exception_with_details.proto". The companion schema is `unmarshalDatabricksServiceExceptionProtoSchema` (line 1854), propagating the leak. +### 6. `DatabricksServiceExceptionProto` — proto-arch-leak: `Service` mid + `Proto` suffix — `src/v1/model.ts:916` +- **Why weird:** The type name stacks three architectural-layer words: `Service` (server-side tier), `Exception` (Java vocabulary), and `Proto` (wire-format suffix). None of these belong in a public TS SDK surface — the SDK exposes errors, not Java exceptions, and not proto messages. JSDoc reinforces the leak: "Serialization format for DatabricksServiceException. Note the definition of this message should be in sync with DatabricksServiceExceptionWithDetailsProto defined in /api-base/proto/exception_with_details.proto". The companion schema is `unmarshalDatabricksServiceExceptionProtoSchema` (line 1936), propagating the leak. - **Category:** Proto-architectural-leak (`Proto` suffix, `Service` mid), 14 (Java-style `Exception` vocabulary in TS), 12 (duplicate concept — the SDK already has `ApiError`). - **Suggested name:** Delete the type and reuse `ApiError` from `@databricks/sdk-databricks/apierror`. If the wire-format shape must be kept locally, name it `ApiErrorPayload` or `WireError` and treat it as an internal marshal-time type, not a public export. - **Rationale:** `Service`, `Exception`, and `Proto` are all backend implementation vocabulary that should never reach the user-facing SDK surface. The type is unused by any public method body, making the leak gratuitous. ## Medium severity -### 7. `GenieStartConversationMessageRequest` — type name conflates `Conversation` and `Message` — `src/v1/model.ts:1483` -- **Why weird:** Request type for `genieStartConversation`. Name contains *both* `Conversation` and `Message`, but the body has only `spaceId` and `content` (`{ spaceId?: string; content?: string; }`). It is not a request to start a "conversation message" — it is a request to start a conversation by sending an initial message. Compare with `GenieStartConversationResponse` (no `Message` in the name). -- **Category:** 6 (misleading — name suggests a compound entity that doesn't exist), 7 (overly verbose). -- **Suggested name:** `StartConversationRequest` (matches the response). -- **Rationale:** Reader has to parse the doc to learn what "ConversationMessage" means here. The companion response name (`GenieStartConversationResponse`) silently drops `Message` — internal inconsistency. - -### 8. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:888` +### 7. `GenieAttachment.attachment` discriminated-union field has the same name as its parent — `src/v1/model.ts:970` - **Why weird:** `GenieAttachment.attachment` is a `{ $case: 'text' | 'query' | 'suggestedQuestions', … } | undefined` field. Reading `myAttachment.attachment.text` reads as "the attachment of the attachment", and the parent `GenieAttachment` also has a peer field `attachmentId`. The shape mixes the discriminator field with a flat id field. - **Category:** 15 (generic field name losing meaning). - **Suggested name:** Hoist to a top-level discriminated union so the variant lives at the type level rather than under a nested same-named field: `type GenieAttachment = ({kind: 'text', text: TextAttachment} | {kind: 'query', query: GenieQueryAttachment} | {kind: 'suggestedQuestions', suggestedQuestions: GenieSuggestedQuestionsAttachment}) & {id?: string}`. - **Rationale:** Same struct, single name; the parent-name-shaped field name confuses readers traversing nested attachments. -### 9. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1085` +### 8. `GenieEvalRunResponse` is the entity type, not just a "response" — `src/v1/model.ts:1167` - **Why weird:** Type name ends `Response`, suggesting an HTTP envelope. Actually it is the eval-run *entity* (resource): it has `evalRunId`, status fields, counts, timestamps. It is returned from `createEvalRun`, `getEvalRun`, and nested as elements inside `listEvalRuns`. Compare with `GenieListEvalRunsResponse` (true envelope). - **Category:** 8 (redundant suffix `Response` for an entity), 6 (misleading suffix). - **Suggested name:** `GenieEvalRun` (the resource). Then `getEvalRun(): Promise`. - **Rationale:** Every other entity in the package is `GenieX` (no suffix). The `Response` suffix here is a generator artefact: the API returns a single instance, the generator wrote it as `*Response`. -### 10. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1145` +### 9. `GenieGenerateDownloadFullQueryResultResponse` — type name is a sentence — `src/v1/model.ts:1227` - **Why weird:** 7 words concatenated: `Genie + Generate + Download + Full + Query + Result + Response` = 49 characters. Verb-tense issue: `Generate` is present tense; everywhere else in the API we use noun-phrase types. - **Category:** 7 (overly verbose), 13 (verb-tense inconsistency). - **Suggested name:** `DownloadStartResponse` / `StartDownloadResponse` (the action is "start a download flow"); the body is `downloadId` + `downloadIdSignature`. - **Rationale:** This is the longest single identifier in the file. Generator-faithful, but the name is wider than most callers' editors. -### 11. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1134,1161` -- **Why weird:** Same as #10 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). +### 10. `GenieGenerateDownloadFullQueryResultRequest` / `GenieGetDownloadFullQueryResultRequest` — pairs spell out long ladder of nouns — `src/v1/model.ts:1216,1243` +- **Why weird:** Same as #9 — these are the request twins. The phrase "Full Query Result" is also under-qualified: it distinguishes from "partial" (a `GetMessageAttachmentQueryResult` is also a full result, just inline). - **Category:** 7 (overly verbose), 6 (misleading — `Full` does not actually contrast with `Partial` anywhere). - **Suggested name:** Pair `StartDownloadRequest` + `GetDownloadRequest`, or `BeginDownloadRequest` + `PollDownloadRequest`. - **Rationale:** The download-flow methods are conceptually a state machine — name the state transitions. ## Low severity -### 12. `Result` type name — too generic — `src/v1/model.ts:1589` +### 11. `Result` type name — too generic — `src/v1/model.ts:1671` - **Why weird:** A top-level type named `Result` in a public package is the most-vague-possible name. In the genie package alone there are also `ResultData`, `ResultManifest`, `GenieResultMetadata`, `StatementResponse.result`, `GenieEvalResult`. The bare `Result` carries a 4-field SQL execution shape. - **Category:** 1 (vague/generic). - **Suggested name:** `SqlQueryResult` / `MessageQueryResult` / `QueryResultSummary`. - **Rationale:** `Result` is also a TS standard-library-adjacent name (`Result` from many libraries); collisions are likely. -### 13. `GenieSuggestedQuestionsAttachment` — payload type name redundant with parent — `src/v1/model.ts:903` +### 12. `GenieSuggestedQuestionsAttachment` — payload type name redundant with parent — `src/v1/model.ts:1582` - **Why weird:** The payload type is `GenieSuggestedQuestionsAttachment` for the discriminator value `'suggestedQuestions'` on `GenieAttachment`. The word `Attachment` is already in the parent (`GenieAttachment`) — three repetitions of "attachment" / "suggested questions" / "questions". - **Category:** 7 (overly verbose), 20 (type-suffix tautology). - **Suggested name:** Payload type `SuggestedQuestions { questions: string[] }`. - **Rationale:** Reduce noise per attachment. -### 14. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:196,1072` -- **Why weird:** Same pattern as flagged in the `database` audit (#14): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. +### 13. `genieCreateConversationMessageWaiter` and `genieStartConversationWaiter` — `Waiter` suffix — `src/v1/client.ts:1182,1259` +- **Why weird:** Same pattern as flagged in the `database` audit (#2): a "Waiter" class with a verb-prefixed name. Reads as "the *create-conversation-message* waiter". The class itself is named `GenieCreateConversationMessageWaiter`. - **Category:** 6 (misleading verb-as-prefix), 14 (Go-style poll-helper naming). - **Suggested name:** `MessagePoller`, `MessageCompletionPoller`, `MessageWait`. Or fold into `createConversationMessage({wait: true})`. - **Rationale:** Class names should be noun phrases; current name reads as a verb. -### 15. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:938, client.ts:165` +### 14. `GenieCreateConversationMessage` — verb chain `Create + Conversation + Message` — `src/v1/model.ts:1020, client.ts:165` - **Why weird:** Reads as "create a conversation message" — but `conversation message` is not a thing, it's a "message inside a conversation". The triple noun ladder also appears in `GenieDeleteConversationMessage`, `GenieGetConversationMessage`, `GenieListConversationMessages`. - **Category:** 7 (overly verbose). - **Suggested name:** `AddMessage` / `PostMessage` (verb-noun pair) on the client; type names `AddMessageRequest`. Or shorten to `Conversation.AddMessage(...)` if the SDK supported sub-clients. - **Rationale:** "Create a conversation message" reads awkwardly; "send a message" or "add a message" is shorter and clearer. -### 16. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:735, model.ts:1255` +### 15. `genieListConversationComments` returns `comments` — plural matches but parent path drops "Message" — `src/v1/client.ts:755, model.ts:1335` - **Why weird:** `ListConversationCommentsResponse.comments: GenieMessageComment[]`. The item type is `GenieMessageComment` but the response field is `comments` (without `messageComments`). At item level, the parent is `GenieMessageComment` (only modelled as a comment-on-a-message — no separate `ConversationComment` type), so the endpoint name `genieListConversationComments` is misleading: it lists *message* comments across the whole conversation. - **Category:** 6 (misleading method name), 17 (inconsistent naming between method, type, and field). - **Suggested name:** `listMessageCommentsInConversation` or `listAllMessageComments`. Or introduce a `ConversationComment` type. - **Rationale:** Reader expects a conversation-level comment thread; gets back message-level comments. -### 17. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:667` +### 16. `genieGetQueryResultByAttachment` — `By` clause is Java/Spring-style — `src/v1/client.ts:685` - **Why weird:** Method named `GetXByY` follows Spring Data convention. Other JS SDKs prefer flat verb-noun. Also the body has the same fields as `genieGetMessageAttachmentQueryResult` — they are duplicates (one path-segment ordering differs). - **Category:** 14 (Java/Spring-style naming), 12 (duplicate concept). - **Suggested name:** Mark as `@deprecated` (already partially), then remove. - **Rationale:** Cleanup; clients should migrate to the canonical name. - -## Observations - -### 18. `pageSize` / `pageToken` casing — `src/v1/model.ts:1248,1250,1266,1268,...` -- **Observation:** Standard pagination fields; this is fine. Noted to confirm consistency across the package. -- **Suggested name:** N/A. -- **Rationale:** Confirms the package's pagination naming is consistent. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md index 22bc7986..badfc8ea 100644 --- a/.agent/naming-audit/gitcredentials.md +++ b/.agent/naming-audit/gitcredentials.md @@ -5,8 +5,7 @@ **Package name:** `@databricks/sdk-gitcredentials` (lowercased compound — the camel-case domain term is "Git credentials", so the package directory and module name both drop the obvious word boundary). -**Total weird names flagged:** 4 -**Last rescan:** 2026-06-02 (post regen, re-validated against current source) +**Total weird names flagged:** 3 --- @@ -16,8 +15,7 @@ module name both drop the obvious word boundary). |---|------|------|------|----------|----------|-------------------| | 1 | `CreateCredentialsRequest` named with plural noun | model.ts:5 | interface | High | 9 Singular/plural mismatches | The request creates *a single* credential. The name uses the plural "Credentials". The wire endpoint `POST /api/2.0/git-credentials` is plural because that's the collection URL, but the request type is singular. Should be `CreateCredentialRequest`. (Compare `Credential` itself — the resource singular is already chosen.) | | 2 | `UpdateCredentialsRequest`, `DeleteCredentialsRequest`, `GetCredentialsRequest` named with plural | model.ts:149, 97, 107 | interface set | High | 9 Singular/plural mismatches | Same as #1 — three more cases. `UpdateCredentialsRequest` updates one credential (the JSDoc on the client method confirms: "Updates the specified Git credential"). `DeleteCredentialsRequest` deletes one. `GetCredentialsRequest` gets one. All three should be singular. | -| 3 | `ListCredentialsResponse.credentials` field | model.ts:146 | field | Low | (none) | Generic but correct — the response is the array, the field naming it `credentials` (plural) matches what is inside. (Listing for completeness.) | -| 4 | `GitCredentialsClient.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:80, 143, 177, 211, 109 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | +| 3 | `GitCredentialsClient.createCredentials` / `getCredentials` / `listCredentials` / `updateCredentials` / `deleteCredentials` (plural method names) | client.ts:79, 144, 179, 214, 109 | method set | High | 9 Singular/plural mismatches | Five methods all named with the plural "Credentials" even though four of them act on a single credential at a time:
- `createCredentials(req)` creates **one** credential.
- `getCredentials(req)` gets **one** (selected by `id`).
- `updateCredentials(req)` updates **one**.
- `deleteCredentials(req)` deletes **one**.
- `listCredentials(req)` is the only legitimately plural one.
TS idiom for CRUD methods is singular for one-record operations (`createX`/`getX`/`updateX`/`deleteX`) and plural for collection ones (`listXs`/`searchXs`). The five-method API mixes the two and reads as "createCredentials" — i.e., a bulk create. | --- @@ -42,7 +40,7 @@ await client.createCredential({gitProvider: 'gitHub', ...}); Recommendation: keep `listCredentials` (plural — list returns many) but rename the four single-resource methods and their request types to -singular. See #1, #2, #4. +singular. See #1, #2, #3. --- diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md index 292bb073..8e78fa5c 100644 --- a/.agent/naming-audit/globalinitscripts.md +++ b/.agent/naming-audit/globalinitscripts.md @@ -16,10 +16,10 @@ | Severity | Count | | -------- | ----- | -| High | 1 | +| High | 0 | | Medium | 3 | | Low | 0 | -| **Total**| **4** | +| **Total**| **3** | --- @@ -29,17 +29,16 @@ | ID | Symbol | Severity | Issue | | ----- | ----------------------------------------------- | -------- | ----- | -| O-01 | `CreateGlobalInitScriptRequest` / `DeleteGlobalInitScriptRequest` / `GetGlobalInitScriptRequest` / `UpdateGlobalInitScriptRequest` / `ListGlobalInitScriptsRequest` (`model.ts:5`, `27`, `35`, `66`, `60`) | High | These are method-aligned request types but every type spells out `GlobalInitScript` in full plus the `Request` suffix, producing ~28-32-char identifiers for one-off request bodies. Since the surrounding namespace is already `globalinitscripts`, peers in other packages use shorter forms like `CreateRequest`, `CreatePolicy`, `CreateCluster`. The Databricks SDK convention is `CreateRequest`, but here `Entity = GlobalInitScript` so each verb-typename pair runs long. Inherited from the API; flagged as an upstream/codegen-level concern. | -| O-02 | `GlobalInitScriptDetails` (entity name, `model.ts:40`) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | +| O-01 | `GlobalInitScriptDetails` (entity name, `model.ts:40`) | Medium | The entity is named `*Details` whereas peer packages (e.g. `Policy`, `Cluster`) name the entity after the resource. `GlobalInitScript` would be the consistent name; the `Details` suffix adds 7 chars without disambiguation (there is no plain `GlobalInitScript` type to disambiguate from). The Go SDK mirrors this name, so this is a 1:1 port concern. | ### 2.2 Go / Java-style names | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix, `model.ts:40`) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-02. | +| G-01 | `GlobalInitScriptDetails` (Java-style "Details" suffix, `model.ts:40`) | Medium | Suffix `Details` is reminiscent of Java DTO conventions (`UserDetails`, `OrderDetails`). TS/JS naming tends to use the bare entity noun. See O-01. | ### 2.3 Type-suffix tautology | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| TS-01 | `GlobalInitScriptDetails` (`model.ts:40`) | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-02 / G-01. | +| TS-01 | `GlobalInitScriptDetails` (`model.ts:40`) | Medium | The entity name encodes both the resource (`GlobalInitScript`) and a descriptive suffix (`Details`). With no peer `GlobalInitScript` type to distinguish from, the suffix is purely redundant. See O-01 / G-01. | diff --git a/.agent/naming-audit/grants.md b/.agent/naming-audit/grants.md deleted file mode 100644 index 7dfa82c5..00000000 --- a/.agent/naming-audit/grants.md +++ /dev/null @@ -1,22 +0,0 @@ -# Naming Audit: grants - -**Path:** `packages/uc/grants/src/v1/` -**Versions audited:** v1 -**Total weird names flagged:** 1 - -## Summary -| Severity | Count | -| --- | --- | -| Medium | 1 | - ---- - -## Medium severity - -### 1. `EffectivePrivilegeAssignment` — `src/v1/model.ts:20` -- **Why weird:** Three-word PascalCase name (`Effective` + `Privilege` + `Assignment`) that on first read parses as "Effective Privilege" / "Assignment" but on second read could parse as "Effective" / "Privilege Assignment". The conceptual model is "the privilege assignment that effectively applies (because of inheritance)", which the doc-comment confirms — but the name doesn't disambiguate. -- **Category:** 7 (overly verbose). -- **Suggested name:** Possibly leave as-is; alternative is `EffectiveAssignment` (drop `Privilege` since `Assignment` is privilege-specific in this file). -- **Rationale:** Marginal; flagged for symmetry with `EffectivePrivilege` (line 5). - ---- diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md index ab8eebd9..9b8f6a2a 100644 --- a/.agent/naming-audit/instancepools.md +++ b/.agent/naming-audit/instancepools.md @@ -5,10 +5,10 @@ **Version audited:** `v2` **Files audited:** -- `src/v2/model.ts` (1250 lines, read in full) -- `src/v2/client.ts` (224 lines, read in full) -- `src/v2/utils.ts` (156 lines, read in full) -- `src/v2/index.ts` (43 lines, read in full) +- `src/v2/model.ts` (1178 lines, read in full) +- `src/v2/client.ts` (228 lines, read in full) +- `src/v2/utils.ts` (157 lines, read in full) +- `src/v2/index.ts` (37 lines, read in full) --- @@ -18,170 +18,42 @@ | ------------ | ----- | | High | 3 | | Medium | 3 | -| Low | 25 | -| Observation | 2 | -| **Total** | **33**| +| Low | 2 | +| **Total** | **8** | --- ## 1. Findings -### 1.1 Cryptic abbreviations — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| C-01 | `EbsVolumeType` (acronym in name) | Low | EBS = Elastic Block Store. Well-known among AWS users; OK. | -| C-02 | `LRS` in `AzureDiskVolumeType.PREMIUM_LRS` / `STANDARD_LRS` | Low | "Locally Redundant Storage" — standard Azure term. JSDoc explains; OK. | - -### 1.2 Misleading names — High +### 1.1 Misleading names | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | M-01 | `editInstancePool()` / `EditInstancePoolRequest` | Medium | Conventional REST/CRUD verb in TS is **update**. `clusterpolicies` (audit #M-01) and `clusters` make the same choice for the wire path `/edit`. Across-package inconsistency: most newer Databricks APIs use `update*`. Flag for upstream alignment. | | M-02 | `InstancePoolStatus` | High | The type carries *only* `pendingInstanceErrors`. The name promises a general "status" but the shape exposes only errors. `InstancePoolPendingErrors` or `InstancePoolFailures` would be more truthful. (`InstancePoolState` is the actual lifecycle state, on the entity itself.) | -| M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 28 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | - -### 1.3 Overly verbose / Redundant suffixes — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| O-01 | `PendingInstanceError` | Low | Three-word type for two-field shape (`instanceId`, `message`). OK. | - -### 1.4 Singular / plural mismatches — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| P-01 | `preloadedDockerImages: DockerImage[]` | Low | Plural array; JSDoc says "Custom Docker Image BYOC" but the field accepts multiple. OK. | -| P-02 | `ListInstancePoolsRequest` (request) vs `listInstancePools()` (method) | Low | Consistent plural. | -| P-03 | `ListInstancePoolsResponse.instancePools: InstancePoolAndStats[]` | Low | Plural array — correct. | - -### 1.5 Reserved-word collisions — Medium +| M-03 | `InstancePoolAndStats` | High | The "AndStats" suffix implies it carries the pool *plus* statistics, but the type also carries `status`, `state`, `defaultTags`, and all 16 configuration fields. The "And" naming pattern is a Go-style listing-result idiom — TS readers expect just a single entity name. Consider `InstancePoolSummary` or `InstancePoolListEntry`. | -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| R-01 | `DockerImage.credsOneof.$case === 'basicAuth'.basicAuth: DockerBasicAuth` | Low | `basicAuth` is not a reserved word but is duplicated across the `$case` discriminator and the embedded field — `library.lib.basicAuth.basicAuth` style access. | -| R-02 | None of the type names collide with TS reserved words. | — | OK. | - -### 1.6 Verb-tense inconsistency — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| T-01 | `createInstancePool`, `deleteInstancePool`, `editInstancePool`, `getInstancePool`, `listInstancePools` | Low | All present-tense imperative — consistent. | -| T-02 | `preloadedDockerImages`, `preloadedSparkVersions` (past participle) | Low | Standard for fields that describe a pre-applied state. OK. | - -### 1.7 Go / Java-style names — Medium +### 1.2 Go / Java-style names | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | G-01 | `InstancePoolAndStats` (the "X-AndY" naming pattern) | Medium | "And" combinators in type names are a Go-isms (e.g., `ResultAndError`). TS usually picks a concept name. | -### 1.8 Generic field names losing meaning — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| F-01 | `DockerImage.url` (outside of `DockerImage`) | Low | Standard. OK in context. | -| F-02 | `DockerBasicAuth.username` / `password` | Low | Standard. OK. | -| F-03 | `InstancePoolStatus.pendingInstanceErrors[]` | Low | OK. | -| F-04 | `NodeTypeFlexibility.alternateNodeTypeIds` (outside the wrapper) | Low | Standalone, `alternateNodeTypeIds: string[]` is clear. OK. | - -### 1.9 Field contradicting type domain — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| K-01 | None observed. All fields are within their type's domain. | — | OK. | - -### 1.10 Inconsistent action verbs — Medium +### 1.3 Inconsistent action verbs | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | AV-01 | `editInstancePool()` vs ecosystem-standard `update` | Medium | Same as `clusterpolicies` AV-01. Driven by wire path `/edit`. Newer Databricks resources expose `update*`. Cross-package inconsistency. | -| AV-02 | `getInstancePool()` (singular) vs `listInstancePools()` (plural) | Low | Correct REST convention. OK. | -| AV-03 | `createInstancePool()` / `deleteInstancePool()` / `editInstancePool()` / `getInstancePool()` / `listInstancePools()` — only five verbs | Low | No `start`, `stop`, `pin`, etc. — instance pools are stateless from the API standpoint; the lifecycle is implicit via fewer endpoints than `clusters`. Consistent. | -### 1.11 Long enum values — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| L-01 | `EbsVolumeType.THROUGHPUT_OPTIMIZED_HDD` (24 chars) | Low | Standard AWS terminology; OK. | -| L-02 | `AzureDiskVolumeType.STANDARD_LRS` (12 chars) | Low | Short. OK. | - -### 1.12 Underspecified IDs — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| I-01 | `instancePoolId` | Low | Well-specified — scope = instance pool. No collisions. OK. | -| I-02 | `nodeTypeId` | Low | Scoped correctly. OK. | -| I-03 | `PendingInstanceError.instanceId` | Low | Scoped. OK. | -| I-04 | `policyFamilyId` is *not* in this package; `clusterId` is *not* in this package — only `instancePoolId` and `nodeTypeId` IDs appear. | Observation | Clean. | -| I-05 | `NodeTypeFlexibility.alternateNodeTypeIds: string[]` | Low | Plural array of node-type IDs; scoped. OK. | -| I-06 | `InstancePoolAwsAttributes.zoneId` / `InstancePoolGcpAttributes.zoneId` | Low | Both reuse `zoneId` for the AWS availability zone ("us-west-2a") and GCP availability zone ("us-west1-a"). Same name, two slightly different value formats. Acceptable cross-cloud abstraction. | - -### 1.13 Type-suffix tautology — Medium +### 1.4 Type-suffix tautology | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | | TS-01 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-01). Doubly off. | -| TS-02 | `NodeTypeFlexibility` | Low | "Flexibility" is the noun-form of a feature, not a type-suffix tautology. OK. | -| TS-03 | `DiskSpec` | Low | `Spec` is acceptable, but combined with each field's `disk*` prefix the type-name still echoes. | -| TS-04 | `EbsVolumeType`, `AzureDiskVolumeType` | Low | `VolumeType` / `DiskVolumeType` — standard cloud-storage terminology. OK. | - -### 1.14 Other observations - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| X-01 | `client.ts:199` `_req: ListInstancePoolsRequest` for empty request type | Observation | Generator artefact: empty request type still produced and prefixed `_` to satisfy lint. | - -### 1.15 Proto-architectural leaks - -### 1. `CreateInstancePoolRequest_CustomTagsEntry` — model.ts:168 - -**Why:** Proto-nested map-entry type. Protobuf compiles `map` fields -into a synthetic `*_Entry` message; TypeScript expresses maps as -`Record` and never needs this entry shape. The type is exported but -unused by the request, which uses `Record` directly -(line 122). -**Category:** Proto suffix/infix. -**Suggested:** Delete the type. -**Rationale:** Dead proto-codegen artefact with no consumer in TS. - -### 2. `EditInstancePoolRequest_CustomTagsEntry` — model.ts:349 - -**Why:** Same proto-map-entry artefact as #1. -**Category:** Proto suffix/infix. -**Suggested:** Delete. -**Rationale:** Same as #1. - -### 3. `GetInstancePoolResponse_CustomTagsEntry` — model.ts:470 - -**Why:** Same proto-map-entry artefact as #1 — Protobuf's synthetic -`*_Entry` message for a `map` field, which TypeScript expresses as -`Record`. The type is exported but has no TS consumer. -**Category:** Proto suffix/infix. -**Suggested:** Delete. -**Rationale:** Same as #1. - -### 4. `GetInstancePoolResponse_DefaultTagsEntry` — model.ts:486 - -**Why:** Same proto-map-entry artefact as #1. -**Category:** Proto suffix/infix. -**Suggested:** Delete. -**Rationale:** Same as #1. - -### 5. `InstancePoolAndStats_CustomTagsEntry` — model.ts:599 - -**Why:** Same proto-map-entry artefact as #1. -**Category:** Proto suffix/infix. -**Suggested:** Delete. -**Rationale:** Same as #1. - -### 6. `InstancePoolAndStats_DefaultTagsEntry` — model.ts:615 -**Why:** Same proto-map-entry artefact as #1. -**Category:** Proto suffix/infix. -**Suggested:** Delete. -**Rationale:** Same as #1. +### 1.5 Proto-architectural leaks -### 7. `marshalCreateInstancePoolRequestSchema` / `unmarshalCreateInstancePoolResponseSchema` (and 26 sibling marshal/unmarshal exports) — model.ts:747, 756, 759, 775, 792, 802, 815, 818, 878, 938, 953, 964, 977, 991, 1002, 1013, 1022, 1033, 1081, 1089, 1105, 1129, 1139, 1158, 1208, 1222, 1232, 1244 +### 1. `marshalCreateInstancePoolRequestSchema` / `unmarshalCreateInstancePoolResponseSchema` (and 26 sibling marshal/unmarshal exports) — model.ts:961, 675, 684, 687, 703, 720, 730, 743, 746, 806, 866, 881, 892, 905, 919, 930, 941, 950, 1009, 1017, 1033, 1057, 1067, 1086, 1136, 1150, 1160, 1172 **Why:** `marshal` / `unmarshal` are proto/Go-codegen verbs (cf. Go's `proto.Marshal` / `proto.Unmarshal`, `encoding/json.Marshal`). TypeScript @@ -193,7 +65,7 @@ convention is `encode` / `decode`, `serialize` / `deserialize`, or **Rationale:** The verb pair betrays the Go-SDK ancestry; TS consumers will not recognise it as the standard name for JSON shape transformation. -### 8. `_req: ListInstancePoolsRequest` parameter on `listInstancePools` — client.ts:199 +### 2. `_req: ListInstancePoolsRequest` parameter on `listInstancePools` — client.ts:202 **Why:** Empty request type generated from a proto with no fields, threaded into the public method signature and leading-underscored to @@ -213,6 +85,5 @@ artefact and the leading underscore at the same time. | ------------ | ----- | | High | 3 | | Medium | 3 | -| Low | 25 | -| Observation | 2 | -| **Total** | **33**| +| Low | 2 | +| **Total** | **8** | diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md index da9d48a7..e21759c6 100644 --- a/.agent/naming-audit/instanceprofiles.md +++ b/.agent/naming-audit/instanceprofiles.md @@ -20,82 +20,19 @@ | ----- | ----------------------------------- | -------- | ----- | | V-01 | `InstanceProfile` (interface, `model.ts:64`) | High | The unqualified name reads as a general "instance profile" concept, but the type is **AWS-specific** (an AWS IAM Instance Profile, see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html). The Databricks SDK supports multiple clouds (AWS, Azure, GCP) — peers in this SDK (e.g. `AzureServicePrincipal`, `GcpAttributes`) lead with the cloud prefix. `AwsInstanceProfile` would prevent collision with future Azure/GCP "instance" abstractions and align with the cloud-prefixed naming in `compute`, `clusters`, etc. Inherited from the API; flagged for visibility. | -### 1.2 Underscores in TS identifiers — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------------------- | -------- | ----- | -| U-01 | Wire-format snake-case in zod schemas (`instance_profile_arn`, `is_meta_instance_profile`, `iam_role_arn`, `instance_profiles`, `skip_validation`) | Low | Underscores in *string literals* are correct — they match the JSON wire format. Not a violation. Noted for completeness. | - -### 1.3 Cryptic abbreviations — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| C-01 | `arn` (within `instanceProfileArn`, `iamRoleArn`) | Low | "ARN" is a well-known AWS acronym; not cryptic in the AWS context. Acceptable. | -| C-02 | `iam` (within `iamRoleArn`) | Low | "IAM" = AWS Identity & Access Management. Well-known AWS acronym. Acceptable. | - -### 1.4 Misleading names — High - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| M-01 | `AddInstanceProfileRequest` / `addInstanceProfile()` (`model.ts:5`, `client.ts:79`) | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | -| M-02 | `RemoveInstanceProfileRequest` / `removeInstanceProfile()` (`model.ts:94`, `client.ts:193`) | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | -| M-03 | `EditInstanceProfileRequest` / `editInstanceProfile()` (`model.ts:39`, `client.ts:121`) | Medium | "Edit" is a non-standard CRUD verb (the standard is "update"). Other Databricks SDK surfaces use `update*` for the same operation. Matches the wire path `/edit`, so this is a per-API upstream decision. | - -### 1.5 Singular / plural mismatches — Low - -| ID | Symbol | Severity | Issue | -| ----- | --------------------------------------------------- | -------- | ----- | -| P-01 | `ListInstanceProfilesRequest` (plural) vs `listInstanceProfiles()` (plural) | Low | Consistent. | -| P-02 | `ListInstanceProfilesResponse.instanceProfiles` | Low | Plural field for an array — correct. | -| P-03 | `InstanceProfile` (singular entity) vs `instanceProfiles` (plural array) | Low | Correct pluralisation throughout. | -| P-04 | `AddInstanceProfileRequest` / `EditInstanceProfileRequest` / `RemoveInstanceProfileRequest` (all singular) | Low | Correct — single-entity operations. | - -### 1.6 Verb-tense inconsistency — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| T-01 | `addInstanceProfile`, `editInstanceProfile`, `listInstanceProfiles`, `removeInstanceProfile` | Low | All imperative present-tense — consistent. | -| T-02 | `isMetaInstanceProfile` (boolean) | Low | Standard `is*` boolean prefix. | -| T-03 | `skipValidation` (boolean) | Low | Imperative — consistent boolean style. | - -### 1.7 Go / Java-style names — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| G-01 | `RemoveInstanceProfileRequest` | Low | Pairs with `addInstanceProfile`. The "add/remove" pair is idiomatic in many languages; OK. | - -### 1.8 Generic field names losing meaning — Low - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| F-01 | `instanceProfileArn`, `iamRoleArn` | Low | Well-qualified; meaning preserved out of context. Good. | -| F-02 | `instanceProfiles` (in `ListInstanceProfilesResponse`) | Low | Self-describing. Good. | - -### 1.9 Field contradicting type domain — Medium - -| ID | Symbol | Severity | Issue | -| ----- | ----------------------------------- | -------- | ----- | -| FD-01 | `InstanceProfile.iamRoleArn` (`model.ts:83`) | Medium | "IAM role" is a related-but-distinct AWS concept from "instance profile". An instance profile *contains* a role, but the role itself is a separate AWS resource. The field is conditionally required (JSDoc says "required if your role name and instance profile name do not match and you want to use the instance profile with Databricks SQL Serverless"). Mixing two AWS resource ARNs in one entity is the API design; flagged. | -| FD-02 | `AddInstanceProfileRequest.skipValidation` | Low | A request-only behaviour flag in a "domain entity"-shaped request. Acceptable for an "add"/"create" request type. | -| FD-03 | `RemoveInstanceProfileRequest.instanceProfileArn` | Low | Identifier-only payload for delete — appropriate. | - -### 1.10 Inconsistent action verbs — High +### 1.2 Misleading names — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| AV-01 | `addInstanceProfile` + `removeInstanceProfile` (pair) | Medium | The verbs `add` + `remove` form a natural pair and match the API wire paths (`/add`, `/remove`). Acceptable. | -| AV-02 | `editInstanceProfile` (verb mismatch with `add` / `remove`) | High | The CRUD verbs in this package are `add`, `edit`, `remove` — three different verb families (`add`/`remove` ↔ pair; `edit` ↔ standalone, no `add`/`edit`/`delete` triplet, no `create`/`update`/`delete` triplet). Inconsistent. Most modern Databricks APIs (and broader REST APIs) use **update**. Matches the wire path `/edit`, so this is a per-API upstream decision. | -| AV-03 | `addInstanceProfile` (vs `createInstanceProfile`) | High | "Add" suggests adding to an existing collection (e.g. registering); "create" suggests minting a new AWS resource. The method **registers an existing AWS instance profile with Databricks** — neither verb is perfectly accurate, but `register*` would be most precise. See M-01. | -| AV-04 | `removeInstanceProfile` (vs `deleteInstanceProfile` / `unregisterInstanceProfile`) | High | Same observation as AV-03. The method un-registers, not deletes. `unregisterInstanceProfile` would be most precise. See M-02. | -| AV-05 | `listInstanceProfiles` (vs `getInstanceProfiles`) | Low | Correct: `list*` for plural retrieval, `get*` for singular. Consistent. | +| M-01 | `AddInstanceProfileRequest` / `addInstanceProfile()` (`model.ts:5`, `client.ts:78`) | High | "Add" is ambiguous between "create a new resource" and "register an existing resource". The JSDoc clarifies this method **registers** an existing AWS instance profile (it does **not** create one in AWS). `registerInstanceProfile` would be more accurate and would pair semantically with `removeInstanceProfile` (where "remove" actually means "unregister"). The current naming implies CRUD-create semantics that aren't true — the AWS resource exists independent of this call. | +| M-02 | `RemoveInstanceProfileRequest` / `removeInstanceProfile()` (`model.ts:94`, `client.ts:195`) | High | Same domain mismatch as M-01: the method **unregisters** the instance profile from Databricks (the AWS resource is untouched). The JSDoc even notes "Existing clusters with this instance profile will continue to function." `unregisterInstanceProfile` would be more accurate. | -### 1.11 Underspecified IDs — High +### 1.3 Inconsistent action verbs — High | ID | Symbol | Severity | Issue | | ----- | ----------------------------------- | -------- | ----- | -| I-01 | `instanceProfileArn` | Low | Well-specified: identifier scope (instance profile), identifier type (AWS ARN). Good — far clearer than a bare `id` or `name` would be. | -| I-02 | `iamRoleArn` | Low | Well-specified: scope (IAM role), type (ARN). Good. | -| I-03 | Absence of `instanceProfileId` | Low | The package uses ARN as the sole identifier — there is no separate "ID" concept. Good (no ambiguity between `id` and `arn`). | +| AV-01 | `addInstanceProfile` (vs `createInstanceProfile`) | High | "Add" suggests adding to an existing collection (e.g. registering); "create" suggests minting a new AWS resource. The method **registers an existing AWS instance profile with Databricks** — neither verb is perfectly accurate, but `register*` would be most precise. See M-01. | +| AV-02 | `removeInstanceProfile` (vs `deleteInstanceProfile` / `unregisterInstanceProfile`) | High | Same observation as AV-01. The method un-registers, not deletes. `unregisterInstanceProfile` would be most precise. See M-02. | --- @@ -105,8 +42,8 @@ | Severity | Count | | -------- | ----- | -| High | 6 | -| Medium | 3 | -| Low | 19 | +| High | 5 | +| Medium | 0 | +| Low | 0 | | Observation | 0 | -| **Total**| **28**| +| **Total**| **5** | diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md index 41f3813e..09cbed4b 100644 --- a/.agent/naming-audit/jobs.md +++ b/.agent/naming-audit/jobs.md @@ -2,105 +2,103 @@ Path: `packages/jobs/src/v2/` Versions: v2 -Files: `model.ts` (10210 lines), `client.ts` (1249 lines), `utils.ts` (180 lines), -`transport.ts` (73 lines), `index.ts` (284 lines). -Total findings: 55 -Last rescanned: 2026-06-02 +Files: `model.ts` (10079 lines), `client.ts` (1290 lines), `utils.ts` (181 lines), +`transport.ts` (113 lines), `index.ts` (248 lines). +Total findings: 22 ## Summary Table -| Severity | Count | Notes | -| ------------ | ----- | ------------------------------------------------------------------------------ | -| High | 14 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | -| Medium | 22 | Redundant prefixes/suffixes, vague names, pluralization. | -| Low | 15 | Mild verbosity, plural mismatches, stylistic inconsistencies. | -| Observations | 4 | Patterns spanning the entire file (oneof wrappers, type design, etc.). | -| **Total** | **55** | | +| Severity | Count | Notes | +| -------- | ------ | ------------------------------------------------------------------------------ | +| High | 14 | Reserved-word risks, broken/misleading names, identifier collisions, contradictions, proto-architectural leaks. | +| Medium | 6 | Redundant prefixes/suffixes, pluralization, optionality. | +| Low | 2 | Plural mismatch, field placement. | +| **Total** | **22** | | --- ## High ### H1. `Format` (top-level public enum) is a reserved-word collision -- **Location:** `model.ts:151`. +- **Location:** `model.ts:185`. - **Category:** Reserved-word collisions (#10), vague/generic (#1). - **Suggestion:** Rename to `JobFormat`. - **Rationale:** `Format` is a well-known global (the `Intl.NumberFormat`/`Intl.DateTimeFormat` family, `console.format` in some runtimes, and a built-in name in many code-generators). Importing `Format` from a Jobs SDK forces consumers to alias it. ### H2. `Source` (top-level public enum) clashes with global Web/TS names -- **Location:** `model.ts:257`. +- **Location:** `model.ts:327`. - **Category:** Reserved-word collisions (#10), vague/generic (#1). - **Suggestion:** Rename to `TaskSource`, `CodeSource`, or `FileSource` (only two values: `WORKSPACE`, `GIT`). - **Rationale:** `Source` is the name of the DOM `EventSource` shorthand, Web Audio `AudioBufferSourceNode`, RxJS `Source`, several stream libraries, and lint rules around it. With only two values describing where SQL/Notebook/dbt code lives, a domain prefix is essential. ### H3. `Compute` interface clashes with the larger Databricks Compute API -- **Location:** `model.ts:1362`. +- **Location:** `model.ts:1493`. - **Category:** Vague/generic (#1), misleading names (#6). - **Suggestion:** Rename to `TaskComputeOverride` or `TaskCompute` — the type wraps only `hardwareAccelerator` for serverless GPU. - **Rationale:** A consumer would expect `Compute` to describe an entire compute target (cluster spec, node type, runtime, etc.). It actually has one field. This is the worst "field contradicting type domain" case in the file (#16). ### H4. `Environment` overload — minimal interface, generic word -- **Location:** `model.ts:1785`. +- **Location:** `model.ts:1893`. - **Category:** Vague/generic (#1), reserved-word collision (#10). - **Suggestion:** Rename to `TaskEnvironment` (matching the per-task `environment_key` reference) or `EnvironmentSpec`. - **Rationale:** `Environment` is a host-level concept in Node (`process.env`) and a common UI/test-framework type. Inside this file it is a tiny dep-list + base-env reference; it is referenced as `JobEnvironment.spec: Environment`, so a `Spec` suffix matches its role. ### H5. `Repair` lacks a noun and is mistaken for a verb -- **Location:** `model.ts:3084`. +- **Location:** `model.ts:3153`. - **Category:** Verb-tense inconsistency (#13), vague/generic (#1). - **Suggestion:** Rename to `RepairHistoryEntry` (or `RepairAttempt`) — it represents a single past repair. -- **Rationale:** The verb `repair()` exists on the client (`client.ts:769`), and `RepairRunRequest`/`RepairRunResponse` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. +- **Rationale:** The verb `repair()` exists on the client (`client.ts:820`), and `RepairRunRequest`/`RepairRunResponse` are the request/response shapes. A standalone `Repair` reads as the action, not as a record. ### H6. `Webhook` is a generic top-level name that collides with the platform `Webhook` concept -- **Location:** `model.ts:4938`. +- **Location:** `model.ts:4825`. - **Category:** Vague/generic (#1), reserved-word/global collision (#10). - **Suggestion:** Rename to `WebhookRef` (or `JobWebhook`) — readers grep `Webhook` expecting the request/payload shape, but the actual Webhook _payload_ is `WebhookNotifications`. The bare `Webhook` token is the wrong claimant for that name. - **Rationale:** "Webhook" is a broad industry term and the actual delivery payload lives under a different identifier; the unqualified type-name should belong to the canonical shape, not to a Jobs-specific reference. ### H7. `Run.numberInJob` always equals `Run.runId` — meaningless field -- **Location:** `model.ts:3408`, `model.ts:916`, `model.ts:2137`. +- **Location:** `model.ts:3391`, `model.ts:1085`, `model.ts:2246`. - **Category:** Misleading names (#6), generic field names losing meaning (#15). - **Suggestion:** Drop or alias; if it must stay for back-compat, document the duplication on the field rather than the type. - **Rationale:** The comment "This is set to the same value as `run_id`" makes the field a no-op. New TS users will assume it's distinct. ### H8. `RunNowResponse.numberInJob` reused -- **Location:** `model.ts:3752`. +- **Location:** `model.ts:3671`. - **Category:** Misleading names (#6). - **Suggestion:** Same as H7 — remove the field, or document the duplication on the field if it must stay for back-compat. - **Rationale:** Same dead duplication on the response. ### H9. `JobsHealthMetric` / `JobsHealthOperator` / `JobsHealthRule` / `JobsHealthRules` — pluralization confusion -- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2561`, `model.ts:2569`. +- **Location:** `model.ts:246`, `model.ts:259`, `model.ts:2659`, `model.ts:2667`. - **Category:** Singular/plural mismatch (#9), redundant suffixes (#8). - **Suggestion:** `JobsHealthRule` and `JobsHealthRules` differ only by `s` and the inner wraps a `rules?: JobsHealthRule[]`. Flatten — make the array the public shape (call it `HealthRules` or just `HealthRule[]`). - **Rationale:** Hairsplitting wrappers around arrays force consumers to write `{rules: [...]}` instead of `[...]`. Plural type names alongside singular ones are the most error-prone pattern in this file. ### H10. `JobsHealth*` prefix is inconsistent — `Jobs` is plural -- **Location:** `model.ts:198`, `model.ts:207`, `model.ts:2561`, `model.ts:2569`. +- **Location:** `model.ts:246`, `model.ts:259`, `model.ts:2659`, `model.ts:2667`. - **Category:** Singular/plural mismatch (#9), Go/Java-style names (#14). - **Suggestion:** Use the singular product noun: `JobHealthMetric`, `JobHealthRule`. Or just `HealthMetric` if global. - **Rationale:** `Job.health: JobsHealthRules` reads as "this job's healths" — the `s` is a porting artifact (proto file is `jobs.proto`). ### H11. `RunJobTask` reads as "run-job task" or "run a job task" — ambiguous -- **Location:** `model.ts:3501`. +- **Location:** `model.ts:3484`. - **Category:** Misleading names (#6). -- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per the oneof JSDoc on line 3976). +- **Suggestion:** Rename to `RunChildJobTask` or `TriggerJobTask` (this is the "trigger another job" task type per the oneof JSDoc on line 3871). - **Rationale:** Reading `task: RunJobTask` is ambiguous: is it "the run of a job task" or "task that runs a job"? ### H12. `client.exportRun` returns `ExportRunResponse` which contains a `views` array of `ViewItem` -- **Location:** `client.ts:440`, `model.ts:1825`, `model.ts:4920`. +- **Location:** `client.ts:451`, `model.ts:1935`, `model.ts:4807`. - **Category:** Vague/generic (#1). - **Suggestion:** Rename `ViewItem` to `ExportedView` or `RunView`. - **Rationale:** "Item" is the canonical empty noun. The type has `content`, `name`, `type: ViewType` — call it what it is. ### H13. `CancelRunWaiter` polls on the V1 lifecycle-state enum while the modern field is `RunStatus.state` -- **Location:** `client.ts:986-997` (and the identical blocks in `RepairWaiter` at `client.ts:1059-1070`, `RunNowWaiter` at `client.ts:1132-1143`, `SubmitRunWaiter` at `client.ts:1205-1216`). +- **Location:** `client.ts:1022-1038` (and the identical blocks in `RepairWaiter` at `client.ts:1095-1111`, `RunNowWaiter` at `client.ts:1168-1184`, `SubmitRunWaiter` at `client.ts:1241-1257`). - **Category:** Versioned API leakage. - **Suggestion:** Either poll on the new `RunStatus` or document why V1 is still authoritative. - **Rationale:** Every waiter's `wait()` reads `pollResp.state?.lifeCycleState` against `RunLifeCycleState_RunLifeCycleState`; future deprecation of V1 will silently break all four waiters. ### H14. `RunLifecycleStateV2` + `RunLifecycleStateV2_State` — `V2` infix leaks API/proto versioning into public identifiers -- **Location:** `model.ts:509` (`RunLifecycleStateV2_State` enum), `model.ts:3616` (`RunLifecycleStateV2` wrapper interface), `model.ts:3867` (`RunStatus.state: RunLifecycleStateV2_State`). +- **Location:** `model.ts:650` (`RunLifecycleStateV2_State` enum), `model.ts:3567` (`RunLifecycleStateV2` wrapper interface), `model.ts:3762` (`RunStatus.state: RunLifecycleStateV2_State`). - **Why:** `V2` mid-token in a type name records that the upstream schema versioned this enum, not anything a JS consumer needs. The V1 type already lives at `RunLifeCycleState` / `RunLifeCycleState_RunLifeCycleState`; the V2 variant should adopt a domain-meaningful name rather than a version-stamped one. - **Category:** Proto-architectural-leak (`V2` mid-position). - **Suggested:** Rename the wrapper to `RunLifecycleState` (singular, modern) and the enum to `RunLifecycleState_State` — then mark the legacy `RunLifeCycleState` family `@deprecated`. If the V1 type must keep its current name for back-compat, rename the V2 family to `RunPhase` or `RunLifecycleStatus` (anything that says "this is the new shape" without encoding the version number). @@ -110,147 +108,37 @@ Last rescanned: 2026-06-02 ## Medium -### M1. `HardwareAcceleratorType` enum values `GPU_1xA10`, `GPU_8xH100` (lowercase `x`) -- **Location:** `model.ts:173-175`. -- **Category:** Naming convention violation in enum value strings. -- **Suggestion:** The TS enum keys are properly `GPU_1X_A10`, but the values keep the wire form. This is OK since the wire is contract — but flag the asymmetry inline. -- **Rationale:** Wire compatibility forces lowercase `x`; the enum key uppercase is fine. - -### M2. `JobsHealthMetric.RUN_DURATION_SECONDS` — long but OK -- **Location:** `model.ts:199`. -- **Category:** Long enum values (#18). -- **Suggestion:** Acceptable. - -### M3. `JobsHealthMetric.STREAMING_BACKLOG_*` (4 values) -- **Location:** `model.ts:200-203`. -- **Category:** Long enum values (#18). -- **Suggestion:** Acceptable; consider grouping into a nested enum if the four become five. - -### M4. `Repair.type` (RepairType) is a reserved-ish word -- **Location:** `model.ts:3086`, `model.ts:215`. -- **Category:** Reserved-word collision (#10). -- **Suggestion:** Acceptable on objects (TS allows `type` as a property), but flag against naming-convention rule. - -### M5. `RunNowRequest.idempotencyToken`, `SubmitRunRequest.idempotencyToken` — OK -- **Location:** `model.ts:3635`, `model.ts:4570`. -- **Category:** Verbose but precise. - -### M6. `RepairRunRequest.rerunTasks` (verb prefix `re-`) + `rerunAllFailedTasks` + `rerunDependentTasks` — OK pattern -- **Location:** `model.ts:3113-3119`. -- **Category:** Consistent prefix; OK. - -### M7. `JobRunAs.identity` — OK -- **Location:** `model.ts:2403`. - -### M8. `JobCluster.jobClusterKey` — `jobCluster` namespace already, `Key` is the only meaningful suffix -- **Location:** `model.ts:2333`. -- **Category:** Acceptable; key is the lookup pattern. - -### M9. `JobEnvironment.environmentKey` — same pattern, OK. -- **Location:** `model.ts:2386`. - -### M10. `TaskSettings.taskKey` — OK, but its repetition across `RunTask`, `RunTaskSettings`, `TaskSettings`, `TaskDependency` is heavy -- **Location:** `model.ts:4681`, `model.ts:3902`, `model.ts:4091`, `model.ts:4670`. -- **Category:** Verbose but precise. - -### M11. `ResolvedValues` interface has 11 single-purpose sub-types -- **Location:** `model.ts:3248-3398`. +### M1. `ResolvedValues` interface has 11 single-purpose sub-types +- **Location:** `model.ts:3326-3381`. - **Category:** Verbose; many shapes for one purpose. - **Suggestion:** Collapse into a single `ResolvedValues` shape with optional fields per task type, or document the union shape pattern. -### M12. `BaseRun.numberInJob` — meaningless field (see H7) -- **Location:** `model.ts:916`. - -### M13. `BaseRun.originalAttemptRunId` — verbose, but precise. - -### M14. `Run.runId` (inside `Run`) — tautological -- **Location:** `model.ts:3404`, `model.ts:912`, `model.ts:2133`, `model.ts:3877`. -- **Category:** Type-suffix tautology (#20). -- **Suggestion:** Keep for ID disambiguation against `jobId`; this is intentional disambiguation rather than tautology. +### M2. `BaseRun.numberInJob` — meaningless field (see H7) +- **Location:** `model.ts:1085`. -### M15. `RunNowResponse.numberInJob` (see H8). +### M3. `RunNowResponse.numberInJob` (see H8). -### M16. `Format` enum has only two values (`SINGLE_TASK`, `MULTI_TASK`) and one is dead -- **Location:** `model.ts:151-154`. -- **Category:** Dead enum value. - -### M17. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized -- **Location:** `model.ts:4967`, `model.ts:4971`. +### M4. `WorkloadType.clients: WorkloadType_ClientsTypes` — `ClientsTypes` is mis-pluralized +- **Location:** `model.ts:4854`, `model.ts:4858`. - **Category:** Singular/plural mismatch (#9). - **Suggestion:** Rename to `ClientTypes`. -### M18. `PythonPyPiLibrary` — duplicate "Py" prefix -- **Location:** `model.ts:3028`. +### M5. `PythonPyPiLibrary` — duplicate "Py" prefix +- **Location:** `model.ts:3105`. - **Category:** Redundant prefixes (#2). - **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). -### M19. `MavenLibrary.coordinates` — common, accept. -- **Location:** `model.ts:2800`. - -### M20. `PythonWheelTask.namedParameters` vs `parameters` — fine when distinct. - -### M21. `ListJobsRequest.expandTasks`, `ListRunsRequest.expandTasks` — `boolean` flag is fine. - -### M22. `ListRunsRequest.runType` shouldn't be optional when the API permits a default -- **Location:** `model.ts:2756`. +### M6. `ListRunsRequest.runType` shouldn't be optional when the API permits a default +- **Location:** `model.ts:2847`. - **Category:** Default semantics. --- ## Low -### L1. `WorkloadType_ClientsTypes` — see M17. - -### L2. `PowerBiTable.name` vs `PowerBiTable.catalog`, `schema` — OK (catalog/schema/name is the Databricks 3-part). -- **Location:** `model.ts:2987-2991`. - -### L3. `JobRunAs.identity` oneof discriminator `userName | servicePrincipalName | groupName` — verbose but precise. +### L1. `WorkloadType_ClientsTypes` — see M4. -### L4. `QueueDetails.message` and `QueueDetails.code` — OK. -- **Location:** `model.ts:3060-3066`. - -### L5. `OutputSchemaInfo.catalogName` / `OutputSchemaInfo.schemaName` — acceptable. -- **Location:** `model.ts:2911`. - -### L6. `JobEmailNotifications.onStart` / `onSuccess` / `onFailure` etc. — OK. - -### L7. `WebhookNotifications.onStreamingBacklogExceeded` — accept. - -### L8. `ContinuousSettings.taskRetryMode` (enum) — OK. - -### L9. `ContinuousSettings.pauseStatus: SchedulePauseStatus` — naming OK. - -### L10. `CronSchedule.timezoneId` (lowercase `z`) — OK per ISO usage. - -### L11. `CronSchedule.quartzCronExpression` — long but precise. - -### L12. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. -- **Location:** `model.ts:3478-3480`. +### L2. `Run.setupDuration` / `executionDuration` — JSDoc states they are 0 for multitask job runs; should be on `RunTask` only. +- **Location:** `model.ts:3461-3463`. - **Category:** Field contradicting type domain (#16). - **Suggestion:** Move to `RunTask` only, mark deprecated on `Run`. - -### L13. `SparkPythonTask.parameters` (string[]) — OK. - -### L14. `Library.requirements: string` (a requirements.txt URI) — OK. - -### L15. `AwsAttributes.spotBidPricePercent` — long but precise. - ---- - -## Observations (whole-file patterns) - -### O1. The oneof `$case` discriminator convention is well-established and consistent -- Every oneof in the file uses `{$case: 'tag'; tag: T} | undefined`. -- This is a porting convention from `protobuf-ts`/`@bufbuild/protobuf-es`; it's noisy but consistent, and consumers can pattern-match cleanly. Keep. - -### O2. Method-vs-type verb-tense pairing -- `client.cancelRun(CancelRunRequest) → CancelRunResponse`: verb-noun matches. -- `client.runNow(RunNowRequest) → RunNowResponse`: verb-now matches. -- `client.repair(RepairRunRequest) → RepairRunResponse`: verb-noun matches now that request and response types carry explicit `Request`/`Response` suffixes; the method/type pairing is consistent. -- `client.submitRun(SubmitRunRequest) → SubmitRunResponse`: verb-noun matches. - -### O3. `index.ts` re-exports both the value classes and types in two blocks -- Enums and waiter classes go through `export { ... }`; interfaces go through `export type { ... }`. Both blocks together have 200+ identifiers. - -### O4. `Format` and `Source` are top-level public enums named with single English words -- These specific names collide with global and tooling identifiers — see H1, H2. diff --git a/.agent/naming-audit/keyconfigurations.md b/.agent/naming-audit/keyconfigurations.md index 63ea16c2..b8eca376 100644 --- a/.agent/naming-audit/keyconfigurations.md +++ b/.agent/naming-audit/keyconfigurations.md @@ -16,12 +16,12 @@ ## Medium severity (worth pushing back on) -### 1. `Public` suffix on every `Client` method — `client.ts:89, 118, 156, 181` +### 1. `Public` suffix on every `Client` method — `client.ts:89, 119, 158, 184` - **Why:** Every method on `Client` carries the `Public` suffix: `createCustomerManagedKeyPublic` (client.ts:89), - `deleteCustomerManagedKeyPublic` (client.ts:118), - `getCustomerManagedKeyPublic` (client.ts:156), and - `listCustomerManagedKeyPublic` (client.ts:181). This is a proto-audience + `deleteCustomerManagedKeyPublic` (client.ts:119), + `getCustomerManagedKeyPublic` (client.ts:158), and + `listCustomerManagedKeyPublic` (client.ts:184). This is a proto-audience leak surfaced on the most caller-visible symbols in the package. A consumer writing `client.createCustomerManagedKeyPublic(...)` sees no contrast to a hypothetical non-public form, because none is exported. diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md index 274cc3f2..63e72b05 100644 --- a/.agent/naming-audit/knowledgeassistants.md +++ b/.agent/naming-audit/knowledgeassistants.md @@ -2,43 +2,23 @@ **Path:** `packages/knowledgeassistants/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 6 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | | High | 2 | -| Observation | 4 | ## High severity ### 1. `KnowledgeAssistant_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:9` -- **Why weird:** The enum is named `KnowledgeAssistant_State` with a literal `_State` infix, and the file even carries an eslint-disable comment declaring "Proto-style nested enum name" (model.ts:8). The underscore is a direct architectural leak from the upstream `.proto` definition where the enum was nested inside the `KnowledgeAssistant` message (proto generates `OuterMessage_InnerEnum` for nested enums). TypeScript has no nested-enum-inside-class concept, so the underscore conveys nothing to a TS consumer and just signals "this code was generated from proto." +- **Why weird:** The enum is named `KnowledgeAssistant_State` with a literal `_State` infix, and the file even carries an eslint-disable comment declaring "Proto-style nested enum name" (model.ts:15). The underscore is a direct architectural leak from the upstream `.proto` definition where the enum was nested inside the `KnowledgeAssistant` message (proto generates `OuterMessage_InnerEnum` for nested enums). TypeScript has no nested-enum-inside-class concept, so the underscore conveys nothing to a TS consumer and just signals "this code was generated from proto." - **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). - **Suggested name:** `KnowledgeAssistantState` (drop the underscore — already the convention in non-leaky TS APIs). The generator can flatten nested-enum names without changing the wire format. - **Rationale:** The proto wire format and the TS identifier shape are decoupled. Carrying the `Outer_Inner` separator into TS leaks the generator's source format and conflicts with the SDK-wide naming-convention lint rule (the file disables `@typescript-eslint/naming-convention` for exactly this reason). -### 2. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:17` -- **Why weird:** Same proto-nested-enum architectural leak as #1. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:16). Two sibling enums in the same file repeat the same proto-leak pattern. +### 2. `KnowledgeSource_State` — proto-style nested-enum name with underscore infix — `src/v1/model.ts:21` +- **Why weird:** Same proto-nested-enum architectural leak as #1. `KnowledgeSource_State` carries the `_State` infix and the same eslint-disable comment "Proto-style nested enum name" (model.ts:27). Two sibling enums in the same file repeat the same proto-leak pattern. - **Category:** Proto-architectural-leak (proto-nested enum naming surfacing in TS identifier). - **Suggested name:** `KnowledgeSourceState` (drop the underscore). - **Rationale:** Same as #1. Generator-level fix. - -## Observations - -### 3. `list` verbs are uniform across all three resources — `src/v1/client.ts:334,388,445` -- **Why weird:** The package supports `list` on `KnowledgeAssistant`, `Example`, and `KnowledgeSource` (`listExamples`, `listKnowledgeAssistants`, `listKnowledgeSources`). Naming consistent. Flagging as a *positive* observation — the verbs are uniform. -- **Category:** 17 (reversed — consistency note). - -### 4. `syncKnowledgeSources` — verb is plural but operates on parent — `src/v1/client.ts:502` -- **Why weird:** Method `syncKnowledgeSources` takes a `SyncKnowledgeSourcesRequest` whose `name` field is the **parent assistant** id. The verb is "sync" and the noun is the (plural) child collection, but the addressing is parent-level. Compare with `cancelOptimization` on `customllms` — same pattern. -- **Category:** 6 (slightly misleading; the resource being addressed is the assistant, not "the sources"). The method does sync *all* sources for one assistant, so the plural is faithful to the *action* if not the *target*. -- **Suggested name:** Acceptable; consider `syncAssistantSources` for parent-clarity, but the current name reads fine. - -### 5. `KnowledgeAssistant` and `KnowledgeSource` symmetric type design — `src/v1/model.ts:155-196,204-240` -- **Why weird:** Both entities carry: `name`, `state`, `id`, `displayName`, `description`, `createTime`. They diverge: `KnowledgeAssistant` adds `instructions`, `creator`, `endpointName`, `experimentId`, `errorInfo`; `KnowledgeSource` adds `sourceType`, `spec`, `knowledgeCutoffTime`. Symmetric design is a good thing — flagged as a *positive* observation. -- **Category:** Observation. - -### 6. `Example` lacks `state` field — `src/v1/model.ts:79-98` -- **Why weird:** Both sibling entities (`KnowledgeAssistant`, `KnowledgeSource`) have a `state` enum; `Example` does not. This is correct given examples are passive metadata (no lifecycle), but consumers expecting symmetry will notice the asymmetry. Flagged as design observation, not a naming bug. -- **Category:** Observation. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md index 3740b41e..9721841c 100644 --- a/.agent/naming-audit/lakeview.md +++ b/.agent/naming-audit/lakeview.md @@ -46,16 +46,19 @@ The product is documented and marketed as "AI/BI Dashboards" (formerly "Lakeview ### 2. `DashboardView` — single-value enum with a generic, role-obscuring name -**Location:** `src/v1/model.ts:6-9` +**Location:** `src/v1/model.ts:7-13` ```ts -export enum DashboardView { +export const DashboardView = { /** Includes summary metadata from the dashboard. */ - DASHBOARD_VIEW_BASIC = 'DASHBOARD_VIEW_BASIC', -} + DASHBOARD_VIEW_BASIC: 'DASHBOARD_VIEW_BASIC', +} as const; +export type DashboardView = + | (typeof DashboardView)[keyof typeof DashboardView] + | (string & {}); ``` -The enum has only one member. It exists because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.). +The type has only one member. It exists because the API anticipates further view modes (`DASHBOARD_VIEW_FULL`, etc.). `View` is also a generic name in a Dashboards package (it overloads the HTML/UI sense of "view" with the "field mask" sense — e.g. `proto3` partial-response style). @@ -67,9 +70,9 @@ The enum has only one member. It exists because the API anticipates further view ### 3. `trashDashboard()` / `TrashDashboardRequest` — verb diverges from the SDK-wide `delete` -**Location:** `src/v1/client.ts:672` (`trashDashboard`), `src/v1/model.ts:421` (`TrashDashboardRequest`) +**Location:** `src/v1/client.ts:687` (`trashDashboard`), `src/v1/model.ts:432` (`TrashDashboardRequest`) -The method uses `trash` and the type uses `Trash`, while every other CRUD-style endpoint in the Databricks SDK uses `Delete`/`delete`. Alerts had the *exact* same `trash` method/type vocabulary (flagged in `alerts.md` #11 and #12); it was renamed in alerts v2 — leaving Lakeview as an outlier. +The method uses `trash` and the type uses `Trash`, while CRUD-style endpoints elsewhere in the Databricks SDK use `Delete`/`delete`. The same `trash` method/type vocabulary survives only in `alerts` (`trashAlert` / `TrashAlertRequest`, both v1 and v2, flagged in `alerts.md`) and `queries` (`trashQuery`) — a three-package island against the SDK-wide `delete` verb. The `trashDashboard()` method (verb `trash`) soft-deletes a dashboard. So the method verb and the type-name suffix share a vocabulary that none of the rest of the SDK uses. @@ -77,7 +80,7 @@ The `trashDashboard()` method (verb `trash`) soft-deletes a dashboard. So the me **Suggested name:** Rename the method and type to `deleteDashboard` / `DeleteDashboardRequest` so the verb matches the rest of the SDK. The cleanest is to rename method + type together. -**Rationale:** A single coherent verb. The trash → delete method/type migration is partially complete in other packages and lakeview is behind. +**Rationale:** A single coherent verb. The `alerts`, `queries`, and `lakeview` soft-delete endpoints are the only places in the SDK that spell delete as `trash`. --- @@ -85,7 +88,7 @@ The `trashDashboard()` method (verb `trash`) soft-deletes a dashboard. So the me ### 4. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb -**Location:** `src/v1/model.ts:285`, `src/v1/client.ts:585` +**Location:** `src/v1/model.ts:297`, `src/v1/client.ts:597` "Migrate" can mean (a) copy and convert, (b) move-and-delete-source, (c) rewrite-in-place. The JSDoc on the method ("Migrates a classic SQL dashboard to Lakeview.") suggests (a): the source dashboard remains, a new AI/BI dashboard is created. The verb does not encode this. @@ -97,7 +100,7 @@ The `trashDashboard()` method (verb `trash`) soft-deletes a dashboard. So the me ### 5. `trashDashboard` — soft-delete method without a paired restore (see also #3) -**Location:** `src/v1/client.ts:672` +**Location:** `src/v1/client.ts:687` Beyond the verb-mismatch flagged in #3, the `trashDashboard` method is paired with no `restoreDashboard` or `untrashDashboard`. The method soft-deletes the dashboard, but the API doesn't expose how to undo it via the SDK — a caller has to use `updateDashboard(...)` to reactivate it. Discovery from method names alone gives no hint that "restore" exists. @@ -109,7 +112,7 @@ Beyond the verb-mismatch flagged in #3, the `trashDashboard` method is paired wi ### 6. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles -**Location:** `src/v1/model.ts:299`, `src/v1/model.ts:315` +**Location:** `src/v1/model.ts:311`, `src/v1/model.ts:327` `PublishDashboardRequest` is the input to `publishDashboard()`. `PublishedDashboard` is the response. The names are one letter apart (`Publish*` vs `Published*`). A code reader picking either out of an auto-complete list can grab the wrong one and the compiler will not immediately tell them apart at construction time — both are records with `warehouseId?: string`. diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md index 7522a6a7..64de8bf8 100644 --- a/.agent/naming-audit/logdelivery.md +++ b/.agent/naming-audit/logdelivery.md @@ -9,7 +9,7 @@ delivery configuration ties a `credentialsId` (AWS IAM role) and a `AUDIT_LOGS`), optionally scoped by a workspace-IDs filter. There is no delete endpoint by design — the API only supports disabling via the update (`PATCH`) method. -**Total weird names flagged:** 7 +**Total weird names flagged:** 6 ## Summary | Severity | Count | @@ -17,51 +17,45 @@ update (`PATCH`) method. | High | 3 | | Medium | 2 | | Low | 1 | -| Observation | 1 | ## High severity -### 1. `LogDeliveryStatusEnum` — type name carries `Enum` suffix — `src/v1/model.ts:39` -- **Why weird:** `LogDeliveryStatusEnum` is the only type in the package whose name ends in `Enum`. The three sibling enums (`LogDeliveryConfigStatus` at line 12, `LogDeliveryOutputFormat` at line 23, `LogDeliveryType` at line 56) carry no such suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` is already claimed by the wrapper *interface* at `model.ts:205` (which holds `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, and `status`). +### 1. `LogDeliveryStatusEnum` — type name carries `Enum` suffix — `src/v1/model.ts:48` +- **Why weird:** `LogDeliveryStatusEnum` is the only type in the package whose name ends in `Enum`. The three sibling enums (`LogDeliveryConfigStatus` at line 13, `LogDeliveryOutputFormat` at line 28, `LogDeliveryType` at line 69) carry no such suffix. The `Enum` tail exists because the simpler name `LogDeliveryStatus` is already claimed by the wrapper *interface* at `model.ts:221` (which holds `lastAttemptTime`, `lastSuccessfulAttemptTime`, `message`, and `status`). - **Category:** 20 (type-suffix tautology), 12 (duplicate concept — `LogDeliveryStatus` interface and `LogDeliveryStatusEnum` enum coexist). - **Suggested name:** Rename the wrapper interface `LogDeliveryStatus` → `LogDeliveryAttempt` (it models the most-recent attempt, not the status per se), and rename the enum `LogDeliveryStatusEnum` → `LogDeliveryAttemptStatus`. The field site then reads `attempt.status: LogDeliveryAttemptStatus` instead of `logDeliveryStatus.status: LogDeliveryStatusEnum`. - **Rationale:** The `Enum` suffix is unique to this one type and signals that the underlying noun is overloaded. Splitting the noun ("attempt" for the wrapper, "attempt status" for the values) removes the suffix and the conflation in one rename. -### 2. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:123-128,227-234` -- **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:123,215`). The client substitutes them via `?? ''` (`client.ts:123,215`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:227-234`. The JSDoc on `configId` (`model.ts:125`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). +### 2. `GetLogDeliveryConfigurationRequest.configId` / `accountId` are required path params typed optional — `src/v1/model.ts:139-144,243-250` +- **Why weird:** `GetLogDeliveryConfigurationRequest` has two fields, both typed `string | undefined`, both required path params in the URL (`/api/2.0/accounts/${accountId}/log-delivery/${configId}` — `client.ts:125,219`). The client substitutes them via `?? ''` (`client.ts:125,219`), so a caller who forgets `configId` silently produces a request to `/log-delivery/`. Same pattern on `UpdateLogDeliveryConfigurationRequest` at `model.ts:243-250`. The JSDoc on `configId` (`model.ts:140`) reads "The log delivery configuration id of customer" — the "of customer" phrase is meaningless boilerplate (a config belongs to an account, not a customer). - **Category:** 6 (misleading — type signature says optional, runtime requires non-empty), 7 (overly verbose / boilerplate JSDoc). -- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional iff the client falls back to `ClientOptions.accountId` (which it does for `get`/`list`/`update`, but *not* for `create`). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." +- **Suggested name:** Drop `| undefined` on `configId` — it is a required path parameter. `accountId` may remain optional since the client falls back to the resolved `accountId` in all four methods (for `create` via the nested `logDeliveryConfiguration.accountId` at `client.ts:92`). Rewrite the JSDoc to "The unique UUID of the log delivery configuration to fetch." - **Rationale:** Required path params should have required types. The current shape silently produces malformed URLs at runtime. The "of customer" prose is generator-emitted boilerplate worth removing globally. -### 3. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:211`, `src/v1/model.ts:227-234` -- **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:227-234`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:206-210`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus`, which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. +### 3. `updateLogDeliveryConfiguration` does not "update" — it only flips ENABLED ↔ DISABLED — `src/v1/client.ts:214`, `src/v1/model.ts:243-250` +- **Why weird:** The method name says "update arbitrary fields of the configuration". The request body (`UpdateLogDeliveryConfigurationRequest` at `model.ts:243-250`) carries exactly three fields: `configId`, `accountId`, `status` — you cannot rewrite `credentialsId`, `storageConfigurationId`, `workspaceIdsFilter`, or anything else. The JSDoc on the method (`client.ts:209-213`) calls it out: "Enables or disables a log delivery configuration." The Go SDK names this method `PatchStatus` (the client JSDoc still references `:method:LogDelivery/PatchStatus` at `client.ts:85`), which is honest about its surface; the TS port renames it to `updateLogDeliveryConfiguration`, which is not. - **Category:** 6 (misleading), 17 (verb inconsistency — Go uses `PatchStatus`, TS paraphrases as `update`). -- **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:224`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. +- **Suggested name:** `patchStatus` (matches Go and the HTTP verb at `client.ts:228`), or `setStatus`, or `updateStatus`. Rename the request type to `UpdateLogDeliveryConfigurationStatusRequest` correspondingly. - **Rationale:** "Update" implies multi-field mutation. A caller writing `updateLogDeliveryConfiguration({configId, status, deliveryPathPrefix: '/new'})` will be surprised — `deliveryPathPrefix` is not on the DTO so TS will type-error, but only after the user reads the type. The verb is a footgun and the existing JSDoc admits it. Naming should match capability. ## Medium severity -### 4. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:147,189` -- **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:157`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). +### 4. `listLogDeliveryConfiguration` — singular method on a collection result — `src/v1/client.ts:149,192` +- **Why weird:** The method name is singular ("Configuration") but it returns a collection — the response body field is `logDeliveryConfigurations` (plural, `model.ts:173`). Adjacent packages use plural method names for list endpoints (e.g., `listBudgetConfigurations` in `packages/budgets/src/v1/client.ts`). - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `listLogDeliveryConfigurations` (plural). The `*Iter` pagination helper should match: `listLogDeliveryConfigurationsIter`. - **Rationale:** Method-name pluralisation should match the data shape it yields. -### 5. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:139` -- **Why weird:** Same shape mismatch as finding 4, applied to the request DTO. The class-level JSDoc on line 137 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. +### 5. `ListLogDeliveryConfigurationRequest` — singular request type for a list operation — `src/v1/model.ts:155` +- **Why weird:** Same shape mismatch as finding 4, applied to the request DTO. The class-level JSDoc on line 153 also says "List Log Delivery Configuration" (singular). Compare with `budgets.ListBudgetConfigurationsRequest` (plural) at `packages/budgets/src/v1/model.ts`. - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and the `_Response` partner correspondingly). +- **Suggested name:** `ListLogDeliveryConfigurationsRequest` (and `ListLogDeliveryConfigurationsResponse` at `model.ts:171` correspondingly). - **Rationale:** Pluralisation is the standard signal for a collection-returning method/type pair. ## Low severity -### 6. `req` / `resp` / `httpReq` / `pageReq` abbreviations — `src/v1/client.ts:88,96,100,120,128,148,167,171,190,193,212,224` +### 6. `req` / `resp` / `httpReq` / `pageReq` abbreviations — `src/v1/client.ts:88,97,101,121,126,150,170,174,193,196,215,224` - **Why weird:** Short abbreviations on parameter and local names across every method (`req` for the request parameter, `resp` for the response local, `httpReq` for the built HTTP request, `pageReq` for the pagination request). The repo style guide (`.agent/rules/typescript.mdc`) discourages cryptic short abbreviations. - **Category:** 5 (cryptic abbreviation). - **Suggested name:** `request`, `response`, `httpRequest`, `pageRequest`. - **Rationale:** Spelling them out costs nothing and removes the need to learn package-local shorthand. Same finding cross-package. - -## Observations - -### 7. `outputFormat` is always derivable from `logType` — `src/v1/model.ts:78-83,177-182` -The JSDoc on `outputFormat` explicitly says: `If log_type is BILLABLE_USAGE, this value must be CSV. … If log_type is AUDIT_LOGS, this value must be JSON.` The field is therefore redundant on the request DTO — the caller cannot pick freely. Carrying it on the response DTO (for clarity) is defensible. Not a name problem; flagged because the API surface is wider than the API contract. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md index f1f5af4e..01dff777 100644 --- a/.agent/naming-audit/marketplaces.md +++ b/.agent/naming-audit/marketplaces.md @@ -3,14 +3,13 @@ **Path:** `packages/marketplaces/src/v1/` **Versions audited:** v1 **Inferred domain:** Databricks Marketplace — provider-side and exchange-side operations for managing **listings** (the marketplace storefront entry for a dataset, model, notebook, app, MCP, partner integration, or git repo), **providers** (the publisher account), **exchanges** (curated, scoped collections of listings, including exchange filters that scope visibility by metastore), **personalization requests** (consumer-side requests for tailored access), **files** attached to listings/providers (icons, embedded notebooks, embedded markdown, commit drawdown attachments), and a separate **provider analytics dashboard** sub-resource (a Lakeview-backed dashboard for provider-side analytics). -**Total weird names flagged:** 14 (14 still present, 0 newly fixed, 0 superseded). +**Total weird names flagged:** 13 ## Summary | Severity | Count | | --- | --- | | High | 3 | | Medium | 10 | -| Low | 1 | --- @@ -18,7 +17,7 @@ ### 1. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order -**Location:** `src/v1/model.ts:142, 774` +**Location:** `src/v1/model.ts:207, 840` ```ts export interface AddExchangeForListingRequest { @@ -36,9 +35,9 @@ The operations are symmetric (associate / disassociate an exchange with a listin - **Suggested name:** `LinkListingToExchangeRequest` / `UnlinkListingFromExchangeRequest` (or `*ExchangeListingRequest`). - **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. -### 2. `ListingSummary` — 20-field "summary" +### 2. `ListingSummary` — 19-field "summary" -**Location:** `src/v1/model.ts:697-718` +**Location:** `src/v1/model.ts:763-784` ```ts export interface ListingSummary { @@ -48,11 +47,11 @@ export interface ListingSummary { share?: ShareInfo | undefined; providerRegion?: RegionInfo | undefined; setting?: ListingSetting | undefined; - createdAt?: number | undefined; + createdAt?: bigint | undefined; createdBy?: string | undefined; - updatedAt?: number | undefined; + updatedAt?: bigint | undefined; updatedBy?: string | undefined; - publishedAt?: number | undefined; + publishedAt?: bigint | undefined; publishedBy?: string | undefined; categories?: Category[] | undefined; listingType?: ListingType | undefined; @@ -64,27 +63,26 @@ export interface ListingSummary { } ``` -A 20-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. +A 19-field type called `Summary` is misleading — summaries are conventionally short. This includes provider-region info, share info, exchange ids, git-repo info, and full audit timestamps. The name promises slim; the shape is fat. - **Category:** 6 (misleading). - **Suggested name:** `ListingMetadata` or `ListingHeader`. -- **Rationale:** A "summary" with 20 fields, including nested objects and full audit metadata, promises a slim shape the type does not deliver. +- **Rationale:** A "summary" with 19 fields, including nested objects and full audit metadata, promises a slim shape the type does not deliver. ### 3. `FileParent` — abstract container with weak typing -**Location:** `src/v1/model.ts:347-351` +**Location:** `src/v1/model.ts:427-430` ```ts export interface FileParent { - /** TODO make the following fields required */ parentId?: string | undefined; fileParentType?: FileParentType | undefined; } ``` -The type ships with a `TODO` in the JSDoc — the API contract is incomplete by the generator's own admission. `parentId` is a free-form string with no statement of which `FileParentType` corresponds to which kind of id. `fileParentType` is a 3-value enum (`PROVIDER`, `LISTING`, `LISTING_RESOURCE`), but `LISTING_RESOURCE` has no separate `ListingResource` type in the package — it's an opaque concept. The pair is effectively a discriminated union that isn't discriminated. -- **Category:** 6 (misleading: looks like a polymorphic parent but isn't typed), Observation (incomplete API). +`parentId` is a free-form string with no statement of which `FileParentType` corresponds to which kind of id. `fileParentType` is a 3-value enum (`PROVIDER`, `LISTING`, `LISTING_RESOURCE`), but `LISTING_RESOURCE` has no separate `ListingResource` type in the package — it's an opaque concept. The pair is effectively a discriminated union that isn't discriminated. +- **Category:** 6 (misleading: looks like a polymorphic parent but isn't typed). - **Suggested name:** Model as a TS discriminated union (`{ $case: 'provider' | 'listing' | 'listingResource', id: string }`). -- **Rationale:** The `TODO` says the team knows; the type is shipped publicly anyway. +- **Rationale:** An id-plus-type-tag pair models a polymorphic parent reference; a discriminated union expresses the same contract with type safety. --- @@ -92,63 +90,68 @@ The type ships with a `TODO` in the JSDoc — the API contract is incomplete by ### 4. `Cost` — single-word, ambiguous enum -**Location:** `src/v1/model.ts:46-49` +**Location:** `src/v1/model.ts:53-57` ```ts -export enum Cost { - FREE = 'FREE', - PAID = 'PAID', -} +export const Cost = { + FREE: 'FREE', + PAID: 'PAID', +} as const; +export type Cost = (typeof Cost)[keyof typeof Cost] | (string & {}); ``` -`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 647) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". +`Cost` is a generic noun. Inside `ListingDetail.cost: Cost` (line 716) the field is documented as "Whether the dataset is free or paid" — so the enum is really a *cost category* or *pricing tier*, not a price. The single-word name is collision-prone (cost appears in many domains) and doesn't communicate "is this paid?". - **Category:** 1 (vague), 6 (misleading: implies price, means tier). - **Suggested name:** `ListingPricingTier`, `PricingTier`, or `PriceCategory`. - **Rationale:** A two-value boolean-like enum named `Cost` reads ambiguously. ### 5. `DataRefresh` — enum named after the noun, not the property -**Location:** `src/v1/model.ts:51-61` +**Location:** `src/v1/model.ts:60-73` ```ts -export enum DataRefresh { - NONE = 'NONE', - SECOND = 'SECOND', - MINUTE = 'MINUTE', - HOURLY = 'HOURLY', - DAILY = 'DAILY', - WEEKLY = 'WEEKLY', - MONTHLY = 'MONTHLY', - QUARTERLY = 'QUARTERLY', - YEARLY = 'YEARLY', -} +export const DataRefresh = { + NONE: 'NONE', + SECOND: 'SECOND', + MINUTE: 'MINUTE', + HOURLY: 'HOURLY', + DAILY: 'DAILY', + WEEKLY: 'WEEKLY', + MONTHLY: 'MONTHLY', + QUARTERLY: 'QUARTERLY', + YEARLY: 'YEARLY', +} as const; +export type DataRefresh = + | (typeof DataRefresh)[keyof typeof DataRefresh] + | (string & {}); ``` -The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 257) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. +The enum is a *time unit / interval*, not a "data refresh". It's used as `DataRefreshInfo.unit: DataRefresh` (line 332) which the wire format calls `data_refresh.unit`. Reading `DataRefresh.HOURLY` requires knowing the value names a frequency, not a refresh event. - **Category:** 1 (vague: name is the noun, not the unit). - **Suggested name:** `RefreshInterval`, `TimeUnit`, or `DataRefreshUnit`. - **Rationale:** Self-documenting enum name. ### 6. `Category` — generic enum name with 22 values -**Location:** `src/v1/model.ts:21-44` +**Location:** `src/v1/model.ts:26-49` ```ts -export enum Category { - ADVERTISING_AND_MARKETING = 'ADVERTISING_AND_MARKETING', +export const Category = { + ADVERTISING_AND_MARKETING: 'ADVERTISING_AND_MARKETING', ... - TRAVEL_AND_TOURISM = 'TRAVEL_AND_TOURISM', -} + TRAVEL_AND_TOURISM: 'TRAVEL_AND_TOURISM', +} as const; +export type Category = (typeof Category)[keyof typeof Category] | (string & {}); ``` `Category` is generic without a domain qualifier (compare with `AssetType`, `ListingType`, `MarketplaceFileType`). The other enums use a domain prefix; `Category` does not. Also, it's exported at the package root and a user importing `Category` doesn't know it's marketplace-scoped. - **Category:** 1 (vague), 17 (inconsistent qualifier convention). -- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 710). +- **Suggested name:** `ListingCategory` (since the only usage is `ListingSummary.categories: Category[]` at line 776). - **Rationale:** Cross-package collision avoidance and self-documentation. ### 7. `ContactInfo` — generic suffix on a single-purpose type -**Location:** `src/v1/model.ts:171-177` +**Location:** `src/v1/model.ts:237-242` ```ts /** contact info for the consumer requesting data or performing a listing installation */ @@ -160,14 +163,14 @@ export interface ContactInfo { } ``` -`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 730). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. +`*Info` suffix is generic. The type is reused only via `PersonalizationRequest.contactInfo: ContactInfo` (line 796). Also note: `firstName` / `lastName` / `email` / `company` describes a person, not generic "contact info". `Person`, `Contact`, or `ConsumerContact` would be more specific. - **Category:** 8 (redundant `Info` suffix), 1 (vague). - **Suggested name:** `Contact` or `ConsumerContact`. - **Rationale:** Cross-package, every `*Info` reads as "the info type"; specificity helps autocomplete. ### 8. `RegionInfo` — `Info` suffix on a single-purpose type -**Location:** `src/v1/model.ts:769-772` +**Location:** `src/v1/model.ts:835-838` ```ts export interface RegionInfo { @@ -184,7 +187,7 @@ a region descriptor. ### 9. `ShareInfo` — `Info` suffix on a sharing concept -**Location:** `src/v1/model.ts:816-819` +**Location:** `src/v1/model.ts:882-885` ```ts export interface ShareInfo { @@ -200,7 +203,7 @@ Same problem as #7 and #8. Additionally, `ShareInfo.type: ListingShareType` read ### 10. `ProviderInfo` — `Info` suffix on the canonical provider type -**Location:** `src/v1/model.ts:750-767` +**Location:** `src/v1/model.ts:816-833` ```ts export interface ProviderInfo { @@ -219,7 +222,7 @@ Same problem as #7. The package also has `CreateProviderRequest`, `GetProviderRe ### 11. `DataRefreshInfo` — `Info` suffix on an interval type -**Location:** `src/v1/model.ts:255-258` +**Location:** `src/v1/model.ts:330-333` ```ts export interface DataRefreshInfo { @@ -235,7 +238,7 @@ Same problem as #7. Also note: the type models a generic time interval, so the ` ### 12. `FileInfo` — `Info` suffix on the canonical file type -**Location:** `src/v1/model.ts:332-345` +**Location:** `src/v1/model.ts:412-425` ```ts export interface FileInfo { @@ -252,7 +255,7 @@ Same problem as #7. The package also has `CreateFileRequest`, `GetFileRequest`, ### 13. `ListingTag` — typed-but-not-typed tags -**Location:** `src/v1/model.ts:682, 720-725` +**Location:** `src/v1/model.ts:748, 786-791` ```ts export interface ListingDetail { @@ -277,23 +280,3 @@ The enum constrains tag *names* to a small set. Values are free-form strings. So - **Category:** 6 (misleading: name implies free-form labels, structure is constrained). - **Suggested name:** Rename type to clarify (e.g. `ListingAttribute`). - **Rationale:** "Tag" colloquially means a single label; this structure is closer to an attribute or property bag. - ---- - -## Low severity - -### 14. `ListingType.STANDARD` / `ListingType.PERSONALIZED` — adjective values - -**Location:** `src/v1/model.ts:118-121` - -```ts -export enum ListingType { - STANDARD = 'STANDARD', - PERSONALIZED = 'PERSONALIZED', -} -``` - -Two adjective values. Fine. Flagged because the package also has `PersonalizationRequest` (line 727) — the noun for `PERSONALIZED` mode. Cross-reference unclear. -- **Category:** Observation. -- **Suggested name:** No rename. -- **Rationale:** Internal consistency check. diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md index 33c71b9e..075db493 100644 --- a/.agent/naming-audit/metastores.md +++ b/.agent/naming-audit/metastores.md @@ -10,7 +10,7 @@ ### 1. Vague / generic names -#### 1.1 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:355, 357) +#### 1.1 `MetastoreAssignment.workspaceId` and `metastoreId` (model.ts:357, 359) Acceptable in isolation — but the *type* `MetastoreAssignment` is just a `(workspaceId, metastoreId, defaultCatalogName)` triple. The name "MetastoreAssignment" promises richer semantics than the three-field @@ -21,86 +21,48 @@ relationship directional in the name. ### 2. Misleading names -#### 2.1 `MetastoreInfo` (model.ts:365) +#### 2.1 `MetastoreInfo` (model.ts:369) "Info" suggests metadata about a metastore separate from the entity -itself; the type is in fact the entity. See also §4.1. +itself; the type is in fact the entity. Rename to `Metastore`. See +also §3.1. -#### 2.2 `getMetastoreSummary` is presented as info-about (client.ts:637) +#### 2.2 `getMetastoreSummary` is presented as info-about (client.ts:648) JSDoc says "Gets information about a metastore. This summary includes…". But the API in fact returns the current workspace's metastore — there is no metastore ID parameter. The name "summary" -omits the "current-workspace" semantics. Cf. -`getCurrentMetastoreAssignment`, which spells out "current". +omits the "current-workspace" semantics. Rename to signal the +current-workspace scope, as `getCurrentMetastoreAssignment` spells out +"current". --- -### 3. Overly verbose +### 3. Redundant suffixes -#### 3.1 `getCurrentMetastoreAssignment` (client.ts:578) -28-character method name. Acceptable — describes the semantics — but -combined with `getMetastoreSummary` (which is also "current-workspace" -in practice, §2.2) one of them carries redundant prefixing. - ---- - -### 4. Redundant suffixes - -#### 4.1 `…Info` suffix on `MetastoreInfo` (model.ts:365) +#### 3.1 `…Info` suffix on `MetastoreInfo` (model.ts:369) "Info" carries no semantic content. Go-SDK convention; TS would just -say `Metastore`. See §6.2. - -#### 4.2 `…Assignment` suffix on `MetastoreAssignment` and four request types -`CreateMetastoreAssignmentRequest`, `DeleteMetastoreAssignmentRequest`, -`UpdateMetastoreAssignmentRequest`, `GetCurrentMetastoreAssignmentRequest`, -`MetastoreAssignment`. The suffix is justified because "metastore -assignment" is a distinct concept. Not redundant — flagged for -completeness. +say `Metastore`. --- -### 5. Singular / plural mismatches - -#### 5.1 `ListMetastoresResponse.metastores` (model.ts:345) -Field is plural and correctly typed `MetastoreInfo[]` — no mismatch. -Flagged as a counter-example. - ---- - -### 6. Reserved-word collisions - -#### 6.1 `name` field on `CreateMetastoreRequest`, `MetastoreInfo`, `UpdateMetastoreRequest`, `GetMetastoreSummaryResponse` (model.ts:214, 291, 367, 469) -Routinely shadows `Function.prototype.name`. Common SDK convention; not -fixable in isolation. +### 4. Field contradicting type domain -#### 6.2 `region` field — collides with conceptual "region" (e.g. Intl.Locale region) in browser code. Minor. - ---- - -### 7. Field contradicting type domain - -#### 7.1 `CreateMetastoreRequest` and `UpdateMetastoreRequest` carry read-only output fields (model.ts:234-248, 489-503) +#### 4.1 `CreateMetastoreRequest` and `UpdateMetastoreRequest` carry read-only output fields (model.ts:238-252, 493-507) `metastoreId`, `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `globalMetastoreId`, `cloud`, `storageRootCredentialName`. These are server-populated; a creator/updater setting them is at best ignored. The type's name promises "create" or "update" but the shape contradicts that by including read-only output. Mirror of -catalogs §16.2. +catalogs §4.1. -#### 7.2 `GetMetastoreSummaryResponse` returns the full metastore (model.ts:287) +#### 4.2 `GetMetastoreSummaryResponse` returns the full metastore (model.ts:291) The type name promises a summary; the value is the full metastore entity, with the same 19 fields and docs as `MetastoreInfo`. --- -### 8. Inconsistent action verbs - -#### 8.1 No `fetch…` / `read…` / `retrieve…` outliers — read-side verbs are uniformly `get` / `list`. No issues. - ---- - ## Additional / cross-cutting observations -### A. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:476, 545, 771) +### A. `req.workspaceId` is interpolated into the URL via `String(req.workspaceId ?? '')` (client.ts:483, 554, 786) If `workspaceId` is undefined, the URL silently becomes `/api/2.1/unity-catalog/workspaces//metastore` (note the double slash) and the request will fail on the server. The optional typing of @@ -108,19 +70,7 @@ and the request will fail on the server. The optional typing of `DeleteMetastoreAssignmentRequest`, and `UpdateMetastoreAssignmentRequest` (each field is `bigint | undefined`) lets the bug hide. -### B. `req.id` is similarly optional but interpolated into URLs (client.ts:511, 610, 738) +### B. `req.id` is similarly optional but interpolated into URLs (client.ts:519, 621, 752) `${req.id ?? ''}` — same pattern: undefined id silently produces a malformed URL. The optional typing leaves the contract too loose for a required path parameter. - -### C. `DeleteMetastoreAssignmentRequest.metastoreId` is sent in the query string, not the path (client.ts:545-549) -On `DELETE /api/2.1/unity-catalog/workspaces/{workspaceId}/metastore`, -the request appends `?metastore_id=…`. That contradicts the doc on -`DeleteMetastoreAssignmentRequest.metastoreId` ("Query for the ID of -the metastore to delete.") only via the leading word "Query" — the -field name itself does not signal that the value is a query parameter, -not a path one. - -### D. `MetastoresClient` constructor throws bare `Error` for missing `host` (client.ts:112) -"Host is required." — bare `Error`. Not a naming issue, flagged in -passing for the broader review. diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md index 227a8ae8..d1eb0b7e 100644 --- a/.agent/naming-audit/modelregistry.md +++ b/.agent/naming-audit/modelregistry.md @@ -8,19 +8,18 @@ Staging / Production / Archived), transition-approval workflow, comments, tags, latest-version lookups, registry webhooks, and Databricks-specific permission/ACL extensions. Distinct from `registeredmodels` package which is the Unity-Catalog-scoped successor. -**Total weird names flagged:** 17 +**Total weird names flagged:** 15 ## Summary | Severity | Count | | --- | --- | | High | 13 | | Medium | 1 | -| Low | 2 | -| Observation | 1 | +| Low | 1 | ## High severity -### 1. `ActivityAction` enum and `availableActions` field — `model.ts:20-31, 187` +### 1. `ActivityAction` enum and `availableActions` field — `model.ts:21-35, 221` - **Why weird:** The field on `Activity` is named `availableActions: ActivityAction[]`, so the *type* is "actions". The enum mixes two unrelated domains (transition-request lifecycle + comment @@ -33,7 +32,7 @@ is the Unity-Catalog-scoped successor. bag-of-strings. Users typing `ActivityAction.` get suggested values that may be illegal for their actual context. -### 2. `RegistryEmailSubscriptionType` enum — `model.ts:106-111` +### 2. `RegistryEmailSubscriptionType` enum — `model.ts:123-131` - **Why weird:** Enum name says `Type` but values are *states* (`ALL_EVENTS`, `DEFAULT`, `SUBSCRIBED`, `UNSUBSCRIBED`). `DEFAULT` and `ALL_EVENTS` overlap in meaning. The class doc-comment marks it @@ -45,7 +44,7 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The field consuming the enum is already called `emailSubscriptionStatus`; the enum should match. -### 3. `CommentObject` — `model.ts:226` +### 3. `CommentObject` — `model.ts:260` - **Why weird:** `Object` is the most generic suffix possible in TS (everything is an object). The type is already a TS object, so the suffix conveys nothing. @@ -55,7 +54,7 @@ is the Unity-Catalog-scoped successor. ### 4. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, `TransitionModelVersionStageDatabricksRequest`, `ModelVersionDatabricks` — - `model.ts:525, 676, 744, 962` + `model.ts:559, 778, 996, 710` - **Why weird:** `Databricks` as a type suffix. The whole SDK is the Databricks SDK; everything is "Databricks". The suffix is used to distinguish workspace-Databricks extensions from upstream MLflow @@ -71,7 +70,7 @@ is the Unity-Catalog-scoped successor. (then split by capability). The current "shadow type per extension" is a generator artefact, not a user-friendly API. -### 5. `TransitionModelVersionStageDatabricksRequest` — `model.ts:962` +### 5. `TransitionModelVersionStageDatabricksRequest` — `model.ts:996` - **Why weird:** Six-word PascalCase identifier with awkward word order. Reads as "transition[verb] model-version-stage[object]-databricks[suffix]-request[suffix]". For a @@ -87,7 +86,7 @@ is the Unity-Catalog-scoped successor. performing similar workspace operations; the asymmetric names obscure this. -### 6. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:525` +### 6. `GetRegisteredModelDatabricksRequest` request DTO — `model.ts:559` - **Why weird:** Verb-phrase request type name (`GetX`) is OK if used consistently, but `GetRegisteredModelDatabricksRequest` is the only method the SDK exposes to fetch a registered model — there is no plain @@ -99,28 +98,27 @@ is the Unity-Catalog-scoped successor. - **Rationale:** No need for the disambiguation suffix when there's no sibling. -### 7. `client.listTransitionsRequest` method vs `ListTransitionRequest` - request type — `client.ts:527, model.ts:632` -- **Why weird:** The method is `listTransitionsRequest` (plural - "Transitions") but the request type is `ListTransitionRequest` - (singular). The doc comment says "Gets a list of all open stage - transition requests" so it's listing *requests* (plural). The method - name should be `listTransitionRequests` (plural "Requests"), and the - request type should be `ListTransitionRequestsRequest`. Right now - none of the four name parts agree. Note: many sibling request DTOs in - this file have been given the `Request` suffix (e.g. +### 7. `ListTransitionRequest` / `ListTransitionResponse` types vs + `listTransitionRequests` method — `model.ts:666, 673`, `client.ts:535` +- **Why weird:** The client method is `listTransitionRequests` and its + doc comment says "Gets a list of all open stage transition requests", + so the operation lists *transition requests* (plural). But the request + DTO is `ListTransitionRequest` (singular "Transition", missing the + "Requests" noun) and the response is `ListTransitionResponse`, so the + type names disagree with the method that consumes them. Sibling + request DTOs in this file name the full operation noun (e.g. `CreateCommentRequest`, `DeleteRegistryWebhookRequest`, - `RenameRegisteredModelRequest`), but `ListTransitionRequest` was left - as the bare verb-phrase, deepening the inconsistency. + `RenameRegisteredModelRequest`); `ListTransitionRequest` reads instead + as "a request to list a transition". - **Category:** 9 (singular/plural mismatch), 6 (misleading), 20 (type suffix tautology if renamed to `ListTransitionRequestsRequest`). -- **Suggested name:** Method `listTransitionRequests`; request type - `ListTransitionRequestsRequest`; response type - `ListTransitionRequestsResponse`. -- **Rationale:** The method name in JS conventions describes the - collection being listed; here that's "transition requests", plural. +- **Suggested name:** Request type `ListTransitionRequestsRequest`; + response type `ListTransitionRequestsResponse`. +- **Rationale:** The DTO names should describe the collection being + listed — "transition requests", plural — matching the + `listTransitionRequests` method. -### 8. `RegistryWebhook` vs `Webhook` — `model.ts:773` +### 8. `RegistryWebhook` vs `Webhook` — `model.ts:807` - **Why weird:** Type is `RegistryWebhook` but client methods, paths, and request types alternate: `CreateRegistryWebhookRequest`, `ListRegistryWebhooksRequest`, `UpdateRegistryWebhookRequest`, @@ -133,7 +131,7 @@ is the Unity-Catalog-scoped successor. `TestWebhookRequest`. - **Rationale:** Package name already establishes the registry context. -### 9. `HttpUrlSpec` / `JobSpec` — `model.ts:534, 545` +### 9. `HttpUrlSpec` / `JobSpec` — `model.ts:568, 579` - **Why weird:** `Spec` is a vague suffix shared by every config-bag in the SDK. Two sibling types in the same package, only the `Spec` suffix distinguishing them. `HttpUrlSpec` is the *target* of a webhook @@ -146,18 +144,18 @@ is the Unity-Catalog-scoped successor. - **Rationale:** The two together discriminate the webhook destination kind; the naming should make that obvious. -### 10. `LinkedFeature` — `model.ts:555` -- **Why weird:** Doc comment says "Feature for model version. ([ML-57150] - Renamed from Feature to LinkedFeature)". The ticket number leaks into - the public docstring. Type name was changed for internal reasons - (probably to avoid collision); the rename history doesn't belong in - the public TS surface. +### 10. `LinkedFeature` — `model.ts:589` +- **Why weird:** Nothing about the type is "linked": its fields + (`featureTableName`, `featureName`, `featureTableId`) are just + identifiers pointing at a feature in the feature store, and the doc + comment says only "Feature for model version." Even the package's own + usage drops the prefix — `FeatureList.features` is typed + `LinkedFeature[]` (`model.ts:525`). - **Category:** 1 (vague), 6 (misleading: nothing "linked" about a feature-table-name + feature-name pair). - **Suggested name:** `ModelFeatureReference` or just `FeatureRef`. - **Rationale:** "Linked" doesn't describe anything specific to this - type; the fields are just identifiers pointing at a feature in the - feature store. + type; the fields are identifiers referencing a feature-store entry. ### 11. `Databricks` as a suffix is overused - **Why weird:** Distinct type names still end in `Databricks` (see #4): @@ -171,7 +169,7 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** See #4. - **Rationale:** See #4. -### 12. `getRegisteredModelDatabricks` client method — `client.ts:424` +### 12. `getRegisteredModelDatabricks` client method — `client.ts:430` - **Why weird:** Method name carries `Databricks` mid-position (between the noun `RegisteredModel` and any conceptual suffix). The whole SDK is the Databricks SDK; embedding `Databricks` inside a method name is @@ -192,7 +190,7 @@ is the Unity-Catalog-scoped successor. no analogue in this TS surface; remove it. ### 13. `transitionModelVersionStageDatabricks` client method — - `client.ts:632` + `client.ts:643` - **Why weird:** Same `Databricks` mid-position leak as #12. The token sits between `Stage` and the implicit method suffix, marking the method as the workspace-extension variant of an upstream MLflow RPC. @@ -210,12 +208,12 @@ is the Unity-Catalog-scoped successor. ## Medium severity -### 14. `listLatestVersions` / `ListLatestVersionsRequest` — `client.ts:1029`, - `model.ts:564` +### 14. `listLatestVersions` / `ListLatestVersionsRequest` — `client.ts:1051`, + `model.ts:598` - **Why weird:** The method returns *one* version per stage, not "the latest version" globally. The name reads as "list the latest versions" (plural overall) but the meaning is "give me the latest one for each - stage". The docstring on the method (`client.ts:1028`) says "Gets the + stage". The docstring on the method (`client.ts:1050`) says "Gets the latest version of a registered model" (singular) — that's *wrong*; the actual response returns a list keyed by stage. - **Category:** 6 (misleading), 9 (singular/plural confusion). @@ -225,15 +223,7 @@ is the Unity-Catalog-scoped successor. ## Low severity -### 15. `pageToken`, `nextPageToken`, `maxResults` — `model.ts:573, 575, - 581, 621, 622, 629, 861, 870, 877, 888, 896, 903` -- **Why weird:** Consistent across the package — good. Noted for - completeness. -- **Category:** N/A (consistent). -- **Suggested name:** No change. -- **Rationale:** Observation. - -### 16. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:847` +### 15. `newName: string` on `RenameRegisteredModelRequest` — `model.ts:881` - **Why weird:** Field doc says "If provided, updates the name for this `registered_model`." Slightly confusing because `RenameRegisteredModelRequest` is *the* rename operation — "if @@ -243,14 +233,3 @@ is the Unity-Catalog-scoped successor. - **Suggested name:** Make it required (drop `?`), or document that omission is a no-op. - **Rationale:** Optional-but-required-in-practice fields confuse users. - -## Observations - -### 17. Action-verb conventions in `Client` -The client mixes `Approve` / `Reject` (active verbs for transition- -request lifecycle) with `Set` / `Delete` (CRUD) and `Test` (verb for -webhook health) and `Transition` (verb-as-method-name for state -machine). Consistency-wise the surface is jagged but each verb is -reasonably motivated by the underlying state model. Not a defect, but -worth noting. -- **Category:** 17 (mixed but justified). diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md index 0fbc8a59..90a556ce 100644 --- a/.agent/naming-audit/modelserving.md +++ b/.agent/naming-audit/modelserving.md @@ -2,8 +2,8 @@ **Path:** `packages/modelserving/src/v1/` **Versions audited:** v1 -**Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Created by the 2026-05-22 regeneration which consolidated the prior `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. -**Total weird names flagged:** 10 +**Inferred domain:** Model Serving control plane — CRUD over "serving endpoints" (a.k.a. "inference endpoints"), plus a parallel provisioned-throughput (PT) variant, plus side-channel updates for AI Gateway, rate limits, tags, notifications, OpenAPI schema fetch, served-model logs (service + build), endpoint metrics export, and an out-of-band UC-connection-backed HTTP proxy (`httpRequest` / `ExternalFunction*`). Consolidates the former `modelservingdebug` and `modelservingmanagement` packages into one. Sibling package: `modelservingquery` (data-plane inference). The wire URL prefix is `/api/2.0/serving-endpoints`; the docs say "serving endpoint"; the TS types say `InferenceEndpoint`. +**Total weird names flagged:** 9 ## Summary | Severity | Count | @@ -11,43 +11,42 @@ | High | 4 | | Medium | 4 | | Low | 1 | -| Observation | 1 | ## High severity -### 1. `ServedModel` type now also holds non-models — `src/v1/model.ts:998` -- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1001) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1003) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. +### 1. `ServedModel` type now also holds non-models — `src/v1/model.ts:1020` +- **Why weird:** The type `ServedModel` represents the "served entity" — and the doc on `ServedModel.externalModel` (line 1024) acknowledges this directly: "Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified...". The doc on `ServedModel.entityName` (line 1025) further widens the meaning: "The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or *a function of type FEATURE_SPEC in the UC*." So `ServedModel` can be a model OR a function. Every `EndpointCoreConfig*.servedEntities: ServedModel[]` confirms this: the field is *called* `servedEntities` but its element type is `ServedModel`. Type name lies; field name is correct. - **Category:** 6 (misleading), 15 (generic field name vs specific type name). - **Suggested name:** Rename `ServedModel` → `ServedEntity`. Keep the field name `servedEntities`. The wire stays whatever it is. - **Rationale:** A type whose name contradicts its values is the highest-impact naming bug; doc text already concedes the rename is correct. -### 2. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:631` +### 2. Method `httpRequest` for "make external services call using UC Connection" — `src/v1/client.ts:652` - **Why weird:** `httpRequest` on a model-serving `Client` is wildly mis-located. The doc reads: "Make external services call using the credentials stored in UC Connection." This is a Unity-Catalog-Connection HTTP proxy endpoint that happens to live at `/api/2.0/external-function`. It has nothing to do with serving endpoints. The method name `httpRequest` is the most generic name in HTTP (the global `Request` constructor builds an HTTP request); collides with `HttpRequest` from `@databricks/sdk-core/http`. The request type is `ExternalFunctionRequest`, response is `ExternalFunctionResponse`, URL says `external-function`, doc says "UC Connection" — none of those words is in the method name. - **Category:** 1 (vague), 6 (misleading), 14 (collides with global `Request`/`HttpRequest`). - **Suggested name:** Rename `httpRequest` → `invokeExternalFunction` or `callConnection`. Better: move the method to a different package (`uc-connections` or similar). The current placement is a layering bug. - **Rationale:** A method called `httpRequest` on a model-serving `Client` will be the first thing every new SDK user tries when they want to query an endpoint — and will fail with confusing errors. Naming + placement is a footgun. -### 3. `Behavior` enum is unqualified — `src/v1/model.ts:5-10` -- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 874). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `NONE | BLOCK | MASK` — so this is *PII action behavior*. +### 3. `Behavior` enum is unqualified — `src/v1/model.ts:6-12` +- **Why weird:** Top-level export named `Behavior` — the most generic noun possible for an enum. It is used as `PiiSettings.behavior: Behavior` (line 896). A consumer importing `Behavior` from `@databricks/sdk-modelserving/v1` has no idea this is about PII guardrails. Other packages will have their own `Behavior` and import aliases become mandatory. Values: `NONE | BLOCK | MASK` — so this is *PII action behavior*. - **Category:** 1 (vague/generic), 15 (generic name losing meaning). - **Suggested name:** `PiiBehavior` or `PiiGuardrailAction`. - **Rationale:** Domain-specific enum names make import lists self-documenting; `Behavior` alone forces every reader to chase the type. -### 4. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:540`, `src/v1/client.ts:227` -- **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but `Get + Export + Endpoint + Metrics + Request` parses as five nouns in a row. The doc string (`client.ts:226`) confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English phrase is "export the endpoint's metrics" → method `exportEndpointMetrics`. Compare with sibling methods on the same client: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags` — none prefix the noun with an output format. +### 4. `GetExportEndpointMetricsRequest` / `getExportEndpointMetrics` — five-noun garble — `src/v1/model.ts:562`, `src/v1/client.ts:231` +- **Why weird:** The grammar is broken. The expected reading is *"export endpoint metrics" → returns metrics in export format*, but `Get + Export + Endpoint + Metrics + Request` parses as five nouns in a row. The doc string (`client.ts:230`) confirms the intent: "Retrieves the metrics associated with the provided serving endpoint in either Prometheus or OpenMetrics exposition format". The natural English phrase is "export the endpoint's metrics" → method `exportEndpointMetrics`. Compare with sibling methods on the same client: `getInferenceEndpoint`, `getInferenceEndpointSchema`, `patchInferenceEndpointTags` — none prefix the noun with an output format. - **Category:** 6 (misleading), 7 (overly verbose), 17 (inconsistent verb — every other method is `getX`, this one is `getExportX`). - **Suggested name:** `exportEndpointMetrics(req: ExportEndpointMetricsRequest)` returning `EndpointMetrics`. Or `getEndpointMetrics(req: GetEndpointMetricsRequest)` returning `EndpointMetrics`. The "export" framing is a wire-protocol detail (Prometheus format) that does not belong in the method name. - **Rationale:** Method naming consistency across siblings; English grammar. ## Medium severity -### 5. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:200, 231, 261, 289, 319, 350, 409, 444, 479, 522, 557, 600` +### 5. `name ?? ''` empty-string fallback when the field is "required" — `src/v1/client.ts:204, 236, 267, 296, 327, 359, 420, 456, 492, 537, 573, 621` - **Why weird:** The JSDoc on each request says "This field is required" yet the type marks `name?: string | undefined` *optional* and the URL is built with `${req.name ?? ''}` — if the caller forgets to set it, the SDK silently emits a URL like `/api/2.0/serving-endpoints//metrics` (double slash) which will 404 server-side. The contradiction between "required per JSDoc" and "optional per TS type" is a typing inconsistency that bites consumers. - **Category:** 6 (misleading — JSDoc contradicts type), 16 (field contradicting type domain). - **Suggested fix:** Mark `name` as required (drop `?: ... | undefined`). Remove the `?? ''` fallback so a missing value throws earlier. Same applies to `servedModelName`. - **Rationale:** Optional + "required" JSDoc + empty-string fallback is a triple-violation. Cf. AIP-122 (https://google.aip.dev/122) which mandates path parameters be required. -### 6. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:711-732, 784-805, 857-878, 930-951` +### 6. `done()` on waiter classes returns `true` for both success AND failure — `src/v1/client.ts:733-754, 806-827, 879-900, 952-973` - **Why weird:** Waiter `done()` returns `true` for: - `NOT_UPDATING` (success) - `UPDATE_FAILED` (failure) @@ -58,13 +57,13 @@ - **Suggested name:** Rename `done()` → `isTerminal()` or split into `isSuccess()` / `isTerminal()`. Or have `done()` throw on failure for parity with `wait()`. - **Rationale:** Method-name semantics divergence is a runtime bug, not a stylistic one. -### 7. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:733-737` +### 7. `ModelDataPlaneInfo` wraps `DataPlaneInfo` — `Info`-around-`Info` placeholder — `src/v1/model.ts:755-759` - **Why weird:** `ModelDataPlaneInfo` is a one-field wrapper: `{queryInfo?: DataPlaneInfo}`. So the public surface is `endpoint.dataPlaneInfo: ModelDataPlaneInfo` → `.queryInfo: DataPlaneInfo` → `.endpointUrl, .authorizationDetails`. Two layers of `*Info` suffix wrapping each other, where the outer layer carries no information beyond "this is the model-specific subset of data-plane info" — but it has only one field, so the wrapping is a pure architectural placeholder reserved for future operations. The JSDoc on `ModelDataPlaneInfo` ("A representation of all DataPlaneInfo for operations that can be done on a model through Data Plane APIs.") tautologically repeats the type name. - **Category:** 7 (overly verbose suffix chain), 20 (type-suffix tautology on `dataPlaneInfo: ModelDataPlaneInfo`). - **Suggested name:** Collapse — drop `ModelDataPlaneInfo` and inline `DataPlaneInfo` as `InferenceEndpointDetailed.queryDataPlane?: DataPlaneInfo`. If a future operation needs a second data-plane URL, add a field then. - **Rationale:** `Info`-wrapping-`Info` is an architectural placeholder that doesn't survive into idiomatic TS where optional fields obviate the wrapper. -### 8. `GetServedModelLogsResponse.logs: string` is a single blob, name is plural — `src/v1/model.ts:569, 581` +### 8. `GetServedModelLogsResponse.logs: string` is a single blob, name is plural — `src/v1/model.ts:591, 603` - **Why weird:** Both `GetServedModelBuildLogsResponse` and `GetServedModelLogsResponse` have `logs?: string`. The field name is plural but the type is a single string — many log *lines* concatenated. A user doing `for (const line of response.logs)` will iterate characters, not lines. - **Category:** 9 (singular/plural mismatch). - **Suggested fix:** Re-shape to `logs: string[]` (split lines server-side) so the plural name matches an iterable of lines. @@ -72,14 +71,8 @@ ## Low severity -### 9. `Get*` prefix on every read method — `src/v1/client.ts:227, 257, 285, 315, 346` +### 9. `Get*` prefix on every read method — `src/v1/client.ts:231, 262, 291, 322, 354` - **Why weird:** Every read method here is prefixed `get*`. The `Get*` verb prefix on TS methods is a Go/Java/.NET pattern; in TS, a noun method `endpointMetrics()` or `metrics()` is more idiomatic for read operations (cf. `URL.searchParams`, `Response.json()`). Where TS does use `get*`, it's typically on synchronous accessors. - **Category:** 14 (Go/Java-style names). - **Suggested name:** Verb-first for actions: `exportMetrics(req)`, `fetchServedModelLogs(req)`, `fetchServedModelBuildLogs(req)`. Or property-style if the request is trivial. - **Rationale:** Google TS Style Guide § Names of functions (https://google.github.io/styleguide/tsguide.html#methods) prefers imperative verbs, but does not mandate `get*` for retrievals. SDK-wide call, flag for project review. - -## Observation - -### 10. `ExternalModel.config` discriminated union with nine variants — `src/v1/model.ts:473-519` -Nine `$case` variants, no exhaustiveness check at the type level. If a tenth provider is added, the discriminated union types it correctly, but the cascade (lines 1389-1430) is hand-rolled and will silently miss the new case. The names of the discriminator keys also vary in casing relative to the type names. This is a maintenance smell, not strictly a naming bug — but the *uniformity* of the names (`Config`) gives a false sense of "this is a clean enum" when it is actually a tower of `if-else`. -- **Category:** 12 (duplicate concept). diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md index b880e4a6..f6c67322 100644 --- a/.agent/naming-audit/modelservingquery.md +++ b/.agent/naming-audit/modelservingquery.md @@ -4,10 +4,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/modelservingquery/` **Version audited:** `v1` -**Total weird names flagged:** 8 - -Rescanned on 2026-06-02 against the current generated output. Line numbers were -refreshed to the current source. +**Total weird names flagged:** 5 --- @@ -18,11 +15,8 @@ refreshed to the current source. | 1 | High | `model.ts` interface | `V1ResponseChoiceElement` | Version segment leaked into type name; empty `Element` suffix | | 2 | High | `model.ts` interface | `EmbeddingsV1ResponseEmbeddingElement` | Version segment leaked into type name; empty `Element` suffix | | 3 | High | `model.ts` interface | `ExternalModelUsageElement` | Misleading scope ("External" implies non-Databricks) and "Element" suffix is meaningless | -| 4 | High | `model.ts` interface | `QueryEndpointInputRequest_ExtraParamsEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | -| 5 | High | `model.ts` interface | `QueryEndpointInputRequest_UsageContextEntry` | Proto-architectural-leak: `_Entry` is Protobuf map-entry generator suffix | -| 6 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | -| 7 | Medium | `model.ts` enum | `ChatMessageRole` | Redundant `Message` segment — values are roles of the speaker, not types of message | -| 8 | Low | `model.ts` enum value | `ChatMessageRole.ASSISTANT` | OK, but missing common values (`tool`, `function`) — incomplete enum | +| 4 | Medium | `client.ts` method | `query()` | Verb-tense / reserved-word feel; conflicts with SQL packages | +| 5 | Medium | `model.ts` enum | `ChatMessageRole` | Redundant `Message` segment — values are roles of the speaker, not types of message | --- @@ -30,7 +24,7 @@ refreshed to the current source. ### 1. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix -**Location:** `src/v1/model.ts:185-196` +**Location:** `src/v1/model.ts:187-198` **Categories:** 7 (overly verbose), 8 (empty suffix), 14 (Go/Java-style names) @@ -42,7 +36,7 @@ The `V1` prefix duplicates the directory it lives in (`src/v1/`). When a hypothe ### 2. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix -**Location:** `src/v1/model.ts:58-65` +**Location:** `src/v1/model.ts:72-79` **Categories:** 7 (overly verbose), 8 (empty suffix) @@ -58,7 +52,7 @@ Same `V1` leak as finding #1. The `Element` suffix is empty — the type is the ### 3. `ExternalModelUsageElement` — misleading scope + meaningless suffix -**Location:** `src/v1/model.ts:67-74` +**Location:** `src/v1/model.ts:81-88` **Categories:** 6 (misleading names), 8 (redundant suffixes), 16 (field contradicting type domain) @@ -78,35 +72,11 @@ Two problems: 1. **"External" is misleading.** This type is the OpenAI-spec `usage` block, returned by Databricks Foundation Model and Databricks Provisioned Throughput endpoints — both of which are **internal** Databricks-managed models. JSDoc in `QueryEndpointResponse.usage` even says "external/foundation model", but Databricks Foundation Models are explicitly *first-party*. The "External" prefix mislabels its scope. 2. **"Element" is meaningless.** The type is the single usage block, not "an element of a list." `TokenUsage`, `Usage`, or `ModelUsage` would suffice. -### 4. `QueryEndpointInputRequest_ExtraParamsEntry` — proto map-entry leak - -**Location:** `src/v1/model.ts:142-145` - -**Why:** Underscore-separated `_ExtraParamsEntry` suffix is the verbatim Protobuf code-generator pattern for the synthetic map-entry message that backs `map extra_params`. The type is exported but never referenced by the client or by `marshalQueryEndpointInputRequestSchema`, which uses `z.record(z.string(), z.string())` directly. The accompanying `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested message name.` directive on line 141 explicitly acknowledges the leak. A TS SDK consumer has no need for the map-entry container shape; only the `Record` itself. - -**Category:** proto-architectural-leak (Protobuf generator artefact: `_Entry` map-entry message) - -**Suggested:** Delete the exported type entirely. A `Record` alias is already the idiomatic TS surface for a string-to-string map. - -**Rationale:** `_Entry` types are a proto-generator implementation detail (`map` lowers to a hidden nested message named `Entry`). Re-exporting them through a TS SDK forces language-specific generator scaffolding into the public API. The file's own ESLint disable comment is direct evidence that the name violates the project's naming convention — it is suppressed rather than fixed. - -### 5. `QueryEndpointInputRequest_UsageContextEntry` — proto map-entry leak - -**Location:** `src/v1/model.ts:148-151` - -**Why:** Same proto-architectural leak as finding #4, applied to the `usage_context` map field. The interface is exported, never used in the schema (which uses `z.record(z.string(), z.string())`), and the file's own ESLint directive on line 147 labels it "Proto-style nested message name." Duplicate leak from the same generator template. - -**Category:** proto-architectural-leak (Protobuf generator artefact: `_Entry` map-entry message) - -**Suggested:** Delete the exported type entirely; `Record` is the natural TS surface. - -**Rationale:** Mirror of #4. Two `_Entry` exports inflate the package surface area with proto-internal types that have no meaningful TS use case. They are a recurring pattern across packages with map fields, suitable for generator-level suppression. - --- ## Medium severity -### 6. `query()` — verb-tense / reserved-word feel +### 4. `query()` — verb-tense / reserved-word feel **Location:** `src/v1/client.ts:59-86` @@ -114,46 +84,28 @@ Two problems: ```ts /** Query a serving endpoint */ -async query(req: QueryEndpointInputRequest, options?: CallOptions): Promise { ... } +async query(req: QueryEndpointRequest, options?: CallOptions): Promise { ... } ``` The method is named `query` — a verb that doubles as the common SQL noun, and that already exists as a method on `IDBDatabase` and on the unrelated `queries` package. `invoke`, `predict`, or `call` would match the underlying REST verb (`POST /invocations`) and would not collide with SQL nomenclature. Also: the method signature omits `endpointName` as a first arg — it has to be supplied inside the input as `req.name`, which conflates the URL parameter with the request body. -### 7. `ChatMessageRole` enum — redundant `Message` segment +### 5. `ChatMessageRole` enum — redundant `Message` segment -**Location:** `src/v1/model.ts:17-23` +**Location:** `src/v1/model.ts:17-27` **Category:** 8 (redundant segment) ```ts /** The role of the message. One of [system, user, assistant]. */ -export enum ChatMessageRole { - CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', - SYSTEM = 'system', - USER = 'user', - ASSISTANT = 'assistant', -} +export const ChatMessageRole = { + CHAT_MESSAGE_ROLE_UNSPECIFIED: 'CHAT_MESSAGE_ROLE_UNSPECIFIED', + SYSTEM: 'system', + USER: 'user', + ASSISTANT: 'assistant', +} as const; +export type ChatMessageRole = + | (typeof ChatMessageRole)[keyof typeof ChatMessageRole] + | (string & {}); ``` The values are not types of "chat message" — they are types of speaker / agent. `ChatRole` (drop `Message`) would parse more naturally because the *role* belongs to the *speaker*, not the *message*. The OpenAI vocabulary that this mirrors uses `role` (not `messageRole`) for the same reason. - ---- - -## Low severity - -### 8. `ChatMessageRole.ASSISTANT` — incomplete enum - -**Location:** `src/v1/model.ts:17-23` - -**Category:** 6 (misleading names) - -```ts -export enum ChatMessageRole { - CHAT_MESSAGE_ROLE_UNSPECIFIED = 'CHAT_MESSAGE_ROLE_UNSPECIFIED', - SYSTEM = 'system', - USER = 'user', - ASSISTANT = 'assistant', -} -``` - -Four values (counting the proto-style `UNSPECIFIED` sentinel), but the OpenAI spec also includes `tool` and `function` (and recent versions add `developer`). The enum is *closed* in TS (an exhaustive switch matches only 4 cases), so the wire format can outgrow the enum. The enum should include the OpenAI-mandated values. Naming-adjacent; flagged because the SDK is meant to broker LLM traffic. diff --git a/.agent/naming-audit/networking.md b/.agent/naming-audit/networking.md index 059771f9..b7896555 100644 --- a/.agent/naming-audit/networking.md +++ b/.agent/naming-audit/networking.md @@ -12,42 +12,34 @@ ## Medium severity -### 1. `ListNetworkRequest` — `src/v1/model.ts:1440` +### 1. `ListNetworkRequest` — `src/v1/model.ts:1294` - **Why weird:** The noun is singular (`Network`) where the sibling list request types in the package pluralise (`ListNetworkPoliciesRequest` - at line 1426, `ListNetworkConnectivityConfigsRequest` at line 1412). - The proto-tier `Public` infix was dropped in the 2026-05-22 - regeneration, leaving the residual singular/plural inconsistency. + at line 1280, `ListNetworkConnectivityConfigsRequest` at line 1266). - **Category:** Singular/plural inconsistency. - **Suggested name:** `ListNetworksRequest`. - **Rationale:** A list operation returns multiple items; pluralise the noun to align with the rest of the package's `List*Request` naming. -### 2. `ListNetworkResponse` — `src/v1/model.ts:1444` +### 2. `ListNetworkResponse` — `src/v1/model.ts:1298` - **Why weird:** Same singular/plural mismatch as #1. Sibling list - response types pluralise (`ListNetworkPoliciesResponse` at line 1433, - `ListNetworkConnectivityConfigsResponse` at line 1420). The proto-tier - `Public` infix was dropped in the 2026-05-22 regeneration, leaving - the residual singular/plural inconsistency. + response types pluralise (`ListNetworkPoliciesResponse` at line 1287, + `ListNetworkConnectivityConfigsResponse` at line 1274). - **Category:** Singular/plural inconsistency. - **Suggested name:** `ListNetworksResponse`. - **Rationale:** Same as #1. -### 3. `ListVpcEndpointRequest` — `src/v1/model.ts:1456` +### 3. `ListVpcEndpointRequest` — `src/v1/model.ts:1310` - **Why weird:** Same singular/plural mismatch as #1. The list request - for VPC endpoints uses a singular noun. The proto-tier `Public` infix - was dropped in the 2026-05-22 regeneration, leaving the residual - singular/plural inconsistency. + for VPC endpoints uses a singular noun. - **Category:** Singular/plural inconsistency. - **Suggested name:** `ListVpcEndpointsRequest`. - **Rationale:** Same as #1; pluralise the noun the way other list request types in the package do. -### 4. `ListVpcEndpointResponse` — `src/v1/model.ts:1460` +### 4. `ListVpcEndpointResponse` — `src/v1/model.ts:1314` - **Why weird:** Same singular/plural mismatch as #1. The list response - for VPC endpoints uses a singular noun. The proto-tier `Public` infix - was dropped in the 2026-05-22 regeneration, leaving the residual - singular/plural inconsistency. + for VPC endpoints uses a singular noun. - **Category:** Singular/plural inconsistency. - **Suggested name:** `ListVpcEndpointsResponse`. - **Rationale:** Same as #1. diff --git a/.agent/naming-audit/notificationdestinations.md b/.agent/naming-audit/notificationdestinations.md index 4c5aa11e..015735f1 100644 --- a/.agent/naming-audit/notificationdestinations.md +++ b/.agent/naming-audit/notificationdestinations.md @@ -17,31 +17,34 @@ | # | Severity | Location | Name | Category | |---|----------|----------|------|----------| -| 1 | High | `model.ts:5-11` | `DestinationType` | 1 (vague) | -| 2 | High | `model.ts:13-21` | `Config` (type) | 1 (vague) | -| 3 | High | `model.ts:42-55` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | -| 4 | Low | `client.ts:74`, `:82`, etc. | `req` / `resp` / `httpReq` abbreviations | 5 (cryptic abbreviation) | -| 5 | Obs | `model.ts:43-54` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | +| 1 | High | `model.ts:6-15` | `DestinationType` | 1 (vague) | +| 2 | High | `model.ts:17-25` | `Config` (type) | 1 (vague) | +| 3 | High | `model.ts:46-59` | `GenericWebhookConfig` | 1 (vague — "generic" carries no info) | +| 4 | Low | `client.ts:73`, `:82`, etc. | `req` / `resp` / `httpReq` abbreviations | 5 (cryptic abbreviation) | +| 5 | Obs | `model.ts:47-58` | `[Input-Only]` / `[Output-Only]` doc convention is not encoded in types | 6 (type-level dishonesty) | ## High severity -### 1. `DestinationType` — vague enum name lacks domain anchor — `src/v1/model.ts:5-11` +### 1. `DestinationType` — vague enum name lacks domain anchor — `src/v1/model.ts:6-15` - **Code:** ```ts - export enum DestinationType { - SLACK = 'SLACK', - EMAIL = 'EMAIL', - WEBHOOK = 'WEBHOOK', - PAGERDUTY = 'PAGERDUTY', - MICROSOFT_TEAMS = 'MICROSOFT_TEAMS', - } + export const DestinationType = { + SLACK: 'SLACK', + EMAIL: 'EMAIL', + WEBHOOK: 'WEBHOOK', + PAGERDUTY: 'PAGERDUTY', + MICROSOFT_TEAMS: 'MICROSOFT_TEAMS', + } as const; + export type DestinationType = + | (typeof DestinationType)[keyof typeof DestinationType] + | (string & {}); ``` - **Why weird:** Exported at package root as just `DestinationType`. The word "destination" is overloaded across the SDK — there is a `destination` concept in jobs (`webhook destination`), workflows (`sink destination`), and infra (`DBFS destination`). A user `import { DestinationType } from '@databricks/sdk-notificationdestinations/v1'` and then mixing it with `import { DestinationType } from '@databricks/sdk-pipelines/v1'` (if it existed) will get a name collision. Also, the values are not "destination types" but "notification channels"; the enum mixes the term-of-art ("destination" = the addressable target) with the type-of-target. Compare with `notification-destinations` REST path: the enum could be `NotificationChannel` or `NotificationDestinationKind`. - **Category:** 1 (vague/generic). - **Suggested name:** `NotificationChannel` or, less invasive, `NotificationDestinationType`. - **Rationale:** Domain-anchored enum names protect users from cross-package collisions and read better in IDE autocomplete (`NotificationChannel.SLACK` vs `DestinationType.SLACK`). -### 2. `Config` (interface) — vague top-level type name — `src/v1/model.ts:13-21` +### 2. `Config` (interface) — vague top-level type name — `src/v1/model.ts:17-25` - **Code:** ```ts export interface Config { @@ -59,7 +62,7 @@ - **Suggested name:** Rename the type to `NotificationDestinationConfig` (matches the package's domain prefix). - **Rationale:** A domain-anchored type name eliminates the cross-package collision risk. -### 3. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:42-55` +### 3. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:46-59` - **Code:** ```ts export interface GenericWebhookConfig { @@ -79,7 +82,7 @@ ## Low severity -### 4. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:74, 82, 89, 106, 109, 134, 137, 162, 182, 201, 219, 234` +### 4. `req` / `resp` / `httpReq` abbreviations — `src/v1/client.ts:73, 82, 89, 106, 111, 135, 140, 164, 178, 204, 222, 231` - **Code:** parameter and local-variable names throughout the client. - **Why weird:** Three-to-five-letter abbreviations everywhere. Project rules (typescript.mdc) discourage cryptic abbreviations. - **Category:** 5 (cryptic abbreviation). @@ -87,7 +90,7 @@ ## Observations -### 5. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:43-103`, `:117-136` +### 5. `[Input-Only]` / `[Output-Only]` doc markers — convention not encoded in types — `src/v1/model.ts:47-107`, `:122-140` JSDoc bracket prefixes mark every secret-bearing field as either input-only or output-only. The TS type system makes both fields `... | undefined` simultaneously, so callers can construct an object that sets both a secret and its `*Set` mirror; the latter is silently ignored on the wire. A cleaner design splits the input and output types or uses TS template literal types / branded types to enforce the modality. - **Category:** 6 (type-level dishonesty). - **Suggested:** Split `SlackConfigInput` / `SlackConfigOutput`, etc. Or accept that secrets cannot round-trip and document at type level (`type Secret = T | { isSet: boolean }`). diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md index 393c035d..fedd6e46 100644 --- a/.agent/naming-audit/pipelines.md +++ b/.agent/naming-audit/pipelines.md @@ -5,10 +5,10 @@ **Inferred domain:** Lakeflow Declarative Pipelines (formerly Delta Live Tables / DLT) — create / clone / get / list / edit / delete pipelines, start / stop / list / get pipeline **updates** ("a run of a pipeline"), and a vast catalog of ingestion connectors (Salesforce, Workday, Outlook, Kafka, RabbitMQ, TikTok Ads, ServiceNow, Confluence, Jira, ...). The API was renamed multiple times (DLT → Spark Declarative Pipelines → Lakeflow Declarative Pipelines); branding leakage and acronyms are abundant. **Files audited:** -- `src/v2/model.ts` (~5,500 lines) — 26 enums, ~116 interfaces, marshal/unmarshal schemas. -- `src/v2/client.ts` (631 lines) — 12 RPC methods + 2 paginators + `StopWaiter`. +- `src/v2/model.ts` (5,461 lines) — 26 enums, 100 interfaces, marshal/unmarshal schemas. +- `src/v2/client.ts` (642 lines) — 11 public RPC methods + 2 paginators + private `stopBase` + `StopWaiter`. - `src/v2/utils.ts` (181 lines) — generic HTTP/marshal helpers (no domain names). -- `src/v2/index.ts` (155 lines) — re-exports. +- `src/v2/index.ts` (135 lines) — re-exports. ## Summary @@ -24,19 +24,19 @@ ## High ### H1. `Update` is a verb in every other Databricks SDK but the noun "pipeline run" here — pervasive overloading -- **Locations:** `model.ts:168` (`UpdateCause`), `model.ts:186` (`UpdateState`), `model.ts:885` (`GetUpdateRequest`), `model.ts:1401` (`ListUpdatesRequest`), `model.ts:2405` (`StartUpdateRequest`), `model.ts:2537` (`UpdateInfo`), `model.ts:2581` (`UpdateStateInfo`), `client.ts:362` (`getUpdate`), `client.ts:450` (`listUpdates`), `client.ts:490` (`start`). +- **Locations:** `model.ts:229` (`UpdateCause`), `model.ts:251` (`UpdateState`), `model.ts:904` (`GetUpdateRequest`), `model.ts:1432` (`ListUpdatesRequest`), `model.ts:2408` (`StartUpdateRequest`), `model.ts:2513` (`UpdateInfo`), `model.ts:2551` (`UpdateStateInfo`), `client.ts:368` (`getUpdate`), `client.ts:458` (`listUpdates`), `client.ts:499` (`start`). - **Category:** 1 (vague), 6 (misleading — rebrand history), 13 (verb/noun inconsistency), 17 (inconsistent action verbs). - **Suggestion:** Rename `Update` → `PipelineRun` everywhere in the public TS surface. `StartUpdateRequest` → `StartRunRequest` (or `RunPipelineRequest`), `GetUpdateRequest` → `GetRunRequest`, `ListUpdatesRequest` → `ListRunsRequest`, `UpdateInfo` → `PipelineRun`, `UpdateState` → `PipelineRunState`, `UpdateCause` → `RunStartCause`, `UpdateStateInfo` → `RunSummary`. The HTTP wire still uses `/updates/`, so the schema layer maps the rename — this is fine. - **Rationale:** "Update" is the standard verb for `PUT`/`PATCH` (and `EditPipelineRequest` already takes that slot — the client method is `edit()`, but the HTTP verb is `PUT`). Every JS/TS developer expects `update()` to mean "mutate". The DLT product feature historically named the unit-of-execution "Update" but Databricks itself renamed the concept to **"Pipeline run"** when the product became Lakeflow Declarative Pipelines. The SDK is on the wrong side of the rebrand. The same problem ripples through `start()` (the method that "starts an update"), `getUpdate()`, and `listUpdates()`. This is the single most confusing name in the package. ### H2. `client.start()` is "start a pipeline update" — but it reads as "start a pipeline" -- **Location:** `client.ts:490`. +- **Location:** `client.ts:499`. - **Category:** 6 (misleading), 17 (inconsistent action verbs). - **Suggestion:** Rename `start(req: StartUpdateRequest)` → `run(req: RunPipelineRequest)` or `startRun(req: StartRunRequest)`. Pair with `stop(req: StopPipelineRequest)`. - **Rationale:** Reading `client.start({pipelineId})` you assume it "starts the pipeline". It actually queues a new **run** (Update). The asymmetry with `stop(req: StopPipelineRequest)` (which DOES stop the pipeline) is silent and dangerous. `run` is the verb Databricks uses in marketing copy and now in the UI; `start` is the legacy name. ### H3. `PipelinesJobRunAs` references `Job` from a `Pipelines` package -- **Location:** `model.ts:2185`. +- **Location:** `model.ts:2188`. - **Category:** 6 (misleading — `Job` is a separate Databricks product), 14 (Go-style). - **Suggestion:** Rename to `RunAs` or `PipelineRunAs`. Drop the `Job` token entirely — this type is not used by `@databricks/sdk-jobs`. - **Rationale:** `Job` belongs to the `jobs` API. A user reading `runAs: PipelinesJobRunAs` cannot tell whether the pipeline is associated with a job or just borrows the shape. The proto comment ("Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as.") confirms this is a pipeline-only concept. @@ -48,37 +48,37 @@ - **Rationale:** A user installs `@databricks/sdk-pipelines` and expects to `import {Pipeline} from '@databricks/sdk-pipelines'`. Instead they have to discover `GetPipelineResponse`, `PipelineSpec`, `PipelineStateInfo`, or `BaseRun`-style scatter. The Go SDK does the same thing — but Go has package-namespace `pipelines.Pipeline`, while TS uses bare identifiers and benefits from a primary name. ### H5. `client.events()` method name is too generic -- **Location:** `client.ts:274`. +- **Location:** `client.ts:278`. - **Category:** 1 (vague), 17 (inconsistent action verbs — should be `listEvents`). - **Suggestion:** Rename to `listEvents()` for symmetry with `listUpdates()`, `list()`. - **Rationale:** Bare `events()` reads as a property accessor or event emitter, not an HTTP `GET`. Every other paginating method uses `list*` (`list`, `listUpdates`). ### H6. `client.list()` — too generic for the package's bare-`list` slot -- **Location:** `client.ts:390`. +- **Location:** `client.ts:397`. - **Category:** 1 (vague), 17 (inconsistent verbs). - **Suggestion:** Rename to `listPipelines()` to match the request type `ListPipelinesRequest` and to disambiguate from `listUpdates`/`listEvents`. - **Rationale:** `client.list(req)` requires the user to remember `list` of *what*. Adjacent methods are `listUpdates`, `events` (sic), and the request type is already `ListPipelinesRequest`. Bare `list` is a Go-SDK convention (where the package name disambiguates) but loses information in TS. ### H7. `ScdType_ScdType` enum uses the cryptic acronym SCD -- **Locations:** `model.ts:268` (`ScdType_ScdType`), `index.ts:27`. +- **Locations:** `model.ts:352` (`ScdType_ScdType`), `index.ts:27`. - **Category:** 5 (cryptic abbreviation). - **Suggestion:** Rename to `SlowlyChangingDimensionType` since "SCD" is jargon for "Slowly Changing Dimension" — the values themselves are `SCD_TYPE_1` / `SCD_TYPE_2` (Kimball-style dimensional modeling). - **Rationale:** SCD is a dimensional-modelling acronym (slowly-changing dimensions, from Kimball's data-warehousing canon). A casual reader does not know that. The enum values then re-spell `SCD_TYPE_*` redundantly (`SCD_TYPE_1`, `SCD_TYPE_2`, `APPEND_ONLY`). ### H8. `client.delete()` collides with JS `delete` keyword -- **Location:** `client.ts:208`. +- **Location:** `client.ts:210`. - **Category:** 10 (reserved-word collision). - **Suggestion:** Rename to `deletePipeline()`. Alternatively, `remove()`. - **Rationale:** `delete` is a JS reserved keyword. While methods can be named `delete` since ES5, every IDE highlights it and parsers in some contexts choke. ### H9. `EventLevel.METRICS` — value on a "severity level" enum that is not a severity -- **Location:** `model.ts:56`. +- **Location:** `model.ts:73`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Either move `METRICS` to a separate `EventCategory` enum or rename the enum to `EventKind`. The JSDoc says "The severity level of the event" — but `METRICS` is a category, not a severity. - **Rationale:** Filtering `where level='ERROR'` makes sense; `where level='METRICS'` is "where this event is a metric measurement, regardless of severity." Mixing the two leads to user mistakes. ### H10. `Notifications` (plural type, singular plural-prefixed) — a single-notification spec named in plural -- **Locations:** `model.ts:1457`, plus all `notifications?: Notifications[]` field declarations. +- **Locations:** `model.ts:1500`, plus all `notifications?: Notifications[]` field declarations. - **Category:** 9 (singular/plural mismatch). - **Suggestion:** Rename the type to `NotificationRule` (singular). - **Rationale:** `notifications: Notifications[]` reads as "a list of lists of notifications". The type holds one `{emailRecipients, alerts}` pair — singular by definition. @@ -88,46 +88,46 @@ ## Medium ### M1. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level -- **Location:** `model.ts:84-88`. +- **Location:** `model.ts:109-112`. - **Category:** 6 (misleading). - **Suggestion:** Rename the enum to `EventStability`. - **Rationale:** `DEPRECATED` is widely used as a TS/JSDoc tag for "do not use." Reading `maturityLevel: DEPRECATED` mis-suggests the EVENT is deprecated, not the schema field. ### M2. `EventLogSpec` — `Spec` suffix on a small config object -- **Location:** `model.ts:750`. +- **Location:** `model.ts:785`. - **Category:** 8 (redundant suffix). - **Suggestion:** `EventLogConfig` or just `EventLog`. The `Spec` suffix is overused (`PipelineSpec`, `RewindSpec`, `RewindDatasetSpec`, `EventLogSpec`, `IngestionPipelineDefinition_SchemaSpec`, `_TableSpec`, `_ReportSpec`). - **Rationale:** TS doesn't need `Spec` as a discriminator; the type's role is clear from its field name. ### M3. `Filters` — pluralized name for a 2-field struct -- **Location:** `model.ts:828-833`. +- **Location:** `model.ts:853-858`. - **Category:** 9 (singular/plural mismatch), 1 (vague). - **Suggestion:** Rename to `PathFilter` (singular). The shape is `{include?: string[]; exclude?: string[]}`. ### M4. `PathPattern` — generic type name for a single-glob struct -- **Location:** `model.ts:1594-1597`. +- **Location:** `model.ts:1637-1640`. - **Category:** 6 (misleading). - **Suggestion:** Rename the type to `GlobPattern`. The type wraps a single glob string, and `PathPattern` is easily confused with the broader path-filter shapes in the package. ### M5. `Origin` — too generic for "event source metadata" -- **Location:** `model.ts:1488`. +- **Location:** `model.ts:1531`. - **Category:** 1 (vague). - **Suggestion:** Rename to `EventOrigin` or `EventSource`. - **Rationale:** "Origin" is also a DOM type (`Window.origin`) and a CORS concept. Type contains many fields covering everything from cloud region to flow IDs. ### M6. `IngestionPipelineDefinition.netsuiteJarPath` — vendor-specific field on a generic type -- **Location:** `model.ts:1017`. +- **Location:** `model.ts:1036`. - **Category:** 6 (misleading), 16 (field contradicts type domain). - **Suggestion:** Move to `NetsuiteOptions` connector-specific type. - **Rationale:** A generic ingestion-definition type carrying a `netsuiteJarPath` field implies every other connector is incomplete. JSDoc literally says "Netsuite only configuration." Belongs in a per-connector options struct. ### M7. `Sequencing` — singular noun for a 2-field record describing one event's position -- **Location:** `model.ts:2328`. +- **Location:** `model.ts:2331`. - **Category:** 1 (vague). - **Suggestion:** `EventSequence` or `EventPosition`. "Sequencing" is the action of putting in order, not the position itself. ### M8. `DataPlaneId` reads like a string but is actually `{instance, seqNo}` -- **Location:** `model.ts:591`. +- **Location:** `model.ts:651`. - **Category:** 6 (misleading: name implies a scalar ID, but the type is a compound). - **Suggestion:** Rename to `DataPlaneSequence` or `DataPlaneCoordinate`. The actual ID is `{instance, seqNo}` — a coordinate, not an identifier. - **Rationale:** Every other `*Id` type in the SDK is a string. Reading `dataPlaneId: DataPlaneId` then accessing `dataPlaneId.seqNo` is jarring. @@ -137,11 +137,11 @@ ## Low ### L1. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system -- **Locations:** `model.ts:2236`, `model.ts:2241`. +- **Locations:** `model.ts:2239`, `model.ts:2244`. - **Category:** 16. - **Suggestion:** Use a discriminated union: `encryption?: {kind: 'none'} | {kind: 'sse-s3'} | {kind: 'sse-kms'; key: string}`. ### L2. `RewindDatasetSpec.resetCheckpoints: boolean` and `cascade: boolean` — coupled flags with no type-level link -- **Locations:** `model.ts:2304` (`cascade`), `model.ts:2306` (`resetCheckpoints`). +- **Locations:** `model.ts:2307` (`cascade`), `model.ts:2309` (`resetCheckpoints`). - **Category:** 16. - **Suggestion:** Group into an `options` substruct or document interactions in JSDoc. diff --git a/.agent/naming-audit/policyfamilies.md b/.agent/naming-audit/policyfamilies.md deleted file mode 100644 index 79e08e4e..00000000 --- a/.agent/naming-audit/policyfamilies.md +++ /dev/null @@ -1,75 +0,0 @@ -# Naming Audit: `policyfamilies` (v2) - -**Package:** `@databricks/sdk-policyfamilies` -**Path:** `/home/parth.bansal/sdk-js/packages/policyfamilies/` -**Version audited:** `v2` -**Files audited:** - -- `src/v2/model.ts` -- `src/v2/client.ts` -- `src/v2/utils.ts` -- `src/v2/index.ts` - ---- - -## 1. Findings by Category - -### 1.1 Singular / plural mismatches — Low - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| P-01 | `getPolicyFamily()` (singular) | Low | Singular for a single-resource GET. Correct. | -| P-02 | `listPolicyFamilies()` (plural method) | Low | Plural for a collection endpoint. Correct. | -| P-03 | `ListPolicyFamiliesRequest` request type vs `listPolicyFamilies` method | Low | Both plural and matched. Correct. | -| P-04 | Package directory `policyfamilies` (lowercase) | Low | The npm package is `@databricks/sdk-policyfamilies` (lowercase, no separator). Compare with `clusterpolicies`, `clusterlibraries`, `instancepools`. Convention is consistent across this codebase — squashed lowercase. The directory and package name use plural ("families") which matches the dominant resource the package exposes. Acceptable but visually awkward (`policyfamilies` is hard to parse versus `policy-families`); a hyphenated path / scoped suffix would be more readable. (Pattern is repo-wide; flagged once.) | -| P-05 | `PolicyFamily` (entity, singular) vs `policyfamilies` (package directory, plural) | Low | Standard pattern — the package is plural, the entity it contains is singular. OK. | - -### 1.2 Verb-tense inconsistency — Low - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| T-01 | `getPolicyFamily`, `listPolicyFamilies` | Low | Both imperative present-tense — consistent. | - -### 1.3 Inconsistent action verbs — Low - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| AV-01 | `getPolicyFamily()` (singular get) vs `listPolicyFamilies()` (plural list) | Low | Correct convention: singular `get` for one-resource, plural `list` for many. Consistent. | -| AV-02 | The package exposes only **read** verbs — `get`, `list`. There are no `create` / `update` / `delete` methods (the API is read-only). The verb set is consistent with the API's read-only nature. | Low | OK. | - -### 1.4 Type-suffix tautology — Low - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| TS-01 | `PolicyFamily` — does the `Family` suffix double up with `Policy`? | Low | `PolicyFamily` is the domain term used in the Databricks docs (cf. https://docs.databricks.com/en/admin/clusters/policy-families.html). The "Family" here means *grouping/template*, not a `*Family` type-suffix tautology. OK. | -| TS-02 | `GetPolicyFamilyRequest`, `ListPolicyFamiliesRequest` — all carry the resource noun | Low | Standard request/response naming; the resource noun is essential for disambiguation across the SDK. OK. | - -### 1.5 Other observations - -| ID | Symbol | Severity | Issue | -| ----- | ---------------------------------------------------- | -------- | ----- | -| X-01 | The package directory `policyfamilies/` is squashed lowercase | Low | Cross-codebase pattern; cf. P-04. The package name choice influences method placement (a future `databricks.policyFamilies.get(...)` aggregator should keep the same casing). | - ---- - -## 2. Summary - -### 2.1 Findings by severity - -| Severity | Count | -| -------- | ----- | -| High | 0 | -| Medium | 0 | -| Low | 11 | -| **Total**| **11**| - -### 2.2 Top themes - -1. **Read-only API ⇒ minimal naming surface.** With only two endpoints - (`getPolicyFamily`, `listPolicyFamilies`) and one entity (`PolicyFamily`), - the package introduces almost no domain-specific naming. After the - regeneration flattened the response type, only Low-severity nits remain. - -### 2.3 Suggested quick wins - -_None. All remaining findings are Low-severity observations._ diff --git a/.agent/naming-audit/postgres.md b/.agent/naming-audit/postgres.md index 9eaf2aac..201232b4 100644 --- a/.agent/naming-audit/postgres.md +++ b/.agent/naming-audit/postgres.md @@ -13,34 +13,34 @@ ## Medium severity -### 1. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:744-770` +### 1. `BranchSpec.expiration` discriminated union — `noExpiry: boolean` accepts an invalid `false` — `src/v1/model.ts:814-840` - **Why weird:** Discriminated union of `expireTime` / `ttl` / `noExpiry`. The doc on `noExpiry` says "If set to false, the request is invalid; provide either ttl or expire_time instead." So the boolean's `false` value is documented as invalid — the type system permits a value the API rejects. - **Category:** 16 (type allows `false` but spec rejects it). - **Suggested name:** Use a union `expiration?: {expireTime: Instant} | {ttl: Duration} | 'never'`, or hoist the three to top-level mutually-exclusive optional fields. - **Rationale:** Boolean fields whose `false` value is invalid encourage type-level lies. -### 2. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1268-1287` +### 2. `EndpointSpec.suspension` discriminated union — `noSuspension: boolean` accepts an invalid `false` — `src/v1/model.ts:1338-1357` - **Why weird:** Same pattern as #1 — one variant carries a duration, the other a boolean documented as accepting only `true`. The type permits `false`, the spec rejects it. - **Category:** 16 (type allows `false` but spec rejects), echo of #1. - **Suggested name:** Inline: `suspension?: Temporal.Duration | 'never'`. - **Rationale:** Same as #1. -### 3. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1590` +### 3. `Project.initialEndpointSpec` — write-only field exposed on read shape — `src/v1/model.ts:1660` - **Why weird:** `Project` carries an `initialEndpointSpec` field that is a create-time-only input but exposed on the response type too — a read-flow consumer sees a field that is typically empty after project creation. - **Category:** 7 (overly verbose surface), 16 (write-only fields exposed on read shape). - **Suggested name:** Hoist the `initialEndpointSpec` onto `CreateProjectRequest` only (where it belongs); leave `Project` to spec/status. -- **Rationale:** Same as `database` audit #12 — input/output shape confusion. +- **Rationale:** Input/output shape confusion — create-time-only input on a read shape. ## Low severity -### 4. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1329` -- **Why weird:** Same as `database` audit #54 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". +### 4. `GenerateDatabaseCredentialRequest.claims: RequestedClaims[]` — plural of a plural type — `src/v1/model.ts:1399` +- **Why weird:** Same as `database` audit #5 — `RequestedClaims` is already plural; `claims: RequestedClaims[]` is "an array of plural claims objects". - **Category:** 9 (singular/plural mismatch). -- **Suggested name:** Same as `database` audit #54 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. -- **Rationale:** Same as `database` audit #54. +- **Suggested name:** Same as `database` audit #5 — singular type `RequestedClaim` + plural field `claims: RequestedClaim[]`. +- **Rationale:** Same as `database` audit #5. -### 5. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1547` -- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1660`). +### 5. `Operation.done: boolean | undefined` — tri-state boolean — `src/v1/model.ts:1617` +- **Why weird:** Boolean that can be `undefined` is a tri-state value. JSDoc says "If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed…" — but doesn't say what `undefined` means. The `*Operation.wait()` methods check `op.done === undefined && throw` (e.g. `client.ts:1764`). - **Category:** 16 (type allows three values but spec only documents two). - **Suggested name:** Make non-optional `done: boolean`. If absent on the wire, treat as `false` in unmarshal. - **Rationale:** Tri-state booleans always confuse callers. diff --git a/.agent/naming-audit/queries.md b/.agent/naming-audit/queries.md index e8517018..03e125bc 100644 --- a/.agent/naming-audit/queries.md +++ b/.agent/naming-audit/queries.md @@ -3,7 +3,7 @@ **Path:** `packages/queries/src/v1/` **Versions audited:** v1 **Inferred domain:** Workspace SQL queries — a stored, named SQL statement bound to a SQL warehouse, with parameterisable values, a "Run as" identity, visualizations attached to it, and a soft-delete (trash) lifecycle. -**Total weird names flagged:** 12 (last rescanned 2026-06-01) +**Total weird names flagged:** 11 ## Summary table @@ -18,15 +18,14 @@ | 7 | Medium | `model.ts` interface | `TrashQueryRequest` | Same verb inconsistency at the type layer | | 8 | Medium | `client.ts` method | `listVisualizationsForQuery` | Overly verbose vs sibling `listQueries`; "ForQuery" is a Go-style nested-resource pattern | | 9 | Medium | `model.ts` interface | `Visualization` | Vague/generic top-level name (no `Query` prefix) — `QueryVisualization` would mirror `QueryParameter` | -| 10 | Medium | `model.ts` enum | `RunAsMode` | Verb-as-noun; `Mode` is filler since the enum has only two values | +| 10 | Medium | `model.ts` const | `RunAsMode` | Verb-as-noun; `Mode` is filler since the type has only two values | | 11 | Medium | `model.ts` interface | `MultiValuesOptions` | Singular/plural mismatch — `MultiValueOptions` or `MultiSelectOptions` reads naturally | -| 12 | Low | `model.ts` fields | `pageToken`, `pageSize`, `nextPageToken` | Conventional; flagged for completeness only | ## High severity ### 1. `Query` — vague/generic top-level name -**Location:** `src/v1/model.ts:223-257` +**Location:** `src/v1/model.ts:243-277` ```ts export interface Query { @@ -44,7 +43,7 @@ A domain-anchored name like `WorkspaceQuery` or `SavedQuery` (this is, in fact, ### 2. `ListQueryObjectsResponseQuery` — Go-style + filler word -**Location:** `src/v1/model.ts:163-197` +**Location:** `src/v1/model.ts:183-217` ```ts export interface ListQueryObjectsResponseQuery { ... } @@ -54,7 +53,7 @@ The "Objects" infix between `Query` and `Response` is filler — the RPC is `Lis ### 3. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) -**Location:** `src/v1/client.ts:242-267` +**Location:** `src/v1/client.ts:245-271` ```ts /** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, ... A trashed query is permanently deleted after 30 days. */ @@ -67,7 +66,7 @@ The HTTP verb is `DELETE`, the docstring talks about "permanently deleted after ### 4. `QueryBackedValue` — misleading -**Location:** `src/v1/model.ts:259-266` +**Location:** `src/v1/model.ts:279-286` ```ts export interface QueryBackedValue { @@ -84,7 +83,7 @@ The name reads as "a value that is backed by a query" — implying the value its ### 5. `EnumValue` — vague/generic top-level name -**Location:** `src/v1/model.ts:140-147` +**Location:** `src/v1/model.ts:160-167` ```ts export interface EnumValue { @@ -103,7 +102,7 @@ export interface EnumValue { ### 6. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) -**Location:** `src/v1/client.ts:242-267` +**Location:** `src/v1/client.ts:245-271` ```ts /** Moves a query to the trash. Trashed queries immediately disappear from searches and list views, and cannot be used for alerts. You can restore a trashed query through the UI. A trashed query is permanently deleted after 30 days. */ @@ -117,7 +116,7 @@ The HTTP verb is `DELETE`, the docstring talks about "permanently deleted," but ### 7. `TrashQueryRequest` — same as #6, in the type layer -**Location:** `src/v1/model.ts:312-314` +**Location:** `src/v1/model.ts:332-334` ```ts export interface TrashQueryRequest { @@ -129,7 +128,7 @@ Same verb inconsistency at the type layer. Carries only `id`. ### 8. `listVisualizationsForQuery` — overly verbose -**Location:** `src/v1/client.ts:185-222` +**Location:** `src/v1/client.ts:187-225` ```ts async listVisualizationsForQuery( @@ -142,7 +141,7 @@ async listVisualizationsForQuery( ### 9. `Visualization` — vague/generic top-level name -**Location:** `src/v1/model.ts:360-377` +**Location:** `src/v1/model.ts:380-397` ```ts export interface Visualization { ... } @@ -152,20 +151,23 @@ export interface Visualization { ... } ### 10. `RunAsMode` — verb-as-noun, filler `Mode` -**Location:** `src/v1/model.ts:19-22` +**Location:** `src/v1/model.ts:28-34` ```ts -export enum RunAsMode { - OWNER = 'OWNER', - VIEWER = 'VIEWER', -} +export const RunAsMode = { + OWNER: 'OWNER', + VIEWER: 'VIEWER', +} as const; +export type RunAsMode = + | (typeof RunAsMode)[keyof typeof RunAsMode] + | (string & {}); ``` -`RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the enum has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity` or `Authority` would be cleaner. +`RunAs` is an imperative phrase pressed into noun service (see same flag in `alerts` audit). `Mode` is filler — the type has only two values and they describe *who* the query runs as, not *how*. `RunAsIdentity` or `Authority` would be cleaner. ### 11. `MultiValuesOptions` — singular/plural mismatch -**Location:** `src/v1/model.ts:210-217` +**Location:** `src/v1/model.ts:230-237` ```ts export interface MultiValuesOptions { @@ -179,11 +181,3 @@ export interface MultiValuesOptions { ``` `MultiValuesOptions` (plural-values, singular-options) is grammatically inconsistent. `MultiValueOptions` or `MultiSelectOptions` would be conventional. The type expresses "options for a multi-value selection" — option (singular for each field) of multi-value (one feature). - -## Low severity - -### 12. `pageToken`, `pageSize`, `nextPageToken` — conventional pagination - -**Location:** `src/v1/model.ts:153-156`, `158-161` - -Standard Google AIP-158 names. Flagged for completeness; no action recommended. diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md index 1398e3bc..749f814b 100644 --- a/.agent/naming-audit/queryhistory.md +++ b/.agent/naming-audit/queryhistory.md @@ -3,18 +3,18 @@ **Path:** `packages/queryhistory/src/v1/` **Versions audited:** v1 **Inferred domain:** Read-only query history API for Databricks SQL warehouses and serverless compute. Surfaces a single endpoint that lists historical queries with filter/pagination and returns per-query status, timing, identity, source, and execution metrics. -**Total weird names flagged:** 4 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | | High | 1 | | Medium | 1 | -| Low | 2 | +| Low | 1 | ## High severity -### 1. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:176` +### 1. `QueryInfo` — "Info" suffix on a top-level domain entity — `src/v1/model.ts:192` - **Why weird:** The most central type in the package — the value returned from `listQueries` — is named `QueryInfo`. "Info" is a category-1 vague suffix; almost every field on it is a first-class property of a *query* (`queryId`, `queryText`, `status`, `userId`, `queryStartTimeMs`, ...). The type *is* the query — there is no other `Query` type for `QueryInfo` to disambiguate from. Compare with Go SDK convention where `*Info` types are common, but in TS the suffix is non-idiomatic; e.g. `alerts.Alert`, `jobs.Job`, `clusters.ClusterInfo` (this last one is the exception, also flagged in another audit). The endpoint URL is `/api/2.0/sql/history/queries` — the resource is "queries", so the response item should be `Query`. - **Category:** 8, 14, 1 (redundant `Info` suffix; Go/Java-style; vague suffix) - **Suggested name:** `Query`. @@ -22,7 +22,7 @@ ## Medium severity -### 2. `PlansState` — vague type name — `src/v1/model.ts:14` +### 2. `PlansState` — vague type name — `src/v1/model.ts:19` - **Why weird:** "Plans state" — state of what? The JSDoc clarifies: "Possible Reasons for which we have not saved plans in the database." So the enum is really an "outcome" or "save status" — not a runtime state of a plan. The values include `EXISTS`, `EMPTY`, `IGNORED_*`, `UNKNOWN` — these are storage outcomes, not lifecycle states. Calling them a "state" is misleading. - **Category:** 1, 6 (vague; misleading) - **Suggested name:** `PlanStorageStatus` or `QueryPlansAvailability`. @@ -30,13 +30,7 @@ ## Low severity -### 3. `TaskTimeOverRange.entries` / `TaskTimeOverRangeEntry` — — `src/v1/model.ts:348,357` -- **Why weird:** `TaskTimeOverRange` and `TaskTimeOverRangeEntry` are paired (collection + element). Element type appends `Entry` — that's a known convention from `WindowsAzure`-style SDKs (`*Item`, `*Entry`). Could be `TaskTimeBucket` (parent) and `TaskTimeBucketPoint` (child) — domain-specific names. Acceptable as-is. -- **Category:** 1 (vague — `Entry`) -- **Suggested name:** Optional rename to domain names. -- **Rationale:** Marginal. - -### 4. `QueryTag.key` — required field marked optional — `src/v1/model.ts:343` +### 3. `QueryTag.key` — required field marked optional — `src/v1/model.ts:359` - **Why weird:** Both `key` and `value` are `?: string | undefined`. A tag with no key is meaningless, yet the schema allows it. The TS interface should make `key` required if business logic requires it. This is a generated-code limitation (proto3 marks scalars as optional). - **Category:** optionality (required field marked optional) - **Suggested name:** Tighten `key` to `key: string` (non-optional). diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md index 01a2ffae..9568b208 100644 --- a/.agent/naming-audit/registeredmodels.md +++ b/.agent/naming-audit/registeredmodels.md @@ -9,7 +9,7 @@ to the legacy workspace-level `modelregistry` (MLflow-style) Model Registry. ## Summary -The `registeredmodels` package exposes ten UC model-registry operations +The `registeredmodels` package exposes twelve UC model-registry operations (`createRegisteredModel`, `deleteRegisteredModel`, `deleteModelVersion`, `deleteRegisteredModelAlias`, `getRegisteredModel`, `getModelVersion`, `getModelVersionByAlias`, `listRegisteredModels`, `listModelVersions`, @@ -28,7 +28,7 @@ read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, ### 1. Redundant suffixes -#### 1.1 `RegisteredModelInfo` (model.ts:271), `ModelVersionInfo` (model.ts:208), `RegisteredModelAliasInfo` (model.ts:256) +#### 1.1 `RegisteredModelInfo` (model.ts:275), `ModelVersionInfo` (model.ts:212), `RegisteredModelAliasInfo` (model.ts:260) The `*Info` suffix is a verbatim Go-ism. In TS the suffix adds nothing — `RegisteredModel`, `ModelVersion`, and `RegisteredModelAlias` would be the natural names. `*Info` is leftover from the proto/Go convention of @@ -37,27 +37,16 @@ TypeScript does not need the distinction. --- -### 2. Singular / plural mismatches +### 2. Go / Java-style names -#### 2.1 `ListModelVersionsRequest`, `ListModelVersionsResponse.modelVersions` (model.ts:140, 158) -The request type is *plural* (`ListModelVersionsRequest`), the response -collection field is *plural* (`modelVersions`). Internally consistent. - -#### 2.2 `ListRegisteredModelsRequest` paginates registered models; field is `registeredModels` (model.ts:200) -Same as 2.1; flagged for completeness. - ---- - -### 3. Go / Java-style names - -#### 3.1 `Info` suffix everywhere +#### 2.1 `Info` suffix everywhere Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §1.1. --- -### 4. Generic field names losing meaning +### 3. Generic field names losing meaning -#### 4.1 `CreateRegisteredModelRequest.aliases` (model.ts:47), `UpdateRegisteredModelRequest.aliases` (model.ts:399) +#### 3.1 `CreateRegisteredModelRequest.aliases` (model.ts:51), `UpdateRegisteredModelRequest.aliases` (model.ts:403) A request to *create* a model accepts a list of `RegisteredModelAliasInfo`. Aliases are normally set on already-existing models, not at create time. The field is also marked optional. The name `aliases` is @@ -66,9 +55,9 @@ shape is semantically odd. Flagged for shape, not just naming. --- -### 5. Field contradicting type domain +### 4. Field contradicting type domain -#### 5.1 `CreateRegisteredModelRequest.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId, storageLocation, browseOnly}` (model.ts:33-49) +#### 4.1 `CreateRegisteredModelRequest.{fullName, createdAt, createdBy, updatedAt, updatedBy, metastoreId, storageLocation, browseOnly}` (model.ts:36-53) `CreateRegisteredModelRequest` is a *request* shape, yet it includes server-populated fields that the client cannot meaningfully set: - `fullName` (computed from `catalogName.schemaName.name`) @@ -79,11 +68,11 @@ server-populated fields that the client cannot meaningfully set: These fields belong on `RegisteredModelInfo` (the response). Their presence on the create request misleads users into thinking they can set creation timestamps or override the metastore. Same defect on -`UpdateRegisteredModelRequest` (model.ts:371-401): all six are present +`UpdateRegisteredModelRequest` (model.ts:373-405): all six are present plus `name`, `catalogName`, `schemaName`, `storageLocation`, `aliases`, and `browseOnly` — most of which are not actually updatable. -#### 5.2 `UpdateModelVersionRequest.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:319-366) +#### 4.2 `UpdateModelVersionRequest.{createdAt, createdBy, updatedAt, updatedBy, id, metastoreId, modelName, catalogName, schemaName, source, runId, runWorkspaceId, modelVersionDependencies, status, version, storageLocation, aliases}` (model.ts:321-370) `UpdateModelVersionRequest` carries *every* field from `ModelVersionInfo`. Only the comment of the model version can be updated. The shape is therefore deeply misleading: it presents 17 optional fields where 16 are @@ -91,7 +80,7 @@ silently no-ops on the server. A user setting `updateModelVersion({comment: 'x', status: ModelVersionStatus.READY})` will see no effect from `status` but no error either. -#### 5.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:264-268) +#### 4.3 `RegisteredModelAliasInfo.{modelName, catalogName, schemaName}` (model.ts:267-272) Three parent-locator fields on an alias type. The alias is already nested inside `RegisteredModelInfo.aliases`, so the parent is known from context. Embedding these makes the alias serialisable in @@ -99,9 +88,9 @@ isolation but pollutes the shape. --- -### 6. Type-suffix tautology +### 5. Type-suffix tautology -#### 6.1 `RegisteredModelInfo` (model.ts:271), `ModelVersionInfo` (model.ts:208), `RegisteredModelAliasInfo` (model.ts:256) +#### 5.1 `RegisteredModelInfo` (model.ts:275), `ModelVersionInfo` (model.ts:212), `RegisteredModelAliasInfo` (model.ts:260) See §1.1. The `Info` suffix is tautological because the type already *is* the info; it does not need to be marked as such. @@ -115,16 +104,16 @@ See §1.1. The `Info` suffix is tautological because the type already especially `UpdateModelVersionRequest` carry the entire response shape on the request side. This is a *type-design* defect surfaced via *naming* (a field called `createdAt` on a "create" request is -meaningless). See §5. +meaningless). See §4. --- ## Recommendations (priority-ordered) 1. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, - `RegisteredModelAliasInfo`. (§1.1, §6.1) + `RegisteredModelAliasInfo`. (§1.1, §5.1) 2. **Strip server-populated fields** from `CreateRegisteredModelRequest`, `UpdateRegisteredModelRequest`, `UpdateModelVersionRequest` request - shapes. (§5, §A) + shapes. (§4, §A) --- diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md index ec8a886d..96488b3f 100644 --- a/.agent/naming-audit/repos.md +++ b/.agent/naming-audit/repos.md @@ -3,7 +3,7 @@ **Path:** `packages/repos/src/v1/` **Versions audited:** v1 **Package name:** `@databricks/sdk-repos` -**Total weird names flagged:** 6 +**Total weird names flagged:** 5 --- @@ -11,12 +11,11 @@ | # | Name | File | Kind | Severity | Category | Issue (one-liner) | |---|------|------|------|----------|----------|-------------------| -| 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". Every JSDoc string in the package uses the form "Git folder (repo)". The package, type, and method names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | +| 1 | package `repos` / module `@databricks/sdk-repos` | (package) | package | High | 1 Vague/generic, 5 Cryptic abbreviations, 6 Misleading names | "Repos" is a casual abbreviation for "Repositories", and Databricks rebranded the product to "Git folders". The JSDoc throughout the package glosses the resource as "Git folder (repo)". The package, type, and method names all keep the legacy term — readers familiar with the rebranded UI ("Git folders") will not search for `@databricks/sdk-repos`. Compare to the sibling `@databricks/sdk-gitcredentials` package, which already uses the spelled-out form. | | 2 | `Repo` as the resource noun | model.ts (throughout) | concept | High | 1 Vague/generic, 5 Cryptic abbreviations | The TS resource type is `RepoInfo`. The JSDoc clarifies: "Git folder (repo) information". The product UI calls it "Git folder". The Go SDK source uses `Repo`. JS-side could use the rebranded name (`GitFolder`/`GitFolderInfo`) or at least spell out the abbreviation (`Repository`). The wire URL still says `repos` so URL renaming is not possible, but the TS types are free. | | 3 | `RepoInfo` interface | model.ts:108 | interface | Medium | 20 Type-suffix tautology, 1 Vague/generic | The `Info` suffix is a Java/proto idiom that does not match TS norms. The interface *is* the repo — there is no `Repo` type that `RepoInfo` is "info about". `Repo` (or `GitFolder` per H1) without `Info` would be cleaner. (See also `CredentialInfo` in the `credentials` audit, M-pattern.) | -| 4 | `DeleteProjectRequest` (request type) | model.ts:49 | interface | High | 6 Misleading names | The type is named `DeleteProjectRequest` but the field, JSDoc, endpoint, and method all say "repo". The doc says: "The ID for the corresponding **repo** to delete." The endpoint is `/api/2.0/repos/{id}`. The client method is `deleteProject` but JSDoc above it says "Deletes the specified **repo**". This is the only `*Project*` name in the entire package — every other operation uses `*Repo*`. The wire-side path name (`/api/2.0/repos`) was likely once `/api/2.0/projects` (legacy/internal name) but the TS-side carries the legacy operation name only for this one method. | -| 5 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:153, 159 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | -| 6 | `req.id ?? ''` String coercion in URL builders | client.ts:114, 142, 230 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `bigint | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | +| 4 | `branch` field on `UpdateRepoRequest` (singular, but related to `tag`) | model.ts:153, 159 | field pair | Medium | 6 Misleading names | The `UpdateRepoRequest` request lets the caller specify *either* a branch *or* a tag — they are mutually exclusive (the JSDoc on `tag` says "Updating the repo to a tag puts the repo in a detached HEAD state. Before committing new changes, you must update the repo to a branch instead of the detached HEAD"). But the TS type allows both fields to be set at once (`branch?: string; tag?: string`), with no discriminated-union or validation. Either should be a discriminated union (`{kind: 'branch'; name: string} | {kind: 'tag'; name: string}`) or at least the doc should say "set exactly one of {branch, tag}". | +| 5 | `req.id ?? ''` String coercion in URL builders | client.ts:115, 144, 234 | (logic, not name) | Medium | 6 Misleading names | The `id` field is typed `bigint | undefined`. The URL builders do `String(req.id ?? '')` — falling back to the empty string when `id` is undefined. That produces URLs like `/api/2.0/repos/` (trailing slash, no ID) which the server will reject. Either the field should be required (no `| undefined`) or the call should throw. The bug-shaped coalesce is hidden behind the name `id` (which suggests the caller knows what an ID is). Same problem appears in every audited package; flagging once per audit. | --- @@ -25,14 +24,13 @@ ### H1. "Repos" is the legacy term; the product is "Git folders" The package name (`repos`), the resource type (`RepoInfo`), and the five -client methods (`createRepo`, `getRepo`, `listRepos`, `updateRepo`, -`deleteProject` (!)) all use the legacy term "Repos". The Databricks -product UI, marketing, and docs have rebranded this resource to -"Git folders". +client methods (`createRepo`, `deleteRepo`, `getRepo`, `listRepos`, +`updateRepo`) all use the legacy term "Repos". The Databricks product UI, +marketing, and docs have rebranded this resource to "Git folders". -The JSDoc *throughout the file* uses the form "Git folder (repo)" — i.e., -the generator already knows the rebrand happened. Twenty-three doc strings -use "Git folder (repo)". Zero doc strings use only "Repo". +The JSDoc *throughout the file* glosses the resource as "Git folder (repo)" +— i.e., the generator already knows the rebrand happened. Eighteen doc +strings use the "Git folder (repo)" (or "Git folders (repos)") form. Two possible fixes: @@ -41,51 +39,13 @@ Two possible fixes: `createGitFolder`, etc. on the TS side. The zod transform layer can map `gitFolder` ↔ JSON keys. This costs one breaking SDK change for one product alignment that reads honestly. -2. **Keep `Repo` but at least make it consistent** — stop using the legacy - word "Project" (see H2), and decide on `Repo` (not "Repository") - everywhere. +2. **Keep `Repo` as the stable API term** — the TS surface is internally + consistent (`Repo` everywhere), so accept the legacy term and rely on + the JSDoc gloss to bridge to the rebranded product name. The package can also adopt the gitcredentials-style hyphenation: rename to `@databricks/sdk-git-folders` (or just `@databricks/sdk-gitfolders`). -### H2. `DeleteProjectRequest` — leftover "Project" name on one operation - -```ts -export interface DeleteProjectRequest { - /** The ID for the corresponding repo to delete. */ - id?: bigint | undefined; -} -``` - -```ts -async deleteProject(req: DeleteProjectRequest, options?: CallOptions): Promise -``` - -The Databricks API endpoint is `DELETE /api/2.0/repos/{id}`. The doc says -"Deletes the specified **repo**". Every sibling type/method uses `Repo`: -`CreateRepoRequest` / `GetRepoRequest` / `ListReposRequest` / -`UpdateRepoRequest`. Only `DeleteProjectRequest` uses the legacy word -"Project". - -The likely history: `Repos` was internally called "Workspace Projects" at -one point, and the `Delete` operation's request envelope was never renamed -on the Go SDK side. The JS SDK is a 1:1 port, so the legacy name leaks -through. - -Reads to a consumer as: - -```ts -// Surreal because deleteProject deletes a repo, not a project. -const client = new ReposClient(opts); -await client.createRepo({...}); // OK -await client.deleteProject({id: 1}); // Wait, what? -``` - -Recommendation: rename `DeleteProjectRequest` → `DeleteRepoRequest`, method -`deleteProject` → `deleteRepo`. The wire URL doesn't change. This is a -pure TS-side rename that fixes a readability footgun. If the Go SDK keeps -the legacy name (likely it does), file an upstream cleanup request. - --- ## Medium severity (worth pushing back on) @@ -106,6 +66,7 @@ interface UpdateRepoRequest { branch?: string; tag?: string; sparseCheckout?: SparseCheckoutUpdate; + dangerouslyForceDiscardAll?: boolean; } ``` @@ -135,11 +96,11 @@ This is a wire-compatible rename; the zod transform can flatten back to ### M3. `req.id ?? ''` URL-builder bug-shape ```ts -const url = `${this.host}/api/2.0/repos/${String(req.id ?? '')}`; +const url = `${host}/api/2.0/repos/${String(req.id ?? '')}`; ``` When `req.id` is `undefined` (the type allows it — `id?: bigint`), this produces `/api/2.0/repos/` (trailing slash, no ID). The server responds 404. Idiomatic TS would mark `id` as required for paths that need it, or throw before issuing the call. The pattern repeats in -`client.ts:114, 142, 230`. +`client.ts:115, 144, 234`. diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md index 59d132f4..70cdf979 100644 --- a/.agent/naming-audit/resourcequotas.md +++ b/.agent/naming-audit/resourcequotas.md @@ -8,30 +8,23 @@ ## Summary -| Severity | Count | -| ----------- | ----- | -| High | 1 | -| Medium | 1 | -| Low | 1 | -| Observation | 1 | -| **Total** | **4** | +| Severity | Count | +| --------- | ----- | +| High | 0 | +| Medium | 1 | +| Low | 1 | +| **Total** | **2** | Headline themes: -1. **Singular/plural mismatch on the `listQuota` / `listQuotaIter` methods.** The package name (`resourcequotas`), HTTP path (`/all-resource-quotas`), and request/response types (`ListQuotasRequest`, `ListQuotasResponse`) are all plural, but the client methods are `listQuota` / `listQuotaIter` (singular). This is the most user-visible naming defect. +1. **Redundant `Info` suffix on the core record type.** `QuotaInfo` is the quota record itself; the bare noun `Quota` is free and reads more naturally. This mirrors the repo-wide `*Info` suffix pattern (see `catalogs.md`). --- ## High Severity -### H1. Method names `listQuota` / `listQuotaIter` are singular but return / paginate a list - -- **File / line:** `src/v1/client.ts:103` (`async listQuota(...)`); `src/v1/client.ts:139` (`async *listQuotaIter(...)`). -- **Category:** #9 singular/plural mismatch; #15 generic-name losing meaning. -- **Current:** `async listQuota(req: ListQuotasRequest, options?): Promise`; `async *listQuotaIter(req: ListQuotasRequest, options?): AsyncGenerator`. -- **Suggestion:** `listQuotas` / `listQuotasIter`. -- **Rationale:** The request type is `ListQuotasRequest` (plural noun), the response is `ListQuotasResponse` carrying `quotas: QuotaInfo[]`, the URL is `/all-resource-quotas`, and the JSDoc explicitly says "ListQuotas returns **all** quota values" (`client.ts:97`). Every neighbouring signal is plural except the method names. Compare to sibling packages (`catalogs.listCatalogs`, `connections.listConnections`, `cleanrooms.listCleanRooms`), all of which use the plural verb. This is a 1-character defect with high user impact, and now duplicated on the generator-added `listQuotaIter` paginator. +_None._ --- @@ -39,11 +32,11 @@ Headline themes: ### M1. `QuotaInfo` carries the redundant `Info` suffix -- **File / line:** `src/v1/model.ts:58`. +- **File / line:** `src/v1/model.ts:62`. - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `interface QuotaInfo`. - **Suggestion:** `Quota`. -- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo`/`ConnectionInfo` discussion in `catalogs.md` §8.1 — repo-wide pattern, flagged here for completeness. See also Observation O1. +- **Rationale:** "Info" adds no semantic content — the type *is* the quota record returned by the API. The codebase has no type named bare `Quota`; the natural noun is free. This mirrors the `CatalogInfo` discussion in `catalogs.md` §2.1 — repo-wide pattern. --- @@ -51,16 +44,8 @@ Headline themes: ### L1. `req` parameter name on every client method -- **File / line:** `src/v1/client.ts:70, 104, 140`. +- **File / line:** `src/v1/client.ts:69, 104, 141`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. -- **Current:** `req: GetQuotaRequest`, `req: ListQuotasRequest` (twice, once on `listQuota` and once on `listQuotaIter`). +- **Current:** `req: GetQuotaRequest`, `req: ListQuotasRequest` (twice, once on `listQuotas` and once on `listQuotasIter`). - **Suggestion:** `request`. -- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:74, 87, 90, 93, 117, 130, 133, 136` — same shorthand, lower priority. - ---- - -## Observations (repo-wide conventions, not local defects) - -### O1. `…Info` suffix repeated across UC types - -`QuotaInfo` mirrors `CatalogInfo`, `ConnectionInfo`, `FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo`. If the codebase decides to drop the `Info` suffix, this is one of many. +- **Rationale:** Throughout the JS/TS ecosystem function parameters are spelled out. The Go `req`/`resp` idiom reads as Go-translated. The companion `resp` shows up at `client.ts:74, 87, 90, 93, 118, 131, 134, 137` — same shorthand, lower priority. diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md index 5db2e990..2763df3f 100644 --- a/.agent/naming-audit/rfa.md +++ b/.agent/naming-audit/rfa.md @@ -3,18 +3,17 @@ **Path:** `packages/uc/rfa/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog **R**equest **F**or **A**ccess — manage where access-request notifications are routed (the destinations: email addresses, Slack channels, Microsoft Teams webhooks, generic webhooks, or URLs) when end-users request access to a UC securable (catalog/schema/table/etc.). Also exposes a batched create endpoint that lets a caller fire one or more access requests on behalf of principals against a list of securables, returning the destinations the request will be sent to. URL prefix is `/api/3.0/rfa/...`. -**Total weird names flagged:** 9 +**Total weird names flagged:** 7 ## Summary | Severity | Count | | --- | --- | | High | 1 | | Medium | 6 | -| Observation | 2 | ## High severity -### 1. Package name `rfa` — `packages/uc/rfa/`, `package.json:2`, `client.ts:80,122,159` +### 1. Package name `rfa` — `packages/uc/rfa/`, `package.json:2`, `client.ts:80,123,161` - **Why weird:** Three-letter cryptic acronym used as the npm package name (`@databricks/sdk-uc-rfa`), the package directory, the import path (`packages/uc/rfa/src/v1/`), and the URL segment (`/api/3.0/rfa/...`). Nothing in the source files spells out what `rfa` stands for — no doc comment, no README description (`package.json` description is empty string), no module-level JSDoc in `index.ts`. From the model alone, the user has to reverse-engineer that `rfa` means "Request For Access" by reading the type names (`CreateAccessRequest`, `AccessRequestDestinations`). The Databricks Go SDK (`databricks/sdk-go`) does not yet contain this code path either — there's no upstream reference. - **Category:** 5 (cryptic abbreviation), 1 (vague). - **Suggested name:** `accessrequests` or `accessrequestdestinations`. The npm package would be `@databricks/sdk-uc-accessrequests`. The wire URL `/api/3.0/rfa/...` can stay locked while the SDK surface uses the spelled-out name. @@ -22,48 +21,38 @@ ## Medium severity -### 2. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:54-73` +### 2. Type name `AccessRequestDestinations` is plural — but represents ONE securable's destinations — `model.ts:71-90` - **Why weird:** The type is plural (`Destinations`) but each instance describes the destinations *for one securable* (`securable?: Securable`, singular). The plural belongs only to the inner `destinations?: NotificationDestination[]` array. Compare: `AccessRequestDestination` (singular) would describe one route; `AccessRequestDestinations` (plural) implies multiple route configs. The current name is the latter but holds the former. - **Category:** 9 (singular/plural mismatch). - **Suggested name:** `AccessRequestRouting` or `AccessRequestDestinationConfig` (singular) — captures "the routing configuration for one securable". - **Rationale:** The pluralization is for the inner array, not the outer concept. Today the type-name reader gets the wrong mental model. -### 3. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:75,85` +### 3. `BatchCreateAccessRequestsRequest` / `BatchCreateAccessRequestsResponse` — `model.ts:92,102` - **Why weird:** Verbose type names (32 / 33 chars). `Batch` + `Create` + `AccessRequests` + `Request`/`Response`. Also: `Batch` prefix is the *only* signal that the endpoint accepts an array — but the client method is just `batchCreateAccessRequests`, and the field inside is `requests?: CreateAccessRequest[]`. Three levels of "batchness". - **Category:** 7 (overly verbose), 8 (redundant suffix `Request`). - **Suggested name:** `CreateAccessRequestsRequest` (drop `Batch`; the plural already implies batching). Or even better: `CreateAccessRequestsInput` / `CreateAccessRequestsOutput`. Pair with method `createAccessRequests`. - **Rationale:** `Batch` doubles as marketing copy ("look, batched!") rather than naming. TS plural-`s` already says "multiple". -### 4. Type name `SecurablePermissions` is plural but models ONE securable + its permissions — `model.ts:173-178` +### 4. Type name `SecurablePermissions` is plural but models ONE securable + its permissions — `model.ts:190-195` - **Why weird:** `CreateAccessRequest` has `securablePermissions?: SecurablePermissions[]` (plural array, type `SecurablePermissions` itself plural). `SecurablePermissions` holds `securable: Securable` (singular) and `permissions: string[]` (plural). So `request.securablePermissions[0].securable` reads as "the singular securable inside the plural securable-permissions". The type name `SecurablePermissions` doesn't say "pairs of securable + permissions list". - **Category:** 9 (singular/plural mismatch), 1 (vague — what does `SecurablePermissions` model?). - **Suggested name:** `SecurablePermissionRequest` (singular type, describes one securable plus the permissions being requested on it). - **Rationale:** The type-name pluralization is hiding what the type actually models (one securable + a permissions list). -### 5. `Principal` shape — bare `id` whose meaning depends on a sibling `principalType` — `model.ts:145-149` +### 5. `Principal` shape — bare `id` whose meaning depends on a sibling `principalType` — `model.ts:162-166` - **Why weird:** Field `id` is documented as " user, group or service principal ID". Which of the three it is depends on the sibling `principalType` enum. Without `principalType`, the `id` is meaningless. Combined: `{ id: '123', principalType: 'USER_PRINCIPAL' }`. The shape couples two fields that the type system leaves independent. - **Category:** 19 (underspecified ID), 1 (vague). - **Suggested name:** Reshape `Principal` into a discriminated union keyed on the principal kind so the type system enforces "this ID belongs to this principal type", rather than two loosely-coupled optional fields. - **Rationale:** Tagged unions express the constraint at the type level. The current shape is a Go-port idiom. -### 6. Method `batchCreateAccessRequests` on `RfaClient` — `client.ts:76` +### 6. Method `batchCreateAccessRequests` on `RfaClient` — `client.ts:75` - **Why weird:** Method name redundantly carries `batch` even though it's the only create method. There's no non-batched alternative. The `batch` prefix is descriptive of the request body shape (an array), not a distinct API mode. - **Category:** 7 (overly verbose), 17 (action verb inconsistency — sibling methods are `getAccessRequestDestinations`/`updateAccessRequestDestinations` with no analogous prefix). - **Suggested name:** `createAccessRequests` (the plural already conveys batch semantics). - **Rationale:** The "batch" prefix is API-design vocabulary leaking into the SDK surface. If the only way to create is batched, the prefix carries zero information. -### 7. Three RfaClient methods, three different domain entity names — `client.ts:76,118,155` +### 7. Three RfaClient methods, three different domain entity names — `client.ts:75,118,156` - **Why weird:** `RfaClient.batchCreateAccessRequests` works on `requests`. `RfaClient.getAccessRequestDestinations` works on `destinations`. `RfaClient.updateAccessRequestDestinations` works on `destinations`. The first method creates *requests*; the other two manage *destinations*. The class has two distinct subdomains (request creation, destination routing) fused into one client surface with no separation. - **Category:** 17 (action verb inconsistency across cohesion boundary), 12 (duplicate concepts — two separate resources blended). - **Suggested name:** Split into two clients: `AccessRequestClient` (create) and `AccessRequestDestinationsClient` (get/update). Or rename `batchCreateAccessRequests` → `createRequests` (singular noun "request" in the URL `/api/3.0/rfa/requests`). - **Rationale:** A class with three methods that cover two disjoint resources is hiding the resource boundary. - -## Observations - -### 8. Comment-tag inconsistency — `client.ts:80,122,159` vs URL -The URL constant `/api/3.0/rfa/...` (lower-case "rfa") is the only place the package name appears outside of imports — the entire SDK surface otherwise uses spelled-out names. Suggests the API itself owns the `rfa` shortname and the SDK is mechanically reflecting it. Worth confirming with the API team whether the URL prefix is intended to stay `/rfa/` or migrate to `/access-requests/`. -- **Category:** Observation. - -### 9. Action-verb conventions on `RfaClient` -`batchCreateAccessRequests`, `getAccessRequestDestinations`, `updateAccessRequestDestinations` — three different verbs across two resources. Verbs themselves match REST convention (`create`/`get`/`update`); the naming inconsistency is that the verb's target switches mid-class (see #7). -- **Category:** Observation. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md index 694e9270..8438999d 100644 --- a/.agent/naming-audit/schemas.md +++ b/.agent/naming-audit/schemas.md @@ -10,7 +10,7 @@ ### 1. Overly verbose -#### 1.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:79) +#### 1.1 `EffectivePredictiveOptimizationFlag` type name (model.ts:73) 39 characters. Consider `EffectivePredictiveOptimization` (drop the `Flag` suffix — the type already wraps the flag) or `EffectivePOSetting` if shortening is acceptable. See also §2.2. @@ -19,7 +19,7 @@ ### 2. Redundant suffixes -#### 2.1 `SchemaInfo` type name (model.ts:123) +#### 2.1 `SchemaInfo` type name (model.ts:117) "Info" is a non-suffix — it carries no semantic content. In the Go SDK this distinguishes the entity type from a resource handle; in TS the convention is to drop it (`Schema`). Compare with `Catalog`, `Table`, @@ -28,39 +28,26 @@ collides with the zod artifact `Schema` (a runtime validator type in common use across the JS ecosystem) — the rename must consider that collision before landing. -#### 2.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:79) +#### 2.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` (model.ts:73) The whole type *is* the flag; the suffix is redundant. See §1.1. --- ### 3. Reserved-word collisions -#### 3.1 `options` field on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` (model.ts:54, 162, 220) +#### 3.1 `options` field on `CreateSchemaRequest`, `UpdateSchemaRequest`, `SchemaInfo` (model.ts:60, 206, 158) `options` collides with the SDK's own `CallOptions` parameter name -used throughout the client (`createSchema(req, options)`, client.ts:77, +used throughout the client (`createSchema(req, options)`, client.ts:76, etc.). Not a compile error but creates cognitive load — inside `createSchema(req, options)` the reader sees both `req.options` (schema metadata) and `options` (call options). The cleanest fix is to rename the client parameter to `callOptions`. -#### 3.2 `properties` is not reserved but conflicts with `Object` semantics -`SchemaInfo.properties` (model.ts:160) is fine but worth noting that -`properties` is a heavily-overloaded term in JS (object properties, -descriptor properties, etc.), making the name overloaded. - ---- - -### 4. Verb-tense inconsistency - -#### 4.1 Client methods: `createSchema`, `deleteSchema`, `getSchema`, `listSchemas`, `updateSchema`, `listSchemasIter`. Imperative present, consistent. - -No verb-tense inconsistencies found across the package. - --- -### 5. Field contradicting type domain +### 4. Field contradicting type domain -#### 5.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:179, 183, 197, 181) +#### 4.1 `UpdateSchemaRequest` has `fullNameArg`, `fullName`, `name`, and `newName` (model.ts:163, 181, 167, 165) Four name-bearing fields on a single update request: - `fullNameArg` — existing schema identifier (path param). @@ -74,53 +61,27 @@ identifying the existing schema; the others are vestigial in the update context.) This is the single most user-hostile naming pattern in the package — and it sits on the most-used mutation method. -#### 5.2 `CreateSchemaRequest` contains read-only output fields (model.ts:32-50) +#### 4.2 `CreateSchemaRequest` contains read-only output fields (model.ts:33-54) + `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, `fullName`, `catalogType`, `effectivePredictiveOptimizationFlag`, `schemaId`, `browseOnly`. These are server-populated; a creator setting them is at best ignored. The type's domain is "create request", but its shape contradicts that. Same mirror issue in -`UpdateSchemaRequest` (model.ts:198-216). - ---- - -### 6. Inconsistent action verbs - -Method verbs in `Client`: `createSchema`, `deleteSchema`, `getSchema`, -`listSchemas`, `updateSchema`. Verbs are consistent — standard CRUD. -No `fetch…` / `retrieve…` / `read…` outliers. No issues found. - ---- - -### 7. Underspecified IDs - -#### 7.1 `schemaId` (model.ts:48, 156, 214) -"The unique identifier of the schema." No format hint (UUID?). The -field exists alongside `fullName` (which is also a unique identifier -in a different sense). Two simultaneous IDs without disambiguation. - ---- - -### 8. Type-suffix tautology - -#### 8.1 `CatalogType` enum with field `catalogType: CatalogType` -(model.ts:6, 41, 149, 207) — field name tautological with type name. -Defensible (field carries the dynamic value) but worth flagging. - -#### 8.2 `SchemaInfo` doesn't carry a `schemaType` field — no tautology there, which is a relief. +`UpdateSchemaRequest` (model.ts:179-200). --- -### 9. Go / Java-style names +### 5. Go / Java-style names -#### 9.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +#### 5.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) Java/Go style. TS convention is to drop it. See §2.1. --- -### 10. Proto-architectural-leak naming +### 6. Proto-architectural-leak naming -#### 10.1 `EffectivePredictiveOptimizationFlag` — `Flag` wrapper suffix (model.ts:79) +#### 6.1 `EffectivePredictiveOptimizationFlag` — `Flag` wrapper suffix (model.ts:73) - **Why:** The type is a proto-style wrapper around a tri-state value (`value`, `inheritedFromType`, `inheritedFromName`). `Flag` is a proto-wrapper marker that leaks the upstream message-modeling pattern @@ -132,15 +93,3 @@ Java/Go style. TS convention is to drop it. See §2.1. - **Rationale:** TS callers care about the value and its inheritance source; the wrapper-ness is an implementation detail of the proto schema, not part of the domain vocabulary. - ---- - -## Additional / cross-cutting observations - -### A. The package name is plural; the entity types are singular -The package is `schemas` (plural); the model types are `Schema` (well, -`SchemaInfo` — singular). The five client methods mix: -`createSchema`/`deleteSchema`/`getSchema`/`updateSchema` (singular — -they act on one) and `listSchemas` (plural — returns many). This is -the same pattern as `catalogs`, `tables`, etc. — consistent across -the SDK. diff --git a/.agent/naming-audit/scim.md b/.agent/naming-audit/scim.md index 461437f5..07ffb73b 100644 --- a/.agent/naming-audit/scim.md +++ b/.agent/naming-audit/scim.md @@ -3,7 +3,7 @@ **Path:** `packages/scim/src/v1/` **Versions audited:** v1 **Inferred domain:** SCIM (System for Cross-domain Identity Management, RFC 7644) — workspace and account user, service principal, and group provisioning, plus password permissions. `SCIM` itself is an industry-standard protocol acronym and is treated as a domain word. -**Total weird names flagged:** 5 +**Total weird names flagged:** 4 ## Summary | Severity | Count | @@ -11,25 +11,24 @@ | High | 1 | | Medium | 2 | | Low | 1 | -| Observation | 1 | ## High severity -### 1. Proto-style nested enum names with `_` separators — `src/v1/model.ts:58,65,73,81,87,95` -- **Why weird:** Six exported enums use the proto-nested form `_`: `AccountGetSortOrder_GetSortOrder`, `AccountListSort_Order`, `AccountPatchOp_PatchOp`, `AccountPatchSchema_PatchSchema`, `ListSort_Order`, and `PasswordPermission_Level`. Each is suppressed by an inline `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.`, which is itself an acknowledgement that the names violate normal TS convention. The reason is purely protoc plumbing: the enum was nested inside a parent proto message to avoid value-name collisions with a sibling enum. That nesting is invisible to the SDK consumer — `AccountGetSortOrder_GetSortOrder` and `GetSortOrder` (line 17) hold the same three values (`UNSPECIFIED`, `ASCENDING`, `DESCENDING`). +### 1. Proto-style nested enum names with `_` separators — `src/v1/model.ts:90,101,113,125,136,148` +- **Why weird:** Six exported enums use the proto-nested form `_`: `AccountGetSortOrder_GetSortOrder`, `AccountListSort_Order`, `AccountPatchOp_PatchOp`, `AccountPatchSchema_PatchSchema`, `ListSort_Order`, and `PasswordPermission_Level`. Each is suppressed by an inline `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested enum name.`, which is itself an acknowledgement that the names violate normal TS convention. The reason is purely protoc plumbing: the enum was nested inside a parent proto message to avoid value-name collisions with a sibling enum. That nesting is invisible to the SDK consumer — `AccountGetSortOrder_GetSortOrder` and `GetSortOrder` (line 18) hold the same three values (`UNSPECIFIED`, `ASCENDING`, `DESCENDING`). - **Category:** Proto-architecture leak - **Suggested name:** Collapse to a single `SortOrder` enum (shared across get/list and account/workspace variants); rename `PasswordPermission_Level` to `PasswordPermissionLevel`. The whole `_` shape is a proto artifact that should not survive code generation. - **Rationale:** TypeScript has structural typing and module-scoped names; there is no value collision to resolve. The disable comment is a clue that the generator is fighting the language. ## Medium severity -### 2. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:583` -- **Why weird:** The list-response type is `ListServicePrincipalResponse` (singular `ServicePrincipal`) while the request type is `ListServicePrincipalsRequest` (plural). Compare to `ListAccountServicePrincipalsResponse` (plural) on line 510. The singular form on a list response reads as a proto message-name copy where the inner message is `ServicePrincipal` and the outer wraps it — i.e., proto's habit of letting the inner singular name dominate. +### 2. `ListServicePrincipalResponse` singular type for a list — `src/v1/model.ts:640` +- **Why weird:** The list-response type is `ListServicePrincipalResponse` (singular `ServicePrincipal`) while the request type is `ListServicePrincipalsRequest` (plural). Compare to `ListAccountServicePrincipalsResponse` (plural) on line 567. The singular form on a list response reads as a proto message-name copy where the inner message is `ServicePrincipal` and the outer wraps it — i.e., proto's habit of letting the inner singular name dominate. - **Category:** Proto-architecture leak - **Suggested name:** `ListServicePrincipalsResponse`. - **Rationale:** Symmetry with sibling types and with the request name; the current singular is a generator artifact. -### 3. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:34,143,715` +### 3. `PatchOp` enum and `Patch.op` field tautology — `src/v1/model.ts:49,113,772` - **Why weird:** `PatchOp` is the enum of patch operation kinds (`ADD`/`REMOVE`/`REPLACE`); `Patch.op` is the field that holds one. The TS field is `op` of type `PatchOp` (or `AccountPatchOp_PatchOp` for the account variant), so the enum has `Op` baked into its own name *and* the field is `op` — `Patch.op: PatchOp` is a type-suffix tautology and `AccountPatchOp_PatchOp` is the worst-case version of finding 1. - **Category:** Proto-architecture leak - **Suggested name:** Rename the enum to `PatchOperation`; keep the field `op`. @@ -37,13 +36,8 @@ ## Low severity -### 4. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:652` +### 4. `MeRequest` mid-position colloquial pronoun — `src/v1/model.ts:709` - **Why weird:** Not a proto leak per se, but the `Me` segment in `MeRequest` is a proto-style shorthand: SCIM defines `GET /Users/me` as the "current user" endpoint, and the proto generator turned `Me` into a type prefix instead of using a verb. `MeRequest` reads as "a Me-shaped request" — the request *to* the `me` endpoint would be `GetCurrentUserRequest` or `GetMeRequest`. - **Category:** Proto-architecture leak - **Suggested name:** `GetCurrentUserRequest` (and rename `client.me()` to `getCurrentUser()`); or `GetMeRequest` if the URL slug is preserved. - **Rationale:** Pronouns are not normally type prefixes in TS; this is the proto RPC name leaking through. - -## Observations - -### O1. `eslint-disable` density as a signal — `src/v1/model.ts:57,64,72,80,86,94,108,131,150,153,403,411,618` -- The file carries 13 inline `eslint-disable-next-line` comments, all for `@typescript-eslint/naming-convention` (proto-nested enum names) or `@typescript-eslint/no-empty-object-type` (empty proto messages). Every disable corresponds to a proto-architecture artifact — taken together, they form a precise list of the proto-shaped pieces the linter wanted to flag and the generator decided to suppress. Removing the underlying naming patterns (findings 1 and 3) would clear every `naming-convention` disable in this file. diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md index 12fc0ae8..d5195ffa 100644 --- a/.agent/naming-audit/secrets.md +++ b/.agent/naming-audit/secrets.md @@ -13,8 +13,7 @@ | ----------- | ----- | | High | 1 | | Medium | 3 | -| Observation | 1 | -| **Total** | **5** | +| **Total** | **4** | Headline themes: @@ -29,16 +28,16 @@ Headline themes: ### H1. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` -- **Files / lines:** `src/v1/client.ts:613` (`putAcl`), `:673` (`putSecret`); - contrast `:139` (`createScope`), `:273` (`deleteSecret`), `:228` +- **Files / lines:** `src/v1/client.ts:621` (`putAcl`), `:682` (`putSecret`); + contrast `:138` (`createScope`), `:275` (`deleteSecret`), `:229` (`deleteScope`), `:185` (`deleteAcl`). - **Category:** #17 inconsistent action verbs. - **Current:** `Put` for ACLs and secrets, `Create` for scopes, `Delete` for all three. No `Update`. - **Issue:** A consumer who learned `createScope` will not guess that the way to create or update a secret is `putSecret`, not `createSecret` or - `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:642) and - "Creates or overwrites the ACL" (client.ts:580) — three different verbs + `setSecret`. The JSDoc itself says "Inserts a secret" (client.ts:651) and + "Creates or overwrites the ACL" (client.ts:588) — three different verbs for the same upsert semantic. - **Suggestion:** unify on one verb pair: either (a) `Create*` for new + `Update*` for existing, or @@ -54,20 +53,20 @@ Headline themes: ### M1. `AclItem` is generic-suffix tautology -- **File / line:** `src/v1/model.ts:36`. +- **File / line:** `src/v1/model.ts:44`. - **Category:** #20 type-suffix tautology. - **Current:** `AclItem` describes "an ACL rule". The `Item` suffix is meaningless. - **Suggestion:** rename to `Acl` or `AclEntry` or `AclRule`. The Go SDK uses `AclItem`, but in TS the suffix doesn't carry weight: `AclItem` and `AclRule` carry exactly the same information. -- **Rationale:** JSDoc on `model.ts:120` says "The associated ACLs rule +- **Rationale:** JSDoc on `model.ts:128` says "The associated ACLs rule applied to principals" — so the type is conceptually "an ACL rule", but it's spelled "AclItem". The doc disagrees with the name. ### M2. `SecretMetadata` describes a list-item, not metadata -- **File / line:** `src/v1/model.ts:180`. +- **File / line:** `src/v1/model.ts:188`. - **Category:** #1 vague/generic, #20 type-suffix tautology. - **Current:** `SecretMetadata { key, lastUpdatedTimestamp }`. The JSDoc says "The metadata about a secret. Returned when listing secrets. Does @@ -83,7 +82,7 @@ Headline themes: ### M3. `ScopeBackendType` enum name is an architectural leak -- **File / line:** `src/v1/model.ts:19` (`ScopeBackendType` enum). +- **File / line:** `src/v1/model.ts:24` (`ScopeBackendType` enum). - **Category:** proto-architectural-leak (`Backend` mid-position, not a domain noun). - **Issue:** the public surface uses `Backend` to mean "where the secret @@ -100,16 +99,3 @@ Headline themes: outlier that smuggles in implementation jargon. Same defect appears in several other audits where "backend" describes an integration/provider layer (e.g., `connections.md` flags `ConnectionType` analogues). - ---- - -## Observations - -### O1. `scope` is optional on every request type, but required at the server - -- **Files / lines:** see model.ts request types. -- The generator marks every proto field optional. The runtime contract - requires `scope` for ten of eleven operations. Not a naming defect but - worth noting: the type is wider than the API allows. - ---- diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md index 2efd9226..08dec2f5 100644 --- a/.agent/naming-audit/secretsuc.md +++ b/.agent/naming-audit/secretsuc.md @@ -3,19 +3,18 @@ **Path:** `packages/uc/secrets/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog (UC) secrets — three-level namespaced (`catalog.schema.secret`) credential objects that store passwords/tokens/keys. Distinct from the workspace-level `secrets` package (scopes + key/value pairs). REST root is `/api/2.1/unity-catalog/secrets`. -**Total weird names flagged:** 6 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | --- | --- | | High | 1 | -| Medium | 3 | -| Observation | 2 | +| Medium | 2 | ## High severity ### 1. `fullName` is the routing key but marked optional — `src/v1/model.ts:23,32,115,152` -- **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:114,144,258`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. +- **Why weird:** `fullName` is the only routing identifier for `DeleteSecret`, `GetSecret`, and `UpdateSecret` (the URL path is `/api/2.1/unity-catalog/secrets/${req.fullName ?? ''}` — `client.ts:115,146,262`). When unset, the client substitutes the empty string, producing a `DELETE /api/2.1/unity-catalog/secrets/` request that quietly hits the wrong endpoint. The TS type marks it `string | undefined`. Same field on `Secret` is also optional, which is correct for a returned object but wrong for the request DTO. - **Category:** 6 (misleading — looks optional, isn't), 16 (field type contradicts domain — required key marked optional). - **Suggested name:** Keep the name, drop `| undefined` on the three request DTOs (or split: `Secret.fullName?` for responses, `SecretRef.fullName` required for requests). - **Rationale:** This is a routing identifier; the TS type system can prevent a whole class of "I forgot the name" bugs and the SDK can stop substituting empty strings. @@ -28,22 +27,8 @@ - **Suggested name:** Keep names, group into a `scope` sub-object so paired-ness is type-enforced. - **Rationale:** Internal grouping fix; not strictly a naming finding. Listed because the field names alone don't communicate the constraint, and the type system isn't carrying the weight. -### 3. `pageToken` / `nextPageToken` asymmetry — `src/v1/model.ts:61,81` -- **Why weird:** Request uses `pageToken`, response uses `nextPageToken`. Internally consistent with conventions across the SDK, but the asymmetry between "what I send" and "what I receive next time" is something the type system can't help with. The pagination iterator (`client.ts:241`) bridges them via `pageReq.pageToken = resp.nextPageToken`. -- **Category:** 17 (action-verb / qualifier asymmetry between request and response). -- **Suggested name:** Accept the convention (`nextPageToken` is the next page; you copy it to `pageToken` on the next request). Listed for completeness. -- **Rationale:** Generator convention; this isn't really a naming defect — flagged because rules 14 and 17 both ask about cross-DTO consistency. - -### 4. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` +### 3. `pageSize` semantic overloading: 0/negative/positive have distinct meanings — `src/v1/model.ts:62-70` - **Why weird:** JSDoc enumerates four meanings of `pageSize`: unset = 10000, positive = min(value, 10000), zero = 10000, negative = error. The field type is `number | undefined` which expresses none of those. A reader of the type signature alone would believe any number works. - **Category:** 16 (type contradicts domain — should be `positive integer | undefined`), 6 (misleading — zero has special meaning). - **Suggested name:** Keep the name; consider a Zod refinement (`z.number().int().nonnegative()`) and document the zero-means-default specially. - **Rationale:** API-level concern (the upstream API conflates "use default" and "0"); flagging at the SDK level because the type system is silent. - -## Observations - -### 5. Action-verb convention in `Client` -`createSecret` / `deleteSecret` / `getSecret` / `listSecrets` / `updateSecret` — fully consistent CRUDL verbs. No mixed `fetch`/`retrieve`. (Good.) - -### 6. No enums in this package -No enum types are defined. (`secrets` workspace package has `AclPermission` and `ScopeBackendType`; this package exposes none.) This avoids the enum-prefix and enum-value-length problems that other audited packages have. Worth noting because the audit checklist asks about enum issues. diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md index c06a45c0..57e86a66 100644 --- a/.agent/naming-audit/settings.md +++ b/.agent/naming-audit/settings.md @@ -3,7 +3,7 @@ **Path:** `/home/parth.bansal/sdk-js/packages/settings/` **Versions audited:** v2 **Inferred domain:** A "unified" generic settings/user-preference key/value API (referred to as `settingsv2` in the wire/JSDoc) that exposes a single `Setting` polymorphic value type with multiple typed payload variants. Operates at three scopes — account-level settings, account-level user preferences, and workspace-level settings — via a single set of generic `get*`/`patch*`/`list*Metadata` endpoints. -**Total weird names flagged:** 20 +**Total weird names flagged:** 19 --- @@ -12,25 +12,24 @@ | # | Severity | Category | Identifier | File:line | |---|----------|----------|------------|-----------| | 1 | Critical | Vague package name | `settings` (package) | package level | -| 2 | High | Vague/generic type | `Setting` | `model.ts:324` | -| 3 | High | Vague/generic type | `SettingsMetadata` | `model.ts:453` | -| 4 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:111, 194, 471, 115, 311, 315` | -| 5 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:30, 97, 103` | -| 6 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:315` | -| 7 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:115` | -| 8 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:30, 142, 38, 50, 149, 160, 132, 75, 82` | -| 9 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:107, 526, 989` | -| 10 | Medium | Plural type singular field | `AibiDashboardEmbeddingApprovedDomains` (plural type, singular `approvedDomains` field) | `model.ts:103-104` | -| 11 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:175, 289, 189, 305, 180, 296`; `client.ts:85, 354, 139, 417, 114, 386` | -| 12 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:85, 354, 139, 417, 114, 386` | -| 13 | Medium | HTTP-verb leak | `patch` for mutation where the SDK convention is `update`/`set` | `client.ts:354, 386, 417` | -| 14 | Medium | Inconsistent action verb | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:386` | -| 15 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:248` | -| 16 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:227` | -| 17 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:296` | -| 18 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #11 as a proto-leak category) | `model.ts:175, 180, 189, 289, 296, 305` | -| 19 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:195` | -| 20 | Low | HTTP-verb leak | `patch` (HTTP idiom) vs `update`/`set` (SDK idiom) | `client.ts:354, 386, 417` | +| 2 | High | Vague/generic type | `Setting` | `model.ts:353` | +| 3 | High | Vague/generic type | `SettingsMetadata` | `model.ts:482` | +| 4 | High | Suffix tautology + Go-style | `*Message` suffix (`BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage`) | `model.ts:140, 223, 500, 144, 340, 344` | +| 5 | High | Cryptic abbreviation (undefined) | `Aibi` (AI/BI) in `AibiDashboardEmbedding*` | `model.ts:34, 126, 132` | +| 6 | High | Verb-tense (action-name as type) | `RestrictWorkspaceAdminsMessage` (verb-noun as state type) | `model.ts:344` | +| 7 | High | Verb-tense | `ClusterAutoRestartMessage` (verb-phrase as state type) | `model.ts:144` | +| 8 | High | Proto-architectural leak (nested-type underscore syntax) | `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType`, `ClusterAutoRestartMessage_MaintenanceWindow`, `ClusterAutoRestartMessage_MaintenanceWindow_DayOfWeek`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayFrequency`, `ClusterAutoRestartMessage_MaintenanceWindow_WeekDayBasedSchedule`, `ClusterAutoRestartMessage_MaintenanceWindow_WindowStartTime`, `ClusterAutoRestartMessage_EnablementDetails`, `PersonalComputeMessage_PersonalComputeMessageEnum`, `RestrictWorkspaceAdminsMessage_Status` | `model.ts:41, 171, 57, 73, 178, 189, 161, 102, 122` | +| 9 | High | Proto-architectural leak (`Api` mid-position) | `AllowedAppsUserApiScopesMessage` (`Api` is the wire/proto term — TS surface should drop it) | `model.ts:136, 553, 1006` | +| 10 | Medium | Redundant `Public` qualifier | `GetPublicAccountSettingRequest`, `PatchPublicAccountSettingRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicWorkspaceSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `PatchPublicAccountUserPreferenceRequest`, and corresponding methods | `model.ts:204, 318, 218, 334, 209, 325`; `client.ts:80, 355, 136, 420, 110, 388` | +| 11 | Medium | Redundant `Public` qualifier | method names `getPublicAccountSetting`, `patchPublicAccountSetting`, `getPublicWorkspaceSetting`, `patchPublicWorkspaceSetting`, `getPublicAccountUserPreference`, `patchPublicAccountUserPreference` | `client.ts:80, 355, 136, 420, 110, 388` | +| 12 | Medium | HTTP-verb leak | `patch` for mutation where the SDK convention is `update`/`set` | `client.ts:355, 388, 420` | +| 13 | Medium | Inconsistent action verb | `patchPublicAccountUserPreference` for setting a preference (vs noun "set" or "put") | `client.ts:388` | +| 14 | Medium | Long type name | `ListAccountUserPreferencesMetadataResponse` (42 chars) | `model.ts:277` | +| 15 | Medium | Long type name | `ListAccountUserPreferencesMetadataRequest` (41 chars) | `model.ts:256` | +| 16 | Medium | Long type name | `PatchPublicAccountUserPreferenceRequest` (39 chars) | `model.ts:325` | +| 17 | Medium | Proto-architectural leak (request type `Public` infix maps 1:1 to a proto `PublicSettingsService`) | `GetPublicAccountSettingRequest`, `GetPublicAccountUserPreferenceRequest`, `GetPublicWorkspaceSettingRequest`, `PatchPublicAccountSettingRequest`, `PatchPublicAccountUserPreferenceRequest`, `PatchPublicWorkspaceSettingRequest` (reiterates #10 as a proto-leak category) | `model.ts:204, 209, 218, 318, 325, 334` | +| 18 | Low | Misleading singular | `IntegerMessage.value` is `number` (TS has no integer/float distinction; "Integer" misleads) | `model.ts:224` | +| 19 | Low | HTTP-verb leak | `patch` (HTTP idiom) vs `update`/`set` (SDK idiom) | `client.ts:355, 388, 420` | --- @@ -49,21 +48,21 @@ ### 2. `Setting` — extreme generic risk -- **File:line:** `model.ts:324-451` +- **File:line:** `model.ts:353-480` - **Category:** Vague/generic, reserved-word risk - **Suggestion:** `UnifiedSetting`, `SettingValue`, or `KeyedSetting`. The Setting concept here is "a name plus a polymorphic value plus a polymorphic effective value" — none of those properties match the bare word "Setting" without context. - **Rationale:** `Setting` is one of the most overloaded single words in software (UI settings, settings menu, settings file, configuration setting, etc.). Inside a "settings" package, the type `Setting` reads like "the thing this package is about" — but the package has other top-level types (`UserPreference`, `SettingsMetadata`, and the wrapper messages). The bare name encourages a `import {Setting}` that competes with React UI `Setting` types, Node `process.config` settings, etc. ### 3. `SettingsMetadata` — plural type, singular use -- **File:line:** `model.ts:453-469` +- **File:line:** `model.ts:482-498` - **Category:** Vague + singular/plural mismatch - **Suggestion:** `SettingMetadata` (singular). The type describes metadata about *one* setting; lists are `SettingMetadata[]`. The current `SettingsMetadata` reads as "all metadata about all settings" which is what the *array* of these things represents — not the element. -- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:219, 250, 277`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). +- **Rationale:** The field `settingsMetadata?: SettingsMetadata[]` (`model.ts:248, 279, 306`) doubles the plural — "settings metadatas" — and an item from the array `settingsMetadata[0]` then has the type `SettingsMetadata` even though it's one row. Standard practice is singular type, plural field/array (e.g. `User`, `users: User[]`). ### 4. `*Message` suffix — Go/proto-style -- **File:line:** `model.ts:111, 194, 471, 115, 311, 315` +- **File:line:** `model.ts:140, 223, 500, 144, 340, 344` - **Category:** Suffix tautology / Go-style - **Identifiers:** `BooleanMessage`, `IntegerMessage`, `StringMessage`, `ClusterAutoRestartMessage`, `PersonalComputeMessage`, `RestrictWorkspaceAdminsMessage` (and `AllowedAppsUserApiScopesMessage`, `CollaborationPlatformConnectivityMessage`, `OperationalEmailCustomRecipientMessage`). - **Suggestion:** Drop `Message`. Rename `ClusterAutoRestartMessage → ClusterAutoRestart`, `RestrictWorkspaceAdminsMessage → RestrictWorkspaceAdmins`, etc. The "Message" suffix is the protobuf convention for "everything is a Message"; in TS where "everything is an interface", the suffix is noise. @@ -71,21 +70,21 @@ ### 5. `Aibi` — undefined cryptic abbreviation (AI/BI) -- **File:line:** `model.ts:30, 97, 103` +- **File:line:** `model.ts:34, 126, 132` - **Category:** Cryptic abbreviation - **Suggestion:** Spell out as `AiBi` for the AI/BI Genie embedding feature, and add a top-of-file `@module` doc explaining: "AI/BI = Databricks's AI- and BI-powered dashboards product." - **Rationale:** "Aibi" is not a recognised English word and is not defined anywhere in this file. A reader has to know the Databricks product naming. ### 6–7. Verb-tense action-as-noun naming -- **File:line:** `model.ts:315 (RestrictWorkspaceAdminsMessage), 115 (ClusterAutoRestartMessage)` +- **File:line:** `model.ts:344 (RestrictWorkspaceAdminsMessage), 144 (ClusterAutoRestartMessage)` - **Category:** Verb-tense inconsistency - **Suggestion:** Types describing *state* should be nouns: `WorkspaceAdminRestriction`, `ClusterAutoRestart` (or `ClusterAutoRestartConfig`). - **Rationale:** Standard naming: imperative verbs for actions/methods; nouns for state types. ### 8. Proto-nested underscore type naming — proto-architectural leak -- **File:line:** `model.ts:30, 142, 38, 50, 149, 160, 132, 75, 82` (and the corresponding marshal/unmarshal schema declarations) +- **File:line:** `model.ts:41, 171, 57, 73, 178, 189, 161, 102, 122` (and the corresponding marshal/unmarshal schema declarations) - **Category:** Proto-architectural leak (nested-message naming) - **Why:** Every nested type carries an `eslint-disable-next-line @typescript-eslint/naming-convention -- Proto-style nested ... name.` comment — an explicit admission that the TS surface is wearing proto-generated shape. Examples: - `AibiDashboardEmbeddingAccessPolicy_AccessPolicyType` @@ -102,7 +101,7 @@ ### 9. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak -- **File:line:** `model.ts:107, 526 (unmarshal), 989 (marshal)` +- **File:line:** `model.ts:136, 553 (unmarshal), 1006 (marshal)` - **Category:** Proto-architectural leak (`Api` mid-position) + `*Message` suffix (covered in #4) - **Why:** `Api` appears mid-name in a domain type that models *what user-OAuth scopes apps may be granted*. The "Api" half describes the **wire/proto** medium ("user-API scopes") rather than the domain concept (OAuth scopes). - **Suggestion:** `AllowedAppsUserScopes` (drop `Api`, drop `Message`). The discriminator value `allowedAppsUserApiScopes` and wire key `allowed_apps_user_api_scopes` would remain wire-side; the TS surface should not carry the proto-medium descriptor. @@ -112,42 +111,36 @@ ## Medium severity -### 10. `AibiDashboardEmbeddingApprovedDomains` — plural type, singular use +### 10. `*Public*` qualifier — redundant -- **File:line:** `model.ts:103-104` -- **Category:** Singular/plural mismatch -- **Suggestion:** Either keep plural type with plural field (current state — `approvedDomains: string[]`) or move to singular type representing one approved domain and let consumers hold `ApprovedDomain[]`. Current naming is internally consistent but the *type* is plural which is unusual. - -### 11. `*Public*` qualifier — redundant - -- **File:line:** `model.ts:175, 289, 189, 305, 180, 296` +- **File:line:** `model.ts:204, 318, 218, 334, 209, 325` - **Category:** Redundant qualifier -- **Suggestion:** Drop `Public` from request type names (and method names — #12). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. +- **Suggestion:** Drop `Public` from request type names (and method names — #11). `GetAccountSettingRequest`/`getAccountSetting` is shorter and equally specific. - **Rationale:** If everything is "public" (vs internal), the qualifier carries no information. The Go SDK upstream uses the same word probably because the proto service is named `PublicSettingsService` to disambiguate from internal admin services — but the JS SDK only ships the public surface, so the qualifier is redundant. -### 12. Method names: `getPublic*`, `patchPublic*` — redundant `Public` +### 11. Method names: `getPublic*`, `patchPublic*` — redundant `Public` -- **File:line:** `client.ts:85, 354, 139, 417, 114, 386` +- **File:line:** `client.ts:80, 355, 136, 420, 110, 388` - **Category:** Redundant qualifier + verbose - **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. -### 13. `patch*` — HTTP-verb leak where the SDK convention is `update`/`set` +### 12. `patch*` — HTTP-verb leak where the SDK convention is `update`/`set` -- **File:line:** `client.ts:354, 386, 417` (use `patch`) +- **File:line:** `client.ts:355, 388, 420` (use `patch`) - **Category:** HTTP-verb leak / inconsistent action verb - **Suggestion:** Pick an SDK-domain verb. `update` (for the setting mutations) or `set`/`put` (for the user-preference replacement) reads more like an SDK operation than the raw HTTP method `patch`. - **Rationale:** The method name echoes the HTTP verb (`PATCH`) rather than the domain action. Mutation methods elsewhere in the SDK favor `update`/`set`; `patch` leaks the transport idiom onto the public surface and breaks muscle memory for users scanning for an `update*` method. -### 14. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action +### 13. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action -- **File:line:** `client.ts:386` +- **File:line:** `client.ts:388` - **Category:** Inconsistent + verbose - **Suggestion:** `setAccountUserPreference` or `putAccountUserPreference`. - **Rationale:** For setting a single preference, `set*` is the conventional SDK verb. `patch*` implies partial-update; this endpoint replaces the whole preference. -### 15–17. Long type names +### 14–16. Long type names -- **File:line:** `model.ts:248, 227, 296` +- **File:line:** `model.ts:277, 256, 325` - **Category:** Overly verbose - **Identifiers:** - `ListAccountUserPreferencesMetadataResponse` (42 chars) @@ -155,37 +148,25 @@ - `PatchPublicAccountUserPreferenceRequest` (39 chars) - **Suggestion:** After applying the suggested simplifications (drop `Public`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. -### 18. `*Public*` qualifier as proto-architectural leak (reframe of #11) +### 17. `*Public*` qualifier as proto-architectural leak (reframe of #10) -- **File:line:** `model.ts:175, 180, 189, 289, 296, 305`; `client.ts:85, 114, 139, 354, 386, 417` +- **File:line:** `model.ts:204, 209, 218, 318, 325, 334`; `client.ts:80, 110, 136, 355, 388, 420` - **Category:** Proto-architectural leak (`Public` mid-position) - **Why:** `Public` in `GetPublic*Request`, `PatchPublic*Request`, and method names `getPublic*`/`patchPublic*` is a direct echo of the proto service-name `PublicSettingsService` — i.e., the *server-side* internal-vs-public service split. The TS SDK only ships the public surface, so the qualifier signals nothing the user can act on. - **Suggestion:** Drop `Public` from every request type and every method name. `GetAccountSettingRequest`/`getAccountSetting`, `PatchAccountSettingRequest`/`patchAccountSetting`, etc. -- **Rationale:** This duplicates #11 and #12 but reframes them as a *proto-architectural leak* per the scan brief. The two earlier findings catalogued the names; this one names the cause. +- **Rationale:** This duplicates #10 and #11 but reframes them as a *proto-architectural leak* per the scan brief. The two earlier findings catalogued the names; this one names the cause. --- ## Low severity -### 19. `IntegerMessage` misleading in JS +### 18. `IntegerMessage` misleading in JS -- **File:line:** `model.ts:194-196` +- **File:line:** `model.ts:223-225` - **Category:** Misleading - **Suggestion:** The "Integer" half of the name is misleading — JS has no distinct integer type, and the `value` field is typed `number` (i.e. IEEE-754 double). A neutral name like `NumberMessage` would be honest about the runtime type. - **Rationale:** A reader seeing `IntegerMessage` may assume validation, bigint, or some integer-preserving codec. None is present. -### 20. `patch*` vs `update*`/`set*` - -- See #13. - ---- - -## Observations - -1. **`Setting`, `SettingsMetadata`, `UserPreference` are all underspecific.** The package theme is "settings v2", but the central types use the bare word "Setting" without qualification. This is the single biggest naming risk in the package — a user importing `Setting` from `@databricks/sdk-settings/v2` will clash with any application-level `Setting` type in seconds. - -2. **`patch` leaks the HTTP verb onto the public surface.** The mutation methods are named `patch*`, echoing the `PATCH` HTTP method rather than a domain action like `update`/`set`. Same wire verb (PATCH HTTP); the SDK-domain name would read more naturally and is easier to discover. - -3. **`Aibi` is an undefined abbreviation.** It is not expanded anywhere in the package — `Aibi` (AI/BI) only appears inside type names. A package-level glossary (or spelling it out in the type identifiers) would be high-ROI and zero-risk. +### 19. `patch*` vs `update*`/`set*` -4. **`patchPublic*` is six syllables and four word-roots for a single PATCH call.** `patch` + `Public` + (`Account` | `Workspace`) + (`Setting` | `UserPreference`) + `Request` accumulates fast. After dropping `Public` and `Request`, names like `patchAccountSetting` would be drastically more usable. +- See #12. diff --git a/.agent/naming-audit/sharing.md b/.agent/naming-audit/sharing.md index b72d6af4..264697c6 100644 --- a/.agent/naming-audit/sharing.md +++ b/.agent/naming-audit/sharing.md @@ -5,12 +5,6 @@ **Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` **Total weird names flagged:** 3 -**Last rescanned:** 2026-06-02. All findings re-verified against the -current source; none addressed upstream. The regeneration shifted most -line numbers and renamed the proto-nested `GetActivationUrlInfoRequest_Response` -to the clean `GetActivationUrlInfoResponse`; every citation was corrected -in place, and finding L1 was rewritten to reference the new response name. - ## Summary | Severity | Count | @@ -24,12 +18,12 @@ in place, and finding L1 was rewritten to reference the new response name. ## High severity (must fix) -### 1. `*Info` suffix repeated across the core entity surface — `model.ts:733, 768, 839, 895, 331, 358` +### 1. `*Info` suffix repeated across the core entity surface — `model.ts:764, 799, 870, 926, 368, 395` - **Why:** Five entity types use the proto-style `*Info` "metadata - message" suffix: `ProviderInfo` (model.ts:733), `RecipientInfo` - (model.ts:768), `RecipientTokenInfo` (model.ts:839), `ShareInfo` - (model.ts:895), and `FunctionParameterInfo` (model.ts:331) plus the - pluralised wrapper `FunctionParameterInfos` (model.ts:358). In every + message" suffix: `ProviderInfo` (model.ts:764), `RecipientInfo` + (model.ts:799), `RecipientTokenInfo` (model.ts:870), `ShareInfo` + (model.ts:926), and `FunctionParameterInfo` (model.ts:368) plus the + pluralised wrapper `FunctionParameterInfos` (model.ts:395). In every case the type IS the entity, not metadata *about* the entity — there is no `Provider` / `Recipient` / `RecipientToken` / `FunctionParameter` counterpart that `*Info` would document the metadata of. The `Info` @@ -58,15 +52,15 @@ in place, and finding L1 was rewritten to reference the new response name. ## Medium severity (worth pushing back on) -### 1. `FunctionParameterInfos` single-field array wrapper — `model.ts:358` +### 1. `FunctionParameterInfos` single-field array wrapper — `model.ts:395` - **Why:** `FunctionParameterInfos { parameters?: FunctionParameterInfo[] }` is a wrapper interface whose only field is the array. It is consumed exactly once, as the `inputParams: FunctionParameterInfos | undefined` - field on `Function` (model.ts:317). The wrapper exists to give the + field on `Function` (model.ts:354). The wrapper exists to give the proto schema a message type to hang the repeated field on; in TS it forces every caller to dereference `function.inputParams?.parameters` instead of `function.inputParams`. Same shape as `DependencyList` - (model.ts:261), which wraps `Dependency[]` as `dependencies`. + (model.ts:298), which wraps `Dependency[]` as `dependencies`. - **Category:** Proto-architecture leak (single-field repeated-only wrapper message — also a duplicated `*Infos` suffix in line with H1) - **Suggested:** Inline the array: change `Function.inputParams` to @@ -84,11 +78,11 @@ in place, and finding L1 was rewritten to reference the new response name. ## Low severity (nits) -### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:363, 369, client.ts:386` -- **Why:** The method `getActivationUrlInfo` (client.ts:386) returns - `GetActivationUrlInfoResponse`, an empty interface (model.ts:369). +### 1. `GetActivationUrlInfoRequest` injects `Info` into a method/type name with no payload — `model.ts:400, 406, client.ts:393` +- **Why:** The method `getActivationUrlInfo` (client.ts:393) returns + `GetActivationUrlInfoResponse`, an empty interface (model.ts:406). The mid-position `Info` in the method and the `GetActivationUrlInfoRequest` - type (model.ts:363) adds nothing semantic: the method just gets the + type (model.ts:400) adds nothing semantic: the method just gets the activation URL data (and currently returns nothing). The naming inherits the proto RPC name (`GetActivationUrlInfo`) where `Info` was the message-type variant suffix. diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md index e569b5e1..8845687f 100644 --- a/.agent/naming-audit/statementexecution.md +++ b/.agent/naming-audit/statementexecution.md @@ -6,44 +6,43 @@ **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`. -**Total weird names flagged:** 20 +**Total weird names flagged:** 17 ## Summary | Severity | Count | | --- | --- | | High | 5 | -| Medium | 11 | -| Low | 3 | -| Observation | 1 | +| Medium | 10 | +| Low | 2 | ## High severity -### 1. `Disposition` enum lacks SDK context — `src/v1/model.ts:40` +### 1. `Disposition` enum lacks SDK context — `src/v1/model.ts:45` - **Why weird:** Enum name is `Disposition` — a generic noun (`Content-Disposition` header? business "disposition"?). The enum members `INLINE` and `EXTERNAL_LINKS` are recognisable, but the type name doesn't say "fetch" or "result". A reader who skims `disposition?: Disposition` in `ExecuteStatementRequest` won't know it means "where the result data goes". As a top-level export, `Disposition` collides with any other "disposition" concept a consumer might pull in. - **Category:** 1 (vague — "Disposition" of what?), 15 (generic top-level export). - **Suggested name:** `ResultDisposition` or `FetchDisposition`. - **Rationale:** Top-level enum names should self-describe at use sites. `request.disposition: Disposition` reads as "disposition disposition"; `request.disposition: ResultDisposition` reads correctly. -### 2. `Format` enum is dangerously generic — `src/v1/model.ts:46` +### 2. `Format` enum is dangerously generic — `src/v1/model.ts:55` - **Why weird:** A top-level enum literally called `Format` exported from the package. The values `JSON_ARRAY`, `ARROW_STREAM`, `CSV` say this is about *result* format. Combine with #1: a user reading `result.format` sees `Format | undefined` and has to chase down what kind of format. As a top-level export, `Format` collides with any other "format" type a consumer might pull in (Intl, Node:format, lodash, etc.). - **Category:** 1 (vague — `Format` is the most generic possible name), 10 (reserved-word-ish — `format` is a builtin function name in many ecosystems), 15 (generic name losing meaning at use sites). - **Suggested name:** `ResultFormat`. Same pattern as #1. - **Rationale:** Top-level enum names should self-describe at use sites. `result.format: Format` reads as "format format"; `result.format: ResultFormat` reads correctly. The collision risk for a single-word `Format` import is high. -### 3. `TimeoutAction` enum name doesn't tie to the timeout field — `src/v1/model.ts:77` +### 3. `TimeoutAction` enum name doesn't tie to the timeout field — `src/v1/model.ts:92` - **Why weird:** The top-level enum `TimeoutAction` is generic — it doesn't tie back to the field it governs. In context: when the user-supplied `wait_timeout` expires, this field decides whether the statement keeps running asynchronously or is cancelled. The relationship between the enum and the timeout is invisible at the type level. - **Category:** 1 (vague — action on what?), 15 (generic top-level export). - **Suggested name:** Rename the enum to `OnTimeout` to match the field `onWaitTimeout`. - **Rationale:** Top-level enum names should self-describe at use sites and tie to the field they govern. -### 4. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:230` +### 4. `getStatementResult` method conflates "poll" with "fetch result" — `src/v1/client.ts:232` - **Why weird:** The JSDoc says: "This request can be used to poll for the statement's status. StatementResponse contains `statement_id` and `status`; other fields might be absent or present depending on context. When the `status.state` field is `SUCCEEDED` it will also return the result manifest and the first chunk of the result data." So the method *is* a polling endpoint that *also* returns results when ready. The method name `getStatementResult` foregrounds "result", but the method's primary job is polling. The companion chunk-fetch method `getResultData` (#5) does the actual result fetch, so a reader sees two `getResult*`-shaped methods, one of which only polls. - **Category:** 6 (misleading — name implies result-fetch, primary purpose is poll), 17 (inconsistent verb usage — `cancel`, `execute`, `getStatementResult`, `getResultData`). - **Suggested name:** `getStatement` (matches the URL path `/{statementId}`). The Go SDK calls this `GetStatement`. The result is *part* of the response; foregrounding it in the method name misleads. - **Rationale:** The Databricks API docs name the operation "Get statement" (https://docs.databricks.com/api/workspace/statementexecution/getstatement). The TS SDK should match. -### 5. `getResultData` method drops resource and chunk-index semantics — `src/v1/client.ts:191` +### 5. `getResultData` method drops resource and chunk-index semantics — `src/v1/client.ts:192` - **Why weird:** Companion to #4. The Databricks public API names this method "Get statement result by chunk index" (https://docs.databricks.com/api/workspace/statementexecution/getstatementresultchunkn). The Go SDK calls it `GetStatementResultChunkN`. The TS SDK shortens to `getResultData`, dropping both the resource ("statement") and the indexing word ("chunk"). The result is that a reader can't tell from the method name what it does or how it relates to `getStatementResult`. - **Category:** 1 (vague — "result data" is too generic), 6 (misleading — drops the chunk-indexing semantic), 17 (asymmetric with sibling method). - **Suggested name:** `getResultChunk` (or `getStatementResultChunk` to match Go). Field rename: `chunkIndex` stays. @@ -51,31 +50,31 @@ ## Medium severity -### 6. `warehouseId` field — `src/v1/model.ts:158` +### 6. `warehouseId` field — `src/v1/model.ts:180` - **Why weird:** Required field in practice (no statement can execute without it) but typed `string | undefined`. The JSDoc links to docs about SQL warehouses, which is good. The name is fine; the modality is wrong — every required field on the request is optional at the type level because the generator emits all fields as `optional`. Flagged for the consistency observation #11. - **Category:** 16 (field contradicts type domain — "required" per docs, optional in TS). - **Suggested name:** Make required: `warehouseId: string`. - **Rationale:** Wire requirements should propagate into TS types where possible. -### 7. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:195` +### 7. `chunkIndex` field type is `number` in URL path — `src/v1/client.ts:197` - **Why weird:** The chunk index is a JS `number` (potentially `undefined`). The URL builder uses `String(req.chunkIndex ?? '')` which produces the empty string when undefined — meaning the URL silently becomes `/result/chunks/` (trailing slash, no index) on an unset value. The client emits the request anyway. This is a footgun that the type name doesn't help with: `chunkIndex?: number | undefined` should probably be required. - **Category:** 16 (field contradicts domain — required in URL, optional in type), 19 (underspecified — what does `undefined` mean for a path component?). - **Suggested name:** Make required: `chunkIndex: number`. Method should refuse to send an empty path component. - **Rationale:** Naming + modality mismatch becomes a real bug at the URL level. -### 8. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:464` +### 8. `truncated` field on `ResultManifest` is ambiguously boolean — `src/v1/model.ts:480` - **Why weird:** A `truncated?: boolean | undefined` field. The JSDoc says "Indicates whether the result is truncated due to `row_limit` or `byte_limit`." But the field doesn't say *which* limit caused truncation. If truncation is rare, the user has to inspect both limits to figure out why. The name doesn't carry that information; a `truncationReason` field would. - **Category:** 1 (vague — boolean doesn't capture cause), 16 (field underdetermines domain). - **Suggested name:** Keep `truncated` but pair with an optional `truncationReason: 'rows' | 'bytes'` (or have the wire surface a reason). - **Rationale:** Boolean fields that conceal a richer enumeration are an anti-pattern. -### 9. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:422` +### 9. `dataArray` JSDoc references `JSON_ARRAY` format — `src/v1/model.ts:438` - **Why weird:** Field JSDoc: "The `JSON_ARRAY` format is an array of arrays of values, where each non-null value is formatted as a string. Null values are encoded as JSON `null`." The field is only populated when `format === JSON_ARRAY`. The type doesn't reflect this conditional: `dataArray?: JsonValue[][] | undefined`. A user setting `format=CSV` will see `dataArray` undefined and have to chase JSDoc to learn it's intentional. - **Category:** 16 (field-vs-format contradicts domain when format differs). - **Suggested name:** Make `ResultData` a discriminated union over `format`. Names stay; the type changes. - **Rationale:** Optional fields whose presence depends on another field should be modelled as discriminated unions. -### 10. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:417, 422` +### 10. `externalLinks?: ExternalLink[]` + `dataArray?: JsonValue[][]` mutual exclusivity — `src/v1/model.ts:433, 438` - **Why weird:** Companion to #9. The JSDoc literally says "Exactly one of these alternatives is used." TypeScript has discriminated unions; the type doesn't use them. So both fields are simultaneously `?: undefined` at the type level; the user must conditionally narrow. - **Category:** 16 (mutual exclusivity not modelled), 17 (asymmetric pair). - **Suggested name:** Discriminate on `disposition` — names unchanged; type shape changes. @@ -85,33 +84,27 @@ - **Why weird:** `warehouseId`, `statement`, `chunkIndex`, `statementId` — all required at the wire level — are all `?: T | undefined` at the TS level. The codegen emits everything as optional to keep round-tripping simple. The names don't communicate which fields are required; the JSDoc occasionally does (statement: "the SQL statement to execute"). A user can call `executeStatement({})` and only learn it's wrong at runtime. - **Category:** 16 (field contradicts domain — required-in-wire, optional-in-TS), 1 (modality silently lost). - **Suggested name:** N/A — the names are fine, the modality is wrong. Mark required fields as required (no `?`). -- **Rationale:** Same finding as `commandexecution.md` and `queryexecution.md`; generator-wide. +- **Rationale:** Generator-wide pattern — the codegen emits every request field as optional across packages. -### 12. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:473` +### 12. `ServiceError` — `Service` is architectural-layer leak — `src/v1/model.ts:489` - **Why weird:** Mid-position `Service` qualifier names an architectural layer ("the service tier"), not a domain concept. The wire payload is a per-statement error carried in `StatementStatus.error`; the "service" is the SQL Statement Execution backend, but that role isn't user-facing. A TS consumer reads `error: ServiceError` and sees an architectural noun rather than the domain concept (statement execution error). - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementError` — domain-named, mirrors the surrounding `Statement*` vocabulary. - **Rationale:** Architectural-layer words ("Service", "Server", "Backend") in user-facing type names are proto/RPC framework carry-overs. Domain-named alternatives compose better with the rest of the package surface. -### 13. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:53` +### 13. `ServiceErrorCode` — `Service` is architectural-layer leak — `src/v1/model.ts:64` - **Why weird:** Same `Service` mid-position architectural leak as #12, applied to the code enum. A TS consumer reads `ServiceErrorCode` and sees an architectural noun rather than the domain concept. - **Category:** 14 (proto/Java/Go-style architectural mid-position qualifier). - **Suggested name:** `StatementErrorCode`. - **Rationale:** Pair with #12 — the `Service` qualifier carries no domain meaning at the use site. -### 14. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:84` +### 14. `StatementStatus_State` — proto-style nested-type underscore — `src/v1/model.ts:102` - **Why weird:** Underscore-joined identifier `StatementStatus_State` directly transcribes the proto nested-message name into TS. The source file even carries an `eslint-disable` for `@typescript-eslint/naming-convention` with the comment "Proto-style nested enum name." That comment confirms it: the name is a verbatim proto leak, not a TS-idiomatic choice. As a top-level export from `index.ts`, every consumer sees the underscore. - **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). - **Suggested name:** `StatementState` (the `Status` parent is itself a thin wrapper; the state is the meaningful enum) or `StatementStatusState` (no underscore) if both halves matter. - **Rationale:** Proto nested-type underscores are an artefact of code generation from `.proto`. TS has no nested-type concept; flattening to a single CamelCase name removes the leak. -### 15. `ExternalLink_HttpHeadersEntry` — proto map-entry leak — `src/v1/model.ts:376` -- **Why weird:** Another underscore-joined name with the same `eslint-disable` and an explicit "Proto-style nested message name" comment. The type exists because proto3 represents `map` as a synthetic nested `*Entry` message; gRPC generators surface this as a nested type. In TS the wire shape is just `Record` (see `httpHeaders` on `ExternalLink`). Re-exporting `ExternalLink_HttpHeadersEntry` from `index.ts` exposes proto machinery the JS user never needs. -- **Category:** 14 (proto/protobuf naming carry-over), 9 (non-idiomatic identifier shape). -- **Suggested name:** Delete the type. The `httpHeaders` field is already `Record | undefined`; no consumer needs the synthetic map-entry pair. -- **Rationale:** Proto `map` synthetic `*Entry` messages should not surface in user-facing TS types. The information is fully captured by `Record`. - -### 16. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:41, 47, 78, 85` +### 15. `*_UNSPECIFIED` enum zero values — `src/v1/model.ts:46, 56, 93, 103` - **Why weird:** Four enums (`Disposition`, `Format`, `TimeoutAction`, `StatementStatus_State`) carry a `FETCH_DISPOSITION_UNSPECIFIED`, `FORMAT_UNSPECIFIED`, `TIMEOUT_ACTION_UNSPECIFIED`, `STATE_UNSPECIFIED` first variant. These are proto3 enum convention: every enum must have a `_UNSPECIFIED = 0` member because the default scalar value is required to be valid. JS/TS has no such constraint — `undefined` already encodes "not specified". So the enums carry a value that exists *only* to satisfy proto3 codegen requirements. End users have to filter out the unspecified variant manually when narrowing. - **Category:** 14 (proto/protobuf convention leak), 6 (misleading — the variant has no domain meaning), 1 (vague — `UNSPECIFIED` is the literal default state). - **Suggested name:** Drop the `*_UNSPECIFIED` variants. TS uses `Disposition | undefined` for "not set". @@ -119,28 +112,13 @@ ## Low severity -### 17. `chunkIndex` vs `nextChunkIndex` naming pair — `src/v1/model.ts:107, 122` -- **Why weird:** A `ChunkInfo` has `chunkIndex` (this chunk's index) and `nextChunkIndex` (the *next* chunk's index). The pair is consistent. But the `ChunkInfo` is also used in two contexts (manifest array, in-chunk metadata), and the wire shape doesn't always populate `nextChunkIndex`. Names are fine but the duplication across two distinct uses is worth flagging. -- **Category:** 17 (acceptable asymmetry). -- **Suggested name:** Keep. - -### 18. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:349` +### 16. `httpHeaders` value type loses sensitivity context — `src/v1/model.ts:371` - **Why weird:** JSDoc says "Headers are typically used to pass a decryption key to the external service. The values of these headers should be considered sensitive and the client should not expose these values in a log." So this is a security-sensitive map. The field name doesn't signal this. A name like `secretHeaders` would surface the constraint at the use site. - **Category:** 16 (field-vs-domain contradiction — sensitive content, neutral field name). - **Suggested name:** `secretHeaders`, or document the sensitivity at the type level. - **Rationale:** Optional/low-priority but worth noting. -### 19. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:468` +### 17. `Schema` type is a top-level export with a maximally overloaded name — `src/v1/model.ts:484` - **Why weird:** The name `Schema` is one of the most overloaded words in SDK ecosystems (validation schemas, database schemas, JSON schemas). Exported at the top level of the package, a consumer importing `Schema` from `@databricks/sdk-statementexecution` collides with any other `Schema` they pull in. - **Category:** 1 (vague — `Schema` is overloaded), 10 (reserved-word-ish), 15 (generic top-level export). - **Suggested name:** `ResultSchema` (or `ColumnSchema`) to disambiguate from other schema concepts. - -## Observations (non-fixable here) - -### O-1. URL string concatenation handles `undefined` silently — `src/v1/client.ts:78, 195, 234` -- The URL is built via template literals like - ``${this.host}/api/2.0/sql/statements/${req.statementId ?? ''}/cancel``. - If `statementId` is `undefined`, the URL becomes - `.../sql/statements//cancel`, which the server will return 404 for. The - fallback to empty string is a silent-failure pattern. Names are fine; the - fallback semantics are wrong. diff --git a/.agent/naming-audit/storageconfigurations.md b/.agent/naming-audit/storageconfigurations.md index f9ed20cd..980afae2 100644 --- a/.agent/naming-audit/storageconfigurations.md +++ b/.agent/naming-audit/storageconfigurations.md @@ -25,29 +25,25 @@ workspaces in an account). - **Suggested:** `createStorageConfiguration`. - **Rationale:** Methods on `Client` are inherently public; the suffix is meaningless to a TS caller. -- **Status:** Still present after regeneration on 2026-06-01. -### 2. `Client.deleteStorageConfigurationPublic` — `src/v1/client.ts:96` +### 2. `Client.deleteStorageConfigurationPublic` — `src/v1/client.ts:97` - **Why weird:** Same `Public` suffix on `Client` method as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `deleteStorageConfiguration`. - **Rationale:** Same as #1. -- **Status:** Still present after regeneration on 2026-06-01. -### 3. `Client.getStorageConfigurationPublic` — `src/v1/client.ts:121` +### 3. `Client.getStorageConfigurationPublic` — `src/v1/client.ts:123` - **Why weird:** Same `Public` suffix on `Client` method as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `getStorageConfiguration`. - **Rationale:** Same as #1. -- **Status:** Still present after regeneration on 2026-06-01. -### 4. `Client.listStorageConfigurationPublic` — `src/v1/client.ts:146` +### 4. `Client.listStorageConfigurationPublic` — `src/v1/client.ts:149` - **Why weird:** Same `Public` suffix on `Client` method as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `listStorageConfigurations` (drop `Public`; pluralise while renaming). - **Rationale:** Same as #1. -- **Status:** Still present after regeneration on 2026-06-01. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md index 4bd74047..31d9ebf4 100644 --- a/.agent/naming-audit/supervisoragents.md +++ b/.agent/naming-audit/supervisoragents.md @@ -11,13 +11,12 @@ resource types: `SupervisorAgent` (top-level), `Tool` (child of in-context steering). Every list endpoint paginates via `pageSize`/`pageToken`. No state enums exist in this package; the entire surface is data plus references to other Databricks resources. -**Total weird names flagged:** 4 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | | High | 2 | -| Observation | 2 | ## High severity @@ -32,13 +31,3 @@ surface is data plus references to other Databricks resources. - **Category:** 1 (vague/generic). - **Suggested name:** `AgentTool`, `SupervisorTool`, or `RegisteredTool`. The qualifier disambiguates against generic `Tool` collisions in a multi-package import set. - **Rationale:** Same reasoning as #1; specificity in type names prevents alias collisions and makes import lists self-documenting. - -## Observations - -### 3. Action verbs in `Client` are consistent — `src/v1/client.ts` -- **Why weird:** The client uses `create`/`delete`/`get`/`list`/`update` — no `fetch`/`retrieve`/`read`/`remove`. This is good. Flagging as a *positive* observation. -- **Category:** 17 (reversed — consistency note). - -### 4. Method-name verb conventions match resource targets — `src/v1/client.ts:89,118,150,191,213,235,257,285,313,338,392,449,503,547,594` -- **Why weird:** Methods are uniformly `verb` + `Subject` (createExample, createSupervisorAgent, createTool, deleteExample, deleteSupervisorAgent, deleteTool, getExample, getSupervisorAgent, getTool, listExamples, listSupervisorAgents, listTools, updateExample, updateSupervisorAgent, updateTool). 15 methods, 5 verbs × 3 subjects, no exceptions. Strong positive observation. -- **Category:** 17 (positive observation). diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md index 074241d2..11cf31a4 100644 --- a/.agent/naming-audit/systemschemas.md +++ b/.agent/naming-audit/systemschemas.md @@ -3,7 +3,7 @@ **Path:** `packages/uc/systemschemas/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog *system schemas* (curated, server-managed schemas such as `access`, `billing`, `lineage`, `query`) — enable/disable a system schema in a metastore and list the system schemas under a metastore. -**Total weird names flagged:** 4 +**Total weird names flagged:** 3 ## Summary | Severity | Count | @@ -11,7 +11,6 @@ | High | 1 | | Medium | 1 | | Low | 1 | -| Observation | 1 | ## High severity @@ -31,13 +30,8 @@ ## Low severity -### 3. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:49`, `client.ts:190` -- **Why weird:** `listSystemSchemasIter` (client.ts:190) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. +### 3. `nextPageToken` is `string | undefined` but server may also return empty-string — `src/v1/model.ts:49`, `client.ts:192` +- **Why weird:** `listSystemSchemasIter` (client.ts:192) checks `resp.nextPageToken === undefined || resp.nextPageToken === ''` to know it's done — i.e., the wire uses an empty string as a sentinel. The TS type `nextPageToken: string | undefined` doesn't capture this contract; readers must inspect the iterator code to learn that `''` is a terminator. - **Category:** 6 (misleading — type allows `''` but doc says "Absent if there are no more pages"), 16 (field-vs-doc mismatch). - **Suggested name:** Keep the name; tighten the contract by replacing `''` with `undefined` in the zod transform (model.ts:76-79) so callers see a consistent sentinel. - **Rationale:** A naming review surfaces the contract drift even though the renaming target is the marshaller, not the field. - -## Observations - -### 4. Action-verb consistency in `SystemSchemasClient` -Methods are `disableSystemSchema`, `enableSystemSchema`, `listSystemSchemas` — no mixed `delete`/`remove` or `fetch`/`get`. The pair `enable` / `disable` is also a clean antonym, which is good. Flagged per rule 17 because the audit asked for inconsistency *and* notable consistency. diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md index c597e888..2ea09064 100644 --- a/.agent/naming-audit/tables.md +++ b/.agent/naming-audit/tables.md @@ -15,10 +15,7 @@ | Severity | Count | | --------------------- | ----- | -| High | 4 | -| Medium | 6 | -| Pass / acceptable | 6 | -| **Total findings** | **16** | +| **Total findings** | **6** | (Findings often span multiple audit categories; counts above are unique findings.) @@ -29,7 +26,7 @@ findings.) ### 1. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) -**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:401). +**Symbol:** `DeltaRuntimePropertiesKvPairs` (model.ts:443). **Issue:** `Kv` (key-value) is borderline cryptic for a TypeScript API; the "Pairs" suffix is redundant if `Kv` already means key-value. The type holds @@ -42,134 +39,7 @@ self-describing). --- -### 2. `ListTablesRequest.maxResults` and `pageToken` paginate negatively-documented semantics — category 6 (Misleading names) — *pass with note* - -**Symbol:** `ListTablesRequest.maxResults?: number | undefined` -(model.ts:530), JSDoc: "Maximum number of tables to return. If not set, all -the tables are returned (not recommended)." - -The pagination docstring is long and warns that unpaginated calls will be -deprecated. The naming is fine; the API behaviour is the issue. - -**Pass on naming.** - ---- - -### 3. `ColumnInfo.position` underspecified field — category 1 (Vague/generic) - -**Symbol:** `ColumnInfo.position?: number | undefined` (model.ts:244). -JSDoc: "Ordinal position of column (starting at position 0)." - -**Issue:** Bare `position` (number) — a consumer cannot tell from the -field name that it's 0-indexed. The JSDoc clarifies. - -**Suggested:** **Pass with note** — the field is short and conventional. - ---- - -### 4. `OptionSpec` has many `is…` boolean fields — category 17 (Inconsistent action verbs) — *pass with note* - -**Symbols:** `OptionSpec.isRequired` (model.ts:586), -`OptionSpec.isSecret` (model.ts:588), `OptionSpec.isHidden` (model.ts:590), -`OptionSpec.isUpdatable` (model.ts:592), `OptionSpec.isLoggable` -(model.ts:596), `OptionSpec.isCreatable` (model.ts:598), -`OptionSpec.isCopiable` (model.ts:600). - -The boolean fields all use the `is…` prefix, which is the right convention -for booleans. **Pass on naming.** - -(The number of booleans on `OptionSpec` (7+) is itself a code smell — the -type packs configuration for a UI form, with each boolean controlling a -different aspect of display. A consumer struggling to set all of these -correctly may want a richer type. **Note for upstream.**) - ---- - -### 5. `EffectivePredictiveOptimizationFlag.value` is a generic field on a specific type — category 1 (Vague/generic) and category 15 (Generic field names losing meaning) - -**Symbol:** `EffectivePredictiveOptimizationFlag.value?: string` -(model.ts:433). JSDoc: "Whether predictive optimization should be enabled -for this object and objects under it." - -**Issue:** The type's *purpose* is to indicate whether PO is enabled. The -field name `value` says nothing about that — the generic `value` token -loses the domain meaning the type name carries. - -**Suggested:** rename the field to reflect its meaning (e.g. -`predictiveOptimization`, matching the type's "enabled" sense). - ---- - -### 6. `EffectivePredictiveOptimizationFlag.inheritedFromType` / `inheritedFromName` — category 17 (Inconsistent action verbs) - -**Symbols:** `EffectivePredictiveOptimizationFlag.inheritedFromType?: string` -(model.ts:435), `EffectivePredictiveOptimizationFlag.inheritedFromName?: string` -(model.ts:437). - -**Issue:** Two fields describing the source of inheritance — the object -type ("CATALOG"|"SCHEMA"|…) and the object's name. Naming is OK, but the -suffix pair `…Type` / `…Name` repeats inside one struct that has only -three fields. - -**Pass with note** — the current flat form is wire-faithful. - ---- - -### 7. `TablesClient.createTable` / `deleteTable` / `getTable` / `updateTable` / `listTables` / `tableExists` — *pass* - -Standard `{verb}{Resource}` shape. Convention. **Pass.** - -(Note: `TablesClient.tableExists` (client.ts:495) breaks the verb-first -pattern — it reads `noun-verb` instead of `verb-noun`. The corresponding -shape in other SDKs is `existsTable` or `checkTableExists`. **Flag at -SDK-wide level.**) - ---- - -### 8. `TablesClient.createTableConstraint` / `deleteTableConstraint` — *pass* - -Same `{verb}{Resource}` pattern. **Pass.** - ---- - -### 9. `TablesClient` private fields `host`, `workspaceId`, `httpClient`, `logger`, `userAgent` — *pass* - -Standard. **Pass.** - ---- - -### 10. Singular/plural — package name `tables` vs type names singular — category 9 (Singular/plural mismatch) — *pass* - -Package: `@databricks/sdk-tables` (plural — collection). Types: `TableInfo`, -`TableSummary`, `TableConstraint`, etc. (singular — one item). SDK-wide -pattern. **Pass.** - ---- - -### 11. `_PropertiesEntry` / `_DeltaRuntimePropertiesEntry` underscore-suffixed proto map-entry type names — category 4 (Underscores in TS identifiers) - -**Symbols:** `CreateTableRequest_PropertiesEntry` (model.ts:363), -`DeltaRuntimePropertiesKvPairs_DeltaRuntimePropertiesEntry` (model.ts:407), -`TableInfo_PropertiesEntry` (model.ts:783), -`UpdateTableRequest_PropertiesEntry` (model.ts:870). - -**Issue:** Underscores in PascalCase identifiers are not idiomatic TS -(Google style guide § 5.1 disallows them; the generated code carries an -`eslint-disable-next-line @typescript-eslint/naming-convention` comment -above each, at model.ts:362, 406, 782, 869). The underscores survive from -the proto's nested map-entry message naming. None of these four types is -referenced anywhere — the actual map fields use `Record` -(e.g. `CreateTableRequest.properties`, model.ts:359) — yet they are still -declared and re-exported from `index.ts`. - -**Suggested:** drop the map-entry types entirely; `Record` -is sufficient and is already what the fields use. - -**Flag for SDK-wide generator cleanup.** - ---- - -### 12. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:213, 226 +### 2. `OptionSpec_OauthStage` / `OptionSpec_OptionType` proto-nested infix — file:line model.ts:253, 270 **Why:** Underscore-separated `OuterMessage_InnerEnum` naming is a literal transcription of proto nested-enum scoping. The infix `_` and the @@ -184,12 +54,12 @@ prefix) — or, if collision risk exists, `OptionOauthStage` / `OptionTypeKind`. **Rationale:** the `OptionSpec_` prefix exists solely to mirror the proto -nesting; the eslint-disable comments on lines 212, 225 acknowledge the +nesting; the eslint-disable comments on lines 258, 280 acknowledge the non-idiomatic shape. --- -### 13. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:565 +### 3. `OptionSpec` type name carries a `Spec` config-suffix — file:line model.ts:601 **Why:** `Spec` is a generic config-style suffix that re-appears across the file (`SecurableKindManifest`, `EffectivePredictiveOptimizationFlag`, @@ -206,7 +76,7 @@ struct describing X" — a proto convention, not a TS one. --- -### 14. `SecurableKindManifest` type name — file:line model.ts:650 +### 4. `SecurableKindManifest` type name — file:line model.ts:686 **Why:** `Manifest` is a config-style suffix (analogous to `Spec`/`Config`). It tags the type as a descriptor message rather than a domain concept. @@ -222,7 +92,7 @@ adds no information beyond "this is the descriptor". --- -### 15. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:237, 711, 788 +### 5. `ColumnInfo`, `TableInfo`, `TableSummary` — repeated `Info`/`Summary` config-suffix — file:line model.ts:285, 747, 818 **Why:** `Info` and `Summary` are generic descriptor-suffixes used to distinguish the wire/RPC message from the domain noun (`Column`, `Table`). @@ -239,7 +109,7 @@ and from server-internal representations — a generator/architectural leak. --- -### 16. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:441, 664 +### 6. `EncryptionDetails` / `SseEncryptionDetails` — repeated `Details` config-suffix — file:line model.ts:477, 700 **Why:** Two `…Details` types in the same file. `Details` is a generic "descriptor" suffix with no domain meaning — same family as `Info`/`Spec`. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md index 17aac381..0159bd6f 100644 --- a/.agent/naming-audit/tagassignments.md +++ b/.agent/naming-audit/tagassignments.md @@ -2,18 +2,17 @@ **Path:** `packages/tagassignments/src/v1/` **Versions audited:** v1 -**Total weird names flagged:** 5 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | | High | 1 | -| Medium | 2 | -| Observation | 2 | +| Medium | 1 | ## High severity -### 1. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:152` +### 1. `ListTagAssignmentsRequest.entityType` / `entityId` are functionally required but typed optional — `src/v1/model.ts:31,33` and used in URL at `client.ts:155` - **Why weird:** The list URL is `/api/2.0/entity-tag-assignments/${entityType ?? ''}/${entityId ?? ''}/tags`. When either is undefined, the URL becomes `.../entity-tag-assignments///tags`. Both fields are typed `string | undefined`, but `entityType` and `entityId` are clearly required to address an entity. Same issue on `Get`/`Delete`/`Update`. The SDK silently produces malformed URLs. - **Category:** 6 (misleading — optional in type but required in practice). - **Suggested name:** Make path-component fields required (non-optional) on the request types. @@ -21,23 +20,8 @@ ## Medium severity -### 2. `ListTagAssignmentsRequest` (plural) vs. `TagAssignment` (singular) — `src/v1/model.ts:29` vs. `src/v1/model.ts:46` -- **Why weird:** The plural appears only on list types. The HTTP resource on the wire is `/entity-tag-assignments` (plural) while the item type is singular `TagAssignment`. List response is `ListTagAssignmentsResponse` (plural). -- **Category:** 9 (singular/plural mismatch — present and intentional, but inconsistent vocabulary). -- **Suggested name:** Keep as-is (cross-SDK convention). Listed for completeness. -- **Rationale:** Rule 9 demands the flag even when intentional. - -### 3. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:102,124,152,206` +### 2. URL composition with `req.entityType ?? ''` etc. — `src/v1/client.ts:103,126,155,210` - **Why weird:** Four endpoints silently fall back to empty string for missing path components. When `entityType` is undefined the URL becomes `.../entity-tag-assignments//entity-id/tags/key`. Same problem flagged in other packages; specific instance here. - **Category:** 6 (misleading — silent malformed URLs). - **Suggested name:** Make `entityType`/`entityId`/`tagKey` non-optional on path-bearing request types. - **Rationale:** See #1. Generator-wide concern. - -## Observations - -### 4. Action verb consistency -The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. - -### 5. `tagassignments` lowercase package name vs. types and HTTP path -The package directory is `tagassignments` (single token, no separator). Types are `TagAssignment` (PascalCase, no compound). HTTP path is `/entity-tag-assignments` (kebab and *with* `entity`). Three different naming conventions for the same concept across three surface layers. Same problem as sister packages. -- **Category:** 3 (casing inconsistency between directory token, kebab wire path, and Pascal types), 1 (vague directory token). diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md index 6cc51668..4cdbd045 100644 --- a/.agent/naming-audit/tagpolicies.md +++ b/.agent/naming-audit/tagpolicies.md @@ -3,29 +3,23 @@ **Path:** `packages/tagpolicies/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level governed-tag definitions. A `TagPolicy` declares a `tagKey`, an allowed set of `values`, and an optional `id`/timestamps so that a tag becomes "governed" across the account. Sister of `tagassignments` (apps/dashboards/geniespaces/notebooks K/V tags) and `entitytagassignments` (Unity Catalog K/V tags). The HTTP surface is `/api/2.1/tag-policies`, with the five standard verbs (create/get/list/update/delete) keyed by `tagKey`. -**Total weird names flagged:** 3 +**Total weird names flagged:** 2 ## Summary | Severity | Count | | --- | --- | | High | 2 | -| Observation | 1 | ## High severity ### 1. `TagPolicy` exposes the wire-side term instead of the domain term — `src/v1/model.ts:36` -- **Why weird:** The primary type is named `TagPolicy`, but the JSDoc on every client method talks about "governed tags" (`client.ts:68,97,119,147,201`). "Governed tag" is the canonical domain term; "tag policy" is the wire/proto-side term that mirrors the `/api/2.1/tag-policies` path. The SDK should expose the domain term, not the wire-side noun. +- **Why weird:** The primary type is named `TagPolicy`, but the JSDoc on every client method talks about "governed tags" (`client.ts:67,97,120,149,204`). "Governed tag" is the canonical domain term; "tag policy" is the wire/proto-side term that mirrors the `/api/2.1/tag-policies` path. The SDK should expose the domain term, not the wire-side noun. - **Category:** 14 (Go-style — Go SDK keeps the wire-side noun; TS users would benefit from the domain term). - **Suggested name:** `GovernedTag` (matches domain language used throughout the JSDoc). - **Rationale:** The user-facing concept is "this tag is governed", not "this tag has a policy attached". Cross-SDK consistency vs. domain readability trade-off. ### 2. `tagKey` field is `string | undefined` on `DeleteTagPolicyRequest` / `GetTagPolicyRequest` — `src/v1/model.ts:13,17` -- **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${this.host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:102,124`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). +- **Why weird:** `DeleteTagPolicyRequest.tagKey` and `GetTagPolicyRequest.tagKey` are both `string | undefined`. The URL is built as `${host}/api/2.1/tag-policies/${req.tagKey ?? ''}` (`client.ts:103,126`) — if `tagKey` is undefined, the path becomes `/tag-policies/` (trailing slash, empty key). That is a guaranteed 404 (or worse, a list-style request). The field is *required* in any meaningful call but typed optional. Sister `EntityTagAssignment` requests have the same problem (docs say "Required" but type is `?`). - **Category:** 6 (misleading — type says optional, semantics says required), 19 (underspecified ID — what should `tagKey` look like? Constraints? Encoding?). - **Suggested name:** Keep `tagKey`; make non-optional (`tagKey: string`) on get/delete/update. Add JSDoc describing valid keys. - **Rationale:** Optional path parameters in REST clients are a generator anti-pattern. Honest required-ness should travel through the type, not through a `?? ''` fallback that produces a malformed URL. - -## Observations - -### 3. Action verb consistency -The client uses `create`/`get`/`update`/`delete`/`list` — no `fetch`/`retrieve`. Consistent across this package and aligned with sister packages. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md index a5010297..e9e8f7ef 100644 --- a/.agent/naming-audit/tokenmanagement.md +++ b/.agent/naming-audit/tokenmanagement.md @@ -15,13 +15,13 @@ ## High severity ### 1. `AdminTokenInfo` — `Info` is a vague suffix, package-specific prefix is misleading -- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. `src/v1/model.ts:23`. +- **Why weird:** `AdminTokenInfo` is the central domain entity but `Info` is a generic suffix that adds nothing — every type is "info about something". `Admin` is a prefix that comes from this being the admin-API variant but is meaningless once you've imported from `@databricks/sdk-tokenmanagement`. Compare to the sibling `tokens` package which calls its entity `PublicTokenInfo` (also `Info`-suffixed) — neither name reads well. `src/v1/model.ts:27`. - **Category:** 1 (vague suffix `Info`), 8 (redundant type suffix), 15 (generic suffix that loses meaning). - **Suggested name:** `Token` (or `ManagedToken` if `Token` would clash with a class on the consumer side; given this is exported from `@databricks/sdk-tokenmanagement/v1`, `Token` is fine). - **Rationale:** `Token` is the noun the user thinks about. `Info` is a Go-SDK tic; TS does not need it. ### 2. Client method `deleteToken` wraps request type `RevokeTokenRequest` — verb-tense inconsistency -- **Why weird:** `client.deleteToken(req: RevokeTokenRequest)` at `client.ts:108-133` with the type defined at `model.ts:110`. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently. +- **Why weird:** `client.deleteToken(req: RevokeTokenRequest)` at `client.ts:108-134` with the type defined at `model.ts:114`. The method says "delete" but the request type, request handler, and HTTP behavior is "revoke". The HTTP method is `DELETE` and the URL is `/tokens/{id}`, so REST-style "delete" is reasonable for the method, but then the request type should match — or the method should be `revokeToken` to match the type. The sibling `tokens` package uses `revokeToken` consistently. - **Category:** 13 (verb-tense inconsistency between method and request type), 17 (inconsistent action verbs across the two packages: `tokenmanagement.deleteToken` vs `tokens.revokeToken` for the same kind of operation). - **Suggested name:** Either rename method to `revokeToken` (matches type and matches sibling package) or rename type to `DeleteTokenRequest` (matches HTTP verb). Recommend the former so both packages share a verb. - **Rationale:** "Revoke" carries a security/lifecycle meaning that "delete" loses; tokens aren't deleted from history, they're invalidated. @@ -29,7 +29,7 @@ ## Medium severity ### 3. `CreateOnBehalfOfTokenRequest` — preposition phrase inside type name -- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:53`. Industry shorthand is "OBO" but the SDK avoids the acronym. +- **Why weird:** The type name contains "OnBehalfOf" — a preposition phrase. Reads as "create on behalf of token request" when the intent is "request to create [on-behalf-of token]" (parse: a kind of token). `model.ts:57`. Industry shorthand is "OBO" but the SDK avoids the acronym. - **Category:** 7 (overly verbose), 14 (Go/Java-style camelCase verb phrase). - **Suggested name:** `CreateOboTokenRequest` (with JSDoc spelling out OBO), or `MintTokenForServicePrincipalRequest` if explicitness wins over brevity. - **Rationale:** This is the only operation in the package whose name relies on the preposition; surfacing the intent (mint a token for someone else) helps. Defensible as-is. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md index 2f673a9f..c853fff2 100644 --- a/.agent/naming-audit/tokens.md +++ b/.agent/naming-audit/tokens.md @@ -13,7 +13,7 @@ ## High severity -### 1. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:56-73` +### 1. `PublicTokenInfo` type name — "public" is unmotivated — `model.ts:60-77` - **Why weird:** Type is named `PublicTokenInfo` but the surrounding context contains no `PrivateTokenInfo`, `InternalTokenInfo`, or any other counterpart. The "Public" qualifier therefore communicates nothing to a TS reader. From the wire perspective, the Go SDK presumably has a parallel internal type that *isn't* exposed; in TS, that distinction is invisible. Compare to `tokenmanagement.AdminTokenInfo` (also "TokenInfo"-flavoured) — the package uses `Admin` to clarify the audience, but `Public` here doesn't. - **Category:** 1 (vague qualifier), 6 (misleading — "Public" implies a public-vs-private dichotomy that doesn't surface in the SDK). - **Suggested name:** `TokenInfo` (drop the `Public` prefix) or `UserTokenInfo` (parallel to `AdminTokenInfo` in `tokenmanagement`). The wire field `token_info` is bare anyway — the qualifier is purely cosmetic. @@ -21,7 +21,7 @@ ## Low severity -### 2. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:224` +### 2. `publicTokenInfoFieldMask` exported helper — public-API field-mask builder — `model.ts:228` - **Why weird:** The package exports `publicTokenInfoFieldMask(...)` as a top-level helper alongside the `Client`. Field-mask builders are an SDK-shape choice: making one a public export per type bakes the proto-FieldMask convention into the public API surface. Consumers writing `UpdateTokenRequest` payloads must learn this helper. - **Category:** 8 (helper-as-public-API). - **Suggested name:** Either hoist into a single `Client.updateToken` overload that accepts a partial payload and derives the mask, or document the helper prominently in `index.ts`. @@ -29,5 +29,5 @@ ## Observations -### 3. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:176` -`const url = \`${this.host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:89`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. +### 3. Method `updateToken` uses URL path interpolation on a potentially empty string — `client.ts:179` +`const url = \`${host}/api/2.0/token/${req.tokenId ?? ''}\`;` — when `req.tokenId` is unset, the URL becomes `${host}/api/2.0/token/` with a trailing slash, which the server may treat differently than a missing ID. Naming-adjacent: the type makes `tokenId` optional (`model.ts:93`), but the endpoint requires it. The TS surface doesn't enforce the required-ness. Not a naming issue per se — but a type-name fix (`tokenId: string` — required) would prevent the silent empty path. diff --git a/.agent/naming-audit/usagedashboards.md b/.agent/naming-audit/usagedashboards.md index 5cd1a29e..4ba65a61 100644 --- a/.agent/naming-audit/usagedashboards.md +++ b/.agent/naming-audit/usagedashboards.md @@ -3,14 +3,13 @@ **Path:** `packages/usagedashboards/src/v1/` **Versions audited:** v1 **Inferred domain:** Account-level CRUD for the Databricks "Billing Usage" dashboard — a workspace-scoped or globally-scoped DBSQL dashboard pre-built by Databricks that visualises account billing/usage data. Two endpoints only: `POST /api/2.0/accounts/{account_id}/dashboard` (create) and `GET /api/2.0/accounts/{account_id}/dashboard` (read). Both return a `dashboardId` (and the read variant also returns a `dashboardUrl`). No update, no delete, no list operation. Two enums (`UsageDashboardMajorVersion`, `UsageDashboardType`). -**Total weird names flagged:** 7 +**Total weird names flagged:** 6 ## Summary | Severity | Count | | --- | --- | | High | 3 | | Medium | 3 | -| Observation | 1 | ## High severity @@ -20,39 +19,34 @@ - **Suggested name:** `usagedashboard` (singular) — or, better, fold into a `billing` package alongside `billableusagedownload` (which has the same parent `/api/2.0/accounts/{account_id}` namespace). - **Rationale:** A user discovering the SDK would expect a "list" operation from a plural package name and be surprised by the lack of one. The singular form also matches the REST path `/dashboard`. The fold-into-`billing` move is a generator-level concern but worth flagging: both `usagedashboards` and `billableusagedownload` are about account-level billing data and live under the same URL prefix. -### 2. `dashboardType` field on `Create*` is misleadingly optional and arrives in the URL query string — `src/v1/model.ts:23, 39` / `src/v1/client.ts:106-107` -- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType` on create? The API presumably 4xx's or picks a side. Also note `dashboardType` is sent as a query-string parameter on the GET (`client.ts:106-107`) but the request shape is otherwise body-shaped — inconsistent transport for fields on the same DTO. -- **Category:** 6 (misleading — TS type says optional, API likely requires it), 16 (field type contradicts domain reality), 17 (inconsistent transport: same field is body on POST, query on GET). -- **Suggested name:** Keep the name but type as `UsageDashboardType` (required). Or split the DTO into `CreateBillingUsageDashboardRequest` (body) and `GetBillingUsageDashboardRequest` (query params), since the GET endpoint conceptually has different parameter semantics from the POST. +### 2. `dashboardType` is misleadingly optional on both request DTOs — `src/v1/model.ts:32, 48` +- **Why weird:** The field is typed `UsageDashboardType | undefined` (optional) on both `CreateBillingUsageDashboardRequest` and `GetBillingUsageDashboardRequest`, but the JSDoc says "Workspace level usage dashboard shows usage data for the specified workspace ID. Global level usage dashboard shows usage data for all workspaces in the account." There is no documented default — what happens if you omit `dashboardType`? The API presumably 4xx's or picks a side. It is the field that distinguishes Workspace from Global dashboards, so it reads as a required selector typed as optional. +- **Category:** 6 (misleading — TS type says optional, API likely requires it). +- **Suggested name:** Keep the name but type as `UsageDashboardType` (required) on both DTOs. - **Rationale:** `dashboardType` is the field that distinguishes Workspace from Global dashboards — it is *the* selector for the resource. Treating it as optional with no default is type-level dishonesty. -### 3. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:21` / `src/v1/client.ts:69, 101` -- **Why weird:** `accountId` lives on `CreateBillingUsageDashboardRequest` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:69, 101` — `${req.accountId ?? this.accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. +### 3. `accountId` is in the request body shape but is actually a URL path parameter — `src/v1/model.ts:30, 46` / `src/v1/client.ts:70, 103` +- **Why weird:** `accountId` lives on `CreateBillingUsageDashboardRequest` and `GetBillingUsageDashboardRequest` (looks like a body field) but the client extracts it for the URL path (`/api/2.0/accounts/${req.accountId}/dashboard`) — it is *not* sent in the JSON body. The marshalled body does emit `account_id` though, so it goes out twice (once in the URL, once in the body). Server may ignore the body copy. The field type and location are misleading about its wire role. Also duplicated against `ClientOptions.accountId` with a silent empty-string fallback at `client.ts:70, 103` — `${req.accountId ?? accountId ?? ''}` produces `/api/2.0/accounts//dashboard` if both are absent. - **Category:** 6 (misleading — body shape implies body field, but it's a path param), 12 (duplicate concept — also lives on `ClientOptions`), 16 (field's structural location contradicts wire role), 19 (underspecified — what happens if URL and body disagree? what happens if both sources are missing?). - **Suggested name:** Remove `accountId` from the request DTOs entirely. Make it a client-level concern only; throw a clear error if it is missing. Or segregate path params into a separate type and document the dual role. - **Rationale:** Same as `billableusagedownload` finding. The current shape misleads callers about the wire format, the duplicated-with-fallback pattern is a footgun, and the silent empty-string fallback compounds it. Removing the request-level field is the cleanest fix. ## Medium severity -### 4. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:65, 97` +### 4. `createBillingUsageDashboard` / `getBillingUsageDashboard` method names duplicate the type name — `src/v1/client.ts:65, 98` - **Why weird:** Method name and request-type name are textually identical (modulo case and the new `Request` suffix): `createBillingUsageDashboard(req: CreateBillingUsageDashboardRequest)`. The repetition is so close that the type name reads like a misnamed method import. Compare with `lakeview` where `Client.createDashboard(req: CreateDashboardRequest)` keeps the type-noun separate from the method-verb. - **Category:** 7 (overly verbose), 8 (redundant — method verb is already implicit in the type's verb prefix). - **Suggested name:** `createDashboard` / `getDashboard` (drop `BillingUsage` since the package name disambiguates) or `create` / `get` (since there are only two methods). Type stays as `CreateBillingUsageDashboardRequest`. - **Rationale:** A method on `usageDashboardsClient` is already in the usage-dashboards namespace; restating `BillingUsageDashboard` in the method name is pure stutter. The Go SDK does this because Go has package-flat method tables; TS classes provide their own namespace. -### 5. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:30, 44` +### 5. `dashboardId` returned but never used to re-fetch — `src/v1/model.ts:39, 53` - **Why weird:** Both response types include `dashboardId?: string` (always optional). But there is no `GetByDashboardId` method, and the request types use `(workspaceId, accountId, dashboardType)` to identify the dashboard, not the `dashboardId`. So `dashboardId` is a returned-but-never-accepted identifier — informational only. The field is also typed optional, but a successful 2xx response should always have an ID; the `?` is again type-level dishonesty. - **Category:** 6 (misleading optionality), 19 (underspecified id — present in responses but not accepted as a request key). - **Suggested name:** Keep the name; make it required (`dashboardId: string`). Or document that it is a read-only side-channel identifier (not a primary key from the API's POV). Or expose a `getByDashboardId` method that round-trips the value. - **Rationale:** If the API returns an ID, the SDK should either let you use it or document why you can't. The current state — return-only, never-accepted — is API-design noise that the SDK faithfully echoes. -### 6. `dashboardUrl` is optional on a success response — `src/v1/model.ts:46` +### 6. `dashboardUrl` is optional on a success response — `src/v1/model.ts:55` - **Why weird:** `dashboardUrl?: string | undefined` is optional on a success response (same dishonesty as #5). A successful 2xx read should always carry the dashboard URL, so the `?` overstates the genuine variability of the field. - **Category:** 6 (misleading optionality). - **Suggested name:** Keep the field name; make it non-optional on a 2xx response. - **Rationale:** If a successful read always returns a URL, the SDK should type it as required rather than forcing every caller to guard against an absence that never occurs. - -## Observations - -### 7. The package has no list/page operations -There is no `ListBillingUsageDashboards`, no `Iterator`, no `nextPageToken`. The package is one-create-one-get only — a very thin API. Audit-rule categories 9 (singular/plural is settled — should be singular, see #1) and 13 (verb tense — no verb tense issues since there is no "Started"/"Starting" parallel) mostly don't apply. The Go SDK source likely has the same shape. diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md index 515944b2..93b197e4 100644 --- a/.agent/naming-audit/vectorsearch.md +++ b/.agent/naming-audit/vectorsearch.md @@ -1,46 +1,40 @@ # Naming Audit: vectorsearch -**Path:** `packages/vectorsearch/src/v1/` (consolidation of the prior `endpoints` and `indexes` packages from the 2026-05-22 regen) +**Path:** `packages/vectorsearch/src/v1/` **Versions audited:** v1 **Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `src/v1/index.ts`, `src/v1/transport.ts` -**Total weird names flagged:** 4 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | ------------ | ----- | | High | 1 | -| Medium | 3 | -| **Total** | **4** | +| Medium | 2 | +| **Total** | **3** | --- ## High severity -### 1. `listEndpoint` / `listVectorIndex` method names are singular for collection operations — `src/v1/client.ts:348, 399` -- **Why weird:** Both methods return a collection (`ListEndpointResponse.endpoints: Endpoint[]`, `ListVectorIndexResponse.vectorIndexes: MiniVectorIndex[]`) yet the method names are singular. The corresponding URLs are plural (`/endpoints`, `/indexes`) and the body field names are plural. The request/response types (`ListEndpointRequest`, `ListEndpointResponse`, `ListVectorIndexRequest`, `ListVectorIndexResponse`) inherit the singular form. +### 1. `listVectorIndex` method name is singular for a collection operation — `src/v1/client.ts:407` +- **Why weird:** The method returns a collection (`ListVectorIndexResponse.vectorIndexes: MiniVectorIndex[]`) yet the method name is singular. The wire URL is plural (`/indexes`) and the response field name is plural. The request/response types (`ListVectorIndexRequest`, `ListVectorIndexResponse` — `model.ts:392, 399`) and the iterator (`listVectorIndexIter` — `client.ts:444`) inherit the singular form. The endpoint-list family is plural (`listEndpoints`, `ListEndpointsRequest`), but its response type `ListEndpointResponse` (`model.ts:375`) is singular, mismatching its own request type. - **Category:** 9 (singular/plural mismatch), 17 (inconsistent action verbs). -- **Suggested name:** `listEndpoints`, `listVectorIndexes`, `ListEndpointsRequest`, `ListEndpointsResponse`, `ListVectorIndexesRequest`, `ListVectorIndexesResponse`. The iterator pair (`listEndpointIter`, `listVectorIndexIter`) follows: `listEndpointsIter`, `listVectorIndexesIter`. +- **Suggested name:** `listVectorIndexes`, `ListVectorIndexesRequest`, `ListVectorIndexesResponse`, `listVectorIndexesIter`; `ListEndpointsResponse` to match `ListEndpointsRequest`. - **Rationale:** A collection method should be plural to match its return type, the wire URL, and the response field shape. --- ## Medium severity -### 2. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:52-56, 633` -- **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:156, 629` — "Result of the upsert or delete operation"). +### 2. `UpsertDeleteDataStatus` and `UpsertDeleteDataResult` couple two unrelated verbs — `model.ts:69-76, 691` +- **Why weird:** Both names join two verbs (`Upsert` AND `Delete`) into one compound noun. There is no "upsert-delete" operation — the type is used as the response shape for two separate operations (`UpsertDataVectorIndexResponse`, `DeleteDataVectorIndexResponse`). The JSDoc on the fields where they are used confirms the verbs are alternatives, not a sequence (`model.ts:184, 687` — "Result of the upsert or delete operation"). - **Category:** 13 (verb-coupling), 7 (verbose), 1 (generic `Status`/`Result`). - **Suggested name:** Split into `UpsertDataStatus` / `DeleteDataStatus` (aliases of the same wire enum), or use a neutral name `DataMutationStatus` / `DataMutationResult`. - **Rationale:** Two-verb compound nouns are unusual and confusing. Most APIs use a single neutral noun for shared response types. -### 3. `createEndpointWaiter` is a parallel verb-method to `createEndpoint` — `client.ts:149-158` -- **Why weird:** Two methods with the same verb start (`createEndpoint` / `createEndpointWaiter`). The waiter version *calls* `createEndpoint` then wraps the result in a `CreateEndpointWaiter`. A reader sees two `create*` methods and may think they are different operations. The Java/Go SDK convention surfaces a waiter via a side return; TS would more naturally inline the wait (`createEndpointAndWait`). -- **Category:** 7 (verbose), 13 (verb overlap), 17 (inconsistent action verbs). -- **Suggested name:** Either fold the wait into `createEndpoint` (return a `CreateEndpointWaiter` that is both an awaitable and the resource shape), or rename to `createEndpointAndWait`, or expose a single `waitForEndpoint(name)` that any caller can use after `createEndpoint`. -- **Rationale:** Two `create*` methods for one logical "create" operation force every caller to learn which one to use. There is also no analogous waiter for the index create flow, so the pattern is inconsistent within the package. - -### 4. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:70-88` -- **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 74-79 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. +### 3. `EndpointStatus_State` mixes lifecycle and health axes — `model.ts:94-116` +- **Why weird:** The enum lumps lifecycle states (`PROVISIONING`, `ONLINE`, `OFFLINE`, `DELETED`) with health-colored states (`RED_STATE`, `YELLOW_STATE`) in a single dimension. The comment block on lines 99-103 even calls out that the health states only apply once the endpoint is "ready". A consumer writing a state machine has to know which states are mutually exclusive with which others. - **Category:** 16 (field contradicting domain — two orthogonal axes squeezed into one enum), 6 (misleading). - **Suggested name:** Split into `EndpointLifecycleState` and `EndpointHealth`. Reflect both on `EndpointStatus` as two fields. - **Rationale:** Single-enum mixing of orthogonal dimensions is an API-design smell. diff --git a/.agent/naming-audit/volumes.md b/.agent/naming-audit/volumes.md index fcef2486..093876f8 100644 --- a/.agent/naming-audit/volumes.md +++ b/.agent/naming-audit/volumes.md @@ -6,12 +6,11 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ## Summary -| Severity | Count | -| ----------- | ----- | -| High | 1 | -| Medium | 3 | -| Observation | 1 | -| **Total** | **5** | +| Severity | Count | +| --------- | ----- | +| High | 1 | +| Medium | 3 | +| **Total** | **4** | --- @@ -19,8 +18,8 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### H1. `Create*` / `Update*` request types include server-only fields -- **File / line:** `src/v1/model.ts:16–52` (`CreateVolumeRequest`), - `src/v1/model.ts:123–163` (`UpdateVolumeRequest`). +- **File / line:** `src/v1/model.ts:24–60` (`CreateVolumeRequest`), + `src/v1/model.ts:131–171` (`UpdateVolumeRequest`). - **Category:** #6 misleading name; #16 field contradicting type domain; #12 duplicate concepts. - **Current:** `CreateVolumeRequest` and `UpdateVolumeRequest` both carry @@ -31,11 +30,11 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `name`, `catalogName`, `schemaName`, `volumeType`, `storageLocation`, `comment`. For `UpdateVolumeRequest`: `fullNameArg` (the path identifier), `newName`, `owner`, `comment` (per the method docstring at - `client.ts:279`). + `client.ts:282`). - **Rationale:** A request type named `CreateVolumeRequest` whose fields include `createdAt`, `createdBy`, `updatedAt`, `updatedBy`, and `volumeId` invites users to populate them — but the server ignores or - rejects them. The `client.ts:279` doc itself says "Currently only the + rejects them. The `client.ts:282` doc itself says "Currently only the name, the owner or the comment of the volume could be updated." Compare with the Go SDK `databricks/sdk-go/databricks/api/volumes/v1/` to confirm the upstream split. @@ -46,7 +45,7 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### M1. `VolumeInfo` — redundant `Info` suffix -- **File / line:** `src/v1/model.ts:165`. +- **File / line:** `src/v1/model.ts:173`. - **Category:** #8 redundant suffix; #14 Go/Java-style name. - **Current:** `VolumeInfo`. - **Suggestion:** `Volume`. @@ -59,8 +58,8 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### M2. `browseOnly` is a server-derived flag on request types -- **File / line:** `src/v1/model.ts:51` (`CreateVolumeRequest.browseOnly`), - `162` (`UpdateVolumeRequest.browseOnly`), `200` +- **File / line:** `src/v1/model.ts:59` (`CreateVolumeRequest.browseOnly`), + `170` (`UpdateVolumeRequest.browseOnly`), `208` (`VolumeInfo.browseOnly`). - **Category:** #6 misleading name; #16 field contradicting type domain. - **Current:** `browseOnly?: boolean | undefined` — present on the @@ -78,7 +77,7 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, ### M3. `req` parameter name on all client methods -- **File / line:** `src/v1/client.ts:92, 127, 162, 211, 256, 282`. +- **File / line:** `src/v1/client.ts:91, 127, 163, 213, 259, 285`. - **Category:** #5 cryptic abbreviation; #14 Go-style name. - **Current:** `req: CreateVolumeRequest`, `req: DeleteVolumeRequest`, etc. - **Suggestion:** `request` (matches Go-port readability without @@ -88,14 +87,3 @@ Files audited: `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/utils.ts`, `req`/`resp` idiom is fine in Go where short identifiers are encouraged; in TS this reads as Go-translated code. Pervasive in this package (every method uses `req`) and across the repo. - ---- - -## Observations (repo-wide conventions, not local defects) - -### O1. `…Info` suffix repeated across UC types - -`VolumeInfo` follows the `CatalogInfo`, `ConnectionInfo`, -`FunctionInfo`, `ExternalLocationInfo`, `SchemaInfo` pattern. If the -codebase decides to drop the `Info` suffix, this is one of many to fix -(M1 above flags it locally). diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md index b13fb76c..f1b265e7 100644 --- a/.agent/naming-audit/warehouses.md +++ b/.agent/naming-audit/warehouses.md @@ -14,11 +14,10 @@ | Severity | Count | | ----------- | ----- | -| High | 17 | -| Medium | 7 | -| Low | 15 | -| Observation | 11 | -| **Total** | **50** | +| High | 13 | +| Medium | 6 | +| Low | 6 | +| **Total** | **25** | --- @@ -40,10 +39,10 @@ add a JSDoc on `Client` clearly explaining the two resource families. Cross-cutting decision. -### F0.2 — Conflict with `endpoints` package across the monorepo (MEDIUM, cross-package) -- **Where:** `packages/endpoints/` exports `Endpoint`, - `EndpointType`, `EndpointStatus`, `EndpointThroughputInfo`, etc. - for vector-search endpoints. This package exports +### F0.2 — Conflict with the vector-search package across the monorepo (MEDIUM, cross-package) +- **Where:** `packages/vectorsearch/` exports `Endpoint` + (`model.ts:303`) and `EndpointType` (`model.ts:20`) for + vector-search endpoints. This package exports `EndpointInfo`, `EndpointHealth`, `EndpointState`, `EndpointTags`, `EndpointTagPair`, `EndpointConfPair`, `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy`, @@ -56,7 +55,7 @@ name says "warehouses". A reader cannot grep for "endpoint" and know which subsystem matches. - **Suggestion:** Rename all `Endpoint*` types in this package to - `Warehouse*` (see F1.x, F8.1). Reconcile with the package brand. + `Warehouse*` (see F1.x). Reconcile with the package brand. --- @@ -65,10 +64,10 @@ ### 1. Vague / generic names #### F1.1 — `EndpointInfo` type name (HIGH) -- **Where:** `model.ts:981`, `index.ts:35`, return field +- **Where:** `model.ts:1045`, `index.ts:35`, return field `warehouses?: EndpointInfo[]` on `ListWarehousesResponse` - (`model.ts:1304`), yield type of `listWarehousesIter` - (`client.ts:483`). + (`model.ts:1370`), yield type of `listWarehousesIter` + (`client.ts:494`). - **Why flagged:** Misleading legacy name. The type represents a SQL warehouse (it has `clusterSize`, `warehouseType`, `jdbcUrl`, `numClusters`, etc.), but the type is named @@ -80,17 +79,17 @@ `GetWarehouseResponse` shape into a single canonical type. #### F1.2 — `EndpointState` enum name (HIGH) -- **Where:** `model.ts:87`, `index.ts:16`. Used in - `EndpointInfo.state` (`model.ts:1081`), - `GetWarehouseResponse.state` (`model.ts:1215`), and as - the poll-target inside every Waiter (`client.ts:691, 694, 695, - 764, ...`). +- **Where:** `model.ts:100`, `index.ts:16`. Used in + `EndpointInfo.state` (`model.ts:1146`), + `GetWarehouseResponse.state` (`model.ts:1281`), and as + the poll-target inside every Waiter (`client.ts:708, 711, 712, + 781, ...`). - **Why flagged:** The states themselves (`RUNNING`, `STOPPING`, `STOPPED`, `DELETING`, `DELETED`, `STARTING`) are warehouse states. JSDoc on the enum says "State of a warehouse." but the type is named `EndpointState`. The mismatch forces every customer-facing waiter to import `EndpointState` then check - `EndpointState.RUNNING` (`client.ts:691`) on a value whose type + `EndpointState.RUNNING` (`client.ts:708`) on a value whose type is warehouse. - **Suggestion:** Rename to `WarehouseState`. The wire string can remain identical (server expects `"RUNNING"`, etc., not @@ -98,30 +97,30 @@ spec level. #### F1.3 — `EndpointHealth` interface and `EndpointHealth_Status` enum (HIGH) -- **Where:** `model.ts:968`, `model.ts:686`, `index.ts:34, 20`. - Field on `EndpointInfo.health` (`model.ts:1087`) and - `GetWarehouseResponse.health` (`model.ts:1221`). JSDoc says - "Health status of the endpoint" (`model.ts:969`). +- **Where:** `model.ts:1032`, `model.ts:744`, `index.ts:34, 20`. + Field on `EndpointInfo.health` (`model.ts:1152`) and + `GetWarehouseResponse.health` (`model.ts:1287`). JSDoc says + "Health status of the endpoint" (`model.ts:1033`). - **Why flagged:** Same root issue as F1.1/F1.2. The health is of a warehouse, not an endpoint. The waiters use - `pollResp.health?.summary` (`client.ts:696`) — a warehouse + `pollResp.health?.summary` (`client.ts:713`) — a warehouse health message. - **Suggestion:** Rename to `WarehouseHealth` / `WarehouseHealth_Status`. #### F1.4 — `EndpointTags`, `EndpointTagPair` interface names (HIGH) -- **Where:** `model.ts:1095, 1090`, `index.ts:37, 36`. Field - `tags?: EndpointTags` on `CreateWarehouseRequest` (`model.ts:794`), - `EditWarehouseRequest` (`model.ts:940`), `EndpointInfo` - (`model.ts:1058`), `GetWarehouseResponse` (`model.ts:1192`). +- **Where:** `model.ts:1160, 1155`, `index.ts:37, 36`. Field + `tags?: EndpointTags` on `CreateWarehouseRequest` (`model.ts:857`), + `EditWarehouseRequest` (`model.ts:1004`), `EndpointInfo` + (`model.ts:1123`), `GetWarehouseResponse` (`model.ts:1258`). - **Why flagged:** Same legacy naming. Tags are on warehouses, not endpoints. JSDoc says "key-value pairs that will be tagged on all resources … associated with this SQL warehouse" - (`model.ts:788, 933, 1051, 1185`). + (`model.ts:851, 998, 1117, 1252`). - **Suggestion:** Rename to `WarehouseTags` / `WarehouseTagPair`. #### F1.5 — `EndpointConfPair`, `RepeatedEndpointConfPairs` (HIGH) -- **Where:** `model.ts:963, 1319`, `index.ts:33, 47`. +- **Where:** `model.ts:1027, 1385`, `index.ts:33, 47`. - **Why flagged:** Workspace-level SQL configuration parameters (`globalParam`, `sqlConfigurationParameters`, etc.) are not per-endpoint. They are workspace-scoped. The current name @@ -131,12 +130,12 @@ `RepeatedConfigPairs`. #### F1.6 — `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` (HIGH) -- **Where:** `model.ts:26, 55`, `index.ts:14, 15`. Field on +- **Where:** `model.ts:36, 64`, `index.ts:14, 15`. Field on `SetWorkspaceWarehouseConfigRequest.securityPolicy` - (`model.ts:1332`), + (`model.ts:1398`), `GetWorkspaceWarehouseConfigResponse.securityPolicy` - (`model.ts:1233`), and `spotInstancePolicy` on each warehouse - (`model.ts:796, 942, 1060, 1194`). + (`model.ts:1299`), and `spotInstancePolicy` on each warehouse + (`model.ts:859, 1006, 1125, 1260`). - **Why flagged:** Same legacy term. JSDoc on `EndpointSecurityPolicy` reads "Security policy to be used for warehouses". JSDoc on `EndpointSpotInstancePolicy` extensively @@ -145,7 +144,7 @@ `WarehouseSpotInstancePolicy`. #### F1.7 — `Channel` type and `ChannelName` enum (MEDIUM) -- **Where:** `model.ts:701, 7`, `index.ts:24, 12`. +- **Where:** `model.ts:763, 8`, `index.ts:24, 12`. - **Why flagged:** "Channel" alone is a generic term (HTTP channel, communication channel, marketing channel). In this domain it means "DBSQL release channel" — `CHANNEL_NAME_PREVIEW`, @@ -156,21 +155,21 @@ - **Suggestion:** Rename the type to `WarehouseChannel` and the enum to `WarehouseChannelName` (or `DbsqlChannel` / `DbsqlChannelName`). Note: the enum name `ChannelName` - duplicates "name" — see F5.2. + duplicates "name" — see F4.2. #### F1.8 — `req` parameter name on every client method (LOW, Go-ism) -- **Where:** `client.ts:110, 157, 185, 201, 223, 251, 279, 295, - 323, 385, 424, 442, 481, 499, 534, 562, 574, 617` (and `_req` at - `client.ts:351`). -- **Why flagged:** `req` is a Go-ism (see category 10). It is +- **Where:** `client.ts:109, 157, 187, 203, 226, 255, 285, 301, + 330, 394, 434, 452, 492, 510, 546, 576, 588, 618, 633` (and `_req` + at `client.ts:359`). +- **Why flagged:** `req` is a Go-ism (see section 5). It is also generic. - **Suggestion:** Use `request` for stylistic consistency with `options` (which is spelled out). Cross-package decision. #### F1.9 — `resp` local variable everywhere (LOW) - **Where:** `client.ts` throughout (e.g. `resp: - CreateWarehouseResponse | undefined`, `client.ts:162`). -- **Why flagged:** Same Go abbreviation as `req`. See F10.1. + CreateWarehouseResponse | undefined`, `client.ts:163`). +- **Why flagged:** Same Go abbreviation as `req`. See F5.1. - **Suggestion:** `response` for consistency. Generator-level. --- @@ -178,56 +177,43 @@ ### 2. Cryptic abbreviations #### F2.1 — `Conf` for configuration (`EndpointConfPair`) (MEDIUM) -- **Where:** `model.ts:963, 1321`. +- **Where:** `model.ts:1027, 1385`. - **Why flagged:** "Conf" is an abbreviation. It is also inconsistent with the spelled-out `Config` / `Configuration` forms used elsewhere in the package. - **Suggestion:** Standardize on `Config`. Rename the type `EndpointConfPair` → `ConfigPair`. -#### F2.2 — `req`, `resp` Go-ism abbreviations (LOW) -- **Where:** `client.ts` throughout. -- Already covered in F1.8 and F1.9. - --- ### 3. Misleading names #### F3.1 — `EndpointInfo` for a warehouse record (HIGH) -- **Where:** `model.ts:981`. +- **Where:** `model.ts:1045`. - Covered in F1.1 / F0. The most glaring example: a value of type `EndpointInfo` is a warehouse, not an endpoint. - **Suggestion:** Rename to `Warehouse` or `WarehouseInfo`. -#### F3.2 — `EndpointState` for warehouse states (HIGH) -- Covered in F1.2 / F0. - -#### F3.3 — `EndpointHealth` for warehouse health (HIGH) -- Covered in F1.3 / F0. - -#### F3.4 — `EndpointTags` / `EndpointTagPair` for warehouse tags (HIGH) -- Covered in F1.4 / F0. - -#### F3.5 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) -- **Where:** `model.ts:963, 1319`. Used inside +#### F3.2 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) +- **Where:** `model.ts:1027, 1385`. Used inside `GetWorkspaceWarehouseConfigResponse.dataAccessConfig` - (`model.ts:1238`, workspace-scoped) and `globalParam` - (`model.ts:1250`, also workspace-scoped). + (`model.ts:1304`, workspace-scoped) and `globalParam` + (`model.ts:1316`, also workspace-scoped). - **Why flagged:** The type name says "endpoint conf" but the scope is workspace. - **Suggestion:** Rename to `WorkspaceConfigPair` or `ConfigPair`. -#### F3.6 — `ChannelName` enum used for the channel's "version selector" (LOW) -- **Where:** `model.ts:7`. +#### F3.3 — `ChannelName` enum used for the channel's "version selector" (LOW) +- **Where:** `model.ts:8`. - **Why flagged:** Enum is named `ChannelName` (suggesting just the "name"), but the values include `CUSTOM` and a release-channel concept. `ChannelType` would be more accurate. - **Suggestion:** Rename to `ChannelType` or `WarehouseChannel`. -#### F3.7 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) -- **Where:** `model.ts:784, 930, 1048, 1182`. +#### F3.4 — `creatorName` is documented as "warehouse creator name" but lives on Create + Edit + Get (LOW) +- **Where:** `model.ts:846, 993, 1112, 1247`. - **Why flagged:** The field is settable on `CreateWarehouseRequest`/`EditWarehouseRequest`, but its meaning is read-only on the server side ("creator" never changes after @@ -235,15 +221,15 @@ - **Suggestion:** Spec-level. Mark read-only on response types only. -#### F3.8 — Waiter `done` returns true on terminal failure states (MEDIUM) -- **Where:** `client.ts:712, 785, 858, 926` (the `done()` of +#### F3.5 — Waiter `done` returns true on terminal failure states (MEDIUM) +- **Where:** `client.ts:729, 802, 875, 943` (the `done()` of each Waiter). - **Why flagged:** `done()` returns `true` for `RUNNING`, - `STOPPED`, `DELETED` indiscriminately (`client.ts:726-728`). A + `STOPPED`, `DELETED` indiscriminately (`client.ts:743-746`). A caller who reads "done()" expects success, but `DELETED` is a failure for `CreateWarehouseWaiter`/`StartWarehouseWaiter`. The wait() method correctly distinguishes (throws on - STOPPED/DELETED at `client.ts:694-697`), but done() does not. + STOPPED/DELETED at `client.ts:711-714`), but done() does not. - **Suggestion:** Either rename `done()` to `terminal()` / `settled()` (clearly signals "stopped progressing", not "succeeded"), or split into `done()` (succeeded) and @@ -252,23 +238,9 @@ --- -### 4. Overly verbose - -#### F4.1 — `CreateDefaultWarehouseOverrideRequest`, `GetDefaultWarehouseOverrideRequest`, `UpdateDefaultWarehouseOverrideRequest`, `DeleteDefaultWarehouseOverrideRequest`, `ListDefaultWarehouseOverridesRequest`, `ListDefaultWarehouseOverridesResponse` (MEDIUM) -- **Where:** `model.ts:707, 1100, 1396, 846, 1273, 1292`. -- **Why flagged:** All AIP-style "DefaultWarehouseOverride" - resources. The names are accurate but very long - (39-48 characters). The matching client methods - (`createDefaultWarehouseOverride`, - `listDefaultWarehouseOverridesIter`) inherit the same length. -- **Suggestion:** Acceptable; AIP-compliant. Aliasing at the - call site is the typical workaround. +### 4. Redundant suffixes ---- - -### 5. Redundant suffixes - -#### F5.1 — `Request` suffix on every request interface (HIGH, generator-driven) +#### F4.1 — `Request` suffix on every request interface (HIGH, generator-driven) - **Where:** `CreateDefaultWarehouseOverrideRequest`, `CreateWarehouseRequest`, `DeleteDefaultWarehouseOverrideRequest`, @@ -281,16 +253,14 @@ `StartRequest`, `StopRequest`. - **Why flagged:** Caller already supplies the request via the parameter type position — the `Request` suffix is a - belt-and-suspenders signal. All request types now carry the - suffix consistently (the prior `CreateWarehouse` / `GetWarehouse` - without-suffix variants were renamed to `CreateWarehouseRequest` - / `GetWarehouseRequest`). The remaining concern is the - redundancy itself, not the consistency. + belt-and-suspenders signal. Every request type in the package + carries the suffix, so the concern is the redundancy itself, + not consistency. - **Suggestion:** Drop the `Request` suffix across the SDK at the generator level. Generator-level. -#### F5.2 — `Name` suffix on `ChannelName` enum (MEDIUM) -- **Where:** `model.ts:7`. +#### F4.2 — `Name` suffix on `ChannelName` enum (MEDIUM) +- **Where:** `model.ts:8`. - **Why flagged:** Both `ChannelName.CHANNEL_NAME_PREVIEW` (the enum) and the `name` field on `Channel` of type `ChannelName` — three layers of "name". The enum is more accurately a @@ -298,8 +268,8 @@ - **Suggestion:** Rename the enum to `ChannelType` (this also clarifies intent — Custom vs. Preview is the *type* of channel). -#### F5.3 — `Pair` suffix on `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair` (MEDIUM) -- **Where:** `model.ts:1090, 963, 1423`. +#### F4.3 — `Pair` suffix on `EndpointTagPair`, `EndpointConfPair`, `WarehouseTypePair` (MEDIUM) +- **Where:** `model.ts:1155, 1027, 1483`. - **Why flagged:** "Pair" is a generic suffix that adds little information when the type's two fields are obvious. For `EndpointTagPair` (`key`, `value`), the suffix duplicates the @@ -309,95 +279,11 @@ `WarehouseTypeAvailability` (or similar) — semantically clearer than the `Pair` suffix. -#### F5.4 — `Params` suffix on `OdbcParams` (LOW) -- **Where:** `model.ts:1312`. -- **Why flagged:** Mild noise. Type has `hostname`, `path`, - `protocol`, `port` — `OdbcConnectionInfo` would be more - accurate. -- **Suggestion:** Acceptable as-is; `OdbcParams` follows - the standard "parameters" terminology. - ---- - -### 6. Singular / plural mismatches - -#### F6.1 — `TerminationReason.parameters` is a map, not a list (LOW) -- **Where:** `model.ts:1386`. Type `Record`. -- **Why flagged:** `parameters` is plural but typed as a map. - Plural maps are fine but inconsistent — compare to - `globalParam` / `configParam` which are singular. -- **Suggestion:** Acceptable; map semantics are clear from the - type. Plural is correct. - -#### F6.2 — `enabledWarehouseTypes` plural array (acceptable) -- **Where:** `model.ts:1269, 1368`. -- **Why flagged:** Plural name + array type. Correct. -- **Suggestion:** No change. - -#### F6.3 — `defaultWarehouseOverrides` plural array (acceptable) -- **Where:** `model.ts:1294`. -- **Why flagged:** Correct. -- **Suggestion:** No change. - -#### F6.4 — `warehouses` plural array (acceptable) -- **Where:** `model.ts:1304`. Correct. - -#### F6.5 — `customTags` plural array (acceptable) -- **Where:** `model.ts:1096`. Correct. - ---- - -### 7. Reserved-word collisions - -#### F7.1 — `type` field (LOW) -- **Where:** `DefaultWarehouseOverride.type` (`model.ts:837`), - `TerminationReason.type` (`model.ts:1384`). -- **Why flagged:** `type` is a TS keyword in certain positions - (the `type` modifier in type imports), but valid as a - property name. No actual collision. Some linters warn. -- **Suggestion:** Acceptable; common pattern in TS APIs. - -#### F7.2 — `name`, `id` (acceptable) -- Common property names; not reserved. - -#### F7.3 — `delete` not used as identifier (acceptable) -- Used only as method name `deleteWarehouse`, - `deleteDefaultWarehouseOverride` — fine in TS (verb prefix). - -#### F7.4 — `default-warehouse-overrides` URL segment vs. `default` TS keyword (acceptable) -- **Where:** Path string only. Not an identifier. - ---- - -### 8. Duplicate concepts / historical baggage - -#### F8.1 — Legacy `Endpoint*` naming for a `Warehouse*` concept (HIGH) -- Covered in F0 and F1.x. Listed here for completeness in - category 8: the entire `Endpoint*` family is historical - baggage from the rename of "SQL Endpoints" to "SQL Warehouses". - ---- - -### 9. Verb-tense inconsistency - -#### F9.1 — `Create*`, `Delete*`, `Edit*`, `Update*`, `Get*`, `Set*`, -`List*`, `Start*`, `Stop*` (acceptable + inconsistency) -- **Where:** Method names across `client.ts`. -- **Why flagged:** All imperatives, present tense. Consistent - *within tense*. But mixed verbs across the same resource: - - Warehouses: `createWarehouse`, `editWarehouse`, - `deleteWarehouse`. `editWarehouse` is the odd one — uses - "edit" instead of the conventional "update". - - Default overrides: `createDefaultWarehouseOverride`, - `updateDefaultWarehouseOverride`, - `deleteDefaultWarehouseOverride`. Standard CRUD verbs. -- **Suggestion:** See F11.1 below — same root cause. - --- -### 10. Go/Java-style names +### 5. Go/Java-style names -#### F10.1 — `req`, `resp`, `opts` Go abbreviations (LOW) +#### F5.1 — `req`, `resp`, `opts` Go abbreviations (LOW) - **Where:** `client.ts` throughout. - **Why flagged:** Go convention is `req`, `resp`, `opts`; TS convention is `request`, `response`, `options`. SDK already @@ -405,19 +291,19 @@ within the same method signature. - **Suggestion:** Generator-level. -#### F10.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) -- **Where:** `client.ts:428, 485`. +#### F5.2 — `for (;;)` C-style infinite loop (LOW, generator-driven) +- **Where:** `client.ts:438, 496`. - **Why flagged:** `for (;;)` is C/Go idiom; TS prefers `while (true)` for readability. Minor. - **Suggestion:** Generator-level. --- -### 11. Inconsistent action verbs +### 6. Inconsistent action verbs -#### F11.1 — `Edit` vs. `Update` (HIGH) -- **Where:** `editWarehouse` (`client.ts:250`) vs. - `updateDefaultWarehouseOverride` (`client.ts:616`). Same +#### F6.1 — `Edit` vs. `Update` (HIGH) +- **Where:** `editWarehouse` (`client.ts:284`) vs. + `updateDefaultWarehouseOverride` (`client.ts:632`). Same package, two different "modify resource" verbs. - **Why flagged:** Warehouses use `edit`; default warehouse overrides use `update`. CRUD-style APIs across the SDK use @@ -430,33 +316,12 @@ `EditWarehouseWaiter` → `UpdateWarehouseWaiter`. Note: this is a method/operation rename — coordinate with backend. -#### F11.2 — `Start` and `Stop` as method names (acceptable) -- **Where:** `startWarehouse`, `stopWarehouse`. -- **Why flagged:** Pair of opposites; standard for state - machines. Good. -- **Suggestion:** No change. - -#### F11.3 — `Create` and `Delete` (acceptable) -- Standard CRUD. No issue. - --- -### 12. Underspecified IDs - -#### F12.1 — `runAsUserId` on `ListWarehousesRequest` (deprecated) (LOW) -- **Where:** `model.ts:1451`. Already deprecated. Numeric (`bigint`), - not string — unusual; most IDs in the SDK are string. -- **Suggestion:** Already deprecated. Leave. - -#### F12.2 — `ListDefaultWarehouseOverridesResponse.nextPageToken` (acceptable) -- **Where:** `model.ts:1299`. Standard pagination identifier. - ---- +### 7. Type-suffix tautology -### 13. Type-suffix tautology - -#### F13.1 — `Channel.name: ChannelName` (HIGH) -- **Where:** `model.ts:701-704`. +#### F7.1 — `Channel.name: ChannelName` (HIGH) +- **Where:** `model.ts:763-766`. ```ts export interface Channel { name?: ChannelName | undefined; @@ -468,18 +333,11 @@ `channel.name.toString()` returns `'CHANNEL_NAME_PREVIEW'` — three layers of "name". - **Suggestion:** Rename the enum to `ChannelType`, which breaks - the tautology between the field and its enum type. See F3.6 / - F5.2. - -#### F13.2 — `EndpointHealth.status: EndpointHealth_Status` (LOW) -- **Where:** `model.ts:970`. -- **Why flagged:** Field name `status` + enum suffix `Status` - + interface "Health Status" namespace. Disambiguated by - typing. -- **Suggestion:** Acceptable; standard pattern. - -#### F13.3 — `WarehouseTypePair.warehouseType: WarehouseType` (HIGH) -- **Where:** `model.ts:1423-1429`. + the tautology between the field and its enum type. See F3.3 / + F4.2. + +#### F7.2 — `WarehouseTypePair.warehouseType: WarehouseType` (HIGH) +- **Where:** `model.ts:1483-1490`. ```ts export interface WarehouseTypePair { warehouseType?: WarehouseType | undefined; @@ -492,18 +350,3 @@ - **Suggestion:** Rename the enum type `WarehouseType` → `Type` (or rename the container to `WarehouseTypeAvailability`) to break the duplication. - -#### F13.4 — `TerminationReason.code: TerminationCode` (LOW) -- **Where:** `model.ts:1382`. Field `code` + enum suffix `Code` - on `TerminationCode`. Generic field name with specific enum — - acceptable. - -#### F13.5 — `TerminationReason.type: TerminationType` (LOW) -- **Where:** `model.ts:1384`. Same pattern. Acceptable. - -#### F13.6 — `DefaultWarehouseOverride.type: DefaultWarehouseOverrideType` (LOW) -- **Where:** `model.ts:837`. -- **Why flagged:** Field `type` typed as - `DefaultWarehouseOverrideType`. Container type already says - "DefaultWarehouseOverride", so the field's type duplicates - the container's name + adds "Type". Acceptable in practice. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md index f6c8e08d..c08081ba 100644 --- a/.agent/naming-audit/workspacebindings.md +++ b/.agent/naming-audit/workspacebindings.md @@ -1,33 +1,23 @@ # Naming Audit: workspacebindings -**Path:** `packages/workspacebindings/src/v1/` +**Path:** `packages/uc/workspacebindings/src/v1/` **Versions audited:** v1 **Inferred domain:** Unity Catalog workspace bindings — controls which Databricks workspaces can access a given UC securable (catalog, storage credential, credential, external location) and at what access level (`READ_WRITE` or `READ_ONLY`). Exposes a legacy catalog-only API (`/workspace-bindings/catalogs/{name}`) and a generic securable-aware API (`/bindings/{type}/{full_name}`). -**Total weird names flagged:** 2 +**Total weird names flagged:** 1 ## Summary | Severity | Count | | --- | --- | | Medium | 1 | -| Observation | 1 | -A redundant Go-style `Info` suffix and a context-free client error message make up -the remaining findings. +A redundant Go-style `Info` suffix makes up the single finding. --- ## Medium severity -### 1. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:84` +### 1. `WorkspaceBindingInfo` (type) — `src/v1/model.ts:88` - **Why weird:** `Info` suffix is a Go-style convention (`*Info` types in `databricks/sdk-go` are pervasive: `CatalogInfo`, `TableInfo`, `SchemaInfo`...). In TS the suffix carries no information — the type *is* the binding, not a separate "info-about-the-binding" record. Just two fields: `workspaceId` and `bindingType`. - **Category:** 14 (Go-style name), 8 (redundant suffix). - **Suggested name:** `WorkspaceBinding`. - **Rationale:** Drop Go suffixes when porting; sibling packages have already done this for some types but not consistently. - ---- - -## Observations - -### 2. Client `Host is required.` error message — `src/v1/client.ts:60` -The error thrown when `options.host` is undefined says only "Host is required." — no client name, no package context. Across many similar packages every Client throws the same string, so a stack trace at the outer layer is ambiguous about which Client failed. Naming-adjacent. -- **Category:** Observation. diff --git a/.agent/naming-audit/workspaces.md b/.agent/naming-audit/workspaces.md index 9b72c3ff..4dc71456 100644 --- a/.agent/naming-audit/workspaces.md +++ b/.agent/naming-audit/workspaces.md @@ -5,38 +5,37 @@ **Inferred domain:** Account-level Databricks workspace management (create/get/list/update/delete a workspace under an account, with all its cloud, network, storage, and encryption configuration). -**Total weird names flagged:** 4 +**Total weird names flagged:** 3 ## Summary | Severity | Count | | ------------ | ----- | -| High | 4 | +| High | 3 | ## High severity -### 1. `Client.createWorkspacePublic` / `createWorkspacePublicWaiter` — `src/v1/client.ts:85,110` -- **Why weird:** `Client` method names end in `Public`. Reads as "the +### 1. `WorkspacesClient.createWorkspacePublic` — `src/v1/client.ts:124` +- **Why weird:** `WorkspacesClient` method name ends in `Public`. Reads as "the method on the public class that calls the public endpoint" — the suffix only exists because the underlying proto/spec uses `Public` - to distinguish account-API routes. The companion waiter factory - carries the same suffix. + to distinguish account-API routes. - **Category:** Proto-architectural leak — `Public` suffix on client method. -- **Suggested:** `createWorkspace`, `createWorkspaceWaiter`. -- **Rationale:** Methods on `Client` are inherently public; the suffix +- **Suggested:** `createWorkspace`. +- **Rationale:** Methods on `WorkspacesClient` are inherently public; the suffix is meaningless to a TS caller. -### 2. `Client.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` / `updateWorkspacePublicWaiter` — `src/v1/client.ts:124,152,177,207,247` -- **Why weird:** Same `Public` suffix on every other `Client` method - (and the update waiter factory) as #1. +### 2. `WorkspacesClient.deleteWorkspacePublic` / `getWorkspacePublic` / `listWorkspacesPublic` / `updateWorkspacePublic` — `src/v1/client.ts:138,167,193,266` +- **Why weird:** Same `Public` suffix on every other `WorkspacesClient` method + as #1. - **Category:** Proto-architectural leak — `Public` suffix on client method. - **Suggested:** `deleteWorkspace`, `getWorkspace`, `listWorkspaces`, - `updateWorkspace`, `updateWorkspaceWaiter`. + `updateWorkspace`. - **Rationale:** Same as #1. -### 3. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:261,334` +### 3. `CreateWorkspacePublicWaiter` / `UpdateWorkspacePublicWaiter` classes — `src/v1/client.ts:280,353` - **Why weird:** Two exported waiter classes carry the `Public` infix between the verb (`Create`/`Update`) and the noun (`Workspace`) plus the `Waiter` role suffix. The class names are wholly SDK-side @@ -47,13 +46,3 @@ its cloud, network, storage, and encryption configuration). - **Suggested:** `CreateWorkspaceWaiter`, `UpdateWorkspaceWaiter`. - **Rationale:** Waiter classes are TS-only constructs; they have no business carrying the upstream proto's public/internal qualifier. - -### 4. `Public` waiter names in the `index.ts` re-export list — `src/v1/index.ts:5-6` -- **Why weird:** `index.ts` mirrors the leaked `Public` names from the - waiter classes in its re-export list: - `CreateWorkspacePublicWaiter`, `UpdateWorkspacePublicWaiter`. -- **Category:** Proto-architectural leak — `Public` mid-position - (re-export mirror). -- **Suggested:** Track the renames of #1–#3. -- **Rationale:** The re-export statement inherits the leaked names - verbatim; nothing to do here independent of the upstream renames. diff --git a/AGENTS.md b/AGENTS.md index 2216dbe2..7b6aeff0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -166,6 +166,15 @@ Each per-package audit follows a fixed structure: a summary table, then issue. Each finding cites `file:line`, the category, a suggested name, and the rationale. +**No history retention.** The audit is a live, current-state snapshot. It +must read as if generated from scratch against the current source, never as +a series of patches over earlier versions. NEVER keep a `## Fixed` section, +a prune-pass or changelog log, "down from N" waypoint history, or +"Last rescanned" / "Status" change-notes — in any per-package audit or in +`_SUMMARY.md`. When a finding is fixed (workflow A) or pruned (workflows B +and C), delete it cleanly with no trace. `_SUMMARY.md` shows only the +current totals, themes, and findings, never how it got there. + Two reduction workflows keep the audit current. Both spawn one `general-purpose` agent per API package in parallel batches of ~30-40 to avoid collision in reasoning. Always omit the `model` parameter so @@ -191,15 +200,18 @@ and asks to re-validate the audit. Phrasings like "rescan the audit", line number; update the line number in place. - **Superseded** — the symbol exists but the original concern shifted into a different category; rewrite the finding. -4. Delete fixed findings from the active `High`/`Medium`/`Low` sections. - Append them to a `## Fixed` section at the bottom of the file with a - one-line note (`Fixed in regeneration on YYYY-MM-DD`). -5. Recompute the summary table totals. +4. Delete fixed findings outright — remove them from the file entirely, + exactly as workflow B removes a pruned finding. Do NOT add a `## Fixed` + section, a "Fixed in regeneration" note, or any other record of what was + removed (see "No history retention" above). +5. Renumber remaining findings sequentially and recompute the summary table + totals. **After every agent finishes:** regenerate `_SUMMARY.md` so the cross-package totals, theme counts, and by-the-numbers table reflect the -new state. Do not edit `_SUMMARY.md` by hand; spawn a synthesis agent -that re-reads every per-package audit. +current state — current state ONLY, with no prune-pass log, no "down from +N" waypoint history, and no rescan changelog. Do not edit `_SUMMARY.md` by +hand; spawn a synthesis agent that re-reads every per-package audit. ### B. Prune a recommendation category